[
  {
    "path": ".editorconfig",
    "content": "root=true\n\n[*.{groovy,java,kt,xml}]\nindent_style = tab\nindent_size = 4\ncontinuation_indent_size = 8\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# .git-blame-ignore-revs\n# Reformat code following spring-javaformat upgrade\ndf5898a1464112f185d295d585740de696934a12\nc4de86c244acdcff69ed0aecacd254399be79ce2\nb07269a018a4a9d4c029aba7dd8a15fa66df681c\n\n    "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Community Support\n    url: https://stackoverflow.com/tags/spring-boot\n    about: Please ask and answer questions on StackOverflow with the tag `spring-boot`.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/issue.md",
    "content": "---\nname: General\nabout: Bugs, enhancements, documentation, tasks.\ntitle: ''\nlabels: ''\nassignees: ''\n---\n\n<!--\nThanks for raising a Spring Boot issue. Please take the time to review the following\ncategories as some of them do not apply here.\n\n🙅 \"Please DO NOT Raise an Issue\" Cases\n- Question\nSTOP!! Please ask questions about how to use something, or to understand why something isn't\nworking as you expect it to, on Stack Overflow using the spring-boot tag.\n- Security Vulnerability\nSTOP!! Please don't raise security vulnerabilities here. Head over to https://spring.io/security-policy to learn how to disclose them responsibly.\n- Managed Dependency Upgrade\nYou DO NOT need to raise an issue for a managed dependency version upgrade as there's a semi-automatic process for checking managed dependencies for new versions before a release. BUT pull requests for upgrades that are more involved than just a version property change are still most welcome.\n- With an Immediate Pull Request\nAn issue will be closed as a duplicate of the immediate pull request, so you don't have to raise an issue if you plan to create a pull request immediately.\n\n🐞 Bug report (please don't include this emoji/text, just add your details)\nPlease provide details of the problem, including the version of Spring Boot that you\nare using. If possible, please provide a test case or sample application that reproduces\nthe problem. This makes it much easier for us to diagnose the problem and to verify that\nwe have fixed it.\n\n🎁 Enhancement (please don't include this emoji/text, just add your details)\nPlease start by describing the problem that you are trying to solve. There may already\nbe a solution, or there may be a way to solve it that you hadn't considered.\n\n\nTIP: You can always edit your issue if it isn't formatted correctly.\n     See https://guides.github.com/features/mastering-markdown \n-->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nThanks for contributing to Spring Boot. Please review the following notes before\nsubmitting a pull request.\n\nPlease submit only genuine pull-requests. Do not use this repository as a GitHub\nplayground.\n\nSecurity Vulnerabilities\n\nSTOP! If your contribution fixes a security vulnerability, please do not submit it.\nInstead, please head over to https://spring.io/security-policy to learn how to disclose a\nvulnerability responsibly.\n\nDependency Upgrades\n\nPlease do not open a pull request for a straightforward dependency upgrade (one that\nonly updates the version property). We have a semi-automated process for such upgrades\nthat we prefer to use. However, if the upgrade is more involved (such as requiring\nchanges for removed or deprecated API) your pull request is most welcome.\n\nDescribing Your Changes\n\nIf, having reviewed the notes above, you're ready to submit your pull request, please\nprovide a brief description of the proposed changes. If they fix a bug, please\ndescribe the broken behaviour and how the changes fix it. If they make an enhancement,\nplease describe the new functionality and why you believe it's useful. If your pull\nrequest relates to any existing issues, please reference them by using the issue number\nprefixed with #.\n-->\n"
  },
  {
    "path": ".github/actions/await-http-resource/action.yml",
    "content": "name: Await HTTP Resource\ndescription: 'Waits for an HTTP resource to be available (a HEAD request succeeds)'\ninputs:\n  url:\n    description: 'URL of the resource to await'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Await HTTP resource\n      shell: bash\n      run: |\n        url=${{ inputs.url }}\n        echo \"Waiting for $url\"\n        until curl --fail --head --silent ${{ inputs.url }} > /dev/null\n        do\n          echo \".\"\n          sleep 60\n        done\n        echo \"$url is available\"\n"
  },
  {
    "path": ".github/actions/create-github-release/action.yml",
    "content": "name: Create GitHub Release\ndescription: 'Create the release on GitHub with a changelog'\ninputs:\n  commercial:\n    description: 'Whether to generate the changelog for the commercial release'\n    required: true\n  milestone:\n    description: 'Name of the GitHub milestone for which a release will be created'\n    required: true\n  pre-release:\n    description: 'Whether the release is a pre-release (a milestone or release candidate)'\n    required: false\n    default: 'false'\n  token:\n    description: 'Token to use for authentication with GitHub'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Generate Changelog\n      uses: spring-io/github-changelog-generator@f7d7a87a3e7c627ecb8c26cf086c38ac5a939721 #v0.0.14\n      with:\n        config-file: ${{ inputs.commercial && '.github/actions/create-github-release/changelog-generator-commercial.yml' || '.github/actions/create-github-release/changelog-generator-oss.yml' }}\n        milestone: ${{ inputs.milestone }}\n        token: ${{ inputs.token }}\n    - name: Create GitHub Release\n      shell: bash\n      env:\n        GITHUB_TOKEN: ${{ inputs.token }}\n      run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md ${{ inputs.pre-release == 'true' && '--prerelease' || '' }}\n"
  },
  {
    "path": ".github/actions/create-github-release/changelog-generator-commercial.yml",
    "content": "changelog:\n  sections:\n    - title: \":warning: Attention Required\"\n      labels:\n        - \"for: upgrade-attention\"\n      summary:\n        mode: \"member-comment\"\n        config:\n          prefix: \"Attention required:\"\n    - title: \":star: New Features\"\n      labels:\n        - \"type: enhancement\"\n    - title: \":lady_beetle: Bug Fixes\"\n      labels:\n        - \"type: bug\"\n        - \"type: regression\"\n    - title: \":notebook_with_decorative_cover: Documentation\"\n      labels:\n        - \"type: documentation\"\n    - title: \":hammer: Dependency Upgrades\"\n      sort: \"title\"\n      labels:\n        - \"type: dependency-upgrade\"\n  issues:\n    generate_links: false\n    ports:\n      - label: \"status: forward-port\"\n        bodyExpression: 'Forward port of issue #(\\d+).*'\n      - label: \"status: back-port\"\n        bodyExpression: 'Back port of issue #(\\d+).*'\n"
  },
  {
    "path": ".github/actions/create-github-release/changelog-generator-oss.yml",
    "content": "changelog:\n  sections:\n    - title: \":warning: Attention Required\"\n      labels:\n        - \"for: upgrade-attention\"\n      summary:\n        mode: \"member-comment\"\n        config:\n          prefix: \"Attention required:\"\n    - title: \":star: New Features\"\n      labels:\n        - \"type: enhancement\"\n    - title: \":lady_beetle: Bug Fixes\"\n      labels:\n        - \"type: bug\"\n        - \"type: regression\"\n    - title: \":notebook_with_decorative_cover: Documentation\"\n      labels:\n        - \"type: documentation\"\n    - title: \":hammer: Dependency Upgrades\"\n      sort: \"title\"\n      labels:\n        - \"type: dependency-upgrade\"\n      summary:\n        mode: \"body-regex\"\n        config:\n          expression: '(Upgrade to \\[.*\\]\\(.*\\)).*'\n  issues:\n    generate_links: true\n    ports:\n      - label: \"status: forward-port\"\n        bodyExpression: 'Forward port of issue #(\\d+).*'\n      - label: \"status: back-port\"\n        bodyExpression: 'Back port of issue #(\\d+).*'\n"
  },
  {
    "path": ".github/actions/prepare-gradle-build/action.yml",
    "content": "name: Prepare Gradle Build\ndescription: 'Prepares a Gradle build. Sets up Java and Gradle and configures Gradle properties'\ninputs:\n  cache-read-only:\n    description: 'Whether Gradle''s cache should be read only'\n    required: false\n    default: 'true'\n  develocity-access-key:\n    description: 'Access key for authentication with ge.spring.io'\n    required: false\n  java-distribution:\n    description: 'Java distribution to use'\n    required: false\n    default: 'liberica'\n  java-early-access:\n    description: 'Whether the Java version is in early access. When true, forces java-distribution to temurin'\n    required: false\n    default: 'false'\n  java-toolchain:\n    description: 'Whether a Java toolchain should be used'\n    required: false\n    default: 'false'\n  java-version:\n    description: 'Java version to use for the build'\n    required: false\n    default: '25'\nruns:\n  using: composite\n  steps:\n    - name: Free Disk Space\n      if: ${{ runner.os == 'Linux' }}\n      uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1\n      with:\n        tool-cache: true\n        docker-images: false\n    - name: Set Up Java\n      uses: actions/setup-java@v5\n      with:\n        distribution: ${{ inputs.java-early-access == 'true' && 'temurin' || (inputs.java-distribution || 'liberica') }}\n        java-version: |\n          ${{ inputs.java-early-access == 'true' && format('{0}-ea', inputs.java-version) || inputs.java-version }}\n          ${{ inputs.java-toolchain == 'true' && '25' || '' }}\n    - name: Set Up Gradle With Read/Write Cache\n      if: ${{ inputs.cache-read-only == 'false' }}\n      uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2\n      with:\n        cache-read-only: false\n        develocity-access-key: ${{ inputs.develocity-access-key }}\n    - name: Set Up Gradle\n      uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2\n      with:\n        develocity-access-key: ${{ inputs.develocity-access-key }}\n        develocity-token-expiry: 4\n    - name: Configure Gradle Properties\n      shell: bash\n      run: |\n        mkdir -p $HOME/.gradle\n        echo 'systemProp.user.name=spring-builds+github' >> $HOME/.gradle/gradle.properties\n        echo 'systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false' >> $HOME/.gradle/gradle.properties\n        echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties\n    - name: Configure Toolchain Properties\n      if: ${{ inputs.java-toolchain == 'true' }}\n      shell: bash\n      run: |\n        echo toolchainVersion=${{ inputs.java-version }} >> $HOME/.gradle/gradle.properties\n        echo systemProp.org.gradle.java.installations.auto-detect=false >> $HOME/.gradle/gradle.properties\n        echo systemProp.org.gradle.java.installations.auto-download=false >> $HOME/.gradle/gradle.properties\n        echo systemProp.org.gradle.java.installations.paths=${{ format('$JAVA_HOME_{0}_X64', inputs.java-version) }} >> $HOME/.gradle/gradle.properties\n"
  },
  {
    "path": ".github/actions/print-jvm-thread-dumps/action.yml",
    "content": "name: Print JVM thread dumps\ndescription: 'Prints a thread dump for all running JVMs'\nruns:\n  using: composite\n  steps:\n    - if: ${{ runner.os == 'Linux' }}\n      shell: bash\n      run: |\n        for jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem); do\n          jcmd $jvm_pid Thread.print\n        done\n    - if: ${{ runner.os == 'Windows' }}\n      shell: powershell\n      run: |\n        foreach ($jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem)) {\n          jcmd $jvm_pid Thread.print\n        }\n"
  },
  {
    "path": ".github/actions/publish-gradle-plugin/action.yml",
    "content": "name: Publish Gradle Plugin\ndescription: 'Publishes Spring Boot''s Gradle plugin to the Plugin Portal'\ninputs:\n  build-number:\n    description: 'Build number to use when downloading plugin artifacts'\n    required: false\n    default: ${{ github.run_number }}\n  gradle-plugin-publish-key:\n    description: 'Gradle publishing key'\n    required: true\n  gradle-plugin-publish-secret:\n    description: 'Gradle publishing secret'\n    required: true\n  jfrog-cli-config-token:\n    description: 'Config token for the JFrog CLI'\n    required: true\n  plugin-version:\n    description: 'Version of the plugin'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Set Up JFrog CLI\n      uses: jfrog/setup-jfrog-cli@1641575d87647fb969c0545f0b6a76873e328b7c # v5.0.0\n      env:\n        JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}\n    - name: Download Artifacts\n      shell: bash\n      run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-boot-{0}', inputs.plugin-version) }};buildNumber=${{ inputs.build-number }}'\n    - name: Set Up Java\n      uses: actions/setup-java@v5\n      with:\n        distribution: 'liberica'\n        java-version: '17'\n    - name: Publish\n      shell: bash\n      working-directory: ${{ github.action_path }}\n      run: ${{ github.workspace }}/gradlew publishExisting -Pgradle.publish.key=${{ inputs.gradle-plugin-publish-key }} -Pgradle.publish.secret=${{ inputs.gradle-plugin-publish-secret }} -PbootVersion=${{ inputs.plugin-version }} -PrepositoryRoot=${{ github.workspace }}/repository\n"
  },
  {
    "path": ".github/actions/publish-gradle-plugin/artifacts.spec",
    "content": "{\n  \"files\": [\n    {\n      \"aql\": {\n        \"items.find\": {\n          \"$and\": [\n            {\n              \"@build.name\": \"${buildName}\",\n              \"@build.number\": \"${buildNumber}\",\n              \"path\": {\n                \"$match\": \"org/springframework/boot/spring-boot-gradle-plugin/*\"\n              }\n            }\n          ]\n        }\n      },\n      \"target\": \"repository/\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/actions/publish-gradle-plugin/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"com.gradle.plugin-publish\" version \"1.2.1\"\n}\n\ntasks.register(\"publishExisting\", com.gradle.publish.PublishExistingTask) {\n\tpluginId = \"org.springframework.boot\"\n\tfileRepositoryRoot = new File(\"${repositoryRoot}\")\n\tpluginVersion = \"${bootVersion}\"\n\tpluginCoordinates = \"org.springframework.boot:spring-boot-gradle-plugin:${bootVersion}\"\n\tdisplayName = \"Spring Boot Gradle Plugin\"\n\tpluginDescription = \"Spring Boot Gradle Plugin\"\n\twebsite = \"https://spring.io/projects/spring-boot\"\n\tvcsUrl = \"https://github.com/spring-projects/spring-boot\"\n}\n"
  },
  {
    "path": ".github/actions/publish-gradle-plugin/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n"
  },
  {
    "path": ".github/actions/publish-to-sdkman/action.yml",
    "content": "name: Publish to SDKMAN!\ndescription: 'Publishes the release as a new candidate version on SDKMAN!'\ninputs:\n  make-default:\n    description: 'Whether the release should be made the default version'\n    required: false\n    default: 'false'\n  sdkman-consumer-key:\n    description: 'Key for publishing to SDKMAN!'\n    required: true\n  sdkman-consumer-token:\n    description: 'Token for publishing to SDKMAN!'\n    required: true\n  spring-boot-version:\n    description: 'Version to publish'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Publish Release\n      shell: bash\n      run: >\n        curl -X POST \\\n          -H \"Consumer-Key: ${{ inputs.sdkman-consumer-key }}\" \\\n          -H \"Consumer-Token: ${{ inputs.sdkman-consumer-token }}\" \\\n          -H \"Content-Type: application/json\" \\\n          -H \"Accept: application/json\" \\\n          -d '{\"candidate\": \"springboot\", \"version\": \"${{ inputs.spring-boot-version }}\", \"url\": \"${{ format('https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/{0}/spring-boot-cli-{0}-bin.zip', inputs.spring-boot-version) }}\"}' \\\n          https://vendors.sdkman.io/release\n    - name: Flag Release as Default\n      if: ${{ inputs.make-default == 'true' }}\n      shell: bash\n      run: >\n        curl -X PUT \\\n          -H \"Consumer-Key: ${{ inputs.sdkman-consumer-key }}\" \\\n          -H \"Consumer-Token: ${{ inputs.sdkman-consumer-token }}\" \\\n          -H \"Content-Type: application/json\" \\\n          -H \"Accept: application/json\" \\\n          -d '{\"candidate\": \"springboot\", \"version\": \"${{ inputs.spring-boot-version }}\"}' \\\n          https://vendors.sdkman.io/default\n"
  },
  {
    "path": ".github/actions/send-notification/action.yml",
    "content": "name: Send Notification\ndescription: 'Sends a Google Chat message as a notification of the job''s outcome'\ninputs:\n  build-scan-url:\n    description: 'URL of the build scan to include in the notification'\n    required: false\n  run-name:\n    description: 'Name of the run to include in the notification'\n    required: false\n    default: ${{ format('{0} {1}', github.ref_name, github.job) }}\n  status:\n    description: 'Status of the job'\n    required: true\n  webhook-url:\n    description: 'Google Chat Webhook URL'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Prepare Variables\n      shell: bash\n      run: |\n        echo \"BUILD_SCAN=${{ inputs.build-scan-url == '' && ' [build scan unavailable]' || format(' [<{0}|Build Scan>]', inputs.build-scan-url) }}\" >> \"$GITHUB_ENV\"\n        echo \"RUN_URL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\" >> \"$GITHUB_ENV\"\n    - name: Success Notification\n      if: ${{ inputs.status == 'success' }}\n      shell: bash\n      run: |\n        curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: \"<${{ env.RUN_URL }}|${{ inputs.run-name }}> was successful ${{ env.BUILD_SCAN }}\"}' || true\n    - name: Failure Notification\n      if: ${{ inputs.status == 'failure' }}\n      shell: bash\n      run: |\n        curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: \"<users/all> *<${{ env.RUN_URL }}|${{ inputs.run-name }}> failed* ${{ env.BUILD_SCAN }}\"}' || true\n    - name: Cancel Notification\n      if: ${{ inputs.status == 'cancelled' }}\n      shell: bash\n      run: |\n        curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: \"<${{ env.RUN_URL }}|${{ inputs.run-name }}> was cancelled\"}' || true\n"
  },
  {
    "path": ".github/actions/sync-to-maven-central/action.yml",
    "content": "name: Sync to Maven Central\ndescription: 'Syncs a release to Maven Central and waits for it to be available for use'\ninputs:\n  central-token-password:\n    description: 'Password for authentication with central.sonatype.com'\n    required: true\n  central-token-username:\n    description: 'Username for authentication with central.sonatype.com'\n    required: true\n  jfrog-cli-config-token:\n    description: 'Config token for the JFrog CLI'\n    required: true\n  spring-boot-version:\n    description: 'Version of Spring Boot that is being synced to Central'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Set Up JFrog CLI\n      uses: jfrog/setup-jfrog-cli@1641575d87647fb969c0545f0b6a76873e328b7c # v5.0.0\n      env:\n        JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}\n    - name: Download Release Artifacts\n      shell: bash\n      run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-boot-{0}', inputs.spring-boot-version) }};buildNumber=${{ github.run_number }}'\n    - name: Sync\n      uses: spring-io/central-publish-action@0c03960e9b16fdfe70e2443e1d5393cbc3a35622 # v0.3.0\n      with:\n        token: ${{ inputs.central-token-password }}\n        token-name: ${{ inputs.central-token-username }}\n        ignore-already-exists-error: true\n        timeout: \"90m\"\n    - name: Await\n      uses: ./.github/actions/await-http-resource\n      with:\n        url: ${{ format('https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot/{0}/spring-boot-{0}.jar', inputs.spring-boot-version) }}\n"
  },
  {
    "path": ".github/actions/sync-to-maven-central/artifacts.spec",
    "content": "{\n  \"files\": [\n    {\n      \"aql\": {\n        \"items.find\": {\n          \"$and\": [\n            {\n              \"@build.name\": \"${buildName}\",\n              \"@build.number\": \"${buildNumber}\",\n              \"path\": {\n                \"$nmatch\": \"org/springframework/boot/spring-boot-docs/*\"\n              }\n            }\n          ]\n        }\n      },\n      \"target\": \"nexus/\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".github/actions/update-homebrew-tap/action.yml",
    "content": "name: Update Homebrew Tap\ndescription: Updates the Homebrew Tap for the Spring Boot CLI\ninputs:\n  spring-boot-version:\n    description: 'The version to publish'\n    required: true\n  token:\n    description: 'Token to use for GitHub authentication'\n    required: true\nruns:\n  using: composite\n  steps:\n    - name: Check Out Homebrew Tap Repo\n      uses: actions/checkout@v6\n      with:\n        path: updated-homebrew-tap-repo\n        repository: spring-io/homebrew-tap\n        token: ${{ inputs.token }}\n    - name: Await Formula\n      uses: ./.github/actions/await-http-resource\n      with:\n        url: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/${{ inputs.spring-boot-version }}/spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb\n    - name: Update Homebrew Tap\n      shell: bash\n      run: |\n        pushd updated-homebrew-tap-repo > /dev/null\n        curl https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/${{ inputs.spring-boot-version }}/spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb --output spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb\n        rm spring-boot.rb\n        mv spring-boot-cli-*.rb spring-boot.rb\n        git config user.name \"Spring Builds\" > /dev/null\n        git config user.email \"spring-builds@users.noreply.github.com\" > /dev/null\n        git add spring-boot.rb > /dev/null\n        git commit -m \"Upgrade to Spring Boot ${{ inputs.spring-boot-version }}\" > /dev/null\n        git push\n        echo \"DONE\"\n        popd > /dev/null\n"
  },
  {
    "path": ".github/dco.yml",
    "content": "require:\n  members: false\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"type: task\"\n      - \"status: waiting-for-triage\"\n  - package-ecosystem: \"npm\"\n    directory: \"/antora\"\n    schedule:\n      interval: \"weekly\"\n    labels:\n      - \"type: task\"\n      - \"status: waiting-for-triage\"\n"
  },
  {
    "path": ".github/scripts/reclaim-docker-diskspace.sh",
    "content": "#!/bin/bash\n\necho \"Reclaiming Docker Disk Space\"\necho\n\ndocker image ls --format \"{{.Size}} {{.ID}} {{.Repository}} {{.Tag}}\" | LANG=en_US sort -rh | while read line; do\n\tsize=$( echo \"$line\" | cut -d' ' -f1 | sed -e 's/\\.[0-9]*//' | sed -e 's/MB/000000/' | sed -e 's/GB/000000000/' )\n\timage=$( echo \"$line\" | cut -d' ' -f2 )\n\trepository=$( echo \"$line\" | cut -d' ' -f3 )\n\ttag=$( echo \"$line\" | cut -d' ' -f4 )\n\techo \"Considering $image $repository:$tag $size\"\n\tif [[ \"$tag\" =~ ^[a-f0-9]{32}$ ]]; then\n\t\techo \"Ignoring GitHub action image $image $repository:$tag\"\n\telif [[ \"$tag\" == \"<none>\" ]]; then\n\t\techo \"Ignoring untagged image $image $repository:$tag\"\n\telif [[ \"$size\" -lt 200000000 ]]; then\n\t\techo \"Ignoring small image $image $repository:$tag\"\n\telse\n\t\techo \"Cleaning $image $repository:$tag\"\n\t\tdocker image rm $image\n\tfi\ndone\n\necho \"Finished cleanup, leaving the following containers:\"\necho\ndocker image ls --format \"{{.Size}} {{.ID}} {{.Repository}}:{{.Tag}}\" | LANG=en_US sort -rh\necho\ndf -h\necho\n"
  },
  {
    "path": ".github/workflows/build-and-deploy-snapshot.yml",
    "content": "name: Build and Deploy Snapshot\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - 'main'\npermissions:\n  contents: read\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\njobs:\n  build-and-deploy-snapshot:\n    name: Build and Deploy Snapshot\n    if: ${{ github.repository == 'spring-projects/spring-boot' || github.repository == 'spring-projects/spring-boot-commercial' }}\n    runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Build and Publish\n        id: build-and-publish\n        uses: ./.github/actions/build\n        with:\n          commercial-release-repository-url: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }}\n          commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\n          commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}\n          commercial-snapshot-repository-url: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}\n          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}\n          gradle-cache-read-only: false\n          publish: true\n      - name: Deploy\n        uses: spring-io/artifactory-deploy-action@926d7f7cc810569395346bf3a4d91b380b3e355b # v0.0.4\n        with:\n          build-name: ${{ vars.COMMERCIAL && format('spring-boot-commercial-{0}', '4.1.x') || format('spring-boot-{0}', '4.1.x') }}\n          folder: 'deployment-repository'\n          password: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_PASSWORD }}\n          project: ${{ vars.COMMERCIAL && 'spring' }}\n          repository: ${{ vars.COMMERCIAL && 'spring-enterprise-maven-dev-local' || 'libs-snapshot-local' }}\n          signing-key: ${{ secrets.GPG_PRIVATE_KEY }}\n          signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}\n          threads: 8\n          uri: ${{ vars.COMMERCIAL_DEPLOY_REPO_URL || 'https://repo.spring.io' }}\n          username: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_USERNAME }}\n      - name: Send Notification\n        if: always()\n        uses: ./.github/actions/send-notification\n        with:\n          build-scan-url: ${{ steps.build-and-publish.outputs.build-scan-url }}\n          run-name: ${{ format('{0} | Linux | Java 25', github.ref_name) }}\n          status: ${{ job.status }}\n          webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n    outputs:\n      version: ${{ steps.build-and-publish.outputs.version }}\n  trigger-docs-build:\n    name: Trigger Docs Build\n    needs: build-and-deploy-snapshot\n    permissions:\n      actions: write\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Run Deploy Docs Workflow\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-sha=${{ github.sha }} -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.build-and-deploy-snapshot.outputs.version }}\n  verify:\n    name: Verify\n    needs: build-and-deploy-snapshot\n    uses: ./.github/workflows/verify.yml\n    secrets:\n      commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\n      commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}\n      google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n      opensource-repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}\n      opensource-repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}\n      token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}\n    with:\n      version: ${{ needs.build-and-deploy-snapshot.outputs.version }}\n"
  },
  {
    "path": ".github/workflows/build-pull-request.yml",
    "content": "name: Build Pull Request\non: pull_request\npermissions:\n  contents: read\njobs:\n  build:\n    name: Build Pull Request\n    if: ${{ github.repository == 'spring-projects/spring-boot' }}\n    runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Build\n        id: build\n        uses: ./.github/actions/build\n      - name: Print JVM Thread Dumps When Cancelled\n        if: cancelled()\n        uses: ./.github/actions/print-jvm-thread-dumps\n      - name: Upload Build Reports\n        if: failure()\n        uses: actions/upload-artifact@v7\n        with:\n          name: build-reports\n          path: '**/build/reports/'\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\non:\n  push:\n    branches:\n      - 'main'\npermissions:\n  contents: read\njobs:\n  ci:\n    name: '${{ matrix.os.name}} | Java ${{ matrix.java.version}}'\n    if: ${{ github.repository == 'spring-projects/spring-boot' || github.repository == 'spring-projects/spring-boot-commercial' }}\n    runs-on: ${{ matrix.os.id }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os:\n          - id: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}\n            name: Linux\n          - id: windows-latest\n            name: Windows\n        java:\n          - version: 17\n            toolchain: true\n          - version: 21\n            toolchain: true\n          - version: 25\n            toolchain: false\n          - version: 26\n            toolchain: true\n        exclude:\n          - os:\n              name: Linux\n            java:\n              version: 25\n          - os:\n              name: ${{ github.repository == 'spring-projects/spring-boot-commercial' && 'Windows' }}\n    steps:\n      - name: Prepare Windows runner\n        if: ${{ runner.os == 'Windows' }}\n        run: |\n          git config --global core.autocrlf true\n          git config --global core.longPaths true\n          Stop-Service -name Docker\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Build\n        id: build\n        uses: ./.github/actions/build\n        with:\n          commercial-release-repository-url: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }}\n          commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\n          commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}\n          commercial-snapshot-repository-url: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}\n          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}\n          gradle-cache-read-only: false\n          java-early-access: ${{ matrix.java.early-access || 'false' }}\n          java-distribution: ${{ matrix.java.distribution }}\n          java-toolchain: ${{ matrix.java.toolchain }}\n          java-version: ${{ matrix.java.version }}\n      - name: Send Notification\n        if: always()\n        uses: ./.github/actions/send-notification\n        with:\n          build-scan-url: ${{ steps.build.outputs.build-scan-url }}\n          run-name: ${{ format('{0} | {1} | Java {2}', github.ref_name, matrix.os.name, matrix.java.version) }}\n          status: ${{ job.status }}\n          webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n"
  },
  {
    "path": ".github/workflows/distribute.yml",
    "content": "name: Distribute\non:\n  workflow_dispatch:\n    inputs:\n      build-number:\n        description: 'Number of the build to use to create the bundle'\n        required: true\n        type: string\n      create-bundle:\n        description: 'Whether to create the bundle. If unchecked, only the bundle distribution is executed'\n        required: true\n        type: boolean\n        default: true\n      version:\n        description: 'Version to bundle and distribute'\n        required: true\n        type: string\npermissions:\n  contents: read\njobs:\n  distribute-spring-enterprise-release-bundle:\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Create Bundle\n        if: ${{ vars.COMMERCIAL && inputs.create-bundle }}\n        shell: bash\n        run: |\n          curl -s -u \"${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}:${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\" \\\n            -X POST -H \"X-JFrog-Signing-Key-Name: packagesKey\" -H \"Content-Type: application/json\" \\\n            \"https://usw1.packages.broadcom.com/lifecycle/api/v2/release_bundle?project=spring\" \\\n            -d '{\"release_bundle_name\": \"TNZ-spring-boot-commercial\", \"release_bundle_version\": \"${{ inputs.version }}\", \"skip_docker_manifest_resolution\": true, \"source_type\": \"builds\", \"source\": {\"builds\": [ {\"build_repository\": \"spring-build-info\", \"build_name\": \"spring-boot-commercial-${{ inputs.version }}\", \"build_number\": \"${{ inputs.build-number }}\", \"include_dependencies\": false}]}}' | \\\n            jq -e 'if has(\"repository_key\") then . else halt_error end'\n      - name: Sleep\n        if: ${{ vars.COMMERCIAL && inputs.create-bundle }}\n        shell: bash\n        run: sleep 30\n      - name: Distribute Bundle\n        if: ${{ vars.COMMERCIAL }}\n        shell: bash\n        run: |\n          curl -s -u \"${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}:${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\" \\\n            -X POST -H \"Content-Type: application/json\" \\\n            \"https://usw1.packages.broadcom.com/lifecycle/api/v2/distribution/distribute/TNZ-spring-boot-commercial/${{ inputs.version }}?project=spring\" \\\n            -d '{\"auto_create_missing_repositories\": \"false\", \"distribution_rules\": [{\"site_name\": \"JP-SaaS\"}], \"modifications\": {\"mappings\": [{\"input\": \"spring-enterprise-maven-prod-local/(.*)\", \"output\": \"spring-enterprise/$1\"}]}}' | \\\n            jq -e 'if has(\"id\") then . else halt_error end'\n"
  },
  {
    "path": ".github/workflows/release-milestone.yml",
    "content": "name: Release Milestone\non:\n  push:\n    tags:\n      - v4.1.0-M[0-9]\n      - v4.1.0-RC[0-9]\npermissions:\n  contents: read\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\njobs:\n  build-and-stage-release:\n    name: Build and Stage Release\n    if: ${{ github.repository == 'spring-projects/spring-boot' }}\n    runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Build and Publish\n        id: build-and-publish\n        uses: ./.github/actions/build\n        with:\n          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}\n          gradle-cache-read-only: false\n          publish: true\n      - name: Stage Release\n        uses: spring-io/artifactory-deploy-action@926d7f7cc810569395346bf3a4d91b380b3e355b # v0.0.4\n        with:\n          build-name: ${{ format('spring-boot-{0}', steps.build-and-publish.outputs.version)}}\n          folder: 'deployment-repository'\n          password: ${{ secrets.ARTIFACTORY_PASSWORD }}\n          repository: 'libs-staging-local'\n          signing-key: ${{ secrets.GPG_PRIVATE_KEY }}\n          signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}\n          threads: 8\n          uri: 'https://repo.spring.io'\n          username: ${{ secrets.ARTIFACTORY_USERNAME }}\n    outputs:\n      version: ${{ steps.build-and-publish.outputs.version }}\n  verify:\n    name: Verify\n    needs: build-and-stage-release\n    uses: ./.github/workflows/verify.yml\n    secrets:\n      commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_RO_PASSWORD }}\n      commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_RO_USERNAME }}\n      google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n      opensource-repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}\n      opensource-repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}\n      token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}\n    with:\n      staging: true\n      version: ${{ needs.build-and-stage-release.outputs.version }}\n  sync-to-maven-central:\n    name: Sync to Maven Central\n    if: ${{ !vars.COMMERCIAL }}\n    needs:\n      - build-and-stage-release\n      - verify\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Sync to Maven Central\n        uses: ./.github/actions/sync-to-maven-central\n        with:\n          central-token-password: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}\n          central-token-username: ${{ secrets.CENTRAL_TOKEN_USERNAME }}\n          jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }}\n          spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}\n  promote-release:\n    name: Promote Release\n    needs:\n      - build-and-stage-release\n      - sync-to-maven-central\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Set up JFrog CLI\n        uses: jfrog/setup-jfrog-cli@1641575d87647fb969c0545f0b6a76873e328b7c # v5.0.0\n        env:\n          JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}\n      - name: Promote build\n        run: jfrog rt build-promote ${{ format('spring-boot-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-milestone-local\n  publish-gradle-plugin:\n    name: Publish Gradle Plugin\n    if: ${{ !vars.COMMERCIAL }}\n    needs:\n      - build-and-stage-release\n      - sync-to-maven-central\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Publish\n        uses: ./.github/actions/publish-gradle-plugin\n        with:\n          gradle-plugin-publish-key: ${{ secrets.GRADLE_PLUGIN_PUBLISH_KEY }}\n          gradle-plugin-publish-secret: ${{ secrets.GRADLE_PLUGIN_PUBLISH_SECRET }}\n          jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }}\n          plugin-version: ${{ needs.build-and-stage-release.outputs.version }}\n  trigger-docs-build:\n    name: Trigger Docs Build\n    needs:\n      - build-and-stage-release\n      - promote-release\n    permissions:\n      actions: write\n    runs-on: ubuntu-latest\n    steps:\n      - name: Run Deploy Docs Workflow\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.build-and-stage-release.outputs.version }}\n  create-github-release:\n    name: Create GitHub Release\n    needs:\n      - build-and-stage-release\n      - promote-release\n      - publish-gradle-plugin\n      - trigger-docs-build\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Create GitHub Release\n        uses: ./.github/actions/create-github-release\n        with:\n          commercial: ${{ vars.COMMERCIAL }}\n          milestone: ${{ needs.build-and-stage-release.outputs.version }}\n          pre-release: true\n          token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  push:\n    tags:\n      - v4.1.[0-9]+\npermissions:\n  contents: read\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.ref }}\njobs:\n  build-and-stage-release:\n    name: Build and Stage Release\n    if: ${{ github.repository == 'spring-projects/spring-boot' || github.repository == 'spring-projects/spring-boot-commercial' }}\n    runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Build and Publish\n        id: build-and-publish\n        uses: ./.github/actions/build\n        with:\n          commercial-release-repository-url: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }}\n          commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\n          commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}\n          commercial-snapshot-repository-url: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }}\n          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}\n          gradle-cache-read-only: false\n          publish: true\n      - name: Stage Release\n        uses: spring-io/artifactory-deploy-action@926d7f7cc810569395346bf3a4d91b380b3e355b # v0.0.4\n        with:\n          build-name: ${{ vars.COMMERCIAL && format('spring-boot-commercial-{0}', steps.build-and-publish.outputs.version) || format('spring-boot-{0}', steps.build-and-publish.outputs.version) }}\n          folder: 'deployment-repository'\n          password: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_PASSWORD }}\n          project: ${{ vars.COMMERCIAL && 'spring' }}\n          repository: ${{ vars.COMMERCIAL && 'spring-enterprise-maven-stage-local' || 'libs-staging-local' }}\n          signing-key: ${{ secrets.GPG_PRIVATE_KEY }}\n          signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}\n          threads: 8\n          uri: ${{ vars.COMMERCIAL_DEPLOY_REPO_URL || 'https://repo.spring.io' }}\n          username: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_USERNAME }}\n      - name: Send Notification\n        if: failure()\n        uses: ./.github/actions/send-notification\n        with:\n          run-name: ${{ format('{0} | Release Staging | {1}', github.ref_name, inputs.version) }}\n          status: ${{ job.status }}\n          webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n    outputs:\n      version: ${{ steps.build-and-publish.outputs.version }}\n  verify:\n    name: Verify\n    needs: build-and-stage-release\n    uses: ./.github/workflows/verify.yml\n    secrets:\n      commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\n      commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}\n      google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n      opensource-repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}\n      opensource-repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}\n      token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}\n    with:\n      staging: true\n      version: ${{ needs.build-and-stage-release.outputs.version }}\n  sync-to-maven-central:\n    name: Sync to Maven Central\n    if: ${{ !vars.COMMERCIAL }}\n    needs:\n      - build-and-stage-release\n      - verify\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Sync to Maven Central\n        uses: ./.github/actions/sync-to-maven-central\n        with:\n          central-token-password: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}\n          central-token-username: ${{ secrets.CENTRAL_TOKEN_USERNAME }}\n          jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }}\n          spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}\n  promote-release:\n    name: Promote Release\n    needs:\n      - build-and-stage-release\n      - sync-to-maven-central\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Set up JFrog CLI\n        uses: jfrog/setup-jfrog-cli@1641575d87647fb969c0545f0b6a76873e328b7c # v5.0.0\n        env:\n          JF_ENV_SPRING: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_JF_ARTIFACTORY_SPRING || secrets.JF_ARTIFACTORY_SPRING }}\n      - name: Promote open source build\n        if: ${{ !vars.COMMERCIAL }}\n        run: jfrog rt build-promote ${{ format('spring-boot-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-release-local\n      - name: Promote commercial build\n        if: ${{ vars.COMMERCIAL }}\n        run: jfrog rt build-promote ${{ format('spring-boot-commercial-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} spring-enterprise-maven-prod-local --project spring\n  publish-gradle-plugin:\n    name: Publish Gradle Plugin\n    if: ${{ !vars.COMMERCIAL }}\n    needs:\n      - build-and-stage-release\n      - sync-to-maven-central\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Publish\n        uses: ./.github/actions/publish-gradle-plugin\n        with:\n          gradle-plugin-publish-key: ${{ secrets.GRADLE_PLUGIN_PUBLISH_KEY }}\n          gradle-plugin-publish-secret: ${{ secrets.GRADLE_PLUGIN_PUBLISH_SECRET }}\n          jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }}\n          plugin-version: ${{ needs.build-and-stage-release.outputs.version }}\n  publish-to-sdkman:\n    name: Publish to SDKMAN!\n    if: ${{ !vars.COMMERCIAL }}\n    needs:\n      - build-and-stage-release\n      - sync-to-maven-central\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Publish to SDKMAN!\n        uses: ./.github/actions/publish-to-sdkman\n        with:\n          make-default: true\n          sdkman-consumer-key: ${{ secrets.SDKMAN_CONSUMER_KEY }}\n          sdkman-consumer-token: ${{ secrets.SDKMAN_CONSUMER_TOKEN }}\n          spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}\n  update-homebrew-tap:\n    name: Update Homebrew Tap\n    needs:\n      - build-and-stage-release\n      - sync-to-maven-central\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Update Homebrew Tap\n        uses: ./.github/actions/update-homebrew-tap\n        with:\n          spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }}\n          token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}\n  trigger-docs-build:\n    name: Trigger Docs Build\n    needs:\n      - build-and-stage-release\n      - promote-release\n    permissions:\n      actions: write\n    runs-on: ubuntu-latest\n    steps:\n      - name: Run Deploy Docs Workflow\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.build-and-stage-release.outputs.version }}\n  create-github-release:\n    name: Create GitHub Release\n    needs:\n      - build-and-stage-release\n      - promote-release\n      - publish-gradle-plugin\n      - publish-to-sdkman\n      - trigger-docs-build\n      - update-homebrew-tap\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Create GitHub Release\n        uses: ./.github/actions/create-github-release\n        with:\n          commercial: ${{ vars.COMMERCIAL }}\n          milestone: ${{ needs.build-and-stage-release.outputs.version }}\n          token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/run-codeql-analysis.yml",
    "content": "name: \"Run CodeQL Analysis\"\non:\n  push:\n  pull_request:\n  workflow_dispatch:\npermissions: read-all\njobs:\n  run-analysis:\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n    uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@6e66995f7d29de1e4ff76e4f0def7a10163fe910\n"
  },
  {
    "path": ".github/workflows/run-system-tests.yml",
    "content": "name: Run System Tests\non:\n  push:\n    branches:\n      - \"main\"\npermissions:\n  contents: read\njobs:\n  run-system-tests:\n    name: \"Java ${{ matrix.java.version}}\"\n    if: ${{ github.repository == 'spring-projects/spring-boot' }}\n    runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }}\n    strategy:\n      matrix:\n        java:\n          - version: 17\n            toolchain: true\n          - version: 21\n            toolchain: true\n    steps:\n      - name: Switch Docker to Overlay2\n        shell: bash\n        run: |\n          echo '{\"storage-driver\":\"overlay2\"}' | sudo tee /etc/docker/daemon.json\n          sudo systemctl restart docker\n      - name: Check Out Code\n        uses: actions/checkout@v6\n      - name: Prepare Gradle Build\n        uses: ./.github/actions/prepare-gradle-build\n        with:\n          develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}\n          java-toolchain: ${{ matrix.java.toolchain }}\n          java-version: ${{ matrix.java.version }}\n      - name: Run System Tests\n        id: run-system-tests\n        shell: bash\n        run: ./gradlew systemTest\n      - name: Show docker info\n        if: always()\n        shell: bash\n        run: docker version ; docker info\n      - name: List docker images\n        if: always()\n        shell: bash\n        run: docker image ls --digests\n      - name: Send Notification\n        if: always()\n        uses: ./.github/actions/send-notification\n        with:\n          build-scan-url: ${{ steps.run-system-tests.outputs.build-scan-url }}\n          run-name: ${{ format('{0} | System Tests | Java {1}', github.ref_name, matrix.java.version) }}\n          status: ${{ job.status }}\n          webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}\n"
  },
  {
    "path": ".github/workflows/trigger-docs-build.yml",
    "content": "name: Trigger Docs Build\non:\n  push:\n    branches: 'main'\n    paths: [ 'antora/*' ]\n  workflow_dispatch:\n    inputs:\n      build-version:\n        description: 'Version being build (e.g. 1.0.3-SNAPSHOT)'\n        required: false\n      build-sha:\n        description: Enter the SHA to build (e.g. 82c97891569821a7f91a77ca074232e0b54ca7a5)\n        required: false\n      build-refname:\n        description: 'Git refname to build (e.g., 1.0.x)'\n        required: false\n\npermissions:\n  contents: read\njobs:\n  trigger-docs-build:\n    name: Trigger Docs Build\n    if: github.repository_owner == 'spring-projects'\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    permissions:\n      actions: write\n    steps:\n    - name: Check Out\n      uses: actions/checkout@v6\n      with:\n        ref: docs-build\n    - name: Trigger Workflow\n      env:\n        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      run: gh workflow run deploy-docs.yml -r docs-build -f build-refname=${{ github.event.inputs.build-refname }} -f build-sha=${{ github.event.inputs.build-sha }} -f build-version=${{ github.event.inputs.build-version }}\n"
  },
  {
    "path": ".github/workflows/verify.yml",
    "content": "name: Verify\non:\n  workflow_call:\n    inputs:\n      staging:\n        description: 'Whether the release to verify is in the staging repository'\n        required: false\n        default: false\n        type: boolean\n      version:\n        description: 'Version to verify'\n        required: true\n        type: string\n    secrets:\n      commercial-repository-password:\n        description: 'Password for authentication with the commercial repository'\n        required: false\n      commercial-repository-username:\n        description: 'Username for authentication with the commercial repository'\n        required: false\n      google-chat-webhook-url:\n        description: 'Google Chat Webhook URL'\n        required: true\n      opensource-repository-password:\n        description: 'Password for authentication with the open-source repository'\n        required: false\n      opensource-repository-username:\n        description: 'Username for authentication with the open-source repository'\n        required: false\n      token:\n        description: 'Token to use for authentication with GitHub'\n        required: true\npermissions:\n  contents: read\njobs:\n  verify:\n    name: Verify\n    runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}\n    steps:\n      - name: Check Out Release Verification Tests\n        uses: actions/checkout@v6\n        with:\n          ref: 'v0.0.15'\n          repository: spring-projects/spring-boot-release-verification\n          token: ${{ secrets.token }}\n      - name: Check Out Send Notification Action\n        uses: actions/checkout@v6\n        with:\n          path: send-notification\n          sparse-checkout: .github/actions/send-notification\n      - name: Set Up Java\n        uses: actions/setup-java@v5\n        with:\n          distribution: 'liberica'\n          java-version: 17\n      - name: Set Up Homebrew\n        if: ${{ !vars.COMMERCIAL }}\n        uses: Homebrew/actions/setup-homebrew@7657c9512f50e1c35b640971116425935bab3eea\n        with:\n          stable: true\n      - name: Set Up Gradle\n        uses: gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2\n        with:\n          cache-read-only: false\n      - name: Configure Gradle Properties\n        shell: bash\n        run: |\n          mkdir -p $HOME/.gradle\n          echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties\n      - name: Run Release Verification Tests\n        env:\n          RVT_COMMERCIAL_REPOSITORY_PASSWORD: ${{ secrets.commercial-repository-password }}\n          RVT_COMMERCIAL_REPOSITORY_USERNAME: ${{ secrets.commercial-repository-username }}\n          RVT_OSS_REPOSITORY_PASSWORD: ${{ secrets.opensource-repository-password }}\n          RVT_OSS_REPOSITORY_USERNAME: ${{ secrets.opensource-repository-username }}\n          RVT_RELEASE_TYPE: ${{ vars.COMMERCIAL && 'commercial' || 'oss' }}\n          RVT_STAGING: ${{ inputs.staging }}\n          RVT_VERSION: ${{ inputs.version }}\n        run: ./gradlew spring-boot-release-verification-tests:test\n      - name: Upload Build Reports on Failure\n        if: failure()\n        uses: actions/upload-artifact@v7\n        with:\n          name: build-reports\n          path: '**/build/reports/'\n      - name: Send Notification\n        if: always()\n        uses: ./send-notification/.github/actions/send-notification\n        with:\n          run-name: ${{ format('{0} | Verification | {1}', github.ref_name, inputs.version) }}\n          status: ${{ job.status }}\n          webhook-url: ${{ secrets.google-chat-webhook-url }}\n"
  },
  {
    "path": ".gitignore",
    "content": "*#\n*.iml\n*.ipr\n*.iws\n*.jar\n*.sw?\n*~\n.#*\n.*.md.html\n.DS_Store\n.attach_pid*\n.classpath\n.factorypath\n.gradle\n.metadata\n.project\n.recommenders\n.settings\n.springBeans\n.vscode\n/code\nMANIFEST.MF\n_site/\nactivemq-data\nbin\nbuild\n!/**/src/**/bin\n!/**/src/**/build\nbuild.log\ndependency-reduced-pom.xml\ndump.rdb\ninterpolated*.xml\nlib/\nmanifest.yml\nout\noverridedb.*\ntarget\n.flattened-pom.xml\nsecrets.yml\n.gradletasknamecache\n.sts4-cache\n.git-hooks/\nnode_modules\n/.kotlin/\n"
  },
  {
    "path": ".idea/.gitignore",
    "content": "# Project name\n.name\n*.xml\n/modules/\n/shelf/\n/workspace.xml\n# Editor-based HTTP Client requests\n/httpRequests/\n# Datasource local storage ignored files\n/dataSources/\n/dataSources.local.xml\n"
  },
  {
    "path": ".sdkmanrc",
    "content": "# Enable auto-env through the sdkman_auto_env config\n# Add key=value pairs of SDKs to use below\njava=25.0.2-librca\n"
  },
  {
    "path": "CONTRIBUTING.adoc",
    "content": "= Contributing to Spring Boot\n\nSpring Boot is released under the Apache 2.0 license. If you would like to contribute something, or want to hack on the code this document should help you get started.\n\n\n\n== Code of Conduct\n\nThis project adheres to the Contributor Covenant https://github.com/spring-projects/spring-boot?tab=coc-ov-file#contributor-code-of-conduct[code of conduct].\nBy participating, you are expected to uphold this code. Please report unacceptable behavior to code-of-conduct@spring.io.\n\n\n\n== Using GitHub Issues\n\nWe use GitHub issues to track bugs and enhancements.\nIf you have a general usage question please ask on https://stackoverflow.com[Stack Overflow].\nThe Spring Boot team and the broader community monitor the https://stackoverflow.com/tags/spring-boot[`spring-boot`] tag.\n\nIf you are reporting a bug, please help to speed up problem diagnosis by providing as much information as possible.\nIdeally, that would include a small sample project that reproduces the problem.\n\n\n\n== Reporting Security Vulnerabilities\n\nIf you think you have found a security vulnerability in Spring Boot please *DO NOT* disclose it publicly until we've had a chance to fix it.\nPlease don't report security vulnerabilities using GitHub issues, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly.\n\n\n\n== Include a Signed Off By Trailer\n\nAll commits must include a __Signed-off-by__ trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin.\nFor additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring].\n\n\n\n== Code Conventions and Housekeeping\n\nNone of these is essential for a pull request, but they will all help.  They can also be\nadded after the original pull request but before a merge.\n\n* We use the https://github.com/spring-io/spring-javaformat/[Spring JavaFormat] project to apply code formatting conventions.\n  If you use Eclipse and you follow the https://github.com/spring-projects/spring-boot/wiki/Working-with-the-Code#importing-into-eclipse[\"Importing into Eclipse\"] instructions you should get project-specific formatting automatically.\n  You can also install the https://github.com/spring-io/spring-javaformat/#intellij-idea[Spring JavaFormat IntelliJ Plugin] or format the code from the Gradle build by running `./gradlew format`.\n  Note that if you have format violations in `buildSrc`, you can fix them by running `./gradlew -p buildSrc format` from the project root directory.\n* The build includes Checkstyle rules for many of our code conventions. Run `./gradlew checkstyleMain checkstyleTest` if you want to check your changes are compliant.\n* Make sure all new `.java` files have a Javadoc class comment with at least an `@author` tag identifying you, and preferably at least a paragraph on what the class is for.\n* Add the ASF license header comment to all new `.java` files (copy from existing files in the project).\n* Add yourself as an `@author` to the `.java` files that you modify substantially (more than cosmetic changes).\n* Add some Javadocs.\n* A few unit tests would help a lot as well -- someone has to do it.\n* Verification tasks, including tests and Checkstyle, can be executed by running `./gradlew check` from the project root.\n  Note that `SPRING_PROFILES_ACTIVE` environment variable might affect the result of tests, so in that case, you can prevent it by running `unset SPRING_PROFILES_ACTIVE` before running the task.\n* If no-one else is using your branch, please rebase it against the current main branch (or other target branch in the project).\n* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions].\n\n\n\n== Working with the Code\n\nFor information on editing, building, and testing the code, see the https://github.com/spring-projects/spring-boot/wiki/Working-with-the-Code[Working with the Code] page on the project wiki.\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.adoc",
    "content": "= Spring Boot image:https://github.com/spring-projects/spring-boot/actions/workflows/build-and-deploy-snapshot.yml/badge.svg?branch=main[\"Build Status\", link=\"https://github.com/spring-projects/spring-boot/actions/workflows/build-and-deploy-snapshot.yml?query=branch%3Amain\"] image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A[\"Revved up by Develocity\", link=\"https://ge.spring.io/scans?&search.rootProjectNames=Spring%20Boot%20Build&search.rootProjectNames=spring-boot-build\"]\n\n:docs: https://docs.spring.io/spring-boot\n:github: https://github.com/spring-projects/spring-boot\n\nSpring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.\nIt takes an opinionated view of the Spring platform so that new and existing users can quickly get to the bits they need.\n\nYou can use Spring Boot to create stand-alone Java applications that can be started using `java -jar` or more traditional WAR deployments.\nWe also provide a command-line tool that runs Spring scripts.\n\nOur primary goals are:\n\n* Provide a radically faster and widely accessible getting started experience for all Spring development.\n* Be opinionated, but get out of the way quickly as requirements start to diverge from the defaults.\n* Provide a range of non-functional features common to large classes of projects (for example, embedded servers, security, metrics, health checks, externalized configuration).\n* Absolutely no code generation and no requirement for XML configuration.\n\n\n\n== Installation and Getting Started\n\nThe {docs}[reference documentation] includes detailed {docs}/installing.html[installation instructions] as well as a comprehensive {docs}/tutorial/first-application/index.html[``getting started``] guide.\n\nHere is a quick teaser of a complete Spring Boot application in Java:\n\n[source,java]\n----\nimport org.springframework.boot.*;\nimport org.springframework.boot.autoconfigure.*;\nimport org.springframework.web.bind.annotation.*;\n\n@RestController\n@SpringBootApplication\npublic class Example {\n\n\t@RequestMapping(\"/\")\n\tString home() {\n\t\treturn \"Hello World!\";\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Example.class, args);\n\t}\n\n}\n----\n\n\n\n== Getting Help\n\nAre you having trouble with Spring Boot? We want to help!\n\n* Check the {docs}/[reference documentation], especially the {docs}/how-to/index.html[How-to's] -- they provide solutions to the most common questions.\n* Learn the Spring basics -- Spring Boot builds on many other Spring projects; check the https://spring.io[spring.io] website for a wealth of reference documentation.\n  If you are new to Spring, try one of the https://spring.io/guides[guides].\n* If you are upgrading, read the {github}/wiki[release notes] for upgrade instructions and \"new and noteworthy\" features.\n* Ask a question -- we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-boot[`spring-boot`].\n* Report bugs with Spring Boot at {github}/issues[github.com/spring-projects/spring-boot/issues].\n\n\n\n== Contributing\n\nWe welcome contributions of all kinds!\nPlease read our link:CONTRIBUTING.adoc[contribution guidelines] before submitting a pull request.\n\n\n\n== Reporting Issues\n\nSpring Boot uses GitHub's integrated issue tracking system to record bugs and feature requests.\nIf you want to raise an issue, please follow the recommendations below:\n\n* Before you log a bug, please search the {github}/issues[issue tracker] to see if someone has already reported the problem.\n* If the issue doesn't already exist, {github}/issues/new[create a new issue].\n* Please provide as much information as possible with the issue report.\nWe like to know the Spring Boot version, operating system, and JVM version you're using.\n* If you need to paste code or include a stack trace, use Markdown.\n+++```+++ escapes before and after your text.\n* If possible, try to create a test case or project that replicates the problem and attach it to the issue.\n\n\n\n== Building from Source\n\nYou don't need to build from source to use Spring Boot.\nIf you want to try out the latest and greatest, Spring Boot can be built and published to your local Maven cache using the https://docs.gradle.org/current/userguide/gradle_wrapper.html[Gradle wrapper].\nYou also need JDK 25.\n\n[source,shell]\n----\n$ ./gradlew publishToMavenLocal\n----\n\nThis command builds all modules and publishes them to your local Maven cache.\nIt won't run any of the tests.\nIf you want to build everything, use the `build` task:\n\n[source,shell]\n----\n$ ./gradlew build\n----\n\n\n\n== Guides\n\nThe https://spring.io/[spring.io] site contains several guides that show how to use Spring Boot step-by-step:\n\n* https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot] is an introductory guide that shows you how to create an application, run it, and add some management services.\n* https://spring.io/guides/gs/actuator-service/[Building a RESTful Web Service with Spring Boot Actuator] is a guide to creating a REST web service and also shows how the server can be configured.\n\n\n\n== License\n\nSpring Boot is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].\n"
  },
  {
    "path": "SUPPORT.adoc",
    "content": "= Getting support for Spring Boot\n\n\n\n== GitHub issues\n\nWe choose not to use GitHub issues for general usage questions and support, preferring to\nuse issues solely for the tracking of bugs and enhancements. If you have a general\nusage question please do not open a GitHub issue, but use one of the other channels\ndescribed below.\n\nIf you are reporting a bug, please help to speed up problem diagnosis by providing as\nmuch information as possible. Ideally, that would include a small sample project that\nreproduces the problem.\n\n\n\n== Stack Overflow\n\nThe Spring Boot community monitors the\nhttps://stackoverflow.com/tags/spring-boot[`spring-boot`] tag on Stack Overflow. Before\nasking a question, please familiarize yourself with Stack Overflow's\nhttps://stackoverflow.com/help/how-to-ask[advice on how to ask a good question].\n\n\n\n== VMware Tanzu Enterprise Support\n\nIf you are interested in more dedicated support, VMware Tanzu provides https://enterprise.spring.io/[enterprise support] for Spring Boot.\n"
  },
  {
    "path": "antora/package.json",
    "content": "{\n  \"scripts\": {\n    \"antora\": \"node npm/antora.js\"\n  },\n  \"dependencies\": {\n    \"@antora/cli\": \"3.2.0-alpha.11\",\n    \"@antora/site-generator\": \"3.2.0-alpha.11\",\n    \"@antora/atlas-extension\": \"1.0.0-alpha.5\",\n    \"@springio/antora-extensions\": \"1.14.10\",\n    \"@springio/antora-xref-extension\": \"1.0.0-alpha.5\",\n    \"@springio/antora-zip-contents-collector-extension\": \"1.0.0-alpha.10\",\n    \"@asciidoctor/tabs\": \"1.0.0-beta.6\",\n    \"@springio/asciidoctor-extensions\": \"1.0.0-alpha.18\"\n  },\n  \"config\": {\n    \"ui-bundle-url\": \"https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.26/ui-bundle.zip\"\n  }\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Antlib\"\n\next {\n\tantVersion = \"1.10.7\"\n}\n\nconfigurations {\n\tantUnit\n\tantIvy\n}\n\ndependencies {\n\tantUnit \"org.apache.ant:ant-antunit:1.3\"\n\n\tantIvy \"org.apache.ivy:ivy:2.5.0\"\n\n\tcompileOnly(project(\":loader:spring-boot-loader\"))\n\tcompileOnly(\"org.apache.ant:ant:${antVersion}\")\n\n\timplementation(project(\":loader:spring-boot-loader-tools\"))\n\timplementation(\"org.springframework:spring-core\")\n}\n\ntasks.register(\"syncIntegrationTestSources\", Sync) {\n\tdestinationDir = file(layout.buildDirectory.dir(\"it\"))\n\tfrom file(\"src/it\")\n\tfilter(springRepositoryTransformers.ant())\n}\n\nprocessResources {\n\tdef version = project.version\n\teachFile {\n\t\tfilter { it.replace('${spring-boot.version}', version) }\n\t}\n\tinputs.property \"version\", version\n}\n\ntasks.register(\"integrationTest\") {\n\tdependsOn syncIntegrationTestSources, jar\n\tdef resultsDir = file(layout.buildDirectory.dir(\"test-results/integrationTest\"))\n\tinputs.dir(file(\"src/it\")).withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName(\"source\")\n\tinputs.files(sourceSets.main.runtimeClasspath).withNormalizer(ClasspathNormalizer).withPropertyName(\"classpath\")\n\toutputs.dirs resultsDir\n\tdoLast {\n\t\tant.with {\n\t\t\ttaskdef(resource: \"org/apache/ant/antunit/antlib.xml\",\n\t\t\t\t\tclasspath: configurations.antUnit.asPath)\n\t\t\ttaskdef(resource: \"org/apache/ivy/ant/antlib.xml\",\n\t\t\t\t\tclasspath: configurations.antIvy.asPath)\n\t\t\ttaskdef(resource: \"org/springframework/boot/ant/antlib.xml\",\n\t\t\t\t\tclasspath: sourceSets.main.runtimeClasspath.asPath,\n\t\t\t\t\turi: \"antlib:org.springframework.boot.ant\")\n\t\t\tant.property(name: \"ivy.class.path\", value: configurations.antIvy.asPath)\n\t\t\tant.property(name: \"antunit.class.path\", value: configurations.antUnit.asPath)\n\t\t\tantunit {\n\t\t\t\tpropertyset {\n\t\t\t\t\tant.propertyref(name: \"build.compiler\")\n\t\t\t\t\tant.propertyref(name: \"antunit.class.path\")\n\t\t\t\t\tant.propertyref(name: \"ivy.class.path\")\n\t\t\t\t}\n\t\t\t\tplainlistener()\n\t\t\t\txmllistener(toDir: resultsDir)\n\t\t\t\tfileset(dir: layout.buildDirectory.dir(\"it\").get().asFile.toString(), includes: \"**/build.xml\")\n\t\t\t}\n\t\t}\n\t}\n}\n\ncheck {\n\tdependsOn integrationTest\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/it/sample/build.xml",
    "content": "<?xml version=\"1.0\"?>\n<project name=\"spring-boot-antlib-test\" default=\"antunit\" xmlns:au=\"antlib:org.apache.ant.antunit\" xmlns:spring-boot=\"antlib:org.springframework.boot.ant\" xmlns:ivy=\"antlib:org.apache.ivy.ant\">\n\n\t<property name=\"src.dir\" location=\"src/main/java\" />\n\t<property name=\"resource.dir\" location=\"src/main/resources\" />\n\t<property name=\"target.dir\" location=\"target\" />\n\t<property name=\"classes.dir\" location=\"${target.dir}/classes\" />\n\n\t<taskdef resource=\"org/apache/ivy/ant/antlib.xml\"\n\t\t\turi=\"antlib:org.apache.ivy.ant\" classpath=\"${ivy.class.path}\"/>\n\t<taskdef resource=\"org/apache/ant/antunit/antlib.xml\"\n\t\t\turi=\"antlib:org.apache.ant.antunit\" classpath=\"${antunit.class.path}\"/>\n\n\t<target name=\"setUp\">\n\t\t<ivy:cachepath inline=\"true\" pathid=\"compile.classpath\" organisation=\"joda-time\" module=\"joda-time\" type=\"jar\" revision=\"2.8.1\" />\n\t\t<mkdir dir=\"${classes.dir}\" />\n\t\t<javac srcdir=\"${src.dir}\" destdir=\"${classes.dir}\" classpathref=\"compile.classpath\" />\n\t\t<au:logcapturer/>\n\t</target>\n\n\t<target name=\"tearDown\">\n\t\t<delete dir=\"${classes.dir}\" />\n\t</target>\n\n\t<target name=\"test-findmainclass-set-property\" depends=\"setUp\">\n\t\t<spring-boot:findmainclass classesroot=\"${classes.dir}\" property=\"main-class\" />\n\t\t<au:assertEquals expected=\"org.test.SampleApplication\" actual=\"${main-class}\" />\n\t</target>\n\n\t<target name=\"test-findmainclass-log-message\" depends=\"setUp\">\n\t\t<spring-boot:findmainclass classesroot=\"${classes.dir}\" />\n\t\t<au:assertLogContains text=\"org.test.SampleApplication\" />\n\t</target>\n\n\t<target name=\"test-findmainclass-override\" depends=\"setUp\">\n\t\t<spring-boot:findmainclass mainclass=\"OVERRIDDEN\" property=\"main-class\" />\n\t\t<au:assertEquals expected=\"OVERRIDDEN\" actual=\"${main-class}\" />\n\t</target>\n\n\t<macrodef name=\"check-exejar\">\n\t\t<attribute name=\"jar\" />\n\t\t<sequential>\n\t\t\t<echo>Checking @{jar}</echo>\n\t\t\t<au:assertFileExists file=\"@{jar}\" />\n\n\t\t\t<javaresource id=\"foo\" name=\"foo\">\n\t\t\t\t<classpath>\n\t\t\t\t\t<pathelement location=\"@{jar}\" />\n\t\t\t\t</classpath>\n\t\t\t</javaresource>\n\t\t\t<au:assertRefResourceExists refid=\"foo\" />\n\t\t\t<au:assertRefResourceContains refid=\"foo\" value=\"FOO\" />\n\n\t\t\t<java jar=\"@{jar}\" fork=\"true\" />\n\t\t\t<au:assertLogContains text=\"LocalDate\" />\n\t\t</sequential>\n\t</macrodef>\n\n\t<target name=\"test-exejar-explicit-start-class\" depends=\"setUp\">\n\t\t<local name=\"jar\" />\n\t\t<property name=\"jar\" location=\"${target.dir}/explicit.jar\" />\n\t\t<spring-boot:exejar destfile=\"${jar}\" classes=\"${classes.dir}\" start-class=\"org.test.SampleApplication\">\n\t\t\t<resources>\n\t\t\t\t<fileset dir=\"${resource.dir}\" />\n\t\t\t</resources>\n\t\t\t<lib>\n\t\t\t\t<path refid=\"compile.classpath\" />\n\t\t\t</lib>\n\t\t</spring-boot:exejar>\n\t\t<check-exejar jar=\"${jar}\" />\n\t</target>\n\n\t<target name=\"test-exejar-find-start-class\" depends=\"setUp\">\n\t\t<local name=\"jar\" />\n\t\t<property name=\"jar\" location=\"${target.dir}/found.jar\" />\n\t\t<spring-boot:exejar destfile=\"${jar}\" classes=\"${classes.dir}\">\n\t\t\t<resources>\n\t\t\t\t<fileset dir=\"${resource.dir}\" />\n\t\t\t</resources>\n\t\t\t<lib>\n\t\t\t\t<path refid=\"compile.classpath\" />\n\t\t\t</lib>\n\t\t</spring-boot:exejar>\n\t\t<check-exejar jar=\"${jar}\" />\n\t</target>\n\n\t<target name=\"antunit\">\n\t\t<au:antunit>\n\t\t\t<au:plainlistener />\n\t\t\t<file file=\"${ant.file}\" />\n\t\t</au:antunit>\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<delete dir=\"${target.dir}\" />\n\t</target>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/it/sample/ivysettings.xml",
    "content": "<ivysettings>\n\t<settings defaultResolver=\"chain\" />\n\t<resolvers>\n\t\t<chain name=\"chain\">\n\t\t\t<filesystem name=\"local\" local=\"true\" m2compatible=\"true\">\n\t\t\t\t<artifact pattern=\"${user.home}/.m2/[organisation]/[module]/[revision]/[module]-[revision].[ext]\" />\n\t\t\t\t<ivy pattern=\"${user.home}/.m2/[organisation]/[module]/[revision]/[module]-[revision].pom\" />\n\t\t\t</filesystem>\n\t\t\t<ibiblio name=\"ibiblio\" m2compatible=\"true\" />\n\t\t\t<!-- {spring.mavenRepositories} -->\n\t\t</chain>\n\t</resolvers>\n\t<!-- {spring.mavenCredentials} -->\n</ivysettings>\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/it/sample/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.joda.time.LocalDate;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(LocalDate.class.getSimpleName());\n\t}\n\n}\n\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/it/sample/src/main/resources/foo",
    "content": "FOO\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/main/java/org/springframework/boot/ant/FindMainClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ant;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.JarFile;\n\nimport org.apache.tools.ant.BuildException;\nimport org.apache.tools.ant.Project;\nimport org.apache.tools.ant.Task;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.MainClassFinder;\nimport org.springframework.util.StringUtils;\n\n/**\n * Ant task to find a main class.\n *\n * @author Matt Benson\n * @since 1.3.0\n */\npublic class FindMainClass extends Task {\n\n\tprivate static final String SPRING_BOOT_APPLICATION_CLASS_NAME = \"org.springframework.boot.autoconfigure.SpringBootApplication\";\n\n\tprivate @Nullable String mainClass;\n\n\tprivate @Nullable File classesRoot;\n\n\tprivate @Nullable String property;\n\n\tpublic FindMainClass(Project project) {\n\t\tsetProject(project);\n\t}\n\n\t@Override\n\tpublic void execute() throws BuildException {\n\t\tString mainClass = this.mainClass;\n\t\tif (!StringUtils.hasText(mainClass)) {\n\t\t\tmainClass = findMainClass();\n\t\t\tif (!StringUtils.hasText(mainClass)) {\n\t\t\t\tthrow new BuildException(\"Could not determine main class given @classesRoot \" + this.classesRoot);\n\t\t\t}\n\t\t}\n\t\thandle(mainClass);\n\t}\n\n\tprivate @Nullable String findMainClass() {\n\t\tif (this.classesRoot == null) {\n\t\t\tthrow new BuildException(\"one of @mainClass or @classesRoot must be specified\");\n\t\t}\n\t\tif (!this.classesRoot.exists()) {\n\t\t\tthrow new BuildException(\"@classesRoot \" + this.classesRoot + \" does not exist\");\n\t\t}\n\t\ttry {\n\t\t\tif (this.classesRoot.isDirectory()) {\n\t\t\t\treturn MainClassFinder.findSingleMainClass(this.classesRoot, SPRING_BOOT_APPLICATION_CLASS_NAME);\n\t\t\t}\n\t\t\treturn MainClassFinder.findSingleMainClass(new JarFile(this.classesRoot), \"/\",\n\t\t\t\t\tSPRING_BOOT_APPLICATION_CLASS_NAME);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new BuildException(ex);\n\t\t}\n\t}\n\n\tprivate void handle(String mainClass) {\n\t\tif (StringUtils.hasText(this.property)) {\n\t\t\tgetProject().setProperty(this.property, mainClass);\n\t\t}\n\t\telse {\n\t\t\tlog(\"Found main class \" + mainClass);\n\t\t}\n\t}\n\n\t/**\n\t * Set the main class, which will cause the search to be bypassed.\n\t * @param mainClass the main class name\n\t */\n\tpublic void setMainClass(String mainClass) {\n\t\tthis.mainClass = mainClass;\n\t}\n\n\t/**\n\t * Set the root location of classes to be searched.\n\t * @param classesRoot the root location\n\t */\n\tpublic void setClassesRoot(File classesRoot) {\n\t\tthis.classesRoot = classesRoot;\n\t}\n\n\t/**\n\t * Set the ANT property to set (if left unset, result will be printed to the log).\n\t * @param property the ANT property to set\n\t */\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/main/java/org/springframework/boot/ant/ShareAntlibLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ant;\n\nimport org.apache.tools.ant.BuildException;\nimport org.apache.tools.ant.Project;\nimport org.apache.tools.ant.Task;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Quiet task that establishes a reference to its loader.\n *\n * @author Matt Benson\n * @since 1.3.0\n */\npublic class ShareAntlibLoader extends Task {\n\n\tprivate @Nullable String refid;\n\n\tpublic ShareAntlibLoader(Project project) {\n\t\tsetProject(project);\n\t}\n\n\t@Override\n\tpublic void execute() throws BuildException {\n\t\tif (!StringUtils.hasText(this.refid)) {\n\t\t\tthrow new BuildException(\"@refid has no text\");\n\t\t}\n\t\tgetProject().addReference(this.refid, getClass().getClassLoader());\n\t}\n\n\tpublic void setRefid(@Nullable String refid) {\n\t\tthis.refid = refid;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/main/java/org/springframework/boot/ant/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for building Spring Boot applications using Ant.\n */\n@NullMarked\npackage org.springframework.boot.ant;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-antlib/src/main/resources/org/springframework/boot/ant/antlib.xml",
    "content": "<?xml version=\"1.0\"?>\n<antlib>\n\n\t<taskdef name=\"findmainclass\" classname=\"org.springframework.boot.ant.FindMainClass\" />\n\n\t<!-- unadvertised taskdef to help pull antlib resources from within the antlib.xml file -->\n\t<taskdef name=\"spring-boot-antlib-share-antlib-loader\" classname=\"org.springframework.boot.ant.ShareAntlibLoader\" />\n\n\t<macrodef name=\"exejar\" description=\"Create a spring-boot executable jar\">\n\t\t<attribute name=\"destfile\" />\n\t\t<attribute name=\"classes\" />\n\t\t<attribute name=\"start-class\" default=\"\" />\n\n\t\t<element name=\"resources\" optional=\"true\"\n\t\t\tdescription=\"includes resource collections specifying additional Java resources\" />\n\n\t\t<element name=\"lib\" optional=\"true\"\n\t\t\tdescription=\"includes resource collections containing (jar) dependencies\" />\n\n\t\t<sequential>\n\t\t\t<local name=\"start-class\" />\n\n\t\t\t<findmainclass\n\t\t\t\txmlns=\"antlib:org.springframework.boot.ant\"\n\t\t\t\tproperty=\"start-class\"\n\t\t\t\tmainclass=\"@{start-class}\"\n\t\t\t\tclassesroot=\"@{classes}\" />\n\n\t\t\t<echo>Using start class ${start-class}</echo>\n\n\t\t\t<spring-boot-antlib-share-antlib-loader\n\t\t\t\txmlns=\"antlib:org.springframework.boot.ant\"\n\t\t\t\trefid=\"spring.boot.antlib.loader\" />\n\n\t\t\t<local name=\"spring-boot.version\" />\n\n\t\t\t<local name=\"destdir\" />\n\t\t\t<dirname file=\"@{destfile}\" property=\"destdir\" />\n\n\t\t\t<echo>Using destination directory ${destdir}</echo>\n\t\t\t<mkdir dir=\"${destdir}/dependency\" />\n\n\t\t\t<echo>Extracting spring-boot-loader to ${destdir}/dependency</echo>\n\t\t\t<copy todir=\"${destdir}/dependency\">\n\t\t\t\t<javaresource name=\"META-INF/loader/spring-boot-loader.jar\"\n\t\t\t\t\tloaderref=\"spring.boot.antlib.loader\" />\n\t\t\t\t<flattenmapper />\n\t\t\t</copy>\n\n\t\t\t<echo>Embedding spring-boot-loader v${spring-boot.version}...</echo>\n\t\t\t<jar destfile=\"@{destfile}\" compress=\"false\">\n\t\t\t\t<mappedresources>\n\t\t\t\t\t<fileset dir=\"@{classes}\"/>\n\t\t\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/classes/*\" />\n\t\t\t\t</mappedresources>\n\t\t\t\t<resources />\n\t\t\t\t<mappedresources>\n\t\t\t\t\t<lib />\n\t\t\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/lib/*\" />\n\t\t\t\t</mappedresources>\n\t\t\t\t<zipfileset src=\"${destdir}/dependency/spring-boot-loader.jar\" />\n\t\t\t\t<manifest>\n\t\t\t\t\t<attribute name=\"Main-Class\"\n\t\t\t\t\t\tvalue=\"org.springframework.boot.loader.launch.JarLauncher\" />\n\t\t\t\t\t<attribute name=\"Start-Class\" value=\"${start-class}\" />\n\t\t\t\t\t<attribute name=\"Spring-Boot-Classes\" value=\"BOOT-INF/classes/\" />\n\t\t\t\t\t<attribute name=\"Spring-Boot-Lib\" value=\"BOOT-INF/lib/\" />\n\t\t\t\t</manifest>\n\t\t\t</jar>\n\t\t</sequential>\n\t</macrodef>\n</antlib>\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/.gitignore",
    "content": "/bin/\n/build/\n/out/\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.gradle.plugins.ide.eclipse.model.Classpath\nimport org.gradle.plugins.ide.eclipse.model.Library\n\nplugins {\n\tid \"java-gradle-plugin\"\n\tid \"maven-publish\"\n\tid \"org.springframework.boot.antora-contributor\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.maven-repository\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Gradle Plugins\"\n\nconfigurations {\n\t\"testCompileClasspath\" {\n\t\t// Downgrade SLF4J is required for tests to run in Eclipse\n\t\tresolutionStrategy.force(\"org.slf4j:slf4j-api:1.7.36\")\n\t}\n}\n\ndependencies {\n\tdockerTestImplementation(project(\":test-support:spring-boot-gradle-test-support\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(gradleTestKit())\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\timplementation(project(\":buildpack:spring-boot-buildpack-platform\"))\n\timplementation(project(\":loader:spring-boot-loader-tools\"))\n\timplementation(\"io.spring.gradle:dependency-management-plugin\")\n\timplementation(\"org.apache.commons:commons-compress\")\n\timplementation(\"org.springframework:spring-core\")\n\n\toptional(\"com.google.protobuf:protobuf-gradle-plugin\")\n\toptional(\"org.graalvm.buildtools:native-gradle-plugin\")\n\toptional(\"org.cyclonedx:cyclonedx-gradle-plugin\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\toptional(\"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion\")\n\n\ttestImplementation(project(\":test-support:spring-boot-gradle-test-support\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.tngtech.archunit:archunit-junit5:1.4.0\")\n\ttestImplementation(\"net.java.dev.jna:jna-platform\")\n\ttestImplementation(\"org.apache.commons:commons-compress\")\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\ttestImplementation(\"org.graalvm.buildtools:native-gradle-plugin\")\n\ttestImplementation(\"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion\")\n\ttestImplementation(\"org.jetbrains.kotlin:kotlin-compiler-runner:$kotlinVersion\")\n\ttestImplementation(\"org.jetbrains.kotlin:kotlin-daemon-client:$kotlinVersion\")\n\ttestImplementation(\"org.tomlj:tomlj:1.0.0\")\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n}\n\nrepositories {\n\tgradlePluginPortal() {\n\t\tcontent {\n\t\t\tincludeGroup(\"org.cyclonedx\")\n\t\t}\n\t}\n}\n\ngradlePlugin {\n\tplugins {\n\t\tspringBootPlugin {\n\t\t\tid = \"org.springframework.boot\"\n\t\t\tdisplayName = \"Spring Boot Gradle Plugin\"\n\t\t\tdescription = \"Spring Boot Gradle Plugin\"\n\t\t\timplementationClass = \"org.springframework.boot.gradle.plugin.SpringBootPlugin\"\n\t\t}\n\t\tspringBootAotPlugin {\n\t\t\tid = \"org.springframework.boot.aot\"\n\t\t\tdisplayName = \"Spring Boot AOT Gradle Plugin\"\n\t\t\tdescription = \"Spring Boot AOT Gradle Plugin\"\n\t\t\timplementationClass = \"org.springframework.boot.gradle.plugin.SpringBootAotPlugin\"\n\t\t}\n\t}\n}\n\ntasks.register(\"preparePluginValidationClasses\", Copy) {\n\tdestinationDir = layout.buildDirectory.dir(\"classes/java/pluginValidation\").get().asFile\n\tfrom(sourceSets.main.output.classesDirs) {\n\t\texclude \"**/CreateBootStartScripts.class\"\n\t}\n}\n\nvalidatePlugins {\n\tclasses.setFrom preparePluginValidationClasses\n\tenableStricterValidation = true\n}\n\ntasks.named('test') {\n\tinputs.dir('src/docs/antora/modules/gradle-plugin/examples').withPathSensitivity(PathSensitivity.RELATIVE).withPropertyName('buildScripts')\n}\n\njavadoc {\n\toptions {\n\t\tauthor = true\n\t\tdocTitle = \"Spring Boot Gradle Plugin ${project.version} API\"\n\t\tencoding = \"UTF-8\"\n\t\tmemberLevel = \"protected\"\n\t\toutputLevel = \"quiet\"\n\t\tsplitIndex = true\n\t\tuse = true\n\t\twindowTitle = \"Spring Boot Gradle Plugin ${project.version} API\"\n\t\tlinks \"https://docs.gradle.org/$gradle.gradleVersion/javadoc\"\n\t\tlinks \"https://docs.oracle.com/en/java/javase/17/docs/api\"\n\t}\n}\n\nantoraContributions {\n\t'gradle-plugin' {\n\t\tcatalogContent {\n\t\t\tfrom(javadoc) {\n\t\t\t\tinto(\"api/java\")\n\t\t\t}\n\t\t}\n\t\tlocalAggregateContent {\n\t\t\tfrom(tasks.named(\"generateAntoraYml\")) {\n\t\t\t\tinto \"modules\"\n\t\t\t}\n\t\t}\n\t\tsource()\n\t}\n}\n\ntasks.named(\"generateAntoraPlaybook\") {\n\tantoraExtensions.xref.stubs = [\"appendix:.*\", \"api:.*\", \"reference:.*\"]\n\tasciidocExtensions.excludeJavadocExtension = true\n}\n\nplugins.withType(EclipsePlugin) {\n\teclipse {\n\t\tclasspath.file { merger ->\n\t\t\tmerger.whenMerged { content ->\n\t\t\t\tif (content instanceof Classpath) {\n\t\t\t\t\tcontent.entries.each { entry ->\n\t\t\t\t\t\tif (entry instanceof Library && (entry.path.contains(\"gradle-api-\") || entry.path.contains(\"groovy-\"))) {\n\t\t\t\t\t\t\tentry.entryAttributes.remove(\"test\")\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.FileAttribute;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.time.OffsetDateTime;\nimport java.util.Random;\nimport java.util.Set;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;\nimport org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.boot.buildpack.platform.io.FilePermissions;\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link BootBuildImage}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Rafael Ceccone\n */\n@GradleCompatibility(configurationCache = true)\n@DisabledIfDockerUnavailable\nclass BootBuildImageIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid buildsImageWithDefaultBuilder() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"Running detector\");\n\t\tassertThat(result.getOutput()).contains(\"Running builder\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"Network status: HTTP/2 200\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithTrustBuilder() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"Network status: HTTP/2 200\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithWarPackaging() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\", \"-PapplyWarPlugin\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\tassertThat(buildLibs.listFiles())\n\t\t\t.containsExactly(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".war\"));\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithWarPackagingAndJarConfiguration() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\tassertThat(buildLibs.listFiles())\n\t\t\t.containsExactly(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".war\"));\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithCustomName() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"example/test-image-name\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(\"example/test-image-name\");\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithCustomBuilderAndRunImage() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"example/test-image-custom\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(\"example/test-image-custom\");\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithCommandLineOptions() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\", \"--pullPolicy=IF_NOT_PRESENT\",\n\t\t\t\t\"--imageName=example/test-image-cmd\", \"--builder=ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\",\n\t\t\t\t\"--trustBuilder\", \"--runImage=paketobuildpacks/run-noble-tiny\", \"--createdDate=2020-07-01T12:34:56Z\",\n\t\t\t\t\"--applicationDirectory=/application\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"example/test-image-cmd\");\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tImage image = new DockerApi().image().inspect(ImageReference.of(\"example/test-image-cmd\"));\n\t\tassertThat(image.getCreated()).isEqualTo(\"2020-07-01T12:34:56Z\");\n\t\tremoveImages(\"example/test-image-cmd\");\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithPullPolicy() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Pulled builder image\").contains(\"Pulled run image\");\n\t\tresult = this.gradleBuild.build(\"bootBuildImage\", \"--pullPolicy=IF_NOT_PRESENT\");\n\t\ttask = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).doesNotContain(\"Pulled builder image\").doesNotContain(\"Pulled run image\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithBuildpackFromBuilder() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\")\n\t\t\t.contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid buildsImageWithBuildpackFromDirectory() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\twriteBuildpackContent();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Hello World buildpack\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid buildsImageWithBuildpackFromTarGzip() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\twriteBuildpackContent();\n\t\ttarGzipBuildpackContent();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Hello World buildpack\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithBuildpacksFromImages() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\")\n\t\t\t.contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithBinding() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\twriteCertificateBindingFiles();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"binding: certificates/type=ca-certificates\");\n\t\tassertThat(result.getOutput()).contains(\"binding: certificates/test1.crt=---certificate one---\");\n\t\tassertThat(result.getOutput()).contains(\"binding: certificates/test2.crt=---certificate two---\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithTag() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tassertThat(result.getOutput()).contains(\"example.com/myapp:latest\");\n\t\tremoveImages(projectName, \"example.com/myapp:latest\");\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithNetworkModeNone() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"Network status: curl failed\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithVolumeCaches() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t\tdeleteVolumes(\"cache-\" + projectName + \".build\", \"cache-\" + projectName + \".launch\");\n\t}\n\n\t@TestTemplate\n\t@EnabledOnOs(value = OS.LINUX, disabledReason = \"Works with Docker Engine on Linux but is not reliable with \"\n\t\t\t+ \"Docker Desktop on other OSs\")\n\tvoid buildsImageWithBindCaches() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t\tString tempDir = System.getProperty(\"java.io.tmpdir\");\n\t\tPath buildCachePath = Paths.get(tempDir, \"junit-image-cache-\" + projectName + \"-build\");\n\t\tPath launchCachePath = Paths.get(tempDir, \"junit-image-cache-\" + projectName + \"-launch\");\n\t\tassertThat(buildCachePath).exists().isDirectory();\n\t\tassertThat(launchCachePath).exists().isDirectory();\n\t\tcleanupCache(buildCachePath);\n\t\tcleanupCache(launchCachePath);\n\t}\n\n\tprivate static void cleanupCache(Path cachePath) {\n\t\ttry {\n\t\t\tFileSystemUtils.deleteRecursively(cachePath);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithCreatedDate() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tImage image = new DockerApi().image().inspect(ImageReference.of(\"docker.io/library/\" + projectName));\n\t\tassertThat(image.getCreated()).isEqualTo(\"2020-07-01T12:34:56Z\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithCurrentCreatedDate() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tImage image = new DockerApi().image().inspect(ImageReference.of(\"docker.io/library/\" + projectName));\n\t\tOffsetDateTime createdDateTime = OffsetDateTime.parse(image.getCreated());\n\t\tOffsetDateTime current = OffsetDateTime.now().withOffsetSameInstant(createdDateTime.getOffset());\n\t\tassertThat(createdDateTime.getYear()).isEqualTo(current.getYear());\n\t\tassertThat(createdDateTime.getMonth()).isEqualTo(current.getMonth());\n\t\tassertThat(createdDateTime.getDayOfMonth()).isEqualTo(current.getDayOfMonth());\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithApplicationDirectory() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithEmptySecurityOptions() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName);\n\t}\n\n\t@TestTemplate\n\t@EnabledOnOs(value = { OS.LINUX, OS.MAC }, architectures = \"aarch64\",\n\t\t\tdisabledReason = \"Lifecycle will only run on ARM architecture\")\n\tvoid buildsImageOnLinuxArmWithImagePlatformLinuxArm() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tString builderImage = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\";\n\t\tString runImage = \"docker.io/paketobuildpacks/run-noble-tiny:latest\";\n\t\tString buildpackImage = \"ghcr.io/spring-io/spring-boot-test-info:0.0.2\";\n\t\tremoveImages(builderImage, runImage, buildpackImage);\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"Pulling builder image '\" + builderImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"Pulling builder image '\" + builderImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput()).contains(\"Pulling run image '\" + runImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"Pulling buildpack image '\" + buildpackImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput()).contains(\"Running detector\");\n\t\tassertThat(result.getOutput()).contains(\"Running builder\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack building\");\n\t\tassertThat(result.getOutput()).contains(\"---> Test Info buildpack done\");\n\t\tremoveImages(projectName, builderImage, runImage, buildpackImage);\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageWithMultipleCommandLineEnvironments() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\", \"--environment\", \"BP_LIVE_RELOAD_ENABLED=true\",\n\t\t\t\t\"--environment\", \"MY_CUSTOM_VAR=hello_world\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"BP_LIVE_RELOAD_ENABLED=true\");\n\t\tassertThat(result.getOutput()).contains(\"MY_CUSTOM_VAR=hello_world\");\n\t\tremoveImages(this.gradleBuild.getProjectDir().getName());\n\t}\n\n\t@TestTemplate\n\t@EnabledOnOs(value = { OS.LINUX, OS.MAC }, architectures = \"amd64\",\n\t\t\tdisabledReason = \"The expected failure condition will not fail on ARM architectures\")\n\tvoid failsWhenBuildingOnLinuxAmdWithImagePlatformLinuxArm() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tString builderImage = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\";\n\t\tString runImage = \"docker.io/paketobuildpacks/run-noble-tiny:latest\";\n\t\tString buildpackImage = \"ghcr.io/spring-io/spring-boot-test-info:0.0.2\";\n\t\tremoveImages(builderImage, runImage, buildpackImage);\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).contains(\"docker.io/library/\" + projectName);\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"Pulling builder image '\" + builderImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput()).contains(\"Pulling run image '\" + runImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"Pulling buildpack image '\" + buildpackImage + \"' for platform 'linux/arm64'\");\n\t\tassertThat(result.getOutput()).contains(\"exec format error\");\n\t\tremoveImages(builderImage, runImage, buildpackImage);\n\t}\n\n\t@TestTemplate\n\tvoid failsWithInvalidCreatedDate() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).contains(\"Error parsing 'invalid date' as an image created date\");\n\t}\n\n\t@TestTemplate\n\tvoid failsWithBuilderError() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).contains(\"Forced builder failure\");\n\t\tassertThat(result.getOutput()).containsPattern(\"Builder lifecycle '.*' failed with status code\");\n\t}\n\n\t@TestTemplate\n\tvoid failsWithInvalidImageName() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\", \"--imageName=example/Invalid-Image-Name\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).containsPattern(\"must be an image reference\")\n\t\t\t.containsPattern(\"example/Invalid-Image-Name\");\n\t}\n\n\t@TestTemplate\n\tvoid failsWithBuildpackNotInBuilder() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).contains(\"'urn:cnb:builder:example/does-not-exist:0.0.1' not found in builder\");\n\t}\n\n\t@TestTemplate\n\tvoid failsWithInvalidTag() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).containsPattern(\"must be an image reference\")\n\t\t\t.containsPattern(\"example/Invalid-Tag-Name\");\n\t}\n\n\t@TestTemplate\n\tvoid failsWhenCachesAreConfiguredTwice() throws IOException {\n\t\twriteMainClass();\n\t\twriteLongNameResource();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tassertThat(result.getOutput()).containsPattern(\"Each image building cache can be configured only once\");\n\t}\n\n\t@TestTemplate\n\tvoid failsWithIncompatiblePlatform() throws IOException {\n\t\twriteMainClass();\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootBuildImage\");\n\t\tassertThat(result.getOutput()).containsAnyOf(\n\t\t\t\t\"Image platform mismatch detected. The configured platform 'linux/arm64' is not supported by the image 'ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.3-amd64'. Requested platform 'linux/arm64' but got 'linux/amd64'\",\n\t\t\t\t\"image with reference ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.3-amd64 was found but its platform (linux/amd64) does not match the specified platform (linux/arm64)\");\n\t}\n\n\tprivate void writeMainClass() throws IOException {\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/main/java/example\");\n\t\texamplePackage.mkdirs();\n\t\tFile main = new File(examplePackage, \"Main.java\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(main))) {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import java.io.IOException;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"public class Main {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    public static void main(String[] args) throws Exception {\");\n\t\t\twriter.println(\"        System.out.println(\\\"Launched\\\");\");\n\t\t\twriter.println(\"        synchronized(args) {\");\n\t\t\twriter.println(\"            args.wait(); // Prevent exit\");\n\t\t\twriter.println(\"        }\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t}\n\t}\n\n\tprivate void writeLongNameResource() throws IOException {\n\t\tStringBuilder name = new StringBuilder();\n\t\tnew Random().ints('a', 'z' + 1).limit(128).forEach((i) -> name.append((char) i));\n\t\tPath path = this.gradleBuild.getProjectDir()\n\t\t\t.toPath()\n\t\t\t.resolve(Paths.get(\"src\", \"main\", \"resources\", name.toString()));\n\t\tFiles.createDirectories(path.getParent());\n\t\tFiles.createFile(path);\n\t}\n\n\tprivate void writeBuildpackContent() throws IOException {\n\t\tFileAttribute<Set<PosixFilePermission>> dirAttribute = PosixFilePermissions\n\t\t\t.asFileAttribute(PosixFilePermissions.fromString(\"rwxr-xr-x\"));\n\t\tFileAttribute<Set<PosixFilePermission>> execFileAttribute = PosixFilePermissions\n\t\t\t.asFileAttribute(PosixFilePermissions.fromString(\"rwxrwxrwx\"));\n\t\tFile buildpackDir = new File(this.gradleBuild.getProjectDir(), \"buildpack/hello-world\");\n\t\tFiles.createDirectories(buildpackDir.toPath(), dirAttribute);\n\t\tFile binDir = new File(buildpackDir, \"bin\");\n\t\tFiles.createDirectories(binDir.toPath(), dirAttribute);\n\t\tFile descriptor = new File(buildpackDir, \"buildpack.toml\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(descriptor))) {\n\t\t\twriter.println(\"api = \\\"0.10\\\"\");\n\t\t\twriter.println(\"[buildpack]\");\n\t\t\twriter.println(\"id = \\\"example/hello-world\\\"\");\n\t\t\twriter.println(\"version = \\\"0.0.1\\\"\");\n\t\t\twriter.println(\"name = \\\"Hello World Buildpack\\\"\");\n\t\t\twriter.println(\"homepage = \\\"https://github.com/buildpacks/samples/tree/main/buildpacks/hello-world\\\"\");\n\t\t\twriter.println(\"[[stacks]]\\n\");\n\t\t\twriter.println(\"id = \\\"*\\\"\");\n\t\t}\n\t\tFile detect = Files.createFile(Paths.get(binDir.getAbsolutePath(), \"detect\"), execFileAttribute).toFile();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(detect))) {\n\t\t\twriter.println(\"#!/usr/bin/env bash\");\n\t\t\twriter.println(\"set -eo pipefail\");\n\t\t\twriter.println(\"exit 0\");\n\t\t}\n\t\tFile build = Files.createFile(Paths.get(binDir.getAbsolutePath(), \"build\"), execFileAttribute).toFile();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(build))) {\n\t\t\twriter.println(\"#!/usr/bin/env bash\");\n\t\t\twriter.println(\"set -eo pipefail\");\n\t\t\twriter.println(\"echo \\\"---> Hello World buildpack\\\"\");\n\t\t\twriter.println(\"echo \\\"---> done\\\"\");\n\t\t\twriter.println(\"exit 0\");\n\t\t}\n\t}\n\n\tprivate void tarGzipBuildpackContent() throws IOException {\n\t\tPath tarGzipPath = Paths.get(this.gradleBuild.getProjectDir().getAbsolutePath(), \"hello-world.tgz\");\n\t\ttry (TarArchiveOutputStream tar = new TarArchiveOutputStream(\n\t\t\t\tnew GzipCompressorOutputStream(Files.newOutputStream(Files.createFile(tarGzipPath))))) {\n\t\t\tFile buildpackDir = new File(this.gradleBuild.getProjectDir(), \"buildpack/hello-world\");\n\t\t\twriteDirectoryToTar(tar, buildpackDir, buildpackDir.getAbsolutePath());\n\t\t}\n\t}\n\n\tprivate void writeDirectoryToTar(TarArchiveOutputStream tar, File dir, String baseDirPath) throws IOException {\n\t\tfor (File file : dir.listFiles()) {\n\t\t\tString name = file.getAbsolutePath().replace(baseDirPath, \"\");\n\t\t\tint mode = FilePermissions.umaskForPath(file.toPath());\n\t\t\tif (file.isDirectory()) {\n\t\t\t\twriteTarEntry(tar, name + \"/\", mode);\n\t\t\t\twriteDirectoryToTar(tar, file, baseDirPath);\n\t\t\t}\n\t\t\telse {\n\t\t\t\twriteTarEntry(tar, file, name, mode);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void writeTarEntry(TarArchiveOutputStream tar, String name, int mode) throws IOException {\n\t\tTarArchiveEntry entry = new TarArchiveEntry(name);\n\t\tentry.setMode(mode);\n\t\ttar.putArchiveEntry(entry);\n\t\ttar.closeArchiveEntry();\n\t}\n\n\tprivate void writeTarEntry(TarArchiveOutputStream tar, File file, String name, int mode) throws IOException {\n\t\tTarArchiveEntry entry = new TarArchiveEntry(file, name);\n\t\tentry.setMode(mode);\n\t\ttar.putArchiveEntry(entry);\n\t\tStreamUtils.copy(Files.newInputStream(file.toPath()), tar);\n\t\ttar.closeArchiveEntry();\n\t}\n\n\tprivate void writeCertificateBindingFiles() throws IOException {\n\t\tFile bindingDir = new File(this.gradleBuild.getProjectDir(), \"bindings/ca-certificates\");\n\t\tbindingDir.mkdirs();\n\t\tFile type = new File(bindingDir, \"type\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(type))) {\n\t\t\twriter.print(\"ca-certificates\");\n\t\t}\n\t\tFile cert1 = new File(bindingDir, \"test1.crt\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(cert1))) {\n\t\t\twriter.println(\"---certificate one---\");\n\t\t}\n\t\tFile cert2 = new File(bindingDir, \"test2.crt\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(cert2))) {\n\t\t\twriter.println(\"---certificate two---\");\n\t\t}\n\t}\n\n\tprivate void removeImages(String... names) throws IOException {\n\t\tImageApi imageApi = new DockerApi().image();\n\t\tfor (String name : names) {\n\t\t\ttry {\n\t\t\t\timageApi.remove(ImageReference.of(name), false);\n\t\t\t}\n\t\t\tcatch (DockerEngineException ex) {\n\t\t\t\t// ignore image remove failures\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void deleteVolumes(String... names) throws IOException {\n\t\tVolumeApi volumeApi = new DockerApi().volume();\n\t\tfor (String name : names) {\n\t\t\tvolumeApi.delete(VolumeName.of(name), false);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageRegistryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.UpdateListener;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.container.RegistryContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link BootBuildImage} tasks requiring a Docker image registry.\n *\n * @author Scott Frederick\n */\n@GradleCompatibility\n@Testcontainers(disabledWithoutDocker = true)\n@Disabled(\"Disabled until differences between running locally and in CI can be diagnosed\")\nclass BootBuildImageRegistryIntegrationTests {\n\n\t@Container\n\tstatic final RegistryContainer registry = TestImage.container(RegistryContainer.class);\n\n\tString registryAddress;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tassertThat(registry.isRunning()).isTrue();\n\t\tthis.registryAddress = registry.getHost() + \":\" + registry.getFirstMappedPort();\n\t}\n\n\t@TestTemplate\n\tvoid buildsImageAndPublishesToRegistry() throws IOException {\n\t\twriteMainClass();\n\t\tString repoName = \"test-image\";\n\t\tString imageName = this.registryAddress + \"/\" + repoName;\n\t\tBuildResult result = this.gradleBuild.build(\"bootBuildImage\", \"--imageName=\" + imageName);\n\t\tBuildTask task = result.task(\":bootBuildImage\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Building image\")\n\t\t\t.contains(\"Successfully built image\")\n\t\t\t.contains(\"Pushing image '\" + imageName + \":latest\" + \"'\")\n\t\t\t.contains(\"Pushed image '\" + imageName + \":latest\" + \"'\");\n\t\tImageReference imageReference = ImageReference.of(imageName);\n\t\tImage pulledImage = new DockerApi().image().pull(imageReference, null, UpdateListener.none());\n\t\tassertThat(pulledImage).isNotNull();\n\t\tnew DockerApi().image().remove(imageReference, false);\n\t}\n\n\tprivate void writeMainClass() {\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/main/java/example\");\n\t\texamplePackage.mkdirs();\n\t\tFile main = new File(examplePackage, \"Main.java\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(main))) {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import java.io.IOException;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"public class Main {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    public static void main(String[] args) {\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageOnLinuxArmWithImagePlatformLinuxArm.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\trunImage = \"paketobuildpacks/run-noble-tiny\"\n\tbuildpacks = [\"ghcr.io/spring-io/spring-boot-test-info:0.0.2\"]\n\timagePlatform = \"linux/arm64\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithApplicationDirectory.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyWarPlugin')) {\n\tapply plugin: 'war'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tapplicationDirectory = \"/application\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithBindCaches.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildWorkspace {\n\t\tbind {\n\t\t\tsource = System.getProperty('java.io.tmpdir') + \"/junit-image-pack-${rootProject.name}-work\"\n\t\t}\n\t}\n\tbuildCache {\n\t\tbind {\n\t\t\tsource = System.getProperty('java.io.tmpdir') + \"/junit-image-cache-${rootProject.name}-build\"\n\t\t}\n\t}\n\tlaunchCache {\n\t\tbind {\n\t\t\tsource = System.getProperty('java.io.tmpdir') + \"/junit-image-cache-${rootProject.name}-launch\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithBinding.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbindings = [ \"${projectDir}/bindings/ca-certificates:/platform/bindings/certificates\" as String ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithBuildpackFromBuilder.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildpacks = [ \"spring-boot/spring-boot-test-info\" ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithBuildpackFromDirectory.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildpacks = [ \"file://${projectDir}/buildpack/hello-world\" as String ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithBuildpackFromTarGzip.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildpacks = [ \"file://${projectDir}/hello-world.tgz\" as String ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithBuildpacksFromImages.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildpacks = [\"ghcr.io/spring-io/spring-boot-test-info:0.0.2\"]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithCommandLineOptions.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithCreatedDate.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tcreatedDate = \"2020-07-01T12:34:56Z\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithCurrentCreatedDate.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tcreatedDate = \"now\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithCustomBuilderAndRunImage.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\timageName = \"example/test-image-custom\"\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\trunImage = \"paketobuildpacks/run-noble-tiny\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithCustomName.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\timageName = \"example/test-image-name\"\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithEmptySecurityOptions.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tsecurityOptions = []\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithNetworkModeNone.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyWarPlugin')) {\n\tapply plugin: 'war'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tnetwork = \"none\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithPullPolicy.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.springframework.boot.buildpack.platform.build.PullPolicy\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyWarPlugin')) {\n\tapply plugin: 'war'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = PullPolicy.ALWAYS\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithTag.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\ttags = [ \"example.com/myapp:latest\" ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithTrustBuilder.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyWarPlugin')) {\n\tapply plugin: 'war'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\ttrustBuilder = true\n\tpullPolicy = \"IF_NOT_PRESENT\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithVolumeCaches.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildWorkspace {\n\t\tvolume {\n\t\t\tname = \"pack-${rootProject.name}.work\"\n\t\t}\n\t}\n\tbuildCache {\n\t\tvolume {\n\t\t\tname = \"cache-${rootProject.name}.build\"\n\t\t}\n\t}\n\tlaunchCache {\n\t\tvolume {\n\t\t\tname = \"cache-${rootProject.name}.launch\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-buildsImageWithWarPackagingAndJarConfiguration.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tarchiveFile = bootWar.archiveFile\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWhenBuildingOnLinuxAmdWithImagePlatformLinuxArm.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\trunImage = \"paketobuildpacks/run-noble-tiny\"\n\tbuildpacks = [\"ghcr.io/spring-io/spring-boot-test-info:0.0.2\"]\n\timagePlatform = \"linux/arm64\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWhenCachesAreConfiguredTwice.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tbuildCache {\n\t\tvolume {\n\t\t\tname = \"build-cache-volume\"\n\t\t}\n\t\tbind {\n\t\t\tname = \"/tmp/build-cache-bind\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithBuilderError.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tenvironment = [\"FORCE_FAILURE\": \"true\"]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithBuildpackNotInBuilder.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tbuildpacks = [ \"urn:cnb:builder:example/does-not-exist:0.0.1\" ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithIncompatiblePlatform.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.3-amd64\"\n\timagePlatform = \"linux/arm64\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithInvalidCreatedDate.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\tcreatedDate = \"invalid date\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests-failsWithInvalidTag.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n\ttags = [ \"example/Invalid-Tag-Name\" ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyWarPlugin')) {\n\tapply plugin: 'war'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpullPolicy = \"IF_NOT_PRESENT\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/dockerTest/resources/org/springframework/boot/gradle/tasks/bundling/BootBuildImageRegistryIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootBuildImage {\n\tbuilder = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\"\n\tpublish = true\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/antora.yml",
    "content": "name: boot\nversion: true\next:\n  zip_contents_collector:\n    include:\n    - name: gradle-plugin\n      classifier: catalog-content\n      module: gradle-plugin\n      destination: content-catalog\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/local-nav.adoc",
    "content": "include::gradle-plugin:partial$nav-gradle-plugin.adoc[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/aot/apply-aot-plugin.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n\tid 'java'\n}\n\napply plugin: 'org.springframework.boot.aot'\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/aot/apply-aot-plugin.gradle.kts",
    "content": "plugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n\tjava\n}\n\napply(plugin = \"org.springframework.boot.aot\")\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/aot/apply-native-image-plugin.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n\tid 'org.graalvm.buildtools.native' version '{version-native-build-tools}'\n\tid 'java'\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/aot/apply-native-image-plugin.gradle.kts",
    "content": "plugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n\tid(\"org.graalvm.buildtools.native\") version \"{version-native-build-tools}\"\n\tjava\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/apply-plugin-commercial.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/apply-plugin-commercial.gradle.kts",
    "content": "plugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/apply-plugin-release.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/apply-plugin-release.gradle.kts",
    "content": "plugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/apply-plugin-snapshot.gradle",
    "content": "buildscript {\n\trepositories {\n\t\tmaven {\n\t\t\turl = 'https://repo.spring.io/libs-snapshot'\n\t\t}\n\t}\n\n\tdependencies {\n\t\tclasspath 'org.springframework.boot:spring-boot-gradle-plugin:{version-spring-boot}'\n\t}\n}\n\napply plugin: 'org.springframework.boot'\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/milestone-settings.gradle",
    "content": "pluginManagement {\n\trepositories {\n\t\tmaven {\n\t\t\turl = 'https://repo.spring.io/milestone'\n\t\t}\n\t\tgradlePluginPortal()\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/milestone-settings.gradle.kts",
    "content": "pluginManagement {\n\trepositories {\n\t\tmaven { url = uri(\"https://repo.spring.io/milestone\") }\n\t\tgradlePluginPortal()\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/snapshot-settings.gradle",
    "content": "pluginManagement {\n\trepositories {\n\t\tmaven {\n\t\t\turl = 'https://repo.spring.io/milestone'\n\t\t}\n\t\tmaven {\n\t\t\turl = 'https://repo.spring.io/snapshot'\n\t\t}\n\t\tgradlePluginPortal()\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/snapshot-settings.gradle.kts",
    "content": "pluginManagement {\n\trepositories {\n\t\tmaven { url = uri(\"https://repo.spring.io/milestone\") }\n\t\tmaven { url = uri(\"https://repo.spring.io/snapshot\") }\n\t\tgradlePluginPortal()\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/typical-plugins.gradle",
    "content": "// tag::apply[]\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\napply plugin: 'io.spring.dependency-management'\n// end::apply[]\n\ntasks.register(\"verify\") {\n\tdoLast {\n\t\tplugins.getPlugin(org.gradle.api.plugins.JavaPlugin.class)\n\t\tplugins.getPlugin(io.spring.gradle.dependencymanagement.DependencyManagementPlugin.class)\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/getting-started/typical-plugins.gradle.kts",
    "content": "// tag::apply[]\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\napply(plugin = \"io.spring.dependency-management\")\n// end::apply[]\n\ntasks.register(\"verify\") {\n\tval plugins = project.plugins\n\tdoLast {\n\t\tplugins.getPlugin(JavaPlugin::class)\n\t\tplugins.getPlugin(io.spring.gradle.dependencymanagement.DependencyManagementPlugin::class)\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-additional.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::additional[]\nspringBoot {\n\tbuildInfo {\n\t\tproperties {\n\t\t\tadditional = [\n\t\t\t\t'a': 'alpha',\n\t\t\t\t'b': 'bravo'\n\t\t\t]\n\t\t}\n\t}\n}\n// end::additional[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-additional.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::additional[]\nspringBoot {\n\tbuildInfo {\n\t\tproperties {\n\t\t\tadditional.set(mapOf(\n\t\t\t\t\"a\" to \"alpha\",\n\t\t\t\t\"b\" to \"bravo\"\n\t\t\t))\n\t\t}\n\t}\n}\n// end::additional[]\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-basic.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::build-info[]\nspringBoot {\n\tbuildInfo()\n}\n// end::build-info[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-basic.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::build-info[]\nspringBoot {\n\tbuildInfo()\n}\n// end::build-info[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-custom-values.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::custom-values[]\nspringBoot {\n\tbuildInfo {\n\t\tproperties {\n\t\t\tartifact = 'example-app'\n\t\t\tversion = '1.2.3'\n\t\t\tgroup = 'com.example'\n\t\t\tname = 'Example application'\n\t\t}\n\t}\n}\n// end::custom-values[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-custom-values.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::custom-values[]\nspringBoot {\n\tbuildInfo {\n\t\tproperties {\n\t\t\tartifact.set(\"example-app\")\n\t\t\tversion.set(\"1.2.3\")\n\t\t\tgroup.set(\"com.example\")\n\t\t\tname.set(\"Example application\")\n\t\t}\n\t}\n}\n// end::custom-values[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-exclude-time.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::exclude-time[]\nspringBoot {\n\tbuildInfo {\n\t\texcludes = ['time']\n\t}\n}\n// end::exclude-time[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/integrating-with-actuator/build-info-exclude-time.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::exclude-time[]\nspringBoot {\n\tbuildInfo {\n\t\texcludes.set(setOf(\"time\"))\n\t}\n}\n// end::exclude-time[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/configure-bom-with-plugins.gradle.kts",
    "content": "import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension\n\n// tag::configure-bom[]\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\" apply false\n\tid(\"io.spring.dependency-management\") version \"{version-dependency-management-plugin}\"\n}\n\ndependencyManagement {\n\timports {\n\t\tmavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)\n\t}\n}\n// end::configure-bom[]\n\nthe<DependencyManagementExtension>().apply {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (requested.group == \"org.springframework.boot\") {\n\t\t\t\tuseVersion(\"TEST-SNAPSHOT\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nrepositories {\n\tmaven {\n\t\turl = uri(\"repository\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/configure-bom.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::configure-bom[]\napply plugin: 'io.spring.dependency-management'\n\ndependencyManagement {\n\timports {\n\t\tmavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES\n\t}\n}\n// end::configure-bom[]\n\ndependencyManagement {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion 'TEST-SNAPSHOT'\n\t\t\t}\n\t\t}\n\t}\n}\n\nrepositories {\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/configure-bom.gradle.kts",
    "content": "import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::configure-bom[]\napply(plugin = \"io.spring.dependency-management\")\n\nthe<DependencyManagementExtension>().apply {\n\timports {\n\t\tmavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)\n\t}\n}\n// end::configure-bom[]\n\nthe<DependencyManagementExtension>().apply {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (requested.group == \"org.springframework.boot\") {\n\t\t\t\tuseVersion(\"TEST-SNAPSHOT\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nrepositories {\n\tmaven {\n\t\turl = uri(\"repository\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/configure-platform.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::configure-platform[]\ndependencies {\n\timplementation platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)\n}\n// end::configure-platform[]\n\ndependencies {\n\timplementation \"org.springframework.boot:spring-boot-starter\"\n}\n\nrepositories {\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion 'TEST-SNAPSHOT'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/configure-platform.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::configure-platform[]\ndependencies {\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n}\n// end::configure-platform[]\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter\")\n}\n\nrepositories {\n\tmaven {\n\t\turl = uri(\"repository\")\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (requested.group == \"org.springframework.boot\") {\n\t\t\t\tuseVersion(\"TEST-SNAPSHOT\")\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/custom-version-with-platform.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ndependencies {\n\timplementation platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)\n\timplementation \"org.slf4j:slf4j-api\"\n}\n\nrepositories {\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion 'TEST-SNAPSHOT'\n\t\t\t}\n\t\t}\n\t}\n}\n\n// tag::custom-version[]\nconfigurations.all {\n\tresolutionStrategy.eachDependency { DependencyResolveDetails details ->\n\t\tif (details.requested.group == 'org.slf4j') {\n\t\t\tdetails.useVersion '1.7.20'\n\t\t}\n\t}\n}\n// end::custom-version[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/custom-version-with-platform.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ndependencies {\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.slf4j:slf4j-api\")\n}\n\nrepositories {\n\tmaven {\n\t\turl = uri(\"repository\")\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (requested.group == \"org.springframework.boot\") {\n\t\t\t\tuseVersion(\"TEST-SNAPSHOT\")\n\t\t\t}\n\t\t}\n\t}\n}\n\n// tag::custom-version[]\nconfigurations.all {\n    resolutionStrategy.eachDependency {\n        if (requested.group == \"org.slf4j\") {\n            useVersion(\"1.7.20\")\n        }\n    }\n}\n// end::custom-version[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/custom-version.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\napply plugin: 'io.spring.dependency-management'\n\ndependencyManagement {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion 'TEST-SNAPSHOT'\n\t\t\t}\n\t\t}\n\t}\n}\n\n// tag::custom-version[]\next['slf4j.version'] = '1.7.20'\n// end::custom-version[]\n\nrepositories {\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ntasks.register(\"slf4jVersion\") {\n\tdoLast {\n\t\tprintln dependencyManagement.managedVersions['org.slf4j:slf4j-api']\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/custom-version.gradle.kts",
    "content": "import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension\n\nplugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\napply(plugin = \"io.spring.dependency-management\")\n\n// tag::custom-version[]\nextra[\"slf4j.version\"] = \"1.7.20\"\n// end::custom-version[]\n\nrepositories {\n\tmaven {\n\t\turl = uri(\"repository\")\n\t}\n}\n\nthe<DependencyManagementExtension>().apply {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (requested.group == \"org.springframework.boot\") {\n\t\t\t\tuseVersion(\"TEST-SNAPSHOT\")\n\t\t\t}\n\t\t}\n\t}\n}\n\ntasks.register(\"slf4jVersion\") {\n\tval dependencyManagement = project.the<DependencyManagementExtension>()\n\tdoLast {\n\t\tprintln(dependencyManagement.managedVersions[\"org.slf4j:slf4j-api\"])\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/depend-on-plugin-commercial.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}' apply false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/depend-on-plugin-commercial.gradle.kts",
    "content": "plugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\" apply false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/depend-on-plugin-milestone.gradle",
    "content": "buildscript {\n\trepositories {\n\t\tmaven {\n\t\t\turl = 'https://repo.spring.io/libs-milestone'\n\t\t}\n\t}\n\n\tdependencies {\n\t\tclasspath 'org.springframework.boot:spring-boot-gradle-plugin:{version-spring-boot}'\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/depend-on-plugin-release.gradle",
    "content": "plugins {\n\tid 'org.springframework.boot' version '{version-spring-boot}' apply false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/depend-on-plugin-release.gradle.kts",
    "content": "plugins {\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\" apply false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/depend-on-plugin-snapshot.gradle",
    "content": "buildscript {\n\trepositories {\n\t\tmaven {\n\t\t\turl = 'https://repo.spring.io/libs-snapshot'\n\t\t}\n\t}\n\n\tdependencies {\n\t\tclasspath 'org.springframework.boot:spring-boot-gradle-plugin:{version-spring-boot}'\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/dependencies.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\napply plugin: 'io.spring.dependency-management'\n\n// tag::dependencies[]\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter-web')\n\timplementation('org.springframework.boot:spring-boot-starter-data-jpa')\n}\n// end::dependencies[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/managing-dependencies/dependencies.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\napply(plugin = \"io.spring.dependency-management\")\n\n// tag::dependencies[]\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-web\")\n\timplementation(\"org.springframework.boot:spring-boot-starter-data-jpa\")\n}\n// end::dependencies[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/application-plugin-main-class.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main-class[]\napplication {\n\tmainClass = 'com.example.ExampleApplication'\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/application-plugin-main-class.gradle.kts",
    "content": "plugins {\n\tjava\n\tapplication\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main-class[]\napplication {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-bind-caches.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::caches[]\ntasks.named(\"bootBuildImage\") {\n\tbuildWorkspace {\n\t\tbind {\n\t\t\tsource = \"/tmp/cache-${rootProject.name}.work\"\n\t\t}\n\t}\n\tbuildCache {\n\t\tbind {\n\t\t\tsource = \"/tmp/cache-${rootProject.name}.build\"\n\t\t}\n\t}\n\tlaunchCache {\n\t\tbind {\n\t\t\tsource = \"/tmp/cache-${rootProject.name}.launch\"\n\t\t}\n\t}\n}\n// end::caches[]\n\ntasks.register(\"bootBuildImageCaches\") {\n\tdoFirst {\n\t\tbootBuildImage.buildWorkspace.asCache().with { print \"buildWorkspace=$source\" }\n\t\tbootBuildImage.buildCache.asCache().with { println \"buildCache=$source\" }\n\t\tbootBuildImage.launchCache.asCache().with { println \"launchCache=$source\" }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-bind-caches.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::caches[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tbuildWorkspace {\n\t\tbind {\n\t\t\tsource.set(\"/tmp/cache-${rootProject.name}.work\")\n\t\t}\n\t}\n\tbuildCache {\n\t\tbind {\n\t\t\tsource.set(\"/tmp/cache-${rootProject.name}.build\")\n\t\t}\n\t}\n\tlaunchCache {\n\t\tbind {\n\t\t\tsource.set(\"/tmp/cache-${rootProject.name}.launch\")\n\t\t}\n\t}\n}\n// end::caches[]\n\ntasks.register(\"bootBuildImageCaches\") {\n\tdoFirst {\n\t\tprintln(\"buildWorkspace=\" + tasks.getByName<BootBuildImage>(\"bootBuildImage\").buildWorkspace.asCache()?.bind?.source)\n\t\tprintln(\"buildCache=\" + tasks.getByName<BootBuildImage>(\"bootBuildImage\").buildCache.asCache()?.bind?.source)\n\t\tprintln(\"launchCache=\" + tasks.getByName<BootBuildImage>(\"bootBuildImage\").launchCache.asCache()?.bind?.source)\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-builder.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::builder[]\ntasks.named(\"bootBuildImage\") {\n\tbuilder = \"mine/java-cnb-builder\"\n\trunImage = \"mine/java-cnb-run\"\n}\n// end::builder[]\n\ntasks.register(\"bootBuildImageBuilder\") {\n\tdoFirst {\n\t\tprintln(\"builder=${tasks.bootBuildImage.builder.get()}\")\n\t\tprintln(\"runImage=${tasks.bootBuildImage.runImage.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-builder.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::builder[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tbuilder.set(\"mine/java-cnb-builder\")\n\trunImage.set(\"mine/java-cnb-run\")\n}\n// end::builder[]\n\ntasks.register(\"bootBuildImageBuilder\") {\n\tdoFirst {\n\t\tprintln(\"builder=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").builder.get()}\")\n\t\tprintln(\"runImage=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").runImage.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-buildpacks.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::buildpacks[]\ntasks.named(\"bootBuildImage\") {\n\tbuildpacks = [\"file:///path/to/example-buildpack.tgz\", \"urn:cnb:builder:paketo-buildpacks/java\"]\n}\n// end::buildpacks[]\n\ntasks.register(\"bootBuildImageBuildpacks\") {\n\tdoFirst {\n\t\tbootBuildImage.buildpacks.get().each { reference -> println \"$reference\" }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-buildpacks.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::buildpacks[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tbuildpacks.set(listOf(\"file:///path/to/example-buildpack.tgz\", \"urn:cnb:builder:paketo-buildpacks/java\"))\n}\n// end::buildpacks[]\n\ntasks.register(\"bootBuildImageBuildpacks\") {\n\tdoFirst {\n\t\tfor(reference in tasks.getByName<BootBuildImage>(\"bootBuildImage\").buildpacks.get()) {\n\t\t\tprint(reference)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-caches.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::caches[]\ntasks.named(\"bootBuildImage\") {\n\tbuildCache {\n\t\tvolume {\n\t\t\tname = \"cache-${rootProject.name}.build\"\n\t\t}\n\t}\n\tlaunchCache {\n\t\tvolume {\n\t\t\tname = \"cache-${rootProject.name}.launch\"\n\t\t}\n\t}\n}\n// end::caches[]\n\ntasks.register(\"bootBuildImageCaches\") {\n\tdoFirst {\n\t\tbootBuildImage.buildCache.asCache().with { println \"buildCache=$name\" }\n\t\tbootBuildImage.launchCache.asCache().with { println \"launchCache=$name\" }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-caches.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::caches[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tbuildCache {\n\t\tvolume {\n\t\t\tname.set(\"cache-${rootProject.name}.build\")\n\t\t}\n\t}\n\tlaunchCache {\n\t\tvolume {\n\t\t\tname.set(\"cache-${rootProject.name}.launch\")\n\t\t}\n\t}\n}\n// end::caches[]\n\ntasks.register(\"bootBuildImageCaches\") {\n\tdoFirst {\n\t\tprintln(\"buildCache=\" + tasks.getByName<BootBuildImage>(\"bootBuildImage\").buildCache.asCache()?.volume?.name)\n\t\tprintln(\"launchCache=\" + tasks.getByName<BootBuildImage>(\"bootBuildImage\").launchCache.asCache()?.volume?.name)\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-auth-token.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::docker-auth-token[]\ntasks.named(\"bootBuildImage\") {\n\tdocker {\n\t\tbuilderRegistry {\n\t\t\ttoken = \"9cbaf023786cd7...\"\n\t\t}\n\t}\n}\n// end::docker-auth-token[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"token=${tasks.bootBuildImage.docker.builderRegistry.token.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-auth-token.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::docker-auth-token[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tdocker {\n\t\tbuilderRegistry {\n\t\t\ttoken.set(\"9cbaf023786cd7...\")\n\t\t}\n\t}\n}\n// end::docker-auth-token[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"token=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.builderRegistry.token.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-auth-user.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::docker-auth-user[]\ntasks.named(\"bootBuildImage\") {\n\tdocker {\n\t\tbuilderRegistry {\n\t\t\tusername = \"user\"\n\t\t\tpassword = \"secret\"\n\t\t\turl = \"https://docker.example.com/v1/\"\n\t\t\temail = \"user@example.com\"\n\t\t}\n\t}\n}\n// end::docker-auth-user[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"username=${tasks.bootBuildImage.docker.builderRegistry.username.get()}\")\n\t\tprintln(\"password=${tasks.bootBuildImage.docker.builderRegistry.password.get()}\")\n\t\tprintln(\"url=${tasks.bootBuildImage.docker.builderRegistry.url.get()}\")\n\t\tprintln(\"email=${tasks.bootBuildImage.docker.builderRegistry.email.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-auth-user.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::docker-auth-user[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tdocker {\n\t\tbuilderRegistry {\n\t\t\tusername.set(\"user\")\n\t\t\tpassword.set(\"secret\")\n\t\t\turl.set(\"https://docker.example.com/v1/\")\n\t\t\temail.set(\"user@example.com\")\n\t\t}\n\t}\n}\n// end::docker-auth-user[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"username=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.builderRegistry.username.get()}\")\n\t\tprintln(\"password=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.builderRegistry.password.get()}\")\n\t\tprintln(\"url=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.builderRegistry.url.get()}\")\n\t\tprintln(\"email=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.builderRegistry.email.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-host-colima.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::docker-host[]\ntasks.named(\"bootBuildImage\") {\n\tdocker {\n\t\thost = \"unix://${System.properties['user.home']}/.colima/docker.sock\"\n\t}\n}\n// end::docker-host[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"host=${tasks.bootBuildImage.docker.host.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-host-colima.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::docker-host[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tdocker {\n\t\thost.set(\"unix://${System.getProperty(\"user.home\")}/.colima/docker.sock\")\n\t}\n}\n// end::docker-host[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"host=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.host.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-host-podman.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::docker-host[]\ntasks.named(\"bootBuildImage\") {\n\tdocker {\n\t\thost = \"unix:///run/user/1000/podman/podman.sock\"\n\t\tbindHostToBuilder = true\n\t}\n}\n// end::docker-host[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"host=${tasks.bootBuildImage.docker.host.get()}\")\n\t\tprintln(\"bindHostToBuilder=${tasks.bootBuildImage.docker.bindHostToBuilder.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-host-podman.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::docker-host[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tdocker {\n\t\thost.set(\"unix:///run/user/1000/podman/podman.sock\")\n\t\tbindHostToBuilder.set(true)\n\t}\n}\n// end::docker-host[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"host=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.host.get()}\")\n\t\tprintln(\"bindHostToBuilder=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.bindHostToBuilder.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-host.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::docker-host[]\ntasks.named(\"bootBuildImage\") {\n\tdocker {\n\t\thost = \"tcp://192.168.99.100:2376\"\n\t\ttlsVerify = true\n\t\tcertPath = \"/home/user/.minikube/certs\"\n\t}\n}\n// end::docker-host[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"host=${tasks.bootBuildImage.docker.host.get()}\")\n\t\tprintln(\"tlsVerify=${tasks.bootBuildImage.docker.tlsVerify.get()}\")\n\t\tprintln(\"certPath=${tasks.bootBuildImage.docker.certPath.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-docker-host.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::docker-host[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tdocker {\n\t\thost.set(\"tcp://192.168.99.100:2376\")\n\t\ttlsVerify.set(true)\n\t\tcertPath.set(\"/home/user/.minikube/certs\")\n\t}\n}\n// end::docker-host[]\n\ntasks.register(\"bootBuildImageDocker\") {\n\tdoFirst {\n\t\tprintln(\"host=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.host.get()}\")\n\t\tprintln(\"tlsVerify=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.tlsVerify.get()}\")\n\t\tprintln(\"certPath=${tasks.getByName<BootBuildImage>(\"bootBuildImage\").docker.certPath.get()}\")\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-env-proxy.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::env[]\ntasks.named(\"bootBuildImage\") {\n\tenvironment[\"HTTP_PROXY\"] = \"http://proxy.example.com\"\n\tenvironment[\"HTTPS_PROXY\"] = \"https://proxy.example.com\"\n}\n// end::env[]\n\ntasks.register(\"bootBuildImageEnvironment\") {\n\tdoFirst {\n\t\tbootBuildImage.environment.get().each { name, value -> println \"$name=$value\" }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-env-proxy.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::env[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tenvironment.putAll(mapOf(\"HTTP_PROXY\" to \"http://proxy.example.com\",\n\t\t\t\t\t\t\"HTTPS_PROXY\" to \"https://proxy.example.com\"))\n}\n// end::env[]\n\ntasks.register(\"bootBuildImageEnvironment\") {\n\tdoFirst {\n\t\tfor((name, value) in tasks.getByName<BootBuildImage>(\"bootBuildImage\").environment.get()) {\n\t\t\tprint(name + \"=\" + value)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-env-runtime.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::env-runtime[]\ntasks.named(\"bootBuildImage\") {\n\tenvironment[\"BPE_DELIM_JAVA_TOOL_OPTIONS\"] = \" \"\n\tenvironment[\"BPE_APPEND_JAVA_TOOL_OPTIONS\"] = \"-XX:+HeapDumpOnOutOfMemoryError\"\n}\n// end::env-runtime[]\n\ntasks.register(\"bootBuildImageEnvironment\") {\n\tdoFirst {\n\t\tbootBuildImage.environment.get().each { name, value -> println \"$name=$value\" }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-env-runtime.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::env-runtime[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tenvironment.putAll(mapOf(\n\t\t\"BPE_DELIM_JAVA_TOOL_OPTIONS\" to \" \",\n\t\t\"BPE_APPEND_JAVA_TOOL_OPTIONS\" to \"-XX:+HeapDumpOnOutOfMemoryError\"\n\t))\n}\n// end::env-runtime[]\n\ntasks.register(\"bootBuildImageEnvironment\") {\n\tdoFirst {\n\t\tfor((name, value) in tasks.getByName<BootBuildImage>(\"bootBuildImage\").environment.get()) {\n\t\t\tprint(name + \"=\" + value)\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-env.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::env[]\ntasks.named(\"bootBuildImage\") {\n\tenvironment[\"BP_JVM_VERSION\"] = \"17\"\n}\n// end::env[]\n\ntasks.register(\"bootBuildImageEnvironment\") {\n\tdoFirst {\n\t\tbootBuildImage.environment.get().each { name, value -> println \"$name=$value\" }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-env.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::env[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\tenvironment.put(\"BP_JVM_VERSION\", \"17\")\n}\n// end::env[]\n\ntasks.register(\"bootBuildImageEnvironment\") {\n\tdoFirst {\n\t\tfor((name, value) in tasks.getByName<BootBuildImage>(\"bootBuildImage\").environment.get()) {\n\t\t\tprint(name + \"=\" + value)\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-name.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::image-name[]\ntasks.named(\"bootBuildImage\") {\n\timageName = \"example.com/library/${project.name}\"\n}\n// end::image-name[]\n\ntasks.register(\"bootBuildImageName\") {\n\tdoFirst {\n\t\tprintln(tasks.bootBuildImage.imageName.get())\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-name.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::image-name[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\timageName.set(\"example.com/library/${project.name}\")\n}\n// end::image-name[]\n\ntasks.register(\"bootBuildImageName\") {\n\tdoFirst {\n\t\tprintln(tasks.getByName<BootBuildImage>(\"bootBuildImage\").imageName.get())\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-publish.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::publish[]\ntasks.named(\"bootBuildImage\") {\n\timageName.set(\"docker.example.com/library/${project.name}\")\n\tpublish = true\n\tdocker {\n\t\tpublishRegistry {\n\t\t\tusername = \"user\"\n\t\t\tpassword = \"secret\"\n\t\t}\n\t}\n}\n// end::publish[]\n\ntasks.register(\"bootBuildImagePublish\") {\n\tdoFirst {\n\t\tprintln(tasks.bootBuildImage.publish.get())\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-build-image-publish.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::publish[]\ntasks.named<BootBuildImage>(\"bootBuildImage\") {\n\timageName.set(\"docker.example.com/library/${project.name}\")\n\tpublish.set(true)\n\tdocker {\n\t\tpublishRegistry {\n\t\t\tusername.set(\"user\")\n\t\t\tpassword.set(\"secret\")\n\t\t}\n\t}\n}\n// end::publish[]\n\ntasks.register(\"bootBuildImagePublish\") {\n\tdoFirst {\n\t\tprintln(tasks.getByName<BootBuildImage>(\"bootBuildImage\").publish.get())\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-and-jar-classifiers.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::classifiers[]\ntasks.named(\"bootJar\") {\n\tarchiveClassifier = 'boot'\n}\n\ntasks.named(\"jar\") {\n\tarchiveClassifier = ''\n}\n// end::classifiers[]\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-and-jar-classifiers.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::classifiers[]\ntasks.named<BootJar>(\"bootJar\") {\n\tarchiveClassifier.set(\"boot\")\n}\n\ntasks.named<Jar>(\"jar\") {\n\tarchiveClassifier.set(\"\")\n}\n// end::classifiers[]\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.Application\")\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-layered-custom.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::layered[]\ntasks.named(\"bootJar\") {\n\tlayered {\n\t\tapplication {\n\t\t\tintoLayer(\"spring-boot-loader\") {\n\t\t\t\tinclude \"org/springframework/boot/loader/**\"\n\t\t\t}\n\t\t\tintoLayer(\"application\")\n\t\t}\n\t\tdependencies {\n\t\t\tintoLayer(\"application\") {\n\t\t\t\tincludeProjectDependencies()\n\t\t\t}\n\t\t\tintoLayer(\"snapshot-dependencies\") {\n\t\t\t\tinclude \"*:*:*SNAPSHOT\"\n\t\t\t}\n\t\t\tintoLayer(\"dependencies\")\n\t\t}\n\t\tlayerOrder = [\"dependencies\", \"spring-boot-loader\", \"snapshot-dependencies\", \"application\"]\n\t}\n}\n// end::layered[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-layered-custom.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::layered[]\ntasks.named<BootJar>(\"bootJar\") {\n\tlayered {\n\t\tapplication {\n\t\t\tintoLayer(\"spring-boot-loader\") {\n\t\t\t\tinclude(\"org/springframework/boot/loader/**\")\n\t\t\t}\n\t\t\tintoLayer(\"application\")\n\t\t}\n\t\tdependencies {\n\t\t\tintoLayer(\"application\") {\n\t\t\t\tincludeProjectDependencies()\n\t\t\t}\n\t\t\tintoLayer(\"snapshot-dependencies\") {\n\t\t\t\tinclude(\"*:*:*SNAPSHOT\")\n\t\t\t}\n\t\t\tintoLayer(\"dependencies\")\n\t\t}\n\t\tlayerOrder.set(listOf(\"dependencies\", \"spring-boot-loader\", \"snapshot-dependencies\", \"application\"))\n\t}\n}\n// end::layered[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-layered-disabled.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::layered[]\ntasks.named(\"bootJar\") {\n\tlayered {\n\t\tenabled = false\n\t}\n}\n// end::layered[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-layered-disabled.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::layered[]\ntasks.named<BootJar>(\"bootJar\") {\n\tlayered {\n\t\tenabled.set(false)\n\t}\n}\n// end::layered[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-layered-exclude-tools.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::layered[]\ntasks.named(\"bootJar\") {\n\tincludeTools = false\n}\n// end::layered[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-layered-exclude-tools.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::layered[]\ntasks.named<BootJar>(\"bootJar\") {\n\tincludeTools.set(false)\n}\n// end::layered[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-main-class.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main-class[]\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-main-class.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main-class[]\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-manifest-main-class.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main-class[]\ntasks.named(\"bootJar\") {\n\tmanifest {\n\t\tattributes 'Start-Class': 'com.example.ExampleApplication'\n\t}\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-manifest-main-class.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main-class[]\ntasks.named<BootJar>(\"bootJar\") {\n\tmanifest {\n\t\tattributes(\"Start-Class\" to \"com.example.ExampleApplication\")\n\t}\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-requires-unpack.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\truntimeOnly('org.jruby:jruby-complete:1.7.25')\n}\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::requires-unpack[]\ntasks.named(\"bootJar\") {\n\trequiresUnpack '**/jruby-complete-*.jar'\n}\n// end::requires-unpack[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-jar-requires-unpack.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\truntimeOnly(\"org.jruby:jruby-complete:1.7.25\")\n}\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::requires-unpack[]\ntasks.named<BootJar>(\"bootJar\") {\n\trequiresUnpack(\"**/jruby-complete-*.jar\")\n}\n// end::requires-unpack[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-war-include-devtools.gradle",
    "content": "plugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootWar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\ndependencies {\n\tdevelopmentOnly files(\"spring-boot-devtools-1.2.3.RELEASE.jar\")\n}\n\n// tag::include-devtools[]\ntasks.named(\"bootWar\") {\n\tclasspath configurations.developmentOnly\n}\n// end::include-devtools[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-war-include-devtools.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootWar\n\nplugins {\n\twar\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootWar>(\"bootWar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\ndependencies {\n\t\"developmentOnly\"(files(\"spring-boot-devtools-1.2.3.RELEASE.jar\"))\n}\n\n// tag::include-devtools[]\ntasks.named<BootWar>(\"bootWar\") {\n\tclasspath(configurations[\"developmentOnly\"])\n}\n// end::include-devtools[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-war-properties-launcher.gradle",
    "content": "plugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\ntasks.named(\"bootWar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n\n// tag::properties-launcher[]\ntasks.named(\"bootWar\") {\n\tmanifest {\n\t\tattributes 'Main-Class': 'org.springframework.boot.loader.launch.PropertiesLauncher'\n\t}\n}\n// end::properties-launcher[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/boot-war-properties-launcher.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootWar\n\nplugins {\n\twar\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\ntasks.named<BootWar>(\"bootWar\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n\n// tag::properties-launcher[]\ntasks.named<BootWar>(\"bootWar\") {\n\tmanifest {\n\t\tattributes(\"Main-Class\" to \"org.springframework.boot.loader.launch.PropertiesLauncher\")\n\t}\n}\n// end::properties-launcher[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/only-boot-jar.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::disable-jar[]\ntasks.named(\"jar\") {\n\tenabled = false\n}\n// end::disable-jar[]\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/only-boot-jar.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::disable-jar[]\ntasks.named<Jar>(\"jar\") {\n\tenabled = false\n}\n// end::disable-jar[]\n\ntasks.named<BootJar>(\"bootJar\") {\n\tmainClass.set(\"com.example.Application\")\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/spring-boot-dsl-main-class.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main-class[]\nspringBoot {\n\tmainClass = 'com.example.ExampleApplication'\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/spring-boot-dsl-main-class.gradle.kts",
    "content": "plugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main-class[]\nspringBoot {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle",
    "content": "plugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\napply plugin: 'io.spring.dependency-management'\n\n// tag::dependencies[]\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter-webmvc')\n\tprovidedRuntime('org.springframework.boot:spring-boot-starter-tomcat-runtime')\n}\n// end::dependencies[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/packaging/war-container-dependency.gradle.kts",
    "content": "plugins {\n\twar\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\napply(plugin = \"io.spring.dependency-management\")\n\n// tag::dependencies[]\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-web\")\n\tprovidedRuntime(\"org.springframework.boot:spring-boot-starter-tomcat-runtime\")\n}\n// end::dependencies[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/publishing/maven-publish.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'maven-publish'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::publishing[]\npublishing {\n\tpublications {\n\t\tbootJava(MavenPublication) {\n\t\t\tartifact tasks.named(\"bootJar\")\n\t\t}\n\t}\n\trepositories {\n\t\tmaven {\n\t\t\turl = 'https://repo.example.com'\n\t\t}\n\t}\n}\n// end::publishing[]\n\ntasks.register(\"publishingConfiguration\") {\n\tdoLast {\n\t\tprintln publishing.publications.bootJava\n\t\tprintln publishing.repositories.maven.url\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/publishing/maven-publish.gradle.kts",
    "content": "plugins {\n\tjava\n\t`maven-publish`\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::publishing[]\npublishing {\n\tpublications {\n\t\tcreate<MavenPublication>(\"bootJava\") {\n\t\t\tartifact(tasks.named(\"bootJar\"))\n\t\t}\n\t}\n\trepositories {\n\t\tmaven {\n\t\t\turl = uri(\"https://repo.example.com\")\n\t\t}\n\t}\n}\n// end::publishing[]\n\ntasks.register(\"publishingConfiguration\") {\n\tdoLast {\n\t\tprintln(publishing.publications[\"bootJava\"])\n\t\tprintln(publishing.repositories.getByName<MavenArtifactRepository>(\"maven\").url)\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/application-plugin-main-class-name.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main-class[]\napplication {\n\tmainClass = 'com.example.ExampleApplication'\n}\n// end::main-class[]\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/application-plugin-main-class-name.gradle.kts",
    "content": "plugins {\n\tjava\n\tapplication\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main-class[]\napplication {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-disable-optimized-launch.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::launch[]\ntasks.named(\"bootRun\") {\n\toptimizedLaunch = false\n}\n// end::launch[]\n\ntasks.register(\"optimizedLaunch\") {\n\tdoLast {\n\t\tprintln bootRun.optimizedLaunch.get()\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-disable-optimized-launch.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.run.BootRun\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::launch[]\ntasks.named<BootRun>(\"bootRun\") {\n\toptimizedLaunch.set(false)\n}\n// end::launch[]\n\ntasks.register(\"optimizedLaunch\") {\n\tdoLast {\n\t\tprintln(tasks.getByName<BootRun>(\"bootRun\").optimizedLaunch.get())\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-main.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main[]\ntasks.named(\"bootRun\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n// end::main[]\n\ntasks.register(\"configuredMainClass\") {\n\tdoLast {\n\t\tprintln bootRun.mainClass\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-main.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.run.BootRun\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main[]\ntasks.named<BootRun>(\"bootRun\") {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n// end::main[]\n\ntasks.register(\"configuredMainClass\") {\n\tdoLast {\n\t\tprintln(tasks.getByName<BootRun>(\"bootRun\").mainClass.get())\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-source-resources.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::source-resources[]\ntasks.named(\"bootRun\") {\n\tsourceResources sourceSets.main\n}\n// end::source-resources[]\n\ntasks.register(\"configuredClasspath\") {\n\tdoLast {\n\t\tprintln bootRun.classpath.files\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-source-resources.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.run.BootRun\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::source-resources[]\ntasks.named<BootRun>(\"bootRun\") {\n\tsourceResources(sourceSets[\"main\"])\n}\n// end::source-resources[]\n\ntasks.register(\"configuredClasspath\") {\n\tdoLast {\n\t\tprintln(tasks.getByName<BootRun>(\"bootRun\").classpath.files)\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-system-property.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\n// tag::system-property[]\ntasks.named(\"bootRun\") {\n\tsystemProperty 'com.example.property', findProperty('example') ?: 'default'\n}\n// end::system-property[]\n\ntasks.register(\"configuredSystemProperties\") {\n\tdoLast {\n\t\tbootRun.systemProperties.each { k, v ->\n\t\t\tprintln \"$k = $v\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/boot-run-system-property.gradle.kts",
    "content": "import org.springframework.boot.gradle.tasks.run.BootRun\n\nplugins {\n\tjava\n\tid(\"org.springframework.boot\") version \"{version}\"\n}\n\n// tag::system-property[]\ntasks.named<BootRun>(\"bootRun\") {\n\tsystemProperty(\"com.example.property\", findProperty(\"example\") ?: \"default\")\n}\n// end::system-property[]\n\ntasks.register(\"configuredSystemProperties\") {\n\tdoLast {\n\t\ttasks.getByName<BootRun>(\"bootRun\").systemProperties.forEach { k, v ->\n\t\t\tprintln(\"$k = $v\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/spring-boot-dsl-main-class-name.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n}\n\n// tag::main-class[]\nspringBoot {\n\tmainClass = 'com.example.ExampleApplication'\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/examples/running/spring-boot-dsl-main-class-name.gradle.kts",
    "content": "plugins {\n\tjava\n\tapplication\n\tid(\"org.springframework.boot\") version \"{version-spring-boot}\"\n}\n\n// tag::main-class[]\nspringBoot {\n\tmainClass.set(\"com.example.ExampleApplication\")\n}\n// end::main-class[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/aot.adoc",
    "content": "[[aot]]\n= Ahead-of-Time Processing\n\nSpring AOT is a process that analyzes your code at build-time in order to generate an optimized version of it.\nIt is most often used to help generate GraalVM native images.\n\nThe `org.springframework.boot.aot` Gradle plugin provides tasks that can be used to perform AOT processing on both application and test code.\nThe plugin is applied automatically when the {url-native-build-tools-docs-gradle-plugin}[GraalVM Native Image plugin] is applied:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot/apply-native-image-plugin.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot/apply-native-image-plugin.gradle.kts[]\n----\n======\n\nIf you want to  xref:reference:packaging/aot.adoc[run an AOT-processed application on the JVM] rather than as a native image, apply the `org.springframework.boot.aot` plugin directly:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot/apply-aot-plugin.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot/apply-aot-plugin.gradle.kts[]\n----\n======\n\n\n\n[[aot.processing-applications]]\n== Processing Applications\n\nBased on your `@SpringBootApplication`-annotated main class, the `processAot` task generates a persistent view of the beans that are going to be contributed at runtime in a way that bean instantiation is as straightforward as possible.\nAdditional post-processing of the factory is possible using callbacks.\nFor instance, these are used to generate the necessary reflection configuration that GraalVM needs to initialize the context in a native image.\n\nAs the `BeanFactory` is fully prepared at build-time, conditions are also evaluated.\nThis has an important difference compared to what a regular Spring Boot application does at runtime.\nFor instance, if you want to opt-in or opt-out for certain features, you need to configure the environment used at build time to do so.\nTo this end, the `processAot` task is a {url-gradle-dsl}/org.gradle.api.tasks.JavaExec.html[`JavaExec`] task and can be configured with environment variables, system properties, and arguments as needed.\n\nThe `nativeCompile` task of the GraalVM Native Image plugin is automatically configured to use the output of the `processAot` task.\n\n\n\n[[aot.processing-tests]]\n== Processing Tests\n\nThe AOT engine can be applied to JUnit 5 tests that use Spring's Test Context Framework.\nSuitable tests are processed by the `processTestAot` task to generate `ApplicationContextInitializer` code.\nAs with application AOT processing, the `BeanFactory` is fully prepared at build-time.\nAs with `processAot`, the `processTestAot` task is `JavaExec` subclass and can be configured as needed to influence this processing.\n\nThe `nativeTest` task of the GraalVM Native Image plugin is automatically configured to use the output of the `processAot` and `processTestAot` tasks.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/getting-started.adoc",
    "content": "[[getting-started]]\n= Getting Started\n\nTo get started with the plugin it needs to be applied to your project.\n\nifeval::[\"{build-type}\" == \"commercial\"]\nThe plugin is published to the Spring Commercial repository.\nYou will have to configure your build to access this repository.\nThis is usual done through a local artifact repository that mirrors the content of the Spring Commercial repository.\nAlternatively, while it is not recommended, the Spring Commercial repository can also be accessed directly.\nIn either case, see https://docs.vmware.com/en/Tanzu-Spring-Runtime/Commercial/Tanzu-Spring-Runtime/spring-enterprise-subscription.html[the Tanzu Spring Runtime documentation] for further details.\n\nWith access to the Spring Commercial repository configured in `settings.gradle` or `settings.gradle.kts`, the plugin can be applied using the `plugins` block:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-commercial.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-commercial.gradle.kts[]\n----\n======\nendif::[]\n\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-release\"]\nThe plugin is https://plugins.gradle.org/plugin/org.springframework.boot[published to Gradle's plugin portal] and can be applied using the `plugins` block:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-release.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-release.gradle.kts[]\n----\n======\nendif::[]\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-milestone\"]\nThe plugin is published to the Spring milestones repository.\nGradle can be configured to use the milestones repository and the plugin can then be applied using the `plugins` block.\nTo configure Gradle to use the milestones repository, add the following to your `settings.gradle` (Groovy) or `settings.gradle.kts` (Kotlin):\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/milestone-settings.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/milestone-settings.gradle.kts[]\n----\n======\n\nThe plugin can then be applied using the `plugins` block:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-release.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-release.gradle.kts[]\n----\n======\nendif::[]\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-snapshot\"]\nThe plugin is published to the Spring snapshots repository.\nGradle can be configured to use the snapshots repository and the plugin can then be applied using the `plugins` block.\nTo configure Gradle to use the snapshots repository, add the following to your `settings.gradle` (Groovy) or `settings.gradle.kts` (Kotlin):\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/snapshot-settings.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/snapshot-settings.gradle.kts[]\n----\n======\n\nThe plugin can then be applied using the `plugins` block:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-release.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/apply-plugin-release.gradle.kts[]\n----\n======\nendif::[]\n\nApplied in isolation the plugin makes few changes to a project.\nInstead, the plugin detects when certain other plugins are applied and reacts accordingly.\nFor example, when the `java` plugin is applied a task for building an executable jar is automatically configured.\nA typical Spring Boot project will apply the {url-gradle-docs-groovy-plugin}[`groovy`], {url-gradle-docs-java-plugin}[`java`], or {url-kotlin-docs-kotlin-plugin}[`org.jetbrains.kotlin.jvm`] plugin as a minimum and also use the {url-dependency-management-plugin-site}[`io.spring.dependency-management`] plugin or Gradle's native bom support for dependency management.\nFor example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/typical-plugins.gradle[tags=apply]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/typical-plugins.gradle.kts[tags=apply]\n----\n======\n\nTo learn more about how the Spring Boot plugin behaves when other plugins are applied please see the section on xref:reacting.adoc[reacting to other plugins].\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/index.adoc",
    "content": "[[gradle-plugin]]\n= Gradle Plugin\n\nThe Spring Boot Gradle Plugin provides Spring Boot support in https://gradle.org[Gradle].\nIt allows you to package executable jar or war archives, run Spring Boot applications, and use the dependency management provided by `spring-boot-dependencies`.\nSpring Boot's Gradle plugin requires Gradle 8.x (8.14 or later) or 9.x and can be used with Gradle's {url-gradle-docs}/configuration_cache.html[configuration cache].\n\nIn addition to this user guide, xref:api/java/index.html[API documentation] is also available.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/integrating-with-actuator.adoc",
    "content": "[[integrating-with-actuator]]\n= Integrating with Actuator\n\n\n\n[[integrating-with-actuator.build-info]]\n== Generating Build Information\n\nSpring Boot Actuator's `info` endpoint automatically publishes information about your build in the presence of a `META-INF/build-info.properties` file.\nA {apiref-gradle-plugin-boot-build-info}[`BuildInfo`] task is provided to generate this file.\nThe easiest way to use the task is through the plugin's DSL:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-basic.gradle[tags=build-info]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-basic.gradle.kts[tags=build-info]\n----\n======\n\nThis will configure a {apiref-gradle-plugin-boot-build-info}[`BuildInfo`] task named `bootBuildInfo`.\nThe task's destination directory will be `build/bootBuildInfo` and its filename will be `META-INF/build-info.properties`.\nIf the main source set exists, its resources are configured to use the output of the `bootBuildInfo` task as a src dir.\n\nBy default, the generated build information is derived from the project:\n\n|===\n| Property | Default value\n\n| `build.artifact`\n| The base name of the `bootJar` or `bootWar` task\n\n| `build.group`\n| The group of the project\n\n| `build.name`\n| The name of the project\n\n| `build.version`\n| The version of the project\n\n| `build.time`\n| The time at which the project is being built\n\n|===\n\nThe properties can be customized using the DSL:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-custom-values.gradle[tags=custom-values]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-custom-values.gradle.kts[tags=custom-values]\n----\n======\n\nTo exclude any of the default properties from the generated build information, add its name to the excludes.\nFor example, the `time` property can be excluded as follows:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-exclude-time.gradle[tags=exclude-time]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-exclude-time.gradle.kts[tags=exclude-time]\n----\n======\n\nThe default value for `build.time` is the instant at which the project is being built.\nA side-effect of this is that the task will never be up-to-date.\nAs a result, builds will take longer as more tasks, including the project's tests, will have to be executed.\nAnother side-effect is that the task's output will always change and, therefore, the build will not be truly repeatable.\nIf you value build performance or repeatability more highly than the accuracy of the `build.time` property, exclude the `time` property as shown in the preceding example.\n\nAdditional properties can also be added to the build information:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-additional.gradle[tags=additional]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integrating-with-actuator/build-info-additional.gradle.kts[tags=additional]\n----\n======\n\nAn additional property's value can be computed lazily by using a `Provider`.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/introduction.adoc",
    "content": "[[introduction]]\n= Introduction\n\nThe Spring Boot Gradle Plugin provides Spring Boot support in https://gradle.org[Gradle].\nIt allows you to package executable jar or war archives, run Spring Boot applications, and use the dependency management provided by `spring-boot-dependencies`.\nSpring Boot's Gradle plugin requires Gradle 8.x (8.14 or later) or 9.x and can be used with Gradle's {url-gradle-docs}/configuration_cache.html[configuration cache].\n\nIn addition to this user guide, xref:api/java/index.html[API documentation] is also available.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/managing-dependencies.adoc",
    "content": "[[managing-dependencies]]\n= Managing Dependencies\n\nTo manage dependencies in your Spring Boot application, you can either apply the {url-dependency-management-plugin-site}[`io.spring.dependency-management`] plugin or use Gradle's native bom support.\nThe primary benefit of the former is that it offers property-based customization of managed versions, while using the latter will likely result in faster builds.\n\n\n\n[[managing-dependencies.dependency-management-plugin]]\n== Managing Dependencies with the Dependency Management Plugin\n\nWhen you apply the {url-dependency-management-plugin-site}[`io.spring.dependency-management`] plugin, Spring Boot's plugin will automatically xref:reacting.adoc#reacting-to-other-plugins.dependency-management[import the `spring-boot-dependencies` bom] from the version of Spring Boot that you are using.\nThis provides a similar dependency management experience to the one that's enjoyed by Maven users.\nFor example, it allows you to omit version numbers when declaring dependencies that are managed in the bom.\nTo make use of this functionality, declare dependencies in the usual way but omit the version number:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/dependencies.gradle[tags=dependencies]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/dependencies.gradle.kts[tags=dependencies]\n----\n======\n\n\n\n[[managing-dependencies.dependency-management-plugin.customizing]]\n=== Customizing Managed Versions\n\nThe `spring-boot-dependencies` bom that is automatically imported when the dependency management plugin is applied uses properties to control the versions of the dependencies that it manages.\nBrowse the xref:appendix:dependency-versions/properties.adoc[Dependency Versions Properties] section in the Spring Boot reference for a complete list of these properties.\n\nTo customize a managed version you set its corresponding property.\nFor example, to customize the version of SLF4J which is controlled by the `slf4j.version` property:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/custom-version.gradle[tags=custom-version]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/custom-version.gradle.kts[tags=custom-version]\n----\n======\n\nWARNING: Each Spring Boot release is designed and tested against a specific set of third-party dependencies.\nOverriding versions may cause compatibility issues and should be done with care.\n\n\n\n[[managing-dependencies.dependency-management-plugin.using-in-isolation]]\n=== Using Spring Boot's Dependency Management in Isolation\n\nSpring Boot's dependency management can be used in a project without applying Spring Boot's plugin to that project.\nThe `SpringBootPlugin` class provides a `BOM_COORDINATES` constant that can be used to import the bom without having to know its group ID, artifact ID, or version.\n\nFirst, configure the project to depend on the Spring Boot plugin but do not apply it:\n\nifeval::[\"{build-type}\" == \"commercial\"]\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-commercial.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-commercial.gradle.kts[]\n----\n======\nendif::[]\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-release\"]\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-release.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-release.gradle.kts[]\n----\n======\nendif::[]\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-milestone\"]\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-milestone.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-release.gradle.kts[]\n----\n======\nendif::[]\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-snapshot\"]\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-snapshot.gradle[]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/depend-on-plugin-release.gradle.kts[]\n----\n======\nendif::[]\n\nThe Spring Boot plugin's dependency on the dependency management plugin means that you can use the dependency management plugin without having to declare a dependency on it.\nThis also means that you will automatically use the same version of the dependency management plugin as Spring Boot uses.\n\nApply the dependency management plugin and then configure it to import Spring Boot's bom:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/configure-bom.gradle[tags=configure-bom]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/configure-bom.gradle.kts[tags=configure-bom]\n----\n======\n\nThe Kotlin code above is a bit awkward.\nThat's because we're using the imperative way of applying the dependency management plugin.\n\nWe can make the code less awkward by applying the plugin from the root parent project, or by using the `plugins` block as we're doing for the Spring Boot plugin.\nA downside of this method is that it forces us to specify the version of the dependency management plugin:\n\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/configure-bom-with-plugins.gradle.kts[tags=configure-bom]\n----\n\n\n\n[[managing-dependencies.dependency-management-plugin.learning-more]]\n=== Learning More\n\nTo learn more about the capabilities of the dependency management plugin, please refer to its {url-dependency-management-plugin-docs}[documentation].\n\n\n\n[[managing-dependencies.gradle-bom-support]]\n== Managing Dependencies with Gradle's Bom Support\n\nGradle allows a bom to be used to manage a project's versions by declaring it as a `platform` or `enforcedPlatform` dependency.\nA `platform` dependency treats the versions in the bom as recommendations and other versions and constraints in the dependency graph may cause a version of a dependency other than that declared in the bom to be used.\nAn `enforcedPlatform` dependency treats the versions in the bom as requirements and they will override any other version found in the dependency graph.\n\nThe `SpringBootPlugin` class provides a `BOM_COORDINATES` constant that can be used to declare a dependency upon Spring Boot's bom without having to know its group ID, artifact ID, or version, as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/configure-platform.gradle[tags=configure-platform]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/configure-platform.gradle.kts[tags=configure-platform]\n----\n======\n\nA platform or enforced platform will only constrain the versions of the configuration in which it has been declared or that extend from the configuration in which it has been declared.\nAs a result, in may be necessary to declare the same dependency in more than one configuration.\n\n\n\n[[managing-dependencies.gradle-bom-support.customizing]]\n=== Customizing Managed Versions\n\nWhen using Gradle's bom support, you cannot use the properties from `spring-boot-dependencies` to control the versions of the dependencies that it manages.\nInstead, you must use one of the mechanisms that Gradle provides.\nOne such mechanism is a resolution strategy.\nSLF4J's modules are all in the `org.slf4j` group so their version can be controlled by configuring every dependency in that group to use a particular version, as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/custom-version-with-platform.gradle[tags=custom-version]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$managing-dependencies/custom-version-with-platform.gradle.kts[tags=custom-version]\n----\n======\n\nWARNING: Each Spring Boot release is designed and tested against a specific set of third-party dependencies.\nOverriding versions may cause compatibility issues and should be done with care.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging-oci-image.adoc",
    "content": "[[build-image]]\n= Packaging OCI Images\n\nThe plugin can create an https://github.com/opencontainers/image-spec[OCI image] from a jar or war file using https://buildpacks.io[Cloud Native Buildpacks] (CNB).\nImages can be built using the `bootBuildImage` task.\n\nNOTE: For security reasons, images build and run as non-root users.\nSee the {url-buildpacks-docs}/reference/spec/platform-api/#users[CNB specification] for more details.\n\nThe task is automatically created when the `java` or `war` plugin is applied and is an instance of {apiref-gradle-plugin-boot-build-image}[`BootBuildImage`].\n\n\n\n[[build-image.docker-daemon]]\n== Docker Daemon\n\nThe `bootBuildImage` task requires access to a Docker daemon.\nThe task will inspect local Docker CLI https://docs.docker.com/engine/reference/commandline/cli/#configuration-files[configuration files] to determine the current https://docs.docker.com/engine/context/working-with-contexts/[context] and use the context connection information to communicate with a Docker daemon.\nIf the current context can not be determined or the context does not have connection information, then the task will use a default local connection.\nThis works with https://docs.docker.com/install/[Docker Engine] on all supported platforms without configuration.\n\nEnvironment variables can be set to configure the `bootBuildImage` task to use an alternative local or remote connection.\nThe following table shows the environment variables and their values:\n\n|===\n| Environment variable | Description\n\n| DOCKER_CONFIG\n| Location of Docker CLI https://docs.docker.com/engine/reference/commandline/cli/#configuration-files[configuration files] used to determine the current context (defaults to `$HOME/.docker`)\n\n| DOCKER_CONTEXT\n| Name of a https://docs.docker.com/engine/context/working-with-contexts/[context] that should be used to retrieve host information from Docker CLI configuration files (overrides `DOCKER_HOST`)\n\n| DOCKER_HOST\n| URL containing the host and port for the Docker daemon - for example `tcp://192.168.99.100:2376`\n\n| DOCKER_TLS_VERIFY\n| Enable secure HTTPS protocol when set to `1` (optional)\n\n| DOCKER_CERT_PATH\n| Path to certificate and key files for HTTPS (required if `DOCKER_TLS_VERIFY=1`, ignored otherwise)\n|===\n\nDocker daemon connection information can also be provided using `docker` properties in the plugin configuration.\nThe following table summarizes the available properties:\n\n|===\n| Property | Description\n\n| `context`\n| Name of a https://docs.docker.com/engine/context/working-with-contexts/[context] that should be used to retrieve host information from Docker CLI https://docs.docker.com/engine/reference/commandline/cli/#configuration-files[configuration files]\n\n| `host`\n| URL containing the host and port for the Docker daemon - for example `tcp://192.168.99.100:2376`\n\n| `tlsVerify`\n| Enable secure HTTPS protocol when set to `true` (optional)\n\n| `certPath`\n| Path to certificate and key files for HTTPS (required if `tlsVerify` is `true`, ignored otherwise)\n\n| `bindHostToBuilder`\n| When `true`, the value of the `host` property will be provided to the container that is created for the CNB builder (optional)\n|===\n\nFor more details, see also xref:packaging-oci-image.adoc#build-image.examples.docker[examples].\n\n\n\n[[build-image.docker-registry]]\n== Docker Registry\n\nIf the Docker images specified by the `builder` or `runImage` properties are stored in a private Docker image registry that requires authentication, the authentication credentials can be provided using `docker.builderRegistry` properties.\n\nIf the generated Docker image is to be published to a Docker image registry, the authentication credentials can be provided using `docker.publishRegistry` properties.\n\nProperties are provided for user authentication or identity token authentication.\nConsult the documentation for the Docker registry being used to store images for further information on supported authentication methods.\n\nThe following table summarizes the available properties for `docker.builderRegistry` and `docker.publishRegistry`:\n\n|===\n| Property | Description\n\n| `username`\n| Username for the Docker image registry user. Required for user authentication.\n\n| `password`\n| Password for the Docker image registry user. Required for user authentication.\n\n| `url`\n| Address of the Docker image registry. Optional for user authentication.\n\n| `email`\n| E-mail address for the Docker image registry user. Optional for user authentication.\n\n| `token`\n| Identity token for the Docker image registry user. Required for token authentication.\n|===\n\nFor more details, see also xref:packaging-oci-image.adoc#build-image.examples.docker[examples].\n\n[NOTE]\n====\nIf credentials are not provided, the plugin reads the user's existing Docker configuration file (typically located at `$HOME/.docker/config.json`) to determine authentication methods.\nUsing these methods, the plugin attempts to provide authentication credentials for the requested image.\n\nThe plugin supports the following authentication methods:\n\n- *Credential Helpers*: External tools configured in the Docker configuration file to provide credentials for specific registries. For example, tools like `osxkeychain` or `ecr-login` handle authentication for certain registries.\n- *Credential Store*: A default fallback mechanism that securely stores and retrieves credentials (e.g., `desktop` for Docker Desktop).\n- *Static Credentials*: Credentials that are stored directly in the Docker configuration file under the `auths` section.\n====\n\n\n\n[[build-image.customization]]\n== Image Customizations\n\nThe plugin invokes a {url-buildpacks-docs}/for-app-developers/concepts/builder/[builder] to orchestrate the generation of an image.\nThe builder includes multiple {url-buildpacks-docs}/for-app-developers/concepts/buildpack/[buildpacks] that can inspect the application to influence the generated image.\nBy default, the plugin chooses a builder image.\nThe name of the generated image is deduced from project properties.\n\nTask properties can be used to configure how the builder should operate on the project.\nThe following table summarizes the available properties and their default values:\n\n|===\n| Property | Command-line option | Description | Default value\n\n| `builder`\n| `--builder`\n| Name of the builder image to use.\n| `paketobuildpacks/builder-noble-java-tiny:latest`\n\n| `trustBuilder`\n| `--trustBuilder`\n| Whether to treat the builder as {url-buildpacks-docs}/for-platform-operators/how-to/integrate-ci/pack/concepts/trusted_builders/#what-is-a-trusted-builder[trusted].\n| `true` if the builder is one of `paketobuildpacks/builder-noble-java-tiny`, `paketobuildpacks/builder-jammy-java-tiny`, `paketobuildpacks/builder-jammy-tiny`, `paketobuildpacks/builder-jammy-base`, `paketobuildpacks/builder-jammy-full`, `paketobuildpacks/builder-jammy-buildpackless-tiny`, `paketobuildpacks/builder-jammy-buildpackless-base`, `paketobuildpacks/builder-jammy-buildpackless-full`, `gcr.io/buildpacks/builder`, `heroku/builder`; `false` otherwise.\n\n| `imagePlatform`\n| `--imagePlatform`\na|The platform (operating system and architecture) of any builder, run, and buildpack images that are pulled.\nMust be in the form of `OS[/architecture[/variant]]`, such as `linux/amd64`, `linux/arm64`, or `linux/arm/v5`.\nRefer to documentation of the builder being used to determine the image OS and architecture options available.\n| No default value, indicating that the platform of the host machine should be used.\n\n| `runImage`\n| `--runImage`\n| Name of the run image to use.\n| No default value, indicating the run image specified in Builder metadata should be used.\n\n| `imageName`\n| `--imageName`\n| javadoc:org.springframework.boot.buildpack.platform.docker.type.ImageReference#of(java.lang.String)[Image name] for the generated image.\n| `docker.io/library/${project.name}:${project.version}`\n\n| `pullPolicy`\n| `--pullPolicy`\n| javadoc:org.springframework.boot.buildpack.platform.build.PullPolicy[Policy] used to determine when to pull the builder and run images from the registry.\nAcceptable values are `ALWAYS`, `NEVER`, and `IF_NOT_PRESENT`.\n| `ALWAYS`\n\n| `environment`\n| `--environment`\n| Environment variables that should be passed to the builder.\n| Empty.\n\n| `buildpacks`\n|\na|Buildpacks that the builder should use when building the image.\nOnly the specified buildpacks will be used, overriding the default buildpacks included in the builder.\nBuildpack references must be in one of the following forms:\n\n* Buildpack in the builder - `[urn:cnb:builder:]<buildpack ID>[@<version>]`\n* Buildpack in a directory on the file system - `[file://]<path>`\n* Buildpack in a gzipped tar (.tgz) file on the file system - `[file://]<path>/<file name>`\n* Buildpack in an OCI image - `[docker://]<host>/<repo>[:<tag>][@<digest>]`\n| None, indicating the builder should use the buildpacks included in it.\n\n| `bindings`\n|\na|https://docs.docker.com/storage/bind-mounts/[Volume bind mounts] that should be mounted to the builder container when building the image.\nThe bindings will be passed unparsed and unvalidated to Docker when creating the builder container.\nBindings must be in one of the following forms:\n\n* `<host source path>:<container destination path>[:<options>]`\n* `<host volume name>:<container destination path>[:<options>]`\n\nWhere `<options>` can contain:\n\n* `ro` to mount the volume as read-only in the container\n* `rw` to mount the volume as readable and writable in the container\n* `volume-opt=key=value` to specify key-value pairs consisting of an option name and its value\n|\n\n| `network`\n| `--network`\n| The https://docs.docker.com/network/#network-drivers[network driver] the builder container will be configured to use.\nThe value supplied will be passed unvalidated to Docker when creating the builder container.\n|\n\n| `cleanCache`\n| `--cleanCache`\n| Whether to clean the cache before building.\n| `false`\n\n| `verboseLogging`\n|\n| Enables verbose logging of builder operations.\n| `false`\n\n| `publish`\n| `--publishImage`\n| Whether to publish the generated image to a Docker registry.\n| `false`\n\n| `tags`\n|\n| A list of one or more additional tags to apply to the generated image.\nThe values provided to the `tags` option should be *full* image references.\nSee xref:packaging-oci-image.adoc#build-image.customization.tags[the tags section] for more details.\n|\n\n| `buildWorkspace`\n|\n| A temporary workspace that will be used by the builder and buildpacks to store files during image building.\nThe value can be a named volume or a bind mount location.\n| A named volume in the Docker daemon, with a name derived from the image name.\n\n| `buildCache`\n|\n| A cache containing layers created by buildpacks and used by the image building process.\nThe value can be a named volume or a bind mount location.\n| A named volume in the Docker daemon, with a name derived from the image name.\n\n| `launchCache`\n|\n| A cache containing layers created by buildpacks and used by the image launching process.\nThe value can be a named volume or a bind mount location.\n| A named volume in the Docker daemon, with a name derived from the image name.\n\n| `createdDate`\n| `--createdDate`\n| A date that will be used to set the `Created` field in the generated image's metadata.\nThe value must be a string in the ISO 8601 instant format, or `now` to use the current date and time.\n| A fixed date that enables {url-buildpacks-docs}/for-app-developers/concepts/reproducibility/[build reproducibility].\n\n| `applicationDirectory`\n| `--applicationDirectory`\n| The path to a directory that application contents will be uploaded to in the builder image.\nApplication contents will also be in this location in the generated image.\n| `/workspace`\n\n| `securityOptions`\n| `--securityOptions`\n| https://docs.docker.com/reference/cli/docker/container/run/#security-opt[Security options] that will be applied to the builder container, provided as an array of string values\n| `[\"label=disable\"]` on Linux and macOS, `[]` on Windows\n\n|===\n\nNOTE: The plugin detects the target Java compatibility of the project using the JavaPlugin's `targetCompatibility` property.\nWhen using the default Paketo builder and buildpacks, the plugin instructs the buildpacks to install the same Java version.\nYou can override this behavior as shown in the xref:packaging-oci-image.adoc#build-image.examples.builder-configuration[builder configuration] examples.\n\nNOTE: The default builder `paketobuildpacks/builder-noble-java-tiny:latest` contains a reduced set of system libraries and does not include a shell.\nApplications that require a shell to run a start script, as might be the case when the {url-gradle-docs-application-plugin}[`application` plugin] has been applied to generate a distribution zip archive, or that depend upon a system library that is not present, should override the `runImage` configuration to use one that includes a shell and a broader set of system libraries, such as `paketobuildpacks/ubuntu-noble-run:latest`.\n\n\n\n[[build-image.customization.tags]]\n=== Tags Format\n\nThe values provided to the `tags` option should be *full* image references.\nThe accepted format is `[domainHost:port/][path/]name[:tag][@digest]`.\n\nIf the domain is missing, it defaults to `docker.io`.\nIf the path is missing, it defaults to `library`.\nIf the tag is missing, it defaults to `latest`.\n\nSome examples:\n\n* `my-image` leads to the image reference `docker.io/library/my-image:latest`\n* `my-repository/my-image` leads to `docker.io/my-repository/my-image:latest`\n* `example.com/my-repository/my-image:1.0.0` will be used as is\n\n\n\n[[build-image.examples]]\n== Examples\n\n\n\n[[build-image.examples.custom-image-builder]]\n=== Custom Image Builder and Run Image\n\nIf you need to customize the builder used to create the image or the run image used to launch the built image, configure the task as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-builder.gradle[tags=builder]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-builder.gradle.kts[tags=builder]\n----\n======\n\nThis configuration will use a builder image with the name `mine/java-cnb-builder` and the tag `latest`, and the run image named `mine/java-cnb-run` and the tag `latest`.\n\nThe builder and run image can be specified on the command line as well, as shown in this example:\n\n[source,shell]\n----\n$ gradle bootBuildImage --builder=mine/java-cnb-builder --runImage=mine/java-cnb-run\n----\n\n\n\n[[build-image.examples.builder-configuration]]\n=== Builder Configuration\n\nIf the builder exposes configuration options, those can be set using the `environment` property.\n\nThe following is an example of {url-paketo-docs-java-buildpack}/#configuring-the-jvm-version[configuring the JVM version] used by the Paketo Java buildpacks at build time:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-env.gradle[tags=env]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-env.gradle.kts[tags=env]\n----\n======\n\nEnvironment variables can also be specified on the command line, as shown in the following example:\n\n[source,shell]\n----\n$ gradle bootBuildImage --environment BP_JVM_VERSION=17\n----\n\n`--environment` can be used multiple times to specify multiple environment variables.\n\nIf there is a network proxy between the Docker daemon the builder runs in and network locations that buildpacks download artifacts from, you will need to configure the builder to use the proxy.\nWhen using the Paketo builder, this can be accomplished by setting the `HTTPS_PROXY` and/or `HTTP_PROXY` environment variables as show in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-env-proxy.gradle[tags=env]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-env-proxy.gradle.kts[tags=env]\n----\n======\n\n\n\n[[build-image.examples.runtime-jvm-configuration]]\n=== Runtime JVM Configuration\n\nPaketo Java buildpacks {url-paketo-docs-java-buildpack}/#runtime-jvm-configuration[configure the JVM runtime environment] by setting the `JAVA_TOOL_OPTIONS` environment variable.\nThe buildpack-provided `JAVA_TOOL_OPTIONS` value can be modified to customize JVM runtime behavior when the application image is launched in a container.\n\nEnvironment variable modifications that should be stored in the image and applied to every deployment can be set as described in the {url-paketo-docs}/buildpacks/configuration/#environment-variables[Paketo documentation] and shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-env-runtime.gradle[tags=env-runtime]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-env-runtime.gradle.kts[tags=env-runtime]\n----\n======\n\n\n\n[[build-image.examples.custom-image-name]]\n=== Custom Image Name\n\nBy default, the image name is inferred from the `name` and the `version` of the project, something like `docker.io/library/${project.name}:${project.version}`.\nYou can take control over the name by setting task properties, as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-name.gradle[tags=image-name]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-name.gradle.kts[tags=image-name]\n----\n======\n\nNote that this configuration does not provide an explicit tag so `latest` is used.\nIt is possible to specify a tag as well, either using `${project.version}`, any property available in the build or a hardcoded version.\n\nThe image name can be specified on the command line as well, as shown in this example:\n\n[source,shell]\n----\n$ gradle bootBuildImage --imageName=example.com/library/my-app:v1\n----\n\n\n\n[[build-image.examples.buildpacks]]\n=== Buildpacks\n\nBy default, the builder will use buildpacks included in the builder image and apply them in a pre-defined order.\nAn alternative set of buildpacks can be provided to apply buildpacks that are not included in the builder, or to change the order of included buildpacks.\nWhen one or more buildpacks are provided, only the specified buildpacks will be applied.\n\nThe following example instructs the builder to use a custom buildpack packaged in a `.tgz` file, followed by a buildpack included in the builder.\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-buildpacks.gradle[tags=buildpacks]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-buildpacks.gradle.kts[tags=buildpacks]\n----\n======\n\nBuildpacks can be specified in any of the forms shown below.\n\nA buildpack located in a CNB Builder (version may be omitted if there is only one buildpack in the builder matching the `buildpack-id`):\n\n* `urn:cnb:builder:buildpack-id`\n* `urn:cnb:builder:buildpack-id@0.0.1`\n* `buildpack-id`\n* `buildpack-id@0.0.1`\n\nA path to a directory containing buildpack content (not supported on Windows):\n\n* `\\file:///path/to/buildpack/`\n* `/path/to/buildpack/`\n\nA path to a gzipped tar file containing buildpack content:\n\n* `\\file:///path/to/buildpack.tgz`\n* `/path/to/buildpack.tgz`\n\nAn OCI image containing a {url-buildpacks-docs}/for-buildpack-authors/how-to/distribute-buildpacks/package-buildpack/[packaged buildpack]:\n\n* `docker://example/buildpack`\n* `docker:///example/buildpack:latest`\n* `docker:///example/buildpack@sha256:45b23dee08...`\n* `example/buildpack`\n* `example/buildpack:latest`\n* `example/buildpack@sha256:45b23dee08...`\n\n\n\n[[build-image.examples.publish]]\n=== Image Publishing\n\nThe generated image can be published to a Docker registry by enabling a `publish` option.\n\nIf the Docker registry requires authentication, the credentials can be configured using `docker.publishRegistry` properties.\nIf the Docker registry does not require authentication, the `docker.publishRegistry` configuration can be omitted.\n\nNOTE: The registry that the image will be published to is determined by the registry part of the image name (`docker.example.com` in these examples).\nIf `docker.publishRegistry` credentials are configured and include a `url` property, this value is passed to the registry but is not used to determine the publishing registry location.\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-publish.gradle[tags=publish]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-publish.gradle.kts[tags=publish]\n----\n======\n\nThe publish option can be specified on the command line as well, as shown in this example:\n\n[source,shell]\n----\n$ gradle bootBuildImage --imageName=docker.example.com/library/my-app:v1 --publishImage\n----\n\n\n\n[[build-image.examples.caches]]\n=== Builder Cache and Workspace Configuration\n\nThe CNB builder caches layers that are used when building and launching an image.\nBy default, these caches are stored as named volumes in the Docker daemon with names that are derived from the full name of the target image.\nIf the image name changes frequently, for example when the project version is used as a tag in the image name, then the caches can be invalidated frequently.\n\nThe cache volumes can be configured to use alternative names to give more control over cache lifecycle as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-caches.gradle[tags=caches]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-caches.gradle.kts[tags=caches]\n----\n======\n\nBuilders and buildpacks need a location to store temporary files during image building.\nBy default, this temporary build workspace is stored in a named volume.\n\nThe caches and the build workspace can be configured to use bind mounts instead of named volumes, as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-bind-caches.gradle[tags=caches]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-bind-caches.gradle.kts[tags=caches]\n----\n======\n\n\n\n[[build-image.examples.docker]]\n=== Docker Configuration\n\n\n\n[[build-image.examples.docker.minikube]]\n==== Docker Configuration for minikube\n\nThe plugin can communicate with the https://minikube.sigs.k8s.io/docs/tasks/docker_daemon/[Docker daemon provided by minikube] instead of the default local connection.\n\nOn Linux and macOS, environment variables can be set using the command `eval $(minikube docker-env)` after minikube has been started.\n\nThe plugin can also be configured to use the minikube daemon by providing connection details similar to those shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-host.gradle[tags=docker-host]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-host.gradle.kts[tags=docker-host]\n----\n======\n\n\n\n[[build-image.examples.docker.podman]]\n==== Docker Configuration for podman\n\nThe plugin can communicate with a https://podman.io/[podman container engine].\n\nThe plugin can be configured to use podman local connection by providing connection details similar to those shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-host-podman.gradle[tags=docker-host]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-host-podman.gradle.kts[tags=docker-host]\n----\n======\n\nTIP: With the `podman` CLI installed, the command `podman info --format='{{.Host.RemoteSocket.Path}}'` can be used to get the value for the `docker.host` configuration property shown in this example.\n\n\n\n[[build-image.examples.docker.colima]]\n==== Docker Configuration for Colima\n\nThe plugin can communicate with the Docker daemon provided by https://github.com/abiosoft/colima[Colima].\nThe `DOCKER_HOST` environment variable can be set by using the following command:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ export DOCKER_HOST=$(docker context inspect colima -f '{{.Endpoints.docker.Host}}')\n----\n\nThe plugin can also be configured to use Colima daemon by providing connection details similar to those shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-host-colima.gradle[tags=docker-host]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-host-colima.gradle.kts[tags=docker-host]\n----\n======\n\n\n\n[[build-image.examples.docker.auth]]\n==== Docker Configuration for Authentication\n\nIf the builder or run image are stored in a private Docker registry that supports user authentication, authentication details can be provided using `docker.builderRegistry` properties as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-auth-user.gradle[tags=docker-auth-user]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-auth-user.gradle.kts[tags=docker-auth-user]\n----\n======\n\nIf the builder or run image is stored in a private Docker registry that supports token authentication, the token value can be provided using `docker.builderRegistry` as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-auth-token.gradle[tags=docker-auth-token]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-build-image-docker-auth-token.gradle.kts[tags=docker-auth-token]\n----\n======\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/packaging.adoc",
    "content": "[[packaging-executable]]\n= Packaging Executable Archives\n\nThe plugin can create executable archives (jar files and war files) that contain all of an application's dependencies and can then be run with `java -jar`.\n\n\n\n[[packaging-executable.jars]]\n== Packaging Executable Jars\n\nExecutable jars can be built using the `bootJar` task.\nThe task is automatically created when the `java` plugin is applied and is an instance of {apiref-gradle-plugin-boot-jar}[`BootJar`].\nThe `assemble` task is automatically configured to depend upon the `bootJar` task so running `assemble` (or `build`) will also run the `bootJar` task.\n\n\n\n[[packaging-executable.wars]]\n== Packaging Executable Wars\n\nExecutable wars can be built using the `bootWar` task.\nThe task is automatically created when the `war` plugin is applied and is an instance of {apiref-gradle-plugin-boot-war}[`BootWar`].\nThe `assemble` task is automatically configured to depend upon the `bootWar` task so running `assemble` (or `build`) will also run the `bootWar` task.\n\n\n\n[[packaging-executable.wars.deployable]]\n=== Packaging Executable and Deployable Wars\n\nA war file can be packaged such that it can be executed using `java -jar` and deployed to an external container.\nTo do so, the embedded servlet container runtime should be added to the `providedRuntime` configuration, for example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/war-container-dependency.gradle[tags=dependencies]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/war-container-dependency.gradle.kts[tags=dependencies]\n----\n======\n\nThis ensures that the runtime jars are packaged in the war file's `WEB-INF/lib-provided` directory from where they will not conflict with the external container's own classes.\n\nNOTE: `providedRuntime` is preferred to Gradle's `compileOnly` configuration as, among other limitations, `compileOnly` dependencies are not on the test classpath so any web-based integration tests will fail.\n\n\n\n[[packaging-executable.and-plain-archives]]\n== Packaging Executable and Plain Archives\n\nBy default, when the `bootJar` or `bootWar` tasks are configured, the `jar` or `war` tasks are configured to use `plain` as the convention for their archive classifier.\nThis ensures that `bootJar` and `jar` or `bootWar` and `war` have different output locations, allowing both the executable archive and the plain archive to be built at the same time.\n\nIf you prefer that the executable archive, rather than the plain archive, uses a classifier, configure the classifiers as shown in the following example for the `jar` and `bootJar` tasks:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-and-jar-classifiers.gradle[tags=classifiers]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-and-jar-classifiers.gradle.kts[tags=classifiers]\n----\n======\n\nAlternatively, if you prefer that the plain archive isn't built at all, disable its task as shown in the following example for the `jar` task:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/only-boot-jar.gradle[tags=disable-jar]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/only-boot-jar.gradle.kts[tags=disable-jar]\n----\n======\n\nWARNING: Do not disable the `jar` task when creating native images.\nSee https://github.com/spring-projects/spring-boot/issues/33238[#33238] for details.\n\n\n\n[[packaging-executable.configuring]]\n== Configuring Executable Archive Packaging\n\nThe {apiref-gradle-plugin-boot-jar}[`BootJar`] and {apiref-gradle-plugin-boot-war}[`BootWar`] tasks are subclasses of Gradle's `Jar` and `War` tasks respectively.\nAs a result, all of the standard configuration options that are available when packaging a jar or war are also available when packaging an executable jar or war.\nA number of configuration options that are specific to executable jars and wars are also provided.\n\n\n\n[[packaging-executable.configuring.main-class]]\n=== Configuring the Main Class\n\nBy default, the executable archive's main class will be configured automatically by looking for a class with a `public static void main(String[])` method in the main source set's output.\n\nThe main class can also be configured explicitly using the task's `mainClass` property:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-main-class.gradle[tags=main-class]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-main-class.gradle.kts[tags=main-class]\n----\n======\n\nAlternatively, the main class name can be configured project-wide using the `mainClass` property of the Spring Boot DSL:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/spring-boot-dsl-main-class.gradle[tags=main-class]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/spring-boot-dsl-main-class.gradle.kts[tags=main-class]\n----\n======\n\nIf the {url-gradle-docs-application-plugin}[`application` plugin] has been applied its `mainClass` property must be configured and can be used for the same purpose:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/application-plugin-main-class.gradle[tags=main-class]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/application-plugin-main-class.gradle.kts[tags=main-class]\n----\n======\n\nLastly, the `Start-Class` attribute can be configured on the task's manifest:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-manifest-main-class.gradle[tags=main-class]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-manifest-main-class.gradle.kts[tags=main-class]\n----\n======\n\nNOTE: If the main class is written in Kotlin, the name of the generated Java class should be used.\nBy default, this is the name of the Kotlin class with the `Kt` suffix added.\nFor example, `ExampleApplication` becomes `ExampleApplicationKt`.\nIf another name is defined using `@JvmName` then that name should be used.\n\n\n\n[[packaging-executable.configuring.including-development-only-dependencies]]\n=== Including Development-only Dependencies\n\nBy default all dependencies declared in the `developmentOnly` configuration will be excluded from an executable jar or war.\n\nIf you want to include dependencies declared in the `developmentOnly` configuration in your archive, configure the classpath of its task to include the configuration, as shown in the following example for the `bootWar` task:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-war-include-devtools.gradle[tags=include-devtools]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-war-include-devtools.gradle.kts[tags=include-devtools]\n----\n======\n\n\n\n[[packaging-executable.configuring.unpacking]]\n=== Configuring Libraries that Require Unpacking\n\nMost libraries can be used directly when nested in an executable archive, however certain libraries can have problems.\nFor example, JRuby includes its own nested jar support which assumes that `jruby-complete.jar` is always directly available on the file system.\n\nTo deal with any problematic libraries, an executable archive can be configured to unpack specific nested jars to a temporary directory when the executable archive is run.\nLibraries can be identified as requiring unpacking using Ant-style patterns that match against the absolute path of the source jar file:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-requires-unpack.gradle[tags=requires-unpack]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-requires-unpack.gradle.kts[tags=requires-unpack]\n----\n======\n\nFor more control a closure can also be used.\nThe closure is passed a `FileTreeElement` and should return a `boolean` indicating whether or not unpacking is required.\n\n\n\n[[packaging-executable.configuring.properties-launcher]]\n=== Using the PropertiesLauncher\n\nTo use the `PropertiesLauncher` to launch an executable jar or war, configure the task's manifest to set the `Main-Class` attribute:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-war-properties-launcher.gradle[tags=properties-launcher]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-war-properties-launcher.gradle.kts[tags=properties-launcher]\n----\n======\n\n\n\n[[packaging-executable.configuring.layered-archives]]\n=== Packaging Layered Jar or War\n\nBy default, the `bootJar` task builds an archive that contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.\nSimilarly, `bootWar` builds an archive that contains the application's classes in `WEB-INF/classes` and dependencies in `WEB-INF/lib` and `WEB-INF/lib-provided`.\nFor cases where a docker image needs to be built from the contents of the jar, it's useful to be able to separate these directories further so that they can be written into distinct layers.\n\nLayered jars use the same layout as regular boot packaged jars, but include an additional meta-data file that describes each layer.\n\nBy default, the following layers are defined:\n\n* `dependencies` for any non-project dependency whose version does not contain `SNAPSHOT`.\n* `spring-boot-loader` for the jar loader classes.\n* `snapshot-dependencies` for any non-project dependency whose version contains `SNAPSHOT`.\n* `application` for project dependencies, application classes, and resources.\n\nThe layers order is important as it determines how likely previous layers can be cached when part of the application changes.\nThe default order is `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`.\nContent that is least likely to change should be added first, followed by layers that are more likely to change.\n\nTo disable this feature, you can do so in the following manner:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-layered-disabled.gradle[tags=layered]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-layered-disabled.gradle.kts[tags=layered]\n----\n======\n\nWhen a layered jar or war is created, the `spring-boot-jarmode-tools` jar will be added as a dependency to your archive.\nWith this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers.\nIf you wish to exclude this dependency, you can do so in the following manner:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-layered-exclude-tools.gradle[tags=layered]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-layered-exclude-tools.gradle.kts[tags=layered]\n----\n======\n\n\n\n[[packaging-executable.configuring.layered-archives.configuration]]\n==== Custom Layers Configuration\n\nDepending on your application, you may want to tune how layers are created and add new ones.\n\nThis can be done using configuration that describes how the jar or war can be separated into layers, and the order of those layers.\nThe following example shows how the default ordering described above can be defined explicitly:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-layered-custom.gradle[tags=layered]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/boot-jar-layered-custom.gradle.kts[tags=layered]\n----\n======\n\nThe `layered` DSL is defined using three parts:\n\n* The `application` closure defines how the application classes and resources should be layered.\n* The `dependencies` closure defines how dependencies should be layered.\n* The `layerOrder` method defines the order that the layers should be written.\n\nNested `intoLayer` closures are used within `application` and `dependencies` sections to claim content for a layer.\nThese closures are evaluated in the order that they are defined, from top to bottom.\nAny content not claimed by an earlier `intoLayer` closure remains available for subsequent ones to consider.\n\nThe `intoLayer` closure claims content using nested `include` and `exclude` calls.\nThe `application` closure uses Ant-style path matching for include/exclude parameters.\nThe `dependencies` section uses `group:artifact[:version]` patterns.\nIt also provides `includeProjectDependencies()` and `excludeProjectDependencies()` methods that can be used to include or exclude project dependencies.\n\nIf no `include` call is made, then all content (not claimed by an earlier closure) is considered.\n\nIf no `exclude` call is made, then no exclusions are applied.\n\nLooking at the `dependencies` closure in the example above, we can see that the first `intoLayer` will claim all project dependencies for the `application` layer.\nThe next `intoLayer` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.\nThe third and final `intoLayer` will claim anything left (in this case, any dependency that is not a project dependency or a SNAPSHOT) for the `dependencies` layer.\n\nThe `application` closure has similar rules.\nFirst claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.\nThen claiming any remaining classes and resources for the `application` layer.\n\nNOTE: The order that `intoLayer` closures are added is often different from the order that the layers are written.\nFor this reason the `layerOrder` method must always be called and _must_ cover all layers referenced by the `intoLayer` calls.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/publishing.adoc",
    "content": "[[publishing-your-application]]\n= Publishing your Application\n\n\n\n[[publishing-your-application.maven-publish]]\n== Publishing with the Maven-publish Plugin\n\nTo publish your Spring Boot jar or war, add it to the publication using the `artifact` method on `MavenPublication`.\nPass the task that produces that artifact that you wish to publish to the `artifact` method.\nFor example, to publish the artifact produced by the default `bootJar` task:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$publishing/maven-publish.gradle[tags=publishing]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$publishing/maven-publish.gradle.kts[tags=publishing]\n----\n======\n\n\n\n[[publishing-your-application.distribution]]\n== Distributing with the Application Plugin\n\nWhen the {url-gradle-docs-application-plugin}[`application` plugin] is applied a distribution named `boot` is created.\nThis distribution contains the archive produced by the `bootJar` or `bootWar` task and scripts to launch it on Unix-like platforms and Windows.\nZip and tar distributions can be built by the `bootDistZip` and `bootDistTar` tasks respectively.\nTo use the `application` plugin, its `mainClassName` property must be configured with the name of your application's main class.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/reacting.adoc",
    "content": "[[reacting-to-other-plugins]]\n= Reacting to Other Plugins\n\nWhen another plugin is applied the Spring Boot plugin reacts by making various changes to the project's configuration.\nThis section describes those changes.\n\n\n\n[[reacting-to-other-plugins.java]]\n== Reacting to the Java Plugin\n\nWhen Gradle's {url-gradle-docs-java-plugin}[`java` plugin] is applied to a project, the Spring Boot plugin:\n\n1. Creates a {apiref-gradle-plugin-boot-jar}[`BootJar`] task named `bootJar` that will create an executable, uber jar for the project.\n   The jar will contain everything on the runtime classpath of the main source set; classes are packaged in `BOOT-INF/classes` and jars are packaged in `BOOT-INF/lib`\n2. Configures the `assemble` task to depend on the `bootJar` task.\n3. Configures the `jar` task to use `plain` as the convention for its archive classifier.\n4. Creates a {apiref-gradle-plugin-boot-build-image}[`BootBuildImage`] task named `bootBuildImage` that will create a OCI image using a https://buildpacks.io[buildpack].\n5. Creates a {apiref-gradle-plugin-boot-run}[`BootRun`] task named `bootRun` that can be used to run your application using the `main` source set to find its main method and provide its runtime classpath.\n6. Creates a {apiref-gradle-plugin-boot-run}[`BootRun`] task named `bootTestRun` that can be used to run your application using the `test` source set to find its main method and provide its runtime classpath.\n7. Creates a configuration named `bootArchives` that contains the artifact produced by the `bootJar` task.\n8. Creates a configuration named `developmentOnly` for dependencies that are only required at development time, such as Spring Boot's Devtools, and should not be packaged in executable jars and wars.\n9. Creates a configuration named `testAndDevelopmentOnly` for dependencies that are only required at development time and when writing and running tests and that should not be packaged in executable jars and wars.\n10. Creates a configuration named `productionRuntimeClasspath`. It is equivalent to `runtimeClasspath` minus any dependencies that only appear in the `developmentOnly` or `testDevelopmentOnly` configurations.\n11. Configures any `JavaCompile` tasks with no configured encoding to use `UTF-8`.\n12. Configures any `JavaCompile` tasks to use the `-parameters` compiler argument.\n\n\n\n[[reacting-to-other-plugins.kotlin]]\n== Reacting to the Kotlin Plugin\n\nWhen {url-kotlin-docs-kotlin-plugin}[Kotlin's Gradle plugin] is applied to a project, the Spring Boot plugin:\n\n1. Aligns the Kotlin version used in Spring Boot's dependency management with the version of the plugin.\n   This is achieved by setting the `kotlin.version` property with a value that matches the version of the Kotlin plugin.\n2. Configures any `KotlinCompile` tasks to use the `-java-parameters` compiler argument.\n\n\n\n[[reacting-to-other-plugins.war]]\n== Reacting to the War Plugin\n\nWhen Gradle's {url-gradle-docs-war-plugin}[`war` plugin] is applied to a project, the Spring Boot plugin:\n\n1. Creates a {apiref-gradle-plugin-boot-war}[`BootWar`] task named `bootWar` that will create an executable, fat war for the project.\n   In addition to the standard packaging, everything in the `providedRuntime` configuration will be packaged in `WEB-INF/lib-provided`.\n2. Configures the `assemble` task to depend on the `bootWar` task.\n3. Configures the `war` task to use `plain` as the convention for its archive classifier.\n4. Configures the `bootArchives` configuration to contain the artifact produced by the `bootWar` task.\n\n\n\n[[reacting-to-other-plugins.dependency-management]]\n== Reacting to the Dependency Management Plugin\n\nWhen the {url-dependency-management-plugin-site}[`io.spring.dependency-management` plugin] is applied to a project, the Spring Boot plugin will automatically import the `spring-boot-dependencies` bom.\n\n\n\n[[reacting-to-other-plugins.application]]\n== Reacting to the Application Plugin\n\nWhen Gradle's {url-gradle-docs-application-plugin}[`application` plugin] is applied to a project, the Spring Boot plugin:\n\n1. Creates a `CreateStartScripts` task named `bootStartScripts` that will create scripts that launch the artifact in the `bootArchives` configuration using `java -jar`.\n   The task is configured to use the `applicationDefaultJvmArgs` property as a convention for its `defaultJvmOpts` property.\n2. Creates a new distribution named `boot` and configures it to contain the artifact in the `bootArchives` configuration in its `lib` directory and the start scripts in its `bin` directory.\n3. Configures the `bootRun` task to use the `mainClassName` property as a convention for its `main` property.\n4. Configures the `bootRun` and `bootTestRun` tasks to use the `applicationDefaultJvmArgs` property as a convention for their `jvmArgs` property.\n5. Configures the `bootJar` task to use the `mainClassName` property as a convention for the `Start-Class` entry in its manifest.\n6. Configures the `bootWar` task to use the `mainClassName` property as a convention for the `Start-Class` entry in its manifest.\n\n\n\n[[reacting-to-other-plugins.nbt]]\n== Reacting to the GraalVM Native Image Plugin\n\nWhen the {url-native-build-tools-docs-gradle-plugin}[GraalVM Native Image plugin] is applied to a project, the Spring Boot plugin:\n\n. Applies the `org.springframework.boot.aot` plugin that:\n.. Registers `aot` and `aotTest` source sets.\n.. Registers a `ProcessAot` task named `processAot` that will generate AOT-optimized source for the application in the `aot` source set.\n.. Configures the Java compilation and process resources tasks for the `aot` source set to depend upon `processAot`.\n.. Registers a `ProcessTestAot` task named `processTestAot` that will generated AOT-optimized source for the application's tests in the `aotTest` source set.\n.. Configures the Java compilation and process resources tasks for the `aotTest` source set to depend upon `processTestAot`.\n. Adds the output of the `aot` source set to the classpath of the `main` GraalVM native binary.\n. Adds the output of the `aotTest` source set to the classpath of the `test` GraalVM native binary.\n. Configures the GraalVM extension to disable Toolchain detection.\n. Configures the `bootJar` task to include the reachability metadata produced by the `collectReachabilityMetadata` task in its jar.\n. Configures the `bootJar` task to add the `Spring-Boot-Native-Processed: true` manifest entry.\n\n\n\n[[reacting-to-other-plugins.cyclonedx]]\n== Reacting to the CycloneDX Plugin\n\nWhen the {url-cyclonedx-docs-gradle-plugin}[CycloneDX plugin] is applied to a project, the Spring Boot plugin:\n\n. Configures the `cyclonedxBom` task to:\n.. Use the `application` project type.\n.. Output a JSON-format SBOM to the `application.cdx.json` file.\n.. Disable the XML-format SBOM.\n.. Disable full license texts.\n. Adds the SBOM under `META-INF/sbom` in the generated jar or war file.\n. Adds the `Sbom-Format` and `Sbom-Location` to the manifest of the jar or war file.\n\n\n\n[[reacting-to-other-plugins.protobuf]]\n== Reacting to the Protobuf Plugin\n\nWhen the {url-protobuf-docs-gradle-plugin}[Protobuf plugin] is applied to a project, the Spring Boot plugin:\n\n. Configures `protoc` to use the artifact `com.google.protobuf:protoc`, aligning its version with that of Protobuf dependencies on the runtime classpath.\n. Configures the `grpc` plugin to use the artifact `io.grpc:protoc-gen-grpc-java`, aligning its version with that of gRPC dependencies on the runtime classpath.\n. Configures the `grpc` plugin of all generate proto tasks with the option `@generated=omit`.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/pages/running.adoc",
    "content": "[[running-your-application]]\n= Running your Application with Gradle\n\nTo run your application without first building an archive use the `bootRun` task:\n\n[source,shell]\n----\n$ ./gradlew bootRun\n----\n\nThe `bootRun` task is an instance of {apiref-gradle-plugin-boot-run}[`BootRun`] which is a `JavaExec` subclass.\nAs such, all of the {url-gradle-dsl}/org.gradle.api.tasks.JavaExec.html[usual configuration options] for executing a Java process in Gradle are available to you.\nThe task is automatically configured to use the runtime classpath of the main source set.\n\nBy default, the main class will be configured automatically by looking for a class with a `public static void main(String[])` method in the main source set's output.\n\nThe main class can also be configured explicitly using the task's `main` property:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-main.gradle[tags=main]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-main.gradle.kts[tags=main]\n----\n======\n\nAlternatively, the main class name can be configured project-wide using the `mainClass` property of the Spring Boot DSL:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/spring-boot-dsl-main-class-name.gradle[tags=main-class]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/spring-boot-dsl-main-class-name.gradle.kts[tags=main-class]\n----\n======\n\nBy default, `bootRun` will configure the JVM to optimize its launch for faster startup during development.\nThis behavior can be disabled by using the `optimizedLaunch` property, as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-disable-optimized-launch.gradle[tags=launch]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-disable-optimized-launch.gradle.kts[tags=launch]\n----\n======\n\nIf the {url-gradle-docs-application-plugin}[`application` plugin] has been applied, its `mainClass` property must be configured and can be used for the same purpose:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/application-plugin-main-class-name.gradle[tags=main-class]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/application-plugin-main-class-name.gradle.kts[tags=main-class]\n----\n======\n\n\n\n[[running-your-application.passing-arguments]]\n== Passing Arguments to Your Application\n\nLike all `JavaExec` tasks, arguments can be passed into `bootRun` from the command line using `--args='<arguments>'` when using Gradle 4.9 or later.\nFor example, to run your application with a profile named `dev` active the following command can be used:\n\n[source,shell]\n----\n$ ./gradlew bootRun --args='--spring.profiles.active=dev'\n----\n\nSee {url-gradle-javadoc}/org/gradle/api/tasks/JavaExec.html#setArgsString(java.lang.String)[the javadoc for `JavaExec.setArgsString`] for further details.\n\n\n\n[[running-your-application.passing-system-properties]]\n== Passing System Properties to Your application\n\nSince `bootRun` is a standard `JavaExec` task, system properties can be passed to the application's JVM by specifying them in the build script.\nTo make that value of a system property to be configurable set its value using a {url-gradle-dsl}/org.gradle.api.Project.html#N14FE1[project property].\nTo allow a project property to be optional, reference it using `findProperty`.\nDoing so also allows a default value to be provided using the `?:` Elvis operator, as shown in the following example:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-system-property.gradle[tags=system-property]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-system-property.gradle.kts[tags=system-property]\n----\n======\n\nThe preceding example sets that `com.example.property` system property to the value of the `example` project property.\nIf the `example` project property has not been set, the value of the system property will be `default`.\n\nGradle allows project properties to be set in a variety of ways, including on the command line using the `-P` flag, as shown in the following example:\n\n[source,bash,indent=0,subs=\"verbatim,attributes\"]\n----\n$ ./gradlew bootRun -Pexample=custom\n----\n\nThe preceding example sets the value of the `example` project property to `custom`.\n`bootRun` will then use this as the value of the `com.example.property` system property.\n\n\n\n[[running-your-application.reloading-resources]]\n== Reloading Resources\n\nIf devtools has been added to your project it will automatically monitor your application's classpath for changes.\nNote that modified files need to be recompiled for the classpath to update in order to trigger reloading with devtools.\nFor more details on using devtools, refer to xref:reference:using/devtools.adoc#using.devtools.restart[this section of the reference documentation].\n\nAlternatively, you can configure `bootRun` such that your application's static resources are loaded from their source location:\n\n[tabs]\n======\nGroovy::\n+\n[source,groovy,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-source-resources.gradle[tags=source-resources]\n----\nKotlin::\n+\n[source,kotlin,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/boot-run-source-resources.gradle.kts[tags=source-resources]\n----\n======\n\nThis makes them reloadable in the live application which can be helpful at development time.\n\n\n\n[[running-your-application.using-a-test-main-class]]\n== Using a Test Main Class\n\nIn addition to `bootRun` a `bootTestRun` task is also registered.\nLike `bootRun`, `bootTestRun` is an instance of `BootRun` but it's configured to use a main class found in the output of the test source set rather than the main source set.\nIt also uses the test source set's runtime classpath rather than the main source set's runtime classpath.\nAs `bootTestRun` is an instance of `BootRun`, all of the configuration options described above for `bootRun` can also be used with `bootTestRun`.\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/docs/antora/modules/gradle-plugin/partials/nav-gradle-plugin.adoc",
    "content": "* xref:gradle-plugin:index.adoc[]\n** xref:gradle-plugin:getting-started.adoc[]\n** xref:gradle-plugin:managing-dependencies.adoc[]\n** xref:gradle-plugin:packaging.adoc[]\n** xref:gradle-plugin:packaging-oci-image.adoc[]\n** xref:gradle-plugin:publishing.adoc[]\n** xref:gradle-plugin:running.adoc[]\n** xref:gradle-plugin:aot.adoc[]\n** xref:gradle-plugin:integrating-with-actuator.adoc[]\n** xref:gradle-plugin:reacting.adoc[]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/SpringBootExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.dsl;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Project;\nimport org.gradle.api.file.SourceDirectorySet;\nimport org.gradle.api.plugins.BasePlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.gradle.tasks.buildinfo.BuildInfo;\n\n/**\n * Entry point to Spring Boot's Gradle DSL.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 2.0.0\n */\npublic class SpringBootExtension {\n\n\tprivate final Project project;\n\n\tprivate final Property<String> mainClass;\n\n\t/**\n\t * Creates a new {@code SpringBootPluginExtension} that is associated with the given\n\t * {@code project}.\n\t * @param project the project\n\t */\n\tpublic SpringBootExtension(Project project) {\n\t\tthis.project = project;\n\t\tthis.mainClass = this.project.getObjects().property(String.class);\n\t}\n\n\t/**\n\t * Returns the fully-qualified name of the application's main class.\n\t * @return the fully-qualified name of the application's main class\n\t * @since 2.4.0\n\t */\n\tpublic Property<String> getMainClass() {\n\t\treturn this.mainClass;\n\t}\n\n\t/**\n\t * Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and adds its\n\t * output as a {@link SourceDirectorySet#srcDir source directory} of the main source\n\t * set's {@link SourceSet#getResources resources}.\n\t * <p>\n\t * By default, the task's project artifact will be the archive base name of the\n\t * {@code bootWar} or {@code bootJar} task.\n\t */\n\tpublic void buildInfo() {\n\t\tbuildInfo(null);\n\t}\n\n\t/**\n\t * Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and adds its\n\t * output as a {@link SourceDirectorySet#srcDir source directory} of the main source\n\t * set's {@link SourceSet#getResources resources}. The task is passed to the given\n\t * {@code configurer} for further configuration.\n\t * <p>\n\t * By default, the task's project artifact will be the archive base name of the\n\t * {@code bootWar} or {@code bootJar} task.\n\t * @param configurer the task configurer\n\t */\n\tpublic void buildInfo(@Nullable Action<BuildInfo> configurer) {\n\t\tTaskContainer tasks = this.project.getTasks();\n\t\tTaskProvider<BuildInfo> bootBuildInfo = tasks.register(\"bootBuildInfo\", BuildInfo.class,\n\t\t\t\tthis::configureBuildInfoTask);\n\t\tthis.project.getPlugins().withType(JavaPlugin.class, (plugin) -> {\n\t\t\tbootBuildInfo.configure((buildInfo) -> buildInfo.getProperties()\n\t\t\t\t.getArtifact()\n\t\t\t\t.convention(this.project.provider(this::determineArtifactBaseName)));\n\t\t\tthis.project.getExtensions()\n\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t.getSourceSets()\n\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME)\n\t\t\t\t.getResources()\n\t\t\t\t.srcDir(bootBuildInfo);\n\t\t});\n\t\tif (configurer != null) {\n\t\t\tbootBuildInfo.configure(configurer);\n\t\t}\n\t}\n\n\tprivate void configureBuildInfoTask(BuildInfo task) {\n\t\ttask.setGroup(BasePlugin.BUILD_GROUP);\n\t\ttask.setDescription(\"Generates a META-INF/build-info.properties file.\");\n\t}\n\n\tprivate @Nullable String determineArtifactBaseName() {\n\t\tJar artifactTask = findArtifactTask();\n\t\treturn (artifactTask != null) ? artifactTask.getArchiveBaseName().get() : null;\n\t}\n\n\tprivate @Nullable Jar findArtifactTask() {\n\t\tJar artifactTask = (Jar) this.project.getTasks().findByName(\"bootWar\");\n\t\tif (artifactTask != null) {\n\t\t\treturn artifactTask;\n\t\t}\n\t\treturn (Jar) this.project.getTasks().findByName(\"bootJar\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot Gradle DSL.\n */\n@NullMarked\npackage org.springframework.boot.gradle.dsl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.StringWriter;\nimport java.util.concurrent.Callable;\n\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.distribution.Distribution;\nimport org.gradle.api.distribution.DistributionContainer;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.plugins.ApplicationPlugin;\nimport org.gradle.api.plugins.JavaApplication;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.application.CreateStartScripts;\nimport org.gradle.jvm.application.scripts.TemplateBasedScriptGenerator;\nimport org.gradle.util.GradleVersion;\n\nimport org.springframework.boot.gradle.tasks.run.BootRun;\nimport org.springframework.util.Assert;\n\n/**\n * Action that is executed in response to the {@link ApplicationPlugin} being applied.\n *\n * @author Andy Wilkinson\n */\nfinal class ApplicationPluginAction implements PluginApplicationAction {\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tJavaApplication javaApplication = project.getExtensions().getByType(JavaApplication.class);\n\t\tDistributionContainer distributions = project.getExtensions().getByType(DistributionContainer.class);\n\t\tDistribution distribution = distributions.create(\"boot\");\n\t\tdistribution.getDistributionBaseName()\n\t\t\t.convention((project.provider(() -> javaApplication.getApplicationName() + \"-boot\")));\n\t\tTaskProvider<CreateStartScripts> bootStartScripts = project.getTasks()\n\t\t\t.register(\"bootStartScripts\", CreateStartScripts.class,\n\t\t\t\t\t(task) -> configureCreateStartScripts(project, javaApplication, distribution, task));\n\t\tCopySpec binCopySpec = project.copySpec().into(\"bin\").from(bootStartScripts);\n\t\tconfigureFilePermissions(binCopySpec, 0755);\n\t\tdistribution.getContents().with(binCopySpec);\n\t\tapplyApplicationDefaultJvmArgsToRunTasks(project.getTasks(), javaApplication);\n\t}\n\n\tprivate void applyApplicationDefaultJvmArgsToRunTasks(TaskContainer tasks, JavaApplication javaApplication) {\n\t\tapplyApplicationDefaultJvmArgsToRunTask(tasks, javaApplication, SpringBootPlugin.BOOT_RUN_TASK_NAME);\n\t\tapplyApplicationDefaultJvmArgsToRunTask(tasks, javaApplication, SpringBootPlugin.BOOT_TEST_RUN_TASK_NAME);\n\t}\n\n\tprivate void applyApplicationDefaultJvmArgsToRunTask(TaskContainer tasks, JavaApplication javaApplication,\n\t\t\tString taskName) {\n\t\ttasks.named(taskName, BootRun.class)\n\t\t\t.configure(\n\t\t\t\t\t(bootRun) -> bootRun.getJvmArguments().convention(javaApplication.getApplicationDefaultJvmArgs()));\n\t}\n\n\tprivate void configureCreateStartScripts(Project project, JavaApplication javaApplication,\n\t\t\tDistribution distribution, CreateStartScripts createStartScripts) {\n\t\tcreateStartScripts\n\t\t\t.setDescription(\"Generates OS-specific start scripts to run the project as a Spring Boot application.\");\n\t\t((TemplateBasedScriptGenerator) createStartScripts.getUnixStartScriptGenerator())\n\t\t\t.setTemplate(project.getResources().getText().fromString(loadResource(\"/unixStartScript.txt\")));\n\t\t((TemplateBasedScriptGenerator) createStartScripts.getWindowsStartScriptGenerator())\n\t\t\t.setTemplate(project.getResources().getText().fromString(loadResource(\"/windowsStartScript.txt\")));\n\t\tproject.getConfigurations().all((configuration) -> {\n\t\t\tif (\"bootArchives\".equals(configuration.getName())) {\n\t\t\t\tdistribution.getContents().with(artifactFilesToLibCopySpec(project, configuration));\n\t\t\t\tcreateStartScripts.setClasspath(configuration.getArtifacts().getFiles());\n\t\t\t}\n\t\t});\n\t\tcreateStartScripts.getConventionMapping()\n\t\t\t.map(\"outputDir\", () -> project.getLayout().getBuildDirectory().dir(\"bootScripts\").get().getAsFile());\n\t\tcreateStartScripts.getConventionMapping().map(\"applicationName\", javaApplication::getApplicationName);\n\t\tcreateStartScripts.getConventionMapping().map(\"defaultJvmOpts\", javaApplication::getApplicationDefaultJvmArgs);\n\t}\n\n\tprivate CopySpec artifactFilesToLibCopySpec(Project project, Configuration configuration) {\n\t\tCopySpec copySpec = project.copySpec().into(\"lib\").from(artifactFiles(configuration));\n\t\tconfigureFilePermissions(copySpec, 0644);\n\t\treturn copySpec;\n\t}\n\n\tprivate Callable<FileCollection> artifactFiles(Configuration configuration) {\n\t\treturn () -> configuration.getArtifacts().getFiles();\n\t}\n\n\t@Override\n\tpublic Class<? extends Plugin<Project>> getPluginClass() {\n\t\treturn ApplicationPlugin.class;\n\t}\n\n\tprivate String loadResource(String name) {\n\t\ttry (InputStreamReader reader = new InputStreamReader(getResourceAsStream(name))) {\n\t\t\tchar[] buffer = new char[4096];\n\t\t\tint read;\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\twhile ((read = reader.read(buffer)) > 0) {\n\t\t\t\twriter.write(buffer, 0, read);\n\t\t\t}\n\t\t\treturn writer.toString();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new GradleException(\"Failed to read '\" + name + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate InputStream getResourceAsStream(String name) {\n\t\tInputStream stream = getClass().getResourceAsStream(name);\n\t\tAssert.state(stream != null, \"Resource '%s' not found'\".formatted(name));\n\t\treturn stream;\n\t}\n\n\tprivate void configureFilePermissions(CopySpec copySpec, int mode) {\n\t\tif (GradleVersion.current().compareTo(GradleVersion.version(\"8.3\")) >= 0) {\n\t\t\tcopySpec.filePermissions((filePermissions) -> filePermissions.unix(Integer.toString(mode, 8)));\n\t\t}\n\t\telse {\n\t\t\tconfigureFileMode(copySpec, mode);\n\t\t}\n\t}\n\n\tprivate void configureFileMode(CopySpec copySpec, int mode) {\n\t\ttry {\n\t\t\tcopySpec.getClass().getMethod(\"setFileMode\", Integer.class).invoke(copySpec, Integer.valueOf(mode));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(\"Failed to set file mode on CopySpec\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/CyclonedxPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.cyclonedx.gradle.CyclonedxAggregateTask;\nimport org.cyclonedx.gradle.CyclonedxPlugin;\nimport org.cyclonedx.model.Component;\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.Copy;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar;\nimport org.springframework.boot.gradle.tasks.bundling.BootWar;\n\n/**\n * {@link Action} that is executed in response to the {@link CyclonedxPlugin} being\n * applied.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nfinal class CyclonedxPluginAction implements PluginApplicationAction {\n\n\t@Override\n\tpublic Class<? extends Plugin<? extends Project>> getPluginClass() {\n\t\treturn CyclonedxPlugin.class;\n\t}\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tTaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider = project.getTasks()\n\t\t\t.named(\"cyclonedxBom\", CyclonedxAggregateTask.class);\n\t\tconfigureCycloneDxTask(cycloneDxTaskProvider, project);\n\t\tconfigureJavaPlugin(project, cycloneDxTaskProvider);\n\t\tconfigureSpringBootPlugin(project, cycloneDxTaskProvider);\n\t}\n\n\tprivate void configureCycloneDxTask(TaskProvider<CyclonedxAggregateTask> taskProvider, Project project) {\n\t\ttaskProvider.configure((task) -> {\n\t\t\ttask.getProjectType().convention(Component.Type.APPLICATION);\n\t\t\ttask.getXmlOutput().unsetConvention();\n\t\t\ttask.getJsonOutput()\n\t\t\t\t.convention(project.getLayout().getBuildDirectory().file(\"reports/cyclonedx/application.cdx.json\"));\n\t\t\ttask.getIncludeLicenseText().convention(false);\n\t\t});\n\t}\n\n\tprivate void configureJavaPlugin(Project project, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {\n\t\tconfigurePlugin(project, JavaPlugin.class, (javaPlugin) -> {\n\t\t\tJavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\t\tSourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\tconfigureTask(project, main.getProcessResourcesTaskName(), Copy.class, (copy) -> {\n\t\t\t\tcopy.dependsOn(cycloneDxTaskProvider);\n\t\t\t\tProvider<String> sbomFileName = cycloneDxTaskProvider.flatMap(\n\t\t\t\t\t\t(cycloneDxTask) -> cycloneDxTask.getJsonOutput().map((file) -> file.getAsFile().getName()));\n\t\t\t\tcopy.from(cycloneDxTaskProvider,\n\t\t\t\t\t\t(spec) -> spec.include((element) -> element.getName().equals(sbomFileName.get()))\n\t\t\t\t\t\t\t.into(\"META-INF/sbom\"));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate void configureSpringBootPlugin(Project project,\n\t\t\tTaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {\n\t\tconfigurePlugin(project, SpringBootPlugin.class, (springBootPlugin) -> {\n\t\t\tconfigureBootJarTask(project, cycloneDxTaskProvider);\n\t\t\tconfigureBootWarTask(project, cycloneDxTaskProvider);\n\t\t});\n\t}\n\n\tprivate void configureBootJarTask(Project project, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {\n\t\tconfigureTask(project, SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class,\n\t\t\t\t(bootJar) -> configureBootJarTask(bootJar, cycloneDxTaskProvider));\n\t}\n\n\tprivate void configureBootWarTask(Project project, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {\n\t\tconfigureTask(project, SpringBootPlugin.BOOT_WAR_TASK_NAME, BootWar.class,\n\t\t\t\t(bootWar) -> configureBootWarTask(bootWar, cycloneDxTaskProvider));\n\t}\n\n\tprivate void configureBootJarTask(BootJar task, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {\n\t\tconfigureJarTask(task, cycloneDxTaskProvider, \"\");\n\t}\n\n\tprivate void configureBootWarTask(BootWar task, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider) {\n\t\tconfigureJarTask(task, cycloneDxTaskProvider, \"WEB-INF/classes/\");\n\t}\n\n\tprivate void configureJarTask(Jar task, TaskProvider<CyclonedxAggregateTask> cycloneDxTaskProvider,\n\t\t\tString sbomLocationPrefix) {\n\t\tProvider<String> sbomFileName = cycloneDxTaskProvider\n\t\t\t.map((cycloneDxTask) -> \"META-INF/sbom/\" + cycloneDxTask.getJsonOutput().get().getAsFile().getName());\n\t\ttask.manifest((manifest) -> {\n\t\t\tmanifest.getAttributes().put(\"Sbom-Format\", \"CycloneDX\");\n\t\t\tmanifest.getAttributes()\n\t\t\t\t.put(\"Sbom-Location\", sbomFileName.map((fileName) -> sbomLocationPrefix + fileName));\n\t\t});\n\t}\n\n\tprivate <T extends Task> void configureTask(Project project, String name, Class<T> type, Action<T> action) {\n\t\tproject.getTasks().withType(type).configureEach((task) -> {\n\t\t\tif (task.getName().equals(name)) {\n\t\t\t\taction.execute(task);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate <T extends Plugin<?>> void configurePlugin(Project project, Class<T> plugin, Action<T> action) {\n\t\tproject.getPlugins().withType(plugin, action);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport io.spring.gradle.dependencymanagement.DependencyManagementPlugin;\nimport io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension;\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link Action} that is performed in response to the {@link DependencyManagementPlugin}\n * being applied.\n *\n * @author Andy Wilkinson\n */\nfinal class DependencyManagementPluginAction implements PluginApplicationAction {\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tDependencyManagementExtension extension = project.getExtensions()\n\t\t\t.findByType(DependencyManagementExtension.class);\n\t\tAssert.state(extension != null, \"'extension' must not be null\");\n\t\textension.imports((importsHandler) -> importsHandler.mavenBom(SpringBootPlugin.BOM_COORDINATES));\n\t}\n\n\t@Override\n\tpublic Class<? extends Plugin<Project>> getPluginClass() {\n\t\treturn DependencyManagementPlugin.class;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JarTypeFileSpec.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\nimport java.util.Set;\nimport java.util.jar.JarFile;\n\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.specs.Spec;\n\n/**\n * A {@link Spec} for {@link FileCollection#filter(Spec) filtering} {@code FileCollection}\n * to remove jar files based on their {@code Spring-Boot-Jar-Type} as defined in the\n * manifest. Jars of type {@code dependencies-starter} are excluded.\n *\n * @author Andy Wilkinson\n */\nclass JarTypeFileSpec implements Spec<File> {\n\n\tprivate static final Set<String> EXCLUDED_JAR_TYPES = Set.of(\"dependencies-starter\", \"development-tool\");\n\n\t@Override\n\tpublic boolean isSatisfiedBy(File file) {\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tString jarType = jar.getManifest().getMainAttributes().getValue(\"Spring-Boot-Jar-Type\");\n\t\t\tif (jarType != null && EXCLUDED_JAR_TYPES.contains(jarType)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Continue\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.attributes.Attribute;\nimport org.gradle.api.attributes.AttributeContainer;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.plugins.ApplicationPlugin;\nimport org.gradle.api.plugins.BasePlugin;\nimport org.gradle.api.plugins.ExtensionContainer;\nimport org.gradle.api.plugins.JavaApplication;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.provider.ProviderFactory;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.gradle.api.tasks.compile.JavaCompile;\nimport org.gradle.jvm.toolchain.JavaToolchainService;\nimport org.gradle.jvm.toolchain.JavaToolchainSpec;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.gradle.dsl.SpringBootExtension;\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage;\nimport org.springframework.boot.gradle.tasks.bundling.BootJar;\nimport org.springframework.boot.gradle.tasks.run.BootRun;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Action} that is executed in response to the {@link JavaPlugin} being applied.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nfinal class JavaPluginAction implements PluginApplicationAction {\n\n\tprivate static final String PARAMETERS_COMPILER_ARG = \"-parameters\";\n\n\tprivate final SinglePublishedArtifact singlePublishedArtifact;\n\n\tJavaPluginAction(SinglePublishedArtifact singlePublishedArtifact) {\n\t\tthis.singlePublishedArtifact = singlePublishedArtifact;\n\t}\n\n\t@Override\n\tpublic Class<? extends Plugin<? extends Project>> getPluginClass() {\n\t\treturn JavaPlugin.class;\n\t}\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tclassifyJarTask(project);\n\t\tconfigureBuildTask(project);\n\t\tconfigureProductionRuntimeClasspathConfiguration(project);\n\t\tconfigureDevelopmentOnlyConfiguration(project);\n\t\tconfigureTestAndDevelopmentOnlyConfiguration(project);\n\t\tTaskProvider<ResolveMainClassName> resolveMainClassName = configureResolveMainClassNameTask(project);\n\t\tTaskProvider<BootJar> bootJar = configureBootJarTask(project, resolveMainClassName);\n\t\tconfigureBootBuildImageTask(project, bootJar);\n\t\tconfigureArtifactPublication(bootJar);\n\t\tconfigureBootRunTask(project, resolveMainClassName);\n\t\tTaskProvider<ResolveMainClassName> resolveMainTestClassName = configureResolveMainTestClassNameTask(project);\n\t\tconfigureBootTestRunTask(project, resolveMainTestClassName);\n\t\tproject.afterEvaluate(this::configureUtf8Encoding);\n\t\tconfigureParametersCompilerArg(project);\n\t\tconfigureAdditionalMetadataLocations(project);\n\t\tconfigureSpringBootStarterTestToDependOnJUnitPlatformLauncher(project);\n\t}\n\n\tprivate void classifyJarTask(Project project) {\n\t\tproject.getTasks()\n\t\t\t.named(JavaPlugin.JAR_TASK_NAME, Jar.class)\n\t\t\t.configure((task) -> task.getArchiveClassifier().convention(\"plain\"));\n\t}\n\n\tprivate void configureBuildTask(Project project) {\n\t\tproject.getTasks()\n\t\t\t.named(BasePlugin.ASSEMBLE_TASK_NAME)\n\t\t\t.configure((task) -> task.dependsOn(this.singlePublishedArtifact));\n\t}\n\n\tprivate TaskProvider<ResolveMainClassName> configureResolveMainClassNameTask(Project project) {\n\t\treturn project.getTasks()\n\t\t\t.register(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class,\n\t\t\t\t\t(resolveMainClassName) -> {\n\t\t\t\t\t\tExtensionContainer extensions = project.getExtensions();\n\t\t\t\t\t\tresolveMainClassName.setDescription(\"Resolves the name of the application's main class.\");\n\t\t\t\t\t\tresolveMainClassName.setGroup(BasePlugin.BUILD_GROUP);\n\t\t\t\t\t\tCallable<FileCollection> classpath = () -> project.getExtensions()\n\t\t\t\t\t\t\t.getByType(SourceSetContainer.class)\n\t\t\t\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME)\n\t\t\t\t\t\t\t.getOutput();\n\t\t\t\t\t\tresolveMainClassName.setClasspath(classpath);\n\t\t\t\t\t\tresolveMainClassName.getConfiguredMainClassName().convention(project.provider(() -> {\n\t\t\t\t\t\t\tString javaApplicationMainClass = getJavaApplicationMainClass(extensions);\n\t\t\t\t\t\t\tif (javaApplicationMainClass != null) {\n\t\t\t\t\t\t\t\treturn javaApplicationMainClass;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tSpringBootExtension springBootExtension = project.getExtensions()\n\t\t\t\t\t\t\t\t.findByType(SpringBootExtension.class);\n\t\t\t\t\t\t\tAssert.state(springBootExtension != null, \"'springBootExtension' must not be null\");\n\t\t\t\t\t\t\treturn springBootExtension.getMainClass().getOrNull();\n\t\t\t\t\t\t}));\n\t\t\t\t\t\tresolveMainClassName.getOutputFile()\n\t\t\t\t\t\t\t.set(project.getLayout().getBuildDirectory().file(\"resolvedMainClassName\"));\n\t\t\t\t\t});\n\t}\n\n\tprivate TaskProvider<ResolveMainClassName> configureResolveMainTestClassNameTask(Project project) {\n\t\treturn project.getTasks()\n\t\t\t.register(SpringBootPlugin.RESOLVE_TEST_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class,\n\t\t\t\t\t(resolveMainClassName) -> {\n\t\t\t\t\t\tresolveMainClassName.setDescription(\"Resolves the name of the application's test main class.\");\n\t\t\t\t\t\tresolveMainClassName.setGroup(BasePlugin.BUILD_GROUP);\n\t\t\t\t\t\tCallable<FileCollection> classpath = () -> {\n\t\t\t\t\t\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);\n\t\t\t\t\t\t\treturn project.files(sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME).getOutput(),\n\t\t\t\t\t\t\t\t\tsourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput());\n\t\t\t\t\t\t};\n\t\t\t\t\t\tresolveMainClassName.setClasspath(classpath);\n\t\t\t\t\t\tresolveMainClassName.getOutputFile()\n\t\t\t\t\t\t\t.set(project.getLayout().getBuildDirectory().file(\"resolvedMainTestClassName\"));\n\t\t\t\t\t});\n\t}\n\n\tprivate static @Nullable String getJavaApplicationMainClass(ExtensionContainer extensions) {\n\t\tJavaApplication javaApplication = extensions.findByType(JavaApplication.class);\n\t\tif (javaApplication == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn javaApplication.getMainClass().getOrNull();\n\t}\n\n\tprivate TaskProvider<BootJar> configureBootJarTask(Project project,\n\t\t\tTaskProvider<ResolveMainClassName> resolveMainClassName) {\n\t\tSourceSet mainSourceSet = javaPluginExtension(project).getSourceSets()\n\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tConfiguration developmentOnly = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);\n\t\tConfiguration testAndDevelopmentOnly = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.TEST_AND_DEVELOPMENT_ONLY_CONFIGURATION_NAME);\n\t\tConfiguration productionRuntimeClasspath = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\t\tConfiguration runtimeClasspath = project.getConfigurations()\n\t\t\t.getByName(mainSourceSet.getRuntimeClasspathConfigurationName());\n\t\tCallable<FileCollection> classpath = () -> mainSourceSet.getRuntimeClasspath()\n\t\t\t.minus((developmentOnly.minus(productionRuntimeClasspath)))\n\t\t\t.minus((testAndDevelopmentOnly.minus(productionRuntimeClasspath)))\n\t\t\t.filter(new JarTypeFileSpec());\n\t\treturn project.getTasks().register(SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class, (bootJar) -> {\n\t\t\tbootJar.setDescription(\n\t\t\t\t\t\"Assembles an executable jar archive containing the main classes and their dependencies.\");\n\t\t\tbootJar.setGroup(BasePlugin.BUILD_GROUP);\n\t\t\tbootJar.classpath(classpath);\n\t\t\tProvider<String> manifestStartClass = project\n\t\t\t\t.provider(() -> (String) bootJar.getManifest().getAttributes().get(\"Start-Class\"));\n\t\t\tbootJar.getMainClass()\n\t\t\t\t.convention(resolveMainClassName.flatMap((resolver) -> manifestStartClass.isPresent()\n\t\t\t\t\t\t? manifestStartClass : resolver.readMainClassName()));\n\t\t\tbootJar.getTargetJavaVersion()\n\t\t\t\t.set(project.provider(() -> javaPluginExtension(project).getTargetCompatibility()));\n\t\t\tbootJar.resolvedArtifacts(runtimeClasspath.getIncoming().getArtifacts().getResolvedArtifacts());\n\t\t});\n\t}\n\n\tprivate void configureBootBuildImageTask(Project project, TaskProvider<BootJar> bootJar) {\n\t\tproject.getTasks().register(SpringBootPlugin.BOOT_BUILD_IMAGE_TASK_NAME, BootBuildImage.class, (buildImage) -> {\n\t\t\tbuildImage.setDescription(\"Builds an OCI image of the application using the output of the bootJar task\");\n\t\t\tbuildImage.setGroup(BasePlugin.BUILD_GROUP);\n\t\t\tbuildImage.getArchiveFile().set(bootJar.get().getArchiveFile());\n\t\t});\n\t}\n\n\tprivate void configureArtifactPublication(TaskProvider<BootJar> bootJar) {\n\t\tthis.singlePublishedArtifact.addJarCandidate(bootJar);\n\t}\n\n\tprivate void configureBootRunTask(Project project, TaskProvider<ResolveMainClassName> resolveMainClassName) {\n\t\tCallable<FileCollection> classpath = () -> {\n\t\t\tSourceSet mainSourceSet = javaPluginExtension(project).getSourceSets()\n\t\t\t\t.findByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\tAssert.state(mainSourceSet != null, \"'mainSourceSet' must not be null\");\n\t\t\treturn mainSourceSet.getRuntimeClasspath().filter(new JarTypeFileSpec());\n\t\t};\n\t\tproject.getTasks().register(SpringBootPlugin.BOOT_RUN_TASK_NAME, BootRun.class, (run) -> {\n\t\t\trun.setDescription(\"Runs this project as a Spring Boot application.\");\n\t\t\trun.setGroup(ApplicationPlugin.APPLICATION_GROUP);\n\t\t\trun.classpath(classpath);\n\t\t\trun.getMainClass().convention(resolveMainClassName.flatMap(ResolveMainClassName::readMainClassName));\n\t\t\tconfigureToolchainConvention(project, run);\n\t\t});\n\t}\n\n\tprivate void configureBootTestRunTask(Project project, TaskProvider<ResolveMainClassName> resolveMainClassName) {\n\t\tCallable<FileCollection> classpath = () -> {\n\t\t\tSourceSet testSourceSet = javaPluginExtension(project).getSourceSets()\n\t\t\t\t.findByName(SourceSet.TEST_SOURCE_SET_NAME);\n\t\t\tAssert.state(testSourceSet != null, \"'testSourceSet' must not be null\");\n\t\t\treturn testSourceSet.getRuntimeClasspath().filter(new JarTypeFileSpec());\n\t\t};\n\t\tproject.getTasks().register(\"bootTestRun\", BootRun.class, (run) -> {\n\t\t\trun.setDescription(\"Runs this project as a Spring Boot application using the test runtime classpath.\");\n\t\t\trun.setGroup(ApplicationPlugin.APPLICATION_GROUP);\n\t\t\trun.classpath(classpath);\n\t\t\trun.getMainClass().convention(resolveMainClassName.flatMap(ResolveMainClassName::readMainClassName));\n\t\t\tconfigureToolchainConvention(project, run);\n\t\t});\n\t}\n\n\tprivate void configureToolchainConvention(Project project, BootRun run) {\n\t\tJavaToolchainSpec toolchain = project.getExtensions().getByType(JavaPluginExtension.class).getToolchain();\n\t\tJavaToolchainService toolchainService = project.getExtensions().getByType(JavaToolchainService.class);\n\t\trun.getJavaLauncher().convention(toolchainService.launcherFor(toolchain));\n\t}\n\n\tprivate JavaPluginExtension javaPluginExtension(Project project) {\n\t\treturn project.getExtensions().getByType(JavaPluginExtension.class);\n\t}\n\n\tprivate void configureUtf8Encoding(Project evaluatedProject) {\n\t\tevaluatedProject.getTasks().withType(JavaCompile.class).configureEach(this::configureUtf8Encoding);\n\t}\n\n\tprivate void configureUtf8Encoding(JavaCompile compile) {\n\t\tif (compile.getOptions().getEncoding() == null) {\n\t\t\tcompile.getOptions().setEncoding(\"UTF-8\");\n\t\t}\n\t}\n\n\tprivate void configureParametersCompilerArg(Project project) {\n\t\tproject.getTasks().withType(JavaCompile.class).configureEach((compile) -> {\n\t\t\tList<String> compilerArgs = compile.getOptions().getCompilerArgs();\n\t\t\tif (!compilerArgs.contains(PARAMETERS_COMPILER_ARG)) {\n\t\t\t\tcompilerArgs.add(PARAMETERS_COMPILER_ARG);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void configureAdditionalMetadataLocations(Project project) {\n\t\tproject.afterEvaluate((evaluated) -> evaluated.getTasks()\n\t\t\t.withType(JavaCompile.class)\n\t\t\t.configureEach(this::configureAdditionalMetadataLocations));\n\t}\n\n\tprivate void configureAdditionalMetadataLocations(JavaCompile compile) {\n\t\tSourceSetContainer sourceSets = compile.getProject()\n\t\t\t.getExtensions()\n\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t.getSourceSets();\n\t\tsourceSets.stream()\n\t\t\t.filter((candidate) -> candidate.getCompileJavaTaskName().equals(compile.getName()))\n\t\t\t.map((match) -> match.getResources().getSrcDirs())\n\t\t\t.findFirst()\n\t\t\t.ifPresent((locations) -> compile.doFirst(new AdditionalMetadataLocationsConfigurer(locations)));\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void configureProductionRuntimeClasspathConfiguration(Project project) {\n\t\tConfiguration productionRuntimeClasspath = project.getConfigurations()\n\t\t\t.create(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\t\tConfiguration runtimeClasspath = project.getConfigurations()\n\t\t\t.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\t\tproductionRuntimeClasspath.attributes((attributes) -> {\n\t\t\tProviderFactory providers = project.getProviders();\n\t\t\tAttributeContainer sourceAttributes = runtimeClasspath.getAttributes();\n\t\t\tfor (Attribute attribute : sourceAttributes.keySet()) {\n\t\t\t\tattributes.attributeProvider(attribute,\n\t\t\t\t\t\tproviders.provider(() -> sourceAttributes.getAttribute(attribute)));\n\t\t\t}\n\t\t});\n\t\tproductionRuntimeClasspath.setExtendsFrom(runtimeClasspath.getExtendsFrom());\n\t\tproductionRuntimeClasspath.setCanBeResolved(runtimeClasspath.isCanBeResolved());\n\t\tproductionRuntimeClasspath.setCanBeConsumed(runtimeClasspath.isCanBeConsumed());\n\t\tproductionRuntimeClasspath.shouldResolveConsistentlyWith(runtimeClasspath);\n\t}\n\n\tprivate void configureDevelopmentOnlyConfiguration(Project project) {\n\t\tConfiguration developmentOnly = project.getConfigurations()\n\t\t\t.create(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);\n\t\tdevelopmentOnly\n\t\t\t.setDescription(\"Configuration for development-only dependencies such as Spring Boot's DevTools.\");\n\t\tConfiguration runtimeClasspath = project.getConfigurations()\n\t\t\t.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\n\t\truntimeClasspath.extendsFrom(developmentOnly);\n\t}\n\n\tprivate void configureTestAndDevelopmentOnlyConfiguration(Project project) {\n\t\tConfiguration testAndDevelopmentOnly = project.getConfigurations()\n\t\t\t.create(SpringBootPlugin.TEST_AND_DEVELOPMENT_ONLY_CONFIGURATION_NAME);\n\t\ttestAndDevelopmentOnly\n\t\t\t.setDescription(\"Configuration for test and development-only dependencies such as Spring Boot's DevTools.\");\n\t\tConfiguration runtimeClasspath = project.getConfigurations()\n\t\t\t.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\t\truntimeClasspath.extendsFrom(testAndDevelopmentOnly);\n\t\tConfiguration testImplementation = project.getConfigurations()\n\t\t\t.getByName(JavaPlugin.TEST_IMPLEMENTATION_CONFIGURATION_NAME);\n\t\ttestImplementation.extendsFrom(testAndDevelopmentOnly);\n\t}\n\n\tprivate void configureSpringBootStarterTestToDependOnJUnitPlatformLauncher(Project project) {\n\t\tproject.getDependencies()\n\t\t\t.components((components) -> components.withModule(\"org.springframework.boot:spring-boot-starter-test\",\n\t\t\t\t\t(metadata) -> metadata.withVariant(\"runtimeElements\", (variant) -> variant.withDependencies(\n\t\t\t\t\t\t\t(dependencies) -> dependencies.add(\"org.junit.platform:junit-platform-launcher\")\n\n\t\t\t\t\t))));\n\t}\n\n\t/**\n\t * Task {@link Action} to add additional meta-data locations. We need to use an\n\t * inner-class rather than a lambda due to\n\t * https://github.com/gradle/gradle/issues/5510.\n\t */\n\tprivate static final class AdditionalMetadataLocationsConfigurer implements Action<Task> {\n\n\t\tprivate final Set<File> locations;\n\n\t\tprivate AdditionalMetadataLocationsConfigurer(Set<File> locations) {\n\t\t\tthis.locations = locations;\n\t\t}\n\n\t\t@Override\n\t\tpublic void execute(Task task) {\n\t\t\tif (!(task instanceof JavaCompile compile)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (hasConfigurationProcessorOnClasspath(compile)) {\n\t\t\t\tconfigureAdditionalMetadataLocations(compile);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean hasConfigurationProcessorOnClasspath(JavaCompile compile) {\n\t\t\tSet<File> files = (compile.getOptions().getAnnotationProcessorPath() != null)\n\t\t\t\t\t? compile.getOptions().getAnnotationProcessorPath().getFiles() : compile.getClasspath().getFiles();\n\t\t\treturn files.stream()\n\t\t\t\t.map(File::getName)\n\t\t\t\t.anyMatch((name) -> name.startsWith(\"spring-boot-configuration-processor\"));\n\t\t}\n\n\t\tprivate void configureAdditionalMetadataLocations(JavaCompile compile) {\n\t\t\tcompile.getOptions()\n\t\t\t\t.getCompilerArgs()\n\t\t\t\t.add(\"-Aorg.springframework.boot.configurationprocessor.additionalMetadataLocations=\"\n\t\t\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(this.locations));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/KotlinPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.plugins.ExtraPropertiesExtension;\nimport org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper;\nimport org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapperKt;\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile;\n\n/**\n * {@link PluginApplicationAction} that reacts to Kotlin's Gradle plugin being applied by\n * configuring a {@code kotlin.version} property to align the version used for dependency\n * management for Kotlin with the version of its plugin.\n *\n * @author Andy Wilkinson\n */\nclass KotlinPluginAction implements PluginApplicationAction {\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tconfigureKotlinVersionProperty(project);\n\t\tenableJavaParametersOption(project);\n\t\trepairDamageToAotCompileConfigurations(project);\n\t}\n\n\tprivate void configureKotlinVersionProperty(Project project) {\n\t\tExtraPropertiesExtension extraProperties = project.getExtensions().getExtraProperties();\n\t\tif (!extraProperties.has(\"kotlin.version\")) {\n\t\t\tString kotlinVersion = getKotlinVersion(project);\n\t\t\textraProperties.set(\"kotlin.version\", kotlinVersion);\n\t\t}\n\t}\n\n\tprivate String getKotlinVersion(Project project) {\n\t\treturn KotlinPluginWrapperKt.getKotlinPluginVersion(project);\n\t}\n\n\tprivate void enableJavaParametersOption(Project project) {\n\t\tproject.getTasks()\n\t\t\t.withType(KotlinCompile.class)\n\t\t\t.configureEach((compile) -> compile.getCompilerOptions().getJavaParameters().set(true));\n\t}\n\n\tprivate void repairDamageToAotCompileConfigurations(Project project) {\n\t\tSpringBootAotPlugin aotPlugin = project.getPlugins().findPlugin(SpringBootAotPlugin.class);\n\t\tif (aotPlugin != null) {\n\t\t\taotPlugin.repairKotlinPluginDamage(project);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Class<? extends Plugin<? extends Project>> getPluginClass() {\n\t\treturn KotlinPluginWrapper.class;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/NativeImagePluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.graalvm.buildtools.gradle.NativeImagePlugin;\nimport org.graalvm.buildtools.gradle.dsl.GraalVMExtension;\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.java.archives.Manifest;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.tasks.SourceSetContainer;\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar;\n\n/**\n * {@link Action} that is executed in response to the {@link NativeImagePlugin} being\n * applied.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass NativeImagePluginAction implements PluginApplicationAction {\n\n\t@Override\n\tpublic Class<? extends Plugin<? extends Project>> getPluginClass() {\n\t\treturn NativeImagePlugin.class;\n\t}\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tproject.getPlugins().apply(SpringBootAotPlugin.class);\n\t\tproject.getPlugins().withType(JavaPlugin.class).all((plugin) -> {\n\t\t\tJavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\t\tSourceSetContainer sourceSets = javaPluginExtension.getSourceSets();\n\t\t\tGraalVMExtension graalVmExtension = configureGraalVmExtension(project);\n\t\t\tconfigureMainNativeBinaryClasspath(project, sourceSets, graalVmExtension);\n\t\t\tconfigureTestNativeBinaryClasspath(sourceSets, graalVmExtension);\n\t\t\tcopyReachabilityMetadataToBootJar(project);\n\t\t\tconfigureJarManifestNativeAttribute(project);\n\t\t});\n\t}\n\n\tprivate void configureMainNativeBinaryClasspath(Project project, SourceSetContainer sourceSets,\n\t\t\tGraalVMExtension graalVmExtension) {\n\t\tFileCollection runtimeClasspath = sourceSets.getByName(SpringBootAotPlugin.AOT_SOURCE_SET_NAME)\n\t\t\t.getRuntimeClasspath();\n\t\tgraalVmExtension.getBinaries().getByName(NativeImagePlugin.NATIVE_MAIN_EXTENSION).classpath(runtimeClasspath);\n\t\tConfiguration nativeImageClasspath = project.getConfigurations().getByName(\"nativeImageClasspath\");\n\t\tnativeImageClasspath.setExtendsFrom(removeDevelopmentOnly(nativeImageClasspath.getExtendsFrom()));\n\t}\n\n\tprivate Iterable<Configuration> removeDevelopmentOnly(Set<Configuration> configurations) {\n\t\treturn configurations.stream()\n\t\t\t.filter(this::isNotDevelopmentOnly)\n\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t}\n\n\tprivate boolean isNotDevelopmentOnly(Configuration configuration) {\n\t\treturn !SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME.equals(configuration.getName())\n\t\t\t\t&& !SpringBootPlugin.TEST_AND_DEVELOPMENT_ONLY_CONFIGURATION_NAME.equals(configuration.getName());\n\t}\n\n\tprivate void configureTestNativeBinaryClasspath(SourceSetContainer sourceSets, GraalVMExtension graalVmExtension) {\n\t\tFileCollection runtimeClasspath = sourceSets.getByName(SpringBootAotPlugin.AOT_TEST_SOURCE_SET_NAME)\n\t\t\t.getRuntimeClasspath();\n\t\tgraalVmExtension.getBinaries().getByName(NativeImagePlugin.NATIVE_TEST_EXTENSION).classpath(runtimeClasspath);\n\t}\n\n\tprivate GraalVMExtension configureGraalVmExtension(Project project) {\n\t\tGraalVMExtension extension = project.getExtensions().getByType(GraalVMExtension.class);\n\t\textension.getToolchainDetection().set(false);\n\t\treturn extension;\n\t}\n\n\tprivate void copyReachabilityMetadataToBootJar(Project project) {\n\t\tproject.getTasks()\n\t\t\t.named(SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class)\n\t\t\t.configure((bootJar) -> bootJar.from(project.getTasks().named(\"collectReachabilityMetadata\")));\n\t}\n\n\tprivate void configureJarManifestNativeAttribute(Project project) {\n\t\tproject.getTasks()\n\t\t\t.named(SpringBootPlugin.BOOT_JAR_TASK_NAME, BootJar.class)\n\t\t\t.configure(this::addNativeProcessedAttribute);\n\t}\n\n\tprivate void addNativeProcessedAttribute(BootJar bootJar) {\n\t\tbootJar.manifest(this::addNativeProcessedAttribute);\n\t}\n\n\tprivate void addNativeProcessedAttribute(Manifest manifest) {\n\t\tmanifest.getAttributes().put(\"Spring-Boot-Native-Processed\", true);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/PluginApplicationAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\n\n/**\n * An {@link Action} to be executed on a {@link Project} in response to a particular type\n * of {@link Plugin} being applied.\n *\n * @author Andy Wilkinson\n */\ninterface PluginApplicationAction extends Action<Project> {\n\n\t/**\n\t * The class of the {@code Plugin} that, when applied, will trigger the execution of\n\t * this action.\n\t * @return the plugin class\n\t * @throws ClassNotFoundException if the plugin class cannot be found\n\t * @throws NoClassDefFoundError if an error occurs when defining the plugin class\n\t */\n\tClass<? extends Plugin<? extends Project>> getPluginClass() throws ClassNotFoundException, NoClassDefFoundError;\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ProtobufPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport com.google.protobuf.gradle.ExecutableLocator;\nimport com.google.protobuf.gradle.GenerateProtoTask;\nimport com.google.protobuf.gradle.GenerateProtoTask.PluginOptions;\nimport com.google.protobuf.gradle.ProtobufExtension;\nimport com.google.protobuf.gradle.ProtobufExtension.GenerateProtoTaskCollection;\nimport com.google.protobuf.gradle.ProtobufPlugin;\nimport org.gradle.api.Action;\nimport org.gradle.api.NamedDomainObjectContainer;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.DependencyResolveDetails;\nimport org.gradle.api.artifacts.ModuleVersionSelector;\nimport org.gradle.api.artifacts.component.ModuleComponentIdentifier;\nimport org.gradle.api.artifacts.result.DependencyResult;\nimport org.gradle.api.artifacts.result.ResolvedComponentResult;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link Action} that is executed in response to the {@link ProtobufPlugin} being\n * applied.\n *\n * @author Andy Wilkinson\n */\nfinal class ProtobufPluginAction implements PluginApplicationAction {\n\n\tprivate static final Dependency protocDependency = new Dependency(\"com.google.protobuf\", \"protoc\");\n\n\tprivate static final Dependency grpcDependency = new Dependency(\"io.grpc\", \"protoc-gen-grpc-java\");\n\n\tprivate static final List<VersionAlignment> versionAlignment = List.of(\n\t\t\tprotocDependency.alignVersionWith(\"com.google.protobuf\", \"protobuf-java-util\"),\n\t\t\tgrpcDependency.alignVersionWith(\"io.grpc\", \"grpc-util\"));\n\n\t@Override\n\tpublic Class<? extends Plugin<? extends Project>> getPluginClass() {\n\t\treturn ProtobufPlugin.class;\n\t}\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tProtobufExtension protobuf = project.getExtensions().getByType(ProtobufExtension.class);\n\t\tprotobuf.protoc(this::configureProtoc);\n\t\tprotobuf.plugins(this::configurePlugins);\n\t\tprotobuf.generateProtoTasks(this::configureGenerateProtoTasks);\n\t\tproject.getConfigurations()\n\t\t\t.named(this::isProtobufToolsLocator)\n\t\t\t.configureEach((configuration) -> configureProtobufToolsLocator(project, configuration));\n\t}\n\n\tprivate void configureProtoc(ExecutableLocator protoc) {\n\t\tprotoc.setArtifact(protocDependency.asDependencySpec());\n\t}\n\n\tprivate ExecutableLocator configurePlugins(NamedDomainObjectContainer<ExecutableLocator> plugins) {\n\t\treturn plugins.create(\"grpc\", (grpc) -> grpc.setArtifact(grpcDependency.asDependencySpec()));\n\t}\n\n\tprivate void configureGenerateProtoTasks(GenerateProtoTaskCollection tasks) {\n\t\ttasks.all().configureEach(this::configureGenerateProtoTask);\n\t}\n\n\tprivate void configureGenerateProtoTask(GenerateProtoTask task) {\n\t\ttask.plugins((plugins) -> plugins.create(\"grpc\", this::configureGrpcOptions));\n\t}\n\n\tprivate void configureGrpcOptions(PluginOptions grpc) {\n\t\tgrpc.option(\"@generated=omit\");\n\t}\n\n\tprivate boolean isProtobufToolsLocator(String name) {\n\t\treturn name.startsWith(\"protobufToolsLocator_\");\n\t}\n\n\tprivate void configureProtobufToolsLocator(Project project, Configuration configuration) {\n\t\tconfiguration.getResolutionStrategy().eachDependency((details) -> {\n\t\t\tVersionAlignment versionAlignment = versionAlignmentFor(details);\n\t\t\tif (versionAlignment != null) {\n\t\t\t\tversionAlignment.applyIfPossible(project, details);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate @Nullable VersionAlignment versionAlignmentFor(DependencyResolveDetails details) {\n\t\tif (\"null\".equals(details.getRequested().getVersion())) {\n\t\t\tfor (VersionAlignment alignment : versionAlignment) {\n\t\t\t\tif (alignment.accepts(details)) {\n\t\t\t\t\treturn alignment;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate record Dependency(String group, String module) {\n\n\t\tprivate VersionAlignment alignVersionWith(String group, String module) {\n\t\t\treturn new VersionAlignment(this, new Dependency(group, module));\n\t\t}\n\n\t\tprivate String asDependencySpec() {\n\t\t\treturn this.group + \":\" + this.module;\n\t\t}\n\n\t}\n\n\tprivate record VersionAlignment(Dependency target, Dependency source) {\n\n\t\tvoid applyIfPossible(Project project, DependencyResolveDetails details) {\n\t\t\tversionFromRuntimeClasspath(project, source()).ifPresent(details::useVersion);\n\t\t}\n\n\t\tboolean accepts(DependencyResolveDetails details) {\n\t\t\tModuleVersionSelector requested = details.getRequested();\n\t\t\treturn target().group().equals(requested.getGroup()) && target().module().equals(requested.getName());\n\t\t}\n\n\t\tprivate Optional<String> versionFromRuntimeClasspath(Project project, Dependency source) {\n\t\t\treturn project.getConfigurations()\n\t\t\t\t.getByName(\"runtimeClasspath\")\n\t\t\t\t.getIncoming()\n\t\t\t\t.getResolutionResult()\n\t\t\t\t.getAllDependencies()\n\t\t\t\t.stream()\n\t\t\t\t.map(DependencyResult::getFrom)\n\t\t\t\t.map(ResolvedComponentResult::getId)\n\t\t\t\t.filter(ModuleComponentIdentifier.class::isInstance)\n\t\t\t\t.map(ModuleComponentIdentifier.class::cast)\n\t\t\t\t.filter((id) -> id.getGroup().equals(source.group()) && id.getModule().equals(source.module()))\n\t\t\t\t.map(ModuleComponentIdentifier::getVersion)\n\t\t\t\t.findFirst();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ResolveMainClassName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.InvalidUserDataException;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.Transformer;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFile;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.work.DisableCachingByDefault;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.MainClassFinder;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Task} for resolving the name of the application's main class.\n *\n * @author Andy Wilkinson\n * @since 2.4\n */\n@DisableCachingByDefault(because = \"Not worth caching\")\npublic class ResolveMainClassName extends DefaultTask {\n\n\tprivate static final String SPRING_BOOT_APPLICATION_CLASS_NAME = \"org.springframework.boot.autoconfigure.SpringBootApplication\";\n\n\tprivate final RegularFileProperty outputFile;\n\n\tprivate final Property<String> configuredMainClass;\n\n\tprivate @Nullable FileCollection classpath;\n\n\t/**\n\t * Creates a new instance of the {@code ResolveMainClassName} task.\n\t */\n\tpublic ResolveMainClassName() {\n\t\tthis.outputFile = getProject().getObjects().fileProperty();\n\t\tthis.configuredMainClass = getProject().getObjects().property(String.class);\n\t}\n\n\t/**\n\t * Returns the classpath that the task will examine when resolving the main class\n\t * name.\n\t * @return the classpath\n\t */\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\tAssert.state(this.classpath != null, \"'classpath' must not be null\");\n\t\treturn this.classpath;\n\t}\n\n\t/**\n\t * Sets the classpath that the task will examine when resolving the main class name.\n\t * @param classpath the classpath\n\t */\n\tpublic void setClasspath(FileCollection classpath) {\n\t\tsetClasspath((Object) classpath);\n\t}\n\n\t/**\n\t * Sets the classpath that the task will examine when resolving the main class name.\n\t * The given {@code classpath} is evaluated as per {@link Project#files(Object...)}.\n\t * @param classpath the classpath\n\t * @since 2.5.10\n\t */\n\tpublic void setClasspath(Object classpath) {\n\t\tthis.classpath = getProject().files(classpath);\n\t}\n\n\t/**\n\t * Returns the property for the task's output file that will contain the name of the\n\t * main class.\n\t * @return the output file\n\t */\n\t@OutputFile\n\tpublic RegularFileProperty getOutputFile() {\n\t\treturn this.outputFile;\n\t}\n\n\t/**\n\t * Returns the property for the explicitly configured main class name that should be\n\t * used in favor of resolving the main class name from the classpath.\n\t * @return the configured main class name property\n\t */\n\t@Input\n\t@Optional\n\tpublic Property<String> getConfiguredMainClassName() {\n\t\treturn this.configuredMainClass;\n\t}\n\n\t@TaskAction\n\tvoid resolveAndStoreMainClassName() throws IOException {\n\t\tFile outputFile = this.outputFile.getAsFile().get();\n\t\toutputFile.getParentFile().mkdirs();\n\t\tString mainClassName = resolveMainClassName();\n\t\tFiles.writeString(outputFile.toPath(), mainClassName, StandardOpenOption.WRITE, StandardOpenOption.CREATE,\n\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t}\n\n\tprivate String resolveMainClassName() {\n\t\tString configuredMainClass = this.configuredMainClass.getOrNull();\n\t\tif (configuredMainClass != null) {\n\t\t\treturn configuredMainClass;\n\t\t}\n\t\treturn getClasspath().filter(File::isDirectory)\n\t\t\t.getFiles()\n\t\t\t.stream()\n\t\t\t.map(this::findMainClass)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(\"\");\n\t}\n\n\tprivate @Nullable String findMainClass(File file) {\n\t\ttry {\n\t\t\treturn MainClassFinder.findSingleMainClass(file, SPRING_BOOT_APPLICATION_CLASS_NAME);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tProvider<String> readMainClassName() {\n\t\tString classpath = getClasspath().filter(File::isDirectory)\n\t\t\t.getFiles()\n\t\t\t.stream()\n\t\t\t.map(File::getAbsolutePath)\n\t\t\t.collect(Collectors.joining(File.pathSeparator));\n\t\treturn this.outputFile.map(new ClassNameReader(classpath));\n\t}\n\n\tprivate static final class ClassNameReader implements Transformer<String, RegularFile> {\n\n\t\tprivate final String classpath;\n\n\t\tprivate ClassNameReader(String classpath) {\n\t\t\tthis.classpath = classpath;\n\t\t}\n\n\t\t@Override\n\t\tpublic String transform(RegularFile file) {\n\t\t\tif (file.getAsFile().length() == 0) {\n\t\t\t\tthrow new InvalidUserDataException(\n\t\t\t\t\t\t\"Main class name has not been configured and it could not be resolved from classpath \"\n\t\t\t\t\t\t\t\t+ this.classpath);\n\t\t\t}\n\t\t\tPath output = file.getAsFile().toPath();\n\t\t\ttry {\n\t\t\t\treturn Files.readString(output);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(\"Failed to read main class name from '\" + output + \"'\");\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SinglePublishedArtifact.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.gradle.api.Buildable;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.PublishArtifact;\nimport org.gradle.api.artifacts.PublishArtifactSet;\nimport org.gradle.api.artifacts.dsl.ArtifactHandler;\nimport org.gradle.api.tasks.TaskDependency;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar;\nimport org.springframework.boot.gradle.tasks.bundling.BootWar;\n\n/**\n * A wrapper for a {@link PublishArtifactSet} that ensures that only a single artifact is\n * published, with a war file taking precedence over a jar file.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nfinal class SinglePublishedArtifact implements Buildable {\n\n\tprivate final Configuration configuration;\n\n\tprivate final ArtifactHandler handler;\n\n\tprivate @Nullable PublishArtifact currentArtifact;\n\n\tSinglePublishedArtifact(Configuration configuration, ArtifactHandler handler) {\n\t\tthis.configuration = configuration;\n\t\tthis.handler = handler;\n\t}\n\n\tvoid addWarCandidate(TaskProvider<BootWar> candidate) {\n\t\tadd(candidate);\n\t}\n\n\tvoid addJarCandidate(TaskProvider<BootJar> candidate) {\n\t\tif (this.currentArtifact == null) {\n\t\t\tadd(candidate);\n\t\t}\n\t}\n\n\tprivate void add(TaskProvider<? extends Jar> artifact) {\n\t\tthis.configuration.getArtifacts().remove(this.currentArtifact);\n\t\tthis.currentArtifact = this.handler.add(this.configuration.getName(), artifact);\n\t}\n\n\t@Override\n\tpublic TaskDependency getBuildDependencies() {\n\t\treturn this.configuration.getArtifacts().getBuildDependencies();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootAotPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.artifacts.DependencySet;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.attributes.Attribute;\nimport org.gradle.api.attributes.AttributeContainer;\nimport org.gradle.api.attributes.LibraryElements;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.file.ConfigurableFileCollection;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.plugins.PluginContainer;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.provider.ProviderFactory;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.jvm.toolchain.JavaToolchainService;\nimport org.gradle.jvm.toolchain.JavaToolchainSpec;\n\nimport org.springframework.boot.gradle.tasks.aot.AbstractAot;\nimport org.springframework.boot.gradle.tasks.aot.ProcessAot;\nimport org.springframework.boot.gradle.tasks.aot.ProcessTestAot;\n\n/**\n * Gradle plugin for Spring Boot AOT.\n *\n * @author Andy Wilkinson\n * @since 3.0.0\n */\npublic class SpringBootAotPlugin implements Plugin<Project> {\n\n\t/**\n\t * Name of the main {@code aot} {@link SourceSet source set}.\n\t */\n\tpublic static final String AOT_SOURCE_SET_NAME = \"aot\";\n\n\t/**\n\t * Name of the {@code aotTest} {@link SourceSet source set}.\n\t */\n\tpublic static final String AOT_TEST_SOURCE_SET_NAME = \"aotTest\";\n\n\t/**\n\t * Name of the default {@link ProcessAot} task.\n\t */\n\tpublic static final String PROCESS_AOT_TASK_NAME = \"processAot\";\n\n\t/**\n\t * Name of the default {@link ProcessAot} task.\n\t */\n\tpublic static final String PROCESS_TEST_AOT_TASK_NAME = \"processTestAot\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tPluginContainer plugins = project.getPlugins();\n\t\tplugins.withType(JavaPlugin.class).all((javaPlugin) -> {\n\t\t\tJavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\t\tSourceSetContainer sourceSets = javaPluginExtension.getSourceSets();\n\t\t\tSourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\tSourceSet aotSourceSet = configureSourceSet(project, AOT_SOURCE_SET_NAME, mainSourceSet);\n\t\t\tSourceSet testSourceSet = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME);\n\t\t\tSourceSet aotTestSourceSet = configureSourceSet(project, AOT_TEST_SOURCE_SET_NAME, testSourceSet);\n\t\t\tplugins.withType(SpringBootPlugin.class).all((bootPlugin) -> {\n\t\t\t\tregisterProcessAotTask(project, aotSourceSet, mainSourceSet);\n\t\t\t\tregisterProcessTestAotTask(project, mainSourceSet, aotTestSourceSet, testSourceSet);\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate SourceSet configureSourceSet(Project project, String newSourceSetName, SourceSet existingSourceSet) {\n\t\tJavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\tSourceSetContainer sourceSets = javaPluginExtension.getSourceSets();\n\t\treturn sourceSets.create(newSourceSetName, (sourceSet) -> {\n\t\t\texistingSourceSet.setRuntimeClasspath(existingSourceSet.getRuntimeClasspath().plus(sourceSet.getOutput()));\n\t\t\tproject.getConfigurations()\n\t\t\t\t.getByName(sourceSet.getCompileClasspathConfigurationName())\n\t\t\t\t.attributes((attributes) -> {\n\t\t\t\t\tconfigureClassesAndResourcesLibraryElementsAttribute(project, attributes);\n\t\t\t\t\tconfigureJavaRuntimeUsageAttribute(project, attributes);\n\t\t\t\t});\n\t\t});\n\t}\n\n\tprivate void configureClassesAndResourcesLibraryElementsAttribute(Project project, AttributeContainer attributes) {\n\t\tLibraryElements classesAndResources = project.getObjects()\n\t\t\t.named(LibraryElements.class, LibraryElements.CLASSES_AND_RESOURCES);\n\t\tattributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, classesAndResources);\n\t}\n\n\tprivate void configureJavaRuntimeUsageAttribute(Project project, AttributeContainer attributes) {\n\t\tUsage javaRuntime = project.getObjects().named(Usage.class, Usage.JAVA_RUNTIME);\n\t\tattributes.attribute(Usage.USAGE_ATTRIBUTE, javaRuntime);\n\t}\n\n\tprivate void registerProcessAotTask(Project project, SourceSet aotSourceSet, SourceSet mainSourceSet) {\n\t\tTaskProvider<ResolveMainClassName> resolveMainClassName = project.getTasks()\n\t\t\t.named(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class);\n\t\tConfiguration aotClasspath = createAotProcessingClasspath(project, PROCESS_AOT_TASK_NAME, mainSourceSet,\n\t\t\t\tSet.of(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME,\n\t\t\t\t\t\tSpringBootPlugin.TEST_AND_DEVELOPMENT_ONLY_CONFIGURATION_NAME));\n\t\tproject.getDependencies().add(aotClasspath.getName(), project.files(mainSourceSet.getOutput()));\n\t\tConfiguration compileClasspath = project.getConfigurations()\n\t\t\t.getByName(aotSourceSet.getCompileClasspathConfigurationName());\n\t\tcompileClasspath.extendsFrom(aotClasspath);\n\t\tProvider<Directory> resourcesOutput = project.getLayout()\n\t\t\t.getBuildDirectory()\n\t\t\t.dir(\"generated/\" + aotSourceSet.getName() + \"Resources\");\n\t\tTaskProvider<ProcessAot> processAot = project.getTasks()\n\t\t\t.register(PROCESS_AOT_TASK_NAME, ProcessAot.class, (task) -> {\n\t\t\t\tconfigureAotTask(project, aotSourceSet, task, resourcesOutput);\n\t\t\t\ttask.getApplicationMainClass()\n\t\t\t\t\t.set(resolveMainClassName.flatMap(ResolveMainClassName::readMainClassName));\n\t\t\t\ttask.setClasspath(aotClasspath);\n\t\t\t});\n\t\taotSourceSet.getJava().srcDir(processAot.map(ProcessAot::getSourcesOutput));\n\t\taotSourceSet.getResources().srcDir(resourcesOutput);\n\t\tConfigurableFileCollection classesOutputFiles = project.files(processAot.map(ProcessAot::getClassesOutput));\n\t\tmainSourceSet.setRuntimeClasspath(mainSourceSet.getRuntimeClasspath().plus(classesOutputFiles));\n\t\tproject.getDependencies().add(aotSourceSet.getImplementationConfigurationName(), classesOutputFiles);\n\t\tconfigureDependsOn(project, aotSourceSet, processAot);\n\t}\n\n\tprivate void configureAotTask(Project project, SourceSet sourceSet, AbstractAot task,\n\t\t\tProvider<Directory> resourcesOutput) {\n\t\ttask.getSourcesOutput()\n\t\t\t.set(project.getLayout().getBuildDirectory().dir(\"generated/\" + sourceSet.getName() + \"Sources\"));\n\t\ttask.getResourcesOutput().set(resourcesOutput);\n\t\ttask.getClassesOutput()\n\t\t\t.set(project.getLayout().getBuildDirectory().dir(\"generated/\" + sourceSet.getName() + \"Classes\"));\n\t\ttask.getGroupId().set(project.provider(() -> String.valueOf(project.getGroup())));\n\t\ttask.getArtifactId().set(project.provider(project::getName));\n\t\tconfigureToolchainConvention(project, task);\n\t}\n\n\tprivate void configureToolchainConvention(Project project, AbstractAot aotTask) {\n\t\tJavaToolchainSpec toolchain = project.getExtensions().getByType(JavaPluginExtension.class).getToolchain();\n\t\tJavaToolchainService toolchainService = project.getExtensions().getByType(JavaToolchainService.class);\n\t\taotTask.getJavaLauncher().convention(toolchainService.launcherFor(toolchain));\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate Configuration createAotProcessingClasspath(Project project, String taskName, SourceSet inputSourceSet,\n\t\t\tSet<String> developmentOnlyConfigurationNames) {\n\t\tConfiguration base = project.getConfigurations()\n\t\t\t.getByName(inputSourceSet.getRuntimeClasspathConfigurationName());\n\t\treturn project.getConfigurations().create(taskName + \"Classpath\", (classpath) -> {\n\t\t\tclasspath.setCanBeConsumed(false);\n\t\t\tif (!classpath.isCanBeResolved()) {\n\t\t\t\tthrow new IllegalStateException(\"Unexpected\");\n\t\t\t}\n\t\t\tclasspath.setCanBeResolved(true);\n\t\t\tclasspath.setDescription(\"Classpath of the \" + taskName + \" task.\");\n\t\t\tremoveDevelopmentOnly(base.getExtendsFrom(), developmentOnlyConfigurationNames)\n\t\t\t\t.forEach(classpath::extendsFrom);\n\t\t\tclasspath.attributes((attributes) -> {\n\t\t\t\tProviderFactory providers = project.getProviders();\n\t\t\t\tAttributeContainer baseAttributes = base.getAttributes();\n\t\t\t\tfor (Attribute attribute : baseAttributes.keySet()) {\n\t\t\t\t\tattributes.attributeProvider(attribute,\n\t\t\t\t\t\t\tproviders.provider(() -> baseAttributes.getAttribute(attribute)));\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate Stream<Configuration> removeDevelopmentOnly(Set<Configuration> configurations,\n\t\t\tSet<String> developmentOnlyConfigurationNames) {\n\t\treturn configurations.stream()\n\t\t\t.filter((configuration) -> !developmentOnlyConfigurationNames.contains(configuration.getName()));\n\t}\n\n\tprivate void configureDependsOn(Project project, SourceSet aotSourceSet,\n\t\t\tTaskProvider<? extends AbstractAot> processAot) {\n\t\tproject.getTasks()\n\t\t\t.named(aotSourceSet.getProcessResourcesTaskName())\n\t\t\t.configure((processResources) -> processResources.dependsOn(processAot));\n\t}\n\n\tprivate void registerProcessTestAotTask(Project project, SourceSet mainSourceSet, SourceSet aotTestSourceSet,\n\t\t\tSourceSet testSourceSet) {\n\t\tConfiguration aotClasspath = createAotProcessingClasspath(project, PROCESS_TEST_AOT_TASK_NAME, testSourceSet,\n\t\t\t\tSet.of(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME));\n\t\taddJUnitPlatformLauncherDependency(project, aotClasspath);\n\t\tConfiguration compileClasspath = project.getConfigurations()\n\t\t\t.getByName(aotTestSourceSet.getCompileClasspathConfigurationName());\n\t\tcompileClasspath.extendsFrom(aotClasspath);\n\t\tProvider<Directory> resourcesOutput = project.getLayout()\n\t\t\t.getBuildDirectory()\n\t\t\t.dir(\"generated/\" + aotTestSourceSet.getName() + \"Resources\");\n\t\tTaskProvider<ProcessTestAot> processTestAot = project.getTasks()\n\t\t\t.register(PROCESS_TEST_AOT_TASK_NAME, ProcessTestAot.class, (task) -> {\n\t\t\t\tconfigureAotTask(project, aotTestSourceSet, task, resourcesOutput);\n\t\t\t\ttask.setClasspath(aotClasspath);\n\t\t\t\ttask.setClasspathRoots(testSourceSet.getOutput());\n\t\t\t});\n\t\taotTestSourceSet.getJava().srcDir(processTestAot.map(ProcessTestAot::getSourcesOutput));\n\t\taotTestSourceSet.getResources().srcDir(resourcesOutput);\n\t\tproject.getDependencies().add(aotClasspath.getName(), project.files(mainSourceSet.getOutput()));\n\t\tproject.getDependencies().add(aotClasspath.getName(), project.files(testSourceSet.getOutput()));\n\t\tConfigurableFileCollection classesOutputFiles = project\n\t\t\t.files(processTestAot.map(ProcessTestAot::getClassesOutput));\n\t\ttestSourceSet.setRuntimeClasspath(testSourceSet.getRuntimeClasspath().plus(classesOutputFiles));\n\t\tproject.getDependencies().add(aotTestSourceSet.getImplementationConfigurationName(), classesOutputFiles);\n\t\tconfigureDependsOn(project, aotTestSourceSet, processTestAot);\n\t}\n\n\tprivate void addJUnitPlatformLauncherDependency(Project project, Configuration configuration) {\n\t\tDependencyHandler dependencyHandler = project.getDependencies();\n\t\tDependency springBootDependencies = dependencyHandler\n\t\t\t.create(dependencyHandler.platform(SpringBootPlugin.BOM_COORDINATES));\n\t\tDependencySet dependencies = configuration.getDependencies();\n\t\tdependencies.add(springBootDependencies);\n\t\tdependencies.add(dependencyHandler.create(\"org.junit.platform:junit-platform-launcher\"));\n\t}\n\n\tvoid repairKotlinPluginDamage(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class).configureEach((javaPlugin) -> {\n\t\t\trepairKotlinPluginDamage(project, SpringBootAotPlugin.AOT_SOURCE_SET_NAME);\n\t\t\trepairKotlinPluginDamage(project, SpringBootAotPlugin.AOT_TEST_SOURCE_SET_NAME);\n\t\t});\n\t}\n\n\tprivate void repairKotlinPluginDamage(Project project, String sourceSetName) {\n\t\tJavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\tSourceSetContainer sourceSets = javaPluginExtension.getSourceSets();\n\t\tConfiguration compileClasspath = project.getConfigurations()\n\t\t\t.getByName(sourceSets.getByName(sourceSetName).getCompileClasspathConfigurationName());\n\t\tconfigureJavaRuntimeUsageAttribute(project, compileClasspath.getAttributes());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.util.GradleVersion;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.gradle.dsl.SpringBootExtension;\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage;\nimport org.springframework.boot.gradle.tasks.bundling.BootJar;\nimport org.springframework.boot.gradle.tasks.bundling.BootWar;\nimport org.springframework.boot.gradle.util.VersionExtractor;\n\n/**\n * Gradle plugin for Spring Boot.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Danny Hyun\n * @author Scott Frederick\n * @since 1.2.7\n */\npublic class SpringBootPlugin implements Plugin<Project> {\n\n\tprivate static final @Nullable String SPRING_BOOT_VERSION = VersionExtractor\n\t\t.forClass(DependencyManagementPluginAction.class);\n\n\t/**\n\t * The name of the {@link Configuration} that contains Spring Boot archives.\n\t * @since 2.0.0\n\t */\n\tpublic static final String BOOT_ARCHIVES_CONFIGURATION_NAME = \"bootArchives\";\n\n\t/**\n\t * The name of the default {@link BootJar} task.\n\t * @since 2.0.0\n\t */\n\tpublic static final String BOOT_JAR_TASK_NAME = \"bootJar\";\n\n\t/**\n\t * The name of the default {@link BootWar} task.\n\t * @since 2.0.0\n\t */\n\tpublic static final String BOOT_WAR_TASK_NAME = \"bootWar\";\n\n\t/**\n\t * The name of the default {@link BootBuildImage} task.\n\t * @since 2.3.0\n\t */\n\tpublic static final String BOOT_BUILD_IMAGE_TASK_NAME = \"bootBuildImage\";\n\n\tstatic final String BOOT_RUN_TASK_NAME = \"bootRun\";\n\n\tstatic final String BOOT_TEST_RUN_TASK_NAME = \"bootTestRun\";\n\n\t/**\n\t * The name of the {@code developmentOnly} configuration.\n\t * @since 2.3.0\n\t */\n\tpublic static final String DEVELOPMENT_ONLY_CONFIGURATION_NAME = \"developmentOnly\";\n\n\t/**\n\t * The name of the {@code testAndDevelopmentOnly} configuration.\n\t * @since 3.2.0\n\t */\n\tpublic static final String TEST_AND_DEVELOPMENT_ONLY_CONFIGURATION_NAME = \"testAndDevelopmentOnly\";\n\n\t/**\n\t * The name of the {@code productionRuntimeClasspath} configuration.\n\t */\n\tpublic static final String PRODUCTION_RUNTIME_CLASSPATH_CONFIGURATION_NAME = \"productionRuntimeClasspath\";\n\n\t/**\n\t * The name of the {@link ResolveMainClassName} task used to resolve a main class from\n\t * the output of the {@code main} source set.\n\t * @since 3.0.0\n\t */\n\tpublic static final String RESOLVE_MAIN_CLASS_NAME_TASK_NAME = \"resolveMainClassName\";\n\n\t/**\n\t * The name of the {@link ResolveMainClassName} task used to resolve a main class from\n\t * the output of the {@code test} source set then, if needed, the output of the\n\t * {@code main} source set.\n\t * @since 3.1.0\n\t */\n\tpublic static final String RESOLVE_TEST_MAIN_CLASS_NAME_TASK_NAME = \"resolveTestMainClassName\";\n\n\t/**\n\t * The coordinates {@code (group:name:version)} of the\n\t * {@code spring-boot-dependencies} bom.\n\t */\n\tpublic static final String BOM_COORDINATES = \"org.springframework.boot:spring-boot-dependencies:\"\n\t\t\t+ SPRING_BOOT_VERSION;\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tverifyGradleVersion();\n\t\tcreateExtension(project);\n\t\tConfiguration bootArchives = createBootArchivesConfiguration(project);\n\t\tregisterPluginActions(project, bootArchives);\n\t}\n\n\tprivate void verifyGradleVersion() {\n\t\tGradleVersion currentVersion = GradleVersion.current();\n\t\tif (currentVersion.compareTo(GradleVersion.version(\"8.14\")) < 0) {\n\t\t\tthrow new GradleException(\"Spring Boot plugin requires Gradle 8.x (8.14 or later) or 9.x. \"\n\t\t\t\t\t+ \"The current version is \" + currentVersion);\n\t\t}\n\t}\n\n\tprivate void createExtension(Project project) {\n\t\tproject.getExtensions().create(\"springBoot\", SpringBootExtension.class, project);\n\t}\n\n\tprivate Configuration createBootArchivesConfiguration(Project project) {\n\t\tConfiguration bootArchives = project.getConfigurations().create(BOOT_ARCHIVES_CONFIGURATION_NAME);\n\t\tbootArchives.setDescription(\"Configuration for Spring Boot archive artifacts.\");\n\t\tbootArchives.setCanBeResolved(false);\n\t\treturn bootArchives;\n\t}\n\n\tprivate void registerPluginActions(Project project, Configuration bootArchives) {\n\t\tSinglePublishedArtifact singlePublishedArtifact = new SinglePublishedArtifact(bootArchives,\n\t\t\t\tproject.getArtifacts());\n\t\tList<PluginApplicationAction> actions = Arrays.asList(new JavaPluginAction(singlePublishedArtifact),\n\t\t\t\tnew WarPluginAction(singlePublishedArtifact), new DependencyManagementPluginAction(),\n\t\t\t\tnew ApplicationPluginAction(), new KotlinPluginAction(), new NativeImagePluginAction(),\n\t\t\t\tnew CyclonedxPluginAction(), new ProtobufPluginAction());\n\t\tfor (PluginApplicationAction action : actions) {\n\t\t\twithPluginClassOfAction(action,\n\t\t\t\t\t(pluginClass) -> project.getPlugins().withType(pluginClass, (plugin) -> action.execute(project)));\n\t\t}\n\t}\n\n\tprivate void withPluginClassOfAction(PluginApplicationAction action,\n\t\t\tConsumer<Class<? extends Plugin<? extends Project>>> consumer) {\n\t\tClass<? extends Plugin<? extends Project>> pluginClass;\n\t\ttry {\n\t\t\tpluginClass = action.getPluginClass();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Plugin class unavailable.\n\t\t\treturn;\n\t\t}\n\t\tconsumer.accept(pluginClass);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.util.concurrent.Callable;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.plugins.BasePlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.plugins.WarPlugin;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.War;\n\nimport org.springframework.boot.gradle.tasks.bundling.BootBuildImage;\nimport org.springframework.boot.gradle.tasks.bundling.BootWar;\n\n/**\n * {@link Action} that is executed in response to the {@link WarPlugin} being applied.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass WarPluginAction implements PluginApplicationAction {\n\n\tprivate final SinglePublishedArtifact singlePublishedArtifact;\n\n\tWarPluginAction(SinglePublishedArtifact singlePublishedArtifact) {\n\t\tthis.singlePublishedArtifact = singlePublishedArtifact;\n\t}\n\n\t@Override\n\tpublic Class<? extends Plugin<? extends Project>> getPluginClass() {\n\t\treturn WarPlugin.class;\n\t}\n\n\t@Override\n\tpublic void execute(Project project) {\n\t\tclassifyWarTask(project);\n\t\tTaskProvider<BootWar> bootWar = configureBootWarTask(project);\n\t\tconfigureBootBuildImageTask(project, bootWar);\n\t\tconfigureArtifactPublication(bootWar);\n\t}\n\n\tprivate void classifyWarTask(Project project) {\n\t\tproject.getTasks()\n\t\t\t.named(WarPlugin.WAR_TASK_NAME, War.class)\n\t\t\t.configure((war) -> war.getArchiveClassifier().convention(\"plain\"));\n\t}\n\n\tprivate TaskProvider<BootWar> configureBootWarTask(Project project) {\n\t\tConfiguration developmentOnly = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.DEVELOPMENT_ONLY_CONFIGURATION_NAME);\n\t\tConfiguration testAndDevelopmentOnly = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.TEST_AND_DEVELOPMENT_ONLY_CONFIGURATION_NAME);\n\t\tConfiguration productionRuntimeClasspath = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.PRODUCTION_RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t.getByType(SourceSetContainer.class)\n\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tConfiguration runtimeClasspath = project.getConfigurations()\n\t\t\t.getByName(mainSourceSet.getRuntimeClasspathConfigurationName());\n\t\tCallable<FileCollection> classpath = () -> mainSourceSet.getRuntimeClasspath()\n\t\t\t.minus(providedRuntimeConfiguration(project))\n\t\t\t.minus((developmentOnly.minus(productionRuntimeClasspath)))\n\t\t\t.minus((testAndDevelopmentOnly.minus(productionRuntimeClasspath)))\n\t\t\t.filter(new JarTypeFileSpec());\n\t\tCallable<FileCollection> providedClasspath = () -> providedRuntimeConfiguration(project)\n\t\t\t.filter(new JarTypeFileSpec());\n\t\tTaskProvider<ResolveMainClassName> resolveMainClassName = project.getTasks()\n\t\t\t.named(SpringBootPlugin.RESOLVE_MAIN_CLASS_NAME_TASK_NAME, ResolveMainClassName.class);\n\t\tTaskProvider<BootWar> bootWarProvider = project.getTasks()\n\t\t\t.register(SpringBootPlugin.BOOT_WAR_TASK_NAME, BootWar.class, (bootWar) -> {\n\t\t\t\tbootWar.setGroup(BasePlugin.BUILD_GROUP);\n\t\t\t\tbootWar.setDescription(\"Assembles an executable war archive containing webapp\"\n\t\t\t\t\t\t+ \" content, and the main classes and their dependencies.\");\n\t\t\t\tbootWar.providedClasspath(providedClasspath);\n\t\t\t\tbootWar.setClasspath(classpath);\n\t\t\t\tProvider<String> manifestStartClass = project\n\t\t\t\t\t.provider(() -> (String) bootWar.getManifest().getAttributes().get(\"Start-Class\"));\n\t\t\t\tbootWar.getMainClass()\n\t\t\t\t\t.convention(resolveMainClassName.flatMap((resolver) -> manifestStartClass.isPresent()\n\t\t\t\t\t\t\t? manifestStartClass : resolver.readMainClassName()));\n\t\t\t\tbootWar.getTargetJavaVersion()\n\t\t\t\t\t.set(project.provider(() -> javaPluginExtension(project).getTargetCompatibility()));\n\t\t\t\tbootWar.resolvedArtifacts(runtimeClasspath.getIncoming().getArtifacts().getResolvedArtifacts());\n\t\t\t});\n\t\treturn bootWarProvider;\n\t}\n\n\tprivate FileCollection providedRuntimeConfiguration(Project project) {\n\t\tConfigurationContainer configurations = project.getConfigurations();\n\t\treturn configurations.getByName(WarPlugin.PROVIDED_RUNTIME_CONFIGURATION_NAME);\n\t}\n\n\tprivate void configureBootBuildImageTask(Project project, TaskProvider<BootWar> bootWar) {\n\t\tproject.getTasks()\n\t\t\t.named(SpringBootPlugin.BOOT_BUILD_IMAGE_TASK_NAME, BootBuildImage.class)\n\t\t\t.configure((buildImage) -> buildImage.getArchiveFile().set(bootWar.get().getArchiveFile()));\n\t}\n\n\tprivate void configureArtifactPublication(TaskProvider<BootWar> bootWar) {\n\t\tthis.singlePublishedArtifact.addWarCandidate(bootWar);\n\t}\n\n\tprivate JavaPluginExtension javaPluginExtension(Project project) {\n\t\treturn project.getExtensions().getByType(JavaPluginExtension.class);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Central classes for the Spring Boot Gradle plugin.\n */\n@NullMarked\npackage org.springframework.boot.gradle.plugin;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/AbstractAot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.aot;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.JavaExec;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.work.DisableCachingByDefault;\n\n/**\n * Specialization of {@link JavaExec} to be used as a base class for tasks that perform\n * ahead-of-time processing.\n *\n * @author Andy Wilkinson\n * @since 3.0.0\n */\n@DisableCachingByDefault(because = \"Cacheability can only be determined by a concrete implementation\")\npublic abstract class AbstractAot extends JavaExec {\n\n\tprivate final DirectoryProperty sourcesDir;\n\n\tprivate final DirectoryProperty resourcesDir;\n\n\tprivate final DirectoryProperty classesDir;\n\n\tprivate final Property<String> groupId;\n\n\tprivate final Property<String> artifactId;\n\n\tprotected AbstractAot() {\n\t\tthis.sourcesDir = getProject().getObjects().directoryProperty();\n\t\tthis.resourcesDir = getProject().getObjects().directoryProperty();\n\t\tthis.classesDir = getProject().getObjects().directoryProperty();\n\t\tthis.groupId = getProject().getObjects().property(String.class);\n\t\tthis.artifactId = getProject().getObjects().property(String.class);\n\t}\n\n\t/**\n\t * The group ID of the application that is to be processed ahead-of-time.\n\t * @return the group ID property\n\t */\n\t@Input\n\tpublic final Property<String> getGroupId() {\n\t\treturn this.groupId;\n\t}\n\n\t/**\n\t * The artifact ID of the application that is to be processed ahead-of-time.\n\t * @return the artifact ID property\n\t */\n\t@Input\n\tpublic final Property<String> getArtifactId() {\n\t\treturn this.artifactId;\n\t}\n\n\t/**\n\t * The directory to which AOT-generated sources should be written.\n\t * @return the sources directory property\n\t */\n\t@OutputDirectory\n\tpublic final DirectoryProperty getSourcesOutput() {\n\t\treturn this.sourcesDir;\n\t}\n\n\t/**\n\t * The directory to which AOT-generated resources should be written.\n\t * @return the resources directory property\n\t */\n\t@OutputDirectory\n\tpublic final DirectoryProperty getResourcesOutput() {\n\t\treturn this.resourcesDir;\n\t}\n\n\t/**\n\t * The directory to which AOT-generated classes should be written.\n\t * @return the classes directory property\n\t */\n\t@OutputDirectory\n\tpublic final DirectoryProperty getClassesOutput() {\n\t\treturn this.classesDir;\n\t}\n\n\tList<String> processorArgs() {\n\t\tList<String> args = new ArrayList<>();\n\t\targs.add(getSourcesOutput().getAsFile().get().getAbsolutePath());\n\t\targs.add(getResourcesOutput().getAsFile().get().getAbsolutePath());\n\t\targs.add(getClassesOutput().getAsFile().get().getAbsolutePath());\n\t\targs.add(getGroupId().get());\n\t\targs.add(getArtifactId().get());\n\t\targs.addAll(super.getArgs());\n\t\treturn args;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessAot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.aot;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.CacheableTask;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.JavaExec;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * Custom {@link JavaExec} task for ahead-of-time processing of a Spring Boot application.\n *\n * @author Andy Wilkinson\n * @since 3.0.0\n */\n@CacheableTask\npublic abstract class ProcessAot extends AbstractAot {\n\n\tpublic ProcessAot() {\n\t\tgetMainClass().set(\"org.springframework.boot.SpringApplicationAotProcessor\");\n\t}\n\n\t/**\n\t * Returns the main class of the application that is to be processed ahead-of-time.\n\t * @return the application main class property\n\t */\n\t@Input\n\tpublic abstract Property<String> getApplicationMainClass();\n\n\t@Override\n\t@TaskAction\n\tpublic void exec() {\n\t\tList<String> args = new ArrayList<>();\n\t\targs.add(getApplicationMainClass().get());\n\t\targs.addAll(processorArgs());\n\t\tsetArgs(args);\n\t\tsuper.exec();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/ProcessTestAot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.aot;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.tasks.CacheableTask;\nimport org.gradle.api.tasks.IgnoreEmptyDirectories;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.JavaExec;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SkipWhenEmpty;\nimport org.gradle.api.tasks.TaskAction;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Custom {@link JavaExec} task for ahead-of-time processing of a Spring Boot\n * application's tests.\n *\n * @author Andy Wilkinson\n * @since 3.0.0\n */\n@CacheableTask\npublic abstract class ProcessTestAot extends AbstractAot {\n\n\tprivate @Nullable FileCollection classpathRoots;\n\n\tpublic ProcessTestAot() {\n\t\tgetMainClass().set(\"org.springframework.boot.test.context.SpringBootTestAotProcessor\");\n\t}\n\n\t/**\n\t * Returns the classpath roots that should be scanned for test classes to process.\n\t * @return the classpath roots\n\t */\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic final @Nullable FileCollection getClasspathRoots() {\n\t\treturn this.classpathRoots;\n\t}\n\n\t/**\n\t * Sets the classpath roots that should be scanned for test classes to process.\n\t * @param classpathRoots the classpath roots\n\t */\n\tpublic void setClasspathRoots(FileCollection classpathRoots) {\n\t\tthis.classpathRoots = classpathRoots;\n\t}\n\n\t@InputFiles\n\t@SkipWhenEmpty\n\t@IgnoreEmptyDirectories\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tfinal FileTree getInputClasses() {\n\t\tAssert.state(this.classpathRoots != null, \"'classpathRoots' must not be null\");\n\t\treturn this.classpathRoots.getAsFileTree();\n\t}\n\n\t@Override\n\t@TaskAction\n\tpublic void exec() {\n\t\tList<String> args = new ArrayList<>();\n\t\tFileCollection classpathRoots = getClasspathRoots();\n\t\tAssert.state(classpathRoots != null, \"'classpathRoots' must not be null\");\n\t\targs.add(classpathRoots.getFiles()\n\t\t\t.stream()\n\t\t\t.filter(File::exists)\n\t\t\t.map(File::getAbsolutePath)\n\t\t\t.collect(Collectors.joining(File.pathSeparator)));\n\t\targs.addAll(processorArgs());\n\t\tsetArgs(args);\n\t\tsuper.exec();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/aot/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for ahead-of-time processing of an application built with Gradle.\n */\n@NullMarked\npackage org.springframework.boot.gradle.tasks.aot;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.buildinfo;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.provider.SetProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Internal;\nimport org.gradle.api.tasks.Nested;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.TaskExecutionException;\nimport org.gradle.work.DisableCachingByDefault;\n\nimport org.springframework.boot.loader.tools.BuildPropertiesWriter;\nimport org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails;\n\n/**\n * {@link Task} for generating a build info properties file from\n * {@link BuildInfoProperties}.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@DisableCachingByDefault(because = \"Not worth caching\")\npublic abstract class BuildInfo extends DefaultTask {\n\n\tprivate final BuildInfoProperties properties;\n\n\tpublic BuildInfo() {\n\t\tthis.properties = getProject().getObjects().newInstance(BuildInfoProperties.class, getExcludes());\n\t\tgetDestinationDir().convention(getProject().getLayout().getBuildDirectory().dir(getName()));\n\t\tgetFilename().convention(\"META-INF/build-info.properties\");\n\t}\n\n\t/**\n\t * Returns the names of the properties to exclude from the output.\n\t * @return names of the properties to exclude\n\t * @since 3.0.0\n\t */\n\t@Internal\n\tpublic abstract SetProperty<String> getExcludes();\n\n\t/**\n\t * Returns the name of the file that is written to the {@link #getDestinationDir\n\t * destination dir}. Convention is {@code META-INF/build-info.properties}.\n\t * @return the name of the written file\n\t * @since 4.1.0\n\t */\n\t@Input\n\tpublic abstract Property<String> getFilename();\n\n\t/**\n\t * Generates the build info properties file in the configured\n\t * {@link #getDestinationDir destination dir}.\n\t */\n\t@TaskAction\n\tpublic void generateBuildProperties() {\n\t\ttry {\n\t\t\tProjectDetails details = new ProjectDetails(this.properties.getGroupIfNotExcluded(),\n\t\t\t\t\tthis.properties.getArtifactIfNotExcluded(), this.properties.getVersionIfNotExcluded(),\n\t\t\t\t\tthis.properties.getNameIfNotExcluded(), this.properties.getTimeIfNotExcluded(),\n\t\t\t\t\tthis.properties.getAdditionalIfNotExcluded());\n\t\t\tFile outputFile = new File(getDestinationDir().getAsFile().get(), getFilename().get());\n\t\t\tnew BuildPropertiesWriter(outputFile).writeBuildProperties(details);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new TaskExecutionException(this, ex);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the directory to which the build info file will be written. Convention is\n\t * <code>build/${taskName}</code>.\n\t * @return the destination directory\n\t */\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getDestinationDir();\n\n\t/**\n\t * Returns the {@link BuildInfoProperties properties} that will be included in the\n\t * written file.\n\t * @return the properties\n\t */\n\t@Nested\n\tpublic BuildInfoProperties getProperties() {\n\t\treturn this.properties;\n\t}\n\n\t/**\n\t * Executes the given {@code action} on the {@link #getProperties()} properties.\n\t * @param action the action\n\t */\n\tpublic void properties(Action<BuildInfoProperties> action) {\n\t\taction.execute(this.properties);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.buildinfo;\n\nimport java.io.Serializable;\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.provider.SetProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Internal;\nimport org.gradle.api.tasks.Optional;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * The properties that are written into the {@code META-INF/build-info.properties} file.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@SuppressWarnings(\"serial\")\npublic abstract class BuildInfoProperties implements Serializable {\n\n\tprivate final SetProperty<String> excludes;\n\n\tprivate final Supplier<@Nullable String> creationTime = () -> DateTimeFormatter.ISO_INSTANT.format(Instant.now());\n\n\t@Inject\n\tpublic BuildInfoProperties(Project project, SetProperty<String> excludes) {\n\t\tthis.excludes = excludes;\n\t\tgetGroup().convention(project.provider(() -> project.getGroup().toString()));\n\t\tgetVersion().convention(project.provider(() -> project.getVersion().toString()));\n\t\tgetArtifact()\n\t\t\t.convention(project.provider(() -> project.findProperty(\"archivesBaseName\")).map(Object::toString));\n\t\tgetName().convention(project.provider(project::getName));\n\t}\n\n\t/**\n\t * Returns the {@code build.group} property. Defaults to the {@link Project#getGroup()\n\t * Project's group}.\n\t * @return the group property\n\t */\n\t@Internal\n\tpublic abstract Property<String> getGroup();\n\n\t/**\n\t * Returns the {@code build.artifact} property.\n\t * @return the artifact property\n\t */\n\t@Internal\n\tpublic abstract Property<String> getArtifact();\n\n\t/**\n\t * Returns the {@code build.version} property. Defaults to the\n\t * {@link Project#getVersion() Project's version}.\n\t * @return the version\n\t */\n\t@Internal\n\tpublic abstract Property<String> getVersion();\n\n\t/**\n\t * Returns the {@code build.name} property. Defaults to the {@link Project#getName()\n\t * Project's name}.\n\t * @return the name\n\t */\n\t@Internal\n\tpublic abstract Property<String> getName();\n\n\t/**\n\t * Returns the {@code build.time} property.\n\t * @return the time\n\t */\n\t@Internal\n\tpublic abstract Property<String> getTime();\n\n\t/**\n\t * Returns the additional properties that will be included. When written, the name of\n\t * each additional property is prefixed with {@code build.}.\n\t * @return the additional properties\n\t */\n\t@Internal\n\tpublic abstract MapProperty<String, Object> getAdditional();\n\n\t@Input\n\t@Optional\n\t@Nullable String getArtifactIfNotExcluded() {\n\t\treturn getIfNotExcluded(getArtifact(), \"artifact\");\n\t}\n\n\t@Input\n\t@Optional\n\t@Nullable String getGroupIfNotExcluded() {\n\t\treturn getIfNotExcluded(getGroup(), \"group\");\n\t}\n\n\t@Input\n\t@Optional\n\t@Nullable String getNameIfNotExcluded() {\n\t\treturn getIfNotExcluded(getName(), \"name\");\n\t}\n\n\t@Input\n\t@Optional\n\t@Nullable Instant getTimeIfNotExcluded() {\n\t\tString time = getIfNotExcluded(getTime(), \"time\", this.creationTime);\n\t\treturn (time != null) ? Instant.parse(time) : null;\n\t}\n\n\t@Input\n\t@Optional\n\t@Nullable String getVersionIfNotExcluded() {\n\t\treturn getIfNotExcluded(getVersion(), \"version\");\n\t}\n\n\t@Input\n\tMap<String, String> getAdditionalIfNotExcluded() {\n\t\treturn coerceToStringValues(applyExclusions(getAdditional().getOrElse(Collections.emptyMap())));\n\t}\n\n\tprivate <T> @Nullable T getIfNotExcluded(Property<T> property, String name) {\n\t\tSupplier<@Nullable T> supplier = () -> null;\n\t\treturn getIfNotExcluded(property, name, supplier);\n\t}\n\n\tprivate <T> @Nullable T getIfNotExcluded(Property<T> property, String name, Supplier<@Nullable T> defaultValue) {\n\t\tif (this.excludes.getOrElse(Collections.emptySet()).contains(name)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (property.isPresent()) {\n\t\t\treturn property.get();\n\t\t}\n\t\treturn defaultValue.get();\n\t}\n\n\tprivate Map<String, String> coerceToStringValues(Map<String, Object> input) {\n\t\tMap<String, String> output = new HashMap<>();\n\t\tinput.forEach((key, value) -> {\n\t\t\tif (value instanceof Provider<?> provider) {\n\t\t\t\tvalue = provider.getOrNull();\n\t\t\t}\n\t\t\tif (value != null) {\n\t\t\t\toutput.put(key, value.toString());\n\t\t\t}\n\t\t});\n\t\treturn output;\n\t}\n\n\tprivate Map<String, Object> applyExclusions(Map<String, Object> input) {\n\t\tMap<String, Object> output = new HashMap<>();\n\t\tSet<String> exclusions = this.excludes.getOrElse(Collections.emptySet());\n\t\tinput.forEach((key, value) -> {\n\t\t\tboolean isExcluded = exclusions.contains(key);\n\t\t\tif (!isExcluded) {\n\t\t\t\toutput.put(key, value);\n\t\t\t}\n\t\t});\n\t\treturn output;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for producing build info for consumption by Spring Boot's actuator.\n */\n@NullMarked\npackage org.springframework.boot.gradle.tasks.buildinfo;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.util.Set;\n\nimport org.gradle.api.JavaVersion;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileTreeElement;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.specs.Spec;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Optional;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A Spring Boot \"fat\" archive task.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @since 2.0.0\n */\npublic interface BootArchive extends Task {\n\n\t/**\n\t * Returns the fully-qualified name of the application's main class.\n\t * @return the fully-qualified name of the application's main class\n\t * @since 2.4.0\n\t */\n\t@Input\n\tProperty<String> getMainClass();\n\n\t/**\n\t * Adds Ant-style patterns that identify files that must be unpacked from the archive\n\t * when it is launched.\n\t * @param patterns the patterns\n\t */\n\tvoid requiresUnpack(String... patterns);\n\n\t/**\n\t * Adds a spec that identifies files that must be unpacked from the archive when it is\n\t * launched.\n\t * @param spec the spec\n\t */\n\tvoid requiresUnpack(Spec<FileTreeElement> spec);\n\n\t/**\n\t * Returns the classpath that will be included in the archive.\n\t * @return the classpath\n\t */\n\t@Optional\n\t@Classpath\n\t@Nullable FileCollection getClasspath();\n\n\t/**\n\t * Adds files to the classpath to include in the archive. The given {@code classpath}\n\t * is evaluated as per {@link Project#files(Object...)}.\n\t * @param classpath the additions to the classpath\n\t */\n\tvoid classpath(Object... classpath);\n\n\t/**\n\t * Sets the classpath to include in the archive. The given {@code classpath} is\n\t * evaluated as per {@link Project#files(Object...)}.\n\t * @param classpath the classpath\n\t * @since 2.0.7\n\t */\n\tvoid setClasspath(Object classpath);\n\n\t/**\n\t * Sets the classpath to include in the archive.\n\t * @param classpath the classpath\n\t * @since 2.0.7\n\t */\n\tvoid setClasspath(FileCollection classpath);\n\n\t/**\n\t * Returns the target Java version of the project (e.g. as provided by the\n\t * {@code targetCompatibility} build property).\n\t * @return the target Java version\n\t */\n\t@Input\n\t@Optional\n\tProperty<JavaVersion> getTargetJavaVersion();\n\n\t/**\n\t * Registers the given lazily provided {@code resolvedArtifacts}. They are used to map\n\t * from the files in the {@link #getClasspath classpath} to their dependency\n\t * coordinates.\n\t * @param resolvedArtifacts the lazily provided resolved artifacts\n\t * @since 3.0.7\n\t */\n\tvoid resolvedArtifacts(Provider<Set<ResolvedArtifactResult>> resolvedArtifacts);\n\n\t/**\n\t * Returns whether the JAR tools should be included as a dependency in the layered\n\t * archive.\n\t * @return whether the JAR tools should be included\n\t * @since 3.3.0\n\t */\n\t@Input\n\tProperty<Boolean> getIncludeTools();\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport org.gradle.api.file.ConfigurableFilePermissions;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.FileCopyDetails;\nimport org.gradle.api.file.FileTreeElement;\nimport org.gradle.api.internal.file.copy.CopyAction;\nimport org.gradle.api.java.archives.Attributes;\nimport org.gradle.api.java.archives.Manifest;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.specs.Spec;\nimport org.gradle.api.specs.Specs;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.gradle.api.tasks.util.PatternSet;\nimport org.gradle.util.GradleVersion;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Support class for implementations of {@link BootArchive}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @see BootJar\n * @see BootWar\n */\nclass BootArchiveSupport {\n\n\tprivate static final byte[] ZIP_FILE_HEADER = new byte[] { 'P', 'K', 3, 4 };\n\n\tprivate static final String UNSPECIFIED_VERSION = \"unspecified\";\n\n\tprivate static final Set<String> DEFAULT_LAUNCHER_CLASSES;\n\n\tstatic {\n\t\tSet<String> defaultLauncherClasses = new HashSet<>();\n\t\tdefaultLauncherClasses.add(\"org.springframework.boot.loader.launch.JarLauncher\");\n\t\tdefaultLauncherClasses.add(\"org.springframework.boot.loader.launch.PropertiesLauncher\");\n\t\tdefaultLauncherClasses.add(\"org.springframework.boot.loader.launch.WarLauncher\");\n\t\tDEFAULT_LAUNCHER_CLASSES = Collections.unmodifiableSet(defaultLauncherClasses);\n\t}\n\n\tprivate final PatternSet requiresUnpack = new PatternSet();\n\n\tprivate final PatternSet exclusions = new PatternSet();\n\n\tprivate final String loaderMainClass;\n\n\tprivate final Spec<FileCopyDetails> librarySpec;\n\n\tprivate final Function<FileCopyDetails, ZipCompression> compressionResolver;\n\n\tBootArchiveSupport(String loaderMainClass, Spec<FileCopyDetails> librarySpec,\n\t\t\tFunction<FileCopyDetails, ZipCompression> compressionResolver) {\n\t\tthis.loaderMainClass = loaderMainClass;\n\t\tthis.librarySpec = librarySpec;\n\t\tthis.compressionResolver = compressionResolver;\n\t\tthis.requiresUnpack.include(Specs.satisfyNone());\n\t}\n\n\tvoid configureManifest(Manifest manifest, String mainClass, String classes, String lib,\n\t\t\t@Nullable String classPathIndex, @Nullable String layersIndex, String jdkVersion,\n\t\t\tString implementationTitle, @Nullable Object implementationVersion) {\n\t\tAttributes attributes = manifest.getAttributes();\n\t\tattributes.putIfAbsent(\"Main-Class\", this.loaderMainClass);\n\t\tattributes.putIfAbsent(\"Start-Class\", mainClass);\n\t\tattributes.computeIfAbsent(\"Spring-Boot-Version\", (name) -> determineSpringBootVersion());\n\t\tattributes.putIfAbsent(\"Spring-Boot-Classes\", classes);\n\t\tattributes.putIfAbsent(\"Spring-Boot-Lib\", lib);\n\t\tif (classPathIndex != null) {\n\t\t\tattributes.putIfAbsent(\"Spring-Boot-Classpath-Index\", classPathIndex);\n\t\t}\n\t\tif (layersIndex != null) {\n\t\t\tattributes.putIfAbsent(\"Spring-Boot-Layers-Index\", layersIndex);\n\t\t}\n\t\tattributes.putIfAbsent(\"Build-Jdk-Spec\", jdkVersion);\n\t\tattributes.putIfAbsent(\"Implementation-Title\", implementationTitle);\n\t\tif (implementationVersion != null) {\n\t\t\tString versionString = implementationVersion.toString();\n\t\t\tif (!UNSPECIFIED_VERSION.equals(versionString)) {\n\t\t\t\tattributes.putIfAbsent(\"Implementation-Version\", versionString);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String determineSpringBootVersion() {\n\t\tString version = getClass().getPackage().getImplementationVersion();\n\t\treturn (version != null) ? version : \"unknown\";\n\t}\n\n\tCopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies) {\n\t\treturn createCopyAction(jar, resolvedDependencies, null, null);\n\t}\n\n\tCopyAction createCopyAction(Jar jar, ResolvedDependencies resolvedDependencies,\n\t\t\t@Nullable LayerResolver layerResolver, @Nullable String jarmodeToolsLocation) {\n\t\tFile output = jar.getArchiveFile().get().getAsFile();\n\t\tManifest manifest = jar.getManifest();\n\t\tboolean preserveFileTimestamps = jar.isPreserveFileTimestamps();\n\t\tInteger dirPermissions = getUnixNumericDirPermissions(jar);\n\t\tInteger filePermissions = getUnixNumericFilePermissions(jar);\n\t\tboolean includeDefaultLoader = isUsingDefaultLoader(jar);\n\t\tSpec<FileTreeElement> requiresUnpack = this.requiresUnpack.getAsSpec();\n\t\tSpec<FileTreeElement> exclusions = this.exclusions.getAsExcludeSpec();\n\t\tSpec<FileCopyDetails> librarySpec = this.librarySpec;\n\t\tFunction<FileCopyDetails, ZipCompression> compressionResolver = this.compressionResolver;\n\t\tString encoding = jar.getMetadataCharset();\n\t\tCopyAction action = new BootZipCopyAction(output, manifest, preserveFileTimestamps, dirPermissions,\n\t\t\t\tfilePermissions, includeDefaultLoader, jarmodeToolsLocation, requiresUnpack, exclusions, librarySpec,\n\t\t\t\tcompressionResolver, encoding, resolvedDependencies, layerResolver);\n\t\treturn action;\n\t}\n\n\tprivate @Nullable Integer getUnixNumericDirPermissions(CopySpec copySpec) {\n\t\treturn (GradleVersion.current().compareTo(GradleVersion.version(\"8.3\")) >= 0)\n\t\t\t\t? asUnixNumeric(copySpec.getDirPermissions()) : getDirMode(copySpec);\n\t}\n\n\tprivate @Nullable Integer getUnixNumericFilePermissions(CopySpec copySpec) {\n\t\treturn (GradleVersion.current().compareTo(GradleVersion.version(\"8.3\")) >= 0)\n\t\t\t\t? asUnixNumeric(copySpec.getFilePermissions()) : getFileMode(copySpec);\n\t}\n\n\tprivate @Nullable Integer asUnixNumeric(Property<ConfigurableFilePermissions> permissions) {\n\t\treturn permissions.isPresent() ? permissions.get().toUnixNumeric() : null;\n\t}\n\n\tprivate @Nullable Integer getDirMode(CopySpec copySpec) {\n\t\ttry {\n\t\t\treturn (Integer) copySpec.getClass().getMethod(\"getDirMode\").invoke(copySpec);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(\"Failed to get dir mode from CopySpec\", ex);\n\t\t}\n\t}\n\n\tprivate @Nullable Integer getFileMode(CopySpec copySpec) {\n\t\ttry {\n\t\t\treturn (Integer) copySpec.getClass().getMethod(\"getFileMode\").invoke(copySpec);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(\"Failed to get file mode from CopySpec\", ex);\n\t\t}\n\t}\n\n\tprivate boolean isUsingDefaultLoader(Jar jar) {\n\t\treturn DEFAULT_LAUNCHER_CLASSES.contains(jar.getManifest().getAttributes().get(\"Main-Class\"));\n\t}\n\n\tvoid requiresUnpack(String... patterns) {\n\t\tthis.requiresUnpack.include(patterns);\n\t}\n\n\tvoid requiresUnpack(Spec<FileTreeElement> spec) {\n\t\tthis.requiresUnpack.include(spec);\n\t}\n\n\tvoid excludeNonZipLibraryFiles(FileCopyDetails details) {\n\t\tif (this.librarySpec.isSatisfiedBy(details)) {\n\t\t\texcludeNonZipFiles(details);\n\t\t}\n\t}\n\n\tvoid excludeNonZipFiles(FileCopyDetails details) {\n\t\tif (!isZip(details.getFile())) {\n\t\t\tdetails.exclude();\n\t\t}\n\t}\n\n\tprivate boolean isZip(File file) {\n\t\ttry {\n\t\t\ttry (FileInputStream fileInputStream = new FileInputStream(file)) {\n\t\t\t\treturn isZip(fileInputStream);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean isZip(InputStream inputStream) throws IOException {\n\t\tfor (byte headerByte : ZIP_FILE_HEADER) {\n\t\t\tif (inputStream.read() != headerByte) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid moveModuleInfoToRoot(CopySpec spec) {\n\t\tspec.filesMatching(\"module-info.class\", this::moveToRoot);\n\t}\n\n\tvoid moveToRoot(FileCopyDetails details) {\n\t\tdetails.setRelativePath(details.getRelativeSourcePath());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.InvalidUserDataException;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.Internal;\nimport org.gradle.api.tasks.Nested;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.options.Option;\nimport org.gradle.work.DisableCachingByDefault;\n\nimport org.springframework.boot.buildpack.platform.build.BuildRequest;\nimport org.springframework.boot.buildpack.platform.build.Builder;\nimport org.springframework.boot.buildpack.platform.build.BuildpackReference;\nimport org.springframework.boot.buildpack.platform.build.Cache;\nimport org.springframework.boot.buildpack.platform.build.Creator;\nimport org.springframework.boot.buildpack.platform.build.PullPolicy;\nimport org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageName;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.ZipFileTarArchive;\nimport org.springframework.boot.gradle.util.VersionExtractor;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link Task} for bundling an application into an OCI image using a\n * <a href=\"https://buildpacks.io\">buildpack</a>.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Rafael Ceccone\n * @author Jeroen Meijer\n * @author Julian Liebig\n * @since 2.3.0\n */\n@DisableCachingByDefault\npublic abstract class BootBuildImage extends DefaultTask {\n\n\tprivate final Property<PullPolicy> pullPolicy;\n\n\tprivate final String projectName;\n\n\tprivate final CacheSpec buildWorkspace;\n\n\tprivate final CacheSpec buildCache;\n\n\tprivate final CacheSpec launchCache;\n\n\tprivate final DockerSpec docker;\n\n\tpublic BootBuildImage() {\n\t\tthis.projectName = getProject().getName();\n\t\tProject project = getProject();\n\t\tProperty<String> projectVersion = project.getObjects()\n\t\t\t.property(String.class)\n\t\t\t.convention(project.provider(() -> project.getVersion().toString()));\n\t\tgetImageName().convention(project.provider(() -> {\n\t\t\tImageName imageName = ImageName.of(this.projectName);\n\t\t\tif (\"unspecified\".equals(projectVersion.get())) {\n\t\t\t\treturn ImageReference.of(imageName).toString();\n\t\t\t}\n\t\t\treturn ImageReference.of(imageName, projectVersion.get()).toString();\n\t\t}));\n\t\tgetTrustBuilder().convention((Boolean) null);\n\t\tgetCleanCache().convention(false);\n\t\tgetVerboseLogging().convention(false);\n\t\tgetPublish().convention(false);\n\t\tthis.buildWorkspace = getProject().getObjects().newInstance(CacheSpec.class);\n\t\tthis.buildCache = getProject().getObjects().newInstance(CacheSpec.class);\n\t\tthis.launchCache = getProject().getObjects().newInstance(CacheSpec.class);\n\t\tthis.docker = getProject().getObjects().newInstance(DockerSpec.class);\n\t\tthis.pullPolicy = getProject().getObjects().property(PullPolicy.class);\n\t\tgetSecurityOptions().convention((Iterable<? extends String>) null);\n\t\tgetEffectiveEnvironment().putAll(getEnvironment());\n\t\tgetEffectiveEnvironment().putAll(getEnvironmentFromCommandLine().map(BootBuildImage::asMap));\n\t}\n\n\tprivate static Map<String, String> asMap(List<String> variables) {\n\t\tMap<String, String> environment = new LinkedHashMap<>();\n\t\tfor (String variable : variables) {\n\t\t\tint index = variable.indexOf('=');\n\t\t\tif (index <= 0) {\n\t\t\t\tthrow new InvalidUserDataException(\n\t\t\t\t\t\t\"Invalid value for option '--environment'. Expected 'NAME=VALUE' but got '\" + variable + \"'.\");\n\t\t\t}\n\t\t\tString name = variable.substring(0, index);\n\t\t\tString value = variable.substring(index + 1);\n\t\t\tenvironment.put(name, value);\n\t\t}\n\t\treturn environment;\n\t}\n\n\t/**\n\t * Returns the property for the archive file from which the image will be built.\n\t * @return the archive file property\n\t */\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract RegularFileProperty getArchiveFile();\n\n\t/**\n\t * Returns the name of the image that will be built. When {@code null}, the name will\n\t * be derived from the {@link Project Project's} {@link Project#getName() name} and\n\t * {@link Project#getVersion version}.\n\t * @return name of the image\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"imageName\", description = \"The name of the image to generate\")\n\tpublic abstract Property<String> getImageName();\n\n\t/**\n\t * Returns the builder that will be used to build the image. When {@code null}, the\n\t * default builder will be used.\n\t * @return the builder\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"builder\", description = \"The name of the builder image to use\")\n\tpublic abstract Property<String> getBuilder();\n\n\t/**\n\t * Whether to treat the builder as trusted.\n\t * @return whether to trust the builder\n\t * @since 3.4.0\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"trustBuilder\", description = \"Consider the builder trusted\")\n\tpublic abstract Property<Boolean> getTrustBuilder();\n\n\t/**\n\t * Returns the run image that will be included in the built image. When {@code null},\n\t * the run image bundled with the builder will be used.\n\t * @return the run image\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"runImage\", description = \"The name of the run image to use\")\n\tpublic abstract Property<String> getRunImage();\n\n\t/**\n\t * Returns the environment that will be used when building the image.\n\t * @return the environment\n\t */\n\t@Internal\n\tpublic abstract MapProperty<String, String> getEnvironment();\n\n\t/**\n\t * Returns environment variables contributed from the command line. Each entry must be\n\t * in the form NAME=VALUE.\n\t * @return the environment variables from the command line\n\t */\n\t@Internal\n\t@Option(option = \"environment\", description = \"Environment variable that will be used when building the image \"\n\t\t\t+ \"(NAME=VALUE). Can be specified multiple times.\")\n\tabstract ListProperty<String> getEnvironmentFromCommandLine();\n\n\t@Input\n\tabstract MapProperty<String, String> getEffectiveEnvironment();\n\n\t/**\n\t * Returns whether caches should be cleaned before packaging.\n\t * @return whether caches should be cleaned\n\t * @since 3.0.0\n\t */\n\t@Input\n\t@Option(option = \"cleanCache\", description = \"Clean caches before packaging\")\n\tpublic abstract Property<Boolean> getCleanCache();\n\n\t/**\n\t * Whether verbose logging should be enabled while building the image.\n\t * @return whether verbose logging should be enabled\n\t * @since 3.0.0\n\t */\n\t@Input\n\tpublic abstract Property<Boolean> getVerboseLogging();\n\n\t/**\n\t * Returns image pull policy that will be used when building the image.\n\t * @return whether images should be pulled\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"pullPolicy\", description = \"The image pull policy\")\n\tpublic Property<PullPolicy> getPullPolicy() {\n\t\treturn this.pullPolicy;\n\t}\n\n\t/**\n\t * Sets image pull policy that will be used when building the image.\n\t * @param pullPolicy the pull policy to use\n\t */\n\tpublic void setPullPolicy(String pullPolicy) {\n\t\tgetPullPolicy().set(PullPolicy.valueOf(pullPolicy));\n\t}\n\n\t/**\n\t * Whether the built image should be pushed to a registry.\n\t * @return whether the built image should be pushed\n\t * @since 3.0.0\n\t */\n\t@Input\n\t@Option(option = \"publishImage\", description = \"Publish the built image to a registry\")\n\tpublic abstract Property<Boolean> getPublish();\n\n\t/**\n\t * Returns the buildpacks that will be used when building the image.\n\t * @return the buildpack references\n\t */\n\t@Input\n\t@Optional\n\tpublic abstract ListProperty<String> getBuildpacks();\n\n\t/**\n\t * Returns the volume bindings that will be mounted to the container when building the\n\t * image.\n\t * @return the bindings\n\t */\n\t@Input\n\t@Optional\n\tpublic abstract ListProperty<String> getBindings();\n\n\t/**\n\t * Returns the tags that will be created for the built image.\n\t * @return the tags\n\t */\n\t@Input\n\t@Optional\n\tpublic abstract ListProperty<String> getTags();\n\n\t/**\n\t * Returns the network the build container will connect to.\n\t * @return the network\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"network\", description = \"Connect detect and build containers to network\")\n\tpublic abstract Property<String> getNetwork();\n\n\t/**\n\t * Returns the build temporary workspace that will be used when building the image.\n\t * @return the cache\n\t * @since 3.2.0\n\t */\n\t@Nested\n\t@Optional\n\tpublic CacheSpec getBuildWorkspace() {\n\t\treturn this.buildWorkspace;\n\t}\n\n\t/**\n\t * Customizes the {@link CacheSpec} for the build temporary workspace using the given\n\t * {@code action}.\n\t * @param action the action\n\t * @since 3.2.0\n\t */\n\tpublic void buildWorkspace(Action<CacheSpec> action) {\n\t\taction.execute(this.buildWorkspace);\n\t}\n\n\t/**\n\t * Returns the build cache that will be used when building the image.\n\t * @return the cache\n\t */\n\t@Nested\n\t@Optional\n\tpublic CacheSpec getBuildCache() {\n\t\treturn this.buildCache;\n\t}\n\n\t/**\n\t * Customizes the {@link CacheSpec} for the build cache using the given\n\t * {@code action}.\n\t * @param action the action\n\t */\n\tpublic void buildCache(Action<CacheSpec> action) {\n\t\taction.execute(this.buildCache);\n\t}\n\n\t/**\n\t * Returns the launch cache that will be used when building the image.\n\t * @return the cache\n\t */\n\t@Nested\n\t@Optional\n\tpublic CacheSpec getLaunchCache() {\n\t\treturn this.launchCache;\n\t}\n\n\t/**\n\t * Customizes the {@link CacheSpec} for the launch cache using the given\n\t * {@code action}.\n\t * @param action the action\n\t */\n\tpublic void launchCache(Action<CacheSpec> action) {\n\t\taction.execute(this.launchCache);\n\t}\n\n\t/**\n\t * Returns the date that will be used as the {@code Created} date of the image. When\n\t * {@code null}, a fixed date that enables build reproducibility will be used.\n\t * @return the created date\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"createdDate\", description = \"The date to use as the created date of the image\")\n\tpublic abstract Property<String> getCreatedDate();\n\n\t/**\n\t * Returns the directory that contains application content in the image. When\n\t * {@code null}, a default location will be used.\n\t * @return the application directory\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"applicationDirectory\", description = \"The directory containing application content in the image\")\n\tpublic abstract Property<String> getApplicationDirectory();\n\n\t/**\n\t * Returns the security options that will be applied to the builder container.\n\t * @return the security options\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"securityOptions\", description = \"Security options that will be applied to the builder container\")\n\tpublic abstract ListProperty<String> getSecurityOptions();\n\n\t/**\n\t * Returns the platform (os/architecture/variant) that will be used for all pulled\n\t * images. When {@code null}, the system will choose a platform based on the host\n\t * operating system and architecture.\n\t * @return the image platform\n\t */\n\t@Input\n\t@Optional\n\t@Option(option = \"imagePlatform\",\n\t\t\tdescription = \"The platform (os/architecture/variant) that will be used for all pulled images\")\n\tpublic abstract Property<String> getImagePlatform();\n\n\t/**\n\t * Returns the Docker configuration the builder will use.\n\t * @return docker configuration.\n\t * @since 2.4.0\n\t */\n\t@Nested\n\tpublic DockerSpec getDocker() {\n\t\treturn this.docker;\n\t}\n\n\t/**\n\t * Configures the Docker connection using the given {@code action}.\n\t * @param action the action to apply\n\t * @since 2.4.0\n\t */\n\tpublic void docker(Action<DockerSpec> action) {\n\t\taction.execute(this.docker);\n\t}\n\n\t@TaskAction\n\tvoid buildImage() throws DockerEngineException, IOException {\n\t\tBuilder builder = new Builder(this.docker.asDockerConfiguration());\n\t\tBuildRequest request = createRequest();\n\t\tbuilder.build(request);\n\t}\n\n\tBuildRequest createRequest() {\n\t\treturn customize(BuildRequest.of(getImageName().map(ImageReference::of).get(),\n\t\t\t\t(owner) -> new ZipFileTarArchive(getArchiveFile().get().getAsFile(), owner)));\n\t}\n\n\tprivate BuildRequest customize(BuildRequest request) {\n\t\trequest = customizeBuilder(request);\n\t\tif (getTrustBuilder().isPresent()) {\n\t\t\trequest = request.withTrustBuilder(getTrustBuilder().get());\n\t\t}\n\t\trequest = customizeRunImage(request);\n\t\trequest = customizeEnvironment(request);\n\t\trequest = customizeCreator(request);\n\t\trequest = request.withCleanCache(getCleanCache().get());\n\t\trequest = request.withVerboseLogging(getVerboseLogging().get());\n\t\trequest = customizePullPolicy(request);\n\t\trequest = request.withPublish(getPublish().get());\n\t\trequest = customizeBuildpacks(request);\n\t\trequest = customizeBindings(request);\n\t\trequest = customizeTags(request);\n\t\trequest = customizeCaches(request);\n\t\trequest = request.withNetwork(getNetwork().getOrNull());\n\t\trequest = customizeCreatedDate(request);\n\t\trequest = customizeApplicationDirectory(request);\n\t\trequest = customizeSecurityOptions(request);\n\t\tif (getImagePlatform().isPresent()) {\n\t\t\trequest = request.withImagePlatform(getImagePlatform().get());\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeBuilder(BuildRequest request) {\n\t\tString builder = getBuilder().getOrNull();\n\t\tif (StringUtils.hasText(builder)) {\n\t\t\treturn request.withBuilder(ImageReference.of(builder));\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeRunImage(BuildRequest request) {\n\t\tString runImage = getRunImage().getOrNull();\n\t\tif (StringUtils.hasText(runImage)) {\n\t\t\treturn request.withRunImage(ImageReference.of(runImage));\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeEnvironment(BuildRequest request) {\n\t\tMap<String, String> environment = getEffectiveEnvironment().getOrElse(Collections.emptyMap());\n\t\tif (!environment.isEmpty()) {\n\t\t\trequest = request.withEnv(environment);\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeCreator(BuildRequest request) {\n\t\tString springBootVersion = VersionExtractor.forClass(BootBuildImage.class);\n\t\tif (StringUtils.hasText(springBootVersion)) {\n\t\t\treturn request.withCreator(Creator.withVersion(springBootVersion));\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizePullPolicy(BuildRequest request) {\n\t\tPullPolicy pullPolicy = getPullPolicy().getOrNull();\n\t\tif (pullPolicy != null) {\n\t\t\trequest = request.withPullPolicy(pullPolicy);\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeBuildpacks(BuildRequest request) {\n\t\tList<String> buildpacks = getBuildpacks().getOrNull();\n\t\tif (!CollectionUtils.isEmpty(buildpacks)) {\n\t\t\treturn request.withBuildpacks(buildpacks.stream().map(BuildpackReference::of).toList());\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeBindings(BuildRequest request) {\n\t\tList<String> bindings = getBindings().getOrNull();\n\t\tif (!CollectionUtils.isEmpty(bindings)) {\n\t\t\treturn request.withBindings(bindings.stream().map(Binding::of).toList());\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeTags(BuildRequest request) {\n\t\tList<String> tags = getTags().getOrNull();\n\t\tif (!CollectionUtils.isEmpty(tags)) {\n\t\t\treturn request.withTags(tags.stream().map(ImageReference::of).toList());\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeCaches(BuildRequest request) {\n\t\tCache buildWorkspaceCache = this.buildWorkspace.asCache();\n\t\tif (buildWorkspaceCache != null) {\n\t\t\trequest = request.withBuildWorkspace(buildWorkspaceCache);\n\t\t}\n\t\tCache buildCache = this.buildCache.asCache();\n\t\tif (buildCache != null) {\n\t\t\trequest = request.withBuildCache(buildCache);\n\t\t}\n\t\tCache launchCache = this.launchCache.asCache();\n\t\tif (launchCache != null) {\n\t\t\trequest = request.withLaunchCache(launchCache);\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeCreatedDate(BuildRequest request) {\n\t\tString createdDate = getCreatedDate().getOrNull();\n\t\tif (createdDate != null) {\n\t\t\treturn request.withCreatedDate(createdDate);\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeApplicationDirectory(BuildRequest request) {\n\t\tString applicationDirectory = getApplicationDirectory().getOrNull();\n\t\tif (applicationDirectory != null) {\n\t\t\treturn request.withApplicationDirectory(applicationDirectory);\n\t\t}\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeSecurityOptions(BuildRequest request) {\n\t\tif (getSecurityOptions().isPresent()) {\n\t\t\tList<String> securityOptions = getSecurityOptions().getOrNull();\n\t\t\tif (securityOptions != null) {\n\t\t\t\treturn request.withSecurityOptions(securityOptions);\n\t\t\t}\n\t\t}\n\t\treturn request;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.function.Function;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileCopyDetails;\nimport org.gradle.api.file.FileTreeElement;\nimport org.gradle.api.internal.file.copy.CopyAction;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.specs.Spec;\nimport org.gradle.api.tasks.Internal;\nimport org.gradle.api.tasks.Nested;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.gradle.work.DisableCachingByDefault;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A custom {@link Jar} task that produces a Spring Boot executable jar.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.0.0\n */\n@DisableCachingByDefault(because = \"Not worth caching\")\npublic abstract class BootJar extends Jar implements BootArchive {\n\n\tprivate static final String LAUNCHER = \"org.springframework.boot.loader.launch.JarLauncher\";\n\n\tprivate static final String CLASSES_DIRECTORY = \"BOOT-INF/classes/\";\n\n\tprivate static final String LIB_DIRECTORY = \"BOOT-INF/lib/\";\n\n\tprivate static final String LAYERS_INDEX = \"BOOT-INF/layers.idx\";\n\n\tprivate static final String CLASSPATH_INDEX = \"BOOT-INF/classpath.idx\";\n\n\tprivate final BootArchiveSupport support;\n\n\tprivate final CopySpec bootInfSpec;\n\n\tprivate final LayeredSpec layered;\n\n\tprivate final Provider<String> projectName;\n\n\tprivate final Provider<Object> projectVersion;\n\n\tprivate final ResolvedDependencies resolvedDependencies;\n\n\tprivate @Nullable FileCollection classpath;\n\n\t/**\n\t * Creates a new {@code BootJar} task.\n\t */\n\tpublic BootJar() {\n\t\tthis.support = new BootArchiveSupport(LAUNCHER, new LibrarySpec(), new ZipCompressionResolver());\n\t\tProject project = getProject();\n\t\tthis.bootInfSpec = project.copySpec().into(\"BOOT-INF\");\n\t\tthis.layered = project.getObjects().newInstance(LayeredSpec.class);\n\t\tconfigureBootInfSpec(this.bootInfSpec);\n\t\tgetMainSpec().with(this.bootInfSpec);\n\t\tthis.projectName = project.provider(project::getName);\n\t\tthis.projectVersion = project.provider(project::getVersion);\n\t\tthis.resolvedDependencies = new ResolvedDependencies(project);\n\t\tgetIncludeTools().convention(true);\n\t}\n\n\tprivate void configureBootInfSpec(CopySpec bootInfSpec) {\n\t\tbootInfSpec.into(\"classes\", fromCallTo(this::classpathDirectories));\n\t\tbootInfSpec.into(\"lib\", fromCallTo(this::classpathFiles)).eachFile(this.support::excludeNonZipFiles);\n\t\tthis.support.moveModuleInfoToRoot(bootInfSpec);\n\t\tmoveMetaInfToRoot(bootInfSpec);\n\t}\n\n\tprivate Iterable<File> classpathDirectories() {\n\t\treturn classpathEntries(File::isDirectory);\n\t}\n\n\tprivate Iterable<File> classpathFiles() {\n\t\treturn classpathEntries(File::isFile);\n\t}\n\n\tprivate Iterable<File> classpathEntries(Spec<File> filter) {\n\t\treturn (this.classpath != null) ? this.classpath.filter(filter) : Collections.emptyList();\n\t}\n\n\tprivate void moveMetaInfToRoot(CopySpec spec) {\n\t\tspec.eachFile((file) -> {\n\t\t\tString path = file.getRelativeSourcePath().getPathString();\n\t\t\tif (path.startsWith(\"META-INF/\") && !path.equals(\"META-INF/aop.xml\") && !path.endsWith(\".kotlin_module\")\n\t\t\t\t\t&& !path.startsWith(\"META-INF/services/\")) {\n\t\t\t\tthis.support.moveToRoot(file);\n\t\t\t}\n\t\t});\n\t}\n\n\t@Override\n\tpublic void resolvedArtifacts(Provider<Set<ResolvedArtifactResult>> resolvedArtifacts) {\n\t\tthis.resolvedDependencies.resolvedArtifacts(resolvedArtifacts);\n\t}\n\n\t@Nested\n\tResolvedDependencies getResolvedDependencies() {\n\t\treturn this.resolvedDependencies;\n\t}\n\n\t@Override\n\tpublic void copy() {\n\t\tthis.support.configureManifest(getManifest(), getMainClass().get(), CLASSES_DIRECTORY, LIB_DIRECTORY,\n\t\t\t\tCLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX,\n\t\t\t\tthis.getTargetJavaVersion().get().getMajorVersion(), this.projectName.get(), this.projectVersion.get());\n\t\tsuper.copy();\n\t}\n\n\tprivate boolean isLayeredDisabled() {\n\t\treturn !getLayered().getEnabled().get();\n\t}\n\n\t@Override\n\tprotected CopyAction createCopyAction() {\n\t\tLayerResolver layerResolver = null;\n\t\tif (!isLayeredDisabled()) {\n\t\t\tlayerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary);\n\t\t}\n\t\tString jarmodeToolsLocation = isIncludeJarmodeTools() ? LIB_DIRECTORY : null;\n\t\treturn this.support.createCopyAction(this, this.resolvedDependencies, layerResolver, jarmodeToolsLocation);\n\t}\n\n\tprivate boolean isIncludeJarmodeTools() {\n\t\treturn Boolean.TRUE.equals(this.getIncludeTools().get());\n\t}\n\n\t@Override\n\tpublic void requiresUnpack(String... patterns) {\n\t\tthis.support.requiresUnpack(patterns);\n\t}\n\n\t@Override\n\tpublic void requiresUnpack(Spec<FileTreeElement> spec) {\n\t\tthis.support.requiresUnpack(spec);\n\t}\n\n\t/**\n\t * Returns the spec that describes the layers in a layered jar.\n\t * @return the spec for the layers\n\t * @since 2.3.0\n\t */\n\t@Nested\n\tpublic LayeredSpec getLayered() {\n\t\treturn this.layered;\n\t}\n\n\t/**\n\t * Configures the jar's layering using the given {@code action}.\n\t * @param action the action to apply\n\t * @since 2.3.0\n\t */\n\tpublic void layered(Action<LayeredSpec> action) {\n\t\taction.execute(this.layered);\n\t}\n\n\t@Override\n\tpublic @Nullable FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\t@Override\n\tpublic void classpath(Object... classpath) {\n\t\tFileCollection existingClasspath = this.classpath;\n\t\tthis.classpath = getProject().files((existingClasspath != null) ? existingClasspath : Collections.emptyList(),\n\t\t\t\tclasspath);\n\t}\n\n\t@Override\n\tpublic void setClasspath(Object classpath) {\n\t\tthis.classpath = getProject().files(classpath);\n\t}\n\n\t@Override\n\tpublic void setClasspath(FileCollection classpath) {\n\t\tthis.classpath = getProject().files(classpath);\n\t}\n\n\t/**\n\t * Returns a {@code CopySpec} that can be used to add content to the {@code BOOT-INF}\n\t * directory of the jar.\n\t * @return a {@code CopySpec} for {@code BOOT-INF}\n\t * @since 2.0.3\n\t */\n\t@Internal\n\tpublic CopySpec getBootInf() {\n\t\tCopySpec child = getProject().copySpec();\n\t\tthis.bootInfSpec.with(child);\n\t\treturn child;\n\t}\n\n\t/**\n\t * Calls the given {@code action} to add content to the {@code BOOT-INF} directory of\n\t * the jar.\n\t * @param action the {@code Action} to call\n\t * @return the {@code CopySpec} for {@code BOOT-INF} that was passed to the\n\t * {@code Action}\n\t * @since 2.0.3\n\t */\n\tpublic CopySpec bootInf(Action<CopySpec> action) {\n\t\tCopySpec bootInf = getBootInf();\n\t\taction.execute(bootInf);\n\t\treturn bootInf;\n\t}\n\n\t/**\n\t * Return the {@link ZipCompression} that should be used when adding the file\n\t * represented by the given {@code details} to the jar. By default, any\n\t * {@link #isLibrary(FileCopyDetails) library} is {@link ZipCompression#STORED stored}\n\t * and all other files are {@link ZipCompression#DEFLATED deflated}.\n\t * @param details the file copy details\n\t * @return the compression to use\n\t */\n\tprotected ZipCompression resolveZipCompression(FileCopyDetails details) {\n\t\treturn isLibrary(details) ? ZipCompression.STORED : ZipCompression.DEFLATED;\n\t}\n\n\t/**\n\t * Return if the {@link FileCopyDetails} are for a library. By default any file in\n\t * {@code BOOT-INF/lib} is considered to be a library.\n\t * @param details the file copy details\n\t * @return {@code true} if the details are for a library\n\t * @since 2.3.0\n\t */\n\tprotected boolean isLibrary(FileCopyDetails details) {\n\t\tString path = details.getRelativePath().getPathString();\n\t\treturn path.startsWith(LIB_DIRECTORY);\n\t}\n\n\t/**\n\t * Syntactic sugar that makes {@link CopySpec#into} calls a little easier to read.\n\t * @param <T> the result type\n\t * @param callable the callable\n\t * @return an action to add the callable to the spec\n\t */\n\tprivate static <T> Action<CopySpec> fromCallTo(Callable<T> callable) {\n\t\treturn (spec) -> spec.from(callTo(callable));\n\t}\n\n\t/**\n\t * Syntactic sugar that makes {@link CopySpec#from} calls a little easier to read.\n\t * @param <T> the result type\n\t * @param callable the callable\n\t * @return the callable\n\t */\n\tprivate static <T> Callable<T> callTo(Callable<T> callable) {\n\t\treturn callable;\n\t}\n\n\tprivate final class LibrarySpec implements Spec<FileCopyDetails> {\n\n\t\t@Override\n\t\tpublic boolean isSatisfiedBy(FileCopyDetails details) {\n\t\t\treturn isLibrary(details);\n\t\t}\n\n\t}\n\n\tprivate final class ZipCompressionResolver implements Function<FileCopyDetails, ZipCompression> {\n\n\t\t@Override\n\t\tpublic ZipCompression apply(FileCopyDetails details) {\n\t\t\treturn resolveZipCompression(details);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.function.Function;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileCopyDetails;\nimport org.gradle.api.file.FileTreeElement;\nimport org.gradle.api.internal.file.copy.CopyAction;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.specs.Spec;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Nested;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.bundling.War;\nimport org.gradle.work.DisableCachingByDefault;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A custom {@link War} task that produces a Spring Boot executable war.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.0.0\n */\n@DisableCachingByDefault(because = \"Not worth caching\")\npublic abstract class BootWar extends War implements BootArchive {\n\n\tprivate static final String LAUNCHER = \"org.springframework.boot.loader.launch.WarLauncher\";\n\n\tprivate static final String CLASSES_DIRECTORY = \"WEB-INF/classes/\";\n\n\tprivate static final String LIB_PROVIDED_DIRECTORY = \"WEB-INF/lib-provided/\";\n\n\tprivate static final String LIB_DIRECTORY = \"WEB-INF/lib/\";\n\n\tprivate static final String LAYERS_INDEX = \"WEB-INF/layers.idx\";\n\n\tprivate static final String CLASSPATH_INDEX = \"WEB-INF/classpath.idx\";\n\n\tprivate final BootArchiveSupport support;\n\n\tprivate final LayeredSpec layered;\n\n\tprivate final Provider<String> projectName;\n\n\tprivate final Provider<Object> projectVersion;\n\n\tprivate final ResolvedDependencies resolvedDependencies;\n\n\tprivate @Nullable FileCollection providedClasspath;\n\n\t/**\n\t * Creates a new {@code BootWar} task.\n\t */\n\tpublic BootWar() {\n\t\tthis.support = new BootArchiveSupport(LAUNCHER, new LibrarySpec(), new ZipCompressionResolver());\n\t\tProject project = getProject();\n\t\tthis.layered = project.getObjects().newInstance(LayeredSpec.class);\n\t\tgetWebInf().into(\"lib-provided\", fromCallTo(this::getProvidedLibFiles));\n\t\tthis.support.moveModuleInfoToRoot(getRootSpec());\n\t\tgetRootSpec().eachFile(this.support::excludeNonZipLibraryFiles);\n\t\tthis.projectName = project.provider(project::getName);\n\t\tthis.projectVersion = project.provider(project::getVersion);\n\t\tthis.resolvedDependencies = new ResolvedDependencies(project);\n\t\tgetIncludeTools().convention(true);\n\t}\n\n\tprivate Object getProvidedLibFiles() {\n\t\treturn (this.providedClasspath != null) ? this.providedClasspath : Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic void resolvedArtifacts(Provider<Set<ResolvedArtifactResult>> resolvedArtifacts) {\n\t\tthis.resolvedDependencies.resolvedArtifacts(resolvedArtifacts);\n\t}\n\n\t@Nested\n\tResolvedDependencies getResolvedDependencies() {\n\t\treturn this.resolvedDependencies;\n\t}\n\n\t@Override\n\tpublic void copy() {\n\t\tthis.support.configureManifest(getManifest(), getMainClass().get(), CLASSES_DIRECTORY, LIB_DIRECTORY,\n\t\t\t\tCLASSPATH_INDEX, (isLayeredDisabled()) ? null : LAYERS_INDEX,\n\t\t\t\tthis.getTargetJavaVersion().get().getMajorVersion(), this.projectName.get(), this.projectVersion.get());\n\t\tsuper.copy();\n\t}\n\n\tprivate boolean isLayeredDisabled() {\n\t\treturn !this.layered.getEnabled().get();\n\t}\n\n\t@Override\n\tprotected CopyAction createCopyAction() {\n\t\tLayerResolver layerResolver = null;\n\t\tif (!isLayeredDisabled()) {\n\t\t\tlayerResolver = new LayerResolver(this.resolvedDependencies, this.layered, this::isLibrary);\n\t\t}\n\t\tString jarmodeToolsLocation = isIncludeJarmodeTools() ? LIB_DIRECTORY : null;\n\t\treturn this.support.createCopyAction(this, this.resolvedDependencies, layerResolver, jarmodeToolsLocation);\n\t}\n\n\tprivate boolean isIncludeJarmodeTools() {\n\t\treturn Boolean.TRUE.equals(this.getIncludeTools().get());\n\t}\n\n\t@Override\n\tpublic void requiresUnpack(String... patterns) {\n\t\tthis.support.requiresUnpack(patterns);\n\t}\n\n\t@Override\n\tpublic void requiresUnpack(Spec<FileTreeElement> spec) {\n\t\tthis.support.requiresUnpack(spec);\n\t}\n\n\t/**\n\t * Returns the provided classpath, the contents of which will be included in the\n\t * {@code WEB-INF/lib-provided} directory of the war.\n\t * @return the provided classpath\n\t */\n\t@Optional\n\t@Classpath\n\tpublic @Nullable FileCollection getProvidedClasspath() {\n\t\treturn this.providedClasspath;\n\t}\n\n\t/**\n\t * Adds files to the provided classpath to include in the {@code WEB-INF/lib-provided}\n\t * directory of the war. The given {@code classpath} is evaluated as per\n\t * {@link Project#files(Object...)}.\n\t * @param classpath the additions to the classpath\n\t */\n\tpublic void providedClasspath(Object... classpath) {\n\t\tFileCollection existingClasspath = this.providedClasspath;\n\t\tthis.providedClasspath = getProject()\n\t\t\t.files((existingClasspath != null) ? existingClasspath : Collections.emptyList(), classpath);\n\t}\n\n\t/**\n\t * Sets the provided classpath to include in the {@code WEB-INF/lib-provided}\n\t * directory of the war.\n\t * @param classpath the classpath\n\t * @since 2.0.7\n\t */\n\tpublic void setProvidedClasspath(FileCollection classpath) {\n\t\tthis.providedClasspath = getProject().files(classpath);\n\t}\n\n\t/**\n\t * Sets the provided classpath to include in the {@code WEB-INF/lib-provided}\n\t * directory of the war. The given {@code classpath} is evaluated as per\n\t * {@link Project#files(Object...)}.\n\t * @param classpath the classpath\n\t * @since 2.0.7\n\t */\n\tpublic void setProvidedClasspath(Object classpath) {\n\t\tthis.providedClasspath = getProject().files(classpath);\n\t}\n\n\t/**\n\t * Return the {@link ZipCompression} that should be used when adding the file\n\t * represented by the given {@code details} to the jar. By default, any\n\t * {@link #isLibrary(FileCopyDetails) library} is {@link ZipCompression#STORED stored}\n\t * and all other files are {@link ZipCompression#DEFLATED deflated}.\n\t * @param details the file copy details\n\t * @return the compression to use\n\t */\n\tprotected ZipCompression resolveZipCompression(FileCopyDetails details) {\n\t\treturn isLibrary(details) ? ZipCompression.STORED : ZipCompression.DEFLATED;\n\t}\n\n\t/**\n\t * Returns the spec that describes the layers in a layered jar.\n\t * @return the spec for the layers\n\t * @since 2.5.0\n\t */\n\t@Nested\n\tpublic LayeredSpec getLayered() {\n\t\treturn this.layered;\n\t}\n\n\t/**\n\t * Configures the war's layering using the given {@code action}.\n\t * @param action the action to apply\n\t * @since 2.5.0\n\t */\n\tpublic void layered(Action<LayeredSpec> action) {\n\t\taction.execute(this.layered);\n\t}\n\n\t/**\n\t * Return if the {@link FileCopyDetails} are for a library. By default any file in\n\t * {@code WEB-INF/lib} or {@code WEB-INF/lib-provided} is considered to be a library.\n\t * @param details the file copy details\n\t * @return {@code true} if the details are for a library\n\t */\n\tprotected boolean isLibrary(FileCopyDetails details) {\n\t\tString path = details.getRelativePath().getPathString();\n\t\treturn path.startsWith(LIB_DIRECTORY) || path.startsWith(LIB_PROVIDED_DIRECTORY);\n\t}\n\n\t/**\n\t * Syntactic sugar that makes {@link CopySpec#into} calls a little easier to read.\n\t * @param <T> the result type\n\t * @param callable the callable\n\t * @return an action to add the callable to the spec\n\t */\n\tprivate static <T> Action<CopySpec> fromCallTo(Callable<T> callable) {\n\t\treturn (spec) -> spec.from(callTo(callable));\n\t}\n\n\t/**\n\t * Syntactic sugar that makes {@link CopySpec#from} calls a little easier to read.\n\t * @param <T> the result type\n\t * @param callable the callable\n\t * @return the callable\n\t */\n\tprivate static <T> Callable<T> callTo(Callable<T> callable) {\n\t\treturn callable;\n\t}\n\n\tprivate final class LibrarySpec implements Spec<FileCopyDetails> {\n\n\t\t@Override\n\t\tpublic boolean isSatisfiedBy(FileCopyDetails details) {\n\t\t\treturn isLibrary(details);\n\t\t}\n\n\t}\n\n\tprivate final class ZipCompressionResolver implements Function<FileCopyDetails, ZipCompression> {\n\n\t\t@Override\n\t\tpublic ZipCompression apply(FileCopyDetails details) {\n\t\t\treturn resolveZipCompression(details);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.regex.Pattern;\nimport java.util.zip.CRC32;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.commons.compress.archivers.zip.UnixStat;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.file.FileCopyDetails;\nimport org.gradle.api.file.FileTreeElement;\nimport org.gradle.api.internal.file.copy.CopyAction;\nimport org.gradle.api.internal.file.copy.CopyActionProcessingStream;\nimport org.gradle.api.java.archives.Attributes;\nimport org.gradle.api.java.archives.Manifest;\nimport org.gradle.api.specs.Spec;\nimport org.gradle.api.tasks.WorkResult;\nimport org.gradle.api.tasks.WorkResults;\nimport org.gradle.util.GradleVersion;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.gradle.tasks.bundling.ResolvedDependencies.DependencyDescriptor;\nimport org.springframework.boot.loader.tools.FileUtils;\nimport org.springframework.boot.loader.tools.JarModeLibrary;\nimport org.springframework.boot.loader.tools.Layer;\nimport org.springframework.boot.loader.tools.LayersIndex;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.boot.loader.tools.NativeImageArgFile;\nimport org.springframework.boot.loader.tools.ReachabilityMetadataProperties;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.ThrowingSupplier;\n\n/**\n * A {@link CopyAction} for creating a Spring Boot zip archive (typically a jar or war).\n * Stores jar files without compression as required by Spring Boot's loader.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass BootZipCopyAction implements CopyAction {\n\n\tstatic final long CONSTANT_TIME_FOR_ZIP_ENTRIES = OffsetDateTime.of(1980, 2, 1, 0, 0, 0, 0, ZoneOffset.UTC)\n\t\t.toInstant()\n\t\t.toEpochMilli();\n\n\tprivate static final Pattern REACHABILITY_METADATA_PROPERTIES_LOCATION_PATTERN = Pattern\n\t\t.compile(ReachabilityMetadataProperties.REACHABILITY_METADATA_PROPERTIES_LOCATION_TEMPLATE.formatted(\".*\", \".*\",\n\t\t\t\t\".*\"));\n\n\tprivate final File output;\n\n\tprivate final Manifest manifest;\n\n\tprivate final boolean preserveFileTimestamps;\n\n\tprivate final @Nullable Integer dirMode;\n\n\tprivate final @Nullable Integer fileMode;\n\n\tprivate final boolean includeDefaultLoader;\n\n\tprivate final @Nullable String jarmodeToolsLocation;\n\n\tprivate final Spec<FileTreeElement> requiresUnpack;\n\n\tprivate final Spec<FileTreeElement> exclusions;\n\n\tprivate final Spec<FileCopyDetails> librarySpec;\n\n\tprivate final Function<FileCopyDetails, ZipCompression> compressionResolver;\n\n\tprivate final @Nullable String encoding;\n\n\tprivate final ResolvedDependencies resolvedDependencies;\n\n\tprivate final @Nullable LayerResolver layerResolver;\n\n\tBootZipCopyAction(File output, Manifest manifest, boolean preserveFileTimestamps, @Nullable Integer dirMode,\n\t\t\t@Nullable Integer fileMode, boolean includeDefaultLoader, @Nullable String jarmodeToolsLocation,\n\t\t\tSpec<FileTreeElement> requiresUnpack, Spec<FileTreeElement> exclusions, Spec<FileCopyDetails> librarySpec,\n\t\t\tFunction<FileCopyDetails, ZipCompression> compressionResolver, @Nullable String encoding,\n\t\t\tResolvedDependencies resolvedDependencies, @Nullable LayerResolver layerResolver) {\n\t\tthis.output = output;\n\t\tthis.manifest = manifest;\n\t\tthis.preserveFileTimestamps = preserveFileTimestamps;\n\t\tthis.dirMode = dirMode;\n\t\tthis.fileMode = fileMode;\n\t\tthis.includeDefaultLoader = includeDefaultLoader;\n\t\tthis.jarmodeToolsLocation = jarmodeToolsLocation;\n\t\tthis.requiresUnpack = requiresUnpack;\n\t\tthis.exclusions = exclusions;\n\t\tthis.librarySpec = librarySpec;\n\t\tthis.compressionResolver = compressionResolver;\n\t\tthis.encoding = encoding;\n\t\tthis.resolvedDependencies = resolvedDependencies;\n\t\tthis.layerResolver = layerResolver;\n\t}\n\n\t@Override\n\tpublic WorkResult execute(CopyActionProcessingStream copyActions) {\n\t\ttry {\n\t\t\twriteArchive(copyActions);\n\t\t\treturn WorkResults.didWork(true);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new GradleException(\"Failed to create \" + this.output, ex);\n\t\t}\n\t}\n\n\tprivate void writeArchive(CopyActionProcessingStream copyActions) throws IOException {\n\t\tOutputStream output = new FileOutputStream(this.output);\n\t\ttry {\n\t\t\twriteArchive(copyActions, output);\n\t\t}\n\t\tfinally {\n\t\t\tcloseQuietly(output);\n\t\t}\n\t}\n\n\tprivate void writeArchive(CopyActionProcessingStream copyActions, OutputStream output) throws IOException {\n\t\tZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(output);\n\t\ttry {\n\t\t\tsetEncodingIfNecessary(zipOutput);\n\t\t\tProcessor processor = new Processor(zipOutput);\n\t\t\tcopyActions.process(processor::process);\n\t\t\tprocessor.finish();\n\t\t}\n\t\tfinally {\n\t\t\tcloseQuietly(zipOutput);\n\t\t}\n\t}\n\n\tprivate void setEncodingIfNecessary(ZipArchiveOutputStream zipOutputStream) {\n\t\tif (this.encoding != null) {\n\t\t\tzipOutputStream.setEncoding(this.encoding);\n\t\t}\n\t}\n\n\tprivate void closeQuietly(OutputStream outputStream) {\n\t\ttry {\n\t\t\toutputStream.close();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t/**\n\t * Internal process used to copy {@link FileCopyDetails file details} to the zip file.\n\t */\n\tprivate class Processor {\n\n\t\tprivate final ZipArchiveOutputStream out;\n\n\t\tprivate final @Nullable LayersIndex layerIndex;\n\n\t\tprivate LoaderZipEntries.@Nullable WrittenEntries writtenLoaderEntries;\n\n\t\tprivate final Set<String> writtenDirectories = new LinkedHashSet<>();\n\n\t\tprivate final Map<String, FileCopyDetails> writtenLibraries = new LinkedHashMap<>();\n\n\t\tprivate final Map<String, FileCopyDetails> reachabilityMetadataProperties = new HashMap<>();\n\n\t\tProcessor(ZipArchiveOutputStream out) {\n\t\t\tthis.out = out;\n\t\t\tthis.layerIndex = (BootZipCopyAction.this.layerResolver != null)\n\t\t\t\t\t? new LayersIndex(BootZipCopyAction.this.layerResolver.getLayers()) : null;\n\t\t}\n\n\t\tvoid process(FileCopyDetails details) {\n\t\t\tif (skipProcessing(details)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\twriteLoaderEntriesIfNecessary(details);\n\t\t\t\tif (details.isDirectory()) {\n\t\t\t\t\tprocessDirectory(details);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tprocessFile(details);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new GradleException(\"Failed to add \" + details + \" to \" + BootZipCopyAction.this.output, ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean skipProcessing(FileCopyDetails details) {\n\t\t\treturn BootZipCopyAction.this.exclusions.isSatisfiedBy(details)\n\t\t\t\t\t|| (this.writtenLoaderEntries != null && this.writtenLoaderEntries.isWrittenDirectory(details));\n\t\t}\n\n\t\tprivate void processDirectory(FileCopyDetails details) throws IOException {\n\t\t\tString name = details.getRelativePath().getPathString();\n\t\t\tZipArchiveEntry entry = new ZipArchiveEntry(name + '/');\n\t\t\tprepareEntry(entry, name, getTime(details), getDirMode(details));\n\t\t\tthis.out.putArchiveEntry(entry);\n\t\t\tthis.out.closeArchiveEntry();\n\t\t\tthis.writtenDirectories.add(name);\n\t\t}\n\n\t\tprivate void processFile(FileCopyDetails details) throws IOException {\n\t\t\tString name = details.getRelativePath().getPathString();\n\t\t\tZipArchiveEntry entry = new ZipArchiveEntry(name);\n\t\t\tprepareEntry(entry, name, getTime(details), getFileMode(details));\n\t\t\tZipCompression compression = BootZipCopyAction.this.compressionResolver.apply(details);\n\t\t\tif (compression == ZipCompression.STORED) {\n\t\t\t\tprepareStoredEntry(details, entry);\n\t\t\t}\n\t\t\tthis.out.putArchiveEntry(entry);\n\t\t\tdetails.copyTo(this.out);\n\t\t\tthis.out.closeArchiveEntry();\n\t\t\tif (BootZipCopyAction.this.librarySpec.isSatisfiedBy(details)) {\n\t\t\t\tthis.writtenLibraries.put(name, details);\n\t\t\t}\n\t\t\tif (REACHABILITY_METADATA_PROPERTIES_LOCATION_PATTERN.matcher(name).matches()) {\n\t\t\t\tthis.reachabilityMetadataProperties.put(name, details);\n\t\t\t}\n\t\t\tif (BootZipCopyAction.this.layerResolver != null) {\n\t\t\t\tLayer layer = BootZipCopyAction.this.layerResolver.getLayer(details);\n\t\t\t\tAssert.state(this.layerIndex != null, \"'layerIndex' must not be null\");\n\t\t\t\tAssert.state(layer != null, \"'layer' must not be null\");\n\t\t\t\tthis.layerIndex.add(layer, name);\n\t\t\t}\n\t\t}\n\n\t\tprivate void writeParentDirectoriesIfNecessary(String name, @Nullable Long time) throws IOException {\n\t\t\tString parentDirectory = getParentDirectory(name);\n\t\t\tif (parentDirectory != null && this.writtenDirectories.add(parentDirectory)) {\n\t\t\t\tZipArchiveEntry entry = new ZipArchiveEntry(parentDirectory + '/');\n\t\t\t\tprepareEntry(entry, parentDirectory, time, getDirMode());\n\t\t\t\tthis.out.putArchiveEntry(entry);\n\t\t\t\tthis.out.closeArchiveEntry();\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable String getParentDirectory(String name) {\n\t\t\tint lastSlash = name.lastIndexOf('/');\n\t\t\tif (lastSlash == -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn name.substring(0, lastSlash);\n\t\t}\n\n\t\tvoid finish() throws IOException {\n\t\t\twriteLoaderEntriesIfNecessary(null);\n\t\t\twriteJarToolsIfNecessary();\n\t\t\twriteSignatureFileIfNecessary();\n\t\t\twriteClassPathIndexIfNecessary();\n\t\t\twriteNativeImageArgFileIfNecessary();\n\t\t\t// We must write the layer index last\n\t\t\twriteLayersIndexIfNecessary();\n\t\t}\n\n\t\tprivate void writeLoaderEntriesIfNecessary(@Nullable FileCopyDetails details) throws IOException {\n\t\t\tif (!BootZipCopyAction.this.includeDefaultLoader || this.writtenLoaderEntries != null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (isInMetaInf(details)) {\n\t\t\t\t// Always write loader entries after META-INF directory (see gh-16698)\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tLoaderZipEntries loaderEntries = new LoaderZipEntries(getTime(), getDirMode(), getFileMode());\n\t\t\tthis.writtenLoaderEntries = loaderEntries.writeTo(this.out);\n\t\t\tif (BootZipCopyAction.this.layerResolver != null) {\n\t\t\t\tfor (String name : this.writtenLoaderEntries.getFiles()) {\n\t\t\t\t\tLayer layer = BootZipCopyAction.this.layerResolver.getLayer(name);\n\t\t\t\t\tAssert.state(this.layerIndex != null, \"'layerIndex' must not be null\");\n\t\t\t\t\tthis.layerIndex.add(layer, name);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isInMetaInf(@Nullable FileCopyDetails details) {\n\t\t\tif (details == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tString[] segments = details.getRelativePath().getSegments();\n\t\t\treturn segments.length > 0 && \"META-INF\".equals(segments[0]);\n\t\t}\n\n\t\tprivate void writeJarToolsIfNecessary() throws IOException {\n\t\t\tif (BootZipCopyAction.this.jarmodeToolsLocation != null) {\n\t\t\t\twriteJarModeLibrary(BootZipCopyAction.this.jarmodeToolsLocation, JarModeLibrary.TOOLS);\n\t\t\t}\n\t\t}\n\n\t\tprivate void writeJarModeLibrary(String location, JarModeLibrary library) throws IOException {\n\t\t\tString name = location + library.getName();\n\t\t\twriteEntry(name, ZipEntryContentWriter.fromInputStream(library.openStream()), false,\n\t\t\t\t\t(entry) -> prepareStoredEntry(library::openStream, false, entry));\n\t\t\tif (BootZipCopyAction.this.layerResolver != null) {\n\t\t\t\tLayer layer = BootZipCopyAction.this.layerResolver.getLayer(library);\n\t\t\t\tAssert.state(this.layerIndex != null, \"'layerIndex' must not be null\");\n\t\t\t\tthis.layerIndex.add(layer, name);\n\t\t\t}\n\t\t}\n\n\t\tprivate void writeSignatureFileIfNecessary() throws IOException {\n\t\t\tif (hasSignedLibrary()) {\n\t\t\t\twriteEntry(\"META-INF/BOOT.SF\", (out) -> {\n\t\t\t\t}, false);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean hasSignedLibrary() throws IOException {\n\t\t\tfor (FileCopyDetails writtenLibrary : this.writtenLibraries.values()) {\n\t\t\t\tif (FileUtils.isSignedJarFile(writtenLibrary.getFile())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void writeClassPathIndexIfNecessary() throws IOException {\n\t\t\tAttributes manifestAttributes = BootZipCopyAction.this.manifest.getAttributes();\n\t\t\tString classPathIndex = (String) manifestAttributes.get(\"Spring-Boot-Classpath-Index\");\n\t\t\tif (classPathIndex != null) {\n\t\t\t\tSet<String> libraryNames = this.writtenLibraries.keySet();\n\t\t\t\tList<String> lines = libraryNames.stream().map((line) -> \"- \\\"\" + line + \"\\\"\").toList();\n\t\t\t\tZipEntryContentWriter writer = ZipEntryContentWriter.fromLines((BootZipCopyAction.this.encoding != null)\n\t\t\t\t\t\t? BootZipCopyAction.this.encoding : StandardCharsets.UTF_8.name(), lines);\n\t\t\t\twriteEntry(classPathIndex, writer, true);\n\t\t\t}\n\t\t}\n\n\t\tprivate void writeNativeImageArgFileIfNecessary() throws IOException {\n\t\t\tSet<String> excludes = new LinkedHashSet<>();\n\t\t\tfor (Map.Entry<String, FileCopyDetails> entry : this.writtenLibraries.entrySet()) {\n\t\t\t\tDependencyDescriptor descriptor = BootZipCopyAction.this.resolvedDependencies\n\t\t\t\t\t.find(entry.getValue().getFile());\n\t\t\t\tLibraryCoordinates coordinates = (descriptor != null) ? descriptor.getCoordinates() : null;\n\t\t\t\tFileCopyDetails propertiesFile = (coordinates != null) ? this.reachabilityMetadataProperties\n\t\t\t\t\t.get(ReachabilityMetadataProperties.getLocation(coordinates)) : null;\n\t\t\t\tif (propertiesFile != null) {\n\t\t\t\t\ttry (InputStream inputStream = propertiesFile.open()) {\n\t\t\t\t\t\tReachabilityMetadataProperties properties = ReachabilityMetadataProperties\n\t\t\t\t\t\t\t.fromInputStream(inputStream);\n\t\t\t\t\t\tif (properties.isOverridden()) {\n\t\t\t\t\t\t\texcludes.add(entry.getKey());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tNativeImageArgFile argFile = new NativeImageArgFile(excludes);\n\t\t\targFile.writeIfNecessary((lines) -> {\n\t\t\t\tZipEntryContentWriter writer = ZipEntryContentWriter.fromLines((BootZipCopyAction.this.encoding != null)\n\t\t\t\t\t\t? BootZipCopyAction.this.encoding : StandardCharsets.UTF_8.name(), lines);\n\t\t\t\twriteEntry(NativeImageArgFile.LOCATION, writer, true);\n\t\t\t});\n\t\t}\n\n\t\tprivate void writeLayersIndexIfNecessary() throws IOException {\n\t\t\tif (BootZipCopyAction.this.layerResolver != null) {\n\t\t\t\tAttributes manifestAttributes = BootZipCopyAction.this.manifest.getAttributes();\n\t\t\t\tString name = (String) manifestAttributes.get(\"Spring-Boot-Layers-Index\");\n\t\t\t\tAssert.state(StringUtils.hasText(name), \"Missing layer index manifest attribute\");\n\t\t\t\tLayer layer = BootZipCopyAction.this.layerResolver.getLayer(name);\n\t\t\t\tAssert.state(this.layerIndex != null, \"'layerIndex' must not be null\");\n\t\t\t\tthis.layerIndex.add(layer, name);\n\t\t\t\twriteEntry(name, this.layerIndex::writeTo, false);\n\t\t\t}\n\t\t}\n\n\t\tprivate void writeEntry(String name, ZipEntryContentWriter entryWriter, boolean addToLayerIndex)\n\t\t\t\tthrows IOException {\n\t\t\twriteEntry(name, entryWriter, addToLayerIndex, ZipEntryCustomizer.NONE);\n\t\t}\n\n\t\tprivate void writeEntry(String name, ZipEntryContentWriter entryWriter, boolean addToLayerIndex,\n\t\t\t\tZipEntryCustomizer entryCustomizer) throws IOException {\n\t\t\tZipArchiveEntry entry = new ZipArchiveEntry(name);\n\t\t\tprepareEntry(entry, name, getTime(), getFileMode());\n\t\t\tentryCustomizer.customize(entry);\n\t\t\tthis.out.putArchiveEntry(entry);\n\t\t\tentryWriter.writeTo(this.out);\n\t\t\tthis.out.closeArchiveEntry();\n\t\t\tif (addToLayerIndex && BootZipCopyAction.this.layerResolver != null) {\n\t\t\t\tLayer layer = BootZipCopyAction.this.layerResolver.getLayer(name);\n\t\t\t\tAssert.state(this.layerIndex != null, \"'layerIndex' must not be null\");\n\t\t\t\tthis.layerIndex.add(layer, name);\n\t\t\t}\n\t\t}\n\n\t\tprivate void prepareEntry(ZipArchiveEntry entry, String name, @Nullable Long time, int mode)\n\t\t\t\tthrows IOException {\n\t\t\twriteParentDirectoriesIfNecessary(name, time);\n\t\t\tentry.setUnixMode(mode);\n\t\t\tif (time != null) {\n\t\t\t\tentry.setTime(DefaultTimeZoneOffset.INSTANCE.removeFrom(time));\n\t\t\t}\n\t\t}\n\n\t\tprivate void prepareStoredEntry(FileCopyDetails details, ZipArchiveEntry archiveEntry) throws IOException {\n\t\t\tprepareStoredEntry(details::open, BootZipCopyAction.this.requiresUnpack.isSatisfiedBy(details),\n\t\t\t\t\tarchiveEntry);\n\t\t}\n\n\t\tprivate void prepareStoredEntry(ThrowingSupplier<InputStream> input, boolean unpack,\n\t\t\t\tZipArchiveEntry archiveEntry) throws IOException {\n\t\t\tnew StoredEntryPreparator(input, unpack).prepareStoredEntry(archiveEntry);\n\t\t}\n\n\t\tprivate @Nullable Long getTime() {\n\t\t\treturn getTime(null);\n\t\t}\n\n\t\tprivate @Nullable Long getTime(@Nullable FileCopyDetails details) {\n\t\t\tif (!BootZipCopyAction.this.preserveFileTimestamps) {\n\t\t\t\treturn CONSTANT_TIME_FOR_ZIP_ENTRIES;\n\t\t\t}\n\t\t\tif (details != null) {\n\t\t\t\treturn details.getLastModified();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate int getDirMode() {\n\t\t\treturn (BootZipCopyAction.this.dirMode != null) ? BootZipCopyAction.this.dirMode\n\t\t\t\t\t: UnixStat.DEFAULT_DIR_PERM;\n\t\t}\n\n\t\tprivate int getFileMode() {\n\t\t\treturn (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode\n\t\t\t\t\t: UnixStat.DEFAULT_FILE_PERM;\n\t\t}\n\n\t\tprivate int getDirMode(FileCopyDetails details) {\n\t\t\treturn (BootZipCopyAction.this.dirMode != null) ? BootZipCopyAction.this.dirMode : getPermissions(details);\n\t\t}\n\n\t\tprivate int getFileMode(FileCopyDetails details) {\n\t\t\treturn (BootZipCopyAction.this.fileMode != null) ? BootZipCopyAction.this.fileMode\n\t\t\t\t\t: getPermissions(details);\n\t\t}\n\n\t\tprivate int getPermissions(FileCopyDetails details) {\n\t\t\treturn (GradleVersion.current().compareTo(GradleVersion.version(\"8.3\")) >= 0)\n\t\t\t\t\t? details.getPermissions().toUnixNumeric() : getMode(details);\n\t\t}\n\n\t\tprivate int getMode(FileCopyDetails details) {\n\t\t\ttry {\n\t\t\t\treturn (int) details.getClass().getMethod(\"getMode\").invoke(details);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(\"Failed to get mode from FileCopyDetails\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Callback interface used to customize a {@link ZipArchiveEntry}.\n\t */\n\t@FunctionalInterface\n\tprivate interface ZipEntryCustomizer {\n\n\t\tZipEntryCustomizer NONE = (entry) -> {\n\t\t};\n\n\t\t/**\n\t\t * Customize the entry.\n\t\t * @param entry the entry to customize\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tvoid customize(ZipArchiveEntry entry) throws IOException;\n\n\t}\n\n\t/**\n\t * Callback used to write a zip entry data.\n\t */\n\t@FunctionalInterface\n\tprivate interface ZipEntryContentWriter {\n\n\t\t/**\n\t\t * Write the entry data.\n\t\t * @param out the output stream used to write the data\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tvoid writeTo(ZipArchiveOutputStream out) throws IOException;\n\n\t\t/**\n\t\t * Create a new {@link ZipEntryContentWriter} that will copy content from the\n\t\t * given {@link InputStream}.\n\t\t * @param in the source input stream\n\t\t * @return a new {@link ZipEntryContentWriter} instance\n\t\t */\n\t\tstatic ZipEntryContentWriter fromInputStream(InputStream in) {\n\t\t\treturn (out) -> {\n\t\t\t\tStreamUtils.copy(in, out);\n\t\t\t\tin.close();\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link ZipEntryContentWriter} that will copy content from the\n\t\t * given lines.\n\t\t * @param encoding the required character encoding\n\t\t * @param lines the lines to write\n\t\t * @return a new {@link ZipEntryContentWriter} instance\n\t\t */\n\t\tstatic ZipEntryContentWriter fromLines(String encoding, Collection<String> lines) {\n\t\t\treturn (out) -> {\n\t\t\t\tOutputStreamWriter writer = new OutputStreamWriter(out, encoding);\n\t\t\t\tfor (String line : lines) {\n\t\t\t\t\twriter.append(line).append(\"\\n\");\n\t\t\t\t}\n\t\t\t\twriter.flush();\n\t\t\t};\n\t\t}\n\n\t}\n\n\t/**\n\t * Prepares a {@link ZipEntry#STORED stored} {@link ZipArchiveEntry entry} with CRC\n\t * and size information. Also adds an {@code UNPACK} comment, if needed.\n\t */\n\tprivate static class StoredEntryPreparator {\n\n\t\tprivate static final int BUFFER_SIZE = 32 * 1024;\n\n\t\tprivate final boolean unpack;\n\n\t\tprivate final CRC32 crc = new CRC32();\n\n\t\tprivate long size;\n\n\t\tStoredEntryPreparator(ThrowingSupplier<InputStream> input, boolean unpack) throws IOException {\n\t\t\tthis.unpack = unpack;\n\t\t\ttry (InputStream stream = input.get()) {\n\t\t\t\tload(stream);\n\t\t\t}\n\t\t}\n\n\t\tprivate void load(InputStream inputStream) throws IOException {\n\t\t\tbyte[] buffer = new byte[BUFFER_SIZE];\n\t\t\tint bytesRead;\n\t\t\twhile ((bytesRead = inputStream.read(buffer)) != -1) {\n\t\t\t\tthis.crc.update(buffer, 0, bytesRead);\n\t\t\t\tthis.size += bytesRead;\n\t\t\t}\n\t\t}\n\n\t\tvoid prepareStoredEntry(ZipArchiveEntry entry) {\n\t\t\tentry.setSize(this.size);\n\t\t\tentry.setCompressedSize(this.size);\n\t\t\tentry.setCrc(this.crc.getValue());\n\t\t\tentry.setMethod(ZipEntry.STORED);\n\t\t\tif (this.unpack) {\n\t\t\t\tentry.setComment(\"UNPACK\");\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/CacheSpec.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.Cache;\n\n/**\n * Configuration for an image building cache.\n *\n * @author Scott Frederick\n * @since 2.6.0\n */\npublic class CacheSpec {\n\n\tprivate final ObjectFactory objectFactory;\n\n\tprivate @Nullable Cache cache;\n\n\t@Inject\n\tpublic CacheSpec(ObjectFactory objectFactory) {\n\t\tthis.objectFactory = objectFactory;\n\t}\n\n\tpublic @Nullable Cache asCache() {\n\t\treturn this.cache;\n\t}\n\n\t/**\n\t * Configures a volume cache using the given {@code action}.\n\t * @param action the action\n\t */\n\tpublic void volume(Action<VolumeCacheSpec> action) {\n\t\tif (this.cache != null) {\n\t\t\tthrow new GradleException(\"Each image building cache can be configured only once\");\n\t\t}\n\t\tVolumeCacheSpec spec = this.objectFactory.newInstance(VolumeCacheSpec.class);\n\t\taction.execute(spec);\n\t\tthis.cache = Cache.volume(spec.getName().get());\n\t}\n\n\t/**\n\t * Configures a bind cache using the given {@code action}.\n\t * @param action the action\n\t */\n\tpublic void bind(Action<BindCacheSpec> action) {\n\t\tif (this.cache != null) {\n\t\t\tthrow new GradleException(\"Each image building cache can be configured only once\");\n\t\t}\n\t\tBindCacheSpec spec = this.objectFactory.newInstance(BindCacheSpec.class);\n\t\taction.execute(spec);\n\t\tthis.cache = Cache.bind(spec.getSource().get());\n\t}\n\n\t/**\n\t * Configuration for an image building cache stored in a Docker volume.\n\t */\n\tpublic abstract static class VolumeCacheSpec {\n\n\t\t/**\n\t\t * Returns the name of the cache.\n\t\t * @return the cache name\n\t\t */\n\t\t@Input\n\t\tpublic abstract Property<String> getName();\n\n\t}\n\n\t/**\n\t * Configuration for an image building cache stored in a bind mount.\n\t */\n\tpublic abstract static class BindCacheSpec {\n\n\t\t/**\n\t\t * Returns the source of the cache.\n\t\t * @return the cache source\n\t\t */\n\t\t@Input\n\t\tpublic abstract Property<String> getSource();\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DefaultTimeZoneOffset.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.nio.file.attribute.FileTime;\nimport java.util.TimeZone;\nimport java.util.zip.ZipEntry;\n\n/**\n * Utility class that can be used to change a UTC time based on the\n * {@link java.util.TimeZone#getDefault() default TimeZone}. This is required because\n * {@link ZipEntry#setTime(long)} expects times in the default timezone and not UTC.\n *\n * @author Phillip Webb\n */\nclass DefaultTimeZoneOffset {\n\n\tstatic final DefaultTimeZoneOffset INSTANCE = new DefaultTimeZoneOffset(TimeZone.getDefault());\n\n\tprivate final TimeZone defaultTimeZone;\n\n\tDefaultTimeZoneOffset(TimeZone defaultTimeZone) {\n\t\tthis.defaultTimeZone = defaultTimeZone;\n\t}\n\n\t/**\n\t * Remove the default offset from the given time.\n\t * @param time the time to remove the default offset from\n\t * @return the time with the default offset removed\n\t */\n\tFileTime removeFrom(FileTime time) {\n\t\treturn FileTime.fromMillis(removeFrom(time.toMillis()));\n\t}\n\n\t/**\n\t * Remove the default offset from the given time.\n\t * @param time the time to remove the default offset from\n\t * @return the time with the default offset removed\n\t */\n\tlong removeFrom(long time) {\n\t\treturn time - this.defaultTimeZone.getOffset(time);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/DockerSpec.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Nested;\nimport org.gradle.api.tasks.Optional;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\n\n/**\n * Encapsulates Docker configuration options.\n *\n * @author Wei Jiang\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic abstract class DockerSpec {\n\n\tprivate final DockerRegistrySpec builderRegistry;\n\n\tprivate final DockerRegistrySpec publishRegistry;\n\n\t@Inject\n\tpublic DockerSpec(ObjectFactory objects) {\n\t\tthis.builderRegistry = objects.newInstance(DockerRegistrySpec.class);\n\t\tthis.publishRegistry = objects.newInstance(DockerRegistrySpec.class);\n\t\tgetBindHostToBuilder().convention(false);\n\t\tgetTlsVerify().convention(false);\n\t}\n\n\tDockerSpec(DockerRegistrySpec builderRegistry, DockerRegistrySpec publishRegistry) {\n\t\tthis.builderRegistry = builderRegistry;\n\t\tthis.publishRegistry = publishRegistry;\n\t}\n\n\t@Input\n\t@Optional\n\tpublic abstract Property<String> getContext();\n\n\t@Input\n\t@Optional\n\tpublic abstract Property<String> getHost();\n\n\t@Input\n\t@Optional\n\tpublic abstract Property<Boolean> getTlsVerify();\n\n\t@Input\n\t@Optional\n\tpublic abstract Property<String> getCertPath();\n\n\t@Input\n\t@Optional\n\tpublic abstract Property<Boolean> getBindHostToBuilder();\n\n\t/**\n\t * Returns the {@link DockerRegistrySpec} that configures authentication to the\n\t * builder registry.\n\t * @return the registry spec\n\t */\n\t@Nested\n\tpublic DockerRegistrySpec getBuilderRegistry() {\n\t\treturn this.builderRegistry;\n\t}\n\n\t/**\n\t * Customizes the {@link DockerRegistrySpec} that configures authentication to the\n\t * builder registry.\n\t * @param action the action to apply\n\t */\n\tpublic void builderRegistry(Action<DockerRegistrySpec> action) {\n\t\taction.execute(this.builderRegistry);\n\t}\n\n\t/**\n\t * Returns the {@link DockerRegistrySpec} that configures authentication to the\n\t * publishing registry.\n\t * @return the registry spec\n\t */\n\t@Nested\n\tpublic DockerRegistrySpec getPublishRegistry() {\n\t\treturn this.publishRegistry;\n\t}\n\n\t/**\n\t * Customizes the {@link DockerRegistrySpec} that configures authentication to the\n\t * publishing registry.\n\t * @param action the action to apply\n\t */\n\tpublic void publishRegistry(Action<DockerRegistrySpec> action) {\n\t\taction.execute(this.publishRegistry);\n\t}\n\n\t/**\n\t * Returns this configuration as a {@link BuilderDockerConfiguration} instance. This\n\t * method should only be called when the configuration is complete and will no longer\n\t * be changed.\n\t * @return the Docker configuration\n\t */\n\tBuilderDockerConfiguration asDockerConfiguration() {\n\t\tBuilderDockerConfiguration dockerConfiguration = new BuilderDockerConfiguration();\n\t\tdockerConfiguration = customizeHost(dockerConfiguration);\n\t\tdockerConfiguration = dockerConfiguration.withBindHostToBuilder(getBindHostToBuilder().get());\n\t\tdockerConfiguration = customizeBuilderAuthentication(dockerConfiguration);\n\t\tdockerConfiguration = customizePublishAuthentication(dockerConfiguration);\n\t\treturn dockerConfiguration;\n\t}\n\n\tprivate BuilderDockerConfiguration customizeHost(BuilderDockerConfiguration dockerConfiguration) {\n\t\tString context = getContext().getOrNull();\n\t\tString host = getHost().getOrNull();\n\t\tif (context != null && host != null) {\n\t\t\tthrow new GradleException(\n\t\t\t\t\t\"Invalid Docker configuration, either context or host can be provided but not both\");\n\t\t}\n\t\tif (context != null) {\n\t\t\treturn dockerConfiguration.withContext(context);\n\t\t}\n\t\tif (host != null) {\n\t\t\treturn dockerConfiguration.withHost(host, getTlsVerify().get(), getCertPath().getOrNull());\n\t\t}\n\t\treturn dockerConfiguration;\n\t}\n\n\tprivate BuilderDockerConfiguration customizeBuilderAuthentication(BuilderDockerConfiguration dockerConfiguration) {\n\t\treturn dockerConfiguration.withBuilderRegistryAuthentication(getRegistryAuthentication(\"builder\",\n\t\t\t\tthis.builderRegistry, DockerRegistryAuthentication.configuration(null)));\n\t}\n\n\tprivate BuilderDockerConfiguration customizePublishAuthentication(BuilderDockerConfiguration dockerConfiguration) {\n\t\treturn dockerConfiguration\n\t\t\t.withPublishRegistryAuthentication(getRegistryAuthentication(\"publish\", this.publishRegistry,\n\t\t\t\t\tDockerRegistryAuthentication.configuration(DockerRegistryAuthentication.EMPTY_USER)));\n\t}\n\n\tprivate DockerRegistryAuthentication getRegistryAuthentication(String type, @Nullable DockerRegistrySpec registry,\n\t\t\tDockerRegistryAuthentication fallback) {\n\t\tif (registry == null || registry.hasEmptyAuth()) {\n\t\t\treturn fallback;\n\t\t}\n\t\tif (registry.hasTokenAuth() && !registry.hasUserAuth()) {\n\t\t\treturn DockerRegistryAuthentication.token(registry.getToken().get());\n\t\t}\n\t\tif (registry.hasUserAuth() && !registry.hasTokenAuth()) {\n\t\t\treturn DockerRegistryAuthentication.user(registry.getUsername().get(), registry.getPassword().get(),\n\t\t\t\t\tregistry.getUrl().getOrNull(), registry.getEmail().getOrNull());\n\t\t}\n\t\tthrow new GradleException(\"Invalid Docker \" + type\n\t\t\t\t+ \" registry configuration, either token or username/password must be provided\");\n\t}\n\n\t/**\n\t * Encapsulates Docker registry authentication configuration options.\n\t */\n\tpublic abstract static class DockerRegistrySpec {\n\n\t\t/**\n\t\t * Returns the username to use when authenticating to the Docker registry.\n\t\t * @return the registry username\n\t\t */\n\t\t@Input\n\t\t@Optional\n\t\tpublic abstract Property<String> getUsername();\n\n\t\t/**\n\t\t * Returns the password to use when authenticating to the Docker registry.\n\t\t * @return the registry password\n\t\t */\n\t\t@Input\n\t\t@Optional\n\t\tpublic abstract Property<String> getPassword();\n\n\t\t/**\n\t\t * Returns the Docker registry URL.\n\t\t * @return the registry URL\n\t\t */\n\t\t@Input\n\t\t@Optional\n\t\tpublic abstract Property<String> getUrl();\n\n\t\t/**\n\t\t * Returns the email address associated with the Docker registry username.\n\t\t * @return the registry email address\n\t\t */\n\t\t@Input\n\t\t@Optional\n\t\tpublic abstract Property<String> getEmail();\n\n\t\t/**\n\t\t * Returns the identity token to use when authenticating to the Docker registry.\n\t\t * @return the registry identity token\n\t\t */\n\t\t@Input\n\t\t@Optional\n\t\tpublic abstract Property<String> getToken();\n\n\t\tboolean hasEmptyAuth() {\n\t\t\treturn nonePresent(getUsername(), getPassword(), getUrl(), getEmail(), getToken());\n\t\t}\n\n\t\tprivate boolean nonePresent(Property<?>... properties) {\n\t\t\tfor (Property<?> property : properties) {\n\t\t\t\tif (property.isPresent()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tboolean hasUserAuth() {\n\t\t\treturn allPresent(getUsername(), getPassword());\n\t\t}\n\n\t\tprivate boolean allPresent(Property<?>... properties) {\n\t\t\tfor (Property<?> property : properties) {\n\t\t\t\tif (!property.isPresent()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tboolean hasTokenAuth() {\n\t\t\treturn getToken().isPresent();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LayerResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\n\nimport org.gradle.api.file.FileCopyDetails;\nimport org.gradle.api.specs.Spec;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.gradle.tasks.bundling.ResolvedDependencies.DependencyDescriptor;\nimport org.springframework.boot.loader.tools.Layer;\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\n\n/**\n * Resolver backed by a {@link LayeredSpec} that provides the destination {@link Layer}\n * for each copied {@link FileCopyDetails}.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Paddy Drury\n * @see BootZipCopyAction\n */\nclass LayerResolver {\n\n\tprivate final ResolvedDependencies resolvedDependencies;\n\n\tprivate final LayeredSpec layeredConfiguration;\n\n\tprivate final Spec<FileCopyDetails> librarySpec;\n\n\tLayerResolver(ResolvedDependencies resolvedDependencies, LayeredSpec layeredConfiguration,\n\t\t\tSpec<FileCopyDetails> librarySpec) {\n\t\tthis.resolvedDependencies = resolvedDependencies;\n\t\tthis.layeredConfiguration = layeredConfiguration;\n\t\tthis.librarySpec = librarySpec;\n\t}\n\n\t@Nullable Layer getLayer(FileCopyDetails details) {\n\t\ttry {\n\t\t\tif (this.librarySpec.isSatisfiedBy(details)) {\n\t\t\t\treturn getLayer(asLibrary(details));\n\t\t\t}\n\t\t\treturn getLayer(details.getSourcePath());\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tLayer getLayer(Library library) {\n\t\treturn this.layeredConfiguration.asLayers().getLayer(library);\n\t}\n\n\tLayer getLayer(String applicationResource) {\n\t\treturn this.layeredConfiguration.asLayers().getLayer(applicationResource);\n\t}\n\n\tIterable<Layer> getLayers() {\n\t\treturn this.layeredConfiguration.asLayers();\n\t}\n\n\tprivate Library asLibrary(FileCopyDetails details) {\n\t\tFile file = details.getFile();\n\t\tDependencyDescriptor dependency = this.resolvedDependencies.find(file);\n\t\tif (dependency == null) {\n\t\t\treturn new Library(null, file, null, null, false, false, true);\n\t\t}\n\t\tLibraryCoordinates coordinates = dependency.getCoordinates();\n\t\tboolean projectDependency = dependency.isProjectDependency();\n\t\treturn new Library(null, file, null, coordinates, false, projectDependency, true);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LayeredSpec.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Optional;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.Layer;\nimport org.springframework.boot.loader.tools.Layers;\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.layer.ApplicationContentFilter;\nimport org.springframework.boot.loader.tools.layer.ContentFilter;\nimport org.springframework.boot.loader.tools.layer.ContentSelector;\nimport org.springframework.boot.loader.tools.layer.CustomLayers;\nimport org.springframework.boot.loader.tools.layer.IncludeExcludeContentSelector;\nimport org.springframework.boot.loader.tools.layer.LibraryContentFilter;\nimport org.springframework.util.Assert;\n\n/**\n * Encapsulates the configuration for a layered archive.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic abstract class LayeredSpec {\n\n\tprivate ApplicationSpec application;\n\n\tprivate DependenciesSpec dependencies;\n\n\tprivate @Nullable Layers layers;\n\n\t@Inject\n\tpublic LayeredSpec(ObjectFactory objects) {\n\t\tthis.application = objects.newInstance(ApplicationSpec.class);\n\t\tthis.dependencies = objects.newInstance(DependenciesSpec.class);\n\t\tgetEnabled().convention(true);\n\t}\n\n\t/**\n\t * Returns whether the layers.idx should be included in the archive.\n\t * @return whether the layers.idx should be included\n\t * @since 3.0.0\n\t */\n\t@Input\n\tpublic abstract Property<Boolean> getEnabled();\n\n\t/**\n\t * Returns the {@link ApplicationSpec} that controls the layers to which application\n\t * classes and resources belong.\n\t * @return the application spec\n\t */\n\t@Input\n\tpublic ApplicationSpec getApplication() {\n\t\treturn this.application;\n\t}\n\n\t/**\n\t * Sets the {@link ApplicationSpec} that controls the layers to which application\n\t * classes are resources belong.\n\t * @param spec the application spec\n\t */\n\tpublic void setApplication(ApplicationSpec spec) {\n\t\tthis.application = spec;\n\t}\n\n\t/**\n\t * Customizes the {@link ApplicationSpec} using the given {@code action}.\n\t * @param action the action\n\t */\n\tpublic void application(Action<ApplicationSpec> action) {\n\t\taction.execute(this.application);\n\t}\n\n\t/**\n\t * Returns the {@link DependenciesSpec} that controls the layers to which dependencies\n\t * belong.\n\t * @return the dependencies spec\n\t */\n\t@Input\n\tpublic DependenciesSpec getDependencies() {\n\t\treturn this.dependencies;\n\t}\n\n\t/**\n\t * Sets the {@link DependenciesSpec} that controls the layers to which dependencies\n\t * belong.\n\t * @param spec the dependencies spec\n\t */\n\tpublic void setDependencies(DependenciesSpec spec) {\n\t\tthis.dependencies = spec;\n\t}\n\n\t/**\n\t * Customizes the {@link DependenciesSpec} using the given {@code action}.\n\t * @param action the action\n\t */\n\tpublic void dependencies(Action<DependenciesSpec> action) {\n\t\taction.execute(this.dependencies);\n\t}\n\n\t/**\n\t * Returns the order of the layers in the archive from least to most frequently\n\t * changing.\n\t * @return the layer order\n\t */\n\t@Input\n\t@Optional\n\tpublic abstract ListProperty<String> getLayerOrder();\n\n\t/**\n\t * Return this configuration as a {@link Layers} instance. This method should only be\n\t * called when the configuration is complete and will no longer be changed.\n\t * @return the layers\n\t */\n\tLayers asLayers() {\n\t\tif (this.layers == null) {\n\t\t\tthis.layers = createLayers();\n\t\t}\n\t\treturn this.layers;\n\t}\n\n\tprivate Layers createLayers() {\n\t\tList<String> layerOrder = getLayerOrder().getOrNull();\n\t\tif (layerOrder == null || layerOrder.isEmpty()) {\n\t\t\tAssert.state(this.application.isEmpty() && this.dependencies.isEmpty(),\n\t\t\t\t\t\"The 'layerOrder' must be defined when using custom layering\");\n\t\t\treturn Layers.IMPLICIT;\n\t\t}\n\t\tList<Layer> layers = layerOrder.stream().map(Layer::new).toList();\n\t\treturn new CustomLayers(layers, this.application.asSelectors(), this.dependencies.asSelectors());\n\t}\n\n\t/**\n\t * Base class for specs that control the layers to which a category of content should\n\t * belong.\n\t *\n\t * @param <S> the type of {@link IntoLayerSpec} used by this spec\n\t */\n\tpublic abstract static class IntoLayersSpec<S extends IntoLayerSpec> implements Serializable {\n\n\t\tprivate final List<IntoLayerSpec> intoLayers;\n\n\t\tprivate final Function<String, S> specFactory;\n\n\t\tboolean isEmpty() {\n\t\t\treturn this.intoLayers.isEmpty();\n\t\t}\n\n\t\tIntoLayersSpec(Function<String, S> specFactory, IntoLayerSpec... spec) {\n\t\t\tthis.intoLayers = new ArrayList<>(Arrays.asList(spec));\n\t\t\tthis.specFactory = specFactory;\n\t\t}\n\n\t\tpublic void intoLayer(String layer) {\n\t\t\tthis.intoLayers.add(this.specFactory.apply(layer));\n\t\t}\n\n\t\tpublic void intoLayer(String layer, Action<S> action) {\n\t\t\tS spec = this.specFactory.apply(layer);\n\t\t\taction.execute(spec);\n\t\t\tthis.intoLayers.add(spec);\n\t\t}\n\n\t\t<T> List<ContentSelector<T>> asSelectors(Function<IntoLayerSpec, ContentSelector<T>> selectorFactory) {\n\t\t\treturn this.intoLayers.stream().map(selectorFactory).toList();\n\t\t}\n\n\t}\n\n\t/**\n\t * Spec that controls the content that should be part of a particular layer.\n\t */\n\tpublic static class IntoLayerSpec implements Serializable {\n\n\t\tprivate final String intoLayer;\n\n\t\tprivate final List<String> includes = new ArrayList<>();\n\n\t\tprivate final List<String> excludes = new ArrayList<>();\n\n\t\t/**\n\t\t * Creates a new {@code IntoLayerSpec} that will control the content of the given\n\t\t * layer.\n\t\t * @param intoLayer the layer\n\t\t */\n\t\tpublic IntoLayerSpec(String intoLayer) {\n\t\t\tthis.intoLayer = intoLayer;\n\t\t}\n\n\t\t/**\n\t\t * Adds patterns that control the content that is included in the layer. If no\n\t\t * includes are specified then all content is included. If includes are specified\n\t\t * then content must match an inclusion and not match any exclusions to be\n\t\t * included.\n\t\t * @param patterns the patterns to be included\n\t\t */\n\t\tpublic void include(String... patterns) {\n\t\t\tthis.includes.addAll(Arrays.asList(patterns));\n\t\t}\n\n\t\t/**\n\t\t * Adds patterns that control the content that is excluded from the layer. If no\n\t\t * excludes a specified no content is excluded. If exclusions are specified then\n\t\t * any content that matches an exclusion will be excluded irrespective of whether\n\t\t * it matches an include.\n\t\t * @param patterns the patterns to be excluded\n\t\t */\n\t\tpublic void exclude(String... patterns) {\n\t\t\tthis.includes.addAll(Arrays.asList(patterns));\n\t\t}\n\n\t\t<T> ContentSelector<T> asSelector(Function<String, ContentFilter<T>> filterFactory) {\n\t\t\tLayer layer = new Layer(this.intoLayer);\n\t\t\treturn new IncludeExcludeContentSelector<>(layer, this.includes, this.excludes, filterFactory);\n\t\t}\n\n\t\tString getIntoLayer() {\n\t\t\treturn this.intoLayer;\n\t\t}\n\n\t\tList<String> getIncludes() {\n\t\t\treturn this.includes;\n\t\t}\n\n\t\tList<String> getExcludes() {\n\t\t\treturn this.excludes;\n\t\t}\n\n\t}\n\n\t/**\n\t * Spec that controls the dependencies that should be part of a particular layer.\n\t *\n\t * @since 2.4.0\n\t */\n\tpublic static class DependenciesIntoLayerSpec extends IntoLayerSpec {\n\n\t\tprivate boolean includeProjectDependencies;\n\n\t\tprivate boolean excludeProjectDependencies;\n\n\t\t/**\n\t\t * Creates a new {@code IntoLayerSpec} that will control the content of the given\n\t\t * layer.\n\t\t * @param intoLayer the layer\n\t\t */\n\t\tpublic DependenciesIntoLayerSpec(String intoLayer) {\n\t\t\tsuper(intoLayer);\n\t\t}\n\n\t\t/**\n\t\t * Configures the layer to include project dependencies. If no includes are\n\t\t * specified then all content is included. If includes are specified then content\n\t\t * must match an inclusion and not match any exclusions to be included.\n\t\t */\n\t\tpublic void includeProjectDependencies() {\n\t\t\tthis.includeProjectDependencies = true;\n\t\t}\n\n\t\t/**\n\t\t * Configures the layer to exclude project dependencies. If no excludes a\n\t\t * specified no content is excluded. If exclusions are specified then any content\n\t\t * that matches an exclusion will be excluded irrespective of whether it matches\n\t\t * an include.\n\t\t */\n\t\tpublic void excludeProjectDependencies() {\n\t\t\tthis.excludeProjectDependencies = true;\n\t\t}\n\n\t\tContentSelector<Library> asLibrarySelector(Function<String, ContentFilter<Library>> filterFactory) {\n\t\t\tLayer layer = new Layer(getIntoLayer());\n\t\t\tList<ContentFilter<Library>> includeFilters = getIncludes().stream()\n\t\t\t\t.map(filterFactory)\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t\tif (this.includeProjectDependencies) {\n\t\t\t\tincludeFilters.add(Library::isLocal);\n\t\t\t}\n\t\t\tList<ContentFilter<Library>> excludeFilters = getExcludes().stream()\n\t\t\t\t.map(filterFactory)\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t\tif (this.excludeProjectDependencies) {\n\t\t\t\texcludeFilters.add(Library::isLocal);\n\t\t\t}\n\t\t\treturn new IncludeExcludeContentSelector<>(layer, includeFilters, excludeFilters);\n\t\t}\n\n\t}\n\n\t/**\n\t * An {@link IntoLayersSpec} that controls the layers to which application classes and\n\t * resources belong.\n\t */\n\tpublic static class ApplicationSpec extends IntoLayersSpec<IntoLayerSpec> {\n\n\t\t@Inject\n\t\tpublic ApplicationSpec() {\n\t\t\tsuper(new IntoLayerSpecFactory());\n\t\t}\n\n\t\t/**\n\t\t * Creates a new {@code ApplicationSpec} with the given {@code contents}.\n\t\t * @param contents specs for the layers in which application content should be\n\t\t * included\n\t\t */\n\t\tpublic ApplicationSpec(IntoLayerSpec... contents) {\n\t\t\tsuper(new IntoLayerSpecFactory(), contents);\n\t\t}\n\n\t\tList<ContentSelector<String>> asSelectors() {\n\t\t\treturn asSelectors((spec) -> spec.asSelector(ApplicationContentFilter::new));\n\t\t}\n\n\t\tprivate static final class IntoLayerSpecFactory implements Function<String, IntoLayerSpec>, Serializable {\n\n\t\t\t@Override\n\t\t\tpublic IntoLayerSpec apply(String layer) {\n\t\t\t\treturn new IntoLayerSpec(layer);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * An {@link IntoLayersSpec} that controls the layers to which dependencies belong.\n\t */\n\tpublic static class DependenciesSpec extends IntoLayersSpec<DependenciesIntoLayerSpec> implements Serializable {\n\n\t\t@Inject\n\t\tpublic DependenciesSpec() {\n\t\t\tsuper(new IntoLayerSpecFactory());\n\t\t}\n\n\t\t/**\n\t\t * Creates a new {@code DependenciesSpec} with the given {@code contents}.\n\t\t * @param contents specs for the layers in which dependencies should be included\n\t\t */\n\t\tpublic DependenciesSpec(DependenciesIntoLayerSpec... contents) {\n\t\t\tsuper(new IntoLayerSpecFactory(), contents);\n\t\t}\n\n\t\tList<ContentSelector<Library>> asSelectors() {\n\t\t\treturn asSelectors(\n\t\t\t\t\t(spec) -> ((DependenciesIntoLayerSpec) spec).asLibrarySelector(LibraryContentFilter::new));\n\t\t}\n\n\t\tprivate static final class IntoLayerSpecFactory\n\t\t\t\timplements Function<String, DependenciesIntoLayerSpec>, Serializable {\n\n\t\t\t@Override\n\t\t\tpublic DependenciesIntoLayerSpec apply(String layer) {\n\t\t\t\treturn new DependenciesIntoLayerSpec(layer);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LoaderZipEntries.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.gradle.api.file.FileTreeElement;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Internal utility used to copy entries from the {@code spring-boot-loader.jar}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass LoaderZipEntries {\n\n\tprivate final @Nullable Long entryTime;\n\n\tprivate final int dirMode;\n\n\tprivate final int fileMode;\n\n\tLoaderZipEntries(@Nullable Long entryTime, int dirMode, int fileMode) {\n\t\tthis.entryTime = entryTime;\n\t\tthis.dirMode = dirMode;\n\t\tthis.fileMode = fileMode;\n\t}\n\n\tWrittenEntries writeTo(ZipArchiveOutputStream out) throws IOException {\n\t\tWrittenEntries written = new WrittenEntries();\n\t\ttry (ZipInputStream loaderJar = new ZipInputStream(\n\t\t\t\tgetResourceAsStream(\"/META-INF/loader/spring-boot-loader.jar\"))) {\n\t\t\tjava.util.zip.ZipEntry entry = loaderJar.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tif (entry.isDirectory() && !entry.getName().equals(\"META-INF/\")) {\n\t\t\t\t\twriteDirectory(new ZipArchiveEntry(entry), out);\n\t\t\t\t\twritten.addDirectory(entry);\n\t\t\t\t}\n\t\t\t\telse if (entry.getName().endsWith(\".class\") || entry.getName().startsWith(\"META-INF/services/\")) {\n\t\t\t\t\twriteFile(new ZipArchiveEntry(entry), loaderJar, out);\n\t\t\t\t\twritten.addFile(entry);\n\t\t\t\t}\n\t\t\t\tentry = loaderJar.getNextEntry();\n\t\t\t}\n\t\t}\n\t\treturn written;\n\t}\n\n\tprivate InputStream getResourceAsStream(String name) {\n\t\tInputStream stream = getClass().getResourceAsStream(name);\n\t\tAssert.state(stream != null, \"Resource '%s not found'\".formatted(name));\n\t\treturn stream;\n\t}\n\n\tprivate void writeDirectory(ZipArchiveEntry entry, ZipArchiveOutputStream out) throws IOException {\n\t\tprepareEntry(entry, this.dirMode);\n\t\tout.putArchiveEntry(entry);\n\t\tout.closeArchiveEntry();\n\t}\n\n\tprivate void writeFile(ZipArchiveEntry entry, ZipInputStream in, ZipArchiveOutputStream out) throws IOException {\n\t\tprepareEntry(entry, this.fileMode);\n\t\tout.putArchiveEntry(entry);\n\t\tcopy(in, out);\n\t\tout.closeArchiveEntry();\n\t}\n\n\tprivate void prepareEntry(ZipArchiveEntry entry, int unixMode) {\n\t\tif (this.entryTime != null) {\n\t\t\tentry.setTime(DefaultTimeZoneOffset.INSTANCE.removeFrom(this.entryTime));\n\t\t}\n\t\tentry.setUnixMode(unixMode);\n\t}\n\n\tprivate void copy(InputStream in, OutputStream out) throws IOException {\n\t\tStreamUtils.copy(in, out);\n\t}\n\n\t/**\n\t * Tracks entries that have been written.\n\t */\n\tstatic class WrittenEntries {\n\n\t\tprivate final Set<String> directories = new LinkedHashSet<>();\n\n\t\tprivate final Set<String> files = new LinkedHashSet<>();\n\n\t\tprivate void addDirectory(ZipEntry entry) {\n\t\t\tthis.directories.add(entry.getName());\n\t\t}\n\n\t\tprivate void addFile(ZipEntry entry) {\n\t\t\tthis.files.add(entry.getName());\n\t\t}\n\n\t\tboolean isWrittenDirectory(FileTreeElement element) {\n\t\t\tString path = element.getRelativePath().getPathString();\n\t\t\tif (element.isDirectory() && !path.endsWith((\"/\"))) {\n\t\t\t\tpath += \"/\";\n\t\t\t}\n\t\t\treturn this.directories.contains(path);\n\t\t}\n\n\t\tSet<String> getFiles() {\n\t\t\treturn this.files;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/ResolvedDependencies.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.ResolvedConfiguration;\nimport org.gradle.api.artifacts.component.ComponentArtifactIdentifier;\nimport org.gradle.api.artifacts.component.ComponentIdentifier;\nimport org.gradle.api.artifacts.component.ModuleComponentIdentifier;\nimport org.gradle.api.artifacts.component.ProjectComponentIdentifier;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\n\n/**\n * Maps from {@link File} to {@link ComponentArtifactIdentifier}.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Paddy Drury\n * @author Andy Wilkinson\n */\nclass ResolvedDependencies {\n\n\tprivate final Map<String, LibraryCoordinates> projectCoordinatesByPath;\n\n\tprivate final ListProperty<ComponentArtifactIdentifier> artifactIds;\n\n\tprivate final ListProperty<File> artifactFiles;\n\n\tResolvedDependencies(Project project) {\n\t\tthis.artifactIds = project.getObjects().listProperty(ComponentArtifactIdentifier.class);\n\t\tthis.artifactFiles = project.getObjects().listProperty(File.class);\n\t\tthis.projectCoordinatesByPath = projectCoordinatesByPath(project);\n\t}\n\n\tprivate static Map<String, LibraryCoordinates> projectCoordinatesByPath(Project project) {\n\t\treturn project.getRootProject()\n\t\t\t.getAllprojects()\n\t\t\t.stream()\n\t\t\t.collect(Collectors.toMap(Project::getPath, ResolvedDependencies::libraryCoordinates));\n\t}\n\n\tprivate static LibraryCoordinates libraryCoordinates(Project project) {\n\t\treturn LibraryCoordinates.of(Objects.toString(project.getGroup()), project.getName(),\n\t\t\t\tObjects.toString(project.getVersion()));\n\t}\n\n\t@Input\n\tListProperty<ComponentArtifactIdentifier> getArtifactIds() {\n\t\treturn this.artifactIds;\n\t}\n\n\t@Classpath\n\tListProperty<File> getArtifactFiles() {\n\t\treturn this.artifactFiles;\n\t}\n\n\tvoid resolvedArtifacts(Provider<Set<ResolvedArtifactResult>> resolvedArtifacts) {\n\t\tthis.artifactFiles.addAll(\n\t\t\t\tresolvedArtifacts.map((artifacts) -> artifacts.stream().map(ResolvedArtifactResult::getFile).toList()));\n\t\tthis.artifactIds.addAll(\n\t\t\t\tresolvedArtifacts.map((artifacts) -> artifacts.stream().map(ResolvedArtifactResult::getId).toList()));\n\t}\n\n\t@Nullable DependencyDescriptor find(File file) {\n\t\tComponentArtifactIdentifier id = findArtifactIdentifier(file);\n\t\tif (id == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (id instanceof ModuleComponentArtifactIdentifier moduleComponentId) {\n\t\t\tModuleComponentIdentifier moduleId = moduleComponentId.getComponentIdentifier();\n\t\t\treturn new DependencyDescriptor(\n\t\t\t\t\tLibraryCoordinates.of(moduleId.getGroup(), moduleId.getModule(), moduleId.getVersion()), false);\n\t\t}\n\t\tComponentIdentifier componentIdentifier = id.getComponentIdentifier();\n\t\tif (componentIdentifier instanceof ProjectComponentIdentifier projectComponentId) {\n\t\t\tString projectPath = projectComponentId.getProjectPath();\n\t\t\tLibraryCoordinates projectCoordinates = this.projectCoordinatesByPath.get(projectPath);\n\t\t\tif (projectCoordinates != null) {\n\t\t\t\treturn new DependencyDescriptor(projectCoordinates, true);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable ComponentArtifactIdentifier findArtifactIdentifier(File file) {\n\t\tList<File> files = this.artifactFiles.get();\n\t\tfor (int i = 0; i < files.size(); i++) {\n\t\t\tif (file.equals(files.get(i))) {\n\t\t\t\treturn this.artifactIds.get().get(i);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Describes a dependency in a {@link ResolvedConfiguration}.\n\t */\n\tstatic final class DependencyDescriptor {\n\n\t\tprivate final LibraryCoordinates coordinates;\n\n\t\tprivate final boolean projectDependency;\n\n\t\tprivate DependencyDescriptor(LibraryCoordinates coordinates, boolean projectDependency) {\n\t\t\tthis.coordinates = coordinates;\n\t\t\tthis.projectDependency = projectDependency;\n\t\t}\n\n\t\tLibraryCoordinates getCoordinates() {\n\t\t\treturn this.coordinates;\n\t\t}\n\n\t\tboolean isProjectDependency() {\n\t\t\treturn this.projectDependency;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/ZipCompression.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.util.zip.ZipEntry;\n\n/**\n * An enumeration of supported compression options for an entry in a ZIP archive.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic enum ZipCompression {\n\n\t/**\n\t * The entry should be {@link ZipEntry#STORED} in the archive.\n\t */\n\tSTORED,\n\n\t/**\n\t * The entry should be {@link ZipEntry#DEFLATED} in the archive.\n\t */\n\tDEFLATED\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for creating executable jars and wars.\n */\n@NullMarked\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/BootRun.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.run;\n\nimport java.io.File;\nimport java.util.Set;\n\nimport org.gradle.api.file.SourceDirectorySet;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.JavaExec;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetOutput;\nimport org.gradle.work.DisableCachingByDefault;\n\n/**\n * Custom {@link JavaExec} task for running a Spring Boot application.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@DisableCachingByDefault(because = \"Application should always run\")\npublic abstract class BootRun extends JavaExec {\n\n\tpublic BootRun() {\n\t\tgetOptimizedLaunch().convention(true);\n\t}\n\n\t/**\n\t * Returns the property for whether the JVM's launch should be optimized. The property\n\t * defaults to {@code true}.\n\t * @return whether the JVM's launch should be optimized\n\t * @since 3.0.0\n\t */\n\t@Input\n\tpublic abstract Property<Boolean> getOptimizedLaunch();\n\n\t/**\n\t * Adds the {@link SourceDirectorySet#getSrcDirs() source directories} of the given\n\t * {@code sourceSet's} {@link SourceSet#getResources() resources} to the start of the\n\t * classpath in place of the {@link SourceSet#getOutput output's}\n\t * {@link SourceSetOutput#getResourcesDir() resources directory}.\n\t * @param sourceSet the source set\n\t */\n\tpublic void sourceResources(SourceSet sourceSet) {\n\t\tFile resourcesDir = sourceSet.getOutput().getResourcesDir();\n\t\tSet<File> srcDirs = sourceSet.getResources().getSrcDirs();\n\t\tsetClasspath(getProject().files(srcDirs, getClasspath()).filter((file) -> !file.equals(resourcesDir)));\n\t}\n\n\t@Override\n\tpublic void exec() {\n\t\tif (getOptimizedLaunch().get()) {\n\t\t\tsetJvmArgs(getJvmArgs());\n\t\t\tjvmArgs(\"-XX:TieredStopAtLevel=1\");\n\t\t}\n\t\tif (System.console() != null) {\n\t\t\t// Record that the console is available here for AnsiOutput to detect later\n\t\t\tgetEnvironment().put(\"spring.output.ansi.console-available\", true);\n\t\t}\n\t\tsuper.exec();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for running Spring Boot applications.\n */\n@NullMarked\npackage org.springframework.boot.gradle.tasks.run;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/util/VersionExtractor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.util;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Extracts version information for a Class.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic final class VersionExtractor {\n\n\tprivate VersionExtractor() {\n\t}\n\n\t/**\n\t * Return the version information for the provided {@link Class}.\n\t * @param cls the Class to retrieve the version for\n\t * @return the version, or {@code null} if a version can not be extracted\n\t */\n\tpublic static @Nullable String forClass(Class<?> cls) {\n\t\tString implementationVersion = cls.getPackage().getImplementationVersion();\n\t\tif (implementationVersion != null) {\n\t\t\treturn implementationVersion;\n\t\t}\n\t\tURL codeSourceLocation = cls.getProtectionDomain().getCodeSource().getLocation();\n\t\ttry {\n\t\t\tURLConnection connection = codeSourceLocation.openConnection();\n\t\t\tif (connection instanceof JarURLConnection jarURLConnection) {\n\t\t\t\treturn getImplementationVersion(jarURLConnection.getJarFile());\n\t\t\t}\n\t\t\ttry (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) {\n\t\t\t\treturn getImplementationVersion(jarFile);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static String getImplementationVersion(JarFile jarFile) throws IOException {\n\t\treturn jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Shared utility classes.\n */\n@NullMarked\npackage org.springframework.boot.gradle.util;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/resources/unixStartScript.txt",
    "content": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  ${applicationName} start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: \\$0 may be a link\nPRG=\"\\$0\"\n# Need this for relative symlinks.\nwhile [ -h \"\\$PRG\" ] ; do\n    ls=`ls -ld \"\\$PRG\"`\n    link=`expr \"\\$ls\" : '.*-> \\\\(.*\\\\)\\$'`\n    if expr \"\\$link\" : '/.*' > /dev/null; then\n        PRG=\"\\$link\"\n    else\n        PRG=`dirname \"\\$PRG\"`\"/\\$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"\\$PRG\\\"`/${appHomeRelativePath}\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"\\$SAVED\" >/dev/null\n\nAPP_NAME=\"${applicationName}\"\nAPP_BASE_NAME=`basename \"\\$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script.\nDEFAULT_JVM_OPTS=${defaultJvmOpts}\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"\\$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"\\$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nJARPATH=$classpath\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"\\$JAVA_HOME\" ] ; then\n    if [ -x \"\\$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"\\$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"\\$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"\\$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: \\$JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"\\$cygwin\" = \"false\" -a \"\\$darwin\" = \"false\" -a \"\\$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ \\$? -eq 0 ] ; then\n        if [ \"\\$MAX_FD\" = \"maximum\" -o \"\\$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"\\$MAX_FD_LIMIT\"\n        fi\n        ulimit -n \\$MAX_FD\n        if [ \\$? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: \\$MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: \\$MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif \\$darwin; then\n    GRADLE_OPTS=\"\\$GRADLE_OPTS \\\\\"-Xdock:name=\\$APP_NAME\\\\\" \\\\\"-Xdock:icon=\\$APP_HOME/media/gradle.icns\\\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif \\$cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"\\$APP_HOME\"`\n    JARPATH=`cygpath --path --mixed \"\\$JARPATH\"`\n    JAVACMD=`cygpath --unix \"\\$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in \\$ROOTDIRSRAW ; do\n        ROOTDIRS=\"\\$ROOTDIRS\\$SEP\\$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^(\\$ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"\\$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"\\$OURCYGPATTERN|(\\$GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"\\$@\" ; do\n        CHECK=`echo \"\\$arg\"|egrep -c \"\\$OURCYGPATTERN\" -`\n        CHECK2=`echo \"\\$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ \\$CHECK -ne 0 ] && [ \\$CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args\\$i`=`cygpath --path --ignore --mixed \"\\$arg\"`\n        else\n            eval `echo args\\$i`=\"\\\"\\$arg\\\"\"\n        fi\n        i=\\$((i+1))\n    done\n    case \\$i in\n        (0) set -- ;;\n        (1) set -- \"\\$args0\" ;;\n        (2) set -- \"\\$args0\" \"\\$args1\" ;;\n        (3) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" ;;\n        (4) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" \"\\$args3\" ;;\n        (5) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" \"\\$args3\" \"\\$args4\" ;;\n        (6) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" \"\\$args3\" \"\\$args4\" \"\\$args5\" ;;\n        (7) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" \"\\$args3\" \"\\$args4\" \"\\$args5\" \"\\$args6\" ;;\n        (8) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" \"\\$args3\" \"\\$args4\" \"\\$args5\" \"\\$args6\" \"\\$args7\" ;;\n        (9) set -- \"\\$args0\" \"\\$args1\" \"\\$args2\" \"\\$args3\" \"\\$args4\" \"\\$args5\" \"\\$args6\" \"\\$args7\" \"\\$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave ( ) {\n    for i do printf %s\\\\\\\\n \"\\$i\" | sed \"s/'/'\\\\\\\\\\\\\\\\''/g;1s/^/'/;\\\\\\$s/\\\\\\$/' \\\\\\\\\\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=\\$(save \"\\$@\")\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- \\$DEFAULT_JVM_OPTS \\$JAVA_OPTS \\$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>\"\\\"-D${appNameSystemProperty}=\\$APP_BASE_NAME\\\"\" <% } %>-jar \"\\\"\\$JARPATH\\\"\" \"\\$APP_ARGS\"\n\n# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong\nif [ \"\\$(uname)\" = \"Darwin\" ] && [ \"\\$HOME\" = \"\\$PWD\" ]; then\n  cd \"\\$(dirname \"\\$0\")\"\nfi\n\nexec \"\\$JAVACMD\" \"\\$@\"\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/main/resources/windowsStartScript.txt",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  ${applicationName} startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\\\n\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%${appHomeRelativePath}\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=${defaultJvmOpts}\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\n\n:execute\n@rem Setup the command line\n\nset JARPATH=$classpath\n\n@rem Execute ${applicationName}\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %${optsEnvironmentVar}% <% if ( appNameSystemProperty ) { %>\"-D${appNameSystemProperty}=%APP_BASE_NAME%\"<% } %> -jar \"%JARPATH%\" %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable ${exitEnvironmentVar} if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%${exitEnvironmentVar}%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/TaskConfigurationAvoidanceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Predicate;\nimport java.util.regex.Pattern;\n\nimport com.tngtech.archunit.base.DescribedPredicate;\nimport com.tngtech.archunit.core.domain.JavaClasses;\nimport com.tngtech.archunit.core.domain.JavaMethodCall;\nimport com.tngtech.archunit.core.domain.JavaType;\nimport com.tngtech.archunit.core.importer.ImportOption;\nimport com.tngtech.archunit.core.importer.Location;\nimport com.tngtech.archunit.junit.AnalyzeClasses;\nimport com.tngtech.archunit.junit.ArchTest;\nimport com.tngtech.archunit.lang.syntax.ArchRuleDefinition;\nimport org.gradle.api.Action;\nimport org.gradle.api.tasks.TaskCollection;\nimport org.gradle.api.tasks.TaskContainer;\n\n/**\n * Tests that verify the plugin's compliance with task configuration avoidance.\n *\n * @author Andy Wilkinson\n */\n@AnalyzeClasses(packages = \"org.springframework.boot.gradle\",\n\t\timportOptions = TaskConfigurationAvoidanceTests.DoNotIncludeTests.class)\nclass TaskConfigurationAvoidanceTests {\n\n\t@ArchTest\n\tvoid noApisThatCauseEagerTaskConfigurationShouldBeCalled(JavaClasses classes) {\n\t\tProhibitedMethods prohibited = new ProhibitedMethods();\n\t\tprohibited.on(TaskContainer.class)\n\t\t\t.methodsNamed(\"create\", \"findByPath, getByPath\")\n\t\t\t.method(\"withType\", Class.class, Action.class);\n\t\tprohibited.on(TaskCollection.class).methodsNamed(\"findByName\", \"getByName\");\n\t\tArchRuleDefinition.noClasses()\n\t\t\t.should()\n\t\t\t.callMethodWhere(DescribedPredicate.describe(\"it would cause eager task configuration\", prohibited))\n\t\t\t.check(classes);\n\t}\n\n\tstatic class DoNotIncludeTests implements ImportOption {\n\n\t\t@Override\n\t\tpublic boolean includes(Location location) {\n\t\t\treturn !location.matches(Pattern.compile(\".*Tests\\\\.class\"));\n\t\t}\n\n\t}\n\n\tprivate static final class ProhibitedMethods implements Predicate<JavaMethodCall> {\n\n\t\tprivate final List<Predicate<JavaMethodCall>> prohibited = new ArrayList<>();\n\n\t\tprivate ProhibitedConfigurer on(Class<?> type) {\n\t\t\treturn new ProhibitedConfigurer(type);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean test(JavaMethodCall methodCall) {\n\t\t\tfor (Predicate<JavaMethodCall> spec : this.prohibited) {\n\t\t\t\tif (spec.test(methodCall)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate final class ProhibitedConfigurer {\n\n\t\t\tprivate final Class<?> type;\n\n\t\t\tprivate ProhibitedConfigurer(Class<?> type) {\n\t\t\t\tthis.type = type;\n\t\t\t}\n\n\t\t\tprivate ProhibitedConfigurer methodsNamed(String... names) {\n\t\t\t\tfor (String name : names) {\n\t\t\t\t\tProhibitedMethods.this.prohibited.add(new ProhibitMethodsNamed(this.type, name));\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tprivate ProhibitedConfigurer method(String name, Class<?>... parameterTypes) {\n\t\t\t\tProhibitedMethods.this.prohibited\n\t\t\t\t\t.add(new ProhibitMethod(this.type, name, Arrays.asList(parameterTypes)));\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class ProhibitMethodsNamed implements Predicate<JavaMethodCall> {\n\n\t\t\tprivate final Class<?> owner;\n\n\t\t\tprivate final String name;\n\n\t\t\tProhibitMethodsNamed(Class<?> owner, String name) {\n\t\t\t\tthis.owner = owner;\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean test(JavaMethodCall methodCall) {\n\t\t\t\treturn methodCall.getTargetOwner().isEquivalentTo(this.owner) && methodCall.getName().equals(this.name);\n\t\t\t}\n\n\t\t}\n\n\t\tprivate static final class ProhibitMethod extends ProhibitMethodsNamed {\n\n\t\t\tprivate final List<Class<?>> parameterTypes;\n\n\t\t\tprivate ProhibitMethod(Class<?> owner, String name, List<Class<?>> parameterTypes) {\n\t\t\t\tsuper(owner, name);\n\t\t\t\tthis.parameterTypes = parameterTypes;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean test(JavaMethodCall methodCall) {\n\t\t\t\treturn super.test(methodCall) && match(methodCall.getTarget().getParameterTypes());\n\t\t\t}\n\n\t\t\tprivate boolean match(List<JavaType> callParameterTypes) {\n\t\t\t\tif (this.parameterTypes.size() != callParameterTypes.size()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < this.parameterTypes.size(); i++) {\n\t\t\t\t\tif (!callParameterTypes.get(i).toErasure().isEquivalentTo(this.parameterTypes.get(i))) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/AotDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for AOT documentation.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass AotDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid applyNativeImagePlugin() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"aot/apply-native-image-plugin\").build(\"tasks\").getOutput())\n\t\t\t.contains(\"nativeCompile\")\n\t\t\t.contains(\"aotClasses\");\n\t}\n\n\t@TestTemplate\n\tvoid applyAotPlugin() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"aot/apply-aot-plugin\").build(\"tasks\").getOutput())\n\t\t\t.contains(\"aotClasses\")\n\t\t\t.doesNotContain(\"nativeCompile\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/Examples.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\n/**\n * @author Phillip Webb\n */\nfinal class Examples {\n\n\tstatic final String DIR = \"src/docs/antora/modules/gradle-plugin/examples/\";\n\n\tprivate Examples() {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/GettingStartedDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\n/**\n * Tests for the getting started documentation.\n *\n * @author Andy Wilkinson\n * @author Jean-Baptiste Nizet\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass GettingStartedDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t// NOTE: We can't run any 'apply-plugin' tests because during a release the\n\t// jar won't be there\n\n\t@TestTemplate\n\tvoid typicalPluginsAppliesExceptedPlugins() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"getting-started/typical-plugins\").build(\"verify\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/IntegratingWithActuatorDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the generating build info documentation.\n *\n * @author Andy Wilkinson\n * @author Jean-Baptiste Nizet\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass IntegratingWithActuatorDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid basicBuildInfo() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"integrating-with-actuator/build-info-basic\").build(\"bootBuildInfo\");\n\t\tassertThat(new File(this.gradleBuild.getProjectDir(), \"build/bootBuildInfo/META-INF/build-info.properties\"))\n\t\t\t.isFile();\n\t}\n\n\t@TestTemplate\n\tvoid buildInfoCustomValues() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"integrating-with-actuator/build-info-custom-values\")\n\t\t\t.build(\"bootBuildInfo\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(), \"build/bootBuildInfo/META-INF/build-info.properties\");\n\t\tassertThat(file).isFile();\n\t\tProperties properties = buildInfoProperties(file);\n\t\tassertThat(properties).containsEntry(\"build.artifact\", \"example-app\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"1.2.3\");\n\t\tassertThat(properties).containsEntry(\"build.group\", \"com.example\");\n\t\tassertThat(properties).containsEntry(\"build.name\", \"Example application\");\n\t\tassertThat(properties).containsKey(\"build.time\");\n\t}\n\n\t@TestTemplate\n\tvoid buildInfoAdditional() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"integrating-with-actuator/build-info-additional\")\n\t\t\t.build(\"bootBuildInfo\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(), \"build/bootBuildInfo/META-INF/build-info.properties\");\n\t\tassertThat(file).isFile();\n\t\tProperties properties = buildInfoProperties(file);\n\t\tassertThat(properties).containsEntry(\"build.a\", \"alpha\");\n\t\tassertThat(properties).containsEntry(\"build.b\", \"bravo\");\n\t}\n\n\t@TestTemplate\n\tvoid buildInfoExcludeTime() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"integrating-with-actuator/build-info-exclude-time\")\n\t\t\t.build(\"bootBuildInfo\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(), \"build/bootBuildInfo/META-INF/build-info.properties\");\n\t\tassertThat(file).isFile();\n\t\tProperties properties = buildInfoProperties(file);\n\t\tassertThat(properties).doesNotContainKey(\"build.time\");\n\t}\n\n\tprivate Properties buildInfoProperties(File file) {\n\t\tassertThat(file).isFile();\n\t\tProperties properties = new Properties();\n\t\ttry (FileReader reader = new FileReader(file)) {\n\t\t\tproperties.load(reader);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/ManagingDependenciesDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.Dsl;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.junit.jupiter.api.Assumptions.assumingThat;\n\n/**\n * Tests for the managing dependencies documentation.\n *\n * @author Andy Wilkinson\n * @author Jean-Baptiste Nizet\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass ManagingDependenciesDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid dependenciesExampleEvaluatesSuccessfully() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"managing-dependencies/dependencies\").build();\n\t}\n\n\t@TestTemplate\n\tvoid customManagedVersions() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"managing-dependencies/custom-version\")\n\t\t\t.build(\"slf4jVersion\")\n\t\t\t.getOutput()).contains(\"1.7.20\");\n\t}\n\n\t@TestTemplate\n\tvoid dependencyManagementInIsolation() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"managing-dependencies/configure-bom\")\n\t\t\t.build(\"dependencyManagement\")\n\t\t\t.getOutput()).contains(\"org.springframework.boot:spring-boot-starter \");\n\t}\n\n\t@TestTemplate\n\tvoid dependencyManagementInIsolationWithPluginsBlock() {\n\t\tassumingThat(this.gradleBuild.getDsl() == Dsl.KOTLIN,\n\t\t\t\t() -> assertThat(\n\t\t\t\t\t\tthis.gradleBuild.script(Examples.DIR + \"managing-dependencies/configure-bom-with-plugins\")\n\t\t\t\t\t\t\t.build(\"dependencyManagement\")\n\t\t\t\t\t\t\t.getOutput())\n\t\t\t\t\t.contains(\"org.springframework.boot:spring-boot-starter TEST-SNAPSHOT\"));\n\t}\n\n\t@TestTemplate\n\tvoid configurePlatform() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"managing-dependencies/configure-platform\")\n\t\t\t.build(\"dependencies\", \"--configuration\", \"compileClasspath\")\n\t\t\t.getOutput()).contains(\"org.springframework.boot:spring-boot-starter \");\n\t}\n\n\t@TestTemplate\n\tvoid customManagedVersionsWithPlatform() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"managing-dependencies/custom-version-with-platform\")\n\t\t\t.build(\"dependencies\", \"--configuration\", \"compileClasspath\")\n\t\t\t.getOutput()).contains(\"1.7.20\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the packaging documentation.\n *\n * @author Andy Wilkinson\n * @author Jean-Baptiste Nizet\n * @author Scott Frederick\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass PackagingDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid warContainerDependencyEvaluatesSuccessfully() {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/war-container-dependency\").build();\n\t}\n\n\t@TestTemplate\n\tvoid bootJarMainClass() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-main-class\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThat(jar.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.ExampleApplication\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootJarManifestMainClass() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-manifest-main-class\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThat(jar.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.ExampleApplication\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginMainClass() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/application-plugin-main-class\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThat(jar.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.ExampleApplication\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid springBootDslMainClass() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/spring-boot-dsl-main-class\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThat(jar.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.ExampleApplication\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootWarIncludeDevtools() throws IOException {\n\t\tjarFile(new File(this.gradleBuild.getProjectDir(), \"spring-boot-devtools-1.2.3.RELEASE.jar\"));\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-war-include-devtools\").build(\"bootWar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".war\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThat(jar.getEntry(\"WEB-INF/lib/spring-boot-devtools-1.2.3.RELEASE.jar\")).isNotNull();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootJarRequiresUnpack() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-requires-unpack\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tJarEntry entry = jar.getJarEntry(\"BOOT-INF/lib/jruby-complete-1.7.25.jar\");\n\t\t\tassertThat(entry).isNotNull();\n\t\t\tassertThat(entry.getComment()).isEqualTo(\"UNPACK\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootWarPropertiesLauncher() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-war-properties-launcher\").build(\"bootWar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".war\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThat(jar.getManifest().getMainAttributes().getValue(\"Main-Class\"))\n\t\t\t\t.isEqualTo(\"org.springframework.boot.loader.launch.PropertiesLauncher\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid onlyBootJar() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/only-boot-jar\").build(\"assemble\");\n\t\tFile plainJar = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \"-plain.jar\");\n\t\tassertThat(plainJar).doesNotExist();\n\t\tFile bootJar = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(bootJar).isFile();\n\t\ttry (JarFile jar = new JarFile(bootJar)) {\n\t\t\tassertThat(jar.getEntry(\"BOOT-INF/\")).isNotNull();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid classifiedBootJar() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-and-jar-classifiers\").build(\"assemble\");\n\t\tFile plainJar = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(plainJar).isFile();\n\t\ttry (JarFile jar = new JarFile(plainJar)) {\n\t\t\tassertThat(jar.getEntry(\"BOOT-INF/\")).isNull();\n\t\t}\n\t\tFile bootJar = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \"-boot.jar\");\n\t\tassertThat(bootJar).isFile();\n\t\ttry (JarFile jar = new JarFile(bootJar)) {\n\t\t\tassertThat(jar.getEntry(\"BOOT-INF/\")).isNotNull();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootJarLayeredDisabled() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-layered-disabled\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tJarEntry entry = jar.getJarEntry(\"BOOT-INF/layers.idx\");\n\t\t\tassertThat(entry).isNull();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootJarLayeredCustom() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-layered-custom\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tJarEntry entry = jar.getJarEntry(\"BOOT-INF/layers.idx\");\n\t\t\tassertThat(entry).isNotNull();\n\t\t\tassertThat(Collections.list(jar.entries())\n\t\t\t\t.stream()\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(\"BOOT-INF/lib/spring-boot\"))).isNotEmpty();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootJarLayeredExcludeTools() throws IOException {\n\t\tthis.gradleBuild.script(Examples.DIR + \"packaging/boot-jar-layered-exclude-tools\").build(\"bootJar\");\n\t\tFile file = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/libs/\" + this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(file).isFile();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tJarEntry entry = jar.getJarEntry(\"BOOT-INF/layers.idx\");\n\t\t\tassertThat(entry).isNotNull();\n\t\t\tassertThat(Collections.list(jar.entries())\n\t\t\t\t.stream()\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(\"BOOT-INF/lib/spring-boot\"))).isEmpty();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithBuilder() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-builder\")\n\t\t\t.build(\"bootBuildImageBuilder\");\n\t\tassertThat(result.getOutput()).contains(\"builder=mine/java-cnb-builder\").contains(\"runImage=mine/java-cnb-run\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithCustomBuildpackJvmVersion() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-env\")\n\t\t\t.build(\"bootBuildImageEnvironment\");\n\t\tassertThat(result.getOutput()).contains(\"BP_JVM_VERSION=17\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithCustomProxySettings() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-env-proxy\")\n\t\t\t.build(\"bootBuildImageEnvironment\");\n\t\tassertThat(result.getOutput()).contains(\"HTTP_PROXY=http://proxy.example.com\")\n\t\t\t.contains(\"HTTPS_PROXY=https://proxy.example.com\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithCustomRuntimeConfiguration() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-env-runtime\")\n\t\t\t.build(\"bootBuildImageEnvironment\");\n\t\tassertThat(result.getOutput()).contains(\"BPE_DELIM_JAVA_TOOL_OPTIONS= \")\n\t\t\t.contains(\"BPE_APPEND_JAVA_TOOL_OPTIONS=-XX:+HeapDumpOnOutOfMemoryError\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithCustomImageName() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-name\")\n\t\t\t.build(\"bootBuildImageName\");\n\t\tassertThat(result.getOutput()).contains(\"example.com/library/\" + this.gradleBuild.getProjectDir().getName());\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithDockerHostMinikube() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-docker-host\")\n\t\t\t.build(\"bootBuildImageDocker\");\n\t\tassertThat(result.getOutput()).contains(\"host=tcp://192.168.99.100:2376\")\n\t\t\t.contains(\"tlsVerify=true\")\n\t\t\t.contains(\"certPath=/home/user/.minikube/certs\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithDockerHostPodman() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-docker-host-podman\")\n\t\t\t.build(\"bootBuildImageDocker\");\n\t\tassertThat(result.getOutput()).contains(\"host=unix:///run/user/1000/podman/podman.sock\")\n\t\t\t.contains(\"bindHostToBuilder=true\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithDockerHostColima() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-docker-host-colima\")\n\t\t\t.build(\"bootBuildImageDocker\");\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"host=unix://\" + System.getProperty(\"user.home\") + \"/.colima/docker.sock\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithDockerUserAuth() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-docker-auth-user\")\n\t\t\t.build(\"bootBuildImageDocker\");\n\t\tassertThat(result.getOutput()).contains(\"username=user\")\n\t\t\t.contains(\"password=secret\")\n\t\t\t.contains(\"url=https://docker.example.com/v1/\")\n\t\t\t.contains(\"email=user@example.com\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithDockerTokenAuth() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-docker-auth-token\")\n\t\t\t.build(\"bootBuildImageDocker\");\n\t\tassertThat(result.getOutput()).contains(\"token=9cbaf023786cd7...\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImagePublish() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-publish\")\n\t\t\t.build(\"bootBuildImagePublish\");\n\t\tassertThat(result.getOutput()).contains(\"true\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithBuildpacks() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-buildpacks\")\n\t\t\t.build(\"bootBuildImageBuildpacks\");\n\t\tassertThat(result.getOutput()).contains(\"file:///path/to/example-buildpack.tgz\")\n\t\t\t.contains(\"urn:cnb:builder:paketo-buildpacks/java\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithCaches() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-caches\")\n\t\t\t.build(\"bootBuildImageCaches\");\n\t\tassertThat(result.getOutput()).containsPattern(\"buildCache=cache-gradle-[\\\\d]+.build\")\n\t\t\t.containsPattern(\"launchCache=cache-gradle-[\\\\d]+.launch\");\n\t}\n\n\t@TestTemplate\n\tvoid bootBuildImageWithBindCaches() {\n\t\tBuildResult result = this.gradleBuild.script(Examples.DIR + \"packaging/boot-build-image-bind-caches\")\n\t\t\t.build(\"bootBuildImageCaches\");\n\t\tassertThat(result.getOutput()).containsPattern(\"buildWorkspace=/tmp/cache-gradle-[\\\\d]+.work\")\n\t\t\t.containsPattern(\"buildCache=/tmp/cache-gradle-[\\\\d]+.build\")\n\t\t\t.containsPattern(\"launchCache=/tmp/cache-gradle-[\\\\d]+.launch\");\n\t}\n\n\tprotected void jarFile(File file) throws IOException {\n\t\ttry (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {\n\t\t\tjar.putNextEntry(new ZipEntry(\"META-INF/MANIFEST.MF\"));\n\t\t\tnew Manifest().write(jar);\n\t\t\tjar.closeEntry();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PublishingDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the publishing documentation.\n *\n * @author Andy Wilkinson\n * @author Jean-Baptiste Nizet\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass PublishingDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid mavenPublish() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"publishing/maven-publish\")\n\t\t\t.build(\"publishingConfiguration\")\n\t\t\t.getOutput()).contains(\"MavenPublication\").contains(\"https://repo.example.com\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/RunningDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.docs;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.junit.GradleMultiDslExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the documentation about running a Spring Boot application.\n *\n * @author Andy Wilkinson\n * @author Jean-Baptiste Nizet\n */\n@ExtendWith(GradleMultiDslExtension.class)\nclass RunningDocumentationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid bootRunMain() throws IOException {\n\t\twriteMainClass();\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/boot-run-main\").build(\"bootRun\").getOutput())\n\t\t\t.contains(\"com.example.ExampleApplication\");\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginMainClassName() throws IOException {\n\t\twriteMainClass();\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/application-plugin-main-class-name\")\n\t\t\t.build(\"bootRun\")\n\t\t\t.getOutput()).contains(\"com.example.ExampleApplication\");\n\t}\n\n\t@TestTemplate\n\tvoid springBootDslMainClassName() throws IOException {\n\t\twriteMainClass();\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/spring-boot-dsl-main-class-name\")\n\t\t\t.build(\"bootRun\")\n\t\t\t.getOutput()).contains(\"com.example.ExampleApplication\");\n\t}\n\n\t@TestTemplate\n\tvoid bootRunSourceResources() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/boot-run-source-resources\")\n\t\t\t.build(\"configuredClasspath\")\n\t\t\t.getOutput()).contains(new File(\"src/main/resources\").getPath());\n\t}\n\n\t@TestTemplate\n\tvoid bootRunDisableOptimizedLaunch() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/boot-run-disable-optimized-launch\")\n\t\t\t.build(\"optimizedLaunch\")\n\t\t\t.getOutput()).contains(\"false\");\n\t}\n\n\t@TestTemplate\n\tvoid bootRunSystemPropertyDefaultValue() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/boot-run-system-property\")\n\t\t\t.build(\"configuredSystemProperties\")\n\t\t\t.getOutput()).contains(\"com.example.property = default\");\n\t}\n\n\t@TestTemplate\n\tvoid bootRunSystemProperty() {\n\t\tassertThat(this.gradleBuild.script(Examples.DIR + \"running/boot-run-system-property\")\n\t\t\t.build(\"-Pexample=custom\", \"configuredSystemProperties\")\n\t\t\t.getOutput()).contains(\"com.example.property = custom\");\n\t}\n\n\tprivate void writeMainClass() throws IOException {\n\t\tFile exampleApplication = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"src/main/java/com/example/ExampleApplication.java\");\n\t\texampleApplication.getParentFile().mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(exampleApplication))) {\n\t\t\twriter.println(\"package com.example;\");\n\t\t\twriter.println(\"public class ExampleApplication {\");\n\t\t\twriter.println(\"    public static void main(String[] args) {\");\n\t\t\twriter.println(\"        System.out.println(ExampleApplication.class.getName());\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println(\"}\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.gradle.docs;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.dsl;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.Properties;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.gradle.tasks.buildinfo.BuildInfo;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link BuildInfo} created using the\n * {@link org.springframework.boot.gradle.dsl.SpringBootExtension DSL}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass BuildInfoDslIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid basicJar() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootJar\").task(\":bootBuildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties properties = buildInfoProperties();\n\t\tassertThat(properties).containsEntry(\"build.name\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.artifact\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.group\", \"com.example\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"1.0\");\n\t\tFile jar = new File(this.gradleBuild.getProjectDir(), \"build/libs/\").listFiles()[0];\n\t\ttry (JarFile jarFile = new JarFile(jar)) {\n\t\t\tJarEntry entry = jarFile.getJarEntry(\"META-INF/build-info.properties\");\n\t\t\tassertThat(entry).isNotNull();\n\t\t\tProperties jarProperties = new Properties();\n\t\t\tjarProperties.load(jarFile.getInputStream(entry));\n\t\t\tassertThat(jarProperties).isEqualTo(properties);\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid jarWithCustomName() {\n\t\tBuildTask task = this.gradleBuild.build(\"bootBuildInfo\", \"--stacktrace\").task(\":bootBuildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties properties = buildInfoProperties();\n\t\tassertThat(properties).containsEntry(\"build.name\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.artifact\", \"foo\");\n\t\tassertThat(properties).containsEntry(\"build.group\", \"com.example\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"1.0\");\n\t}\n\n\t@TestTemplate\n\tvoid basicWar() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootWar\").task(\":bootBuildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties properties = buildInfoProperties();\n\t\tassertThat(properties).containsEntry(\"build.name\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.artifact\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.group\", \"com.example\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"1.0\");\n\t\tFile war = new File(this.gradleBuild.getProjectDir(), \"build/libs/\").listFiles()[0];\n\t\ttry (JarFile warFile = new JarFile(war)) {\n\t\t\tJarEntry entry = warFile.getJarEntry(\"WEB-INF/classes/META-INF/build-info.properties\");\n\t\t\tassertThat(entry).isNotNull();\n\t\t\tProperties jarProperties = new Properties();\n\t\t\tjarProperties.load(warFile.getInputStream(entry));\n\t\t\tassertThat(jarProperties).isEqualTo(properties);\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid warWithCustomName() {\n\t\tBuildTask task = this.gradleBuild.build(\"bootBuildInfo\", \"--stacktrace\").task(\":bootBuildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties properties = buildInfoProperties();\n\t\tassertThat(properties).containsEntry(\"build.name\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.artifact\", \"foo\");\n\t\tassertThat(properties).containsEntry(\"build.group\", \"com.example\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"1.0\");\n\t}\n\n\t@TestTemplate\n\tvoid additionalProperties() {\n\t\tBuildTask task = this.gradleBuild.build(\"bootBuildInfo\", \"--stacktrace\").task(\":bootBuildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties properties = buildInfoProperties();\n\t\tassertThat(properties).containsEntry(\"build.name\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.artifact\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(properties).containsEntry(\"build.group\", \"com.example\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"1.0\");\n\t\tassertThat(properties).containsEntry(\"build.a\", \"alpha\");\n\t\tassertThat(properties).containsEntry(\"build.b\", \"bravo\");\n\t}\n\n\tprivate Properties buildInfoProperties() {\n\t\tFile file = new File(this.gradleBuild.getProjectDir(), \"build/bootBuildInfo/META-INF/build-info.properties\");\n\t\tassertThat(file).isFile();\n\t\tProperties properties = new Properties();\n\t\ttry (FileReader reader = new FileReader(file)) {\n\t\t\tproperties.load(reader);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleBuildFieldSetter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.junit;\n\nimport java.lang.reflect.Field;\n\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link BeforeEachCallback} to set a test class's {@code gradleBuild} field prior to\n * test execution.\n *\n * @author Andy Wilkinson\n */\nfinal class GradleBuildFieldSetter implements BeforeEachCallback {\n\n\tprivate final GradleBuild gradleBuild;\n\n\tGradleBuildFieldSetter(GradleBuild gradleBuild) {\n\t\tthis.gradleBuild = gradleBuild;\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tField field = ReflectionUtils.findField(context.getRequiredTestClass(), \"gradleBuild\");\n\t\tAssert.notNull(field, \"Field named gradleBuild not found in \" + context.getRequiredTestClass().getName());\n\t\tfield.setAccessible(true);\n\t\tfield.set(context.getRequiredTestInstance(), this.gradleBuild);\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibility.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.junit;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.Extension;\n\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\n/**\n * {@link Extension} that runs {@link TestTemplate templated tests} against multiple\n * versions of Gradle. Test classes using the extension must have a non-private and\n * non-final {@link GradleBuild} field named {@code gradleBuild}.\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Inherited\n@ExtendWith(GradleCompatibilityExtension.class)\npublic @interface GradleCompatibility {\n\n\t/**\n\t * Whether to include running Gradle with {@code --cache-configuration} cache in the\n\t * compatibility matrix.\n\t * @return {@code true} to enable the configuration cache, {@code false} otherwise\n\t */\n\tboolean configurationCache() default false;\n\n\t/**\n\t * Minimum version of Gradle against which compatibility should be tested.\n\t * @return minimum version\n\t */\n\tString minimumVersion() default \"\";\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleCompatibilityExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.junit;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.gradle.util.GradleVersion;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;\nimport org.junit.platform.commons.util.AnnotationUtils;\n\nimport org.springframework.boot.gradle.testkit.PluginClasspathGradleBuild;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuildExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleVersions;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Extension} that runs {@link TestTemplate templated tests} against multiple\n * versions of Gradle. Test classes using the extension must have a non-private and\n * non-final {@link GradleBuild} field named {@code gradleBuild}.\n *\n * @author Andy Wilkinson\n */\nfinal class GradleCompatibilityExtension implements TestTemplateInvocationContextProvider {\n\n\tprivate static final List<String> GRADLE_VERSIONS = GradleVersions.allCompatible();\n\n\t@Override\n\tpublic Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {\n\t\tGradleVersion highestVersion = GRADLE_VERSIONS.stream()\n\t\t\t.map(GradleVersion::version)\n\t\t\t.collect(Collectors.toCollection(TreeSet::new))\n\t\t\t.last();\n\t\tClass<?> testClass = context.getRequiredTestClass();\n\t\tGradleCompatibility gradleCompatibility = AnnotationUtils.findAnnotation(testClass, GradleCompatibility.class)\n\t\t\t.get();\n\t\tStream<String> gradleVersions = GRADLE_VERSIONS.stream();\n\t\tif (StringUtils.hasText(gradleCompatibility.minimumVersion())) {\n\t\t\tGradleVersion lowerInclusive = GradleVersion.version(gradleCompatibility.minimumVersion());\n\t\t\tgradleVersions = gradleVersions\n\t\t\t\t.filter((version) -> GradleVersion.version(version).compareTo(lowerInclusive) >= 0);\n\t\t}\n\t\treturn gradleVersions.flatMap((version) -> {\n\t\t\tList<TestTemplateInvocationContext> invocationContexts = new ArrayList<>();\n\t\t\tBuildOutput buildOutput = new BuildOutput(testClass);\n\t\t\tinvocationContexts.add(new GradleVersionTestTemplateInvocationContext(version, false, buildOutput));\n\t\t\tboolean configurationCache = gradleCompatibility.configurationCache();\n\t\t\tif (configurationCache && GradleVersion.version(version).equals(highestVersion)) {\n\t\t\t\tinvocationContexts.add(new GradleVersionTestTemplateInvocationContext(version, true, buildOutput));\n\t\t\t}\n\t\t\treturn invocationContexts.stream();\n\t\t});\n\t}\n\n\t@Override\n\tpublic boolean supportsTestTemplate(ExtensionContext context) {\n\t\treturn true;\n\t}\n\n\tprivate static final class GradleVersionTestTemplateInvocationContext implements TestTemplateInvocationContext {\n\n\t\tprivate final BuildOutput buildOutput;\n\n\t\tprivate final String gradleVersion;\n\n\t\tprivate final boolean configurationCache;\n\n\t\tGradleVersionTestTemplateInvocationContext(String gradleVersion, boolean configurationCache,\n\t\t\t\tBuildOutput buildOutput) {\n\t\t\tthis.buildOutput = buildOutput;\n\t\t\tthis.gradleVersion = gradleVersion;\n\t\t\tthis.configurationCache = configurationCache;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDisplayName(int invocationIndex) {\n\t\t\treturn \"Gradle \" + this.gradleVersion + ((this.configurationCache) ? \" --configuration-cache\" : \"\");\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Extension> getAdditionalExtensions() {\n\t\t\tGradleBuild gradleBuild = new PluginClasspathGradleBuild(this.buildOutput)\n\t\t\t\t.gradleVersion(this.gradleVersion);\n\t\t\tif (this.configurationCache) {\n\t\t\t\tgradleBuild.configurationCache();\n\t\t\t}\n\t\t\treturn Arrays.asList(new GradleBuildFieldSetter(gradleBuild), new GradleBuildExtension());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleMultiDslExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.junit;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;\n\nimport org.springframework.boot.gradle.testkit.PluginClasspathGradleBuild;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.gradle.testkit.Dsl;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuildExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleVersions;\n\n/**\n * {@link Extension} that runs {@link TestTemplate templated tests} against the Groovy and\n * Kotlin DSLs. Test classes using the extension most have a non-private non-final\n * {@link GradleBuild} field named {@code gradleBuild}.\n *\n * @author Andy Wilkinson\n */\npublic class GradleMultiDslExtension implements TestTemplateInvocationContextProvider {\n\n\t@Override\n\tpublic Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {\n\t\tBuildOutput buildOutput = new BuildOutput(context.getRequiredTestClass());\n\t\treturn Stream.of(Dsl.values()).map((dsl) -> new DslTestTemplateInvocationContext(buildOutput, dsl));\n\t}\n\n\t@Override\n\tpublic boolean supportsTestTemplate(ExtensionContext context) {\n\t\treturn true;\n\t}\n\n\tprivate static final class DslTestTemplateInvocationContext implements TestTemplateInvocationContext {\n\n\t\tprivate final BuildOutput buildOutput;\n\n\t\tprivate final Dsl dsl;\n\n\t\tDslTestTemplateInvocationContext(BuildOutput buildOutput, Dsl dsl) {\n\t\t\tthis.buildOutput = buildOutput;\n\t\t\tthis.dsl = dsl;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Extension> getAdditionalExtensions() {\n\t\t\tPluginClasspathGradleBuild gradleBuild = new PluginClasspathGradleBuild(this.buildOutput, this.dsl);\n\t\t\tif (this.dsl == Dsl.KOTLIN) {\n\t\t\t\tgradleBuild.kotlin();\n\t\t\t}\n\t\t\tgradleBuild.gradleVersion(GradleVersions.minimumCompatible());\n\t\t\treturn Arrays.asList(new GradleBuildFieldSetter(gradleBuild), new GradleBuildExtension());\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDisplayName(int invocationIndex) {\n\t\t\treturn this.dsl.getName();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/GradleProjectBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.junit;\n\nimport java.io.File;\n\nimport org.gradle.api.Project;\nimport org.gradle.testfixtures.ProjectBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Helper class to build Gradle {@link Project Projects} for test fixtures. Wraps\n * functionality of Gradle's own {@link ProjectBuilder}.\n *\n * @author Christoph Dreis\n */\npublic final class GradleProjectBuilder {\n\n\tprivate @Nullable File projectDir;\n\n\tprivate @Nullable String name;\n\n\tprivate GradleProjectBuilder() {\n\t}\n\n\tpublic static GradleProjectBuilder builder() {\n\t\treturn new GradleProjectBuilder();\n\t}\n\n\tpublic GradleProjectBuilder withProjectDir(File dir) {\n\t\tthis.projectDir = dir;\n\t\treturn this;\n\t}\n\n\tpublic GradleProjectBuilder withName(String name) {\n\t\tthis.name = name;\n\t\treturn this;\n\t}\n\n\tpublic Project build() {\n\t\tAssert.notNull(this.projectDir, \"ProjectDir must not be null\");\n\t\tProjectBuilder builder = ProjectBuilder.builder();\n\t\tbuilder.withProjectDir(this.projectDir);\n\t\tFile userHome = new File(this.projectDir, \"userHome\");\n\t\tbuilder.withGradleUserHomeDir(userHome);\n\t\tif (StringUtils.hasText(this.name)) {\n\t\t\tbuilder.withName(this.name);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/junit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.gradle.junit;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.gradle;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.gradle.util.GradleVersion;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ApplicationPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass ApplicationPluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid noBootDistributionWithoutApplicationPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"distributionExists\", \"-PdistributionName=boot\").getOutput())\n\t\t\t.contains(\"boot exists = false\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingApplicationPluginCreatesBootDistribution() {\n\t\tassertThat(this.gradleBuild.build(\"distributionExists\", \"-PdistributionName=boot\", \"-PapplyApplicationPlugin\")\n\t\t\t.getOutput()).contains(\"boot exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid noBootStartScriptsTaskWithoutApplicationPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=bootStartScripts\").getOutput())\n\t\t\t.contains(\"bootStartScripts exists = false\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingApplicationPluginCreatesBootStartScriptsTask() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=bootStartScripts\", \"-PapplyApplicationPlugin\")\n\t\t\t.getOutput()).contains(\"bootStartScripts exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid createsBootStartScriptsTaskUsesApplicationPluginsDefaultJvmOpts() {\n\t\tassertThat(this.gradleBuild.build(\"startScriptsDefaultJvmOpts\", \"-PapplyApplicationPlugin\").getOutput())\n\t\t\t.contains(\"bootStartScripts defaultJvmOpts = [-Dcom.example.a=alpha, -Dcom.example.b=bravo]\");\n\t}\n\n\t@TestTemplate\n\tvoid zipDistributionForJarCanBeBuilt() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootDistZip\").task(\":bootDistZip\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\tFile distribution = new File(this.gradleBuild.getProjectDir(), \"build/distributions/\" + name + \"-boot.zip\");\n\t\tassertThat(distribution).isFile();\n\t\tassertThat(zipEntryNames(distribution)).containsExactlyInAnyOrder(name + \"-boot/\", name + \"-boot/lib/\",\n\t\t\t\tname + \"-boot/lib/\" + name + \".jar\", name + \"-boot/bin/\", name + \"-boot/bin/\" + name,\n\t\t\t\tname + \"-boot/bin/\" + name + \".bat\");\n\t}\n\n\t@TestTemplate\n\tvoid tarDistributionForJarCanBeBuilt() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootDistTar\").task(\":bootDistTar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\tFile distribution = new File(this.gradleBuild.getProjectDir(), \"build/distributions/\" + name + \"-boot.tar\");\n\t\tassertThat(distribution).isFile();\n\t\tassertThat(tarEntryNames(distribution)).containsExactlyInAnyOrder(name + \"-boot/\", name + \"-boot/lib/\",\n\t\t\t\tname + \"-boot/lib/\" + name + \".jar\", name + \"-boot/bin/\", name + \"-boot/bin/\" + name,\n\t\t\t\tname + \"-boot/bin/\" + name + \".bat\");\n\t}\n\n\t@TestTemplate\n\tvoid zipDistributionForWarCanBeBuilt() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootDistZip\").task(\":bootDistZip\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\tFile distribution = new File(this.gradleBuild.getProjectDir(), \"build/distributions/\" + name + \"-boot.zip\");\n\t\tassertThat(distribution).isFile();\n\t\tassertThat(zipEntryNames(distribution)).containsExactlyInAnyOrder(name + \"-boot/\", name + \"-boot/lib/\",\n\t\t\t\tname + \"-boot/lib/\" + name + \".war\", name + \"-boot/bin/\", name + \"-boot/bin/\" + name,\n\t\t\t\tname + \"-boot/bin/\" + name + \".bat\");\n\t}\n\n\t@TestTemplate\n\tvoid tarDistributionForWarCanBeBuilt() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootDistTar\").task(\":bootDistTar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\tFile distribution = new File(this.gradleBuild.getProjectDir(), \"build/distributions/\" + name + \"-boot.tar\");\n\t\tassertThat(distribution).isFile();\n\t\tassertThat(tarEntryNames(distribution)).containsExactlyInAnyOrder(name + \"-boot/\", name + \"-boot/lib/\",\n\t\t\t\tname + \"-boot/lib/\" + name + \".war\", name + \"-boot/bin/\", name + \"-boot/bin/\" + name,\n\t\t\t\tname + \"-boot/bin/\" + name + \".bat\");\n\t}\n\n\t@TestTemplate\n\tvoid applicationNameCanBeUsedToCustomizeDistributionName() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootDistTar\").task(\":bootDistTar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile distribution = new File(this.gradleBuild.getProjectDir(), \"build/distributions/custom-boot.tar\");\n\t\tassertThat(distribution).isFile();\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\tassertThat(tarEntryNames(distribution)).containsExactlyInAnyOrder(\"custom-boot/\", \"custom-boot/lib/\",\n\t\t\t\t\"custom-boot/lib/\" + name + \".jar\", \"custom-boot/bin/\", \"custom-boot/bin/custom\",\n\t\t\t\t\"custom-boot/bin/custom.bat\");\n\t}\n\n\t@TestTemplate\n\tvoid scriptsHaveCorrectPermissions() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(\"bootDistTar\").task(\":bootDistTar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\tFile distribution = new File(this.gradleBuild.getProjectDir(), \"build/distributions/\" + name + \"-boot.tar\");\n\t\tassertThat(distribution).isFile();\n\t\ttarEntries(distribution, (entry) -> {\n\t\t\tint filePermissions = entry.getMode() & 0777;\n\t\t\tif (entry.isFile() && !entry.getName().startsWith(name + \"-boot/bin/\")) {\n\t\t\t\tassertThat(filePermissions).isEqualTo(0644);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tassertThat(filePermissions).isEqualTo(0755);\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid taskConfigurationIsAvoided() throws IOException {\n\t\tBuildResult result = this.gradleBuild.build(\"help\");\n\t\tString output = result.getOutput();\n\t\tBufferedReader reader = new BufferedReader(new StringReader(output));\n\t\tString line;\n\t\tSet<String> configured = new HashSet<>();\n\t\twhile ((line = reader.readLine()) != null) {\n\t\t\tif (line.startsWith(\"Configuring :\")) {\n\t\t\t\tconfigured.add(line.substring(\"Configuring :\".length()));\n\t\t\t}\n\t\t}\n\t\tif (GradleVersion.version(this.gradleBuild.getGradleVersion()).compareTo(GradleVersion.version(\"7.3.3\")) < 0) {\n\t\t\tassertThat(configured).containsExactly(\"help\");\n\t\t}\n\t\telse {\n\t\t\tassertThat(configured).containsExactlyInAnyOrder(\"help\", \"clean\");\n\t\t}\n\t}\n\n\tprivate List<String> zipEntryNames(File distribution) throws IOException {\n\t\tList<String> entryNames = new ArrayList<>();\n\t\ttry (ZipFile zipFile = new ZipFile(distribution)) {\n\t\t\tEnumeration<? extends ZipEntry> entries = zipFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tentryNames.add(entries.nextElement().getName());\n\t\t\t}\n\t\t}\n\t\treturn entryNames;\n\t}\n\n\tprivate List<String> tarEntryNames(File distribution) throws IOException {\n\t\tList<String> entryNames = new ArrayList<>();\n\t\ttry (TarArchiveInputStream input = new TarArchiveInputStream(new FileInputStream(distribution))) {\n\t\t\tTarArchiveEntry entry;\n\t\t\twhile ((entry = input.getNextEntry()) != null) {\n\t\t\t\tentryNames.add(entry.getName());\n\t\t\t}\n\t\t}\n\t\treturn entryNames;\n\t}\n\n\tprivate void tarEntries(File distribution, Consumer<TarArchiveEntry> consumer) throws IOException {\n\t\ttry (TarArchiveInputStream input = new TarArchiveInputStream(new FileInputStream(distribution))) {\n\t\t\tTarArchiveEntry entry;\n\t\t\twhile ((entry = input.getNextEntry()) != null) {\n\t\t\t\tconsumer.accept(entry);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/CyclonedxPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CyclonedxPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass CyclonedxPluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid sbomIsIncludedInUberJar() throws IOException {\n\t\tsbomIsIncludedInUberArchive(\"bootJar\", \"\");\n\t}\n\n\t@TestTemplate\n\tvoid sbomIsIncludedInUberWar() throws IOException {\n\t\tsbomIsIncludedInUberArchive(\"bootWar\", \"WEB-INF/classes/\");\n\t}\n\n\tprivate void sbomIsIncludedInUberArchive(String taskName, String sbomLocationPrefix) throws IOException {\n\t\tBuildResult result = this.gradleBuild.expectDeprecationWarningsWithAtLeastVersion(\"7.6.6\").build(taskName);\n\t\tBuildTask task = result.task(\":cyclonedxBom\");\n\t\tassertThat(task).isNotNull().extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile[] libs = new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles();\n\t\tassertThat(libs).hasSize(1);\n\t\ttry (JarFile jar = new JarFile(libs[0])) {\n\t\t\tassertThat(jar.getManifest().getMainAttributes().getValue(\"Sbom-Format\")).isEqualTo(\"CycloneDX\");\n\t\t\tString sbomLocation = jar.getManifest().getMainAttributes().getValue(\"Sbom-Location\");\n\t\t\tassertThat(sbomLocation).isEqualTo(sbomLocationPrefix + \"META-INF/sbom/application.cdx.json\");\n\t\t\tList<String> entryNames = jar.stream().map(JarEntry::getName).toList();\n\t\t\tassertThat(entryNames).contains(sbomLocation);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the configuration applied by\n * {@link DependencyManagementPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass DependencyManagementPluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid noDependencyManagementIsAppliedByDefault() {\n\t\tBuildTask task = this.gradleBuild.build(\"doesNotHaveDependencyManagement\")\n\t\t\t.task(\":doesNotHaveDependencyManagement\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid bomIsImportedWhenDependencyManagementPluginIsApplied() {\n\t\tBuildTask task = this.gradleBuild.build(\"hasDependencyManagement\", \"-PapplyDependencyManagementPlugin\")\n\t\t\t.task(\":hasDependencyManagement\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.jar.JarOutputStream;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.gradle.util.GradleVersion;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JavaPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility(configurationCache = true)\nclass JavaPluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid noBootJarTaskWithoutJavaPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"tasks\").getOutput()).doesNotContain(\"bootJar\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingJavaPluginCreatesBootJarTask() {\n\t\tassertThat(this.gradleBuild.build(\"tasks\").getOutput()).contains(\"bootJar\");\n\t}\n\n\t@TestTemplate\n\tvoid noBootRunTaskWithoutJavaPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"tasks\").getOutput()).doesNotContain(\"bootRun\");\n\t}\n\n\t@TestTemplate\n\tvoid noBootTestRunTaskWithoutJavaPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"tasks\").getOutput()).doesNotContain(\"bootTestRun\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingJavaPluginCreatesBootRunTask() {\n\t\tassertThat(this.gradleBuild.build(\"tasks\").getOutput()).contains(\"bootRun\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingJavaPluginCreatesBootTestRunTask() {\n\t\tassertThat(this.gradleBuild.build(\"tasks\").getOutput()).contains(\"bootTestRun\");\n\t}\n\n\t@TestTemplate\n\tvoid javaCompileTasksUseUtf8Encoding() {\n\t\tassertThat(this.gradleBuild.build(\"build\").getOutput()).contains(\"compileJava = UTF-8\")\n\t\t\t.contains(\"compileTestJava = UTF-8\");\n\t}\n\n\t@TestTemplate\n\tvoid javaCompileTasksUseParametersCompilerFlagByDefault() {\n\t\tassertThat(this.gradleBuild.build(\"build\").getOutput()).contains(\"compileJava compiler args: [-parameters]\")\n\t\t\t.contains(\"compileTestJava compiler args: [-parameters]\");\n\t}\n\n\t@TestTemplate\n\tvoid javaCompileTasksUseParametersAndAdditionalCompilerFlags() {\n\t\tassertThat(this.gradleBuild.build(\"build\").getOutput())\n\t\t\t.contains(\"compileJava compiler args: [-parameters, -Xlint:all]\")\n\t\t\t.contains(\"compileTestJava compiler args: [-parameters, -Xlint:all]\");\n\t}\n\n\t@TestTemplate\n\tvoid javaCompileTasksCanOverrideDefaultParametersCompilerFlag() {\n\t\tassertThat(this.gradleBuild.build(\"build\").getOutput()).contains(\"compileJava compiler args: [-Xlint:all]\")\n\t\t\t.contains(\"compileTestJava compiler args: [-Xlint:all]\");\n\t}\n\n\t@TestTemplate\n\tvoid assembleRunsBootJarAndJar() {\n\t\tBuildResult result = this.gradleBuild.build(\"assemble\");\n\t\tBuildTask bootJar = result.task(\":bootJar\");\n\t\tassertThat(bootJar).isNotNull();\n\t\tassertThat(bootJar.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tBuildTask jar = result.task(\":jar\");\n\t\tassertThat(jar).isNotNull();\n\t\tassertThat(jar.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\tassertThat(buildLibs.listFiles()).containsExactlyInAnyOrder(\n\t\t\t\tnew File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".jar\"),\n\t\t\t\tnew File(buildLibs, this.gradleBuild.getProjectDir().getName() + \"-plain.jar\"));\n\t}\n\n\t@TestTemplate\n\tvoid errorMessageIsHelpfulWhenMainClassCannotBeResolved() {\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"build\", \"-PapplyJavaPlugin\");\n\t\tBuildTask task = result.task(\":bootJar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).contains(\"Main class name has not been configured and it could not be resolved\");\n\t}\n\n\t@TestTemplate\n\tvoid additionalMetadataLocationsConfiguredWhenProcessorIsPresent() throws IOException {\n\t\tcreateMinimalMainSource();\n\t\tFile libs = new File(this.gradleBuild.getProjectDir(), \"libs\");\n\t\tlibs.mkdirs();\n\t\tnew JarOutputStream(new FileOutputStream(new File(libs, \"spring-boot-configuration-processor-1.2.3.jar\")))\n\t\t\t.close();\n\t\tBuildResult result = this.gradleBuild.build(\"compileJava\");\n\t\tBuildTask task = result.task(\":compileJava\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"compileJava compiler args: [-parameters, -Aorg.springframework.boot.\"\n\t\t\t\t+ \"configurationprocessor.additionalMetadataLocations=\"\n\t\t\t\t+ new File(this.gradleBuild.getProjectDir(), \"src/main/resources\").getCanonicalPath());\n\t}\n\n\t@TestTemplate\n\tvoid additionalMetadataLocationsNotConfiguredWhenProcessorIsAbsent() throws IOException {\n\t\tcreateMinimalMainSource();\n\t\tBuildResult result = this.gradleBuild.build(\"compileJava\");\n\t\tBuildTask task = result.task(\":compileJava\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"compileJava compiler args: [-parameters]\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingJavaPluginCreatesDevelopmentOnlyConfiguration() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).contains(\"developmentOnly exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingJavaPluginCreatesTestAndDevelopmentOnlyConfiguration() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).contains(\"testAndDevelopmentOnly exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid testCompileClasspathIncludesTestAndDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid testRuntimeClasspathIncludesTestAndDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid testCompileClasspathDoesNotIncludeDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).doesNotContain(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid testRuntimeClasspathDoesNotIncludeDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).doesNotContain(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid compileClasspathDoesNotIncludeTestAndDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).doesNotContain(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid runtimeClasspathIncludesTestAndDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid compileClasspathDoesNotIncludeDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).doesNotContain(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid runtimeClasspathIncludesDevelopmentOnlyDependencies() {\n\t\tassertThat(this.gradleBuild.build(\"help\").getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath() {\n\t\tString output = this.gradleBuild.build(\"build\").getOutput();\n\t\tMatcher matcher = Pattern.compile(\"runtimeClasspath: (\\\\[.*])\").matcher(output);\n\t\tassertThat(matcher.find()).as(\"%s found in %s\", matcher, output).isTrue();\n\t\tString attributes = matcher.group(1);\n\t\tassertThat(output).contains(\"productionRuntimeClasspath: \" + attributes);\n\t}\n\n\t@TestTemplate\n\tvoid productionRuntimeClasspathIsConfiguredWithResolvabilityAndConsumabilityThatMatchesRuntimeClasspath() {\n\t\tString output = this.gradleBuild.build(\"build\").getOutput();\n\t\tassertThat(output).contains(\"runtimeClasspath canBeResolved: true\");\n\t\tassertThat(output).contains(\"runtimeClasspath canBeConsumed: false\");\n\t\tassertThat(output).contains(\"productionRuntimeClasspath canBeResolved: true\");\n\t\tassertThat(output).contains(\"productionRuntimeClasspath canBeConsumed: false\");\n\t}\n\n\t@TestTemplate\n\tvoid taskConfigurationIsAvoided() throws IOException {\n\t\tBuildResult result = this.gradleBuild.build(\"help\");\n\t\tString output = result.getOutput();\n\t\tBufferedReader reader = new BufferedReader(new StringReader(output));\n\t\tString line;\n\t\tSet<String> configured = new HashSet<>();\n\t\twhile ((line = reader.readLine()) != null) {\n\t\t\tif (line.startsWith(\"Configuring :\")) {\n\t\t\t\tconfigured.add(line.substring(\"Configuring :\".length()));\n\t\t\t}\n\t\t}\n\t\tif (!this.gradleBuild.isConfigurationCache() && GradleVersion.version(this.gradleBuild.getGradleVersion())\n\t\t\t.compareTo(GradleVersion.version(\"7.3.3\")) < 0) {\n\t\t\tassertThat(configured).containsExactly(\"help\");\n\t\t}\n\t\telse {\n\t\t\tassertThat(configured).containsExactlyInAnyOrder(\"help\", \"clean\");\n\t\t}\n\t}\n\n\tprivate void createMinimalMainSource() throws IOException {\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/main/java/com/example\");\n\t\texamplePackage.mkdirs();\n\t\tnew File(examplePackage, \"Application.java\").createNewFile();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.testkit.PluginClasspathGradleBuild;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuildExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link KotlinPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@DisabledForJreRange(min = JRE.JAVA_20)\n@ExtendWith(GradleBuildExtension.class)\nclass KotlinPluginActionIntegrationTests {\n\n\tGradleBuild gradleBuild = new PluginClasspathGradleBuild(new BuildOutput(getClass())).kotlin();\n\n\t@Test\n\tvoid noKotlinVersionPropertyWithoutKotlinPlugin() {\n\t\tassertThat(this.gradleBuild.build(\"kotlinVersion\").getOutput()).contains(\"Kotlin version: none\");\n\t}\n\n\t@Test\n\tvoid kotlinVersionPropertyIsSet() {\n\t\texpectConfigurationCacheRequestedDeprecationWarning();\n\t\tString output = this.gradleBuild.build(\"kotlinVersion\", \"dependencies\", \"--configuration\", \"compileClasspath\")\n\t\t\t.getOutput();\n\t\tassertThat(output).containsPattern(\"Kotlin version: [0-9]\\\\.[0-9]\\\\.[0-9]+\");\n\t}\n\n\t@Test\n\tvoid kotlinCompileTasksUseJavaParametersFlagByDefault() {\n\t\texpectConfigurationCacheRequestedDeprecationWarning();\n\t\tassertThat(this.gradleBuild.build(\"kotlinCompileTasksJavaParameters\").getOutput())\n\t\t\t.contains(\"compileKotlin java parameters: true\")\n\t\t\t.contains(\"compileTestKotlin java parameters: true\");\n\t}\n\n\t@Test\n\tvoid kotlinCompileTasksCanOverrideDefaultJavaParametersFlag() {\n\t\texpectConfigurationCacheRequestedDeprecationWarning();\n\t\tassertThat(this.gradleBuild.build(\"kotlinCompileTasksJavaParameters\").getOutput())\n\t\t\t.contains(\"compileKotlin java parameters: false\")\n\t\t\t.contains(\"compileTestKotlin java parameters: false\");\n\t}\n\n\t@Test\n\tvoid taskConfigurationIsAvoided() throws IOException {\n\t\texpectConfigurationCacheRequestedDeprecationWarning();\n\t\tBuildResult result = this.gradleBuild.build(\"help\");\n\t\tString output = result.getOutput();\n\t\tBufferedReader reader = new BufferedReader(new StringReader(output));\n\t\tString line;\n\t\tSet<String> configured = new HashSet<>();\n\t\twhile ((line = reader.readLine()) != null) {\n\t\t\tif (line.startsWith(\"Configuring :\")) {\n\t\t\t\tconfigured.add(line.substring(\"Configuring :\".length()));\n\t\t\t}\n\t\t}\n\t\tassertThat(configured).containsExactlyInAnyOrder(\"help\", \"clean\");\n\t}\n\n\t@Test\n\tvoid compileAotJavaHasTransitiveRuntimeDependenciesOnItsClasspathWhenUsingKotlin() {\n\t\texpectConfigurationCacheRequestedDeprecationWarning();\n\t\texpectResolvableUsageIsAlreadyAllowedWarning();\n\t\tString output = this.gradleBuild.build(\"compileAotJavaClasspath\").getOutput();\n\t\tassertThat(output).contains(\"org.jboss.logging\" + File.separatorChar + \"jboss-logging\");\n\t}\n\n\t@Test\n\tvoid compileAotTestJavaHasTransitiveRuntimeDependenciesOnItsClasspathWhenUsingKotlin() {\n\t\texpectConfigurationCacheRequestedDeprecationWarning();\n\t\texpectResolvableUsageIsAlreadyAllowedWarning();\n\t\tString output = this.gradleBuild.build(\"compileAotTestJavaClasspath\").getOutput();\n\t\tassertThat(output).contains(\"org.jboss.logging\" + File.separatorChar + \"jboss-logging\");\n\t}\n\n\tprivate void expectConfigurationCacheRequestedDeprecationWarning() {\n\t\tthis.gradleBuild.expectDeprecationWarningsWithAtLeastVersion(\"8.14\")\n\t\t\t.expectDeprecationMessages(\"The StartParameter.isConfigurationCacheRequested property has been deprecated\");\n\t}\n\n\tprivate void expectResolvableUsageIsAlreadyAllowedWarning() {\n\t\tthis.gradleBuild.expectDeprecationWarningsWithAtLeastVersion(\"8.4\")\n\t\t\t.expectDeprecationMessages(\"The resolvable usage is already allowed on configuration \"\n\t\t\t\t\t+ \"':aotRuntimeClasspath'. This behavior has been deprecated.\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link NativeImagePluginAction}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@GradleCompatibility(minimumVersion = \"8.3\")\nclass NativeImagePluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid applyingNativeImagePluginAppliesAotPlugin() {\n\t\tassertThat(this.gradleBuild.build(\"aotPluginApplied\").getOutput())\n\t\t\t.contains(\"org.springframework.boot.aot applied = true\");\n\t}\n\n\t@TestTemplate\n\tvoid reachabilityMetadataConfigurationFilesAreCopiedToJar() throws IOException {\n\t\twriteDummySpringApplicationAotProcessorMainClass();\n\t\tBuildResult result = this.gradleBuild.build(\"bootJar\");\n\t\tBuildTask task = result.task(\":bootJar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\tFile jarFile = new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(buildLibs.listFiles()).contains(jarFile);\n\t\tassertThat(getEntryNames(jarFile)).contains(\n\t\t\t\t\"META-INF/native-image/ch.qos.logback/logback-classic/1.2.11/reflect-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/jni-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/proxy-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/reflect-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/resource-config.json\");\n\t}\n\n\t@TestTemplate\n\tvoid reachabilityMetadataConfigurationFilesFromFileRepositoryAreCopiedToJar() throws IOException {\n\t\twriteDummySpringApplicationAotProcessorMainClass();\n\t\tFileSystemUtils.copyRecursively(new File(\"src/test/resources/reachability-metadata-repository\"),\n\t\t\t\tnew File(this.gradleBuild.getProjectDir(), \"reachability-metadata-repository\"));\n\t\tBuildResult result = this.gradleBuild.build(\"bootJar\");\n\t\tBuildTask task = result.task(\":bootJar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\tFile jarFile = new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".jar\");\n\t\tassertThat(buildLibs.listFiles()).contains(jarFile);\n\t\tassertThat(getEntryNames(jarFile)).contains(\n\t\t\t\t\"META-INF/native-image/ch.qos.logback/logback-classic/1.2.11/reflect-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/jni-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/proxy-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/reflect-config.json\",\n\t\t\t\t\"META-INF/native-image/org.jline/jline/3.21.0/resource-config.json\");\n\t}\n\n\t@TestTemplate\n\tvoid developmentOnlyDependenciesDoNotAppearInNativeImageClasspath() {\n\t\twriteDummySpringApplicationAotProcessorMainClass();\n\t\tBuildResult result = this.gradleBuild.build(\"checkNativeImageClasspath\");\n\t\tassertThat(result.getOutput()).doesNotContain(\"commons-lang\");\n\t}\n\n\t@TestTemplate\n\tvoid testAndDevelopmentOnlyDependenciesDoNotAppearInNativeImageClasspath() {\n\t\twriteDummySpringApplicationAotProcessorMainClass();\n\t\tBuildResult result = this.gradleBuild.build(\"checkNativeImageClasspath\");\n\t\tassertThat(result.getOutput()).doesNotContain(\"commons-lang\");\n\t}\n\n\t@TestTemplate\n\tvoid classesGeneratedDuringAotProcessingAreOnTheNativeImageClasspath() {\n\t\tBuildResult result = this.gradleBuild.build(\"checkNativeImageClasspath\");\n\t\tassertThat(result.getOutput()).contains(projectPath(\"build/classes/java/aot\"),\n\t\t\t\tprojectPath(\"build/resources/aot\"), projectPath(\"build/generated/aotClasses\"));\n\t}\n\n\t@TestTemplate\n\tvoid classesGeneratedDuringAotTestProcessingAreOnTheTestNativeImageClasspath() {\n\t\tBuildResult result = this.gradleBuild\n\t\t\t.scriptProperty(\"junitVersion\", TestTemplate.class.getPackage().getImplementationVersion())\n\t\t\t.build(\"checkTestNativeImageClasspath\");\n\t\tassertThat(result.getOutput()).contains(projectPath(\"build/classes/java/aotTest\"),\n\t\t\t\tprojectPath(\"build/resources/aotTest\"), projectPath(\"build/generated/aotTestClasses\"));\n\t}\n\n\t@TestTemplate\n\tvoid nativeEntryIsAddedToManifest() throws IOException {\n\t\twriteDummySpringApplicationAotProcessorMainClass();\n\t\tBuildResult result = this.gradleBuild.build(\"bootJar\");\n\t\tBuildTask task = result.task(\":bootJar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\ttry (JarFile jarFile = new JarFile(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".jar\"))) {\n\t\t\tManifest manifest = jarFile.getManifest();\n\t\t\tassertThat(manifest.getMainAttributes().getValue(\"Spring-Boot-Native-Processed\")).isEqualTo(\"true\");\n\t\t}\n\t}\n\n\tprivate String projectPath(String path) {\n\t\ttry {\n\t\t\treturn new File(this.gradleBuild.getProjectDir(), path).getCanonicalPath();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void writeDummySpringApplicationAotProcessorMainClass() {\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/main/java/org/springframework/boot\");\n\t\texamplePackage.mkdirs();\n\t\tFile main = new File(examplePackage, \"SpringApplicationAotProcessor.java\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(main))) {\n\t\t\twriter.println(\"package org.springframework.boot;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import java.io.IOException;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"public class SpringApplicationAotProcessor {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    public static void main(String[] args) {\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprotected List<String> getEntryNames(File file) throws IOException {\n\t\tList<String> entryNames = new ArrayList<>();\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tentryNames.add(entries.nextElement().getName());\n\t\t\t}\n\t\t}\n\t\treturn entryNames;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/OnlyDependencyManagementIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for configuring a project to only use Spring Boot's dependency\n * management.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass OnlyDependencyManagementIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid dependencyManagementCanBeConfiguredUsingCoordinatesConstant() {\n\t\tassertThat(this.gradleBuild.build(\"dependencyManagement\").getOutput())\n\t\t\t.contains(\"org.springframework.boot:spring-boot-starter \");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ProtobufPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ProtobufPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass ProtobufPluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid configuresProtocArtifact() {\n\t\tassertThat(this.gradleBuild.build(\"protocArtifact\").getOutput())\n\t\t\t.contains(\"protoc artifact: 'com.google.protobuf:protoc'\");\n\t}\n\n\t@TestTemplate\n\tvoid configuresGrpcPlugin() {\n\t\tassertThat(this.gradleBuild.build(\"grpcPlugin\").getOutput())\n\t\t\t.contains(\"grpc plugin artifact: 'io.grpc:protoc-gen-grpc-java'\");\n\t}\n\n\t@TestTemplate\n\tvoid configuresGenerateProtoTasksToOmitGenerated() {\n\t\tassertThat(this.gradleBuild.build(\"generateProtoTasksGrpcPluginOptions\").getOutput())\n\t\t\t.contains(\"generateProto: [[@generated=omit]]\")\n\t\t\t.contains(\"generateTestProto: [[@generated=omit]]\");\n\t}\n\n\t@TestTemplate\n\tvoid alignsVersionOfProtocDependency() {\n\t\tassertThat(this.gradleBuild.build(\"dependencies\", \"--configuration\", \"protobufToolsLocator_protoc\").getOutput())\n\t\t\t.contains(\"com.google.protobuf:protoc:null -> 4.34.0\");\n\t}\n\n\t@TestTemplate\n\tvoid alignsVersionOfGrpcDependency() {\n\t\tassertThat(this.gradleBuild.build(\"dependencies\", \"--configuration\", \"protobufToolsLocator_grpc\").getOutput())\n\t\t\t.contains(\"io.grpc:protoc-gen-grpc-java:null -> 1.79.0\");\n\t}\n\n\t@TestTemplate\n\tvoid usesVersionOfProtocDependencyWhenSpecified() {\n\t\tassertThat(this.gradleBuild.build(\"dependencies\", \"--configuration\", \"protobufToolsLocator_protoc\").getOutput())\n\t\t\t.contains(\"com.google.protobuf:protoc:4.33.5\");\n\t}\n\n\t@TestTemplate\n\tvoid usesVersionOfGrpcPluginDependencyWhenSpecified() {\n\t\tassertThat(this.gradleBuild.build(\"dependencies\", \"--configuration\", \"protobufToolsLocator_grpc\").getOutput())\n\t\t\t.contains(\"io.grpc:protoc-gen-grpc-java:1.78.0\");\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.util.List;\n\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.EnabledOnJre;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Integration tests for {@link SpringBootAotPlugin}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass SpringBootAotPluginIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid noProcessAotTaskWithoutAotPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=processAot\").getOutput())\n\t\t\t.contains(\"processAot exists = false\");\n\t}\n\n\t@TestTemplate\n\tvoid noProcessTestAotTaskWithoutAotPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=processTestAot\").getOutput())\n\t\t\t.contains(\"processTestAot exists = false\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingAotPluginCreatesProcessAotTask() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=processAot\").getOutput())\n\t\t\t.contains(\"processAot exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingAotPluginCreatesProcessTestAotTask() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=processTestAot\").getOutput())\n\t\t\t.contains(\"processTestAot exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid processAotHasLibraryResourcesOnItsClasspath() throws IOException {\n\t\tFile settings = new File(this.gradleBuild.getProjectDir(), \"settings.gradle\");\n\t\tFiles.write(settings.toPath(), List.of(\"include 'library'\"));\n\t\tFile library = new File(this.gradleBuild.getProjectDir(), \"library\");\n\t\tlibrary.mkdirs();\n\t\tFiles.write(library.toPath().resolve(\"build.gradle\"), List.of(\"plugins {\", \"    id 'java-library'\", \"}\"));\n\t\tassertThat(this.gradleBuild.build(\"processAotClasspath\").getOutput()).contains(\"library.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid processTestAotHasLibraryResourcesOnItsClasspath() throws IOException {\n\t\tFile settings = new File(this.gradleBuild.getProjectDir(), \"settings.gradle\");\n\t\tFiles.write(settings.toPath(), List.of(\"include 'library'\"));\n\t\tFile library = new File(this.gradleBuild.getProjectDir(), \"library\");\n\t\tlibrary.mkdirs();\n\t\tFiles.write(library.toPath().resolve(\"build.gradle\"), List.of(\"plugins {\", \"    id 'java-library'\", \"}\"));\n\t\tassertThat(this.gradleBuild.build(\"processTestAotClasspath\").getOutput()).contains(\"library.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid processAotHasTransitiveRuntimeDependenciesOnItsClasspath() {\n\t\tString output = this.gradleBuild.build(\"processAotClasspath\").getOutput();\n\t\tassertThat(output).contains(\"org.jboss.logging\" + File.separatorChar + \"jboss-logging\");\n\t}\n\n\t@TestTemplate\n\tvoid processTestAotHasTransitiveRuntimeDependenciesOnItsClasspath() {\n\t\tString output = this.gradleBuild.build(\"processTestAotClasspath\").getOutput();\n\t\tassertThat(output).contains(\"org.jboss.logging\" + File.separatorChar + \"jboss-logging\");\n\t}\n\n\t@TestTemplate\n\tvoid processAotDoesNotHaveDevelopmentOnlyDependenciesOnItsClasspath() {\n\t\tString output = this.gradleBuild.build(\"processAotClasspath\").getOutput();\n\t\tassertThat(output).doesNotContain(\"commons-lang\");\n\t}\n\n\t@TestTemplate\n\tvoid processTestAotDoesNotHaveDevelopmentOnlyDependenciesOnItsClasspath() {\n\t\tString output = this.gradleBuild.build(\"processTestAotClasspath\").getOutput();\n\t\tassertThat(output).doesNotContain(\"commons-lang\");\n\t}\n\n\t@TestTemplate\n\tvoid processAotDoesNotHaveTestAndDevelopmentOnlyDependenciesOnItsClasspath() {\n\t\tString output = this.gradleBuild.build(\"processAotClasspath\").getOutput();\n\t\tassertThat(output).doesNotContain(\"commons-lang\");\n\t}\n\n\t@TestTemplate\n\tvoid processTestAotHasTestAndDevelopmentOnlyDependenciesOnItsClasspath() {\n\t\tString output = this.gradleBuild.build(\"processTestAotClasspath\").getOutput();\n\t\tassertThat(output).contains(\"commons-lang\");\n\t}\n\n\t@TestTemplate\n\tvoid processAotRunsWhenProjectHasMainSource() throws IOException {\n\t\twriteMainClass(\"org.springframework.boot\", \"SpringApplicationAotProcessor\");\n\t\twriteMainClass(\"com.example\", \"Main\");\n\t\tBuildTask task = this.gradleBuild.build(\"processAot\").task(\":processAot\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid processTestAotIsSkippedWhenProjectHasNoTestSource() {\n\t\tBuildTask task = this.gradleBuild.build(\"processTestAot\").task(\":processTestAot\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.NO_SOURCE);\n\t}\n\n\t// gh-37343\n\t@TestTemplate\n\t@EnabledOnJre(JRE.JAVA_17)\n\tvoid applyingAotPluginDoesNotPreventConfigurationOfJavaToolchainLanguageVersion() {\n\t\tassertThatNoException().isThrownBy(() -> this.gradleBuild.build(\"help\").getOutput());\n\t}\n\n\tprivate void writeMainClass(String packageName, String className) throws IOException {\n\t\tFile java = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"src/main/java/\" + packageName.replace(\".\", \"/\") + \"/\" + className + \".java\");\n\t\tjava.getParentFile().mkdirs();\n\t\tFiles.writeString(java.toPath(), \"\"\"\n\t\t\t\tpackage %s;\n\n\t\t\t\tpublic class %s {\n\n\t\t\t\t\tpublic static void main(String[] args) {\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\t\"\"\".formatted(packageName, className));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.gradle.testkit.PluginClasspathGradleBuild;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuildExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootPlugin}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(GradleBuildExtension.class)\nclass SpringBootPluginIntegrationTests {\n\n\tfinal GradleBuild gradleBuild = new PluginClasspathGradleBuild(new BuildOutput(getClass()));\n\n\t@Test\n\t@DisabledForJreRange(min = JRE.JAVA_24)\n\tvoid failFastWithVersionOfGradle8LowerThanRequired() {\n\t\tBuildResult result = this.gradleBuild.gradleVersion(\"8.13\").buildAndFail();\n\t\tassertThat(result.getOutput()).contains(\n\t\t\t\t\"Spring Boot plugin requires Gradle 8.x (8.14 or later) or 9.x. The current version is Gradle 8.13\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/SpringBootPluginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.File;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.gradle.junit.GradleProjectBuilder;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootPlugin}.\n *\n * @author Martin Chalupa\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"kotlin-daemon-client-*.jar\")\nclass SpringBootPluginTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid bootArchivesConfigurationsCannotBeResolved() {\n\t\tProject project = GradleProjectBuilder.builder().withProjectDir(this.temp).build();\n\t\tproject.getPlugins().apply(SpringBootPlugin.class);\n\t\tConfiguration bootArchives = project.getConfigurations()\n\t\t\t.getByName(SpringBootPlugin.BOOT_ARCHIVES_CONFIGURATION_NAME);\n\t\tassertThat(bootArchives.isCanBeResolved()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.plugin;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.gradle.util.GradleVersion;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JavaPluginAction}.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass WarPluginActionIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid noBootWarTaskWithoutWarPluginApplied() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=bootWar\").getOutput())\n\t\t\t.contains(\"bootWar exists = false\");\n\t}\n\n\t@TestTemplate\n\tvoid applyingWarPluginCreatesBootWarTask() {\n\t\tassertThat(this.gradleBuild.build(\"taskExists\", \"-PtaskName=bootWar\", \"-PapplyWarPlugin\").getOutput())\n\t\t\t.contains(\"bootWar exists = true\");\n\t}\n\n\t@TestTemplate\n\tvoid assembleRunsBootWarAndWar() {\n\t\tBuildResult result = this.gradleBuild.build(\"assemble\");\n\t\tBuildTask bootWar = result.task(\":bootWar\");\n\t\tassertThat(bootWar).isNotNull();\n\t\tassertThat(bootWar.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tBuildTask war = result.task(\":war\");\n\t\tassertThat(war).isNotNull();\n\t\tassertThat(war.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile buildLibs = new File(this.gradleBuild.getProjectDir(), \"build/libs\");\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \".war\"));\n\t\texpected.add(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \"-plain.war\"));\n\t\tif (this.gradleBuild.gradleVersionIsAtLeast(\"9.0-milestone-2\")) {\n\t\t\texpected.add(new File(buildLibs, this.gradleBuild.getProjectDir().getName() + \"-plain.jar\"));\n\t\t}\n\t\tassertThat(buildLibs.listFiles()).containsExactlyInAnyOrderElementsOf(expected);\n\t}\n\n\t@TestTemplate\n\tvoid errorMessageIsHelpfulWhenMainClassCannotBeResolved() {\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"build\", \"-PapplyWarPlugin\");\n\t\tBuildTask task = result.task(\":bootWar\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tassertThat(result.getOutput()).contains(\"Main class name has not been configured and it could not be resolved\");\n\t}\n\n\t@TestTemplate\n\tvoid taskConfigurationIsAvoided() throws IOException {\n\t\tBuildResult result = this.gradleBuild.build(\"help\");\n\t\tString output = result.getOutput();\n\t\tBufferedReader reader = new BufferedReader(new StringReader(output));\n\t\tString line;\n\t\tSet<String> configured = new HashSet<>();\n\t\twhile ((line = reader.readLine()) != null) {\n\t\t\tif (line.startsWith(\"Configuring :\")) {\n\t\t\t\tconfigured.add(line.substring(\"Configuring :\".length()));\n\t\t\t}\n\t\t}\n\t\tif (GradleVersion.version(this.gradleBuild.getGradleVersion()).compareTo(GradleVersion.version(\"7.3.3\")) < 0) {\n\t\t\tassertThat(configured).containsExactly(\"help\");\n\t\t}\n\t\telse {\n\t\t\tassertThat(configured).containsExactlyInAnyOrder(\"help\", \"clean\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.buildinfo;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.time.Instant;\nimport java.util.Properties;\n\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.FileUtils;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the {@link BuildInfo} task.\n *\n * @author Andy Wilkinson\n * @author Vedran Pavic\n */\n@GradleCompatibility(configurationCache = true)\nclass BuildInfoIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid defaultValues() {\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties buildInfoProperties = buildInfoProperties();\n\t\tassertThat(buildInfoProperties).containsKey(\"build.time\");\n\t\tassertThat(buildInfoProperties).doesNotContainKey(\"build.artifact\");\n\t\tassertThat(buildInfoProperties).doesNotContainKey(\"build.group\");\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.name\", this.gradleBuild.getProjectDir().getName());\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.version\", \"unspecified\");\n\t}\n\n\t@TestTemplate\n\tvoid basicExecution() {\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties buildInfoProperties = buildInfoProperties();\n\t\tassertThat(buildInfoProperties).containsKey(\"build.time\");\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.artifact\", \"foo\");\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.group\", \"foo\");\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.additional\", \"foo\");\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.name\", \"foo\");\n\t\tassertThat(buildInfoProperties).containsEntry(\"build.version\", \"0.1.0\");\n\t}\n\n\t@TestTemplate\n\tvoid notUpToDateWhenExecutedTwiceAsTimeChanges() {\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties first = buildInfoProperties();\n\t\tString firstBuildTime = first.getProperty(\"build.time\");\n\t\tassertThat(firstBuildTime).isNotNull();\n\t\ttask = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties second = buildInfoProperties();\n\t\tString secondBuildTime = second.getProperty(\"build.time\");\n\t\tassertThat(secondBuildTime).isNotNull();\n\t\tassertThat(Instant.parse(firstBuildTime)).isBefore(Instant.parse(secondBuildTime));\n\t}\n\n\t@TestTemplate\n\tvoid upToDateWhenExecutedTwiceWithFixedTime() {\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\", \"-PnullTime\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttask = this.gradleBuild.build(\"buildInfo\", \"-PnullTime\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE);\n\t}\n\n\t@TestTemplate\n\tvoid notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedProjectVersion() {\n\t\tBuildTask task = this.gradleBuild.scriptProperty(\"projectVersion\", \"0.1.0\")\n\t\t\t.build(\"buildInfo\")\n\t\t\t.task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttask = this.gradleBuild.scriptProperty(\"projectVersion\", \"0.2.0\").build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedGradlePropertiesProjectVersion() throws IOException {\n\t\tPath gradleProperties = new File(this.gradleBuild.getProjectDir(), \"gradle.properties\").toPath();\n\t\tFiles.writeString(gradleProperties, \"version=0.1.0\", StandardOpenOption.CREATE, StandardOpenOption.WRITE,\n\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFiles.writeString(gradleProperties, \"version=0.2.0\", StandardOpenOption.CREATE, StandardOpenOption.WRITE,\n\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t\ttask = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid reproducibleOutputWithFixedTime() throws IOException, InterruptedException {\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\", \"-PnullTime\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile buildInfoProperties = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"build/buildInfo/META-INF/build-info.properties\");\n\t\tString firstHash = FileUtils.sha1Hash(buildInfoProperties);\n\t\tassertThat(buildInfoProperties.delete()).isTrue();\n\t\tThread.sleep(1500);\n\t\ttask = this.gradleBuild.build(\"buildInfo\", \"-PnullTime\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString secondHash = FileUtils.sha1Hash(buildInfoProperties);\n\t\tassertThat(firstHash).isEqualTo(secondHash);\n\t}\n\n\t@TestTemplate\n\tvoid excludeProperties() {\n\t\tBuildTask task = this.gradleBuild.build(\"buildInfo\").task(\":buildInfo\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tProperties buildInfoProperties = buildInfoProperties();\n\t\tassertThat(buildInfoProperties).doesNotContainKey(\"build.group\");\n\t\tassertThat(buildInfoProperties).doesNotContainKey(\"build.artifact\");\n\t\tassertThat(buildInfoProperties).doesNotContainKey(\"build.version\");\n\t\tassertThat(buildInfoProperties).doesNotContainKey(\"build.name\");\n\t}\n\n\tprivate Properties buildInfoProperties() {\n\t\tFile file = new File(this.gradleBuild.getProjectDir(), \"build/buildInfo/META-INF/build-info.properties\");\n\t\tassertThat(file).isFile();\n\t\tProperties properties = new Properties();\n\t\ttry (FileReader reader = new FileReader(file)) {\n\t\t\tproperties.load(reader);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.buildinfo;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Properties;\n\nimport org.gradle.api.Project;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.gradle.junit.GradleProjectBuilder;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Tests for {@link BuildInfo}.\n *\n * @author Andy Wilkinson\n * @author Vedran Pavic\n */\n@ClassPathExclusions(\"kotlin-daemon-client-*\")\nclass BuildInfoTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid basicExecution() {\n\t\tProperties properties = buildInfoProperties(createTask(createProject(\"test\")));\n\t\tassertThat(properties).containsKey(\"build.time\");\n\t\tassertThat(properties).doesNotContainKey(\"build.artifact\");\n\t\tassertThat(properties).doesNotContainKey(\"build.group\");\n\t\tassertThat(properties).containsEntry(\"build.name\", \"test\");\n\t\tassertThat(properties).containsEntry(\"build.version\", \"unspecified\");\n\t}\n\n\t@Test\n\tvoid customArtifactIsReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProperties().getArtifact().set(\"custom\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.artifact\", \"custom\");\n\t}\n\n\t@Test\n\tvoid artifactCanBeExcludedFromProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getExcludes().addAll(\"artifact\");\n\t\tassertThat(buildInfoProperties(task)).doesNotContainKey(\"build.artifact\");\n\t}\n\n\t@Test\n\tvoid projectGroupIsReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProject().setGroup(\"com.example\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.group\", \"com.example\");\n\t}\n\n\t@Test\n\tvoid customGroupIsReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProperties().getGroup().set(\"com.example\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.group\", \"com.example\");\n\t}\n\n\t@Test\n\tvoid groupCanBeExcludedFromProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getExcludes().add(\"group\");\n\t\tassertThat(buildInfoProperties(task)).doesNotContainKey(\"build.group\");\n\t}\n\n\t@Test\n\tvoid customNameIsReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProperties().getName().set(\"Example\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.name\", \"Example\");\n\t}\n\n\t@Test\n\tvoid nameCanBeExcludedFromProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getExcludes().add(\"name\");\n\t\tassertThat(buildInfoProperties(task)).doesNotContainKey(\"build.name\");\n\t}\n\n\t@Test\n\tvoid projectVersionIsReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProject().setVersion(\"1.2.3\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.version\", \"1.2.3\");\n\t}\n\n\t@Test\n\tvoid customVersionIsReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProperties().getVersion().set(\"2.3.4\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.version\", \"2.3.4\");\n\t}\n\n\t@Test\n\tvoid versionCanBeExcludedFromProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getExcludes().add(\"version\");\n\t\tassertThat(buildInfoProperties(task)).doesNotContainKey(\"build.version\");\n\t}\n\n\t@Test\n\tvoid timeIsSetInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\tassertThat(buildInfoProperties(task)).containsKey(\"build.time\");\n\t}\n\n\t@Test\n\tvoid timeCanBeExcludedFromProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getExcludes().add(\"time\");\n\t\tassertThat(buildInfoProperties(task)).doesNotContainKey(\"build.time\");\n\t}\n\n\t@Test\n\tvoid timeCanBeCustomizedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\tString isoTime = DateTimeFormatter.ISO_INSTANT.format(Instant.now());\n\t\ttask.getProperties().getTime().set(isoTime);\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.time\", isoTime);\n\t}\n\n\t@Test\n\tvoid additionalPropertiesAreReflectedInProperties() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProperties().getAdditional().put(\"a\", \"alpha\");\n\t\ttask.getProperties().getAdditional().put(\"b\", \"bravo\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.a\", \"alpha\").containsEntry(\"build.b\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid additionalPropertiesCanBeExcluded() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\ttask.getProperties().getAdditional().put(\"a\", \"alpha\");\n\t\ttask.getExcludes().add(\"b\");\n\t\tassertThat(buildInfoProperties(task)).containsEntry(\"build.a\", \"alpha\").doesNotContainKey(\"b\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullAdditionalPropertyProducesInformativeFailure() {\n\t\tBuildInfo task = createTask(createProject(\"test\"));\n\t\tassertThatException().isThrownBy(() -> task.getProperties().getAdditional().put(\"a\", null))\n\t\t\t.withMessage(\"Cannot add an entry with a null value to a property of type Map.\");\n\t}\n\n\t@Test\n\tvoid filenameCanBeCustomized() {\n\t\tProject project = createProject(\"test\");\n\t\tBuildInfo task = createTask(project);\n\t\ttask.getFilename().set(\"custom-location-build-info.properties\");\n\t\ttask.generateBuildProperties();\n\t\tassertThat(new File(project.getLayout().getBuildDirectory().dir(\"testBuildInfo\").get().getAsFile(),\n\t\t\t\t\"custom-location-build-info.properties\"))\n\t\t\t.exists();\n\t}\n\n\tprivate Project createProject(String projectName) {\n\t\tFile projectDir = new File(this.temp, projectName);\n\t\treturn GradleProjectBuilder.builder().withProjectDir(projectDir).withName(projectName).build();\n\t}\n\n\tprivate BuildInfo createTask(Project project) {\n\t\treturn project.getTasks().register(\"testBuildInfo\", BuildInfo.class).get();\n\t}\n\n\tprivate Properties buildInfoProperties(BuildInfo task) {\n\t\ttask.generateBuildProperties();\n\t\treturn buildInfoProperties(\n\t\t\t\tnew File(task.getDestinationDir().get().getAsFile(), \"META-INF/build-info.properties\"));\n\t}\n\n\tprivate Properties buildInfoProperties(File file) {\n\t\tassertThat(file).isFile();\n\t\tProperties properties = new Properties();\n\t\ttry (FileReader reader = new FileReader(file)) {\n\t\t\tproperties.load(reader);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.io.StringReader;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Consumer;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.stream.Stream;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.commons.compress.archivers.zip.UnixStat;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipFile;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.Assumptions;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.loader.tools.JarModeLibrary;\nimport org.springframework.boot.testsupport.FileUtils;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link BootJar} and {@link BootWar}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nabstract class AbstractBootArchiveIntegrationTests {\n\n\tprivate final String taskName;\n\n\tprivate final String libPath;\n\n\tprivate final String classesPath;\n\n\tprivate final String indexPath;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\tprotected AbstractBootArchiveIntegrationTests(String taskName, String libPath, String classesPath,\n\t\t\tString indexPath) {\n\t\tthis.taskName = taskName;\n\t\tthis.libPath = libPath;\n\t\tthis.classesPath = classesPath;\n\t\tthis.indexPath = indexPath;\n\t}\n\n\t@TestTemplate\n\tvoid basicBuild() {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid reproducibleArchive() throws IOException, InterruptedException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile jar = new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0];\n\t\tString firstHash = FileUtils.sha1Hash(jar);\n\t\tThread.sleep(1500);\n\t\ttask = this.gradleBuild.build(\"clean\", this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString secondHash = FileUtils.sha1Hash(jar);\n\t\tassertThat(firstHash).isEqualTo(secondHash);\n\t}\n\n\t@TestTemplate\n\tvoid upToDateWhenBuiltTwice() {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttask = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE);\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginMainClassNameIsUsed() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.CustomMain\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid springBootExtensionMainClassNameIsUsed() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.CustomMain\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid duplicatesAreHandledGracefully() {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid developmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault() throws IOException {\n\t\tFile srcMainResources = new File(this.gradleBuild.getProjectDir(), \"src/main/resources\");\n\t\tsrcMainResources.mkdirs();\n\t\tnew File(srcMainResources, \"resource\").createNewFile();\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> libEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.libPath));\n\t\t\tassertThat(libEntryNames).containsExactly(this.libPath + \"commons-io-2.6.jar\");\n\t\t\tStream<String> classesEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.classesPath));\n\t\t\tassertThat(classesEntryNames).containsExactly(this.classesPath + \"resource\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid developmentOnlyDependenciesCanBeIncludedInTheArchive() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> libEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.libPath));\n\t\t\tassertThat(libEntryNames).containsExactly(this.libPath + \"commons-io-2.6.jar\",\n\t\t\t\t\tthis.libPath + \"commons-lang3-3.9.jar\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid versionMismatchBetweenTransitiveDevelopmentOnlyImplementationDependenciesDoesNotRemoveDependencyFromTheArchive()\n\t\t\tthrows IOException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> libEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.libPath));\n\t\t\tassertThat(libEntryNames).containsExactly(this.libPath + \"two-1.0.jar\",\n\t\t\t\t\tthis.libPath + \"commons-io-2.19.0.jar\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid testAndDevelopmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault() throws IOException {\n\t\tFile srcMainResources = new File(this.gradleBuild.getProjectDir(), \"src/main/resources\");\n\t\tsrcMainResources.mkdirs();\n\t\tnew File(srcMainResources, \"resource\").createNewFile();\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> libEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.libPath));\n\t\t\tassertThat(libEntryNames).containsExactly(this.libPath + \"commons-io-2.6.jar\");\n\t\t\tStream<String> classesEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.classesPath));\n\t\t\tassertThat(classesEntryNames).containsExactly(this.classesPath + \"resource\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid testAndDevelopmentOnlyDependenciesCanBeIncludedInTheArchive() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> libEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.libPath));\n\t\t\tassertThat(libEntryNames).containsExactly(this.libPath + \"commons-io-2.6.jar\",\n\t\t\t\t\tthis.libPath + \"commons-lang3-3.9.jar\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid jarTypeFilteringIsApplied() throws IOException {\n\t\tFile flatDirRepository = new File(this.gradleBuild.getProjectDir(), \"repository\");\n\t\tcreateDependenciesStarterJar(new File(flatDirRepository, \"starter.jar\"));\n\t\tcreateDependenciesDeveloperToolsJar(new File(flatDirRepository, \"devonly.jar\"));\n\t\tcreateStandardJar(new File(flatDirRepository, \"standard.jar\"));\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> libEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.libPath));\n\t\t\tassertThat(libEntryNames).containsExactly(this.libPath + \"standard.jar\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid startClassIsSetByResolvingTheMainClass() throws IOException {\n\t\tcopyMainClassApplication();\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tAttributes mainAttributes = jarFile.getManifest().getMainAttributes();\n\t\t\tassertThat(mainAttributes.getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.\" + this.taskName.toLowerCase(Locale.ENGLISH) + \".main.CustomMainClass\");\n\t\t}\n\t\ttask = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE);\n\t}\n\n\t@TestTemplate\n\tvoid upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered() {\n\t\tBuildTask task = this.gradleBuild.scriptProperty(\"layered\", \"\")\n\t\t\t.build(\"\" + this.taskName)\n\t\t\t.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttask = this.gradleBuild.scriptProperty(\"layered\", \"layered {}\")\n\t\t\t.build(\"\" + this.taskName)\n\t\t\t.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE);\n\t}\n\n\t@TestTemplate\n\tvoid notUpToDateWhenBuiltWithoutLayersAndThenWithLayers() {\n\t\tBuildTask task = this.gradleBuild.scriptProperty(\"layerEnablement\", \"enabled = false\")\n\t\t\t.build(this.taskName)\n\t\t\t.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttask = this.gradleBuild.scriptProperty(\"layerEnablement\", \"enabled = true\")\n\t\t\t.build(this.taskName)\n\t\t\t.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid notUpToDateWhenBuiltWithToolsAndThenWithoutTools() {\n\t\tBuildTask task = this.gradleBuild.scriptProperty(\"includeTools\", \"\")\n\t\t\t.build(this.taskName)\n\t\t\t.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttask = this.gradleBuild.scriptProperty(\"includeTools\", \"includeTools = false\")\n\t\t\t.build(this.taskName)\n\t\t\t.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid layersWithCustomSourceSet() {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t}\n\n\t@TestTemplate\n\tvoid implicitLayers() throws IOException {\n\t\twriteMainClass();\n\t\twriteResource();\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tMap<String, List<String>> indexedLayers;\n\t\tString toolsJar = this.libPath + JarModeLibrary.TOOLS.getName();\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getEntry(toolsJar)).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"commons-lang3-3.9.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-core-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"library-1.0-SNAPSHOT.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"example/Main.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"static/file.txt\")).isNotNull();\n\t\t\tindexedLayers = readLayerIndex(jarFile);\n\t\t}\n\t\tList<String> layerNames = Arrays.asList(\"dependencies\", \"spring-boot-loader\", \"snapshot-dependencies\",\n\t\t\t\t\"application\");\n\t\tassertThat(indexedLayers.keySet()).containsExactlyElementsOf(layerNames);\n\t\tSet<String> expectedDependencies = new TreeSet<>();\n\t\texpectedDependencies.add(this.libPath + \"commons-lang3-3.9.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-core-5.2.5.RELEASE.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\");\n\t\texpectedDependencies.add(this.libPath + \"jul-to-slf4j-1.7.28.jar\");\n\t\texpectedDependencies.add(this.libPath + \"log4j-api-2.12.1.jar\");\n\t\texpectedDependencies.add(this.libPath + \"log4j-to-slf4j-2.12.1.jar\");\n\t\texpectedDependencies.add(this.libPath + \"logback-classic-1.2.3.jar\");\n\t\texpectedDependencies.add(this.libPath + \"logback-core-1.2.3.jar\");\n\t\texpectedDependencies.add(this.libPath + \"slf4j-api-1.7.28.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-boot-starter-logging-2.2.0.RELEASE.jar\");\n\t\tSet<String> expectedSnapshotDependencies = new TreeSet<>();\n\t\texpectedSnapshotDependencies.add(this.libPath + \"library-1.0-SNAPSHOT.jar\");\n\t\t(toolsJar.contains(\"SNAPSHOT\") ? expectedSnapshotDependencies : expectedDependencies).add(toolsJar);\n\t\tassertThat(indexedLayers.get(\"dependencies\")).containsExactlyElementsOf(expectedDependencies);\n\t\tassertThat(indexedLayers.get(\"spring-boot-loader\")).containsExactly(\"org/\");\n\t\tassertThat(indexedLayers.get(\"snapshot-dependencies\")).containsExactlyElementsOf(expectedSnapshotDependencies);\n\t\tassertThat(indexedLayers.get(\"application\"))\n\t\t\t.containsExactly(getExpectedApplicationLayerContents(this.classesPath));\n\t\tBuildResult listLayers = this.gradleBuild.build(\"listLayers\");\n\t\ttask = listLayers.task(\":listLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString listLayersOutput = listLayers.getOutput();\n\t\tassertThat(new BufferedReader(new StringReader(listLayersOutput)).lines()).containsSequence(layerNames);\n\t\tBuildResult extractLayers = this.gradleBuild.build(\"extractLayers\");\n\t\ttask = extractLayers.task(\":extractLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertExtractedLayers(layerNames, indexedLayers);\n\t}\n\n\tabstract String[] getExpectedApplicationLayerContents(String... additionalFiles);\n\n\t@TestTemplate\n\tvoid multiModuleImplicitLayers() throws IOException {\n\t\twriteSettingsGradle();\n\t\twriteMainClass();\n\t\twriteResource();\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tMap<String, List<String>> indexedLayers;\n\t\tString toolsJar = this.libPath + JarModeLibrary.TOOLS.getName();\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getEntry(toolsJar)).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"alpha-1.2.3.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"bravo-1.2.3.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"charlie-1.2.3.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"commons-lang3-3.9.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-core-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"library-1.0-SNAPSHOT.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"example/Main.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"static/file.txt\")).isNotNull();\n\t\t\tindexedLayers = readLayerIndex(jarFile);\n\t\t}\n\t\tList<String> layerNames = Arrays.asList(\"dependencies\", \"spring-boot-loader\", \"snapshot-dependencies\",\n\t\t\t\t\"application\");\n\t\tassertThat(indexedLayers.keySet()).containsExactlyElementsOf(layerNames);\n\t\tSet<String> expectedDependencies = new TreeSet<>();\n\t\texpectedDependencies.add(this.libPath + \"commons-lang3-3.9.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-core-5.2.5.RELEASE.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\");\n\t\tSet<String> expectedSnapshotDependencies = new TreeSet<>();\n\t\texpectedSnapshotDependencies.add(this.libPath + \"library-1.0-SNAPSHOT.jar\");\n\t\t(toolsJar.contains(\"SNAPSHOT\") ? expectedSnapshotDependencies : expectedDependencies).add(toolsJar);\n\t\tassertThat(indexedLayers.get(\"dependencies\")).containsExactlyElementsOf(expectedDependencies);\n\t\tassertThat(indexedLayers.get(\"spring-boot-loader\")).containsExactly(\"org/\");\n\t\tassertThat(indexedLayers.get(\"snapshot-dependencies\")).containsExactlyElementsOf(expectedSnapshotDependencies);\n\t\tassertThat(indexedLayers.get(\"application\"))\n\t\t\t.containsExactly(getExpectedApplicationLayerContents(this.classesPath, this.libPath + \"alpha-1.2.3.jar\",\n\t\t\t\t\tthis.libPath + \"bravo-1.2.3.jar\", this.libPath + \"charlie-1.2.3.jar\"));\n\t\tBuildResult listLayers = this.gradleBuild.build(\"listLayers\");\n\t\ttask = listLayers.task(\":listLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString listLayersOutput = listLayers.getOutput();\n\t\tassertThat(new BufferedReader(new StringReader(listLayersOutput)).lines()).containsSequence(layerNames);\n\t\tBuildResult extractLayers = this.gradleBuild.build(\"extractLayers\");\n\t\ttask = extractLayers.task(\":extractLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertExtractedLayers(layerNames, indexedLayers);\n\t}\n\n\t@TestTemplate\n\tvoid customLayers() throws IOException {\n\t\twriteMainClass();\n\t\twriteResource();\n\t\tBuildResult build = this.gradleBuild.build(this.taskName);\n\t\tBuildTask task = build.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tMap<String, List<String>> indexedLayers;\n\t\tString toolsJar = this.libPath + JarModeLibrary.TOOLS.getName();\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getEntry(toolsJar)).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"commons-lang3-3.9.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-core-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"library-1.0-SNAPSHOT.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"example/Main.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"static/file.txt\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.indexPath + \"layers.idx\")).isNotNull();\n\t\t\tindexedLayers = readLayerIndex(jarFile);\n\t\t}\n\t\tList<String> layerNames = Arrays.asList(\"dependencies\", \"commons-dependencies\", \"snapshot-dependencies\",\n\t\t\t\t\"static\", \"app\");\n\t\tassertThat(indexedLayers.keySet()).containsExactlyElementsOf(layerNames);\n\t\tSet<String> expectedDependencies = new TreeSet<>();\n\t\texpectedDependencies.add(this.libPath + \"spring-core-5.2.5.RELEASE.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\");\n\t\tList<String> expectedSnapshotDependencies = new ArrayList<>();\n\t\texpectedSnapshotDependencies.add(this.libPath + \"library-1.0-SNAPSHOT.jar\");\n\t\t(toolsJar.contains(\"SNAPSHOT\") ? expectedSnapshotDependencies : expectedDependencies).add(toolsJar);\n\t\tassertThat(indexedLayers.get(\"dependencies\")).containsExactlyElementsOf(expectedDependencies);\n\t\tassertThat(indexedLayers.get(\"commons-dependencies\")).containsExactly(this.libPath + \"commons-lang3-3.9.jar\");\n\t\tassertThat(indexedLayers.get(\"snapshot-dependencies\")).containsExactlyElementsOf(expectedSnapshotDependencies);\n\t\tassertThat(indexedLayers.get(\"static\")).containsExactly(this.classesPath + \"static/\");\n\t\tList<String> appLayer = new ArrayList<>(indexedLayers.get(\"app\"));\n\t\tString[] appLayerContents = getExpectedApplicationLayerContents(this.classesPath + \"example/\");\n\t\tassertThat(appLayer).containsSubsequence(appLayerContents);\n\t\tappLayer.removeAll(Arrays.asList(appLayerContents));\n\t\tassertThat(appLayer).containsExactly(\"org/\");\n\t\tBuildResult listLayers = this.gradleBuild.build(\"listLayers\");\n\t\ttask = listLayers.task(\":listLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString listLayersOutput = listLayers.getOutput();\n\t\tassertThat(new BufferedReader(new StringReader(listLayersOutput)).lines()).containsSequence(layerNames);\n\t\tBuildResult extractLayers = this.gradleBuild.build(\"extractLayers\");\n\t\ttask = extractLayers.task(\":extractLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertExtractedLayers(layerNames, indexedLayers);\n\t}\n\n\t@TestTemplate\n\tvoid multiModuleCustomLayers() throws IOException {\n\t\twriteSettingsGradle();\n\t\twriteMainClass();\n\t\twriteResource();\n\t\tBuildResult build = this.gradleBuild.build(this.taskName);\n\t\tBuildTask task = build.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tMap<String, List<String>> indexedLayers;\n\t\tString toolsJar = this.libPath + JarModeLibrary.TOOLS.getName();\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getEntry(toolsJar)).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"alpha-1.2.3.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"bravo-1.2.3.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"charlie-1.2.3.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"commons-lang3-3.9.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-core-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"library-1.0-SNAPSHOT.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"example/Main.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"static/file.txt\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.indexPath + \"layers.idx\")).isNotNull();\n\t\t\tindexedLayers = readLayerIndex(jarFile);\n\t\t}\n\t\tList<String> layerNames = Arrays.asList(\"dependencies\", \"commons-dependencies\", \"snapshot-dependencies\",\n\t\t\t\t\"subproject-dependencies\", \"static\", \"app\");\n\t\tassertThat(indexedLayers.keySet()).containsExactlyElementsOf(layerNames);\n\t\tSet<String> expectedSubprojectDependencies = new TreeSet<>();\n\t\texpectedSubprojectDependencies.add(this.libPath + \"alpha-1.2.3.jar\");\n\t\texpectedSubprojectDependencies.add(this.libPath + \"bravo-1.2.3.jar\");\n\t\texpectedSubprojectDependencies.add(this.libPath + \"charlie-1.2.3.jar\");\n\t\tSet<String> expectedDependencies = new TreeSet<>();\n\t\texpectedDependencies.add(this.libPath + \"spring-core-5.2.5.RELEASE.jar\");\n\t\texpectedDependencies.add(this.libPath + \"spring-jcl-5.2.5.RELEASE.jar\");\n\t\tList<String> expectedSnapshotDependencies = new ArrayList<>();\n\t\texpectedSnapshotDependencies.add(this.libPath + \"library-1.0-SNAPSHOT.jar\");\n\t\t(toolsJar.contains(\"SNAPSHOT\") ? expectedSnapshotDependencies : expectedDependencies).add(toolsJar);\n\t\tassertThat(indexedLayers.get(\"subproject-dependencies\"))\n\t\t\t.containsExactlyElementsOf(expectedSubprojectDependencies);\n\t\tassertThat(indexedLayers.get(\"dependencies\")).containsExactlyElementsOf(expectedDependencies);\n\t\tassertThat(indexedLayers.get(\"commons-dependencies\")).containsExactly(this.libPath + \"commons-lang3-3.9.jar\");\n\t\tassertThat(indexedLayers.get(\"snapshot-dependencies\")).containsExactlyElementsOf(expectedSnapshotDependencies);\n\t\tassertThat(indexedLayers.get(\"static\")).containsExactly(this.classesPath + \"static/\");\n\t\tList<String> appLayer = new ArrayList<>(indexedLayers.get(\"app\"));\n\t\tString[] appLayerContents = getExpectedApplicationLayerContents(this.classesPath + \"example/\");\n\t\tassertThat(appLayer).containsSubsequence(appLayerContents);\n\t\tappLayer.removeAll(Arrays.asList(appLayerContents));\n\t\tassertThat(appLayer).containsExactly(\"org/\");\n\t\tBuildResult listLayers = this.gradleBuild.build(\"listLayers\");\n\t\ttask = listLayers.task(\":listLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tString listLayersOutput = listLayers.getOutput();\n\t\tassertThat(new BufferedReader(new StringReader(listLayersOutput)).lines()).containsSequence(layerNames);\n\t\tBuildResult extractLayers = this.gradleBuild.build(\"extractLayers\");\n\t\ttask = extractLayers.task(\":extractLayers\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertExtractedLayers(layerNames, indexedLayers);\n\t}\n\n\t@TestTemplate\n\tvoid classesFromASecondarySourceSetCanBeIncludedInTheArchive() throws IOException {\n\t\twriteMainClass();\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/secondary/java/example\");\n\t\texamplePackage.mkdirs();\n\t\tFile main = new File(examplePackage, \"Secondary.java\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(main))) {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"public class Secondary {}\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\tBuildResult build = this.gradleBuild.build(this.taskName);\n\t\tBuildTask task = build.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tStream<String> classesEntryNames = jarFile.stream()\n\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t.filter((name) -> name.startsWith(this.classesPath));\n\t\t\tassertThat(classesEntryNames).containsExactly(this.classesPath + \"example/Main.class\",\n\t\t\t\t\tthis.classesPath + \"example/Secondary.class\");\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid javaVersionIsSetInManifest() throws IOException {\n\t\tBuildResult result = this.gradleBuild.build(this.taskName);\n\t\tBuildTask task = result.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Build-Jdk-Spec\")).isNotEmpty();\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid defaultDirAndFileModesAreUsed() throws IOException {\n\t\tBuildResult result = this.gradleBuild.build(this.taskName);\n\t\tBuildTask task = result.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (ZipFile jarFile = ZipFile.builder()\n\t\t\t.setFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])\n\t\t\t.get()) {\n\t\t\tEnumeration<ZipArchiveEntry> entries = jarFile.getEntries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tZipArchiveEntry entry = entries.nextElement();\n\t\t\t\tif (entry.getName().startsWith(\"META-INF/\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tassertEntryMode(entry, UnixStat.DEFAULT_DIR_PERM);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tassertEntryMode(entry, UnixStat.DEFAULT_FILE_PERM);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid dirModeAndFileModeAreApplied() throws IOException {\n\t\tAssumptions.assumeTrue(this.gradleBuild.gradleVersionIsLessThan(\"9.0-milestone-1\"));\n\t\tBuildResult result = this.gradleBuild.expectDeprecationWarningsWithAtLeastVersion(\"8.8-rc-1\")\n\t\t\t.expectDeprecationMessages(\"The CopyProcessingSpec.setDirMode(Integer) method has been deprecated\",\n\t\t\t\t\t\"The CopyProcessingSpec.setFileMode(Integer) method has been deprecated\",\n\t\t\t\t\t\"upgrading_version_8.html#unix_file_permissions_deprecated\")\n\t\t\t.build(this.taskName);\n\t\tBuildTask task = result.task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (ZipFile jarFile = ZipFile.builder()\n\t\t\t.setFile(new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0])\n\t\t\t.get()) {\n\t\t\tEnumeration<ZipArchiveEntry> entries = jarFile.getEntries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tZipArchiveEntry entry = entries.nextElement();\n\t\t\t\tif (entry.getName().startsWith(\"META-INF/\")) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tassertEntryMode(entry, 0500);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tassertEntryMode(entry, 0400);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid signed() throws IOException {\n\t\tBuildTask task = this.gradleBuild.build(this.taskName).task(\":\" + this.taskName);\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tFile jar = new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0];\n\t\ttry (JarFile jarFile = new JarFile(jar)) {\n\t\t\tassertThat(jarFile.getEntry(\"META-INF/BOOT.SF\")).isNotNull();\n\t\t}\n\t}\n\n\tprivate void copyMainClassApplication() throws IOException {\n\t\tcopyApplication(\"main\");\n\t}\n\n\tprotected void copyApplication(String name) throws IOException {\n\t\tFile output = new File(this.gradleBuild.getProjectDir(),\n\t\t\t\t\"src/main/java/com/example/\" + this.taskName.toLowerCase(Locale.ROOT) + \"/\" + name);\n\t\toutput.mkdirs();\n\t\tFileSystemUtils.copyRecursively(\n\t\t\t\tnew File(\"src/test/resources/com/example/\" + this.taskName.toLowerCase(Locale.ENGLISH) + \"/\" + name),\n\t\t\t\toutput);\n\t}\n\n\tprivate void createStandardJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> {\n\t\t});\n\t}\n\n\tprivate void createDependenciesStarterJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> attributes.putValue(\"Spring-Boot-Jar-Type\", \"dependencies-starter\"));\n\t}\n\n\tprivate void createDependenciesDeveloperToolsJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> attributes.putValue(\"Spring-Boot-Jar-Type\", \"development-tool\"));\n\t}\n\n\tprivate void createJar(File location, Consumer<Attributes> attributesConfigurer) throws IOException {\n\t\tlocation.getParentFile().mkdirs();\n\t\tManifest manifest = new Manifest();\n\t\tAttributes attributes = manifest.getMainAttributes();\n\t\tattributes.put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\t\tattributesConfigurer.accept(attributes);\n\t\tnew JarOutputStream(new FileOutputStream(location), manifest).close();\n\t}\n\n\tprivate void writeSettingsGradle() {\n\t\ttry (PrintWriter writer = new PrintWriter(\n\t\t\t\tnew FileWriter(new File(this.gradleBuild.getProjectDir(), \"settings.gradle\")))) {\n\t\t\twriter.println(\"include 'alpha', 'bravo', 'charlie'\");\n\t\t\tnew File(this.gradleBuild.getProjectDir(), \"alpha\").mkdirs();\n\t\t\tnew File(this.gradleBuild.getProjectDir(), \"bravo\").mkdirs();\n\t\t\tnew File(this.gradleBuild.getProjectDir(), \"charlie\").mkdirs();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void writeMainClass() {\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/main/java/example\");\n\t\texamplePackage.mkdirs();\n\t\tFile main = new File(examplePackage, \"Main.java\");\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(main))) {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import java.io.IOException;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"public class Main {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    public static void main(String[] args) {\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void writeResource() {\n\t\ttry {\n\t\t\tPath path = this.gradleBuild.getProjectDir()\n\t\t\t\t.toPath()\n\t\t\t\t.resolve(Paths.get(\"src\", \"main\", \"resources\", \"static\", \"file.txt\"));\n\t\t\tFiles.createDirectories(path.getParent());\n\t\t\tFiles.createFile(path);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate Map<String, List<String>> readLayerIndex(JarFile jarFile) throws IOException {\n\t\tMap<String, List<String>> index = new LinkedHashMap<>();\n\t\tZipEntry indexEntry = jarFile.getEntry(this.indexPath + \"layers.idx\");\n\t\ttry (BufferedReader reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(indexEntry)))) {\n\t\t\tString line = reader.readLine();\n\t\t\tString layer = null;\n\t\t\twhile (line != null) {\n\t\t\t\tif (line.startsWith(\"- \")) {\n\t\t\t\t\tlayer = line.substring(3, line.length() - 2);\n\t\t\t\t}\n\t\t\t\telse if (line.startsWith(\"  - \")) {\n\t\t\t\t\tindex.computeIfAbsent(layer, (key) -> new ArrayList<>()).add(line.substring(5, line.length() - 1));\n\t\t\t\t}\n\t\t\t\tline = reader.readLine();\n\t\t\t}\n\t\t\treturn index;\n\t\t}\n\t}\n\n\tprivate Map<String, List<String>> readExtractedLayers(File root, List<String> layerNames) throws IOException {\n\t\tMap<String, List<String>> extractedLayers = new LinkedHashMap<>();\n\t\tfor (String layerName : layerNames) {\n\t\t\tFile layer = new File(root, layerName);\n\t\t\tassertThat(layer).isDirectory();\n\t\t\tList<String> files;\n\t\t\ttry (Stream<Path> pathStream = Files.walk(layer.toPath())) {\n\t\t\t\tfiles = pathStream.filter((path) -> path.toFile().isFile())\n\t\t\t\t\t.map(layer.toPath()::relativize)\n\t\t\t\t\t.map(Path::toString)\n\t\t\t\t\t.map(StringUtils::cleanPath)\n\t\t\t\t\t.toList();\n\t\t\t}\n\t\t\textractedLayers.put(layerName, files);\n\t\t}\n\t\treturn extractedLayers;\n\t}\n\n\tprivate void assertExtractedLayers(List<String> layerNames, Map<String, List<String>> indexedLayers)\n\t\t\tthrows IOException {\n\t\tMap<String, List<String>> extractedLayers = readExtractedLayers(this.gradleBuild.getProjectDir(), layerNames);\n\t\tassertThat(extractedLayers.keySet()).isEqualTo(indexedLayers.keySet());\n\t\textractedLayers.forEach((name, contents) -> {\n\t\t\tList<String> index = indexedLayers.get(name);\n\t\t\tassertThat(index).isNotNull();\n\t\t\tList<String> unexpected = new ArrayList<>();\n\t\t\tfor (String file : contents) {\n\t\t\t\tif (!isInIndex(index, file)) {\n\t\t\t\t\tunexpected.add(name);\n\t\t\t\t}\n\t\t\t}\n\t\t\tassertThat(unexpected).isEmpty();\n\t\t});\n\t}\n\n\tprivate boolean isInIndex(List<String> index, String file) {\n\t\tfor (String candidate : index) {\n\t\t\tif (file.equals(candidate) || candidate.endsWith(\"/\") && file.startsWith(candidate)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static void assertEntryMode(ZipArchiveEntry entry, int expectedMode) {\n\t\tassertThat(entry.getUnixMode())\n\t\t\t.withFailMessage(() -> \"Expected mode \" + Integer.toOctalString(expectedMode) + \" for entry \"\n\t\t\t\t\t+ entry.getName() + \" but actual is \" + Integer.toOctalString(entry.getUnixMode()))\n\t\t\t.isEqualTo(expectedMode);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.UUID;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipFile;\nimport org.gradle.api.Action;\nimport org.gradle.api.DomainObjectSet;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.ArtifactCollection;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.DependencySet;\nimport org.gradle.api.artifacts.ProjectDependency;\nimport org.gradle.api.artifacts.ResolvableDependencies;\nimport org.gradle.api.artifacts.component.ModuleComponentIdentifier;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.internal.file.archive.ZipEntryConstants;\nimport org.gradle.api.tasks.bundling.AbstractArchiveTask;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.gradle.junit.GradleProjectBuilder;\nimport org.springframework.boot.loader.tools.JarModeLibrary;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Abstract base class for testing {@link BootArchive} implementations.\n *\n * @param <T> the type of the concrete BootArchive implementation\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nabstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\tprivate final Class<T> taskClass;\n\n\tprivate final String launcherClass;\n\n\tprivate final String libPath;\n\n\tprivate final String classesPath;\n\n\tprivate final String indexPath;\n\n\tprivate Project project;\n\n\tprivate T task;\n\n\tprotected AbstractBootArchiveTests(Class<T> taskClass, String launcherClass, String libPath, String classesPath,\n\t\t\tString indexPath) {\n\t\tthis.taskClass = taskClass;\n\t\tthis.launcherClass = launcherClass;\n\t\tthis.libPath = libPath;\n\t\tthis.classesPath = classesPath;\n\t\tthis.indexPath = indexPath;\n\t}\n\n\t@BeforeEach\n\tvoid createTask() {\n\t\tFile projectDir = new File(this.temp, \"project\");\n\t\tprojectDir.mkdirs();\n\t\tthis.project = GradleProjectBuilder.builder().withProjectDir(projectDir).build();\n\t\tthis.project.setDescription(\"Test project for \" + this.taskClass.getSimpleName());\n\t\tthis.task = this.project.getTasks().register(\"testArchive\", this.taskClass, this::configure).get();\n\t}\n\n\t@Test\n\tvoid basicArchiveCreation() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Main-Class\")).isEqualTo(this.launcherClass);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Start-Class\")).isEqualTo(\"com.example.Main\");\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Classes\"))\n\t\t\t\t.isEqualTo(this.classesPath);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Lib\")).isEqualTo(this.libPath);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Version\")).isNotNull();\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Implementation-Title\"))\n\t\t\t\t.isEqualTo(this.project.getName());\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Implementation-Version\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenImplementationNameIsCustomizedItShouldAppearInArchiveManifest() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.getManifest().getAttributes().put(\"Implementation-Title\", \"Customized\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Implementation-Title\"))\n\t\t\t\t.isEqualTo(\"Customized\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsSetThenImplementationVersionShouldAppearInArchiveManifest() throws IOException {\n\t\tthis.project.setVersion(\"1.0.0\");\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Implementation-Version\")).isEqualTo(\"1.0.0\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenImplementationVersionIsCustomizedItShouldAppearInArchiveManifest() throws IOException {\n\t\tthis.project.setVersion(\"1.0.0\");\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.getManifest().getAttributes().put(\"Implementation-Version\", \"Customized\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Implementation-Version\"))\n\t\t\t\t.isEqualTo(\"Customized\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid classpathJarsArePackagedBeneathLibPathAndAreStored() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(jarFile(\"one.jar\"), jarFile(\"two.jar\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"one.jar\")).isNotNull()\n\t\t\t\t.extracting(ZipEntry::getMethod)\n\t\t\t\t.isEqualTo(ZipEntry.STORED);\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"two.jar\")).isNotNull()\n\t\t\t\t.extracting(ZipEntry::getMethod)\n\t\t\t\t.isEqualTo(ZipEntry.STORED);\n\t\t}\n\t}\n\n\t@Test\n\tvoid classpathDirectoriesArePackagedBeneathClassesPath() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tthis.task.classpath(classpathDirectory);\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"com/example/Application.class\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid moduleInfoClassIsPackagedInTheRootOfTheArchive() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile moduleInfoClass = new File(classpathDirectory, \"module-info.class\");\n\t\tmoduleInfoClass.getParentFile().mkdirs();\n\t\tmoduleInfoClass.createNewFile();\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tthis.task.classpath(classpathDirectory);\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"com/example/Application.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"com/example/Application.class\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"module-info.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(this.classesPath + \"/module-info.class\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid classpathCanBeSetUsingAFileCollection() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(jarFile(\"one.jar\"));\n\t\tthis.task.setClasspath(this.task.getProject().files(jarFile(\"two.jar\")));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"one.jar\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"two.jar\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid classpathCanBeSetUsingAnObject() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(jarFile(\"one.jar\"));\n\t\tthis.task.setClasspath(jarFile(\"two.jar\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"one.jar\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"two.jar\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid filesOnTheClasspathThatAreNotZipFilesAreSkipped() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(new File(\"test.pom\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"/test.pom\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loaderIsWrittenToTheRootOfTheJarAfterManifest() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"org/springframework/boot/loader/launch/LaunchedClassLoader.class\"))\n\t\t\t\t.isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"org/springframework/boot/loader/\")).isNotNull();\n\t\t}\n\t\t// gh-16698\n\t\ttry (ZipInputStream zipInputStream = new ZipInputStream(\n\t\t\t\tnew FileInputStream(this.task.getArchiveFile().get().getAsFile()))) {\n\t\t\tassertThat(zipInputStream.getNextEntry().getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(zipInputStream.getNextEntry().getName()).isEqualTo(\"META-INF/MANIFEST.MF\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid loaderIsWrittenToTheRootOfTheJarWhenUsingThePropertiesLauncher() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\tthis.task.getManifest()\n\t\t\t.getAttributes()\n\t\t\t.put(\"Main-Class\", \"org.springframework.boot.loader.launch.PropertiesLauncher\");\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"org/springframework/boot/loader/launch/LaunchedClassLoader.class\"))\n\t\t\t\t.isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"org/springframework/boot/loader/\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid unpackCommentIsAddedToEntryIdentifiedByAPattern() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(jarFile(\"one.jar\"), jarFile(\"two.jar\"));\n\t\tthis.task.requiresUnpack(\"**/one.jar\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"one.jar\").getComment()).isEqualTo(\"UNPACK\");\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"two.jar\").getComment()).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid unpackCommentIsAddedToEntryIdentifiedByASpec() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(jarFile(\"one.jar\"), jarFile(\"two.jar\"));\n\t\tthis.task.requiresUnpack((element) -> element.getName().endsWith(\"two.jar\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"two.jar\").getComment()).isEqualTo(\"UNPACK\");\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"one.jar\").getComment()).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid customMainClassInTheManifestIsHonored() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.getManifest().getAttributes().put(\"Main-Class\", \"com.example.CustomLauncher\");\n\t\texecuteTask();\n\t\tassertThat(this.task.getArchiveFile().get().getAsFile()).exists();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Main-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.CustomLauncher\");\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Start-Class\")).isEqualTo(\"com.example.Main\");\n\t\t\tassertThat(jarFile.getEntry(\"org/springframework/boot/loader/launch/LaunchedClassLoader.class\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid customStartClassInTheManifestIsHonored() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.getManifest().getAttributes().put(\"Start-Class\", \"com.example.CustomMain\");\n\t\texecuteTask();\n\t\tassertThat(this.task.getArchiveFile().get().getAsFile()).exists();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Main-Class\")).isEqualTo(this.launcherClass);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Start-Class\"))\n\t\t\t\t.isEqualTo(\"com.example.CustomMain\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid fileTimestampPreservationCanBeDisabled() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.setPreserveFileTimestamps(false);\n\t\texecuteTask();\n\t\tassertThat(this.task.getArchiveFile().get().getAsFile()).exists();\n\t\tlong expectedTime = DefaultTimeZoneOffset.INSTANCE.removeFrom(BootZipCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES);\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tJarEntry entry = entries.nextElement();\n\t\t\t\tassertThat(entry.getTime()).isEqualTo(expectedTime);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid constantTimestampMatchesGradleInternalTimestamp() {\n\t\tassertThat(DefaultTimeZoneOffset.INSTANCE.removeFrom(BootZipCopyAction.CONSTANT_TIME_FOR_ZIP_ENTRIES))\n\t\t\t.isEqualTo(ZipEntryConstants.CONSTANT_TIME_FOR_ZIP_ENTRIES);\n\t}\n\n\t@Test\n\tvoid archiveIsReproducibleByDefault() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.from(newFiles(\"files/b/bravo.txt\", \"files/a/alpha.txt\", \"files/c/charlie.txt\"));\n\t\texecuteTask();\n\t\tassertThat(this.task.getArchiveFile().get().getAsFile()).exists();\n\t\tList<String> files = new ArrayList<>();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tJarEntry entry = entries.nextElement();\n\t\t\t\tassertThat(entry.getLastModifiedTime().toMillis())\n\t\t\t\t\t.isEqualTo(ZipEntryConstants.CONSTANT_TIME_FOR_ZIP_ENTRIES);\n\t\t\t\tif (entry.getName().startsWith(\"files/\")) {\n\t\t\t\t\tfiles.add(entry.getName());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tassertThat(files).containsExactly(\"files/\", \"files/a/\", \"files/a/alpha.txt\", \"files/b/\", \"files/b/bravo.txt\",\n\t\t\t\t\"files/c/\", \"files/c/charlie.txt\");\n\t}\n\n\t@Test\n\tvoid archiveReproducibilityCanBeDisabled() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.from(newFiles(\"files/b/bravo.txt\", \"files/a/alpha.txt\", \"files/c/charlie.txt\"));\n\t\tthis.task.setPreserveFileTimestamps(true);\n\t\tthis.task.setReproducibleFileOrder(false);\n\t\texecuteTask();\n\t\tassertThat(this.task.getArchiveFile().get().getAsFile()).exists();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tJarEntry entry = entries.nextElement();\n\t\t\t\tif (entry.getName().endsWith(\".txt\") || entry.getName().startsWith(\"BOOT-INF/lib/\")) {\n\t\t\t\t\tOffsetDateTime lastModifiedTime = entry.getLastModifiedTime().toInstant().atOffset(ZoneOffset.UTC);\n\t\t\t\t\tassertThat(lastModifiedTime)\n\t\t\t\t\t\t.isNotEqualTo(OffsetDateTime.of(1980, 2, 1, 0, 0, 0, 0, ZoneOffset.UTC));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid devtoolsJarIsExcludedByDefault() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.classpath(newFile(\"spring-boot-devtools-0.1.2.jar\"));\n\t\texecuteTask();\n\t\tassertThat(this.task.getArchiveFile().get().getAsFile()).exists();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(this.libPath + \"spring-boot-devtools-0.1.2.jar\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid allEntriesUseUnixPlatformAndUtf8NameEncoding() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tthis.task.setMetadataCharset(\"UTF-8\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile resource = new File(classpathDirectory, \"some-resource.xml\");\n\t\tresource.getParentFile().mkdirs();\n\t\tresource.createNewFile();\n\t\tthis.task.classpath(classpathDirectory);\n\t\texecuteTask();\n\t\tFile archivePath = this.task.getArchiveFile().get().getAsFile();\n\t\ttry (ZipFile zip = ZipFile.builder().setFile(archivePath).get()) {\n\t\t\tEnumeration<ZipArchiveEntry> entries = zip.getEntries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tZipArchiveEntry entry = entries.nextElement();\n\t\t\t\tassertThat(entry.getPlatform()).isEqualTo(ZipArchiveEntry.PLATFORM_UNIX);\n\t\t\t\tassertThat(entry.getGeneralPurposeBit().usesUTF8ForNames()).isTrue();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid loaderIsWrittenFirstThenApplicationClassesThenLibraries() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tthis.task.classpath(classpathDirectory, jarFile(\"first-library.jar\"), jarFile(\"second-library.jar\"),\n\t\t\t\tjarFile(\"third-library.jar\"));\n\t\tthis.task.requiresUnpack(\"second-library.jar\");\n\t\texecuteTask();\n\t\tassertThat(getEntryNames(this.task.getArchiveFile().get().getAsFile())).containsSubsequence(\n\t\t\t\t\"org/springframework/boot/loader/\", this.classesPath + \"com/example/Application.class\",\n\t\t\t\tthis.libPath + \"first-library.jar\", this.libPath + \"second-library.jar\",\n\t\t\t\tthis.libPath + \"third-library.jar\");\n\t}\n\n\t@Test\n\tvoid archiveShouldBeLayeredByDefault() throws IOException {\n\t\taddContent();\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Classes\"))\n\t\t\t\t.isEqualTo(this.classesPath);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Lib\")).isEqualTo(this.libPath);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Layers-Index\"))\n\t\t\t\t.isEqualTo(this.indexPath + \"layers.idx\");\n\t\t\tassertThat(getEntryNames(jarFile)).contains(this.libPath + JarModeLibrary.TOOLS.getName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid jarWhenLayersDisabledShouldNotContainLayersIndex() throws IOException {\n\t\tList<String> entryNames = getEntryNames(\n\t\t\t\tcreateLayeredJar((configuration) -> configuration.getEnabled().set(false)));\n\t\tassertThat(entryNames).isNotEmpty().doesNotContain(this.indexPath + \"layers.idx\");\n\t}\n\n\t@Test\n\tvoid whenJarIsLayeredThenManifestContainsEntryForLayersIndexInPlaceOfClassesAndLib() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Classes\"))\n\t\t\t\t.isEqualTo(this.classesPath);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Lib\")).isEqualTo(this.libPath);\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Layers-Index\"))\n\t\t\t\t.isEqualTo(this.indexPath + \"layers.idx\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenJarIsLayeredThenLayersIndexIsPresentAndCorrect() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar())) {\n\t\t\tList<String> entryNames = getEntryNames(jarFile);\n\t\t\tassertThat(entryNames).contains(this.libPath + \"first-library.jar\", this.libPath + \"second-library.jar\",\n\t\t\t\t\tthis.libPath + \"third-library-SNAPSHOT.jar\", this.libPath + \"first-project-library.jar\",\n\t\t\t\t\tthis.libPath + \"second-project-library-SNAPSHOT.jar\",\n\t\t\t\t\tthis.classesPath + \"com/example/Application.class\", this.classesPath + \"application.properties\",\n\t\t\t\t\tthis.classesPath + \"static/test.css\");\n\t\t\tList<String> index = entryLines(jarFile, this.indexPath + \"layers.idx\");\n\t\t\tassertThat(getLayerNames(index)).containsExactly(\"dependencies\", \"spring-boot-loader\",\n\t\t\t\t\t\"snapshot-dependencies\", \"application\");\n\t\t\tString toolsJar = this.libPath + JarModeLibrary.TOOLS.getName();\n\t\t\tList<String> expected = new ArrayList<>();\n\t\t\texpected.add(\"- \\\"dependencies\\\":\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"first-library.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"first-project-library.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"fourth-library.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"second-library.jar\\\"\");\n\t\t\tif (!toolsJar.contains(\"SNAPSHOT\")) {\n\t\t\t\texpected.add(\"  - \\\"\" + toolsJar + \"\\\"\");\n\t\t\t}\n\t\t\texpected.add(\"- \\\"spring-boot-loader\\\":\");\n\t\t\texpected.add(\"  - \\\"org/\\\"\");\n\t\t\texpected.add(\"- \\\"snapshot-dependencies\\\":\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"second-project-library-SNAPSHOT.jar\\\"\");\n\t\t\tif (toolsJar.contains(\"SNAPSHOT\")) {\n\t\t\t\texpected.add(\"  - \\\"\" + toolsJar + \"\\\"\");\n\t\t\t}\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"third-library-SNAPSHOT.jar\\\"\");\n\t\t\texpected.add(\"- \\\"application\\\":\");\n\t\t\tSet<String> applicationContents = new TreeSet<>();\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.classesPath + \"\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.indexPath + \"classpath.idx\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.indexPath + \"layers.idx\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"META-INF/\\\"\");\n\t\t\texpected.addAll(applicationContents);\n\t\t\tassertThat(index).containsExactlyElementsOf(expected);\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenJarIsLayeredWithCustomStrategiesThenLayersIndexIsPresentAndCorrect() throws IOException {\n\t\tFile jar = createLayeredJar((layered) -> {\n\t\t\tlayered.application((application) -> {\n\t\t\t\tapplication.intoLayer(\"resources\", (spec) -> spec.include(\"static/**\"));\n\t\t\t\tapplication.intoLayer(\"application\");\n\t\t\t});\n\t\t\tlayered.dependencies((dependencies) -> {\n\t\t\t\tdependencies.intoLayer(\"my-snapshot-deps\", (spec) -> spec.include(\"com.example:*:*.SNAPSHOT\"));\n\t\t\t\tdependencies.intoLayer(\"my-internal-deps\", (spec) -> spec.include(\"com.example:*:*\"));\n\t\t\t\tdependencies.intoLayer(\"my-deps\");\n\t\t\t});\n\t\t\tlayered.getLayerOrder()\n\t\t\t\t.set(List.of(\"my-deps\", \"my-internal-deps\", \"my-snapshot-deps\", \"resources\", \"application\"));\n\t\t});\n\t\ttry (JarFile jarFile = new JarFile(jar)) {\n\t\t\tList<String> entryNames = getEntryNames(jar);\n\t\t\tassertThat(entryNames).contains(this.libPath + \"first-library.jar\", this.libPath + \"second-library.jar\",\n\t\t\t\t\tthis.libPath + \"third-library-SNAPSHOT.jar\", this.libPath + \"first-project-library.jar\",\n\t\t\t\t\tthis.libPath + \"second-project-library-SNAPSHOT.jar\",\n\t\t\t\t\tthis.classesPath + \"com/example/Application.class\", this.classesPath + \"application.properties\",\n\t\t\t\t\tthis.classesPath + \"static/test.css\");\n\t\t\tList<String> index = entryLines(jarFile, this.indexPath + \"layers.idx\");\n\t\t\tassertThat(getLayerNames(index)).containsExactly(\"my-deps\", \"my-internal-deps\", \"my-snapshot-deps\",\n\t\t\t\t\t\"resources\", \"application\");\n\t\t\tString toolsJar = this.libPath + JarModeLibrary.TOOLS.getName();\n\t\t\tList<String> expected = new ArrayList<>();\n\t\t\texpected.add(\"- \\\"my-deps\\\":\");\n\t\t\texpected.add(\"  - \\\"\" + toolsJar + \"\\\"\");\n\t\t\texpected.add(\"- \\\"my-internal-deps\\\":\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"first-library.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"first-project-library.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"fourth-library.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"second-library.jar\\\"\");\n\t\t\texpected.add(\"- \\\"my-snapshot-deps\\\":\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"second-project-library-SNAPSHOT.jar\\\"\");\n\t\t\texpected.add(\"  - \\\"\" + this.libPath + \"third-library-SNAPSHOT.jar\\\"\");\n\t\t\texpected.add(\"- \\\"resources\\\":\");\n\t\t\texpected.add(\"  - \\\"\" + this.classesPath + \"static/\\\"\");\n\t\t\texpected.add(\"- \\\"application\\\":\");\n\t\t\tSet<String> applicationContents = new TreeSet<>();\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.classesPath + \"application.properties\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.classesPath + \"com/\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.indexPath + \"classpath.idx\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"\" + this.indexPath + \"layers.idx\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"META-INF/\\\"\");\n\t\t\tapplicationContents.add(\"  - \\\"org/\\\"\");\n\t\t\texpected.addAll(applicationContents);\n\t\t\tassertThat(index).containsExactlyElementsOf(expected);\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenArchiveIsLayeredThenToolsJarIsIncluded() throws IOException {\n\t\tList<String> entryNames = getEntryNames(createLayeredJar());\n\t\tassertThat(entryNames).contains(this.libPath + JarModeLibrary.TOOLS.getName());\n\t}\n\n\t@Test\n\tvoid shouldAddToolsToTheJar() throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\tList<String> entryNames = getEntryNames(this.task.getArchiveFile().get().getAsFile());\n\t\tassertThat(entryNames).isNotEmpty().contains(this.libPath + JarModeLibrary.TOOLS.getName());\n\t}\n\n\t@Test\n\tvoid whenIncludeToolsIsFalseThenToolsAreNotAddedToTheJar() throws IOException {\n\t\tthis.task.getIncludeTools().set(false);\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\tList<String> entryNames = getEntryNames(this.task.getArchiveFile().get().getAsFile());\n\t\tassertThat(entryNames).isNotEmpty().doesNotContain(this.libPath + JarModeLibrary.TOOLS.getName());\n\t}\n\n\tprotected File jarFile(String name) throws IOException {\n\t\tFile file = newFile(name);\n\t\ttry (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {\n\t\t\tjar.putNextEntry(new ZipEntry(\"META-INF/MANIFEST.MF\"));\n\t\t\tnew Manifest().write(jar);\n\t\t\tjar.closeEntry();\n\t\t}\n\t\treturn file;\n\t}\n\n\tprivate T configure(T task) {\n\t\tAbstractArchiveTask archiveTask = task;\n\t\tarchiveTask.getArchiveBaseName().set(\"test\");\n\t\tFile destination = new File(this.temp, \"destination\");\n\t\tdestination.mkdirs();\n\t\tarchiveTask.getDestinationDirectory().set(destination);\n\t\treturn task;\n\t}\n\n\tprotected abstract void executeTask();\n\n\tprotected T getTask() {\n\t\treturn this.task;\n\t}\n\n\tprotected List<String> getEntryNames(File file) throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\treturn getEntryNames(jarFile);\n\t\t}\n\t}\n\n\tprotected List<String> getEntryNames(JarFile jarFile) {\n\t\tList<String> entryNames = new ArrayList<>();\n\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\twhile (entries.hasMoreElements()) {\n\t\t\tentryNames.add(entries.nextElement().getName());\n\t\t}\n\t\treturn entryNames;\n\t}\n\n\tprotected File newFiles(String... names) throws IOException {\n\t\tFile dir = new File(this.temp, UUID.randomUUID().toString());\n\t\tdir.mkdir();\n\t\tList<File> files = new ArrayList<>();\n\t\tfor (String name : names) {\n\t\t\tFile file = new File(dir, name);\n\t\t\tfile.getParentFile().mkdirs();\n\t\t\tfile.createNewFile();\n\t\t\tfiles.add(file);\n\t\t}\n\t\treturn dir;\n\t}\n\n\tprotected File newFile(String name) throws IOException {\n\t\tFile file = new File(this.temp, name);\n\t\tfile.createNewFile();\n\t\treturn file;\n\t}\n\n\tFile createLayeredJar() throws IOException {\n\t\treturn createLayeredJar(false);\n\t}\n\n\tFile createLayeredJar(boolean addReachabilityProperties) throws IOException {\n\t\treturn createLayeredJar(addReachabilityProperties, (spec) -> {\n\t\t});\n\t}\n\n\tFile createLayeredJar(Action<LayeredSpec> action) throws IOException {\n\t\treturn createLayeredJar(false, action);\n\t}\n\n\tFile createLayeredJar(boolean addReachabilityProperties, Action<LayeredSpec> action) throws IOException {\n\t\tapplyLayered(action);\n\t\taddContent(addReachabilityProperties);\n\t\texecuteTask();\n\t\treturn getTask().getArchiveFile().get().getAsFile();\n\t}\n\n\tFile createPopulatedJar() throws IOException {\n\t\treturn createPopulatedJar(false);\n\t}\n\n\tFile createPopulatedJar(boolean addReachabilityProperties) throws IOException {\n\t\taddContent(addReachabilityProperties);\n\t\texecuteTask();\n\t\treturn getTask().getArchiveFile().get().getAsFile();\n\t}\n\n\tabstract void applyLayered(Action<LayeredSpec> action);\n\n\tvoid addContent() throws IOException {\n\t\taddContent(false);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tvoid addContent(boolean addReachabilityProperties) throws IOException {\n\t\tthis.task.getMainClass().set(\"com.example.Main\");\n\t\tFile classesJavaMain = new File(this.temp, \"classes/java/main\");\n\t\tFile applicationClass = new File(classesJavaMain, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tFile resourcesMain = new File(this.temp, \"resources/main\");\n\t\tFile applicationProperties = new File(resourcesMain, \"application.properties\");\n\t\tapplicationProperties.getParentFile().mkdirs();\n\t\tapplicationProperties.createNewFile();\n\t\tFile staticResources = new File(resourcesMain, \"static\");\n\t\tstaticResources.mkdir();\n\t\tFile css = new File(staticResources, \"test.css\");\n\t\tcss.createNewFile();\n\t\tif (addReachabilityProperties) {\n\t\t\tcreateReachabilityProperties(resourcesMain, \"com.example\", \"first-library\", \"1.0.0\", \"true\");\n\t\t\tcreateReachabilityProperties(resourcesMain, \"com.example\", \"second-library\", \"1.0.0\", \"true\");\n\t\t\tcreateReachabilityProperties(resourcesMain, \"com.example\", \"fourth-library\", \"1.0.0\", \"false\");\n\t\t}\n\t\tthis.task.classpath(classesJavaMain, resourcesMain, jarFile(\"first-library.jar\"), jarFile(\"second-library.jar\"),\n\t\t\t\tjarFile(\"third-library-SNAPSHOT.jar\"), jarFile(\"fourth-library.jar\"),\n\t\t\t\tjarFile(\"first-project-library.jar\"), jarFile(\"second-project-library-SNAPSHOT.jar\"));\n\t\tSet<ResolvedArtifactResult> resolvedArtifacts = new LinkedHashSet<>();\n\t\tresolvedArtifacts.add(mockArtifact(\"first-library.jar\", \"com.example\", \"first-library\", \"1.0.0\"));\n\t\tresolvedArtifacts.add(mockArtifact(\"second-library.jar\", \"com.example\", \"second-library\", \"1.0.0\"));\n\t\tresolvedArtifacts\n\t\t\t.add(mockArtifact(\"third-library-SNAPSHOT.jar\", \"com.example\", \"third-library\", \"1.0.0.SNAPSHOT\"));\n\t\tresolvedArtifacts.add(mockArtifact(\"fourth-library.jar\", \"com.example\", \"fourth-library\", \"1.0.0\"));\n\t\tresolvedArtifacts\n\t\t\t.add(mockArtifact(\"first-project-library.jar\", \"com.example\", \"first-project-library\", \"1.0.0\"));\n\t\tresolvedArtifacts.add(mockArtifact(\"second-project-library-SNAPSHOT.jar\", \"com.example\",\n\t\t\t\t\"second-project-library\", \"1.0.0.SNAPSHOT\"));\n\t\tArtifactCollection artifacts = mock(ArtifactCollection.class);\n\t\tgiven(artifacts.getResolvedArtifacts()).willReturn(this.project.provider(() -> resolvedArtifacts));\n\t\tResolvableDependencies resolvableDependencies = mock(ResolvableDependencies.class);\n\t\tgiven(resolvableDependencies.getArtifacts()).willReturn(artifacts);\n\t\tConfiguration configuration = mock(Configuration.class);\n\t\tgiven(configuration.getIncoming()).willReturn(resolvableDependencies);\n\t\tDependencySet dependencies = mock(DependencySet.class);\n\t\tDomainObjectSet<ProjectDependency> projectDependencies = mock(DomainObjectSet.class);\n\t\tgiven(dependencies.withType(ProjectDependency.class)).willReturn(projectDependencies);\n\t\tgiven(configuration.getAllDependencies()).willReturn(dependencies);\n\t\twillAnswer((invocation) -> {\n\t\t\tinvocation.getArgument(0, Action.class).execute(resolvableDependencies);\n\t\t\treturn null;\n\t\t}).given(resolvableDependencies).afterResolve(any(Action.class));\n\t\tgiven(configuration.getIncoming()).willReturn(resolvableDependencies);\n\t\tpopulateResolvedDependencies(configuration);\n\t}\n\n\tprotected void createReachabilityProperties(File directory, String groupId, String artifactId, String version,\n\t\t\tString override) throws IOException {\n\t\tFile targetDirectory = new File(directory,\n\t\t\t\t\"META-INF/native-image/%s/%s/%s\".formatted(groupId, artifactId, version));\n\t\tFile target = new File(targetDirectory, \"reachability-metadata.properties\");\n\t\ttargetDirectory.mkdirs();\n\t\tFileCopyUtils.copy(\"override=%s\\n\".formatted(override).getBytes(StandardCharsets.ISO_8859_1), target);\n\t}\n\n\tprivate void populateResolvedDependencies(Configuration configuration) {\n\t\tgetTask().resolvedArtifacts(configuration.getIncoming().getArtifacts().getResolvedArtifacts());\n\t}\n\n\tprivate ResolvedArtifactResult mockArtifact(String fileName, String group, String module, String version) {\n\t\tModuleComponentArtifactIdentifier moduleId = mock(ModuleComponentArtifactIdentifier.class);\n\t\tModuleComponentIdentifier componentId = mock(ModuleComponentIdentifier.class);\n\t\tgiven(moduleId.getComponentIdentifier()).willReturn(componentId);\n\t\tgiven(componentId.getGroup()).willReturn(group);\n\t\tgiven(componentId.getModule()).willReturn(module);\n\t\tgiven(componentId.getVersion()).willReturn(version);\n\t\tResolvedArtifactResult libraryArtifact = mock(ResolvedArtifactResult.class);\n\t\tFile file = new File(this.temp, fileName).getAbsoluteFile();\n\t\tgiven(libraryArtifact.getFile()).willReturn(file);\n\t\tgiven(libraryArtifact.getId()).willReturn(moduleId);\n\t\treturn libraryArtifact;\n\t}\n\n\tList<String> entryLines(JarFile jarFile, String entryName) throws IOException {\n\t\ttry (BufferedReader reader = new BufferedReader(\n\t\t\t\tnew InputStreamReader(jarFile.getInputStream(jarFile.getEntry(entryName))))) {\n\t\t\treturn reader.lines().toList();\n\t\t}\n\t}\n\n\tprivate Set<String> getLayerNames(List<String> index) {\n\t\tSet<String> layerNames = new LinkedHashSet<>();\n\t\tfor (String line : index) {\n\t\t\tif (line.startsWith(\"- \")) {\n\t\t\t\tlayerNames.add(line.substring(3, line.length() - 2));\n\t\t\t}\n\t\t}\n\t\treturn layerNames;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.gradle.api.Project;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.buildpack.platform.build.BuildRequest;\nimport org.springframework.boot.buildpack.platform.build.BuildpackReference;\nimport org.springframework.boot.buildpack.platform.build.PullPolicy;\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.gradle.junit.GradleProjectBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BootBuildImage}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Andrey Shlykov\n * @author Jeroen Meijer\n * @author Rafael Ceccone\n */\nclass BootBuildImageTests {\n\n\tProject project;\n\n\tprivate BootBuildImage buildImage;\n\n\t@BeforeEach\n\tvoid setUp(@TempDir File temp) {\n\t\tFile projectDir = new File(temp, \"project\");\n\t\tprojectDir.mkdirs();\n\t\tthis.project = GradleProjectBuilder.builder().withProjectDir(projectDir).withName(\"build-image-test\").build();\n\t\tthis.project.setDescription(\"Test project for BootBuildImage\");\n\t\tthis.buildImage = this.project.getTasks().register(\"buildImage\", BootBuildImage.class).get();\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsUnspecifiedThenItIsIgnoredWhenDerivingImageName() {\n\t\tassertThat(this.buildImage.getImageName().get()).isEqualTo(\"docker.io/library/build-image-test\");\n\t\tBuildRequest request = this.buildImage.createRequest();\n\t\tassertThat(request.getName().getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(request.getName().getName()).isEqualTo(\"library/build-image-test\");\n\t\tassertThat(request.getName().getTag()).isEqualTo(\"latest\");\n\t\tassertThat(request.getName().getDigest()).isNull();\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsSpecifiedThenItIsUsedInTagOfImageName() {\n\t\tthis.project.setVersion(\"1.2.3\");\n\t\tassertThat(this.buildImage.getImageName().get()).isEqualTo(\"docker.io/library/build-image-test:1.2.3\");\n\t\tBuildRequest request = this.buildImage.createRequest();\n\t\tassertThat(request.getName().getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(request.getName().getName()).isEqualTo(\"library/build-image-test\");\n\t\tassertThat(request.getName().getTag()).isEqualTo(\"1.2.3\");\n\t\tassertThat(request.getName().getDigest()).isNull();\n\t}\n\n\t@Test\n\tvoid whenImageNameIsSpecifiedThenItIsUsedInRequest() {\n\t\tthis.project.setVersion(\"1.2.3\");\n\t\tthis.buildImage.getImageName().set(\"example.com/test/build-image:1.0\");\n\t\tassertThat(this.buildImage.getImageName().get()).isEqualTo(\"example.com/test/build-image:1.0\");\n\t\tBuildRequest request = this.buildImage.createRequest();\n\t\tassertThat(request.getName().getDomain()).isEqualTo(\"example.com\");\n\t\tassertThat(request.getName().getName()).isEqualTo(\"test/build-image\");\n\t\tassertThat(request.getName().getTag()).isEqualTo(\"1.0\");\n\t\tassertThat(request.getName().getDigest()).isNull();\n\t}\n\n\t@Test\n\tvoid springBootVersionDefaultValueIsUsed() {\n\t\tBuildRequest request = this.buildImage.createRequest();\n\t\tassertThat(request.getCreator().getName()).isEqualTo(\"Spring Boot\");\n\t\tassertThat(request.getCreator().getVersion()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenIndividualEntriesAreAddedToTheEnvironmentThenTheyAreIncludedInTheRequest() {\n\t\tthis.buildImage.getEnvironment().put(\"ALPHA\", \"a\");\n\t\tthis.buildImage.getEnvironment().put(\"BRAVO\", \"b\");\n\t\tassertThat(this.buildImage.createRequest().getEnv()).containsEntry(\"ALPHA\", \"a\")\n\t\t\t.containsEntry(\"BRAVO\", \"b\")\n\t\t\t.hasSize(2);\n\t}\n\n\t@Test\n\tvoid whenEntriesAreAddedToTheEnvironmentThenTheyAreIncludedInTheRequest() {\n\t\tMap<String, String> environment = new HashMap<>();\n\t\tenvironment.put(\"ALPHA\", \"a\");\n\t\tenvironment.put(\"BRAVO\", \"b\");\n\t\tthis.buildImage.getEnvironment().putAll(environment);\n\t\tassertThat(this.buildImage.createRequest().getEnv()).containsEntry(\"ALPHA\", \"a\")\n\t\t\t.containsEntry(\"BRAVO\", \"b\")\n\t\t\t.hasSize(2);\n\t}\n\n\t@Test\n\tvoid whenTheEnvironmentIsSetItIsIncludedInTheRequest() {\n\t\tMap<String, String> environment = new HashMap<>();\n\t\tenvironment.put(\"ALPHA\", \"a\");\n\t\tenvironment.put(\"BRAVO\", \"b\");\n\t\tthis.buildImage.getEnvironment().set(environment);\n\t\tassertThat(this.buildImage.createRequest().getEnv()).containsEntry(\"ALPHA\", \"a\")\n\t\t\t.containsEntry(\"BRAVO\", \"b\")\n\t\t\t.hasSize(2);\n\t}\n\n\t@Test\n\tvoid whenTheEnvironmentIsSetItReplacesAnyExistingEntriesAndIsIncludedInTheRequest() {\n\t\tMap<String, String> environment = new HashMap<>();\n\t\tenvironment.put(\"ALPHA\", \"a\");\n\t\tenvironment.put(\"BRAVO\", \"b\");\n\t\tthis.buildImage.getEnvironment().put(\"C\", \"Charlie\");\n\t\tthis.buildImage.getEnvironment().set(environment);\n\t\tassertThat(this.buildImage.createRequest().getEnv()).containsEntry(\"ALPHA\", \"a\")\n\t\t\t.containsEntry(\"BRAVO\", \"b\")\n\t\t\t.hasSize(2);\n\t}\n\n\t@Test\n\tvoid whenEnvironmentVariablesAreSetOnTheCommandLineTheyAreIncludedInTheRequest() {\n\t\tthis.buildImage.getEnvironmentFromCommandLine().add(\"ALPHA=a\");\n\t\tthis.buildImage.getEnvironmentFromCommandLine().add(\"BRAVO=b\");\n\t\tassertThat(this.buildImage.createRequest().getEnv()).containsEntry(\"ALPHA\", \"a\")\n\t\t\t.containsEntry(\"BRAVO\", \"b\")\n\t\t\t.hasSize(2);\n\t}\n\n\t@Test\n\tvoid environmentVariablesFromTheCommandLineOverrideThoseInTheBuildScript() {\n\t\tthis.buildImage.getEnvironment().put(\"ALPHA\", \"a\");\n\t\tthis.buildImage.getEnvironmentFromCommandLine().add(\"ALPHA=apple\");\n\t\tthis.buildImage.getEnvironmentFromCommandLine().add(\"BRAVO=banana\");\n\t\tassertThat(this.buildImage.createRequest().getEnv()).containsEntry(\"ALPHA\", \"apple\")\n\t\t\t.containsEntry(\"BRAVO\", \"banana\")\n\t\t\t.hasSize(2);\n\t}\n\n\t@Test\n\tvoid whenUsingDefaultConfigurationThenRequestHasVerboseLoggingDisabled() {\n\t\tassertThat(this.buildImage.createRequest().isVerboseLogging()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenVerboseLoggingIsEnabledThenRequestHasVerboseLoggingEnabled() {\n\t\tthis.buildImage.getVerboseLogging().set(true);\n\t\tassertThat(this.buildImage.createRequest().isVerboseLogging()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenUsingDefaultConfigurationThenRequestHasCleanCacheDisabled() {\n\t\tassertThat(this.buildImage.createRequest().isCleanCache()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenCleanCacheIsEnabledThenRequestHasCleanCacheEnabled() {\n\t\tthis.buildImage.getCleanCache().set(true);\n\t\tassertThat(this.buildImage.createRequest().isCleanCache()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenUsingDefaultConfigurationThenRequestHasPublishDisabled() {\n\t\tassertThat(this.buildImage.createRequest().isPublish()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenNoBuilderIsConfiguredThenRequestHasDefaultBuilder() {\n\t\tBuildRequest request = this.buildImage.createRequest();\n\t\tassertThat(request.getBuilder().getName()).isEqualTo(\"paketobuildpacks/builder-noble-java-tiny\");\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenBuilderIsConfiguredThenRequestUsesSpecifiedBuilder() {\n\t\tthis.buildImage.getBuilder().set(\"example.com/test/builder:1.2\");\n\t\tBuildRequest request = this.buildImage.createRequest();\n\t\tassertThat(request.getBuilder().getName()).isEqualTo(\"test/builder\");\n\t\tassertThat(request.isTrustBuilder()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenTrustBuilderIsEnabledThenRequestHasTrustBuilderEnabled() {\n\t\tthis.buildImage.getBuilder().set(\"example.com/test/builder:1.2\");\n\t\tthis.buildImage.getTrustBuilder().set(true);\n\t\tassertThat(this.buildImage.createRequest().isTrustBuilder()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenNoRunImageIsConfiguredThenRequestUsesDefaultRunImage() {\n\t\tassertThat(this.buildImage.createRequest().getRunImage()).isNull();\n\t}\n\n\t@Test\n\tvoid whenRunImageIsConfiguredThenRequestUsesSpecifiedRunImage() {\n\t\tthis.buildImage.getRunImage().set(\"example.com/test/run:1.0\");\n\t\tImageReference runImage = this.buildImage.createRequest().getRunImage();\n\t\tassertThat(runImage).isNotNull();\n\t\tassertThat(runImage.getName()).isEqualTo(\"test/run\");\n\t}\n\n\t@Test\n\tvoid whenUsingDefaultConfigurationThenRequestHasAlwaysPullPolicy() {\n\t\tassertThat(this.buildImage.createRequest().getPullPolicy()).isEqualTo(PullPolicy.ALWAYS);\n\t}\n\n\t@Test\n\tvoid whenPullPolicyIsConfiguredThenRequestHasPullPolicy() {\n\t\tthis.buildImage.getPullPolicy().set(PullPolicy.NEVER);\n\t\tassertThat(this.buildImage.createRequest().getPullPolicy()).isEqualTo(PullPolicy.NEVER);\n\t}\n\n\t@Test\n\tvoid whenNoBuildpacksAreConfiguredThenRequestUsesDefaultBuildpacks() {\n\t\tassertThat(this.buildImage.createRequest().getBuildpacks()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenBuildpacksAreConfiguredThenRequestHasBuildpacks() {\n\t\tthis.buildImage.getBuildpacks().set(Arrays.asList(\"example/buildpack1\", \"example/buildpack2\"));\n\t\tassertThat(this.buildImage.createRequest().getBuildpacks())\n\t\t\t.containsExactly(BuildpackReference.of(\"example/buildpack1\"), BuildpackReference.of(\"example/buildpack2\"));\n\t}\n\n\t@Test\n\tvoid whenEntriesAreAddedToBuildpacksThenRequestHasBuildpacks() {\n\t\tthis.buildImage.getBuildpacks().addAll(Arrays.asList(\"example/buildpack1\", \"example/buildpack2\"));\n\t\tassertThat(this.buildImage.createRequest().getBuildpacks())\n\t\t\t.containsExactly(BuildpackReference.of(\"example/buildpack1\"), BuildpackReference.of(\"example/buildpack2\"));\n\t}\n\n\t@Test\n\tvoid whenIndividualEntriesAreAddedToBuildpacksThenRequestHasBuildpacks() {\n\t\tthis.buildImage.getBuildpacks().add(\"example/buildpack1\");\n\t\tthis.buildImage.getBuildpacks().add(\"example/buildpack2\");\n\t\tassertThat(this.buildImage.createRequest().getBuildpacks())\n\t\t\t.containsExactly(BuildpackReference.of(\"example/buildpack1\"), BuildpackReference.of(\"example/buildpack2\"));\n\t}\n\n\t@Test\n\tvoid whenNoBindingsAreConfiguredThenRequestHasNoBindings() {\n\t\tassertThat(this.buildImage.createRequest().getBindings()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenBindingsAreConfiguredThenRequestHasBindings() {\n\t\tthis.buildImage.getBindings().set(Arrays.asList(\"host-src:container-dest:ro\", \"volume-name:container-dest:rw\"));\n\t\tassertThat(this.buildImage.createRequest().getBindings())\n\t\t\t.containsExactly(Binding.of(\"host-src:container-dest:ro\"), Binding.of(\"volume-name:container-dest:rw\"));\n\t}\n\n\t@Test\n\tvoid whenEntriesAreAddedToBindingsThenRequestHasBindings() {\n\t\tthis.buildImage.getBindings()\n\t\t\t.addAll(Arrays.asList(\"host-src:container-dest:ro\", \"volume-name:container-dest:rw\"));\n\t\tassertThat(this.buildImage.createRequest().getBindings())\n\t\t\t.containsExactly(Binding.of(\"host-src:container-dest:ro\"), Binding.of(\"volume-name:container-dest:rw\"));\n\t}\n\n\t@Test\n\tvoid whenIndividualEntriesAreAddedToBindingsThenRequestHasBindings() {\n\t\tthis.buildImage.getBindings().add(\"host-src:container-dest:ro\");\n\t\tthis.buildImage.getBindings().add(\"volume-name:container-dest:rw\");\n\t\tassertThat(this.buildImage.createRequest().getBindings())\n\t\t\t.containsExactly(Binding.of(\"host-src:container-dest:ro\"), Binding.of(\"volume-name:container-dest:rw\"));\n\t}\n\n\t@Test\n\tvoid whenNetworkIsConfiguredThenRequestHasNetwork() {\n\t\tthis.buildImage.getNetwork().set(\"test\");\n\t\tassertThat(this.buildImage.createRequest().getNetwork()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid whenNoTagsAreConfiguredThenRequestHasNoTags() {\n\t\tassertThat(this.buildImage.createRequest().getTags()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenTagsAreConfiguredThenRequestHasTags() {\n\t\tthis.buildImage.getTags()\n\t\t\t.set(Arrays.asList(\"my-app:latest\", \"example.com/my-app:0.0.1-SNAPSHOT\", \"example.com/my-app:latest\"));\n\t\tassertThat(this.buildImage.createRequest().getTags()).containsExactly(ImageReference.of(\"my-app:latest\"),\n\t\t\t\tImageReference.of(\"example.com/my-app:0.0.1-SNAPSHOT\"), ImageReference.of(\"example.com/my-app:latest\"));\n\t}\n\n\t@Test\n\tvoid whenEntriesAreAddedToTagsThenRequestHasTags() {\n\t\tthis.buildImage.getTags()\n\t\t\t.addAll(Arrays.asList(\"my-app:latest\", \"example.com/my-app:0.0.1-SNAPSHOT\", \"example.com/my-app:latest\"));\n\t\tassertThat(this.buildImage.createRequest().getTags()).containsExactly(ImageReference.of(\"my-app:latest\"),\n\t\t\t\tImageReference.of(\"example.com/my-app:0.0.1-SNAPSHOT\"), ImageReference.of(\"example.com/my-app:latest\"));\n\t}\n\n\t@Test\n\tvoid whenIndividualEntriesAreAddedToTagsThenRequestHasTags() {\n\t\tthis.buildImage.getTags().add(\"my-app:latest\");\n\t\tthis.buildImage.getTags().add(\"example.com/my-app:0.0.1-SNAPSHOT\");\n\t\tthis.buildImage.getTags().add(\"example.com/my-app:latest\");\n\t\tassertThat(this.buildImage.createRequest().getTags()).containsExactly(ImageReference.of(\"my-app:latest\"),\n\t\t\t\tImageReference.of(\"example.com/my-app:0.0.1-SNAPSHOT\"), ImageReference.of(\"example.com/my-app:latest\"));\n\t}\n\n\t@Test\n\tvoid whenSecurityOptionsAreNotConfiguredThenRequestHasNoSecurityOptions() {\n\t\tassertThat(this.buildImage.createRequest().getSecurityOptions()).isNull();\n\t}\n\n\t@Test\n\tvoid whenSecurityOptionsAreEmptyThenRequestHasEmptySecurityOptions() {\n\t\tthis.buildImage.getSecurityOptions().set(Collections.emptyList());\n\t\tassertThat(this.buildImage.createRequest().getSecurityOptions()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenSecurityOptionsAreConfiguredThenRequestHasSecurityOptions() {\n\t\tthis.buildImage.getSecurityOptions().add(\"label=user:USER\");\n\t\tthis.buildImage.getSecurityOptions().add(\"label=role:ROLE\");\n\t\tassertThat(this.buildImage.createRequest().getSecurityOptions()).containsExactly(\"label=user:USER\",\n\t\t\t\t\"label=role:ROLE\");\n\t}\n\n\t@Test\n\tvoid whenImagePlatformIsNotConfiguredThenRequestHasNoImagePlatform() {\n\t\tassertThat(this.buildImage.createRequest().getImagePlatform()).isNull();\n\t}\n\n\t@Test\n\tvoid whenImagePlatformIsConfiguredThenRequestHasImagePlatform() {\n\t\tthis.buildImage.getImagePlatform().set(\"linux/arm64/v1\");\n\t\tassertThat(this.buildImage.createRequest().getImagePlatform()).isEqualTo(ImagePlatform.of(\"linux/arm64/v1\"));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.junit.jupiter.api.Assumptions;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link BootJar}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Paddy Drury\n */\n@GradleCompatibility(configurationCache = true)\nclass BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {\n\n\tBootJarIntegrationTests() {\n\t\tsuper(\"bootJar\", \"BOOT-INF/lib/\", \"BOOT-INF/classes/\", \"BOOT-INF/\");\n\t}\n\n\t@TestTemplate\n\tvoid whenAResolvableCopyOfAnUnresolvableConfigurationIsResolvedThenResolutionSucceeds() {\n\t\tAssumptions.assumeTrue(this.gradleBuild.gradleVersionIsLessThan(\"9.0-milestone-1\"));\n\t\tthis.gradleBuild.expectDeprecationWarningsWithAtLeastVersion(\"8.0\").build(\"build\");\n\t}\n\n\t@TestTemplate\n\tvoid packagedApplicationClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"launch\");\n\t\tString output = result.getOutput();\n\t\tassertThat(output).containsPattern(\"1\\\\. .*classes\");\n\t\tassertThat(output).containsPattern(\"2\\\\. .*library-1.0-SNAPSHOT.jar\");\n\t\tassertThat(output).containsPattern(\"3\\\\. .*commons-lang3-3.9.jar\");\n\t\tassertThat(output).containsPattern(\"4\\\\. .*spring-boot-jarmode-tools.*.jar\");\n\t\tassertThat(output).doesNotContain(\"5. \");\n\t}\n\n\t@TestTemplate\n\tvoid explodedApplicationClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"launch\");\n\t\tString output = result.getOutput();\n\t\tassertThat(output).containsPattern(\"1\\\\. .*classes\");\n\t\tassertThat(output).containsPattern(\"2\\\\. .*spring-boot-jarmode-tools.*.jar\");\n\t\tassertThat(output).containsPattern(\"3\\\\. .*library-1.0-SNAPSHOT.jar\");\n\t\tassertThat(output).containsPattern(\"4\\\\. .*commons-lang3-3.9.jar\");\n\t\tassertThat(output).doesNotContain(\"5. \");\n\t}\n\n\tprivate void copyClasspathApplication() throws IOException {\n\t\tcopyApplication(\"classpath\");\n\t}\n\n\t@Override\n\tString[] getExpectedApplicationLayerContents(String... additionalFiles) {\n\t\tSet<String> contents = new TreeSet<>(Arrays.asList(additionalFiles));\n\t\tcontents.addAll(Arrays.asList(\"BOOT-INF/classpath.idx\", \"BOOT-INF/layers.idx\", \"META-INF/\"));\n\t\treturn contents.toArray(new String[0]);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.JarFile;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.JavaVersion;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BootJar}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Paddy Drury\n */\n@ClassPathExclusions(\"kotlin-daemon-client-*\")\nclass BootJarTests extends AbstractBootArchiveTests<BootJar> {\n\n\tBootJarTests() {\n\t\tsuper(BootJar.class, \"org.springframework.boot.loader.launch.JarLauncher\", \"BOOT-INF/lib/\", \"BOOT-INF/classes/\",\n\t\t\t\t\"BOOT-INF/\");\n\t}\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.getTask().getTargetJavaVersion().set(JavaVersion.VERSION_17);\n\t}\n\n\t@Test\n\tvoid contentCanBeAddedToBootInfUsingCopySpecFromGetter() throws IOException {\n\t\tBootJar bootJar = getTask();\n\t\tbootJar.getMainClass().set(\"com.example.Application\");\n\t\tbootJar.getBootInf().into(\"test\").from(new File(\"build.gradle\").getAbsolutePath());\n\t\tbootJar.copy();\n\t\ttry (JarFile jarFile = new JarFile(bootJar.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getJarEntry(\"BOOT-INF/test/build.gradle\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid contentCanBeAddedToBootInfUsingCopySpecAction() throws IOException {\n\t\tBootJar bootJar = getTask();\n\t\tbootJar.getMainClass().set(\"com.example.Application\");\n\t\tbootJar.bootInf((copySpec) -> copySpec.into(\"test\").from(new File(\"build.gradle\").getAbsolutePath()));\n\t\tbootJar.copy();\n\t\ttry (JarFile jarFile = new JarFile(bootJar.getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getJarEntry(\"BOOT-INF/test/build.gradle\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid jarsInLibAreStored() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar())) {\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/lib/first-library.jar\").getMethod()).isZero();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/lib/second-library.jar\").getMethod()).isZero();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/lib/third-library-SNAPSHOT.jar\").getMethod()).isZero();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/lib/first-project-library.jar\").getMethod()).isZero();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\").getMethod()).isZero();\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenJarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar())) {\n\t\t\tassertThat(entryLines(jarFile, \"BOOT-INF/classpath.idx\")).containsExactly(\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/first-library.jar\\\"\", \"- \\\"BOOT-INF/lib/second-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/third-library-SNAPSHOT.jar\\\"\", \"- \\\"BOOT-INF/lib/fourth-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/first-project-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\\\"\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid classpathIndexPointsToBootInfLibs() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createPopulatedJar())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Classpath-Index\"))\n\t\t\t\t.isEqualTo(\"BOOT-INF/classpath.idx\");\n\t\t\tassertThat(entryLines(jarFile, \"BOOT-INF/classpath.idx\")).containsExactly(\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/first-library.jar\\\"\", \"- \\\"BOOT-INF/lib/second-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/third-library-SNAPSHOT.jar\\\"\", \"- \\\"BOOT-INF/lib/fourth-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/first-project-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\\\"\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid metaInfEntryIsPackagedInTheRootOfTheArchive() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile metaInfEntry = new File(classpathDirectory, \"META-INF/test\");\n\t\tmetaInfEntry.getParentFile().mkdirs();\n\t\tmetaInfEntry.createNewFile();\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tgetTask().classpath(classpathDirectory);\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/com/example/Application.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"com/example/Application.class\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/META-INF/test\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"META-INF/test\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid aopXmlIsPackagedBeneathClassesDirectory() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile aopXml = new File(classpathDirectory, \"META-INF/aop.xml\");\n\t\taopXml.getParentFile().mkdirs();\n\t\taopXml.createNewFile();\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tgetTask().classpath(classpathDirectory);\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/com/example/Application.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"com/example/Application.class\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/META-INF/aop.xml\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"META-INF/aop.xml\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid kotlinModuleIsPackagedBeneathClassesDirectory() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile kotlinModule = new File(classpathDirectory, \"META-INF/example.kotlin_module\");\n\t\tkotlinModule.getParentFile().mkdirs();\n\t\tkotlinModule.createNewFile();\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tgetTask().classpath(classpathDirectory);\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/com/example/Application.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"com/example/Application.class\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/META-INF/example.kotlin_module\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"META-INF/example.kotlin_module\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid metaInfServicesEntryIsPackagedBeneathClassesDirectory() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tFile classpathDirectory = new File(this.temp, \"classes\");\n\t\tFile service = new File(classpathDirectory, \"META-INF/services/com.example.Service\");\n\t\tservice.getParentFile().mkdirs();\n\t\tservice.createNewFile();\n\t\tFile applicationClass = new File(classpathDirectory, \"com/example/Application.class\");\n\t\tapplicationClass.getParentFile().mkdirs();\n\t\tapplicationClass.createNewFile();\n\t\tgetTask().classpath(classpathDirectory);\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/com/example/Application.class\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"com/example/Application.class\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"BOOT-INF/classes/META-INF/services/com.example.Service\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"META-INF/services/com.example.Service\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid nativeImageArgFileWithExcludesIsWritten() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar(true))) {\n\t\t\tassertThat(entryLines(jarFile, \"META-INF/native-image/argfile\")).containsExactly(\"--exclude-config\",\n\t\t\t\t\t\"\\\\Qfirst-library.jar\\\\E\", \"^/META-INF/native-image/.*\", \"--exclude-config\",\n\t\t\t\t\t\"\\\\Qsecond-library.jar\\\\E\", \"^/META-INF/native-image/.*\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid nativeImageArgFileIsNotWrittenWhenExcludesAreEmpty() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar(false))) {\n\t\t\tassertThat(jarFile.getEntry(\"META-INF/native-image/argfile\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid javaVersionIsWrittenToManifest() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createPopulatedJar())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Build-Jdk-Spec\"))\n\t\t\t\t.isEqualTo(JavaVersion.VERSION_17.getMajorVersion());\n\t\t}\n\t}\n\n\t@Override\n\tvoid applyLayered(Action<LayeredSpec> action) {\n\t\tgetTask().layered(action);\n\t}\n\n\t@Override\n\tprotected void executeTask() {\n\t\tgetTask().copy();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.assertj.core.api.Assumptions;\nimport org.gradle.util.GradleVersion;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\n\n/**\n * Integration tests for {@link BootWar}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@GradleCompatibility(configurationCache = true)\nclass BootWarIntegrationTests extends AbstractBootArchiveIntegrationTests {\n\n\tBootWarIntegrationTests() {\n\t\tsuper(\"bootWar\", \"WEB-INF/lib/\", \"WEB-INF/classes/\", \"WEB-INF/\");\n\t}\n\n\t@Override\n\tString[] getExpectedApplicationLayerContents(String... additionalFiles) {\n\t\tSet<String> contents = new TreeSet<>(Arrays.asList(additionalFiles));\n\t\tcontents.addAll(Arrays.asList(\"WEB-INF/classpath.idx\", \"WEB-INF/layers.idx\", \"META-INF/\"));\n\t\treturn contents.toArray(new String[0]);\n\t}\n\n\t@Override\n\tvoid multiModuleImplicitLayers() throws IOException {\n\t\twhenTestingWithTheConfigurationCacheAssumeThatTheGradleVersionIsLessThan8();\n\t\tsuper.multiModuleImplicitLayers();\n\t}\n\n\t@Override\n\tvoid multiModuleCustomLayers() throws IOException {\n\t\twhenTestingWithTheConfigurationCacheAssumeThatTheGradleVersionIsLessThan8();\n\t\tsuper.multiModuleCustomLayers();\n\t}\n\n\tprivate void whenTestingWithTheConfigurationCacheAssumeThatTheGradleVersionIsLessThan8() {\n\t\tif (this.gradleBuild.isConfigurationCache()) {\n\t\t\t// With Gradle 8.0, a configuration cache bug prevents ResolvedDependencies\n\t\t\t// from processing dependencies on the runtime classpath\n\t\t\tAssumptions.assumeThat(GradleVersion.version(this.gradleBuild.getGradleVersion()))\n\t\t\t\t.isLessThan(GradleVersion.version(\"8.0\"));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.JarFile;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.JavaVersion;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BootWar}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@ClassPathExclusions(\"kotlin-daemon-client-*\")\nclass BootWarTests extends AbstractBootArchiveTests<BootWar> {\n\n\tBootWarTests() {\n\t\tsuper(BootWar.class, \"org.springframework.boot.loader.launch.WarLauncher\", \"WEB-INF/lib/\", \"WEB-INF/classes/\",\n\t\t\t\t\"WEB-INF/\");\n\t}\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.getTask().getTargetJavaVersion().set(JavaVersion.VERSION_17);\n\t}\n\n\t@Test\n\tvoid providedClasspathJarsArePackagedInWebInfLibProvided() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tgetTask().providedClasspath(jarFile(\"one.jar\"), jarFile(\"two.jar\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/one.jar\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/two.jar\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid providedClasspathCanBeSetUsingAFileCollection() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tgetTask().providedClasspath(jarFile(\"one.jar\"));\n\t\tgetTask().setProvidedClasspath(getTask().getProject().files(jarFile(\"two.jar\")));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/one.jar\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/two.jar\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid providedClasspathCanBeSetUsingAnObject() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tgetTask().providedClasspath(jarFile(\"one.jar\"));\n\t\tgetTask().setProvidedClasspath(jarFile(\"two.jar\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/one.jar\")).isNull();\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/two.jar\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid devtoolsJarIsExcludedByDefaultWhenItsOnTheProvidedClasspath() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tgetTask().providedClasspath(newFile(\"spring-boot-devtools-0.1.2.jar\"));\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"WEB-INF/lib-provided/spring-boot-devtools-0.1.2.jar\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid webappResourcesInDirectoriesThatOverlapWithLoaderCanBePackaged() throws IOException {\n\t\tFile webappDirectory = new File(this.temp, \"src/main/webapp\");\n\t\twebappDirectory.mkdirs();\n\t\tFile orgDirectory = new File(webappDirectory, \"org\");\n\t\torgDirectory.mkdir();\n\t\tnew File(orgDirectory, \"foo.txt\").createNewFile();\n\t\tgetTask().from(webappDirectory);\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\texecuteTask();\n\t\ttry (JarFile jarFile = new JarFile(getTask().getArchiveFile().get().getAsFile())) {\n\t\t\tassertThat(jarFile.getEntry(\"org/\")).isNotNull();\n\t\t\tassertThat(jarFile.getEntry(\"org/foo.txt\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid libProvidedEntriesAreWrittenAfterLibEntries() throws IOException {\n\t\tgetTask().getMainClass().set(\"com.example.Main\");\n\t\tgetTask().classpath(jarFile(\"library.jar\"));\n\t\tgetTask().providedClasspath(jarFile(\"provided-library.jar\"));\n\t\texecuteTask();\n\t\tassertThat(getEntryNames(getTask().getArchiveFile().get().getAsFile()))\n\t\t\t.containsSubsequence(\"WEB-INF/lib/library.jar\", \"WEB-INF/lib-provided/provided-library.jar\");\n\t}\n\n\t@Test\n\tvoid whenWarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createLayeredJar())) {\n\t\t\tassertThat(entryLines(jarFile, \"WEB-INF/classpath.idx\")).containsExactly(\n\t\t\t\t\t\"- \\\"WEB-INF/lib/first-library.jar\\\"\", \"- \\\"WEB-INF/lib/second-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"WEB-INF/lib/third-library-SNAPSHOT.jar\\\"\", \"- \\\"WEB-INF/lib/fourth-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"WEB-INF/lib/first-project-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"WEB-INF/lib/second-project-library-SNAPSHOT.jar\\\"\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid classpathIndexPointsToWebInfLibs() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createPopulatedJar())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Spring-Boot-Classpath-Index\"))\n\t\t\t\t.isEqualTo(\"WEB-INF/classpath.idx\");\n\t\t\tassertThat(entryLines(jarFile, \"WEB-INF/classpath.idx\")).containsExactly(\n\t\t\t\t\t\"- \\\"WEB-INF/lib/first-library.jar\\\"\", \"- \\\"WEB-INF/lib/second-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"WEB-INF/lib/third-library-SNAPSHOT.jar\\\"\", \"- \\\"WEB-INF/lib/fourth-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"WEB-INF/lib/first-project-library.jar\\\"\",\n\t\t\t\t\t\"- \\\"WEB-INF/lib/second-project-library-SNAPSHOT.jar\\\"\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid javaVersionIsWrittenToManifest() throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(createPopulatedJar())) {\n\t\t\tassertThat(jarFile.getManifest().getMainAttributes().getValue(\"Build-Jdk-Spec\"))\n\t\t\t\t.isEqualTo(JavaVersion.VERSION_17.getMajorVersion());\n\t\t}\n\t}\n\n\t@Override\n\tprotected void executeTask() {\n\t\tgetTask().copy();\n\t}\n\n\t@Override\n\tvoid applyLayered(Action<LayeredSpec> action) {\n\t\tgetTask().layered(action);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DefaultTimeZoneOffsetTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.util.Calendar;\nimport java.util.TimeZone;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DefaultTimeZoneOffset}\n *\n * @author Phillip Webb\n */\nclass DefaultTimeZoneOffsetTests {\n\n\t// gh-21005\n\n\t@Test\n\tvoid removeFromWithLongInDifferentTimeZonesReturnsSameValue() {\n\t\tlong time = OffsetDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();\n\t\tTimeZone timeZone1 = TimeZone.getTimeZone(\"GMT\");\n\t\tTimeZone timeZone2 = TimeZone.getTimeZone(\"GMT+8\");\n\t\tTimeZone timeZone3 = TimeZone.getTimeZone(\"GMT-8\");\n\t\tlong result1 = new DefaultTimeZoneOffset(timeZone1).removeFrom(time);\n\t\tlong result2 = new DefaultTimeZoneOffset(timeZone2).removeFrom(time);\n\t\tlong result3 = new DefaultTimeZoneOffset(timeZone3).removeFrom(time);\n\t\tlong dosTime1 = toDosTime(Calendar.getInstance(timeZone1), result1);\n\t\tlong dosTime2 = toDosTime(Calendar.getInstance(timeZone2), result2);\n\t\tlong dosTime3 = toDosTime(Calendar.getInstance(timeZone3), result3);\n\t\tassertThat(dosTime1).isEqualTo(dosTime2).isEqualTo(dosTime3);\n\t}\n\n\t@Test\n\tvoid removeFromWithFileTimeReturnsFileTime() {\n\t\tlong time = OffsetDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();\n\t\tlong result = new DefaultTimeZoneOffset(TimeZone.getTimeZone(\"GMT+8\")).removeFrom(time);\n\t\tassertThat(result).isNotEqualTo(time).isEqualTo(946656000000L);\n\t}\n\n\t/**\n\t * Identical functionality to package-private\n\t * org.apache.commons.compress.archivers.zip.ZipUtil.toDosTime(Calendar, long, byte[],\n\t * int) method used by {@link ZipArchiveOutputStream} to convert times.\n\t * @param calendar the source calendar\n\t * @param time the time to convert\n\t * @return the DOS time\n\t */\n\tprivate long toDosTime(Calendar calendar, long time) {\n\t\tcalendar.setTimeInMillis(time);\n\t\tfinal int year = calendar.get(Calendar.YEAR);\n\t\tfinal int month = calendar.get(Calendar.MONTH) + 1;\n\t\treturn ((year - 1980) << 25) | (month << 21) | (calendar.get(Calendar.DAY_OF_MONTH) << 16)\n\t\t\t\t| (calendar.get(Calendar.HOUR_OF_DAY) << 11) | (calendar.get(Calendar.MINUTE) << 5)\n\t\t\t\t| (calendar.get(Calendar.SECOND) >> 1);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/DockerSpecTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.util.Base64;\n\nimport org.gradle.api.GradleException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\nimport org.springframework.boot.gradle.junit.GradleProjectBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link DockerSpec}.\n *\n * @author Wei Jiang\n * @author Scott Frederick\n */\nclass DockerSpecTests {\n\n\tprivate DockerSpec dockerSpec;\n\n\t@BeforeEach\n\tvoid prepareDockerSpec(@TempDir File temp) {\n\t\tthis.dockerSpec = GradleProjectBuilder.builder()\n\t\t\t.withProjectDir(temp)\n\t\t\t.build()\n\t\t\t.getObjects()\n\t\t\t.newInstance(DockerSpec.class);\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithDefaults() {\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tassertThat(dockerConfiguration.connection()).isNull();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithHostConfiguration() {\n\t\tthis.dockerSpec.getHost().set(\"docker.example.com\");\n\t\tthis.dockerSpec.getTlsVerify().set(true);\n\t\tthis.dockerSpec.getCertPath().set(\"/tmp/ca-cert\");\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tDockerConnectionConfiguration.Host host = (DockerConnectionConfiguration.Host) dockerConfiguration.connection();\n\t\tassertThat(host).isNotNull();\n\t\tassertThat(host.address()).isEqualTo(\"docker.example.com\");\n\t\tassertThat(host.secure()).isTrue();\n\t\tassertThat(host.certificatePath()).isEqualTo(\"/tmp/ca-cert\");\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isFalse();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithHostConfigurationNoTlsVerify() {\n\t\tthis.dockerSpec.getHost().set(\"docker.example.com\");\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tDockerConnectionConfiguration.Host host = (DockerConnectionConfiguration.Host) dockerConfiguration.connection();\n\t\tassertThat(host).isNotNull();\n\t\tassertThat(host.address()).isEqualTo(\"docker.example.com\");\n\t\tassertThat(host.secure()).isFalse();\n\t\tassertThat(host.certificatePath()).isNull();\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isFalse();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithContextConfiguration() {\n\t\tthis.dockerSpec.getContext().set(\"test-context\");\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tDockerConnectionConfiguration.Context host = (DockerConnectionConfiguration.Context) dockerConfiguration\n\t\t\t.connection();\n\t\tassertThat(host).isNotNull();\n\t\tassertThat(host.context()).isEqualTo(\"test-context\");\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isFalse();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithHostAndContextFails() {\n\t\tthis.dockerSpec.getContext().set(\"test-context\");\n\t\tthis.dockerSpec.getHost().set(\"docker.example.com\");\n\t\tassertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)\n\t\t\t.withMessageContaining(\"Invalid Docker configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithBindHostToBuilder() {\n\t\tthis.dockerSpec.getHost().set(\"docker.example.com\");\n\t\tthis.dockerSpec.getBindHostToBuilder().set(true);\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tDockerConnectionConfiguration.Host host = (DockerConnectionConfiguration.Host) dockerConfiguration.connection();\n\t\tassertThat(host).isNotNull();\n\t\tassertThat(host.address()).isEqualTo(\"docker.example.com\");\n\t\tassertThat(host.secure()).isFalse();\n\t\tassertThat(host.certificatePath()).isNull();\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isTrue();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithUserAuth() {\n\t\tthis.dockerSpec.builderRegistry((registry) -> {\n\t\t\tregistry.getUsername().set(\"user1\");\n\t\t\tregistry.getPassword().set(\"secret1\");\n\t\t\tregistry.getUrl().set(\"https://docker1.example.com\");\n\t\t\tregistry.getEmail().set(\"docker1@example.com\");\n\t\t});\n\t\tthis.dockerSpec.publishRegistry((registry) -> {\n\t\t\tregistry.getUsername().set(\"user2\");\n\t\t\tregistry.getPassword().set(\"secret2\");\n\t\t\tregistry.getUrl().set(\"https://docker2.example.com\");\n\t\t\tregistry.getEmail().set(\"docker2@example.com\");\n\t\t});\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(builderRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"user1\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"secret1\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"docker1@example.com\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"https://docker1.example.com\\\"\");\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"username\\\" : \\\"user2\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"secret2\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"docker2@example.com\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"https://docker2.example.com\\\"\");\n\t\tassertThat(dockerConfiguration.connection()).isNull();\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithIncompleteBuilderUserAuthFails() {\n\t\tthis.dockerSpec.builderRegistry((registry) -> {\n\t\t\tregistry.getUsername().set(\"user1\");\n\t\t\tregistry.getUrl().set(\"https://docker1.example.com\");\n\t\t\tregistry.getEmail().set(\"docker1@example.com\");\n\t\t});\n\t\tassertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)\n\t\t\t.withMessageContaining(\"Invalid Docker builder registry configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithIncompletePublishUserAuthFails() {\n\t\tthis.dockerSpec.publishRegistry((registry) -> {\n\t\t\tregistry.getUsername().set(\"user2\");\n\t\t\tregistry.getUrl().set(\"https://docker2.example.com\");\n\t\t\tregistry.getEmail().set(\"docker2@example.com\");\n\t\t});\n\t\tassertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)\n\t\t\t.withMessageContaining(\"Invalid Docker publish registry configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithTokenAuth() {\n\t\tthis.dockerSpec.builderRegistry((registry) -> registry.getToken().set(\"token1\"));\n\t\tthis.dockerSpec.publishRegistry((registry) -> registry.getToken().set(\"token2\"));\n\t\tBuilderDockerConfiguration dockerConfiguration = this.dockerSpec.asDockerConfiguration();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(builderRegistryAuthentication.getAuthHeader())).contains(\"\\\"identitytoken\\\" : \\\"token1\\\"\");\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tassertThat(decoded(publishRegistryAuthentication.getAuthHeader())).contains(\"\\\"identitytoken\\\" : \\\"token2\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithUserAndTokenAuthFails() {\n\t\tthis.dockerSpec.builderRegistry((registry) -> {\n\t\t\tregistry.getUsername().set(\"user\");\n\t\t\tregistry.getPassword().set(\"secret\");\n\t\t\tregistry.getToken().set(\"token\");\n\t\t});\n\t\tassertThatExceptionOfType(GradleException.class).isThrownBy(this.dockerSpec::asDockerConfiguration)\n\t\t\t.withMessageContaining(\"Invalid Docker builder registry configuration\");\n\t}\n\n\t@Nullable String decoded(@Nullable String value) {\n\t\treturn (value != null) ? new String(Base64.getDecoder().decode(value)) : value;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for publishing Boot jars and wars using Gradle's Maven Publish\n * plugin.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility\nclass MavenPublishingIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid bootJarCanBePublished() {\n\t\tBuildResult result = this.gradleBuild.build(\"publish\");\n\t\tBuildTask task = result.task(\":publish\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(artifactWithSuffix(\"jar\")).isFile();\n\t\tassertThat(artifactWithSuffix(\"pom\")).is(pomWith().groupId(\"com.example\")\n\t\t\t.artifactId(this.gradleBuild.getProjectDir().getName())\n\t\t\t.version(\"1.0\")\n\t\t\t.noPackaging()\n\t\t\t.noDependencies());\n\t}\n\n\t@TestTemplate\n\tvoid bootWarCanBePublished() {\n\t\tBuildResult result = this.gradleBuild.build(\"publish\");\n\t\tBuildTask task = result.task(\":publish\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(artifactWithSuffix(\"war\")).isFile();\n\t\tassertThat(artifactWithSuffix(\"pom\")).is(pomWith().groupId(\"com.example\")\n\t\t\t.artifactId(this.gradleBuild.getProjectDir().getName())\n\t\t\t.version(\"1.0\")\n\t\t\t.packaging(\"war\")\n\t\t\t.noDependencies());\n\t}\n\n\tprivate File artifactWithSuffix(String suffix) {\n\t\tString name = this.gradleBuild.getProjectDir().getName();\n\t\treturn new File(new File(this.gradleBuild.getProjectDir(), \"build/repo\"),\n\t\t\t\tString.format(\"com/example/%s/1.0/%s-1.0.%s\", name, name, suffix));\n\t}\n\n\tprivate PomCondition pomWith() {\n\t\treturn new PomCondition();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/PomCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.bundling;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.assertj.core.api.Condition;\nimport org.assertj.core.description.Description;\nimport org.assertj.core.description.TextDescription;\n\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * AssertJ {@link Condition} for asserting the contents of a pom file.\n *\n * @author Andy Wilkinson\n */\nclass PomCondition extends Condition<File> {\n\n\tprivate final Set<String> expectedContents;\n\n\tprivate final Set<String> notExpectedContents;\n\n\tPomCondition() {\n\t\tthis(new HashSet<>(), new HashSet<>());\n\t}\n\n\tprivate PomCondition(Set<String> expectedContents, Set<String> notExpectedContents) {\n\t\tsuper(new TextDescription(\"Pom file containing %s and not containing %s\", expectedContents,\n\t\t\t\tnotExpectedContents));\n\t\tthis.expectedContents = expectedContents;\n\t\tthis.notExpectedContents = notExpectedContents;\n\t}\n\n\t@Override\n\tpublic boolean matches(File pom) {\n\t\ttry {\n\t\t\tString contents = FileCopyUtils.copyToString(new FileReader(pom));\n\t\t\tfor (String expected : this.expectedContents) {\n\t\t\t\tif (!contents.contains(expected)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (String notExpected : this.notExpectedContents) {\n\t\t\t\tif (contents.contains(notExpected)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Description description() {\n\t\treturn new TextDescription(\"Pom file containing %s and not containing %s\", this.expectedContents,\n\t\t\t\tthis.notExpectedContents);\n\t}\n\n\tPomCondition groupId(String groupId) {\n\t\tthis.expectedContents.add(String.format(\"<groupId>%s</groupId>\", groupId));\n\t\treturn this;\n\t}\n\n\tPomCondition artifactId(String artifactId) {\n\t\tthis.expectedContents.add(String.format(\"<artifactId>%s</artifactId>\", artifactId));\n\t\treturn this;\n\t}\n\n\tPomCondition version(String version) {\n\t\tthis.expectedContents.add(String.format(\"<version>%s</version>\", version));\n\t\treturn this;\n\t}\n\n\tPomCondition packaging(String packaging) {\n\t\tthis.expectedContents.add(String.format(\"<packaging>%s</packaging>\", packaging));\n\t\treturn this;\n\t}\n\n\tPomCondition noDependencies() {\n\t\tthis.notExpectedContents.add(\"<dependencies>\");\n\t\treturn this;\n\t}\n\n\tPomCondition noPackaging() {\n\t\tthis.notExpectedContents.add(\"<packaging>\");\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.run;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.function.Consumer;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\n\nimport org.assertj.core.api.Assumptions;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.gradle.util.GradleVersion;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the {@link BootRun} task.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility(configurationCache = true)\nclass BootRunIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid basicExecution() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tnew File(this.gradleBuild.getProjectDir(), \"src/main/resources\").mkdirs();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"1. \" + canonicalPathOf(\"build/classes/java/main\"));\n\t\tassertThat(result.getOutput()).contains(\"2. \" + canonicalPathOf(\"build/resources/main\"));\n\t\tassertThat(result.getOutput()).doesNotContain(canonicalPathOf(\"src/main/resources\"));\n\t}\n\n\t@TestTemplate\n\tvoid sourceResourcesCanBeUsed() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"1. \" + canonicalPathOf(\"src/main/resources\"));\n\t\tassertThat(result.getOutput()).contains(\"2. \" + canonicalPathOf(\"build/classes/java/main\"));\n\t\tassertThat(result.getOutput()).doesNotContain(canonicalPathOf(\"build/resources/main\"));\n\t}\n\n\t@TestTemplate\n\tvoid springBootExtensionMainClassNameIsUsed() throws IOException {\n\t\tcopyMainClassApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"com.example.bootrun.main.CustomMainClass\");\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginMainClassNameIsUsed() throws IOException {\n\t\tcopyMainClassApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"com.example.bootrun.main.CustomMainClass\");\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginMainClassNameIsNotUsedWhenItIsNull() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput())\n\t\t\t.contains(\"Main class name = com.example.bootrun.classpath.BootRunClasspathApplication\");\n\t}\n\n\t@TestTemplate\n\tvoid defaultJvmArgs() throws IOException {\n\t\tcopyJvmArgsApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"-XX:TieredStopAtLevel=1\");\n\t}\n\n\t@TestTemplate\n\tvoid optimizedLaunchDisabledJvmArgs() throws IOException {\n\t\tcopyJvmArgsApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).doesNotContain(\"-Xverify:none\").doesNotContain(\"-XX:TieredStopAtLevel=1\");\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginJvmArgumentsAreUsed() throws IOException {\n\t\tif (this.gradleBuild.isConfigurationCache()) {\n\t\t\t// https://github.com/gradle/gradle/pull/23924\n\t\t\tGradleVersion gradleVersion = GradleVersion.version(this.gradleBuild.getGradleVersion());\n\t\t\tAssumptions.assumeThat(gradleVersion)\n\t\t\t\t.isLessThan(GradleVersion.version(\"8.0\"))\n\t\t\t\t.isGreaterThanOrEqualTo(GradleVersion.version(\"8.1-rc-1\"));\n\t\t}\n\t\tcopyJvmArgsApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"-Dcom.bar=baz\")\n\t\t\t.contains(\"-Dcom.foo=bar\")\n\t\t\t.contains(\"-XX:TieredStopAtLevel=1\");\n\t}\n\n\t@TestTemplate\n\tvoid jarTypeFilteringIsAppliedToTheClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tFile flatDirRepository = new File(this.gradleBuild.getProjectDir(), \"repository\");\n\t\tcreateDependenciesStarterJar(new File(flatDirRepository, \"starter.jar\"));\n\t\tcreateStandardJar(new File(flatDirRepository, \"standard.jar\"));\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"standard.jar\").doesNotContain(\"starter.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid classesFromASecondarySourceSetCanBeOnTheClasspath() throws IOException {\n\t\tFile output = new File(this.gradleBuild.getProjectDir(), \"src/secondary/java/com/example/bootrun/main\");\n\t\toutput.mkdirs();\n\t\tFileSystemUtils.copyRecursively(new File(\"src/test/resources/com/example/bootrun/main\"), output);\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"com.example.bootrun.main.CustomMainClass\");\n\t}\n\n\t@TestTemplate\n\tvoid developmentOnlyDependenciesAreOnTheClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid testAndDevelopmentOnlyDependenciesAreOnTheClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootRun\");\n\t\tBuildTask task = result.task(\":bootRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\tprivate void copyMainClassApplication() throws IOException {\n\t\tcopyApplication(\"main\");\n\t}\n\n\tprivate void copyClasspathApplication() throws IOException {\n\t\tcopyApplication(\"classpath\");\n\t}\n\n\tprivate void copyJvmArgsApplication() throws IOException {\n\t\tcopyApplication(\"jvmargs\");\n\t}\n\n\tprivate void copyApplication(String name) throws IOException {\n\t\tFile output = new File(this.gradleBuild.getProjectDir(), \"src/main/java/com/example/bootrun/\" + name);\n\t\toutput.mkdirs();\n\t\tFileSystemUtils.copyRecursively(new File(\"src/test/resources/com/example/bootrun/\" + name), output);\n\t}\n\n\tprivate String canonicalPathOf(String path) throws IOException {\n\t\treturn new File(this.gradleBuild.getProjectDir(), path).getCanonicalPath();\n\t}\n\n\tprivate void createStandardJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> {\n\t\t});\n\t}\n\n\tprivate void createDependenciesStarterJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> attributes.putValue(\"Spring-Boot-Jar-Type\", \"dependencies-starter\"));\n\t}\n\n\tprivate void createJar(File location, Consumer<Attributes> attributesConfigurer) throws IOException {\n\t\tlocation.getParentFile().mkdirs();\n\t\tManifest manifest = new Manifest();\n\t\tAttributes attributes = manifest.getMainAttributes();\n\t\tattributes.put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\t\tattributesConfigurer.accept(attributes);\n\t\tnew JarOutputStream(new FileOutputStream(location), manifest).close();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.tasks.run;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.function.Consumer;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\n\nimport org.assertj.core.api.Assumptions;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.gradle.util.GradleVersion;\nimport org.junit.jupiter.api.TestTemplate;\n\nimport org.springframework.boot.gradle.junit.GradleCompatibility;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the {@link BootRun} task configured to use the test source set.\n *\n * @author Andy Wilkinson\n */\n@GradleCompatibility(configurationCache = true)\nclass BootTestRunIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@TestTemplate\n\tvoid basicExecution() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"1. \" + canonicalPathOf(\"build/classes/java/test\"))\n\t\t\t.contains(\"2. \" + canonicalPathOf(\"build/resources/test\"))\n\t\t\t.contains(\"3. \" + canonicalPathOf(\"build/classes/java/main\"))\n\t\t\t.contains(\"4. \" + canonicalPathOf(\"build/resources/main\"));\n\t}\n\n\t@TestTemplate\n\tvoid defaultJvmArgs() throws IOException {\n\t\tcopyJvmArgsApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"-XX:TieredStopAtLevel=1\");\n\t}\n\n\t@TestTemplate\n\tvoid optimizedLaunchDisabledJvmArgs() throws IOException {\n\t\tcopyJvmArgsApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).doesNotContain(\"-Xverify:none\").doesNotContain(\"-XX:TieredStopAtLevel=1\");\n\t}\n\n\t@TestTemplate\n\tvoid applicationPluginJvmArgumentsAreUsed() throws IOException {\n\t\tif (this.gradleBuild.isConfigurationCache()) {\n\t\t\t// https://github.com/gradle/gradle/pull/23924\n\t\t\tGradleVersion gradleVersion = GradleVersion.version(this.gradleBuild.getGradleVersion());\n\t\t\tAssumptions.assumeThat(gradleVersion)\n\t\t\t\t.isLessThan(GradleVersion.version(\"8.0\"))\n\t\t\t\t.isGreaterThanOrEqualTo(GradleVersion.version(\"8.1-rc-1\"));\n\t\t}\n\t\tcopyJvmArgsApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"-Dcom.bar=baz\")\n\t\t\t.contains(\"-Dcom.foo=bar\")\n\t\t\t.contains(\"-XX:TieredStopAtLevel=1\");\n\t}\n\n\t@TestTemplate\n\tvoid jarTypeFilteringIsAppliedToTheClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tFile flatDirRepository = new File(this.gradleBuild.getProjectDir(), \"repository\");\n\t\tcreateDependenciesStarterJar(new File(flatDirRepository, \"starter.jar\"));\n\t\tcreateStandardJar(new File(flatDirRepository, \"standard.jar\"));\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"standard.jar\").doesNotContain(\"starter.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid failsGracefullyWhenNoTestMainMethodIsFound() throws IOException {\n\t\tcopyApplication(\"nomain\");\n\t\tBuildResult result = this.gradleBuild.buildAndFail(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.FAILED);\n\t\tif (this.gradleBuild.isConfigurationCache() && this.gradleBuild.gradleVersionIsAtLeast(\"8.0\")) {\n\t\t\tassertThat(result.getOutput())\n\t\t\t\t.contains(\"Main class name has not been configured and it could not be resolved from classpath\");\n\t\t}\n\t\telse {\n\t\t\tassertThat(result.getOutput())\n\t\t\t\t.contains(\"Main class name has not been configured and it could not be resolved from classpath \"\n\t\t\t\t\t\t+ canonicalPathOf(\"build/classes/java/test\"));\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid developmentOnlyDependenciesAreNotOnTheClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).doesNotContain(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\t@TestTemplate\n\tvoid testAndDevelopmentOnlyDependenciesAreOnTheClasspath() throws IOException {\n\t\tcopyClasspathApplication();\n\t\tBuildResult result = this.gradleBuild.build(\"bootTestRun\");\n\t\tBuildTask task = result.task(\":bootTestRun\");\n\t\tassertThat(task).isNotNull();\n\t\tassertThat(task.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"commons-lang3-3.12.0.jar\");\n\t}\n\n\tprivate void copyClasspathApplication() throws IOException {\n\t\tcopyApplication(\"classpath\");\n\t}\n\n\tprivate void copyJvmArgsApplication() throws IOException {\n\t\tcopyApplication(\"jvmargs\");\n\t}\n\n\tprivate void copyApplication(String name) throws IOException {\n\t\tFile output = new File(this.gradleBuild.getProjectDir(), \"src/test/java/com/example/boottestrun/\" + name);\n\t\toutput.mkdirs();\n\t\tFileSystemUtils.copyRecursively(new File(\"src/test/resources/com/example/boottestrun/\" + name), output);\n\t}\n\n\tprivate String canonicalPathOf(String path) throws IOException {\n\t\treturn new File(this.gradleBuild.getProjectDir(), path).getCanonicalPath();\n\t}\n\n\tprivate void createStandardJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> {\n\t\t});\n\t}\n\n\tprivate void createDependenciesStarterJar(File location) throws IOException {\n\t\tcreateJar(location, (attributes) -> attributes.putValue(\"Spring-Boot-Jar-Type\", \"dependencies-starter\"));\n\t}\n\n\tprivate void createJar(File location, Consumer<Attributes> attributesConfigurer) throws IOException {\n\t\tlocation.getParentFile().mkdirs();\n\t\tManifest manifest = new Manifest();\n\t\tAttributes attributes = manifest.getMainAttributes();\n\t\tattributes.put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\t\tattributesConfigurer.accept(attributes);\n\t\tnew JarOutputStream(new FileOutputStream(location), manifest).close();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/PluginClasspathGradleBuild.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gradle.testkit;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.fasterxml.jackson.annotation.JsonView;\nimport com.google.protobuf.gradle.ProtobufPlugin;\nimport com.sun.jna.Platform;\nimport io.spring.gradle.dependencymanagement.DependencyManagementPlugin;\nimport org.antlr.v4.runtime.Lexer;\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.hc.client5.http.io.HttpClientConnectionManager;\nimport org.apache.hc.core5.http.HttpRequest;\nimport org.apache.hc.core5.http2.HttpVersionPolicy;\nimport org.cyclonedx.gradle.CyclonedxPlugin;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.jetbrains.kotlin.gradle.fus.BuildUidService;\nimport org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin;\nimport org.jetbrains.kotlin.project.model.LanguageSettings;\nimport org.jetbrains.kotlin.tooling.core.KotlinToolingVersion;\nimport org.tomlj.Toml;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.JacksonModule;\n\nimport org.springframework.asm.ClassVisitor;\nimport org.springframework.boot.buildpack.platform.build.BuildRequest;\nimport org.springframework.boot.loader.tools.Layers;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.gradle.testkit.Dsl;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\n\n/**\n * Custom {@link GradleBuild} that configures the\n * {@link GradleRunner#withPluginClasspath(Iterable) plugin classpath}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic class PluginClasspathGradleBuild extends GradleBuild {\n\n\tprivate boolean kotlin;\n\n\tpublic PluginClasspathGradleBuild(BuildOutput buildOutput) {\n\t\tsuper(buildOutput);\n\t}\n\n\tpublic PluginClasspathGradleBuild(BuildOutput buildOutput, Dsl dsl) {\n\t\tsuper(buildOutput, dsl);\n\t}\n\n\tpublic PluginClasspathGradleBuild kotlin() {\n\t\tthis.kotlin = true;\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic GradleRunner prepareRunner(String... arguments) throws IOException {\n\t\treturn super.prepareRunner(arguments).withPluginClasspath(pluginClasspath());\n\t}\n\n\tprivate List<File> pluginClasspath() {\n\t\tList<File> classpath = new ArrayList<>();\n\t\tclasspath.add(new File(\"bin/main\"));\n\t\tclasspath.add(new File(\"build/classes/java/main\"));\n\t\tclasspath.add(new File(\"build/resources/main\"));\n\t\tclasspath.add(new File(pathOfJarContaining(Layers.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(ClassVisitor.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(DependencyManagementPlugin.class)));\n\t\tif (this.kotlin) {\n\t\t\tclasspath.add(new File(pathOfJarContaining(\"org.jetbrains.kotlin.cli.common.PropertiesKt\")));\n\t\t\tclasspath.add(new File(pathOfJarContaining(KotlinToolingVersion.class)));\n\t\t\tclasspath.add(new File(pathOfJarContaining(\"org.jetbrains.kotlin.build.report.metrics.BuildTimes\")));\n\t\t\tclasspath.add(new File(pathOfJarContaining(\"org.jetbrains.kotlin.buildtools.api.CompilationService\")));\n\t\t\tclasspath.add(new File(pathOfJarContaining(\"org.jetbrains.kotlin.daemon.client.KotlinCompilerClient\")));\n\t\t\tclasspath.add(new File(pathOfJarContaining(KotlinCompilerPluginSupportPlugin.class)));\n\t\t\tclasspath.add(new File(pathOfJarContaining(LanguageSettings.class)));\n\t\t\tclasspath.add(new File(pathOfJarContaining(BuildUidService.class)));\n\t\t}\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.apache.commons.lang3.ArrayFill\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.apache.commons.io.Charsets\")));\n\t\tclasspath.add(new File(pathOfJarContaining(ArchiveEntry.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(BuildRequest.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(HttpClientConnectionManager.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(HttpRequest.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(HttpVersionPolicy.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(JacksonModule.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(JsonParser.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.github.openjson.JSONObject\")));\n\t\tclasspath.add(new File(pathOfJarContaining(JsonView.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(Platform.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(Toml.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(Lexer.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.graalvm.buildtools.gradle.NativeImagePlugin\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.graalvm.reachability.GraalVMReachabilityMetadataRepository\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.graalvm.buildtools.utils.SharedConstants\")));\n\t\t// Cyclonedx dependencies\n\t\tclasspath.add(new File(pathOfJarContaining(CyclonedxPlugin.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.ctc.wstx.api.WriterConfig\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.fasterxml.jackson.core.Versioned\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.fasterxml.jackson.databind.JsonSerializer\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.github.packageurl.MalformedPackageURLException\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.google.common.collect.ImmutableMap\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.networknt.schema.resource.SchemaMappers\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.apache.commons.collections4.CollectionUtils\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.apache.maven.model.building.ModelBuildingException\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.codehaus.plexus.util.xml.pull.XmlPullParserException\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.codehaus.stax2.ri.Stax2WriterAdapter\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"org.cyclonedx.model.ExternalReference\")));\n\t\t// Protobuf dependencies\n\t\tclasspath.add(new File(pathOfJarContaining(ProtobufPlugin.class)));\n\t\tclasspath.add(new File(pathOfJarContaining(\"com.google.gradle.osdetector.OsDetectorPlugin\")));\n\t\tclasspath.add(new File(pathOfJarContaining(\"kr.motd.maven.os.FileOperationProvider\")));\n\t\treturn classpath;\n\t}\n\n\tprivate String pathOfJarContaining(String className) {\n\t\ttry {\n\t\t\treturn pathOfJarContaining(Class.forName(className));\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\tthrow new IllegalArgumentException(ex);\n\t\t}\n\t}\n\n\tprivate String pathOfJarContaining(Class<?> type) {\n\t\treturn type.getProtectionDomain().getCodeSource().getLocation().getPath();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.gradle.testkit;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/bootjar/classpath/BootJarClasspathApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.bootjar.classpath;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\n\n/**\n * Application used for testing classpath handling with BootJar.\n *\n * @author Andy Wilkinson\n */\npublic class BootJarClasspathApplication {\n\n\tprotected BootJarClasspathApplication() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tint i = 1;\n\t\tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n\t\tfor (URL url : ((URLClassLoader) classLoader).getURLs()) {\n\t\t\tSystem.out.println(i++ + \". \" + url.getFile());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/bootjar/main/CustomMainClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.bootjar.main;\n\n/**\n * Application used for testing {@code BootRun}'s main class configuration.\n *\n * @author Andy Wilkinson\n */\npublic class CustomMainClass {\n\n\tprotected CustomMainClass() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(CustomMainClass.class.getName());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/bootrun/classpath/BootRunClasspathApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.bootrun.classpath;\n\nimport java.io.File;\nimport java.lang.management.ManagementFactory;\n\n/**\n * Application used for testing {@code BootRun}'s classpath handling.\n *\n * @author Andy Wilkinson\n */\npublic class BootRunClasspathApplication {\n\n\tprotected BootRunClasspathApplication() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"Main class name = \" + BootRunClasspathApplication.class.getName());\n\t\tint i = 1;\n\t\tfor (String entry : ManagementFactory.getRuntimeMXBean().getClassPath().split(File.pathSeparator)) {\n\t\t\tSystem.out.println(i++ + \". \" + entry);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/bootrun/jvmargs/BootRunJvmArgsApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.bootrun.jvmargs;\n\nimport java.lang.management.ManagementFactory;\n\n/**\n * Application used for testing {@code BootRun}'s JVM argument handling.\n *\n * @author Andy Wilkinson\n */\npublic class BootRunJvmArgsApplication {\n\n\tprotected BootRunJvmArgsApplication() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tint i = 1;\n\t\tfor (String entry : ManagementFactory.getRuntimeMXBean().getInputArguments()) {\n\t\t\tSystem.out.println(i++ + \". \" + entry);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/bootrun/main/CustomMainClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.bootrun.main;\n\n/**\n * Application used for testing {@code BootRun}'s main class configuration.\n *\n * @author Andy Wilkinson\n */\npublic class CustomMainClass {\n\n\tprotected CustomMainClass() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(CustomMainClass.class.getName());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/boottestrun/classpath/BootTestRunClasspathApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.boottestrun.classpath;\n\nimport java.io.File;\nimport java.lang.management.ManagementFactory;\n\n/**\n * Application used for testing {@code bootTestRun}'s classpath handling.\n *\n * @author Andy Wilkinson\n */\npublic class BootTestRunClasspathApplication {\n\n\tprotected BootTestRunClasspathApplication() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"Main class name = \" + BootTestRunClasspathApplication.class.getName());\n\t\tint i = 1;\n\t\tfor (String entry : ManagementFactory.getRuntimeMXBean().getClassPath().split(File.pathSeparator)) {\n\t\t\tSystem.out.println(i++ + \". \" + entry);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/boottestrun/jvmargs/BootTestRunJvmArgsApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.boottestrun.jvmargs;\n\nimport java.lang.management.ManagementFactory;\n\n/**\n * Application used for testing {@code bootTestRun}'s JVM argument handling.\n *\n * @author Andy Wilkinson\n */\npublic class BootTestRunJvmArgsApplication {\n\n\tprotected BootTestRunJvmArgsApplication() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tint i = 1;\n\t\tfor (String entry : ManagementFactory.getRuntimeMXBean().getInputArguments()) {\n\t\t\tSystem.out.println(i++ + \". \" + entry);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/boottestrun/nomain/BootTestRunNoMain.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.boottestrun.nomain;\n\n/**\n * Application used for testing {@code bootTestRun}'s handling of no test main method\n *\n * @author Andy Wilkinson\n */\npublic class BootTestRunNoMain {\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/com/example/bootwar/main/CustomMainClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.bootwar.main;\n\n/**\n * Application used for testing {@code BootRun}'s main class configuration.\n *\n * @author Andy Wilkinson\n */\npublic class CustomMainClass {\n\n\tprotected CustomMainClass() {\n\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(CustomMainClass.class.getName());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-additionalProperties.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nspringBoot {\n\tbuildInfo {\n\t\tproperties {\n\t\t\tadditional = [\n\t\t\t\t'a': 'alpha',\n\t\t\t\t'b': providers.provider({'bravo'})\n\t\t\t]\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicJar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nspringBoot {\n\tbuildInfo()\n\tmainClass = \"com.example.Main\"\n}\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicWar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nspringBoot {\n\tbuildInfo()\n\tmainClass = \"com.example.Main\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-classesDependency.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tbuildInfo()\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-jarWithCustomName.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.gradle.util.GradleVersion\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nbootJar {\n\tif (GradleVersion.current().compareTo(GradleVersion.version('6.0.0')) < 0) {\n\t\tbaseName = 'foo'\n\t}\n\telse {\n\t\tarchiveBaseName = 'foo'\n\t}\n}\n\nspringBoot {\n\tbuildInfo()\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-warWithCustomName.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.gradle.util.GradleVersion\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nbootWar {\n\tif (GradleVersion.current().compareTo(GradleVersion.version('6.0.0')) < 0) {\n\t\tbaseName = 'foo'\n\t}\n\telse {\n\t\tarchiveBaseName = 'foo'\n\t}\n}\n\nspringBoot {\n\tbuildInfo()\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-applicationNameCanBeUsedToCustomizeDistributionName.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\napplication {\n\tapplicationName = 'custom'\n}\n\nbootJar {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-scriptsHaveCorrectPermissions.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForJarCanBeBuilt.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForWarCanBeBuilt.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-taskConfigurationIsAvoided.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n\tid 'application'\n}\n\ntasks.configureEach {\n\tprintln \"Configuring ${it.path}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForJarCanBeBuilt.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForWarCanBeBuilt.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyApplicationPlugin')) {\n\tapply plugin: 'application'\n\tapplication {\n\t\tapplicationDefaultJvmArgs = ['-Dcom.example.a=alpha', '-Dcom.example.b=bravo']\n\t}\n}\n\ntask('taskExists') {\n\tdoFirst {\n\t\tprintln \"${taskName} exists = ${tasks.findByName(taskName) != null}\"\n\t}\n}\n\ntask('distributionExists') {\n\tdef distributions = project.extensions.findByType(DistributionContainer)\n\tdoFirst {\n\t\tboolean found = distributions != null && distributions.findByName(distributionName) != null\n\t\tprintln \"${distributionName} exists = ${found}\"\n\t}\n}\n\ntask('javaCompileEncoding') {\n\tdoFirst {\n\t\ttasks.withType(JavaCompile) {\n\t\t\tprintln \"${name} = ${options.encoding}\"\n\t\t}\n\t}\n}\n\ntask('startScriptsDefaultJvmOpts') {\n\tdoFirst {\n\t\ttasks.getByName(\"bootStartScripts\") {\n\t\t\tprintln \"$name defaultJvmOpts = $defaultJvmOpts\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/CyclonedxPluginActionIntegrationTests-sbomIsIncludedInUberJar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.cyclonedx.bom'\n\ngroup = 'com.example'\nversion = '0.0.1'\n\ntasks.named(\"bootJar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/CyclonedxPluginActionIntegrationTests-sbomIsIncludedInUberWar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\napply plugin: 'org.cyclonedx.bom'\n\ngroup = 'com.example'\nversion = '0.0.1'\n\ntasks.named(\"bootWar\") {\n\tmainClass = 'com.example.ExampleApplication'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests-helpfulErrorWhenVersionlessDependencyFailsToResolve.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter-web')\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyDependencyManagementPlugin')) {\n\tapply plugin: 'io.spring.dependency-management'\n\tdependencyManagement {\n\t\tresolutionStrategy {\n\t\t\teachDependency {\n\t\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\t\tit.useVersion project.bootVersion\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nrepositories {\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ntasks.register(\"doesNotHaveDependencyManagement\") {\n\tdef extensions = project.extensions\n\tdoLast {\n\t\tif (extensions.findByName('dependencyManagement') != null) {\n\t\t\tthrow new GradleException('Found dependency management extension')\n\t\t}\n\t}\n}\n\ntasks.register(\"hasDependencyManagement\") {\n\tdoLast {\n\t\tif (!dependencyManagement.managedVersions) {\n\t\t\tthrow new GradleException('No managed versions have been configured')\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-additionalMetadataLocationsConfiguredWhenProcessorIsPresent.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tflatDir { dirs 'libs' }\n}\n\ndependencies {\n\tannotationProcessor(':spring-boot-configuration-processor:1.2.3')\n}\n\ncompileJava {\n\tdoLast {\n\t\tprintln \"${name} compiler args: ${options.compilerArgs}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-additionalMetadataLocationsNotConfiguredWhenProcessorIsAbsent.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ncompileJava {\n\tdoLast {\n\t\tprintln \"${name} compiler args: ${options.compilerArgs}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-applyingJavaPluginCreatesBootJarTask.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-applyingJavaPluginCreatesBootRunTask.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-applyingJavaPluginCreatesBootTestRunTask.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-applyingJavaPluginCreatesDevelopmentOnlyConfiguration.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ngradle.taskGraph.whenReady {\n\tprintln \"developmentOnly exists = ${configurations.findByName('developmentOnly') != null}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-applyingJavaPluginCreatesTestAndDevelopmentOnlyConfiguration.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ngradle.taskGraph.whenReady {\n\tprintln \"testAndDevelopmentOnly exists = ${configurations.findByName('testAndDevelopmentOnly') != null}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-assembleRunsBootJarAndJar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-compileClasspathDoesNotIncludeDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.compileClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-compileClasspathDoesNotIncludeTestAndDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.compileClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-errorMessageIsHelpfulWhenMainClassCannotBeResolved.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-javaCompileTasksCanOverrideDefaultParametersCompilerFlag.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ntasks.withType(JavaCompile) {\n\toptions.compilerArgs = ['-Xlint:all']\n}\n\ngradle.taskGraph.whenReady {\n\tgradle.taskGraph.allTasks.each {\n\t\tif (it instanceof JavaCompile) {\n\t\t\tprintln \"${it.name} compiler args: ${it.options.compilerArgs}\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-javaCompileTasksUseParametersAndAdditionalCompilerFlags.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ntasks.withType(JavaCompile) {\n\toptions.compilerArgs << '-Xlint:all'\n}\n\ngradle.taskGraph.whenReady {\n\tgradle.taskGraph.allTasks.each {\n\t\tif (it instanceof JavaCompile) {\n\t\t\tprintln \"${it.name} compiler args: ${it.options.compilerArgs}\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-javaCompileTasksUseParametersCompilerFlagByDefault.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ngradle.taskGraph.whenReady {\n\tgradle.taskGraph.allTasks.each {\n\t\tif (it instanceof JavaCompile) {\n\t\t\tprintln \"${it.name} compiler args: ${it.options.compilerArgs}\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-javaCompileTasksUseUtf8Encoding.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ngradle.taskGraph.whenReady {\n\tgradle.taskGraph.allTasks.each {\n\t\tif (it instanceof JavaCompile) {\n\t\t\tprintln \"${it.name} = ${it.options.encoding}\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-noBootJarTaskWithoutJavaPluginApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-noBootRunTaskWithoutJavaPluginApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-noBootTestRunTaskWithoutJavaPluginApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithAttributesThatMatchRuntimeClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ndef collectAttributes(String configurationName) {\n\tdef attributes = configurations.findByName(configurationName).attributes\n\tdef keys = new TreeSet<>((a1, a2) -> a1.name.compareTo(a2.name))\n\tkeys.addAll(attributes.keySet())\n\tkeys.collect { key -> \"${key}: ${attributes.getAttribute(key)}\" }\n}\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ngradle.taskGraph.whenReady {\n\tdef runtimeClasspathAttributes = collectAttributes(\"runtimeClasspath\")\n\tdef productionRuntimeClasspathAttributes = collectAttributes(\"productionRuntimeClasspath\")\n\tprintln(\"runtimeClasspath: ${runtimeClasspathAttributes}\")\n\tprintln(\"productionRuntimeClasspath: ${productionRuntimeClasspathAttributes}\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-productionRuntimeClasspathIsConfiguredWithResolvabilityAndConsumabilityThatMatchesRuntimeClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\ngradle.taskGraph.whenReady {\n\tanalyzeConfiguration('productionRuntimeClasspath')\n\tanalyzeConfiguration('runtimeClasspath')\n}\n\ndef analyzeConfiguration(String configurationName) {\n\tConfiguration configuration = configurations.findByName(configurationName)\n\tprintln \"$configurationName canBeResolved: ${configuration.canBeResolved}\"\n\tprintln \"$configurationName canBeConsumed: ${configuration.canBeConsumed}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-runtimeClasspathIncludesDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.runtimeClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-runtimeClasspathIncludesTestAndDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.runtimeClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-taskConfigurationIsAvoided.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\ntasks.configureEach {\n\tprintln \"Configuring ${it.path}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-testCompileClasspathDoesNotIncludeDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.testCompileClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-testCompileClasspathIncludesTestAndDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.testCompileClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-testRuntimeClasspathDoesNotIncludeDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.testRuntimeClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests-testRuntimeClasspathIncludesTestAndDevelopmentOnlyDependencies.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\nspringBoot {\n\tmainClass = \"com.example.Main\"\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ngradle.taskGraph.whenReady {\n\tconfigurations.testRuntimeClasspath.resolve().each { println it }\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-compileAotJavaHasTransitiveRuntimeDependenciesOnItsClasspathWhenUsingKotlin.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n\tid 'org.jetbrains.kotlin.jvm'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation \"org.hibernate.orm:hibernate-core:6.1.1.Final\"\n}\n\ntask('compileAotJavaClasspath') {\n\tdoFirst {\n\t\ttasks.findByName('compileAotJava').classpath.files.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-compileAotTestJavaHasTransitiveRuntimeDependenciesOnItsClasspathWhenUsingKotlin.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n\tid \"org.jetbrains.kotlin.jvm\"\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n}\n\ndependencies {\n\timplementation \"org.hibernate.orm:hibernate-core:6.1.1.Final\"\n}\n\ntask('compileAotTestJavaClasspath') {\n\tdoFirst {\n\t\ttasks.findByName('compileAotTestJava').classpath.files.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-kotlinCompileTasksCanOverrideDefaultJavaParametersFlag.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\napply plugin: 'org.jetbrains.kotlin.jvm'\n\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\ntasks.withType(KotlinCompile) {\n\tcompilerOptions {\n\t\tjavaParameters = false\n\t}\n}\n\ntask('kotlinCompileTasksJavaParameters') {\n\tdoFirst {\n\t\ttasks.withType(KotlinCompile) {\n\t\t\tprintln \"${name} java parameters: ${compilerOptions.javaParameters.get()}\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-kotlinCompileTasksUseJavaParametersFlagByDefault.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\napply plugin: 'org.jetbrains.kotlin.jvm'\n\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\ntask('kotlinCompileTasksJavaParameters') {\n\tdoFirst {\n\t\ttasks.withType(KotlinCompile) {\n\t\t\tprintln \"${name} java parameters: ${compilerOptions.javaParameters.get()}\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-kotlinVersionPropertyIsSet.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\napply plugin: 'io.spring.dependency-management'\napply plugin: 'org.jetbrains.kotlin.jvm'\n\ndependencyManagement {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation('org.jetbrains.kotlin:kotlin-stdlib-jdk8')\n}\n\ntasks.register(\"kotlinVersion\") {\n\tdef properties = project.properties\n\tdoLast {\n\t\tdef kotlinVersion = properties.getOrDefault('kotlin.version', 'none')\n\t\tprintln \"Kotlin version: ${kotlinVersion}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-noKotlinVersionPropertyWithoutKotlinPlugin.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\ntasks.register(\"kotlinVersion\") {\n\tdef properties = project.properties\n\tdoLast {\n\t\tdef kotlinVersion = properties.getOrDefault('kotlin.version', 'none')\n\t\tprintln \"Kotlin version: ${kotlinVersion}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/KotlinPluginActionIntegrationTests-taskConfigurationIsAvoided.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\napply plugin: 'org.jetbrains.kotlin.jvm'\n\ntasks.configureEach {\n\tprintln \"Configuring ${it.path}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'maven'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ntask('conf2ScopeMappings') {\n\tdoFirst {\n\t\ttasks.getByName('uploadBootArchives').repositories.withType(MavenResolver) {\n\t\t\tprintln \"Conf2ScopeMappings = ${pom.scopeMappings.mappings.size()}\"\n\t\t}\n\t}\n}\n\nuploadBootArchives {\n\trepositories {\n\t\tmavenDeployer {\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-applyingNativeImagePluginAppliesAotPlugin.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\ntask('aotPluginApplied') {\n\tdoFirst {\n\t\tprintln \"org.springframework.boot.aot applied = ${plugins.hasPlugin('org.springframework.boot.aot')}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-classesGeneratedDuringAotProcessingAreOnTheNativeImageClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\nrepositories {\n\tmavenCentral()\n}\n\ntask('checkNativeImageClasspath') {\n\tdoFirst {\n\t\ttasks.nativeCompile.options.get().classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-classesGeneratedDuringAotTestProcessingAreOnTheTestNativeImageClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter:{junitVersion}\")\n}\n\ntask('checkTestNativeImageClasspath') {\n\tdoFirst {\n\t\ttasks.nativeTestCompile.options.get().classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-developmentOnlyDependenciesDoNotAppearInNativeImageClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ntask('checkNativeImageClasspath') {\n\tdoFirst {\n\t\ttasks.nativeCompile.options.get().classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-nativeEntryIsAddedToManifest.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-reachabilityMetadataConfigurationFilesAreCopiedToJar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation \"ch.qos.logback:logback-classic:1.2.11\"\n\timplementation \"org.jline:jline:3.21.0\"\n}\n\n// see https://github.com/graalvm/native-build-tools/issues/302\ngraalvmNative {\n\tagent {\n\t\ttasksToInstrumentPredicate = { t -> false } as java.util.function.Predicate<Test>\n\t}\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-reachabilityMetadataConfigurationFilesFromFileRepositoryAreCopiedToJar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation \"ch.qos.logback:logback-classic:1.2.11\"\n\timplementation \"org.jline:jline:3.21.0\"\n}\n\ngraalvmNative {\n\tmetadataRepository {\n\t\turi(file(\"reachability-metadata-repository\"))\n\t}\n\t// see https://github.com/graalvm/native-build-tools/issues/302\n\tagent {\n\t\ttasksToInstrumentPredicate = { t -> false } as java.util.function.Predicate<Test>\n\t}\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/NativeImagePluginActionIntegrationTests-testAndDevelopmentOnlyDependenciesDoNotAppearInNativeImageClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.graalvm.buildtools.native'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ntask('checkNativeImageClasspath') {\n\tdoFirst {\n\t\ttasks.nativeCompile.options.get().classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/OnlyDependencyManagementIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n\tid 'java'\n}\n\napply plugin: 'io.spring.dependency-management'\n\nrepositories {\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencyManagement {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n\timports {\n\t\tmavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ProtobufPluginActionIntegrationTests-usesVersionOfGrpcPluginDependencyWhenSpecified.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'com.google.protobuf'\n\ngroup = 'com.example'\nversion = '0.0.1'\n\nrepositories {\n\tmavenCentral()\n}\n\nprotobuf {\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:1.78.0\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ProtobufPluginActionIntegrationTests-usesVersionOfProtocDependencyWhenSpecified.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'com.google.protobuf'\n\ngroup = 'com.example'\nversion = '0.0.1'\n\nrepositories {\n\tmavenCentral()\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:4.33.5\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ProtobufPluginActionIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'com.google.protobuf'\n\ngroup = 'com.example'\nversion = '0.0.1'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation(\"com.google.protobuf:protobuf-java-util:4.34.0\")\n\timplementation(\"io.grpc:grpc-util:1.79.0\")\n}\n\ntasks.register(\"protocArtifact\") {\n\tdoFirst {\n\t\tprotobuf {\n\t\t\tprotoc {\n\t\t\t\tprintln \"protoc artifact: '$artifact'\"\n\t\t\t}\n\t\t}\n\t}\n}\n\ntasks.register(\"grpcPlugin\") {\n\tdoFirst {\n\t\tprotobuf {\n\t\t\tplugins {\n\t\t\t\tgrpc {\n\t\t\t\t\tprintln \"grpc plugin artifact: '$artifact'\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntasks.register(\"generateProtoTasksGrpcPluginOptions\") {\n\tdoFirst {\n\t\ttasks.withType(com.google.protobuf.gradle.GenerateProtoTask).each { println \"${it.name}: ${it.pluginsForCaching.collect { it.options }}\" }\n\t}\n}\n\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-applyingAotPluginCreatesProcessAotTask.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\ntask('taskExists') {\n\tdoFirst {\n\t\tprintln \"${taskName} exists = ${tasks.findByName(taskName) != null}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-applyingAotPluginCreatesProcessTestAotTask.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\ntask('taskExists') {\n\tdoFirst {\n\t\tprintln \"${taskName} exists = ${tasks.findByName(taskName) != null}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-applyingAotPluginDoesNotPreventConfigurationOfJavaToolchainLanguageVersion.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\njava {\n    toolchain {\n        languageVersion.set(JavaLanguageVersion.of(17))\n    }\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-noProcessAotTaskWithoutAotPluginApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'java'\n}\n\ntask('taskExists') {\n\tdoFirst {\n\t\tprintln \"${taskName} exists = ${tasks.findByName(taskName) != null}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-noProcessTestAotTaskWithoutAotPluginApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'java'\n}\n\ntask('taskExists') {\n\tdoFirst {\n\t\tprintln \"${taskName} exists = ${tasks.findByName(taskName) != null}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotDoesNotHaveDevelopmentOnlyDependenciesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.springframework.boot.aot'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ntask('processAotClasspath') {\n\tdoFirst {\n\t\ttasks.processAot.classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotDoesNotHaveTestAndDevelopmentOnlyDependenciesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.springframework.boot.aot'\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ntask('processAotClasspath') {\n\tdoFirst {\n\t\ttasks.processAot.classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotHasLibraryResourcesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\ndependencies {\n\timplementation project(\":library\")\n}\n\ntask('processAotClasspath') {\n\tdoFirst {\n\t\ttasks.findByName('processAot').classpath.files.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotHasTransitiveRuntimeDependenciesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation \"org.hibernate.orm:hibernate-core:6.1.1.Final\"\n}\n\ntask('processAotClasspath') {\n\tdoFirst {\n\t\ttasks.findByName('processAot').classpath.files.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotIsSkippedWhenProjectHasNoMainSource.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\nspringBoot {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processAotRunsWhenProjectHasMainSource.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\nspringBoot {\n\tmainClass = 'com.example.Main'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotDoesNotHaveDevelopmentOnlyDependenciesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.springframework.boot.aot'\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ntask('processTestAotClasspath') {\n\tdoFirst {\n\t\ttasks.processTestAot.classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotHasLibraryResourcesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n}\n\ndependencies {\n\timplementation project(\":library\")\n}\n\ntask('processTestAotClasspath') {\n\tdependsOn configurations.processTestAotClasspath\n\tdoFirst {\n\t\tconfigurations.processTestAotClasspath.files.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotHasTestAndDevelopmentOnlyDependenciesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'java'\n}\n\napply plugin: 'org.springframework.boot.aot'\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}\n\ntask('processTestAotClasspath') {\n\tdoFirst {\n\t\ttasks.processTestAot.classpath.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotHasTransitiveRuntimeDependenciesOnItsClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\nconfigurations.all {\n\tresolutionStrategy {\n\t\teachDependency {\n\t\t\tif (it.requested.group == 'org.springframework.boot') {\n\t\t\t\tit.useVersion project.bootVersion\n\t\t\t}\n\t\t}\n\t}\n}\n\ndependencies {\n\timplementation \"org.hibernate.orm:hibernate-core:6.1.1.Final\"\n}\n\ntask('processTestAotClasspath') {\n\tdependsOn configurations.processTestAotClasspath\n\tdoFirst {\n\t\tconfigurations.processTestAotClasspath.files.each { println it }\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootAotPluginIntegrationTests-processTestAotIsSkippedWhenProjectHasNoTestSource.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n\tid 'org.springframework.boot.aot'\n\tid 'java'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\nspringBoot {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests-unresolvedDependenciesAreAnalyzedWhenDependencyResolutionFails.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tflatDir { dirs 'libs' }\n}\n\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter')\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/SpringBootPluginIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests-assembleRunsBootWarAndWar.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests-taskConfigurationIsAvoided.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\ntasks.configureEach {\n\tprintln \"Configuring ${it.path}\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}'\n}\n\nif (project.hasProperty('applyWarPlugin')) {\n\tapply plugin: 'war'\n}\n\ntask('taskExists') {\n\tdoFirst {\n\t\tprintln \"${taskName} exists = ${tasks.findByName(taskName) != null}\"\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-basicExecution.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\nversion = '0.1.0'\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {\n\tproperties {\n\t\tartifact = 'foo'\n\t\tgroup = 'foo'\n\t\tname = 'foo'\n\t\tadditional = ['additional': 'foo']\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-defaultValues.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo)\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-excludeProperties.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\ngroup = 'foo'\nversion = '0.1.0'\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {\n\texcludes = ['group', 'artifact', 'version', 'name']\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-notUpToDateWhenExecutedTwiceAsTimeChanges.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo)\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedGradlePropertiesProjectVersion.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {\n\texcludes = [\"time\"]\n\tproperties {\n\t\tartifact = 'example'\n\t\tgroup = 'com.example'\n\t\tname = 'example'\n\t\tadditional = ['additional': 'alpha']\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-notUpToDateWhenExecutedTwiceWithFixedTimeAndChangedProjectVersion.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\nversion = '{projectVersion}'\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {\n\texcludes = [\"time\"]\n\tproperties {\n\t\tartifact = 'example'\n\t\tgroup = 'com.example'\n\t\tname = 'example'\n\t\tadditional = ['additional': 'alpha']\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-reproducibleOutputWithFixedTime.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {\n\texcludes = [\"time\"]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-upToDateWhenExecutedTwiceWithFixedTime.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{version}' apply false\n}\n\ntasks.register(\"buildInfo\", org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) {\n\texcludes = [\"time\"]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\napplication {\n\tmainClass = 'com.example.CustomMain'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-classesFromASecondarySourceSetCanBeIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nsourceSets {\n\tsecondary\n\tmain {\n\t\truntimeClasspath += secondary.output\n\t}\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-customLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n\tlayered {\n\t\tapplication {\n\t\t\tintoLayer(\"static\") {\n\t\t\t\tinclude \"META-INF/resources/**\", \"resources/**\", \"static/**\", \"public/**\"\n\t\t\t}\n\t\t\tintoLayer(\"app\")\n\t\t}\n\t\tdependencies {\n\t\t\tintoLayer(\"snapshot-dependencies\") {\n\t\t\t\tinclude \"*:*:*SNAPSHOT\"\n\t\t\t}\n\t\t\tintoLayer(\"commons-dependencies\") {\n\t\t\t\tinclude \"org.apache.commons:*\"\n\t\t\t}\n\t\t\tintoLayer(\"dependencies\")\n\t\t}\n\t\tlayerOrder = [\"dependencies\", \"commons-dependencies\", \"snapshot-dependencies\", \"static\", \"app\"]\n\t}\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-developmentOnlyDependenciesAreNotIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootJar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-developmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\tdevelopmentOnly(\"commons-io:commons-io:2.6\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootJar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-developmentOnlyDependenciesCanBeIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootJar {\n\tclasspath configurations.developmentOnly\n}\n\nbootJar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-dirModeAndFileModeAreApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ntasks.named(\"bootJar\") {\n\tfileMode = 0400\n\tdirMode = 0500\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-duplicatesAreHandledGracefully.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.CustomMain'\n\tduplicatesStrategy = \"exclude\"\n}\n\nconfigurations {\n\tprovided\n}\n\nsourceSets.all {\n\tcompileClasspath += configurations.provided\n\truntimeClasspath += configurations.provided\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation(\"org.apache.commons:commons-lang3:3.6\")\n\tprovided \"org.apache.commons:commons-lang3:3.6\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-explodedApplicationClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n}\n\ntasks.register(\"explode\", Sync) {\n\tdependsOn(bootJar)\n\tdestinationDir = layout.buildDirectory.dir(\"exploded\").get().asFile\n\tfrom zipTree(files(bootJar).singleFile)\n}\n\ntasks.register(\"launch\", JavaExec) {\n\tclasspath = files(explode)\n\tmainClass = 'org.springframework.boot.loader.launch.JarLauncher'\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-implicitLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n\timplementation(\"org.springframework.boot:spring-boot-starter-logging:2.2.0.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-jarTypeFilteringIsApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tflatDir {\n\t\tdirs 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\":standard:\")\n\timplementation(\":starter:\")\n}\n\nbootJar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-layersWithCustomSourceSet.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nsourceSets {\n\tcustom\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-multiModuleCustomLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nsubprojects {\n\tapply plugin: 'java'\n\tgroup = 'org.example.projects'\n\tversion = '1.2.3'\n\tif (it.name == 'bravo') {\n\t\tdependencies {\n\t\t\timplementation(project(':charlie'))\n\t\t}\n\t}\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n\tlayered {\n\t\tapplication {\n\t\t\tintoLayer(\"static\") {\n\t\t\t\tinclude \"META-INF/resources/**\", \"resources/**\", \"static/**\", \"public/**\"\n\t\t\t}\n\t\t\tintoLayer(\"app\")\n\t\t}\n\t\tdependencies {\n\t\t\tintoLayer(\"snapshot-dependencies\") {\n\t\t\t\tinclude \"*:*:*SNAPSHOT\"\n\t\t\t\texcludeProjectDependencies()\n\t\t\t}\n\t\t\tintoLayer(\"subproject-dependencies\") {\n\t\t\t\tincludeProjectDependencies()\n\t\t\t}\n\t\t\tintoLayer(\"commons-dependencies\") {\n\t\t\t\tinclude \"org.apache.commons:*\"\n\t\t\t}\n\t\t\tintoLayer(\"dependencies\")\n\t\t}\n\t\tlayerOrder = [\"dependencies\", \"commons-dependencies\", \"snapshot-dependencies\", \"subproject-dependencies\", \"static\", \"app\"]\n\t}\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(project(':alpha'))\n\timplementation(project(':bravo'))\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-multiModuleImplicitLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nsubprojects {\n\tapply plugin: 'java'\n\tgroup = 'org.example.projects'\n\tversion = '1.2.3'\n\tif (it.name == 'bravo') {\n\t\tdependencies {\n\t\t\timplementation(project(':charlie'))\n\t\t}\n\t}\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(project(':alpha'))\n\timplementation(project(':bravo'))\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootJar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-notUpToDateWhenBuiltWithToolsAndThenWithoutTools.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n\t{includeTools}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-notUpToDateWhenBuiltWithoutLayersAndThenWithLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n\tlayered {\n\t\t{layerEnablement}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-packagedApplicationClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ntasks.register(\"launch\", JavaExec) {\n\tclasspath = files(bootJar)\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-reproducibleArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n\tif (GradleVersion.current().compareTo(GradleVersion.version(\"9.0.0-rc-1\")) < 0) {\n\t\tpreserveFileTimestamps = false\n\t\treproducibleFileOrder = true\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-signed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"org.bouncycastle:bcprov-jdk18on:1.78.1\")\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-springBootExtensionMainClassNameIsUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tmainClass = 'com.example.CustomMain'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-startClassIsSetByResolvingTheMainClass.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-testAndDevelopmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\ttestAndDevelopmentOnly(\"commons-io:commons-io:2.6\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootJar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-testAndDevelopmentOnlyDependenciesCanBeIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootJar {\n\tclasspath configurations.testAndDevelopmentOnly\n}\n\nbootJar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-upToDateWhenBuiltTwice.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n\t{layered}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-versionMismatchBetweenTransitiveDevelopmentOnlyImplementationDependenciesDoesNotRemoveDependencyFromTheArchive.gradle",
    "content": "plugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\tdevelopmentOnly(\"commons-io-consumer:one:1.0\")\n\timplementation(\"commons-io-consumer:two:1.0\")\n}\n\nbootJar {\n\tincludeTools = false\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-whenAResolvableCopyOfAnUnresolvableConfigurationIsResolvedThenResolutionSucceeds.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\ngradle.taskGraph.whenReady {\n\tdef copy = configurations.implementation.copyRecursive()\n\tcopy.canBeResolved = true\n\tcopy.resolve()\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\napplication {\n\tmainClass = 'com.example.CustomMain'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-classesFromASecondarySourceSetCanBeIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nsourceSets {\n\tsecondary\n\tmain {\n\t\truntimeClasspath += secondary.output\n\t}\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-customLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n\tlayered {\n\t\tapplication {\n\t\t\tintoLayer(\"static\") {\n\t\t\t\tinclude \"META-INF/resources/**\", \"resources/**\", \"static/**\", \"public/**\"\n\t\t\t}\n\t\t\tintoLayer(\"app\")\n\t\t}\n\t\tdependencies {\n\t\t\tintoLayer(\"snapshot-dependencies\") {\n\t\t\t\tinclude \"*:*:*SNAPSHOT\"\n\t\t\t}\n\t\t\tintoLayer(\"commons-dependencies\") {\n\t\t\t\tinclude \"org.apache.commons:*\"\n\t\t\t}\n\t\t\tintoLayer(\"dependencies\")\n\t\t}\n\t\tlayerOrder = [\"dependencies\", \"commons-dependencies\", \"snapshot-dependencies\", \"static\", \"app\"]\n\t}\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-developmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\tdevelopmentOnly(\"commons-io:commons-io:2.6\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootWar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-developmentOnlyDependenciesCanBeIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootWar {\n\tclasspath configurations.developmentOnly\n}\n\nbootWar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-dirModeAndFileModeAreApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\ntasks.named(\"bootWar\") {\n\tfileMode = 0400\n\tdirMode = 0500\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-duplicatesAreHandledGracefully.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.CustomMain'\n\tduplicatesStrategy = \"exclude\"\n}\n\nconfigurations {\n\tprovided\n}\n\nsourceSets.all {\n\tcompileClasspath += configurations.provided\n\truntimeClasspath += configurations.provided\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\timplementation(\"org.apache.commons:commons-lang3:3.6\")\n\tprovided \"org.apache.commons:commons-lang3:3.6\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-implicitLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n\timplementation(\"org.springframework.boot:spring-boot-starter-logging:2.2.0.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-jarTypeFilteringIsApplied.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tflatDir {\n\t\tdirs 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\":standard:\")\n\timplementation(\":starter:\")\n}\n\nbootWar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-layersWithCustomSourceSet.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nsourceSets {\n\tcustom\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-multiModuleCustomLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nsubprojects {\n\tapply plugin: 'java'\n\tgroup = 'org.example.projects'\n\tversion = '1.2.3'\n\tif (it.name == 'bravo') {\n\t\tdependencies {\n\t\t\timplementation(project(':charlie'))\n\t\t}\n\t}\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n\tlayered {\n\t\tapplication {\n\t\t\tintoLayer(\"static\") {\n\t\t\t\tinclude \"META-INF/resources/**\", \"resources/**\", \"static/**\", \"public/**\"\n\t\t\t}\n\t\t\tintoLayer(\"app\")\n\t\t}\n\t\tdependencies {\n\t\t\tintoLayer(\"snapshot-dependencies\") {\n\t\t\t\tinclude \"*:*:*SNAPSHOT\"\n\t\t\t\texcludeProjectDependencies()\n\t\t\t}\n\t\t\tintoLayer(\"subproject-dependencies\") {\n\t\t\t\tincludeProjectDependencies()\n\t\t\t}\n\t\t\tintoLayer(\"commons-dependencies\") {\n\t\t\t\tinclude \"org.apache.commons:*\"\n\t\t\t}\n\t\t\tintoLayer(\"dependencies\")\n\t\t}\n\t\tlayerOrder = [\"dependencies\", \"commons-dependencies\", \"snapshot-dependencies\", \"subproject-dependencies\", \"static\", \"app\"]\n\t}\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(project(':alpha'))\n\timplementation(project(':bravo'))\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-multiModuleImplicitLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nsubprojects {\n\tapply plugin: 'java'\n\tgroup = 'org.example.projects'\n\tversion = '1.2.3'\n\tif (it.name == 'bravo') {\n\t\tdependencies {\n\t\t\timplementation(project(':charlie'))\n\t\t}\n\t}\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(project(':alpha'))\n\timplementation(project(':bravo'))\n\timplementation(\"com.example:library:1.0-SNAPSHOT\")\n\timplementation(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"org.springframework:spring-core:5.2.5.RELEASE\")\n}\n\ntasks.register(\"listLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"list-layers\"\n}\n\ntasks.register(\"extractLayers\", JavaExec) {\n\tclasspath = bootWar.outputs.files\n\tsystemProperties = [ \"jarmode\": \"tools\" ]\n\targs \"extract\", \"--layers\", \"--launcher\", \"--destination\", \".\", \"--force\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-notUpToDateWhenBuiltWithToolsAndThenWithoutTools.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n\t{includeTools}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-notUpToDateWhenBuiltWithoutLayersAndThenWithLayers.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n\tlayered {\n\t\t{layerEnablement}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-reproducibleArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n\tif (GradleVersion.current().compareTo(GradleVersion.version(\"9.0.0-rc-1\")) < 0) {\n\t\tpreserveFileTimestamps = false\n\t\treproducibleFileOrder = true\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-signed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\"org.bouncycastle:bcprov-jdk18on:1.78.1\")\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-springBootExtensionMainClassNameIsUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tmainClass = 'com.example.CustomMain'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-startClassIsSetByResolvingTheMainClass.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-testAndDevelopmentOnlyDependenciesAreNotIncludedInTheArchiveByDefault.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\ttestAndDevelopmentOnly(\"commons-io:commons-io:2.6\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootWar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-testAndDevelopmentOnlyDependenciesCanBeIncludedInTheArchive.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.9\")\n\timplementation(\"commons-io:commons-io:2.6\")\n}\n\nbootWar {\n\tclasspath configurations.testAndDevelopmentOnly\n}\n\nbootWar {\n\tincludeTools = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-upToDateWhenBuiltTwice.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-upToDateWhenBuiltWithDefaultLayeredAndThenWithExplicitLayered.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n\tid 'war'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n\t{layered}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-versionMismatchBetweenTransitiveDevelopmentOnlyImplementationDependenciesDoesNotRemoveDependencyFromTheArchive.gradle",
    "content": "plugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n\tmaven {\n\t\turl = 'repository'\n\t}\n}\n\ndependencies {\n\tdevelopmentOnly(\"commons-io-consumer:one:1.0\")\n\timplementation(\"commons-io-consumer:two:1.0\")\n}\n\nbootWar {\n\tincludeTools = false\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootJarCanBeUploaded.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'maven'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nuploadBootArchives {\n\trepositories {\n\t\tmavenDeployer {\n\t\t \trepository(url: \"file:${layout.buildDirectory.dir(\"repo\").get().asFile}\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootWarCanBeUploaded.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'maven'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\nuploadBootArchives {\n\trepositories {\n\t\tmavenDeployer {\n\t\t\trepository(url: \"file:${layout.buildDirectory.dir(\"repo\").get().asFile}\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootJarCanBePublished.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'maven-publish'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootJar {\n\tmainClass = 'com.example.Application'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\npublishing {\n\trepositories {\n\t\tmaven {\n\t\t\turl = layout.buildDirectory.dir(\"repo\")\n\t\t}\n\t}\n\tpublications {\n\t\tbootJava(MavenPublication) {\n\t\t\tartifact bootJar\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootWarCanBePublished.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'war'\n\tid 'maven-publish'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootWar {\n\tmainClass = 'com.example.Application'\n}\n\ngroup = 'com.example'\nversion = '1.0'\n\npublishing {\n\trepositories {\n\t\tmaven {\n\t\t\turl = layout.buildDirectory.dir(\"repo\")\n\t\t}\n\t}\n\tpublications {\n\t\tbootWeb(MavenPublication) {\n\t\t\tartifact bootWar\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginJvmArgumentsAreUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\napplication {\n\tapplicationDefaultJvmArgs = ['-Dcom.foo=bar', '-Dcom.bar=baz']\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginMainClassNameIsNotUsedWhenItIsNull.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginMainClassNameIsUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\napplication {\n\tmainClass = 'com.example.bootrun.main.CustomMainClass'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-basicExecution.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-classesFromASecondarySourceSetCanBeOnTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nsourceSets {\n\tsecondary\n\tmain {\n\t\truntimeClasspath += secondary.output\n\t}\n}\n\nspringBoot {\n\tmainClass = 'com.example.bootrun.main.CustomMainClass'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-defaultJvmArgs.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-developmentOnlyDependenciesAreOnTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-jarTypeFilteringIsAppliedToTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tflatDir {\n\t\tdirs 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\":standard:\")\n\timplementation(\":starter:\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-optimizedLaunchDisabledJvmArgs.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootRun {\n\toptimizedLaunch = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootRun {\n\tsourceResources sourceSets.main\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-springBootExtensionMainClassNameIsUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nspringBoot {\n\tmainClass = 'com.example.bootrun.main.CustomMainClass'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-testAndDevelopmentOnlyDependenciesAreOnTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-applicationPluginJvmArgumentsAreUsed.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\napplication {\n\tapplicationDefaultJvmArgs = ['-Dcom.foo=bar', '-Dcom.bar=baz']\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-basicExecution.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-defaultJvmArgs.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-developmentOnlyDependenciesAreNotOnTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\tdevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-failsGracefullyWhenNoTestMainMethodIsFound.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-jarTypeFilteringIsAppliedToTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tflatDir {\n\t\tdirs 'repository'\n\t}\n}\n\ndependencies {\n\timplementation(\":standard:\")\n\timplementation(\":starter:\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-optimizedLaunchDisabledJvmArgs.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'application'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nbootTestRun {\n\toptimizedLaunch = false\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootTestRunIntegrationTests-testAndDevelopmentOnlyDependenciesAreOnTheClasspath.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version}'\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ndependencies {\n\ttestAndDevelopmentOnly(\"org.apache.commons:commons-lang3:3.12.0\")\n}"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/ch.qos.logback/logback-classic/1.2.11/index.json",
    "content": "[\n  \"reflect-config.json\"\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/ch.qos.logback/logback-classic/1.2.11/reflect-config.json",
    "content": "[\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.CallerDataConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.CallerDataConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.ClassOfCallerConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.ContextNameConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.DateConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.ExtendedThrowableProxyConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.FileOfCallerConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.LevelConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.LineOfCallerConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.LineSeparatorConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.LocalSequenceNumberConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.LoggerConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.MDCConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.MarkerConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.MessageConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.MethodOfCallerConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.NopThrowableInformationConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.PrefixCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.PropertyConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.RelativeTimeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.RootCauseFirstThrowableProxyConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.ThreadConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.ThrowableProxyConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.classic.pattern.color.HighlightingCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.IdentityCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.ReplacingCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BlackCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BlueCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldBlueCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldCyanCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldGreenCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldMagentaCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldRedCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldWhiteCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.BoldYellowCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.CyanCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.GrayCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.GreenCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.MagentaCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.RedCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.WhiteCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"ch.qos.logback.classic.LoggerContext\"\n    },\n    \"name\": \"ch.qos.logback.core.pattern.color.YellowCompositeConverter\",\n    \"allPublicConstructors\": true\n  },\n  {\n    \"name\": \"org.slf4j.impl.StaticLoggerBinder\"\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/ch.qos.logback/logback-classic/index.json",
    "content": "[\n  {\n    \"latest\": true,\n    \"metadata-version\": \"1.2.11\",\n    \"module\": \"ch.qos.logback:logback-classic\",\n    \"tested-versions\": [\n      \"1.2.11\"\n    ]\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/index.json",
    "content": "[\n  {\n    \"directory\": \"org.jline/jline\",\n    \"module\": \"org.jline:jline\"\n  },\n  {\n    \"directory\": \"ch.qos.logback/logback-classic\",\n    \"module\": \"ch.qos.logback:logback-classic\"\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/org.jline/jline/3.21.0/index.json",
    "content": "[\n  \"jni-config.json\",\n  \"proxy-config.json\",\n  \"reflect-config.json\",\n  \"resource-config.json\"\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/org.jline/jline/3.21.0/jni-config.json",
    "content": "[\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.terminal.impl.jansi.JansiNativePty\"\n    },\n    \"fields\": [\n      {\n        \"name\": \"HAVE_ISATTY\"\n      },\n      {\n        \"name\": \"HAVE_TTYNAME\"\n      },\n      {\n        \"name\": \"TCSADRAIN\"\n      },\n      {\n        \"name\": \"TCSAFLUSH\"\n      },\n      {\n        \"name\": \"TCSANOW\"\n      },\n      {\n        \"name\": \"TIOCGETD\"\n      },\n      {\n        \"name\": \"TIOCGWINSZ\"\n      },\n      {\n        \"name\": \"TIOCSETD\"\n      },\n      {\n        \"name\": \"TIOCSWINSZ\"\n      }\n    ],\n    \"name\": \"org.fusesource.jansi.internal.CLibrary\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.CLibrary$WinSize\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.CLibrary$WinSize\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.CLibrary$Termios\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.CLibrary$Termios\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$SMALL_RECT\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$SMALL_RECT\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$COORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$COORD\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$CONSOLE_SCREEN_BUFFER_INFO\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$CONSOLE_SCREEN_BUFFER_INFO\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$CHAR_INFO\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$CHAR_INFO\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$KEY_EVENT_RECORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$KEY_EVENT_RECORD\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$MOUSE_EVENT_RECORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$MOUSE_EVENT_RECORD\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$WINDOW_BUFFER_SIZE_RECORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$WINDOW_BUFFER_SIZE_RECORD\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$FOCUS_EVENT_RECORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$FOCUS_EVENT_RECORD\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$MENU_EVENT_RECORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$MENU_EVENT_RECORD\"\n  },\n  {\n    \"allDeclaredFields\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.fusesource.jansi.internal.Kernel32$INPUT_RECORD\"\n    },\n    \"name\": \"org.fusesource.jansi.internal.Kernel32$INPUT_RECORD\"\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/org.jline/jline/3.21.0/proxy-config.json",
    "content": "[\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.utils.Signals\"\n    },\n    \"interfaces\": [\n      \"sun.misc.SignalHandler\"\n    ]\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/org.jline/jline/3.21.0/reflect-config.json",
    "content": "[\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.terminal.impl.jansi.JansiNativePty\"\n    },\n    \"name\": \"java.io.FileDescriptor\",\n    \"queriedMethods\": [\n      {\n        \"name\": \"<init>\",\n        \"parameterTypes\": [\n          \"int\"\n        ]\n      }\n    ]\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.terminal.TerminalBuilder\"\n    },\n    \"methods\": [\n      {\n        \"name\": \"current\",\n        \"parameterTypes\": []\n      },\n      {\n        \"name\": \"info\",\n        \"parameterTypes\": []\n      },\n      {\n        \"name\": \"parent\",\n        \"parameterTypes\": []\n      }\n    ],\n    \"name\": \"java.lang.ProcessHandle\"\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.terminal.TerminalBuilder\"\n    },\n    \"methods\": [\n      {\n        \"name\": \"command\",\n        \"parameterTypes\": []\n      }\n    ],\n    \"name\": \"java.lang.ProcessHandle$Info\"\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.builtins.Styles\"\n    },\n    \"methods\": [\n      {\n        \"name\": \"get\",\n        \"parameterTypes\": []\n      }\n    ],\n    \"name\": \"org.jline.console.SystemRegistry\"\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.utils.Signals\"\n    },\n    \"methods\": [\n      {\n        \"name\": \"<init>\",\n        \"parameterTypes\": [\n          \"java.lang.String\"\n        ]\n      },\n      {\n        \"name\": \"handle\",\n        \"parameterTypes\": [\n          \"sun.misc.Signal\",\n          \"sun.misc.SignalHandler\"\n        ]\n      }\n    ],\n    \"name\": \"sun.misc.Signal\"\n  },\n  {\n    \"condition\": {\n      \"typeReachable\": \"org.jline.utils.Signals\"\n    },\n    \"fields\": [\n      {\n        \"name\": \"SIG_DFL\"\n      }\n    ],\n    \"name\": \"sun.misc.SignalHandler\"\n  },\n  {\n    \"allDeclaredClasses\": true,\n    \"allDeclaredConstructors\": true,\n    \"allDeclaredMethods\": true,\n    \"allPublicClasses\": true,\n    \"allPublicConstructors\": true,\n    \"allPublicMethods\": true,\n    \"condition\": {\n      \"typeReachable\": \"org.jline.terminal.TerminalBuilder\"\n    },\n    \"name\": \"sun.misc.SignalHandler\"\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/org.jline/jline/3.21.0/resource-config.json",
    "content": "{\n  \"bundles\": [],\n  \"resources\": {\n    \"includes\": [\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.TerminalBuilder\"\n        },\n        \"pattern\": \"\\\\QMETA-INF/services/org.jline.terminal.spi.JansiSupport\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.TerminalBuilder\"\n        },\n        \"pattern\": \"\\\\QMETA-INF/services/org.jline.terminal.spi.JnaSupport\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.jansi.JansiNativePty\"\n        },\n        \"pattern\": \"\\\\Qorg/fusesource/jansi/internal/native/Linux/x86_64/libjansi.so\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.jansi.JansiNativePty\"\n        },\n        \"pattern\": \"\\\\QMETA-INF/native/windows64/jansi.dll\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.jansi.JansiNativePty\"\n        },\n        \"pattern\": \"\\\\Qorg/fusesource/jansi/jansi.properties\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.jansi.JansiSupportImpl\"\n        },\n        \"pattern\": \"\\\\Qorg/fusesource/jansi/jansi.properties\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/capabilities.txt\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.Colors\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/colors.txt\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/ansi.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.DumbTerminal\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/dumb.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.DumbTerminal\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/dumb-color.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/rxvt.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/rxvt-basic.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/rxvt-unicode.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/rxvt-unicode-256color.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/screen.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/screen-256color.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.AbstractWindowsTerminal\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/windows.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.AbstractWindowsTerminal\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/windows-256color.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.terminal.impl.AbstractWindowsTerminal\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/windows-conemu.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/xterm.caps\\\\E\"\n      },\n      {\n        \"condition\": {\n          \"typeReachable\": \"org.jline.utils.InfoCmp\"\n        },\n        \"pattern\": \"\\\\Qorg/jline/utils/xterm-256color.caps\\\\E\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/org.jline/jline/index.json",
    "content": "[\n  {\n    \"latest\": true,\n    \"metadata-version\": \"3.21.0\",\n    \"module\": \"org.jline:jline\",\n    \"tested-versions\": [\n      \"3.21.0\"\n    ]\n  }\n]\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/schemas/library-and-framework-list-schema-v1.0.0.json",
    "content": "{\n  \"$id\": \"https://raw.githubusercontent.com/oracle/graalvm-reachability-metadata/master/metadata/schemas/library-and-framework-support-schema-v1.0.0.json\",\n  \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n  \"default\": [],\n  \"examples\": [\n    {\n      \"artifact\": \"io.netty:netty5-parent\",\n      \"details\": [\n        {\n          \"minimum_version\": \"4.1\",\n          \"metadata_locations\": [\n            \"https://github.com/netty/netty/tree/main/common/src/main/resources/META-INF/native-image\"\n          ],\n          \"tests_locations\": [\n            \"https://github.com/netty/netty/actions\"\n          ],\n          \"test_level\": \"fully-tested\"\n        }\n      ]\n    }\n  ],\n  \"items\": {\n    \"properties\": {\n      \"artifact\": {\n        \"default\": \"\",\n        \"description\": \"The artifact name in the groupId:artifactId format\",\n        \"pattern\": \"^[a-zA-Z0-9._-]+:[a-zA-Z0-9._*-]+$\",\n        \"title\": \"The name of the artifact\",\n        \"type\": \"string\"\n      },\n      \"description\": {\n        \"default\": \"\",\n        \"title\": \"Short description of the library or framework\",\n        \"type\": \"string\"\n      },\n      \"details\": {\n        \"default\": [],\n        \"items\": {\n          \"default\": {},\n          \"properties\": {\n            \"maximal_version\": {\n              \"default\": \"\",\n              \"description\": \"Maximum version for which this entry applies. If not defined, it is assumed to be supported for all versions starting from the minimum_version\",\n              \"title\": \"Maximal version for which this entry applies\",\n              \"type\": \"string\"\n            },\n            \"metadata_locations\": {\n              \"default\": [],\n              \"items\": {\n                \"default\": \"\",\n                \"type\": \"string\"\n              },\n              \"title\": \"Web URLs of provided metadata\",\n              \"type\": \"array\"\n            },\n            \"minimum_version\": {\n              \"default\": \"\",\n              \"title\": \"Minimal version for which this entry applies\",\n              \"type\": \"string\"\n            },\n            \"test_level\": {\n              \"default\": \"Untested\",\n              \"enum\": [\n                \"untested\",\n                \"community-tested\",\n                \"fully-tested\"\n              ],\n              \"title\": \"Testing level of reachability metadata for the library or framework\",\n              \"type\": \"string\"\n            },\n            \"tests_locations\": {\n              \"default\": [],\n              \"items\": {\n                \"default\": \"\",\n                \"type\": \"string\"\n              },\n              \"title\": \"Web URLs to tests (sources, CI dashboards/configurations, ...)\",\n              \"type\": \"array\"\n            }\n          },\n          \"required\": [\n            \"minimum_version\",\n            \"metadata_locations\",\n            \"tests_locations\",\n            \"test_level\"\n          ],\n          \"type\": \"object\"\n        },\n        \"type\": \"array\"\n      }\n    },\n    \"required\": [\n      \"artifact\",\n      \"details\"\n    ],\n    \"type\": \"object\"\n  },\n  \"title\": \"Schema for the 'library-and-framework-list.json'\",\n  \"type\": \"array\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/schemas/metadata-library-index-schema-v1.0.0.json",
    "content": "{\n  \"$id\": \"https://raw.githubusercontent.com/oracle/graalvm-reachability-metadata/master/metadata/schemas/metadata-library-index-schema-v1.0.0.json\",\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"description\": \"Schema for metadata/<groupId>/<artifactId>/index.json. Each entry describes a metadata bundle for a range of library versions.\",\n  \"type\": \"array\",\n  \"minItems\": 1,\n  \"items\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\n      \"module\",\n      \"metadata-version\",\n      \"tested-versions\"\n    ],\n    \"properties\": {\n      \"module\": {\n        \"$ref\": \"#/$defs/moduleCoordinate\",\n        \"description\": \"Maven coordinates in the form '<groupId>:<artifactId>'.\"\n      },\n      \"metadata-version\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"description\": \"Subdirectory name where the metadata files for this entry reside, e.g. '7.1.0.Final'.\"\n      },\n      \"tested-versions\": {\n        \"type\": \"array\",\n        \"description\": \"Explicitly tested upstream library versions that this metadata is known to support.\",\n        \"minItems\": 1,\n        \"uniqueItems\": true,\n        \"items\": {\n          \"type\": \"string\",\n          \"minLength\": 1\n        }\n      },\n      \"test-version\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"description\": \"Overrides 'metadata-version' for use in test directories. This allows one metadata entry to share tests defined for a different version's metadata directory.\"\n      },\n      \"latest\": {\n        \"type\": \"boolean\",\n        \"description\": \"Marks this entry as the latest/default metadata for currently supported versions.\"\n      },\n      \"default-for\": {\n        \"type\": \"string\",\n        \"description\": \"Java regular expression describing the version range for which this entry should be used by default (e.g. '7\\\\\\\\.1\\\\\\\\..*').\"\n      },\n      \"override\": {\n        \"type\": \"boolean\",\n        \"description\": \"When true, expresses the intent to exclude outdated built-in metadata shipped with Native Image for the matched versions.\"\n      },\n      \"skipped-versions\": {\n        \"type\": \"array\",\n        \"description\": \"Versions explicitly excluded from support, each with a reason.\",\n        \"minItems\": 1,\n        \"items\": {\n          \"type\": \"object\",\n          \"additionalProperties\": false,\n          \"required\": [ \"version\", \"reason\" ],\n          \"properties\": {\n            \"version\": {\n              \"type\": \"string\",\n              \"minLength\": 1\n            },\n            \"reason\": {\n              \"type\": \"string\",\n              \"minLength\": 1\n            }\n          }\n        }\n      }\n    }\n  },\n  \"$defs\": {\n    \"moduleCoordinate\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[^:]+:[^:]+$\"\n    }\n  },\n  \"examples\": [\n    [\n      {\n        \"metadata-version\": \"0.0.1\",\n        \"module\": \"org.example:library\",\n        \"tested-versions\": [ \"0.0.1\", \"0.0.2\" ],\n        \"default-for\": \"0\\\\.0\\\\..*\",\n        \"test-version\": \"0.0.1\"\n      },\n      {\n        \"latest\": true,\n        \"metadata-version\": \"1.0.0\",\n        \"module\": \"org.example:library\",\n        \"tested-versions\": [ \"1.0.0\", \"1.1.0\" , \"1.2.0\"]\n      },\n      {\n        \"metadata-version\": \"1.19.0\",\n        \"module\": \"io.opentelemetry:opentelemetry-sdk-trace\",\n        \"tested-versions\": [ \"1.19.0\" ],\n        \"override\": true,\n        \"skipped-versions\": [\n          { \"version\": \"1.34.0\", \"reason\": \"Dependency io.opentelemetry:opentelemetry-api:1.34.0 provides reflect-config.json which does not parse.\" }\n        ]\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/reachability-metadata-repository/schemas/metadata-root-index-schema-v1.0.0.json",
    "content": "{\n  \"$id\": \"https://raw.githubusercontent.com/oracle/graalvm-reachability-metadata/master/metadata/schemas/metadata-root-index-schema-v1.0.0.json\",\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"description\": \"Schema for metadata/index.json. This file lists modules known to the repository and optionally the directory where their metadata is stored, the allowed package prefixes for metadata, and inter-module requirements. See docs/CONTRIBUTING.md (Metadata structure).\",\n  \"type\": \"array\",\n  \"items\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"required\": [\"module\"],\n    \"properties\": {\n      \"module\": {\n        \"$ref\": \"#/$defs/moduleCoordinate\",\n        \"description\": \"Maven coordinates for the module in the form '<groupId>:<artifactId>'.\"\n      },\n      \"directory\": {\n        \"type\": \"string\",\n        \"minLength\": 1,\n        \"pattern\": \"^[^\\\\s].*$\",\n        \"description\": \"Repository-relative path under 'metadata/' containing this module's metadata (e.g. 'org.example/library'). If omitted, the entry may reference requirements only.\"\n      },\n      \"allowed-packages\": {\n        \"type\": \"array\",\n        \"description\": \"List of package (or fully-qualified name) prefixes considered valid sources of metadata entries for this module. Used to filter-in relevant JSON entries.\",\n        \"minItems\": 1,\n        \"uniqueItems\": true,\n        \"items\": {\n          \"type\": \"string\",\n          \"minLength\": 1\n        }\n      },\n      \"requires\": {\n        \"type\": \"array\",\n        \"description\": \"Optional list of module coordinates this module depends on. Each item is '<groupId>:<artifactId>'.\",\n        \"minItems\": 1,\n        \"uniqueItems\": true,\n        \"items\": {\n          \"$ref\": \"#/$defs/moduleCoordinate\"\n        }\n      }\n    }\n  },\n  \"$defs\": {\n    \"moduleCoordinate\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[^:]+:[^:]+$\"\n    }\n  },\n  \"examples\": [\n    [\n      {\n        \"directory\": \"org.example/library\",\n        \"module\": \"org.example:library\"\n      },\n      {\n        \"allowed-packages\": [\"org.package.name\"],\n        \"module\": \"org.example:dependant-library\",\n        \"requires\": [\"org.example:library\"]\n      },\n      {\n        \"allowed-packages\" : [ \"org.hibernate\", \"jakarta\" ],\n        \"directory\" : \"org.hibernate.orm/hibernate-envers\",\n        \"module\" : \"org.hibernate.orm:hibernate-envers\",\n        \"requires\" : [ \"org.hibernate.orm:hibernate-core\" ]\n      }\n    ]\n  ]\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/repository/com/example/library/1.0-SNAPSHOT/library-1.0-SNAPSHOT.pom",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>com.example</groupId>\n  <artifactId>library</artifactId>\n  <version>1.0-SNAPSHOT</version>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/repository/commons-io-consumer/one/1.0/one-1.0.pom",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>commons-io-consumer</groupId>\n  <artifactId>one</artifactId>\n  <version>1.0</version>\n  <dependencies>\n\t<dependency>\n\t\t<groupId>commons-io</groupId>\n\t\t<artifactId>commons-io</artifactId>\n\t\t<version>2.19.0</version>\n\t</dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/repository/commons-io-consumer/two/1.0/two-1.0.pom",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n  <modelVersion>4.0.0</modelVersion>\n  <groupId>commons-io-consumer</groupId>\n  <artifactId>two</artifactId>\n  <version>1.0</version>\n  <dependencies>\n\t<dependency>\n\t\t<groupId>commons-io</groupId>\n\t\t<artifactId>commons-io</artifactId>\n\t\t<version>2.18.0</version>\n\t</dependency>\n  </dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-gradle-plugin/src/test/resources/repository/org/springframework/boot/spring-boot-dependencies/TEST-SNAPSHOT/spring-boot-dependencies-TEST-SNAPSHOT.pom",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-dependencies</artifactId>\n\t<version>TEST-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<slf4j.version>1.7.25</slf4j.version>\n\t</properties>\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t\t<version>${slf4j.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-starter</artifactId>\n\t\t\t\t<version>TEST-SNAPSHOT</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.junit.platform</groupId>\n\t\t\t\t<artifactId>junit-platform-launcher</artifactId>\n\t\t\t\t<version>1.9.1</version>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.antora-contributor\"\n\tid \"org.springframework.boot.maven-plugin\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Maven Plugin\"\n\nconfigurations {\n\tdependenciesBom\n}\n\ndependencies {\n\tcompileOnly(\"org.apache.maven.plugin-tools:maven-plugin-annotations\")\n\tcompileOnly(\"org.apache.maven:maven-core\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t}\n\tcompileOnly(\"org.apache.maven:maven-plugin-api\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t\texclude(group: \"javax.enterprise\", module: \"cdi-api\")\n\t}\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.apache.maven.shared:maven-invoker\") {\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\timplementation(project(\":buildpack:spring-boot-buildpack-platform\"))\n\timplementation(project(\":loader:spring-boot-loader-tools\"))\n\timplementation(\"org.apache.maven.shared:maven-common-artifact-filters\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t\texclude(group: \"javax.enterprise\", module: \"cdi-api\")\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\timplementation(\"org.sonatype.plexus:plexus-build-api\") {\n\t\texclude(group: \"org.codehaus.plexus\", module: \"plexus-utils\")\n\t}\n\timplementation(\"org.springframework:spring-core\")\n\timplementation(\"org.springframework:spring-context\")\n\n\toptional(\"org.apache.maven.plugins:maven-shade-plugin\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t\texclude(group: \"javax.enterprise\", module: \"cdi-api\")\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\n\ttestImplementation(\"org.apache.maven:maven-core\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\ttestImplementation(\"org.apache.maven.shared:maven-common-artifact-filters\") {\n\t\texclude(group: \"javax.annotation\", module: \"javax.annotation-api\")\n\t\texclude(group: \"javax.enterprise\", module: \"cdi-api\")\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.mockito:mockito-core\")\n\ttestImplementation(\"org.mockito:mockito-junit-jupiter\")\n\ttestImplementation(\"org.springframework:spring-core\")\n\n\tintTestImplementation(project(\":buildpack:spring-boot-buildpack-platform\"))\n\tintTestImplementation(project(\":loader:spring-boot-loader-tools\"))\n\tintTestImplementation(project(\":test-support:spring-boot-test-support\"))\n\tintTestImplementation(\"org.apache.maven.shared:maven-invoker\") {\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\tintTestImplementation(\"org.assertj:assertj-core\")\n\tintTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\n\tmavenRepository(project(path: \":core:spring-boot\", configuration: \"mavenRepository\"))\n\tmavenRepository(project(path: \":platform:spring-boot-dependencies\", configuration: \"mavenRepository\"))\n\tmavenRepository(project(path: \":core:spring-boot-test\", configuration: \"mavenRepository\"))\n\tmavenRepository(project(path: \":module:spring-boot-devtools\", configuration: \"mavenRepository\"))\n\tmavenRepository(project(path: \":core:spring-boot-docker-compose\", configuration: \"mavenRepository\"))\n\tmavenRepository(project(path: \":starter:spring-boot-starter-parent\", configuration: \"mavenRepository\"))\n\tmavenRepository(\"org.springframework:spring-test\")\n\n\tversionProperties(project(path: \":platform:spring-boot-dependencies\", configuration: \"resolvedBom\"))\n}\n\next {\n\tversionElements = version.split(\"\\\\.\")\n\txsdVersion = versionElements[0] + \".\" + versionElements[1]\n}\n\ntasks.named(\"checkCompileClasspathForProhibitedDependencies\") {\n\tpermittedGroups = [\"javax.inject\"]\n}\n\nsourceSets {\n\tmain {\n\t\toutput.dir(layout.buildDirectory.dir(\"generated/resources/xsd\"), builtBy: \"xsdResources\")\n\t}\n\tintTest {\n\t\toutput.dir(layout.buildDirectory.dir(\"generated-resources\"), builtBy: [\"extractVersionProperties\"])\n\t}\n\tdockerTest {\n\t\toutput.dir(layout.buildDirectory.dir(\"generated-resources\"), builtBy: \"extractVersionProperties\")\n\t}\n}\n\njavadoc {\n\toptions {\n\t\tauthor = true\n\t\tdocTitle = \"Spring Boot Maven Plugin ${project.version} API\"\n\t\tencoding = \"UTF-8\"\n\t\tmemberLevel = \"protected\"\n\t\toutputLevel = \"quiet\"\n\t\tsplitIndex = true\n\t\tuse = true\n\t\twindowTitle = \"Spring Boot Maven Plugin ${project.version} API\"\n\t}\n}\n\ntasks.register(\"xsdResources\", Sync) {\n\tfrom \"src/main/xsd/layers-${project.ext.xsdVersion}.xsd\"\n\tinto layout.buildDirectory.dir(\"generated/resources/xsd/org/springframework/boot/maven\")\n\trename { fileName -> \"layers.xsd\" }\n}\n\nprepareMavenBinaries {\n\tversions.add(providers.gradleProperty('mavenVersion'))\n\tversions.add(\"3.6.3\")\n}\n\ntasks.named(\"documentPluginGoals\") {\n\tgoalSections = [\n\t\t\"build-image\": \"build-image\",\n\t\t\"build-image-no-fork\": \"build-image\",\n\t\t\"build-info\": \"build-info\",\n\t\t\"help\": \"help\",\n\t\t\"process-aot\": \"aot\",\n\t\t\"process-test-aot\": \"aot\",\n\t\t\"repackage\": \"packaging\",\n\t\t\"run\": \"run\",\n\t\t\"start\": \"integration-tests\",\n\t\t\"stop\": \"integration-tests\",\n\t\t\"test-run\": \"run\"\n\t]\n}\n\nantoraContributions {\n\t'maven-plugin' {\n\t\taggregateContent {\n\t\t\tfrom(documentPluginGoals) {\n\t\t\t\tinto \"modules/maven-plugin/partials/goals\"\n\t\t\t}\n\t\t}\n\t\tcatalogContent {\n\t\t\tfrom(javadoc) {\n\t\t\t\tinto \"api/java\"\n\t\t\t}\n\t\t}\n\t\tlocalAggregateContent {\n\t\t\tfrom(tasks.named(\"generateAntoraYml\")) {\n\t\t\t\tinto \"modules\"\n\t\t\t}\n\t\t}\n\t\tsource()\n\t}\n}\n\ntasks.named(\"generateAntoraPlaybook\") {\n\tantoraExtensions.xref.stubs = [\"appendix:.*\", \"api:.*\", \"reference:.*\", \"how-to:.*\"]\n\tasciidocExtensions.excludeJavadocExtension = true\n}\n\ntasks.named(\"dockerTest\").configure {\n\tdependsOn tasks.named(\"prepareMavenBinaries\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileIntTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/java/org/springframework/boot/maven/BuildImageRegistryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport com.github.dockerjava.api.DockerClient;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.UpdateListener;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.testsupport.container.RegistryContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Maven plugin's image support using a Docker image registry.\n *\n * @author Scott Frederick\n */\n@ExtendWith(MavenBuildExtension.class)\n@Testcontainers(disabledWithoutDocker = true)\n@Disabled(\"Disabled until differences between running locally and in CI can be diagnosed\")\nclass BuildImageRegistryIntegrationTests extends AbstractArchiveIntegrationTests {\n\n\t@Container\n\tstatic final RegistryContainer registry = TestImage.container(RegistryContainer.class);\n\n\tDockerClient dockerClient;\n\n\tString registryAddress;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tassertThat(registry.isRunning()).isTrue();\n\t\tthis.dockerClient = registry.getDockerClient();\n\t\tthis.registryAddress = registry.getHost() + \":\" + registry.getFirstMappedPort();\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithPublish(MavenBuild mavenBuild) {\n\t\tString repoName = \"test-image\";\n\t\tString imageName = this.registryAddress + \"/\" + repoName;\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-publish\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.imageName\", imageName)\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"Successfully built image\")\n\t\t\t\t\t.contains(\"Pushing image '\" + imageName + \":latest\" + \"'\")\n\t\t\t\t\t.contains(\"Pushed image '\" + imageName + \":latest\" + \"'\");\n\t\t\t\tImageReference imageReference = ImageReference.of(imageName);\n\t\t\t\tDockerApi.ImageApi imageApi = new DockerApi().image();\n\t\t\t\tImage pulledImage = imageApi.pull(imageReference, null, UpdateListener.none());\n\t\t\t\tassertThat(pulledImage).isNotNull();\n\t\t\t\timageApi.remove(imageReference, false);\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/java/org/springframework/boot/maven/BuildImageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.time.OffsetDateTime;\nimport java.util.Random;\nimport java.util.stream.IntStream;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;\nimport org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageName;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Maven plugin's image support.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Rafael Ceccone\n */\n@ExtendWith(MavenBuildExtension.class)\n@DisabledIfDockerUnavailable\nclass BuildImageTests extends AbstractArchiveIntegrationTests {\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithoutRepackageTheArchiveIsRepackagedOnTheFly(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project, \"target/build-image-0.0.1.BUILD-SNAPSHOT.jar.original\");\n\t\t\t\tassertThat(original).doesNotExist();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Running detector\")\n\t\t\t\t\t.contains(\"Running builder\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedOnTheCommandLineWithoutRepackageTheArchiveIsRepackagedOnTheFly(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-cmd-line\")\n\t\t\t.goals(\"spring-boot:build-image\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-cmd-line-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project, \"target/build-image-cmd-line-0.0.1.BUILD-SNAPSHOT.jar.original\");\n\t\t\t\tassertThat(original).doesNotExist();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-cmd-line:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Running detector\")\n\t\t\t\t\t.contains(\"Running builder\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-cmd-line\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenPackageIsInvokedWithClassifierTheOriginalArchiveIsFound(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-classifier\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-classifier-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile classifier = new File(project, \"target/build-image-classifier-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\t\tassertThat(classifier).doesNotExist();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-classifier:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-classifier\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithClassifierAndRepackageTheOriginalArchiveIsFound(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-fork-classifier\")\n\t\t\t.goals(\"spring-boot:build-image\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-fork-classifier-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile classifier = new File(project, \"target/build-image-fork-classifier-0.0.1.BUILD-SNAPSHOT-exec.jar\");\n\t\t\t\tassertThat(classifier).exists();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-fork-classifier:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-fork-classifier\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithClassifierSourceWithoutRepackageTheArchiveIsRepackagedOnTheFly(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-classifier-source\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project,\n\t\t\t\t\t\t\"target/build-image-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar.original\");\n\t\t\t\tassertThat(original).doesNotExist();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-classifier-source:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-classifier-source\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithRepackageTheExistingArchiveIsUsed(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-with-repackage\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-with-repackage-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project,\n\t\t\t\t\t\t\"target/build-image-with-repackage-0.0.1.BUILD-SNAPSHOT.jar.original\");\n\t\t\t\tassertThat(original).isFile();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-with-repackage:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-with-repackage\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithClassifierAndRepackageTheExistingArchiveIsUsed(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-classifier-with-repackage\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-classifier-with-repackage-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project,\n\t\t\t\t\t\t\"target/build-image-classifier-with-repackage-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\t\tassertThat(original).isFile();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-classifier-with-repackage:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-classifier-with-repackage\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithClassifierSourceAndRepackageTheExistingArchiveIsUsed(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-classifier-source-with-repackage\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project,\n\t\t\t\t\t\t\"target/build-image-classifier-source-with-repackage-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project,\n\t\t\t\t\t\t\"target/build-image-classifier-source-with-repackage-0.0.1.BUILD-SNAPSHOT-test.jar.original\");\n\t\t\t\tassertThat(original).isFile();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-classifier-source-with-repackage:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-classifier-source-with-repackage\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithWarPackaging(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-war-packaging\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tFile war = new File(project, \"target/build-image-war-packaging-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\t\tassertThat(war).isFile();\n\t\t\t\tFile original = new File(project, \"target/build-image-war-packaging-0.0.1.BUILD-SNAPSHOT.war.original\");\n\t\t\t\tassertThat(original).doesNotExist();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-war-packaging:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-war-packaging\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithCustomImageName(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-custom-name\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.systemProperty(\"spring-boot.build-image.imageName\", \"example.com/test/property-ignored:pom-preferred\")\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-custom-name-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tFile original = new File(project, \"target/build-image-custom-name-0.0.1.BUILD-SNAPSHOT.jar.original\");\n\t\t\t\tassertThat(original).doesNotExist();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"example.com/test/build-image:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"example.com/test/build-image\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithCommandLineParameters(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.systemProperty(\"spring-boot.build-image.imageName\", \"example.com/test/cmd-property-name:v1\")\n\t\t\t.systemProperty(\"spring-boot.build-image.builder\", \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\")\n\t\t\t.systemProperty(\"spring-boot.build-image.trustBuilder\", \"true\")\n\t\t\t.systemProperty(\"spring-boot.build-image.runImage\", \"paketobuildpacks/run-noble-tiny\")\n\t\t\t.systemProperty(\"spring-boot.build-image.createdDate\", \"2020-07-01T12:34:56Z\")\n\t\t\t.systemProperty(\"spring-boot.build-image.applicationDirectory\", \"/application\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"example.com/test/cmd-property-name:v1\")\n\t\t\t\t\t.contains(\"Running creator\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tImage image = new DockerApi().image()\n\t\t\t\t\t.inspect(ImageReference.of(\"example.com/test/cmd-property-name:v1\"));\n\t\t\t\tassertThat(image.getCreated()).isEqualTo(\"2020-07-01T12:34:56Z\");\n\t\t\t\tremoveImage(\"example.com/test/cmd-property-name\", \"v1\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithCustomBuilderImageAndRunImage(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-custom-builder\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-v2-builder:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"docker.io/library/build-image-v2-builder\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithTrustBuilder(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-trust-builder\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-v2-trust-builder:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Running creator\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"docker.io/library/build-image-v2-trust-builder\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithEmptyEnvEntry(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-empty-env-entry\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-empty-env-entry:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-empty-env-entry\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithZipPackaging(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-zip-packaging\")\n\t\t\t.goals(\"package\")\n\t\t\t.prepare(this::writeLongNameResource)\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tFile jar = new File(project, \"target/build-image-zip-packaging-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar).isFile();\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-zip-packaging:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Main-Class: org.springframework.boot.loader.launch.PropertiesLauncher\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-zip-packaging\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithBuildpacks(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-custom-buildpacks\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-custom-buildpacks:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-custom-buildpacks\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithBinding(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-bindings\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-bindings:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"binding: ca-certificates/type=ca-certificates\")\n\t\t\t\t\t.contains(\"binding: ca-certificates/test.crt=---certificate one---\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-bindings\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithNetworkModeNone(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-network\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-network:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Network status: curl failed\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-network\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedOnMultiModuleProjectWithPackageGoal(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-multi-module\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-multi-module-app:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-multi-module-app\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithTags(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-tags\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-tags:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-tags:latest\")\n\t\t\t\t\t.contains(\"Successfully created image tag\");\n\t\t\t\tremoveImage(\"build-image-tags\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t\tremoveImage(\"build-image-tags\", \"latest\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithVolumeCaches(MavenBuild mavenBuild) {\n\t\tString testBuildId = randomString();\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-volume-caches\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.systemProperty(\"test-build-id\", testBuildId)\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-volume-caches:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-volume-caches\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t\tdeleteVolumes(\"cache-\" + testBuildId + \".build\", \"cache-\" + testBuildId + \".launch\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\t@EnabledOnOs(value = OS.LINUX, disabledReason = \"Works with Docker Engine on Linux but is not reliable with \"\n\t\t\t+ \"Docker Desktop on other OSs\")\n\tvoid whenBuildImageIsInvokedWithBindCaches(MavenBuild mavenBuild) {\n\t\tString testBuildId = randomString();\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-bind-caches\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.systemProperty(\"test-build-id\", testBuildId)\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-bind-caches:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-bind-caches\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t\tString tempDir = System.getProperty(\"java.io.tmpdir\");\n\t\t\t\tPath buildCachePath = Paths.get(tempDir, \"junit-image-cache-\" + testBuildId + \"-build\");\n\t\t\t\tPath launchCachePath = Paths.get(tempDir, \"junit-image-cache-\" + testBuildId + \"-launch\");\n\t\t\t\tassertThat(buildCachePath).exists().isDirectory();\n\t\t\t\tassertThat(launchCachePath).exists().isDirectory();\n\t\t\t\tcleanupCache(buildCachePath);\n\t\t\t\tcleanupCache(launchCachePath);\n\t\t\t});\n\t}\n\n\tprivate static void cleanupCache(Path cachePath) {\n\t\ttry {\n\t\t\tFileSystemUtils.deleteRecursively(cachePath);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithCreatedDate(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-created-date\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-created-date:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tImage image = new DockerApi().image()\n\t\t\t\t\t.inspect(ImageReference.of(\"docker.io/library/build-image-created-date:0.0.1.BUILD-SNAPSHOT\"));\n\t\t\t\tassertThat(image.getCreated()).isEqualTo(\"2020-07-01T12:34:56Z\");\n\t\t\t\tremoveImage(\"build-image-created-date\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithCurrentCreatedDate(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-current-created-date\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-current-created-date:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tImage image = new DockerApi().image()\n\t\t\t\t\t.inspect(ImageReference\n\t\t\t\t\t\t.of(\"docker.io/library/build-image-current-created-date:0.0.1.BUILD-SNAPSHOT\"));\n\t\t\t\tOffsetDateTime createdDateTime = OffsetDateTime.parse(image.getCreated());\n\t\t\t\tOffsetDateTime current = OffsetDateTime.now().withOffsetSameInstant(createdDateTime.getOffset());\n\t\t\t\tassertThat(createdDateTime.getYear()).isEqualTo(current.getYear());\n\t\t\t\tassertThat(createdDateTime.getMonth()).isEqualTo(current.getMonth());\n\t\t\t\tassertThat(createdDateTime.getDayOfMonth()).isEqualTo(current.getDayOfMonth());\n\t\t\t\tremoveImage(\"build-image-current-created-date\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithApplicationDirectory(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-app-dir\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-app-dir:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-app-dir\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildImageIsInvokedWithEmptySecurityOptions(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-security-opts\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.execute((project) -> {\n\t\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t\t.contains(\"docker.io/library/build-image-security-opts:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t.contains(\"Successfully built image\");\n\t\t\t\tremoveImage(\"build-image-security-opts\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\t@EnabledOnOs(value = { OS.LINUX, OS.MAC }, architectures = \"aarch64\",\n\t\t\tdisabledReason = \"Lifecycle will only run on ARM architecture\")\n\tvoid whenBuildImageIsInvokedOnLinuxArmWithImagePlatformLinuxArm(MavenBuild mavenBuild) throws IOException {\n\t\tString builderImage = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\";\n\t\tString runImage = \"docker.io/paketobuildpacks/run-noble-tiny:latest\";\n\t\tString buildpackImage = \"ghcr.io/spring-io/spring-boot-test-info:0.0.2\";\n\t\tremoveImages(builderImage, runImage, buildpackImage);\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-platform-linux-arm\").goals(\"package\").execute((project) -> {\n\t\t\tFile jar = new File(project, \"target/build-image-platform-linux-arm-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar).isFile();\n\t\t\tassertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t.contains(\"docker.io/library/build-image-platform-linux-arm:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.contains(\"Pulling builder image '\" + builderImage + \"' for platform 'linux/arm64'\")\n\t\t\t\t.contains(\"Pulling run image '\" + runImage + \"' for platform 'linux/arm64'\")\n\t\t\t\t.contains(\"Pulling buildpack image '\" + buildpackImage + \"' for platform 'linux/arm64'\")\n\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t.contains(\"---> Test Info buildpack done\")\n\t\t\t\t.contains(\"Successfully built image\");\n\t\t\tremoveImage(\"docker.io/library/build-image-platform-linux-arm\", \"0.0.1.BUILD-SNAPSHOT\");\n\t\t});\n\t\tremoveImages(builderImage, runImage, buildpackImage);\n\t}\n\n\t@TestTemplate\n\t@EnabledOnOs(value = { OS.LINUX, OS.MAC }, architectures = \"amd64\",\n\t\t\tdisabledReason = \"The expected failure condition will not fail on ARM architectures\")\n\tvoid failsWhenBuildImageIsInvokedOnLinuxAmdWithImagePlatformLinuxArm(MavenBuild mavenBuild) throws IOException {\n\t\tString builderImage = \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2\";\n\t\tString runImage = \"docker.io/paketobuildpacks/run-noble-tiny:latest\";\n\t\tString buildpackImage = \"ghcr.io/spring-io/spring-boot-test-info:0.0.2\";\n\t\tremoveImages(buildpackImage, runImage, buildpackImage);\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-platform-linux-arm\")\n\t\t\t.goals(\"package\")\n\t\t\t.executeAndFail((project) -> assertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t.contains(\"docker.io/library/build-image-platform-linux-arm:0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.contains(\"Pulling builder image '\" + builderImage + \"' for platform 'linux/arm64'\")\n\t\t\t\t.contains(\"Pulling run image '\" + runImage + \"' for platform 'linux/arm64'\")\n\t\t\t\t.contains(\"Pulling buildpack image '\" + buildpackImage + \"' for platform 'linux/arm64'\")\n\t\t\t\t.contains(\"exec format error\"));\n\t\tremoveImages(builderImage, runImage, buildpackImage);\n\t}\n\n\t@TestTemplate\n\tvoid failsWhenBuildImageIsInvokedOnMultiModuleProjectWithBuildImageGoal(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-multi-module\")\n\t\t\t.goals(\"spring-boot:build-image\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.executeAndFail((project) -> assertThat(buildLog(project)).contains(\"Error packaging archive for image\"));\n\t}\n\n\t@TestTemplate\n\tvoid failsWhenBuilderFails(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-builder-error\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.executeAndFail((project) -> assertThat(buildLog(project)).contains(\"Building image\")\n\t\t\t\t.contains(\"---> Test Info buildpack building\")\n\t\t\t\t.contains(\"Forced builder failure\")\n\t\t\t\t.containsPattern(\"Builder lifecycle '.*' failed with status code\"));\n\t}\n\n\t@TestTemplate\n\tvoid failsWithBuildpackNotInBuilder(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-bad-buildpack\")\n\t\t\t.goals(\"package\")\n\t\t\t.systemProperty(\"spring-boot.build-image.pullPolicy\", \"IF_NOT_PRESENT\")\n\t\t\t.executeAndFail((project) -> assertThat(buildLog(project))\n\t\t\t\t.contains(\"'urn:cnb:builder:example/does-not-exist:0.0.1' not found in builder\"));\n\t}\n\n\t@TestTemplate\n\tvoid failsWhenFinalNameIsMisconfigured(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-final-name\")\n\t\t\t.goals(\"package\")\n\t\t\t.executeAndFail((project) -> assertThat(buildLog(project)).contains(\"final-name.jar.original\")\n\t\t\t\t.contains(\"is required for building an image\"));\n\t}\n\n\t@TestTemplate\n\tvoid failsWhenCachesAreConfiguredTwice(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"dockerTest\", \"build-image-caches-multiple\")\n\t\t\t.goals(\"package\")\n\t\t\t.executeAndFail((project) -> assertThat(buildLog(project))\n\t\t\t\t.contains(\"Each image building cache can be configured only once\"));\n\t}\n\n\tprivate void writeLongNameResource(File project) {\n\t\tStringBuilder name = new StringBuilder();\n\t\tnew Random().ints('a', 'z' + 1).limit(128).forEach((i) -> name.append((char) i));\n\t\ttry {\n\t\t\tPath path = project.toPath().resolve(Paths.get(\"src\", \"main\", \"resources\", name.toString()));\n\t\t\tFiles.createDirectories(path.getParent());\n\t\t\tFiles.createFile(path);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void removeImages(String... names) throws IOException {\n\t\tImageApi imageApi = new DockerApi().image();\n\t\tfor (String name : names) {\n\t\t\ttry {\n\t\t\t\timageApi.remove(ImageReference.of(name), false);\n\t\t\t}\n\t\t\tcatch (DockerEngineException ex) {\n\t\t\t\t// ignore image remove failures\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void removeImage(String name, String version) {\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(name), version);\n\t\ttry {\n\t\t\tnew DockerApi().image().remove(imageReference, false);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to remove docker image \" + imageReference, ex);\n\t\t}\n\t}\n\n\tprivate void deleteVolumes(String... names) throws IOException {\n\t\tVolumeApi volumeApi = new DockerApi().volume();\n\t\tfor (String name : names) {\n\t\t\tvolumeApi.delete(VolumeName.of(name), false);\n\t\t}\n\t}\n\n\tprivate String randomString() {\n\t\tIntStream chars = new Random().ints('a', 'z' + 1).limit(10);\n\t\treturn chars.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-app-dir/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-app-dir</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<applicationDirectory>/application</applicationDirectory>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-app-dir/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bad-buildpack/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-custom-buildpacks</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<buildpacks>\n\t\t\t\t\t\t\t\t\t<buildpack>urn:cnb:builder:example/does-not-exist:0.0.1</buildpack>\n\t\t\t\t\t\t\t\t</buildpacks>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bad-buildpack/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bind-caches/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-bind-caches</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<buildWorkspace>\n\t\t\t\t\t\t\t\t\t<bind>\n\t\t\t\t\t\t\t\t\t\t<source>${java.io.tmpdir}/junit-image-cache-${test-build-id}-work</source>\n\t\t\t\t\t\t\t\t\t</bind>\n\t\t\t\t\t\t\t\t</buildWorkspace>\n\t\t\t\t\t\t\t\t<buildCache>\n\t\t\t\t\t\t\t\t\t<bind>\n\t\t\t\t\t\t\t\t\t\t<source>${java.io.tmpdir}/junit-image-cache-${test-build-id}-build</source>\n\t\t\t\t\t\t\t\t\t</bind>\n\t\t\t\t\t\t\t\t</buildCache>\n\t\t\t\t\t\t\t\t<launchCache>\n\t\t\t\t\t\t\t\t\t<bind>\n\t\t\t\t\t\t\t\t\t\t<source>${java.io.tmpdir}/junit-image-cache-${test-build-id}-launch</source>\n\t\t\t\t\t\t\t\t\t</bind>\n\t\t\t\t\t\t\t\t</launchCache>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bind-caches/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bindings/bindings/ca-certificates/test.crt",
    "content": "---certificate one---"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bindings/bindings/ca-certificates/type",
    "content": "ca-certificates"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bindings/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-bindings</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<bindings>\n\t\t\t\t\t\t\t\t\t<binding>${basedir}/bindings/ca-certificates:/platform/bindings/ca-certificates</binding>\n\t\t\t\t\t\t\t\t</bindings>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-bindings/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-builder-error/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-builder-error</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<env>\n\t\t\t\t\t\t\t\t\t<FORCE_FAILURE>true</FORCE_FAILURE>\n\t\t\t\t\t\t\t\t</env>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-builder-error/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-caches-multiple/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-caches-multiple</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<buildCache>\n\t\t\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t\t\t<name>build-cache-volume1</name>\n\t\t\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t\t\t<name>build-cache-volume2</name>\n\t\t\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t\t\t</buildCache>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-caches-multiple/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-classifier</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier-source/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-classifier-source</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>3.2.0</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier-source/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier-source-with-repackage/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-classifier-source-with-repackage</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>3.2.0</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier-source-with-repackage/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier-with-repackage/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-classifier-with-repackage</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-classifier-with-repackage/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-cmd-line/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-cmd-line</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<pluginManagement>\n\t\t\t<plugins>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t\t<version>@project.version@</version>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t</image>\n\t\t\t\t\t</configuration>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-cmd-line/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-created-date/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-created-date</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<createdDate>2020-07-01T12:34:56Z</createdDate>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-created-date/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-current-created-date/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-current-created-date</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<createdDate>now</createdDate>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-current-created-date/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-custom-builder/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-v2-builder</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<runImage>paketobuildpacks/run-noble-tiny</runImage>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-custom-builder/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-custom-buildpacks/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-custom-buildpacks</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<buildpacks>\n\t\t\t\t\t\t\t\t\t<buildpack>urn:cnb:builder:spring-boot/spring-boot-test-info</buildpack>\n\t\t\t\t\t\t\t\t</buildpacks>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-custom-buildpacks/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-custom-name/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-custom-name</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<name>example.com/test/build-image:${project.version}</name>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-custom-name/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-empty-env-entry/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-empty-env-entry</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<env>\n\t\t\t\t\t\t\t\t\t<EMPTY_KEY></EMPTY_KEY>\n\t\t\t\t\t\t\t\t</env>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-empty-env-entry/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-final-name/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-final-name</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<finalName>final-name</finalName>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-final-name/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-fork-classifier/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-fork-classifier</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<classifier>exec</classifier>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-fork-classifier/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-multi-module/app/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>build-image-multi-module</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>build-image-multi-module-app</artifactId>\n\t<name>app</name>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>build-image-multi-module-library</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-multi-module/app/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.test.SampleLibrary;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(SampleLibrary.getMessage());\n\t\tsynchronized (args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-multi-module/library/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>build-image-multi-module</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>build-image-multi-module-library</artifactId>\n\t<name>library</name>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-multi-module/library/src/main/java/org/test/SampleLibrary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleLibrary {\n\tpublic static String getMessage() {\n\t\treturn \"Launched\";\n\t}\n}"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-multi-module/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-multi-module</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\t\t<module>library</module>\n\t\t<module>app</module>\n\t</modules>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-network/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-network</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<network>none</network>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-network/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-platform-linux-arm/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-platform-linux-arm</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<runImage>paketobuildpacks/run-noble-tiny</runImage>\n\t\t\t\t\t\t\t\t<buildpacks>\n\t\t\t\t\t\t\t\t\t<buildpack>ghcr.io/spring-io/spring-boot-test-info:0.0.2</buildpack>\n\t\t\t\t\t\t\t\t</buildpacks>\n\t\t\t\t\t\t\t\t<imagePlatform>linux/arm64</imagePlatform>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-platform-linux-arm/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-publish/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<publish>true</publish>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-publish/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-security-opts/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-security-opts</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<security-options/>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-security-opts/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-tags/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-tags</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<tags>\n\t\t\t\t\t\t\t\t\t<tag>${project.artifactId}:latest</tag>\n\t\t\t\t\t\t\t\t</tags>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-tags/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-v2-trust-builder</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<trustBuilder>true</trustBuilder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-trust-builder/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-volume-caches/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-volume-caches</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t\t<buildWorkspace>\n\t\t\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t\t\t<name>cache-${test-build-id}.work</name>\n\t\t\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t\t\t</buildWorkspace>\n\t\t\t\t\t\t\t\t<buildCache>\n\t\t\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t\t\t<name>cache-${test-build-id}.build</name>\n\t\t\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t\t\t</buildCache>\n\t\t\t\t\t\t\t\t<launchCache>\n\t\t\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t\t\t<name>cache-${test-build-id}.launch</name>\n\t\t\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t\t\t</launchCache>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-volume-caches/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-war-packaging/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-war-packaging</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-war-packaging/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-with-repackage/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-with-repackage</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t\t\t</image>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-with-repackage/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-zip-packaging/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-image-zip-packaging</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<layout>ZIP</layout>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<builder>ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.2</builder>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/dockerTest/projects/build-image-zip-packaging/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Launched\");\n\t\tsynchronized(args) {\n\t\t\targs.wait(); // Prevent exit\"\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/antora.yml",
    "content": "name: boot\nversion: true\next:\n  zip_contents_collector:\n    include:\n    - name: maven-plugin\n      classifier: aggregate-content\n    - name: maven-plugin\n      classifier: catalog-content\n      module: maven-plugin\n      destination: content-catalog\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/local-nav.adoc",
    "content": "include::maven-plugin:partial$nav-maven-plugin.adoc[]"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/aot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>aot</artifactId>\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- tag::aot[] -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>process-aot</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<!-- end::aot[] -->\n\t\t</plugins>\n\t</build>\n</project>\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/aot-native/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>aot-native</artifactId>\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- tag::aot-native[] -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.graalvm.buildtools</groupId>\n\t\t\t\t<artifactId>native-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<!-- end::aot-native[] -->\n\t\t</plugins>\n\t</build>\n</project>\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/aot-native-profile-buildpacks/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>aot-native-profile-buildpacks</artifactId>\n\t<profiles>\n\t\t<!-- tag::profile[] -->\n\t\t<profile>\n\t\t\t<id>native</id>\n\t\t\t<build>\n\t\t\t\t<pluginManagement>\n\t\t\t\t\t<plugins>\n\t\t\t\t\t\t<plugin>\n\t\t\t\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t\t<id>build-image</id>\n\t\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t</plugin>\n\t\t\t\t\t</plugins>\n\t\t\t\t</pluginManagement>\n\t\t\t</build>\n\t\t</profile>\n\t\t<!-- end::profile[] -->\n\t</profiles>\n\n</project>\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/aot-native-profile-nbt/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>aot-native-nbt</artifactId>\n\t<profiles>\n\t\t<!-- tag::profile[] -->\n\t\t<profile>\n\t\t\t<id>native</id>\n\t\t\t<build>\n\t\t\t\t<pluginManagement>\n\t\t\t\t\t<plugins>\n\t\t\t\t\t\t<plugin>\n\t\t\t\t\t\t\t<groupId>org.graalvm.buildtools</groupId>\n\t\t\t\t\t\t\t<artifactId>native-maven-plugin</artifactId>\n\t\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t\t<id>build-image</id>\n\t\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t\t<goal>compile-no-fork</goal>\n\t\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t</plugin>\n\t\t\t\t\t</plugins>\n\t\t\t\t</pluginManagement>\n\t\t\t</build>\n\t\t</profile>\n\t\t<!-- end::profile[] -->\n\t</profiles>\n\n</project>\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/build-info/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::build-info[] -->\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>build-info</artifactId>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<additionalProperties>\n\t\t\t\t\t\t\t\t<encoding.source>UTF-8</encoding.source>\n\t\t\t\t\t\t\t\t<encoding.reporting>UTF-8</encoding.reporting>\n\t\t\t\t\t\t\t\t<java.version>${java.version}</java.version>\n\t\t\t\t\t\t\t</additionalProperties>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::build-info[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/getting-started/plugin-repositories-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>getting-started</artifactId>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<additionalProperties>\n\t\t\t\t\t\t\t\t<encoding.source>UTF-8</encoding.source>\n\t\t\t\t\t\t\t\t<encoding.reporting>UTF-8</encoding.reporting>\n\t\t\t\t\t\t\t\t<java.source>${maven.compiler.source}</java.source>\n\t\t\t\t\t\t\t\t<java.target>${maven.compiler.target}</java.target>\n\t\t\t\t\t\t\t</additionalProperties>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<!-- tag::plugin-repositories[] -->\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\t<!-- end::plugin-repositories[] -->\n\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/getting-started/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::getting-started[] -->\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>getting-started</artifactId>\n\t<!-- ... -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::getting-started[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/integration-tests/customize-jmx-port-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>integration-tests</artifactId>\n\t<!-- tag::customize-jmx-port[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<jmxPort>9009</jmxPort>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>start</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>stop</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::customize-jmx-port[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/integration-tests/failsafe-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>integration-tests</artifactId>\n\t<build>\n\t\t<plugins>\n\t\t\t<!-- tag::failsafe[] -->\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-failsafe-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<classesDirectory>${project.build.outputDirectory}</classesDirectory>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<!-- end::failsafe[] -->\n\t\t</plugins>\n\t</build>\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/integration-tests/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>integration-tests</artifactId>\n\t<!-- tag::integration-tests[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>start</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>stop</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::integration-tests[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/integration-tests/random-port-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>integration-tests</artifactId>\n\t<!-- tag::random-port[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>build-helper-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>reserve-tomcat-port</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>reserve-network-port</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>process-resources</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<portNames>\n\t\t\t\t\t\t\t\t<portName>tomcat.http.port</portName>\n\t\t\t\t\t\t\t</portNames>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>start</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<arguments>\n\t\t\t\t\t\t\t\t<argument>--server.port=${tomcat.http.port}</argument>\n\t\t\t\t\t\t\t</arguments>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>stop</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-failsafe-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<systemPropertyVariables>\n\t\t\t\t\t\t<test.server.port>${tomcat.http.port}</test.server.port>\n\t\t\t\t\t</systemPropertyVariables>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::random-port[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/integration-tests/skip-integration-tests-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::skip-integration-tests[] -->\n<project>\n\t<properties>\n\t\t<skip.it>false</skip.it>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>start</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<skip>${skip.it}</skip>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>stop</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<skip>${skip.it}</skip>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-failsafe-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>${skip.it}</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::skip-integration-tests[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/classified-artifact-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::classified-artifact[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>task</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>task</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::classified-artifact[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/custom-layers-classpath-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::custom-layers-classpath[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<layers>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t\t<configurationName>custom</configurationName>\n\t\t\t\t\t</layers>\n\t\t\t\t</configuration>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>com.example</groupId>\n\t\t\t\t\t\t<artifactId>layers-configuration</artifactId>\n\t\t\t\t\t\t<version>1.0.0</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::custom-layers-classpath[] -->\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/custom-layers-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::custom-layers[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<layers>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t\t<configuration>${project.basedir}/src/layers.xml</configuration>\n\t\t\t\t\t</layers>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::custom-layers[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/custom-layout-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::custom-layout[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layoutFactory implementation=\"com.example.CustomLayoutFactory\">\n\t\t\t\t\t\t\t\t<customProperty>value</customProperty>\n\t\t\t\t\t\t\t</layoutFactory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>com.example</groupId>\n\t\t\t\t\t\t<artifactId>custom-layout</artifactId>\n\t\t\t\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::custom-layout[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/custom-name-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::custom-name[] -->\n<project>\n\t<build>\n\t\t<finalName>my-app</finalName>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::custom-name[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/different-classifier-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::different-classifier[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>exec</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::different-classifier[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/disable-layers-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::disable-layers[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<layers>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</layers>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::disable-layers[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/exclude-artifact-group-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::exclude-artifact-group[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<excludeGroupIds>com.example</excludeGroupIds>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::exclude-artifact-group[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/exclude-artifact-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::exclude-artifact[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<excludes>\n\t\t\t\t\t\t<exclude>\n\t\t\t\t\t\t\t<groupId>com.example</groupId>\n\t\t\t\t\t\t\t<artifactId>module1</artifactId>\n\t\t\t\t\t\t</exclude>\n\t\t\t\t\t</excludes>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::exclude-artifact[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/exclude-dependency-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::exclude-dependency[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<includeTools>false</includeTools>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::exclude-dependency[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/jar-plugin-first-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::jar-plugin-first[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-jar</id>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>task</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>task</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::jar-plugin-first[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/layers-configuration.xml",
    "content": "<!-- tag::layers-configuration[] -->\n<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t\t  {url-spring-boot-layers-xsd}\">\n\t<application>\n\t\t<into layer=\"spring-boot-loader\">\n\t\t\t<include>org/springframework/boot/loader/**</include>\n\t\t</into>\n\t\t<into layer=\"application\" />\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*SNAPSHOT</include>\n\t\t</into>\n\t\t<into layer=\"company-dependencies\">\n\t\t\t<include>com.acme:*</include>\n\t\t</into>\n\t\t<into layer=\"dependencies\"/>\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>dependencies</layer>\n\t\t<layer>spring-boot-loader</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>company-dependencies</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>\n<!-- end::layers-configuration[] -->\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/layers.xml",
    "content": "<!-- tag::layers[] -->\n<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t                      {url-spring-boot-layers-xsd}\">\n\t<application>\n\t\t<into layer=\"spring-boot-loader\">\n\t\t\t<include>org/springframework/boot/loader/**</include>\n\t\t</into>\n\t\t<into layer=\"application\" />\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"application\">\n\t\t\t<includeModuleDependencies />\n\t\t</into>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*SNAPSHOT</include>\n\t\t</into>\n\t\t<into layer=\"dependencies\" />\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>dependencies</layer>\n\t\t<layer>spring-boot-loader</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>\n<!-- end::layers[] -->\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/local-repackaged-artifact-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::local-repackaged-artifact[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<attach>false</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::local-repackaged-artifact[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/non-default-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>packaging</artifactId>\n\t<!-- ... -->\n\t<!-- tag::non-default[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<mainClass>${start.class}</mainClass>\n\t\t\t\t\t<layout>ZIP</layout>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::non-default[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/repackage-configuration-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::repackage-configuration[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>exec</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::repackage-configuration[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging/repackage-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>packaging</artifactId>\n\t<!-- ... -->\n\t<!-- tag::repackage[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::repackage[] -->\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/bind-caches-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::caches[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<buildWorkspace>\n\t\t\t\t\t\t\t<bind>\n\t\t\t\t\t\t\t\t<source>/tmp/cache-${project.artifactId}.work</source>\n\t\t\t\t\t\t\t</bind>\n\t\t\t\t\t\t</buildWorkspace>\n\t\t\t\t\t\t<buildCache>\n\t\t\t\t\t\t\t<bind>\n\t\t\t\t\t\t\t\t<source>/tmp/cache-${project.artifactId}.build</source>\n\t\t\t\t\t\t\t</bind>\n\t\t\t\t\t\t</buildCache>\n\t\t\t\t\t\t<launchCache>\n\t\t\t\t\t\t\t<bind>\n\t\t\t\t\t\t\t\t<source>/tmp/cache-${project.artifactId}.launch</source>\n\t\t\t\t\t\t\t</bind>\n\t\t\t\t\t\t</launchCache>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::caches[] -->"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/build-image-example-builder-configuration-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::build-image-example-builder-configuration[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<env>\n\t\t\t\t\t\t\t<BP_JVM_VERSION>17</BP_JVM_VERSION>\n\t\t\t\t\t\t</env>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::build-image-example-builder-configuration[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/buildpacks-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::buildpacks[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<buildpacks>\n\t\t\t\t\t\t\t<buildpack>file:///path/to/example-buildpack.tgz</buildpack>\n\t\t\t\t\t\t\t<buildpack>urn:cnb:builder:paketo-buildpacks/java</buildpack>\n\t\t\t\t\t\t</buildpacks>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::buildpacks[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/caches-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::caches[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<buildCache>\n\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t<name>cache-${project.artifactId}.build</name>\n\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t</buildCache>\n\t\t\t\t\t\t<launchCache>\n\t\t\t\t\t\t\t<volume>\n\t\t\t\t\t\t\t\t<name>cache-${project.artifactId}.launch</name>\n\t\t\t\t\t\t\t</volume>\n\t\t\t\t\t\t</launchCache>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::caches[] -->"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/custom-image-builder-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::custom-image-builder[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<builder>mine/java-cnb-builder</builder>\n\t\t\t\t\t\t<runImage>mine/java-cnb-run</runImage>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::custom-image-builder[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/custom-image-name-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::custom-image-name[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<name>example.com/library/${project.artifactId}</name>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::custom-image-name[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-colima-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker-colima[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<host>unix:///${user.home}/.colima/docker.sock</host>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker-colima[] -->\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-minikube-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker-minikube[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<host>tcp://192.168.99.100:2376</host>\n\t\t\t\t\t\t<tlsVerify>true</tlsVerify>\n\t\t\t\t\t\t<certPath>/home/user/.minikube/certs</certPath>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker-minikube[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-podman-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker-podman[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<host>unix:///run/user/1000/podman/podman.sock</host>\n\t\t\t\t\t\t<bindHostToBuilder>true</bindHostToBuilder>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker-podman[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-pom-authentication-command-line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<publishRegistry>\n\t\t\t\t\t\t\t<url>${docker.publishRegistry.url}</url>\n\t\t\t\t\t\t\t<username>${docker.publishRegistry.username}</username>\n\t\t\t\t\t\t\t<password>${docker.publishRegistry.password}</password>\n\t\t\t\t\t\t</publishRegistry>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker[] -->"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<name>docker.example.com/library/${project.artifactId}</name>\n\t\t\t\t\t\t<publish>true</publish>\n\t\t\t\t\t</image>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<publishRegistry>\n\t\t\t\t\t\t\t<username>user</username>\n\t\t\t\t\t\t\t<password>secret</password>\n\t\t\t\t\t\t</publishRegistry>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-registry-authentication-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker-registry-authentication[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<builderRegistry>\n\t\t\t\t\t\t\t<username>user</username>\n\t\t\t\t\t\t\t<password>secret</password>\n\t\t\t\t\t\t\t<url>https://docker.example.com/v1/</url>\n\t\t\t\t\t\t\t<email>user@example.com</email>\n\t\t\t\t\t\t</builderRegistry>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker-registry-authentication[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/docker-token-authentication-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::docker-token-authentication[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<docker>\n\t\t\t\t\t\t<builderRegistry>\n\t\t\t\t\t\t\t<token>9cbaf023786cd7...</token>\n\t\t\t\t\t\t</builderRegistry>\n\t\t\t\t\t</docker>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::docker-token-authentication[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/paketo-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::paketo[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<env>\n\t\t\t\t\t\t\t<HTTP_PROXY>http://proxy.example.com</HTTP_PROXY>\n\t\t\t\t\t\t\t<HTTPS_PROXY>https://proxy.example.com</HTTPS_PROXY>\n\t\t\t\t\t\t</env>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::paketo[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>packaging-oci-image</artifactId>\n\t<!-- ... -->\n\t<!-- tag::packaging-oci-image[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-image-no-fork</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::packaging-oci-image[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/packaging-oci-image/runtime-jvm-configuration-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::runtime-jvm-configuration[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<image>\n\t\t\t\t\t\t<env>\n\t\t\t\t\t\t\t<BPE_DELIM_JAVA_TOOL_OPTIONS xml:space=\"preserve\"> </BPE_DELIM_JAVA_TOOL_OPTIONS>\n\t\t\t\t\t\t\t<BPE_APPEND_JAVA_TOOL_OPTIONS>-XX:+HeapDumpOnOutOfMemoryError</BPE_APPEND_JAVA_TOOL_OPTIONS>\n\t\t\t\t\t\t</env>\n\t\t\t\t\t</image>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::runtime-jvm-configuration[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/active-profiles-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::active-profiles[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<profiles>\n\t\t\t\t\t\t<profile>local</profile>\n\t\t\t\t\t\t<profile>dev</profile>\n\t\t\t\t\t</profiles>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::active-profiles[] -->\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/application-arguments-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::application-arguments[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<arguments>\n\t\t\t\t\t\t<argument>property1</argument>\n\t\t\t\t\t\t<argument>property2=${my.value}</argument>\n\t\t\t\t\t</arguments>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::application-arguments[] -->\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/debug-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::debug[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<jvmArguments>\n\t\t\t\t\t\t-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005\n\t\t\t\t\t</jvmArguments>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::debug[] -->\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/devtools-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>running</artifactId>\n\t<!-- ... -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<!-- tag::devtools[] -->\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\t<!-- end::devtools[] -->\n\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/environment-variables-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::environment-variables[] -->\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<environmentVariables>\n\t\t\t\t\t\t<ENV1>5000</ENV1>\n\t\t\t\t\t\t<ENV2>Some Text</ENV2>\n\t\t\t\t\t\t<ENV3/>\n\t\t\t\t\t\t<ENV4></ENV4>\n\t\t\t\t\t</environmentVariables>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::environment-variables[] -->\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/hot-refresh-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>getting-started</artifactId>\n\t<!-- ... -->\n\t<!-- tag::hot-refresh[] -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<addResources>true</addResources>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<!-- end::hot-refresh[] -->\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/running/system-properties-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::system-properties[] -->\n<project>\n\t<build>\n\t\t<properties>\n\t\t\t<my.value>42</my.value>\n\t\t</properties>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<systemPropertyVariables>\n\t\t\t\t\t\t<property1>test</property1>\n\t\t\t\t\t\t<property2>${my.value}</property2>\n\t\t\t\t\t</systemPropertyVariables>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::system-properties[] -->\n\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/using/default-and-override-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- tag::default-and-override[] -->\n<project>\n\t<properties>\n\t\t<app.profiles>local,dev</app.profiles>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<profiles>${app.profiles}</profiles>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n<!-- end::default-and-override[] -->\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/using/different-versions-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>getting-started</artifactId>\n\t<!-- ... -->\n\t<!-- tag::different-versions[] -->\n\t<properties>\n\t\t<slf4j.version>1.7.30</slf4j.version>\n\t\t<spring-data-bom.version>2024.1.10</spring-data-bom.version>\n\t</properties>\n\t<!-- end::different-versions[] -->\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/using/no-starter-parent-override-dependencies-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>getting-started</artifactId>\n\t<!-- ... -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<!-- tag::no-starter-parent-override-dependencies[] -->\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<!-- Override SLF4J provided by Spring Boot -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t\t<version>1.7.30</version>\n\t\t\t</dependency>\n\t\t\t<!-- Override Spring Data release train provided by Spring Boot -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.data</groupId>\n\t\t\t\t<artifactId>spring-data-bom</artifactId>\n\t\t\t\t<version>2024.1.10</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-dependencies</artifactId>\n\t\t\t\t<version>{version-spring-boot}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\t<!-- end::no-starter-parent-override-dependencies[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/examples/using/no-starter-parent-pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>using</artifactId>\n\t<!-- ... -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\t<!-- tag::no-starter-parent[] -->\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<!-- Import dependency management from Spring Boot -->\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-dependencies</artifactId>\n\t\t\t\t<version>{version-spring-boot}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\t<!-- end::no-starter-parent[] -->\n</project>\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/aot.adoc",
    "content": "[[aot]]\n= Ahead-of-Time Processing\n\nSpring AOT is a process that analyzes your application at build-time and generate an optimized version of it.\nIt is a mandatory step to run a Spring `ApplicationContext` in a native image.\n\nNOTE: For an overview of GraalVM Native Images support in Spring Boot, check the xref:reference:packaging/native-image/index.adoc[reference documentation].\n\nThe Spring Boot Maven plugin offers goals that can be used to perform AOT processing on both application and test code.\n\n\n\n[[aot.processing-applications]]\n== Processing Applications\n\nTo configure your application to use this feature, add an execution for the `process-aot` goal, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot/pom.xml[tags=aot]\n----\n\nAs the `BeanFactory` is fully prepared at build-time, conditions are also evaluated.\nThis has an important difference compared to what a regular Spring Boot application does at runtime.\nFor instance, if you want to opt-in or opt-out for certain features, you need to configure the environment used at build time to do so.\nThe `process-aot` goal shares a number of properties with the xref:run.adoc[run goal] for that reason.\n\n\n\n[[aot.processing-applications.using-the-native-profile]]\n=== Using the Native Profile\n\nIf you use `spring-boot-starter-parent` as the `parent` of your project, a `native` profile can be used to streamline the steps required to build a native image.\n\nThe `native` profile configures the following:\n\n* Execution of `process-aot` when the Spring Boot Maven Plugin is applied on a project.\n* Suitable settings so that xref:build-image.adoc[build-image] generates a native image.\n* Sensible defaults for the {url-native-build-tools-docs-maven-plugin}[Native Build Tools Maven Plugin], in particular:\n** Making sure the plugin uses the raw classpath, and not the main jar file as it does not understand our repackaged jar format.\n** Validate that a suitable GraalVM version is available.\n** Download third-party reachability metadata.\n\n[WARNING]\n====\nThe use of the raw classpath means that native image does not know about the generated `MANIFEST.MF`.\nIf you need to read the content of the manifest in a native image, for instance to get the implementation version of your application, configure the `classesDirectory` option to use the regular jar.\n====\n\nTo benefit from the `native` profile, a module that represents an application should define two plugins, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot-native/pom.xml[tags=aot-native]\n----\n\nA single project can trigger the generation of a native image on the command-line using either xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.maven[Cloud Native Buildpacks] or xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.maven[Native Image Build Tools].\n\nTo use the `native` profile with a multi-modules project, you can create a customization of the `native` profile so that it invokes your preferred technique.\n\nTo bind Cloud Native Buildpacks during the `package` phase, add the following to the root POM of your multi-modules project:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot-native-profile-buildpacks/pom.xml[tags=profile]\n----\n\nThe example below does the same for Native Build Tools:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot-native-profile-nbt/pom.xml[tags=profile]\n----\n\nOnce the above is in place, you can build your multi-modules project and generate a native image in the relevant sub-modules, as shown in the following example:\n\n[source,shell]\n----\n$ mvn package -Pnative\n----\n\nNOTE: A \"relevant\" sub-module is a module that represents a Spring Boot application.\nSuch module must define the Native Build Tools and Spring Boot plugins as described above.\n\ninclude::partial$goals/process-aot.adoc[leveloffset=+1]\n\n\n\n[[aot.processing-tests]]\n== Processing Tests\n\nThe AOT engine can be applied to JUnit 5 tests that use Spring's Test Context Framework.\nThose tests are processed by the AOT engine and are then executed in a native image.\n\nNOTE: Tests are not processed when the regular tests are skipped using the `maven.test.skip` property.\n\nJust like <<aot.processing-applications.using-the-native-profile,for production code>>, the `spring-boot-starter-parent` defines a `nativeTest` profile that can be used to streamline the steps required to execute your tests in a native image.\n\nThe `nativeTest` profile configures the following:\n\n* Execution of `process-test-aot` when the Spring Boot Maven Plugin is applied on a project.\n* Execution of `test` when the {url-native-build-tools-docs-maven-plugin}[Native Build Tools Maven Plugin] is applied on a project.\nThe execution defines sensible defaults, in particular:\n** Making sure the plugin uses the raw classpath, and not the main jar file as it does not understand our repackaged jar format.\n** Validate that a suitable GraalVM version is available.\n** Download third-party reachability metadata.\n\nTo benefit from the `nativeTest` profile, a module that represents an application should define two plugins, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$aot-native/pom.xml[tags=aot-native]\n----\n\nOnce the above is in place for each module that needs this feature, you can build your multi-modules project and execute your tests in a native image in the relevant sub-modules, as shown in the following example:\n\n[source,shell]\n----\n$ mvn test -PnativeTest\n----\n\nNOTE: As with application AOT processing, the `BeanFactory` is fully prepared at build-time.\n\ninclude::partial$goals/process-test-aot.adoc[leveloffset=+1]\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-image.adoc",
    "content": "[[build-image]]\n= Packaging OCI Images\n\nThe plugin can create an https://github.com/opencontainers/image-spec[OCI image] from a jar or war file using https://buildpacks.io/[Cloud Native Buildpacks] (CNB).\nImages can be built on the command-line using the `build-image` goal.\nThis makes sure that the package lifecycle has run before the image is created.\n\nNOTE: For security reasons, images build and run as non-root users.\nSee the {url-buildpacks-docs}/reference/spec/platform-api/#users[CNB specification] for more details.\n\nThe easiest way to get started is to invoke `mvn spring-boot:build-image` on a project.\nIt is possible to automate the creation of an image whenever the `package` phase is invoked, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/pom.xml[tags=packaging-oci-image]\n----\n\nNOTE: Use `build-image-no-fork` when binding the goal to the package lifecycle.\nThis goal is similar to `build-image` but does not fork the lifecycle to make sure `package` has run.\nIn the rest of this section, `build-image` is used to refer to either the `build-image` or `build-image-no-fork` goals.\n\nTIP: While the buildpack runs from an xref:packaging.adoc[executable archive], it is not necessary to execute the `repackage` goal first as the executable archive is created automatically if necessary.\nWhen the `build-image` repackages the application, it applies the same settings as the `repackage` goal would, that is dependencies can be excluded using one of the exclude options.\nThe `spring-boot-devtools` and `spring-boot-docker-compose` modules are automatically excluded by default (you can control this using the `excludeDevtools` and `excludeDockerCompose` properties).\nPay also attention that optional dependencies are not included by default.\nIf you have defined those modules as optional, you also need to set the `includeOptional` property to `true`.\n\n\n\n[[build-image.docker-daemon]]\n== Docker Daemon\n\nThe `build-image` goal requires access to a Docker daemon.\nThe goal will inspect local Docker CLI https://docs.docker.com/engine/reference/commandline/cli/#configuration-files[configuration files] to determine the current https://docs.docker.com/engine/context/working-with-contexts/[context] and use the context connection information to communicate with a Docker daemon.\nIf the current context can not be determined or the context does not have connection information, then the goal will use a default local connection.\nThis works with https://docs.docker.com/install/[Docker Engine] on all supported platforms without configuration.\n\nEnvironment variables can be set to configure the `build-image` goal to use an alternative local or remote connection.\nThe following table shows the environment variables and their values:\n\n|===\n| Environment variable | Description\n\n| DOCKER_CONFIG\n| Location of Docker CLI https://docs.docker.com/engine/reference/commandline/cli/#configuration-files[configuration files] used to determine the current context (defaults to `$HOME/.docker`)\n\n| DOCKER_CONTEXT\n| Name of a https://docs.docker.com/engine/context/working-with-contexts/[context] that should be used to retrieve host information from Docker CLI configuration files (overrides `DOCKER_HOST`)\n\n| DOCKER_HOST\n| URL containing the host and port for the Docker daemon - for example `tcp://192.168.99.100:2376`\n\n| DOCKER_TLS_VERIFY\n| Enable secure HTTPS protocol when set to `1` (optional)\n\n| DOCKER_CERT_PATH\n| Path to certificate and key files for HTTPS (required if `DOCKER_TLS_VERIFY=1`, ignored otherwise)\n|===\n\nDocker daemon connection information can also be provided using `docker` parameters in the plugin configuration.\nThe following table summarizes the available parameters:\n\n|===\n| Parameter | Description\n\n| `context`\n| Name of a https://docs.docker.com/engine/context/working-with-contexts/[context] that should be used to retrieve host information from Docker CLI https://docs.docker.com/engine/reference/commandline/cli/#configuration-files[configuration files]\n\n| `host`\n| URL containing the host and port for the Docker daemon - for example `tcp://192.168.99.100:2376`\n\n| `tlsVerify`\n| Enable secure HTTPS protocol when set to `true` (optional)\n\n| `certPath`\n| Path to certificate and key files for HTTPS (required if `tlsVerify` is `true`, ignored otherwise)\n\n| `bindHostToBuilder`\n| When `true`, the value of the `host` property will be provided to the container that is created for the CNB builder (optional)\n|===\n\nFor more details, see also xref:build-image.adoc#build-image.examples.docker[examples].\n\n\n\n[[build-image.docker-registry]]\n== Docker Registry\n\nIf the Docker images specified by the `builder` or `runImage` parameters are stored in a private Docker image registry that requires authentication, the authentication credentials can be provided using `docker.builderRegistry` parameters.\n\nIf the generated Docker image is to be published to a Docker image registry, the authentication credentials can be provided using `docker.publishRegistry` parameters.\n\nParameters are provided for user authentication or identity token authentication.\nConsult the documentation for the Docker registry being used to store images for further information on supported authentication methods.\n\nThe following table summarizes the available parameters for `docker.builderRegistry` and `docker.publishRegistry`:\n\n|===\n| Parameter | Description\n\n| `username`\n| Username for the Docker image registry user. Required for user authentication.\n\n| `password`\n| Password for the Docker image registry user. Required for user authentication.\n\n| `url`\n| Address of the Docker image registry. Optional for user authentication.\n\n| `email`\n| E-mail address for the Docker image registry user. Optional for user authentication.\n\n| `token`\n| Identity token for the Docker image registry user. Required for token authentication.\n|===\n\nFor more details, see also xref:build-image.adoc#build-image.examples.docker[examples].\n\n[NOTE]\n====\nIf credentials are not provided, the plugin reads the user's existing Docker configuration file (typically located at `$HOME/.docker/config.json`) to determine authentication methods.\nUsing these methods, the plugin attempts to provide authentication credentials for the requested image.\n\nThe plugin supports the following authentication methods:\n\n- *Credential Helpers*: External tools configured in the Docker configuration file to provide credentials for specific registries. For example, tools like `osxkeychain` or `ecr-login` handle authentication for certain registries.\n- *Credential Store*: A default fallback mechanism that securely stores and retrieves credentials (e.g., `desktop` for Docker Desktop).\n- *Static Credentials*: Credentials that are stored directly in the Docker configuration file under the `auths` section.\n====\n\n\n\n[[build-image.customization]]\n== Image Customizations\n\nThe plugin invokes a {url-buildpacks-docs}/for-app-developers/concepts/builder/[builder] to orchestrate the generation of an image.\nThe builder includes multiple {url-buildpacks-docs}/for-app-developers/concepts/buildpack/[buildpacks] that can inspect the application to influence the generated image.\nBy default, the plugin chooses a builder image.\nThe name of the generated image is deduced from project properties.\n\nThe `image` parameter allows configuration of the builder and how it should operate on the project.\nThe following table summarizes the available parameters and their default values:\n\n[cols=\"1,4,1\"]\n|===\n| Parameter / (User Property)| Description | Default value\n\n| `builder` +\n(`spring-boot.build-image.builder`)\n| Name of the builder image to use.\n| `paketobuildpacks/builder-noble-java-tiny:latest`\n\n| `trustBuilder` +\n(`spring-boot.build-image.trustBuilder`)\n| Whether to treat the builder as {url-buildpacks-docs}/for-platform-operators/how-to/integrate-ci/pack/concepts/trusted_builders/#what-is-a-trusted-builder[trusted].\n| `true` if the builder is one of `paketobuildpacks/builder-noble-java-tiny`, `paketobuildpacks/builder-jammy-java-tiny`, `paketobuildpacks/builder-jammy-tiny`, `paketobuildpacks/builder-jammy-base`, `paketobuildpacks/builder-jammy-full`, `paketobuildpacks/builder-jammy-buildpackless-tiny`, `paketobuildpacks/builder-jammy-buildpackless-base`, `paketobuildpacks/builder-jammy-buildpackless-full`, `gcr.io/buildpacks/builder`, `heroku/builder`; `false` otherwise.\n\n| `imagePlatform` +\n(`spring-boot.build-image.imagePlatform`)\na|The platform (operating system and architecture) of any builder, run, and buildpack images that are pulled.\nMust be in the form of `OS[/architecture[/variant]]`, such as `linux/amd64`, `linux/arm64`, or `linux/arm/v5`.\nRefer to documentation of the builder being used to determine the image OS and architecture options available.\n| No default value, indicating that the platform of the host machine should be used.\n\n| `runImage` +\n(`spring-boot.build-image.runImage`)\n| Name of the run image to use.\n| No default value, indicating the run image specified in Builder metadata should be used.\n\n| `name` +\n(`spring-boot.build-image.imageName`)\n| javadoc:org.springframework.boot.buildpack.platform.docker.type.ImageName#of(java.lang.String)[Image name] for the generated image.\n| `docker.io/library/` +\n`${project.artifactId}:${project.version}`\n\n| `pullPolicy` +\n(`spring-boot.build-image.pullPolicy`)\n| javadoc:org.springframework.boot.buildpack.platform.build.PullPolicy[Policy] used to determine when to pull the builder and run images from the registry.\nAcceptable values are `ALWAYS`, `NEVER`, and `IF_NOT_PRESENT`.\n| `ALWAYS`\n\n| `env`\n| Environment variables that should be passed to the builder.\n|\n\n| `buildpacks`\na|Buildpacks that the builder should use when building the image.\nOnly the specified buildpacks will be used, overriding the default buildpacks included in the builder.\nBuildpack references must be in one of the following forms:\n\n* Buildpack in the builder - `[urn:cnb:builder:]<buildpack ID>[@<version>]`\n* Buildpack in a directory on the file system - `[file://]<path>`\n* Buildpack in a gzipped tar (.tgz) file on the file system - `[file://]<path>/<file name>`\n* Buildpack in an OCI image - `[docker://]<host>/<repo>[:<tag>][@<digest>]`\n| None, indicating the builder should use the buildpacks included in it.\n\n| `bindings`\na|https://docs.docker.com/storage/bind-mounts/[Volume bind mounts] that should be mounted to the builder container when building the image.\nThe bindings will be passed unparsed and unvalidated to Docker when creating the builder container.\nBindings must be in one of the following forms:\n\n* `<host source path>:<container destination path>[:<options>]`\n* `<host volume name>:<container destination path>[:<options>]`\n\nWhere `<options>` can contain:\n\n* `ro` to mount the volume as read-only in the container\n* `rw` to mount the volume as readable and writable in the container\n* `volume-opt=key=value` to specify key-value pairs consisting of an option name and its value\n|\n\n| `network` + (`spring-boot.build-image.network`)\n| The https://docs.docker.com/network/#network-drivers[network driver] the builder container will be configured to use.\nThe value supplied will be passed unvalidated to Docker when creating the builder container.\n|\n\n| `cleanCache` + (`spring-boot.build-image.cleanCache`)\n| Whether to clean the cache before building.\n| `false`\n\n| `verboseLogging`\n| Enables verbose logging of builder operations.\n| `false`\n\n| `publish` + (`spring-boot.build-image.publish`)\n| Whether to publish the generated image to a Docker registry.\n| `false`\n\n| `tags`\n| One or more additional tags to apply to the generated image.\nThe values provided to the `tags` option should be *full* image references.\nSee xref:build-image.adoc#build-image.customization.tags[the tags section] for more details.\n|\n\n| `buildWorkspace`\n| A temporary workspace that will be used by the builder and buildpacks to store files during image building.\nThe value can be a named volume or a bind mount location.\n| A named volume in the Docker daemon, with a name derived from the image name.\n\n| `buildCache`\n| A cache containing layers created by buildpacks and used by the image building process.\nThe value can be a named volume or a bind mount location.\n| A named volume in the Docker daemon, with a name derived from the image name.\n\n| `launchCache`\n| A cache containing layers created by buildpacks and used by the image launching process.\nThe value can be a named volume or a bind mount location.\n| A named volume in the Docker daemon, with a name derived from the image name.\n\n| `createdDate` +\n(`spring-boot.build-image.createdDate`)\n| A date that will be used to set the `Created` field in the generated image's metadata.\nThe value must be a string in the ISO 8601 instant format, or `now` to use the current date and time.\n| A fixed date that enables {url-buildpacks-docs}/for-app-developers/concepts/reproducibility/[build reproducibility].\n\n\n| `applicationDirectory` +\n(`spring-boot.build-image.applicationDirectory`)\n| The path to a directory that application contents will be uploaded to in the builder image.\nApplication contents will also be in this location in the generated image.\n| `/workspace`\n\n| `securityOptions`\n| https://docs.docker.com/reference/cli/docker/container/run/#security-opt[Security options] that will be applied to the builder container, provided as an array of string values\n| `[\"label=disable\"]` on Linux and macOS, `[]` on Windows\n\n|===\n\nNOTE: The plugin detects the target Java compatibility of the project using the compiler's plugin configuration or the `maven.compiler.target` property.\nWhen using the default Paketo builder and buildpacks, the plugin instructs the buildpacks to install the same Java version.\nYou can override this behaviour as shown in the xref:build-image.adoc#build-image.examples.builder-configuration[builder configuration] examples.\n\nFor more details, see also xref:build-image.adoc#build-image.examples[examples].\n\n\n\n[[build-image.customization.tags]]\n=== Tags Format\n\nThe values provided to the `tags` option should be *full* image references.\nThe accepted format is `[domainHost:port/][path/]name[:tag][@digest]`.\n\nIf the domain is missing, it defaults to `docker.io`.\nIf the path is missing, it defaults to `library`.\nIf the tag is missing, it defaults to `latest`.\n\nSome examples:\n\n* `my-image` leads to the image reference `docker.io/library/my-image:latest`\n* `my-repository/my-image` leads to `docker.io/my-repository/my-image:latest`\n* `example.com/my-repository/my-image:1.0.0` will be used as is\n\ninclude::partial$goals/build-image.adoc[leveloffset=+1]\ninclude::partial$goals/build-image-no-fork.adoc[leveloffset=+1]\n\n\n\n[[build-image.examples]]\n== Examples\n\n\n\n[[build-image.examples.custom-image-builder]]\n=== Custom Image Builder\n\nIf you need to customize the builder used to create the image or the run image used to launch the built image, configure the plugin as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/custom-image-builder-pom.xml[tags=custom-image-builder]\n----\n\nThis configuration will use a builder image with the name `mine/java-cnb-builder` and the tag `latest`, and the run image named `mine/java-cnb-run` and the tag `latest`.\n\nThe builder and run image can be specified on the command line as well, as shown in this example:\n\n[source,shell]\n----\n$ mvn spring-boot:build-image -Dspring-boot.build-image.builder=mine/java-cnb-builder -Dspring-boot.build-image.runImage=mine/java-cnb-run\n----\n\n\n\n[[build-image.examples.builder-configuration]]\n=== Builder Configuration\n\nIf the builder exposes configuration options using environment variables, those can be set using the `env` attributes.\n\nThe following is an example of {url-paketo-docs-java-buildpack}/#configuring-the-jvm-version[configuring the JVM version] used by the Paketo Java buildpacks at build time:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/build-image-example-builder-configuration-pom.xml[tags=build-image-example-builder-configuration]\n----\n\nIf there is a network proxy between the Docker daemon the builder runs in and network locations that buildpacks download artifacts from, you will need to configure the builder to use the proxy.\nWhen using the Paketo builder, this can be accomplished by setting the `HTTPS_PROXY` and/or `HTTP_PROXY` environment variables as show in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/paketo-pom.xml[tags=paketo]\n----\n\n\n\n[[build-image.examples.runtime-jvm-configuration]]\n=== Runtime JVM Configuration\n\nPaketo Java buildpacks {url-paketo-docs-java-buildpack}/#runtime-jvm-configuration[configure the JVM runtime environment] by setting the `JAVA_TOOL_OPTIONS` environment variable.\nThe buildpack-provided `JAVA_TOOL_OPTIONS` value can be modified to customize JVM runtime behavior when the application image is launched in a container.\n\nEnvironment variable modifications that should be stored in the image and applied to every deployment can be set as described in the {url-paketo-docs}/buildpacks/configuration/#environment-variables[Paketo documentation] and shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/runtime-jvm-configuration-pom.xml[tags=runtime-jvm-configuration]\n----\n\n\n\n[[build-image.examples.custom-image-name]]\n=== Custom Image Name\n\nBy default, the image name is inferred from the `artifactId` and the `version` of the project, something like `docker.io/library/${project.artifactId}:${project.version}`.\nYou can take control over the name, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/custom-image-name-pom.xml[tags=custom-image-name]\n----\n\nNOTE: This configuration does not provide an explicit tag so `latest` is used.\nIt is possible to specify a tag as well, either using `${project.version}`, any property available in the build or a hardcoded version.\n\nThe image name can be specified on the command line as well, as shown in this example:\n\n[source,shell]\n----\n$ mvn spring-boot:build-image -Dspring-boot.build-image.imageName=example.com/library/my-app:v1\n----\n\n\n\n[[build-image.examples.buildpacks]]\n=== Buildpacks\n\nBy default, the builder will use buildpacks included in the builder image and apply them in a pre-defined order.\nAn alternative set of buildpacks can be provided to apply buildpacks that are not included in the builder, or to change the order of included buildpacks.\nWhen one or more buildpacks are provided, only the specified buildpacks will be applied.\n\nThe following example instructs the builder to use a custom buildpack packaged in a `.tgz` file, followed by a buildpack included in the builder.\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/buildpacks-pom.xml[tags=buildpacks]\n----\n\nBuildpacks can be specified in any of the forms shown below.\n\nA buildpack located in a CNB Builder (version may be omitted if there is only one buildpack in the builder matching the `buildpack-id`):\n\n* `urn:cnb:builder:buildpack-id`\n* `urn:cnb:builder:buildpack-id@0.0.1`\n* `buildpack-id`\n* `buildpack-id@0.0.1`\n\nA path to a directory containing buildpack content (not supported on Windows):\n\n* `\\file:///path/to/buildpack/`\n* `/path/to/buildpack/`\n\nA path to a gzipped tar file containing buildpack content:\n\n* `\\file:///path/to/buildpack.tgz`\n* `/path/to/buildpack.tgz`\n\nAn OCI image containing a {url-buildpacks-docs}/for-buildpack-authors/how-to/distribute-buildpacks/package-buildpack/[packaged buildpack]:\n\n* `docker://example/buildpack`\n* `docker:///example/buildpack:latest`\n* `docker:///example/buildpack@sha256:45b23dee08...`\n* `example/buildpack`\n* `example/buildpack:latest`\n* `example/buildpack@sha256:45b23dee08...`\n\n\n\n[[build-image.examples.publish]]\n=== Image Publishing\n\nThe generated image can be published to a Docker registry by enabling a `publish` option.\n\nIf the Docker registry requires authentication, the credentials can be configured using `docker.publishRegistry` parameters.\nIf the Docker registry does not require authentication, the `docker.publishRegistry` configuration can be omitted.\n\nNOTE: The registry that the image will be published to is determined by the registry part of the image name (`docker.example.com` in these examples).\nIf `docker.publishRegistry` credentials are configured and include a `url` parameter, this value is passed to the registry but is not used to determine the publishing registry location.\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-pom.xml[tags=docker]\n----\n\nThe `publish` option can be specified on the command line as well, as shown in this example:\n\n[source,shell]\n----\n$ mvn spring-boot:build-image -Dspring-boot.build-image.imageName=docker.example.com/library/my-app:v1 -Dspring-boot.build-image.publish=true\n----\n\nWhen using the `publish` option on the command line with authentication, you can provide credentials using properties as in this example:\n\n[source,shell]\n----\n$ mvn spring-boot:build-image \\\n      -Ddocker.publishRegistry.username=user \\\n      -Ddocker.publishRegistry.password=secret \\\n      -Ddocker.publishRegistry.url=docker.example.com \\\n      -Dspring-boot.build-image.publish=true \\\n      -Dspring-boot.build-image.imageName=docker.example.com/library/my-app:v1\n----\n\nand reference the properties in the XML configuration:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-pom-authentication-command-line.xml[tags=docker]\n----\n\n\n\n[[build-image.examples.caches]]\n=== Builder Cache and Workspace Configuration\n\nThe CNB builder caches layers that are used when building and launching an image.\nBy default, these caches are stored as named volumes in the Docker daemon with names that are derived from the full name of the target image.\nIf the image name changes frequently, for example when the project version is used as a tag in the image name, then the caches can be invalidated frequently.\n\nThe cache volumes can be configured to use alternative names to give more control over cache lifecycle as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/caches-pom.xml[tags=caches]\n----\n\nBuilders and buildpacks need a location to store temporary files during image building.\nBy default, this temporary build workspace is stored in a named volume.\n\nThe caches and the build workspace can be configured to use bind mounts instead of named volumes, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/bind-caches-pom.xml[tags=caches]\n----\n\n\n\n[[build-image.examples.docker]]\n=== Docker Configuration\n\n\n\n[[build-image.examples.docker.minikube]]\n==== Docker Configuration for minikube\n\nThe plugin can communicate with the https://minikube.sigs.k8s.io/docs/tasks/docker_daemon/[Docker daemon provided by minikube] instead of the default local connection.\n\nOn Linux and macOS, environment variables can be set using the command `eval $(minikube docker-env)` after minikube has been started.\n\nThe plugin can also be configured to use the minikube daemon by providing connection details similar to those shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-minikube-pom.xml[tags=docker-minikube]\n----\n\n\n\n[[build-image.examples.docker.podman]]\n==== Docker Configuration for podman\n\nThe plugin can communicate with a https://podman.io/[podman container engine].\n\nThe plugin can be configured to use podman local connection by providing connection details similar to those shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-podman-pom.xml[tags=docker-podman]\n----\n\nTIP: With the `colima` CLI installed, the command `podman info --format='{{.Host.RemoteSocket.Path}}'` can be used to get the value for the `docker.host` configuration property shown in this example.\n\n\n\n[[build-image.examples.docker.colima]]\n==== Docker Configuration for Colima\n\nThe plugin can communicate with the Docker daemon provided by https://github.com/abiosoft/colima[Colima].\nThe `DOCKER_HOST` environment variable can be set by using the following command:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ export DOCKER_HOST=$(docker context inspect colima -f '{{.Endpoints.docker.Host}}')\n----\n\nThe plugin can also be configured to use Colima daemon by providing connection details similar to those shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-colima-pom.xml[tags=docker-colima]\n----\n\n\n\n[[build-image.examples.docker.auth]]\n==== Docker Configuration for Authentication\n\nIf the builder or run image are stored in a private Docker registry that supports user authentication, authentication details can be provided using `docker.builderRegistry` parameters as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-registry-authentication-pom.xml[tags=docker-registry-authentication]\n----\n\nIf the builder or run image is stored in a private Docker registry that supports token authentication, the token value can be provided using `docker.builderRegistry` parameters as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging-oci-image/docker-token-authentication-pom.xml[tags=docker-token-authentication]\n----\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/build-info.adoc",
    "content": "[[build-info]]\n= Integrating with Actuator\n\nSpring Boot Actuator displays build-related information if a `META-INF/build-info.properties` file is present.\nThe `build-info` goal generates such file with the coordinates of the project and the build time.\nIt also allows you to add an arbitrary number of additional properties, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$build-info/pom.xml[tags=build-info]\n----\n\nThis configuration will generate a `build-info.properties` at the expected location with three additional keys.\n\nNOTE: `java.version` is expected to be a regular property available in the project.\nIt will be interpolated as you would expect.\n\ninclude::partial$goals/build-info.adoc[leveloffset=+1]\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/getting-started.adoc",
    "content": "[[getting-started]]\n= Getting Started\n\nTo use the Spring Boot Maven Plugin, include the appropriate XML in the `plugins` section of your `pom.xml`, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/pom.xml[tags=getting-started]\n----\n\nifeval::[\"{build-type}\" == \"commercial\"]\nThe plugin is published to the Spring Commercial repository.\nYou will have to configure your build to access this repository.\nThis is usually done through a local artifact repository that mirrors the content of the Spring Commercial repository.\nAlternatively, while it is not recommended, the Spring Commercial repository can also be accessed directly.\nIn either case, see https://docs.vmware.com/en/Tanzu-Spring-Runtime/Commercial/Tanzu-Spring-Runtime/spring-enterprise-subscription.html[the Tanzu Spring Runtime documentation] for further details.\nendif::[]\n\nifeval::[\"{build-type}\" == \"opensource\"]\nIf you use a milestone or snapshot release, you also need to add the appropriate `pluginRepository` elements, as shown in the following listing:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$getting-started/plugin-repositories-pom.xml[tags=plugin-repositories]\n----\nendif::[]\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/goals.adoc",
    "content": "[[goals]]\n= Goals\n\nThe Spring Boot Plugin has the following goals:\n\ninclude::partial$goals/overview.adoc[]\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/help.adoc",
    "content": "[[help]]\n= Help Information\nThe `help` goal is a standard goal that  displays information on the capabilities of the plugin.\n\ninclude::partial$goals/help.adoc[leveloffset=+1]\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/index.adoc",
    "content": "[[maven-plugin]]\n= Maven Plugin\n\nThe Spring Boot Maven Plugin provides Spring Boot support in https://maven.org[Apache Maven].\nIt allows you to package executable jar or war archives, run Spring Boot applications, generate build information and start your Spring Boot application prior to running integration tests.\n\nTo use it, you must use Maven 3.6.3 or later.\n\nIn addition to this user guide, xref:api/java/index.html[API documentation] is also available.\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/integration-tests.adoc",
    "content": "[[integration-tests]]\n= Running Integration Tests\n\nWhile you may start your Spring Boot application very easily from your test (or test suite) itself, it may be desirable to handle that in the build itself.\nTo make sure that the lifecycle of your Spring Boot application is properly managed around your integration tests, you can use the `start` and `stop` goals, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integration-tests/pom.xml[tags=integration-tests]\n----\n\nSuch setup can now use the https://maven.apache.org/surefire/maven-failsafe-plugin[failsafe-plugin] to run your integration tests as you would expect.\n\nNOTE: The application is started in a separate process and JMX is used to communicate with the application.\nBy default, the plugin uses port `9001`.\nIf you need to configure the JMX port, see xref:integration-tests.adoc#integration-tests.examples.jmx-port[the dedicated example].\n\nYou could also configure a more advanced setup to skip the integration tests when a specific property has been set, see xref:integration-tests.adoc#integration-tests.examples.skip[the dedicated example].\n\n\n\n[[integration-tests.no-starter-parent]]\n== Using Failsafe Without Spring Boot's Parent POM\n\nSpring Boot's Parent POM, `spring-boot-starter-parent`, configures Failsafe's `<classesDirectory>` to be `${project.build.outputDirectory}`.\nWithout this configuration, which causes Failsafe to use the compiled classes rather than the repackaged jar, Failsafe cannot load your application's classes.\nIf you are not using the parent POM, you should configure Failsafe in the same way, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integration-tests/failsafe-pom.xml[tags=failsafe]\n----\n\ninclude::partial$goals/start.adoc[leveloffset=+1]\n\ninclude::partial$goals/stop.adoc[leveloffset=+1]\n\n\n\n[[integration-tests.examples]]\n== Examples\n\n\n\n[[integration-tests.examples.random-port]]\n=== Random Port for Integration Tests\n\nOne nice feature of the Spring Boot test integration is that it can allocate a free port for the web application.\nWhen the `start` goal of the plugin is used, the Spring Boot application is started separately, making it difficult to pass the actual port to the integration test itself.\n\nThe example below showcases how you could achieve the same feature using the https://www.mojohaus.org/build-helper-maven-plugin[Build Helper Maven Plugin]:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integration-tests/random-port-pom.xml[tags=random-port]\n----\n\nYou can now retrieve the `test.server.port` system property in any of your integration test to create a proper `URL` to the server.\n\n\n\n[[integration-tests.examples.jmx-port]]\n=== Customize JMX Port\n\nThe `jmxPort` property allows to customize the port the plugin uses to communicate with the Spring Boot application.\n\nThis example shows how you can customize the port in case `9001` is already used:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integration-tests/customize-jmx-port-pom.xml[tags=customize-jmx-port]\n----\n\nTIP: If you need to configure the JMX port, make sure to do so in the global configuration as shown above so that it is shared by both goals.\n\n\n\n[[integration-tests.examples.skip]]\n=== Skip Integration Tests\n\nThe `skip` property allows to skip the execution of the Spring Boot maven plugin altogether.\n\nThis example shows how you can skip integration tests with a command-line property and still make sure that the `repackage` goal runs:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$integration-tests/skip-integration-tests-pom.xml[tags=skip-integration-tests]\n----\n\nBy default, the integration tests will run but this setup allows you to easily disable them on the command-line as follows:\n\n[source,shell]\n----\n$ mvn verify -Dskip.it=true\n----\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/packaging.adoc",
    "content": "[[packaging]]\n= Packaging Executable Archives\n\nThe plugin can create executable archives (jar files and war files) that contain all of an application's dependencies and can then be run with `java -jar`.\n\nPackaging an executable archive is performed by the `repackage` goal, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/repackage-pom.xml[tags=repackage]\n----\n\nWARNING: The `repackage` goal is not meant to be used alone on the command-line as it operates on the source\n`jar` (or `war`) produced by the `package` phase.\nTo use this goal on the command-line, you must include the `package` phase: `mvn package spring-boot:repackage`.\n\nTIP: If you are using `spring-boot-starter-parent`, such execution is already pre-configured with a `repackage` execution ID so that only the plugin definition should be added.\n\nThe example above repackages a `jar` or `war` archive that is built during the package phase of the Maven lifecycle, including any `provided` dependencies that are defined in the project.\nIf some of these dependencies need to be excluded, you can use one of the `exclude` options; see the xref:packaging.adoc#packaging.examples.exclude-dependency[dependency exclusion] for more details.\n\nThe original (that is non-executable) artifact is renamed to `.original` by default but it is also possible to keep the original artifact using a custom classifier.\n\nNOTE: The `outputFileNameMapping` feature of the `maven-war-plugin` is currently not supported.\n\nThe `spring-boot-devtools` and `spring-boot-docker-compose` modules are automatically excluded by default (you can control this using the `excludeDevtools` and `excludeDockerCompose` properties).\nIn order to make that work with `war` packaging, the `spring-boot-devtools` and `spring-boot-docker-compose` dependencies must be set as `optional` or with the `provided` scope.\nPay also attention that optional dependencies are not included by default.\nIf you have defined those modules as optional, you also need to set the `includeOptional` property to `true`.\n\nThe plugin rewrites your manifest, and in particular it manages the `Main-Class` and `Start-Class` entries.\nIf the defaults don't work you have to configure the values in the Spring Boot plugin, not in the jar plugin.\nThe `Main-Class` in the manifest is controlled by the `layout` property of the Spring Boot plugin, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/non-default-pom.xml[tags=non-default]\n----\n\nThe `layout` property defaults to a value determined by the archive type (`jar` or `war`). The following layouts are available:\n\n* `JAR`: regular executable JAR layout.\n* `WAR`: executable WAR layout. `provided` dependencies are placed in `WEB-INF/lib-provided` to avoid any clash when the `war` is deployed in a servlet container.\n* `ZIP` (alias to `DIR`): similar to the `JAR` layout using `PropertiesLauncher`.\n* `NONE`: Bundle all dependencies and project resources. Does not bundle a bootstrap loader.\n\n\n\n[[packaging.layers]]\n== Layered Jar or War\n\nA repackaged jar contains the application's classes and dependencies in `BOOT-INF/classes` and `BOOT-INF/lib` respectively.\nSimilarly, an executable war contains the application's classes in `WEB-INF/classes` and dependencies in `WEB-INF/lib` and `WEB-INF/lib-provided`.\nFor cases where a docker image needs to be built from the contents of a jar or war, it's useful to be able to separate these directories further so that they can be written into distinct layers.\n\nLayered archives use the same layout as a regular repackaged jar or war, but include an additional meta-data file that describes each layer.\n\nBy default, the following layers are defined:\n\n* `dependencies` for any dependency whose version does not contain `SNAPSHOT`.\n* `spring-boot-loader` for the loader classes.\n* `snapshot-dependencies` for any dependency whose version contains `SNAPSHOT`.\n* `application` for local module dependencies, application classes, and resources.\n\nModule dependencies are identified by looking at all of the modules that are part of the current build.\nIf a module dependency can only be resolved because it has been installed into Maven's local cache and it is not part of the current build, it will be identified as regular dependency.\n\nThe layers order is important as it determines how likely previous layers can be cached when part of the application changes.\nThe default order is `dependencies`, `spring-boot-loader`, `snapshot-dependencies`, `application`.\nContent that is least likely to change should be added first, followed by layers that are more likely to change.\n\nThe repackaged archive includes the `layers.idx` file by default.\nTo disable this feature, you can do so in the following manner:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/disable-layers-pom.xml[tags=disable-layers]\n----\n\n\n\n[[packaging.layers.configuration]]\n=== Custom Layers Configuration\n\nDepending on your application, you may want to tune how layers are created and add new ones.\nThis can be done using a configuration loaded from a file or from the classpath.\n\nTo use a configuration file, register it as shown below:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/custom-layers-pom.xml[tags=custom-layers]\n----\n\nAlternatively, the configuration can be loaded from the classpath by specifying its name.\nA matching file is expected at `META-INF/spring/layers/<name>.xml` on the plugin's classpath.\nThe jar that contains the configuration can be added as a plugin dependency, as shown below:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/custom-layers-classpath-pom.xml[tags=custom-layers-classpath]\n----\n\nIn the example above, `META-INF/spring/layers/custom.xml` is expected to be available on the plugin's classpath.\n\nThe configuration file describes how an archive can be separated into layers, and the order of those layers.\nThe following example shows how the default ordering described above can be defined explicitly:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/layers.xml[tags=layers]\n----\n\nThe `layers` XML format is defined in three sections:\n\n* The `<application>` block defines how the application classes and resources should be layered.\n* The `<dependencies>` block defines how dependencies should be layered.\n* The `<layerOrder>` block defines the order that the layers should be written.\n\nNested `<into>` blocks are used within `<application>` and `<dependencies>` sections to claim content for a layer.\nThe blocks are evaluated in the order that they are defined, from top to bottom.\nAny content not claimed by an earlier block remains available for subsequent blocks to consider.\n\nThe `<into>` block claims content using nested `<include>` and `<exclude>` elements.\nThe `<application>` section uses Ant-style path matching for include/exclude expressions.\nThe `<dependencies>` section uses `group:artifact[:version]` patterns.\nIt also provides `<includeModuleDependencies />` and `<excludeModuleDependencies />` elements that can be used to include or exclude local module dependencies.\n\nIf no `<include>` is defined, then all content (not claimed by an earlier block) is considered.\n\nIf no `<exclude>` is defined, then no exclusions are applied.\n\nLooking at the `<dependencies>` example above, we can see that the first `<into>` will claim all module dependencies for the `application.layer`.\nThe next `<into>` will claim all SNAPSHOT dependencies for the `snapshot-dependencies` layer.\nThe final `<into>` will claim anything left (in this case, any dependency that is not a SNAPSHOT) for the `dependencies` layer.\n\nThe `<application>` block has similar rules.\nFirst claiming `org/springframework/boot/loader/**` content for the `spring-boot-loader` layer.\nThen claiming any remaining classes and resources for the `application` layer.\n\nNOTE: The order that `<into>` blocks are defined is often different from the order that the layers are written.\nFor this reason the `<layerOrder>` element must always be included and _must_ cover all layers referenced by the `<into>` blocks.\n\ninclude::partial$goals/repackage.adoc[leveloffset=+1]\n\n\n\n[[packaging.examples]]\n== Examples\n\n\n\n[[packaging.examples.custom-classifier]]\n=== Custom Classifier\n\nBy default, the `repackage` goal replaces the original artifact with the repackaged one.\nThat is a sane behavior for modules that represent an application but if your module is used as a dependency of another module, you need to provide a classifier for the repackaged one.\nThe reason for that is that application classes are packaged in `BOOT-INF/classes` so that the dependent module cannot load a repackaged jar's classes.\n\nIf that is the case or if you prefer to keep the original artifact and attach the repackaged one with a different classifier, configure the plugin as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/different-classifier-pom.xml[tags=different-classifier]\n----\n\nIf you are using `spring-boot-starter-parent`, the `repackage` goal is executed automatically in an execution with id `repackage`.\nIn that setup, only the configuration should be specified, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/repackage-configuration-pom.xml[tags=repackage-configuration]\n----\n\nThis configuration will generate two artifacts: the original one and the repackaged counter part produced by the repackage goal.\nBoth will be installed/deployed transparently.\n\nYou can also use the same configuration if you want to repackage a secondary artifact the same way the main artifact is replaced.\nThe following configuration installs/deploys a single `task` classified artifact with the repackaged application:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/classified-artifact-pom.xml[tags=classified-artifact]\n----\n\nAs both the `maven-jar-plugin` and the `spring-boot-maven-plugin` run at the same phase, it is important that the jar plugin is defined first (so that it runs before the repackage goal).\nAgain, if you are using `spring-boot-starter-parent`, this can be simplified as follows:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/jar-plugin-first-pom.xml[tags=jar-plugin-first]\n----\n\n\n\n[[packaging.examples.custom-name]]\n=== Custom Name\n\nIf you need the repackaged jar to have a different local name than the one defined by the `artifactId` attribute of the project, use the standard `finalName`, as shown in the following example:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/custom-name-pom.xml[tags=custom-name]\n----\n\nThis configuration will generate the repackaged artifact in `target/my-app.jar`.\n\n\n\n[[packaging.examples.local-artifact]]\n=== Local Repackaged Artifact\n\nBy default, the `repackage` goal replaces the original artifact with the executable one.\nIf you need to only deploy the original jar and yet be able to run your app with the regular file name, configure the plugin as follows:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/local-repackaged-artifact-pom.xml[tags=local-repackaged-artifact]\n----\n\nThis configuration generates two artifacts: the original one and the executable counter part produced by the `repackage` goal.\nOnly the original one will be installed/deployed.\n\n\n\n[[packaging.examples.custom-layout]]\n=== Custom Layout\n\nSpring Boot repackages the jar file for this project using a custom layout factory defined in the additional jar file, provided as a dependency to the build plugin:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/custom-layout-pom.xml[tags=custom-layout]\n----\n\nThe layout factory is provided as an implementation of `LayoutFactory` (from `spring-boot-loader-tools`) explicitly specified in the pom.\nIf there is only one custom `LayoutFactory` on the plugin classpath and it is listed in `META-INF/spring.factories` then it is unnecessary to explicitly set it in the plugin configuration.\n\nLayout factories are always ignored if an explicit xref:#packaging.repackage-goal.parameter-details.layout-factory[layout] is set.\n\n\n\n[[packaging.examples.exclude-dependency]]\n=== Dependency Exclusion\n\nBy default, both the `repackage` and the `run` goals will include any `provided` dependencies that are defined in the project.\nA Spring Boot project should consider `provided` dependencies as \"container\" dependencies that are required to run the application.\nGenerally speaking, Spring Boot projects are not used as dependencies and are therefore unlikely to have any `optional` dependencies.\nWhen a project does have optional dependencies they too will be included by the `repackage` and `run` goals.\n\nSome of these dependencies may not be required at all and should be excluded from the executable jar.\nFor consistency, they should not be present either when running the application.\n\nThere are two ways one can exclude a dependency from being packaged/used at runtime:\n\n* Exclude a specific artifact identified by `groupId` and `artifactId`, optionally with a `classifier` if needed.\n* Exclude any artifact belonging to a given `groupId`.\n\nThe following example excludes `com.example:module1`, and only that artifact:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/exclude-artifact-pom.xml[tags=exclude-artifact]\n----\n\nThis example excludes any artifact belonging to the `com.example` group:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/exclude-artifact-group-pom.xml[tags=exclude-artifact-group]\n----\n\n\n\n[[packaging.examples.layered-archive-tools]]\n=== JAR Tools\n\nWhen a layered jar or war is created, the `spring-boot-jarmode-tools` jar will be added as a dependency to your archive.\nWith this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers.\nIf you wish to exclude this dependency, you can do so in the following manner:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/exclude-dependency-pom.xml[tags=exclude-dependency]\n----\n\n\n\n[[packaging.examples.custom-layers-configuration]]\n=== Custom Layers Configuration\n\nThe default setup splits dependencies into snapshot and non-snapshot, however, you may have more complex rules.\nFor example, you may want to isolate company-specific dependencies of your project in a dedicated layer.\nThe following `layers.xml` configuration shown one such setup:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$packaging/layers-configuration.xml[tags=layers-configuration]\n----\n\nThe configuration above creates an additional `company-dependencies` layer with all libraries with the `com.acme` groupId.\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/run.adoc",
    "content": "[[run]]\n= Running your Application with Maven\n\nThe plugin includes a run goal which can be used to launch your application from the command line, as shown in the following example:\n\n[source,shell]\n----\n$ mvn spring-boot:run\n----\n\nApplication arguments can be specified using the `arguments` parameter, see xref:run.adoc#run.examples.using-application-arguments[using application arguments] for more details.\n\nThe application is executed in a forked process and setting properties on the command-line will not affect the application.\nIf you need to specify some JVM arguments (that is for debugging purposes), you can use the `jvmArguments` parameter, see xref:run.adoc#run.examples.debug[Debug the application] for more details.\nThere is also explicit support for xref:run.adoc#run.examples.system-properties[system properties] and xref:run.adoc#run.examples.environment-variables[environment variables].\n\nAs enabling a profile is quite common, there is dedicated `profiles` property that offers a shortcut for `-Dspring-boot.run.jvmArguments=\"-Dspring.profiles.active=dev\"`, see xref:run.adoc#run.examples.specify-active-profiles[Specify active profiles].\n\nSpring Boot `devtools` is a module to improve the development-time experience when working on Spring Boot applications.\nTo enable it, just add the following dependency to your project:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/devtools-pom.xml[tags=devtools]\n----\n\nWhen `devtools` is running, it detects changes when you recompile your application and automatically refreshes it.\nThis works for not only resources but code as well.\nIt also provides a LiveReload server so that it can automatically trigger a browser refresh whenever things change.\n\nDevtools can also be configured to only refresh the browser whenever a static resource has changed (and ignore any change in the code).\nJust include the following property in your project:\n\n[source,properties]\n----\nspring.devtools.remote.restart.enabled=false\n----\n\nPrior to `devtools`, the plugin supported hot refreshing of resources by default which has now been disabled in favour of the solution described above.\nYou can restore it at any time by configuring your project:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/hot-refresh-pom.xml[tags=hot-refresh]\n----\n\nWhen `addResources` is enabled, any `src/main/resources` directory will be added to the application classpath when you run the application and any duplicate found in the classes output will be removed.\nThis allows hot refreshing of resources which can be very useful when developing web applications.\nFor example, you can work on HTML, CSS or JavaScript files and see your changes immediately without recompiling your application.\nIt is also a helpful way of allowing your front end developers to work without needing to download and install a Java IDE.\n\nNOTE: A side effect of using this feature is that filtering of resources at build time will not work.\n\nIn order to be consistent with the `repackage` goal, the `run` goal builds the classpath in such a way that any dependency that is excluded in the plugin's configuration gets excluded from the classpath as well.\nFor more details, see xref:packaging.adoc#packaging.examples.exclude-dependency[the dedicated example].\n\nSometimes it is useful to run a test variant of your application.\nFor example, if you want to xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[use Testcontainers at development time] or make use of some test stubs.\nUse the `test-run` goal with many of the same features and configuration options as `run` for this purpose.\n\ninclude::partial$goals/run.adoc[leveloffset=+1]\n\ninclude::partial$goals/test-run.adoc[leveloffset=+1]\n\n\n\n[[run.examples]]\n== Examples\n\n\n\n[[run.examples.debug]]\n=== Debug the Application\n\nThe `run` and `test-run` goals run your application in a forked process.\nIf you need to debug it, you should add the necessary JVM arguments to enable remote debugging.\nThe following configuration suspend the process until a debugger has joined on port 5005:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/debug-pom.xml[tags=debug]\n----\n\nThese arguments can be specified on the command line as well:\n\n[source,shell]\n----\n$ mvn spring-boot:run -Dspring-boot.run.jvmArguments=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005\n----\n\n\n\n[[run.examples.system-properties]]\n=== Using System Properties\n\nSystem properties can be specified using the `systemPropertyVariables` attribute.\nThe following example sets `property1` to `test` and `property2` to 42:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/system-properties-pom.xml[tags=system-properties]\n----\n\nIf the value is empty or not defined (that is `<my-property/`>), the system property is set with an empty String as the value.\nMaven trims values specified in the pom, so it is not possible to specify a System property which needs to start or end with a space through this mechanism: consider using `jvmArguments` instead.\n\nAny String typed Maven variable can be passed as system properties.\nAny attempt to pass any other Maven variable type (for example a `List` or a `URL` variable) will cause the variable expression to be passed literally (unevaluated).\n\nThe `jvmArguments` parameter takes precedence over system properties defined with the mechanism above.\nIn the following example, the value for `property1` is `overridden`:\n\n[source,shell]\n----\n$ mvn spring-boot:run -Dspring-boot.run.jvmArguments=\"-Dproperty1=overridden\"\n----\n\n\n\n[[run.examples.environment-variables]]\n=== Using Environment Variables\n\nEnvironment variables can be specified using the `environmentVariables` attribute.\nThe following example sets the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/environment-variables-pom.xml[tags=environment-variables]\n----\n\nIf the value is empty or not defined (that is `<MY_ENV/`>), the env variable is set with an empty String as the value.\nMaven trims values specified in the pom so it is not possible to specify an env variable which needs to start or end with a space.\n\nAny String typed Maven variable can be passed as system properties.\nAny attempt to pass any other Maven variable type (for example a `List` or a `URL` variable) will cause the variable expression to be passed literally (unevaluated).\n\nEnvironment variables defined this way take precedence over existing values.\n\n\n\n[[run.examples.using-application-arguments]]\n=== Using Application Arguments\n\nApplication arguments can be specified using the `arguments` attribute.\nThe following example sets two arguments: `property1` and `property2=42`:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/application-arguments-pom.xml[tags=application-arguments]\n----\n\nOn the command-line, arguments are separated by a space the same way `jvmArguments` are.\nIf an argument contains a space, make sure to quote it.\nIn the following example, two arguments are available: `property1` and `property2=Hello World`:\n\n[source,shell]\n----\n$ mvn spring-boot:run -Dspring-boot.run.arguments=\"property1 'property2=Hello World'\"\n----\n\n\n\n[[run.examples.specify-active-profiles]]\n=== Specify Active Profiles\n\nThe active profiles to use for a particular application can be specified using the `profiles` argument.\n\nThe following configuration enables the `local` and `dev` profiles:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$running/active-profiles-pom.xml[tags=active-profiles]\n----\n\nThe profiles to enable can be specified on the command line as well, make sure to separate them with a comma, as shown in the following example:\n\n[source,shell]\n----\n$ mvn spring-boot:run -Dspring-boot.run.profiles=local,dev\n----\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/pages/using.adoc",
    "content": "[[using]]\n= Using the Plugin\n\nMaven users can inherit from the `spring-boot-starter-parent` project to obtain sensible defaults.\nThe parent project provides the following features:\n\n* Java 17 as the default compiler level.\n* UTF-8 source encoding.\n* Compilation with `-parameters`.\n* A dependency management section, inherited from the `spring-boot-dependencies` POM, that manages the versions of common dependencies.\nThis dependency management lets you omit `<version>` tags for those dependencies when used in your own POM.\n* An execution of the xref:maven-plugin:packaging.adoc#packaging.repackage-goal[`repackage` goal] with a `repackage` execution id.\n* A `native` profile that configures the build to be able to generate a Native image.\n* Sensible https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html[resource filtering].\n* Sensible plugin configuration ({url-git-commit-id-maven-plugin}[`Git Commit Id Plugin`], and https://maven.apache.org/plugins/maven-shade-plugin/[shade]).\n* Sensible resource filtering for `application.properties` and `application.yml` including profile-specific files (for example, `application-dev.properties` and `application-dev.yml`)\n\nNOTE: Since the `application.properties` and `application.yml` files accept Spring style placeholders (`${...}`), the Maven filtering is changed to use `@..@` placeholders.\n(You can override that by setting a Maven property called `resource.delimiter`.)\n\n[NOTE]\n====\nThe `spring-boot-starter-parent` sets the `maven.compiler.release` property, which restricts the `--add-exports`, `--add-reads`, and `--patch-module` options https://openjdk.org/jeps/247[if they modify system modules].\nIn case you need to use those options, unset `maven.compiler.release`:\n\n[source,xml,indent=0,subs=\"verbatim,quotes,attributes\"]\n----\n<maven.compiler.release></maven.compiler.release>\n----\n\nand then configure the source and the target options instead:\n\n[source,xml,indent=0,subs=\"verbatim,quotes,attributes\"]\n----\n<maven.compiler.source>${java.version}</maven.compiler.source>\n<maven.compiler.target>${java.version}</maven.compiler.target>\n----\n====\n\n\n\n[[using.parent-pom]]\n== Inheriting the Starter Parent POM\n\nTo configure your project to inherit from the `spring-boot-starter-parent`, set the `parent` as follows:\n\n[source,xml,subs=\"verbatim,quotes,attributes\"]\n----\n<!-- Inherit defaults from Spring Boot -->\n<parent>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-parent</artifactId>\n\t<version>{version-spring-boot}</version>\n</parent>\n----\n\nNOTE: You should need to specify only the Spring Boot version number on this dependency.\nIf you import additional starters, you can safely omit the version number.\n\nWith that setup, you can also override individual dependencies by overriding a property in your own project.\nFor instance, to use a different version of the SLF4J library and the Spring Data release train, you would add the following to your `pom.xml`:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$using/different-versions-pom.xml[tags=different-versions]\n----\n\nBrowse the xref:appendix:dependency-versions/properties.adoc[Dependency Versions Properties] section in the Spring Boot reference for a complete list of dependency version properties.\n\nWARNING: Each Spring Boot release is designed and tested against a specific set of third-party dependencies.\nOverriding versions may cause compatibility issues and should be done with care.\n\n\n\n[[using.import]]\n== Using Spring Boot without the Parent POM\n\nThere may be reasons for you not to inherit from the `spring-boot-starter-parent` POM.\nYou may have your own corporate standard parent that you need to use or you may prefer to explicitly declare all your Maven configuration.\n\nIf you do not want to use the `spring-boot-starter-parent`, you can still keep the benefit of the dependency management (but not the plugin management) by using an `import` scoped dependency, as follows:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$using/no-starter-parent-pom.xml[tags=no-starter-parent]\n----\n\nThe preceding sample setup does not let you override individual dependencies by using properties, as explained above.\nTo achieve the same result, you need to add entries in the `dependencyManagement` section of your project **before** the `spring-boot-dependencies` entry.\nFor instance, to use a different version of the SLF4J library and the Spring Data release train, you could add the following elements to your `pom.xml`:\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$using/no-starter-parent-override-dependencies-pom.xml[tags=no-starter-parent-override-dependencies]\n----\n\n\n\n[[using.overriding-command-line]]\n== Overriding Settings on the Command Line\n\nThe plugin offers a number of user properties, starting with `spring-boot`, to let you customize the configuration from the command line.\n\nFor instance, you could tune the profiles to enable when running the application as follows:\n\n[source,shell]\n----\n$ mvn spring-boot:run -Dspring-boot.run.profiles=dev,local\n----\n\nIf you want to both have a default while allowing it to be overridden on the command line, you should use a combination of a user-provided project property and MOJO configuration.\n\n[source,xml,indent=0,subs=\"verbatim,attributes\"]\n----\ninclude::example$using/default-and-override-pom.xml[tags=default-and-override]\n----\n\nThe above makes sure that `local` and `dev` are enabled by default.\nNow a dedicated property has been exposed, this can be overridden on the command line as well:\n\n[source,shell]\n----\n$ mvn spring-boot:run -Dapp.profiles=test\n----\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/docs/antora/modules/maven-plugin/partials/nav-maven-plugin.adoc",
    "content": "* xref:maven-plugin:index.adoc[]\n** xref:maven-plugin:getting-started.adoc[]\n** xref:maven-plugin:using.adoc[]\n** xref:maven-plugin:goals.adoc[]\n** xref:maven-plugin:packaging.adoc[]\n** xref:maven-plugin:build-image.adoc[]\n** xref:maven-plugin:run.adoc[]\n** xref:maven-plugin:aot.adoc[]\n** xref:maven-plugin:integration-tests.adoc[]\n** xref:maven-plugin:build-info.adoc[]\n** xref:maven-plugin:help.adoc[]\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AbstractArchiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Consumer;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Stream;\nimport java.util.zip.ZipEntry;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.assertj.core.api.ListAssert;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.CheckReturnValue;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Base class for archive (jar or war) related Maven plugin integration tests.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nabstract class AbstractArchiveIntegrationTests {\n\n\tprotected String buildLog(File project) {\n\t\treturn contentOf(new File(project, \"target/build.log\"));\n\t}\n\n\tprotected AssertProvider<JarAssert> jar(File file) {\n\t\treturn new AssertProvider<>() {\n\n\t\t\t@Override\n\t\t\t@Deprecated(since = \"2.3.0\", forRemoval = false)\n\t\t\tpublic JarAssert assertThat() {\n\t\t\t\treturn new JarAssert(file);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprotected Map<String, List<String>> readLayerIndex(JarFile jarFile) throws IOException {\n\t\tif (getLayersIndexLocation() == null) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<String, List<String>> index = new LinkedHashMap<>();\n\t\tString layerPrefix = \"- \";\n\t\tString entryPrefix = \"  - \";\n\t\tZipEntry indexEntry = jarFile.getEntry(getLayersIndexLocation());\n\t\ttry (BufferedReader reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(indexEntry)))) {\n\t\t\tString line = reader.readLine();\n\t\t\tString layer = null;\n\t\t\twhile (line != null) {\n\t\t\t\tif (line.startsWith(layerPrefix)) {\n\t\t\t\t\tlayer = line.substring(layerPrefix.length() + 1, line.length() - 2);\n\t\t\t\t\tindex.put(layer, new ArrayList<>());\n\t\t\t\t}\n\t\t\t\telse if (line.startsWith(entryPrefix)) {\n\t\t\t\t\tindex.computeIfAbsent(layer, (key) -> new ArrayList<>())\n\t\t\t\t\t\t.add(line.substring(entryPrefix.length() + 1, line.length() - 1));\n\t\t\t\t}\n\t\t\t\tline = reader.readLine();\n\t\t\t}\n\t\t\treturn index;\n\t\t}\n\t}\n\n\tprotected @Nullable String getLayersIndexLocation() {\n\t\treturn null;\n\t}\n\n\tprotected List<String> readClasspathIndex(JarFile jarFile, String location) throws IOException {\n\t\tList<String> index = new ArrayList<>();\n\t\tString entryPrefix = \"- \";\n\t\tZipEntry indexEntry = jarFile.getEntry(location);\n\t\ttry (BufferedReader reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(indexEntry)))) {\n\t\t\tString line = reader.readLine();\n\t\t\twhile (line != null) {\n\t\t\t\tif (line.startsWith(entryPrefix)) {\n\t\t\t\t\tindex.add(line.substring(entryPrefix.length() + 1, line.length() - 1));\n\t\t\t\t}\n\t\t\t\tline = reader.readLine();\n\t\t\t}\n\t\t}\n\t\treturn index;\n\t}\n\n\tstatic final class JarAssert extends AbstractAssert<JarAssert, File> {\n\n\t\tprivate JarAssert(File actual) {\n\t\t\tsuper(actual, JarAssert.class);\n\t\t\tassertThat(actual).exists();\n\t\t}\n\n\t\tJarAssert doesNotHaveEntryWithName(String name) {\n\t\t\twithJarFile((jarFile) -> {\n\t\t\t\twithEntries(jarFile, (entries) -> {\n\t\t\t\t\tOptional<JarEntry> match = entries.filter((entry) -> entry.getName().equals(name)).findFirst();\n\t\t\t\t\tassertThat(match).isNotPresent();\n\t\t\t\t});\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tJarAssert hasEntryWithName(String name) {\n\t\t\twithJarFile((jarFile) -> {\n\t\t\t\twithEntries(jarFile, (entries) -> {\n\t\t\t\t\tOptional<JarEntry> match = entries.filter((entry) -> entry.getName().equals(name)).findFirst();\n\t\t\t\t\tassertThat(match).hasValueSatisfying((entry) -> assertThat(entry.getComment()).isNull());\n\t\t\t\t});\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tJarAssert hasEntryWithNameStartingWith(String prefix) {\n\t\t\twithJarFile((jarFile) -> {\n\t\t\t\twithEntries(jarFile, (entries) -> {\n\t\t\t\t\tOptional<JarEntry> match = entries.filter((entry) -> entry.getName().startsWith(prefix))\n\t\t\t\t\t\t.findFirst();\n\t\t\t\t\tassertThat(match).hasValueSatisfying((entry) -> assertThat(entry.getComment()).isNull());\n\t\t\t\t});\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tJarAssert hasUnpackEntryWithNameStartingWith(String prefix) {\n\t\t\twithJarFile((jarFile) -> {\n\t\t\t\twithEntries(jarFile, (entries) -> {\n\t\t\t\t\tOptional<JarEntry> match = entries.filter((entry) -> entry.getName().startsWith(prefix))\n\t\t\t\t\t\t.findFirst();\n\t\t\t\t\tassertThat(match).as(\"Name starting with %s\", prefix)\n\t\t\t\t\t\t.hasValueSatisfying((entry) -> assertThat(entry.getComment()).isEqualTo(\"UNPACK\"));\n\t\t\t\t});\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tJarAssert doesNotHaveEntryWithNameStartingWith(String prefix) {\n\t\t\twithJarFile((jarFile) -> {\n\t\t\t\twithEntries(jarFile, (entries) -> {\n\t\t\t\t\tOptional<JarEntry> match = entries.filter((entry) -> entry.getName().startsWith(prefix))\n\t\t\t\t\t\t.findFirst();\n\t\t\t\t\tassertThat(match).isNotPresent();\n\t\t\t\t});\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tListAssert<String> entryNamesInPath(String path) {\n\t\t\tList<String> matches = new ArrayList<>();\n\t\t\twithJarFile((jarFile) -> withEntries(jarFile,\n\t\t\t\t\t(entries) -> matches.addAll(entries.map(ZipEntry::getName)\n\t\t\t\t\t\t.filter((name) -> name.startsWith(path) && name.length() > path.length())\n\t\t\t\t\t\t.toList())));\n\t\t\treturn new ListAssert<>(matches);\n\t\t}\n\n\t\tJarAssert manifest(Consumer<ManifestAssert> consumer) {\n\t\t\twithJarFile((jarFile) -> {\n\t\t\t\ttry {\n\t\t\t\t\tconsumer.accept(new ManifestAssert(jarFile.getManifest()));\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tvoid withJarFile(Consumer<JarFile> consumer) {\n\t\t\ttry (JarFile jarFile = new JarFile(this.actual)) {\n\t\t\t\tconsumer.accept(jarFile);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\tvoid withEntries(JarFile jarFile, Consumer<Stream<JarEntry>> entries) {\n\t\t\tentries.accept(Collections.list(jarFile.entries()).stream());\n\t\t}\n\n\t\tstatic final class ManifestAssert extends AbstractAssert<ManifestAssert, Manifest> {\n\n\t\t\tprivate ManifestAssert(Manifest actual) {\n\t\t\t\tsuper(actual, ManifestAssert.class);\n\t\t\t}\n\n\t\t\tManifestAssert hasStartClass(String expected) {\n\t\t\t\tassertThat(this.actual.getMainAttributes().getValue(\"Start-Class\")).isEqualTo(expected);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tManifestAssert hasMainClass(String expected) {\n\t\t\t\tassertThat(this.actual.getMainAttributes().getValue(\"Main-Class\")).isEqualTo(expected);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tManifestAssert hasAttribute(String name, String value) {\n\t\t\t\tassertThat(this.actual.getMainAttributes().getValue(name)).isEqualTo(value);\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t\tManifestAssert doesNotHaveAttribute(String name) {\n\t\t\t\tassertThat(this.actual.getMainAttributes().getValue(name)).isNull();\n\t\t\t\treturn this;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/AotTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.junit.EnabledOnLocale;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Integration tests for the Maven plugin's AOT support.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\n@ExtendWith(MavenBuildExtension.class)\nclass AotTests {\n\n\t@TestTemplate\n\tvoid whenAotRunsSourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"SampleApplication__ApplicationContextInitializer.java\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsResourcesAreGeneratedAndCopiedToTargetClasses(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-resource-generation\").goals(\"package\").execute((project) -> {\n\t\t\tPath targetClasses = project.toPath().resolve(\"target/classes\");\n\t\t\tassertThat(collectRelativePaths(targetClasses)).contains(\n\t\t\t\t\tPath.of(\"META-INF\", \"native-image\", \"org.springframework.boot.maven.it\", \"aot-resource-generation\",\n\t\t\t\t\t\t\t\"reachability-metadata.json\"),\n\t\t\t\t\tPath.of(\"META-INF\", \"native-image\", \"org.springframework.boot.maven.it\", \"aot-resource-generation\",\n\t\t\t\t\t\t\t\"native-image.properties\"),\n\t\t\t\t\tPath.of(\"generated-resource\"), Path.of(\"nested/generated-resource\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithJdkProxyResourcesIncludeProxyConfig(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-jdk-proxy\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"resources\"))).contains(\n\t\t\t\t\tPath.of(\"META-INF\", \"native-image\", \"org.springframework.boot.maven.it\", \"aot-jdk-proxy\",\n\t\t\t\t\t\t\t\"reachability-metadata.json\"),\n\t\t\t\t\tPath.of(\"META-INF\", \"native-image\", \"org.springframework.boot.maven.it\", \"aot-jdk-proxy\",\n\t\t\t\t\t\t\t\"native-image.properties\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithClassProxyClassesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-class-proxy\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"classes\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"SampleRunner$$SpringCGLIB$$0.class\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithProfilesSourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-profile\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"TestProfileConfiguration__BeanDefinitions.java\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithArgumentsSourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-arguments\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"TestProfileConfiguration__BeanDefinitions.java\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithSystemPropertiesSourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-system-properties\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"TestProfileConfiguration__BeanDefinitions.java\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithJvmArgumentsSourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-jvm-arguments\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"TestProfileConfiguration__BeanDefinitions.java\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithReleaseSourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-release\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\")))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"SampleApplication__ApplicationContextInitializer.java\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\t@EnabledOnLocale(language = \"en\")\n\tvoid whenAotRunsWithInvalidCompilerArgumentsCompileFails(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-compiler-arguments\")\n\t\t\t.goals(\"package\")\n\t\t\t.executeAndFail(\n\t\t\t\t\t(project) -> assertThat(buildLog(project)).contains(\"invalid flag: --invalid-compiler-arg\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsSourcesAreCompiledAndMovedToTargetClasses(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot\").goals(\"package\").execute((project) -> {\n\t\t\tPath classesDirectory = project.toPath().resolve(\"target/classes\");\n\t\t\tassertThat(collectRelativePaths(classesDirectory))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"SampleApplication__ApplicationContextInitializer.class\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithModuleInfoSourcesAreCompiledAndMovedToTargetClass(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-module-info\").goals(\"package\").execute((project) -> {\n\t\t\tPath classesDirectory = project.toPath().resolve(\"target/classes\");\n\t\t\tassertThat(collectRelativePaths(classesDirectory))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"SampleApplication__ApplicationContextInitializer.class\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsResourcesAreCopiedToTargetClasses(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-jdk-proxy\").goals(\"package\").execute((project) -> {\n\t\t\tPath classesDirectory = project.toPath().resolve(\"target/classes/META-INF/native-image\");\n\t\t\tassertThat(collectRelativePaths(classesDirectory)).contains(\n\t\t\t\t\tPath.of(\"org.springframework.boot.maven.it\", \"aot-jdk-proxy\", \"reachability-metadata.json\"),\n\t\t\t\t\tPath.of(\"org.springframework.boot.maven.it\", \"aot-jdk-proxy\", \"native-image.properties\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithClassProxyClassesAreCopiedToTargetClasses(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-class-proxy\").goals(\"package\").execute((project) -> {\n\t\t\tPath classesDirectory = project.toPath().resolve(\"target/classes/\");\n\t\t\tassertThat(collectRelativePaths(classesDirectory))\n\t\t\t\t.contains(Path.of(\"org\", \"test\", \"SampleRunner$$SpringCGLIB$$0.class\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotRunsWithDevtoolsInClasspathItIsExcluded(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-exclude-devtools\").goals(\"package\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/main\");\n\t\t\tassertThat(aotDirectory).exists();\n\t\t\tPath sourcesDirectory = aotDirectory.resolve(\"sources\");\n\t\t\tassertThat(sourcesDirectory).exists();\n\t\t\tassertThat(collectRelativePaths(sourcesDirectory)).isNotEmpty();\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAotTestRunsSourcesAndResourcesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-test\").goals(\"test\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/test\");\n\t\t\tassertThat(collectRelativePaths(aotDirectory.resolve(\"sources\"))).contains(Path.of(\"org\", \"test\",\n\t\t\t\t\t\"SampleApplicationTests__TestContext001_ApplicationContextInitializer.java\"));\n\t\t\tPath testClassesDirectory = project.toPath().resolve(\"target/test-classes\");\n\t\t\tassertThat(collectRelativePaths(testClassesDirectory)).contains(Path.of(\"META-INF\", \"native-image\",\n\t\t\t\t\t\"org.springframework.boot.maven.it\", \"aot-test\", \"reachability-metadata.json\"));\n\t\t\tassertThat(collectRelativePaths(testClassesDirectory)).contains(Path.of(\"org\", \"test\",\n\t\t\t\t\t\"SampleApplicationTests__TestContext001_ApplicationContextInitializer.class\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenTestAotRunsWithTestSkipItIsAlsoSkipped(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-test-skip\").goals(\"test\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/test\");\n\t\t\tassertThat(aotDirectory).doesNotExist();\n\t\t\tPath testClassesDirectory = project.toPath().resolve(\"target/test-classes\");\n\t\t\tassertThat(testClassesDirectory.resolve(\"META-INF\").resolve(\"native-image\")).doesNotExist();\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenTestAotRunsWithDevtoolsInClasspathItIsExcluded(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"aot-test-exclude-devtools\").goals(\"process-test-classes\").execute((project) -> {\n\t\t\tPath aotDirectory = project.toPath().resolve(\"target/spring-aot/test\");\n\t\t\tassertThat(aotDirectory).exists();\n\t\t\tPath sourcesDirectory = aotDirectory.resolve(\"sources\");\n\t\t\tassertThat(sourcesDirectory).exists();\n\t\t\tassertThat(collectRelativePaths(sourcesDirectory)).isNotEmpty();\n\t\t});\n\t}\n\n\tList<Path> collectRelativePaths(Path sourceDirectory) {\n\t\ttry (Stream<Path> pathStream = Files.walk(sourceDirectory)) {\n\t\t\treturn pathStream.filter(Files::isRegularFile)\n\t\t\t\t.map((path) -> path.subpath(sourceDirectory.getNameCount(), path.getNameCount()))\n\t\t\t\t.toList();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprotected String buildLog(File project) {\n\t\treturn contentOf(new File(project, \"target/build.log\"));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/BuildInfoIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.time.Instant;\nimport java.util.Properties;\nimport java.util.function.Consumer;\n\nimport org.assertj.core.api.AbstractMapAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.maven.MavenBuild.ProjectCallback;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Maven plugin's build info support.\n *\n * @author Andy Wilkinson\n * @author Vedran Pavic\n */\n@ExtendWith(MavenBuildExtension.class)\nclass BuildInfoIntegrationTests {\n\n\t@TestTemplate\n\tvoid buildInfoPropertiesAreGenerated(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-info\")\n\t\t\t\t.hasBuildName(\"Generate build info\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.containsBuildTime()));\n\t}\n\n\t@TestTemplate\n\tvoid generatedBuildInfoIncludesAdditionalProperties(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-additional-properties\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-info-additional-properties\")\n\t\t\t\t.hasBuildName(\"Generate build info with additional properties\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.containsBuildTime()\n\t\t\t\t.containsEntry(\"build.foo\", \"bar\")\n\t\t\t\t.containsEntry(\"build.encoding\", \"UTF-8\")\n\t\t\t\t.containsEntry(\"build.java.source\", \"1.8\")));\n\t}\n\n\t@TestTemplate\n\tvoid generatedBuildInfoUsesCustomBuildTime(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-custom-build-time\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-info-custom-build-time\")\n\t\t\t\t.hasBuildName(\"Generate build info with custom build time\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.hasBuildTime(\"2019-07-08T08:00:00Z\")));\n\t}\n\n\t@TestTemplate\n\tvoid generatedBuildInfoReproducible(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-reproducible\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-reproducible\")\n\t\t\t\t.hasBuildName(\"Generate build info with build time from project.build.outputTimestamp\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.hasBuildTime(\"2021-04-21T11:22:33Z\")));\n\t}\n\n\t@TestTemplate\n\tvoid generatedBuildInfoReproducibleEpochSeconds(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-reproducible-epoch-seconds\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-reproducible-epoch-seconds\")\n\t\t\t\t.hasBuildName(\"Generate build info with build time from project.build.outputTimestamp\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.hasBuildTime(Instant.ofEpochSecond(1619004153).toString())));\n\t}\n\n\t@TestTemplate\n\tvoid buildInfoPropertiesAreGeneratedToCustomOutputLocation(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-custom-file\")\n\t\t\t.execute(buildInfo(\"target/build.info\",\n\t\t\t\t\t(buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t\t\t.hasBuildArtifact(\"build-info-custom-file\")\n\t\t\t\t\t\t.hasBuildName(\"Generate custom build info\")\n\t\t\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t\t\t.containsBuildTime()));\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildTimeIsDisabledIfDoesNotAppearInGeneratedBuildInfo(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-disable-build-time\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-info-disable-build-time\")\n\t\t\t\t.hasBuildName(\"Generate build info with disabled build time\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.doesNotContainBuildTime()));\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildTimeIsExcludedIfDoesNotAppearInGeneratedBuildInfo(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-exclude-build-time\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).hasBuildGroup(\"org.springframework.boot.maven.it\")\n\t\t\t\t.hasBuildArtifact(\"build-info-exclude-build-time\")\n\t\t\t\t.hasBuildName(\"Generate build info with excluded build time\")\n\t\t\t\t.hasBuildVersion(\"0.0.1.BUILD-SNAPSHOT\")\n\t\t\t\t.doesNotContainBuildTime()));\n\t}\n\n\t@TestTemplate\n\tvoid whenBuildPropertiesAreExcludedTheyDoNotAppearInGeneratedBuildInfo(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"build-info-exclude-build-properties\")\n\t\t\t.execute(buildInfo((buildInfo) -> assertThat(buildInfo).doesNotContainBuildGroup()\n\t\t\t\t.doesNotContainBuildArtifact()\n\t\t\t\t.doesNotContainBuildName()\n\t\t\t\t.doesNotContainBuildVersion()\n\t\t\t\t.containsBuildTime()));\n\t}\n\n\tprivate ProjectCallback buildInfo(Consumer<AssertProvider<BuildInfoAssert>> buildInfo) {\n\t\treturn buildInfo(\"target/classes/META-INF/build-info.properties\", buildInfo);\n\t}\n\n\tprivate ProjectCallback buildInfo(String location, Consumer<AssertProvider<BuildInfoAssert>> buildInfo) {\n\t\treturn (project) -> buildInfo.accept((buildInfo(project, location)));\n\t}\n\n\tprivate AssertProvider<BuildInfoAssert> buildInfo(File project, String buildInfo) {\n\t\treturn new AssertProvider<>() {\n\n\t\t\t@Override\n\t\t\t@Deprecated(since = \"2.3.0\", forRemoval = false)\n\t\t\tpublic BuildInfoAssert assertThat() {\n\t\t\t\treturn new BuildInfoAssert(new File(project, buildInfo));\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate static final class BuildInfoAssert extends AbstractMapAssert<BuildInfoAssert, Properties, Object, Object> {\n\n\t\tprivate BuildInfoAssert(File actual) {\n\t\t\tsuper(loadProperties(actual), BuildInfoAssert.class);\n\t\t}\n\n\t\tprivate static Properties loadProperties(File file) {\n\t\t\ttry (FileReader reader = new FileReader(file)) {\n\t\t\t\tProperties properties = new Properties();\n\t\t\t\tproperties.load(reader);\n\t\t\t\treturn properties;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\tBuildInfoAssert hasBuildGroup(String expected) {\n\t\t\treturn containsEntry(\"build.group\", expected);\n\t\t}\n\n\t\tBuildInfoAssert doesNotContainBuildGroup() {\n\t\t\treturn doesNotContainKey(\"build.group\");\n\t\t}\n\n\t\tBuildInfoAssert hasBuildArtifact(String expected) {\n\t\t\treturn containsEntry(\"build.artifact\", expected);\n\t\t}\n\n\t\tBuildInfoAssert doesNotContainBuildArtifact() {\n\t\t\treturn doesNotContainKey(\"build.artifact\");\n\t\t}\n\n\t\tBuildInfoAssert hasBuildName(String expected) {\n\t\t\treturn containsEntry(\"build.name\", expected);\n\t\t}\n\n\t\tBuildInfoAssert doesNotContainBuildName() {\n\t\t\treturn doesNotContainKey(\"build.name\");\n\t\t}\n\n\t\tBuildInfoAssert hasBuildVersion(String expected) {\n\t\t\treturn containsEntry(\"build.version\", expected);\n\t\t}\n\n\t\tBuildInfoAssert doesNotContainBuildVersion() {\n\t\t\treturn doesNotContainKey(\"build.version\");\n\t\t}\n\n\t\tBuildInfoAssert containsBuildTime() {\n\t\t\treturn containsKey(\"build.time\");\n\t\t}\n\n\t\tBuildInfoAssert doesNotContainBuildTime() {\n\t\t\treturn doesNotContainKey(\"build.time\");\n\t\t}\n\n\t\tBuildInfoAssert hasBuildTime(String expected) {\n\t\t\treturn containsEntry(\"build.time\", expected);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/EclipseM2eIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Comparator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests to check that our plugin works well with Eclipse m2e.\n *\n * @author Phillip Webb\n */\nclass EclipseM2eIntegrationTests {\n\n\t@Test // gh-21992\n\tvoid pluginPomIncludesOptionalShadeDependency() throws Exception {\n\t\tString version = new Versions().get(\"project.version\");\n\t\tFile repository = new File(\"build/test-maven-repository\");\n\t\tFile pluginDirectory = new File(repository, \"org/springframework/boot/spring-boot-maven-plugin/\" + version);\n\t\tFile[] pomFiles = pluginDirectory.listFiles(this::isPomFile);\n\t\tArrays.sort(pomFiles, Comparator.comparing(File::getName));\n\t\tFile pomFile = pomFiles[pomFiles.length - 1];\n\t\tString pomContent = new String(FileCopyUtils.copyToByteArray(pomFile), StandardCharsets.UTF_8);\n\t\tassertThat(pomContent).contains(\"maven-shade-plugin\");\n\t}\n\n\tprivate boolean isPomFile(File file) {\n\t\treturn file.getName().endsWith(\".pom\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/JarIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TimeZone;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.jar.JarFile;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.loader.tools.JarModeLibrary;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.boot.testsupport.FileUtils;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Maven plugin's jar support.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\n@ExtendWith(MavenBuildExtension.class)\nclass JarIntegrationTests extends AbstractArchiveIntegrationTests {\n\n\t@Override\n\tprotected String getLayersIndexLocation() {\n\t\treturn \"BOOT-INF/layers.idx\";\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedInPlaceOnlyRepackagedJarIsInstalled(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar\").goals(\"install\").execute((project) -> {\n\t\t\tFile original = new File(project, \"target/jar-0.0.1.BUILD-SNAPSHOT.jar.original\");\n\t\t\tassertThat(original).isFile();\n\t\t\tFile repackaged = new File(project, \"target/jar-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).manifest((manifest) -> {\n\t\t\t\tmanifest.hasMainClass(\"org.springframework.boot.loader.launch.JarLauncher\");\n\t\t\t\tmanifest.hasStartClass(\"some.random.Main\");\n\t\t\t\tmanifest.hasAttribute(\"Not-Used\", \"Foo\");\n\t\t\t})\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/commons-logging\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jakarta.servlet-api-6\")\n\t\t\t\t.hasEntryWithName(\"BOOT-INF/classes/org/test/SampleApplication.class\")\n\t\t\t\t.hasEntryWithName(\"org/springframework/boot/loader/launch/JarLauncher.class\");\n\t\t\tassertThat(buildLog(project))\n\t\t\t\t.contains(\"Replacing main artifact \" + repackaged + \" with repackaged archive,\")\n\t\t\t\t.contains(\"The original artifact has been renamed to \" + original)\n\t\t\t\t.contains(\"Installing \" + repackaged + \" to\")\n\t\t\t\t.doesNotContain(\"Installing \" + original + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAttachIsDisabledOnlyTheOriginalJarIsInstalled(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-attach-disabled\").goals(\"install\").execute((project) -> {\n\t\t\tFile original = new File(project, \"target/jar-attach-disabled-0.0.1.BUILD-SNAPSHOT.jar.original\");\n\t\t\tassertThat(original).isFile();\n\t\t\tFile main = new File(project, \"target/jar-attach-disabled-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(main).isFile();\n\t\t\tassertThat(buildLog(project)).contains(\"Updating main artifact \" + main + \" to \" + original)\n\t\t\t\t.contains(\"Installing \" + original + \" to\")\n\t\t\t\t.doesNotContain(\"Installing \" + main + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAClassifierIsConfiguredTheRepackagedJarHasAClassifierAndBothItAndTheOriginalAreInstalled(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-classifier-main\").goals(\"install\").execute((project) -> {\n\t\t\tassertThat(new File(project, \"target/jar-classifier-main-0.0.1.BUILD-SNAPSHOT.jar.original\"))\n\t\t\t\t.doesNotExist();\n\t\t\tFile main = new File(project, \"target/jar-classifier-main-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(main).isFile();\n\t\t\tFile repackaged = new File(project, \"target/jar-classifier-main-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\");\n\t\t\tassertThat(buildLog(project))\n\t\t\t\t.contains(\"Attaching repackaged archive \" + repackaged + \" with classifier test\")\n\t\t\t\t.doesNotContain(\"Creating repackaged archive \" + repackaged + \" with classifier test\")\n\t\t\t\t.contains(\"Installing \" + main + \" to\")\n\t\t\t\t.contains(\"Installing \" + repackaged + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBothJarsHaveTheSameClassifierRepackagingIsDoneInPlaceAndOnlyRepackagedJarIsInstalled(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-classifier-source\").goals(\"install\").execute((project) -> {\n\t\t\tFile original = new File(project, \"target/jar-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar.original\");\n\t\t\tassertThat(original).isFile();\n\t\t\tFile repackaged = new File(project, \"target/jar-classifier-source-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\");\n\t\t\tassertThat(buildLog(project))\n\t\t\t\t.contains(\"Replacing artifact with classifier test \" + repackaged + \" with repackaged archive,\")\n\t\t\t\t.contains(\"The original artifact has been renamed to \" + original)\n\t\t\t\t.doesNotContain(\"Installing \" + original + \" to\")\n\t\t\t\t.contains(\"Installing \" + repackaged + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenBothJarsHaveTheSameClassifierAndAttachIsDisabledOnlyTheOriginalJarIsInstalled(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-classifier-source-attach-disabled\").goals(\"install\").execute((project) -> {\n\t\t\tFile original = new File(project,\n\t\t\t\t\t\"target/jar-classifier-source-attach-disabled-0.0.1.BUILD-SNAPSHOT-test.jar.original\");\n\t\t\tassertThat(original).isFile();\n\t\t\tFile repackaged = new File(project,\n\t\t\t\t\t\"target/jar-classifier-source-attach-disabled-0.0.1.BUILD-SNAPSHOT-test.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\");\n\t\t\tassertThat(buildLog(project))\n\t\t\t\t.doesNotContain(\"Attaching repackaged archive \" + repackaged + \" with classifier test\")\n\t\t\t\t.contains(\"Updating artifact with classifier test \" + repackaged + \" to \" + original)\n\t\t\t\t.contains(\"Installing \" + original + \" to\")\n\t\t\t\t.doesNotContain(\"Installing \" + repackaged + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAClassifierAndAnOutputDirectoryAreConfiguredTheRepackagedJarHasAClassifierAndIsWrittenToTheOutputDirectory(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-create-dir\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/foo/jar-create-dir-0.0.1.BUILD-SNAPSHOT-foo.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\");\n\t\t\tassertThat(buildLog(project)).contains(\"Installing \" + repackaged + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnOutputDirectoryIsConfiguredTheRepackagedJarIsWrittenToIt(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-custom-dir\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/foo/jar-custom-dir-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\");\n\t\t\tassertThat(buildLog(project)).contains(\"Installing \" + repackaged + \" to\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnEntryIsExcludedItDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-exclude-entry\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-exclude-entry-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/commons-logging\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/servlet-api-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnEntryIsOptionalByDefaultDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-optional-default\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-optional-default-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/log4j-api-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnEntryIsOptionalAndOptionalsIncludedAppearsInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-optional-include\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-optional-include-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/log4j-api-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnEntryIsOptionalAndOptionalsExcludedDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-optional-exclude\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-optional-exclude-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/log4j-api-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnEntryIsExcludedWithPropertyItDoesNotAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar\")\n\t\t\t.systemProperty(\"spring-boot.excludes\", \"jakarta.servlet:jakarta.servlet-api\")\n\t\t\t.goals(\"install\")\n\t\t\t.execute((project) -> {\n\t\t\t\tFile repackaged = new File(project, \"target/jar-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/commons-logging\")\n\t\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/jakarta.servlet-api-\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnEntryIsIncludedOnlyIncludedEntriesAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-include-entry\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-include-entry-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jakarta.servlet-api-\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/commons-logging\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAnIncludeIsSpecifiedAsAPropertyOnlyIncludedEntriesAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar\")\n\t\t\t.systemProperty(\"spring-boot.includes\", \"jakarta.servlet:jakarta.servlet-api\")\n\t\t\t.goals(\"install\")\n\t\t\t.execute((project) -> {\n\t\t\t\tFile repackaged = new File(project, \"target/jar-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jakarta.servlet-api-\")\n\t\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core\")\n\t\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/commons-logging\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAGroupIsExcludedNoEntriesInThatGroupAppearInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-exclude-group\").goals(\"install\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-exclude-group-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/commons-logging\")\n\t\t\t\t.doesNotHaveEntryWithName(\"BOOT-INF/lib/log4j-api-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAJarIsBuiltWithLibrariesWithConflictingNamesTheyAreMadeUniqueUsingTheirGroupIds(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-lib-name-conflict\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"test-project/target/test-project-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithName(\"BOOT-INF/lib/org.springframework.boot.maven.it-acme-lib-0.0.1.BUILD-SNAPSHOT.jar\")\n\t\t\t\t.hasEntryWithName(\n\t\t\t\t\t\t\"BOOT-INF/lib/org.springframework.boot.maven.it.another-acme-lib-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAProjectUsesPomPackagingRepackagingIsSkipped(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-pom\").execute((project) -> {\n\t\t\tFile target = new File(project, \"target\");\n\t\t\tassertThat(target.listFiles()).containsExactly(new File(target, \"build.log\"));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenRepackagingIsSkippedTheJarIsNotRepackaged(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-skip\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-skip-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).doesNotHaveEntryWithNameStartingWith(\"org/springframework/boot\");\n\t\t\tassertThat(new File(project, \"target/jar-skip-0.0.1.BUILD-SNAPSHOT.jar.original\")).doesNotExist();\n\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenADependencyHasSystemScopeAndInclusionOfSystemScopeDependenciesIsEnabledItIsIncludedInTheRepackagedJar(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-system-scope\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-system-scope-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).hasEntryWithName(\"BOOT-INF/lib/sample-1.0.0.jar\");\n\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenADependencyHasSystemScopeItIsNotIncludedInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-system-scope-default\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-system-scope-default-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).doesNotHaveEntryWithName(\"BOOT-INF/lib/sample-1.0.0.jar\");\n\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenADependencyHasTestScopeItIsNotIncludedInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-test-scope\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-test-scope-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/log4j\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAProjectUsesKotlinItsModuleMetadataIsRepackagedIntoBootInfClasses(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-with-kotlin-module\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-with-kotlin-module-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).hasEntryWithName(\"BOOT-INF/classes/META-INF/jar-with-kotlin-module.kotlin_module\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenAProjectIsBuiltWithALayoutPropertyTheSpecifiedLayoutIsUsed(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-with-layout-property\")\n\t\t\t.goals(\"package\", \"-Dspring-boot.repackage.layout=ZIP\")\n\t\t\t.execute((project) -> {\n\t\t\t\tFile main = new File(project, \"target/jar-with-layout-property-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(jar(main)).manifest(\n\t\t\t\t\t\t(manifest) -> manifest.hasMainClass(\"org.springframework.boot.loader.launch.PropertiesLauncher\")\n\t\t\t\t\t\t\t.hasStartClass(\"org.test.SampleApplication\"));\n\t\t\t\tassertThat(buildLog(project)).contains(\"Layout: ZIP\");\n\t\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenALayoutIsConfiguredTheSpecifiedLayoutIsUsed(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-with-zip-layout\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-with-zip-layout-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).manifest(\n\t\t\t\t\t(manifest) -> manifest.hasMainClass(\"org.springframework.boot.loader.launch.PropertiesLauncher\")\n\t\t\t\t\t\t.hasStartClass(\"org.test.SampleApplication\"));\n\t\t\tassertThat(buildLog(project)).contains(\"Layout: ZIP\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenRequiresUnpackConfigurationIsProvidedItIsReflectedInTheRepackagedJar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-with-unpack\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/jar-with-unpack-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(main)).hasUnpackEntryWithNameStartingWith(\"BOOT-INF/lib/spring-core-\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/spring-context-\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithACustomLayoutTheJarUsesTheLayout(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-custom-layout\").execute((project) -> {\n\t\t\tassertThat(jar(new File(project, \"custom/target/custom-0.0.1.BUILD-SNAPSHOT.jar\")))\n\t\t\t\t.hasEntryWithName(\"custom\");\n\t\t\tassertThat(jar(new File(project, \"default/target/default-0.0.1.BUILD-SNAPSHOT.jar\")))\n\t\t\t\t.hasEntryWithName(\"sample\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid repackagedJarContainsTheLayersIndexByDefault(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-layered\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"jar/target/jar-layered-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-snapshot\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/\" + coordinates.getArtifactId());\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tMap<String, List<String>> layerIndex = readLayerIndex(jarFile);\n\t\t\t\tassertThat(layerIndex.keySet()).containsExactly(\"dependencies\", \"spring-boot-loader\",\n\t\t\t\t\t\t\"snapshot-dependencies\", \"application\");\n\t\t\t\tassertThat(layerIndex.get(\"application\")).contains(\"BOOT-INF/lib/jar-release-0.0.1.RELEASE.jar\",\n\t\t\t\t\t\t\"BOOT-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(layerIndex.get(\"dependencies\"))\n\t\t\t\t\t.anyMatch((dependency) -> dependency.startsWith(\"BOOT-INF/lib/log4j-api-\"));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithTheLayersDisabledDoesNotContainLayersIndex(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-layered-disabled\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"jar/target/jar-layered-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-snapshot\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/\" + coordinates.getArtifactId())\n\t\t\t\t.doesNotHaveEntryWithName(\"BOOT-INF/layers.idx\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithToolsExclude(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-no-tools\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"jar/target/jar-no-tools-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-snapshot\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"BOOT-INF/lib/\" + coordinates.getArtifactId());\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithTheCustomLayers(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-layered-custom\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"jar/target/jar-layered-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-snapshot\");\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tMap<String, List<String>> layerIndex = readLayerIndex(jarFile);\n\t\t\t\tassertThat(layerIndex.keySet()).containsExactly(\"my-dependencies-name\", \"snapshot-dependencies\",\n\t\t\t\t\t\t\"configuration\", \"application\");\n\t\t\t\tassertThat(layerIndex.get(\"application\"))\n\t\t\t\t\t.contains(\"BOOT-INF/lib/jar-release-0.0.1.RELEASE.jar\",\n\t\t\t\t\t\t\t\"BOOT-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar\",\n\t\t\t\t\t\t\t\"BOOT-INF/lib/jar-classifier-0.0.1-bravo.jar\")\n\t\t\t\t\t.doesNotContain(\"BOOT-INF/lib/jar-classifier-0.0.1-alpha.jar\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithTheCustomLayersFromClasspath(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-layered-custom-name\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"jar/target/jar-layered-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"BOOT-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"BOOT-INF/lib/jar-snapshot\");\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tMap<String, List<String>> layerIndex = readLayerIndex(jarFile);\n\t\t\t\tassertThat(layerIndex.keySet()).containsExactly(\"my-dependencies-name\", \"snapshot-dependencies\",\n\t\t\t\t\t\t\"configuration\", \"application\");\n\t\t\t\tassertThat(layerIndex.get(\"application\"))\n\t\t\t\t\t.contains(\"BOOT-INF/lib/jar-release-0.0.1.RELEASE.jar\",\n\t\t\t\t\t\t\t\"BOOT-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar\",\n\t\t\t\t\t\t\t\"BOOT-INF/lib/jar-classifier-0.0.1-bravo.jar\")\n\t\t\t\t\t.doesNotContain(\"BOOT-INF/lib/jar-classifier-0.0.1-alpha.jar\",\n\t\t\t\t\t\t\t\"BOOT-INF/lib/jar-layers-configuration-0.0.1.jar\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid repackagedJarContainsClasspathIndex(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged))\n\t\t\t\t.manifest((manifest) -> manifest.hasAttribute(\"Spring-Boot-Classpath-Index\", \"BOOT-INF/classpath.idx\"));\n\t\t\tassertThat(jar(repackaged)).hasEntryWithName(\"BOOT-INF/classpath.idx\");\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tList<String> index = readClasspathIndex(jarFile, \"BOOT-INF/classpath.idx\");\n\t\t\t\tassertThat(index).allMatch((entry) -> entry.startsWith(\"BOOT-INF/lib/\"));\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithOutputTimestampConfiguredThenJarIsReproducible(MavenBuild mavenBuild)\n\t\t\tthrows InterruptedException {\n\t\tString firstHash = buildJarWithOutputTimestamp(mavenBuild);\n\t\tThread.sleep(1500);\n\t\tString secondHash = buildJarWithOutputTimestamp(mavenBuild);\n\t\tassertThat(firstHash).isEqualTo(secondHash);\n\t}\n\n\tprivate String buildJarWithOutputTimestamp(MavenBuild mavenBuild) {\n\t\tAtomicReference<String> jarHash = new AtomicReference<>();\n\t\tmavenBuild.project(\"jar-output-timestamp\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-output-timestamp-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(repackaged).isFile();\n\t\t\tlong expectedModified = 1584352800000L;\n\t\t\tlong offsetExpectedModified = expectedModified - TimeZone.getDefault().getOffset(expectedModified);\n\t\t\tassertThat(repackaged.lastModified()).isEqualTo(expectedModified);\n\t\t\ttry (JarFile jar = new JarFile(repackaged)) {\n\t\t\t\tList<String> unreproducibleEntries = jar.stream()\n\t\t\t\t\t.filter((entry) -> entry.getLastModifiedTime().toMillis() != offsetExpectedModified)\n\t\t\t\t\t.map((entry) -> entry.getName() + \": \" + entry.getLastModifiedTime())\n\t\t\t\t\t.toList();\n\t\t\t\tassertThat(unreproducibleEntries).isEmpty();\n\t\t\t\tjarHash.set(FileUtils.sha1Hash(repackaged));\n\t\t\t\tFileSystemUtils.deleteRecursively(project);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t});\n\t\tString hash = jarHash.get();\n\t\tassertThat(hash).isNotNull();\n\t\treturn hash;\n\t}\n\n\t@TestTemplate\n\tvoid whenJarIsRepackagedWithOutputTimestampConfiguredThenLibrariesAreSorted(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-output-timestamp\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-output-timestamp-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tList<String> sortedLibs = Arrays.asList(\"BOOT-INF/lib/commons-logging\", \"BOOT-INF/lib/jakarta.servlet-api\",\n\t\t\t\t\t\"BOOT-INF/lib/jspecify\", \"BOOT-INF/lib/micrometer-commons\", \"BOOT-INF/lib/micrometer-observation\",\n\t\t\t\t\t\"BOOT-INF/lib/spring-aop\", \"BOOT-INF/lib/spring-beans\",\n\t\t\t\t\t\"BOOT-INF/lib/\" + coordinates.getArtifactId(), \"BOOT-INF/lib/spring-context\",\n\t\t\t\t\t\"BOOT-INF/lib/spring-core\", \"BOOT-INF/lib/spring-expression\");\n\t\t\tassertThat(jar(repackaged)).entryNamesInPath(\"BOOT-INF/lib/\")\n\t\t\t\t.zipSatisfy(sortedLibs,\n\t\t\t\t\t\t(String jarLib, String expectedLib) -> assertThat(jarLib).startsWith(expectedLib));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenSigned(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"jar-signed\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/jar-signed-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithName(\"META-INF/BOOT.SF\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/MavenBuild.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.nio.file.FileVisitResult;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.SimpleFileVisitor;\nimport java.nio.file.StandardCopyOption;\nimport java.nio.file.StandardOpenOption;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Properties;\n\nimport org.apache.maven.shared.invoker.DefaultInvocationRequest;\nimport org.apache.maven.shared.invoker.DefaultInvoker;\nimport org.apache.maven.shared.invoker.InvocationRequest;\nimport org.apache.maven.shared.invoker.InvocationResult;\nimport org.apache.maven.shared.invoker.Invoker;\nimport org.apache.maven.shared.invoker.MavenInvocationException;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Helper class for executing a Maven build.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass MavenBuild {\n\n\tprivate final File home;\n\n\tprivate final File temp;\n\n\tprivate final Map<String, String> pomReplacements;\n\n\tprivate final List<String> goals = new ArrayList<>();\n\n\tprivate final Properties properties = new Properties();\n\n\tprivate @Nullable ProjectCallback preparation;\n\n\tprivate @Nullable File projectDir;\n\n\tMavenBuild(File home) {\n\t\tthis.home = home;\n\t\tthis.temp = createTempDirectory();\n\t\tthis.pomReplacements = getPomReplacements();\n\t}\n\n\tprivate File createTempDirectory() {\n\t\ttry {\n\t\t\treturn Files.createTempDirectory(\"maven-build\").toFile().getCanonicalFile();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate Map<String, String> getPomReplacements() {\n\t\tMap<String, String> replacements = new HashMap<>();\n\t\treplacements.put(\"java.version\", \"17\");\n\t\treplacements.put(\"project.groupId\", \"org.springframework.boot\");\n\t\treplacements.put(\"project.artifactId\", \"spring-boot-maven-plugin\");\n\t\treplacements.putAll(new Versions().asMap());\n\t\treturn Collections.unmodifiableMap(replacements);\n\t}\n\n\tMavenBuild project(String project) {\n\t\treturn project(\"intTest\", project);\n\t}\n\n\tMavenBuild project(String root, String project) {\n\t\tthis.projectDir = new File(\"src/\" + root + \"/projects/\" + project);\n\t\treturn this;\n\t}\n\n\tMavenBuild goals(String... goals) {\n\t\tthis.goals.addAll(Arrays.asList(goals));\n\t\treturn this;\n\t}\n\n\tMavenBuild systemProperty(String name, String value) {\n\t\tthis.properties.setProperty(name, value);\n\t\treturn this;\n\t}\n\n\tMavenBuild prepare(ProjectCallback callback) {\n\t\tthis.preparation = callback;\n\t\treturn this;\n\t}\n\n\tvoid execute(ProjectCallback callback) {\n\t\texecute(callback, 0);\n\t}\n\n\tvoid executeAndFail(ProjectCallback callback) {\n\t\texecute(callback, 1);\n\t}\n\n\tprivate void execute(ProjectCallback callback, int expectedExitCode) {\n\t\tInvoker invoker = new DefaultInvoker();\n\t\tinvoker.setMavenHome(this.home);\n\t\tInvocationRequest request = new DefaultInvocationRequest();\n\t\ttry {\n\t\t\tPath destination = this.temp.toPath();\n\t\t\tAssert.notNull(this.projectDir, \"'projectDir' must not be null\");\n\t\t\tPath source = this.projectDir.toPath();\n\t\t\tFiles.walkFileTree(source, new SimpleFileVisitor<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\n\t\t\t\t\tFiles.createDirectories(destination.resolve(source.relativize(dir)));\n\t\t\t\t\treturn FileVisitResult.CONTINUE;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\n\t\t\t\t\tif (file.toFile().getName().equals(\"pom.xml\")) {\n\t\t\t\t\t\tString pomXml = Files.readString(file);\n\t\t\t\t\t\tfor (Entry<String, String> replacement : MavenBuild.this.pomReplacements.entrySet()) {\n\t\t\t\t\t\t\tpomXml = pomXml.replace(\"@\" + replacement.getKey() + \"@\", replacement.getValue());\n\t\t\t\t\t\t}\n\t\t\t\t\t\tFiles.writeString(destination.resolve(source.relativize(file)), pomXml,\n\t\t\t\t\t\t\t\tStandardOpenOption.CREATE_NEW);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tFiles.copy(file, destination.resolve(source.relativize(file)),\n\t\t\t\t\t\t\t\tStandardCopyOption.REPLACE_EXISTING);\n\t\t\t\t\t}\n\t\t\t\t\treturn FileVisitResult.CONTINUE;\n\t\t\t\t}\n\n\t\t\t});\n\t\t\tString settingsXml = Files.readString(Paths.get(\"src\", \"intTest\", \"projects\", \"settings.xml\"))\n\t\t\t\t.replace(\"@localCentralUrl@\", new File(\"build/test-maven-repository\").toURI().toURL().toString())\n\t\t\t\t.replace(\"@localRepositoryPath@\", new File(\"build/local-maven-repository\").getAbsolutePath());\n\t\t\tFiles.writeString(destination.resolve(\"settings.xml\"), settingsXml, StandardOpenOption.CREATE_NEW);\n\t\t\trequest.setBaseDirectory(this.temp);\n\t\t\trequest.setJavaHome(new File(System.getProperty(\"java.home\")));\n\t\t\trequest.setProperties(this.properties);\n\t\t\trequest.addArgs(this.goals.isEmpty() ? Collections.singletonList(\"package\") : this.goals);\n\t\t\trequest.setUserSettingsFile(new File(this.temp, \"settings.xml\"));\n\t\t\trequest.setUpdateSnapshots(true);\n\t\t\trequest.setBatchMode(true);\n\t\t\t// request.setMavenOpts(\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000\");\n\t\t\tFile target = new File(this.temp, \"target\");\n\t\t\ttarget.mkdirs();\n\t\t\tif (this.preparation != null) {\n\t\t\t\tthis.preparation.doWith(this.temp);\n\t\t\t}\n\t\t\tFile buildLogFile = new File(target, \"build.log\");\n\t\t\ttry (PrintWriter buildLog = new PrintWriter(new FileWriter(buildLogFile))) {\n\t\t\t\trequest.setOutputHandler((line) -> {\n\t\t\t\t\tbuildLog.println(line);\n\t\t\t\t\tbuildLog.flush();\n\t\t\t\t});\n\t\t\t\ttry {\n\t\t\t\t\tInvocationResult result = invoker.execute(request);\n\t\t\t\t\tassertThat(result.getExitCode()).as(contentOf(buildLogFile)).isEqualTo(expectedExitCode);\n\t\t\t\t}\n\t\t\t\tcatch (MavenInvocationException ex) {\n\t\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcallback.doWith(this.temp);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\tfinally {\n\t\t\tFileSystemUtils.deleteRecursively(this.temp);\n\t\t}\n\t}\n\n\t/**\n\t * Action to take on a maven project directory.\n\t */\n\t@FunctionalInterface\n\tpublic interface ProjectCallback {\n\n\t\t/**\n\t\t * Take the action on the given project.\n\t\t * @param project the project directory\n\t\t * @throws Exception on error\n\t\t */\n\t\tvoid doWith(File project) throws Exception;\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/MavenBuildExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolver;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;\n\n/**\n * An {@link Extension} for templated tests that use {@link MavenBuild}. Each templated\n * test is run against multiple versions of Maven.\n *\n * @author Andy Wilkinson\n */\nclass MavenBuildExtension implements TestTemplateInvocationContextProvider {\n\n\t@Override\n\tpublic boolean supportsTestTemplate(ExtensionContext context) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {\n\t\ttry {\n\t\t\t// Returning a stream which must be closed here is fine, as JUnit will take\n\t\t\t// care of closing it\n\t\t\treturn Files.list(Paths.get(\"build/maven-binaries\")).map(MavenVersionTestTemplateInvocationContext::new);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate static final class MavenVersionTestTemplateInvocationContext implements TestTemplateInvocationContext {\n\n\t\tprivate final Path mavenHome;\n\n\t\tprivate MavenVersionTestTemplateInvocationContext(Path mavenHome) {\n\t\t\tthis.mavenHome = mavenHome;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDisplayName(int invocationIndex) {\n\t\t\treturn this.mavenHome.getFileName().toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Extension> getAdditionalExtensions() {\n\t\t\treturn Arrays.asList(new MavenBuildParameterResolver(this.mavenHome));\n\t\t}\n\n\t}\n\n\tprivate static final class MavenBuildParameterResolver implements ParameterResolver {\n\n\t\tprivate final Path mavenHome;\n\n\t\tprivate MavenBuildParameterResolver(Path mavenHome) {\n\t\t\tthis.mavenHome = mavenHome;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\treturn parameterContext.getParameter().getType().equals(MavenBuild.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\treturn new MavenBuild(this.mavenHome.toFile());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/RunIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Integration tests for the Maven plugin's run goal.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@ExtendWith(MavenBuildExtension.class)\nclass RunIntegrationTests {\n\n\t@TestTemplate\n\tvoid whenTheRunGoalIsExecutedTheApplicationIsForkedWithOptimizedJvmArguments(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run\").goals(\"spring-boot:run\", \"-X\").execute((project) -> {\n\t\t\tString jvmArguments = \"JVM argument: -XX:TieredStopAtLevel=1\";\n\t\t\tassertThat(buildLog(project)).contains(\"I haz been run\").contains(jvmArguments);\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenEnvironmentVariablesAreConfiguredTheyAreAvailableToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-envargs\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenExclusionsAreConfiguredExcludedDependenciesDoNotAppearOnTheClasspath(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-exclude\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenSystemPropertiesAndJvmArgumentsAreConfiguredTheyAreAvailableToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-jvm-system-props\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenJvmArgumentsAreConfiguredTheyAreAvailableToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-jvmargs\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenCommandLineSpecifiesJvmArgumentsTheyAreAvailableToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-jvmargs-commandline\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.systemProperty(\"spring-boot.run.jvmArguments\", \"-Dfoo=value-from-cmd\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenPomAndCommandLineSpecifyJvmArgumentsThenPomOverrides(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-jvmargs\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.systemProperty(\"spring-boot.run.jvmArguments\", \"-Dfoo=value-from-cmd\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenProfilesAreConfiguredTheyArePassedToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-profiles\")\n\t\t\t.goals(\"spring-boot:run\", \"-X\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run with profile(s) 'foo,bar'\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenUseTestClasspathIsEnabledTheApplicationHasTestDependenciesOnItsClasspath(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-use-test-classpath\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenAWorkingDirectoryIsConfiguredTheApplicationIsRunFromThatDirectory(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-working-directory\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).containsPattern(\"I haz been run from.*src.main.java\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenAdditionalClasspathDirectoryIsConfiguredItsResourcesAreAvailableToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-additional-classpath-directory\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenAdditionalClasspathFileIsConfiguredItsContentIsAvailableToTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-additional-classpath-jar\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"I haz been run\"));\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid whenAToolchainIsConfiguredItIsUsedToRunTheApplication(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-toolchains\")\n\t\t\t.goals(\"verify\", \"-t\", \"toolchains.xml\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"The Maven Toolchains is awesome!\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenPomSpecifiesRunArgumentsContainingCommasTheyArePassedToTheApplicationCorrectly(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-arguments\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.execute((project) -> assertThat(buildLog(project))\n\t\t\t\t.contains(\"I haz been run with profile(s) 'foo,bar' and endpoint(s) 'prometheus,info'\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenCommandLineSpecifiesRunArgumentsContainingCommasTheyArePassedToTheApplicationCorrectly(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-arguments-commandline\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.systemProperty(\"spring-boot.run.arguments\",\n\t\t\t\t\t\"--management.endpoints.web.exposure.include=prometheus,info,health,metrics --spring.profiles.active=foo,bar\")\n\t\t\t.execute((project) -> assertThat(buildLog(project))\n\t\t\t\t.contains(\"I haz been run with profile(s) 'foo,bar' and endpoint(s) 'prometheus,info,health,metrics'\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenPomAndCommandLineSpecifyRunArgumentsThenPomOverrides(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"run-arguments\")\n\t\t\t.goals(\"spring-boot:run\")\n\t\t\t.systemProperty(\"spring-boot.run.arguments\",\n\t\t\t\t\t\"--management.endpoints.web.exposure.include=one,two,three --spring.profiles.active=test\")\n\t\t\t.execute((project) -> assertThat(buildLog(project))\n\t\t\t\t.contains(\"I haz been run with profile(s) 'foo,bar' and endpoint(s) 'prometheus,info'\"));\n\t}\n\n\tprivate String buildLog(File project) {\n\t\treturn contentOf(new File(project, \"target/build.log\"));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/StartStopIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Integration tests for the Maven plugin's war support.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(MavenBuildExtension.class)\nclass StartStopIntegrationTests {\n\n\t@TestTemplate\n\tvoid startStopWaitsForApplicationToBeReadyAndThenRequestsShutdown(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"start-stop\")\n\t\t\t.goals(\"verify\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).contains(\"isReady: true\")\n\t\t\t\t.contains(\"Shutdown requested\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenSkipIsTrueStartAndStopAreSkipped(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"start-stop-skip\")\n\t\t\t.goals(\"verify\")\n\t\t\t.execute((project) -> assertThat(buildLog(project)).doesNotContain(\"Ooops, I haz been run\")\n\t\t\t\t.doesNotContain(\"Stopping application\"));\n\t}\n\n\tprivate String buildLog(File project) {\n\t\treturn contentOf(new File(project, \"target/build.log\"));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/TestRunIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Integration tests for the Maven plugin's {@code test-run} goal.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(MavenBuildExtension.class)\nclass TestRunIntegrationTests {\n\n\t@TestTemplate\n\tvoid whenTheTestRunGoalIsExecutedTheApplicationIsRunWithTestAndMainClassesAndTestClasspath(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"test-run\")\n\t\t\t.goals(\"spring-boot:test-run\", \"-X\")\n\t\t\t.execute((project) -> assertThat(buildLog(project))\n\t\t\t\t.contains(\"Main class name = org.test.TestSampleApplication\")\n\t\t\t\t.contains(\"1. \" + canonicalPathOf(project, \"target/test-classes\"))\n\t\t\t\t.contains(\"2. \" + canonicalPathOf(project, \"target/classes\"))\n\t\t\t\t.containsPattern(\"3\\\\. .*spring-core\")\n\t\t\t\t.containsPattern(\"4\\\\. .*commons-logging\"));\n\t}\n\n\tprivate String canonicalPathOf(File project, String path) throws IOException {\n\t\treturn new File(project, path).getCanonicalPath();\n\t}\n\n\tprivate String buildLog(File project) {\n\t\treturn contentOf(new File(project, \"target/build.log\"));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/Versions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides access to various versions.\n *\n * @author Andy Wilkinson\n */\nclass Versions {\n\n\tprivate final Map<String, String> versions;\n\n\tVersions() {\n\t\tthis.versions = loadVersions();\n\t}\n\n\tprivate static Map<String, String> loadVersions() {\n\t\ttry (InputStream input = Versions.class.getClassLoader().getResourceAsStream(\"extracted-versions.properties\")) {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.load(input);\n\t\t\tMap<String, String> versions = new HashMap<>();\n\t\t\tproperties.forEach((key, value) -> versions.put((String) key, (String) value));\n\t\t\treturn versions;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Nullable String get(String name) {\n\t\treturn this.versions.get(name);\n\t}\n\n\tMap<String, String> asMap() {\n\t\treturn Collections.unmodifiableMap(this.versions);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/java/org/springframework/boot/maven/WarIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TimeZone;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.jar.JarFile;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.loader.tools.JarModeLibrary;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.boot.testsupport.FileUtils;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Maven plugin's war support.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\n@ExtendWith(MavenBuildExtension.class)\nclass WarIntegrationTests extends AbstractArchiveIntegrationTests {\n\n\t@Override\n\tprotected String getLayersIndexLocation() {\n\t\treturn \"WEB-INF/layers.idx\";\n\t}\n\n\t@TestTemplate\n\tvoid warRepackaging(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war\")\n\t\t\t.execute((project) -> assertThat(jar(new File(project, \"target/war-0.0.1.BUILD-SNAPSHOT.war\")))\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/spring-context\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/spring-core\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/commons-logging\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib-provided/jakarta.servlet-api-6\")\n\t\t\t\t.hasEntryWithName(\"org/springframework/boot/loader/launch/WarLauncher.class\")\n\t\t\t\t.hasEntryWithName(\"WEB-INF/classes/org/test/SampleApplication.class\")\n\t\t\t\t.hasEntryWithName(\"index.html\")\n\t\t\t\t.manifest((manifest) -> manifest.hasMainClass(\"org.springframework.boot.loader.launch.WarLauncher\")\n\t\t\t\t\t.hasStartClass(\"org.test.SampleApplication\")\n\t\t\t\t\t.hasAttribute(\"Not-Used\", \"Foo\")));\n\t}\n\n\t@TestTemplate\n\tvoid jarDependencyWithCustomFinalNameBuiltInSameReactorIsPackagedUsingArtifactIdAndVersion(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-reactor\")\n\t\t\t.execute(((project) -> assertThat(jar(new File(project, \"war/target/war-0.0.1.BUILD-SNAPSHOT.war\")))\n\t\t\t\t.hasEntryWithName(\"WEB-INF/lib/jar-0.0.1.BUILD-SNAPSHOT.jar\")\n\t\t\t\t.doesNotHaveEntryWithName(\"WEB-INF/lib/jar.jar\")));\n\t}\n\n\t@TestTemplate\n\tvoid whenRequiresUnpackConfigurationIsProvidedItIsReflectedInTheRepackagedWar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-with-unpack\")\n\t\t\t.execute((project) -> assertThat(jar(new File(project, \"target/war-with-unpack-0.0.1.BUILD-SNAPSHOT.war\")))\n\t\t\t\t.hasUnpackEntryWithNameStartingWith(\"WEB-INF/lib/spring-core-\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/spring-context-\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/commons-logging-\"));\n\t}\n\n\t@TestTemplate\n\tvoid whenWarIsRepackagedWithOutputTimestampConfiguredThenWarIsReproducible(MavenBuild mavenBuild)\n\t\t\tthrows InterruptedException {\n\t\tString firstHash = buildWarWithOutputTimestamp(mavenBuild);\n\t\tThread.sleep(1500);\n\t\tString secondHash = buildWarWithOutputTimestamp(mavenBuild);\n\t\tassertThat(firstHash).isEqualTo(secondHash);\n\t}\n\n\tprivate String buildWarWithOutputTimestamp(MavenBuild mavenBuild) {\n\t\tAtomicReference<String> warHash = new AtomicReference<>();\n\t\tmavenBuild.project(\"war-output-timestamp\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/war-output-timestamp-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tassertThat(repackaged).isFile();\n\t\t\tlong expectedModified = 1584352800000L;\n\t\t\tassertThat(repackaged.lastModified()).isEqualTo(expectedModified);\n\t\t\tlong offsetExpectedModified = expectedModified - TimeZone.getDefault().getOffset(expectedModified);\n\t\t\ttry (JarFile jar = new JarFile(repackaged)) {\n\t\t\t\tList<String> unreproducibleEntries = jar.stream()\n\t\t\t\t\t.filter((entry) -> entry.getLastModifiedTime().toMillis() != offsetExpectedModified)\n\t\t\t\t\t.map((entry) -> entry.getName() + \": \" + entry.getLastModifiedTime())\n\t\t\t\t\t.toList();\n\t\t\t\tassertThat(unreproducibleEntries).isEmpty();\n\t\t\t\twarHash.set(FileUtils.sha1Hash(repackaged));\n\t\t\t\tFileSystemUtils.deleteRecursively(project);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t});\n\t\tString hash = warHash.get();\n\t\tassertThat(hash).isNotNull();\n\t\treturn hash;\n\t}\n\n\t@TestTemplate\n\tvoid whenWarIsRepackagedWithOutputTimestampConfiguredThenLibrariesAreSorted(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-output-timestamp\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/war-output-timestamp-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tList<String> sortedLibs = Arrays.asList(\n\t\t\t\t\t// these libraries are copied from the original war, sorted when\n\t\t\t\t\t// packaged by Maven\n\t\t\t\t\t\"WEB-INF/lib/commons-logging\", \"WEB-INF/lib/jspecify\", \"WEB-INF/lib/micrometer-commons\",\n\t\t\t\t\t\"WEB-INF/lib/micrometer-observation\", \"WEB-INF/lib/spring-aop\", \"WEB-INF/lib/spring-beans\",\n\t\t\t\t\t\"WEB-INF/lib/spring-context\", \"WEB-INF/lib/spring-core\", \"WEB-INF/lib/spring-expression\",\n\t\t\t\t\t// these libraries are contributed by Spring Boot repackaging, and\n\t\t\t\t\t// sorted separately\n\t\t\t\t\t\"WEB-INF/lib/\" + coordinates.getArtifactId());\n\t\t\tassertThat(jar(repackaged)).entryNamesInPath(\"WEB-INF/lib/\")\n\t\t\t\t.zipSatisfy(sortedLibs,\n\t\t\t\t\t\t(String jarLib, String expectedLib) -> assertThat(jarLib).startsWith(expectedLib));\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenADependencyHasSystemScopeAndInclusionOfSystemScopeDependenciesIsEnabledItIsIncludedInTheRepackagedJar(\n\t\t\tMavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-system-scope\").execute((project) -> {\n\t\t\tFile main = new File(project, \"target/war-system-scope-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tassertThat(jar(main)).hasEntryWithName(\"WEB-INF/lib-provided/sample-1.0.0.jar\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid repackagedWarContainsTheLayersIndexByDefault(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-layered\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"WEB-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-snapshot\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/\" + coordinates.getArtifactId());\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tMap<String, List<String>> layerIndex = readLayerIndex(jarFile);\n\t\t\t\tassertThat(layerIndex.keySet()).containsExactly(\"dependencies\", \"spring-boot-loader\",\n\t\t\t\t\t\t\"snapshot-dependencies\", \"application\");\n\t\t\t\tList<String> dependenciesAndSnapshotDependencies = new ArrayList<>();\n\t\t\t\tdependenciesAndSnapshotDependencies.addAll(layerIndex.get(\"dependencies\"));\n\t\t\t\tdependenciesAndSnapshotDependencies.addAll(layerIndex.get(\"snapshot-dependencies\"));\n\t\t\t\tassertThat(layerIndex.get(\"application\")).contains(\"WEB-INF/lib/jar-release-0.0.1.RELEASE.jar\",\n\t\t\t\t\t\t\"WEB-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar\");\n\t\t\t\tassertThat(dependenciesAndSnapshotDependencies)\n\t\t\t\t\t.anyMatch((dependency) -> dependency.startsWith(\"WEB-INF/lib/spring-context\"));\n\t\t\t\tassertThat(layerIndex.get(\"dependencies\"))\n\t\t\t\t\t.anyMatch((dependency) -> dependency.startsWith(\"WEB-INF/lib-provided/\"));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenWarIsRepackagedWithTheLayersDisabledDoesNotContainLayersIndex(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-layered-disabled\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"WEB-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-snapshot\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/\" + coordinates.getArtifactId())\n\t\t\t\t.doesNotHaveEntryWithName(\"WEB-INF/layers.idx\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenWarIsRepackagedWithToolsExclude(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-no-tools\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"war/target/war-no-tools-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tLibraryCoordinates coordinates = JarModeLibrary.TOOLS.getCoordinates();\n\t\t\tassertThat(coordinates).isNotNull();\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"WEB-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-snapshot\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"WEB-INF/lib/\" + coordinates.getArtifactId());\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenWarIsRepackagedWithTheCustomLayers(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-layered-custom\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"war/target/war-layered-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithNameStartingWith(\"WEB-INF/classes/\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-release\")\n\t\t\t\t.hasEntryWithNameStartingWith(\"WEB-INF/lib/jar-snapshot\");\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tMap<String, List<String>> layerIndex = readLayerIndex(jarFile);\n\t\t\t\tassertThat(layerIndex.keySet()).containsExactly(\"my-dependencies-name\", \"snapshot-dependencies\",\n\t\t\t\t\t\t\"configuration\", \"application\");\n\t\t\t\tassertThat(layerIndex.get(\"application\"))\n\t\t\t\t\t.contains(\"WEB-INF/lib/jar-release-0.0.1.RELEASE.jar\",\n\t\t\t\t\t\t\t\"WEB-INF/lib/jar-snapshot-0.0.1.BUILD-SNAPSHOT.jar\",\n\t\t\t\t\t\t\t\"WEB-INF/lib/jar-classifier-0.0.1-bravo.jar\")\n\t\t\t\t\t.doesNotContain(\"WEB-INF/lib/jar-classifier-0.0.1-alpha.jar\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid repackagedWarContainsClasspathIndex(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/war-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tassertThat(jar(repackaged))\n\t\t\t\t.manifest((manifest) -> manifest.hasAttribute(\"Spring-Boot-Classpath-Index\", \"WEB-INF/classpath.idx\"));\n\t\t\tassertThat(jar(repackaged)).hasEntryWithName(\"WEB-INF/classpath.idx\");\n\t\t\ttry (JarFile jarFile = new JarFile(repackaged)) {\n\t\t\t\tList<String> index = readClasspathIndex(jarFile, \"WEB-INF/classpath.idx\");\n\t\t\t\tassertThat(index)\n\t\t\t\t\t.allMatch((entry) -> entry.startsWith(\"WEB-INF/lib/\") || entry.startsWith(\"WEB-INF/lib-provided/\"));\n\t\t\t}\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenEntryIsExcludedItShouldNotBePresentInTheRepackagedWar(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-exclude-entry\").execute((project) -> {\n\t\t\tFile war = new File(project, \"target/war-exclude-entry-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tassertThat(jar(war)).hasEntryWithNameStartingWith(\"WEB-INF/lib/spring-context\")\n\t\t\t\t.doesNotHaveEntryWithNameStartingWith(\"WEB-INF/lib/spring-core\");\n\t\t});\n\t}\n\n\t@TestTemplate\n\tvoid whenSigned(MavenBuild mavenBuild) {\n\t\tmavenBuild.project(\"war-signed\").execute((project) -> {\n\t\t\tFile repackaged = new File(project, \"target/war-signed-0.0.1.BUILD-SNAPSHOT.war\");\n\t\t\tassertThat(jar(repackaged)).hasEntryWithName(\"META-INF/BOOT.SF\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-arguments/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<arguments>\n\t\t\t\t\t\t\t\t<argument>--spring.profiles.active=abc</argument>\n\t\t\t\t\t\t\t</arguments>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-arguments/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration(proxyBeanMethods = false)\n@Import(TestProfileConfiguration.class)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-arguments/src/main/java/org/test/TestProfileConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\n\n@Configuration(proxyBeanMethods = false)\n@Profile(\"abc\")\nclass TestProfileConfiguration {\n\n\t@Bean\n\tpublic String abc() {\n\t\treturn \"abc\";\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-class-proxy/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-class-proxy</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-class-proxy/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.annotation.EnableAsync;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan\n@EnableAsync\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-class-proxy/src/main/java/org/test/SampleRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class SampleRunner {\n\n\t@Async\n\tpublic void run() {\n\n\t}\n}\n\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-compiler-arguments/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<compilerArguments>-parameters --invalid-compiler-arg</compilerArguments>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-compiler-arguments/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-exclude-devtools</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-exclude-devtools/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-jdk-proxy/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-jdk-proxy</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-jdk-proxy/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.test.SampleApplication.SampleApplicationRuntimeHints;\n\nimport org.springframework.aop.framework.AopProxyUtils;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.stereotype.Service;\n\n@Configuration(proxyBeanMethods = false)\n@ImportRuntimeHints(SampleApplicationRuntimeHints.class)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n\tstatic class SampleApplicationRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {\n\t\t\t// Force creation of at least one JDK proxy\n\t\t\thints.proxies().registerJdkProxy(AopProxyUtils.completeJdkProxyInterfaces(Service.class));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-jvm-arguments/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<jvmArguments>-Dspring.profiles.active=abc</jvmArguments>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-jvm-arguments/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration(proxyBeanMethods = false)\n@Import(TestProfileConfiguration.class)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-jvm-arguments/src/main/java/org/test/TestProfileConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\n\n@Configuration(proxyBeanMethods = false)\n@Profile(\"abc\")\nclass TestProfileConfiguration {\n\n\t@Bean\n\tpublic String abc() {\n\t\treturn \"abc\";\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-module-info/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent> <!-- required to use a recent compiler plugin with old Maven versions -->\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>@project.version@</version>\n\t\t<relativePath/>\n\t</parent>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-module-info</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>repackage</id>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<skip>true</skip>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-module-info/src/main/java/module-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nmodule sampleApp {\n\trequires spring.boot;\n\trequires spring.context;\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-module-info/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-profile/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<profiles>\n\t\t\t\t\t\t\t\t<profile>abc</profile>\n\t\t\t\t\t\t\t</profiles>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-profile/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration(proxyBeanMethods = false)\n@Import(TestProfileConfiguration.class)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-profile/src/main/java/org/test/TestProfileConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\n\n@Configuration(proxyBeanMethods = false)\n@Profile(\"abc\")\nclass TestProfileConfiguration {\n\n\t@Bean\n\tpublic String abc() {\n\t\treturn \"abc\";\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t\t<maven.compiler.release>@java.version@</maven.compiler.release>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-release/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-resource-generation/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-resource-generation</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-resource-generation/src/main/java/org/test/ResourceRegisteringAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n\nclass ResourceRegisteringAotProcessor implements BeanFactoryInitializationAotProcessor {\n\n\t@Override\n\tpublic BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn new BeanFactoryInitializationAotContribution() {\n\n\t\t\t@Override\n\t\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\t\tgenerationContext.getGeneratedFiles().addResourceFile(\"generated-resource\", \"content\");\n\t\t\t\tgenerationContext.getGeneratedFiles().addResourceFile(\"nested/generated-resource\", \"nested content\");\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-resource-generation/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-resource-generation/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\\\norg.test.ResourceRegisteringAotProcessor"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-system-properties/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-system-properties</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<systemPropertyVariables>\n\t\t\t\t\t\t\t\t<spring.profiles.active>abc</spring.profiles.active>\n\t\t\t\t\t\t\t</systemPropertyVariables>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-system-properties/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n@Configuration(proxyBeanMethods = false)\n@Import(TestProfileConfiguration.class)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-system-properties/src/main/java/org/test/TestProfileConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\n\n@Configuration(proxyBeanMethods = false)\n@Profile(\"abc\")\nclass TestProfileConfiguration {\n\n\t@Bean\n\tpublic String abc() {\n\t\treturn \"abc\";\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-test</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-test-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-test</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.assertj</groupId>\n\t\t\t<artifactId>assertj-core</artifactId>\n\t\t\t<version>@assertj.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter</artifactId>\n\t\t\t<version>@junit-jupiter.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test/src/test/java/org/test/SampleApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n package org.test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\n@SpringJUnitConfig\nclass SampleApplicationTests {\n\n\t@Autowired\n\tprivate MyBean myBean;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.myBean).isNotNull();\n\t}\n\n\t@Configuration\n\tstatic class MyConfig {\n\n\t\t@Bean\n\t\tMyBean myBean() {\n\t\t\treturn new MyBean();\n\t\t}\n\n\t}\n\n\tstatic class MyBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-test-exclude-devtools</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-test-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-test</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter</artifactId>\n\t\t\t<version>@junit-jupiter.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-exclude-devtools/src/test/java/org/test/SampleApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass SampleApplicationTests {\n\n\t@Test\n\tvoid contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-skip/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aot-test-skip</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t\t<maven.test.skip>true</maven.test.skip>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>process-test-aot</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-test</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.assertj</groupId>\n\t\t\t<artifactId>assertj-core</artifactId>\n\t\t\t<version>@assertj.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter</artifactId>\n\t\t\t<version>@junit-jupiter.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-skip/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/aot-test-skip/src/test/java/org/test/SampleApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n package org.test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\n@SpringJUnitConfig\nclass SampleApplicationTests {\n\n\t@Autowired\n\tprivate MyBean myBean;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.myBean).isNotNull();\n\t}\n\n\t@Configuration\n\tstatic class MyConfig {\n\n\t\t@Bean\n\t\tMyBean myBean() {\n\t\t\treturn new MyBean();\n\t\t}\n\n\t}\n\n\tstatic class MyBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-additional-properties/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info-additional-properties</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with additional properties</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<additionalProperties>\n\t\t\t\t\t\t\t\t<foo>bar</foo>\n\t\t\t\t\t\t\t\t<encoding>${project.build.sourceEncoding}</encoding>\n\t\t\t\t\t\t\t\t<java.source>1.8</java.source>\n\t\t\t\t\t\t\t</additionalProperties>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-additional-properties/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-custom-build-time/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info-custom-build-time</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with custom build time</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<time>2019-07-08T08:00:00Z</time>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-custom-build-time/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-custom-file/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info-custom-file</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate custom build info</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<outputFile>${project.build.directory}/build.info</outputFile>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-custom-file/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-disable-build-time/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info-disable-build-time</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with disabled build time</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<time>off</time>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-disable-build-time/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-exclude-build-properties/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info-exclude-build-properties</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with excluded build properties</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludeInfoProperties>\n\t\t\t\t\t\t\t\t<excludeInfoProperty>group</excludeInfoProperty>\n\t\t\t\t\t\t\t\t<excludeInfoProperty>artifact</excludeInfoProperty>\n\t\t\t\t\t\t\t\t<excludeInfoProperty>version</excludeInfoProperty>\n\t\t\t\t\t\t\t\t<excludeInfoProperty>name</excludeInfoProperty>\n\t\t\t\t\t\t\t</excludeInfoProperties>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-exclude-build-properties/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-exclude-build-time/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-info-exclude-build-time</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with excluded build time</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludeInfoProperties>\n\t\t\t\t\t\t\t\t<excludeInfoProperty>time</excludeInfoProperty>\n\t\t\t\t\t\t\t</excludeInfoProperties>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-exclude-build-time/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-reproducible/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-reproducible</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with build time from project.build.outputTimestamp</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t\t<project.build.outputTimestamp>2021-04-21T11:22:33Z</project.build.outputTimestamp>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-reproducible/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-reproducible-epoch-seconds/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>build-reproducible-epoch-seconds</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<name>Generate build info with build time from project.build.outputTimestamp</name>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t\t<project.build.outputTimestamp>1619004153</project.build.outputTimestamp>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/build-info-reproducible-epoch-seconds/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>some.random.Main</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-attach-disabled/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-attach-disabled</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<attach>false</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-attach-disabled/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-main/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier-main</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-main/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-main-attach-disabled/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier-main-attach-disabled</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t\t<attach>false</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-main-attach-disabled/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-source/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier-source</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-source/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-source-attach-disabled/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier-source-attach-disabled</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>test</classifier>\n\t\t\t\t\t\t\t<attach>false</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-classifier-source-attach-disabled/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-create-dir/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-create-dir</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<outputDirectory>${project.build.directory}/foo</outputDirectory>\n\t\t\t\t\t\t\t<classifier>foo</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-create-dir/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-dir/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-custom-dir</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<outputDirectory>${project.build.directory}/foo</outputDirectory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-dir/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/custom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>custom</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layoutFactory implementation=\"smoketest.layout.SampleLayoutFactory\">\n\t\t\t\t\t\t\t\t<name>custom</name>\n\t\t\t\t\t\t\t</layoutFactory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t\t\t\t<artifactId>layout</artifactId>\n\t\t\t\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/custom/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/default/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>default</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>1.8</maven.compiler.target>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t\t\t\t<artifactId>layout</artifactId>\n\t\t\t\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/default/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/layout/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>jar-custom-layout</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<packaging>jar</packaging>\n\t<artifactId>layout</artifactId>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-loader-tools</artifactId>\n\t\t\t<version>@project.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/layout/src/main/java/smoketest/layout/SampleLayout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.layout;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport org.springframework.boot.loader.tools.CustomLoaderLayout;\nimport org.springframework.boot.loader.tools.Layouts;\nimport org.springframework.boot.loader.tools.LoaderClassesWriter;\n\n/**\n * An example layout.\n *\n * @author Phillip Webb\n */\npublic class SampleLayout extends Layouts.Jar implements CustomLoaderLayout {\n\n\tprivate String name;\n\n\tpublic SampleLayout(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic void writeLoadedClasses(LoaderClassesWriter writer) throws IOException {\n\t\twriter.writeEntry(this.name, new ByteArrayInputStream(\"test\".getBytes()));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/layout/src/main/java/smoketest/layout/SampleLayoutFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.layout;\n\nimport java.io.File;\n\nimport org.springframework.boot.loader.tools.Layout;\nimport org.springframework.boot.loader.tools.LayoutFactory;\n\npublic class SampleLayoutFactory implements LayoutFactory {\n\n\tprivate String name = \"sample\";\n\n\tpublic SampleLayoutFactory() {\n\t}\n\n\tpublic SampleLayoutFactory(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic Layout getLayout(File source) {\n\t\treturn new SampleLayout(this.name);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/layout/src/main/resources/META-INF/spring.factories",
    "content": "# Layout Factories\norg.springframework.boot.loader.tools.LayoutFactory=\\\nsmoketest.layout.SampleLayoutFactory\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-custom-layout/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-custom-layout</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>layout</module>\n\t\t<module>custom</module>\n\t\t<module>default</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-exclude-entry/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-exclude-entry</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t<exclude>\n\t\t\t\t\t\t\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t\t\t\t\t\t\t<artifactId>servlet-api</artifactId>\n\t\t\t\t\t\t\t\t</exclude>\n\t\t\t\t\t\t\t</excludes>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>servlet-api</artifactId>\n\t\t\t<version>2.5</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-exclude-entry/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-exclude-group/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-exclude-group</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludeGroupIds>org.apache.logging.log4j</excludeGroupIds>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-exclude-group/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-include-entry</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includes>\n\t\t\t\t\t\t\t\t<include>\n\t\t\t\t\t\t\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t\t\t\t\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t\t\t\t\t\t</include>\n\t\t\t\t\t\t\t</includes>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-include-entry/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-layered</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered/jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar-release</module>\n\t\t<module>jar</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-layered</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layers>\n\t\t\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t\t\t\t<configuration>${project.basedir}/src/layers.xml</configuration>\n\t\t\t\t\t\t\t</layers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-classifier</artifactId>\n\t\t\t<version>0.0.1</version>\n\t\t\t<classifier>bravo</classifier>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar/src/layers.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t  https://www.springframework.org/schema/layers/layers-4.1.xsd\">\n\t<application>\n\t\t<into layer=\"configuration\">\n\t\t\t<include>**/application*.*</include>\n\t\t</into>\n\t\t<into layer=\"application\" />\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"application\">\n\t\t\t<includeModuleDependencies />\n\t\t</into>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*-SNAPSHOT</include>\n\t\t</into>\n\t\t<into layer=\"my-dependencies-name\" />\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>my-dependencies-name</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>configuration</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar/src/main/resources/application.yml",
    "content": ""
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar-classifier/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier</artifactId>\n\t<version>0.0.1</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Classifier Jar dependency</description>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>alpha</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>alpha</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n                    <execution>\n                        <id>bravo</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <classifier>bravo</classifier>\n                        </configuration>\n                    </execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-classifier</module>\n\t\t<module>jar-release</module>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-layered</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layers>\n\t\t\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t\t\t\t<configurationName>custom</configurationName>\n\t\t\t\t\t\t\t</layers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t\t\t\t<artifactId>jar-layers-configuration</artifactId>\n\t\t\t\t\t\t<version>0.0.1</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-classifier</artifactId>\n\t\t\t<version>0.0.1</version>\n\t\t\t<classifier>bravo</classifier>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar/src/main/resources/application.yml",
    "content": ""
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar-classifier/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier</artifactId>\n\t<version>0.0.1</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Classifier Jar dependency</description>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>alpha</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>alpha</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t<execution>\n\t\t\t\t\t\t<id>bravo</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>bravo</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar-layers-configuration/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-layers-configuration</artifactId>\n\t<version>0.0.1</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Layers configuration dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar-layers-configuration/src/main/resources/META-INF/spring/layers/custom.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t  https://www.springframework.org/schema/boot/layers/layers-4.1.xsd\">\n\t<application>\n\t\t<into layer=\"configuration\">\n\t\t\t<include>**/application*.*</include>\n\t\t</into>\n\t\t<into layer=\"application\" />\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"application\">\n\t\t\t<includeModuleDependencies />\n\t\t</into>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*-SNAPSHOT</include>\n\t\t</into>\n\t\t<into layer=\"my-dependencies-name\" />\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>my-dependencies-name</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>configuration</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-custom-name/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-classifier</module>\n\t\t<module>jar-layers-configuration</module>\n\t\t<module>jar-release</module>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-disabled/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-layered</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layers>\n\t\t\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t\t\t</layers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-disabled/jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-disabled/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-disabled/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-layered-disabled/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar-release</module>\n\t\t<module>jar</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-lib-name-conflict/acme-lib/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>acme-lib</artifactId>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>jar-lib-name-conflict</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-lib-name-conflict/another-acme-lib/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it.another</groupId>\n\t<artifactId>acme-lib</artifactId>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>jar-lib-name-conflict</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-lib-name-conflict/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-lib-name-conflict</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\n\t<modules>\n\t\t<module>acme-lib</module>\n\t\t<module>another-acme-lib</module>\n\t\t<module>test-project</module>\n\t</modules>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-lib-name-conflict/test-project/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>test-project</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<!-- Two dependencies with the same artifactId -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>acme-lib</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it.another</groupId>\n\t\t\t<artifactId>acme-lib</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-lib-name-conflict/test-project/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-no-tools/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-no-tools</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includeTools>false</includeTools>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-no-tools/jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-no-tools/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-no-tools/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-no-tools/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar-release</module>\n\t\t<module>jar</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-optional-default/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-optional-default</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-optional-default/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-optional-exclude/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-optional-exclude</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includeOptional>false</includeOptional>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-optional-exclude/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-optional-include/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-optional-include</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includeOptional>true</includeOptional>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-optional-include/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-output-timestamp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-output-timestamp</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.build.outputTimestamp>2020-03-16T02:00:00-08:00</project.build.outputTimestamp>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>some.random.Main</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-output-timestamp/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-pom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-pom</artifactId>\n\t<packaging>pom</packaging>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-signed/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-signed</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>some.random.Main</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.bouncycastle</groupId>\n\t\t\t<artifactId>bcprov-jdk18on</artifactId>\n\t\t\t<version>1.78.1</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-signed/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-skip/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-skip</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t<!-- There is no main class on purpose as we skip the whole execution so it shouldn't be necessary -->\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n \t\t\t\t\t\t\t<skip>true</skip>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-system-scope/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-system-scope</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includeSystemScope>true</includeSystemScope>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.example</groupId>\n\t\t\t<artifactId>sample</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t\t<scope>system</scope>\n\t\t\t<systemPath>${project.basedir}/sample-1.0.0.jar</systemPath>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-system-scope/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-system-scope-default/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-system-scope-default</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.example</groupId>\n\t\t\t<artifactId>sample</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t\t<scope>system</scope>\n\t\t\t<systemPath>${project.basedir}/sample-1.0.0.jar</systemPath>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-system-scope-default/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-test-scope/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-test-scope</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-test-scope/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-kotlin-module/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-with-kotlin-module</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>\n\t\t<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t\t<artifactId>kotlin-maven-plugin</artifactId>\n\t\t\t\t<version>@kotlin.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>compile</id>\n\t\t\t\t\t\t<phase>process-resources</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>compile</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>test-compile</id>\n\t\t\t\t\t\t<phase>process-test-resources</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>compile</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t<artifactId>kotlin-stdlib-jdk8</artifactId>\n\t\t\t<version>@kotlin.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t<artifactId>kotlin-reflect</artifactId>\n\t\t\t<version>@kotlin.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t<artifactId>kotlin-compiler</artifactId>\n\t\t\t<version>@kotlin.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-kotlin-module/src/main/kotlin/org/test/SampleApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@file:JvmName(\"SampleApplication\")\npackage org.test;\n\nfun main(args: Array<String>) {\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-layout-property/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-with-layout-property</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-layout-property/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-unpack/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-with-unpack</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<requiresUnpack>\n\t\t\t\t\t\t\t\t<dependency>\n\t\t\t\t\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t\t\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t\t\t\t\t\t</dependency>\n\t\t\t\t\t\t\t</requiresUnpack>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>@maven-jar-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-unpack/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-zip-layout/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-with-zip-layout</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layout>ZIP</layout>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/jar-with-zip-layout/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-additional-classpath-directory/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-additional-classpath-directory</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<additionalClasspathElements>\n\t\t\t\t\t\t<additionalClasspathElement>src/main/additional-elements/</additionalClasspathElement>\n\t\t\t\t\t</additionalClasspathElements>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-additional-classpath-directory/src/main/additional-elements/another/two.txt",
    "content": "2"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-additional-classpath-directory/src/main/additional-elements/one.txt",
    "content": "1"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-additional-classpath-directory/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Scanner;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tif (!readContent(\"one.txt\").contains(\"1\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid content for one.txt\");\n\t\t}\n\t\tif (!readContent(\"another/two.txt\").contains(\"2\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid content for another/two.txt\");\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n\tprivate static String readContent(String location) {\n\t\tInputStream in = SampleApplication.class.getClassLoader().getResourceAsStream(location);\n\t\tif (in == null) {\n\t\t\tthrow new IllegalArgumentException(\"Not found: '\" + location + \"'\");\n\t\t}\n\t\ttry (Scanner scanner = new Scanner(in, StandardCharsets.UTF_8)) {\n\t\t\treturn scanner.useDelimiter(\"\\\\A\").next();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-additional-classpath-jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-additional-classpath-directory</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<additionalClasspathElements>\n\t\t\t\t\t\t<additionalClasspathElement>src/main/additional-jar/resources-1.0.0.jar</additionalClasspathElement>\n\t\t\t\t\t</additionalClasspathElements>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-additional-classpath-jar/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Scanner;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tif (!readContent(\"one.txt\").contains(\"1\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid content for one.txt\");\n\t\t}\n\t\tif (!readContent(\"another/two.txt\").contains(\"2\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid content for another/two.txt\");\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n\tprivate static String readContent(String location) {\n\t\tInputStream in = SampleApplication.class.getClassLoader().getResourceAsStream(location);\n\t\tif (in == null) {\n\t\t\tthrow new IllegalArgumentException(\"Not found: '\" + location + \"'\");\n\t\t}\n\t\ttry (Scanner scanner = new Scanner(in, StandardCharsets.UTF_8)) {\n\t\t\treturn scanner.useDelimiter(\"\\\\A\").next();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-arguments/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-arguments</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<arguments>\n\t\t\t\t\t\t<argument>--management.endpoints.web.exposure.include=prometheus,info</argument>\n\t\t\t\t\t\t<argument>--spring.profiles.active=foo,bar</argument>\n\t\t\t\t\t</arguments>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-arguments/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.util.Arrays;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tif (args.length < 2) {\n\t\t\tthrow new IllegalArgumentException(\"Missing arguments \" + Arrays.toString(args));\n\t\t}\n\t\tif (!args[0].startsWith(\"--management.endpoints.web.exposure.include=\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid argument \" + args[0]);\n\t\t}\n\t\tif (!args[1].startsWith(\"--spring.profiles.active=\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid argument \" + args[1]);\n\t\t}\n\t\tString endpoints = args[0].split(\"=\")[1];\n\t\tString profile = args[1].split(\"=\")[1];\n\t\tSystem.out.println(\"I haz been run with profile(s) '\" + profile + \"' and endpoint(s) '\" + endpoints + \"'\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-arguments-commandline/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-arguments-commandline</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-arguments-commandline/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.util.Arrays;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tif (args.length < 2) {\n\t\t\tthrow new IllegalArgumentException(\"Missing arguments \" + Arrays.toString(args));\n\t\t}\n\t\tif (!args[0].startsWith(\"--management.endpoints.web.exposure.include=\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid argument \" + args[0]);\n\t\t}\n\t\tif (!args[1].startsWith(\"--spring.profiles.active=\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid argument \" + args[1]);\n\t\t}\n\t\tString endpoints = args[0].split(\"=\")[1];\n\t\tString profile = args[1].split(\"=\")[1];\n\t\tSystem.out.println(\"I haz been run with profile(s) '\" + profile + \"' and endpoint(s) '\" + endpoints + \"'\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-envargs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-envargs</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<environmentVariables>\n\t\t\t\t\t\t<ENV1>5000</ENV1>\n\t\t\t\t\t\t<ENV2>Some Text</ENV2>\n\t\t\t\t\t\t<ENV3/>\n\t\t\t\t\t\t<ENV4></ENV4>\n\t\t\t\t\t</environmentVariables>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-envargs/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tassertEnvValue(\"ENV1\", \"5000\");\n\t\tassertEnvValue(\"ENV2\", \"Some Text\");\n\t\tassertEnvValue(\"ENV3\", \"\");\n\t\tassertEnvValue(\"ENV4\", \"\");\n\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n\tprivate static void assertEnvValue(String envKey, String expectedValue) {\n\t\tString actual = System.getenv(envKey);\n\t\tif (!expectedValue.equals(actual)) {\n\t\t\tthrow new IllegalStateException(\"env property [\" + envKey + \"] mismatch \"\n\t\t\t\t\t+ \"(got [\" + actual + \"], expected [\" + expectedValue + \"]\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-exclude/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-exclude</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<excludes>\n\t\t\t\t\t\t<exclude>\n\t\t\t\t\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t\t\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t\t\t\t</exclude>\n\t\t\t\t\t</excludes>\n\t\t\t\t\t<excludeGroupIds>jakarta.servlet,javax.servlet</excludeGroupIds>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-api</artifactId>\n\t\t\t<version>@log4j2.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>servlet-api</artifactId>\n\t\t\t<version>2.5</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-exclude/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tif (isClassPresent(\"org.apache.log4j.Logger\")) {\n\t\t\tthrow new IllegalStateException(\"Log4j was present and should not\");\n\t\t}\n\t\tif (isClassPresent(\"jakarta.servlet.Servlet\")) {\n\t\t\tthrow new IllegalStateException(\"servlet-api was present and should not\");\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n\tprivate static boolean isClassPresent(String className) {\n\n\t\ttry {\n\t\t\tClassLoader classLoader = SampleApplication.class.getClassLoader();\n\t\t\tClass.forName(className, false, classLoader);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (ClassNotFoundException e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-fork/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-fork</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>run</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-fork/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.io.File;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"I haz been run from '\" + new File(\"\").getAbsolutePath() + \"'\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-jvm-system-props/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-jvmargs</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<jvmArguments>-Dfoo=\"value 1\" -Dbar=value2</jvmArguments>\n\t\t\t\t\t<systemPropertyVariables>\n\t\t\t\t\t\t<property1>value1</property1>\n\t\t\t\t\t\t<property2/>\n\t\t\t\t\t\t<property3>${project.artifactId}</property3>\n\t\t\t\t\t\t<foo>should-be-ignored</foo>\n\t\t\t\t\t</systemPropertyVariables>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-jvm-system-props/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tString foo = System.getProperty(\"foo\");\n\t\tif (!\"value 1\".equals(foo)) {\n\t\t\tthrow new IllegalStateException(\"foo system property mismatch (got [\" + foo + \"]\");\n\t\t}\n\t\tString bar = System.getProperty(\"bar\");\n\t\tif (!\"value2\".equals(bar)) {\n\t\t\tthrow new IllegalStateException(\"bar system property mismatch (got [\" + bar + \"]\");\n\t\t}\n\t\tString property1 = System.getProperty(\"property1\");\n\t\tif (!\"value1\".equals(property1)) {\n\t\t\tthrow new IllegalStateException(\"property1 system property mismatch (got [\" + property1 + \"]\");\n\t\t}\n\t\tString property2 = System.getProperty(\"property2\");\n\t\tif (!\"\".equals(property2)) {\n\t\t\tthrow new IllegalStateException(\"property2 system property mismatch (got [\" + property2 + \"]\");\n\t\t}\n\t\tString property3 = System.getProperty(\"property3\");\n\t\tif (!\"run-jvmargs\".equals(property3)) {\n\t\t\tthrow new IllegalStateException(\"property3 system property mismatch (got [\" + property3 + \"]\");\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-jvmargs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-jvmargs</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<jvmArguments>-Dfoo=\"value 1\" -Dbar=value2</jvmArguments>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-jvmargs/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tString foo = System.getProperty(\"foo\");\n\t\tif (!\"value 1\".equals(foo)) {\n\t\t\tthrow new IllegalStateException(\"foo system property mismatch (got [\" + foo + \"]\");\n\t\t}\n\t\tString bar = System.getProperty(\"bar\");\n\t\tif (!\"value2\".equals(bar)) {\n\t\t\tthrow new IllegalStateException(\"bar system property mismatch (got [\" + bar + \"]\");\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-jvmargs-commandline/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-jvmargs-commandline</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-jvmargs-commandline/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tString foo = System.getProperty(\"foo\");\n\t\tif (!\"value-from-cmd\".equals(foo)) {\n\t\t\tthrow new IllegalStateException(\"foo system property mismatch (got [\" + foo + \"]\");\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-profiles/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-profiles</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<profiles>\n\t\t\t\t\t\t<profile>foo</profile>\n\t\t\t\t\t\t<profile>bar</profile>\n\t\t\t\t\t</profiles>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-profiles/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.util.Arrays;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tif (args.length < 1) {\n\t\t\tthrow new IllegalArgumentException(\"Missing active profile argument \" + Arrays.toString(args));\n\t\t}\n\t\tString argument = args[0];\n\t\tif (!argument.startsWith(\"--spring.profiles.active=\")) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid argument \" + argument);\n\t\t}\n\t\tint index = args[0].indexOf('=');\n\t\tString profile = argument.substring(index + 1);\n\t\tSystem.out.println(\"I haz been run with profile(s) '\" + profile + \"'\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-toolchains/jdkHome/bin/java",
    "content": "#!/bin/bash\necho 'The Maven Toolchains is awesome!'\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-toolchains/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-toolchains</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-toolchains-plugin</artifactId>\n\t\t\t\t<version>3.0.0</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>toolchain</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<toolchains>\n\t\t\t\t\t\t<jdk>\n\t\t\t\t\t\t\t<version>42</version>\n\t\t\t\t\t\t\t<vendor>test</vendor>\n\t\t\t\t\t\t</jdk>\n\t\t\t\t\t</toolchains>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>run</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-toolchains/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tthrow new IllegalStateException(\"Should not be called!\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-toolchains/toolchains.xml",
    "content": "<toolchains>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>42</version>\n\t\t\t<vendor>test</vendor>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>jdkHome</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n</toolchains>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-use-test-classpath/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-use-test-classpath</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<useTestClasspath>true</useTestClasspath>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-use-test-classpath/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\n\t\tClass<?> appContext = null;\n\t\ttry {\n\t\t\tappContext = Class.forName(\"org.springframework.context.ApplicationContext\");\n\t\t}\n\t\tcatch (ClassNotFoundException e) {\n\t\t\tthrow new IllegalStateException(\"Test dependencies not added to classpath\", e);\n\t\t}\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-working-directory/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>run-working-directory</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<workingDirectory>${project.build.sourceDirectory}</workingDirectory>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/run-working-directory/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tString workingDirectory =  System.getProperty(\"user.dir\");\n\t\tSystem.out.println(String.format(\"I haz been run from %s\", workingDirectory));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<settings>\n\t<localRepository>@localRepositoryPath@</localRepository>\n\t<servers>\n\t\t<server>\n\t\t\t<id>spring-commercial-release</id>\n\t\t\t<username>${env.COMMERCIAL_REPO_USERNAME}</username>\n\t\t\t<password>${env.COMMERCIAL_REPO_PASSWORD}</password>\n\t\t</server>\n\t\t<server>\n\t\t\t<id>spring-commercial-snapshot</id>\n\t\t\t<username>${env.COMMERCIAL_REPO_USERNAME}</username>\n\t\t\t<password>${env.COMMERCIAL_REPO_PASSWORD}</password>\n\t\t</server>\n\t</servers>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>it-repo</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>local.central</id>\n\t\t\t\t\t<url>@localCentralUrl@</url>\n\t\t\t\t\t<releases>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</releases>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<!-- {spring.mavenRepositories} -->\n\t\t\t</repositories>\n\t\t\t<pluginRepositories>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>local.central</id>\n\t\t\t\t\t<url>@localCentralUrl@</url>\n\t\t\t\t\t<releases>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</releases>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t\t<!-- {spring.mavenPluginRepositories} -->\n\t\t\t</pluginRepositories>\n\t\t</profile>\n\t</profiles>\n</settings>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>start-stop-fork</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>build-helper-maven-plugin</artifactId>\n\t\t\t\t<version>@build-helper-maven-plugin.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>reserve-jmx-port</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>reserve-network-port</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>process-resources</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<portNames>\n\t\t\t\t\t\t\t\t<portName>jmx.port</portName>\n\t\t\t\t\t\t\t</portNames>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>start</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>stop</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<jmxPort>${jmx.port}</jmxPort>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.lang.management.ManagementFactory;\n\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\n/**\n * This sample app simulates the JMX Mbean that is exposed by the Spring Boot application.\n */\npublic class SampleApplication {\n\n\tprivate static final Object lock = new Object();\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tMBeanServer mbs = ManagementFactory.getPlatformMBeanServer();\n\t\tObjectName name = new ObjectName(\n\t\t\t\t\"org.springframework.boot:type=Admin,name=SpringApplication\");\n\t\tSpringApplicationAdmin mbean = new SpringApplicationAdmin();\n\t\tmbs.registerMBean(mbean, name);\n\n\t\t// Flag the app as ready\n\t\tmbean.ready = true;\n\n\t\tint waitAttempts = 0;\n\t\twhile (!mbean.shutdownInvoked) {\n\t\t\tif (waitAttempts > 30) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Shutdown should have been invoked by now\");\n\t\t\t}\n\t\t\tsynchronized (lock) {\n\t\t\t\tlock.wait(250);\n\t\t\t}\n\t\t\twaitAttempts++;\n\t\t}\n\t}\n\n\tpublic interface SpringApplicationAdminMXBean {\n\n\t\tboolean isReady();\n\n\t\tvoid shutdown();\n\n\t}\n\n\tstatic final class SpringApplicationAdmin implements SpringApplicationAdminMXBean {\n\n\t\tprivate boolean ready;\n\n\t\tprivate boolean shutdownInvoked;\n\n\t\t@Override\n\t\tpublic boolean isReady() {\n\t\t\tSystem.out.println(\"isReady: \" + this.ready);\n\t\t\treturn this.ready;\n\t\t}\n\n\t\t@Override\n\t\tpublic void shutdown() {\n\t\t\tthis.shutdownInvoked = true;\n\t\t\tSystem.out.println(\"Shutdown requested\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-skip/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>start-stop-skip</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>start</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-integration-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>stop</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/start-stop-skip/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\n/**\n * This sample should not run at all\n */\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSystem.out.println(\"Ooops, I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/test-run/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>test-run</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/test-run/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"I haz been run\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/test-run/src/test/java/org/test/TestSampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\nimport java.io.File;\nimport java.lang.management.ManagementFactory;\n\npublic class TestSampleApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"Main class name = \" + TestSampleApplication.class.getName());\n\t\tint i = 1;\n\t\tfor (String entry : ManagementFactory.getRuntimeMXBean().getClassPath().split(File.pathSeparator)) {\n\t\t\tSystem.out.println(i++ + \". \" + entry);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-exclude-entry/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war-exclude-entry</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t<exclude>\n\t\t\t\t\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t\t\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t\t\t\t\t\t</exclude>\n\t\t\t\t\t\t\t</excludes>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-exclude-entry/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-exclude-entry/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar-release</module>\n\t\t<module>war</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>aggregator</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>war-layered</artifactId>\n\t<packaging>war</packaging>\n\t<name>war</name>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered/war/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-classifier/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-classifier</artifactId>\n\t<version>0.0.1</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Classifier Jar dependency</description>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>alpha</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>alpha</classifier>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n                    <execution>\n                        <id>bravo</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                        <configuration>\n                            <classifier>bravo</classifier>\n                        </configuration>\n                    </execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-classifier</module>\n\t\t<module>jar-release</module>\n\t\t<module>jar-snapshot</module>\n\t\t<module>war</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>aggregator</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>war-layered</artifactId>\n\t<packaging>war</packaging>\n\t<name>war</name>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layers>\n\t\t\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t\t\t\t<configuration>${project.basedir}/src/layers.xml</configuration>\n\t\t\t\t\t\t\t</layers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-classifier</artifactId>\n\t\t\t<version>0.0.1</version>\n\t\t\t<classifier>bravo</classifier>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/layers.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t  https://www.springframework.org/schema/layers/layers-4.1.xsd\">\n\t<application>\n\t\t<into layer=\"configuration\">\n\t\t\t<include>**/application*.*</include>\n\t\t</into>\n\t\t<into layer=\"application\" />\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"application\">\n\t\t\t<includeModuleDependencies />\n\t\t</into>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*-SNAPSHOT</include>\n\t\t</into>\n\t\t<into layer=\"my-dependencies-name\" />\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>my-dependencies-name</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>configuration</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-custom/war/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar-release</module>\n\t\t<module>war</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>aggregator</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>war-layered</artifactId>\n\t<packaging>war</packaging>\n\t<name>war</name>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<layers>\n\t\t\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t\t\t</layers>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-layered-disabled/war/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-no-tools/jar-release/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-release</artifactId>\n\t<version>0.0.1.RELEASE</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Release Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-no-tools/jar-snapshot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>jar-snapshot</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Snapshot Jar dependency</description>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-no-tools/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>aggregator</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar-snapshot</module>\n\t\t<module>jar-release</module>\n\t\t<module>war</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-no-tools/war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>aggregator</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>war-no-tools</artifactId>\n\t<packaging>war</packaging>\n\t<name>war</name>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includeTools>false</includeTools>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-snapshot</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar-release</artifactId>\n\t\t\t<version>0.0.1.RELEASE</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-no-tools/war/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-no-tools/war/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-output-timestamp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war-output-timestamp</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<project.build.outputTimestamp>2020-03-16T02:00:00-08:00</project.build.outputTimestamp>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-output-timestamp/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-output-timestamp/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-reactor/jar/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>war-reactor</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>jar</artifactId>\n\t<packaging>jar</packaging>\n\t<name>jar</name>\n\t<description>Jar dependency</description>\n\n\t<build>\n\t\t<finalName>jar</finalName>\n\t</build>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-reactor/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war-reactor</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<modules>\n\t\t<module>jar</module>\n\t\t<module>war</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-reactor/war/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t<artifactId>war-reactor</artifactId>\n\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>war</artifactId>\n\t<packaging>war</packaging>\n\t<name>war</name>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot.maven.it</groupId>\n\t\t\t<artifactId>jar</artifactId>\n\t\t\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-reactor/war/src/main/java/com/example/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-reactor/war/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-signed/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war-signed</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>some.random.Main</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.bouncycastle</groupId>\n\t\t\t<artifactId>bcprov-jdk18on</artifactId>\n\t\t\t<version>1.78.1</version>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-signed/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-system-scope/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war-system-scope</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<includeSystemScope>true</includeSystemScope>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.example</groupId>\n\t\t\t<artifactId>sample</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t\t<scope>system</scope>\n\t\t\t<systemPath>${project.basedir}/sample-1.0.0.jar</systemPath>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-system-scope/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-system-scope/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-with-unpack/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot.maven.it</groupId>\n\t<artifactId>war-with-unpack</artifactId>\n\t<version>0.0.1.BUILD-SNAPSHOT</version>\n\t<packaging>war</packaging>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.compiler.source>@java.version@</maven.compiler.source>\n\t\t<maven.compiler.target>@java.version@</maven.compiler.target>\n\t</properties>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>@project.groupId@</groupId>\n\t\t\t\t<artifactId>@project.artifactId@</artifactId>\n\t\t\t\t<version>@project.version@</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<requiresUnpack>\n\t\t\t\t\t\t\t\t<dependency>\n\t\t\t\t\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t\t\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t\t\t\t\t\t</dependency>\n\t\t\t\t\t\t\t</requiresUnpack>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-war-plugin</artifactId>\n\t\t\t\t<version>@maven-war-plugin.version@</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Not-Used>Foo</Not-Used>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-context</artifactId>\n\t\t\t<version>@spring-framework.version@</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.servlet</groupId>\n\t\t\t<artifactId>jakarta.servlet-api</artifactId>\n\t\t\t<version>@jakarta-servlet.version@</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-with-unpack/src/main/java/org/test/SampleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test;\n\npublic class SampleApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/intTest/projects/war-with-unpack/src/main/webapp/index.html",
    "content": "<html></html>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractAotMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport javax.tools.Diagnostic;\nimport javax.tools.DiagnosticListener;\nimport javax.tools.JavaCompiler;\nimport javax.tools.JavaCompiler.CompilationTask;\nimport javax.tools.JavaFileObject;\nimport javax.tools.StandardJavaFileManager;\nimport javax.tools.ToolProvider;\n\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\nimport org.apache.maven.toolchain.ToolchainManager;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Abstract base class for AOT processing MOJOs.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Omar YAYA\n * @since 3.0.0\n */\npublic abstract class AbstractAotMojo extends AbstractDependencyFilterMojo {\n\n\t/**\n\t * The current Maven session. This is used for toolchain manager API calls.\n\t */\n\t@Parameter(defaultValue = \"${session}\", readonly = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MavenSession session;\n\n\t/**\n\t * The toolchain manager to use to locate a custom JDK.\n\t */\n\tprivate final ToolchainManager toolchainManager;\n\n\t/**\n\t * Skip the execution.\n\t */\n\t@Parameter(property = \"spring-boot.aot.skip\", defaultValue = \"false\")\n\tprivate boolean skip;\n\n\t/**\n\t * List of JVM system properties to pass to the AOT process.\n\t */\n\t@Parameter\n\tprivate @Nullable Map<String, String> systemPropertyVariables;\n\n\t/**\n\t * JVM arguments that should be associated with the AOT process. On command line, make\n\t * sure to wrap multiple values between quotes.\n\t */\n\t@Parameter(property = \"spring-boot.aot.jvmArguments\")\n\tprivate @Nullable String jvmArguments;\n\n\t/**\n\t * Arguments that should be provided to the AOT compile process. On command line, make\n\t * sure to wrap multiple values between quotes.\n\t */\n\t@Parameter(property = \"spring-boot.aot.compilerArguments\")\n\tprivate @Nullable String compilerArguments;\n\n\tprotected AbstractAotMojo(ToolchainManager toolchainManager) {\n\t\tthis.toolchainManager = toolchainManager;\n\t}\n\n\t/**\n\t * Return Maven execution session.\n\t * @return session\n\t * @since 3.0.10\n\t */\n\tprotected final MavenSession getSession() {\n\t\treturn this.session;\n\t}\n\n\t@Override\n\tpublic void execute() throws MojoExecutionException, MojoFailureException {\n\t\tif (this.skip) {\n\t\t\tgetLog().debug(\"Skipping AOT execution as per configuration\");\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\texecuteAot();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprotected abstract void executeAot() throws Exception;\n\n\tprotected void generateAotAssets(URL[] classPath, String processorClassName, String... arguments) throws Exception {\n\t\tList<String> command = CommandLineBuilder.forMainClass(processorClassName)\n\t\t\t.withSystemProperties(this.systemPropertyVariables)\n\t\t\t.withJvmArguments(new RunArguments(this.jvmArguments).asArray())\n\t\t\t.withClasspath(classPath)\n\t\t\t.withArguments(arguments)\n\t\t\t.build();\n\t\tif (getLog().isDebugEnabled()) {\n\t\t\tgetLog().debug(\"Generating AOT assets using command: \" + command);\n\t\t}\n\t\tJavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);\n\t\tprocessExecutor.run(this.project.getBasedir(), command, Collections.emptyMap());\n\t}\n\n\tprotected final void compileSourceFiles(URL[] classPath, File sourcesDirectory, File outputDirectory)\n\t\t\tthrows Exception {\n\t\tList<Path> sourceFiles;\n\t\ttry (Stream<Path> pathStream = Files.walk(sourcesDirectory.toPath())) {\n\t\t\tsourceFiles = pathStream.filter(Files::isRegularFile).toList();\n\t\t}\n\t\tif (sourceFiles.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tJavaCompiler compiler = ToolProvider.getSystemJavaCompiler();\n\t\ttry (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) {\n\t\t\tJavaCompilerPluginConfiguration compilerConfiguration = new JavaCompilerPluginConfiguration(this.project);\n\t\t\tList<String> args = new ArrayList<>();\n\t\t\targs.addAll(ClassPath.of(classPath).args(false));\n\t\t\targs.add(\"-d\");\n\t\t\targs.add(outputDirectory.toPath().toAbsolutePath().toString());\n\t\t\tString releaseVersion = compilerConfiguration.getReleaseVersion();\n\t\t\tif (releaseVersion != null) {\n\t\t\t\targs.add(\"--release\");\n\t\t\t\targs.add(releaseVersion);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tString source = compilerConfiguration.getSourceMajorVersion();\n\t\t\t\tif (source != null) {\n\t\t\t\t\targs.add(\"--source\");\n\t\t\t\t\targs.add(source);\n\t\t\t\t}\n\t\t\t\tString target = compilerConfiguration.getTargetMajorVersion();\n\t\t\t\tif (target != null) {\n\t\t\t\t\targs.add(\"--target\");\n\t\t\t\t\targs.add(target);\n\t\t\t\t}\n\t\t\t}\n\t\t\targs.add(\"-parameters\");\n\t\t\targs.addAll(new RunArguments(this.compilerArguments).getArgs());\n\t\t\tIterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromPaths(sourceFiles);\n\t\t\tErrors errors = new Errors();\n\t\t\tCompilationTask task = compiler.getTask(null, fileManager, errors, args, null, compilationUnits);\n\t\t\tboolean result = task.call();\n\t\t\tif (!result || errors.hasReportedErrors()) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to compile generated source\" + errors);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected final URL[] getClassPath(File[] directories, ArtifactsFilter... artifactFilters)\n\t\t\tthrows MojoExecutionException {\n\t\tList<URL> urls = new ArrayList<>();\n\t\tArrays.stream(directories).map(this::toURL).forEach(urls::add);\n\t\turls.addAll(getDependencyURLs(artifactFilters));\n\t\treturn urls.toArray(URL[]::new);\n\t}\n\n\tprotected final void copyAll(Path from, Path to) throws IOException {\n\t\tif (!Files.exists(from)) {\n\t\t\treturn;\n\t\t}\n\t\tList<Path> files;\n\t\ttry (Stream<Path> pathStream = Files.walk(from)) {\n\t\t\tfiles = pathStream.filter(Files::isRegularFile).toList();\n\t\t}\n\t\tfor (Path file : files) {\n\t\t\tString relativeFileName = file.subpath(from.getNameCount(), file.getNameCount()).toString();\n\t\t\tgetLog().debug(\"Copying '\" + relativeFileName + \"' to \" + to);\n\t\t\tPath target = to.resolve(relativeFileName);\n\t\t\tFiles.createDirectories(target.getParent());\n\t\t\tFiles.copy(file, target, StandardCopyOption.REPLACE_EXISTING);\n\t\t}\n\t}\n\n\t/**\n\t * {@link DiagnosticListener} used to collect errors.\n\t */\n\tprotected static class Errors implements DiagnosticListener<JavaFileObject> {\n\n\t\tprivate final StringBuilder message = new StringBuilder();\n\n\t\t@Override\n\t\tpublic void report(Diagnostic<? extends JavaFileObject> diagnostic) {\n\t\t\tif (diagnostic.getKind() == Diagnostic.Kind.ERROR) {\n\t\t\t\tthis.message.append(\"\\n\");\n\t\t\t\tthis.message.append(diagnostic.getMessage(Locale.getDefault()));\n\t\t\t\tif (diagnostic.getSource() != null) {\n\t\t\t\t\tthis.message.append(\" \");\n\t\t\t\t\tthis.message.append(diagnostic.getSource().getName());\n\t\t\t\t\tthis.message.append(\" \");\n\t\t\t\t\tthis.message.append(diagnostic.getLineNumber()).append(\":\").append(diagnostic.getColumnNumber());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tboolean hasReportedErrors() {\n\t\t\treturn !this.message.isEmpty();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.message.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractDependencyFilterMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.StringTokenizer;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.resolver.filter.ArtifactFilter;\nimport org.apache.maven.plugin.AbstractMojo;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProject;\nimport org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\nimport org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A base mojo filtering the dependencies of the project.\n *\n * @author Stephane Nicoll\n * @author David Turanski\n * @since 1.1.0\n */\npublic abstract class AbstractDependencyFilterMojo extends AbstractMojo {\n\n\tstatic final ExcludeFilter DEVTOOLS_EXCLUDE_FILTER;\n\tstatic {\n\t\tExclude exclude = new Exclude();\n\t\texclude.setGroupId(\"org.springframework.boot\");\n\t\texclude.setArtifactId(\"spring-boot-devtools\");\n\t\tDEVTOOLS_EXCLUDE_FILTER = new ExcludeFilter(exclude);\n\t}\n\n\tstatic final ExcludeFilter DOCKER_COMPOSE_EXCLUDE_FILTER;\n\tstatic {\n\t\tExclude exclude = new Exclude();\n\t\texclude.setGroupId(\"org.springframework.boot\");\n\t\texclude.setArtifactId(\"spring-boot-docker-compose\");\n\t\tDOCKER_COMPOSE_EXCLUDE_FILTER = new ExcludeFilter(exclude);\n\t}\n\n\t/**\n\t * The Maven project.\n\t * @since 3.0.0\n\t */\n\t@Parameter(defaultValue = \"${project}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprotected MavenProject project;\n\n\t/**\n\t * Collection of artifact definitions to include. The {@link Include} element defines\n\t * mandatory {@code groupId} and {@code artifactId} components and an optional\n\t * {@code classifier} component. When configured as a property, values should be\n\t * comma-separated with colon-separated components:\n\t * {@code groupId:artifactId,groupId:artifactId:classifier}\n\t * @since 1.2.0\n\t */\n\t@Parameter(property = \"spring-boot.includes\")\n\tprivate @Nullable List<Include> includes;\n\n\t/**\n\t * Collection of artifact definitions to exclude. The {@link Exclude} element defines\n\t * mandatory {@code groupId} and {@code artifactId} components and an optional\n\t * {@code classifier} component. When configured as a property, values should be\n\t * comma-separated with colon-separated components:\n\t * {@code groupId:artifactId,groupId:artifactId:classifier}\n\t * @since 1.1.0\n\t */\n\t@Parameter(property = \"spring-boot.excludes\")\n\tprivate @Nullable List<Exclude> excludes;\n\n\t/**\n\t * Comma separated list of groupId names to exclude (exact match).\n\t * @since 1.1.0\n\t */\n\t@Parameter(property = \"spring-boot.excludeGroupIds\", defaultValue = \"\")\n\tprivate @Nullable String excludeGroupIds;\n\n\tprotected void setExcludes(@Nullable List<Exclude> excludes) {\n\t\tthis.excludes = excludes;\n\t}\n\n\tprotected void setIncludes(@Nullable List<Include> includes) {\n\t\tthis.includes = includes;\n\t}\n\n\tprotected void setExcludeGroupIds(String excludeGroupIds) {\n\t\tthis.excludeGroupIds = excludeGroupIds;\n\t}\n\n\tprotected List<URL> getDependencyURLs(ArtifactsFilter... additionalFilters) throws MojoExecutionException {\n\t\tSet<Artifact> artifacts = filterDependencies(this.project.getArtifacts(), additionalFilters);\n\t\tList<URL> urls = new ArrayList<>();\n\t\tfor (Artifact artifact : artifacts) {\n\t\t\tif (artifact.getFile() != null) {\n\t\t\t\turls.add(toURL(artifact.getFile()));\n\t\t\t}\n\t\t}\n\t\treturn urls;\n\t}\n\n\tprotected final Set<Artifact> filterDependencies(Set<Artifact> dependencies, ArtifactsFilter... additionalFilters)\n\t\t\tthrows MojoExecutionException {\n\t\ttry {\n\t\t\tSet<Artifact> filtered = new LinkedHashSet<>(dependencies);\n\t\t\tfiltered.retainAll(getFilters(additionalFilters).filter(dependencies));\n\t\t\treturn filtered;\n\t\t}\n\t\tcatch (ArtifactFilterException ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprotected URL toURL(File file) {\n\t\ttry {\n\t\t\treturn file.toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid URL for \" + file, ex);\n\t\t}\n\t}\n\n\t/**\n\t * Return artifact filters configured for this MOJO.\n\t * @param additionalFilters optional additional filters to apply\n\t * @return the filters\n\t */\n\tprivate FilterArtifacts getFilters(ArtifactsFilter... additionalFilters) {\n\t\tFilterArtifacts filters = new FilterArtifacts();\n\t\tfor (ArtifactsFilter additionalFilter : additionalFilters) {\n\t\t\tfilters.addFilter(additionalFilter);\n\t\t}\n\t\tfilters.addFilter(new MatchingGroupIdFilter(cleanFilterConfig(this.excludeGroupIds)));\n\t\tif (this.includes != null && !this.includes.isEmpty()) {\n\t\t\tfilters.addFilter(new IncludeFilter(this.includes));\n\t\t}\n\t\tif (this.excludes != null && !this.excludes.isEmpty()) {\n\t\t\tfilters.addFilter(new ExcludeFilter(this.excludes));\n\t\t}\n\t\tfilters.addFilter(new JarTypeFilter());\n\t\treturn filters;\n\t}\n\n\tprivate String cleanFilterConfig(@Nullable String content) {\n\t\tif (content == null || content.trim().isEmpty()) {\n\t\t\treturn \"\";\n\t\t}\n\t\tStringBuilder cleaned = new StringBuilder();\n\t\tStringTokenizer tokenizer = new StringTokenizer(content, \",\");\n\t\twhile (tokenizer.hasMoreElements()) {\n\t\t\tcleaned.append(tokenizer.nextToken().trim());\n\t\t\tif (tokenizer.hasMoreElements()) {\n\t\t\t\tcleaned.append(\",\");\n\t\t\t}\n\t\t}\n\t\treturn cleaned.toString();\n\t}\n\n\t/**\n\t * {@link ArtifactFilter} to exclude test scope dependencies.\n\t */\n\tprotected static class ExcludeTestScopeArtifactFilter extends AbstractArtifactFeatureFilter {\n\n\t\tExcludeTestScopeArtifactFilter() {\n\t\t\tsuper(\"\", Artifact.SCOPE_TEST);\n\t\t}\n\n\t\t@Override\n\t\tprotected String getArtifactFeature(Artifact artifact) {\n\t\t\treturn artifact.getScope();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractPackagerMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.model.Dependency;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.descriptor.PluginDescriptor;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProject;\nimport org.apache.maven.project.MavenProjectHelper;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\nimport org.apache.maven.shared.artifact.filter.collection.ScopeFilter;\nimport org.jspecify.annotations.Nullable;\nimport org.w3c.dom.Document;\nimport org.xml.sax.InputSource;\n\nimport org.springframework.boot.loader.tools.Layout;\nimport org.springframework.boot.loader.tools.LayoutFactory;\nimport org.springframework.boot.loader.tools.Layouts.Expanded;\nimport org.springframework.boot.loader.tools.Layouts.Jar;\nimport org.springframework.boot.loader.tools.Layouts.None;\nimport org.springframework.boot.loader.tools.Layouts.War;\nimport org.springframework.boot.loader.tools.Libraries;\nimport org.springframework.boot.loader.tools.Packager;\nimport org.springframework.boot.loader.tools.layer.CustomLayers;\n\n/**\n * Abstract base class for classes that work with an {@link Packager}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 2.3.0\n */\npublic abstract class AbstractPackagerMojo extends AbstractDependencyFilterMojo {\n\n\tprivate static final org.springframework.boot.loader.tools.Layers IMPLICIT_LAYERS = org.springframework.boot.loader.tools.Layers.IMPLICIT;\n\n\t/**\n\t * The Maven project.\n\t * @since 1.0.0\n\t */\n\t@Parameter(defaultValue = \"${project}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprotected MavenProject project;\n\n\t/**\n\t * The Maven session.\n\t * @since 2.4.0\n\t */\n\t@Parameter(defaultValue = \"${session}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprotected MavenSession session;\n\n\t/**\n\t * The plugin descriptor.\n\t * @since 4.1.0\n\t */\n\t@Parameter(defaultValue = \"${plugin}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate PluginDescriptor pluginDescriptor;\n\n\t/**\n\t * Maven project helper utils.\n\t * @since 1.0.0\n\t */\n\tprotected final MavenProjectHelper projectHelper;\n\n\t/**\n\t * The name of the main class. If not specified the first compiled class found that\n\t * contains a {@code main} method will be used.\n\t * @since 1.0.0\n\t */\n\t@Parameter\n\tprivate @Nullable String mainClass;\n\n\t/**\n\t * Exclude Spring Boot devtools from the repackaged archive.\n\t * @since 1.3.0\n\t */\n\t@Parameter(property = \"spring-boot.repackage.excludeDevtools\", defaultValue = \"true\")\n\tprivate boolean excludeDevtools = true;\n\n\t/**\n\t * Exclude Spring Boot dev services from the repackaged archive.\n\t * @since 3.1.0\n\t */\n\t@Parameter(property = \"spring-boot.repackage.excludeDockerCompose\", defaultValue = \"true\")\n\tprivate boolean excludeDockerCompose = true;\n\n\t/**\n\t * Include system scoped dependencies.\n\t * @since 1.4.0\n\t */\n\t@Parameter(defaultValue = \"false\")\n\tpublic boolean includeSystemScope;\n\n\t/**\n\t * Include optional dependencies.\n\t * @since 3.5.7\n\t */\n\t@Parameter(defaultValue = \"false\")\n\tpublic boolean includeOptional;\n\n\t/**\n\t * Include JAR tools.\n\t * @since 3.3.0\n\t */\n\t@Parameter(defaultValue = \"true\")\n\tpublic boolean includeTools = true;\n\n\t/**\n\t * Layer configuration with options to disable layer creation, exclude layer tools\n\t * jar, and provide a custom layers configuration file.\n\t * @since 2.3.0\n\t */\n\t@Parameter\n\tprivate Layers layers = new Layers();\n\n\tprotected AbstractPackagerMojo(MavenProjectHelper projectHelper) {\n\t\tthis.projectHelper = projectHelper;\n\t}\n\n\t/**\n\t * Return the type of archive that should be packaged by this MOJO.\n\t * @return {@code null}, indicating a layout type will be chosen based on the original\n\t * archive type\n\t */\n\tprotected @Nullable LayoutType getLayout() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the layout factory that will be used to determine the {@link LayoutType} if\n\t * no explicit layout is set.\n\t * @return {@code null}, indicating a default layout factory will be chosen\n\t */\n\tprotected @Nullable LayoutFactory getLayoutFactory() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return a {@link Packager} configured for this MOJO.\n\t * @param <P> the packager type\n\t * @param supplier a packager supplier\n\t * @return a configured packager\n\t */\n\tprotected <P extends Packager> P getConfiguredPackager(Supplier<P> supplier) {\n\t\tP packager = supplier.get();\n\t\tpackager.setLayoutFactory(getLayoutFactory());\n\t\tpackager.addMainClassTimeoutWarningListener(new LoggingMainClassTimeoutWarningListener(this::getLog));\n\t\tpackager.setMainClass(this.mainClass);\n\t\tLayoutType layout = getLayout();\n\t\tif (layout != null) {\n\t\t\tgetLog().info(\"Layout: \" + layout);\n\t\t\tpackager.setLayout(layout.layout());\n\t\t}\n\t\tif (this.layers.isEnabled()) {\n\t\t\tpackager.setLayers(loadLayersConfiguration());\n\t\t}\n\t\tpackager.setIncludeRelevantJarModeJars(getIncludeRelevantJarModeJars());\n\t\treturn packager;\n\t}\n\n\tprivate boolean getIncludeRelevantJarModeJars() {\n\t\treturn this.includeTools;\n\t}\n\n\tprivate org.springframework.boot.loader.tools.Layers loadLayersConfiguration() {\n\t\tFile configuration = this.layers.getConfiguration();\n\t\tif (configuration != null) {\n\t\t\treturn getCustomLayers(configuration.getAbsolutePath(), () -> new FileInputStream(configuration));\n\t\t}\n\t\tString configurationName = this.layers.getConfigurationName();\n\t\tif (configurationName != null) {\n\t\t\tString location = \"META-INF/spring/layers/%s.xml\".formatted(configurationName);\n\t\t\treturn getCustomLayers(location, () -> loadLayersConfigurationFromClasspath(configurationName, location));\n\t\t}\n\t\treturn IMPLICIT_LAYERS;\n\t}\n\n\tprivate InputStream loadLayersConfigurationFromClasspath(String name, String location) {\n\t\tInputStream in = this.pluginDescriptor.getClassRealm().getResourceAsStream(location);\n\t\tif (in == null) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Failed to load layers configuration with name '%s': '%s' not found\".formatted(name, location));\n\t\t}\n\t\treturn in;\n\t}\n\n\tprivate CustomLayers getCustomLayers(String source, InputStreamSource inputStreamSource) {\n\t\ttry {\n\t\t\tDocument document = getDocumentIfAvailable(inputStreamSource);\n\t\t\treturn new CustomLayersProvider().getLayers(document);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to process custom layers configuration \" + source, ex);\n\t\t}\n\t}\n\n\tprivate Document getDocumentIfAvailable(InputStreamSource source) throws Exception {\n\t\ttry (InputStream in = source.getInputStream()) {\n\t\t\tInputSource inputSource = new InputSource(in);\n\t\t\tDocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n\t\t\tfactory.setNamespaceAware(true);\n\t\t\tDocumentBuilder builder = factory.newDocumentBuilder();\n\t\t\treturn builder.parse(inputSource);\n\t\t}\n\t}\n\n\t/**\n\t * Return {@link Libraries} that the packager can use.\n\t * @param unpacks any libraries that require unpack\n\t * @return the libraries to use\n\t * @throws MojoExecutionException on execution error\n\t */\n\tprotected final Libraries getLibraries(@Nullable Collection<Dependency> unpacks) throws MojoExecutionException {\n\t\tSet<Artifact> artifacts = this.project.getArtifacts();\n\t\tSet<Artifact> includedArtifacts = filterDependencies(artifacts, getAdditionalFilters());\n\t\treturn new ArtifactsLibraries(artifacts, includedArtifacts, this.session.getProjects(), unpacks, getLog());\n\t}\n\n\tprivate ArtifactsFilter[] getAdditionalFilters() {\n\t\tList<ArtifactsFilter> filters = new ArrayList<>();\n\t\tif (this.excludeDevtools) {\n\t\t\tfilters.add(DEVTOOLS_EXCLUDE_FILTER);\n\t\t}\n\t\tif (this.excludeDockerCompose) {\n\t\t\tfilters.add(DOCKER_COMPOSE_EXCLUDE_FILTER);\n\t\t}\n\t\tif (!this.includeSystemScope) {\n\t\t\tfilters.add(new ScopeFilter(null, Artifact.SCOPE_SYSTEM));\n\t\t}\n\t\tif (!this.includeOptional) {\n\t\t\tfilters.add(DependencyFilter.exclude(Artifact::isOptional));\n\t\t}\n\t\treturn filters.toArray(new ArtifactsFilter[0]);\n\t}\n\n\t/**\n\t * Return the source {@link Artifact} to repackage. If a classifier is specified and\n\t * an artifact with that classifier exists, it is used. Otherwise, the main artifact\n\t * is used.\n\t * @param classifier the artifact classifier\n\t * @return the source artifact to repackage\n\t */\n\tprotected Artifact getSourceArtifact(@Nullable String classifier) {\n\t\tArtifact sourceArtifact = getArtifact(classifier);\n\t\treturn (sourceArtifact != null) ? sourceArtifact : this.project.getArtifact();\n\t}\n\n\tprivate @Nullable Artifact getArtifact(@Nullable String classifier) {\n\t\tif (classifier != null) {\n\t\t\tfor (Artifact attachedArtifact : this.project.getAttachedArtifacts()) {\n\t\t\t\tif (classifier.equals(attachedArtifact.getClassifier()) && attachedArtifact.getFile() != null\n\t\t\t\t\t\t&& attachedArtifact.getFile().isFile()) {\n\t\t\t\t\treturn attachedArtifact;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprotected File getTargetFile(String finalName, @Nullable String classifier, File targetDirectory) {\n\t\tString classifierSuffix = (classifier != null) ? classifier.trim() : \"\";\n\t\tif (!classifierSuffix.isEmpty() && !classifierSuffix.startsWith(\"-\")) {\n\t\t\tclassifierSuffix = \"-\" + classifierSuffix;\n\t\t}\n\t\tif (!targetDirectory.exists()) {\n\t\t\ttargetDirectory.mkdirs();\n\t\t}\n\t\treturn new File(targetDirectory,\n\t\t\t\tfinalName + classifierSuffix + \".\" + this.project.getArtifact().getArtifactHandler().getExtension());\n\t}\n\n\t/**\n\t * Archive layout types.\n\t */\n\tpublic enum LayoutType {\n\n\t\t/**\n\t\t * Jar Layout.\n\t\t */\n\t\tJAR(new Jar()),\n\n\t\t/**\n\t\t * War Layout.\n\t\t */\n\t\tWAR(new War()),\n\n\t\t/**\n\t\t * Zip Layout.\n\t\t */\n\t\tZIP(new Expanded()),\n\n\t\t/**\n\t\t * Directory Layout.\n\t\t */\n\t\tDIR(new Expanded()),\n\n\t\t/**\n\t\t * No Layout.\n\t\t */\n\t\tNONE(new None());\n\n\t\tprivate final Layout layout;\n\n\t\tLayoutType(Layout layout) {\n\t\t\tthis.layout = layout;\n\t\t}\n\n\t\tpublic Layout layout() {\n\t\t\treturn this.layout;\n\t\t}\n\n\t}\n\n\t@FunctionalInterface\n\tprivate interface InputStreamSource {\n\n\t\tInputStream getInputStream() throws IOException;\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/AbstractRunMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.model.Resource;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProject;\nimport org.apache.maven.toolchain.ToolchainManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.FileUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class to run a Spring Boot application.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author David Liu\n * @author Daniel Young\n * @author Dmytro Nosan\n * @author Moritz Halbritter\n * @since 1.3.0\n * @see RunMojo\n * @see StartMojo\n */\npublic abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {\n\n\t/**\n\t * The Maven project.\n\t *\n\t * @since 1.0.0\n\t */\n\t@Parameter(defaultValue = \"${project}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MavenProject project;\n\n\t/**\n\t * The current Maven session. This is used for toolchain manager API calls.\n\t *\n\t * @since 2.3.0\n\t */\n\t@Parameter(defaultValue = \"${session}\", readonly = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MavenSession session;\n\n\t/**\n\t * The toolchain manager to use to locate a custom JDK.\n\t *\n\t * @since 2.3.0\n\t */\n\tprivate final ToolchainManager toolchainManager;\n\n\t/**\n\t * Add maven resources to the classpath directly, this allows live in-place editing of\n\t * resources. Duplicate resources are removed from {@code target/classes} to prevent\n\t * them from appearing twice if {@code ClassLoader.getResources()} is called. Please\n\t * consider adding {@code spring-boot-devtools} to your project instead as it provides\n\t * this feature and many more.\n\t *\n\t * @since 1.0.0\n\t */\n\t@Parameter(property = \"spring-boot.run.addResources\", defaultValue = \"false\")\n\tprivate boolean addResources;\n\n\t/**\n\t * Path to agent jars.\n\t *\n\t * @since 2.2.0\n\t */\n\t@Parameter(property = \"spring-boot.run.agents\")\n\t@SuppressWarnings(\"NullAway\") // maven-maven-plugin can't handle annotated arrays\n\tprivate File[] agents;\n\n\t/**\n\t * Flag to say that the agent requires -noverify.\n\t *\n\t * @since 1.0.0\n\t */\n\t@Parameter(property = \"spring-boot.run.noverify\")\n\tprivate boolean noverify;\n\n\t/**\n\t * Current working directory to use for the application. If not specified, basedir\n\t * will be used.\n\t *\n\t * @since 1.5.0\n\t */\n\t@Parameter(property = \"spring-boot.run.workingDirectory\")\n\tprivate @Nullable File workingDirectory;\n\n\t/**\n\t * JVM arguments that should be associated with the forked process used to run the\n\t * application. On command line, make sure to wrap multiple values between quotes.\n\t *\n\t * @since 1.1.0\n\t */\n\t@Parameter(property = \"spring-boot.run.jvmArguments\")\n\tprivate @Nullable String jvmArguments;\n\n\t/**\n\t * List of JVM system properties to pass to the process.\n\t *\n\t * @since 2.1.0\n\t */\n\t@Parameter\n\tprivate @Nullable Map<String, String> systemPropertyVariables;\n\n\t/**\n\t * List of Environment variables that should be associated with the forked process\n\t * used to run the application.\n\t *\n\t * @since 2.1.0\n\t */\n\t@Parameter\n\tprivate @Nullable Map<String, String> environmentVariables;\n\n\t/**\n\t * Arguments that should be passed to the application.\n\t *\n\t * @since 1.0.0\n\t */\n\t@Parameter\n\t@SuppressWarnings(\"NullAway\") // maven-maven-plugin can't handle annotated arrays\n\tprivate String[] arguments;\n\n\t/**\n\t * Arguments from the command line that should be passed to the application. Use\n\t * spaces to separate multiple arguments and make sure to wrap multiple values between\n\t * quotes. When specified, takes precedence over {@link #arguments}.\n\t *\n\t * @since 2.2.3\n\t */\n\t@Parameter(property = \"spring-boot.run.arguments\")\n\tprivate @Nullable String commandlineArguments;\n\n\t/**\n\t * The spring profiles to activate. Convenience shortcut of specifying the\n\t * 'spring.profiles.active' argument. On command line use commas to separate multiple\n\t * profiles.\n\t *\n\t * @since 1.3.0\n\t */\n\t@Parameter(property = \"spring-boot.run.profiles\")\n\t@SuppressWarnings(\"NullAway\") // maven-maven-plugin can't handle annotated arrays\n\tprivate String[] profiles;\n\n\t/**\n\t * The name of the main class. If not specified the first compiled class found that\n\t * contains a 'main' method will be used.\n\t *\n\t * @since 1.0.0\n\t */\n\t@Parameter(property = \"spring-boot.run.main-class\")\n\tprivate @Nullable String mainClass;\n\n\t/**\n\t * Additional classpath elements that should be added to the classpath. An element can\n\t * be a directory with classes and resources or a jar file.\n\t *\n\t * @since 3.2.0\n\t */\n\t@Parameter(property = \"spring-boot.run.additional-classpath-elements\")\n\t@SuppressWarnings(\"NullAway\") // maven-maven-plugin can't handle annotated arrays\n\tprivate String[] additionalClasspathElements;\n\n\t/**\n\t * Directory containing the classes and resource files that should be used to run the\n\t * application.\n\t *\n\t * @since 1.0.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.outputDirectory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File classesDirectory;\n\n\t/**\n\t * Skip the execution.\n\t *\n\t * @since 1.3.2\n\t */\n\t@Parameter(property = \"spring-boot.run.skip\", defaultValue = \"false\")\n\tprivate boolean skip;\n\n\tprotected AbstractRunMojo(ToolchainManager toolchainManager) {\n\t\tthis.toolchainManager = toolchainManager;\n\t}\n\n\t@Override\n\tpublic void execute() throws MojoExecutionException, MojoFailureException {\n\t\tif (this.skip) {\n\t\t\tgetLog().debug(\"skipping run as per configuration.\");\n\t\t\treturn;\n\t\t}\n\t\trun(determineMainClass());\n\t}\n\n\tprivate String determineMainClass() throws MojoExecutionException {\n\t\tif (this.mainClass != null) {\n\t\t\treturn this.mainClass;\n\t\t}\n\t\treturn SpringBootApplicationClassFinder.findSingleClass(getClassesDirectories());\n\t}\n\n\t/**\n\t * Returns the directories that contain the application's classes and resources. When\n\t * the application's main class has not been configured, each directory is searched in\n\t * turn for an appropriate main class.\n\t * @return the directories that contain the application's classes and resources\n\t * @since 3.1.0\n\t */\n\tprotected List<File> getClassesDirectories() {\n\t\treturn List.of(this.classesDirectory);\n\t}\n\n\tprotected abstract boolean isUseTestClasspath();\n\n\tprivate void run(String startClassName) throws MojoExecutionException, MojoFailureException {\n\t\tList<String> args = new ArrayList<>();\n\t\taddAgents(args);\n\t\taddJvmArgs(args);\n\t\taddClasspath(args);\n\t\targs.add(startClassName);\n\t\taddArgs(args);\n\t\tJavaProcessExecutor processExecutor = new JavaProcessExecutor(this.session, this.toolchainManager);\n\t\tFile workingDirectoryToUse = (this.workingDirectory != null) ? this.workingDirectory\n\t\t\t\t: this.project.getBasedir();\n\t\tif (getLog().isDebugEnabled()) {\n\t\t\tgetLog().debug(\"Working directory: \" + workingDirectoryToUse);\n\t\t\tgetLog().debug(\"Java arguments: \" + String.join(\" \", args));\n\t\t}\n\t\trun(processExecutor, workingDirectoryToUse, args, determineEnvironmentVariables());\n\t}\n\n\t/**\n\t * Run the application.\n\t * @param processExecutor the {@link JavaProcessExecutor} to use\n\t * @param workingDirectory the working directory of the forked JVM\n\t * @param args the arguments (JVM arguments and application arguments)\n\t * @param environmentVariables the environment variables\n\t * @throws MojoExecutionException in case of MOJO execution errors\n\t * @throws MojoFailureException in case of MOJO failures\n\t * @since 3.0.0\n\t */\n\tprotected abstract void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,\n\t\t\tMap<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException;\n\n\t/**\n\t * Resolve the application arguments to use.\n\t * @return a {@link RunArguments} defining the application arguments\n\t */\n\tprotected RunArguments resolveApplicationArguments() {\n\t\tRunArguments runArguments = (this.arguments != null) ? new RunArguments(this.arguments)\n\t\t\t\t: new RunArguments(this.commandlineArguments);\n\t\taddActiveProfileArgument(runArguments);\n\t\treturn runArguments;\n\t}\n\n\t/**\n\t * Resolve the environment variables to use.\n\t * @return an {@link EnvVariables} defining the environment variables\n\t */\n\tprotected EnvVariables resolveEnvVariables() {\n\t\treturn new EnvVariables(this.environmentVariables);\n\t}\n\n\tprivate void addArgs(List<String> args) {\n\t\tRunArguments applicationArguments = resolveApplicationArguments();\n\t\tCollections.addAll(args, applicationArguments.asArray());\n\t\tlogArguments(\"Application argument\", applicationArguments.asArray());\n\t}\n\n\tprivate Map<String, String> determineEnvironmentVariables() {\n\t\tEnvVariables envVariables = resolveEnvVariables();\n\t\tlogArguments(\"Environment variable\", envVariables.asArray());\n\t\treturn envVariables.asMap();\n\t}\n\n\t/**\n\t * Resolve the JVM arguments to use.\n\t * @return a {@link RunArguments} defining the JVM arguments\n\t */\n\tprotected RunArguments resolveJvmArguments() {\n\t\tList<@Nullable String> arguments = new ArrayList<>();\n\t\tif (this.systemPropertyVariables != null) {\n\t\t\tfor (Entry<String, String> systemProperty : this.systemPropertyVariables.entrySet()) {\n\t\t\t\tString argument = SystemPropertyFormatter.format(systemProperty.getKey(), systemProperty.getValue());\n\t\t\t\tif (StringUtils.hasText(argument)) {\n\t\t\t\t\targuments.add(argument);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (this.jvmArguments != null) {\n\t\t\tString[] jvmArguments = RunArguments.parseArgs(this.jvmArguments);\n\t\t\targuments.addAll(Arrays.asList(jvmArguments));\n\t\t}\n\t\treturn new RunArguments(arguments);\n\t}\n\n\tprivate void addJvmArgs(List<String> args) {\n\t\tRunArguments jvmArguments = resolveJvmArguments();\n\t\tCollections.addAll(args, jvmArguments.asArray());\n\t\tlogArguments(\"JVM argument\", jvmArguments.asArray());\n\t}\n\n\tprivate void addAgents(List<String> args) {\n\t\tif (this.agents != null) {\n\t\t\tif (getLog().isInfoEnabled()) {\n\t\t\t\tgetLog().info(\"Attaching agents: \" + Arrays.asList(this.agents));\n\t\t\t}\n\t\t\tfor (File agent : this.agents) {\n\t\t\t\targs.add(\"-javaagent:\" + agent);\n\t\t\t}\n\t\t}\n\t\tif (this.noverify) {\n\t\t\targs.add(\"-noverify\");\n\t\t}\n\t}\n\n\tprivate void addActiveProfileArgument(RunArguments arguments) {\n\t\tif (this.profiles != null && this.profiles.length > 0) {\n\t\t\tStringBuilder arg = new StringBuilder(\"--spring.profiles.active=\");\n\t\t\tfor (int i = 0; i < this.profiles.length; i++) {\n\t\t\t\targ.append(this.profiles[i]);\n\t\t\t\tif (i < this.profiles.length - 1) {\n\t\t\t\t\targ.append(\",\");\n\t\t\t\t}\n\t\t\t}\n\t\t\targuments.getArgs().addFirst(arg.toString());\n\t\t\tlogArguments(\"Active profile\", this.profiles);\n\t\t}\n\t}\n\n\tprivate void addClasspath(List<String> args) throws MojoExecutionException {\n\t\ttry {\n\t\t\tClassPath classpath = ClassPath.of(getClassPathUrls());\n\t\t\tif (getLog().isDebugEnabled()) {\n\t\t\t\tgetLog().debug(\"Classpath for forked process: \" + classpath);\n\t\t\t}\n\t\t\targs.addAll(classpath.args(true));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MojoExecutionException(\"Could not build classpath\", ex);\n\t\t}\n\t}\n\n\tprotected URL[] getClassPathUrls() throws MojoExecutionException {\n\t\ttry {\n\t\t\tList<URL> urls = new ArrayList<>();\n\t\t\taddAdditionalClasspathLocations(urls);\n\t\t\taddResources(urls);\n\t\t\taddProjectClasses(urls);\n\t\t\taddDependencies(urls);\n\t\t\treturn urls.toArray(new URL[0]);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(\"Unable to build classpath\", ex);\n\t\t}\n\t}\n\n\tprivate void addAdditionalClasspathLocations(List<URL> urls) throws MalformedURLException {\n\t\tif (this.additionalClasspathElements != null) {\n\t\t\tfor (String element : this.additionalClasspathElements) {\n\t\t\t\turls.add(new File(element).toURI().toURL());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addResources(List<URL> urls) throws IOException {\n\t\tif (this.addResources) {\n\t\t\tfor (Resource resource : this.project.getResources()) {\n\t\t\t\tFile directory = new File(resource.getDirectory());\n\t\t\t\turls.add(directory.toURI().toURL());\n\t\t\t\tfor (File classesDirectory : getClassesDirectories()) {\n\t\t\t\t\tFileUtils.removeDuplicatesFromOutputDirectory(classesDirectory, directory);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addProjectClasses(List<URL> urls) throws MalformedURLException {\n\t\tfor (File classesDirectory : getClassesDirectories()) {\n\t\t\turls.add(classesDirectory.toURI().toURL());\n\t\t}\n\t}\n\n\tprivate void addDependencies(List<URL> urls) throws MalformedURLException, MojoExecutionException {\n\t\tSet<Artifact> artifacts = (isUseTestClasspath()) ? filterDependencies(this.project.getArtifacts())\n\t\t\t\t: filterDependencies(this.project.getArtifacts(), new ExcludeTestScopeArtifactFilter());\n\t\tfor (Artifact artifact : artifacts) {\n\t\t\tif (artifact.getFile() != null) {\n\t\t\t\turls.add(artifact.getFile().toURI().toURL());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void logArguments(String name, String[] args) {\n\t\tif (getLog().isDebugEnabled()) {\n\t\t\tString message = (args.length == 1) ? name + \": \" : name + \"s: \";\n\t\t\tgetLog().debug(Arrays.stream(args).collect(Collectors.joining(\" \", message, \"\")));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ArtifactsLibraries.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.model.Dependency;\nimport org.apache.maven.plugin.logging.Log;\nimport org.apache.maven.project.MavenProject;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.Libraries;\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCallback;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.boot.loader.tools.LibraryScope;\n\n/**\n * {@link Libraries} backed by Maven {@link Artifact}s.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 1.0.0\n */\npublic class ArtifactsLibraries implements Libraries {\n\n\tprivate static final Map<String, LibraryScope> SCOPES;\n\n\tstatic {\n\t\tMap<String, LibraryScope> libraryScopes = new HashMap<>();\n\t\tlibraryScopes.put(Artifact.SCOPE_COMPILE, LibraryScope.COMPILE);\n\t\tlibraryScopes.put(Artifact.SCOPE_RUNTIME, LibraryScope.RUNTIME);\n\t\tlibraryScopes.put(Artifact.SCOPE_PROVIDED, LibraryScope.PROVIDED);\n\t\tlibraryScopes.put(Artifact.SCOPE_SYSTEM, LibraryScope.PROVIDED);\n\t\tSCOPES = Collections.unmodifiableMap(libraryScopes);\n\t}\n\n\tprivate final Set<Artifact> artifacts;\n\n\tprivate final Set<Artifact> includedArtifacts;\n\n\tprivate final Collection<MavenProject> localProjects;\n\n\tprivate final @Nullable Collection<Dependency> unpacks;\n\n\tprivate final Log log;\n\n\t/**\n\t * Creates a new {@code ArtifactsLibraries} from the given {@code artifacts}.\n\t * @param artifacts the artifacts to represent as libraries\n\t * @param localProjects projects for which {@link Library#isLocal() local} libraries\n\t * should be created\n\t * @param unpacks artifacts that should be unpacked on launch\n\t * @param log the log\n\t * @since 2.4.0\n\t */\n\tpublic ArtifactsLibraries(Set<Artifact> artifacts, Collection<MavenProject> localProjects,\n\t\t\t@Nullable Collection<Dependency> unpacks, Log log) {\n\t\tthis(artifacts, artifacts, localProjects, unpacks, log);\n\t}\n\n\t/**\n\t * Creates a new {@code ArtifactsLibraries} from the given {@code artifacts}.\n\t * @param artifacts all artifacts that can be represented as libraries\n\t * @param includedArtifacts the actual artifacts to include in the uber jar\n\t * @param localProjects projects for which {@link Library#isLocal() local} libraries\n\t * should be created\n\t * @param unpacks artifacts that should be unpacked on launch\n\t * @param log the log\n\t * @since 2.4.8\n\t */\n\tpublic ArtifactsLibraries(Set<Artifact> artifacts, Set<Artifact> includedArtifacts,\n\t\t\tCollection<MavenProject> localProjects, @Nullable Collection<Dependency> unpacks, Log log) {\n\t\tthis.artifacts = artifacts;\n\t\tthis.includedArtifacts = includedArtifacts;\n\t\tthis.localProjects = localProjects;\n\t\tthis.unpacks = unpacks;\n\t\tthis.log = log;\n\t}\n\n\t@Override\n\tpublic void doWithLibraries(LibraryCallback callback) throws IOException {\n\t\tSet<String> duplicates = getDuplicates(this.artifacts);\n\t\tfor (Artifact artifact : this.artifacts) {\n\t\t\tString name = getFileName(artifact);\n\t\t\tFile file = artifact.getFile();\n\t\t\tLibraryScope scope = SCOPES.get(artifact.getScope());\n\t\t\tif (scope == null || file == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (duplicates.contains(name)) {\n\t\t\t\tthis.log.debug(\"Duplicate found: \" + name);\n\t\t\t\tname = artifact.getGroupId() + \"-\" + name;\n\t\t\t\tthis.log.debug(\"Renamed to: \" + name);\n\t\t\t}\n\t\t\tLibraryCoordinates coordinates = new ArtifactLibraryCoordinates(artifact);\n\t\t\tboolean unpackRequired = isUnpackRequired(artifact);\n\t\t\tboolean local = isLocal(artifact);\n\t\t\tboolean included = this.includedArtifacts.contains(artifact);\n\t\t\tcallback.library(new Library(name, file, scope, coordinates, unpackRequired, local, included));\n\t\t}\n\t}\n\n\tprivate Set<String> getDuplicates(Set<Artifact> artifacts) {\n\t\tSet<String> duplicates = new HashSet<>();\n\t\tSet<String> seen = new HashSet<>();\n\t\tfor (Artifact artifact : artifacts) {\n\t\t\tString fileName = getFileName(artifact);\n\t\t\tif (artifact.getFile() != null && !seen.add(fileName)) {\n\t\t\t\tduplicates.add(fileName);\n\t\t\t}\n\t\t}\n\t\treturn duplicates;\n\t}\n\n\tprivate boolean isUnpackRequired(Artifact artifact) {\n\t\tif (this.unpacks != null) {\n\t\t\tfor (Dependency unpack : this.unpacks) {\n\t\t\t\tif (artifact.getGroupId().equals(unpack.getGroupId())\n\t\t\t\t\t\t&& artifact.getArtifactId().equals(unpack.getArtifactId())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isLocal(Artifact artifact) {\n\t\tfor (MavenProject localProject : this.localProjects) {\n\t\t\tif (localProject.getArtifact().equals(artifact)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (Artifact attachedArtifact : localProject.getAttachedArtifacts()) {\n\t\t\t\tif (attachedArtifact.equals(artifact)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate String getFileName(Artifact artifact) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tsb.append(artifact.getArtifactId()).append(\"-\").append(artifact.getBaseVersion());\n\t\tString classifier = artifact.getClassifier();\n\t\tif (classifier != null) {\n\t\t\tsb.append(\"-\").append(classifier);\n\t\t}\n\t\tsb.append(\".\").append(artifact.getArtifactHandler().getExtension());\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * {@link LibraryCoordinates} backed by a Maven {@link Artifact}.\n\t */\n\tprivate static class ArtifactLibraryCoordinates implements LibraryCoordinates {\n\n\t\tprivate final Artifact artifact;\n\n\t\tArtifactLibraryCoordinates(Artifact artifact) {\n\t\t\tthis.artifact = artifact;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getGroupId() {\n\t\t\treturn this.artifact.getGroupId();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getArtifactId() {\n\t\t\treturn this.artifact.getArtifactId();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getVersion() {\n\t\t\treturn this.artifact.getBaseVersion();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.artifact.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageForkMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.plugins.annotations.Execute;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.project.MavenProjectHelper;\n\n/**\n * Package an application into an OCI image using a buildpack, forking the lifecycle to\n * make sure that {@code package} ran. This goal is suitable for command-line invocation.\n * If you need to configure a goal {@code execution} in your build, use\n * {@code build-image-no-fork} instead.\n *\n * @author Stephane Nicoll\n * @since 3.0.0\n */\n@Mojo(name = \"build-image\", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true,\n\t\trequiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,\n\t\trequiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)\n@Execute(phase = LifecyclePhase.PACKAGE)\npublic class BuildImageForkMojo extends BuildImageMojo {\n\n\t@Inject\n\tpublic BuildImageForkMojo(MavenProjectHelper projectHelper) {\n\t\tsuper(projectHelper);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.archivers.tar.TarConstants;\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.logging.Log;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProjectHelper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.AbstractBuildLog;\nimport org.springframework.boot.buildpack.platform.build.BuildLog;\nimport org.springframework.boot.buildpack.platform.build.BuildRequest;\nimport org.springframework.boot.buildpack.platform.build.Builder;\nimport org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;\nimport org.springframework.boot.buildpack.platform.build.Creator;\nimport org.springframework.boot.buildpack.platform.build.PullPolicy;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.loader.tools.EntryWriter;\nimport org.springframework.boot.loader.tools.ImagePackager;\nimport org.springframework.boot.loader.tools.LayoutFactory;\nimport org.springframework.boot.loader.tools.Libraries;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Package an application into an OCI image using a buildpack.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n * @since 2.3.0\n */\npublic abstract class BuildImageMojo extends AbstractPackagerMojo {\n\n\tstatic {\n\t\tSystem.setProperty(\"org.slf4j.simpleLogger.log.org.apache.http.wire\", \"ERROR\");\n\t}\n\n\t/**\n\t * Directory containing the source archive.\n\t * @since 2.3.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File sourceDirectory;\n\n\t/**\n\t * Name of the source archive.\n\t * @since 2.3.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.finalName}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String finalName;\n\n\t/**\n\t * Skip the execution.\n\t * @since 2.3.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.skip\", defaultValue = \"false\")\n\tprivate boolean skip;\n\n\t/**\n\t * Classifier used when finding the source archive.\n\t * @since 2.3.0\n\t */\n\t@Parameter\n\tprivate @Nullable String classifier;\n\n\t/**\n\t * Image configuration, with {@code builder}, {@code runImage}, {@code name},\n\t * {@code env}, {@code cleanCache}, {@code verboseLogging}, {@code pullPolicy}, and\n\t * {@code publish} options.\n\t * @since 2.3.0\n\t */\n\t@Parameter\n\tprivate @Nullable Image image;\n\n\t/**\n\t * Alias for {@link Image#name} to support configuration through command-line\n\t * property.\n\t * @since 2.3.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.imageName\")\n\t@Nullable String imageName;\n\n\t/**\n\t * Alias for {@link Image#builder} to support configuration through command-line\n\t * property.\n\t * @since 2.3.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.builder\")\n\t@Nullable String imageBuilder;\n\n\t/**\n\t * Alias for {@link Image#trustBuilder} to support configuration through command-line\n\t * property.\n\t */\n\t@Parameter(property = \"spring-boot.build-image.trustBuilder\")\n\t@Nullable Boolean trustBuilder;\n\n\t/**\n\t * Alias for {@link Image#runImage} to support configuration through command-line\n\t * property.\n\t * @since 2.3.1\n\t */\n\t@Parameter(property = \"spring-boot.build-image.runImage\")\n\t@Nullable String runImage;\n\n\t/**\n\t * Alias for {@link Image#cleanCache} to support configuration through command-line\n\t * property.\n\t * @since 2.4.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.cleanCache\")\n\t@Nullable Boolean cleanCache;\n\n\t/**\n\t * Alias for {@link Image#pullPolicy} to support configuration through command-line\n\t * property.\n\t */\n\t@Parameter(property = \"spring-boot.build-image.pullPolicy\")\n\t@Nullable PullPolicy pullPolicy;\n\n\t/**\n\t * Alias for {@link Image#publish} to support configuration through command-line\n\t * property.\n\t */\n\t@Parameter(property = \"spring-boot.build-image.publish\")\n\t@Nullable Boolean publish;\n\n\t/**\n\t * Alias for {@link Image#network} to support configuration through command-line\n\t * property.\n\t * @since 2.6.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.network\")\n\t@Nullable String network;\n\n\t/**\n\t * Alias for {@link Image#createdDate} to support configuration through command-line\n\t * property.\n\t * @since 3.1.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.createdDate\")\n\t@Nullable String createdDate;\n\n\t/**\n\t * Alias for {@link Image#applicationDirectory} to support configuration through\n\t * command-line property.\n\t * @since 3.1.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.applicationDirectory\")\n\t@Nullable String applicationDirectory;\n\n\t/**\n\t * Alias for {@link Image#imagePlatform} to support configuration through command-line\n\t * property.\n\t * @since 3.4.0\n\t */\n\t@Parameter(property = \"spring-boot.build-image.imagePlatform\")\n\t@Nullable String imagePlatform;\n\n\t/**\n\t * Docker configuration options.\n\t * @since 2.4.0\n\t */\n\t@Parameter\n\tprivate @Nullable Docker docker;\n\n\t/**\n\t * The type of archive (which corresponds to how the dependencies are laid out inside\n\t * it). Possible values are {@code JAR}, {@code WAR}, {@code ZIP}, {@code DIR},\n\t * {@code NONE}. Defaults to a guess based on the archive type.\n\t * @since 2.3.11\n\t */\n\t@Parameter\n\tprivate @Nullable LayoutType layout;\n\n\t/**\n\t * The layout factory that will be used to create the executable archive if no\n\t * explicit layout is set. Alternative layouts implementations can be provided by 3rd\n\t * parties.\n\t * @since 2.3.11\n\t */\n\t@Parameter\n\tprivate @Nullable LayoutFactory layoutFactory;\n\n\tprotected BuildImageMojo(MavenProjectHelper projectHelper) {\n\t\tsuper(projectHelper);\n\t}\n\n\t/**\n\t * Return the type of archive that should be used when building the image.\n\t * @return the value of the {@code layout} parameter, or {@code null} if the parameter\n\t * is not provided\n\t */\n\t@Override\n\tprotected @Nullable LayoutType getLayout() {\n\t\treturn this.layout;\n\t}\n\n\t/**\n\t * Return the layout factory that will be used to determine the\n\t * {@link AbstractPackagerMojo.LayoutType} if no explicit layout is set.\n\t * @return the value of the {@code layoutFactory} parameter, or {@code null} if the\n\t * parameter is not provided\n\t */\n\t@Override\n\tprotected @Nullable LayoutFactory getLayoutFactory() {\n\t\treturn this.layoutFactory;\n\t}\n\n\t@Override\n\tpublic void execute() throws MojoExecutionException {\n\t\tif (this.project.getPackaging().equals(\"pom\")) {\n\t\t\tgetLog().debug(\"build-image goal could not be applied to pom project.\");\n\t\t\treturn;\n\t\t}\n\t\tif (this.skip) {\n\t\t\tgetLog().debug(\"skipping build-image as per configuration.\");\n\t\t\treturn;\n\t\t}\n\t\tbuildImage();\n\t}\n\n\tprivate void buildImage() throws MojoExecutionException {\n\t\tLibraries libraries = getLibraries(Collections.emptySet());\n\t\ttry {\n\t\t\tBuildRequest request = getBuildRequest(libraries);\n\t\t\tDocker docker = (this.docker != null) ? this.docker : new Docker();\n\t\t\tBuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(getLog(),\n\t\t\t\t\trequest.isPublish());\n\t\t\tBuilder builder = new Builder(new MojoBuildLog(this::getLog), dockerConfiguration);\n\t\t\tbuilder.build(request);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate BuildRequest getBuildRequest(Libraries libraries) {\n\t\tImagePackager imagePackager = new ImagePackager(getArchiveFile(), getBackupFile());\n\t\tFunction<Owner, TarArchive> content = (owner) -> getApplicationContent(owner, libraries, imagePackager);\n\t\tImage image = (this.image != null) ? this.image : new Image();\n\t\tif (image.name == null && this.imageName != null) {\n\t\t\timage.setName(this.imageName);\n\t\t}\n\t\tif (image.builder == null && this.imageBuilder != null) {\n\t\t\timage.setBuilder(this.imageBuilder);\n\t\t}\n\t\tif (image.trustBuilder == null && this.trustBuilder != null) {\n\t\t\timage.setTrustBuilder(this.trustBuilder);\n\t\t}\n\t\tif (image.runImage == null && this.runImage != null) {\n\t\t\timage.setRunImage(this.runImage);\n\t\t}\n\t\tif (image.cleanCache == null && this.cleanCache != null) {\n\t\t\timage.setCleanCache(this.cleanCache);\n\t\t}\n\t\tif (image.pullPolicy == null && this.pullPolicy != null) {\n\t\t\timage.setPullPolicy(this.pullPolicy);\n\t\t}\n\t\tif (image.publish == null && this.publish != null) {\n\t\t\timage.setPublish(this.publish);\n\t\t}\n\t\tif (image.network == null && this.network != null) {\n\t\t\timage.setNetwork(this.network);\n\t\t}\n\t\tif (image.createdDate == null && this.createdDate != null) {\n\t\t\timage.setCreatedDate(this.createdDate);\n\t\t}\n\t\tif (image.applicationDirectory == null && this.applicationDirectory != null) {\n\t\t\timage.setApplicationDirectory(this.applicationDirectory);\n\t\t}\n\t\tif (image.imagePlatform == null && this.imagePlatform != null) {\n\t\t\timage.setImagePlatform(this.imagePlatform);\n\t\t}\n\t\treturn customize(image.getBuildRequest(this.project.getArtifact(), content));\n\t}\n\n\tprivate TarArchive getApplicationContent(Owner owner, Libraries libraries, ImagePackager imagePackager) {\n\t\tImagePackager packager = getConfiguredPackager(() -> imagePackager);\n\t\treturn new PackagedTarArchive(owner, libraries, packager);\n\t}\n\n\tprivate File getArchiveFile() {\n\t\t// We can't use 'project.getArtifact().getFile()' because package can be done in a\n\t\t// forked lifecycle and will be null\n\t\tFile archiveFile = getTargetFile(this.finalName, this.classifier, this.sourceDirectory);\n\t\tif (!archiveFile.exists()) {\n\t\t\tarchiveFile = getSourceArtifact(this.classifier).getFile();\n\t\t}\n\t\tif (!archiveFile.exists()) {\n\t\t\tthrow new IllegalStateException(\"A jar or war file is required for building image\");\n\t\t}\n\t\treturn archiveFile;\n\t}\n\n\t/**\n\t * Return the {@link File} to use to back up the original source.\n\t * @return the file to use to back up the original source\n\t */\n\tprivate @Nullable File getBackupFile() {\n\t\t// We can't use 'project.getAttachedArtifacts()' because package can be done in a\n\t\t// forked lifecycle and will be null\n\t\tif (this.classifier != null) {\n\t\t\tFile backupFile = getTargetFile(this.finalName, null, this.sourceDirectory);\n\t\t\tif (backupFile.exists()) {\n\t\t\t\treturn backupFile;\n\t\t\t}\n\t\t\tArtifact source = getSourceArtifact(null);\n\t\t\tif (!this.classifier.equals(source.getClassifier())) {\n\t\t\t\treturn source.getFile();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate BuildRequest customize(BuildRequest request) {\n\t\trequest = customizeCreator(request);\n\t\treturn request;\n\t}\n\n\tprivate BuildRequest customizeCreator(BuildRequest request) {\n\t\tString springBootVersion = VersionExtractor.forClass(BuildImageMojo.class);\n\t\tif (StringUtils.hasText(springBootVersion)) {\n\t\t\trequest = request.withCreator(Creator.withVersion(springBootVersion));\n\t\t}\n\t\treturn request;\n\t}\n\n\t/**\n\t * {@link BuildLog} backed by Mojo logging.\n\t */\n\tprivate static class MojoBuildLog extends AbstractBuildLog {\n\n\t\tprivate static final long THRESHOLD = Duration.ofSeconds(2).toMillis();\n\n\t\tprivate final Supplier<Log> log;\n\n\t\tMojoBuildLog(Supplier<Log> log) {\n\t\t\tthis.log = log;\n\t\t}\n\n\t\t@Override\n\t\tprotected void log(String message) {\n\t\t\tthis.log.get().info(message);\n\t\t}\n\n\t\t@Override\n\t\tprotected Consumer<TotalProgressEvent> getProgressConsumer(String message) {\n\t\t\treturn new ProgressLog(message);\n\t\t}\n\n\t\tprivate class ProgressLog implements Consumer<TotalProgressEvent> {\n\n\t\t\tprivate final String message;\n\n\t\t\tprivate long last;\n\n\t\t\tProgressLog(String message) {\n\t\t\t\tthis.message = message;\n\t\t\t\tthis.last = System.currentTimeMillis();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void accept(TotalProgressEvent progress) {\n\t\t\t\tlog(progress.getPercent());\n\t\t\t}\n\n\t\t\tprivate void log(int percent) {\n\t\t\t\tif (percent == 100 || (System.currentTimeMillis() - this.last) > THRESHOLD) {\n\t\t\t\t\tMojoBuildLog.this.log.get().info(this.message + \" \" + percent + \"%\");\n\t\t\t\t\tthis.last = System.currentTimeMillis();\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapter class to expose the packaged jar as a {@link TarArchive}.\n\t */\n\tstatic class PackagedTarArchive implements TarArchive {\n\n\t\tstatic final long NORMALIZED_MOD_TIME = TarArchive.NORMALIZED_TIME.toEpochMilli();\n\n\t\tprivate final Owner owner;\n\n\t\tprivate final Libraries libraries;\n\n\t\tprivate final ImagePackager packager;\n\n\t\tPackagedTarArchive(Owner owner, Libraries libraries, ImagePackager packager) {\n\t\t\tthis.owner = owner;\n\t\t\tthis.libraries = libraries;\n\t\t\tthis.packager = packager;\n\t\t}\n\n\t\t@Override\n\t\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\t\tTarArchiveOutputStream tar = new TarArchiveOutputStream(outputStream);\n\t\t\ttar.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n\t\t\ttry {\n\t\t\t\tthis.packager.packageImage(this.libraries, (entry, entryWriter) -> write(entry, entryWriter, tar));\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\toutputStream.close();\n\t\t\t\tthrow new RuntimeException(\"Error packaging archive for image\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate void write(ZipEntry jarEntry, @Nullable EntryWriter entryWriter, TarArchiveOutputStream tar) {\n\t\t\ttry {\n\t\t\t\tTarArchiveEntry tarEntry = convert(jarEntry);\n\t\t\t\ttar.putArchiveEntry(tarEntry);\n\t\t\t\tif (tarEntry.isFile()) {\n\t\t\t\t\tAssert.state(entryWriter != null, \"'entryWriter' must not be null\");\n\t\t\t\t\tentryWriter.write(tar);\n\t\t\t\t}\n\t\t\t\ttar.closeArchiveEntry();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate TarArchiveEntry convert(ZipEntry entry) {\n\t\t\tbyte linkFlag = (entry.isDirectory()) ? TarConstants.LF_DIR : TarConstants.LF_NORMAL;\n\t\t\tTarArchiveEntry tarEntry = new TarArchiveEntry(entry.getName(), linkFlag, true);\n\t\t\ttarEntry.setUserId(this.owner.getUid());\n\t\t\ttarEntry.setGroupId(this.owner.getGid());\n\t\t\ttarEntry.setModTime(NORMALIZED_MOD_TIME);\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\ttarEntry.setSize(entry.getSize());\n\t\t\t}\n\t\t\treturn tarEntry;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildImageNoForkMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.project.MavenProjectHelper;\n\n/**\n * Package an application into an OCI image using a buildpack, but without forking the\n * lifecycle. This goal should be used when configuring a goal {@code execution} in your\n * build. To invoke the goal on the command-line, use {@code build-image} instead.\n *\n * @author Stephane Nicoll\n * @since 3.0.0\n */\n@Mojo(name = \"build-image-no-fork\", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true,\n\t\trequiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,\n\t\trequiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)\npublic class BuildImageNoForkMojo extends BuildImageMojo {\n\n\t@Inject\n\tpublic BuildImageNoForkMojo(MavenProjectHelper projectHelper) {\n\t\tsuper(projectHelper);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/BuildInfoMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.time.Instant;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.plugin.AbstractMojo;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProject;\nimport org.jspecify.annotations.Nullable;\nimport org.sonatype.plexus.build.incremental.BuildContext;\n\nimport org.springframework.boot.loader.tools.BuildPropertiesWriter;\nimport org.springframework.boot.loader.tools.BuildPropertiesWriter.NullAdditionalPropertyValueException;\nimport org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails;\n\n/**\n * Generate a {@code build-info.properties} file based on the content of the current\n * {@link MavenProject}.\n *\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 1.4.0\n */\n@Mojo(name = \"build-info\", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true)\npublic class BuildInfoMojo extends AbstractMojo {\n\n\tprivate final BuildContext buildContext;\n\n\t/**\n\t * The Maven session.\n\t */\n\t@Parameter(defaultValue = \"${session}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MavenSession session;\n\n\t/**\n\t * The Maven project.\n\t */\n\t@Parameter(defaultValue = \"${project}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MavenProject project;\n\n\t/**\n\t * The location of the generated {@code build-info.properties} file.\n\t */\n\t@Parameter(defaultValue = \"${project.build.outputDirectory}/META-INF/build-info.properties\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File outputFile;\n\n\t/**\n\t * The value used for the {@code build.time} property in a form suitable for\n\t * {@link Instant#parse(CharSequence)}. Defaults to\n\t * {@code project.build.outputTimestamp} or {@code session.request.startTime} if the\n\t * former is not set. To disable the {@code build.time} property entirely, use\n\t * {@code 'off'} or add it to {@code excludeInfoProperties}.\n\t * @since 2.2.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.outputTimestamp}\")\n\tprivate @Nullable String time;\n\n\t/**\n\t * Additional properties to store in the {@code build-info.properties} file. Each\n\t * entry is prefixed by {@code build.} in the generated {@code build-info.properties}.\n\t */\n\t@Parameter\n\tprivate @Nullable Map<String, String> additionalProperties;\n\n\t/**\n\t * Properties that should be excluded {@code build-info.properties} file. Can be used\n\t * to exclude the standard {@code group}, {@code artifact}, {@code name},\n\t * {@code version} or {@code time} properties as well as items from\n\t * {@code additionalProperties}.\n\t */\n\t@Parameter\n\tprivate @Nullable List<String> excludeInfoProperties;\n\n\t/**\n\t * Skip the execution.\n\t * @since 3.1.0\n\t */\n\t@Parameter(property = \"spring-boot.build-info.skip\", defaultValue = \"false\")\n\tprivate boolean skip;\n\n\t@Inject\n\tpublic BuildInfoMojo(BuildContext buildContext) {\n\t\tthis.buildContext = buildContext;\n\t}\n\n\t@Override\n\tpublic void execute() throws MojoExecutionException, MojoFailureException {\n\t\tif (this.skip) {\n\t\t\tgetLog().debug(\"skipping build-info as per configuration.\");\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tProjectDetails details = getProjectDetails();\n\t\t\tnew BuildPropertiesWriter(this.outputFile).writeBuildProperties(details);\n\t\t\tthis.buildContext.refresh(this.outputFile);\n\t\t}\n\t\tcatch (NullAdditionalPropertyValueException ex) {\n\t\t\tthrow new MojoFailureException(\"Failed to generate build-info.properties. \" + ex.getMessage(), ex);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate ProjectDetails getProjectDetails() {\n\t\tString group = getIfNotExcluded(\"group\", this.project.getGroupId());\n\t\tString artifact = getIfNotExcluded(\"artifact\", this.project.getArtifactId());\n\t\tString version = getIfNotExcluded(\"version\", this.project.getVersion());\n\t\tString name = getIfNotExcluded(\"name\", this.project.getName());\n\t\tInstant time = getIfNotExcluded(\"time\", getBuildTime());\n\t\tMap<String, String> additionalProperties = applyExclusions(this.additionalProperties);\n\t\treturn new ProjectDetails(group, artifact, version, name, time, additionalProperties);\n\t}\n\n\tprivate <T> @Nullable T getIfNotExcluded(String name, @Nullable T value) {\n\t\treturn (this.excludeInfoProperties == null || !this.excludeInfoProperties.contains(name)) ? value : null;\n\t}\n\n\tprivate @Nullable Map<String, String> applyExclusions(@Nullable Map<String, String> source) {\n\t\tif (source == null || this.excludeInfoProperties == null) {\n\t\t\treturn source;\n\t\t}\n\t\tMap<String, String> result = new LinkedHashMap<>(source);\n\t\tthis.excludeInfoProperties.forEach(result::remove);\n\t\treturn result;\n\t}\n\n\tprivate @Nullable Instant getBuildTime() {\n\t\tif (this.time == null || this.time.isEmpty()) {\n\t\t\tDate startTime = this.session.getRequest().getStartTime();\n\t\t\treturn (startTime != null) ? startTime.toInstant() : Instant.now();\n\t\t}\n\t\tif (\"off\".equalsIgnoreCase(this.time)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new MavenBuildOutputTimestamp(this.time).toInstant();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CacheInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.Cache;\nimport org.springframework.util.Assert;\n\n/**\n * Encapsulates configuration of an image building cache.\n *\n * @author Scott Frederick\n * @since 2.6.0\n */\npublic class CacheInfo {\n\n\tprivate @Nullable Cache cache;\n\n\tpublic CacheInfo() {\n\t}\n\n\tprivate CacheInfo(Cache cache) {\n\t\tthis.cache = cache;\n\t}\n\n\tpublic void setVolume(VolumeCacheInfo info) {\n\t\tAssert.state(this.cache == null, \"Each image building cache can be configured only once\");\n\t\tString name = info.getName();\n\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\tthis.cache = Cache.volume(name);\n\t}\n\n\tpublic void setBind(BindCacheInfo info) {\n\t\tAssert.state(this.cache == null, \"Each image building cache can be configured only once\");\n\t\tString source = info.getSource();\n\t\tAssert.state(source != null, \"'source' must not be null\");\n\t\tthis.cache = Cache.bind(source);\n\t}\n\n\t@Nullable Cache asCache() {\n\t\treturn this.cache;\n\t}\n\n\tstatic CacheInfo fromVolume(VolumeCacheInfo cacheInfo) {\n\t\tString name = cacheInfo.getName();\n\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\treturn new CacheInfo(Cache.volume(name));\n\t}\n\n\tstatic CacheInfo fromBind(BindCacheInfo cacheInfo) {\n\t\tString source = cacheInfo.getSource();\n\t\tAssert.state(source != null, \"'source' must not be null\");\n\t\treturn new CacheInfo(Cache.bind(source));\n\t}\n\n\t/**\n\t * Encapsulates configuration of an image building cache stored in a volume.\n\t */\n\tpublic static class VolumeCacheInfo {\n\n\t\tprivate @Nullable String name;\n\n\t\tpublic VolumeCacheInfo() {\n\t\t}\n\n\t\tVolumeCacheInfo(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t/**\n\t * Encapsulates configuration of an image building cache stored in a bind mount.\n\t */\n\tpublic static class BindCacheInfo {\n\n\t\tprivate @Nullable String source;\n\n\t\tpublic BindCacheInfo() {\n\t\t}\n\n\t\tBindCacheInfo(String name) {\n\t\t\tthis.source = name;\n\t\t}\n\n\t\tpublic @Nullable String getSource() {\n\t\t\treturn this.source;\n\t\t}\n\n\t\tvoid setSource(@Nullable String source) {\n\t\t\tthis.source = source;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ClassPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.nio.charset.UnsupportedCharsetException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.function.UnaryOperator;\nimport java.util.stream.Collector;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Encapsulates a class path and allows argument parameters to be created. On Windows an\n * argument file is used whenever possible since the maximum command line length is\n * limited.\n *\n * @author Stephane Nicoll\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\nfinal class ClassPath {\n\n\tprivate static final Collector<CharSequence, ?, String> JOIN_BY_PATH_SEPARATOR = Collectors\n\t\t.joining(File.pathSeparator);\n\n\tprivate final boolean preferArgFile;\n\n\tprivate final String path;\n\n\tprivate ClassPath(boolean preferArgFile, String path) {\n\t\tthis.preferArgFile = preferArgFile;\n\t\tthis.path = path;\n\t}\n\n\t/**\n\t * Return the args to append to a java command line call (including {@code -cp}).\n\t * @param allowArgFile if an arg file can be used\n\t * @return the command line arguments\n\t */\n\tList<String> args(boolean allowArgFile) {\n\t\treturn (!this.path.isEmpty()) ? List.of(\"-cp\", classPathArg(allowArgFile)) : Collections.emptyList();\n\t}\n\n\tprivate String classPathArg(boolean allowArgFile) {\n\t\tif (this.preferArgFile && allowArgFile) {\n\t\t\ttry {\n\t\t\t\treturn \"@\" + createArgFile();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\treturn this.path;\n\t\t\t}\n\t\t}\n\t\treturn this.path;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.path;\n\t}\n\n\tprivate Path createArgFile() throws IOException {\n\t\tPath argFile = Files.createTempFile(\"spring-boot-\", \".argfile\");\n\t\targFile.toFile().deleteOnExit();\n\t\tFiles.writeString(argFile, \"\\\"\" + this.path.replace(\"\\\\\", \"\\\\\\\\\") + \"\\\"\", charset());\n\t\treturn argFile;\n\t}\n\n\tprivate Charset charset() {\n\t\ttry {\n\t\t\tString nativeEncoding = System.getProperty(\"native.encoding\");\n\t\t\treturn (nativeEncoding != null) ? Charset.forName(nativeEncoding) : Charset.defaultCharset();\n\t\t}\n\t\tcatch (UnsupportedCharsetException ex) {\n\t\t\treturn Charset.defaultCharset();\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to create a {@link ClassPath} of the given URLs.\n\t * @param urls the class path URLs\n\t * @return a new {@link ClassPath} instance\n\t */\n\tstatic ClassPath of(URL... urls) {\n\t\treturn of(Arrays.asList(urls));\n\t}\n\n\t/**\n\t * Factory method to create a {@link ClassPath} of the given URLs.\n\t * @param urls the class path URLs\n\t * @return a new {@link ClassPath} instance\n\t */\n\tstatic ClassPath of(List<URL> urls) {\n\t\treturn of(System::getProperty, urls);\n\t}\n\n\t/**\n\t * Factory method to create a {@link ClassPath} of the given URLs.\n\t * @param getSystemProperty {@link UnaryOperator} allowing access to system properties\n\t * @param urls the class path URLs\n\t * @return a new {@link ClassPath} instance\n\t */\n\tstatic ClassPath of(UnaryOperator<@Nullable String> getSystemProperty, List<URL> urls) {\n\t\tboolean preferArgFile = urls.size() > 1 && isWindows(getSystemProperty);\n\t\treturn new ClassPath(preferArgFile, urls.stream().map(ClassPath::toPathString).collect(JOIN_BY_PATH_SEPARATOR));\n\t}\n\n\tprivate static boolean isWindows(UnaryOperator<@Nullable String> getSystemProperty) {\n\t\tString os = getSystemProperty.apply(\"os.name\");\n\t\treturn StringUtils.hasText(os) && os.toLowerCase(Locale.ROOT).contains(\"win\");\n\t}\n\n\tprivate static String toPathString(URL url) {\n\t\ttry {\n\t\t\treturn Paths.get(url.toURI()).toString();\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalArgumentException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CommandLineBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Helper class to build the command-line arguments of a java process.\n *\n * @author Stephane Nicoll\n */\nfinal class CommandLineBuilder {\n\n\tprivate final List<String> options = new ArrayList<>();\n\n\tprivate final List<URL> classpathElements = new ArrayList<>();\n\n\tprivate final String mainClass;\n\n\tprivate final List<String> arguments = new ArrayList<>();\n\n\tprivate CommandLineBuilder(String mainClass) {\n\t\tthis.mainClass = mainClass;\n\t}\n\n\tstatic CommandLineBuilder forMainClass(String mainClass) {\n\t\treturn new CommandLineBuilder(mainClass);\n\t}\n\n\t// Do not use String @Nullable ... jvmArguments, Maven can't deal with that\n\tCommandLineBuilder withJvmArguments(@Nullable String... jvmArguments) {\n\t\tif (jvmArguments != null) {\n\t\t\tthis.options.addAll(Arrays.stream(jvmArguments).filter(Objects::nonNull).toList());\n\t\t}\n\t\treturn this;\n\t}\n\n\tCommandLineBuilder withSystemProperties(@Nullable Map<String, String> systemProperties) {\n\t\tif (systemProperties != null) {\n\t\t\tfor (Entry<String, String> systemProperty : systemProperties.entrySet()) {\n\t\t\t\tString option = SystemPropertyFormatter.format(systemProperty.getKey(), systemProperty.getValue());\n\t\t\t\tif (StringUtils.hasText(option)) {\n\t\t\t\t\tthis.options.add(option);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tCommandLineBuilder withClasspath(URL... elements) {\n\t\tthis.classpathElements.addAll(Arrays.asList(elements));\n\t\treturn this;\n\t}\n\n\t// Do not use String @Nullable ... arguments, Maven can't deal with that\n\tCommandLineBuilder withArguments(@Nullable String... arguments) {\n\t\tif (arguments != null) {\n\t\t\tthis.arguments.addAll(Arrays.stream(arguments).filter(Objects::nonNull).toList());\n\t\t}\n\t\treturn this;\n\t}\n\n\tList<String> build() {\n\t\tList<String> commandLine = new ArrayList<>();\n\t\tif (!this.options.isEmpty()) {\n\t\t\tcommandLine.addAll(this.options);\n\t\t}\n\t\tcommandLine.addAll(ClassPath.of(this.classpathElements).args(true));\n\t\tcommandLine.add(this.mainClass);\n\t\tif (!this.arguments.isEmpty()) {\n\t\t\tcommandLine.addAll(this.arguments);\n\t\t}\n\t\treturn commandLine;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/CustomLayersProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport javax.xml.XMLConstants;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.validation.Schema;\nimport javax.xml.validation.SchemaFactory;\nimport javax.xml.validation.Validator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.SAXException;\n\nimport org.springframework.boot.loader.tools.Layer;\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.layer.ApplicationContentFilter;\nimport org.springframework.boot.loader.tools.layer.ContentFilter;\nimport org.springframework.boot.loader.tools.layer.ContentSelector;\nimport org.springframework.boot.loader.tools.layer.CustomLayers;\nimport org.springframework.boot.loader.tools.layer.IncludeExcludeContentSelector;\nimport org.springframework.boot.loader.tools.layer.LibraryContentFilter;\n\n/**\n * Produces a {@link CustomLayers} based on the given {@link Document}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass CustomLayersProvider {\n\n\tCustomLayers getLayers(Document document) {\n\t\tvalidate(document);\n\t\tElement root = document.getDocumentElement();\n\t\tList<ContentSelector<String>> applicationSelectors = getApplicationSelectors(root);\n\t\tList<ContentSelector<Library>> librarySelectors = getLibrarySelectors(root);\n\t\tList<Layer> layers = getLayers(root);\n\t\treturn new CustomLayers(layers, applicationSelectors, librarySelectors);\n\t}\n\n\tprivate void validate(Document document) {\n\t\tSchema schema = loadSchema();\n\t\ttry {\n\t\t\tValidator validator = schema.newValidator();\n\t\t\tvalidator.validate(new DOMSource(document));\n\t\t}\n\t\tcatch (SAXException | IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid layers.xml configuration\", ex);\n\t\t}\n\t}\n\n\tprivate Schema loadSchema() {\n\t\ttry {\n\t\t\tSchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);\n\t\t\treturn factory.newSchema(getClass().getResource(\"layers.xsd\"));\n\t\t}\n\t\tcatch (SAXException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load layers XSD\");\n\t\t}\n\t}\n\n\tprivate List<ContentSelector<String>> getApplicationSelectors(Element root) {\n\t\treturn getSelectors(root, \"application\", (element) -> getSelector(element, ApplicationContentFilter::new));\n\t}\n\n\tprivate List<ContentSelector<Library>> getLibrarySelectors(Element root) {\n\t\treturn getSelectors(root, \"dependencies\", (element) -> getLibrarySelector(element, LibraryContentFilter::new));\n\t}\n\n\tprivate List<Layer> getLayers(Element root) {\n\t\tElement layerOrder = getChildElement(root, \"layerOrder\");\n\t\tif (layerOrder == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\treturn getChildNodeTextContent(layerOrder, \"layer\").stream().map(Layer::new).toList();\n\t}\n\n\tprivate <T> List<ContentSelector<T>> getSelectors(Element root, String elementName,\n\t\t\tFunction<Element, ContentSelector<T>> selectorFactory) {\n\t\tElement element = getChildElement(root, elementName);\n\t\tif (element == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<ContentSelector<T>> selectors = new ArrayList<>();\n\t\tNodeList children = element.getChildNodes();\n\t\tfor (int i = 0; i < children.getLength(); i++) {\n\t\t\tNode child = children.item(i);\n\t\t\tif (child instanceof Element childElement) {\n\t\t\t\tContentSelector<T> selector = selectorFactory.apply(childElement);\n\t\t\t\tselectors.add(selector);\n\t\t\t}\n\t\t}\n\t\treturn selectors;\n\t}\n\n\tprivate <T> ContentSelector<T> getSelector(Element element, Function<String, ContentFilter<T>> filterFactory) {\n\t\tLayer layer = new Layer(element.getAttribute(\"layer\"));\n\t\tList<String> includes = getChildNodeTextContent(element, \"include\");\n\t\tList<String> excludes = getChildNodeTextContent(element, \"exclude\");\n\t\treturn new IncludeExcludeContentSelector<>(layer, includes, excludes, filterFactory);\n\t}\n\n\tprivate ContentSelector<Library> getLibrarySelector(Element element,\n\t\t\tFunction<String, ContentFilter<Library>> filterFactory) {\n\t\tLayer layer = new Layer(element.getAttribute(\"layer\"));\n\t\tList<String> includes = getChildNodeTextContent(element, \"include\");\n\t\tList<String> excludes = getChildNodeTextContent(element, \"exclude\");\n\t\tElement includeModuleDependencies = getChildElement(element, \"includeModuleDependencies\");\n\t\tElement excludeModuleDependencies = getChildElement(element, \"excludeModuleDependencies\");\n\t\tList<ContentFilter<Library>> includeFilters = includes.stream()\n\t\t\t.map(filterFactory)\n\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\tif (includeModuleDependencies != null) {\n\t\t\tincludeFilters.add(Library::isLocal);\n\t\t}\n\t\tList<ContentFilter<Library>> excludeFilters = excludes.stream()\n\t\t\t.map(filterFactory)\n\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\tif (excludeModuleDependencies != null) {\n\t\t\texcludeFilters.add(Library::isLocal);\n\t\t}\n\t\treturn new IncludeExcludeContentSelector<>(layer, includeFilters, excludeFilters);\n\t}\n\n\tprivate List<String> getChildNodeTextContent(Element element, String tagName) {\n\t\tList<String> patterns = new ArrayList<>();\n\t\tNodeList nodes = element.getElementsByTagName(tagName);\n\t\tfor (int i = 0; i < nodes.getLength(); i++) {\n\t\t\tNode node = nodes.item(i);\n\t\t\tif (node instanceof Element) {\n\t\t\t\tpatterns.add(node.getTextContent());\n\t\t\t}\n\t\t}\n\t\treturn patterns;\n\t}\n\n\tprivate @Nullable Element getChildElement(Element element, String tagName) {\n\t\tNodeList nodes = element.getElementsByTagName(tagName);\n\t\tif (nodes.getLength() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (nodes.getLength() > 1) {\n\t\t\tthrow new IllegalStateException(\"Multiple '\" + tagName + \"' nodes found\");\n\t\t}\n\t\treturn (Element) nodes.item(0);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/DependencyFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.AbstractArtifactsFilter;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\n\n/**\n * Base class for {@link ArtifactsFilter} based on a {@link FilterableDependency} list.\n *\n * @author Stephane Nicoll\n * @author David Turanski\n * @since 1.2.0\n */\npublic abstract class DependencyFilter extends AbstractArtifactsFilter {\n\n\tprivate final List<? extends FilterableDependency> filters;\n\n\t/**\n\t * Create a new instance with the list of {@link FilterableDependency} instance(s) to\n\t * use.\n\t * @param dependencies the source dependencies\n\t */\n\tpublic DependencyFilter(List<? extends FilterableDependency> dependencies) {\n\t\tthis.filters = dependencies;\n\t}\n\n\t@Override\n\tpublic Set<Artifact> filter(Set<Artifact> artifacts) throws ArtifactFilterException {\n\t\tSet<Artifact> result = new HashSet<>();\n\t\tfor (Artifact artifact : artifacts) {\n\t\t\tif (!filter(artifact)) {\n\t\t\t\tresult.add(artifact);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected abstract boolean filter(Artifact artifact);\n\n\t/**\n\t * Check if the specified {@link org.apache.maven.artifact.Artifact} matches the\n\t * specified {@link org.springframework.boot.maven.FilterableDependency}. Returns\n\t * {@code true} if it should be excluded\n\t * @param artifact the Maven {@link Artifact}\n\t * @param dependency the {@link FilterableDependency}\n\t * @return {@code true} if the artifact matches the dependency\n\t */\n\tprotected final boolean equals(Artifact artifact, FilterableDependency dependency) {\n\t\tif (!dependency.getGroupId().equals(artifact.getGroupId())) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!dependency.getArtifactId().equals(artifact.getArtifactId())) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (dependency.getClassifier() == null\n\t\t\t\t|| artifact.getClassifier() != null && dependency.getClassifier().equals(artifact.getClassifier()));\n\t}\n\n\tprotected final List<? extends FilterableDependency> getFilters() {\n\t\treturn this.filters;\n\t}\n\n\t/**\n\t * Return a new {@link DependencyFilter} the excludes artifacts based on the given\n\t * predicate.\n\t * @param filter the predicate used to filter the artifacts.\n\t * @return a new {@link DependencyFilter} instance\n\t * @since 3.5.7\n\t */\n\tpublic static DependencyFilter exclude(Predicate<Artifact> filter) {\n\t\treturn new DependencyFilter(Collections.emptyList()) {\n\n\t\t\t@Override\n\t\t\tprotected boolean filter(Artifact artifact) {\n\t\t\t\treturn filter.test(artifact);\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Docker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.apache.maven.plugin.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\nimport org.springframework.util.Assert;\n\n/**\n * Docker configuration options.\n *\n * @author Wei Jiang\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic class Docker {\n\n\tprivate @Nullable String host;\n\n\tprivate @Nullable String context;\n\n\tprivate boolean tlsVerify;\n\n\tprivate @Nullable String certPath;\n\n\tprivate boolean bindHostToBuilder;\n\n\tprivate @Nullable DockerRegistry builderRegistry;\n\n\tprivate @Nullable DockerRegistry publishRegistry;\n\n\t/**\n\t * The host address of the Docker daemon.\n\t * @return the Docker host\n\t */\n\tpublic @Nullable String getHost() {\n\t\treturn this.host;\n\t}\n\n\tvoid setHost(@Nullable String host) {\n\t\tthis.host = host;\n\t}\n\n\t/**\n\t * The Docker context to use to retrieve host configuration.\n\t * @return the Docker context\n\t */\n\tpublic @Nullable String getContext() {\n\t\treturn this.context;\n\t}\n\n\tpublic void setContext(@Nullable String context) {\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * Whether the Docker daemon requires TLS communication.\n\t * @return {@code true} to enable TLS\n\t */\n\tpublic boolean isTlsVerify() {\n\t\treturn this.tlsVerify;\n\t}\n\n\tvoid setTlsVerify(boolean tlsVerify) {\n\t\tthis.tlsVerify = tlsVerify;\n\t}\n\n\t/**\n\t * The path to TLS certificate and key files required for TLS communication with the\n\t * Docker daemon.\n\t * @return the TLS certificate path\n\t */\n\tpublic @Nullable String getCertPath() {\n\t\treturn this.certPath;\n\t}\n\n\tvoid setCertPath(@Nullable String certPath) {\n\t\tthis.certPath = certPath;\n\t}\n\n\t/**\n\t * Whether to use the configured Docker host in the builder container.\n\t * @return {@code true} to use the configured Docker host in the builder container\n\t */\n\tpublic boolean isBindHostToBuilder() {\n\t\treturn this.bindHostToBuilder;\n\t}\n\n\tvoid setBindHostToBuilder(boolean bindHostToBuilder) {\n\t\tthis.bindHostToBuilder = bindHostToBuilder;\n\t}\n\n\t/**\n\t * Configuration of the Docker registry where builder and run images are stored.\n\t * @return the registry configuration\n\t */\n\t@Nullable DockerRegistry getBuilderRegistry() {\n\t\treturn this.builderRegistry;\n\t}\n\n\t/**\n\t * Sets the {@link DockerRegistry} that configures authentication to the builder\n\t * registry.\n\t * @param builderRegistry the registry configuration\n\t */\n\tvoid setBuilderRegistry(@Nullable DockerRegistry builderRegistry) {\n\t\tthis.builderRegistry = builderRegistry;\n\t}\n\n\t/**\n\t * Configuration of the Docker registry where the generated image will be published.\n\t * @return the registry configuration\n\t */\n\t@Nullable DockerRegistry getPublishRegistry() {\n\t\treturn this.publishRegistry;\n\t}\n\n\t/**\n\t * Sets the {@link DockerRegistry} that configures authentication to the publishing\n\t * registry.\n\t * @param builderRegistry the registry configuration\n\t */\n\tvoid setPublishRegistry(@Nullable DockerRegistry builderRegistry) {\n\t\tthis.publishRegistry = builderRegistry;\n\t}\n\n\t/**\n\t * Returns this configuration as a {@link BuilderDockerConfiguration} instance. This\n\t * method should only be called when the configuration is complete and will no longer\n\t * be changed.\n\t * @param log the output log\n\t * @param publish whether the image should be published\n\t * @return the Docker configuration\n\t */\n\tBuilderDockerConfiguration asDockerConfiguration(Log log, boolean publish) {\n\t\tBuilderDockerConfiguration dockerConfiguration = new BuilderDockerConfiguration();\n\t\tdockerConfiguration = customizeHost(dockerConfiguration);\n\t\tdockerConfiguration = dockerConfiguration.withBindHostToBuilder(this.bindHostToBuilder);\n\t\tdockerConfiguration = customizeBuilderAuthentication(log, dockerConfiguration);\n\t\tdockerConfiguration = customizePublishAuthentication(log, dockerConfiguration, publish);\n\t\treturn dockerConfiguration;\n\t}\n\n\tprivate BuilderDockerConfiguration customizeHost(BuilderDockerConfiguration dockerConfiguration) {\n\t\tif (this.context != null && this.host != null) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Invalid Docker configuration, either context or host can be provided but not both\");\n\t\t}\n\t\tif (this.context != null) {\n\t\t\treturn dockerConfiguration.withContext(this.context);\n\t\t}\n\t\tif (this.host != null) {\n\t\t\treturn dockerConfiguration.withHost(this.host, this.tlsVerify, this.certPath);\n\t\t}\n\t\treturn dockerConfiguration;\n\t}\n\n\tprivate BuilderDockerConfiguration customizeBuilderAuthentication(Log log,\n\t\t\tBuilderDockerConfiguration dockerConfiguration) {\n\t\tDockerRegistryAuthentication authentication = DockerRegistryAuthentication.configuration(null,\n\t\t\t\t(message, ex) -> log.warn(message));\n\t\treturn dockerConfiguration.withBuilderRegistryAuthentication(\n\t\t\t\tgetRegistryAuthentication(\"builder\", this.builderRegistry, authentication));\n\t}\n\n\tprivate BuilderDockerConfiguration customizePublishAuthentication(Log log,\n\t\t\tBuilderDockerConfiguration dockerConfiguration, boolean publish) {\n\t\tif (!publish) {\n\t\t\treturn dockerConfiguration;\n\t\t}\n\t\tDockerRegistryAuthentication authentication = DockerRegistryAuthentication\n\t\t\t.configuration(DockerRegistryAuthentication.EMPTY_USER, (message, ex) -> log.warn(message));\n\t\treturn dockerConfiguration.withPublishRegistryAuthentication(\n\t\t\t\tgetRegistryAuthentication(\"publish\", this.publishRegistry, authentication));\n\t}\n\n\tprivate DockerRegistryAuthentication getRegistryAuthentication(String type, @Nullable DockerRegistry registry,\n\t\t\tDockerRegistryAuthentication fallback) {\n\t\tif (registry == null || registry.isEmpty()) {\n\t\t\treturn fallback;\n\t\t}\n\t\tif (registry.hasTokenAuth() && !registry.hasUserAuth()) {\n\t\t\tString token = registry.getToken();\n\t\t\tAssert.state(token != null, \"'token' must not be null\");\n\t\t\treturn DockerRegistryAuthentication.token(token);\n\t\t}\n\t\tif (registry.hasUserAuth() && !registry.hasTokenAuth()) {\n\t\t\tString username = registry.getUsername();\n\t\t\tString password = registry.getPassword();\n\t\t\tAssert.state(username != null, \"'username' must not be null\");\n\t\t\tAssert.state(password != null, \"'password' must not be null\");\n\t\t\treturn DockerRegistryAuthentication.user(username, password, registry.getUrl(), registry.getEmail());\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Invalid Docker \" + type\n\t\t\t\t+ \" registry configuration, either token or username/password must be provided\");\n\t}\n\n\t/**\n\t * Encapsulates Docker registry authentication configuration options.\n\t */\n\tpublic static class DockerRegistry {\n\n\t\tprivate @Nullable String username;\n\n\t\tprivate @Nullable String password;\n\n\t\tprivate @Nullable String url;\n\n\t\tprivate @Nullable String email;\n\n\t\tprivate @Nullable String token;\n\n\t\tpublic DockerRegistry() {\n\t\t}\n\n\t\tpublic DockerRegistry(@Nullable String username, @Nullable String password, @Nullable String url,\n\t\t\t\t@Nullable String email) {\n\t\t\tthis.username = username;\n\t\t\tthis.password = password;\n\t\t\tthis.url = url;\n\t\t\tthis.email = email;\n\t\t}\n\n\t\tpublic DockerRegistry(String token) {\n\t\t\tthis.token = token;\n\t\t}\n\n\t\t/**\n\t\t * The username that will be used for user authentication to the registry.\n\t\t * @return the username\n\t\t */\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tvoid setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\t/**\n\t\t * The password that will be used for user authentication to the registry.\n\t\t * @return the password\n\t\t */\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tvoid setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t\t/**\n\t\t * The email address that will be used for user authentication to the registry.\n\t\t * @return the email address\n\t\t */\n\t\tpublic @Nullable String getEmail() {\n\t\t\treturn this.email;\n\t\t}\n\n\t\tvoid setEmail(@Nullable String email) {\n\t\t\tthis.email = email;\n\t\t}\n\n\t\t/**\n\t\t * The URL of the registry.\n\t\t * @return the registry URL\n\t\t */\n\t\t@Nullable String getUrl() {\n\t\t\treturn this.url;\n\t\t}\n\n\t\tvoid setUrl(@Nullable String url) {\n\t\t\tthis.url = url;\n\t\t}\n\n\t\t/**\n\t\t * The token that will be used for token authentication to the registry.\n\t\t * @return the authentication token\n\t\t */\n\t\tpublic @Nullable String getToken() {\n\t\t\treturn this.token;\n\t\t}\n\n\t\tvoid setToken(@Nullable String token) {\n\t\t\tthis.token = token;\n\t\t}\n\n\t\tboolean isEmpty() {\n\t\t\treturn this.username == null && this.password == null && this.url == null && this.email == null\n\t\t\t\t\t&& this.token == null;\n\t\t}\n\n\t\tboolean hasTokenAuth() {\n\t\t\treturn this.token != null;\n\t\t}\n\n\t\tboolean hasUserAuth() {\n\t\t\treturn this.username != null && this.password != null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/EnvVariables.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Utility class for working with Env variables.\n *\n * @author Dmytro Nosan\n */\nclass EnvVariables {\n\n\tprivate final Map<String, String> variables;\n\n\tEnvVariables(@Nullable Map<String, String> variables) {\n\t\tthis.variables = parseEnvVariables(variables);\n\t}\n\n\tprivate static Map<String, String> parseEnvVariables(@Nullable Map<String, String> args) {\n\t\tif (args == null || args.isEmpty()) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<String, String> result = new LinkedHashMap<>();\n\t\tfor (Map.Entry<String, String> e : args.entrySet()) {\n\t\t\tif (e.getKey() != null) {\n\t\t\t\tresult.put(e.getKey(), getValue(e.getValue()));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static String getValue(@Nullable String value) {\n\t\treturn (value != null) ? value : \"\";\n\t}\n\n\tMap<String, String> asMap() {\n\t\treturn Collections.unmodifiableMap(this.variables);\n\t}\n\n\tString[] asArray() {\n\t\tList<String> args = new ArrayList<>(this.variables.size());\n\t\tfor (Map.Entry<String, String> arg : this.variables.entrySet()) {\n\t\t\targs.add(arg.getKey() + \"=\" + arg.getValue());\n\t\t}\n\t\treturn args.toArray(new String[0]);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Exclude.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\n/**\n * A model for a dependency to exclude.\n *\n * @author Stephane Nicoll\n * @since 1.1.0\n */\npublic class Exclude extends FilterableDependency {\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.maven.artifact.Artifact;\n\n/**\n * An {DependencyFilter} that filters out any artifact matching an {@link Exclude}.\n *\n * @author Stephane Nicoll\n * @author David Turanski\n * @since 1.1.0\n */\npublic class ExcludeFilter extends DependencyFilter {\n\n\tpublic ExcludeFilter(Exclude... excludes) {\n\t\tthis(Arrays.asList(excludes));\n\t}\n\n\tpublic ExcludeFilter(List<Exclude> excludes) {\n\t\tsuper(excludes);\n\t}\n\n\t@Override\n\tprotected boolean filter(Artifact artifact) {\n\t\tfor (FilterableDependency dependency : getFilters()) {\n\t\t\tif (equals(artifact, dependency)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/FilterableDependency.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A model for a dependency to include or exclude.\n *\n * @author Stephane Nicoll\n * @author David Turanski\n * @since 3.1.11\n */\npublic abstract class FilterableDependency {\n\n\t/**\n\t * The groupId of the artifact to exclude.\n\t */\n\t@Parameter(required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String groupId;\n\n\t/**\n\t * The artifactId of the artifact to exclude.\n\t */\n\t@Parameter(required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String artifactId;\n\n\t/**\n\t * The classifier of the artifact to exclude.\n\t */\n\t@Parameter\n\tprivate @Nullable String classifier;\n\n\tString getGroupId() {\n\t\treturn this.groupId;\n\t}\n\n\tvoid setGroupId(String groupId) {\n\t\tthis.groupId = groupId;\n\t}\n\n\tString getArtifactId() {\n\t\treturn this.artifactId;\n\t}\n\n\tvoid setArtifactId(String artifactId) {\n\t\tthis.artifactId = artifactId;\n\t}\n\n\t@Nullable String getClassifier() {\n\t\treturn this.classifier;\n\t}\n\n\tvoid setClassifier(@Nullable String classifier) {\n\t\tthis.classifier = classifier;\n\t}\n\n\t/**\n\t * Configures the include or exclude using a user-provided property in the form\n\t * {@code groupId:artifactId} or {@code groupId:artifactId:classifier}.\n\t * @param property the user-provided property\n\t */\n\tpublic void set(String property) {\n\t\tString[] parts = property.split(\":\");\n\t\tAssert.isTrue(parts.length == 2 || parts.length == 3, getClass().getSimpleName()\n\t\t\t\t+ \" 'property' must be in the form groupId:artifactId or groupId:artifactId:classifier\");\n\t\tsetGroupId(parts[0]);\n\t\tsetArtifactId(parts[1]);\n\t\tif (parts.length == 3) {\n\t\t\tsetClassifier(parts[2]);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Image.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.BuildRequest;\nimport org.springframework.boot.buildpack.platform.build.BuildpackReference;\nimport org.springframework.boot.buildpack.platform.build.Cache;\nimport org.springframework.boot.buildpack.platform.build.PullPolicy;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageName;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Image configuration options.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n * @author Rafael Ceccone\n * @author Julian Liebig\n * @since 2.3.0\n */\npublic class Image {\n\n\t@Nullable String name;\n\n\t@Nullable String builder;\n\n\t@Nullable Boolean trustBuilder;\n\n\t@Nullable String runImage;\n\n\t@Nullable Map<String, String> env;\n\n\t@Nullable Boolean cleanCache;\n\n\tboolean verboseLogging;\n\n\t@Nullable PullPolicy pullPolicy;\n\n\t@Nullable Boolean publish;\n\n\t@Nullable List<String> buildpacks;\n\n\t@Nullable List<String> bindings;\n\n\t@Nullable String network;\n\n\t@Nullable List<String> tags;\n\n\t@Nullable CacheInfo buildWorkspace;\n\n\t@Nullable CacheInfo buildCache;\n\n\t@Nullable CacheInfo launchCache;\n\n\t@Nullable String createdDate;\n\n\t@Nullable String applicationDirectory;\n\n\t@Nullable List<String> securityOptions;\n\n\t@Nullable String imagePlatform;\n\n\t/**\n\t * The name of the created image.\n\t * @return the image name\n\t */\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tvoid setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * The name of the builder image to use to create the image.\n\t * @return the builder image name\n\t */\n\tpublic @Nullable String getBuilder() {\n\t\treturn this.builder;\n\t}\n\n\tvoid setBuilder(@Nullable String builder) {\n\t\tthis.builder = builder;\n\t}\n\n\t/**\n\t * If the builder should be treated as trusted.\n\t * @return {@code true} if the builder should be treated as trusted\n\t */\n\tpublic @Nullable Boolean getTrustBuilder() {\n\t\treturn this.trustBuilder;\n\t}\n\n\tvoid setTrustBuilder(@Nullable Boolean trustBuilder) {\n\t\tthis.trustBuilder = trustBuilder;\n\t}\n\n\t/**\n\t * The name of the run image to use to create the image.\n\t * @return the builder image name\n\t */\n\tpublic @Nullable String getRunImage() {\n\t\treturn this.runImage;\n\t}\n\n\tvoid setRunImage(@Nullable String runImage) {\n\t\tthis.runImage = runImage;\n\t}\n\n\t/**\n\t * Environment properties that should be passed to the builder.\n\t * @return the environment properties\n\t */\n\tpublic @Nullable Map<String, String> getEnv() {\n\t\treturn this.env;\n\t}\n\n\t/**\n\t * If the cache should be cleaned before building.\n\t * @return {@code true} if the cache should be cleaned\n\t */\n\tpublic @Nullable Boolean getCleanCache() {\n\t\treturn this.cleanCache;\n\t}\n\n\tvoid setCleanCache(@Nullable Boolean cleanCache) {\n\t\tthis.cleanCache = cleanCache;\n\t}\n\n\t/**\n\t * If verbose logging is required.\n\t * @return {@code true} for verbose logging\n\t */\n\tpublic boolean isVerboseLogging() {\n\t\treturn this.verboseLogging;\n\t}\n\n\t/**\n\t * If images should be pulled from a remote repository during image build.\n\t * @return the pull policy\n\t */\n\tpublic @Nullable PullPolicy getPullPolicy() {\n\t\treturn this.pullPolicy;\n\t}\n\n\tvoid setPullPolicy(@Nullable PullPolicy pullPolicy) {\n\t\tthis.pullPolicy = pullPolicy;\n\t}\n\n\t/**\n\t * If the built image should be pushed to a registry.\n\t * @return {@code true} if the image should be published\n\t */\n\tpublic @Nullable Boolean getPublish() {\n\t\treturn this.publish;\n\t}\n\n\tvoid setPublish(@Nullable Boolean publish) {\n\t\tthis.publish = publish;\n\t}\n\n\t/**\n\t * Returns the network the build container will connect to.\n\t * @return the network\n\t */\n\tpublic @Nullable String getNetwork() {\n\t\treturn this.network;\n\t}\n\n\tpublic void setNetwork(@Nullable String network) {\n\t\tthis.network = network;\n\t}\n\n\t/**\n\t * Returns the created date for the image.\n\t * @return the created date\n\t */\n\tpublic @Nullable String getCreatedDate() {\n\t\treturn this.createdDate;\n\t}\n\n\tpublic void setCreatedDate(@Nullable String createdDate) {\n\t\tthis.createdDate = createdDate;\n\t}\n\n\t/**\n\t * Returns the application content directory for the image.\n\t * @return the application directory\n\t */\n\tpublic @Nullable String getApplicationDirectory() {\n\t\treturn this.applicationDirectory;\n\t}\n\n\tpublic void setApplicationDirectory(@Nullable String applicationDirectory) {\n\t\tthis.applicationDirectory = applicationDirectory;\n\t}\n\n\t/**\n\t * Returns the platform (os/architecture/variant) that will be used for all pulled\n\t * images. When {@code null}, the system will choose a platform based on the host\n\t * operating system and architecture.\n\t * @return the image platform\n\t */\n\tpublic @Nullable String getImagePlatform() {\n\t\treturn this.imagePlatform;\n\t}\n\n\tpublic void setImagePlatform(@Nullable String imagePlatform) {\n\t\tthis.imagePlatform = imagePlatform;\n\t}\n\n\tBuildRequest getBuildRequest(Artifact artifact, Function<Owner, TarArchive> applicationContent) {\n\t\treturn customize(BuildRequest.of(getOrDeduceName(artifact), applicationContent));\n\t}\n\n\tprivate ImageReference getOrDeduceName(Artifact artifact) {\n\t\tif (StringUtils.hasText(this.name)) {\n\t\t\treturn ImageReference.of(this.name);\n\t\t}\n\t\tImageName imageName = ImageName.of(artifact.getArtifactId());\n\t\treturn ImageReference.of(imageName, artifact.getVersion());\n\t}\n\n\tprivate BuildRequest customize(BuildRequest request) {\n\t\tif (StringUtils.hasText(this.builder)) {\n\t\t\trequest = request.withBuilder(ImageReference.of(this.builder));\n\t\t}\n\t\tif (this.trustBuilder != null) {\n\t\t\trequest = request.withTrustBuilder(this.trustBuilder);\n\t\t}\n\t\tif (StringUtils.hasText(this.runImage)) {\n\t\t\trequest = request.withRunImage(ImageReference.of(this.runImage));\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.env)) {\n\t\t\trequest = request.withEnv(this.env);\n\t\t}\n\t\tif (this.cleanCache != null) {\n\t\t\trequest = request.withCleanCache(this.cleanCache);\n\t\t}\n\t\trequest = request.withVerboseLogging(this.verboseLogging);\n\t\tif (this.pullPolicy != null) {\n\t\t\trequest = request.withPullPolicy(this.pullPolicy);\n\t\t}\n\t\tif (this.publish != null) {\n\t\t\trequest = request.withPublish(this.publish);\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.buildpacks)) {\n\t\t\trequest = request.withBuildpacks(this.buildpacks.stream().map(BuildpackReference::of).toList());\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.bindings)) {\n\t\t\trequest = request.withBindings(this.bindings.stream().map(Binding::of).toList());\n\t\t}\n\t\trequest = request.withNetwork(this.network);\n\t\tif (!CollectionUtils.isEmpty(this.tags)) {\n\t\t\trequest = request.withTags(this.tags.stream().map(ImageReference::of).toList());\n\t\t}\n\t\tif (this.buildWorkspace != null) {\n\t\t\tCache cache = this.buildWorkspace.asCache();\n\t\t\tAssert.state(cache != null, \"'cache' must not be null\");\n\t\t\trequest = request.withBuildWorkspace(cache);\n\t\t}\n\t\tif (this.buildCache != null) {\n\t\t\tCache cache = this.buildCache.asCache();\n\t\t\tAssert.state(cache != null, \"'cache' must not be null\");\n\t\t\trequest = request.withBuildCache(cache);\n\t\t}\n\t\tif (this.launchCache != null) {\n\t\t\tCache cache = this.launchCache.asCache();\n\t\t\tAssert.state(cache != null, \"'cache' must not be null\");\n\t\t\trequest = request.withLaunchCache(cache);\n\t\t}\n\t\tif (StringUtils.hasText(this.createdDate)) {\n\t\t\trequest = request.withCreatedDate(this.createdDate);\n\t\t}\n\t\tif (StringUtils.hasText(this.applicationDirectory)) {\n\t\t\trequest = request.withApplicationDirectory(this.applicationDirectory);\n\t\t}\n\t\tif (this.securityOptions != null) {\n\t\t\trequest = request.withSecurityOptions(this.securityOptions);\n\t\t}\n\t\tif (StringUtils.hasText(this.imagePlatform)) {\n\t\t\trequest = request.withImagePlatform(this.imagePlatform);\n\t\t}\n\t\treturn request;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Include.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\n/**\n * A model for a dependency to include.\n *\n * @author David Turanski\n * @since 1.2.0\n */\npublic class Include extends FilterableDependency {\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/IncludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.List;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\n\n/**\n * An {@link ArtifactsFilter} that filters out any artifact not matching an\n * {@link Include}.\n *\n * @author David Turanski\n * @since 1.2.0\n */\npublic class IncludeFilter extends DependencyFilter {\n\n\tpublic IncludeFilter(List<Include> includes) {\n\t\tsuper(includes);\n\t}\n\n\t@Override\n\tprotected boolean filter(Artifact artifact) {\n\t\tfor (FilterableDependency dependency : getFilters()) {\n\t\t\tif (equals(artifact, dependency)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/JarTypeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.apache.maven.artifact.Artifact;\n\n/**\n * A {@link DependencyFilter} that filters dependencies based on the jar type declared in\n * their manifest.\n *\n * @author Andy Wilkinson\n */\nclass JarTypeFilter extends DependencyFilter {\n\n\tprivate static final Set<String> EXCLUDED_JAR_TYPES = Collections.unmodifiableSet(\n\t\t\tnew HashSet<>(Arrays.asList(\"annotation-processor\", \"dependencies-starter\", \"development-tool\")));\n\n\tJarTypeFilter() {\n\t\tsuper(Collections.emptyList());\n\t}\n\n\t@Override\n\tprotected boolean filter(Artifact artifact) {\n\t\ttry (JarFile jarFile = new JarFile(artifact.getFile())) {\n\t\t\tManifest manifest = jarFile.getManifest();\n\t\t\tif (manifest != null) {\n\t\t\t\tString jarType = manifest.getMainAttributes().getValue(\"Spring-Boot-Jar-Type\");\n\t\t\t\tif (jarType != null && EXCLUDED_JAR_TYPES.contains(jarType)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Continue\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/JavaCompilerPluginConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Arrays;\n\nimport org.apache.maven.model.Plugin;\nimport org.apache.maven.project.MavenProject;\nimport org.codehaus.plexus.util.xml.Xpp3Dom;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Provides access to the Maven Java Compiler plugin configuration.\n *\n * @author Scott Frederick\n */\nclass JavaCompilerPluginConfiguration {\n\n\tprivate final MavenProject project;\n\n\tJavaCompilerPluginConfiguration(MavenProject project) {\n\t\tthis.project = project;\n\t}\n\n\t@Nullable String getSourceMajorVersion() {\n\t\tString version = getConfigurationValue(\"source\");\n\n\t\tif (version == null) {\n\t\t\tversion = getPropertyValue(\"maven.compiler.source\");\n\t\t}\n\n\t\treturn majorVersionFor(version);\n\t}\n\n\t@Nullable String getTargetMajorVersion() {\n\t\tString version = getConfigurationValue(\"target\");\n\n\t\tif (version == null) {\n\t\t\tversion = getPropertyValue(\"maven.compiler.target\");\n\t\t}\n\n\t\treturn majorVersionFor(version);\n\t}\n\n\t@Nullable String getReleaseVersion() {\n\t\tString version = getConfigurationValue(\"release\");\n\n\t\tif (version == null) {\n\t\t\tversion = getPropertyValue(\"maven.compiler.release\");\n\t\t}\n\n\t\treturn majorVersionFor(version);\n\t}\n\n\tprivate @Nullable String getConfigurationValue(String propertyName) {\n\t\tPlugin plugin = this.project.getPlugin(\"org.apache.maven.plugins:maven-compiler-plugin\");\n\t\tif (plugin != null) {\n\t\t\tObject pluginConfiguration = plugin.getConfiguration();\n\t\t\tif (pluginConfiguration instanceof Xpp3Dom dom) {\n\t\t\t\treturn getNodeValue(dom, propertyName);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable String getPropertyValue(String propertyName) {\n\t\tif (this.project.getProperties().containsKey(propertyName)) {\n\t\t\treturn this.project.getProperties().get(propertyName).toString();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable String getNodeValue(Xpp3Dom dom, String... childNames) {\n\t\tXpp3Dom childNode = dom.getChild(childNames[0]);\n\n\t\tif (childNode == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (childNames.length > 1) {\n\t\t\treturn getNodeValue(childNode, Arrays.copyOfRange(childNames, 1, childNames.length));\n\t\t}\n\n\t\treturn childNode.getValue();\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate @Nullable String majorVersionFor(@Nullable String version) {\n\t\tif (version != null && version.startsWith(\"1.\")) {\n\t\t\treturn version.substring(\"1.\".length());\n\t\t}\n\t\treturn version;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/JavaProcessExecutor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.apache.maven.execution.MavenSession;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.toolchain.Toolchain;\nimport org.apache.maven.toolchain.ToolchainManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.JavaExecutable;\nimport org.springframework.boot.loader.tools.RunProcess;\n\n/**\n * Ease the execution of a Java process using Maven's toolchain support.\n *\n * @author Stephane Nicoll\n */\nclass JavaProcessExecutor {\n\n\tprivate static final int EXIT_CODE_SIGINT = 130;\n\n\tprivate final MavenSession mavenSession;\n\n\tprivate final ToolchainManager toolchainManager;\n\n\tprivate final @Nullable Consumer<RunProcess> runProcessCustomizer;\n\n\tJavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager) {\n\t\tthis(mavenSession, toolchainManager, null);\n\t}\n\n\tprivate JavaProcessExecutor(MavenSession mavenSession, ToolchainManager toolchainManager,\n\t\t\t@Nullable Consumer<RunProcess> runProcessCustomizer) {\n\t\tthis.mavenSession = mavenSession;\n\t\tthis.toolchainManager = toolchainManager;\n\t\tthis.runProcessCustomizer = runProcessCustomizer;\n\t}\n\n\tJavaProcessExecutor withRunProcessCustomizer(Consumer<RunProcess> customizer) {\n\t\tConsumer<RunProcess> combinedCustomizer = (this.runProcessCustomizer != null)\n\t\t\t\t? this.runProcessCustomizer.andThen(customizer) : customizer;\n\t\treturn new JavaProcessExecutor(this.mavenSession, this.toolchainManager, combinedCustomizer);\n\t}\n\n\tint run(File workingDirectory, List<String> args, Map<String, String> environmentVariables)\n\t\t\tthrows MojoExecutionException {\n\t\tRunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());\n\t\tif (this.runProcessCustomizer != null) {\n\t\t\tthis.runProcessCustomizer.accept(runProcess);\n\t\t}\n\t\ttry {\n\t\t\tint exitCode = runProcess.run(true, args, environmentVariables);\n\t\t\tif (!hasTerminatedSuccessfully(exitCode)) {\n\t\t\t\tthrow new MojoExecutionException(\"Process terminated with exit code: \" + exitCode);\n\t\t\t}\n\t\t\treturn exitCode;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(\"Process execution failed\", ex);\n\t\t}\n\t}\n\n\tRunProcess runAsync(File workingDirectory, List<String> args, Map<String, String> environmentVariables)\n\t\t\tthrows MojoExecutionException {\n\t\ttry {\n\t\t\tRunProcess runProcess = new RunProcess(workingDirectory, getJavaExecutable());\n\t\t\trunProcess.run(false, args, environmentVariables);\n\t\t\treturn runProcess;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(\"Process execution failed\", ex);\n\t\t}\n\t}\n\n\tprivate boolean hasTerminatedSuccessfully(int exitCode) {\n\t\treturn (exitCode == 0 || exitCode == EXIT_CODE_SIGINT);\n\t}\n\n\tprivate String getJavaExecutable() {\n\t\tToolchain toolchain = this.toolchainManager.getToolchainFromBuildContext(\"jdk\", this.mavenSession);\n\t\tString javaExecutable = (toolchain != null) ? toolchain.findTool(\"java\") : null;\n\t\treturn (javaExecutable != null) ? javaExecutable : new JavaExecutable().toString();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/Layers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Layer configuration options.\n *\n * @author Madhura Bhave\n * @since 2.3.0\n */\npublic class Layers {\n\n\tprivate boolean enabled = true;\n\n\tprivate @Nullable File configuration;\n\n\tprivate @Nullable String configurationName;\n\n\t/**\n\t * Whether a {@code layers.idx} file should be added to the jar.\n\t * @return true if a {@code layers.idx} file should be added.\n\t */\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\t/**\n\t * The location of the layers configuration file. If no file is provided, a default\n\t * configuration is used with four layers: {@code application}, {@code resources},\n\t * {@code snapshot-dependencies} and {@code dependencies}.\n\t * @return the layers configuration file\n\t */\n\tpublic @Nullable File getConfiguration() {\n\t\treturn this.configuration;\n\t}\n\n\tpublic void setConfiguration(@Nullable File configuration) {\n\t\tthis.configuration = configuration;\n\t}\n\n\t/**\n\t * The name of the layers configuration to load from the classpath. A matching file is\n\t * expected at {@code META-INF/spring/layers/<name>.xml}\n\t * @return the layers configuration name to load from the classpath\n\t */\n\tpublic @Nullable String getConfigurationName() {\n\t\treturn this.configurationName;\n\t}\n\n\tpublic void setConfigurationName(@Nullable String configurationName) {\n\t\tthis.configurationName = configurationName;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/LoggingMainClassTimeoutWarningListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.function.Supplier;\n\nimport org.apache.maven.plugin.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.Packager.MainClassTimeoutWarningListener;\n\n/**\n * {@link MainClassTimeoutWarningListener} backed by a supplied Maven {@link Log}.\n *\n * @author Phillip Webb\n */\nclass LoggingMainClassTimeoutWarningListener implements MainClassTimeoutWarningListener {\n\n\tprivate final Supplier<Log> log;\n\n\tLoggingMainClassTimeoutWarningListener(Supplier<Log> log) {\n\t\tthis.log = log;\n\t}\n\n\t@Override\n\tpublic void handleTimeoutWarning(long duration, @Nullable String mainMethod) {\n\t\tthis.log.get()\n\t\t\t.warn(\"Searching for the main-class is taking some time, \"\n\t\t\t\t\t+ \"consider using the mainClass configuration parameter\");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/MatchingGroupIdFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.AbstractArtifactFeatureFilter;\n\n/**\n * An {@link org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter\n * ArtifactsFilter} that filters by matching groupId.\n *\n * Preferred over the\n * {@link org.apache.maven.shared.artifact.filter.collection.GroupIdFilter} due to that\n * classes use of {@link String#startsWith} to match on prefix.\n *\n * @author Mark Ingram\n * @since 1.1.0\n */\npublic class MatchingGroupIdFilter extends AbstractArtifactFeatureFilter {\n\n\t/**\n\t * Create a new instance with the CSV groupId values that should be excluded.\n\t * @param exclude the group values to exclude\n\t */\n\tpublic MatchingGroupIdFilter(String exclude) {\n\t\tsuper(\"\", exclude);\n\t}\n\n\t@Override\n\tprotected String getArtifactFeature(Artifact artifact) {\n\t\treturn artifact.getGroupId();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/MavenBuildOutputTimestamp.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.nio.file.attribute.FileTime;\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.time.format.DateTimeParseException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Parse output timestamp configured for Reproducible Builds' archive entries.\n * <p>\n * Either as {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE_TIME} or as a\n * number representing seconds since the epoch (like <a href=\n * \"https://reproducible-builds.org/docs/source-date-epoch/\">SOURCE_DATE_EPOCH</a>).\n * Implementation inspired by <a href=\n * \"https://github.com/apache/maven-archiver/blob/cc2f6a219f6563f450b0c00e8ccd651520b67406/src/main/java/org/apache/maven/archiver/MavenArchiver.java#L768\">MavenArchiver</a>.\n *\n * @author Niels Basjes\n * @author Moritz Halbritter\n */\nclass MavenBuildOutputTimestamp {\n\n\tprivate static final Instant DATE_MIN = Instant.parse(\"1980-01-01T00:00:02Z\");\n\n\tprivate static final Instant DATE_MAX = Instant.parse(\"2099-12-31T23:59:59Z\");\n\n\tprivate final @Nullable String timestamp;\n\n\t/**\n\t * Creates a new {@link MavenBuildOutputTimestamp}.\n\t * @param timestamp timestamp or {@code null}\n\t */\n\tMavenBuildOutputTimestamp(@Nullable String timestamp) {\n\t\tthis.timestamp = timestamp;\n\t}\n\n\t/**\n\t * Returns the parsed timestamp as an {@code FileTime}.\n\t * @return the parsed timestamp as an {@code FileTime}, or {@code null}\n\t * @throws IllegalArgumentException if the outputTimestamp is neither ISO 8601 nor an\n\t * integer, or it's not within the valid range 1980-01-01T00:00:02Z to\n\t * 2099-12-31T23:59:59Z\n\t */\n\t@Nullable FileTime toFileTime() {\n\t\tInstant instant = toInstant();\n\t\tif (instant == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn FileTime.from(instant);\n\t}\n\n\t/**\n\t * Returns the parsed timestamp as an {@code Instant}.\n\t * @return the parsed timestamp as an {@code Instant}, or {@code null}\n\t * @throws IllegalArgumentException if the outputTimestamp is neither ISO 8601 nor an\n\t * integer, or it's not within the valid range 1980-01-01T00:00:02Z to\n\t * 2099-12-31T23:59:59Z\n\t */\n\t@Nullable Instant toInstant() {\n\t\tif (!StringUtils.hasLength(this.timestamp)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (isNumeric(this.timestamp)) {\n\t\t\treturn Instant.ofEpochSecond(Long.parseLong(this.timestamp));\n\t\t}\n\t\tif (this.timestamp.length() < 2) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tInstant instant = OffsetDateTime.parse(this.timestamp).withOffsetSameInstant(ZoneOffset.UTC).toInstant();\n\t\t\tif (instant.isBefore(DATE_MIN) || instant.isAfter(DATE_MAX)) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\tString.format(\"'%s' is not within the valid range %s to %s\", instant, DATE_MIN, DATE_MAX));\n\t\t\t}\n\t\t\treturn instant;\n\t\t}\n\t\tcatch (DateTimeParseException pe) {\n\t\t\tthrow new IllegalArgumentException(String.format(\"Can't parse '%s' to instant\", this.timestamp));\n\t\t}\n\t}\n\n\tprivate static boolean isNumeric(String str) {\n\t\tfor (char c : str.toCharArray()) {\n\t\t\tif (!Character.isDigit(c)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessAotMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.toolchain.ToolchainManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Invoke the AOT engine on the application.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 3.0.0\n */\n@Mojo(name = \"process-aot\", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true,\n\t\trequiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,\n\t\trequiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)\npublic class ProcessAotMojo extends AbstractAotMojo {\n\n\tprivate static final String AOT_PROCESSOR_CLASS_NAME = \"org.springframework.boot.SpringApplicationAotProcessor\";\n\n\t/**\n\t * Directory containing the classes and resource files that should be packaged into\n\t * the archive.\n\t */\n\t@Parameter(defaultValue = \"${project.build.outputDirectory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File classesDirectory;\n\n\t/**\n\t * Directory containing the generated sources.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/main/sources\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedSources;\n\n\t/**\n\t * Directory containing the generated resources.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/main/resources\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedResources;\n\n\t/**\n\t * Directory containing the generated classes.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/main/classes\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedClasses;\n\n\t/**\n\t * Name of the main class to use as the source for the AOT process. If not specified\n\t * the first compiled class found that contains a 'main' method will be used.\n\t */\n\t@Parameter(property = \"spring-boot.aot.main-class\")\n\tprivate @Nullable String mainClass;\n\n\t/**\n\t * Application arguments that should be taken into account for AOT processing.\n\t */\n\t@Parameter\n\t@SuppressWarnings(\"NullAway\") // maven-maven-plugin can't handle annotated arrays\n\tprivate String[] arguments;\n\n\t/**\n\t * Spring profiles to take into account for AOT processing.\n\t */\n\t@Parameter\n\t@SuppressWarnings(\"NullAway\") // maven-maven-plugin can't handle annotated arrays\n\tprivate String[] profiles;\n\n\t@Inject\n\tpublic ProcessAotMojo(ToolchainManager toolchainManager) {\n\t\tsuper(toolchainManager);\n\t}\n\n\t@Override\n\tprotected void executeAot() throws Exception {\n\t\tif (this.project.getPackaging().equals(\"pom\")) {\n\t\t\tgetLog().debug(\"process-aot goal could not be applied to pom project.\");\n\t\t\treturn;\n\t\t}\n\t\tString applicationClass = (this.mainClass != null) ? this.mainClass\n\t\t\t\t: SpringBootApplicationClassFinder.findSingleClass(this.classesDirectory);\n\t\tURL[] classPath = getClassPath();\n\t\tgenerateAotAssets(classPath, AOT_PROCESSOR_CLASS_NAME, getAotArguments(applicationClass));\n\t\tcompileSourceFiles(classPath, this.generatedSources, this.generatedClasses);\n\t\tcopyAll(this.generatedResources.toPath(), this.classesDirectory.toPath());\n\t\tcopyAll(this.generatedClasses.toPath(), this.classesDirectory.toPath());\n\t}\n\n\tprivate String[] getAotArguments(String applicationClass) {\n\t\tList<String> aotArguments = new ArrayList<>();\n\t\taotArguments.add(applicationClass);\n\t\taotArguments.add(this.generatedSources.toString());\n\t\taotArguments.add(this.generatedResources.toString());\n\t\taotArguments.add(this.generatedClasses.toString());\n\t\taotArguments.add(this.project.getGroupId());\n\t\taotArguments.add(this.project.getArtifactId());\n\t\taotArguments.addAll(resolveArguments().getArgs());\n\t\treturn aotArguments.toArray(String[]::new);\n\t}\n\n\tprivate URL[] getClassPath() throws Exception {\n\t\tFile[] directories = new File[] { this.classesDirectory, this.generatedClasses };\n\t\treturn getClassPath(directories, new ExcludeTestScopeArtifactFilter(), DEVTOOLS_EXCLUDE_FILTER);\n\t}\n\n\tprivate RunArguments resolveArguments() {\n\t\tRunArguments runArguments = new RunArguments(this.arguments);\n\t\tif (!ObjectUtils.isEmpty(this.profiles)) {\n\t\t\trunArguments.getArgs().addFirst(\"--spring.profiles.active=\" + String.join(\",\", this.profiles));\n\t\t}\n\t\treturn runArguments;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/ProcessTestAotMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.RepositoryUtils;\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.DefaultArtifact;\nimport org.apache.maven.artifact.handler.DefaultArtifactHandler;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.toolchain.ToolchainManager;\nimport org.eclipse.aether.RepositorySystem;\nimport org.eclipse.aether.collection.CollectRequest;\nimport org.eclipse.aether.resolution.ArtifactResult;\nimport org.eclipse.aether.resolution.DependencyRequest;\nimport org.eclipse.aether.resolution.DependencyResult;\nimport org.eclipse.aether.util.artifact.JavaScopes;\nimport org.eclipse.aether.util.filter.DependencyFilterUtils;\n\n/**\n * Invoke the AOT engine on tests.\n *\n * @author Phillip Webb\n * @since 3.0.0\n */\n@Mojo(name = \"process-test-aot\", defaultPhase = LifecyclePhase.PROCESS_TEST_CLASSES, threadSafe = true,\n\t\trequiresDependencyResolution = ResolutionScope.TEST, requiresDependencyCollection = ResolutionScope.TEST)\npublic class ProcessTestAotMojo extends AbstractAotMojo {\n\n\tprivate static final String JUNIT_PLATFORM_GROUP_ID = \"org.junit.platform\";\n\n\tprivate static final String JUNIT_PLATFORM_COMMONS_ARTIFACT_ID = \"junit-platform-commons\";\n\n\tprivate static final String JUNIT_PLATFORM_LAUNCHER_ARTIFACT_ID = \"junit-platform-launcher\";\n\n\tprivate static final String AOT_PROCESSOR_CLASS_NAME = \"org.springframework.boot.test.context.SpringBootTestAotProcessor\";\n\n\t/**\n\t * Directory containing the classes and resource files that should be packaged into\n\t * the archive.\n\t */\n\t@Parameter(defaultValue = \"${project.build.testOutputDirectory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File testClassesDirectory;\n\n\t/**\n\t * Directory containing the classes and resource files that should be used to run the\n\t * tests.\n\t */\n\t@Parameter(defaultValue = \"${project.build.outputDirectory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File classesDirectory;\n\n\t/**\n\t * Directory containing the generated sources.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/test/sources\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedSources;\n\n\t/**\n\t * Directory containing the generated test resources.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/test/resources\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedResources;\n\n\t/**\n\t * Directory containing the generated test classes.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/test/classes\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedTestClasses;\n\n\t/**\n\t * Directory containing the generated test classes.\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}/spring-aot/main/classes\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File generatedClasses;\n\n\tprivate final RepositorySystem repositorySystem;\n\n\t@Inject\n\tpublic ProcessTestAotMojo(ToolchainManager toolchainManager, RepositorySystem repositorySystem) {\n\t\tsuper(toolchainManager);\n\t\tthis.repositorySystem = repositorySystem;\n\t}\n\n\t@Override\n\tprotected void executeAot() throws Exception {\n\t\tif (this.project.getPackaging().equals(\"pom\")) {\n\t\t\tgetLog().debug(\"process-test-aot goal could not be applied to pom project.\");\n\t\t\treturn;\n\t\t}\n\t\tif (Boolean.getBoolean(\"maven.test.skip\")) {\n\t\t\tgetLog().info(\"Skipping AOT test processing since tests are skipped\");\n\t\t\treturn;\n\t\t}\n\t\tPath testOutputDirectory = Paths.get(this.project.getBuild().getTestOutputDirectory());\n\t\tif (Files.notExists(testOutputDirectory)) {\n\t\t\tgetLog().info(\"Skipping AOT test processing since no tests have been detected\");\n\t\t\treturn;\n\t\t}\n\t\tgenerateAotAssets(getClassPath(true), AOT_PROCESSOR_CLASS_NAME, getAotArguments());\n\t\tcompileSourceFiles(getClassPath(false), this.generatedSources, this.generatedTestClasses);\n\t\tcopyAll(this.generatedResources.toPath().resolve(\"META-INF/native-image\"),\n\t\t\t\tthis.testClassesDirectory.toPath().resolve(\"META-INF/native-image\"));\n\t\tcopyAll(this.generatedTestClasses.toPath(), this.testClassesDirectory.toPath());\n\t}\n\n\tprivate String[] getAotArguments() {\n\t\tList<String> aotArguments = new ArrayList<>();\n\t\taotArguments.add(this.testClassesDirectory.toPath().toAbsolutePath().normalize().toString());\n\t\taotArguments.add(this.generatedSources.toString());\n\t\taotArguments.add(this.generatedResources.toString());\n\t\taotArguments.add(this.generatedTestClasses.toString());\n\t\taotArguments.add(this.project.getGroupId());\n\t\taotArguments.add(this.project.getArtifactId());\n\t\treturn aotArguments.toArray(String[]::new);\n\t}\n\n\tprotected URL[] getClassPath(boolean includeJUnitPlatformLauncher) throws Exception {\n\t\tFile[] directories = new File[] { this.testClassesDirectory, this.generatedTestClasses, this.classesDirectory,\n\t\t\t\tthis.generatedClasses };\n\t\tURL[] classPath = getClassPath(directories, DEVTOOLS_EXCLUDE_FILTER);\n\t\tif (!includeJUnitPlatformLauncher || this.project.getArtifactMap()\n\t\t\t.containsKey(JUNIT_PLATFORM_GROUP_ID + \":\" + JUNIT_PLATFORM_LAUNCHER_ARTIFACT_ID)) {\n\t\t\treturn classPath;\n\t\t}\n\t\treturn addJUnitPlatformLauncher(classPath);\n\t}\n\n\tprivate URL[] addJUnitPlatformLauncher(URL[] classPath) throws Exception {\n\t\tString version = getJUnitPlatformVersion();\n\t\tDefaultArtifactHandler handler = new DefaultArtifactHandler(\"jar\");\n\t\thandler.setIncludesDependencies(true);\n\t\tSet<Artifact> artifacts = resolveArtifact(new DefaultArtifact(JUNIT_PLATFORM_GROUP_ID,\n\t\t\t\tJUNIT_PLATFORM_LAUNCHER_ARTIFACT_ID, version, null, \"jar\", null, handler));\n\t\tSet<URL> fullClassPath = new LinkedHashSet<>(Arrays.asList(classPath));\n\t\tfor (Artifact artifact : artifacts) {\n\t\t\tfullClassPath.add(artifact.getFile().toURI().toURL());\n\t\t}\n\t\treturn fullClassPath.toArray(URL[]::new);\n\t}\n\n\tprivate String getJUnitPlatformVersion() throws MojoExecutionException {\n\t\tString id = JUNIT_PLATFORM_GROUP_ID + \":\" + JUNIT_PLATFORM_COMMONS_ARTIFACT_ID;\n\t\tArtifact platformCommonsArtifact = this.project.getArtifactMap().get(id);\n\t\tString version = (platformCommonsArtifact != null) ? platformCommonsArtifact.getBaseVersion() : null;\n\t\tif (version == null) {\n\t\t\tthrow new MojoExecutionException(\n\t\t\t\t\t\"Unable to find '%s' dependency. Please ensure JUnit is correctly configured.\".formatted(id));\n\t\t}\n\t\treturn version;\n\t}\n\n\tprivate Set<Artifact> resolveArtifact(Artifact artifact) throws Exception {\n\t\tCollectRequest collectRequest = new CollectRequest();\n\t\tcollectRequest.setRoot(RepositoryUtils.toDependency(artifact, null));\n\t\tcollectRequest.setRepositories(this.project.getRemotePluginRepositories());\n\t\tDependencyRequest request = new DependencyRequest();\n\t\trequest.setCollectRequest(collectRequest);\n\t\trequest.setFilter(DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME));\n\t\tDependencyResult dependencyResult = this.repositorySystem\n\t\t\t.resolveDependencies(getSession().getRepositorySession(), request);\n\t\treturn dependencyResult.getArtifactResults()\n\t\t\t.stream()\n\t\t\t.map(ArtifactResult::getArtifact)\n\t\t\t.map(RepositoryUtils::toArtifact)\n\t\t\t.collect(Collectors.toSet());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/PropertiesMergingResourceTransformer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\n\nimport org.apache.maven.plugins.shade.relocation.Relocator;\nimport org.apache.maven.plugins.shade.resource.ReproducibleResourceTransformer;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Extension for the <a href=\"https://maven.apache.org/plugins/maven-shade-plugin/\">Maven\n * shade plugin</a> to allow properties files (e.g. {@literal META-INF/spring.factories})\n * to be merged without losing any information.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 1.0.0\n */\npublic class PropertiesMergingResourceTransformer implements ReproducibleResourceTransformer {\n\n\t// Set this in pom configuration with <resource>...</resource>\n\tprivate @Nullable String resource;\n\n\tprivate final Properties data = new Properties();\n\n\tprivate long time;\n\n\t/**\n\t * Return the data the properties being merged.\n\t * @return the data\n\t */\n\tpublic Properties getData() {\n\t\treturn this.data;\n\t}\n\n\t@Override\n\tpublic boolean canTransformResource(String resource) {\n\t\treturn this.resource != null && this.resource.equalsIgnoreCase(resource);\n\t}\n\n\t@Override\n\t@Deprecated(since = \"2.4.0\", forRemoval = false)\n\tpublic void processResource(String resource, InputStream inputStream, List<Relocator> relocators)\n\t\t\tthrows IOException {\n\t\tprocessResource(resource, inputStream, relocators, 0);\n\t}\n\n\t@Override\n\tpublic void processResource(String resource, InputStream inputStream, List<Relocator> relocators, long time)\n\t\t\tthrows IOException {\n\t\tProperties properties = new Properties();\n\t\tproperties.load(inputStream);\n\t\tproperties.forEach((name, value) -> process((String) name, (String) value));\n\t\tif (time > this.time) {\n\t\t\tthis.time = time;\n\t\t}\n\t}\n\n\tprivate void process(String name, String value) {\n\t\tString existing = this.data.getProperty(name);\n\t\tthis.data.setProperty(name, (existing != null) ? existing + \",\" + value : value);\n\t}\n\n\t@Override\n\tpublic boolean hasTransformedResource() {\n\t\treturn !this.data.isEmpty();\n\t}\n\n\t@Override\n\tpublic void modifyOutputStream(JarOutputStream os) throws IOException {\n\t\tAssert.state(this.resource != null, \"'resource' must not be null\");\n\t\tJarEntry jarEntry = new JarEntry(this.resource);\n\t\tjarEntry.setTime(this.time);\n\t\tos.putNextEntry(jarEntry);\n\t\tthis.data.store(os, \"Merged by PropertiesMergingResourceTransformer\");\n\t\tos.flush();\n\t\tthis.data.clear();\n\t}\n\n\tpublic @Nullable String getResource() {\n\t\treturn this.resource;\n\t}\n\n\tpublic void setResource(@Nullable String resource) {\n\t\tthis.resource = resource;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.attribute.FileTime;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.model.Dependency;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.project.MavenProjectHelper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.LayoutFactory;\nimport org.springframework.boot.loader.tools.Libraries;\nimport org.springframework.boot.loader.tools.Repackager;\nimport org.springframework.lang.Contract;\n\n/**\n * Repackage existing JAR and WAR archives so that they can be executed from the command\n * line using {@literal java -jar}. With <code>layout=NONE</code> can also be used simply\n * to package a JAR with nested dependencies (and no main class, so not executable).\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Björn Lindström\n * @author Scott Frederick\n * @since 1.0.0\n */\n@Mojo(name = \"repackage\", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true,\n\t\trequiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,\n\t\trequiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)\npublic class RepackageMojo extends AbstractPackagerMojo {\n\n\tprivate static final Pattern WHITE_SPACE_PATTERN = Pattern.compile(\"\\\\s+\");\n\n\t/**\n\t * Directory containing the generated archive.\n\t * @since 1.0.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.directory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File outputDirectory;\n\n\t/**\n\t * Name of the generated archive.\n\t * @since 1.0.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.finalName}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String finalName;\n\n\t/**\n\t * Skip the execution.\n\t * @since 1.2.0\n\t */\n\t@Parameter(property = \"spring-boot.repackage.skip\", defaultValue = \"false\")\n\tprivate boolean skip;\n\n\t/**\n\t * Classifier to add to the repackaged archive. If not given, the main artifact will\n\t * be replaced by the repackaged archive. If given, the classifier will also be used\n\t * to determine the source archive to repackage: if an artifact with that classifier\n\t * already exists, it will be used as source and replaced. If no such artifact exists,\n\t * the main artifact will be used as source and the repackaged archive will be\n\t * attached as a supplemental artifact with that classifier. Attaching the artifact\n\t * allows to deploy it alongside to the original one, see <a href=\n\t * \"https://maven.apache.org/plugins/maven-deploy-plugin/examples/deploying-with-classifiers.html\"\n\t * >the Maven documentation for more details</a>.\n\t * @since 1.0.0\n\t */\n\t@Parameter\n\tprivate @Nullable String classifier;\n\n\t/**\n\t * Attach the repackaged archive to be installed into your local Maven repository or\n\t * deployed to a remote repository. If no classifier has been configured, it will\n\t * replace the normal jar. If a {@code classifier} has been configured such that the\n\t * normal jar and the repackaged jar are different, it will be attached alongside the\n\t * normal jar. When the property is set to {@code false}, the repackaged archive will\n\t * not be installed or deployed.\n\t * @since 1.4.0\n\t */\n\t@Parameter(defaultValue = \"true\")\n\tprivate boolean attach = true;\n\n\t/**\n\t * A list of the libraries that must be unpacked from uber jars in order to run.\n\t * Specify each library as a {@code <dependency>} with a {@code <groupId>} and a\n\t * {@code <artifactId>} and they will be unpacked at runtime.\n\t * @since 1.1.0\n\t */\n\t@Parameter\n\tprivate @Nullable List<Dependency> requiresUnpack;\n\n\t/**\n\t * Timestamp for reproducible output archive entries, either formatted as ISO 8601\n\t * (<code>yyyy-MM-dd'T'HH:mm:ssXXX</code>) or an {@code int} representing seconds\n\t * since the epoch.\n\t * @since 2.3.0\n\t */\n\t@Parameter(defaultValue = \"${project.build.outputTimestamp}\")\n\tprivate @Nullable String outputTimestamp;\n\n\t/**\n\t * The type of archive (which corresponds to how the dependencies are laid out inside\n\t * it). Possible values are {@code JAR}, {@code WAR}, {@code ZIP}, {@code DIR},\n\t * {@code NONE}. Defaults to a guess based on the archive type.\n\t * @since 1.0.0\n\t */\n\t@Parameter(property = \"spring-boot.repackage.layout\")\n\tprivate @Nullable LayoutType layout;\n\n\t/**\n\t * The layout factory that will be used to create the executable archive if no\n\t * explicit layout is set. Alternative layouts implementations can be provided by 3rd\n\t * parties.\n\t * @since 1.5.0\n\t */\n\t@Parameter\n\tprivate @Nullable LayoutFactory layoutFactory;\n\n\t@Inject\n\tpublic RepackageMojo(MavenProjectHelper projectHelper) {\n\t\tsuper(projectHelper);\n\t}\n\n\t/**\n\t * Return the type of archive that should be packaged by this MOJO.\n\t * @return the value of the {@code layout} parameter, or {@code null} if the parameter\n\t * is not provided\n\t */\n\t@Override\n\tprotected @Nullable LayoutType getLayout() {\n\t\treturn this.layout;\n\t}\n\n\t/**\n\t * Return the layout factory that will be used to determine the\n\t * {@link AbstractPackagerMojo.LayoutType} if no explicit layout is set.\n\t * @return the value of the {@code layoutFactory} parameter, or {@code null} if the\n\t * parameter is not provided\n\t */\n\t@Override\n\tprotected @Nullable LayoutFactory getLayoutFactory() {\n\t\treturn this.layoutFactory;\n\t}\n\n\t@Override\n\tpublic void execute() throws MojoExecutionException, MojoFailureException {\n\t\tif (this.project.getPackaging().equals(\"pom\")) {\n\t\t\tgetLog().debug(\"repackage goal could not be applied to pom project.\");\n\t\t\treturn;\n\t\t}\n\t\tif (this.skip) {\n\t\t\tgetLog().debug(\"skipping repackaging as per configuration.\");\n\t\t\treturn;\n\t\t}\n\t\trepackage();\n\t}\n\n\tprivate void repackage() throws MojoExecutionException {\n\t\tArtifact source = getSourceArtifact(this.classifier);\n\t\tFile target = getTargetFile(this.finalName, this.classifier, this.outputDirectory);\n\t\tif (source.getFile() == null) {\n\t\t\tthrow new MojoExecutionException(\n\t\t\t\t\t\"Source file is not available, make sure 'package' runs as part of the same lifecycle\");\n\t\t}\n\t\tRepackager repackager = getRepackager(source.getFile());\n\t\tLibraries libraries = getLibraries(this.requiresUnpack);\n\t\ttry {\n\t\t\trepackager.repackage(target, libraries, parseOutputTimestamp());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t\tupdateArtifact(source, target, repackager.getBackupFile());\n\t}\n\n\tprivate @Nullable FileTime parseOutputTimestamp() throws MojoExecutionException {\n\t\ttry {\n\t\t\treturn new MavenBuildOutputTimestamp(this.outputTimestamp).toFileTime();\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\tthrow new MojoExecutionException(\"Invalid value for parameter 'outputTimestamp'\", ex);\n\t\t}\n\t}\n\n\tprivate Repackager getRepackager(File source) {\n\t\treturn getConfiguredPackager(() -> new Repackager(source));\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate @Nullable String removeLineBreaks(@Nullable String description) {\n\t\treturn (description != null) ? WHITE_SPACE_PATTERN.matcher(description).replaceAll(\" \") : null;\n\t}\n\n\tprivate void updateArtifact(Artifact source, File target, File original) {\n\t\tif (this.attach) {\n\t\t\tattachArtifact(source, target, original);\n\t\t}\n\t\telse if (source.getFile().equals(target) && original.exists()) {\n\t\t\tString artifactId = (this.classifier != null) ? \"artifact with classifier \" + this.classifier\n\t\t\t\t\t: \"main artifact\";\n\t\t\tgetLog().info(String.format(\"Updating %s %s to %s\", artifactId, source.getFile(), original));\n\t\t\tsource.setFile(original);\n\t\t}\n\t\telse if (this.classifier != null) {\n\t\t\tgetLog().info(\"Creating repackaged archive \" + target + \" with classifier \" + this.classifier);\n\t\t}\n\t}\n\n\tprivate void attachArtifact(Artifact source, File target, File original) {\n\t\tif (this.classifier != null && !source.getFile().equals(target)) {\n\t\t\tgetLog().info(\"Attaching repackaged archive \" + target + \" with classifier \" + this.classifier);\n\t\t\tthis.projectHelper.attachArtifact(this.project, this.project.getPackaging(), this.classifier, target);\n\t\t}\n\t\telse {\n\t\t\tString artifactId = (this.classifier != null) ? \"artifact with classifier \" + this.classifier\n\t\t\t\t\t: \"main artifact\";\n\t\t\tgetLog()\n\t\t\t\t.info(String.format(\"Replacing %s %s with repackaged archive, adding nested dependencies in BOOT-INF/.\",\n\t\t\t\t\t\tartifactId, source.getFile()));\n\t\t\tgetLog().info(\"The original artifact has been renamed to \" + original);\n\t\t\tsource.setFile(target);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunArguments.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Arrays;\nimport java.util.Deque;\nimport java.util.LinkedList;\n\nimport org.codehaus.plexus.util.cli.CommandLineUtils;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Parse and expose arguments specified in a single string.\n *\n * @author Stephane Nicoll\n */\nclass RunArguments {\n\n\tprivate static final String[] NO_ARGS = {};\n\n\tprivate final Deque<String> args = new LinkedList<>();\n\n\tRunArguments(@Nullable String arguments) {\n\t\tthis(parseArgs(arguments));\n\t}\n\n\t@SuppressWarnings(\"NullAway\") // Maven can't handle nullable arrays\n\tRunArguments(@Nullable String[] args) {\n\t\tthis((args != null) ? Arrays.asList(args) : null);\n\t}\n\n\tRunArguments(@Nullable Iterable<@Nullable String> args) {\n\t\tif (args != null) {\n\t\t\tfor (String arg : args) {\n\t\t\t\tif (arg != null) {\n\t\t\t\t\tthis.args.add(arg);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDeque<String> getArgs() {\n\t\treturn this.args;\n\t}\n\n\tString[] asArray() {\n\t\treturn this.args.toArray(new String[0]);\n\t}\n\n\tstatic String[] parseArgs(@Nullable String arguments) {\n\t\tif (arguments == null || arguments.trim().isEmpty()) {\n\t\t\treturn NO_ARGS;\n\t\t}\n\t\ttry {\n\t\t\targuments = arguments.replace('\\n', ' ').replace('\\t', ' ');\n\t\t\treturn CommandLineUtils.translateCommandline(arguments);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to parse arguments [\" + arguments + \"]\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RunMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.Execute;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.toolchain.ToolchainManager;\n\nimport org.springframework.boot.loader.tools.RunProcess;\n\n/**\n * Run an application in place.\n *\n * @author Phillip Webb\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 1.0.0\n */\n@Mojo(name = \"run\", requiresProject = true, defaultPhase = LifecyclePhase.VALIDATE,\n\t\trequiresDependencyResolution = ResolutionScope.TEST)\n@Execute(phase = LifecyclePhase.TEST_COMPILE)\npublic class RunMojo extends AbstractRunMojo {\n\n\t/**\n\t * Whether the JVM's launch should be optimized.\n\t * @since 2.2.0\n\t */\n\t@Parameter(property = \"spring-boot.run.optimizedLaunch\", defaultValue = \"true\")\n\tprivate boolean optimizedLaunch;\n\n\t/**\n\t * Flag to include the test classpath when running.\n\t * @since 1.3.0\n\t */\n\t@Parameter(property = \"spring-boot.run.useTestClasspath\", defaultValue = \"false\")\n\tprivate boolean useTestClasspath;\n\n\t@Inject\n\tpublic RunMojo(ToolchainManager toolchainManager) {\n\t\tsuper(toolchainManager);\n\t}\n\n\t@Override\n\tprotected RunArguments resolveJvmArguments() {\n\t\tRunArguments jvmArguments = super.resolveJvmArguments();\n\t\tif (this.optimizedLaunch) {\n\t\t\tjvmArguments.getArgs().addFirst(\"-XX:TieredStopAtLevel=1\");\n\t\t}\n\t\treturn jvmArguments;\n\t}\n\n\t@Override\n\tprotected void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,\n\t\t\tMap<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException {\n\t\tprocessExecutor\n\t\t\t.withRunProcessCustomizer(\n\t\t\t\t\t(runProcess) -> Runtime.getRuntime().addShutdownHook(new Thread(new RunProcessKiller(runProcess))))\n\t\t\t.run(workingDirectory, args, environmentVariables);\n\t}\n\n\t@Override\n\tprotected boolean isUseTestClasspath() {\n\t\treturn this.useTestClasspath;\n\t}\n\n\tprivate static final class RunProcessKiller implements Runnable {\n\n\t\tprivate final RunProcess runProcess;\n\n\t\tprivate RunProcessKiller(RunProcess runProcess) {\n\t\t\tthis.runProcess = runProcess;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tthis.runProcess.kill();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringApplicationAdminClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\n\nimport javax.management.AttributeNotFoundException;\nimport javax.management.InstanceNotFoundException;\nimport javax.management.MBeanException;\nimport javax.management.MBeanServerConnection;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\nimport javax.management.ReflectionException;\nimport javax.management.remote.JMXConnector;\nimport javax.management.remote.JMXConnectorFactory;\nimport javax.management.remote.JMXServiceURL;\n\nimport org.apache.maven.plugin.MojoExecutionException;\n\n/**\n * A JMX client for the {@code SpringApplicationAdmin} MBean. Permits to obtain\n * information about a given Spring application.\n *\n * @author Stephane Nicoll\n */\nclass SpringApplicationAdminClient {\n\n\t// Note: see SpringApplicationAdminJmxAutoConfiguration\n\tstatic final String DEFAULT_OBJECT_NAME = \"org.springframework.boot:type=Admin,name=SpringApplication\";\n\n\tprivate final MBeanServerConnection connection;\n\n\tprivate final ObjectName objectName;\n\n\tSpringApplicationAdminClient(MBeanServerConnection connection, String jmxName) {\n\t\tthis.connection = connection;\n\t\tthis.objectName = toObjectName(jmxName);\n\t}\n\n\t/**\n\t * Check if the spring application managed by this instance is ready. Returns\n\t * {@code false} if the mbean is not yet deployed so this method should be repeatedly\n\t * called until a timeout is reached.\n\t * @return {@code true} if the application is ready to service requests\n\t * @throws MojoExecutionException if the JMX service could not be contacted\n\t */\n\tboolean isReady() throws MojoExecutionException {\n\t\ttry {\n\t\t\treturn (Boolean) this.connection.getAttribute(this.objectName, \"Ready\");\n\t\t}\n\t\tcatch (InstanceNotFoundException ex) {\n\t\t\treturn false; // Instance not available yet\n\t\t}\n\t\tcatch (AttributeNotFoundException ex) {\n\t\t\tthrow new IllegalStateException(\"Unexpected: attribute 'Ready' not available\", ex);\n\t\t}\n\t\tcatch (ReflectionException ex) {\n\t\t\tthrow new MojoExecutionException(\"Failed to retrieve Ready attribute\", ex.getCause());\n\t\t}\n\t\tcatch (MBeanException | IOException ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Stop the application managed by this instance.\n\t * @throws MojoExecutionException if the JMX service could not be contacted\n\t * @throws IOException if an I/O error occurs\n\t * @throws InstanceNotFoundException if the lifecycle mbean cannot be found\n\t */\n\tvoid stop() throws MojoExecutionException, IOException, InstanceNotFoundException {\n\t\ttry {\n\t\t\tthis.connection.invoke(this.objectName, \"shutdown\", null, null);\n\t\t}\n\t\tcatch (ReflectionException ex) {\n\t\t\tthrow new MojoExecutionException(\"Shutdown failed\", ex.getCause());\n\t\t}\n\t\tcatch (MBeanException ex) {\n\t\t\tthrow new MojoExecutionException(\"Could not invoke shutdown operation\", ex);\n\t\t}\n\t}\n\n\tprivate ObjectName toObjectName(String name) {\n\t\ttry {\n\t\t\treturn new ObjectName(name);\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid jmx name '\" + name + \"'\");\n\t\t}\n\t}\n\n\t/**\n\t * Create a connector for an {@link javax.management.MBeanServer} exposed on the\n\t * current machine and the current port. Security should be disabled.\n\t * @param port the port on which the mbean server is exposed\n\t * @return a connection\n\t * @throws IOException if the connection to that server failed\n\t */\n\tstatic JMXConnector connect(int port) throws IOException {\n\t\tString url = \"service:jmx:rmi:///jndi/rmi://127.0.0.1:\" + port + \"/jmxrmi\";\n\t\tJMXServiceURL serviceUrl = new JMXServiceURL(url);\n\t\treturn JMXConnectorFactory.connect(serviceUrl, null);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SpringBootApplicationClassFinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.apache.maven.plugin.MojoExecutionException;\n\nimport org.springframework.boot.loader.tools.MainClassFinder;\n\n/**\n * Find a single Spring Boot Application class match based on directory.\n *\n * @author Stephane Nicoll\n * @see MainClassFinder\n */\nabstract class SpringBootApplicationClassFinder {\n\n\tprivate static final String SPRING_BOOT_APPLICATION_CLASS_NAME = \"org.springframework.boot.autoconfigure.SpringBootApplication\";\n\n\tstatic String findSingleClass(File classesDirectory) throws MojoExecutionException {\n\t\treturn findSingleClass(List.of(classesDirectory));\n\t}\n\n\tstatic String findSingleClass(List<File> classesDirectories) throws MojoExecutionException {\n\t\ttry {\n\t\t\tfor (File classesDirectory : classesDirectories) {\n\t\t\t\tString mainClass = MainClassFinder.findSingleMainClass(classesDirectory,\n\t\t\t\t\t\tSPRING_BOOT_APPLICATION_CLASS_NAME);\n\t\t\t\tif (mainClass != null) {\n\t\t\t\t\treturn mainClass;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new MojoExecutionException(\"Unable to find a suitable main class, please add a 'mainClass' property\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoExecutionException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StartMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.ConnectException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\n\nimport javax.inject.Inject;\nimport javax.management.MBeanServerConnection;\nimport javax.management.ReflectionException;\nimport javax.management.remote.JMXConnector;\n\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.toolchain.ToolchainManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.RunProcess;\n\n/**\n * Start a spring application. Contrary to the {@code run} goal, this does not block and\n * allows other goals to operate on the application. This goal is typically used in\n * integration test scenario where the application is started before a test suite and\n * stopped after.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n * @see StopMojo\n */\n@Mojo(name = \"start\", requiresProject = true, defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST,\n\t\trequiresDependencyResolution = ResolutionScope.TEST)\npublic class StartMojo extends AbstractRunMojo {\n\n\tprivate static final String ENABLE_MBEAN_PROPERTY = \"--spring.application.admin.enabled=true\";\n\n\tprivate static final String JMX_NAME_PROPERTY_PREFIX = \"--spring.application.admin.jmx-name=\";\n\n\t/**\n\t * The JMX name of the automatically deployed MBean managing the lifecycle of the\n\t * spring application.\n\t */\n\t@Parameter(defaultValue = SpringApplicationAdminClient.DEFAULT_OBJECT_NAME)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String jmxName;\n\n\t/**\n\t * The port to use to expose the platform MBeanServer.\n\t */\n\t@Parameter(defaultValue = \"9001\")\n\tprivate int jmxPort;\n\n\t/**\n\t * The number of milliseconds to wait between each attempt to check if the spring\n\t * application is ready.\n\t */\n\t@Parameter(property = \"spring-boot.start.wait\", defaultValue = \"500\")\n\tprivate long wait;\n\n\t/**\n\t * The maximum number of attempts to check if the spring application is ready.\n\t * Combined with the \"wait\" argument, this gives a global timeout value (30 sec by\n\t * default)\n\t */\n\t@Parameter(property = \"spring-boot.start.maxAttempts\", defaultValue = \"60\")\n\tprivate int maxAttempts;\n\n\tprivate final Object lock = new Object();\n\n\t/**\n\t * Flag to include the test classpath when running.\n\t */\n\t@Parameter(property = \"spring-boot.run.useTestClasspath\", defaultValue = \"false\")\n\tprivate boolean useTestClasspath;\n\n\t@Inject\n\tpublic StartMojo(ToolchainManager toolchainManager) {\n\t\tsuper(toolchainManager);\n\t}\n\n\t@Override\n\tprotected void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,\n\t\t\tMap<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException {\n\t\tRunProcess runProcess = processExecutor.runAsync(workingDirectory, args, environmentVariables);\n\t\ttry {\n\t\t\twaitForSpringApplication();\n\t\t}\n\t\tcatch (MojoExecutionException | MojoFailureException ex) {\n\t\t\trunProcess.kill();\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@Override\n\tprotected RunArguments resolveApplicationArguments() {\n\t\tRunArguments applicationArguments = super.resolveApplicationArguments();\n\t\tapplicationArguments.getArgs().addLast(ENABLE_MBEAN_PROPERTY);\n\t\tapplicationArguments.getArgs().addLast(JMX_NAME_PROPERTY_PREFIX + this.jmxName);\n\t\treturn applicationArguments;\n\t}\n\n\t@Override\n\tprotected RunArguments resolveJvmArguments() {\n\t\tRunArguments jvmArguments = super.resolveJvmArguments();\n\t\tList<String> remoteJmxArguments = new ArrayList<>();\n\t\tremoteJmxArguments.add(\"-Dcom.sun.management.jmxremote\");\n\t\tremoteJmxArguments.add(\"-Dcom.sun.management.jmxremote.port=\" + this.jmxPort);\n\t\tremoteJmxArguments.add(\"-Dcom.sun.management.jmxremote.authenticate=false\");\n\t\tremoteJmxArguments.add(\"-Dcom.sun.management.jmxremote.ssl=false\");\n\t\tremoteJmxArguments.add(\"-Djava.rmi.server.hostname=127.0.0.1\");\n\t\tjvmArguments.getArgs().addAll(remoteJmxArguments);\n\t\treturn jvmArguments;\n\t}\n\n\tprivate void waitForSpringApplication() throws MojoFailureException, MojoExecutionException {\n\t\ttry {\n\t\t\tgetLog().debug(\"Connecting to local MBeanServer at port \" + this.jmxPort);\n\t\t\ttry (JMXConnector connector = execute(this.wait, this.maxAttempts, new CreateJmxConnector(this.jmxPort))) {\n\t\t\t\tif (connector == null) {\n\t\t\t\t\tthrow new MojoExecutionException(\"JMX MBean server was not reachable before the configured \"\n\t\t\t\t\t\t\t+ \"timeout (\" + (this.wait * this.maxAttempts) + \"ms\");\n\t\t\t\t}\n\t\t\t\tgetLog().debug(\"Connected to local MBeanServer at port \" + this.jmxPort);\n\t\t\t\tMBeanServerConnection connection = connector.getMBeanServerConnection();\n\t\t\t\tdoWaitForSpringApplication(connection);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new MojoFailureException(\"Could not contact Spring Boot application via JMX on port \" + this.jmxPort\n\t\t\t\t\t+ \". Please make sure that no other process is using that port\", ex);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MojoExecutionException(\"Failed to connect to MBean server at port \" + this.jmxPort, ex);\n\t\t}\n\t}\n\n\tprivate void doWaitForSpringApplication(MBeanServerConnection connection)\n\t\t\tthrows MojoExecutionException, MojoFailureException {\n\t\tfinal SpringApplicationAdminClient client = new SpringApplicationAdminClient(connection, this.jmxName);\n\t\ttry {\n\t\t\tCallable<@Nullable Boolean> isReady = () -> (client.isReady() ? true : null);\n\t\t\texecute(this.wait, this.maxAttempts, isReady);\n\t\t}\n\t\tcatch (ReflectionException ex) {\n\t\t\tthrow new MojoExecutionException(\"Unable to retrieve 'ready' attribute\", ex.getCause());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MojoFailureException(\"Could not invoke shutdown operation\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Execute a task, retrying it on failure.\n\t * @param <T> the result type\n\t * @param wait the wait time\n\t * @param maxAttempts the maximum number of attempts\n\t * @param callback the task to execute (possibly multiple times). The callback should\n\t * return {@code null} to indicate that another attempt should be made\n\t * @return the result\n\t * @throws Exception in case of execution errors\n\t */\n\tpublic <T> T execute(long wait, int maxAttempts, Callable<@Nullable T> callback) throws Exception {\n\t\tgetLog().debug(\"Waiting for spring application to start...\");\n\t\tfor (int i = 0; i < maxAttempts; i++) {\n\t\t\tT result = callback.call();\n\t\t\tif (result != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tString message = \"Spring application is not ready yet, waiting \" + wait + \"ms (attempt \" + (i + 1) + \")\";\n\t\t\tgetLog().debug(message);\n\t\t\tsynchronized (this.lock) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.lock.wait(wait);\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t\tthrow new IllegalStateException(\"Interrupted while waiting for Spring Boot app to start.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new MojoExecutionException(\n\t\t\t\t\"Spring application did not start before the configured timeout (\" + (wait * maxAttempts) + \"ms\");\n\t}\n\n\t@Override\n\tprotected boolean isUseTestClasspath() {\n\t\treturn this.useTestClasspath;\n\t}\n\n\tprivate class CreateJmxConnector implements Callable<@Nullable JMXConnector> {\n\n\t\tprivate final int port;\n\n\t\tCreateJmxConnector(int port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable JMXConnector call() throws Exception {\n\t\t\ttry {\n\t\t\t\treturn SpringApplicationAdminClient.connect(this.port);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tif (hasCauseWithType(ex, ConnectException.class)) {\n\t\t\t\t\tString message = \"MBean server at port \" + this.port + \" is not up yet...\";\n\t\t\t\t\tgetLog().debug(message);\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean hasCauseWithType(Throwable t, Class<? extends Exception> type) {\n\t\t\treturn type.isAssignableFrom(t.getClass()) || t.getCause() != null && hasCauseWithType(t.getCause(), type);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/StopMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\n\nimport javax.management.InstanceNotFoundException;\nimport javax.management.MBeanServerConnection;\nimport javax.management.remote.JMXConnector;\n\nimport org.apache.maven.plugin.AbstractMojo;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.project.MavenProject;\n\n/**\n * Stop an application that has been started by the \"start\" goal. Typically invoked once a\n * test suite has completed.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@Mojo(name = \"stop\", requiresProject = true, defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST)\npublic class StopMojo extends AbstractMojo {\n\n\t/**\n\t * The Maven project.\n\t * @since 1.4.1\n\t */\n\t@Parameter(defaultValue = \"${project}\", readonly = true, required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MavenProject project;\n\n\t/**\n\t * The JMX name of the automatically deployed MBean managing the lifecycle of the\n\t * application.\n\t */\n\t@Parameter(defaultValue = SpringApplicationAdminClient.DEFAULT_OBJECT_NAME)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String jmxName;\n\n\t/**\n\t * The port to use to look up the platform MBeanServer.\n\t */\n\t@Parameter(defaultValue = \"9001\")\n\tprivate int jmxPort;\n\n\t/**\n\t * Skip the execution.\n\t * @since 1.3.2\n\t */\n\t@Parameter(property = \"spring-boot.stop.skip\", defaultValue = \"false\")\n\tprivate boolean skip;\n\n\t@Override\n\tpublic void execute() throws MojoExecutionException, MojoFailureException {\n\t\tif (this.skip) {\n\t\t\tgetLog().debug(\"skipping stop as per configuration.\");\n\t\t\treturn;\n\t\t}\n\t\tgetLog().info(\"Stopping application...\");\n\t\ttry (JMXConnector connector = SpringApplicationAdminClient.connect(this.jmxPort)) {\n\t\t\tMBeanServerConnection connection = connector.getMBeanServerConnection();\n\t\t\tstop(connection);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// The response won't be received as the server has died - ignoring\n\t\t\tgetLog().debug(\"Service is not reachable anymore (\" + ex.getMessage() + \")\");\n\t\t}\n\t}\n\n\tprivate void stop(MBeanServerConnection connection) throws IOException, MojoExecutionException {\n\t\ttry {\n\t\t\tnew SpringApplicationAdminClient(connection, this.jmxName).stop();\n\t\t}\n\t\tcatch (InstanceNotFoundException ex) {\n\t\t\tthrow new MojoExecutionException(\n\t\t\t\t\t\"Spring application lifecycle JMX bean not found. Could not stop application gracefully\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/SystemPropertyFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Format System properties.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nfinal class SystemPropertyFormatter {\n\n\tprivate SystemPropertyFormatter() {\n\t}\n\n\tstatic String format(@Nullable String key, @Nullable String value) {\n\t\tif (key == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tif (value == null || value.isEmpty()) {\n\t\t\treturn String.format(\"-D%s\", key);\n\t\t}\n\t\treturn String.format(\"-D%s=%s\", key, value);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/TestRunMojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.plugin.MojoFailureException;\nimport org.apache.maven.plugins.annotations.Execute;\nimport org.apache.maven.plugins.annotations.LifecyclePhase;\nimport org.apache.maven.plugins.annotations.Mojo;\nimport org.apache.maven.plugins.annotations.Parameter;\nimport org.apache.maven.plugins.annotations.ResolutionScope;\nimport org.apache.maven.toolchain.ToolchainManager;\n\nimport org.springframework.boot.loader.tools.RunProcess;\n\n/**\n * Run an application in place using the test runtime classpath. The main class that will\n * be used to launch the application is determined as follows: The configured main class,\n * if any. Then the main class found in the test classes directory, if any. Then the main\n * class found in the classes directory, if any.\n *\n * @author Phillip Webb\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 3.1.0\n */\n@Mojo(name = \"test-run\", requiresProject = true, defaultPhase = LifecyclePhase.VALIDATE,\n\t\trequiresDependencyResolution = ResolutionScope.TEST)\n@Execute(phase = LifecyclePhase.TEST_COMPILE)\npublic class TestRunMojo extends AbstractRunMojo {\n\n\t/**\n\t * Whether the JVM's launch should be optimized.\n\t */\n\t@Parameter(property = \"spring-boot.test-run.optimizedLaunch\", defaultValue = \"true\")\n\tprivate boolean optimizedLaunch;\n\n\t/**\n\t * Directory containing the test classes and resource files that should be used to run\n\t * the application.\n\t */\n\t@Parameter(defaultValue = \"${project.build.testOutputDirectory}\", required = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File testClassesDirectory;\n\n\t@Inject\n\tpublic TestRunMojo(ToolchainManager toolchainManager) {\n\t\tsuper(toolchainManager);\n\t}\n\n\t@Override\n\tprotected List<File> getClassesDirectories() {\n\t\tArrayList<File> classesDirectories = new ArrayList<>(super.getClassesDirectories());\n\t\tclassesDirectories.add(0, this.testClassesDirectory);\n\t\treturn classesDirectories;\n\t}\n\n\t@Override\n\tprotected boolean isUseTestClasspath() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tprotected RunArguments resolveJvmArguments() {\n\t\tRunArguments jvmArguments = super.resolveJvmArguments();\n\t\tif (this.optimizedLaunch) {\n\t\t\tjvmArguments.getArgs().addFirst(\"-XX:TieredStopAtLevel=1\");\n\t\t}\n\t\treturn jvmArguments;\n\t}\n\n\t@Override\n\tprotected void run(JavaProcessExecutor processExecutor, File workingDirectory, List<String> args,\n\t\t\tMap<String, String> environmentVariables) throws MojoExecutionException, MojoFailureException {\n\t\tprocessExecutor\n\t\t\t.withRunProcessCustomizer(\n\t\t\t\t\t(runProcess) -> Runtime.getRuntime().addShutdownHook(new Thread(new RunProcessKiller(runProcess))))\n\t\t\t.run(workingDirectory, args, environmentVariables);\n\t}\n\n\tprivate static final class RunProcessKiller implements Runnable {\n\n\t\tprivate final RunProcess runProcess;\n\n\t\tprivate RunProcessKiller(RunProcess runProcess) {\n\t\t\tthis.runProcess = runProcess;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tthis.runProcess.kill();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/VersionExtractor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Extracts version information for a Class.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nfinal class VersionExtractor {\n\n\tprivate VersionExtractor() {\n\t}\n\n\t/**\n\t * Return the version information for the provided {@link Class}.\n\t * @param cls the Class to retrieve the version for\n\t * @return the version, or {@code null} if a version can not be extracted\n\t */\n\tstatic @Nullable String forClass(Class<?> cls) {\n\t\tString implementationVersion = cls.getPackage().getImplementationVersion();\n\t\tif (implementationVersion != null) {\n\t\t\treturn implementationVersion;\n\t\t}\n\t\tURL codeSourceLocation = cls.getProtectionDomain().getCodeSource().getLocation();\n\t\ttry {\n\t\t\tURLConnection connection = codeSourceLocation.openConnection();\n\t\t\tif (connection instanceof JarURLConnection jarURLConnection) {\n\t\t\t\treturn getImplementationVersion(jarURLConnection.getJarFile());\n\t\t\t}\n\t\t\ttry (JarFile jarFile = new JarFile(new File(codeSourceLocation.toURI()))) {\n\t\t\t\treturn getImplementationVersion(jarFile);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static String getImplementationVersion(JarFile jarFile) throws IOException {\n\t\treturn jarFile.getManifest().getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Maven plugin for Spring Boot.\n */\n@NullMarked\npackage org.springframework.boot.maven;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml",
    "content": "<lifecycleMappingMetadata>\n\t<pluginExecutions>\n\t\t<pluginExecution>\n\t\t\t<pluginExecutionFilter>\n\t\t\t\t<goals>\n\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t</goals>\n\t\t\t</pluginExecutionFilter>\n\t\t\t<action>\n\t\t\t\t<execute>\n\t\t\t\t\t<runOnIncremental>true</runOnIncremental>\n\t\t\t\t\t<runOnConfiguration>false</runOnConfiguration>\n\t\t\t\t</execute>\n\t\t\t</action>\n\t\t</pluginExecution>\n\t</pluginExecutions>\n</lifecycleMappingMetadata>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/resources/META-INF/spring/layers/default.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t                      https://www.springframework.org/schema/boot/layers/layers-4.1.xsd\">\n\t<application>\n\t\t<into layer=\"spring-boot-loader\">\n\t\t\t<include>org/springframework/boot/loader/**</include>\n\t\t</into>\n\t\t<into layer=\"application\"/>\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"application\">\n\t\t\t<includeModuleDependencies/>\n\t\t</into>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*SNAPSHOT</include>\n\t\t</into>\n\t\t<into layer=\"dependencies\"/>\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>dependencies</layer>\n\t\t<layer>spring-boot-loader</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-2.3.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-2.4.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-2.5.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-2.6.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-2.7.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-3.0.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-3.1.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-3.2.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-3.3.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-3.4.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-3.5.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-4.0.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/main/xsd/layers-4.1.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<xsd:schema elementFormDefault=\"qualified\"\n\txmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\ttargetNamespace=\"http://www.springframework.org/schema/boot/layers\">\n\t<xsd:element name=\"layers\" type=\"layersType\" />\n\t<xsd:complexType name=\"layersType\">\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"application\" type=\"applicationType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"dependencies\" type=\"dependenciesType\" minOccurs=\"0\"/>\n\t\t\t<xsd:element name=\"layerOrder\" type=\"layerOrderType\" minOccurs=\"0\"/>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"applicationType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to application classes and resources.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"intoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe 'into layer' selections that should be applied to dependencies.\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence maxOccurs=\"unbounded\">\n\t\t\t<xsd:element name=\"into\" type=\"dependenciesIntoType\" />\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"layerOrderType\">\n\t\t<xsd:annotation>\n\t\t\t<xsd:documentation><![CDATA[\n\tThe order that layers should be added (starting with the least frequently changed layer).\n\t\t\t\t]]></xsd:documentation>\n\t\t</xsd:annotation>\n\t\t<xsd:sequence>\n\t\t\t<xsd:element name=\"layer\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tThe layer name.\n\t\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t\t<xsd:simpleType>\n\t\t\t\t\t<xsd:restriction base=\"xsd:string\">\n\t\t\t\t\t\t<xsd:minLength value=\"1\" />\n\t\t\t\t\t</xsd:restriction>\n\t\t\t\t</xsd:simpleType>\n\t\t\t</xsd:element>\n\t\t</xsd:sequence>\n\t</xsd:complexType>\n\t<xsd:complexType name=\"intoType\">\n\t\t<xsd:choice maxOccurs=\"unbounded\">\n\t\t\t<xsd:element type=\"xsd:string\" name=\"include\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to include.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t\t<xsd:element type=\"xsd:string\" name=\"exclude\"\n\t\t\t\tminOccurs=\"0\" maxOccurs=\"unbounded\">\n\t\t\t\t<xsd:annotation>\n\t\t\t\t\t<xsd:documentation><![CDATA[\n\tPattern of the elements to exclude.\n\t\t\t]]></xsd:documentation>\n\t\t\t\t</xsd:annotation>\n\t\t\t</xsd:element>\n\t\t</xsd:choice>\n\t\t<xsd:attribute type=\"xsd:string\" name=\"layer\"\n\t\t\tuse=\"required\" />\n\t</xsd:complexType>\n\t<xsd:complexType name=\"dependenciesIntoType\">\n\t\t<xsd:complexContent>\n\t\t\t<xsd:extension base=\"intoType\">\n\t\t\t\t<xsd:choice minOccurs=\"0\">\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"includeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tInclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t\t<xsd:element type=\"xsd:string\" name=\"excludeModuleDependencies\" minOccurs=\"0\">\n\t\t\t\t\t\t<xsd:annotation>\n\t\t\t\t\t\t\t<xsd:documentation><![CDATA[\n\tExclude dependencies on other modules in the build.\n\t\t\t\t\t\t\t]]></xsd:documentation>\n\t\t\t\t\t\t</xsd:annotation>\n\t\t\t\t\t</xsd:element>\n\t\t\t\t</xsd:choice>\n\t\t\t</xsd:extension>\n\t\t</xsd:complexContent>\n\t</xsd:complexType>\n\n</xsd:schema>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/maven/resources/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t<version>{{version}}</version>\n\t<packaging>maven-plugin</packaging>\n\t<name>Spring Boot Maven Plugin</name>\n\t<url>https://projects.spring.io/spring-boot/#</url>\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache License, Version 2.0</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0</url>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<url>https://github.com/spring-projects/spring-boot</url>\n\t\t<connection>scm:git:git://github.com/spring-projects/spring-boot.git</connection>\n\t\t<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-boot.git</developerConnection>\n\t</scm>\n\t<issueManagement>\n\t\t<system>GitHub</system>\n\t\t<url>https://github.com/spring-projects/spring-boot/issues</url>\n\t</issueManagement>\n\t<organization>\n\t\t<name>Spring</name>\n\t\t<url>https://spring.io</url>\n\t</organization>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-plugin-plugin</artifactId>\n\t\t\t\t<version>3.6.0</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<helpPackageName>org.springframework.boot.maven</helpPackageName>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ArtifactsLibrariesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.handler.ArtifactHandler;\nimport org.apache.maven.model.Dependency;\nimport org.apache.maven.plugin.logging.Log;\nimport org.apache.maven.project.MavenProject;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCallback;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.boot.loader.tools.LibraryScope;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link ArtifactsLibraries}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass ArtifactsLibrariesTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Artifact artifact;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ArtifactHandler artifactHandler;\n\n\tprivate Set<Artifact> artifacts;\n\n\tprivate final File file = new File(\".\");\n\n\tprivate ArtifactsLibraries libs;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate LibraryCallback callback;\n\n\t@Captor\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ArgumentCaptor<Library> libraryCaptor;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.artifacts = Collections.singleton(this.artifact);\n\t\tthis.libs = new ArtifactsLibraries(this.artifacts, Collections.emptyList(), null, mock(Log.class));\n\t\tgiven(this.artifactHandler.getExtension()).willReturn(\"jar\");\n\t}\n\n\t@Test\n\tvoid callbackForJars() throws Exception {\n\t\tgiven(this.artifact.getFile()).willReturn(this.file);\n\t\tgiven(this.artifact.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tgiven(this.artifact.getScope()).willReturn(\"compile\");\n\t\tthis.libs.doWithLibraries(this.callback);\n\t\tthen(this.callback).should().library(assertArg((library) -> {\n\t\t\tassertThat(library.getFile()).isEqualTo(this.file);\n\t\t\tassertThat(library.getScope()).isEqualTo(LibraryScope.COMPILE);\n\t\t\tassertThat(library.isUnpackRequired()).isFalse();\n\t\t}));\n\t}\n\n\t@Test\n\tvoid callbackWithUnpack() throws Exception {\n\t\tgiven(this.artifact.getFile()).willReturn(this.file);\n\t\tgiven(this.artifact.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tgiven(this.artifact.getGroupId()).willReturn(\"gid\");\n\t\tgiven(this.artifact.getArtifactId()).willReturn(\"aid\");\n\t\tgiven(this.artifact.getScope()).willReturn(\"compile\");\n\t\tDependency unpack = new Dependency();\n\t\tunpack.setGroupId(\"gid\");\n\t\tunpack.setArtifactId(\"aid\");\n\t\tthis.libs = new ArtifactsLibraries(this.artifacts, Collections.emptyList(), Collections.singleton(unpack),\n\t\t\t\tmock(Log.class));\n\t\tthis.libs.doWithLibraries(this.callback);\n\t\tthen(this.callback).should().library(assertArg((library) -> assertThat(library.isUnpackRequired()).isTrue()));\n\t}\n\n\t@Test\n\tvoid renamesDuplicates() throws Exception {\n\t\tArtifact artifact1 = mock(Artifact.class);\n\t\tArtifact artifact2 = mock(Artifact.class);\n\t\tgiven(artifact1.getScope()).willReturn(\"compile\");\n\t\tgiven(artifact1.getGroupId()).willReturn(\"g1\");\n\t\tgiven(artifact1.getArtifactId()).willReturn(\"artifact\");\n\t\tgiven(artifact1.getBaseVersion()).willReturn(\"1.0\");\n\t\tgiven(artifact1.getFile()).willReturn(new File(\"a\"));\n\t\tgiven(artifact1.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tgiven(artifact2.getScope()).willReturn(\"compile\");\n\t\tgiven(artifact2.getGroupId()).willReturn(\"g2\");\n\t\tgiven(artifact2.getArtifactId()).willReturn(\"artifact\");\n\t\tgiven(artifact2.getBaseVersion()).willReturn(\"1.0\");\n\t\tgiven(artifact2.getFile()).willReturn(new File(\"a\"));\n\t\tgiven(artifact2.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tthis.artifacts = new LinkedHashSet<>(Arrays.asList(artifact1, artifact2));\n\t\tthis.libs = new ArtifactsLibraries(this.artifacts, Collections.emptyList(), null, mock(Log.class));\n\t\tthis.libs.doWithLibraries(this.callback);\n\t\tthen(this.callback).should(times(2)).library(this.libraryCaptor.capture());\n\t\tassertThat(this.libraryCaptor.getAllValues().get(0).getName()).isEqualTo(\"g1-artifact-1.0.jar\");\n\t\tassertThat(this.libraryCaptor.getAllValues().get(1).getName()).isEqualTo(\"g2-artifact-1.0.jar\");\n\t}\n\n\t@Test\n\tvoid libraryCoordinatesVersionUsesBaseVersionOfArtifact() throws IOException {\n\t\tArtifact snapshotArtifact = mock(Artifact.class);\n\t\tgiven(snapshotArtifact.getScope()).willReturn(\"compile\");\n\t\tgiven(snapshotArtifact.getArtifactId()).willReturn(\"artifact\");\n\t\tgiven(snapshotArtifact.getBaseVersion()).willReturn(\"1.0-SNAPSHOT\");\n\t\tgiven(snapshotArtifact.getFile()).willReturn(new File(\"a\"));\n\t\tgiven(snapshotArtifact.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tthis.artifacts = Collections.singleton(snapshotArtifact);\n\t\tnew ArtifactsLibraries(this.artifacts, Collections.emptyList(), null, mock(Log.class))\n\t\t\t.doWithLibraries((library) -> {\n\t\t\t\tassertThat(library.isIncluded()).isTrue();\n\t\t\t\tassertThat(library.isLocal()).isFalse();\n\t\t\t\tLibraryCoordinates coordinates = library.getCoordinates();\n\t\t\t\tassertThat(coordinates).isNotNull();\n\t\t\t\tassertThat(coordinates.getVersion()).isEqualTo(\"1.0-SNAPSHOT\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid artifactForLocalProjectProducesLocalLibrary() throws IOException {\n\t\tArtifact artifact = mock(Artifact.class);\n\t\tgiven(artifact.getScope()).willReturn(\"compile\");\n\t\tgiven(artifact.getArtifactId()).willReturn(\"artifact\");\n\t\tgiven(artifact.getBaseVersion()).willReturn(\"1.0-SNAPSHOT\");\n\t\tgiven(artifact.getFile()).willReturn(new File(\"a\"));\n\t\tgiven(artifact.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tMavenProject mavenProject = mock(MavenProject.class);\n\t\tgiven(mavenProject.getArtifact()).willReturn(artifact);\n\t\tthis.artifacts = Collections.singleton(artifact);\n\t\tnew ArtifactsLibraries(this.artifacts, Collections.singleton(mavenProject), null, mock(Log.class))\n\t\t\t.doWithLibraries((library) -> assertThat(library.isLocal()).isTrue());\n\t}\n\n\t@Test\n\tvoid attachedArtifactForLocalProjectProducesLocalLibrary() throws IOException {\n\t\tMavenProject mavenProject = mock(MavenProject.class);\n\t\tArtifact artifact = mock(Artifact.class);\n\t\tgiven(mavenProject.getArtifact()).willReturn(artifact);\n\t\tArtifact attachedArtifact = mock(Artifact.class);\n\t\tgiven(attachedArtifact.getScope()).willReturn(\"compile\");\n\t\tgiven(attachedArtifact.getArtifactId()).willReturn(\"attached-artifact\");\n\t\tgiven(attachedArtifact.getBaseVersion()).willReturn(\"1.0-SNAPSHOT\");\n\t\tgiven(attachedArtifact.getFile()).willReturn(new File(\"a\"));\n\t\tgiven(attachedArtifact.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tgiven(mavenProject.getAttachedArtifacts()).willReturn(Collections.singletonList(attachedArtifact));\n\t\tthis.artifacts = Collections.singleton(attachedArtifact);\n\t\tnew ArtifactsLibraries(this.artifacts, Collections.singleton(mavenProject), null, mock(Log.class))\n\t\t\t.doWithLibraries((library) -> assertThat(library.isLocal()).isTrue());\n\t}\n\n\t@Test\n\tvoid nonIncludedArtifact() throws IOException {\n\t\tArtifact artifact = mock(Artifact.class);\n\t\tgiven(artifact.getScope()).willReturn(\"compile\");\n\t\tgiven(artifact.getArtifactId()).willReturn(\"artifact\");\n\t\tgiven(artifact.getBaseVersion()).willReturn(\"1.0-SNAPSHOT\");\n\t\tgiven(artifact.getFile()).willReturn(new File(\"a\"));\n\t\tgiven(artifact.getArtifactHandler()).willReturn(this.artifactHandler);\n\t\tMavenProject mavenProject = mock(MavenProject.class);\n\t\tgiven(mavenProject.getArtifact()).willReturn(artifact);\n\t\tthis.artifacts = Collections.singleton(artifact);\n\t\tnew ArtifactsLibraries(this.artifacts, Collections.emptySet(), Collections.singleton(mavenProject), null,\n\t\t\t\tmock(Log.class))\n\t\t\t.doWithLibraries((library) -> assertThat(library.isIncluded()).isFalse());\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ClassPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link ClassPath}.\n *\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ClassPathTests {\n\n\t@Test\n\tvoid argsWhenNoClassPathReturnsEmptyList() {\n\t\tassertThat(ClassPath.of(Collections.emptyList()).args(false)).isEmpty();\n\t}\n\n\t@Test\n\tvoid argsWhenSingleUrlOnWindowsUsesPath(@TempDir Path temp) throws Exception {\n\t\tPath path = temp.resolve(\"test.jar\");\n\t\tClassPath classPath = ClassPath.of(onWindows(), List.of(path.toUri().toURL()));\n\t\tassertThat(classPath.args(true)).containsExactly(\"-cp\", path.toString());\n\t}\n\n\t@Test\n\tvoid argsWhenSingleUrlNotOnWindowsUsesPath(@TempDir Path temp) throws Exception {\n\t\tPath path = temp.resolve(\"test.jar\");\n\t\tClassPath classPath = ClassPath.of(onLinux(), List.of(path.toUri().toURL()));\n\t\tassertThat(classPath.args(true)).containsExactly(\"-cp\", path.toString());\n\t}\n\n\t@Test\n\tvoid argsWhenMultipleUrlsOnWindowsAndAllowedUsesArgFile(@TempDir Path temp) throws Exception {\n\t\tPath path1 = temp.resolve(\"test1.jar\");\n\t\tPath path2 = temp.resolve(\"test2.jar\");\n\t\tClassPath classPath = ClassPath.of(onWindows(), List.of(path1.toUri().toURL(), path2.toUri().toURL()));\n\t\tList<String> args = classPath.args(true);\n\t\tassertThat(args.get(0)).isEqualTo(\"-cp\");\n\t\tassertThat(args.get(1)).startsWith(\"@\");\n\t\tassertThat(Paths.get(args.get(1).substring(1)))\n\t\t\t.hasContent(\"\\\"\" + (path1 + File.pathSeparator + path2).replace(\"\\\\\", \"\\\\\\\\\") + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid argsWhenMultipleUrlsOnWindowsAndNotAllowedUsesPath(@TempDir Path temp) throws Exception {\n\t\tPath path1 = temp.resolve(\"test1.jar\");\n\t\tPath path2 = temp.resolve(\"test2.jar\");\n\t\tClassPath classPath = ClassPath.of(onWindows(), List.of(path1.toUri().toURL(), path2.toUri().toURL()));\n\t\tassertThat(classPath.args(false)).containsExactly(\"-cp\", path1 + File.pathSeparator + path2);\n\t}\n\n\t@Test\n\tvoid argsWhenMultipleUrlsNotOnWindowsUsesPath(@TempDir Path temp) throws Exception {\n\t\tPath path1 = temp.resolve(\"test1.jar\");\n\t\tPath path2 = temp.resolve(\"test2.jar\");\n\t\tClassPath classPath = ClassPath.of(onLinux(), List.of(path1.toUri().toURL(), path2.toUri().toURL()));\n\t\tassertThat(classPath.args(true)).containsExactly(\"-cp\", path1 + File.pathSeparator + path2);\n\t}\n\n\t@Test\n\tvoid toStringShouldReturnClassPath(@TempDir Path temp) throws Exception {\n\t\tPath path1 = temp.resolve(\"test1.jar\");\n\t\tPath path2 = temp.resolve(\"test2.jar\");\n\t\tClassPath classPath = ClassPath.of(onLinux(), List.of(path1.toUri().toURL(), path2.toUri().toURL()));\n\t\tassertThat(classPath.toString()).isEqualTo(path1 + File.pathSeparator + path2);\n\t}\n\n\tprivate UnaryOperator<@Nullable String> onWindows() {\n\t\treturn Map.of(\"os.name\", \"windows\")::get;\n\t}\n\n\tprivate UnaryOperator<@Nullable String> onLinux() {\n\t\treturn Map.of(\"os.name\", \"linux\")::get;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/CommandLineBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.management.ManagementFactory;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.tools.JavaExecutable;\nimport org.springframework.boot.maven.sample.ClassWithMainMethod;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CommandLineBuilder}.\n *\n * @author Stephane Nicoll\n */\nclass CommandLineBuilderTests {\n\n\tpublic static final String CLASS_NAME = ClassWithMainMethod.class.getName();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Maven can't deal with @Nullable arrays / varargs\n\tvoid buildWithNullJvmArgumentsIsIgnored() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withJvmArguments((String[]) null).build())\n\t\t\t.containsExactly(CLASS_NAME);\n\t}\n\n\t@Test\n\tvoid buildWithNullIntermediateJvmArgumentIsIgnored() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME)\n\t\t\t.withJvmArguments(\"-verbose:class\", null, \"-verbose:gc\")\n\t\t\t.build()).containsExactly(\"-verbose:class\", \"-verbose:gc\", CLASS_NAME);\n\t}\n\n\t@Test\n\tvoid buildWithJvmArgument() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withJvmArguments(\"-verbose:class\").build())\n\t\t\t.containsExactly(\"-verbose:class\", CLASS_NAME);\n\t}\n\n\t@Test\n\tvoid buildWithNullSystemPropertyIsIgnored() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withSystemProperties(null).build())\n\t\t\t.containsExactly(CLASS_NAME);\n\t}\n\n\t@Test\n\tvoid buildWithSystemProperty() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withSystemProperties(Map.of(\"flag\", \"enabled\")).build())\n\t\t\t.containsExactly(\"-Dflag=enabled\", CLASS_NAME);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Maven can't deal with @Nullable arrays / varargs\n\tvoid buildWithNullArgumentsIsIgnored() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withArguments((String[]) null).build())\n\t\t\t.containsExactly(CLASS_NAME);\n\t}\n\n\t@Test\n\tvoid buildWithNullIntermediateArgumentIsIgnored() {\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME).withArguments(\"--test\", null, \"--another\").build())\n\t\t\t.containsExactly(CLASS_NAME, \"--test\", \"--another\");\n\t}\n\n\t@Test\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid buildWithClassPath(@TempDir Path tempDir) throws Exception {\n\t\tPath file = tempDir.resolve(\"test.jar\");\n\t\tPath file1 = tempDir.resolve(\"test1.jar\");\n\t\tassertThat(CommandLineBuilder.forMainClass(CLASS_NAME)\n\t\t\t.withClasspath(file.toUri().toURL(), file1.toUri().toURL())\n\t\t\t.build()).containsExactly(\"-cp\", file + File.pathSeparator + file1, CLASS_NAME);\n\t}\n\n\t@Test\n\t@EnabledOnOs(OS.WINDOWS)\n\tvoid buildWithClassPathOnWindows(@TempDir Path tempDir) throws Exception {\n\t\tPath file = tempDir.resolve(\"test.jar\");\n\t\tPath file1 = tempDir.resolve(\"test1.jar\");\n\t\tList<String> args = CommandLineBuilder.forMainClass(CLASS_NAME)\n\t\t\t.withClasspath(file.toUri().toURL(), file1.toUri().toURL())\n\t\t\t.build();\n\t\tassertThat(args).hasSize(3);\n\t\tassertThat(args.get(0)).isEqualTo(\"-cp\");\n\t\tassertThat(args.get(1)).startsWith(\"@\");\n\t\tassertThat(args.get(2)).isEqualTo(CLASS_NAME);\n\t\tassertThat(Paths.get(args.get(1).substring(1)))\n\t\t\t.hasContent(\"\\\"\" + (file + File.pathSeparator + file1).replace(\"\\\\\", \"\\\\\\\\\") + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid buildAndRunWithLongClassPath() throws IOException, InterruptedException {\n\t\tStringBuilder classPath = new StringBuilder(ManagementFactory.getRuntimeMXBean().getClassPath());\n\t\t// Simulates [CreateProcess error=206, The filename or extension is too long]\n\t\twhile (classPath.length() < 35000) {\n\t\t\tclassPath.append(File.pathSeparator).append(classPath);\n\t\t}\n\t\tURL[] urls = Arrays.stream(classPath.toString().split(File.pathSeparator)).map(this::toURL).toArray(URL[]::new);\n\t\tList<String> command = CommandLineBuilder.forMainClass(ClassWithMainMethod.class.getName())\n\t\t\t.withClasspath(urls)\n\t\t\t.build();\n\t\tProcessBuilder pb = new JavaExecutable().processBuilder(command.toArray(new String[0]));\n\t\tProcess process = pb.start();\n\t\tassertThat(process.waitFor()).isEqualTo(0);\n\t\ttry (InputStream inputStream = process.getInputStream()) {\n\t\t\tassertThat(inputStream).hasContent(\"Hello World\");\n\t\t}\n\t}\n\n\tprivate URL toURL(String path) {\n\t\ttry {\n\t\t\treturn Paths.get(path).toUri().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/CustomLayersProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.w3c.dom.Document;\nimport org.xml.sax.InputSource;\n\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.boot.loader.tools.layer.CustomLayers;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CustomLayersProvider}.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass CustomLayersProviderTests {\n\n\tprivate CustomLayersProvider customLayersProvider;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.customLayersProvider = new CustomLayersProvider();\n\t}\n\n\t@Test\n\tvoid getLayerResolverWhenDocumentValid() throws Exception {\n\t\tCustomLayers layers = this.customLayersProvider.getLayers(getDocument(\"layers.xml\"));\n\t\tassertThat(layers).extracting(\"name\")\n\t\t\t.containsExactly(\"my-deps\", \"my-dependencies-name\", \"snapshot-dependencies\", \"my-resources\",\n\t\t\t\t\t\"configuration\", \"application\");\n\t\tLibrary snapshot = mockLibrary(\"test-SNAPSHOT.jar\", \"org.foo\", \"1.0.0-SNAPSHOT\");\n\t\tLibrary groupId = mockLibrary(\"my-library\", \"com.acme\", null);\n\t\tLibrary otherDependency = mockLibrary(\"other-library\", \"org.foo\", null);\n\t\tLibrary localSnapshotDependency = mockLibrary(\"local-library\", \"org.foo\", \"1.0-SNAPSHOT\");\n\t\tgiven(localSnapshotDependency.isLocal()).willReturn(true);\n\t\tassertThat(layers.getLayer(snapshot)).hasToString(\"snapshot-dependencies\");\n\t\tassertThat(layers.getLayer(groupId)).hasToString(\"my-deps\");\n\t\tassertThat(layers.getLayer(otherDependency)).hasToString(\"my-dependencies-name\");\n\t\tassertThat(layers.getLayer(localSnapshotDependency)).hasToString(\"application\");\n\t\tassertThat(layers.getLayer(\"META-INF/resources/test.css\")).hasToString(\"my-resources\");\n\t\tassertThat(layers.getLayer(\"application.yml\")).hasToString(\"configuration\");\n\t\tassertThat(layers.getLayer(\"test\")).hasToString(\"application\");\n\t}\n\n\tprivate Library mockLibrary(String name, String groupId, @Nullable String version) {\n\t\tLibrary library = mock(Library.class);\n\t\tgiven(library.getName()).willReturn(name);\n\t\tgiven(library.getCoordinates()).willReturn(LibraryCoordinates.of(groupId, null, version));\n\t\treturn library;\n\t}\n\n\t@Test\n\tvoid getLayerResolverWhenDocumentContainsLibraryLayerWithNoFilters() throws Exception {\n\t\tCustomLayers layers = this.customLayersProvider.getLayers(getDocument(\"dependencies-layer-no-filter.xml\"));\n\t\tLibrary library = mockLibrary(\"my-library\", \"com.acme\", null);\n\t\tassertThat(layers.getLayer(library)).hasToString(\"my-deps\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> layers.getLayer(\"application.yml\"))\n\t\t\t.withMessageContaining(\"match any layer\");\n\t}\n\n\t@Test\n\tvoid getLayerResolverWhenDocumentContainsResourceLayerWithNoFilters() throws Exception {\n\t\tCustomLayers layers = this.customLayersProvider.getLayers(getDocument(\"application-layer-no-filter.xml\"));\n\t\tLibrary library = mockLibrary(\"my-library\", \"com.acme\", null);\n\t\tassertThat(layers.getLayer(\"application.yml\")).hasToString(\"my-layer\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> layers.getLayer(library))\n\t\t\t.withMessageContaining(\"match any layer\");\n\t}\n\n\tprivate Document getDocument(String resourceName) throws Exception {\n\t\tClassPathResource resource = new ClassPathResource(resourceName);\n\t\tInputSource inputSource = new InputSource(resource.getInputStream());\n\t\tDocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n\t\tfactory.setNamespaceAware(true);\n\t\tDocumentBuilder documentBuilder = factory.newDocumentBuilder();\n\t\treturn documentBuilder.parse(inputSource);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterMojoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.plugin.MojoExecutionException;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;\nimport org.apache.maven.shared.artifact.filter.collection.ScopeFilter;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AbstractDependencyFilterMojo}.\n *\n * @author Stephane Nicoll\n */\nclass DependencyFilterMojoTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tstatic Path temp;\n\n\t@Test\n\tvoid filterDependencies() throws MojoExecutionException {\n\t\tTestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), \"com.foo\");\n\n\t\tArtifact artifact = createArtifact(\"com.bar\", \"one\");\n\t\tSet<Artifact> artifacts = mojo.filterDependencies(createArtifact(\"com.foo\", \"one\"),\n\t\t\t\tcreateArtifact(\"com.foo\", \"two\"), artifact);\n\t\tassertThat(artifacts).hasSize(1);\n\t\tassertThat(artifacts.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid filterGroupIdExactMatch() throws MojoExecutionException {\n\t\tTestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), \"com.foo\");\n\n\t\tArtifact artifact = createArtifact(\"com.foo.bar\", \"one\");\n\t\tSet<Artifact> artifacts = mojo.filterDependencies(createArtifact(\"com.foo\", \"one\"),\n\t\t\t\tcreateArtifact(\"com.foo\", \"two\"), artifact);\n\t\tassertThat(artifacts).hasSize(1);\n\t\tassertThat(artifacts.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid filterScopeKeepOrder() throws MojoExecutionException {\n\t\tTestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), \"\",\n\t\t\t\tnew ScopeFilter(null, Artifact.SCOPE_SYSTEM));\n\t\tArtifact one = createArtifact(\"com.foo\", \"one\");\n\t\tArtifact two = createArtifact(\"com.foo\", \"two\", Artifact.SCOPE_SYSTEM);\n\t\tArtifact three = createArtifact(\"com.foo\", \"three\", Artifact.SCOPE_RUNTIME);\n\t\tSet<Artifact> artifacts = mojo.filterDependencies(one, two, three);\n\t\tassertThat(artifacts).containsExactly(one, three);\n\t}\n\n\t@Test\n\tvoid filterGroupIdKeepOrder() throws MojoExecutionException {\n\t\tTestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), \"com.foo\");\n\t\tArtifact one = createArtifact(\"com.foo\", \"one\");\n\t\tArtifact two = createArtifact(\"com.bar\", \"two\");\n\t\tArtifact three = createArtifact(\"com.bar\", \"three\");\n\t\tArtifact four = createArtifact(\"com.foo\", \"four\");\n\t\tSet<Artifact> artifacts = mojo.filterDependencies(one, two, three, four);\n\t\tassertThat(artifacts).containsExactly(two, three);\n\t}\n\n\t@Test\n\tvoid filterExcludeKeepOrder() throws MojoExecutionException {\n\t\tExclude exclude = new Exclude();\n\t\texclude.setGroupId(\"com.bar\");\n\t\texclude.setArtifactId(\"two\");\n\t\tTestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.singletonList(exclude), \"\");\n\t\tArtifact one = createArtifact(\"com.foo\", \"one\");\n\t\tArtifact two = createArtifact(\"com.bar\", \"two\");\n\t\tArtifact three = createArtifact(\"com.bar\", \"three\");\n\t\tArtifact four = createArtifact(\"com.foo\", \"four\");\n\t\tSet<Artifact> artifacts = mojo.filterDependencies(one, two, three, four);\n\t\tassertThat(artifacts).containsExactly(one, three, four);\n\t}\n\n\t@Test\n\tvoid excludeByJarType() throws MojoExecutionException {\n\t\tTestableDependencyFilterMojo mojo = new TestableDependencyFilterMojo(Collections.emptyList(), \"\");\n\t\tArtifact one = createArtifact(\"com.foo\", \"one\", null, \"dependencies-starter\");\n\t\tArtifact two = createArtifact(\"com.bar\", \"two\");\n\t\tSet<Artifact> artifacts = mojo.filterDependencies(one, two);\n\t\tassertThat(artifacts).containsExactly(two);\n\t}\n\n\tprivate static Artifact createArtifact(String groupId, String artifactId) {\n\t\treturn createArtifact(groupId, artifactId, null);\n\t}\n\n\tprivate static Artifact createArtifact(String groupId, String artifactId, @Nullable String scope) {\n\t\treturn createArtifact(groupId, artifactId, scope, null);\n\t}\n\n\tprivate static Artifact createArtifact(String groupId, String artifactId, @Nullable String scope,\n\t\t\t@Nullable String jarType) {\n\t\tArtifact a = mock(Artifact.class);\n\t\tgiven(a.getGroupId()).willReturn(groupId);\n\t\tgiven(a.getArtifactId()).willReturn(artifactId);\n\t\tif (scope != null) {\n\t\t\tgiven(a.getScope()).willReturn(scope);\n\t\t}\n\t\tgiven(a.getFile()).willReturn(createArtifactFile(jarType));\n\t\treturn a;\n\t}\n\n\tprivate static File createArtifactFile(@Nullable String jarType) {\n\t\tPath jarPath = temp.resolve(UUID.randomUUID() + \".jar\");\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(\"Manifest-Version\", \"1.0\");\n\t\tif (jarType != null) {\n\t\t\tmanifest.getMainAttributes().putValue(\"Spring-Boot-Jar-Type\", jarType);\n\t\t}\n\t\ttry {\n\t\t\tnew JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest).close();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn jarPath.toFile();\n\t}\n\n\tprivate static final class TestableDependencyFilterMojo extends AbstractDependencyFilterMojo {\n\n\t\tprivate final ArtifactsFilter[] additionalFilters;\n\n\t\tprivate TestableDependencyFilterMojo(List<Exclude> excludes, String excludeGroupIds,\n\t\t\t\tArtifactsFilter... additionalFilters) {\n\t\t\tsetExcludes(excludes);\n\t\t\tsetExcludeGroupIds(excludeGroupIds);\n\t\t\tthis.additionalFilters = additionalFilters;\n\t\t}\n\n\t\tSet<Artifact> filterDependencies(Artifact... artifacts) throws MojoExecutionException {\n\t\t\tSet<Artifact> input = new LinkedHashSet<>(Arrays.asList(artifacts));\n\t\t\treturn filterDependencies(input, this.additionalFilters);\n\t\t}\n\n\t\t@Override\n\t\tpublic void execute() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DependencyFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Set;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.DefaultArtifact;\nimport org.apache.maven.artifact.handler.ArtifactHandler;\nimport org.apache.maven.artifact.handler.DefaultArtifactHandler;\nimport org.apache.maven.artifact.versioning.VersionRange;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DependencyFilter}.\n *\n * @author Phillip Webb\n */\nclass DependencyFilterTests {\n\n\t@Test\n\tvoid excludeFiltersBasedOnPredicate() throws ArtifactFilterException {\n\t\tDependencyFilter filter = DependencyFilter.exclude(Artifact::isOptional);\n\t\tArtifactHandler ah = new DefaultArtifactHandler();\n\t\tVersionRange v = VersionRange.createFromVersion(\"1.0.0\");\n\t\tDefaultArtifact a1 = new DefaultArtifact(\"com.example\", \"a1\", v, \"compile\", \"jar\", null, ah, false);\n\t\tDefaultArtifact a2 = new DefaultArtifact(\"com.example\", \"a2\", v, \"compile\", \"jar\", null, ah, true);\n\t\tDefaultArtifact a3 = new DefaultArtifact(\"com.example\", \"a3\", v, \"compile\", \"jar\", null, ah, false);\n\t\tSet<Artifact> filtered = filter.filter(Set.of(a1, a2, a3));\n\t\tassertThat(filtered).containsExactlyInAnyOrder(a1, a3);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/DockerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Base64;\n\nimport org.apache.maven.plugin.logging.Log;\nimport org.apache.maven.plugin.logging.SystemStreamLog;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.build.BuilderDockerConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Docker}.\n *\n * @author Wei Jiang\n * @author Scott Frederick\n */\nclass DockerTests {\n\n\tprivate final Log log = new SystemStreamLog();\n\n\t@Test\n\tvoid asDockerConfigurationWithDefaults() {\n\t\tDocker docker = new Docker();\n\t\tBuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);\n\t\tassertThat(dockerConfiguration.connection()).isNull();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tString authHeader = publishRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithHostConfiguration() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setHost(\"docker.example.com\");\n\t\tdocker.setTlsVerify(true);\n\t\tdocker.setCertPath(\"/tmp/ca-cert\");\n\t\tBuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);\n\t\tDockerConnectionConfiguration.Host host = (DockerConnectionConfiguration.Host) dockerConfiguration.connection();\n\t\tassertThat(host).isNotNull();\n\t\tassertThat(host.address()).isEqualTo(\"docker.example.com\");\n\t\tassertThat(host.secure()).isTrue();\n\t\tassertThat(host.certificatePath()).isEqualTo(\"/tmp/ca-cert\");\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isFalse();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = createDockerConfiguration(docker)\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tString authHeader = publishRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithContextConfiguration() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setContext(\"test-context\");\n\t\tBuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);\n\t\tDockerConnectionConfiguration.Context context = (DockerConnectionConfiguration.Context) dockerConfiguration\n\t\t\t.connection();\n\t\tassertThat(context).isNotNull();\n\t\tassertThat(context.context()).isEqualTo(\"test-context\");\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isFalse();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = createDockerConfiguration(docker)\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tString authHeader = publishRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithHostAndContextFails() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setContext(\"test-context\");\n\t\tdocker.setHost(\"docker.example.com\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createDockerConfiguration(docker))\n\t\t\t.withMessageContaining(\"Invalid Docker configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithBindHostToBuilder() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setHost(\"docker.example.com\");\n\t\tdocker.setTlsVerify(true);\n\t\tdocker.setCertPath(\"/tmp/ca-cert\");\n\t\tdocker.setBindHostToBuilder(true);\n\t\tBuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);\n\t\tDockerConnectionConfiguration.Host host = (DockerConnectionConfiguration.Host) dockerConfiguration.connection();\n\t\tassertThat(host).isNotNull();\n\t\tassertThat(host.address()).isEqualTo(\"docker.example.com\");\n\t\tassertThat(host.secure()).isTrue();\n\t\tassertThat(host.certificatePath()).isEqualTo(\"/tmp/ca-cert\");\n\t\tassertThat(dockerConfiguration.bindHostToBuilder()).isTrue();\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = createDockerConfiguration(docker)\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tassertThat(builderRegistryAuthentication.getAuthHeader()).isNull();\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tString authHeader = publishRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"username\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithUserAuth() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setBuilderRegistry(\n\t\t\t\tnew Docker.DockerRegistry(\"user1\", \"secret1\", \"https://docker1.example.com\", \"docker1@example.com\"));\n\t\tdocker.setPublishRegistry(\n\t\t\t\tnew Docker.DockerRegistry(\"user2\", \"secret2\", \"https://docker2.example.com\", \"docker2@example.com\"));\n\t\tBuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tString authHeader = builderRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"username\\\" : \\\"user1\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"secret1\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"docker1@example.com\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"https://docker1.example.com\\\"\");\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tauthHeader = publishRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"username\\\" : \\\"user2\\\"\")\n\t\t\t.contains(\"\\\"password\\\" : \\\"secret2\\\"\")\n\t\t\t.contains(\"\\\"email\\\" : \\\"docker2@example.com\\\"\")\n\t\t\t.contains(\"\\\"serveraddress\\\" : \\\"https://docker2.example.com\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithIncompleteBuilderUserAuthFails() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setBuilderRegistry(\n\t\t\t\tnew Docker.DockerRegistry(\"user\", null, \"https://docker.example.com\", \"docker@example.com\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createDockerConfiguration(docker))\n\t\t\t.withMessageContaining(\"Invalid Docker builder registry configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithIncompletePublishUserAuthFails() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setPublishRegistry(\n\t\t\t\tnew Docker.DockerRegistry(\"user\", null, \"https://docker.example.com\", \"docker@example.com\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createDockerConfiguration(docker))\n\t\t\t.withMessageContaining(\"Invalid Docker publish registry configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithIncompletePublishUserAuthDoesNotFailIfPublishIsDisabled() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setPublishRegistry(\n\t\t\t\tnew Docker.DockerRegistry(\"user\", null, \"https://docker.example.com\", \"docker@example.com\"));\n\t\tBuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(this.log, false);\n\t\tassertThat(dockerConfiguration.publishRegistryAuthentication()).isNull();\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithTokenAuth() {\n\t\tDocker docker = new Docker();\n\t\tdocker.setBuilderRegistry(new Docker.DockerRegistry(\"token1\"));\n\t\tdocker.setPublishRegistry(new Docker.DockerRegistry(\"token2\"));\n\t\tBuilderDockerConfiguration dockerConfiguration = createDockerConfiguration(docker);\n\t\tDockerRegistryAuthentication builderRegistryAuthentication = dockerConfiguration\n\t\t\t.builderRegistryAuthentication();\n\t\tassertThat(builderRegistryAuthentication).isNotNull();\n\t\tString authHeader = builderRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"identitytoken\\\" : \\\"token1\\\"\");\n\t\tDockerRegistryAuthentication publishRegistryAuthentication = dockerConfiguration\n\t\t\t.publishRegistryAuthentication();\n\t\tassertThat(publishRegistryAuthentication).isNotNull();\n\t\tauthHeader = publishRegistryAuthentication.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decoded(authHeader)).contains(\"\\\"identitytoken\\\" : \\\"token2\\\"\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithUserAndTokenAuthFails() {\n\t\tDocker.DockerRegistry dockerRegistry = new Docker.DockerRegistry();\n\t\tdockerRegistry.setUsername(\"user\");\n\t\tdockerRegistry.setPassword(\"secret\");\n\t\tdockerRegistry.setToken(\"token\");\n\t\tDocker docker = new Docker();\n\t\tdocker.setBuilderRegistry(dockerRegistry);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createDockerConfiguration(docker))\n\t\t\t.withMessageContaining(\"Invalid Docker builder registry configuration\");\n\t}\n\n\t@Test\n\tvoid asDockerConfigurationWithUserAndTokenAuthDoesNotFailIfPublishingIsDisabled() {\n\t\tDocker.DockerRegistry dockerRegistry = new Docker.DockerRegistry();\n\t\tdockerRegistry.setUsername(\"user\");\n\t\tdockerRegistry.setPassword(\"secret\");\n\t\tdockerRegistry.setToken(\"token\");\n\t\tDocker docker = new Docker();\n\t\tdocker.setPublishRegistry(dockerRegistry);\n\t\tBuilderDockerConfiguration dockerConfiguration = docker.asDockerConfiguration(this.log, false);\n\t\tassertThat(dockerConfiguration.publishRegistryAuthentication()).isNull();\n\t}\n\n\tprivate BuilderDockerConfiguration createDockerConfiguration(Docker docker) {\n\t\treturn docker.asDockerConfiguration(this.log, true);\n\t}\n\n\tString decoded(String value) {\n\t\treturn new String(Base64.getDecoder().decode(value));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/EnvVariablesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link EnvVariables}.\n *\n * @author Dmytro Nosan\n */\nclass EnvVariablesTests {\n\n\t@Test\n\tvoid asNull() {\n\t\tMap<String, String> args = new EnvVariables(null).asMap();\n\t\tassertThat(args).isEmpty();\n\t}\n\n\t@Test\n\tvoid asArray() {\n\t\tassertThat(new EnvVariables(getTestArgs()).asArray()).contains(\"key=My Value\", \"key1= tt \", \"key2=   \",\n\t\t\t\t\"key3=\");\n\t}\n\n\t@Test\n\tvoid asMap() {\n\t\tassertThat(new EnvVariables(getTestArgs()).asMap()).containsExactly(entry(\"key\", \"My Value\"),\n\t\t\t\tentry(\"key1\", \" tt \"), entry(\"key2\", \"   \"), entry(\"key3\", \"\"));\n\t}\n\n\tprivate Map<String, String> getTestArgs() {\n\t\tMap<String, String> args = new LinkedHashMap<>();\n\t\targs.put(\"key\", \"My Value\");\n\t\targs.put(\"key1\", \" tt \");\n\t\targs.put(\"key2\", \"   \");\n\t\targs.put(\"key3\", null);\n\t\treturn args;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ExcludeFilter}.\n *\n * @author Stephane Nicoll\n * @author David Turanski\n */\n@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\nclass ExcludeFilterTests {\n\n\t@Test\n\tvoid excludeSimple() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\")));\n\t\tSet result = filter.filter(Collections.singleton(createArtifact(\"com.foo\", \"bar\")));\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid excludeGroupIdNoMatch() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\")));\n\t\tArtifact artifact = createArtifact(\"com.baz\", \"bar\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid excludeArtifactIdNoMatch() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"biz\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid excludeClassifier() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tSet result = filter.filter(Collections.singleton(createArtifact(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid excludeClassifierNoTargetClassifier() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"bar\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid excludeClassifierNoMatch() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"bar\", \"jdk6\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid excludeMulti() throws ArtifactFilterException {\n\t\tExcludeFilter filter = new ExcludeFilter(Arrays.asList(createExclude(\"com.foo\", \"bar\"),\n\t\t\t\tcreateExclude(\"com.foo\", \"bar2\"), createExclude(\"org.acme\", \"app\")));\n\t\tSet<Artifact> artifacts = new HashSet<>();\n\t\tartifacts.add(createArtifact(\"com.foo\", \"bar\"));\n\t\tartifacts.add(createArtifact(\"com.foo\", \"bar\"));\n\t\tArtifact anotherAcme = createArtifact(\"org.acme\", \"another-app\");\n\t\tartifacts.add(anotherAcme);\n\t\tSet result = filter.filter(artifacts);\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(anotherAcme);\n\t}\n\n\tprivate Exclude createExclude(String groupId, String artifactId) {\n\t\treturn createExclude(groupId, artifactId, null);\n\t}\n\n\tprivate Exclude createExclude(String groupId, String artifactId, @Nullable String classifier) {\n\t\tExclude exclude = new Exclude();\n\t\texclude.setGroupId(groupId);\n\t\texclude.setArtifactId(artifactId);\n\t\tif (classifier != null) {\n\t\t\texclude.setClassifier(classifier);\n\t\t}\n\t\treturn exclude;\n\t}\n\n\tprivate Artifact createArtifact(String groupId, String artifactId, @Nullable String classifier) {\n\t\tArtifact a = mock(Artifact.class);\n\t\tgiven(a.getGroupId()).willReturn(groupId);\n\t\tgiven(a.getArtifactId()).willReturn(artifactId);\n\t\tgiven(a.getClassifier()).willReturn(classifier);\n\t\treturn a;\n\t}\n\n\tprivate Artifact createArtifact(String groupId, String artifactId) {\n\t\treturn createArtifact(groupId, artifactId, null);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/ImageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.artifact.DefaultArtifact;\nimport org.apache.maven.artifact.handler.DefaultArtifactHandler;\nimport org.apache.maven.artifact.versioning.VersionRange;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.build.BuildRequest;\nimport org.springframework.boot.buildpack.platform.build.BuildpackReference;\nimport org.springframework.boot.buildpack.platform.build.Cache;\nimport org.springframework.boot.buildpack.platform.build.PullPolicy;\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.maven.CacheInfo.BindCacheInfo;\nimport org.springframework.boot.maven.CacheInfo.VolumeCacheInfo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Image}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n * @author Rafael Ceccone\n * @author Moritz Halbritter\n */\nclass ImageTests {\n\n\t@Test\n\tvoid getBuildRequestWhenNameIsNullDeducesName() {\n\t\tBuildRequest request = new Image().getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getName()).hasToString(\"docker.io/library/my-app:0.0.1-SNAPSHOT\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenNameIsSetUsesName() {\n\t\tImage image = new Image();\n\t\timage.name = \"demo\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getName()).hasToString(\"docker.io/library/demo:latest\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenNoCustomizationsUsesDefaults() {\n\t\tBuildRequest request = new Image().getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getName()).hasToString(\"docker.io/library/my-app:0.0.1-SNAPSHOT\");\n\t\tassertThat(request.getBuilder().toString()).contains(\"paketobuildpacks/builder-noble-java-tiny\");\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t\tassertThat(request.getRunImage()).isNull();\n\t\tassertThat(request.getEnv()).isEmpty();\n\t\tassertThat(request.isCleanCache()).isFalse();\n\t\tassertThat(request.isVerboseLogging()).isFalse();\n\t\tassertThat(request.getPullPolicy()).isEqualTo(PullPolicy.ALWAYS);\n\t\tassertThat(request.isPublish()).isFalse();\n\t\tassertThat(request.getBuildpacks()).isEmpty();\n\t\tassertThat(request.getBindings()).isEmpty();\n\t\tassertThat(request.getNetwork()).isNull();\n\t\tassertThat(request.getImagePlatform()).isNull();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuilderUsesBuilder() {\n\t\tImage image = new Image();\n\t\timage.builder = \"springboot/builder:2.2.x\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuilder()).hasToString(\"docker.io/springboot/builder:2.2.x\");\n\t\tassertThat(request.isTrustBuilder()).isFalse();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuilderAndTrustBuilderUsesBuilderAndTrustBuilder() {\n\t\tImage image = new Image();\n\t\timage.builder = \"springboot/builder:2.2.x\";\n\t\timage.trustBuilder = true;\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuilder()).hasToString(\"docker.io/springboot/builder:2.2.x\");\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasDefaultBuilderAndTrustBuilderUsesTrustBuilder() {\n\t\tImage image = new Image();\n\t\timage.trustBuilder = false;\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuilder().toString()).contains(\"paketobuildpacks/builder-noble-java-tiny\");\n\t\tassertThat(request.isTrustBuilder()).isFalse();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasRunImageUsesRunImage() {\n\t\tImage image = new Image();\n\t\timage.runImage = \"springboot/run:latest\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getRunImage()).hasToString(\"docker.io/springboot/run:latest\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasEnvUsesEnv() {\n\t\tImage image = new Image();\n\t\timage.env = Collections.singletonMap(\"test\", \"test\");\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getEnv()).containsExactly(entry(\"test\", \"test\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasCleanCacheUsesCleanCache() {\n\t\tImage image = new Image();\n\t\timage.cleanCache = true;\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.isCleanCache()).isTrue();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasVerboseLoggingUsesVerboseLogging() {\n\t\tImage image = new Image();\n\t\timage.verboseLogging = true;\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.isVerboseLogging()).isTrue();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasPullPolicyUsesPullPolicy() {\n\t\tImage image = new Image();\n\t\timage.setPullPolicy(PullPolicy.NEVER);\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getPullPolicy()).isEqualTo(PullPolicy.NEVER);\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasPublishUsesPublish() {\n\t\tImage image = new Image();\n\t\timage.publish = true;\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.isPublish()).isTrue();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuildpacksUsesBuildpacks() {\n\t\tImage image = new Image();\n\t\timage.buildpacks = Arrays.asList(\"example/buildpack1@0.0.1\", \"example/buildpack2@0.0.2\");\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuildpacks()).containsExactly(BuildpackReference.of(\"example/buildpack1@0.0.1\"),\n\t\t\t\tBuildpackReference.of(\"example/buildpack2@0.0.2\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBindingsUsesBindings() {\n\t\tImage image = new Image();\n\t\timage.bindings = Arrays.asList(\"host-src:container-dest:ro\", \"volume-name:container-dest:rw\");\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBindings()).containsExactly(Binding.of(\"host-src:container-dest:ro\"),\n\t\t\t\tBinding.of(\"volume-name:container-dest:rw\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenNetworkUsesNetwork() {\n\t\tImage image = new Image();\n\t\timage.network = \"test\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getNetwork()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasTagsUsesTags() {\n\t\tImage image = new Image();\n\t\timage.tags = Arrays.asList(\"my-app:latest\", \"example.com/my-app:0.0.1-SNAPSHOT\", \"example.com/my-app:latest\");\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getTags()).containsExactly(ImageReference.of(\"my-app:latest\"),\n\t\t\t\tImageReference.of(\"example.com/my-app:0.0.1-SNAPSHOT\"), ImageReference.of(\"example.com/my-app:latest\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuildWorkspaceVolumeUsesWorkspace() {\n\t\tImage image = new Image();\n\t\timage.buildWorkspace = CacheInfo.fromVolume(new VolumeCacheInfo(\"build-work-vol\"));\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuildWorkspace()).isEqualTo(Cache.volume(\"build-work-vol\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuildCacheVolumeUsesCache() {\n\t\tImage image = new Image();\n\t\timage.buildCache = CacheInfo.fromVolume(new VolumeCacheInfo(\"build-cache-vol\"));\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuildCache()).isEqualTo(Cache.volume(\"build-cache-vol\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasLaunchCacheVolumeUsesCache() {\n\t\tImage image = new Image();\n\t\timage.launchCache = CacheInfo.fromVolume(new VolumeCacheInfo(\"launch-cache-vol\"));\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getLaunchCache()).isEqualTo(Cache.volume(\"launch-cache-vol\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuildWorkspaceBindUsesWorkspace() {\n\t\tImage image = new Image();\n\t\timage.buildWorkspace = CacheInfo.fromBind(new BindCacheInfo(\"build-work-dir\"));\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuildWorkspace()).isEqualTo(Cache.bind(\"build-work-dir\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasBuildCacheBindUsesCache() {\n\t\tImage image = new Image();\n\t\timage.buildCache = CacheInfo.fromBind(new BindCacheInfo(\"build-cache-dir\"));\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getBuildCache()).isEqualTo(Cache.bind(\"build-cache-dir\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasLaunchCacheBindUsesCache() {\n\t\tImage image = new Image();\n\t\timage.launchCache = CacheInfo.fromBind(new BindCacheInfo(\"launch-cache-dir\"));\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getLaunchCache()).isEqualTo(Cache.bind(\"launch-cache-dir\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasCreatedDateUsesCreatedDate() {\n\t\tImage image = new Image();\n\t\timage.createdDate = \"2020-07-01T12:34:56Z\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getCreatedDate()).isEqualTo(\"2020-07-01T12:34:56Z\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasApplicationDirectoryUsesApplicationDirectory() {\n\t\tImage image = new Image();\n\t\timage.applicationDirectory = \"/application\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getApplicationDirectory()).isEqualTo(\"/application\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasNoSecurityOptionsUsesNoSecurityOptions() {\n\t\tImage image = new Image();\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getSecurityOptions()).isNull();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasSecurityOptionsUsesSecurityOptions() {\n\t\tImage image = new Image();\n\t\timage.securityOptions = List.of(\"label=user:USER\", \"label=role:ROLE\");\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getSecurityOptions()).containsExactly(\"label=user:USER\", \"label=role:ROLE\");\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasEmptySecurityOptionsUsesSecurityOptions() {\n\t\tImage image = new Image();\n\t\timage.securityOptions = Collections.emptyList();\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getSecurityOptions()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenHasImagePlatformUsesImagePlatform() {\n\t\tImage image = new Image();\n\t\timage.imagePlatform = \"linux/arm64\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getImagePlatform()).isEqualTo(ImagePlatform.of(\"linux/arm64\"));\n\t}\n\n\t@Test\n\tvoid getBuildRequestWhenImagePlatformIsEmptyDoesntSetImagePlatform() {\n\t\tImage image = new Image();\n\t\timage.imagePlatform = \"\";\n\t\tBuildRequest request = image.getBuildRequest(createArtifact(), mockApplicationContent());\n\t\tassertThat(request.getImagePlatform()).isNull();\n\t}\n\n\tprivate Artifact createArtifact() {\n\t\treturn new DefaultArtifact(\"com.example\", \"my-app\", VersionRange.createFromVersion(\"0.0.1-SNAPSHOT\"), \"compile\",\n\t\t\t\t\"jar\", null, new DefaultArtifactHandler());\n\t}\n\n\tprivate Function<Owner, TarArchive> mockApplicationContent() {\n\t\treturn (owner) -> mock(TarArchive.class);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/IncludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link org.springframework.boot.maven.IncludeFilter}.\n *\n * @author David Turanski\n */\n@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\nclass IncludeFilterTests {\n\n\t@Test\n\tvoid includeSimple() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"bar\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid includeGroupIdNoMatch() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\")));\n\t\tArtifact artifact = createArtifact(\"com.baz\", \"bar\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid includeArtifactIdNoMatch() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"biz\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid includeClassifier() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"bar\", \"jdk5\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.iterator().next()).isSameAs(artifact);\n\t}\n\n\t@Test\n\tvoid includeClassifierNoTargetClassifier() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"bar\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid includeClassifierNoMatch() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\", \"jdk5\")));\n\t\tArtifact artifact = createArtifact(\"com.foo\", \"bar\", \"jdk6\");\n\t\tSet result = filter.filter(Collections.singleton(artifact));\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid includeMulti() throws ArtifactFilterException {\n\t\tIncludeFilter filter = new IncludeFilter(Arrays.asList(createInclude(\"com.foo\", \"bar\"),\n\t\t\t\tcreateInclude(\"com.foo\", \"bar2\"), createInclude(\"org.acme\", \"app\")));\n\t\tSet<Artifact> artifacts = new HashSet<>();\n\t\tartifacts.add(createArtifact(\"com.foo\", \"bar\"));\n\t\tartifacts.add(createArtifact(\"com.foo\", \"bar\"));\n\t\tArtifact anotherAcme = createArtifact(\"org.acme\", \"another-app\");\n\t\tartifacts.add(anotherAcme);\n\t\tSet result = filter.filter(artifacts);\n\t\tassertThat(result).hasSize(2);\n\t}\n\n\tprivate Include createInclude(String groupId, String artifactId) {\n\t\treturn createInclude(groupId, artifactId, null);\n\t}\n\n\tprivate Include createInclude(String groupId, String artifactId, @Nullable String classifier) {\n\t\tInclude include = new Include();\n\t\tinclude.setGroupId(groupId);\n\t\tinclude.setArtifactId(artifactId);\n\t\tif (classifier != null) {\n\t\t\tinclude.setClassifier(classifier);\n\t\t}\n\t\treturn include;\n\t}\n\n\tprivate Artifact createArtifact(String groupId, String artifactId, @Nullable String classifier) {\n\t\tArtifact a = mock(Artifact.class);\n\t\tgiven(a.getGroupId()).willReturn(groupId);\n\t\tgiven(a.getArtifactId()).willReturn(artifactId);\n\t\tgiven(a.getClassifier()).willReturn(classifier);\n\t\treturn a;\n\t}\n\n\tprivate Artifact createArtifact(String groupId, String artifactId) {\n\t\treturn createArtifact(groupId, artifactId, null);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/JarTypeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\n\nimport org.apache.maven.artifact.Artifact;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JarTypeFilter}.\n *\n * @author Andy Wilkinson\n */\nclass JarTypeFilterTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath temp;\n\n\t@Test\n\tvoid whenArtifactHasNoJarTypeThenItIsIncluded() {\n\t\tassertThat(new JarTypeFilter().filter(createArtifact(null))).isFalse();\n\t}\n\n\t@Test\n\tvoid whenArtifactHasJarTypeThatIsNotExcludedThenItIsIncluded() {\n\t\tassertThat(new JarTypeFilter().filter(createArtifact(\"something-included\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid whenArtifactHasDependenciesStarterJarTypeThenItIsExcluded() {\n\t\tassertThat(new JarTypeFilter().filter(createArtifact(\"dependencies-starter\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid whenArtifactHasAnnotationProcessorJarTypeThenItIsExcluded() {\n\t\tassertThat(new JarTypeFilter().filter(createArtifact(\"annotation-processor\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid whenArtifactHasDevelopmentToolJarTypeThenItIsExcluded() {\n\t\tassertThat(new JarTypeFilter().filter(createArtifact(\"development-tool\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid whenArtifactHasNoManifestFileThenItIsIncluded() {\n\t\tassertThat(new JarTypeFilter().filter(createArtifactWithNoManifest())).isFalse();\n\t}\n\n\tprivate Artifact createArtifact(@Nullable String springBootJarType) {\n\t\tPath jarPath = this.temp.resolve(\"test.jar\");\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(\"Manifest-Version\", \"1.0\");\n\t\tif (springBootJarType != null) {\n\t\t\tmanifest.getMainAttributes().putValue(\"Spring-Boot-Jar-Type\", springBootJarType);\n\t\t}\n\t\ttry {\n\t\t\tnew JarOutputStream(new FileOutputStream(jarPath.toFile()), manifest).close();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn mockArtifact(jarPath);\n\t}\n\n\tprivate Artifact createArtifactWithNoManifest() {\n\t\tPath jarPath = this.temp.resolve(\"test.jar\");\n\t\ttry {\n\t\t\tnew JarOutputStream(new FileOutputStream(jarPath.toFile())).close();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn mockArtifact(jarPath);\n\t}\n\n\tprivate Artifact mockArtifact(Path jarPath) {\n\t\tArtifact artifact = mock(Artifact.class);\n\t\tgiven(artifact.getFile()).willReturn(jarPath.toFile());\n\t\treturn artifact;\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/JavaCompilerPluginConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.Arrays;\nimport java.util.Properties;\n\nimport org.apache.maven.model.Plugin;\nimport org.apache.maven.project.MavenProject;\nimport org.codehaus.plexus.util.xml.Xpp3Dom;\nimport org.codehaus.plexus.util.xml.Xpp3DomBuilder;\nimport org.codehaus.plexus.util.xml.pull.XmlPullParserException;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JavaCompilerPluginConfiguration}.\n *\n * @author Scott Frederick\n */\nclass JavaCompilerPluginConfigurationTests {\n\n\tprivate MavenProject project;\n\n\tprivate Plugin plugin;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.project = mock(MavenProject.class);\n\t\tthis.plugin = mock(Plugin.class);\n\t\tgiven(this.project.getPlugin(anyString())).willReturn(this.plugin);\n\t}\n\n\t@Test\n\tvoid versionsAreNullWithNoConfiguration() {\n\t\tgiven(this.plugin.getConfiguration()).willReturn(null);\n\t\tgiven(this.project.getProperties()).willReturn(new Properties());\n\t\tJavaCompilerPluginConfiguration configuration = new JavaCompilerPluginConfiguration(this.project);\n\t\tassertThat(configuration.getSourceMajorVersion()).isNull();\n\t\tassertThat(configuration.getTargetMajorVersion()).isNull();\n\t\tassertThat(configuration.getReleaseVersion()).isNull();\n\t}\n\n\t@Test\n\tvoid versionsAreReturnedFromConfiguration() throws IOException, XmlPullParserException {\n\t\tXpp3Dom dom = buildConfigurationDom(\"<source>1.9</source>\", \"<target>11</target>\", \"<release>12</release>\");\n\t\tgiven(this.plugin.getConfiguration()).willReturn(dom);\n\t\tProperties properties = new Properties();\n\t\tproperties.setProperty(\"maven.compiler.source\", \"1.8\");\n\t\tproperties.setProperty(\"maven.compiler.target\", \"10\");\n\t\tproperties.setProperty(\"maven.compiler.release\", \"11\");\n\t\tgiven(this.project.getProperties()).willReturn(properties);\n\t\tJavaCompilerPluginConfiguration configuration = new JavaCompilerPluginConfiguration(this.project);\n\t\tassertThat(configuration.getSourceMajorVersion()).isEqualTo(\"9\");\n\t\tassertThat(configuration.getTargetMajorVersion()).isEqualTo(\"11\");\n\t\tassertThat(configuration.getReleaseVersion()).isEqualTo(\"12\");\n\t}\n\n\t@Test\n\tvoid versionsAreReturnedFromProperties() {\n\t\tgiven(this.plugin.getConfiguration()).willReturn(null);\n\t\tProperties properties = new Properties();\n\t\tproperties.setProperty(\"maven.compiler.source\", \"1.8\");\n\t\tproperties.setProperty(\"maven.compiler.target\", \"11\");\n\t\tproperties.setProperty(\"maven.compiler.release\", \"12\");\n\t\tgiven(this.project.getProperties()).willReturn(properties);\n\t\tJavaCompilerPluginConfiguration configuration = new JavaCompilerPluginConfiguration(this.project);\n\t\tassertThat(configuration.getSourceMajorVersion()).isEqualTo(\"8\");\n\t\tassertThat(configuration.getTargetMajorVersion()).isEqualTo(\"11\");\n\t\tassertThat(configuration.getReleaseVersion()).isEqualTo(\"12\");\n\t}\n\n\tprivate Xpp3Dom buildConfigurationDom(String... properties) throws IOException, XmlPullParserException {\n\t\treturn Xpp3DomBuilder\n\t\t\t.build(new StringReader(\"<configuration>\" + Arrays.toString(properties) + \"</configuration>\"));\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/MavenBuildOutputTimestampTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.nio.file.attribute.FileTime;\nimport java.time.Instant;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link MavenBuildOutputTimestamp}.\n *\n * @author Moritz Halbritter\n */\nclass MavenBuildOutputTimestampTests {\n\n\t@Test\n\tvoid shouldParseNull() {\n\t\tassertThat(parse(null)).isNull();\n\t}\n\n\t@Test\n\tvoid shouldParseSingleDigit() {\n\t\tassertThat(parse(\"0\")).isEqualTo(Instant.parse(\"1970-01-01T00:00:00Z\"));\n\t}\n\n\t@Test\n\tvoid shouldNotParseSingleCharacter() {\n\t\tassertThat(parse(\"a\")).isNull();\n\t}\n\n\t@Test\n\tvoid shouldParseIso8601() {\n\t\tassertThat(parse(\"2011-12-03T10:15:30Z\")).isEqualTo(Instant.parse(\"2011-12-03T10:15:30.000Z\"));\n\t}\n\n\t@Test\n\tvoid shouldParseIso8601WithMilliseconds() {\n\t\tassertThat(parse(\"2011-12-03T10:15:30.123Z\")).isEqualTo(Instant.parse(\"2011-12-03T10:15:30.123Z\"));\n\t}\n\n\t@Test\n\tvoid shouldFailIfIso8601BeforeMin() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> parse(\"1970-01-01T00:00:00Z\"))\n\t\t\t.withMessage(\n\t\t\t\t\t\"'1970-01-01T00:00:00Z' is not within the valid range 1980-01-01T00:00:02Z to 2099-12-31T23:59:59Z\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfIso8601AfterMax() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> parse(\"2100-01-01T00:00:00Z\"))\n\t\t\t.withMessage(\n\t\t\t\t\t\"'2100-01-01T00:00:00Z' is not within the valid range 1980-01-01T00:00:02Z to 2099-12-31T23:59:59Z\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfNotIso8601() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> parse(\"dummy\"))\n\t\t\t.withMessage(\"Can't parse 'dummy' to instant\");\n\t}\n\n\t@Test\n\tvoid shouldParseIso8601WithOffset() {\n\t\tassertThat(parse(\"2019-10-05T20:37:42+06:00\")).isEqualTo(Instant.parse(\"2019-10-05T14:37:42Z\"));\n\t}\n\n\t@Test\n\tvoid shouldParseToFileTime() {\n\t\tassertThat(parseFileTime(null)).isEqualTo(null);\n\t\tassertThat(parseFileTime(\"0\")).isEqualTo(FileTime.fromMillis(0));\n\t\tassertThat(parseFileTime(\"2019-10-05T14:37:42Z\")).isEqualTo(FileTime.fromMillis(1570286262000L));\n\t}\n\n\tprivate static @Nullable Instant parse(@Nullable String timestamp) {\n\t\treturn new MavenBuildOutputTimestamp(timestamp).toInstant();\n\t}\n\n\tprivate static @Nullable FileTime parseFileTime(@Nullable String timestamp) {\n\t\treturn new MavenBuildOutputTimestamp(timestamp).toFileTime();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/PropertiesMergingResourceTransformerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarInputStream;\nimport java.util.jar.JarOutputStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesMergingResourceTransformer}.\n *\n * @author Dave Syer\n */\nclass PropertiesMergingResourceTransformerTests {\n\n\tprivate final PropertiesMergingResourceTransformer transformer = new PropertiesMergingResourceTransformer();\n\n\t@Test\n\tvoid testProcess() throws Exception {\n\t\tassertThat(this.transformer.hasTransformedResource()).isFalse();\n\t\tthis.transformer.processResource(\"foo\", new ByteArrayInputStream(\"foo=bar\".getBytes()), Collections.emptyList(),\n\t\t\t\t0);\n\t\tassertThat(this.transformer.hasTransformedResource()).isTrue();\n\t}\n\n\t@Test\n\tvoid testMerge() throws Exception {\n\t\tthis.transformer.processResource(\"foo\", new ByteArrayInputStream(\"foo=bar\".getBytes()), Collections.emptyList(),\n\t\t\t\t0);\n\t\tthis.transformer.processResource(\"bar\", new ByteArrayInputStream(\"foo=spam\".getBytes()),\n\t\t\t\tCollections.emptyList(), 0);\n\t\tassertThat(this.transformer.getData().getProperty(\"foo\")).isEqualTo(\"bar,spam\");\n\t}\n\n\t@Test\n\tvoid testOutput() throws Exception {\n\t\tthis.transformer.setResource(\"foo\");\n\t\tlong time = 1592911068000L;\n\t\tthis.transformer.processResource(\"foo\", new ByteArrayInputStream(\"foo=bar\".getBytes()), Collections.emptyList(),\n\t\t\t\ttime);\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tJarOutputStream os = new JarOutputStream(out);\n\t\tthis.transformer.modifyOutputStream(os);\n\t\tos.flush();\n\t\tos.close();\n\t\tbyte[] bytes = out.toByteArray();\n\t\tassertThat(bytes).isNotEmpty();\n\t\tList<JarEntry> entries = new ArrayList<>();\n\t\ttry (JarInputStream is = new JarInputStream(new ByteArrayInputStream(bytes))) {\n\t\t\tJarEntry entry;\n\t\t\twhile ((entry = is.getNextJarEntry()) != null) {\n\t\t\t\tentries.add(entry);\n\t\t\t}\n\t\t}\n\t\tassertThat(entries).hasSize(1);\n\t\tassertThat(entries.get(0).getTime()).isEqualTo(time);\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/RunArgumentsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RunArguments}.\n *\n * @author Stephane Nicoll\n */\nclass RunArgumentsTests {\n\n\t@Test\n\tvoid parseNull() {\n\t\tString[] args = parseArgs(null);\n\t\tassertThat(args).isNotNull();\n\t\tassertThat(args).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Maven can't handle nullable arrays\n\tvoid parseNullArray() {\n\t\tString[] args = new RunArguments((String[]) null).asArray();\n\t\tassertThat(args).isNotNull();\n\t\tassertThat(args).isEmpty();\n\t}\n\n\t@Test\n\tvoid parseArrayContainingNullValue() {\n\t\tString[] args = new RunArguments(new String[] { \"foo\", null, \"bar\" }).asArray();\n\t\tassertThat(args).isNotNull();\n\t\tassertThat(args).containsOnly(\"foo\", \"bar\");\n\t}\n\n\t@Test\n\tvoid parseArrayContainingEmptyValue() {\n\t\tString[] args = new RunArguments(new String[] { \"foo\", \"\", \"bar\" }).asArray();\n\t\tassertThat(args).isNotNull();\n\t\tassertThat(args).containsOnly(\"foo\", \"\", \"bar\");\n\t}\n\n\t@Test\n\tvoid parseEmpty() {\n\t\tString[] args = parseArgs(\"   \");\n\t\tassertThat(args).isNotNull();\n\t\tassertThat(args).isEmpty();\n\t}\n\n\t@Test\n\tvoid parseDebugFlag() {\n\t\tString[] args = parseArgs(\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005\");\n\t\tassertThat(args).hasSize(1);\n\t\tassertThat(args[0]).isEqualTo(\"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005\");\n\t}\n\n\t@Test\n\tvoid parseWithExtraSpaces() {\n\t\tString[] args = parseArgs(\"     -Dfoo=bar        -Dfoo2=bar2  \");\n\t\tassertThat(args).hasSize(2);\n\t\tassertThat(args[0]).isEqualTo(\"-Dfoo=bar\");\n\t\tassertThat(args[1]).isEqualTo(\"-Dfoo2=bar2\");\n\t}\n\n\t@Test\n\tvoid parseWithNewLinesAndTabs() {\n\t\tString[] args = parseArgs(\"     -Dfoo=bar \\n\\t\\t -Dfoo2=bar2  \");\n\t\tassertThat(args).hasSize(2);\n\t\tassertThat(args[0]).isEqualTo(\"-Dfoo=bar\");\n\t\tassertThat(args[1]).isEqualTo(\"-Dfoo2=bar2\");\n\t}\n\n\t@Test\n\tvoid quoteHandledProperly() {\n\t\tString[] args = parseArgs(\"-Dvalue=\\\"My Value\\\"    \");\n\t\tassertThat(args).hasSize(1);\n\t\tassertThat(args[0]).isEqualTo(\"-Dvalue=My Value\");\n\t}\n\n\tprivate String[] parseArgs(@Nullable String args) {\n\t\treturn new RunArguments(args).asArray();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/SystemPropertyFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SystemPropertyFormatter}.\n */\nclass SystemPropertyFormatterTests {\n\n\t@Test\n\tvoid parseEmpty() {\n\t\tassertThat(SystemPropertyFormatter.format(null, null)).isEmpty();\n\t}\n\n\t@Test\n\tvoid parseOnlyKey() {\n\t\tassertThat(SystemPropertyFormatter.format(\"key1\", null)).isEqualTo(\"-Dkey1\");\n\t}\n\n\t@Test\n\tvoid parseKeyWithValue() {\n\t\tassertThat(SystemPropertyFormatter.format(\"key1\", \"value1\")).isEqualTo(\"-Dkey1=value1\");\n\t}\n\n\t@Test\n\tvoid parseKeyWithEmptyValue() {\n\t\tassertThat(SystemPropertyFormatter.format(\"key1\", \"\")).isEqualTo(\"-Dkey1\");\n\t}\n\n\t@Test\n\tvoid parseKeyWithOnlySpaces() {\n\t\tassertThat(SystemPropertyFormatter.format(\"key1\", \"   \")).isEqualTo(\"-Dkey1=   \");\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/sample/ClassWithMainMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven.sample;\n\n/**\n * Sample class with a main method.\n *\n * @author Phillip Webb\n */\npublic class ClassWithMainMethod {\n\n\tpublic void run() {\n\t\tSystem.out.println(\"Hello World\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew ClassWithMainMethod().run();\n\t}\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/sample/ClassWithoutMainMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.maven.sample;\n\n/**\n * Sample class without a main method.\n *\n * @author Phillip Webb\n */\npublic class ClassWithoutMainMethod {\n\n}\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/java/org/springframework/boot/maven/sample/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sample code for testing the Maven plugin for Spring Boot.\n */\n@NullMarked\npackage org.springframework.boot.maven.sample;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/resources/application-layer-no-filter.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t  https://www.springframework.org/schema/boot/layers/layers.xsd\">\n\t<application>\n\t\t<into layer=\"my-layer\" />\n\t</application>\n\t<layerOrder>\n\t\t<layer>my-layer</layer>\n\t</layerOrder>\n</layers>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/resources/dependencies-layer-no-filter.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t  https://www.springframework.org/schema/boot/layers/layers-4.1.xsd\">\n\t<dependencies>\n\t\t<into layer=\"my-deps\" />\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>my-deps</layer>\n\t</layerOrder>\n</layers>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/resources/layers.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t  https://www.springframework.org/schema/boot/layers/layers-4.1.xsd\">\n\t<application>\n\t\t<into layer=\"my-resources\">\n\t\t\t<include>META-INF/resources/**</include>\n\t\t\t<exclude>*.properties</exclude>\n\t\t</into>\n\t\t<into layer=\"configuration\">\n\t\t\t<include>**/application*.*</include>\n\t\t</into>\n\t\t<into layer=\"application\" />\n\t</application>\n\t<dependencies>\n\t\t<into layer=\"snapshot-dependencies\">\n\t\t\t<include>*:*:*-SNAPSHOT</include>\n\t\t\t<excludeModuleDependencies/>\n\t\t</into>\n\t\t<into layer=\"application\">\n\t\t\t<includeModuleDependencies/>\n\t\t</into>\n\t\t<into layer=\"my-deps\">\n\t\t\t<include>com.acme:*</include>\n\t\t</into>\n\t\t<into layer=\"my-dependencies-name\"/>\n\t</dependencies>\n\t<layerOrder>\n\t\t<layer>my-deps</layer>\n\t\t<layer>my-dependencies-name</layer>\n\t\t<layer>snapshot-dependencies</layer>\n\t\t<layer>my-resources</layer>\n\t\t<layer>configuration</layer>\n\t\t<layer>application</layer>\n\t</layerOrder>\n</layers>"
  },
  {
    "path": "build-plugin/spring-boot-maven-plugin/src/test/resources/resource-layer-no-filter.xml",
    "content": "<layers xmlns=\"http://www.springframework.org/schema/boot/layers\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/boot/layers\n\t\t\t\t\t  https://www.springframework.org/schema/boot/layers/layers-4.1.xsd\">\n\t<application>\n\t\t<into layer=\"my-layer\" />\n\t</application>\n\t<layerOrder>\n\t\t<layer>my-layer</layer>\n\t</layerOrder>\n</layers>"
  },
  {
    "path": "build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"base\"\n}\n\ndescription = \"Spring Boot Build\"\n\ndefaultTasks 'build'\n\nallprojects {\n\tgroup = \"org.springframework.boot\"\n}\n\nsubprojects {\n\tapply plugin: \"org.springframework.boot.conventions\"\n\n\trepositories {\n\t\tmavenCentral()\n\t\tmaven {\n\t\t\tname = \"Shibboleth Releases\"\n\t\t\turl = \"https://build.shibboleth.net/nexus/content/repositories/releases\"\n\t\t\tcontent {\n\t\t\t\tincludeGroup \"org.opensaml\"\n\t\t\t\tincludeGroup \"net.shibboleth\"\n\t\t\t}\n\t\t}\n\t\tspring.mavenRepositories()\n\t}\n\n\tconfigurations.all {\n\t\tresolutionStrategy.cacheChangingModulesFor 0, \"minutes\"\n\t}\n}\n"
  },
  {
    "path": "buildSrc/SpringRepositorySupport.groovy",
    "content": "/*\n * Copyright 2012-2024 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n//\n// This script can be used in the `pluginManagement` block of a `settings.gradle` file to provide\n// support for spring maven repositories.\n//\n// To use the script add the following as the first line in the `pluginManagement` block:\n//\n//     evaluate(new File(\"${rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n//\n// You can then use `spring.mavenRepositories()` to add the Spring repositories required for the\n// version being built.\n//\n\nimport java.util.function.*\n\ndef apply(settings) {\n\tdef version =  property(settings, 'version')\n\tdef buildType = property(settings, 'spring.build-type')\n\tSpringRepositoriesExtension.addTo(settings.pluginManagement.repositories, version, buildType)\n\tsettings.gradle.allprojects {\n\t\tSpringRepositoriesExtension.addTo(repositories, version, buildType)\n\t}\n}\n\nprivate def property(settings, name) {\n\tdef value = null\n\ttry {\n\t\tvalue = settings.gradle.parent?.rootProject?.findProperty(name)\n\t}\n\tcatch (Exception ex) {\n\t}\n\ttry {\n\t\tvalue = (value != null) ? value : settings.ext.find(name)\n\t}\n\tcatch (Exception ex) {\n\t}\n\tvalue = (value != null) ? value : loadProperty(settings, name)\n\treturn value\n}\n\nprivate def loadProperty(settings, name) {\n\tdef scriptDir = new File(getClass().protectionDomain.codeSource.location.path).parent\n\tnew File(scriptDir, \"../gradle.properties\").withInputStream {\n\t\tdef properties = new Properties()\n\t\tproperties.load(it)\n\t\treturn properties.get(name)\n\t}\n}\n\nreturn this\n\nclass SpringRepositoriesExtension {\n\n\tprivate final def repositories\n\tprivate final def version\n\tprivate final def buildType\n\tprivate final UnaryOperator<String> environment\n\n\t@javax.inject.Inject\n\tSpringRepositoriesExtension(repositories, version, buildType) {\n\t\tthis(repositories, version, buildType, System::getenv)\n\t}\n\n\tSpringRepositoriesExtension(repositories, version, buildType, environment) {\n\t\tthis.repositories = repositories\n\t\tthis.version = version\n\t\tthis.buildType = buildType\n\t\tthis.environment = environment\n\t}\n\n\tdef mavenRepositories() {\n\t\taddRepositories { }\n\t}\n\n\tdef mavenRepositoriesFor(version) {\n\t\taddRepositories(version) { }\n\t}\n\n\tdef mavenRepositoriesExcludingBootGroup() {\n\t\taddRepositories { maven ->\n\t\t\tmaven.content { content ->\n\t\t\t\tcontent.excludeGroup(\"org.springframework.boot\")\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addRepositories(action) {\n\t\taddRepositories(this.version, action)\n\t}\n\n\tprivate void addRepositories(version, action) {\n\t\taddCommercialRepositoryIfNecessary(\"release\", false, \"/spring-enterprise-maven-prod-local\", action)\n\t\tif (version.endsWith(\"-SNAPSHOT\")) {\n\t\t\taddCommercialRepositoryIfNecessary(\"snapshot\", true, \"/spring-enterprise-maven-dev-local\", action)\n\t\t\taddOssRepository(\"snapshot\", true, \"/snapshot\", action)\n\t\t}\n\t}\n\n\tprivate void addOssRepository(id, snapshot, path, action) {\n\t\tdef name = \"spring-oss-\" + id\n\t\tdef url = \"https://repo.spring.io\" + path\n\t\taddRepository(name, snapshot, url, action)\n\t}\n\n\tprivate void addCommercialRepositoryIfNecessary(id, snapshot, path, action) {\n\t\tif (!\"commercial\".equalsIgnoreCase(this.buildType)) return\n\t\tdef name = \"spring-commercial-\" + id\n\t\tdef url = fromEnv(\"COMMERCIAL_%SREPO_URL\", id, \"https://usw1.packages.broadcom.com\" + path)\n\t\tdef username = fromEnv(\"COMMERCIAL_%SREPO_USERNAME\", id)\n\t\tdef password = fromEnv(\"COMMERCIAL_%SREPO_PASSWORD\", id)\n\t\taddRepository(name, snapshot, url, { maven ->\n\t\t\tmaven.credentials { credentials ->\n\t\t\t\tcredentials.setUsername(username)\n\t\t\t\tcredentials.setPassword(password)\n\t\t\t}\n\t\t\taction(maven)\n\t\t})\n\t}\n\n\tprivate void addRepository(name, snapshot, url, action) {\n\t\tthis.repositories.maven { maven ->\n\t\t\tmaven.setName(name)\n\t\t\tmaven.setUrl(url)\n\t\t\tmaven.mavenContent { mavenContent ->\n\t\t\t\tif (snapshot) {\n\t\t\t\t\tmavenContent.snapshotsOnly()\n\t\t\t\t} else {\n\t\t\t\t\tmavenContent.releasesOnly()\n\t\t\t\t}\n\t\t\t}\n\t\t\taction(maven)\n\t\t}\n\t}\n\n\tprivate String fromEnv(template, id) {\n\t\treturn fromEnv(template, id, null)\n\t}\n\n\tprivate String fromEnv(template, id, defaultValue) {\n\t\tString value = this.environment.apply(template.formatted(id.toUpperCase() + \"_\"))\n\t\tvalue = (value != null) ? value : this.environment.apply(template.formatted(\"\"))\n\t\treturn (value != null) ? value : defaultValue\n\t}\n\n\tstatic def addTo(repositories, version, buildType) {\n\t\trepositories.extensions.create(\"spring\", SpringRepositoriesExtension.class, repositories, version, buildType)\n\t}\n\n}"
  },
  {
    "path": "buildSrc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-gradle-plugin\"\n\tid \"io.spring.javaformat\" version \"${javaFormatVersion}\"\n\tid \"checkstyle\"\n\tid \"eclipse\"\n\tid \"org.jetbrains.dokka\" version \"2.1.0\"\n}\n\nrepositories {\n\tmavenCentral()\n\tspring.mavenRepositoriesFor(\"${springFrameworkVersion}\")\n\tgradlePluginPortal()\n\tmaven { url = \"https://repo.spring.io/snapshot\" }\n}\n\njava {\n\tsourceCompatibility = 17\n\ttargetCompatibility = 17\n}\n\ncheckstyle {\n\ttoolVersion = \"${checkstyleToolVersion}\"\n}\n\ndependencies {\n\tcheckstyle(\"com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}\")\n\tcheckstyle(\"io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}\")\n\n\timplementation(platform(\"com.fasterxml.jackson:jackson-bom:${jackson2Version}\"))\n\timplementation(platform(\"tools.jackson:jackson-bom:${jacksonVersion}\"))\n\timplementation(platform(\"org.springframework:spring-framework-bom:${springFrameworkVersion}\"))\n\timplementation(\"com.github.node-gradle:gradle-node-plugin:7.1.0\")\n\timplementation(\"com.gradle:develocity-gradle-plugin:4.2.2\")\n\timplementation(\"com.tngtech.archunit:archunit:1.4.1\")\n\timplementation(\"commons-codec:commons-codec:${commonsCodecVersion}\")\n\timplementation(\"de.undercouch.download:de.undercouch.download.gradle.plugin:5.5.0\")\n\timplementation(\"org.jetbrains.dokka:dokka-gradle-plugin:2.1.0\")\n\timplementation(\"dev.detekt:detekt-gradle-plugin:2.0.0-alpha.0\")\n\timplementation(\"io.spring.gradle.antora:spring-antora-plugin:0.0.1\")\n\timplementation(\"io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}\")\n\timplementation(\"io.spring.nohttp:nohttp-gradle:0.0.11\")\n\timplementation(\"org.apache.httpcomponents.client5:httpclient5:5.3.1\")\n\timplementation(\"org.apache.maven:maven-artifact:${mavenVersion}\")\n\timplementation(\"org.antora:gradle-antora-plugin:1.0.0\")\n\timplementation(\"org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}\")\n\timplementation(\"org.springframework:spring-context\")\n\timplementation(\"org.springframework:spring-core\")\n\timplementation(\"org.springframework:spring-web\")\n\timplementation(\"org.yaml:snakeyaml:${snakeYamlVersion}\")\n\timplementation(\"io.spring.gradle.nullability:nullability-plugin:${nullabilityPluginVersion}\")\n\timplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestImplementation(platform(\"org.junit:junit-bom:${junitJupiterVersion}\"))\n\ttestImplementation(\"org.assertj:assertj-core:${assertjVersion}\")\n\ttestImplementation(\"org.hamcrest:hamcrest:${hamcrestVersion}\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.mockito:mockito-core:${mockitoVersion}\")\n\ttestImplementation(\"org.springframework:spring-test\")\n\n\ttestRuntimeOnly(\"org.junit.platform:junit-platform-launcher\")\n}\n\nconfigurations.all {\n\texclude group:\"org.slf4j\", module:\"slf4j-api\"\n\texclude group:\"ch.qos.logback\", module:\"logback-classic\"\n\texclude group:\"ch.qos.logback\", module:\"logback-core\"\n\n\tresolutionStrategy.cacheChangingModulesFor 0, \"minutes\"\n}\n\ngradlePlugin {\n\tplugins {\n\t\taggregatorPlugin {\n\t\t\tid = \"org.springframework.boot.aggregator\"\n\t\t\timplementationClass = \"org.springframework.boot.build.aggregation.AggregatorPlugin\"\n\t\t}\n\t\tannotationProcessorPlugin {\n\t\t\tid = \"org.springframework.boot.annotation-processor\"\n\t\t\timplementationClass = \"org.springframework.boot.build.processors.AnnotationProcessorPlugin\"\n\t\t}\n\t\tantoraAggregatedPlugin {\n\t\t\tid = \"org.springframework.boot.antora-contributor\"\n\t\t\timplementationClass = \"org.springframework.boot.build.antora.AntoraContributorPlugin\"\n\t\t}\n\t\tantoraAggregatorPlugin {\n\t\t\tid = \"org.springframework.boot.antora-dependencies\"\n\t\t\timplementationClass = \"org.springframework.boot.build.antora.AntoraDependenciesPlugin\"\n\t\t}\n\t\tarchitecturePlugin {\n\t\t\tid = \"org.springframework.boot.architecture\"\n\t\t\timplementationClass = \"org.springframework.boot.build.architecture.ArchitecturePlugin\"\n\t\t}\n\t\tautoConfigurationPlugin {\n\t\t\tid = \"org.springframework.boot.auto-configuration\"\n\t\t\timplementationClass = \"org.springframework.boot.build.autoconfigure.AutoConfigurationPlugin\"\n\t\t}\n\t\tbomPlugin {\n\t\t\tid = \"org.springframework.boot.bom\"\n\t\t\timplementationClass = \"org.springframework.boot.build.bom.BomPlugin\"\n\t\t}\n\t\tconfigurationMetadataPlugin {\n\t\t\tid = \"org.springframework.boot.configuration-metadata\"\n\t\t\timplementationClass = \"org.springframework.boot.build.context.properties.ConfigurationMetadataPlugin\"\n\t\t}\n\t\tconfigurationPropertiesPlugin {\n\t\t\tid = \"org.springframework.boot.configuration-properties\"\n\t\t\timplementationClass = \"org.springframework.boot.build.context.properties.ConfigurationPropertiesPlugin\"\n\t\t}\n\t\tconventionsPlugin {\n\t\t\tid = \"org.springframework.boot.conventions\"\n\t\t\timplementationClass = \"org.springframework.boot.build.ConventionsPlugin\"\n\t\t}\n\t\tdeployedPlugin {\n\t\t\tid = \"org.springframework.boot.deployed\"\n\t\t\timplementationClass = \"org.springframework.boot.build.DeployedPlugin\"\n\t\t}\n\t\tdockerTestPlugin {\n\t\t\tid = \"org.springframework.boot.docker-test\"\n\t\t\timplementationClass = \"org.springframework.boot.build.test.DockerTestPlugin\"\n\t\t}\n\t\tintegrationTestPlugin {\n\t\t\tid = \"org.springframework.boot.integration-test\"\n\t\t\timplementationClass = \"org.springframework.boot.build.test.IntegrationTestPlugin\"\n\t\t}\n\t\tmavenPluginPlugin {\n\t\t\tid = \"org.springframework.boot.maven-plugin\"\n\t\t\timplementationClass = \"org.springframework.boot.build.mavenplugin.MavenPluginPlugin\"\n\t\t}\n\t\tmavenRepositoryPlugin {\n\t\t\tid = \"org.springframework.boot.maven-repository\"\n\t\t\timplementationClass = \"org.springframework.boot.build.MavenRepositoryPlugin\"\n\t\t}\n\t\toptionalDependenciesPlugin {\n\t\t\tid = \"org.springframework.boot.optional-dependencies\"\n\t\t\timplementationClass = \"org.springframework.boot.build.optional.OptionalDependenciesPlugin\"\n\t\t}\n\t\tstarterPlugin {\n\t\t\tid = \"org.springframework.boot.starter\"\n\t\t\timplementationClass = \"org.springframework.boot.build.starters.StarterPlugin\"\n\t\t}\n\t\tsystemTestPlugin {\n\t\t\tid = \"org.springframework.boot.system-test\"\n\t\t\timplementationClass = \"org.springframework.boot.build.test.SystemTestPlugin\"\n\t\t}\n\t\ttestAutoConfigurationPlugin {\n\t\t\tid = \"org.springframework.boot.test-auto-configuration\"\n\t\t\timplementationClass = \"org.springframework.boot.build.test.autoconfigure.TestAutoConfigurationPlugin\"\n\t\t}\n\t\ttestFailuresPlugin {\n\t\t\tid = \"org.springframework.boot.test-failures\"\n\t\t\timplementationClass = \"org.springframework.boot.build.testing.TestFailuresPlugin\"\n\t\t}\n\t\ttestSlicePlugin {\n\t\t\tid = \"org.springframework.boot.test-slice\"\n\t\t\timplementationClass = \"org.springframework.boot.build.test.autoconfigure.TestSlicePlugin\"\n\t\t}\n\t}\n}\n\ntest {\n\tuseJUnitPlatform()\n}\n\neclipse {\n\tjdt {\n\t\tfile {\n\t\t\twithProperties {\n\t\t\t\tit[\"org.eclipse.jdt.core.compiler.ignoreUnnamedModuleForSplitPackage\"] = \"enabled\"\n\t\t\t}\n\t\t}\n\t}\n}\n\njar.dependsOn check\n"
  },
  {
    "path": "buildSrc/config/checkstyle/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n\t\t\"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\"\n\t\t\"https://checkstyle.org/dtds/configuration_1_3.dtd\">\n<module name=\"com.puppycrawl.tools.checkstyle.Checker\">\n\t<module name=\"io.spring.javaformat.checkstyle.SpringChecks\">\n\t\t<property name=\"excludes\" value=\"com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck\" />\n\t</module>\n\t<module name=\"com.puppycrawl.tools.checkstyle.TreeWalker\">\n\t\t<module name=\"com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck\">\n\t\t\t<property name=\"regexp\" value=\"true\" />\n\t\t\t<property name=\"illegalPkgs\"\n\t\t\t\tvalue=\"^com\\.fasterxml\\.jackson(?!\\.annotation).*\" />\n\t\t</module>\n\t</module>\n</module>\n"
  },
  {
    "path": "buildSrc/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tnew File(rootDir.parentFile, \"gradle.properties\").withInputStream {\n\t\tdef properties = new Properties()\n\t\tproperties.load(it)\n\t\tproperties.forEach(settings.ext::set)\n\t\tgradle.rootProject {\n\t\t\tproperties.forEach(project.ext::set)\n\t\t}\n\t}\n\tevaluate(new File(\"${rootDir}/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmavenCentral()\n\t\tgradlePluginPortal()\n\t}\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/AntoraConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.github.gradle.node.NodeExtension;\nimport com.github.gradle.node.npm.task.NpmInstallTask;\nimport io.spring.gradle.antora.GenerateAntoraYmlPlugin;\nimport io.spring.gradle.antora.GenerateAntoraYmlTask;\nimport org.antora.gradle.AntoraPlugin;\nimport org.antora.gradle.AntoraTask;\nimport org.gradle.StartParameter;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.logging.LogLevel;\nimport org.gradle.api.plugins.JavaBasePlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.Copy;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.build.antora.AntoraAsciidocAttributes;\nimport org.springframework.boot.build.antora.CheckJavadocMacros;\nimport org.springframework.boot.build.antora.GenerateAntoraPlaybook;\nimport org.springframework.boot.build.bom.BomExtension;\nimport org.springframework.boot.build.bom.ResolvedBom;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Conventions that are applied in the presence of the {@link AntoraPlugin}.\n *\n * @author Phillip Webb\n */\npublic class AntoraConventions {\n\n\tprivate static final String DEPENDENCIES_PATH = \":platform:spring-boot-dependencies\";\n\n\tprivate static final List<String> NAV_FILES = List.of(\"nav.adoc\", \"local-nav.adoc\");\n\n\t/**\n\t * Default Antora source directory.\n\t */\n\tpublic static final String ANTORA_SOURCE_DIR = \"src/docs/antora\";\n\n\t/**\n\t * Name of the {@link GenerateAntoraPlaybook} task.\n\t */\n\tpublic static final String GENERATE_ANTORA_PLAYBOOK_TASK_NAME = \"generateAntoraPlaybook\";\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withType(AntoraPlugin.class, (antoraPlugin) -> apply(project, antoraPlugin));\n\t}\n\n\tprivate void apply(Project project, AntoraPlugin antoraPlugin) {\n\t\tConfiguration resolvedBom = project.getConfigurations().create(\"resolveBom\");\n\t\tproject.getDependencies()\n\t\t\t.add(resolvedBom.getName(), project.getDependencies()\n\t\t\t\t.project(Map.of(\"path\", DEPENDENCIES_PATH, \"configuration\", \"resolvedBom\")));\n\t\tproject.getPlugins().apply(GenerateAntoraYmlPlugin.class);\n\t\tTaskContainer tasks = project.getTasks();\n\t\tTaskProvider<GenerateAntoraPlaybook> generateAntoraPlaybookTask = tasks.register(\n\t\t\t\tGENERATE_ANTORA_PLAYBOOK_TASK_NAME, GenerateAntoraPlaybook.class,\n\t\t\t\t(task) -> configureGenerateAntoraPlaybookTask(project, task));\n\t\tTaskProvider<Copy> copyAntoraPackageJsonTask = tasks.register(\"copyAntoraPackageJson\", Copy.class,\n\t\t\t\t(task) -> configureCopyAntoraPackageJsonTask(project, task));\n\t\tTaskProvider<NpmInstallTask> npmInstallTask = tasks.register(\"antoraNpmInstall\", NpmInstallTask.class,\n\t\t\t\t(task) -> configureNpmInstallTask(project, task, copyAntoraPackageJsonTask));\n\t\ttasks.withType(GenerateAntoraYmlTask.class,\n\t\t\t\t(generateAntoraYmlTask) -> configureGenerateAntoraYmlTask(project, generateAntoraYmlTask, resolvedBom));\n\t\ttasks.withType(AntoraTask.class,\n\t\t\t\t(antoraTask) -> configureAntoraTask(project, antoraTask, npmInstallTask, generateAntoraPlaybookTask));\n\t\tproject.getExtensions()\n\t\t\t.configure(NodeExtension.class, (nodeExtension) -> configureNodeExtension(project, nodeExtension));\n\t\tTaskProvider<CheckJavadocMacros> checkAntoraJavadocMacros = tasks.register(\"checkAntoraJavadocMacros\",\n\t\t\t\tCheckJavadocMacros.class, (task) -> {\n\t\t\t\t\ttask.setSource(project.files(ANTORA_SOURCE_DIR));\n\t\t\t\t\ttask.getOutputDirectory().set(project.getLayout().getBuildDirectory().dir(task.getName()));\n\t\t\t\t});\n\t\tproject.getPlugins().withType(JavaPlugin.class, (java) -> {\n\t\t\tString runtimeClasspathConfigurationName = project.getExtensions()\n\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t.getSourceSets()\n\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME)\n\t\t\t\t.getRuntimeClasspathConfigurationName();\n\t\t\tConfiguration javadocMacros = project.getConfigurations().create(\"javadocMacros\", (configuration) -> {\n\t\t\t\tconfiguration.extendsFrom(project.getConfigurations().getByName(runtimeClasspathConfigurationName));\n\t\t\t\tconfiguration.setDescription(\n\t\t\t\t\t\t\"Dependencies referenced in javadoc macros. Extends from \" + runtimeClasspathConfigurationName);\n\t\t\t\tconfiguration.setCanBeResolved(true);\n\t\t\t\tconfiguration.setCanBeDeclared(true);\n\t\t\t\tconfiguration.setCanBeConsumed(false);\n\t\t\t});\n\t\t\tcheckAntoraJavadocMacros.configure((macrosTask) -> macrosTask.setClasspath(javadocMacros));\n\t\t});\n\t}\n\n\tprivate void configureGenerateAntoraPlaybookTask(Project project,\n\t\t\tGenerateAntoraPlaybook generateAntoraPlaybookTask) {\n\t\tProvider<Directory> nodeProjectDir = getNodeProjectDir(project);\n\t\tgenerateAntoraPlaybookTask.getOutputFile()\n\t\t\t.set(nodeProjectDir.map((directory) -> directory.file(\"antora-playbook.yml\")));\n\t}\n\n\tprivate void configureCopyAntoraPackageJsonTask(Project project, Copy copyAntoraPackageJsonTask) {\n\t\tcopyAntoraPackageJsonTask\n\t\t\t.from(project.getRootProject().file(\"antora\"),\n\t\t\t\t\t(spec) -> spec.include(\"package.json\", \"package-lock.json\", \"patches/**\"))\n\t\t\t.into(getNodeProjectDir(project));\n\t}\n\n\tprivate void configureNpmInstallTask(Project project, NpmInstallTask npmInstallTask,\n\t\t\tTaskProvider<Copy> copyAntoraPackageJson) {\n\t\tnpmInstallTask.dependsOn(copyAntoraPackageJson);\n\t\tMap<String, String> environment = new HashMap<>();\n\t\tenvironment.put(\"npm_config_omit\", \"optional\");\n\t\tenvironment.put(\"npm_config_update_notifier\", \"false\");\n\t\tnpmInstallTask.getEnvironment().set(environment);\n\t\tnpmInstallTask.getNpmCommand().set(List.of(\"ci\", \"--silent\", \"--no-progress\"));\n\t}\n\n\tprivate void configureGenerateAntoraYmlTask(Project project, GenerateAntoraYmlTask generateAntoraYmlTask,\n\t\t\tConfiguration resolvedBom) {\n\t\tgenerateAntoraYmlTask.getOutputs().doNotCacheIf(\"getAsciidocAttributes() changes output\", (task) -> true);\n\t\tgenerateAntoraYmlTask.dependsOn(resolvedBom);\n\t\tgenerateAntoraYmlTask.setProperty(\"componentName\", \"boot\");\n\t\tgenerateAntoraYmlTask.setProperty(\"outputFile\",\n\t\t\t\tproject.getLayout().getBuildDirectory().file(\"generated/docs/antora-yml/antora.yml\"));\n\t\tgenerateAntoraYmlTask.setProperty(\"yml\", getDefaultYml(project));\n\t\tgenerateAntoraYmlTask.getAsciidocAttributes().putAll(getAsciidocAttributes(project, resolvedBom));\n\t}\n\n\tprivate Map<String, ?> getDefaultYml(Project project) {\n\t\tString navFile = null;\n\t\tfor (String candidate : NAV_FILES) {\n\t\t\tif (project.file(ANTORA_SOURCE_DIR + \"/\" + candidate).exists()) {\n\t\t\t\tAssert.state(navFile == null, \"Multiple nav files found\");\n\t\t\t\tnavFile = candidate;\n\t\t\t}\n\t\t}\n\t\tMap<String, Object> defaultYml = new LinkedHashMap<>();\n\t\tdefaultYml.put(\"title\", \"Spring Boot\");\n\t\tif (navFile != null) {\n\t\t\tdefaultYml.put(\"nav\", List.of(navFile));\n\t\t}\n\t\treturn defaultYml;\n\t}\n\n\tprivate Provider<Map<String, String>> getAsciidocAttributes(Project project, FileCollection resolvedBoms) {\n\t\treturn project.provider(() -> {\n\t\t\tBomExtension bom = (BomExtension) project.project(DEPENDENCIES_PATH).getExtensions().getByName(\"bom\");\n\t\t\tResolvedBom resolvedBom = ResolvedBom.readFrom(resolvedBoms.getSingleFile());\n\t\t\treturn new AntoraAsciidocAttributes(project, bom, resolvedBom).get();\n\t\t});\n\t}\n\n\tprivate void configureAntoraTask(Project project, AntoraTask antoraTask,\n\t\t\tTaskProvider<NpmInstallTask> npmInstallTask,\n\t\t\tTaskProvider<GenerateAntoraPlaybook> generateAntoraPlaybookTask) {\n\t\tantoraTask.setGroup(\"Documentation\");\n\t\tantoraTask.dependsOn(npmInstallTask, generateAntoraPlaybookTask);\n\t\tantoraTask.setPlaybook(\"antora-playbook.yml\");\n\t\tantoraTask.setUiBundleUrl(getUiBundleUrl(project));\n\t\tantoraTask.getArgs().set(project.provider(() -> getAntoraNpxArs(project, antoraTask)));\n\t\tproject.getPlugins()\n\t\t\t.withType(JavaBasePlugin.class,\n\t\t\t\t\t(javaBasePlugin) -> project.getTasks()\n\t\t\t\t\t\t.getByName(JavaBasePlugin.CHECK_TASK_NAME)\n\t\t\t\t\t\t.dependsOn(antoraTask));\n\t}\n\n\tprivate List<String> getAntoraNpxArs(Project project, AntoraTask antoraTask) {\n\t\tlogWarningIfNodeModulesInUserHome(project);\n\t\tStartParameter startParameter = project.getGradle().getStartParameter();\n\t\tboolean showStacktrace = startParameter.getShowStacktrace().name().startsWith(\"ALWAYS\");\n\t\tboolean debugLogging = project.getGradle().getStartParameter().getLogLevel() == LogLevel.DEBUG;\n\t\tString playbookPath = antoraTask.getPlaybook();\n\t\tList<String> arguments = new ArrayList<>();\n\t\targuments.addAll(List.of(\"--package\", \"@antora/cli\"));\n\t\targuments.add(\"antora\");\n\t\targuments.addAll((!showStacktrace) ? Collections.emptyList() : List.of(\"--stacktrace\"));\n\t\targuments.addAll((!debugLogging) ? List.of(\"--quiet\") : List.of(\"--log-level\", \"all\"));\n\t\targuments.addAll(List.of(\"--ui-bundle-url\", antoraTask.getUiBundleUrl()));\n\t\targuments.add(playbookPath);\n\t\treturn arguments;\n\t}\n\n\tprivate void logWarningIfNodeModulesInUserHome(Project project) {\n\t\tif (new File(System.getProperty(\"user.home\"), \"node_modules\").exists()) {\n\t\t\tproject.getLogger()\n\t\t\t\t.warn(\"Detected the existence of $HOME/node_modules. This directory is \"\n\t\t\t\t\t\t+ \"not compatible with this plugin. Please remove it.\");\n\t\t}\n\t}\n\n\tprivate String getUiBundleUrl(Project project) {\n\t\tFile packageJson = project.getRootProject().file(\"antora/package.json\");\n\t\tJsonMapper jsonMapper = new JsonMapper();\n\t\tMap<?, ?> json = jsonMapper.readerFor(Map.class).readValue(packageJson);\n\t\tMap<?, ?> config = (json != null) ? (Map<?, ?>) json.get(\"config\") : null;\n\t\tString url = (config != null) ? (String) config.get(\"ui-bundle-url\") : null;\n\t\tAssert.state(StringUtils.hasText(url.toString()), \"package.json has not ui-bundle-url config\");\n\t\treturn url;\n\t}\n\n\tprivate void configureNodeExtension(Project project, NodeExtension nodeExtension) {\n\t\tnodeExtension.getWorkDir().set(project.getLayout().getBuildDirectory().dir(\".gradle/nodejs\"));\n\t\tnodeExtension.getNpmWorkDir().set(project.getLayout().getBuildDirectory().dir(\".gradle/npm\"));\n\t\tnodeExtension.getNodeProjectDir().set(getNodeProjectDir(project));\n\t}\n\n\tprivate Provider<Directory> getNodeProjectDir(Project project) {\n\t\treturn project.getLayout().getBuildDirectory().dir(\".gradle/nodeproject\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport org.antora.gradle.AntoraPlugin;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.plugins.JavaBasePlugin;\nimport org.gradle.api.publish.maven.plugins.MavenPublishPlugin;\n\n/**\n * Plugin to apply conventions to projects that are part of Spring Boot's build.\n * Conventions are applied in response to various plugins being applied.\n *\n * When the {@link JavaBasePlugin} is applied, the conventions in {@link JavaConventions}\n * are applied.\n *\n * When the {@link MavenPublishPlugin} is applied, the conventions in\n * {@link MavenPublishingConventions} are applied.\n *\n * When the {@link AntoraPlugin} is applied, the conventions in {@link AntoraConventions}\n * are applied.\n *\n * @author Andy Wilkinson\n * @author Christoph Dreis\n * @author Mike Smithson\n */\npublic class ConventionsPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tSystemRequirementsExtension systemRequirements = project.getExtensions()\n\t\t\t.create(\"systemRequirements\", SystemRequirementsExtension.class);\n\t\tnew NoHttpConventions().apply(project);\n\t\tnew JavaConventions(systemRequirements).apply(project);\n\t\tnew MavenPublishingConventions().apply(project);\n\t\tnew AntoraConventions().apply(project);\n\t\tnew KotlinConventions().apply(project);\n\t\tnew WarConventions().apply(project);\n\t\tnew EclipseConventions(systemRequirements).apply(project);\n\t\tnew TestFixturesConventions().apply(project);\n\t\tRepositoryTransformersExtension.apply(project);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/DeployedPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.plugins.JavaPlatformPlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.publish.PublishingExtension;\nimport org.gradle.api.publish.maven.MavenPublication;\nimport org.gradle.api.publish.maven.plugins.MavenPublishPlugin;\nimport org.gradle.api.tasks.bundling.Jar;\n\n/**\n * A plugin applied to a project that should be deployed.\n *\n * @author Andy Wilkinson\n */\npublic class DeployedPlugin implements Plugin<Project> {\n\n\t/**\n\t * Name of the task that generates the deployed pom file.\n\t */\n\tpublic static final String GENERATE_POM_TASK_NAME = \"generatePomFileForMavenPublication\";\n\n\t@Override\n\t@SuppressWarnings(\"deprecation\")\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().apply(MavenPublishPlugin.class);\n\t\tproject.getPlugins().apply(MavenRepositoryPlugin.class);\n\t\tPublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);\n\t\tMavenPublication mavenPublication = publishing.getPublications().create(\"maven\", MavenPublication.class);\n\t\tproject.afterEvaluate((evaluated) -> project.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> {\n\t\t\tif (((Jar) project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME)).isEnabled()) {\n\t\t\t\tproject.getComponents()\n\t\t\t\t\t.matching((component) -> component.getName().equals(\"java\"))\n\t\t\t\t\t.all(mavenPublication::from);\n\t\t\t}\n\t\t}));\n\t\tproject.getPlugins()\n\t\t\t.withType(JavaPlatformPlugin.class)\n\t\t\t.all((javaPlugin) -> project.getComponents()\n\t\t\t\t.matching((component) -> component.getName().equals(\"javaPlatform\"))\n\t\t\t\t.all(mavenPublication::from));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/EclipseConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport org.gradle.api.DomainObjectCollection;\nimport org.gradle.api.JavaVersion;\nimport org.gradle.api.Project;\nimport org.gradle.api.plugins.JavaBasePlugin;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.plugins.ide.api.XmlFileContentMerger;\nimport org.gradle.plugins.ide.eclipse.EclipsePlugin;\nimport org.gradle.plugins.ide.eclipse.model.Classpath;\nimport org.gradle.plugins.ide.eclipse.model.ClasspathEntry;\nimport org.gradle.plugins.ide.eclipse.model.EclipseClasspath;\nimport org.gradle.plugins.ide.eclipse.model.EclipseJdt;\nimport org.gradle.plugins.ide.eclipse.model.EclipseModel;\nimport org.gradle.plugins.ide.eclipse.model.Library;\n\n/**\n * Conventions that are applied in the presence of the {@link EclipsePlugin} to work\n * around buildship issue {@code #1238}.\n *\n * @author Phillip Webb\n */\nclass EclipseConventions {\n\n\tprivate final SystemRequirementsExtension systemRequirements;\n\n\tEclipseConventions(SystemRequirementsExtension systemRequirements) {\n\t\tthis.systemRequirements = systemRequirements;\n\t}\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withType(EclipsePlugin.class, (eclipse) -> configure(project, eclipse));\n\t\tproject.afterEvaluate(this::setJavaRuntimeName);\n\t}\n\n\tprivate DomainObjectCollection<JavaBasePlugin> configure(Project project, EclipsePlugin eclipsePlugin) {\n\t\tTaskProvider<?> synchronizeResourceSettings = registerEclipseSynchronizeResourceSettings(project);\n\t\tTaskProvider<?> synchronizeJdtSettings = registerEclipseSynchronizeJdtSettings(project);\n\t\treturn project.getPlugins().withType(JavaBasePlugin.class, (javaBase) -> {\n\t\t\tEclipseModel model = project.getExtensions().getByType(EclipseModel.class);\n\t\t\tmodel.synchronizationTasks(synchronizeResourceSettings, synchronizeJdtSettings);\n\t\t\tmodel.jdt(this::configureJdt);\n\t\t\tmodel.classpath(this::configureClasspath);\n\t\t});\n\t}\n\n\tprivate TaskProvider<?> registerEclipseSynchronizeResourceSettings(Project project) {\n\t\tTaskProvider<EclipseSynchronizeResourceSettings> eclipseSynchronizateResource = project.getTasks()\n\t\t\t.register(\"eclipseSynchronizateResourceSettings\", EclipseSynchronizeResourceSettings.class);\n\t\teclipseSynchronizateResource.configure((task) -> {\n\t\t\ttask.setDescription(\"Synchronizate the Eclipse resource settings file from Buildship.\");\n\t\t\ttask.setOutputFile(project.file(\".settings/org.eclipse.core.resources.prefs\"));\n\t\t\ttask.setInputFile(project.file(\".settings/org.eclipse.core.resources.prefs\"));\n\t\t});\n\t\treturn eclipseSynchronizateResource;\n\t}\n\n\tprivate TaskProvider<EclipseSynchronizeJdtSettings> registerEclipseSynchronizeJdtSettings(Project project) {\n\t\tTaskProvider<EclipseSynchronizeJdtSettings> taskProvider = project.getTasks()\n\t\t\t.register(\"eclipseSynchronizeJdtSettings\", EclipseSynchronizeJdtSettings.class);\n\t\ttaskProvider.configure((task) -> {\n\t\t\ttask.setDescription(\"Synchronizate the Eclipse JDT settings file from Buildship.\");\n\t\t\ttask.setOutputFile(project.file(\".settings/org.eclipse.jdt.core.prefs\"));\n\t\t\ttask.setInputFile(project.file(\".settings/org.eclipse.jdt.core.prefs\"));\n\t\t});\n\t\treturn taskProvider;\n\t}\n\n\tprivate void configureJdt(EclipseJdt jdt) {\n\t\tjdt.setSourceCompatibility(JavaVersion.toVersion(JavaConventions.RUNTIME_JAVA_VERSION));\n\t\tjdt.setTargetCompatibility(JavaVersion.toVersion(JavaConventions.RUNTIME_JAVA_VERSION));\n\t}\n\n\tprivate void configureClasspath(EclipseClasspath classpath) {\n\t\tclasspath.file(this::configureClasspathFile);\n\t}\n\n\tprivate void configureClasspathFile(XmlFileContentMerger merger) {\n\t\tmerger.whenMerged((content) -> {\n\t\t\tif (content instanceof Classpath classpath) {\n\t\t\t\tclasspath.getEntries().removeIf(this::isKotlinPluginContributedBuildDirectory);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void setJavaRuntimeName(Project project) {\n\t\tEclipseModel model = project.getExtensions().findByType(EclipseModel.class);\n\t\tEclipseJdt jdt = (model != null) ? model.getJdt() : null;\n\t\tif (jdt != null) {\n\t\t\tmodel.getJdt().setJavaRuntimeName(\"JavaSE-\" + this.systemRequirements.getJava().getVersion());\n\t\t}\n\t}\n\n\tprivate boolean isKotlinPluginContributedBuildDirectory(ClasspathEntry entry) {\n\t\treturn (entry instanceof Library library) && isKotlinPluginContributedBuildDirectory(library.getPath())\n\t\t\t\t&& isTest(library);\n\t}\n\n\tprivate boolean isKotlinPluginContributedBuildDirectory(String path) {\n\t\treturn path.contains(\"/main\") && (path.contains(\"/build/classes/\") || path.contains(\"/build/resources/\"));\n\t}\n\n\tprivate boolean isTest(Library library) {\n\t\tObject value = library.getEntryAttributes().get(\"test\");\n\t\treturn (value instanceof String string && Boolean.parseBoolean(string));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/EclipseSynchronizeJdtSettings.java",
    "content": "/*\n * Copyright 2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.util.Properties;\n\nimport org.gradle.api.Task;\nimport org.gradle.api.internal.PropertiesTransformer;\nimport org.gradle.plugins.ide.api.PropertiesGeneratorTask;\n\nimport org.springframework.boot.build.EclipseSynchronizeJdtSettings.Configuration;\n\n/**\n * {@link Task} to synchronize Eclipse JDT settings.\n *\n * @author Phillip Webb\n */\npublic abstract class EclipseSynchronizeJdtSettings extends PropertiesGeneratorTask<Configuration> {\n\n\t@Override\n\tprotected Configuration create() {\n\t\treturn new Configuration(getTransformer());\n\t}\n\n\t@Override\n\tprotected void configure(Configuration configuration) {\n\t}\n\n\tstatic class Configuration extends EmptyPropertiesPersistableConfigurationObject {\n\n\t\tConfiguration(PropertiesTransformer transformer) {\n\t\t\tsuper(transformer);\n\t\t}\n\n\t\t@Override\n\t\tprotected void store(Properties properties) {\n\t\t\tproperties.put(\"org.eclipse.jdt.core.compiler.release\", \"true\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/EclipseSynchronizeResourceSettings.java",
    "content": "/*\n * Copyright 2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.util.Properties;\n\nimport org.gradle.api.Task;\nimport org.gradle.api.internal.PropertiesTransformer;\nimport org.gradle.plugins.ide.api.PropertiesGeneratorTask;\n\nimport org.springframework.boot.build.EclipseSynchronizeResourceSettings.Configuration;\n\n/**\n * {@link Task} to synchronize Eclipse resource settings.\n *\n * @author Phillip Webb\n */\npublic abstract class EclipseSynchronizeResourceSettings extends PropertiesGeneratorTask<Configuration> {\n\n\t@Override\n\tprotected Configuration create() {\n\t\treturn new Configuration(getTransformer());\n\t}\n\n\t@Override\n\tprotected void configure(Configuration configuration) {\n\t}\n\n\tpublic static class Configuration extends EmptyPropertiesPersistableConfigurationObject {\n\n\t\tConfiguration(PropertiesTransformer transformer) {\n\t\t\tsuper(transformer);\n\t\t}\n\n\t\t@Override\n\t\tprotected void store(Properties properties) {\n\t\t\tproperties.put(\"encoding/<project>\", \"UTF-8\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/EmptyPropertiesPersistableConfigurationObject.java",
    "content": "/*\n * Copyright 2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.Properties;\n\nimport org.gradle.api.internal.PropertiesTransformer;\nimport org.gradle.internal.UncheckedException;\nimport org.gradle.plugins.ide.internal.generator.PropertiesPersistableConfigurationObject;\n\n/**\n * Base class for {@link PropertiesPersistableConfigurationObject} instances start empty\n * and have no default resource.\n *\n * @author Phillip Webb\n */\nabstract class EmptyPropertiesPersistableConfigurationObject extends PropertiesPersistableConfigurationObject {\n\n\tEmptyPropertiesPersistableConfigurationObject(PropertiesTransformer transformer) {\n\t\tsuper(transformer);\n\t}\n\n\t@Override\n\tprotected String getDefaultResourceName() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void loadDefaults() {\n\t\ttry {\n\t\t\tload(new ByteArrayInputStream(new byte[0]));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow UncheckedException.throwAsUncheckedException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void load(Properties properties) {\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/ExtractResources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.PropertyPlaceholderHelper;\n\n/**\n * {@link Task} to extract resources from the classpath and write them to disk.\n *\n * @author Andy Wilkinson\n */\npublic abstract class ExtractResources extends DefaultTask {\n\n\tprivate final PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper(\"${\", \"}\");\n\n\t@Input\n\tpublic abstract Property<String> getPackageName();\n\n\t@Input\n\tpublic abstract ListProperty<String> getResourceNames();\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getDestinationDirectory();\n\n\t@Input\n\tpublic abstract MapProperty<String, String> getProperties();\n\n\t@TaskAction\n\tvoid extractResources() throws IOException {\n\t\tfor (String resourceName : getResourceNames().get()) {\n\t\t\tInputStream resourceStream = getClass().getClassLoader()\n\t\t\t\t.getResourceAsStream(getPackageName().getOrElse(\"\").replace(\".\", \"/\") + \"/\" + resourceName);\n\t\t\tif (resourceStream == null) {\n\t\t\t\tthrow new GradleException(\"Resource '\" + resourceName + \"' does not exist\");\n\t\t\t}\n\t\t\tString resource = FileCopyUtils.copyToString(new InputStreamReader(resourceStream, StandardCharsets.UTF_8));\n\t\t\tresource = this.propertyPlaceholderHelper.replacePlaceholders(resource, getProperties().get()::get);\n\t\t\tFileCopyUtils.copy(resource,\n\t\t\t\t\tnew FileWriter(getDestinationDirectory().file(resourceName).get().getAsFile()));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/JavaConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\nimport com.gradle.develocity.agent.gradle.test.DevelocityTestConfiguration;\nimport com.gradle.develocity.agent.gradle.test.PredictiveTestSelectionConfiguration;\nimport com.gradle.develocity.agent.gradle.test.TestRetryConfiguration;\nimport io.spring.gradle.nullability.NullabilityPlugin;\nimport io.spring.gradle.nullability.NullabilityPluginExtension;\nimport io.spring.javaformat.gradle.SpringJavaFormatPlugin;\nimport io.spring.javaformat.gradle.tasks.CheckFormat;\nimport io.spring.javaformat.gradle.tasks.Format;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.JavaVersion;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.artifacts.DependencySet;\nimport org.gradle.api.file.FileTreeElement;\nimport org.gradle.api.plugins.JavaBasePlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.plugins.quality.Checkstyle;\nimport org.gradle.api.plugins.quality.CheckstyleExtension;\nimport org.gradle.api.plugins.quality.CheckstylePlugin;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.SourceTask;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.gradle.api.tasks.compile.JavaCompile;\nimport org.gradle.api.tasks.javadoc.Javadoc;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.external.javadoc.CoreJavadocOptions;\nimport org.gradle.jvm.toolchain.JavaCompiler;\nimport org.gradle.jvm.toolchain.JavaInstallationMetadata;\nimport org.gradle.jvm.toolchain.JavaLanguageVersion;\n\nimport org.springframework.boot.build.architecture.ArchitecturePlugin;\nimport org.springframework.boot.build.classpath.CheckClasspathForProhibitedDependencies;\nimport org.springframework.boot.build.optional.OptionalDependenciesPlugin;\nimport org.springframework.boot.build.springframework.CheckAotFactories;\nimport org.springframework.boot.build.springframework.CheckSpringFactories;\nimport org.springframework.boot.build.testing.TestFailuresPlugin;\nimport org.springframework.boot.build.toolchain.ToolchainPlugin;\nimport org.springframework.util.StringUtils;\n\n/**\n * Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the\n * plugin is applied:\n *\n * <ul>\n * <li>The project is configured with source and target compatibility of 17\n * <li>{@link SpringJavaFormatPlugin Spring Java Format}, {@link CheckstylePlugin\n * Checkstyle}, {@link TestFailuresPlugin Test Failures}, {@link ArchitecturePlugin\n * Architecture} and {@link NullabilityPlugin} plugins are applied\n * <li>{@link Test} tasks are configured:\n * <ul>\n * <li>to use JUnit Platform\n * <li>with a max heap of 1536M\n * <li>to run after any Checkstyle and format checking tasks\n * <li>to enable retries with a maximum of three attempts when running on CI\n * <li>to use predictive test selection when the value of the\n * {@code ENABLE_PREDICTIVE_TEST_SELECTION} environment variable is {@code true}\n * </ul>\n * <li>A {@code testRuntimeOnly} dependency upon\n * {@code org.junit.platform:junit-platform-launcher} is added to projects with the\n * {@link JavaPlugin} applied\n * <li>{@link JavaCompile}, {@link Javadoc}, and {@link Format} tasks are configured to\n * use UTF-8 encoding\n * <li>{@link JavaCompile} tasks are configured to:\n * <ul>\n * <li>Use {@code -parameters}.\n * <li>Treat warnings as errors\n * <li>Enable {@code unchecked}, {@code deprecation}, {@code rawtypes}, and\n * {@code varargs} warnings\n * </ul>\n * <li>{@link Jar} tasks are configured to produce jars with LICENSE.txt and NOTICE.txt\n * files and the following manifest entries:\n * <ul>\n * <li>{@code Automatic-Module-Name}\n * <li>{@code Build-Jdk-Spec}\n * <li>{@code Built-By}\n * <li>{@code Implementation-Title}\n * <li>{@code Implementation-Version}\n * </ul>\n * <li>{@code spring-boot-parent} is used for dependency management</li>\n * <li>Additional checks are configured:\n * <ul>\n * <li>For all source sets:\n * <ul>\n * <li>Prohibited dependencies on the compile classpath\n * <li>Prohibited dependencies on the runtime classpath\n * </ul>\n * <li>For the {@code main} source set:\n * <ul>\n * <li>{@code META-INF/spring/aot.factories}\n * <li>{@code META-INF/spring.factories}\n * </ul>\n * </ul>\n * </ul>\n *\n * <p/>\n *\n * @author Andy Wilkinson\n * @author Christoph Dreis\n * @author Mike Smithson\n * @author Scott Frederick\n */\nclass JavaConventions {\n\n\tpublic static final int BUILD_JAVA_VERSION = 25;\n\n\tpublic static final int RUNTIME_JAVA_VERSION = 17;\n\n\tprivate final SystemRequirementsExtension systemRequirements;\n\n\tJavaConventions(SystemRequirementsExtension systemRequirements) {\n\t\tthis.systemRequirements = systemRequirements;\n\t}\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withType(JavaBasePlugin.class, (java) -> {\n\t\t\tproject.getPlugins().apply(TestFailuresPlugin.class);\n\t\t\tproject.getPlugins().apply(ArchitecturePlugin.class);\n\t\t\tconfigureSpringJavaFormat(project);\n\t\t\tconfigureJavaConventions(project);\n\t\t\tconfigureJavadocConventions(project);\n\t\t\tconfigureTestConventions(project);\n\t\t\tconfigureJarManifestConventions(project);\n\t\t\tconfigureDependencyManagement(project);\n\t\t\tconfigureToolchain(project);\n\t\t\tconfigureProhibitedDependencyChecks(project);\n\t\t\tconfigureFactoriesFilesChecks(project);\n\t\t\tconfigureNullability(project);\n\t\t});\n\t}\n\n\tprivate void configureJarManifestConventions(Project project) {\n\t\tTaskProvider<ExtractResources> extractLegalResources = project.getTasks()\n\t\t\t.register(\"extractLegalResources\", ExtractResources.class, (task) -> {\n\t\t\t\ttask.getPackageName().set(\"org.springframework.boot.build.legal\");\n\t\t\t\ttask.getDestinationDirectory().set(project.getLayout().getBuildDirectory().dir(\"legal\"));\n\t\t\t\ttask.getResourceNames().set(Arrays.asList(\"LICENSE.txt\", \"NOTICE.txt\"));\n\t\t\t\ttask.getProperties().put(\"version\", project.getVersion().toString());\n\t\t\t});\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);\n\t\tSet<String> sourceJarTaskNames = sourceSets.stream()\n\t\t\t.map(SourceSet::getSourcesJarTaskName)\n\t\t\t.collect(Collectors.toSet());\n\t\tSet<String> javadocJarTaskNames = sourceSets.stream()\n\t\t\t.map(SourceSet::getJavadocJarTaskName)\n\t\t\t.collect(Collectors.toSet());\n\t\tproject.getTasks().withType(Jar.class, (jar) -> project.afterEvaluate((evaluated) -> {\n\t\t\tjar.metaInf((metaInf) -> metaInf.from(extractLegalResources));\n\t\t\tjar.manifest((manifest) -> {\n\t\t\t\tMap<String, Object> attributes = new TreeMap<>();\n\t\t\t\tattributes.put(\"Automatic-Module-Name\", project.getName().replace(\"-\", \".\"));\n\t\t\t\t// Build-Jdk-Spec is used by buildpacks to pick the JRE to install\n\t\t\t\tattributes.put(\"Build-Jdk-Spec\", this.systemRequirements.getJava().getVersion());\n\t\t\t\tattributes.put(\"Built-By\", \"Spring\");\n\t\t\t\tattributes.put(\"Implementation-Title\",\n\t\t\t\t\t\tdetermineImplementationTitle(project, sourceJarTaskNames, javadocJarTaskNames, jar));\n\t\t\t\tattributes.put(\"Implementation-Version\", project.getVersion());\n\t\t\t\tmanifest.attributes(attributes);\n\t\t\t});\n\t\t}));\n\t}\n\n\tprivate String determineImplementationTitle(Project project, Set<String> sourceJarTaskNames,\n\t\t\tSet<String> javadocJarTaskNames, Jar jar) {\n\t\tif (sourceJarTaskNames.contains(jar.getName())) {\n\t\t\treturn \"Source for \" + project.getName();\n\t\t}\n\t\tif (javadocJarTaskNames.contains(jar.getName())) {\n\t\t\treturn \"Javadoc for \" + project.getName();\n\t\t}\n\t\treturn project.getDescription();\n\t}\n\n\tprivate void configureTestConventions(Project project) {\n\t\tproject.getTasks().withType(Test.class, (test) -> {\n\t\t\ttest.useJUnitPlatform();\n\t\t\ttest.setMaxHeapSize(\"1536M\");\n\t\t\tproject.getTasks().withType(Checkstyle.class, test::mustRunAfter);\n\t\t\tproject.getTasks().withType(CheckFormat.class, test::mustRunAfter);\n\t\t\tconfigureTestRetries(test);\n\t\t\tconfigurePredictiveTestSelection(test);\n\t\t});\n\t\tproject.getPlugins()\n\t\t\t.withType(JavaPlugin.class, (javaPlugin) -> project.getDependencies()\n\t\t\t\t.add(JavaPlugin.TEST_RUNTIME_ONLY_CONFIGURATION_NAME, \"org.junit.platform:junit-platform-launcher\"));\n\t}\n\n\tprivate void configureTestRetries(Test test) {\n\t\tTestRetryConfiguration testRetry = test.getExtensions()\n\t\t\t.getByType(DevelocityTestConfiguration.class)\n\t\t\t.getTestRetry();\n\t\ttestRetry.getFailOnPassedAfterRetry().set(false);\n\t\ttestRetry.getMaxRetries().set(isCi() ? 3 : 0);\n\t}\n\n\tprivate boolean isCi() {\n\t\treturn Boolean.parseBoolean(System.getenv(\"CI\"));\n\t}\n\n\tprivate void configurePredictiveTestSelection(Test test) {\n\t\tif (isPredictiveTestSelectionEnabled()) {\n\t\t\tPredictiveTestSelectionConfiguration predictiveTestSelection = test.getExtensions()\n\t\t\t\t.getByType(DevelocityTestConfiguration.class)\n\t\t\t\t.getPredictiveTestSelection();\n\t\t\tpredictiveTestSelection.getEnabled().convention(true);\n\t\t}\n\t}\n\n\tprivate boolean isPredictiveTestSelectionEnabled() {\n\t\treturn Boolean.parseBoolean(System.getenv(\"ENABLE_PREDICTIVE_TEST_SELECTION\"));\n\t}\n\n\tprivate void configureJavadocConventions(Project project) {\n\t\tproject.getTasks().withType(Javadoc.class, (javadoc) -> {\n\t\t\tCoreJavadocOptions options = (CoreJavadocOptions) javadoc.getOptions();\n\t\t\toptions.source(\"17\");\n\t\t\toptions.encoding(\"UTF-8\");\n\t\t\taddValuelessOption(options, \"Xdoclint:none\");\n\t\t\taddValuelessOption(options, \"quiet\");\n\t\t\tif (!javadoc.getName().contains(\"aggregated\")) {\n\t\t\t\taddValuelessOption(options, \"-no-fonts\");\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void addValuelessOption(CoreJavadocOptions options, String option) {\n\t\toptions.addMultilineMultiValueOption(option).setValue(List.of(Collections.emptyList()));\n\t}\n\n\tprivate void configureJavaConventions(Project project) {\n\t\tproject.getTasks().withType(JavaCompile.class, (compile) -> {\n\t\t\tcompile.doFirst((task) -> assertCompatible(compile));\n\t\t\tcompile.getOptions().setEncoding(\"UTF-8\");\n\t\t\tcompile.getOptions().getRelease().set(RUNTIME_JAVA_VERSION);\n\t\t\tSet<String> args = new LinkedHashSet<>(compile.getOptions().getCompilerArgs());\n\t\t\targs.addAll(List.of(\"-parameters\", \"-Werror\", \"-Xlint:unchecked\", \"-Xlint:deprecation\", \"-Xlint:rawtypes\",\n\t\t\t\t\t\"-Xlint:varargs\"));\n\t\t\tcompile.getOptions().setCompilerArgs(new ArrayList<>(args));\n\t\t});\n\t}\n\n\tprivate void assertCompatible(JavaCompile compile) {\n\t\tJavaVersion requiredVersion = JavaVersion.toVersion(BUILD_JAVA_VERSION);\n\t\tJavaVersion actualVersion = compile.getJavaCompiler()\n\t\t\t.map(JavaCompiler::getMetadata)\n\t\t\t.map(JavaInstallationMetadata::getLanguageVersion)\n\t\t\t.map(JavaLanguageVersion::asInt)\n\t\t\t.map(JavaVersion::toVersion)\n\t\t\t.orElse(JavaVersion.current())\n\t\t\t.get();\n\t\tif (!actualVersion.isCompatibleWith(requiredVersion)) {\n\t\t\tthrow new GradleException(\"This project should be built with Java %s or above\".formatted(requiredVersion));\n\t\t}\n\t}\n\n\tprivate void configureSpringJavaFormat(Project project) {\n\t\tproject.getPlugins().apply(SpringJavaFormatPlugin.class);\n\t\tproject.getTasks().withType(Format.class, (Format) -> Format.setEncoding(\"UTF-8\"));\n\t\tproject.getPlugins().apply(CheckstylePlugin.class);\n\t\tCheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);\n\t\tString checkstyleToolVersion = (String) project.findProperty(\"checkstyleToolVersion\");\n\t\tcheckstyle.setToolVersion(checkstyleToolVersion);\n\t\tcheckstyle.getConfigDirectory().set(project.getRootProject().file(\"config/checkstyle\"));\n\t\tString version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();\n\t\tDependencySet checkstyleDependencies = project.getConfigurations().getByName(\"checkstyle\").getDependencies();\n\t\tcheckstyleDependencies\n\t\t\t.add(project.getDependencies().create(\"com.puppycrawl.tools:checkstyle:\" + checkstyle.getToolVersion()));\n\t\tcheckstyleDependencies\n\t\t\t.add(project.getDependencies().create(\"io.spring.javaformat:spring-javaformat-checkstyle:\" + version));\n\t\tproject.getTasks().withType(CheckFormat.class, this::excludeGeneratedSources);\n\t\tproject.getTasks().withType(Checkstyle.class, this::excludeGeneratedSources);\n\t}\n\n\tprivate SourceTask excludeGeneratedSources(SourceTask task) {\n\t\treturn task.exclude(this::isGeneratedSource);\n\t}\n\n\tprivate boolean isGeneratedSource(FileTreeElement candidate) {\n\t\tString path = StringUtils.cleanPath(candidate.getFile().getPath());\n\t\treturn path.contains(\"/generated/sources/\") || path.contains(\"/generated-source/\");\n\t}\n\n\tprivate void configureDependencyManagement(Project project) {\n\t\tConfigurationContainer configurations = project.getConfigurations();\n\t\tConfiguration dependencyManagement = configurations.create(\"dependencyManagement\", (configuration) -> {\n\t\t\tconfiguration.setVisible(false);\n\t\t\tconfiguration.setCanBeConsumed(false);\n\t\t\tconfiguration.setCanBeResolved(false);\n\t\t});\n\t\tconfigurations\n\t\t\t.matching((configuration) -> (configuration.getName().endsWith(\"Classpath\")\n\t\t\t\t\t|| JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME.equals(configuration.getName()))\n\t\t\t\t\t&& (!configuration.getName().contains(\"dokka\")))\n\t\t\t.all((configuration) -> configuration.extendsFrom(dependencyManagement));\n\t\tDependency springBootParent = project.getDependencies()\n\t\t\t.enforcedPlatform(project.getDependencies()\n\t\t\t\t.project(Collections.singletonMap(\"path\", \":platform:spring-boot-internal-dependencies\")));\n\t\tdependencyManagement.getDependencies().add(springBootParent);\n\t\tproject.getPlugins()\n\t\t\t.withType(OptionalDependenciesPlugin.class,\n\t\t\t\t\t(optionalDependencies) -> configurations\n\t\t\t\t\t\t.getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME)\n\t\t\t\t\t\t.extendsFrom(dependencyManagement));\n\t}\n\n\tprivate void configureToolchain(Project project) {\n\t\tproject.getPlugins().apply(ToolchainPlugin.class);\n\t}\n\n\tprivate void configureProhibitedDependencyChecks(Project project) {\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(SourceSetContainer.class);\n\t\tsourceSets.all((sourceSet) -> createProhibitedDependenciesChecks(project,\n\t\t\t\tsourceSet.getCompileClasspathConfigurationName(), sourceSet.getRuntimeClasspathConfigurationName()));\n\t}\n\n\tprivate void createProhibitedDependenciesChecks(Project project, String... configurationNames) {\n\t\tConfigurationContainer configurations = project.getConfigurations();\n\t\tfor (String configurationName : configurationNames) {\n\t\t\tConfiguration configuration = configurations.getByName(configurationName);\n\t\t\tcreateProhibitedDependenciesCheck(configuration, project);\n\t\t}\n\t}\n\n\tprivate void createProhibitedDependenciesCheck(Configuration classpath, Project project) {\n\t\tTaskProvider<CheckClasspathForProhibitedDependencies> checkClasspathForProhibitedDependencies = project\n\t\t\t.getTasks()\n\t\t\t.register(\"check\" + StringUtils.capitalize(classpath.getName() + \"ForProhibitedDependencies\"),\n\t\t\t\t\tCheckClasspathForProhibitedDependencies.class, (task) -> task.setClasspath(classpath));\n\t\tproject.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForProhibitedDependencies);\n\t}\n\n\tprivate void configureFactoriesFilesChecks(Project project) {\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();\n\t\tsourceSets.matching((sourceSet) -> SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName()))\n\t\t\t.configureEach((main) -> {\n\t\t\t\tTaskProvider<Task> check = project.getTasks().named(JavaBasePlugin.CHECK_TASK_NAME);\n\t\t\t\tTaskProvider<CheckAotFactories> checkAotFactories = project.getTasks()\n\t\t\t\t\t.register(\"checkAotFactories\", CheckAotFactories.class, (task) -> {\n\t\t\t\t\t\ttask.setSource(main.getResources());\n\t\t\t\t\t\ttask.setClasspath(main.getOutput().getClassesDirs());\n\t\t\t\t\t\ttask.setDescription(\"Checks the META-INF/spring/aot.factories file of the main source set.\");\n\t\t\t\t\t});\n\t\t\t\tcheck.configure((task) -> task.dependsOn(checkAotFactories));\n\t\t\t\tTaskProvider<CheckSpringFactories> checkSpringFactories = project.getTasks()\n\t\t\t\t\t.register(\"checkSpringFactories\", CheckSpringFactories.class, (task) -> {\n\t\t\t\t\t\ttask.setSource(main.getResources());\n\t\t\t\t\t\ttask.setClasspath(main.getOutput().getClassesDirs());\n\t\t\t\t\t\ttask.setDescription(\"Checks the META-INF/spring.factories file of the main source set.\");\n\t\t\t\t\t});\n\t\t\t\tcheck.configure((task) -> task.dependsOn(checkSpringFactories));\n\t\t\t});\n\t}\n\n\tprivate void configureNullability(Project project) {\n\t\tproject.getPlugins().apply(NullabilityPlugin.class);\n\t\tNullabilityPluginExtension extension = project.getExtensions().getByType(NullabilityPluginExtension.class);\n\t\tString nullAwayVersion = (String) project.findProperty(\"nullAwayVersion\");\n\t\tif (nullAwayVersion != null) {\n\t\t\textension.getNullAwayVersion().set(nullAwayVersion);\n\t\t}\n\t\tString errorProneVersion = (String) project.findProperty(\"errorProneVersion\");\n\t\tif (errorProneVersion != null) {\n\t\t\textension.getErrorProneVersion().set(errorProneVersion);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/KotlinConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.net.URI;\n\nimport dev.detekt.gradle.Detekt;\nimport dev.detekt.gradle.extensions.DetektExtension;\nimport dev.detekt.gradle.plugin.DetektPlugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.jetbrains.dokka.gradle.DokkaExtension;\nimport org.jetbrains.dokka.gradle.formats.DokkaHtmlPlugin;\nimport org.jetbrains.kotlin.gradle.dsl.JvmTarget;\nimport org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions;\nimport org.jetbrains.kotlin.gradle.dsl.KotlinVersion;\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompile;\n\n/**\n * Conventions that are applied in the presence of the {@code org.jetbrains.kotlin.jvm}\n * plugin. When the plugin is applied:\n *\n * <ul>\n * <li>{@link KotlinCompile} tasks are configured to:\n * <ul>\n * <li>Use {@code apiVersion} and {@code languageVersion} 1.7.\n * <li>Use {@code jvmTarget} 17.\n * <li>Treat all warnings as errors\n * <li>Suppress version warnings\n * </ul>\n * <li>Detekt plugin is applied to perform static analysis of Kotlin code\n * </ul>\n *\n * <p/>\n *\n * @author Andy Wilkinson\n */\nclass KotlinConventions {\n\n\tprivate static final JvmTarget JVM_TARGET = JvmTarget.JVM_17;\n\n\tprivate static final KotlinVersion KOTLIN_VERSION = KotlinVersion.KOTLIN_2_2;\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withId(\"org.jetbrains.kotlin.jvm\", (plugin) -> {\n\t\t\tproject.getTasks().withType(KotlinCompile.class, this::configure);\n\t\t\tproject.getPlugins().withType(DokkaHtmlPlugin.class, (dokkaPlugin) -> configureDokka(project));\n\t\t\tconfigureDetekt(project);\n\t\t});\n\t}\n\n\tprivate void configure(KotlinCompile compile) {\n\t\tKotlinJvmCompilerOptions compilerOptions = compile.getCompilerOptions();\n\t\tcompilerOptions.getApiVersion().set(KOTLIN_VERSION);\n\t\tcompilerOptions.getLanguageVersion().set(KOTLIN_VERSION);\n\t\tcompilerOptions.getJvmTarget().set(JVM_TARGET);\n\t\tcompilerOptions.getAllWarningsAsErrors().set(true);\n\t\tcompilerOptions.getFreeCompilerArgs()\n\t\t\t.addAll(\"-Xsuppress-version-warnings\", \"-Xannotation-default-target=param-property\");\n\t}\n\n\tprivate void configureDokka(Project project) {\n\t\tDokkaExtension dokka = project.getExtensions().getByType(DokkaExtension.class);\n\t\tdokka.getDokkaSourceSets().configureEach((sourceSet) -> {\n\t\t\tif (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) {\n\t\t\t\tsourceSet.getSourceRoots().setFrom(project.file(\"src/main/kotlin\"));\n\t\t\t\tsourceSet.getClasspath()\n\t\t\t\t\t.from(project.getExtensions()\n\t\t\t\t\t\t.getByType(SourceSetContainer.class)\n\t\t\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME)\n\t\t\t\t\t\t.getOutput());\n\t\t\t\tsourceSet.getExternalDocumentationLinks().create(\"spring-boot-javadoc\", (link) -> {\n\t\t\t\t\tlink.getUrl().set(URI.create(\"https://docs.spring.io/spring-boot/api/java/\"));\n\t\t\t\t\tlink.getPackageListUrl()\n\t\t\t\t\t\t.set(URI.create(\"https://docs.spring.io/spring-boot/api/java/element-list\"));\n\t\t\t\t});\n\t\t\t\tsourceSet.getExternalDocumentationLinks().create(\"spring-framework-javadoc\", (link) -> {\n\t\t\t\t\tString url = \"https://docs.spring.io/spring-framework/docs/%s/javadoc-api/\"\n\t\t\t\t\t\t.formatted(project.property(\"springFrameworkVersion\"));\n\t\t\t\t\tlink.getUrl().set(URI.create(url));\n\t\t\t\t\tlink.getPackageListUrl().set(URI.create(url + \"/element-list\"));\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsourceSet.getSuppress().set(true);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void configureDetekt(Project project) {\n\t\tproject.getPlugins().apply(DetektPlugin.class);\n\t\tDetektExtension detekt = project.getExtensions().getByType(DetektExtension.class);\n\t\tdetekt.getConfig().setFrom(project.getRootProject().file(\"config/detekt/config.yml\"));\n\t\tproject.getTasks()\n\t\t\t.withType(Detekt.class)\n\t\t\t.configureEach((task) -> task.getJvmTarget().set(JVM_TARGET.getTarget()));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/MavenPublishingConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.publish.PublishingExtension;\nimport org.gradle.api.publish.VariantVersionMappingStrategy;\nimport org.gradle.api.publish.maven.MavenPom;\nimport org.gradle.api.publish.maven.MavenPomDeveloperSpec;\nimport org.gradle.api.publish.maven.MavenPomIssueManagement;\nimport org.gradle.api.publish.maven.MavenPomLicenseSpec;\nimport org.gradle.api.publish.maven.MavenPomOrganization;\nimport org.gradle.api.publish.maven.MavenPomScm;\nimport org.gradle.api.publish.maven.MavenPublication;\nimport org.gradle.api.publish.maven.plugins.MavenPublishPlugin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.build.properties.BuildProperties;\nimport org.springframework.boot.build.properties.BuildType;\n\n/**\n * Conventions that are applied in the presence of the {@link MavenPublishPlugin}. When\n * the plugin is applied:\n *\n * <ul>\n * <li>If the {@code deploymentRepository} property has been set, a\n * {@link MavenArtifactRepository Maven artifact repository} is configured to publish to\n * it.\n * <li>The poms of all {@link MavenPublication Maven publications} are customized to meet\n * Maven Central's requirements.\n * <li>If the {@link JavaPlugin Java plugin} has also been applied:\n * <ul>\n * <li>Creation of Javadoc and source jars is enabled.\n * <li>Publication metadata (poms and Gradle module metadata) is configured to use\n * resolved versions.\n * </ul>\n * </ul>\n *\n * @author Andy Wilkinson\n * @author Christoph Dreis\n * @author Mike Smithson\n */\nclass MavenPublishingConventions {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(MavenPublishingConventions.class);\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withType(MavenPublishPlugin.class).all((mavenPublish) -> {\n\t\t\tPublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);\n\t\t\tif (project.hasProperty(\"deploymentRepository\")) {\n\t\t\t\tpublishing.getRepositories().maven((mavenRepository) -> {\n\t\t\t\t\tmavenRepository.setUrl(project.property(\"deploymentRepository\"));\n\t\t\t\t\tmavenRepository.setName(\"deployment\");\n\t\t\t\t});\n\t\t\t}\n\t\t\tpublishing.getPublications()\n\t\t\t\t.withType(MavenPublication.class)\n\t\t\t\t.all((mavenPublication) -> customizeMavenPublication(mavenPublication, project));\n\t\t\tproject.getPlugins().withType(JavaPlugin.class).all((javaPlugin) -> {\n\t\t\t\tJavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\t\t\textension.withJavadocJar();\n\t\t\t\textension.withSourcesJar();\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate void customizeMavenPublication(MavenPublication publication, Project project) {\n\t\tcustomizePom(publication.getPom(), project);\n\t\tproject.getPlugins()\n\t\t\t.withType(JavaPlugin.class)\n\t\t\t.all((javaPlugin) -> customizeJavaMavenPublication(publication, project));\n\t}\n\n\tprivate void customizePom(MavenPom pom, Project project) {\n\t\tpom.getUrl().set(\"https://spring.io/projects/spring-boot\");\n\t\tpom.getName().set(project.provider(project::getName));\n\t\tpom.getDescription().set(project.provider(project::getDescription));\n\t\tif (!isUserInherited(project)) {\n\t\t\tpom.organization(this::customizeOrganization);\n\t\t}\n\t\tpom.licenses(this::customizeLicences);\n\t\tpom.developers(this::customizeDevelopers);\n\t\tpom.scm((scm) -> customizeScm(scm, project));\n\t\tpom.issueManagement((issueManagement) -> customizeIssueManagement(issueManagement, project));\n\t}\n\n\tprivate void customizeJavaMavenPublication(MavenPublication publication, Project project) {\n\t\tpublication.versionMapping((strategy) -> strategy.usage(Usage.JAVA_API, (mappingStrategy) -> mappingStrategy\n\t\t\t.fromResolutionOf(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)));\n\t\tpublication.versionMapping(\n\t\t\t\t(strategy) -> strategy.usage(Usage.JAVA_RUNTIME, VariantVersionMappingStrategy::fromResolutionResult));\n\t}\n\n\tprivate void customizeOrganization(MavenPomOrganization organization) {\n\t\torganization.getName().set(\"VMware, Inc.\");\n\t\torganization.getUrl().set(\"https://spring.io\");\n\t}\n\n\tprivate void customizeLicences(MavenPomLicenseSpec licences) {\n\t\tlicences.license((licence) -> {\n\t\t\tlicence.getName().set(\"Apache License, Version 2.0\");\n\t\t\tlicence.getUrl().set(\"https://www.apache.org/licenses/LICENSE-2.0\");\n\t\t});\n\t}\n\n\tprivate void customizeDevelopers(MavenPomDeveloperSpec developers) {\n\t\tdevelopers.developer((developer) -> {\n\t\t\tdeveloper.getName().set(\"Spring\");\n\t\t\tdeveloper.getEmail().set(\"ask@spring.io\");\n\t\t\tdeveloper.getOrganization().set(\"VMware, Inc.\");\n\t\t\tdeveloper.getOrganizationUrl().set(\"https://www.spring.io\");\n\t\t});\n\t}\n\n\tprivate void customizeScm(MavenPomScm scm, Project project) {\n\t\tif (BuildProperties.get(project).buildType() != BuildType.OPEN_SOURCE) {\n\t\t\tlogger.debug(\"Skipping Maven POM SCM for non open source build type\");\n\t\t\treturn;\n\t\t}\n\t\tscm.getUrl().set(\"https://github.com/spring-projects/spring-boot\");\n\t\tif (!isUserInherited(project)) {\n\t\t\tscm.getConnection().set(\"scm:git:git://github.com/spring-projects/spring-boot.git\");\n\t\t\tscm.getDeveloperConnection().set(\"scm:git:ssh://git@github.com/spring-projects/spring-boot.git\");\n\t\t}\n\t}\n\n\tprivate void customizeIssueManagement(MavenPomIssueManagement issueManagement, Project project) {\n\t\tif (BuildProperties.get(project).buildType() != BuildType.OPEN_SOURCE) {\n\t\t\tlogger.debug(\"Skipping Maven POM SCM for non open source build type\");\n\t\t\treturn;\n\t\t}\n\t\tif (!isUserInherited(project)) {\n\t\t\tissueManagement.getSystem().set(\"GitHub\");\n\t\t\tissueManagement.getUrl().set(\"https://github.com/spring-projects/spring-boot/issues\");\n\t\t}\n\t}\n\n\tprivate boolean isUserInherited(Project project) {\n\t\treturn \"spring-boot-starter-parent\".equals(project.getName())\n\t\t\t\t|| \"spring-boot-dependencies\".equals(project.getName());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/MavenRepositoryPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.io.File;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.artifacts.DependencySet;\nimport org.gradle.api.artifacts.ModuleDependency;\nimport org.gradle.api.artifacts.ProjectDependency;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.plugins.JavaLibraryPlugin;\nimport org.gradle.api.plugins.JavaPlatformPlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.publish.PublishingExtension;\nimport org.gradle.api.publish.maven.plugins.MavenPublishPlugin;\n\nimport org.springframework.util.FileSystemUtils;\n\n/**\n * A plugin to make a project's {@code deployment} publication available as a Maven\n * repository. The repository can be consumed by depending upon the project using the\n * {@code mavenRepository} configuration.\n *\n * @author Andy Wilkinson\n */\npublic class MavenRepositoryPlugin implements Plugin<Project> {\n\n\t/**\n\t * Name of the {@code mavenRepository} configuration.\n\t */\n\tpublic static final String MAVEN_REPOSITORY_CONFIGURATION_NAME = \"mavenRepository\";\n\n\t/**\n\t * Name of the task that publishes to the project repository.\n\t */\n\tpublic static final String PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME = \"publishMavenPublicationToProjectRepository\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().apply(MavenPublishPlugin.class);\n\t\tPublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);\n\t\tFile repositoryLocation = project.getLayout().getBuildDirectory().dir(\"maven-repository\").get().getAsFile();\n\t\tpublishing.getRepositories().maven((mavenRepository) -> {\n\t\t\tmavenRepository.setName(\"project\");\n\t\t\tmavenRepository.setUrl(repositoryLocation.toURI());\n\t\t});\n\t\tproject.getTasks()\n\t\t\t.matching((task) -> task.getName().equals(PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME))\n\t\t\t.all((task) -> setUpProjectRepository(project, task, repositoryLocation));\n\t\tproject.getTasks()\n\t\t\t.matching((task) -> task.getName().equals(\"publishPluginMavenPublicationToProjectRepository\"))\n\t\t\t.all((task) -> setUpProjectRepository(project, task, repositoryLocation));\n\t}\n\n\tprivate void setUpProjectRepository(Project project, Task publishTask, File repositoryLocation) {\n\t\tpublishTask.doFirst(new CleanAction(repositoryLocation));\n\t\tConfiguration projectRepository = project.getConfigurations().create(MAVEN_REPOSITORY_CONFIGURATION_NAME);\n\t\tproject.getArtifacts()\n\t\t\t.add(projectRepository.getName(), repositoryLocation, (artifact) -> artifact.builtBy(publishTask));\n\t\tDependencySet target = projectRepository.getDependencies();\n\t\tproject.getPlugins()\n\t\t\t.withType(JavaPlugin.class)\n\t\t\t.all((javaPlugin) -> addMavenRepositoryProjectDependencies(project,\n\t\t\t\t\tJavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, target));\n\t\tproject.getPlugins()\n\t\t\t.withType(JavaLibraryPlugin.class)\n\t\t\t.all((javaLibraryPlugin) -> addMavenRepositoryProjectDependencies(project,\n\t\t\t\t\tJavaPlugin.API_CONFIGURATION_NAME, target));\n\t\tproject.getPlugins().withType(JavaPlatformPlugin.class).all((javaPlugin) -> {\n\t\t\taddMavenRepositoryProjectDependencies(project, JavaPlatformPlugin.API_CONFIGURATION_NAME, target);\n\t\t\taddMavenRepositoryPlatformDependencies(project, JavaPlatformPlugin.API_CONFIGURATION_NAME, target);\n\t\t});\n\t}\n\n\tprivate void addMavenRepositoryProjectDependencies(Project project, String sourceConfigurationName,\n\t\t\tDependencySet target) {\n\t\tproject.getConfigurations()\n\t\t\t.getByName(sourceConfigurationName)\n\t\t\t.getDependencies()\n\t\t\t.withType(ProjectDependency.class)\n\t\t\t.all((dependency) -> {\n\t\t\t\tProjectDependency copy = dependency.copy();\n\t\t\t\tif (copy.getAttributes().isEmpty()) {\n\t\t\t\t\tcopy.setTargetConfiguration(MAVEN_REPOSITORY_CONFIGURATION_NAME);\n\t\t\t\t}\n\t\t\t\ttarget.add(copy);\n\t\t\t});\n\t}\n\n\tprivate void addMavenRepositoryPlatformDependencies(Project project, String sourceConfigurationName,\n\t\t\tDependencySet target) {\n\t\tproject.getConfigurations()\n\t\t\t.getByName(sourceConfigurationName)\n\t\t\t.getDependencies()\n\t\t\t.withType(ModuleDependency.class)\n\t\t\t.matching((dependency) -> {\n\t\t\t\tCategory category = dependency.getAttributes().getAttribute(Category.CATEGORY_ATTRIBUTE);\n\t\t\t\treturn Category.REGULAR_PLATFORM.equals(category.getName());\n\t\t\t})\n\t\t\t.all((dependency) -> {\n\t\t\t\tDependency pom = project.getDependencies()\n\t\t\t\t\t.create(dependency.getGroup() + \":\" + dependency.getName() + \":\" + dependency.getVersion());\n\t\t\t\ttarget.add(pom);\n\t\t\t});\n\t}\n\n\tprivate static final class CleanAction implements Action<Task> {\n\n\t\tprivate final File location;\n\n\t\tprivate CleanAction(File location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\t@Override\n\t\tpublic void execute(Task task) {\n\t\t\tFileSystemUtils.deleteRecursively(this.location);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/NoHttpConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport io.spring.nohttp.gradle.NoHttpCheckstylePlugin;\nimport io.spring.nohttp.gradle.NoHttpExtension;\nimport org.gradle.api.Project;\nimport org.gradle.api.file.ConfigurableFileTree;\nimport org.gradle.api.plugins.quality.Checkstyle;\n\n/**\n * Conventions that are applied to enforce that no HTTP urls are used.\n *\n * @author Phillip Webb\n */\npublic class NoHttpConventions {\n\n\tvoid apply(Project project) {\n\t\tproject.getPluginManager().apply(NoHttpCheckstylePlugin.class);\n\t\tconfigureNoHttpExtension(project, project.getExtensions().getByType(NoHttpExtension.class));\n\t\tproject.getTasks()\n\t\t\t.named(NoHttpCheckstylePlugin.CHECKSTYLE_NOHTTP_TASK_NAME, Checkstyle.class)\n\t\t\t.configure((task) -> task.getConfigDirectory().set(project.getRootProject().file(\"config/nohttp\")));\n\t}\n\n\tprivate void configureNoHttpExtension(Project project, NoHttpExtension extension) {\n\t\textension.setAllowlistFile(project.getRootProject().file(\"config/nohttp/allowlist.lines\"));\n\t\tConfigurableFileTree source = extension.getSource();\n\t\tsource.exclude(\"bin/**\");\n\t\tsource.exclude(\"build/**\");\n\t\tsource.exclude(\"out/**\");\n\t\tsource.exclude(\"target/**\");\n\t\tsource.exclude(\".settings/**\");\n\t\tsource.exclude(\".classpath\");\n\t\tsource.exclude(\".project\");\n\t\tsource.exclude(\".gradle\");\n\t\tsource.exclude(\"**/docker/export.tar\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/RepositoryTransformersExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.Transformer;\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\n\n/**\n * Extension to add {@code springRepositoryTransformers} utility methods.\n *\n * @author Phillip Webb\n */\npublic class RepositoryTransformersExtension {\n\n\tprivate static final String CREDENTIALS_MARKER = \"{spring.mavenCredentials}\";\n\n\tprivate static final String REPOSITORIES_MARKER = \"{spring.mavenRepositories}\";\n\n\tprivate final Project project;\n\n\t@Inject\n\tpublic RepositoryTransformersExtension(Project project) {\n\t\tthis.project = project;\n\t}\n\n\tpublic Transformer<String, String> ant() {\n\t\treturn this::transformAnt;\n\t}\n\n\tprivate String transformAnt(String line) {\n\t\tif (line.contains(REPOSITORIES_MARKER)) {\n\t\t\treturn transform(line, (repository, indent) -> {\n\t\t\t\tString name = repository.getName();\n\t\t\t\tURI url = repository.getUrl();\n\t\t\t\treturn \"%s<ibiblio name=\\\"%s\\\" m2compatible=\\\"true\\\" root=\\\"%s\\\" />\".formatted(indent, name, url);\n\t\t\t});\n\t\t}\n\t\tif (line.contains(CREDENTIALS_MARKER)) {\n\t\t\tMap<String, MavenCredential> hostCredentials = new LinkedHashMap<>();\n\t\t\tgetSpringRepositories().forEach((repository) -> {\n\t\t\t\tif (repository.getName().startsWith(\"spring-commercial-\")) {\n\t\t\t\t\tString host = repository.getUrl().getHost();\n\t\t\t\t\thostCredentials.put(host,\n\t\t\t\t\t\t\tnew MavenCredential(\"${env.COMMERCIAL_REPO_USERNAME}\", \"${env.COMMERCIAL_REPO_PASSWORD\"));\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn transform(line, hostCredentials.entrySet(), (entry,\n\t\t\t\t\tindent) -> \"%s<credentials host=\\\"%s\\\" realm=\\\"Artifactory Realm\\\" username=\\\"%s\\\" passwd=\\\"%s\\\" />%n\"\n\t\t\t\t\t\t.formatted(indent, entry.getKey(), entry.getValue().username(), entry.getValue().password()));\n\t\t}\n\t\treturn line;\n\t}\n\n\tprivate String transformMavenRepositories(String line, boolean pluginRepository) {\n\t\treturn transform(line, (repository, indent) -> mavenRepositoryXml(indent, repository, pluginRepository));\n\t}\n\n\tprivate String mavenRepositoryXml(String indent, MavenArtifactRepository repository, boolean pluginRepository) {\n\t\tString rootTag = pluginRepository ? \"pluginRepository\" : \"repository\";\n\t\tboolean snapshots = repository.getName().endsWith(\"-snapshot\");\n\t\tStringBuilder xml = new StringBuilder();\n\t\txml.append(\"%s<%s>%n\".formatted(indent, rootTag));\n\t\txml.append(\"%s\\t<id>%s</id>%n\".formatted(indent, repository.getName()));\n\t\txml.append(\"%s\\t<url>%s</url>%n\".formatted(indent, repository.getUrl()));\n\t\txml.append(\"%s\\t<releases>%n\".formatted(indent));\n\t\txml.append(\"%s\\t\\t<enabled>%s</enabled>%n\".formatted(indent, !snapshots));\n\t\txml.append(\"%s\\t</releases>%n\".formatted(indent));\n\t\txml.append(\"%s\\t<snapshots>%n\".formatted(indent));\n\t\txml.append(\"%s\\t\\t<enabled>%s</enabled>%n\".formatted(indent, snapshots));\n\t\txml.append(\"%s\\t</snapshots>%n\".formatted(indent));\n\t\txml.append(\"%s</%s>\".formatted(indent, rootTag));\n\t\treturn xml.toString();\n\t}\n\n\tprivate String transform(String line, BiFunction<MavenArtifactRepository, String, String> generator) {\n\t\treturn transform(line, getSpringRepositories(), generator);\n\t}\n\n\tprivate <T> String transform(String line, Iterable<T> iterable, BiFunction<T, String, String> generator) {\n\t\tStringBuilder result = new StringBuilder();\n\t\tString indent = getIndent(line);\n\t\titerable.forEach((item) -> {\n\t\t\tString fragment = generator.apply(item, indent);\n\t\t\tif (fragment != null) {\n\t\t\t\tresult.append(!result.isEmpty() ? \"\\n\" : \"\");\n\t\t\t\tresult.append(fragment);\n\t\t\t}\n\t\t});\n\t\treturn result.toString();\n\t}\n\n\tprivate List<MavenArtifactRepository> getSpringRepositories() {\n\t\tList<MavenArtifactRepository> springRepositories = new ArrayList<>(this.project.getRepositories()\n\t\t\t.withType(MavenArtifactRepository.class)\n\t\t\t.stream()\n\t\t\t.filter(this::isSpringRepository)\n\t\t\t.toList());\n\t\tFunction<MavenArtifactRepository, Boolean> bySnapshots = (repository) -> repository.getName()\n\t\t\t.contains(\"snapshot\");\n\t\tFunction<MavenArtifactRepository, String> byName = MavenArtifactRepository::getName;\n\t\tCollections.sort(springRepositories, Comparator.comparing(bySnapshots).thenComparing(byName));\n\t\treturn springRepositories;\n\t}\n\n\tprivate boolean isSpringRepository(MavenArtifactRepository repository) {\n\t\treturn (repository.getName().startsWith(\"spring-\"));\n\t}\n\n\tprivate String getIndent(String line) {\n\t\treturn line.substring(0, line.length() - line.stripLeading().length());\n\t}\n\n\tstatic void apply(Project project) {\n\t\tproject.getExtensions().create(\"springRepositoryTransformers\", RepositoryTransformersExtension.class, project);\n\t}\n\n\trecord MavenCredential(String username, String password) {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/SyncAppSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileSystemOperations;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputDirectory;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * Tasks for syncing the source code of a Spring Boot application, filtering its\n * {@code build.gradle} to set the version of its {@code org.springframework.boot} plugin.\n *\n * @author Andy Wilkinson\n */\npublic abstract class SyncAppSource extends DefaultTask {\n\n\tprivate final FileSystemOperations fileSystemOperations;\n\n\t@Inject\n\tpublic SyncAppSource(FileSystemOperations fileSystemOperations) {\n\t\tgetPluginVersion().convention(getProject().provider(() -> getProject().getVersion().toString()));\n\t\tthis.fileSystemOperations = fileSystemOperations;\n\t}\n\n\t@InputDirectory\n\tpublic abstract DirectoryProperty getSourceDirectory();\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getDestinationDirectory();\n\n\t@Input\n\tpublic abstract Property<String> getPluginVersion();\n\n\t@TaskAction\n\tvoid syncAppSources() {\n\t\tthis.fileSystemOperations.sync((copySpec) -> {\n\t\t\tcopySpec.from(getSourceDirectory());\n\t\t\tcopySpec.into(getDestinationDirectory());\n\t\t\tcopySpec.filter((line) -> line.replace(\"id \\\"org.springframework.boot\\\"\",\n\t\t\t\t\t\"id \\\"org.springframework.boot\\\" version \\\"\" + getPluginVersion().get() + \"\\\"\"));\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/SystemRequirementsExtension.java",
    "content": "/*\n * Copyright 2026 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.model.ObjectFactory;\n\n/**\n * DSL extension for configuring a project's system requirements.\n *\n * @author Andy Wilkinson\n */\npublic class SystemRequirementsExtension {\n\n\tprivate final JavaSpec javaSpec;\n\n\t@Inject\n\tpublic SystemRequirementsExtension(ObjectFactory objects) {\n\t\tthis.javaSpec = objects.newInstance(JavaSpec.class);\n\t}\n\n\tpublic void java(Action<JavaSpec> action) {\n\t\taction.execute(this.javaSpec);\n\t}\n\n\tpublic JavaSpec getJava() {\n\t\treturn this.javaSpec;\n\t}\n\n\tpublic abstract static class JavaSpec {\n\n\t\tprivate int version = 17;\n\n\t\tpublic int getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\tpublic void setVersion(int version) {\n\t\t\tthis.version = version;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/TestFixturesConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.component.AdhocComponentWithVariants;\nimport org.gradle.api.plugins.JavaTestFixturesPlugin;\n\n/**\n * Conventions that are applied in the presence of the {@link JavaTestFixturesPlugin}.\n * When the plugin is applied:\n *\n * <ul>\n * <li>Publishing of the test fixtures is disabled.\n * </ul>\n *\n * @author Andy Wilkinson\n */\nclass TestFixturesConventions {\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withType(JavaTestFixturesPlugin.class, (testFixtures) -> disablePublishing(project));\n\t}\n\n\tprivate void disablePublishing(Project project) {\n\t\tConfigurationContainer configurations = project.getConfigurations();\n\t\tAdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.getComponents()\n\t\t\t.getByName(\"java\");\n\t\tjavaComponent.withVariantsFromConfiguration(configurations.getByName(\"testFixturesApiElements\"),\n\t\t\t\t(variant) -> variant.skip());\n\t\tjavaComponent.withVariantsFromConfiguration(configurations.getByName(\"testFixturesRuntimeElements\"),\n\t\t\t\t(variant) -> variant.skip());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/WarConventions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.gradle.api.JavaVersion;\nimport org.gradle.api.Project;\nimport org.gradle.api.internal.IConventionAware;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.plugins.ide.eclipse.EclipseWtpPlugin;\nimport org.gradle.plugins.ide.eclipse.model.EclipseModel;\nimport org.gradle.plugins.ide.eclipse.model.Facet;\n\n/**\n * Conventions that are applied in the presence of the {WarPlugin}. When the plugin is\n * applied:\n * <ul>\n * <li>Update Eclipse WTP Plugin facets to use Servlet 5.0</li>\n * </ul>\n *\n * @author Phillip Webb\n */\npublic class WarConventions {\n\n\tvoid apply(Project project) {\n\t\tproject.getPlugins().withType(EclipseWtpPlugin.class, (wtp) -> {\n\t\t\tproject.getTasks().getByName(EclipseWtpPlugin.ECLIPSE_WTP_FACET_TASK_NAME).doFirst((task) -> {\n\t\t\t\tEclipseModel eclipseModel = project.getExtensions().getByType(EclipseModel.class);\n\t\t\t\t((IConventionAware) eclipseModel.getWtp().getFacet()).getConventionMapping()\n\t\t\t\t\t.map(\"facets\", () -> getFacets(project));\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate List<Facet> getFacets(Project project) {\n\t\tJavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility();\n\t\tList<Facet> facets = new ArrayList<>();\n\t\tfacets.add(new Facet(Facet.FacetType.fixed, \"jst.web\", null));\n\t\tfacets.add(new Facet(Facet.FacetType.installed, \"jst.web\", \"5.0\"));\n\t\tfacets.add(new Facet(Facet.FacetType.installed, \"jst.java\", javaVersion.toString()));\n\t\treturn facets;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/aggregation/Aggregate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.aggregation;\n\nimport org.gradle.api.Named;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.file.ConfigurableFileCollection;\nimport org.gradle.api.provider.Property;\n\n/**\n * An aggregate.\n *\n * @author Andy Wilkinson\n */\npublic interface Aggregate extends Named {\n\n\t/**\n\t * The {@link Category} used to select the variant that's included in the aggregate.\n\t * @return the category\n\t */\n\tProperty<String> getCategory();\n\n\t/**\n\t * The {@link Usage} used to select the variant that's included in the aggregate.\n\t * @return the usage\n\t */\n\tProperty<String> getUsage();\n\n\t/**\n\t * The aggregated files.\n\t * @return the aggregated files\n\t */\n\tConfigurableFileCollection getFiles();\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/aggregation/AggregatorPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.aggregation;\n\nimport org.gradle.api.NamedDomainObjectContainer;\nimport org.gradle.api.NamedDomainObjectProvider;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.DependencyScopeConfiguration;\nimport org.gradle.api.artifacts.ResolvableConfiguration;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.model.ObjectFactory;\n\n/**\n * {@link Plugin} for aggregating the output of other projects.\n *\n * @author Andy Wilkinson\n */\npublic class AggregatorPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project target) {\n\t\tNamedDomainObjectContainer<Aggregate> aggregates = target.getObjects().domainObjectContainer(Aggregate.class);\n\t\ttarget.getExtensions().add(\"aggregates\", aggregates);\n\t\taggregates.all((aggregate) -> {\n\t\t\tNamedDomainObjectProvider<DependencyScopeConfiguration> dependencies = target.getConfigurations()\n\t\t\t\t.dependencyScope(aggregate.getName() + \"Dependencies\");\n\t\t\tNamedDomainObjectProvider<ResolvableConfiguration> aggregated = target.getConfigurations()\n\t\t\t\t.resolvable(aggregate.getName(), (configuration) -> {\n\t\t\t\t\tconfiguration.extendsFrom(dependencies.get());\n\t\t\t\t\tconfigureAttributes(configuration, aggregate, target.getObjects());\n\t\t\t\t});\n\t\t\ttarget.getRootProject()\n\t\t\t\t.allprojects((project) -> target.getDependencies().add(dependencies.getName(), project));\n\t\t\taggregate.getFiles()\n\t\t\t\t.convention(aggregated.map((configuration) -> configuration.getIncoming()\n\t\t\t\t\t.artifactView((view) -> view.setLenient(true))\n\t\t\t\t\t.getFiles()));\n\t\t});\n\t}\n\n\tprivate void configureAttributes(Configuration configuration, Aggregate aggregate, ObjectFactory objects) {\n\t\tconfiguration.attributes((attributes) -> {\n\t\t\tattributes.attributeProvider(Category.CATEGORY_ATTRIBUTE,\n\t\t\t\t\taggregate.getCategory().map((category) -> objects.named(Category.class, category)));\n\t\t\tattributes.attributeProvider(Usage.USAGE_ATTRIBUTE,\n\t\t\t\t\taggregate.getUsage().map((usage) -> objects.named(Usage.class, usage)));\n\t\t});\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/AggregateContentContribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport org.gradle.api.Project;\n\n/**\n * A contribution of aggregate content.\n *\n * @author Andy Wilkinson\n */\nclass AggregateContentContribution extends ConsumableContentContribution {\n\n\tprotected AggregateContentContribution(Project project, String name) {\n\t\tsuper(project, \"aggregate\", name);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraAsciidocAttributes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.Project;\n\nimport org.springframework.boot.build.artifacts.ArtifactRelease;\nimport org.springframework.boot.build.bom.BomExtension;\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.ResolvedBom;\nimport org.springframework.boot.build.bom.ResolvedBom.Bom;\nimport org.springframework.boot.build.bom.ResolvedBom.Id;\nimport org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;\nimport org.springframework.boot.build.properties.BuildProperties;\nimport org.springframework.boot.build.properties.BuildType;\nimport org.springframework.util.Assert;\n\n/**\n * Generates Asciidoctor attributes for use with Antora.\n *\n * @author Phillip Webb\n */\npublic class AntoraAsciidocAttributes {\n\n\tprivate static final String DASH_SNAPSHOT = \"-SNAPSHOT\";\n\n\tprivate final String version;\n\n\tprivate final boolean latestVersion;\n\n\tprivate final BuildType buildType;\n\n\tprivate final ArtifactRelease artifactRelease;\n\n\tprivate final List<Library> libraries;\n\n\tprivate final Map<String, String> dependencyVersions;\n\n\tprivate final Map<String, ?> projectProperties;\n\n\tpublic AntoraAsciidocAttributes(Project project, BomExtension dependencyBom, ResolvedBom resolvedBom) {\n\t\tthis.version = String.valueOf(project.getVersion());\n\t\tthis.latestVersion = Boolean.parseBoolean(String.valueOf(project.findProperty(\"latestVersion\")));\n\t\tthis.buildType = BuildProperties.get(project).buildType();\n\t\tthis.artifactRelease = ArtifactRelease.forProject(project);\n\t\tthis.libraries = dependencyBom.getLibraries();\n\t\tthis.dependencyVersions = dependencyVersionsOf(resolvedBom);\n\t\tthis.projectProperties = project.getProperties();\n\t}\n\n\tprivate static Map<String, String> dependencyVersionsOf(ResolvedBom resolvedBom) {\n\t\tMap<String, String> dependencyVersions = new HashMap<>();\n\t\tfor (ResolvedLibrary library : resolvedBom.libraries()) {\n\t\t\tdependencyVersions.putAll(dependencyVersionsOf(library.managedDependencies()));\n\t\t\tfor (Bom importedBom : library.importedBoms()) {\n\t\t\t\tdependencyVersions.putAll(dependencyVersionsOf(importedBom));\n\t\t\t}\n\t\t}\n\t\treturn dependencyVersions;\n\t}\n\n\tprivate static Map<String, String> dependencyVersionsOf(Bom bom) {\n\t\tMap<String, String> dependencyVersions = new HashMap<>();\n\t\tif (bom != null) {\n\t\t\tdependencyVersions.putAll(dependencyVersionsOf(bom.managedDependencies()));\n\t\t\tdependencyVersions.putAll(dependencyVersionsOf(bom.parent()));\n\t\t\tfor (Bom importedBom : bom.importedBoms()) {\n\t\t\t\tdependencyVersions.putAll(dependencyVersionsOf(importedBom));\n\t\t\t}\n\t\t}\n\t\treturn dependencyVersions;\n\t}\n\n\tprivate static Map<String, String> dependencyVersionsOf(Collection<Id> managedDependencies) {\n\t\tMap<String, String> dependencyVersions = new HashMap<>();\n\t\tfor (Id managedDependency : managedDependencies) {\n\t\t\tdependencyVersions.put(managedDependency.groupId() + \":\" + managedDependency.artifactId(),\n\t\t\t\t\tmanagedDependency.version());\n\t\t}\n\t\treturn dependencyVersions;\n\t}\n\n\tAntoraAsciidocAttributes(String version, boolean latestVersion, BuildType buildType, List<Library> libraries,\n\t\t\tMap<String, String> dependencyVersions, Map<String, ?> projectProperties) {\n\t\tthis.version = version;\n\t\tthis.latestVersion = latestVersion;\n\t\tthis.buildType = buildType;\n\t\tthis.artifactRelease = ArtifactRelease.forVersion(version);\n\t\tthis.libraries = (libraries != null) ? libraries : Collections.emptyList();\n\t\tthis.dependencyVersions = (dependencyVersions != null) ? dependencyVersions : Collections.emptyMap();\n\t\tthis.projectProperties = (projectProperties != null) ? projectProperties : Collections.emptyMap();\n\t}\n\n\tpublic Map<String, String> get() {\n\t\tMap<String, String> attributes = new LinkedHashMap<>();\n\t\tMap<String, String> internal = new LinkedHashMap<>();\n\t\taddBuildTypeAttribute(attributes);\n\t\taddGitHubAttributes(attributes);\n\t\taddVersionAttributes(attributes, internal);\n\t\taddArtifactAttributes(attributes);\n\t\taddUrlJava(attributes);\n\t\taddUrlLibraryLinkAttributes(attributes);\n\t\taddPropertyAttributes(attributes, internal);\n\t\treturn attributes;\n\t}\n\n\tprivate void addBuildTypeAttribute(Map<String, String> attributes) {\n\t\tattributes.put(\"build-type\", this.buildType.toIdentifier());\n\t}\n\n\tprivate void addGitHubAttributes(Map<String, String> attributes) {\n\t\tattributes.put(\"github-repo\", \"spring-projects/spring-boot\");\n\t\tattributes.put(\"github-ref\", determineGitHubRef());\n\t}\n\n\tprivate String determineGitHubRef() {\n\t\tint snapshotIndex = this.version.lastIndexOf(DASH_SNAPSHOT);\n\t\tif (snapshotIndex == -1) {\n\t\t\treturn \"v\" + this.version;\n\t\t}\n\t\tif (this.latestVersion) {\n\t\t\treturn \"main\";\n\t\t}\n\t\tString versionRoot = this.version.substring(0, snapshotIndex);\n\t\tint lastDot = versionRoot.lastIndexOf('.');\n\t\treturn versionRoot.substring(0, lastDot) + \".x\";\n\t}\n\n\tprivate void addVersionAttributes(Map<String, String> attributes, Map<String, String> internal) {\n\t\tthis.libraries.forEach((library) -> {\n\t\t\tString name = \"version-\" + library.getLinkRootName();\n\t\t\tString value = library.getVersion().toString();\n\t\t\tattributes.put(name, value);\n\t\t});\n\t\tattributes.put(\"version-native-build-tools\", (String) this.projectProperties.get(\"nativeBuildToolsVersion\"));\n\t\tattributes.put(\"version-graal\", (String) this.projectProperties.get(\"graalVersion\"));\n\t\taddDependencyVersion(attributes, \"jackson-annotations\", \"com.fasterxml.jackson.core:jackson-annotations\");\n\t\taddDependencyVersion(attributes, \"jackson-core\", \"tools.jackson.core:jackson-core\");\n\t\taddDependencyVersion(attributes, \"jackson-databind\", \"tools.jackson.core:jackson-databind\");\n\t\taddDependencyVersion(attributes, \"jackson-dataformat-xml\", \"tools.jackson.dataformat:jackson-dataformat-xml\");\n\t\taddDependencyVersion(attributes, \"jackson2-databind\", \"com.fasterxml.jackson.core:jackson-databind\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-commons\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-couchbase\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-cassandra\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-elasticsearch\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-jdbc\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-jpa\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-mongodb\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-neo4j\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-r2dbc\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-redis\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-rest\", \"spring-data-rest-core\");\n\t\taddSpringDataDependencyVersion(attributes, internal, \"spring-data-ldap\");\n\t\taddDependencyVersion(attributes, \"pulsar-client-api\", \"org.apache.pulsar:pulsar-client-api\");\n\t}\n\n\tprivate void addSpringDataDependencyVersion(Map<String, String> attributes, Map<String, String> internal,\n\t\t\tString artifactId) {\n\t\taddSpringDataDependencyVersion(attributes, internal, artifactId, artifactId);\n\t}\n\n\tprivate void addSpringDataDependencyVersion(Map<String, String> attributes, Map<String, String> internal,\n\t\t\tString name, String artifactId) {\n\t\tString groupAndArtifactId = \"org.springframework.data:\" + artifactId;\n\t\taddDependencyVersion(attributes, name, groupAndArtifactId);\n\t\tString version = getVersion(groupAndArtifactId);\n\t\tString majorMinor = Arrays.stream(version.split(\"\\\\.\")).limit(2).collect(Collectors.joining(\".\"));\n\t\tString antoraVersion = version.endsWith(DASH_SNAPSHOT) ? majorMinor + DASH_SNAPSHOT : majorMinor;\n\t\tinternal.put(\"antoraversion-\" + name, antoraVersion);\n\t\tinternal.put(\"dotxversion-\" + name, majorMinor + \".x\");\n\t}\n\n\tprivate void addDependencyVersion(Map<String, String> attributes, String name, String groupAndArtifactId) {\n\t\tattributes.put(\"version-\" + name, getVersion(groupAndArtifactId));\n\t}\n\n\tprivate String getVersion(String groupAndArtifactId) {\n\t\tString version = this.dependencyVersions.get(groupAndArtifactId);\n\t\tAssert.notNull(version, () -> \"No version found for \" + groupAndArtifactId);\n\t\treturn version;\n\t}\n\n\tprivate void addArtifactAttributes(Map<String, String> attributes) {\n\t\tattributes.put(\"url-artifact-repository\", this.artifactRelease.getDownloadRepo());\n\t\tattributes.put(\"artifact-release-type\", this.artifactRelease.getType());\n\t\tattributes.put(\"build-and-artifact-release-type\",\n\t\t\t\tthis.buildType.toIdentifier() + \"-\" + this.artifactRelease.getType());\n\t}\n\n\tprivate void addUrlJava(Map<String, String> attributes) {\n\t\tattributes.put(\"url-javase-javadoc\", \"https://docs.oracle.com/en/java/javase/17/docs/api\");\n\t\tattributes.put(\"javadoc-location-java\", \"{url-javase-javadoc}/java.base\");\n\t\tattributes.put(\"javadoc-location-java-beans\", \"{url-javase-javadoc}/java.desktop\");\n\t\tattributes.put(\"javadoc-location-java-sql\", \"{url-javase-javadoc}/java.sql\");\n\t\tattributes.put(\"javadoc-location-javax\", \"{url-javase-javadoc}/java.base\");\n\t\tattributes.put(\"javadoc-location-javax-management\", \"{url-javase-javadoc}/java.management\");\n\t\tattributes.put(\"javadoc-location-javax-net\", \"{url-javase-javadoc}/java.base\");\n\t\tattributes.put(\"javadoc-location-javax-sql\", \"{url-javase-javadoc}/java.sql\");\n\t\tattributes.put(\"javadoc-location-javax-xml\", \"{url-javase-javadoc}/java.xml\");\n\t}\n\n\tprivate void addUrlLibraryLinkAttributes(Map<String, String> attributes) {\n\t\tMap<String, String> packageAttributes = new LinkedHashMap<>();\n\t\tthis.libraries.forEach((library) -> {\n\t\t\tlibrary.getLinks().forEach((name, links) -> links.forEach((link) -> {\n\t\t\t\tString linkRootName = (link.rootName() != null) ? link.rootName() : library.getLinkRootName();\n\t\t\t\tString linkName = \"url-\" + linkRootName + \"-\" + name;\n\t\t\t\tattributes.put(linkName, link.url(library));\n\t\t\t\tlink.packages()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map(this::packageAttributeName)\n\t\t\t\t\t.forEach((packageAttributeName) -> packageAttributes.put(packageAttributeName,\n\t\t\t\t\t\t\t\"{\" + linkName + \"}\"));\n\t\t\t}));\n\t\t});\n\t\tattributes.putAll(packageAttributes);\n\t}\n\n\tprivate String packageAttributeName(String packageName) {\n\t\treturn \"javadoc-location-\" + packageName.replace('.', '-');\n\t}\n\n\tprivate void addPropertyAttributes(Map<String, String> attributes, Map<String, String> internal) {\n\t\tProperties properties = new Properties() {\n\n\t\t\t@Override\n\t\t\tpublic synchronized Object put(Object key, Object value) {\n\t\t\t\t// Put directly because order is important for us\n\t\t\t\treturn attributes.put(key.toString(), resolve(value.toString(), internal));\n\t\t\t}\n\n\t\t};\n\t\ttry (InputStream in = getClass().getResourceAsStream(\"antora-asciidoc-attributes.properties\")) {\n\t\t\tproperties.load(in);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate String resolve(String value, Map<String, String> internal) {\n\t\tfor (Map.Entry<String, String> entry : internal.entrySet()) {\n\t\t\tvalue = value.replace(\"{\" + entry.getKey() + \"}\", entry.getValue());\n\t\t}\n\t\treturn value;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraContributorPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport javax.inject.Inject;\n\nimport org.antora.gradle.AntoraPlugin;\nimport org.gradle.api.Action;\nimport org.gradle.api.NamedDomainObjectContainer;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.file.CopySpec;\n\n/**\n * {@link Plugin} for a project that contributes to Antora-based documentation that is\n * {@link AntoraDependenciesPlugin depended upon} by another project.\n *\n * @author Andy Wilkinson\n */\npublic class AntoraContributorPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().apply(AntoraPlugin.class);\n\t\tNamedDomainObjectContainer<Contribution> antoraContributions = project.getObjects()\n\t\t\t.domainObjectContainer(Contribution.class,\n\t\t\t\t\t(name) -> project.getObjects().newInstance(Contribution.class, name, project));\n\t\tproject.getExtensions().add(\"antoraContributions\", antoraContributions);\n\t}\n\n\tpublic static class Contribution {\n\n\t\tprivate final String name;\n\n\t\tprivate final Project project;\n\n\t\tprivate boolean publish;\n\n\t\t@Inject\n\t\tpublic Contribution(String name, Project project) {\n\t\t\tthis.name = name;\n\t\t\tthis.project = project;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void publish() {\n\t\t\tthis.publish = true;\n\t\t}\n\n\t\tpublic void source() {\n\t\t\tnew SourceContribution(this.project, this.name).produce();\n\t\t}\n\n\t\tpublic void catalogContent(Action<CopySpec> action) {\n\t\t\tCopySpec copySpec = this.project.copySpec();\n\t\t\taction.execute(copySpec);\n\t\t\tnew CatalogContentContribution(this.project, this.name).produceFrom(copySpec, this.publish);\n\t\t}\n\n\t\tpublic void aggregateContent(Action<CopySpec> action) {\n\t\t\tCopySpec copySpec = this.project.copySpec();\n\t\t\taction.execute(copySpec);\n\t\t\tnew AggregateContentContribution(this.project, this.name).produceFrom(copySpec, this.publish);\n\t\t}\n\n\t\tpublic void localAggregateContent(Action<CopySpec> action) {\n\t\t\tCopySpec copySpec = this.project.copySpec();\n\t\t\taction.execute(copySpec);\n\t\t\tnew LocalAggregateContentContribution(this.project, this.name).produceFrom(copySpec);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/AntoraDependenciesPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.NamedDomainObjectContainer;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\n\n/**\n * {@link Plugin} for a project that depends on {@link AntoraContributorPlugin\n * contributed} Antora-based documentation.\n *\n * @author Andy Wilkinson\n */\npublic class AntoraDependenciesPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tNamedDomainObjectContainer<AntoraDependency> antoraDependencies = project.getObjects()\n\t\t\t.domainObjectContainer(AntoraDependency.class);\n\t\tproject.getExtensions().add(\"antoraDependencies\", antoraDependencies);\n\t}\n\n\tpublic static class AntoraDependency {\n\n\t\tprivate final String name;\n\n\t\tprivate final Project project;\n\n\t\tprivate String path;\n\n\t\t@Inject\n\t\tpublic AntoraDependency(String name, Project project) {\n\t\t\tthis.name = name;\n\t\t\tthis.project = project;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getPath() {\n\t\t\treturn this.path;\n\t\t}\n\n\t\tpublic void setPath(String path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tpublic void catalogContent() {\n\t\t\tnew CatalogContentContribution(this.project, this.name).consumeFrom(this.path);\n\t\t}\n\n\t\tpublic void aggregateContent() {\n\t\t\tnew AggregateContentContribution(this.project, this.name).consumeFrom(this.path);\n\t\t}\n\n\t\tpublic void source() {\n\t\t\tnew SourceContribution(this.project, this.name).consumeFrom(this.path);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/CatalogContentContribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport org.gradle.api.Project;\n\n/**\n * A contribution of catalog content.\n *\n * @author Andy Wilkinson\n */\nclass CatalogContentContribution extends ConsumableContentContribution {\n\n\tCatalogContentContribution(Project project, String name) {\n\t\tsuper(project, \"catalog\", name);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/CheckJavadocMacros.java",
    "content": "/*\n * Copyright 2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\nimport java.util.zip.ZipEntry;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\nimport org.springframework.asm.ClassReader;\nimport org.springframework.asm.ClassVisitor;\nimport org.springframework.asm.FieldVisitor;\nimport org.springframework.asm.MethodVisitor;\nimport org.springframework.asm.SpringAsmInfo;\nimport org.springframework.asm.Type;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * A task to check {@code javadoc:[]} macros in Antora source files.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckJavadocMacros extends DefaultTask {\n\n\tprivate static final Pattern JAVADOC_MACRO_PATTERN = Pattern.compile(\"javadoc:(.*?)\\\\[(.*?)\\\\]\");\n\n\tprivate final Path projectRoot;\n\n\tprivate FileCollection source;\n\n\tprivate FileCollection classpath;\n\n\tpublic CheckJavadocMacros() {\n\t\tthis.projectRoot = getProject().getRootDir().toPath();\n\t}\n\n\t@InputFiles\n\tpublic FileCollection getSource() {\n\t\treturn this.source;\n\t}\n\n\tpublic void setSource(FileCollection source) {\n\t\tthis.source = source;\n\t}\n\n\t@Optional\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(FileCollection classpath) {\n\t\tthis.classpath = classpath;\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@TaskAction\n\tvoid checkJavadocMacros() {\n\t\tSet<String> availableClasses = indexClasspath();\n\t\tList<String> problems = new ArrayList<>();\n\t\tthis.source.getAsFileTree()\n\t\t\t.filter((file) -> file.getName().endsWith(\".adoc\"))\n\t\t\t.forEach((file) -> problems.addAll(checkJavadocMacros(file, availableClasses)));\n\t\tFile outputFile = getOutputDirectory().file(\"failure-report.txt\").get().getAsFile();\n\t\twriteReport(problems, outputFile);\n\t\tif (!problems.isEmpty()) {\n\t\t\tthrow new VerificationException(\"Javadoc macro check failed. See '%s' for details\".formatted(outputFile));\n\t\t}\n\t}\n\n\tprivate Set<String> indexClasspath() {\n\t\tSet<String> availableClasses = StreamSupport.stream(this.classpath.spliterator(), false).flatMap((root) -> {\n\t\t\tif (root.isFile()) {\n\t\t\t\ttry (JarFile jar = new JarFile(root)) {\n\t\t\t\t\treturn jar.stream()\n\t\t\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t\t\t.filter((entryName) -> entryName.endsWith(\".class\"))\n\t\t\t\t\t\t.map((className) -> {\n\t\t\t\t\t\t\tif (className.startsWith(\"META-INF/versions/\")) {\n\t\t\t\t\t\t\t\tclassName = className.substring(\"META-INF/versions/\".length());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tclassName = className.substring(0, className.length() - \".class\".length());\n\t\t\t\t\t\t\tclassName = className.replace('/', '.');\n\t\t\t\t\t\t\treturn className;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.toList()\n\t\t\t\t\t\t.stream();\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Stream.empty();\n\t\t}).collect(Collectors.toSet());\n\t\treturn availableClasses;\n\t}\n\n\tprivate List<String> checkJavadocMacros(File adocFile, Set<String> availableClasses) {\n\t\tList<String> problems = new ArrayList<>();\n\t\tList<JavadocMacro> macros = JavadocMacro.parse(adocFile);\n\t\tfor (JavadocMacro macro : macros) {\n\t\t\tif (!classIsAvailable(macro.className.name, availableClasses)) {\n\t\t\t\tproblems.add(this.projectRoot.relativize(macro.className.origin.file.toPath()) + \":\"\n\t\t\t\t\t\t+ macro.className.origin.line + \":\" + macro.className.origin.column + \": class \"\n\t\t\t\t\t\t+ macro.className.name + \" does not exist.\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tJavadocAnchor anchor = macro.anchor;\n\t\t\t\tif (anchor != null) {\n\t\t\t\t\tif (anchor instanceof MethodAnchor methodAnchor) {\n\t\t\t\t\t\tMethodMatcher methodMatcher = new MethodMatcher(methodAnchor);\n\t\t\t\t\t\tinputStreamOf(macro.className.name, (stream) -> {\n\t\t\t\t\t\t\tClassReader reader = new ClassReader(stream);\n\t\t\t\t\t\t\treader.accept(methodMatcher, 0);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!methodMatcher.matched) {\n\t\t\t\t\t\t\tproblems.add(this.projectRoot.relativize(macro.anchor.origin.file.toPath()) + \":\"\n\t\t\t\t\t\t\t\t\t+ macro.anchor.origin.line + \":\" + methodAnchor.origin().column + \": method \"\n\t\t\t\t\t\t\t\t\t+ methodAnchor + \" does not exist\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (anchor instanceof FieldAnchor fieldAnchor) {\n\t\t\t\t\t\tFieldMatcher fieldMatcher = new FieldMatcher(fieldAnchor);\n\t\t\t\t\t\tinputStreamOf(macro.className.name, (stream) -> {\n\t\t\t\t\t\t\tClassReader reader = new ClassReader(stream);\n\t\t\t\t\t\t\treader.accept(fieldMatcher, 0);\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!fieldMatcher.matched) {\n\t\t\t\t\t\t\tproblems.add(this.projectRoot.relativize(macro.anchor.origin.file.toPath()) + \":\"\n\t\t\t\t\t\t\t\t\t+ macro.anchor.origin.line + \":\" + fieldAnchor.origin().column + \": field \"\n\t\t\t\t\t\t\t\t\t+ fieldAnchor.name + \" does not exist\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn problems;\n\t}\n\n\tprivate boolean classIsAvailable(String className, Set<String> availableClasses) {\n\t\tif (availableClasses.contains(className)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (className.startsWith(\"java.\") || className.startsWith(\"javax.\")) {\n\t\t\treturn jdkResourceForClass(className) != null;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate URL jdkResourceForClass(String className) {\n\t\treturn getClass().getClassLoader().getResource(className.replace(\".\", \"/\") + \".class\");\n\t}\n\n\tprivate void inputStreamOf(String className, ThrowingConsumer<InputStream> streamHandler) {\n\t\tfor (File root : this.classpath) {\n\t\t\tif (root.isFile()) {\n\t\t\t\ttry (JarFile jar = new JarFile(root)) {\n\t\t\t\t\tZipEntry entry = jar.getEntry(className.replace(\".\", \"/\") + \".class\");\n\t\t\t\t\tif (entry != null) {\n\t\t\t\t\t\ttry (InputStream stream = jar.getInputStream(entry)) {\n\t\t\t\t\t\t\tstreamHandler.accept(stream);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tURL resource = jdkResourceForClass(className);\n\t\tif (resource != null) {\n\t\t\ttry (InputStream stream = resource.openStream()) {\n\t\t\t\tstreamHandler.accept(stream);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void writeReport(List<String> problems, File outputFile) {\n\t\toutputFile.getParentFile().mkdirs();\n\t\tStringBuilder report = new StringBuilder();\n\t\tif (!problems.isEmpty()) {\n\t\t\tif (problems.size() == 1) {\n\t\t\t\treport.append(\"Found 1 javadoc macro problem:%n\".formatted());\n\t\t\t}\n\t\t\telse {\n\t\t\t\treport.append(\"Found %d javadoc macro problems:%n\".formatted(problems.size()));\n\t\t\t}\n\t\t\tproblems.forEach((problem) -> report.append(\"%s%n\".formatted(problem)));\n\t\t}\n\t\ttry {\n\t\t\tFiles.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,\n\t\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate static final class JavadocMacro {\n\n\t\tprivate final ClassName className;\n\n\t\tprivate final JavadocAnchor anchor;\n\n\t\tprivate JavadocMacro(ClassName className, JavadocAnchor anchor) {\n\t\t\tthis.className = className;\n\t\t\tthis.anchor = anchor;\n\t\t}\n\n\t\tprivate static List<JavadocMacro> parse(File adocFile) {\n\t\t\tList<JavadocMacro> macros = new ArrayList<>();\n\t\t\ttry {\n\t\t\t\tPath adocFilePath = adocFile.toPath();\n\t\t\t\tList<String> lines = Files.readAllLines(adocFilePath);\n\t\t\t\tfor (int i = 0; i < lines.size(); i++) {\n\t\t\t\t\tMatcher matcher = JAVADOC_MACRO_PATTERN.matcher(lines.get(i));\n\t\t\t\t\twhile (matcher.find()) {\n\t\t\t\t\t\tOrigin classNameOrigin = new Origin(adocFile, i + 1, matcher.start(1) + 1);\n\t\t\t\t\t\tString target = matcher.group(1);\n\t\t\t\t\t\tString className = target;\n\t\t\t\t\t\tint endOfUrlAttribute = className.indexOf(\"}/\");\n\t\t\t\t\t\tif (endOfUrlAttribute != -1) {\n\t\t\t\t\t\t\tclassName = className.substring(endOfUrlAttribute + 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJavadocAnchor anchor = null;\n\t\t\t\t\t\tint anchorIndex = className.indexOf(\"#\");\n\t\t\t\t\t\tif (anchorIndex != -1) {\n\t\t\t\t\t\t\tanchor = JavadocAnchor.of(className.substring(anchorIndex + 1), new Origin(adocFile,\n\t\t\t\t\t\t\t\t\tclassNameOrigin.line(), classNameOrigin.column + anchorIndex + 1));\n\t\t\t\t\t\t\tclassName = className.substring(0, anchorIndex);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmacros.add(new JavadocMacro(new ClassName(classNameOrigin, className), anchor));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t\treturn macros;\n\t\t}\n\n\t}\n\n\tprivate static final class ClassName {\n\n\t\tprivate final Origin origin;\n\n\t\tprivate final String name;\n\n\t\tprivate ClassName(Origin origin, String name) {\n\t\t\tthis.origin = origin;\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\tprivate record Origin(File file, int line, int column) {\n\n\t}\n\n\tprivate abstract static class JavadocAnchor {\n\n\t\tprivate final Origin origin;\n\n\t\tprotected JavadocAnchor(Origin origin) {\n\t\t\tthis.origin = origin;\n\t\t}\n\n\t\tOrigin origin() {\n\t\t\treturn this.origin;\n\t\t}\n\n\t\tprivate static JavadocAnchor of(String anchor, Origin origin) {\n\t\t\tJavadocAnchor javadocAnchor = WellKnownAnchor.of(anchor, origin);\n\t\t\tif (javadocAnchor == null) {\n\t\t\t\tjavadocAnchor = MethodAnchor.of(anchor, origin);\n\t\t\t}\n\t\t\tif (javadocAnchor == null) {\n\t\t\t\tjavadocAnchor = FieldAnchor.of(anchor, origin);\n\t\t\t}\n\t\t\treturn javadocAnchor;\n\t\t}\n\n\t}\n\n\tprivate static final class WellKnownAnchor extends JavadocAnchor {\n\n\t\tprivate WellKnownAnchor(Origin origin) {\n\t\t\tsuper(origin);\n\t\t}\n\n\t\tprivate static WellKnownAnchor of(String anchor, Origin origin) {\n\t\t\tif (anchor.equals(\"enum-constant-summary\")) {\n\t\t\t\treturn new WellKnownAnchor(origin);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate static final class MethodAnchor extends JavadocAnchor {\n\n\t\tprivate final String name;\n\n\t\tprivate final List<String> arguments;\n\n\t\tprivate MethodAnchor(String name, List<String> arguments, Origin origin) {\n\t\t\tsuper(origin);\n\t\t\tthis.name = name;\n\t\t\tthis.arguments = arguments;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name + \"(\" + String.join(\", \", this.arguments + \")\");\n\t\t}\n\n\t\tstatic MethodAnchor of(String anchor, Origin origin) {\n\t\t\tif (!anchor.contains(\"(\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tint openingIndex = anchor.indexOf('(');\n\t\t\tString name = anchor.substring(0, openingIndex);\n\t\t\tList<String> arguments = Stream.of(anchor.substring(openingIndex + 1, anchor.length() - 1).split(\",\"))\n\t\t\t\t.map(String::trim)\n\t\t\t\t.map((argument) -> argument.endsWith(\"...\") ? argument.replace(\"...\", \"[]\") : argument)\n\t\t\t\t.toList();\n\t\t\treturn new MethodAnchor(name, arguments, origin);\n\t\t}\n\n\t}\n\n\tprivate static final class FieldAnchor extends JavadocAnchor {\n\n\t\tprivate final String name;\n\n\t\tprivate FieldAnchor(String name, Origin origin) {\n\t\t\tsuper(origin);\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tstatic FieldAnchor of(String anchor, Origin origin) {\n\t\t\treturn new FieldAnchor(anchor, origin);\n\t\t}\n\n\t}\n\n\tprivate static final class MethodMatcher extends ClassVisitor {\n\n\t\tprivate final MethodAnchor methodAnchor;\n\n\t\tprivate boolean matched = false;\n\n\t\tprivate MethodMatcher(MethodAnchor methodAnchor) {\n\t\t\tsuper(SpringAsmInfo.ASM_VERSION);\n\t\t\tthis.methodAnchor = methodAnchor;\n\t\t}\n\n\t\t@Override\n\t\tpublic MethodVisitor visitMethod(int access, String name, String descriptor, String signature,\n\t\t\t\tString[] exceptions) {\n\t\t\tif (!this.matched && name.equals(this.methodAnchor.name)) {\n\t\t\t\tType type = Type.getType(descriptor);\n\t\t\t\tif (type.getArgumentCount() == this.methodAnchor.arguments.size()) {\n\t\t\t\t\tList<String> argumentTypeNames = Arrays.asList(type.getArgumentTypes())\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.map(Type::getClassName)\n\t\t\t\t\t\t.toList();\n\t\t\t\t\tif (argumentTypeNames.equals(this.methodAnchor.arguments)) {\n\t\t\t\t\t\tthis.matched = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate static final class FieldMatcher extends ClassVisitor {\n\n\t\tprivate final FieldAnchor fieldAnchor;\n\n\t\tprivate boolean matched = false;\n\n\t\tprivate FieldMatcher(FieldAnchor fieldAnchor) {\n\t\t\tsuper(SpringAsmInfo.ASM_VERSION);\n\t\t\tthis.fieldAnchor = fieldAnchor;\n\t\t}\n\n\t\t@Override\n\t\tpublic FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {\n\t\t\tif (!this.matched && name.equals(this.fieldAnchor.name)) {\n\t\t\t\tthis.matched = true;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/ConsumableContentContribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.file.RegularFile;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.publish.PublishingExtension;\nimport org.gradle.api.publish.maven.MavenPublication;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\n\n/**\n * A contribution of content to Antora that can be consumed by other projects.\n *\n * @author Andy Wilkinson\n */\nclass ConsumableContentContribution extends ContentContribution {\n\n\tprotected ConsumableContentContribution(Project project, String type, String name) {\n\t\tsuper(project, name, type);\n\t}\n\n\t@Override\n\tvoid produceFrom(CopySpec copySpec) {\n\t\tthis.produceFrom(copySpec, false);\n\t}\n\n\tvoid produceFrom(CopySpec copySpec, boolean publish) {\n\t\tTaskProvider<? extends Task> producer = super.configureProduction(copySpec);\n\t\tif (publish) {\n\t\t\tpublish(producer);\n\t\t}\n\t\tConfiguration configuration = createConfiguration(getName(),\n\t\t\t\t\"Configuration for %s Antora %s content artifacts.\");\n\t\tconfiguration.setCanBeConsumed(true);\n\t\tconfiguration.setCanBeResolved(false);\n\t\tgetProject().getArtifacts().add(configuration.getName(), producer);\n\t}\n\n\tvoid consumeFrom(String path) {\n\t\tConfiguration configuration = createConfiguration(getName(), \"Configuration for %s Antora %s content.\");\n\t\tconfiguration.setCanBeConsumed(false);\n\t\tconfiguration.setCanBeResolved(true);\n\t\tDependencyHandler dependencies = getProject().getDependencies();\n\t\tdependencies.add(configuration.getName(),\n\t\t\t\tgetProject().provider(() -> projectDependency(path, configuration.getName())));\n\t\tProvider<Directory> outputDirectory = outputDirectory(\"content\", getName());\n\t\tTaskContainer tasks = getProject().getTasks();\n\t\tTaskProvider<?> copyAntoraContent = tasks.register(taskName(\"copy\", \"%s\", configuration.getName()),\n\t\t\t\tCopyAntoraContent.class, (task) -> configureCopyContent(task, path, configuration, outputDirectory));\n\t\tconfigureAntora(addInputFrom(copyAntoraContent, configuration.getName()));\n\t\tconfigurePlaybookGeneration(this::addToZipContentsCollectorDependencies);\n\t\tpublish(copyAntoraContent);\n\t}\n\n\tvoid publish(TaskProvider<? extends Task> producer) {\n\t\tgetProject().getExtensions()\n\t\t\t.getByType(PublishingExtension.class)\n\t\t\t.getPublications()\n\t\t\t.withType(MavenPublication.class)\n\t\t\t.configureEach((mavenPublication) -> addPublishedMavenArtifact(mavenPublication, producer));\n\t}\n\n\tprivate void configureCopyContent(CopyAntoraContent task, String path, Configuration configuration,\n\t\t\tProvider<Directory> outputDirectory) {\n\t\ttask.setDescription(\n\t\t\t\t\"Syncs the %s Antora %s content from %s.\".formatted(getName(), toDescription(getType()), path));\n\t\ttask.setSource(configuration);\n\t\ttask.getOutputFile().set(outputDirectory.map(this::getContentZipFile));\n\t}\n\n\tprivate void addToZipContentsCollectorDependencies(GenerateAntoraPlaybook task) {\n\t\ttask.getAntoraExtensions().getZipContentsCollector().getDependencies().add(getName());\n\t}\n\n\tprivate void addPublishedMavenArtifact(MavenPublication mavenPublication, TaskProvider<?> producer) {\n\t\tif (\"maven\".equals(mavenPublication.getName())) {\n\t\t\tString classifier = \"%s-%s-content\".formatted(getName(), getType());\n\t\t\tmavenPublication.artifact(producer, (mavenArtifact) -> mavenArtifact.setClassifier(classifier));\n\t\t}\n\t}\n\n\tprivate RegularFile getContentZipFile(Directory dir) {\n\t\tObject version = getProject().getVersion();\n\t\treturn dir.file(\"spring-boot-docs-%s-%s-%s-content.zip\".formatted(version, getName(), getType()));\n\t}\n\n\tprivate static String toDescription(String input) {\n\t\treturn input.replace(\"-\", \" \");\n\t}\n\n\tprivate Configuration createConfiguration(String name, String description) {\n\t\treturn getProject().getConfigurations()\n\t\t\t.create(configurationName(name, \"Antora%sContent\", getType()),\n\t\t\t\t\t(configuration) -> configuration.setDescription(description.formatted(getName(), getType())));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/ContentContribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Zip;\n\n/**\n * A contribution of content to Antora.\n *\n * @author Andy Wilkinson\n */\nabstract class ContentContribution extends Contribution {\n\n\tprivate final String type;\n\n\tprotected ContentContribution(Project project, String name, String type) {\n\t\tsuper(project, name);\n\t\tthis.type = type;\n\t}\n\n\tprotected String getType() {\n\t\treturn this.type;\n\t}\n\n\tabstract void produceFrom(CopySpec copySpec);\n\n\tprotected TaskProvider<? extends Task> configureProduction(CopySpec copySpec) {\n\t\tTaskContainer tasks = getProject().getTasks();\n\t\tTaskProvider<Zip> zipContent = tasks.register(taskName(\"zip\", \"%sAntora%sContent\", getName(), this.type),\n\t\t\t\tZip.class, (zip) -> {\n\t\t\t\t\tzip.getDestinationDirectory()\n\t\t\t\t\t\t.set(getProject().getLayout().getBuildDirectory().dir(\"generated/docs/antora-content\"));\n\t\t\t\t\tzip.getArchiveClassifier().set(\"%s-%s-content\".formatted(getName(), this.type));\n\t\t\t\t\tzip.with(copySpec);\n\t\t\t\t\tzip.setDescription(\"Creates a zip archive of the %s Antora %s content.\".formatted(getName(),\n\t\t\t\t\t\t\ttoDescription(this.type)));\n\t\t\t\t});\n\t\tconfigureAntora(addInputFrom(zipContent, zipContent.getName()));\n\t\treturn zipContent;\n\t}\n\n\tprivate static String toDescription(String input) {\n\t\treturn input.replace(\"-\", \" \");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/Contribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.antora.gradle.AntoraTask;\nimport org.gradle.api.Action;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskProvider;\n\nimport org.springframework.boot.build.AntoraConventions;\nimport org.springframework.util.StringUtils;\n\n/**\n * A contribution to Antora.\n *\n * @author Andy Wilkinson\n */\nabstract class Contribution {\n\n\tprivate final Project project;\n\n\tprivate final String name;\n\n\tprotected Contribution(Project project, String name) {\n\t\tthis.project = project;\n\t\tthis.name = name;\n\t}\n\n\tprotected Project getProject() {\n\t\treturn this.project;\n\t}\n\n\tprotected String getName() {\n\t\treturn this.name;\n\t}\n\n\tprotected Dependency projectDependency(String path, String configurationName) {\n\t\treturn getProject().getDependencies().project(Map.of(\"path\", path, \"configuration\", configurationName));\n\t}\n\n\tprotected Provider<Directory> outputDirectory(String dependencyType, String theName) {\n\t\treturn getProject().getLayout()\n\t\t\t.getBuildDirectory()\n\t\t\t.dir(\"generated/docs/antora-dependencies-\" + dependencyType + \"/\" + theName);\n\t}\n\n\tprotected String taskName(String verb, String object, String... args) {\n\t\treturn name(verb, object, args);\n\t}\n\n\tprotected String configurationName(String name, String type, String... args) {\n\t\treturn name(toCamelCase(name), type, args);\n\t}\n\n\tprotected void configurePlaybookGeneration(Action<GenerateAntoraPlaybook> action) {\n\t\tthis.project.getTasks()\n\t\t\t.named(AntoraConventions.GENERATE_ANTORA_PLAYBOOK_TASK_NAME, GenerateAntoraPlaybook.class, action);\n\t}\n\n\tprotected void configureAntora(Action<AntoraTask> action) {\n\t\tthis.project.getTasks().named(\"antora\", AntoraTask.class, action);\n\t}\n\n\tprotected Action<AntoraTask> addInputFrom(TaskProvider<?> task, String propertyName) {\n\t\treturn (antora) -> antora.getInputs()\n\t\t\t.files(task)\n\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t.withPropertyName(propertyName);\n\t}\n\n\tprivate String name(String prefix, String format, String... args) {\n\t\treturn prefix + format.formatted(Arrays.stream(args).map(this::toPascalCase).toArray());\n\t}\n\n\tprivate String toPascalCase(String input) {\n\t\treturn StringUtils.capitalize(toCamelCase(input));\n\t}\n\n\tprivate String toCamelCase(String input) {\n\t\tStringBuilder output = new StringBuilder(input.length());\n\t\tboolean capitalize = false;\n\t\tfor (char c : input.toCharArray()) {\n\t\t\tif (c == '-') {\n\t\t\t\tcapitalize = true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\toutput.append(capitalize ? Character.toUpperCase(c) : c);\n\t\t\t\tcapitalize = false;\n\t\t\t}\n\t\t}\n\t\treturn output.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/CopyAntoraContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * Tasks to copy Antora content.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CopyAntoraContent extends DefaultTask {\n\n\tprivate FileCollection source;\n\n\t@Inject\n\tpublic CopyAntoraContent() {\n\t}\n\n\t@InputFiles\n\tpublic FileCollection getSource() {\n\t\treturn this.source;\n\t}\n\n\tpublic void setSource(FileCollection source) {\n\t\tthis.source = source;\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@TaskAction\n\tvoid copyAntoraContent() throws IllegalStateException, IOException {\n\t\tPath source = this.source.getSingleFile().toPath();\n\t\tPath target = getOutputFile().getAsFile().get().toPath();\n\t\tFiles.copy(source, target, StandardCopyOption.REPLACE_EXISTING);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/Extensions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\n/**\n * Antora and Asciidoc extensions used by Spring Boot.\n *\n * @author Phillip Webb\n */\npublic final class Extensions {\n\n\tprivate static final String ROOT_COMPONENT_EXTENSION = \"@springio/antora-extensions/root-component-extension\";\n\n\tprivate static final List<Extension> antora;\n\tstatic {\n\t\tList<Extension> extensions = new ArrayList<>();\n\t\textensions.add(new Extension(\"@springio/antora-extensions\", ROOT_COMPONENT_EXTENSION,\n\t\t\t\t\"@springio/antora-extensions/static-page-extension\",\n\t\t\t\t\"@springio/antora-extensions/override-navigation-builder-extension\"));\n\t\textensions.add(new Extension(\"@springio/antora-xref-extension\"));\n\t\textensions.add(new Extension(\"@springio/antora-zip-contents-collector-extension\"));\n\t\tantora = List.copyOf(extensions);\n\t}\n\n\tprivate static final List<Extension> asciidoc;\n\tstatic {\n\t\tList<Extension> extensions = new ArrayList<>();\n\t\textensions.add(new Extension(\"@asciidoctor/tabs\"));\n\t\textensions.add(new Extension(\"@springio/asciidoctor-extensions\", \"@springio/asciidoctor-extensions\",\n\t\t\t\t\"@springio/asciidoctor-extensions/javadoc-extension\",\n\t\t\t\t\"@springio/asciidoctor-extensions/configuration-properties-extension\",\n\t\t\t\t\"@springio/asciidoctor-extensions/section-ids-extension\"));\n\t\tasciidoc = List.copyOf(extensions);\n\t}\n\n\tprivate static final Map<String, String> localOverrides = Collections.emptyMap();\n\n\tprivate Extensions() {\n\t}\n\n\tstatic List<Map<String, Object>> antora(Consumer<AntoraExtensionsConfiguration> extensions) {\n\t\tAntoraExtensionsConfiguration result = new AntoraExtensionsConfiguration(\n\t\t\t\tantora.stream().flatMap(Extension::names).sorted().toList());\n\t\textensions.accept(result);\n\t\treturn result.config();\n\t}\n\n\tstatic List<String> asciidoc() {\n\t\treturn asciidoc.stream().flatMap(Extension::names).sorted().toList();\n\t}\n\n\tprivate record Extension(String name, String... includeNames) {\n\n\t\tStream<String> names() {\n\t\t\treturn (this.includeNames.length != 0) ? Arrays.stream(this.includeNames) : Stream.of(this.name);\n\t\t}\n\n\t}\n\n\tstatic final class AntoraExtensionsConfiguration {\n\n\t\tprivate final Map<String, Map<String, Object>> extensions = new TreeMap<>();\n\n\t\tprivate AntoraExtensionsConfiguration(List<String> names) {\n\t\t\tnames.forEach((name) -> this.extensions.put(name, null));\n\t\t}\n\n\t\tvoid xref(Consumer<Xref> xref) {\n\t\t\txref.accept(new Xref());\n\t\t}\n\n\t\tvoid zipContentsCollector(Consumer<ZipContentsCollector> zipContentsCollector) {\n\t\t\tzipContentsCollector.accept(new ZipContentsCollector());\n\t\t}\n\n\t\tvoid rootComponent(Consumer<RootComponent> rootComponent) {\n\t\t\trootComponent.accept(new RootComponent());\n\t\t}\n\n\t\tList<Map<String, Object>> config() {\n\t\t\tList<Map<String, Object>> config = new ArrayList<>();\n\t\t\tMap<String, Map<String, Object>> orderedExtensions = new LinkedHashMap<>(this.extensions);\n\t\t\t// The root component extension must be last\n\t\t\tMap<String, Object> rootComponentConfig = orderedExtensions.remove(ROOT_COMPONENT_EXTENSION);\n\t\t\torderedExtensions.put(ROOT_COMPONENT_EXTENSION, rootComponentConfig);\n\t\t\torderedExtensions.forEach((name, customizations) -> {\n\t\t\t\tMap<String, Object> extensionConfig = new LinkedHashMap<>();\n\t\t\t\textensionConfig.put(\"require\", localOverrides.getOrDefault(name, name));\n\t\t\t\tif (customizations != null) {\n\t\t\t\t\textensionConfig.putAll(customizations);\n\t\t\t\t}\n\t\t\t\tconfig.add(extensionConfig);\n\t\t\t});\n\t\t\treturn List.copyOf(config);\n\t\t}\n\n\t\tabstract class Customizer {\n\n\t\t\tprivate final String name;\n\n\t\t\tCustomizer(String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t\tprotected void customize(String key, Object value) {\n\t\t\t\tAntoraExtensionsConfiguration.this.extensions.computeIfAbsent(this.name, (name) -> new TreeMap<>())\n\t\t\t\t\t.put(key, value);\n\t\t\t}\n\n\t\t}\n\n\t\tclass Xref extends Customizer {\n\n\t\t\tXref() {\n\t\t\t\tsuper(\"@springio/antora-xref-extension\");\n\t\t\t}\n\n\t\t\tvoid stub(List<String> stub) {\n\t\t\t\tif (stub != null && !stub.isEmpty()) {\n\t\t\t\t\tcustomize(\"stub\", stub);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tclass ZipContentsCollector extends Customizer {\n\n\t\t\tZipContentsCollector() {\n\t\t\t\tsuper(\"@springio/antora-zip-contents-collector-extension\");\n\t\t\t}\n\n\t\t\tvoid versionFile(String versionFile) {\n\t\t\t\tcustomize(\"version_file\", versionFile);\n\t\t\t}\n\n\t\t\tvoid locations(List<String> locations) {\n\t\t\t\tcustomize(\"locations\", locations);\n\t\t\t}\n\n\t\t\tvoid alwaysInclude(List<AlwaysInclude> alwaysInclude) {\n\t\t\t\tif (alwaysInclude != null && !alwaysInclude.isEmpty()) {\n\t\t\t\t\tcustomize(\"always_include\", alwaysInclude.stream().map(AlwaysInclude::asMap).toList());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trecord AlwaysInclude(String name, String classifier) implements Serializable {\n\n\t\t\t\tprivate Map<String, String> asMap() {\n\t\t\t\t\treturn new TreeMap<>(Map.of(\"name\", name(), \"classifier\", classifier()));\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tclass RootComponent extends Customizer {\n\n\t\t\tRootComponent() {\n\t\t\t\tsuper(ROOT_COMPONENT_EXTENSION);\n\t\t\t}\n\n\t\t\tvoid name(String name) {\n\t\t\t\tcustomize(\"root_component_name\", name);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/GenerateAntoraPlaybook.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Project;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.provider.SetProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Nested;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.TaskAction;\nimport org.yaml.snakeyaml.DumperOptions;\nimport org.yaml.snakeyaml.Yaml;\n\nimport org.springframework.boot.build.AntoraConventions;\nimport org.springframework.boot.build.antora.Extensions.AntoraExtensionsConfiguration.ZipContentsCollector.AlwaysInclude;\n\n/**\n * Task to generate a local Antora playbook.\n *\n * @author Phillip Webb\n */\npublic abstract class GenerateAntoraPlaybook extends DefaultTask {\n\n\tprivate static final String GENERATED_DOCS = \"build/generated/docs/\";\n\n\tprivate final Path root;\n\n\tprivate final Provider<String> playbookOutputDir;\n\n\tprivate final String version;\n\n\tprivate final AntoraExtensions antoraExtensions;\n\n\tprivate final AsciidocExtensions asciidocExtensions;\n\n\tprivate final ContentSource contentSource;\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\tpublic GenerateAntoraPlaybook() {\n\t\tthis.root = toRealPath(getProject().getRootDir().toPath());\n\t\tthis.antoraExtensions = getProject().getObjects().newInstance(AntoraExtensions.class, this.root);\n\t\tthis.asciidocExtensions = getProject().getObjects().newInstance(AsciidocExtensions.class);\n\t\tthis.version = getProject().getVersion().toString();\n\t\tthis.playbookOutputDir = configurePlaybookOutputDir(getProject());\n\t\tthis.contentSource = getProject().getObjects().newInstance(ContentSource.class, this.root);\n\t\tsetGroup(\"Documentation\");\n\t\tsetDescription(\"Generates an Antora playbook.yml file for local use\");\n\t\tgetOutputFile().convention(getProject().getLayout()\n\t\t\t.getBuildDirectory()\n\t\t\t.file(\"generated/docs/antora-playbook/antora-playbook.yml\"));\n\t\tthis.contentSource.addStartPath(getProject()\n\t\t\t.provider(() -> getProject().getLayout().getProjectDirectory().dir(AntoraConventions.ANTORA_SOURCE_DIR)));\n\t}\n\n\t@Nested\n\tpublic AntoraExtensions getAntoraExtensions() {\n\t\treturn this.antoraExtensions;\n\t}\n\n\t@Nested\n\tpublic AsciidocExtensions getAsciidocExtensions() {\n\t\treturn this.asciidocExtensions;\n\t}\n\n\t@Nested\n\tpublic ContentSource getContentSource() {\n\t\treturn this.contentSource;\n\t}\n\n\tprivate Provider<String> configurePlaybookOutputDir(Project project) {\n\t\tPath siteDirectory = getProject().getLayout().getBuildDirectory().dir(\"site\").get().getAsFile().toPath();\n\t\treturn project.provider(() -> {\n\t\t\tPath playbookDir = toRealPath(getOutputFile().get().getAsFile().toPath()).getParent();\n\t\t\tPath outputDir = toRealPath(siteDirectory);\n\t\t\treturn \".\" + File.separator + playbookDir.relativize(outputDir);\n\t\t});\n\t}\n\n\t@TaskAction\n\tpublic void writePlaybookYml() throws IOException {\n\t\tFile file = getOutputFile().get().getAsFile();\n\t\tfile.getParentFile().mkdirs();\n\t\ttry (FileWriter out = new FileWriter(file)) {\n\t\t\tcreateYaml().dump(getData(), out);\n\t\t}\n\t}\n\n\tprivate Map<String, Object> getData() throws IOException {\n\t\tMap<String, Object> data = loadPlaybookTemplate();\n\t\taddExtensions(data);\n\t\taddSources(data);\n\t\taddDir(data);\n\t\treturn data;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, Object> loadPlaybookTemplate() throws IOException {\n\t\ttry (InputStream resource = getClass().getResourceAsStream(\"antora-playbook-template.yml\")) {\n\t\t\treturn createYaml().loadAs(resource, LinkedHashMap.class);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void addExtensions(Map<String, Object> data) {\n\t\tMap<String, Object> antora = (Map<String, Object>) data.get(\"antora\");\n\t\tantora.put(\"extensions\", Extensions.antora((extensions) -> {\n\t\t\textensions.xref(\n\t\t\t\t\t(xref) -> xref.stub(this.antoraExtensions.getXref().getStubs().getOrElse(Collections.emptyList())));\n\t\t\textensions.zipContentsCollector((zipContentsCollector) -> {\n\t\t\t\tzipContentsCollector.versionFile(\"gradle.properties\");\n\t\t\t\tzipContentsCollector.locations(this.antoraExtensions.getZipContentsCollector()\n\t\t\t\t\t.getLocations()\n\t\t\t\t\t.getOrElse(Collections.emptyList()));\n\t\t\t\tzipContentsCollector\n\t\t\t\t\t.alwaysInclude(this.antoraExtensions.getZipContentsCollector().getAlwaysInclude().getOrNull());\n\t\t\t});\n\t\t\textensions.rootComponent((rootComponent) -> rootComponent.name(\"boot\"));\n\t\t}));\n\t\tMap<String, Object> asciidoc = (Map<String, Object>) data.get(\"asciidoc\");\n\t\tList<String> asciidocExtensions = Extensions.asciidoc();\n\t\tif (this.asciidocExtensions.getExcludeJavadocExtension().getOrElse(Boolean.FALSE)) {\n\t\t\tasciidocExtensions = new ArrayList<>(asciidocExtensions);\n\t\t\tasciidocExtensions.remove(\"@springio/asciidoctor-extensions/javadoc-extension\");\n\t\t}\n\t\tasciidoc.put(\"extensions\", asciidocExtensions);\n\t}\n\n\tprivate void addSources(Map<String, Object> data) {\n\t\tList<Map<String, Object>> contentSources = getList(data, \"content.sources\");\n\t\tcontentSources.add(createContentSource());\n\t}\n\n\tprivate Map<String, Object> createContentSource() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tPath playbookPath = getOutputFile().get().getAsFile().toPath().getParent();\n\t\tStringBuilder url = new StringBuilder(\".\");\n\t\tthis.root.relativize(playbookPath).normalize().forEach((path) -> url.append(File.separator).append(\"..\"));\n\t\tsource.put(\"url\", url.toString());\n\t\tsource.put(\"branches\", \"HEAD\");\n\t\tsource.put(\"version\", this.version);\n\t\tsource.put(\"start_paths\", this.contentSource.getStartPaths().get());\n\t\treturn source;\n\t}\n\n\tprivate void addDir(Map<String, Object> data) {\n\t\tdata.put(\"output\", Map.of(\"dir\", this.playbookOutputDir.get()));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> List<T> getList(Map<String, Object> data, String location) {\n\t\treturn (List<T>) get(data, location);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Object get(Map<String, Object> data, String location) {\n\t\tObject result = data;\n\t\tString[] keys = location.split(\"\\\\.\");\n\t\tfor (String key : keys) {\n\t\t\tresult = ((Map<String, Object>) result).get(key);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate Yaml createYaml() {\n\t\tDumperOptions options = new DumperOptions();\n\t\toptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);\n\t\toptions.setPrettyFlow(true);\n\t\treturn new Yaml(options);\n\t}\n\n\tprivate static Path toRealPath(Path path) {\n\t\ttry {\n\t\t\treturn Files.exists(path) ? path.toRealPath() : path;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tpublic abstract static class AntoraExtensions {\n\n\t\tprivate final Xref xref;\n\n\t\tprivate final ZipContentsCollector zipContentsCollector;\n\n\t\t@Inject\n\t\tpublic AntoraExtensions(ObjectFactory objects, Path root) {\n\t\t\tthis.xref = objects.newInstance(Xref.class);\n\t\t\tthis.zipContentsCollector = objects.newInstance(ZipContentsCollector.class, root);\n\t\t}\n\n\t\t@Nested\n\t\tpublic Xref getXref() {\n\t\t\treturn this.xref;\n\t\t}\n\n\t\t@Nested\n\t\tpublic ZipContentsCollector getZipContentsCollector() {\n\t\t\treturn this.zipContentsCollector;\n\t\t}\n\n\t\tpublic abstract static class Xref {\n\n\t\t\t@Input\n\t\t\t@Optional\n\t\t\tpublic abstract ListProperty<String> getStubs();\n\n\t\t}\n\n\t\tpublic abstract static class ZipContentsCollector {\n\n\t\t\tprivate final Provider<List<String>> locations;\n\n\t\t\t@Inject\n\t\t\tpublic ZipContentsCollector(Project project, Path root) {\n\t\t\t\tthis.locations = configureZipContentCollectorLocations(project, root);\n\t\t\t}\n\n\t\t\tprivate Provider<List<String>> configureZipContentCollectorLocations(Project project, Path root) {\n\t\t\t\tListProperty<String> locations = project.getObjects().listProperty(String.class);\n\t\t\t\tPath relativeProjectPath = relativize(root, project.getProjectDir().toPath());\n\t\t\t\tString locationName = project.getName() + \"-${version}-${name}-${classifier}.zip\";\n\t\t\t\tlocations.add(project\n\t\t\t\t\t.provider(() -> relativeProjectPath.resolve(GENERATED_DOCS + \"antora-content/\" + locationName)\n\t\t\t\t\t\t.toString()));\n\t\t\t\tlocations.addAll(getDependencies().map((dependencies) -> dependencies.stream()\n\t\t\t\t\t.map((dependency) -> relativeProjectPath\n\t\t\t\t\t\t.resolve(GENERATED_DOCS + \"antora-dependencies-content/\" + dependency + \"/\" + locationName))\n\t\t\t\t\t.map(Path::toString)\n\t\t\t\t\t.toList()));\n\t\t\t\treturn locations;\n\t\t\t}\n\n\t\t\tprivate static Path relativize(Path root, Path subPath) {\n\t\t\t\treturn toRealPath(root).relativize(toRealPath(subPath)).normalize();\n\t\t\t}\n\n\t\t\t@Input\n\t\t\t@Optional\n\t\t\tpublic abstract ListProperty<AlwaysInclude> getAlwaysInclude();\n\n\t\t\t@Input\n\t\t\t@Optional\n\t\t\tpublic Provider<List<String>> getLocations() {\n\t\t\t\treturn this.locations;\n\t\t\t}\n\n\t\t\t@Input\n\t\t\t@Optional\n\t\t\tpublic abstract SetProperty<String> getDependencies();\n\n\t\t}\n\n\t}\n\n\tpublic abstract static class AsciidocExtensions {\n\n\t\t@Inject\n\t\tpublic AsciidocExtensions() {\n\n\t\t}\n\n\t\t@Input\n\t\t@Optional\n\t\tpublic abstract Property<Boolean> getExcludeJavadocExtension();\n\n\t}\n\n\tpublic abstract static class ContentSource {\n\n\t\tprivate final Path root;\n\n\t\t@Inject\n\t\tpublic ContentSource(Path root) {\n\t\t\tthis.root = root;\n\t\t}\n\n\t\t@Input\n\t\tpublic abstract ListProperty<String> getStartPaths();\n\n\t\tvoid addStartPath(Provider<Directory> startPath) {\n\t\t\tgetStartPaths()\n\t\t\t\t.add(startPath.map((dir) -> this.root.relativize(toRealPath(dir.getAsFile().toPath())).toString()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/LocalAggregateContentContribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.file.CopySpec;\n\nimport org.springframework.boot.build.antora.Extensions.AntoraExtensionsConfiguration.ZipContentsCollector.AlwaysInclude;\n\n/**\n * A contribution of aggregate content that cannot be consumed by other projects.\n *\n * @author Andy Wilkinson\n */\nclass LocalAggregateContentContribution extends ContentContribution {\n\n\tprotected LocalAggregateContentContribution(Project project, String name) {\n\t\tsuper(project, name, \"local-aggregate\");\n\t}\n\n\t@Override\n\tvoid produceFrom(CopySpec copySpec) {\n\t\tsuper.configureProduction(copySpec);\n\t\tconfigurePlaybookGeneration(this::addToAlwaysInclude);\n\t}\n\n\tprivate void addToAlwaysInclude(GenerateAntoraPlaybook task) {\n\t\ttask.getAntoraExtensions()\n\t\t\t.getZipContentsCollector()\n\t\t\t.getAlwaysInclude()\n\t\t\t.add(new AlwaysInclude(getName(), \"local-aggregate-content\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/SourceContribution.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Zip;\n\nimport org.springframework.boot.build.AntoraConventions;\n\n/**\n * A contribution of source to Antora.\n *\n * @author Andy Wilkinson\n */\nclass SourceContribution extends Contribution {\n\n\tprivate static final String CONFIGURATION_NAME = \"antoraSource\";\n\n\tSourceContribution(Project project, String name) {\n\t\tsuper(project, name);\n\t}\n\n\tvoid produce() {\n\t\tConfiguration antoraSource = getProject().getConfigurations().create(CONFIGURATION_NAME);\n\t\tTaskProvider<Zip> antoraSourceZip = getProject().getTasks().register(\"antoraSourceZip\", Zip.class, (zip) -> {\n\t\t\tzip.getDestinationDirectory().set(getProject().getLayout().getBuildDirectory().dir(\"antora-source\"));\n\t\t\tzip.from(AntoraConventions.ANTORA_SOURCE_DIR);\n\t\t\tzip.setDescription(\n\t\t\t\t\t\"Creates a zip archive of the Antora source in %s.\".formatted(AntoraConventions.ANTORA_SOURCE_DIR));\n\t\t});\n\t\tgetProject().getArtifacts().add(antoraSource.getName(), antoraSourceZip);\n\t}\n\n\tvoid consumeFrom(String path) {\n\t\tConfiguration configuration = createConfiguration(getName());\n\t\tDependencyHandler dependencies = getProject().getDependencies();\n\t\tdependencies.add(configuration.getName(),\n\t\t\t\tgetProject().provider(() -> projectDependency(path, CONFIGURATION_NAME)));\n\t\tProvider<Directory> outputDirectory = outputDirectory(\"source\", getName());\n\t\tTaskContainer tasks = getProject().getTasks();\n\t\tTaskProvider<SyncAntoraSource> syncSource = tasks.register(taskName(\"sync\", \"%s\", configuration.getName()),\n\t\t\t\tSyncAntoraSource.class, (task) -> configureSyncSource(task, path, configuration, outputDirectory));\n\t\tconfigureAntora(addInputFrom(syncSource, configuration.getName()));\n\t\tconfigurePlaybookGeneration(\n\t\t\t\t(generatePlaybook) -> generatePlaybook.getContentSource().addStartPath(outputDirectory));\n\t}\n\n\tprivate void configureSyncSource(SyncAntoraSource task, String path, Configuration configuration,\n\t\t\tProvider<Directory> outputDirectory) {\n\t\ttask.setDescription(\"Syncs the %s Antora source from %s.\".formatted(getName(), path));\n\t\ttask.setSource(configuration);\n\t\ttask.getOutputDirectory().set(outputDirectory);\n\t}\n\n\tprivate Configuration createConfiguration(String name) {\n\t\treturn getProject().getConfigurations().create(configurationName(name, \"AntoraSource\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/antora/SyncAntoraSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.ArchiveOperations;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileSystemOperations;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * Task sync Antora source.\n *\n * @author Andy Wilkinson\n */\npublic abstract class SyncAntoraSource extends DefaultTask {\n\n\tprivate final FileSystemOperations fileSystemOperations;\n\n\tprivate final ArchiveOperations archiveOperations;\n\n\tprivate FileCollection source;\n\n\t@Inject\n\tpublic SyncAntoraSource(FileSystemOperations fileSystemOperations, ArchiveOperations archiveOperations) {\n\t\tthis.fileSystemOperations = fileSystemOperations;\n\t\tthis.archiveOperations = archiveOperations;\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@InputFiles\n\tpublic FileCollection getSource() {\n\t\treturn this.source;\n\t}\n\n\tpublic void setSource(FileCollection source) {\n\t\tthis.source = source;\n\t}\n\n\t@TaskAction\n\tvoid syncAntoraSource() {\n\t\tthis.fileSystemOperations.sync(this::syncAntoraSource);\n\t}\n\n\tprivate void syncAntoraSource(CopySpec sync) {\n\t\tsync.into(getOutputDirectory());\n\t\tthis.source.getFiles().forEach((file) -> sync.from(this.archiveOperations.zipTree(file)));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheck.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport com.tngtech.archunit.core.domain.JavaClasses;\nimport com.tngtech.archunit.core.importer.ClassFileImporter;\nimport com.tngtech.archunit.lang.ArchRule;\nimport com.tngtech.archunit.lang.EvaluationResult;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.Transformer;\nimport org.gradle.api.file.ConfigurableFileCollection;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.IgnoreEmptyDirectories;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.Internal;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SkipWhenEmpty;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\n/**\n * {@link Task} that checks for architecture problems.\n *\n * @author Andy Wilkinson\n * @author Yanming Zhou\n * @author Scott Frederick\n * @author Ivan Malutin\n * @author Phillip Webb\n * @author Dmytro Nosan\n * @author Moritz Halbritter\n * @author Stefano Cordio\n */\npublic abstract class ArchitectureCheck extends DefaultTask {\n\n\tprivate FileCollection classes;\n\n\tpublic ArchitectureCheck() {\n\t\tgetOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));\n\t\tgetAnnotationClasses().convention(ArchitectureCheckAnnotation.asMap());\n\t\tgetRules().addAll(getProhibitObjectsRequireNonNull().convention(true)\n\t\t\t.map(whenTrue(ArchitectureRules::noClassesShouldCallObjectsRequireNonNull)));\n\t\tgetRules().addAll(ArchitectureRules.standard());\n\t\tgetRules().addAll(whenMainSources(() -> ArchitectureRules.beanMethods(ArchitectureCheckAnnotation\n\t\t\t.classFor(getAnnotationClasses().get(), ArchitectureCheckAnnotation.CONDITIONAL_ON_CLASS))));\n\t\tgetRules().addAll(whenMainSources(() -> ArchitectureRules.conditionalOnMissingBean(ArchitectureCheckAnnotation\n\t\t\t.classFor(getAnnotationClasses().get(), ArchitectureCheckAnnotation.CONDITIONAL_ON_MISSING_BEAN))));\n\t\tgetRules().addAll(whenMainSources(() -> ArchitectureRules.configurationProperties(ArchitectureCheckAnnotation\n\t\t\t.classFor(getAnnotationClasses().get(), ArchitectureCheckAnnotation.CONFIGURATION_PROPERTIES))));\n\t\tgetRules().addAll(whenMainSources(\n\t\t\t\t() -> ArchitectureRules.configurationPropertiesBinding(ArchitectureCheckAnnotation.classFor(\n\t\t\t\t\t\tgetAnnotationClasses().get(), ArchitectureCheckAnnotation.CONFIGURATION_PROPERTIES_BINDING))));\n\t\tgetRules().addAll(whenMainSources(\n\t\t\t\t() -> ArchitectureRules.configurationPropertiesDeprecation(ArchitectureCheckAnnotation.classFor(\n\t\t\t\t\t\tgetAnnotationClasses().get(), ArchitectureCheckAnnotation.DEPRECATED_CONFIGURATION_PROPERTY))));\n\t\tgetRules().addAll(whenMainSources(() -> Collections.singletonList(\n\t\t\t\tArchitectureRules.allCustomAssertionMethodsNotReturningSelfShouldBeAnnotatedWithCheckReturnValue())));\n\t\tgetRuleDescriptions().set(getRules().map(this::asDescriptions));\n\t}\n\n\tprivate Provider<List<ArchRule>> whenMainSources(Supplier<List<ArchRule>> rules) {\n\t\treturn isMainSourceSet().map(whenTrue(rules));\n\t}\n\n\tprivate Provider<Boolean> isMainSourceSet() {\n\t\treturn getSourceSet().convention(SourceSet.MAIN_SOURCE_SET_NAME).map(SourceSet.MAIN_SOURCE_SET_NAME::equals);\n\t}\n\n\tprivate Transformer<List<ArchRule>, Boolean> whenTrue(Supplier<List<ArchRule>> rules) {\n\t\treturn (in) -> (!in) ? Collections.emptyList() : rules.get();\n\t}\n\n\tprivate List<String> asDescriptions(List<ArchRule> rules) {\n\t\treturn rules.stream().map(ArchRule::getDescription).toList();\n\t}\n\n\t@TaskAction\n\tvoid checkArchitecture() throws Exception {\n\t\twithCompileClasspath(() -> {\n\t\t\tJavaClasses javaClasses = new ClassFileImporter().importPaths(classFilesPaths());\n\t\t\tList<EvaluationResult> results = new ArrayList<>();\n\t\t\tevaluate(javaClasses).forEach(results::add);\n\t\t\tresults.add(new AutoConfigurationChecker().check(javaClasses));\n\t\t\tFile outputFile = getOutputDirectory().file(\"failure-report.txt\").get().getAsFile();\n\t\t\tList<EvaluationResult> violations = results.stream().filter(EvaluationResult::hasViolation).toList();\n\t\t\twriteViolationReport(violations, outputFile);\n\t\t\tif (!violations.isEmpty()) {\n\t\t\t\tthrow new VerificationException(\"Architecture check failed. See '\" + outputFile + \"' for details.\");\n\t\t\t}\n\t\t\treturn null;\n\t\t});\n\t}\n\n\tprivate List<Path> classFilesPaths() {\n\t\treturn this.classes.getFiles().stream().map(File::toPath).toList();\n\t}\n\n\tprivate Stream<EvaluationResult> evaluate(JavaClasses javaClasses) {\n\t\treturn getRules().get().stream().map((rule) -> rule.evaluate(javaClasses));\n\t}\n\n\tprivate void withCompileClasspath(Callable<?> callable) throws Exception {\n\t\tClassLoader previous = Thread.currentThread().getContextClassLoader();\n\t\ttry {\n\t\t\tList<URL> urls = new ArrayList<>();\n\t\t\tfor (File file : getCompileClasspath().getFiles()) {\n\t\t\t\turls.add(file.toURI().toURL());\n\t\t\t}\n\t\t\tClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[0]), getClass().getClassLoader());\n\t\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\t\tcallable.call();\n\t\t}\n\t\tfinally {\n\t\t\tThread.currentThread().setContextClassLoader(previous);\n\t\t}\n\t}\n\n\tprivate void writeViolationReport(List<EvaluationResult> violations, File outputFile) throws IOException {\n\t\toutputFile.getParentFile().mkdirs();\n\t\tStringBuilder report = new StringBuilder();\n\t\tfor (EvaluationResult violation : violations) {\n\t\t\treport.append(violation.getFailureReport());\n\t\t\treport.append(String.format(\"%n\"));\n\t\t}\n\t\tFiles.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,\n\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t}\n\n\tpublic void setClasses(FileCollection classes) {\n\t\tthis.classes = classes;\n\t}\n\n\t@Internal\n\tpublic FileCollection getClasses() {\n\t\treturn this.classes;\n\t}\n\n\t@InputFiles\n\t@SkipWhenEmpty\n\t@IgnoreEmptyDirectories\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tfinal FileTree getInputClasses() {\n\t\treturn this.classes.getAsFileTree();\n\t}\n\n\t@InputFiles\n\t@Classpath\n\tpublic abstract ConfigurableFileCollection getCompileClasspath();\n\n\t@Optional\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract DirectoryProperty getResourcesDirectory();\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@Internal\n\tpublic abstract ListProperty<ArchRule> getRules();\n\n\t@Internal\n\tpublic abstract Property<Boolean> getProhibitObjectsRequireNonNull();\n\n\t@Internal\n\tabstract Property<String> getSourceSet();\n\n\t@Input // Use descriptions as input since rules aren't serializable\n\tabstract ListProperty<String> getRuleDescriptions();\n\n\t@Internal\n\tabstract MapProperty<String, String> getAnnotationClasses();\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureCheckAnnotation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture;\n\nimport java.util.Map;\n\n/**\n * Annotations used in architecture checks, which can be overridden in architecture rule\n * tests.\n *\n * @author Scott Frederick\n * @author Stephane Nicoll\n */\npublic enum ArchitectureCheckAnnotation {\n\n\t/**\n\t * Condition on class check.\n\t */\n\tCONDITIONAL_ON_CLASS,\n\n\t/**\n\t * Condition on missing bean check.\n\t */\n\tCONDITIONAL_ON_MISSING_BEAN,\n\n\t/**\n\t * Configuration properties bean.\n\t */\n\tCONFIGURATION_PROPERTIES,\n\n\t/**\n\t * Deprecated configuration property.\n\t */\n\tDEPRECATED_CONFIGURATION_PROPERTY,\n\n\t/**\n\t * Custom implementation to bind configuration properties.\n\t */\n\tCONFIGURATION_PROPERTIES_BINDING;\n\n\tprivate static final Map<String, String> annotationNameToClassName = Map.of(CONDITIONAL_ON_CLASS.name(),\n\t\t\t\"org.springframework.boot.autoconfigure.condition.ConditionalOnClass\", CONDITIONAL_ON_MISSING_BEAN.name(),\n\t\t\t\"org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean\",\n\t\t\tCONFIGURATION_PROPERTIES.name(), \"org.springframework.boot.context.properties.ConfigurationProperties\",\n\t\t\tDEPRECATED_CONFIGURATION_PROPERTY.name(),\n\t\t\t\"org.springframework.boot.context.properties.DeprecatedConfigurationProperty\",\n\t\t\tCONFIGURATION_PROPERTIES_BINDING.name(),\n\t\t\t\"org.springframework.boot.context.properties.ConfigurationPropertiesBinding\");\n\n\tstatic Map<String, String> asMap() {\n\t\treturn annotationNameToClassName;\n\t}\n\n\tstatic String classFor(Map<String, String> annotationProperty, ArchitectureCheckAnnotation annotation) {\n\t\tString name = annotation.name();\n\t\treturn annotationProperty.getOrDefault(name, asMap().get(name));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitecturePlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.compile.JavaCompile;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Plugin} for verifying a project's architecture.\n *\n * @author Andy Wilkinson\n */\npublic class ArchitecturePlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> registerTasks(project));\n\t}\n\n\tprivate void registerTasks(Project project) {\n\t\tJavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);\n\t\tfor (SourceSet sourceSet : javaPluginExtension.getSourceSets()) {\n\t\t\tregisterArchitectureCheck(sourceSet, \"java\", project)\n\t\t\t\t.configure((task) -> task.setClasses(project.files(project.getTasks()\n\t\t\t\t\t.named(sourceSet.getCompileTaskName(\"java\"), JavaCompile.class)\n\t\t\t\t\t.flatMap((compile) -> compile.getDestinationDirectory()))));\n\t\t\tproject.getPlugins()\n\t\t\t\t.withId(\"org.jetbrains.kotlin.jvm\",\n\t\t\t\t\t\t(kotlinPlugin) -> registerArchitectureCheck(sourceSet, \"kotlin\", project)\n\t\t\t\t\t\t\t.configure((task) -> task.setClasses(project.files(project.getTasks()\n\t\t\t\t\t\t\t\t.named(sourceSet.getCompileTaskName(\"kotlin\"), KotlinCompileTool.class)\n\t\t\t\t\t\t\t\t.flatMap((compile) -> compile.getDestinationDirectory())))));\n\t\t}\n\t}\n\n\tprivate TaskProvider<ArchitectureCheck> registerArchitectureCheck(SourceSet sourceSet, String language,\n\t\t\tProject project) {\n\t\tTaskProvider<ArchitectureCheck> checkArchitecture = project.getTasks()\n\t\t\t.register(\n\t\t\t\t\t\"checkArchitecture\"\n\t\t\t\t\t\t\t+ StringUtils.capitalize(sourceSet.getName() + StringUtils.capitalize(language)),\n\t\t\t\t\tArchitectureCheck.class, (task) -> {\n\t\t\t\t\t\ttask.getSourceSet().set(sourceSet.getName());\n\t\t\t\t\t\ttask.getCompileClasspath().from(sourceSet.getCompileClasspath());\n\t\t\t\t\t\ttask.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());\n\t\t\t\t\t\ttask.dependsOn(sourceSet.getProcessResourcesTaskName());\n\t\t\t\t\t\ttask.setDescription(\"Checks the architecture of the \" + language + \" classes of the \"\n\t\t\t\t\t\t\t\t+ sourceSet.getName() + \" source set.\");\n\t\t\t\t\t\ttask.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t\t\t\t\t});\n\t\tproject.getTasks()\n\t\t\t.named(LifecycleBasePlugin.CHECK_TASK_NAME)\n\t\t\t.configure((check) -> check.dependsOn(checkArchitecture));\n\t\treturn checkArchitecture;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/architecture/ArchitectureRules.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture;\n\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport com.tngtech.archunit.base.DescribedPredicate;\nimport com.tngtech.archunit.core.domain.AccessTarget.CodeUnitCallTarget;\nimport com.tngtech.archunit.core.domain.JavaAnnotation;\nimport com.tngtech.archunit.core.domain.JavaCall;\nimport com.tngtech.archunit.core.domain.JavaClass;\nimport com.tngtech.archunit.core.domain.JavaClass.Predicates;\nimport com.tngtech.archunit.core.domain.JavaClasses;\nimport com.tngtech.archunit.core.domain.JavaConstructor;\nimport com.tngtech.archunit.core.domain.JavaField;\nimport com.tngtech.archunit.core.domain.JavaMember;\nimport com.tngtech.archunit.core.domain.JavaMethod;\nimport com.tngtech.archunit.core.domain.JavaModifier;\nimport com.tngtech.archunit.core.domain.JavaPackage;\nimport com.tngtech.archunit.core.domain.JavaParameter;\nimport com.tngtech.archunit.core.domain.JavaType;\nimport com.tngtech.archunit.core.domain.properties.CanBeAnnotated;\nimport com.tngtech.archunit.core.domain.properties.HasAnnotations;\nimport com.tngtech.archunit.core.domain.properties.HasName;\nimport com.tngtech.archunit.core.domain.properties.HasOwner;\nimport com.tngtech.archunit.core.domain.properties.HasOwner.Predicates.With;\nimport com.tngtech.archunit.core.domain.properties.HasParameterTypes;\nimport com.tngtech.archunit.lang.AbstractClassesTransformer;\nimport com.tngtech.archunit.lang.ArchCondition;\nimport com.tngtech.archunit.lang.ArchRule;\nimport com.tngtech.archunit.lang.ClassesTransformer;\nimport com.tngtech.archunit.lang.ConditionEvents;\nimport com.tngtech.archunit.lang.SimpleConditionEvent;\nimport com.tngtech.archunit.lang.syntax.ArchRuleDefinition;\nimport com.tngtech.archunit.lang.syntax.elements.ClassesShould;\nimport com.tngtech.archunit.lang.syntax.elements.GivenMethodsConjunction;\nimport com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.lang.CheckReturnValue;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * Factory used to create {@link ArchRule architecture rules}.\n *\n * @author Andy Wilkinson\n * @author Yanming Zhou\n * @author Scott Frederick\n * @author Ivan Malutin\n * @author Phillip Webb\n * @author Ngoc Nhan\n * @author Moritz Halbritter\n * @author Stefano Cordio\n */\nfinal class ArchitectureRules {\n\n\tprivate static final String AUTOCONFIGURATION_ANNOTATION = \"org.springframework.boot.autoconfigure.AutoConfiguration\";\n\n\tprivate ArchitectureRules() {\n\t}\n\n\tstatic List<ArchRule> noClassesShouldCallObjectsRequireNonNull() {\n\t\treturn List.of(\n\t\t\t\tnoClassesShould().callMethod(Objects.class, \"requireNonNull\", Object.class, String.class)\n\t\t\t\t\t.because(shouldUse(\"org.springframework.utils.Assert.notNull(Object, String)\")),\n\t\t\t\tnoClassesShould().callMethod(Objects.class, \"requireNonNull\", Object.class, Supplier.class)\n\t\t\t\t\t.because(shouldUse(\"org.springframework.utils.Assert.notNull(Object, Supplier)\")));\n\t}\n\n\tstatic List<ArchRule> standard() {\n\t\tList<ArchRule> rules = new ArrayList<>();\n\t\trules.add(allPackagesShouldBeFreeOfTangles());\n\t\trules.add(allBeanPostProcessorBeanMethodsShouldBeStaticAndNotCausePrematureInitialization());\n\t\trules.add(allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveOnlyInjectEnvironment());\n\t\trules.add(noClassesShouldCallStepVerifierStepVerifyComplete());\n\t\trules.add(noClassesShouldConfigureDefaultStepVerifierTimeout());\n\t\trules.add(noClassesShouldCallCollectorsToList());\n\t\trules.add(noClassesShouldCallURLEncoderWithStringEncoding());\n\t\trules.add(noClassesShouldCallURLDecoderWithStringEncoding());\n\t\trules.add(noClassesShouldLoadResourcesUsingResourceUtils());\n\t\trules.add(noClassesShouldCallStringToUpperCaseWithoutLocale());\n\t\trules.add(noClassesShouldCallStringToLowerCaseWithoutLocale());\n\t\trules.add(enumSourceShouldNotHaveValueThatIsTheSameAsTypeOfMethodsFirstParameter());\n\t\trules.add(conditionsShouldNotBePublic());\n\t\trules.add(autoConfigurationClassesShouldBePublicAndFinal());\n\t\trules.add(autoConfigurationClassesShouldHaveNoPublicMembers());\n\t\trules.add(testAutoConfigurationClassesShouldBePackagePrivateAndFinal());\n\t\treturn List.copyOf(rules);\n\t}\n\n\tstatic List<ArchRule> beanMethods(String annotationClass) {\n\t\treturn List.of(allBeanMethodsShouldReturnNonPrivateType(),\n\t\t\t\tallBeanMethodsShouldNotHaveConditionalOnClassAnnotation(annotationClass));\n\t}\n\n\tstatic List<ArchRule> conditionalOnMissingBean(String annotationClass) {\n\t\treturn List\n\t\t\t.of(conditionalOnMissingBeanShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodReturnType(annotationClass));\n\t}\n\n\tstatic List<ArchRule> configurationProperties(String annotationClass) {\n\t\treturn List.of(classLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute(annotationClass),\n\t\t\t\tmethodLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute(annotationClass));\n\t}\n\n\tstatic List<ArchRule> configurationPropertiesBinding(String annotationClass) {\n\t\treturn List.of(allConfigurationPropertiesBindingBeanMethodsShouldBeStatic(annotationClass));\n\t}\n\n\tstatic List<ArchRule> configurationPropertiesDeprecation(String annotationClass) {\n\t\treturn List.of(allDeprecatedConfigurationPropertiesShouldIncludeSince(annotationClass));\n\t}\n\n\tprivate static ArchRule allBeanMethodsShouldReturnNonPrivateType() {\n\t\treturn methodsThatAreAnnotatedWith(\"org.springframework.context.annotation.Bean\").should(check(\n\t\t\t\t\"not return types declared with the %s modifier, as such types are incompatible with Spring AOT processing\"\n\t\t\t\t\t.formatted(JavaModifier.PRIVATE),\n\t\t\t\t(method, events) -> {\n\t\t\t\t\tJavaClass returnType = method.getRawReturnType();\n\t\t\t\t\tif (returnType.getModifiers().contains(JavaModifier.PRIVATE)) {\n\t\t\t\t\t\taddViolation(events, method, \"%s returns %s which is declared as %s\".formatted(\n\t\t\t\t\t\t\t\tmethod.getDescription(), returnType.getDescription(), returnType.getModifiers()));\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule allBeanMethodsShouldNotHaveConditionalOnClassAnnotation(String annotationName) {\n\t\treturn methodsThatAreAnnotatedWith(\"org.springframework.context.annotation.Bean\").should()\n\t\t\t.notBeAnnotatedWith(annotationName)\n\t\t\t.because(\"@ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent \"\n\t\t\t\t\t+ \"the method signature from being loaded. Such condition need to be placed\"\n\t\t\t\t\t+ \" on a @Configuration class, allowing the condition to back off before the type is loaded.\")\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tstatic ArchRule allCustomAssertionMethodsNotReturningSelfShouldBeAnnotatedWithCheckReturnValue() {\n\t\treturn ArchRuleDefinition.methods()\n\t\t\t.that()\n\t\t\t.areDeclaredInClassesThat()\n\t\t\t.implement(\"org.assertj.core.api.Assert\")\n\t\t\t.and()\n\t\t\t.arePublic()\n\t\t\t.and()\n\t\t\t.doNotHaveModifier(JavaModifier.BRIDGE)\n\t\t\t.and(doNotReturnSelfType())\n\t\t\t.should()\n\t\t\t.beAnnotatedWith(CheckReturnValue.class)\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static DescribedPredicate<JavaMethod> doNotReturnSelfType() {\n\t\treturn DescribedPredicate.describe(\"do not return self type\",\n\t\t\t\t(method) -> !method.getRawReturnType().equals(method.getOwner()));\n\t}\n\n\tprivate static ArchRule allPackagesShouldBeFreeOfTangles() {\n\t\treturn SlicesRuleDefinition.slices()\n\t\t\t.matching(\"(**)\")\n\t\t\t.should()\n\t\t\t.beFreeOfCycles()\n\t\t\t.ignoreDependency(\"org.springframework.boot.env.EnvironmentPostProcessor\",\n\t\t\t\t\t\"org.springframework.boot.SpringApplication\");\n\t}\n\n\tprivate static ArchRule allBeanPostProcessorBeanMethodsShouldBeStaticAndNotCausePrematureInitialization() {\n\t\treturn methodsThatAreAnnotatedWith(\"org.springframework.context.annotation.Bean\").and()\n\t\t\t.haveRawReturnType(assignableTo(\"org.springframework.beans.factory.config.BeanPostProcessor\"))\n\t\t\t.should(onlyHaveParametersThatWillNotCauseEagerInitialization())\n\t\t\t.andShould()\n\t\t\t.beStatic()\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchCondition<JavaMethod> onlyHaveParametersThatWillNotCauseEagerInitialization() {\n\t\treturn check(\"not have parameters that will cause eager initialization\",\n\t\t\t\tArchitectureRules::allBeanPostProcessorBeanMethodsShouldBeStaticAndNotCausePrematureInitialization);\n\t}\n\n\tprivate static void allBeanPostProcessorBeanMethodsShouldBeStaticAndNotCausePrematureInitialization(JavaMethod item,\n\t\t\tConditionEvents events) {\n\t\tDescribedPredicate<JavaParameter> notAnnotatedWithLazy = DescribedPredicate\n\t\t\t.not(CanBeAnnotated.Predicates.annotatedWith(\"org.springframework.context.annotation.Lazy\"));\n\t\tDescribedPredicate<JavaClass> notOfASafeType = notAssignableTo(\n\t\t\t\t\"org.springframework.beans.factory.ObjectProvider\", \"org.springframework.context.ApplicationContext\",\n\t\t\t\t\"org.springframework.core.env.Environment\")\n\t\t\t.and(notAnnotatedWithRoleInfrastructure());\n\t\titem.getParameters()\n\t\t\t.stream()\n\t\t\t.filter(notAnnotatedWithLazy)\n\t\t\t.filter((parameter) -> notOfASafeType.test(parameter.getRawType()))\n\t\t\t.forEach((parameter) -> addViolation(events, parameter,\n\t\t\t\t\tparameter.getDescription() + \" will cause eager initialization as it is \"\n\t\t\t\t\t\t\t+ notAnnotatedWithLazy.getDescription() + \" and is \" + notOfASafeType.getDescription()));\n\t}\n\n\tprivate static DescribedPredicate<JavaClass> notAnnotatedWithRoleInfrastructure() {\n\t\treturn is(\"not annotated with @Role(BeanDefinition.ROLE_INFRASTRUCTURE\", (candidate) -> {\n\t\t\tif (!candidate.isAnnotatedWith(Role.class)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tRole role = candidate.getAnnotationOfType(Role.class);\n\t\t\treturn role.value() != BeanDefinition.ROLE_INFRASTRUCTURE;\n\t\t});\n\t}\n\n\tprivate static ArchRule allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveOnlyInjectEnvironment() {\n\t\treturn methodsThatAreAnnotatedWith(\"org.springframework.context.annotation.Bean\").and()\n\t\t\t.haveRawReturnType(assignableTo(\"org.springframework.beans.factory.config.BeanFactoryPostProcessor\"))\n\t\t\t.should(onlyInjectEnvironment())\n\t\t\t.andShould()\n\t\t\t.beStatic()\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchCondition<JavaMethod> onlyInjectEnvironment() {\n\t\treturn check(\"only inject Environment\", ArchitectureRules::onlyInjectEnvironment);\n\t}\n\n\tprivate static void onlyInjectEnvironment(JavaMethod item, ConditionEvents events) {\n\t\tif (item.getParameters().stream().anyMatch(ArchitectureRules::isNotEnvironment)) {\n\t\t\taddViolation(events, item, item.getDescription() + \" should only inject Environment\");\n\t\t}\n\t}\n\n\tprivate static boolean isNotEnvironment(JavaParameter parameter) {\n\t\treturn !\"org.springframework.core.env.Environment\".equals(parameter.getType().getName());\n\t}\n\n\tprivate static ArchRule noClassesShouldCallStepVerifierStepVerifyComplete() {\n\t\treturn noClassesShould().callMethod(\"reactor.test.StepVerifier$Step\", \"verifyComplete\")\n\t\t\t.because(\"it can block indefinitely and \" + shouldUse(\"expectComplete().verify(Duration)\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldConfigureDefaultStepVerifierTimeout() {\n\t\treturn noClassesShould().callMethod(\"reactor.test.StepVerifier\", \"setDefaultTimeout\", \"java.time.Duration\")\n\t\t\t.because(shouldUse(\"expectComplete().verify(Duration)\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldCallCollectorsToList() {\n\t\treturn noClassesShould().callMethod(Collectors.class, \"toList\")\n\t\t\t.because(shouldUse(\"java.util.stream.Stream.toList()\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldCallURLEncoderWithStringEncoding() {\n\t\treturn noClassesShould().callMethod(URLEncoder.class, \"encode\", String.class, String.class)\n\t\t\t.because(shouldUse(\"java.net.URLEncoder.encode(String s, Charset charset)\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldCallURLDecoderWithStringEncoding() {\n\t\treturn noClassesShould().callMethod(URLDecoder.class, \"decode\", String.class, String.class)\n\t\t\t.because(shouldUse(\"java.net.URLDecoder.decode(String s, Charset charset)\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldLoadResourcesUsingResourceUtils() {\n\t\tDescribedPredicate<JavaCall<?>> resourceUtilsGetURL = hasJavaCallTarget(ownedByResourceUtils())\n\t\t\t.and(hasJavaCallTarget(hasNameOf(\"getURL\")))\n\t\t\t.and(hasJavaCallTarget(hasRawStringParameterType()));\n\t\tDescribedPredicate<JavaCall<?>> resourceUtilsGetFile = hasJavaCallTarget(ownedByResourceUtils())\n\t\t\t.and(hasJavaCallTarget(hasNameOf(\"getFile\")))\n\t\t\t.and(hasJavaCallTarget(hasRawStringParameterType()));\n\t\treturn noClassesShould().callMethodWhere(resourceUtilsGetURL.or(resourceUtilsGetFile))\n\t\t\t.because(shouldUse(\"org.springframework.boot.io.ApplicationResourceLoader\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldCallStringToUpperCaseWithoutLocale() {\n\t\treturn noClassesShould().callMethod(String.class, \"toUpperCase\")\n\t\t\t.because(shouldUse(\"String.toUpperCase(Locale.ROOT)\"));\n\t}\n\n\tprivate static ArchRule noClassesShouldCallStringToLowerCaseWithoutLocale() {\n\t\treturn noClassesShould().callMethod(String.class, \"toLowerCase\")\n\t\t\t.because(shouldUse(\"String.toLowerCase(Locale.ROOT)\"));\n\t}\n\n\tprivate static ArchRule conditionalOnMissingBeanShouldNotSpecifyOnlyATypeThatIsTheSameAsMethodReturnType(\n\t\t\tString annotation) {\n\t\treturn methodsThatAreAnnotatedWith(annotation)\n\t\t\t.should(notSpecifyOnlyATypeThatIsTheSameAsTheMethodReturnType(annotation))\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchCondition<? super JavaMethod> notSpecifyOnlyATypeThatIsTheSameAsTheMethodReturnType(\n\t\t\tString annotation) {\n\t\treturn check(\"not specify only a type that is the same as the method's return type\", (item, events) -> {\n\t\t\tJavaAnnotation<JavaMethod> conditionalAnnotation = item.getAnnotationOfType(annotation);\n\t\t\tMap<String, Object> properties = conditionalAnnotation.getProperties();\n\t\t\tif (!hasProperty(\"type\", properties) && !hasProperty(\"name\", properties)) {\n\t\t\t\tconditionalAnnotation.get(\"value\").ifPresent((value) -> {\n\t\t\t\t\tif (containsOnlySingleType((JavaType[]) value, item.getReturnType())) {\n\t\t\t\t\t\taddViolation(events, item, conditionalAnnotation.getDescription()\n\t\t\t\t\t\t\t\t+ \" should not specify only a value that is the same as the method's return type\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static boolean hasProperty(String name, Map<String, Object> properties) {\n\t\tObject property = properties.get(name);\n\t\tif (property == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (property.getClass().isArray()) ? ((Object[]) property).length > 0 : !property.toString().isEmpty();\n\t}\n\n\tprivate static ArchRule enumSourceShouldNotHaveValueThatIsTheSameAsTypeOfMethodsFirstParameter() {\n\t\treturn ArchRuleDefinition.methods()\n\t\t\t.that()\n\t\t\t.areAnnotatedWith(\"org.junit.jupiter.params.provider.EnumSource\")\n\t\t\t.should(notHaveValueThatIsTheSameAsTheTypeOfTheMethodsFirstParameter())\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchCondition<? super JavaMethod> notHaveValueThatIsTheSameAsTheTypeOfTheMethodsFirstParameter() {\n\t\treturn check(\"not have a value that is the same as the type of the method's first parameter\",\n\t\t\t\tArchitectureRules::notSpecifyOnlyATypeThatIsTheSameAsTheMethodParameterType);\n\t}\n\n\tprivate static void notSpecifyOnlyATypeThatIsTheSameAsTheMethodParameterType(JavaMethod item,\n\t\t\tConditionEvents events) {\n\t\tJavaAnnotation<JavaMethod> enumSourceAnnotation = item\n\t\t\t.getAnnotationOfType(\"org.junit.jupiter.params.provider.EnumSource\");\n\t\tenumSourceAnnotation.get(\"value\").ifPresent((value) -> {\n\t\t\tJavaType parameterType = item.getParameterTypes().get(0);\n\t\t\tif (value.equals(parameterType)) {\n\t\t\t\taddViolation(events, item, enumSourceAnnotation.getDescription()\n\t\t\t\t\t\t+ \" should not specify a value that is the same as the type of the method's first parameter\");\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static ArchRule classLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute(\n\t\t\tString annotationClass) {\n\t\treturn ArchRuleDefinition.classes()\n\t\t\t.that()\n\t\t\t.areAnnotatedWith(annotationClass)\n\t\t\t.should(notSpecifyOnlyPrefixAttributeOfConfigurationProperties(annotationClass))\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule methodLevelConfigurationPropertiesShouldNotSpecifyOnlyPrefixAttribute(\n\t\t\tString annotationClass) {\n\t\treturn ArchRuleDefinition.methods()\n\t\t\t.that()\n\t\t\t.areAnnotatedWith(annotationClass)\n\t\t\t.should(notSpecifyOnlyPrefixAttributeOfConfigurationProperties(annotationClass))\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchCondition<? super HasAnnotations<?>> notSpecifyOnlyPrefixAttributeOfConfigurationProperties(\n\t\t\tString annotationClass) {\n\t\treturn check(\"not specify only prefix attribute of @ConfigurationProperties\", (item,\n\t\t\t\tevents) -> notSpecifyOnlyPrefixAttributeOfConfigurationProperties(annotationClass, item, events));\n\t}\n\n\tprivate static void notSpecifyOnlyPrefixAttributeOfConfigurationProperties(String annotationClass,\n\t\t\tHasAnnotations<?> item, ConditionEvents events) {\n\t\tJavaAnnotation<?> configurationPropertiesAnnotation = item.getAnnotationOfType(annotationClass);\n\t\tMap<String, Object> properties = configurationPropertiesAnnotation.getProperties();\n\t\tif (hasProperty(\"prefix\", properties) && !hasProperty(\"value\", properties)\n\t\t\t\t&& properties.get(\"ignoreInvalidFields\").equals(false)\n\t\t\t\t&& properties.get(\"ignoreUnknownFields\").equals(true)) {\n\t\t\taddViolation(events, item, configurationPropertiesAnnotation.getDescription()\n\t\t\t\t\t+ \" should specify implicit 'value' attribute other than explicit 'prefix' attribute\");\n\t\t}\n\t}\n\n\tprivate static ArchRule conditionsShouldNotBePublic() {\n\t\tString springBootCondition = \"org.springframework.boot.autoconfigure.condition.SpringBootCondition\";\n\t\treturn ArchRuleDefinition.noClasses()\n\t\t\t.that()\n\t\t\t.areAssignableTo(springBootCondition)\n\t\t\t.and()\n\t\t\t.doNotHaveModifier(JavaModifier.ABSTRACT)\n\t\t\t.and()\n\t\t\t.areNotAnnotatedWith(Deprecated.class)\n\t\t\t.should()\n\t\t\t.bePublic()\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule allConfigurationPropertiesBindingBeanMethodsShouldBeStatic(String annotationClass) {\n\t\treturn methodsThatAreAnnotatedWith(\"org.springframework.context.annotation.Bean\").and()\n\t\t\t.areAnnotatedWith(annotationClass)\n\t\t\t.should()\n\t\t\t.beStatic()\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule allDeprecatedConfigurationPropertiesShouldIncludeSince(String annotationName) {\n\t\treturn methodsThatAreAnnotatedWith(annotationName)\n\t\t\t.should(check(\"include a non-empty 'since' attribute\", (method, events) -> {\n\t\t\t\tJavaAnnotation<JavaMethod> annotation = method.getAnnotationOfType(annotationName);\n\t\t\t\tMap<String, Object> properties = annotation.getProperties();\n\t\t\t\tObject since = properties.get(\"since\");\n\t\t\t\tif (!(since instanceof String) || ((String) since).isEmpty()) {\n\t\t\t\t\taddViolation(events, method, annotation.getDescription()\n\t\t\t\t\t\t\t+ \" should include a non-empty 'since' attribute of @DeprecatedConfigurationProperty\");\n\t\t\t\t}\n\t\t\t}))\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule autoConfigurationClassesShouldBePublicAndFinal() {\n\t\treturn ArchRuleDefinition.classes()\n\t\t\t.that(areRegularAutoConfiguration())\n\t\t\t.should()\n\t\t\t.bePublic()\n\t\t\t.andShould()\n\t\t\t.haveModifier(JavaModifier.FINAL)\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule testAutoConfigurationClassesShouldBePackagePrivateAndFinal() {\n\t\treturn ArchRuleDefinition.classes()\n\t\t\t.that(areTestAutoConfiguration())\n\t\t\t.should()\n\t\t\t.bePackagePrivate()\n\t\t\t.andShould()\n\t\t\t.haveModifier(JavaModifier.FINAL)\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tprivate static ArchRule autoConfigurationClassesShouldHaveNoPublicMembers() {\n\t\treturn ArchRuleDefinition.members()\n\t\t\t.that()\n\t\t\t.areDeclaredInClassesThat(areRegularAutoConfiguration())\n\t\t\t.and()\n\t\t\t.areDeclaredInClassesThat(areNotKotlinClasses())\n\t\t\t.and(areNotDefaultConstructors())\n\t\t\t.and(areNotConstants())\n\t\t\t.and(dontOverridePublicMethods())\n\t\t\t.should()\n\t\t\t.notBePublic()\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tstatic ArchRule shouldHaveNoPublicMembers() {\n\t\treturn ArchRuleDefinition.members()\n\t\t\t.that(areNotDefaultConstructors())\n\t\t\t.and(areNotConstants())\n\t\t\t.and(dontOverridePublicMethods())\n\t\t\t.should()\n\t\t\t.notBePublic()\n\t\t\t.allowEmptyShould(true);\n\t}\n\n\tstatic DescribedPredicate<JavaClass> areRegularAutoConfiguration() {\n\t\treturn DescribedPredicate.describe(\"are regular @AutoConfiguration\",\n\t\t\t\t(javaClass) -> javaClass.isAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)\n\t\t\t\t\t\t&& !javaClass.getName().contains(\"TestAutoConfiguration\") && !javaClass.isAnnotation());\n\t}\n\n\tstatic DescribedPredicate<JavaClass> areNotKotlinClasses() {\n\t\treturn DescribedPredicate.describe(\"are not Kotlin classes\",\n\t\t\t\t(javaClass) -> !javaClass.isAnnotatedWith(\"kotlin.Metadata\"));\n\t}\n\n\tstatic DescribedPredicate<JavaClass> areTestAutoConfiguration() {\n\t\treturn DescribedPredicate.describe(\"are test @AutoConfiguration\",\n\t\t\t\t(javaClass) -> javaClass.isAnnotatedWith(AUTOCONFIGURATION_ANNOTATION)\n\t\t\t\t\t\t&& javaClass.getName().contains(\"TestAutoConfiguration\") && !javaClass.isAnnotation());\n\t}\n\n\tprivate static DescribedPredicate<? super JavaMember> dontOverridePublicMethods() {\n\t\tOverridesPublicMethod<JavaMember> predicate = new OverridesPublicMethod<>();\n\t\treturn DescribedPredicate.describe(\"don't override public methods\", (member) -> !predicate.test(member));\n\t}\n\n\tprivate static DescribedPredicate<JavaMember> areNotDefaultConstructors() {\n\t\treturn DescribedPredicate.describe(\"aren't default constructors\",\n\t\t\t\t(member) -> !areDefaultConstructors().test(member));\n\t}\n\n\tprivate static DescribedPredicate<JavaMember> areDefaultConstructors() {\n\t\treturn DescribedPredicate.describe(\"are default constructors\", (member) -> {\n\t\t\tif (!(member instanceof JavaConstructor constructor)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn constructor.getParameters().isEmpty();\n\t\t});\n\t}\n\n\tprivate static DescribedPredicate<JavaMember> areNotConstants() {\n\t\treturn DescribedPredicate.describe(\"aren't constants\", (member) -> !areConstants().test(member));\n\t}\n\n\tprivate static DescribedPredicate<JavaMember> areConstants() {\n\t\treturn DescribedPredicate.describe(\"are constants\", (member) -> {\n\t\t\tif (member instanceof JavaField field) {\n\t\t\t\tSet<JavaModifier> modifiers = field.getModifiers();\n\t\t\t\treturn modifiers.contains(JavaModifier.STATIC) && modifiers.contains(JavaModifier.FINAL);\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\t}\n\n\tprivate static boolean containsOnlySingleType(JavaType[] types, JavaType type) {\n\t\treturn types.length == 1 && type.equals(types[0]);\n\t}\n\n\tprivate static ClassesShould noClassesShould() {\n\t\treturn ArchRuleDefinition.noClasses().should();\n\t}\n\n\tprivate static GivenMethodsConjunction methodsThatAreAnnotatedWith(String annotation) {\n\t\treturn ArchRuleDefinition.methods().that().areAnnotatedWith(annotation);\n\t}\n\n\tprivate static DescribedPredicate<HasOwner<JavaClass>> ownedByResourceUtils() {\n\t\treturn With.owner(Predicates.type(ResourceUtils.class));\n\t}\n\n\tprivate static DescribedPredicate<? super CodeUnitCallTarget> hasNameOf(String name) {\n\t\treturn HasName.Predicates.name(name);\n\t}\n\n\tprivate static DescribedPredicate<HasParameterTypes> hasRawStringParameterType() {\n\t\treturn HasParameterTypes.Predicates.rawParameterTypes(String.class);\n\t}\n\n\tprivate static DescribedPredicate<JavaCall<?>> hasJavaCallTarget(\n\t\t\tDescribedPredicate<? super CodeUnitCallTarget> predicate) {\n\t\treturn JavaCall.Predicates.target(predicate);\n\t}\n\n\tprivate static DescribedPredicate<JavaClass> notAssignableTo(String... typeNames) {\n\t\treturn DescribedPredicate.not(assignableTo(typeNames));\n\t}\n\n\tprivate static DescribedPredicate<JavaClass> assignableTo(String... typeNames) {\n\t\tDescribedPredicate<JavaClass> result = null;\n\t\tfor (String typeName : typeNames) {\n\t\t\tDescribedPredicate<JavaClass> assignableTo = Predicates.assignableTo(typeName);\n\t\t\tresult = (result != null) ? result.or(assignableTo) : assignableTo;\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static DescribedPredicate<JavaClass> is(String description, Predicate<JavaClass> predicate) {\n\t\treturn new DescribedPredicate<>(description) {\n\n\t\t\t@Override\n\t\t\tpublic boolean test(JavaClass t) {\n\t\t\t\treturn predicate.test(t);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate static <T> ArchCondition<T> check(String description, BiConsumer<T, ConditionEvents> check) {\n\t\treturn new ArchCondition<>(description) {\n\n\t\t\t@Override\n\t\t\tpublic void check(T item, ConditionEvents events) {\n\t\t\t\tcheck.accept(item, events);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate static void addViolation(ConditionEvents events, Object correspondingObject, String message) {\n\t\tevents.add(SimpleConditionEvent.violated(correspondingObject, message));\n\t}\n\n\tprivate static String shouldUse(String string) {\n\t\treturn string + \" should be used instead\";\n\t}\n\n\tstatic ClassesTransformer<JavaPackage> packages(Predicate<JavaPackage> filter) {\n\t\treturn new AbstractClassesTransformer<>(\"packages\") {\n\t\t\t@Override\n\t\t\tpublic Iterable<JavaPackage> doTransform(JavaClasses collection) {\n\t\t\t\treturn collection.stream().map(JavaClass::getPackage).filter(filter).collect(Collectors.toSet());\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate static class OverridesPublicMethod<T extends JavaMember> extends DescribedPredicate<T> {\n\n\t\tOverridesPublicMethod() {\n\t\t\tsuper(\"overrides public method\");\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean test(T member) {\n\t\t\tif (!(member instanceof JavaMethod javaMethod)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tStream<JavaMethod> superClassMethods = member.getOwner()\n\t\t\t\t.getAllRawSuperclasses()\n\t\t\t\t.stream()\n\t\t\t\t.flatMap((superClass) -> superClass.getMethods().stream());\n\t\t\tStream<JavaMethod> interfaceMethods = member.getOwner()\n\t\t\t\t.getAllRawInterfaces()\n\t\t\t\t.stream()\n\t\t\t\t.flatMap((iface) -> iface.getMethods().stream());\n\t\t\treturn Stream.concat(superClassMethods, interfaceMethods)\n\t\t\t\t.anyMatch((superMethod) -> isPublic(superMethod) && isOverridden(superMethod, javaMethod));\n\t\t}\n\n\t\tprivate boolean isPublic(JavaMethod method) {\n\t\t\treturn method.getModifiers().contains(JavaModifier.PUBLIC);\n\t\t}\n\n\t\tprivate boolean isOverridden(JavaMethod superMethod, JavaMethod method) {\n\t\t\treturn superMethod.getName().equals(method.getName())\n\t\t\t\t\t&& superMethod.getRawParameterTypes().size() == method.getRawParameterTypes().size()\n\t\t\t\t\t&& superMethod.getDescriptor().equals(method.getDescriptor());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/architecture/AutoConfigurationChecker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.tngtech.archunit.base.DescribedPredicate;\nimport com.tngtech.archunit.core.domain.JavaAnnotation;\nimport com.tngtech.archunit.core.domain.JavaClass;\nimport com.tngtech.archunit.core.domain.JavaClasses;\nimport com.tngtech.archunit.lang.EvaluationResult;\n\n/**\n * Finds all configurations from auto-configurations (either nested configurations or\n * imported ones) and checks that these classes don't contain public members.\n * <p>\n * Kotlin classes are ignored as Kotlin does not have package-private visibility and\n * {@code internal} isn't a good substitute.\n *\n * @author Moritz Halbritter\n */\nclass AutoConfigurationChecker {\n\n\tprivate final DescribedPredicate<JavaClass> isAutoConfiguration = ArchitectureRules.areRegularAutoConfiguration()\n\t\t.and(ArchitectureRules.areNotKotlinClasses());\n\n\tEvaluationResult check(JavaClasses javaClasses) {\n\t\tAutoConfigurations autoConfigurations = new AutoConfigurations(javaClasses);\n\t\tfor (JavaClass javaClass : javaClasses) {\n\t\t\tif (isAutoConfigurationOrEnclosedInAutoConfiguration(javaClass)) {\n\t\t\t\tautoConfigurations.add(javaClass);\n\t\t\t}\n\t\t}\n\t\treturn ArchitectureRules.shouldHaveNoPublicMembers().evaluate(autoConfigurations.getConfigurations());\n\t}\n\n\tprivate boolean isAutoConfigurationOrEnclosedInAutoConfiguration(JavaClass javaClass) {\n\t\tif (this.isAutoConfiguration.test(javaClass)) {\n\t\t\treturn true;\n\t\t}\n\t\tJavaClass enclosingClass = javaClass.getEnclosingClass().orElse(null);\n\t\twhile (enclosingClass != null) {\n\t\t\tif (this.isAutoConfiguration.test(enclosingClass)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tenclosingClass = enclosingClass.getEnclosingClass().orElse(null);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static final class AutoConfigurations {\n\n\t\tprivate static final String SPRING_BOOT_ROOT_PACKAGE = \"org.springframework.boot\";\n\n\t\tprivate static final String IMPORT = \"org.springframework.context.annotation.Import\";\n\n\t\tprivate static final String CONFIGURATION = \"org.springframework.context.annotation.Configuration\";\n\n\t\tprivate final JavaClasses classes;\n\n\t\tprivate final Map<String, JavaClass> autoConfigurationClasses = new HashMap<>();\n\n\t\tAutoConfigurations(JavaClasses classes) {\n\t\t\tthis.classes = classes;\n\t\t}\n\n\t\tvoid add(JavaClass autoConfiguration) {\n\t\t\tif (!autoConfiguration.isMetaAnnotatedWith(CONFIGURATION)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.autoConfigurationClasses.putIfAbsent(autoConfiguration.getName(), autoConfiguration) != null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprocessImports(autoConfiguration, this.autoConfigurationClasses);\n\t\t}\n\n\t\tJavaClasses getConfigurations() {\n\t\t\tDescribedPredicate<JavaClass> isAutoConfiguration = DescribedPredicate.describe(\"is an auto-configuration\",\n\t\t\t\t\t(c) -> this.autoConfigurationClasses.containsKey(c.getName()));\n\t\t\treturn this.classes.that(isAutoConfiguration);\n\t\t}\n\n\t\tprivate void processImports(JavaClass javaClass, Map<String, JavaClass> result) {\n\t\t\tJavaClass[] importedClasses = getImportedClasses(javaClass);\n\t\t\tfor (JavaClass importedClass : importedClasses) {\n\t\t\t\tif (!isBootClass(importedClass)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (result.putIfAbsent(importedClass.getName(), importedClass) != null) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Recursively find other imported classes\n\t\t\t\tprocessImports(importedClass, result);\n\t\t\t}\n\t\t}\n\n\t\tprivate JavaClass[] getImportedClasses(JavaClass javaClass) {\n\t\t\tif (!javaClass.isAnnotatedWith(IMPORT)) {\n\t\t\t\treturn new JavaClass[0];\n\t\t\t}\n\t\t\tJavaAnnotation<JavaClass> imports = javaClass.getAnnotationOfType(IMPORT);\n\t\t\treturn (JavaClass[]) imports.get(\"value\").orElse(new JavaClass[0]);\n\t\t}\n\n\t\tprivate boolean isBootClass(JavaClass javaClass) {\n\t\t\tString pkg = javaClass.getPackage().getName();\n\t\t\treturn pkg.equals(SPRING_BOOT_ROOT_PACKAGE) || pkg.startsWith(SPRING_BOOT_ROOT_PACKAGE + \".\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/artifacts/ArtifactRelease.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.artifacts;\n\nimport java.util.Locale;\n\nimport org.gradle.api.Project;\n\n/**\n * Information about artifacts produced by a build.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic final class ArtifactRelease {\n\n\tprivate static final String SPRING_SNAPSHOT_REPO = \"https://repo.spring.io/snapshot\";\n\n\tprivate static final String MAVEN_REPO = \"https://repo.maven.apache.org/maven2\";\n\n\tprivate final Type type;\n\n\tprivate ArtifactRelease(Type type) {\n\t\tthis.type = type;\n\t}\n\n\tpublic String getType() {\n\t\treturn this.type.toString().toLowerCase(Locale.ROOT);\n\t}\n\n\tpublic String getDownloadRepo() {\n\t\treturn (this.type == Type.SNAPSHOT) ? SPRING_SNAPSHOT_REPO : MAVEN_REPO;\n\t}\n\n\tpublic boolean isRelease() {\n\t\treturn this.type == Type.RELEASE;\n\t}\n\n\tpublic static ArtifactRelease forProject(Project project) {\n\t\treturn forVersion(project.getVersion().toString());\n\t}\n\n\tpublic static ArtifactRelease forVersion(String version) {\n\t\treturn new ArtifactRelease(Type.forVersion(version));\n\t}\n\n\tenum Type {\n\n\t\tSNAPSHOT, MILESTONE, RELEASE;\n\n\t\tstatic Type forVersion(String version) {\n\t\t\tint modifierIndex = version.lastIndexOf('-');\n\t\t\tif (modifierIndex == -1) {\n\t\t\t\treturn RELEASE;\n\t\t\t}\n\t\t\tString type = version.substring(modifierIndex + 1);\n\t\t\tif (type.startsWith(\"M\") || type.startsWith(\"RC\")) {\n\t\t\t\treturn MILESTONE;\n\t\t\t}\n\t\t\treturn SNAPSHOT;\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationClass.java",
    "content": "/*\n * Copyright 2025-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.springframework.asm.AnnotationVisitor;\nimport org.springframework.asm.ClassReader;\nimport org.springframework.asm.ClassVisitor;\nimport org.springframework.asm.SpringAsmInfo;\nimport org.springframework.asm.Type;\n\n/**\n * An {@code @AutoConfiguration} class.\n *\n * @param name name of the auto-configuration class\n * @param before values of the {@code before} attribute\n * @param beforeName values of the {@code beforeName} attribute\n * @param after values of the {@code after} attribute\n * @param afterName values of the {@code afterName} attribute\n * @author Andy Wilkinson\n */\npublic record AutoConfigurationClass(String name, List<String> before, List<String> beforeName, List<String> after,\n\t\tList<String> afterName) {\n\n\tprivate AutoConfigurationClass(String name, Map<String, List<String>> attributes) {\n\t\tthis(name, attributes.getOrDefault(\"before\", Collections.emptyList()),\n\t\t\t\tattributes.getOrDefault(\"beforeName\", Collections.emptyList()),\n\t\t\t\tattributes.getOrDefault(\"after\", Collections.emptyList()),\n\t\t\t\tattributes.getOrDefault(\"afterName\", Collections.emptyList()));\n\t}\n\n\tpublic static AutoConfigurationClass of(InputStream input) {\n\t\ttry {\n\t\t\tClassReader classReader = new ClassReader(input);\n\t\t\tAutoConfigurationClassVisitor visitor = new AutoConfigurationClassVisitor();\n\t\t\tclassReader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);\n\t\t\treturn visitor.autoConfigurationClass;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tstatic AutoConfigurationClass of(File classFile) {\n\t\ttry (InputStream input = new FileInputStream(classFile)) {\n\t\t\treturn of(input);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate static final class AutoConfigurationClassVisitor extends ClassVisitor {\n\n\t\tprivate AutoConfigurationClass autoConfigurationClass;\n\n\t\tprivate String name;\n\n\t\tprivate AutoConfigurationClassVisitor() {\n\t\t\tsuper(SpringAsmInfo.ASM_VERSION);\n\t\t}\n\n\t\t@Override\n\t\tpublic void visit(int version, int access, String name, String signature, String superName,\n\t\t\t\tString[] interfaces) {\n\t\t\tthis.name = Type.getObjectType(name).getClassName();\n\t\t}\n\n\t\t@Override\n\t\tpublic AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {\n\t\t\tString annotationClassName = Type.getType(descriptor).getClassName();\n\t\t\tif (\"org.springframework.boot.autoconfigure.AutoConfiguration\".equals(annotationClassName)) {\n\t\t\t\treturn new AutoConfigurationAnnotationVisitor();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate final class AutoConfigurationAnnotationVisitor extends AnnotationVisitor {\n\n\t\t\tprivate Map<String, List<String>> attributes = new HashMap<>();\n\n\t\t\tprivate static final Set<String> INTERESTING_ATTRIBUTES = Set.of(\"before\", \"beforeName\", \"after\",\n\t\t\t\t\t\"afterName\");\n\n\t\t\tprivate AutoConfigurationAnnotationVisitor() {\n\t\t\t\tsuper(SpringAsmInfo.ASM_VERSION);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void visitEnd() {\n\t\t\t\tAutoConfigurationClassVisitor.this.autoConfigurationClass = new AutoConfigurationClass(\n\t\t\t\t\t\tAutoConfigurationClassVisitor.this.name, this.attributes);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic AnnotationVisitor visitArray(String attributeName) {\n\t\t\t\tif (INTERESTING_ATTRIBUTES.contains(attributeName)) {\n\t\t\t\t\treturn new AnnotationVisitor(SpringAsmInfo.ASM_VERSION) {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic void visit(String name, Object value) {\n\t\t\t\t\t\t\tif (value instanceof Type type) {\n\t\t\t\t\t\t\t\tvalue = type.getClassName();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tAutoConfigurationAnnotationVisitor.this.attributes\n\t\t\t\t\t\t\t\t.computeIfAbsent(attributeName, (n) -> new ArrayList<>())\n\t\t\t\t\t\t\t\t.add(Objects.toString(value));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationImportsTask.java",
    "content": "/*\n * Copyright 2025-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.util.List;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SkipWhenEmpty;\n\n/**\n * A {@link Task} that uses a project's auto-configuration imports.\n *\n * @author Andy Wilkinson\n */\npublic abstract class AutoConfigurationImportsTask extends DefaultTask {\n\n\t/**\n\t * The path of the {@code AutoConfiguration.imports} file.\n\t */\n\tpublic static final String IMPORTS_FILE = \"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports\";\n\n\tprivate FileCollection sourceFiles = getProject().getObjects().fileCollection();\n\n\t@InputFiles\n\t@SkipWhenEmpty\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileTree getSource() {\n\t\treturn this.sourceFiles.getAsFileTree().matching((filter) -> filter.include(IMPORTS_FILE));\n\t}\n\n\tpublic void setSource(Object source) {\n\t\tthis.sourceFiles = getProject().getObjects().fileCollection().from(source);\n\t}\n\n\tprotected List<String> loadImports() {\n\t\tFile importsFile = getSource().getSingleFile();\n\t\ttry {\n\t\t\treturn Files.readAllLines(importsFile.toPath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.asm.ClassReader;\nimport org.springframework.asm.Opcodes;\nimport org.springframework.core.CollectionFactory;\n\n/**\n * A {@link Task} for generating metadata describing a project's auto-configuration\n * classes.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic abstract class AutoConfigurationMetadata extends DefaultTask {\n\n\tprivate static final String COMMENT_START = \"#\";\n\n\tprivate final String moduleName;\n\n\tprivate FileCollection classesDirectories;\n\n\tpublic AutoConfigurationMetadata() {\n\t\tthis.moduleName = getProject().getName();\n\t}\n\n\tpublic void setSourceSet(SourceSet sourceSet) {\n\t\tgetAutoConfigurationImports().set(new File(sourceSet.getOutput().getResourcesDir(),\n\t\t\t\t\"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports\"));\n\t\tthis.classesDirectories = sourceSet.getOutput().getClassesDirs();\n\t\tdependsOn(sourceSet.getOutput());\n\t}\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tabstract RegularFileProperty getAutoConfigurationImports();\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@Classpath\n\tFileCollection getClassesDirectories() {\n\t\treturn this.classesDirectories;\n\t}\n\n\t@TaskAction\n\tvoid documentAutoConfiguration() throws IOException {\n\t\tProperties autoConfiguration = readAutoConfiguration();\n\t\tFile outputFile = getOutputFile().get().getAsFile();\n\t\toutputFile.getParentFile().mkdirs();\n\t\ttry (FileWriter writer = new FileWriter(outputFile)) {\n\t\t\tautoConfiguration.store(writer, null);\n\t\t}\n\t}\n\n\tprivate Properties readAutoConfiguration() throws IOException {\n\t\tProperties autoConfiguration = CollectionFactory.createSortedProperties(true);\n\t\tList<String> classNames = readAutoConfigurationsFile();\n\t\tSet<String> publicClassNames = new LinkedHashSet<>();\n\t\tfor (String className : classNames) {\n\t\t\tFile classFile = findClassFile(className);\n\t\t\tif (classFile == null) {\n\t\t\t\tthrow new IllegalStateException(\"Auto-configuration class '\" + className + \"' not found.\");\n\t\t\t}\n\t\t\ttry (InputStream in = new FileInputStream(classFile)) {\n\t\t\t\tint access = new ClassReader(in).getAccess();\n\t\t\t\tif ((access & Opcodes.ACC_PUBLIC) == Opcodes.ACC_PUBLIC) {\n\t\t\t\t\tpublicClassNames.add(className);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tautoConfiguration.setProperty(\"autoConfigurationClassNames\", String.join(\",\", publicClassNames));\n\t\tautoConfiguration.setProperty(\"module\", this.moduleName);\n\t\treturn autoConfiguration;\n\t}\n\n\t/**\n\t * Reads auto-configurations from\n\t * META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.\n\t * @return auto-configurations\n\t */\n\tprivate List<String> readAutoConfigurationsFile() throws IOException {\n\t\tFile file = getAutoConfigurationImports().getAsFile().get();\n\t\tif (!file.exists()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\ttry (BufferedReader reader = new BufferedReader(new FileReader(file))) {\n\t\t\treturn reader.lines().map(this::stripComment).filter((line) -> !line.isEmpty()).toList();\n\t\t}\n\t}\n\n\tprivate String stripComment(String line) {\n\t\tint commentStart = line.indexOf(COMMENT_START);\n\t\tif (commentStart == -1) {\n\t\t\treturn line.trim();\n\t\t}\n\t\treturn line.substring(0, commentStart).trim();\n\t}\n\n\tprivate File findClassFile(String className) {\n\t\tString classFileName = className.replace(\".\", \"/\") + \".class\";\n\t\tfor (File classesDir : this.classesDirectories) {\n\t\t\tFile classFile = new File(classesDir, classFileName);\n\t\t\tif (classFile.isFile()) {\n\t\t\t\treturn classFile;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/AutoConfigurationPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.plugins.JavaBasePlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskContainer;\nimport org.gradle.api.tasks.TaskProvider;\n\nimport org.springframework.boot.build.DeployedPlugin;\nimport org.springframework.boot.build.optional.OptionalDependenciesPlugin;\n\n/**\n * {@link Plugin} for projects that define auto-configuration. When applied, the plugin\n * applies the {@link DeployedPlugin}. Additionally, when the {@link JavaPlugin} is\n * applied it:\n *\n * <ul>\n * <li>Adds a dependency on the auto-configuration annotation processor.\n * <li>Defines a task that produces metadata describing the auto-configuration. The\n * metadata is made available as an artifact in the {@code autoConfigurationMetadata}\n * configuration.\n * <li>Add checks to ensure import files and annotations are correct</li>\n * </ul>\n *\n * @author Andy Wilkinson\n */\npublic class AutoConfigurationPlugin implements Plugin<Project> {\n\n\tprivate static final String AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME = \"autoConfigurationMetadata\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().apply(DeployedPlugin.class);\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> new Configurer(project).configure());\n\t}\n\n\tprivate static class Configurer {\n\n\t\tprivate final Project project;\n\n\t\tprivate SourceSet main;\n\n\t\tConfigurer(Project project) {\n\t\t\tthis.project = project;\n\t\t\tthis.main = project.getExtensions()\n\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t.getSourceSets()\n\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t}\n\n\t\tvoid configure() {\n\t\t\taddAnnotationProcessorsDependencies();\n\t\t\tTaskContainer tasks = this.project.getTasks();\n\t\t\tConfigurationContainer configurations = this.project.getConfigurations();\n\t\t\tconfigurations.consumable(AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, (configuration) -> {\n\t\t\t\tconfiguration.attributes((attributes) -> {\n\t\t\t\t\tattributes.attribute(Category.CATEGORY_ATTRIBUTE,\n\t\t\t\t\t\t\tthis.project.getObjects().named(Category.class, Category.DOCUMENTATION));\n\t\t\t\t\tattributes.attribute(Usage.USAGE_ATTRIBUTE,\n\t\t\t\t\t\t\tthis.project.getObjects().named(Usage.class, \"auto-configuration-metadata\"));\n\t\t\t\t});\n\t\t\t});\n\t\t\ttasks.register(\"autoConfigurationMetadata\", AutoConfigurationMetadata.class,\n\t\t\t\t\tthis::configureAutoConfigurationMetadata);\n\t\t\tTaskProvider<CheckAutoConfigurationImports> checkAutoConfigurationImports = tasks.register(\n\t\t\t\t\t\"checkAutoConfigurationImports\", CheckAutoConfigurationImports.class,\n\t\t\t\t\tthis::configureCheckAutoConfigurationImports);\n\t\t\tConfiguration requiredClasspath = configurations.create(\"autoConfigurationRequiredClasspath\")\n\t\t\t\t.extendsFrom(configurations.getByName(this.main.getImplementationConfigurationName()),\n\t\t\t\t\t\tconfigurations.getByName(this.main.getRuntimeOnlyConfigurationName()));\n\t\t\trequiredClasspath.getDependencies().add(projectDependency(\":core:spring-boot-autoconfigure\"));\n\t\t\tTaskProvider<CheckAutoConfigurationClasses> checkAutoConfigurationClasses = tasks.register(\n\t\t\t\t\t\"checkAutoConfigurationClasses\", CheckAutoConfigurationClasses.class,\n\t\t\t\t\t(task) -> configureCheckAutoConfigurationClasses(requiredClasspath, task));\n\t\t\tthis.project.getPlugins()\n\t\t\t\t.withType(OptionalDependenciesPlugin.class,\n\t\t\t\t\t\t(plugin) -> configureCheckAutoConfigurationClassesForOptionalDependencies(configurations,\n\t\t\t\t\t\t\t\tcheckAutoConfigurationClasses));\n\t\t\tthis.project.getTasks()\n\t\t\t\t.getByName(JavaBasePlugin.CHECK_TASK_NAME)\n\t\t\t\t.dependsOn(checkAutoConfigurationImports, checkAutoConfigurationClasses);\n\t\t}\n\n\t\tprivate void addAnnotationProcessorsDependencies() {\n\t\t\tthis.project.getConfigurations()\n\t\t\t\t.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME)\n\t\t\t\t.getDependencies()\n\t\t\t\t.addAll(projectDependencies(\":core:spring-boot-autoconfigure-processor\",\n\t\t\t\t\t\t\":configuration-metadata:spring-boot-configuration-processor\"));\n\t\t}\n\n\t\tprivate void configureAutoConfigurationMetadata(AutoConfigurationMetadata task) {\n\t\t\ttask.setSourceSet(this.main);\n\t\t\ttask.dependsOn(this.main.getClassesTaskName());\n\t\t\ttask.getOutputFile()\n\t\t\t\t.set(this.project.getLayout().getBuildDirectory().file(\"auto-configuration-metadata.properties\"));\n\t\t\tthis.project.getArtifacts()\n\t\t\t\t.add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, task.getOutputFile(),\n\t\t\t\t\t\t(artifact) -> artifact.builtBy(task));\n\t\t}\n\n\t\tprivate void configureCheckAutoConfigurationImports(CheckAutoConfigurationImports task) {\n\t\t\ttask.setSource(this.main.getResources());\n\t\t\ttask.setClasspath(this.main.getOutput().getClassesDirs());\n\t\t\ttask.setDescription(\n\t\t\t\t\t\"Checks the %s file of the main source set.\".formatted(AutoConfigurationImportsTask.IMPORTS_FILE));\n\t\t}\n\n\t\tprivate void configureCheckAutoConfigurationClasses(Configuration requiredClasspath,\n\t\t\t\tCheckAutoConfigurationClasses task) {\n\t\t\ttask.setSource(this.main.getResources());\n\t\t\ttask.setClasspath(this.main.getOutput().getClassesDirs());\n\t\t\ttask.setRequiredDependencies(requiredClasspath);\n\t\t\ttask.setDescription(\"Checks the auto-configuration classes of the main source set.\");\n\t\t}\n\n\t\tprivate void configureCheckAutoConfigurationClassesForOptionalDependencies(\n\t\t\t\tConfigurationContainer configurations,\n\t\t\t\tTaskProvider<CheckAutoConfigurationClasses> checkAutoConfigurationClasses) {\n\t\t\tcheckAutoConfigurationClasses.configure((check) -> {\n\t\t\t\tConfiguration optionalClasspath = configurations.create(\"autoConfigurationOptionalClassPath\")\n\t\t\t\t\t.extendsFrom(configurations.getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME));\n\t\t\t\tcheck.setOptionalDependencies(optionalClasspath);\n\t\t\t});\n\t\t}\n\n\t\tprivate Set<Dependency> projectDependencies(String... paths) {\n\t\t\treturn Arrays.stream(paths).map((path) -> projectDependency(path)).collect(Collectors.toSet());\n\t\t}\n\n\t\tprivate Dependency projectDependency(String path) {\n\t\t\treturn this.project.getDependencies().project(Collections.singletonMap(\"path\", path));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/CheckAutoConfigurationClasses.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.stream.Stream;\n\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.provider.SetProperty;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\n\n/**\n * Task to check a project's {@code @AutoConfiguration} classes.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckAutoConfigurationClasses extends AutoConfigurationImportsTask {\n\n\tprivate FileCollection classpath = getProject().getObjects().fileCollection();\n\n\tprivate FileCollection optionalDependencies = getProject().getObjects().fileCollection();\n\n\tprivate FileCollection requiredDependencies = getProject().getObjects().fileCollection();\n\n\tprivate SetProperty<String> optionalDependencyClassNames = getProject().getObjects().setProperty(String.class);\n\n\tprivate SetProperty<String> requiredDependencyClassNames = getProject().getObjects().setProperty(String.class);\n\n\tpublic CheckAutoConfigurationClasses() {\n\t\tgetOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));\n\t\tsetGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t\tthis.optionalDependencyClassNames.set(getProject().provider(() -> classNamesOf(this.optionalDependencies)));\n\t\tthis.requiredDependencyClassNames.set(getProject().provider(() -> classNamesOf(this.requiredDependencies)));\n\t}\n\n\tprivate static List<String> classNamesOf(FileCollection classpath) {\n\t\treturn classpath.getFiles().stream().flatMap((file) -> {\n\t\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\t\treturn Collections.list(jarFile.entries())\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter((entry) -> !entry.isDirectory())\n\t\t\t\t\t.map(JarEntry::getName)\n\t\t\t\t\t.filter((entryName) -> entryName.endsWith(\".class\"))\n\t\t\t\t\t.map((entryName) -> entryName.substring(0, entryName.length() - \".class\".length()))\n\t\t\t\t\t.map((entryName) -> entryName.replace(\"/\", \".\"));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}).toList();\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(Object classpath) {\n\t\tthis.classpath = getProject().getObjects().fileCollection().from(classpath);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getOptionalDependencies() {\n\t\treturn this.optionalDependencies;\n\t}\n\n\tpublic void setOptionalDependencies(Object classpath) {\n\t\tthis.optionalDependencies = getProject().getObjects().fileCollection().from(classpath);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getRequiredDependencies() {\n\t\treturn this.requiredDependencies;\n\t}\n\n\tpublic void setRequiredDependencies(Object classpath) {\n\t\tthis.requiredDependencies = getProject().getObjects().fileCollection().from(classpath);\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@Input\n\tpublic abstract SetProperty<String> getOmittedFromImports();\n\n\t@TaskAction\n\tvoid execute() {\n\t\tMap<String, List<String>> problems = new TreeMap<>();\n\t\tSet<String> optionalOnlyClassNames = new HashSet<>(this.optionalDependencyClassNames.get());\n\t\tSet<String> requiredClassNames = this.requiredDependencyClassNames.get();\n\t\toptionalOnlyClassNames.removeAll(requiredClassNames);\n\t\tList<String> imports = loadImports();\n\t\tclassFiles().forEach((classFile) -> {\n\t\t\tAutoConfigurationClass autoConfigurationClass = AutoConfigurationClass.of(classFile);\n\t\t\tif (autoConfigurationClass != null) {\n\t\t\t\tcheck(autoConfigurationClass, optionalOnlyClassNames, requiredClassNames, imports, problems);\n\t\t\t}\n\t\t});\n\t\tFile outputFile = getOutputDirectory().file(\"failure-report.txt\").get().getAsFile();\n\t\twriteReport(problems, outputFile);\n\t\tif (!problems.isEmpty()) {\n\t\t\tthrow new VerificationException(\n\t\t\t\t\t\"Auto-configuration class check failed. See '%s' for details\".formatted(outputFile));\n\t\t}\n\t}\n\n\tprivate List<File> classFiles() {\n\t\tList<File> classFiles = new ArrayList<>();\n\t\tfor (File root : this.classpath.getFiles()) {\n\t\t\tif (root.exists()) {\n\t\t\t\ttry (Stream<Path> files = Files.walk(root.toPath())) {\n\t\t\t\t\tfiles.forEach((file) -> {\n\t\t\t\t\t\tif (Files.isRegularFile(file) && file.getFileName().toString().endsWith(\".class\")) {\n\t\t\t\t\t\t\tclassFiles.add(file.toFile());\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn classFiles;\n\t}\n\n\tprivate void check(AutoConfigurationClass autoConfigurationClass, Set<String> optionalOnlyClassNames,\n\t\t\tSet<String> requiredClassNames, List<String> imports, Map<String, List<String>> problems) {\n\t\tif (!autoConfigurationClass.name().endsWith(\"AutoConfiguration\")) {\n\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())\n\t\t\t\t.add(\"Name of a class annotated with @AutoConfiguration should end with AutoConfiguration\");\n\t\t}\n\t\tboolean testAutoConfiguration = autoConfigurationClass.name().endsWith(\"TestAutoConfiguration\");\n\t\tif (!getOmittedFromImports().getOrElse(Collections.emptySet()).contains(autoConfigurationClass.name())\n\t\t\t\t&& !imports.contains(autoConfigurationClass.name()) && !testAutoConfiguration) {\n\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())\n\t\t\t\t.add(\"Class is not registered in AutoConfiguration.imports\");\n\t\t}\n\t\tif ((getOmittedFromImports().getOrElse(Collections.emptySet()).contains(autoConfigurationClass.name())\n\t\t\t\t|| testAutoConfiguration) && imports.contains(autoConfigurationClass.name())) {\n\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())\n\t\t\t\t.add(\"Class should not be registered in AutoConfiguration.imports\");\n\t\t}\n\t\tautoConfigurationClass.before().forEach((before) -> {\n\t\t\tif (optionalOnlyClassNames.contains(before)) {\n\t\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())\n\t\t\t\t\t.add(\"before '%s' is from an optional dependency and should be declared in beforeName\"\n\t\t\t\t\t\t.formatted(before));\n\t\t\t}\n\t\t});\n\t\tautoConfigurationClass.beforeName().forEach((beforeName) -> {\n\t\t\tif (!optionalOnlyClassNames.contains(beforeName)) {\n\t\t\t\tString problem = requiredClassNames.contains(beforeName)\n\t\t\t\t\t\t? \"beforeName '%s' is from a required dependency and should be declared in before\"\n\t\t\t\t\t\t\t.formatted(beforeName)\n\t\t\t\t\t\t: \"beforeName '%s' not found\".formatted(beforeName);\n\t\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>()).add(problem);\n\t\t\t}\n\t\t});\n\t\tautoConfigurationClass.after().forEach((after) -> {\n\t\t\tif (optionalOnlyClassNames.contains(after)) {\n\t\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())\n\t\t\t\t\t.add(\"after '%s' is from an optional dependency and should be declared in afterName\"\n\t\t\t\t\t\t.formatted(after));\n\t\t\t}\n\t\t});\n\t\tautoConfigurationClass.afterName().forEach((afterName) -> {\n\t\t\tif (!optionalOnlyClassNames.contains(afterName)) {\n\t\t\t\tString problem = requiredClassNames.contains(afterName)\n\t\t\t\t\t\t? \"afterName '%s' is from a required dependency and should be declared in after\"\n\t\t\t\t\t\t\t.formatted(afterName)\n\t\t\t\t\t\t: \"afterName '%s' not found\".formatted(afterName);\n\t\t\t\tproblems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>()).add(problem);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void writeReport(Map<String, List<String>> problems, File outputFile) {\n\t\toutputFile.getParentFile().mkdirs();\n\t\tStringBuilder report = new StringBuilder();\n\t\tif (!problems.isEmpty()) {\n\t\t\treport.append(\"Found auto-configuration class problems:%n\".formatted());\n\t\t\tproblems.forEach((className, classProblems) -> {\n\t\t\t\treport.append(\"  - %s:%n\".formatted(className));\n\t\t\t\tclassProblems.forEach((problem) -> report.append(\"    - %s%n\".formatted(problem)));\n\t\t\t});\n\t\t}\n\t\ttry {\n\t\t\tFiles.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,\n\t\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/CheckAutoConfigurationImports.java",
    "content": "/*\n * Copyright 2025-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\n\n/**\n * Task to check the contents of a project's\n * {@code META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports}\n * file.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckAutoConfigurationImports extends AutoConfigurationImportsTask {\n\n\tprivate FileCollection classpath = getProject().getObjects().fileCollection();\n\n\tpublic CheckAutoConfigurationImports() {\n\t\tgetOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));\n\t\tsetGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(Object classpath) {\n\t\tthis.classpath = getProject().getObjects().fileCollection().from(classpath);\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@TaskAction\n\tvoid execute() {\n\t\tFile importsFile = getSource().getSingleFile();\n\t\tcheck(importsFile);\n\t}\n\n\tprivate void check(File importsFile) {\n\t\tList<String> imports = loadImports();\n\t\tList<String> problems = new ArrayList<>();\n\t\tfor (String imported : imports) {\n\t\t\tFile classFile = find(imported);\n\t\t\tif (classFile == null) {\n\t\t\t\tproblems.add(\"'%s' was not found\".formatted(imported));\n\t\t\t}\n\t\t\telse if (!correctlyAnnotated(classFile)) {\n\t\t\t\tproblems.add(\"'%s' is not annotated with @AutoConfiguration\".formatted(imported));\n\t\t\t}\n\t\t}\n\t\tList<String> sortedValues = new ArrayList<>(imports);\n\t\tCollections.sort(sortedValues);\n\t\tif (!sortedValues.equals(imports)) {\n\t\t\tFile sortedOutputFile = getOutputDirectory().file(\"sorted-\" + importsFile.getName()).get().getAsFile();\n\t\t\twriteString(sortedOutputFile,\n\t\t\t\t\tsortedValues.stream().collect(Collectors.joining(System.lineSeparator())) + System.lineSeparator());\n\t\t\tproblems.add(\"Entries should be sorted alphabetically (expect content written to \"\n\t\t\t\t\t+ sortedOutputFile.getAbsolutePath() + \")\");\n\t\t}\n\t\tFile outputFile = getOutputDirectory().file(\"failure-report.txt\").get().getAsFile();\n\t\twriteReport(importsFile, problems, outputFile);\n\t\tif (!problems.isEmpty()) {\n\t\t\tthrow new VerificationException(\"%s check failed. See '%s' for details\"\n\t\t\t\t.formatted(AutoConfigurationImportsTask.IMPORTS_FILE, outputFile));\n\t\t}\n\t}\n\n\tprivate File find(String className) {\n\t\tfor (File root : this.classpath.getFiles()) {\n\t\t\tString classFilePath = className.replace(\".\", \"/\") + \".class\";\n\t\t\tFile classFile = new File(root, classFilePath);\n\t\t\tif (classFile.isFile()) {\n\t\t\t\treturn classFile;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean correctlyAnnotated(File classFile) {\n\t\treturn AutoConfigurationClass.of(classFile) != null;\n\t}\n\n\tprivate void writeReport(File importsFile, List<String> problems, File outputFile) {\n\t\toutputFile.getParentFile().mkdirs();\n\t\tStringBuilder report = new StringBuilder();\n\t\tif (!problems.isEmpty()) {\n\t\t\treport.append(\"Found problems in '%s':%n\".formatted(importsFile));\n\t\t\tproblems.forEach((problem) -> report.append(\"  - %s%n\".formatted(problem)));\n\t\t}\n\t\twriteString(outputFile, report.toString());\n\t}\n\n\tprivate void writeString(File file, String content) {\n\t\ttry {\n\t\t\tFiles.writeString(file.toPath(), content);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/autoconfigure/DocumentAutoConfigurationClasses.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Reader;\nimport java.io.UncheckedIOException;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Task} used to document auto-configuration classes.\n *\n * @author Andy Wilkinson\n */\npublic abstract class DocumentAutoConfigurationClasses extends DefaultTask {\n\n\tprivate FileCollection autoConfiguration;\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getAutoConfiguration() {\n\t\treturn this.autoConfiguration;\n\t}\n\n\tpublic void setAutoConfiguration(FileCollection autoConfiguration) {\n\t\tthis.autoConfiguration = autoConfiguration;\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDir();\n\n\t@TaskAction\n\tvoid documentAutoConfigurationClasses() throws IOException {\n\t\tFileSystemUtils.deleteRecursively(getOutputDir().getAsFile().get());\n\t\tList<AutoConfiguration> autoConfigurations = load();\n\t\tautoConfigurations.forEach(this::writeModuleAdoc);\n\t\tfor (File metadataFile : this.autoConfiguration) {\n\t\t\tProperties metadata = new Properties();\n\t\t\ttry (Reader reader = new FileReader(metadataFile)) {\n\t\t\t\tmetadata.load(reader);\n\t\t\t}\n\t\t\tAutoConfiguration autoConfiguration = new AutoConfiguration(metadata.getProperty(\"module\"), new TreeSet<>(\n\t\t\t\t\tStringUtils.commaDelimitedListToSet(metadata.getProperty(\"autoConfigurationClassNames\"))));\n\t\t\twriteModuleAdoc(autoConfiguration);\n\t\t}\n\t\twriteNavAdoc(autoConfigurations);\n\t}\n\n\tprivate List<AutoConfiguration> load() {\n\t\treturn this.autoConfiguration.getFiles()\n\t\t\t.stream()\n\t\t\t.map(AutoConfiguration::of)\n\t\t\t.sorted((a1, a2) -> a1.module.compareTo(a2.module))\n\t\t\t.toList();\n\t}\n\n\tprivate void writeModuleAdoc(AutoConfiguration autoConfigurationClasses) {\n\t\tFile outputDir = getOutputDir().getAsFile().get();\n\t\toutputDir.mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(\n\t\t\t\tnew FileWriter(new File(outputDir, autoConfigurationClasses.module + \".adoc\")))) {\n\t\t\twriter.println(\"[[appendix.auto-configuration-classes.%s]]\".formatted(autoConfigurationClasses.module));\n\t\t\twriter.println(\"= %s\".formatted(autoConfigurationClasses.module));\n\t\t\twriter.println();\n\t\t\twriter.println(\"The following auto-configuration classes are from the `%s` module:\"\n\t\t\t\t.formatted(autoConfigurationClasses.module));\n\t\t\twriter.println();\n\t\t\twriter.println(\"[cols=\\\"4,1\\\"]\");\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"| Configuration Class | Links\");\n\t\t\tfor (AutoConfigurationClass autoConfigurationClass : autoConfigurationClasses.classes) {\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"| {code-spring-boot}/module/%s/src/main/java/%s.java[`%s`]%n\",\n\t\t\t\t\t\tautoConfigurationClasses.module, autoConfigurationClass.path, autoConfigurationClass.name);\n\t\t\t\twriter.printf(\"| xref:api:java/%s.html[javadoc]%n\", autoConfigurationClass.path);\n\t\t\t}\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate void writeNavAdoc(List<AutoConfiguration> autoConfigurations) {\n\t\tFile outputDir = getOutputDir().getAsFile().get();\n\t\toutputDir.mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(new File(outputDir, \"nav.adoc\")))) {\n\t\t\tautoConfigurations.forEach((autoConfigurationClasses) -> writer\n\t\t\t\t.println(\"*** xref:appendix:auto-configuration-classes/%s.adoc[]\"\n\t\t\t\t\t.formatted(autoConfigurationClasses.module)));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate static final class AutoConfiguration {\n\n\t\tprivate final String module;\n\n\t\tprivate final SortedSet<AutoConfigurationClass> classes;\n\n\t\tprivate AutoConfiguration(String module, Set<String> classNames) {\n\t\t\tthis.module = module;\n\t\t\tthis.classes = classNames.stream().map((className) -> {\n\t\t\t\tString path = className.replace('.', '/');\n\t\t\t\tString name = className.substring(className.lastIndexOf('.') + 1);\n\t\t\t\treturn new AutoConfigurationClass(name, path);\n\t\t\t}).collect(Collectors.toCollection(TreeSet::new));\n\t\t}\n\n\t\tprivate static AutoConfiguration of(File metadataFile) {\n\t\t\tProperties metadata = new Properties();\n\t\t\ttry (Reader reader = new FileReader(metadataFile)) {\n\t\t\t\tmetadata.load(reader);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t\treturn new AutoConfiguration(metadata.getProperty(\"module\"), new TreeSet<>(\n\t\t\t\t\tStringUtils.commaDelimitedListToSet(metadata.getProperty(\"autoConfigurationClassNames\"))));\n\t\t}\n\n\t}\n\n\tprivate static final class AutoConfigurationClass implements Comparable<AutoConfigurationClass> {\n\n\t\tprivate final String name;\n\n\t\tprivate final String path;\n\n\t\tprivate AutoConfigurationClass(String name, String path) {\n\t\t\tthis.name = name;\n\t\t\tthis.path = path;\n\t\t}\n\n\t\t@Override\n\t\tpublic int compareTo(AutoConfigurationClass other) {\n\t\t\treturn this.name.compareTo(other.name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/BomExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\nimport javax.inject.Inject;\n\nimport groovy.lang.Closure;\nimport groovy.lang.GroovyObjectSupport;\nimport org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;\nimport org.apache.maven.artifact.versioning.VersionRange;\nimport org.gradle.api.Action;\nimport org.gradle.api.InvalidUserCodeException;\nimport org.gradle.api.InvalidUserDataException;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.plugins.JavaPlatformPlugin;\n\nimport org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithHandler.PropertyHandler;\nimport org.springframework.boot.build.bom.BomExtension.LibraryHandler.AlignWithHandler.VersionHandler;\nimport org.springframework.boot.build.bom.Library.BomAlignment;\nimport org.springframework.boot.build.bom.Library.DependencyVersionAlignment;\nimport org.springframework.boot.build.bom.Library.Exclusion;\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.ImportedBom;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.Library.Link;\nimport org.springframework.boot.build.bom.Library.Module;\nimport org.springframework.boot.build.bom.Library.PermittedDependency;\nimport org.springframework.boot.build.bom.Library.PomPropertyVersionAlignment;\nimport org.springframework.boot.build.bom.Library.ProhibitedVersion;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.ResolvedBom.Id;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.boot.build.properties.BuildProperties;\nimport org.springframework.util.PropertyPlaceholderHelper;\nimport org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;\n\n/**\n * DSL extensions for {@link BomPlugin}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\npublic class BomExtension {\n\n\tprivate final String id;\n\n\tprivate final Project project;\n\n\tprivate final UpgradeHandler upgradeHandler;\n\n\tprivate final Map<String, DependencyVersion> properties = new LinkedHashMap<>();\n\n\tprivate final Map<String, String> artifactVersionProperties = new HashMap<>();\n\n\tprivate final List<Library> libraries = new ArrayList<>();\n\n\tpublic BomExtension(Project project) {\n\t\tthis.project = project;\n\t\tthis.upgradeHandler = project.getObjects().newInstance(UpgradeHandler.class, project);\n\t\tthis.id = \"%s:%s:%s\".formatted(project.getGroup(), project.getName(), project.getVersion());\n\t}\n\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic List<Library> getLibraries() {\n\t\treturn this.libraries;\n\t}\n\n\tpublic Library getLibrary(String name) {\n\t\treturn getLibraries().stream()\n\t\t\t.filter((library) -> library.getName().equals(name))\n\t\t\t.findFirst()\n\t\t\t.orElseThrow(() -> new IllegalStateException(\"No library found named '%s'\".formatted(name)));\n\t}\n\n\tpublic void upgrade(Action<UpgradeHandler> action) {\n\t\taction.execute(this.upgradeHandler);\n\t}\n\n\tpublic Upgrade getUpgrade() {\n\t\tGitHubHandler gitHub = this.upgradeHandler.gitHub;\n\t\treturn new Upgrade(this.upgradeHandler.upgradePolicy,\n\t\t\t\tnew GitHub(gitHub.organization, gitHub.repository, gitHub.issueLabels));\n\t}\n\n\tpublic void library(String name, Action<LibraryHandler> action) {\n\t\tlibrary(name, null, action);\n\t}\n\n\tpublic void library(String name, String version, Action<LibraryHandler> action) {\n\t\tObjectFactory objects = this.project.getObjects();\n\t\tLibraryHandler libraryHandler = objects.newInstance(LibraryHandler.class, this.project,\n\t\t\t\t(version != null) ? version : \"\");\n\t\taction.execute(libraryHandler);\n\t\tLibraryVersion libraryVersion = new LibraryVersion(DependencyVersion.parse(libraryHandler.version));\n\t\taddLibrary(new Library(name, libraryHandler.calendarName, libraryVersion, libraryHandler.groups,\n\t\t\t\tlibraryHandler.upgradePolicy, libraryHandler.prohibitedVersions, libraryHandler.considerSnapshots,\n\t\t\t\tversionAlignment(libraryHandler), libraryHandler.alignWith.bomAlignment, libraryHandler.linkRootName,\n\t\t\t\tlibraryHandler.links));\n\t}\n\n\tprivate VersionAlignment versionAlignment(LibraryHandler libraryHandler) {\n\t\tVersionHandler version = libraryHandler.alignWith.version;\n\t\tif (version != null) {\n\t\t\treturn new DependencyVersionAlignment(version.of, version.from, version.managedBy, this.project,\n\t\t\t\t\tthis.libraries, libraryHandler.groups);\n\t\t}\n\t\tPropertyHandler property = libraryHandler.alignWith.property;\n\t\tif (property != null) {\n\t\t\treturn new PomPropertyVersionAlignment(property.name, property.of, property.managedBy, this.project,\n\t\t\t\t\tthis.libraries);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String createDependencyNotation(String groupId, String artifactId, DependencyVersion version) {\n\t\treturn groupId + \":\" + artifactId + \":\" + version;\n\t}\n\n\tMap<String, DependencyVersion> getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tString getArtifactVersionProperty(String groupId, String artifactId, String classifier) {\n\t\tString coordinates = groupId + \":\" + artifactId + \":\" + classifier;\n\t\treturn this.artifactVersionProperties.get(coordinates);\n\t}\n\n\tprivate void putArtifactVersionProperty(String groupId, String artifactId, String versionProperty) {\n\t\tputArtifactVersionProperty(groupId, artifactId, null, versionProperty);\n\t}\n\n\tprivate void putArtifactVersionProperty(String groupId, String artifactId, String classifier,\n\t\t\tString versionProperty) {\n\t\tString coordinates = groupId + \":\" + artifactId + \":\" + ((classifier != null) ? classifier : \"\");\n\t\tString existing = this.artifactVersionProperties.putIfAbsent(coordinates, versionProperty);\n\t\tif (existing != null) {\n\t\t\tthrow new InvalidUserDataException(\"Cannot put version property for '\" + coordinates\n\t\t\t\t\t+ \"'. Version property '\" + existing + \"' has already been stored.\");\n\t\t}\n\t}\n\n\tprivate void addLibrary(Library library) {\n\t\tDependencyHandler dependencies = this.project.getDependencies();\n\t\tthis.libraries.add(library);\n\t\tString versionProperty = library.getVersionProperty();\n\t\tif (versionProperty != null) {\n\t\t\tthis.properties.put(versionProperty, library.getVersion().getVersion());\n\t\t}\n\t\tfor (Group group : library.getGroups()) {\n\t\t\tfor (Module module : group.getModules()) {\n\t\t\t\taddModule(library, dependencies, versionProperty, group, module);\n\t\t\t}\n\t\t\tfor (ImportedBom bomImport : group.getBoms()) {\n\t\t\t\taddBomImport(library, dependencies, versionProperty, group, bomImport.name());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addModule(Library library, DependencyHandler dependencies, String versionProperty, Group group,\n\t\t\tModule module) {\n\t\tputArtifactVersionProperty(group.getId(), module.getName(), module.getClassifier(), versionProperty);\n\t\tString constraint = createDependencyNotation(group.getId(), module.getName(),\n\t\t\t\tlibrary.getVersion().getVersion());\n\t\tdependencies.getConstraints().add(JavaPlatformPlugin.API_CONFIGURATION_NAME, constraint);\n\t}\n\n\tprivate void addBomImport(Library library, DependencyHandler dependencies, String versionProperty, Group group,\n\t\t\tString bomImport) {\n\t\tputArtifactVersionProperty(group.getId(), bomImport, versionProperty);\n\t\tString bomDependency = createDependencyNotation(group.getId(), bomImport, library.getVersion().getVersion());\n\t\tdependencies.add(JavaPlatformPlugin.API_CONFIGURATION_NAME, dependencies.platform(bomDependency));\n\t\tdependencies.add(BomPlugin.API_ENFORCED_CONFIGURATION_NAME, dependencies.enforcedPlatform(bomDependency));\n\t}\n\n\tpublic static class LibraryHandler {\n\n\t\tprivate final Project project;\n\n\t\tprivate final List<Group> groups = new ArrayList<>();\n\n\t\tprivate UpgradePolicy upgradePolicy;\n\n\t\tprivate final List<ProhibitedVersion> prohibitedVersions = new ArrayList<>();\n\n\t\tprivate final AlignWithHandler alignWith;\n\n\t\tprivate boolean considerSnapshots;\n\n\t\tprivate String version;\n\n\t\tprivate String calendarName;\n\n\t\tprivate String linkRootName;\n\n\t\tprivate final Map<String, List<Link>> links = new HashMap<>();\n\n\t\t@Inject\n\t\tpublic LibraryHandler(Project project, String version) {\n\t\t\tthis.project = project;\n\t\t\tthis.version = version;\n\t\t\tthis.alignWith = project.getObjects().newInstance(AlignWithHandler.class);\n\t\t}\n\n\t\tpublic void version(String version) {\n\t\t\tthis.version = version;\n\t\t}\n\n\t\tpublic void considerSnapshots() {\n\t\t\tthis.considerSnapshots = true;\n\t\t}\n\n\t\tpublic void setCalendarName(String calendarName) {\n\t\t\tthis.calendarName = calendarName;\n\t\t}\n\n\t\tpublic void group(String id, Action<GroupHandler> action) {\n\t\t\tGroupHandler groupHandler = this.project.getObjects().newInstance(GroupHandler.class, id);\n\t\t\taction.execute(groupHandler);\n\t\t\tthis.groups\n\t\t\t\t.add(new Group(groupHandler.id, groupHandler.modules, groupHandler.plugins, groupHandler.imports));\n\t\t}\n\n\t\tpublic void setUpgradePolicy(UpgradePolicy upgradePolicy) {\n\t\t\tthis.upgradePolicy = upgradePolicy;\n\t\t}\n\n\t\tpublic void prohibit(Action<ProhibitedHandler> action) {\n\t\t\tProhibitedHandler handler = new ProhibitedHandler();\n\t\t\taction.execute(handler);\n\t\t\tthis.prohibitedVersions.add(new ProhibitedVersion(handler.versionRange, handler.startsWith,\n\t\t\t\t\thandler.endsWith, handler.contains, handler.reason));\n\t\t}\n\n\t\tpublic void alignWith(Action<AlignWithHandler> action) {\n\t\t\taction.execute(this.alignWith);\n\t\t}\n\n\t\tpublic void links(Action<LinksHandler> action) {\n\t\t\tlinks(null, action);\n\t\t}\n\n\t\tpublic void links(String linkRootName, Action<LinksHandler> action) {\n\t\t\tLinksHandler handler = new LinksHandler();\n\t\t\taction.execute(handler);\n\t\t\tthis.linkRootName = linkRootName;\n\t\t\tthis.links.putAll(handler.links);\n\t\t}\n\n\t\tpublic static class ProhibitedHandler {\n\n\t\t\tprivate String reason;\n\n\t\t\tprivate final List<String> startsWith = new ArrayList<>();\n\n\t\t\tprivate final List<String> endsWith = new ArrayList<>();\n\n\t\t\tprivate final List<String> contains = new ArrayList<>();\n\n\t\t\tprivate VersionRange versionRange;\n\n\t\t\tpublic void versionRange(String versionRange) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.versionRange = VersionRange.createFromVersionSpec(versionRange);\n\t\t\t\t}\n\t\t\t\tcatch (InvalidVersionSpecificationException ex) {\n\t\t\t\t\tthrow new InvalidUserCodeException(\"Invalid version range\", ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic void startsWith(String startsWith) {\n\t\t\t\tthis.startsWith.add(startsWith);\n\t\t\t}\n\n\t\t\tpublic void startsWith(Collection<String> startsWith) {\n\t\t\t\tthis.startsWith.addAll(startsWith);\n\t\t\t}\n\n\t\t\tpublic void endsWith(String endsWith) {\n\t\t\t\tthis.endsWith.add(endsWith);\n\t\t\t}\n\n\t\t\tpublic void endsWith(Collection<String> endsWith) {\n\t\t\t\tthis.endsWith.addAll(endsWith);\n\t\t\t}\n\n\t\t\tpublic void contains(String contains) {\n\t\t\t\tthis.contains.add(contains);\n\t\t\t}\n\n\t\t\tpublic void contains(List<String> contains) {\n\t\t\t\tthis.contains.addAll(contains);\n\t\t\t}\n\n\t\t\tpublic void because(String because) {\n\t\t\t\tthis.reason = because;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class GroupHandler extends GroovyObjectSupport {\n\n\t\t\tprivate final String id;\n\n\t\t\tprivate List<Module> modules = new ArrayList<>();\n\n\t\t\tprivate List<ImportedBom> imports = new ArrayList<>();\n\n\t\t\tprivate List<String> plugins = new ArrayList<>();\n\n\t\t\t@Inject\n\t\t\tpublic GroupHandler(String id) {\n\t\t\t\tthis.id = id;\n\t\t\t}\n\n\t\t\tpublic void setModules(List<Object> modules) {\n\t\t\t\tthis.modules = modules.stream()\n\t\t\t\t\t.map((input) -> (input instanceof Module module) ? module : new Module((String) input))\n\t\t\t\t\t.toList();\n\t\t\t}\n\n\t\t\tpublic void bom(String bom) {\n\t\t\t\tthis.imports.add(new ImportedBom(bom));\n\t\t\t}\n\n\t\t\tpublic void bom(String bom, Action<ImportBomHandler> action) {\n\t\t\t\tImportBomHandler handler = new ImportBomHandler();\n\t\t\t\taction.execute(handler);\n\t\t\t\tthis.imports.add(new ImportedBom(bom, handler.permittedDependencies));\n\t\t\t}\n\n\t\t\tpublic void setPlugins(List<String> plugins) {\n\t\t\t\tthis.plugins = plugins;\n\t\t\t}\n\n\t\t\tpublic Object methodMissing(String name, Object args) {\n\t\t\t\tif (args instanceof Object[] argsArray && argsArray.length == 1) {\n\t\t\t\t\tif (argsArray[0] instanceof Closure<?> closure) {\n\t\t\t\t\t\tModuleHandler moduleHandler = new ModuleHandler();\n\t\t\t\t\t\tclosure.setResolveStrategy(Closure.DELEGATE_FIRST);\n\t\t\t\t\t\tclosure.setDelegate(moduleHandler);\n\t\t\t\t\t\tclosure.call(moduleHandler);\n\t\t\t\t\t\treturn new Module(name, moduleHandler.type, moduleHandler.classifier, moduleHandler.exclusions);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow new InvalidUserDataException(\"Invalid configuration for module '\" + name + \"'\");\n\t\t\t}\n\n\t\t\tpublic class ModuleHandler {\n\n\t\t\t\tprivate final List<Exclusion> exclusions = new ArrayList<>();\n\n\t\t\t\tprivate String type;\n\n\t\t\t\tprivate String classifier;\n\n\t\t\t\tpublic void exclude(Map<String, String> exclusion) {\n\t\t\t\t\tthis.exclusions.add(new Exclusion(exclusion.get(\"group\"), exclusion.get(\"module\")));\n\t\t\t\t}\n\n\t\t\t\tpublic void setType(String type) {\n\t\t\t\t\tthis.type = type;\n\t\t\t\t}\n\n\t\t\t\tpublic void setClassifier(String classifier) {\n\t\t\t\t\tthis.classifier = classifier;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tpublic class ImportBomHandler {\n\n\t\t\t\tprivate final List<PermittedDependency> permittedDependencies = new ArrayList<>();\n\n\t\t\t\tpublic void permit(String allowed) {\n\t\t\t\t\tString[] components = allowed.split(\":\");\n\t\t\t\t\tthis.permittedDependencies.add(new PermittedDependency(components[0], components[1]));\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class AlignWithHandler {\n\n\t\t\tprivate VersionHandler version;\n\n\t\t\tprivate PropertyHandler property;\n\n\t\t\tprivate BomAlignment bomAlignment;\n\n\t\t\tpublic void version(Action<VersionHandler> action) {\n\t\t\t\tthis.version = new VersionHandler();\n\t\t\t\taction.execute(this.version);\n\t\t\t}\n\n\t\t\tpublic void property(Action<PropertyHandler> action) {\n\t\t\t\tthis.property = new PropertyHandler();\n\t\t\t\taction.execute(this.property);\n\t\t\t}\n\n\t\t\tpublic void dependencyManagementDeclaredIn(String bomCoordinates) {\n\t\t\t\tthis.bomAlignment = new BomAlignment(bomCoordinates, (id) -> false);\n\t\t\t}\n\n\t\t\tpublic void dependencyManagementDeclaredIn(String bomCoordinates,\n\t\t\t\t\tAction<DependencyManagementDeclaredInHandler> action) {\n\t\t\t\tDependencyManagementDeclaredInHandler handler = new DependencyManagementDeclaredInHandler();\n\t\t\t\taction.execute(handler);\n\t\t\t\tthis.bomAlignment = new BomAlignment(bomCoordinates, handler.exclusions);\n\t\t\t}\n\n\t\t\tpublic static class VersionHandler {\n\n\t\t\t\tprivate String of;\n\n\t\t\t\tprivate String from;\n\n\t\t\t\tprivate String managedBy;\n\n\t\t\t\tpublic void of(String of) {\n\t\t\t\t\tthis.of = of;\n\t\t\t\t}\n\n\t\t\t\tpublic void from(String from) {\n\t\t\t\t\tthis.from = from;\n\t\t\t\t}\n\n\t\t\t\tpublic void managedBy(String managedBy) {\n\t\t\t\t\tthis.managedBy = managedBy;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tpublic static class PropertyHandler {\n\n\t\t\t\tprivate String name;\n\n\t\t\t\tprivate String of;\n\n\t\t\t\tprivate String managedBy;\n\n\t\t\t\tpublic void name(String name) {\n\t\t\t\t\tthis.name = name;\n\t\t\t\t}\n\n\t\t\t\tpublic void of(String dependency) {\n\t\t\t\t\tthis.of = dependency;\n\t\t\t\t}\n\n\t\t\t\tpublic void managedBy(String managedBy) {\n\t\t\t\t\tthis.managedBy = managedBy;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tpublic static class DependencyManagementDeclaredInHandler {\n\n\t\t\t\tprivate Predicate<Id> exclusions = (id) -> false;\n\n\t\t\t\tpublic void excluding(Predicate<Id> exclusion) {\n\t\t\t\t\tthis.exclusions = this.exclusions.or(exclusion);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class LinksHandler {\n\n\t\tprivate final Map<String, List<Link>> links = new HashMap<>();\n\n\t\tpublic void site(String linkTemplate) {\n\t\t\tsite(asFactory(linkTemplate));\n\t\t}\n\n\t\tpublic void site(Function<LibraryVersion, String> linkFactory) {\n\t\t\tadd(\"site\", linkFactory);\n\t\t}\n\n\t\tpublic void github(String linkTemplate) {\n\t\t\tgithub(asFactory(linkTemplate));\n\t\t}\n\n\t\tpublic void github(Function<LibraryVersion, String> linkFactory) {\n\t\t\tadd(\"github\", linkFactory);\n\t\t}\n\n\t\tpublic void docs(String linkTemplate) {\n\t\t\tdocs(asFactory(linkTemplate));\n\t\t}\n\n\t\tpublic void docs(Function<LibraryVersion, String> linkFactory) {\n\t\t\tadd(\"docs\", linkFactory);\n\t\t}\n\n\t\tpublic void javadoc(String linkTemplate) {\n\t\t\tjavadoc(asFactory(linkTemplate));\n\t\t}\n\n\t\tpublic void javadoc(String linkTemplate, String... packages) {\n\t\t\tjavadoc(asFactory(linkTemplate), packages);\n\t\t}\n\n\t\tpublic void javadoc(Function<LibraryVersion, String> linkFactory) {\n\t\t\tadd(\"javadoc\", linkFactory);\n\t\t}\n\n\t\tpublic void javadoc(Function<LibraryVersion, String> linkFactory, String... packages) {\n\t\t\tadd(\"javadoc\", linkFactory, packages);\n\t\t}\n\n\t\tpublic void javadoc(String rootName, Function<LibraryVersion, String> linkFactory, String... packages) {\n\t\t\tadd(rootName, \"javadoc\", linkFactory, packages);\n\t\t}\n\n\t\tpublic void releaseNotes(String linkTemplate) {\n\t\t\treleaseNotes(asFactory(linkTemplate));\n\t\t}\n\n\t\tpublic void releaseNotes(Function<LibraryVersion, String> linkFactory) {\n\t\t\tadd(\"releaseNotes\", linkFactory);\n\t\t}\n\n\t\tpublic void add(String name, String linkTemplate) {\n\t\t\tadd(name, asFactory(linkTemplate));\n\t\t}\n\n\t\tpublic void add(String name, Function<LibraryVersion, String> linkFactory) {\n\t\t\tadd(name, linkFactory, null);\n\t\t}\n\n\t\tpublic void add(String name, Function<LibraryVersion, String> linkFactory, String[] packages) {\n\t\t\tadd(null, name, linkFactory, packages);\n\t\t}\n\n\t\tprivate void add(String rootName, String name, Function<LibraryVersion, String> linkFactory,\n\t\t\t\tString[] packages) {\n\t\t\tLink link = new Link(rootName, linkFactory, (packages != null) ? List.of(packages) : null);\n\t\t\tthis.links.computeIfAbsent(name, (key) -> new ArrayList<>()).add(link);\n\t\t}\n\n\t\tprivate Function<LibraryVersion, String> asFactory(String linkTemplate) {\n\t\t\treturn (version) -> {\n\t\t\t\tPlaceholderResolver resolver = (name) -> \"version\".equals(name) ? version.toString() : null;\n\t\t\t\treturn new PropertyPlaceholderHelper(\"{\", \"}\").replacePlaceholders(linkTemplate, resolver);\n\t\t\t};\n\t\t}\n\n\t}\n\n\tpublic static class UpgradeHandler {\n\n\t\tprivate UpgradePolicy upgradePolicy;\n\n\t\tprivate final GitHubHandler gitHub;\n\n\t\t@Inject\n\t\tpublic UpgradeHandler(Project project) {\n\t\t\tthis.gitHub = new GitHubHandler(project);\n\t\t}\n\n\t\tpublic void setPolicy(UpgradePolicy upgradePolicy) {\n\t\t\tthis.upgradePolicy = upgradePolicy;\n\t\t}\n\n\t\tpublic void gitHub(Action<GitHubHandler> action) {\n\t\t\taction.execute(this.gitHub);\n\t\t}\n\n\t}\n\n\tpublic static final class Upgrade {\n\n\t\tprivate final UpgradePolicy upgradePolicy;\n\n\t\tprivate final GitHub gitHub;\n\n\t\tprivate Upgrade(UpgradePolicy upgradePolicy, GitHub gitHub) {\n\t\t\tthis.upgradePolicy = upgradePolicy;\n\t\t\tthis.gitHub = gitHub;\n\t\t}\n\n\t\tpublic UpgradePolicy getPolicy() {\n\t\t\treturn this.upgradePolicy;\n\t\t}\n\n\t\tpublic GitHub getGitHub() {\n\t\t\treturn this.gitHub;\n\t\t}\n\n\t}\n\n\tpublic static class GitHubHandler {\n\n\t\tprivate String organization;\n\n\t\tprivate String repository;\n\n\t\tprivate List<String> issueLabels;\n\n\t\tpublic GitHubHandler(Project project) {\n\t\t\tBuildProperties buildProperties = BuildProperties.get(project);\n\t\t\tthis.organization = buildProperties.gitHub().organization();\n\t\t\tthis.repository = buildProperties.gitHub().repository();\n\t\t}\n\n\t\tpublic void setOrganization(String organization) {\n\t\t\tthis.organization = organization;\n\t\t}\n\n\t\tpublic void setRepository(String repository) {\n\t\t\tthis.repository = repository;\n\t\t}\n\n\t\tpublic void setIssueLabels(List<String> issueLabels) {\n\t\t\tthis.issueLabels = issueLabels;\n\t\t}\n\n\t}\n\n\tpublic static final class GitHub {\n\n\t\tprivate final String organization;\n\n\t\tprivate final String repository;\n\n\t\tprivate final List<String> issueLabels;\n\n\t\tprivate GitHub(String organization, String repository, List<String> issueLabels) {\n\t\t\tthis.organization = organization;\n\t\t\tthis.repository = repository;\n\t\t\tthis.issueLabels = issueLabels;\n\t\t}\n\n\t\tpublic String getOrganization() {\n\t\t\treturn this.organization;\n\t\t}\n\n\t\tpublic String getRepository() {\n\t\t\treturn this.repository;\n\t\t}\n\n\t\tpublic List<String> getIssueLabels() {\n\t\t\treturn this.issueLabels;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/BomPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport groovy.namespace.QName;\nimport groovy.util.Node;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.plugins.JavaPlatformExtension;\nimport org.gradle.api.plugins.JavaPlatformPlugin;\nimport org.gradle.api.plugins.PluginContainer;\nimport org.gradle.api.publish.PublishingExtension;\nimport org.gradle.api.publish.maven.MavenPom;\nimport org.gradle.api.publish.maven.MavenPublication;\nimport org.gradle.api.tasks.TaskProvider;\n\nimport org.springframework.boot.build.MavenRepositoryPlugin;\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.Module;\nimport org.springframework.boot.build.bom.bomr.MoveToSnapshots;\nimport org.springframework.boot.build.bom.bomr.UpgradeBom;\n\n/**\n * {@link Plugin} for defining a bom. Dependencies are added as constraints in the\n * {@code api} configuration. Imported boms are added as enforced platforms in the\n * {@code api} configuration.\n *\n * @author Andy Wilkinson\n */\npublic class BomPlugin implements Plugin<Project> {\n\n\tstatic final String API_ENFORCED_CONFIGURATION_NAME = \"apiEnforced\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tPluginContainer plugins = project.getPlugins();\n\t\tplugins.apply(MavenRepositoryPlugin.class);\n\t\tplugins.apply(JavaPlatformPlugin.class);\n\t\tJavaPlatformExtension javaPlatform = project.getExtensions().getByType(JavaPlatformExtension.class);\n\t\tjavaPlatform.allowDependencies();\n\t\tcreateApiEnforcedConfiguration(project);\n\t\tBomExtension bom = project.getExtensions().create(\"bom\", BomExtension.class, project);\n\t\tTaskProvider<CreateResolvedBom> createResolvedBom = project.getTasks()\n\t\t\t.register(\"createResolvedBom\", CreateResolvedBom.class, bom);\n\t\tTaskProvider<CheckBom> checkBom = project.getTasks().register(\"bomrCheck\", CheckBom.class, bom);\n\t\tcheckBom.configure(\n\t\t\t\t(task) -> task.getResolvedBomFile().set(createResolvedBom.flatMap(CreateResolvedBom::getOutputFile)));\n\t\tproject.getTasks().named(\"check\").configure((check) -> check.dependsOn(checkBom));\n\t\tproject.getTasks().register(\"bomrUpgrade\", UpgradeBom.class, bom);\n\t\tproject.getTasks().register(\"moveToSnapshots\", MoveToSnapshots.class, bom);\n\t\tproject.getTasks().register(\"checkLinks\", CheckLinks.class, bom);\n\t\tConfiguration resolvedBomConfiguration = project.getConfigurations().create(\"resolvedBom\");\n\t\tproject.getArtifacts()\n\t\t\t.add(resolvedBomConfiguration.getName(), createResolvedBom.map(CreateResolvedBom::getOutputFile),\n\t\t\t\t\t(artifact) -> artifact.builtBy(createResolvedBom));\n\t\tnew PublishingCustomizer(project, bom).customize();\n\t}\n\n\tprivate void createApiEnforcedConfiguration(Project project) {\n\t\tConfiguration apiEnforced = project.getConfigurations()\n\t\t\t.create(API_ENFORCED_CONFIGURATION_NAME, (configuration) -> {\n\t\t\t\tconfiguration.setCanBeConsumed(false);\n\t\t\t\tconfiguration.setCanBeResolved(false);\n\t\t\t\tconfiguration.setVisible(false);\n\t\t\t});\n\t\tproject.getConfigurations()\n\t\t\t.getByName(JavaPlatformPlugin.ENFORCED_API_ELEMENTS_CONFIGURATION_NAME)\n\t\t\t.extendsFrom(apiEnforced);\n\t\tproject.getConfigurations()\n\t\t\t.getByName(JavaPlatformPlugin.ENFORCED_RUNTIME_ELEMENTS_CONFIGURATION_NAME)\n\t\t\t.extendsFrom(apiEnforced);\n\t}\n\n\tprivate static final class PublishingCustomizer {\n\n\t\tprivate final Project project;\n\n\t\tprivate final BomExtension bom;\n\n\t\tprivate PublishingCustomizer(Project project, BomExtension bom) {\n\t\t\tthis.project = project;\n\t\t\tthis.bom = bom;\n\t\t}\n\n\t\tprivate void customize() {\n\t\t\tPublishingExtension publishing = this.project.getExtensions().getByType(PublishingExtension.class);\n\t\t\tpublishing.getPublications().withType(MavenPublication.class).all(this::configurePublication);\n\t\t}\n\n\t\tprivate void configurePublication(MavenPublication publication) {\n\t\t\tpublication.pom(this::customizePom);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate void customizePom(MavenPom pom) {\n\t\t\tpom.withXml((xml) -> {\n\t\t\t\tNode projectNode = xml.asNode();\n\t\t\t\tNode properties = new Node(null, \"properties\");\n\t\t\t\tthis.bom.getProperties().forEach(properties::appendNode);\n\t\t\t\tNode dependencyManagement = findChild(projectNode, \"dependencyManagement\");\n\t\t\t\tif (dependencyManagement != null) {\n\t\t\t\t\taddPropertiesBeforeDependencyManagement(projectNode, properties);\n\t\t\t\t\taddClassifiedManagedDependencies(dependencyManagement);\n\t\t\t\t\treplaceVersionsWithVersionPropertyReferences(dependencyManagement);\n\t\t\t\t\taddExclusionsToManagedDependencies(dependencyManagement);\n\t\t\t\t\taddTypesToManagedDependencies(dependencyManagement);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tprojectNode.children().add(properties);\n\t\t\t\t}\n\t\t\t\taddPluginManagement(projectNode);\n\t\t\t});\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate void addPropertiesBeforeDependencyManagement(Node projectNode, Node properties) {\n\t\t\tfor (int i = 0; i < projectNode.children().size(); i++) {\n\t\t\t\tif (isNodeWithName(projectNode.children().get(i), \"dependencyManagement\")) {\n\t\t\t\t\tprojectNode.children().add(i, properties);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void replaceVersionsWithVersionPropertyReferences(Node dependencyManagement) {\n\t\t\tNode dependencies = findChild(dependencyManagement, \"dependencies\");\n\t\t\tif (dependencies != null) {\n\t\t\t\tfor (Node dependency : findChildren(dependencies, \"dependency\")) {\n\t\t\t\t\tString groupId = findChild(dependency, \"groupId\").text();\n\t\t\t\t\tString artifactId = findChild(dependency, \"artifactId\").text();\n\t\t\t\t\tNode classifierNode = findChild(dependency, \"classifier\");\n\t\t\t\t\tString classifier = (classifierNode != null) ? classifierNode.text() : \"\";\n\t\t\t\t\tString versionProperty = this.bom.getArtifactVersionProperty(groupId, artifactId, classifier);\n\t\t\t\t\tif (versionProperty != null) {\n\t\t\t\t\t\tfindChild(dependency, \"version\").setValue(\"${\" + versionProperty + \"}\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void addExclusionsToManagedDependencies(Node dependencyManagement) {\n\t\t\tNode dependencies = findChild(dependencyManagement, \"dependencies\");\n\t\t\tif (dependencies != null) {\n\t\t\t\tfor (Node dependency : findChildren(dependencies, \"dependency\")) {\n\t\t\t\t\tString groupId = findChild(dependency, \"groupId\").text();\n\t\t\t\t\tString artifactId = findChild(dependency, \"artifactId\").text();\n\t\t\t\t\tthis.bom.getLibraries()\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.flatMap((library) -> library.getGroups().stream())\n\t\t\t\t\t\t.filter((group) -> group.getId().equals(groupId))\n\t\t\t\t\t\t.flatMap((group) -> group.getModules().stream())\n\t\t\t\t\t\t.filter((module) -> module.getName().equals(artifactId))\n\t\t\t\t\t\t.flatMap((module) -> module.getExclusions().stream())\n\t\t\t\t\t\t.forEach((exclusion) -> {\n\t\t\t\t\t\t\tNode exclusions = findOrCreateNode(dependency, \"exclusions\");\n\t\t\t\t\t\t\tNode node = new Node(exclusions, \"exclusion\");\n\t\t\t\t\t\t\tnode.appendNode(\"groupId\", exclusion.getGroupId());\n\t\t\t\t\t\t\tnode.appendNode(\"artifactId\", exclusion.getArtifactId());\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void addTypesToManagedDependencies(Node dependencyManagement) {\n\t\t\tNode dependencies = findChild(dependencyManagement, \"dependencies\");\n\t\t\tif (dependencies != null) {\n\t\t\t\tfor (Node dependency : findChildren(dependencies, \"dependency\")) {\n\t\t\t\t\tString groupId = findChild(dependency, \"groupId\").text();\n\t\t\t\t\tString artifactId = findChild(dependency, \"artifactId\").text();\n\t\t\t\t\tSet<String> types = this.bom.getLibraries()\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.flatMap((library) -> library.getGroups().stream())\n\t\t\t\t\t\t.filter((group) -> group.getId().equals(groupId))\n\t\t\t\t\t\t.flatMap((group) -> group.getModules().stream())\n\t\t\t\t\t\t.filter((module) -> module.getName().equals(artifactId))\n\t\t\t\t\t\t.map(Module::getType)\n\t\t\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t\t\t.collect(Collectors.toSet());\n\t\t\t\t\tif (types.size() > 1) {\n\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\"Multiple types for \" + groupId + \":\" + artifactId + \": \" + types);\n\t\t\t\t\t}\n\t\t\t\t\tif (types.size() == 1) {\n\t\t\t\t\t\tString type = types.iterator().next();\n\t\t\t\t\t\tdependency.appendNode(\"type\", type);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate void addClassifiedManagedDependencies(Node dependencyManagement) {\n\t\t\tNode dependencies = findChild(dependencyManagement, \"dependencies\");\n\t\t\tif (dependencies != null) {\n\t\t\t\tfor (Node dependency : findChildren(dependencies, \"dependency\")) {\n\t\t\t\t\tString groupId = findChild(dependency, \"groupId\").text();\n\t\t\t\t\tString artifactId = findChild(dependency, \"artifactId\").text();\n\t\t\t\t\tString version = findChild(dependency, \"version\").text();\n\t\t\t\t\tSet<String> classifiers = this.bom.getLibraries()\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.flatMap((library) -> library.getGroups().stream())\n\t\t\t\t\t\t.filter((group) -> group.getId().equals(groupId))\n\t\t\t\t\t\t.flatMap((group) -> group.getModules().stream())\n\t\t\t\t\t\t.filter((module) -> module.getName().equals(artifactId))\n\t\t\t\t\t\t.map(Module::getClassifier)\n\t\t\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t\t\t.collect(Collectors.toSet());\n\t\t\t\t\tNode target = dependency;\n\t\t\t\t\tfor (String classifier : classifiers) {\n\t\t\t\t\t\tif (!classifier.isEmpty()) {\n\t\t\t\t\t\t\tif (target == null) {\n\t\t\t\t\t\t\t\ttarget = new Node(null, \"dependency\");\n\t\t\t\t\t\t\t\ttarget.appendNode(\"groupId\", groupId);\n\t\t\t\t\t\t\t\ttarget.appendNode(\"artifactId\", artifactId);\n\t\t\t\t\t\t\t\ttarget.appendNode(\"version\", version);\n\t\t\t\t\t\t\t\tint index = dependency.parent().children().indexOf(dependency);\n\t\t\t\t\t\t\t\tdependency.parent().children().add(index + 1, target);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttarget.appendNode(\"classifier\", classifier);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttarget = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void addPluginManagement(Node projectNode) {\n\t\t\tfor (Library library : this.bom.getLibraries()) {\n\t\t\t\tfor (Group group : library.getGroups()) {\n\t\t\t\t\tNode plugins = findOrCreateNode(projectNode, \"build\", \"pluginManagement\", \"plugins\");\n\t\t\t\t\tfor (String pluginName : group.getPlugins()) {\n\t\t\t\t\t\tNode plugin = new Node(plugins, \"plugin\");\n\t\t\t\t\t\tplugin.appendNode(\"groupId\", group.getId());\n\t\t\t\t\t\tplugin.appendNode(\"artifactId\", pluginName);\n\t\t\t\t\t\tString versionProperty = library.getVersionProperty();\n\t\t\t\t\t\tString value = (versionProperty != null) ? \"${\" + versionProperty + \"}\"\n\t\t\t\t\t\t\t\t: library.getVersion().getVersion().toString();\n\t\t\t\t\t\tplugin.appendNode(\"version\", value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate Node findOrCreateNode(Node parent, String... path) {\n\t\t\tNode current = parent;\n\t\t\tfor (String nodeName : path) {\n\t\t\t\tNode child = findChild(current, nodeName);\n\t\t\t\tif (child == null) {\n\t\t\t\t\tchild = new Node(current, nodeName);\n\t\t\t\t}\n\t\t\t\tcurrent = child;\n\t\t\t}\n\t\t\treturn current;\n\t\t}\n\n\t\tprivate Node findChild(Node parent, String name) {\n\t\t\tfor (Object child : parent.children()) {\n\t\t\t\tif (isNodeWithName(child, name)) {\n\t\t\t\t\treturn (Node) child;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate List<Node> findChildren(Node parent, String name) {\n\t\t\treturn parent.children().stream().filter((child) -> isNodeWithName(child, name)).toList();\n\t\t}\n\n\t\tprivate boolean isNodeWithName(Object candidate, String name) {\n\t\t\tif (candidate instanceof Node node) {\n\t\t\t\tif ((node.name() instanceof QName qname) && name.equals(qname.getLocalPart())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn name.equals(node.name());\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/BomResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport javax.xml.namespace.QName;\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.artifacts.ResolvedArtifact;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NodeList;\n\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.ImportedBom;\nimport org.springframework.boot.build.bom.Library.Link;\nimport org.springframework.boot.build.bom.Library.Module;\nimport org.springframework.boot.build.bom.ResolvedBom.Bom;\nimport org.springframework.boot.build.bom.ResolvedBom.Id;\nimport org.springframework.boot.build.bom.ResolvedBom.JavadocLink;\nimport org.springframework.boot.build.bom.ResolvedBom.Links;\nimport org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;\n\n/**\n * Creates a {@link ResolvedBom resolved bom}.\n *\n * @author Andy Wilkinson\n */\nclass BomResolver {\n\n\tprivate final ConfigurationContainer configurations;\n\n\tprivate final DependencyHandler dependencies;\n\n\tprivate final DocumentBuilder documentBuilder;\n\n\tBomResolver(ConfigurationContainer configurations, DependencyHandler dependencies) {\n\t\tthis.configurations = configurations;\n\t\tthis.dependencies = dependencies;\n\t\ttry {\n\t\t\tthis.documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();\n\t\t}\n\t\tcatch (ParserConfigurationException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tResolvedBom resolve(BomExtension bomExtension) {\n\t\tList<ResolvedLibrary> libraries = new ArrayList<>();\n\t\tfor (Library library : bomExtension.getLibraries()) {\n\t\t\tList<Id> managedDependencies = new ArrayList<>();\n\t\t\tList<Bom> imports = new ArrayList<>();\n\t\t\tfor (Group group : library.getGroups()) {\n\t\t\t\tfor (Module module : group.getModules()) {\n\t\t\t\t\tId id = new Id(group.getId(), module.getName(), library.getVersion().getVersion().toString());\n\t\t\t\t\tmanagedDependencies.add(id);\n\t\t\t\t}\n\t\t\t\tfor (ImportedBom imported : group.getBoms()) {\n\t\t\t\t\tBom bom = bomFrom(resolveBom(\n\t\t\t\t\t\t\t\"%s:%s:%s\".formatted(group.getId(), imported.name(), library.getVersion().getVersion())));\n\t\t\t\t\timports.add(bom);\n\t\t\t\t}\n\t\t\t}\n\t\t\tList<JavadocLink> javadocLinks = javadocLinksOf(library).stream()\n\t\t\t\t.map((link) -> new JavadocLink(URI.create(link.url(library)), link.packages()))\n\t\t\t\t.toList();\n\t\t\tResolvedLibrary resolvedLibrary = new ResolvedLibrary(library.getName(),\n\t\t\t\t\tlibrary.getVersion().getVersion().toString(), library.getVersionProperty(), managedDependencies,\n\t\t\t\t\timports, new Links(javadocLinks));\n\t\t\tlibraries.add(resolvedLibrary);\n\t\t}\n\t\tString[] idComponents = bomExtension.getId().split(\":\");\n\t\treturn new ResolvedBom(new Id(idComponents[0], idComponents[1], idComponents[2]), libraries);\n\t}\n\n\tprivate List<Link> javadocLinksOf(Library library) {\n\t\tList<Link> javadocLinks = library.getLinks(\"javadoc\");\n\t\treturn (javadocLinks != null) ? javadocLinks : Collections.emptyList();\n\t}\n\n\tBom resolveMavenBom(String coordinates) {\n\t\treturn bomFrom(resolveBom(coordinates));\n\t}\n\n\tprivate File resolveBom(String coordinates) {\n\t\tSet<ResolvedArtifact> artifacts = this.configurations\n\t\t\t.detachedConfiguration(this.dependencies.create(coordinates + \"@pom\"))\n\t\t\t.getResolvedConfiguration()\n\t\t\t.getResolvedArtifacts();\n\t\tif (artifacts.size() != 1) {\n\t\t\tthrow new IllegalStateException(\"Expected a single artifact but '%s' resolved to %d artifacts\"\n\t\t\t\t.formatted(coordinates, artifacts.size()));\n\t\t}\n\t\treturn artifacts.iterator().next().getFile();\n\t}\n\n\tprivate Bom bomFrom(File bomFile) {\n\t\ttry {\n\t\t\tNode bom = nodeFrom(bomFile);\n\t\t\tFile parentBomFile = parentBomFile(bom);\n\t\t\tBom parent = null;\n\t\t\tif (parentBomFile != null) {\n\t\t\t\tparent = bomFrom(parentBomFile);\n\t\t\t}\n\t\t\tProperties properties = Properties.from(bom, this::nodeFrom);\n\t\t\tList<Node> dependencyNodes = bom.nodesAt(\"/project/dependencyManagement/dependencies/dependency\");\n\t\t\tList<Id> managedDependencies = new ArrayList<>();\n\t\t\tList<Bom> imports = new ArrayList<>();\n\t\t\tfor (Node dependency : dependencyNodes) {\n\t\t\t\tString groupId = properties.replace(dependency.textAt(\"groupId\"));\n\t\t\t\tString artifactId = properties.replace(dependency.textAt(\"artifactId\"));\n\t\t\t\tString version = properties.replace(dependency.textAt(\"version\"));\n\t\t\t\tString classifier = properties.replace(dependency.textAt(\"classifier\"));\n\t\t\t\tString scope = properties.replace(dependency.textAt(\"scope\"));\n\t\t\t\tBom importedBom = null;\n\t\t\t\tif (\"import\".equals(scope)) {\n\t\t\t\t\tString type = properties.replace(dependency.textAt(\"type\"));\n\t\t\t\t\tif (\"pom\".equals(type)) {\n\t\t\t\t\t\timportedBom = bomFrom(resolveBom(groupId + \":\" + artifactId + \":\" + version));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (importedBom != null) {\n\t\t\t\t\timports.add(importedBom);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tmanagedDependencies.add(new Id(groupId, artifactId, version, classifier));\n\t\t\t\t}\n\t\t\t}\n\t\t\tString groupId = bom.textAt(\"/project/groupId\");\n\t\t\tif ((groupId == null || groupId.isEmpty()) && parent != null) {\n\t\t\t\tgroupId = parent.id().groupId();\n\t\t\t}\n\t\t\tString artifactId = bom.textAt(\"/project/artifactId\");\n\t\t\tString version = bom.textAt(\"/project/version\");\n\t\t\tif ((version == null || version.isEmpty()) && parent != null) {\n\t\t\t\tversion = parent.id().version();\n\t\t\t}\n\t\t\treturn new Bom(new Id(groupId, artifactId, version), parent, managedDependencies, imports);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate Node nodeFrom(String coordinates) {\n\t\treturn nodeFrom(resolveBom(coordinates));\n\t}\n\n\tprivate Node nodeFrom(File bomFile) {\n\t\ttry {\n\t\t\tDocument document = this.documentBuilder.parse(bomFile);\n\t\t\treturn new Node(document);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate File parentBomFile(Node bom) {\n\t\tNode parent = bom.nodeAt(\"/project/parent\");\n\t\tif (parent != null) {\n\t\t\tString parentGroupId = parent.textAt(\"groupId\");\n\t\t\tString parentArtifactId = parent.textAt(\"artifactId\");\n\t\t\tString parentVersion = parent.textAt(\"version\");\n\t\t\treturn resolveBom(parentGroupId + \":\" + parentArtifactId + \":\" + parentVersion);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static final class Node {\n\n\t\tprivate final XPath xpath;\n\n\t\tprivate final org.w3c.dom.Node delegate;\n\n\t\tprivate Node(org.w3c.dom.Node delegate) {\n\t\t\tthis(delegate, XPathFactory.newInstance().newXPath());\n\t\t}\n\n\t\tprivate Node(org.w3c.dom.Node delegate, XPath xpath) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.xpath = xpath;\n\t\t}\n\n\t\tprivate String textAt(String expression) {\n\t\t\tString text = (String) evaluate(expression + \"/text()\", XPathConstants.STRING);\n\t\t\treturn (text != null && !text.isBlank()) ? text : null;\n\t\t}\n\n\t\tprivate Node nodeAt(String expression) {\n\t\t\torg.w3c.dom.Node result = (org.w3c.dom.Node) evaluate(expression, XPathConstants.NODE);\n\t\t\treturn (result != null) ? new Node(result, this.xpath) : null;\n\t\t}\n\n\t\tprivate List<Node> nodesAt(String expression) {\n\t\t\tNodeList nodes = (NodeList) evaluate(expression, XPathConstants.NODESET);\n\t\t\tList<Node> things = new ArrayList<>(nodes.getLength());\n\t\t\tfor (int i = 0; i < nodes.getLength(); i++) {\n\t\t\t\tthings.add(new Node(nodes.item(i), this.xpath));\n\t\t\t}\n\t\t\treturn things;\n\t\t}\n\n\t\tprivate Object evaluate(String expression, QName type) {\n\t\t\ttry {\n\t\t\t\treturn this.xpath.evaluate(expression, this.delegate, type);\n\t\t\t}\n\t\t\tcatch (XPathExpressionException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate String name() {\n\t\t\treturn this.delegate.getNodeName();\n\t\t}\n\n\t\tprivate String textContent() {\n\t\t\treturn this.delegate.getTextContent();\n\t\t}\n\n\t}\n\n\tprivate static final class Properties {\n\n\t\tprivate final Map<String, String> properties;\n\n\t\tprivate Properties(Map<String, String> properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\tprivate static Properties from(Node bom, Function<String, Node> resolver) {\n\t\t\ttry {\n\t\t\t\tMap<String, String> properties = new HashMap<>();\n\t\t\t\tNode current = bom;\n\t\t\t\twhile (current != null) {\n\t\t\t\t\tString groupId = current.textAt(\"/project/groupId\");\n\t\t\t\t\tif (groupId != null && !groupId.isEmpty()) {\n\t\t\t\t\t\tproperties.putIfAbsent(\"${project.groupId}\", groupId);\n\t\t\t\t\t}\n\t\t\t\t\tString version = current.textAt(\"/project/version\");\n\t\t\t\t\tif (version != null && !version.isEmpty()) {\n\t\t\t\t\t\tproperties.putIfAbsent(\"${project.version}\", version);\n\t\t\t\t\t}\n\t\t\t\t\tList<Node> propertyNodes = current.nodesAt(\"/project/properties/*\");\n\t\t\t\t\tfor (Node property : propertyNodes) {\n\t\t\t\t\t\tproperties.putIfAbsent(\"${%s}\".formatted(property.name()), property.textContent());\n\t\t\t\t\t}\n\t\t\t\t\tcurrent = parent(current, resolver);\n\t\t\t\t}\n\t\t\t\treturn new Properties(properties);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate static Node parent(Node current, Function<String, Node> resolver) {\n\t\t\tNode parent = current.nodeAt(\"/project/parent\");\n\t\t\tif (parent != null) {\n\t\t\t\tString parentGroupId = parent.textAt(\"groupId\");\n\t\t\t\tString parentArtifactId = parent.textAt(\"artifactId\");\n\t\t\t\tString parentVersion = parent.textAt(\"version\");\n\t\t\t\treturn resolver.apply(parentGroupId + \":\" + parentArtifactId + \":\" + parentVersion);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate String replace(String input) {\n\t\t\tif (input != null && input.startsWith(\"${\") && input.endsWith(\"}\")) {\n\t\t\t\tString value = this.properties.get(input);\n\t\t\t\tif (value != null) {\n\t\t\t\t\treturn replace(value);\n\t\t\t\t}\n\t\t\t\tthrow new IllegalStateException(\"No replacement for \" + input);\n\t\t\t}\n\t\t\treturn input;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/CheckBom.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport javax.inject.Inject;\n\nimport org.apache.maven.artifact.versioning.ArtifactVersion;\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\nimport org.apache.maven.artifact.versioning.Restriction;\nimport org.apache.maven.artifact.versioning.VersionRange;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.file.RegularFile;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\nimport org.springframework.boot.build.bom.Library.BomAlignment;\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.ImportedBom;\nimport org.springframework.boot.build.bom.Library.Module;\nimport org.springframework.boot.build.bom.Library.PermittedDependency;\nimport org.springframework.boot.build.bom.Library.ProhibitedVersion;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.ResolvedBom.Bom;\nimport org.springframework.boot.build.bom.ResolvedBom.Id;\nimport org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\n/**\n * Checks the validity of a bom.\n *\n * @author Andy Wilkinson\n * @author Wick Dynex\n */\npublic abstract class CheckBom extends DefaultTask {\n\n\tprivate final BomExtension bom;\n\n\tprivate final List<LibraryCheck> checks;\n\n\t@Inject\n\tpublic CheckBom(BomExtension bom) {\n\t\tConfigurationContainer configurations = getProject().getConfigurations();\n\t\tDependencyHandler dependencies = getProject().getDependencies();\n\t\tProvider<ResolvedBom> resolvedBom = getResolvedBomFile().map(RegularFile::getAsFile).map(ResolvedBom::readFrom);\n\t\tthis.checks = List.of(new CheckExclusions(configurations, dependencies), new CheckProhibitedVersions(),\n\t\t\t\tnew CheckVersionAlignment(),\n\t\t\t\tnew CheckDependencyManagementAlignment(resolvedBom, configurations, dependencies),\n\t\t\t\tnew CheckForUnwantedDependencyManagement(resolvedBom));\n\t\tthis.bom = bom;\n\t}\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract RegularFileProperty getResolvedBomFile();\n\n\t@TaskAction\n\tvoid checkBom() {\n\t\tList<String> errors = new ArrayList<>();\n\t\tfor (Library library : this.bom.getLibraries()) {\n\t\t\terrors.addAll(checkLibrary(library));\n\t\t}\n\t\tif (!errors.isEmpty()) {\n\t\t\tSystem.out.println();\n\t\t\terrors.forEach(System.out::println);\n\t\t\tSystem.out.println();\n\t\t\tthrow new VerificationException(\"Bom check failed. See previous output for details.\");\n\t\t}\n\t}\n\n\tprivate List<String> checkLibrary(Library library) {\n\t\tList<String> libraryErrors = new ArrayList<>();\n\t\tthis.checks.stream().flatMap((check) -> check.check(library).stream()).forEach(libraryErrors::add);\n\t\tList<String> errors = new ArrayList<>();\n\t\tif (!libraryErrors.isEmpty()) {\n\t\t\terrors.add(library.getName());\n\t\t\tfor (String libraryError : libraryErrors) {\n\t\t\t\terrors.add(\"    - \" + libraryError);\n\t\t\t}\n\t\t}\n\t\treturn errors;\n\t}\n\n\tprivate interface LibraryCheck {\n\n\t\tList<String> check(Library library);\n\n\t}\n\n\tprivate static final class CheckExclusions implements LibraryCheck {\n\n\t\tprivate final ConfigurationContainer configurations;\n\n\t\tprivate final DependencyHandler dependencies;\n\n\t\tprivate CheckExclusions(ConfigurationContainer configurations, DependencyHandler dependencies) {\n\t\t\tthis.configurations = configurations;\n\t\t\tthis.dependencies = dependencies;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> check(Library library) {\n\t\t\tList<String> errors = new ArrayList<>();\n\t\t\tfor (Group group : library.getGroups()) {\n\t\t\t\tfor (Module module : group.getModules()) {\n\t\t\t\t\tif (!module.getExclusions().isEmpty()) {\n\t\t\t\t\t\tcheckExclusions(group.getId(), module, library.getVersion().getVersion(), errors);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn errors;\n\t\t}\n\n\t\tprivate void checkExclusions(String groupId, Module module, DependencyVersion version, List<String> errors) {\n\t\t\tSet<String> resolved = this.configurations\n\t\t\t\t.detachedConfiguration(this.dependencies.create(groupId + \":\" + module.getName() + \":\" + version))\n\t\t\t\t.getResolvedConfiguration()\n\t\t\t\t.getResolvedArtifacts()\n\t\t\t\t.stream()\n\t\t\t\t.map((artifact) -> artifact.getModuleVersion().getId())\n\t\t\t\t.map((id) -> id.getGroup() + \":\" + id.getModule().getName())\n\t\t\t\t.collect(Collectors.toSet());\n\t\t\tSet<String> exclusions = module.getExclusions()\n\t\t\t\t.stream()\n\t\t\t\t.map((exclusion) -> exclusion.getGroupId() + \":\" + exclusion.getArtifactId())\n\t\t\t\t.collect(Collectors.toSet());\n\t\t\tSet<String> unused = new TreeSet<>();\n\t\t\tfor (String exclusion : exclusions) {\n\t\t\t\tif (!resolved.contains(exclusion)) {\n\t\t\t\t\tif (exclusion.endsWith(\":*\")) {\n\t\t\t\t\t\tString group = exclusion.substring(0, exclusion.indexOf(':') + 1);\n\t\t\t\t\t\tif (resolved.stream().noneMatch((candidate) -> candidate.startsWith(group))) {\n\t\t\t\t\t\t\tunused.add(exclusion);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tunused.add(exclusion);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\texclusions.removeAll(resolved);\n\t\t\tif (!unused.isEmpty()) {\n\t\t\t\terrors.add(\"Unnecessary exclusions on \" + groupId + \":\" + module.getName() + \": \" + exclusions);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static final class CheckProhibitedVersions implements LibraryCheck {\n\n\t\t@Override\n\t\tpublic List<String> check(Library library) {\n\t\t\tList<String> errors = new ArrayList<>();\n\t\t\tArtifactVersion currentVersion = new DefaultArtifactVersion(library.getVersion().getVersion().toString());\n\t\t\tfor (ProhibitedVersion prohibited : library.getProhibitedVersions()) {\n\t\t\t\tif (prohibited.isProhibited(library.getVersion().getVersion().toString())) {\n\t\t\t\t\terrors.add(\"Current version \" + currentVersion + \" is prohibited\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tVersionRange versionRange = prohibited.getRange();\n\t\t\t\t\tif (versionRange != null) {\n\t\t\t\t\t\tcheck(currentVersion, versionRange, errors);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn errors;\n\t\t}\n\n\t\tprivate void check(ArtifactVersion currentVersion, VersionRange versionRange, List<String> errors) {\n\t\t\tfor (Restriction restriction : versionRange.getRestrictions()) {\n\t\t\t\tArtifactVersion upperBound = restriction.getUpperBound();\n\t\t\t\tif (upperBound == null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tint comparison = currentVersion.compareTo(upperBound);\n\t\t\t\tif ((restriction.isUpperBoundInclusive() && comparison <= 0)\n\t\t\t\t\t\t|| ((!restriction.isUpperBoundInclusive()) && comparison < 0)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\terrors.add(\"Version range \" + versionRange + \" is ineffective as the current version, \" + currentVersion\n\t\t\t\t\t+ \", is greater than its upper bound\");\n\t\t}\n\n\t}\n\n\tprivate static final class CheckVersionAlignment implements LibraryCheck {\n\n\t\t@Override\n\t\tpublic List<String> check(Library library) {\n\t\t\tList<String> errors = new ArrayList<>();\n\t\t\tVersionAlignment versionAlignment = library.getVersionAlignment();\n\t\t\tif (versionAlignment != null) {\n\t\t\t\tcheck(versionAlignment, library, errors);\n\t\t\t}\n\t\t\treturn errors;\n\t\t}\n\n\t\tprivate void check(VersionAlignment versionAlignment, Library library, List<String> errors) {\n\t\t\tSet<String> alignedVersions = versionAlignment.resolve();\n\t\t\tif (alignedVersions.size() == 1) {\n\t\t\t\tString alignedVersion = alignedVersions.iterator().next();\n\t\t\t\tif (!alignedVersion.equals(library.getVersion().getVersion().toString())) {\n\t\t\t\t\terrors.add(\"Version \" + library.getVersion().getVersion() + \" is misaligned. It should be \"\n\t\t\t\t\t\t\t+ alignedVersion + \".\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (alignedVersions.isEmpty()) {\n\t\t\t\t\terrors.add(\"Version alignment requires a single version but none were found.\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\terrors.add(\"Version alignment requires a single version but \" + alignedVersions.size()\n\t\t\t\t\t\t\t+ \" were found: \" + alignedVersions + \".\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate abstract static class ResolvedLibraryCheck implements LibraryCheck {\n\n\t\tprivate final Provider<ResolvedBom> resolvedBom;\n\n\t\tprivate ResolvedLibraryCheck(Provider<ResolvedBom> resolvedBom) {\n\t\t\tthis.resolvedBom = resolvedBom;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> check(Library library) {\n\t\t\tResolvedLibrary resolvedLibrary = getResolvedLibrary(library);\n\t\t\treturn check(library, resolvedLibrary);\n\t\t}\n\n\t\tprotected abstract List<String> check(Library library, ResolvedLibrary resolvedLibrary);\n\n\t\tprivate ResolvedLibrary getResolvedLibrary(Library library) {\n\t\t\tResolvedBom resolvedBom = this.resolvedBom.get();\n\t\t\tOptional<ResolvedLibrary> resolvedLibrary = resolvedBom.libraries()\n\t\t\t\t.stream()\n\t\t\t\t.filter((candidate) -> candidate.name().equals(library.getName()))\n\t\t\t\t.findFirst();\n\t\t\tif (!resolvedLibrary.isPresent()) {\n\t\t\t\tthrow new RuntimeException(\"Library '%s' not found in resolved bom\".formatted(library.getName()));\n\t\t\t}\n\t\t\treturn resolvedLibrary.get();\n\t\t}\n\n\t}\n\n\tprivate static final class CheckDependencyManagementAlignment extends ResolvedLibraryCheck {\n\n\t\tprivate final BomResolver bomResolver;\n\n\t\tprivate CheckDependencyManagementAlignment(Provider<ResolvedBom> resolvedBom,\n\t\t\t\tConfigurationContainer configurations, DependencyHandler dependencies) {\n\t\t\tsuper(resolvedBom);\n\t\t\tthis.bomResolver = new BomResolver(configurations, dependencies);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> check(Library library, ResolvedLibrary resolvedLibrary) {\n\t\t\tList<String> errors = new ArrayList<>();\n\t\t\tBomAlignment alignsWithBom = library.getAlignsWithBom();\n\t\t\tif (alignsWithBom != null) {\n\t\t\t\tBom mavenBom = this.bomResolver\n\t\t\t\t\t.resolveMavenBom(alignsWithBom.getCoordinates() + \":\" + library.getVersion().getVersion());\n\t\t\t\tcheckDependencyManagementAlignment(resolvedLibrary, mavenBom, errors, alignsWithBom::exclude);\n\t\t\t}\n\t\t\treturn errors;\n\t\t}\n\n\t\tprivate void checkDependencyManagementAlignment(ResolvedLibrary library, Bom mavenBom, List<String> errors,\n\t\t\t\tPredicate<Id> excluded) {\n\t\t\tList<Id> managedByLibrary = library.managedDependencies();\n\t\t\tList<Id> managedByBom = managedDependenciesOf(mavenBom);\n\n\t\t\tList<Id> missing = new ArrayList<>(managedByBom);\n\t\t\tmissing.removeIf(excluded);\n\t\t\tmissing.removeAll(managedByLibrary);\n\n\t\t\tList<Id> unexpected = new ArrayList<>(managedByLibrary);\n\t\t\tunexpected.removeAll(managedByBom);\n\t\t\tif (missing.isEmpty() && unexpected.isEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tString error = \"Dependency management does not align with \" + mavenBom.id() + \":\";\n\t\t\tif (!missing.isEmpty()) {\n\t\t\t\terror = error + \"%n        - Missing:%n            %s\".formatted(String.join(\"\\n            \",\n\t\t\t\t\t\tmissing.stream().map((dependency) -> dependency.toString()).toList()));\n\t\t\t}\n\t\t\tif (!unexpected.isEmpty()) {\n\t\t\t\terror = error + \"%n        - Unexpected:%n            %s\".formatted(String.join(\"\\n            \",\n\t\t\t\t\t\tunexpected.stream().map((dependency) -> dependency.toString()).toList()));\n\t\t\t}\n\t\t\terrors.add(error);\n\t\t}\n\n\t\tprivate List<Id> managedDependenciesOf(Bom mavenBom) {\n\t\t\tList<Id> managedDependencies = new ArrayList<>();\n\t\t\tmanagedDependencies.addAll(mavenBom.managedDependencies());\n\t\t\tif (mavenBom.parent() != null) {\n\t\t\t\tmanagedDependencies.addAll(managedDependenciesOf(mavenBom.parent()));\n\t\t\t}\n\t\t\tfor (Bom importedBom : mavenBom.importedBoms()) {\n\t\t\t\tmanagedDependencies.addAll(managedDependenciesOf(importedBom));\n\t\t\t}\n\t\t\treturn managedDependencies;\n\t\t}\n\n\t}\n\n\tprivate static final class CheckForUnwantedDependencyManagement extends ResolvedLibraryCheck {\n\n\t\tprivate CheckForUnwantedDependencyManagement(Provider<ResolvedBom> resolvedBom) {\n\t\t\tsuper(resolvedBom);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> check(Library library, ResolvedLibrary resolvedLibrary) {\n\t\t\tMap<String, Set<String>> unwanted = findUnwantedDependencyManagement(library, resolvedLibrary);\n\t\t\tList<String> errors = new ArrayList<>();\n\t\t\tif (!unwanted.isEmpty()) {\n\t\t\t\tStringBuilder error = new StringBuilder(\"Unwanted dependency management:\");\n\t\t\t\tunwanted.forEach((bom, dependencies) -> {\n\t\t\t\t\terror.append(\"%n        - %s:\".formatted(bom));\n\t\t\t\t\terror.append(\"%n            - %s\".formatted(String.join(\"\\n            - \", dependencies)));\n\t\t\t\t});\n\t\t\t\terrors.add(error.toString());\n\t\t\t}\n\t\t\tMap<String, Set<String>> unnecessary = findUnnecessaryPermittedDependencies(library, resolvedLibrary);\n\t\t\tif (!unnecessary.isEmpty()) {\n\t\t\t\tStringBuilder error = new StringBuilder(\"Dependencies permitted unnecessarily:\");\n\t\t\t\tunnecessary.forEach((bom, dependencies) -> {\n\t\t\t\t\terror.append(\"%n        - %s:\".formatted(bom));\n\t\t\t\t\terror.append(\"%n            - %s\".formatted(String.join(\"\\n            - \", dependencies)));\n\t\t\t\t});\n\t\t\t\terrors.add(error.toString());\n\t\t\t}\n\t\t\treturn errors;\n\t\t}\n\n\t\tprivate Map<String, Set<String>> findUnwantedDependencyManagement(Library library,\n\t\t\t\tResolvedLibrary resolvedLibrary) {\n\t\t\tMap<String, Set<String>> unwanted = new LinkedHashMap<>();\n\t\t\tfor (Bom bom : resolvedLibrary.importedBoms()) {\n\t\t\t\tSet<String> notPermitted = new TreeSet<>();\n\t\t\t\tSet<Id> managedDependencies = managedDependenciesOf(bom);\n\t\t\t\tmanagedDependencies.stream()\n\t\t\t\t\t.filter((dependency) -> unwanted(bom, dependency, findPermittedDependencies(library, bom)))\n\t\t\t\t\t.map(Id::toString)\n\t\t\t\t\t.forEach(notPermitted::add);\n\t\t\t\tif (!notPermitted.isEmpty()) {\n\t\t\t\t\tunwanted.put(bom.id().artifactId(), notPermitted);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn unwanted;\n\t\t}\n\n\t\tprivate List<PermittedDependency> findPermittedDependencies(Library library, Bom bom) {\n\t\t\tfor (Group group : library.getGroups()) {\n\t\t\t\tfor (ImportedBom importedBom : group.getBoms()) {\n\t\t\t\t\tif (importedBom.name().equals(bom.id().artifactId()) && group.getId().equals(bom.id().groupId())) {\n\t\t\t\t\t\treturn importedBom.permittedDependencies();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\tprivate Set<Id> managedDependenciesOf(Bom bom) {\n\t\t\tSet<Id> managedDependencies = new TreeSet<>();\n\t\t\tif (bom != null) {\n\t\t\t\tmanagedDependencies.addAll(bom.managedDependencies());\n\t\t\t\tmanagedDependencies.addAll(managedDependenciesOf(bom.parent()));\n\t\t\t\tfor (Bom importedBom : bom.importedBoms()) {\n\t\t\t\t\tmanagedDependencies.addAll(managedDependenciesOf(importedBom));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn managedDependencies;\n\t\t}\n\n\t\tprivate boolean unwanted(Bom bom, Id managedDependency, List<PermittedDependency> permittedDependencies) {\n\t\t\tif (bom.id().groupId().equals(managedDependency.groupId())\n\t\t\t\t\t|| managedDependency.groupId().startsWith(bom.id().groupId() + \".\")) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (PermittedDependency permittedDependency : permittedDependencies) {\n\t\t\t\tif (permittedDependency.artifactId().equals(managedDependency.artifactId())\n\t\t\t\t\t\t&& permittedDependency.groupId().equals(managedDependency.groupId())) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate Map<String, Set<String>> findUnnecessaryPermittedDependencies(Library library,\n\t\t\t\tResolvedLibrary resolvedLibrary) {\n\t\t\tMap<String, Set<String>> unnecessary = new HashMap<>();\n\t\t\tfor (Bom bom : resolvedLibrary.importedBoms()) {\n\t\t\t\tSet<String> permittedDependencies = findPermittedDependencies(library, bom).stream()\n\t\t\t\t\t.map((dependency) -> dependency.groupId() + \":\" + dependency.artifactId())\n\t\t\t\t\t.collect(Collectors.toCollection(TreeSet::new));\n\t\t\t\tSet<String> dependencies = managedDependenciesOf(bom).stream()\n\t\t\t\t\t.map((dependency) -> dependency.groupId() + \":\" + dependency.artifactId())\n\t\t\t\t\t.collect(Collectors.toCollection(TreeSet::new));\n\t\t\t\tpermittedDependencies.removeAll(dependencies);\n\t\t\t\tif (!permittedDependencies.isEmpty()) {\n\t\t\t\t\tunnecessary.put(bom.id().artifactId(), permittedDependencies);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn unnecessary;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/CheckLinks.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport javax.inject.Inject;\n\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.classic.CloseableHttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.internal.impldep.org.apache.http.client.config.CookieSpecs;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.web.client.NoOpResponseErrorHandler;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Task to check that links are working.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\npublic abstract class CheckLinks extends DefaultTask {\n\n\tprivate final BomExtension bom;\n\n\t@Inject\n\tpublic CheckLinks(BomExtension bom) {\n\t\tthis.bom = bom;\n\t}\n\n\t@TaskAction\n\tvoid releaseNotes() {\n\t\tRequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).build();\n\t\tCloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(config).build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);\n\t\tRestTemplate restTemplate = new RestTemplate(requestFactory);\n\t\trestTemplate.setErrorHandler(new NoOpResponseErrorHandler());\n\t\tfor (Library library : this.bom.getLibraries()) {\n\t\t\tlibrary.getLinks().forEach((name, links) -> links.forEach((link) -> {\n\t\t\t\tURI uri;\n\t\t\t\ttry {\n\t\t\t\t\turi = new URI(link.url(library));\n\t\t\t\t\tResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.HEAD, null, String.class);\n\t\t\t\t\tSystem.out.printf(\"[%3d] %s - %s (%s)%n\", response.getStatusCode().value(), library.getName(), name,\n\t\t\t\t\t\t\turi);\n\t\t\t\t}\n\t\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/CreateResolvedBom.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.io.FileWriter;\nimport java.io.IOException;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * {@link Task} to create a {@link ResolvedBom resolved bom}.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CreateResolvedBom extends DefaultTask {\n\n\tprivate final BomExtension bomExtension;\n\n\tprivate final BomResolver bomResolver;\n\n\t@Inject\n\tpublic CreateResolvedBom(BomExtension bomExtension) {\n\t\tgetOutputs().upToDateWhen((spec) -> false);\n\t\tthis.bomExtension = bomExtension;\n\t\tthis.bomResolver = new BomResolver(getProject().getConfigurations(), getProject().getDependencies());\n\t\tgetOutputFile().convention(getProject().getLayout().getBuildDirectory().file(getName() + \"/resolved-bom.json\"));\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@TaskAction\n\tvoid createResolvedBom() throws IOException {\n\t\tResolvedBom resolvedBom = this.bomResolver.resolve(this.bomExtension);\n\t\ttry (FileWriter writer = new FileWriter(getOutputFile().get().getAsFile())) {\n\t\t\tresolvedBom.writeTo(writer);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/Library.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Stream;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\nimport org.apache.maven.artifact.versioning.VersionRange;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.artifacts.result.DependencyResult;\nimport org.gradle.api.artifacts.result.ResolutionResult;\nimport org.w3c.dom.Document;\n\nimport org.springframework.boot.build.bom.ResolvedBom.Id;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\n/**\n * A collection of modules, Maven plugins, and Maven boms that are versioned and released\n * together.\n *\n * @author Andy Wilkinson\n */\npublic class Library {\n\n\tprivate final String name;\n\n\tprivate final String calendarName;\n\n\tprivate final LibraryVersion version;\n\n\tprivate final List<Group> groups;\n\n\tprivate final String versionProperty;\n\n\tprivate final UpgradePolicy upgradePolicy;\n\n\tprivate final List<ProhibitedVersion> prohibitedVersions;\n\n\tprivate final boolean considerSnapshots;\n\n\tprivate final VersionAlignment versionAlignment;\n\n\tprivate final BomAlignment bomAlignment;\n\n\tprivate final String linkRootName;\n\n\tprivate final Map<String, List<Link>> links;\n\n\t/**\n\t * Create a new {@code Library} with the given {@code name}, {@code version}, and\n\t * {@code groups}.\n\t * @param name name of the library\n\t * @param calendarName name of the library as it appears in the Spring Calendar. May\n\t * be {@code null} in which case the {@code name} is used.\n\t * @param version version of the library\n\t * @param groups groups in the library\n\t * @param upgradePolicy the upgrade policy of the library, or {@code null} to use the\n\t * containing bom's policy\n\t * @param prohibitedVersions version of the library that are prohibited\n\t * @param considerSnapshots whether to consider snapshots\n\t * @param versionAlignment version alignment, if any, for the library\n\t * @param bomAlignment the bom, if any, that this library should align with\n\t * @param linkRootName the root name to use when generating link variable or\n\t * {@code null} to generate one based on the library {@code name}\n\t * @param links a list of HTTP links relevant to the library\n\t */\n\tpublic Library(String name, String calendarName, LibraryVersion version, List<Group> groups,\n\t\t\tUpgradePolicy upgradePolicy, List<ProhibitedVersion> prohibitedVersions, boolean considerSnapshots,\n\t\t\tVersionAlignment versionAlignment, BomAlignment bomAlignment, String linkRootName,\n\t\t\tMap<String, List<Link>> links) {\n\t\tthis.name = name;\n\t\tthis.calendarName = (calendarName != null) ? calendarName : name;\n\t\tthis.version = version;\n\t\tthis.groups = groups;\n\t\tthis.versionProperty = \"Spring Boot\".equals(name) ? null\n\t\t\t\t: name.toLowerCase(Locale.ENGLISH).replace(' ', '-') + \".version\";\n\t\tthis.upgradePolicy = upgradePolicy;\n\t\tthis.prohibitedVersions = prohibitedVersions;\n\t\tthis.considerSnapshots = considerSnapshots;\n\t\tthis.versionAlignment = versionAlignment;\n\t\tthis.bomAlignment = bomAlignment;\n\t\tthis.linkRootName = (linkRootName != null) ? linkRootName : generateLinkRootName(name);\n\t\tthis.links = (links != null) ? Collections.unmodifiableMap(new TreeMap<>(links)) : Collections.emptyMap();\n\t}\n\n\tprivate static String generateLinkRootName(String name) {\n\t\treturn name.replace(\"-\", \"\").replace(\" \", \"-\").toLowerCase(Locale.ROOT);\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getCalendarName() {\n\t\treturn this.calendarName;\n\t}\n\n\tpublic LibraryVersion getVersion() {\n\t\treturn this.version;\n\t}\n\n\tpublic List<Group> getGroups() {\n\t\treturn this.groups;\n\t}\n\n\tpublic String getVersionProperty() {\n\t\treturn this.versionProperty;\n\t}\n\n\tpublic UpgradePolicy getUpgradePolicy() {\n\t\treturn this.upgradePolicy;\n\t}\n\n\tpublic List<ProhibitedVersion> getProhibitedVersions() {\n\t\treturn this.prohibitedVersions;\n\t}\n\n\tpublic boolean isConsiderSnapshots() {\n\t\treturn this.considerSnapshots;\n\t}\n\n\tpublic VersionAlignment getVersionAlignment() {\n\t\treturn this.versionAlignment;\n\t}\n\n\tpublic String getLinkRootName() {\n\t\treturn this.linkRootName;\n\t}\n\n\tpublic BomAlignment getAlignsWithBom() {\n\t\treturn this.bomAlignment;\n\t}\n\n\tpublic Map<String, List<Link>> getLinks() {\n\t\treturn this.links;\n\t}\n\n\tpublic String getLinkUrl(String name) {\n\t\tList<Link> links = getLinks(name);\n\t\tif (links == null || links.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tif (links.size() > 1) {\n\t\t\tthrow new IllegalStateException(\"Expected a single '%s' link for %s\".formatted(name, getName()));\n\t\t}\n\t\treturn links.get(0).url(this);\n\t}\n\n\tpublic List<Link> getLinks(String name) {\n\t\treturn this.links.get(name);\n\t}\n\n\tpublic String getNameAndVersion() {\n\t\treturn getName() + \" \" + getVersion();\n\t}\n\n\tpublic Library withVersion(LibraryVersion version) {\n\t\treturn new Library(this.name, this.calendarName, version, this.groups, this.upgradePolicy,\n\t\t\t\tthis.prohibitedVersions, this.considerSnapshots, this.versionAlignment, this.bomAlignment,\n\t\t\t\tthis.linkRootName, this.links);\n\t}\n\n\t/**\n\t * A version or range of versions that are prohibited from being used in a bom.\n\t */\n\tpublic static class ProhibitedVersion {\n\n\t\tprivate final VersionRange range;\n\n\t\tprivate final List<String> startsWith;\n\n\t\tprivate final List<String> endsWith;\n\n\t\tprivate final List<String> contains;\n\n\t\tprivate final String reason;\n\n\t\tpublic ProhibitedVersion(VersionRange range, List<String> startsWith, List<String> endsWith,\n\t\t\t\tList<String> contains, String reason) {\n\t\t\tthis.range = range;\n\t\t\tthis.startsWith = startsWith;\n\t\t\tthis.endsWith = endsWith;\n\t\t\tthis.contains = contains;\n\t\t\tthis.reason = reason;\n\t\t}\n\n\t\tpublic VersionRange getRange() {\n\t\t\treturn this.range;\n\t\t}\n\n\t\tpublic List<String> getStartsWith() {\n\t\t\treturn this.startsWith;\n\t\t}\n\n\t\tpublic List<String> getEndsWith() {\n\t\t\treturn this.endsWith;\n\t\t}\n\n\t\tpublic List<String> getContains() {\n\t\t\treturn this.contains;\n\t\t}\n\n\t\tpublic String getReason() {\n\t\t\treturn this.reason;\n\t\t}\n\n\t\tpublic boolean isProhibited(String candidate) {\n\t\t\tboolean result = false;\n\t\t\tresult = result\n\t\t\t\t\t|| (this.range != null && this.range.containsVersion(new DefaultArtifactVersion(candidate)));\n\t\t\tresult = result || this.startsWith.stream().anyMatch(candidate::startsWith);\n\t\t\tresult = result || this.endsWith.stream().anyMatch(candidate::endsWith);\n\t\t\tresult = result || this.contains.stream().anyMatch(candidate::contains);\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tpublic static class LibraryVersion {\n\n\t\tprivate final DependencyVersion version;\n\n\t\tpublic LibraryVersion(DependencyVersion version) {\n\t\t\tthis.version = version;\n\t\t}\n\n\t\tpublic DependencyVersion getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\tpublic int[] componentInts() {\n\t\t\treturn Arrays.stream(parts()).mapToInt(Integer::parseInt).toArray();\n\t\t}\n\n\t\tpublic String major() {\n\t\t\treturn parts()[0];\n\t\t}\n\n\t\tpublic String minor() {\n\t\t\treturn parts()[1];\n\t\t}\n\n\t\tpublic String patch() {\n\t\t\treturn parts()[2];\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.version.toString();\n\t\t}\n\n\t\tpublic String toString(String separator) {\n\t\t\treturn this.version.toString().replace(\".\", separator);\n\t\t}\n\n\t\tpublic String forAntora() {\n\t\t\tString[] parts = parts();\n\t\t\tString result = parts[0] + \".\" + parts[1];\n\t\t\tif (toString().endsWith(\"SNAPSHOT\")) {\n\t\t\t\tresult += \"-SNAPSHOT\";\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tpublic String forMajorMinorGeneration() {\n\t\t\tString[] parts = parts();\n\t\t\tString result = parts[0] + \".\" + parts[1] + \".x\";\n\t\t\tif (toString().endsWith(\"SNAPSHOT\")) {\n\t\t\t\tresult += \"-SNAPSHOT\";\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate String[] parts() {\n\t\t\treturn toString().split(\"[.-]\");\n\t\t}\n\n\t}\n\n\t/**\n\t * A collection of modules, Maven plugins, and Maven boms with the same group ID.\n\t */\n\tpublic static class Group {\n\n\t\tprivate final String id;\n\n\t\tprivate final List<Module> modules;\n\n\t\tprivate final List<String> plugins;\n\n\t\tprivate final List<ImportedBom> boms;\n\n\t\tpublic Group(String id, List<Module> modules, List<String> plugins, List<ImportedBom> boms) {\n\t\t\tthis.id = id;\n\t\t\tthis.modules = modules;\n\t\t\tthis.plugins = plugins;\n\t\t\tthis.boms = boms;\n\t\t}\n\n\t\tpublic String getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t\tpublic List<Module> getModules() {\n\t\t\treturn this.modules;\n\t\t}\n\n\t\tpublic List<String> getPlugins() {\n\t\t\treturn this.plugins;\n\t\t}\n\n\t\tpublic List<ImportedBom> getBoms() {\n\t\t\treturn this.boms;\n\t\t}\n\n\t}\n\n\t/**\n\t * A module in a group.\n\t */\n\tpublic static class Module {\n\n\t\tprivate final String name;\n\n\t\tprivate final String type;\n\n\t\tprivate final String classifier;\n\n\t\tprivate final List<Exclusion> exclusions;\n\n\t\tpublic Module(String name) {\n\t\t\tthis(name, Collections.emptyList());\n\t\t}\n\n\t\tpublic Module(String name, String type) {\n\t\t\tthis(name, type, null, Collections.emptyList());\n\t\t}\n\n\t\tpublic Module(String name, List<Exclusion> exclusions) {\n\t\t\tthis(name, null, null, exclusions);\n\t\t}\n\n\t\tpublic Module(String name, String type, String classifier, List<Exclusion> exclusions) {\n\t\t\tthis.name = name;\n\t\t\tthis.type = type;\n\t\t\tthis.classifier = (classifier != null) ? classifier : \"\";\n\t\t\tthis.exclusions = exclusions;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getClassifier() {\n\t\t\treturn this.classifier;\n\t\t}\n\n\t\tpublic String getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic List<Exclusion> getExclusions() {\n\t\t\treturn this.exclusions;\n\t\t}\n\n\t}\n\n\t/**\n\t * An exclusion of a dependency identified by its group ID and artifact ID.\n\t */\n\tpublic static class Exclusion {\n\n\t\tprivate final String groupId;\n\n\t\tprivate final String artifactId;\n\n\t\tpublic Exclusion(String groupId, String artifactId) {\n\t\t\tthis.groupId = groupId;\n\t\t\tthis.artifactId = artifactId;\n\t\t}\n\n\t\tpublic String getGroupId() {\n\t\t\treturn this.groupId;\n\t\t}\n\n\t\tpublic String getArtifactId() {\n\t\t\treturn this.artifactId;\n\t\t}\n\n\t}\n\n\tpublic interface VersionAlignment {\n\n\t\tSet<String> resolve();\n\n\t\tdefault Configuration alignmentConfiguration(Project project, Collection<Dependency> dependencies) {\n\t\t\tConfiguration alignmentConfiguration = project.getConfigurations()\n\t\t\t\t.detachedConfiguration(dependencies.toArray(new Dependency[0]));\n\t\t\talignmentConfiguration.getResolutionStrategy().cacheChangingModulesFor(0, TimeUnit.SECONDS);\n\t\t\treturn alignmentConfiguration;\n\t\t}\n\n\t}\n\n\tpublic static class BomAlignment {\n\n\t\tprivate final String coordinates;\n\n\t\tprivate final Predicate<Id> excluding;\n\n\t\tpublic BomAlignment(String bomCoordinates, Predicate<Id> excluding) {\n\t\t\tthis.coordinates = bomCoordinates;\n\t\t\tthis.excluding = excluding;\n\t\t}\n\n\t\tpublic String getCoordinates() {\n\t\t\treturn this.coordinates;\n\t\t}\n\n\t\tpublic boolean exclude(Id id) {\n\t\t\treturn this.excluding.test(id);\n\t\t}\n\n\t}\n\n\t/**\n\t * Version alignment for a library based on a dependency of another module.\n\t */\n\tpublic static class DependencyVersionAlignment implements VersionAlignment {\n\n\t\tprivate final String dependency;\n\n\t\tprivate final String from;\n\n\t\tprivate final String managedBy;\n\n\t\tprivate final Project project;\n\n\t\tprivate final List<Library> libraries;\n\n\t\tprivate final List<Group> groups;\n\n\t\tprivate Set<String> alignedVersions;\n\n\t\tDependencyVersionAlignment(String dependency, String from, String managedBy, Project project,\n\t\t\t\tList<Library> libraries, List<Group> groups) {\n\t\t\tthis.dependency = dependency;\n\t\t\tthis.from = from;\n\t\t\tthis.managedBy = managedBy;\n\t\t\tthis.project = project;\n\t\t\tthis.libraries = libraries;\n\t\t\tthis.groups = groups;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> resolve() {\n\t\t\tif (this.alignedVersions != null) {\n\t\t\t\treturn this.alignedVersions;\n\t\t\t}\n\t\t\tMap<String, String> versions = resolveAligningDependencies();\n\t\t\tif (this.dependency != null) {\n\t\t\t\tString version = versions.get(this.dependency);\n\t\t\t\tthis.alignedVersions = (version != null) ? Set.of(version) : Collections.emptySet();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSet<String> versionsInLibrary = new HashSet<>();\n\t\t\t\tfor (Group group : this.groups) {\n\t\t\t\t\tfor (Module module : group.getModules()) {\n\t\t\t\t\t\tString version = versions.get(group.getId() + \":\" + module.getName());\n\t\t\t\t\t\tif (version != null) {\n\t\t\t\t\t\t\tversionsInLibrary.add(version);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfor (String plugin : group.getPlugins()) {\n\t\t\t\t\t\tString version = versions.get(group.getId() + \":\" + plugin);\n\t\t\t\t\t\tif (version != null) {\n\t\t\t\t\t\t\tversionsInLibrary.add(version);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.alignedVersions = versionsInLibrary;\n\t\t\t}\n\t\t\treturn this.alignedVersions;\n\t\t}\n\n\t\tprivate Map<String, String> resolveAligningDependencies() {\n\t\t\tList<Dependency> dependencies = getAligningDependencies();\n\t\t\tConfiguration alignmentConfiguration = alignmentConfiguration(this.project, dependencies);\n\t\t\tMap<String, String> versions = new HashMap<>();\n\t\t\tResolutionResult resolutionResult = alignmentConfiguration.getIncoming().getResolutionResult();\n\t\t\tfor (DependencyResult dependency : resolutionResult.getAllDependencies()) {\n\t\t\t\tversions.put(dependency.getFrom().getModuleVersion().getModule().toString(),\n\t\t\t\t\t\tdependency.getFrom().getModuleVersion().getVersion());\n\t\t\t}\n\t\t\treturn versions;\n\t\t}\n\n\t\tprivate List<Dependency> getAligningDependencies() {\n\t\t\tif (this.managedBy == null) {\n\t\t\t\tLibrary fromLibrary = findFromLibrary();\n\t\t\t\treturn List\n\t\t\t\t\t.of(this.project.getDependencies().create(this.from + \":\" + fromLibrary.getVersion().getVersion()));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tLibrary managingLibrary = findManagingLibrary();\n\t\t\t\tList<Dependency> boms = getBomDependencies(managingLibrary);\n\t\t\t\tList<Dependency> dependencies = new ArrayList<>();\n\t\t\t\tdependencies.addAll(boms);\n\t\t\t\tdependencies.add(this.project.getDependencies().create(this.from));\n\t\t\t\treturn dependencies;\n\t\t\t}\n\t\t}\n\n\t\tprivate Library findFromLibrary() {\n\t\t\tfor (Library library : this.libraries) {\n\t\t\t\tfor (Group group : library.getGroups()) {\n\t\t\t\t\tfor (Module module : group.getModules()) {\n\t\t\t\t\t\tif (this.from.equals(group.getId() + \":\" + module.getName())) {\n\t\t\t\t\t\t\treturn library;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate Library findManagingLibrary() {\n\t\t\tif (this.managedBy == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.libraries.stream()\n\t\t\t\t.filter((candidate) -> this.managedBy.equals(candidate.getName()))\n\t\t\t\t.findFirst()\n\t\t\t\t.orElseThrow(() -> new IllegalStateException(\"Managing library '\" + this.managedBy + \"' not found.\"));\n\t\t}\n\n\t\tprivate List<Dependency> getBomDependencies(Library manager) {\n\t\t\tif (manager == null) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\treturn manager.getGroups()\n\t\t\t\t.stream()\n\t\t\t\t.flatMap((group) -> group.getBoms()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map((bom) -> this.project.getDependencies()\n\t\t\t\t\t\t.platform(group.getId() + \":\" + bom.name() + \":\" + manager.getVersion().getVersion())))\n\t\t\t\t.toList();\n\t\t}\n\n\t\tString getFrom() {\n\t\t\treturn this.from;\n\t\t}\n\n\t\tString getManagedBy() {\n\t\t\treturn this.managedBy;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tString result = \"version from dependencies of \" + this.from;\n\t\t\tif (this.managedBy != null) {\n\t\t\t\tresult += \" that is managed by \" + this.managedBy;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\t/**\n\t * Version alignment for a library based on a property in the pom of another module.\n\t */\n\tpublic static class PomPropertyVersionAlignment implements VersionAlignment {\n\n\t\tprivate final String name;\n\n\t\tprivate final String from;\n\n\t\tprivate final String managedBy;\n\n\t\tprivate final Project project;\n\n\t\tprivate final List<Library> libraries;\n\n\t\tprivate Set<String> alignedVersions;\n\n\t\tPomPropertyVersionAlignment(String name, String from, String managedBy, Project project,\n\t\t\t\tList<Library> libraries) {\n\t\t\tthis.name = name;\n\t\t\tthis.from = from;\n\t\t\tthis.managedBy = managedBy;\n\t\t\tthis.project = project;\n\t\t\tthis.libraries = libraries;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> resolve() {\n\t\t\tif (this.alignedVersions != null) {\n\t\t\t\treturn this.alignedVersions;\n\t\t\t}\n\t\t\tConfiguration alignmentConfiguration = alignmentConfiguration(this.project, getAligningDependencies());\n\t\t\tSet<File> files = alignmentConfiguration.resolve();\n\t\t\tif (files.size() != 1) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Expected a single file when resolving the pom of \" + this.from + \" but found \" + files.size());\n\t\t\t}\n\t\t\tFile pomFile = files.iterator().next();\n\t\t\treturn Set.of(propertyFrom(pomFile));\n\t\t}\n\n\t\tprivate List<Dependency> getAligningDependencies() {\n\t\t\tLibrary managingLibrary = findManagingLibrary();\n\t\t\tList<Dependency> boms = getBomDependencies(managingLibrary);\n\t\t\tList<Dependency> dependencies = new ArrayList<>();\n\t\t\tdependencies.addAll(boms);\n\t\t\tdependencies.add(this.project.getDependencies().create(this.from + \"@pom\"));\n\t\t\treturn dependencies;\n\t\t}\n\n\t\tprivate Library findManagingLibrary() {\n\t\t\tif (this.managedBy == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn this.libraries.stream()\n\t\t\t\t.filter((candidate) -> this.managedBy.equals(candidate.getName()))\n\t\t\t\t.findFirst()\n\t\t\t\t.orElseThrow(() -> new IllegalStateException(\"Managing library '\" + this.managedBy + \"' not found.\"));\n\t\t}\n\n\t\tprivate List<Dependency> getBomDependencies(Library manager) {\n\t\t\treturn manager.getGroups()\n\t\t\t\t.stream()\n\t\t\t\t.flatMap((group) -> group.getBoms()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map((bom) -> this.project.getDependencies()\n\t\t\t\t\t\t.platform(group.getId() + \":\" + bom.name() + \":\" + manager.getVersion().getVersion())))\n\t\t\t\t.toList();\n\t\t}\n\n\t\tprivate String propertyFrom(File pomFile) {\n\t\t\ttry {\n\t\t\t\tDocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();\n\t\t\t\tDocument document = documentBuilder.parse(pomFile);\n\t\t\t\tXPath xpath = XPathFactory.newInstance().newXPath();\n\t\t\t\treturn xpath.evaluate(\"/project/properties/\" + this.name + \"/text()\", document);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tString result = \"version from properties of \" + this.from;\n\t\t\tif (this.managedBy != null) {\n\t\t\t\tresult += \" that is managed by \" + this.managedBy;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tpublic record Link(String rootName, Function<LibraryVersion, String> factory, List<String> packages) {\n\n\t\tprivate static final Pattern PACKAGE_EXPAND = Pattern.compile(\"^(.*)\\\\[(.*)\\\\]$\");\n\n\t\tpublic Link {\n\t\t\tpackages = (packages != null) ? List.copyOf(expandPackages(packages)) : Collections.emptyList();\n\t\t}\n\n\t\tprivate static List<String> expandPackages(List<String> packages) {\n\t\t\treturn packages.stream().flatMap(Link::expandPackage).toList();\n\t\t}\n\n\t\tprivate static Stream<String> expandPackage(String packageName) {\n\t\t\tMatcher matcher = PACKAGE_EXPAND.matcher(packageName);\n\t\t\tif (!matcher.matches()) {\n\t\t\t\treturn Stream.of(packageName);\n\t\t\t}\n\t\t\tString root = matcher.group(1);\n\t\t\tString[] suffixes = matcher.group(2).split(\"\\\\|\");\n\t\t\treturn Stream.of(suffixes).map((suffix) -> root + suffix);\n\t\t}\n\n\t\tpublic String url(Library library) {\n\t\t\treturn url(library.getVersion());\n\t\t}\n\n\t\tpublic String url(LibraryVersion libraryVersion) {\n\t\t\treturn factory().apply(libraryVersion);\n\t\t}\n\n\t}\n\n\tpublic record ImportedBom(String name, List<PermittedDependency> permittedDependencies) {\n\n\t\tpublic ImportedBom(String name) {\n\t\t\tthis(name, Collections.emptyList());\n\t\t}\n\n\t}\n\n\tpublic record PermittedDependency(String groupId, String artifactId) {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/ResolvedBom.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.io.Writer;\nimport java.net.URI;\nimport java.util.List;\n\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * A resolved bom.\n *\n * @author Andy Wilkinson\n * @param id the ID of the resolved bom\n * @param libraries the libraries declared in the bom\n */\npublic record ResolvedBom(Id id, List<ResolvedLibrary> libraries) {\n\n\tprivate static final JsonMapper jsonMapper;\n\n\tstatic {\n\t\tjsonMapper = JsonMapper.builder()\n\t\t\t.changeDefaultPropertyInclusion((value) -> value.withContentInclusion(Include.NON_EMPTY))\n\t\t\t.build();\n\t}\n\n\tpublic static ResolvedBom readFrom(File file) {\n\t\ttry (FileReader reader = new FileReader(file)) {\n\t\t\treturn jsonMapper.readValue(reader, ResolvedBom.class);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tpublic void writeTo(Writer writer) {\n\t\tjsonMapper.writeValue(writer, this);\n\t}\n\n\tpublic record ResolvedLibrary(String name, String version, String versionProperty, List<Id> managedDependencies,\n\t\t\tList<Bom> importedBoms, Links links) {\n\n\t}\n\n\tpublic record Id(String groupId, String artifactId, String version, String classifier) implements Comparable<Id> {\n\n\t\tId(String groupId, String artifactId, String version) {\n\t\t\tthis(groupId, artifactId, version, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic int compareTo(Id o) {\n\t\t\tint result = this.groupId.compareTo(o.groupId);\n\t\t\tif (result != 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tresult = this.artifactId.compareTo(o.artifactId);\n\t\t\tif (result != 0) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\treturn this.version.compareTo(o.version);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tStringBuilder builder = new StringBuilder();\n\t\t\tbuilder.append(this.groupId);\n\t\t\tbuilder.append(\":\");\n\t\t\tbuilder.append(this.artifactId);\n\t\t\tbuilder.append(\":\");\n\t\t\tbuilder.append(this.version);\n\t\t\tif (this.classifier != null) {\n\t\t\t\tbuilder.append(\":\");\n\t\t\t\tbuilder.append(this.classifier);\n\t\t\t}\n\t\t\treturn builder.toString();\n\t\t}\n\n\t}\n\n\tpublic record Bom(Id id, Bom parent, List<Id> managedDependencies, List<Bom> importedBoms) {\n\n\t}\n\n\tpublic record Links(List<JavadocLink> javadoc) {\n\n\t}\n\n\tpublic record JavadocLink(URI uri, List<String> packages) {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/UpgradePolicy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.util.function.BiPredicate;\n\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\n/**\n * Policies used to decide which versions are considered as possible upgrades.\n *\n * @author Andy Wilkinson\n */\npublic enum UpgradePolicy implements BiPredicate<DependencyVersion, DependencyVersion> {\n\n\t/**\n\t * Any version.\n\t */\n\tANY((candidate, current) -> true),\n\n\t/**\n\t * Minor versions of the current major version.\n\t */\n\tSAME_MAJOR_VERSION(DependencyVersion::isSameMajor),\n\n\t/**\n\t * Patch versions of the current minor version.\n\t */\n\tSAME_MINOR_VERSION(DependencyVersion::isSameMinor);\n\n\tprivate final BiPredicate<DependencyVersion, DependencyVersion> delegate;\n\n\tUpgradePolicy(BiPredicate<DependencyVersion, DependencyVersion> delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic boolean test(DependencyVersion candidate, DependencyVersion current) {\n\t\treturn this.delegate.test(candidate, current);\n\t}\n\n\tpublic static UpgradePolicy max(UpgradePolicy one, UpgradePolicy two) {\n\t\tif (one == null && two != null) {\n\t\t\treturn two;\n\t\t}\n\t\telse if (one != null && two == null) {\n\t\t\treturn one;\n\t\t}\n\t\treturn (one.ordinal() < two.ordinal()) ? one : two;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.gradle.api.internal.tasks.userinput.UserInputHandler;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\n/**\n * Interactive {@link UpgradeResolver} that uses command line input to choose the upgrades\n * to apply.\n *\n * @author Andy Wilkinson\n */\npublic final class InteractiveUpgradeResolver implements UpgradeResolver {\n\n\tprivate final UserInputHandler userInputHandler;\n\n\tprivate final LibraryUpdateResolver libraryUpdateResolver;\n\n\tInteractiveUpgradeResolver(UserInputHandler userInputHandler, LibraryUpdateResolver libraryUpdateResolver) {\n\t\tthis.userInputHandler = userInputHandler;\n\t\tthis.libraryUpdateResolver = libraryUpdateResolver;\n\t}\n\n\t@Override\n\tpublic List<Upgrade> resolveUpgrades(Collection<Library> librariesToUpgrade, Collection<Library> libraries) {\n\t\tMap<String, Library> librariesByName = new HashMap<>();\n\t\tfor (Library library : libraries) {\n\t\t\tlibrariesByName.put(library.getName(), library);\n\t\t}\n\t\ttry {\n\t\t\treturn this.libraryUpdateResolver.findLibraryUpdates(librariesToUpgrade, librariesByName)\n\t\t\t\t.stream()\n\t\t\t\t.map(this::resolveUpgrade)\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.toList();\n\t\t}\n\t\tcatch (UpgradesInterruptedException ex) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t}\n\n\tprivate Upgrade resolveUpgrade(LibraryWithVersionOptions libraryWithVersionOptions) {\n\t\tLibrary library = libraryWithVersionOptions.getLibrary();\n\t\tList<VersionOption> versionOptions = libraryWithVersionOptions.getVersionOptions();\n\t\tif (versionOptions.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tVersionOption defaultOption = defaultOption(library);\n\t\tVersionOption selected = selectOption(defaultOption, library, versionOptions);\n\t\treturn (selected.equals(defaultOption)) ? null : selected.upgrade(library);\n\t}\n\n\tprivate VersionOption defaultOption(Library library) {\n\t\tVersionAlignment alignment = library.getVersionAlignment();\n\t\tSet<String> alignedVersions = (alignment != null) ? alignment.resolve() : null;\n\t\tif (alignedVersions != null && alignedVersions.size() == 1) {\n\t\t\tDependencyVersion alignedVersion = DependencyVersion.parse(alignedVersions.iterator().next());\n\t\t\tif (alignedVersion.equals(library.getVersion().getVersion())) {\n\t\t\t\treturn new VersionOption.AlignedVersionOption(alignedVersion, alignment);\n\t\t\t}\n\t\t}\n\t\treturn new VersionOption(library.getVersion().getVersion());\n\t}\n\n\tprivate VersionOption selectOption(VersionOption defaultOption, Library library,\n\t\t\tList<VersionOption> versionOptions) {\n\t\tVersionOption selected = this.userInputHandler.askUser((questions) -> {\n\t\t\tString question = library.getNameAndVersion();\n\t\t\tList<VersionOption> options = new ArrayList<>();\n\t\t\toptions.add(defaultOption);\n\t\t\toptions.addAll(versionOptions);\n\t\t\treturn questions.selectOption(question, options, defaultOption);\n\t\t}).get();\n\t\tif (this.userInputHandler.interrupted()) {\n\t\t\tthrow new UpgradesInterruptedException();\n\t\t}\n\t\treturn selected;\n\t}\n\n\tstatic class UpgradesInterruptedException extends RuntimeException {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/LibraryUpdateResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.build.bom.Library;\n\n/**\n * Resolves library updates.\n *\n * @author Moritz Halbritter\n */\npublic interface LibraryUpdateResolver {\n\n\t/**\n\t * Finds library updates.\n\t * @param librariesToUpgrade libraries to update\n\t * @param librariesByName libraries indexed by name\n\t * @return library which have updates\n\t */\n\tList<LibraryWithVersionOptions> findLibraryUpdates(Collection<Library> librariesToUpgrade,\n\t\t\tMap<String, Library> librariesByName);\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/LibraryWithVersionOptions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.List;\n\nimport org.springframework.boot.build.bom.Library;\n\nclass LibraryWithVersionOptions {\n\n\tprivate final Library library;\n\n\tprivate final List<VersionOption> versionOptions;\n\n\tLibraryWithVersionOptions(Library library, List<VersionOption> versionOptions) {\n\t\tthis.library = library;\n\t\tthis.versionOptions = versionOptions;\n\t}\n\n\tLibrary getLibrary() {\n\t\treturn this.library;\n\t}\n\n\tList<VersionOption> getVersionOptions() {\n\t\treturn this.versionOptions;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MavenMetadataVersionResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.io.StringReader;\nimport java.net.URI;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\nimport org.gradle.api.artifacts.repositories.PasswordCredentials;\nimport org.gradle.api.credentials.Credentials;\nimport org.gradle.internal.artifacts.repositories.AuthenticationSupportedInternal;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.InputSource;\n\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.web.client.HttpClientErrorException;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.UriComponentsBuilder;\n\n/**\n * A {@link VersionResolver} that examines {@code maven-metadata.xml} to determine the\n * available versions.\n *\n * @author Andy Wilkinson\n */\nfinal class MavenMetadataVersionResolver implements VersionResolver {\n\n\tprivate final RestTemplate rest;\n\n\tprivate final Collection<MavenArtifactRepository> repositories;\n\n\tMavenMetadataVersionResolver(Collection<MavenArtifactRepository> repositories) {\n\t\tthis(new RestTemplate(Collections.singletonList(new StringHttpMessageConverter())), repositories);\n\t}\n\n\tMavenMetadataVersionResolver(RestTemplate restTemplate, Collection<MavenArtifactRepository> repositories) {\n\t\tthis.rest = restTemplate;\n\t\tthis.repositories = repositories;\n\t}\n\n\t@Override\n\tpublic SortedSet<DependencyVersion> resolveVersions(String groupId, String artifactId) {\n\t\tSet<String> versions = new HashSet<>();\n\t\tfor (MavenArtifactRepository repository : this.repositories) {\n\t\t\tversions.addAll(resolveVersions(groupId, artifactId, repository));\n\t\t}\n\t\treturn versions.stream().map(DependencyVersion::parse).collect(Collectors.toCollection(TreeSet::new));\n\t}\n\n\tprivate Set<String> resolveVersions(String groupId, String artifactId, MavenArtifactRepository repository) {\n\t\tSet<String> versions = new HashSet<>();\n\t\tURI url = UriComponentsBuilder.fromUri(repository.getUrl())\n\t\t\t.pathSegment(groupId.replace('.', '/'), artifactId, \"maven-metadata.xml\")\n\t\t\t.build()\n\t\t\t.toUri();\n\t\ttry {\n\t\t\tHttpHeaders headers = new HttpHeaders();\n\t\t\tPasswordCredentials credentials = credentialsOf(repository);\n\t\t\tString username = (credentials != null) ? credentials.getUsername() : null;\n\t\t\tif (username != null) {\n\t\t\t\theaders.setBasicAuth(username, credentials.getPassword());\n\t\t\t}\n\t\t\tHttpEntity<Void> request = new HttpEntity<>(headers);\n\t\t\tString metadata = this.rest.exchange(url, HttpMethod.GET, request, String.class).getBody();\n\t\t\tDocument metadataDocument = DocumentBuilderFactory.newInstance()\n\t\t\t\t.newDocumentBuilder()\n\t\t\t\t.parse(new InputSource(new StringReader(metadata)));\n\t\t\tNodeList versionNodes = (NodeList) XPathFactory.newInstance()\n\t\t\t\t.newXPath()\n\t\t\t\t.evaluate(\"/metadata/versioning/versions/version\", metadataDocument, XPathConstants.NODESET);\n\t\t\tfor (int i = 0; i < versionNodes.getLength(); i++) {\n\t\t\t\tversions.add(versionNodes.item(i).getTextContent());\n\t\t\t}\n\t\t}\n\t\tcatch (HttpClientErrorException ex) {\n\t\t\tif (ex.getStatusCode() != HttpStatus.NOT_FOUND) {\n\t\t\t\tSystem.err.println(\"Failed to download maven-metadata.xml for \" + groupId + \":\" + artifactId + \" from \"\n\t\t\t\t\t\t+ url + \": \" + ex.getMessage());\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tSystem.err.println(\"Failed to resolve versions for module \" + groupId + \":\" + artifactId + \" in repository \"\n\t\t\t\t\t+ repository + \": \" + ex.getMessage());\n\t\t}\n\t\treturn versions;\n\t}\n\n\t/**\n\t * Retrieves the configured credentials of the given {@code repository}. We cannot use\n\t * {@link MavenArtifactRepository#getCredentials()} as, if the repository has no\n\t * credentials, it has the unwanted side-effect of assigning an empty set of username\n\t * and password credentials to the repository which may cause subsequent \"Username\n\t * must not be null!\" failures.\n\t * @param repository the repository that is the source of the credentials\n\t * @return the configured password credentials or {@code null}\n\t */\n\tprivate PasswordCredentials credentialsOf(MavenArtifactRepository repository) {\n\t\tCredentials credentials = ((AuthenticationSupportedInternal) repository).getConfiguredCredentials().getOrNull();\n\t\tif (credentials != null) {\n\t\t\tif (credentials instanceof PasswordCredentials passwordCredentials) {\n\t\t\t\treturn passwordCredentials;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Repository '%s (%s)' has credentials '%s' that are not PasswordCredentials\"\n\t\t\t\t.formatted(repository.getName(), repository.getUrl(), credentials));\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MoveToSnapshots.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.time.OffsetDateTime;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiFunction;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\nimport org.gradle.api.tasks.TaskAction;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.build.bom.BomExtension;\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.bomr.ReleaseSchedule.Release;\nimport org.springframework.boot.build.bom.bomr.github.Milestone;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.boot.build.properties.BuildProperties;\nimport org.springframework.boot.build.properties.BuildType;\n\n/**\n * A {@link Task} to move to snapshot dependencies.\n *\n * @author Andy Wilkinson\n */\npublic abstract class MoveToSnapshots extends UpgradeDependencies {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(MoveToSnapshots.class);\n\n\tprivate final BuildType buildType = BuildProperties.get(getProject()).buildType();\n\n\t@Inject\n\tpublic MoveToSnapshots(BomExtension bom) {\n\t\tsuper(bom, true);\n\t\tgetProject().getRepositories().withType(MavenArtifactRepository.class, (repository) -> {\n\t\t\tString name = repository.getName();\n\t\t\tif (name.startsWith(\"spring-\") && name.endsWith(\"-snapshot\")) {\n\t\t\t\tgetRepositoryNames().add(name);\n\t\t\t}\n\t\t});\n\t}\n\n\t@Override\n\t@TaskAction\n\tvoid upgradeDependencies() {\n\t\tsuper.upgradeDependencies();\n\t}\n\n\t@Override\n\tprotected String commitMessage(Upgrade upgrade, int issueNumber) {\n\t\treturn \"Start building against \" + upgrade.toRelease().getNameAndVersion() + \" snapshots\" + \"\\n\\nSee gh-\"\n\t\t\t\t+ issueNumber;\n\t}\n\n\t@Override\n\tprotected boolean eligible(Library library) {\n\t\treturn library.isConsiderSnapshots() && super.eligible(library);\n\t}\n\n\t@Override\n\tprotected BiFunction<Library, DependencyVersion, VersionOption> createVersionOptionResolver(Milestone milestone) {\n\t\treturn switch (this.buildType) {\n\t\t\tcase OPEN_SOURCE -> createOpenSourceVersionOptionResolver(milestone);\n\t\t\tcase COMMERCIAL -> super.createVersionOptionResolver(milestone);\n\t\t};\n\t}\n\n\tprivate BiFunction<Library, DependencyVersion, VersionOption> createOpenSourceVersionOptionResolver(\n\t\t\tMilestone milestone) {\n\t\tMap<String, List<Release>> scheduledReleases = getScheduledOpenSourceReleases(milestone);\n\t\tBiFunction<Library, DependencyVersion, VersionOption> resolver = super.createVersionOptionResolver(milestone);\n\t\treturn (library, dependencyVersion) -> {\n\t\t\tVersionOption versionOption = resolver.apply(library, dependencyVersion);\n\t\t\tif (versionOption != null) {\n\t\t\t\tList<Release> releases = scheduledReleases.get(library.getCalendarName());\n\t\t\t\tif (releases != null) {\n\t\t\t\t\tList<Release> matches = releases.stream()\n\t\t\t\t\t\t.filter((release) -> dependencyVersion.isSnapshotFor(release.getVersion()))\n\t\t\t\t\t\t.toList();\n\t\t\t\t\tif (!matches.isEmpty()) {\n\t\t\t\t\t\treturn new VersionOption.SnapshotVersionOption(versionOption.getVersion(),\n\t\t\t\t\t\t\t\tmatches.get(0).getVersion());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\tlogger.info(\"Ignoring {}. No release of {} scheduled before {}\", dependencyVersion,\n\t\t\t\t\t\t\tlibrary.getName(), milestone.getDueOn());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t}\n\n\tprivate Map<String, List<Release>> getScheduledOpenSourceReleases(Milestone milestone) {\n\t\tReleaseSchedule releaseSchedule = new ReleaseSchedule();\n\t\treturn releaseSchedule.releasesBetween(OffsetDateTime.now(), milestone.getDueOn());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/MultithreadedLibraryUpdateResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.stream.Stream;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.build.bom.Library;\n\n/**\n * {@link LibraryUpdateResolver} decorator that uses multiple threads to find library\n * updates.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nclass MultithreadedLibraryUpdateResolver implements LibraryUpdateResolver {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(MultithreadedLibraryUpdateResolver.class);\n\n\tprivate final int threads;\n\n\tprivate final LibraryUpdateResolver delegate;\n\n\tMultithreadedLibraryUpdateResolver(int threads, LibraryUpdateResolver delegate) {\n\t\tthis.threads = threads;\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic List<LibraryWithVersionOptions> findLibraryUpdates(Collection<Library> librariesToUpgrade,\n\t\t\tMap<String, Library> librariesByName) {\n\t\tlogger.info(\"Looking for updates using {} threads\", this.threads);\n\t\tExecutorService executorService = Executors.newFixedThreadPool(this.threads);\n\t\ttry {\n\t\t\treturn librariesToUpgrade.stream().map((library) -> {\n\t\t\t\tif (library.getVersionAlignment() == null) {\n\t\t\t\t\treturn executorService.submit(() -> this.delegate\n\t\t\t\t\t\t.findLibraryUpdates(Collections.singletonList(library), librariesByName));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn CompletableFuture.completedFuture(\n\t\t\t\t\t\t\tthis.delegate.findLibraryUpdates(Collections.singletonList(library), librariesByName));\n\t\t\t\t}\n\t\t\t}).flatMap(this::getResult).toList();\n\t\t}\n\t\tfinally {\n\t\t\texecutorService.shutdownNow();\n\t\t}\n\t}\n\n\tprivate Stream<LibraryWithVersionOptions> getResult(Future<List<LibraryWithVersionOptions>> job) {\n\t\ttry {\n\t\t\treturn job.get().stream();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\tcatch (ExecutionException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/ReleaseSchedule.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.time.LocalDate;\nimport java.time.OffsetDateTime;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedCaseInsensitiveMap;\nimport org.springframework.web.client.RestOperations;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Release schedule for Spring projects, retrieved from\n * <a href=\"https://calendar.spring.io\">https://calendar.spring.io</a>.\n *\n * @author Andy Wilkinson\n */\nclass ReleaseSchedule {\n\n\tprivate static final Pattern LIBRARY_AND_VERSION = Pattern.compile(\"([A-Za-z0-9 ]+) ([0-9A-Za-z.-]+)\");\n\n\tprivate final RestOperations rest;\n\n\tReleaseSchedule() {\n\t\tthis(new RestTemplate());\n\t}\n\n\tReleaseSchedule(RestOperations rest) {\n\t\tthis.rest = rest;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tMap<String, List<Release>> releasesBetween(OffsetDateTime start, OffsetDateTime end) {\n\t\tResponseEntity<List> response = this.rest\n\t\t\t.getForEntity(\"https://calendar.spring.io/releases?start=\" + start + \"&end=\" + end, List.class);\n\t\tList<Map<String, String>> body = response.getBody();\n\t\tMap<String, List<Release>> releasesByLibrary = new LinkedCaseInsensitiveMap<>();\n\t\tbody.stream()\n\t\t\t.map(this::asRelease)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.forEach((release) -> releasesByLibrary.computeIfAbsent(release.getLibraryName(), (l) -> new ArrayList<>())\n\t\t\t\t.add(release));\n\t\treturn releasesByLibrary;\n\t}\n\n\tprivate Release asRelease(Map<String, String> entry) {\n\t\tLocalDate due = LocalDate.parse(entry.get(\"start\"));\n\t\tString title = entry.get(\"title\");\n\t\tMatcher matcher = LIBRARY_AND_VERSION.matcher(title);\n\t\tif (!matcher.matches()) {\n\t\t\treturn null;\n\t\t}\n\t\tString library = matcher.group(1);\n\t\tString version = matcher.group(2);\n\t\treturn new Release(library, DependencyVersion.parse(version), due);\n\t}\n\n\tstatic class Release {\n\n\t\tprivate final String libraryName;\n\n\t\tprivate final DependencyVersion version;\n\n\t\tprivate final LocalDate dueOn;\n\n\t\tRelease(String libraryName, DependencyVersion version, LocalDate dueOn) {\n\t\t\tthis.libraryName = libraryName;\n\t\t\tthis.version = version;\n\t\t\tthis.dueOn = dueOn;\n\t\t}\n\n\t\tString getLibraryName() {\n\t\t\treturn this.libraryName;\n\t\t}\n\n\t\tDependencyVersion getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\tLocalDate getDueOn() {\n\t\t\treturn this.dueOn;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/StandardLibraryUpdateResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.function.BiFunction;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.ImportedBom;\nimport org.springframework.boot.build.bom.Library.Module;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\n/**\n * Standard implementation for {@link LibraryUpdateResolver}.\n *\n * @author Andy Wilkinson\n */\nclass StandardLibraryUpdateResolver implements LibraryUpdateResolver {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(StandardLibraryUpdateResolver.class);\n\n\tprivate final VersionResolver versionResolver;\n\n\tprivate final BiFunction<Library, DependencyVersion, VersionOption> versionOptionResolver;\n\n\tStandardLibraryUpdateResolver(VersionResolver versionResolver,\n\t\t\tBiFunction<Library, DependencyVersion, VersionOption> versionOptionResolver) {\n\t\tthis.versionResolver = versionResolver;\n\t\tthis.versionOptionResolver = versionOptionResolver;\n\t}\n\n\t@Override\n\tpublic List<LibraryWithVersionOptions> findLibraryUpdates(Collection<Library> librariesToUpgrade,\n\t\t\tMap<String, Library> librariesByName) {\n\t\tList<LibraryWithVersionOptions> result = new ArrayList<>();\n\t\tfor (Library library : librariesToUpgrade) {\n\t\t\tif (isLibraryExcluded(library)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlogger.info(\"Looking for updates for {}\", library.getName());\n\t\t\tlong start = System.nanoTime();\n\t\t\tList<VersionOption> versionOptions = getVersionOptions(library);\n\t\t\tresult.add(new LibraryWithVersionOptions(library, versionOptions));\n\t\t\tlogger.info(\"Found {} updates for {}, took {}\", versionOptions.size(), library.getName(),\n\t\t\t\t\tDuration.ofNanos(System.nanoTime() - start));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected boolean isLibraryExcluded(Library library) {\n\t\treturn library.getName().equals(\"Spring Boot\");\n\t}\n\n\tprotected List<VersionOption> getVersionOptions(Library library) {\n\t\tList<VersionOption> options = new ArrayList<>();\n\t\tVersionOption alignedOption = determineAlignedVersionOption(library);\n\t\tif (alignedOption != null) {\n\t\t\toptions.add(alignedOption);\n\t\t}\n\t\tfor (VersionOption resolvedOption : determineResolvedVersionOptions(library)) {\n\t\t\tif (alignedOption == null || !alignedOption.getVersion().equals(resolvedOption.getVersion())) {\n\t\t\t\toptions.add(resolvedOption);\n\t\t\t}\n\t\t}\n\t\treturn options;\n\t}\n\n\tprivate VersionOption determineAlignedVersionOption(Library library) {\n\t\tVersionAlignment versionAlignment = library.getVersionAlignment();\n\t\tif (versionAlignment != null) {\n\t\t\tSet<String> alignedVersions = versionAlignment.resolve();\n\t\t\tif (alignedVersions != null && alignedVersions.size() == 1) {\n\t\t\t\tDependencyVersion alignedVersion = DependencyVersion.parse(alignedVersions.iterator().next());\n\t\t\t\tif (!alignedVersion.equals(library.getVersion().getVersion())) {\n\t\t\t\t\treturn new VersionOption.AlignedVersionOption(alignedVersion, versionAlignment);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<VersionOption> determineResolvedVersionOptions(Library library) {\n\t\tMap<String, SortedSet<DependencyVersion>> moduleVersions = new LinkedHashMap<>();\n\t\tfor (Group group : library.getGroups()) {\n\t\t\tfor (Module module : group.getModules()) {\n\t\t\t\tmoduleVersions.put(group.getId() + \":\" + module.getName(),\n\t\t\t\t\t\tgetLaterVersionsForModule(group.getId(), module.getName(), library));\n\t\t\t}\n\t\t\tfor (ImportedBom bom : group.getBoms()) {\n\t\t\t\tmoduleVersions.put(group.getId() + \":\" + bom,\n\t\t\t\t\t\tgetLaterVersionsForModule(group.getId(), bom.name(), library));\n\t\t\t}\n\t\t\tfor (String plugin : group.getPlugins()) {\n\t\t\t\tmoduleVersions.put(group.getId() + \":\" + plugin,\n\t\t\t\t\t\tgetLaterVersionsForModule(group.getId(), plugin, library));\n\t\t\t}\n\t\t}\n\t\tList<VersionOption> versionOptions = new ArrayList<>();\n\t\tmoduleVersions.values().stream().flatMap(SortedSet::stream).distinct().forEach((dependencyVersion) -> {\n\t\t\tVersionOption versionOption = this.versionOptionResolver.apply(library, dependencyVersion);\n\t\t\tif (versionOption != null) {\n\t\t\t\tList<String> missingModules = getMissingModules(moduleVersions, dependencyVersion);\n\t\t\t\tif (!missingModules.isEmpty()) {\n\t\t\t\t\tversionOption = new VersionOption.ResolvedVersionOption(versionOption.getVersion(), missingModules);\n\t\t\t\t}\n\t\t\t\tversionOptions.add(versionOption);\n\t\t\t}\n\t\t});\n\t\treturn versionOptions;\n\t}\n\n\tprivate List<String> getMissingModules(Map<String, SortedSet<DependencyVersion>> moduleVersions,\n\t\t\tDependencyVersion version) {\n\t\tList<String> missingModules = new ArrayList<>();\n\t\tmoduleVersions.forEach((name, versions) -> {\n\t\t\tif (!versions.contains(version)) {\n\t\t\t\tmissingModules.add(name);\n\t\t\t}\n\t\t});\n\t\treturn missingModules;\n\t}\n\n\tprivate SortedSet<DependencyVersion> getLaterVersionsForModule(String groupId, String artifactId, Library library) {\n\t\treturn this.versionResolver.resolveVersions(groupId, artifactId);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/Upgrade.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport org.springframework.boot.build.bom.Library;\n\n/**\n * An upgrade to change a {@link Library} to use a new version.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @param from the library we're upgrading from\n * @param to the library we're upgrading to (may be a SNAPSHOT)\n * @param toRelease the release version of the library we're ultimately upgrading to\n */\nrecord Upgrade(Library from, Library to, Library toRelease) {\n\n\tUpgrade(Library from, Library to) {\n\t\tthis(from, to, to);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeApplicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * {@code UpgradeApplicator} is used to apply an {@link Upgrade}. Modifies the bom\n * configuration in the build file or a version property in {@code gradle.properties}.\n *\n * @author Andy Wilkinson\n */\nclass UpgradeApplicator {\n\n\tprivate final Path buildFile;\n\n\tprivate final Path gradleProperties;\n\n\tUpgradeApplicator(Path buildFile, Path gradleProperties) {\n\t\tthis.buildFile = buildFile;\n\t\tthis.gradleProperties = gradleProperties;\n\t}\n\n\tPath apply(Upgrade upgrade) throws IOException {\n\t\tString buildFileContents = Files.readString(this.buildFile);\n\t\tString toName = upgrade.to().getName();\n\t\tMatcher matcher = Pattern.compile(\"library\\\\(\\\"\" + toName + \"\\\", \\\"(.+)\\\"\\\\)\").matcher(buildFileContents);\n\t\tif (!matcher.find()) {\n\t\t\tmatcher = Pattern.compile(\"library\\\\(\\\"\" + toName + \"\\\"\\\\) \\\\{\\\\s+version\\\\(\\\"(.+)\\\"\\\\)\", Pattern.MULTILINE)\n\t\t\t\t.matcher(buildFileContents);\n\t\t\tif (!matcher.find()) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to find definition for library '\" + upgrade.to().getName()\n\t\t\t\t\t\t+ \"' in bom '\" + this.buildFile + \"'\");\n\t\t\t}\n\t\t}\n\t\tString version = matcher.group(1);\n\t\tif (version.startsWith(\"${\") && version.endsWith(\"}\")) {\n\t\t\tupdateGradleProperties(upgrade, version);\n\t\t\treturn this.gradleProperties;\n\t\t}\n\t\telse {\n\t\t\tupdateBuildFile(upgrade, buildFileContents, matcher.start(1), matcher.end(1));\n\t\t\treturn this.buildFile;\n\t\t}\n\t}\n\n\tprivate void updateGradleProperties(Upgrade upgrade, String version) throws IOException {\n\t\tString property = version.substring(2, version.length() - 1);\n\t\tString gradlePropertiesContents = Files.readString(this.gradleProperties);\n\t\tString modified = gradlePropertiesContents.replace(property + \"=\" + upgrade.from().getVersion(),\n\t\t\t\tproperty + \"=\" + upgrade.to().getVersion());\n\t\toverwrite(this.gradleProperties, modified);\n\t}\n\n\tprivate void updateBuildFile(Upgrade upgrade, String buildFileContents, int versionStart, int versionEnd)\n\t\t\tthrows IOException {\n\t\tString modified = buildFileContents.substring(0, versionStart) + upgrade.to().getVersion()\n\t\t\t\t+ buildFileContents.substring(versionEnd);\n\t\toverwrite(this.buildFile, modified);\n\t}\n\n\tprivate void overwrite(Path target, String content) throws IOException {\n\t\tFiles.writeString(target, content, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeBom.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.List;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.ArtifactRepositoryContainer;\nimport org.gradle.api.artifacts.dsl.RepositoryHandler;\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\n\nimport org.springframework.boot.build.bom.BomExtension;\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.properties.BuildProperties;\n\n/**\n * {@link Task} to upgrade the libraries managed by a bom.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\npublic abstract class UpgradeBom extends UpgradeDependencies {\n\n\t@Inject\n\tpublic UpgradeBom(BomExtension bom) {\n\t\tsuper(bom);\n\t\tswitch (BuildProperties.get(getProject()).buildType()) {\n\t\t\tcase OPEN_SOURCE -> addOpenSourceRepositories(getProject().getRepositories());\n\t\t\tcase COMMERCIAL -> addCommercialRepositories();\n\t\t}\n\t}\n\n\tprivate void addOpenSourceRepositories(RepositoryHandler repositories) {\n\t\tgetRepositoryNames().add(ArtifactRepositoryContainer.DEFAULT_MAVEN_CENTRAL_REPO_NAME);\n\t\trepositories.withType(MavenArtifactRepository.class, (repository) -> {\n\t\t\tString name = repository.getName();\n\t\t\tif (name.startsWith(\"spring-\") && !name.endsWith(\"-snapshot\")) {\n\t\t\t\tgetRepositoryNames().add(name);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void addCommercialRepositories() {\n\t\tgetRepositoryNames().addAll(ArtifactRepositoryContainer.DEFAULT_MAVEN_CENTRAL_REPO_NAME,\n\t\t\t\t\"spring-commercial-release\");\n\t}\n\n\t@Override\n\tprotected String commitMessage(Upgrade upgrade, int issueNumber) {\n\t\treturn issueTitle(upgrade) + \"\\n\\nCloses gh-\" + issueNumber;\n\t}\n\n\t@Override\n\tprotected void upgradesApplied(List<Upgrade> upgrades) {\n\t\tif (upgrades.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tSystem.out.println();\n\t\tSystem.out.println(\"Upgrade release notes:\");\n\t\tSystem.out.println();\n\t\tfor (Upgrade upgrade : upgrades) {\n\t\t\tLibrary library = upgrade.toRelease();\n\t\t\tString releaseNotes = library.getLinkUrl(\"releaseNotes\");\n\t\t\tif (releaseNotes != null) {\n\t\t\t\tSystem.out.println(\"* \" + releaseNotes + \"[\" + library.getNameAndVersion() + \"]\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.out.println(\"* \" + library.getNameAndVersion());\n\t\t\t}\n\t\t}\n\t\tSystem.out.println();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeDependencies.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.BiFunction;\nimport java.util.function.BiPredicate;\nimport java.util.function.Predicate;\nimport java.util.regex.Pattern;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.InvalidUserDataException;\nimport org.gradle.api.artifacts.dsl.RepositoryHandler;\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\nimport org.gradle.api.internal.tasks.userinput.UserInputHandler;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.Optional;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.TaskExecutionException;\nimport org.gradle.api.tasks.options.Option;\n\nimport org.springframework.boot.build.bom.BomExtension;\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.UpgradePolicy;\nimport org.springframework.boot.build.bom.bomr.github.GitHub;\nimport org.springframework.boot.build.bom.bomr.github.GitHubRepository;\nimport org.springframework.boot.build.bom.bomr.github.Issue;\nimport org.springframework.boot.build.bom.bomr.github.Milestone;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for tasks that upgrade dependencies in a BOM.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\npublic abstract class UpgradeDependencies extends DefaultTask {\n\n\tprivate final BomExtension bom;\n\n\tprivate final boolean movingToSnapshots;\n\n\tprivate final UpgradeApplicator upgradeApplicator;\n\n\tprivate final RepositoryHandler repositories;\n\n\t@Inject\n\tpublic UpgradeDependencies(BomExtension bom) {\n\t\tthis(bom, false);\n\t}\n\n\tprotected UpgradeDependencies(BomExtension bom, boolean movingToSnapshots) {\n\t\tthis.bom = bom;\n\t\tgetThreads().convention(2);\n\t\tthis.movingToSnapshots = movingToSnapshots;\n\t\tthis.upgradeApplicator = new UpgradeApplicator(getProject().getBuildFile().toPath(),\n\t\t\t\tnew File(getProject().getRootProject().getProjectDir(), \"gradle.properties\").toPath());\n\t\tthis.repositories = getProject().getRepositories();\n\t}\n\n\t@Input\n\t@Option(option = \"milestone\", description = \"Milestone to which dependency upgrade issues should be assigned\")\n\tpublic abstract Property<String> getMilestone();\n\n\t@Input\n\t@Optional\n\t@Option(option = \"threads\", description = \"Number of Threads to use for update resolution\")\n\tpublic abstract Property<Integer> getThreads();\n\n\t@Input\n\t@Optional\n\t@Option(option = \"libraries\", description = \"Regular expression that identifies the libraries to upgrade\")\n\tpublic abstract Property<String> getLibraries();\n\n\t@Input\n\t@Optional\n\t@Option(option = \"dry-run-upgrades\",\n\t\t\tdescription = \"Whether to perform a dry run that doesn't open issues or change the bom\")\n\tpublic abstract Property<Boolean> getDryRun();\n\n\t@Input\n\tabstract ListProperty<String> getRepositoryNames();\n\n\t@TaskAction\n\tvoid upgradeDependencies() {\n\t\tGitHubRepository repository = createGitHub().getRepository(this.bom.getUpgrade().getGitHub().getOrganization(),\n\t\t\t\tthis.bom.getUpgrade().getGitHub().getRepository());\n\t\tList<String> issueLabels = verifyLabels(repository);\n\t\tMilestone milestone = determineMilestone(repository);\n\t\tList<Upgrade> upgrades = resolveUpgrades(milestone);\n\t\tif (!getDryRun().getOrElse(false)) {\n\t\t\tapplyUpgrades(repository, issueLabels, milestone, upgrades);\n\t\t}\n\t\tupgradesApplied(upgrades);\n\t}\n\n\tprotected void upgradesApplied(List<Upgrade> upgrades) {\n\n\t}\n\n\tprivate void applyUpgrades(GitHubRepository repository, List<String> issueLabels, Milestone milestone,\n\t\t\tList<Upgrade> upgrades) {\n\t\tList<Issue> existingUpgradeIssues = repository.findIssues(issueLabels, milestone);\n\t\tSystem.out.println(\"Applying upgrades...\");\n\t\tSystem.out.println(\"\");\n\t\tfor (Upgrade upgrade : upgrades) {\n\t\t\tSystem.out.println(upgrade.to().getNameAndVersion());\n\t\t\tIssue existingUpgradeIssue = findExistingUpgradeIssue(existingUpgradeIssues, upgrade);\n\t\t\ttry {\n\t\t\t\tPath modified = this.upgradeApplicator.apply(upgrade);\n\t\t\t\tString title = issueTitle(upgrade);\n\t\t\t\tString body = issueBody(upgrade, existingUpgradeIssue);\n\t\t\t\tint issueNumber = getOrOpenUpgradeIssue(repository, issueLabels, milestone, title, body,\n\t\t\t\t\t\texistingUpgradeIssue);\n\t\t\t\tif (existingUpgradeIssue != null && existingUpgradeIssue.getState() == Issue.State.CLOSED) {\n\t\t\t\t\texistingUpgradeIssue.label(Arrays.asList(\"type: task\", \"status: superseded\"));\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"   Issue: \" + issueNumber + \" - \" + title\n\t\t\t\t\t\t+ getExistingUpgradeIssueMessageDetails(existingUpgradeIssue));\n\t\t\t\tif (new ProcessBuilder().command(\"git\", \"add\", modified.toFile().getAbsolutePath())\n\t\t\t\t\t.start()\n\t\t\t\t\t.waitFor() != 0) {\n\t\t\t\t\tthrow new IllegalStateException(\"git add failed\");\n\t\t\t\t}\n\t\t\t\tString commitMessage = commitMessage(upgrade, issueNumber);\n\t\t\t\tif (new ProcessBuilder().command(\"git\", \"commit\", \"-m\", commitMessage).start().waitFor() != 0) {\n\t\t\t\t\tthrow new IllegalStateException(\"git commit failed\");\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"  Commit: \" + commitMessage.substring(0, commitMessage.indexOf('\\n')));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new TaskExecutionException(this, ex);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate int getOrOpenUpgradeIssue(GitHubRepository repository, List<String> issueLabels, Milestone milestone,\n\t\t\tString title, String body, Issue existingUpgradeIssue) {\n\t\tif (existingUpgradeIssue != null && existingUpgradeIssue.getState() == Issue.State.OPEN) {\n\t\t\treturn existingUpgradeIssue.getNumber();\n\t\t}\n\t\treturn repository.openIssue(title, body, issueLabels, milestone);\n\t}\n\n\tprivate String getExistingUpgradeIssueMessageDetails(Issue existingUpgradeIssue) {\n\t\tif (existingUpgradeIssue == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tif (existingUpgradeIssue.getState() != Issue.State.CLOSED) {\n\t\t\treturn \" (completes existing upgrade)\";\n\t\t}\n\t\treturn \" (supersedes #\" + existingUpgradeIssue.getNumber() + \" \" + existingUpgradeIssue.getTitle() + \")\";\n\t}\n\n\tprivate List<String> verifyLabels(GitHubRepository repository) {\n\t\tSet<String> availableLabels = repository.getLabels();\n\t\tList<String> issueLabels = this.bom.getUpgrade().getGitHub().getIssueLabels();\n\t\tif (!availableLabels.containsAll(issueLabels)) {\n\t\t\tList<String> unknownLabels = new ArrayList<>(issueLabels);\n\t\t\tunknownLabels.removeAll(availableLabels);\n\t\t\tString suffix = (unknownLabels.size() == 1) ? \"\" : \"s\";\n\t\t\tthrow new InvalidUserDataException(\n\t\t\t\t\t\"Unknown label\" + suffix + \": \" + StringUtils.collectionToCommaDelimitedString(unknownLabels));\n\t\t}\n\t\treturn issueLabels;\n\t}\n\n\tprivate GitHub createGitHub() {\n\t\tProperties bomrProperties = new Properties();\n\t\ttry (Reader reader = new FileReader(new File(System.getProperty(\"user.home\"), \".bomr.properties\"))) {\n\t\t\tbomrProperties.load(reader);\n\t\t\tString username = bomrProperties.getProperty(\"bomr.github.username\");\n\t\t\tString password = bomrProperties.getProperty(\"bomr.github.password\");\n\t\t\treturn GitHub.withCredentials(username, password);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new InvalidUserDataException(\"Failed to load .bomr.properties from user home\", ex);\n\t\t}\n\t}\n\n\tprivate Milestone determineMilestone(GitHubRepository repository) {\n\t\tList<Milestone> milestones = repository.getMilestones();\n\t\tjava.util.Optional<Milestone> matchingMilestone = milestones.stream()\n\t\t\t.filter((milestone) -> milestone.getName().equals(getMilestone().get()))\n\t\t\t.findFirst();\n\t\tif (matchingMilestone.isEmpty()) {\n\t\t\tthrow new InvalidUserDataException(\"Unknown milestone: \" + getMilestone().get());\n\t\t}\n\t\treturn matchingMilestone.get();\n\t}\n\n\tprivate Issue findExistingUpgradeIssue(List<Issue> existingUpgradeIssues, Upgrade upgrade) {\n\t\tString toMatch = \"Upgrade to \" + upgrade.toRelease().getName();\n\t\tfor (Issue existingUpgradeIssue : existingUpgradeIssues) {\n\t\t\tString title = existingUpgradeIssue.getTitle();\n\t\t\tint lastSpaceIndex = title.lastIndexOf(' ');\n\t\t\tif (lastSpaceIndex > -1) {\n\t\t\t\ttitle = title.substring(0, lastSpaceIndex);\n\t\t\t}\n\t\t\tif (title.equals(toMatch)) {\n\t\t\t\treturn existingUpgradeIssue;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate List<Upgrade> resolveUpgrades(Milestone milestone) {\n\t\tInteractiveUpgradeResolver upgradeResolver = new InteractiveUpgradeResolver(\n\t\t\t\tgetServices().get(UserInputHandler.class), getLibraryUpdateResolver(milestone));\n\t\treturn upgradeResolver.resolveUpgrades(matchingLibraries(), this.bom.getLibraries());\n\t}\n\n\tprivate LibraryUpdateResolver getLibraryUpdateResolver(Milestone milestone) {\n\t\tVersionResolver versionResolver = new MavenMetadataVersionResolver(getRepositories());\n\t\tLibraryUpdateResolver libraryResolver = new StandardLibraryUpdateResolver(versionResolver,\n\t\t\t\tcreateVersionOptionResolver(milestone));\n\t\treturn new MultithreadedLibraryUpdateResolver(getThreads().get(), libraryResolver);\n\t}\n\n\tprivate Collection<MavenArtifactRepository> getRepositories() {\n\t\treturn getRepositoryNames().map(this::asRepositories).get();\n\t}\n\n\tprivate List<MavenArtifactRepository> asRepositories(List<String> repositoryNames) {\n\t\treturn repositoryNames.stream()\n\t\t\t.map(this.repositories::getByName)\n\t\t\t.map(MavenArtifactRepository.class::cast)\n\t\t\t.toList();\n\t}\n\n\tprotected BiFunction<Library, DependencyVersion, VersionOption> createVersionOptionResolver(Milestone milestone) {\n\t\tList<BiPredicate<Library, DependencyVersion>> updatePredicates = new ArrayList<>();\n\t\tupdatePredicates.add(this::compliesWithUpgradePolicy);\n\t\tupdatePredicates.add(this::isAnUpgrade);\n\t\tupdatePredicates.add(this::isNotProhibited);\n\t\treturn (library, dependencyVersion) -> {\n\t\t\tif (this.compliesWithUpgradePolicy(library, dependencyVersion)\n\t\t\t\t\t&& this.isAnUpgrade(library, dependencyVersion)\n\t\t\t\t\t&& this.isNotProhibited(library, dependencyVersion)) {\n\t\t\t\treturn new VersionOption.ResolvedVersionOption(dependencyVersion, Collections.emptyList());\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t}\n\n\tprivate boolean compliesWithUpgradePolicy(Library library, DependencyVersion candidate) {\n\t\tUpgradePolicy libraryPolicy = library.getUpgradePolicy();\n\t\tUpgradePolicy bomPolicy = this.bom.getUpgrade().getPolicy();\n\t\tUpgradePolicy upgradePolicy = UpgradePolicy.max(libraryPolicy, bomPolicy);\n\t\treturn upgradePolicy.test(candidate, library.getVersion().getVersion());\n\t}\n\n\tprivate boolean isAnUpgrade(Library library, DependencyVersion candidate) {\n\t\treturn library.getVersion().getVersion().isUpgrade(candidate, this.movingToSnapshots);\n\t}\n\n\tprivate boolean isNotProhibited(Library library, DependencyVersion candidate) {\n\t\treturn library.getProhibitedVersions()\n\t\t\t.stream()\n\t\t\t.noneMatch((prohibited) -> prohibited.isProhibited(candidate.toString()));\n\t}\n\n\tprivate List<Library> matchingLibraries() {\n\t\tList<Library> matchingLibraries = this.bom.getLibraries().stream().filter(this::eligible).toList();\n\t\tif (matchingLibraries.isEmpty()) {\n\t\t\tthrow new InvalidUserDataException(\"No libraries to upgrade\");\n\t\t}\n\t\treturn matchingLibraries;\n\t}\n\n\tprotected boolean eligible(Library library) {\n\t\tString pattern = getLibraries().getOrNull();\n\t\tif (pattern == null) {\n\t\t\treturn true;\n\t\t}\n\t\tPredicate<String> libraryPredicate = Pattern.compile(pattern).asPredicate();\n\t\treturn libraryPredicate.test(library.getName());\n\t}\n\n\tprotected abstract String commitMessage(Upgrade upgrade, int issueNumber);\n\n\tprotected String issueTitle(Upgrade upgrade) {\n\t\treturn \"Upgrade to \" + upgrade.toRelease().getNameAndVersion();\n\t}\n\n\tprotected String issueBody(Upgrade upgrade, Issue existingUpgrade) {\n\t\tString description = upgrade.toRelease().getNameAndVersion();\n\t\tString releaseNotesLink = upgrade.toRelease().getLinkUrl(\"releaseNotes\");\n\t\tString body = (releaseNotesLink != null) ? \"Upgrade to [%s](%s).\".formatted(description, releaseNotesLink)\n\t\t\t\t: \"Upgrade to %s.\".formatted(description);\n\t\tif (existingUpgrade != null) {\n\t\t\tbody += \"\\n\\nSupersedes #\" + existingUpgrade.getNumber();\n\t\t}\n\t\treturn body;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/UpgradeResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.springframework.boot.build.bom.Library;\n\n/**\n * Resolves upgrades for the libraries in a bom.\n *\n * @author Andy Wilkinson\n */\ninterface UpgradeResolver {\n\n\t/**\n\t * Resolves the upgrades to be applied to the given {@code libraries}.\n\t * @param librariesToUpgrade the libraries to upgrade\n\t * @param libraries all libraries\n\t * @return the upgrades\n\t */\n\tList<Upgrade> resolveUpgrades(Collection<Library> librariesToUpgrade, Collection<Library> libraries);\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/VersionOption.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.List;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.util.StringUtils;\n\n/**\n * An option for a library update.\n *\n * @author Andy Wilkinson\n */\nclass VersionOption {\n\n\tprivate final DependencyVersion version;\n\n\tVersionOption(DependencyVersion version) {\n\t\tthis.version = version;\n\t}\n\n\tDependencyVersion getVersion() {\n\t\treturn this.version;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.version.toString();\n\t}\n\n\tUpgrade upgrade(Library library) {\n\t\treturn new Upgrade(library, library.withVersion(new LibraryVersion(this.version)));\n\t}\n\n\tstatic final class AlignedVersionOption extends VersionOption {\n\n\t\tprivate final VersionAlignment alignedWith;\n\n\t\tAlignedVersionOption(DependencyVersion version, VersionAlignment alignedWith) {\n\t\t\tsuper(version);\n\t\t\tthis.alignedWith = alignedWith;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn super.toString() + \" (aligned with \" + this.alignedWith + \")\";\n\t\t}\n\n\t}\n\n\tstatic final class ResolvedVersionOption extends VersionOption {\n\n\t\tprivate final List<String> missingModules;\n\n\t\tResolvedVersionOption(DependencyVersion version, List<String> missingModules) {\n\t\t\tsuper(version);\n\t\t\tthis.missingModules = missingModules;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tif (this.missingModules.isEmpty()) {\n\t\t\t\treturn super.toString();\n\t\t\t}\n\t\t\treturn super.toString() + \" (some modules are missing: \"\n\t\t\t\t\t+ StringUtils.collectionToDelimitedString(this.missingModules, \", \") + \")\";\n\t\t}\n\n\t}\n\n\tstatic final class SnapshotVersionOption extends VersionOption {\n\n\t\tprivate final DependencyVersion releaseVersion;\n\n\t\tSnapshotVersionOption(DependencyVersion version, DependencyVersion releaseVersion) {\n\t\t\tsuper(version);\n\t\t\tthis.releaseVersion = releaseVersion;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn super.toString() + \" (for \" + this.releaseVersion + \")\";\n\t\t}\n\n\t\t@Override\n\t\tUpgrade upgrade(Library library) {\n\t\t\treturn new Upgrade(library, library.withVersion(new LibraryVersion(super.version)),\n\t\t\t\t\tlibrary.withVersion(new LibraryVersion(this.releaseVersion)));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/VersionResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.SortedSet;\n\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\n/**\n * Resolves the available versions for a module.\n *\n * @author Andy Wilkinson\n */\ninterface VersionResolver {\n\n\t/**\n\t * Resolves the available versions for the module identified by the given\n\t * {@code groupId} and {@code artifactId}.\n\t * @param groupId module's group ID\n\t * @param artifactId module's artifact ID\n\t * @return the available versions\n\t */\n\tSortedSet<DependencyVersion> resolveVersions(String groupId, String artifactId);\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/GitHub.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.github;\n\n/**\n * Minimal API for interacting with GitHub.\n *\n * @author Andy Wilkinson\n */\npublic interface GitHub {\n\n\t/**\n\t * Returns a {@link GitHubRepository} with the given {@code name} in the given\n\t * {@code organization}.\n\t * @param organization the organization\n\t * @param name the name of the repository\n\t * @return the repository\n\t */\n\tGitHubRepository getRepository(String organization, String name);\n\n\t/**\n\t * Creates a new {@code GitHub} that will authenticate with given {@code username} and\n\t * {@code password}.\n\t * @param username username for authentication\n\t * @param password password for authentication\n\t * @return the new {@code GitHub} instance\n\t */\n\tstatic GitHub withCredentials(String username, String password) {\n\t\treturn new StandardGitHub(username, password);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/GitHubRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.github;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Minimal API for interacting with a GitHub repository.\n *\n * @author Andy Wilkinson\n */\npublic interface GitHubRepository {\n\n\t/**\n\t * Opens a new issue with the given title. The given {@code labels} will be applied to\n\t * the issue and it will be assigned to the given {@code milestone}.\n\t * @param title the title of the issue\n\t * @param body the body of the issue\n\t * @param labels the labels to apply to the issue\n\t * @param milestone the milestone to assign the issue to\n\t * @return the number of the new issue\n\t */\n\tint openIssue(String title, String body, List<String> labels, Milestone milestone);\n\n\t/**\n\t * Returns the labels in the repository.\n\t * @return the labels\n\t */\n\tSet<String> getLabels();\n\n\t/**\n\t * Returns the milestones in the repository.\n\t * @return the milestones\n\t */\n\tList<Milestone> getMilestones();\n\n\t/**\n\t * Finds issues that have the given {@code labels} and are assigned to the given\n\t * {@code milestone}.\n\t * @param labels issue labels\n\t * @param milestone assigned milestone\n\t * @return the matching issues\n\t */\n\tList<Issue> findIssues(List<String> labels, Milestone milestone);\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/Issue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.github;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Minimal representation of a GitHub issue.\n *\n * @author Andy Wilkinson\n */\npublic class Issue {\n\n\tprivate final RestTemplate rest;\n\n\tprivate final int number;\n\n\tprivate final String title;\n\n\tprivate final State state;\n\n\tIssue(RestTemplate rest, int number, String title, State state) {\n\t\tthis.rest = rest;\n\t\tthis.number = number;\n\t\tthis.title = title;\n\t\tthis.state = state;\n\t}\n\n\tpublic int getNumber() {\n\t\treturn this.number;\n\t}\n\n\tpublic String getTitle() {\n\t\treturn this.title;\n\t}\n\n\tpublic State getState() {\n\t\treturn this.state;\n\t}\n\n\t/**\n\t * Labels the issue with the given {@code labels}. Any existing labels are removed.\n\t * @param labels the labels to apply to the issue\n\t */\n\tpublic void label(List<String> labels) {\n\t\tMap<String, List<String>> body = Collections.singletonMap(\"labels\", labels);\n\t\tthis.rest.put(\"issues/\" + this.number + \"/labels\", body);\n\t}\n\n\tpublic enum State {\n\n\t\t/**\n\t\t * The issue is open.\n\t\t */\n\t\tOPEN,\n\n\t\t/**\n\t\t * The issue is closed.\n\t\t */\n\t\tCLOSED;\n\n\t\tstatic State of(String state) {\n\t\t\tif (\"open\".equals(state)) {\n\t\t\t\treturn OPEN;\n\t\t\t}\n\t\t\tif (\"closed\".equals(state)) {\n\t\t\t\treturn CLOSED;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalArgumentException(\"Unknown state '\" + state + \"'\");\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/Milestone.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.github;\n\nimport java.time.OffsetDateTime;\n\n/**\n * A milestone in a {@link GitHubRepository GitHub repository}.\n *\n * @author Andy Wilkinson\n */\npublic class Milestone {\n\n\tprivate final String name;\n\n\tprivate final int number;\n\n\tprivate final OffsetDateTime dueOn;\n\n\tMilestone(String name, int number, OffsetDateTime dueOn) {\n\t\tthis.name = name;\n\t\tthis.number = number;\n\t\tthis.dueOn = dueOn;\n\t}\n\n\t/**\n\t * Returns the name of the milestone.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Returns the number of the milestone.\n\t * @return the number\n\t */\n\tpublic int getNumber() {\n\t\treturn this.number;\n\t}\n\n\tpublic OffsetDateTime getDueOn() {\n\t\treturn this.dueOn;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name + \" (\" + this.number + \")\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHub.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.github;\n\nimport java.util.Base64;\nimport java.util.Collections;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * Standard implementation of {@link GitHub}.\n *\n * @author Andy Wilkinson\n */\nfinal class StandardGitHub implements GitHub {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tStandardGitHub(String username, String password) {\n\t\tthis.username = username;\n\t\tthis.password = password;\n\t}\n\n\t@Override\n\tpublic GitHubRepository getRepository(String organization, String name) {\n\t\tRestTemplate restTemplate = createRestTemplate();\n\t\trestTemplate.getInterceptors().add((request, body, execution) -> {\n\t\t\trequest.getHeaders().add(\"User-Agent\", StandardGitHub.this.username);\n\t\t\trequest.getHeaders()\n\t\t\t\t.add(\"Authorization\", \"Basic \" + Base64.getEncoder()\n\t\t\t\t\t.encodeToString((StandardGitHub.this.username + \":\" + StandardGitHub.this.password).getBytes()));\n\t\t\trequest.getHeaders().add(\"Accept\", MediaType.APPLICATION_JSON_VALUE);\n\t\t\treturn execution.execute(request, body);\n\t\t});\n\t\tUriTemplateHandler uriTemplateHandler = new DefaultUriBuilderFactory(\n\t\t\t\t\"https://api.github.com/repos/\" + organization + \"/\" + name + \"/\");\n\t\trestTemplate.setUriTemplateHandler(uriTemplateHandler);\n\t\treturn new StandardGitHubRepository(restTemplate);\n\t}\n\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tprivate RestTemplate createRestTemplate() {\n\t\treturn new RestTemplate(Collections.singletonList(new JacksonJsonHttpMessageConverter()));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/github/StandardGitHubRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.github;\n\nimport java.time.Duration;\nimport java.time.OffsetDateTime;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.client.HttpClientErrorException.Forbidden;\nimport org.springframework.web.client.RestClientException;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Standard implementation of {@link GitHubRepository}.\n *\n * @author Andy Wilkinson\n */\nfinal class StandardGitHubRepository implements GitHubRepository {\n\n\tprivate final RestTemplate rest;\n\n\tStandardGitHubRepository(RestTemplate restTemplate) {\n\t\tthis.rest = restTemplate;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic int openIssue(String title, String body, List<String> labels, Milestone milestone) {\n\t\tMap<String, Object> requestBody = new HashMap<>();\n\t\trequestBody.put(\"title\", title);\n\t\tif (milestone != null) {\n\t\t\trequestBody.put(\"milestone\", milestone.getNumber());\n\t\t}\n\t\tif (!labels.isEmpty()) {\n\t\t\trequestBody.put(\"labels\", labels);\n\t\t}\n\t\trequestBody.put(\"body\", body);\n\t\ttry {\n\t\t\tResponseEntity<Map> response = this.rest.postForEntity(\"issues\", requestBody, Map.class);\n\t\t\t// See gh-30304\n\t\t\tsleep(Duration.ofSeconds(3));\n\t\t\treturn (Integer) response.getBody().get(\"number\");\n\t\t}\n\t\tcatch (RestClientException ex) {\n\t\t\tif (ex instanceof Forbidden forbidden) {\n\t\t\t\tSystem.out.println(\"Received 403 response with headers \" + forbidden.getResponseHeaders());\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Set<String> getLabels() {\n\t\treturn new HashSet<>(get(\"labels?per_page=100\", (label) -> (String) label.get(\"name\")));\n\t}\n\n\t@Override\n\tpublic List<Milestone> getMilestones() {\n\t\treturn get(\"milestones?per_page=100\", (milestone) -> new Milestone((String) milestone.get(\"title\"),\n\t\t\t\t(Integer) milestone.get(\"number\"),\n\t\t\t\t(milestone.get(\"due_on\") != null) ? OffsetDateTime.parse((String) milestone.get(\"due_on\")) : null));\n\t}\n\n\t@Override\n\tpublic List<Issue> findIssues(List<String> labels, Milestone milestone) {\n\t\treturn get(\n\t\t\t\t\"issues?per_page=100&state=all&labels=\" + String.join(\",\", labels) + \"&milestone=\"\n\t\t\t\t\t\t+ milestone.getNumber(),\n\t\t\t\t(issue) -> new Issue(this.rest, (Integer) issue.get(\"number\"), (String) issue.get(\"title\"),\n\t\t\t\t\t\tIssue.State.of((String) issue.get(\"state\"))));\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate <T> List<T> get(String name, Function<Map<String, Object>, T> mapper) {\n\t\tResponseEntity<List> response = this.rest.getForEntity(name, List.class);\n\t\treturn ((List<Map<String, Object>>) response.getBody()).stream().map(mapper).toList();\n\t}\n\n\tprivate static void sleep(Duration duration) {\n\t\ttry {\n\t\t\tThread.sleep(duration.toMillis());\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/AbstractDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.apache.maven.artifact.versioning.ComparableVersion;\n\n/**\n * Base class for {@link DependencyVersion} implementations.\n *\n * @author Andy Wilkinson\n */\nabstract class AbstractDependencyVersion implements DependencyVersion {\n\n\tprivate final ComparableVersion comparableVersion;\n\n\tprotected AbstractDependencyVersion(ComparableVersion comparableVersion) {\n\t\tthis.comparableVersion = comparableVersion;\n\t}\n\n\t@Override\n\tpublic int compareTo(DependencyVersion other) {\n\t\tComparableVersion otherComparable = (other instanceof AbstractDependencyVersion otherVersion)\n\t\t\t\t? otherVersion.comparableVersion : new ComparableVersion(other.toString());\n\t\treturn this.comparableVersion.compareTo(otherComparable);\n\t}\n\n\t@Override\n\tpublic boolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots) {\n\t\tComparableVersion comparableCandidate = (candidate instanceof AbstractDependencyVersion abstractDependencyVersion)\n\t\t\t\t? abstractDependencyVersion.comparableVersion : new ComparableVersion(candidate.toString());\n\t\treturn comparableCandidate.compareTo(this.comparableVersion) > 0;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tAbstractDependencyVersion other = (AbstractDependencyVersion) obj;\n\t\treturn this.comparableVersion.equals(other.comparableVersion);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.comparableVersion.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.comparableVersion.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ArtifactVersionDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.apache.maven.artifact.versioning.ArtifactVersion;\nimport org.apache.maven.artifact.versioning.ComparableVersion;\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link DependencyVersion} backed by an {@link ArtifactVersion}.\n *\n * @author Andy Wilkinson\n */\nclass ArtifactVersionDependencyVersion extends AbstractDependencyVersion {\n\n\tprivate final ArtifactVersion artifactVersion;\n\n\tprotected ArtifactVersionDependencyVersion(ArtifactVersion artifactVersion) {\n\t\tsuper(new ComparableVersion(toNormalizedString(artifactVersion)));\n\t\tthis.artifactVersion = artifactVersion;\n\t}\n\n\tprivate static String toNormalizedString(ArtifactVersion artifactVersion) {\n\t\tString versionString = artifactVersion.toString();\n\t\tif (versionString.endsWith(\".RELEASE\")) {\n\t\t\treturn versionString.substring(0, versionString.length() - 8);\n\t\t}\n\t\tif (versionString.endsWith(\".BUILD-SNAPSHOT\")) {\n\t\t\treturn versionString.substring(0, versionString.length() - 15) + \"-SNAPSHOT\";\n\t\t}\n\t\treturn versionString;\n\t}\n\n\tprotected ArtifactVersionDependencyVersion(ArtifactVersion artifactVersion, ComparableVersion comparableVersion) {\n\t\tsuper(comparableVersion);\n\t\tthis.artifactVersion = artifactVersion;\n\t}\n\n\t@Override\n\tpublic boolean isSameMajor(DependencyVersion other) {\n\t\tif (other instanceof ReleaseTrainDependencyVersion) {\n\t\t\treturn false;\n\t\t}\n\t\treturn extractArtifactVersionDependencyVersion(other).map(this::isSameMajor).orElse(true);\n\t}\n\n\tprivate boolean isSameMajor(ArtifactVersionDependencyVersion other) {\n\t\treturn this.artifactVersion.getMajorVersion() == other.artifactVersion.getMajorVersion();\n\t}\n\n\t@Override\n\tpublic boolean isSameMinor(DependencyVersion other) {\n\t\tif (other instanceof ReleaseTrainDependencyVersion) {\n\t\t\treturn false;\n\t\t}\n\t\treturn extractArtifactVersionDependencyVersion(other).map(this::isSameMinor).orElse(true);\n\t}\n\n\tprivate boolean isSameMinor(ArtifactVersionDependencyVersion other) {\n\t\treturn isSameMajor(other) && this.artifactVersion.getMinorVersion() == other.artifactVersion.getMinorVersion();\n\t}\n\n\t@Override\n\tpublic boolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots) {\n\t\tif (candidate instanceof MultipleComponentsDependencyVersion) {\n\t\t\treturn super.isUpgrade(candidate, movingToSnapshots);\n\t\t}\n\t\tif (!(candidate instanceof ArtifactVersionDependencyVersion)) {\n\t\t\treturn false;\n\t\t}\n\t\tArtifactVersion other = ((ArtifactVersionDependencyVersion) candidate).artifactVersion;\n\t\tif (this.artifactVersion.equals(other)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (sameMajorMinorIncremental(other)) {\n\t\t\tif (!StringUtils.hasLength(this.artifactVersion.getQualifier())\n\t\t\t\t\t|| \"RELEASE\".equals(this.artifactVersion.getQualifier())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (isSnapshot()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if (((ArtifactVersionDependencyVersion) candidate).isSnapshot()) {\n\t\t\t\treturn movingToSnapshots;\n\t\t\t}\n\t\t}\n\t\treturn super.isUpgrade(candidate, movingToSnapshots);\n\t}\n\n\tprivate boolean sameMajorMinorIncremental(ArtifactVersion other) {\n\t\treturn this.artifactVersion.getMajorVersion() == other.getMajorVersion()\n\t\t\t\t&& this.artifactVersion.getMinorVersion() == other.getMinorVersion()\n\t\t\t\t&& this.artifactVersion.getIncrementalVersion() == other.getIncrementalVersion();\n\t}\n\n\tprivate boolean isSnapshot() {\n\t\treturn \"SNAPSHOT\".equals(this.artifactVersion.getQualifier())\n\t\t\t\t|| \"BUILD\".equals(this.artifactVersion.getQualifier());\n\t}\n\n\t@Override\n\tpublic boolean isSnapshotFor(DependencyVersion candidate) {\n\t\tif (!isSnapshot() || !(candidate instanceof ArtifactVersionDependencyVersion)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn sameMajorMinorIncremental(((ArtifactVersionDependencyVersion) candidate).artifactVersion);\n\t}\n\n\t@Override\n\tpublic int compareTo(DependencyVersion other) {\n\t\tif (other instanceof ArtifactVersionDependencyVersion otherArtifactDependencyVersion) {\n\t\t\tArtifactVersion otherArtifactVersion = otherArtifactDependencyVersion.artifactVersion;\n\t\t\tif ((!Objects.equals(this.artifactVersion.getQualifier(), otherArtifactVersion.getQualifier()))\n\t\t\t\t\t&& \"snapshot\".equalsIgnoreCase(otherArtifactVersion.getQualifier())\n\t\t\t\t\t&& otherArtifactVersion.getMajorVersion() == this.artifactVersion.getMajorVersion()\n\t\t\t\t\t&& otherArtifactVersion.getMinorVersion() == this.artifactVersion.getMinorVersion()\n\t\t\t\t\t&& otherArtifactVersion.getIncrementalVersion() == this.artifactVersion.getIncrementalVersion()) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\treturn super.compareTo(other);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.artifactVersion.toString();\n\t}\n\n\tprotected Optional<ArtifactVersionDependencyVersion> extractArtifactVersionDependencyVersion(\n\t\t\tDependencyVersion other) {\n\t\tArtifactVersionDependencyVersion artifactVersion = null;\n\t\tif (other instanceof ArtifactVersionDependencyVersion otherVersion) {\n\t\t\tartifactVersion = otherVersion;\n\t\t}\n\t\treturn Optional.ofNullable(artifactVersion);\n\t}\n\n\tstatic ArtifactVersionDependencyVersion parse(String version) {\n\t\tArtifactVersion artifactVersion = new DefaultArtifactVersion(version);\n\t\tif (artifactVersion.getQualifier() != null && artifactVersion.getQualifier().equals(version)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ArtifactVersionDependencyVersion(artifactVersion);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/CalendarVersionDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.util.regex.Pattern;\n\nimport org.apache.maven.artifact.versioning.ArtifactVersion;\nimport org.apache.maven.artifact.versioning.ComparableVersion;\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\n\n/**\n * A specialization of {@link ArtifactVersionDependencyVersion} for calendar versions.\n * Calendar versions are always considered to be newer than\n * {@link ReleaseTrainDependencyVersion release train versions}.\n *\n * @author Andy Wilkinson\n */\nclass CalendarVersionDependencyVersion extends ArtifactVersionDependencyVersion {\n\n\tprivate static final Pattern CALENDAR_VERSION_PATTERN = Pattern.compile(\"\\\\d{4}\\\\.\\\\d+\\\\.\\\\d+(-.+)?\");\n\n\tprotected CalendarVersionDependencyVersion(ArtifactVersion artifactVersion) {\n\t\tsuper(artifactVersion);\n\t}\n\n\tprotected CalendarVersionDependencyVersion(ArtifactVersion artifactVersion, ComparableVersion comparableVersion) {\n\t\tsuper(artifactVersion, comparableVersion);\n\t}\n\n\tstatic CalendarVersionDependencyVersion parse(String version) {\n\t\tif (!CALENDAR_VERSION_PATTERN.matcher(version).matches()) {\n\t\t\treturn null;\n\t\t}\n\t\tArtifactVersion artifactVersion = new DefaultArtifactVersion(version);\n\t\tif (artifactVersion.getQualifier() != null && artifactVersion.getQualifier().equals(version)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new CalendarVersionDependencyVersion(artifactVersion);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/CombinedPatchAndQualifierDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.maven.artifact.versioning.ArtifactVersion;\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\n\n/**\n * A {@link DependencyVersion} where the patch and qualifier are not separated.\n *\n * @author Andy Wilkinson\n */\nfinal class CombinedPatchAndQualifierDependencyVersion extends ArtifactVersionDependencyVersion {\n\n\tprivate static final Pattern PATTERN = Pattern.compile(\"([0-9]+\\\\.[0-9]+\\\\.[0-9]+)([A-Za-z][A-Za-z0-9]+)\");\n\n\tprivate final String original;\n\n\tprivate CombinedPatchAndQualifierDependencyVersion(ArtifactVersion artifactVersion, String original) {\n\t\tsuper(artifactVersion);\n\t\tthis.original = original;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.original;\n\t}\n\n\tstatic CombinedPatchAndQualifierDependencyVersion parse(String version) {\n\t\tMatcher matcher = PATTERN.matcher(version);\n\t\tif (!matcher.matches()) {\n\t\t\treturn null;\n\t\t}\n\t\tArtifactVersion artifactVersion = new DefaultArtifactVersion(matcher.group(1) + \".\" + matcher.group(2));\n\t\tif (artifactVersion.getQualifier() != null && artifactVersion.getQualifier().equals(version)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new CombinedPatchAndQualifierDependencyVersion(artifactVersion, version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/DependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Function;\n\n/**\n * Version of a dependency.\n *\n * @author Andy Wilkinson\n */\npublic interface DependencyVersion extends Comparable<DependencyVersion> {\n\n\t/**\n\t * Returns whether this version has the same major and minor versions as the\n\t * {@code other} version.\n\t * @param other the version to test\n\t * @return {@code true} if this version has the same major and minor, otherwise\n\t * {@code false}\n\t */\n\tboolean isSameMinor(DependencyVersion other);\n\n\t/**\n\t * Returns whether this version has the same major version as the {@code other}\n\t * version.\n\t * @param other the version to test\n\t * @return {@code true} if this version has the same major, otherwise {@code false}\n\t */\n\tboolean isSameMajor(DependencyVersion other);\n\n\t/**\n\t * Returns whether the given {@code candidate} is an upgrade of this version.\n\t * @param candidate the version to consider\n\t * @param movingToSnapshots whether the upgrade is to be considered as part of moving\n\t * to snapshots\n\t * @return {@code true} if the candidate is an upgrade, otherwise false\n\t */\n\tboolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots);\n\n\t/**\n\t * Returns whether this version is a snapshot for the given {@code candidate}.\n\t * @param candidate the version to consider\n\t * @return {@code true} if this version is a snapshot for the candidate, otherwise\n\t * false\n\t */\n\tboolean isSnapshotFor(DependencyVersion candidate);\n\n\tstatic DependencyVersion parse(String version) {\n\t\tList<Function<String, DependencyVersion>> parsers = Arrays.asList(CalendarVersionDependencyVersion::parse,\n\t\t\t\tArtifactVersionDependencyVersion::parse, ReleaseTrainDependencyVersion::parse,\n\t\t\t\tMultipleComponentsDependencyVersion::parse, CombinedPatchAndQualifierDependencyVersion::parse,\n\t\t\t\tLeadingZeroesDependencyVersion::parse, UnstructuredDependencyVersion::parse);\n\t\tfor (Function<String, DependencyVersion> parser : parsers) {\n\t\t\tDependencyVersion result = parser.apply(version);\n\t\t\tif (result != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Version '\" + version + \"' could not be parsed\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/LeadingZeroesDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.maven.artifact.versioning.ArtifactVersion;\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\n\n/**\n * A {@link DependencyVersion} that tolerates leading zeroes.\n *\n * @author Andy Wilkinson\n */\nfinal class LeadingZeroesDependencyVersion extends ArtifactVersionDependencyVersion {\n\n\tprivate static final Pattern PATTERN = Pattern.compile(\"0*([0-9]+)\\\\.0*([0-9]+)\\\\.0*([0-9]+)\");\n\n\tprivate final String original;\n\n\tprivate LeadingZeroesDependencyVersion(ArtifactVersion artifactVersion, String original) {\n\t\tsuper(artifactVersion);\n\t\tthis.original = original;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.original;\n\t}\n\n\tstatic LeadingZeroesDependencyVersion parse(String input) {\n\t\tMatcher matcher = PATTERN.matcher(input);\n\t\tif (!matcher.matches()) {\n\t\t\treturn null;\n\t\t}\n\t\tArtifactVersion artifactVersion = new DefaultArtifactVersion(\n\t\t\t\tmatcher.group(1) + matcher.group(2) + matcher.group(3));\n\t\treturn new LeadingZeroesDependencyVersion(artifactVersion, input);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/MultipleComponentsDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.apache.maven.artifact.versioning.ArtifactVersion;\nimport org.apache.maven.artifact.versioning.ComparableVersion;\nimport org.apache.maven.artifact.versioning.DefaultArtifactVersion;\n\n/**\n * A fallback {@link DependencyVersion} to handle versions with four or five components\n * that cannot be handled by {@link ArtifactVersion} because the fourth component is\n * numeric.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nfinal class MultipleComponentsDependencyVersion extends ArtifactVersionDependencyVersion {\n\n\tprivate final String original;\n\n\tprivate MultipleComponentsDependencyVersion(ArtifactVersion artifactVersion, String original) {\n\t\tsuper(artifactVersion, new ComparableVersion(original));\n\t\tthis.original = original;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.original;\n\t}\n\n\tstatic MultipleComponentsDependencyVersion parse(String input) {\n\t\tString[] components = input.split(\"\\\\.\");\n\t\tif (components.length == 4 || components.length == 5) {\n\t\t\tArtifactVersion artifactVersion = new DefaultArtifactVersion(\n\t\t\t\t\tcomponents[0] + \".\" + components[1] + \".\" + components[2]);\n\t\t\tif (artifactVersion.getQualifier() != null && artifactVersion.getQualifier().equals(input)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn new MultipleComponentsDependencyVersion(artifactVersion, input);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/ReleaseTrainDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link DependencyVersion} for a release train such as Spring Data.\n *\n * @author Andy Wilkinson\n */\nfinal class ReleaseTrainDependencyVersion implements DependencyVersion {\n\n\tprivate static final Pattern VERSION_PATTERN = Pattern\n\t\t.compile(\"([A-Z][a-z]+)-((BUILD-SNAPSHOT)|([A-Z-]+)([0-9]*))\");\n\n\tprivate final String releaseTrain;\n\n\tprivate final String type;\n\n\tprivate final int version;\n\n\tprivate final String original;\n\n\tprivate ReleaseTrainDependencyVersion(String releaseTrain, String type, int version, String original) {\n\t\tthis.releaseTrain = releaseTrain;\n\t\tthis.type = type;\n\t\tthis.version = version;\n\t\tthis.original = original;\n\t}\n\n\t@Override\n\tpublic int compareTo(DependencyVersion other) {\n\t\tif (!(other instanceof ReleaseTrainDependencyVersion otherReleaseTrain)) {\n\t\t\treturn -1;\n\t\t}\n\t\tint comparison = this.releaseTrain.compareTo(otherReleaseTrain.releaseTrain);\n\t\tif (comparison != 0) {\n\t\t\treturn comparison;\n\t\t}\n\t\tcomparison = this.type.compareTo(otherReleaseTrain.type);\n\t\tif (comparison != 0) {\n\t\t\treturn comparison;\n\t\t}\n\t\treturn Integer.compare(this.version, otherReleaseTrain.version);\n\t}\n\n\t@Override\n\tpublic boolean isUpgrade(DependencyVersion candidate, boolean movingToSnapshots) {\n\t\tif (candidate instanceof ReleaseTrainDependencyVersion candidateReleaseTrain) {\n\t\t\treturn isUpgrade(candidateReleaseTrain, movingToSnapshots);\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate boolean isUpgrade(ReleaseTrainDependencyVersion candidate, boolean movingToSnapshots) {\n\t\tint comparison = this.releaseTrain.compareTo(candidate.releaseTrain);\n\t\tif (comparison != 0) {\n\t\t\treturn comparison < 0;\n\t\t}\n\t\tif (movingToSnapshots && !isSnapshot() && candidate.isSnapshot()) {\n\t\t\treturn true;\n\t\t}\n\t\tcomparison = this.type.compareTo(candidate.type);\n\t\tif (comparison != 0) {\n\t\t\treturn comparison < 0;\n\t\t}\n\t\treturn Integer.compare(this.version, candidate.version) < 0;\n\t}\n\n\tprivate boolean isSnapshot() {\n\t\treturn \"BUILD-SNAPSHOT\".equals(this.type);\n\t}\n\n\t@Override\n\tpublic boolean isSnapshotFor(DependencyVersion candidate) {\n\t\tif (!isSnapshot() || !(candidate instanceof ReleaseTrainDependencyVersion candidateReleaseTrain)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.releaseTrain.equals(candidateReleaseTrain.releaseTrain);\n\t}\n\n\t@Override\n\tpublic boolean isSameMajor(DependencyVersion other) {\n\t\treturn isSameReleaseTrain(other);\n\t}\n\n\t@Override\n\tpublic boolean isSameMinor(DependencyVersion other) {\n\t\treturn isSameReleaseTrain(other);\n\t}\n\n\tprivate boolean isSameReleaseTrain(DependencyVersion other) {\n\t\tif (other instanceof CalendarVersionDependencyVersion) {\n\t\t\treturn false;\n\t\t}\n\t\tif (other instanceof ReleaseTrainDependencyVersion otherReleaseTrain) {\n\t\t\treturn otherReleaseTrain.releaseTrain.equals(this.releaseTrain);\n\t\t}\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tReleaseTrainDependencyVersion other = (ReleaseTrainDependencyVersion) obj;\n\t\treturn this.original.equals(other.original);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.original.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.original;\n\t}\n\n\tstatic ReleaseTrainDependencyVersion parse(String input) {\n\t\tMatcher matcher = VERSION_PATTERN.matcher(input);\n\t\tif (!matcher.matches()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ReleaseTrainDependencyVersion(matcher.group(1),\n\t\t\t\tStringUtils.hasLength(matcher.group(3)) ? matcher.group(3) : matcher.group(4),\n\t\t\t\t(StringUtils.hasLength(matcher.group(5))) ? Integer.parseInt(matcher.group(5)) : 0, input);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/bom/bomr/version/UnstructuredDependencyVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.apache.maven.artifact.versioning.ComparableVersion;\n\n/**\n * A {@link DependencyVersion} with no structure such that version comparisons are not\n * possible.\n *\n * @author Andy Wilkinson\n */\nfinal class UnstructuredDependencyVersion extends AbstractDependencyVersion implements DependencyVersion {\n\n\tprivate final String version;\n\n\tprivate UnstructuredDependencyVersion(String version) {\n\t\tsuper(new ComparableVersion(version));\n\t\tthis.version = version;\n\t}\n\n\t@Override\n\tpublic boolean isSameMajor(DependencyVersion other) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic boolean isSameMinor(DependencyVersion other) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.version;\n\t}\n\n\t@Override\n\tpublic boolean isSnapshotFor(DependencyVersion candidate) {\n\t\treturn false;\n\t}\n\n\tstatic UnstructuredDependencyVersion parse(String version) {\n\t\treturn new UnstructuredDependencyVersion(version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForConflicts.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.classpath;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.function.Predicate;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * A {@link Task} for checking the classpath for conflicting classes and resources.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckClasspathForConflicts extends DefaultTask {\n\n\tprivate final List<Predicate<String>> ignores = new ArrayList<>();\n\n\tprivate FileCollection classpath;\n\n\tpublic void setClasspath(FileCollection classpath) {\n\t\tthis.classpath = classpath;\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\t@TaskAction\n\tpublic void checkForConflicts() throws IOException {\n\t\tClasspathContents classpathContents = new ClasspathContents();\n\t\tfor (File file : this.classpath) {\n\t\t\tif (file.isDirectory()) {\n\t\t\t\tPath root = file.toPath();\n\t\t\t\ttry (Stream<Path> pathStream = Files.walk(root)) {\n\t\t\t\t\tpathStream.filter(Files::isRegularFile)\n\t\t\t\t\t\t.forEach((entry) -> classpathContents.add(root.relativize(entry).toString(), root.toString()));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\t\t\tfor (JarEntry entry : Collections.list(jar.entries())) {\n\t\t\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\t\t\tclasspathContents.add(entry.getName(), file.getAbsolutePath());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tMap<String, List<String>> conflicts = classpathContents.getConflicts(this.ignores);\n\t\tif (!conflicts.isEmpty()) {\n\t\t\tStringBuilder message = new StringBuilder(String.format(\"Found classpath conflicts:%n\"));\n\t\t\tconflicts.forEach((entry, locations) -> {\n\t\t\t\tmessage.append(String.format(\"    %s%n\", entry));\n\t\t\t\tlocations.forEach((location) -> message.append(String.format(\"        %s%n\", location)));\n\t\t\t});\n\t\t\tthrow new GradleException(message.toString());\n\t\t}\n\t}\n\n\tpublic void ignore(Predicate<String> predicate) {\n\t\tthis.ignores.add(predicate);\n\t}\n\n\tprivate static final class ClasspathContents {\n\n\t\tprivate static final Set<String> IGNORED_NAMES = new HashSet<>(Arrays.asList(\"about.html\", \"changelog.txt\",\n\t\t\t\t\"LICENSE\", \"license.txt\", \"module-info.class\", \"notice.txt\", \"readme.txt\"));\n\n\t\tprivate final Map<String, List<String>> classpathContents = new HashMap<>();\n\n\t\tprivate void add(String name, String source) {\n\t\t\tthis.classpathContents.computeIfAbsent(name, (key) -> new ArrayList<>()).add(source);\n\t\t}\n\n\t\tprivate Map<String, List<String>> getConflicts(List<Predicate<String>> ignores) {\n\t\t\treturn this.classpathContents.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((entry) -> entry.getValue().size() > 1)\n\t\t\t\t.filter((entry) -> canConflict(entry.getKey(), ignores))\n\t\t\t\t.collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1, v2) -> v1, TreeMap::new));\n\t\t}\n\n\t\tprivate boolean canConflict(String name, List<Predicate<String>> ignores) {\n\t\t\tif (name.startsWith(\"META-INF/\")) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (String ignoredName : IGNORED_NAMES) {\n\t\t\t\tif (name.equals(ignoredName)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (Predicate<String> ignore : ignores) {\n\t\t\t\tif (ignore.test(name)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForProhibitedDependencies.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.classpath;\n\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ModuleVersionIdentifier;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.provider.SetProperty;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * A {@link Task} for checking the classpath for prohibited dependencies.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckClasspathForProhibitedDependencies extends DefaultTask {\n\n\tprivate static final Set<String> PROHIBITED_GROUPS = Set.of(\"org.codehaus.groovy\", \"org.eclipse.jetty.toolchain\",\n\t\t\t\"org.apache.geronimo.specs\", \"com.sun.activation\");\n\n\tprivate static final Set<String> PERMITTED_JAVAX_GROUPS = Set.of(\"javax.batch\", \"javax.cache\", \"javax.money\");\n\n\tprivate Configuration classpath;\n\n\tpublic CheckClasspathForProhibitedDependencies() {\n\t\tgetOutputs().upToDateWhen((task) -> true);\n\t}\n\n\t@Input\n\tpublic abstract SetProperty<String> getPermittedGroups();\n\n\tpublic void setClasspath(Configuration classpath) {\n\t\tthis.classpath = classpath;\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\t@TaskAction\n\tpublic void checkForProhibitedDependencies() {\n\t\tTreeSet<String> prohibited = this.classpath.getResolvedConfiguration()\n\t\t\t.getResolvedArtifacts()\n\t\t\t.stream()\n\t\t\t.map((artifact) -> artifact.getModuleVersion().getId())\n\t\t\t.filter(this::prohibited)\n\t\t\t.map((id) -> id.getGroup() + \":\" + id.getName())\n\t\t\t.collect(Collectors.toCollection(TreeSet::new));\n\t\tif (!prohibited.isEmpty()) {\n\t\t\tStringBuilder message = new StringBuilder(String.format(\"Found prohibited dependencies:%n\"));\n\t\t\tfor (String dependency : prohibited) {\n\t\t\t\tmessage.append(String.format(\"    %s%n\", dependency));\n\t\t\t}\n\t\t\tthrow new GradleException(message.toString());\n\t\t}\n\t}\n\n\tprivate boolean prohibited(ModuleVersionIdentifier id) {\n\t\treturn (!getPermittedGroups().get().contains(id.getGroup())) && (PROHIBITED_GROUPS.contains(id.getGroup())\n\t\t\t\t|| prohibitedJavax(id) || prohibitedSlf4j(id) || prohibitedJbossSpec(id));\n\t}\n\n\tprivate boolean prohibitedSlf4j(ModuleVersionIdentifier id) {\n\t\treturn id.getGroup().equals(\"org.slf4j\") && id.getName().equals(\"jcl-over-slf4j\");\n\t}\n\n\tprivate boolean prohibitedJbossSpec(ModuleVersionIdentifier id) {\n\t\treturn id.getGroup().startsWith(\"org.jboss.spec\");\n\t}\n\n\tprivate boolean prohibitedJavax(ModuleVersionIdentifier id) {\n\t\treturn id.getGroup().startsWith(\"javax.\") && !PERMITTED_JAVAX_GROUPS.contains(id.getGroup());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnconstrainedDirectDependencies.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.classpath;\n\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.component.ModuleComponentSelector;\nimport org.gradle.api.artifacts.result.DependencyResult;\nimport org.gradle.api.artifacts.result.ResolutionResult;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * Tasks to check that none of classpath's direct dependencies are unconstrained.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckClasspathForUnconstrainedDirectDependencies extends DefaultTask {\n\n\tprivate Configuration classpath;\n\n\tpublic CheckClasspathForUnconstrainedDirectDependencies() {\n\t\tgetOutputs().upToDateWhen((task) -> true);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(Configuration classpath) {\n\t\tthis.classpath = classpath;\n\t}\n\n\t@TaskAction\n\tvoid checkForUnconstrainedDirectDependencies() {\n\t\tResolutionResult resolutionResult = this.classpath.getIncoming().getResolutionResult();\n\t\tSet<? extends DependencyResult> dependencies = resolutionResult.getRoot().getDependencies();\n\t\tSet<String> unconstrainedDependencies = dependencies.stream()\n\t\t\t.map(DependencyResult::getRequested)\n\t\t\t.filter(ModuleComponentSelector.class::isInstance)\n\t\t\t.map(ModuleComponentSelector.class::cast)\n\t\t\t.map((selector) -> selector.getGroup() + \":\" + selector.getModule())\n\t\t\t.collect(Collectors.toSet());\n\t\tSet<String> constraints = resolutionResult.getAllDependencies()\n\t\t\t.stream()\n\t\t\t.filter(DependencyResult::isConstraint)\n\t\t\t.map(DependencyResult::getRequested)\n\t\t\t.filter(ModuleComponentSelector.class::isInstance)\n\t\t\t.map(ModuleComponentSelector.class::cast)\n\t\t\t.map((selector) -> selector.getGroup() + \":\" + selector.getModule())\n\t\t\t.collect(Collectors.toSet());\n\t\tunconstrainedDependencies.removeAll(constraints);\n\t\tif (!unconstrainedDependencies.isEmpty()) {\n\t\t\tthrow new GradleException(\"Found unconstrained direct dependencies: \" + unconstrainedDependencies);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/classpath/CheckClasspathForUnnecessaryExclusions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.classpath;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.artifacts.Dependency;\nimport org.gradle.api.artifacts.ExcludeRule;\nimport org.gradle.api.artifacts.ModuleDependency;\nimport org.gradle.api.artifacts.component.ModuleComponentIdentifier;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * A {@link Task} for checking the classpath for unnecessary exclusions.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckClasspathForUnnecessaryExclusions extends DefaultTask {\n\n\tprivate static final Map<String, String> SPRING_BOOT_DEPENDENCIES_PROJECT = Collections.singletonMap(\"path\",\n\t\t\t\":platform:spring-boot-dependencies\");\n\n\tprivate final Map<String, Set<String>> exclusionsByDependencyId = new TreeMap<>();\n\n\tprivate final Map<String, Dependency> dependencyById = new HashMap<>();\n\n\tprivate final Dependency platform;\n\n\tprivate final DependencyHandler dependencies;\n\n\tprivate final ConfigurationContainer configurations;\n\n\tprivate Configuration classpath;\n\n\t@Inject\n\tpublic CheckClasspathForUnnecessaryExclusions(DependencyHandler dependencyHandler,\n\t\t\tConfigurationContainer configurations) {\n\t\tthis.dependencies = getProject().getDependencies();\n\t\tthis.configurations = getProject().getConfigurations();\n\t\tthis.platform = this.dependencies\n\t\t\t.create(this.dependencies.platform(this.dependencies.project(SPRING_BOOT_DEPENDENCIES_PROJECT)));\n\t\tgetOutputs().upToDateWhen((task) -> true);\n\t}\n\n\tpublic void setClasspath(Configuration classpath) {\n\t\tthis.classpath = classpath;\n\t\tthis.exclusionsByDependencyId.clear();\n\t\tthis.dependencyById.clear();\n\t\tclasspath.getAllDependencies().all(this::processDependency);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tprivate void processDependency(Dependency dependency) {\n\t\tif (dependency instanceof ModuleDependency moduleDependency) {\n\t\t\tprocessDependency(moduleDependency);\n\t\t}\n\t}\n\n\tprivate void processDependency(ModuleDependency dependency) {\n\t\tString dependencyId = getId(dependency);\n\t\tTreeSet<String> exclusions = dependency.getExcludeRules()\n\t\t\t.stream()\n\t\t\t.map(this::getId)\n\t\t\t.collect(Collectors.toCollection(TreeSet::new));\n\t\tthis.exclusionsByDependencyId.put(dependencyId, exclusions);\n\t\tif (!exclusions.isEmpty()) {\n\t\t\tthis.dependencyById.put(dependencyId, this.dependencies.create(dependencyId));\n\t\t}\n\t}\n\n\t@Input\n\tMap<String, Set<String>> getExclusionsByDependencyId() {\n\t\treturn this.exclusionsByDependencyId;\n\t}\n\n\t@TaskAction\n\tpublic void checkForUnnecessaryExclusions() {\n\t\tMap<String, Set<String>> unnecessaryExclusions = new HashMap<>();\n\t\tthis.exclusionsByDependencyId.forEach((dependencyId, exclusions) -> {\n\t\t\tif (!exclusions.isEmpty()) {\n\t\t\t\tDependency toCheck = this.dependencyById.get(dependencyId);\n\t\t\t\tthis.configurations.detachedConfiguration(toCheck, this.platform)\n\t\t\t\t\t.getIncoming()\n\t\t\t\t\t.getArtifacts()\n\t\t\t\t\t.getArtifacts()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map(this::getId)\n\t\t\t\t\t.forEach(exclusions::remove);\n\t\t\t\tremoveProfileExclusions(dependencyId, exclusions);\n\t\t\t\tif (!exclusions.isEmpty()) {\n\t\t\t\t\tunnecessaryExclusions.put(dependencyId, exclusions);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (!unnecessaryExclusions.isEmpty()) {\n\t\t\tthrow new GradleException(getExceptionMessage(unnecessaryExclusions));\n\t\t}\n\t}\n\n\tprivate void removeProfileExclusions(String dependencyId, Set<String> exclusions) {\n\t\tif (\"org.xmlunit:xmlunit-core\".equals(dependencyId)) {\n\t\t\texclusions.remove(\"javax.xml.bind:jaxb-api\");\n\t\t}\n\t}\n\n\tprivate String getExceptionMessage(Map<String, Set<String>> unnecessaryExclusions) {\n\t\tStringBuilder message = new StringBuilder(\"Unnecessary exclusions detected:\");\n\t\tfor (Entry<String, Set<String>> entry : unnecessaryExclusions.entrySet()) {\n\t\t\tmessage.append(String.format(\"%n    %s\", entry.getKey()));\n\t\t\tfor (String exclusion : entry.getValue()) {\n\t\t\t\tmessage.append(String.format(\"%n       %s\", exclusion));\n\t\t\t}\n\t\t}\n\t\treturn message.toString();\n\t}\n\n\tprivate String getId(ResolvedArtifactResult artifact) {\n\t\treturn getId((ModuleComponentIdentifier) artifact.getId().getComponentIdentifier());\n\t}\n\n\tprivate String getId(ModuleDependency dependency) {\n\t\treturn dependency.getGroup() + \":\" + dependency.getName();\n\t}\n\n\tprivate String getId(ExcludeRule rule) {\n\t\treturn rule.getGroup() + \":\" + rule.getModule();\n\t}\n\n\tprivate String getId(ModuleComponentIdentifier identifier) {\n\t\treturn identifier.getGroup() + \":\" + identifier.getModule();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/cli/HomebrewFormula.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.cli;\n\nimport java.io.File;\nimport java.security.MessageDigest;\n\nimport javax.inject.Inject;\n\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileSystemOperations;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.TaskExecutionException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.build.artifacts.ArtifactRelease;\nimport org.springframework.boot.build.properties.BuildProperties;\nimport org.springframework.boot.build.properties.BuildType;\n\n/**\n * A {@link Task} for creating a Homebrew formula manifest.\n *\n * @author Andy Wilkinson\n */\npublic abstract class HomebrewFormula extends DefaultTask {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(HomebrewFormula.class);\n\n\tprivate final FileSystemOperations fileSystemOperations;\n\n\tprivate final BuildType buildType;\n\n\t@Inject\n\tpublic HomebrewFormula(FileSystemOperations fileSystemOperations) {\n\t\tthis.fileSystemOperations = fileSystemOperations;\n\t\tProject project = getProject();\n\t\tMapProperty<String, Object> properties = getProperties();\n\t\tproperties.put(\"hash\", getArchive().map((archive) -> sha256(archive.getAsFile())));\n\t\tgetProperties().put(\"repo\", ArtifactRelease.forProject(project).getDownloadRepo());\n\t\tgetProperties().put(\"version\", project.getVersion().toString());\n\t\tthis.buildType = BuildProperties.get(getProject()).buildType();\n\t}\n\n\tprivate String sha256(File file) {\n\t\ttry {\n\t\t\tMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n\t\t\treturn new DigestUtils(digest).digestAsHex(file);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new TaskExecutionException(this, ex);\n\t\t}\n\t}\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract RegularFileProperty getArchive();\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract RegularFileProperty getTemplate();\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDir();\n\n\t@Input\n\tabstract MapProperty<String, Object> getProperties();\n\n\t@TaskAction\n\tvoid createFormula() {\n\t\tif (this.buildType != BuildType.OPEN_SOURCE) {\n\t\t\tlogger.debug(\"Skipping Homebrew formula for non open source build type\");\n\t\t\treturn;\n\t\t}\n\t\tthis.fileSystemOperations.copy((copy) -> {\n\t\t\tcopy.from(getTemplate());\n\t\t\tcopy.into(getOutputDir());\n\t\t\tcopy.expand(getProperties().get());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/Asciidoc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\n/**\n * Simple builder to help construct Asciidoc markup.\n *\n * @author Phillip Webb\n */\nclass Asciidoc {\n\n\tprivate final StringBuilder content;\n\n\tAsciidoc() {\n\t\tthis.content = new StringBuilder();\n\t}\n\n\tAsciidoc appendWithHardLineBreaks(Object... items) {\n\t\tfor (Object item : items) {\n\t\t\tappendln(\"`+\", item, \"+` +\");\n\t\t}\n\t\treturn this;\n\t}\n\n\tAsciidoc appendln(Object... items) {\n\t\treturn append(items).newLine();\n\t}\n\n\tAsciidoc append(Object... items) {\n\t\tfor (Object item : items) {\n\t\t\tthis.content.append(item);\n\t\t}\n\t\treturn this;\n\t}\n\n\tAsciidoc newLine() {\n\t\treturn append(System.lineSeparator());\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.content.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAdditionalSpringConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceTask;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\nimport org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;\n\n/**\n * {@link SourceTask} that checks additional Spring configuration metadata files.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckAdditionalSpringConfigurationMetadata extends SourceTask {\n\n\tprivate final File projectDir;\n\n\tpublic CheckAdditionalSpringConfigurationMetadata() {\n\t\tthis.projectDir = getProject().getProjectDir();\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getReportLocation();\n\n\t@Override\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileTree getSource() {\n\t\treturn super.getSource();\n\t}\n\n\t@TaskAction\n\tvoid check() throws IOException {\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(getSource().getFiles());\n\t\tReport report = new Report(this.projectDir);\n\t\tanalyzer.analyzeOrder(report);\n\t\tanalyzer.analyzeDuplicates(report);\n\t\tanalyzer.analyzeDeprecationSince(report);\n\t\tFile reportFile = getReportLocation().get().getAsFile();\n\t\treport.write(reportFile);\n\t\tif (report.hasProblems()) {\n\t\t\tthrow new VerificationException(\n\t\t\t\t\t\"Problems found in additional Spring configuration metadata. See \" + reportFile + \" for details.\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckAggregatedSpringConfigurationMetadata.java",
    "content": "/*\n * Copyright 2025 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\n/**\n * {@link Task} that checks aggregated Spring configuration metadata.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckAggregatedSpringConfigurationMetadata extends DefaultTask {\n\n\tprivate FileCollection configurationPropertyMetadata;\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getReportLocation();\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getConfigurationPropertyMetadata() {\n\t\treturn this.configurationPropertyMetadata;\n\t}\n\n\tpublic void setConfigurationPropertyMetadata(FileCollection configurationPropertyMetadata) {\n\t\tthis.configurationPropertyMetadata = configurationPropertyMetadata;\n\t}\n\n\t@TaskAction\n\tvoid check() throws IOException {\n\t\tReport report = createReport();\n\t\tFile reportFile = getReportLocation().get().getAsFile();\n\t\tFiles.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);\n\t\tif (report.hasProblems()) {\n\t\t\tthrow new VerificationException(\n\t\t\t\t\t\"Problems found in aggregated Spring configuration metadata. See \" + reportFile + \" for details.\");\n\t\t}\n\t}\n\n\tprivate Report createReport() {\n\t\tConfigurationProperties configurationProperties = ConfigurationProperties\n\t\t\t.fromFiles(this.configurationPropertyMetadata);\n\t\tSet<String> propertyNames = configurationProperties.stream()\n\t\t\t.map(ConfigurationProperty::getName)\n\t\t\t.collect(Collectors.toSet());\n\t\tList<ConfigurationProperty> missingReplacement = configurationProperties.stream()\n\t\t\t.filter(ConfigurationProperty::isDeprecated)\n\t\t\t.filter((deprecated) -> {\n\t\t\t\tString replacement = deprecated.getDeprecation().replacement();\n\t\t\t\treturn replacement != null && !propertyNames.contains(replacement);\n\t\t\t})\n\t\t\t.toList();\n\t\treturn new Report(missingReplacement);\n\t}\n\n\tprivate static final class Report implements Iterable<String> {\n\n\t\tprivate final List<ConfigurationProperty> propertiesWithMissingReplacement;\n\n\t\tprivate Report(List<ConfigurationProperty> propertiesWithMissingReplacement) {\n\t\t\tthis.propertiesWithMissingReplacement = propertiesWithMissingReplacement;\n\t\t}\n\n\t\tprivate boolean hasProblems() {\n\t\t\treturn !this.propertiesWithMissingReplacement.isEmpty();\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<String> iterator() {\n\t\t\tList<String> lines = new ArrayList<>();\n\t\t\tif (this.propertiesWithMissingReplacement.isEmpty()) {\n\t\t\t\tlines.add(\"No problems found.\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlines.add(\"The following properties have a replacement that does not exist:\");\n\t\t\t\tlines.add(\"\");\n\t\t\t\tlines.addAll(this.propertiesWithMissingReplacement.stream()\n\t\t\t\t\t.map((property) -> \"\\t\" + property.getName() + \" (replacement \"\n\t\t\t\t\t\t\t+ property.getDeprecation().replacement() + \")\")\n\t\t\t\t\t.toList());\n\t\t\t}\n\t\t\tlines.add(\"\");\n\t\t\treturn lines.iterator();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckManualSpringConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceTask;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\nimport org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;\n\n/**\n * {@link SourceTask} that checks manual Spring configuration metadata files.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\npublic abstract class CheckManualSpringConfigurationMetadata extends DefaultTask {\n\n\tprivate final File projectDir;\n\n\tpublic CheckManualSpringConfigurationMetadata() {\n\t\tthis.projectDir = getProject().getProjectDir();\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getReportLocation();\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract Property<File> getMetadataLocation();\n\n\t@Input\n\tpublic abstract ListProperty<String> getExclusions();\n\n\t@TaskAction\n\tvoid check() throws IOException {\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(\n\t\t\t\tList.of(getMetadataLocation().get()));\n\t\tReport report = new Report(this.projectDir);\n\t\tanalyzer.analyzeOrder(report);\n\t\tanalyzer.analyzeDuplicates(report);\n\t\tanalyzer.analyzePropertyDescription(report, getExclusions().get());\n\t\tanalyzer.analyzeDeprecationSince(report);\n\t\tFile reportFile = getReportLocation().get().getAsFile();\n\t\treport.write(reportFile);\n\t\tif (report.hasProblems()) {\n\t\t\tthrow new VerificationException(\n\t\t\t\t\t\"Problems found in manual Spring configuration metadata. See \" + reportFile + \" for details.\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/CheckSpringConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceTask;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\n\nimport org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;\n\n/**\n * {@link SourceTask} that checks {@code spring-configuration-metadata.json} files.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckSpringConfigurationMetadata extends DefaultTask {\n\n\tprivate final File projectRoot;\n\n\tpublic CheckSpringConfigurationMetadata() {\n\t\tthis.projectRoot = getProject().getProjectDir();\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getReportLocation();\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic abstract RegularFileProperty getMetadataLocation();\n\n\t@Input\n\tpublic abstract ListProperty<String> getExclusions();\n\n\t@TaskAction\n\tvoid check() throws IOException {\n\t\tReport report = new Report(this.projectRoot);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(\n\t\t\t\tList.of(getMetadataLocation().get().getAsFile()));\n\t\tanalyzer.analyzePropertyDescription(report, getExclusions().get());\n\t\tFile reportFile = getReportLocation().get().getAsFile();\n\t\treport.write(reportFile);\n\t\tif (report.hasProblems()) {\n\t\t\tthrow new VerificationException(\n\t\t\t\t\t\"Problems found in Spring configuration metadata. See \" + reportFile + \" for details.\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/CompoundRow.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.util.Set;\nimport java.util.TreeSet;\n\n/**\n * Table row regrouping a list of configuration properties sharing the same description.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass CompoundRow extends Row {\n\n\tprivate final Set<String> propertyNames;\n\n\tprivate final String description;\n\n\tCompoundRow(Snippet snippet, String prefix, String description) {\n\t\tsuper(snippet, prefix);\n\t\tthis.description = description;\n\t\tthis.propertyNames = new TreeSet<>();\n\t}\n\n\tvoid addProperty(ConfigurationProperty property) {\n\t\tthis.propertyNames.add(property.getDisplayName());\n\t}\n\n\tboolean isEmpty() {\n\t\treturn this.propertyNames.isEmpty();\n\t}\n\n\t@Override\n\tvoid write(Asciidoc asciidoc) {\n\t\tasciidoc.append(\"|\");\n\t\tasciidoc.append(\"[[\" + getAnchor() + \"]]\");\n\t\tasciidoc.append(\"xref:#\" + getAnchor() + \"[\");\n\t\tthis.propertyNames.forEach(asciidoc::appendWithHardLineBreaks);\n\t\tasciidoc.appendln(\"]\");\n\t\tasciidoc.appendln(\"|+++\", this.description, \"+++\");\n\t\tasciidoc.appendln(\"|\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationMetadataPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\nimport org.gradle.language.jvm.tasks.ProcessResources;\n\n/**\n * {@link Plugin} for projects that <em>only</em> define manual configuration metadata.\n * When applied, the plugin registers a {@link CheckManualSpringConfigurationMetadata}\n * task and configures the {@code check} task to depend upon it.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\npublic class ConfigurationMetadataPlugin implements Plugin<Project> {\n\n\tprivate static final String CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME = \"configurationPropertiesMetadata\";\n\n\t/**\n\t * Name of the {@link CheckAdditionalSpringConfigurationMetadata} task.\n\t */\n\tpublic static final String CHECK_MANUAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = \"checkManualSpringConfigurationMetadata\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> registerCheckAdditionalMetadataTask(project));\n\t}\n\n\tprivate void registerCheckAdditionalMetadataTask(Project project) {\n\t\tTaskProvider<CheckManualSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()\n\t\t\t.register(CHECK_MANUAL_SPRING_CONFIGURATION_METADATA_TASK_NAME,\n\t\t\t\t\tCheckManualSpringConfigurationMetadata.class);\n\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t.getSourceSets()\n\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tProvider<File> manualMetadataLocation = project.getTasks()\n\t\t\t.named(mainSourceSet.getProcessResourcesTaskName(), ProcessResources.class)\n\t\t\t.map((processResources) -> new File(processResources.getDestinationDir(),\n\t\t\t\t\t\"META-INF/spring-configuration-metadata.json\"));\n\t\tcheckConfigurationMetadata.configure((check) -> {\n\t\t\tcheck.getMetadataLocation().set(manualMetadataLocation);\n\t\t\tcheck.getReportLocation()\n\t\t\t\t.set(project.getLayout()\n\t\t\t\t\t.getBuildDirectory()\n\t\t\t\t\t.file(\"reports/manual-spring-configuration-metadata/check.txt\"));\n\t\t});\n\t\taddMetadataArtifact(project, manualMetadataLocation);\n\t\tproject.getTasks()\n\t\t\t.named(LifecycleBasePlugin.CHECK_TASK_NAME)\n\t\t\t.configure((check) -> check.dependsOn(checkConfigurationMetadata));\n\t}\n\n\tprivate void addMetadataArtifact(Project project, Provider<File> metadataLocation) {\n\t\tproject.getConfigurations()\n\t\t\t.consumable(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, (configuration) -> {\n\t\t\t\tconfiguration.attributes((attributes) -> {\n\t\t\t\t\tattributes.attribute(Category.CATEGORY_ATTRIBUTE,\n\t\t\t\t\t\t\tproject.getObjects().named(Category.class, Category.DOCUMENTATION));\n\t\t\t\t\tattributes.attribute(Usage.USAGE_ATTRIBUTE,\n\t\t\t\t\t\t\tproject.getObjects().named(Usage.class, \"configuration-properties-metadata\"));\n\t\t\t\t});\n\t\t\t});\n\t\tproject.getArtifacts().add(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, metadataLocation);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * Configuration properties read from one or more\n * {@code META-INF/spring-configuration-metadata.json} files.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nfinal class ConfigurationProperties {\n\n\tprivate final Map<String, ConfigurationProperty> byName;\n\n\tprivate ConfigurationProperties(List<ConfigurationProperty> properties) {\n\t\tMap<String, ConfigurationProperty> byName = new LinkedHashMap<>();\n\t\tfor (ConfigurationProperty property : properties) {\n\t\t\tbyName.put(property.getName(), property);\n\t\t}\n\t\tthis.byName = Collections.unmodifiableMap(byName);\n\t}\n\n\tConfigurationProperty get(String propertyName) {\n\t\treturn this.byName.get(propertyName);\n\t}\n\n\tStream<ConfigurationProperty> stream() {\n\t\treturn this.byName.values().stream();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tstatic ConfigurationProperties fromFiles(Iterable<File> files) {\n\t\tJsonMapper jsonMapper = new JsonMapper();\n\t\tList<ConfigurationProperty> properties = new ArrayList<>();\n\t\tfor (File file : files) {\n\t\t\tMap<String, Object> json = jsonMapper.readValue(file, Map.class);\n\t\t\tfor (Map<String, Object> property : (List<Map<String, Object>>) json.get(\"properties\")) {\n\t\t\t\tproperties.add(ConfigurationProperty.fromJsonProperties(property));\n\t\t\t}\n\t\t}\n\t\treturn new ConfigurationProperties(properties);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.nio.file.Files;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport tools.jackson.core.StreamReadFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * Check configuration metadata for inconsistencies. The available checks are:\n * <ul>\n * <li>Metadata elements {@link #analyzeOrder(Report) must be sorted alphabetically}</li>\n * <li>Metadata elements {@link #analyzeDuplicates(Report) must not be duplicates}</li>\n * <li>Properties {@link #analyzePropertyDescription(Report, List) must have a\n * description}</li>\n * </ul>\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationPropertiesAnalyzer {\n\n\tprivate static final List<String> ELEMENT_TYPES = List.of(\"groups\", \"properties\", \"hints\");\n\n\tprivate final Collection<File> sources;\n\n\tprivate final SingletonSupplier<JsonMapper> jsonMapperSupplier;\n\n\tConfigurationPropertiesAnalyzer(Collection<File> sources) {\n\t\tif (sources.isEmpty()) {\n\t\t\tthrow new IllegalArgumentException(\"At least one source should be provided\");\n\t\t}\n\t\tthis.sources = sources;\n\t\tthis.jsonMapperSupplier = SingletonSupplier\n\t\t\t.of(() -> JsonMapper.builder().enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION).build());\n\t}\n\n\tvoid analyzeOrder(Report report) {\n\t\tfor (File source : this.sources) {\n\t\t\treport.registerAnalysis(source, analyzeOrder(source));\n\t\t}\n\t}\n\n\tprivate Analysis analyzeOrder(File source) {\n\t\tMap<String, Object> json = readJsonContent(source);\n\t\tAnalysis analysis = new Analysis(\"Metadata element order:\");\n\t\tfor (String elementType : ELEMENT_TYPES) {\n\t\t\tanalyzeMetadataElementOrder(elementType, json, analysis);\n\t\t}\n\t\treturn analysis;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void analyzeMetadataElementOrder(String key, Map<String, Object> json, Analysis analysis) {\n\t\tList<Map<String, Object>> groups = (List<Map<String, Object>>) json.getOrDefault(key, Collections.emptyList());\n\t\tList<String> names = groups.stream().map((group) -> (String) group.get(\"name\")).toList();\n\t\tList<String> sortedNames = names.stream().sorted().toList();\n\t\tfor (int i = 0; i < names.size(); i++) {\n\t\t\tString actual = names.get(i);\n\t\t\tString expected = sortedNames.get(i);\n\t\t\tif (!actual.equals(expected)) {\n\t\t\t\tanalysis.addItem(\"Wrong order at $.\" + key + \"[\" + i + \"].name - expected '\" + expected\n\t\t\t\t\t\t+ \"' but found '\" + actual + \"'\");\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid analyzeDuplicates(Report report) {\n\t\tfor (File source : this.sources) {\n\t\t\treport.registerAnalysis(source, analyzeDuplicates(source));\n\t\t}\n\t}\n\n\tprivate Analysis analyzeDuplicates(File source) {\n\t\tMap<String, Object> json = readJsonContent(source);\n\t\tAnalysis analysis = new Analysis(\"Metadata element duplicates:\");\n\t\tfor (String elementType : ELEMENT_TYPES) {\n\t\t\tanalyzeMetadataElementDuplicates(elementType, json, analysis);\n\t\t}\n\t\treturn analysis;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void analyzeMetadataElementDuplicates(String key, Map<String, Object> json, Analysis analysis) {\n\t\tList<Map<String, Object>> elements = (List<Map<String, Object>>) json.getOrDefault(key,\n\t\t\t\tCollections.emptyList());\n\t\tList<String> names = elements.stream().map((group) -> (String) group.get(\"name\")).toList();\n\t\tSet<String> uniqueNames = new HashSet<>();\n\t\tfor (int i = 0; i < names.size(); i++) {\n\t\t\tString name = names.get(i);\n\t\t\tif (!uniqueNames.add(name)) {\n\t\t\t\tanalysis.addItem(\"Duplicate name '\" + name + \"' at $.\" + key + \"[\" + i + \"]\");\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid analyzePropertyDescription(Report report, List<String> exclusions) {\n\t\tfor (File source : this.sources) {\n\t\t\treport.registerAnalysis(source, analyzePropertyDescription(source, exclusions));\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Analysis analyzePropertyDescription(File source, List<String> exclusions) {\n\t\tMap<String, Object> json = readJsonContent(source);\n\t\tAnalysis analysis = new Analysis(\"The following properties have no description:\");\n\t\tList<Map<String, Object>> properties = (List<Map<String, Object>>) json.get(\"properties\");\n\t\tfor (Map<String, Object> property : properties) {\n\t\t\tString name = (String) property.get(\"name\");\n\t\t\tif (!isDeprecated(property) && !isDescribed(property) && !isExcluded(exclusions, name)) {\n\t\t\t\tanalysis.addItem(name);\n\t\t\t}\n\t\t}\n\t\treturn analysis;\n\t}\n\n\tprivate boolean isExcluded(List<String> exclusions, String propertyName) {\n\t\tfor (String exclusion : exclusions) {\n\t\t\tif (propertyName.equals(exclusion)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (exclusion.endsWith(\".*\")) {\n\t\t\t\tif (propertyName.startsWith(exclusion.substring(0, exclusion.length() - 2))) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isDeprecated(Map<String, Object> property) {\n\t\treturn property.get(\"deprecation\") != null;\n\t}\n\n\tprivate boolean isDescribed(Map<String, Object> property) {\n\t\treturn property.get(\"description\") != null;\n\t}\n\n\tvoid analyzeDeprecationSince(Report report) throws IOException {\n\t\tfor (File source : this.sources) {\n\t\t\treport.registerAnalysis(source, analyzeDeprecationSince(source));\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Analysis analyzeDeprecationSince(File source) throws IOException {\n\t\tAnalysis analysis = new Analysis(\"The following properties are deprecated without a 'since' version:\");\n\t\tMap<String, Object> json = readJsonContent(source);\n\t\tList<Map<String, Object>> properties = (List<Map<String, Object>>) json.get(\"properties\");\n\t\tproperties.stream().filter((property) -> property.containsKey(\"deprecation\")).forEach((property) -> {\n\t\t\tMap<String, Object> deprecation = (Map<String, Object>) property.get(\"deprecation\");\n\t\t\tif (!deprecation.containsKey(\"since\")) {\n\t\t\t\tanalysis.addItem(property.get(\"name\").toString());\n\t\t\t}\n\t\t});\n\t\treturn analysis;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, Object> readJsonContent(File source) {\n\t\treturn this.jsonMapperSupplier.obtain().readValue(source, Map.class);\n\t}\n\n\tprivate static <T> void writeAll(PrintWriter writer, Iterable<T> elements, Consumer<T> itemWriter) {\n\t\tIterator<T> it = elements.iterator();\n\t\twhile (it.hasNext()) {\n\t\t\titemWriter.accept(it.next());\n\t\t\tif (it.hasNext()) {\n\t\t\t\twriter.println();\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic class Report {\n\n\t\tprivate final File baseDirectory;\n\n\t\tprivate final MultiValueMap<File, Analysis> analyses = new LinkedMultiValueMap<>();\n\n\t\tReport(File baseDirectory) {\n\t\t\tthis.baseDirectory = baseDirectory;\n\t\t}\n\n\t\tvoid registerAnalysis(File path, Analysis analysis) {\n\t\t\tthis.analyses.add(path, analysis);\n\t\t}\n\n\t\tboolean hasProblems() {\n\t\t\treturn this.analyses.values()\n\t\t\t\t.stream()\n\t\t\t\t.anyMatch((candidates) -> candidates.stream().anyMatch(Analysis::hasProblems));\n\t\t}\n\n\t\tList<Analysis> getAnalyses(File source) {\n\t\t\treturn this.analyses.getOrDefault(source, Collections.emptyList());\n\t\t}\n\n\t\t/**\n\t\t * Write this report to the given {@code file}.\n\t\t * @param file the file to write the report to\n\t\t */\n\t\tvoid write(File file) throws IOException {\n\t\t\tFiles.writeString(file.toPath(), createContent(), StandardOpenOption.CREATE,\n\t\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t\t}\n\n\t\tprivate String createContent() {\n\t\t\tif (this.analyses.isEmpty()) {\n\t\t\t\treturn \"No problems found.\";\n\t\t\t}\n\t\t\tStringWriter out = new StringWriter();\n\t\t\ttry (PrintWriter writer = new PrintWriter(out)) {\n\t\t\t\twriteAll(writer, this.analyses.entrySet(), (entry) -> {\n\t\t\t\t\twriter.println(this.baseDirectory.toPath().relativize(entry.getKey().toPath()));\n\t\t\t\t\tboolean hasProblems = entry.getValue().stream().anyMatch(Analysis::hasProblems);\n\t\t\t\t\tif (hasProblems) {\n\t\t\t\t\t\twriteAll(writer, entry.getValue(), (analysis) -> analysis.createDetails(writer));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\twriter.println(\"No problems found.\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn out.toString();\n\t\t}\n\n\t}\n\n\tstatic class Analysis {\n\n\t\tprivate final String header;\n\n\t\tprivate final List<String> items;\n\n\t\tAnalysis(String header) {\n\t\t\tthis.header = header;\n\t\t\tthis.items = new ArrayList<>();\n\t\t}\n\n\t\tvoid addItem(String item) {\n\t\t\tthis.items.add(item);\n\t\t}\n\n\t\tboolean hasProblems() {\n\t\t\treturn !this.items.isEmpty();\n\t\t}\n\n\t\tList<String> getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t\tvoid createDetails(PrintWriter writer) {\n\t\t\twriter.println(this.header);\n\t\t\tif (this.items.isEmpty()) {\n\t\t\t\twriter.println(\"No problems found.\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (String item : this.items) {\n\t\t\t\t\twriter.println(\"\\t- \" + item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tStringWriter out = new StringWriter();\n\t\t\tPrintWriter writer = new PrintWriter(out);\n\t\t\tcreateDetails(writer);\n\t\t\treturn out.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.file.RegularFile;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.compile.JavaCompile;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Plugin} for projects that define {@code @ConfigurationProperties}. When applied,\n * the plugin reacts to the presence of the {@link JavaPlugin} by:\n *\n * <ul>\n * <li>Adding a dependency on the configuration properties annotation processor.\n * <li>Disables incremental compilation to avoid property descriptions being lost.\n * <li>Configuring the additional metadata locations annotation processor compiler\n * argument.\n * <li>Adding the outputs of the processResources task as inputs of the compileJava task\n * to ensure that the additional metadata is available when the annotation processor runs.\n * <li>Registering a {@link CheckAdditionalSpringConfigurationMetadata} task and\n * configuring the {@code check} task to depend upon it.\n * <li>Defining an artifact for the resulting configuration property metadata so that it\n * can be consumed by downstream projects.\n * </ul>\n *\n * @author Andy Wilkinson\n */\npublic class ConfigurationPropertiesPlugin implements Plugin<Project> {\n\n\tprivate static final String CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME = \"configurationPropertiesMetadata\";\n\n\t/**\n\t * Name of the {@link CheckAdditionalSpringConfigurationMetadata} task.\n\t */\n\tpublic static final String CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME = \"checkAdditionalSpringConfigurationMetadata\";\n\n\t/**\n\t * Name of the {@link CheckSpringConfigurationMetadata} task.\n\t */\n\tpublic static final String CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME = \"checkSpringConfigurationMetadata\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {\n\t\t\tconfigureConfigurationPropertiesAnnotationProcessor(project);\n\t\t\tdisableIncrementalCompilation(project);\n\t\t\tconfigureAdditionalMetadataLocationsCompilerArgument(project);\n\t\t\tregisterCheckAdditionalMetadataTask(project);\n\t\t\tregisterCheckMetadataTask(project);\n\t\t\taddMetadataArtifact(project);\n\t\t});\n\t}\n\n\tprivate void configureConfigurationPropertiesAnnotationProcessor(Project project) {\n\t\tConfiguration annotationProcessors = project.getConfigurations()\n\t\t\t.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME);\n\t\tannotationProcessors.getDependencies()\n\t\t\t.add(project.getDependencies()\n\t\t\t\t.project(Map.of(\"path\", \":configuration-metadata:spring-boot-configuration-processor\")));\n\t}\n\n\tprivate void disableIncrementalCompilation(Project project) {\n\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t.getSourceSets()\n\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tproject.getTasks()\n\t\t\t.named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class)\n\t\t\t.configure((compileJava) -> compileJava.getOptions().setIncremental(false));\n\t}\n\n\tprivate void addMetadataArtifact(Project project) {\n\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t.getSourceSets()\n\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tproject.getConfigurations()\n\t\t\t.consumable(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME, (configuration) -> {\n\t\t\t\tconfiguration.attributes((attributes) -> {\n\t\t\t\t\tattributes.attribute(Category.CATEGORY_ATTRIBUTE,\n\t\t\t\t\t\t\tproject.getObjects().named(Category.class, Category.DOCUMENTATION));\n\t\t\t\t\tattributes.attribute(Usage.USAGE_ATTRIBUTE,\n\t\t\t\t\t\t\tproject.getObjects().named(Usage.class, \"configuration-properties-metadata\"));\n\t\t\t\t});\n\t\t\t});\n\t\tproject.afterEvaluate((evaluatedProject) -> evaluatedProject.getArtifacts()\n\t\t\t.add(CONFIGURATION_PROPERTIES_METADATA_CONFIGURATION_NAME,\n\t\t\t\t\tmainSourceSet.getJava()\n\t\t\t\t\t\t.getDestinationDirectory()\n\t\t\t\t\t\t.dir(\"META-INF/spring-configuration-metadata.json\"),\n\t\t\t\t\t(artifact) -> artifact\n\t\t\t\t\t\t.builtBy(evaluatedProject.getTasks().getByName(mainSourceSet.getClassesTaskName()))));\n\t}\n\n\tprivate void configureAdditionalMetadataLocationsCompilerArgument(Project project) {\n\t\tJavaCompile compileJava = project.getTasks()\n\t\t\t.withType(JavaCompile.class)\n\t\t\t.getByName(JavaPlugin.COMPILE_JAVA_TASK_NAME);\n\t\tcompileJava.getInputs()\n\t\t\t.files(project.getTasks().getByName(JavaPlugin.PROCESS_RESOURCES_TASK_NAME))\n\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t.withPropertyName(\"processed resources\");\n\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t.getSourceSets()\n\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tcompileJava.getOptions()\n\t\t\t.getCompilerArgs()\n\t\t\t.add(\"-Aorg.springframework.boot.configurationprocessor.additionalMetadataLocations=\"\n\t\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(mainSourceSet.getResources()\n\t\t\t\t\t\t.getSourceDirectories()\n\t\t\t\t\t\t.getFiles()\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.map(project.getRootProject()::relativePath)\n\t\t\t\t\t\t.collect(Collectors.toSet())));\n\t}\n\n\tprivate void registerCheckAdditionalMetadataTask(Project project) {\n\t\tTaskProvider<CheckAdditionalSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()\n\t\t\t.register(CHECK_ADDITIONAL_SPRING_CONFIGURATION_METADATA_TASK_NAME,\n\t\t\t\t\tCheckAdditionalSpringConfigurationMetadata.class);\n\t\tcheckConfigurationMetadata.configure((check) -> {\n\t\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t.getSourceSets()\n\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\tcheck.setSource(mainSourceSet.getResources());\n\t\t\tcheck.include(\"META-INF/additional-spring-configuration-metadata.json\");\n\t\t\tcheck.getReportLocation()\n\t\t\t\t.set(project.getLayout()\n\t\t\t\t\t.getBuildDirectory()\n\t\t\t\t\t.file(\"reports/additional-spring-configuration-metadata/check.txt\"));\n\t\t});\n\t\tproject.getTasks()\n\t\t\t.named(LifecycleBasePlugin.CHECK_TASK_NAME)\n\t\t\t.configure((check) -> check.dependsOn(checkConfigurationMetadata));\n\t}\n\n\tprivate void registerCheckMetadataTask(Project project) {\n\t\tTaskProvider<CheckSpringConfigurationMetadata> checkConfigurationMetadata = project.getTasks()\n\t\t\t.register(CHECK_SPRING_CONFIGURATION_METADATA_TASK_NAME, CheckSpringConfigurationMetadata.class);\n\t\tcheckConfigurationMetadata.configure((check) -> {\n\t\t\tSourceSet mainSourceSet = project.getExtensions()\n\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t.getSourceSets()\n\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\tProvider<RegularFile> metadataLocation = project.getTasks()\n\t\t\t\t.named(mainSourceSet.getCompileJavaTaskName(), JavaCompile.class)\n\t\t\t\t.flatMap((javaCompile) -> javaCompile.getDestinationDirectory()\n\t\t\t\t\t.file(\"META-INF/spring-configuration-metadata.json\"));\n\t\t\tcheck.getMetadataLocation().set(metadataLocation);\n\t\t\tcheck.getReportLocation()\n\t\t\t\t.set(project.getLayout().getBuildDirectory().file(\"reports/spring-configuration-metadata/check.txt\"));\n\t\t});\n\t\tproject.getTasks()\n\t\t\t.named(LifecycleBasePlugin.CHECK_TASK_NAME)\n\t\t\t.configure((check) -> check.dependsOn(checkConfigurationMetadata));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/ConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.util.Map;\n\n/**\n * A configuration property.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConfigurationProperty {\n\n\tprivate final String name;\n\n\tprivate final String type;\n\n\tprivate final Object defaultValue;\n\n\tprivate final String description;\n\n\tprivate final boolean deprecated;\n\n\tprivate final Deprecation deprecation;\n\n\tConfigurationProperty(String name, String type) {\n\t\tthis(name, type, null, null, false, null);\n\t}\n\n\tConfigurationProperty(String name, String type, Object defaultValue, String description, boolean deprecated,\n\t\t\tDeprecation deprecation) {\n\t\tthis.name = name;\n\t\tthis.type = type;\n\t\tthis.defaultValue = defaultValue;\n\t\tthis.description = description;\n\t\tthis.deprecated = deprecated;\n\t\tthis.deprecation = deprecation;\n\t}\n\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\tString getDisplayName() {\n\t\treturn (getType() != null && getType().startsWith(\"java.util.Map\")) ? getName() + \".*\" : getName();\n\t}\n\n\tString getType() {\n\t\treturn this.type;\n\t}\n\n\tObject getDefaultValue() {\n\t\treturn this.defaultValue;\n\t}\n\n\tString getDescription() {\n\t\treturn this.description;\n\t}\n\n\tboolean isDeprecated() {\n\t\treturn this.deprecated;\n\t}\n\n\tDeprecation getDeprecation() {\n\t\treturn this.deprecation;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"ConfigurationProperty [name=\" + this.name + \", type=\" + this.type + \"]\";\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tstatic ConfigurationProperty fromJsonProperties(Map<String, Object> property) {\n\t\tString name = (String) property.get(\"name\");\n\t\tString type = (String) property.get(\"type\");\n\t\tObject defaultValue = property.get(\"defaultValue\");\n\t\tString description = (String) property.get(\"description\");\n\t\tboolean deprecated = property.containsKey(\"deprecated\");\n\t\tMap<String, Object> deprecation = (Map<String, Object>) property.get(\"deprecation\");\n\t\treturn new ConfigurationProperty(name, type, defaultValue, description, deprecated,\n\t\t\t\tDeprecation.fromJsonProperties(deprecation));\n\t}\n\n\trecord Deprecation(String reason, String replacement, String since, String level) {\n\n\t\tstatic Deprecation fromJsonProperties(Map<String, Object> property) {\n\t\t\tif (property == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tString reason = (String) property.get(\"reason\");\n\t\t\tString replacement = (String) property.get(\"replacement\");\n\t\t\tString since = (String) property.get(\"since\");\n\t\t\tString level = (String) property.get(\"level\");\n\t\t\treturn new Deprecation(reason, replacement, since, level);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/DocumentConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.IOException;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.boot.build.context.properties.Snippet.Config;\n\n/**\n * {@link Task} used to document auto-configuration classes.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\npublic abstract class DocumentConfigurationProperties extends DefaultTask {\n\n\tprivate FileCollection configurationPropertyMetadata;\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getConfigurationPropertyMetadata() {\n\t\treturn this.configurationPropertyMetadata;\n\t}\n\n\tpublic void setConfigurationPropertyMetadata(FileCollection configurationPropertyMetadata) {\n\t\tthis.configurationPropertyMetadata = configurationPropertyMetadata;\n\t}\n\n\t@Input\n\tpublic abstract Property<Boolean> getDeprecated();\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDir();\n\n\t@TaskAction\n\tvoid documentConfigurationProperties() throws IOException {\n\t\tSnippets snippets = new Snippets(this.configurationPropertyMetadata, getDeprecated().getOrElse(false));\n\t\tsnippets.add(\"application-properties.core\", \"Core Properties\", this::corePrefixes);\n\t\tsnippets.add(\"application-properties.cache\", \"Cache Properties\", this::cachePrefixes);\n\t\tsnippets.add(\"application-properties.grpc\", \"gRPC Properties\", this::grpcPrefixes);\n\t\tsnippets.add(\"application-properties.mail\", \"Mail Properties\", this::mailPrefixes);\n\t\tsnippets.add(\"application-properties.json\", \"JSON Properties\", this::jsonPrefixes);\n\t\tsnippets.add(\"application-properties.data\", \"Data Properties\", this::dataPrefixes);\n\t\tsnippets.add(\"application-properties.transaction\", \"Transaction Properties\", this::transactionPrefixes);\n\t\tsnippets.add(\"application-properties.data-migration\", \"Data Migration Properties\", this::dataMigrationPrefixes);\n\t\tsnippets.add(\"application-properties.integration\", \"Integration Properties\", this::integrationPrefixes);\n\t\tsnippets.add(\"application-properties.web\", \"Web Properties\", this::webPrefixes);\n\t\tsnippets.add(\"application-properties.templating\", \"Templating Properties\", this::templatePrefixes);\n\t\tsnippets.add(\"application-properties.server\", \"Server Properties\", this::serverPrefixes);\n\t\tsnippets.add(\"application-properties.security\", \"Security Properties\", this::securityPrefixes);\n\t\tsnippets.add(\"application-properties.rsocket\", \"RSocket Properties\", this::rsocketPrefixes);\n\t\tsnippets.add(\"application-properties.actuator\", \"Actuator Properties\", this::actuatorPrefixes);\n\t\tsnippets.add(\"application-properties.devtools\", \"Devtools Properties\", this::devtoolsPrefixes);\n\t\tsnippets.add(\"application-properties.docker-compose\", \"Docker Compose Properties\", this::dockerComposePrefixes);\n\t\tsnippets.add(\"application-properties.testcontainers\", \"Testcontainers Properties\",\n\t\t\t\tthis::testcontainersPrefixes);\n\t\tsnippets.add(\"application-properties.testing\", \"Testing Properties\", this::testingPrefixes);\n\t\tsnippets.writeTo(getOutputDir().getAsFile().get().toPath());\n\t}\n\n\tprivate void corePrefixes(Config config) {\n\t\tconfig.accept(\"debug\");\n\t\tconfig.accept(\"trace\");\n\t\tconfig.accept(\"logging\");\n\t\tconfig.accept(\"spring.aop\");\n\t\tconfig.accept(\"spring.application\");\n\t\tconfig.accept(\"spring.autoconfigure\");\n\t\tconfig.accept(\"spring.banner\");\n\t\tconfig.accept(\"spring.beaninfo\");\n\t\tconfig.accept(\"spring.config\");\n\t\tconfig.accept(\"spring.info\");\n\t\tconfig.accept(\"spring.jmx\");\n\t\tconfig.accept(\"spring.lifecycle\");\n\t\tconfig.accept(\"spring.main\");\n\t\tconfig.accept(\"spring.messages\");\n\t\tconfig.accept(\"spring.pid\");\n\t\tconfig.accept(\"spring.profiles\");\n\t\tconfig.accept(\"spring.quartz\");\n\t\tconfig.accept(\"spring.reactor\");\n\t\tconfig.accept(\"spring.ssl\");\n\t\tconfig.accept(\"spring.task\");\n\t\tconfig.accept(\"spring.threads\");\n\t\tconfig.accept(\"spring.validation\");\n\t\tconfig.accept(\"spring.mandatory-file-encoding\");\n\t\tconfig.accept(\"info\");\n\t\tconfig.accept(\"spring.output.ansi.enabled\");\n\t}\n\n\tprivate void cachePrefixes(Config config) {\n\t\tconfig.accept(\"spring.cache\");\n\t}\n\n\tprivate void grpcPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.grpc\");\n\t}\n\n\tprivate void mailPrefixes(Config config) {\n\t\tconfig.accept(\"spring.mail\");\n\t\tconfig.accept(\"spring.sendgrid\");\n\t}\n\n\tprivate void jsonPrefixes(Config config) {\n\t\tconfig.accept(\"spring.jackson\");\n\t\tconfig.accept(\"spring.gson\");\n\t\tconfig.accept(\"spring.kotlinx.serialization.json\");\n\t}\n\n\tprivate void dataPrefixes(Config config) {\n\t\tconfig.accept(\"spring.couchbase\");\n\t\tconfig.accept(\"spring.cassandra\");\n\t\tconfig.accept(\"spring.elasticsearch\");\n\t\tconfig.accept(\"spring.h2\");\n\t\tconfig.accept(\"spring.influx\");\n\t\tconfig.accept(\"spring.ldap\");\n\t\tconfig.accept(\"spring.mongodb\");\n\t\tconfig.accept(\"spring.neo4j\");\n\t\tconfig.accept(\"spring.persistence\");\n\t\tconfig.accept(\"spring.data\");\n\t\tconfig.accept(\"spring.datasource\");\n\t\tconfig.accept(\"spring.jooq\");\n\t\tconfig.accept(\"spring.jdbc\");\n\t\tconfig.accept(\"spring.jpa\");\n\t\tconfig.accept(\"spring.r2dbc\");\n\t\tconfig.accept(\"spring.datasource.oracleucp\",\n\t\t\t\t\"Oracle UCP specific settings bound to an instance of Oracle UCP's PoolDataSource\");\n\t\tconfig.accept(\"spring.datasource.dbcp2\",\n\t\t\t\t\"Commons DBCP2 specific settings bound to an instance of DBCP2's BasicDataSource\");\n\t\tconfig.accept(\"spring.datasource.tomcat\",\n\t\t\t\t\"Tomcat datasource specific settings bound to an instance of Tomcat JDBC's DataSource\");\n\t\tconfig.accept(\"spring.datasource.hikari\",\n\t\t\t\t\"Hikari specific settings bound to an instance of Hikari's HikariDataSource\");\n\n\t}\n\n\tprivate void transactionPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.jta\");\n\t\tprefix.accept(\"spring.transaction\");\n\t}\n\n\tprivate void dataMigrationPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.flyway\");\n\t\tprefix.accept(\"spring.liquibase\");\n\t\tprefix.accept(\"spring.sql.init\");\n\t}\n\n\tprivate void integrationPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.activemq\");\n\t\tprefix.accept(\"spring.artemis\");\n\t\tprefix.accept(\"spring.batch\");\n\t\tprefix.accept(\"spring.integration\");\n\t\tprefix.accept(\"spring.jms\");\n\t\tprefix.accept(\"spring.kafka\");\n\t\tprefix.accept(\"spring.pulsar\");\n\t\tprefix.accept(\"spring.rabbitmq\");\n\t\tprefix.accept(\"spring.hazelcast\");\n\t\tprefix.accept(\"spring.webservices\");\n\t}\n\n\tprivate void webPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.graphql\");\n\t\tprefix.accept(\"spring.hateoas\");\n\t\tprefix.accept(\"spring.http\");\n\t\tprefix.accept(\"spring.jersey\");\n\t\tprefix.accept(\"spring.mvc\");\n\t\tprefix.accept(\"spring.netty\");\n\t\tprefix.accept(\"spring.resources\");\n\t\tprefix.accept(\"spring.servlet\");\n\t\tprefix.accept(\"spring.session\");\n\t\tprefix.accept(\"spring.web\");\n\t\tprefix.accept(\"spring.webflux\");\n\t}\n\n\tprivate void templatePrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.freemarker\");\n\t\tprefix.accept(\"spring.groovy\");\n\t\tprefix.accept(\"spring.mustache\");\n\t\tprefix.accept(\"spring.thymeleaf\");\n\t}\n\n\tprivate void serverPrefixes(Config prefix) {\n\t\tprefix.accept(\"server\");\n\t}\n\n\tprivate void securityPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.security\");\n\t}\n\n\tprivate void rsocketPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.rsocket\");\n\t}\n\n\tprivate void actuatorPrefixes(Config prefix) {\n\t\tprefix.accept(\"management\");\n\t\tprefix.accept(\"micrometer\");\n\t}\n\n\tprivate void dockerComposePrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.docker.compose\");\n\t}\n\n\tprivate void devtoolsPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.devtools\");\n\t}\n\n\tprivate void testingPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.test.\");\n\t}\n\n\tprivate void testcontainersPrefixes(Config prefix) {\n\t\tprefix.accept(\"spring.testcontainers.\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/Row.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\n/**\n * Abstract class for rows in {@link Table}.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nabstract class Row implements Comparable<Row> {\n\n\tprivate final Snippet snippet;\n\n\tprivate final String id;\n\n\tprotected Row(Snippet snippet, String id) {\n\t\tthis.snippet = snippet;\n\t\tthis.id = id;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tRow other = (Row) obj;\n\t\treturn this.id.equals(other.id);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.id.hashCode();\n\t}\n\n\t@Override\n\tpublic int compareTo(Row other) {\n\t\treturn this.id.compareTo(other.id);\n\t}\n\n\tString getAnchor() {\n\t\treturn this.snippet.getAnchor() + \".\" + this.id;\n\t}\n\n\tabstract void write(Asciidoc asciidoc);\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/SingleRow.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.util.Arrays;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.build.context.properties.ConfigurationProperty.Deprecation;\n\n/**\n * Table row containing a single configuration property.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass SingleRow extends Row {\n\n\tprivate final Snippets snippets;\n\n\tprivate final String defaultValue;\n\n\tprivate final ConfigurationProperty property;\n\n\tSingleRow(Snippet snippet, ConfigurationProperty property) {\n\t\tthis(null, snippet, property);\n\t}\n\n\tSingleRow(Snippets snippets, Snippet snippet, ConfigurationProperty property) {\n\t\tsuper(snippet, property.getName());\n\t\tthis.snippets = snippets;\n\t\tthis.defaultValue = getDefaultValue(property.getDefaultValue());\n\t\tthis.property = property;\n\t}\n\n\tprivate String getDefaultValue(Object defaultValue) {\n\t\tif (defaultValue == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (defaultValue.getClass().isArray()) {\n\t\t\treturn Arrays.stream((Object[]) defaultValue)\n\t\t\t\t.map(Object::toString)\n\t\t\t\t.collect(Collectors.joining(\",\" + System.lineSeparator()));\n\t\t}\n\t\treturn defaultValue.toString();\n\t}\n\n\t@Override\n\tvoid write(Asciidoc asciidoc) {\n\t\tasciidoc.append(\"|\");\n\t\tasciidoc.append(\"[[\" + getAnchor() + \"]]\");\n\t\tasciidoc.appendln(\"xref:#\" + getAnchor() + \"[`+\", this.property.getDisplayName(), \"+`]\");\n\t\twriteDescription(asciidoc);\n\t\twriteDefaultValue(asciidoc);\n\t}\n\n\tprivate void writeDescription(Asciidoc builder) {\n\t\tbuilder.append(\"|\");\n\t\tif (this.property.isDeprecated()) {\n\t\t\tDeprecation deprecation = this.property.getDeprecation();\n\t\t\tString replacement = (deprecation != null) ? deprecation.replacement() : null;\n\t\t\tString reason = (deprecation != null) ? deprecation.reason() : null;\n\t\t\tif (replacement != null && !replacement.isEmpty()) {\n\t\t\t\tString xref = (this.snippets != null) ? this.snippets.findXref(deprecation.replacement()) : null;\n\t\t\t\tif (xref != null) {\n\t\t\t\t\tbuilder.append(\"Replaced by xref:\" + xref + \"[`+\" + deprecation.replacement() + \"+`]\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuilder.append(\"Replaced by `+\" + deprecation.replacement() + \"+`\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (reason != null && !reason.isEmpty()) {\n\t\t\t\tbuilder.append(\"+++\", clean(reason), \"+++\");\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tString description = this.property.getDescription();\n\t\t\tif (description != null && !description.isEmpty()) {\n\t\t\t\tbuilder.append(\"+++\", clean(description), \"+++\");\n\t\t\t}\n\t\t}\n\t\tbuilder.appendln();\n\t}\n\n\tprivate String clean(String text) {\n\t\treturn text.replace(\"|\", \"\\\\|\").replace(\"<\", \"&lt;\").replace(\">\", \"&gt;\");\n\t}\n\n\tprivate void writeDefaultValue(Asciidoc builder) {\n\t\tString defaultValue = (this.defaultValue != null) ? this.defaultValue : \"\";\n\t\tif (defaultValue.isEmpty()) {\n\t\t\tbuilder.appendln(\"|\");\n\t\t}\n\t\telse {\n\t\t\tdefaultValue = defaultValue.replace(\"\\\\\", \"\\\\\\\\\").replace(\"|\", \"\\\\|\");\n\t\t\tbuilder.appendln(\"|`+\", defaultValue, \"+`\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\n/**\n * A configuration properties snippet.\n *\n * @author Brian Clozed\n * @author Phillip Webb\n */\nclass Snippet {\n\n\tprivate final String anchor;\n\n\tprivate final String title;\n\n\tprivate final Set<String> prefixes;\n\n\tprivate final Map<String, String> overrides;\n\n\tSnippet(String anchor, String title, Consumer<Config> config) {\n\t\tSet<String> prefixes = new LinkedHashSet<>();\n\t\tMap<String, String> overrides = new LinkedHashMap<>();\n\t\tif (config != null) {\n\t\t\tconfig.accept(new Config() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void accept(String prefix) {\n\t\t\t\t\tprefixes.add(prefix);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void accept(String prefix, String description) {\n\t\t\t\t\toverrides.put(prefix, description);\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\t\tthis.anchor = anchor;\n\t\tthis.title = title;\n\t\tthis.prefixes = prefixes;\n\t\tthis.overrides = overrides;\n\t}\n\n\tString getAnchor() {\n\t\treturn this.anchor;\n\t}\n\n\tString getTitle() {\n\t\treturn this.title;\n\t}\n\n\tSet<String> getPrefixes() {\n\t\treturn this.prefixes;\n\t}\n\n\tMap<String, String> getOverrides() {\n\t\treturn this.overrides;\n\t}\n\n\tvoid forEachPrefix(Consumer<String> action) {\n\t\tthis.prefixes.forEach(action);\n\t}\n\n\tvoid forEachOverride(BiConsumer<String, String> action) {\n\t\tthis.overrides.forEach(action);\n\t}\n\n\t/**\n\t * Callback to configure the snippet.\n\t */\n\tinterface Config {\n\n\t\t/**\n\t\t * Accept the given prefix using the meta-data description.\n\t\t * @param prefix the prefix to accept\n\t\t */\n\t\tvoid accept(String prefix);\n\n\t\t/**\n\t\t * Accept the given prefix with a defined description.\n\t\t * @param prefix the prefix to accept\n\t\t * @param description the description to use\n\t\t */\n\t\tvoid accept(String prefix, String description);\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/Snippets.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.file.FileCollection;\n\nimport org.springframework.boot.build.context.properties.ConfigurationProperty.Deprecation;\n\n/**\n * Configuration properties snippets.\n *\n * @author Brian Clozed\n * @author Phillip Webb\n */\nclass Snippets {\n\n\tprivate final ConfigurationProperties properties;\n\n\tprivate final List<Snippet> snippets = new ArrayList<>();\n\n\tprivate final boolean deprecated;\n\n\tSnippets(FileCollection configurationPropertyMetadata, boolean deprecated) {\n\t\tthis.properties = ConfigurationProperties.fromFiles(configurationPropertyMetadata);\n\t\tthis.deprecated = deprecated;\n\t}\n\n\tvoid add(String anchor, String title, Consumer<Snippet.Config> config) {\n\t\tthis.snippets.add(new Snippet(anchor, title, config));\n\t}\n\n\tvoid writeTo(Path outputDirectory) throws IOException {\n\t\tcreateDirectory(outputDirectory);\n\t\tSet<String> remaining = this.properties.stream()\n\t\t\t.filter(this::shouldAdd)\n\t\t\t.map(ConfigurationProperty::getName)\n\t\t\t.collect(Collectors.toSet());\n\t\tfor (Snippet snippet : this.snippets) {\n\t\t\tSet<String> written = writeSnippet(outputDirectory, snippet, remaining);\n\t\t\tremaining.removeAll(written);\n\t\t}\n\t\tif (!this.deprecated && !remaining.isEmpty()) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"The following keys were not written to the documentation: \" + String.join(\", \", remaining));\n\t\t}\n\t}\n\n\tprivate Set<String> writeSnippet(Path outputDirectory, Snippet snippet, Set<String> remaining) throws IOException {\n\t\tTable table = new Table();\n\t\tSet<String> added = new HashSet<>();\n\t\tsnippet.forEachOverride((prefix, description) -> {\n\t\t\tCompoundRow row = new CompoundRow(snippet, prefix, (!this.deprecated) ? description : \"\");\n\t\t\tremaining.stream().filter((candidate) -> candidate.startsWith(prefix)).forEach((name) -> {\n\t\t\t\tConfigurationProperty property = this.properties.get(name);\n\t\t\t\tif (shouldAdd(property) && added.add(name)) {\n\t\t\t\t\trow.addProperty(property);\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (!row.isEmpty()) {\n\t\t\t\ttable.addRow(row);\n\t\t\t}\n\t\t});\n\t\tsnippet.forEachPrefix((prefix) -> {\n\t\t\tremaining.stream().filter((candidate) -> candidate.startsWith(prefix)).forEach((name) -> {\n\t\t\t\tConfigurationProperty property = this.properties.get(name);\n\t\t\t\tif (shouldAdd(property) && added.add(name)) {\n\t\t\t\t\ttable.addRow(new SingleRow(this, snippet, property));\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tAsciidoc asciidoc = getAsciidoc(snippet, table);\n\t\twriteAsciidoc(outputDirectory, snippet, asciidoc);\n\t\treturn added;\n\t}\n\n\tString findXref(String name) {\n\t\tConfigurationProperty property = this.properties.get(name);\n\t\tif (property == null || property.isDeprecated()) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (Snippet snippet : this.snippets) {\n\t\t\tfor (String prefix : snippet.getOverrides().keySet()) {\n\t\t\t\tif (name.startsWith(prefix)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (String prefix : snippet.getPrefixes()) {\n\t\t\t\tif (name.startsWith(prefix)) {\n\t\t\t\t\treturn \"appendix:application-properties/index.adoc#%s.%s\".formatted(snippet.getAnchor(), name);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean shouldAdd(ConfigurationProperty property) {\n\t\treturn (property == null || (property.isDeprecated() == this.deprecated && !deprecatedAtErrorLevel(property)));\n\t}\n\n\tprivate boolean deprecatedAtErrorLevel(ConfigurationProperty property) {\n\t\tDeprecation deprecation = property.getDeprecation();\n\t\treturn deprecation != null && \"error\".equals(deprecation.level());\n\t}\n\n\tprivate Asciidoc getAsciidoc(Snippet snippet, Table table) {\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\tif (!table.isEmpty()) {\n\t\t\t// We have to prepend 'appendix.' as a section id here, otherwise the\n\t\t\t// spring-asciidoctor-extensions:section-id asciidoctor extension complains\n\t\t\tasciidoc.appendln(\"[[appendix.\" + ((this.deprecated) ? \"deprecated-\" : \"\") + snippet.getAnchor() + \"]]\");\n\t\t\tasciidoc.appendln(\"== \", ((this.deprecated) ? \"Deprecated \" : \"\") + snippet.getTitle());\n\t\t\ttable.write(asciidoc);\n\t\t}\n\t\treturn asciidoc;\n\t}\n\n\tprivate void writeAsciidoc(Path outputDirectory, Snippet snippet, Asciidoc asciidoc) throws IOException {\n\t\tString[] parts = (snippet.getAnchor()).split(\"\\\\.\");\n\t\tPath path = outputDirectory.resolve(parts[parts.length - 1] + \".adoc\");\n\t\tcreateDirectory(path.getParent());\n\t\tFiles.deleteIfExists(path);\n\t\ttry (OutputStream outputStream = Files.newOutputStream(path)) {\n\t\t\toutputStream.write(asciidoc.toString().getBytes(StandardCharsets.UTF_8));\n\t\t}\n\t}\n\n\tprivate void createDirectory(Path path) throws IOException {\n\t\tassertValidOutputDirectory(path);\n\t\tif (!Files.exists(path)) {\n\t\t\tFiles.createDirectory(path);\n\t\t}\n\t}\n\n\tprivate void assertValidOutputDirectory(Path path) {\n\t\tif (path == null) {\n\t\t\tthrow new IllegalArgumentException(\"Directory path should not be null\");\n\t\t}\n\t\tif (Files.exists(path) && !Files.isDirectory(path)) {\n\t\t\tthrow new IllegalArgumentException(\"Path already exists and is not a directory\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/context/properties/Table.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.util.Set;\nimport java.util.TreeSet;\n\n/**\n * Asciidoctor table listing configuration properties sharing to a common theme.\n *\n * @author Brian Clozel\n */\nclass Table {\n\n\tprivate final Set<Row> rows = new TreeSet<>();\n\n\tvoid addRow(Row row) {\n\t\tthis.rows.add(row);\n\t}\n\n\tvoid write(Asciidoc asciidoc) {\n\t\tasciidoc.appendln(\"[cols=\\\"4,3,3\\\", options=\\\"header\\\"]\");\n\t\tasciidoc.appendln(\"|===\");\n\t\tasciidoc.appendln(\"|Name|Description|Default Value\");\n\t\tasciidoc.appendln();\n\t\tthis.rows.forEach((entry) -> {\n\t\t\tentry.write(asciidoc);\n\t\t\tasciidoc.appendln();\n\t\t});\n\t\tasciidoc.appendln(\"|===\");\n\t}\n\n\tboolean isEmpty() {\n\t\treturn this.rows.isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/devtools/DocumentDevtoolsPropertyDefaults.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.devtools;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.TreeMap;\nimport java.util.jar.JarFile;\nimport java.util.zip.ZipEntry;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * Task for documenting Devtools' property defaults.\n *\n * @author Andy Wilkinson\n */\npublic abstract class DocumentDevtoolsPropertyDefaults extends DefaultTask {\n\n\tprivate FileCollection defaults;\n\n\tpublic DocumentDevtoolsPropertyDefaults() {\n\t\tgetOutputFile().convention(getProject().getLayout()\n\t\t\t.getBuildDirectory()\n\t\t\t.file(\"generated/docs/using/devtools-property-defaults.adoc\"));\n\t}\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getDefaults() {\n\t\treturn this.defaults;\n\t}\n\n\tpublic void setDefaults(FileCollection defaults) {\n\t\tthis.defaults = defaults;\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@TaskAction\n\tvoid documentPropertyDefaults() throws IOException {\n\t\tMap<String, String> propertyDefaults = loadPropertyDefaults();\n\t\tdocumentPropertyDefaults(propertyDefaults);\n\t}\n\n\tprivate Map<String, String> loadPropertyDefaults() throws IOException, FileNotFoundException {\n\t\tProperties properties = new Properties();\n\t\tMap<String, String> propertyDefaults = new TreeMap<>();\n\t\tfor (File contribution : this.defaults.getFiles()) {\n\t\t\tif (contribution.isFile()) {\n\t\t\t\ttry (JarFile jar = new JarFile(contribution)) {\n\t\t\t\t\tZipEntry entry = jar.getEntry(\"META-INF/spring-devtools.properties\");\n\t\t\t\t\tif (entry != null) {\n\t\t\t\t\t\tproperties.load(jar.getInputStream(entry));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (contribution.exists()) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Unexpected Devtools default properties contribution from '\" + contribution + \"'\");\n\t\t\t}\n\t\t}\n\t\tfor (String name : properties.stringPropertyNames()) {\n\t\t\tif (name.startsWith(\"defaults.\")) {\n\t\t\t\tpropertyDefaults.put(name.substring(\"defaults.\".length()), properties.getProperty(name));\n\t\t\t}\n\t\t}\n\t\treturn propertyDefaults;\n\t}\n\n\tprivate void documentPropertyDefaults(Map<String, String> properties) throws IOException {\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(getOutputFile().getAsFile().get()))) {\n\t\t\twriter.println(\"[cols=\\\"3,1\\\"]\");\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"| Name | Default Value\");\n\t\t\tproperties.forEach((name, value) -> {\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"| `%s`%n\", name);\n\t\t\t\twriter.printf(\"| `%s`%n\", value);\n\t\t\t});\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/docs/ApplicationRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.docs;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.internal.jvm.Jvm;\n\n/**\n * {@link Task} to run an application for the purpose of capturing its output for\n * inclusion in the reference documentation.\n *\n * @author Andy Wilkinson\n */\npublic abstract class ApplicationRunner extends DefaultTask {\n\n\tprivate FileCollection classpath;\n\n\tpublic ApplicationRunner() {\n\t\tgetApplicationJar().convention(\"/opt/apps/myapp.jar\");\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutput();\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(FileCollection classpath) {\n\t\tthis.classpath = classpath;\n\t}\n\n\t@Input\n\tpublic abstract ListProperty<String> getArgs();\n\n\t@Input\n\tpublic abstract Property<String> getMainClass();\n\n\t@Input\n\tpublic abstract Property<String> getExpectedLogging();\n\n\t@Input\n\tabstract MapProperty<String, String> getNormalizations();\n\n\t@Input\n\tabstract Property<String> getApplicationJar();\n\n\tpublic void normalizeTomcatPort() {\n\t\tgetNormalizations().put(\"(Tomcat started on port )[\\\\d]+( \\\\(http\\\\))\", \"$18080$2\");\n\t\tgetNormalizations().put(\"(Tomcat initialized with port )[\\\\d]+( \\\\(http\\\\))\", \"$18080$2\");\n\t}\n\n\tpublic void normalizeLiveReloadPort() {\n\t\tgetNormalizations().put(\"(LiveReload server is running on port )[\\\\d]+\", \"$135729\");\n\t}\n\n\t@TaskAction\n\tvoid runApplication() throws IOException {\n\t\tList<String> command = new ArrayList<>();\n\t\tFile executable = Jvm.current().getExecutable(\"java\");\n\t\tcommand.add(executable.getAbsolutePath());\n\t\tcommand.add(\"-cp\");\n\t\tcommand.add(this.classpath.getFiles()\n\t\t\t.stream()\n\t\t\t.map(File::getAbsolutePath)\n\t\t\t.collect(Collectors.joining(File.pathSeparator)));\n\t\tcommand.add(getMainClass().get());\n\t\tcommand.addAll(getArgs().get());\n\t\tFile outputFile = getOutput().getAsFile().get();\n\t\tProcess process = new ProcessBuilder().redirectOutput(outputFile)\n\t\t\t.redirectError(outputFile)\n\t\t\t.command(command)\n\t\t\t.start();\n\t\tawaitLogging(process);\n\t\tprocess.destroy();\n\t\tnormalizeLogging();\n\t}\n\n\tprivate void awaitLogging(Process process) {\n\t\tlong end = System.currentTimeMillis() + 60000;\n\t\tString expectedLogging = getExpectedLogging().get();\n\t\twhile (System.currentTimeMillis() < end) {\n\t\t\tfor (String line : outputLines()) {\n\t\t\t\tif (line.contains(expectedLogging)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!process.isAlive()) {\n\t\t\t\tthrow new IllegalStateException(\"Process exited before '\" + expectedLogging + \"' was logged\");\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"'\" + expectedLogging + \"' was not logged within 60 seconds\");\n\t}\n\n\tprivate List<String> outputLines() {\n\t\tPath outputPath = getOutput().get().getAsFile().toPath();\n\t\ttry {\n\t\t\treturn Files.readAllLines(outputPath);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to read lines of output from '\" + outputPath + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate void normalizeLogging() {\n\t\tList<String> outputLines = outputLines();\n\t\tList<String> normalizedLines = normalize(outputLines);\n\t\tPath outputPath = getOutput().get().getAsFile().toPath();\n\t\ttry {\n\t\t\tFiles.write(outputPath, normalizedLines);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to write normalized lines of output to '\" + outputPath + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate List<String> normalize(List<String> lines) {\n\t\tList<String> normalizedLines = lines;\n\t\tMap<String, String> normalizations = new HashMap<>(getNormalizations().get());\n\t\tnormalizations.put(\"(Starting .* using Java .* with PID [\\\\d]+ \\\\().*( started by ).*( in ).*(\\\\))\",\n\t\t\t\t\"$1\" + getApplicationJar().get() + \"$2myuser$3/opt/apps/$4\");\n\t\tfor (Entry<String, String> normalization : normalizations.entrySet()) {\n\t\t\tPattern pattern = Pattern.compile(normalization.getKey());\n\t\t\tnormalizedLines = normalize(normalizedLines, pattern, normalization.getValue());\n\t\t}\n\t\treturn normalizedLines;\n\t}\n\n\tprivate List<String> normalize(List<String> lines, Pattern pattern, String replacement) {\n\t\tboolean matched = false;\n\t\tList<String> normalizedLines = new ArrayList<>();\n\t\tfor (String line : lines) {\n\t\t\tMatcher matcher = pattern.matcher(line);\n\t\t\tStringBuilder transformed = new StringBuilder();\n\t\t\twhile (matcher.find()) {\n\t\t\t\tmatched = true;\n\t\t\t\tmatcher.appendReplacement(transformed, replacement);\n\t\t\t}\n\t\t\tmatcher.appendTail(transformed);\n\t\t\tnormalizedLines.add(transformed.toString());\n\t\t}\n\t\tif (!matched) {\n\t\t\treportUnmatchedNormalization(lines, pattern);\n\t\t}\n\t\treturn normalizedLines;\n\t}\n\n\tprivate void reportUnmatchedNormalization(List<String> lines, Pattern pattern) {\n\t\tStringBuilder message = new StringBuilder(\n\t\t\t\t\"'\" + pattern + \"' did not match any of the following lines of output:\");\n\t\tmessage.append(String.format(\"%n\"));\n\t\tfor (String line : lines) {\n\t\t\tmessage.append(String.format(\"%s%n\", line));\n\t\t}\n\t\tthrow new IllegalStateException(message.toString());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/docs/ConfigureJavadocLinks.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.docs;\n\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.gradle.api.Action;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.javadoc.Javadoc;\nimport org.gradle.external.javadoc.StandardJavadocDocletOptions;\n\nimport org.springframework.boot.build.bom.ResolvedBom;\nimport org.springframework.boot.build.bom.ResolvedBom.JavadocLink;\n\n/**\n * An {@link Action} to configure the links option of a {@link Javadoc} task.\n *\n * @author Andy Wilkinson\n */\npublic class ConfigureJavadocLinks implements Action<Javadoc> {\n\n\tprivate final FileCollection resolvedBoms;\n\n\tprivate final Collection<String> includedLibraries;\n\n\tpublic ConfigureJavadocLinks(FileCollection resolvedBoms, Collection<String> includedLibraries) {\n\t\tthis.resolvedBoms = resolvedBoms;\n\t\tthis.includedLibraries = includedLibraries;\n\t}\n\n\t@Override\n\tpublic void execute(Javadoc javadoc) {\n\t\tjavadoc.options((options) -> {\n\t\t\tif (options instanceof StandardJavadocDocletOptions standardOptions) {\n\t\t\t\tconfigureLinks(standardOptions);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void configureLinks(StandardJavadocDocletOptions options) {\n\t\tResolvedBom resolvedBom = ResolvedBom.readFrom(this.resolvedBoms.getSingleFile());\n\t\tList<String> links = new ArrayList<>();\n\t\tlinks.add(\"https://docs.oracle.com/en/java/javase/17/docs/api/\");\n\t\tlinks.add(\"https://jakarta.ee/specifications/platform/11/apidocs/\");\n\t\tresolvedBom.libraries()\n\t\t\t.stream()\n\t\t\t.filter((candidate) -> this.includedLibraries.contains(candidate.name()))\n\t\t\t.flatMap((library) -> library.links().javadoc().stream())\n\t\t\t.map(JavadocLink::uri)\n\t\t\t.map(URI::toString)\n\t\t\t.forEach(links::add);\n\t\toptions.setLinks(links);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/docs/DocumentManagedDependencies.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.docs;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.boot.build.bom.ResolvedBom;\nimport org.springframework.boot.build.bom.ResolvedBom.Bom;\nimport org.springframework.boot.build.bom.ResolvedBom.Id;\nimport org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;\n\n/**\n * Task for documenting {@link ResolvedBom boms'} managed dependencies.\n *\n * @author Andy Wilkinson\n */\npublic abstract class DocumentManagedDependencies extends DefaultTask {\n\n\tprivate FileCollection resolvedBoms;\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getResolvedBoms() {\n\t\treturn this.resolvedBoms;\n\t}\n\n\tpublic void setResolvedBoms(FileCollection resolvedBoms) {\n\t\tthis.resolvedBoms = resolvedBoms;\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@TaskAction\n\tpublic void documentConstrainedVersions() throws IOException {\n\t\tFile outputFile = getOutputFile().get().getAsFile();\n\t\toutputFile.getParentFile().mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"| Group ID | Artifact ID | Version\");\n\t\t\tSet<Id> managedCoordinates = new TreeSet<>((id1, id2) -> {\n\t\t\t\tint result = id1.groupId().compareTo(id2.groupId());\n\t\t\t\tif (result != 0) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\treturn id1.artifactId().compareTo(id2.artifactId());\n\t\t\t});\n\t\t\tfor (File file : getResolvedBoms().getFiles()) {\n\t\t\t\tmanagedCoordinates.addAll(process(ResolvedBom.readFrom(file)));\n\t\t\t}\n\t\t\tfor (Id id : managedCoordinates) {\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"| `%s`%n\", id.groupId());\n\t\t\t\twriter.printf(\"| `%s`%n\", id.artifactId());\n\t\t\t\twriter.printf(\"| `%s`%n\", id.version());\n\t\t\t}\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t}\n\n\tprivate Set<Id> process(ResolvedBom resolvedBom) {\n\t\tTreeSet<Id> managedCoordinates = new TreeSet<>();\n\t\tfor (ResolvedLibrary library : resolvedBom.libraries()) {\n\t\t\tfor (Id managedDependency : library.managedDependencies()) {\n\t\t\t\tmanagedCoordinates.add(managedDependency);\n\t\t\t}\n\t\t\tfor (Bom importedBom : library.importedBoms()) {\n\t\t\t\tmanagedCoordinates.addAll(process(importedBom));\n\t\t\t}\n\t\t}\n\t\treturn managedCoordinates;\n\t}\n\n\tprivate Set<Id> process(Bom bom) {\n\t\tTreeSet<Id> managedCoordinates = new TreeSet<>();\n\t\tbom.managedDependencies().stream().forEach(managedCoordinates::add);\n\t\tBom parent = bom.parent();\n\t\tif (parent != null) {\n\t\t\tmanagedCoordinates.addAll(process(parent));\n\t\t}\n\t\treturn managedCoordinates;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/docs/DocumentVersionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.docs;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.List;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.boot.build.bom.ResolvedBom;\nimport org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;\n\n/**\n * Task for documenting {@link ResolvedBom boms'} version properties.\n *\n * @author Christoph Dreis\n * @author Andy Wilkinson\n */\npublic abstract class DocumentVersionProperties extends DefaultTask {\n\n\tprivate FileCollection resolvedBoms;\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getResolvedBoms() {\n\t\treturn this.resolvedBoms;\n\t}\n\n\tpublic void setResolvedBoms(FileCollection resolvedBoms) {\n\t\tthis.resolvedBoms = resolvedBoms;\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@TaskAction\n\tpublic void documentVersionProperties() throws IOException {\n\t\tList<ResolvedLibrary> libraries = this.resolvedBoms.getFiles()\n\t\t\t.stream()\n\t\t\t.map(ResolvedBom::readFrom)\n\t\t\t.flatMap((resolvedBom) -> resolvedBom.libraries().stream())\n\t\t\t.sorted((l1, l2) -> l1.name().compareToIgnoreCase(l2.name()))\n\t\t\t.toList();\n\t\tFile outputFile = getOutputFile().getAsFile().get();\n\t\toutputFile.getParentFile().mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"| Library | Version Property\");\n\t\t\tfor (ResolvedLibrary library : libraries) {\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"| `%s`%n\", library.name());\n\t\t\t\twriter.printf(\"| `%s`%n\", library.versionProperty());\n\t\t\t}\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/DocumentPluginGoals.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.mavenplugin;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.List;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.MapProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.boot.build.mavenplugin.PluginXmlParser.Mojo;\nimport org.springframework.boot.build.mavenplugin.PluginXmlParser.Parameter;\nimport org.springframework.boot.build.mavenplugin.PluginXmlParser.Plugin;\n\n/**\n * A {@link Task} to document the plugin's goals.\n *\n * @author Andy Wilkinson\n */\npublic abstract class DocumentPluginGoals extends DefaultTask {\n\n\tprivate final PluginXmlParser parser = new PluginXmlParser();\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDir();\n\n\t@Input\n\tpublic abstract MapProperty<String, String> getGoalSections();\n\n\t@InputFile\n\tpublic abstract RegularFileProperty getPluginXml();\n\n\t@TaskAction\n\tpublic void documentPluginGoals() throws IOException {\n\t\tPlugin plugin = this.parser.parse(getPluginXml().getAsFile().get());\n\t\twriteOverview(plugin);\n\t\tfor (Mojo mojo : plugin.getMojos()) {\n\t\t\tdocumentMojo(plugin, mojo);\n\t\t}\n\t}\n\n\tprivate void writeOverview(Plugin plugin) throws IOException {\n\t\ttry (PrintWriter writer = new PrintWriter(\n\t\t\t\tnew FileWriter(new File(getOutputDir().getAsFile().get(), \"overview.adoc\")))) {\n\t\t\twriter.println(\"[cols=\\\"1,3\\\"]\");\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"| Goal | Description\");\n\t\t\twriter.println();\n\t\t\tfor (Mojo mojo : plugin.getMojos()) {\n\t\t\t\twriter.printf(\"| xref:%s[%s:%s]%n\", goalSectionId(mojo, false), plugin.getGoalPrefix(), mojo.getGoal());\n\t\t\t\twriter.printf(\"| %s%n\", mojo.getDescription());\n\t\t\t\twriter.println();\n\t\t\t}\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t}\n\n\tprivate void documentMojo(Plugin plugin, Mojo mojo) throws IOException {\n\t\ttry (PrintWriter writer = new PrintWriter(\n\t\t\t\tnew FileWriter(new File(getOutputDir().getAsFile().get(), mojo.getGoal() + \".adoc\")))) {\n\t\t\tString sectionId = goalSectionId(mojo, true);\n\t\t\twriter.printf(\"[[%s]]%n\", sectionId);\n\t\t\twriter.printf(\"= `%s:%s`%n%n\", plugin.getGoalPrefix(), mojo.getGoal());\n\t\t\twriter.printf(\"`%s:%s:%s`%n\", plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion());\n\t\t\twriter.println();\n\t\t\twriter.println(mojo.getDescription());\n\t\t\tList<Parameter> parameters = mojo.getParameters().stream().filter(Parameter::isEditable).toList();\n\t\t\tList<Parameter> requiredParameters = parameters.stream().filter(Parameter::isRequired).toList();\n\t\t\tString detailsSectionId = sectionId + \".parameter-details\";\n\t\t\tif (!requiredParameters.isEmpty()) {\n\t\t\t\twriter.println();\n\t\t\t\twriter.println();\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"[[%s.required-parameters]]%n\", sectionId);\n\t\t\t\twriter.println(\"== Required parameters\");\n\t\t\t\twriter.println();\n\t\t\t\twriteParametersTable(writer, detailsSectionId, requiredParameters);\n\t\t\t}\n\t\t\tList<Parameter> optionalParameters = parameters.stream()\n\t\t\t\t.filter((parameter) -> !parameter.isRequired())\n\t\t\t\t.toList();\n\t\t\tif (!optionalParameters.isEmpty()) {\n\t\t\t\twriter.println();\n\t\t\t\twriter.println();\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"[[%s.optional-parameters]]%n\", sectionId);\n\t\t\t\twriter.println(\"== Optional parameters\");\n\t\t\t\twriter.println();\n\t\t\t\twriteParametersTable(writer, detailsSectionId, optionalParameters);\n\t\t\t}\n\t\t\twriter.println();\n\t\t\twriter.println();\n\t\t\twriter.println();\n\t\t\twriter.printf(\"[[%s]]%n\", detailsSectionId);\n\t\t\twriter.println(\"== Parameter details\");\n\t\t\twriter.println();\n\t\t\twriteParameterDetails(writer, parameters, detailsSectionId);\n\t\t}\n\t}\n\n\tprivate String goalSectionId(Mojo mojo, boolean innerReference) {\n\t\tString goalSection = getGoalSections().getting(mojo.getGoal()).get();\n\t\tif (goalSection == null) {\n\t\t\tthrow new IllegalStateException(\"Goal '\" + mojo.getGoal() + \"' has not be assigned to a section\");\n\t\t}\n\t\tString sectionId = goalSection + \".\" + mojo.getGoal() + \"-goal\";\n\t\treturn (!innerReference) ? goalSection + \"#\" + sectionId : sectionId;\n\t}\n\n\tprivate void writeParametersTable(PrintWriter writer, String detailsSectionId, List<Parameter> parameters) {\n\t\twriter.println(\"[cols=\\\"3,2,3\\\"]\");\n\t\twriter.println(\"|===\");\n\t\twriter.println(\"| Name | Type | Default\");\n\t\twriter.println();\n\t\tfor (Parameter parameter : parameters) {\n\t\t\tString name = parameter.getName();\n\t\t\twriter.printf(\"| xref:#%s.%s[%s]%n\", detailsSectionId, parameterId(name), name);\n\t\t\twriter.printf(\"| `%s`%n\", typeNameToJavadocLink(shortTypeName(parameter.getType()), parameter.getType()));\n\t\t\tString defaultValue = parameter.getDefaultValue();\n\t\t\tif (defaultValue != null) {\n\t\t\t\twriter.printf(\"| `%s`%n\", defaultValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\twriter.println(\"|\");\n\t\t\t}\n\t\t\twriter.println();\n\t\t}\n\t\twriter.println(\"|===\");\n\t}\n\n\tprivate void writeParameterDetails(PrintWriter writer, List<Parameter> parameters, String sectionId) {\n\t\tfor (Parameter parameter : parameters) {\n\t\t\tString name = parameter.getName();\n\t\t\twriter.println();\n\t\t\twriter.println();\n\t\t\twriter.printf(\"[[%s.%s]]%n\", sectionId, parameterId(name));\n\t\t\twriter.printf(\"=== `%s`%n\", name);\n\t\t\twriter.println(parameter.getDescription());\n\t\t\twriter.println();\n\t\t\twriter.println(\"[cols=\\\"10h,90\\\"]\");\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println();\n\t\t\twriteDetail(writer, \"Name\", name);\n\t\t\twriteDetail(writer, \"Type\", typeNameToJavadocLink(parameter.getType()));\n\t\t\twriteOptionalDetail(writer, \"Default value\", parameter.getDefaultValue());\n\t\t\twriteOptionalDetail(writer, \"User property\", parameter.getUserProperty());\n\t\t\twriteOptionalDetail(writer, \"Since\", parameter.getSince());\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t}\n\n\tprivate String parameterId(String name) {\n\t\tStringBuilder id = new StringBuilder(name.length() + 4);\n\t\tfor (char c : name.toCharArray()) {\n\t\t\tif (Character.isLowerCase(c)) {\n\t\t\t\tid.append(c);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tid.append(\"-\");\n\t\t\t\tid.append(Character.toLowerCase(c));\n\t\t\t}\n\t\t}\n\t\treturn id.toString();\n\t}\n\n\tprivate void writeDetail(PrintWriter writer, String name, String value) {\n\t\twriter.printf(\"| %s%n\", name);\n\t\twriter.printf(\"| `%s`%n\", value);\n\t\twriter.println();\n\t}\n\n\tprivate void writeOptionalDetail(PrintWriter writer, String name, String value) {\n\t\twriter.printf(\"| %s%n\", name);\n\t\tif (value != null) {\n\t\t\twriter.printf(\"| `%s`%n\", value);\n\t\t}\n\t\telse {\n\t\t\twriter.println(\"|\");\n\t\t}\n\t\twriter.println();\n\t}\n\n\tprivate String shortTypeName(String name) {\n\t\tif (name.lastIndexOf('.') >= 0) {\n\t\t\tname = name.substring(name.lastIndexOf('.') + 1);\n\t\t}\n\t\tif (name.lastIndexOf('$') >= 0) {\n\t\t\tname = name.substring(name.lastIndexOf('$') + 1);\n\t\t}\n\t\treturn name;\n\t}\n\n\tprivate String typeNameToJavadocLink(String name) {\n\t\treturn typeNameToJavadocLink(name, name);\n\t}\n\n\tprivate String typeNameToJavadocLink(String shortName, String name) {\n\t\tif (name.startsWith(\"org.springframework.boot.maven\")) {\n\t\t\treturn \"xref:maven-plugin:api/java/\" + typeNameToJavadocPath(name) + \".html[\" + shortName + \"]\";\n\t\t}\n\t\tif (name.startsWith(\"org.springframework.boot\")) {\n\t\t\treturn \"xref:api:java/\" + typeNameToJavadocPath(name) + \".html[\" + shortName + \"]\";\n\t\t}\n\t\treturn shortName;\n\t}\n\n\tprivate String typeNameToJavadocPath(String name) {\n\t\treturn name.replace(\".\", \"/\").replace(\"$\", \".\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenExec.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.mavenplugin;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFile;\nimport org.gradle.api.tasks.Internal;\nimport org.gradle.api.tasks.JavaExec;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskExecutionException;\nimport org.gradle.process.internal.ExecException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A custom {@link JavaExec} {@link Task task} for running Maven.\n *\n * @author Andy Wilkinson\n */\npublic abstract class MavenExec extends JavaExec {\n\n\tprivate final Logger logger = LoggerFactory.getLogger(MavenExec.class);\n\n\tpublic MavenExec() {\n\t\tsetClasspath(mavenConfiguration(getProject()));\n\t\targs(\"--batch-mode\");\n\t\tgetMainClass().set(\"org.apache.maven.cli.MavenCli\");\n\t\tgetPom().set(getProjectDir().file(\"pom.xml\"));\n\t}\n\n\t@Internal\n\tpublic abstract DirectoryProperty getProjectDir();\n\n\t@InputFile\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tabstract RegularFileProperty getPom();\n\n\t@Override\n\tpublic void exec() {\n\t\tFile workingDir = getProjectDir().getAsFile().get();\n\t\tworkingDir(workingDir);\n\t\tsystemProperty(\"maven.multiModuleProjectDirectory\", workingDir.getAbsolutePath());\n\t\ttry {\n\t\t\tPath logFile = Files.createTempFile(getName(), \".log\");\n\t\t\ttry {\n\t\t\t\targs(\"--log-file\", logFile.toFile().getAbsolutePath());\n\t\t\t\tsuper.exec();\n\t\t\t\tif (this.logger.isInfoEnabled()) {\n\t\t\t\t\tFiles.readAllLines(logFile).forEach(this.logger::info);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ExecException ex) {\n\t\t\t\tSystem.out.println(\"Exec exception! Dumping log\");\n\t\t\t\tFiles.readAllLines(logFile).forEach(System.out::println);\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new TaskExecutionException(this, ex);\n\t\t}\n\t}\n\n\tprivate Configuration mavenConfiguration(Project project) {\n\t\tConfiguration existing = project.getConfigurations().findByName(\"maven\");\n\t\tif (existing != null) {\n\t\t\treturn existing;\n\t\t}\n\t\treturn project.getConfigurations().create(\"maven\", (maven) -> {\n\t\t\tmaven.getDependencies().add(project.getDependencies().create(\"org.apache.maven:maven-embedder:3.6.3\"));\n\t\t\tmaven.getDependencies().add(project.getDependencies().create(\"org.apache.maven:maven-compat:3.6.3\"));\n\t\t\tmaven.getDependencies().add(project.getDependencies().create(\"org.slf4j:slf4j-simple:1.7.5\"));\n\t\t\tmaven.getDependencies()\n\t\t\t\t.add(project.getDependencies()\n\t\t\t\t\t.create(\"org.apache.maven.resolver:maven-resolver-connector-basic:1.4.1\"));\n\t\t\tmaven.getDependencies()\n\t\t\t\t.add(project.getDependencies().create(\"org.apache.maven.resolver:maven-resolver-transport-http:1.4.1\"));\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenPluginPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.mavenplugin;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.Arrays;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport javax.inject.Inject;\n\nimport io.spring.javaformat.formatter.FileEdit;\nimport io.spring.javaformat.formatter.FileFormatter;\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.ComponentMetadataContext;\nimport org.gradle.api.artifacts.ComponentMetadataRule;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ModuleVersionIdentifier;\nimport org.gradle.api.artifacts.VariantMetadata;\nimport org.gradle.api.artifacts.component.ModuleComponentIdentifier;\nimport org.gradle.api.artifacts.result.ResolvedArtifactResult;\nimport org.gradle.api.attributes.DocsType;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.component.AdhocComponentWithVariants;\nimport org.gradle.api.component.ConfigurationVariantDetails;\nimport org.gradle.api.component.SoftwareComponent;\nimport org.gradle.api.file.CopySpec;\nimport org.gradle.api.file.Directory;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.ProjectLayout;\nimport org.gradle.api.file.RegularFile;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.plugins.JavaLibraryPlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.publish.PublishingExtension;\nimport org.gradle.api.publish.maven.MavenPublication;\nimport org.gradle.api.publish.maven.plugins.MavenPublishPlugin;\nimport org.gradle.api.publish.tasks.GenerateModuleMetadata;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.Sync;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.TaskExecutionException;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\nimport org.gradle.api.tasks.javadoc.Javadoc;\nimport org.gradle.external.javadoc.StandardJavadocDocletOptions;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\nimport org.springframework.boot.build.DeployedPlugin;\nimport org.springframework.boot.build.MavenRepositoryPlugin;\nimport org.springframework.boot.build.bom.ResolvedBom;\nimport org.springframework.boot.build.bom.ResolvedBom.ResolvedLibrary;\nimport org.springframework.boot.build.optional.OptionalDependenciesPlugin;\nimport org.springframework.boot.build.test.DockerTestPlugin;\nimport org.springframework.boot.build.test.IntegrationTestPlugin;\nimport org.springframework.core.CollectionFactory;\n\n/**\n * Plugin for building Spring Boot's Maven Plugin.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\npublic class MavenPluginPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().apply(JavaLibraryPlugin.class);\n\t\tproject.getPlugins().apply(MavenPublishPlugin.class);\n\t\tproject.getPlugins().apply(DeployedPlugin.class);\n\t\tproject.getPlugins().apply(MavenRepositoryPlugin.class);\n\t\tproject.getPlugins().apply(IntegrationTestPlugin.class);\n\t\tJar jarTask = (Jar) project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME);\n\t\tconfigurePomPackaging(project);\n\t\taddPopulateIntTestMavenRepositoryTask(project);\n\t\tTaskProvider<MavenExec> generateHelpMojoTask = addGenerateHelpMojoTask(project, jarTask);\n\t\tTaskProvider<MavenExec> generatePluginDescriptorTask = addGeneratePluginDescriptorTask(project, jarTask,\n\t\t\t\tgenerateHelpMojoTask);\n\t\taddDocumentPluginGoalsTask(project, generatePluginDescriptorTask);\n\t\taddPrepareMavenBinariesTask(project);\n\t\tTaskProvider<ExtractVersionProperties> extractVersionPropertiesTask = addExtractVersionPropertiesTask(project);\n\t\tproject.getTasks()\n\t\t\t.named(IntegrationTestPlugin.INT_TEST_TASK_NAME)\n\t\t\t.configure((task) -> task.getInputs()\n\t\t\t\t.file(extractVersionPropertiesTask.map(ExtractVersionProperties::getDestination))\n\t\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t\t.withPropertyName(\"versionProperties\"));\n\t\tpublishOptionalDependenciesInPom(project);\n\t\tproject.getTasks().withType(GenerateModuleMetadata.class).configureEach((task) -> task.setEnabled(false));\n\t}\n\n\tprivate void publishOptionalDependenciesInPom(Project project) {\n\t\tproject.getPlugins().withType(OptionalDependenciesPlugin.class, (optionalDependencies) -> {\n\t\t\tSoftwareComponent component = project.getComponents().findByName(\"java\");\n\t\t\tif (component instanceof AdhocComponentWithVariants componentWithVariants) {\n\t\t\t\tcomponentWithVariants.addVariantsFromConfiguration(\n\t\t\t\t\t\tproject.getConfigurations().getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME),\n\t\t\t\t\t\tConfigurationVariantDetails::mapToOptional);\n\t\t\t}\n\t\t});\n\t\tMavenPublication publication = (MavenPublication) project.getExtensions()\n\t\t\t.getByType(PublishingExtension.class)\n\t\t\t.getPublications()\n\t\t\t.getByName(\"maven\");\n\t\tpublication.getPom().withXml((xml) -> {\n\t\t\tElement root = xml.asElement();\n\t\t\tNodeList children = root.getChildNodes();\n\t\t\tfor (int i = 0; i < children.getLength(); i++) {\n\t\t\t\tNode child = children.item(i);\n\t\t\t\tif (\"dependencyManagement\".equals(child.getNodeName())) {\n\t\t\t\t\troot.removeChild(child);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void configurePomPackaging(Project project) {\n\t\tPublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);\n\t\tpublishing.getPublications().withType(MavenPublication.class, this::setPackaging);\n\t}\n\n\tprivate void setPackaging(MavenPublication mavenPublication) {\n\t\tmavenPublication.pom((pom) -> pom.setPackaging(\"maven-plugin\"));\n\t}\n\n\tprivate void addPopulateIntTestMavenRepositoryTask(Project project) {\n\t\tConfiguration repositoryContents = project.getConfigurations().create(\"repositoryContents\");\n\t\trepositoryContents.extendsFrom(\n\t\t\t\tproject.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME),\n\t\t\t\tproject.getConfigurations().getByName(\"mavenRepository\"));\n\t\trepositoryContents.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,\n\t\t\t\tproject.getObjects().named(DocsType.class, \"maven-repository\")));\n\t\trepositoryContents.setCanBeConsumed(false);\n\t\tTaskProvider<ResolvedConfigurationMavenRepository> populateMavenRepository = project.getTasks()\n\t\t\t.register(\"populateResolvedDependenciesMavenRepository\", ResolvedConfigurationMavenRepository.class,\n\t\t\t\t\t(task) -> {\n\t\t\t\t\t\ttask.setConfiguration(repositoryContents);\n\t\t\t\t\t\ttask.getOutputDir()\n\t\t\t\t\t\t\t.set(project.getLayout().getBuildDirectory().dir(\"resolved-dependencies-maven-repository\"));\n\t\t\t\t\t});\n\t\tproject.getDependencies()\n\t\t\t.components((components) -> components.all(MavenRepositoryComponentMetadataRule.class));\n\t\tTaskProvider<Sync> populateRepository = project.getTasks()\n\t\t\t.register(\"populateTestMavenRepository\", Sync.class, (task) -> {\n\t\t\t\ttask.setDestinationDir(\n\t\t\t\t\t\tproject.getLayout().getBuildDirectory().dir(\"test-maven-repository\").get().getAsFile());\n\t\t\t\ttask.with(copyIntTestMavenRepositoryFiles(project, populateMavenRepository));\n\t\t\t\ttask.dependsOn(\n\t\t\t\t\t\tproject.getTasks().getByName(MavenRepositoryPlugin.PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME));\n\t\t\t});\n\t\tproject.getTasks().getByName(IntegrationTestPlugin.INT_TEST_TASK_NAME).dependsOn(populateRepository);\n\t\tproject.getPlugins()\n\t\t\t.withType(DockerTestPlugin.class)\n\t\t\t.all((dockerTestPlugin) -> project.getTasks()\n\t\t\t\t.named(DockerTestPlugin.DOCKER_TEST_TASK_NAME,\n\t\t\t\t\t\t(dockerTest) -> dockerTest.dependsOn(populateRepository)));\n\t}\n\n\tprivate CopySpec copyIntTestMavenRepositoryFiles(Project project,\n\t\t\tTaskProvider<ResolvedConfigurationMavenRepository> runtimeClasspathMavenRepository) {\n\t\tCopySpec copySpec = project.copySpec();\n\t\tcopySpec.from(project.getConfigurations().getByName(MavenRepositoryPlugin.MAVEN_REPOSITORY_CONFIGURATION_NAME));\n\t\tcopySpec.from(project.getLayout().getBuildDirectory().dir(\"maven-repository\"));\n\t\tcopySpec.from(runtimeClasspathMavenRepository);\n\t\treturn copySpec;\n\t}\n\n\tprivate void addDocumentPluginGoalsTask(Project project, TaskProvider<MavenExec> generatePluginDescriptorTask) {\n\t\tproject.getTasks().register(\"documentPluginGoals\", DocumentPluginGoals.class, (task) -> {\n\t\t\tProjectLayout layout = project.getLayout();\n\t\t\tProvider<RegularFile> pluginXml = layout.file(generatePluginDescriptorTask\n\t\t\t\t.map((generateDescriptor) -> new File(generateDescriptor.getOutputs().getFiles().getSingleFile(),\n\t\t\t\t\t\t\"plugin.xml\")));\n\t\t\ttask.getPluginXml().set(pluginXml);\n\t\t\ttask.getOutputDir().set(layout.getBuildDirectory().dir(\"docs/generated/goals/\"));\n\t\t\ttask.dependsOn(generatePluginDescriptorTask);\n\t\t});\n\t}\n\n\tprivate TaskProvider<MavenExec> addGenerateHelpMojoTask(Project project, Jar jarTask) {\n\t\tProvider<Directory> helpMojoDir = project.getLayout().getBuildDirectory().dir(\"help-mojo\");\n\t\tTaskProvider<Sync> syncHelpMojoInputs = createSyncHelpMojoInputsTask(project, helpMojoDir);\n\t\tTaskProvider<MavenExec> task = createGenerateHelpMojoTask(project, helpMojoDir, syncHelpMojoInputs);\n\t\tincludeHelpMojoInJar(jarTask, task);\n\t\treturn task;\n\t}\n\n\tprivate TaskProvider<MavenExec> createGenerateHelpMojoTask(Project project, Provider<Directory> helpMojoDir,\n\t\t\tTaskProvider<Sync> syncHelpMojoInputs) {\n\t\treturn project.getTasks().register(\"generateHelpMojo\", MavenExec.class, (task) -> {\n\t\t\ttask.getProjectDir().set(helpMojoDir);\n\t\t\ttask.args(\"org.apache.maven.plugins:maven-plugin-plugin:3.6.1:helpmojo\");\n\t\t\ttask.getOutputs().dir(helpMojoDir.map((directory) -> directory.dir(\"target/generated-sources/plugin\")));\n\t\t\ttask.dependsOn(syncHelpMojoInputs);\n\t\t});\n\t}\n\n\tprivate TaskProvider<Sync> createSyncHelpMojoInputsTask(Project project, Provider<Directory> helpMojoDir) {\n\t\treturn project.getTasks().register(\"syncHelpMojoInputs\", Sync.class, (task) -> {\n\t\t\ttask.setDestinationDir(helpMojoDir.get().getAsFile());\n\t\t\tFile pomFile = new File(project.getProjectDir(), \"src/maven/resources/pom.xml\");\n\t\t\ttask.from(pomFile, (copy) -> replaceVersionPlaceholder(copy, project));\n\t\t});\n\t}\n\n\tprivate void includeHelpMojoInJar(Jar jarTask, TaskProvider<MavenExec> generateHelpMojoTask) {\n\t\tjarTask.from(generateHelpMojoTask).exclude(\"**/*.java\");\n\t\tjarTask.dependsOn(generateHelpMojoTask);\n\t}\n\n\tprivate TaskProvider<MavenExec> addGeneratePluginDescriptorTask(Project project, Jar jarTask,\n\t\t\tTaskProvider<MavenExec> generateHelpMojoTask) {\n\t\tProvider<Directory> pluginDescriptorDir = project.getLayout().getBuildDirectory().dir(\"plugin-descriptor\");\n\t\tProvider<Directory> generatedHelpMojoDir = project.getLayout()\n\t\t\t.getBuildDirectory()\n\t\t\t.dir(\"generated/sources/helpMojo\");\n\t\tSourceSet mainSourceSet = getMainSourceSet(project);\n\t\tproject.getTasks().withType(Javadoc.class, this::setJavadocOptions);\n\t\tTaskProvider<FormatHelpMojoSource> formattedHelpMojoSource = createFormatHelpMojoSource(project,\n\t\t\t\tgenerateHelpMojoTask, generatedHelpMojoDir);\n\t\tproject.getTasks().getByName(mainSourceSet.getCompileJavaTaskName()).dependsOn(formattedHelpMojoSource);\n\t\tmainSourceSet.java((javaSources) -> javaSources.srcDir(formattedHelpMojoSource));\n\t\tTaskProvider<Sync> pluginDescriptorInputs = createSyncPluginDescriptorInputs(project, pluginDescriptorDir,\n\t\t\t\tmainSourceSet);\n\t\tTaskProvider<MavenExec> task = createGeneratePluginDescriptorTask(project, pluginDescriptorDir,\n\t\t\t\tpluginDescriptorInputs);\n\t\tincludeDescriptorInJar(jarTask, task);\n\t\treturn task;\n\t}\n\n\tprivate SourceSet getMainSourceSet(Project project) {\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();\n\t\treturn sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t}\n\n\tprivate void setJavadocOptions(Javadoc javadoc) {\n\t\tStandardJavadocDocletOptions options = (StandardJavadocDocletOptions) javadoc.getOptions();\n\t\toptions.addMultilineStringsOption(\"tag\").setValue(Arrays.asList(\"goal:X\", \"requiresProject:X\", \"threadSafe:X\"));\n\t}\n\n\tprivate TaskProvider<FormatHelpMojoSource> createFormatHelpMojoSource(Project project,\n\t\t\tTaskProvider<MavenExec> generateHelpMojoTask, Provider<Directory> generatedHelpMojoDir) {\n\t\treturn project.getTasks().register(\"formatHelpMojoSource\", FormatHelpMojoSource.class, (task) -> {\n\t\t\ttask.setGenerator(generateHelpMojoTask);\n\t\t\ttask.getOutputDir().set(generatedHelpMojoDir);\n\t\t});\n\t}\n\n\tprivate TaskProvider<Sync> createSyncPluginDescriptorInputs(Project project, Provider<Directory> destination,\n\t\t\tSourceSet sourceSet) {\n\t\treturn project.getTasks().register(\"syncPluginDescriptorInputs\", Sync.class, (task) -> {\n\t\t\ttask.setDestinationDir(destination.get().getAsFile());\n\t\t\tFile pomFile = new File(project.getProjectDir(), \"src/maven/resources/pom.xml\");\n\t\t\ttask.from(pomFile, (copy) -> replaceVersionPlaceholder(copy, project));\n\t\t\ttask.from(sourceSet.getOutput().getClassesDirs(), (sync) -> sync.into(\"target/classes\"));\n\t\t\ttask.from(sourceSet.getAllJava().getSrcDirs(), (sync) -> sync.into(\"src/main/java\"));\n\t\t\ttask.getInputs().property(\"version\", project.getVersion());\n\t\t\ttask.dependsOn(sourceSet.getClassesTaskName());\n\t\t});\n\t}\n\n\tprivate TaskProvider<MavenExec> createGeneratePluginDescriptorTask(Project project, Provider<Directory> mavenDir,\n\t\t\tTaskProvider<Sync> pluginDescriptorInputs) {\n\t\treturn project.getTasks().register(\"generatePluginDescriptor\", MavenExec.class, (task) -> {\n\t\t\ttask.args(\"org.apache.maven.plugins:maven-plugin-plugin:3.6.1:descriptor\");\n\t\t\ttask.getOutputs().dir(mavenDir.map((directory) -> directory.dir(\"target/classes/META-INF/maven\")));\n\t\t\ttask.getInputs()\n\t\t\t\t.dir(mavenDir.map((directory) -> directory.dir(\"target/classes/org\")))\n\t\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t\t.withPropertyName(\"plugin classes\");\n\t\t\ttask.getProjectDir().set(mavenDir);\n\t\t\ttask.dependsOn(pluginDescriptorInputs);\n\t\t});\n\t}\n\n\tprivate void includeDescriptorInJar(Jar jar, TaskProvider<MavenExec> generatePluginDescriptorTask) {\n\t\tjar.from(generatePluginDescriptorTask, (copy) -> copy.into(\"META-INF/maven/\"));\n\t\tjar.dependsOn(generatePluginDescriptorTask);\n\t}\n\n\tprivate void addPrepareMavenBinariesTask(Project project) {\n\t\tTaskProvider<PrepareMavenBinaries> task = project.getTasks()\n\t\t\t.register(\"prepareMavenBinaries\", PrepareMavenBinaries.class,\n\t\t\t\t\t(prepareMavenBinaries) -> prepareMavenBinaries.getOutputDir()\n\t\t\t\t\t\t.set(project.getLayout().getBuildDirectory().dir(\"maven-binaries\")));\n\t\tproject.getTasks()\n\t\t\t.getByName(IntegrationTestPlugin.INT_TEST_TASK_NAME)\n\t\t\t.getInputs()\n\t\t\t.dir(task.map(PrepareMavenBinaries::getOutputDir))\n\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t.withPropertyName(\"mavenBinaries\");\n\t}\n\n\tprivate void replaceVersionPlaceholder(CopySpec copy, Project project) {\n\t\tcopy.filter((input) -> replaceVersionPlaceholder(project, input));\n\t}\n\n\tprivate String replaceVersionPlaceholder(Project project, String input) {\n\t\treturn input.replace(\"{{version}}\", project.getVersion().toString());\n\t}\n\n\tprivate TaskProvider<ExtractVersionProperties> addExtractVersionPropertiesTask(Project project) {\n\t\treturn project.getTasks().register(\"extractVersionProperties\", ExtractVersionProperties.class, (task) -> {\n\t\t\ttask.setResolvedBoms(project.getConfigurations().create(\"versionProperties\"));\n\t\t\ttask.getDestination()\n\t\t\t\t.set(project.getLayout()\n\t\t\t\t\t.getBuildDirectory()\n\t\t\t\t\t.dir(\"generated-resources\")\n\t\t\t\t\t.map((dir) -> dir.file(\"extracted-versions.properties\")));\n\t\t});\n\t}\n\n\tpublic abstract static class FormatHelpMojoSource extends DefaultTask {\n\n\t\tprivate final ObjectFactory objectFactory;\n\n\t\t@Inject\n\t\tpublic FormatHelpMojoSource(ObjectFactory objectFactory) {\n\t\t\tthis.objectFactory = objectFactory;\n\t\t}\n\n\t\tprivate TaskProvider<?> generator;\n\n\t\tvoid setGenerator(TaskProvider<?> generator) {\n\t\t\tthis.generator = generator;\n\t\t\tgetInputs().files(this.generator)\n\t\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t\t.withPropertyName(\"generated source\");\n\t\t}\n\n\t\t@OutputDirectory\n\t\tpublic abstract DirectoryProperty getOutputDir();\n\n\t\t@TaskAction\n\t\tvoid syncAndFormat() {\n\t\t\tFileFormatter formatter = new FileFormatter();\n\t\t\tfor (File output : this.generator.get().getOutputs().getFiles()) {\n\t\t\t\tformatter.formatFiles(this.objectFactory.fileTree().from(output), StandardCharsets.UTF_8)\n\t\t\t\t\t.forEach((edit) -> save(output, edit));\n\t\t\t}\n\t\t}\n\n\t\tprivate void save(File output, FileEdit edit) {\n\t\t\tPath relativePath = output.toPath().relativize(edit.getFile().toPath());\n\t\t\tPath outputLocation = getOutputDir().getAsFile().get().toPath().resolve(relativePath);\n\t\t\ttry {\n\t\t\t\tFiles.createDirectories(outputLocation.getParent());\n\t\t\t\tString content = edit.getFormattedContent();\n\t\t\t\tcontent = addNullAwaySuppression(content);\n\t\t\t\tFiles.writeString(outputLocation, content);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new TaskExecutionException(this, ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate String addNullAwaySuppression(String content) {\n\t\t\tString separator = System.lineSeparator();\n\t\t\tString[] lines = content.split(separator);\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tfor (String line : lines) {\n\t\t\t\tif (line.startsWith(\"public class \")) {\n\t\t\t\t\tresult.append(\"@SuppressWarnings(\\\"NullAway\\\")\").append(separator);\n\t\t\t\t}\n\t\t\t\tresult.append(line).append(separator);\n\t\t\t}\n\t\t\treturn result.toString();\n\t\t}\n\n\t}\n\n\tpublic static class MavenRepositoryComponentMetadataRule implements ComponentMetadataRule {\n\n\t\tprivate final ObjectFactory objects;\n\n\t\t@javax.inject.Inject\n\t\tpublic MavenRepositoryComponentMetadataRule(ObjectFactory objects) {\n\t\t\tthis.objects = objects;\n\t\t}\n\n\t\t@Override\n\t\tpublic void execute(ComponentMetadataContext context) {\n\t\t\tcontext.getDetails()\n\t\t\t\t.maybeAddVariant(\"compileWithMetadata\", \"compile\", (variant) -> configureVariant(context, variant));\n\t\t\tcontext.getDetails()\n\t\t\t\t.maybeAddVariant(\"apiElementsWithMetadata\", \"apiElements\",\n\t\t\t\t\t\t(variant) -> configureVariant(context, variant));\n\t\t}\n\n\t\tprivate void configureVariant(ComponentMetadataContext context, VariantMetadata variant) {\n\t\t\tvariant.attributes((attributes) -> {\n\t\t\t\tattributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,\n\t\t\t\t\t\tthis.objects.named(DocsType.class, \"maven-repository\"));\n\t\t\t\tattributes.attribute(Usage.USAGE_ATTRIBUTE, this.objects.named(Usage.class, \"maven-repository\"));\n\t\t\t});\n\t\t\tvariant.withFiles((files) -> {\n\t\t\t\tModuleVersionIdentifier id = context.getDetails().getId();\n\t\t\t\tfiles.addFile(id.getName() + \"-\" + id.getVersion() + \".pom\");\n\t\t\t});\n\t\t}\n\n\t}\n\n\tpublic abstract static class ResolvedConfigurationMavenRepository extends DefaultTask {\n\n\t\tprivate Configuration configuration;\n\n\t\t@OutputDirectory\n\t\tpublic abstract DirectoryProperty getOutputDir();\n\n\t\t@Classpath\n\t\tpublic Configuration getConfiguration() {\n\t\t\treturn this.configuration;\n\t\t}\n\n\t\tpublic void setConfiguration(Configuration configuration) {\n\t\t\tthis.configuration = configuration;\n\t\t}\n\n\t\t@TaskAction\n\t\tpublic void createRepository() {\n\t\t\tfor (ResolvedArtifactResult result : this.configuration.getIncoming().getArtifacts()) {\n\t\t\t\tif (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier identifier) {\n\t\t\t\t\tString fileName = result.getFile()\n\t\t\t\t\t\t.getName()\n\t\t\t\t\t\t.replace(identifier.getVersion() + \"-\" + identifier.getVersion(), identifier.getVersion());\n\t\t\t\t\tFile repositoryLocation = getOutputDir()\n\t\t\t\t\t\t.dir(identifier.getGroup().replace('.', '/') + \"/\" + identifier.getModule() + \"/\"\n\t\t\t\t\t\t\t\t+ identifier.getVersion() + \"/\" + fileName)\n\t\t\t\t\t\t.get()\n\t\t\t\t\t\t.getAsFile();\n\t\t\t\t\trepositoryLocation.getParentFile().mkdirs();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tFiles.copy(result.getFile().toPath(), repositoryLocation.toPath(),\n\t\t\t\t\t\t\t\tStandardCopyOption.REPLACE_EXISTING);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t\tthrow new RuntimeException(\"Failed to copy artifact '\" + result + \"'\", ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic abstract static class ExtractVersionProperties extends DefaultTask {\n\n\t\tprivate FileCollection resolvedBoms;\n\n\t\t@InputFiles\n\t\t@PathSensitive(PathSensitivity.RELATIVE)\n\t\tpublic FileCollection getResolvedBoms() {\n\t\t\treturn this.resolvedBoms;\n\t\t}\n\n\t\tpublic void setResolvedBoms(FileCollection resolvedBoms) {\n\t\t\tthis.resolvedBoms = resolvedBoms;\n\t\t}\n\n\t\t@OutputFile\n\t\tpublic abstract RegularFileProperty getDestination();\n\n\t\t@TaskAction\n\t\tpublic void extractVersionProperties() {\n\t\t\tResolvedBom resolvedBom = ResolvedBom.readFrom(this.resolvedBoms.getSingleFile());\n\t\t\tProperties versions = extractVersionProperties(resolvedBom);\n\t\t\twriteProperties(versions);\n\t\t}\n\n\t\tprivate void writeProperties(Properties versions) {\n\t\t\tFile outputFile = getDestination().getAsFile().get();\n\t\t\toutputFile.getParentFile().mkdirs();\n\t\t\ttry (Writer writer = new FileWriter(outputFile)) {\n\t\t\t\tversions.store(writer, null);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new GradleException(\"Failed to write extracted version properties\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate Properties extractVersionProperties(ResolvedBom resolvedBom) {\n\t\t\tProperties versions = CollectionFactory.createSortedProperties(true);\n\t\t\tversions.setProperty(\"project.version\", resolvedBom.id().version());\n\t\t\tSet<String> versionProperties = Set.of(\"log4j2.version\", \"maven-jar-plugin.version\",\n\t\t\t\t\t\"maven-war-plugin.version\", \"build-helper-maven-plugin.version\", \"spring-framework.version\",\n\t\t\t\t\t\"jakarta-servlet.version\", \"kotlin.version\", \"assertj.version\", \"junit-jupiter.version\");\n\t\t\tfor (ResolvedLibrary library : resolvedBom.libraries()) {\n\t\t\t\tif (library.versionProperty() != null && versionProperties.contains(library.versionProperty())) {\n\t\t\t\t\tversions.setProperty(library.versionProperty(), library.version());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn versions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/PluginXmlParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.mavenplugin;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\n/**\n * A parser for a Maven plugin's {@code plugin.xml} file.\n *\n * @author Andy Wilkinson\n * @author Mike Smithson\n */\nclass PluginXmlParser {\n\n\tprivate final XPath xpath;\n\n\tPluginXmlParser() {\n\t\tthis.xpath = XPathFactory.newInstance().newXPath();\n\t}\n\n\tPlugin parse(File pluginXml) {\n\t\ttry {\n\t\t\tNode root = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pluginXml);\n\t\t\tList<Mojo> mojos = parseMojos(root);\n\t\t\treturn new Plugin(textAt(\"//plugin/groupId\", root), textAt(\"//plugin/artifactId\", root),\n\t\t\t\t\ttextAt(\"//plugin/version\", root), textAt(\"//plugin/goalPrefix\", root), mojos);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate String textAt(String path, Node source) throws XPathExpressionException {\n\t\tString text = this.xpath.evaluate(path + \"/text()\", source);\n\t\treturn text.isEmpty() ? null : text;\n\t}\n\n\tprivate List<Mojo> parseMojos(Node plugin) throws XPathExpressionException {\n\t\tList<Mojo> mojos = new ArrayList<>();\n\t\tfor (Node mojoNode : nodesAt(\"//plugin/mojos/mojo\", plugin)) {\n\t\t\tmojos.add(new Mojo(textAt(\"goal\", mojoNode), format(textAt(\"description\", mojoNode)),\n\t\t\t\t\tparseParameters(mojoNode)));\n\t\t}\n\t\treturn mojos;\n\t}\n\n\tprivate Iterable<Node> nodesAt(String path, Node source) throws XPathExpressionException {\n\t\treturn IterableNodeList.of((NodeList) this.xpath.evaluate(path, source, XPathConstants.NODESET));\n\t}\n\n\tprivate List<Parameter> parseParameters(Node mojoNode) throws XPathExpressionException {\n\t\tMap<String, String> defaultValues = new HashMap<>();\n\t\tMap<String, String> userProperties = new HashMap<>();\n\t\tfor (Node parameterConfigurationNode : nodesAt(\"configuration/*\", mojoNode)) {\n\t\t\tString userProperty = parameterConfigurationNode.getTextContent();\n\t\t\tif (userProperty != null && !userProperty.isEmpty()) {\n\t\t\t\tuserProperties.put(parameterConfigurationNode.getNodeName(),\n\t\t\t\t\t\tuserProperty.replace(\"${\", \"`\").replace(\"}\", \"`\"));\n\t\t\t}\n\t\t\tNode defaultValueAttribute = parameterConfigurationNode.getAttributes().getNamedItem(\"default-value\");\n\t\t\tif (defaultValueAttribute != null && !defaultValueAttribute.getTextContent().isEmpty()) {\n\t\t\t\tdefaultValues.put(parameterConfigurationNode.getNodeName(), defaultValueAttribute.getTextContent());\n\t\t\t}\n\t\t}\n\t\tList<Parameter> parameters = new ArrayList<>();\n\t\tfor (Node parameterNode : nodesAt(\"parameters/parameter\", mojoNode)) {\n\t\t\tparameters.add(parseParameter(parameterNode, defaultValues, userProperties));\n\t\t}\n\t\treturn parameters;\n\t}\n\n\tprivate Parameter parseParameter(Node parameterNode, Map<String, String> defaultValues,\n\t\t\tMap<String, String> userProperties) throws XPathExpressionException {\n\t\tString description = textAt(\"description\", parameterNode);\n\t\treturn new Parameter(textAt(\"name\", parameterNode), textAt(\"type\", parameterNode),\n\t\t\t\tbooleanAt(\"required\", parameterNode), booleanAt(\"editable\", parameterNode),\n\t\t\t\t(description != null) ? format(description) : \"\", defaultValues.get(textAt(\"name\", parameterNode)),\n\t\t\t\tuserProperties.get(textAt(\"name\", parameterNode)), textAt(\"since\", parameterNode));\n\t}\n\n\tprivate boolean booleanAt(String path, Node node) throws XPathExpressionException {\n\t\treturn Boolean.parseBoolean(textAt(path, node));\n\t}\n\n\tprivate String format(String input) {\n\t\treturn input.replace(\"<code>\", \"`\")\n\t\t\t.replace(\"</code>\", \"`\")\n\t\t\t.replace(\"&lt;\", \"<\")\n\t\t\t.replace(\"&gt;\", \">\")\n\t\t\t.replace(\"<br>\", \" \")\n\t\t\t.replace(\"<p>\", \" \")\n\t\t\t.replace(\"\\n\", \" \")\n\t\t\t.replace(\"&quot;\", \"\\\"\")\n\t\t\t.replaceAll(\"\\\\{@code (.*?)}\", \"`$1`\")\n\t\t\t.replaceAll(\"\\\\{@link (.*?)}\", \"`$1`\")\n\t\t\t.replaceAll(\"\\\\{@literal (.*?)}\", \"`$1`\")\n\t\t\t.replaceAll(\"<a href=.\\\"(.*?)\\\".>(.*?)</a>\", \"$1[$2]\");\n\t}\n\n\tprivate static final class IterableNodeList implements Iterable<Node> {\n\n\t\tprivate final NodeList nodeList;\n\n\t\tprivate IterableNodeList(NodeList nodeList) {\n\t\t\tthis.nodeList = nodeList;\n\t\t}\n\n\t\tprivate static Iterable<Node> of(NodeList nodeList) {\n\t\t\treturn new IterableNodeList(nodeList);\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<Node> iterator() {\n\n\t\t\treturn new Iterator<>() {\n\n\t\t\t\tprivate int index;\n\n\t\t\t\t@Override\n\t\t\t\tpublic boolean hasNext() {\n\t\t\t\t\treturn this.index < IterableNodeList.this.nodeList.getLength();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Node next() {\n\t\t\t\t\treturn IterableNodeList.this.nodeList.item(this.index++);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic final class Plugin {\n\n\t\tprivate final String groupId;\n\n\t\tprivate final String artifactId;\n\n\t\tprivate final String version;\n\n\t\tprivate final String goalPrefix;\n\n\t\tprivate final List<Mojo> mojos;\n\n\t\tprivate Plugin(String groupId, String artifactId, String version, String goalPrefix, List<Mojo> mojos) {\n\t\t\tthis.groupId = groupId;\n\t\t\tthis.artifactId = artifactId;\n\t\t\tthis.version = version;\n\t\t\tthis.goalPrefix = goalPrefix;\n\t\t\tthis.mojos = mojos;\n\t\t}\n\n\t\tString getGroupId() {\n\t\t\treturn this.groupId;\n\t\t}\n\n\t\tString getArtifactId() {\n\t\t\treturn this.artifactId;\n\t\t}\n\n\t\tString getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\tString getGoalPrefix() {\n\t\t\treturn this.goalPrefix;\n\t\t}\n\n\t\tList<Mojo> getMojos() {\n\t\t\treturn this.mojos;\n\t\t}\n\n\t}\n\n\tstatic final class Mojo {\n\n\t\tprivate final String goal;\n\n\t\tprivate final String description;\n\n\t\tprivate final List<Parameter> parameters;\n\n\t\tprivate Mojo(String goal, String description, List<Parameter> parameters) {\n\t\t\tthis.goal = goal;\n\t\t\tthis.description = description;\n\t\t\tthis.parameters = parameters;\n\t\t}\n\n\t\tString getGoal() {\n\t\t\treturn this.goal;\n\t\t}\n\n\t\tString getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tList<Parameter> getParameters() {\n\t\t\treturn this.parameters;\n\t\t}\n\n\t}\n\n\tstatic final class Parameter {\n\n\t\tprivate final String name;\n\n\t\tprivate final String type;\n\n\t\tprivate final boolean required;\n\n\t\tprivate final boolean editable;\n\n\t\tprivate final String description;\n\n\t\tprivate final String defaultValue;\n\n\t\tprivate final String userProperty;\n\n\t\tprivate final String since;\n\n\t\tprivate Parameter(String name, String type, boolean required, boolean editable, String description,\n\t\t\t\tString defaultValue, String userProperty, String since) {\n\t\t\tthis.name = name;\n\t\t\tthis.type = type;\n\t\t\tthis.required = required;\n\t\t\tthis.editable = editable;\n\t\t\tthis.description = description;\n\t\t\tthis.defaultValue = defaultValue;\n\t\t\tthis.userProperty = userProperty;\n\t\t\tthis.since = since;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tString getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tboolean isRequired() {\n\t\t\treturn this.required;\n\t\t}\n\n\t\tboolean isEditable() {\n\t\t\treturn this.editable;\n\t\t}\n\n\t\tString getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tString getDefaultValue() {\n\t\t\treturn this.defaultValue;\n\t\t}\n\n\t\tString getUserProperty() {\n\t\t\treturn this.userProperty;\n\t\t}\n\n\t\tString getSince() {\n\t\t\treturn this.since;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/PrepareMavenBinaries.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.mavenplugin;\n\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.artifacts.dsl.DependencyHandler;\nimport org.gradle.api.file.ArchiveOperations;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileSystemOperations;\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.provider.SetProperty;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.TaskAction;\n\n/**\n * {@link Task} to make Maven binaries available for integration testing.\n *\n * @author Andy Wilkinson\n */\npublic abstract class PrepareMavenBinaries extends DefaultTask {\n\n\tprivate final FileSystemOperations fileSystemOperations;\n\n\tprivate final Provider<Set<FileTree>> binaries;\n\n\t@Inject\n\tpublic PrepareMavenBinaries(FileSystemOperations fileSystemOperations, ArchiveOperations archiveOperations) {\n\t\tthis.fileSystemOperations = fileSystemOperations;\n\t\tConfigurationContainer configurations = getProject().getConfigurations();\n\t\tDependencyHandler dependencies = getProject().getDependencies();\n\t\tthis.binaries = getVersions().map((versions) -> versions.stream()\n\t\t\t.map((version) -> configurations\n\t\t\t\t.detachedConfiguration(dependencies.create(\"org.apache.maven:apache-maven:\" + version + \":bin@zip\")))\n\t\t\t.map(Configuration::getSingleFile)\n\t\t\t.map(archiveOperations::zipTree)\n\t\t\t.collect(Collectors.toSet()));\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDir();\n\n\t@Input\n\tpublic abstract SetProperty<String> getVersions();\n\n\t@TaskAction\n\tpublic void prepareBinaries() {\n\t\tthis.fileSystemOperations.sync((sync) -> {\n\t\t\tsync.into(getOutputDir());\n\t\t\tthis.binaries.get().forEach(sync::from);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/optional/OptionalDependenciesPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.optional;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.tasks.SourceSetContainer;\n\n/**\n * A {@code Plugin} that adds support for Maven-style optional dependencies. Creates a new\n * {@code optional} configuration. The {@code optional} configuration is part of the\n * project's compile and runtime classpaths but does not affect the classpath of dependent\n * projects.\n *\n * @author Andy Wilkinson\n */\npublic class OptionalDependenciesPlugin implements Plugin<Project> {\n\n\t/**\n\t * Name of the {@code optional} configuration.\n\t */\n\tpublic static final String OPTIONAL_CONFIGURATION_NAME = \"optional\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tConfiguration optional = project.getConfigurations().create(\"optional\");\n\t\toptional.setCanBeConsumed(true);\n\t\toptional.setCanBeResolved(false);\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {\n\t\t\tSourceSetContainer sourceSets = project.getExtensions()\n\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t.getSourceSets();\n\t\t\tsourceSets.all((sourceSet) -> {\n\t\t\t\tproject.getConfigurations()\n\t\t\t\t\t.getByName(sourceSet.getCompileClasspathConfigurationName())\n\t\t\t\t\t.extendsFrom(optional);\n\t\t\t\tproject.getConfigurations()\n\t\t\t\t\t.getByName(sourceSet.getRuntimeClasspathConfigurationName())\n\t\t\t\t\t.extendsFrom(optional);\n\t\t\t});\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/processors/AnnotationProcessorPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.processors;\n\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.tasks.bundling.Jar;\n\n/**\n * A {@link Plugin} for an annotation processor project.\n *\n * @author Christoph Dreis\n */\npublic class AnnotationProcessorPlugin implements Plugin<Project> {\n\n\tprivate static final String JAR_TYPE = \"annotation-processor\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getTasks().withType(Jar.class, (jar) -> project.afterEvaluate((evaluated) -> {\n\t\t\tjar.manifest((manifest) -> {\n\t\t\t\tMap<String, Object> attributes = new TreeMap<>();\n\t\t\t\tattributes.put(\"Spring-Boot-Jar-Type\", JAR_TYPE);\n\t\t\t\tmanifest.attributes(attributes);\n\t\t\t});\n\t\t}));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/properties/BuildProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.properties;\n\nimport org.gradle.api.Project;\n\n/**\n * Properties that can influence the build.\n *\n * @param buildType the build type\n * @param gitHub GitHub details\n * @author Phillip Webb\n */\npublic record BuildProperties(BuildType buildType, GitHub gitHub) {\n\n\tprivate static final String PROPERTY_NAME = BuildProperties.class.getName();\n\n\t/**\n\t * Get the {@link BuildProperties} for the given {@link Project}.\n\t * @param project the source project\n\t * @return the build properties\n\t */\n\tpublic static BuildProperties get(Project project) {\n\t\tBuildProperties buildProperties = (BuildProperties) project.findProperty(PROPERTY_NAME);\n\t\tif (buildProperties == null) {\n\t\t\tbuildProperties = load(project);\n\t\t\tproject.getExtensions().getExtraProperties().set(PROPERTY_NAME, buildProperties);\n\t\t}\n\t\treturn buildProperties;\n\t}\n\n\tprivate static BuildProperties load(Project project) {\n\t\tBuildType buildType = buildType(project.findProperty(\"spring.build-type\"));\n\t\treturn switch (buildType) {\n\t\t\tcase OPEN_SOURCE -> new BuildProperties(buildType, GitHub.OPEN_SOURCE);\n\t\t\tcase COMMERCIAL -> new BuildProperties(buildType, GitHub.COMMERCIAL);\n\t\t};\n\t}\n\n\tprivate static BuildType buildType(Object value) {\n\t\tif (value == null || \"oss\".equals(value.toString())) {\n\t\t\treturn BuildType.OPEN_SOURCE;\n\t\t}\n\t\tif (\"commercial\".equals(value.toString())) {\n\t\t\treturn BuildType.COMMERCIAL;\n\t\t}\n\t\tthrow new IllegalStateException(\"Unknown build type property '\" + value + \"'\");\n\t}\n\n\t/**\n\t * GitHub properties.\n\t *\n\t * @param organization the GitHub organization\n\t * @param repository the GitHub repository\n\t */\n\tpublic record GitHub(String organization, String repository) {\n\n\t\tstatic final GitHub OPEN_SOURCE = new GitHub(\"spring-projects\", \"spring-boot\");\n\n\t\tstatic final GitHub COMMERCIAL = new GitHub(\"spring-projects\", \"spring-boot-commercial\");\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/properties/BuildType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.properties;\n\nimport java.util.Locale;\n\n/**\n * The type of build being performed.\n *\n * @author Phillip Webb\n */\npublic enum BuildType {\n\n\t/**\n\t * An open source build.\n\t */\n\tOPEN_SOURCE,\n\n\t/**\n\t * A commercial build.\n\t */\n\tCOMMERCIAL;\n\n\tpublic String toIdentifier() {\n\t\treturn toString().replace(\"_\", \"\").toLowerCase(Locale.ROOT);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/springframework/CheckAotFactories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.springframework;\n\nimport org.gradle.api.Task;\n\n/**\n * {@link Task} that checks {@code META-INF/spring/aot.factories}.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckAotFactories extends CheckFactoriesFile {\n\n\tpublic CheckAotFactories() {\n\t\tsuper(\"META-INF/spring/aot.factories\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/springframework/CheckFactoriesFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.springframework;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SkipWhenEmpty;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\n\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Task} that checks files loaded by {@link SpringFactoriesLoader}.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckFactoriesFile extends DefaultTask {\n\n\tprivate final String path;\n\n\tprivate FileCollection sourceFiles = getProject().getObjects().fileCollection();\n\n\tprivate FileCollection classpath = getProject().getObjects().fileCollection();\n\n\tprotected CheckFactoriesFile(String path) {\n\t\tthis.path = path;\n\t\tgetOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));\n\t\tsetGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t}\n\n\t@InputFiles\n\t@SkipWhenEmpty\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileTree getSource() {\n\t\treturn this.sourceFiles.getAsFileTree().matching((filter) -> filter.include(this.path));\n\t}\n\n\tpublic void setSource(Object source) {\n\t\tthis.sourceFiles = getProject().getObjects().fileCollection().from(source);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(Object classpath) {\n\t\tthis.classpath = getProject().getObjects().fileCollection().from(classpath);\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@TaskAction\n\tvoid execute() {\n\t\tgetSource().forEach(this::check);\n\t}\n\n\tprivate void check(File factoriesFile) {\n\t\tProperties properties = load(factoriesFile);\n\t\tMap<String, List<String>> problems = new LinkedHashMap<>();\n\t\tfor (String name : properties.stringPropertyNames()) {\n\t\t\tString value = properties.getProperty(name);\n\t\t\tList<String> classNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray(value));\n\t\t\tcollectProblems(problems, name, classNames);\n\t\t\tList<String> sortedValues = new ArrayList<>(classNames);\n\t\t\tCollections.sort(sortedValues);\n\t\t\tif (!sortedValues.equals(classNames)) {\n\t\t\t\tList<String> problemsForClassName = problems.computeIfAbsent(name, (k) -> new ArrayList<>());\n\t\t\t\tproblemsForClassName.add(\"Entries should be sorted alphabetically\");\n\t\t\t}\n\t\t}\n\t\tFile outputFile = getOutputDirectory().file(\"failure-report.txt\").get().getAsFile();\n\t\twriteReport(factoriesFile, problems, outputFile);\n\t\tif (!problems.isEmpty()) {\n\t\t\tthrow new VerificationException(\"%s check failed. See '%s' for details\".formatted(this.path, outputFile));\n\t\t}\n\t}\n\n\tprivate void collectProblems(Map<String, List<String>> problems, String key, List<String> classNames) {\n\t\tfor (String className : classNames) {\n\t\t\tif (!find(className)) {\n\t\t\t\taddNoFoundProblem(className, problems.computeIfAbsent(key, (k) -> new ArrayList<>()));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addNoFoundProblem(String className, List<String> problemsForClassName) {\n\t\tString binaryName = binaryNameOf(className);\n\t\tboolean foundBinaryForm = find(binaryName);\n\t\tproblemsForClassName.add(!foundBinaryForm ? \"'%s' was not found\".formatted(className)\n\t\t\t\t: \"'%s' should be listed using its binary name '%s'\".formatted(className, binaryName));\n\t}\n\n\tprivate boolean find(String className) {\n\t\tfor (File root : this.classpath.getFiles()) {\n\t\t\tString classFilePath = className.replace(\".\", \"/\") + \".class\";\n\t\t\tif (new File(root, classFilePath).isFile()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate String binaryNameOf(String className) {\n\t\tint lastDotIndex = className.lastIndexOf('.');\n\t\treturn className.substring(0, lastDotIndex) + \"$\" + className.substring(lastDotIndex + 1);\n\t}\n\n\tprivate Properties load(File aotFactories) {\n\t\tProperties properties = new Properties();\n\t\ttry (FileInputStream input = new FileInputStream(aotFactories)) {\n\t\t\tproperties.load(input);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate void writeReport(File factoriesFile, Map<String, List<String>> problems, File outputFile) {\n\t\toutputFile.getParentFile().mkdirs();\n\t\tStringBuilder report = new StringBuilder();\n\t\tif (!problems.isEmpty()) {\n\t\t\treport.append(\"Found problems in '%s':%n\".formatted(factoriesFile));\n\t\t\tproblems.forEach((key, problemsForKey) -> {\n\t\t\t\treport.append(\"  - %s:%n\".formatted(key));\n\t\t\t\tproblemsForKey.forEach((problem) -> report.append(\"    - %s%n\".formatted(problem)));\n\t\t\t});\n\t\t}\n\t\ttry {\n\t\t\tFiles.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,\n\t\t\t\t\tStandardOpenOption.TRUNCATE_EXISTING);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/springframework/CheckSpringFactories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.springframework;\n\nimport org.gradle.api.Task;\n\n/**\n * {@link Task} that checks {@code META-INF/spring.factories}.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckSpringFactories extends CheckFactoriesFile {\n\n\tpublic CheckSpringFactories() {\n\t\tsuper(\"META-INF/spring.factories\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/starters/DocumentStarters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.starters;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Task} to document all starter projects.\n *\n * @author Andy Wilkinson\n */\npublic abstract class DocumentStarters extends DefaultTask {\n\n\tprivate final Configuration starters;\n\n\tpublic DocumentStarters() {\n\t\tthis.starters = getProject().getConfigurations().create(\"starters\");\n\t\tgetProject().getGradle().projectsEvaluated((gradle) -> {\n\t\t\tgradle.allprojects((project) -> {\n\t\t\t\tif (project.getPlugins().hasPlugin(StarterPlugin.class)) {\n\t\t\t\t\tMap<String, String> dependency = new HashMap<>();\n\t\t\t\t\tdependency.put(\"path\", project.getPath());\n\t\t\t\t\tdependency.put(\"configuration\", \"starterMetadata\");\n\t\t\t\t\tthis.starters.getDependencies().add(project.getDependencies().project(dependency));\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDir();\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getStarters() {\n\t\treturn this.starters;\n\t}\n\n\t@TaskAction\n\tvoid documentStarters() {\n\t\tSet<Starter> starters = this.starters.getFiles()\n\t\t\t.stream()\n\t\t\t.map(this::loadStarter)\n\t\t\t.collect(Collectors.toCollection(TreeSet::new));\n\t\twriteTable(\"application-starters\", starters.stream().filter(Starter::isApplication));\n\t\twriteTable(\"production-starters\", starters.stream().filter(Starter::isProduction));\n\t\twriteTable(\"technical-starters\", starters.stream().filter(Starter::isTechnical));\n\t}\n\n\tprivate Starter loadStarter(File metadata) {\n\t\tProperties properties = new Properties();\n\t\ttry (FileReader reader = new FileReader(metadata)) {\n\t\t\tproperties.load(reader);\n\t\t\treturn new Starter(properties.getProperty(\"name\"), properties.getProperty(\"description\"),\n\t\t\t\t\tStringUtils.commaDelimitedListToSet(properties.getProperty(\"dependencies\")));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void writeTable(String name, Stream<Starter> starters) {\n\t\tFile output = new File(getOutputDir().getAsFile().get(), name + \".adoc\");\n\t\toutput.getParentFile().mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(output))) {\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"| Name | Description\");\n\t\t\tstarters.forEach((starter) -> {\n\t\t\t\twriter.println();\n\t\t\t\twriter.printf(\"| [[%s]]`%s`%n\", starter.name, starter.name);\n\t\t\t\twriter.printf(\"| %s%n\", postProcessDescription(starter.description));\n\t\t\t});\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate String postProcessDescription(String description) {\n\t\treturn addStarterCrossLinks(description);\n\t}\n\n\tprivate String addStarterCrossLinks(String input) {\n\t\treturn input.replaceAll(\"(spring-boot-starter[A-Za-z0-9-]*)\", \"xref:#$1[`$1`]\");\n\t}\n\n\tprivate static final class Starter implements Comparable<Starter> {\n\n\t\tprivate final String name;\n\n\t\tprivate final String description;\n\n\t\tprivate final Set<String> dependencies;\n\n\t\tprivate Starter(String name, String description, Set<String> dependencies) {\n\t\t\tthis.name = name;\n\t\t\tthis.description = description;\n\t\t\tthis.dependencies = dependencies;\n\t\t}\n\n\t\tprivate boolean isProduction() {\n\t\t\treturn this.name.equals(\"spring-boot-starter-actuator\");\n\t\t}\n\n\t\tprivate boolean isTechnical() {\n\t\t\treturn !Arrays.asList(\"spring-boot-starter\", \"spring-boot-starter-test\").contains(this.name)\n\t\t\t\t\t&& !isProduction() && !this.dependencies.contains(\"spring-boot-starter\");\n\t\t}\n\n\t\tprivate boolean isApplication() {\n\t\t\treturn !isProduction() && !isTechnical();\n\t\t}\n\n\t\t@Override\n\t\tpublic int compareTo(Starter other) {\n\t\t\treturn this.name.compareTo(other.name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/starters/StarterMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.starters;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.Properties;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ResolvedArtifact;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.core.CollectionFactory;\n\n/**\n * A {@link Task} for generating metadata that describes a starter.\n *\n * @author Andy Wilkinson\n */\npublic abstract class StarterMetadata extends DefaultTask {\n\n\tprivate Configuration dependencies;\n\n\tpublic StarterMetadata() {\n\t\tProject project = getProject();\n\t\tgetStarterName().convention(project.provider(project::getName));\n\t\tgetStarterDescription().convention(project.provider(project::getDescription));\n\t}\n\n\t@Input\n\tpublic abstract Property<String> getStarterName();\n\n\t@Input\n\tpublic abstract Property<String> getStarterDescription();\n\n\t@Classpath\n\tpublic FileCollection getDependencies() {\n\t\treturn this.dependencies;\n\t}\n\n\tpublic void setDependencies(Configuration dependencies) {\n\t\tthis.dependencies = dependencies;\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getDestination();\n\n\t@TaskAction\n\tvoid generateMetadata() throws IOException {\n\t\tProperties properties = CollectionFactory.createSortedProperties(true);\n\t\tproperties.setProperty(\"name\", getStarterName().get());\n\t\tproperties.setProperty(\"description\", getStarterDescription().get());\n\t\tproperties.setProperty(\"dependencies\",\n\t\t\t\tString.join(\",\",\n\t\t\t\t\t\tthis.dependencies.getResolvedConfiguration()\n\t\t\t\t\t\t\t.getResolvedArtifacts()\n\t\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t\t.map(ResolvedArtifact::getName)\n\t\t\t\t\t\t\t.collect(Collectors.toSet())));\n\t\tFile destination = getDestination().getAsFile().get();\n\t\tdestination.getParentFile().mkdirs();\n\t\ttry (FileWriter writer = new FileWriter(destination)) {\n\t\t\tproperties.store(writer, null);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/starters/StarterPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.starters;\n\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.artifacts.Configuration;\nimport org.gradle.api.artifacts.ConfigurationContainer;\nimport org.gradle.api.file.RegularFile;\nimport org.gradle.api.plugins.JavaBasePlugin;\nimport org.gradle.api.plugins.JavaLibraryPlugin;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.PluginContainer;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.bundling.Jar;\n\nimport org.springframework.boot.build.ConventionsPlugin;\nimport org.springframework.boot.build.DeployedPlugin;\nimport org.springframework.boot.build.classpath.CheckClasspathForConflicts;\nimport org.springframework.boot.build.classpath.CheckClasspathForUnconstrainedDirectDependencies;\nimport org.springframework.boot.build.classpath.CheckClasspathForUnnecessaryExclusions;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link Plugin} for a starter project.\n *\n * @author Andy Wilkinson\n */\npublic class StarterPlugin implements Plugin<Project> {\n\n\tprivate static final String JAR_TYPE = \"dependencies-starter\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tPluginContainer plugins = project.getPlugins();\n\t\tplugins.apply(DeployedPlugin.class);\n\t\tplugins.apply(JavaLibraryPlugin.class);\n\t\tplugins.apply(ConventionsPlugin.class);\n\t\tConfigurationContainer configurations = project.getConfigurations();\n\t\tConfiguration runtimeClasspath = configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);\n\t\tTaskProvider<StarterMetadata> starterMetadata = project.getTasks()\n\t\t\t.register(\"starterMetadata\", StarterMetadata.class, (task) -> {\n\t\t\t\ttask.setDependencies(runtimeClasspath);\n\t\t\t\tProvider<RegularFile> destination = project.getLayout()\n\t\t\t\t\t.getBuildDirectory()\n\t\t\t\t\t.file(\"starter-metadata.properties\");\n\t\t\t\ttask.getDestination().set(destination);\n\t\t\t});\n\t\tconfigurations.create(\"starterMetadata\");\n\t\tproject.getArtifacts()\n\t\t\t.add(\"starterMetadata\", starterMetadata.map(StarterMetadata::getDestination),\n\t\t\t\t\t(artifact) -> artifact.builtBy(starterMetadata));\n\t\tcreateClasspathConflictsCheck(runtimeClasspath, project);\n\t\tcreateUnnecessaryExclusionsCheck(runtimeClasspath, project);\n\t\tcreateUnconstrainedDirectDependenciesCheck(runtimeClasspath, project);\n\t\tconfigureJarManifest(project);\n\t}\n\n\tprivate void createClasspathConflictsCheck(Configuration classpath, Project project) {\n\t\tTaskProvider<CheckClasspathForConflicts> checkClasspathForConflicts = project.getTasks()\n\t\t\t.register(\"check\" + StringUtils.capitalize(classpath.getName() + \"ForConflicts\"),\n\t\t\t\t\tCheckClasspathForConflicts.class, (task) -> task.setClasspath(classpath));\n\t\tproject.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForConflicts);\n\t}\n\n\tprivate void createUnnecessaryExclusionsCheck(Configuration classpath, Project project) {\n\t\tTaskProvider<CheckClasspathForUnnecessaryExclusions> checkClasspathForUnnecessaryExclusions = project.getTasks()\n\t\t\t.register(\"check\" + StringUtils.capitalize(classpath.getName() + \"ForUnnecessaryExclusions\"),\n\t\t\t\t\tCheckClasspathForUnnecessaryExclusions.class, (task) -> task.setClasspath(classpath));\n\t\tproject.getTasks().getByName(JavaBasePlugin.CHECK_TASK_NAME).dependsOn(checkClasspathForUnnecessaryExclusions);\n\t}\n\n\tprivate void createUnconstrainedDirectDependenciesCheck(Configuration classpath, Project project) {\n\t\tTaskProvider<CheckClasspathForUnconstrainedDirectDependencies> checkClasspathForUnconstrainedDirectDependencies = project\n\t\t\t.getTasks()\n\t\t\t.register(\"check\" + StringUtils.capitalize(classpath.getName() + \"ForUnconstrainedDirectDependencies\"),\n\t\t\t\t\tCheckClasspathForUnconstrainedDirectDependencies.class, (task) -> task.setClasspath(classpath));\n\t\tproject.getTasks()\n\t\t\t.getByName(JavaBasePlugin.CHECK_TASK_NAME)\n\t\t\t.dependsOn(checkClasspathForUnconstrainedDirectDependencies);\n\t}\n\n\tprivate void configureJarManifest(Project project) {\n\t\tproject.getTasks().withType(Jar.class, (jar) -> project.afterEvaluate((evaluated) -> {\n\t\t\tjar.manifest((manifest) -> {\n\t\t\t\tMap<String, Object> attributes = new TreeMap<>();\n\t\t\t\tattributes.put(\"Spring-Boot-Jar-Type\", JAR_TYPE);\n\t\t\t\tmanifest.attributes(attributes);\n\t\t\t});\n\t\t}));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestBuildService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.services.BuildService;\nimport org.gradle.api.services.BuildServiceParameters;\n\n/**\n * Build service for Docker-based tests. The maximum number of {@code dockerTest} tasks\n * that can run in parallel can be configured using\n * {@code org.springframework.boot.dockertest.max-parallel-tasks}. By default, only a\n * single {@code dockerTest} task will run at a time.\n *\n * @author Andy Wilkinson\n */\nabstract class DockerTestBuildService implements BuildService<BuildServiceParameters.None> {\n\n\tstatic Provider<DockerTestBuildService> registerIfNecessary(Project project) {\n\t\treturn project.getGradle()\n\t\t\t.getSharedServices()\n\t\t\t.registerIfAbsent(\"dockerTest\", DockerTestBuildService.class,\n\t\t\t\t\t(spec) -> spec.getMaxParallelUsages().set(maxParallelTasks(project)));\n\t}\n\n\tprivate static int maxParallelTasks(Project project) {\n\t\tObject property = project.findProperty(\"org.springframework.boot.dockertest.max-parallel-tasks\");\n\t\tif (property == null) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn Integer.parseInt(property.toString());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/DockerTestPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.services.BuildService;\nimport org.gradle.api.tasks.Exec;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\nimport org.gradle.plugins.ide.eclipse.EclipsePlugin;\nimport org.gradle.plugins.ide.eclipse.model.EclipseModel;\n\n/**\n * Plugin for Docker-based tests. Creates a {@link SourceSet source set}, {@link Test\n * test} task, and {@link BuildService shared service} named {@code dockerTest}. The build\n * service is configured to only allow serial usage and the {@code dockerTest} task is\n * configured to use the build service. In a parallel build, this ensures that only a\n * single {@code dockerTest} task can run at any given time.\n *\n * @author Andy Wilkinson\n */\npublic class DockerTestPlugin implements Plugin<Project> {\n\n\t/**\n\t * Name of the {@code dockerTest} task.\n\t */\n\tpublic static final String DOCKER_TEST_TASK_NAME = \"dockerTest\";\n\n\t/**\n\t * Name of the {@code dockerTest} source set.\n\t */\n\tpublic static final String DOCKER_TEST_SOURCE_SET_NAME = \"dockerTest\";\n\n\t/**\n\t * Name of the {@code dockerTest} shared service.\n\t */\n\tpublic static final String DOCKER_TEST_SERVICE_NAME = \"dockerTest\";\n\n\tprivate static final String RECLAIM_DOCKER_SPACE_TASK_NAME = \"reclaimDockerSpace\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> configureDockerTesting(project));\n\t}\n\n\tprivate void configureDockerTesting(Project project) {\n\t\tProvider<DockerTestBuildService> buildService = DockerTestBuildService.registerIfNecessary(project);\n\t\tSourceSet dockerTestSourceSet = createSourceSet(project);\n\t\tProvider<Test> dockerTest = createTestTask(project, dockerTestSourceSet, buildService);\n\t\tproject.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(dockerTest);\n\t\tproject.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> {\n\t\t\tEclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);\n\t\t\teclipse.classpath((classpath) -> classpath.getPlusConfigurations()\n\t\t\t\t.add(project.getConfigurations()\n\t\t\t\t\t.getByName(dockerTestSourceSet.getRuntimeClasspathConfigurationName())));\n\t\t});\n\t\tproject.getDependencies()\n\t\t\t.add(dockerTestSourceSet.getRuntimeOnlyConfigurationName(), \"org.junit.platform:junit-platform-launcher\");\n\t\tProvider<Exec> reclaimDockerSpace = createReclaimDockerSpaceTask(project, buildService);\n\t\tproject.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(reclaimDockerSpace);\n\t}\n\n\tprivate SourceSet createSourceSet(Project project) {\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();\n\t\tSourceSet dockerTestSourceSet = sourceSets.create(DOCKER_TEST_SOURCE_SET_NAME);\n\t\tSourceSet main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tSourceSet test = sourceSets.getByName(SourceSet.TEST_SOURCE_SET_NAME);\n\t\tdockerTestSourceSet.setCompileClasspath(dockerTestSourceSet.getCompileClasspath()\n\t\t\t.plus(main.getOutput())\n\t\t\t.plus(main.getCompileClasspath())\n\t\t\t.plus(test.getOutput()));\n\t\tdockerTestSourceSet.setRuntimeClasspath(dockerTestSourceSet.getRuntimeClasspath()\n\t\t\t.plus(main.getOutput())\n\t\t\t.plus(main.getRuntimeClasspath())\n\t\t\t.plus(test.getOutput()));\n\t\tproject.getPlugins().withType(IntegrationTestPlugin.class, (integrationTestPlugin) -> {\n\t\t\tSourceSet intTest = sourceSets.getByName(IntegrationTestPlugin.INT_TEST_SOURCE_SET_NAME);\n\t\t\tdockerTestSourceSet\n\t\t\t\t.setCompileClasspath(dockerTestSourceSet.getCompileClasspath().plus(intTest.getOutput()));\n\t\t\tdockerTestSourceSet\n\t\t\t\t.setRuntimeClasspath(dockerTestSourceSet.getRuntimeClasspath().plus(intTest.getOutput()));\n\t\t});\n\t\treturn dockerTestSourceSet;\n\t}\n\n\tprivate Provider<Test> createTestTask(Project project, SourceSet dockerTestSourceSet,\n\t\t\tProvider<DockerTestBuildService> buildService) {\n\t\treturn project.getTasks().register(DOCKER_TEST_TASK_NAME, Test.class, (task) -> {\n\t\t\ttask.usesService(buildService);\n\t\t\ttask.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t\t\ttask.setDescription(\"Runs Docker-based tests.\");\n\t\t\ttask.setTestClassesDirs(dockerTestSourceSet.getOutput().getClassesDirs());\n\t\t\ttask.setClasspath(dockerTestSourceSet.getRuntimeClasspath());\n\t\t\ttask.shouldRunAfter(JavaPlugin.TEST_TASK_NAME);\n\t\t});\n\t}\n\n\tprivate Provider<Exec> createReclaimDockerSpaceTask(Project project,\n\t\t\tProvider<DockerTestBuildService> buildService) {\n\t\treturn project.getTasks().register(RECLAIM_DOCKER_SPACE_TASK_NAME, Exec.class, (task) -> {\n\t\t\ttask.usesService(buildService);\n\t\t\ttask.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t\t\ttask.setDescription(\"Reclaims Docker space on CI.\");\n\t\t\ttask.shouldRunAfter(DOCKER_TEST_TASK_NAME);\n\t\t\ttask.onlyIf(this::shouldReclaimDockerSpace);\n\t\t\ttask.executable(\"bash\");\n\t\t\ttask.args(\"-c\",\n\t\t\t\t\tproject.getRootDir()\n\t\t\t\t\t\t.toPath()\n\t\t\t\t\t\t.resolve(\".github/scripts/reclaim-docker-diskspace.sh\")\n\t\t\t\t\t\t.toAbsolutePath());\n\t\t});\n\t}\n\n\tprivate boolean shouldReclaimDockerSpace(Task task) {\n\t\tif (System.getProperty(\"os.name\").startsWith(\"Windows\")) {\n\t\t\treturn false;\n\t\t}\n\t\treturn System.getenv(\"GITHUB_ACTIONS\") != null || System.getenv(\"RECLAIM_DOCKER_SPACE\") != null;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/IntegrationTestPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\nimport org.gradle.plugins.ide.eclipse.EclipsePlugin;\nimport org.gradle.plugins.ide.eclipse.model.EclipseModel;\n\n/**\n * A {@link Plugin} to configure integration testing support in a {@link Project}.\n *\n * @author Andy Wilkinson\n */\npublic class IntegrationTestPlugin implements Plugin<Project> {\n\n\t/**\n\t * Name of the {@code intTest} task.\n\t */\n\tpublic static String INT_TEST_TASK_NAME = \"intTest\";\n\n\t/**\n\t * Name of the {@code intTest} source set.\n\t */\n\tpublic static String INT_TEST_SOURCE_SET_NAME = \"intTest\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> configureIntegrationTesting(project));\n\t}\n\n\tprivate void configureIntegrationTesting(Project project) {\n\t\tSourceSet intTestSourceSet = createSourceSet(project);\n\t\tTaskProvider<Test> intTest = createTestTask(project, intTestSourceSet);\n\t\tproject.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(intTest);\n\t\tproject.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> {\n\t\t\tEclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);\n\t\t\teclipse.classpath((classpath) -> classpath.getPlusConfigurations()\n\t\t\t\t.add(project.getConfigurations().getByName(intTestSourceSet.getRuntimeClasspathConfigurationName())));\n\t\t});\n\t\tproject.getDependencies()\n\t\t\t.add(intTestSourceSet.getRuntimeOnlyConfigurationName(), \"org.junit.platform:junit-platform-launcher\");\n\t}\n\n\tprivate SourceSet createSourceSet(Project project) {\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();\n\t\tSourceSet intTestSourceSet = sourceSets.create(INT_TEST_SOURCE_SET_NAME);\n\t\tSourceSet main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tintTestSourceSet.setCompileClasspath(intTestSourceSet.getCompileClasspath().plus(main.getOutput()));\n\t\tintTestSourceSet.setRuntimeClasspath(intTestSourceSet.getRuntimeClasspath().plus(main.getOutput()));\n\t\treturn intTestSourceSet;\n\t}\n\n\tprivate TaskProvider<Test> createTestTask(Project project, SourceSet intTestSourceSet) {\n\t\treturn project.getTasks().register(INT_TEST_TASK_NAME, Test.class, (task) -> {\n\t\t\ttask.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t\t\ttask.setDescription(\"Runs integration tests.\");\n\t\t\ttask.setTestClassesDirs(intTestSourceSet.getOutput().getClassesDirs());\n\t\t\ttask.setClasspath(intTestSourceSet.getRuntimeClasspath());\n\t\t\ttask.shouldRunAfter(JavaPlugin.TEST_TASK_NAME);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/SystemTestPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.specs.Spec;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.SourceSetContainer;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\nimport org.gradle.plugins.ide.eclipse.EclipsePlugin;\nimport org.gradle.plugins.ide.eclipse.model.EclipseModel;\n\n/**\n * A {@link Plugin} to configure system testing support in a {@link Project}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic class SystemTestPlugin implements Plugin<Project> {\n\n\tprivate static final Spec<Task> NEVER = (task) -> false;\n\n\t/**\n\t * Name of the {@code systemTest} task.\n\t */\n\tpublic static String SYSTEM_TEST_TASK_NAME = \"systemTest\";\n\n\t/**\n\t * Name of the {@code systemTest} source set.\n\t */\n\tpublic static String SYSTEM_TEST_SOURCE_SET_NAME = \"systemTest\";\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tproject.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> configureSystemTesting(project));\n\t}\n\n\tprivate void configureSystemTesting(Project project) {\n\t\tSourceSet systemTestSourceSet = createSourceSet(project);\n\t\tcreateTestTask(project, systemTestSourceSet);\n\t\tproject.getPlugins().withType(EclipsePlugin.class, (eclipsePlugin) -> {\n\t\t\tEclipseModel eclipse = project.getExtensions().getByType(EclipseModel.class);\n\t\t\teclipse.classpath((classpath) -> classpath.getPlusConfigurations()\n\t\t\t\t.add(project.getConfigurations()\n\t\t\t\t\t.getByName(systemTestSourceSet.getRuntimeClasspathConfigurationName())));\n\t\t});\n\t\tproject.getDependencies()\n\t\t\t.add(systemTestSourceSet.getRuntimeOnlyConfigurationName(), \"org.junit.platform:junit-platform-launcher\");\n\t}\n\n\tprivate SourceSet createSourceSet(Project project) {\n\t\tSourceSetContainer sourceSets = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets();\n\t\tSourceSet systemTestSourceSet = sourceSets.create(SYSTEM_TEST_SOURCE_SET_NAME);\n\t\tSourceSet mainSourceSet = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\tsystemTestSourceSet\n\t\t\t.setCompileClasspath(systemTestSourceSet.getCompileClasspath().plus(mainSourceSet.getOutput()));\n\t\tsystemTestSourceSet\n\t\t\t.setRuntimeClasspath(systemTestSourceSet.getRuntimeClasspath().plus(mainSourceSet.getOutput()));\n\t\treturn systemTestSourceSet;\n\t}\n\n\tprivate TaskProvider<Test> createTestTask(Project project, SourceSet systemTestSourceSet) {\n\t\treturn project.getTasks().register(SYSTEM_TEST_TASK_NAME, Test.class, (task) -> {\n\t\t\ttask.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t\t\ttask.setDescription(\"Runs system tests.\");\n\t\t\ttask.setTestClassesDirs(systemTestSourceSet.getOutput().getClassesDirs());\n\t\t\ttask.setClasspath(systemTestSourceSet.getRuntimeClasspath());\n\t\t\ttask.shouldRunAfter(JavaPlugin.TEST_TASK_NAME);\n\t\t\tif (isCi()) {\n\t\t\t\ttask.getOutputs().upToDateWhen(NEVER);\n\t\t\t\ttask.getOutputs().doNotCacheIf(\"System tests are always rerun on CI\", (spec) -> true);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate boolean isCi() {\n\t\treturn Boolean.parseBoolean(System.getenv(\"CI\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/CheckAutoConfigureImports.java",
    "content": "/*\n * Copyright 2025-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.function.Consumer;\nimport java.util.jar.JarFile;\nimport java.util.stream.Collectors;\nimport java.util.zip.ZipEntry;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.file.DirectoryProperty;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.FileTree;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputDirectory;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SkipWhenEmpty;\nimport org.gradle.api.tasks.TaskAction;\nimport org.gradle.api.tasks.VerificationException;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\n\nimport org.springframework.boot.build.autoconfigure.AutoConfigurationClass;\n\n/**\n * Task to check the contents of a project's\n * {@code META-INF/spring/*.AutoConfigure*.imports} files.\n *\n * @author Andy Wilkinson\n */\npublic abstract class CheckAutoConfigureImports extends DefaultTask {\n\n\tprivate FileCollection sourceFiles = getProject().getObjects().fileCollection();\n\n\tprivate FileCollection classpath = getProject().getObjects().fileCollection();\n\n\tpublic CheckAutoConfigureImports() {\n\t\tgetOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));\n\t\tsetGroup(LifecycleBasePlugin.VERIFICATION_GROUP);\n\t}\n\n\t@InputFiles\n\t@SkipWhenEmpty\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileTree getSource() {\n\t\treturn this.sourceFiles.getAsFileTree()\n\t\t\t.matching((filter) -> filter.include(\"META-INF/spring/*.AutoConfigure*.imports\"));\n\t}\n\n\tpublic void setSource(Object source) {\n\t\tthis.sourceFiles = getProject().getObjects().fileCollection().from(source);\n\t}\n\n\t@Classpath\n\tpublic FileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\tpublic void setClasspath(Object classpath) {\n\t\tthis.classpath = getProject().getObjects().fileCollection().from(classpath);\n\t}\n\n\t@OutputDirectory\n\tpublic abstract DirectoryProperty getOutputDirectory();\n\n\t@TaskAction\n\tvoid execute() {\n\t\tMap<String, List<String>> allProblems = new TreeMap<>();\n\t\tfor (AutoConfigureImports autoConfigureImports : loadImports()) {\n\t\t\tList<String> problems = new ArrayList<>();\n\t\t\tif (!find(autoConfigureImports.annotationName)) {\n\t\t\t\tproblems.add(\"Annotation '%s' was not found\".formatted(autoConfigureImports.annotationName));\n\t\t\t}\n\t\t\tfor (String imported : autoConfigureImports.imports) {\n\t\t\t\tString importedClassName = imported;\n\t\t\t\tif (importedClassName.startsWith(\"optional:\")) {\n\t\t\t\t\timportedClassName = importedClassName.substring(\"optional:\".length());\n\t\t\t\t}\n\t\t\t\tboolean found = find(importedClassName, (input) -> {\n\t\t\t\t\tif (!correctlyAnnotated(input)) {\n\t\t\t\t\t\tproblems.add(\"Imported auto-configuration '%s' is not annotated with @AutoConfiguration\"\n\t\t\t\t\t\t\t.formatted(imported));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tif (!found) {\n\t\t\t\t\tproblems.add(\"Imported auto-configuration '%s' was not found\".formatted(importedClassName));\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tList<String> sortedValues = new ArrayList<>(autoConfigureImports.imports);\n\t\t\tCollections.sort(sortedValues, (i1, i2) -> {\n\t\t\t\tboolean imported1 = i1.startsWith(\"optional:\");\n\t\t\t\tboolean imported2 = i2.startsWith(\"optional:\");\n\t\t\t\tint comparison = Boolean.compare(imported1, imported2);\n\t\t\t\tif (comparison != 0) {\n\t\t\t\t\treturn comparison;\n\t\t\t\t}\n\t\t\t\treturn i1.compareTo(i2);\n\t\t\t});\n\t\t\tif (!sortedValues.equals(autoConfigureImports.imports)) {\n\t\t\t\tFile sortedOutputFile = getOutputDirectory().file(\"sorted-\" + autoConfigureImports.fileName)\n\t\t\t\t\t.get()\n\t\t\t\t\t.getAsFile();\n\t\t\t\twriteString(sortedOutputFile, sortedValues.stream().collect(Collectors.joining(System.lineSeparator()))\n\t\t\t\t\t\t+ System.lineSeparator());\n\t\t\t\tproblems.add(\n\t\t\t\t\t\t\"Entries should be required then optional, each sorted alphabetically (expected content written to '%s')\"\n\t\t\t\t\t\t\t.formatted(sortedOutputFile.getAbsolutePath()));\n\t\t\t}\n\t\t\tif (!problems.isEmpty()) {\n\t\t\t\tallProblems.computeIfAbsent(autoConfigureImports.fileName, (unused) -> new ArrayList<>())\n\t\t\t\t\t.addAll(problems);\n\t\t\t}\n\t\t}\n\t\tFile outputFile = getOutputDirectory().file(\"failure-report.txt\").get().getAsFile();\n\t\twriteReport(allProblems, outputFile);\n\t\tif (!allProblems.isEmpty()) {\n\t\t\tthrow new VerificationException(\n\t\t\t\t\t\"AutoConfigure….imports checks failed. See '%s' for details\".formatted(outputFile));\n\t\t}\n\t}\n\n\tprivate List<AutoConfigureImports> loadImports() {\n\t\treturn getSource().getFiles().stream().map((file) -> {\n\t\t\tString fileName = file.getName();\n\t\t\tString annotationName = fileName.substring(0, fileName.length() - \".imports\".length());\n\t\t\treturn new AutoConfigureImports(annotationName, loadImports(file), fileName);\n\t\t}).toList();\n\t}\n\n\tprivate List<String> loadImports(File importsFile) {\n\t\ttry {\n\t\t\treturn Files.readAllLines(importsFile.toPath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate boolean find(String className) {\n\t\treturn find(className, (input) -> {\n\t\t});\n\t}\n\n\tprivate boolean find(String className, Consumer<InputStream> handler) {\n\t\tfor (File root : this.classpath.getFiles()) {\n\t\t\tString classFilePath = className.replace(\".\", \"/\") + \".class\";\n\t\t\tif (root.isDirectory()) {\n\t\t\t\tFile classFile = new File(root, classFilePath);\n\t\t\t\tif (classFile.isFile()) {\n\t\t\t\t\ttry (InputStream input = new FileInputStream(classFile)) {\n\t\t\t\t\t\thandler.accept(input);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttry (JarFile jar = new JarFile(root)) {\n\t\t\t\t\tZipEntry entry = jar.getEntry(classFilePath);\n\t\t\t\t\tif (entry != null) {\n\t\t\t\t\t\ttry (InputStream input = jar.getInputStream(entry)) {\n\t\t\t\t\t\t\thandler.accept(input);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean correctlyAnnotated(InputStream classFile) {\n\t\treturn AutoConfigurationClass.of(classFile) != null;\n\t}\n\n\tprivate void writeReport(Map<String, List<String>> allProblems, File outputFile) {\n\t\toutputFile.getParentFile().mkdirs();\n\t\tStringBuilder report = new StringBuilder();\n\t\tif (!allProblems.isEmpty()) {\n\t\t\tallProblems.forEach((fileName, problems) -> {\n\t\t\t\treport.append(\"Found problems in '%s':%n\".formatted(fileName));\n\t\t\t\tproblems.forEach((problem) -> report.append(\"  - %s%n\".formatted(problem)));\n\t\t\t});\n\t\t}\n\t\twriteString(outputFile, report.toString());\n\t}\n\n\tprivate void writeString(File file, String content) {\n\t\ttry {\n\t\t\tFiles.writeString(file.toPath(), content);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\trecord AutoConfigureImports(String annotationName, List<String> imports, String fileName) {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/DocumentTestSlices.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.TaskAction;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.build.test.autoconfigure.TestSliceMetadata.TestSlice;\n\n/**\n * {@link Task} used to document test slices.\n *\n * @author Andy Wilkinson\n */\npublic abstract class DocumentTestSlices extends DefaultTask {\n\n\tprivate FileCollection testSliceMetadata;\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tpublic FileCollection getTestSlices() {\n\t\treturn this.testSliceMetadata;\n\t}\n\n\tpublic void setTestSlices(FileCollection testSlices) {\n\t\tthis.testSliceMetadata = testSlices;\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@TaskAction\n\tvoid documentTestSlices() throws IOException {\n\t\tMap<String, List<TestSlice>> testSlices = readTestSlices();\n\t\twriteTable(testSlices);\n\t}\n\n\tprivate Map<String, List<TestSlice>> readTestSlices() {\n\t\tMap<String, List<TestSlice>> testSlices = new TreeMap<>();\n\t\tfor (File metadataFile : this.testSliceMetadata) {\n\t\t\tJsonMapper mapper = JsonMapper.builder().build();\n\t\t\tTestSliceMetadata metadata = mapper.readValue(metadataFile, TestSliceMetadata.class);\n\t\t\tList<TestSlice> slices = new ArrayList<>(metadata.testSlices());\n\t\t\tCollections.sort(slices, (s1, s2) -> s1.annotation().compareTo(s2.annotation()));\n\t\t\ttestSlices.put(metadata.module(), slices);\n\t\t}\n\t\treturn testSlices;\n\t}\n\n\tprivate void writeTable(Map<String, List<TestSlice>> testSlicesByModule) throws IOException {\n\t\tFile outputFile = getOutputFile().getAsFile().get();\n\t\toutputFile.getParentFile().mkdirs();\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(outputFile))) {\n\t\t\twriter.println(\"[cols=\\\"d,d,a\\\"]\");\n\t\t\twriter.println(\"|===\");\n\t\t\twriter.println(\"|Module | Test slice | Imported auto-configuration\");\n\t\t\ttestSlicesByModule.forEach((module, testSlices) -> {\n\t\t\t\ttestSlices.forEach((testSlice) -> {\n\t\t\t\t\twriter.println();\n\t\t\t\t\twriter.printf(\"| `%s`%n\", module);\n\t\t\t\t\twriter.printf(\"| javadoc:%s[format=annotation]%n\", testSlice.annotation());\n\t\t\t\t\twriter.println(\"| \");\n\t\t\t\t\tfor (String importedAutoConfiguration : testSlice.importedAutoConfigurations()) {\n\t\t\t\t\t\twriter.printf(\"`%s`%n\", importedAutoConfiguration);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t\twriter.println(\"|===\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/GenerateTestSliceMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.UncheckedIOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport javax.inject.Inject;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.Task;\nimport org.gradle.api.file.FileCollection;\nimport org.gradle.api.file.RegularFileProperty;\nimport org.gradle.api.model.ObjectFactory;\nimport org.gradle.api.provider.Property;\nimport org.gradle.api.tasks.Classpath;\nimport org.gradle.api.tasks.Input;\nimport org.gradle.api.tasks.InputFiles;\nimport org.gradle.api.tasks.OutputFile;\nimport org.gradle.api.tasks.PathSensitive;\nimport org.gradle.api.tasks.PathSensitivity;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskAction;\n\nimport org.springframework.boot.build.test.autoconfigure.TestSliceMetadata.TestSlice;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link Task} for generating metadata describing a project's test slices.\n *\n * @author Andy Wilkinson\n */\npublic abstract class GenerateTestSliceMetadata extends DefaultTask {\n\n\tprivate final ObjectFactory objectFactory;\n\n\tprivate FileCollection classpath;\n\n\tprivate FileCollection importsFiles;\n\n\tprivate FileCollection classesDirs;\n\n\t@Inject\n\tpublic GenerateTestSliceMetadata(ObjectFactory objectFactory) {\n\t\tthis.objectFactory = objectFactory;\n\t\tthis.getModuleName().convention(getProject().getName());\n\t}\n\n\tpublic void setSourceSet(SourceSet sourceSet) {\n\t\tthis.classpath = sourceSet.getRuntimeClasspath();\n\t\tthis.importsFiles = this.objectFactory.fileTree()\n\t\t\t.from(new File(sourceSet.getOutput().getResourcesDir(), \"META-INF/spring\"));\n\t\tthis.importsFiles.filter((file) -> file.getName().endsWith(\".imports\"));\n\t\tgetSpringFactories().set(new File(sourceSet.getOutput().getResourcesDir(), \"META-INF/spring.factories\"));\n\t\tthis.classesDirs = sourceSet.getOutput().getClassesDirs();\n\t}\n\n\t@OutputFile\n\tpublic abstract RegularFileProperty getOutputFile();\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tabstract RegularFileProperty getSpringFactories();\n\n\t@Input\n\tpublic abstract Property<String> getModuleName();\n\n\t@Classpath\n\tFileCollection getClasspath() {\n\t\treturn this.classpath;\n\t}\n\n\t@InputFiles\n\t@PathSensitive(PathSensitivity.RELATIVE)\n\tFileCollection getImportFiles() {\n\t\treturn this.importsFiles;\n\t}\n\n\t@Classpath\n\tFileCollection getClassesDirs() {\n\t\treturn this.classesDirs;\n\t}\n\n\t@TaskAction\n\tvoid generateTestSliceMetadata() throws IOException {\n\t\tTestSliceMetadata metadata = readTestSlices();\n\t\tFile outputFile = getOutputFile().getAsFile().get();\n\t\toutputFile.getParentFile().mkdirs();\n\t\tmetadata.writeTo(outputFile);\n\t}\n\n\tprivate TestSliceMetadata readTestSlices() throws IOException {\n\t\tList<TestSlice> testSlices = new ArrayList<>();\n\t\ttry (URLClassLoader classLoader = new URLClassLoader(\n\t\t\t\tStreamSupport.stream(this.classpath.spliterator(), false).map(this::toURL).toArray(URL[]::new))) {\n\t\t\tMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(classLoader);\n\t\t\tProperties springFactories = readSpringFactories(getSpringFactories().getAsFile().getOrNull());\n\t\t\treadImportsFiles(springFactories, this.importsFiles);\n\t\t\tfor (File classesDir : this.classesDirs) {\n\t\t\t\ttestSlices.addAll(readTestSlices(classesDir, metadataReaderFactory, springFactories));\n\t\t\t}\n\t\t}\n\t\treturn new TestSliceMetadata(getModuleName().get(), testSlices);\n\t}\n\n\t/**\n\t * Reads the given imports files and puts them in springFactories. The key is the file\n\t * name, the value is the file contents, split by line, delimited with a comma. This\n\t * is done to mimic the spring.factories structure.\n\t * @param springFactories spring.factories parsed as properties\n\t * @param importsFiles the imports files to read\n\t */\n\tprivate void readImportsFiles(Properties springFactories, FileCollection importsFiles) {\n\t\tfor (File file : importsFiles.getFiles()) {\n\t\t\ttry {\n\t\t\t\tList<String> lines = removeComments(Files.readAllLines(file.toPath()));\n\t\t\t\tString fileNameWithoutExtension = file.getName()\n\t\t\t\t\t.substring(0, file.getName().length() - \".imports\".length());\n\t\t\t\tspringFactories.setProperty(fileNameWithoutExtension,\n\t\t\t\t\t\tStringUtils.collectionToCommaDelimitedString(lines));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(\"Failed to read file \" + file, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate List<String> removeComments(List<String> lines) {\n\t\tList<String> result = new ArrayList<>();\n\t\tfor (String line : lines) {\n\t\t\tint commentIndex = line.indexOf('#');\n\t\t\tif (commentIndex > -1) {\n\t\t\t\tline = line.substring(0, commentIndex);\n\t\t\t}\n\t\t\tline = line.trim();\n\t\t\tif (!line.isEmpty()) {\n\t\t\t\tresult.add(line);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate URL toURL(File file) {\n\t\ttry {\n\t\t\treturn file.toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate Properties readSpringFactories(File file) throws IOException {\n\t\tProperties springFactories = new Properties();\n\t\tif (file.isFile()) {\n\t\t\ttry (Reader in = new FileReader(file)) {\n\t\t\t\tspringFactories.load(in);\n\t\t\t}\n\t\t}\n\t\treturn springFactories;\n\t}\n\n\tprivate List<TestSlice> readTestSlices(File classesDir, MetadataReaderFactory metadataReaderFactory,\n\t\t\tProperties springFactories) throws IOException {\n\t\ttry (Stream<Path> classes = Files.walk(classesDir.toPath())) {\n\t\t\treturn classes.filter((path) -> path.toString().endsWith(\"Test.class\"))\n\t\t\t\t.map((path) -> getMetadataReader(path, metadataReaderFactory))\n\t\t\t\t.filter((metadataReader) -> metadataReader.getClassMetadata().isAnnotation())\n\t\t\t\t.map((metadataReader) -> readTestSlice(metadataReader, springFactories))\n\t\t\t\t.toList();\n\t\t}\n\n\t}\n\n\tprivate MetadataReader getMetadataReader(Path path, MetadataReaderFactory metadataReaderFactory) {\n\t\ttry {\n\t\t\treturn metadataReaderFactory.getMetadataReader(new FileSystemResource(path));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate TestSlice readTestSlice(MetadataReader metadataReader, Properties springFactories) {\n\t\tString annotationName = metadataReader.getClassMetadata().getClassName();\n\t\tList<String> importedAutoConfiguration = getImportedAutoConfiguration(springFactories,\n\t\t\t\tmetadataReader.getAnnotationMetadata());\n\t\treturn new TestSlice(annotationName, importedAutoConfiguration);\n\t}\n\n\tprivate List<String> getImportedAutoConfiguration(Properties springFactories,\n\t\t\tAnnotationMetadata annotationMetadata) {\n\t\tStream<String> importers = findMetaImporters(annotationMetadata);\n\t\tif (annotationMetadata.isAnnotated(\"org.springframework.boot.autoconfigure.ImportAutoConfiguration\")) {\n\t\t\timporters = Stream.concat(importers, Stream.of(annotationMetadata.getClassName()));\n\t\t}\n\t\treturn importers\n\t\t\t.flatMap((importer) -> StringUtils.commaDelimitedListToSet(springFactories.getProperty(importer)).stream())\n\t\t\t.toList();\n\t}\n\n\tprivate Stream<String> findMetaImporters(AnnotationMetadata annotationMetadata) {\n\t\treturn annotationMetadata.getAnnotationTypes()\n\t\t\t.stream()\n\t\t\t.filter((annotationType) -> isAutoConfigurationImporter(annotationType, annotationMetadata));\n\t}\n\n\tprivate boolean isAutoConfigurationImporter(String annotationType, AnnotationMetadata metadata) {\n\t\treturn metadata.getMetaAnnotationTypes(annotationType)\n\t\t\t.contains(\"org.springframework.boot.autoconfigure.ImportAutoConfiguration\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestAutoConfigurationPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.file.ConfigurableFileCollection;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskProvider;\nimport org.gradle.language.base.plugins.LifecycleBasePlugin;\n\n/**\n * {@link Plugin} for projects that define test auto-configuration. When the\n * {@link JavaPlugin} is applied it:\n *\n * <ul>\n * <li>Add checks to ensure AutoConfigure*.import files and related annotations are\n * correct</li>\n * </ul>\n *\n * @author Andy Wilkinson\n */\npublic class TestAutoConfigurationPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project target) {\n\t\ttarget.getPlugins().withType(JavaPlugin.class, (plugin) -> {\n\t\t\tTaskProvider<CheckAutoConfigureImports> checkAutoConfigureImports = target.getTasks()\n\t\t\t\t.register(\"checkAutoConfigureImports\", CheckAutoConfigureImports.class, (task) -> {\n\t\t\t\t\tSourceSet mainSourceSet = target.getExtensions()\n\t\t\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t\t\t.getSourceSets()\n\t\t\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\t\t\ttask.setSource(mainSourceSet.getResources());\n\t\t\t\t\tConfigurableFileCollection classpath = target.files(mainSourceSet.getRuntimeClasspath(),\n\t\t\t\t\t\t\ttarget.getConfigurations().getByName(mainSourceSet.getRuntimeClasspathConfigurationName()));\n\t\t\t\t\ttask.setClasspath(classpath);\n\t\t\t\t});\n\t\t\ttarget.getTasks()\n\t\t\t\t.named(LifecycleBasePlugin.CHECK_TASK_NAME)\n\t\t\t\t.configure((check) -> check.dependsOn(checkAutoConfigureImports));\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestSliceMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport java.io.File;\nimport java.util.List;\n\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * Metadata describing a module's test slices.\n *\n * @param module the module's name\n * @param testSlices the module's test slices\n * @author Andy Wilkinson\n */\nrecord TestSliceMetadata(String module, List<TestSlice> testSlices) {\n\n\tstatic TestSliceMetadata readFrom(File file) {\n\t\treturn JsonMapper.builder().build().readValue(file, TestSliceMetadata.class);\n\t}\n\n\tvoid writeTo(File file) {\n\t\tJsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build().writeValue(file, this);\n\t}\n\n\trecord TestSlice(String annotation, List<String> importedAutoConfigurations) {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/test/autoconfigure/TestSlicePlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.attributes.Category;\nimport org.gradle.api.attributes.Usage;\nimport org.gradle.api.plugins.JavaPlugin;\nimport org.gradle.api.plugins.JavaPluginExtension;\nimport org.gradle.api.plugins.PluginContainer;\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.api.tasks.TaskProvider;\n\n/**\n * {@link Plugin} for projects that define one or more test slices. When applied, it:\n *\n * <ul>\n * <li>Applies the {@link TestAutoConfigurationPlugin}\n * </ul>\n * Additionally, when the {@link JavaPlugin} is applied it:\n *\n * <ul>\n * <li>Defines a task that produces metadata describing the test slices. The metadata is\n * made available as an artifact in the {@code testSliceMetadata} configuration\n * </ul>\n *\n * @author Andy Wilkinson\n */\npublic class TestSlicePlugin implements Plugin<Project> {\n\n\tprivate static final String TEST_SLICE_METADATA_CONFIGURATION_NAME = \"testSliceMetadata\";\n\n\t@Override\n\tpublic void apply(Project target) {\n\t\tPluginContainer plugins = target.getPlugins();\n\t\tplugins.apply(TestAutoConfigurationPlugin.class);\n\t\tplugins.withType(JavaPlugin.class, (plugin) -> {\n\t\t\tTaskProvider<GenerateTestSliceMetadata> generateTestSliceMetadata = target.getTasks()\n\t\t\t\t.register(\"generateTestSliceMetadata\", GenerateTestSliceMetadata.class, (task) -> {\n\t\t\t\t\tSourceSet mainSourceSet = target.getExtensions()\n\t\t\t\t\t\t.getByType(JavaPluginExtension.class)\n\t\t\t\t\t\t.getSourceSets()\n\t\t\t\t\t\t.getByName(SourceSet.MAIN_SOURCE_SET_NAME);\n\t\t\t\t\ttask.setSourceSet(mainSourceSet);\n\t\t\t\t\ttask.getOutputFile().set(target.getLayout().getBuildDirectory().file(\"test-slice-metadata.json\"));\n\t\t\t\t});\n\t\t\taddMetadataArtifact(target, generateTestSliceMetadata);\n\t\t});\n\t}\n\n\tprivate void addMetadataArtifact(Project project, TaskProvider<GenerateTestSliceMetadata> task) {\n\t\tproject.getConfigurations().consumable(TEST_SLICE_METADATA_CONFIGURATION_NAME, (configuration) -> {\n\t\t\tconfiguration.attributes((attributes) -> {\n\t\t\t\tattributes.attribute(Category.CATEGORY_ATTRIBUTE,\n\t\t\t\t\t\tproject.getObjects().named(Category.class, Category.DOCUMENTATION));\n\t\t\t\tattributes.attribute(Usage.USAGE_ATTRIBUTE,\n\t\t\t\t\t\tproject.getObjects().named(Usage.class, \"test-slice-metadata\"));\n\t\t\t});\n\t\t});\n\t\tproject.getArtifacts().add(TEST_SLICE_METADATA_CONFIGURATION_NAME, task);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/testing/TestFailuresPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.testing;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.provider.Provider;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.api.tasks.testing.TestDescriptor;\nimport org.gradle.api.tasks.testing.TestListener;\nimport org.gradle.api.tasks.testing.TestResult;\n\n/**\n * Plugin for recording test failures and reporting them at the end of the build.\n *\n * @author Andy Wilkinson\n */\npublic class TestFailuresPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tProvider<TestResultsOverview> testResultsOverview = project.getGradle()\n\t\t\t.getSharedServices()\n\t\t\t.registerIfAbsent(\"testResultsOverview\", TestResultsOverview.class, (spec) -> {\n\t\t\t});\n\t\tproject.getTasks().withType(Test.class, (test) -> {\n\t\t\ttest.usesService(testResultsOverview);\n\t\t\ttest.addTestListener(new FailureRecordingTestListener(testResultsOverview, test));\n\t\t});\n\t}\n\n\tprivate final class FailureRecordingTestListener implements TestListener {\n\n\t\tprivate final List<TestDescriptor> failures = new ArrayList<>();\n\n\t\tprivate final Provider<TestResultsOverview> testResultsOverview;\n\n\t\tprivate final Test test;\n\n\t\tprivate FailureRecordingTestListener(Provider<TestResultsOverview> testResultOverview, Test test) {\n\t\t\tthis.testResultsOverview = testResultOverview;\n\t\t\tthis.test = test;\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterSuite(TestDescriptor descriptor, TestResult result) {\n\t\t\tif (!this.failures.isEmpty()) {\n\t\t\t\tthis.testResultsOverview.get().addFailures(this.test, this.failures);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterTest(TestDescriptor descriptor, TestResult result) {\n\t\t\tif (result.getFailedTestCount() > 0) {\n\t\t\t\tthis.failures.add(descriptor);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void beforeSuite(TestDescriptor descriptor) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void beforeTest(TestDescriptor descriptor) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/testing/TestResultsOverview.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.testing;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport org.gradle.api.DefaultTask;\nimport org.gradle.api.services.BuildService;\nimport org.gradle.api.services.BuildServiceParameters;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.api.tasks.testing.TestDescriptor;\nimport org.gradle.tooling.events.FinishEvent;\nimport org.gradle.tooling.events.OperationCompletionListener;\n\n/**\n * {@link BuildService} that provides an overview of all the test failures in the build.\n *\n * @author Andy Wilkinson\n */\npublic abstract class TestResultsOverview\n\t\timplements BuildService<BuildServiceParameters.None>, OperationCompletionListener, AutoCloseable {\n\n\tprivate final Map<Test, List<TestFailure>> testFailures = new TreeMap<>(Comparator.comparing(DefaultTask::getPath));\n\n\tprivate final Object monitor = new Object();\n\n\tvoid addFailures(Test test, List<TestDescriptor> failureDescriptors) {\n\t\tList<TestFailure> testFailures = failureDescriptors.stream().map(TestFailure::new).sorted().toList();\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.testFailures.put(test, testFailures);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onFinish(FinishEvent event) {\n\t\t// OperationCompletionListener is implemented to defer close until the build ends\n\t}\n\n\t@Override\n\tpublic void close() {\n\t\tsynchronized (this.monitor) {\n\t\t\tif (this.testFailures.isEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tSystem.err.println();\n\t\t\tSystem.err.println(\"Found test failures in \" + this.testFailures.size() + \" test task\"\n\t\t\t\t\t+ ((this.testFailures.size() == 1) ? \":\" : \"s:\"));\n\t\t\tthis.testFailures.forEach((task, failures) -> {\n\t\t\t\tSystem.err.println();\n\t\t\t\tSystem.err.println(task.getPath());\n\t\t\t\tfailures.forEach((failure) -> System.err\n\t\t\t\t\t.println(\"    \" + failure.descriptor.getClassName() + \" > \" + failure.descriptor.getName()));\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate static final class TestFailure implements Comparable<TestFailure> {\n\n\t\tprivate final TestDescriptor descriptor;\n\n\t\tprivate TestFailure(TestDescriptor descriptor) {\n\t\t\tthis.descriptor = descriptor;\n\t\t}\n\n\t\t@Override\n\t\tpublic int compareTo(TestFailure other) {\n\t\t\tint comparison = this.descriptor.getClassName().compareTo(other.descriptor.getClassName());\n\t\t\tif (comparison == 0) {\n\t\t\t\tcomparison = this.descriptor.getName().compareTo(other.descriptor.getName());\n\t\t\t}\n\t\t\treturn comparison;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/toolchain/ToolchainExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.toolchain;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.provider.ListProperty;\nimport org.gradle.api.provider.Property;\nimport org.gradle.jvm.toolchain.JavaLanguageVersion;\n\nimport org.springframework.boot.build.SystemRequirementsExtension;\n\n/**\n * DSL extension for {@link ToolchainPlugin}.\n *\n * @author Christoph Dreis\n */\npublic abstract class ToolchainExtension {\n\n\tprivate final JavaLanguageVersion javaVersion;\n\n\tpublic ToolchainExtension(Project project) {\n\t\tString toolchainVersion = (String) project.findProperty(\"toolchainVersion\");\n\t\tthis.javaVersion = (toolchainVersion != null) ? JavaLanguageVersion.of(toolchainVersion) : null;\n\t\tSystemRequirementsExtension systemRequirements = project.getExtensions()\n\t\t\t.getByType(SystemRequirementsExtension.class);\n\t\tgetMinimumCompatibleJavaVersion()\n\t\t\t.convention(project.provider(() -> JavaLanguageVersion.of(systemRequirements.getJava().getVersion())));\n\t}\n\n\tpublic abstract Property<JavaLanguageVersion> getMinimumCompatibleJavaVersion();\n\n\tpublic abstract Property<JavaLanguageVersion> getMaximumCompatibleJavaVersion();\n\n\tpublic abstract ListProperty<String> getTestJvmArgs();\n\n\tJavaLanguageVersion getJavaVersion() {\n\t\treturn this.javaVersion;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/java/org/springframework/boot/build/toolchain/ToolchainPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.toolchain;\n\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.tasks.testing.Test;\nimport org.gradle.jvm.toolchain.JavaLanguageVersion;\nimport org.gradle.jvm.toolchain.JavaToolchainService;\n\n/**\n * {@link Plugin} for customizing Gradle's toolchain support.\n *\n * @author Christoph Dreis\n * @author Andy Wilkinson\n */\npublic class ToolchainPlugin implements Plugin<Project> {\n\n\t@Override\n\tpublic void apply(Project project) {\n\t\tconfigureToolchain(project);\n\t}\n\n\tprivate void configureToolchain(Project project) {\n\t\tToolchainExtension toolchain = project.getExtensions().create(\"toolchain\", ToolchainExtension.class, project);\n\t\tJavaLanguageVersion toolchainVersion = toolchain.getJavaVersion();\n\t\tif (toolchainVersion != null) {\n\t\t\tproject.afterEvaluate((evaluated) -> configure(evaluated, toolchain));\n\t\t}\n\t}\n\n\tprivate void configure(Project project, ToolchainExtension toolchain) {\n\t\tif (!isJavaVersionSupported(toolchain, toolchain.getJavaVersion())) {\n\t\t\tdisableToolchainTasks(project);\n\t\t}\n\t\telse {\n\t\t\tconfigureTestToolchain(project, toolchain.getJavaVersion());\n\t\t}\n\t}\n\n\tprivate boolean isJavaVersionSupported(ToolchainExtension toolchain, JavaLanguageVersion toolchainVersion) {\n\t\tJavaLanguageVersion minimumVersion = toolchain.getMinimumCompatibleJavaVersion().getOrNull();\n\t\tif (minimumVersion == null || toolchainVersion.canCompileOrRun(minimumVersion)) {\n\t\t\treturn toolchain.getMaximumCompatibleJavaVersion()\n\t\t\t\t.map((version) -> version.canCompileOrRun(toolchainVersion))\n\t\t\t\t.getOrElse(true);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate void disableToolchainTasks(Project project) {\n\t\tproject.getTasks().withType(Test.class, (task) -> task.setEnabled(false));\n\t}\n\n\tprivate void configureTestToolchain(Project project, JavaLanguageVersion toolchainVersion) {\n\t\tJavaToolchainService javaToolchains = project.getExtensions().getByType(JavaToolchainService.class);\n\t\tproject.getTasks()\n\t\t\t.withType(Test.class, (test) -> test.getJavaLauncher()\n\t\t\t\t.set(javaToolchains.launcherFor((spec) -> spec.getLanguageVersion().set(toolchainVersion))));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-asciidoc-attributes.properties",
    "content": "# === INCLUDE-CODE LOCATIONS ===\n\ninclude-java=ROOT:example$java/org/springframework/boot/docs\ninclude-kotlin= ROOT:example$kotlin/org/springframework/boot/docs\n\n# === URLs ===\n\nurl-ant-docs=https://ant.apache.org/manual\nurl-buildpacks-docs=https://buildpacks.io/docs\nurl-cyclonedx-docs-gradle-plugin=https://github.com/CycloneDX/cyclonedx-gradle-plugin\nurl-cyclonedx-docs-maven-plugin=https://github.com/CycloneDX/cyclonedx-maven-plugin\nurl-git-commit-id-maven-plugin=https://github.com/git-commit-id/git-commit-id-maven-plugin\nurl-download-liberica-nik=https://bell-sw.com/pages/downloads/native-image-kit/#/nik-22-17\nurl-dynatrace-docs=https://docs.dynatrace.com/docs\nurl-dynatrace-docs-shortlink={url-dynatrace-docs}/shortlink\nurl-github-raw=https://raw.githubusercontent.com/{github-repo}/{github-ref}\nurl-github-issues=https://github.com/{github-repo}/issues\nurl-github-wiki=https://github.com/{github-repo}/wiki\nurl-github=https://github.com/{github-repo}\nurl-graal-docs=https://www.graalvm.org/{version-graal}/reference-manual\nurl-graal-docs-native-image={url-graal-docs}/native-image\nurl-gradle-docs=https://docs.gradle.org/current/userguide\nurl-gradle-docs-application-plugin={url-gradle-docs}/application_plugin.html\nurl-gradle-docs-groovy-plugin={url-gradle-docs}/groovy_plugin.html\nurl-gradle-docs-java-plugin={url-gradle-docs}/java_plugin.html\nurl-gradle-docs-war-plugin={url-gradle-docs}/war_plugin.html\nurl-gradle-dsl=https://docs.gradle.org/current/dsl\nurl-gradle-javadoc=https://docs.gradle.org/current/javadoc\nurl-kotlin-docs-kotlin-plugin={url-kotlin-docs}/using-gradle.html\nurl-micrometer-docs-concepts={url-micrometer-docs}/concepts\nurl-micrometer-docs-implementations={url-micrometer-docs}/implementations\nurl-micrometer-docs-observation={url-micrometer-docs}/observation\nurl-native-build-tools-docs=https://graalvm.github.io/native-build-tools/{version-native-build-tools}\nurl-native-build-tools-docs-gradle-plugin={url-native-build-tools-docs}/gradle-plugin.html\nurl-native-build-tools-docs-maven-plugin={url-native-build-tools-docs}/maven-plugin.html\nurl-paketo-docs=https://paketo.io/docs\nurl-paketo-docs-java-buildpack={url-paketo-docs}/buildpacks/language-family-buildpacks/java\nurl-protobuf-docs-gradle-plugin=https://github.com/google/protobuf-gradle-plugin\nurl-pulsar-client-api-javadoc=https://javadoc.io/doc/org.apache.pulsar/pulsar-client-api/{version-pulsar-client-api}\nurl-spring-boot-for-apache-geode-docs=https://docs.spring.io/spring-boot-data-geode-build/2.0.x/reference/html5\nurl-spring-boot-for-apache-geode-site=https://github.com/spring-projects/spring-boot-data-geode\nurl-spring-data-cassandra-docs=https://docs.spring.io/spring-data/cassandra/reference/{antoraversion-spring-data-cassandra}\nurl-spring-data-cassandra-site=https://spring.io/projects/spring-data-cassandra\nurl-spring-data-cassandra-javadoc=https://docs.spring.io/spring-data/cassandra/docs/{dotxversion-spring-data-cassandra}/api\nurl-spring-data-commons-javadoc=https://docs.spring.io/spring-data/commons/docs/{dotxversion-spring-data-commons}/api\nurl-spring-data-couchbase-docs=https://docs.spring.io/spring-data/couchbase/reference/{antoraversion-spring-data-couchbase}\nurl-spring-data-couchbase-site=https://spring.io/projects/spring-data-couchbase\nurl-spring-data-couchbase-javadoc=https://docs.spring.io/spring-data/couchbase/docs/{dotxversion-spring-data-couchbase}/api\nurl-spring-data-elasticsearch-docs=https://docs.spring.io/spring-data/elasticsearch/reference/{antoraversion-spring-data-elasticsearch}\nurl-spring-data-elasticsearch-site=https://spring.io/projects/spring-data-elasticsearch\nurl-spring-data-elasticsearch-javadoc=https://docs.spring.io/spring-data/elasticsearch/docs/{dotxversion-spring-data-elasticsearch}/api\nurl-spring-data-envers-site=https://spring.io/projects/spring-data-envers\nurl-spring-data-geode-site=https://spring.io/projects/spring-data-geode\nurl-spring-data-jdbc-docs=https://docs.spring.io/spring-data/relational/reference/{antoraversion-spring-data-jdbc}\nurl-spring-data-jdbc-site=https://spring.io/projects/spring-data-jdbc\nurl-spring-data-jdbc-javadoc=https://docs.spring.io/spring-data/jdbc/docs/{dotxversion-spring-data-jdbc}/api\nurl-spring-data-jpa-docs=https://docs.spring.io/spring-data/jpa/reference/{antoraversion-spring-data-jpa}\nurl-spring-data-jpa-site=https://spring.io/projects/spring-data-jpa\nurl-spring-data-jpa-javadoc=https://docs.spring.io/spring-data/jpa/docs/{dotxversion-spring-data-jpa}/api\nurl-spring-data-ldap-docs=https://docs.spring.io/spring-data/ldap/reference/{antoraversion-spring-data-ldap}\nurl-spring-data-ldap-site=https://spring.io/projects/spring-data-ldap\nurl-spring-data-ldap-javadoc=https://docs.spring.io/spring-data/ldap/docs/{dotxversion-spring-data-ldap}/api\nurl-spring-data-mongodb-docs=https://docs.spring.io/spring-data/mongodb/reference/{antoraversion-spring-data-mongodb}\nurl-spring-data-mongodb-site=https://spring.io/projects/spring-data-mongodb\nurl-spring-data-mongodb-javadoc=https://docs.spring.io/spring-data/mongodb/docs/{dotxversion-spring-data-mongodb}/api\nurl-spring-data-neo4j-docs=https://docs.spring.io/spring-data/neo4j/reference/{antoraversion-spring-data-neo4j}\nurl-spring-data-neo4j-site=https://spring.io/projects/spring-data-neo4j\nurl-spring-data-neo4j-javadoc=https://docs.spring.io/spring-data/neo4j/docs/{dotxversion-spring-data-neo4j}/api\nurl-spring-data-r2dbc-docs=https://docs.spring.io/spring-data/relational/reference/{antoraversion-spring-data-r2dbc}\nurl-spring-data-r2dbc-site=https://spring.io/projects/spring-data-r2dbc\nurl-spring-data-r2dbc-javadoc=https://docs.spring.io/spring-data/r2dbc/docs/{dotxversion-spring-data-r2dbc}/api\nurl-spring-data-redis-docs=https://docs.spring.io/spring-data/redis/reference/{antoraversion-spring-data-redis}\nurl-spring-data-redis-site=https://spring.io/projects/spring-data-redis\nurl-spring-data-redis-javadoc=https://docs.spring.io/spring-data/redis/docs/{dotxversion-spring-data-redis}/api\nurl-spring-data-rest-docs=https://docs.spring.io/spring-data/rest/reference/{antoraversion-spring-data-rest}\nurl-spring-data-rest-site=https://spring.io/projects/spring-data-rest\nurl-spring-data-rest-javadoc=https://docs.spring.io/spring-data/rest/docs/{dotxversion-spring-data-rest}/api\nurl-spring-data-site=https://spring.io/projects/spring-data\nurl-jackson-annotations-javadoc=https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/{version-jackson-annotations}\nurl-jackson-core-javadoc=https://javadoc.io/doc/tools.jackson.core/jackson-core/{version-jackson-core}\nurl-jackson-databind-javadoc=https://javadoc.io/doc/tools.jackson.core/jackson-databind/{version-jackson-databind}\nurl-jackson-dataformat-xml-javadoc=https://javadoc.io/doc/tools.jackson.dataformat/jackson-dataformat-xml/{version-jackson-dataformat-xml}\nurl-jackson2-databind-javadoc=https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/{version-jackson2-databind}\n\n# === Javadoc Locations ===\n\njavadoc-location-com-fasterxml-jackson-annotation={url-jackson-annotations-javadoc}\njavadoc-location-com-fasterxml-jackson-databind={url-jackson2-databind-javadoc}\njavadoc-location-org-apache-pulsar-client-api={url-pulsar-client-api-javadoc}\njavadoc-location-org-springframework-data-cassandra={url-spring-data-cassandra-javadoc}\njavadoc-location-org-springframework-data-convert={url-spring-data-commons-javadoc}\njavadoc-location-org-springframework-data-querydsl={url-spring-data-commons-javadoc}\njavadoc-location-org-springframework-data-repository={url-spring-data-commons-javadoc}\njavadoc-location-org-springframework-data-couchbase={url-spring-data-couchbase-javadoc}\njavadoc-location-org-springframework-data-elasticsearch={url-spring-data-elasticsearch-javadoc}\njavadoc-location-org-springframework-data-jdbc={url-spring-data-jdbc-javadoc}\njavadoc-location-org-springframework-data-jpa={url-spring-data-jpa-javadoc}\njavadoc-location-org-springframework-data-ldap={url-spring-data-ldap-javadoc}\njavadoc-location-org-springframework-data-mongodb={url-spring-data-mongodb-javadoc}\njavadoc-location-org-springframework-data-neo4j={url-spring-data-neo4j-javadoc}\njavadoc-location-org-springframework-data-r2dbc={url-spring-data-r2dbc-javadoc}\njavadoc-location-org-springframework-data-redis={url-spring-data-redis-javadoc}\njavadoc-location-org-springframework-data-rest={url-spring-data-rest-javadoc}\njavadoc-location-tools-jackson-core={url-jackson-core-javadoc}\njavadoc-location-tools-jackson-databind={url-jackson-databind-javadoc}\njavadoc-location-tools-jackson-dataformat-xml={url-jackson-dataformat-xml-javadoc}\n\n# === API References ===\n\napiref-gradle-plugin-boot-build-image=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootBuildImage.html\napiref-gradle-plugin-boot-jar=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootJar.html\napiref-gradle-plugin-boot-run=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/run/BootRun.html\napiref-gradle-plugin-boot-war=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/bundling/BootWar.html\napiref-gradle-plugin-boot-build-info=xref:gradle-plugin:api/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.html\napiref-openjdk=https://docs.oracle.com/en/java/javase/17/docs/api\n\n# === Code Links ===\n\ncode-spring-boot=https://github.com/{github-repo}/tree/{github-ref}\ncode-spring-boot-autoconfigure-src={code-spring-boot}/core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure\ncode-spring-boot-batch-data-mongodb-src={code-spring-boot}/module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb\ncode-spring-boot-batch-jdbc-src={code-spring-boot}/module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc\ncode-spring-boot-batch-src={code-spring-boot}/module/spring-boot-batch/src/main/java/org/springframework/boot/batch\ncode-spring-boot-freemarker-src={code-spring-boot}/module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker\ncode-spring-boot-groovy-templates-src={code-spring-boot}/module/spring-boot-groovy-templates/src/main/java/org/springframework/boot/groovy/template\ncode-spring-boot-hibernate-src={code-spring-boot}/module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate\ncode-spring-boot-integration-src={code-spring-boot}/module/spring-boot-integration/src/main/java/org/springframework/boot/integration\ncode-spring-boot-jdbc-src={code-spring-boot}/module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc\ncode-spring-boot-jooq-src={code-spring-boot}/module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq\ncode-spring-boot-jpa-src={code-spring-boot}/module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa\ncode-spring-boot-latest=https://github.com/{github-repo}/tree/main\ncode-spring-boot-servlet-src={code-spring-boot}/module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet\ncode-spring-boot-thymeleaf-src={code-spring-boot}/module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf\ncode-spring-boot-webmvc-src={code-spring-boot}/module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc\n"
  },
  {
    "path": "buildSrc/src/main/resources/org/springframework/boot/build/antora/antora-playbook-template.yml",
    "content": "antora:\n  extensions:\nsite:\n  title: Spring Boot\ncontent:\n  sources: []\nasciidoc:\n  sourcemap: true\n  attributes:\n    chomp: all\n    hide-uri-scheme: '@'\n    javadoc-location: xref:api:java/\n    page-pagination: ''\n    page-stackoverflow-url: https://stackoverflow.com/tags/spring-boot\n    tabs-sync-option: '@'\n  extensions:\nurls:\n  latest_version_segment: ''\nruntime:\n  log:\n    failure_level: warn\n"
  },
  {
    "path": "buildSrc/src/main/resources/org/springframework/boot/build/legal/LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        https://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "buildSrc/src/main/resources/org/springframework/boot/build/legal/NOTICE.txt",
    "content": "Spring Boot ${version}\nCopyright (c) 2012-2026 VMware, Inc.\n\nThis product is licensed to you under the Apache License, Version 2.0\n(the \"License\"). You may not use this product except in compliance with\nthe License."
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/ConventionsPluginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ConventionsPlugin}.\n *\n * @author Christoph Dreis\n */\nclass ConventionsPluginTests {\n\n\tprivate File projectDir;\n\n\tprivate File buildFile;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File projectDir) throws IOException {\n\t\tthis.projectDir = projectDir;\n\t\tthis.buildFile = new File(this.projectDir, \"build.gradle\");\n\t\tFile settingsFile = new File(this.projectDir, \"settings.gradle\");\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(settingsFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'com.gradle.develocity'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"include ':platform:spring-boot-internal-dependencies'\");\n\t\t}\n\t\tFile internalDependencies = new File(this.projectDir,\n\t\t\t\t\"platform/spring-boot-internal-dependencies/build.gradle\");\n\t\tinternalDependencies.getParentFile().mkdirs();\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(internalDependencies))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'java-platform'\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid jarIncludesLegalFiles() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'java'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.conventions'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"version = '1.2.3'\");\n\t\t\tout.println(\"java {\");\n\t\t\tout.println(\"    sourceCompatibility = '17'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"description 'Test project for manifest customization'\");\n\t\t\tout.println(\"jar.archiveFileName = 'test.jar'\");\n\t\t}\n\t\trunGradle(\"jar\");\n\t\tFile file = new File(this.projectDir, \"/build/libs/test.jar\");\n\t\tassertThat(file).exists();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThatLicenseIsPresent(jar);\n\t\t\tassertThatNoticeIsPresent(jar);\n\t\t\tAttributes mainAttributes = jar.getManifest().getMainAttributes();\n\t\t\tassertThat(mainAttributes.getValue(\"Implementation-Title\"))\n\t\t\t\t.isEqualTo(\"Test project for manifest customization\");\n\t\t\tassertThat(mainAttributes.getValue(\"Automatic-Module-Name\"))\n\t\t\t\t.isEqualTo(this.projectDir.getName().replace(\"-\", \".\"));\n\t\t\tassertThat(mainAttributes.getValue(\"Implementation-Version\")).isEqualTo(\"1.2.3\");\n\t\t\tassertThat(mainAttributes.getValue(\"Built-By\")).isEqualTo(\"Spring\");\n\t\t\tassertThat(mainAttributes.getValue(\"Build-Jdk-Spec\")).isEqualTo(\"17\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid sourceJarIsBuilt() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'java'\");\n\t\t\tout.println(\"    id 'maven-publish'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.conventions'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"version = '1.2.3'\");\n\t\t\tout.println(\"java {\");\n\t\t\tout.println(\"    sourceCompatibility = '17'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"description 'Test'\");\n\t\t}\n\t\trunGradle(\"assemble\");\n\t\tFile file = new File(this.projectDir, \"/build/libs/\" + this.projectDir.getName() + \"-1.2.3-sources.jar\");\n\t\tassertThat(file).exists();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThatLicenseIsPresent(jar);\n\t\t\tassertThatNoticeIsPresent(jar);\n\t\t\tAttributes mainAttributes = jar.getManifest().getMainAttributes();\n\t\t\tassertThat(mainAttributes.getValue(\"Implementation-Title\"))\n\t\t\t\t.isEqualTo(\"Source for \" + this.projectDir.getName());\n\t\t\tassertThat(mainAttributes.getValue(\"Automatic-Module-Name\"))\n\t\t\t\t.isEqualTo(this.projectDir.getName().replace(\"-\", \".\"));\n\t\t\tassertThat(mainAttributes.getValue(\"Implementation-Version\")).isEqualTo(\"1.2.3\");\n\t\t\tassertThat(mainAttributes.getValue(\"Built-By\")).isEqualTo(\"Spring\");\n\t\t\tassertThat(mainAttributes.getValue(\"Build-Jdk-Spec\")).isEqualTo(\"17\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid javadocJarIsBuilt() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'java'\");\n\t\t\tout.println(\"    id 'maven-publish'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.conventions'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"version = '1.2.3'\");\n\t\t\tout.println(\"java {\");\n\t\t\tout.println(\"    sourceCompatibility = '17'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"description 'Test'\");\n\t\t}\n\t\trunGradle(\"assemble\");\n\t\tFile file = new File(this.projectDir, \"/build/libs/\" + this.projectDir.getName() + \"-1.2.3-javadoc.jar\");\n\t\tassertThat(file).exists();\n\t\ttry (JarFile jar = new JarFile(file)) {\n\t\t\tassertThatLicenseIsPresent(jar);\n\t\t\tassertThatNoticeIsPresent(jar);\n\t\t\tAttributes mainAttributes = jar.getManifest().getMainAttributes();\n\t\t\tassertThat(mainAttributes.getValue(\"Implementation-Title\"))\n\t\t\t\t.isEqualTo(\"Javadoc for \" + this.projectDir.getName());\n\t\t\tassertThat(mainAttributes.getValue(\"Automatic-Module-Name\"))\n\t\t\t\t.isEqualTo(this.projectDir.getName().replace(\"-\", \".\"));\n\t\t\tassertThat(mainAttributes.getValue(\"Implementation-Version\")).isEqualTo(\"1.2.3\");\n\t\t\tassertThat(mainAttributes.getValue(\"Built-By\")).isEqualTo(\"Spring\");\n\t\t\tassertThat(mainAttributes.getValue(\"Build-Jdk-Spec\")).isEqualTo(\"17\");\n\t\t}\n\t}\n\n\tprivate void assertThatLicenseIsPresent(JarFile jar) throws IOException {\n\t\tJarEntry license = jar.getJarEntry(\"META-INF/LICENSE.txt\");\n\t\tassertThat(license).isNotNull();\n\t\tString licenseContent = FileCopyUtils.copyToString(new InputStreamReader(jar.getInputStream(license)));\n\t\tassertThat(licenseContent).isEqualTo(Files.readString(Path.of(\"src\", \"main\", \"resources\", \"org\",\n\t\t\t\t\"springframework\", \"boot\", \"build\", \"legal\", \"LICENSE.txt\")));\n\t}\n\n\tprivate void assertThatNoticeIsPresent(JarFile jar) throws IOException {\n\t\tJarEntry notice = jar.getJarEntry(\"META-INF/NOTICE.txt\");\n\t\tassertThat(notice).isNotNull();\n\t\tString noticeContent = FileCopyUtils.copyToString(new InputStreamReader(jar.getInputStream(notice)));\n\t\t// Test that variables were replaced\n\t\tassertThat(noticeContent).doesNotContain(\"${\");\n\t}\n\n\t@Test\n\tvoid testRetryIsConfiguredWithThreeRetriesOnCI() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'java'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.conventions'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"description 'Test'\");\n\t\t\tout.println(\"task retryConfig {\");\n\t\t\tout.println(\"    doLast {\");\n\t\t\tout.println(\"        test.develocity.testRetry {\");\n\t\t\tout.println(\"            println \\\"maxRetries: ${maxRetries.get()}\\\"\");\n\t\t\tout.println(\"            println \\\"failOnPassedAfterRetry: ${failOnPassedAfterRetry.get()}\\\"\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tassertThat(runGradle(Collections.singletonMap(\"CI\", \"true\"), \"retryConfig\", \"--stacktrace\").getOutput())\n\t\t\t.contains(\"maxRetries: 3\")\n\t\t\t.contains(\"failOnPassedAfterRetry: false\");\n\t}\n\n\t@Test\n\tvoid testRetryIsConfiguredWithZeroRetriesLocally() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'java'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.conventions'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"description 'Test'\");\n\t\t\tout.println(\"task retryConfig {\");\n\t\t\tout.println(\"    doLast {\");\n\t\t\tout.println(\"        test.develocity.testRetry {\");\n\t\t\tout.println(\"            println \\\"maxRetries: ${maxRetries.get()}\\\"\");\n\t\t\tout.println(\"            println \\\"failOnPassedAfterRetry: ${failOnPassedAfterRetry.get()}\\\"\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tassertThat(runGradle(Collections.singletonMap(\"CI\", \"local\"), \"retryConfig\", \"--stacktrace\").getOutput())\n\t\t\t.contains(\"maxRetries: 0\")\n\t\t\t.contains(\"failOnPassedAfterRetry: false\");\n\t}\n\n\tprivate BuildResult runGradle(String... args) {\n\t\treturn runGradle(Collections.emptyMap(), args);\n\t}\n\n\tprivate BuildResult runGradle(Map<String, String> environment, String... args) {\n\t\treturn GradleRunner.create()\n\t\t\t.withProjectDir(this.projectDir)\n\t\t\t.withEnvironment(environment)\n\t\t\t.withArguments(args)\n\t\t\t.withPluginClasspath()\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/antora/AntoraAsciidocAttributesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.BomAlignment;\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.Library.Link;\nimport org.springframework.boot.build.bom.Library.ProhibitedVersion;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.boot.build.properties.BuildType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AntoraAsciidocAttributes}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass AntoraAsciidocAttributesTests {\n\n\t@Test\n\tvoid buildTypeWhenOpenSource() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"build-type\", \"opensource\");\n\t}\n\n\t@Test\n\tvoid buildTypeWhenCommercial() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.COMMERCIAL, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"build-type\", \"commercial\");\n\t}\n\n\t@Test\n\tvoid githubRefWhenReleasedVersionIsTag() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"github-ref\", \"v1.2.3\");\n\t}\n\n\t@Test\n\tvoid githubRefWhenLatestSnapshotVersionIsMainBranch() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-SNAPSHOT\", true,\n\t\t\t\tBuildType.OPEN_SOURCE, null, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"github-ref\", \"main\");\n\t}\n\n\t@Test\n\tvoid githubRefWhenOlderSnapshotVersionIsBranch() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-SNAPSHOT\", false,\n\t\t\t\tBuildType.OPEN_SOURCE, null, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"github-ref\", \"1.2.x\");\n\t}\n\n\t@Test\n\tvoid githubRefWhenOlderSnapshotHotFixVersionIsBranch() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3.1-SNAPSHOT\", false,\n\t\t\t\tBuildType.OPEN_SOURCE, null, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"github-ref\", \"1.2.3.x\");\n\t}\n\n\t@Test\n\tvoid versionReferenceFromLibrary() {\n\t\tLibrary library = mockLibrary(Collections.emptyMap());\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3.1-SNAPSHOT\", false,\n\t\t\t\tBuildType.OPEN_SOURCE, List.of(library), mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"version-spring-framework\", \"1.2.3\");\n\t}\n\n\t@Test\n\tvoid versionReferenceFromSpringDataDependencyReleaseVersion() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(\"3.2.5\"), null);\n\t\tassertThat(attributes.get()).containsEntry(\"version-spring-data-mongodb\", \"3.2.5\");\n\t\tassertThat(attributes.get()).containsEntry(\"url-spring-data-mongodb-docs\",\n\t\t\t\t\"https://docs.spring.io/spring-data/mongodb/reference/3.2\");\n\t\tassertThat(attributes.get()).containsEntry(\"url-spring-data-mongodb-javadoc\",\n\t\t\t\t\"https://docs.spring.io/spring-data/mongodb/docs/3.2.x/api\");\n\t}\n\n\t@Test\n\tvoid versionReferenceFromSpringDataDependencySnapshotVersion() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(\"3.2.0-SNAPSHOT\"), null);\n\t\tassertThat(attributes.get()).containsEntry(\"version-spring-data-mongodb\", \"3.2.0-SNAPSHOT\");\n\t\tassertThat(attributes.get()).containsEntry(\"url-spring-data-mongodb-docs\",\n\t\t\t\t\"https://docs.spring.io/spring-data/mongodb/reference/3.2-SNAPSHOT\");\n\t\tassertThat(attributes.get()).containsEntry(\"url-spring-data-mongodb-javadoc\",\n\t\t\t\t\"https://docs.spring.io/spring-data/mongodb/docs/3.2.x/api\");\n\t}\n\n\t@Test\n\tvoid versionNativeBuildTools() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(), Map.of(\"nativeBuildToolsVersion\", \"3.4.5\"));\n\t\tassertThat(attributes.get()).containsEntry(\"version-native-build-tools\", \"3.4.5\");\n\t}\n\n\t@Test\n\tvoid urlArtifactRepositoryWhenRelease() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"url-artifact-repository\", \"https://repo.maven.apache.org/maven2\");\n\t}\n\n\t@Test\n\tvoid urlArtifactRepositoryWhenMilestone() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-M1\", true, BuildType.OPEN_SOURCE,\n\t\t\t\tnull, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"url-artifact-repository\", \"https://repo.maven.apache.org/maven2\");\n\t}\n\n\t@Test\n\tvoid urlArtifactRepositoryWhenSnapshot() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-SNAPSHOT\", true,\n\t\t\t\tBuildType.OPEN_SOURCE, null, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"url-artifact-repository\", \"https://repo.spring.io/snapshot\");\n\t}\n\n\t@Test\n\tvoid artifactReleaseTypeWhenOpenSourceRelease() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.OPEN_SOURCE, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"artifact-release-type\", \"release\");\n\t\tassertThat(attributes.get()).containsEntry(\"build-and-artifact-release-type\", \"opensource-release\");\n\t}\n\n\t@Test\n\tvoid artifactReleaseTypeWhenOpenSourceMilestone() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-M1\", true, BuildType.OPEN_SOURCE,\n\t\t\t\tnull, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"artifact-release-type\", \"milestone\");\n\t\tassertThat(attributes.get()).containsEntry(\"build-and-artifact-release-type\", \"opensource-milestone\");\n\t}\n\n\t@Test\n\tvoid artifactReleaseTypeWhenOpenSourceSnapshot() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-SNAPSHOT\", true,\n\t\t\t\tBuildType.OPEN_SOURCE, null, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"artifact-release-type\", \"snapshot\");\n\t\tassertThat(attributes.get()).containsEntry(\"build-and-artifact-release-type\", \"opensource-snapshot\");\n\t}\n\n\t@Test\n\tvoid artifactReleaseTypeWhenCommercialRelease() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3\", true, BuildType.COMMERCIAL, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"artifact-release-type\", \"release\");\n\t\tassertThat(attributes.get()).containsEntry(\"build-and-artifact-release-type\", \"commercial-release\");\n\t}\n\n\t@Test\n\tvoid artifactReleaseTypeWhenCommercialMilestone() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-M1\", true, BuildType.COMMERCIAL, null,\n\t\t\t\tmockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"artifact-release-type\", \"milestone\");\n\t\tassertThat(attributes.get()).containsEntry(\"build-and-artifact-release-type\", \"commercial-milestone\");\n\t}\n\n\t@Test\n\tvoid artifactReleaseTypeWhenCommercialSnapshot() {\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3-SNAPSHOT\", true, BuildType.COMMERCIAL,\n\t\t\t\tnull, mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"artifact-release-type\", \"snapshot\");\n\t\tassertThat(attributes.get()).containsEntry(\"build-and-artifact-release-type\", \"commercial-snapshot\");\n\t}\n\n\t@Test\n\tvoid urlLinksFromLibrary() {\n\t\tMap<String, List<Link>> links = new LinkedHashMap<>();\n\t\tlinks.put(\"site\", singleLink((version) -> \"https://example.com/site/\" + version));\n\t\tlinks.put(\"docs\", singleLink((version) -> \"https://example.com/docs/\" + version));\n\t\tlinks.put(\"javadoc\",\n\t\t\t\tsingleLink((version) -> \"https://example.com/api/\" + version, \"org.springframework.[core|util]\"));\n\t\tLibrary library = mockLibrary(links);\n\t\tAntoraAsciidocAttributes attributes = new AntoraAsciidocAttributes(\"1.2.3.1-SNAPSHOT\", false,\n\t\t\t\tBuildType.OPEN_SOURCE, List.of(library), mockDependencyVersions(), null);\n\t\tassertThat(attributes.get()).containsEntry(\"url-spring-framework-site\", \"https://example.com/site/1.2.3\")\n\t\t\t.containsEntry(\"url-spring-framework-docs\", \"https://example.com/docs/1.2.3\")\n\t\t\t.containsEntry(\"url-spring-framework-javadoc\", \"https://example.com/api/1.2.3\");\n\t\tassertThat(attributes.get())\n\t\t\t.containsEntry(\"javadoc-location-org-springframework-core\", \"{url-spring-framework-javadoc}\")\n\t\t\t.containsEntry(\"javadoc-location-org-springframework-util\", \"{url-spring-framework-javadoc}\");\n\t}\n\n\tprivate List<Link> singleLink(Function<LibraryVersion, String> factory, String... packages) {\n\t\tLink link = new Link(null, factory, List.of(packages));\n\t\treturn List.of(link);\n\t}\n\n\t@Test\n\tvoid linksFromProperties() {\n\t\tMap<String, String> attributes = new AntoraAsciidocAttributes(\"1.2.3-SNAPSHOT\", true, BuildType.OPEN_SOURCE,\n\t\t\t\tnull, mockDependencyVersions(), null)\n\t\t\t.get();\n\t\tassertThat(attributes).containsEntry(\"include-java\", \"ROOT:example$java/org/springframework/boot/docs\");\n\t\tassertThat(attributes).containsEntry(\"url-spring-data-cassandra-site\",\n\t\t\t\t\"https://spring.io/projects/spring-data-cassandra\");\n\t\tList<String> keys = new ArrayList<>(attributes.keySet());\n\t\tassertThat(keys.indexOf(\"include-java\")).isLessThan(keys.indexOf(\"code-spring-boot-latest\"));\n\t}\n\n\tprivate Library mockLibrary(Map<String, List<Link>> links) {\n\t\tString name = \"Spring Framework\";\n\t\tString calendarName = null;\n\t\tLibraryVersion version = new LibraryVersion(DependencyVersion.parse(\"1.2.3\"));\n\t\tList<Group> groups = Collections.emptyList();\n\t\tList<ProhibitedVersion> prohibitedVersion = Collections.emptyList();\n\t\tboolean considerSnapshots = false;\n\t\tVersionAlignment versionAlignment = null;\n\t\tBomAlignment alignsWithBom = null;\n\t\tString linkRootName = null;\n\t\tLibrary library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots,\n\t\t\t\tversionAlignment, alignsWithBom, linkRootName, links);\n\t\treturn library;\n\t}\n\n\tprivate Map<String, String> mockDependencyVersions() {\n\t\treturn mockDependencyVersions(\"1.2.3\");\n\t}\n\n\tprivate Map<String, String> mockDependencyVersions(String version) {\n\t\tMap<String, String> versions = new LinkedHashMap<>();\n\t\taddMockSpringDataVersion(versions, \"spring-data-commons\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-cassandra\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-couchbase\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-elasticsearch\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-jdbc\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-jpa\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-mongodb\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-neo4j\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-r2dbc\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-redis\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-rest-core\", version);\n\t\taddMockSpringDataVersion(versions, \"spring-data-ldap\", version);\n\t\taddMockTestcontainersVersion(versions, \"activemq\", version);\n\t\taddMockTestcontainersVersion(versions, \"cassandra\", version);\n\t\taddMockTestcontainersVersion(versions, \"clickhouse\", version);\n\t\taddMockTestcontainersVersion(versions, \"couchbase\", version);\n\t\taddMockTestcontainersVersion(versions, \"elasticsearch\", version);\n\t\taddMockTestcontainersVersion(versions, \"grafana\", version);\n\t\taddMockTestcontainersVersion(versions, \"jdbc\", version);\n\t\taddMockTestcontainersVersion(versions, \"kafka\", version);\n\t\taddMockTestcontainersVersion(versions, \"mariadb\", version);\n\t\taddMockTestcontainersVersion(versions, \"mongodb\", version);\n\t\taddMockTestcontainersVersion(versions, \"mssqlserver\", version);\n\t\taddMockTestcontainersVersion(versions, \"mysql\", version);\n\t\taddMockTestcontainersVersion(versions, \"neo4j\", version);\n\t\taddMockTestcontainersVersion(versions, \"oracle-xe\", version);\n\t\taddMockTestcontainersVersion(versions, \"oracle-free\", version);\n\t\taddMockTestcontainersVersion(versions, \"postgresql\", version);\n\t\taddMockTestcontainersVersion(versions, \"pulsar\", version);\n\t\taddMockTestcontainersVersion(versions, \"rabbitmq\", version);\n\t\taddMockTestcontainersVersion(versions, \"redpanda\", version);\n\t\taddMockTestcontainersVersion(versions, \"r2dbc\", version);\n\t\taddMockJackson2CoreVersion(versions, \"jackson-annotations\", version);\n\t\taddMockJackson2CoreVersion(versions, \"jackson-databind\", version);\n\t\taddMockJacksonCoreVersion(versions, \"jackson-core\", version);\n\t\taddMockJacksonCoreVersion(versions, \"jackson-databind\", version);\n\t\taddMockJacksonCoreVersion(versions, \"jackson-databind\", version);\n\t\tversions.put(\"org.apache.pulsar:pulsar-client-api\", version);\n\t\tversions.put(\"tools.jackson.dataformat:jackson-dataformat-xml\", version);\n\t\treturn versions;\n\t}\n\n\tprivate void addMockSpringDataVersion(Map<String, String> versions, String artifactId, String version) {\n\t\tversions.put(\"org.springframework.data:\" + artifactId, version);\n\t}\n\n\tprivate void addMockTestcontainersVersion(Map<String, String> versions, String artifactId, String version) {\n\t\tversions.put(\"org.testcontainers:\" + artifactId, version);\n\t}\n\n\tprivate void addMockJackson2CoreVersion(Map<String, String> versions, String artifactId, String version) {\n\t\tversions.put(\"com.fasterxml.jackson.core:\" + artifactId, version);\n\t}\n\n\tprivate void addMockJacksonCoreVersion(Map<String, String> versions, String artifactId, String version) {\n\t\tversions.put(\"tools.jackson.core:\" + artifactId, version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/antora/GenerateAntoraPlaybookTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.antora;\n\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.List;\n\nimport org.gradle.api.Project;\nimport org.gradle.testfixtures.ProjectBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.build.antora.Extensions.AntoraExtensionsConfiguration.ZipContentsCollector.AlwaysInclude;\nimport org.springframework.boot.build.antora.GenerateAntoraPlaybook.AntoraExtensions.ZipContentsCollector;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GenerateAntoraPlaybook}.\n *\n * @author Phillip Webb\n */\nclass GenerateAntoraPlaybookTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid writePlaybookGeneratesExpectedContent() throws Exception {\n\t\twritePlaybookYml((task) -> {\n\t\t\ttask.getAntoraExtensions().getXref().getStubs().addAll(\"appendix:.*\", \"api:.*\", \"reference:.*\");\n\t\t\tZipContentsCollector zipContentsCollector = task.getAntoraExtensions().getZipContentsCollector();\n\t\t\tzipContentsCollector.getAlwaysInclude().set(List.of(new AlwaysInclude(\"test\", \"local-aggregate-content\")));\n\t\t\tzipContentsCollector.getDependencies().add(\"test-dependency\");\n\t\t});\n\t\tString actual = Files.readString(this.temp.toPath()\n\t\t\t.resolve(\"rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml\"));\n\t\tString expected = Files\n\t\t\t.readString(Path.of(\"src/test/resources/org/springframework/boot/build/antora/expected-playbook.yml\"));\n\t\tassertThat(actual.replace('\\\\', '/')).isEqualToNormalizingNewlines(expected.replace('\\\\', '/'));\n\t}\n\n\t@Test\n\tvoid writePlaybookWhenHasJavadocExcludeGeneratesExpectedContent() throws Exception {\n\t\twritePlaybookYml((task) -> {\n\t\t\ttask.getAntoraExtensions().getXref().getStubs().addAll(\"appendix:.*\", \"api:.*\", \"reference:.*\");\n\t\t\tZipContentsCollector zipContentsCollector = task.getAntoraExtensions().getZipContentsCollector();\n\t\t\tzipContentsCollector.getAlwaysInclude().set(List.of(new AlwaysInclude(\"test\", \"local-aggregate-content\")));\n\t\t\tzipContentsCollector.getDependencies().add(\"test-dependency\");\n\t\t\ttask.getAsciidocExtensions().getExcludeJavadocExtension().set(true);\n\t\t});\n\t\tString actual = Files.readString(this.temp.toPath()\n\t\t\t.resolve(\"rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml\"));\n\t\tassertThat(actual).doesNotContain(\"javadoc-extension\");\n\t}\n\n\tprivate void writePlaybookYml(ThrowingConsumer<GenerateAntoraPlaybook> customizer) throws Exception {\n\t\tFile rootProjectDir = new File(this.temp, \"rootproject\").getCanonicalFile();\n\t\trootProjectDir.mkdirs();\n\t\tProject rootProject = ProjectBuilder.builder().withProjectDir(rootProjectDir).build();\n\t\tFile projectDir = new File(rootProjectDir, \"project\");\n\t\tprojectDir.mkdirs();\n\t\tProject project = ProjectBuilder.builder().withProjectDir(projectDir).withParent(rootProject).build();\n\t\tproject.getTasks()\n\t\t\t.register(\"generateAntoraPlaybook\", GenerateAntoraPlaybook.class, customizer::accept)\n\t\t\t.get()\n\t\t\t.writePlaybookYml();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/ArchitectureCheckTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.NoSuchFileException;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.UnaryOperator;\nimport java.util.stream.Collectors;\n\nimport org.gradle.api.tasks.SourceSet;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.gradle.testkit.runner.UnexpectedBuildFailure;\nimport org.gradle.testkit.runner.UnexpectedBuildSuccess;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;\nimport org.springframework.boot.build.architecture.annotations.TestConditionalOnMissingBean;\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationPropertiesBinding;\nimport org.springframework.boot.build.architecture.annotations.TestDeprecatedConfigurationProperty;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArchitectureCheck}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Ivan Malutin\n * @author Dmytro Nosan\n * @author Stefano Cordio\n */\nclass ArchitectureCheckTests {\n\n\tprivate static final String ASSERTJ_CORE = \"org.assertj:assertj-core:3.27.4\";\n\n\tprivate static final String JUNIT_JUPITER = \"org.junit.jupiter:junit-jupiter:5.12.0\";\n\n\tprivate static final String SPRING_CONTEXT = \"org.springframework:spring-context:6.2.15\";\n\n\tprivate static final String SPRING_CORE = \"org.springframework:spring-core:6.2.15\";\n\n\tprivate static final String SPRING_INTEGRATION_JMX = \"org.springframework.integration:spring-integration-jmx:6.5.1\";\n\n\tprivate GradleBuild gradleBuild;\n\n\t@BeforeEach\n\tvoid setup(@TempDir Path projectDir) {\n\t\tthis.gradleBuild = new GradleBuild(projectDir);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenPackagesAreTangledShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"tangled\");\n\t\tbuildAndFail(this.gradleBuild, task, \"slices matching '(**)' should be free of cycles\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenPackagesAreNotTangledShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"untangled\");\n\t\tbuild(this.gradleBuild, task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanPostProcessorBeanMethodIsNotStaticShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"bpp/nonstatic\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT), task,\n\t\t\t\t\"methods that are annotated with @Bean and have raw return type assignable\"\n\t\t\t\t\t\t+ \" to org.springframework.beans.factory.config.BeanPostProcessor\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanPostProcessorBeanMethodIsStaticAndHasUnsafeParametersShouldFailAndWriteReport(Task task)\n\t\t\tthrows IOException {\n\t\tprepareTask(task, \"bpp/unsafeparameters\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT), task,\n\t\t\t\t\"methods that are annotated with @Bean and have raw return type assignable\"\n\t\t\t\t\t\t+ \" to org.springframework.beans.factory.config.BeanPostProcessor\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanPostProcessorBeanMethodIsStaticAndHasSafeParametersShouldSucceedAndWriteEmptyReport(Task task)\n\t\t\tthrows IOException {\n\t\tprepareTask(task, \"bpp/safeparameters\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanPostProcessorBeanMethodIsStaticAndHasNoParametersShouldSucceedAndWriteEmptyReport(Task task)\n\t\t\tthrows IOException {\n\t\tprepareTask(task, \"bpp/noparameters\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanFactoryPostProcessorBeanMethodIsNotStaticShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"bfpp/nonstatic\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT), task,\n\t\t\t\t\"methods that are annotated with @Bean and have raw return type assignable\"\n\t\t\t\t\t\t+ \" to org.springframework.beans.factory.config.BeanFactoryPostProcessor\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanFactoryPostProcessorBeanMethodIsStaticAndHasParametersShouldFailAndWriteReport(Task task)\n\t\t\tthrows IOException {\n\t\tprepareTask(task, \"bfpp/parameters\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT), task,\n\t\t\t\t\"methods that are annotated with @Bean and have raw return type assignable\"\n\t\t\t\t\t\t+ \" to org.springframework.beans.factory.config.BeanFactoryPostProcessor\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanFactoryPostProcessorBeanMethodIsStaticAndHasNoParametersShouldSucceedAndWriteEmptyReport(Task task)\n\t\t\tthrows IOException {\n\t\tprepareTask(task, \"bfpp/noparameters\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassLoadsResourceUsingResourceUtilsShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"resources/loads\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT), task,\n\t\t\t\t\"no classes should call method where target owner type\"\n\t\t\t\t\t\t+ \" org.springframework.util.ResourceUtils and target name 'getURL'\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassUsesResourceUtilsWithoutLoadingResourcesShouldSucceedAndWriteEmptyReport(Task task)\n\t\t\tthrows IOException {\n\t\tprepareTask(task, \"resources/noloads\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassDoesNotCallObjectsRequireNonNullShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"objects/noRequireNonNull\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsObjectsRequireNonNullWithMessageShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"objects/requireNonNullWithString\");\n\t\tbuildAndFail(this.gradleBuild, task, \"no classes should call method Objects.requireNonNull(Object, String)\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsObjectsRequireNonNullWithMessageAndProhibitObjectsRequireNonNullIsFalseShouldSucceedAndWriteEmptyReport(\n\t\t\tTask task) throws IOException {\n\t\tprepareTask(task, \"objects/requireNonNullWithString\");\n\t\tbuild(this.gradleBuild.withProhibitObjectsRequireNonNull(false), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsObjectsRequireNonNullWithSupplierShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"objects/requireNonNullWithSupplier\");\n\t\tbuildAndFail(this.gradleBuild, task, \"no classes should call method Objects.requireNonNull(Object, Supplier)\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsObjectsRequireNonNullWithSupplierAndProhibitObjectsRequireNonNullIsFalseShouldSucceedAndWriteEmptyReport(\n\t\t\tTask task) throws IOException {\n\t\tprepareTask(task, \"objects/requireNonNullWithSupplier\");\n\t\tbuild(this.gradleBuild.withProhibitObjectsRequireNonNull(false), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsCollectorsToListShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"collectors/toList\");\n\t\tbuildAndFail(this.gradleBuild, task, \"because java.util.stream.Stream.toList() should be used instead\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsUrlEncoderWithStringEncodingShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"url/encode\");\n\t\tbuildAndFail(this.gradleBuild, task,\n\t\t\t\t\"because java.net.URLEncoder.encode(String s, Charset charset) should be used instead\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsUrlDecoderWithStringEncodingShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"url/decode\");\n\t\tbuildAndFail(this.gradleBuild, task,\n\t\t\t\t\"because java.net.URLDecoder.decode(String s, Charset charset) should be used instead\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsStringToUpperCaseWithoutLocaleShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"string/toUpperCase\");\n\t\tbuildAndFail(this.gradleBuild, task, \"because String.toUpperCase(Locale.ROOT) should be used instead\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsStringToLowerCaseWithoutLocaleShouldFailAndWriteReport(Task task) throws IOException {\n\t\tprepareTask(task, \"string/toLowerCase\");\n\t\tbuildAndFail(this.gradleBuild, task, \"because String.toLowerCase(Locale.ROOT) should be used instead\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsStringToLowerCaseWithLocaleShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"string/toLowerCaseWithLocale\");\n\t\tbuild(this.gradleBuild, task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenClassCallsStringToUpperCaseWithLocaleShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"string/toUpperCaseWithLocale\");\n\t\tbuild(this.gradleBuild, task);\n\t}\n\n\t@Test\n\tvoid whenConditionalOnMissingBeanWithTypeSameAsMethodReturnTypeShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"conditionalonmissingbean/valueonly\", \"annotations\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConditionalOnMissingBeanAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"should not specify only a value that is the same as the method's return type\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenConditionalOnMissingBeanWithTypeAttributeShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"conditionalonmissingbean/withtype\", \"annotations\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenConditionalOnMissingBeanWithNameAttributeShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"conditionalonmissingbean/withname\", \"annotations\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@Test\n\tvoid whenClassLevelConfigurationPropertiesContainsOnlyPrefixShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/classprefixonly\", \"annotations\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"should specify implicit 'value' attribute other than explicit 'prefix' attribute\");\n\t}\n\n\t@Test\n\tvoid whenClassLevelConfigurationPropertiesContainsPrefixAndIgnoreShouldSucceedAndWriteEmptyReport()\n\t\t\tthrows IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/classprefixandignore\", \"annotations\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN);\n\t}\n\n\t@Test\n\tvoid whenClassLevelConfigurationPropertiesContainsOnlyValueShouldSucceedAndWriteEmptyReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/classvalueonly\", \"annotations\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN);\n\t}\n\n\t@Test\n\tvoid whenMethodLevelConfigurationPropertiesContainsOnlyPrefixShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/methodprefixonly\", \"annotations\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"should specify implicit 'value' attribute other than explicit 'prefix' attribute\");\n\t}\n\n\t@Test\n\tvoid whenMethodLevelConfigurationPropertiesContainsPrefixAndIgnoreShouldSucceedAndWriteEmptyReport()\n\t\t\tthrows IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/methodprefixandignore\", \"annotations\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN);\n\t}\n\n\t@Test\n\tvoid whenMethodLevelConfigurationPropertiesContainsOnlyValueShouldSucceedAndWriteEmptyReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/methodvalueonly\", \"annotations\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN);\n\t}\n\n\t@Test\n\tvoid whenConfigurationPropertiesBindingBeanMethodIsNotStaticShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/bindingnonstatic\", \"annotations\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT).withConfigurationPropertiesBindingAnnotation(),\n\t\t\t\tTask.CHECK_ARCHITECTURE_MAIN, \"does not have modifier STATIC\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanPostProcessorBeanMethodIsNotStaticWithExternalClassShouldFailAndWriteReport(Task task)\n\t\t\tthrows IOException {\n\t\tPath sourceDirectory = task.getSourceDirectory(this.gradleBuild.getProjectDir())\n\t\t\t.resolve(ClassUtils.classPackageAsResourcePath(getClass()));\n\t\tFiles.createDirectories(sourceDirectory);\n\t\tFiles.writeString(sourceDirectory.resolve(\"TestClass.java\"), \"\"\"\n\t\t\t\tpackage %s;\n\t\t\t\timport org.springframework.context.annotation.Bean;\n\t\t\t\timport org.springframework.integration.monitor.IntegrationMBeanExporter;\n\t\t\t\tpublic class TestClass {\n\t\t\t\t\t@Bean\n\t\t\t\t\tIntegrationMBeanExporter integrationMBeanExporter() {\n\t\t\t\t\t\treturn new IntegrationMBeanExporter();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\"\"\".formatted(ClassUtils.getPackageName(getClass())));\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_INTEGRATION_JMX), task,\n\t\t\t\t\"methods that are annotated with @Bean and have raw return type assignable \"\n\t\t\t\t\t\t+ \"to org.springframework.beans.factory.config.BeanPostProcessor\");\n\t}\n\n\t@Test\n\tvoid whenBeanMethodExposesPrivateTypeWithMainSourcesShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"beans/privatebean\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(SPRING_CONTEXT), Task.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"methods that are annotated with @Bean should not return types declared \"\n\t\t\t\t\t\t+ \"with the PRIVATE modifier, as such types are incompatible with Spring AOT processing\",\n\t\t\t\t\"returns Class <org.springframework.boot.build.architecture.beans.privatebean.PrivateBean$MyBean>\"\n\t\t\t\t\t\t+ \" which is declared as [PRIVATE, STATIC, FINAL]\");\n\t}\n\n\t@Test\n\tvoid whenBeanMethodExposesPrivateTypeWithTestsSourcesShouldSucceedAndWriteEmptyReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_TEST, \"beans/privatebean\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), Task.CHECK_ARCHITECTURE_TEST);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@EnumSource(Task.class)\n\tvoid whenBeanMethodExposesNonPrivateTypeShouldSucceedAndWriteEmptyReport(Task task) throws IOException {\n\t\tprepareTask(task, \"beans/regular\");\n\t\tbuild(this.gradleBuild.withDependencies(SPRING_CONTEXT), task);\n\t}\n\n\t@Test\n\tvoid whenEnumSourceValueIsInferredShouldSucceedAndWriteEmptyReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_TEST, \"junit/enumsource/inferredfromparametertype\");\n\t\tbuild(this.gradleBuild.withDependencies(JUNIT_JUPITER), Task.CHECK_ARCHITECTURE_TEST);\n\t}\n\n\t@Test\n\tvoid whenEnumSourceValueIsNotTheSameAsTypeOfMethodsFirstParameterShouldSucceedAndWriteEmptyReport()\n\t\t\tthrows IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_TEST, \"junit/enumsource/valuenecessary\");\n\t\tbuild(this.gradleBuild.withDependencies(JUNIT_JUPITER), Task.CHECK_ARCHITECTURE_TEST);\n\t}\n\n\t@Test\n\tvoid whenEnumSourceValueIsSameAsTypeOfMethodsFirstParameterShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_TEST, \"junit/enumsource/sameasparametertype\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(JUNIT_JUPITER), Task.CHECK_ARCHITECTURE_TEST,\n\t\t\t\t\"method <org.springframework.boot.build.architecture.junit.enumsource.sameasparametertype\"\n\t\t\t\t\t\t+ \".EnumSourceSameAsParameterType.exampleMethod(org.springframework.boot.build.\"\n\t\t\t\t\t\t+ \"architecture.junit.enumsource.sameasparametertype.EnumSourceSameAsParameterType$Example)>\",\n\t\t\t\t\"should not have a value that is the same as the type of the method's first parameter\");\n\t}\n\n\t@Test\n\tvoid whenConditionalOnClassUsedOnBeanMethodsWithMainSourcesShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"conditionalonclass\", \"annotations\");\n\t\tGradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT).withConditionalOnClassAnnotation();\n\t\tbuildAndFail(gradleBuild, Task.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"because @ConditionalOnClass on @Bean methods is ineffective - it doesn't prevent\"\n\t\t\t\t\t\t+ \" the method signature from being loaded. Such condition need to be placed\"\n\t\t\t\t\t\t+ \" on a @Configuration class, allowing the condition to back off before the type is loaded\");\n\t}\n\n\t@Test\n\tvoid whenConditionalOnClassUsedOnBeanMethodsWithTestSourcesShouldSucceedAndWriteEmptyReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_TEST, \"conditionalonclass\", \"annotations\");\n\t\tGradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT).withConditionalOnClassAnnotation();\n\t\tbuild(gradleBuild, Task.CHECK_ARCHITECTURE_TEST);\n\t}\n\n\t@Test\n\tvoid whenDeprecatedConfigurationPropertyIsMissingSinceShouldFailAndWriteReport() throws IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"configurationproperties/deprecatedsince\", \"annotations\");\n\t\tGradleBuild gradleBuild = this.gradleBuild.withDependencies(SPRING_CONTEXT)\n\t\t\t.withDeprecatedConfigurationPropertyAnnotation();\n\t\tbuildAndFail(gradleBuild, Task.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"should include a non-empty 'since' attribute of @DeprecatedConfigurationProperty\",\n\t\t\t\t\"DeprecatedConfigurationPropertySince.getProperty\");\n\t}\n\n\t@Test\n\tvoid whenCustomAssertionMethodNotReturningSelfIsAnnotatedWithCheckReturnValueShouldSucceedAndWriteEmptyReport()\n\t\t\tthrows IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"assertj/checkReturnValue\");\n\t\tbuild(this.gradleBuild.withDependencies(ASSERTJ_CORE, SPRING_CORE), Task.CHECK_ARCHITECTURE_MAIN);\n\t}\n\n\t@Test\n\tvoid whenCustomAssertionMethodNotReturningSelfIsNotAnnotatedWithCheckReturnValueShouldFailAndWriteReport()\n\t\t\tthrows IOException {\n\t\tprepareTask(Task.CHECK_ARCHITECTURE_MAIN, \"assertj/noCheckReturnValue\");\n\t\tbuildAndFail(this.gradleBuild.withDependencies(ASSERTJ_CORE), Task.CHECK_ARCHITECTURE_MAIN,\n\t\t\t\t\"methods that are declared in classes that implement org.assertj.core.api.Assert and \"\n\t\t\t\t\t\t+ \"are public and do not have modifier BRIDGE and do not return self type should be annotated \"\n\t\t\t\t\t\t+ \"with @CheckReturnValue\");\n\t}\n\n\tprivate void prepareTask(Task task, String... sourceDirectories) throws IOException {\n\t\tfor (String sourceDirectory : sourceDirectories) {\n\t\t\tFileSystemUtils.copyRecursively(\n\t\t\t\t\tPaths.get(\"src/test/java\")\n\t\t\t\t\t\t.resolve(ClassUtils.classPackageAsResourcePath(getClass()))\n\t\t\t\t\t\t.resolve(sourceDirectory),\n\t\t\t\t\ttask.getSourceDirectory(this.gradleBuild.getProjectDir())\n\t\t\t\t\t\t.resolve(ClassUtils.classPackageAsResourcePath(getClass()))\n\t\t\t\t\t\t.resolve(sourceDirectory));\n\t\t}\n\t}\n\n\tprivate void build(GradleBuild gradleBuild, Task task) throws IOException {\n\t\ttry {\n\t\t\tBuildResult buildResult = gradleBuild.build(task.toString());\n\t\t\tassertThat(buildResult.taskPaths(TaskOutcome.SUCCESS)).as(buildResult.getOutput()).contains(\":\" + task);\n\t\t\tassertThat(task.getFailureReport(gradleBuild.getProjectDir())).isEmpty();\n\t\t}\n\t\tcatch (UnexpectedBuildFailure ex) {\n\t\t\tStringBuilder message = new StringBuilder(\"Expected build to succeed but it failed\");\n\t\t\tif (Files.exists(task.getFailureReportFile(gradleBuild.getProjectDir()))) {\n\t\t\t\tmessage.append('\\n').append(task.getFailureReport(gradleBuild.getProjectDir()));\n\t\t\t}\n\t\t\tmessage.append('\\n').append(ex.getBuildResult().getOutput());\n\t\t\tthrow new AssertionError(message.toString(), ex);\n\t\t}\n\t}\n\n\tprivate void buildAndFail(GradleBuild gradleBuild, Task task, String... messages) throws IOException {\n\t\ttry {\n\t\t\tBuildResult buildResult = gradleBuild.buildAndFail(task.toString());\n\t\t\tassertThat(buildResult.taskPaths(TaskOutcome.FAILED)).as(buildResult.getOutput()).contains(\":\" + task);\n\t\t\ttry {\n\t\t\t\tassertThat(task.getFailureReport(gradleBuild.getProjectDir())).contains(messages);\n\t\t\t}\n\t\t\tcatch (NoSuchFileException ex) {\n\t\t\t\tthrow new AssertionError(\"Expected failure report not found\\n\" + buildResult.getOutput());\n\t\t\t}\n\t\t}\n\t\tcatch (UnexpectedBuildSuccess ex) {\n\t\t\tthrow new AssertionError(\"Expected build to fail but it succeeded\\n\" + ex.getBuildResult().getOutput(), ex);\n\t\t}\n\t}\n\n\tprivate enum Task {\n\n\t\tCHECK_ARCHITECTURE_MAIN(SourceSet.MAIN_SOURCE_SET_NAME),\n\n\t\tCHECK_ARCHITECTURE_TEST(SourceSet.TEST_SOURCE_SET_NAME);\n\n\t\tprivate final String sourceSetName;\n\n\t\tTask(String sourceSetName) {\n\t\t\tthis.sourceSetName = sourceSetName;\n\t\t}\n\n\t\tString getFailureReport(Path projectDir) throws IOException {\n\t\t\treturn Files.readString(getFailureReportFile(projectDir), StandardCharsets.UTF_8);\n\t\t}\n\n\t\tPath getFailureReportFile(Path projectDir) {\n\t\t\treturn projectDir.resolve(\"build/%s/failure-report.txt\".formatted(toString()));\n\t\t}\n\n\t\tPath getSourceDirectory(Path projectDir) {\n\t\t\treturn projectDir.resolve(\"src/%s/java\".formatted(this.sourceSetName));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"checkArchitecture\" + StringUtils.capitalize(this.sourceSetName) + \"Java\";\n\t\t}\n\n\t}\n\n\tprivate static final class GradleBuild {\n\n\t\tprivate final Path projectDir;\n\n\t\tprivate final Set<String> dependencies = new LinkedHashSet<>();\n\n\t\tprivate final Map<Task, TaskConfiguration> taskConfigurations = new LinkedHashMap<>();\n\n\t\tprivate GradleBuild(Path projectDir) {\n\t\t\tthis.projectDir = projectDir;\n\t\t}\n\n\t\tPath getProjectDir() {\n\t\t\treturn this.projectDir;\n\t\t}\n\n\t\tGradleBuild withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {\n\t\t\tfor (Task task : Task.values()) {\n\t\t\t\tconfigureTask(task, (configuration) -> configuration\n\t\t\t\t\t.withProhibitObjectsRequireNonNull(prohibitObjectsRequireNonNull));\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tGradleBuild withConditionalOnClassAnnotation() {\n\t\t\tconfigureTasks(ArchitectureCheckAnnotation.CONDITIONAL_ON_CLASS.name(),\n\t\t\t\t\tTestConditionalOnClass.class.getName());\n\t\t\treturn this;\n\t\t}\n\n\t\tGradleBuild withConditionalOnMissingBeanAnnotation() {\n\t\t\tconfigureTasks(ArchitectureCheckAnnotation.CONDITIONAL_ON_MISSING_BEAN.name(),\n\t\t\t\t\tTestConditionalOnMissingBean.class.getName());\n\t\t\treturn this;\n\t\t}\n\n\t\tGradleBuild withConfigurationPropertiesAnnotation() {\n\t\t\tconfigureTasks(ArchitectureCheckAnnotation.CONFIGURATION_PROPERTIES.name(),\n\t\t\t\t\tTestConfigurationProperties.class.getName());\n\t\t\treturn this;\n\t\t}\n\n\t\tGradleBuild withConfigurationPropertiesBindingAnnotation() {\n\t\t\tconfigureTasks(ArchitectureCheckAnnotation.CONFIGURATION_PROPERTIES_BINDING.name(),\n\t\t\t\t\tTestConfigurationPropertiesBinding.class.getName());\n\t\t\treturn this;\n\t\t}\n\n\t\tGradleBuild withDeprecatedConfigurationPropertyAnnotation() {\n\t\t\tconfigureTasks(ArchitectureCheckAnnotation.DEPRECATED_CONFIGURATION_PROPERTY.name(),\n\t\t\t\t\tTestDeprecatedConfigurationProperty.class.getName());\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate void configureTasks(String annotationName, String annotationClass) {\n\t\t\tfor (Task task : Task.values()) {\n\t\t\t\tconfigureTask(task, (configuration) -> configuration.withAnnotation(annotationName, annotationClass));\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureTask(Task task, UnaryOperator<TaskConfiguration> configurer) {\n\t\t\tthis.taskConfigurations.computeIfAbsent(task, (key) -> new TaskConfiguration(null, null));\n\t\t\tthis.taskConfigurations.compute(task, (key, value) -> configurer.apply(value));\n\t\t}\n\n\t\tGradleBuild withDependencies(String... dependencies) {\n\t\t\tthis.dependencies.clear();\n\t\t\tthis.dependencies.addAll(Arrays.asList(dependencies));\n\t\t\treturn this;\n\t\t}\n\n\t\tBuildResult build(String... arguments) throws IOException {\n\t\t\treturn prepareRunner(arguments).build();\n\t\t}\n\n\t\tBuildResult buildAndFail(String... arguments) throws IOException {\n\t\t\treturn prepareRunner(arguments).buildAndFail();\n\t\t}\n\n\t\tprivate GradleRunner prepareRunner(String... arguments) throws IOException {\n\t\t\tStringBuilder buildFile = new StringBuilder();\n\t\t\tbuildFile.append(\"plugins {\\n\")\n\t\t\t\t.append(\"    id 'java'\\n\")\n\t\t\t\t.append(\"    id 'org.springframework.boot.architecture'\\n\")\n\t\t\t\t.append(\"}\\n\\n\")\n\t\t\t\t.append(\"repositories {\\n\")\n\t\t\t\t.append(\"    mavenCentral()\\n\")\n\t\t\t\t.append(\"}\\n\\n\")\n\t\t\t\t.append(\"java {\\n\")\n\t\t\t\t.append(\"    sourceCompatibility = '17'\\n\")\n\t\t\t\t.append(\"    targetCompatibility = '17'\\n\")\n\t\t\t\t.append(\"}\\n\\n\");\n\t\t\tif (!this.dependencies.isEmpty()) {\n\t\t\t\tbuildFile.append(\"dependencies {\\n\");\n\t\t\t\tfor (String dependency : this.dependencies) {\n\t\t\t\t\tbuildFile.append(\"\\n    implementation \").append(StringUtils.quote(dependency));\n\t\t\t\t}\n\t\t\t\tbuildFile.append(\"\\n}\\n\\n\");\n\t\t\t}\n\t\t\tthis.taskConfigurations.forEach((task, configuration) -> {\n\t\t\t\tbuildFile.append(task).append(\" {\");\n\t\t\t\tif (configuration.prohibitObjectsRequireNonNull() != null) {\n\t\t\t\t\tbuildFile.append(\"\\n    prohibitObjectsRequireNonNull = \")\n\t\t\t\t\t\t.append(configuration.prohibitObjectsRequireNonNull());\n\t\t\t\t}\n\t\t\t\tif (configuration.annotations() != null && !configuration.annotations().isEmpty()) {\n\t\t\t\t\tbuildFile.append(\"\\n    annotationClasses = \")\n\t\t\t\t\t\t.append(toGroovyMapString(configuration.annotations()));\n\t\t\t\t}\n\t\t\t\tbuildFile.append(\"\\n}\\n\");\n\t\t\t});\n\t\t\tFiles.writeString(this.projectDir.resolve(\"build.gradle\"), buildFile, StandardCharsets.UTF_8);\n\t\t\treturn GradleRunner.create()\n\t\t\t\t.withProjectDir(this.projectDir.toFile())\n\t\t\t\t.withArguments(arguments)\n\t\t\t\t.withPluginClasspath();\n\t\t}\n\n\t\tstatic String toGroovyMapString(Map<String, String> map) {\n\t\t\treturn map.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.map((entry) -> \"'\" + entry.getKey() + \"' : '\" + entry.getValue() + \"'\")\n\t\t\t\t.collect(Collectors.joining(\", \", \"[\", \"]\"));\n\t\t}\n\n\t\tprivate record TaskConfiguration(Boolean prohibitObjectsRequireNonNull, Map<String, String> annotations) {\n\n\t\t\tpublic TaskConfiguration {\n\t\t\t\tif (annotations == null) {\n\t\t\t\t\tannotations = new HashMap<>();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate TaskConfiguration withProhibitObjectsRequireNonNull(Boolean prohibitObjectsRequireNonNull) {\n\t\t\t\treturn new TaskConfiguration(prohibitObjectsRequireNonNull, this.annotations);\n\t\t\t}\n\n\t\t\tprivate TaskConfiguration withAnnotation(String name, String annotationClass) {\n\t\t\t\tMap<String, String> map = new HashMap<>(this.annotations);\n\t\t\t\tmap.put(name, annotationClass);\n\t\t\t\treturn new TaskConfiguration(this.prohibitObjectsRequireNonNull, map);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestConditionalOnClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * {@code @ConditionalOnClass} analogue for architecture checks.\n *\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TestConditionalOnClass {\n\n\tClass<?>[] value() default {};\n\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestConditionalOnMissingBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.annotations;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * {@code @ConditionalOnMissingBean} analogue for architecture checks.\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TestConditionalOnMissingBean {\n\n\tClass<?>[] value() default {};\n\n\tString[] type() default {};\n\n\tClass<?>[] ignored() default {};\n\n\tString[] ignoredType() default {};\n\n\tClass<? extends Annotation>[] annotation() default {};\n\n\tString[] name() default {};\n\n\tClass<?>[] parameterizedContainer() default {};\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Indexed;\n\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Indexed\npublic @interface TestConfigurationProperties {\n\n\t@AliasFor(\"prefix\")\n\tString value() default \"\";\n\n\t@AliasFor(\"value\")\n\tString prefix() default \"\";\n\n\tboolean ignoreInvalidFields() default false;\n\n\tboolean ignoreUnknownFields() default true;\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestConfigurationPropertiesBinding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TestConfigurationPropertiesBinding {\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/annotations/TestDeprecatedConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.annotations;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * {@code @DeprecatedConfigurationProperty} analogue for architecture checks.\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TestDeprecatedConfigurationProperty {\n\n\t/**\n\t * The reason for the deprecation.\n\t * @return the deprecation reason\n\t */\n\tString reason() default \"\";\n\n\t/**\n\t * The field that should be used instead (if any).\n\t * @return the replacement field\n\t */\n\tString replacement() default \"\";\n\n\t/**\n\t * The version in which the property became deprecated.\n\t * @return the version\n\t */\n\tString since() default \"\";\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/checkReturnValue/WithCheckReturnValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.assertj.checkReturnValue;\n\nimport org.assertj.core.api.AbstractAssert;\n\nimport org.springframework.lang.CheckReturnValue;\n\npublic class WithCheckReturnValue extends AbstractAssert<WithCheckReturnValue, Object> {\n\n\tWithCheckReturnValue() {\n\t\tsuper(null, WithCheckReturnValue.class);\n\t}\n\n\t@CheckReturnValue\n\tpublic Object notReturningSelf() {\n\t\treturn new Object();\n\t}\n\n\t@Override\n\tpublic WithCheckReturnValue isEqualTo(Object expected) {\n\t\treturn super.isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/assertj/noCheckReturnValue/NoCheckReturnValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.assertj.noCheckReturnValue;\n\nimport org.assertj.core.api.AbstractAssert;\n\npublic class NoCheckReturnValue extends AbstractAssert<NoCheckReturnValue, Object> {\n\n\tNoCheckReturnValue() {\n\t\tsuper(null, NoCheckReturnValue.class);\n\t}\n\n\tpublic Object notReturningSelf() {\n\t\treturn new Object();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/beans/privatebean/PrivateBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.beans.privatebean;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\nclass PrivateBean {\n\n\t@Bean\n\tstatic MyBean myBean() {\n\t\treturn new MyBean();\n\t}\n\n\tprivate static final class MyBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/beans/regular/RegularBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.beans.regular;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\nclass RegularBean {\n\n\t@Bean\n\tstatic PackagePrivate packagePrivateBean() {\n\t\treturn new PackagePrivate();\n\t}\n\n\t@Bean\n\tstatic Protected protectedBean() {\n\t\treturn new Protected();\n\t}\n\n\t@Bean\n\tstatic Public publicBean() {\n\t\treturn new Public();\n\t}\n\n\tstatic final class PackagePrivate {\n\n\t}\n\n\tprotected static final class Protected {\n\n\t}\n\n\tpublic static final class Public {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bfpp/nonstatic/NonStaticBeanFactoryPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bfpp.nonstatic;\n\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.context.annotation.Bean;\n\nclass NonStaticBeanFactoryPostProcessorConfiguration {\n\n\t@Bean\n\tBeanFactoryPostProcessor nonStaticBeanFactoryPostProcessor() {\n\t\treturn (beanFactory) -> {\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bfpp/noparameters/NoParametersBeanFactoryPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bfpp.noparameters;\n\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.context.annotation.Bean;\n\nclass NoParametersBeanFactoryPostProcessorConfiguration {\n\n\t@Bean\n\tstatic BeanFactoryPostProcessor noParametersBeanFactoryPostProcessor() {\n\t\treturn (beanFactory) -> {\n\t\t};\n\t}\n\n\t@Bean\n\tInteger beanOne() {\n\t\treturn 1;\n\t}\n\n\t@Bean\n\tString beanTwo() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bfpp/parameters/ParametersBeanFactoryPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bfpp.parameters;\n\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.context.annotation.Bean;\n\nclass ParametersBeanFactoryPostProcessorConfiguration {\n\n\t@Bean\n\tstatic BeanFactoryPostProcessor parametersBeanFactoryPostProcessor(Integer param) {\n\t\treturn (beanFactory) -> {\n\t\t};\n\t}\n\n\t@Bean\n\tInteger beanOne() {\n\t\treturn 1;\n\t}\n\n\t@Bean\n\tString beanTwo() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bpp/nonstatic/NonStaticBeanPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bpp.nonstatic;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.context.annotation.Bean;\n\nclass NonStaticBeanPostProcessorConfiguration {\n\n\t@Bean\n\tBeanPostProcessor nonStaticBeanPostProcessor() {\n\t\treturn new BeanPostProcessor() {\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bpp/noparameters/NoParametersBeanPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bpp.noparameters;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.context.annotation.Bean;\n\nclass NoParametersBeanPostProcessorConfiguration {\n\n\t@Bean\n\tstatic BeanPostProcessor noParametersBeanPostProcessor() {\n\t\treturn new BeanPostProcessor() {\n\n\t\t};\n\t}\n\n\t@Bean\n\tInteger beanOne() {\n\t\treturn 1;\n\t}\n\n\t@Bean\n\tString beanTwo() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bpp/safeparameters/SafeParametersBeanPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bpp.safeparameters;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.core.env.Environment;\n\nclass SafeParametersBeanPostProcessorConfiguration {\n\n\t@Bean\n\tstatic BeanPostProcessor safeParametersBeanPostProcessor(ApplicationContext context, ObjectProvider<String> beanOne,\n\t\t\tObjectProvider<String> beanTwo, Environment environment, @Lazy String beanThree) {\n\t\treturn new BeanPostProcessor() {\n\n\t\t};\n\t}\n\n\t@Bean\n\tInteger beanOne() {\n\t\treturn 1;\n\t}\n\n\t@Bean\n\tString beanTwo() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/bpp/unsafeparameters/UnsafeParametersBeanPostProcessorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.bpp.unsafeparameters;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\nclass UnsafeParametersBeanPostProcessorConfiguration {\n\n\t@Bean\n\tstatic BeanPostProcessor unsafeParametersBeanPostProcessor(ApplicationContext context, Integer beanOne,\n\t\t\tString beanTwo) {\n\t\treturn new BeanPostProcessor() {\n\n\t\t};\n\t}\n\n\t@Bean\n\tInteger beanOne() {\n\t\treturn 1;\n\t}\n\n\t@Bean\n\tString beanTwo() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/collectors/toList/CollectorsToList.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.collectors.toList;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nclass CollectorsToList {\n\n\tvoid exampleMethod() {\n\t\tList<String> strings = Stream.of(\"a\", \"b\", \"c\").collect(Collectors.toList());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/conditionalonclass/OnBeanMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.conditionalonclass;\n\nimport org.springframework.boot.build.architecture.annotations.TestConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\n\nclass OnBeanMethod {\n\n\t@Bean\n\t@TestConditionalOnClass(String.class)\n\tString helloWorld() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/conditionalonmissingbean/valueonly/TypeSameAsMethodReturnType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.conditionalonmissingbean.valueonly;\n\nimport org.springframework.boot.build.architecture.annotations.TestConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\nclass TypeSameAsMethodReturnType {\n\n\t@Bean\n\t@TestConditionalOnMissingBean(String.class)\n\tString helloWorld() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/conditionalonmissingbean/withname/WithNameAttribute.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.conditionalonmissingbean.withname;\n\nimport org.springframework.boot.build.architecture.annotations.TestConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\nclass WithNameAttribute {\n\n\t@Bean\n\t@TestConditionalOnMissingBean(name = \"myBean\")\n\tString helloWorld() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/conditionalonmissingbean/withtype/WithTypeAttribute.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.conditionalonmissingbean.withtype;\n\nimport org.springframework.boot.build.architecture.annotations.TestConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\nclass WithTypeAttribute {\n\n\t@Bean\n\t@TestConditionalOnMissingBean(type = \"String\")\n\tString helloWorld() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/bindingnonstatic/BindingMethodNonStatic.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.bindingnonstatic;\n\nimport java.util.List;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationPropertiesBinding;\nimport org.springframework.context.annotation.Bean;\n\npublic class BindingMethodNonStatic {\n\n\t@Bean\n\t@TestConfigurationPropertiesBinding\n\tpublic List<String> binder() {\n\t\treturn List.of(\"hello\", \"world\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/classprefixandignore/ConfigurationPropertiesWithPrefixAndIgnore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.classprefixandignore;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\n\n@TestConfigurationProperties(prefix = \"testing\", ignoreUnknownFields = false)\npublic class ConfigurationPropertiesWithPrefixAndIgnore {\n\n\tprivate String property;\n\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/classprefixonly/ConfigurationPropertiesWithPrefixOnly.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.classprefixonly;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\n\n@TestConfigurationProperties(prefix = \"testing\")\npublic class ConfigurationPropertiesWithPrefixOnly {\n\n\tprivate String property;\n\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/classvalueonly/ConfigurationPropertiesWithValueOnly.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.classvalueonly;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"testing\")\npublic class ConfigurationPropertiesWithValueOnly {\n\n\tprivate String property;\n\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/deprecatedsince/DeprecatedConfigurationPropertySince.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.deprecatedsince;\n\nimport org.springframework.boot.build.architecture.annotations.TestDeprecatedConfigurationProperty;\n\npublic class DeprecatedConfigurationPropertySince {\n\n\tprivate String property;\n\n\t@TestDeprecatedConfigurationProperty(reason = \"no longer used\")\n\t@Deprecated\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/methodprefixandignore/ConfigurationPropertiesWithPrefixAndIgnore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.methodprefixandignore;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\n\npublic class ConfigurationPropertiesWithPrefixAndIgnore {\n\n\tprivate String property;\n\n\t@TestConfigurationProperties(prefix = \"testing\", ignoreInvalidFields = true)\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/methodprefixonly/ConfigurationPropertiesWithPrefixOnly.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.methodprefixonly;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\n\npublic class ConfigurationPropertiesWithPrefixOnly {\n\n\tprivate String property;\n\n\t@TestConfigurationProperties(prefix = \"testing\")\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/configurationproperties/methodvalueonly/ConfigurationPropertiesWithValueOnly.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.configurationproperties.methodvalueonly;\n\nimport org.springframework.boot.build.architecture.annotations.TestConfigurationProperties;\n\npublic class ConfigurationPropertiesWithValueOnly {\n\n\tprivate String property;\n\n\t@TestConfigurationProperties(\"testing\")\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\tpublic void setProperty(String property) {\n\t\tthis.property = property;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/inferredfromparametertype/EnumSourceInferredFromParameterType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.junit.enumsource.inferredfromparametertype;\n\nimport org.junit.jupiter.params.provider.EnumSource;\n\nclass EnumSourceInferredFromParameterType {\n\n\t@EnumSource\n\tvoid exampleMethod(Example example) {\n\n\t}\n\n\tenum Example {\n\n\t\tONE, TWO, THREE\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/sameasparametertype/EnumSourceSameAsParameterType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.junit.enumsource.sameasparametertype;\n\nimport org.junit.jupiter.params.provider.EnumSource;\n\nclass EnumSourceSameAsParameterType {\n\n\t@EnumSource(Example.class)\n\tvoid exampleMethod(Example example) {\n\n\t}\n\n\tenum Example {\n\n\t\tONE, TWO, THREE\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/junit/enumsource/valuenecessary/EnumSourceValueNecessary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.junit.enumsource.valuenecessary;\n\nimport org.junit.jupiter.params.provider.EnumSource;\n\nclass EnumSourceValueNecessary {\n\n\t@EnumSource(Example.class)\n\tvoid exampleMethod(String thing, Example example) {\n\n\t}\n\n\tenum Example {\n\n\t\tONE, TWO, THREE\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/nullmarked/notannotated/TestClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.nullmarked.notannotated;\n\npublic class TestClass {\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/objects/noRequireNonNull/NoRequireNonNull.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.objects.noRequireNonNull;\n\nimport java.util.Collections;\n\nimport org.springframework.util.Assert;\n\nclass NoRequireNonNull {\n\n\tvoid exampleMethod() {\n\t\tAssert.notNull(new Object(), \"Object must not be null\");\n\t\t// Compilation of a method reference generates code that uses\n\t\t// Objects.requireNonNull(Object). Check that it doesn't cause a failure.\n\t\tCollections.emptyList().forEach(System.out::println);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/objects/requireNonNullWithString/RequireNonNullWithString.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.objects.requireNonNullWithString;\n\nimport java.util.Objects;\n\nclass RequireNonNullWithString {\n\n\tvoid exampleMethod() {\n\t\tObjects.requireNonNull(new Object(), \"Object cannot be null\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/objects/requireNonNullWithSupplier/RequireNonNullWithSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.objects.requireNonNullWithSupplier;\n\nimport java.util.Objects;\n\nclass RequireNonNullWithSupplier {\n\n\tvoid exampleMethod() {\n\t\tObjects.requireNonNull(new Object(), () -> \"Object cannot be null\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/loads/ResourceUtilsResourceLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.resources.loads;\n\nimport java.io.FileNotFoundException;\n\nimport org.springframework.util.ResourceUtils;\n\npublic class ResourceUtilsResourceLoader {\n\n\tvoid getResource() throws FileNotFoundException {\n\t\tResourceUtils.getURL(\"gradle.properties\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/resources/noloads/ResourceUtilsWithoutLoading.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.resources.noloads;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport org.springframework.util.ResourceUtils;\n\npublic class ResourceUtilsWithoutLoading {\n\n\tvoid inspectResourceLocation() throws MalformedURLException {\n\t\tResourceUtils.isUrl(\"gradle.properties\");\n\t\tResourceUtils.isFileURL(new URL(\"gradle.properties\"));\n\t\t\"test\".startsWith(ResourceUtils.FILE_URL_PREFIX);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCase/ToLowerCase.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.string.toLowerCase;\n\nclass ToLowerCase {\n\n\tvoid exampleMethod() {\n\t\tString test = \"Object must not be null\";\n\t\tSystem.out.println(test.toLowerCase());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toLowerCaseWithLocale/ToLowerCaseWithLocale.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.string.toLowerCaseWithLocale;\n\nimport java.util.Locale;\n\nclass ToLowerCaseWithLocale {\n\n\tvoid exampleMethod() {\n\t\tString test = \"Object must not be null\";\n\t\tSystem.out.println(test.toLowerCase(Locale.ENGLISH));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCase/ToUpperCase.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.string.toUpperCase;\n\nclass ToUpperCase {\n\n\tvoid exampleMethod() {\n\t\tString test = \"Object must not be null\";\n\t\tSystem.out.println(test.toUpperCase());\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/string/toUpperCaseWithLocale/ToUpperCaseWithLocale.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.string.toUpperCaseWithLocale;\n\nimport java.util.Locale;\n\nclass ToUpperCaseWithLocale {\n\n\tvoid exampleMethod() {\n\t\tString test = \"Object must not be null\";\n\t\tSystem.out.println(test.toUpperCase(Locale.ROOT));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/tangled/TangledOne.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.tangled;\n\nimport org.springframework.boot.build.architecture.tangled.sub.TangledTwo;\n\npublic final class TangledOne {\n\n\tpublic static final String ID = TangledTwo.class.getName() + \"One\";\n\n\tprivate TangledOne() {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/tangled/sub/TangledTwo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.tangled.sub;\n\nimport org.springframework.boot.build.architecture.tangled.TangledOne;\n\npublic final class TangledTwo {\n\n\tpublic static final String ID = TangledOne.ID + \"-Two\";\n\n\tprivate TangledTwo() {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/untangled/UntangledOne.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.untangled;\n\nimport org.springframework.boot.build.architecture.untangled.sub.UntangledTwo;\n\npublic final class UntangledOne {\n\n\tpublic static final String ID = UntangledTwo.class.getName() + \"One\";\n\n\tprivate UntangledOne() {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/untangled/sub/UntangledTwo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.untangled.sub;\n\npublic final class UntangledTwo {\n\n\tpublic static final String ID = \"Two\";\n\n\tprivate UntangledTwo() {\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/url/decode/UrlDecodeWithStringEncoding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.url.decode;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\n\nclass UrlDecodeWithStringEncoding {\n\n\tvoid exampleMethod() throws UnsupportedEncodingException {\n\t\tURLDecoder.decode(\"https://example.com\", \"UTF-8\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/architecture/url/encode/UrlEncodeWithStringEncoding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.architecture.url.encode;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\n\nclass UrlEncodeWithStringEncoding {\n\n\tvoid exampleMethod() throws UnsupportedEncodingException {\n\t\tURLEncoder.encode(\"https://example.com\", \"UTF-8\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/artifacts/ArtifactReleaseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.artifacts;\n\nimport org.gradle.api.Project;\nimport org.gradle.testfixtures.ProjectBuilder;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArtifactRelease}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass ArtifactReleaseTests {\n\n\t@Test\n\tvoid whenProjectVersionIsSnapshotThenTypeIsSnapshot() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"1.2.3-SNAPSHOT\");\n\t\tassertThat(ArtifactRelease.forProject(project).getType()).isEqualTo(\"snapshot\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsMilestoneThenTypeIsMilestone() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"1.2.3-M1\");\n\t\tassertThat(ArtifactRelease.forProject(project).getType()).isEqualTo(\"milestone\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsReleaseCandidateThenTypeIsMilestone() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"1.2.3-RC1\");\n\t\tassertThat(ArtifactRelease.forProject(project).getType()).isEqualTo(\"milestone\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsReleaseThenTypeIsRelease() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"1.2.3\");\n\t\tassertThat(ArtifactRelease.forProject(project).getType()).isEqualTo(\"release\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsSnapshotThenRepositoryIsArtifactorySnapshot() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"1.2.3-SNAPSHOT\");\n\t\tassertThat(ArtifactRelease.forProject(project).getDownloadRepo()).contains(\"repo.spring.io/snapshot\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsMilestoneThenRepositoryIsMavenCentral() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"4.0.0-M1\");\n\t\tassertThat(ArtifactRelease.forProject(project).getDownloadRepo())\n\t\t\t.contains(\"https://repo.maven.apache.org/maven2\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsReleaseCandidateThenRepositoryIsMavenCentral() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"4.0.0-RC1\");\n\t\tassertThat(ArtifactRelease.forProject(project).getDownloadRepo())\n\t\t\t.contains(\"https://repo.maven.apache.org/maven2\");\n\t}\n\n\t@Test\n\tvoid whenProjectVersionIsReleaseThenRepositoryIsMavenCentral() {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tproject.setVersion(\"1.2.3\");\n\t\tassertThat(ArtifactRelease.forProject(project).getDownloadRepo())\n\t\t\t.contains(\"https://repo.maven.apache.org/maven2\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/assertj/NodeAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.assertj;\n\nimport java.io.File;\n\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.assertj.core.api.StringAssert;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Node;\n\n/**\n * AssertJ {@link AssertProvider} for {@link Node} assertions.\n *\n * @author Andy Wilkinson\n */\npublic class NodeAssert extends AbstractAssert<NodeAssert, Node> implements AssertProvider<NodeAssert> {\n\n\tprivate static final DocumentBuilderFactory FACTORY = DocumentBuilderFactory.newInstance();\n\n\tprivate final XPathFactory xpathFactory = XPathFactory.newInstance();\n\n\tprivate final XPath xpath = this.xpathFactory.newXPath();\n\n\tpublic NodeAssert(File xmlFile) {\n\t\tthis(read(xmlFile));\n\t}\n\n\tpublic NodeAssert(Node actual) {\n\t\tsuper(actual, NodeAssert.class);\n\t}\n\n\tprivate static Document read(File xmlFile) {\n\t\ttry {\n\t\t\treturn FACTORY.newDocumentBuilder().parse(xmlFile);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tpublic NodeAssert nodeAtPath(String xpath) {\n\t\ttry {\n\t\t\treturn new NodeAssert((Node) this.xpath.evaluate(xpath, this.actual, XPathConstants.NODE));\n\t\t}\n\t\tcatch (XPathExpressionException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tpublic StringAssert textAtPath(String xpath) {\n\t\ttry {\n\t\t\treturn new StringAssert(\n\t\t\t\t\t(String) this.xpath.evaluate(xpath + \"/text()\", this.actual, XPathConstants.STRING));\n\t\t}\n\t\tcatch (XPathExpressionException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic NodeAssert assertThat() {\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/autoconfigure/DocumentAutoConfigurationClassesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport org.gradle.api.Project;\nimport org.gradle.api.file.ConfigurableFileCollection;\nimport org.gradle.testfixtures.ProjectBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DocumentAutoConfigurationClasses}.\n *\n * @author Andy Wilkinson\n */\nclass DocumentAutoConfigurationClassesTests {\n\n\t@TempDir\n\tprivate File temp;\n\n\t@Test\n\tvoid classesAreDocumented() throws IOException {\n\t\tFile output = documentAutoConfigurationClasses((metadataDir) -> {\n\t\t\twriteAutoConfigurationMetadata(\"spring-boot-one\", List.of(\"org.springframework.boot.one.AAutoConfiguration\",\n\t\t\t\t\t\"org.springframework.boot.one.BAutoConfiguration\"), metadataDir);\n\t\t\twriteAutoConfigurationMetadata(\"spring-boot-two\", List.of(\"org.springframework.boot.two.CAutoConfiguration\",\n\t\t\t\t\t\"org.springframework.boot.two.DAutoConfiguration\"), metadataDir);\n\t\t});\n\t\tassertThat(output).isNotEmptyDirectory();\n\t\tassertThat(output.listFiles()).extracting(File::getName)\n\t\t\t.containsExactlyInAnyOrder(\"spring-boot-one.adoc\", \"spring-boot-two.adoc\", \"nav.adoc\");\n\t}\n\n\t@Test\n\tvoid whenMetadataIsRemovedThenOutputForThatMetadataIsNoLongerPresent() throws IOException {\n\t\tdocumentAutoConfigurationClasses((metadataDir) -> {\n\t\t\twriteAutoConfigurationMetadata(\"spring-boot-one\", List.of(\"org.springframework.boot.one.AAutoConfiguration\",\n\t\t\t\t\t\"org.springframework.boot.one.BAutoConfiguration\"), metadataDir);\n\t\t\twriteAutoConfigurationMetadata(\"spring-boot-two\", List.of(\"org.springframework.boot.two.CAutoConfiguration\",\n\t\t\t\t\t\"org.springframework.boot.two.DAutoConfiguration\"), metadataDir);\n\t\t});\n\t\tFile output = documentAutoConfigurationClasses(\n\t\t\t\t(metadataDir) -> assertThat(new File(metadataDir, \"spring-boot-two.properties\").delete()).isTrue());\n\t\tassertThat(output).isNotEmptyDirectory();\n\t\tassertThat(output.listFiles()).extracting(File::getName)\n\t\t\t.containsExactlyInAnyOrder(\"spring-boot-one.adoc\", \"nav.adoc\");\n\t}\n\n\tprivate File documentAutoConfigurationClasses(Consumer<File> metadataDir) throws IOException {\n\t\tProject project = ProjectBuilder.builder().build();\n\t\tDocumentAutoConfigurationClasses task = project.getTasks()\n\t\t\t.register(\"documentAutoConfigurationClasses\", DocumentAutoConfigurationClasses.class)\n\t\t\t.get();\n\t\tFile output = new File(this.temp, \"output\");\n\t\tFile input = new File(this.temp, \"input\");\n\t\tinput.mkdirs();\n\t\tmetadataDir.accept(input);\n\t\tConfigurableFileCollection autoConfiguration = project.files();\n\t\tStream.of(input.listFiles()).forEach(autoConfiguration::from);\n\t\ttask.getOutputDir().set(output);\n\t\ttask.setAutoConfiguration(autoConfiguration);\n\t\ttask.documentAutoConfigurationClasses();\n\t\treturn output;\n\t}\n\n\tprivate void writeAutoConfigurationMetadata(String module, List<String> classes, File outputDir) {\n\t\tFile metadata = new File(outputDir, module + \".properties\");\n\t\tProperties properties = new Properties();\n\t\tproperties.setProperty(\"autoConfigurationClassNames\", String.join(\",\", classes));\n\t\tproperties.setProperty(\"module\", module);\n\t\ttry (FileOutputStream out = new FileOutputStream(metadata)) {\n\t\t\tproperties.store(out, null);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new java.io.UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/BomPluginIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.function.Consumer;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.build.DeployedPlugin;\nimport org.springframework.boot.build.assertj.NodeAssert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BomPlugin}.\n *\n * @author Andy Wilkinson\n */\nclass BomPluginIntegrationTests {\n\n\tprivate File projectDir;\n\n\tprivate File buildFile;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File projectDir) {\n\t\tthis.projectDir = projectDir;\n\t\tthis.buildFile = new File(this.projectDir, \"build.gradle\");\n\t}\n\n\t@Test\n\tvoid libraryModulesAreIncludedInDependencyManagementOfGeneratedPom() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('ActiveMQ', '5.15.10') {\");\n\t\t\tout.println(\"        group('org.apache.activemq') {\");\n\t\t\tout.println(\"            modules = [\");\n\t\t\tout.println(\"                'activemq-amqp',\");\n\t\t\tout.println(\"                'activemq-blueprint'\");\n\t\t\tout.println(\"            ]\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/activemq.version\").isEqualTo(\"5.15.10\");\n\t\t\tNodeAssert dependency = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[1]\");\n\t\t\tassertThat(dependency).textAtPath(\"groupId\").isEqualTo(\"org.apache.activemq\");\n\t\t\tassertThat(dependency).textAtPath(\"artifactId\").isEqualTo(\"activemq-amqp\");\n\t\t\tassertThat(dependency).textAtPath(\"version\").isEqualTo(\"${activemq.version}\");\n\t\t\tassertThat(dependency).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t\tdependency = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[2]\");\n\t\t\tassertThat(dependency).textAtPath(\"groupId\").isEqualTo(\"org.apache.activemq\");\n\t\t\tassertThat(dependency).textAtPath(\"artifactId\").isEqualTo(\"activemq-blueprint\");\n\t\t\tassertThat(dependency).textAtPath(\"version\").isEqualTo(\"${activemq.version}\");\n\t\t\tassertThat(dependency).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid libraryPluginsAreIncludedInPluginManagementOfGeneratedPom() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('Flyway', '6.0.8') {\");\n\t\t\tout.println(\"        group('org.flywaydb') {\");\n\t\t\tout.println(\"            plugins = [\");\n\t\t\tout.println(\"                'flyway-maven-plugin'\");\n\t\t\tout.println(\"            ]\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/flyway.version\").isEqualTo(\"6.0.8\");\n\t\t\tNodeAssert plugin = pom.nodeAtPath(\"//pluginManagement/plugins/plugin\");\n\t\t\tassertThat(plugin).textAtPath(\"groupId\").isEqualTo(\"org.flywaydb\");\n\t\t\tassertThat(plugin).textAtPath(\"artifactId\").isEqualTo(\"flyway-maven-plugin\");\n\t\t\tassertThat(plugin).textAtPath(\"version\").isEqualTo(\"${flyway.version}\");\n\t\t\tassertThat(plugin).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(plugin).textAtPath(\"type\").isNullOrEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid libraryImportsAreIncludedInDependencyManagementOfGeneratedPom() throws Exception {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('Jackson Bom', '2.10.0') {\");\n\t\t\tout.println(\"        group('com.fasterxml.jackson') {\");\n\t\t\tout.println(\"            bom('jackson-bom')\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/jackson-bom.version\").isEqualTo(\"2.10.0\");\n\t\t\tNodeAssert dependency = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency\");\n\t\t\tassertThat(dependency).textAtPath(\"groupId\").isEqualTo(\"com.fasterxml.jackson\");\n\t\t\tassertThat(dependency).textAtPath(\"artifactId\").isEqualTo(\"jackson-bom\");\n\t\t\tassertThat(dependency).textAtPath(\"version\").isEqualTo(\"${jackson-bom.version}\");\n\t\t\tassertThat(dependency).textAtPath(\"scope\").isEqualTo(\"import\");\n\t\t\tassertThat(dependency).textAtPath(\"type\").isEqualTo(\"pom\");\n\t\t\tassertThat(dependency).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid moduleExclusionsAreIncludedInDependencyManagementOfGeneratedPom() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('MySQL', '8.0.18') {\");\n\t\t\tout.println(\"        group('mysql') {\");\n\t\t\tout.println(\"            modules = [\");\n\t\t\tout.println(\"                'mysql-connector-java' {\");\n\t\t\tout.println(\"                    exclude group: 'com.google.protobuf', module: 'protobuf-java'\");\n\t\t\tout.println(\"                }\");\n\t\t\tout.println(\"            ]\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/mysql.version\").isEqualTo(\"8.0.18\");\n\t\t\tNodeAssert dependency = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency\");\n\t\t\tassertThat(dependency).textAtPath(\"groupId\").isEqualTo(\"mysql\");\n\t\t\tassertThat(dependency).textAtPath(\"artifactId\").isEqualTo(\"mysql-connector-java\");\n\t\t\tassertThat(dependency).textAtPath(\"version\").isEqualTo(\"${mysql.version}\");\n\t\t\tassertThat(dependency).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t\tNodeAssert exclusion = dependency.nodeAtPath(\"exclusions/exclusion\");\n\t\t\tassertThat(exclusion).textAtPath(\"groupId\").isEqualTo(\"com.google.protobuf\");\n\t\t\tassertThat(exclusion).textAtPath(\"artifactId\").isEqualTo(\"protobuf-java\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid moduleTypesAreIncludedInDependencyManagementOfGeneratedPom() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('Elasticsearch', '7.15.2') {\");\n\t\t\tout.println(\"        group('org.elasticsearch.distribution.integ-test-zip') {\");\n\t\t\tout.println(\"            modules = [\");\n\t\t\tout.println(\"                'elasticsearch' {\");\n\t\t\tout.println(\"                    type = 'zip'\");\n\t\t\tout.println(\"                }\");\n\t\t\tout.println(\"            ]\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/elasticsearch.version\").isEqualTo(\"7.15.2\");\n\t\t\tNodeAssert dependency = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency\");\n\t\t\tassertThat(dependency).textAtPath(\"groupId\").isEqualTo(\"org.elasticsearch.distribution.integ-test-zip\");\n\t\t\tassertThat(dependency).textAtPath(\"artifactId\").isEqualTo(\"elasticsearch\");\n\t\t\tassertThat(dependency).textAtPath(\"version\").isEqualTo(\"${elasticsearch.version}\");\n\t\t\tassertThat(dependency).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"type\").isEqualTo(\"zip\");\n\t\t\tassertThat(dependency).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t\tassertThat(dependency).nodeAtPath(\"exclusions\").isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid moduleClassifiersAreIncludedInDependencyManagementOfGeneratedPom() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('Kafka', '2.7.2') {\");\n\t\t\tout.println(\"        group('org.apache.kafka') {\");\n\t\t\tout.println(\"            modules = [\");\n\t\t\tout.println(\"                'connect-api',\");\n\t\t\tout.println(\"                'generator',\");\n\t\t\tout.println(\"                'generator' {\");\n\t\t\tout.println(\"                    classifier = 'test'\");\n\t\t\tout.println(\"                },\");\n\t\t\tout.println(\"                'kafka-tools',\");\n\t\t\tout.println(\"            ]\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/kafka.version\").isEqualTo(\"2.7.2\");\n\t\t\tNodeAssert connectApi = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[1]\");\n\t\t\tassertThat(connectApi).textAtPath(\"groupId\").isEqualTo(\"org.apache.kafka\");\n\t\t\tassertThat(connectApi).textAtPath(\"artifactId\").isEqualTo(\"connect-api\");\n\t\t\tassertThat(connectApi).textAtPath(\"version\").isEqualTo(\"${kafka.version}\");\n\t\t\tassertThat(connectApi).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(connectApi).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(connectApi).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t\tassertThat(connectApi).nodeAtPath(\"exclusions\").isNull();\n\t\t\tNodeAssert generator = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[2]\");\n\t\t\tassertThat(generator).textAtPath(\"groupId\").isEqualTo(\"org.apache.kafka\");\n\t\t\tassertThat(generator).textAtPath(\"artifactId\").isEqualTo(\"generator\");\n\t\t\tassertThat(generator).textAtPath(\"version\").isEqualTo(\"${kafka.version}\");\n\t\t\tassertThat(generator).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(generator).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(generator).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t\tassertThat(generator).nodeAtPath(\"exclusions\").isNull();\n\t\t\tNodeAssert generatorTest = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[3]\");\n\t\t\tassertThat(generatorTest).textAtPath(\"groupId\").isEqualTo(\"org.apache.kafka\");\n\t\t\tassertThat(generatorTest).textAtPath(\"artifactId\").isEqualTo(\"generator\");\n\t\t\tassertThat(generatorTest).textAtPath(\"version\").isEqualTo(\"${kafka.version}\");\n\t\t\tassertThat(generatorTest).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(generatorTest).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(generatorTest).textAtPath(\"classifier\").isEqualTo(\"test\");\n\t\t\tassertThat(generatorTest).nodeAtPath(\"exclusions\").isNull();\n\t\t\tNodeAssert kafkaTools = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[4]\");\n\t\t\tassertThat(kafkaTools).textAtPath(\"groupId\").isEqualTo(\"org.apache.kafka\");\n\t\t\tassertThat(kafkaTools).textAtPath(\"artifactId\").isEqualTo(\"kafka-tools\");\n\t\t\tassertThat(kafkaTools).textAtPath(\"version\").isEqualTo(\"${kafka.version}\");\n\t\t\tassertThat(kafkaTools).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(kafkaTools).textAtPath(\"type\").isNullOrEmpty();\n\t\t\tassertThat(kafkaTools).textAtPath(\"classifier\").isNullOrEmpty();\n\t\t\tassertThat(kafkaTools).nodeAtPath(\"exclusions\").isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid libraryNamedSpringBootHasNoVersionProperty() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.bom'\");\n\t\t\tout.println(\"    id 'org.springframework.boot.deployed'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"bom {\");\n\t\t\tout.println(\"    library('Spring Boot', '1.2.3') {\");\n\t\t\tout.println(\"        group('org.springframework.boot') {\");\n\t\t\tout.println(\"            modules = [\");\n\t\t\tout.println(\"                'spring-boot'\");\n\t\t\tout.println(\"            ]\");\n\t\t\tout.println(\"        }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tgeneratePom((pom) -> {\n\t\t\tassertThat(pom).textAtPath(\"//properties/spring-boot.version\").isEmpty();\n\t\t\tNodeAssert dependency = pom.nodeAtPath(\"//dependencyManagement/dependencies/dependency[1]\");\n\t\t\tassertThat(dependency).textAtPath(\"groupId\").isEqualTo(\"org.springframework.boot\");\n\t\t\tassertThat(dependency).textAtPath(\"artifactId\").isEqualTo(\"spring-boot\");\n\t\t\tassertThat(dependency).textAtPath(\"version\").isEqualTo(\"1.2.3\");\n\t\t\tassertThat(dependency).textAtPath(\"scope\").isNullOrEmpty();\n\t\t\tassertThat(dependency).textAtPath(\"type\").isNullOrEmpty();\n\t\t});\n\t}\n\n\tprivate BuildResult runGradle(String... args) {\n\t\treturn GradleRunner.create()\n\t\t\t.withDebug(true)\n\t\t\t.withProjectDir(this.projectDir)\n\t\t\t.withArguments(args)\n\t\t\t.withPluginClasspath()\n\t\t\t.build();\n\t}\n\n\tprivate void generatePom(Consumer<NodeAssert> consumer) {\n\t\trunGradle(DeployedPlugin.GENERATE_POM_TASK_NAME, \"-s\");\n\t\tFile generatedPomXml = new File(this.projectDir, \"build/publications/maven/pom-default.xml\");\n\t\tassertThat(generatedPomXml).isFile();\n\t\tconsumer.accept(new NodeAssert(generatedPomXml));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/LibraryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.build.bom.Library.BomAlignment;\nimport org.springframework.boot.build.bom.Library.Group;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.Library.Link;\nimport org.springframework.boot.build.bom.Library.ProhibitedVersion;\nimport org.springframework.boot.build.bom.Library.VersionAlignment;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Library}.\n *\n * @author Phillip Webb\n */\nclass LibraryTests {\n\n\t@Test\n\tvoid getLinkRootNameWhenNoneSpecified() {\n\t\tString name = \"Spring Framework\";\n\t\tString calendarName = null;\n\t\tLibraryVersion version = new LibraryVersion(DependencyVersion.parse(\"1.2.3\"));\n\t\tList<Group> groups = Collections.emptyList();\n\t\tList<ProhibitedVersion> prohibitedVersion = Collections.emptyList();\n\t\tboolean considerSnapshots = false;\n\t\tVersionAlignment versionAlignment = null;\n\t\tBomAlignment alignsWithBom = null;\n\t\tString linkRootName = null;\n\t\tMap<String, List<Link>> links = Collections.emptyMap();\n\t\tLibrary library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots,\n\t\t\t\tversionAlignment, alignsWithBom, linkRootName, links);\n\t\tassertThat(library.getLinkRootName()).isEqualTo(\"spring-framework\");\n\t}\n\n\t@Test\n\tvoid getLinkRootNameWhenSpecified() {\n\t\tString name = \"Spring Data BOM\";\n\t\tString calendarName = null;\n\t\tLibraryVersion version = new LibraryVersion(DependencyVersion.parse(\"1.2.3\"));\n\t\tList<Group> groups = Collections.emptyList();\n\t\tList<ProhibitedVersion> prohibitedVersion = Collections.emptyList();\n\t\tboolean considerSnapshots = false;\n\t\tVersionAlignment versionAlignment = null;\n\t\tBomAlignment alignsWithBom = null;\n\t\tString linkRootName = \"spring-data\";\n\t\tMap<String, List<Link>> links = Collections.emptyMap();\n\t\tLibrary library = new Library(name, calendarName, version, groups, null, prohibitedVersion, considerSnapshots,\n\t\t\t\tversionAlignment, alignsWithBom, linkRootName, links);\n\t\tassertThat(library.getLinkRootName()).isEqualTo(\"spring-data\");\n\t}\n\n\t@Test\n\tvoid toMajorMinorGenerationWithRelease() {\n\t\tLibraryVersion version = new LibraryVersion(DependencyVersion.parse(\"1.2.3\"));\n\t\tassertThat(version.forMajorMinorGeneration()).isEqualTo(\"1.2.x\");\n\t}\n\n\t@Test\n\tvoid toMajorMinorGenerationWithSnapshot() {\n\t\tLibraryVersion version = new LibraryVersion(DependencyVersion.parse(\"2.0.0-SNAPSHOT\"));\n\t\tassertThat(version.forMajorMinorGeneration()).isEqualTo(\"2.0.x-SNAPSHOT\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/InteractiveUpgradeResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.gradle.api.internal.tasks.userinput.UserInputHandler;\nimport org.gradle.api.provider.Provider;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link InteractiveUpgradeResolver}.\n *\n * @author Phillip Webb\n */\nclass InteractiveUpgradeResolverTests {\n\n\t@Test\n\tvoid resolveUpgradeUpdateVersionNumberInLibrary() {\n\t\tUserInputHandler userInputHandler = mock(UserInputHandler.class);\n\t\tLibraryUpdateResolver libaryUpdateResolver = mock(LibraryUpdateResolver.class);\n\t\tInteractiveUpgradeResolver upgradeResolver = new InteractiveUpgradeResolver(userInputHandler,\n\t\t\t\tlibaryUpdateResolver);\n\t\tList<Library> libraries = new ArrayList<>();\n\t\tDependencyVersion version = DependencyVersion.parse(\"1.0.0\");\n\t\tLibraryVersion libraryVersion = new LibraryVersion(version);\n\t\tLibrary library = new Library(\"test\", null, libraryVersion, null, null, null, false, null, null, null, null);\n\t\tlibraries.add(library);\n\t\tList<Library> librariesToUpgrade = new ArrayList<>();\n\t\tlibrariesToUpgrade.add(library);\n\t\tList<LibraryWithVersionOptions> updates = new ArrayList<>();\n\t\tDependencyVersion updateVersion = DependencyVersion.parse(\"1.0.1\");\n\t\tVersionOption versionOption = new VersionOption(updateVersion);\n\t\tupdates.add(new LibraryWithVersionOptions(library, List.of(versionOption)));\n\t\tgiven(libaryUpdateResolver.findLibraryUpdates(any(), any())).willReturn(updates);\n\t\tProvider<Object> providerOfVersionOption = providerOf(versionOption);\n\t\tgiven(userInputHandler.askUser(any())).willReturn(providerOfVersionOption);\n\t\tList<Upgrade> upgrades = upgradeResolver.resolveUpgrades(librariesToUpgrade, libraries);\n\t\tassertThat(upgrades.get(0).to().getVersion().getVersion()).isEqualTo(updateVersion);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate <T> Provider<T> providerOf(VersionOption versionOption) {\n\t\tProvider provider = mock(Provider.class);\n\t\tgiven(provider.get()).willReturn(versionOption);\n\t\treturn provider;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/ReleaseScheduleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.time.OffsetDateTime;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.build.bom.bomr.ReleaseSchedule.Release;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link ReleaseSchedule}.\n *\n * @author Andy Wilkinson\n */\nclass ReleaseScheduleTests {\n\n\tprivate final RestTemplate rest = new RestTemplate();\n\n\tprivate final ReleaseSchedule releaseSchedule = new ReleaseSchedule(this.rest);\n\n\tprivate final MockRestServiceServer server = MockRestServiceServer.bindTo(this.rest).build();\n\n\t@Test\n\tvoid releasesBetween() {\n\t\tthis.server\n\t\t\t.expect(requestTo(\"https://calendar.spring.io/releases?start=2023-09-01T00:00Z&end=2023-09-21T23:59Z\"))\n\t\t\t.andRespond(withSuccess(new ClassPathResource(\"releases.json\"), MediaType.APPLICATION_JSON));\n\t\tMap<String, List<Release>> releases = this.releaseSchedule\n\t\t\t.releasesBetween(OffsetDateTime.parse(\"2023-09-01T00:00Z\"), OffsetDateTime.parse(\"2023-09-21T23:59Z\"));\n\t\tassertThat(releases).hasSize(23);\n\t\tassertThat(releases.get(\"Spring Framework\")).hasSize(3);\n\t\tassertThat(releases.get(\"Spring Boot\")).hasSize(4);\n\t\tassertThat(releases.get(\"Spring Modulith\")).hasSize(1);\n\t\tassertThat(releases.get(\"spring graphql\")).hasSize(3);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeApplicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Files;\nimport java.util.Collections;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link UpgradeApplicator}.\n *\n * @author Andy Wilkinson\n */\nclass UpgradeApplicatorTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid whenUpgradeIsAppliedToLibraryWithVersionThenBomIsUpdated() throws IOException {\n\t\tFile bom = new File(this.temp, \"bom.gradle\");\n\t\tFileCopyUtils.copy(new File(\"src/test/resources/bom.gradle\"), bom);\n\t\tString originalContents = Files.readString(bom.toPath());\n\t\tFile gradleProperties = new File(this.temp, \"gradle.properties\");\n\t\tFileCopyUtils.copy(new File(\"src/test/resources/gradle.properties\"), gradleProperties);\n\t\tLibrary activeMq = new Library(\"ActiveMQ\", null, new LibraryVersion(DependencyVersion.parse(\"5.15.11\")), null,\n\t\t\t\tnull, null, false, null, null, null, Collections.emptyMap());\n\t\tnew UpgradeApplicator(bom.toPath(), gradleProperties.toPath())\n\t\t\t.apply(new Upgrade(activeMq, activeMq.withVersion(new LibraryVersion(DependencyVersion.parse(\"5.16\")))));\n\t\tString bomContents = Files.readString(bom.toPath());\n\t\tassertThat(bomContents).hasSize(originalContents.length() - 3);\n\t}\n\n\t@Test\n\tvoid whenUpgradeIsAppliedToLibraryWithVersionPropertyThenGradlePropertiesIsUpdated() throws IOException {\n\t\tFile bom = new File(this.temp, \"bom.gradle\");\n\t\tFileCopyUtils.copy(new File(\"src/test/resources/bom.gradle\"), bom);\n\t\tFile gradleProperties = new File(this.temp, \"gradle.properties\");\n\t\tFileCopyUtils.copy(new File(\"src/test/resources/gradle.properties\"), gradleProperties);\n\t\tLibrary kotlin = new Library(\"Kotlin\", null, new LibraryVersion(DependencyVersion.parse(\"1.3.70\")), null, null,\n\t\t\t\tnull, false, null, null, null, Collections.emptyMap());\n\t\tnew UpgradeApplicator(bom.toPath(), gradleProperties.toPath())\n\t\t\t.apply(new Upgrade(kotlin, kotlin.withVersion(new LibraryVersion(DependencyVersion.parse(\"1.4\")))));\n\t\tProperties properties = new Properties();\n\t\ttry (InputStream in = new FileInputStream(gradleProperties)) {\n\t\t\tproperties.load(in);\n\t\t}\n\t\tassertThat(properties).containsOnly(entry(\"a\", \"alpha\"), entry(\"b\", \"bravo\"), entry(\"kotlinVersion\", \"1.4\"),\n\t\t\t\tentry(\"t\", \"tango\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/UpgradeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.build.bom.Library;\nimport org.springframework.boot.build.bom.Library.LibraryVersion;\nimport org.springframework.boot.build.bom.bomr.version.DependencyVersion;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Upgrade}.\n *\n * @author Phillip Webb\n */\nclass UpgradeTests {\n\n\t@Test\n\tvoid createToRelease() {\n\t\tLibrary from = new Library(\"Test\", null, new LibraryVersion(DependencyVersion.parse(\"1.0.0\")), null, null, null,\n\t\t\t\tfalse, null, null, null, null);\n\t\tUpgrade upgrade = new Upgrade(from, from.withVersion(new LibraryVersion(DependencyVersion.parse(\"1.0.1\"))));\n\t\tassertThat(upgrade.from().getNameAndVersion()).isEqualTo(\"Test 1.0.0\");\n\t\tassertThat(upgrade.to().getNameAndVersion()).isEqualTo(\"Test 1.0.1\");\n\t\tassertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo(\"Test 1.0.1\");\n\t}\n\n\t@Test\n\tvoid createToSnapshot() {\n\t\tLibrary from = new Library(\"Test\", null, new LibraryVersion(DependencyVersion.parse(\"1.0.0\")), null, null, null,\n\t\t\t\tfalse, null, null, null, null);\n\t\tUpgrade upgrade = new Upgrade(from,\n\t\t\t\tfrom.withVersion(new LibraryVersion(DependencyVersion.parse(\"1.0.1-SNAPSHOT\"))),\n\t\t\t\tfrom.withVersion(new LibraryVersion(DependencyVersion.parse(\"1.0.1\"))));\n\t\tassertThat(upgrade.from().getNameAndVersion()).isEqualTo(\"Test 1.0.0\");\n\t\tassertThat(upgrade.to().getNameAndVersion()).isEqualTo(\"Test 1.0.1-SNAPSHOT\");\n\t\tassertThat(upgrade.toRelease().getNameAndVersion()).isEqualTo(\"Test 1.0.1\");\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/version/ArtifactVersionDependencyVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArtifactVersionDependencyVersion}.\n *\n * @author Andy Wilkinson\n */\nclass ArtifactVersionDependencyVersionTests {\n\n\t@Test\n\tvoid parseWhenVersionIsNotAMavenVersionShouldReturnNull() {\n\t\tassertThat(version(\"1.2.3.1\")).isNull();\n\t}\n\n\t@Test\n\tvoid parseWhenVersionIsAMavenVersionShouldReturnAVersion() {\n\t\tassertThat(version(\"1.2.3\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenSameMajorAndMinorShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2\").isSameMajor(version(\"1.10.0\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenSameMajorShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2\").isSameMajor(version(\"1.9.0\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenDifferentMajorShouldReturnFalse() {\n\t\tassertThat(version(\"2.0.2\").isSameMajor(version(\"1.9.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSameMinorWhenSameMinorShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2\").isSameMinor(version(\"1.10.1\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMinorWhenDifferentMinorShouldReturnFalse() {\n\t\tassertThat(version(\"1.10.2\").isSameMinor(version(\"1.9.1\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForReleaseShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2-SNAPSHOT\").isSnapshotFor(version(\"1.10.2\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenBuildSnapshotForReleaseShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2.BUILD-SNAPSHOT\").isSnapshotFor(version(\"1.10.2.RELEASE\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForReleaseCandidateShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2-SNAPSHOT\").isSnapshotFor(version(\"1.10.2-RC2\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenBuildSnapshotForReleaseCandidateShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2.BUILD-SNAPSHOT\").isSnapshotFor(version(\"1.10.2.RC2\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForMilestoneShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2-SNAPSHOT\").isSnapshotFor(version(\"1.10.2-M1\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenBuildSnapshotForMilestoneShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.2.BUILD-SNAPSHOT\").isSnapshotFor(version(\"1.10.2.M1\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForDifferentReleaseShouldReturnFalse() {\n\t\tassertThat(version(\"1.10.1-SNAPSHOT\").isSnapshotFor(version(\"1.10.2\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenBuildSnapshotForDifferentReleaseShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.1.BUILD-SNAPSHOT\").isSnapshotFor(version(\"1.10.2.RELEASE\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForDifferentReleaseCandidateShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.1-SNAPSHOT\").isSnapshotFor(version(\"1.10.2-RC2\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenBuildSnapshotForDifferentReleaseCandidateShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.1.BUILD-SNAPSHOT\").isSnapshotFor(version(\"1.10.2.RC2\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForDifferentMilestoneShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.1-SNAPSHOT\").isSnapshotFor(version(\"1.10.2-M1\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenBuildSnapshotForDifferentMilestoneShouldReturnTrue() {\n\t\tassertThat(version(\"1.10.1.BUILD-SNAPSHOT\").isSnapshotFor(version(\"1.10.2.M1\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenNotSnapshotShouldReturnFalse() {\n\t\tassertThat(version(\"1.10.1-M1\").isSnapshotFor(version(\"1.10.1\"))).isFalse();\n\t}\n\n\tprivate ArtifactVersionDependencyVersion version(String version) {\n\t\treturn ArtifactVersionDependencyVersion.parse(version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/version/CalendarVersionDependencyVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CalendarVersionDependencyVersion}.\n *\n * @author Andy Wilkinson\n */\nclass CalendarVersionDependencyVersionTests {\n\n\t@Test\n\tvoid parseWhenVersionIsNotACalendarVersionShouldReturnNull() {\n\t\tassertThat(version(\"1.2.3\")).isNull();\n\t}\n\n\t@Test\n\tvoid parseWhenVersionIsACalendarVersionShouldReturnAVersion() {\n\t\tassertThat(version(\"2020.0.0\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenSameMajorAndMinorShouldReturnTrue() {\n\t\tassertThat(version(\"2020.0.0\").isSameMajor(version(\"2020.0.1\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenSameMajorShouldReturnTrue() {\n\t\tassertThat(version(\"2020.0.0\").isSameMajor(version(\"2020.1.0\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenDifferentMajorShouldReturnFalse() {\n\t\tassertThat(version(\"2020.0.0\").isSameMajor(version(\"2021.0.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSameMinorWhenSameMinorShouldReturnTrue() {\n\t\tassertThat(version(\"2020.0.0\").isSameMinor(version(\"2020.0.1\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMinorWhenDifferentMinorShouldReturnFalse() {\n\t\tassertThat(version(\"2020.0.0\").isSameMinor(version(\"2020.1.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid calendarVersionIsNotSameMajorAsReleaseTrainVersion() {\n\t\tassertThat(version(\"2020.0.0\").isSameMajor(releaseTrainVersion(\"Aluminium-RELEASE\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid calendarVersionIsNotSameMinorAsReleaseTrainVersion() {\n\t\tassertThat(version(\"2020.0.0\").isSameMinor(releaseTrainVersion(\"Aluminium-RELEASE\"))).isFalse();\n\t}\n\n\tprivate ReleaseTrainDependencyVersion releaseTrainVersion(String version) {\n\t\treturn ReleaseTrainDependencyVersion.parse(version);\n\t}\n\n\tprivate CalendarVersionDependencyVersion version(String version) {\n\t\treturn CalendarVersionDependencyVersion.parse(version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/version/DependencyVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DependencyVersion}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nclass DependencyVersionTests {\n\n\t@Test\n\tvoid parseWhenValidMavenVersionShouldReturnArtifactVersionDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"1.2.3.Final\")).isExactlyInstanceOf(ArtifactVersionDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhenReleaseTrainShouldReturnReleaseTrainDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"Ingalls-SR5\")).isInstanceOf(ReleaseTrainDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhenMavenLikeVersionWithNumericQualifierShouldReturnNumericQualifierDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"1.2.3.4\")).isInstanceOf(MultipleComponentsDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhen5ComponentsShouldReturnNumericQualifierDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"1.2.3.4.5\")).isInstanceOf(MultipleComponentsDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhenVersionWithLeadingZeroesShouldReturnLeadingZeroesDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"1.4.01\")).isInstanceOf(LeadingZeroesDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhenVersionWithCombinedPatchAndQualifierShouldReturnCombinedPatchAndQualifierDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"4.0.0M4\")).isInstanceOf(CombinedPatchAndQualifierDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhenCalendarVersionShouldReturnArtifactVersionDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"2020.0.0\")).isInstanceOf(CalendarVersionDependencyVersion.class);\n\t}\n\n\t@Test\n\tvoid parseWhenCalendarVersionWithModifierShouldReturnArtifactVersionDependencyVersion() {\n\t\tassertThat(DependencyVersion.parse(\"2020.0.0-M1\")).isInstanceOf(CalendarVersionDependencyVersion.class);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/version/DependencyVersionUpgradeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Repeatable;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.Method;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.ArgumentsProvider;\nimport org.junit.jupiter.params.provider.ArgumentsSource;\nimport org.junit.jupiter.params.support.ParameterDeclarations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DependencyVersion#isUpgrade} of {@link DependencyVersion}\n * implementations.\n *\n * @author Andy Wilkinson\n */\nclass DependencyVersionUpgradeTests {\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.3\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.3.RELEASE\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.0\")\n\t@ReleaseTrain(current = \"Kay-RELEASE\", candidate = \"Kay-RELEASE\")\n\tvoid isUpgradeWhenSameVersionShouldReturnFalse(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-SNAPSHOT\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.BUILD-SNAPSHOT\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0-SNAPSHOT\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-BUILD-SNAPSHOT\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenSameSnapshotVersionShouldReturnFalse(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-SNAPSHOT\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.BUILD-SNAPSHOT\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0-SNAPSHOT\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-BUILD-SNAPSHOT\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenSameSnapshotVersionAndMovingToSnapshotsShouldReturnFalse(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, true)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.4\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.4.RELEASE\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.1\")\n\t@ReleaseTrain(current = \"Kay-RELEASE\", candidate = \"Kay-SR1\")\n\tvoid isUpgradeWhenLaterPatchReleaseShouldReturnTrue(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.4-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.4.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.1-SNAPSHOT\")\n\tvoid isUpgradeWhenSnapshotOfLaterPatchReleaseShouldReturnTrue(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.4-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.4.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.1-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-RELEASE\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenSnapshotOfLaterPatchReleaseAndMovingToSnapshotsShouldReturnTrue(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, true)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-RELEASE\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenSnapshotOfSameVersionShouldReturnFalse(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-SNAPSHOT\", candidate = \"1.2.3-M2\")\n\t@ArtifactVersion(current = \"1.2.3.BUILD-SNAPSHOT\", candidate = \"1.2.3.M2\")\n\t@CalendarVersion(current = \"2023.0.0-SNAPSHOT\", candidate = \"2023.0.0-M2\")\n\t@ReleaseTrain(current = \"Kay-BUILD-SNAPSHOT\", candidate = \"Kay-M2\")\n\tvoid isUpgradeWhenSnapshotToMilestoneShouldReturnTrue(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-SNAPSHOT\", candidate = \"1.2.3-RC1\")\n\t@ArtifactVersion(current = \"1.2.3.BUILD-SNAPSHOT\", candidate = \"1.2.3.RC1\")\n\t@CalendarVersion(current = \"2023.0.0-SNAPSHOT\", candidate = \"2023.0.0-RC1\")\n\t@ReleaseTrain(current = \"Kay-BUILD-SNAPSHOT\", candidate = \"Kay-RC1\")\n\tvoid isUpgradeWhenSnapshotToReleaseCandidateShouldReturnTrue(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-SNAPSHOT\", candidate = \"1.2.3\")\n\t@ArtifactVersion(current = \"1.2.3.BUILD-SNAPSHOT\", candidate = \"1.2.3.RELEASE\")\n\t@CalendarVersion(current = \"2023.0.0-SNAPSHOT\", candidate = \"2023.0.0\")\n\t@ReleaseTrain(current = \"Kay-BUILD-SNAPSHOT\", candidate = \"Kay-RELEASE\")\n\tvoid isUpgradeWhenSnapshotToReleaseShouldReturnTrue(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-M1\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.M1\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0-M1\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-M1\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenMilestoneToSnapshotShouldReturnFalse(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-RC1\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RC1\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0-RC1\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-RC1\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenReleaseCandidateToSnapshotShouldReturnFalse(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-RELEASE\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenReleaseToSnapshotShouldReturnFalse(DependencyVersion current, DependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, false)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-M1\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.M1\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0-M1\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-M1\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenMilestoneToSnapshotAndMovingToSnapshotsShouldReturnTrue(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, true)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3-RC1\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RC1\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0-RC1\", candidate = \"2023.0.0-SNAPSHOT\")\n\t@ReleaseTrain(current = \"Kay-RC1\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenReleaseCandidateToSnapshotAndMovingToSnapshotsShouldReturnTrue(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, true)).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@ArtifactVersion(current = \"1.2.3\", candidate = \"1.2.3-SNAPSHOT\")\n\t@ArtifactVersion(current = \"1.2.3.RELEASE\", candidate = \"1.2.3.BUILD-SNAPSHOT\")\n\t@CalendarVersion(current = \"2023.0.0\", candidate = \"2023.0.0-SNAPSHOT\")\n\tvoid isUpgradeWhenReleaseToSnapshotAndMovingToSnapshotsShouldReturnFalse(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, true)).isFalse();\n\t}\n\n\t@ParameterizedTest\n\t@ReleaseTrain(current = \"Kay-RELEASE\", candidate = \"Kay-BUILD-SNAPSHOT\")\n\tvoid isUpgradeWhenReleaseTrainToSnapshotAndMovingToSnapshotsShouldReturnTrue(DependencyVersion current,\n\t\t\tDependencyVersion candidate) {\n\t\tassertThat(current.isUpgrade(candidate, true)).isTrue();\n\t}\n\n\t@Repeatable(ArtifactVersions.class)\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ArgumentsSource(InputProvider.class)\n\t@interface ArtifactVersion {\n\n\t\tString current();\n\n\t\tString candidate();\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface ArtifactVersions {\n\n\t\tArtifactVersion[] value();\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ArgumentsSource(InputProvider.class)\n\t@interface ReleaseTrain {\n\n\t\tString current();\n\n\t\tString candidate();\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ArgumentsSource(InputProvider.class)\n\t@interface CalendarVersion {\n\n\t\tString current();\n\n\t\tString candidate();\n\n\t}\n\n\tstatic class InputProvider implements ArgumentsProvider {\n\n\t\t@Override\n\t\tpublic Stream<? extends Arguments> provideArguments(ParameterDeclarations parameterDeclarations,\n\t\t\t\tExtensionContext context) {\n\t\t\tMethod testMethod = context.getRequiredTestMethod();\n\t\t\tStream<Arguments> artifactVersions = artifactVersions(testMethod)\n\t\t\t\t.map((artifactVersion) -> Arguments.of(VersionType.ARTIFACT_VERSION.parse(artifactVersion.current()),\n\t\t\t\t\t\tVersionType.ARTIFACT_VERSION.parse(artifactVersion.candidate())));\n\t\t\tStream<Arguments> releaseTrains = releaseTrains(testMethod)\n\t\t\t\t.map((releaseTrain) -> Arguments.of(VersionType.RELEASE_TRAIN.parse(releaseTrain.current()),\n\t\t\t\t\t\tVersionType.RELEASE_TRAIN.parse(releaseTrain.candidate())));\n\t\t\tStream<Arguments> calendarVersions = calendarVersions(testMethod)\n\t\t\t\t.map((calendarVersion) -> Arguments.of(VersionType.CALENDAR_VERSION.parse(calendarVersion.current()),\n\t\t\t\t\t\tVersionType.CALENDAR_VERSION.parse(calendarVersion.candidate())));\n\t\t\treturn Stream.concat(Stream.concat(artifactVersions, releaseTrains), calendarVersions);\n\t\t}\n\n\t\tprivate Stream<ArtifactVersion> artifactVersions(Method testMethod) {\n\t\t\tArtifactVersions artifactVersions = testMethod.getAnnotation(ArtifactVersions.class);\n\t\t\tif (artifactVersions != null) {\n\t\t\t\treturn Stream.of(artifactVersions.value());\n\t\t\t}\n\t\t\treturn versions(testMethod, ArtifactVersion.class);\n\t\t}\n\n\t\tprivate Stream<ReleaseTrain> releaseTrains(Method testMethod) {\n\t\t\treturn versions(testMethod, ReleaseTrain.class);\n\t\t}\n\n\t\tprivate Stream<CalendarVersion> calendarVersions(Method testMethod) {\n\t\t\treturn versions(testMethod, CalendarVersion.class);\n\t\t}\n\n\t\tprivate <T extends Annotation> Stream<T> versions(Method testMethod, Class<T> type) {\n\t\t\tT annotation = testMethod.getAnnotation(type);\n\t\t\treturn (annotation != null) ? Stream.of(annotation) : Stream.empty();\n\t\t}\n\n\t}\n\n\tenum VersionType {\n\n\t\tARTIFACT_VERSION(ArtifactVersionDependencyVersion::parse),\n\n\t\tCALENDAR_VERSION(CalendarVersionDependencyVersion::parse),\n\n\t\tRELEASE_TRAIN(ReleaseTrainDependencyVersion::parse);\n\n\t\tprivate final Function<String, DependencyVersion> parser;\n\n\t\tVersionType(Function<String, DependencyVersion> parser) {\n\t\t\tthis.parser = parser;\n\t\t}\n\n\t\tDependencyVersion parse(String version) {\n\t\t\treturn this.parser.apply(version);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/version/MultipleComponentsDependencyVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MultipleComponentsDependencyVersion}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nclass MultipleComponentsDependencyVersionTests {\n\n\t@Test\n\tvoid isSameMajorOfFiveComponentVersionWithSameMajorShouldReturnTrue() {\n\t\tassertThat(version(\"21.4.0.0.1\").isSameMajor(version(\"21.1.0.0\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMajorOfFiveComponentVersionWithDifferentMajorShouldReturnFalse() {\n\t\tassertThat(version(\"21.4.0.0.1\").isSameMajor(version(\"22.1.0.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSameMinorOfFiveComponentVersionWithSameMinorShouldReturnTrue() {\n\t\tassertThat(version(\"21.4.0.0.1\").isSameMinor(version(\"21.4.0.0\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMinorOfFiveComponentVersionWithDifferentMinorShouldReturnFalse() {\n\t\tassertThat(version(\"21.4.0.0.1\").isSameMinor(version(\"21.5.0.0\"))).isFalse();\n\t}\n\n\tprivate MultipleComponentsDependencyVersion version(String version) {\n\t\treturn MultipleComponentsDependencyVersion.parse(version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/bom/bomr/version/ReleaseTrainDependencyVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.bom.bomr.version;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReleaseTrainDependencyVersion}.\n *\n * @author Andy Wilkinson\n */\nclass ReleaseTrainDependencyVersionTests {\n\n\t@Test\n\tvoid parsingOfANonReleaseTrainVersionReturnsNull() {\n\t\tassertThat(version(\"5.1.4.RELEASE\")).isNull();\n\t}\n\n\t@Test\n\tvoid parsingOfAReleaseTrainVersionReturnsVersion() {\n\t\tassertThat(version(\"Lovelace-SR3\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenReleaseTrainIsDifferentShouldReturnFalse() {\n\t\tassertThat(version(\"Lovelace-RELEASE\").isSameMajor(version(\"Kay-SR5\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSameMajorWhenReleaseTrainIsTheSameShouldReturnTrue() {\n\t\tassertThat(version(\"Lovelace-RELEASE\").isSameMajor(version(\"Lovelace-SR5\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameMinorWhenReleaseTrainIsDifferentShouldReturnFalse() {\n\t\tassertThat(version(\"Lovelace-RELEASE\").isSameMajor(version(\"Kay-SR5\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSameMinorWhenReleaseTrainIsTheSameShouldReturnTrue() {\n\t\tassertThat(version(\"Lovelace-RELEASE\").isSameMajor(version(\"Lovelace-SR5\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid releaseTrainVersionIsNotSameMajorAsCalendarTrainVersion() {\n\t\tassertThat(version(\"Kay-SR6\").isSameMajor(calendarVersion(\"2020.0.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid releaseTrainVersionIsNotSameMinorAsCalendarVersion() {\n\t\tassertThat(version(\"Kay-SR6\").isSameMinor(calendarVersion(\"2020.0.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForServiceReleaseShouldReturnTrue() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Kay-SR2\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForReleaseShouldReturnTrue() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Kay-RELEASE\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForReleaseCandidateShouldReturnTrue() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Kay-RC1\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForMilestoneShouldReturnTrue() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Kay-M2\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForDifferentReleaseShouldReturnFalse() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Lovelace-RELEASE\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForDifferentReleaseCandidateShouldReturnTrue() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Lovelace-RC2\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenSnapshotForDifferentMilestoneShouldReturnTrue() {\n\t\tassertThat(version(\"Kay-BUILD-SNAPSHOT\").isSnapshotFor(version(\"Lovelace-M1\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isSnapshotForWhenNotSnapshotShouldReturnFalse() {\n\t\tassertThat(version(\"Kay-M1\").isSnapshotFor(version(\"Kay-RELEASE\"))).isFalse();\n\t}\n\n\tprivate static ReleaseTrainDependencyVersion version(String input) {\n\t\treturn ReleaseTrainDependencyVersion.parse(input);\n\t}\n\n\tprivate CalendarVersionDependencyVersion calendarVersion(String version) {\n\t\treturn CalendarVersionDependencyVersion.parse(version);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/context/properties/CompoundRowTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompoundRow}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\nclass CompoundRowTests {\n\n\tprivate static final String NEWLINE = System.lineSeparator();\n\n\tprivate static final Snippet SNIPPET = new Snippet(\"my\", \"title\", null);\n\n\t@Test\n\tvoid simpleProperty() {\n\t\tCompoundRow row = new CompoundRow(SNIPPET, \"spring.test\", \"This is a description.\");\n\t\trow.addProperty(new ConfigurationProperty(\"spring.test.first\", \"java.lang.String\"));\n\t\trow.addProperty(new ConfigurationProperty(\"spring.test.second\", \"java.lang.String\"));\n\t\trow.addProperty(new ConfigurationProperty(\"spring.test.third\", \"java.lang.String\"));\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test]]xref:#my.spring.test[`+spring.test.first+` +\" + NEWLINE\n\t\t\t\t+ \"`+spring.test.second+` +\" + NEWLINE + \"`+spring.test.third+` +\" + NEWLINE + \"]\" + NEWLINE\n\t\t\t\t+ \"|+++This is a description.+++\" + NEWLINE + \"|\" + NEWLINE);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Analysis;\nimport org.springframework.boot.build.context.properties.ConfigurationPropertiesAnalyzer.Report;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigurationPropertiesAnalyzer}.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationPropertiesAnalyzerTests {\n\n\t@Test\n\tvoid createAnalyzerWithNoSource() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ConfigurationPropertiesAnalyzer(Collections.emptyList()))\n\t\t\t.withMessage(\"At least one source should be provided\");\n\t}\n\n\t@Test\n\tvoid analyzeOrderWithAlphabeticalOrder(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t\t{ \"name\": \"abc\"}, {\"name\": \"def\"}, {\"name\": \"xyz\"}\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzeOrder(report);\n\t\tassertThat(report.hasProblems()).isFalse();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));\n\t}\n\n\t@Test\n\tvoid analyzeOrderWithViolations(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t\t{ \"name\": \"def\"}, {\"name\": \"abc\"}, {\"name\": \"xyz\"}\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzeOrder(report);\n\t\tassertThat(report.hasProblems()).isTrue();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies((analysis) -> assertThat(analysis.getItems()).containsExactly(\n\t\t\t\t\t\"Wrong order at $.properties[0].name - expected 'abc' but found 'def'\",\n\t\t\t\t\t\"Wrong order at $.properties[1].name - expected 'def' but found 'abc'\"));\n\t}\n\n\t@Test\n\tvoid analyzeDuplicatesWithNoDuplicates(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t\t{ \"name\": \"abc\"}, {\"name\": \"def\"}, {\"name\": \"xyz\"}\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzeOrder(report);\n\t\tassertThat(report.hasProblems()).isFalse();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));\n\t}\n\n\t@Test\n\tvoid analyzeDuplicatesWithDuplicate(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t\t{ \"name\": \"abc\"}, {\"name\": \"abc\"}, {\"name\": \"def\"}\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzeDuplicates(report);\n\t\tassertThat(report.hasProblems()).isTrue();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies((analysis) -> assertThat(analysis.getItems())\n\t\t\t\t.containsExactly(\"Duplicate name 'abc' at $.properties[1]\"));\n\t}\n\n\t@Test\n\tvoid analyzePropertyDescription(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t\t{ \"name\": \"abc\", \"description\": \"This is abc.\" },\n\t\t\t\t\t{ \"name\": \"def\", \"description\": \"This is def.\" },\n\t\t\t\t\t{ \"name\": \"xyz\", \"description\": \"This is xyz.\" }\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzePropertyDescription(report, List.of());\n\t\tassertThat(report.hasProblems()).isFalse();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies(((analysis) -> assertThat(analysis.getItems()).isEmpty()));\n\t}\n\n\t@Test\n\tvoid analyzePropertyDescriptionWithMissingDescription(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t\t{ \"name\": \"abc\", \"description\": \"This is abc.\" },\n\t\t\t\t\t{ \"name\": \"def\" },\n\t\t\t\t\t{ \"name\": \"xyz\", \"description\": \"This is xyz.\" }\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzePropertyDescription(report, List.of());\n\t\tassertThat(report.hasProblems()).isTrue();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies(((analysis) -> assertThat(analysis.getItems()).containsExactly(\"def\")));\n\t}\n\n\t@Test\n\tvoid analyzeDeprecatedPropertyWithMissingSince(@TempDir File tempDir) throws IOException {\n\t\tFile metadata = new File(tempDir, \"metadata.json\");\n\t\tFiles.writeString(metadata.toPath(), \"\"\"\n\t\t\t\t{ \"properties\": [\n\t\t\t\t  {\n\t\t\t\t    \"name\": \"abc\",\n\t\t\t\t    \"description\": \"This is abc.\",\n\t\t\t\t    \"deprecation\": { \"reason\": \"abc reason\", \"since\": \"3.0.0\" }\n\t\t\t\t  },\n\t\t\t\t  { \"name\": \"def\", \"description\": \"This is def.\" },\n\t\t\t\t  {\n\t\t\t\t    \"name\": \"xyz\",\n\t\t\t\t    \"description\": \"This is xyz.\",\n\t\t\t\t    \"deprecation\": { \"reason\": \"xyz reason\" }\n\t\t\t\t  }\n\t\t\t\t  ]\n\t\t\t\t}\"\"\");\n\t\tReport report = new Report(tempDir);\n\t\tConfigurationPropertiesAnalyzer analyzer = new ConfigurationPropertiesAnalyzer(List.of(metadata));\n\t\tanalyzer.analyzeDeprecationSince(report);\n\t\tassertThat(report.hasProblems()).isTrue();\n\t\tassertThat(report.getAnalyses(metadata)).singleElement()\n\t\t\t.satisfies(((analysis) -> assertThat(analysis.getItems()).containsExactly(\"xyz\")));\n\t}\n\n\t@Test\n\tvoid writeEmptyReport(@TempDir File tempDir) throws IOException {\n\t\tassertThat(writeToFile(tempDir, new Report(tempDir))).hasContent(\"No problems found.\");\n\t}\n\n\t@Test\n\tvoid writeReportWithNoProblemsFound(@TempDir File tempDir) throws IOException {\n\t\tReport report = new Report(tempDir);\n\t\tFile first = new File(tempDir, \"metadata-1.json\");\n\t\treport.registerAnalysis(first, new Analysis(\"Check for things:\"));\n\t\tFile second = new File(tempDir, \"metadata-2.json\");\n\t\treport.registerAnalysis(second, new Analysis(\"Check for other things:\"));\n\t\tassertThat(writeToFile(tempDir, report)).content().isEqualToIgnoringNewLines(\"\"\"\n\t\t\t\tmetadata-1.json\n\t\t\t\tNo problems found.\n\n\t\t\t\tmetadata-2.json\n\t\t\t\tNo problems found.\n\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid writeReportWithOneProblem(@TempDir File tempDir) throws IOException {\n\t\tReport report = new Report(tempDir);\n\t\tFile metadata = new File(tempDir, \"metadata-1.json\");\n\t\tAnalysis analysis = new Analysis(\"Check for things:\");\n\t\tanalysis.addItem(\"Should not be deprecated\");\n\t\treport.registerAnalysis(metadata, analysis);\n\t\treport.registerAnalysis(metadata, new Analysis(\"Check for other things:\"));\n\t\tassertThat(writeToFile(tempDir, report)).content().isEqualToIgnoringNewLines(\"\"\"\n\t\t\t\tmetadata-1.json\n\t\t\t\tCheck for things:\n\t\t\t\t\t- Should not be deprecated\n\n\t\t\t\tCheck for other things:\n\t\t\t\tNo problems found.\n\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid writeReportWithSeveralProblems(@TempDir File tempDir) throws IOException {\n\t\tReport report = new Report(tempDir);\n\t\tFile metadata = new File(tempDir, \"metadata-1.json\");\n\t\tAnalysis firstAnalysis = new Analysis(\"Check for things:\");\n\t\tfirstAnalysis.addItem(\"Should not be deprecated\");\n\t\tfirstAnalysis.addItem(\"Should not be public\");\n\t\treport.registerAnalysis(metadata, firstAnalysis);\n\t\tAnalysis secondAnalysis = new Analysis(\"Check for other things:\");\n\t\tsecondAnalysis.addItem(\"Field 'this' not expected\");\n\t\treport.registerAnalysis(metadata, secondAnalysis);\n\t\tassertThat(writeToFile(tempDir, report)).content().isEqualToIgnoringNewLines(\"\"\"\n\t\t\t\tmetadata-1.json\n\t\t\t\tCheck for things:\n\t\t\t\t\t- Should not be deprecated\n\t\t\t\t\t- Should not be public\n\n\t\t\t\tCheck for other things:\n\t\t\t\t\t- Field 'this' not expected\n\t\t\t\t\"\"\");\n\t}\n\n\tprivate File writeToFile(File directory, Report report) throws IOException {\n\t\tFile file = new File(directory, \"report.txt\");\n\t\treport.write(file);\n\t\treturn file;\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/context/properties/ConfigurationPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport java.io.File;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationProperties}\n *\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesTests {\n\n\t@Test\n\tvoid whenJsonHasAnIntegerDefaultValueThenItRemainsAnIntegerWhenRead() {\n\t\tConfigurationProperties properties = ConfigurationProperties\n\t\t\t.fromFiles(Arrays.asList(new File(\"src/test/resources/spring-configuration-metadata.json\")));\n\t\tassertThat(properties.get(\"example.counter\").getDefaultValue()).isEqualTo(0);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/context/properties/SingleRowTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SingleRow}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\nclass SingleRowTests {\n\n\tprivate static final String NEWLINE = System.lineSeparator();\n\n\tprivate static final Snippet SNIPPET = new Snippet(\"my\", \"title\", null);\n\n\t@Test\n\tvoid simpleProperty() {\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\", \"java.lang.String\", \"something\",\n\t\t\t\t\"This is a description.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description.+++\" + NEWLINE + \"|`+something+`\" + NEWLINE);\n\t}\n\n\t@Test\n\tvoid noDefaultValue() {\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\", \"java.lang.String\", null,\n\t\t\t\t\"This is a description.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description.+++\" + NEWLINE + \"|\" + NEWLINE);\n\t}\n\n\t@Test\n\tvoid defaultValueWithPipes() {\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\", \"java.lang.String\",\n\t\t\t\t\"first|second\", \"This is a description.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description.+++\" + NEWLINE + \"|`+first\\\\|second+`\" + NEWLINE);\n\t}\n\n\t@Test\n\tvoid defaultValueWithBackslash() {\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\", \"java.lang.String\",\n\t\t\t\t\"first\\\\second\", \"This is a description.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description.+++\" + NEWLINE + \"|`+first\\\\\\\\second+`\" + NEWLINE);\n\t}\n\n\t@Test\n\tvoid descriptionWithPipe() {\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\", \"java.lang.String\", null,\n\t\t\t\t\"This is a description with a | pipe.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description with a \\\\| pipe.+++\" + NEWLINE + \"|\" + NEWLINE);\n\t}\n\n\t@Test\n\tvoid mapProperty() {\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\",\n\t\t\t\t\"java.util.Map<java.lang.String,java.lang.String>\", null, \"This is a description.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop.*+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description.+++\" + NEWLINE + \"|\" + NEWLINE);\n\t}\n\n\t@Test\n\tvoid listProperty() {\n\t\tString[] defaultValue = new String[] { \"first\", \"second\", \"third\" };\n\t\tConfigurationProperty property = new ConfigurationProperty(\"spring.test.prop\",\n\t\t\t\t\"java.util.List<java.lang.String>\", defaultValue, \"This is a description.\", false, null);\n\t\tSingleRow row = new SingleRow(SNIPPET, property);\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\trow.write(asciidoc);\n\t\tassertThat(asciidoc).hasToString(\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\"\n\t\t\t\t+ NEWLINE + \"|+++This is a description.+++\" + NEWLINE + \"|`+first,\" + NEWLINE + \"second,\" + NEWLINE\n\t\t\t\t+ \"third+`\" + NEWLINE);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/context/properties/TableTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.context.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Table}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\nclass TableTests {\n\n\tprivate static final String NEWLINE = System.lineSeparator();\n\n\tprivate static final Snippet SNIPPET = new Snippet(\"my\", \"title\", null);\n\n\t@Test\n\tvoid simpleTable() {\n\t\tTable table = new Table();\n\t\ttable.addRow(new SingleRow(SNIPPET, new ConfigurationProperty(\"spring.test.prop\", \"java.lang.String\",\n\t\t\t\t\"something\", \"This is a description.\", false, null)));\n\t\ttable.addRow(new SingleRow(SNIPPET, new ConfigurationProperty(\"spring.test.other\", \"java.lang.String\",\n\t\t\t\t\"other value\", \"This is another description.\", false, null)));\n\t\tAsciidoc asciidoc = new Asciidoc();\n\t\ttable.write(asciidoc);\n\t\t// @formatter:off\n\t\tassertThat(asciidoc).hasToString(\"[cols=\\\"4,3,3\\\", options=\\\"header\\\"]\" + NEWLINE +\n\t\t\"|===\" + NEWLINE +\n\t\t\"|Name|Description|Default Value\" + NEWLINE + NEWLINE +\n\t\t\"|[[my.spring.test.other]]xref:#my.spring.test.other[`+spring.test.other+`]\" + NEWLINE +\n\t\t\"|+++This is another description.+++\" + NEWLINE +\n\t\t\"|`+other value+`\" + NEWLINE + NEWLINE +\n\t\t\"|[[my.spring.test.prop]]xref:#my.spring.test.prop[`+spring.test.prop+`]\" + NEWLINE +\n\t\t\"|+++This is a description.+++\" + NEWLINE +\n\t\t\"|`+something+`\" + NEWLINE + NEWLINE +\n\t\t\"|===\" + NEWLINE);\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/groovyscripts/SpringRepositoriesExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.groovyscripts;\n\nimport java.io.File;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.UnaryOperator;\n\nimport groovy.lang.Closure;\nimport groovy.lang.GroovyClassLoader;\nimport org.gradle.api.Action;\nimport org.gradle.api.artifacts.dsl.RepositoryHandler;\nimport org.gradle.api.artifacts.repositories.MavenArtifactRepository;\nimport org.gradle.api.artifacts.repositories.MavenRepositoryContentDescriptor;\nimport org.gradle.api.artifacts.repositories.PasswordCredentials;\nimport org.gradle.api.artifacts.repositories.RepositoryContentDescriptor;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.invocation.InvocationOnMock;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\n\n/**\n * Tests for {@code SpringRepositorySupport.groovy}.\n *\n * @author Phillip Webb\n */\nclass SpringRepositoriesExtensionTests {\n\n\tprivate static GroovyClassLoader groovyClassLoader;\n\n\tprivate static Class<?> supportClass;\n\n\t@BeforeAll\n\tstatic void loadGroovyClass() throws Exception {\n\t\tgroovyClassLoader = new GroovyClassLoader(SpringRepositoriesExtensionTests.class.getClassLoader());\n\t\tsupportClass = groovyClassLoader.parseClass(new File(\"SpringRepositorySupport.groovy\"));\n\t}\n\n\t@AfterAll\n\tstatic void cleanup() throws Exception {\n\t\tgroovyClassLoader.close();\n\t}\n\n\tprivate final List<MavenArtifactRepository> repositories = new ArrayList<>();\n\n\tprivate final List<RepositoryContentDescriptor> contents = new ArrayList<>();\n\n\tprivate final List<PasswordCredentials> credentials = new ArrayList<>();\n\n\tprivate final List<MavenRepositoryContentDescriptor> mavenContent = new ArrayList<>();\n\n\t@Test\n\tvoid mavenRepositoriesWhenNotCommercialSnapshot() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"oss\");\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).hasSize(1);\n\t\tverify(this.repositories.get(0)).setName(\"spring-oss-snapshot\");\n\t\tverify(this.repositories.get(0)).setUrl(\"https://repo.spring.io/snapshot\");\n\t\tverify(this.mavenContent.get(0)).snapshotsOnly();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenCommercialSnapshot() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"commercial\");\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).hasSize(3);\n\t\tverify(this.repositories.get(0)).setName(\"spring-commercial-release\");\n\t\tverify(this.repositories.get(0))\n\t\t\t.setUrl(\"https://usw1.packages.broadcom.com/spring-enterprise-maven-prod-local\");\n\t\tverify(this.mavenContent.get(0)).releasesOnly();\n\t\tverify(this.repositories.get(1)).setName(\"spring-commercial-snapshot\");\n\t\tverify(this.repositories.get(1)).setUrl(\"https://usw1.packages.broadcom.com/spring-enterprise-maven-dev-local\");\n\t\tverify(this.mavenContent.get(1)).snapshotsOnly();\n\t\tverify(this.repositories.get(2)).setName(\"spring-oss-snapshot\");\n\t\tverify(this.repositories.get(2)).setUrl(\"https://repo.spring.io/snapshot\");\n\t\tverify(this.mavenContent.get(2)).snapshotsOnly();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenNotCommercialMilestone() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-M1\", \"oss\");\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).isEmpty();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenCommercialMilestone() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-M1\", \"commercial\");\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).hasSize(1);\n\t\tverify(this.repositories.get(0)).setName(\"spring-commercial-release\");\n\t\tverify(this.repositories.get(0))\n\t\t\t.setUrl(\"https://usw1.packages.broadcom.com/spring-enterprise-maven-prod-local\");\n\t\tverify(this.mavenContent.get(0)).releasesOnly();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenNotCommercialRelease() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.1\", \"oss\");\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).isEmpty();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenCommercialRelease() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.1\", \"commercial\");\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).hasSize(1);\n\t\tverify(this.repositories.get(0)).setName(\"spring-commercial-release\");\n\t\tverify(this.repositories.get(0))\n\t\t\t.setUrl(\"https://usw1.packages.broadcom.com/spring-enterprise-maven-prod-local\");\n\t\tverify(this.mavenContent.get(0)).releasesOnly();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenConditionMatches() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"oss\");\n\t\textension.mavenRepositoriesFor(\"1.2.3-SNAPSHOT\");\n\t\tassertThat(this.repositories).hasSize(1);\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenConditionDoesNotMatch() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"oss\");\n\t\textension.mavenRepositoriesFor(\"1.2.3\");\n\t\tassertThat(this.repositories).isEmpty();\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesExcludingBootGroup() {\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"oss\");\n\t\textension.mavenRepositoriesExcludingBootGroup();\n\t\tassertThat(this.contents).hasSize(1);\n\t\tverify(this.contents.get(0)).excludeGroup(\"org.springframework.boot\");\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWithRepositorySpecificEnvironmentVariables() {\n\t\tMap<String, String> environment = new HashMap<>();\n\t\tenvironment.put(\"COMMERCIAL_RELEASE_REPO_URL\", \"curl\");\n\t\tenvironment.put(\"COMMERCIAL_RELEASE_REPO_USERNAME\", \"cuser\");\n\t\tenvironment.put(\"COMMERCIAL_RELEASE_REPO_PASSWORD\", \"cpass\");\n\t\tenvironment.put(\"COMMERCIAL_SNAPSHOT_REPO_URL\", \"surl\");\n\t\tenvironment.put(\"COMMERCIAL_SNAPSHOT_REPO_USERNAME\", \"suser\");\n\t\tenvironment.put(\"COMMERCIAL_SNAPSHOT_REPO_PASSWORD\", \"spass\");\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"commercial\", environment::get);\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).hasSize(3);\n\t\tverify(this.repositories.get(0)).setUrl(\"curl\");\n\t\tverify(this.repositories.get(1)).setUrl(\"surl\");\n\t\tassertThat(this.credentials).hasSize(2);\n\t\tverify(this.credentials.get(0)).setUsername(\"cuser\");\n\t\tverify(this.credentials.get(0)).setPassword(\"cpass\");\n\t\tverify(this.credentials.get(1)).setUsername(\"suser\");\n\t\tverify(this.credentials.get(1)).setPassword(\"spass\");\n\t}\n\n\t@Test\n\tvoid mavenRepositoriesWhenRepositoryEnvironmentVariables() {\n\t\tMap<String, String> environment = new HashMap<>();\n\t\tenvironment.put(\"COMMERCIAL_REPO_URL\", \"url\");\n\t\tenvironment.put(\"COMMERCIAL_REPO_USERNAME\", \"user\");\n\t\tenvironment.put(\"COMMERCIAL_REPO_PASSWORD\", \"pass\");\n\t\tSpringRepositoriesExtension extension = createExtension(\"0.0.0-SNAPSHOT\", \"commercial\", environment::get);\n\t\textension.mavenRepositories();\n\t\tassertThat(this.repositories).hasSize(3);\n\t\tverify(this.repositories.get(0)).setUrl(\"url\");\n\t\tverify(this.repositories.get(1)).setUrl(\"url\");\n\t\tassertThat(this.credentials).hasSize(2);\n\t\tverify(this.credentials.get(0)).setUsername(\"user\");\n\t\tverify(this.credentials.get(0)).setPassword(\"pass\");\n\t\tverify(this.credentials.get(1)).setUsername(\"user\");\n\t\tverify(this.credentials.get(1)).setPassword(\"pass\");\n\t}\n\n\tprivate SpringRepositoriesExtension createExtension(String version, String buildType) {\n\t\treturn createExtension(version, buildType, (name) -> null);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"unchecked\" })\n\tprivate SpringRepositoriesExtension createExtension(String version, String buildType,\n\t\t\tUnaryOperator<String> environment) {\n\t\tRepositoryHandler repositoryHandler = mock(RepositoryHandler.class);\n\t\tgiven(repositoryHandler.maven(any(Closure.class))).willAnswer(this::mavenClosure);\n\t\treturn SpringRepositoriesExtension.get(repositoryHandler, version, buildType, environment);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"unchecked\" })\n\tprivate Object mavenClosure(InvocationOnMock invocation) {\n\t\tMavenArtifactRepository repository = mock(MavenArtifactRepository.class);\n\t\twillAnswer(this::contentAction).given(repository).content(any(Action.class));\n\t\twillAnswer(this::credentialsAction).given(repository).credentials(any(Action.class));\n\t\twillAnswer(this::mavenContentAction).given(repository).mavenContent(any(Action.class));\n\t\tClosure<MavenArtifactRepository> closure = invocation.getArgument(0);\n\t\tclosure.call(repository);\n\t\tthis.repositories.add(repository);\n\t\treturn null;\n\t}\n\n\tprivate Object contentAction(InvocationOnMock invocation) {\n\t\tRepositoryContentDescriptor content = mock(RepositoryContentDescriptor.class);\n\t\tAction<RepositoryContentDescriptor> action = invocation.getArgument(0);\n\t\taction.execute(content);\n\t\tthis.contents.add(content);\n\t\treturn null;\n\t}\n\n\tprivate Object credentialsAction(InvocationOnMock invocation) {\n\t\tPasswordCredentials credentials = mock(PasswordCredentials.class);\n\t\tAction<PasswordCredentials> action = invocation.getArgument(0);\n\t\taction.execute(credentials);\n\t\tthis.credentials.add(credentials);\n\t\treturn null;\n\t}\n\n\tprivate Object mavenContentAction(InvocationOnMock invocation) {\n\t\tMavenRepositoryContentDescriptor mavenContent = mock(MavenRepositoryContentDescriptor.class);\n\t\tAction<MavenRepositoryContentDescriptor> action = invocation.getArgument(0);\n\t\taction.execute(mavenContent);\n\t\tthis.mavenContent.add(mavenContent);\n\t\treturn null;\n\t}\n\n\tinterface SpringRepositoriesExtension {\n\n\t\tvoid mavenRepositories();\n\n\t\tvoid mavenRepositoriesFor(Object version);\n\n\t\tvoid mavenRepositoriesExcludingBootGroup();\n\n\t\tstatic SpringRepositoriesExtension get(RepositoryHandler repositoryHandler, String version, String buildType,\n\t\t\t\tUnaryOperator<String> environment) {\n\t\t\ttry {\n\t\t\t\tClass<?> extensionClass = supportClass.getClassLoader().loadClass(\"SpringRepositoriesExtension\");\n\t\t\t\tObject extension = extensionClass\n\t\t\t\t\t.getDeclaredConstructor(Object.class, Object.class, Object.class, Object.class)\n\t\t\t\t\t.newInstance(repositoryHandler, version, buildType, environment);\n\t\t\t\treturn (SpringRepositoriesExtension) Proxy.newProxyInstance(\n\t\t\t\t\t\tSpringRepositoriesExtensionTests.class.getClassLoader(),\n\t\t\t\t\t\tnew Class<?>[] { SpringRepositoriesExtension.class }, (instance, method, args) -> {\n\t\t\t\t\t\t\tClass<?>[] params = new Class<?>[(args != null) ? args.length : 0];\n\t\t\t\t\t\t\tArrays.fill(params, Object.class);\n\t\t\t\t\t\t\tMethod groovyMethod = extension.getClass().getDeclaredMethod(method.getName(), params);\n\t\t\t\t\t\t\treturn groovyMethod.invoke(extension, args);\n\t\t\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/mavenplugin/PluginXmlParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.mavenplugin;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.build.mavenplugin.PluginXmlParser.Plugin;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link PluginXmlParser}.\n *\n * @author Andy Wilkinson\n * @author Mike Smithson\n */\nclass PluginXmlParserTests {\n\n\tprivate final PluginXmlParser parser = new PluginXmlParser();\n\n\t@Test\n\tvoid parseExistingDescriptorReturnPluginDescriptor() {\n\t\tPlugin plugin = this.parser.parse(new File(\"src/test/resources/plugin.xml\"));\n\t\tassertThat(plugin.getGroupId()).isEqualTo(\"org.springframework.boot\");\n\t\tassertThat(plugin.getArtifactId()).isEqualTo(\"spring-boot-maven-plugin\");\n\t\tassertThat(plugin.getVersion()).isEqualTo(\"2.2.0.GRADLE-SNAPSHOT\");\n\t\tassertThat(plugin.getGoalPrefix()).isEqualTo(\"spring-boot\");\n\t\tassertThat(plugin.getMojos().stream().map(PluginXmlParser.Mojo::getGoal)).containsExactly(\"build-info\", \"help\",\n\t\t\t\t\"repackage\", \"run\", \"start\", \"stop\");\n\t}\n\n\t@Test\n\tvoid parseNonExistingFileThrowException() {\n\t\tassertThatExceptionOfType(RuntimeException.class)\n\t\t\t.isThrownBy(() -> this.parser.parse(new File(\"src/test/resources/nonexistent.xml\")))\n\t\t\t.withCauseInstanceOf(FileNotFoundException.class);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/optional/OptionalDependenciesPluginIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.optional;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OptionalDependenciesPlugin}.\n *\n * @author Andy Wilkinson\n */\nclass OptionalDependenciesPluginIntegrationTests {\n\n\tprivate File projectDir;\n\n\tprivate File buildFile;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File projectDir) {\n\t\tthis.projectDir = projectDir;\n\t\tthis.buildFile = new File(this.projectDir, \"build.gradle\");\n\t}\n\n\t@Test\n\tvoid optionalConfigurationIsCreated() throws IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins { id 'org.springframework.boot.optional-dependencies' }\");\n\t\t\tout.println(\"task printConfigurations {\");\n\t\t\tout.println(\"    doLast {\");\n\t\t\tout.println(\"        configurations.all { println it.name }\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tBuildResult buildResult = runGradle(\"printConfigurations\");\n\t\tassertThat(buildResult.getOutput()).contains(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME);\n\t}\n\n\t@Test\n\tvoid optionalDependenciesAreAddedToMainSourceSetsCompileClasspath() throws IOException {\n\t\toptionalDependenciesAreAddedToSourceSetClasspath(\"main\", \"compileClasspath\");\n\t}\n\n\t@Test\n\tvoid optionalDependenciesAreAddedToMainSourceSetsRuntimeClasspath() throws IOException {\n\t\toptionalDependenciesAreAddedToSourceSetClasspath(\"main\", \"runtimeClasspath\");\n\t}\n\n\t@Test\n\tvoid optionalDependenciesAreAddedToTestSourceSetsCompileClasspath() throws IOException {\n\t\toptionalDependenciesAreAddedToSourceSetClasspath(\"test\", \"compileClasspath\");\n\t}\n\n\t@Test\n\tvoid optionalDependenciesAreAddedToTestSourceSetsRuntimeClasspath() throws IOException {\n\t\toptionalDependenciesAreAddedToSourceSetClasspath(\"test\", \"runtimeClasspath\");\n\t}\n\n\tprivate void optionalDependenciesAreAddedToSourceSetClasspath(String sourceSet, String classpath)\n\t\t\tthrows IOException {\n\t\ttry (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {\n\t\t\tout.println(\"plugins {\");\n\t\t\tout.println(\"    id 'org.springframework.boot.optional-dependencies'\");\n\t\t\tout.println(\"    id 'java'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"repositories {\");\n\t\t\tout.println(\"    mavenCentral()\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"dependencies {\");\n\t\t\tout.println(\"    optional 'org.springframework:spring-jcl:5.1.2.RELEASE'\");\n\t\t\tout.println(\"}\");\n\t\t\tout.println(\"task printClasspath {\");\n\t\t\tout.println(\"    doLast {\");\n\t\t\tout.println(\"        println sourceSets.\" + sourceSet + \".\" + classpath + \".files\");\n\t\t\tout.println(\"    }\");\n\t\t\tout.println(\"}\");\n\t\t}\n\t\tBuildResult buildResult = runGradle(\"printClasspath\");\n\t\tassertThat(buildResult.getOutput()).contains(\"spring-jcl\");\n\t}\n\n\tprivate BuildResult runGradle(String... args) {\n\t\treturn GradleRunner.create().withProjectDir(this.projectDir).withArguments(args).withPluginClasspath().build();\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/test/autoconfigure/TestSliceMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.test.autoconfigure;\n\nimport java.io.File;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.build.test.autoconfigure.TestSliceMetadata.TestSlice;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestSliceMetadata}.\n *\n * @author Andy Wilkinson\n */\npublic class TestSliceMetadataTests {\n\n\t@TempDir\n\tprivate File temp;\n\n\t@Test\n\tvoid roundtripJson() {\n\t\tTestSliceMetadata source = new TestSliceMetadata(\"example\",\n\t\t\t\tList.of(new TestSlice(\"ExampleOneTest\", List.of(\"com.example.OneAutoConfiguration\")),\n\t\t\t\t\t\tnew TestSlice(\"ExampleTwoTest\", List.of(\"com.example.TwoAutoConfiguration\"))));\n\t\tFile metadataFile = new File(this.temp, \"metadata.json\");\n\t\tsource.writeTo(metadataFile);\n\t\tTestSliceMetadata readBack = TestSliceMetadata.readFrom(metadataFile);\n\t\tassertThat(source).isEqualTo(readBack);\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/java/org/springframework/boot/build/testing/TestFailuresPluginIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.testing;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringReader;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integrations tests for {@link TestFailuresPlugin}.\n *\n * @author Andy Wilkinson\n */\nclass TestFailuresPluginIntegrationTests {\n\n\tprivate File projectDir;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File projectDir) {\n\t\tthis.projectDir = projectDir;\n\t}\n\n\t@Test\n\tvoid singleProject() {\n\t\tcreateProject(this.projectDir);\n\t\tBuildResult result = GradleRunner.create()\n\t\t\t.withDebug(true)\n\t\t\t.withProjectDir(this.projectDir)\n\t\t\t.withArguments(\"build\")\n\t\t\t.withPluginClasspath()\n\t\t\t.buildAndFail();\n\t\tassertThat(readLines(result.getOutput())).containsSequence(\"Found test failures in 1 test task:\", \"\", \":test\",\n\t\t\t\t\"    example.ExampleTests > bad()\", \"    example.ExampleTests > fail()\",\n\t\t\t\t\"    example.MoreTests > bad()\", \"    example.MoreTests > fail()\");\n\t}\n\n\t@Test\n\tvoid multiProject() {\n\t\tcreateMultiProjectBuild();\n\t\tBuildResult result = GradleRunner.create()\n\t\t\t.withDebug(true)\n\t\t\t.withProjectDir(this.projectDir)\n\t\t\t.withArguments(\"build\")\n\t\t\t.withPluginClasspath()\n\t\t\t.buildAndFail();\n\t\tassertThat(readLines(result.getOutput())).containsSequence(\"Found test failures in 1 test task:\", \"\",\n\t\t\t\t\":project-one:test\", \"    example.ExampleTests > bad()\", \"    example.ExampleTests > fail()\",\n\t\t\t\t\"    example.MoreTests > bad()\", \"    example.MoreTests > fail()\");\n\t}\n\n\t@Test\n\tvoid multiProjectContinue() {\n\t\tcreateMultiProjectBuild();\n\t\tBuildResult result = GradleRunner.create()\n\t\t\t.withDebug(true)\n\t\t\t.withProjectDir(this.projectDir)\n\t\t\t.withArguments(\"build\", \"--continue\")\n\t\t\t.withPluginClasspath()\n\t\t\t.buildAndFail();\n\t\tassertThat(readLines(result.getOutput())).containsSequence(\"Found test failures in 2 test tasks:\", \"\",\n\t\t\t\t\":project-one:test\", \"    example.ExampleTests > bad()\", \"    example.ExampleTests > fail()\",\n\t\t\t\t\"    example.MoreTests > bad()\", \"    example.MoreTests > fail()\", \"\", \":project-two:test\",\n\t\t\t\t\"    example.ExampleTests > bad()\", \"    example.ExampleTests > fail()\",\n\t\t\t\t\"    example.MoreTests > bad()\", \"    example.MoreTests > fail()\");\n\t}\n\n\t@Test\n\tvoid multiProjectParallel() {\n\t\tcreateMultiProjectBuild();\n\t\tBuildResult result = GradleRunner.create()\n\t\t\t.withDebug(true)\n\t\t\t.withProjectDir(this.projectDir)\n\t\t\t.withArguments(\"build\", \"--parallel\", \"--stacktrace\")\n\t\t\t.withPluginClasspath()\n\t\t\t.buildAndFail();\n\t\tassertThat(readLines(result.getOutput())).containsSequence(\"Found test failures in 2 test tasks:\", \"\",\n\t\t\t\t\":project-one:test\", \"    example.ExampleTests > bad()\", \"    example.ExampleTests > fail()\",\n\t\t\t\t\"    example.MoreTests > bad()\", \"    example.MoreTests > fail()\", \"\", \":project-two:test\",\n\t\t\t\t\"    example.ExampleTests > bad()\", \"    example.ExampleTests > fail()\",\n\t\t\t\t\"    example.MoreTests > bad()\", \"    example.MoreTests > fail()\");\n\t}\n\n\tprivate void createProject(File dir) {\n\t\tFile examplePackage = new File(dir, \"src/test/java/example\");\n\t\texamplePackage.mkdirs();\n\t\tcreateTestSource(\"ExampleTests\", examplePackage);\n\t\tcreateTestSource(\"MoreTests\", examplePackage);\n\t\tcreateBuildScript(dir);\n\t}\n\n\tprivate void createMultiProjectBuild() {\n\t\tcreateProject(new File(this.projectDir, \"project-one\"));\n\t\tcreateProject(new File(this.projectDir, \"project-two\"));\n\t\twithPrintWriter(new File(this.projectDir, \"settings.gradle\"), (writer) -> {\n\t\t\twriter.println(\"include 'project-one'\");\n\t\t\twriter.println(\"include 'project-two'\");\n\t\t});\n\t}\n\n\tprivate void createTestSource(String name, File dir) {\n\t\twithPrintWriter(new File(dir, name + \".java\"), (writer) -> {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import org.junit.jupiter.api.Test;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import static org.assertj.core.api.Assertions.assertThat;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"class \" + name + \"{\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"\t@Test\");\n\t\t\twriter.println(\"\tvoid fail() {\");\n\t\t\twriter.println(\"\t\tassertThat(true).isFalse();\");\n\t\t\twriter.println(\"\t}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"\t@Test\");\n\t\t\twriter.println(\"\tvoid bad() {\");\n\t\t\twriter.println(\"\t\tassertThat(5).isLessThan(4);\");\n\t\t\twriter.println(\"\t}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"\t@Test\");\n\t\t\twriter.println(\"\tvoid ok() {\");\n\t\t\twriter.println(\"\t}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t});\n\t}\n\n\tprivate void createBuildScript(File dir) {\n\t\twithPrintWriter(new File(dir, \"build.gradle\"), (writer) -> {\n\t\t\twriter.println(\"plugins {\");\n\t\t\twriter.println(\"\tid 'java'\");\n\t\t\twriter.println(\"\tid 'org.springframework.boot.test-failures'\");\n\t\t\twriter.println(\"}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"repositories {\");\n\t\t\twriter.println(\"\tmavenCentral()\");\n\t\t\twriter.println(\"}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"dependencies {\");\n\t\t\twriter.println(\"\ttestImplementation 'org.junit.jupiter:junit-jupiter:5.6.0'\");\n\t\t\twriter.println(\"\ttestImplementation 'org.assertj:assertj-core:3.11.1'\");\n\t\t\twriter.println(\"\ttestRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.6.0'\");\n\t\t\twriter.println(\"}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"test {\");\n\t\t\twriter.println(\"\tuseJUnitPlatform()\");\n\t\t\twriter.println(\"}\");\n\t\t});\n\t}\n\n\tprivate void withPrintWriter(File file, Consumer<PrintWriter> consumer) {\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(file))) {\n\t\t\tconsumer.accept(writer);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate List<String> readLines(String output) {\n\t\ttry (BufferedReader reader = new BufferedReader(new StringReader(output))) {\n\t\t\treturn reader.lines().toList();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildSrc/src/test/resources/bom.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nbom {\n\tlibrary(\"ActiveMQ\", \"5.15.11\") {\n\t\tgroup(\"org.apache.activemq\") {\n\t\t\tmodules = [\n\t\t\t\t\"activemq-amqp\",\n\t\t\t\t\"activemq-blueprint\",\n\t\t\t\t\"activemq-broker\",\n\t\t\t\t\"activemq-camel\",\n\t\t\t\t\"activemq-client\",\n\t\t\t\t\"activemq-console\",\n\t\t\t\t\"activemq-http\",\n\t\t\t\t\"activemq-jaas\",\n\t\t\t\t\"activemq-jdbc-store\",\n\t\t\t\t\"activemq-jms-pool\",\n\t\t\t\t\"activemq-kahadb-store\",\n\t\t\t\t\"activemq-karaf\",\n\t\t\t\t\"activemq-leveldb-store\",\n\t\t\t\t\"activemq-log4j-appender\",\n\t\t\t\t\"activemq-mqtt\",\n\t\t\t\t\"activemq-openwire-generator\",\n\t\t\t\t\"activemq-openwire-legacy\",\n\t\t\t\t\"activemq-osgi\",\n\t\t\t\t\"activemq-partition\",\n\t\t\t\t\"activemq-pool\",\n\t\t\t\t\"activemq-ra\",\n\t\t\t\t\"activemq-run\",\n\t\t\t\t\"activemq-runtime-config\",\n\t\t\t\t\"activemq-shiro\",\n\t\t\t\t\"activemq-spring\",\n\t\t\t\t\"activemq-stomp\",\n\t\t\t\t\"activemq-web\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Kotlin\", \"${kotlinVersion}\") {\n\t\tgroup(\"org.jetbrains.kotlin\") {\n\t\t\timports = [\n\t\t\t\t\"kotlin-bom\"\n\t\t\t]\n\t\t\tplugins = [\n\t\t\t\t\"kotlin-maven-plugin\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"OAuth2 OIDC SDK\") {\n\t\tversion(\"8.36.1\") {\n\t\t\tshouldAlignWithVersionFrom(\"Spring Security\")\n\t\t}\n\t\tgroup(\"com.nimbusds\") {\n\t\t\tmodules = [\n\t\t\t\t\"oauth2-oidc-sdk\"\n\t\t\t]\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "buildSrc/src/test/resources/gradle.properties",
    "content": "a=alpha\nb=bravo\nkotlinVersion=1.3.70\nt=tango"
  },
  {
    "path": "buildSrc/src/test/resources/org/springframework/boot/build/antora/expected-playbook.yml",
    "content": "antora:\n  extensions:\n  - require: '@springio/antora-extensions/override-navigation-builder-extension'\n  - require: '@springio/antora-extensions/static-page-extension'\n  - require: '@springio/antora-xref-extension'\n    stub:\n    - appendix:.*\n    - api:.*\n    - reference:.*\n  - require: '@springio/antora-zip-contents-collector-extension'\n    always_include:\n    - classifier: local-aggregate-content\n      name: test\n    locations:\n    - project/build/generated/docs/antora-content/test-${version}-${name}-${classifier}.zip\n    - project/build/generated/docs/antora-dependencies-content/test-dependency/test-${version}-${name}-${classifier}.zip\n    version_file: gradle.properties\n  - require: '@springio/antora-extensions/root-component-extension'\n    root_component_name: boot\nsite:\n  title: Spring Boot\ncontent:\n  sources:\n  - url: ./../../../../..\n    branches: HEAD\n    version: unspecified\n    start_paths:\n    - project/src/docs/antora\nasciidoc:\n  sourcemap: true\n  attributes:\n    chomp: all\n    hide-uri-scheme: '@'\n    javadoc-location: xref:api:java/\n    page-pagination: ''\n    page-stackoverflow-url: https://stackoverflow.com/tags/spring-boot\n    tabs-sync-option: '@'\n  extensions:\n  - '@asciidoctor/tabs'\n  - '@springio/asciidoctor-extensions'\n  - '@springio/asciidoctor-extensions/configuration-properties-extension'\n  - '@springio/asciidoctor-extensions/javadoc-extension'\n  - '@springio/asciidoctor-extensions/section-ids-extension'\nurls:\n  latest_version_segment: ''\nruntime:\n  log:\n    failure_level: warn\noutput:\n  dir: ./../../../site\n"
  },
  {
    "path": "buildSrc/src/test/resources/plugin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!-- Generated by maven-plugin-tools 3.6 -->\n\n<plugin>\n  <name>Spring Boot Maven Plugin</name>\n  <description></description>\n  <groupId>org.springframework.boot</groupId>\n  <artifactId>spring-boot-maven-plugin</artifactId>\n  <version>2.2.0.GRADLE-SNAPSHOT</version>\n  <goalPrefix>spring-boot</goalPrefix>\n  <isolatedRealm>false</isolatedRealm>\n  <inheritedByDefault>true</inheritedByDefault>\n  <mojos>\n    <mojo>\n      <goal>build-info</goal>\n      <description>Generate a {@code build-info.properties} file based on the content of the current\n{@link MavenProject}.</description>\n      <requiresDirectInvocation>false</requiresDirectInvocation>\n      <requiresProject>true</requiresProject>\n      <requiresReports>false</requiresReports>\n      <aggregator>false</aggregator>\n      <requiresOnline>false</requiresOnline>\n      <inheritedByDefault>true</inheritedByDefault>\n      <phase>generate-resources</phase>\n      <implementation>org.springframework.boot.maven.BuildInfoMojo</implementation>\n      <language>java</language>\n      <instantiationStrategy>per-lookup</instantiationStrategy>\n      <executionStrategy>once-per-session</executionStrategy>\n      <since>1.4.0</since>\n      <threadSafe>true</threadSafe>\n      <parameters>\n        <parameter>\n          <name>additionalProperties</name>\n          <type>java.util.Map</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Additional properties to store in the build-info.properties. Each entry is prefixed\nby {@code build.} in the generated build-info.properties.</description>\n        </parameter>\n        <parameter>\n          <name>outputFile</name>\n          <type>java.io.File</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The location of the generated build-info.properties.</description>\n        </parameter>\n        <parameter>\n          <name>project</name>\n          <type>org.apache.maven.project.MavenProject</type>\n          <required>true</required>\n          <editable>false</editable>\n          <description>The Maven project.</description>\n        </parameter>\n        <parameter>\n          <name>session</name>\n          <type>org.apache.maven.execution.MavenSession</type>\n          <required>true</required>\n          <editable>false</editable>\n          <description>The Maven session.</description>\n        </parameter>\n        <parameter>\n          <name>time</name>\n          <type>java.lang.String</type>\n          <since>2.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The value used for the {@code build.time} property in a form suitable for\n{@link Instant#parse(CharSequence)}. Defaults to {@code session.request.startTime}.\nTo disable the {@code build.time} property entirely, use {@code &apos;off&apos;}.</description>\n        </parameter>\n      </parameters>\n      <configuration>\n        <outputFile implementation=\"java.io.File\" default-value=\"${project.build.outputDirectory}/META-INF/build-info.properties\"/>\n        <project implementation=\"org.apache.maven.project.MavenProject\" default-value=\"${project}\"/>\n        <session implementation=\"org.apache.maven.execution.MavenSession\" default-value=\"${session}\"/>\n      </configuration>\n      <requirements>\n        <requirement>\n          <role>org.sonatype.plexus.build.incremental.BuildContext</role>\n          <field-name>buildContext</field-name>\n        </requirement>\n      </requirements>\n    </mojo>\n    <mojo>\n      <goal>help</goal>\n      <description>Display help information on spring-boot-maven-plugin.&lt;br&gt;\nCall &lt;code&gt;mvn spring-boot:help -Ddetail=true -Dgoal=&amp;lt;goal-name&amp;gt;&lt;/code&gt; to display parameter details.</description>\n      <requiresDirectInvocation>false</requiresDirectInvocation>\n      <requiresProject>false</requiresProject>\n      <requiresReports>false</requiresReports>\n      <aggregator>false</aggregator>\n      <requiresOnline>false</requiresOnline>\n      <inheritedByDefault>true</inheritedByDefault>\n      <implementation>org.springframework.boot.maven.HelpMojo</implementation>\n      <language>java</language>\n      <instantiationStrategy>per-lookup</instantiationStrategy>\n      <executionStrategy>once-per-session</executionStrategy>\n      <threadSafe>true</threadSafe>\n      <parameters>\n        <parameter>\n          <name>detail</name>\n          <type>boolean</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>If &lt;code&gt;true&lt;/code&gt;, display all settable properties for each goal.</description>\n        </parameter>\n        <parameter>\n          <name>goal</name>\n          <type>java.lang.String</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The name of the goal for which to show help. If unspecified, all goals will be displayed.</description>\n        </parameter>\n        <parameter>\n          <name>indentSize</name>\n          <type>int</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The number of spaces per indentation level, should be positive.</description>\n        </parameter>\n        <parameter>\n          <name>lineLength</name>\n          <type>int</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The maximum length of a display line, should be positive.</description>\n        </parameter>\n      </parameters>\n      <configuration>\n        <detail implementation=\"boolean\" default-value=\"false\">${detail}</detail>\n        <goal implementation=\"java.lang.String\">${goal}</goal>\n        <indentSize implementation=\"int\" default-value=\"2\">${indentSize}</indentSize>\n        <lineLength implementation=\"int\" default-value=\"80\">${lineLength}</lineLength>\n      </configuration>\n    </mojo>\n    <mojo>\n      <goal>repackage</goal>\n      <description>Repackages existing JAR and WAR archives so that they can be executed from the command\nline using {@literal java -jar}. With &lt;code&gt;layout=NONE&lt;/code&gt; can also be used simply\nto package a JAR with nested dependencies (and no main class, so not executable).</description>\n      <requiresDependencyResolution>compile+runtime</requiresDependencyResolution>\n      <requiresDirectInvocation>false</requiresDirectInvocation>\n      <requiresProject>true</requiresProject>\n      <requiresReports>false</requiresReports>\n      <aggregator>false</aggregator>\n      <requiresOnline>false</requiresOnline>\n      <inheritedByDefault>true</inheritedByDefault>\n      <phase>package</phase>\n      <implementation>org.springframework.boot.maven.RepackageMojo</implementation>\n      <language>java</language>\n      <instantiationStrategy>per-lookup</instantiationStrategy>\n      <executionStrategy>once-per-session</executionStrategy>\n      <since>1.0.0</since>\n      <requiresDependencyCollection>compile+runtime</requiresDependencyCollection>\n      <threadSafe>true</threadSafe>\n      <parameters>\n        <parameter>\n          <name>attach</name>\n          <type>boolean</type>\n          <since>1.4.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Attach the repackaged archive to be installed and deployed.</description>\n        </parameter>\n        <parameter>\n          <name>classifier</name>\n          <type>java.lang.String</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Classifier to add to the repackaged archive. If not given, the main artifact will\nbe replaced by the repackaged archive. If given, the classifier will also be used\nto determine the source archive to repackage: if an artifact with that classifier\nalready exists, it will be used as source and replaced. If no such artifact exists,\nthe main artifact will be used as source and the repackaged archive will be\nattached as a supplemental artifact with that classifier. Attaching the artifact\nallows to deploy it alongside to the original one, see &lt;a href=\n&quot;https://maven.apache.org/plugins/maven-deploy-plugin/examples/deploying-with-classifiers.html&quot;\n&gt;the Maven documentation for more details&lt;/a&gt;.</description>\n        </parameter>\n        <parameter>\n          <name>embeddedLaunchScript</name>\n          <type>java.io.File</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The embedded launch script to prepend to the front of the jar if it is fully\nexecutable. If not specified the &apos;Spring Boot&apos; default script will be used.</description>\n        </parameter>\n        <parameter>\n          <name>embeddedLaunchScriptProperties</name>\n          <type>java.util.Properties</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Properties that should be expanded in the embedded launch script.</description>\n        </parameter>\n        <parameter>\n          <name>excludeDevtools</name>\n          <type>boolean</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Exclude Spring Boot devtools from the repackaged archive.</description>\n        </parameter>\n        <parameter>\n          <name>excludeGroupIds</name>\n          <type>java.lang.String</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Comma separated list of groupId names to exclude (exact match).</description>\n        </parameter>\n        <parameter>\n          <name>excludes</name>\n          <type>java.util.List</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Collection of artifact definitions to exclude. The {@link Exclude} element defines\na {@code groupId} and {@code artifactId} mandatory properties and an optional\n{@code classifier} property.</description>\n        </parameter>\n        <parameter>\n          <name>executable</name>\n          <type>boolean</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Make a fully executable jar for *nix machines by prepending a launch script to the\njar.\n&lt;p&gt;\nCurrently, some tools do not accept this format so you may not always be able to\nuse this technique. For example, {@code jar -xf} may silently fail to extract a jar\nor war that has been made fully-executable. It is recommended that you only enable\nthis option if you intend to execute it directly, rather than running it with\n{@code java -jar} or deploying it to a servlet container.</description>\n        </parameter>\n        <parameter>\n          <name>finalName</name>\n          <type>java.lang.String</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>false</editable>\n          <description>Name of the generated archive.</description>\n        </parameter>\n        <parameter>\n          <name>includeSystemScope</name>\n          <type>boolean</type>\n          <since>1.4.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Include system scoped dependencies.</description>\n        </parameter>\n        <parameter>\n          <name>includes</name>\n          <type>java.util.List</type>\n          <since>1.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Collection of artifact definitions to include. The {@link Include} element defines\na {@code groupId} and {@code artifactId} mandatory properties and an optional\n{@code classifier} property.</description>\n        </parameter>\n        <parameter>\n          <name>layout</name>\n          <type>org.springframework.boot.maven.RepackageMojo$LayoutType</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The type of archive (which corresponds to how the dependencies are laid out inside\nit). Possible values are JAR, WAR, ZIP, DIR, NONE. Defaults to a guess based on the\narchive type.</description>\n        </parameter>\n        <parameter>\n          <name>layoutFactory</name>\n          <type>org.springframework.boot.loader.tools.LayoutFactory</type>\n          <since>1.5.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The layout factory that will be used to create the executable archive if no\nexplicit layout is set. Alternative layouts implementations can be provided by 3rd\nparties.</description>\n        </parameter>\n        <parameter>\n          <name>mainClass</name>\n          <type>java.lang.String</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The name of the main class. If not specified the first compiled class found that\ncontains a &apos;main&apos; method will be used.</description>\n        </parameter>\n        <parameter>\n          <name>outputDirectory</name>\n          <type>java.io.File</type>\n          <since>1.0.0</since>\n          <required>true</required>\n          <editable>true</editable>\n          <description>Directory containing the generated archive.</description>\n        </parameter>\n        <parameter>\n          <name>project</name>\n          <type>org.apache.maven.project.MavenProject</type>\n          <since>1.0.0</since>\n          <required>true</required>\n          <editable>false</editable>\n          <description>The Maven project.</description>\n        </parameter>\n        <parameter>\n          <name>requiresUnpack</name>\n          <type>java.util.List</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>A list of the libraries that must be unpacked from fat jars in order to run.\nSpecify each library as a {@code &lt;dependency&gt;} with a {@code &lt;groupId&gt;} and a\n{@code &lt;artifactId&gt;} and they will be unpacked at runtime.</description>\n        </parameter>\n        <parameter>\n          <name>skip</name>\n          <type>boolean</type>\n          <since>1.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Skip the execution.</description>\n        </parameter>\n      </parameters>\n      <configuration>\n        <attach implementation=\"boolean\" default-value=\"true\"/>\n        <excludeDevtools implementation=\"boolean\" default-value=\"true\">${spring-boot.repackage.excludeDevtools}</excludeDevtools>\n        <excludeGroupIds implementation=\"java.lang.String\" default-value=\"\">${spring-boot.excludeGroupIds}</excludeGroupIds>\n        <excludes implementation=\"java.util.List\">${spring-boot.excludes}</excludes>\n        <executable implementation=\"boolean\" default-value=\"false\"/>\n        <finalName implementation=\"java.lang.String\" default-value=\"${project.build.finalName}\"/>\n        <includeSystemScope implementation=\"boolean\" default-value=\"false\"/>\n        <includes implementation=\"java.util.List\">${spring-boot.includes}</includes>\n        <layout implementation=\"org.springframework.boot.maven.RepackageMojo$LayoutType\">${spring-boot.repackage.layout}</layout>\n        <outputDirectory implementation=\"java.io.File\" default-value=\"${project.build.directory}\"/>\n        <project implementation=\"org.apache.maven.project.MavenProject\" default-value=\"${project}\"/>\n        <skip implementation=\"boolean\" default-value=\"false\">${spring-boot.repackage.skip}</skip>\n      </configuration>\n      <requirements>\n        <requirement>\n          <role>org.apache.maven.project.MavenProjectHelper</role>\n          <field-name>projectHelper</field-name>\n        </requirement>\n      </requirements>\n    </mojo>\n    <mojo>\n      <goal>run</goal>\n      <description>Run an executable archive application.</description>\n      <requiresDependencyResolution>test</requiresDependencyResolution>\n      <requiresDirectInvocation>false</requiresDirectInvocation>\n      <requiresProject>true</requiresProject>\n      <requiresReports>false</requiresReports>\n      <aggregator>false</aggregator>\n      <requiresOnline>false</requiresOnline>\n      <inheritedByDefault>true</inheritedByDefault>\n      <phase>validate</phase>\n      <executePhase>test-compile</executePhase>\n      <implementation>org.springframework.boot.maven.RunMojo</implementation>\n      <language>java</language>\n      <instantiationStrategy>per-lookup</instantiationStrategy>\n      <executionStrategy>once-per-session</executionStrategy>\n      <since>1.0.0</since>\n      <threadSafe>false</threadSafe>\n      <parameters>\n        <parameter>\n          <name>addResources</name>\n          <type>boolean</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Add maven resources to the classpath directly, this allows live in-place editing of\nresources. Duplicate resources are removed from {@code target/classes} to prevent\nthem to appear twice if {@code ClassLoader.getResources()} is called. Please\nconsider adding {@code spring-boot-devtools} to your project instead as it provides\nthis feature and many more.</description>\n        </parameter>\n        <parameter>\n          <name>agent</name>\n          <type>java.io.File[]</type>\n          <since>1.0.0</since>\n          <deprecated>since 2.2.0 in favor of {@code agents}</deprecated>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Path to agent jar. NOTE: a forked process is required to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>agents</name>\n          <type>java.io.File[]</type>\n          <since>2.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Path to agent jars. NOTE: a forked process is required to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>arguments</name>\n          <type>java.lang.String[]</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Arguments that should be passed to the application. On command line use commas to\nseparate multiple arguments.</description>\n        </parameter>\n        <parameter>\n          <name>classesDirectory</name>\n          <type>java.io.File</type>\n          <since>1.0.0</since>\n          <required>true</required>\n          <editable>true</editable>\n          <description>Directory containing the classes and resource files that should be packaged into\nthe archive.</description>\n        </parameter>\n        <parameter>\n          <name>environmentVariables</name>\n          <type>java.util.Map</type>\n          <since>2.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>List of Environment variables that should be associated with the forked process\nused to run the application. NOTE: a forked process is required to use this\nfeature.</description>\n        </parameter>\n        <parameter>\n          <name>excludeGroupIds</name>\n          <type>java.lang.String</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Comma separated list of groupId names to exclude (exact match).</description>\n        </parameter>\n        <parameter>\n          <name>excludes</name>\n          <type>java.util.List</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Collection of artifact definitions to exclude. The {@link Exclude} element defines\na {@code groupId} and {@code artifactId} mandatory properties and an optional\n{@code classifier} property.</description>\n        </parameter>\n        <parameter>\n          <name>folders</name>\n          <type>java.lang.String[]</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Additional folders besides the classes directory that should be added to the\nclasspath.</description>\n        </parameter>\n        <parameter>\n          <name>fork</name>\n          <type>boolean</type>\n          <since>1.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to indicate if the run processes should be forked. Disabling forking will\ndisable some features such as an agent, custom JVM arguments, devtools or\nspecifying the working directory to use.</description>\n        </parameter>\n        <parameter>\n          <name>includes</name>\n          <type>java.util.List</type>\n          <since>1.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Collection of artifact definitions to include. The {@link Include} element defines\na {@code groupId} and {@code artifactId} mandatory properties and an optional\n{@code classifier} property.</description>\n        </parameter>\n        <parameter>\n          <name>jvmArguments</name>\n          <type>java.lang.String</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>JVM arguments that should be associated with the forked process used to run the\napplication. On command line, make sure to wrap multiple values between quotes.\nNOTE: a forked process is required to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>mainClass</name>\n          <type>java.lang.String</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The name of the main class. If not specified the first compiled class found that\ncontains a &apos;main&apos; method will be used.</description>\n        </parameter>\n        <parameter>\n          <name>noverify</name>\n          <type>boolean</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to say that the agent requires -noverify.</description>\n        </parameter>\n        <parameter>\n          <name>optimizedLaunch</name>\n          <type>boolean</type>\n          <since>2.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Whether the JVM&apos;s launch should be optimized.</description>\n        </parameter>\n        <parameter>\n          <name>profiles</name>\n          <type>java.lang.String[]</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The spring profiles to activate. Convenience shortcut of specifying the\n&apos;spring.profiles.active&apos; argument. On command line use commas to separate multiple\nprofiles.</description>\n        </parameter>\n        <parameter>\n          <name>project</name>\n          <type>org.apache.maven.project.MavenProject</type>\n          <since>1.0.0</since>\n          <required>true</required>\n          <editable>false</editable>\n          <description>The Maven project.</description>\n        </parameter>\n        <parameter>\n          <name>skip</name>\n          <type>boolean</type>\n          <since>1.3.2</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Skip the execution.</description>\n        </parameter>\n        <parameter>\n          <name>systemPropertyVariables</name>\n          <type>java.util.Map</type>\n          <since>2.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>List of JVM system properties to pass to the process. NOTE: a forked process is\nrequired to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>useTestClasspath</name>\n          <type>java.lang.Boolean</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to include the test classpath when running.</description>\n        </parameter>\n        <parameter>\n          <name>workingDirectory</name>\n          <type>java.io.File</type>\n          <since>1.5.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Current working directory to use for the application. If not specified, basedir\nwill be used. NOTE: a forked process is required to use this feature.</description>\n        </parameter>\n      </parameters>\n      <configuration>\n        <addResources implementation=\"boolean\" default-value=\"false\">${spring-boot.run.addResources}</addResources>\n        <agent implementation=\"java.io.File[]\">${spring-boot.run.agent}</agent>\n        <agents implementation=\"java.io.File[]\">${spring-boot.run.agents}</agents>\n        <arguments implementation=\"java.lang.String[]\">${spring-boot.run.arguments}</arguments>\n        <classesDirectory implementation=\"java.io.File\" default-value=\"${project.build.outputDirectory}\"/>\n        <excludeGroupIds implementation=\"java.lang.String\" default-value=\"\">${spring-boot.excludeGroupIds}</excludeGroupIds>\n        <excludes implementation=\"java.util.List\">${spring-boot.excludes}</excludes>\n        <folders implementation=\"java.lang.String[]\">${spring-boot.run.folders}</folders>\n        <fork implementation=\"boolean\" default-value=\"true\">${spring-boot.run.fork}</fork>\n        <includes implementation=\"java.util.List\">${spring-boot.includes}</includes>\n        <jvmArguments implementation=\"java.lang.String\">${spring-boot.run.jvmArguments}</jvmArguments>\n        <mainClass implementation=\"java.lang.String\">${spring-boot.run.main-class}</mainClass>\n        <noverify implementation=\"boolean\">${spring-boot.run.noverify}</noverify>\n        <optimizedLaunch implementation=\"boolean\" default-value=\"true\">${spring-boot.run.optimizedLaunch}</optimizedLaunch>\n        <profiles implementation=\"java.lang.String[]\">${spring-boot.run.profiles}</profiles>\n        <project implementation=\"org.apache.maven.project.MavenProject\" default-value=\"${project}\"/>\n        <skip implementation=\"boolean\" default-value=\"false\">${spring-boot.run.skip}</skip>\n        <useTestClasspath implementation=\"java.lang.Boolean\" default-value=\"false\">${spring-boot.run.useTestClasspath}</useTestClasspath>\n        <workingDirectory implementation=\"java.io.File\">${spring-boot.run.workingDirectory}</workingDirectory>\n      </configuration>\n    </mojo>\n    <mojo>\n      <goal>start</goal>\n      <description>Start a spring application. Contrary to the {@code run} goal, this does not block and\nallows other goal to operate on the application. This goal is typically used in\nintegration test scenario where the application is started before a test suite and\nstopped after.</description>\n      <requiresDependencyResolution>test</requiresDependencyResolution>\n      <requiresDirectInvocation>false</requiresDirectInvocation>\n      <requiresProject>true</requiresProject>\n      <requiresReports>false</requiresReports>\n      <aggregator>false</aggregator>\n      <requiresOnline>false</requiresOnline>\n      <inheritedByDefault>true</inheritedByDefault>\n      <phase>pre-integration-test</phase>\n      <implementation>org.springframework.boot.maven.StartMojo</implementation>\n      <language>java</language>\n      <instantiationStrategy>per-lookup</instantiationStrategy>\n      <executionStrategy>once-per-session</executionStrategy>\n      <since>1.3.0</since>\n      <threadSafe>false</threadSafe>\n      <parameters>\n        <parameter>\n          <name>addResources</name>\n          <type>boolean</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Add maven resources to the classpath directly, this allows live in-place editing of\nresources. Duplicate resources are removed from {@code target/classes} to prevent\nthem to appear twice if {@code ClassLoader.getResources()} is called. Please\nconsider adding {@code spring-boot-devtools} to your project instead as it provides\nthis feature and many more.</description>\n        </parameter>\n        <parameter>\n          <name>agent</name>\n          <type>java.io.File[]</type>\n          <since>1.0.0</since>\n          <deprecated>since 2.2.0 in favor of {@code agents}</deprecated>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Path to agent jar. NOTE: a forked process is required to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>agents</name>\n          <type>java.io.File[]</type>\n          <since>2.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Path to agent jars. NOTE: a forked process is required to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>arguments</name>\n          <type>java.lang.String[]</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Arguments that should be passed to the application. On command line use commas to\nseparate multiple arguments.</description>\n        </parameter>\n        <parameter>\n          <name>classesDirectory</name>\n          <type>java.io.File</type>\n          <since>1.0.0</since>\n          <required>true</required>\n          <editable>true</editable>\n          <description>Directory containing the classes and resource files that should be packaged into\nthe archive.</description>\n        </parameter>\n        <parameter>\n          <name>environmentVariables</name>\n          <type>java.util.Map</type>\n          <since>2.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>List of Environment variables that should be associated with the forked process\nused to run the application. NOTE: a forked process is required to use this\nfeature.</description>\n        </parameter>\n        <parameter>\n          <name>excludeGroupIds</name>\n          <type>java.lang.String</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Comma separated list of groupId names to exclude (exact match).</description>\n        </parameter>\n        <parameter>\n          <name>excludes</name>\n          <type>java.util.List</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Collection of artifact definitions to exclude. The {@link Exclude} element defines\na {@code groupId} and {@code artifactId} mandatory properties and an optional\n{@code classifier} property.</description>\n        </parameter>\n        <parameter>\n          <name>folders</name>\n          <type>java.lang.String[]</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Additional folders besides the classes directory that should be added to the\nclasspath.</description>\n        </parameter>\n        <parameter>\n          <name>fork</name>\n          <type>boolean</type>\n          <since>1.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to indicate if the run processes should be forked. Disabling forking will\ndisable some features such as an agent, custom JVM arguments, devtools or\nspecifying the working directory to use.</description>\n        </parameter>\n        <parameter>\n          <name>includes</name>\n          <type>java.util.List</type>\n          <since>1.2.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Collection of artifact definitions to include. The {@link Include} element defines\na {@code groupId} and {@code artifactId} mandatory properties and an optional\n{@code classifier} property.</description>\n        </parameter>\n        <parameter>\n          <name>jmxName</name>\n          <type>java.lang.String</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The JMX name of the automatically deployed MBean managing the lifecycle of the\nspring application.</description>\n        </parameter>\n        <parameter>\n          <name>jmxPort</name>\n          <type>int</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The port to use to expose the platform MBeanServer if the application is forked.</description>\n        </parameter>\n        <parameter>\n          <name>jvmArguments</name>\n          <type>java.lang.String</type>\n          <since>1.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>JVM arguments that should be associated with the forked process used to run the\napplication. On command line, make sure to wrap multiple values between quotes.\nNOTE: a forked process is required to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>mainClass</name>\n          <type>java.lang.String</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The name of the main class. If not specified the first compiled class found that\ncontains a &apos;main&apos; method will be used.</description>\n        </parameter>\n        <parameter>\n          <name>maxAttempts</name>\n          <type>int</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The maximum number of attempts to check if the spring application is ready.\nCombined with the &quot;wait&quot; argument, this gives a global timeout value (30 sec by\ndefault)</description>\n        </parameter>\n        <parameter>\n          <name>noverify</name>\n          <type>boolean</type>\n          <since>1.0.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to say that the agent requires -noverify.</description>\n        </parameter>\n        <parameter>\n          <name>profiles</name>\n          <type>java.lang.String[]</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The spring profiles to activate. Convenience shortcut of specifying the\n&apos;spring.profiles.active&apos; argument. On command line use commas to separate multiple\nprofiles.</description>\n        </parameter>\n        <parameter>\n          <name>project</name>\n          <type>org.apache.maven.project.MavenProject</type>\n          <since>1.0.0</since>\n          <required>true</required>\n          <editable>false</editable>\n          <description>The Maven project.</description>\n        </parameter>\n        <parameter>\n          <name>skip</name>\n          <type>boolean</type>\n          <since>1.3.2</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Skip the execution.</description>\n        </parameter>\n        <parameter>\n          <name>systemPropertyVariables</name>\n          <type>java.util.Map</type>\n          <since>2.1.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>List of JVM system properties to pass to the process. NOTE: a forked process is\nrequired to use this feature.</description>\n        </parameter>\n        <parameter>\n          <name>useTestClasspath</name>\n          <type>java.lang.Boolean</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to include the test classpath when running.</description>\n        </parameter>\n        <parameter>\n          <name>wait</name>\n          <type>long</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The number of milliseconds to wait between each attempt to check if the spring\napplication is ready.</description>\n        </parameter>\n        <parameter>\n          <name>workingDirectory</name>\n          <type>java.io.File</type>\n          <since>1.5.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Current working directory to use for the application. If not specified, basedir\nwill be used. NOTE: a forked process is required to use this feature.</description>\n        </parameter>\n      </parameters>\n      <configuration>\n        <addResources implementation=\"boolean\" default-value=\"false\">${spring-boot.run.addResources}</addResources>\n        <agent implementation=\"java.io.File[]\">${spring-boot.run.agent}</agent>\n        <agents implementation=\"java.io.File[]\">${spring-boot.run.agents}</agents>\n        <arguments implementation=\"java.lang.String[]\">${spring-boot.run.arguments}</arguments>\n        <classesDirectory implementation=\"java.io.File\" default-value=\"${project.build.outputDirectory}\"/>\n        <excludeGroupIds implementation=\"java.lang.String\" default-value=\"\">${spring-boot.excludeGroupIds}</excludeGroupIds>\n        <excludes implementation=\"java.util.List\">${spring-boot.excludes}</excludes>\n        <folders implementation=\"java.lang.String[]\">${spring-boot.run.folders}</folders>\n        <fork implementation=\"boolean\" default-value=\"true\">${spring-boot.run.fork}</fork>\n        <includes implementation=\"java.util.List\">${spring-boot.includes}</includes>\n        <jvmArguments implementation=\"java.lang.String\">${spring-boot.run.jvmArguments}</jvmArguments>\n        <mainClass implementation=\"java.lang.String\">${spring-boot.run.main-class}</mainClass>\n        <noverify implementation=\"boolean\">${spring-boot.run.noverify}</noverify>\n        <profiles implementation=\"java.lang.String[]\">${spring-boot.run.profiles}</profiles>\n        <project implementation=\"org.apache.maven.project.MavenProject\" default-value=\"${project}\"/>\n        <skip implementation=\"boolean\" default-value=\"false\">${spring-boot.run.skip}</skip>\n        <useTestClasspath implementation=\"java.lang.Boolean\" default-value=\"false\">${spring-boot.run.useTestClasspath}</useTestClasspath>\n        <workingDirectory implementation=\"java.io.File\">${spring-boot.run.workingDirectory}</workingDirectory>\n      </configuration>\n    </mojo>\n    <mojo>\n      <goal>stop</goal>\n      <description>Stop a spring application that has been started by the &quot;start&quot; goal. Typically invoked\nonce a test suite has completed.</description>\n      <requiresDirectInvocation>false</requiresDirectInvocation>\n      <requiresProject>true</requiresProject>\n      <requiresReports>false</requiresReports>\n      <aggregator>false</aggregator>\n      <requiresOnline>false</requiresOnline>\n      <inheritedByDefault>true</inheritedByDefault>\n      <phase>post-integration-test</phase>\n      <implementation>org.springframework.boot.maven.StopMojo</implementation>\n      <language>java</language>\n      <instantiationStrategy>per-lookup</instantiationStrategy>\n      <executionStrategy>once-per-session</executionStrategy>\n      <since>1.3.0</since>\n      <threadSafe>false</threadSafe>\n      <parameters>\n        <parameter>\n          <name>fork</name>\n          <type>java.lang.Boolean</type>\n          <since>1.3.0</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Flag to indicate if process to stop was forked. By default, the value is inherited\nfrom the {@link MavenProject}. If it is set, it must match the value used to\n{@link StartMojo start} the process.</description>\n        </parameter>\n        <parameter>\n          <name>jmxName</name>\n          <type>java.lang.String</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The JMX name of the automatically deployed MBean managing the lifecycle of the\napplication.</description>\n        </parameter>\n        <parameter>\n          <name>jmxPort</name>\n          <type>int</type>\n          <required>false</required>\n          <editable>true</editable>\n          <description>The port to use to look up the platform MBeanServer if the application has been\nforked.</description>\n        </parameter>\n        <parameter>\n          <name>project</name>\n          <type>org.apache.maven.project.MavenProject</type>\n          <since>1.4.1</since>\n          <required>true</required>\n          <editable>false</editable>\n          <description>The Maven project.</description>\n        </parameter>\n        <parameter>\n          <name>skip</name>\n          <type>boolean</type>\n          <since>1.3.2</since>\n          <required>false</required>\n          <editable>true</editable>\n          <description>Skip the execution.</description>\n        </parameter>\n      </parameters>\n      <configuration>\n        <fork implementation=\"java.lang.Boolean\">${spring-boot.stop.fork}</fork>\n        <project implementation=\"org.apache.maven.project.MavenProject\" default-value=\"${project}\"/>\n        <skip implementation=\"boolean\" default-value=\"false\">${spring-boot.stop.skip}</skip>\n      </configuration>\n    </mojo>\n  </mojos>\n  <dependencies/>\n</plugin>\n"
  },
  {
    "path": "buildSrc/src/test/resources/releases.json",
    "content": "[\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-22\",\n        \"title\": \"Spring Modulith 1.0.1\",\n        \"url\": \"https://github.com/spring-projects/spring-modulith/milestone/15\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-22\",\n        \"title\": \"Spring Modulith 1.1 M1\",\n        \"url\": \"https://github.com/spring-projects/spring-modulith/milestone/16\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor 2020.0.36\",\n        \"url\": \"https://github.com/reactor/reactor/milestone/51\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor 2022.0.11\",\n        \"url\": \"https://github.com/reactor/reactor/milestone/52\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor 2023.0.0-M3\",\n        \"url\": \"https://github.com/reactor/reactor/milestone/53\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor Core 3.4.33\",\n        \"url\": \"https://github.com/reactor/reactor-core/milestone/158\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor Core 3.5.10\",\n        \"url\": \"https://github.com/reactor/reactor-core/milestone/159\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor Core 3.6.0-M3\",\n        \"url\": \"https://github.com/reactor/reactor-core/milestone/160\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-13\",\n        \"title\": \"Sts4 4.20.0.RELEASE\",\n        \"url\": \"https://github.com/spring-projects/sts4/milestone/66\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-20\",\n        \"title\": \"Spring Batch 5.1.0-M3\",\n        \"url\": \"https://github.com/spring-projects/spring-batch/milestone/150\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Integration 6.2.0-M3\",\n        \"url\": \"https://github.com/spring-projects/spring-integration/milestone/306\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Integration 5.5.19\",\n        \"url\": \"https://github.com/spring-projects/spring-integration/milestone/309\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Integration 6.1.3\",\n        \"url\": \"https://github.com/spring-projects/spring-integration/milestone/310\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-15\",\n        \"title\": \"Spring Data Release 2023.1.0-M3\",\n        \"url\": \"https://github.com/spring-projects/spring-data-release/milestone/30\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-15\",\n        \"title\": \"Spring Data Release 2021.2.16\",\n        \"url\": \"https://github.com/spring-projects/spring-data-release/milestone/39\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-15\",\n        \"title\": \"Spring Data Release 2022.0.10\",\n        \"url\": \"https://github.com/spring-projects/spring-data-release/milestone/40\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-15\",\n        \"title\": \"Spring Data Release 2023.0.4\",\n        \"url\": \"https://github.com/spring-projects/spring-data-release/milestone/41\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Graphql 1.0.5\",\n        \"url\": \"https://github.com/spring-projects/spring-graphql/milestone/27\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Graphql 1.1.6\",\n        \"url\": \"https://github.com/spring-projects/spring-graphql/milestone/33\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Graphql 1.2.3\",\n        \"url\": \"https://github.com/spring-projects/spring-graphql/milestone/34\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-19\",\n        \"title\": \"Spring Authorization Server 1.2.0-M1\",\n        \"url\": \"https://github.com/spring-projects/spring-authorization-server/milestone/34\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-18\",\n        \"title\": \"Spring Kafka 3.1.0-M1\",\n        \"url\": \"https://github.com/spring-projects/spring-kafka/milestone/225\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-14\",\n        \"title\": \"Spring Cloud Dataflow 2.11.0\",\n        \"url\": \"https://github.com/spring-cloud/spring-cloud-dataflow/milestone/159\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Micrometer 1.9.15\",\n        \"url\": \"https://github.com/micrometer-metrics/micrometer/milestone/217\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Micrometer 1.10.11\",\n        \"url\": \"https://github.com/micrometer-metrics/micrometer/milestone/218\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Micrometer 1.11.4\",\n        \"url\": \"https://github.com/micrometer-metrics/micrometer/milestone/219\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Micrometer 1.12.0-M3\",\n        \"url\": \"https://github.com/micrometer-metrics/micrometer/milestone/220\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Tracing 1.0.10\",\n        \"url\": \"https://github.com/micrometer-metrics/tracing/milestone/33\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Tracing 1.1.5\",\n        \"url\": \"https://github.com/micrometer-metrics/tracing/milestone/34\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-26\",\n        \"title\": \"Spring Cloud Release 2023.0.0-M2\",\n        \"url\": \"https://github.com/spring-cloud/spring-cloud-release/milestone/134\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-11\",\n        \"title\": \"Context Propagation 1.0.6\",\n        \"url\": \"https://github.com/micrometer-metrics/context-propagation/milestone/19\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-14\",\n        \"title\": \"Spring Ldap 3.2.0-M3\",\n        \"url\": \"https://github.com/spring-projects/spring-ldap/milestone/63\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-21\",\n        \"title\": \"Spring Boot 3.2.0-M3\",\n        \"url\": \"https://github.com/spring-projects/spring-boot/milestone/306\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-21\",\n        \"title\": \"Spring Boot 2.7.16\",\n        \"url\": \"https://github.com/spring-projects/spring-boot/milestone/315\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-21\",\n        \"title\": \"Spring Boot 3.0.11\",\n        \"url\": \"https://github.com/spring-projects/spring-boot/milestone/316\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-21\",\n        \"title\": \"Spring Boot 3.1.4\",\n        \"url\": \"https://github.com/spring-projects/spring-boot/milestone/317\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-14\",\n        \"title\": \"Spring Cloud Deployer 2.9.0\",\n        \"url\": \"https://github.com/spring-cloud/spring-cloud-deployer/milestone/116\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor Kafka 1.3.21\",\n        \"url\": \"https://github.com/reactor/reactor-kafka/milestone/38\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-18\",\n        \"title\": \"Spring Security 6.2.0-M3\",\n        \"url\": \"https://github.com/spring-projects/spring-security/milestone/308\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-22\",\n        \"title\": \"Stream Applications 4.0.0\",\n        \"url\": \"https://github.com/spring-cloud/stream-applications/milestone/7\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor Netty 1.1.11\",\n        \"url\": \"https://github.com/reactor/reactor-netty/milestone/153\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-12\",\n        \"title\": \"Reactor Netty 1.0.36\",\n        \"url\": \"https://github.com/reactor/reactor-netty/milestone/154\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-14\",\n        \"title\": \"Spring Framework 6.0.12\",\n        \"url\": \"https://github.com/spring-projects/spring-framework/milestone/331\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-14\",\n        \"title\": \"Spring Framework 5.3.30\",\n        \"url\": \"https://github.com/spring-projects/spring-framework/milestone/332\"\n    },\n    {\n        \"allDay\": true,\n        \"start\": \"2023-09-14\",\n        \"title\": \"Spring Framework 6.1.0-RC1\",\n        \"url\": \"https://github.com/spring-projects/spring-framework/milestone/333\"\n    }\n]"
  },
  {
    "path": "buildSrc/src/test/resources/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"example.counter\",\n      \"type\": \"java.lang.Integer\",\n      \"defaultValue\": 0\n    }\n  ]\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Buildpack Platform\"\n\ndependencies {\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\n\tdockerTestRuntimeOnly(\"org.testcontainers:testcontainers\")\n\n\timplementation(\"net.java.dev.jna:jna-platform\")\n\timplementation(\"org.apache.commons:commons-compress\")\n\timplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\timplementation(\"org.springframework:spring-core\")\n\timplementation(\"org.tomlj:tomlj:1.0.0\")\n\timplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/dockerTest/java/org/springframework/boot/buildpack/platform/docker/DockerApiIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\n\n/**\n * Integration tests for {@link DockerApi}.\n *\n * @author Phillip Webb\n */\n@DisabledIfDockerUnavailable\nclass DockerApiIntegrationTests {\n\n\tprivate final DockerApi docker = new DockerApi();\n\n\t@Test\n\tvoid pullImage() throws IOException {\n\t\tthis.docker.image()\n\t\t\t.pull(ImageReference.of(\"docker.io/paketobuildpacks/builder:base\"), null,\n\t\t\t\t\tnew TotalProgressPullListener(new TotalProgressBar(\"Pulling: \")));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/AbstractBuildLog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\n\n/**\n * Base class for {@link BuildLog} implementations.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Andrey Shlykov\n * @author Rafael Ceccone\n * @since 2.3.0\n */\npublic abstract class AbstractBuildLog implements BuildLog {\n\n\t@Override\n\tpublic void start(BuildRequest request) {\n\t\tlog(\"Building image '\" + request.getName() + \"'\");\n\t\tlog();\n\t}\n\n\t@Override\n\tpublic Consumer<TotalProgressEvent> pullingImage(ImageReference imageReference, @Nullable ImagePlatform platform,\n\t\t\tImageType imageType) {\n\t\treturn (platform != null)\n\t\t\t\t? getProgressConsumer(\" > Pulling %s '%s' for platform '%s'\".formatted(imageType.getDescription(),\n\t\t\t\t\t\timageReference, platform))\n\t\t\t\t: getProgressConsumer(\" > Pulling %s '%s'\".formatted(imageType.getDescription(), imageReference));\n\t}\n\n\t@Override\n\tpublic void pulledImage(Image image, ImageType imageType) {\n\t\tlog(String.format(\" > Pulled %s '%s'\", imageType.getDescription(), getDigest(image)));\n\t}\n\n\t@Override\n\tpublic Consumer<TotalProgressEvent> pushingImage(ImageReference imageReference) {\n\t\treturn getProgressConsumer(String.format(\" > Pushing image '%s'\", imageReference));\n\t}\n\n\t@Override\n\tpublic void pushedImage(ImageReference imageReference) {\n\t\tlog(String.format(\" > Pushed image '%s'\", imageReference));\n\t}\n\n\t@Override\n\tpublic void executingLifecycle(BuildRequest request, LifecycleVersion version, VolumeName buildCacheVolume) {\n\t\tlog(\" > Executing lifecycle version \" + version);\n\t\tlog(\" > Using build cache volume '\" + buildCacheVolume + \"'\");\n\t}\n\n\t@Override\n\tpublic void executingLifecycle(BuildRequest request, LifecycleVersion version, Cache buildCache) {\n\t\tlog(\" > Executing lifecycle version \" + version);\n\t\tlog(\" > Using build cache \" + buildCache);\n\t}\n\n\t@Override\n\tpublic Consumer<LogUpdateEvent> runningPhase(BuildRequest request, String name) {\n\t\tlog();\n\t\tlog(\" > Running \" + name);\n\t\tString prefix = String.format(\"    %-14s\", \"[\" + name + \"] \");\n\t\treturn (event) -> log(prefix + event);\n\t}\n\n\t@Override\n\tpublic void skippingPhase(String name, String reason) {\n\t\tlog();\n\t\tlog(\" > Skipping \" + name + \" \" + reason);\n\t\tlog();\n\t}\n\n\t@Override\n\tpublic void executedLifecycle(BuildRequest request) {\n\t\tlog();\n\t\tlog(\"Successfully built image '\" + request.getName() + \"'\");\n\t\tlog();\n\t}\n\n\t@Override\n\tpublic void taggedImage(ImageReference tag) {\n\t\tlog(\"Successfully created image tag '\" + tag + \"'\");\n\t\tlog();\n\t}\n\n\t@Override\n\tpublic void failedCleaningWorkDir(Cache cache, @Nullable Exception exception) {\n\t\tStringBuilder message = new StringBuilder(\"Warning: Working location \" + cache + \" could not be cleaned\");\n\t\tif (exception != null) {\n\t\t\tmessage.append(\": \").append(exception.getMessage());\n\t\t}\n\t\tlog();\n\t\tlog(message.toString());\n\t\tlog();\n\t}\n\n\t@Override\n\tpublic void sensitiveTargetBindingDetected(Binding binding) {\n\t\tlog(\"Warning: Binding '%s' uses a container path which is used by buildpacks while building. Binding to it can cause problems!\"\n\t\t\t.formatted(binding));\n\t\tlog();\n\t}\n\n\tprivate String getDigest(Image image) {\n\t\tList<String> digests = image.getDigests();\n\t\treturn (digests.isEmpty() ? \"\" : digests.get(0));\n\t}\n\n\tprotected void log() {\n\t\tlog(\"\");\n\t}\n\n\tprotected abstract void log(String message);\n\n\tprotected abstract Consumer<TotalProgressEvent> getProgressConsumer(String message);\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ApiVersions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.Arrays;\nimport java.util.stream.IntStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.ApiVersion;\nimport org.springframework.util.StringUtils;\n\n/**\n * A set of API Version numbers comprised of major and minor values.\n *\n * @author Scott Frederick\n */\nfinal class ApiVersions {\n\n\t/**\n\t * The platform API versions supported by this release.\n\t */\n\tstatic final ApiVersions SUPPORTED_PLATFORMS = ApiVersions.of(0, IntStream.rangeClosed(3, 14));\n\n\tprivate final ApiVersion[] apiVersions;\n\n\tprivate ApiVersions(ApiVersion... versions) {\n\t\tthis.apiVersions = versions;\n\t}\n\n\t/**\n\t * Find the latest version among the specified versions that is supported by these API\n\t * versions.\n\t * @param others the versions to check against\n\t * @return the version\n\t */\n\tApiVersion findLatestSupported(String... others) {\n\t\tfor (int versionsIndex = this.apiVersions.length - 1; versionsIndex >= 0; versionsIndex--) {\n\t\t\tApiVersion apiVersion = this.apiVersions[versionsIndex];\n\t\t\tfor (int otherIndex = others.length - 1; otherIndex >= 0; otherIndex--) {\n\t\t\t\tApiVersion other = ApiVersion.parse(others[otherIndex]);\n\t\t\t\tif (apiVersion.supports(other)) {\n\t\t\t\t\treturn apiVersion;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Detected platform API versions '\" + StringUtils.arrayToCommaDelimitedString(others)\n\t\t\t\t\t\t+ \"' are not included in supported versions '\" + this + \"'\");\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tApiVersions other = (ApiVersions) obj;\n\t\treturn Arrays.equals(this.apiVersions, other.apiVersions);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Arrays.hashCode(this.apiVersions);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn StringUtils.arrayToCommaDelimitedString(this.apiVersions);\n\t}\n\n\t/**\n\t * Factory method to parse strings into an {@link ApiVersions} instance.\n\t * @param values the values to parse.\n\t * @return the corresponding {@link ApiVersions}\n\t * @throws IllegalArgumentException if any values could not be parsed\n\t */\n\tstatic ApiVersions parse(String... values) {\n\t\treturn new ApiVersions(Arrays.stream(values).map(ApiVersion::parse).toArray(ApiVersion[]::new));\n\t}\n\n\tstatic ApiVersions of(int major, IntStream minorsInclusive) {\n\t\treturn new ApiVersions(\n\t\t\t\tminorsInclusive.mapToObj((minor) -> ApiVersion.of(major, minor)).toArray(ApiVersion[]::new));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildLog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.PrintStream;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\n\n/**\n * Callback interface used to provide {@link Builder} output logging.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Andrey Shlykov\n * @author Rafael Ceccone\n * @since 2.3.0\n * @see #toSystemOut()\n */\npublic interface BuildLog {\n\n\t/**\n\t * Log that a build is starting.\n\t * @param request the build request\n\t */\n\tvoid start(BuildRequest request);\n\n\t/**\n\t * Log that an image is being pulled.\n\t * @param imageReference the image reference\n\t * @param platform the platform of the image\n\t * @param imageType the image type\n\t * @return a consumer for progress update events\n\t */\n\tConsumer<TotalProgressEvent> pullingImage(ImageReference imageReference, @Nullable ImagePlatform platform,\n\t\t\tImageType imageType);\n\n\t/**\n\t * Log that an image has been pulled.\n\t * @param image the image that was pulled\n\t * @param imageType the image type that was pulled\n\t */\n\tvoid pulledImage(Image image, ImageType imageType);\n\n\t/**\n\t * Log that an image is being pushed.\n\t * @param imageReference the image reference\n\t * @return a consumer for progress update events\n\t */\n\tConsumer<TotalProgressEvent> pushingImage(ImageReference imageReference);\n\n\t/**\n\t * Log that an image has been pushed.\n\t * @param imageReference the image reference\n\t */\n\tvoid pushedImage(ImageReference imageReference);\n\n\t/**\n\t * Log that the lifecycle is executing.\n\t * @param request the build request\n\t * @param version the lifecycle version\n\t * @param buildCacheVolume the name of the build cache volume in use\n\t */\n\tvoid executingLifecycle(BuildRequest request, LifecycleVersion version, VolumeName buildCacheVolume);\n\n\t/**\n\t * Log that the lifecycle is executing.\n\t * @param request the build request\n\t * @param version the lifecycle version\n\t * @param buildCache the build cache in use\n\t */\n\tvoid executingLifecycle(BuildRequest request, LifecycleVersion version, Cache buildCache);\n\n\t/**\n\t * Log that a specific phase is running.\n\t * @param request the build request\n\t * @param name the name of the phase\n\t * @return a consumer for log updates\n\t */\n\tConsumer<LogUpdateEvent> runningPhase(BuildRequest request, String name);\n\n\t/**\n\t * Log that a specific phase is being skipped.\n\t * @param name the name of the phase\n\t * @param reason the reason the phase is skipped\n\t */\n\tvoid skippingPhase(String name, String reason);\n\n\t/**\n\t * Log that the lifecycle has executed.\n\t * @param request the build request\n\t */\n\tvoid executedLifecycle(BuildRequest request);\n\n\t/**\n\t * Log that a tag has been created.\n\t * @param tag the tag reference\n\t */\n\tvoid taggedImage(ImageReference tag);\n\n\t/**\n\t * Log that a cache cleanup step was not completed successfully.\n\t * @param cache the cache\n\t * @param exception any exception that caused the failure\n\t * @since 3.2.6\n\t */\n\tvoid failedCleaningWorkDir(Cache cache, @Nullable Exception exception);\n\n\t/**\n\t * Log that a binding with a sensitive target has been detected.\n\t * @param binding the binding\n\t * @since 3.4.0\n\t */\n\tvoid sensitiveTargetBindingDetected(Binding binding);\n\n\t/**\n\t * Factory method that returns a {@link BuildLog} the outputs to {@link System#out}.\n\t * @return a build log instance that logs to system out\n\t */\n\tstatic BuildLog toSystemOut() {\n\t\treturn to(System.out);\n\t}\n\n\t/**\n\t * Factory method that returns a {@link BuildLog} the outputs to a given\n\t * {@link PrintStream}.\n\t * @param out the print stream used to output the log\n\t * @return a build log instance that logs to the given print stream\n\t */\n\tstatic BuildLog to(PrintStream out) {\n\t\treturn new PrintStreamBuildLog(out);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildOwner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * The {@link Owner} that should perform the build.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass BuildOwner implements Owner {\n\n\tprivate static final String USER_PROPERTY_NAME = \"CNB_USER_ID\";\n\n\tprivate static final String GROUP_PROPERTY_NAME = \"CNB_GROUP_ID\";\n\n\tprivate final long uid;\n\n\tprivate final long gid;\n\n\tBuildOwner(Map<String, @Nullable String> env) {\n\t\tthis.uid = getValue(env, USER_PROPERTY_NAME);\n\t\tthis.gid = getValue(env, GROUP_PROPERTY_NAME);\n\t}\n\n\tBuildOwner(long uid, long gid) {\n\t\tthis.uid = uid;\n\t\tthis.gid = gid;\n\t}\n\n\tprivate long getValue(Map<String, @Nullable String> env, String name) {\n\t\tString value = env.get(name);\n\t\tAssert.state(StringUtils.hasText(value),\n\t\t\t\t() -> \"Missing '\" + name + \"' value from the builder environment '\" + env + \"'\");\n\t\ttry {\n\t\t\treturn Long.parseLong(value);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Malformed '\" + name + \"' value '\" + value + \"' in the builder environment '\" + env + \"'\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic long getUid() {\n\t\treturn this.uid;\n\t}\n\n\t@Override\n\tpublic long getGid() {\n\t\treturn this.gid;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.uid + \"/\" + this.gid;\n\t}\n\n\t/**\n\t * Factory method to create the {@link BuildOwner} by inspecting the image env for\n\t * {@code CNB_USER_ID}/{@code CNB_GROUP_ID} variables.\n\t * @param env the env to parse\n\t * @return a {@link BuildOwner} instance extracted from the env\n\t * @throws IllegalStateException if the env does not contain the correct CNB variables\n\t */\n\tstatic BuildOwner fromEnv(Map<String, @Nullable String> env) {\n\t\tAssert.notNull(env, \"'env' must not be null\");\n\t\treturn new BuildOwner(env);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link BuildOwner} with specified user/group\n\t * identifier.\n\t * @param uid the user identifier\n\t * @param gid the group identifier\n\t * @return a new {@link BuildOwner} instance\n\t */\n\tstatic BuildOwner of(long uid, long gid) {\n\t\treturn new BuildOwner(uid, gid);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.File;\nimport java.time.Instant;\nimport java.time.format.DateTimeParseException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\n\n/**\n * A build request to be handled by the {@link Builder}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Andrey Shlykov\n * @author Jeroen Meijer\n * @author Rafael Ceccone\n * @author Julian Liebig\n * @since 2.3.0\n */\npublic class BuildRequest {\n\n\tstatic final String DEFAULT_BUILDER_IMAGE_NAME = \"paketobuildpacks/builder-noble-java-tiny\";\n\n\tstatic final String DEFAULT_BUILDER_IMAGE_REF = DEFAULT_BUILDER_IMAGE_NAME + \":latest\";\n\n\tstatic final List<ImageReference> KNOWN_TRUSTED_BUILDERS = List.of(\n\t\t\tImageReference.of(\"paketobuildpacks/builder-noble-java-tiny\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-java-tiny\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-tiny\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-base\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-full\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-buildpackless-tiny\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-buildpackless-base\"),\n\t\t\tImageReference.of(\"paketobuildpacks/builder-jammy-buildpackless-full\"),\n\t\t\tImageReference.of(\"gcr.io/buildpacks/builder\"), ImageReference.of(\"heroku/builder\"));\n\n\tprivate static final ImageReference DEFAULT_BUILDER = ImageReference.of(DEFAULT_BUILDER_IMAGE_REF);\n\n\tprivate final ImageReference name;\n\n\tprivate final Function<Owner, TarArchive> applicationContent;\n\n\tprivate final ImageReference builder;\n\n\tprivate final @Nullable Boolean trustBuilder;\n\n\tprivate final @Nullable ImageReference runImage;\n\n\tprivate final Creator creator;\n\n\tprivate final Map<String, String> env;\n\n\tprivate final boolean cleanCache;\n\n\tprivate final boolean verboseLogging;\n\n\tprivate final PullPolicy pullPolicy;\n\n\tprivate final boolean publish;\n\n\tprivate final List<BuildpackReference> buildpacks;\n\n\tprivate final List<Binding> bindings;\n\n\tprivate final @Nullable String network;\n\n\tprivate final List<ImageReference> tags;\n\n\tprivate final @Nullable Cache buildWorkspace;\n\n\tprivate final @Nullable Cache buildCache;\n\n\tprivate final @Nullable Cache launchCache;\n\n\tprivate final @Nullable Instant createdDate;\n\n\tprivate final @Nullable String applicationDirectory;\n\n\tprivate final @Nullable List<String> securityOptions;\n\n\tprivate final @Nullable ImagePlatform platform;\n\n\tBuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(applicationContent, \"'applicationContent' must not be null\");\n\t\tthis.name = name.inTaggedForm();\n\t\tthis.applicationContent = applicationContent;\n\t\tthis.builder = DEFAULT_BUILDER;\n\t\tthis.trustBuilder = null;\n\t\tthis.runImage = null;\n\t\tthis.env = Collections.emptyMap();\n\t\tthis.cleanCache = false;\n\t\tthis.verboseLogging = false;\n\t\tthis.pullPolicy = PullPolicy.ALWAYS;\n\t\tthis.publish = false;\n\t\tthis.creator = Creator.withVersion(\"\");\n\t\tthis.buildpacks = Collections.emptyList();\n\t\tthis.bindings = Collections.emptyList();\n\t\tthis.network = null;\n\t\tthis.tags = Collections.emptyList();\n\t\tthis.buildWorkspace = null;\n\t\tthis.buildCache = null;\n\t\tthis.launchCache = null;\n\t\tthis.createdDate = null;\n\t\tthis.applicationDirectory = null;\n\t\tthis.securityOptions = null;\n\t\tthis.platform = null;\n\t}\n\n\tBuildRequest(ImageReference name, Function<Owner, TarArchive> applicationContent, ImageReference builder,\n\t\t\t@Nullable Boolean trustBuilder, @Nullable ImageReference runImage, Creator creator, Map<String, String> env,\n\t\t\tboolean cleanCache, boolean verboseLogging, PullPolicy pullPolicy, boolean publish,\n\t\t\tList<BuildpackReference> buildpacks, List<Binding> bindings, @Nullable String network,\n\t\t\tList<ImageReference> tags, @Nullable Cache buildWorkspace, @Nullable Cache buildCache,\n\t\t\t@Nullable Cache launchCache, @Nullable Instant createdDate, @Nullable String applicationDirectory,\n\t\t\t@Nullable List<String> securityOptions, @Nullable ImagePlatform platform) {\n\t\tthis.name = name;\n\t\tthis.applicationContent = applicationContent;\n\t\tthis.builder = builder;\n\t\tthis.trustBuilder = trustBuilder;\n\t\tthis.runImage = runImage;\n\t\tthis.creator = creator;\n\t\tthis.env = env;\n\t\tthis.cleanCache = cleanCache;\n\t\tthis.verboseLogging = verboseLogging;\n\t\tthis.pullPolicy = pullPolicy;\n\t\tthis.publish = publish;\n\t\tthis.buildpacks = buildpacks;\n\t\tthis.bindings = bindings;\n\t\tthis.network = network;\n\t\tthis.tags = tags;\n\t\tthis.buildWorkspace = buildWorkspace;\n\t\tthis.buildCache = buildCache;\n\t\tthis.launchCache = launchCache;\n\t\tthis.createdDate = createdDate;\n\t\tthis.applicationDirectory = applicationDirectory;\n\t\tthis.securityOptions = securityOptions;\n\t\tthis.platform = platform;\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated builder.\n\t * @param builder the new builder to use\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withBuilder(ImageReference builder) {\n\t\tAssert.notNull(builder, \"'builder' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, builder.inTaggedOrDigestForm(), this.trustBuilder,\n\t\t\t\tthis.runImage, this.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy,\n\t\t\t\tthis.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace,\n\t\t\t\tthis.buildCache, this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions,\n\t\t\t\tthis.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated trust builder setting.\n\t * @param trustBuilder {@code true} if the builder should be treated as trusted,\n\t * {@code false} otherwise\n\t * @return an updated build request\n\t * @since 3.4.0\n\t */\n\tpublic BuildRequest withTrustBuilder(boolean trustBuilder) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated run image.\n\t * @param runImageName the run image to use\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withRunImage(ImageReference runImageName) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder,\n\t\t\t\trunImageName.inTaggedOrDigestForm(), this.creator, this.env, this.cleanCache, this.verboseLogging,\n\t\t\t\tthis.pullPolicy, this.publish, this.buildpacks, this.bindings, this.network, this.tags,\n\t\t\t\tthis.buildWorkspace, this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory,\n\t\t\t\tthis.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated creator.\n\t * @param creator the new {@code Creator} to use\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withCreator(Creator creator) {\n\t\tAssert.notNull(creator, \"'creator' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tcreator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks,\n\t\t\t\tthis.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,\n\t\t\t\tthis.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an additional env variable.\n\t * @param name the variable name\n\t * @param value the variable value\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withEnv(String name, String value) {\n\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tMap<String, String> env = new LinkedHashMap<>(this.env);\n\t\tenv.put(name, value);\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, Collections.unmodifiableMap(env), this.cleanCache, this.verboseLogging, this.pullPolicy,\n\t\t\t\tthis.publish, this.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace,\n\t\t\t\tthis.buildCache, this.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions,\n\t\t\t\tthis.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with additional env variables.\n\t * @param env the additional variables\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withEnv(Map<String, String> env) {\n\t\tAssert.notNull(env, \"'env' must not be null\");\n\t\tMap<String, String> updatedEnv = new LinkedHashMap<>(this.env);\n\t\tupdatedEnv.putAll(env);\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, Collections.unmodifiableMap(updatedEnv), this.cleanCache, this.verboseLogging,\n\t\t\t\tthis.pullPolicy, this.publish, this.buildpacks, this.bindings, this.network, this.tags,\n\t\t\t\tthis.buildWorkspace, this.buildCache, this.launchCache, this.createdDate, this.applicationDirectory,\n\t\t\t\tthis.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated clean cache setting.\n\t * @param cleanCache if the cache should be cleaned\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withCleanCache(boolean cleanCache) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, cleanCache, this.verboseLogging, this.pullPolicy, this.publish, this.buildpacks,\n\t\t\t\tthis.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,\n\t\t\t\tthis.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated verbose logging setting.\n\t * @param verboseLogging if verbose logging should be used\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withVerboseLogging(boolean verboseLogging) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, verboseLogging, this.pullPolicy, this.publish, this.buildpacks,\n\t\t\t\tthis.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,\n\t\t\t\tthis.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with the updated image pull policy.\n\t * @param pullPolicy image pull policy {@link PullPolicy}\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withPullPolicy(PullPolicy pullPolicy) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, pullPolicy, this.publish, this.buildpacks,\n\t\t\t\tthis.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,\n\t\t\t\tthis.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated publish setting.\n\t * @param publish if the built image should be pushed to a registry\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withPublish(boolean publish) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, publish, this.buildpacks,\n\t\t\t\tthis.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,\n\t\t\t\tthis.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated buildpacks setting.\n\t * @param buildpacks a collection of buildpacks to use when building the image\n\t * @return an updated build request\n\t * @since 2.5.0\n\t */\n\tpublic BuildRequest withBuildpacks(BuildpackReference... buildpacks) {\n\t\tAssert.notEmpty(buildpacks, \"'buildpacks' must not be empty\");\n\t\treturn withBuildpacks(Arrays.asList(buildpacks));\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated buildpacks setting.\n\t * @param buildpacks a collection of buildpacks to use when building the image\n\t * @return an updated build request\n\t * @since 2.5.0\n\t */\n\tpublic BuildRequest withBuildpacks(List<BuildpackReference> buildpacks) {\n\t\tAssert.notNull(buildpacks, \"'buildpacks' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish, buildpacks,\n\t\t\t\tthis.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache, this.launchCache,\n\t\t\t\tthis.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with updated bindings.\n\t * @param bindings a collection of bindings to mount to the build container\n\t * @return an updated build request\n\t * @since 2.5.0\n\t */\n\tpublic BuildRequest withBindings(Binding... bindings) {\n\t\tAssert.notEmpty(bindings, \"'bindings' must not be empty\");\n\t\treturn withBindings(Arrays.asList(bindings));\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with updated bindings.\n\t * @param bindings a collection of bindings to mount to the build container\n\t * @return an updated build request\n\t * @since 2.5.0\n\t */\n\tpublic BuildRequest withBindings(List<Binding> bindings) {\n\t\tAssert.notNull(bindings, \"'bindings' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated network setting.\n\t * @param network the network the build container will connect to\n\t * @return an updated build request\n\t * @since 2.6.0\n\t */\n\tpublic BuildRequest withNetwork(@Nullable String network) {\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with updated tags.\n\t * @param tags a collection of tags to be created for the built image\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withTags(ImageReference... tags) {\n\t\tAssert.notEmpty(tags, \"'tags' must not be empty\");\n\t\treturn withTags(Arrays.asList(tags));\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with updated tags.\n\t * @param tags a collection of tags to be created for the built image\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withTags(List<ImageReference> tags) {\n\t\tAssert.notNull(tags, \"'tags' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated build workspace.\n\t * @param buildWorkspace the build workspace\n\t * @return an updated build request\n\t * @since 3.2.0\n\t */\n\tpublic BuildRequest withBuildWorkspace(Cache buildWorkspace) {\n\t\tAssert.notNull(buildWorkspace, \"'buildWorkspace' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated build cache.\n\t * @param buildCache the build cache\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withBuildCache(Cache buildCache) {\n\t\tAssert.notNull(buildCache, \"'buildCache' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated launch cache.\n\t * @param launchCache the cache\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withLaunchCache(Cache launchCache) {\n\t\tAssert.notNull(launchCache, \"'launchCache' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tlaunchCache, this.createdDate, this.applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated created date.\n\t * @param createdDate the created date\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withCreatedDate(String createdDate) {\n\t\tAssert.notNull(createdDate, \"'createdDate' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, parseCreatedDate(createdDate), this.applicationDirectory, this.securityOptions,\n\t\t\t\tthis.platform);\n\t}\n\n\tprivate Instant parseCreatedDate(String createdDate) {\n\t\tif (\"now\".equalsIgnoreCase(createdDate)) {\n\t\t\treturn Instant.now();\n\t\t}\n\t\ttry {\n\t\t\treturn Instant.parse(createdDate);\n\t\t}\n\t\tcatch (DateTimeParseException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Error parsing '\" + createdDate + \"' as an image created date\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated application directory.\n\t * @param applicationDirectory the application directory\n\t * @return an updated build request\n\t */\n\tpublic BuildRequest withApplicationDirectory(String applicationDirectory) {\n\t\tAssert.notNull(applicationDirectory, \"'applicationDirectory' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, applicationDirectory, this.securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated security options.\n\t * @param securityOptions the security options\n\t * @return an updated build request\n\t * @since 3.2.0\n\t */\n\tpublic BuildRequest withSecurityOptions(List<String> securityOptions) {\n\t\tAssert.notNull(securityOptions, \"'securityOptions' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, securityOptions, this.platform);\n\t}\n\n\t/**\n\t * Return a new {@link BuildRequest} with an updated image platform.\n\t * @param platform the image platform\n\t * @return an updated build request\n\t * @since 3.4.0\n\t */\n\tpublic BuildRequest withImagePlatform(String platform) {\n\t\tAssert.notNull(platform, \"'platform' must not be null\");\n\t\treturn new BuildRequest(this.name, this.applicationContent, this.builder, this.trustBuilder, this.runImage,\n\t\t\t\tthis.creator, this.env, this.cleanCache, this.verboseLogging, this.pullPolicy, this.publish,\n\t\t\t\tthis.buildpacks, this.bindings, this.network, this.tags, this.buildWorkspace, this.buildCache,\n\t\t\t\tthis.launchCache, this.createdDate, this.applicationDirectory, this.securityOptions,\n\t\t\t\tImagePlatform.of(platform));\n\t}\n\n\t/**\n\t * Return the name of the image that should be created.\n\t * @return the name of the image\n\t */\n\tpublic ImageReference getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return a {@link TarArchive} containing the application content that the buildpack\n\t * should package. This is typically the contents of the Jar.\n\t * @param owner the owner of the tar entries\n\t * @return the application content\n\t * @see TarArchive#fromZip(File, Owner)\n\t */\n\tpublic TarArchive getApplicationContent(Owner owner) {\n\t\treturn this.applicationContent.apply(owner);\n\t}\n\n\t/**\n\t * Return the builder that should be used.\n\t * @return the builder to use\n\t */\n\tpublic ImageReference getBuilder() {\n\t\treturn this.builder;\n\t}\n\n\t/**\n\t * Return whether the builder should be treated as trusted.\n\t * @return the trust builder flag\n\t * @since 3.4.0\n\t */\n\tpublic boolean isTrustBuilder() {\n\t\treturn (this.trustBuilder != null) ? this.trustBuilder : isBuilderKnownAndTrusted();\n\t}\n\n\tprivate boolean isBuilderKnownAndTrusted() {\n\t\treturn KNOWN_TRUSTED_BUILDERS.stream().anyMatch((builder) -> builder.getName().equals(this.builder.getName()));\n\t}\n\n\t/**\n\t * Return the run image that should be used, if provided.\n\t * @return the run image\n\t */\n\tpublic @Nullable ImageReference getRunImage() {\n\t\treturn this.runImage;\n\t}\n\n\t/**\n\t * Return the {@link Creator} the builder should use.\n\t * @return the {@code Creator}\n\t */\n\tpublic Creator getCreator() {\n\t\treturn this.creator;\n\t}\n\n\t/**\n\t * Return any env variable that should be passed to the builder.\n\t * @return the builder env\n\t */\n\tpublic Map<String, String> getEnv() {\n\t\treturn this.env;\n\t}\n\n\t/**\n\t * Return if caches should be cleaned before packaging.\n\t * @return if caches should be cleaned\n\t */\n\tpublic boolean isCleanCache() {\n\t\treturn this.cleanCache;\n\t}\n\n\t/**\n\t * Return if verbose logging output should be used.\n\t * @return if verbose logging should be used\n\t */\n\tpublic boolean isVerboseLogging() {\n\t\treturn this.verboseLogging;\n\t}\n\n\t/**\n\t * Return if the built image should be pushed to a registry.\n\t * @return if the built image should be pushed to a registry\n\t */\n\tpublic boolean isPublish() {\n\t\treturn this.publish;\n\t}\n\n\t/**\n\t * Return the image {@link PullPolicy} that the builder should use.\n\t * @return image pull policy\n\t */\n\tpublic PullPolicy getPullPolicy() {\n\t\treturn this.pullPolicy;\n\t}\n\n\t/**\n\t * Return the collection of buildpacks to use when building the image, if provided.\n\t * @return the buildpacks\n\t */\n\tpublic List<BuildpackReference> getBuildpacks() {\n\t\treturn this.buildpacks;\n\t}\n\n\t/**\n\t * Return the collection of bindings to mount to the build container.\n\t * @return the bindings\n\t * @since 2.5.0\n\t */\n\tpublic List<Binding> getBindings() {\n\t\treturn this.bindings;\n\t}\n\n\t/**\n\t * Return the network the build container will connect to.\n\t * @return the network\n\t * @since 2.6.0\n\t */\n\tpublic @Nullable String getNetwork() {\n\t\treturn this.network;\n\t}\n\n\t/**\n\t * Return the collection of tags that should be created.\n\t * @return the tags\n\t */\n\tpublic List<ImageReference> getTags() {\n\t\treturn this.tags;\n\t}\n\n\t/**\n\t * Return the build workspace that should be used by the lifecycle.\n\t * @return the build workspace or {@code null}\n\t * @since 3.2.0\n\t */\n\tpublic @Nullable Cache getBuildWorkspace() {\n\t\treturn this.buildWorkspace;\n\t}\n\n\t/**\n\t * Return the custom build cache that should be used by the lifecycle.\n\t * @return the build cache\n\t */\n\tpublic @Nullable Cache getBuildCache() {\n\t\treturn this.buildCache;\n\t}\n\n\t/**\n\t * Return the custom launch cache that should be used by the lifecycle.\n\t * @return the launch cache\n\t */\n\tpublic @Nullable Cache getLaunchCache() {\n\t\treturn this.launchCache;\n\t}\n\n\t/**\n\t * Return the custom created date that should be used by the lifecycle.\n\t * @return the created date\n\t */\n\tpublic @Nullable Instant getCreatedDate() {\n\t\treturn this.createdDate;\n\t}\n\n\t/**\n\t * Return the application directory that should be used by the lifecycle.\n\t * @return the application directory\n\t */\n\tpublic @Nullable String getApplicationDirectory() {\n\t\treturn this.applicationDirectory;\n\t}\n\n\t/**\n\t * Return the security options that should be used by the lifecycle.\n\t * @return the security options or {@code null}\n\t * @since 3.2.0\n\t */\n\tpublic @Nullable List<String> getSecurityOptions() {\n\t\treturn this.securityOptions;\n\t}\n\n\t/**\n\t * Return the platform that should be used when pulling images.\n\t * @return the platform or {@code null}\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable ImagePlatform getImagePlatform() {\n\t\treturn this.platform;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link BuildRequest} from a JAR file.\n\t * @param jarFile the source jar file\n\t * @return a new build request instance\n\t */\n\tpublic static BuildRequest forJarFile(File jarFile) {\n\t\tassertJarFile(jarFile);\n\t\treturn forJarFile(ImageReference.forJarFile(jarFile).inTaggedForm(), jarFile);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link BuildRequest} from a JAR file.\n\t * @param name the name of the image that should be created\n\t * @param jarFile the source jar file\n\t * @return a new build request instance\n\t */\n\tpublic static BuildRequest forJarFile(ImageReference name, File jarFile) {\n\t\tassertJarFile(jarFile);\n\t\treturn new BuildRequest(name, (owner) -> TarArchive.fromZip(jarFile, owner));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link BuildRequest} with specific content.\n\t * @param name the name of the image that should be created\n\t * @param applicationContent function to provide the application content\n\t * @return a new build request instance\n\t */\n\tpublic static BuildRequest of(ImageReference name, Function<Owner, TarArchive> applicationContent) {\n\t\treturn new BuildRequest(name, applicationContent);\n\t}\n\n\tprivate static void assertJarFile(File jarFile) {\n\t\tAssert.notNull(jarFile, \"'jarFile' must not be null\");\n\t\tAssert.isTrue(jarFile.exists(), \"'jarFile' must exist\");\n\t\tAssert.isTrue(jarFile.isFile(), \"'jarFile' must be a file\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Builder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerLog;\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressPushListener;\nimport org.springframework.boot.buildpack.platform.docker.UpdateListener;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.IOBiConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Central API for running buildpack operations.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Andrey Shlykov\n * @author Rafael Ceccone\n * @since 2.3.0\n */\npublic class Builder {\n\n\tprivate final BuildLog log;\n\n\tprivate final DockerApi docker;\n\n\tprivate final BuilderDockerConfiguration dockerConfiguration;\n\n\t/**\n\t * Create a new builder instance.\n\t */\n\tpublic Builder() {\n\t\tthis(BuildLog.toSystemOut());\n\t}\n\n\t/**\n\t * Create a new builder instance.\n\t * @param dockerConfiguration the docker configuration\n\t * @since 3.5.0\n\t */\n\tpublic Builder(BuilderDockerConfiguration dockerConfiguration) {\n\t\tthis(BuildLog.toSystemOut(), dockerConfiguration);\n\t}\n\n\t/**\n\t * Create a new builder instance.\n\t * @param log a logger used to record output\n\t */\n\tpublic Builder(BuildLog log) {\n\t\tthis(log, new DockerApi(null, BuildLogAdapter.get(log)), null);\n\t}\n\n\t/**\n\t * Create a new builder instance.\n\t * @param log a logger used to record output\n\t * @param dockerConfiguration the docker configuration\n\t * @since 3.5.0\n\t */\n\tpublic Builder(BuildLog log, @Nullable BuilderDockerConfiguration dockerConfiguration) {\n\t\tthis(log, new DockerApi((dockerConfiguration != null) ? dockerConfiguration.connection() : null,\n\t\t\t\tBuildLogAdapter.get(log)), dockerConfiguration);\n\t}\n\n\tBuilder(BuildLog log, DockerApi docker, @Nullable BuilderDockerConfiguration dockerConfiguration) {\n\t\tAssert.notNull(log, \"'log' must not be null\");\n\t\tthis.log = log;\n\t\tthis.docker = docker;\n\t\tthis.dockerConfiguration = (dockerConfiguration != null) ? dockerConfiguration\n\t\t\t\t: new BuilderDockerConfiguration();\n\t}\n\n\tpublic void build(BuildRequest request) throws DockerEngineException, IOException {\n\t\tAssert.notNull(request, \"'request' must not be null\");\n\t\tthis.log.start(request);\n\t\tvalidateBindings(request.getBindings());\n\t\tPullPolicy pullPolicy = request.getPullPolicy();\n\t\tImagePlatform platform = request.getImagePlatform();\n\t\tboolean specifiedPlatform = request.getImagePlatform() != null;\n\t\tDockerRegistryAuthentication registryAuthentication = this.dockerConfiguration.builderRegistryAuthentication();\n\t\tImageFetcher imageFetcher = new ImageFetcher(registryAuthentication, pullPolicy);\n\t\tImage builderImage = imageFetcher.fetchImage(ImageType.BUILDER, request.getBuilder(), platform);\n\t\tBuilderMetadata builderMetadata = BuilderMetadata.fromImage(builderImage);\n\t\trequest = withRunImageIfNeeded(request, builderMetadata);\n\t\tAssert.state(request.getRunImage() != null, \"'request.getRunImage()' must not be null\");\n\t\tplatform = (platform != null) ? platform : ImagePlatform.from(builderImage);\n\t\tImage runImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage(), platform);\n\t\tif (specifiedPlatform && runImage.getPrimaryDigest() != null) {\n\t\t\trequest = request.withRunImage(request.getRunImage().withDigest(runImage.getPrimaryDigest()));\n\t\t\trunImage = imageFetcher.fetchImage(ImageType.RUNNER, request.getRunImage(), platform);\n\t\t}\n\t\tassertStackIdsMatch(runImage, builderImage);\n\t\tBuildOwner buildOwner = BuildOwner.fromEnv(builderImage.getConfig().getEnv());\n\t\tBuildpackLayersMetadata buildpackLayersMetadata = BuildpackLayersMetadata.fromImage(builderImage);\n\t\tBuildpacks buildpacks = getBuildpacks(request, imageFetcher, platform, builderMetadata,\n\t\t\t\tbuildpackLayersMetadata);\n\t\tEphemeralBuilder ephemeralBuilder = new EphemeralBuilder(buildOwner, builderImage, request.getName(),\n\t\t\t\tbuilderMetadata, request.getCreator(), request.getEnv(), buildpacks);\n\t\texecuteLifecycle(request, ephemeralBuilder);\n\t\ttagImage(request.getName(), request.getTags());\n\t\tif (request.isPublish()) {\n\t\t\tpushImages(request.getName(), request.getTags());\n\t\t}\n\t}\n\n\tprivate void validateBindings(List<Binding> bindings) {\n\t\tfor (Binding binding : bindings) {\n\t\t\tif (binding.usesSensitiveContainerPath()) {\n\t\t\t\tthis.log.sensitiveTargetBindingDetected(binding);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate BuildRequest withRunImageIfNeeded(BuildRequest request, BuilderMetadata metadata) {\n\t\tif (request.getRunImage() != null) {\n\t\t\treturn request;\n\t\t}\n\t\treturn request.withRunImage(getRunImageReference(metadata));\n\t}\n\n\tprivate ImageReference getRunImageReference(BuilderMetadata metadata) {\n\t\tif (metadata.getRunImages() != null && !metadata.getRunImages().isEmpty()) {\n\t\t\tString runImageName = metadata.getRunImages().get(0).getImage();\n\t\t\treturn ImageReference.of(runImageName).inTaggedOrDigestForm();\n\t\t}\n\t\tString runImageName = metadata.getStack().getRunImage().getImage();\n\t\tAssert.state(StringUtils.hasText(runImageName), \"Run image must be specified in the builder image metadata\");\n\t\treturn ImageReference.of(runImageName).inTaggedOrDigestForm();\n\t}\n\n\tprivate void assertStackIdsMatch(Image runImage, Image builderImage) {\n\t\tStackId runImageStackId = StackId.fromImage(runImage);\n\t\tStackId builderImageStackId = StackId.fromImage(builderImage);\n\t\tif (runImageStackId.hasId() && builderImageStackId.hasId()) {\n\t\t\tAssert.state(runImageStackId.equals(builderImageStackId), () -> \"Run image stack '\" + runImageStackId\n\t\t\t\t\t+ \"' does not match builder stack '\" + builderImageStackId + \"'\");\n\t\t}\n\t}\n\n\tprivate Buildpacks getBuildpacks(BuildRequest request, ImageFetcher imageFetcher, ImagePlatform platform,\n\t\t\tBuilderMetadata builderMetadata, BuildpackLayersMetadata buildpackLayersMetadata) {\n\t\tBuildpackResolverContext resolverContext = new BuilderResolverContext(imageFetcher, platform, builderMetadata,\n\t\t\t\tbuildpackLayersMetadata);\n\t\treturn BuildpackResolvers.resolveAll(resolverContext, request.getBuildpacks());\n\t}\n\n\tprivate void executeLifecycle(BuildRequest request, EphemeralBuilder builder) throws IOException {\n\t\ttry (Lifecycle lifecycle = new Lifecycle(this.log, this.docker, getDockerHost(), request, builder)) {\n\t\t\texecuteLifecycle(builder, lifecycle);\n\t\t}\n\t}\n\n\tprivate void executeLifecycle(EphemeralBuilder builder, Lifecycle lifecycle) throws IOException {\n\t\tImageArchive archive = builder.getArchive(lifecycle.getApplicationDirectory());\n\t\tthis.docker.image().load(archive, UpdateListener.none());\n\t\ttry {\n\t\t\tlifecycle.execute();\n\t\t}\n\t\tfinally {\n\t\t\tthis.docker.image().remove(builder.getName(), true);\n\t\t}\n\t}\n\n\tprivate @Nullable ResolvedDockerHost getDockerHost() {\n\t\tboolean bindToBuilder = this.dockerConfiguration.bindHostToBuilder();\n\t\treturn (bindToBuilder) ? ResolvedDockerHost.from(this.dockerConfiguration.connection()) : null;\n\t}\n\n\tprivate void tagImage(ImageReference sourceReference, List<ImageReference> tags) throws IOException {\n\t\tfor (ImageReference tag : tags) {\n\t\t\tthis.docker.image().tag(sourceReference, tag);\n\t\t\tthis.log.taggedImage(tag);\n\t\t}\n\t}\n\n\tprivate void pushImages(ImageReference name, List<ImageReference> tags) throws IOException {\n\t\tpushImage(name);\n\t\tfor (ImageReference tag : tags) {\n\t\t\tpushImage(tag);\n\t\t}\n\t}\n\n\tprivate void pushImage(ImageReference reference) throws IOException {\n\t\tConsumer<TotalProgressEvent> progressConsumer = this.log.pushingImage(reference);\n\t\tTotalProgressPushListener listener = new TotalProgressPushListener(progressConsumer);\n\t\tString authHeader = authHeader(this.dockerConfiguration.publishRegistryAuthentication(), reference);\n\t\tthis.docker.image().push(reference, listener, authHeader);\n\t\tthis.log.pushedImage(reference);\n\t}\n\n\tprivate static @Nullable String authHeader(@Nullable DockerRegistryAuthentication authentication,\n\t\t\tImageReference reference) {\n\t\treturn (authentication != null) ? authentication.getAuthHeader(reference) : null;\n\t}\n\n\t/**\n\t * Internal utility class used to fetch images.\n\t */\n\tprivate class ImageFetcher {\n\n\t\tprivate final @Nullable DockerRegistryAuthentication registryAuthentication;\n\n\t\tprivate final PullPolicy pullPolicy;\n\n\t\tImageFetcher(@Nullable DockerRegistryAuthentication registryAuthentication, PullPolicy pullPolicy) {\n\t\t\tthis.registryAuthentication = registryAuthentication;\n\t\t\tthis.pullPolicy = pullPolicy;\n\t\t}\n\n\t\tImage fetchImage(ImageType type, ImageReference reference, @Nullable ImagePlatform platform)\n\t\t\t\tthrows IOException {\n\t\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tif (this.pullPolicy == PullPolicy.ALWAYS) {\n\t\t\t\treturn pullImageAndCheckForPlatformMismatch(type, reference, platform);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tImage image = Builder.this.docker.image().inspect(reference, platform);\n\t\t\t\treturn checkPlatformMismatch(image, reference, platform);\n\t\t\t}\n\t\t\tcatch (DockerEngineException ex) {\n\t\t\t\tif (this.pullPolicy == PullPolicy.IF_NOT_PRESENT && ex.getStatusCode() == 404) {\n\t\t\t\t\treturn pullImageAndCheckForPlatformMismatch(type, reference, platform);\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate Image pullImageAndCheckForPlatformMismatch(ImageType type, ImageReference reference,\n\t\t\t\t@Nullable ImagePlatform platform) throws IOException {\n\t\t\ttry {\n\t\t\t\tImage image = pullImage(reference, type, platform);\n\t\t\t\treturn checkPlatformMismatch(image, reference, platform);\n\t\t\t}\n\t\t\tcatch (DockerEngineException ex) {\n\t\t\t\t// Try to throw our own exception for consistent log output. Matching\n\t\t\t\t// on the message is a little brittle, but it doesn't matter too much\n\t\t\t\t// if it fails as the original exception is still enough to stop the build\n\t\t\t\tif (platform != null && ex.getMessage() != null\n\t\t\t\t\t\t&& ex.getMessage().contains(\"does not provide the specified platform\")) {\n\t\t\t\t\tthrowAsPlatformMismatchException(type, reference, platform, ex);\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate void throwAsPlatformMismatchException(ImageType type, ImageReference reference, ImagePlatform platform,\n\t\t\t\t@Nullable Throwable cause) throws IOException {\n\t\t\ttry {\n\t\t\t\tImage image = pullImage(reference, type, null);\n\t\t\t\tthrow new PlatformMismatchException(reference, platform, ImagePlatform.from(image), cause);\n\t\t\t}\n\t\t\tcatch (DockerEngineException ex) {\n\t\t\t}\n\t\t}\n\n\t\tprivate Image pullImage(ImageReference reference, ImageType imageType, @Nullable ImagePlatform platform)\n\t\t\t\tthrows IOException {\n\t\t\tTotalProgressPullListener listener = new TotalProgressPullListener(\n\t\t\t\t\tBuilder.this.log.pullingImage(reference, platform, imageType));\n\t\t\tString authHeader = authHeader(this.registryAuthentication, reference);\n\t\t\tImage image = Builder.this.docker.image().pull(reference, platform, listener, authHeader);\n\t\t\tBuilder.this.log.pulledImage(image, imageType);\n\t\t\treturn image;\n\t\t}\n\n\t\tprivate Image checkPlatformMismatch(Image image, ImageReference reference,\n\t\t\t\t@Nullable ImagePlatform requestedPlatform) {\n\t\t\tif (requestedPlatform != null) {\n\t\t\t\tImagePlatform actualPlatform = ImagePlatform.from(image);\n\t\t\t\tif (!actualPlatform.equals(requestedPlatform)) {\n\t\t\t\t\tthrow new PlatformMismatchException(reference, requestedPlatform, actualPlatform, null);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn image;\n\t\t}\n\n\t}\n\n\tprivate static final class PlatformMismatchException extends RuntimeException {\n\n\t\tprivate PlatformMismatchException(ImageReference imageReference, ImagePlatform requestedPlatform,\n\t\t\t\tImagePlatform actualPlatform, @Nullable Throwable cause) {\n\t\t\tsuper(\"Image platform mismatch detected. The configured platform '%s' is not supported by the image '%s'. Requested platform '%s' but got '%s'\"\n\t\t\t\t.formatted(requestedPlatform, imageReference, requestedPlatform, actualPlatform), cause);\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@link DockerLog} implementation that adapts to an {@link AbstractBuildLog}.\n\t */\n\tstatic final class BuildLogAdapter implements DockerLog {\n\n\t\tprivate final AbstractBuildLog log;\n\n\t\tprivate BuildLogAdapter(AbstractBuildLog log) {\n\t\t\tthis.log = log;\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message) {\n\t\t\tthis.log.log(message);\n\t\t}\n\n\t\t/**\n\t\t * Creates {@link DockerLog} instance based on the provided {@link BuildLog}.\n\t\t * <p>\n\t\t * If the provided {@link BuildLog} instance is an {@link AbstractBuildLog}, the\n\t\t * method returns a {@link BuildLogAdapter}, otherwise it returns a default\n\t\t * {@link DockerLog#toSystemOut()}.\n\t\t * @param log the {@link BuildLog} instance to delegate\n\t\t * @return a {@link DockerLog} instance for logging\n\t\t */\n\t\tstatic DockerLog get(BuildLog log) {\n\t\t\tif (log instanceof AbstractBuildLog abstractBuildLog) {\n\t\t\t\treturn new BuildLogAdapter(abstractBuildLog);\n\t\t\t}\n\t\t\treturn DockerLog.toSystemOut();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link BuildpackResolverContext} implementation for the {@link Builder}.\n\t */\n\tprivate class BuilderResolverContext implements BuildpackResolverContext {\n\n\t\tprivate final ImageFetcher imageFetcher;\n\n\t\tprivate final ImagePlatform platform;\n\n\t\tprivate final BuilderMetadata builderMetadata;\n\n\t\tprivate final BuildpackLayersMetadata buildpackLayersMetadata;\n\n\t\tBuilderResolverContext(ImageFetcher imageFetcher, ImagePlatform platform, BuilderMetadata builderMetadata,\n\t\t\t\tBuildpackLayersMetadata buildpackLayersMetadata) {\n\t\t\tthis.imageFetcher = imageFetcher;\n\t\t\tthis.platform = platform;\n\t\t\tthis.builderMetadata = builderMetadata;\n\t\t\tthis.buildpackLayersMetadata = buildpackLayersMetadata;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<BuildpackMetadata> getBuildpackMetadata() {\n\t\t\treturn this.builderMetadata.getBuildpacks();\n\t\t}\n\n\t\t@Override\n\t\tpublic BuildpackLayersMetadata getBuildpackLayersMetadata() {\n\t\t\treturn this.buildpackLayersMetadata;\n\t\t}\n\n\t\t@Override\n\t\tpublic Image fetchImage(ImageReference reference, ImageType imageType) throws IOException {\n\t\t\treturn this.imageFetcher.fetchImage(imageType, reference, this.platform);\n\t\t}\n\n\t\t@Override\n\t\tpublic void exportImageLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)\n\t\t\t\tthrows IOException {\n\t\t\tBuilder.this.docker.image().exportLayers(reference, this.platform, exports);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuilderBuildpack.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link Buildpack} that references a buildpack contained in the builder.\n *\n * The buildpack reference must contain a buildpack ID (for example,\n * {@code \"example/buildpack\"}) or a buildpack ID and version (for example,\n * {@code \"example/buildpack@1.0.0\"}). The reference can optionally contain a prefix\n * {@code urn:cnb:builder:} to unambiguously identify it as a builder buildpack reference.\n * If a version is not provided, the reference will match any version of a buildpack with\n * the same ID as the reference.\n *\n * @author Scott Frederick\n */\nclass BuilderBuildpack implements Buildpack {\n\n\tprivate static final String PREFIX = \"urn:cnb:builder:\";\n\n\tprivate final BuildpackCoordinates coordinates;\n\n\tBuilderBuildpack(BuildpackMetadata buildpackMetadata) {\n\t\tthis.coordinates = BuildpackCoordinates.fromBuildpackMetadata(buildpackMetadata);\n\t}\n\n\t@Override\n\tpublic BuildpackCoordinates getCoordinates() {\n\t\treturn this.coordinates;\n\t}\n\n\t@Override\n\tpublic void apply(IOConsumer<Layer> layers) throws IOException {\n\t}\n\n\t/**\n\t * A {@link BuildpackResolver} compatible method to resolve builder buildpacks.\n\t * @param context the resolver context\n\t * @param reference the buildpack reference\n\t * @return the resolved {@link Buildpack} or {@code null}\n\t */\n\tstatic @Nullable Buildpack resolve(BuildpackResolverContext context, BuildpackReference reference) {\n\t\tboolean unambiguous = reference.hasPrefix(PREFIX);\n\t\tBuilderReference builderReference = BuilderReference\n\t\t\t.of(unambiguous ? getSubReference(reference) : reference.toString());\n\t\tBuildpackMetadata buildpackMetadata = findBuildpackMetadata(context, builderReference);\n\t\tif (unambiguous) {\n\t\t\tAssert.state(buildpackMetadata != null, () -> \"Buildpack '\" + reference + \"' not found in builder\");\n\t\t}\n\t\treturn (buildpackMetadata != null) ? new BuilderBuildpack(buildpackMetadata) : null;\n\t}\n\n\tprivate static String getSubReference(BuildpackReference reference) {\n\t\tString result = reference.getSubReference(PREFIX);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate static @Nullable BuildpackMetadata findBuildpackMetadata(BuildpackResolverContext context,\n\t\t\tBuilderReference builderReference) {\n\t\tfor (BuildpackMetadata candidate : context.getBuildpackMetadata()) {\n\t\t\tif (builderReference.matches(candidate)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * A reference to a buildpack builder.\n\t */\n\tstatic class BuilderReference {\n\n\t\tprivate final String id;\n\n\t\tprivate final @Nullable String version;\n\n\t\tBuilderReference(String id, @Nullable String version) {\n\t\t\tthis.id = id;\n\t\t\tthis.version = version;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn (this.version != null) ? this.id + \"@\" + this.version : this.id;\n\t\t}\n\n\t\tboolean matches(BuildpackMetadata candidate) {\n\t\t\treturn this.id.equals(candidate.getId())\n\t\t\t\t\t&& (this.version == null || this.version.equals(candidate.getVersion()));\n\t\t}\n\n\t\tstatic BuilderReference of(String value) {\n\t\t\tif (value.contains(\"@\")) {\n\t\t\t\tString[] parts = value.split(\"@\");\n\t\t\t\treturn new BuilderReference(parts[0], parts[1]);\n\t\t\t}\n\t\t\treturn new BuilderReference(value, null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuilderDockerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\n\n/**\n * {@link Builder} configuration options for Docker.\n *\n * @param connection the Docker host configuration\n * @param bindHostToBuilder if the host resolved from the connection should be bound to\n * the builder\n * @param builderRegistryAuthentication the builder {@link DockerRegistryAuthentication}\n * @param publishRegistryAuthentication the publish {@link DockerRegistryAuthentication}\n * @author Phillip Webb\n * @author Wei Jiang\n * @author Scott Frederick\n * @since 3.5.0\n */\npublic record BuilderDockerConfiguration(@Nullable DockerConnectionConfiguration connection, boolean bindHostToBuilder,\n\t\t@Nullable DockerRegistryAuthentication builderRegistryAuthentication,\n\t\t@Nullable DockerRegistryAuthentication publishRegistryAuthentication) {\n\n\tpublic BuilderDockerConfiguration() {\n\t\tthis(null, false, null, null);\n\t}\n\n\tpublic BuilderDockerConfiguration withContext(String context) {\n\t\treturn withConnection(new DockerConnectionConfiguration.Context(context));\n\t}\n\n\tpublic BuilderDockerConfiguration withHost(String address, boolean secure, @Nullable String certificatePath) {\n\t\treturn withConnection(new DockerConnectionConfiguration.Host(address, secure, certificatePath));\n\t}\n\n\tprivate BuilderDockerConfiguration withConnection(DockerConnectionConfiguration hostConfiguration) {\n\t\treturn new BuilderDockerConfiguration(hostConfiguration, this.bindHostToBuilder,\n\t\t\t\tthis.builderRegistryAuthentication, this.publishRegistryAuthentication);\n\t}\n\n\tpublic BuilderDockerConfiguration withBindHostToBuilder(boolean bindHostToBuilder) {\n\t\treturn new BuilderDockerConfiguration(this.connection, bindHostToBuilder, this.builderRegistryAuthentication,\n\t\t\t\tthis.publishRegistryAuthentication);\n\t}\n\n\tpublic BuilderDockerConfiguration withBuilderRegistryAuthentication(\n\t\t\tDockerRegistryAuthentication builderRegistryAuthentication) {\n\t\treturn new BuilderDockerConfiguration(this.connection, this.bindHostToBuilder, builderRegistryAuthentication,\n\t\t\t\tthis.publishRegistryAuthentication);\n\n\t}\n\n\tpublic BuilderDockerConfiguration withPublishRegistryAuthentication(\n\t\t\tDockerRegistryAuthentication publishRegistryAuthentication) {\n\t\treturn new BuilderDockerConfiguration(this.connection, this.bindHostToBuilder,\n\t\t\t\tthis.builderRegistryAuthentication, publishRegistryAuthentication);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuilderException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Exception thrown to indicate a Builder error.\n *\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class BuilderException extends RuntimeException {\n\n\tprivate final @Nullable String operation;\n\n\tprivate final int statusCode;\n\n\tBuilderException(@Nullable String operation, int statusCode) {\n\t\tsuper(buildMessage(operation, statusCode));\n\t\tthis.operation = operation;\n\t\tthis.statusCode = statusCode;\n\t}\n\n\t/**\n\t * Return the Builder operation that failed.\n\t * @return the operation description\n\t */\n\tpublic @Nullable String getOperation() {\n\t\treturn this.operation;\n\t}\n\n\t/**\n\t * Return the status code returned from a Builder operation.\n\t * @return the statusCode the status code\n\t */\n\tpublic int getStatusCode() {\n\t\treturn this.statusCode;\n\t}\n\n\tprivate static String buildMessage(@Nullable String operation, int statusCode) {\n\t\tStringBuilder message = new StringBuilder(\"Builder\");\n\t\tif (StringUtils.hasLength(operation)) {\n\t\t\tmessage.append(\" lifecycle '\").append(operation).append(\"'\");\n\t\t}\n\t\tmessage.append(\" failed with status code \").append(statusCode);\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuilderMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.lang.invoke.MethodHandles;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JacksonException;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Builder metadata information.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass BuilderMetadata extends MappedObject {\n\n\tprivate static final String LABEL_NAME = \"io.buildpacks.builder.metadata\";\n\n\tprivate static final String[] EMPTY_MIRRORS = {};\n\n\tprivate final Stack stack;\n\n\tprivate final List<RunImage> runImages;\n\n\tprivate final Lifecycle lifecycle;\n\n\tprivate final CreatedBy createdBy;\n\n\tprivate final List<BuildpackMetadata> buildpacks;\n\n\tBuilderMetadata(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.stack = extractStack();\n\t\tthis.runImages = childrenAt(\"/images\", RunImage::new);\n\t\tthis.lifecycle = extractLifecycle();\n\t\tthis.createdBy = extractCreatedBy();\n\t\tthis.buildpacks = extractBuildpacks(getNode().at(\"/buildpacks\"));\n\t}\n\n\tprivate CreatedBy extractCreatedBy() {\n\t\tCreatedBy result = valueAt(\"/createdBy\", CreatedBy.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate Lifecycle extractLifecycle() {\n\t\tLifecycle result = valueAt(\"/lifecycle\", Lifecycle.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate Stack extractStack() {\n\t\tStack result = valueAt(\"/stack\", Stack.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate List<BuildpackMetadata> extractBuildpacks(JsonNode node) {\n\t\tif (node.isEmpty()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<BuildpackMetadata> entries = new ArrayList<>();\n\t\tnode.forEach((child) -> entries.add(BuildpackMetadata.fromJson(child)));\n\t\treturn entries;\n\t}\n\n\t/**\n\t * Return stack metadata.\n\t * @return the stack metadata\n\t */\n\tStack getStack() {\n\t\treturn this.stack;\n\t}\n\n\t/**\n\t * Return run images metadata.\n\t * @return the run images metadata\n\t */\n\tList<RunImage> getRunImages() {\n\t\treturn this.runImages;\n\t}\n\n\t/**\n\t * Return lifecycle metadata.\n\t * @return the lifecycle metadata\n\t */\n\tLifecycle getLifecycle() {\n\t\treturn this.lifecycle;\n\t}\n\n\t/**\n\t * Return information about who created the builder.\n\t * @return the created by metadata\n\t */\n\tCreatedBy getCreatedBy() {\n\t\treturn this.createdBy;\n\t}\n\n\t/**\n\t * Return the buildpacks that are bundled in the builder.\n\t * @return the buildpacks\n\t */\n\tList<BuildpackMetadata> getBuildpacks() {\n\t\treturn this.buildpacks;\n\t}\n\n\t/**\n\t * Create an updated copy of this metadata.\n\t * @param update consumer to apply updates\n\t * @return an updated metadata instance\n\t */\n\tBuilderMetadata copy(Consumer<Update> update) {\n\t\treturn new Update(this).run(update);\n\t}\n\n\t/**\n\t * Attach this metadata to the given update callback.\n\t * @param update the update used to attach the metadata\n\t */\n\tvoid attachTo(ImageConfig.Update update) {\n\t\ttry {\n\t\t\tString json = SharedJsonMapper.get().writeValueAsString(getNode());\n\t\t\tupdate.withLabel(LABEL_NAME, json);\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to extract {@link BuilderMetadata} from an image.\n\t * @param image the source image\n\t * @return the builder metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuilderMetadata fromImage(Image image) throws IOException {\n\t\tAssert.notNull(image, \"'image' must not be null\");\n\t\treturn fromImageConfig(image.getConfig());\n\t}\n\n\t/**\n\t * Factory method to extract {@link BuilderMetadata} from image config.\n\t * @param imageConfig the image config\n\t * @return the builder metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuilderMetadata fromImageConfig(ImageConfig imageConfig) throws IOException {\n\t\tAssert.notNull(imageConfig, \"'imageConfig' must not be null\");\n\t\tString json = imageConfig.getLabels().get(LABEL_NAME);\n\t\tAssert.state(json != null, () -> \"No '\" + LABEL_NAME + \"' label found in image config labels '\"\n\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(imageConfig.getLabels().keySet()) + \"'\");\n\t\treturn fromJson(json);\n\t}\n\n\t/**\n\t * Factory method create {@link BuilderMetadata} from some JSON.\n\t * @param json the source JSON\n\t * @return the builder metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuilderMetadata fromJson(String json) throws IOException {\n\t\treturn new BuilderMetadata(SharedJsonMapper.get().readTree(json));\n\t}\n\n\t/**\n\t * Stack metadata.\n\t */\n\tinterface Stack {\n\n\t\t/**\n\t\t * Return run image metadata.\n\t\t * @return the run image metadata\n\t\t */\n\t\tRunImage getRunImage();\n\n\t\t/**\n\t\t * Run image metadata.\n\t\t */\n\t\tinterface RunImage {\n\n\t\t\t/**\n\t\t\t * Return the builder image reference.\n\t\t\t * @return the image reference\n\t\t\t */\n\t\t\tString getImage();\n\n\t\t\t/**\n\t\t\t * Return stack mirrors.\n\t\t\t * @return the stack mirrors\n\t\t\t */\n\t\t\tdefault String[] getMirrors() {\n\t\t\t\treturn EMPTY_MIRRORS;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class RunImage extends MappedObject {\n\n\t\tprivate final String image;\n\n\t\tprivate final List<String> mirrors;\n\n\t\t/**\n\t\t * Create a new {@link MappedObject} instance.\n\t\t * @param node the source node\n\t\t */\n\t\tRunImage(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tthis.image = extractImage();\n\t\t\tthis.mirrors = childrenAt(\"/mirrors\", JsonNode::asString);\n\t\t}\n\n\t\tprivate String extractImage() {\n\t\t\tString result = valueAt(\"/image\", String.class);\n\t\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\t\treturn result;\n\t\t}\n\n\t\tString getImage() {\n\t\t\treturn this.image;\n\t\t}\n\n\t\tList<String> getMirrors() {\n\t\t\treturn this.mirrors;\n\t\t}\n\n\t}\n\n\t/**\n\t * Lifecycle metadata.\n\t */\n\tinterface Lifecycle {\n\n\t\t/**\n\t\t * Return the lifecycle version.\n\t\t * @return the lifecycle version\n\t\t */\n\t\tString getVersion();\n\n\t\t/**\n\t\t * Return the default API versions.\n\t\t * @return the API versions\n\t\t */\n\t\tApi getApi();\n\n\t\t/**\n\t\t * Return the supported API versions.\n\t\t * @return the API versions\n\t\t */\n\t\tApis getApis();\n\n\t\t/**\n\t\t * Default API versions.\n\t\t */\n\t\tinterface Api {\n\n\t\t\t/**\n\t\t\t * Return the default buildpack API version.\n\t\t\t * @return the buildpack version\n\t\t\t */\n\t\t\tString getBuildpack();\n\n\t\t\t/**\n\t\t\t * Return the default platform API version.\n\t\t\t * @return the platform version\n\t\t\t */\n\t\t\tString getPlatform();\n\n\t\t}\n\n\t\t/**\n\t\t * Supported API versions.\n\t\t */\n\t\tinterface Apis {\n\n\t\t\t/**\n\t\t\t * Return the supported buildpack API versions.\n\t\t\t * @return the buildpack versions\n\t\t\t */\n\t\t\tdefault String @Nullable [] getBuildpack() {\n\t\t\t\treturn valueAt(this, \"/buildpack/supported\", String[].class);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Return the supported platform API versions.\n\t\t\t * @return the platform versions\n\t\t\t */\n\t\t\tdefault String @Nullable [] getPlatform() {\n\t\t\t\treturn valueAt(this, \"/platform/supported\", String[].class);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Created-by metadata.\n\t */\n\tinterface CreatedBy {\n\n\t\t/**\n\t\t * Return the name of the creator.\n\t\t * @return the creator name\n\t\t */\n\t\tString getName();\n\n\t\t/**\n\t\t * Return the version of the creator.\n\t\t * @return the creator version\n\t\t */\n\t\tString getVersion();\n\n\t}\n\n\t/**\n\t * Update class used to change data when creating a copy.\n\t */\n\tstatic final class Update {\n\n\t\tprivate final ObjectNode copy;\n\n\t\tprivate Update(BuilderMetadata source) {\n\t\t\tthis.copy = (ObjectNode) source.getNode().deepCopy();\n\t\t}\n\n\t\tprivate BuilderMetadata run(Consumer<Update> update) {\n\t\t\tupdate.accept(this);\n\t\t\treturn new BuilderMetadata(this.copy);\n\t\t}\n\n\t\t/**\n\t\t * Update the builder meta-data with a specific created by section.\n\t\t * @param name the name of the creator\n\t\t * @param version the version of the creator\n\t\t */\n\t\tvoid withCreatedBy(String name, String version) {\n\t\t\tObjectNode createdBy = (ObjectNode) this.copy.at(\"/createdBy\");\n\t\t\tif (createdBy == null) {\n\t\t\t\tcreatedBy = this.copy.putObject(\"createdBy\");\n\t\t\t}\n\t\t\tcreatedBy.put(\"name\", name);\n\t\t\tcreatedBy.put(\"version\", version);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Buildpack.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\n\n/**\n * A Buildpack that should be invoked by the builder during image building.\n *\n * @author Scott Frederick\n * @see BuildpackResolver\n */\ninterface Buildpack {\n\n\t/**\n\t * Return the coordinates of the builder.\n\t * @return the builder coordinates\n\t */\n\tBuildpackCoordinates getCoordinates();\n\n\t/**\n\t * Apply the necessary buildpack layers.\n\t * @param layers a consumer that should accept the layers\n\t * @throws IOException on IO error\n\t */\n\tvoid apply(IOConsumer<Layer> layers) throws IOException;\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackCoordinates.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\n\nimport org.jspecify.annotations.Nullable;\nimport org.tomlj.Toml;\nimport org.tomlj.TomlParseResult;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A set of buildpack coordinates that uniquely identifies a buildpack.\n *\n * @author Scott Frederick\n * @see <a href=\n * \"https://github.com/buildpacks/spec/blob/main/platform.md#ordertoml-toml\">Platform\n * Interface Specification</a>\n */\nfinal class BuildpackCoordinates {\n\n\tprivate final String id;\n\n\tprivate final @Nullable String version;\n\n\tprivate BuildpackCoordinates(String id, @Nullable String version) {\n\t\tAssert.hasText(id, \"'id' must not be empty\");\n\t\tthis.id = id;\n\t\tthis.version = version;\n\t}\n\n\tString getId() {\n\t\treturn this.id;\n\t}\n\n\t/**\n\t * Return the buildpack ID with all \"/\" replaced by \"_\".\n\t * @return the ID\n\t */\n\tString getSanitizedId() {\n\t\treturn this.id.replace(\"/\", \"_\");\n\t}\n\n\t@Nullable String getVersion() {\n\t\treturn this.version;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tBuildpackCoordinates other = (BuildpackCoordinates) obj;\n\t\treturn this.id.equals(other.id) && ObjectUtils.nullSafeEquals(this.version, other.version);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.id.hashCode();\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.version);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.id + ((StringUtils.hasText(this.version)) ? \"@\" + this.version : \"\");\n\t}\n\n\t/**\n\t * Create {@link BuildpackCoordinates} from a <a href=\n\t * \"https://github.com/buildpacks/spec/blob/main/buildpack.md#buildpacktoml-toml\">{@code buildpack.toml}</a>\n\t * file.\n\t * @param inputStream an input stream containing {@code buildpack.toml} content\n\t * @param path the path to the buildpack containing the {@code buildpack.toml} file\n\t * @return a new {@link BuildpackCoordinates} instance\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackCoordinates fromToml(InputStream inputStream, Path path) throws IOException {\n\t\treturn fromToml(Toml.parse(inputStream), path);\n\t}\n\n\tprivate static BuildpackCoordinates fromToml(TomlParseResult toml, Path path) {\n\t\tAssert.isTrue(!toml.isEmpty(),\n\t\t\t\t() -> \"Buildpack descriptor 'buildpack.toml' is required in buildpack '\" + path + \"'\");\n\t\tString buildpackId = toml.getString(\"buildpack.id\");\n\t\tAssert.hasText(buildpackId, () -> \"Buildpack descriptor must contain ID in buildpack '\" + path + \"'\");\n\t\tAssert.hasText(toml.getString(\"buildpack.version\"),\n\t\t\t\t() -> \"Buildpack descriptor must contain version in buildpack '\" + path + \"'\");\n\t\tAssert.isTrue(toml.contains(\"stacks\") || toml.contains(\"order\"),\n\t\t\t\t() -> \"Buildpack descriptor must contain either 'stacks' or 'order' in buildpack '\" + path + \"'\");\n\t\tAssert.isTrue(!(toml.contains(\"stacks\") && toml.contains(\"order\")),\n\t\t\t\t() -> \"Buildpack descriptor must not contain both 'stacks' and 'order' in buildpack '\" + path + \"'\");\n\t\treturn new BuildpackCoordinates(buildpackId, toml.getString(\"buildpack.version\"));\n\t}\n\n\t/**\n\t * Create {@link BuildpackCoordinates} by extracting values from\n\t * {@link BuildpackMetadata}.\n\t * @param buildpackMetadata the buildpack metadata\n\t * @return a new {@link BuildpackCoordinates} instance\n\t */\n\tstatic BuildpackCoordinates fromBuildpackMetadata(BuildpackMetadata buildpackMetadata) {\n\t\tAssert.notNull(buildpackMetadata, \"'buildpackMetadata' must not be null\");\n\t\treturn new BuildpackCoordinates(buildpackMetadata.getId(), buildpackMetadata.getVersion());\n\t}\n\n\t/**\n\t * Create {@link BuildpackCoordinates} from an ID and version.\n\t * @param id the buildpack ID\n\t * @param version the buildpack version\n\t * @return a new {@link BuildpackCoordinates} instance\n\t */\n\tstatic BuildpackCoordinates of(String id, @Nullable String version) {\n\t\treturn new BuildpackCoordinates(id, version);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackLayersMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.lang.invoke.MethodHandles;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Buildpack layers metadata information.\n *\n * @author Scott Frederick\n */\nfinal class BuildpackLayersMetadata extends MappedObject {\n\n\tprivate static final String LABEL_NAME = \"io.buildpacks.buildpack.layers\";\n\n\tprivate final Buildpacks buildpacks;\n\n\tprivate BuildpackLayersMetadata(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.buildpacks = Buildpacks.fromJson(getNode());\n\t}\n\n\t/**\n\t * Return the metadata details of a buildpack with the given ID and version.\n\t * @param id the buildpack ID\n\t * @param version the buildpack version\n\t * @return the buildpack details or {@code null} if a buildpack with the given ID and\n\t * version does not exist in the metadata\n\t */\n\t@Nullable BuildpackLayerDetails getBuildpack(String id, @Nullable String version) {\n\t\treturn this.buildpacks.getBuildpack(id, version);\n\t}\n\n\t/**\n\t * Create a {@link BuildpackLayersMetadata} from an image.\n\t * @param image the source image\n\t * @return the buildpack layers metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackLayersMetadata fromImage(Image image) throws IOException {\n\t\tAssert.notNull(image, \"'image' must not be null\");\n\t\treturn fromImageConfig(image.getConfig());\n\t}\n\n\t/**\n\t * Create a {@link BuildpackLayersMetadata} from image config.\n\t * @param imageConfig the source image config\n\t * @return the buildpack layers metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackLayersMetadata fromImageConfig(ImageConfig imageConfig) throws IOException {\n\t\tAssert.notNull(imageConfig, \"'imageConfig' must not be null\");\n\t\tString json = imageConfig.getLabels().get(LABEL_NAME);\n\t\tAssert.state(json != null, () -> \"No '\" + LABEL_NAME + \"' label found in image config labels '\"\n\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(imageConfig.getLabels().keySet()) + \"'\");\n\t\treturn fromJson(json);\n\t}\n\n\t/**\n\t * Create a {@link BuildpackLayersMetadata} from JSON.\n\t * @param json the source JSON\n\t * @return the buildpack layers metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackLayersMetadata fromJson(String json) throws IOException {\n\t\treturn fromJson(SharedJsonMapper.get().readTree(json));\n\t}\n\n\t/**\n\t * Create a {@link BuildpackLayersMetadata} from JSON.\n\t * @param node the source JSON\n\t * @return the buildpack layers metadata\n\t */\n\tstatic BuildpackLayersMetadata fromJson(JsonNode node) {\n\t\treturn new BuildpackLayersMetadata(node);\n\t}\n\n\tprivate static final class Buildpacks {\n\n\t\tprivate final Map<String, BuildpackVersions> buildpacks = new HashMap<>();\n\n\t\tprivate @Nullable BuildpackLayerDetails getBuildpack(String id, @Nullable String version) {\n\t\t\tif (this.buildpacks.containsKey(id)) {\n\t\t\t\treturn this.buildpacks.get(id).getBuildpack(version);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate void addBuildpackVersions(String id, BuildpackVersions versions) {\n\t\t\tthis.buildpacks.put(id, versions);\n\t\t}\n\n\t\tprivate static Buildpacks fromJson(JsonNode node) {\n\t\t\tBuildpacks buildpacks = new Buildpacks();\n\t\t\tnode.properties()\n\t\t\t\t.forEach((field) -> buildpacks.addBuildpackVersions(field.getKey(),\n\t\t\t\t\t\tBuildpackVersions.fromJson(field.getValue())));\n\t\t\treturn buildpacks;\n\t\t}\n\n\t}\n\n\tprivate static final class BuildpackVersions {\n\n\t\tprivate final Map<String, BuildpackLayerDetails> versions = new HashMap<>();\n\n\t\tprivate @Nullable BuildpackLayerDetails getBuildpack(@Nullable String version) {\n\t\t\treturn this.versions.get(version);\n\t\t}\n\n\t\tprivate void addBuildpackVersion(String version, BuildpackLayerDetails details) {\n\t\t\tthis.versions.put(version, details);\n\t\t}\n\n\t\tprivate static BuildpackVersions fromJson(JsonNode node) {\n\t\t\tBuildpackVersions versions = new BuildpackVersions();\n\t\t\tnode.properties()\n\t\t\t\t.forEach((field) -> versions.addBuildpackVersion(field.getKey(),\n\t\t\t\t\t\tBuildpackLayerDetails.fromJson(field.getValue())));\n\t\t\treturn versions;\n\t\t}\n\n\t}\n\n\tstatic final class BuildpackLayerDetails extends MappedObject {\n\n\t\tprivate final @Nullable String name;\n\n\t\tprivate final @Nullable String homepage;\n\n\t\tprivate final @Nullable String layerDiffId;\n\n\t\tprivate BuildpackLayerDetails(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tthis.name = valueAt(\"/name\", String.class);\n\t\t\tthis.homepage = valueAt(\"/homepage\", String.class);\n\t\t\tthis.layerDiffId = valueAt(\"/layerDiffID\", String.class);\n\t\t}\n\n\t\t/**\n\t\t * Return the buildpack name.\n\t\t * @return the name\n\t\t */\n\t\t@Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t/**\n\t\t * Return the buildpack homepage address.\n\t\t * @return the homepage address\n\t\t */\n\t\t@Nullable String getHomepage() {\n\t\t\treturn this.homepage;\n\t\t}\n\n\t\t/**\n\t\t * Return the buildpack layer {@code diffID}.\n\t\t * @return the layer {@code diffID}\n\t\t */\n\t\t@Nullable String getLayerDiffId() {\n\t\t\treturn this.layerDiffId;\n\t\t}\n\n\t\tprivate static BuildpackLayerDetails fromJson(JsonNode node) {\n\t\t\treturn new BuildpackLayerDetails(node);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.lang.invoke.MethodHandles;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Buildpack metadata information.\n *\n * @author Scott Frederick\n */\nfinal class BuildpackMetadata extends MappedObject {\n\n\tprivate static final String LABEL_NAME = \"io.buildpacks.buildpackage.metadata\";\n\n\tprivate final String id;\n\n\tprivate final @Nullable String version;\n\n\tprivate final @Nullable String homepage;\n\n\tprivate BuildpackMetadata(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.id = extractId();\n\t\tthis.version = valueAt(\"/version\", String.class);\n\t\tthis.homepage = valueAt(\"/homepage\", String.class);\n\t}\n\n\tprivate String extractId() {\n\t\tString result = valueAt(\"/id\", String.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the buildpack ID.\n\t * @return the ID\n\t */\n\tString getId() {\n\t\treturn this.id;\n\t}\n\n\t/**\n\t * Return the buildpack version.\n\t * @return the version\n\t */\n\t@Nullable String getVersion() {\n\t\treturn this.version;\n\t}\n\n\t/**\n\t * Return the buildpack homepage address.\n\t * @return the homepage\n\t */\n\t@Nullable String getHomepage() {\n\t\treturn this.homepage;\n\t}\n\n\t/**\n\t * Factory method to extract {@link BuildpackMetadata} from an image.\n\t * @param image the source image\n\t * @return the builder metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackMetadata fromImage(Image image) throws IOException {\n\t\tAssert.notNull(image, \"'image' must not be null\");\n\t\treturn fromImageConfig(image.getConfig());\n\t}\n\n\t/**\n\t * Factory method to extract {@link BuildpackMetadata} from image config.\n\t * @param imageConfig the source image config\n\t * @return the builder metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackMetadata fromImageConfig(ImageConfig imageConfig) throws IOException {\n\t\tAssert.notNull(imageConfig, \"'imageConfig' must not be null\");\n\t\tString json = imageConfig.getLabels().get(LABEL_NAME);\n\t\tAssert.state(json != null, () -> \"No '\" + LABEL_NAME + \"' label found in image config labels '\"\n\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(imageConfig.getLabels().keySet()) + \"'\");\n\t\treturn fromJson(json);\n\t}\n\n\t/**\n\t * Factory method create {@link BuildpackMetadata} from JSON.\n\t * @param json the source JSON\n\t * @return the builder metadata\n\t * @throws IOException on IO error\n\t */\n\tstatic BuildpackMetadata fromJson(String json) throws IOException {\n\t\treturn fromJson(SharedJsonMapper.get().readTree(json));\n\t}\n\n\t/**\n\t * Factory method create {@link BuildpackMetadata} from JSON.\n\t * @param node the source JSON\n\t * @return the builder metadata\n\t */\n\tstatic BuildpackMetadata fromJson(JsonNode node) {\n\t\treturn new BuildpackMetadata(node);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackReference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.net.MalformedURLException;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * An opaque reference to a {@link Buildpack}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.5.0\n * @see BuildpackResolver\n */\npublic final class BuildpackReference {\n\n\tprivate final String value;\n\n\tprivate BuildpackReference(String value) {\n\t\tthis.value = value;\n\t}\n\n\tboolean hasPrefix(String prefix) {\n\t\treturn this.value.startsWith(prefix);\n\t}\n\n\t@Nullable String getSubReference(String prefix) {\n\t\treturn this.value.startsWith(prefix) ? this.value.substring(prefix.length()) : null;\n\t}\n\n\t@Nullable Path asPath() {\n\t\ttry {\n\t\t\tURL url = new URL(this.value);\n\t\t\tif (url.getProtocol().equals(\"file\")) {\n\t\t\t\treturn Paths.get(url.toURI());\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tcatch (MalformedURLException | URISyntaxException ex) {\n\t\t\t// not a URL, fall through to attempting to find a plain file path\n\t\t}\n\t\ttry {\n\t\t\treturn Paths.get(this.value);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.value.equals(((BuildpackReference) obj).value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Create a new {@link BuildpackReference} from the given value.\n\t * @param value the value to use\n\t * @return a new {@link BuildpackReference}\n\t */\n\tpublic static BuildpackReference of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\treturn new BuildpackReference(value);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Strategy interface used to resolve a {@link BuildpackReference} to a {@link Buildpack}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @see BuildpackResolvers\n */\ninterface BuildpackResolver {\n\n\t/**\n\t * Attempt to resolve the given {@link BuildpackReference}.\n\t * @param context the resolver context\n\t * @param reference the reference to resolve\n\t * @return a resolved {@link Buildpack} instance or {@code null}\n\t */\n\t@Nullable Buildpack resolve(BuildpackResolverContext context, BuildpackReference reference);\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackResolverContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.IOBiConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\n\n/**\n * Context passed to a {@link BuildpackResolver}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\ninterface BuildpackResolverContext {\n\n\tList<BuildpackMetadata> getBuildpackMetadata();\n\n\tBuildpackLayersMetadata getBuildpackLayersMetadata();\n\n\t/**\n\t * Retrieve an image.\n\t * @param reference the image reference\n\t * @param type the type of image\n\t * @return the retrieved image\n\t * @throws IOException on IO error\n\t */\n\tImage fetchImage(ImageReference reference, ImageType type) throws IOException;\n\n\t/**\n\t * Export the layers of an image.\n\t * @param reference the reference to export\n\t * @param exports a consumer to receive the layers (contents can only be accessed\n\t * during the callback)\n\t * @throws IOException on IO error\n\t */\n\tvoid exportImageLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports) throws IOException;\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/BuildpackResolvers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * All {@link BuildpackResolver} instances that can be used to resolve\n * {@link BuildpackReference BuildpackReferences}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nfinal class BuildpackResolvers {\n\n\tprivate static final List<BuildpackResolver> resolvers = getResolvers();\n\n\tprivate BuildpackResolvers() {\n\t}\n\n\tprivate static List<BuildpackResolver> getResolvers() {\n\t\tList<BuildpackResolver> resolvers = new ArrayList<>();\n\t\tresolvers.add(BuilderBuildpack::resolve);\n\t\tresolvers.add(DirectoryBuildpack::resolve);\n\t\tresolvers.add(TarGzipBuildpack::resolve);\n\t\tresolvers.add(ImageBuildpack::resolve);\n\t\treturn Collections.unmodifiableList(resolvers);\n\t}\n\n\t/**\n\t * Resolve a collection of {@link BuildpackReference BuildpackReferences} to a\n\t * {@link Buildpacks} instance.\n\t * @param context the resolver context\n\t * @param references the references to resolve\n\t * @return a {@link Buildpacks} instance\n\t */\n\tstatic Buildpacks resolveAll(BuildpackResolverContext context, Collection<BuildpackReference> references) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tif (CollectionUtils.isEmpty(references)) {\n\t\t\treturn Buildpacks.EMPTY;\n\t\t}\n\t\tList<Buildpack> buildpacks = new ArrayList<>(references.size());\n\t\tfor (BuildpackReference reference : references) {\n\t\t\tbuildpacks.add(resolve(context, reference));\n\t\t}\n\t\treturn Buildpacks.of(buildpacks);\n\t}\n\n\tprivate static Buildpack resolve(BuildpackResolverContext context, BuildpackReference reference) {\n\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\tfor (BuildpackResolver resolver : resolvers) {\n\t\t\tBuildpack buildpack = resolver.resolve(context, reference);\n\t\t\tif (buildpack != null) {\n\t\t\t\treturn buildpack;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Invalid buildpack reference '\" + reference + \"'\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Buildpacks.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.Layout;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A collection of {@link Buildpack} instances that can be used to apply buildpack layers.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nfinal class Buildpacks {\n\n\tstatic final Buildpacks EMPTY = new Buildpacks(Collections.emptyList());\n\n\tprivate final List<Buildpack> buildpacks;\n\n\tprivate Buildpacks(List<Buildpack> buildpacks) {\n\t\tthis.buildpacks = buildpacks;\n\t}\n\n\tList<Buildpack> getBuildpacks() {\n\t\treturn this.buildpacks;\n\t}\n\n\tvoid apply(IOConsumer<Layer> layers) throws IOException {\n\t\tif (!this.buildpacks.isEmpty()) {\n\t\t\tfor (Buildpack buildpack : this.buildpacks) {\n\t\t\t\tbuildpack.apply(layers);\n\t\t\t}\n\t\t\tlayers.accept(Layer.of(this::addOrderLayerContent));\n\t\t}\n\t}\n\n\tvoid addOrderLayerContent(Layout layout) throws IOException {\n\t\tlayout.file(\"/cnb/order.toml\", Owner.ROOT, Content.of(getOrderToml()));\n\t}\n\n\tprivate String getOrderToml() {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tbuilder.append(\"[[order]]\\n\\n\");\n\t\tfor (Buildpack buildpack : this.buildpacks) {\n\t\t\tappendToOrderToml(builder, buildpack.getCoordinates());\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n\tprivate void appendToOrderToml(StringBuilder builder, BuildpackCoordinates coordinates) {\n\t\tbuilder.append(\"  [[order.group]]\\n\");\n\t\tbuilder.append(\"    id = \\\"\" + coordinates.getId() + \"\\\"\\n\");\n\t\tif (StringUtils.hasText(coordinates.getVersion())) {\n\t\t\tbuilder.append(\"    version = \\\"\" + coordinates.getVersion() + \"\\\"\\n\");\n\t\t}\n\t\tbuilder.append(\"\\n\");\n\t}\n\n\tstatic Buildpacks of(@Nullable List<Buildpack> buildpacks) {\n\t\treturn CollectionUtils.isEmpty(buildpacks) ? EMPTY : new Buildpacks(buildpacks);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Cache.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Details of a cache for use by the CNB builder.\n *\n * @author Scott Frederick\n * @since 2.6.0\n */\npublic class Cache {\n\n\t/**\n\t * The format of the cache.\n\t */\n\tpublic enum Format {\n\n\t\t/**\n\t\t * A cache stored as a volume in the Docker daemon.\n\t\t */\n\t\tVOLUME(\"volume\"),\n\n\t\t/**\n\t\t * A cache stored as a bind mount.\n\t\t */\n\t\tBIND(\"bind mount\");\n\n\t\tprivate final String description;\n\n\t\tFormat(String description) {\n\t\t\tthis.description = description;\n\t\t}\n\n\t\tpublic String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t}\n\n\tprotected final Format format;\n\n\tCache(Format format) {\n\t\tthis.format = format;\n\t}\n\n\t/**\n\t * Return the details of the cache if it is a volume cache.\n\t * @return the cache, or {@code null} if it is not a volume cache\n\t */\n\tpublic @Nullable Volume getVolume() {\n\t\treturn (this.format.equals(Format.VOLUME)) ? (Volume) this : null;\n\t}\n\n\t/**\n\t * Return the details of the cache if it is a bind cache.\n\t * @return the cache, or {@code null} if it is not a bind cache\n\t */\n\tpublic @Nullable Bind getBind() {\n\t\treturn (this.format.equals(Format.BIND)) ? (Bind) this : null;\n\t}\n\n\t/**\n\t * Create a new {@code Cache} that uses a volume with the provided name.\n\t * @param name the cache volume name\n\t * @return a new cache instance\n\t */\n\tpublic static Cache volume(String name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\treturn new Volume(VolumeName.of(name));\n\t}\n\n\t/**\n\t * Create a new {@code Cache} that uses a volume with the provided name.\n\t * @param name the cache volume name\n\t * @return a new cache instance\n\t */\n\tpublic static Cache volume(VolumeName name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\treturn new Volume(name);\n\t}\n\n\t/**\n\t * Create a new {@code Cache} that uses a bind mount with the provided source.\n\t * @param source the cache bind mount source\n\t * @return a new cache instance\n\t */\n\tpublic static Cache bind(String source) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\treturn new Bind(source);\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tCache other = (Cache) obj;\n\t\treturn Objects.equals(this.format, other.format);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHashCode(this.format);\n\t}\n\n\t/**\n\t * Details of a cache stored in a Docker volume.\n\t */\n\tpublic static class Volume extends Cache {\n\n\t\tprivate final VolumeName name;\n\n\t\tVolume(VolumeName name) {\n\t\t\tsuper(Format.VOLUME);\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name.toString();\n\t\t}\n\n\t\tpublic VolumeName getVolumeName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!super.equals(obj)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tVolume other = (Volume) obj;\n\t\t\treturn Objects.equals(this.name, other.name);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\tint result = super.hashCode();\n\t\t\tresult = 31 * result + ObjectUtils.nullSafeHashCode(this.name);\n\t\t\treturn result;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.format.getDescription() + \" '\" + this.name + \"'\";\n\t\t}\n\n\t}\n\n\t/**\n\t * Details of a cache stored in a bind mount.\n\t */\n\tpublic static class Bind extends Cache {\n\n\t\tprivate final String source;\n\n\t\tBind(String source) {\n\t\t\tsuper(Format.BIND);\n\t\t\tthis.source = source;\n\t\t}\n\n\t\tpublic String getSource() {\n\t\t\treturn this.source;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!super.equals(obj)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tBind other = (Bind) obj;\n\t\t\treturn Objects.equals(this.source, other.source);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\tint result = super.hashCode();\n\t\t\tresult = 31 * result + ObjectUtils.nullSafeHashCode(this.source);\n\t\t\treturn result;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.format.getDescription() + \" '\" + this.source + \"'\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Creator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.springframework.util.Assert;\n\n/**\n * Identifying information about the tooling that created a builder.\n *\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class Creator {\n\n\tprivate final String version;\n\n\tCreator(String version) {\n\t\tthis.version = version;\n\t}\n\n\t/**\n\t * Return the name of the builder creator.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn \"Spring Boot\";\n\t}\n\n\t/**\n\t * Return the version of the builder creator.\n\t * @return the version\n\t */\n\tpublic String getVersion() {\n\t\treturn this.version;\n\t}\n\n\t/**\n\t * Create a new {@code Creator} using the provided version.\n\t * @param version the creator version\n\t * @return a new creator instance\n\t */\n\tpublic static Creator withVersion(String version) {\n\t\tAssert.notNull(version, \"'version' must not be null\");\n\t\treturn new Creator(version);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \" version \" + getVersion();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/DirectoryBuildpack.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.FileVisitResult;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.SimpleFileVisitor;\nimport java.nio.file.attribute.BasicFileAttributes;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.FilePermissions;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.Layout;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link Buildpack} that references a buildpack in a directory on the local file\n * system.\n *\n * The file system must contain a buildpack descriptor named {@code buildpack.toml} in the\n * root of the directory. The contents of the directory tree will be provided as a single\n * layer to be included in the builder image.\n *\n * @author Scott Frederick\n */\nfinal class DirectoryBuildpack implements Buildpack {\n\n\tprivate final Path path;\n\n\tprivate final BuildpackCoordinates coordinates;\n\n\tprivate DirectoryBuildpack(Path path) {\n\t\tthis.path = path;\n\t\tthis.coordinates = findBuildpackCoordinates(path);\n\t}\n\n\tprivate BuildpackCoordinates findBuildpackCoordinates(Path path) {\n\t\tPath buildpackToml = path.resolve(\"buildpack.toml\");\n\t\tAssert.state(Files.exists(buildpackToml),\n\t\t\t\t() -> \"Buildpack descriptor 'buildpack.toml' is required in buildpack '\" + path + \"'\");\n\t\ttry {\n\t\t\ttry (InputStream inputStream = Files.newInputStream(buildpackToml)) {\n\t\t\t\treturn BuildpackCoordinates.fromToml(inputStream, path);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Error parsing descriptor for buildpack '\" + path + \"'\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic BuildpackCoordinates getCoordinates() {\n\t\treturn this.coordinates;\n\t}\n\n\t@Override\n\tpublic void apply(IOConsumer<Layer> layers) throws IOException {\n\t\tlayers.accept(Layer.of(this::addLayerContent));\n\t}\n\n\tprivate void addLayerContent(Layout layout) throws IOException {\n\t\tString id = this.coordinates.getSanitizedId();\n\t\tPath cnbPath = Paths.get(\"/cnb/buildpacks/\", id, this.coordinates.getVersion());\n\t\twriteBasePathEntries(layout, cnbPath);\n\t\tFiles.walkFileTree(this.path, new LayoutFileVisitor(this.path, cnbPath, layout));\n\t}\n\n\tprivate void writeBasePathEntries(Layout layout, Path basePath) throws IOException {\n\t\tint pathCount = basePath.getNameCount();\n\t\tfor (int pathIndex = 1; pathIndex < pathCount + 1; pathIndex++) {\n\t\t\tString name = \"/\" + basePath.subpath(0, pathIndex) + \"/\";\n\t\t\tlayout.directory(name, Owner.ROOT);\n\t\t}\n\t}\n\n\t/**\n\t * A {@link BuildpackResolver} compatible method to resolve directory buildpacks.\n\t * @param context the resolver context\n\t * @param reference the buildpack reference\n\t * @return the resolved {@link Buildpack} or {@code null}\n\t */\n\tstatic @Nullable Buildpack resolve(BuildpackResolverContext context, BuildpackReference reference) {\n\t\tPath path = reference.asPath();\n\t\tif (path != null && Files.exists(path) && Files.isDirectory(path)) {\n\t\t\treturn new DirectoryBuildpack(path);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * {@link SimpleFileVisitor} to used to create the {@link Layout}.\n\t */\n\tprivate static class LayoutFileVisitor extends SimpleFileVisitor<Path> {\n\n\t\tprivate final Path basePath;\n\n\t\tprivate final Path layerPath;\n\n\t\tprivate final Layout layout;\n\n\t\tLayoutFileVisitor(Path basePath, Path layerPath, Layout layout) {\n\t\t\tthis.basePath = basePath;\n\t\t\tthis.layerPath = layerPath;\n\t\t\tthis.layout = layout;\n\t\t}\n\n\t\t@Override\n\t\tpublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {\n\t\t\tif (!dir.equals(this.basePath)) {\n\t\t\t\tthis.layout.directory(relocate(dir), Owner.ROOT, getMode(dir));\n\t\t\t}\n\t\t\treturn FileVisitResult.CONTINUE;\n\t\t}\n\n\t\t@Override\n\t\tpublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {\n\t\t\tthis.layout.file(relocate(file), Owner.ROOT, getMode(file), Content.of(file.toFile()));\n\t\t\treturn FileVisitResult.CONTINUE;\n\t\t}\n\n\t\tprivate int getMode(Path path) throws IOException {\n\t\t\ttry {\n\t\t\t\treturn FilePermissions.umaskForPath(path);\n\t\t\t}\n\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Buildpack content in a directory is not supported on this operating system\");\n\t\t\t}\n\t\t}\n\n\t\tprivate String relocate(Path path) {\n\t\t\tPath node = path.subpath(this.basePath.getNameCount(), path.getNameCount());\n\t\t\treturn Paths.get(this.layerPath.toString(), node.toString()).toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/EphemeralBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive.Update;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A short-lived builder that is created for each {@link Lifecycle} run.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass EphemeralBuilder {\n\n\tstatic final String BUILDER_FOR_LABEL_NAME = \"org.springframework.boot.builderFor\";\n\n\tprivate ImageReference name;\n\n\tprivate final BuildOwner buildOwner;\n\n\tprivate final Creator creator;\n\n\tprivate final BuilderMetadata builderMetadata;\n\n\tprivate final Image builderImage;\n\n\tprivate final IOConsumer<Update> archiveUpdate;\n\n\t/**\n\t * Create a new {@link EphemeralBuilder} instance.\n\t * @param buildOwner the build owner\n\t * @param builderImage the base builder image\n\t * @param targetImage the image being built\n\t * @param builderMetadata the builder metadata\n\t * @param creator the builder creator\n\t * @param env the builder env\n\t * @param buildpacks an optional set of buildpacks to apply\n\t */\n\tEphemeralBuilder(BuildOwner buildOwner, Image builderImage, ImageReference targetImage,\n\t\t\tBuilderMetadata builderMetadata, Creator creator, @Nullable Map<String, String> env,\n\t\t\t@Nullable Buildpacks buildpacks) {\n\t\tthis.name = ImageReference.random(\"pack.local/builder/\").inTaggedForm();\n\t\tthis.buildOwner = buildOwner;\n\t\tthis.creator = creator;\n\t\tthis.builderMetadata = builderMetadata.copy(this::updateMetadata);\n\t\tthis.builderImage = builderImage;\n\t\tthis.archiveUpdate = (update) -> {\n\t\t\tupdate.withUpdatedConfig(this.builderMetadata::attachTo);\n\t\t\tupdate.withUpdatedConfig((config) -> config.withLabel(BUILDER_FOR_LABEL_NAME, targetImage.toString()));\n\t\t\tupdate.withTag(this.name);\n\t\t\tif (!CollectionUtils.isEmpty(env)) {\n\t\t\t\tupdate.withNewLayer(getEnvLayer(env));\n\t\t\t}\n\t\t\tif (buildpacks != null) {\n\t\t\t\tbuildpacks.apply(update::withNewLayer);\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate void updateMetadata(BuilderMetadata.Update update) {\n\t\tupdate.withCreatedBy(this.creator.getName(), this.creator.getVersion());\n\t}\n\n\tprivate Layer getEnvLayer(Map<String, String> env) throws IOException {\n\t\treturn Layer.of((layout) -> {\n\t\t\tfor (Map.Entry<String, String> entry : env.entrySet()) {\n\t\t\t\tString name = \"/platform/env/\" + entry.getKey();\n\t\t\t\tContent content = Content.of((entry.getValue() != null) ? entry.getValue() : \"\");\n\t\t\t\tlayout.file(name, Owner.ROOT, content);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Return the name of this archive as tagged in Docker.\n\t * @return the ephemeral builder name\n\t */\n\tImageReference getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the build owner that should be used for written content.\n\t * @return the builder owner\n\t */\n\tOwner getBuildOwner() {\n\t\treturn this.buildOwner;\n\t}\n\n\t/**\n\t * Return the builder meta-data that was used to create this ephemeral builder.\n\t * @return the builder meta-data\n\t */\n\tBuilderMetadata getBuilderMetadata() {\n\t\treturn this.builderMetadata;\n\t}\n\n\t/**\n\t * Return the contents of ephemeral builder for passing to Docker.\n\t * @param applicationDirectory the application directory\n\t * @return the ephemeral builder archive\n\t * @throws IOException on IO error\n\t */\n\tImageArchive getArchive(@Nullable String applicationDirectory) throws IOException {\n\t\treturn ImageArchive.from(this.builderImage, (update) -> {\n\t\t\tthis.archiveUpdate.accept(update);\n\t\t\tif (StringUtils.hasLength(applicationDirectory)) {\n\t\t\t\tupdate.withNewLayer(applicationDirectoryLayer(applicationDirectory));\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate Layer applicationDirectoryLayer(String applicationDirectory) throws IOException {\n\t\treturn Layer.of((layout) -> layout.directory(applicationDirectory, this.buildOwner));\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ImageBuildpack.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.BuildpackLayersMetadata.BuildpackLayerDetails;\nimport org.springframework.boot.buildpack.platform.docker.transport.DockerEngineException;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.docker.type.LayerId;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * A {@link Buildpack} that references a buildpack contained in an OCI image.\n *\n * The reference must be an OCI image reference. The reference can optionally contain a\n * prefix {@code docker://} to unambiguously identify it as an image buildpack reference.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nfinal class ImageBuildpack implements Buildpack {\n\n\tprivate static final String PREFIX = \"docker://\";\n\n\tprivate final BuildpackCoordinates coordinates;\n\n\tprivate final @Nullable ExportedLayers exportedLayers;\n\n\tprivate ImageBuildpack(BuildpackResolverContext context, ImageReference imageReference) {\n\t\tImageReference reference = imageReference.inTaggedOrDigestForm();\n\t\ttry {\n\t\t\tImage image = context.fetchImage(reference, ImageType.BUILDPACK);\n\t\t\tBuildpackMetadata buildpackMetadata = BuildpackMetadata.fromImage(image);\n\t\t\tthis.coordinates = BuildpackCoordinates.fromBuildpackMetadata(buildpackMetadata);\n\t\t\tthis.exportedLayers = (!buildpackExistsInBuilder(context, image.getLayers()))\n\t\t\t\t\t? new ExportedLayers(context, reference) : null;\n\t\t}\n\t\tcatch (IOException | DockerEngineException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Error pulling buildpack image '\" + reference + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate boolean buildpackExistsInBuilder(BuildpackResolverContext context, List<LayerId> imageLayers) {\n\t\tBuildpackLayerDetails buildpackLayerDetails = context.getBuildpackLayersMetadata()\n\t\t\t.getBuildpack(this.coordinates.getId(), this.coordinates.getVersion());\n\t\tString layerDiffId = (buildpackLayerDetails != null) ? buildpackLayerDetails.getLayerDiffId() : null;\n\t\treturn (layerDiffId != null) && imageLayers.stream().map(LayerId::toString).anyMatch(layerDiffId::equals);\n\t}\n\n\t@Override\n\tpublic BuildpackCoordinates getCoordinates() {\n\t\treturn this.coordinates;\n\t}\n\n\t@Override\n\tpublic void apply(IOConsumer<Layer> layers) throws IOException {\n\t\tif (this.exportedLayers != null) {\n\t\t\tthis.exportedLayers.apply(layers);\n\t\t}\n\t}\n\n\t/**\n\t * A {@link BuildpackResolver} compatible method to resolve image buildpacks.\n\t * @param context the resolver context\n\t * @param reference the buildpack reference\n\t * @return the resolved {@link Buildpack} or {@code null}\n\t */\n\tstatic @Nullable Buildpack resolve(BuildpackResolverContext context, BuildpackReference reference) {\n\t\tboolean unambiguous = reference.hasPrefix(PREFIX);\n\t\ttry {\n\t\t\tImageReference imageReference;\n\t\t\tif (unambiguous) {\n\t\t\t\tString subReference = reference.getSubReference(PREFIX);\n\t\t\t\tAssert.state(subReference != null, \"'subReference' must not be null\");\n\t\t\t\timageReference = ImageReference.of(subReference);\n\t\t\t}\n\t\t\telse {\n\t\t\t\timageReference = ImageReference.of(reference.toString());\n\t\t\t}\n\t\t\treturn new ImageBuildpack(context, imageReference);\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\tif (unambiguous) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static class ExportedLayers {\n\n\t\tprivate final List<Path> layerFiles;\n\n\t\tExportedLayers(BuildpackResolverContext context, ImageReference imageReference) throws IOException {\n\t\t\tList<Path> layerFiles = new ArrayList<>();\n\t\t\tcontext.exportImageLayers(imageReference,\n\t\t\t\t\t(name, tarArchive) -> layerFiles.add(createLayerFile(tarArchive)));\n\t\t\tthis.layerFiles = Collections.unmodifiableList(layerFiles);\n\t\t}\n\n\t\tprivate Path createLayerFile(TarArchive tarArchive) throws IOException {\n\t\t\tPath sourceTarFile = Files.createTempFile(\"create-builder-scratch-source-\", null);\n\t\t\ttry (OutputStream out = Files.newOutputStream(sourceTarFile)) {\n\t\t\t\ttarArchive.writeTo(out);\n\t\t\t}\n\t\t\tPath layerFile = Files.createTempFile(\"create-builder-scratch-\", null);\n\t\t\ttry (TarArchiveOutputStream out = new TarArchiveOutputStream(Files.newOutputStream(layerFile))) {\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(Files.newInputStream(sourceTarFile))) {\n\t\t\t\t\tout.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tout.putArchiveEntry(entry);\n\t\t\t\t\t\tStreamUtils.copy(in, out);\n\t\t\t\t\t\tout.closeArchiveEntry();\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t\tout.finish();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn layerFile;\n\t\t}\n\n\t\tvoid apply(IOConsumer<Layer> layers) throws IOException {\n\t\t\tfor (Path path : this.layerFiles) {\n\t\t\t\tlayers.accept(Layer.fromTarArchive((out) -> {\n\t\t\t\t\tInputStream in = Files.newInputStream(path);\n\t\t\t\t\tStreamUtils.copy(in, out);\n\t\t\t\t}));\n\t\t\t\tFiles.delete(path);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ImageType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\n/**\n * Image types.\n *\n * @author Andrey Shlykov\n */\nenum ImageType {\n\n\t/**\n\t * Builder image.\n\t */\n\tBUILDER(\"builder image\"),\n\n\t/**\n\t * Run image.\n\t */\n\tRUNNER(\"run image\"),\n\n\t/**\n\t * Buildpack image.\n\t */\n\tBUILDPACK(\"buildpack image\");\n\n\tprivate final String description;\n\n\tImageType(String description) {\n\t\tthis.description = description;\n\t}\n\n\tString getDescription() {\n\t\treturn this.description;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Lifecycle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport com.sun.jna.Platform;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.build.Cache.Bind;\nimport org.springframework.boot.buildpack.platform.docker.ApiVersion;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerContent;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerReference;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileSystemUtils;\n\n/**\n * A buildpack lifecycle used to run the build {@link Phase phases} needed to package an\n * application.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n * @author Julian Liebig\n */\nclass Lifecycle implements Closeable {\n\n\tprivate static final LifecycleVersion LOGGING_MINIMUM_VERSION = LifecycleVersion.parse(\"0.0.5\");\n\n\tprivate static final String PLATFORM_API_VERSION_KEY = \"CNB_PLATFORM_API\";\n\n\tprivate static final String SOURCE_DATE_EPOCH_KEY = \"SOURCE_DATE_EPOCH\";\n\n\tprivate static final String DOMAIN_SOCKET_PATH = \"/var/run/docker.sock\";\n\n\tprivate static final List<String> DEFAULT_SECURITY_OPTIONS = List.of(\"label=disable\");\n\n\tprivate final BuildLog log;\n\n\tprivate final DockerApi docker;\n\n\tprivate final @Nullable ResolvedDockerHost dockerHost;\n\n\tprivate final BuildRequest request;\n\n\tprivate final EphemeralBuilder builder;\n\n\tprivate final LifecycleVersion lifecycleVersion;\n\n\tprivate final ApiVersion platformVersion;\n\n\tprivate final Cache layers;\n\n\tprivate final Cache application;\n\n\tprivate final Cache buildCache;\n\n\tprivate final Cache launchCache;\n\n\tprivate final String applicationDirectory;\n\n\tprivate final List<String> securityOptions;\n\n\tprivate boolean executed;\n\n\tprivate boolean applicationVolumePopulated;\n\n\t/**\n\t * Create a new {@link Lifecycle} instance.\n\t * @param log build output log\n\t * @param docker the Docker API\n\t * @param dockerHost the Docker host information\n\t * @param request the request to process\n\t * @param builder the ephemeral builder used to run the phases\n\t */\n\tLifecycle(BuildLog log, DockerApi docker, @Nullable ResolvedDockerHost dockerHost, BuildRequest request,\n\t\t\tEphemeralBuilder builder) {\n\t\tthis.log = log;\n\t\tthis.docker = docker;\n\t\tthis.dockerHost = dockerHost;\n\t\tthis.request = request;\n\t\tthis.builder = builder;\n\t\tthis.lifecycleVersion = LifecycleVersion.parse(builder.getBuilderMetadata().getLifecycle().getVersion());\n\t\tthis.platformVersion = getPlatformVersion(builder.getBuilderMetadata().getLifecycle());\n\t\tthis.layers = getLayersBindingSource(request);\n\t\tthis.application = getApplicationBindingSource(request);\n\t\tthis.buildCache = getBuildCache(request);\n\t\tthis.launchCache = getLaunchCache(request);\n\t\tthis.applicationDirectory = getApplicationDirectory(request);\n\t\tthis.securityOptions = getSecurityOptions(request);\n\t}\n\n\tString getApplicationDirectory() {\n\t\treturn this.applicationDirectory;\n\t}\n\n\tprivate Cache getBuildCache(BuildRequest request) {\n\t\tif (request.getBuildCache() != null) {\n\t\t\treturn request.getBuildCache();\n\t\t}\n\t\treturn createVolumeCache(request, \"build\");\n\t}\n\n\tprivate Cache getLaunchCache(BuildRequest request) {\n\t\tif (request.getLaunchCache() != null) {\n\t\t\treturn request.getLaunchCache();\n\t\t}\n\t\treturn createVolumeCache(request, \"launch\");\n\t}\n\n\tprivate String getApplicationDirectory(BuildRequest request) {\n\t\treturn (request.getApplicationDirectory() != null) ? request.getApplicationDirectory() : Directory.APPLICATION;\n\t}\n\n\tprivate List<String> getSecurityOptions(BuildRequest request) {\n\t\tif (request.getSecurityOptions() != null) {\n\t\t\treturn request.getSecurityOptions();\n\t\t}\n\t\treturn (Platform.isWindows()) ? Collections.emptyList() : DEFAULT_SECURITY_OPTIONS;\n\t}\n\n\tprivate ApiVersion getPlatformVersion(BuilderMetadata.Lifecycle lifecycle) {\n\t\tif (lifecycle.getApis().getPlatform() != null) {\n\t\t\tString[] supportedVersions = lifecycle.getApis().getPlatform();\n\t\t\treturn ApiVersions.SUPPORTED_PLATFORMS.findLatestSupported(supportedVersions);\n\t\t}\n\t\tString version = lifecycle.getApi().getPlatform();\n\t\treturn ApiVersions.SUPPORTED_PLATFORMS.findLatestSupported(version);\n\t}\n\n\t/**\n\t * Execute this lifecycle by running each phase in turn.\n\t * @throws IOException on IO error\n\t */\n\tvoid execute() throws IOException {\n\t\tAssert.state(!this.executed, \"Lifecycle has already been executed\");\n\t\tthis.executed = true;\n\t\tthis.log.executingLifecycle(this.request, this.lifecycleVersion, this.buildCache);\n\t\tif (this.request.isCleanCache()) {\n\t\t\tdeleteCache(this.buildCache);\n\t\t}\n\t\tif (this.request.isTrustBuilder()) {\n\t\t\trun(createPhase());\n\t\t}\n\t\telse {\n\t\t\trun(analyzePhase());\n\t\t\trun(detectPhase());\n\t\t\tif (!this.request.isCleanCache()) {\n\t\t\t\trun(restorePhase());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.log.skippingPhase(\"restorer\", \"because 'cleanCache' is enabled\");\n\t\t\t}\n\t\t\trun(buildPhase());\n\t\t\trun(exportPhase());\n\t\t}\n\t\tthis.log.executedLifecycle(this.request);\n\t}\n\n\tprivate Phase createPhase() {\n\t\tPhase phase = new Phase(\"creator\", isVerboseLogging());\n\t\tphase.withApp(this.applicationDirectory,\n\t\t\t\tBinding.from(getCacheBindingSource(this.application), this.applicationDirectory));\n\t\tphase.withPlatform(Directory.PLATFORM);\n\t\tImageReference runImage = this.request.getRunImage();\n\t\tAssert.state(runImage != null, \"'runImage' must not be null\");\n\t\tphase.withRunImage(runImage);\n\t\tphase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));\n\t\tphase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE));\n\t\tphase.withLaunchCache(Directory.LAUNCH_CACHE,\n\t\t\t\tBinding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE));\n\t\tconfigureDaemonAccess(phase);\n\t\tif (this.request.isCleanCache()) {\n\t\t\tphase.withSkipRestore();\n\t\t}\n\t\tif (requiresProcessTypeDefault()) {\n\t\t\tphase.withProcessType(\"web\");\n\t\t}\n\t\tphase.withImageName(this.request.getName());\n\t\tconfigureOptions(phase);\n\t\tconfigureCreatedDate(phase);\n\t\treturn phase;\n\n\t}\n\n\tprivate Phase analyzePhase() {\n\t\tPhase phase = new Phase(\"analyzer\", isVerboseLogging());\n\t\tconfigureDaemonAccess(phase);\n\t\tphase.withLaunchCache(Directory.LAUNCH_CACHE,\n\t\t\t\tBinding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE));\n\t\tphase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));\n\t\tImageReference runImage = this.request.getRunImage();\n\t\tAssert.state(runImage != null, \"'runImage' must not be null\");\n\t\tphase.withRunImage(runImage);\n\t\tphase.withImageName(this.request.getName());\n\t\tconfigureOptions(phase);\n\t\treturn phase;\n\t}\n\n\tprivate Phase detectPhase() {\n\t\tPhase phase = new Phase(\"detector\", isVerboseLogging());\n\t\tphase.withApp(this.applicationDirectory,\n\t\t\t\tBinding.from(getCacheBindingSource(this.application), this.applicationDirectory));\n\t\tphase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));\n\t\tphase.withPlatform(Directory.PLATFORM);\n\t\tconfigureOptions(phase);\n\t\treturn phase;\n\t}\n\n\tprivate Phase restorePhase() {\n\t\tPhase phase = new Phase(\"restorer\", isVerboseLogging());\n\t\tconfigureDaemonAccess(phase);\n\t\tphase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE));\n\t\tphase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));\n\t\tconfigureOptions(phase);\n\t\treturn phase;\n\t}\n\n\tprivate Phase buildPhase() {\n\t\tPhase phase = new Phase(\"builder\", isVerboseLogging());\n\t\tphase.withApp(this.applicationDirectory,\n\t\t\t\tBinding.from(getCacheBindingSource(this.application), this.applicationDirectory));\n\t\tphase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));\n\t\tphase.withPlatform(Directory.PLATFORM);\n\t\tconfigureOptions(phase);\n\t\treturn phase;\n\t}\n\n\tprivate Phase exportPhase() {\n\t\tPhase phase = new Phase(\"exporter\", isVerboseLogging());\n\t\tconfigureDaemonAccess(phase);\n\t\tphase.withApp(this.applicationDirectory,\n\t\t\t\tBinding.from(getCacheBindingSource(this.application), this.applicationDirectory));\n\t\tphase.withBuildCache(Directory.CACHE, Binding.from(getCacheBindingSource(this.buildCache), Directory.CACHE));\n\t\tphase.withLaunchCache(Directory.LAUNCH_CACHE,\n\t\t\t\tBinding.from(getCacheBindingSource(this.launchCache), Directory.LAUNCH_CACHE));\n\t\tphase.withLayers(Directory.LAYERS, Binding.from(getCacheBindingSource(this.layers), Directory.LAYERS));\n\t\tif (requiresProcessTypeDefault()) {\n\t\t\tphase.withProcessType(\"web\");\n\t\t}\n\t\tphase.withImageName(this.request.getName());\n\t\tconfigureOptions(phase);\n\t\tconfigureCreatedDate(phase);\n\t\treturn phase;\n\t}\n\n\tprivate Cache getLayersBindingSource(BuildRequest request) {\n\t\tif (request.getBuildWorkspace() != null) {\n\t\t\treturn getBuildWorkspaceBindingSource(request.getBuildWorkspace(), \"layers\");\n\t\t}\n\t\treturn createVolumeCache(\"pack-layers-\");\n\t}\n\n\tprivate Cache getApplicationBindingSource(BuildRequest request) {\n\t\tif (request.getBuildWorkspace() != null) {\n\t\t\treturn getBuildWorkspaceBindingSource(request.getBuildWorkspace(), \"app\");\n\t\t}\n\t\treturn createVolumeCache(\"pack-app-\");\n\t}\n\n\tprivate Cache getBuildWorkspaceBindingSource(Cache buildWorkspace, String suffix) {\n\t\tif (buildWorkspace.getVolume() != null) {\n\t\t\treturn Cache.volume(buildWorkspace.getVolume().getName() + \"-\" + suffix);\n\t\t}\n\n\t\tBind bind = buildWorkspace.getBind();\n\t\tAssert.state(bind != null, \"'bind' must not be null\");\n\t\treturn Cache.bind(bind.getSource() + \"-\" + suffix);\n\t}\n\n\tprivate String getCacheBindingSource(Cache cache) {\n\t\tif (cache.getVolume() != null) {\n\t\t\treturn cache.getVolume().getName();\n\t\t}\n\t\tBind bind = cache.getBind();\n\t\tAssert.state(bind != null, \"'bind' must not be null\");\n\t\treturn bind.getSource();\n\t}\n\n\tprivate Cache createVolumeCache(String prefix) {\n\t\treturn Cache.volume(createRandomVolumeName(prefix));\n\t}\n\n\tprivate Cache createVolumeCache(BuildRequest request, String suffix) {\n\t\treturn Cache.volume(\n\t\t\t\tVolumeName.basedOn(request.getName(), ImageReference::toLegacyString, \"pack-cache-\", \".\" + suffix, 6));\n\t}\n\n\tprotected VolumeName createRandomVolumeName(String prefix) {\n\t\treturn VolumeName.random(prefix);\n\t}\n\n\tprivate void configureDaemonAccess(Phase phase) {\n\t\tphase.withDaemonAccess();\n\t\tif (this.dockerHost != null) {\n\t\t\tif (this.dockerHost.isRemote()) {\n\t\t\t\tphase.withEnv(\"DOCKER_HOST\", this.dockerHost.getAddress());\n\t\t\t\tif (this.dockerHost.isSecure()) {\n\t\t\t\t\tphase.withEnv(\"DOCKER_TLS_VERIFY\", \"1\");\n\t\t\t\t\tif (this.dockerHost.getCertificatePath() != null) {\n\t\t\t\t\t\tphase.withEnv(\"DOCKER_CERT_PATH\", this.dockerHost.getCertificatePath());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tphase.withBinding(Binding.from(this.dockerHost.getAddress(), DOMAIN_SOCKET_PATH));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tphase.withBinding(Binding.from(DOMAIN_SOCKET_PATH, DOMAIN_SOCKET_PATH));\n\t\t}\n\t\tif (this.securityOptions != null) {\n\t\t\tthis.securityOptions.forEach(phase::withSecurityOption);\n\t\t}\n\t}\n\n\tprivate void configureCreatedDate(Phase phase) {\n\t\tif (this.request.getCreatedDate() != null) {\n\t\t\tphase.withEnv(SOURCE_DATE_EPOCH_KEY, Long.toString(this.request.getCreatedDate().getEpochSecond()));\n\t\t}\n\t}\n\n\tprivate void configureOptions(Phase phase) {\n\t\tif (this.request.getBindings() != null) {\n\t\t\tthis.request.getBindings().forEach(phase::withBinding);\n\t\t}\n\t\tif (this.request.getNetwork() != null) {\n\t\t\tphase.withNetworkMode(this.request.getNetwork());\n\t\t}\n\t\tphase.withEnv(PLATFORM_API_VERSION_KEY, this.platformVersion.toString());\n\t}\n\n\tprivate boolean isVerboseLogging() {\n\t\treturn this.request.isVerboseLogging() && this.lifecycleVersion.isEqualOrGreaterThan(LOGGING_MINIMUM_VERSION);\n\t}\n\n\tprivate boolean requiresProcessTypeDefault() {\n\t\treturn this.platformVersion.supportsAny(ApiVersion.of(0, 4), ApiVersion.of(0, 5));\n\t}\n\n\tprivate void run(Phase phase) throws IOException {\n\t\tConsumer<LogUpdateEvent> logConsumer = this.log.runningPhase(this.request, phase.getName());\n\t\tContainerConfig containerConfig = ContainerConfig.of(this.builder.getName(), phase::apply);\n\t\tContainerReference reference = createContainer(containerConfig, phase.requiresApp());\n\t\ttry {\n\t\t\tthis.docker.container().start(reference);\n\t\t\tthis.docker.container().logs(reference, logConsumer::accept);\n\t\t\tContainerStatus status = this.docker.container().wait(reference);\n\t\t\tif (status.getStatusCode() != 0) {\n\t\t\t\tthrow new BuilderException(phase.getName(), status.getStatusCode());\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tthis.docker.container().remove(reference, true);\n\t\t}\n\t}\n\n\tprivate ContainerReference createContainer(ContainerConfig config, boolean requiresAppUpload) throws IOException {\n\t\tif (!requiresAppUpload || this.applicationVolumePopulated) {\n\t\t\treturn this.docker.container().create(config, this.request.getImagePlatform());\n\t\t}\n\t\ttry {\n\t\t\tif (this.application.getBind() != null) {\n\t\t\t\tFiles.createDirectories(Path.of(this.application.getBind().getSource()));\n\t\t\t}\n\t\t\tTarArchive applicationContent = this.request.getApplicationContent(this.builder.getBuildOwner());\n\t\t\treturn this.docker.container()\n\t\t\t\t.create(config, this.request.getImagePlatform(),\n\t\t\t\t\t\tContainerContent.of(applicationContent, this.applicationDirectory));\n\t\t}\n\t\tfinally {\n\t\t\tthis.applicationVolumePopulated = true;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tdeleteCache(this.layers);\n\t\tdeleteCache(this.application);\n\t}\n\n\tprivate void deleteCache(Cache cache) throws IOException {\n\t\tif (cache.getVolume() != null) {\n\t\t\tdeleteVolume(cache.getVolume().getVolumeName());\n\t\t}\n\t\tif (cache.getBind() != null) {\n\t\t\tdeleteBind(cache.getBind());\n\t\t}\n\t}\n\n\tprivate void deleteVolume(VolumeName name) throws IOException {\n\t\tthis.docker.volume().delete(name, true);\n\t}\n\n\tprivate void deleteBind(Cache.Bind bind) {\n\t\ttry {\n\t\t\tFileSystemUtils.deleteRecursively(Path.of(bind.getSource()));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.log.failedCleaningWorkDir(bind, ex);\n\t\t}\n\t}\n\n\t/**\n\t * Common directories used by the various phases.\n\t */\n\tprivate static final class Directory {\n\n\t\t/**\n\t\t * The directory used by buildpacks to write their layer contributions. A new\n\t\t * layer directory is created for each lifecycle execution.\n\t\t * <p>\n\t\t * Maps to the {@code <layers...>} concept in the\n\t\t * <a href=\"https://github.com/buildpacks/spec/blob/master/buildpack.md\">buildpack\n\t\t * specification</a> and the {@code -layers} argument to lifecycle phases.\n\t\t */\n\t\tstatic final String LAYERS = \"/layers\";\n\n\t\t/**\n\t\t * The directory containing the original contributed application. A new\n\t\t * application directory is created for each lifecycle execution.\n\t\t * <p>\n\t\t * Maps to the {@code <app...>} concept in the\n\t\t * <a href=\"https://github.com/buildpacks/spec/blob/master/buildpack.md\">buildpack\n\t\t * specification</a> and the {@code -app} argument from the reference lifecycle\n\t\t * implementation. The reference lifecycle follows the Kubernetes/Docker\n\t\t * convention of using {@code '/workspace'}.\n\t\t * <p>\n\t\t * Note that application content is uploaded to the container with the first phase\n\t\t * that runs and saved in a volume that is passed to subsequent phases. The\n\t\t * directory is mutable and buildpacks may modify the content.\n\t\t */\n\t\tstatic final String APPLICATION = \"/workspace\";\n\n\t\t/**\n\t\t * The directory used by buildpacks to obtain environment variables and platform\n\t\t * specific concerns. The platform directory is read-only and is created/populated\n\t\t * by the {@link EphemeralBuilder}.\n\t\t * <p>\n\t\t * Maps to the {@code <platform>/env} and {@code <platform>/#} concepts in the\n\t\t * <a href=\"https://github.com/buildpacks/spec/blob/master/buildpack.md\">buildpack\n\t\t * specification</a> and the {@code -platform} argument to lifecycle phases.\n\t\t */\n\t\tstatic final String PLATFORM = \"/platform\";\n\n\t\t/**\n\t\t * The directory used by buildpacks for caching. The volume name is based on the\n\t\t * image {@link BuildRequest#getName() name} being built, and is persistent across\n\t\t * invocations even if the application content has changed.\n\t\t * <p>\n\t\t * Maps to the {@code -path} argument to lifecycle phases.\n\t\t */\n\t\tstatic final String CACHE = \"/cache\";\n\n\t\t/**\n\t\t * The directory used by buildpacks for launch related caching. The volume name is\n\t\t * based on the image {@link BuildRequest#getName() name} being built, and is\n\t\t * persistent across invocations even if the application content has changed.\n\t\t * <p>\n\t\t * Maps to the {@code -launch-cache} argument to lifecycle phases.\n\t\t */\n\t\tstatic final String LAUNCH_CACHE = \"/launch-cache\";\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/LifecycleVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.Comparator;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A lifecycle version number comprised of a major, minor and patch value.\n *\n * @author Phillip Webb\n */\nclass LifecycleVersion implements Comparable<LifecycleVersion> {\n\n\tprivate static final Comparator<LifecycleVersion> COMPARATOR = Comparator.comparingInt(LifecycleVersion::getMajor)\n\t\t.thenComparingInt(LifecycleVersion::getMinor)\n\t\t.thenComparing(LifecycleVersion::getPatch);\n\n\tprivate final int major;\n\n\tprivate final int minor;\n\n\tprivate final int patch;\n\n\tLifecycleVersion(int major, int minor, int patch) {\n\t\tthis.major = major;\n\t\tthis.minor = minor;\n\t\tthis.patch = patch;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tLifecycleVersion other = (LifecycleVersion) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.major == other.major;\n\t\tresult = result && this.minor == other.minor;\n\t\tresult = result && this.patch == other.patch;\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.major;\n\t\tresult = prime * result + this.minor;\n\t\tresult = prime * result + this.patch;\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"v\" + this.major + \".\" + this.minor + \".\" + this.patch;\n\t}\n\n\t/**\n\t * Return if this version is greater than or equal to the specified version.\n\t * @param other the version to compare\n\t * @return {@code true} if this version is greater than or equal to the specified\n\t * version\n\t */\n\tboolean isEqualOrGreaterThan(LifecycleVersion other) {\n\t\treturn compareTo(other) >= 0;\n\t}\n\n\t@Override\n\tpublic int compareTo(LifecycleVersion other) {\n\t\treturn COMPARATOR.compare(this, other);\n\t}\n\n\t/**\n\t * Return the major version number.\n\t * @return the major version\n\t */\n\tint getMajor() {\n\t\treturn this.major;\n\t}\n\n\t/**\n\t * Return the minor version number.\n\t * @return the minor version\n\t */\n\tint getMinor() {\n\t\treturn this.minor;\n\t}\n\n\t/**\n\t * Return the patch version number.\n\t * @return the patch version\n\t */\n\tint getPatch() {\n\t\treturn this.patch;\n\t}\n\n\t/**\n\t * Factory method to parse a string into a {@link LifecycleVersion} instance.\n\t * @param value the value to parse.\n\t * @return the corresponding {@link LifecycleVersion}\n\t * @throws IllegalArgumentException if the value could not be parsed\n\t */\n\tstatic LifecycleVersion parse(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tString withoutPrefix = (value.startsWith(\"v\") || value.startsWith(\"V\")) ? value.substring(1) : value;\n\t\tString[] components = withoutPrefix.split(\"\\\\.\");\n\t\tAssert.isTrue(components.length <= 3, () -> \"'value' [%s] must be a valid version number\".formatted(value));\n\t\tint[] versions = new int[3];\n\t\tfor (int i = 0; i < components.length; i++) {\n\t\t\ttry {\n\t\t\t\tversions[i] = Integer.parseInt(components[i]);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"'value' [\" + value + \"] must be a valid version number\", ex);\n\t\t\t}\n\t\t}\n\t\treturn new LifecycleVersion(versions[0], versions[1], versions[2]);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/Phase.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.util.StringUtils;\n\n/**\n * An individual build phase executed as part of a {@link Lifecycle} run.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n */\nclass Phase {\n\n\tprivate final String name;\n\n\tprivate boolean daemonAccess;\n\n\tprivate final List<String> args = new ArrayList<>();\n\n\tprivate final List<Binding> bindings = new ArrayList<>();\n\n\tprivate final Map<String, String> env = new LinkedHashMap<>();\n\n\tprivate final List<String> securityOptions = new ArrayList<>();\n\n\tprivate @Nullable String networkMode;\n\n\tprivate boolean requiresApp;\n\n\t/**\n\t * Create a new {@link Phase} instance.\n\t * @param name the name of the phase\n\t * @param verboseLogging if verbose logging is requested\n\t */\n\tPhase(String name, boolean verboseLogging) {\n\t\tthis.name = name;\n\t\twithLogLevelArg(verboseLogging);\n\t}\n\n\tvoid withApp(String path, Binding binding) {\n\t\twithArgs(\"-app\", path);\n\t\twithBinding(binding);\n\t\tthis.requiresApp = true;\n\t}\n\n\tvoid withBuildCache(String path, Binding binding) {\n\t\twithArgs(\"-cache-dir\", path);\n\t\twithBinding(binding);\n\t}\n\n\t/**\n\t * Update this phase with Docker daemon access.\n\t */\n\tvoid withDaemonAccess() {\n\t\tthis.withArgs(\"-daemon\");\n\t\tthis.daemonAccess = true;\n\t}\n\n\tvoid withImageName(ImageReference imageName) {\n\t\twithArgs(imageName);\n\t}\n\n\tvoid withLaunchCache(String path, Binding binding) {\n\t\twithArgs(\"-launch-cache\", path);\n\t\twithBinding(binding);\n\t}\n\n\tvoid withLayers(String path, Binding binding) {\n\t\twithArgs(\"-layers\", path);\n\t\twithBinding(binding);\n\t}\n\n\tvoid withPlatform(String path) {\n\t\twithArgs(\"-platform\", path);\n\t}\n\n\tvoid withProcessType(String type) {\n\t\twithArgs(\"-process-type\", type);\n\t}\n\n\tvoid withRunImage(ImageReference runImage) {\n\t\twithArgs(\"-run-image\", runImage);\n\t}\n\n\tvoid withSkipRestore() {\n\t\twithArgs(\"-skip-restore\");\n\t}\n\n\t/**\n\t * Update this phase with a debug log level arguments if verbose logging has been\n\t * requested.\n\t * @param verboseLogging if verbose logging is requested\n\t */\n\tprivate void withLogLevelArg(boolean verboseLogging) {\n\t\tif (verboseLogging) {\n\t\t\tthis.args.add(\"-log-level\");\n\t\t\tthis.args.add(\"debug\");\n\t\t}\n\t}\n\n\t/**\n\t * Update this phase with additional run arguments.\n\t * @param args the arguments to add\n\t */\n\tvoid withArgs(Object... args) {\n\t\tArrays.stream(args).map(Object::toString).forEach(this.args::add);\n\t}\n\n\t/**\n\t * Update this phase with an addition volume binding.\n\t * @param binding the binding\n\t */\n\tvoid withBinding(Binding binding) {\n\t\tthis.bindings.add(binding);\n\t}\n\n\t/**\n\t * Update this phase with an additional environment variable.\n\t * @param name the variable name\n\t * @param value the variable value\n\t */\n\tvoid withEnv(String name, String value) {\n\t\tthis.env.put(name, value);\n\t}\n\n\t/**\n\t * Update this phase with the network the build container will connect to.\n\t * @param networkMode the network\n\t */\n\tvoid withNetworkMode(@Nullable String networkMode) {\n\t\tthis.networkMode = networkMode;\n\t}\n\n\t/**\n\t * Update this phase with a security option.\n\t * @param option the security option\n\t */\n\tvoid withSecurityOption(String option) {\n\t\tthis.securityOptions.add(option);\n\t}\n\n\t/**\n\t * Return the name of the phase.\n\t * @return the phase name\n\t */\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\tboolean requiresApp() {\n\t\treturn this.requiresApp;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Apply this phase settings to a {@link ContainerConfig} update.\n\t * @param update the update to apply the phase to\n\t */\n\tvoid apply(ContainerConfig.Update update) {\n\t\tif (this.daemonAccess) {\n\t\t\tupdate.withUser(\"root\");\n\t\t}\n\t\tupdate.withCommand(\"/cnb/lifecycle/\" + this.name, StringUtils.toStringArray(this.args));\n\t\tupdate.withLabel(\"author\", \"spring-boot\");\n\t\tthis.bindings.forEach(update::withBinding);\n\t\tthis.env.forEach(update::withEnv);\n\t\tif (this.networkMode != null) {\n\t\t\tupdate.withNetworkMode(this.networkMode);\n\t\t}\n\t\tthis.securityOptions.forEach(update::withSecurityOption);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/PrintStreamBuildLog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.PrintStream;\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressBar;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;\n\n/**\n * {@link BuildLog} implementation that prints output to a {@link PrintStream}.\n *\n * @author Phillip Webb\n * @see BuildLog#to(PrintStream)\n */\nclass PrintStreamBuildLog extends AbstractBuildLog {\n\n\tprivate final PrintStream out;\n\n\tPrintStreamBuildLog(PrintStream out) {\n\t\tthis.out = out;\n\t}\n\n\t@Override\n\tprotected void log(String message) {\n\t\tthis.out.println(message);\n\t}\n\n\t@Override\n\tprotected Consumer<TotalProgressEvent> getProgressConsumer(String prefix) {\n\t\treturn new TotalProgressBar(prefix, '.', false, this.out);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/PullPolicy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\n/**\n * Image pull policy.\n *\n * @author Andrey Shlykov\n * @since 2.4.0\n */\npublic enum PullPolicy {\n\n\t/**\n\t * Always pull the image from the registry.\n\t */\n\tALWAYS,\n\n\t/**\n\t * Never pull the image from the registry.\n\t */\n\tNEVER,\n\n\t/**\n\t * Pull the image from the registry only if it does not exist locally.\n\t */\n\tIF_NOT_PRESENT\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/StackId.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.util.Assert;\n\n/**\n * A Stack ID.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass StackId {\n\n\tprivate static final String LABEL_NAME = \"io.buildpacks.stack.id\";\n\n\tprivate final @Nullable String value;\n\n\tStackId(@Nullable String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn Objects.equals(this.value, ((StackId) obj).value);\n\t}\n\n\tboolean hasId() {\n\t\treturn this.value != null;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hashCode(this.value);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.value != null) ? this.value : \"<null>\";\n\t}\n\n\t/**\n\t * Factory method to create a {@link StackId} from an {@link Image}.\n\t * @param image the source image\n\t * @return the extracted stack ID\n\t */\n\tstatic StackId fromImage(Image image) {\n\t\tAssert.notNull(image, \"'image' must not be null\");\n\t\treturn fromImageConfig(image.getConfig());\n\t}\n\n\t/**\n\t * Factory method to create a {@link StackId} from an {@link ImageConfig}.\n\t * @param imageConfig the source image config\n\t * @return the extracted stack ID\n\t */\n\tprivate static StackId fromImageConfig(ImageConfig imageConfig) {\n\t\tString value = imageConfig.getLabels().get(LABEL_NAME);\n\t\treturn new StackId(value);\n\t}\n\n\t/**\n\t * Factory method to create a {@link StackId} with a given value.\n\t * @param value the stack ID value\n\t * @return a new stack ID instance\n\t */\n\tstatic StackId of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\treturn new StackId(value);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/TarGzipBuildpack.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.util.StreamUtils;\n\n/**\n * A {@link Buildpack} that references a buildpack contained in a local gzipped tar\n * archive file.\n *\n * The archive must contain a buildpack descriptor named {@code buildpack.toml} at the\n * root of the archive. The contents of the archive will be provided as a single layer to\n * be included in the builder image.\n *\n * @author Scott Frederick\n */\nfinal class TarGzipBuildpack implements Buildpack {\n\n\tprivate final Path path;\n\n\tprivate final BuildpackCoordinates coordinates;\n\n\tprivate TarGzipBuildpack(Path path) {\n\t\tthis.path = path;\n\t\tthis.coordinates = findBuildpackCoordinates(path);\n\t}\n\n\tprivate BuildpackCoordinates findBuildpackCoordinates(Path path) {\n\t\ttry {\n\t\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(\n\t\t\t\t\tnew GzipCompressorInputStream(Files.newInputStream(path)))) {\n\t\t\t\tArchiveEntry entry = tar.getNextEntry();\n\t\t\t\twhile (entry != null) {\n\t\t\t\t\tif (\"buildpack.toml\".equals(entry.getName())) {\n\t\t\t\t\t\treturn BuildpackCoordinates.fromToml(tar, path);\n\t\t\t\t\t}\n\t\t\t\t\tentry = tar.getNextEntry();\n\t\t\t\t}\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Buildpack descriptor 'buildpack.toml' is required in buildpack '\" + path + \"'\");\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(\"Error parsing descriptor for buildpack '\" + path + \"'\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic BuildpackCoordinates getCoordinates() {\n\t\treturn this.coordinates;\n\t}\n\n\t@Override\n\tpublic void apply(IOConsumer<Layer> layers) throws IOException {\n\t\tlayers.accept(Layer.fromTarArchive(this::copyAndRebaseEntries));\n\t}\n\n\tprivate void copyAndRebaseEntries(OutputStream outputStream) throws IOException {\n\t\tString id = this.coordinates.getSanitizedId();\n\t\tPath basePath = Paths.get(\"/cnb/buildpacks/\", id, this.coordinates.getVersion());\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(\n\t\t\t\tnew GzipCompressorInputStream(Files.newInputStream(this.path)));\n\t\t\t\tTarArchiveOutputStream output = new TarArchiveOutputStream(outputStream)) {\n\t\t\twriteBasePathEntries(output, basePath);\n\t\t\tTarArchiveEntry entry = tar.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tentry.setName(basePath + \"/\" + entry.getName());\n\t\t\t\toutput.putArchiveEntry(entry);\n\t\t\t\tStreamUtils.copy(tar, output);\n\t\t\t\toutput.closeArchiveEntry();\n\t\t\t\tentry = tar.getNextEntry();\n\t\t\t}\n\t\t\toutput.finish();\n\t\t}\n\t}\n\n\tprivate void writeBasePathEntries(TarArchiveOutputStream output, Path basePath) throws IOException {\n\t\tint pathCount = basePath.getNameCount();\n\t\tfor (int pathIndex = 1; pathIndex < pathCount + 1; pathIndex++) {\n\t\t\tString name = \"/\" + basePath.subpath(0, pathIndex) + \"/\";\n\t\t\tTarArchiveEntry entry = new TarArchiveEntry(name);\n\t\t\toutput.putArchiveEntry(entry);\n\t\t\toutput.closeArchiveEntry();\n\t\t}\n\t}\n\n\t/**\n\t * A {@link BuildpackResolver} compatible method to resolve tar-gzip buildpacks.\n\t * @param context the resolver context\n\t * @param reference the buildpack reference\n\t * @return the resolved {@link Buildpack} or {@code null}\n\t */\n\tstatic @Nullable Buildpack resolve(BuildpackResolverContext context, BuildpackReference reference) {\n\t\tPath path = reference.asPath();\n\t\tif (path != null && Files.exists(path) && Files.isRegularFile(path)) {\n\t\t\treturn new TarGzipBuildpack(path);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Central API for performing a buildpack build.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ApiVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.Comparator;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * API Version number comprised of a major and minor value.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic final class ApiVersion implements Comparable<ApiVersion> {\n\n\tprivate static final Pattern PATTERN = Pattern.compile(\"^v?(\\\\d+)\\\\.(\\\\d*)$\");\n\n\tprivate static final Comparator<ApiVersion> COMPARATOR = Comparator.comparing(ApiVersion::getMajor)\n\t\t.thenComparing(ApiVersion::getMinor);\n\n\tprivate final int major;\n\n\tprivate final int minor;\n\n\tprivate ApiVersion(int major, int minor) {\n\t\tthis.major = major;\n\t\tthis.minor = minor;\n\t}\n\n\t/**\n\t * Return the major version number.\n\t * @return the major version\n\t */\n\tint getMajor() {\n\t\treturn this.major;\n\t}\n\n\t/**\n\t * Return the minor version number.\n\t * @return the minor version\n\t */\n\tint getMinor() {\n\t\treturn this.minor;\n\t}\n\n\t/**\n\t * Returns if this API version supports the given version. A {@code 0.x} matches only\n\t * the same version number. A 1.x or higher release matches when the versions have the\n\t * same major version and a minor that is equal or greater.\n\t * @param other the version to check against\n\t * @return if the specified API version is supported\n\t */\n\tpublic boolean supports(ApiVersion other) {\n\t\tif (equals(other)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (this.major == 0 || this.major != other.major) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.minor >= other.minor;\n\t}\n\n\t/**\n\t * Returns if this API version supports any of the given versions.\n\t * @param others the versions to check against\n\t * @return if any of the specified API versions are supported\n\t * @see #supports(ApiVersion)\n\t */\n\tpublic boolean supportsAny(ApiVersion... others) {\n\t\tfor (ApiVersion other : others) {\n\t\t\tif (supports(other)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tApiVersion other = (ApiVersion) obj;\n\t\treturn (this.major == other.major) && (this.minor == other.minor);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.major * 31 + this.minor;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.major + \".\" + this.minor;\n\t}\n\n\t/**\n\t * Factory method to parse a string into an {@link ApiVersion} instance.\n\t * @param value the value to parse.\n\t * @return the corresponding {@link ApiVersion}\n\t * @throws IllegalArgumentException if the value could not be parsed\n\t */\n\tpublic static ApiVersion parse(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tMatcher matcher = PATTERN.matcher(value);\n\t\tAssert.isTrue(matcher.matches(),\n\t\t\t\t() -> \"'value' [%s] must contain a well formed version number\".formatted(value));\n\t\ttry {\n\t\t\tint major = Integer.parseInt(matcher.group(1));\n\t\t\tint minor = Integer.parseInt(matcher.group(2));\n\t\t\treturn new ApiVersion(major, minor);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\tthrow new IllegalArgumentException(\"'value' must contain a well formed version number [\" + value + \"]\", ex);\n\t\t}\n\t}\n\n\tpublic static ApiVersion of(int major, int minor) {\n\t\treturn new ApiVersion(major, minor);\n\t}\n\n\t@Override\n\tpublic int compareTo(ApiVersion other) {\n\t\treturn COMPARATOR.compare(this, other);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerApi.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.net.URIBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.PushImageUpdateEvent.ErrorDetail;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;\nimport org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerContent;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerReference;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.boot.buildpack.platform.io.IOBiConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.buildpack.platform.json.JsonStream;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provides access to the limited set of Docker APIs needed by pack.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Rafael Ceccone\n * @author Moritz Halbritter\n * @since 2.3.0\n */\npublic class DockerApi {\n\n\tprivate static final List<String> FORCE_PARAMS = Collections.unmodifiableList(Arrays.asList(\"force\", \"1\"));\n\n\tstatic final ApiVersion UNKNOWN_API_VERSION = ApiVersion.of(0, 0);\n\n\tstatic final ApiVersion PREFERRED_API_VERSION = ApiVersion.of(1, 50);\n\n\tstatic final String API_VERSION_HEADER_NAME = \"API-Version\";\n\n\tprivate final HttpTransport http;\n\n\tprivate final JsonStream jsonStream;\n\n\tprivate final ImageApi image;\n\n\tprivate final ContainerApi container;\n\n\tprivate final VolumeApi volume;\n\n\tprivate final SystemApi system;\n\n\tprivate volatile @Nullable ApiVersion apiVersion;\n\n\t/**\n\t * Create a new {@link DockerApi} instance.\n\t */\n\tpublic DockerApi() {\n\t\tthis(HttpTransport.create((DockerConnectionConfiguration) null), DockerLog.toSystemOut());\n\t}\n\n\t/**\n\t * Create a new {@link DockerApi} instance.\n\t * @param connectionConfiguration the connection configuration to use\n\t * @param log a logger used to record output\n\t * @since 3.5.0\n\t */\n\tpublic DockerApi(@Nullable DockerConnectionConfiguration connectionConfiguration, DockerLog log) {\n\t\tthis(HttpTransport.create(connectionConfiguration), log);\n\t}\n\n\t/**\n\t * Create a new {@link DockerApi} instance backed by a specific {@link HttpTransport}\n\t * implementation.\n\t * @param http the http implementation\n\t * @param log a logger used to record output\n\t */\n\tDockerApi(HttpTransport http, DockerLog log) {\n\t\tAssert.notNull(http, \"'http' must not be null\");\n\t\tAssert.notNull(log, \"'log' must not be null\");\n\t\tthis.http = http;\n\t\tthis.jsonStream = new JsonStream(SharedJsonMapper.get());\n\t\tthis.image = new ImageApi();\n\t\tthis.container = new ContainerApi();\n\t\tthis.volume = new VolumeApi();\n\t\tthis.system = new SystemApi(log);\n\t}\n\n\tprivate HttpTransport http() {\n\t\treturn this.http;\n\t}\n\n\tprivate JsonStream jsonStream() {\n\t\treturn this.jsonStream;\n\t}\n\n\tURI buildPlatformJsonUrl(Feature feature, @Nullable ImagePlatform platform, String path) {\n\t\tif (platform != null && getApiVersion().supports(feature.minimumVersion())) {\n\t\t\treturn buildUrl(feature, path, \"platform\", platform.toJson());\n\t\t}\n\t\treturn buildUrl(path);\n\t}\n\n\tprivate URI buildUrl(String path, @Nullable Collection<?> params) {\n\t\treturn buildUrl(Feature.BASELINE, path, (params != null) ? params.toArray() : null);\n\t}\n\n\tprivate URI buildUrl(String path, Object... params) {\n\t\treturn buildUrl(Feature.BASELINE, path, params);\n\t}\n\n\tURI buildUrl(Feature feature, String path, Object @Nullable ... params) {\n\t\tApiVersion version = getApiVersion();\n\t\tif (version.equals(UNKNOWN_API_VERSION) || (version.compareTo(PREFERRED_API_VERSION) >= 0\n\t\t\t\t&& version.compareTo(feature.minimumVersion()) >= 0)) {\n\t\t\treturn buildVersionedUrl(PREFERRED_API_VERSION, path, params);\n\t\t}\n\t\tif (version.compareTo(feature.minimumVersion()) >= 0) {\n\t\t\treturn buildVersionedUrl(version, path, params);\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Docker API version must be at least %s to support this feature, but current API version is %s\"\n\t\t\t\t\t.formatted(feature.minimumVersion(), version));\n\t}\n\n\tprivate URI buildVersionedUrl(ApiVersion version, String path, Object @Nullable ... params) {\n\t\ttry {\n\t\t\tURIBuilder builder = new URIBuilder(\"/v\" + version + path);\n\t\t\tif (params != null) {\n\t\t\t\tint param = 0;\n\t\t\t\twhile (param < params.length) {\n\t\t\t\t\tbuilder.addParameter(Objects.toString(params[param++]), Objects.toString(params[param++]));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn builder.build();\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate ApiVersion getApiVersion() {\n\t\tApiVersion apiVersion = this.apiVersion;\n\t\tif (apiVersion == null) {\n\t\t\tapiVersion = this.system.getApiVersion();\n\t\t\tthis.apiVersion = apiVersion;\n\t\t}\n\t\treturn apiVersion;\n\t}\n\n\t/**\n\t * Return the Docker API for image operations.\n\t * @return the image API\n\t */\n\tpublic ImageApi image() {\n\t\treturn this.image;\n\t}\n\n\t/**\n\t * Return the Docker API for container operations.\n\t * @return the container API\n\t */\n\tpublic ContainerApi container() {\n\t\treturn this.container;\n\t}\n\n\tpublic VolumeApi volume() {\n\t\treturn this.volume;\n\t}\n\n\tSystemApi system() {\n\t\treturn this.system;\n\t}\n\n\t/**\n\t * Docker API for image operations.\n\t */\n\tpublic class ImageApi {\n\n\t\tImageApi() {\n\t\t}\n\n\t\t/**\n\t\t * Pull an image from a registry.\n\t\t * @param reference the image reference to pull\n\t\t * @param platform the platform (os/architecture/variant) of the image to pull\n\t\t * @param listener a pull listener to receive update events\n\t\t * @return the {@link ImageApi pulled image} instance\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic Image pull(ImageReference reference, @Nullable ImagePlatform platform,\n\t\t\t\tUpdateListener<PullImageUpdateEvent> listener) throws IOException {\n\t\t\treturn pull(reference, platform, listener, null);\n\t\t}\n\n\t\t/**\n\t\t * Pull an image from a registry.\n\t\t * @param reference the image reference to pull\n\t\t * @param platform the platform (os/architecture/variant) of the image to pull\n\t\t * @param listener a pull listener to receive update events\n\t\t * @param registryAuth registry authentication credentials\n\t\t * @return the {@link ImageApi pulled image} instance\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic Image pull(ImageReference reference, @Nullable ImagePlatform platform,\n\t\t\t\tUpdateListener<PullImageUpdateEvent> listener, @Nullable String registryAuth) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tAssert.notNull(listener, \"'listener' must not be null\");\n\t\t\tURI createUri = (platform != null) ? buildUrl(Feature.PLATFORM_IMAGE_PULL, \"/images/create\", \"fromImage\",\n\t\t\t\t\treference, \"platform\", platform) : buildUrl(\"/images/create\", \"fromImage\", reference);\n\t\t\tDigestCaptureUpdateListener digestCapture = new DigestCaptureUpdateListener();\n\t\t\tlistener.onStart();\n\t\t\ttry {\n\t\t\t\ttry (Response response = http().post(createUri, registryAuth)) {\n\t\t\t\t\tjsonStream().get(response.getContent(), PullImageUpdateEvent.class, (event) -> {\n\t\t\t\t\t\tdigestCapture.onUpdate(event);\n\t\t\t\t\t\tlistener.onUpdate(event);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn inspect(reference, platform);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tlistener.onFinish();\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Push an image to a registry.\n\t\t * @param reference the image reference to push\n\t\t * @param listener a push listener to receive update events\n\t\t * @param registryAuth registry authentication credentials\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void push(ImageReference reference, UpdateListener<PushImageUpdateEvent> listener,\n\t\t\t\t@Nullable String registryAuth) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tAssert.notNull(listener, \"'listener' must not be null\");\n\t\t\tURI pushUri = buildUrl(\"/images/\" + reference + \"/push\");\n\t\t\tErrorCaptureUpdateListener errorListener = new ErrorCaptureUpdateListener();\n\t\t\tlistener.onStart();\n\t\t\ttry {\n\t\t\t\ttry (Response response = http().post(pushUri, registryAuth)) {\n\t\t\t\t\tjsonStream().get(response.getContent(), PushImageUpdateEvent.class, (event) -> {\n\t\t\t\t\t\terrorListener.onUpdate(event);\n\t\t\t\t\t\tlistener.onUpdate(event);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tlistener.onFinish();\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Load an {@link ImageArchive} into Docker.\n\t\t * @param archive the archive to load\n\t\t * @param listener a pull listener to receive update events\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void load(ImageArchive archive, UpdateListener<LoadImageUpdateEvent> listener) throws IOException {\n\t\t\tAssert.notNull(archive, \"'archive' must not be null\");\n\t\t\tAssert.notNull(listener, \"'listener' must not be null\");\n\t\t\tURI loadUri = buildUrl(\"/images/load\");\n\t\t\tLoadImageUpdateListener streamListener = new LoadImageUpdateListener(archive);\n\t\t\tlistener.onStart();\n\t\t\ttry {\n\t\t\t\ttry (Response response = http().post(loadUri, \"application/x-tar\", archive::writeTo)) {\n\t\t\t\t\tInputStream content = response.getContent();\n\t\t\t\t\tif (content != null) {\n\t\t\t\t\t\tjsonStream().get(content, LoadImageUpdateEvent.class, (event) -> {\n\t\t\t\t\t\t\tstreamListener.onUpdate(event);\n\t\t\t\t\t\t\tlistener.onUpdate(event);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstreamListener.assertValidResponseReceived();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tlistener.onFinish();\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Export the layers of an image as {@link TarArchive TarArchives}.\n\t\t * @param reference the reference to export\n\t\t * @param exports a consumer to receive the layers (contents can only be accessed\n\t\t * during the callback)\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void exportLayers(ImageReference reference, IOBiConsumer<String, TarArchive> exports)\n\t\t\t\tthrows IOException {\n\t\t\texportLayers(reference, null, exports);\n\t\t}\n\n\t\t/**\n\t\t * Export the layers of an image as {@link TarArchive TarArchives}.\n\t\t * @param reference the reference to export\n\t\t * @param platform the platform (os/architecture/variant) of the image to export.\n\t\t * Ignored on older versions of Docker.\n\t\t * @param exports a consumer to receive the layers (contents can only be accessed\n\t\t * during the callback)\n\t\t * @throws IOException on IO error\n\t\t * @since 3.4.12\n\t\t */\n\t\tpublic void exportLayers(ImageReference reference, @Nullable ImagePlatform platform,\n\t\t\t\tIOBiConsumer<String, TarArchive> exports) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tAssert.notNull(exports, \"'exports' must not be null\");\n\t\t\tURI uri = buildPlatformJsonUrl(Feature.PLATFORM_IMAGE_EXPORT, platform, \"/images/\" + reference + \"/get\");\n\t\t\ttry (Response response = http().get(uri)) {\n\t\t\t\ttry (ExportedImageTar exportedImageTar = new ExportedImageTar(reference, response.getContent())) {\n\t\t\t\t\texportedImageTar.exportLayers(exports);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Remove a specific image.\n\t\t * @param reference the reference the remove\n\t\t * @param force if removal should be forced\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void remove(ImageReference reference, boolean force) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tCollection<String> params = force ? FORCE_PARAMS : Collections.emptySet();\n\t\t\tURI uri = buildUrl(\"/images/\" + reference, params);\n\t\t\thttp().delete(uri).close();\n\t\t}\n\n\t\t/**\n\t\t * Inspect an image.\n\t\t * @param reference the image reference\n\t\t * @return the image from the local repository\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic Image inspect(ImageReference reference) throws IOException {\n\t\t\treturn inspect(reference, null);\n\t\t}\n\n\t\t/**\n\t\t * Inspect an image.\n\t\t * @param reference the image reference\n\t\t * @param platform the platform (os/architecture/variant) of the image to inspect.\n\t\t * Ignored on older versions of Docker.\n\t\t * @return the image from the local repository\n\t\t * @throws IOException on IO error\n\t\t * @since 3.4.12\n\t\t */\n\t\tpublic Image inspect(ImageReference reference, @Nullable ImagePlatform platform) throws IOException {\n\t\t\t// The Docker documentation is incomplete but platform parameters\n\t\t\t// are supported since 1.49 (see https://github.com/moby/moby/pull/49586)\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tURI inspectUrl = buildPlatformJsonUrl(Feature.PLATFORM_IMAGE_INSPECT, platform,\n\t\t\t\t\t\"/images/\" + reference + \"/json\");\n\t\t\ttry (Response response = http().get(inspectUrl)) {\n\t\t\t\treturn Image.of(response.getContent());\n\t\t\t}\n\t\t}\n\n\t\tpublic void tag(ImageReference sourceReference, ImageReference targetReference) throws IOException {\n\t\t\tAssert.notNull(sourceReference, \"'sourceReference' must not be null\");\n\t\t\tAssert.notNull(targetReference, \"'targetReference' must not be null\");\n\t\t\tString tag = targetReference.getTag();\n\t\t\tString path = \"/images/\" + sourceReference + \"/tag\";\n\t\t\tURI uri = (tag != null) ? buildUrl(path, \"repo\", targetReference.inTaglessForm(), \"tag\", tag)\n\t\t\t\t\t: buildUrl(path, \"repo\", targetReference);\n\t\t\thttp().post(uri).close();\n\t\t}\n\n\t}\n\n\t/**\n\t * Docker API for container operations.\n\t */\n\tpublic class ContainerApi {\n\n\t\tContainerApi() {\n\t\t}\n\n\t\t/**\n\t\t * Create a new container a {@link ContainerConfig}.\n\t\t * @param config the container config\n\t\t * @param platform the platform (os/architecture/variant) of the image the\n\t\t * container should be created from\n\t\t * @param contents additional contents to include\n\t\t * @return a {@link ContainerReference} for the newly created container\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic ContainerReference create(ContainerConfig config, @Nullable ImagePlatform platform,\n\t\t\t\tContainerContent... contents) throws IOException {\n\t\t\tAssert.notNull(config, \"'config' must not be null\");\n\t\t\tAssert.noNullElements(contents, \"'contents' must not contain null elements\");\n\t\t\tContainerReference containerReference = createContainer(config, platform);\n\t\t\tfor (ContainerContent content : contents) {\n\t\t\t\tuploadContainerContent(containerReference, content);\n\t\t\t}\n\t\t\treturn containerReference;\n\t\t}\n\n\t\tprivate ContainerReference createContainer(ContainerConfig config, @Nullable ImagePlatform platform)\n\t\t\t\tthrows IOException {\n\t\t\tURI createUri = (platform != null)\n\t\t\t\t\t? buildUrl(Feature.PLATFORM_CONTAINER_CREATE, \"/containers/create\", \"platform\", platform)\n\t\t\t\t\t: buildUrl(\"/containers/create\");\n\t\t\ttry (Response response = http().post(createUri, \"application/json\", config::writeTo)) {\n\t\t\t\treturn ContainerReference\n\t\t\t\t\t.of(SharedJsonMapper.get().readTree(response.getContent()).at(\"/Id\").asString());\n\t\t\t}\n\t\t}\n\n\t\tprivate void uploadContainerContent(ContainerReference reference, ContainerContent content) throws IOException {\n\t\t\tURI uri = buildUrl(\"/containers/\" + reference + \"/archive\", \"path\", content.getDestinationPath());\n\t\t\thttp().put(uri, \"application/x-tar\", content.getArchive()::writeTo).close();\n\t\t}\n\n\t\t/**\n\t\t * Start a specific container.\n\t\t * @param reference the container reference to start\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void start(ContainerReference reference) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tURI uri = buildUrl(\"/containers/\" + reference + \"/start\");\n\t\t\thttp().post(uri).close();\n\t\t}\n\n\t\t/**\n\t\t * Return and follow logs for a specific container.\n\t\t * @param reference the container reference\n\t\t * @param listener a listener to receive log update events\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void logs(ContainerReference reference, UpdateListener<LogUpdateEvent> listener) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tAssert.notNull(listener, \"'listener' must not be null\");\n\t\t\tObject[] params = { \"stdout\", \"1\", \"stderr\", \"1\", \"follow\", \"1\" };\n\t\t\tURI uri = buildUrl(\"/containers/\" + reference + \"/logs\", params);\n\t\t\tlistener.onStart();\n\t\t\ttry {\n\t\t\t\ttry (Response response = http().get(uri)) {\n\t\t\t\t\tLogUpdateEvent.readAll(response.getContent(), listener::onUpdate);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tlistener.onFinish();\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Wait for a container to stop and retrieve the status.\n\t\t * @param reference the container reference\n\t\t * @return a {@link ContainerStatus} indicating the exit status of the container\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic ContainerStatus wait(ContainerReference reference) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tURI uri = buildUrl(\"/containers/\" + reference + \"/wait\");\n\t\t\ttry (Response response = http().post(uri)) {\n\t\t\t\treturn ContainerStatus.of(response.getContent());\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Remove a specific container.\n\t\t * @param reference the container to remove\n\t\t * @param force if removal should be forced\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void remove(ContainerReference reference, boolean force) throws IOException {\n\t\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\t\tCollection<String> params = force ? FORCE_PARAMS : Collections.emptySet();\n\t\t\tURI uri = buildUrl(\"/containers/\" + reference, params);\n\t\t\thttp().delete(uri).close();\n\t\t}\n\n\t}\n\n\t/**\n\t * Docker API for volume operations.\n\t */\n\tpublic class VolumeApi {\n\n\t\tVolumeApi() {\n\t\t}\n\n\t\t/**\n\t\t * Delete a volume.\n\t\t * @param name the name of the volume to delete\n\t\t * @param force if the deletion should be forced\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tpublic void delete(VolumeName name, boolean force) throws IOException {\n\t\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\t\tCollection<String> params = force ? FORCE_PARAMS : Collections.emptySet();\n\t\t\tURI uri = buildUrl(\"/volumes/\" + name, params);\n\t\t\thttp().delete(uri).close();\n\t\t}\n\n\t}\n\n\t/**\n\t * Docker API for system operations.\n\t */\n\tclass SystemApi {\n\n\t\tprivate final DockerLog log;\n\n\t\tSystemApi(DockerLog log) {\n\t\t\tthis.log = log;\n\t\t}\n\n\t\t/**\n\t\t * Get the API version supported by the Docker daemon.\n\t\t * @return the Docker daemon API version\n\t\t */\n\t\tApiVersion getApiVersion() {\n\t\t\ttry {\n\t\t\t\tURI uri = new URIBuilder(\"/_ping\").build();\n\t\t\t\ttry (Response response = http().head(uri)) {\n\t\t\t\t\tHeader apiVersionHeader = response.getHeader(API_VERSION_HEADER_NAME);\n\t\t\t\t\tif (apiVersionHeader != null) {\n\t\t\t\t\t\treturn ApiVersion.parse(apiVersionHeader.getValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthis.log.log(\"Warning: Failed to determine Docker API version: \" + ex.getMessage());\n\t\t\t\t\t// fall through to return default value\n\t\t\t\t}\n\t\t\t\treturn UNKNOWN_API_VERSION;\n\t\t\t}\n\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link UpdateListener} used to capture the image digest.\n\t */\n\tprivate static final class DigestCaptureUpdateListener implements UpdateListener<ProgressUpdateEvent> {\n\n\t\tprivate static final String PREFIX = \"Digest:\";\n\n\t\tprivate @Nullable String digest;\n\n\t\t@Override\n\t\tpublic void onUpdate(ProgressUpdateEvent event) {\n\t\t\tString status = event.getStatus();\n\t\t\tif (status != null && status.startsWith(PREFIX)) {\n\t\t\t\tString digest = status.substring(PREFIX.length()).trim();\n\t\t\t\tAssert.state(this.digest == null || this.digest.equals(digest), \"Different digests IDs provided\");\n\t\t\t\tthis.digest = digest;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link UpdateListener} for an image load response stream.\n\t */\n\tprivate static final class LoadImageUpdateListener implements UpdateListener<LoadImageUpdateEvent> {\n\n\t\tprivate final ImageArchive archive;\n\n\t\tprivate @Nullable String stream;\n\n\t\tprivate LoadImageUpdateListener(ImageArchive archive) {\n\t\t\tthis.archive = archive;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onUpdate(LoadImageUpdateEvent event) {\n\t\t\tAssert.state(event.getErrorDetail() == null,\n\t\t\t\t\t() -> \"Error response received when loading image\" + image() + \": \" + event.getErrorDetail());\n\t\t\tthis.stream = event.getStream();\n\t\t}\n\n\t\tprivate String image() {\n\t\t\tImageReference tag = this.archive.getTag();\n\t\t\treturn (tag != null) ? \" \\\"\" + tag + \"\\\"\" : \"\";\n\t\t}\n\n\t\tprivate void assertValidResponseReceived() {\n\t\t\tAssert.state(StringUtils.hasText(this.stream),\n\t\t\t\t\t() -> \"Invalid response received when loading image\" + image());\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link UpdateListener} used to capture the details of an error in a response\n\t * stream.\n\t */\n\tprivate static final class ErrorCaptureUpdateListener implements UpdateListener<PushImageUpdateEvent> {\n\n\t\t@Override\n\t\tpublic void onUpdate(PushImageUpdateEvent event) {\n\t\t\tErrorDetail errorDetail = event.getErrorDetail();\n\t\t\tif (errorDetail != null) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Error response received when pushing image: \" + errorDetail.getMessage());\n\t\t\t}\n\t\t}\n\n\t}\n\n\tenum Feature {\n\n\t\tBASELINE(ApiVersion.of(1, 24)),\n\n\t\tPLATFORM_IMAGE_PULL(ApiVersion.of(1, 41)),\n\n\t\tPLATFORM_CONTAINER_CREATE(ApiVersion.of(1, 41)),\n\n\t\tPLATFORM_IMAGE_INSPECT(ApiVersion.of(1, 49)),\n\n\t\tPLATFORM_IMAGE_EXPORT(ApiVersion.of(1, 48));\n\n\t\tprivate final ApiVersion minimumVersion;\n\n\t\tFeature(ApiVersion minimumVersion) {\n\t\t\tthis.minimumVersion = minimumVersion;\n\t\t}\n\n\t\tApiVersion minimumVersion() {\n\t\t\treturn this.minimumVersion;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/DockerLog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.PrintStream;\n\n/**\n * Callback interface used to provide {@link DockerApi} output logging.\n *\n * @author Dmytro Nosan\n * @since 3.5.0\n * @see #toSystemOut()\n */\npublic interface DockerLog {\n\n\t/**\n\t * Logs a given message.\n\t * @param message the message to log\n\t */\n\tvoid log(String message);\n\n\t/**\n\t * Factory method that returns a {@link DockerLog} that outputs to {@link System#out}.\n\t * @return {@link DockerLog} instance that logs to system out\n\t */\n\tstatic DockerLog toSystemOut() {\n\t\treturn to(System.out);\n\t}\n\n\t/**\n\t * Factory method that returns a {@link DockerLog} that outputs to a given\n\t * {@link PrintStream}.\n\t * @param out the print stream used to output the log\n\t * @return {@link DockerLog} instance that logs to the given print stream\n\t */\n\tstatic DockerLog to(PrintStream out) {\n\t\treturn out::println;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ExportedImageTar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.BlobReference;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchiveIndex;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchiveManifest;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.Manifest;\nimport org.springframework.boot.buildpack.platform.docker.type.ManifestList;\nimport org.springframework.boot.buildpack.platform.io.IOBiConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.buildpack.platform.io.TarArchive.Compression;\nimport org.springframework.util.Assert;\nimport org.springframework.util.function.ThrowingFunction;\n\n/**\n * Internal helper class used by the {@link DockerApi} to extract layers from an exported\n * image tar.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Scott Frederick\n */\nclass ExportedImageTar implements Closeable {\n\n\tprivate final Path tarFile;\n\n\tprivate final LayerArchiveFactory layerArchiveFactory;\n\n\tExportedImageTar(ImageReference reference, InputStream inputStream) throws IOException {\n\t\tthis.tarFile = Files.createTempFile(\"docker-layers-\", null);\n\t\tFiles.copy(inputStream, this.tarFile, StandardCopyOption.REPLACE_EXISTING);\n\t\tthis.layerArchiveFactory = LayerArchiveFactory.create(reference, this.tarFile);\n\t}\n\n\tvoid exportLayers(IOBiConsumer<String, TarArchive> exports) throws IOException {\n\t\ttry (TarArchiveInputStream tar = openTar(this.tarFile)) {\n\t\t\tTarArchiveEntry entry = tar.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tTarArchive layerArchive = this.layerArchiveFactory.getLayerArchive(tar, entry);\n\t\t\t\tif (layerArchive != null) {\n\t\t\t\t\texports.accept(entry.getName(), layerArchive);\n\t\t\t\t}\n\t\t\t\tentry = tar.getNextEntry();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static TarArchiveInputStream openTar(Path path) throws IOException {\n\t\treturn new TarArchiveInputStream(Files.newInputStream(path));\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tFiles.delete(this.tarFile);\n\t}\n\n\t/**\n\t * Factory class used to create a {@link TarArchiveEntry} for layer.\n\t */\n\tprivate abstract static class LayerArchiveFactory {\n\n\t\t/**\n\t\t * Create a new {@link TarArchive} if the given entry represents a layer.\n\t\t * @param tar the tar input stream\n\t\t * @param entry the candidate entry\n\t\t * @return a new {@link TarArchive} instance or {@code null} if this entry is not\n\t\t * a layer.\n\t\t */\n\t\tabstract @Nullable TarArchive getLayerArchive(TarArchiveInputStream tar, TarArchiveEntry entry);\n\n\t\t/**\n\t\t * Create a new {@link LayerArchiveFactory} for the given tar file using either\n\t\t * the {@code index.json} or {@code manifest.json} to detect layers.\n\t\t * @param reference the image that was referenced\n\t\t * @param tarFile the source tar file\n\t\t * @return a new {@link LayerArchiveFactory} instance\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tstatic LayerArchiveFactory create(ImageReference reference, Path tarFile) throws IOException {\n\t\t\ttry (TarArchiveInputStream tar = openTar(tarFile)) {\n\t\t\t\tImageArchiveIndex index = null;\n\t\t\t\tImageArchiveManifest manifest = null;\n\t\t\t\tTarArchiveEntry entry = tar.getNextEntry();\n\t\t\t\twhile (entry != null) {\n\t\t\t\t\tif (\"index.json\".equals(entry.getName())) {\n\t\t\t\t\t\tindex = ImageArchiveIndex.of(tar);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"manifest.json\".equals(entry.getName())) {\n\t\t\t\t\t\tmanifest = ImageArchiveManifest.of(tar);\n\t\t\t\t\t}\n\t\t\t\t\tentry = tar.getNextEntry();\n\t\t\t\t}\n\t\t\t\tAssert.state(index != null || manifest != null,\n\t\t\t\t\t\t() -> \"Exported image '%s' does not contain 'index.json' or 'manifest.json'\"\n\t\t\t\t\t\t\t.formatted(reference));\n\t\t\t\tif (index != null) {\n\t\t\t\t\treturn new IndexLayerArchiveFactory(tarFile, index);\n\t\t\t\t}\n\t\t\t\tAssert.state(manifest != null, \"'manifest' must not be null\");\n\t\t\t\treturn new ManifestLayerArchiveFactory(manifest);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link LayerArchiveFactory} backed by the more recent {@code index.json} file.\n\t */\n\tprivate static class IndexLayerArchiveFactory extends LayerArchiveFactory {\n\n\t\tprivate final Map<String, String> layerMediaTypes;\n\n\t\tIndexLayerArchiveFactory(Path tarFile, ImageArchiveIndex index) throws IOException {\n\t\t\tthis(tarFile, withNestedIndexes(tarFile, index));\n\t\t}\n\n\t\tIndexLayerArchiveFactory(Path tarFile, List<ImageArchiveIndex> indexes) throws IOException {\n\t\t\tSet<String> manifestDigests = getDigests(indexes, this::isManifest);\n\t\t\tSet<String> manifestListDigests = getDigests(indexes, IndexLayerArchiveFactory::isManifestList);\n\t\t\tList<ManifestList> manifestLists = getManifestLists(tarFile, manifestListDigests);\n\t\t\tList<Manifest> manifests = getManifests(tarFile, manifestDigests, manifestLists);\n\t\t\tthis.layerMediaTypes = manifests.stream()\n\t\t\t\t.flatMap((manifest) -> manifest.getLayers().stream())\n\t\t\t\t.collect(Collectors.toMap(IndexLayerArchiveFactory::getEntryName, BlobReference::getMediaType));\n\t\t}\n\n\t\tprivate static List<ImageArchiveIndex> withNestedIndexes(Path tarFile, ImageArchiveIndex index)\n\t\t\t\tthrows IOException {\n\t\t\tSet<String> indexDigests = getDigests(Stream.of(index), IndexLayerArchiveFactory::isIndex);\n\t\t\tList<ImageArchiveIndex> indexes = new ArrayList<>();\n\t\t\tindexes.add(index);\n\t\t\tindexes.addAll(getDigestMatches(tarFile, indexDigests, ImageArchiveIndex::of));\n\t\t\treturn indexes;\n\t\t}\n\n\t\tprivate static Set<String> getDigests(List<ImageArchiveIndex> indexes, Predicate<BlobReference> predicate) {\n\t\t\treturn getDigests(indexes.stream(), predicate);\n\t\t}\n\n\t\tprivate static Set<String> getDigests(Stream<ImageArchiveIndex> indexes, Predicate<BlobReference> predicate) {\n\t\t\treturn indexes.flatMap((index) -> index.getManifests().stream())\n\t\t\t\t.filter(predicate)\n\t\t\t\t.map(BlobReference::getDigest)\n\t\t\t\t.collect(Collectors.toUnmodifiableSet());\n\t\t}\n\n\t\tprivate static List<ManifestList> getManifestLists(Path tarFile, Set<String> digests) throws IOException {\n\t\t\treturn getDigestMatches(tarFile, digests, ManifestList::of);\n\t\t}\n\n\t\tprivate List<Manifest> getManifests(Path tarFile, Set<String> manifestDigests, List<ManifestList> manifestLists)\n\t\t\t\tthrows IOException {\n\t\t\tSet<String> digests = new HashSet<>(manifestDigests);\n\t\t\tmanifestLists.stream()\n\t\t\t\t.flatMap(ManifestList::streamManifests)\n\t\t\t\t.filter(this::isManifest)\n\t\t\t\t.map(BlobReference::getDigest)\n\t\t\t\t.forEach(digests::add);\n\t\t\treturn getDigestMatches(tarFile, digests, Manifest::of);\n\t\t}\n\n\t\tprivate static <T> List<T> getDigestMatches(Path tarFile, Set<String> digests,\n\t\t\t\tThrowingFunction<InputStream, T> factory) throws IOException {\n\t\t\tif (digests.isEmpty()) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\tSet<String> names = digests.stream()\n\t\t\t\t.map(IndexLayerArchiveFactory::getEntryName)\n\t\t\t\t.collect(Collectors.toUnmodifiableSet());\n\t\t\tList<T> result = new ArrayList<>();\n\t\t\ttry (TarArchiveInputStream tar = openTar(tarFile)) {\n\t\t\t\tTarArchiveEntry entry = tar.getNextEntry();\n\t\t\t\twhile (entry != null) {\n\t\t\t\t\tif (names.contains(entry.getName())) {\n\t\t\t\t\t\tresult.add(factory.apply(tar));\n\t\t\t\t\t}\n\t\t\t\t\tentry = tar.getNextEntry();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Collections.unmodifiableList(result);\n\t\t}\n\n\t\tprivate boolean isManifest(BlobReference reference) {\n\t\t\treturn isJsonWithPrefix(reference.getMediaType(), \"application/vnd.oci.image.manifest.v\")\n\t\t\t\t\t|| isJsonWithPrefix(reference.getMediaType(), \"application/vnd.docker.distribution.manifest.v\");\n\t\t}\n\n\t\tprivate static boolean isIndex(BlobReference reference) {\n\t\t\treturn isJsonWithPrefix(reference.getMediaType(), \"application/vnd.oci.image.index.v\");\n\t\t}\n\n\t\tprivate static boolean isManifestList(BlobReference reference) {\n\t\t\treturn isJsonWithPrefix(reference.getMediaType(), \"application/vnd.docker.distribution.manifest.list.v\");\n\t\t}\n\n\t\tprivate static boolean isJsonWithPrefix(String mediaType, String prefix) {\n\t\t\treturn mediaType.startsWith(prefix) && mediaType.endsWith(\"+json\");\n\t\t}\n\n\t\tprivate static String getEntryName(BlobReference reference) {\n\t\t\treturn getEntryName(reference.getDigest());\n\t\t}\n\n\t\tprivate static String getEntryName(String digest) {\n\t\t\treturn \"blobs/\" + digest.replace(':', '/');\n\t\t}\n\n\t\t@Override\n\t\t@Nullable TarArchive getLayerArchive(TarArchiveInputStream tar, TarArchiveEntry entry) {\n\t\t\tString mediaType = this.layerMediaTypes.get(entry.getName());\n\t\t\tif (mediaType == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn TarArchive.fromInputStream(tar, getCompression(mediaType));\n\t\t}\n\n\t\tprivate Compression getCompression(String mediaType) {\n\t\t\tif (mediaType.endsWith(\".tar.gzip\") || mediaType.endsWith(\".tar+gzip\")) {\n\t\t\t\treturn Compression.GZIP;\n\t\t\t}\n\t\t\tif (mediaType.endsWith(\".tar.zstd\") || mediaType.endsWith(\".tar+zstd\")) {\n\t\t\t\treturn Compression.ZSTD;\n\t\t\t}\n\t\t\treturn Compression.NONE;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link LayerArchiveFactory} backed by the legacy {@code manifest.json} file.\n\t */\n\tprivate static class ManifestLayerArchiveFactory extends LayerArchiveFactory {\n\n\t\tprivate final Set<String> layers;\n\n\t\tManifestLayerArchiveFactory(ImageArchiveManifest manifest) {\n\t\t\tthis.layers = manifest.getEntries()\n\t\t\t\t.stream()\n\t\t\t\t.flatMap((entry) -> entry.getLayers().stream())\n\t\t\t\t.collect(Collectors.toUnmodifiableSet());\n\t\t}\n\n\t\t@Override\n\t\t@Nullable TarArchive getLayerArchive(TarArchiveInputStream tar, TarArchiveEntry entry) {\n\t\t\tif (!this.layers.contains(entry.getName())) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn TarArchive.fromInputStream(tar, Compression.NONE);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ImagePlatform.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A platform specification for a Docker image.\n *\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class ImagePlatform {\n\n\tprivate final String os;\n\n\tprivate final @Nullable String architecture;\n\n\tprivate final @Nullable String variant;\n\n\tImagePlatform(String os, @Nullable String architecture, @Nullable String variant) {\n\t\tAssert.hasText(os, \"'os' must not be empty\");\n\t\tthis.os = os;\n\t\tthis.architecture = architecture;\n\t\tthis.variant = variant;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tImagePlatform other = (ImagePlatform) obj;\n\t\treturn Objects.equals(this.architecture, other.architecture) && Objects.equals(this.os, other.os)\n\t\t\t\t&& Objects.equals(this.variant, other.variant);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.architecture, this.os, this.variant);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder builder = new StringBuilder(this.os);\n\t\tif (this.architecture != null) {\n\t\t\tbuilder.append(\"/\").append(this.architecture);\n\t\t}\n\t\tif (this.variant != null) {\n\t\t\tbuilder.append(\"/\").append(this.variant);\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n\t/**\n\t * Create a new {@link ImagePlatform} from the given value in the form\n\t * {@code os[/architecture[/variant]]}.\n\t * @param value the value to parse\n\t * @return an {@link ImagePlatform} instance\n\t */\n\tpublic static ImagePlatform of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tString[] split = value.split(\"/+\");\n\t\treturn switch (split.length) {\n\t\t\tcase 1 -> new ImagePlatform(split[0], null, null);\n\t\t\tcase 2 -> new ImagePlatform(split[0], split[1], null);\n\t\t\tcase 3 -> new ImagePlatform(split[0], split[1], split[2]);\n\t\t\tdefault -> throw new IllegalArgumentException(\n\t\t\t\t\t\"'value' [\" + value + \"] must be in the form 'os[/architecture[/variant]]'\");\n\t\t};\n\t}\n\n\t/**\n\t * Create a new {@link ImagePlatform} matching the platform information from the\n\t * provided {@link Image}.\n\t * @param image the image to get platform information from\n\t * @return an {@link ImagePlatform} instance\n\t */\n\tpublic static ImagePlatform from(Image image) {\n\t\treturn new ImagePlatform(image.getOs(), image.getArchitecture(), image.getVariant());\n\t}\n\n\t/**\n\t * Return a JSON-encoded representation of this platform.\n\t * @return the JSON string\n\t */\n\tpublic String toJson() {\n\t\tObjectNode json = SharedJsonMapper.get().createObjectNode();\n\t\tjson.put(\"os\", this.os);\n\t\tif (StringUtils.hasText(this.architecture)) {\n\t\t\tjson.put(\"architecture\", this.architecture);\n\t\t}\n\t\tif (StringUtils.hasText(this.variant)) {\n\t\t\tjson.put(\"variant\", this.variant);\n\t\t}\n\t\treturn json.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ImageProgressUpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@link ProgressUpdateEvent} fired for image events.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic class ImageProgressUpdateEvent extends ProgressUpdateEvent {\n\n\tprivate final @Nullable String id;\n\n\tprotected ImageProgressUpdateEvent(@Nullable String id, String status, @Nullable ProgressDetail progressDetail,\n\t\t\t@Nullable String progress) {\n\t\tsuper(status, progressDetail, progress);\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * Returns the ID of the image layer being updated if available.\n\t * @return the ID of the updated layer or {@code null}\n\t */\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/LoadImageUpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@link ProgressUpdateEvent} fired as an image is loaded.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class LoadImageUpdateEvent extends ProgressUpdateEvent {\n\n\tprivate final @Nullable String stream;\n\n\tprivate final @Nullable ErrorDetail errorDetail;\n\n\t@JsonCreator\n\tpublic LoadImageUpdateEvent(@Nullable String stream, String status, ProgressDetail progressDetail, String progress,\n\t\t\t@Nullable ErrorDetail errorDetail) {\n\t\tsuper(status, progressDetail, progress);\n\t\tthis.stream = stream;\n\t\tthis.errorDetail = errorDetail;\n\t}\n\n\t/**\n\t * Return the stream response or {@code null} if no response is available.\n\t * @return the stream response.\n\t */\n\tpublic @Nullable String getStream() {\n\t\treturn this.stream;\n\t}\n\n\t/**\n\t * Return the error detail or {@code null} if no error occurred.\n\t * @return the error detail, if any\n\t * @since 3.2.12\n\t */\n\tpublic @Nullable ErrorDetail getErrorDetail() {\n\t\treturn this.errorDetail;\n\t}\n\n\t/**\n\t * Details of an error embedded in a response stream.\n\t *\n\t * @since 3.2.12\n\t */\n\tpublic static class ErrorDetail {\n\n\t\tprivate final String message;\n\n\t\t@JsonCreator\n\t\tpublic ErrorDetail(@JsonProperty(\"message\") String message) {\n\t\t\tthis.message = message;\n\t\t}\n\n\t\t/**\n\t\t * Returns the message field from the error detail.\n\t\t * @return the message\n\t\t */\n\t\tpublic String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.message;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/LogUpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.function.Consumer;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * An update event used to provide log updates.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class LogUpdateEvent extends UpdateEvent {\n\n\tprivate static final Pattern ANSI_PATTERN = Pattern.compile(\"\\u001B\\\\[[;\\\\d]*m\");\n\n\tprivate static final Pattern TRAILING_NEW_LINE_PATTERN = Pattern.compile(\"\\\\n$\");\n\n\tprivate final StreamType streamType;\n\n\tprivate final byte[] payload;\n\n\tprivate final String string;\n\n\tLogUpdateEvent(StreamType streamType, byte[] payload) {\n\t\tthis.streamType = streamType;\n\t\tthis.payload = payload;\n\t\tString string = new String(payload, StandardCharsets.UTF_8);\n\t\tstring = ANSI_PATTERN.matcher(string).replaceAll(\"\");\n\t\tstring = TRAILING_NEW_LINE_PATTERN.matcher(string).replaceAll(\"\");\n\t\tthis.string = string;\n\t}\n\n\tpublic void print() {\n\t\tswitch (this.streamType) {\n\t\t\tcase STD_OUT -> System.out.println(this);\n\t\t\tcase STD_ERR -> System.err.println(this);\n\t\t}\n\t}\n\n\tpublic StreamType getStreamType() {\n\t\treturn this.streamType;\n\t}\n\n\tpublic byte[] getPayload() {\n\t\treturn this.payload;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.string;\n\t}\n\n\tstatic void readAll(InputStream inputStream, Consumer<LogUpdateEvent> consumer) throws IOException {\n\t\ttry {\n\t\t\tLogUpdateEvent event;\n\t\t\twhile ((event = LogUpdateEvent.read(inputStream)) != null) {\n\t\t\t\tconsumer.accept(event);\n\t\t\t}\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\tbyte[] message = (ex.getMessage() == null) ? new byte[0] : ex.getMessage().getBytes(StandardCharsets.UTF_8);\n\t\t\tconsumer.accept(new LogUpdateEvent(StreamType.STD_ERR, message));\n\t\t\tStreamUtils.drain(inputStream);\n\t\t}\n\t\tfinally {\n\t\t\tinputStream.close();\n\t\t}\n\t}\n\n\tprivate static @Nullable LogUpdateEvent read(InputStream inputStream) throws IOException {\n\t\tbyte[] header = read(inputStream, 8);\n\t\tif (header == null) {\n\t\t\treturn null;\n\t\t}\n\t\tStreamType streamType = StreamType.forId(header[0]);\n\t\tlong size = 0;\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tsize = (size << 8) + (header[i + 4] & 0xff);\n\t\t}\n\t\tbyte[] payload = read(inputStream, size);\n\t\tAssert.state(payload != null, \"'payload' must not be null\");\n\t\treturn new LogUpdateEvent(streamType, payload);\n\t}\n\n\tprivate static byte @Nullable [] read(InputStream inputStream, long size) throws IOException {\n\t\tbyte[] data = new byte[(int) size];\n\t\tint offset = 0;\n\t\tdo {\n\t\t\tint amountRead = inputStream.read(data, offset, data.length - offset);\n\t\t\tif (amountRead == -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\toffset += amountRead;\n\t\t}\n\t\twhile (offset < data.length);\n\t\treturn data;\n\t}\n\n\t/**\n\t * Stream types supported by the event.\n\t */\n\tpublic enum StreamType {\n\n\t\t/**\n\t\t * Input from {@code stdin}.\n\t\t */\n\t\tSTD_IN,\n\n\t\t/**\n\t\t * Output to {@code stdout}.\n\t\t */\n\t\tSTD_OUT,\n\n\t\t/**\n\t\t * Output to {@code stderr}.\n\t\t */\n\t\tSTD_ERR;\n\n\t\tstatic StreamType forId(byte id) {\n\t\t\tint upperBound = values().length;\n\t\t\tAssert.state(id > 0 && id < upperBound,\n\t\t\t\t\t() -> \"Stream type is out of bounds. Must be >= 0 and < \" + upperBound + \", but was \" + id);\n\t\t\treturn values()[id];\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * An {@link UpdateEvent} that includes progress information.\n *\n * @author Phillip Webb\n * @author Wolfgang Kronberg\n * @since 2.3.0\n */\npublic abstract class ProgressUpdateEvent extends UpdateEvent {\n\n\tprivate final @Nullable String status;\n\n\tprivate final @Nullable ProgressDetail progressDetail;\n\n\tprivate final @Nullable String progress;\n\n\tprotected ProgressUpdateEvent(@Nullable String status, @Nullable ProgressDetail progressDetail,\n\t\t\t@Nullable String progress) {\n\t\tthis.status = status;\n\t\tthis.progressDetail = (ProgressDetail.isEmpty(progressDetail)) ? null : progressDetail;\n\t\tthis.progress = progress;\n\t}\n\n\t/**\n\t * Return the status for the update. For example, \"Extracting\" or \"Downloading\".\n\t * @return the status of the update.\n\t */\n\tpublic @Nullable String getStatus() {\n\t\treturn this.status;\n\t}\n\n\t/**\n\t * Return progress details if available.\n\t * @return progress details or {@code null}\n\t */\n\tpublic @Nullable ProgressDetail getProgressDetail() {\n\t\treturn this.progressDetail;\n\t}\n\n\t/**\n\t * Return a text based progress bar if progress information is available.\n\t * @return the progress bar or {@code null}\n\t */\n\tpublic @Nullable String getProgress() {\n\t\treturn this.progress;\n\t}\n\n\t/**\n\t * Provide details about the progress of a task.\n\t */\n\tpublic static class ProgressDetail {\n\n\t\tprivate final @Nullable Long current;\n\n\t\tprivate final @Nullable Long total;\n\n\t\t@JsonCreator\n\t\tpublic ProgressDetail(@Nullable Long current, @Nullable Long total) {\n\t\t\tthis.current = current;\n\t\t\tthis.total = total;\n\t\t}\n\n\t\t/**\n\t\t * Return the progress as a percentage.\n\t\t * @return the progress percentage\n\t\t * @since 3.3.7\n\t\t */\n\t\tpublic int asPercentage() {\n\t\t\tif (this.total == null || this.current == null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tint percentage = (int) ((100.0 / this.total) * this.current);\n\t\t\treturn (percentage < 0) ? 0 : Math.min(percentage, 100);\n\t\t}\n\n\t\tprivate static boolean isEmpty(@Nullable ProgressDetail progressDetail) {\n\t\t\treturn progressDetail == null || progressDetail.current == null || progressDetail.total == null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/PullImageUpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\n\n/**\n * A {@link ProgressUpdateEvent} fired as an image is pulled.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class PullImageUpdateEvent extends ImageProgressUpdateEvent {\n\n\t@JsonCreator\n\tpublic PullImageUpdateEvent(String id, String status, ProgressDetail progressDetail, String progress) {\n\t\tsuper(id, status, progressDetail, progress);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/PushImageUpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@link ProgressUpdateEvent} fired as an image is pushed to a registry.\n *\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic class PushImageUpdateEvent extends ImageProgressUpdateEvent {\n\n\tprivate final @Nullable ErrorDetail errorDetail;\n\n\t@JsonCreator\n\tpublic PushImageUpdateEvent(String id, String status, ProgressDetail progressDetail, String progress,\n\t\t\t@Nullable ErrorDetail errorDetail) {\n\t\tsuper(id, status, progressDetail, progress);\n\t\tthis.errorDetail = errorDetail;\n\t}\n\n\t/**\n\t * Returns the details of any error encountered during processing.\n\t * @return the error\n\t */\n\tpublic @Nullable ErrorDetail getErrorDetail() {\n\t\treturn this.errorDetail;\n\t}\n\n\t/**\n\t * Details of an error embedded in a response stream.\n\t */\n\tpublic static class ErrorDetail {\n\n\t\tprivate final String message;\n\n\t\t@JsonCreator\n\t\tpublic ErrorDetail(@JsonProperty(\"message\") String message) {\n\t\t\tthis.message = message;\n\t\t}\n\n\t\t/**\n\t\t * Returns the message field from the error detail.\n\t\t * @return the message\n\t\t */\n\t\tpublic String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.message;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressBar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.PrintStream;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility to render a simple progress bar based on consumed {@link TotalProgressEvent}\n * objects.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class TotalProgressBar implements Consumer<TotalProgressEvent> {\n\n\tprivate final char progressChar;\n\n\tprivate final boolean bookend;\n\n\tprivate final PrintStream out;\n\n\tprivate int printed;\n\n\t/**\n\t * Create a new {@link TotalProgressBar} instance.\n\t * @param prefix the prefix to output\n\t */\n\tpublic TotalProgressBar(String prefix) {\n\t\tthis(prefix, System.out);\n\t}\n\n\t/**\n\t * Create a new {@link TotalProgressBar} instance.\n\t * @param prefix the prefix to output\n\t * @param out the output print stream to use\n\t */\n\tpublic TotalProgressBar(String prefix, PrintStream out) {\n\t\tthis(prefix, '#', true, out);\n\t}\n\n\t/**\n\t * Create a new {@link TotalProgressBar} instance.\n\t * @param prefix the prefix to output\n\t * @param progressChar the progress char to print\n\t * @param bookend if bookends should be printed\n\t * @param out the output print stream to use\n\t */\n\tpublic TotalProgressBar(@Nullable String prefix, char progressChar, boolean bookend, PrintStream out) {\n\t\tthis.progressChar = progressChar;\n\t\tthis.bookend = bookend;\n\t\tif (StringUtils.hasLength(prefix)) {\n\t\t\tout.print(prefix);\n\t\t\tout.print(\" \");\n\t\t}\n\t\tif (bookend) {\n\t\t\tout.print(\"[ \");\n\t\t}\n\t\tthis.out = out;\n\t}\n\n\t@Override\n\tpublic void accept(TotalProgressEvent event) {\n\t\tint percent = event.getPercent() / 2;\n\t\twhile (this.printed < percent) {\n\t\t\tthis.out.print(this.progressChar);\n\t\t\tthis.printed++;\n\t\t}\n\t\tif (event.getPercent() == 100) {\n\t\t\tthis.out.println(this.bookend ? \" ]\" : \"\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.springframework.util.Assert;\n\n/**\n * Event published by the {@link TotalProgressPullListener} showing the total progress of\n * an operation.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class TotalProgressEvent {\n\n\tprivate final int percent;\n\n\t/**\n\t * Create a new {@link TotalProgressEvent} with a specific percent value.\n\t * @param percent the progress as a percentage\n\t */\n\tpublic TotalProgressEvent(int percent) {\n\t\tAssert.isTrue(percent >= 0 && percent <= 100, \"'percent' must be in the range 0 to 100\");\n\t\tthis.percent = percent;\n\t}\n\n\t/**\n\t * Return the total progress.\n\t * @return the total progress\n\t */\n\tpublic int getPercent() {\n\t\treturn this.percent;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.buildpack.platform.docker.ProgressUpdateEvent.ProgressDetail;\n\n/**\n * {@link UpdateListener} that calculates the total progress of the entire image operation\n * and publishes {@link TotalProgressEvent}.\n *\n * @param <E> the type of {@link ImageProgressUpdateEvent}\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic abstract class TotalProgressListener<E extends ImageProgressUpdateEvent> implements UpdateListener<E> {\n\n\tprivate final Map<String, Layer> layers = new ConcurrentHashMap<>();\n\n\tprivate final Consumer<TotalProgressEvent> consumer;\n\n\tprivate final String[] trackedStatusKeys;\n\n\tprivate boolean progressStarted;\n\n\t/**\n\t * Create a new {@link TotalProgressListener} that sends {@link TotalProgressEvent\n\t * events} to the given consumer.\n\t * @param consumer the consumer that receives {@link TotalProgressEvent progress\n\t * events}\n\t * @param trackedStatusKeys a list of status event keys to track the progress of\n\t */\n\tprotected TotalProgressListener(Consumer<TotalProgressEvent> consumer, String[] trackedStatusKeys) {\n\t\tthis.consumer = consumer;\n\t\tthis.trackedStatusKeys = trackedStatusKeys;\n\t}\n\n\t@Override\n\tpublic void onStart() {\n\t}\n\n\t@Override\n\tpublic void onUpdate(E event) {\n\t\tif (event.getId() != null) {\n\t\t\tthis.layers.computeIfAbsent(event.getId(), (value) -> new Layer(this.trackedStatusKeys)).update(event);\n\t\t}\n\t\tthis.progressStarted = this.progressStarted || event.getProgress() != null;\n\t\tif (this.progressStarted) {\n\t\t\tpublish(0);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onFinish() {\n\t\tthis.layers.values().forEach(Layer::finish);\n\t\tpublish(100);\n\t}\n\n\tprivate void publish(int fallback) {\n\t\tint count = 0;\n\t\tint total = 0;\n\t\tfor (Layer layer : this.layers.values()) {\n\t\t\tcount++;\n\t\t\ttotal += layer.getProgress();\n\t\t}\n\t\tTotalProgressEvent event = new TotalProgressEvent(\n\t\t\t\t(count != 0) ? withinPercentageBounds(total / count) : fallback);\n\t\tthis.consumer.accept(event);\n\t}\n\n\tprivate static int withinPercentageBounds(int value) {\n\t\treturn (value < 0) ? 0 : Math.min(value, 100);\n\t}\n\n\t/**\n\t * Progress for an individual layer.\n\t */\n\tprivate static class Layer {\n\n\t\tprivate final Map<String, Integer> progressByStatus = new HashMap<>();\n\n\t\tLayer(String[] trackedStatusKeys) {\n\t\t\tArrays.stream(trackedStatusKeys).forEach((status) -> this.progressByStatus.put(status, 0));\n\t\t}\n\n\t\tvoid update(ImageProgressUpdateEvent event) {\n\t\t\tString status = event.getStatus();\n\t\t\tif (status == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (event.getProgressDetail() != null && this.progressByStatus.containsKey(status)) {\n\t\t\t\tint current = this.progressByStatus.get(status);\n\t\t\t\tthis.progressByStatus.put(status, updateProgress(current, event.getProgressDetail()));\n\t\t\t}\n\t\t}\n\n\t\tprivate int updateProgress(int current, ProgressDetail detail) {\n\t\t\treturn Math.max(detail.asPercentage(), current);\n\t\t}\n\n\t\tvoid finish() {\n\t\t\tthis.progressByStatus.keySet().forEach((key) -> this.progressByStatus.put(key, 100));\n\t\t}\n\n\t\tint getProgress() {\n\t\t\treturn withinPercentageBounds((this.progressByStatus.values().stream().mapToInt(Integer::intValue).sum())\n\t\t\t\t\t/ this.progressByStatus.size());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressPullListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.function.Consumer;\n\n/**\n * {@link UpdateListener} that calculates the total progress of the entire pull operation\n * and publishes {@link TotalProgressEvent}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class TotalProgressPullListener extends TotalProgressListener<PullImageUpdateEvent> {\n\n\tprivate static final String[] TRACKED_STATUS_KEYS = { \"Downloading\", \"Extracting\" };\n\n\t/**\n\t * Create a new {@link TotalProgressPullListener} that prints a progress bar to\n\t * {@link System#out}.\n\t * @param prefix the prefix to output\n\t */\n\tpublic TotalProgressPullListener(String prefix) {\n\t\tthis(new TotalProgressBar(prefix));\n\t}\n\n\t/**\n\t * Create a new {@link TotalProgressPullListener} that sends {@link TotalProgressEvent\n\t * events} to the given consumer.\n\t * @param consumer the consumer that receives {@link TotalProgressEvent progress\n\t * events}\n\t */\n\tpublic TotalProgressPullListener(Consumer<TotalProgressEvent> consumer) {\n\t\tsuper(consumer, TRACKED_STATUS_KEYS);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/TotalProgressPushListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.function.Consumer;\n\n/**\n * {@link UpdateListener} that calculates the total progress of the entire push operation\n * and publishes {@link TotalProgressEvent}.\n *\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic class TotalProgressPushListener extends TotalProgressListener<PushImageUpdateEvent> {\n\n\tprivate static final String[] TRACKED_STATUS_KEYS = { \"Pushing\" };\n\n\t/**\n\t * Create a new {@link TotalProgressPushListener} that prints a progress bar to\n\t * {@link System#out}.\n\t * @param prefix the prefix to output\n\t */\n\tpublic TotalProgressPushListener(String prefix) {\n\t\tthis(new TotalProgressBar(prefix));\n\t}\n\n\t/**\n\t * Create a new {@link TotalProgressPushListener} that sends {@link TotalProgressEvent\n\t * events} to the given consumer.\n\t * @param consumer the consumer that receives {@link TotalProgressEvent progress\n\t * events}\n\t */\n\tpublic TotalProgressPushListener(Consumer<TotalProgressEvent> consumer) {\n\t\tsuper(consumer, TRACKED_STATUS_KEYS);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/UpdateEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\n/**\n * Base class for update events published by Docker.\n *\n * @author Phillip Webb\n * @since 2.3.0\n * @see UpdateListener\n */\npublic abstract class UpdateEvent {\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/UpdateListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\n/**\n * Listener for update events published from the {@link DockerApi}.\n *\n * @param <E> the update event type\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface UpdateListener<E extends UpdateEvent> {\n\n\t/**\n\t * A no-op update listener.\n\t * @see #none()\n\t */\n\tUpdateListener<UpdateEvent> NONE = (event) -> {\n\t};\n\n\t/**\n\t * Called when the operation starts.\n\t */\n\tdefault void onStart() {\n\t}\n\n\t/**\n\t * Called when an update event is available.\n\t * @param event the update event\n\t */\n\tvoid onUpdate(E event);\n\n\t/**\n\t * Called when the operation finishes (with or without error).\n\t */\n\tdefault void onFinish() {\n\t}\n\n\t/**\n\t * A no-op update listener that does nothing.\n\t * @param <E> the event type\n\t * @return a no-op update listener\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <E extends UpdateEvent> UpdateListener<E> none() {\n\t\treturn (UpdateListener<E>) NONE;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/Credential.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.lang.invoke.MethodHandles;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.Assert;\n\n/**\n * A class that represents credentials for a server as returned from a\n * {@link CredentialHelper}.\n *\n * @author Dmytro Nosan\n */\nclass Credential extends MappedObject {\n\n\t/**\n\t * If the secret being stored is an identity token, the username should be set to\n\t * {@code <token>}.\n\t */\n\tprivate static final String TOKEN_USERNAME = \"<token>\";\n\n\tprivate final String username;\n\n\tprivate final String secret;\n\n\tprivate final @Nullable String serverUrl;\n\n\tCredential(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.username = extractUsername();\n\t\tthis.secret = extractSecret();\n\t\tthis.serverUrl = valueAt(\"/ServerURL\", String.class);\n\t}\n\n\tprivate String extractSecret() {\n\t\tString result = valueAt(\"/Secret\", String.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate String extractUsername() {\n\t\tString result = valueAt(\"/Username\", String.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getSecret() {\n\t\treturn this.secret;\n\t}\n\n\t@Nullable String getServerUrl() {\n\t\treturn this.serverUrl;\n\t}\n\n\tboolean isIdentityToken() {\n\t\treturn TOKEN_USERNAME.equals(this.username);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/CredentialHelper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\n\nimport com.sun.jna.Platform;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\n\n/**\n * Invokes a Docker credential helper executable that can be used to get {@link Credential\n * credentials}.\n *\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\nclass CredentialHelper {\n\n\tprivate static final String USR_LOCAL_BIN = \"/usr/local/bin/\";\n\n\tprivate static final Set<String> CREDENTIAL_NOT_FOUND_MESSAGES = Set.of(\"credentials not found in native keychain\",\n\t\t\t\"no credentials server URL\", \"no credentials username\");\n\n\tprivate final String executable;\n\n\tCredentialHelper(String executable) {\n\t\tthis.executable = executable;\n\t}\n\n\t@Nullable Credential get(String serverUrl) throws IOException {\n\t\tProcessBuilder processBuilder = processBuilder(\"get\");\n\t\tProcess process = start(processBuilder);\n\t\ttry (OutputStream request = process.getOutputStream()) {\n\t\t\trequest.write(serverUrl.getBytes(StandardCharsets.UTF_8));\n\t\t}\n\t\ttry {\n\t\t\tint exitCode = process.waitFor();\n\t\t\ttry (InputStream response = process.getInputStream()) {\n\t\t\t\tif (exitCode == 0) {\n\t\t\t\t\treturn new Credential(SharedJsonMapper.get().readTree(response));\n\t\t\t\t}\n\t\t\t\tString errorMessage = new String(response.readAllBytes(), StandardCharsets.UTF_8);\n\t\t\t\tif (!isCredentialsNotFoundError(errorMessage)) {\n\t\t\t\t\tthrow new IOException(\"%s' exited with code %d: %s\".formatted(process, exitCode, errorMessage));\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate ProcessBuilder processBuilder(String action) {\n\t\tProcessBuilder processBuilder = new ProcessBuilder().redirectErrorStream(true);\n\t\tif (Platform.isWindows()) {\n\t\t\tprocessBuilder.command(\"cmd\", \"/c\");\n\t\t}\n\t\tprocessBuilder.command().addAll(Arrays.asList(this.executable, action));\n\t\treturn processBuilder;\n\t}\n\n\tprivate Process start(ProcessBuilder processBuilder) throws IOException {\n\t\ttry {\n\t\t\treturn processBuilder.start();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tif (!Platform.isMac()) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tList<String> command = new ArrayList<>(processBuilder.command());\n\t\t\t\tcommand.set(0, USR_LOCAL_BIN + command.get(0));\n\t\t\t\treturn processBuilder.command(command).start();\n\t\t\t}\n\t\t\tcatch (Exception suppressed) {\n\t\t\t\t// Suppresses the exception and rethrows the original exception\n\t\t\t\tex.addSuppressed(suppressed);\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static boolean isCredentialsNotFoundError(String message) {\n\t\treturn CREDENTIAL_NOT_FOUND_MESSAGES.contains(message.trim());\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.lang.invoke.MethodHandles;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\nimport java.util.HexFormat;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JacksonException;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.node.NullNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.boot.buildpack.platform.system.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * Docker configuration stored in metadata files managed by the Docker CLI.\n *\n * @author Scott Frederick\n * @author Dmytro Nosan\n */\nfinal class DockerConfigurationMetadata {\n\n\tprivate static final String DOCKER_CONFIG = \"DOCKER_CONFIG\";\n\n\tprivate static final String DEFAULT_CONTEXT = \"default\";\n\n\tprivate static final String CONFIG_DIR = \".docker\";\n\n\tprivate static final String CONTEXTS_DIR = \"contexts\";\n\n\tprivate static final String META_DIR = \"meta\";\n\n\tprivate static final String TLS_DIR = \"tls\";\n\n\tprivate static final String DOCKER_ENDPOINT = \"docker\";\n\n\tprivate static final String CONFIG_FILE_NAME = \"config.json\";\n\n\tprivate static final String CONTEXT_FILE_NAME = \"meta.json\";\n\n\tprivate static final Supplier<DockerConfigurationMetadata> systemEnvironmentConfigurationMetadata = SingletonSupplier\n\t\t.of(() -> DockerConfigurationMetadata.create(Environment.SYSTEM));\n\n\tprivate final String configLocation;\n\n\tprivate final DockerConfig config;\n\n\tprivate final DockerContext context;\n\n\tprivate DockerConfigurationMetadata(String configLocation, DockerConfig config, DockerContext context) {\n\t\tthis.configLocation = configLocation;\n\t\tthis.config = config;\n\t\tthis.context = context;\n\t}\n\n\tDockerConfig getConfiguration() {\n\t\treturn this.config;\n\t}\n\n\tDockerContext getContext() {\n\t\treturn this.context;\n\t}\n\n\tDockerContext forContext(@Nullable String context) {\n\t\treturn createDockerContext(this.configLocation, context);\n\t}\n\n\tstatic DockerConfigurationMetadata from(Environment environment) {\n\t\tif (environment == Environment.SYSTEM) {\n\t\t\treturn systemEnvironmentConfigurationMetadata.get();\n\t\t}\n\t\treturn create(environment);\n\t}\n\n\tprivate static DockerConfigurationMetadata create(Environment environment) {\n\t\tString configLocation = environment.get(DOCKER_CONFIG);\n\t\tconfigLocation = (configLocation != null) ? configLocation : getUserHomeConfigLocation();\n\t\tDockerConfig dockerConfig = createDockerConfig(configLocation);\n\t\tDockerContext dockerContext = createDockerContext(configLocation, dockerConfig.getCurrentContext());\n\t\treturn new DockerConfigurationMetadata(configLocation, dockerConfig, dockerContext);\n\t}\n\n\tprivate static String getUserHomeConfigLocation() {\n\t\treturn Path.of(System.getProperty(\"user.home\"), CONFIG_DIR).toString();\n\t}\n\n\tprivate static DockerConfig createDockerConfig(String configLocation) {\n\t\tPath path = Path.of(configLocation, CONFIG_FILE_NAME);\n\t\tif (!path.toFile().exists()) {\n\t\t\treturn DockerConfig.empty();\n\t\t}\n\t\ttry {\n\t\t\treturn DockerConfig.fromJson(readPathContent(path));\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\tthrow new IllegalStateException(\"Error parsing Docker configuration file '\" + path + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate static DockerContext createDockerContext(String configLocation, @Nullable String currentContext) {\n\t\tif (currentContext == null || DEFAULT_CONTEXT.equals(currentContext)) {\n\t\t\treturn DockerContext.empty();\n\t\t}\n\t\tString hash = asHash(currentContext);\n\t\tPath metaPath = Path.of(configLocation, CONTEXTS_DIR, META_DIR, hash, CONTEXT_FILE_NAME);\n\t\tPath tlsPath = Path.of(configLocation, CONTEXTS_DIR, TLS_DIR, hash, DOCKER_ENDPOINT);\n\t\tif (!metaPath.toFile().exists()) {\n\t\t\tthrow new IllegalArgumentException(\"Docker context '\" + currentContext + \"' does not exist\");\n\t\t}\n\t\ttry {\n\t\t\tDockerContext context = DockerContext.fromJson(readPathContent(metaPath));\n\t\t\tif (tlsPath.toFile().isDirectory()) {\n\t\t\t\treturn context.withTlsPath(tlsPath.toString());\n\t\t\t}\n\t\t\treturn context;\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\tthrow new IllegalStateException(\"Error parsing Docker context metadata file '\" + metaPath + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate static String asHash(String currentContext) {\n\t\ttry {\n\t\t\tMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n\t\t\tbyte[] hash = digest.digest(currentContext.getBytes(StandardCharsets.UTF_8));\n\t\t\treturn HexFormat.of().formatHex(hash);\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\tthrow new IllegalStateException(\"SHA-256 is not available\", ex);\n\t\t}\n\t}\n\n\tprivate static String readPathContent(Path path) {\n\t\ttry {\n\t\t\treturn Files.readString(path);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Error reading Docker configuration file '\" + path + \"'\", ex);\n\t\t}\n\t}\n\n\tstatic final class DockerConfig extends MappedObject {\n\n\t\tprivate final @Nullable String currentContext;\n\n\t\tprivate final @Nullable String credsStore;\n\n\t\tprivate final Map<String, String> credHelpers;\n\n\t\tprivate final Map<String, Auth> auths;\n\n\t\tprivate DockerConfig(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tthis.currentContext = valueAt(\"/currentContext\", String.class);\n\t\t\tthis.credsStore = valueAt(\"/credsStore\", String.class);\n\t\t\tthis.credHelpers = mapAt(\"/credHelpers\", JsonNode::stringValue);\n\t\t\tthis.auths = mapAt(\"/auths\", Auth::new);\n\t\t}\n\n\t\t@Nullable String getCurrentContext() {\n\t\t\treturn this.currentContext;\n\t\t}\n\n\t\t@Nullable String getCredsStore() {\n\t\t\treturn this.credsStore;\n\t\t}\n\n\t\tMap<String, String> getCredHelpers() {\n\t\t\treturn this.credHelpers;\n\t\t}\n\n\t\tMap<String, Auth> getAuths() {\n\t\t\treturn this.auths;\n\t\t}\n\n\t\tstatic DockerConfig fromJson(String json) {\n\t\t\treturn new DockerConfig(SharedJsonMapper.get().readTree(json));\n\t\t}\n\n\t\tstatic DockerConfig empty() {\n\t\t\treturn new DockerConfig(NullNode.instance);\n\t\t}\n\n\t}\n\n\tstatic final class Auth extends MappedObject {\n\n\t\tprivate final @Nullable String username;\n\n\t\tprivate final @Nullable String password;\n\n\t\tprivate final @Nullable String email;\n\n\t\tAuth(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tString auth = valueAt(\"/auth\", String.class);\n\t\t\tif (StringUtils.hasLength(auth)) {\n\t\t\t\tString[] parts = new String(Base64.getDecoder().decode(auth)).split(\":\", 2);\n\t\t\t\tAssert.state(parts.length == 2, \"Malformed auth in docker configuration metadata\");\n\t\t\t\tthis.username = parts[0];\n\t\t\t\tthis.password = trim(parts[1], Character.MIN_VALUE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.username = valueAt(\"/username\", String.class);\n\t\t\t\tthis.password = valueAt(\"/password\", String.class);\n\t\t\t}\n\t\t\tthis.email = valueAt(\"/email\", String.class);\n\t\t}\n\n\t\t@Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\t@Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\t@Nullable String getEmail() {\n\t\t\treturn this.email;\n\t\t}\n\n\t\tprivate static String trim(String source, char character) {\n\t\t\tsource = StringUtils.trimLeadingCharacter(source, character);\n\t\t\treturn StringUtils.trimTrailingCharacter(source, character);\n\t\t}\n\n\t}\n\n\tstatic final class DockerContext extends MappedObject {\n\n\t\tprivate final @Nullable String dockerHost;\n\n\t\tprivate final @Nullable Boolean skipTlsVerify;\n\n\t\tprivate final @Nullable String tlsPath;\n\n\t\tprivate DockerContext(JsonNode node, @Nullable String tlsPath) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tthis.dockerHost = valueAt(\"/Endpoints/\" + DOCKER_ENDPOINT + \"/Host\", String.class);\n\t\t\tthis.skipTlsVerify = valueAt(\"/Endpoints/\" + DOCKER_ENDPOINT + \"/SkipTLSVerify\", Boolean.class);\n\t\t\tthis.tlsPath = tlsPath;\n\t\t}\n\n\t\t@Nullable String getDockerHost() {\n\t\t\treturn this.dockerHost;\n\t\t}\n\n\t\tBoolean isTlsVerify() {\n\t\t\treturn this.skipTlsVerify != null && !this.skipTlsVerify;\n\t\t}\n\n\t\t@Nullable String getTlsPath() {\n\t\t\treturn this.tlsPath;\n\t\t}\n\n\t\tDockerContext withTlsPath(String tlsPath) {\n\t\t\treturn new DockerContext(this.getNode(), tlsPath);\n\t\t}\n\n\t\tstatic DockerContext fromJson(String json) {\n\t\t\treturn new DockerContext(SharedJsonMapper.get().readTree(json), null);\n\t\t}\n\n\t\tstatic DockerContext empty() {\n\t\t\treturn new DockerContext(NullNode.instance, null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConnectionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Configuration for how to connect to Docker.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic sealed interface DockerConnectionConfiguration {\n\n\t/**\n\t * Connect to specific host.\n\t *\n\t * @param address the host address\n\t * @param secure if connection is secure\n\t * @param certificatePath a path to the certificate used for secure connections\n\t */\n\trecord Host(String address, boolean secure,\n\t\t\t@Nullable String certificatePath) implements DockerConnectionConfiguration {\n\n\t\tpublic Host(String address) {\n\t\t\tthis(address, false, null);\n\t\t}\n\n\t\tpublic Host {\n\t\t\tAssert.hasLength(address, \"'address' must not be empty\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Connect using a specific context reference.\n\t *\n\t * @param context a reference to the Docker context\n\t */\n\trecord Context(String context) implements DockerConnectionConfiguration {\n\n\t\tpublic Context {\n\t\t\tAssert.hasLength(context, \"'context' must not be empty\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerHost.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Docker host connection options.\n *\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic class DockerHost {\n\n\tprivate final @Nullable String address;\n\n\tprivate final boolean secure;\n\n\tprivate final @Nullable String certificatePath;\n\n\tpublic DockerHost(@Nullable String address) {\n\t\tthis(address, false, null);\n\t}\n\n\tpublic DockerHost(@Nullable String address, boolean secure, @Nullable String certificatePath) {\n\t\tthis.address = address;\n\t\tthis.secure = secure;\n\t\tthis.certificatePath = certificatePath;\n\t}\n\n\tpublic @Nullable String getAddress() {\n\t\treturn this.address;\n\t}\n\n\tpublic boolean isSecure() {\n\t\treturn this.secure;\n\t}\n\n\tpublic @Nullable String getCertificatePath() {\n\t\treturn this.certificatePath;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.util.function.BiConsumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.util.Assert;\n\n/**\n * Docker registry authentication configuration.\n *\n * @author Scott Frederick\n * @since 2.4.0\n */\n@FunctionalInterface\npublic interface DockerRegistryAuthentication {\n\n\t/**\n\t * An empty {@link #user(String, String, String, String)} authentication.\n\t * @since 3.5.0\n\t */\n\tDockerRegistryAuthentication EMPTY_USER = DockerRegistryAuthentication.user(\"\", \"\", \"\", \"\");\n\n\t/**\n\t * Returns the auth header that should be used for docker authentication for the given\n\t * image reference.\n\t * @param imageReference the image reference or {@code null}\n\t * @return the auth header\n\t * @since 3.5.0\n\t */\n\tdefault @Nullable String getAuthHeader(@Nullable ImageReference imageReference) {\n\t\treturn getAuthHeader();\n\t}\n\n\t/**\n\t * Returns the auth header that should be used for docker authentication.\n\t * @return the auth header\n\t */\n\t@Nullable String getAuthHeader();\n\n\t/**\n\t * Factory method to that returns a new {@link DockerRegistryAuthentication} instance\n\t * that uses a header generated by base64 encoding a JSON payload created from the\n\t * given parameters.\n\t * @param identityToken the identity token JSON field\n\t * @return a new {@link DockerRegistryAuthentication} instance\n\t * @since 3.5.0\n\t */\n\tstatic DockerRegistryAuthentication token(String identityToken) {\n\t\treturn new DockerRegistryTokenAuthentication(identityToken);\n\t}\n\n\t/**\n\t * Factory method to that returns a new {@link DockerRegistryAuthentication} instance\n\t * that uses a header generated by base64 encoding a JSON payload created from the\n\t * given parameters.\n\t * @param username the username JSON field\n\t * @param password the password JSON field\n\t * @param serverAddress the server address JSON field\n\t * @param email the email JSON field\n\t * @return a new {@link DockerRegistryAuthentication} instance\n\t * @since 3.5.0\n\t */\n\tstatic DockerRegistryAuthentication user(String username, String password, @Nullable String serverAddress,\n\t\t\t@Nullable String email) {\n\t\treturn new DockerRegistryUserAuthentication(username, password, serverAddress, email);\n\t}\n\n\t/**\n\t * Factory method that returns a new {@link DockerRegistryAuthentication} instance\n\t * that uses the standard docker JSON config (including support for credential\n\t * helpers) to generate auth headers.\n\t * @param fallback the fallback authentication to use if no suitable config is found,\n\t * may be {@code null}\n\t * @return a new {@link DockerRegistryAuthentication} instance\n\t * @since 3.5.0\n\t * @see #configuration(DockerRegistryAuthentication, BiConsumer)\n\t */\n\tstatic DockerRegistryAuthentication configuration(@Nullable DockerRegistryAuthentication fallback) {\n\t\treturn configuration(fallback, (message, ex) -> System.out.println(message));\n\t}\n\n\t/**\n\t * Factory method that returns a new {@link DockerRegistryAuthentication} instance\n\t * that uses the standard docker JSON config (including support for credential\n\t * helpers) to generate auth headers.\n\t * @param fallback the fallback authentication to use if no suitable config is found,\n\t * may be {@code null}\n\t * @param credentialHelperExceptionHandler callback that should handle credential\n\t * helper exceptions, never {@code null}\n\t * @return a new {@link DockerRegistryAuthentication} instance\n\t * @since 3.5.0\n\t * @see #configuration(DockerRegistryAuthentication, BiConsumer)\n\t */\n\tstatic DockerRegistryAuthentication configuration(@Nullable DockerRegistryAuthentication fallback,\n\t\t\tBiConsumer<String, Exception> credentialHelperExceptionHandler) {\n\t\tAssert.notNull(credentialHelperExceptionHandler, () -> \"'credentialHelperExceptionHandler' must not be null\");\n\t\treturn new DockerRegistryConfigAuthentication(fallback, credentialHelperExceptionHandler);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfigAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConfigurationMetadata.Auth;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConfigurationMetadata.DockerConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.system.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link DockerRegistryAuthentication} for\n * {@link DockerRegistryAuthentication#configuration(DockerRegistryAuthentication, BiConsumer)}.\n *\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\nclass DockerRegistryConfigAuthentication implements DockerRegistryAuthentication {\n\n\tprivate static final String DEFAULT_DOMAIN = \"docker.io\";\n\n\tprivate static final String INDEX_URL = \"https://index.docker.io/v1/\";\n\n\tstatic Map<String, Credential> credentialFromHelperCache = new ConcurrentHashMap<>();\n\n\tprivate final @Nullable DockerRegistryAuthentication fallback;\n\n\tprivate final BiConsumer<String, Exception> credentialHelperExceptionHandler;\n\n\tprivate final Function<String, @Nullable CredentialHelper> credentialHelperFactory;\n\n\tprivate final DockerConfig dockerConfig;\n\n\tDockerRegistryConfigAuthentication(@Nullable DockerRegistryAuthentication fallback,\n\t\t\tBiConsumer<String, Exception> credentialHelperExceptionHandler) {\n\t\tthis(fallback, credentialHelperExceptionHandler, Environment.SYSTEM,\n\t\t\t\t(helper) -> new CredentialHelper(\"docker-credential-\" + helper));\n\t}\n\n\tDockerRegistryConfigAuthentication(@Nullable DockerRegistryAuthentication fallback,\n\t\t\tBiConsumer<String, Exception> credentialHelperExceptionHandler, Environment environment,\n\t\t\tFunction<String, @Nullable CredentialHelper> credentialHelperFactory) {\n\t\tthis.fallback = fallback;\n\t\tthis.credentialHelperExceptionHandler = credentialHelperExceptionHandler;\n\t\tthis.dockerConfig = DockerConfigurationMetadata.from(environment).getConfiguration();\n\t\tthis.credentialHelperFactory = credentialHelperFactory;\n\t}\n\n\t@Override\n\tpublic @Nullable String getAuthHeader() {\n\t\treturn getAuthHeader(null);\n\t}\n\n\t@Override\n\tpublic @Nullable String getAuthHeader(@Nullable ImageReference imageReference) {\n\t\tString serverUrl = getServerUrl(imageReference);\n\t\tDockerRegistryAuthentication authentication = getAuthentication(serverUrl);\n\t\treturn (authentication != null) ? authentication.getAuthHeader(imageReference) : null;\n\t}\n\n\tprivate @Nullable String getServerUrl(@Nullable ImageReference imageReference) {\n\t\tString domain = (imageReference != null) ? imageReference.getDomain() : null;\n\t\treturn (!DEFAULT_DOMAIN.equals(domain)) ? domain : INDEX_URL;\n\t}\n\n\tprivate @Nullable DockerRegistryAuthentication getAuthentication(@Nullable String serverUrl) {\n\t\tCredential credentialsFromHelper = getCredentialsFromHelper(serverUrl);\n\t\tMap.Entry<String, Auth> authConfigEntry = getAuthConfigEntry(serverUrl);\n\t\tAuth authConfig = (authConfigEntry != null) ? authConfigEntry.getValue() : null;\n\t\tif (credentialsFromHelper != null) {\n\t\t\treturn getAuthentication(credentialsFromHelper, authConfig, serverUrl);\n\t\t}\n\t\tif (authConfig != null) {\n\t\t\tAssert.state(authConfigEntry != null, \"'authConfigEntry' must not be null\");\n\t\t\tString username = authConfig.getUsername();\n\t\t\tString password = authConfig.getPassword();\n\t\t\tAssert.state(username != null, \"'username' must not be null\");\n\t\t\tAssert.state(password != null, \"'password' must not be null\");\n\t\t\treturn DockerRegistryAuthentication.user(username, password, authConfigEntry.getKey(),\n\t\t\t\t\tauthConfig.getEmail());\n\t\t}\n\t\treturn this.fallback;\n\t}\n\n\tprivate DockerRegistryAuthentication getAuthentication(Credential credentialsFromHelper, @Nullable Auth authConfig,\n\t\t\t@Nullable String serverUrl) {\n\t\tif (credentialsFromHelper.isIdentityToken()) {\n\t\t\treturn DockerRegistryAuthentication.token(credentialsFromHelper.getSecret());\n\t\t}\n\t\tString username = credentialsFromHelper.getUsername();\n\t\tString password = credentialsFromHelper.getSecret();\n\t\tString serverAddress = (StringUtils.hasLength(credentialsFromHelper.getServerUrl()))\n\t\t\t\t? credentialsFromHelper.getServerUrl() : serverUrl;\n\t\tString email = (authConfig != null) ? authConfig.getEmail() : null;\n\t\treturn DockerRegistryAuthentication.user(username, password, serverAddress, email);\n\t}\n\n\tprivate @Nullable Credential getCredentialsFromHelper(@Nullable String serverUrl) {\n\t\treturn StringUtils.hasLength(serverUrl)\n\t\t\t\t? credentialFromHelperCache.computeIfAbsent(serverUrl, this::computeCredentialsFromHelper) : null;\n\t}\n\n\tprivate @Nullable Credential computeCredentialsFromHelper(String serverUrl) {\n\t\tCredentialHelper credentialHelper = getCredentialHelper(serverUrl);\n\t\tif (credentialHelper != null) {\n\t\t\ttry {\n\t\t\t\treturn credentialHelper.get(serverUrl);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tString message = \"Error retrieving credentials for '%s' due to: %s\".formatted(serverUrl,\n\t\t\t\t\t\tex.getMessage());\n\t\t\t\tthis.credentialHelperExceptionHandler.accept(message, ex);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable CredentialHelper getCredentialHelper(String serverUrl) {\n\t\tString name = this.dockerConfig.getCredHelpers().getOrDefault(serverUrl, this.dockerConfig.getCredsStore());\n\t\treturn (StringUtils.hasLength(name)) ? this.credentialHelperFactory.apply(name) : null;\n\t}\n\n\tprivate Map.@Nullable Entry<String, Auth> getAuthConfigEntry(@Nullable String serverUrl) {\n\t\tif (serverUrl == null) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (Map.Entry<String, Auth> candidate : this.dockerConfig.getAuths().entrySet()) {\n\t\t\tif (candidate.getKey().equals(serverUrl) || candidate.getKey().endsWith(\"://\" + serverUrl)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryTokenAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\n/**\n * {@link DockerRegistryAuthentication} for\n * {@link DockerRegistryAuthentication#user(String, String, String, String)}.\n *\n * @author Scott Frederick\n */\nclass DockerRegistryTokenAuthentication extends JsonEncodedDockerRegistryAuthentication {\n\n\t@JsonProperty(\"identitytoken\")\n\tprivate final String token;\n\n\tDockerRegistryTokenAuthentication(String token) {\n\t\tthis.token = token;\n\t\tcreateAuthHeader();\n\t}\n\n\tString getToken() {\n\t\treturn this.token;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryUserAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link DockerRegistryAuthentication} for\n * {@link DockerRegistryAuthentication#token(String)}.\n *\n * @author Scott Frederick\n */\nclass DockerRegistryUserAuthentication extends JsonEncodedDockerRegistryAuthentication {\n\n\t@JsonProperty\n\tprivate final String username;\n\n\t@JsonProperty\n\tprivate final String password;\n\n\t@JsonProperty(\"serveraddress\")\n\tprivate final @Nullable String url;\n\n\t@JsonProperty\n\tprivate final @Nullable String email;\n\n\tDockerRegistryUserAuthentication(String username, String password, @Nullable String url, @Nullable String email) {\n\t\tthis.username = username;\n\t\tthis.password = password;\n\t\tthis.url = url;\n\t\tthis.email = email;\n\t\tcreateAuthHeader();\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\t@Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\t@Nullable String getEmail() {\n\t\treturn this.email;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/JsonEncodedDockerRegistryAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.util.Base64;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JacksonException;\n\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\n\n/**\n * {@link DockerRegistryAuthentication} that uses a Base64 encoded auth header value based\n * on the JSON created from the instance.\n *\n * @author Scott Frederick\n */\nclass JsonEncodedDockerRegistryAuthentication implements DockerRegistryAuthentication {\n\n\t@JsonIgnore\n\tprivate @Nullable String authHeader;\n\n\t@Override\n\tpublic @Nullable String getAuthHeader() {\n\t\treturn this.authHeader;\n\t}\n\n\tprotected void createAuthHeader() {\n\t\ttry {\n\t\t\tthis.authHeader = Base64.getUrlEncoder().encodeToString(SharedJsonMapper.get().writeValueAsBytes(this));\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\tthrow new IllegalStateException(\"Error creating Docker registry authentication header\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/ResolvedDockerHost.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\nimport com.sun.jna.Platform;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConfigurationMetadata.DockerContext;\nimport org.springframework.boot.buildpack.platform.system.Environment;\n\n/**\n * Resolves a {@link DockerHost} from the environment, configuration, or using defaults.\n *\n * @author Scott Frederick\n * @since 2.7.0\n */\npublic class ResolvedDockerHost extends DockerHost {\n\n\tprivate static final String UNIX_SOCKET_PREFIX = \"unix://\";\n\n\tprivate static final String DOMAIN_SOCKET_PATH = \"/var/run/docker.sock\";\n\n\tprivate static final String WINDOWS_NAMED_PIPE_PATH = \"//./pipe/docker_engine\";\n\n\tprivate static final String DOCKER_HOST = \"DOCKER_HOST\";\n\n\tprivate static final String DOCKER_TLS_VERIFY = \"DOCKER_TLS_VERIFY\";\n\n\tprivate static final String DOCKER_CERT_PATH = \"DOCKER_CERT_PATH\";\n\n\tprivate static final String DOCKER_CONTEXT = \"DOCKER_CONTEXT\";\n\n\tResolvedDockerHost(@Nullable String address) {\n\t\tsuper(address);\n\t}\n\n\tResolvedDockerHost(@Nullable String address, boolean secure, @Nullable String certificatePath) {\n\t\tsuper(address, secure, certificatePath);\n\t}\n\n\t@Override\n\tpublic String getAddress() {\n\t\tString address = super.getAddress();\n\t\tif (address == null) {\n\t\t\treturn getDefaultAddress();\n\t\t}\n\t\tif (address.startsWith(UNIX_SOCKET_PREFIX)) {\n\t\t\treturn address.substring(UNIX_SOCKET_PREFIX.length());\n\t\t}\n\t\tif (address.startsWith(\"tcp://\")) {\n\t\t\twhile (address.endsWith(\"/\")) {\n\t\t\t\taddress = address.substring(0, address.length() - 1);\n\t\t\t}\n\t\t}\n\t\treturn address;\n\t}\n\n\tpublic boolean isRemote() {\n\t\treturn getAddress().startsWith(\"http\") || getAddress().startsWith(\"tcp\");\n\t}\n\n\tpublic boolean isLocalFileReference() {\n\t\ttry {\n\t\t\treturn Files.exists(Paths.get(getAddress()));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Create a new {@link ResolvedDockerHost} from the given host configuration.\n\t * @param connectionConfiguration the host configuration or {@code null}\n\t * @return the resolved docker host\n\t */\n\tpublic static ResolvedDockerHost from(@Nullable DockerConnectionConfiguration connectionConfiguration) {\n\t\treturn from(Environment.SYSTEM, connectionConfiguration);\n\t}\n\n\tstatic ResolvedDockerHost from(Environment environment,\n\t\t\t@Nullable DockerConnectionConfiguration connectionConfiguration) {\n\t\tDockerConfigurationMetadata environmentConfiguration = DockerConfigurationMetadata.from(environment);\n\t\tif (environment.get(DOCKER_CONTEXT) != null) {\n\t\t\tDockerContext context = environmentConfiguration.forContext(environment.get(DOCKER_CONTEXT));\n\t\t\treturn new ResolvedDockerHost(context.getDockerHost(), context.isTlsVerify(), context.getTlsPath());\n\t\t}\n\t\tif (connectionConfiguration instanceof DockerConnectionConfiguration.Context contextConfiguration) {\n\t\t\tDockerContext context = environmentConfiguration.forContext(contextConfiguration.context());\n\t\t\treturn new ResolvedDockerHost(context.getDockerHost(), context.isTlsVerify(), context.getTlsPath());\n\t\t}\n\t\tif (environment.get(DOCKER_HOST) != null) {\n\t\t\treturn new ResolvedDockerHost(environment.get(DOCKER_HOST), isTrue(environment.get(DOCKER_TLS_VERIFY)),\n\t\t\t\t\tenvironment.get(DOCKER_CERT_PATH));\n\t\t}\n\t\tif (connectionConfiguration instanceof DockerConnectionConfiguration.Host addressConfiguration) {\n\t\t\treturn new ResolvedDockerHost(addressConfiguration.address(), addressConfiguration.secure(),\n\t\t\t\t\taddressConfiguration.certificatePath());\n\t\t}\n\t\tif (environmentConfiguration.getContext().getDockerHost() != null) {\n\t\t\tDockerContext context = environmentConfiguration.getContext();\n\t\t\treturn new ResolvedDockerHost(context.getDockerHost(), context.isTlsVerify(), context.getTlsPath());\n\t\t}\n\t\treturn new ResolvedDockerHost(getDefaultAddress());\n\t}\n\n\tprivate static String getDefaultAddress() {\n\t\treturn Platform.isWindows() ? WINDOWS_NAMED_PIPE_PATH : DOMAIN_SOCKET_PATH;\n\t}\n\n\tprivate static boolean isTrue(@Nullable String value) {\n\t\ttry {\n\t\t\treturn (value != null) && (Integer.parseInt(value) == 1);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/configuration/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Docker configuration options.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A limited Docker API providing the operations needed by pack.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ssl/KeyStoreFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Utility methods for creating Java trust material from key and certificate files.\n *\n * @author Scott Frederick\n */\nfinal class KeyStoreFactory {\n\n\tprivate static final char[] NO_PASSWORD = {};\n\n\tprivate KeyStoreFactory() {\n\t}\n\n\t/**\n\t * Create a new {@link KeyStore} populated with the certificate stored at the\n\t * specified file path and an optional private key.\n\t * @param certPath the path to the certificate authority file\n\t * @param keyPath the path to the private file\n\t * @param alias the alias to use for KeyStore entries\n\t * @return the {@code KeyStore}\n\t */\n\tstatic KeyStore create(Path certPath, @Nullable Path keyPath, String alias) {\n\t\ttry {\n\t\t\tKeyStore keyStore = getKeyStore();\n\t\t\tString certificateText = Files.readString(certPath);\n\t\t\tList<X509Certificate> certificates = PemCertificateParser.parse(certificateText);\n\t\t\tPrivateKey privateKey = getPrivateKey(keyPath);\n\t\t\ttry {\n\t\t\t\taddCertificates(keyStore, certificates.toArray(X509Certificate[]::new), privateKey, alias);\n\t\t\t}\n\t\t\tcatch (KeyStoreException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Error adding certificates to KeyStore: \" + ex.getMessage(), ex);\n\t\t\t}\n\t\t\treturn keyStore;\n\t\t}\n\t\tcatch (GeneralSecurityException | IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Error creating KeyStore: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate static KeyStore getKeyStore()\n\t\t\tthrows KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {\n\t\tKeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\tkeyStore.load(null);\n\t\treturn keyStore;\n\t}\n\n\tprivate static @Nullable PrivateKey getPrivateKey(@Nullable Path path) throws IOException {\n\t\tif (path != null && Files.exists(path)) {\n\t\t\tString text = Files.readString(path);\n\t\t\treturn PemPrivateKeyParser.parse(text);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static void addCertificates(KeyStore keyStore, X509Certificate[] certificates,\n\t\t\t@Nullable PrivateKey privateKey, String alias) throws KeyStoreException {\n\t\tif (privateKey != null) {\n\t\t\tkeyStore.setKeyEntry(alias, privateKey, NO_PASSWORD, certificates);\n\t\t}\n\t\telse {\n\t\t\tfor (int index = 0; index < certificates.length; index++) {\n\t\t\t\tkeyStore.setCertificateEntry(alias + \"-\" + index, certificates[index]);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ssl/PemCertificateParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.ByteArrayInputStream;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Parser for X.509 certificates in PEM format.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nfinal class PemCertificateParser {\n\n\tprivate static final String HEADER = \"-+BEGIN\\\\s+.*CERTIFICATE[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String BASE64_TEXT = \"([a-z0-9+/=\\\\r\\\\n]+)\";\n\n\tprivate static final String FOOTER = \"-+END\\\\s+.*CERTIFICATE[^-]*-+\";\n\n\tprivate static final Pattern PATTERN = Pattern.compile(HEADER + BASE64_TEXT + FOOTER, Pattern.CASE_INSENSITIVE);\n\n\tprivate PemCertificateParser() {\n\t}\n\n\t/**\n\t * Parse certificates from the specified string.\n\t * @param text the text to parse\n\t * @return the parsed certificates\n\t */\n\t@Contract(\"!null -> !null\")\n\tstatic @Nullable List<X509Certificate> parse(@Nullable String text) {\n\t\tif (text == null) {\n\t\t\treturn null;\n\t\t}\n\t\tCertificateFactory factory = getCertificateFactory();\n\t\tList<X509Certificate> certs = new ArrayList<>();\n\t\treadCertificates(text, factory, certs::add);\n\t\tAssert.state(!CollectionUtils.isEmpty(certs), \"Missing certificates or unrecognized format\");\n\t\treturn List.copyOf(certs);\n\t}\n\n\tprivate static CertificateFactory getCertificateFactory() {\n\t\ttry {\n\t\t\treturn CertificateFactory.getInstance(\"X.509\");\n\t\t}\n\t\tcatch (CertificateException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to get X.509 certificate factory\", ex);\n\t\t}\n\t}\n\n\tprivate static void readCertificates(String text, CertificateFactory factory, Consumer<X509Certificate> consumer) {\n\t\ttry {\n\t\t\tMatcher matcher = PATTERN.matcher(text);\n\t\t\twhile (matcher.find()) {\n\t\t\t\tString encodedText = matcher.group(1);\n\t\t\t\tbyte[] decodedBytes = decodeBase64(encodedText);\n\t\t\t\tByteArrayInputStream inputStream = new ByteArrayInputStream(decodedBytes);\n\t\t\t\twhile (inputStream.available() > 0) {\n\t\t\t\t\tconsumer.accept((X509Certificate) factory.generateCertificate(inputStream));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (CertificateException ex) {\n\t\t\tthrow new IllegalStateException(\"Error reading certificate: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate static byte[] decodeBase64(String content) {\n\t\tbyte[] bytes = content.replace(\"\\r\", \"\").replace(\"\\n\", \"\").getBytes();\n\t\treturn Base64.getDecoder().decode(bytes);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ssl/PemPrivateKeyParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.security.AlgorithmParameters;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HexFormat;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiFunction;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.EncryptedPrivateKeyInfo;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.PBEKeySpec;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.ssl.PemPrivateKeyParser.DerElement.TagType;\nimport org.springframework.boot.buildpack.platform.docker.ssl.PemPrivateKeyParser.DerElement.ValueType;\nimport org.springframework.util.Assert;\n\n/**\n * Parser for PKCS private key files in PEM format.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nfinal class PemPrivateKeyParser {\n\n\tprivate static final String PKCS1_RSA_HEADER = \"-+BEGIN\\\\s+RSA\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String PKCS1_RSA_FOOTER = \"-+END\\\\s+RSA\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String PKCS8_HEADER = \"-+BEGIN\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String PKCS8_FOOTER = \"-+END\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String PKCS8_ENCRYPTED_HEADER = \"-+BEGIN\\\\s+ENCRYPTED\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String PKCS8_ENCRYPTED_FOOTER = \"-+END\\\\s+ENCRYPTED\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String SEC1_EC_HEADER = \"-+BEGIN\\\\s+EC\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String SEC1_EC_FOOTER = \"-+END\\\\s+EC\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String BASE64_TEXT = \"([a-z0-9+/=\\\\r\\\\n]+)\";\n\n\tpublic static final int BASE64_TEXT_GROUP = 1;\n\n\tprivate static final EncodedOid RSA_ALGORITHM = EncodedOid.OID_1_2_840_113549_1_1_1;\n\n\tprivate static final EncodedOid ELLIPTIC_CURVE_ALGORITHM = EncodedOid.OID_1_2_840_10045_2_1;\n\n\tprivate static final EncodedOid ELLIPTIC_CURVE_384_BIT = EncodedOid.OID_1_3_132_0_34;\n\n\tprivate static final Map<EncodedOid, String> ALGORITHMS;\n\tstatic {\n\t\tMap<EncodedOid, String> algorithms = new HashMap<>();\n\t\talgorithms.put(EncodedOid.OID_1_2_840_113549_1_1_1, \"RSA\");\n\t\talgorithms.put(EncodedOid.OID_1_2_840_113549_1_1_10, \"RSA\");\n\t\talgorithms.put(EncodedOid.OID_1_2_840_10040_4_1, \"DSA\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_110, \"XDH\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_111, \"XDH\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_112, \"EdDSA\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_113, \"EdDSA\");\n\t\talgorithms.put(EncodedOid.OID_1_2_840_10045_2_1, \"EC\");\n\t\tALGORITHMS = Collections.unmodifiableMap(algorithms);\n\t}\n\n\tprivate static final List<PemParser> PEM_PARSERS;\n\tstatic {\n\t\tList<PemParser> parsers = new ArrayList<>();\n\t\tparsers.add(new PemParser(PKCS1_RSA_HEADER, PKCS1_RSA_FOOTER, PemPrivateKeyParser::createKeySpecForPkcs1Rsa,\n\t\t\t\t\"RSA\"));\n\t\tparsers.add(new PemParser(SEC1_EC_HEADER, SEC1_EC_FOOTER, PemPrivateKeyParser::createKeySpecForSec1Ec, \"EC\"));\n\t\tparsers.add(new PemParser(PKCS8_HEADER, PKCS8_FOOTER, PemPrivateKeyParser::createKeySpecForPkcs8, \"RSA\",\n\t\t\t\t\"RSASSA-PSS\", \"EC\", \"DSA\", \"EdDSA\", \"XDH\"));\n\t\tparsers.add(new PemParser(PKCS8_ENCRYPTED_HEADER, PKCS8_ENCRYPTED_FOOTER,\n\t\t\t\tPemPrivateKeyParser::createKeySpecForPkcs8Encrypted, \"RSA\", \"RSASSA-PSS\", \"EC\", \"DSA\", \"EdDSA\", \"XDH\"));\n\t\tPEM_PARSERS = Collections.unmodifiableList(parsers);\n\t}\n\n\tprivate PemPrivateKeyParser() {\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForPkcs1Rsa(byte[] bytes, @Nullable String password) {\n\t\treturn createKeySpecForAlgorithm(bytes, RSA_ALGORITHM, null);\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForSec1Ec(byte[] bytes, @Nullable String password) {\n\t\tDerElement ecPrivateKey = DerElement.of(bytes);\n\t\tAssert.state(ecPrivateKey != null, \"Unable to find private key\");\n\t\tAssert.state(ecPrivateKey.isType(ValueType.ENCODED, TagType.SEQUENCE),\n\t\t\t\t\"Key spec should be an ASN.1 encoded sequence\");\n\t\tDerElement version = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(version != null && version.isType(ValueType.PRIMITIVE, TagType.INTEGER),\n\t\t\t\t\"Key spec should start with version\");\n\t\tAssert.state(version.getContents().remaining() == 1 && version.getContents().get() == 1,\n\t\t\t\t\"Key spec version must be 1\");\n\t\tDerElement privateKey = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(privateKey != null && privateKey.isType(ValueType.PRIMITIVE, TagType.OCTET_STRING),\n\t\t\t\t\"Key spec should contain private key\");\n\t\tDerElement parameters = DerElement.of(ecPrivateKey.getContents());\n\t\treturn createKeySpecForAlgorithm(bytes, ELLIPTIC_CURVE_ALGORITHM, getEcParameters(parameters));\n\t}\n\n\tprivate static EncodedOid getEcParameters(@Nullable DerElement parameters) {\n\t\tif (parameters == null) {\n\t\t\treturn ELLIPTIC_CURVE_384_BIT;\n\t\t}\n\t\tAssert.state(parameters.isType(ValueType.ENCODED), \"Key spec should contain encoded parameters\");\n\t\tDerElement contents = DerElement.of(parameters.getContents());\n\t\tAssert.state(contents != null && contents.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),\n\t\t\t\t\"Key spec parameters should contain object identifier\");\n\t\treturn EncodedOid.of(contents);\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, EncodedOid algorithm,\n\t\t\t@Nullable EncodedOid parameters) {\n\t\ttry {\n\t\t\tDerEncoder encoder = new DerEncoder();\n\t\t\tencoder.integer(0x00); // Version 0\n\t\t\tDerEncoder algorithmIdentifier = new DerEncoder();\n\t\t\talgorithmIdentifier.objectIdentifier(algorithm);\n\t\t\talgorithmIdentifier.objectIdentifier(parameters);\n\t\t\tencoder.sequence(algorithmIdentifier.toByteArray());\n\t\t\tencoder.octetString(bytes);\n\t\t\treturn new PKCS8EncodedKeySpec(encoder.toSequence());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForPkcs8(byte[] bytes, @Nullable String password) {\n\t\tDerElement ecPrivateKey = DerElement.of(bytes);\n\t\tAssert.state(ecPrivateKey != null, \"Unable to find private key\");\n\t\tAssert.state(ecPrivateKey.isType(ValueType.ENCODED, TagType.SEQUENCE),\n\t\t\t\t\"Key spec should be an ASN.1 encoded sequence\");\n\t\tDerElement version = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(version != null && version.isType(ValueType.PRIMITIVE, TagType.INTEGER),\n\t\t\t\t\"Key spec should start with version\");\n\t\tDerElement sequence = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(sequence != null && sequence.isType(ValueType.ENCODED, TagType.SEQUENCE),\n\t\t\t\t\"Key spec should contain private key\");\n\t\tDerElement algorithmId = DerElement.of(sequence.getContents());\n\t\tAssert.state(algorithmId != null && algorithmId.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),\n\t\t\t\t\"Key spec container object identifier\");\n\t\tString algorithmName = ALGORITHMS.get(EncodedOid.of(algorithmId));\n\t\treturn (algorithmName != null) ? new PKCS8EncodedKeySpec(bytes, algorithmName) : new PKCS8EncodedKeySpec(bytes);\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForPkcs8Encrypted(byte[] bytes, @Nullable String password) {\n\t\treturn Pkcs8PrivateKeyDecryptor.decrypt(bytes, password);\n\t}\n\n\t/**\n\t * Parse a private key from the specified string.\n\t * @param text the text to parse\n\t * @return the parsed private key\n\t */\n\tstatic @Nullable PrivateKey parse(String text) {\n\t\treturn parse(text, null);\n\t}\n\n\t/**\n\t * Parse a private key from the specified string, using the provided password for\n\t * decryption if necessary.\n\t * @param text the text to parse\n\t * @param password the password used to decrypt an encrypted private key\n\t * @return the parsed private key\n\t */\n\tstatic @Nullable PrivateKey parse(@Nullable String text, @Nullable String password) {\n\t\tif (text == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tfor (PemParser pemParser : PEM_PARSERS) {\n\t\t\t\tPrivateKey privateKey = pemParser.parse(text, password);\n\t\t\t\tif (privateKey != null) {\n\t\t\t\t\treturn privateKey;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Error loading private key file: \" + ex.getMessage(), ex);\n\t\t}\n\t\tthrow new IllegalStateException(\"Missing private key or unrecognized format\");\n\t}\n\n\t/**\n\t * Parser for a specific PEM format.\n\t */\n\tprivate static class PemParser {\n\n\t\tprivate final Pattern pattern;\n\n\t\tprivate final BiFunction<byte[], @Nullable String, PKCS8EncodedKeySpec> keySpecFactory;\n\n\t\tprivate final String[] algorithms;\n\n\t\tPemParser(String header, String footer,\n\t\t\t\tBiFunction<byte[], @Nullable String, PKCS8EncodedKeySpec> keySpecFactory, String... algorithms) {\n\t\t\tthis.pattern = Pattern.compile(header + BASE64_TEXT + footer, Pattern.CASE_INSENSITIVE);\n\t\t\tthis.keySpecFactory = keySpecFactory;\n\t\t\tthis.algorithms = algorithms;\n\t\t}\n\n\t\t@Nullable PrivateKey parse(String text, @Nullable String password) {\n\t\t\tMatcher matcher = this.pattern.matcher(text);\n\t\t\treturn (!matcher.find()) ? null : parse(decodeBase64(matcher.group(BASE64_TEXT_GROUP)), password);\n\t\t}\n\n\t\tprivate static byte[] decodeBase64(String content) {\n\t\t\tbyte[] contentBytes = content.replace(\"\\r\", \"\").replace(\"\\n\", \"\").getBytes();\n\t\t\treturn Base64.getDecoder().decode(contentBytes);\n\t\t}\n\n\t\tprivate @Nullable PrivateKey parse(byte[] bytes, @Nullable String password) {\n\t\t\tPKCS8EncodedKeySpec keySpec = this.keySpecFactory.apply(bytes, password);\n\t\t\tif (keySpec.getAlgorithm() != null) {\n\t\t\t\ttry {\n\t\t\t\t\tKeyFactory keyFactory = KeyFactory.getInstance(keySpec.getAlgorithm());\n\t\t\t\t\treturn keyFactory.generatePrivate(keySpec);\n\t\t\t\t}\n\t\t\t\tcatch (InvalidKeySpecException | NoSuchAlgorithmException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (String algorithm : this.algorithms) {\n\t\t\t\ttry {\n\t\t\t\t\tKeyFactory keyFactory = KeyFactory.getInstance(algorithm);\n\t\t\t\t\treturn keyFactory.generatePrivate(keySpec);\n\t\t\t\t}\n\t\t\t\tcatch (InvalidKeySpecException | NoSuchAlgorithmException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Simple ASN.1 DER encoder.\n\t */\n\tstatic class DerEncoder {\n\n\t\tprivate final ByteArrayOutputStream stream = new ByteArrayOutputStream();\n\n\t\tvoid objectIdentifier(@Nullable EncodedOid encodedOid) throws IOException {\n\t\t\tint code = (encodedOid != null) ? 0x06 : 0x05;\n\t\t\tcodeLengthBytes(code, (encodedOid != null) ? encodedOid.toByteArray() : null);\n\t\t}\n\n\t\tvoid integer(int... encodedInteger) throws IOException {\n\t\t\tcodeLengthBytes(0x02, bytes(encodedInteger));\n\t\t}\n\n\t\tvoid octetString(byte[] bytes) throws IOException {\n\t\t\tcodeLengthBytes(0x04, bytes);\n\t\t}\n\n\t\tvoid sequence(byte[] bytes) throws IOException {\n\t\t\tcodeLengthBytes(0x30, bytes);\n\t\t}\n\n\t\tvoid codeLengthBytes(int code, byte @Nullable [] bytes) throws IOException {\n\t\t\tthis.stream.write(code);\n\t\t\tint length = (bytes != null) ? bytes.length : 0;\n\t\t\tif (length <= 127) {\n\t\t\t\tthis.stream.write(length & 0xFF);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tByteArrayOutputStream lengthStream = new ByteArrayOutputStream();\n\t\t\t\twhile (length != 0) {\n\t\t\t\t\tlengthStream.write(length & 0xFF);\n\t\t\t\t\tlength = length >> 8;\n\t\t\t\t}\n\t\t\t\tbyte[] lengthBytes = lengthStream.toByteArray();\n\t\t\t\tthis.stream.write(0x80 | lengthBytes.length);\n\t\t\t\tfor (int i = lengthBytes.length - 1; i >= 0; i--) {\n\t\t\t\t\tthis.stream.write(lengthBytes[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bytes != null) {\n\t\t\t\tthis.stream.write(bytes);\n\t\t\t}\n\t\t}\n\n\t\tprivate static byte @Nullable [] bytes(int @Nullable ... elements) {\n\t\t\tif (elements == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tbyte[] result = new byte[elements.length];\n\t\t\tfor (int i = 0; i < elements.length; i++) {\n\t\t\t\tresult[i] = (byte) elements[i];\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tbyte[] toSequence() throws IOException {\n\t\t\tDerEncoder sequenceEncoder = new DerEncoder();\n\t\t\tsequenceEncoder.sequence(toByteArray());\n\t\t\treturn sequenceEncoder.toByteArray();\n\t\t}\n\n\t\tbyte[] toByteArray() {\n\t\t\treturn this.stream.toByteArray();\n\t\t}\n\n\t}\n\n\t/**\n\t * An ASN.1 DER encoded element.\n\t */\n\tstatic final class DerElement {\n\n\t\tprivate final ValueType valueType;\n\n\t\tprivate final long tagType;\n\n\t\tprivate final ByteBuffer contents;\n\n\t\tprivate DerElement(ByteBuffer bytes) {\n\t\t\tbyte b = bytes.get();\n\t\t\tthis.valueType = ((b & 0x20) == 0) ? ValueType.PRIMITIVE : ValueType.ENCODED;\n\t\t\tthis.tagType = decodeTagType(b, bytes);\n\t\t\tint length = decodeLength(bytes);\n\t\t\tbytes.limit(bytes.position() + length);\n\t\t\tthis.contents = bytes.slice();\n\t\t\tbytes.limit(bytes.capacity());\n\t\t\tbytes.position(bytes.position() + length);\n\t\t}\n\n\t\tprivate long decodeTagType(byte b, ByteBuffer bytes) {\n\t\t\tlong tagType = (b & 0x1F);\n\t\t\tif (tagType != 0x1F) {\n\t\t\t\treturn tagType;\n\t\t\t}\n\t\t\ttagType = 0;\n\t\t\tb = bytes.get();\n\t\t\twhile ((b & 0x80) != 0) {\n\t\t\t\ttagType <<= 7;\n\t\t\t\ttagType = tagType | (b & 0x7F);\n\t\t\t\tb = bytes.get();\n\t\t\t}\n\t\t\treturn tagType;\n\t\t}\n\n\t\tprivate int decodeLength(ByteBuffer bytes) {\n\t\t\tbyte b = bytes.get();\n\t\t\tif ((b & 0x80) == 0) {\n\t\t\t\treturn b & 0x7F;\n\t\t\t}\n\t\t\tint numberOfLengthBytes = (b & 0x7F);\n\t\t\tAssert.state(numberOfLengthBytes != 0, \"Infinite length encoding is not supported\");\n\t\t\tAssert.state(numberOfLengthBytes != 0x7F, \"Reserved length encoding is not supported\");\n\t\t\tAssert.state(numberOfLengthBytes <= 4, \"Length overflow\");\n\t\t\tint length = 0;\n\t\t\tfor (int i = 0; i < numberOfLengthBytes; i++) {\n\t\t\t\tlength <<= 8;\n\t\t\t\tlength |= (bytes.get() & 0xFF);\n\t\t\t}\n\t\t\treturn length;\n\t\t}\n\n\t\tboolean isType(ValueType valueType) {\n\t\t\treturn this.valueType == valueType;\n\t\t}\n\n\t\tboolean isType(ValueType valueType, TagType tagType) {\n\t\t\treturn this.valueType == valueType && this.tagType == tagType.getNumber();\n\t\t}\n\n\t\tByteBuffer getContents() {\n\t\t\treturn this.contents;\n\t\t}\n\n\t\tstatic @Nullable DerElement of(byte[] bytes) {\n\t\t\treturn of(ByteBuffer.wrap(bytes));\n\t\t}\n\n\t\tstatic @Nullable DerElement of(ByteBuffer bytes) {\n\t\t\treturn (bytes.remaining() > 0) ? new DerElement(bytes) : null;\n\t\t}\n\n\t\tenum ValueType {\n\n\t\t\tPRIMITIVE, ENCODED\n\n\t\t}\n\n\t\tenum TagType {\n\n\t\t\tINTEGER(0x02), OCTET_STRING(0x04), OBJECT_IDENTIFIER(0x06), SEQUENCE(0x10);\n\n\t\t\tprivate final int number;\n\n\t\t\tTagType(int number) {\n\t\t\t\tthis.number = number;\n\t\t\t}\n\n\t\t\tint getNumber() {\n\t\t\t\treturn this.number;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Decryptor for PKCS8 encoded private keys.\n\t */\n\tstatic class Pkcs8PrivateKeyDecryptor {\n\n\t\tpublic static final String PBES2_ALGORITHM = \"PBES2\";\n\n\t\tstatic PKCS8EncodedKeySpec decrypt(byte[] bytes, @Nullable String password) {\n\t\t\tAssert.state(password != null, \"Password is required for an encrypted private key\");\n\t\t\ttry {\n\t\t\t\tEncryptedPrivateKeyInfo keyInfo = new EncryptedPrivateKeyInfo(bytes);\n\t\t\t\tAlgorithmParameters algorithmParameters = keyInfo.getAlgParameters();\n\t\t\t\tString encryptionAlgorithm = getEncryptionAlgorithm(algorithmParameters, keyInfo.getAlgName());\n\t\t\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptionAlgorithm);\n\t\t\t\tSecretKey key = keyFactory.generateSecret(new PBEKeySpec(password.toCharArray()));\n\t\t\t\tCipher cipher = Cipher.getInstance(encryptionAlgorithm);\n\t\t\t\tcipher.init(Cipher.DECRYPT_MODE, key, algorithmParameters);\n\t\t\t\treturn keyInfo.getKeySpec(cipher);\n\t\t\t}\n\t\t\tcatch (IOException | GeneralSecurityException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Error decrypting private key\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate static String getEncryptionAlgorithm(@Nullable AlgorithmParameters algParameters, String algName) {\n\t\t\tif (algParameters != null && PBES2_ALGORITHM.equals(algName)) {\n\t\t\t\treturn algParameters.toString();\n\t\t\t}\n\t\t\treturn algName;\n\t\t}\n\n\t}\n\n\t/**\n\t * ANS.1 encoded object identifier.\n\t */\n\tstatic final class EncodedOid {\n\n\t\tstatic final EncodedOid OID_1_2_840_10040_4_1 = EncodedOid.of(\"2a8648ce380401\");\n\t\tstatic final EncodedOid OID_1_2_840_113549_1_1_1 = EncodedOid.of(\"2A864886F70D010101\");\n\t\tstatic final EncodedOid OID_1_2_840_113549_1_1_10 = EncodedOid.of(\"2a864886f70d01010a\");\n\t\tstatic final EncodedOid OID_1_3_101_110 = EncodedOid.of(\"2b656e\");\n\t\tstatic final EncodedOid OID_1_3_101_111 = EncodedOid.of(\"2b656f\");\n\t\tstatic final EncodedOid OID_1_3_101_112 = EncodedOid.of(\"2b6570\");\n\t\tstatic final EncodedOid OID_1_3_101_113 = EncodedOid.of(\"2b6571\");\n\t\tstatic final EncodedOid OID_1_2_840_10045_2_1 = EncodedOid.of(\"2a8648ce3d0201\");\n\t\tstatic final EncodedOid OID_1_3_132_0_34 = EncodedOid.of(\"2b81040022\");\n\n\t\tprivate final byte[] value;\n\n\t\tprivate EncodedOid(byte[] value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tbyte[] toByteArray() {\n\t\t\treturn this.value.clone();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn Arrays.equals(this.value, ((EncodedOid) obj).value);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Arrays.hashCode(this.value);\n\t\t}\n\n\t\tstatic EncodedOid of(String hexString) {\n\t\t\treturn of(HexFormat.of().parseHex(hexString));\n\t\t}\n\n\t\tstatic EncodedOid of(DerElement derElement) {\n\t\t\treturn of(derElement.getContents());\n\t\t}\n\n\t\tstatic EncodedOid of(ByteBuffer byteBuffer) {\n\t\t\treturn of(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining());\n\t\t}\n\n\t\tstatic EncodedOid of(byte[] bytes) {\n\t\t\treturn of(bytes, 0, bytes.length);\n\t\t}\n\n\t\tstatic EncodedOid of(byte[] bytes, int off, int len) {\n\t\t\tbyte[] value = new byte[len];\n\t\t\tSystem.arraycopy(bytes, off, value, 0, len);\n\t\t\treturn new EncodedOid(value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ssl/SslContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.springframework.util.Assert;\n\n/**\n * Builds an {@link SSLContext} for use with an HTTP connection.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class SslContextFactory {\n\n\tprivate static final char[] NO_PASSWORD = {};\n\n\tprivate static final String KEY_STORE_ALIAS = \"spring-boot-docker\";\n\n\tpublic SslContextFactory() {\n\t}\n\n\t/**\n\t * Create an {@link SSLContext} from files in the specified directory. The directory\n\t * must contain files with the names 'key.pem', 'cert.pem', and 'ca.pem'.\n\t * @param directory the path to a directory containing certificate and key files\n\t * @return the {@code SSLContext}\n\t */\n\tpublic SSLContext forDirectory(String directory) {\n\t\ttry {\n\t\t\tPath keyPath = Paths.get(directory, \"key.pem\");\n\t\t\tPath certPath = Paths.get(directory, \"cert.pem\");\n\t\t\tPath caPath = Paths.get(directory, \"ca.pem\");\n\t\t\tPath caKeyPath = Paths.get(directory, \"ca-key.pem\");\n\t\t\tverifyCertificateFiles(keyPath, certPath, caPath);\n\t\t\tKeyManagerFactory keyManagerFactory = getKeyManagerFactory(keyPath, certPath);\n\t\t\tTrustManagerFactory trustManagerFactory = getTrustManagerFactory(caPath, caKeyPath);\n\t\t\tSSLContext sslContext = SSLContext.getInstance(\"TLS\");\n\t\t\tsslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);\n\t\t\treturn sslContext;\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow ex;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate KeyManagerFactory getKeyManagerFactory(Path keyPath, Path certPath) throws Exception {\n\t\tKeyStore store = KeyStoreFactory.create(certPath, keyPath, KEY_STORE_ALIAS);\n\t\tKeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n\t\tfactory.init(store, NO_PASSWORD);\n\t\treturn factory;\n\t}\n\n\tprivate TrustManagerFactory getTrustManagerFactory(Path caPath, Path caKeyPath)\n\t\t\tthrows NoSuchAlgorithmException, KeyStoreException {\n\t\tKeyStore store = KeyStoreFactory.create(caPath, caKeyPath, KEY_STORE_ALIAS);\n\t\tTrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n\t\tfactory.init(store);\n\t\treturn factory;\n\t}\n\n\tprivate static void verifyCertificateFiles(Path... paths) {\n\t\tfor (Path path : paths) {\n\t\t\tAssert.state(Files.exists(path) && Files.isRegularFile(path),\n\t\t\t\t\t\"Certificate path must contain the files 'ca.pem', 'cert.pem', and 'key.pem' files\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utilities and classes for managing SSL context and keys.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/DockerConnectionException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Exception thrown when connection to the Docker daemon fails.\n *\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class DockerConnectionException extends RuntimeException {\n\n\tprivate static final String JNA_EXCEPTION_CLASS_NAME = \"com.sun.jna.LastErrorException\";\n\n\tpublic DockerConnectionException(String host, Exception cause) {\n\t\tsuper(buildMessage(host, cause), cause);\n\t}\n\n\tprivate static String buildMessage(String host, Exception cause) {\n\t\tAssert.notNull(host, \"'host' must not be null\");\n\t\tAssert.notNull(cause, \"'cause' must not be null\");\n\t\tStringBuilder message = new StringBuilder(\"Connection to the Docker daemon at '\" + host + \"' failed\");\n\t\tString causeMessage = getCauseMessage(cause);\n\t\tif (StringUtils.hasText(causeMessage)) {\n\t\t\tmessage.append(\" with error \\\"\").append(causeMessage).append(\"\\\"\");\n\t\t}\n\t\tmessage.append(\"; ensure the Docker daemon is running and accessible\");\n\t\treturn message.toString();\n\t}\n\n\tprivate static @Nullable String getCauseMessage(Exception cause) {\n\t\tif (cause.getCause() != null && cause.getCause().getClass().getName().equals(JNA_EXCEPTION_CLASS_NAME)) {\n\t\t\treturn cause.getCause().getMessage();\n\t\t}\n\t\treturn cause.getMessage();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/DockerEngineException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.net.URI;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.hc.core5.http.HttpStatus;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Exception thrown when a call to the Docker API fails.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Siva Sai Udayagiri\n * @since 2.3.0\n */\npublic class DockerEngineException extends RuntimeException {\n\n\tprivate final int statusCode;\n\n\tprivate final @Nullable String reasonPhrase;\n\n\tprivate final @Nullable Errors errors;\n\n\tprivate final @Nullable Message responseMessage;\n\n\tpublic DockerEngineException(String host, URI uri, int statusCode, @Nullable String reasonPhrase,\n\t\t\t@Nullable Errors errors, @Nullable Message responseMessage, byte @Nullable [] content) {\n\t\tsuper(buildMessage(host, uri, statusCode, reasonPhrase, errors, responseMessage, content));\n\t\tthis.statusCode = statusCode;\n\t\tthis.reasonPhrase = reasonPhrase;\n\t\tthis.errors = errors;\n\t\tthis.responseMessage = responseMessage;\n\t}\n\n\t/**\n\t * Return the status code returned by the Docker API.\n\t * @return the statusCode the status code\n\t */\n\tpublic int getStatusCode() {\n\t\treturn this.statusCode;\n\t}\n\n\t/**\n\t * Return the reason phrase returned by the Docker API.\n\t * @return the reasonPhrase\n\t */\n\tpublic @Nullable String getReasonPhrase() {\n\t\treturn this.reasonPhrase;\n\t}\n\n\t/**\n\t * Return the errors from the body of the Docker API response, or {@code null} if the\n\t * errors JSON could not be read.\n\t * @return the errors or {@code null}\n\t */\n\tpublic @Nullable Errors getErrors() {\n\t\treturn this.errors;\n\t}\n\n\t/**\n\t * Return the message from the body of the Docker API response, or {@code null} if the\n\t * message JSON could not be read.\n\t * @return the message or {@code null}\n\t */\n\tpublic @Nullable Message getResponseMessage() {\n\t\treturn this.responseMessage;\n\t}\n\n\tprivate static String buildMessage(String host, URI uri, int statusCode, @Nullable String reasonPhrase,\n\t\t\t@Nullable Errors errors, @Nullable Message responseMessage, byte @Nullable [] content) {\n\t\tAssert.notNull(host, \"'host' must not be null\");\n\t\tAssert.notNull(uri, \"'uri' must not be null\");\n\t\tStringBuilder message = new StringBuilder(\n\t\t\t\t\"Docker API call to '\" + host + uri + \"' failed with status code \" + statusCode);\n\t\tif (StringUtils.hasLength(reasonPhrase)) {\n\t\t\tmessage.append(\" \\\"\").append(reasonPhrase).append(\"\\\"\");\n\t\t}\n\t\tif (responseMessage != null && StringUtils.hasLength(responseMessage.getMessage())) {\n\t\t\tmessage.append(\" and message \\\"\").append(responseMessage.getMessage()).append(\"\\\"\");\n\t\t}\n\t\telse if (statusCode == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED && !ObjectUtils.isEmpty(content)) {\n\t\t\tString contentString = new String(content, StandardCharsets.UTF_8);\n\t\t\tmessage.append(\" and content \\\"\").append(contentString.trim()).append(\"\\\"\");\n\t\t}\n\t\tif (errors != null && !errors.isEmpty()) {\n\t\t\tmessage.append(\" \").append(errors);\n\t\t}\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/Errors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Errors returned from the Docker API.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class Errors implements Iterable<Errors.Error> {\n\n\tprivate final List<Error> errors;\n\n\t@JsonCreator\n\tErrors(@JsonProperty(\"errors\") @Nullable List<Error> errors) {\n\t\tthis.errors = (errors != null) ? errors : Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic Iterator<Errors.Error> iterator() {\n\t\treturn this.errors.iterator();\n\t}\n\n\t/**\n\t * Returns a sequential {@code Stream} of the errors.\n\t * @return a stream of the errors\n\t */\n\tpublic Stream<Error> stream() {\n\t\treturn this.errors.stream();\n\t}\n\n\t/**\n\t * Return if there are any contained errors.\n\t * @return if the errors are empty\n\t */\n\tpublic boolean isEmpty() {\n\t\treturn this.errors.isEmpty();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.errors.toString();\n\t}\n\n\t/**\n\t * An individual Docker error.\n\t */\n\tpublic static class Error {\n\n\t\tprivate final String code;\n\n\t\tprivate final String message;\n\n\t\t@JsonCreator\n\t\tError(String code, String message) {\n\t\t\tthis.code = code;\n\t\t\tthis.message = message;\n\t\t}\n\n\t\t/**\n\t\t * Return the error code.\n\t\t * @return the error code\n\t\t */\n\t\tpublic String getCode() {\n\t\t\treturn this.code;\n\t\t}\n\n\t\t/**\n\t\t * Return the error message.\n\t\t * @return the error message\n\t\t */\n\t\tpublic String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.code + \": \" + this.message;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.classic.methods.HttpDelete;\nimport org.apache.hc.client5.http.classic.methods.HttpGet;\nimport org.apache.hc.client5.http.classic.methods.HttpHead;\nimport org.apache.hc.client5.http.classic.methods.HttpPost;\nimport org.apache.hc.client5.http.classic.methods.HttpPut;\nimport org.apache.hc.client5.http.classic.methods.HttpUriRequest;\nimport org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;\nimport org.apache.hc.core5.http.ClassicHttpResponse;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.HttpEntity;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.HttpRequest;\nimport org.apache.hc.core5.http.io.entity.AbstractHttpEntity;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JacksonException;\n\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Abstract base class for {@link HttpTransport} implementations backed by a\n * {@link HttpClient}.\n *\n * @author Phillip Webb\n * @author Mike Smithson\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nabstract class HttpClientTransport implements HttpTransport {\n\n\tstatic final String REGISTRY_AUTH_HEADER = \"X-Registry-Auth\";\n\n\tprivate final HttpClient client;\n\n\tprivate final HttpHost host;\n\n\tprotected HttpClientTransport(HttpClient client, HttpHost host) {\n\t\tAssert.notNull(client, \"'client' must not be null\");\n\t\tAssert.notNull(host, \"'host' must not be null\");\n\t\tthis.client = client;\n\t\tthis.host = host;\n\t}\n\n\t/**\n\t * Perform an HTTP GET operation.\n\t * @param uri the destination URI\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response get(URI uri) {\n\t\treturn execute(new HttpGet(uri));\n\t}\n\n\t/**\n\t * Perform an HTTP POST operation.\n\t * @param uri the destination URI\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response post(URI uri) {\n\t\treturn execute(new HttpPost(uri));\n\t}\n\n\t/**\n\t * Perform an HTTP POST operation.\n\t * @param uri the destination URI\n\t * @param registryAuth registry authentication credentials\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response post(URI uri, @Nullable String registryAuth) {\n\t\treturn execute(new HttpPost(uri), registryAuth);\n\t}\n\n\t/**\n\t * Perform an HTTP POST operation.\n\t * @param uri the destination URI\n\t * @param contentType the content type to write\n\t * @param writer a content writer\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response post(URI uri, String contentType, IOConsumer<OutputStream> writer) {\n\t\treturn execute(new HttpPost(uri), contentType, writer);\n\t}\n\n\t/**\n\t * Perform an HTTP PUT operation.\n\t * @param uri the destination URI\n\t * @param contentType the content type to write\n\t * @param writer a content writer\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response put(URI uri, String contentType, IOConsumer<OutputStream> writer) {\n\t\treturn execute(new HttpPut(uri), contentType, writer);\n\t}\n\n\t/**\n\t * Perform an HTTP DELETE operation.\n\t * @param uri the destination URI\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response delete(URI uri) {\n\t\treturn execute(new HttpDelete(uri));\n\t}\n\n\t/**\n\t * Perform an HTTP HEAD operation.\n\t * @param uri the destination URI\n\t * @return the operation response\n\t */\n\t@Override\n\tpublic Response head(URI uri) {\n\t\treturn execute(new HttpHead(uri));\n\t}\n\n\tprivate Response execute(HttpUriRequestBase request, String contentType, IOConsumer<OutputStream> writer) {\n\t\trequest.setEntity(new WritableHttpEntity(contentType, writer));\n\t\treturn execute(request);\n\t}\n\n\tprivate Response execute(HttpUriRequestBase request, @Nullable String registryAuth) {\n\t\tif (StringUtils.hasText(registryAuth)) {\n\t\t\trequest.setHeader(REGISTRY_AUTH_HEADER, registryAuth);\n\t\t}\n\t\treturn execute(request);\n\t}\n\n\tprivate Response execute(HttpUriRequest request) {\n\t\ttry {\n\t\t\tbeforeExecute(request);\n\t\t\tClassicHttpResponse response = this.client.executeOpen(this.host, request, null);\n\t\t\tint statusCode = response.getCode();\n\t\t\tif (statusCode >= 400 && statusCode <= 500) {\n\t\t\t\tbyte[] content = readContent(response);\n\t\t\t\tresponse.close();\n\t\t\t\tErrors errors = (statusCode != 500) ? deserializeErrors(content) : null;\n\t\t\t\tMessage message = deserializeMessage(content);\n\t\t\t\tthrow new DockerEngineException(this.host.toHostString(), request.getUri(), statusCode,\n\t\t\t\t\t\tresponse.getReasonPhrase(), errors, message, content);\n\t\t\t}\n\t\t\treturn new HttpClientResponse(response);\n\t\t}\n\t\tcatch (IOException | URISyntaxException ex) {\n\t\t\tthrow new DockerConnectionException(this.host.toHostString(), ex);\n\t\t}\n\t}\n\n\tprotected void beforeExecute(HttpRequest request) {\n\t}\n\n\tprivate byte @Nullable [] readContent(ClassicHttpResponse response) throws IOException {\n\t\tHttpEntity entity = response.getEntity();\n\t\tif (entity == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry (InputStream stream = entity.getContent()) {\n\t\t\treturn (stream != null) ? stream.readAllBytes() : null;\n\t\t}\n\t}\n\n\tprivate @Nullable Errors deserializeErrors(byte @Nullable [] content) {\n\t\tif (content == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn SharedJsonMapper.get().readValue(content, Errors.class);\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable Message deserializeMessage(byte @Nullable [] content) {\n\t\tif (content == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tMessage message = SharedJsonMapper.get().readValue(content, Message.class);\n\t\t\treturn (message.getMessage() != null) ? message : null;\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tHttpHost getHost() {\n\t\treturn this.host;\n\t}\n\n\t/**\n\t * {@link HttpEntity} to send {@link Content} content.\n\t */\n\tprivate static class WritableHttpEntity extends AbstractHttpEntity {\n\n\t\tprivate final IOConsumer<OutputStream> writer;\n\n\t\tWritableHttpEntity(String contentType, IOConsumer<OutputStream> writer) {\n\t\t\tsuper(contentType, \"UTF-8\");\n\t\t\tthis.writer = writer;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isRepeatable() {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getContentLength() {\n\t\t\tif (this.getContentType() != null && this.getContentType().equals(\"application/json\")) {\n\t\t\t\treturn calculateStringContentLength();\n\t\t\t}\n\t\t\treturn -1;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getContent() throws UnsupportedOperationException {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\t\tthis.writer.accept(outputStream);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isStreaming() {\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate int calculateStringContentLength() {\n\t\t\ttry {\n\t\t\t\tByteArrayOutputStream bytes = new ByteArrayOutputStream();\n\t\t\t\tthis.writer.accept(bytes);\n\t\t\t\treturn bytes.toByteArray().length;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t}\n\n\t}\n\n\t/**\n\t * An HTTP operation response.\n\t */\n\tprivate static class HttpClientResponse implements Response {\n\n\t\tprivate final ClassicHttpResponse response;\n\n\t\tHttpClientResponse(ClassicHttpResponse response) {\n\t\t\tthis.response = response;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getContent() throws IOException {\n\t\t\treturn this.response.getEntity().getContent();\n\t\t}\n\n\t\t@Override\n\t\tpublic Header getHeader(String name) {\n\t\t\treturn this.response.getFirstHeader(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tthis.response.close();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URI;\n\nimport org.apache.hc.core5.http.Header;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerHost;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\n\n/**\n * HTTP transport used for docker access.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic interface HttpTransport {\n\n\t/**\n\t * Perform an HTTP GET operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse get(URI uri) throws IOException;\n\n\t/**\n\t * Perform an HTTP POST operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse post(URI uri) throws IOException;\n\n\t/**\n\t * Perform an HTTP POST operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @param registryAuth registry authentication credentials\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse post(URI uri, @Nullable String registryAuth) throws IOException;\n\n\t/**\n\t * Perform an HTTP POST operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @param contentType the content type to write\n\t * @param writer a content writer\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse post(URI uri, String contentType, IOConsumer<OutputStream> writer) throws IOException;\n\n\t/**\n\t * Perform an HTTP PUT operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @param contentType the content type to write\n\t * @param writer a content writer\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse put(URI uri, String contentType, IOConsumer<OutputStream> writer) throws IOException;\n\n\t/**\n\t * Perform an HTTP DELETE operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse delete(URI uri) throws IOException;\n\n\t/**\n\t * Perform an HTTP HEAD operation.\n\t * @param uri the destination URI (excluding any host/port)\n\t * @return the operation response\n\t * @throws IOException on IO error\n\t */\n\tResponse head(URI uri) throws IOException;\n\n\t/**\n\t * Create the most suitable {@link HttpTransport} based on the {@link DockerHost}.\n\t * @param connectionConfiguration the Docker host information\n\t * @return a {@link HttpTransport} instance\n\t */\n\tstatic HttpTransport create(@Nullable DockerConnectionConfiguration connectionConfiguration) {\n\t\tResolvedDockerHost host = ResolvedDockerHost.from(connectionConfiguration);\n\t\tHttpTransport remote = RemoteHttpClientTransport.createIfPossible(host);\n\t\treturn (remote != null) ? remote : LocalHttpClientTransport.create(host);\n\t}\n\n\t/**\n\t * An HTTP operation response.\n\t */\n\tinterface Response extends Closeable {\n\n\t\t/**\n\t\t * Return the content of the response.\n\t\t * @return the response content\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tInputStream getContent() throws IOException;\n\n\t\tdefault @Nullable Header getHeader(String name) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.Proxy;\nimport java.net.Socket;\n\nimport com.sun.jna.Platform;\nimport org.apache.hc.client5.http.DnsResolver;\nimport org.apache.hc.client5.http.HttpRoute;\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;\nimport org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator;\nimport org.apache.hc.client5.http.io.DetachedSocketFactory;\nimport org.apache.hc.client5.http.io.HttpClientConnectionManager;\nimport org.apache.hc.client5.http.routing.HttpRoutePlanner;\nimport org.apache.hc.client5.http.ssl.TlsSocketStrategy;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.HttpRequest;\nimport org.apache.hc.core5.http.config.Lookup;\nimport org.apache.hc.core5.http.protocol.HttpContext;\nimport org.apache.hc.core5.util.TimeValue;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.socket.NamedPipeSocket;\nimport org.springframework.boot.buildpack.platform.socket.UnixDomainSocket;\n\n/**\n * {@link HttpClientTransport} that talks to local Docker.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nfinal class LocalHttpClientTransport extends HttpClientTransport {\n\n\tprivate static final String DOCKER_SCHEME = \"docker\";\n\n\tprivate static final int DEFAULT_DOCKER_PORT = 2376;\n\n\tprivate static final HttpHost LOCAL_DOCKER_HOST = new HttpHost(DOCKER_SCHEME, \"localhost\", DEFAULT_DOCKER_PORT);\n\n\tprivate LocalHttpClientTransport(HttpClient client, HttpHost host) {\n\t\tsuper(client, host);\n\t}\n\n\t@Override\n\tprotected void beforeExecute(HttpRequest request) {\n\t\trequest.setHeader(\"Host\", LOCAL_DOCKER_HOST.toHostString());\n\t}\n\n\tstatic LocalHttpClientTransport create(ResolvedDockerHost dockerHost) {\n\t\tHttpClientBuilder builder = HttpClients.custom()\n\t\t\t.setConnectionManager(new LocalConnectionManager(dockerHost))\n\t\t\t.setRoutePlanner(new LocalRoutePlanner());\n\t\tHttpHost host = new HttpHost(DOCKER_SCHEME, dockerHost.getAddress());\n\t\treturn new LocalHttpClientTransport(builder.build(), host);\n\t}\n\n\t/**\n\t * {@link HttpClientConnectionManager} for local Docker.\n\t */\n\tprivate static class LocalConnectionManager extends BasicHttpClientConnectionManager {\n\n\t\tprivate static final ConnectionConfig CONNECTION_CONFIG = ConnectionConfig.copy(ConnectionConfig.DEFAULT)\n\t\t\t.setValidateAfterInactivity(TimeValue.NEG_ONE_MILLISECOND)\n\t\t\t.build();\n\n\t\tprivate static final Lookup<@Nullable TlsSocketStrategy> NO_TLS_SOCKET = (name) -> null;\n\n\t\tLocalConnectionManager(ResolvedDockerHost dockerHost) {\n\t\t\tsuper(createHttpClientConnectionOperator(dockerHost), null);\n\t\t\tsetConnectionConfig(CONNECTION_CONFIG);\n\t\t}\n\n\t\tprivate static DefaultHttpClientConnectionOperator createHttpClientConnectionOperator(\n\t\t\t\tResolvedDockerHost dockerHost) {\n\t\t\tLocalDetachedSocketFactory detachedSocketFactory = new LocalDetachedSocketFactory(dockerHost);\n\t\t\tLocalDnsResolver dnsResolver = new LocalDnsResolver();\n\t\t\treturn new DefaultHttpClientConnectionOperator(detachedSocketFactory, null, dnsResolver, NO_TLS_SOCKET);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DetachedSocketFactory} for local Docker.\n\t */\n\tstatic class LocalDetachedSocketFactory implements DetachedSocketFactory {\n\n\t\tprivate static final String NPIPE_PREFIX = \"npipe://\";\n\n\t\tprivate final ResolvedDockerHost dockerHost;\n\n\t\tLocalDetachedSocketFactory(ResolvedDockerHost dockerHost) {\n\t\t\tthis.dockerHost = dockerHost;\n\t\t}\n\n\t\t@Override\n\t\tpublic Socket create(Proxy proxy) throws IOException {\n\t\t\tString address = this.dockerHost.getAddress();\n\t\t\tif (address.startsWith(NPIPE_PREFIX)) {\n\t\t\t\treturn NamedPipeSocket.get(address.substring(NPIPE_PREFIX.length()));\n\t\t\t}\n\t\t\treturn (!Platform.isWindows()) ? UnixDomainSocket.get(address) : NamedPipeSocket.get(address);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DnsResolver} that ensures only the loopback address is used.\n\t */\n\tprivate static final class LocalDnsResolver implements DnsResolver {\n\n\t\tprivate static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress();\n\n\t\t@Override\n\t\tpublic InetAddress[] resolve(String host) {\n\t\t\treturn new InetAddress[] { LOOPBACK };\n\t\t}\n\n\t\t@Override\n\t\tpublic String resolveCanonicalHostname(String host) {\n\t\t\treturn LOOPBACK.getCanonicalHostName();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link HttpRoutePlanner} for local Docker.\n\t */\n\tprivate static final class LocalRoutePlanner implements HttpRoutePlanner {\n\n\t\t@Override\n\t\tpublic HttpRoute determineRoute(HttpHost target, HttpContext context) {\n\t\t\treturn new HttpRoute(LOCAL_DOCKER_HOST);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/Message.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A message returned from the Docker API.\n *\n * @author Scott Frederick\n * @since 2.3.1\n */\npublic class Message {\n\n\tprivate final @Nullable String message;\n\n\t@JsonCreator\n\tMessage(@JsonProperty(\"message\") @Nullable String message) {\n\t\tthis.message = message;\n\t}\n\n\t/**\n\t * Return the message contained in the response.\n\t * @return the message\n\t */\n\tpublic @Nullable String getMessage() {\n\t\treturn this.message;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.message == null) ? \"<null>\" : this.message;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.net.URISyntaxException;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;\nimport org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;\nimport org.apache.hc.client5.http.ssl.TlsSocketStrategy;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.io.SocketConfig;\nimport org.apache.hc.core5.util.Timeout;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerHost;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.docker.ssl.SslContextFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link HttpClientTransport} that talks to a remote Docker.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nfinal class RemoteHttpClientTransport extends HttpClientTransport {\n\n\tprivate static final Timeout SOCKET_TIMEOUT = Timeout.of(30, TimeUnit.MINUTES);\n\n\tprivate RemoteHttpClientTransport(HttpClient client, HttpHost host) {\n\t\tsuper(client, host);\n\t}\n\n\tstatic @Nullable RemoteHttpClientTransport createIfPossible(ResolvedDockerHost dockerHost) {\n\t\treturn createIfPossible(dockerHost, new SslContextFactory());\n\t}\n\n\tstatic @Nullable RemoteHttpClientTransport createIfPossible(ResolvedDockerHost dockerHost,\n\t\t\tSslContextFactory sslContextFactory) {\n\t\tif (!dockerHost.isRemote()) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn create(dockerHost, sslContextFactory, HttpHost.create(dockerHost.getAddress()));\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static RemoteHttpClientTransport create(DockerHost host, SslContextFactory sslContextFactory,\n\t\t\tHttpHost tcpHost) {\n\t\tSocketConfig socketConfig = SocketConfig.copy(SocketConfig.DEFAULT).setSoTimeout(SOCKET_TIMEOUT).build();\n\t\tPoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder\n\t\t\t.create()\n\t\t\t.setDefaultSocketConfig(socketConfig);\n\t\tif (host.isSecure()) {\n\t\t\tconnectionManagerBuilder.setTlsSocketStrategy(getTlsSocketStrategy(host, sslContextFactory));\n\t\t}\n\t\tHttpClientBuilder builder = HttpClients.custom();\n\t\tbuilder.setConnectionManager(connectionManagerBuilder.build());\n\t\tString scheme = host.isSecure() ? \"https\" : \"http\";\n\t\tHttpHost httpHost = new HttpHost(scheme, tcpHost.getHostName(), tcpHost.getPort());\n\t\treturn new RemoteHttpClientTransport(builder.build(), httpHost);\n\t}\n\n\tprivate static TlsSocketStrategy getTlsSocketStrategy(DockerHost host, SslContextFactory sslContextFactory) {\n\t\tString directory = host.getCertificatePath();\n\t\tAssert.state(StringUtils.hasText(directory),\n\t\t\t\t\"Docker host TLS verification requires trust material location to be specified with certificate path\");\n\t\tSSLContext sslContext = sslContextFactory.forDirectory(directory);\n\t\treturn new DefaultClientTlsStrategy(sslContext);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/transport/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Docker transport classes providing HTTP operations on a local or remote engine.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/Binding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.springframework.util.Assert;\n\n/**\n * Volume bindings to apply when creating a container.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 2.5.0\n */\npublic final class Binding {\n\n\t/**\n\t * Sensitive container paths, which lead to problems if used in a binding.\n\t */\n\tprivate static final Set<String> SENSITIVE_CONTAINER_PATHS = Set.of(\"/cnb\", \"/layers\", \"/workspace\", \"c:\\\\cnb\",\n\t\t\t\"c:\\\\layers\", \"c:\\\\workspace\");\n\n\tprivate final String value;\n\n\tprivate Binding(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!(obj instanceof Binding binding)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn Objects.equals(this.value, binding.value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.value);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Whether the binding uses a sensitive container path.\n\t * @return whether the binding uses a sensitive container path\n\t * @since 3.4.0\n\t */\n\tpublic boolean usesSensitiveContainerPath() {\n\t\treturn SENSITIVE_CONTAINER_PATHS.contains(getContainerDestinationPath());\n\t}\n\n\t/**\n\t * Returns the container destination path.\n\t * @return the container destination path\n\t */\n\tString getContainerDestinationPath() {\n\t\tList<String> parts = getParts();\n\t\tAssert.state(parts.size() >= 2, () -> \"Expected 2 or more parts, but found %d\".formatted(parts.size()));\n\t\treturn parts.get(1);\n\t}\n\n\tprivate List<String> getParts() {\n\t\t// Format is <host>:<container>:[<options>]\n\t\tList<String> parts = new ArrayList<>();\n\t\tStringBuilder buffer = new StringBuilder();\n\t\tfor (int i = 0; i < this.value.length(); i++) {\n\t\t\tchar ch = this.value.charAt(i);\n\t\t\tchar nextChar = (i + 1 < this.value.length()) ? this.value.charAt(i + 1) : '\\0';\n\t\t\tif (ch == ':' && nextChar != '\\\\') {\n\t\t\t\tparts.add(buffer.toString());\n\t\t\t\tbuffer.setLength(0);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbuffer.append(ch);\n\t\t\t}\n\t\t}\n\t\tparts.add(buffer.toString());\n\t\treturn parts;\n\t}\n\n\t/**\n\t * Create a {@link Binding} with the specified value containing a host source,\n\t * container destination, and options.\n\t * @param value the volume binding value\n\t * @return a new {@link Binding} instance\n\t */\n\tpublic static Binding of(String value) {\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\treturn new Binding(value);\n\t}\n\n\t/**\n\t * Create a {@link Binding} from the specified source and destination.\n\t * @param sourceVolume the volume binding host source\n\t * @param destination the volume binding container destination\n\t * @return a new {@link Binding} instance\n\t */\n\tpublic static Binding from(VolumeName sourceVolume, String destination) {\n\t\tAssert.notNull(sourceVolume, \"'sourceVolume' must not be null\");\n\t\treturn from(sourceVolume.toString(), destination);\n\t}\n\n\t/**\n\t * Create a {@link Binding} from the specified source and destination.\n\t * @param source the volume binding host source\n\t * @param destination the volume binding container destination\n\t * @return a new {@link Binding} instance\n\t */\n\tpublic static Binding from(String source, String destination) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(destination, \"'destination' must not be null\");\n\t\treturn new Binding(source + \":\" + destination);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/BlobReference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.lang.invoke.MethodHandles;\n\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.Assert;\n\n/**\n * A reference to a blob by its digest.\n *\n * @author Phillip Webb\n * @since 3.2.6\n */\npublic class BlobReference extends MappedObject {\n\n\tprivate final String digest;\n\n\tprivate final String mediaType;\n\n\tBlobReference(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.digest = extractDigest();\n\t\tthis.mediaType = extractMediaType();\n\t}\n\n\tprivate String extractMediaType() {\n\t\tString result = valueAt(\"/mediaType\", String.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate String extractDigest() {\n\t\tString result = valueAt(\"/digest\", String.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the digest of the blob.\n\t * @return the blob digest\n\t */\n\tpublic String getDigest() {\n\t\treturn this.digest;\n\t}\n\n\t/**\n\t * Return the media type of the blob.\n\t * @return the blob media type\n\t */\n\tpublic String getMediaType() {\n\t\treturn this.mediaType;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.node.ArrayNode;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration used when creating a new container.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n * @since 2.3.0\n */\npublic class ContainerConfig {\n\n\tprivate final String json;\n\n\tContainerConfig(@Nullable String user, ImageReference image, String command, List<String> args,\n\t\t\tMap<String, String> labels, List<Binding> bindings, Map<String, String> env, @Nullable String networkMode,\n\t\t\tList<String> securityOptions) {\n\t\tAssert.notNull(image, \"'image' must not be null\");\n\t\tAssert.hasText(command, \"'command' must not be empty\");\n\t\tJsonMapper jsonMapper = SharedJsonMapper.get();\n\t\tObjectNode node = jsonMapper.createObjectNode();\n\t\tif (StringUtils.hasText(user)) {\n\t\t\tnode.put(\"User\", user);\n\t\t}\n\t\tnode.put(\"Image\", image.toString());\n\t\tArrayNode commandNode = node.putArray(\"Cmd\");\n\t\tcommandNode.add(command);\n\t\targs.forEach(commandNode::add);\n\t\tArrayNode envNode = node.putArray(\"Env\");\n\t\tenv.forEach((name, value) -> envNode.add(name + \"=\" + value));\n\t\tObjectNode labelsNode = node.putObject(\"Labels\");\n\t\tlabels.forEach(labelsNode::put);\n\t\tObjectNode hostConfigNode = node.putObject(\"HostConfig\");\n\t\tif (networkMode != null) {\n\t\t\thostConfigNode.put(\"NetworkMode\", networkMode);\n\t\t}\n\t\tArrayNode bindsNode = hostConfigNode.putArray(\"Binds\");\n\t\tbindings.forEach((binding) -> bindsNode.add(binding.toString()));\n\t\tif (!CollectionUtils.isEmpty(securityOptions)) {\n\t\t\tArrayNode securityOptsNode = hostConfigNode.putArray(\"SecurityOpt\");\n\t\t\tsecurityOptions.forEach(securityOptsNode::add);\n\t\t}\n\t\tthis.json = jsonMapper.writeValueAsString(node);\n\t}\n\n\t/**\n\t * Write this container configuration to the specified {@link OutputStream}.\n\t * @param outputStream the output stream\n\t * @throws IOException on IO error\n\t */\n\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\tStreamUtils.copy(this.json, StandardCharsets.UTF_8, outputStream);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.json;\n\t}\n\n\t/**\n\t * Factory method to create a {@link ContainerConfig} with specific settings.\n\t * @param imageReference the source image for the container config\n\t * @param update an update callback used to customize the config\n\t * @return a new {@link ContainerConfig} instance\n\t */\n\tpublic static ContainerConfig of(ImageReference imageReference, Consumer<Update> update) {\n\t\tAssert.notNull(imageReference, \"'imageReference' must not be null\");\n\t\tAssert.notNull(update, \"'update' must not be null\");\n\t\treturn new Update(imageReference).run(update);\n\t}\n\n\t/**\n\t * Update class used to change data when creating a container config.\n\t */\n\tpublic static class Update {\n\n\t\tprivate final ImageReference image;\n\n\t\tprivate @Nullable String user;\n\n\t\tprivate @Nullable String command;\n\n\t\tprivate final List<String> args = new ArrayList<>();\n\n\t\tprivate final Map<String, String> labels = new LinkedHashMap<>();\n\n\t\tprivate final List<Binding> bindings = new ArrayList<>();\n\n\t\tprivate final Map<String, String> env = new LinkedHashMap<>();\n\n\t\tprivate @Nullable String networkMode;\n\n\t\tprivate final List<String> securityOptions = new ArrayList<>();\n\n\t\tUpdate(ImageReference image) {\n\t\t\tthis.image = image;\n\t\t}\n\n\t\tprivate ContainerConfig run(Consumer<Update> update) {\n\t\t\tupdate.accept(this);\n\t\t\tAssert.state(this.command != null, \"'command' must not be null\");\n\t\t\treturn new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings,\n\t\t\t\t\tthis.env, this.networkMode, this.securityOptions);\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with a specific user.\n\t\t * @param user the user to set\n\t\t */\n\t\tpublic void withUser(String user) {\n\t\t\tthis.user = user;\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with a specific command.\n\t\t * @param command the command to set\n\t\t * @param args additional arguments to add\n\t\t * @see #withArgs(String...)\n\t\t */\n\t\tpublic void withCommand(String command, String... args) {\n\t\t\tthis.command = command;\n\t\t\twithArgs(args);\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with additional args.\n\t\t * @param args the arguments to add\n\t\t */\n\t\tpublic void withArgs(String... args) {\n\t\t\tthis.args.addAll(Arrays.asList(args));\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with an additional label.\n\t\t * @param name the label name\n\t\t * @param value the label value\n\t\t */\n\t\tpublic void withLabel(String name, String value) {\n\t\t\tthis.labels.put(name, value);\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with an additional binding.\n\t\t * @param binding the binding\n\t\t */\n\t\tpublic void withBinding(Binding binding) {\n\t\t\tthis.bindings.add(binding);\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with an additional environment variable.\n\t\t * @param name the variable name\n\t\t * @param value the variable value\n\t\t */\n\t\tpublic void withEnv(String name, String value) {\n\t\t\tthis.env.put(name, value);\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with the network that the build container will\n\t\t * connect to.\n\t\t * @param networkMode the network\n\t\t */\n\t\tpublic void withNetworkMode(@Nullable String networkMode) {\n\t\t\tthis.networkMode = networkMode;\n\t\t}\n\n\t\t/**\n\t\t * Update the container config with a security option.\n\t\t * @param option the security option\n\t\t */\n\t\tpublic void withSecurityOption(String option) {\n\t\t\tthis.securityOptions.add(option);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\n\n/**\n * Additional content that can be written to a created container.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface ContainerContent {\n\n\t/**\n\t * Return the actual content to be added.\n\t * @return the content\n\t */\n\tTarArchive getArchive();\n\n\t/**\n\t * Return the destination path where the content should be added.\n\t * @return the destination path\n\t */\n\tString getDestinationPath();\n\n\t/**\n\t * Factory method to create a new {@link ContainerContent} instance written to the\n\t * root of the container.\n\t * @param archive the archive to add\n\t * @return a new {@link ContainerContent} instance\n\t */\n\tstatic ContainerContent of(TarArchive archive) {\n\t\treturn of(archive, \"/\");\n\t}\n\n\t/**\n\t * Factory method to create a new {@link ContainerContent} instance.\n\t * @param archive the archive to add\n\t * @param destinationPath the destination path within the container\n\t * @return a new {@link ContainerContent} instance\n\t */\n\tstatic ContainerContent of(TarArchive archive, String destinationPath) {\n\t\tAssert.notNull(archive, \"'archive' must not be null\");\n\t\tAssert.hasText(destinationPath, \"'destinationPath' must not be empty\");\n\t\treturn new ContainerContent() {\n\n\t\t\t@Override\n\t\t\tpublic TarArchive getArchive() {\n\t\t\t\treturn archive;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getDestinationPath() {\n\t\t\t\treturn destinationPath;\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerReference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A reference to a Docker container.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic final class ContainerReference {\n\n\tprivate final String value;\n\n\tprivate ContainerReference(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tContainerReference other = (ContainerReference) obj;\n\t\treturn this.value.equals(other.value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Factory method to create a {@link ContainerReference} with a specific value.\n\t * @param value the container reference value\n\t * @return a new container reference instance\n\t */\n\tpublic static ContainerReference of(String value) {\n\t\treturn new ContainerReference(value);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ContainerStatus.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.node.NullNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.Assert;\n\n/**\n * Status details returned from {@code Docker container wait}.\n *\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class ContainerStatus extends MappedObject {\n\n\tprivate final int statusCode;\n\n\tprivate final @Nullable String waitingErrorMessage;\n\n\tContainerStatus(int statusCode, @Nullable String waitingErrorMessage) {\n\t\tsuper(NullNode.getInstance(), MethodHandles.lookup());\n\t\tthis.statusCode = statusCode;\n\t\tthis.waitingErrorMessage = waitingErrorMessage;\n\t}\n\n\tContainerStatus(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.statusCode = extractStatusCode();\n\t\tthis.waitingErrorMessage = valueAt(\"/Error/Message\", String.class);\n\t}\n\n\tprivate Integer extractStatusCode() {\n\t\tInteger result = valueAt(\"/StatusCode\", Integer.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the container exit status code.\n\t * @return the exit status code\n\t */\n\tpublic int getStatusCode() {\n\t\treturn this.statusCode;\n\t}\n\n\t/**\n\t * Return a message indicating an error waiting for a container to stop.\n\t * @return the waiting error message\n\t */\n\tpublic @Nullable String getWaitingErrorMessage() {\n\t\treturn this.waitingErrorMessage;\n\t}\n\n\t/**\n\t * Create a new {@link ContainerStatus} instance from the specified JSON content\n\t * stream.\n\t * @param content the JSON content stream\n\t * @return a new {@link ContainerStatus} instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static ContainerStatus of(InputStream content) throws IOException {\n\t\treturn of(content, ContainerStatus::new);\n\t}\n\n\t/**\n\t * Create a new {@link ContainerStatus} instance with the specified values.\n\t * @param statusCode the status code\n\t * @param errorMessage the error message\n\t * @return a new {@link ContainerStatus} instance\n\t */\n\tpublic static ContainerStatus of(int statusCode, @Nullable String errorMessage) {\n\t\treturn new ContainerStatus(statusCode, errorMessage);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/Image.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Image details as returned from {@code Docker inspect}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class Image extends MappedObject {\n\n\tprivate final List<String> digests;\n\n\tprivate final ImageConfig config;\n\n\tprivate final List<LayerId> layers;\n\n\tprivate final @Nullable String os;\n\n\tprivate final @Nullable String architecture;\n\n\tprivate final @Nullable String variant;\n\n\tprivate final @Nullable String created;\n\n\tprivate final @Nullable Descriptor descriptor;\n\n\tImage(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.digests = childrenAt(\"/RepoDigests\", JsonNode::asString);\n\t\tthis.config = new ImageConfig(getNode().at(\"/Config\"));\n\t\tthis.layers = extractLayers(valueAt(\"/RootFS/Layers\", String[].class));\n\t\tthis.os = valueAt(\"/Os\", String.class);\n\t\tthis.architecture = valueAt(\"/Architecture\", String.class);\n\t\tthis.variant = valueAt(\"/Variant\", String.class);\n\t\tthis.created = valueAt(\"/Created\", String.class);\n\t\tJsonNode descriptorNode = getNode().path(\"Descriptor\");\n\t\tthis.descriptor = (descriptorNode.isMissingNode() || descriptorNode.isNull()) ? null\n\t\t\t\t: new Descriptor(descriptorNode);\n\t}\n\n\tprivate List<LayerId> extractLayers(String @Nullable [] layers) {\n\t\tif (layers == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\treturn Arrays.stream(layers).map(LayerId::of).toList();\n\t}\n\n\t/**\n\t * Return the digests of the image.\n\t * @return the image digests\n\t */\n\tpublic List<String> getDigests() {\n\t\treturn this.digests;\n\t}\n\n\t/**\n\t * Return image config information.\n\t * @return the image config\n\t */\n\tpublic ImageConfig getConfig() {\n\t\treturn this.config;\n\t}\n\n\t/**\n\t * Return the layer IDs contained in the image.\n\t * @return the layer IDs.\n\t */\n\tpublic List<LayerId> getLayers() {\n\t\treturn this.layers;\n\t}\n\n\t/**\n\t * Return the OS of the image.\n\t * @return the image OS\n\t */\n\tpublic String getOs() {\n\t\treturn (StringUtils.hasText(this.os)) ? this.os : \"linux\";\n\t}\n\n\t/**\n\t * Return the architecture of the image.\n\t * @return the image architecture\n\t */\n\tpublic @Nullable String getArchitecture() {\n\t\treturn this.architecture;\n\t}\n\n\t/**\n\t * Return the variant of the image.\n\t * @return the image variant\n\t */\n\tpublic @Nullable String getVariant() {\n\t\treturn this.variant;\n\t}\n\n\t/**\n\t * Return the created date of the image.\n\t * @return the image created date\n\t */\n\tpublic @Nullable String getCreated() {\n\t\treturn this.created;\n\t}\n\n\t/**\n\t * Return the descriptor for this image as reported by Docker Engine inspect.\n\t * @return the image descriptor or {@code null}\n\t */\n\tpublic @Nullable Descriptor getDescriptor() {\n\t\treturn this.descriptor;\n\t}\n\n\t/**\n\t * Return the primary digest of the image or {@code null}. Checks the\n\t * {@code Descriptor.digest} first, falling back to {@code RepoDigest}.\n\t * @return the primary digest or {@code null}\n\t * @since 3.4.12\n\t */\n\tpublic @Nullable String getPrimaryDigest() {\n\t\tif (this.descriptor != null && StringUtils.hasText(this.descriptor.getDigest())) {\n\t\t\treturn this.descriptor.getDigest();\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.digests)) {\n\t\t\ttry {\n\t\t\t\tString digest = this.digests.get(0);\n\t\t\t\treturn (digest != null) ? ImageReference.of(digest).getDigest() : null;\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create a new {@link Image} instance from the specified JSON content.\n\t * @param content the JSON content\n\t * @return a new {@link Image} instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static Image of(InputStream content) throws IOException {\n\t\treturn of(content, Image::new);\n\t}\n\n\t/**\n\t * Descriptor details as reported in the {@code Docker inspect} response.\n\t *\n\t * @since 3.4.12\n\t */\n\tpublic final class Descriptor extends MappedObject {\n\n\t\tprivate final String digest;\n\n\t\tDescriptor(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tthis.digest = Objects.requireNonNull(valueAt(\"/digest\", String.class));\n\t\t}\n\n\t\tpublic String getDigest() {\n\t\t\treturn this.digest;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageArchive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.time.format.DateTimeFormatter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.node.ArrayNode;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.InspectedContent;\nimport org.springframework.boot.buildpack.platform.io.Layout;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.util.Assert;\n\n/**\n * An image archive that can be loaded into Docker.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n * @see #from(Image, IOConsumer)\n * @see <a href=\"https://github.com/moby/moby/blob/master/image/spec/v1.2.md\">Docker Image\n * Specification</a>\n */\npublic class ImageArchive implements TarArchive {\n\n\tprivate static final Instant WINDOWS_EPOCH_PLUS_SECOND = OffsetDateTime.of(1980, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC)\n\t\t.toInstant();\n\n\tprivate static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME\n\t\t.withZone(ZoneOffset.UTC);\n\n\tprivate static final String EMPTY_LAYER_NAME_PREFIX = \"blank_\";\n\n\tprivate static final IOConsumer<Update> NO_UPDATES = (update) -> {\n\t};\n\n\tprivate final JsonMapper jsonMapper;\n\n\tprivate final ImageConfig imageConfig;\n\n\tprivate final Instant createDate;\n\n\tprivate final @Nullable ImageReference tag;\n\n\tprivate final String os;\n\n\tprivate final @Nullable String architecture;\n\n\tprivate final @Nullable String variant;\n\n\tprivate final List<LayerId> existingLayers;\n\n\tprivate final List<Layer> newLayers;\n\n\tImageArchive(JsonMapper jsonMapper, ImageConfig imageConfig, Instant createDate, @Nullable ImageReference tag,\n\t\t\tString os, @Nullable String architecture, @Nullable String variant, List<LayerId> existingLayers,\n\t\t\tList<Layer> newLayers) {\n\t\tthis.jsonMapper = jsonMapper;\n\t\tthis.imageConfig = imageConfig;\n\t\tthis.createDate = createDate;\n\t\tthis.tag = tag;\n\t\tthis.os = os;\n\t\tthis.architecture = architecture;\n\t\tthis.variant = variant;\n\t\tthis.existingLayers = existingLayers;\n\t\tthis.newLayers = newLayers;\n\t}\n\n\t/**\n\t * Return the image config for the archive.\n\t * @return the image config\n\t */\n\tpublic ImageConfig getImageConfig() {\n\t\treturn this.imageConfig;\n\t}\n\n\t/**\n\t * Return the create date of the archive.\n\t * @return the create date\n\t */\n\tpublic Instant getCreateDate() {\n\t\treturn this.createDate;\n\t}\n\n\t/**\n\t * Return the tag of the archive.\n\t * @return the tag\n\t */\n\tpublic @Nullable ImageReference getTag() {\n\t\treturn this.tag;\n\t}\n\n\t@Override\n\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\tTarArchive.of(this::write).writeTo(outputStream);\n\t}\n\n\tprivate void write(Layout writer) throws IOException {\n\t\tList<LayerId> writtenLayers = writeLayers(writer);\n\t\tString config = writeConfig(writer, writtenLayers);\n\t\twriteManifest(writer, config, writtenLayers);\n\t}\n\n\tprivate List<LayerId> writeLayers(Layout writer) throws IOException {\n\t\tfor (int i = 0; i < this.existingLayers.size(); i++) {\n\t\t\twriteEmptyLayer(writer, EMPTY_LAYER_NAME_PREFIX + i);\n\t\t}\n\t\tList<LayerId> writtenLayers = new ArrayList<>();\n\t\tfor (Layer layer : this.newLayers) {\n\t\t\twrittenLayers.add(writeLayer(writer, layer));\n\t\t}\n\t\treturn Collections.unmodifiableList(writtenLayers);\n\t}\n\n\tprivate void writeEmptyLayer(Layout writer, String name) throws IOException {\n\t\twriter.file(name, Owner.ROOT, Content.of(\"\"));\n\t}\n\n\tprivate LayerId writeLayer(Layout writer, Layer layer) throws IOException {\n\t\tLayerId id = layer.getId();\n\t\twriter.file(id.getHash() + \".tar\", Owner.ROOT, layer);\n\t\treturn id;\n\t}\n\n\tprivate String writeConfig(Layout writer, List<LayerId> writtenLayers) throws IOException {\n\t\ttry {\n\t\t\tObjectNode config = createConfig(writtenLayers);\n\t\t\tString json = this.jsonMapper.writeValueAsString(config).replace(\"\\r\\n\", \"\\n\");\n\t\t\tMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n\t\t\tInspectedContent content = InspectedContent.of(Content.of(json), digest::update);\n\t\t\tString name = LayerId.ofSha256Digest(digest.digest()).getHash() + \".json\";\n\t\t\twriter.file(name, Owner.ROOT, content);\n\t\t\treturn name;\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate ObjectNode createConfig(List<LayerId> writtenLayers) {\n\t\tObjectNode config = this.jsonMapper.createObjectNode();\n\t\tconfig.set(\"Config\", this.imageConfig.getNodeCopy());\n\t\tconfig.set(\"Created\", config.stringNode(getCreatedDate()));\n\t\tconfig.set(\"History\", createHistory(writtenLayers));\n\t\tconfig.set(\"Os\", config.stringNode(this.os));\n\t\tconfig.set(\"Architecture\", config.stringNode(this.architecture));\n\t\tconfig.set(\"Variant\", config.stringNode(this.variant));\n\t\tconfig.set(\"RootFS\", createRootFs(writtenLayers));\n\t\treturn config;\n\t}\n\n\tprivate String getCreatedDate() {\n\t\treturn DATE_FORMATTER.format(this.createDate);\n\t}\n\n\tprivate JsonNode createHistory(List<LayerId> writtenLayers) {\n\t\tArrayNode history = this.jsonMapper.createArrayNode();\n\t\tint size = this.existingLayers.size() + writtenLayers.size();\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\thistory.addObject();\n\t\t}\n\t\treturn history;\n\t}\n\n\tprivate JsonNode createRootFs(List<LayerId> writtenLayers) {\n\t\tObjectNode rootFs = this.jsonMapper.createObjectNode();\n\t\tArrayNode diffIds = rootFs.putArray(\"diff_ids\");\n\t\tthis.existingLayers.stream().map(Object::toString).forEach(diffIds::add);\n\t\twrittenLayers.stream().map(Object::toString).forEach(diffIds::add);\n\t\treturn rootFs;\n\t}\n\n\tprivate void writeManifest(Layout writer, String config, List<LayerId> writtenLayers) throws IOException {\n\t\tArrayNode manifest = createManifest(config, writtenLayers);\n\t\tString manifestJson = this.jsonMapper.writeValueAsString(manifest);\n\t\twriter.file(\"manifest.json\", Owner.ROOT, Content.of(manifestJson));\n\t}\n\n\tprivate ArrayNode createManifest(String config, List<LayerId> writtenLayers) {\n\t\tArrayNode manifest = this.jsonMapper.createArrayNode();\n\t\tObjectNode entry = manifest.addObject();\n\t\tentry.set(\"Config\", entry.stringNode(config));\n\t\tentry.set(\"Layers\", getManifestLayers(writtenLayers));\n\t\tif (this.tag != null) {\n\t\t\tentry.set(\"RepoTags\", entry.arrayNode().add(this.tag.toString()));\n\t\t}\n\t\treturn manifest;\n\t}\n\n\tprivate ArrayNode getManifestLayers(List<LayerId> writtenLayers) {\n\t\tArrayNode layers = this.jsonMapper.createArrayNode();\n\t\tfor (int i = 0; i < this.existingLayers.size(); i++) {\n\t\t\tlayers.add(EMPTY_LAYER_NAME_PREFIX + i);\n\t\t}\n\t\twrittenLayers.stream().map((id) -> id.getHash() + \".tar\").forEach(layers::add);\n\t\treturn layers;\n\t}\n\n\t/**\n\t * Create a new {@link ImageArchive} based on an existing {@link Image}.\n\t * @param image the image that this archive is based on\n\t * @return the new image archive.\n\t * @throws IOException on IO error\n\t */\n\tpublic static ImageArchive from(Image image) throws IOException {\n\t\treturn from(image, NO_UPDATES);\n\t}\n\n\t/**\n\t * Create a new {@link ImageArchive} based on an existing {@link Image}.\n\t * @param image the image that this archive is based on\n\t * @param update consumer to apply updates\n\t * @return the new image archive.\n\t * @throws IOException on IO error\n\t */\n\tpublic static ImageArchive from(Image image, IOConsumer<Update> update) throws IOException {\n\t\treturn new Update(image).applyTo(update);\n\t}\n\n\t/**\n\t * Update class used to change data when creating an image archive.\n\t */\n\tpublic static final class Update {\n\n\t\tprivate final Image image;\n\n\t\tprivate ImageConfig config;\n\n\t\tprivate @Nullable Instant createDate;\n\n\t\tprivate @Nullable ImageReference tag;\n\n\t\tprivate final List<Layer> newLayers = new ArrayList<>();\n\n\t\tprivate Update(Image image) {\n\t\t\tthis.image = image;\n\t\t\tthis.config = image.getConfig();\n\t\t}\n\n\t\tprivate ImageArchive applyTo(IOConsumer<Update> update) throws IOException {\n\t\t\tupdate.accept(this);\n\t\t\tInstant createDate = (this.createDate != null) ? this.createDate : WINDOWS_EPOCH_PLUS_SECOND;\n\t\t\treturn new ImageArchive(SharedJsonMapper.get(), this.config, createDate, this.tag, this.image.getOs(),\n\t\t\t\t\tthis.image.getArchitecture(), this.image.getVariant(), this.image.getLayers(),\n\t\t\t\t\tCollections.unmodifiableList(this.newLayers));\n\t\t}\n\n\t\t/**\n\t\t * Apply updates to the {@link ImageConfig}.\n\t\t * @param update consumer to apply updates\n\t\t */\n\t\tpublic void withUpdatedConfig(Consumer<ImageConfig.Update> update) {\n\t\t\tthis.config = this.config.copy(update);\n\t\t}\n\n\t\t/**\n\t\t * Add a new layer to the image archive.\n\t\t * @param layer the layer to add\n\t\t */\n\t\tpublic void withNewLayer(Layer layer) {\n\t\t\tAssert.notNull(layer, \"'layer' must not be null\");\n\t\t\tthis.newLayers.add(layer);\n\t\t}\n\n\t\t/**\n\t\t * Set the create date for the image archive.\n\t\t * @param createDate the create date\n\t\t */\n\t\tpublic void withCreateDate(Instant createDate) {\n\t\t\tAssert.notNull(createDate, \"'createDate' must not be null\");\n\t\t\tthis.createDate = createDate;\n\t\t}\n\n\t\t/**\n\t\t * Set the tag for the image archive.\n\t\t * @param tag the tag\n\t\t */\n\t\tpublic void withTag(ImageReference tag) {\n\t\t\tAssert.notNull(tag, \"'tag' must not be null\");\n\t\t\tthis.tag = tag.inTaggedForm();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageArchiveIndex.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\nimport java.util.List;\n\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.Assert;\n\n/**\n * Image archive index information as provided by {@code index.json}.\n *\n * @author Phillip Webb\n * @since 3.2.6\n * @see <a href=\n * \"https://github.com/opencontainers/image-spec/blob/main/image-index.md\">OCI Image Index\n * Specification</a>\n */\npublic class ImageArchiveIndex extends MappedObject {\n\n\tprivate final Integer schemaVersion;\n\n\tprivate final List<BlobReference> manifests;\n\n\tprotected ImageArchiveIndex(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.schemaVersion = extractSchemaVersion();\n\t\tthis.manifests = childrenAt(\"/manifests\", BlobReference::new);\n\t}\n\n\tprivate Integer extractSchemaVersion() {\n\t\tInteger result = valueAt(\"/schemaVersion\", Integer.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tpublic Integer getSchemaVersion() {\n\t\treturn this.schemaVersion;\n\t}\n\n\tpublic List<BlobReference> getManifests() {\n\t\treturn this.manifests;\n\t}\n\n\t/**\n\t * Create an {@link ImageArchiveIndex} from the provided JSON input stream.\n\t * @param content the JSON input stream\n\t * @return a new {@link ImageArchiveIndex} instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static ImageArchiveIndex of(InputStream content) throws IOException {\n\t\treturn of(content, ImageArchiveIndex::new);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageArchiveManifest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\nimport java.util.Collections;\nimport java.util.List;\n\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\n\n/**\n * Image archive manifest information as provided by {@code manifest.json}.\n *\n * @author Scott Frederick\n * @since 2.7.10\n */\npublic class ImageArchiveManifest extends MappedObject {\n\n\tprivate final List<ManifestEntry> entries;\n\n\tprotected ImageArchiveManifest(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.entries = childrenAt(null, ManifestEntry::new);\n\t}\n\n\t/**\n\t * Return the entries contained in the manifest.\n\t * @return the manifest entries\n\t */\n\tpublic List<ManifestEntry> getEntries() {\n\t\treturn this.entries;\n\t}\n\n\t/**\n\t * Create an {@link ImageArchiveManifest} from the provided JSON input stream.\n\t * @param content the JSON input stream\n\t * @return a new {@link ImageArchiveManifest} instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static ImageArchiveManifest of(InputStream content) throws IOException {\n\t\treturn of(content, ImageArchiveManifest::new);\n\t}\n\n\tpublic static class ManifestEntry extends MappedObject {\n\n\t\tprivate final List<String> layers;\n\n\t\tprotected ManifestEntry(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t\tthis.layers = extractLayers();\n\t\t}\n\n\t\t/**\n\t\t * Return the collection of layer IDs from a section of the manifest.\n\t\t * @return a collection of layer IDs\n\t\t */\n\t\tpublic List<String> getLayers() {\n\t\t\treturn this.layers;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate List<String> extractLayers() {\n\t\t\tList<String> layers = valueAt(\"/Layers\", List.class);\n\t\t\tif (layers == null) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\treturn layers;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.lang.invoke.MethodHandles;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\n\n/**\n * Image configuration information.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.3.0\n */\npublic class ImageConfig extends MappedObject {\n\n\tprivate final Map<String, String> labels;\n\n\tprivate final Map<String, @Nullable String> configEnv;\n\n\tImageConfig(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.labels = extractLabels();\n\t\tthis.configEnv = parseConfigEnv();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, String> extractLabels() {\n\t\tMap<String, String> labels = valueAt(\"/Labels\", Map.class);\n\t\tif (labels == null) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\treturn labels;\n\t}\n\n\tprivate Map<String, @Nullable String> parseConfigEnv() {\n\t\tString[] entries = valueAt(\"/Env\", String[].class);\n\t\tif (entries == null) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<String, @Nullable String> env = new LinkedHashMap<>();\n\t\tfor (String entry : entries) {\n\t\t\tint i = entry.indexOf('=');\n\t\t\tString name = (i != -1) ? entry.substring(0, i) : entry;\n\t\t\tString value = (i != -1) ? entry.substring(i + 1) : null;\n\t\t\tenv.put(name, value);\n\t\t}\n\t\treturn Collections.unmodifiableMap(env);\n\t}\n\n\tJsonNode getNodeCopy() {\n\t\treturn super.getNode().deepCopy();\n\t}\n\n\t/**\n\t * Return the image labels. If the image has no labels, an empty {@code Map} is\n\t * returned.\n\t * @return the image labels, never {@code null}\n\t */\n\tpublic Map<String, String> getLabels() {\n\t\treturn this.labels;\n\t}\n\n\t/**\n\t * Return the image environment variables. If the image has no environment variables,\n\t * an empty {@code Map} is returned.\n\t * @return the env, never {@code null}\n\t */\n\tpublic Map<String, @Nullable String> getEnv() {\n\t\treturn this.configEnv;\n\t}\n\n\t/**\n\t * Create an updated copy of this image config.\n\t * @param update consumer to apply updates\n\t * @return an updated image config\n\t */\n\tpublic ImageConfig copy(Consumer<Update> update) {\n\t\treturn new Update(this).run(update);\n\n\t}\n\n\t/**\n\t * Update class used to change data when creating a copy.\n\t */\n\tpublic static final class Update {\n\n\t\tprivate final ObjectNode copy;\n\n\t\tprivate Update(ImageConfig source) {\n\t\t\tthis.copy = (ObjectNode) source.getNode().deepCopy();\n\t\t}\n\n\t\tprivate ImageConfig run(Consumer<Update> update) {\n\t\t\tupdate.accept(this);\n\t\t\treturn new ImageConfig(this.copy);\n\t\t}\n\n\t\t/**\n\t\t * Update the image config with an additional label.\n\t\t * @param label the label name\n\t\t * @param value the label value\n\t\t */\n\t\tpublic void withLabel(String label, String value) {\n\t\t\tJsonNode labels = this.copy.at(\"/Labels\");\n\t\t\tif (labels.isMissingNode()) {\n\t\t\t\tlabels = this.copy.putObject(\"Labels\");\n\t\t\t}\n\t\t\t((ObjectNode) labels).put(label, value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A Docker image name of the form {@literal \"docker.io/library/ubuntu\"}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n * @see ImageReference\n * @see #of(String)\n */\npublic class ImageName {\n\n\tprivate static final String DEFAULT_DOMAIN = \"docker.io\";\n\n\tprivate static final String OFFICIAL_REPOSITORY_NAME = \"library\";\n\n\tprivate static final String LEGACY_DOMAIN = \"index.docker.io\";\n\n\tprivate final String domain;\n\n\tprivate final String name;\n\n\tprivate final String string;\n\n\tImageName(@Nullable String domain, String path) {\n\t\tAssert.hasText(path, \"'path' must not be empty\");\n\t\tthis.domain = getDomainOrDefault(domain);\n\t\tthis.name = getNameWithDefaultPath(this.domain, path);\n\t\tthis.string = this.domain + \"/\" + this.name;\n\t}\n\n\t/**\n\t * Return the domain for this image name.\n\t * @return the domain\n\t */\n\tpublic String getDomain() {\n\t\treturn this.domain;\n\t}\n\n\t/**\n\t * Return the name of this image.\n\t * @return the image name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tImageName other = (ImageName) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.domain.equals(other.domain);\n\t\tresult = result && this.name.equals(other.name);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.domain.hashCode();\n\t\tresult = prime * result + this.name.hashCode();\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.string;\n\t}\n\n\tpublic String toLegacyString() {\n\t\tif (DEFAULT_DOMAIN.equals(this.domain)) {\n\t\t\treturn LEGACY_DOMAIN + \"/\" + this.name;\n\t\t}\n\t\treturn this.string;\n\t}\n\n\tprivate String getDomainOrDefault(@Nullable String domain) {\n\t\tif (domain == null || LEGACY_DOMAIN.equals(domain)) {\n\t\t\treturn DEFAULT_DOMAIN;\n\t\t}\n\t\treturn domain;\n\t}\n\n\tprivate String getNameWithDefaultPath(String domain, String name) {\n\t\tif (DEFAULT_DOMAIN.equals(domain) && !name.contains(\"/\")) {\n\t\t\treturn OFFICIAL_REPOSITORY_NAME + \"/\" + name;\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * Create a new {@link ImageName} from the given value. The following value forms can\n\t * be used:\n\t * <ul>\n\t * <li>{@code name} (maps to {@code docker.io/library/name})</li>\n\t * <li>{@code domain/name}</li>\n\t * <li>{@code domain:port/name}</li>\n\t * </ul>\n\t * @param value the value to parse\n\t * @return an {@link ImageName} instance\n\t */\n\tpublic static ImageName of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tString domain = parseDomain(value);\n\t\tString path = (domain != null) ? value.substring(domain.length() + 1) : value;\n\t\tAssert.isTrue(Regex.PATH.matcher(path).matches(),\n\t\t\t\t() -> \"'value' [\" + value + \"] must be a parsable name in the form '[domainHost:port/][path/]name' (\"\n\t\t\t\t\t\t+ \"with 'path' and 'name' containing only [a-z0-9][.][_][-])\");\n\t\treturn new ImageName(domain, path);\n\t}\n\n\tstatic @Nullable String parseDomain(String value) {\n\t\tint firstSlash = value.indexOf('/');\n\t\tString candidate = (firstSlash != -1) ? value.substring(0, firstSlash) : null;\n\t\tif (candidate != null && Regex.DOMAIN.matcher(candidate).matches()) {\n\t\t\treturn candidate;\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ImageReference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.File;\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A reference to a Docker image of the form {@code \"imagename[:tag|@digest]\"}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 2.3.0\n * @see ImageName\n */\npublic final class ImageReference {\n\n\tprivate static final Pattern JAR_VERSION_PATTERN = Pattern.compile(\"^(.*)(-\\\\d+)$\");\n\n\tprivate static final String LATEST = \"latest\";\n\n\tprivate final ImageName name;\n\n\tprivate final @Nullable String tag;\n\n\tprivate final @Nullable String digest;\n\n\tprivate final String string;\n\n\tprivate ImageReference(ImageName name, @Nullable String tag, @Nullable String digest) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.name = name;\n\t\tthis.tag = tag;\n\t\tthis.digest = digest;\n\t\tthis.string = buildString(name.toString(), tag, digest);\n\t}\n\n\t/**\n\t * Return the domain for this image name.\n\t * @return the domain\n\t * @see ImageName#getDomain()\n\t */\n\tpublic String getDomain() {\n\t\treturn this.name.getDomain();\n\t}\n\n\t/**\n\t * Return the name of this image.\n\t * @return the image name\n\t * @see ImageName#getName()\n\t */\n\tpublic String getName() {\n\t\treturn this.name.getName();\n\t}\n\n\t/**\n\t * Return the tag from the reference or {@code null}.\n\t * @return the referenced tag\n\t */\n\tpublic @Nullable String getTag() {\n\t\treturn this.tag;\n\t}\n\n\t/**\n\t * Return the digest from the reference or {@code null}.\n\t * @return the referenced digest\n\t */\n\tpublic @Nullable String getDigest() {\n\t\treturn this.digest;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tImageReference other = (ImageReference) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.name.equals(other.name);\n\t\tresult = result && ObjectUtils.nullSafeEquals(this.tag, other.tag);\n\t\tresult = result && ObjectUtils.nullSafeEquals(this.digest, other.digest);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.name.hashCode();\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.tag);\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.digest);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.string;\n\t}\n\n\tpublic String toLegacyString() {\n\t\treturn buildString(this.name.toLegacyString(), this.tag, this.digest);\n\t}\n\n\tprivate String buildString(String name, @Nullable String tag, @Nullable String digest) {\n\t\tStringBuilder string = new StringBuilder(name);\n\t\tif (tag != null) {\n\t\t\tstring.append(\":\").append(tag);\n\t\t}\n\t\tif (digest != null) {\n\t\t\tstring.append(\"@\").append(digest);\n\t\t}\n\t\treturn string.toString();\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} with an updated digest.\n\t * @param digest the new digest\n\t * @return an updated image reference\n\t */\n\tpublic ImageReference withDigest(String digest) {\n\t\treturn new ImageReference(this.name, null, digest);\n\t}\n\n\t/**\n\t * Return an {@link ImageReference} in the form {@code \"imagename:tag\"}. If the tag\n\t * has not been defined then {@code latest} is used.\n\t * @return the image reference in tagged form\n\t * @throws IllegalStateException if the image reference contains a digest\n\t */\n\tpublic ImageReference inTaggedForm() {\n\t\tAssert.state(this.digest == null, () -> \"Image reference '\" + this + \"' cannot contain a digest\");\n\t\treturn new ImageReference(this.name, (this.tag != null) ? this.tag : LATEST, null);\n\t}\n\n\t/**\n\t * Return an {@link ImageReference} without the tag.\n\t * @return the image reference in tagless form\n\t * @since 2.7.12\n\t */\n\tpublic ImageReference inTaglessForm() {\n\t\tif (this.tag == null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new ImageReference(this.name, null, this.digest);\n\t}\n\n\t/**\n\t * Return an {@link ImageReference} containing either a tag or a digest. If neither\n\t * the digest nor the tag has been defined then tag {@code latest} is used.\n\t * @return the image reference in tagged or digest form\n\t */\n\tpublic ImageReference inTaggedOrDigestForm() {\n\t\tif (this.digest != null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn inTaggedForm();\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} instance deduced from a source JAR file that\n\t * follows common Java naming conventions.\n\t * @param jarFile the source jar file\n\t * @return an {@link ImageName} for the jar file.\n\t */\n\tpublic static ImageReference forJarFile(File jarFile) {\n\t\tAssert.notNull(jarFile, \"'jarFile' must not be null\");\n\t\tString filename = jarFile.getName();\n\t\tAssert.isTrue(filename.toLowerCase(Locale.ROOT).endsWith(\".jar\"),\n\t\t\t\t() -> \"'jarFile' must end with '.jar' [\" + jarFile + \"]\");\n\t\tfilename = filename.substring(0, filename.length() - 4);\n\t\tint firstDot = filename.indexOf('.');\n\t\tif (firstDot == -1) {\n\t\t\treturn of(filename);\n\t\t}\n\t\tString name = filename.substring(0, firstDot);\n\t\tString version = filename.substring(firstDot + 1);\n\t\tMatcher matcher = JAR_VERSION_PATTERN.matcher(name);\n\t\tif (matcher.matches()) {\n\t\t\tname = matcher.group(1);\n\t\t\tversion = matcher.group(2).substring(1) + \".\" + version;\n\t\t}\n\t\treturn of(ImageName.of(name), version);\n\t}\n\n\t/**\n\t * Generate an image name with a random suffix.\n\t * @param prefix the name prefix\n\t * @return a random image reference\n\t */\n\tpublic static ImageReference random(String prefix) {\n\t\treturn ImageReference.random(prefix, 10);\n\t}\n\n\t/**\n\t * Generate an image name with a random suffix.\n\t * @param prefix the name prefix\n\t * @param randomLength the number of chars in the random part of the name\n\t * @return a random image reference\n\t */\n\tpublic static ImageReference random(String prefix, int randomLength) {\n\t\treturn of(RandomString.generate(prefix, randomLength));\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} from the given value. The following value forms\n\t * can be used:\n\t * <ul>\n\t * <li>{@code name} (maps to {@code docker.io/library/name})</li>\n\t * <li>{@code domain/name}</li>\n\t * <li>{@code domain:port/name}</li>\n\t * <li>{@code domain:port/name:tag}</li>\n\t * <li>{@code domain:port/name@digest}</li>\n\t * </ul>\n\t * @param value the value to parse\n\t * @return an {@link ImageName} instance\n\t */\n\tpublic static ImageReference of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be null\");\n\t\tString domain = ImageName.parseDomain(value);\n\t\tString path = (domain != null) ? value.substring(domain.length() + 1) : value;\n\t\tString digest = null;\n\t\tint digestSplit = path.indexOf(\"@\");\n\t\tif (digestSplit != -1) {\n\t\t\tString remainder = path.substring(digestSplit + 1);\n\t\t\tMatcher matcher = Regex.DIGEST.matcher(remainder);\n\t\t\tif (matcher.find()) {\n\t\t\t\tdigest = remainder.substring(0, matcher.end());\n\t\t\t\tremainder = remainder.substring(matcher.end());\n\t\t\t\tpath = path.substring(0, digestSplit) + remainder;\n\t\t\t}\n\t\t}\n\t\tString tag = null;\n\t\tint tagSplit = path.lastIndexOf(\":\");\n\t\tif (tagSplit != -1) {\n\t\t\tString remainder = path.substring(tagSplit + 1);\n\t\t\tMatcher matcher = Regex.TAG.matcher(remainder);\n\t\t\tif (matcher.find()) {\n\t\t\t\ttag = remainder.substring(0, matcher.end());\n\t\t\t\tremainder = remainder.substring(matcher.end());\n\t\t\t\tpath = path.substring(0, tagSplit) + remainder;\n\t\t\t}\n\t\t}\n\t\tAssert.isTrue(isLowerCase(path) && matchesPathRegex(path),\n\t\t\t\t() -> \"'value' [\" + value + \"] must be an image reference in the form \"\n\t\t\t\t\t\t+ \"'[domainHost:port/][path/]name[:tag][@digest]' \"\n\t\t\t\t\t\t+ \"(with 'path' and 'name' containing only [a-z0-9][.][_][-])\");\n\t\tImageName name = new ImageName(domain, path);\n\t\treturn new ImageReference(name, tag, digest);\n\t}\n\n\tprivate static boolean isLowerCase(String path) {\n\t\treturn path.toLowerCase(Locale.ENGLISH).equals(path);\n\t}\n\n\tprivate static boolean matchesPathRegex(String path) {\n\t\treturn Regex.PATH.matcher(path).matches();\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} from the given {@link ImageName}.\n\t * @param name the image name\n\t * @return a new image reference\n\t */\n\tpublic static ImageReference of(ImageName name) {\n\t\treturn new ImageReference(name, null, null);\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} from the given {@link ImageName} and tag.\n\t * @param name the image name\n\t * @param tag the referenced tag\n\t * @return a new image reference\n\t */\n\tpublic static ImageReference of(ImageName name, String tag) {\n\t\treturn new ImageReference(name, tag, null);\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} from the given {@link ImageName}, tag and\n\t * digest.\n\t * @param name the image name\n\t * @param tag the referenced tag\n\t * @param digest the referenced digest\n\t * @return a new image reference\n\t */\n\tpublic static ImageReference of(ImageName name, String tag, String digest) {\n\t\treturn new ImageReference(name, tag, digest);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/Layer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.InspectedContent;\nimport org.springframework.boot.buildpack.platform.io.Layout;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.util.Assert;\n\n/**\n * A layer that can be written to an {@link ImageArchive}.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class Layer implements Content {\n\n\tprivate final Content content;\n\n\tprivate final LayerId id;\n\n\tLayer(TarArchive tarArchive) throws NoSuchAlgorithmException, IOException {\n\t\tMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n\t\tthis.content = InspectedContent.of(tarArchive::writeTo, digest::update);\n\t\tthis.id = LayerId.ofSha256Digest(digest.digest());\n\t}\n\n\t/**\n\t * Return the ID of the layer.\n\t * @return the layer ID\n\t */\n\tpublic LayerId getId() {\n\t\treturn this.id;\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\treturn this.content.size();\n\t}\n\n\t@Override\n\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\tthis.content.writeTo(outputStream);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link Layer} with a specific {@link Layout}.\n\t * @param layout the layer layout\n\t * @return a new layer instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static Layer of(IOConsumer<Layout> layout) throws IOException {\n\t\tAssert.notNull(layout, \"'layout' must not be null\");\n\t\treturn fromTarArchive(TarArchive.of(layout));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link Layer} from a {@link TarArchive}.\n\t * @param tarArchive the contents of the layer\n\t * @return a new layer instance\n\t * @throws IOException on error\n\t */\n\tpublic static Layer fromTarArchive(TarArchive tarArchive) throws IOException {\n\t\tAssert.notNull(tarArchive, \"'tarArchive' must not be null\");\n\t\ttry {\n\t\t\treturn new Layer(tarArchive);\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/LayerId.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.math.BigInteger;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A layer ID as used inside a Docker image of the form {@code algorithm: hash}.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic final class LayerId {\n\n\tprivate final String value;\n\n\tprivate final String algorithm;\n\n\tprivate final String hash;\n\n\tprivate LayerId(String value, String algorithm, String hash) {\n\t\tthis.value = value;\n\t\tthis.algorithm = algorithm;\n\t\tthis.hash = hash;\n\t}\n\n\t/**\n\t * Return the algorithm of layer.\n\t * @return the algorithm\n\t */\n\tpublic String getAlgorithm() {\n\t\treturn this.algorithm;\n\t}\n\n\t/**\n\t * Return the hash of the layer.\n\t * @return the layer hash\n\t */\n\tpublic String getHash() {\n\t\treturn this.hash;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.value.equals(((LayerId) obj).value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Create a new {@link LayerId} with the specified value.\n\t * @param value the layer ID value of the form {@code algorithm: hash}\n\t * @return a new layer ID instance\n\t */\n\tpublic static LayerId of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tint i = value.indexOf(':');\n\t\tAssert.isTrue(i >= 0, () -> \"'value' [%s] must contain a valid layer ID\".formatted(value));\n\t\treturn new LayerId(value, value.substring(0, i), value.substring(i + 1));\n\t}\n\n\t/**\n\t * Create a new {@link LayerId} from a SHA-256 digest.\n\t * @param digest the digest\n\t * @return a new layer ID instance\n\t */\n\tpublic static LayerId ofSha256Digest(byte[] digest) {\n\t\tAssert.notNull(digest, \"'digest' must not be null\");\n\t\tAssert.isTrue(digest.length == 32, \"'digest' must be exactly 32 bytes\");\n\t\tString algorithm = \"sha256\";\n\t\tString hash = String.format(\"%064x\", new BigInteger(1, digest));\n\t\treturn new LayerId(algorithm + \":\" + hash, algorithm, hash);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/Manifest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.Assert;\n\n/**\n * A manifest as defined in {@code application/vnd.docker.distribution.manifest} or\n * {@code application/vnd.oci.image.manifest} files.\n *\n * @author Phillip Webb\n * @since 3.2.6\n * @see <a href=\"https://github.com/opencontainers/image-spec/blob/main/manifest.md\">OCI\n * Image Manifest Specification</a>\n */\npublic class Manifest extends MappedObject {\n\n\tprivate final Integer schemaVersion;\n\n\tprivate final @Nullable String mediaType;\n\n\tprivate final List<BlobReference> layers;\n\n\tprotected Manifest(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.schemaVersion = extractSchemaVersion();\n\t\tthis.mediaType = valueAt(\"/mediaType\", String.class);\n\t\tthis.layers = childrenAt(\"/layers\", BlobReference::new);\n\t}\n\n\tprivate Integer extractSchemaVersion() {\n\t\tInteger result = valueAt(\"/schemaVersion\", Integer.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tpublic Integer getSchemaVersion() {\n\t\treturn this.schemaVersion;\n\t}\n\n\tpublic @Nullable String getMediaType() {\n\t\treturn this.mediaType;\n\t}\n\n\tpublic List<BlobReference> getLayers() {\n\t\treturn this.layers;\n\t}\n\n\t/**\n\t * Create an {@link Manifest} from the provided JSON input stream.\n\t * @param content the JSON input stream\n\t * @return a new {@link Manifest} instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static Manifest of(InputStream content) throws IOException {\n\t\treturn of(content, Manifest::new);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/ManifestList.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObject;\nimport org.springframework.util.Assert;\n\n/**\n * A distribution manifest list as defined in\n * {@code application/vnd.docker.distribution.manifest.list} files.\n *\n * @author Phillip Webb\n * @since 3.2.6\n * @see <a href=\"https://github.com/opencontainers/image-spec/blob/main/manifest.md\">OCI\n * Image Manifest Specification</a>\n */\npublic class ManifestList extends MappedObject {\n\n\tprivate final Integer schemaVersion;\n\n\tprivate final @Nullable String mediaType;\n\n\tprivate final List<BlobReference> manifests;\n\n\tprotected ManifestList(JsonNode node) {\n\t\tsuper(node, MethodHandles.lookup());\n\t\tthis.schemaVersion = extractSchemaVersion();\n\t\tthis.mediaType = valueAt(\"/mediaType\", String.class);\n\t\tthis.manifests = childrenAt(\"/manifests\", BlobReference::new);\n\t}\n\n\tprivate Integer extractSchemaVersion() {\n\t\tInteger result = valueAt(\"/schemaVersion\", Integer.class);\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tpublic Integer getSchemaVersion() {\n\t\treturn this.schemaVersion;\n\t}\n\n\tpublic @Nullable String getMediaType() {\n\t\treturn this.mediaType;\n\t}\n\n\tpublic Stream<BlobReference> streamManifests() {\n\t\treturn getManifests().stream();\n\t}\n\n\tpublic List<BlobReference> getManifests() {\n\t\treturn this.manifests;\n\t}\n\n\t/**\n\t * Create an {@link ManifestList} from the provided JSON input stream.\n\t * @param content the JSON input stream\n\t * @return a new {@link ManifestList} instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static ManifestList of(InputStream content) throws IOException {\n\t\treturn of(content, ManifestList::new);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/RandomString.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.util.Random;\nimport java.util.stream.IntStream;\n\nimport org.springframework.util.Assert;\n\n/**\n * Utility class used to generate random strings.\n *\n * @author Phillip Webb\n */\nfinal class RandomString {\n\n\tprivate static final Random random = new Random();\n\n\tprivate RandomString() {\n\t}\n\n\tstatic String generate(String prefix, int randomLength) {\n\t\tAssert.notNull(prefix, \"'prefix' must not be null\");\n\t\treturn prefix + generateRandom(randomLength);\n\t}\n\n\tstatic CharSequence generateRandom(int length) {\n\t\tIntStream chars = random.ints('a', 'z' + 1).limit(length);\n\t\treturn chars.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/Regex.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.util.regex.Pattern;\n\n/**\n * Regular Expressions for image names and references based on those found in the Docker\n * codebase.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @see <a href=\n * \"https://github.com/docker/distribution/blob/master/reference/reference.go\">Docker\n * grammar reference</a>\n * @see <a href=\n * \"https://github.com/docker/distribution/blob/master/reference/regexp.go\">Docker grammar\n * implementation</a>\n * @see <a href=\n * \"https://stackoverflow.com/questions/37861791/how-are-docker-image-names-parsed\">How\n * are Docker image names parsed?</a>\n */\nfinal class Regex implements CharSequence {\n\n\tstatic final Pattern DOMAIN;\n\tstatic {\n\t\tRegex component = Regex.oneOf(\"[a-zA-Z0-9]\", \"[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]\");\n\t\tRegex dotComponent = Regex.group(\"[.]\", component);\n\t\tRegex colonPort = Regex.of(\"[:][0-9]+\");\n\t\tRegex dottedDomain = Regex.group(component, dotComponent.oneOrMoreTimes());\n\t\tRegex dottedDomainAndPort = Regex.group(component, dotComponent.oneOrMoreTimes(), colonPort);\n\t\tRegex nameAndPort = Regex.group(component, colonPort);\n\t\tDOMAIN = Regex.oneOf(dottedDomain, nameAndPort, dottedDomainAndPort, \"localhost\").compile();\n\t}\n\n\tprivate static final Regex PATH_COMPONENT;\n\tstatic {\n\t\tRegex segment = Regex.of(\"[a-z0-9]+\");\n\t\tRegex separator = Regex.group(\"[._-]{1,2}\");\n\t\tRegex separatedSegment = Regex.group(separator, segment).oneOrMoreTimes();\n\t\tPATH_COMPONENT = Regex.of(segment, Regex.group(separatedSegment).zeroOrOnce());\n\t}\n\n\tstatic final Pattern PATH;\n\tstatic {\n\t\tRegex component = PATH_COMPONENT;\n\t\tRegex slashComponent = Regex.group(\"[/]\", component);\n\t\tRegex slashComponents = Regex.group(slashComponent.oneOrMoreTimes());\n\t\tPATH = Regex.of(component, slashComponents.zeroOrOnce()).compile();\n\t}\n\n\tstatic final Pattern TAG = Regex.of(\"^[\\\\w][\\\\w.-]{0,127}\").compile();\n\n\tstatic final Pattern DIGEST = Regex.of(\"^[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[A-Fa-f0-9]]{32,}\")\n\t\t.compile();\n\n\tprivate final String value;\n\n\tprivate Regex(CharSequence value) {\n\t\tthis.value = value.toString();\n\t}\n\n\tprivate Regex oneOrMoreTimes() {\n\t\treturn new Regex(this.value + \"+\");\n\t}\n\n\tprivate Regex zeroOrOnce() {\n\t\treturn new Regex(this.value + \"?\");\n\t}\n\n\tPattern compile() {\n\t\treturn Pattern.compile(\"^\" + this.value + \"$\");\n\t}\n\n\t@Override\n\tpublic int length() {\n\t\treturn this.value.length();\n\t}\n\n\t@Override\n\tpublic char charAt(int index) {\n\t\treturn this.value.charAt(index);\n\t}\n\n\t@Override\n\tpublic CharSequence subSequence(int start, int end) {\n\t\treturn this.value.subSequence(start, end);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\tprivate static Regex of(CharSequence... expressions) {\n\t\treturn new Regex(String.join(\"\", expressions));\n\t}\n\n\tprivate static Regex oneOf(CharSequence... expressions) {\n\t\treturn new Regex(\"(?:\" + String.join(\"|\", expressions) + \")\");\n\t}\n\n\tprivate static Regex group(CharSequence... expressions) {\n\t\treturn new Regex(\"(?:\" + String.join(\"\", expressions) + \")\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/VolumeName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HexFormat;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A Docker volume name.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic final class VolumeName {\n\n\tprivate final String value;\n\n\tprivate VolumeName(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.value.equals(((VolumeName) obj).value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link VolumeName} with a random name.\n\t * @param prefix the prefix to use with the random name\n\t * @return a randomly named volume\n\t */\n\tpublic static VolumeName random(String prefix) {\n\t\treturn random(prefix, 10);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link VolumeName} with a random name.\n\t * @param prefix the prefix to use with the random name\n\t * @param randomLength the number of chars in the random part of the name\n\t * @return a randomly named volume reference\n\t */\n\tpublic static VolumeName random(String prefix, int randomLength) {\n\t\treturn of(RandomString.generate(prefix, randomLength));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link VolumeName} based on an object. The resulting\n\t * name will be based off a SHA-256 digest of the given object's {@code toString()}\n\t * method.\n\t * @param <S> the source object type\n\t * @param source the source object\n\t * @param prefix the prefix to use with the volume name\n\t * @param suffix the suffix to use with the volume name\n\t * @param digestLength the number of chars in the digest part of the name\n\t * @return a name based off the image reference\n\t */\n\tpublic static <S> VolumeName basedOn(S source, String prefix, String suffix, int digestLength) {\n\t\treturn basedOn(source, Object::toString, prefix, suffix, digestLength);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link VolumeName} based on an object. The resulting\n\t * name will be based off a SHA-256 digest of the given object's name.\n\t * @param <S> the source object type\n\t * @param source the source object\n\t * @param nameExtractor a method to extract the name of the object\n\t * @param prefix the prefix to use with the volume name\n\t * @param suffix the suffix to use with the volume name\n\t * @param digestLength the number of chars in the digest part of the name\n\t * @return a name based off the image reference\n\t */\n\tpublic static <S> VolumeName basedOn(S source, Function<S, String> nameExtractor, String prefix, String suffix,\n\t\t\tint digestLength) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(nameExtractor, \"'nameExtractor' must not be null\");\n\t\tAssert.notNull(prefix, \"'prefix' must not be null\");\n\t\tAssert.notNull(suffix, \"'suffix' must not be null\");\n\t\treturn of(prefix + getDigest(nameExtractor.apply(source), digestLength) + suffix);\n\t}\n\n\tprivate static String getDigest(String name, int length) {\n\t\ttry {\n\t\t\tMessageDigest digest = MessageDigest.getInstance(\"sha-256\");\n\t\t\treturn asHexString(digest.digest(name.getBytes(StandardCharsets.UTF_8)), length);\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate static String asHexString(byte[] digest, int digestLength) {\n\t\tAssert.isTrue(digestLength <= digest.length,\n\t\t\t\t() -> \"'digestLength' must be less than or equal to \" + digest.length);\n\t\treturn HexFormat.of().formatHex(digest, 0, digestLength);\n\t}\n\n\t/**\n\t * Factory method to create a {@link VolumeName} with a specific value.\n\t * @param value the volume reference value\n\t * @return a new {@link VolumeName} instance\n\t */\n\tpublic static VolumeName of(String value) {\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\treturn new VolumeName(value);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/docker/type/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Docker types.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/Content.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * Content with a known size that can be written to an {@link OutputStream}.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface Content {\n\n\t/**\n\t * The size of the content in bytes.\n\t * @return the content size\n\t */\n\tint size();\n\n\t/**\n\t * Write the content to the given output stream.\n\t * @param outputStream the output stream to write to\n\t * @throws IOException on IO error\n\t */\n\tvoid writeTo(OutputStream outputStream) throws IOException;\n\n\t/**\n\t * Create a new {@link Content} from the given UTF-8 string.\n\t * @param string the string to write\n\t * @return a new {@link Content} instance\n\t */\n\tstatic Content of(String string) {\n\t\tAssert.notNull(string, \"'string' must not be null\");\n\t\treturn of(string.getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t/**\n\t * Create a new {@link Content} from the given input stream.\n\t * @param bytes the bytes to write\n\t * @return a new {@link Content} instance\n\t */\n\tstatic Content of(byte[] bytes) {\n\t\tAssert.notNull(bytes, \"'bytes' must not be null\");\n\t\treturn of(bytes.length, () -> new ByteArrayInputStream(bytes));\n\t}\n\n\t/**\n\t * Create a new {@link Content} from the given file.\n\t * @param file the file to write\n\t * @return a new {@link Content} instance\n\t */\n\tstatic Content of(File file) {\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\treturn of((int) file.length(), () -> new FileInputStream(file));\n\t}\n\n\t/**\n\t * Create a new {@link Content} from the given input stream. The stream will be closed\n\t * after it has been written.\n\t * @param size the size of the supplied input stream\n\t * @param supplier the input stream supplier\n\t * @return a new {@link Content} instance\n\t */\n\tstatic Content of(int size, IOSupplier<InputStream> supplier) {\n\t\tAssert.isTrue(size >= 0, \"'size' must not be negative\");\n\t\tAssert.notNull(supplier, \"'supplier' must not be null\");\n\t\treturn new Content() {\n\n\t\t\t@Override\n\t\t\tpublic int size() {\n\t\t\t\treturn size;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\t\t\tFileCopyUtils.copy(supplier.get(), outputStream);\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/DefaultOwner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\n/**\n * Default {@link Owner} implementation.\n *\n * @author Phillip Webb\n * @see Owner#of(long, long)\n */\nclass DefaultOwner implements Owner {\n\n\tprivate final long uid;\n\n\tprivate final long gid;\n\n\tDefaultOwner(long uid, long gid) {\n\t\tthis.uid = uid;\n\t\tthis.gid = gid;\n\t}\n\n\t@Override\n\tpublic long getUid() {\n\t\treturn this.uid;\n\t}\n\n\t@Override\n\tpublic long getGid() {\n\t\treturn this.gid;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.uid + \"/\" + this.gid;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/FilePermissions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.PosixFileAttributeView;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.util.Collection;\n\nimport org.springframework.util.Assert;\n\n/**\n * Utilities for dealing with file permissions and attributes.\n *\n * @author Scott Frederick\n * @since 2.5.0\n */\npublic final class FilePermissions {\n\n\tprivate FilePermissions() {\n\t}\n\n\t/**\n\t * Return the integer representation of the file permissions for a path, where the\n\t * integer value conforms to the\n\t * <a href=\"https://en.wikipedia.org/wiki/Umask\">umask</a> octal notation.\n\t * @param path the file path\n\t * @return the integer representation\n\t * @throws IOException if path permissions cannot be read\n\t */\n\tpublic static int umaskForPath(Path path) throws IOException {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tPosixFileAttributeView attributeView = Files.getFileAttributeView(path, PosixFileAttributeView.class);\n\t\tAssert.state(attributeView != null, \"Unsupported file type for retrieving Posix attributes\");\n\t\treturn posixPermissionsToUmask(attributeView.readAttributes().permissions());\n\t}\n\n\t/**\n\t * Return the integer representation of a set of Posix file permissions, where the\n\t * integer value conforms to the\n\t * <a href=\"https://en.wikipedia.org/wiki/Umask\">umask</a> octal notation.\n\t * @param permissions the set of {@code PosixFilePermission}s\n\t * @return the integer representation\n\t */\n\tpublic static int posixPermissionsToUmask(Collection<PosixFilePermission> permissions) {\n\t\tAssert.notNull(permissions, \"'permissions' must not be null\");\n\t\tint owner = permissionToUmask(permissions, PosixFilePermission.OWNER_EXECUTE, PosixFilePermission.OWNER_WRITE,\n\t\t\t\tPosixFilePermission.OWNER_READ);\n\t\tint group = permissionToUmask(permissions, PosixFilePermission.GROUP_EXECUTE, PosixFilePermission.GROUP_WRITE,\n\t\t\t\tPosixFilePermission.GROUP_READ);\n\t\tint other = permissionToUmask(permissions, PosixFilePermission.OTHERS_EXECUTE, PosixFilePermission.OTHERS_WRITE,\n\t\t\t\tPosixFilePermission.OTHERS_READ);\n\t\treturn Integer.parseInt(\"\" + owner + group + other, 8);\n\t}\n\n\tprivate static int permissionToUmask(Collection<PosixFilePermission> permissions, PosixFilePermission execute,\n\t\t\tPosixFilePermission write, PosixFilePermission read) {\n\t\tint value = 0;\n\t\tif (permissions.contains(execute)) {\n\t\t\tvalue += 1;\n\t\t}\n\t\tif (permissions.contains(write)) {\n\t\t\tvalue += 2;\n\t\t}\n\t\tif (permissions.contains(read)) {\n\t\t\tvalue += 4;\n\t\t}\n\t\treturn value;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/IOBiConsumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.IOException;\n\n/**\n * BiConsumer that can safely throw {@link IOException IO exceptions}.\n *\n * @param <T> the first consumed type\n * @param <U> the second consumed type\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface IOBiConsumer<T, U> {\n\n\t/**\n\t * Performs this operation on the given argument.\n\t * @param t the first instance to consume\n\t * @param u the second instance to consumer\n\t * @throws IOException on IO error\n\t */\n\tvoid accept(T t, U u) throws IOException;\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/IOConsumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.IOException;\n\n/**\n * Consumer that can safely throw {@link IOException IO exceptions}.\n *\n * @param <T> the consumed type\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface IOConsumer<T> {\n\n\t/**\n\t * Performs this operation on the given argument.\n\t * @param t the instance to consume\n\t * @throws IOException on IO error\n\t */\n\tvoid accept(T t) throws IOException;\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/IOSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.IOException;\n\n/**\n * Supplier that can safely throw {@link IOException IO exceptions}.\n *\n * @param <T> the supplied type\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface IOSupplier<T> {\n\n\t/**\n\t * Gets the supplied value.\n\t * @return the supplied value\n\t * @throws IOException on IO error\n\t */\n\tT get() throws IOException;\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/InspectedContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\n/**\n * {@link Content} that is reads and inspects a source of data only once but allows it to\n * be consumed multiple times.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class InspectedContent implements Content {\n\n\tstatic final int MEMORY_LIMIT = 4 * 1024 + 3;\n\n\tprivate final int size;\n\n\tprivate final Object content;\n\n\tInspectedContent(int size, Object content) {\n\t\tthis.size = size;\n\t\tthis.content = content;\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\treturn this.size;\n\t}\n\n\t@Override\n\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\tif (this.content instanceof byte[] bytes) {\n\t\t\tFileCopyUtils.copy(bytes, outputStream);\n\t\t}\n\t\telse if (this.content instanceof File file) {\n\t\t\tInputStream inputStream = new FileInputStream(file);\n\t\t\tFileCopyUtils.copy(inputStream, outputStream);\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalStateException(\"Unknown content type\");\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to create an {@link InspectedContent} instance from a source input\n\t * stream.\n\t * @param inputStream the content input stream\n\t * @param inspectors any inspectors to apply\n\t * @return a new inspected content instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static InspectedContent of(InputStream inputStream, Inspector... inspectors) throws IOException {\n\t\tAssert.notNull(inputStream, \"'inputStream' must not be null\");\n\t\treturn of((outputStream) -> FileCopyUtils.copy(inputStream, outputStream), inspectors);\n\t}\n\n\t/**\n\t * Factory method to create an {@link InspectedContent} instance from source content.\n\t * @param content the content\n\t * @param inspectors any inspectors to apply\n\t * @return a new inspected content instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static InspectedContent of(Content content, Inspector... inspectors) throws IOException {\n\t\tAssert.notNull(content, \"'content' must not be null\");\n\t\treturn of(content::writeTo, inspectors);\n\t}\n\n\t/**\n\t * Factory method to create an {@link InspectedContent} instance from a source write\n\t * method.\n\t * @param writer a consumer representing the write method\n\t * @param inspectors any inspectors to apply\n\t * @return a new inspected content instance\n\t * @throws IOException on IO error\n\t */\n\tpublic static InspectedContent of(IOConsumer<OutputStream> writer, Inspector... inspectors) throws IOException {\n\t\tAssert.notNull(writer, \"'writer' must not be null\");\n\t\tInspectingOutputStream outputStream = new InspectingOutputStream(inspectors);\n\t\ttry (outputStream) {\n\t\t\twriter.accept(outputStream);\n\t\t}\n\t\treturn new InspectedContent(outputStream.getSize(), outputStream.getContent());\n\t}\n\n\t/**\n\t * Interface that can be used to inspect content as it is initially read.\n\t */\n\tpublic interface Inspector {\n\n\t\t/**\n\t\t * Update inspected information based on the provided bytes.\n\t\t * @param input the array of bytes.\n\t\t * @param offset the offset to start from in the array of bytes.\n\t\t * @param len the number of bytes to use, starting at {@code offset}.\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tvoid update(byte[] input, int offset, int len) throws IOException;\n\n\t}\n\n\t/**\n\t * Internal {@link OutputStream} used to capture the content either as bytes, or to a\n\t * File if the content is too large.\n\t */\n\tprivate static final class InspectingOutputStream extends OutputStream {\n\n\t\tprivate final Inspector[] inspectors;\n\n\t\tprivate int size;\n\n\t\tprivate OutputStream delegate;\n\n\t\tprivate @Nullable File tempFile;\n\n\t\tprivate final byte[] singleByteBuffer = new byte[1];\n\n\t\tprivate InspectingOutputStream(Inspector[] inspectors) {\n\t\t\tthis.inspectors = inspectors;\n\t\t\tthis.delegate = new ByteArrayOutputStream();\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(int b) throws IOException {\n\t\t\tthis.singleByteBuffer[0] = (byte) (b & 0xFF);\n\t\t\twrite(this.singleByteBuffer);\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(byte[] b, int off, int len) throws IOException {\n\t\t\tint size = len - off;\n\t\t\tif (this.tempFile == null && (this.size + size) > MEMORY_LIMIT) {\n\t\t\t\tconvertToTempFile();\n\t\t\t}\n\t\t\tthis.delegate.write(b, off, len);\n\t\t\tfor (Inspector inspector : this.inspectors) {\n\t\t\t\tinspector.update(b, off, len);\n\t\t\t}\n\t\t\tthis.size += size;\n\t\t}\n\n\t\tprivate void convertToTempFile() throws IOException {\n\t\t\tthis.tempFile = File.createTempFile(\"buildpack\", \".tmp\");\n\t\t\tbyte[] bytes = ((ByteArrayOutputStream) this.delegate).toByteArray();\n\t\t\tthis.delegate = new FileOutputStream(this.tempFile);\n\t\t\tStreamUtils.copy(bytes, this.delegate);\n\t\t}\n\n\t\tprivate Object getContent() {\n\t\t\treturn (this.tempFile != null) ? this.tempFile : ((ByteArrayOutputStream) this.delegate).toByteArray();\n\t\t}\n\n\t\tprivate int getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/Layout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.IOException;\n\n/**\n * Interface that can be used to write a file/directory layout.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic interface Layout {\n\n\t/**\n\t * Add a directory to the content.\n\t * @param name the full name of the directory to add\n\t * @param owner the owner of the directory\n\t * @throws IOException on IO error\n\t */\n\tdefault void directory(String name, Owner owner) throws IOException {\n\t\tdirectory(name, owner, 0755);\n\t}\n\n\t/**\n\t * Add a directory to the content.\n\t * @param name the full name of the directory to add\n\t * @param owner the owner of the directory\n\t * @param mode the permissions for the file\n\t * @throws IOException on IO error\n\t */\n\tvoid directory(String name, Owner owner, int mode) throws IOException;\n\n\t/**\n\t * Write a file to the content.\n\t * @param name the full name of the file to add\n\t * @param owner the owner of the file\n\t * @param content the content to add\n\t * @throws IOException on IO error\n\t */\n\tdefault void file(String name, Owner owner, Content content) throws IOException {\n\t\tfile(name, owner, 0644, content);\n\t}\n\n\t/**\n\t * Write a file to the content.\n\t * @param name the full name of the file to add\n\t * @param owner the owner of the file\n\t * @param mode the permissions for the file\n\t * @param content the content to add\n\t * @throws IOException on IO error\n\t */\n\tvoid file(String name, Owner owner, int mode, Content content) throws IOException;\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/Owner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\n/**\n * A user and group ID that can be used to indicate file ownership.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface Owner {\n\n\t/**\n\t * Owner for root ownership.\n\t */\n\tOwner ROOT = Owner.of(0, 0);\n\n\t/**\n\t * Return the user identifier (UID) of the owner.\n\t * @return the user identifier\n\t */\n\tlong getUid();\n\n\t/**\n\t * Return the group identifier (GID) of the owner.\n\t * @return the group identifier\n\t */\n\tlong getGid();\n\n\t/**\n\t * Factory method to create a new {@link Owner} with specified user/group identifier.\n\t * @param uid the user identifier\n\t * @param gid the group identifier\n\t * @return a new {@link Owner} instance\n\t */\n\tstatic Owner of(long uid, long gid) {\n\t\treturn new DefaultOwner(uid, gid);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/TarArchive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.util.zip.GZIPInputStream;\n\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.function.ThrowingFunction;\n\n/**\n * A TAR archive that can be written to an output stream.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface TarArchive {\n\n\t/**\n\t * {@link Instant} that can be used to normalize TAR files so all entries have the\n\t * same modification time.\n\t */\n\tInstant NORMALIZED_TIME = OffsetDateTime.of(1980, 1, 1, 0, 0, 1, 0, ZoneOffset.UTC).toInstant();\n\n\t/**\n\t * Write the TAR archive to the given output stream.\n\t * @param outputStream the output stream to write to\n\t * @throws IOException on IO error\n\t */\n\tvoid writeTo(OutputStream outputStream) throws IOException;\n\n\t/**\n\t * Return the compression being used with the tar archive.\n\t * @return the used compression\n\t * @since 3.2.6\n\t */\n\tdefault Compression getCompression() {\n\t\treturn Compression.NONE;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link TarArchive} instance with a specific layout.\n\t * @param layout the TAR layout\n\t * @return a new {@link TarArchive} instance\n\t */\n\tstatic TarArchive of(IOConsumer<Layout> layout) {\n\t\treturn (outputStream) -> {\n\t\t\tTarLayoutWriter writer = new TarLayoutWriter(outputStream);\n\t\t\tlayout.accept(writer);\n\t\t\twriter.finish();\n\t\t};\n\t}\n\n\t/**\n\t * Factory method to adapt a ZIP file to {@link TarArchive}.\n\t * @param zip the source zip file\n\t * @param owner the owner of the entries in the TAR\n\t * @return a new {@link TarArchive} instance\n\t */\n\tstatic TarArchive fromZip(File zip, Owner owner) {\n\t\treturn new ZipFileTarArchive(zip, owner);\n\t}\n\n\t/**\n\t * Factory method to adapt a ZIP file to {@link TarArchive}. Assumes that\n\t * {@link #writeTo(OutputStream)} will only be called once.\n\t * @param inputStream the source input stream\n\t * @param compression the compression used\n\t * @return a new {@link TarArchive} instance\n\t * @since 3.2.6\n\t */\n\tstatic TarArchive fromInputStream(InputStream inputStream, Compression compression) {\n\t\treturn new TarArchive() {\n\n\t\t\t@Override\n\t\t\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\t\t\tStreamUtils.copy(compression.uncompress(inputStream), outputStream);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Compression getCompression() {\n\t\t\t\treturn compression;\n\t\t\t}\n\n\t\t};\n\t}\n\n\t/**\n\t * Compression type applied to the archive.\n\t *\n\t * @since 3.2.6\n\t */\n\tenum Compression {\n\n\t\t/**\n\t\t * The tar file is not compressed.\n\t\t */\n\t\tNONE((inputStream) -> inputStream),\n\n\t\t/**\n\t\t * The tar file is compressed using gzip.\n\t\t */\n\t\tGZIP(GZIPInputStream::new),\n\n\t\t/**\n\t\t * The tar file is compressed using zstd.\n\t\t */\n\t\tZSTD(\"zstd compression is not supported\");\n\n\t\tprivate final ThrowingFunction<InputStream, InputStream> uncompressor;\n\n\t\tCompression(String uncompressError) {\n\t\t\tthis((inputStream) -> {\n\t\t\t\tthrow new IllegalStateException(uncompressError);\n\t\t\t});\n\t\t}\n\n\t\tCompression(ThrowingFunction<InputStream, InputStream> wrapper) {\n\t\t\tthis.uncompressor = wrapper;\n\t\t}\n\n\t\tInputStream uncompress(InputStream inputStream) {\n\t\t\treturn this.uncompressor.apply(inputStream);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/TarLayoutWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.archivers.tar.TarConstants;\n\nimport org.springframework.util.StreamUtils;\n\n/**\n * {@link Layout} for writing TAR archive content directly to an {@link OutputStream}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass TarLayoutWriter implements Layout, Closeable {\n\n\tstatic final long NORMALIZED_MOD_TIME = TarArchive.NORMALIZED_TIME.toEpochMilli();\n\n\tprivate final TarArchiveOutputStream outputStream;\n\n\tTarLayoutWriter(OutputStream outputStream) {\n\t\tthis.outputStream = new TarArchiveOutputStream(outputStream);\n\t\tthis.outputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n\t}\n\n\t@Override\n\tpublic void directory(String name, Owner owner, int mode) throws IOException {\n\t\tthis.outputStream.putArchiveEntry(createDirectoryEntry(name, owner, mode));\n\t\tthis.outputStream.closeArchiveEntry();\n\t}\n\n\t@Override\n\tpublic void file(String name, Owner owner, int mode, Content content) throws IOException {\n\t\tthis.outputStream.putArchiveEntry(createFileEntry(name, owner, mode, content.size()));\n\t\tcontent.writeTo(StreamUtils.nonClosing(this.outputStream));\n\t\tthis.outputStream.closeArchiveEntry();\n\t}\n\n\tprivate TarArchiveEntry createDirectoryEntry(String name, Owner owner, int mode) {\n\t\treturn createEntry(name, owner, TarConstants.LF_DIR, mode, 0);\n\t}\n\n\tprivate TarArchiveEntry createFileEntry(String name, Owner owner, int mode, int size) {\n\t\treturn createEntry(name, owner, TarConstants.LF_NORMAL, mode, size);\n\t}\n\n\tprivate TarArchiveEntry createEntry(String name, Owner owner, byte linkFlag, int mode, int size) {\n\t\tTarArchiveEntry entry = new TarArchiveEntry(name, linkFlag, true);\n\t\tentry.setUserId(owner.getUid());\n\t\tentry.setGroupId(owner.getGid());\n\t\tentry.setMode(mode);\n\t\tentry.setModTime(NORMALIZED_MOD_TIME);\n\t\tentry.setSize(size);\n\t\treturn entry;\n\t}\n\n\tvoid finish() throws IOException {\n\t\tthis.outputStream.finish();\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.outputStream.close();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/ZipFileTarArchive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Enumeration;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.archivers.tar.TarConstants;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipFile;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Adapter class to convert a ZIP file to a {@link TarArchive}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class ZipFileTarArchive implements TarArchive {\n\n\tstatic final long NORMALIZED_MOD_TIME = TarArchive.NORMALIZED_TIME.toEpochMilli();\n\n\tprivate final File zip;\n\n\tprivate final Owner owner;\n\n\t/**\n\t * Creates an archive from the contents of the given {@code zip}. Each entry in the\n\t * archive will be owned by the given {@code owner}.\n\t * @param zip the zip to use as a source\n\t * @param owner the owner of the tar entries\n\t */\n\tpublic ZipFileTarArchive(File zip, Owner owner) {\n\t\tAssert.notNull(zip, \"'zip' must not be null\");\n\t\tAssert.notNull(owner, \"'owner' must not be null\");\n\t\tassertArchiveHasEntries(zip);\n\t\tthis.zip = zip;\n\t\tthis.owner = owner;\n\t}\n\n\t@Override\n\tpublic void writeTo(OutputStream outputStream) throws IOException {\n\t\tTarArchiveOutputStream tar = new TarArchiveOutputStream(outputStream);\n\t\ttar.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n\t\ttry (ZipFile zipFile = ZipFile.builder().setFile(this.zip).get()) {\n\t\t\tEnumeration<ZipArchiveEntry> entries = zipFile.getEntries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tZipArchiveEntry zipEntry = entries.nextElement();\n\t\t\t\tcopy(zipEntry, zipFile.getInputStream(zipEntry), tar);\n\t\t\t}\n\t\t}\n\t\ttar.finish();\n\t}\n\n\tprivate void assertArchiveHasEntries(File file) {\n\t\ttry (ZipFile zipFile = ZipFile.builder().setFile(file).get()) {\n\t\t\tAssert.state(zipFile.getEntries().hasMoreElements(), () -> \"Archive file '\" + file + \"' is not valid\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"File '\" + file + \"' is not readable\", ex);\n\t\t}\n\t}\n\n\tprivate void copy(ZipArchiveEntry zipEntry, InputStream zip, TarArchiveOutputStream tar) throws IOException {\n\t\tTarArchiveEntry tarEntry = convert(zipEntry);\n\t\ttar.putArchiveEntry(tarEntry);\n\t\tif (tarEntry.isFile()) {\n\t\t\tStreamUtils.copyRange(zip, tar, 0, tarEntry.getSize());\n\t\t}\n\t\ttar.closeArchiveEntry();\n\t}\n\n\tprivate TarArchiveEntry convert(ZipArchiveEntry zipEntry) {\n\t\tbyte linkFlag = (zipEntry.isDirectory()) ? TarConstants.LF_DIR : TarConstants.LF_NORMAL;\n\t\tTarArchiveEntry tarEntry = new TarArchiveEntry(zipEntry.getName(), linkFlag, true);\n\t\ttarEntry.setUserId(this.owner.getUid());\n\t\ttarEntry.setGroupId(this.owner.getGid());\n\t\ttarEntry.setModTime(NORMALIZED_MOD_TIME);\n\t\ttarEntry.setMode(zipEntry.getUnixMode());\n\t\tif (!zipEntry.isDirectory()) {\n\t\t\ttarEntry.setSize(zipEntry.getSize());\n\t\t}\n\t\treturn tarEntry;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/io/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * IO classes and utilities.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.io;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/json/JsonStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.core.JsonToken;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.node.ObjectNode;\n\n/**\n * Utility class that allows JSON to be parsed and processed as it's received.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class JsonStream {\n\n\tprivate final JsonMapper jsonMapper;\n\n\t/**\n\t * Create a new {@link JsonStream} backed by the given JSON mapper.\n\t * @param jsonMapper the object mapper to use\n\t * @since 4.0.0\n\t */\n\tpublic JsonStream(JsonMapper jsonMapper) {\n\t\tthis.jsonMapper = jsonMapper;\n\t}\n\n\t/**\n\t * Stream {@link ObjectNode object nodes} from the content as they become available.\n\t * @param content the source content\n\t * @param consumer the {@link ObjectNode} consumer\n\t * @throws IOException on IO error\n\t */\n\tpublic void get(InputStream content, Consumer<ObjectNode> consumer) throws IOException {\n\t\tget(content, ObjectNode.class, consumer);\n\t}\n\n\t/**\n\t * Stream objects from the content as they become available.\n\t * @param <T> the object type\n\t * @param content the source content\n\t * @param type the object type\n\t * @param consumer the {@link ObjectNode} consumer\n\t * @throws IOException on IO error\n\t */\n\tpublic <T> void get(InputStream content, Class<T> type, Consumer<T> consumer) throws IOException {\n\t\ttry (JsonParser parser = this.jsonMapper.createParser(content)) {\n\t\t\twhile (!parser.isClosed()) {\n\t\t\t\tJsonToken token = parser.nextToken();\n\t\t\t\tif (token != null && token != JsonToken.END_OBJECT) {\n\t\t\t\t\tT node = read(parser, type);\n\t\t\t\t\tif (node != null) {\n\t\t\t\t\t\tconsumer.accept(node);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T read(JsonParser parser, Class<T> type) {\n\t\tif (ObjectNode.class.isAssignableFrom(type)) {\n\t\t\tObjectNode node = (ObjectNode) this.jsonMapper.readTree(parser);\n\t\t\tif (node == null || node.isMissingNode() || node.isEmpty()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn (T) node;\n\t\t}\n\t\treturn this.jsonMapper.readValue(parser, type);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/json/MappedObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles.Lookup;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JacksonException;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Base class for mapped JSON objects.\n *\n * @author Phillip Webb\n * @author Dmytro Nosan\n * @since 2.3.0\n */\npublic class MappedObject {\n\n\tprivate final JsonNode node;\n\n\tprivate final Lookup lookup;\n\n\t/**\n\t * Create a new {@link MappedObject} instance.\n\t * @param node the source node\n\t * @param lookup method handle lookup\n\t */\n\tprotected MappedObject(JsonNode node, Lookup lookup) {\n\t\tthis.node = node;\n\t\tthis.lookup = lookup;\n\t}\n\n\t/**\n\t * Return the source node of the mapped object.\n\t * @return the source node\n\t */\n\tprotected final JsonNode getNode() {\n\t\treturn this.node;\n\t}\n\n\t/**\n\t * Get the value at the given JSON path expression as a specific type.\n\t * @param <T> the data type\n\t * @param expression the JSON path expression\n\t * @param type the desired type. May be a simple JSON type or an interface\n\t * @return the value\n\t */\n\tprotected <T> @Nullable T valueAt(String expression, Class<T> type) {\n\t\treturn valueAt(this, this.node, this.lookup, expression, type);\n\t}\n\n\t/**\n\t * Get a {@link Map} at the given JSON path expression with a value mapped from a\n\t * related {@link JsonNode}.\n\t * @param <V> the value type\n\t * @param expression the JSON path expression\n\t * @param valueMapper function to map the value from the {@link JsonNode}\n\t * @return the map\n\t * @since 3.5.0\n\t */\n\tprotected <V> Map<String, V> mapAt(String expression, Function<JsonNode, V> valueMapper) {\n\t\tMap<String, V> map = new LinkedHashMap<>();\n\t\tgetNode().at(expression)\n\t\t\t.properties()\n\t\t\t.forEach((entry) -> map.put(entry.getKey(), valueMapper.apply(entry.getValue())));\n\t\treturn Collections.unmodifiableMap(map);\n\t}\n\n\t/**\n\t * Get children at the given JSON path expression by constructing them using the given\n\t * factory.\n\t * @param <T> the child type\n\t * @param expression the JSON path expression\n\t * @param factory factory used to create the child\n\t * @return a list of children\n\t * @since 3.2.6\n\t */\n\tprotected <T> List<T> childrenAt(@Nullable String expression, Function<JsonNode, T> factory) {\n\t\tJsonNode node = (expression != null) ? this.node.at(expression) : this.node;\n\t\tif (node.isEmpty()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<T> children = new ArrayList<>();\n\t\tnode.values().forEach((childNode) -> children.add(factory.apply(childNode)));\n\t\treturn Collections.unmodifiableList(children);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected static <T extends MappedObject> T getRoot(Object proxy) {\n\t\tMappedInvocationHandler handler = (MappedInvocationHandler) Proxy.getInvocationHandler(proxy);\n\t\treturn (T) handler.root;\n\t}\n\n\tprotected static <T> @Nullable T valueAt(Object proxy, String expression, Class<T> type) {\n\t\tMappedInvocationHandler handler = (MappedInvocationHandler) Proxy.getInvocationHandler(proxy);\n\t\treturn valueAt(handler.root, handler.node, handler.lookup, expression, type);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <T> @Nullable T valueAt(MappedObject root, JsonNode node, Lookup lookup, String expression,\n\t\t\tClass<T> type) {\n\t\tJsonNode result = node.at(expression);\n\t\tif (result.isMissingNode() && expression.startsWith(\"/\") && expression.length() > 1\n\t\t\t\t&& Character.isLowerCase(expression.charAt(1))) {\n\t\t\tStringBuilder alternative = new StringBuilder(expression);\n\t\t\talternative.setCharAt(1, Character.toUpperCase(alternative.charAt(1)));\n\t\t\tresult = node.at(alternative.toString());\n\t\t}\n\t\tif (type.isInterface() && !type.getName().startsWith(\"java\")) {\n\t\t\treturn (T) Proxy.newProxyInstance(MappedObject.class.getClassLoader(), new Class<?>[] { type },\n\t\t\t\t\tnew MappedInvocationHandler(root, result, lookup));\n\t\t}\n\t\tif (result.isMissingNode()) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn SharedJsonMapper.get().treeToValue(result, type);\n\t\t}\n\t\tcatch (JacksonException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to create a new {@link MappedObject} instance.\n\t * @param <T> the mapped object type\n\t * @param content the JSON content for the object\n\t * @param factory a factory to create the mapped object from a {@link JsonNode}\n\t * @return the mapped object\n\t * @throws IOException on IO error\n\t */\n\tprotected static <T extends MappedObject> T of(String content, Function<JsonNode, T> factory) throws IOException {\n\t\treturn of(content, JsonMapper::readTree, factory);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link MappedObject} instance.\n\t * @param <T> the mapped object type\n\t * @param content the JSON content for the object\n\t * @param factory a factory to create the mapped object from a {@link JsonNode}\n\t * @return the mapped object\n\t * @throws IOException on IO error\n\t */\n\tprotected static <T extends MappedObject> T of(InputStream content, Function<JsonNode, T> factory)\n\t\t\tthrows IOException {\n\t\treturn of(StreamUtils.nonClosing(content), JsonMapper::readTree, factory);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link MappedObject} instance.\n\t * @param <T> the mapped object type\n\t * @param <C> the content type\n\t * @param content the JSON content for the object\n\t * @param reader the content reader\n\t * @param factory a factory to create the mapped object from a {@link JsonNode}\n\t * @return the mapped object\n\t * @throws IOException on IO error\n\t */\n\tprotected static <T extends MappedObject, C> T of(C content, ContentReader<C> reader, Function<JsonNode, T> factory)\n\t\t\tthrows IOException {\n\t\tJsonMapper jsonMapper = SharedJsonMapper.get();\n\t\tJsonNode node = reader.read(jsonMapper, content);\n\t\treturn factory.apply(node);\n\t}\n\n\t/**\n\t * Strategy used to read JSON content.\n\t *\n\t * @param <C> the content type\n\t */\n\t@FunctionalInterface\n\tprotected interface ContentReader<C> {\n\n\t\t/**\n\t\t * Read JSON content as a {@link JsonNode}.\n\t\t * @param jsonMapper the source JSON mapper\n\t\t * @param content the content to read\n\t\t * @return a {@link JsonNode}\n\t\t * @throws IOException on IO error\n\t\t */\n\t\tJsonNode read(JsonMapper jsonMapper, C content) throws IOException;\n\n\t}\n\n\t/**\n\t * {@link InvocationHandler} used to support\n\t * {@link MappedObject#valueAt(String, Class) valueAt} with {@code interface} types.\n\t */\n\tprivate static class MappedInvocationHandler implements InvocationHandler {\n\n\t\tprivate static final String GET = \"get\";\n\n\t\tprivate static final String IS = \"is\";\n\n\t\tprivate final MappedObject root;\n\n\t\tprivate final JsonNode node;\n\n\t\tprivate final Lookup lookup;\n\n\t\tMappedInvocationHandler(MappedObject root, JsonNode node, Lookup lookup) {\n\t\t\tthis.root = root;\n\t\t\tthis.node = node;\n\t\t\tthis.lookup = lookup;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\t\tClass<?> declaringClass = method.getDeclaringClass();\n\t\t\tif (method.isDefault()) {\n\t\t\t\tLookup lookup = this.lookup.in(declaringClass);\n\t\t\t\tMethodHandle methodHandle = lookup.unreflectSpecial(method, declaringClass).bindTo(proxy);\n\t\t\t\treturn methodHandle.invokeWithArguments();\n\t\t\t}\n\t\t\tif (declaringClass == Object.class) {\n\t\t\t\tmethod.invoke(proxy, args);\n\t\t\t}\n\t\t\tAssert.state(args == null || args.length == 0, () -> \"Unsupported method \" + method);\n\t\t\tString name = getName(method.getName());\n\t\t\tClass<?> type = method.getReturnType();\n\t\t\treturn valueForProperty(name, type);\n\t\t}\n\n\t\tprivate String getName(String name) {\n\t\t\tStringBuilder result = new StringBuilder(name);\n\t\t\tif (name.startsWith(GET)) {\n\t\t\t\tresult = new StringBuilder(name.substring(GET.length()));\n\t\t\t}\n\t\t\tif (name.startsWith(IS)) {\n\t\t\t\tresult = new StringBuilder(name.substring(IS.length()));\n\t\t\t}\n\t\t\tAssert.state(result.length() >= 0, \"Missing name\");\n\t\t\tresult.setCharAt(0, Character.toLowerCase(result.charAt(0)));\n\t\t\treturn result.toString();\n\t\t}\n\n\t\tprivate @Nullable Object valueForProperty(String name, Class<?> type) {\n\t\t\treturn valueAt(this.root, this.node, this.lookup, \"/\" + name, type);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/json/SharedJsonMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport tools.jackson.core.json.JsonWriteFeature;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.PropertyNamingStrategies;\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * Provides access to a shared pre-configured {@link JsonMapper}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class SharedJsonMapper {\n\n\tprivate static final JsonMapper INSTANCE;\n\n\tstatic {\n\t\tINSTANCE = JsonMapper.builder()\n\t\t\t.enable(SerializationFeature.INDENT_OUTPUT)\n\t\t\t.disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)\n\t\t\t.disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES)\n\t\t\t.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE)\n\t\t\t.build();\n\t}\n\n\tprivate SharedJsonMapper() {\n\t}\n\n\tpublic static JsonMapper get() {\n\t\treturn INSTANCE;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/json/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utilities and classes for JSON processing.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.json;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/socket/AbstractSocket.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.socket;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Abstract base class for custom socket implementation.\n *\n * @author Phillip Webb\n */\nclass AbstractSocket extends Socket {\n\n\t@Override\n\tpublic void connect(SocketAddress endpoint) throws IOException {\n\t}\n\n\t@Override\n\tpublic void connect(SocketAddress endpoint, int timeout) throws IOException {\n\t}\n\n\t@Override\n\tpublic boolean isConnected() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic boolean isBound() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void shutdownInput() throws IOException {\n\t\tthrow new UnsupportedSocketOperationException();\n\t}\n\n\t@Override\n\tpublic void shutdownOutput() throws IOException {\n\t\tthrow new UnsupportedSocketOperationException();\n\t}\n\n\t@Override\n\tpublic @Nullable InetAddress getInetAddress() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable InetAddress getLocalAddress() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable SocketAddress getLocalSocketAddress() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable SocketAddress getRemoteSocketAddress() {\n\t\treturn null;\n\t}\n\n\tprivate static class UnsupportedSocketOperationException extends UnsupportedOperationException {\n\n\t\tUnsupportedSocketOperationException() {\n\t\t\tsuper(\"Unsupported socket operation\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/socket/FileDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.socket;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.util.function.IntConsumer;\n\n/**\n * Provides access to the underlying file system representation of an open file.\n *\n * @author Phillip Webb\n * @see #acquire()\n */\nclass FileDescriptor {\n\n\tprivate final Handle openHandle;\n\n\tprivate final Handle closedHandler;\n\n\tprivate final IntConsumer closer;\n\n\tprivate Status status = Status.OPEN;\n\n\tprivate int referenceCount;\n\n\tFileDescriptor(int handle, IntConsumer closer) {\n\t\tthis.openHandle = new Handle(handle);\n\t\tthis.closedHandler = new Handle(-1);\n\t\tthis.closer = closer;\n\t}\n\n\t/**\n\t * Acquire an instance of the actual {@link Handle}. The caller must\n\t * {@link Handle#close() close} the resulting handle when done.\n\t * @return the handle\n\t */\n\tsynchronized Handle acquire() {\n\t\tthis.referenceCount++;\n\t\treturn (this.status != Status.OPEN) ? this.closedHandler : this.openHandle;\n\t}\n\n\tprivate synchronized void release() {\n\t\tthis.referenceCount--;\n\t\tif (this.referenceCount == 0 && this.status == Status.CLOSE_PENDING) {\n\t\t\tthis.closer.accept(this.openHandle.value);\n\t\t\tthis.status = Status.CLOSED;\n\t\t}\n\t}\n\n\t/**\n\t * Close the underlying file when all handles have been released.\n\t */\n\tsynchronized void close() {\n\t\tif (this.status == Status.OPEN) {\n\t\t\tif (this.referenceCount == 0) {\n\t\t\t\tthis.closer.accept(this.openHandle.value);\n\t\t\t\tthis.status = Status.CLOSED;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.status = Status.CLOSE_PENDING;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The status of the file descriptor.\n\t */\n\tprivate enum Status {\n\n\t\tOPEN, CLOSE_PENDING, CLOSED\n\n\t}\n\n\t/**\n\t * Provides access to the actual file descriptor handle.\n\t */\n\tfinal class Handle implements Closeable {\n\n\t\tprivate final int value;\n\n\t\tprivate Handle(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tboolean isClosed() {\n\t\t\treturn this.value == -1;\n\t\t}\n\n\t\tint intValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tif (!isClosed()) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/socket/NamedPipeSocket.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.socket;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousByteChannel;\nimport java.nio.channels.AsynchronousCloseException;\nimport java.nio.channels.AsynchronousFileChannel;\nimport java.nio.channels.Channels;\nimport java.nio.channels.CompletionHandler;\nimport java.nio.file.FileSystemException;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport com.sun.jna.Platform;\nimport com.sun.jna.platform.win32.Kernel32;\n\n/**\n * A {@link Socket} implementation for named pipes.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class NamedPipeSocket extends Socket {\n\n\tprivate static final int WAIT_INTERVAL = 100;\n\n\tprivate static final long TIMEOUT = TimeUnit.MILLISECONDS.toNanos(1000);\n\n\tprivate final AsynchronousFileByteChannel channel;\n\n\tNamedPipeSocket(String path) throws IOException {\n\t\tthis.channel = open(path);\n\t}\n\n\tprivate AsynchronousFileByteChannel open(String path) throws IOException {\n\t\tConsumer<String> awaiter = Platform.isWindows() ? new WindowsAwaiter() : new SleepAwaiter();\n\t\tlong startTime = System.nanoTime();\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\treturn new AsynchronousFileByteChannel(AsynchronousFileChannel.open(Paths.get(path),\n\t\t\t\t\t\tStandardOpenOption.READ, StandardOpenOption.WRITE));\n\t\t\t}\n\t\t\tcatch (FileSystemException ex) {\n\t\t\t\tif (System.nanoTime() - startTime >= TIMEOUT) {\n\t\t\t\t\tthrow ex;\n\t\t\t\t}\n\t\t\t\tawaiter.accept(path);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void connect(SocketAddress endpoint) throws IOException {\n\t\t// No-op\n\t}\n\n\t@Override\n\tpublic void connect(SocketAddress endpoint, int timeout) throws IOException {\n\t\t// No-op\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream() {\n\t\treturn Channels.newInputStream(this.channel);\n\t}\n\n\t@Override\n\tpublic OutputStream getOutputStream() {\n\t\treturn Channels.newOutputStream(this.channel);\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tif (this.channel != null) {\n\t\t\tthis.channel.close();\n\t\t}\n\t}\n\n\t/**\n\t * Return a new {@link NamedPipeSocket} for the given path.\n\t * @param path the path to the domain socket\n\t * @return a {@link NamedPipeSocket} instance\n\t * @throws IOException if the socket cannot be opened\n\t */\n\tpublic static NamedPipeSocket get(String path) throws IOException {\n\t\treturn new NamedPipeSocket(path);\n\t}\n\n\t/**\n\t * Adapt an {@code AsynchronousByteChannel} to an {@code AsynchronousFileChannel}.\n\t */\n\tprivate static class AsynchronousFileByteChannel implements AsynchronousByteChannel {\n\n\t\tprivate final AsynchronousFileChannel fileChannel;\n\n\t\tAsynchronousFileByteChannel(AsynchronousFileChannel fileChannel) {\n\t\t\tthis.fileChannel = fileChannel;\n\t\t}\n\n\t\t@Override\n\t\tpublic <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer, ? super A> handler) {\n\t\t\tthis.fileChannel.read(dst, 0, attachment, new CompletionHandler<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void completed(Integer read, A attachment) {\n\t\t\t\t\thandler.completed((read > 0) ? read : -1, attachment);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void failed(Throwable exc, A attachment) {\n\t\t\t\t\tif (exc instanceof AsynchronousCloseException) {\n\t\t\t\t\t\thandler.completed(-1, attachment);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\thandler.failed(exc, attachment);\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\n\t\t@Override\n\t\tpublic Future<Integer> read(ByteBuffer dst) {\n\t\t\tCompletableFutureHandler future = new CompletableFutureHandler();\n\t\t\tthis.fileChannel.read(dst, 0, null, future);\n\t\t\treturn future;\n\t\t}\n\n\t\t@Override\n\t\tpublic <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer, ? super A> handler) {\n\t\t\tthis.fileChannel.write(src, 0, attachment, handler);\n\t\t}\n\n\t\t@Override\n\t\tpublic Future<Integer> write(ByteBuffer src) {\n\t\t\treturn this.fileChannel.write(src, 0);\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tthis.fileChannel.close();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isOpen() {\n\t\t\treturn this.fileChannel.isOpen();\n\t\t}\n\n\t\tprivate static final class CompletableFutureHandler extends CompletableFuture<Integer>\n\t\t\t\timplements CompletionHandler<Integer, Object> {\n\n\t\t\t@Override\n\t\t\tpublic void completed(Integer read, Object attachment) {\n\t\t\t\tcomplete((read > 0) ? read : -1);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void failed(Throwable exc, Object attachment) {\n\t\t\t\tif (exc instanceof AsynchronousCloseException) {\n\t\t\t\t\tcomplete(-1);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcompleteExceptionally(exc);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Waits for the name pipe file using a simple sleep.\n\t */\n\tprivate static final class SleepAwaiter implements Consumer<String> {\n\n\t\t@Override\n\t\tpublic void accept(String path) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(WAIT_INTERVAL);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Waits for the name pipe file using Windows specific logic.\n\t */\n\tprivate static final class WindowsAwaiter implements Consumer<String> {\n\n\t\t@Override\n\t\tpublic void accept(String path) {\n\t\t\tKernel32.INSTANCE.WaitNamedPipe(path, WAIT_INTERVAL);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/socket/UnixDomainSocket.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.socket;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.net.SocketException;\nimport java.net.UnixDomainSocketAddress;\nimport java.nio.channels.Channels;\nimport java.nio.channels.SocketChannel;\n\n/**\n * A {@link Socket} implementation for Unix domain sockets.\n *\n * @author Scott Frederick\n * @since 3.4.0\n */\npublic final class UnixDomainSocket extends AbstractSocket {\n\n\t/**\n\t * Create a new {@link Socket} for the given path.\n\t * @param path the path to the domain socket\n\t * @return a {@link Socket} instance\n\t * @throws IOException if the socket cannot be opened\n\t */\n\tpublic static Socket get(String path) throws IOException {\n\t\treturn new UnixDomainSocket(path);\n\t}\n\n\tprivate final SocketAddress socketAddress;\n\n\tprivate final SocketChannel socketChannel;\n\n\tprivate UnixDomainSocket(String path) throws IOException {\n\t\tthis.socketAddress = UnixDomainSocketAddress.of(path);\n\t\tthis.socketChannel = SocketChannel.open(this.socketAddress);\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream() throws IOException {\n\t\tif (isClosed()) {\n\t\t\tthrow new SocketException(\"Socket is closed\");\n\t\t}\n\t\tif (!isConnected()) {\n\t\t\tthrow new SocketException(\"Socket is not connected\");\n\t\t}\n\t\tif (isInputShutdown()) {\n\t\t\tthrow new SocketException(\"Socket input is shutdown\");\n\t\t}\n\n\t\treturn Channels.newInputStream(this.socketChannel);\n\t}\n\n\t@Override\n\tpublic OutputStream getOutputStream() throws IOException {\n\t\tif (isClosed()) {\n\t\t\tthrow new SocketException(\"Socket is closed\");\n\t\t}\n\t\tif (!isConnected()) {\n\t\t\tthrow new SocketException(\"Socket is not connected\");\n\t\t}\n\t\tif (isOutputShutdown()) {\n\t\t\tthrow new SocketException(\"Socket output is shutdown\");\n\t\t}\n\n\t\treturn Channels.newOutputStream(this.socketChannel);\n\t}\n\n\t@Override\n\tpublic SocketAddress getLocalSocketAddress() {\n\t\treturn this.socketAddress;\n\t}\n\n\t@Override\n\tpublic SocketAddress getRemoteSocketAddress() {\n\t\treturn this.socketAddress;\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tsuper.close();\n\t\tthis.socketChannel.close();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/socket/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Low-level {@link java.net.Socket} implementations required for local Docker access.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.socket;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/system/Environment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.system;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides access to environment variable values.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface Environment {\n\n\t/**\n\t * Standard {@link Environment} implementation backed by\n\t * {@link System#getenv(String)}.\n\t */\n\tEnvironment SYSTEM = System::getenv;\n\n\t/**\n\t * Gets the value of the specified environment variable.\n\t * @param name the name of the environment variable\n\t * @return the string value of the variable, or {@code null} if the variable is not\n\t * defined in the environment\n\t */\n\t@Nullable String get(String name);\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * System abstractions.\n */\n@NullMarked\npackage org.springframework.boot.buildpack.platform.system;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ApiVersionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.stream.IntStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.ApiVersion;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ApiVersions}.\n *\n * @author Scott Frederick\n */\nclass ApiVersionsTests {\n\n\t@Test\n\tvoid findsLatestWhenOneMatchesMajor() {\n\t\tApiVersion version = ApiVersions.parse(\"1.1\", \"2.2\").findLatestSupported(\"1.0\");\n\t\tassertThat(version).isEqualTo(ApiVersion.parse(\"1.1\"));\n\t}\n\n\t@Test\n\tvoid findsLatestWhenOneMatchesWithReleaseVersions() {\n\t\tApiVersion version = ApiVersions.parse(\"1.1\", \"1.2\").findLatestSupported(\"1.1\");\n\t\tassertThat(version).isEqualTo(ApiVersion.parse(\"1.2\"));\n\t}\n\n\t@Test\n\tvoid findsLatestWhenOneMatchesWithPreReleaseVersions() {\n\t\tApiVersion version = ApiVersions.parse(\"0.2\", \"0.3\").findLatestSupported(\"0.2\");\n\t\tassertThat(version).isEqualTo(ApiVersion.parse(\"0.2\"));\n\t}\n\n\t@Test\n\tvoid findsLatestWhenMultipleMatchesWithReleaseVersions() {\n\t\tApiVersion version = ApiVersions.parse(\"1.1\", \"1.2\").findLatestSupported(\"1.1\", \"1.2\");\n\t\tassertThat(version).isEqualTo(ApiVersion.parse(\"1.2\"));\n\t}\n\n\t@Test\n\tvoid findsLatestWhenMultipleMatchesWithPreReleaseVersions() {\n\t\tApiVersion version = ApiVersions.parse(\"0.2\", \"0.3\").findLatestSupported(\"0.2\", \"0.3\");\n\t\tassertThat(version).isEqualTo(ApiVersion.parse(\"0.3\"));\n\t}\n\n\t@Test\n\tvoid findLatestWhenNoneSupportedThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> ApiVersions.parse(\"1.1\", \"1.2\").findLatestSupported(\"1.3\", \"1.4\"))\n\t\t\t.withMessage(\"Detected platform API versions '1.3,1.4' are not included in supported versions '1.1,1.2'\");\n\t}\n\n\t@Test\n\tvoid createFromRange() {\n\t\tApiVersions versions = ApiVersions.of(1, IntStream.rangeClosed(2, 7));\n\t\tassertThat(versions).hasToString(\"1.2,1.3,1.4,1.5,1.6,1.7\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tassertThat(ApiVersions.parse(\"1.1\", \"2.2\", \"3.3\")).hasToString(\"1.1,2.2,3.3\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tApiVersions v12a = ApiVersions.parse(\"1.2\", \"2.3\");\n\t\tApiVersions v12b = ApiVersions.parse(\"1.2\", \"2.3\");\n\t\tApiVersions v13 = ApiVersions.parse(\"1.3\", \"2.4\");\n\t\tassertThat(v12a).hasSameHashCodeAs(v12b);\n\t\tassertThat(v12a).isEqualTo(v12a).isEqualTo(v12b).isNotEqualTo(v13);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildLogTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BuildLog}.\n *\n * @author Phillip Webb\n */\nclass BuildLogTests {\n\n\t@Test\n\tvoid toSystemOutPrintsToSystemOut() {\n\t\tBuildLog log = BuildLog.toSystemOut();\n\t\tassertThat(log).isInstanceOf(PrintStreamBuildLog.class);\n\t\tassertThat(log).extracting(\"out\").isSameAs(System.out);\n\t}\n\n\t@Test\n\tvoid toPrintsToOutput() {\n\t\tBuildLog log = BuildLog.to(System.err);\n\t\tassertThat(log).isInstanceOf(PrintStreamBuildLog.class);\n\t\tassertThat(log).extracting(\"out\").isSameAs(System.err);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildOwnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link BuildOwner}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass BuildOwnerTests {\n\n\t@Test\n\tvoid fromEnvReturnsOwner() {\n\t\tMap<String, @Nullable String> env = new LinkedHashMap<>();\n\t\tenv.put(\"CNB_USER_ID\", \"123\");\n\t\tenv.put(\"CNB_GROUP_ID\", \"456\");\n\t\tBuildOwner owner = BuildOwner.fromEnv(env);\n\t\tassertThat(owner.getUid()).isEqualTo(123);\n\t\tassertThat(owner.getGid()).isEqualTo(456);\n\t\tassertThat(owner).hasToString(\"123/456\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromEnvWhenEnvIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildOwner.fromEnv(null))\n\t\t\t.withMessage(\"'env' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromEnvWhenUserPropertyIsMissingThrowsException() {\n\t\tMap<String, @Nullable String> env = new LinkedHashMap<>();\n\t\tenv.put(\"CNB_GROUP_ID\", \"456\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))\n\t\t\t.withMessage(\"Missing 'CNB_USER_ID' value from the builder environment '\" + env + \"'\");\n\t}\n\n\t@Test\n\tvoid fromEnvWhenGroupPropertyIsMissingThrowsException() {\n\t\tMap<String, @Nullable String> env = new LinkedHashMap<>();\n\t\tenv.put(\"CNB_USER_ID\", \"123\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))\n\t\t\t.withMessage(\"Missing 'CNB_GROUP_ID' value from the builder environment '\" + env + \"'\");\n\t}\n\n\t@Test\n\tvoid fromEnvWhenUserPropertyIsMalformedThrowsException() {\n\t\tMap<String, @Nullable String> env = new LinkedHashMap<>();\n\t\tenv.put(\"CNB_USER_ID\", \"nope\");\n\t\tenv.put(\"CNB_GROUP_ID\", \"456\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))\n\t\t\t.withMessage(\"Malformed 'CNB_USER_ID' value 'nope' in the builder environment '\" + env + \"'\");\n\t}\n\n\t@Test\n\tvoid fromEnvWhenGroupPropertyIsMalformedThrowsException() {\n\t\tMap<String, @Nullable String> env = new LinkedHashMap<>();\n\t\tenv.put(\"CNB_USER_ID\", \"123\");\n\t\tenv.put(\"CNB_GROUP_ID\", \"nope\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuildOwner.fromEnv(env))\n\t\t\t.withMessage(\"Malformed 'CNB_GROUP_ID' value 'nope' in the builder environment '\" + env + \"'\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneId;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageName;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link BuildRequest}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n * @author Rafael Ceccone\n */\nclass BuildRequestTests {\n\n\tprivate static final ZoneId UTC = ZoneId.of(\"UTC\");\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid forJarFileReturnsRequest() throws IOException {\n\t\tFile jarFile = new File(this.tempDir, \"my-app-0.0.1.jar\");\n\t\twriteTestJarFile(jarFile);\n\t\tBuildRequest request = BuildRequest.forJarFile(jarFile);\n\t\tassertThat(request.getName()).hasToString(\"docker.io/library/my-app:0.0.1\");\n\t\tassertThat(request.getBuilder()).hasToString(\"docker.io/\" + BuildRequest.DEFAULT_BUILDER_IMAGE_REF);\n\t\tassertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent);\n\t\tassertThat(request.getEnv()).isEmpty();\n\t}\n\n\t@Test\n\tvoid forJarFileWithNameReturnsRequest() throws IOException {\n\t\tFile jarFile = new File(this.tempDir, \"my-app-0.0.1.jar\");\n\t\twriteTestJarFile(jarFile);\n\t\tBuildRequest request = BuildRequest.forJarFile(ImageReference.of(\"test-app\"), jarFile);\n\t\tassertThat(request.getName()).hasToString(\"docker.io/library/test-app:latest\");\n\t\tassertThat(request.getBuilder()).hasToString(\"docker.io/\" + BuildRequest.DEFAULT_BUILDER_IMAGE_REF);\n\t\tassertThat(request.getApplicationContent(Owner.ROOT)).satisfies(this::hasExpectedJarContent);\n\t\tassertThat(request.getEnv()).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid forJarFileWhenJarFileIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildRequest.forJarFile(null))\n\t\t\t.withMessage(\"'jarFile' must not be null\");\n\t}\n\n\t@Test\n\tvoid forJarFileWhenJarFileIsMissingThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> BuildRequest.forJarFile(new File(this.tempDir, \"missing.jar\")))\n\t\t\t.withMessage(\"'jarFile' must exist\");\n\t}\n\n\t@Test\n\tvoid forJarFileWhenJarFileIsDirectoryThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildRequest.forJarFile(this.tempDir))\n\t\t\t.withMessage(\"'jarFile' must be a file\");\n\t}\n\n\t@Test\n\tvoid withBuilderUpdatesBuilder() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withBuilder(ImageReference.of(\"spring/builder\"));\n\t\tassertThat(request.getBuilder()).hasToString(\"docker.io/spring/builder:latest\");\n\t\tassertThat(request.isTrustBuilder()).isFalse();\n\t}\n\n\t@Test\n\tvoid withBuilderWhenHasDigestUpdatesBuilder() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withBuilder(ImageReference\n\t\t\t\t.of(\"spring/builder@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\"));\n\t\tassertThat(request.getBuilder()).hasToString(\n\t\t\t\t\"docker.io/spring/builder@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(request.isTrustBuilder()).isFalse();\n\t}\n\n\t@Test\n\tvoid withoutBuilderTrustsDefaultBuilder() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\t@Test\n\tvoid withoutBuilderTrustsDefaultBuilderWithDifferentTag() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withBuilder(ImageReference.of(ImageName.of(BuildRequest.DEFAULT_BUILDER_IMAGE_NAME), \"other\"));\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\t@Test\n\tvoid withoutBuilderTrustsDefaultBuilderWithDigest() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withBuilder(ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF)\n\t\t\t\t.withDigest(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\"));\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"trustedBuilders\")\n\tvoid withKnownTrustedBuilderTrustsBuilder(ImageReference builder) throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\")).withBuilder(builder);\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\tstatic Stream<ImageReference> trustedBuilders() {\n\t\treturn BuildRequest.KNOWN_TRUSTED_BUILDERS.stream();\n\t}\n\n\t@Test\n\tvoid withoutTrustBuilderAndDefaultBuilderUpdatesTrustsBuilder() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\")).withTrustBuilder(false);\n\t\tassertThat(request.isTrustBuilder()).isFalse();\n\t}\n\n\t@Test\n\tvoid withTrustBuilderAndBuilderUpdatesTrustBuilder() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withBuilder(ImageReference.of(\"spring/builder\"))\n\t\t\t.withTrustBuilder(true);\n\t\tassertThat(request.isTrustBuilder()).isTrue();\n\t}\n\n\t@Test\n\tvoid withRunImageUpdatesRunImage() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withRunImage(ImageReference.of(\"example.com/custom/run-image:latest\"));\n\t\tassertThat(request.getRunImage()).hasToString(\"example.com/custom/run-image:latest\");\n\t}\n\n\t@Test\n\tvoid withRunImageWhenHasDigestUpdatesRunImage() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"))\n\t\t\t.withRunImage(ImageReference\n\t\t\t\t.of(\"example.com/custom/run-image@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\"));\n\t\tassertThat(request.getRunImage()).hasToString(\n\t\t\t\t\"example.com/custom/run-image@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid withCreatorUpdatesCreator() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCreator = request.withCreator(Creator.withVersion(\"1.0.0\"));\n\t\tassertThat(request.getCreator().getName()).isEqualTo(\"Spring Boot\");\n\t\tassertThat(request.getCreator().getVersion()).isEmpty();\n\t\tassertThat(withCreator.getCreator().getName()).isEqualTo(\"Spring Boot\");\n\t\tassertThat(withCreator.getCreator().getVersion()).isEqualTo(\"1.0.0\");\n\t}\n\n\t@Test\n\tvoid withEnvAddsEnvEntry() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withEnv = request.withEnv(\"spring\", \"boot\");\n\t\tassertThat(request.getEnv()).isEmpty();\n\t\tassertThat(withEnv.getEnv()).containsExactly(entry(\"spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid withEnvMapAddsEnvEntries() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tMap<String, String> env = new LinkedHashMap<>();\n\t\tenv.put(\"spring\", \"boot\");\n\t\tenv.put(\"test\", \"test\");\n\t\tBuildRequest withEnv = request.withEnv(env);\n\t\tassertThat(request.getEnv()).isEmpty();\n\t\tassertThat(withEnv.getEnv()).containsExactly(entry(\"spring\", \"boot\"), entry(\"test\", \"test\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withEnvWhenKeyIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withEnv(null, \"test\"))\n\t\t\t.withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withEnvWhenValueIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withEnv(\"test\", null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid withBuildpacksAddsBuildpacks() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildpackReference buildpackReference1 = BuildpackReference.of(\"example/buildpack1\");\n\t\tBuildpackReference buildpackReference2 = BuildpackReference.of(\"example/buildpack2\");\n\t\tBuildRequest withBuildpacks = request.withBuildpacks(buildpackReference1, buildpackReference2);\n\t\tassertThat(request.getBuildpacks()).isEmpty();\n\t\tassertThat(withBuildpacks.getBuildpacks()).containsExactly(buildpackReference1, buildpackReference2);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withBuildpacksWhenBuildpacksIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withBuildpacks((List<BuildpackReference>) null))\n\t\t\t.withMessage(\"'buildpacks' must not be null\");\n\t}\n\n\t@Test\n\tvoid withBindingsAddsBindings() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withBindings = request.withBindings(Binding.of(\"/host/path:/container/path:ro\"),\n\t\t\t\tBinding.of(\"volume-name:/container/path:rw\"));\n\t\tassertThat(request.getBindings()).isEmpty();\n\t\tassertThat(withBindings.getBindings()).containsExactly(Binding.of(\"/host/path:/container/path:ro\"),\n\t\t\t\tBinding.of(\"volume-name:/container/path:rw\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withBindingsWhenBindingsIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withBindings((List<Binding>) null))\n\t\t\t.withMessage(\"'bindings' must not be null\");\n\t}\n\n\t@Test\n\tvoid withNetworkUpdatesNetwork() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\")).withNetwork(\"test\");\n\t\tassertThat(request.getNetwork()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid withTagsAddsTags() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withTags = request.withTags(ImageReference.of(\"docker.io/library/my-app:latest\"),\n\t\t\t\tImageReference.of(\"example.com/custom/my-app:0.0.1\"),\n\t\t\t\tImageReference.of(\"example.com/custom/my-app:latest\"));\n\t\tassertThat(request.getTags()).isEmpty();\n\t\tassertThat(withTags.getTags()).containsExactly(ImageReference.of(\"docker.io/library/my-app:latest\"),\n\t\t\t\tImageReference.of(\"example.com/custom/my-app:0.0.1\"),\n\t\t\t\tImageReference.of(\"example.com/custom/my-app:latest\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withTagsWhenTagsIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withTags((List<ImageReference>) null))\n\t\t\t.withMessage(\"'tags' must not be null\");\n\t}\n\n\t@Test\n\tvoid withBuildWorkspaceVolumeAddsWorkspace() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withWorkspace = request.withBuildWorkspace(Cache.volume(\"build-workspace\"));\n\t\tassertThat(request.getBuildWorkspace()).isNull();\n\t\tassertThat(withWorkspace.getBuildWorkspace()).isEqualTo(Cache.volume(\"build-workspace\"));\n\t}\n\n\t@Test\n\tvoid withBuildWorkspaceBindAddsWorkspace() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withWorkspace = request.withBuildWorkspace(Cache.bind(\"/tmp/build-workspace\"));\n\t\tassertThat(request.getBuildWorkspace()).isNull();\n\t\tassertThat(withWorkspace.getBuildWorkspace()).isEqualTo(Cache.bind(\"/tmp/build-workspace\"));\n\t}\n\n\t@Test\n\tvoid withBuildVolumeCacheAddsCache() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCache = request.withBuildCache(Cache.volume(\"build-volume\"));\n\t\tassertThat(request.getBuildCache()).isNull();\n\t\tassertThat(withCache.getBuildCache()).isEqualTo(Cache.volume(\"build-volume\"));\n\t}\n\n\t@Test\n\tvoid withBuildBindCacheAddsCache() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCache = request.withBuildCache(Cache.bind(\"/tmp/build-cache\"));\n\t\tassertThat(request.getBuildCache()).isNull();\n\t\tassertThat(withCache.getBuildCache()).isEqualTo(Cache.bind(\"/tmp/build-cache\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withBuildVolumeCacheWhenCacheIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withBuildCache(null))\n\t\t\t.withMessage(\"'buildCache' must not be null\");\n\t}\n\n\t@Test\n\tvoid withLaunchVolumeCacheAddsCache() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCache = request.withLaunchCache(Cache.volume(\"launch-volume\"));\n\t\tassertThat(request.getLaunchCache()).isNull();\n\t\tassertThat(withCache.getLaunchCache()).isEqualTo(Cache.volume(\"launch-volume\"));\n\t}\n\n\t@Test\n\tvoid withLaunchBindCacheAddsCache() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCache = request.withLaunchCache(Cache.bind(\"/tmp/launch-cache\"));\n\t\tassertThat(request.getLaunchCache()).isNull();\n\t\tassertThat(withCache.getLaunchCache()).isEqualTo(Cache.bind(\"/tmp/launch-cache\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withLaunchVolumeCacheWhenCacheIsNullThrowsException() throws IOException {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withLaunchCache(null))\n\t\t\t.withMessage(\"'launchCache' must not be null\");\n\t}\n\n\t@Test\n\tvoid withCreatedDateSetsCreatedDate() throws Exception {\n\t\tInstant createDate = Instant.now();\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCreatedDate = request.withCreatedDate(createDate.toString());\n\t\tassertThat(withCreatedDate.getCreatedDate()).isEqualTo(createDate);\n\t}\n\n\t@Test\n\tvoid withCreatedDateNowSetsCreatedDate() throws Exception {\n\t\tOffsetDateTime now = OffsetDateTime.now(UTC);\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withCreatedDate = request.withCreatedDate(\"now\");\n\t\tOffsetDateTime createdDate = OffsetDateTime.ofInstant(withCreatedDate.getCreatedDate(), UTC);\n\t\tassertThat(createdDate.getYear()).isEqualTo(now.getYear());\n\t\tassertThat(createdDate.getMonth()).isEqualTo(now.getMonth());\n\t\tassertThat(createdDate.getDayOfMonth()).isEqualTo(now.getDayOfMonth());\n\t\twithCreatedDate = request.withCreatedDate(\"NOW\");\n\t\tcreatedDate = OffsetDateTime.ofInstant(withCreatedDate.getCreatedDate(), UTC);\n\t\tassertThat(createdDate.getYear()).isEqualTo(now.getYear());\n\t\tassertThat(createdDate.getMonth()).isEqualTo(now.getMonth());\n\t\tassertThat(createdDate.getDayOfMonth()).isEqualTo(now.getDayOfMonth());\n\t}\n\n\t@Test\n\tvoid withCreatedDateAndInvalidDateThrowsException() throws Exception {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> request.withCreatedDate(\"not a date\"))\n\t\t\t.withMessageContaining(\"'not a date'\");\n\t}\n\n\t@Test\n\tvoid withApplicationDirectorySetsApplicationDirectory() throws Exception {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withAppDir = request.withApplicationDirectory(\"/application\");\n\t\tassertThat(withAppDir.getApplicationDirectory()).isEqualTo(\"/application\");\n\t}\n\n\t@Test\n\tvoid withSecurityOptionsSetsSecurityOptions() throws Exception {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withAppDir = request.withSecurityOptions(List.of(\"label=user:USER\", \"label=role:ROLE\"));\n\t\tassertThat(withAppDir.getSecurityOptions()).containsExactly(\"label=user:USER\", \"label=role:ROLE\");\n\t}\n\n\t@Test\n\tvoid withPlatformSetsPlatform() throws Exception {\n\t\tBuildRequest request = BuildRequest.forJarFile(writeTestJarFile(\"my-app-0.0.1.jar\"));\n\t\tBuildRequest withAppDir = request.withImagePlatform(\"linux/arm64\");\n\t\tassertThat(withAppDir.getImagePlatform()).isEqualTo(ImagePlatform.of(\"linux/arm64\"));\n\t}\n\n\tprivate void hasExpectedJarContent(TarArchive archive) {\n\t\ttry {\n\t\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\t\tarchive.writeTo(outputStream);\n\t\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(\n\t\t\t\t\tnew ByteArrayInputStream(outputStream.toByteArray()))) {\n\t\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"spring/\");\n\t\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"spring/boot\");\n\t\t\t\tassertThat(tar.getNextEntry()).isNull();\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate File writeTestJarFile(String name) throws IOException {\n\t\tFile file = new File(this.tempDir, name);\n\t\twriteTestJarFile(file);\n\t\treturn file;\n\t}\n\n\tprivate void writeTestJarFile(File file) throws IOException {\n\t\ttry (ZipArchiveOutputStream zip = new ZipArchiveOutputStream(file)) {\n\t\t\tZipArchiveEntry dirEntry = new ZipArchiveEntry(\"spring/\");\n\t\t\tzip.putArchiveEntry(dirEntry);\n\t\t\tzip.closeArchiveEntry();\n\t\t\tZipArchiveEntry fileEntry = new ZipArchiveEntry(\"spring/boot\");\n\t\t\tzip.putArchiveEntry(fileEntry);\n\t\t\tzip.write(\"test\".getBytes(StandardCharsets.UTF_8));\n\t\t\tzip.closeArchiveEntry();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderBuildpackTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BuilderBuildpack}.\n *\n * @author Scott Frederick\n */\nclass BuilderBuildpackTests extends AbstractJsonTests {\n\n\tprivate BuildpackResolverContext resolverContext;\n\n\t@BeforeEach\n\tvoid setUp() throws Exception {\n\t\tBuilderMetadata metadata = BuilderMetadata.fromJson(getContentAsString(\"builder-metadata.json\"));\n\t\tthis.resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(this.resolverContext.getBuildpackMetadata()).willReturn(metadata.getBuildpacks());\n\t}\n\n\t@Test\n\tvoid resolveWhenFullyQualifiedBuildpackWithVersionResolves() throws Exception {\n\t\tBuildpackReference reference = BuildpackReference.of(\"urn:cnb:builder:paketo-buildpacks/spring-boot@3.5.0\");\n\t\tBuildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates())\n\t\t\t.isEqualTo(BuildpackCoordinates.of(\"paketo-buildpacks/spring-boot\", \"3.5.0\"));\n\t\tassertThatNoLayersAreAdded(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenFullyQualifiedBuildpackWithoutVersionResolves() throws Exception {\n\t\tBuildpackReference reference = BuildpackReference.of(\"urn:cnb:builder:paketo-buildpacks/spring-boot\");\n\t\tBuildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates())\n\t\t\t.isEqualTo(BuildpackCoordinates.of(\"paketo-buildpacks/spring-boot\", \"3.5.0\"));\n\t\tassertThatNoLayersAreAdded(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenUnqualifiedBuildpackWithVersionResolves() throws Exception {\n\t\tBuildpackReference reference = BuildpackReference.of(\"paketo-buildpacks/spring-boot@3.5.0\");\n\t\tBuildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates())\n\t\t\t.isEqualTo(BuildpackCoordinates.of(\"paketo-buildpacks/spring-boot\", \"3.5.0\"));\n\t\tassertThatNoLayersAreAdded(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenUnqualifiedBuildpackWithoutVersionResolves() throws Exception {\n\t\tBuildpackReference reference = BuildpackReference.of(\"paketo-buildpacks/spring-boot\");\n\t\tBuildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates())\n\t\t\t.isEqualTo(BuildpackCoordinates.of(\"paketo-buildpacks/spring-boot\", \"3.5.0\"));\n\t\tassertThatNoLayersAreAdded(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenFullyQualifiedBuildpackWithVersionNotInBuilderThrowsException() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"urn:cnb:builder:example/buildpack1@1.2.3\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuilderBuildpack.resolve(this.resolverContext, reference))\n\t\t\t.withMessageContaining(\"'urn:cnb:builder:example/buildpack1@1.2.3'\")\n\t\t\t.withMessageContaining(\"not found in builder\");\n\t}\n\n\t@Test\n\tvoid resolveWhenFullyQualifiedBuildpackWithoutVersionNotInBuilderThrowsException() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"urn:cnb:builder:example/buildpack1\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuilderBuildpack.resolve(this.resolverContext, reference))\n\t\t\t.withMessageContaining(\"'urn:cnb:builder:example/buildpack1'\")\n\t\t\t.withMessageContaining(\"not found in builder\");\n\t}\n\n\t@Test\n\tvoid resolveWhenUnqualifiedBuildpackNotInBuilderReturnsNull() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"example/buildpack1@1.2.3\");\n\t\tBuildpack buildpack = BuilderBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n\tprivate void assertThatNoLayersAreAdded(Buildpack buildpack) throws IOException {\n\t\tList<Layer> layers = new ArrayList<>();\n\t\tbuildpack.apply(layers::add);\n\t\tassertThat(layers).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BuilderException}.\n *\n * @author Scott Frederick\n */\nclass BuilderExceptionTests {\n\n\t@Test\n\tvoid create() {\n\t\tBuilderException exception = new BuilderException(\"detector\", 1);\n\t\tassertThat(exception.getOperation()).isEqualTo(\"detector\");\n\t\tassertThat(exception.getStatusCode()).isOne();\n\t\tassertThat(exception.getMessage()).isEqualTo(\"Builder lifecycle 'detector' failed with status code 1\");\n\t}\n\n\t@Test\n\tvoid createWhenOperationIsNull() {\n\t\tBuilderException exception = new BuilderException(null, 1);\n\t\tassertThat(exception.getOperation()).isNull();\n\t\tassertThat(exception.getStatusCode()).isOne();\n\t\tassertThat(exception.getMessage()).isEqualTo(\"Builder failed with status code 1\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.build.BuilderMetadata.RunImage;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.tuple;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BuilderMetadata}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Andy Wilkinson\n */\nclass BuilderMetadataTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid fromImageLoadsMetadata() throws IOException {\n\t\tImage image = Image.of(getContent(\"image.json\"));\n\t\tBuilderMetadata metadata = BuilderMetadata.fromImage(image);\n\t\tassertThat(metadata.getStack().getRunImage().getImage()).isEqualTo(\"cloudfoundry/run:base-cnb\");\n\t\tassertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty();\n\t\tassertThat(metadata.getRunImages()).isEmpty();\n\t\tassertThat(metadata.getLifecycle().getVersion()).isEqualTo(\"0.7.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo(\"0.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo(\"0.3\");\n\t\tassertThat(metadata.getCreatedBy().getName()).isEqualTo(\"Pack CLI\");\n\t\tassertThat(metadata.getCreatedBy().getVersion())\n\t\t\t.isEqualTo(\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\");\n\t\tassertThat(metadata.getBuildpacks()).extracting(BuildpackMetadata::getId, BuildpackMetadata::getVersion)\n\t\t\t.contains(tuple(\"paketo-buildpacks/java\", \"4.10.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/spring-boot\", \"3.5.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/executable-jar\", \"3.1.3\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/graalvm\", \"4.1.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/java-native-image\", \"4.7.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/spring-boot-native-image\", \"2.0.1\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/bellsoft-liberica\", \"6.2.0\"));\n\t}\n\n\t@Test\n\tvoid fromImageWithoutStackLoadsMetadata() throws IOException {\n\t\tImage image = Image.of(getContent(\"image-with-empty-stack.json\"));\n\t\tBuilderMetadata metadata = BuilderMetadata.fromImage(image);\n\t\tassertThat(metadata.getRunImages()).extracting(RunImage::getImage, RunImage::getMirrors)\n\t\t\t.contains(tuple(\"cloudfoundry/run:base-cnb\", Collections.emptyList()));\n\t\tassertThat(metadata.getLifecycle().getVersion()).isEqualTo(\"0.7.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo(\"0.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo(\"0.3\");\n\t\tassertThat(metadata.getCreatedBy().getName()).isEqualTo(\"Pack CLI\");\n\t\tassertThat(metadata.getCreatedBy().getVersion())\n\t\t\t.isEqualTo(\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\");\n\t\tassertThat(metadata.getBuildpacks()).extracting(BuildpackMetadata::getId, BuildpackMetadata::getVersion)\n\t\t\t.contains(tuple(\"paketo-buildpacks/java\", \"4.10.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/spring-boot\", \"3.5.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/executable-jar\", \"3.1.3\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/graalvm\", \"4.1.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/java-native-image\", \"4.7.0\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/spring-boot-native-image\", \"2.0.1\"))\n\t\t\t.contains(tuple(\"paketo-buildpacks/bellsoft-liberica\", \"6.2.0\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromImageWhenImageIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuilderMetadata.fromImage(null))\n\t\t\t.withMessage(\"'image' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageWhenImageConfigIsNullThrowsException() {\n\t\tImage image = mock(Image.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuilderMetadata.fromImage(image))\n\t\t\t.withMessage(\"'imageConfig' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageConfigWhenLabelIsMissingThrowsException() {\n\t\tImage image = mock(Image.class);\n\t\tImageConfig imageConfig = mock(ImageConfig.class);\n\t\tgiven(image.getConfig()).willReturn(imageConfig);\n\t\tgiven(imageConfig.getLabels()).willReturn(Collections.singletonMap(\"alpha\", \"a\"));\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuilderMetadata.fromImage(image))\n\t\t\t.withMessage(\"No 'io.buildpacks.builder.metadata' label found in image config labels 'alpha'\");\n\t}\n\n\t@Test\n\tvoid fromJsonLoadsMetadataWithoutSupportedApis() throws IOException {\n\t\tBuilderMetadata metadata = BuilderMetadata.fromJson(getContentAsString(\"builder-metadata.json\"));\n\t\tassertThat(metadata.getStack().getRunImage().getImage()).isEqualTo(\"cloudfoundry/run:base-cnb\");\n\t\tassertThat(metadata.getStack().getRunImage().getMirrors()).isEmpty();\n\t\tassertThat(metadata.getLifecycle().getVersion()).isEqualTo(\"0.7.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo(\"0.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo(\"0.8\");\n\t\tassertThat(metadata.getLifecycle().getApis().getBuildpack()).isNull();\n\t\tassertThat(metadata.getLifecycle().getApis().getPlatform()).isNull();\n\t}\n\n\t@Test\n\tvoid fromJsonLoadsMetadataWithSupportedApis() throws IOException {\n\t\tBuilderMetadata metadata = BuilderMetadata.fromJson(getContentAsString(\"builder-metadata-supported-apis.json\"));\n\t\tassertThat(metadata.getLifecycle().getVersion()).isEqualTo(\"0.7.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getBuildpack()).isEqualTo(\"0.2\");\n\t\tassertThat(metadata.getLifecycle().getApi().getPlatform()).isEqualTo(\"0.8\");\n\t\tassertThat(metadata.getLifecycle().getApis().getBuildpack()).containsExactly(\"0.1\", \"0.2\", \"0.3\");\n\t\tassertThat(metadata.getLifecycle().getApis().getPlatform()).containsExactly(\"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\",\n\t\t\t\t\"0.8\");\n\t}\n\n\t@Test\n\tvoid copyWithUpdatedCreatedByReturnsNewMetadata() throws IOException {\n\t\tImage image = Image.of(getContent(\"image.json\"));\n\t\tBuilderMetadata metadata = BuilderMetadata.fromImage(image);\n\t\tBuilderMetadata copy = metadata.copy((update) -> update.withCreatedBy(\"test123\", \"test456\"));\n\t\tassertThat(copy).isNotSameAs(metadata);\n\t\tassertThat(copy.getCreatedBy().getName()).isEqualTo(\"test123\");\n\t\tassertThat(copy.getCreatedBy().getVersion()).isEqualTo(\"test456\");\n\t}\n\n\t@Test\n\tvoid attachToUpdatesMetadata() throws IOException {\n\t\tImage image = Image.of(getContent(\"image.json\"));\n\t\tImageConfig imageConfig = image.getConfig();\n\t\tBuilderMetadata metadata = BuilderMetadata.fromImage(image);\n\t\tImageConfig imageConfigCopy = imageConfig.copy(metadata::attachTo);\n\t\tString label = imageConfigCopy.getLabels().get(\"io.buildpacks.builder.metadata\");\n\t\tassertThat(label).isNotNull();\n\t\tBuilderMetadata metadataCopy = BuilderMetadata.fromJson(label);\n\t\tassertThat(metadataCopy.getStack().getRunImage().getImage())\n\t\t\t.isEqualTo(metadata.getStack().getRunImage().getImage());\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.net.URI;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.stubbing.Answer;\n\nimport org.springframework.boot.buildpack.platform.build.Builder.BuildLogAdapter;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerLog;\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressPullListener;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerRegistryAuthentication;\nimport org.springframework.boot.buildpack.platform.docker.transport.TestDockerEngineException;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerReference;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link Builder}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Rafael Ceccone\n */\nclass BuilderTests {\n\n\tprivate static final ImageReference PAKETO_BUILDPACKS_BUILDER = ImageReference\n\t\t.of(\"docker.io/paketobuildpacks/builder\");\n\n\tprivate static final ImageReference LATEST_PAKETO_BUILDPACKS_BUILDER = PAKETO_BUILDPACKS_BUILDER.inTaggedForm();\n\n\tprivate static final ImageReference DEFAULT_BUILDER = ImageReference.of(BuildRequest.DEFAULT_BUILDER_IMAGE_REF);\n\n\tprivate static final ImageReference BASE_CNB = ImageReference.of(\"docker.io/cloudfoundry/run:base-cnb\");\n\n\tprivate static final ImageReference PLATFORM_CNB = ImageReference\n\t\t.of(\"docker.io/cloudfoundry/run@sha256:fb5ecb90a42b2067a859aab23fc1f5e9d9c2589d07ba285608879e7baa415aad\");\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenLogIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Builder((BuildLog) null))\n\t\t\t.withMessage(\"'log' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithDockerConfiguration() {\n\t\tassertThatNoException().isThrownBy(() -> new Builder(BuildLog.toSystemOut()));\n\t}\n\n\t@Test\n\tvoid createDockerApiWithLogDockerLogDelegate() {\n\t\tBuilder builder = new Builder(BuildLog.toSystemOut());\n\t\tassertThat(builder).extracting(\"docker\")\n\t\t\t.extracting(\"system\")\n\t\t\t.extracting(\"log\")\n\t\t\t.isInstanceOf(BuildLogAdapter.class);\n\t}\n\n\t@Test\n\tvoid createDockerApiWithLogDockerSystemOutDelegate() {\n\t\tBuilder builder = new Builder(mock(BuildLog.class));\n\t\tassertThat(builder).extracting(\"docker\")\n\t\t\t.extracting(\"system\")\n\t\t\t.extracting(\"log\")\n\t\t\t.isInstanceOf(DockerLog.toSystemOut().getClass());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid buildWhenRequestIsNullThrowsException() {\n\t\tBuilder builder = new Builder();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> builder.build(null))\n\t\t\t.withMessage(\"'request' must not be null\");\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilder() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest();\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull());\n\t\tthen(docker.image()).should().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull());\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderAndPublishesImage() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tDockerRegistryAuthentication builderToken = DockerRegistryAuthentication.token(\"builder token\");\n\t\tDockerRegistryAuthentication publishToken = DockerRegistryAuthentication.token(\"publish token\");\n\t\tBuilderDockerConfiguration dockerConfiguration = new BuilderDockerConfiguration()\n\t\t\t.withBuilderRegistryAuthentication(builderToken)\n\t\t\t.withPublishRegistryAuthentication(publishToken);\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), regAuthEq(builderToken)))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), regAuthEq(builderToken)))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, dockerConfiguration);\n\t\tBuildRequest request = getTestRequest().withPublish(true);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().pull(eq(DEFAULT_BUILDER), isNull(), any(), regAuthEq(builderToken));\n\t\tthen(docker.image()).should()\n\t\t\t.pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), regAuthEq(builderToken));\n\t\tthen(docker.image()).should().push(eq(request.getName()), any(), regAuthEq(publishToken));\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithDefaultImageTags() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image-with-no-run-image-tag.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(LATEST_PAKETO_BUILDPACKS_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image()\n\t\t\t.pull(eq(ImageReference.of(\"docker.io/cloudfoundry/run:latest\")), eq(ImagePlatform.from(builderImage)),\n\t\t\t\t\tany(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withBuilder(PAKETO_BUILDPACKS_BUILDER);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithRunImageInDigestForm() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image-with-run-image-digest.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image()\n\t\t\t.pull(eq(ImageReference\n\t\t\t\t.of(\"docker.io/cloudfoundry/run@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\")),\n\t\t\t\t\teq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest();\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithNoStack() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image-with-empty-stack.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(LATEST_PAKETO_BUILDPACKS_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withBuilder(PAKETO_BUILDPACKS_BUILDER);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithRunImageFromRequest() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image()\n\t\t\t.pull(eq(ImageReference.of(\"example.com/custom/run:latest\")), eq(ImagePlatform.from(builderImage)), any(),\n\t\t\t\t\tisNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withRunImage(ImageReference.of(\"example.com/custom/run:latest\"));\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithNeverPullPolicy() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tgiven(docker.image().inspect(eq(DEFAULT_BUILDER), any())).willReturn(builderImage);\n\t\tgiven(docker.image().inspect(eq(BASE_CNB), any())).willReturn(runImage);\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withPullPolicy(PullPolicy.NEVER);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).should(never()).pull(any(), any(), any());\n\t\tthen(docker.image()).should(times(2)).inspect(any(), any());\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithAlwaysPullPolicy() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tgiven(docker.image().inspect(eq(DEFAULT_BUILDER))).willReturn(builderImage);\n\t\tgiven(docker.image().inspect(eq(BASE_CNB))).willReturn(runImage);\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withPullPolicy(PullPolicy.ALWAYS);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).should(times(2)).pull(any(), any(), any(), isNull());\n\t\tthen(docker.image()).should(never()).inspect(any());\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithIfNotPresentPullPolicy() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tgiven(docker.image().inspect(eq(DEFAULT_BUILDER), any()))\n\t\t\t.willThrow(new TestDockerEngineException(\"docker://localhost/\", new URI(\"example\"), 404, \"NOT FOUND\", null,\n\t\t\t\t\tnull, null))\n\t\t\t.willReturn(builderImage);\n\t\tgiven(docker.image().inspect(eq(BASE_CNB), any()))\n\t\t\t.willThrow(new TestDockerEngineException(\"docker://localhost/\", new URI(\"example\"), 404, \"NOT FOUND\", null,\n\t\t\t\t\tnull, null))\n\t\t\t.willReturn(runImage);\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withPullPolicy(PullPolicy.IF_NOT_PRESENT);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).should(times(2)).inspect(any(), any());\n\t\tthen(docker.image()).should(times(2)).pull(any(), any(), any(), isNull());\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithTags() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withTags(ImageReference.of(\"my-application:1.2.3\"));\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tassertThat(out.toString()).contains(\"Successfully created image tag 'docker.io/library/my-application:1.2.3'\");\n\t\tthen(docker.image()).should().tag(eq(request.getName()), eq(ImageReference.of(\"my-application:1.2.3\")));\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithTagsAndPublishesImageAndTags() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tDockerRegistryAuthentication builderToken = DockerRegistryAuthentication.token(\"builder token\");\n\t\tDockerRegistryAuthentication publishToken = DockerRegistryAuthentication.token(\"publish token\");\n\t\tBuilderDockerConfiguration dockerConfiguration = new BuilderDockerConfiguration()\n\t\t\t.withBuilderRegistryAuthentication(builderToken)\n\t\t\t.withPublishRegistryAuthentication(publishToken);\n\t\tImageReference defaultBuilderImageReference = DEFAULT_BUILDER;\n\t\tgiven(docker.image().pull(eq(defaultBuilderImageReference), isNull(), any(), regAuthEq(builderToken)))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tImageReference baseImageReference = BASE_CNB;\n\t\tgiven(docker.image()\n\t\t\t.pull(eq(baseImageReference), eq(ImagePlatform.from(builderImage)), any(), regAuthEq(builderToken)))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, dockerConfiguration);\n\t\tImageReference builtImageReference = ImageReference.of(\"my-application:1.2.3\");\n\t\tBuildRequest request = getTestRequest().withPublish(true).withTags(builtImageReference);\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tassertThat(out.toString()).contains(\"Successfully created image tag 'docker.io/library/my-application:1.2.3'\");\n\t\tthen(docker.image()).should().pull(eq(defaultBuilderImageReference), isNull(), any(), regAuthEq(builderToken));\n\t\tthen(docker.image()).should()\n\t\t\t.pull(eq(baseImageReference), eq(ImagePlatform.from(builderImage)), any(), regAuthEq(builderToken));\n\t\tthen(docker.image()).should().push(eq(request.getName()), any(), regAuthEq(publishToken));\n\t\tthen(docker.image()).should().tag(eq(request.getName()), eq(builtImageReference));\n\t\tthen(docker.image()).should().push(eq(builtImageReference), any(), regAuthEq(publishToken));\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid buildInvokesBuilderWithPlatform() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tImagePlatform platform = ImagePlatform.of(\"linux/arm64/v1\");\n\t\tDockerApi docker = mockDockerApi(platform);\n\t\tImage builderImage = loadImage(\"image-with-platform.json\");\n\t\tImage runImage = loadImage(\"run-image-with-platform.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), eq(platform), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(platform), any(), isNull())).willAnswer(withPulledImage(runImage));\n\t\tgiven(docker.image().pull(eq(PLATFORM_CNB), eq(platform), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withImagePlatform(\"linux/arm64/v1\");\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\"Running creator\");\n\t\tassertThat(out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t\tArgumentCaptor<ImageArchive> archive = ArgumentCaptor.forClass(ImageArchive.class);\n\t\tthen(docker.image()).should().pull(eq(DEFAULT_BUILDER), eq(platform), any(), isNull());\n\t\tthen(docker.image()).should().pull(eq(BASE_CNB), eq(platform), any(), isNull());\n\t\tthen(docker.image()).should().pull(eq(PLATFORM_CNB), eq(platform), any(), isNull());\n\t\tthen(docker.image()).should().load(archive.capture(), any());\n\t\tImageReference tag = archive.getValue().getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tthen(docker.image()).should().remove(tag, true);\n\t\tthen(docker.image()).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid buildWhenStackIdDoesNotMatchThrowsException() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image-with-bad-stack.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest();\n\t\tassertThatIllegalStateException().isThrownBy(() -> builder.build(request))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Run image stack 'org.cloudfoundry.stacks.cfwindowsfs3' does not match builder stack 'io.buildpacks.stacks.bionic'\");\n\t}\n\n\t@Test\n\tvoid buildWhenBuilderReturnsErrorThrowsException() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApiLifecycleError();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest();\n\t\tassertThatExceptionOfType(BuilderException.class).isThrownBy(() -> builder.build(request))\n\t\t\t.withMessage(\"Builder lifecycle 'creator' failed with status code 9\");\n\t}\n\n\t@Test\n\tvoid buildWhenRequestedBuildpackNotInBuilderThrowsException() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApiLifecycleError();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), any(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), any(), any(), isNull())).willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildpackReference reference = BuildpackReference.of(\"urn:cnb:builder:example/buildpack@1.2.3\");\n\t\tBuildRequest request = getTestRequest().withBuildpacks(reference);\n\t\tassertThatIllegalStateException().isThrownBy(() -> builder.build(request))\n\t\t\t.withMessageContaining(\"'urn:cnb:builder:example/buildpack@1.2.3'\")\n\t\t\t.withMessageContaining(\"not found in builder\");\n\t}\n\n\t@Test\n\tvoid logsWarningIfBindingWithSensitiveTargetIsDetected() throws IOException {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tDockerApi docker = mockDockerApi();\n\t\tImage builderImage = loadImage(\"image.json\");\n\t\tImage runImage = loadImage(\"run-image.json\");\n\t\tgiven(docker.image().pull(eq(DEFAULT_BUILDER), isNull(), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(builderImage));\n\t\tgiven(docker.image().pull(eq(BASE_CNB), eq(ImagePlatform.from(builderImage)), any(), isNull()))\n\t\t\t.willAnswer(withPulledImage(runImage));\n\t\tBuilder builder = new Builder(BuildLog.to(out), docker, null);\n\t\tBuildRequest request = getTestRequest().withBindings(Binding.from(\"/host\", \"/cnb\"));\n\t\tbuilder.build(request);\n\t\tassertThat(out.toString()).contains(\n\t\t\t\t\"Warning: Binding '/host:/cnb' uses a container path which is used by buildpacks while building. Binding to it can cause problems!\");\n\t}\n\n\tprivate DockerApi mockDockerApi() throws IOException {\n\t\treturn mockDockerApi(null);\n\t}\n\n\tprivate DockerApi mockDockerApi(@Nullable ImagePlatform platform) throws IOException {\n\t\tContainerApi containerApi = mock(ContainerApi.class);\n\t\tContainerReference reference = ContainerReference.of(\"container-ref\");\n\t\tgiven(containerApi.create(any(), eq(platform), any())).willReturn(reference);\n\t\tgiven(containerApi.wait(eq(reference))).willReturn(ContainerStatus.of(0, null));\n\t\tImageApi imageApi = mock(ImageApi.class);\n\t\tVolumeApi volumeApi = mock(VolumeApi.class);\n\t\tDockerApi docker = mock(DockerApi.class);\n\t\tgiven(docker.image()).willReturn(imageApi);\n\t\tgiven(docker.container()).willReturn(containerApi);\n\t\tgiven(docker.volume()).willReturn(volumeApi);\n\t\treturn docker;\n\t}\n\n\tprivate DockerApi mockDockerApiLifecycleError() throws IOException {\n\t\tContainerApi containerApi = mock(ContainerApi.class);\n\t\tContainerReference reference = ContainerReference.of(\"container-ref\");\n\t\tgiven(containerApi.create(any(), isNull(), any())).willReturn(reference);\n\t\tgiven(containerApi.wait(eq(reference))).willReturn(ContainerStatus.of(9, null));\n\t\tImageApi imageApi = mock(ImageApi.class);\n\t\tVolumeApi volumeApi = mock(VolumeApi.class);\n\t\tDockerApi docker = mock(DockerApi.class);\n\t\tgiven(docker.image()).willReturn(imageApi);\n\t\tgiven(docker.container()).willReturn(containerApi);\n\t\tgiven(docker.volume()).willReturn(volumeApi);\n\t\treturn docker;\n\t}\n\n\tprivate BuildRequest getTestRequest() {\n\t\tTarArchive content = mock(TarArchive.class);\n\t\tImageReference name = ImageReference.of(\"my-application\");\n\t\treturn BuildRequest.of(name, (owner) -> content).withTrustBuilder(true);\n\t}\n\n\tprivate Image loadImage(String name) throws IOException {\n\t\treturn Image.of(getClass().getResourceAsStream(name));\n\t}\n\n\tprivate Answer<Image> withPulledImage(Image image) {\n\t\treturn (invocation) -> {\n\t\t\tTotalProgressPullListener listener = invocation.getArgument(2, TotalProgressPullListener.class);\n\t\t\tlistener.onStart();\n\t\t\tlistener.onFinish();\n\t\t\treturn image;\n\t\t};\n\t}\n\n\tprivate static String regAuthEq(DockerRegistryAuthentication authentication) {\n\t\treturn argThat((arg) -> Objects.equals(authentication.getAuthHeader(), arg));\n\t}\n\n\tstatic class TestPrintStream extends PrintStream {\n\n\t\tTestPrintStream() {\n\t\t\tsuper(new ByteArrayOutputStream());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.out.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildpackCoordinatesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link BuildpackCoordinates}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nclass BuildpackCoordinatesTests extends AbstractJsonTests {\n\n\tprivate final Path archive = Paths.get(\"/buildpack/path\");\n\n\t@Test\n\tvoid fromToml() throws IOException {\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates\n\t\t\t.fromToml(createTomlStream(\"example/buildpack1\", \"0.0.1\", true, false), this.archive);\n\t\tassertThat(coordinates.getId()).isEqualTo(\"example/buildpack1\");\n\t\tassertThat(coordinates.getVersion()).isEqualTo(\"0.0.1\");\n\t}\n\n\t@Test\n\tvoid fromTomlWhenMissingDescriptorThrowsException() {\n\t\tByteArrayInputStream coordinates = new ByteArrayInputStream(\"\".getBytes());\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackCoordinates.fromToml(coordinates, this.archive))\n\t\t\t.withMessageContaining(\"Buildpack descriptor 'buildpack.toml' is required\")\n\t\t\t.withMessageContaining(this.archive.toString());\n\t}\n\n\t@Test\n\tvoid fromTomlWhenMissingIDThrowsException() throws IOException {\n\t\ttry (InputStream coordinates = createTomlStream(null, null, true, false)) {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> BuildpackCoordinates.fromToml(coordinates, this.archive))\n\t\t\t\t.withMessageContaining(\"Buildpack descriptor must contain ID\")\n\t\t\t\t.withMessageContaining(this.archive.toString());\n\t\t}\n\t}\n\n\t@Test\n\tvoid fromTomlWhenMissingVersionThrowsException() throws IOException {\n\t\ttry (InputStream coordinates = createTomlStream(\"example/buildpack1\", null, true, false)) {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> BuildpackCoordinates.fromToml(coordinates, this.archive))\n\t\t\t\t.withMessageContaining(\"Buildpack descriptor must contain version\")\n\t\t\t\t.withMessageContaining(this.archive.toString());\n\t\t}\n\t}\n\n\t@Test\n\tvoid fromTomlWhenMissingStacksAndOrderThrowsException() throws IOException {\n\t\ttry (InputStream coordinates = createTomlStream(\"example/buildpack1\", \"0.0.1\", false, false)) {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> BuildpackCoordinates.fromToml(coordinates, this.archive))\n\t\t\t\t.withMessageContaining(\"Buildpack descriptor must contain either 'stacks' or 'order'\")\n\t\t\t\t.withMessageContaining(this.archive.toString());\n\t\t}\n\t}\n\n\t@Test\n\tvoid fromTomlWhenContainsBothStacksAndOrderThrowsException() throws IOException {\n\t\ttry (InputStream coordinates = createTomlStream(\"example/buildpack1\", \"0.0.1\", true, true)) {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> BuildpackCoordinates.fromToml(coordinates, this.archive))\n\t\t\t\t.withMessageContaining(\"Buildpack descriptor must not contain both 'stacks' and 'order'\")\n\t\t\t\t.withMessageContaining(this.archive.toString());\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromBuildpackMetadataWhenMetadataIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackCoordinates.fromBuildpackMetadata(null))\n\t\t\t.withMessage(\"'buildpackMetadata' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromBuildpackMetadataReturnsCoordinates() throws Exception {\n\t\tBuildpackMetadata metadata = BuildpackMetadata.fromJson(getContentAsString(\"buildpack-metadata.json\"));\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates.fromBuildpackMetadata(metadata);\n\t\tassertThat(coordinates.getId()).isEqualTo(\"example/hello-universe\");\n\t\tassertThat(coordinates.getVersion()).isEqualTo(\"0.0.1\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenIdIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackCoordinates.of(null, null))\n\t\t\t.withMessage(\"'id' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofReturnsCoordinates() {\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates.of(\"id\", \"1\");\n\t\tassertThat(coordinates).hasToString(\"id@1\");\n\t}\n\n\t@Test\n\tvoid getIdReturnsId() {\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates.of(\"id\", \"1\");\n\t\tassertThat(coordinates.getId()).isEqualTo(\"id\");\n\t}\n\n\t@Test\n\tvoid getVersionReturnsVersion() {\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates.of(\"id\", \"1\");\n\t\tassertThat(coordinates.getVersion()).isEqualTo(\"1\");\n\t}\n\n\t@Test\n\tvoid getVersionWhenVersionIsNullReturnsNull() {\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates.of(\"id\", null);\n\t\tassertThat(coordinates.getVersion()).isNull();\n\t}\n\n\t@Test\n\tvoid toStringReturnsNiceString() {\n\t\tBuildpackCoordinates coordinates = BuildpackCoordinates.of(\"id\", \"1\");\n\t\tassertThat(coordinates).hasToString(\"id@1\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tBuildpackCoordinates c1a = BuildpackCoordinates.of(\"id\", \"1\");\n\t\tBuildpackCoordinates c1b = BuildpackCoordinates.of(\"id\", \"1\");\n\t\tBuildpackCoordinates c2 = BuildpackCoordinates.of(\"id\", \"2\");\n\t\tassertThat(c1a).isEqualTo(c1a).isEqualTo(c1b).isNotEqualTo(c2);\n\t\tassertThat(c1a).hasSameHashCodeAs(c1b);\n\t}\n\n\tprivate InputStream createTomlStream(@Nullable String id, @Nullable String version, boolean includeStacks,\n\t\t\tboolean includeOrder) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tbuilder.append(\"[buildpack]\\n\");\n\t\tif (id != null) {\n\t\t\tbuilder.append(\"id = \\\"\").append(id).append(\"\\\"\\n\");\n\t\t}\n\t\tif (version != null) {\n\t\t\tbuilder.append(\"version = \\\"\").append(version).append(\"\\\"\\n\");\n\t\t}\n\t\tbuilder.append(\"name = \\\"Example buildpack\\\"\\n\");\n\t\tbuilder.append(\"homepage = \\\"https://github.com/example/example-buildpack\\\"\\n\");\n\t\tif (includeStacks) {\n\t\t\tbuilder.append(\"[[stacks]]\\n\");\n\t\t\tbuilder.append(\"id = \\\"io.buildpacks.stacks.bionic\\\"\\n\");\n\t\t}\n\t\tif (includeOrder) {\n\t\t\tbuilder.append(\"[[order]]\\n\");\n\t\t\tbuilder.append(\"group = [ { id = \\\"example/buildpack2\\\", version=\\\"0.0.2\\\" } ]\\n\");\n\t\t}\n\t\treturn new ByteArrayInputStream(builder.toString().getBytes(StandardCharsets.UTF_8));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildpackLayersMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BuildpackLayersMetadata}.\n *\n * @author Scott Frederick\n */\nclass BuildpackLayersMetadataTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid fromImageLoadsMetadata() throws IOException {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tBuildpackLayersMetadata metadata = BuildpackLayersMetadata.fromImage(image);\n\t\tassertThat(metadata.getBuildpack(\"example/hello-moon\", \"0.0.3\")).extracting(\"homepage\", \"layerDiffId\")\n\t\t\t.containsExactly(\"https://github.com/example/tree/main/buildpacks/hello-moon\",\n\t\t\t\t\t\"sha256:4bfdc8714aee68da6662c43bc28d3b41202c88e915641c356523dabe729814c2\");\n\t\tassertThat(metadata.getBuildpack(\"example/hello-world\", \"0.0.2\")).extracting(\"homepage\", \"layerDiffId\")\n\t\t\t.containsExactly(\"https://github.com/example/tree/main/buildpacks/hello-world\",\n\t\t\t\t\t\"sha256:f752fe099c846e501bdc991d1a22f98c055ddc62f01cfc0495fff2c69f8eb940\");\n\t\tassertThat(metadata.getBuildpack(\"example/hello-world\", \"version-does-not-exist\")).isNull();\n\t\tassertThat(metadata.getBuildpack(\"id-does-not-exist\", \"9.9.9\")).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromImageWhenImageIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackLayersMetadata.fromImage(null))\n\t\t\t.withMessage(\"'image' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageWhenImageConfigIsNullThrowsException() {\n\t\tImage image = mock(Image.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackLayersMetadata.fromImage(image))\n\t\t\t.withMessage(\"'imageConfig' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageConfigWhenLabelIsMissingThrowsException() {\n\t\tImage image = mock(Image.class);\n\t\tImageConfig imageConfig = mock(ImageConfig.class);\n\t\tgiven(image.getConfig()).willReturn(imageConfig);\n\t\tgiven(imageConfig.getLabels()).willReturn(Collections.singletonMap(\"alpha\", \"a\"));\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuildpackLayersMetadata.fromImage(image))\n\t\t\t.withMessage(\"No 'io.buildpacks.buildpack.layers' label found in image config labels 'alpha'\");\n\t}\n\n\t@Test\n\tvoid fromJsonLoadsMetadata() throws IOException {\n\t\tBuildpackLayersMetadata metadata = BuildpackLayersMetadata\n\t\t\t.fromJson(getContentAsString(\"buildpack-layers-metadata.json\"));\n\t\tassertThat(metadata.getBuildpack(\"example/hello-moon\", \"0.0.3\")).extracting(\"name\", \"homepage\", \"layerDiffId\")\n\t\t\t.containsExactly(\"Example hello-moon buildpack\",\n\t\t\t\t\t\"https://github.com/example/tree/main/buildpacks/hello-moon\",\n\t\t\t\t\t\"sha256:4bfdc8714aee68da6662c43bc28d3b41202c88e915641c356523dabe729814c2\");\n\t\tassertThat(metadata.getBuildpack(\"example/hello-world\", \"0.0.1\")).extracting(\"name\", \"homepage\", \"layerDiffId\")\n\t\t\t.containsExactly(\"Example hello-world buildpack\",\n\t\t\t\t\t\"https://github.com/example/tree/main/buildpacks/hello-world\",\n\t\t\t\t\t\"sha256:1c90e0b80d92555a0523c9ee6500845328fc39ba9dca9d30a877ff759ffbff28\");\n\t\tassertThat(metadata.getBuildpack(\"example/hello-world\", \"0.0.2\")).extracting(\"name\", \"homepage\", \"layerDiffId\")\n\t\t\t.containsExactly(\"Example hello-world buildpack\",\n\t\t\t\t\t\"https://github.com/example/tree/main/buildpacks/hello-world\",\n\t\t\t\t\t\"sha256:f752fe099c846e501bdc991d1a22f98c055ddc62f01cfc0495fff2c69f8eb940\");\n\t\tassertThat(metadata.getBuildpack(\"example/hello-world\", \"version-does-not-exist\")).isNull();\n\t\tassertThat(metadata.getBuildpack(\"id-does-not-exist\", \"9.9.9\")).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildpackMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BuildpackMetadata}.\n *\n * @author Scott Frederick\n */\nclass BuildpackMetadataTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid fromImageLoadsMetadata() throws IOException {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tBuildpackMetadata metadata = BuildpackMetadata.fromImage(image);\n\t\tassertThat(metadata.getId()).isEqualTo(\"example/hello-universe\");\n\t\tassertThat(metadata.getVersion()).isEqualTo(\"0.0.1\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromImageWhenImageIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackMetadata.fromImage(null))\n\t\t\t.withMessage(\"'image' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageWhenImageConfigIsNullThrowsException() {\n\t\tImage image = mock(Image.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackMetadata.fromImage(image))\n\t\t\t.withMessage(\"'imageConfig' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageConfigWhenLabelIsMissingThrowsException() {\n\t\tImage image = mock(Image.class);\n\t\tImageConfig imageConfig = mock(ImageConfig.class);\n\t\tgiven(image.getConfig()).willReturn(imageConfig);\n\t\tgiven(imageConfig.getLabels()).willReturn(Collections.singletonMap(\"alpha\", \"a\"));\n\t\tassertThatIllegalStateException().isThrownBy(() -> BuildpackMetadata.fromImage(image))\n\t\t\t.withMessage(\"No 'io.buildpacks.buildpackage.metadata' label found in image config labels 'alpha'\");\n\t}\n\n\t@Test\n\tvoid fromJsonLoadsMetadata() throws IOException {\n\t\tBuildpackMetadata metadata = BuildpackMetadata.fromJson(getContentAsString(\"buildpack-metadata.json\"));\n\t\tassertThat(metadata.getId()).isEqualTo(\"example/hello-universe\");\n\t\tassertThat(metadata.getVersion()).isEqualTo(\"0.0.1\");\n\t\tassertThat(metadata.getHomepage()).isEqualTo(\"https://github.com/example/tree/main/buildpacks/hello-universe\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildpackReferenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.nio.file.Paths;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link BuildpackReference}.\n *\n * @author Phillip Webb\n */\nclass BuildpackReferenceTests {\n\n\t@Test\n\tvoid ofWhenValueIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> BuildpackReference.of(\"\"))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofCreatesInstance() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"test\");\n\t\tassertThat(reference).isNotNull();\n\t}\n\n\t@Test\n\tvoid toStringReturnsValue() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"test\");\n\t\tassertThat(reference).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tBuildpackReference a = BuildpackReference.of(\"test1\");\n\t\tBuildpackReference b = BuildpackReference.of(\"test1\");\n\t\tBuildpackReference c = BuildpackReference.of(\"test2\");\n\t\tassertThat(a).isEqualTo(a).isEqualTo(b).isNotEqualTo(c);\n\t\tassertThat(a).hasSameHashCodeAs(b);\n\t}\n\n\t@Test\n\tvoid hasPrefixWhenPrefixMatchReturnsTrue() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"test\");\n\t\tassertThat(reference.hasPrefix(\"te\")).isTrue();\n\t}\n\n\t@Test\n\tvoid hasPrefixWhenPrefixMismatchReturnsFalse() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"test\");\n\t\tassertThat(reference.hasPrefix(\"st\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getSubReferenceWhenPrefixMatchReturnsSubReference() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"test\");\n\t\tassertThat(reference.getSubReference(\"te\")).isEqualTo(\"st\");\n\t}\n\n\t@Test\n\tvoid getSubReferenceWhenPrefixMismatchReturnsNull() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"test\");\n\t\tassertThat(reference.getSubReference(\"st\")).isNull();\n\t}\n\n\t@Test\n\tvoid asPathWhenFileUrlReturnsPath() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"file:///test.dat\");\n\t\tassertThat(reference.asPath()).isEqualTo(Paths.get(\"/test.dat\"));\n\t}\n\n\t@Test\n\tvoid asPathWhenPathReturnsPath() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"/test.dat\");\n\t\tassertThat(reference.asPath()).isEqualTo(Paths.get(\"/test.dat\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildpackResolversTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BuildpackResolvers}.\n *\n * @author Scott Frederick\n */\nclass BuildpackResolversTests extends AbstractJsonTests {\n\n\tprivate BuildpackResolverContext resolverContext;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tBuilderMetadata metadata = BuilderMetadata.fromJson(getContentAsString(\"builder-metadata.json\"));\n\t\tthis.resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(this.resolverContext.getBuildpackMetadata()).willReturn(metadata.getBuildpacks());\n\t}\n\n\t@Test\n\tvoid resolveAllWithBuilderBuildpackReferenceReturnsExpectedBuildpack() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"urn:cnb:builder:paketo-buildpacks/spring-boot@3.5.0\");\n\t\tBuildpacks buildpacks = BuildpackResolvers.resolveAll(this.resolverContext, Collections.singleton(reference));\n\t\tassertThat(buildpacks.getBuildpacks()).hasSize(1);\n\t\tassertThat(buildpacks.getBuildpacks().get(0)).isInstanceOf(BuilderBuildpack.class);\n\t}\n\n\t@Test\n\tvoid resolveAllWithDirectoryBuildpackReferenceReturnsExpectedBuildpack(@TempDir Path temp) throws IOException {\n\t\tFileCopyUtils.copy(getClass().getResourceAsStream(\"buildpack.toml\"),\n\t\t\t\tFiles.newOutputStream(temp.resolve(\"buildpack.toml\")));\n\t\tBuildpackReference reference = BuildpackReference.of(temp.toAbsolutePath().toString());\n\t\tBuildpacks buildpacks = BuildpackResolvers.resolveAll(this.resolverContext, Collections.singleton(reference));\n\t\tassertThat(buildpacks.getBuildpacks()).hasSize(1);\n\t\tassertThat(buildpacks.getBuildpacks().get(0)).isInstanceOf(DirectoryBuildpack.class);\n\t}\n\n\t@Test\n\tvoid resolveAllWithTarGzipBuildpackReferenceReturnsExpectedBuildpack(@TempDir File temp) throws Exception {\n\t\tTestTarGzip testTarGzip = new TestTarGzip(temp);\n\t\tPath archive = testTarGzip.createArchive();\n\t\tBuildpackReference reference = BuildpackReference.of(archive.toString());\n\t\tBuildpacks buildpacks = BuildpackResolvers.resolveAll(this.resolverContext, Collections.singleton(reference));\n\t\tassertThat(buildpacks.getBuildpacks()).hasSize(1);\n\t\tassertThat(buildpacks.getBuildpacks().get(0)).isInstanceOf(TarGzipBuildpack.class);\n\t}\n\n\t@Test\n\tvoid resolveAllWithImageBuildpackReferenceReturnsExpectedBuildpack() throws IOException {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.getBuildpackLayersMetadata()).willReturn(BuildpackLayersMetadata.fromJson(\"{}\"));\n\t\tgiven(resolverContext.fetchImage(any(), any())).willReturn(image);\n\t\tBuildpackReference reference = BuildpackReference.of(\"docker://example/buildpack1:latest\");\n\t\tBuildpacks buildpacks = BuildpackResolvers.resolveAll(resolverContext, Collections.singleton(reference));\n\t\tassertThat(buildpacks.getBuildpacks()).hasSize(1);\n\t\tassertThat(buildpacks.getBuildpacks().get(0)).isInstanceOf(ImageBuildpack.class);\n\t}\n\n\t@Test\n\tvoid resolveAllWithInvalidLocatorThrowsException() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"unknown-buildpack@0.0.1\");\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> BuildpackResolvers.resolveAll(this.resolverContext, Collections.singleton(reference)))\n\t\t\t.withMessageContaining(\"Invalid buildpack reference\")\n\t\t\t.withMessageContaining(\"'unknown-buildpack@0.0.1'\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/BuildpacksTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Buildpacks}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nclass BuildpacksTests {\n\n\t@Test\n\tvoid ofWhenBuildpacksIsNullReturnsEmpty() {\n\t\tBuildpacks buildpacks = Buildpacks.of(null);\n\t\tassertThat(buildpacks).isSameAs(Buildpacks.EMPTY);\n\t\tassertThat(buildpacks.getBuildpacks()).isEmpty();\n\t}\n\n\t@Test\n\tvoid ofReturnsBuildpacks() {\n\t\tList<Buildpack> buildpackList = new ArrayList<>();\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack1\", \"0.0.1\"));\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack2\", \"0.0.2\"));\n\t\tBuildpacks buildpacks = Buildpacks.of(buildpackList);\n\t\tassertThat(buildpacks.getBuildpacks()).isEqualTo(buildpackList);\n\t}\n\n\t@Test\n\tvoid applyWritesLayersAndOrderLayer() throws Exception {\n\t\tList<Buildpack> buildpackList = new ArrayList<>();\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack1\", \"0.0.1\"));\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack2\", \"0.0.2\"));\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack3\", null));\n\t\tBuildpacks buildpacks = Buildpacks.of(buildpackList);\n\t\tList<Layer> layers = new ArrayList<>();\n\t\tbuildpacks.apply(layers::add);\n\t\tassertThat(layers).hasSize(4);\n\t\tassertThatLayerContentIsCorrect(layers.get(0), \"example_buildpack1/0.0.1\");\n\t\tassertThatLayerContentIsCorrect(layers.get(1), \"example_buildpack2/0.0.2\");\n\t\tassertThatLayerContentIsCorrect(layers.get(2), \"example_buildpack3/null\");\n\t\tassertThatOrderLayerContentIsCorrect(layers.get(3));\n\t}\n\n\tprivate void assertThatLayerContentIsCorrect(Layer layer, String path) throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tlayer.writeTo(out);\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(out.toByteArray()))) {\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"/cnb/buildpacks/\" + path + \"/buildpack.toml\");\n\t\t\tassertThat(tar.getNextEntry()).isNull();\n\t\t}\n\t}\n\n\tprivate void assertThatOrderLayerContentIsCorrect(Layer layer) throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tlayer.writeTo(out);\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(out.toByteArray()))) {\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"/cnb/order.toml\");\n\t\t\tbyte[] content = StreamUtils.copyToByteArray(tar);\n\t\t\tString toml = new String(content, StandardCharsets.UTF_8);\n\t\t\tassertThat(toml).isEqualTo(getExpectedToml());\n\t\t}\n\t}\n\n\tprivate String getExpectedToml() {\n\t\tStringBuilder toml = new StringBuilder();\n\t\ttoml.append(\"[[order]]\\n\");\n\t\ttoml.append(\"\\n\");\n\t\ttoml.append(\"  [[order.group]]\\n\");\n\t\ttoml.append(\"    id = \\\"example/buildpack1\\\"\\n\");\n\t\ttoml.append(\"    version = \\\"0.0.1\\\"\\n\");\n\t\ttoml.append(\"\\n\");\n\t\ttoml.append(\"  [[order.group]]\\n\");\n\t\ttoml.append(\"    id = \\\"example/buildpack2\\\"\\n\");\n\t\ttoml.append(\"    version = \\\"0.0.2\\\"\\n\");\n\t\ttoml.append(\"\\n\");\n\t\ttoml.append(\"  [[order.group]]\\n\");\n\t\ttoml.append(\"    id = \\\"example/buildpack3\\\"\\n\");\n\t\ttoml.append(\"\\n\");\n\t\treturn toml.toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/DirectoryBuildpackTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.tuple;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DirectoryBuildpack}.\n *\n * @author Scott Frederick\n */\n@DisabledOnOs(OS.WINDOWS)\nclass DirectoryBuildpackTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\tprivate File buildpackDir;\n\n\tprivate BuildpackResolverContext resolverContext;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.buildpackDir = new File(this.temp, \"buildpack\");\n\t\tthis.buildpackDir.mkdirs();\n\t\tthis.resolverContext = mock(BuildpackResolverContext.class);\n\t}\n\n\t@Test\n\tvoid resolveWhenPath() throws Exception {\n\t\twriteBuildpackDescriptor();\n\t\twriteScripts();\n\t\tBuildpackReference reference = BuildpackReference.of(this.buildpackDir.toString());\n\t\tBuildpack buildpack = DirectoryBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/buildpack1@0.0.1\");\n\t\tassertHasExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenFileUrl() throws Exception {\n\t\twriteBuildpackDescriptor();\n\t\twriteScripts();\n\t\tBuildpackReference reference = BuildpackReference.of(\"file://\" + this.buildpackDir.toString());\n\t\tBuildpack buildpack = DirectoryBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/buildpack1@0.0.1\");\n\t\tassertHasExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenDirectoryWithoutBuildpackTomlThrowsException() throws Exception {\n\t\tFiles.createDirectories(this.buildpackDir.toPath());\n\t\tBuildpackReference reference = BuildpackReference.of(this.buildpackDir.toString());\n\t\tassertThatIllegalStateException().isThrownBy(() -> DirectoryBuildpack.resolve(this.resolverContext, reference))\n\t\t\t.withMessageContaining(\"Buildpack descriptor 'buildpack.toml' is required\")\n\t\t\t.withMessageContaining(this.buildpackDir.getAbsolutePath());\n\t}\n\n\t@Test\n\tvoid resolveWhenFileReturnsNull() throws Exception {\n\t\tPath file = Files.createFile(Paths.get(this.buildpackDir.toString(), \"test\"));\n\t\tBuildpackReference reference = BuildpackReference.of(file.toString());\n\t\tBuildpack buildpack = DirectoryBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenDirectoryDoesNotExistReturnsNull() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"/test/a/missing/buildpack\");\n\t\tBuildpack buildpack = DirectoryBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n\t@Test\n\tvoid locateDirectoryAsUrlThatDoesNotExistThrowsException() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"file:///test/a/missing/buildpack\");\n\t\tBuildpack buildpack = DirectoryBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n\tprivate void assertHasExpectedLayers(Buildpack buildpack) throws IOException {\n\t\tList<ByteArrayOutputStream> layers = new ArrayList<>();\n\t\tbuildpack.apply((layer) -> {\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tlayer.writeTo(out);\n\t\t\tlayers.add(out);\n\t\t});\n\t\tassertThat(layers).hasSize(1);\n\t\tbyte[] content = layers.get(0).toByteArray();\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(content))) {\n\t\t\tList<TarArchiveEntry> entries = new ArrayList<>();\n\t\t\tTarArchiveEntry entry = tar.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tentries.add(entry);\n\t\t\t\tentry = tar.getNextEntry();\n\t\t\t}\n\t\t\tassertThat(entries).extracting(\"name\", \"mode\")\n\t\t\t\t.containsExactlyInAnyOrder(tuple(\"/cnb/\", 0755), tuple(\"/cnb/buildpacks/\", 0755),\n\t\t\t\t\t\ttuple(\"/cnb/buildpacks/example_buildpack1/\", 0755),\n\t\t\t\t\t\ttuple(\"/cnb/buildpacks/example_buildpack1/0.0.1/\", 0755),\n\t\t\t\t\t\ttuple(\"/cnb/buildpacks/example_buildpack1/0.0.1/buildpack.toml\", 0644),\n\t\t\t\t\t\ttuple(\"/cnb/buildpacks/example_buildpack1/0.0.1/bin/\", 0755),\n\t\t\t\t\t\ttuple(\"/cnb/buildpacks/example_buildpack1/0.0.1/bin/detect\", 0744),\n\t\t\t\t\t\ttuple(\"/cnb/buildpacks/example_buildpack1/0.0.1/bin/build\", 0744));\n\t\t}\n\t}\n\n\tprivate void writeBuildpackDescriptor() throws IOException {\n\t\tPath descriptor = Files.createFile(Paths.get(this.buildpackDir.getAbsolutePath(), \"buildpack.toml\"),\n\t\t\t\tPosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(\"rw-r--r--\")));\n\t\ttry (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(descriptor))) {\n\t\t\twriter.println(\"[buildpack]\");\n\t\t\twriter.println(\"id = \\\"example/buildpack1\\\"\");\n\t\t\twriter.println(\"version = \\\"0.0.1\\\"\");\n\t\t\twriter.println(\"name = \\\"Example buildpack\\\"\");\n\t\t\twriter.println(\"homepage = \\\"https://github.com/example/example-buildpack\\\"\");\n\t\t\twriter.println(\"[[stacks]]\");\n\t\t\twriter.println(\"id = \\\"io.buildpacks.stacks.bionic\\\"\");\n\t\t}\n\t}\n\n\tprivate void writeScripts() throws IOException {\n\t\tPath binDirectory = Files.createDirectory(Paths.get(this.buildpackDir.getAbsolutePath(), \"bin\"),\n\t\t\t\tPosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(\"rwxr-xr-x\")));\n\t\tbinDirectory.toFile().mkdirs();\n\t\tPath detect = Files.createFile(Paths.get(binDirectory.toString(), \"detect\"),\n\t\t\t\tPosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(\"rwxr--r--\")));\n\t\ttry (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(detect))) {\n\t\t\twriter.println(\"#!/usr/bin/env bash\");\n\t\t\twriter.println(\"echo \\\"---> detect\\\"\");\n\t\t}\n\t\tPath build = Files.createFile(Paths.get(binDirectory.toString(), \"build\"),\n\t\t\t\tPosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString(\"rwxr--r--\")));\n\t\ttry (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(build))) {\n\t\t\twriter.println(\"#!/usr/bin/env bash\");\n\t\t\twriter.println(\"echo \\\"---> build\\\"\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/EphemeralBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneId;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link EphemeralBuilder}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass EphemeralBuilderTests extends AbstractJsonTests {\n\n\tprivate static final int EXISTING_IMAGE_LAYER_COUNT = 43;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\tprivate final BuildOwner owner = BuildOwner.of(123, 456);\n\n\tprivate Image image;\n\n\tprivate ImageReference targetImage;\n\n\tprivate BuilderMetadata metadata;\n\n\tprivate Map<String, String> env;\n\n\tprivate @Nullable Buildpacks buildpacks;\n\n\tprivate final Creator creator = Creator.withVersion(\"dev\");\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.image = Image.of(getContent(\"image.json\"));\n\t\tthis.targetImage = ImageReference.of(\"my-image:latest\");\n\t\tthis.metadata = BuilderMetadata.fromImage(this.image);\n\t\tthis.env = new HashMap<>();\n\t\tthis.env.put(\"spring\", \"boot\");\n\t\tthis.env.put(\"empty\", null);\n\t}\n\n\t@Test\n\tvoid getNameHasRandomName() {\n\t\tEphemeralBuilder b1 = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tEphemeralBuilder b2 = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tassertThat(b1.getName().toString()).startsWith(\"pack.local/builder/\").endsWith(\":latest\");\n\t\tassertThat(b1.getName().toString()).isNotEqualTo(b2.getName().toString());\n\t}\n\n\t@Test\n\tvoid getArchiveHasCreatedByConfig() throws Exception {\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tImageConfig config = builder.getArchive(null).getImageConfig();\n\t\tBuilderMetadata ephemeralMetadata = BuilderMetadata.fromImageConfig(config);\n\t\tassertThat(ephemeralMetadata.getCreatedBy().getName()).isEqualTo(\"Spring Boot\");\n\t\tassertThat(ephemeralMetadata.getCreatedBy().getVersion()).isEqualTo(\"dev\");\n\t}\n\n\t@Test\n\tvoid getArchiveHasTag() throws Exception {\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tImageReference tag = builder.getArchive(null).getTag();\n\t\tassertThat(tag).isNotNull();\n\t\tassertThat(tag.toString()).startsWith(\"pack.local/builder/\").endsWith(\":latest\");\n\t}\n\n\t@Test\n\tvoid getArchiveHasFixedCreatedDate() throws Exception {\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tInstant createInstant = builder.getArchive(null).getCreateDate();\n\t\tOffsetDateTime createDateTime = OffsetDateTime.ofInstant(createInstant, ZoneId.of(\"UTC\"));\n\t\tassertThat(createDateTime.getYear()).isEqualTo(1980);\n\t\tassertThat(createDateTime.getMonthValue()).isOne();\n\t\tassertThat(createDateTime.getDayOfMonth()).isOne();\n\t\tassertThat(createDateTime.getHour()).isZero();\n\t\tassertThat(createDateTime.getMinute()).isZero();\n\t\tassertThat(createDateTime.getSecond()).isOne();\n\t}\n\n\t@Test\n\tvoid getArchiveContainsEnvLayer() throws Exception {\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tFile directory = unpack(getLayer(builder.getArchive(null), EXISTING_IMAGE_LAYER_COUNT), \"env\");\n\t\tassertThat(new File(directory, \"platform/env/spring\")).usingCharset(StandardCharsets.UTF_8).hasContent(\"boot\");\n\t\tassertThat(new File(directory, \"platform/env/empty\")).usingCharset(StandardCharsets.UTF_8).hasContent(\"\");\n\t}\n\n\t@Test\n\tvoid getArchiveHasBuilderForLabel() throws Exception {\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tImageConfig config = builder.getArchive(null).getImageConfig();\n\t\tassertThat(config.getLabels())\n\t\t\t.contains(entry(EphemeralBuilder.BUILDER_FOR_LABEL_NAME, this.targetImage.toString()));\n\t}\n\n\t@Test\n\tvoid getArchiveContainsBuildpackLayers() throws Exception {\n\t\tList<Buildpack> buildpackList = new ArrayList<>();\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack1\", \"0.0.1\"));\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack2\", \"0.0.2\"));\n\t\tbuildpackList.add(new TestBuildpack(\"example/buildpack3\", \"0.0.3\"));\n\t\tthis.buildpacks = Buildpacks.of(buildpackList);\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, null, this.buildpacks);\n\t\tassertBuildpackLayerContent(builder, EXISTING_IMAGE_LAYER_COUNT,\n\t\t\t\t\"/cnb/buildpacks/example_buildpack1/0.0.1/buildpack.toml\");\n\t\tassertBuildpackLayerContent(builder, EXISTING_IMAGE_LAYER_COUNT + 1,\n\t\t\t\t\"/cnb/buildpacks/example_buildpack2/0.0.2/buildpack.toml\");\n\t\tassertBuildpackLayerContent(builder, EXISTING_IMAGE_LAYER_COUNT + 2,\n\t\t\t\t\"/cnb/buildpacks/example_buildpack3/0.0.3/buildpack.toml\");\n\t\tFile orderDirectory = unpack(getLayer(builder.getArchive(null), EXISTING_IMAGE_LAYER_COUNT + 3), \"order\");\n\t\tassertThat(new File(orderDirectory, \"cnb/order.toml\")).usingCharset(StandardCharsets.UTF_8)\n\t\t\t.hasContent(content(\"order.toml\"));\n\t}\n\n\t@Test\n\tvoid getArchiveHasApplicationDirectoryLayer() throws Exception {\n\t\tEphemeralBuilder builder = new EphemeralBuilder(this.owner, this.image, this.targetImage, this.metadata,\n\t\t\t\tthis.creator, this.env, this.buildpacks);\n\t\tFile directory = unpack(getLayer(builder.getArchive(\"/myapp\"), EXISTING_IMAGE_LAYER_COUNT + 1), \"appdir\");\n\t\tassertThat(new File(directory, \"myapp\")).isDirectory();\n\t}\n\n\tprivate void assertBuildpackLayerContent(EphemeralBuilder builder, int index, String s) throws Exception {\n\t\tFile buildpackDirectory = unpack(getLayer(builder.getArchive(null), index), \"buildpack\");\n\t\tassertThat(new File(buildpackDirectory, s)).usingCharset(StandardCharsets.UTF_8).hasContent(\"[test]\");\n\t}\n\n\tprivate TarArchiveInputStream getLayer(ImageArchive archive, int index) throws Exception {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tarchive.writeTo(outputStream);\n\t\tTarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(outputStream.toByteArray()));\n\t\tfor (int i = 0; i <= index; i++) {\n\t\t\ttar.getNextEntry();\n\t\t}\n\t\treturn new TarArchiveInputStream(tar);\n\t}\n\n\tprivate File unpack(TarArchiveInputStream archive, String name) throws Exception {\n\t\tFile directory = new File(this.temp, name);\n\t\tdirectory.mkdirs();\n\t\tArchiveEntry entry = archive.getNextEntry();\n\t\twhile (entry != null) {\n\t\t\tFile file = new File(directory, entry.getName());\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tfile.mkdirs();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfile.getParentFile().mkdirs();\n\t\t\t\ttry (OutputStream out = new FileOutputStream(file)) {\n\t\t\t\t\tStreamUtils.copy(archive, out);\n\t\t\t\t}\n\t\t\t}\n\t\t\tentry = archive.getNextEntry();\n\t\t}\n\t\treturn directory;\n\t}\n\n\tprivate String content(String fileName) throws IOException {\n\t\tInputStream in = getClass().getResourceAsStream(fileName);\n\t\treturn FileCopyUtils.copyToString(new InputStreamReader(in, StandardCharsets.UTF_8));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ImageBuildpackTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.invocation.InvocationOnMock;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.IOBiConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.buildpack.platform.io.TarArchive.Compression;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.assertj.core.api.Assertions.tuple;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ImageBuildpack}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nclass ImageBuildpackTests extends AbstractJsonTests {\n\n\tprivate String longFilePath;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tStringBuilder path = new StringBuilder();\n\t\tnew Random().ints('a', 'z' + 1).limit(100).forEach((i) -> path.append((char) i));\n\t\tthis.longFilePath = path.toString();\n\t}\n\n\t@Test\n\tvoid resolveWhenFullyQualifiedReferenceReturnsBuildpack() throws Exception {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tImageReference imageReference = ImageReference.of(\"example/buildpack1:1.0.0\");\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.getBuildpackLayersMetadata()).willReturn(BuildpackLayersMetadata.fromJson(\"{}\"));\n\t\tgiven(resolverContext.fetchImage(eq(imageReference), eq(ImageType.BUILDPACK))).willReturn(image);\n\t\twillAnswer(this::withMockLayers).given(resolverContext).exportImageLayers(eq(imageReference), any());\n\t\tBuildpackReference reference = BuildpackReference.of(\"docker://example/buildpack1:1.0.0\");\n\t\tBuildpack buildpack = ImageBuildpack.resolve(resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/hello-universe@0.0.1\");\n\t\tassertAppliesExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenUnqualifiedReferenceReturnsBuildpack() throws Exception {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tImageReference imageReference = ImageReference.of(\"example/buildpack1:1.0.0\");\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.getBuildpackLayersMetadata()).willReturn(BuildpackLayersMetadata.fromJson(\"{}\"));\n\t\tgiven(resolverContext.fetchImage(eq(imageReference), eq(ImageType.BUILDPACK))).willReturn(image);\n\t\twillAnswer(this::withMockLayers).given(resolverContext).exportImageLayers(eq(imageReference), any());\n\t\tBuildpackReference reference = BuildpackReference.of(\"example/buildpack1:1.0.0\");\n\t\tBuildpack buildpack = ImageBuildpack.resolve(resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/hello-universe@0.0.1\");\n\t\tassertAppliesExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveReferenceWithoutTagUsesLatestTag() throws Exception {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tImageReference imageReference = ImageReference.of(\"example/buildpack1:latest\");\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.getBuildpackLayersMetadata()).willReturn(BuildpackLayersMetadata.fromJson(\"{}\"));\n\t\tgiven(resolverContext.fetchImage(eq(imageReference), eq(ImageType.BUILDPACK))).willReturn(image);\n\t\twillAnswer(this::withMockLayers).given(resolverContext).exportImageLayers(eq(imageReference), any());\n\t\tBuildpackReference reference = BuildpackReference.of(\"example/buildpack1\");\n\t\tBuildpack buildpack = ImageBuildpack.resolve(resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/hello-universe@0.0.1\");\n\t\tassertAppliesExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveReferenceWithDigestUsesDigest() throws Exception {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tString digest = \"sha256:4acb6bfd6c4f0cabaf7f3690e444afe51f1c7de54d51da7e63fac709c56f1c30\";\n\t\tImageReference imageReference = ImageReference.of(\"example/buildpack1@\" + digest);\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.getBuildpackLayersMetadata()).willReturn(BuildpackLayersMetadata.fromJson(\"{}\"));\n\t\tgiven(resolverContext.fetchImage(eq(imageReference), eq(ImageType.BUILDPACK))).willReturn(image);\n\t\twillAnswer(this::withMockLayers).given(resolverContext).exportImageLayers(eq(imageReference), any());\n\t\tBuildpackReference reference = BuildpackReference.of(\"example/buildpack1@\" + digest);\n\t\tBuildpack buildpack = ImageBuildpack.resolve(resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/hello-universe@0.0.1\");\n\t\tassertAppliesExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenBuildpackExistsInBuilderSkipsLayers() throws Exception {\n\t\tImage image = Image.of(getContent(\"buildpack-image.json\"));\n\t\tImageReference imageReference = ImageReference.of(\"example/buildpack1:1.0.0\");\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.getBuildpackLayersMetadata())\n\t\t\t.willReturn(BuildpackLayersMetadata.fromJson(getContentAsString(\"buildpack-layers-metadata.json\")));\n\t\tgiven(resolverContext.fetchImage(eq(imageReference), eq(ImageType.BUILDPACK))).willReturn(image);\n\t\twillAnswer(this::withMockLayers).given(resolverContext).exportImageLayers(eq(imageReference), any());\n\t\tBuildpackReference reference = BuildpackReference.of(\"docker://example/buildpack1:1.0.0\");\n\t\tBuildpack buildpack = ImageBuildpack.resolve(resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/hello-universe@0.0.1\");\n\t\tassertAppliesNoLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenWhenImageNotPulledThrowsException() throws Exception {\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.fetchImage(any(), any())).willThrow(IOException.class);\n\t\tBuildpackReference reference = BuildpackReference.of(\"docker://example/buildpack1\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageBuildpack.resolve(resolverContext, reference))\n\t\t\t.withMessageContaining(\"Error pulling buildpack image\")\n\t\t\t.withMessageContaining(\"example/buildpack1:latest\");\n\t}\n\n\t@Test\n\tvoid resolveWhenMissingMetadataLabelThrowsException() throws Exception {\n\t\tImage image = Image.of(getContent(\"image.json\"));\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tgiven(resolverContext.fetchImage(any(), any())).willReturn(image);\n\t\tBuildpackReference reference = BuildpackReference.of(\"docker://example/buildpack1:latest\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> ImageBuildpack.resolve(resolverContext, reference))\n\t\t\t.withMessageContaining(\"No 'io.buildpacks.buildpackage.metadata' label found\");\n\t}\n\n\t@Test\n\tvoid resolveWhenFullyQualifiedReferenceWithInvalidImageReferenceThrowsException() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"docker://buildpack@0.0.1\");\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageBuildpack.resolve(resolverContext, reference))\n\t\t\t.withMessageContaining(\"'value' [buildpack@0.0.1] must be an image reference\");\n\t}\n\n\t@Test\n\tvoid resolveWhenUnqualifiedReferenceWithInvalidImageReferenceReturnsNull() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"buildpack@0.0.1\");\n\t\tBuildpackResolverContext resolverContext = mock(BuildpackResolverContext.class);\n\t\tBuildpack buildpack = ImageBuildpack.resolve(resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n\tprivate @Nullable Object withMockLayers(InvocationOnMock invocation) {\n\t\ttry {\n\t\t\tIOBiConsumer<String, TarArchive> consumer = invocation.getArgument(1);\n\t\t\tFile tarFile = File.createTempFile(\"create-builder-test-\", null);\n\t\t\ttry (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(new FileOutputStream(tarFile))) {\n\t\t\t\ttarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n\t\t\t\twriteTarEntry(tarOut, \"/cnb/\");\n\t\t\t\twriteTarEntry(tarOut, \"/cnb/buildpacks/\");\n\t\t\t\twriteTarEntry(tarOut, \"/cnb/buildpacks/example_buildpack/\");\n\t\t\t\twriteTarEntry(tarOut, \"/cnb/buildpacks/example_buildpack/0.0.1/\");\n\t\t\t\twriteTarEntry(tarOut, \"/cnb/buildpacks/example_buildpack/0.0.1/buildpack.toml\");\n\t\t\t\twriteTarEntry(tarOut, \"/cnb/buildpacks/example_buildpack/0.0.1/\" + this.longFilePath);\n\t\t\t\ttarOut.finish();\n\t\t\t}\n\t\t\ttry (FileInputStream tarFileStream = new FileInputStream(tarFile)) {\n\t\t\t\tconsumer.accept(\"test\", TarArchive.fromInputStream(tarFileStream, Compression.NONE));\n\t\t\t}\n\t\t\tFiles.delete(tarFile.toPath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tfail(\"Error writing mock layers\", ex);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void writeTarEntry(TarArchiveOutputStream tarOut, String name) throws IOException {\n\t\tTarArchiveEntry entry = new TarArchiveEntry(name);\n\t\ttarOut.putArchiveEntry(entry);\n\t\ttarOut.closeArchiveEntry();\n\t}\n\n\tprivate void assertAppliesExpectedLayers(Buildpack buildpack) throws IOException {\n\t\tList<ByteArrayOutputStream> layers = new ArrayList<>();\n\t\tbuildpack.apply((layer) -> {\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tlayer.writeTo(out);\n\t\t\tlayers.add(out);\n\t\t});\n\t\tassertThat(layers).hasSize(1);\n\t\tbyte[] content = layers.get(0).toByteArray();\n\t\tList<TarArchiveEntry> entries = new ArrayList<>();\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(content))) {\n\t\t\tTarArchiveEntry entry = tar.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tentries.add(entry);\n\t\t\t\tentry = tar.getNextEntry();\n\t\t\t}\n\t\t}\n\t\tassertThat(entries).extracting(\"name\", \"mode\")\n\t\t\t.containsExactlyInAnyOrder(tuple(\"cnb/\", TarArchiveEntry.DEFAULT_DIR_MODE),\n\t\t\t\t\ttuple(\"cnb/buildpacks/\", TarArchiveEntry.DEFAULT_DIR_MODE),\n\t\t\t\t\ttuple(\"cnb/buildpacks/example_buildpack/\", TarArchiveEntry.DEFAULT_DIR_MODE),\n\t\t\t\t\ttuple(\"cnb/buildpacks/example_buildpack/0.0.1/\", TarArchiveEntry.DEFAULT_DIR_MODE),\n\t\t\t\t\ttuple(\"cnb/buildpacks/example_buildpack/0.0.1/buildpack.toml\", TarArchiveEntry.DEFAULT_FILE_MODE),\n\t\t\t\t\ttuple(\"cnb/buildpacks/example_buildpack/0.0.1/\" + this.longFilePath,\n\t\t\t\t\t\t\tTarArchiveEntry.DEFAULT_FILE_MODE));\n\t}\n\n\tprivate void assertAppliesNoLayers(Buildpack buildpack) throws IOException {\n\t\tList<ByteArrayOutputStream> layers = new ArrayList<>();\n\t\tbuildpack.apply((layer) -> {\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tlayer.writeTo(out);\n\t\t\tlayers.add(out);\n\t\t});\n\t\tassertThat(layers).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.PrintStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.sun.jna.Platform;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.mockito.stubbing.Answer;\nimport org.skyscreamer.jsonassert.JSONAssert;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.node.ArrayNode;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerContent;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerReference;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.boot.testsupport.junit.BooleanValueSource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Lifecycle}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n */\nclass LifecycleTests {\n\n\tprivate TestPrintStream out;\n\n\tprivate DockerApi docker;\n\n\tprivate final Map<String, ContainerConfig> configs = new LinkedHashMap<>();\n\n\tprivate final Map<String, ContainerContent> content = new LinkedHashMap<>();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.out = new TestPrintStream();\n\t\tthis.docker = mockDockerApi();\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tcreateLifecycle(trustBuilder).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@Test\n\tvoid executeWithBindingsExecutesPhases() throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(true).withBindings(Binding.of(\"/host/src/path:/container/dest/path:ro\"),\n\t\t\t\tBinding.of(\"volume-name:/container/volume/path:rw\"));\n\t\tcreateLifecycle(request).execute();\n\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-bindings.json\"));\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@Test\n\tvoid executeExecutesPhasesWithPlatformApi03() throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tcreateLifecycle(true, \"builder-metadata-platform-api-0.3.json\").execute();\n\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-platform-api-0.3.json\"));\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeOnlyUploadsContentOnce(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tcreateLifecycle(trustBuilder).execute();\n\t\tassertThat(this.content).hasSize(1);\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWhenAlreadyRunThrowsException(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tLifecycle lifecycle = createLifecycle(trustBuilder);\n\t\tlifecycle.execute();\n\t\tassertThatIllegalStateException().isThrownBy(lifecycle::execute)\n\t\t\t.withMessage(\"Lifecycle has already been executed\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWhenBuilderReturnsErrorThrowsException(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(9, null));\n\t\tassertThatExceptionOfType(BuilderException.class).isThrownBy(() -> createLifecycle(trustBuilder).execute())\n\t\t\t.withMessage(\n\t\t\t\t\t\"Builder lifecycle '\" + ((trustBuilder) ? \"creator\" : \"analyzer\") + \"' failed with status code 9\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWhenCleanCacheClearsCache(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder).withCleanCache(true);\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-clean-cache.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter.json\"));\n\t\t\tassertThat(this.out.toString()).contains(\"Skipping restorer because 'cleanCache' is enabled\");\n\t\t}\n\t\tVolumeName name = VolumeName.of(\"pack-cache-b35197ac41ea.build\");\n\t\tthen(this.docker.volume()).should().delete(name, true);\n\t}\n\n\t@Test\n\tvoid executeWhenPlatformApiNotSupportedThrowsException() throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> createLifecycle(true, \"builder-metadata-unsupported-api.json\").execute())\n\t\t\t.withMessageContaining(\"Detected platform API versions '0.2' are not included in supported versions\");\n\t}\n\n\t@Test\n\tvoid executeWhenMultiplePlatformApisNotSupportedThrowsException() throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> createLifecycle(true, \"builder-metadata-unsupported-apis.json\").execute())\n\t\t\t.withMessageContaining(\"Detected platform API versions '0.1,0.2' are not included in supported versions\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWhenMultiplePlatformApisSupportedExecutesPhase(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tcreateLifecycle(trustBuilder, \"builder-metadata-supported-apis.json\").execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter.json\"));\n\t\t}\n\t}\n\n\t@Test\n\tvoid closeClearsVolumes() throws Exception {\n\t\tcreateLifecycle(true).close();\n\t\tthen(this.docker.volume()).should().delete(VolumeName.of(\"pack-layers-aaaaaaaaaa\"), true);\n\t\tthen(this.docker.volume()).should().delete(VolumeName.of(\"pack-app-aaaaaaaaaa\"), true);\n\t}\n\n\t@Test\n\tvoid executeWithNetworkExecutesPhases() throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(true).withNetwork(\"test\");\n\t\tcreateLifecycle(request).execute();\n\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-network.json\"));\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithCacheVolumeNamesExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder).withBuildWorkspace(Cache.volume(\"work-volume\"))\n\t\t\t.withBuildCache(Cache.volume(\"build-volume\"))\n\t\t\t.withLaunchCache(Cache.volume(\"launch-volume\"));\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-cache-volumes.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer-cache-volumes.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector-cache-volumes.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer-cache-volumes.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder-cache-volumes.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-cache-volumes.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithCacheBindMountsExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder).withBuildWorkspace(Cache.bind(\"/tmp/work\"))\n\t\t\t.withBuildCache(Cache.bind(\"/tmp/build-cache\"))\n\t\t\t.withLaunchCache(Cache.bind(\"/tmp/launch-cache\"));\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-cache-bind-mounts.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer-cache-bind-mounts.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector-cache-bind-mounts.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer-cache-bind-mounts.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder-cache-bind-mounts.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-cache-bind-mounts.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithCreatedDateExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder).withCreatedDate(\"2020-07-01T12:34:56Z\");\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-created-date.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-created-date.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithApplicationDirectoryExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder).withApplicationDirectory(\"/application\");\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-app-dir.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector-app-dir.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder-app-dir.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-app-dir.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithSecurityOptionsExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder)\n\t\t\t.withSecurityOptions(List.of(\"label=user:USER\", \"label=role:ROLE\"));\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-security-opts.json\", true));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer-security-opts.json\", true));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer-security-opts.json\", true));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-security-opts.json\", true));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithDockerHostAndRemoteAddressExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder);\n\t\tcreateLifecycle(request,\n\t\t\t\tResolvedDockerHost.from(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.2:2376\")))\n\t\t\t.execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-inherit-remote.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer-inherit-remote.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer-inherit-remote.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-inherit-remote.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithDockerHostAndLocalAddressExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), isNull())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), isNull(), any())).willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder);\n\t\tcreateLifecycle(request, ResolvedDockerHost.from(new DockerConnectionConfiguration.Host(\"/var/alt.sock\")))\n\t\t\t.execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator-inherit-local.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer-inherit-local.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer-inherit-local.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter-inherit-local.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\t@ParameterizedTest\n\t@BooleanValueSource\n\tvoid executeWithImagePlatformExecutesPhases(boolean trustBuilder) throws Exception {\n\t\tgiven(this.docker.container().create(any(), eq(ImagePlatform.of(\"linux/arm64\"))))\n\t\t\t.willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().create(any(), eq(ImagePlatform.of(\"linux/arm64\")), any()))\n\t\t\t.willAnswer(answerWithGeneratedContainerId());\n\t\tgiven(this.docker.container().wait(any())).willReturn(ContainerStatus.of(0, null));\n\t\tBuildRequest request = getTestRequest(trustBuilder).withImagePlatform(\"linux/arm64\");\n\t\tcreateLifecycle(request).execute();\n\t\tif (trustBuilder) {\n\t\t\tassertPhaseWasRun(\"creator\", withExpectedConfig(\"lifecycle-creator.json\"));\n\t\t}\n\t\telse {\n\t\t\tassertPhaseWasRun(\"analyzer\", withExpectedConfig(\"lifecycle-analyzer.json\"));\n\t\t\tassertPhaseWasRun(\"detector\", withExpectedConfig(\"lifecycle-detector.json\"));\n\t\t\tassertPhaseWasRun(\"restorer\", withExpectedConfig(\"lifecycle-restorer.json\"));\n\t\t\tassertPhaseWasRun(\"builder\", withExpectedConfig(\"lifecycle-builder.json\"));\n\t\t\tassertPhaseWasRun(\"exporter\", withExpectedConfig(\"lifecycle-exporter.json\"));\n\t\t}\n\t\tassertThat(this.out.toString()).contains(\"Successfully built image 'docker.io/library/my-application:latest'\");\n\t}\n\n\tprivate DockerApi mockDockerApi() {\n\t\tDockerApi docker = mock(DockerApi.class);\n\t\tImageApi imageApi = mock(ImageApi.class);\n\t\tContainerApi containerApi = mock(ContainerApi.class);\n\t\tVolumeApi volumeApi = mock(VolumeApi.class);\n\t\tgiven(docker.image()).willReturn(imageApi);\n\t\tgiven(docker.container()).willReturn(containerApi);\n\t\tgiven(docker.volume()).willReturn(volumeApi);\n\t\treturn docker;\n\t}\n\n\tprivate BuildRequest getTestRequest(boolean trustBuilder) {\n\t\tTarArchive content = mock(TarArchive.class);\n\t\tImageReference name = ImageReference.of(\"my-application\");\n\t\treturn BuildRequest.of(name, (owner) -> content)\n\t\t\t.withRunImage(ImageReference.of(\"cloudfoundry/run\"))\n\t\t\t.withTrustBuilder(trustBuilder);\n\t}\n\n\tprivate Lifecycle createLifecycle(boolean trustBuilder) throws IOException {\n\t\treturn createLifecycle(getTestRequest(trustBuilder));\n\t}\n\n\tprivate Lifecycle createLifecycle(BuildRequest request) throws IOException {\n\t\tEphemeralBuilder builder = mockEphemeralBuilder();\n\t\treturn createLifecycle(request, builder);\n\t}\n\n\tprivate Lifecycle createLifecycle(boolean trustBuilder, String builderMetadata) throws IOException {\n\t\tEphemeralBuilder builder = mockEphemeralBuilder(builderMetadata);\n\t\treturn createLifecycle(getTestRequest(trustBuilder), builder);\n\t}\n\n\tprivate Lifecycle createLifecycle(BuildRequest request, ResolvedDockerHost dockerHost) throws IOException {\n\t\tEphemeralBuilder builder = mockEphemeralBuilder();\n\t\treturn new TestLifecycle(BuildLog.to(this.out), this.docker, dockerHost, request, builder);\n\t}\n\n\tprivate Lifecycle createLifecycle(BuildRequest request, EphemeralBuilder ephemeralBuilder) {\n\t\treturn new TestLifecycle(BuildLog.to(this.out), this.docker, null, request, ephemeralBuilder);\n\t}\n\n\tprivate EphemeralBuilder mockEphemeralBuilder() throws IOException {\n\t\treturn mockEphemeralBuilder(\"builder-metadata.json\");\n\t}\n\n\tprivate EphemeralBuilder mockEphemeralBuilder(String builderMetadata) throws IOException {\n\t\tEphemeralBuilder builder = mock(EphemeralBuilder.class);\n\t\tbyte[] metadataContent = FileCopyUtils.copyToByteArray(getClass().getResourceAsStream(builderMetadata));\n\t\tBuilderMetadata metadata = BuilderMetadata.fromJson(new String(metadataContent, StandardCharsets.UTF_8));\n\t\tgiven(builder.getName()).willReturn(ImageReference.of(\"pack.local/ephemeral-builder\"));\n\t\tgiven(builder.getBuilderMetadata()).willReturn(metadata);\n\t\treturn builder;\n\t}\n\n\tprivate Answer<ContainerReference> answerWithGeneratedContainerId() {\n\t\treturn (invocation) -> {\n\t\t\tContainerConfig config = invocation.getArgument(0, ContainerConfig.class);\n\t\t\tArrayNode command = getCommand(config);\n\t\t\tString name = command.get(0).asString().substring(1).replace('/', '-');\n\t\t\tthis.configs.put(name, config);\n\t\t\tif (invocation.getArguments().length > 2) {\n\t\t\t\tthis.content.put(name, invocation.getArgument(2, ContainerContent.class));\n\t\t\t}\n\t\t\treturn ContainerReference.of(name);\n\t\t};\n\t}\n\n\tprivate ArrayNode getCommand(ContainerConfig config) {\n\t\tJsonNode node = SharedJsonMapper.get().readTree(config.toString());\n\t\treturn (ArrayNode) node.at(\"/Cmd\");\n\t}\n\n\tprivate void assertPhaseWasRun(String name, IOConsumer<ContainerConfig> configConsumer) throws IOException {\n\t\tContainerReference containerReference = ContainerReference.of(\"cnb-lifecycle-\" + name);\n\t\tthen(this.docker.container()).should().start(containerReference);\n\t\tthen(this.docker.container()).should().logs(eq(containerReference), any());\n\t\tthen(this.docker.container()).should().remove(containerReference, true);\n\t\tContainerConfig containerConfig = this.configs.get(containerReference.toString());\n\t\tassertThat(containerConfig).isNotNull();\n\t\tconfigConsumer.accept(containerConfig);\n\t}\n\n\tprivate IOConsumer<ContainerConfig> withExpectedConfig(String name) {\n\t\treturn withExpectedConfig(name, false);\n\t}\n\n\tprivate IOConsumer<ContainerConfig> withExpectedConfig(String name, boolean expectSecurityOptAlways) {\n\t\treturn (config) -> {\n\t\t\ttry {\n\t\t\t\tInputStream in = getClass().getResourceAsStream(name);\n\t\t\t\tString jsonString = FileCopyUtils.copyToString(new InputStreamReader(in, StandardCharsets.UTF_8));\n\t\t\t\tJSONObject json = new JSONObject(jsonString);\n\t\t\t\tif (!expectSecurityOptAlways && Platform.isWindows()) {\n\t\t\t\t\tJSONObject hostConfig = json.getJSONObject(\"HostConfig\");\n\t\t\t\t\thostConfig.remove(\"SecurityOpt\");\n\t\t\t\t}\n\t\t\t\tJSONAssert.assertEquals(config.toString(), json, true);\n\t\t\t}\n\t\t\tcatch (JSONException ex) {\n\t\t\t\tthrow new IOException(ex);\n\t\t\t}\n\t\t};\n\t}\n\n\tstatic class TestLifecycle extends Lifecycle {\n\n\t\tTestLifecycle(BuildLog log, DockerApi docker, @Nullable ResolvedDockerHost dockerHost, BuildRequest request,\n\t\t\t\tEphemeralBuilder builder) {\n\t\t\tsuper(log, docker, dockerHost, request, builder);\n\t\t}\n\n\t\t@Override\n\t\tprotected VolumeName createRandomVolumeName(String prefix) {\n\t\t\treturn VolumeName.of(prefix + \"aaaaaaaaaa\");\n\t\t}\n\n\t}\n\n\tstatic class TestPrintStream extends PrintStream {\n\n\t\tTestPrintStream() {\n\t\t\tsuper(new ByteArrayOutputStream());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.out.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/LifecycleVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link LifecycleVersion}.\n *\n * @author Phillip Webb\n */\nclass LifecycleVersionTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid parseWhenValueIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LifecycleVersion.parse(null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid parseWhenTooLongThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LifecycleVersion.parse(\"v1.2.3.4\"))\n\t\t\t.withMessage(\"'value' [v1.2.3.4] must be a valid version number\");\n\t}\n\n\t@Test\n\tvoid parseWhenNonNumericThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LifecycleVersion.parse(\"v1.2.3a\"))\n\t\t\t.withMessage(\"'value' [v1.2.3a] must be a valid version number\");\n\t}\n\n\t@Test\n\tvoid compareTo() {\n\t\tLifecycleVersion v4 = LifecycleVersion.parse(\"0.0.4\");\n\t\tassertThat(LifecycleVersion.parse(\"0.0.3\")).isLessThan(v4);\n\t\tassertThat(LifecycleVersion.parse(\"0.0.4\")).isEqualByComparingTo(v4);\n\t\tassertThat(LifecycleVersion.parse(\"0.0.5\")).isGreaterThan(v4);\n\t}\n\n\t@Test\n\tvoid isEqualOrGreaterThan() {\n\t\tLifecycleVersion v4 = LifecycleVersion.parse(\"0.0.4\");\n\t\tassertThat(LifecycleVersion.parse(\"0.0.3\").isEqualOrGreaterThan(v4)).isFalse();\n\t\tassertThat(LifecycleVersion.parse(\"0.0.4\").isEqualOrGreaterThan(v4)).isTrue();\n\t\tassertThat(LifecycleVersion.parse(\"0.0.5\").isEqualOrGreaterThan(v4)).isTrue();\n\t}\n\n\t@Test\n\tvoid parseReturnsVersion() {\n\t\tassertThat(LifecycleVersion.parse(\"1.2.3\")).hasToString(\"v1.2.3\");\n\t\tassertThat(LifecycleVersion.parse(\"1.2\")).hasToString(\"v1.2.0\");\n\t\tassertThat(LifecycleVersion.parse(\"1\")).hasToString(\"v1.0.0\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PhaseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Binding;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerConfig.Update;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Phase}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n */\nclass PhaseTests {\n\n\tprivate static final String[] NO_ARGS = {};\n\n\t@Test\n\tvoid getNameReturnsName() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tassertThat(phase.getName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsName() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tassertThat(phase).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid applyUpdatesConfiguration() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\", NO_ARGS);\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithDaemonAccessUpdatesConfigurationWithRootUser() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tphase.withDaemonAccess();\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withUser(\"root\");\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\", \"-daemon\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithLogLevelArgAndVerboseLoggingUpdatesConfigurationWithLogLevel() {\n\t\tPhase phase = new Phase(\"test\", true);\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\", \"-log-level\", \"debug\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithLogLevelArgAndNonVerboseLoggingDoesNotUpdateLogLevel() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithArgsUpdatesConfigurationWithArguments() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tphase.withArgs(\"a\", \"b\", \"c\");\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\", \"a\", \"b\", \"c\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithBindsUpdatesConfigurationWithBinds() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tVolumeName volumeName = VolumeName.of(\"test\");\n\t\tphase.withBinding(Binding.from(volumeName, \"/test\"));\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).should().withBinding(Binding.from(volumeName, \"/test\"));\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithEnvUpdatesConfigurationWithEnv() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tphase.withEnv(\"name1\", \"value1\");\n\t\tphase.withEnv(\"name2\", \"value2\");\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).should().withEnv(\"name1\", \"value1\");\n\t\tthen(update).should().withEnv(\"name2\", \"value2\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithNetworkModeUpdatesConfigurationWithNetworkMode() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tphase.withNetworkMode(\"test\");\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\");\n\t\tthen(update).should().withNetworkMode(\"test\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenWithSecurityOptionsUpdatesConfigurationWithSecurityOptions() {\n\t\tPhase phase = new Phase(\"test\", false);\n\t\tphase.withSecurityOption(\"option1=value1\");\n\t\tphase.withSecurityOption(\"option2=value2\");\n\t\tUpdate update = mock(Update.class);\n\t\tphase.apply(update);\n\t\tthen(update).should().withCommand(\"/cnb/lifecycle/test\");\n\t\tthen(update).should().withLabel(\"author\", \"spring-boot\");\n\t\tthen(update).should().withSecurityOption(\"option1=value1\");\n\t\tthen(update).should().withSecurityOption(\"option2=value2\");\n\t\tthen(update).shouldHaveNoMoreInteractions();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/PrintStreamBuildLogTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStreamReader;\nimport java.io.PrintStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.ImagePlatform;\nimport org.springframework.boot.buildpack.platform.docker.LogUpdateEvent;\nimport org.springframework.boot.buildpack.platform.docker.TotalProgressEvent;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PrintStreamBuildLog}.\n *\n * @author Phillip Webb\n * @author Rafael Ceccone\n */\nclass PrintStreamBuildLogTests {\n\n\t@Test\n\tvoid printsExpectedOutput() throws Exception {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tPrintStreamBuildLog log = new PrintStreamBuildLog(out);\n\t\tBuildRequest request = mock(BuildRequest.class);\n\t\tImageReference name = ImageReference.of(\"my-app:latest\");\n\t\tImageReference builderImageReference = ImageReference.of(\"cnb/builder\");\n\t\tImagePlatform platform = ImagePlatform.of(\"linux/arm64/v1\");\n\t\tImage builderImage = mock(Image.class);\n\t\tgiven(builderImage.getDigests()).willReturn(Collections.singletonList(\"00000001\"));\n\t\tImageReference runImageReference = ImageReference.of(\"cnb/runner\");\n\t\tImage runImage = mock(Image.class);\n\t\tgiven(runImage.getDigests()).willReturn(Collections.singletonList(\"00000002\"));\n\t\tgiven(request.getName()).willReturn(name);\n\t\tImageReference tag = ImageReference.of(\"my-app:1.0\");\n\t\tgiven(request.getTags()).willReturn(Collections.singletonList(tag));\n\t\tlog.start(request);\n\t\tConsumer<TotalProgressEvent> pullBuildImageConsumer = log.pullingImage(builderImageReference, null,\n\t\t\t\tImageType.BUILDER);\n\t\tpullBuildImageConsumer.accept(new TotalProgressEvent(100));\n\t\tlog.pulledImage(builderImage, ImageType.BUILDER);\n\t\tConsumer<TotalProgressEvent> pullRunImageConsumer = log.pullingImage(runImageReference, platform,\n\t\t\t\tImageType.RUNNER);\n\t\tpullRunImageConsumer.accept(new TotalProgressEvent(100));\n\t\tlog.pulledImage(runImage, ImageType.RUNNER);\n\t\tlog.executingLifecycle(request, LifecycleVersion.parse(\"0.5\"), Cache.volume(VolumeName.of(\"pack-abc.cache\")));\n\t\tConsumer<LogUpdateEvent> phase1Consumer = log.runningPhase(request, \"alphabet\");\n\t\tphase1Consumer.accept(mockLogEvent(\"one\"));\n\t\tphase1Consumer.accept(mockLogEvent(\"two\"));\n\t\tphase1Consumer.accept(mockLogEvent(\"three\"));\n\t\tConsumer<LogUpdateEvent> phase2Consumer = log.runningPhase(request, \"basket\");\n\t\tphase2Consumer.accept(mockLogEvent(\"spring\"));\n\t\tphase2Consumer.accept(mockLogEvent(\"boot\"));\n\t\tlog.executedLifecycle(request);\n\t\tlog.taggedImage(tag);\n\t\tString expected = FileCopyUtils.copyToString(new InputStreamReader(\n\t\t\t\tgetClass().getResourceAsStream(\"print-stream-build-log.txt\"), StandardCharsets.UTF_8));\n\t\tassertThat(out.toString()).isEqualToIgnoringNewLines(expected);\n\t}\n\n\tprivate LogUpdateEvent mockLogEvent(String string) {\n\t\tLogUpdateEvent event = mock(LogUpdateEvent.class);\n\t\tgiven(event.toString()).willReturn(string);\n\t\treturn event;\n\t}\n\n\tstatic class TestPrintStream extends PrintStream {\n\n\t\tTestPrintStream() {\n\t\t\tsuper(new ByteArrayOutputStream());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.out.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/StackIdTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StackId}.\n *\n * @author Phillip Webb\n */\nclass StackIdTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromImageWhenImageIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> StackId.fromImage(null))\n\t\t\t.withMessage(\"'image' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromImageWhenLabelIsMissingHasNoId() {\n\t\tImage image = mock(Image.class);\n\t\tImageConfig imageConfig = mock(ImageConfig.class);\n\t\tgiven(image.getConfig()).willReturn(imageConfig);\n\t\tStackId stackId = StackId.fromImage(image);\n\t\tassertThat(stackId.hasId()).isFalse();\n\t}\n\n\t@Test\n\tvoid fromImageCreatesStackId() {\n\t\tImage image = mock(Image.class);\n\t\tImageConfig imageConfig = mock(ImageConfig.class);\n\t\tgiven(image.getConfig()).willReturn(imageConfig);\n\t\tgiven(imageConfig.getLabels()).willReturn(Collections.singletonMap(\"io.buildpacks.stack.id\", \"test\"));\n\t\tStackId stackId = StackId.fromImage(image);\n\t\tassertThat(stackId).hasToString(\"test\");\n\t\tassertThat(stackId.hasId()).isTrue();\n\t}\n\n\t@Test\n\tvoid ofCreatesStackId() {\n\t\tStackId stackId = StackId.of(\"test\");\n\t\tassertThat(stackId).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tStackId s1 = StackId.of(\"a\");\n\t\tStackId s2 = StackId.of(\"a\");\n\t\tStackId s3 = StackId.of(\"b\");\n\t\tassertThat(s1).hasSameHashCodeAs(s2);\n\t\tassertThat(s1).isEqualTo(s1).isEqualTo(s2).isNotEqualTo(s3);\n\t}\n\n\t@Test\n\tvoid toStringReturnsValue() {\n\t\tStackId stackId = StackId.of(\"test\");\n\t\tassertThat(stackId).hasToString(\"test\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/TarGzipBuildpackTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.File;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TarGzipBuildpack}.\n *\n * @author Scott Frederick\n */\nclass TarGzipBuildpackTests {\n\n\tprivate File buildpackDir;\n\n\tprivate TestTarGzip testTarGzip;\n\n\tprivate BuildpackResolverContext resolverContext;\n\n\t@BeforeEach\n\tvoid setUp(@TempDir File temp) {\n\t\tthis.buildpackDir = new File(temp, \"buildpack\");\n\t\tthis.buildpackDir.mkdirs();\n\t\tthis.testTarGzip = new TestTarGzip(this.buildpackDir);\n\t\tthis.resolverContext = mock(BuildpackResolverContext.class);\n\t}\n\n\t@Test\n\tvoid resolveWhenFilePathReturnsBuildpack() throws Exception {\n\t\tPath compressedArchive = this.testTarGzip.createArchive();\n\t\tBuildpackReference reference = BuildpackReference.of(compressedArchive.toString());\n\t\tBuildpack buildpack = TarGzipBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/buildpack1@0.0.1\");\n\t\tthis.testTarGzip.assertHasExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenFileUrlReturnsBuildpack() throws Exception {\n\t\tPath compressedArchive = this.testTarGzip.createArchive();\n\t\tBuildpackReference reference = BuildpackReference.of(compressedArchive.toUri().toString());\n\t\tBuildpack buildpack = TarGzipBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).as(\"Buildpack %s resolved from reference %s\", buildpack, reference).isNotNull();\n\t\tassertThat(buildpack.getCoordinates()).hasToString(\"example/buildpack1@0.0.1\");\n\t\tthis.testTarGzip.assertHasExpectedLayers(buildpack);\n\t}\n\n\t@Test\n\tvoid resolveWhenArchiveWithoutDescriptorThrowsException() throws Exception {\n\t\tPath compressedArchive = this.testTarGzip.createEmptyArchive();\n\t\tBuildpackReference reference = BuildpackReference.of(compressedArchive.toString());\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> TarGzipBuildpack.resolve(this.resolverContext, reference))\n\t\t\t.withMessageContaining(\"Buildpack descriptor 'buildpack.toml' is required\")\n\t\t\t.withMessageContaining(compressedArchive.toString());\n\t}\n\n\t@Test\n\tvoid resolveWhenArchiveWithDirectoryReturnsNull() {\n\t\tBuildpackReference reference = BuildpackReference.of(this.buildpackDir.getAbsolutePath());\n\t\tBuildpack buildpack = TarGzipBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenArchiveThatDoesNotExistReturnsNull() {\n\t\tBuildpackReference reference = BuildpackReference.of(\"/test/i/am/missing/buildpack.tar\");\n\t\tBuildpack buildpack = TarGzipBuildpack.resolve(this.resolverContext, reference);\n\t\tassertThat(buildpack).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/TestBuildpack.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.Layout;\nimport org.springframework.boot.buildpack.platform.io.Owner;\n\n/**\n * A test {@link Buildpack}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nclass TestBuildpack implements Buildpack {\n\n\tprivate final BuildpackCoordinates coordinates;\n\n\tTestBuildpack(String id, @Nullable String version) {\n\t\tthis.coordinates = BuildpackCoordinates.of(id, version);\n\t}\n\n\t@Override\n\tpublic BuildpackCoordinates getCoordinates() {\n\t\treturn this.coordinates;\n\t}\n\n\t@Override\n\tpublic void apply(IOConsumer<Layer> layers) throws IOException {\n\t\tlayers.accept(Layer.of(this::getContent));\n\t}\n\n\tprivate void getContent(Layout layout) throws IOException {\n\t\tString id = this.coordinates.getSanitizedId();\n\t\tString dir = \"/cnb/buildpacks/\" + id + \"/\" + this.coordinates.getVersion();\n\t\tlayout.file(dir + \"/buildpack.toml\", Owner.ROOT, Content.of(\"[test]\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/TestTarGzip.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.build;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;\n\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Utility to create test tgz files.\n *\n * @author Scott Frederick\n */\nclass TestTarGzip {\n\n\tprivate final File buildpackDir;\n\n\tTestTarGzip(File buildpackDir) {\n\t\tthis.buildpackDir = buildpackDir;\n\t}\n\n\tPath createArchive() throws Exception {\n\t\treturn createArchive(true);\n\t}\n\n\tPath createEmptyArchive() throws Exception {\n\t\treturn createArchive(false);\n\t}\n\n\tprivate Path createArchive(boolean addContent) throws Exception {\n\t\tPath path = Paths.get(this.buildpackDir.getAbsolutePath(), \"buildpack.tar\");\n\t\tPath archive = Files.createFile(path);\n\t\tif (addContent) {\n\t\t\twriteBuildpackContentToArchive(archive);\n\t\t}\n\t\treturn compressBuildpackArchive(archive);\n\t}\n\n\tprivate Path compressBuildpackArchive(Path archive) throws Exception {\n\t\tPath tgzPath = Paths.get(this.buildpackDir.getAbsolutePath(), \"buildpack.tgz\");\n\t\tFileCopyUtils.copy(Files.newInputStream(archive),\n\t\t\t\tnew GzipCompressorOutputStream(Files.newOutputStream(tgzPath)));\n\t\treturn tgzPath;\n\t}\n\n\tprivate void writeBuildpackContentToArchive(Path archive) throws Exception {\n\t\tStringBuilder buildpackToml = new StringBuilder();\n\t\tbuildpackToml.append(\"[buildpack]\\n\");\n\t\tbuildpackToml.append(\"id = \\\"example/buildpack1\\\"\\n\");\n\t\tbuildpackToml.append(\"version = \\\"0.0.1\\\"\\n\");\n\t\tbuildpackToml.append(\"name = \\\"Example buildpack\\\"\\n\");\n\t\tbuildpackToml.append(\"homepage = \\\"https://github.com/example/example-buildpack\\\"\\n\");\n\t\tbuildpackToml.append(\"[[stacks]]\\n\");\n\t\tbuildpackToml.append(\"id = \\\"io.buildpacks.stacks.bionic\\\"\\n\");\n\t\tString detectScript = \"\"\"\n\t\t\t\t#!/usr/bin/env bash\n\t\t\t\techo \"---> detect\"\n\t\t\t\t\"\"\";\n\t\tString buildScript = \"\"\"\n\t\t\t\t#!/usr/bin/env bash\n\t\t\t\techo \"---> build\"\n\t\t\t\t\"\"\";\n\t\ttry (TarArchiveOutputStream tar = new TarArchiveOutputStream(Files.newOutputStream(archive))) {\n\t\t\twriteEntry(tar, \"buildpack.toml\", buildpackToml.toString());\n\t\t\twriteEntry(tar, \"bin/\");\n\t\t\twriteEntry(tar, \"bin/detect\", detectScript);\n\t\t\twriteEntry(tar, \"bin/build\", buildScript);\n\t\t\ttar.finish();\n\t\t}\n\t}\n\n\tprivate void writeEntry(TarArchiveOutputStream tar, String entryName) throws IOException {\n\t\tTarArchiveEntry entry = new TarArchiveEntry(entryName);\n\t\ttar.putArchiveEntry(entry);\n\t\ttar.closeArchiveEntry();\n\t}\n\n\tprivate void writeEntry(TarArchiveOutputStream tar, String entryName, String content) throws IOException {\n\t\tTarArchiveEntry entry = new TarArchiveEntry(entryName);\n\t\tentry.setSize(content.length());\n\t\ttar.putArchiveEntry(entry);\n\t\tStreamUtils.copy(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)), tar);\n\t\ttar.closeArchiveEntry();\n\t}\n\n\tvoid assertHasExpectedLayers(Buildpack buildpack) throws IOException {\n\t\tList<ByteArrayOutputStream> layers = new ArrayList<>();\n\t\tbuildpack.apply((layer) -> {\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tlayer.writeTo(out);\n\t\t\tlayers.add(out);\n\t\t});\n\t\tassertThat(layers).hasSize(1);\n\t\tbyte[] content = layers.get(0).toByteArray();\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(content))) {\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/\");\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/buildpacks/\");\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/buildpacks/example_buildpack1/\");\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/buildpacks/example_buildpack1/0.0.1/\");\n\t\t\tassertThat(tar.getNextEntry().getName())\n\t\t\t\t.isEqualTo(\"cnb/buildpacks/example_buildpack1/0.0.1/buildpack.toml\");\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/buildpacks/example_buildpack1/0.0.1/bin/\");\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/buildpacks/example_buildpack1/0.0.1/bin/detect\");\n\t\t\tassertThat(tar.getNextEntry().getName()).isEqualTo(\"cnb/buildpacks/example_buildpack1/0.0.1/bin/build\");\n\t\t\tassertThat(tar.getNextEntry()).isNull();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ApiVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ApiVersion}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ApiVersionTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid parseWhenVersionIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ApiVersion.parse(null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid parseWhenVersionIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ApiVersion.parse(\"\"))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid parseWhenVersionDoesNotMatchPatternThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ApiVersion.parse(\"bad\"))\n\t\t\t.withMessage(\"'value' [bad] must contain a well formed version number\");\n\t}\n\n\t@Test\n\tvoid parseReturnsVersion() {\n\t\tApiVersion version = ApiVersion.parse(\"1.2\");\n\t\tassertThat(version.getMajor()).isOne();\n\t\tassertThat(version.getMinor()).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid supportsWhenSame() {\n\t\tassertThat(supports(\"0.0\", \"0.0\")).isTrue();\n\t\tassertThat(supports(\"0.1\", \"0.1\")).isTrue();\n\t\tassertThat(supports(\"1.0\", \"1.0\")).isTrue();\n\t\tassertThat(supports(\"1.1\", \"1.1\")).isTrue();\n\t}\n\n\t@Test\n\tvoid supportsWhenDifferentMajor() {\n\t\tassertThat(supports(\"0.0\", \"1.0\")).isFalse();\n\t\tassertThat(supports(\"1.0\", \"0.0\")).isFalse();\n\t\tassertThat(supports(\"1.0\", \"2.0\")).isFalse();\n\t\tassertThat(supports(\"2.0\", \"1.0\")).isFalse();\n\t\tassertThat(supports(\"1.1\", \"2.1\")).isFalse();\n\t\tassertThat(supports(\"2.1\", \"1.1\")).isFalse();\n\t}\n\n\t@Test\n\tvoid supportsWhenDifferentMinor() {\n\t\tassertThat(supports(\"1.2\", \"1.1\")).isTrue();\n\t\tassertThat(supports(\"1.2\", \"1.3\")).isFalse();\n\t}\n\n\t@Test\n\tvoid supportsWhenMajorZeroAndDifferentMinor() {\n\t\tassertThat(supports(\"0.2\", \"0.1\")).isFalse();\n\t\tassertThat(supports(\"0.2\", \"0.3\")).isFalse();\n\t}\n\n\t@Test\n\tvoid supportsAnyWhenOneMatches() {\n\t\tassertThat(supportsAny(\"0.2\", \"0.1\", \"0.2\")).isTrue();\n\t}\n\n\t@Test\n\tvoid supportsAnyWhenNoneMatch() {\n\t\tassertThat(supportsAny(\"0.2\", \"0.3\", \"0.4\")).isFalse();\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tassertThat(ApiVersion.parse(\"1.2\")).hasToString(\"1.2\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tApiVersion v12a = ApiVersion.parse(\"1.2\");\n\t\tApiVersion v12b = ApiVersion.parse(\"1.2\");\n\t\tApiVersion v13 = ApiVersion.parse(\"1.3\");\n\t\tassertThat(v12a).hasSameHashCodeAs(v12b);\n\t\tassertThat(v12a).isEqualTo(v12a).isEqualTo(v12b).isNotEqualTo(v13);\n\t}\n\n\t@Test\n\tvoid compareTo() {\n\t\tassertThat(ApiVersion.of(0, 0).compareTo(ApiVersion.of(0, 0))).isZero();\n\t\tassertThat(ApiVersion.of(0, 1).compareTo(ApiVersion.of(0, 1))).isZero();\n\t\tassertThat(ApiVersion.of(1, 0).compareTo(ApiVersion.of(1, 0))).isZero();\n\t\tassertThat(ApiVersion.of(0, 0).compareTo(ApiVersion.of(0, 1))).isLessThan(0);\n\t\tassertThat(ApiVersion.of(0, 1).compareTo(ApiVersion.of(0, 0))).isGreaterThan(0);\n\t\tassertThat(ApiVersion.of(1, 0).compareTo(ApiVersion.of(0, 1))).isGreaterThan(0);\n\t\tassertThat(ApiVersion.of(0, 1).compareTo(ApiVersion.of(1, 0))).isLessThan(0);\n\t}\n\n\tprivate boolean supports(String v1, String v2) {\n\t\treturn ApiVersion.parse(v1).supports(ApiVersion.parse(v2));\n\t}\n\n\tprivate boolean supportsAny(String v1, String... others) {\n\t\treturn ApiVersion.parse(v1)\n\t\t\t.supportsAny(Arrays.stream(others).map(ApiVersion::parse).toArray(ApiVersion[]::new));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerApiTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.message.BasicHeader;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.InOrder;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.Feature;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.ImageApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.SystemApi;\nimport org.springframework.boot.buildpack.platform.docker.DockerApi.VolumeApi;\nimport org.springframework.boot.buildpack.platform.docker.transport.HttpTransport;\nimport org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerConfig;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerContent;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerReference;\nimport org.springframework.boot.buildpack.platform.docker.type.ContainerStatus;\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageArchive;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.VolumeName;\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link DockerApi}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Rafael Ceccone\n * @author Moritz Halbritter\n */\n@ExtendWith({ MockitoExtension.class, OutputCaptureExtension.class })\nclass DockerApiTests {\n\n\tprivate static final String API_URL = \"/v\" + DockerApi.PREFERRED_API_VERSION;\n\n\tpublic static final String PING_URL = \"/_ping\";\n\n\tprivate static final String IMAGES_URL = API_URL + \"/images\";\n\n\tprivate static final String CONTAINERS_URL = API_URL + \"/containers\";\n\n\tprivate static final String VOLUMES_URL = API_URL + \"/volumes\";\n\n\tprivate static final ImagePlatform LINUX_ARM64_PLATFORM = ImagePlatform.of(\"linux/arm64/v1\");\n\n\tprivate static final String ENCODED_LINUX_ARM64_PLATFORM_JSON = URLEncoder.encode(LINUX_ARM64_PLATFORM.toJson(),\n\t\t\tStandardCharsets.UTF_8);\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate HttpTransport http;\n\n\tprivate DockerApi dockerApi;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.dockerApi = new DockerApi(this.http, DockerLog.toSystemOut());\n\t}\n\n\tprivate HttpTransport http() {\n\t\treturn this.http;\n\t}\n\n\tprivate Response emptyResponse() {\n\t\treturn responseOf(null);\n\t}\n\n\tprivate Response responseOf(@Nullable String name) {\n\t\treturn new Response() {\n\n\t\t\t@Override\n\t\t\tpublic void close() {\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic InputStream getContent() {\n\t\t\t\tif (name == null) {\n\t\t\t\t\treturn new ByteArrayInputStream(new byte[0]);\n\t\t\t\t}\n\t\t\t\treturn getClass().getResourceAsStream(name);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate Response responseWithHeaders(Header... headers) {\n\t\treturn new Response() {\n\n\t\t\t@Override\n\t\t\tpublic InputStream getContent() {\n\t\t\t\treturn new ByteArrayInputStream(new byte[0]);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Header getHeader(String name) {\n\t\t\t\treturn Arrays.stream(headers)\n\t\t\t\t\t.filter((header) -> header.getName().equals(name))\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.orElse(null);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void close() {\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Test\n\tvoid createDockerApi() {\n\t\tDockerApi api = new DockerApi();\n\t\tassertThat(api).isNotNull();\n\t}\n\n\t@Test\n\tvoid buildUrlWhenUnknownVersionUsesPreferredVersion() throws Exception {\n\t\tsetVersion(\"0.0\");\n\t\tassertThat(this.dockerApi.buildUrl(Feature.BASELINE, \"/test\"))\n\t\t\t.isEqualTo(URI.create(\"/v\" + DockerApi.PREFERRED_API_VERSION + \"/test\"));\n\t}\n\n\t@Test\n\tvoid buildUrlWhenVersionIsGreaterThanPreferredUsesPreferred() throws Exception {\n\t\tsetVersion(\"1000.0\");\n\t\tassertThat(this.dockerApi.buildUrl(Feature.BASELINE, \"/test\"))\n\t\t\t.isEqualTo(URI.create(\"/v\" + DockerApi.PREFERRED_API_VERSION + \"/test\"));\n\t}\n\n\t@Test\n\tvoid buildUrlWhenVersionIsEqualToPreferredUsesPreferred() throws Exception {\n\t\tsetVersion(DockerApi.PREFERRED_API_VERSION.toString());\n\t\tassertThat(this.dockerApi.buildUrl(Feature.BASELINE, \"/test\"))\n\t\t\t.isEqualTo(URI.create(\"/v\" + DockerApi.PREFERRED_API_VERSION + \"/test\"));\n\t}\n\n\t@Test\n\tvoid buildUrlWhenVersionIsLessThanPreferredAndGreaterThanMinimumUsesVersionVersion() throws Exception {\n\t\tsetVersion(\"1.48\");\n\t\tassertThat(this.dockerApi.buildUrl(Feature.BASELINE, \"/test\")).isEqualTo(URI.create(\"/v1.48/test\"));\n\t}\n\n\t@Test\n\tvoid buildUrlWhenVersionIsLessThanPreferredAndEqualToMinimumUsesVersionVersion() throws Exception {\n\t\tsetVersion(Feature.BASELINE.minimumVersion().toString());\n\t\tassertThat(this.dockerApi.buildUrl(Feature.BASELINE, \"/test\")).isEqualTo(URI.create(\"/v1.24/test\"));\n\t}\n\n\t@Test\n\tvoid buildUrlWhenVersionIsLessThanMinimumThrowsException() throws Exception {\n\t\tsetVersion(\"1.23\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.dockerApi.buildUrl(Feature.BASELINE, \"/test\"))\n\t\t\t.withMessage(\"Docker API version must be at least 1.24 \"\n\t\t\t\t\t+ \"to support this feature, but current API version is 1.23\");\n\t}\n\n\tprivate void setVersion(String version) throws IOException, URISyntaxException {\n\t\tgiven(http().head(eq(new URI(PING_URL))))\n\t\t\t.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, version)));\n\t}\n\n\t@Nested\n\tclass ImageDockerApiTests {\n\n\t\tprivate ImageApi api;\n\n\t\t@Mock\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate UpdateListener<PullImageUpdateEvent> pullListener;\n\n\t\t@Mock\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate UpdateListener<PushImageUpdateEvent> pushListener;\n\n\t\t@Mock\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate UpdateListener<LoadImageUpdateEvent> loadListener;\n\n\t\t@Captor\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ArgumentCaptor<IOConsumer<OutputStream>> writer;\n\n\t\t@BeforeEach\n\t\tvoid setup() {\n\t\t\tthis.api = DockerApiTests.this.dockerApi.image();\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid pullWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.pull(null, null, this.pullListener))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid pullWhenListenerIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> this.api.pull(ImageReference.of(\"ubuntu\"), null, null))\n\t\t\t\t.withMessage(\"'listener' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid pullPullsImageAndProducesEvents() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI createUri = new URI(IMAGES_URL + \"/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder%3Abase\");\n\t\t\tURI imageUri = new URI(IMAGES_URL + \"/docker.io/paketobuildpacks/builder:base/json\");\n\t\t\tgiven(http().post(eq(createUri), isNull())).willReturn(responseOf(\"pull-stream.json\"));\n\t\t\tgiven(http().get(imageUri)).willReturn(responseOf(\"type/image.json\"));\n\t\t\tImage image = this.api.pull(reference, null, this.pullListener);\n\t\t\tassertThat(image.getLayers()).hasSize(46);\n\t\t\tInOrder ordered = inOrder(this.pullListener);\n\t\t\tordered.verify(this.pullListener).onStart();\n\t\t\tordered.verify(this.pullListener, times(595)).onUpdate(any());\n\t\t\tordered.verify(this.pullListener).onFinish();\n\t\t}\n\n\t\t@Test\n\t\tvoid pullWithRegistryAuthPullsImageAndProducesEvents() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI createUri = new URI(IMAGES_URL + \"/create?fromImage=docker.io%2Fpaketobuildpacks%2Fbuilder%3Abase\");\n\t\t\tURI imageUri = new URI(IMAGES_URL + \"/docker.io/paketobuildpacks/builder:base/json\");\n\t\t\tgiven(http().post(eq(createUri), eq(\"auth token\"))).willReturn(responseOf(\"pull-stream.json\"));\n\t\t\tgiven(http().get(imageUri)).willReturn(responseOf(\"type/image.json\"));\n\t\t\tImage image = this.api.pull(reference, null, this.pullListener, \"auth token\");\n\t\t\tassertThat(image.getLayers()).hasSize(46);\n\t\t\tInOrder ordered = inOrder(this.pullListener);\n\t\t\tordered.verify(this.pullListener).onStart();\n\t\t\tordered.verify(this.pullListener, times(595)).onUpdate(any());\n\t\t\tordered.verify(this.pullListener).onFinish();\n\t\t}\n\n\t\t@Test\n\t\tvoid pullWithPlatformPullsImageAndProducesEvents() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"gcr.io/paketo-buildpacks/builder:base\");\n\t\t\tURI createUri = new URI(\n\t\t\t\t\t\"/v1.49/images/create?fromImage=gcr.io%2Fpaketo-buildpacks%2Fbuilder%3Abase&platform=linux%2Farm64%2Fv1\");\n\t\t\tURI imageUri = new URI(\"/v1.49/images/gcr.io/paketo-buildpacks/builder:base/json?platform=\"\n\t\t\t\t\t+ ENCODED_LINUX_ARM64_PLATFORM_JSON);\n\t\t\tsetVersion(\"1.49\");\n\t\t\tgiven(http().post(eq(createUri), isNull())).willReturn(responseOf(\"pull-stream.json\"));\n\t\t\tgiven(http().get(imageUri)).willReturn(responseOf(\"type/image.json\"));\n\t\t\tImage image = this.api.pull(reference, LINUX_ARM64_PLATFORM, this.pullListener);\n\t\t\tassertThat(image.getLayers()).hasSize(46);\n\t\t\tInOrder ordered = inOrder(this.pullListener);\n\t\t\tordered.verify(this.pullListener).onStart();\n\t\t\tordered.verify(this.pullListener, times(595)).onUpdate(any());\n\t\t\tordered.verify(this.pullListener).onFinish();\n\t\t}\n\n\t\t@Test\n\t\tvoid pullWithPlatformAndInsufficientApiVersionThrowsException() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"gcr.io/paketo-buildpacks/builder:base\");\n\t\t\tImagePlatform platform = ImagePlatform.of(\"linux/arm64/v1\");\n\t\t\tsetVersion(\"1.24\");\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> this.api.pull(reference, platform, this.pullListener))\n\t\t\t\t.withMessageContaining(\"must be at least 1.41\")\n\t\t\t\t.withMessageContaining(\"current API version is 1.24\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid pushWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.push(null, this.pushListener, null))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid pushWhenListenerIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> this.api.push(ImageReference.of(\"ubuntu\"), null, null))\n\t\t\t\t.withMessage(\"'listener' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid pushPushesImageAndProducesEvents() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"localhost:5000/ubuntu\");\n\t\t\tURI pushUri = new URI(IMAGES_URL + \"/localhost:5000/ubuntu/push\");\n\t\t\tgiven(http().post(pushUri, \"auth token\")).willReturn(responseOf(\"push-stream.json\"));\n\t\t\tthis.api.push(reference, this.pushListener, \"auth token\");\n\t\t\tInOrder ordered = inOrder(this.pushListener);\n\t\t\tordered.verify(this.pushListener).onStart();\n\t\t\tordered.verify(this.pushListener, times(44)).onUpdate(any());\n\t\t\tordered.verify(this.pushListener).onFinish();\n\t\t}\n\n\t\t@Test\n\t\tvoid pushWithErrorInStreamThrowsException() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"localhost:5000/ubuntu\");\n\t\t\tURI pushUri = new URI(IMAGES_URL + \"/localhost:5000/ubuntu/push\");\n\t\t\tgiven(http().post(pushUri, \"auth token\")).willReturn(responseOf(\"push-stream-with-error.json\"));\n\t\t\tassertThatIllegalStateException()\n\t\t\t\t.isThrownBy(() -> this.api.push(reference, this.pushListener, \"auth token\"))\n\t\t\t\t.withMessageContaining(\"test message\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid loadWhenArchiveIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.load(null, UpdateListener.none()))\n\t\t\t\t.withMessage(\"'archive' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid loadWhenListenerIsNullThrowsException() {\n\t\t\tImageArchive archive = mock(ImageArchive.class);\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.load(archive, null))\n\t\t\t\t.withMessage(\"'listener' must not be null\");\n\t\t}\n\n\t\t@Test // gh-23130\n\t\tvoid loadWithEmptyResponseThrowsException() throws Exception {\n\t\t\tImage image = Image.of(getClass().getResourceAsStream(\"type/image.json\"));\n\t\t\tImageArchive archive = ImageArchive.from(image);\n\t\t\tURI loadUri = new URI(IMAGES_URL + \"/load\");\n\t\t\tgiven(http().post(eq(loadUri), eq(\"application/x-tar\"), any())).willReturn(emptyResponse());\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> this.api.load(archive, this.loadListener))\n\t\t\t\t.withMessageContaining(\"Invalid response received\");\n\t\t}\n\n\t\t@Test // gh-31243\n\t\tvoid loadWithErrorResponseThrowsException() throws Exception {\n\t\t\tImage image = Image.of(getClass().getResourceAsStream(\"type/image.json\"));\n\t\t\tImageArchive archive = ImageArchive.from(image);\n\t\t\tURI loadUri = new URI(IMAGES_URL + \"/load\");\n\t\t\tgiven(http().post(eq(loadUri), eq(\"application/x-tar\"), any())).willReturn(responseOf(\"load-error.json\"));\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> this.api.load(archive, this.loadListener))\n\t\t\t\t.withMessageContaining(\"Error response received\");\n\t\t}\n\n\t\t@Test\n\t\tvoid loadLoadsImage() throws Exception {\n\t\t\tImage image = Image.of(getClass().getResourceAsStream(\"type/image.json\"));\n\t\t\tImageArchive archive = ImageArchive.from(image);\n\t\t\tURI loadUri = new URI(IMAGES_URL + \"/load\");\n\t\t\tgiven(http().post(eq(loadUri), eq(\"application/x-tar\"), any())).willReturn(responseOf(\"load-stream.json\"));\n\t\t\tthis.api.load(archive, this.loadListener);\n\t\t\tInOrder ordered = inOrder(this.loadListener);\n\t\t\tordered.verify(this.loadListener).onStart();\n\t\t\tordered.verify(this.loadListener).onUpdate(any());\n\t\t\tordered.verify(this.loadListener).onFinish();\n\t\t\tthen(http()).should().post(any(), any(), this.writer.capture());\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tthis.writer.getValue().accept(out);\n\t\t\tassertThat(out.toByteArray()).hasSizeGreaterThan(21000);\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid removeWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.remove(null, true))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid removeRemovesContainer() throws Exception {\n\t\t\tImageReference reference = ImageReference\n\t\t\t\t.of(\"ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\t\tURI removeUri = new URI(IMAGES_URL\n\t\t\t\t\t+ \"/docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\t\tgiven(http().delete(removeUri)).willReturn(emptyResponse());\n\t\t\tthis.api.remove(reference, false);\n\t\t\tthen(http()).should().delete(removeUri);\n\t\t}\n\n\t\t@Test\n\t\tvoid removeWhenForceIsTrueRemovesContainer() throws Exception {\n\t\t\tImageReference reference = ImageReference\n\t\t\t\t.of(\"ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\t\tURI removeUri = new URI(IMAGES_URL\n\t\t\t\t\t+ \"/docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d?force=1\");\n\t\t\tgiven(http().delete(removeUri)).willReturn(emptyResponse());\n\t\t\tthis.api.remove(reference, true);\n\t\t\tthen(http()).should().delete(removeUri);\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid inspectWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.inspect(null))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid inspectInspectImage() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI imageUri = new URI(IMAGES_URL + \"/docker.io/paketobuildpacks/builder:base/json\");\n\t\t\tgiven(http().get(imageUri)).willReturn(responseOf(\"type/image.json\"));\n\t\t\tImage image = this.api.inspect(reference);\n\t\t\tassertThat(image.getArchitecture()).isEqualTo(\"amd64\");\n\t\t\tassertThat(image.getLayers()).hasSize(46);\n\t\t}\n\n\t\t@Test\n\t\tvoid inspectWithPlatformWhenSupportedVersionInspectImage() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI imageUri = new URI(\"/v1.49/images/docker.io/paketobuildpacks/builder:base/json?platform=\"\n\t\t\t\t\t+ ENCODED_LINUX_ARM64_PLATFORM_JSON);\n\t\t\tsetVersion(\"1.49\");\n\t\t\tgiven(http().get(imageUri)).willReturn(responseOf(\"type/image-platform.json\"));\n\t\t\tImage image = this.api.inspect(reference, LINUX_ARM64_PLATFORM);\n\t\t\tassertThat(image.getArchitecture()).isEqualTo(\"arm64\");\n\t\t\tassertThat(image.getLayers()).hasSize(2);\n\t\t}\n\n\t\t@Test\n\t\tvoid inspectWithPlatformWhenOldVersionInspectImage() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI imageUri = new URI(\"/v1.48/images/docker.io/paketobuildpacks/builder:base/json\");\n\t\t\tsetVersion(\"1.48\");\n\t\t\tgiven(http().get(imageUri)).willReturn(responseOf(\"type/image.json\"));\n\t\t\tImage image = this.api.inspect(reference, LINUX_ARM64_PLATFORM);\n\t\t\tassertThat(image.getArchitecture()).isEqualTo(\"amd64\");\n\t\t\tassertThat(image.getLayers()).hasSize(46);\n\t\t}\n\n\t\t@Test\n\t\tvoid exportLayersExportsLayerTars() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI exportUri = new URI(IMAGES_URL + \"/docker.io/paketobuildpacks/builder:base/get\");\n\t\t\tgiven(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf(\"export.tar\"));\n\t\t\tMultiValueMap<String, String> contents = new LinkedMultiValueMap<>();\n\t\t\tthis.api.exportLayers(reference, (name, archive) -> {\n\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\tarchive.writeTo(out);\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(\n\t\t\t\t\t\tnew ByteArrayInputStream(out.toByteArray()))) {\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tcontents.add(name, entry.getName());\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tassertThat(contents).hasSize(3)\n\t\t\t\t.containsKeys(\"70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar\",\n\t\t\t\t\t\t\"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar\",\n\t\t\t\t\t\t\"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar\");\n\t\t\tassertThat(contents.get(\"70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/order.toml\");\n\t\t\tassertThat(contents.get(\"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/stack.toml\");\n\t\t}\n\n\t\t@Test\n\t\tvoid exportLayersExportsLayerTarsWithPlatformWhenSupportedVersion() throws Exception {\n\t\t\tsetVersion(\"1.48\");\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI exportUri = new URI(\"/v1.48/images/docker.io/paketobuildpacks/builder:base/get?platform=\"\n\t\t\t\t\t+ ENCODED_LINUX_ARM64_PLATFORM_JSON);\n\t\t\tgiven(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf(\"export.tar\"));\n\t\t\tMultiValueMap<String, String> contents = new LinkedMultiValueMap<>();\n\t\t\tthis.api.exportLayers(reference, LINUX_ARM64_PLATFORM, (name, archive) -> {\n\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\tarchive.writeTo(out);\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(\n\t\t\t\t\t\tnew ByteArrayInputStream(out.toByteArray()))) {\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tcontents.add(name, entry.getName());\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tassertThat(contents).hasSize(3)\n\t\t\t\t.containsKeys(\"70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar\",\n\t\t\t\t\t\t\"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar\",\n\t\t\t\t\t\t\"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar\");\n\t\t\tassertThat(contents.get(\"70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/order.toml\");\n\t\t\tassertThat(contents.get(\"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/stack.toml\");\n\t\t}\n\n\t\t@Test\n\t\tvoid exportLayersExportsLayerTarsWithPlatformWhenOldVersionInspectImage() throws Exception {\n\t\t\tsetVersion(\"1.47\");\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI exportUri = new URI(\"/v1.47/images/docker.io/paketobuildpacks/builder:base/get\");\n\t\t\tgiven(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf(\"export.tar\"));\n\t\t\tMultiValueMap<String, String> contents = new LinkedMultiValueMap<>();\n\t\t\tthis.api.exportLayers(reference, LINUX_ARM64_PLATFORM, (name, archive) -> {\n\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\tarchive.writeTo(out);\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(\n\t\t\t\t\t\tnew ByteArrayInputStream(out.toByteArray()))) {\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tcontents.add(name, entry.getName());\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tassertThat(contents).hasSize(3)\n\t\t\t\t.containsKeys(\"70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar\",\n\t\t\t\t\t\t\"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar\",\n\t\t\t\t\t\t\"a69532b5b92bb891fbd9fa1a6b3af9087ea7050255f59ba61a796f8555ecd783/layer.tar\");\n\t\t\tassertThat(contents.get(\"70bb7a3115f3d5c01099852112c7e05bf593789e510468edb06b6a9a11fa3b73/layer.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/order.toml\");\n\t\t\tassertThat(contents.get(\"74a9a50ece13c025cf10e9110d9ddc86c995079c34e2a22a28d1a3d523222c6e/layer.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/stack.toml\");\n\t\t}\n\n\t\t@Test\n\t\tvoid exportLayersWithSymlinksExportsLayerTars() throws Exception {\n\t\t\tImageReference reference = ImageReference.of(\"docker.io/paketobuildpacks/builder:base\");\n\t\t\tURI exportUri = new URI(IMAGES_URL + \"/docker.io/paketobuildpacks/builder:base/get\");\n\t\t\tgiven(DockerApiTests.this.http.get(exportUri)).willReturn(responseOf(\"export-symlinks.tar\"));\n\t\t\tMultiValueMap<String, String> contents = new LinkedMultiValueMap<>();\n\t\t\tthis.api.exportLayers(reference, (name, archive) -> {\n\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\tarchive.writeTo(out);\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(\n\t\t\t\t\t\tnew ByteArrayInputStream(out.toByteArray()))) {\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tcontents.add(name, entry.getName());\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tassertThat(contents).hasSize(3)\n\t\t\t\t.containsKeys(\"6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a.tar\",\n\t\t\t\t\t\t\"762e198f655bc2580ef3e56b538810fd2b9981bd707f8a44c70344b58f9aee68.tar\",\n\t\t\t\t\t\t\"d3cc975ad97fdfbb73d9daf157e7f658d6117249fd9c237e3856ad173c87e1d2.tar\");\n\t\t\tassertThat(contents.get(\"d3cc975ad97fdfbb73d9daf157e7f658d6117249fd9c237e3856ad173c87e1d2.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/order.toml\");\n\t\t\tassertThat(contents.get(\"762e198f655bc2580ef3e56b538810fd2b9981bd707f8a44c70344b58f9aee68.tar\"))\n\t\t\t\t.containsExactly(\"/cnb/stack.toml\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid tagWhenReferenceIsNullThrowsException() {\n\t\t\tImageReference tag = ImageReference.of(\"localhost:5000/ubuntu\");\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.tag(null, tag))\n\t\t\t\t.withMessage(\"'sourceReference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid tagWhenTargetIsNullThrowsException() {\n\t\t\tImageReference reference = ImageReference.of(\"localhost:5000/ubuntu\");\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.tag(reference, null))\n\t\t\t\t.withMessage(\"'targetReference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid tagTagsImage() throws Exception {\n\t\t\tImageReference sourceReference = ImageReference.of(\"localhost:5000/ubuntu\");\n\t\t\tImageReference targetReference = ImageReference.of(\"localhost:5000/ubuntu:tagged\");\n\t\t\tURI tagURI = new URI(IMAGES_URL + \"/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu&tag=tagged\");\n\t\t\tgiven(http().post(tagURI)).willReturn(emptyResponse());\n\t\t\tthis.api.tag(sourceReference, targetReference);\n\t\t\tthen(http()).should().post(tagURI);\n\t\t}\n\n\t\t@Test\n\t\tvoid tagRenamesImage() throws Exception {\n\t\t\tImageReference sourceReference = ImageReference.of(\"localhost:5000/ubuntu\");\n\t\t\tImageReference targetReference = ImageReference.of(\"localhost:5000/ubuntu-2\");\n\t\t\tURI tagURI = new URI(IMAGES_URL + \"/localhost:5000/ubuntu/tag?repo=localhost%3A5000%2Fubuntu-2\");\n\t\t\tgiven(http().post(tagURI)).willReturn(emptyResponse());\n\t\t\tthis.api.tag(sourceReference, targetReference);\n\t\t\tthen(http()).should().post(tagURI);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ContainerDockerApiTests {\n\n\t\tprivate ContainerApi api;\n\n\t\t@Captor\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ArgumentCaptor<IOConsumer<OutputStream>> writer;\n\n\t\t@Mock\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate UpdateListener<LogUpdateEvent> logListener;\n\n\t\t@BeforeEach\n\t\tvoid setup() {\n\t\t\tthis.api = DockerApiTests.this.dockerApi.container();\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid createWhenConfigIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.create(null, null))\n\t\t\t\t.withMessage(\"'config' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid createCreatesContainer() throws Exception {\n\t\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\t\tContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand(\"/bin/bash\"));\n\t\t\tURI createUri = new URI(CONTAINERS_URL + \"/create\");\n\t\t\tgiven(http().post(eq(createUri), eq(\"application/json\"), any()))\n\t\t\t\t.willReturn(responseOf(\"create-container-response.json\"));\n\t\t\tContainerReference containerReference = this.api.create(config, null);\n\t\t\tassertThat(containerReference).hasToString(\"e90e34656806\");\n\t\t\tthen(http()).should().post(any(), any(), this.writer.capture());\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tthis.writer.getValue().accept(out);\n\t\t\tassertThat(out.toByteArray()).hasSize(config.toString().length());\n\t\t}\n\n\t\t@Test\n\t\tvoid createWhenHasContentContainerWithContent() throws Exception {\n\t\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\t\tContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand(\"/bin/bash\"));\n\t\t\tTarArchive archive = TarArchive.of((layout) -> {\n\t\t\t\tlayout.directory(\"/test\", Owner.ROOT);\n\t\t\t\tlayout.file(\"/test/file\", Owner.ROOT, Content.of(\"test\"));\n\t\t\t});\n\t\t\tContainerContent content = ContainerContent.of(archive);\n\t\t\tURI createUri = new URI(CONTAINERS_URL + \"/create\");\n\t\t\tgiven(http().post(eq(createUri), eq(\"application/json\"), any()))\n\t\t\t\t.willReturn(responseOf(\"create-container-response.json\"));\n\t\t\tURI uploadUri = new URI(CONTAINERS_URL + \"/e90e34656806/archive?path=%2F\");\n\t\t\tgiven(http().put(eq(uploadUri), eq(\"application/x-tar\"), any())).willReturn(emptyResponse());\n\t\t\tContainerReference containerReference = this.api.create(config, null, content);\n\t\t\tassertThat(containerReference).hasToString(\"e90e34656806\");\n\t\t\tthen(http()).should().post(any(), any(), this.writer.capture());\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tthis.writer.getValue().accept(out);\n\t\t\tassertThat(out.toByteArray()).hasSize(config.toString().length());\n\t\t\tthen(http()).should().put(any(), any(), this.writer.capture());\n\t\t\tthis.writer.getValue().accept(out);\n\t\t\tassertThat(out.toByteArray()).hasSizeGreaterThan(2000);\n\t\t}\n\n\t\t@Test\n\t\tvoid createWithPlatformCreatesContainer() throws Exception {\n\t\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\t\tContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand(\"/bin/bash\"));\n\t\t\tImagePlatform platform = ImagePlatform.of(\"linux/arm64/v1\");\n\t\t\tsetVersion(\"1.41\");\n\t\t\tURI createUri = new URI(\"/v1.41/containers/create?platform=linux%2Farm64%2Fv1\");\n\t\t\tgiven(http().post(eq(createUri), eq(\"application/json\"), any()))\n\t\t\t\t.willReturn(responseOf(\"create-container-response.json\"));\n\t\t\tContainerReference containerReference = this.api.create(config, platform);\n\t\t\tassertThat(containerReference).hasToString(\"e90e34656806\");\n\t\t\tthen(http()).should().post(any(), any(), this.writer.capture());\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tthis.writer.getValue().accept(out);\n\t\t\tassertThat(out.toByteArray()).hasSize(config.toString().length());\n\t\t}\n\n\t\t@Test\n\t\tvoid createWithPlatformAndUnknownApiVersionAttemptsCreate() throws Exception {\n\t\t\tcreateWithPlatform(null);\n\t\t}\n\n\t\tprivate void createWithPlatform(@Nullable String apiVersion) throws IOException, URISyntaxException {\n\t\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\t\tContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand(\"/bin/bash\"));\n\t\t\tImagePlatform platform = ImagePlatform.of(\"linux/arm64/v1\");\n\t\t\tURI createUri = new URI(CONTAINERS_URL + \"/create?platform=linux%2Farm64%2Fv1\");\n\t\t\tgiven(http().post(eq(createUri), eq(\"application/json\"), any()))\n\t\t\t\t.willReturn(responseOf(\"create-container-response.json\"));\n\t\t\tContainerReference containerReference = this.api.create(config, platform);\n\t\t\tassertThat(containerReference).hasToString(\"e90e34656806\");\n\t\t\tthen(http()).should().post(any(), any(), this.writer.capture());\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tthis.writer.getValue().accept(out);\n\t\t\tassertThat(out.toByteArray()).hasSize(config.toString().length());\n\t\t}\n\n\t\t@Test\n\t\tvoid createWithPlatformAndKnownInsufficientApiVersionThrowsException() throws Exception {\n\t\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\t\tContainerConfig config = ContainerConfig.of(imageReference, (update) -> update.withCommand(\"/bin/bash\"));\n\t\t\tImagePlatform platform = ImagePlatform.of(\"linux/arm64/v1\");\n\t\t\tsetVersion(\"1.24\");\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> this.api.create(config, platform))\n\t\t\t\t.withMessageContaining(\"must be at least 1.41\")\n\t\t\t\t.withMessageContaining(\"current API version is 1.24\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid startWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.start(null))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid startStartsContainer() throws Exception {\n\t\t\tContainerReference reference = ContainerReference.of(\"e90e34656806\");\n\t\t\tURI startContainerUri = new URI(CONTAINERS_URL + \"/e90e34656806/start\");\n\t\t\tgiven(http().post(startContainerUri)).willReturn(emptyResponse());\n\t\t\tthis.api.start(reference);\n\t\t\tthen(http()).should().post(startContainerUri);\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid logsWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.logs(null, UpdateListener.none()))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid logsWhenListenerIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> this.api.logs(ContainerReference.of(\"e90e34656806\"), null))\n\t\t\t\t.withMessage(\"'listener' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid logsProducesEvents() throws Exception {\n\t\t\tContainerReference reference = ContainerReference.of(\"e90e34656806\");\n\t\t\tURI logsUri = new URI(CONTAINERS_URL + \"/e90e34656806/logs?stdout=1&stderr=1&follow=1\");\n\t\t\tgiven(http().get(logsUri)).willReturn(responseOf(\"log-update-event.stream\"));\n\t\t\tthis.api.logs(reference, this.logListener);\n\t\t\tInOrder ordered = inOrder(this.logListener);\n\t\t\tordered.verify(this.logListener).onStart();\n\t\t\tordered.verify(this.logListener, times(7)).onUpdate(any());\n\t\t\tordered.verify(this.logListener).onFinish();\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid waitWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.wait(null))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid waitReturnsStatus() throws Exception {\n\t\t\tContainerReference reference = ContainerReference.of(\"e90e34656806\");\n\t\t\tURI waitUri = new URI(CONTAINERS_URL + \"/e90e34656806/wait\");\n\t\t\tgiven(http().post(waitUri)).willReturn(responseOf(\"container-wait-response.json\"));\n\t\t\tContainerStatus status = this.api.wait(reference);\n\t\t\tassertThat(status.getStatusCode()).isOne();\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid removeWhenReferenceIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.remove(null, true))\n\t\t\t\t.withMessage(\"'reference' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid removeRemovesContainer() throws Exception {\n\t\t\tContainerReference reference = ContainerReference.of(\"e90e34656806\");\n\t\t\tURI removeUri = new URI(CONTAINERS_URL + \"/e90e34656806\");\n\t\t\tgiven(http().delete(removeUri)).willReturn(emptyResponse());\n\t\t\tthis.api.remove(reference, false);\n\t\t\tthen(http()).should().delete(removeUri);\n\t\t}\n\n\t\t@Test\n\t\tvoid removeWhenForceIsTrueRemovesContainer() throws Exception {\n\t\t\tContainerReference reference = ContainerReference.of(\"e90e34656806\");\n\t\t\tURI removeUri = new URI(CONTAINERS_URL + \"/e90e34656806?force=1\");\n\t\t\tgiven(http().delete(removeUri)).willReturn(emptyResponse());\n\t\t\tthis.api.remove(reference, true);\n\t\t\tthen(http()).should().delete(removeUri);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass VolumeDockerApiTests {\n\n\t\tprivate VolumeApi api;\n\n\t\t@BeforeEach\n\t\tvoid setup() {\n\t\t\tthis.api = DockerApiTests.this.dockerApi.volume();\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid deleteWhenNameIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.api.delete(null, false))\n\t\t\t\t.withMessage(\"'name' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid deleteDeletesContainer() throws Exception {\n\t\t\tVolumeName name = VolumeName.of(\"test\");\n\t\t\tURI removeUri = new URI(VOLUMES_URL + \"/test\");\n\t\t\tgiven(http().delete(removeUri)).willReturn(emptyResponse());\n\t\t\tthis.api.delete(name, false);\n\t\t\tthen(http()).should().delete(removeUri);\n\t\t}\n\n\t\t@Test\n\t\tvoid deleteWhenForceIsTrueDeletesContainer() throws Exception {\n\t\t\tVolumeName name = VolumeName.of(\"test\");\n\t\t\tURI removeUri = new URI(VOLUMES_URL + \"/test?force=1\");\n\t\t\tgiven(http().delete(removeUri)).willReturn(emptyResponse());\n\t\t\tthis.api.delete(name, true);\n\t\t\tthen(http()).should().delete(removeUri);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass SystemDockerApiTests {\n\n\t\tprivate SystemApi api;\n\n\t\t@BeforeEach\n\t\tvoid setup() {\n\t\t\tthis.api = DockerApiTests.this.dockerApi.system();\n\t\t}\n\n\t\t@Test\n\t\tvoid getApiVersionWithVersionHeaderReturnsVersion() throws Exception {\n\t\t\tgiven(http().head(eq(new URI(PING_URL))))\n\t\t\t\t.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, \"1.44\")));\n\t\t\tassertThat(this.api.getApiVersion()).isEqualTo(ApiVersion.of(1, 44));\n\t\t}\n\n\t\t@Test\n\t\tvoid getApiVersionWithEmptyVersionHeaderReturnsUnknownVersion() throws Exception {\n\t\t\tgiven(http().head(eq(new URI(PING_URL))))\n\t\t\t\t.willReturn(responseWithHeaders(new BasicHeader(DockerApi.API_VERSION_HEADER_NAME, \"\")));\n\t\t\tassertThat(this.api.getApiVersion()).isEqualTo(DockerApi.UNKNOWN_API_VERSION);\n\t\t}\n\n\t\t@Test\n\t\tvoid getApiVersionWithNoVersionHeaderReturnsUnknownVersion() throws Exception {\n\t\t\tgiven(http().head(eq(new URI(PING_URL)))).willReturn(emptyResponse());\n\t\t\tassertThat(this.api.getApiVersion()).isEqualTo(DockerApi.UNKNOWN_API_VERSION);\n\t\t}\n\n\t\t@Test\n\t\tvoid getApiVersionWithExceptionReturnsUnknownVersion(CapturedOutput output) throws Exception {\n\t\t\tgiven(http().head(eq(new URI(PING_URL)))).willThrow(new IOException(\"simulated error\"));\n\t\t\tassertThat(this.api.getApiVersion()).isEqualTo(DockerApi.UNKNOWN_API_VERSION);\n\t\t\tassertThat(output).contains(\"Warning: Failed to determine Docker API version: simulated error\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/DockerLogTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerLog}.\n *\n * @author Dmytro nosan\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass DockerLogTests {\n\n\t@Test\n\tvoid toSystemOutPrintsToSystemOut(CapturedOutput output) {\n\t\tDockerLog logger = DockerLog.toSystemOut();\n\t\tlogger.log(\"Hello world\");\n\t\tassertThat(output.getErr()).isEmpty();\n\t\tassertThat(output.getOut()).contains(\"Hello world\");\n\t}\n\n\t@Test\n\tvoid toPrintsToOutput(CapturedOutput output) {\n\t\tDockerLog logger = DockerLog.to(System.err);\n\t\tlogger.log(\"Hello world\");\n\t\tassertThat(output.getOut()).isEmpty();\n\t\tassertThat(output.getErr()).contains(\"Hello world\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ExportedImageTarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.io.TarArchive.Compression;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ExportedImageTar}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ExportedImageTarTests {\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"export-docker-desktop.tar\", \"export-docker-desktop-containerd.tar\",\n\t\t\t\"export-docker-desktop-containerd-manifest-list.tar\", \"export-docker-engine.tar\", \"export-podman.tar\",\n\t\t\t\"export-docker-desktop-nested-index.tar\", \"export-docker-desktop-containerd-alt-mediatype.tar\" })\n\tvoid test(String tarFile) throws Exception {\n\t\tImageReference reference = ImageReference.of(\"test:latest\");\n\t\ttry (ExportedImageTar exportedImageTar = new ExportedImageTar(reference,\n\t\t\t\tgetClass().getResourceAsStream(tarFile))) {\n\t\t\tCompression expectedCompression = (!tarFile.contains(\"containerd\")) ? Compression.NONE : Compression.GZIP;\n\t\t\tString expectedName = (expectedCompression != Compression.GZIP)\n\t\t\t\t\t? \"5caae51697b248b905dca1a4160864b0e1a15c300981736555cdce6567e8d477\"\n\t\t\t\t\t: \"f0f1fd1bdc71ac6a4dc99cea5f5e45c86c5ec26fe4d1daceeb78207303606429\";\n\t\t\tList<String> names = new ArrayList<>();\n\t\t\texportedImageTar.exportLayers((name, tarArchive) -> {\n\t\t\t\tnames.add(name);\n\t\t\t\tassertThat(tarArchive.getCompression()).isEqualTo(expectedCompression);\n\t\t\t});\n\t\t\tassertThat(names).filteredOn((name) -> name.contains(expectedName)).isNotEmpty();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ImagePlatformTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\nclass ImagePlatformTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid ofWithOsParses() {\n\t\tImagePlatform platform = ImagePlatform.of(\"linux\");\n\t\tassertThat(platform.toString()).isEqualTo(\"linux\");\n\t}\n\n\t@Test\n\tvoid ofWithOsAndArchitectureParses() {\n\t\tImagePlatform platform = ImagePlatform.of(\"linux/amd64\");\n\t\tassertThat(platform.toString()).isEqualTo(\"linux/amd64\");\n\t}\n\n\t@Test\n\tvoid ofWithOsAndArchitectureAndVariantParses() {\n\t\tImagePlatform platform = ImagePlatform.of(\"linux/amd64/v1\");\n\t\tassertThat(platform.toString()).isEqualTo(\"linux/amd64/v1\");\n\t}\n\n\t@Test\n\tvoid ofWithEmptyValueFails() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImagePlatform.of(\"\"))\n\t\t\t.withMessageContaining(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWithTooManySegmentsFails() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImagePlatform.of(\"linux/amd64/v1/extra\"))\n\t\t\t.withMessageContaining(\"'value' [linux/amd64/v1/extra] must be in the form\");\n\t}\n\n\t@Test\n\tvoid fromImageMatchesImage() throws IOException {\n\t\tImagePlatform platform = ImagePlatform.from(getImage());\n\t\tassertThat(platform.toString()).isEqualTo(\"linux/amd64/v1\");\n\t}\n\n\t@Test\n\tvoid toJsonString() {\n\t\tImagePlatform platform = ImagePlatform.of(\"linux/amd64/v1\");\n\t\tassertThat(platform.toJson()).isEqualTo(\"\"\"\n\t\t\t\t{\"os\":\"linux\",\"architecture\":\"amd64\",\"variant\":\"v1\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid toJsonStringWhenOnlyOs() {\n\t\tImagePlatform platform = ImagePlatform.of(\"linux\");\n\t\tassertThat(platform.toJson()).isEqualTo(\"\"\"\n\t\t\t\t{\"os\":\"linux\"}\"\"\");\n\t}\n\n\tprivate Image getImage() throws IOException {\n\t\treturn Image.of(getContent(\"type/image.json\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/LoadImageUpdateEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.LoadImageUpdateEvent.ErrorDetail;\nimport org.springframework.boot.buildpack.platform.docker.ProgressUpdateEvent.ProgressDetail;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LoadImageUpdateEvent}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass LoadImageUpdateEventTests extends ProgressUpdateEventTests<LoadImageUpdateEvent> {\n\n\t@Test\n\tvoid getStreamReturnsStream() {\n\t\tLoadImageUpdateEvent event = createEvent();\n\t\tassertThat(event.getStream()).isEqualTo(\"stream\");\n\t}\n\n\t@Test\n\tvoid getErrorDetailReturnsErrorDetail() {\n\t\tLoadImageUpdateEvent event = createEvent();\n\t\tassertThat(event.getErrorDetail()).extracting(ErrorDetail::getMessage).isEqualTo(\"max depth exceeded\");\n\t}\n\n\t@Override\n\tprotected LoadImageUpdateEvent createEvent(String status, ProgressDetail progressDetail, String progress) {\n\t\treturn new LoadImageUpdateEvent(\"stream\", status, progressDetail, progress,\n\t\t\t\tnew ErrorDetail(\"max depth exceeded\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/LogUpdateEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LogUpdateEvent}.\n *\n * @author Phillip Webb\n */\nclass LogUpdateEventTests {\n\n\t@Test\n\tvoid readAllWhenSimpleStreamReturnsEvents() throws Exception {\n\t\tList<LogUpdateEvent> events = readAll(\"log-update-event.stream\");\n\t\tassertThat(events).hasSize(7);\n\t\tassertThat(events.get(0))\n\t\t\t.hasToString(\"Analyzing image '307c032c4ceaa6330b6c02af945a1fe56a8c3c27c28268574b217c1d38b093cf'\");\n\t\tassertThat(events.get(1))\n\t\t\t.hasToString(\"Writing metadata for uncached layer 'org.cloudfoundry.openjdk:openjdk-jre'\");\n\t\tassertThat(events.get(2))\n\t\t\t.hasToString(\"Using cached launch layer 'org.cloudfoundry.jvmapplication:executable-jar'\");\n\t}\n\n\t@Test\n\tvoid readAllWhenAnsiStreamReturnsEvents() throws Exception {\n\t\tList<LogUpdateEvent> events = readAll(\"log-update-event-ansi.stream\");\n\t\tassertThat(events).hasSize(20);\n\t\tassertThat(events.get(0).toString()).isEmpty();\n\t\tassertThat(events.get(1)).hasToString(\"Cloud Foundry OpenJDK Buildpack v1.0.64\");\n\t\tassertThat(events.get(2)).hasToString(\"  OpenJDK JRE 11.0.5: Reusing cached layer\");\n\t}\n\n\t@Test\n\tvoid readSucceedsWhenStreamTypeIsInvalid() throws IOException {\n\t\tList<LogUpdateEvent> events = readAll(\"log-update-event-invalid-stream-type.stream\");\n\t\tassertThat(events).hasSize(1);\n\t\tassertThat(events.get(0)).hasToString(\"Stream type is out of bounds. Must be >= 0 and < 3, but was 3\");\n\t}\n\n\tprivate List<LogUpdateEvent> readAll(String name) throws IOException {\n\t\tList<LogUpdateEvent> events = new ArrayList<>();\n\t\ttry (InputStream inputStream = getClass().getResourceAsStream(name)) {\n\t\t\tLogUpdateEvent.readAll(inputStream, events::add);\n\t\t}\n\t\treturn events;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ProgressUpdateEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.ProgressUpdateEvent.ProgressDetail;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ProgressUpdateEvent}.\n *\n * @param <E> The event type\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Wolfgang Kronberg\n */\nabstract class ProgressUpdateEventTests<E extends ProgressUpdateEvent> {\n\n\t@Test\n\tvoid getStatusReturnsStatus() {\n\t\tProgressUpdateEvent event = createEvent();\n\t\tassertThat(event.getStatus()).isEqualTo(\"status\");\n\t}\n\n\t@Test\n\tvoid getProgressDetailReturnsProgressDetails() {\n\t\tProgressUpdateEvent event = createEvent();\n\t\tProgressDetail progressDetail = event.getProgressDetail();\n\t\tassertThat(progressDetail).isNotNull();\n\t\tassertThat(progressDetail.asPercentage()).isEqualTo(50);\n\t}\n\n\t@Test\n\tvoid getProgressDetailReturnsProgressDetailsForLongNumbers() {\n\t\tProgressUpdateEvent event = createEvent(\"status\", new ProgressDetail(4000000000L, 8000000000L), \"progress\");\n\t\tProgressDetail progressDetail = event.getProgressDetail();\n\t\tassertThat(progressDetail).isNotNull();\n\t\tassertThat(progressDetail.asPercentage()).isEqualTo(50);\n\t}\n\n\t@Test\n\tvoid getProgressReturnsProgress() {\n\t\tProgressUpdateEvent event = createEvent();\n\t\tassertThat(event.getProgress()).isEqualTo(\"progress\");\n\t}\n\n\tprotected E createEvent() {\n\t\treturn createEvent(\"status\", new ProgressDetail(1L, 2L), \"progress\");\n\t}\n\n\tprotected abstract E createEvent(String status, ProgressDetail progressDetail, String progress);\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullImageUpdateEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.ProgressUpdateEvent.ProgressDetail;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PullImageUpdateEvent}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass PullImageUpdateEventTests extends ProgressUpdateEventTests<PullImageUpdateEvent> {\n\n\t@Test\n\tvoid getIdReturnsId() {\n\t\tPullImageUpdateEvent event = createEvent();\n\t\tassertThat(event.getId()).isEqualTo(\"id\");\n\t}\n\n\t@Override\n\tprotected PullImageUpdateEvent createEvent(String status, ProgressDetail progressDetail, String progress) {\n\t\treturn new PullImageUpdateEvent(\"id\", status, progressDetail, progress);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PullUpdateEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.ProgressUpdateEvent.ProgressDetail;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PullImageUpdateEvent}.\n *\n * @author Phillip Webb\n */\nclass PullUpdateEventTests extends AbstractJsonTests {\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid readValueWhenFullDeserializesJson() throws Exception {\n\t\tPullImageUpdateEvent event = getJsonMapper().readValue(getContent(\"pull-update-full.json\"),\n\t\t\t\tPullImageUpdateEvent.class);\n\t\tassertThat(event.getId()).isEqualTo(\"4f4fb700ef54\");\n\t\tassertThat(event.getStatus()).isEqualTo(\"Extracting\");\n\t\tProgressDetail progressDetail = event.getProgressDetail();\n\t\tassertThat(progressDetail).isNotNull();\n\t\tassertThat(progressDetail.asPercentage()).isEqualTo(50);\n\t\tassertThat(event.getProgress()).isEqualTo(\"[==================================================>]      32B/32B\");\n\t}\n\n\t@Test\n\tvoid readValueWhenMinimalDeserializesJson() throws Exception {\n\t\tPullImageUpdateEvent event = getJsonMapper().readValue(getContent(\"pull-update-minimal.json\"),\n\t\t\t\tPullImageUpdateEvent.class);\n\t\tassertThat(event.getId()).isNull();\n\t\tassertThat(event.getStatus()).isEqualTo(\"Status: Downloaded newer image for paketo-buildpacks/cnb:base\");\n\t\tassertThat(event.getProgressDetail()).isNull();\n\t\tassertThat(event.getProgress()).isNull();\n\t}\n\n\t@Test\n\tvoid readValueWhenEmptyDetailsDeserializesJson() throws Exception {\n\t\tPullImageUpdateEvent event = getJsonMapper().readValue(getContent(\"pull-with-empty-details.json\"),\n\t\t\t\tPullImageUpdateEvent.class);\n\t\tassertThat(event.getId()).isEqualTo(\"d837a2a1365e\");\n\t\tassertThat(event.getStatus()).isEqualTo(\"Pulling fs layer\");\n\t\tassertThat(event.getProgressDetail()).isNull();\n\t\tassertThat(event.getProgress()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/PushImageUpdateEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.ProgressUpdateEvent.ProgressDetail;\nimport org.springframework.boot.buildpack.platform.docker.PushImageUpdateEvent.ErrorDetail;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PushImageUpdateEvent}.\n *\n * @author Scott Frederick\n */\nclass PushImageUpdateEventTests extends ProgressUpdateEventTests<PushImageUpdateEvent> {\n\n\t@Test\n\tvoid getIdReturnsId() {\n\t\tPushImageUpdateEvent event = createEvent();\n\t\tassertThat(event.getId()).isEqualTo(\"id\");\n\t}\n\n\t@Test\n\tvoid getErrorReturnsErrorDetail() {\n\t\tPushImageUpdateEvent event = new PushImageUpdateEvent(\"id\", \"status\", new ProgressDetail(null, null),\n\t\t\t\t\"progress\", new PushImageUpdateEvent.ErrorDetail(\"test message\"));\n\t\tErrorDetail errorDetail = event.getErrorDetail();\n\t\tassertThat(errorDetail).isNotNull();\n\t\tassertThat(errorDetail.getMessage()).isEqualTo(\"test message\");\n\t}\n\n\t@Override\n\tprotected PushImageUpdateEvent createEvent(String status, ProgressDetail progressDetail, String progress) {\n\t\treturn new PushImageUpdateEvent(\"id\", status, progressDetail, progress, null);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/TotalProgressBarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.PrintStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TotalProgressBar}.\n *\n * @author Phillip Webb\n */\nclass TotalProgressBarTests {\n\n\t@Test\n\tvoid withPrefixAndBookends() {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tTotalProgressBar bar = new TotalProgressBar(\"prefix:\", '#', true, out);\n\t\tassertThat(out).hasToString(\"prefix: [ \");\n\t\tbar.accept(new TotalProgressEvent(10));\n\t\tassertThat(out).hasToString(\"prefix: [ #####\");\n\t\tbar.accept(new TotalProgressEvent(50));\n\t\tassertThat(out).hasToString(\"prefix: [ #########################\");\n\t\tbar.accept(new TotalProgressEvent(100));\n\t\tassertThat(out).hasToString(String.format(\"prefix: [ ################################################## ]%n\"));\n\t}\n\n\t@Test\n\tvoid withoutPrefix() {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tTotalProgressBar bar = new TotalProgressBar(null, '#', true, out);\n\t\tassertThat(out).hasToString(\"[ \");\n\t\tbar.accept(new TotalProgressEvent(10));\n\t\tassertThat(out).hasToString(\"[ #####\");\n\t\tbar.accept(new TotalProgressEvent(50));\n\t\tassertThat(out).hasToString(\"[ #########################\");\n\t\tbar.accept(new TotalProgressEvent(100));\n\t\tassertThat(out).hasToString(String.format(\"[ ################################################## ]%n\"));\n\t}\n\n\t@Test\n\tvoid withoutBookends() {\n\t\tTestPrintStream out = new TestPrintStream();\n\t\tTotalProgressBar bar = new TotalProgressBar(\"\", '.', false, out);\n\t\tassertThat(out).hasToString(\"\");\n\t\tbar.accept(new TotalProgressEvent(10));\n\t\tassertThat(out).hasToString(\".....\");\n\t\tbar.accept(new TotalProgressEvent(50));\n\t\tassertThat(out).hasToString(\".........................\");\n\t\tbar.accept(new TotalProgressEvent(100));\n\t\tassertThat(out).hasToString(String.format(\"..................................................%n\"));\n\t}\n\n\tstatic class TestPrintStream extends PrintStream {\n\n\t\tTestPrintStream() {\n\t\t\tsuper(new ByteArrayOutputStream());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.out.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/TotalProgressEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link TotalProgressEvent}.\n *\n * @author Phillip Webb\n */\nclass TotalProgressEventTests {\n\n\t@Test\n\tvoid create() {\n\t\tassertThat(new TotalProgressEvent(0).getPercent()).isZero();\n\t\tassertThat(new TotalProgressEvent(10).getPercent()).isEqualTo(10);\n\t\tassertThat(new TotalProgressEvent(100).getPercent()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid createWhenPercentLessThanZeroThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TotalProgressEvent(-1))\n\t\t\t.withMessage(\"'percent' must be in the range 0 to 100\");\n\t}\n\n\t@Test\n\tvoid createWhenEventMoreThanOneHundredThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TotalProgressEvent(101))\n\t\t\t.withMessage(\"'percent' must be in the range 0 to 100\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/TotalProgressListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.boot.buildpack.platform.json.JsonStream;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TotalProgressPullListener}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass TotalProgressListenerTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid totalProgress() throws Exception {\n\t\tList<Integer> progress = new ArrayList<>();\n\t\tTestTotalProgressListener listener = new TestTotalProgressListener((event) -> progress.add(event.getPercent()));\n\t\trun(listener);\n\t\tint last = 0;\n\t\tfor (Integer update : progress) {\n\t\t\tassertThat(update).isGreaterThanOrEqualTo(last);\n\t\t\tlast = update;\n\t\t}\n\t\tassertThat(last).isEqualTo(100);\n\t}\n\n\t@Test\n\t@Disabled(\"For visual inspection\")\n\tvoid totalProgressUpdatesSmoothly() throws Exception {\n\t\tTestTotalProgressListener listener = new TestTotalProgressListener(new TotalProgressBar(\"Pulling layers:\"));\n\t\trun(listener);\n\t}\n\n\tprivate void run(TestTotalProgressListener listener) throws IOException {\n\t\tJsonStream jsonStream = new JsonStream(getJsonMapper());\n\t\tlistener.onStart();\n\t\tjsonStream.get(getContent(\"pull-stream.json\"), TestImageUpdateEvent.class, listener::onUpdate);\n\t\tlistener.onFinish();\n\t}\n\n\tprivate static class TestTotalProgressListener extends TotalProgressListener<TestImageUpdateEvent> {\n\n\t\tTestTotalProgressListener(Consumer<TotalProgressEvent> consumer) {\n\t\t\tsuper(consumer, new String[] { \"Pulling\", \"Downloading\", \"Extracting\" });\n\t\t}\n\n\t\t@Override\n\t\tpublic void onUpdate(TestImageUpdateEvent event) {\n\t\t\tsuper.onUpdate(event);\n\t\t\ttry {\n\t\t\t\tThread.sleep(10);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static class TestImageUpdateEvent extends ImageProgressUpdateEvent {\n\n\t\t@JsonCreator\n\t\tTestImageUpdateEvent(String id, String status, ProgressDetail progressDetail, String progress) {\n\t\t\tsuper(id, status, progressDetail, progress);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/CredentialHelperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.util.UUID;\n\nimport com.sun.jna.Platform;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link CredentialHelper}.\n *\n * @author Dmytro Nosan\n */\nclass CredentialHelperTests {\n\n\tprivate static CredentialHelper helper;\n\n\t@BeforeAll\n\tstatic void setUp() throws Exception {\n\t\thelper = new CredentialHelper(getExecutableName());\n\t}\n\n\tprivate static String getExecutableName() throws Exception {\n\t\tif (Platform.isWindows()) {\n\t\t\tString executablePath = geExecutableAbsolutePath(\"docker-credential-test.bat\");\n\t\t\t// cmd /c must resolve automatically .bat suffix\n\t\t\treturn executablePath.substring(0, executablePath.lastIndexOf(\".bat\"));\n\t\t}\n\t\treturn geExecutableAbsolutePath(\"docker-credential-test.sh\");\n\t}\n\n\tprivate static String geExecutableAbsolutePath(String executableName) throws Exception {\n\t\treturn new ClassPathResource(executableName, CredentialHelperTests.class).getFile().getAbsolutePath();\n\t}\n\n\t@Test\n\tvoid getWhenKnowUser() throws Exception {\n\t\tCredential credentials = helper.get(\"user.example.com\");\n\t\tassertThat(credentials).isNotNull();\n\t\tassertThat(credentials.isIdentityToken()).isFalse();\n\t\tassertThat(credentials.getServerUrl()).isEqualTo(\"user.example.com\");\n\t\tassertThat(credentials.getUsername()).isEqualTo(\"username\");\n\t\tassertThat(credentials.getSecret()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getWhenKnowToken() throws Exception {\n\t\tCredential credentials = helper.get(\"token.example.com\");\n\t\tassertThat(credentials).isNotNull();\n\t\tassertThat(credentials.isIdentityToken()).isTrue();\n\t\tassertThat(credentials.getServerUrl()).isEqualTo(\"token.example.com\");\n\t\tassertThat(credentials.getUsername()).isEqualTo(\"<token>\");\n\t\tassertThat(credentials.getSecret()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getWhenCredentialsMissingMessageReturnsNull() throws Exception {\n\t\tCredential credentials = helper.get(\"credentials.missing.example.com\");\n\t\tassertThat(credentials).isNull();\n\t}\n\n\t@Test\n\tvoid getWhenUsernameMissingMessageReturnsNull() throws Exception {\n\t\tCredential credentials = helper.get(\"username.missing.example.com\");\n\t\tassertThat(credentials).isNull();\n\t}\n\n\t@Test\n\tvoid getWhenUrlMissingMessageReturnsNull() throws Exception {\n\t\tCredential credentials = helper.get(\"url.missing.example.com\");\n\t\tassertThat(credentials).isNull();\n\t}\n\n\t@Test\n\tvoid getWhenUnknownErrorThrowsException() {\n\t\tassertThatIOException().isThrownBy(() -> helper.get(\"invalid.example.com\"))\n\t\t\t.withMessageContaining(\"Unknown error\");\n\t}\n\n\t@Test\n\tvoid getWhenExecutableDoesNotExistErrorThrowsException() {\n\t\tString executable = \"docker-credential-%s\".formatted(UUID.randomUUID().toString());\n\t\tassertThatIOException().isThrownBy(() -> new CredentialHelper(executable).get(\"invalid.example.com\"))\n\t\t\t.withMessageContaining(executable)\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tif (Platform.isMac()) {\n\t\t\t\t\tassertThat(ex.getMessage()).doesNotContain(\"/usr/local/bin/\");\n\t\t\t\t\tassertThat(ex.getSuppressed()).allSatisfy((suppressed) -> assertThat(suppressed)\n\t\t\t\t\t\t.hasMessageContaining(\"/usr/local/bin/\" + executable));\n\t\t\t\t}\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/CredentialTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Credential}.\n *\n * @author Dmytro Nosan\n */\nclass CredentialTests {\n\n\t@Test\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"ServerURL\": \"https://index.docker.io/v1/\",\n\t\t\t  \"Username\": \"user\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid createWhenUserCredentials() throws Exception {\n\t\tCredential credentials = getCredentials(\"credentials.json\");\n\t\tassertThat(credentials.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(credentials.getSecret()).isEqualTo(\"secret\");\n\t\tassertThat(credentials.getServerUrl()).isEqualTo(\"https://index.docker.io/v1/\");\n\t\tassertThat(credentials.isIdentityToken()).isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"ServerURL\": \"https://index.docker.io/v1/\",\n\t\t\t  \"Username\": \"<token>\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid createWhenTokenCredentials() throws Exception {\n\t\tCredential credentials = getCredentials(\"credentials.json\");\n\t\tassertThat(credentials.getUsername()).isEqualTo(\"<token>\");\n\t\tassertThat(credentials.getSecret()).isEqualTo(\"secret\");\n\t\tassertThat(credentials.getServerUrl()).isEqualTo(\"https://index.docker.io/v1/\");\n\t\tassertThat(credentials.isIdentityToken()).isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"Username\": \"user\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid createWhenNoServerUrl() throws Exception {\n\t\tCredential credentials = getCredentials(\"credentials.json\");\n\t\tassertThat(credentials.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(credentials.getSecret()).isEqualTo(\"secret\");\n\t\tassertThat(credentials.getServerUrl()).isNull();\n\t\tassertThat(credentials.isIdentityToken()).isFalse();\n\t}\n\n\tprivate Credential getCredentials(String name) throws IOException {\n\t\ttry (InputStream inputStream = new ClassPathResource(name).getInputStream()) {\n\t\t\treturn new Credential(SharedJsonMapper.get().readTree(inputStream));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerConfigurationMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.File;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConfigurationMetadata.DockerConfig;\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConfigurationMetadata.DockerContext;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DockerConfigurationMetadata}.\n *\n * @author Scott Frederick\n * @author Dmytro Nosan\n */\nclass DockerConfigurationMetadataTests extends AbstractJsonTests {\n\n\tprivate final Map<String, String> environment = new LinkedHashMap<>();\n\n\t@Test\n\tvoid configWithContextIsRead() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-context/config.json\"));\n\t\tDockerConfigurationMetadata config = DockerConfigurationMetadata.from(this.environment::get);\n\t\tassertThat(config.getConfiguration().getCurrentContext()).isEqualTo(\"test-context\");\n\t\tassertThat(config.getConfiguration().getAuths()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredHelpers()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredsStore()).isNull();\n\t\tassertThat(config.getContext().getDockerHost()).isEqualTo(\"unix:///home/user/.docker/docker.sock\");\n\t\tassertThat(config.getContext().isTlsVerify()).isFalse();\n\t\tassertThat(config.getContext().getTlsPath()).isNull();\n\t}\n\n\t@Test\n\tvoid configWithoutContextIsRead() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"without-context/config.json\"));\n\t\tDockerConfigurationMetadata config = DockerConfigurationMetadata.from(this.environment::get);\n\t\tassertThat(config.getConfiguration().getCurrentContext()).isNull();\n\t\tassertThat(config.getConfiguration().getAuths()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredHelpers()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredsStore()).isNull();\n\t\tassertThat(config.getContext().getDockerHost()).isNull();\n\t\tassertThat(config.getContext().isTlsVerify()).isFalse();\n\t\tassertThat(config.getContext().getTlsPath()).isNull();\n\t}\n\n\t@Test\n\tvoid configWithDefaultContextIsRead() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-default-context/config.json\"));\n\t\tDockerConfigurationMetadata config = DockerConfigurationMetadata.from(this.environment::get);\n\t\tassertThat(config.getConfiguration().getCurrentContext()).isEqualTo(\"default\");\n\t\tassertThat(config.getConfiguration().getAuths()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredHelpers()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredsStore()).isNull();\n\t\tassertThat(config.getContext().getDockerHost()).isNull();\n\t\tassertThat(config.getContext().isTlsVerify()).isFalse();\n\t\tassertThat(config.getContext().getTlsPath()).isNull();\n\t}\n\n\t@Test\n\tvoid configIsReadWithProvidedContext() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-default-context/config.json\"));\n\t\tDockerConfigurationMetadata config = DockerConfigurationMetadata.from(this.environment::get);\n\t\tDockerContext context = config.forContext(\"test-context\");\n\t\tassertThat(context.getDockerHost()).isEqualTo(\"unix:///home/user/.docker/docker.sock\");\n\t\tassertThat(context.isTlsVerify()).isTrue();\n\t\tassertThat(context.getTlsPath()).matches(String.join(Pattern.quote(File.separator), \"^.*\",\n\t\t\t\t\"with-default-context\", \"contexts\", \"tls\", \"[a-zA-z0-9]*\", \"docker$\"));\n\t}\n\n\t@Test\n\tvoid invalidContextThrowsException() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-default-context/config.json\"));\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> DockerConfigurationMetadata.from(this.environment::get).forContext(\"invalid-context\"))\n\t\t\t.withMessageContaining(\"Docker context 'invalid-context' does not exist\");\n\t}\n\n\t@Test\n\tvoid configIsEmptyWhenConfigFileDoesNotExist() {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", \"docker-config-dummy-path\");\n\t\tDockerConfigurationMetadata config = DockerConfigurationMetadata.from(this.environment::get);\n\t\tassertThat(config.getConfiguration().getCurrentContext()).isNull();\n\t\tassertThat(config.getConfiguration().getAuths()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredHelpers()).isEmpty();\n\t\tassertThat(config.getConfiguration().getCredsStore()).isNull();\n\t\tassertThat(config.getContext().getDockerHost()).isNull();\n\t\tassertThat(config.getContext().isTlsVerify()).isFalse();\n\t}\n\n\t@Test\n\tvoid configWithAuthIsRead() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-auth/config.json\"));\n\t\tDockerConfigurationMetadata metadata = DockerConfigurationMetadata.from(this.environment::get);\n\t\tDockerConfig configuration = metadata.getConfiguration();\n\t\tassertThat(configuration.getCredsStore()).isEqualTo(\"desktop\");\n\t\tassertThat(configuration.getCredHelpers()).hasSize(3)\n\t\t\t.containsEntry(\"azurecr.io\", \"acr-env\")\n\t\t\t.containsEntry(\"ecr.us-east-1.amazonaws.com\", \"ecr-login\")\n\t\t\t.containsEntry(\"gcr.io\", \"gcr\");\n\t\tassertThat(configuration.getAuths()).hasSize(3).hasEntrySatisfying(\"https://index.docker.io/v1/\", (auth) -> {\n\t\t\tassertThat(auth.getUsername()).isEqualTo(\"username\");\n\t\t\tassertThat(auth.getPassword()).isEqualTo(\"pass\\u0000word\");\n\t\t\tassertThat(auth.getEmail()).isEqualTo(\"test@example.com\");\n\t\t}).hasEntrySatisfying(\"custom-registry.example.com\", (auth) -> {\n\t\t\tassertThat(auth.getUsername()).isEqualTo(\"customUser\");\n\t\t\tassertThat(auth.getPassword()).isEqualTo(\"customPass\");\n\t\t\tassertThat(auth.getEmail()).isNull();\n\t\t}).hasEntrySatisfying(\"my-registry.example.com\", (auth) -> {\n\t\t\tassertThat(auth.getUsername()).isEqualTo(\"user\");\n\t\t\tassertThat(auth.getPassword()).isEqualTo(\"password\");\n\t\t\tassertThat(auth.getEmail()).isNull();\n\t\t});\n\t}\n\n\tprivate String pathToResource(String resource) throws URISyntaxException {\n\t\tURL url = getClass().getResource(resource);\n\t\tPath parent = Paths.get(url.toURI()).getParent();\n\t\tassertThat(parent).isNotNull();\n\t\treturn parent.toAbsolutePath().toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryConfigAuthenticationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\nimport java.util.Base64;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport tools.jackson.core.type.TypeReference;\n\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.json.SharedJsonMapper;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcesRoot;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link DockerRegistryConfigAuthentication}.\n *\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass DockerRegistryConfigAuthenticationTests {\n\n\tprivate final Map<String, String> environment = new LinkedHashMap<>();\n\n\tprivate final Map<String, Exception> helperExceptions = new LinkedHashMap<>();\n\n\tprivate final Map<String, CredentialHelper> credentialHelpers = new HashMap<>();\n\n\t@BeforeEach\n\tvoid cleanup() {\n\t\tDockerRegistryConfigAuthentication.credentialFromHelperCache.clear();\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"auths\": {\n\t\t\t    \"https://index.docker.io/v1/\": {\n\t\t\t      \"auth\": \"dXNlcm5hbWU6cGFzc3dvcmQ=\",\n\t\t\t      \"email\": \"test@example.com\"\n\t\t\t    }\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenAuthForDockerDomain(@ResourcesRoot Path directory) {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"docker.io/ubuntu:latest\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"https://index.docker.io/v1/\")\n\t\t\t.containsEntry(\"username\", \"username\")\n\t\t\t.containsEntry(\"password\", \"password\")\n\t\t\t.containsEntry(\"email\", \"test@example.com\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"auths\": {\n\t\t\t    \"https://index.docker.io/v1/\": {\n\t\t\t      \"auth\": \"dXNlcm5hbWU6cGFzc3dvcmQ=\",\n\t\t\t      \"email\": \"test@example.com\"\n\t\t\t    }\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenAuthForLegacyDockerDomain(@ResourcesRoot Path directory) {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"index.docker.io/ubuntu:latest\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"https://index.docker.io/v1/\")\n\t\t\t.containsEntry(\"username\", \"username\")\n\t\t\t.containsEntry(\"password\", \"password\")\n\t\t\t.containsEntry(\"email\", \"test@example.com\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"auths\": {\n\t\t\t\t\"my-registry.example.com\": {\n\t\t\t\t  \"auth\": \"Y3VzdG9tVXNlcjpjdXN0b21QYXNz\"\n\t\t\t\t}\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenAuthForCustomDomain(@ResourcesRoot Path directory) {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"my-registry.example.com/ubuntu:latest\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"my-registry.example.com\")\n\t\t\t.containsEntry(\"username\", \"customUser\")\n\t\t\t.containsEntry(\"password\", \"customPass\")\n\t\t\t.containsEntry(\"email\", null);\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"auths\": {\n\t\t\t\t\"https://my-registry.example.com\": {\n\t\t\t\t  \"auth\": \"Y3VzdG9tVXNlcjpjdXN0b21QYXNz\"\n\t\t\t\t}\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenAuthForCustomDomainWithLegacyFormat(@ResourcesRoot Path directory) {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"my-registry.example.com/ubuntu:latest\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"https://my-registry.example.com\")\n\t\t\t.containsEntry(\"username\", \"customUser\")\n\t\t\t.containsEntry(\"password\", \"customPass\")\n\t\t\t.containsEntry(\"email\", null);\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenEmptyConfigDirectoryReturnsFallback(@ResourcesRoot Path directory) {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"docker.io/ubuntu:latest\");\n\t\tString authHeader = getAuthHeader(imageReference, DockerRegistryAuthentication.EMPTY_USER);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"\")\n\t\t\t.containsEntry(\"username\", \"\")\n\t\t\t.containsEntry(\"password\", \"\")\n\t\t\t.containsEntry(\"email\", \"\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t\t{\n\t\t\t\t  \"credsStore\": \"desktop\"\n\t\t\t\t}\n\t\t\t\"\"\")\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"ServerURL\": \"https://index.docker.io/v1/\",\n\t\t\t  \"Username\": \"<token>\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenUsingHelperFromCredsStore(@ResourcesRoot Path directory) throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"docker.io/ubuntu:latest\");\n\t\tmockHelper(\"desktop\", \"https://index.docker.io/v1/\", \"credentials.json\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(1).containsEntry(\"identitytoken\", \"secret\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"auths\": {\n\t\t\t    \"gcr.io\": {\n\t\t\t      \"email\": \"test@example.com\"\n\t\t\t    }\n\t\t\t  },\n\t\t\t  \"credsStore\": \"desktop\",\n\t\t\t  \"credHelpers\": {\n\t\t\t    \"gcr.io\": \"gcr\"\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"ServerURL\": \"https://my-gcr.io\",\n\t\t\t  \"Username\": \"username\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenUsingHelperFromCredsStoreAndUseEmailFromAuth(@ResourcesRoot Path directory) throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"gcr.io/ubuntu:latest\");\n\t\tmockHelper(\"gcr\", \"gcr.io\", \"credentials.json\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"https://my-gcr.io\")\n\t\t\t.containsEntry(\"username\", \"username\")\n\t\t\t.containsEntry(\"password\", \"secret\")\n\t\t\t.containsEntry(\"email\", \"test@example.com\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"credsStore\": \"desktop\",\n\t\t\t  \"credHelpers\": {\n\t\t\t    \"gcr.io\": \"gcr\"\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"Username\": \"username\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenUsingHelperFromCredHelpersUsesProvidedServerUrl(@ResourcesRoot Path directory)\n\t\t\tthrows Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"gcr.io/ubuntu:latest\");\n\t\tmockHelper(\"gcr\", \"gcr.io\", \"credentials.json\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"gcr.io\")\n\t\t\t.containsEntry(\"username\", \"username\")\n\t\t\t.containsEntry(\"password\", \"secret\")\n\t\t\t.containsEntry(\"email\", null);\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t\"auths\": {\n\t\t\t    \"gcr.io\": {\n\t\t\t      \"auth\": \"dXNlcm5hbWU6cGFzc3dvcmQ=\",\n\t\t\t      \"email\": \"test@example.com\"\n\t\t\t    }\n\t\t\t  },\n\t\t\t  \"credsStore\": \"desktop\",\n\t\t\t  \"credHelpers\": {\n\t\t\t    \"gcr.io\": \"gcr\"\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenUsingHelperThatFailsLogsErrorAndReturnsFromAuths(@ResourcesRoot Path directory)\n\t\t\tthrows Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"gcr.io/ubuntu:latest\");\n\t\tCredentialHelper helper = mockHelper(\"gcr\");\n\t\tgiven(helper.get(\"gcr.io\")).willThrow(new IOException(\"Failed to obtain credentials for registry\"));\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"gcr.io\")\n\t\t\t.containsEntry(\"username\", \"username\")\n\t\t\t.containsEntry(\"password\", \"password\")\n\t\t\t.containsEntry(\"email\", \"test@example.com\");\n\t\tassertThat(this.helperExceptions).hasSize(1);\n\t\tassertThat(this.helperExceptions.keySet().iterator().next())\n\t\t\t.contains(\"Error retrieving credentials for 'gcr.io' due to: Failed to obtain credentials for registry\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"credsStore\": \"desktop\",\n\t\t\t  \"credHelpers\": {\n\t\t\t    \"gcr.io\": \"gcr\"\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenUsingHelperThatFailsAndNoAuthLogsErrorAndReturnsFallback(@ResourcesRoot Path directory)\n\t\t\tthrows Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"gcr.io/ubuntu:latest\");\n\t\tCredentialHelper helper = mockHelper(\"gcr\");\n\t\tgiven(helper.get(\"gcr.io\")).willThrow(new IOException(\"Failed to obtain credentials for registry\"));\n\t\tString authHeader = getAuthHeader(imageReference, DockerRegistryAuthentication.EMPTY_USER);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(this.helperExceptions).hasSize(1);\n\t\tassertThat(this.helperExceptions.keySet().iterator().next())\n\t\t\t.contains(\"Error retrieving credentials for 'gcr.io' due to: Failed to obtain credentials for registry\");\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"\")\n\t\t\t.containsEntry(\"username\", \"\")\n\t\t\t.containsEntry(\"password\", \"\")\n\t\t\t.containsEntry(\"email\", \"\");\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"credsStore\": \"desktop\",\n\t\t\t  \"credHelpers\": {\n\t\t\t    \"gcr.io\": \"\"\n\t\t\t  }\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenEmptyCredHelperReturnsFallbackAndDoesNotUseCredStore(@ResourcesRoot Path directory)\n\t\t\tthrows Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tImageReference imageReference = ImageReference.of(\"gcr.io/ubuntu:latest\");\n\t\tCredentialHelper desktopHelper = mockHelper(\"desktop\");\n\t\tString authHeader = getAuthHeader(imageReference, DockerRegistryAuthentication.EMPTY_USER);\n\t\tassertThat(authHeader).isNotNull();\n\t\t// The Docker CLI appears to prioritize the credential helper over the\n\t\t// credential store, even when the helper is empty.\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"\")\n\t\t\t.containsEntry(\"username\", \"\")\n\t\t\t.containsEntry(\"password\", \"\")\n\t\t\t.containsEntry(\"email\", \"\");\n\t\tthen(desktopHelper).should(never()).get(any(String.class));\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"credsStore\": \"desktop\"\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderReturnsFallbackWhenImageReferenceNull(@ResourcesRoot Path directory) throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tCredentialHelper desktopHelper = mockHelper(\"desktop\");\n\t\tString authHeader = getAuthHeader(null, DockerRegistryAuthentication.EMPTY_USER);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"\")\n\t\t\t.containsEntry(\"username\", \"\")\n\t\t\t.containsEntry(\"password\", \"\")\n\t\t\t.containsEntry(\"email\", \"\");\n\t\tthen(desktopHelper).should(never()).get(any(String.class));\n\t}\n\n\t@WithResource(name = \"config.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"auths\": {\n\t\t\t    \"https://my-registry.example.com\": {\n\t\t\t      \"email\": \"test@example.com\"\n\t\t\t    }\n\t\t\t  },\n\t\t\t  \"credsStore\": \"desktop\"\n\t\t\t}\n\t\t\t\"\"\")\n\t@WithResource(name = \"credentials.json\", content = \"\"\"\n\t\t\t{\n\t\t\t  \"Username\": \"username\",\n\t\t\t  \"Secret\": \"secret\"\n\t\t\t}\n\t\t\t\"\"\")\n\t@Test\n\tvoid getAuthHeaderWhenUsingHelperFromCredHelpersUsesImageReferenceServerUrlAsFallback(@ResourcesRoot Path directory)\n\t\t\tthrows Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", directory.toString());\n\t\tmockHelper(\"desktop\", \"my-registry.example.com\", \"credentials.json\");\n\t\tImageReference imageReference = ImageReference.of(\"my-registry.example.com/ubuntu:latest\");\n\t\tString authHeader = getAuthHeader(imageReference);\n\t\tassertThat(authHeader).isNotNull();\n\t\tassertThat(decode(authHeader)).hasSize(4)\n\t\t\t.containsEntry(\"serveraddress\", \"my-registry.example.com\")\n\t\t\t.containsEntry(\"username\", \"username\")\n\t\t\t.containsEntry(\"password\", \"secret\")\n\t\t\t.containsEntry(\"email\", \"test@example.com\");\n\t}\n\n\tprivate @Nullable String getAuthHeader(@Nullable ImageReference imageReference) {\n\t\treturn getAuthHeader(imageReference, null);\n\t}\n\n\tprivate @Nullable String getAuthHeader(@Nullable ImageReference imageReference,\n\t\t\t@Nullable DockerRegistryAuthentication fallback) {\n\t\tDockerRegistryConfigAuthentication authentication = getAuthentication(fallback);\n\t\treturn authentication.getAuthHeader(imageReference);\n\t}\n\n\tprivate DockerRegistryConfigAuthentication getAuthentication(@Nullable DockerRegistryAuthentication fallback) {\n\t\tFunction<String, @Nullable CredentialHelper> credentialHelperFactory = this.credentialHelpers::get;\n\t\treturn new DockerRegistryConfigAuthentication(fallback, this.helperExceptions::put, this.environment::get,\n\t\t\t\tcredentialHelperFactory);\n\t}\n\n\tprivate void mockHelper(String name, String serverUrl, String credentialsResourceName) throws Exception {\n\t\tCredentialHelper helper = mockHelper(name);\n\t\tgiven(helper.get(serverUrl)).willReturn(getCredentials(credentialsResourceName));\n\t}\n\n\tprivate CredentialHelper mockHelper(String name) {\n\t\tCredentialHelper helper = mock(CredentialHelper.class);\n\t\tthis.credentialHelpers.put(name, helper);\n\t\treturn helper;\n\t}\n\n\tprivate Credential getCredentials(String resourceName) throws Exception {\n\t\ttry (InputStream inputStream = new ClassPathResource(resourceName).getInputStream()) {\n\t\t\treturn new Credential(SharedJsonMapper.get().readTree(inputStream));\n\t\t}\n\t}\n\n\tprivate Map<String, String> decode(String authHeader) {\n\t\treturn SharedJsonMapper.get().readValue(Base64.getDecoder().decode(authHeader), new TypeReference<>() {\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryTokenAuthenticationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\nimport org.json.JSONException;\nimport org.junit.jupiter.api.Test;\nimport org.skyscreamer.jsonassert.JSONAssert;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Tests for {@link DockerRegistryTokenAuthentication}.\n *\n * @author Scott Frederick\n */\nclass DockerRegistryTokenAuthenticationTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid createAuthHeaderReturnsEncodedHeader() throws IOException, JSONException {\n\t\tDockerRegistryTokenAuthentication auth = new DockerRegistryTokenAuthentication(\"tokenvalue\");\n\t\tString header = auth.getAuthHeader();\n\t\tString expectedJson = StreamUtils.copyToString(getContent(\"auth-token.json\"), StandardCharsets.UTF_8);\n\t\tJSONAssert.assertEquals(expectedJson, new String(Base64.getUrlDecoder().decode(header)), true);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/DockerRegistryUserAuthenticationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\nimport org.json.JSONException;\nimport org.junit.jupiter.api.Test;\nimport org.skyscreamer.jsonassert.JSONAssert;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerRegistryUserAuthentication}.\n *\n * @author Scott Frederick\n */\nclass DockerRegistryUserAuthenticationTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid createMinimalAuthHeaderReturnsEncodedHeader() throws IOException, JSONException {\n\t\tDockerRegistryUserAuthentication auth = new DockerRegistryUserAuthentication(\"user\", \"secret\",\n\t\t\t\t\"https://docker.example.com\", \"docker@example.com\");\n\t\tString authHeader = auth.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tJSONAssert.assertEquals(jsonContent(\"auth-user-full.json\"), decoded(authHeader), true);\n\t}\n\n\t@Test\n\tvoid createFullAuthHeaderReturnsEncodedHeader() throws IOException, JSONException {\n\t\tDockerRegistryUserAuthentication auth = new DockerRegistryUserAuthentication(\"user\", \"secret\", null, null);\n\t\tString authHeader = auth.getAuthHeader();\n\t\tassertThat(authHeader).isNotNull();\n\t\tJSONAssert.assertEquals(jsonContent(\"auth-user-minimal.json\"), decoded(authHeader), false);\n\t}\n\n\tprivate String jsonContent(String s) throws IOException {\n\t\treturn StreamUtils.copyToString(getContent(s), StandardCharsets.UTF_8);\n\t}\n\n\tprivate String decoded(String header) {\n\t\treturn new String(Base64.getUrlDecoder().decode(header));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/configuration/ResolvedDockerHostTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.configuration;\n\nimport java.io.IOException;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ResolvedDockerHost}.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass ResolvedDockerHostTests {\n\n\tprivate final Map<String, String> environment = new LinkedHashMap<>();\n\n\t@Test\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid resolveWhenDockerHostIsNullReturnsLinuxDefault() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-default-context/config.json\"));\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get, null);\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"/var/run/docker.sock\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\t@EnabledOnOs(OS.WINDOWS)\n\tvoid resolveWhenDockerHostIsNullReturnsWindowsDefault() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-default-context/config.json\"));\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get, null);\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"//./pipe/docker_engine\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\t@EnabledOnOs(OS.WINDOWS)\n\tvoid resolveWhenUsingDefaultContextReturnsWindowsDefault() {\n\t\tthis.environment.put(\"DOCKER_CONTEXT\", \"default\");\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get, null);\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"//./pipe/docker_engine\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid resolveWhenUsingDefaultContextReturnsLinuxDefault() {\n\t\tthis.environment.put(\"DOCKER_CONTEXT\", \"default\");\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get, null);\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"/var/run/docker.sock\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenDockerHostAddressIsLocalReturnsAddress(@TempDir Path tempDir) throws IOException {\n\t\tString socketFilePath = Files.createTempFile(tempDir, \"remote-transport\", null).toAbsolutePath().toString();\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(socketFilePath));\n\t\tassertThat(dockerHost.isLocalFileReference()).isTrue();\n\t\tassertThat(dockerHost.isRemote()).isFalse();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(socketFilePath);\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenDockerHostAddressIsLocalWithSchemeReturnsAddress(@TempDir Path tempDir) throws IOException {\n\t\tString socketFilePath = Files.createTempFile(tempDir, \"remote-transport\", null).toAbsolutePath().toString();\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"unix://\" + socketFilePath));\n\t\tassertThat(dockerHost.isLocalFileReference()).isTrue();\n\t\tassertThat(dockerHost.isRemote()).isFalse();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(socketFilePath);\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenDockerHostAddressIsHttpReturnsAddress() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"http://docker.example.com\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isFalse();\n\t\tassertThat(dockerHost.isRemote()).isTrue();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"http://docker.example.com\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenDockerHostAddressIsHttpsReturnsAddress() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"https://docker.example.com\", true, \"/cert-path\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isFalse();\n\t\tassertThat(dockerHost.isRemote()).isTrue();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"https://docker.example.com\");\n\t\tassertThat(dockerHost.isSecure()).isTrue();\n\t\tassertThat(dockerHost.getCertificatePath()).isEqualTo(\"/cert-path\");\n\t}\n\n\t@Test\n\tvoid resolveWhenDockerHostAddressIsTcpReturnsAddress() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"tcp://192.168.99.100:2376\", true, \"/cert-path\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isFalse();\n\t\tassertThat(dockerHost.isRemote()).isTrue();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"tcp://192.168.99.100:2376\");\n\t\tassertThat(dockerHost.isSecure()).isTrue();\n\t\tassertThat(dockerHost.getCertificatePath()).isEqualTo(\"/cert-path\");\n\t}\n\n\t@Test\n\tvoid resolveWhenDockerHostAddressIsTcpWithTrailingReturnsAddress() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"tcp://192.168.99.100:2376/\", true, \"/cert-path\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isFalse();\n\t\tassertThat(dockerHost.isRemote()).isTrue();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"tcp://192.168.99.100:2376\");\n\t\tassertThat(dockerHost.isSecure()).isTrue();\n\t\tassertThat(dockerHost.getCertificatePath()).isEqualTo(\"/cert-path\");\n\t}\n\n\t@Test\n\tvoid resolveWhenEnvironmentAddressIsLocalReturnsAddress(@TempDir Path tempDir) throws IOException {\n\t\tString socketFilePath = Files.createTempFile(tempDir, \"remote-transport\", null).toAbsolutePath().toString();\n\t\tthis.environment.put(\"DOCKER_HOST\", socketFilePath);\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"/unused\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isTrue();\n\t\tassertThat(dockerHost.isRemote()).isFalse();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(socketFilePath);\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenEnvironmentAddressIsLocalWithSchemeReturnsAddress(@TempDir Path tempDir) throws IOException {\n\t\tString socketFilePath = Files.createTempFile(tempDir, \"remote-transport\", null).toAbsolutePath().toString();\n\t\tthis.environment.put(\"DOCKER_HOST\", \"unix://\" + socketFilePath);\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"/unused\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isTrue();\n\t\tassertThat(dockerHost.isRemote()).isFalse();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(socketFilePath);\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenEnvironmentAddressIsTcpReturnsAddress() {\n\t\tthis.environment.put(\"DOCKER_HOST\", \"tcp://192.168.99.100:2376\");\n\t\tthis.environment.put(\"DOCKER_TLS_VERIFY\", \"1\");\n\t\tthis.environment.put(\"DOCKER_CERT_PATH\", \"/cert-path\");\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"tcp://1.1.1.1\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isFalse();\n\t\tassertThat(dockerHost.isRemote()).isTrue();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"tcp://192.168.99.100:2376\");\n\t\tassertThat(dockerHost.isSecure()).isTrue();\n\t\tassertThat(dockerHost.getCertificatePath()).isEqualTo(\"/cert-path\");\n\t}\n\n\t@Test\n\tvoid resolveWhenEnvironmentAddressIsTcpWithTrailingSlashReturnsAddress() {\n\t\tthis.environment.put(\"DOCKER_HOST\", \"tcp://192.168.99.100:2376/\");\n\t\tthis.environment.put(\"DOCKER_TLS_VERIFY\", \"1\");\n\t\tthis.environment.put(\"DOCKER_CERT_PATH\", \"/cert-path\");\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Host(\"tcp://1.1.1.1\"));\n\t\tassertThat(dockerHost.isLocalFileReference()).isFalse();\n\t\tassertThat(dockerHost.isRemote()).isTrue();\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"tcp://192.168.99.100:2376\");\n\t\tassertThat(dockerHost.isSecure()).isTrue();\n\t\tassertThat(dockerHost.getCertificatePath()).isEqualTo(\"/cert-path\");\n\t}\n\n\t@Test\n\tvoid resolveWithDockerHostContextReturnsAddress() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-default-context/config.json\"));\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get,\n\t\t\t\tnew DockerConnectionConfiguration.Context(\"test-context\"));\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"/home/user/.docker/docker.sock\");\n\t\tassertThat(dockerHost.isSecure()).isTrue();\n\t\tassertThat(dockerHost.getCertificatePath()).isNotNull();\n\t}\n\n\t@Test\n\tvoid resolveWithDockerConfigMetadataContextReturnsAddress() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-context/config.json\"));\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get, null);\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"/home/user/.docker/docker.sock\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenEnvironmentHasAddressAndContextPrefersContext() throws Exception {\n\t\tthis.environment.put(\"DOCKER_CONFIG\", pathToResource(\"with-context/config.json\"));\n\t\tthis.environment.put(\"DOCKER_CONTEXT\", \"test-context\");\n\t\tthis.environment.put(\"DOCKER_HOST\", \"notused\");\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(this.environment::get, null);\n\t\tassertThat(dockerHost.getAddress()).isEqualTo(\"/home/user/.docker/docker.sock\");\n\t\tassertThat(dockerHost.isSecure()).isFalse();\n\t\tassertThat(dockerHost.getCertificatePath()).isNull();\n\t}\n\n\tprivate String pathToResource(String resource) throws URISyntaxException {\n\t\tURL url = getClass().getResource(resource);\n\t\tPath parent = Paths.get(url.toURI()).getParent();\n\t\tassertThat(parent).isNotNull();\n\t\treturn parent.toAbsolutePath().toString();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ssl/KeyStoreFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.UnrecoverableKeyException;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link KeyStoreFactory}.\n *\n * @author Scott Frederick\n */\nclass KeyStoreFactoryTests {\n\n\tprivate PemFileWriter fileWriter;\n\n\t@BeforeEach\n\tvoid setUp() throws IOException {\n\t\tthis.fileWriter = new PemFileWriter();\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws IOException {\n\t\tthis.fileWriter.cleanup();\n\t}\n\n\t@Test\n\tvoid createKeyStoreWithCertChain()\n\t\t\tthrows IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {\n\t\tPath certPath = this.fileWriter.writeFile(\"cert.pem\", PemFileWriter.CA_CERTIFICATE, PemFileWriter.CERTIFICATE);\n\t\tKeyStore keyStore = KeyStoreFactory.create(certPath, null, \"test-alias\");\n\t\tassertThat(keyStore.containsAlias(\"test-alias-0\")).isTrue();\n\t\tassertThat(keyStore.getCertificate(\"test-alias-0\")).isNotNull();\n\t\tassertThat(keyStore.getKey(\"test-alias-0\", new char[] {})).isNull();\n\t\tassertThat(keyStore.containsAlias(\"test-alias-1\")).isTrue();\n\t\tassertThat(keyStore.getCertificate(\"test-alias-1\")).isNotNull();\n\t\tassertThat(keyStore.getKey(\"test-alias-1\", new char[] {})).isNull();\n\t}\n\n\t@Test\n\tvoid createKeyStoreWithCertChainAndRsaPrivateKey()\n\t\t\tthrows IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {\n\t\tPath certPath = this.fileWriter.writeFile(\"cert.pem\", PemFileWriter.CA_CERTIFICATE, PemFileWriter.CERTIFICATE);\n\t\tPath keyPath = this.fileWriter.writeFile(\"key.pem\", PemFileWriter.PRIVATE_RSA_KEY);\n\t\tKeyStore keyStore = KeyStoreFactory.create(certPath, keyPath, \"test-alias\");\n\t\tassertThat(keyStore.containsAlias(\"test-alias\")).isTrue();\n\t\tassertThat(keyStore.getCertificate(\"test-alias\")).isNotNull();\n\t\tassertThat(keyStore.getKey(\"test-alias\", new char[] {})).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ssl/PemCertificateParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PemCertificateParser}.\n *\n * @author Phillip Webb\n */\nclass PemCertificateParserTests {\n\n\tprivate static final String SOURCE = \"PemCertificateParser.java\";\n\n\t@Test\n\tvoid codeShouldMatchSpringBootSslPackage() throws IOException {\n\t\tString buildpackVersion = SslSource.loadBuildpackVersion(SOURCE);\n\t\tString springBootVersion = SslSource.loadSpringBootVersion(SOURCE);\n\t\tassertThat(buildpackVersion).isEqualTo(springBootVersion);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ssl/PemFileWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\n\nimport org.springframework.util.FileSystemUtils;\n\n/**\n * Utility to write certificate and key PEM files for testing.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\npublic class PemFileWriter {\n\n\tprivate static final String EXAMPLE_SECRET_QUALIFIER = \"example\";\n\n\tpublic static final String CA_CERTIFICATE = \"\"\"\n\t\t\t-----BEGIN TRUSTED CERTIFICATE-----\n\t\t\tMIIClzCCAgACCQCPbjkRoMVEQDANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMC\n\t\t\tVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x\n\t\t\tDTALBgNVBAoMBFRlc3QxDTALBgNVBAsMBFRlc3QxFDASBgNVBAMMC2V4YW1wbGUu\n\t\t\tY29tMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTIwMDMyNzIx\n\t\t\tNTgwNFoXDTIxMDMyNzIxNTgwNFowgY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD\n\t\t\tYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARUZXN0\n\t\t\tMQ0wCwYDVQQLDARUZXN0MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3\n\t\t\tDQEJARYQdGVzdEBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\n\t\t\tgYEA1YzixWEoyzrd20C2R1gjyPCoPfFLlG6UYTyT0tueNy6yjv6qbJ8lcZg7616O\n\t\t\t3I9LuOHhZh9U+fCDCgPfiDdyJfDEW/P+dsOMFyMUXPrJPze2yPpOnvV8iJ5DM93u\n\t\t\tfEVhCCyzLdYu0P2P3hU2W+T3/Im9DA7FOPA2vF1SrIJ2qtUCAwEAATANBgkqhkiG\n\t\t\t9w0BAQUFAAOBgQBdShkwUv78vkn1jAdtfbB+7mpV9tufVdo29j7pmotTCz3ny5fc\n\t\t\tzLEfeu6JPugAR71JYbc2CqGrMneSk1zT91EH6ohIz8OR5VNvzB7N7q65Ci7OFMPl\n\t\t\tly6k3rHpMCBtHoyNFhNVfPLxGJ9VlWFKLgIAbCmL4OIQm1l6Fr1MSM38Zw==\n\t\t\t-----END TRUSTED CERTIFICATE-----\n\t\t\t\"\"\";\n\n\tpublic static final String CERTIFICATE = \"\"\"\n\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\tMIICjzCCAfgCAQEwDQYJKoZIhvcNAQEFBQAwgY8xCzAJBgNVBAYTAlVTMRMwEQYD\n\t\t\tVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQK\n\t\t\tDARUZXN0MQ0wCwYDVQQLDARUZXN0MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0G\n\t\t\tCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0yMDAzMjcyMjAxNDZaFw0y\n\t\t\tMTAzMjcyMjAxNDZaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p\n\t\t\tYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwEVGVzdDENMAsGA1UE\n\t\t\tCwwEVGVzdDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRl\n\t\t\tc3RAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM7kd2cj\n\t\t\tF49wm1+OQ7Q5GE96cXueWNPr/Nwei71tf6G4BmE0B+suXHEvnLpHTj9pdX/ZzBIK\n\t\t\t8jIZ/x8RnSduK/Ky+zm1QMYUWZtWCAgCW8WzgB69Cn/hQG8KSX3S9bqODuQAvP54\n\t\t\tGQJD7+4kVuNBGjFb4DaD4nvMmPtALSZf8ZCZAgMBAAEwDQYJKoZIhvcNAQEFBQAD\n\t\t\tgYEAOn6X8+0VVlDjF+TvTgI0KIasA6nDm+KXe7LVtfvqWqQZH4qyd2uiwcDM3Aux\n\t\t\ta/OsPdOw0j+NqFDBd3mSMhSVgfvXdK6j9WaxY1VGXyaidLARgvn63wfzgr857sQW\n\t\t\tc8eSxbwEQxwlMvVxW6Os4VhCfUQr8VrBrvPa2zs+6IlK+Ug=\n\t\t\t-----END CERTIFICATE-----\n\t\t\t\"\"\";\n\n\tpublic static final String PRIVATE_RSA_KEY = \"\"\"\n\t\t\t%s-----BEGIN RSA PRIVATE KEY-----\n\t\t\tMIICXAIBAAKBgQDO5HdnIxePcJtfjkO0ORhPenF7nljT6/zcHou9bX+huAZhNAfr\n\t\t\tLlxxL5y6R04/aXV/2cwSCvIyGf8fEZ0nbivysvs5tUDGFFmbVggIAlvFs4AevQp/\n\t\t\t4UBvCkl90vW6jg7kALz+eBkCQ+/uJFbjQRoxW+A2g+J7zJj7QC0mX/GQmQIDAQAB\n\t\t\tAoGAIWPsBWA7gDHrUYuzT5XbX5BiWlIfAezXPWtMoEDY1W/Oz8dG8+TilH3brJCv\n\t\t\thzps9TpgXhUYK4/Yhdog4+k6/EEY80RvcObOnflazTCVS041B0Ipm27uZjIq2+1F\n\t\t\tZfbWP+B3crpzh8wvIYA+6BCcZV9zi8Od32NEs39CtrOrFPUCQQDxnt9+JlWjtteR\n\t\t\tVttRSKjtzKIF08BzNuZlRP9HNWveLhphIvdwBfjASwqgtuslqziEnGG8kniWzyYB\n\t\t\ta/ZZVoT3AkEA2zSBMpvGPDkGbOMqbnR8UL3uijkOj+blQe1gsyu3dUa9T42O1u9h\n\t\t\tIz5SdCYlSFHbDNRFrwuW2QnhippqIQqC7wJAbVeyWEpM0yu5XiJqWdyB5iuG3xA2\n\t\t\ttW0Q0p9ozvbT+9XtRiwmweFR8uOCybw9qexURV7ntAis3cKctmP/Neq7fQJBAKGa\n\t\t\t59UjutYTRIVqRJICFtR/8ii9P9sfYs1j7/KnvC0d5duMhU44VOjivW8b4Eic8F1Y\n\t\t\t8bbHWILSIhFJHg0V7skCQDa8/YkRWF/3pwIZNWQr4ce4OzvYsFMkRvGRdX8B2a0p\n\t\t\twSKcVTdEdO2DhBlYddN0zG0rjq4vDMtdmldEl4BdldQ=\n\t\t\t-----END RSA PRIVATE KEY-----\n\t\t\t\"\"\".formatted(EXAMPLE_SECRET_QUALIFIER);\n\n\tpublic static final String PRIVATE_EC_KEY = EXAMPLE_SECRET_QUALIFIER + \"-----BEGIN EC PRIVATE KEY-----\\n\"\n\t\t\t+ \"MIGkAgEBBDB21WGGOb1DokKW0MUHO7RQ6jZSUYXfO2iyfCbjmSJhyK8fSuq1V0N2\\n\"\n\t\t\t+ \"Bj7X+XYhS6ygBwYFK4EEACKhZANiAATsRaYri/tDMvrrB2NJlxWFOZ4YBLYdSM+a\\n\"\n\t\t\t+ \"FlGh1FuLjOHW9cx8w0iRHd1Hxn4sxqsa62KzGoCj63lGoaJgi67YNCF0lBa/zCLy\\n\"\n\t\t\t+ \"ktaMsQePDOR8UR0Cfi2J9bh+IjxXd+o=\\n\" + \"-----END EC PRIVATE KEY-----\";\n\n\tpublic static final String PRIVATE_EC_KEY_PRIME_256_V1 = EXAMPLE_SECRET_QUALIFIER\n\t\t\t+ \"-----BEGIN EC PRIVATE KEY-----\\n\" + \"MHcCAQEEIIwZkO8Zjbggzi8wwrk5rzSPzUX31gqTRhBYw4AL6w44oAoGCCqGSM49\\n\"\n\t\t\t+ \"AwEHoUQDQgAE8y28khug747bA68M90IAMCPHAYyen+RsN6i84LORpNDUhv00QZWd\\n\"\n\t\t\t+ \"hOhjWFCQjnewR98Y8pEb1fnORll4LhHPlQ==\\n\" + \"-----END EC PRIVATE KEY-----\";\n\n\tpublic static final String PRIVATE_DSA_KEY = EXAMPLE_SECRET_QUALIFIER + \"-----BEGIN PRIVATE KEY-----\\n\"\n\t\t\t+ \"MIICXAIBADCCAjUGByqGSM44BAEwggIoAoIBAQCPeTXZuarpv6vtiHrPSVG28y7F\\n\"\n\t\t\t+ \"njuvNxjo6sSWHz79NgbnQ1GpxBgzObgJ58KuHFObp0dbhdARrbi0eYd1SYRpXKwO\\n\"\n\t\t\t+ \"jxSzNggooi/6JxEKPWKpk0U0CaD+aWxGWPhL3SCBnDcJoBBXsZWtzQAjPbpUhLYp\\n\"\n\t\t\t+ \"H51kjviDRIZ3l5zsBLQ0pqwudemYXeI9sCkvwRGMn/qdgYHnM423krcw17njSVkv\\n\"\n\t\t\t+ \"aAmYchU5Feo9a4tGU8YzRY+AOzKkwuDycpAlbk4/ijsIOKHEUOThjBopo33fXqFD\\n\"\n\t\t\t+ \"3ktm/wSQPtXPFiPhWNSHxgjpfyEc2B3KI8tuOAdl+CLjQr5ITAV2OTlgHNZnAh0A\\n\"\n\t\t\t+ \"uvaWpoV499/e5/pnyXfHhe8ysjO65YDAvNVpXQKCAQAWplxYIEhQcE51AqOXVwQN\\n\"\n\t\t\t+ \"NNo6NHjBVNTkpcAtJC7gT5bmHkvQkEq9rI837rHgnzGC0jyQQ8tkL4gAQWDt+coJ\\n\"\n\t\t\t+ \"syB2p5wypifyRz6Rh5uixOdEvSCBVEy1W4AsNo0fqD7UielOD6BojjJCilx4xHjG\\n\"\n\t\t\t+ \"jQUntxyaOrsLC+EsRGiWOefTznTbEBplqiuH9kxoJts+xy9LVZmDS7TtsC98kOmk\\n\"\n\t\t\t+ \"ltOlXVNb6/xF1PYZ9j897buHOSXC8iTgdzEpbaiH7B5HSPh++1/et1SEMWsiMt7l\\n\"\n\t\t\t+ \"U92vAhErDR8C2jCXMiT+J67ai51LKSLZuovjntnhA6Y8UoELxoi34u1DFuHvF9ve\\n\"\n\t\t\t+ \"BB4CHHBQgJ3ST6U8rIxoTqGe42TiVckPf1PoSiJy8GY=\\n\" + \"-----END PRIVATE KEY-----\\n\";\n\n\tpublic static final String PKCS8_PRIVATE_EC_NIST_P256_KEY = EXAMPLE_SECRET_QUALIFIER\n\t\t\t+ \"-----BEGIN PRIVATE KEY-----\\n\" + \"MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgd6SePFfpaTKFd1Gm\\n\"\n\t\t\t+ \"+WeHZNkORkot5hx6X9elPdICL9ygCgYIKoZIzj0DAQehRANCAASnMAMgeFBv9ks0\\n\"\n\t\t\t+ \"d0jP+utQ3mohwmxY93xljfaBofdg1IeHgDd4I4pBzPxEnvXrU3kcz+SgPZyH1ybl\\n\" + \"P6mSXDXu\\n\"\n\t\t\t+ \"-----END PRIVATE KEY-----\\n\";\n\n\tpublic static final String PKCS8_PRIVATE_EC_NIST_P384_KEY = EXAMPLE_SECRET_QUALIFIER\n\t\t\t+ \"-----BEGIN PRIVATE KEY-----\\n\" + \"MIG/AgEAMBAGByqGSM49AgEGBSuBBAAiBIGnMIGkAgEBBDCexXiWKrtrqV1+d1Tv\\n\"\n\t\t\t+ \"t1n5huuw2A+204mQHRuPL9UC8l0XniJjx/PVELCciyJM/7+gBwYFK4EEACKhZANi\\n\"\n\t\t\t+ \"AASHEELZSdrHiSXqU1B+/jrOCr6yjxCMqQsetTb0q5WZdCXOhggGXfbzlRynqphQ\\n\"\n\t\t\t+ \"i4G7azBUklgLaXfxN5eFk6C+E38SYOR7iippcQsSR2ZsCiTk7rnur4b40gQ7IgLA\\n\" + \"/sU=\\n\"\n\t\t\t+ \"-----END PRIVATE KEY-----\\n\";\n\n\tpublic static final String PKCS8_PRIVATE_EC_PRIME256V1_KEY = EXAMPLE_SECRET_QUALIFIER\n\t\t\t+ \"-----BEGIN PRIVATE KEY-----\\n\" + \"MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg4dVuddgQ6enDvPPw\\n\"\n\t\t\t+ \"Dd1mmS6FMm/kzTJjDVsltrNmRuSgCgYIKoZIzj0DAQehRANCAAR1WMrRADEaVj9m\\n\"\n\t\t\t+ \"uoUfPhUefJK+lS89NHikQ0ZdkHkybyVKLFMLe1hCynhzpKQmnpgud3E10F0P2PZQ\\n\" + \"L9RCEpGf\\n\"\n\t\t\t+ \"-----END PRIVATE KEY-----\\n\";\n\n\tpublic static final String PKCS8_PRIVATE_EC_SECP256R1_KEY = EXAMPLE_SECRET_QUALIFIER\n\t\t\t+ \"-----BEGIN PRIVATE KEY-----\\n\" + \"MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgU9+v5hUNnTKix8fe\\n\"\n\t\t\t+ \"Pfz+NfXFlGxQZMReSCT2Id9PfKagCgYIKoZIzj0DAQehRANCAATeJg+YS4BrJ35A\\n\"\n\t\t\t+ \"KgRlZ59yKLDpmENCMoaYUuWbQ9hqHzdybQGzQsrNJqgH0nzWghPwP4nFaLPN+pgB\\n\" + \"bqiRgbjG\\n\"\n\t\t\t+ \"-----END PRIVATE KEY-----\\n\";\n\n\tpublic static final String PKCS8_PRIVATE_RSA_KEY = EXAMPLE_SECRET_QUALIFIER + \"-----BEGIN PRIVATE KEY-----\\n\"\n\t\t\t+ \"MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDR0KfxUw7MF/8R\\n\"\n\t\t\t+ \"B5/YXOM7yLnoHYb/M/6dyoulMbtEdKKhQhU28o5FiDkHcEG9PJQLgqrRgAjl3VmC\\n\"\n\t\t\t+ \"C9omtfZJQ2EpfkTttkJjnKOOroXhYE51/CYSckapBYCVh8GkjUEJuEfnp07cTfYZ\\n\"\n\t\t\t+ \"FqViIgIWPZyjkzl3w4girS7kCuzNdDntVJVx5F/EsFwMA8n3C0QazHQoM5s00Fer\\n\"\n\t\t\t+ \"6aTwd6AW0JD5QkADavpfzZ554e4HrVGwHlM28WKQQkFzzGu44FFXyVuEF3HeyVPu\\n\"\n\t\t\t+ \"g8GRHAc8UU7ijVgJB5TmbvRGYowIErD5i4VvGLuOv9mgR3aVyN0SdJ1N7aJnXpeS\\n\"\n\t\t\t+ \"QjAgf03jAgMBAAECggEBAIhQyzwj3WJGWOZkkLqOpufJotcmj/Wwf0VfOdkq9WMl\\n\"\n\t\t\t+ \"cB/bAlN/xWVxerPVgDCFch4EWBzi1WUaqbOvJZ2u7QNubmr56aiTmJCFTVI/GyZx\\n\"\n\t\t\t+ \"XqiTGN01N6lKtN7xo6LYTyAUhUsBTWAemrx0FSErvTVb9C/mUBj6hbEZ2XQ5kN5t\\n\"\n\t\t\t+ \"7qYX4Lu0zyn7s1kX5SLtm5I+YRq7HSwB6wLy+DSroO71izZ/VPwME3SwT5SN+c87\\n\"\n\t\t\t+ \"3dkklR7fumNd9dOpSWKrLPnq4aMko00rvIGc63xD1HrEpXUkB5v24YEn7HwCLEH7\\n\"\n\t\t\t+ \"b8jrp79j2nCvvR47inpf+BR8FIWAHEOUUqCEzjQkdiECgYEA6ifjMM0f02KPeIs7\\n\"\n\t\t\t+ \"zXd1lI7CUmJmzkcklCIpEbKWf/t/PHv3QgqIkJzERzRaJ8b+GhQ4zrSwAhrGUmI8\\n\"\n\t\t\t+ \"kDkXIqe2/2ONgIOX2UOHYHyTDQZHnlXyDecvHUTqs2JQZCGBZkXyZ9i0j3BnTymC\\n\"\n\t\t\t+ \"iZ8DvEa0nxsbP+U3rgzPQmXiQVMCgYEA5WN2Y/RndbriNsNrsHYRldbPO5nfV9rp\\n\"\n\t\t\t+ \"cDzcQU66HRdK5VIdbXT9tlMYCJIZsSqE0tkOwTgEB/sFvF/tIHSCY5iO6hpIyk6g\\n\"\n\t\t\t+ \"kkUzPcld4eM0dEPAge7SYUbakB9CMvA7MkDQSXQNFyZ0mH83+UikwT6uYHFh7+ox\\n\"\n\t\t\t+ \"N1P+psDhXzECgYEA1gXLVQnIcy/9LxMkgDMWV8j8uMyUZysDthpbK3/uq+A2dhRg\\n\"\n\t\t\t+ \"9g4msPd5OBQT65OpIjElk1n4HpRWfWqpLLHiAZ0GWPynk7W0D7P3gyuaRSdeQs0P\\n\"\n\t\t\t+ \"x8FtgPVDCN9t13gAjHiWjnC26Py2kNbCKAQeJ/MAmQTvrUFX2VCACJKTcV0CgYAj\\n\"\n\t\t\t+ \"xJWSUmrLfb+GQISLOG3Xim434e9keJsLyEGj4U29+YLRLTOvfJ2PD3fg5j8hU/rw\\n\"\n\t\t\t+ \"Ea5uTHi8cdTcIa0M8X3fX8txD3YoLYh2JlouGTcNYOst8d6TpBSj3HN6I5Wj8beZ\\n\"\n\t\t\t+ \"R2fy/CiKYpGtsbCdq0kdZNO18BgQW9kewncjs1GxEQKBgQCf8q34h6KuHpHSDh9h\\n\"\n\t\t\t+ \"YkDTypk0FReWBAVJCzDNDUMhVLFivjcwtaMd2LiC3FMKZYodr52iKg60cj43vbYI\\n\"\n\t\t\t+ \"frmFFxoL37rTmUocCTBKc0LhWj6MicI+rcvQYe1uwTrpWdFf1aZJMYRLRczeKtev\\n\" + \"OWaE/9hVZ5+9pild1NukGpOydw==\\n\"\n\t\t\t+ \"-----END PRIVATE KEY-----\\n\";\n\n\tpublic static final String PKCS8_PRIVATE_EC_ED25519_KEY = EXAMPLE_SECRET_QUALIFIER + \"-----BEGIN PRIVATE KEY-----\\n\"\n\t\t\t+ \"MC4CAQAwBQYDK2VwBCIEIJOKNTaIJQTVuEqZ+yvclnjnlWJG6F+K+VsNCOlWRda+\\n\" + \"-----END PRIVATE KEY-----\";\n\n\tprivate final Path tempDir;\n\n\tpublic PemFileWriter() throws IOException {\n\t\tthis.tempDir = Files.createTempDirectory(\"buildpack-platform-docker-ssl-tests\");\n\t}\n\n\tPath writeFile(String name, String... contents) throws IOException {\n\t\tPath path = Paths.get(this.tempDir.toString(), name);\n\t\tfor (String content : contents) {\n\t\t\tFiles.write(path, content.replace(EXAMPLE_SECRET_QUALIFIER, \"\").getBytes(), StandardOpenOption.CREATE,\n\t\t\t\t\tStandardOpenOption.APPEND);\n\t\t}\n\t\treturn path;\n\t}\n\n\tpublic Path getTempDir() {\n\t\treturn this.tempDir;\n\t}\n\n\tvoid cleanup() throws IOException {\n\t\tFileSystemUtils.deleteRecursively(this.tempDir);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ssl/PemPrivateKeyParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PemPrivateKeyParser}.\n *\n * @author Phillip Webb\n */\nclass PemPrivateKeyParserTests {\n\n\tprivate static final String SOURCE = \"PemPrivateKeyParser.java\";\n\n\t@Test\n\tvoid codeShouldMatchSpringBootSslPackage() throws IOException {\n\t\tString buildpackVersion = SslSource.loadBuildpackVersion(SOURCE);\n\t\tString springBootVersion = SslSource.loadSpringBootVersion(SOURCE);\n\t\tassertThat(buildpackVersion).isEqualTo(springBootVersion);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ssl/SslContextFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslContextFactory}.\n *\n * @author Scott Frederick\n */\nclass SslContextFactoryTests {\n\n\tprivate PemFileWriter fileWriter;\n\n\t@BeforeEach\n\tvoid setUp() throws IOException {\n\t\tthis.fileWriter = new PemFileWriter();\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws IOException {\n\t\tthis.fileWriter.cleanup();\n\t}\n\n\t@Test\n\tvoid createKeyStoreWithCertChain() throws IOException {\n\t\tthis.fileWriter.writeFile(\"cert.pem\", PemFileWriter.CERTIFICATE);\n\t\tthis.fileWriter.writeFile(\"key.pem\", PemFileWriter.PRIVATE_RSA_KEY);\n\t\tthis.fileWriter.writeFile(\"ca.pem\", PemFileWriter.CA_CERTIFICATE);\n\t\tSSLContext sslContext = new SslContextFactory().forDirectory(this.fileWriter.getTempDir().toString());\n\t\tassertThat(sslContext).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/ssl/SslSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.ssl;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\n/**\n * Utility to compare SSL source code.\n *\n * @author Phillip Webb\n */\nfinal class SslSource {\n\n\tprivate static final Path BUILDPACK_LOCATION = Path\n\t\t.of(\"src/main/java/org/springframework/boot/buildpack/platform/docker/ssl\");\n\n\tprivate static final Path SPRINGBOOT_LOCATION = Path\n\t\t.of(\"../../core/spring-boot/src/main/java/org/springframework/boot/ssl/pem\");\n\n\tprivate SslSource() {\n\t}\n\n\tstatic String loadBuildpackVersion(String name) throws IOException {\n\t\treturn load(BUILDPACK_LOCATION.resolve(name));\n\t}\n\n\tstatic String loadSpringBootVersion(String name) throws IOException {\n\t\treturn load(SPRINGBOOT_LOCATION.resolve(name));\n\t}\n\n\tprivate static String load(Path path) throws IOException {\n\t\tString code = Files.readString(path);\n\t\tint firstBrace = code.indexOf(\"{\");\n\t\tint lastBrace = code.lastIndexOf(\"}\");\n\t\treturn code.substring(firstBrace, lastBrace + 1);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/DockerConnectionExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DockerEngineException}.\n *\n * @author Scott Frederick\n */\nclass DockerConnectionExceptionTests {\n\n\tprivate static final String HOST = \"docker://localhost/\";\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenHostIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DockerConnectionException(null, null))\n\t\t\t.withMessage(\"'host' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenCauseIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DockerConnectionException(HOST, null))\n\t\t\t.withMessage(\"'cause' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithIOException() {\n\t\tDockerConnectionException exception = new DockerConnectionException(HOST, new IOException(\"error\"));\n\t\tassertThat(exception.getMessage())\n\t\t\t.contains(\"Connection to the Docker daemon at 'docker://localhost/' failed with error \\\"error\\\"\");\n\t}\n\n\t@Test\n\tvoid createWithLastErrorException() {\n\t\tDockerConnectionException exception = new DockerConnectionException(HOST,\n\t\t\t\tnew IOException(new com.sun.jna.LastErrorException(\"root cause\")));\n\t\tassertThat(exception.getMessage())\n\t\t\t.contains(\"Connection to the Docker daemon at 'docker://localhost/' failed with error \\\"root cause\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/DockerEngineExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DockerEngineException}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass DockerEngineExceptionTests {\n\n\tprivate static final String HOST = \"docker://localhost/\";\n\n\tprivate static final URI URI;\n\tstatic {\n\t\ttry {\n\t\t\tURI = new URI(\"example\");\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate static final Errors NO_ERRORS = new Errors(Collections.emptyList());\n\n\tprivate static final Errors ERRORS = new Errors(Collections.singletonList(new Errors.Error(\"code\", \"message\")));\n\n\tprivate static final Message NO_MESSAGE = new Message(null);\n\n\tprivate static final Message MESSAGE = new Message(\"response message\");\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenHostIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DockerEngineException(null, null, 404, null, NO_ERRORS, NO_MESSAGE, null))\n\t\t\t.withMessage(\"'host' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenUriIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DockerEngineException(HOST, null, 404, null, NO_ERRORS, NO_MESSAGE, null))\n\t\t\t.withMessage(\"'uri' must not be null\");\n\t}\n\n\t@Test\n\tvoid create() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 404, \"missing\", ERRORS, MESSAGE, null);\n\t\tassertThat(exception.getMessage()).isEqualTo(\n\t\t\t\t\"Docker API call to 'docker://localhost/example' failed with status code 404 \\\"missing\\\" and message \\\"response message\\\" [code: message]\");\n\t\tassertThat(exception.getStatusCode()).isEqualTo(404);\n\t\tassertThat(exception.getReasonPhrase()).isEqualTo(\"missing\");\n\t\tassertThat(exception.getErrors()).isSameAs(ERRORS);\n\t\tassertThat(exception.getResponseMessage()).isSameAs(MESSAGE);\n\t}\n\n\t@Test\n\tvoid createWhenReasonPhraseIsNull() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 404, null, ERRORS, MESSAGE, null);\n\t\tassertThat(exception.getMessage()).isEqualTo(\n\t\t\t\t\"Docker API call to 'docker://localhost/example' failed with status code 404 and message \\\"response message\\\" [code: message]\");\n\t\tassertThat(exception.getStatusCode()).isEqualTo(404);\n\t\tassertThat(exception.getReasonPhrase()).isNull();\n\t\tassertThat(exception.getErrors()).isSameAs(ERRORS);\n\t\tassertThat(exception.getResponseMessage()).isSameAs(MESSAGE);\n\t}\n\n\t@Test\n\tvoid createWhenErrorsIsNull() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 404, \"missing\", null, MESSAGE, null);\n\t\tassertThat(exception.getMessage()).isEqualTo(\n\t\t\t\t\"Docker API call to 'docker://localhost/example' failed with status code 404 \\\"missing\\\" and message \\\"response message\\\"\");\n\t\tassertThat(exception.getErrors()).isNull();\n\t}\n\n\t@Test\n\tvoid createWhenErrorsIsEmpty() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 404, \"missing\", NO_ERRORS, MESSAGE,\n\t\t\t\tnull);\n\t\tassertThat(exception.getMessage()).isEqualTo(\n\t\t\t\t\"Docker API call to 'docker://localhost/example' failed with status code 404 \\\"missing\\\" and message \\\"response message\\\"\");\n\t\tassertThat(exception.getStatusCode()).isEqualTo(404);\n\t\tassertThat(exception.getReasonPhrase()).isEqualTo(\"missing\");\n\t\tassertThat(exception.getErrors()).isSameAs(NO_ERRORS);\n\t}\n\n\t@Test\n\tvoid createWhenMessageIsNull() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 404, \"missing\", ERRORS, null, null);\n\t\tassertThat(exception.getMessage()).isEqualTo(\n\t\t\t\t\"Docker API call to 'docker://localhost/example' failed with status code 404 \\\"missing\\\" [code: message]\");\n\t\tassertThat(exception.getResponseMessage()).isNull();\n\t}\n\n\t@Test\n\tvoid createWhenMessageIsEmpty() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 404, \"missing\", ERRORS, NO_MESSAGE,\n\t\t\t\tnull);\n\t\tassertThat(exception.getMessage()).isEqualTo(\n\t\t\t\t\"Docker API call to 'docker://localhost/example' failed with status code 404 \\\"missing\\\" [code: message]\");\n\t\tassertThat(exception.getResponseMessage()).isSameAs(NO_MESSAGE);\n\t}\n\n\t@Test\n\tvoid createWhenProxyAuthFailureWithTextContent() {\n\t\tDockerEngineException exception = new DockerEngineException(HOST, URI, 407, \"Proxy Authentication Required\",\n\t\t\t\tnull, null, \"Badness\".getBytes(StandardCharsets.UTF_8));\n\t\tassertThat(exception.getMessage())\n\t\t\t.isEqualTo(\"Docker API call to 'docker://localhost/example' failed with status code 407 \"\n\t\t\t\t\t+ \"\\\"Proxy Authentication Required\\\" and content \\\"Badness\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/ErrorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.util.Iterator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.transport.Errors.Error;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Errors}.\n *\n * @author Phillip Webb\n */\nclass ErrorsTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid readValueDeserializesJson() throws Exception {\n\t\tErrors errors = getJsonMapper().readValue(getContent(\"errors.json\"), Errors.class);\n\t\tIterator<Error> iterator = errors.iterator();\n\t\tError error1 = iterator.next();\n\t\tError error2 = iterator.next();\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t\tassertThat(error1.getCode()).isEqualTo(\"TEST1\");\n\t\tassertThat(error1.getMessage()).isEqualTo(\"Test One\");\n\t\tassertThat(error2.getCode()).isEqualTo(\"TEST2\");\n\t\tassertThat(error2.getMessage()).isEqualTo(\"Test Two\");\n\t}\n\n\t@Test\n\tvoid toStringHasErrorDetails() throws Exception {\n\t\tErrors errors = getJsonMapper().readValue(getContent(\"errors.json\"), Errors.class);\n\t\tassertThat(errors).hasToString(\"[TEST1: Test One, TEST2: Test Two]\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpClientTransportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.classic.methods.HttpDelete;\nimport org.apache.hc.client5.http.classic.methods.HttpGet;\nimport org.apache.hc.client5.http.classic.methods.HttpPost;\nimport org.apache.hc.client5.http.classic.methods.HttpPut;\nimport org.apache.hc.client5.http.classic.methods.HttpUriRequest;\nimport org.apache.hc.core5.http.ClassicHttpResponse;\nimport org.apache.hc.core5.http.HttpEntity;\nimport org.apache.hc.core5.http.HttpHeaders;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.HttpStatus;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.buildpack.platform.docker.transport.HttpTransport.Response;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link HttpClientTransport}.\n *\n * @author Phillip Webb\n * @author Mike Smithson\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\n@ExtendWith(MockitoExtension.class)\nclass HttpClientTransportTests {\n\n\tprivate static final String APPLICATION_JSON = \"application/json\";\n\n\tprivate static final String APPLICATION_X_TAR = \"application/x-tar\";\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate HttpClient client;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassicHttpResponse response;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate HttpEntity entity;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate InputStream content;\n\n\tprivate HttpClientTransport http;\n\n\tprivate URI uri;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.http = new TestHttpClientTransport(this.client);\n\t\tthis.uri = new URI(\"example\");\n\t}\n\n\t@Test\n\tvoid getShouldExecuteHttpGet() throws Exception {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.get(this.uri);\n\t\tthen(this.client).should().executeOpen(any(HttpHost.class), assertArg((request) -> {\n\t\t\ttry {\n\t\t\t\tassertThat(request).isInstanceOf(HttpGet.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull();\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}), isNull());\n\n\t}\n\n\t@Test\n\tvoid postShouldExecuteHttpPost() throws Exception {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.post(this.uri);\n\t\tthen(this.client).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPost>) (request) -> {\n\t\t\t\tassertThat(request).isInstanceOf(HttpPost.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull();\n\t\t\t\tassertThat(request.getFirstHeader(HttpClientTransport.REGISTRY_AUTH_HEADER)).isNull();\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid postWithRegistryAuthShouldExecuteHttpPostWithHeader() throws Exception {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.post(this.uri, \"auth token\");\n\t\tthen(this.client).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPost>) (request) -> {\n\t\t\t\tassertThat(request).isInstanceOf(HttpPost.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull();\n\t\t\t\tassertThat(request.getFirstHeader(HttpClientTransport.REGISTRY_AUTH_HEADER).getValue())\n\t\t\t\t\t.isEqualTo(\"auth token\");\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid postWithEmptyRegistryAuthShouldExecuteHttpPostWithoutHeader() throws Exception {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.post(this.uri, \"\");\n\t\tthen(this.client).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPost>) (request) -> {\n\t\t\t\tassertThat(request).isInstanceOf(HttpPost.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull();\n\t\t\t\tassertThat(request.getFirstHeader(HttpClientTransport.REGISTRY_AUTH_HEADER)).isNull();\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid postWithJsonContentShouldExecuteHttpPost() throws Exception {\n\t\tString content = \"test\";\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.post(this.uri, APPLICATION_JSON,\n\t\t\t\t(out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out));\n\t\tthen(this.client).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPost>) (request) -> {\n\t\t\t\tHttpEntity entity = request.getEntity();\n\t\t\t\tassertThat(request).isInstanceOf(HttpPost.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(entity.isRepeatable()).isFalse();\n\t\t\t\tassertThat(entity.getContentLength()).isEqualTo(content.length());\n\t\t\t\tassertThat(entity.getContentType()).isEqualTo(APPLICATION_JSON);\n\t\t\t\tassertThat(entity.isStreaming()).isTrue();\n\t\t\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent);\n\t\t\t\tassertThat(writeToString(entity)).isEqualTo(content);\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid postWithArchiveContentShouldExecuteHttpPost() throws Exception {\n\t\tString content = \"test\";\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.post(this.uri, APPLICATION_X_TAR,\n\t\t\t\t(out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out));\n\t\tthen(this.client).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPost>) (request) -> {\n\t\t\t\tHttpEntity entity = request.getEntity();\n\t\t\t\tassertThat(request).isInstanceOf(HttpPost.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(entity.isRepeatable()).isFalse();\n\t\t\t\tassertThat(entity.getContentLength()).isEqualTo(-1);\n\t\t\t\tassertThat(entity.getContentType()).isEqualTo(APPLICATION_X_TAR);\n\t\t\t\tassertThat(entity.isStreaming()).isTrue();\n\t\t\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent);\n\t\t\t\tassertThat(writeToString(entity)).isEqualTo(content);\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid putWithJsonContentShouldExecuteHttpPut() throws Exception {\n\t\tString content = \"test\";\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.put(this.uri, APPLICATION_JSON,\n\t\t\t\t(out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out));\n\t\tthen(this.client).should().executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPut>) (request) -> {\n\t\t\tHttpEntity entity = request.getEntity();\n\t\t\tassertThat(request).isInstanceOf(HttpPut.class);\n\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\tassertThat(entity.isRepeatable()).isFalse();\n\t\t\tassertThat(entity.getContentLength()).isEqualTo(content.length());\n\t\t\tassertThat(entity.getContentType()).isEqualTo(APPLICATION_JSON);\n\t\t\tassertThat(entity.isStreaming()).isTrue();\n\t\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent);\n\t\t\tassertThat(writeToString(entity)).isEqualTo(content);\n\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid putWithArchiveContentShouldExecuteHttpPut() throws Exception {\n\t\tString content = \"test\";\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.put(this.uri, APPLICATION_X_TAR,\n\t\t\t\t(out) -> StreamUtils.copy(content, StandardCharsets.UTF_8, out));\n\t\tthen(this.client).should().executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpPut>) (request) -> {\n\t\t\tHttpEntity entity = request.getEntity();\n\t\t\tassertThat(request).isInstanceOf(HttpPut.class);\n\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\tassertThat(entity.isRepeatable()).isFalse();\n\t\t\tassertThat(entity.getContentLength()).isEqualTo(-1);\n\t\t\tassertThat(entity.getContentType()).isEqualTo(APPLICATION_X_TAR);\n\t\t\tassertThat(entity.isStreaming()).isTrue();\n\t\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(entity::getContent);\n\t\t\tassertThat(writeToString(entity)).isEqualTo(content);\n\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid deleteShouldExecuteHttpDelete() throws Exception {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(200);\n\t\tResponse response = this.http.delete(this.uri);\n\n\t\tthen(this.client).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((ThrowingConsumer<HttpDelete>) (request) -> {\n\t\t\t\tassertThat(request).isInstanceOf(HttpDelete.class);\n\t\t\t\tassertThat(request.getUri()).isEqualTo(this.uri);\n\t\t\t\tassertThat(request.getFirstHeader(HttpHeaders.CONTENT_TYPE)).isNull();\n\t\t\t\tassertThat(response.getContent()).isSameAs(this.content);\n\t\t\t}), isNull());\n\t}\n\n\t@Test\n\tvoid executeWhenResponseIsIn400RangeShouldThrowDockerException() throws IOException {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(getClass().getResourceAsStream(\"errors.json\"));\n\t\tgiven(this.response.getCode()).willReturn(404);\n\t\tassertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getErrors()).hasSize(2);\n\t\t\t\tassertThat(ex.getResponseMessage()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid executeWhenResponseIsIn500RangeWithNoContentShouldThrowDockerException() throws IOException {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.response.getCode()).willReturn(500);\n\t\tassertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getErrors()).isNull();\n\t\t\t\tassertThat(ex.getResponseMessage()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid executeWhenResponseIsIn500RangeWithMessageShouldThrowDockerException() throws IOException {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(getClass().getResourceAsStream(\"message.json\"));\n\t\tgiven(this.response.getCode()).willReturn(500);\n\t\tassertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getErrors()).isNull();\n\t\t\t\tMessage responseMessage = ex.getResponseMessage();\n\t\t\t\tassertThat(responseMessage).isNotNull();\n\t\t\t\tassertThat(responseMessage.getMessage()).contains(\"test message\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid executeWhenResponseIsIn500RangeWithOtherContentShouldThrowDockerException() throws IOException {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(this.content);\n\t\tgiven(this.response.getCode()).willReturn(500);\n\t\tassertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getErrors()).isNull();\n\t\t\t\tassertThat(ex.getResponseMessage()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReturnErrorsAndMessage() throws IOException {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(getClass().getResourceAsStream(\"message-and-errors.json\"));\n\t\tgiven(this.response.getCode()).willReturn(404);\n\t\tassertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getErrors()).hasSize(2);\n\t\t\t\tMessage responseMessage = ex.getResponseMessage();\n\t\t\t\tassertThat(responseMessage).isNotNull();\n\t\t\t\tassertThat(responseMessage.getMessage()).contains(\"test message\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReturnContentIfProxyAuthError() throws IOException {\n\t\tgivenClientWillReturnResponse();\n\t\tgiven(this.entity.getContent()).willReturn(getClass().getResourceAsStream(\"proxy-error.txt\"));\n\t\tgiven(this.response.getCode()).willReturn(HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED);\n\t\tassertThatExceptionOfType(DockerEngineException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getErrors()).isNull();\n\t\t\t\tassertThat(ex.getResponseMessage()).isNull();\n\t\t\t\tassertThat(ex.getMessage()).contains(\"Some kind of proxy auth problem!\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid executeWhenClientThrowsIOExceptionRethrowsAsDockerException() throws IOException {\n\t\tgiven(this.client.executeOpen(any(HttpHost.class), any(HttpUriRequest.class), isNull()))\n\t\t\t.willThrow(new IOException(\"test IO exception\"));\n\t\tassertThatExceptionOfType(DockerConnectionException.class).isThrownBy(() -> this.http.get(this.uri))\n\t\t\t.satisfies((ex) -> assertThat(ex.getMessage()).contains(\"test IO exception\"));\n\t}\n\n\tprivate String writeToString(HttpEntity entity) throws IOException {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tentity.writeTo(out);\n\t\treturn out.toString(StandardCharsets.UTF_8);\n\t}\n\n\tprivate void givenClientWillReturnResponse() throws IOException {\n\t\tgiven(this.client.executeOpen(any(HttpHost.class), any(HttpUriRequest.class), isNull()))\n\t\t\t.willReturn(this.response);\n\t\tgiven(this.response.getEntity()).willReturn(this.entity);\n\t}\n\n\t/**\n\t * Test {@link HttpClientTransport} implementation.\n\t */\n\tstatic class TestHttpClientTransport extends HttpClientTransport {\n\n\t\tprotected TestHttpClientTransport(HttpClient client) throws URISyntaxException {\n\t\t\tsuper(client, HttpHost.create(\"docker://localhost\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/HttpTransportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpTransport}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass HttpTransportTests {\n\n\t@Test\n\tvoid createWhenDockerHostVariableIsAddressReturnsRemote() {\n\t\tHttpTransport transport = HttpTransport.create(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.0\"));\n\t\tassertThat(transport).isInstanceOf(RemoteHttpClientTransport.class);\n\t}\n\n\t@Test\n\tvoid createWhenDockerHostVariableIsFileReturnsLocal(@TempDir Path tempDir) throws IOException {\n\t\tString dummySocketFilePath = Files.createTempFile(tempDir, \"http-transport\", null).toAbsolutePath().toString();\n\t\tHttpTransport transport = HttpTransport.create(new DockerConnectionConfiguration.Host(dummySocketFilePath));\n\t\tassertThat(transport).isInstanceOf(LocalHttpClientTransport.class);\n\t}\n\n\t@Test\n\tvoid createWhenDockerHostVariableIsUnixSchemePrefixedFileReturnsLocal(@TempDir Path tempDir) throws IOException {\n\t\tString dummySocketFilePath = \"unix://\" + Files.createTempFile(tempDir, \"http-transport\", null).toAbsolutePath();\n\t\tHttpTransport transport = HttpTransport.create(new DockerConnectionConfiguration.Host(dummySocketFilePath));\n\t\tassertThat(transport).isInstanceOf(LocalHttpClientTransport.class);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/LocalHttpClientTransportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LocalHttpClientTransport}\n *\n * @author Scott Frederick\n */\nclass LocalHttpClientTransportTests {\n\n\t@Test\n\tvoid createWhenDockerHostIsFileReturnsTransport(@TempDir Path tempDir) throws IOException {\n\t\tString socketFilePath = Files.createTempFile(tempDir, \"remote-transport\", null).toAbsolutePath().toString();\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(new DockerConnectionConfiguration.Host(socketFilePath));\n\t\tLocalHttpClientTransport transport = LocalHttpClientTransport.create(dockerHost);\n\t\tassertThat(transport).isNotNull();\n\t\tassertThat(transport.getHost().toHostString()).isEqualTo(socketFilePath);\n\t}\n\n\t@Test\n\tvoid createWhenDockerHostIsFileThatDoesNotExistReturnsTransport(@TempDir Path tempDir) {\n\t\tString socketFilePath = Paths.get(tempDir.toString(), \"dummy\").toAbsolutePath().toString();\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from(new DockerConnectionConfiguration.Host(socketFilePath));\n\t\tLocalHttpClientTransport transport = LocalHttpClientTransport.create(dockerHost);\n\t\tassertThat(transport).isNotNull();\n\t\tassertThat(transport.getHost().toHostString()).isEqualTo(socketFilePath);\n\t}\n\n\t@Test\n\tvoid createWhenDockerHostIsAddressReturnsTransport() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost\n\t\t\t.from(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.2:2376\"));\n\t\tLocalHttpClientTransport transport = LocalHttpClientTransport.create(dockerHost);\n\t\tassertThat(transport).isNotNull();\n\t\tassertThat(transport.getHost().toHostString()).isEqualTo(\"tcp://192.168.1.2:2376\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/MessageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Message}.\n *\n * @author Scott Frederick\n */\nclass MessageTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid readValueDeserializesJson() throws Exception {\n\t\tMessage message = getJsonMapper().readValue(getContent(\"message.json\"), Message.class);\n\t\tassertThat(message.getMessage()).isEqualTo(\"test message\");\n\t}\n\n\t@Test\n\tvoid toStringHasErrorDetails() throws Exception {\n\t\tMessage errors = getJsonMapper().readValue(getContent(\"message.json\"), Message.class);\n\t\tassertThat(errors).hasToString(\"test message\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/RemoteHttpClientTransportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.util.function.Consumer;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.hc.core5.http.HttpHost;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.configuration.DockerConnectionConfiguration;\nimport org.springframework.boot.buildpack.platform.docker.configuration.ResolvedDockerHost;\nimport org.springframework.boot.buildpack.platform.docker.ssl.SslContextFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RemoteHttpClientTransport}\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nclass RemoteHttpClientTransportTests {\n\n\t@Test\n\tvoid createIfPossibleWhenDockerHostIsNotSetReturnsNull() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost.from((DockerConnectionConfiguration) null);\n\t\tRemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(dockerHost);\n\t\tassertThat(transport).isNull();\n\t}\n\n\t@Test\n\tvoid createIfPossibleWhenDockerHostIsFileReturnsNull() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost\n\t\t\t.from(new DockerConnectionConfiguration.Host(\"unix:///var/run/socket.sock\"));\n\t\tRemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(dockerHost);\n\t\tassertThat(transport).isNull();\n\t}\n\n\t@Test\n\tvoid createIfPossibleWhenDockerHostIsAddressReturnsTransport() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost\n\t\t\t.from(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.2:2376\"));\n\t\tRemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(dockerHost);\n\t\tassertThat(transport).isNotNull();\n\t}\n\n\t@Test\n\tvoid createIfPossibleWhenNoTlsVerifyUsesHttp() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost\n\t\t\t.from(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.2:2376\"));\n\t\tRemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(dockerHost);\n\t\tassertThat(transport).isNotNull();\n\t\tassertThat(transport.getHost()).satisfies(hostOf(\"http\", \"192.168.1.2\", 2376));\n\t}\n\n\t@Test\n\tvoid createIfPossibleWhenTlsVerifyUsesHttps() throws Exception {\n\t\tSslContextFactory sslContextFactory = mock(SslContextFactory.class);\n\t\tgiven(sslContextFactory.forDirectory(\"/test-cert-path\")).willReturn(SSLContext.getDefault());\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost\n\t\t\t.from(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.2:2376\", true, \"/test-cert-path\"));\n\t\tRemoteHttpClientTransport transport = RemoteHttpClientTransport.createIfPossible(dockerHost, sslContextFactory);\n\t\tassertThat(transport).isNotNull();\n\t\tassertThat(transport.getHost()).satisfies(hostOf(\"https\", \"192.168.1.2\", 2376));\n\t}\n\n\t@Test\n\tvoid createIfPossibleWhenTlsVerifyWithMissingCertPathThrowsException() {\n\t\tResolvedDockerHost dockerHost = ResolvedDockerHost\n\t\t\t.from(new DockerConnectionConfiguration.Host(\"tcp://192.168.1.2:2376\", true, null));\n\t\tassertThatIllegalStateException().isThrownBy(() -> RemoteHttpClientTransport.createIfPossible(dockerHost))\n\t\t\t.withMessageContaining(\"Docker host TLS verification requires trust material\");\n\t}\n\n\tprivate Consumer<HttpHost> hostOf(String scheme, String hostName, int port) {\n\t\treturn (host) -> {\n\t\t\tassertThat(host).isNotNull();\n\t\t\tassertThat(host.getSchemeName()).isEqualTo(scheme);\n\t\t\tassertThat(host.getHostName()).isEqualTo(hostName);\n\t\t\tassertThat(host.getPort()).isEqualTo(port);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/transport/TestDockerEngineException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.transport;\n\nimport java.net.URI;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Subclass of {@link DockerEngineException} for testing.\n *\n * @author Phillip Webb\n */\npublic class TestDockerEngineException extends DockerEngineException {\n\n\tpublic TestDockerEngineException(String host, URI uri, int statusCode, @Nullable String reasonPhrase,\n\t\t\t@Nullable Errors errors, @Nullable Message responseMessage, byte @Nullable [] content) {\n\t\tsuper(host, uri, statusCode, reasonPhrase, errors, responseMessage, content);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/BindingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.CsvSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Binding}.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass BindingTests {\n\n\t@Test\n\tvoid ofReturnsValue() {\n\t\tBinding binding = Binding.of(\"host-src:container-dest:ro\");\n\t\tassertThat(binding).hasToString(\"host-src:container-dest:ro\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWithNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Binding.of(null))\n\t\t\t.withMessageContaining(\"'value' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromReturnsValue() {\n\t\tBinding binding = Binding.from(\"host-src\", \"container-dest\");\n\t\tassertThat(binding).hasToString(\"host-src:container-dest\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromWithNullSourceThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Binding.from((String) null, \"container-dest\"))\n\t\t\t.withMessageContaining(\"'source' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromWithNullDestinationThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Binding.from(\"host-src\", null))\n\t\t\t.withMessageContaining(\"'destination' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromVolumeNameSourceReturnsValue() {\n\t\tBinding binding = Binding.from(VolumeName.of(\"host-src\"), \"container-dest\");\n\t\tassertThat(binding).hasToString(\"host-src:container-dest\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromVolumeNameSourceWithNullSourceThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Binding.from((VolumeName) null, \"container-dest\"))\n\t\t\t.withMessageContaining(\"'sourceVolume' must not be null\");\n\t}\n\n\t@Test\n\tvoid shouldReturnContainerDestinationPath() {\n\t\tBinding binding = Binding.from(\"/host\", \"/container\");\n\t\tassertThat(binding.getContainerDestinationPath()).isEqualTo(\"/container\");\n\t}\n\n\t@Test\n\tvoid shouldReturnContainerDestinationPathWithOptions() {\n\t\tBinding binding = Binding.of(\"/host:/container:ro\");\n\t\tassertThat(binding.getContainerDestinationPath()).isEqualTo(\"/container\");\n\t}\n\n\t@Test\n\tvoid shouldReturnContainerDestinationPathOnWindows() {\n\t\tBinding binding = Binding.from(\"C:\\\\host\", \"C:\\\\container\");\n\t\tassertThat(binding.getContainerDestinationPath()).isEqualTo(\"C:\\\\container\");\n\t}\n\n\t@Test\n\tvoid shouldReturnContainerDestinationPathOnWindowsWithOptions() {\n\t\tBinding binding = Binding.of(\"C:\\\\host:C:\\\\container:ro\");\n\t\tassertThat(binding.getContainerDestinationPath()).isEqualTo(\"C:\\\\container\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfBindingIsMalformed() {\n\t\tBinding binding = Binding.of(\"some-invalid-binding\");\n\t\tassertThatIllegalStateException().isThrownBy(binding::getContainerDestinationPath)\n\t\t\t.withMessage(\"Expected 2 or more parts, but found 1\");\n\t}\n\n\t@ParameterizedTest\n\t@CsvSource(textBlock = \"\"\"\n\t\t\t/cnb, true\n\t\t\t/layers, true\n\t\t\t/workspace, true\n\t\t\t/something, false\n\t\t\tc:\\\\cnb, true\n\t\t\tc:\\\\layers, true\n\t\t\tc:\\\\workspace, true\n\t\t\tc:\\\\something, false\n\t\t\t\"\"\")\n\tvoid shouldDetectSensitiveContainerPaths(String containerPath, boolean sensitive) {\n\t\tBinding binding = Binding.from(\"/host\", containerPath);\n\t\tassertThat(binding.usesSensitiveContainerPath()).isEqualTo(sensitive);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerConfigTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.ByteArrayOutputStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport org.skyscreamer.jsonassert.JSONAssert;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ContainerConfig}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jeroen Meijer\n */\nclass ContainerConfigTests extends AbstractJsonTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenImageReferenceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerConfig.of(null, (update) -> {\n\t\t})).withMessage(\"'imageReference' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenUpdateIsNullThrowsException() {\n\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerConfig.of(imageReference, null))\n\t\t\t.withMessage(\"'update' must not be null\");\n\t}\n\n\t@Test\n\tvoid writeToWritesJson() throws Exception {\n\t\tImageReference imageReference = ImageReference.of(\"ubuntu:bionic\");\n\t\tContainerConfig containerConfig = ContainerConfig.of(imageReference, (update) -> {\n\t\t\tupdate.withUser(\"root\");\n\t\t\tupdate.withCommand(\"ls\", \"-l\");\n\t\t\tupdate.withArgs(\"-h\");\n\t\t\tupdate.withLabel(\"spring\", \"boot\");\n\t\t\tupdate.withBinding(Binding.from(\"bind-source\", \"bind-dest\"));\n\t\t\tupdate.withEnv(\"name1\", \"value1\");\n\t\t\tupdate.withEnv(\"name2\", \"value2\");\n\t\t\tupdate.withNetworkMode(\"test\");\n\t\t\tupdate.withSecurityOption(\"option=value\");\n\t\t});\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tcontainerConfig.writeTo(outputStream);\n\t\tString actualJson = outputStream.toString(StandardCharsets.UTF_8);\n\t\tString expectedJson = StreamUtils.copyToString(getContent(\"container-config.json\"), StandardCharsets.UTF_8);\n\t\tJSONAssert.assertEquals(expectedJson, actualJson, true);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.io.TarArchive;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ContainerContent}.\n *\n * @author Phillip Webb\n */\nclass ContainerContentTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenArchiveIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerContent.of(null))\n\t\t\t.withMessage(\"'archive' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenDestinationPathIsNullThrowsException() {\n\t\tTarArchive archive = mock(TarArchive.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerContent.of(archive, null))\n\t\t\t.withMessage(\"'destinationPath' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenDestinationPathIsEmptyThrowsException() {\n\t\tTarArchive archive = mock(TarArchive.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerContent.of(archive, \"\"))\n\t\t\t.withMessage(\"'destinationPath' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofCreatesContainerContent() {\n\t\tTarArchive archive = mock(TarArchive.class);\n\t\tContainerContent content = ContainerContent.of(archive);\n\t\tassertThat(content.getArchive()).isSameAs(archive);\n\t\tassertThat(content.getDestinationPath()).isEqualTo(\"/\");\n\t}\n\n\t@Test\n\tvoid ofWithDestinationPathCreatesContainerContent() {\n\t\tTarArchive archive = mock(TarArchive.class);\n\t\tContainerContent content = ContainerContent.of(archive, \"/test\");\n\t\tassertThat(content.getArchive()).isSameAs(archive);\n\t\tassertThat(content.getDestinationPath()).isEqualTo(\"/test\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerReferenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ContainerReference}.\n *\n * @author Phillip Webb\n */\nclass ContainerReferenceTests {\n\n\t@Test\n\tvoid ofCreatesInstance() {\n\t\tContainerReference reference = ContainerReference\n\t\t\t.of(\"92691aec176333f7ae890de9aaeeafef11166efcaa3908edf83eb44a5c943781\");\n\t\tassertThat(reference).hasToString(\"92691aec176333f7ae890de9aaeeafef11166efcaa3908edf83eb44a5c943781\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerReference.of(null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ContainerReference.of(\"\"))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tContainerReference r1 = ContainerReference\n\t\t\t.of(\"92691aec176333f7ae890de9aaeeafef11166efcaa3908edf83eb44a5c943781\");\n\t\tContainerReference r2 = ContainerReference\n\t\t\t.of(\"92691aec176333f7ae890de9aaeeafef11166efcaa3908edf83eb44a5c943781\");\n\t\tContainerReference r3 = ContainerReference\n\t\t\t.of(\"02691aec176333f7ae890de9aaeeafef11166efcaa3908edf83eb44a5c943781\");\n\t\tassertThat(r1).hasSameHashCodeAs(r2);\n\t\tassertThat(r1).isEqualTo(r1).isEqualTo(r2).isNotEqualTo(r3);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ContainerStatusTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ContainerStatus}.\n *\n * @author Scott Frederick\n */\nclass ContainerStatusTests {\n\n\t@Test\n\tvoid ofCreatesFromJson() throws IOException {\n\t\tContainerStatus status = ContainerStatus.of(getClass().getResourceAsStream(\"container-status-error.json\"));\n\t\tassertThat(status.getStatusCode()).isOne();\n\t\tassertThat(status.getWaitingErrorMessage()).isEqualTo(\"error detail\");\n\t}\n\n\t@Test\n\tvoid ofCreatesFromValues() {\n\t\tContainerStatus status = ContainerStatus.of(1, \"error detail\");\n\t\tassertThat(status.getStatusCode()).isOne();\n\t\tassertThat(status.getWaitingErrorMessage()).isEqualTo(\"error detail\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageArchiveIndexTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImageArchiveIndex}.\n *\n * @author Phillip Webb\n */\nclass ImageArchiveIndexTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid loadJson() {\n\t\tString content = getContentAsString(\"image-archive-index.json\");\n\t\tImageArchiveIndex index = getIndex(content);\n\t\tassertThat(index.getSchemaVersion()).isEqualTo(2);\n\t\tassertThat(index.getManifests()).hasSize(1);\n\t\tBlobReference manifest = index.getManifests().get(0);\n\t\tassertThat(manifest.getMediaType()).isEqualTo(\"application/vnd.docker.distribution.manifest.list.v2+json\");\n\t\tassertThat(manifest.getDigest())\n\t\t\t.isEqualTo(\"sha256:3bbe02431d8e5124ffe816ec27bf6508b50edd1d10218be1a03e799a186b9004\");\n\t}\n\n\tprivate ImageArchiveIndex getIndex(String content) {\n\t\treturn new ImageArchiveIndex(getJsonMapper().readTree(content));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageArchiveManifestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImageArchiveManifest}.\n *\n * @author Scott Frederick\n * @author Andy Wilkinson\n */\nclass ImageArchiveManifestTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid getLayersReturnsLayers() {\n\t\tString content = getContentAsString(\"image-archive-manifest.json\");\n\t\tImageArchiveManifest manifest = getManifest(content);\n\t\tList<String> expectedLayers = new ArrayList<>();\n\t\tfor (int blankLayersCount = 0; blankLayersCount < 46; blankLayersCount++) {\n\t\t\texpectedLayers.add(\"blank_\" + blankLayersCount);\n\t\t}\n\t\texpectedLayers.add(\"bb09e17fd1bd2ee47155f1349645fcd9fff31e1247c7ed99cad469f1c16a4216.tar\");\n\t\tassertThat(manifest.getEntries()).hasSize(1);\n\t\tassertThat(manifest.getEntries().get(0).getLayers()).hasSize(47);\n\t\tassertThat(manifest.getEntries().get(0).getLayers()).isEqualTo(expectedLayers);\n\t}\n\n\t@Test\n\tvoid getLayersWithNoLayersReturnsEmptyList() {\n\t\tString content = \"[{\\\"Layers\\\": []}]\";\n\t\tImageArchiveManifest manifest = getManifest(content);\n\t\tassertThat(manifest.getEntries()).hasSize(1);\n\t\tassertThat(manifest.getEntries().get(0).getLayers()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getLayersWithEmptyManifestReturnsEmptyList() {\n\t\tString content = \"[]\";\n\t\tImageArchiveManifest manifest = getManifest(content);\n\t\tassertThat(manifest.getEntries()).isEmpty();\n\t}\n\n\tprivate ImageArchiveManifest getManifest(String content) {\n\t\treturn new ImageArchiveManifest(getJsonMapper().readTree(content));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.jupiter.api.Test;\nimport org.skyscreamer.jsonassert.JSONAssert;\n\nimport org.springframework.boot.buildpack.platform.io.Owner;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImageArchive}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ImageArchiveTests extends AbstractJsonTests {\n\n\tprivate static final int EXISTING_IMAGE_LAYER_COUNT = 46;\n\n\t@Test\n\tvoid fromImageWritesToValidArchiveTar() throws Exception {\n\t\tImage image = Image.of(getContent(\"image.json\"));\n\t\tImageArchive archive = ImageArchive.from(image, (update) -> {\n\t\t\tupdate.withNewLayer(Layer.of((layout) -> layout.directory(\"/spring\", Owner.ROOT)));\n\t\t\tupdate.withTag(ImageReference.of(\"pack.local/builder/6b7874626575656b6162\"));\n\t\t});\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tarchive.writeTo(outputStream);\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(\n\t\t\t\tnew ByteArrayInputStream(outputStream.toByteArray()))) {\n\t\t\tfor (int i = 0; i < EXISTING_IMAGE_LAYER_COUNT; i++) {\n\t\t\t\tTarArchiveEntry blankEntry = tar.getNextEntry();\n\t\t\t\tassertThat(blankEntry.getName()).isEqualTo(\"blank_\" + i);\n\t\t\t}\n\t\t\tTarArchiveEntry layerEntry = tar.getNextEntry();\n\t\t\tbyte[] layerContent = read(tar, layerEntry.getSize());\n\t\t\tTarArchiveEntry configEntry = tar.getNextEntry();\n\t\t\tbyte[] configContent = read(tar, configEntry.getSize());\n\t\t\tTarArchiveEntry manifestEntry = tar.getNextEntry();\n\t\t\tbyte[] manifestContent = read(tar, manifestEntry.getSize());\n\t\t\tassertExpectedLayer(layerEntry, layerContent);\n\t\t\tassertExpectedConfig(configEntry, configContent);\n\t\t\tassertExpectedManifest(manifestEntry, manifestContent);\n\t\t}\n\t}\n\n\tprivate void assertExpectedLayer(TarArchiveEntry entry, byte[] content) throws Exception {\n\t\tassertThat(entry.getName()).isEqualTo(\"bb09e17fd1bd2ee47155f1349645fcd9fff31e1247c7ed99cad469f1c16a4216.tar\");\n\t\ttry (TarArchiveInputStream tar = new TarArchiveInputStream(new ByteArrayInputStream(content))) {\n\t\t\tTarArchiveEntry contentEntry = tar.getNextEntry();\n\t\t\tassertThat(contentEntry.getName()).isEqualTo(\"/spring/\");\n\t\t}\n\t}\n\n\tprivate void assertExpectedConfig(TarArchiveEntry entry, byte[] content) throws Exception {\n\t\tassertThat(entry.getName()).isEqualTo(\"416c76dc7f691f91e80516ff039e056f32f996b59af4b1cb8114e6ae8171a374.json\");\n\t\tString actualJson = new String(content, StandardCharsets.UTF_8);\n\t\tString expectedJson = StreamUtils.copyToString(getContent(\"image-archive-config.json\"), StandardCharsets.UTF_8);\n\t\tJSONAssert.assertEquals(expectedJson, actualJson, false);\n\t}\n\n\tprivate void assertExpectedManifest(TarArchiveEntry entry, byte[] content) throws Exception {\n\t\tassertThat(entry.getName()).isEqualTo(\"manifest.json\");\n\t\tString actualJson = new String(content, StandardCharsets.UTF_8);\n\t\tString expectedJson = StreamUtils.copyToString(getContent(\"image-archive-manifest.json\"),\n\t\t\t\tStandardCharsets.UTF_8);\n\t\tJSONAssert.assertEquals(expectedJson, actualJson, false);\n\t}\n\n\tprivate byte[] read(TarArchiveInputStream tar, long size) throws IOException {\n\t\tbyte[] content = new byte[(int) size];\n\t\ttar.read(content);\n\t\treturn content;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageConfigTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ImageConfig}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ImageConfigTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid getEnvContainsParsedValues() {\n\t\tImageConfig imageConfig = getImageConfig();\n\t\tMap<String, @Nullable String> env = imageConfig.getEnv();\n\t\tassertThat(env).contains(entry(\"PATH\", \"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"),\n\t\t\t\tentry(\"CNB_USER_ID\", \"2000\"), entry(\"CNB_GROUP_ID\", \"2000\"),\n\t\t\t\tentry(\"CNB_STACK_ID\", \"org.cloudfoundry.stacks.cflinuxfs3\"));\n\t}\n\n\t@Test\n\tvoid whenConfigHasNoEnvThenImageConfigEnvIsEmpty() {\n\t\tImageConfig imageConfig = getMinimalImageConfig();\n\t\tMap<String, @Nullable String> env = imageConfig.getEnv();\n\t\tassertThat(env).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenConfigHasNoLabelsThenImageConfigLabelsIsEmpty() {\n\t\tImageConfig imageConfig = getMinimalImageConfig();\n\t\tMap<String, String> env = imageConfig.getLabels();\n\t\tassertThat(env).isEmpty();\n\t}\n\n\t@Test\n\tvoid getLabelsReturnsLabels() {\n\t\tImageConfig imageConfig = getImageConfig();\n\t\tMap<String, String> labels = imageConfig.getLabels();\n\t\tassertThat(labels).hasSize(4).contains(entry(\"io.buildpacks.stack.id\", \"org.cloudfoundry.stacks.cflinuxfs3\"));\n\t}\n\n\t@Test\n\tvoid updateWithLabelUpdatesLabels() {\n\t\tImageConfig imageConfig = getImageConfig();\n\t\tImageConfig updatedImageConfig = imageConfig\n\t\t\t.copy((update) -> update.withLabel(\"io.buildpacks.stack.id\", \"test\"));\n\t\tassertThat(imageConfig.getLabels()).hasSize(4)\n\t\t\t.contains(entry(\"io.buildpacks.stack.id\", \"org.cloudfoundry.stacks.cflinuxfs3\"));\n\t\tassertThat(updatedImageConfig.getLabels()).hasSize(4).contains(entry(\"io.buildpacks.stack.id\", \"test\"));\n\t}\n\n\tprivate ImageConfig getImageConfig() {\n\t\treturn new ImageConfig(getJsonMapper().readTree(getContent(\"image-config.json\")));\n\t}\n\n\tprivate ImageConfig getMinimalImageConfig() {\n\t\treturn new ImageConfig(getJsonMapper().readTree(getContent(\"minimal-image-config.json\")));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ImageName}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ImageNameTests {\n\n\t@Test\n\tvoid ofWhenNameOnlyCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/library/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenSlashedNameCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLocalhostNameCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"localhost/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"localhost/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"localhost\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenDomainAndNameCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo.spring.io/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo.spring.io/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo.spring.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenDomainNameAndPortCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo.spring.io:8080/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo.spring.io:8080/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo.spring.io:8080\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenSimpleNameAndPortCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo:8080/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo:8080/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo:8080\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenSimplePathAndPortCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo:8080/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo:8080/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo:8080\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameWithLongPathCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"path1/path2/path3/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/path1/path2/path3/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"path1/path2/path3/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLocalhostDomainCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"localhost/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"localhost\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLocalhostDomainAndPathCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"localhost/library/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"localhost\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLegacyDomainUsesNewDomain() {\n\t\tImageName imageName = ImageName.of(\"index.docker.io/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/library/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"library/ubuntu\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(\"\"))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsUppercaseThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(\"Test\"))\n\t\t\t.withMessageContaining(\"must be a parsable name\")\n\t\t\t.withMessageContaining(\"Test\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameIncludesTagThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(\"ubuntu:latest\"))\n\t\t\t.withMessageContaining(\"must be a parsable name\")\n\t\t\t.withMessageContaining(\":latest\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameIncludeDigestThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(\n\t\t\t\t() -> ImageName.of(\"ubuntu@sha256:47bfdb88c3ae13e488167607973b7688f69d9e8c142c2045af343ec199649c09\"))\n\t\t\t.withMessageContaining(\"must be a parsable name\")\n\t\t\t.withMessageContaining(\"@sha256:47b\");\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tImageName n1 = ImageName.of(\"ubuntu\");\n\t\tImageName n2 = ImageName.of(\"library/ubuntu\");\n\t\tImageName n3 = ImageName.of(\"docker.io/ubuntu\");\n\t\tImageName n4 = ImageName.of(\"docker.io/library/ubuntu\");\n\t\tImageName n5 = ImageName.of(\"index.docker.io/library/ubuntu\");\n\t\tImageName n6 = ImageName.of(\"alpine\");\n\t\tassertThat(n1).hasSameHashCodeAs(n2).hasSameHashCodeAs(n3).hasSameHashCodeAs(n4).hasSameHashCodeAs(n5);\n\t\tassertThat(n1).isEqualTo(n1).isEqualTo(n2).isEqualTo(n3).isEqualTo(n4).isNotEqualTo(n6);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageReferenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\nimport org.junit.jupiter.api.Timeout.ThreadMode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ImageReference}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass ImageReferenceTests {\n\n\t@Test\n\tvoid ofSimpleName() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofSimpleNameWithSingleCharacterSuffix() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu-a\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu-a\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu-a\");\n\t}\n\n\t@Test\n\tvoid ofLibrarySlashName() {\n\t\tImageReference reference = ImageReference.of(\"library/ubuntu\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofSlashName() {\n\t\tImageReference reference = ImageReference.of(\"adoptopenjdk/openjdk11\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"adoptopenjdk/openjdk11\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/adoptopenjdk/openjdk11\");\n\t}\n\n\t@Test\n\tvoid ofCustomDomain() {\n\t\tImageReference reference = ImageReference.of(\"repo.example.com/java/jdk\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"repo.example.com\");\n\t\tassertThat(reference.getName()).isEqualTo(\"java/jdk\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"repo.example.com/java/jdk\");\n\t}\n\n\t@Test\n\tvoid ofCustomDomainAndPort() {\n\t\tImageReference reference = ImageReference.of(\"repo.example.com:8080/java/jdk\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"repo.example.com:8080\");\n\t\tassertThat(reference.getName()).isEqualTo(\"java/jdk\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"repo.example.com:8080/java/jdk\");\n\t}\n\n\t@Test\n\tvoid ofLegacyDomain() {\n\t\tImageReference reference = ImageReference.of(\"index.docker.io/ubuntu\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofNameAndTag() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu:bionic\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"bionic\");\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu:bionic\");\n\t}\n\n\t@Test\n\tvoid ofDomainPortAndTag() {\n\t\tImageReference reference = ImageReference.of(\"repo.example.com:8080/library/ubuntu:v1\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"repo.example.com:8080\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"v1\");\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"repo.example.com:8080/library/ubuntu:v1\");\n\t}\n\n\t@Test\n\tvoid ofNameAndDigest() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest())\n\t\t\t.isEqualTo(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofNameAndTagAndDigest() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"bionic\");\n\t\tassertThat(reference.getDigest())\n\t\t\t.isEqualTo(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofCustomDomainAndPortWithTag() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"example.com:8080/canonical/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"example.com:8080\");\n\t\tassertThat(reference.getName()).isEqualTo(\"canonical/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"bionic\");\n\t\tassertThat(reference.getDigest())\n\t\t\t.isEqualTo(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"example.com:8080/canonical/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofImageName() {\n\t\tImageReference reference = ImageReference.of(ImageName.of(\"ubuntu\"));\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofImageNameAndTag() {\n\t\tImageReference reference = ImageReference.of(ImageName.of(\"ubuntu\"), \"bionic\");\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu:bionic\");\n\t}\n\n\t@Test\n\tvoid ofImageNameTagAndDigest() {\n\t\tImageReference reference = ImageReference.of(ImageName.of(\"ubuntu\"), \"bionic\",\n\t\t\t\t\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofWhenHasIllegalCharacterThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ImageReference\n\t\t\t\t.of(\"registry.example.com/example/example-app:1.6.0-dev.2.uncommitted+wip.foo.c75795d\"))\n\t\t\t.withMessageContaining(\"must be an image reference\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsUpperCaseThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ImageReference\n\t\t\t\t.of(\"europe-west1-docker.pkg.dev/aaaaaa-bbbbb-123456/docker-registry/bootBuildImage:0.0.1\"))\n\t\t\t.withMessageContaining(\"must be an image reference\");\n\t}\n\n\t@Test\n\t@Timeout(value = 1, threadMode = ThreadMode.SEPARATE_THREAD)\n\tvoid ofWhenIsVeryLongAndHasIllegalCharacter() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageReference\n\t\t\t.of(\"docker.io/library/this-image-has-a-long-name-with-an-invalid-tag-which-is-at-danger-of-catastrophic-backtracking:1.0.0+1234\"))\n\t\t\t.withMessageContaining(\"must be an image reference\");\n\t}\n\n\t@Test\n\tvoid forJarFile() {\n\t\tassertForJarFile(\"spring-boot.2.0.0.BUILD-SNAPSHOT.jar\", \"library/spring-boot\", \"2.0.0.BUILD-SNAPSHOT\");\n\t\tassertForJarFile(\"spring-boot.2.0.0.M1.jar\", \"library/spring-boot\", \"2.0.0.M1\");\n\t\tassertForJarFile(\"spring-boot.2.0.0.RC1.jar\", \"library/spring-boot\", \"2.0.0.RC1\");\n\t\tassertForJarFile(\"spring-boot.2.0.0.RELEASE.jar\", \"library/spring-boot\", \"2.0.0.RELEASE\");\n\t\tassertForJarFile(\"sample-0.0.1-SNAPSHOT.jar\", \"library/sample\", \"0.0.1-SNAPSHOT\");\n\t\tassertForJarFile(\"sample-0.0.1.jar\", \"library/sample\", \"0.0.1\");\n\t}\n\n\tprivate void assertForJarFile(String jarFile, String expectedName, String expectedTag) {\n\t\tImageReference reference = ImageReference.forJarFile(new File(jarFile));\n\t\tassertThat(reference.getName()).isEqualTo(expectedName);\n\t\tassertThat(reference.getTag()).isEqualTo(expectedTag);\n\t}\n\n\t@Test\n\tvoid randomGeneratesRandomName() {\n\t\tString prefix = \"pack.local/builder/\";\n\t\tImageReference random = ImageReference.random(prefix);\n\t\tassertThat(random.toString()).startsWith(prefix).hasSize(prefix.length() + 10);\n\t\tImageReference another = ImageReference.random(prefix);\n\t\tint attempts = 0;\n\t\twhile (another.equals(random)) {\n\t\t\tassertThat(attempts).as(\"Duplicate results\").isLessThan(10);\n\t\t\tanother = ImageReference.random(prefix);\n\t\t\tattempts++;\n\t\t}\n\t}\n\n\t@Test\n\tvoid randomWithLengthGeneratesRandomName() {\n\t\tString prefix = \"pack.local/builder/\";\n\t\tImageReference random = ImageReference.random(prefix, 20);\n\t\tassertThat(random.toString()).startsWith(prefix).hasSize(prefix.length() + 20);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid randomWherePrefixIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageReference.random(null))\n\t\t\t.withMessage(\"'prefix' must not be null\");\n\t}\n\n\t@Test\n\tvoid inTaggedFormWhenHasDigestThrowsException() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThatIllegalStateException().isThrownBy(reference::inTaggedForm)\n\t\t\t.withMessage(\n\t\t\t\t\t\"Image reference 'docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d' cannot contain a digest\");\n\t}\n\n\t@Test\n\tvoid inTaggedFormWhenHasNoTagUsesLatest() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu\");\n\t\tassertThat(reference.inTaggedForm()).hasToString(\"docker.io/library/ubuntu:latest\");\n\t}\n\n\t@Test\n\tvoid inTaggedFormWhenHasTagUsesTag() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu:bionic\");\n\t\tassertThat(reference.inTaggedForm()).hasToString(\"docker.io/library/ubuntu:bionic\");\n\t}\n\n\t@Test\n\tvoid inTaggedOrDigestFormWhenHasDigestUsesDigest() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.inTaggedOrDigestForm()).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid inTaggedOrDigestFormWhenHasTagUsesTag() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu:bionic\");\n\t\tassertThat(reference.inTaggedOrDigestForm()).hasToString(\"docker.io/library/ubuntu:bionic\");\n\t}\n\n\t@Test\n\tvoid inTaggedOrDigestFormWhenHasNoTagOrDigestUsesLatest() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu\");\n\t\tassertThat(reference.inTaggedOrDigestForm()).hasToString(\"docker.io/library/ubuntu:latest\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tImageReference r1 = ImageReference.of(\"ubuntu:bionic\");\n\t\tImageReference r2 = ImageReference.of(\"docker.io/library/ubuntu:bionic\");\n\t\tImageReference r3 = ImageReference.of(\"docker.io/library/ubuntu:latest\");\n\t\tassertThat(r1).hasSameHashCodeAs(r2);\n\t\tassertThat(r1).isEqualTo(r1).isEqualTo(r2).isNotEqualTo(r3);\n\t}\n\n\t@Test\n\tvoid withDigest() {\n\t\tImageReference reference = ImageReference.of(\"docker.io/library/ubuntu:bionic\");\n\t\tImageReference updated = reference\n\t\t\t.withDigest(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(updated).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid inTaglessFormWithDigest() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tImageReference updated = reference.inTaglessForm();\n\t\tassertThat(updated).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid inTaglessForm() {\n\t\tImageReference reference = ImageReference.of(\"docker.io/library/ubuntu:bionic\");\n\t\tImageReference updated = reference.inTaglessForm();\n\t\tassertThat(updated).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ImageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.docker.type.Image.Descriptor;\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link Image}.\n *\n * @author Phillip Webb\n */\nclass ImageTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid getConfigEnvContainsParsedValues() throws Exception {\n\t\tImage image = getImage();\n\t\tMap<String, @Nullable String> env = image.getConfig().getEnv();\n\t\tassertThat(env).contains(entry(\"PATH\", \"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"),\n\t\t\t\tentry(\"CNB_USER_ID\", \"2000\"), entry(\"CNB_GROUP_ID\", \"2000\"),\n\t\t\t\tentry(\"CNB_STACK_ID\", \"org.cloudfoundry.stacks.cflinuxfs3\"));\n\t}\n\n\t@Test\n\tvoid getConfigLabelsReturnsLabels() throws Exception {\n\t\tImage image = getImage();\n\t\tMap<String, String> labels = image.getConfig().getLabels();\n\t\tassertThat(labels).contains(entry(\"io.buildpacks.stack.id\", \"org.cloudfoundry.stacks.cflinuxfs3\"));\n\t}\n\n\t@Test\n\tvoid getLayersReturnsImageLayers() throws Exception {\n\t\tImage image = getImage();\n\t\tList<LayerId> layers = image.getLayers();\n\t\tassertThat(layers).hasSize(46);\n\t\tassertThat(layers.get(0))\n\t\t\t.hasToString(\"sha256:733a8e5ce32984099ef675fce04730f6e2a6dcfdf5bd292fea01a8f936265342\");\n\t\tassertThat(layers.get(45))\n\t\t\t.hasToString(\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\");\n\t}\n\n\t@Test\n\tvoid getOsReturnsOs() throws Exception {\n\t\tImage image = getImage();\n\t\tassertThat(image.getOs()).isEqualTo(\"linux\");\n\t}\n\n\t@Test\n\tvoid getOsWhenOsIsNotDefaultOsReturnsOs() throws Exception {\n\t\tImage image = Image.of(getContent(\"image-non-default-os.json\"));\n\t\tassertThat(image.getOs()).isEqualTo(\"windows\");\n\t}\n\n\t@Test\n\tvoid getOsWhenOsIsEmptyReturnsDefaultOs() throws Exception {\n\t\tImage image = Image.of(getContent(\"image-empty-os.json\"));\n\t\tassertThat(image.getOs()).isEqualTo(\"linux\");\n\t}\n\n\t@Test\n\tvoid getArchitectureReturnsArchitecture() throws Exception {\n\t\tImage image = getImage();\n\t\tassertThat(image.getArchitecture()).isEqualTo(\"amd64\");\n\t}\n\n\t@Test\n\tvoid getVariantReturnsVariant() throws Exception {\n\t\tImage image = getImage();\n\t\tassertThat(image.getVariant()).isEqualTo(\"v1\");\n\t}\n\n\t@Test\n\tvoid getCreatedReturnsDate() throws Exception {\n\t\tImage image = getImage();\n\t\tassertThat(image.getCreated()).isEqualTo(\"2019-10-30T19:34:56.296666503Z\");\n\t}\n\n\t@Test\n\tvoid getDescriptorReturnsDescriptor() throws Exception {\n\t\tImage image = getImage();\n\t\tDescriptor descriptor = image.getDescriptor();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getDigest())\n\t\t\t.isEqualTo(\"sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96\");\n\t}\n\n\t@Test\n\tvoid getPrimaryDigestWhenHasDescriptor() throws Exception {\n\t\tImage image = getImage();\n\t\tassertThat(image.getPrimaryDigest())\n\t\t\t.isEqualTo(\"sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96\");\n\t}\n\n\t@Test\n\tvoid getPrimaryDigestWhenNoDescriptor() throws Exception {\n\t\tImage image = Image.of(getContent(\"image-no-descriptor.json\"));\n\t\tassertThat(image.getPrimaryDigest())\n\t\t\t.isEqualTo(\"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\");\n\t}\n\n\t@Test\n\tvoid getPrimaryDigestWhenNoDigest() throws Exception {\n\t\tImage image = Image.of(getContent(\"image-no-digest.json\"));\n\t\tassertThat(image.getPrimaryDigest()).isNull();\n\t}\n\n\tprivate Image getImage() throws IOException {\n\t\treturn Image.of(getContent(\"image.json\"));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/LayerIdTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Test for {@link LayerId}.\n *\n * @author Phillip Webb\n */\nclass LayerIdTests {\n\n\t@Test\n\tvoid ofReturnsLayerId() {\n\t\tLayerId id = LayerId.of(\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\");\n\t\tassertThat(id.getAlgorithm()).isEqualTo(\"sha256\");\n\t\tassertThat(id.getHash()).isEqualTo(\"9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\");\n\t\tassertThat(id).hasToString(\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\");\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tLayerId id1 = LayerId.of(\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\");\n\t\tLayerId id2 = LayerId.of(\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\");\n\t\tLayerId id3 = LayerId.of(\"sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n\t\tassertThat(id1).hasSameHashCodeAs(id2);\n\t\tassertThat(id1).isEqualTo(id1).isEqualTo(id2).isNotEqualTo(id3);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenValueIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LayerId.of((String) null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenValueIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LayerId.of(\" \")).withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofSha256Digest() throws Exception {\n\t\tMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n\t\tdigest.update(\"test\".getBytes(StandardCharsets.UTF_8));\n\t\tLayerId id = LayerId.ofSha256Digest(digest.digest());\n\t\tassertThat(id).hasToString(\"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\");\n\t}\n\n\t@Test\n\tvoid ofSha256DigestWithZeroPadding() {\n\t\tbyte[] digest = new byte[32];\n\t\tArrays.fill(digest, (byte) 127);\n\t\tdigest[0] = 1;\n\t\tLayerId id = LayerId.ofSha256Digest(digest);\n\t\tassertThat(id).hasToString(\"sha256:017f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofSha256DigestWhenNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LayerId.ofSha256Digest((byte[]) null))\n\t\t\t.withMessage(\"'digest' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofSha256DigestWhenWrongLengthThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LayerId.ofSha256Digest(new byte[31]))\n\t\t\t.withMessage(\"'digest' must be exactly 32 bytes\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/LayerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.io.Content;\nimport org.springframework.boot.buildpack.platform.io.IOConsumer;\nimport org.springframework.boot.buildpack.platform.io.Layout;\nimport org.springframework.boot.buildpack.platform.io.Owner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Layer}.\n *\n * @author Phillip Webb\n */\nclass LayerTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenLayoutIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Layer.of((IOConsumer<Layout>) null))\n\t\t\t.withMessage(\"'layout' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromTarArchiveWhenTarArchiveIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Layer.fromTarArchive(null))\n\t\t\t.withMessage(\"'tarArchive' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofCreatesLayer() throws Exception {\n\t\tLayer layer = Layer.of((layout) -> {\n\t\t\tlayout.directory(\"/directory\", Owner.ROOT);\n\t\t\tlayout.file(\"/directory/file\", Owner.ROOT, Content.of(\"test\"));\n\t\t});\n\t\tassertThat(layer.getId())\n\t\t\t.hasToString(\"sha256:d03a34f73804698c875eb56ff694fc2fceccc69b645e4adceb004ed13588613b\");\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tlayer.writeTo(outputStream);\n\t\ttry (TarArchiveInputStream tarStream = new TarArchiveInputStream(\n\t\t\t\tnew ByteArrayInputStream(outputStream.toByteArray()))) {\n\t\t\tassertThat(tarStream.getNextEntry().getName()).isEqualTo(\"/directory/\");\n\t\t\tassertThat(tarStream.getNextEntry().getName()).isEqualTo(\"/directory/file\");\n\t\t\tassertThat(tarStream.getNextEntry()).isNull();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ManifestListTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ManifestList}.\n *\n * @author Phillip Webb\n */\nclass ManifestListTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid loadJsonFromDistributionManifestList() {\n\t\tString content = getContentAsString(\"distribution-manifest-list.json\");\n\t\tManifestList manifestList = getManifestList(content);\n\t\tassertThat(manifestList.getSchemaVersion()).isEqualTo(2);\n\t\tassertThat(manifestList.getMediaType()).isEqualTo(\"application/vnd.docker.distribution.manifest.list.v2+json\");\n\t\tassertThat(manifestList.getManifests()).hasSize(2);\n\t}\n\n\tprivate ManifestList getManifestList(String content) {\n\t\treturn new ManifestList(getJsonMapper().readTree(content));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/ManifestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.json.AbstractJsonTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Manifest}.\n *\n * @author Phillip Webb\n */\nclass ManifestTests extends AbstractJsonTests {\n\n\t@Test\n\tvoid loadJsonFromDistributionManifest() {\n\t\tString content = getContentAsString(\"distribution-manifest.json\");\n\t\tManifest manifestList = getManifest(content);\n\t\tassertThat(manifestList.getSchemaVersion()).isEqualTo(2);\n\t\tassertThat(manifestList.getMediaType()).isEqualTo(\"application/vnd.docker.distribution.manifest.v2+json\");\n\t\tassertThat(manifestList.getLayers()).hasSize(1);\n\t}\n\n\t@Test\n\tvoid loadJsonFromImageManifest() {\n\t\tString content = getContentAsString(\"image-manifest.json\");\n\t\tManifest manifestList = getManifest(content);\n\t\tassertThat(manifestList.getSchemaVersion()).isEqualTo(2);\n\t\tassertThat(manifestList.getMediaType()).isEqualTo(\"application/vnd.oci.image.manifest.v1+json\");\n\t\tassertThat(manifestList.getLayers()).hasSize(1);\n\t}\n\n\tprivate Manifest getManifest(String content) {\n\t\treturn new Manifest(getJsonMapper().readTree(content));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/RandomStringTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link RandomString}.\n *\n * @author Phillip Webb\n */\nclass RandomStringTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid generateWhenPrefixIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> RandomString.generate(null, 10))\n\t\t\t.withMessage(\"'prefix' must not be null\");\n\t}\n\n\t@Test\n\tvoid generateGeneratesRandomString() {\n\t\tString s1 = RandomString.generate(\"abc-\", 10);\n\t\tString s2 = RandomString.generate(\"abc-\", 10);\n\t\tString s3 = RandomString.generate(\"abc-\", 20);\n\t\tassertThat(s1).hasSize(14).startsWith(\"abc-\").isNotEqualTo(s2);\n\t\tassertThat(s3).hasSize(24).startsWith(\"abc-\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/docker/type/VolumeNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.docker.type;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link VolumeName}.\n *\n * @author Phillip Webb\n */\nclass VolumeNameTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid randomWhenPrefixIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.random(null))\n\t\t\t.withMessage(\"'prefix' must not be null\");\n\t}\n\n\t@Test\n\tvoid randomGeneratesRandomString() {\n\t\tVolumeName v1 = VolumeName.random(\"abc-\");\n\t\tVolumeName v2 = VolumeName.random(\"abc-\");\n\t\tassertThat(v1.toString()).startsWith(\"abc-\").hasSize(14);\n\t\tassertThat(v2.toString()).startsWith(\"abc-\").hasSize(14);\n\t\tassertThat(v1).isNotEqualTo(v2);\n\t\tassertThat(v1.toString()).isNotEqualTo(v2.toString());\n\t}\n\n\t@Test\n\tvoid randomStringWithLengthGeneratesRandomString() {\n\t\tVolumeName v1 = VolumeName.random(\"abc-\", 20);\n\t\tVolumeName v2 = VolumeName.random(\"abc-\", 20);\n\t\tassertThat(v1.toString()).startsWith(\"abc-\").hasSize(24);\n\t\tassertThat(v2.toString()).startsWith(\"abc-\").hasSize(24);\n\t\tassertThat(v1).isNotEqualTo(v2);\n\t\tassertThat(v1.toString()).isNotEqualTo(v2.toString());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid basedOnWhenSourceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.basedOn(null, \"prefix\", \"suffix\", 6))\n\t\t\t.withMessage(\"'source' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid basedOnWhenNameExtractorIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.basedOn(\"test\", null, \"prefix\", \"suffix\", 6))\n\t\t\t.withMessage(\"'nameExtractor' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid basedOnWhenPrefixIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.basedOn(\"test\", null, \"suffix\", 6))\n\t\t\t.withMessage(\"'prefix' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid basedOnWhenSuffixIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.basedOn(\"test\", \"prefix\", null, 6))\n\t\t\t.withMessage(\"'suffix' must not be null\");\n\t}\n\n\t@Test\n\tvoid basedOnGeneratesHashBasedName() {\n\t\tVolumeName name = VolumeName.basedOn(\"index.docker.io/library/myapp:latest\", \"pack-cache-\", \".build\", 6);\n\t\tassertThat(name).hasToString(\"pack-cache-40a311b545d7.build\");\n\t}\n\n\t@Test\n\tvoid basedOnWhenSizeIsTooBigThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.basedOn(\"name\", \"prefix\", \"suffix\", 33))\n\t\t\t.withMessage(\"'digestLength' must be less than or equal to 32\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenValueIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> VolumeName.of(null))\n\t\t\t.withMessage(\"'value' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofGeneratesValue() {\n\t\tVolumeName name = VolumeName.of(\"test\");\n\t\tassertThat(name).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tVolumeName n1 = VolumeName.of(\"test1\");\n\t\tVolumeName n2 = VolumeName.of(\"test1\");\n\t\tVolumeName n3 = VolumeName.of(\"test2\");\n\t\tassertThat(n1).hasSameHashCodeAs(n2);\n\t\tassertThat(n1).isEqualTo(n1).isEqualTo(n2).isNotEqualTo(n3);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/ContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Content}.\n *\n * @author Phillip Webb\n */\nclass ContentTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenSupplierIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Content.of(1, (IOSupplier<InputStream>) null))\n\t\t\t.withMessage(\"'supplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofWhenStreamReturnsWritable() throws Exception {\n\t\tbyte[] bytes = { 1, 2, 3, 4 };\n\t\tByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);\n\t\tContent writable = Content.of(4, () -> inputStream);\n\t\tassertThat(writeToAndGetBytes(writable)).isEqualTo(bytes);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenStringIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Content.of((String) null))\n\t\t\t.withMessage(\"'string' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofWhenStringReturnsWritable() throws Exception {\n\t\tContent writable = Content.of(\"spring\");\n\t\tassertThat(writeToAndGetBytes(writable)).isEqualTo(\"spring\".getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenBytesIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Content.of((byte[]) null))\n\t\t\t.withMessage(\"'bytes' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofWhenBytesReturnsWritable() throws Exception {\n\t\tbyte[] bytes = { 1, 2, 3, 4 };\n\t\tContent writable = Content.of(bytes);\n\t\tassertThat(writeToAndGetBytes(writable)).isEqualTo(bytes);\n\t}\n\n\tprivate byte[] writeToAndGetBytes(Content writable) throws IOException {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\twritable.writeTo(outputStream);\n\t\treturn outputStream.toByteArray();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/DefaultOwnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DefaultOwner}.\n *\n * @author Phillip Webb\n */\nclass DefaultOwnerTests {\n\n\t@Test\n\tvoid getUidReturnsUid() {\n\t\tDefaultOwner owner = new DefaultOwner(123, 456);\n\t\tassertThat(owner.getUid()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid getGidReturnsGid() {\n\t\tDefaultOwner owner = new DefaultOwner(123, 456);\n\t\tassertThat(owner.getGid()).isEqualTo(456);\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tDefaultOwner owner = new DefaultOwner(123, 456);\n\t\tassertThat(owner).hasToString(\"123/456\");\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/FilePermissionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.FileAttribute;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link FilePermissions}.\n *\n * @author Scott Frederick\n */\nclass FilePermissionsTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath tempDir;\n\n\t@Test\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid umaskForPath() throws IOException {\n\t\tFileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions\n\t\t\t.asFileAttribute(PosixFilePermissions.fromString(\"rw-r-----\"));\n\t\tPath tempFile = Files.createTempFile(this.tempDir, \"umask\", null, fileAttribute);\n\t\tassertThat(FilePermissions.umaskForPath(tempFile)).isEqualTo(0640);\n\t}\n\n\t@Test\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid umaskForPathWithNonExistentFile() {\n\t\tassertThatIOException()\n\t\t\t.isThrownBy(() -> FilePermissions.umaskForPath(Paths.get(this.tempDir.toString(), \"does-not-exist\")));\n\t}\n\n\t@Test\n\t@EnabledOnOs(OS.WINDOWS)\n\tvoid umaskForPathOnWindowsFails() throws IOException {\n\t\tPath tempFile = Files.createTempFile(\"umask\", null);\n\t\tassertThatIllegalStateException().isThrownBy(() -> FilePermissions.umaskForPath(tempFile))\n\t\t\t.withMessageContaining(\"Unsupported file type for retrieving Posix attributes\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid umaskForPathWithNullPath() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> FilePermissions.umaskForPath(null));\n\t}\n\n\t@Test\n\tvoid posixPermissionsToUmask() {\n\t\tSet<PosixFilePermission> permissions = PosixFilePermissions.fromString(\"rwxrw-r--\");\n\t\tassertThat(FilePermissions.posixPermissionsToUmask(permissions)).isEqualTo(0764);\n\t}\n\n\t@Test\n\tvoid posixPermissionsToUmaskWithEmptyPermissions() {\n\t\tSet<PosixFilePermission> permissions = Collections.emptySet();\n\t\tassertThat(FilePermissions.posixPermissionsToUmask(permissions)).isZero();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid posixPermissionsToUmaskWithNullPermissions() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> FilePermissions.posixPermissionsToUmask(null));\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/InspectedContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.security.MessageDigest;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link InspectedContent}.\n *\n * @author Phillip Webb\n */\nclass InspectedContentTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenInputStreamThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> InspectedContent.of((InputStream) null))\n\t\t\t.withMessage(\"'inputStream' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenContentIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> InspectedContent.of((Content) null))\n\t\t\t.withMessage(\"'content' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenConsumerIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> InspectedContent.of((IOConsumer<OutputStream>) null))\n\t\t\t.withMessage(\"'writer' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofFromContent() throws Exception {\n\t\tInspectedContent content = InspectedContent.of(Content.of(\"test\"));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tcontent.writeTo(outputStream);\n\t\tassertThat(outputStream.toByteArray()).containsExactly(\"test\".getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t@Test\n\tvoid ofSmallContent() throws Exception {\n\t\tInputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });\n\t\tInspectedContent content = InspectedContent.of(inputStream);\n\t\tassertThat(content.size()).isEqualTo(3);\n\t\tassertThat(readBytes(content)).containsExactly(0, 1, 2);\n\t}\n\n\t@Test\n\tvoid ofLargeContent() throws Exception {\n\t\tbyte[] bytes = new byte[InspectedContent.MEMORY_LIMIT + 3];\n\t\tSystem.arraycopy(new byte[] { 0, 1, 2 }, 0, bytes, 0, 3);\n\t\tInputStream inputStream = new ByteArrayInputStream(bytes);\n\t\tInspectedContent content = InspectedContent.of(inputStream);\n\t\tassertThat(content.size()).isEqualTo(bytes.length);\n\t\tassertThat(readBytes(content)).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid ofWithInspector() throws Exception {\n\t\tInputStream inputStream = new ByteArrayInputStream(\"test\".getBytes(StandardCharsets.UTF_8));\n\t\tMessageDigest digest = MessageDigest.getInstance(\"SHA-256\");\n\t\tInspectedContent.of(inputStream, digest::update);\n\t\tassertThat(digest.digest()).inHexadecimal()\n\t\t\t.contains(0x9f, 0x86, 0xd0, 0x81, 0x88, 0x4c, 0x7d, 0x65, 0x9a, 0x2f, 0xea, 0xa0, 0xc5, 0x5a, 0xd0, 0x15,\n\t\t\t\t\t0xa3, 0xbf, 0x4f, 0x1b, 0x2b, 0x0b, 0x82, 0x2c, 0xd1, 0x5d, 0x6c, 0x15, 0xb0, 0xf0, 0x0a, 0x08);\n\t}\n\n\t@Test\n\tvoid ofWritingSingleBytesShouldWork() throws Exception {\n\t\tInspectedContent content = InspectedContent.of((outputStream) -> {\n\t\t\toutputStream.write('A');\n\t\t\toutputStream.write('B');\n\t\t\toutputStream.write('C');\n\t\t});\n\t\tassertThat(content.size()).isEqualTo(3);\n\t\tassertThat(readBytes(content)).containsExactly('A', 'B', 'C');\n\t}\n\n\tprivate byte[] readBytes(InspectedContent content) throws IOException {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tcontent.writeTo(outputStream);\n\t\treturn outputStream.toByteArray();\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/OwnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Owner}.\n *\n * @author Phillip Webb\n */\nclass OwnerTests {\n\n\t@Test\n\tvoid ofReturnsNewOwner() {\n\t\tOwner owner = Owner.of(123, 456);\n\t\tassertThat(owner.getUid()).isEqualTo(123);\n\t\tassertThat(owner.getGid()).isEqualTo(456);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/TarArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TarArchive}.\n *\n * @author Phillip Webb\n */\nclass TarArchiveTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid ofWritesTarContent() throws Exception {\n\t\tOwner owner = Owner.of(123, 456);\n\t\tTarArchive tarArchive = TarArchive.of((content) -> {\n\t\t\tcontent.directory(\"/workspace\", owner);\n\t\t\tcontent.directory(\"/layers\", owner);\n\t\t\tcontent.directory(\"/cnb\", Owner.ROOT);\n\t\t\tcontent.directory(\"/cnb/buildpacks\", Owner.ROOT);\n\t\t\tcontent.directory(\"/platform\", Owner.ROOT);\n\t\t\tcontent.directory(\"/platform/env\", Owner.ROOT);\n\t\t});\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\ttarArchive.writeTo(outputStream);\n\t\ttry (TarArchiveInputStream tarStream = new TarArchiveInputStream(\n\t\t\t\tnew ByteArrayInputStream(outputStream.toByteArray()))) {\n\t\t\tList<TarArchiveEntry> entries = new ArrayList<>();\n\t\t\tTarArchiveEntry entry = tarStream.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tentries.add(entry);\n\t\t\t\tentry = tarStream.getNextEntry();\n\t\t\t}\n\t\t\tassertThat(entries).hasSize(6);\n\t\t\tassertThat(entries.get(0).getName()).isEqualTo(\"/workspace/\");\n\t\t\tassertThat(entries.get(0).getLongUserId()).isEqualTo(123);\n\t\t\tassertThat(entries.get(0).getLongGroupId()).isEqualTo(456);\n\t\t\tassertThat(entries.get(2).getName()).isEqualTo(\"/cnb/\");\n\t\t\tassertThat(entries.get(2).getLongUserId()).isZero();\n\t\t\tassertThat(entries.get(2).getLongGroupId()).isZero();\n\t\t}\n\t}\n\n\t@Test\n\tvoid fromZipFileReturnsZipFileAdapter() throws Exception {\n\t\tOwner owner = Owner.of(123, 456);\n\t\tFile file = new File(this.tempDir, \"test.zip\");\n\t\twriteTestZip(file);\n\t\tTarArchive tarArchive = TarArchive.fromZip(file, owner);\n\t\tassertThat(tarArchive).isInstanceOf(ZipFileTarArchive.class);\n\t}\n\n\tprivate void writeTestZip(File file) throws IOException {\n\t\ttry (ZipArchiveOutputStream zip = new ZipArchiveOutputStream(file)) {\n\t\t\tZipArchiveEntry dirEntry = new ZipArchiveEntry(\"spring/\");\n\t\t\tzip.putArchiveEntry(dirEntry);\n\t\t\tzip.closeArchiveEntry();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/TarLayoutWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Date;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TarLayoutWriter}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass TarLayoutWriterTests {\n\n\t@Test\n\tvoid writesTarArchive() throws Exception {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\ttry (TarLayoutWriter writer = new TarLayoutWriter(outputStream)) {\n\t\t\twriter.directory(\"/foo\", Owner.ROOT);\n\t\t\twriter.file(\"/foo/bar.txt\", Owner.of(1, 1), 0777, Content.of(\"test\"));\n\t\t}\n\t\ttry (TarArchiveInputStream tarInputStream = new TarArchiveInputStream(\n\t\t\t\tnew ByteArrayInputStream(outputStream.toByteArray()))) {\n\t\t\tTarArchiveEntry directoryEntry = tarInputStream.getNextEntry();\n\t\t\tTarArchiveEntry fileEntry = tarInputStream.getNextEntry();\n\t\t\tbyte[] fileContent = new byte[(int) fileEntry.getSize()];\n\t\t\ttarInputStream.read(fileContent);\n\t\t\tassertThat(tarInputStream.getNextEntry()).isNull();\n\t\t\tassertThat(directoryEntry.getName()).isEqualTo(\"/foo/\");\n\t\t\tassertThat(directoryEntry.getMode()).isEqualTo(0755);\n\t\t\tassertThat(directoryEntry.getLongUserId()).isZero();\n\t\t\tassertThat(directoryEntry.getLongGroupId()).isZero();\n\t\t\tassertThat(directoryEntry.getModTime()).isEqualTo(new Date(TarLayoutWriter.NORMALIZED_MOD_TIME));\n\t\t\tassertThat(fileEntry.getName()).isEqualTo(\"/foo/bar.txt\");\n\t\t\tassertThat(fileEntry.getMode()).isEqualTo(0777);\n\t\t\tassertThat(fileEntry.getLongUserId()).isOne();\n\t\t\tassertThat(fileEntry.getLongGroupId()).isOne();\n\t\t\tassertThat(fileEntry.getModTime()).isEqualTo(new Date(TarLayoutWriter.NORMALIZED_MOD_TIME));\n\t\t\tassertThat(fileContent).isEqualTo(\"test\".getBytes(StandardCharsets.UTF_8));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/io/ZipFileTarArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.io;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ZipFileTarArchive}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ZipFileTarArchiveTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenZipIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ZipFileTarArchive(null, Owner.ROOT))\n\t\t\t.withMessage(\"'zip' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenOwnerIsNullThrowsException() throws Exception {\n\t\tFile file = new File(this.tempDir, \"test.zip\");\n\t\twriteTestZip(file);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ZipFileTarArchive(file, null))\n\t\t\t.withMessage(\"'owner' must not be null\");\n\t}\n\n\t@Test\n\tvoid writeToAdaptsContent() throws Exception {\n\t\tOwner owner = Owner.of(123, 456);\n\t\tFile file = new File(this.tempDir, \"test.zip\");\n\t\twriteTestZip(file);\n\t\tTarArchive tarArchive = TarArchive.fromZip(file, owner);\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\ttarArchive.writeTo(outputStream);\n\t\ttry (TarArchiveInputStream tarStream = new TarArchiveInputStream(\n\t\t\t\tnew ByteArrayInputStream(outputStream.toByteArray()))) {\n\t\t\tTarArchiveEntry dirEntry = tarStream.getNextEntry();\n\t\t\tassertThat(dirEntry.getName()).isEqualTo(\"spring/\");\n\t\t\tassertThat(dirEntry.getLongUserId()).isEqualTo(123);\n\t\t\tassertThat(dirEntry.getLongGroupId()).isEqualTo(456);\n\t\t\tTarArchiveEntry fileEntry = tarStream.getNextEntry();\n\t\t\tassertThat(fileEntry.getName()).isEqualTo(\"spring/boot\");\n\t\t\tassertThat(fileEntry.getLongUserId()).isEqualTo(123);\n\t\t\tassertThat(fileEntry.getLongGroupId()).isEqualTo(456);\n\t\t\tassertThat(fileEntry.getSize()).isEqualTo(4);\n\t\t\tassertThat(fileEntry.getMode()).isEqualTo(0755);\n\t\t\tassertThat(tarStream).hasContent(\"test\");\n\t\t}\n\t}\n\n\tprivate void writeTestZip(File file) throws IOException {\n\t\ttry (ZipArchiveOutputStream zip = new ZipArchiveOutputStream(file)) {\n\t\t\tZipArchiveEntry dirEntry = new ZipArchiveEntry(\"spring/\");\n\t\t\tzip.putArchiveEntry(dirEntry);\n\t\t\tzip.closeArchiveEntry();\n\t\t\tZipArchiveEntry fileEntry = new ZipArchiveEntry(\"spring/boot\");\n\t\t\tfileEntry.setUnixMode(0755);\n\t\t\tzip.putArchiveEntry(fileEntry);\n\t\t\tzip.write(\"test\".getBytes(StandardCharsets.UTF_8));\n\t\t\tzip.closeArchiveEntry();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/AbstractJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.stream.Collectors;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for JSON based tests.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\npublic abstract class AbstractJsonTests {\n\n\tprotected final JsonMapper getJsonMapper() {\n\t\treturn SharedJsonMapper.get();\n\t}\n\n\tprotected final InputStream getContent(String name) {\n\t\tInputStream result = getClass().getResourceAsStream(name);\n\t\tassertThat(result).as(\"JSON source \" + name).isNotNull();\n\t\treturn result;\n\t}\n\n\tprotected final String getContentAsString(String name) {\n\t\ttry (InputStream in = getContent(name)) {\n\t\t\treturn new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines()\n\t\t\t\t.collect(Collectors.joining(\"\\n\"));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/JsonStreamTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.node.ObjectNode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonStream}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass JsonStreamTests extends AbstractJsonTests {\n\n\tprivate final JsonStream jsonStream;\n\n\tJsonStreamTests() {\n\t\tthis.jsonStream = new JsonStream(getJsonMapper());\n\t}\n\n\t@Test\n\tvoid getWhenReadingObjectNodeReturnsNodes() throws Exception {\n\t\tList<ObjectNode> result = new ArrayList<>();\n\t\tthis.jsonStream.get(getContent(\"stream.json\"), result::add);\n\t\tassertThat(result).hasSize(595);\n\t\tassertThat(result.get(594).get(\"status\").asString())\n\t\t\t.contains(\"Status: Downloaded newer image for paketo-buildpacks/cnb:base\");\n\t}\n\n\t@Test\n\tvoid getWhenReadTypesReturnsTypes() throws Exception {\n\t\tList<TestEvent> result = new ArrayList<>();\n\t\tthis.jsonStream.get(getContent(\"stream.json\"), TestEvent.class, result::add);\n\t\tassertThat(result).hasSize(595);\n\t\tassertThat(result.get(1).getId()).isEqualTo(\"5667fdb72017\");\n\t\tassertThat(result.get(594).getStatus())\n\t\t\t.isEqualTo(\"Status: Downloaded newer image for paketo-buildpacks/cnb:base\");\n\t}\n\n\t/**\n\t * Event for type deserialization tests.\n\t */\n\tstatic class TestEvent {\n\n\t\tprivate final String id;\n\n\t\tprivate final String status;\n\n\t\t@JsonCreator\n\t\tTestEvent(String id, String status) {\n\t\t\tthis.id = id;\n\t\t\tthis.status = status;\n\t\t}\n\n\t\tString getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t\tString getStatus() {\n\t\t\treturn this.status;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/MappedObjectTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.invoke.MethodHandles;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.boot.buildpack.platform.json.MappedObjectTests.TestMappedObject.Person;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MappedObject}.\n *\n * @author Phillip Webb\n */\nclass MappedObjectTests extends AbstractJsonTests {\n\n\tprivate final TestMappedObject mapped;\n\n\tMappedObjectTests() throws IOException {\n\t\tthis.mapped = TestMappedObject.of(getContent(\"test-mapped-object.json\"));\n\t}\n\n\t@Test\n\tvoid ofReadsJson() {\n\t\tassertThat(this.mapped.getNode()).isNotNull();\n\t}\n\n\t@Test\n\tvoid valueAtWhenStringReturnsValue() {\n\t\tassertThat(this.mapped.valueAt(\"/string\", String.class)).isEqualTo(\"stringvalue\");\n\t}\n\n\t@Test\n\tvoid valueAtWhenStringArrayReturnsValue() {\n\t\tassertThat(this.mapped.valueAt(\"/stringarray\", String[].class)).containsExactly(\"a\", \"b\");\n\t}\n\n\t@Test\n\tvoid valueAtWhenMissingReturnsNull() {\n\t\tassertThat(this.mapped.valueAt(\"/missing\", String.class)).isNull();\n\t}\n\n\t@Test\n\tvoid valueAtWhenInterfaceReturnsProxy() {\n\t\tPerson person = this.mapped.valueAt(\"/person\", Person.class);\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.getName().getFirst()).isEqualTo(\"spring\");\n\t\tassertThat(person.getName().getLast()).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid valueAtWhenInterfaceAndMissingReturnsProxy() {\n\t\tPerson person = this.mapped.valueAt(\"/missing\", Person.class);\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.getName().getFirst()).isNull();\n\t\tassertThat(person.getName().getLast()).isNull();\n\t}\n\n\t@Test\n\tvoid valueAtWhenActualPropertyStartsWithUppercaseReturnsValue() {\n\t\tassertThat(this.mapped.valueAt(\"/startsWithUppercase\", String.class)).isEqualTo(\"value\");\n\t}\n\n\t@Test\n\tvoid valueAtWhenDefaultMethodReturnsValue() {\n\t\tPerson person = this.mapped.valueAt(\"/person\", Person.class);\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.getName().getFullName()).isEqualTo(\"dr spring boot\");\n\t}\n\n\t/**\n\t * {@link MappedObject} for testing.\n\t */\n\tstatic class TestMappedObject extends MappedObject {\n\n\t\tTestMappedObject(JsonNode node) {\n\t\t\tsuper(node, MethodHandles.lookup());\n\t\t}\n\n\t\tstatic TestMappedObject of(InputStream content) throws IOException {\n\t\t\treturn of(content, TestMappedObject::new);\n\t\t}\n\n\t\tinterface Person {\n\n\t\t\tName getName();\n\n\t\t\tinterface Name {\n\n\t\t\t\tString getFirst();\n\n\t\t\t\tString getLast();\n\n\t\t\t\tdefault String getFullName() {\n\t\t\t\t\tString title = valueAt(this, \"/title\", String.class);\n\t\t\t\t\treturn title + \" \" + getFirst() + \" \" + getLast();\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/json/SharedJsonMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.json;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.PropertyNamingStrategies;\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SharedJsonMapper}.\n *\n * @author Phillip Webb\n */\nclass SharedJsonMapperTests {\n\n\t@Test\n\tvoid getReturnsConfiguredJsonMapper() {\n\t\tJsonMapper mapper = SharedJsonMapper.get();\n\t\tassertThat(mapper).isNotNull();\n\t\tassertThat(\n\t\t\t\tSerializationFeature.INDENT_OUTPUT.enabledIn(mapper.serializationConfig().getSerializationFeatures()))\n\t\t\t.isTrue();\n\t\tassertThat(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES\n\t\t\t.enabledIn(mapper.deserializationConfig().getDeserializationFeatures())).isFalse();\n\t\tassertThat(mapper.serializationConfig().getPropertyNamingStrategy())\n\t\t\t.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);\n\t\tassertThat(mapper.deserializationConfig().getPropertyNamingStrategy())\n\t\t\t.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/socket/FileDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.buildpack.platform.socket;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.buildpack.platform.socket.FileDescriptor.Handle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link FileDescriptor}.\n *\n * @author Phillip Webb\n */\nclass FileDescriptorTests {\n\n\tprivate final int sourceHandle = 123;\n\n\tprivate int closedHandle;\n\n\t@Test\n\tvoid acquireReturnsHandle() throws Exception {\n\t\tFileDescriptor descriptor = new FileDescriptor(this.sourceHandle, this::close);\n\t\ttry (Handle handle = descriptor.acquire()) {\n\t\t\tassertThat(handle.intValue()).isEqualTo(this.sourceHandle);\n\t\t\tassertThat(handle.isClosed()).isFalse();\n\t\t}\n\t}\n\n\t@Test\n\tvoid acquireWhenClosedReturnsClosedHandle() throws Exception {\n\t\tFileDescriptor descriptor = new FileDescriptor(this.sourceHandle, this::close);\n\t\tdescriptor.close();\n\t\ttry (Handle handle = descriptor.acquire()) {\n\t\t\tassertThat(handle.intValue()).isEqualTo(-1);\n\t\t\tassertThat(handle.isClosed()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid acquireWhenPendingCloseReturnsClosedHandle() throws Exception {\n\t\tFileDescriptor descriptor = new FileDescriptor(this.sourceHandle, this::close);\n\t\ttry (Handle handle1 = descriptor.acquire()) {\n\t\t\tdescriptor.close();\n\t\t\ttry (Handle handle2 = descriptor.acquire()) {\n\t\t\t\tassertThat(handle2.intValue()).isEqualTo(-1);\n\t\t\t\tassertThat(handle2.isClosed()).isTrue();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid finalizeTriggersClose() {\n\t\tFileDescriptor descriptor = new FileDescriptor(this.sourceHandle, this::close);\n\t\tdescriptor.close();\n\t\tassertThat(this.closedHandle).isEqualTo(this.sourceHandle);\n\t}\n\n\t@Test\n\tvoid closeWhenHandleAcquiredClosesOnRelease() throws Exception {\n\t\tFileDescriptor descriptor = new FileDescriptor(this.sourceHandle, this::close);\n\t\ttry (Handle handle = descriptor.acquire()) {\n\t\t\tdescriptor.close();\n\t\t\tassertThat(this.closedHandle).isZero();\n\t\t}\n\t\tassertThat(this.closedHandle).isEqualTo(this.sourceHandle);\n\t}\n\n\t@Test\n\tvoid closeWhenHandleNotAcquiredClosesImmediately() {\n\t\tFileDescriptor descriptor = new FileDescriptor(this.sourceHandle, this::close);\n\t\tdescriptor.close();\n\t\tassertThat(this.closedHandle).isEqualTo(this.sourceHandle);\n\t}\n\n\tprivate void close(int handle) {\n\t\tthis.closedHandle = handle;\n\t}\n\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-platform-api-0.3.json",
    "content": "{\n\t\"description\": \"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\",\n\t\"buildpacks\": [\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.googlestackdriver\",\n\t\t\t\"version\": \"v1.1.11\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.springboot\",\n\t\t\t\"version\": \"v1.2.13\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.debug\",\n\t\t\t\"version\": \"v1.2.11\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.tomcat\",\n\t\t\t\"version\": \"v1.3.18\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.go\",\n\t\t\t\"version\": \"v0.0.4\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.openjdk\",\n\t\t\t\"version\": \"v1.2.14\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.buildsystem\",\n\t\t\t\"version\": \"v1.2.15\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.jvmapplication\",\n\t\t\t\"version\": \"v1.1.12\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.springautoreconfiguration\",\n\t\t\t\"version\": \"v1.1.11\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.archiveexpanding\",\n\t\t\t\"version\": \"v1.0.102\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.jmx\",\n\t\t\t\"version\": \"v1.1.12\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.nodejs\",\n\t\t\t\"version\": \"v2.0.8\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.jdbc\",\n\t\t\t\"version\": \"v1.1.14\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.procfile\",\n\t\t\t\"version\": \"v1.1.12\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dotnet-core\",\n\t\t\t\"version\": \"v0.0.6\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.azureapplicationinsights\",\n\t\t\t\"version\": \"v1.1.12\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.distzip\",\n\t\t\t\"version\": \"v1.1.12\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dep\",\n\t\t\t\"version\": \"0.0.101\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.go-compiler\",\n\t\t\t\"version\": \"0.0.105\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.go-mod\",\n\t\t\t\"version\": \"0.0.89\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.node-engine\",\n\t\t\t\"version\": \"0.0.163\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.npm\",\n\t\t\t\"version\": \"0.1.3\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.yarn-install\",\n\t\t\t\"version\": \"0.1.10\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dotnet-core-aspnet\",\n\t\t\t\"version\": \"0.0.118\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dotnet-core-build\",\n\t\t\t\"version\": \"0.0.68\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dotnet-core-conf\",\n\t\t\t\"version\": \"0.0.115\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dotnet-core-runtime\",\n\t\t\t\"version\": \"0.0.127\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.dotnet-core-sdk\",\n\t\t\t\"version\": \"0.0.122\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.icu\",\n\t\t\t\"version\": \"0.0.43\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.node-engine\",\n\t\t\t\"version\": \"0.0.158\"\n\t\t}\n\t],\n\t\"stack\": {\n\t\t\"runImage\": {\n\t\t\t\"image\": \"cloudfoundry/run:base-cnb\",\n\t\t\t\"mirrors\": null\n\t\t}\n\t},\n\t\"lifecycle\": {\n\t\t\"version\": \"0.7.2\",\n\t\t\"api\": {\n\t\t\t\"buildpack\": \"0.2\",\n\t\t\t\"platform\": \"0.3\"\n\t\t}\n\t},\n\t\"createdBy\": {\n\t\t\"name\": \"Pack CLI\",\n\t\t\"version\": \"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\"\n\t}\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-supported-apis.json",
    "content": "{\n\t\"description\": \"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\",\n\t\"buildpacks\": [\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.springboot\",\n\t\t\t\"version\": \"v1.2.13\"\n\t\t}\n\t],\n\t\"stack\": {\n\t\t\"runImage\": {\n\t\t\t\"image\": \"cloudfoundry/run:base-cnb\",\n\t\t\t\"mirrors\": null\n\t\t}\n\t},\n\t\"lifecycle\": {\n\t\t\"version\": \"0.7.2\",\n\t\t\"api\": {\n\t\t\t\"buildpack\": \"0.2\",\n\t\t\t\"platform\": \"0.8\"\n\t\t},\n\t\t\"apis\": {\n\t\t\t\"buildpack\": {\n\t\t\t\t\"deprecated\": [],\n\t\t\t\t\"supported\": [\n\t\t\t\t\t\"0.1\",\n\t\t\t\t\t\"0.2\",\n\t\t\t\t\t\"0.3\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"platform\": {\n\t\t\t\t\"deprecated\": [],\n\t\t\t\t\"supported\": [\n          \"0.3\",\n          \"0.4\",\n          \"0.5\",\n          \"0.6\",\n          \"0.7\",\n          \"0.8\"\n        ]\n\t\t\t}\n\t\t}\n\t},\n\t\"createdBy\": {\n\t\t\"name\": \"Pack CLI\",\n\t\t\"version\": \"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\"\n\t}\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-unsupported-api.json",
    "content": "{\n\t\"description\": \"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\",\n\t\"buildpacks\": [\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.springboot\",\n\t\t\t\"version\": \"v1.2.13\"\n\t\t}\n\t],\n\t\"stack\": {\n\t\t\"runImage\": {\n\t\t\t\"image\": \"cloudfoundry/run:base-cnb\",\n\t\t\t\"mirrors\": null\n\t\t}\n\t},\n\t\"lifecycle\": {\n\t\t\"version\": \"0.7.2\",\n\t\t\"api\": {\n\t\t\t\"buildpack\": \"0.2\",\n\t\t\t\"platform\": \"0.2\"\n\t\t}\n\t},\n\t\"createdBy\": {\n\t\t\"name\": \"Pack CLI\",\n\t\t\"version\": \"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\"\n\t}\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata-unsupported-apis.json",
    "content": "{\n\t\"description\": \"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\",\n\t\"buildpacks\": [\n\t\t{\n\t\t\t\"id\": \"org.cloudfoundry.springboot\",\n\t\t\t\"version\": \"v1.2.13\"\n\t\t}\n\t],\n\t\"stack\": {\n\t\t\"runImage\": {\n\t\t\t\"image\": \"cloudfoundry/run:base-cnb\",\n\t\t\t\"mirrors\": null\n\t\t}\n\t},\n\t\"lifecycle\": {\n\t\t\"version\": \"0.7.2\",\n\t\t\"api\": {\n\t\t\t\"buildpack\": \"0.2\",\n\t\t\t\"platform\": \"0.3\"\n\t\t},\n\t\t\"apis\": {\n\t\t\t\"buildpack\": {\n\t\t\t\t\"deprecated\": [],\n\t\t\t\t\"supported\": [\n\t\t\t\t\t\"0.1\",\n\t\t\t\t\t\"0.2\",\n\t\t\t\t\t\"0.3\"\n\t\t\t\t]\n\t\t\t},\n\t\t\t\"platform\": {\n\t\t\t\t\"deprecated\": [],\n\t\t\t\t\"supported\": [\n          \"0.1\",\n          \"0.2\"\n        ]\n\t\t\t}\n\t\t}\n\t},\n\t\"createdBy\": {\n\t\t\"name\": \"Pack CLI\",\n\t\t\"version\": \"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\"\n\t}\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/builder-metadata.json",
    "content": "{\n\t\"description\": \"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\",\n\t\"buildpacks\": [\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dotnet-core\",\n\t\t\t\"version\": \"0.0.9\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dotnet-core\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dotnet-core-runtime\",\n\t\t\t\"version\": \"0.0.201\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dotnet-core-runtime\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dotnet-core-sdk\",\n\t\t\t\"version\": \"0.0.196\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dotnet-core-sdk\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dotnet-execute\",\n\t\t\t\"version\": \"0.0.180\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dotnet-execute\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dotnet-publish\",\n\t\t\t\"version\": \"0.0.121\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dotnet-publish\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dotnet-core-aspnet\",\n\t\t\t\"version\": \"0.0.196\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dotnet-core-aspnet\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/java-native-image\",\n\t\t\t\"version\": \"4.7.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/java-native-image\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/spring-boot\",\n\t\t\t\"version\": \"3.5.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/spring-boot\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/executable-jar\",\n\t\t\t\"version\": \"3.1.3\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/executable-jar\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/graalvm\",\n\t\t\t\"version\": \"4.1.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/graalvm\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/gradle\",\n\t\t\t\"version\": \"3.5.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/gradle\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/leiningen\",\n\t\t\t\"version\": \"1.2.1\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/leiningen\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/procfile\",\n\t\t\t\"version\": \"3.0.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/procfile\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/sbt\",\n\t\t\t\"version\": \"3.6.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/sbt\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/spring-boot-native-image\",\n\t\t\t\"version\": \"2.0.1\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/spring-boot-native-image\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/environment-variables\",\n\t\t\t\"version\": \"2.1.2\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/environment-variables\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/image-labels\",\n\t\t\t\"version\": \"2.0.7\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/image-labels\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/maven\",\n\t\t\t\"version\": \"3.2.1\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/maven\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/java\",\n\t\t\t\"version\": \"4.10.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/java\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/ca-certificates\",\n\t\t\t\"version\": \"1.0.1\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/ca-certificates\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/environment-variables\",\n\t\t\t\"version\": \"2.1.2\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/environment-variables\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/executable-jar\",\n\t\t\t\"version\": \"3.1.3\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/executable-jar\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/procfile\",\n\t\t\t\"version\": \"3.0.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/procfile\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/apache-tomcat\",\n\t\t\t\"version\": \"3.2.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/apache-tomcat\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/gradle\",\n\t\t\t\"version\": \"3.5.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/gradle\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/maven\",\n\t\t\t\"version\": \"3.2.1\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/maven\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/sbt\",\n\t\t\t\"version\": \"3.6.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/sbt\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\"version\": \"6.2.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/bellsoft-liberica\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/image-labels\",\n\t\t\t\"version\": \"2.0.7\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/image-labels\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/debug\",\n\t\t\t\"version\": \"2.1.4\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/debug\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/dist-zip\",\n\t\t\t\"version\": \"2.2.2\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/dist-zip\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/spring-boot\",\n\t\t\t\"version\": \"3.5.0\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/spring-boot\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/jmx\",\n\t\t\t\"version\": \"2.1.4\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/jmx\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"paketo-buildpacks/leiningen\",\n\t\t\t\"version\": \"1.2.1\",\n\t\t\t\"homepage\": \"https://github.com/paketo-buildpacks/leiningen\"\n\t\t}\n\t],\n\t\"stack\": {\n\t\t\"runImage\": {\n\t\t\t\"image\": \"cloudfoundry/run:base-cnb\",\n\t\t\t\"mirrors\": null\n\t\t}\n\t},\n\t\"lifecycle\": {\n\t\t\"version\": \"0.7.2\",\n\t\t\"api\": {\n\t\t\t\"buildpack\": \"0.2\",\n\t\t\t\"platform\": \"0.8\"\n\t\t}\n\t},\n\t\"createdBy\": {\n\t\t\"name\": \"Pack CLI\",\n\t\t\"version\": \"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/buildpack-image.json",
    "content": "{\n\t\"Id\": \"sha256:a266647e285b52403b556adc963f1809556aa999f2f694e8dc54098c570ee55a\",\n\t\"RepoTags\": [\n\t\t\"example/hello-universe:latest\"\n\t],\n\t\"RepoDigests\": [],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.buildpackage.metadata\": \"{\\\"id\\\":\\\"example/hello-universe\\\",\\\"version\\\":\\\"0.0.1\\\",\\\"homepage\\\":\\\"https://github.com/buildpacks/example/tree/main/buildpacks/hello-universe\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.example.stacks.alpine\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}]}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"example/hello-moon\\\":{\\\"0.0.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.alpine\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:4bfdc8714aee68da6662c43bc28d3b41202c88e915641c356523dabe729814c2\\\",\\\"homepage\\\":\\\"https://github.com/example/tree/main/buildpacks/hello-moon\\\"}},\\\"example/hello-universe\\\":{\\\"0.0.1\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"example/hello-world\\\",\\\"version\\\":\\\"0.0.2\\\"},{\\\"id\\\":\\\"example/hello-moon\\\",\\\"version\\\":\\\"0.0.2\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:739b4e8f3caae7237584a1bfe029ebdb05403752b1a60a4f9be991b1d51dbb69\\\",\\\"homepage\\\":\\\"https://github.com/example/tree/main/buildpacks/hello-universe\\\"}},\\\"example/hello-world\\\":{\\\"0.0.2\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.alpine\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:f752fe099c846e501bdc991d1a22f98c055ddc62f01cfc0495fff2c69f8eb940\\\",\\\"homepage\\\":\\\"https://github.com/example/tree/main/buildpacks/hello-world\\\"}}}\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 4654,\n\t\"VirtualSize\": 4654,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/cbf39b4508463beeb1d0a553c3e2baa84b8cd8dbc95681aaecc243e3ca77bcf4/diff:/var/lib/docker/overlay2/15e3d01b65c962b50a3da1b6663b8196284fb3c7e7f8497f2c1a0a736d0ec237/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/1425ea68b0daff01bcc32e55e09eeeada2318d7dd1dc4e184711359da8425bb7/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/1425ea68b0daff01bcc32e55e09eeeada2318d7dd1dc4e184711359da8425bb7/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/1425ea68b0daff01bcc32e55e09eeeada2318d7dd1dc4e184711359da8425bb7/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:4bfdc8714aee68da6662c43bc28d3b41202c88e915641c356523dabe729814c2\",\n\t\t\t\"sha256:f752fe099c846e501bdc991d1a22f98c055ddc62f01cfc0495fff2c69f8eb940\",\n\t\t\t\"sha256:739b4e8f3caae7237584a1bfe029ebdb05403752b1a60a4f9be991b1d51dbb69\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"2021-01-27T22:56:06.4599859Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/buildpack-layers-metadata.json",
    "content": "{\n\t\"example/hello-moon\": {\n\t\t\"0.0.3\": {\n\t\t\t\"api\": \"0.2\",\n\t\t\t\"stacks\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"io.buildpacks.stacks.alpine\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"io.buildpacks.stacks.bionic\"\n\t\t\t\t}\n\t\t\t],\n            \"name\": \"Example hello-moon buildpack\",\n\t\t\t\"layerDiffID\": \"sha256:4bfdc8714aee68da6662c43bc28d3b41202c88e915641c356523dabe729814c2\",\n\t\t\t\"homepage\": \"https://github.com/example/tree/main/buildpacks/hello-moon\"\n\t\t}\n\t},\n\t\"example/hello-universe\": {\n\t\t\"0.0.1\": {\n\t\t\t\"api\": \"0.2\",\n\t\t\t\"order\": [\n\t\t\t\t{\n\t\t\t\t\t\"group\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"example/hello-world\",\n\t\t\t\t\t\t\t\"version\": \"0.0.2\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"example/hello-moon\",\n\t\t\t\t\t\t\t\"version\": \"0.0.2\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t],\n            \"name\": \"Example hello-universe buildpack\",\n\t\t\t\"layerDiffID\": \"sha256:739b4e8f3caae7237584a1bfe029ebdb05403752b1a60a4f9be991b1d51dbb69\",\n\t\t\t\"homepage\": \"https://github.com/example/tree/main/buildpacks/hello-universe\"\n\t\t}\n\t},\n\t\"example/hello-world\": {\n\t\t\"0.0.1\": {\n\t\t\t\"api\": \"0.2\",\n\t\t\t\"stacks\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"io.buildpacks.stacks.alpine\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"io.buildpacks.stacks.bionic\"\n\t\t\t\t}\n\t\t\t],\n            \"name\": \"Example hello-world buildpack\",\n\t\t\t\"layerDiffID\": \"sha256:1c90e0b80d92555a0523c9ee6500845328fc39ba9dca9d30a877ff759ffbff28\",\n\t\t\t\"homepage\": \"https://github.com/example/tree/main/buildpacks/hello-world\"\n\t\t},\n\t\t\"0.0.2\": {\n\t\t\t\"api\": \"0.2\",\n\t\t\t\"stacks\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"io.buildpacks.stacks.alpine\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"io.buildpacks.stacks.bionic\"\n\t\t\t\t}\n\t\t\t],\n            \"name\": \"Example hello-world buildpack\",\n\t\t\t\"layerDiffID\": \"sha256:f752fe099c846e501bdc991d1a22f98c055ddc62f01cfc0495fff2c69f8eb940\",\n\t\t\t\"homepage\": \"https://github.com/example/tree/main/buildpacks/hello-world\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/buildpack-metadata.json",
    "content": "{\n\t\"id\": \"example/hello-universe\",\n\t\"version\": \"0.0.1\",\n\t\"homepage\": \"https://github.com/example/tree/main/buildpacks/hello-universe\",\n\t\"stacks\": [\n\t\t{\n\t\t\t\"id\": \"io.buildpacks.stacks.alpine\"\n\t\t},\n\t\t{\n\t\t\t\"id\": \"io.buildpacks.stacks.bionic\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/buildpack.toml",
    "content": "[buildpack]\nid = \"test\";\nversion = \"1.0.0\"\nname = \"Example buildpack\"\nhomepage = \"https://github.com/example/example-buildpack\"\n\n[[stacks]]\nid = \"io.buildpacks.stacks.bionic\"\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/image-with-empty-stack.json",
    "content": "{\n\t\"Id\": \"sha256:44cc64492fb6a6d78d3e6d087f380ae6e479aa1b2c79823b32cdacfcc2f3d715\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:base\",\n\t\t\"paketo-buildpacks/builder:base-platform-api-0.2\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buidpacks/cnb@sha256:5b03a853e636b78c44e475bbc514e2b7b140cc41cca8ab907e9753431ae8c0b0\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=1000\",\n\t\t\t\"CNB_GROUP_ID=1000\",\n\t\t\t\"CNB_STACK_ID=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:2d153261a5e359c632a17377cfb5d1986c27b96c8b6e95334bf80f1029dbd4bb\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core\\\",\\\"version\\\":\\\"0.0.9\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.201\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-runtime\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.196\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-sdk\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-execute\\\",\\\"version\\\":\\\"0.0.180\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-execute\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-publish\\\",\\\"version\\\":\\\"0.0.121\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-publish\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.196\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-aspnet\\\"},{\\\"id\\\":\\\"paketo-buildpacks/java-native-image\\\",\\\"version\\\":\\\"4.7.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/java-native-image\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot\\\"},{\\\"id\\\":\\\"paketo-buildpacks/executable-jar\\\",\\\"version\\\":\\\"3.1.3\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/executable-jar\\\"},{\\\"id\\\":\\\"paketo-buildpacks/graalvm\\\",\\\"version\\\":\\\"4.1.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/graalvm\\\"},{\\\"id\\\":\\\"paketo-buildpacks/gradle\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/gradle\\\"},{\\\"id\\\":\\\"paketo-buildpacks/leiningen\\\",\\\"version\\\":\\\"1.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/leiningen\\\"},{\\\"id\\\":\\\"paketo-buildpacks/sbt\\\",\\\"version\\\":\\\"3.6.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/sbt\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot-native-image\\\",\\\"version\\\":\\\"2.0.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot-native-image\\\"},{\\\"id\\\":\\\"paketo-buildpacks/environment-variables\\\",\\\"version\\\":\\\"2.1.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/environment-variables\\\"},{\\\"id\\\":\\\"paketo-buildpacks/image-labels\\\",\\\"version\\\":\\\"2.0.7\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/image-labels\\\"},{\\\"id\\\":\\\"paketo-buildpacks/maven\\\",\\\"version\\\":\\\"3.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/maven\\\"},{\\\"id\\\":\\\"paketo-buildpacks/java\\\",\\\"version\\\":\\\"4.10.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/java\\\"},{\\\"id\\\":\\\"paketo-buildpacks/ca-certificates\\\",\\\"version\\\":\\\"1.0.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/ca-certificates\\\"},{\\\"id\\\":\\\"paketo-buildpacks/environment-variables\\\",\\\"version\\\":\\\"2.1.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/environment-variables\\\"},{\\\"id\\\":\\\"paketo-buildpacks/executable-jar\\\",\\\"version\\\":\\\"3.1.3\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/executable-jar\\\"},{\\\"id\\\":\\\"paketo-buildpacks/procfile\\\",\\\"version\\\":\\\"3.0.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/procfile\\\"},{\\\"id\\\":\\\"paketo-buildpacks/apache-tomcat\\\",\\\"version\\\":\\\"3.2.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/apache-tomcat\\\"},{\\\"id\\\":\\\"paketo-buildpacks/gradle\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/gradle\\\"},{\\\"id\\\":\\\"paketo-buildpacks/maven\\\",\\\"version\\\":\\\"3.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/maven\\\"},{\\\"id\\\":\\\"paketo-buildpacks/sbt\\\",\\\"version\\\":\\\"3.6.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/sbt\\\"},{\\\"id\\\":\\\"paketo-buildpacks/bellsoft-liberica\\\",\\\"version\\\":\\\"6.2.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/bellsoft-liberica\\\"},{\\\"id\\\":\\\"paketo-buildpacks/google-stackdriver\\\",\\\"version\\\":\\\"2.16.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/google-stackdriver\\\"},{\\\"id\\\":\\\"paketo-buildpacks/image-labels\\\",\\\"version\\\":\\\"2.0.7\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/image-labels\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dist-zip\\\",\\\"version\\\":\\\"2.2.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dist-zip\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot\\\"},{\\\"id\\\":\\\"paketo-buildpacks/jmx\\\",\\\"version\\\":\\\"2.1.4\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/jmx\\\"},{\\\"id\\\":\\\"paketo-buildpacks/leiningen\\\",\\\"version\\\":\\\"1.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/leiningen\\\"}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"\\\",\\\"mirrors\\\":null}},\\\"images\\\":[{\\\"image\\\":\\\"cloudfoundry/run:base-cnb\\\",\\\"mirrors\\\":null}],\\\"lifecycle\\\":{\\\"version\\\":\\\"0.7.2\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.3\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.102\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.2.15\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.2.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.101\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.6\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\\\"}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.118\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.68\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.115\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.127\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.122\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.4\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\\\"}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.105\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.89\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\\\"}},\\\"org.cloudfoundry.icu\\\":{\\\"0.0.43\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.1.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.158\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\\\"},\\\"0.0.163\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v2.0.8\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\\\"}},\\\"org.cloudfoundry.npm\\\":{\\\"0.1.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.2.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.2.13\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.3.18\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\\\"}},\\\"org.cloudfoundry.yarn-install\\\":{\\\"0.1.10\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\"}]}]\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 688884758,\n\t\"VirtualSize\": 688884758,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/6a79181b2840da2706624f46ce5abd4448973b4f951925d5a276b273256063b2/diff:/var/lib/docker/overlay2/429419a203100f60ab16ec6c879fce975c8138422b9053f80accd6124c730fc2/diff:/var/lib/docker/overlay2/6e45ed6daf4f4f3b90fd1ec5fa958775000875661d3e8be3f1af218d192b058d/diff:/var/lib/docker/overlay2/22928ad308cdd55b3fe849d92b6e38c6bc303ba7c9beb8c0e79aa958e16b1864/diff:/var/lib/docker/overlay2/2ca9ec213226a1604f57c8e141d6f1168134a5cb2ccd8f91ee9be5a39036e6bf/diff:/var/lib/docker/overlay2/96ae944fe00ec20cf5b4441b112ebcc9395faaf08108c9ee38c62e1da33af1c8/diff:/var/lib/docker/overlay2/13ee52e300e476e27350c9ac6274dedf26af85c3079b42a41f9dfc92eff57a80/diff:/var/lib/docker/overlay2/223edb4cc62a2ba2b8bda866905a55c4798c6c32e31d22d60e6ed4f3169ce85e/diff:/var/lib/docker/overlay2/a41235cd7277299cb74ead47def3771885948719e24075ea3bf37580f3af7ae2/diff:/var/lib/docker/overlay2/ed0438e8e2c27b9d62ad21a0761237c350a2ffc9e52f47c019e4f627091c832e/diff:/var/lib/docker/overlay2/0c27c8229b31eafc57ab739b44962dcc07b72f3d8950888873ecb3cfd385032f/diff:/var/lib/docker/overlay2/0957cbcca052cd58bcf9a3d945b0e6876b0df79c1c534da1872c3415a019427d/diff:/var/lib/docker/overlay2/b621414d53d71349c07df8ed45e3e04b2e97bfbaf4bf0d86463f46e0f810eeb4/diff:/var/lib/docker/overlay2/ad521bc47f0bb44262358cf47c3d81a544d098494cf24a5b510620d34eb9c353/diff:/var/lib/docker/overlay2/081501d5bfbd927e69c10eb320513c7c0d5f00bea8cf9e55faa90579fd33adf4/diff:/var/lib/docker/overlay2/fb1ba66bee5568f5700c72865d020d4171a62bfdd099c3cc05b9a253d36a35a4/diff:/var/lib/docker/overlay2/06bcc6b3adeca727d554f1a745ee33242dfe1b3c6392023ac947666057303288/diff:/var/lib/docker/overlay2/1c5397d63d893202dffde29013ee826fb695bda26c718ee03ddde376be4da0a3/diff:/var/lib/docker/overlay2/76075fb7fd3c6b3fb116fb3b464e220918e56d94461c61af9a1aff288ebdba60/diff:/var/lib/docker/overlay2/43d1026bb7b618393912ecc9ddf57b604336184d5f8dc70bcf6332b5f08a3e8d/diff:/var/lib/docker/overlay2/ee27d1fba3deaca0556f7bab171cb3368f169011dd132cf335b5308728f6db8f/diff:/var/lib/docker/overlay2/464d3ec8d86ff31dcb5063ea25521368ea8e9c7964f65e15ff5e0e1ecdbe991e/diff:/var/lib/docker/overlay2/a4a80c33c8b78f68bdc9dbd5903cc2ba1d48e78b9a97d43acb018823ece8e6cb/diff:/var/lib/docker/overlay2/6494f2f1693cff8b16d51fa95620eb0bb691a76fb39b5175d953649577791297/diff:/var/lib/docker/overlay2/9d49e146f82eb5fc4fd81613538e9c5f5f95091fbbc8c49729c6c9140ae356de/diff:/var/lib/docker/overlay2/2934818c52bcd017abe000e71342d67fbc9ccb7dbc165ce05e3250e2110229a5/diff:/var/lib/docker/overlay2/651ca06b2bf75e2122855264287fc937f30d2b49229d628909895be7128b4eb6/diff:/var/lib/docker/overlay2/c93bab59be44fa1b66689dc059d26742d00d2e787d06c3236e1f116199c9807e/diff:/var/lib/docker/overlay2/d0a8e2a0c7e0df172f7a8ebe75e2dce371bb6cc65531b06799bc677c5b5e3627/diff:/var/lib/docker/overlay2/7d14bac240e0d7936351e3fac80b7fbe2a209f4de8992091c4f75e41f9627852/diff:/var/lib/docker/overlay2/d6b192ea137a4ae95e309d263ee8c890e35da02aacd9bdcf5adbd4c28a0c0a3f/diff:/var/lib/docker/overlay2/335bfb632ab7723e25fb5dc7b67389e6ec38178ef10bfbf83337501403e61574/diff:/var/lib/docker/overlay2/0293c7e3472da58f51cbdf15fb293ff71e32c1f80f83f00fb09f8941deef5e43/diff:/var/lib/docker/overlay2/55faa8b47bcb0dd29c3836580f451a0461dd499065af9c830beff6e8329ab484/diff:/var/lib/docker/overlay2/afcb6e109c1ba7d71b8a8b7e573d4ce04f22da3fe0ee523359db5cfb95e65bb6/diff:/var/lib/docker/overlay2/b42eefd9bf6629ae9d16e7aba6ba3939d37816aba7a0999f6d639012a3119be1/diff:/var/lib/docker/overlay2/a9832c8f81ee889a622ce4d95d9f4bab2f91d30e18f69bfd7cfc385c781068d4/diff:/var/lib/docker/overlay2/224041c135f13881a98b9e833584bedab81d5650061457f522a1ebd1daa2c77a/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:2df36adfe1af661aebb75a0db796b074bb8f861fbc8f98f6f642570692b3b133\",\n\t\t\t\"sha256:f499c7d34e01d860492ef1cc34b7d7e1319b3c3c81ee7d23258b21605b5902ca\",\n\t\t\t\"sha256:c4bf1d4e5d4adb566b173a0769d247f67c5dd8ff90dfdcebd8c7060f1c06caa9\",\n\t\t\t\"sha256:15259abd479904cbe0d8d421e5b05b2e5745e2bf82e62cdd7fb6d3eafbe4168a\",\n\t\t\t\"sha256:6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a\",\n\t\t\t\"sha256:2d6ad1b66f5660dd860c1fe2d90d26398fcfab4dc1c87c3d5e7c0fc24f8d6fb2\",\n\t\t\t\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\",\n\t\t\t\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\",\n\t\t\t\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\",\n\t\t\t\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\",\n\t\t\t\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\",\n\t\t\t\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\",\n\t\t\t\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\",\n\t\t\t\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\",\n\t\t\t\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\",\n\t\t\t\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\",\n\t\t\t\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\",\n\t\t\t\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\",\n\t\t\t\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\",\n\t\t\t\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\",\n\t\t\t\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\",\n\t\t\t\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\",\n\t\t\t\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\",\n\t\t\t\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\",\n\t\t\t\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\",\n\t\t\t\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\",\n\t\t\t\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\",\n\t\t\t\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\",\n\t\t\t\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\",\n\t\t\t\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\",\n\t\t\t\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\",\n\t\t\t\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\",\n\t\t\t\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\",\n\t\t\t\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\",\n\t\t\t\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\",\n\t\t\t\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\",\n\t\t\t\"sha256:6cf0f8f815d5371cf5c04e7ebf76c62467948d693b8343184d1446036980d261\",\n\t\t\t\"sha256:7cbffcbb09fc5e9d00372e80990016609c09cc3113429ddc951c4a19b1a5ec72\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/image-with-no-run-image-tag.json",
    "content": "{\n\t\"Id\": \"sha256:44cc64492fb6a6d78d3e6d087f380ae6e479aa1b2c79823b32cdacfcc2f3d715\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:base\",\n\t\t\"paketo-buildpacks/builder:base-platform-api-0.2\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buidpacks/cnb@sha256:5b03a853e636b78c44e475bbc514e2b7b140cc41cca8ab907e9753431ae8c0b0\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=1000\",\n\t\t\t\"CNB_GROUP_ID=1000\",\n\t\t\t\"CNB_STACK_ID=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:2d153261a5e359c632a17377cfb5d1986c27b96c8b6e95334bf80f1029dbd4bb\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.1.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.2.13\\\"},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.2.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.3.18\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.4\\\"},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.2.14\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.2.15\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.1.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.102\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v2.0.8\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.1.14\\\"},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.6\\\"},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\"},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\"},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\"}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.7.2\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.3\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.102\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.2.15\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.2.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.101\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.6\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\\\"}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.118\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.68\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.115\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.127\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.122\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.4\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\\\"}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.105\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.89\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\\\"}},\\\"org.cloudfoundry.icu\\\":{\\\"0.0.43\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.1.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.158\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\\\"},\\\"0.0.163\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v2.0.8\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\\\"}},\\\"org.cloudfoundry.npm\\\":{\\\"0.1.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.2.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.2.13\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.3.18\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\\\"}},\\\"org.cloudfoundry.yarn-install\\\":{\\\"0.1.10\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\",\n\t\t\t\"io.buildpacks.stack.mixins\": \"[\\\"build:git\\\",\\\"build:build-essential\\\"]\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 688884758,\n\t\"VirtualSize\": 688884758,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/6a79181b2840da2706624f46ce5abd4448973b4f951925d5a276b273256063b2/diff:/var/lib/docker/overlay2/429419a203100f60ab16ec6c879fce975c8138422b9053f80accd6124c730fc2/diff:/var/lib/docker/overlay2/6e45ed6daf4f4f3b90fd1ec5fa958775000875661d3e8be3f1af218d192b058d/diff:/var/lib/docker/overlay2/22928ad308cdd55b3fe849d92b6e38c6bc303ba7c9beb8c0e79aa958e16b1864/diff:/var/lib/docker/overlay2/2ca9ec213226a1604f57c8e141d6f1168134a5cb2ccd8f91ee9be5a39036e6bf/diff:/var/lib/docker/overlay2/96ae944fe00ec20cf5b4441b112ebcc9395faaf08108c9ee38c62e1da33af1c8/diff:/var/lib/docker/overlay2/13ee52e300e476e27350c9ac6274dedf26af85c3079b42a41f9dfc92eff57a80/diff:/var/lib/docker/overlay2/223edb4cc62a2ba2b8bda866905a55c4798c6c32e31d22d60e6ed4f3169ce85e/diff:/var/lib/docker/overlay2/a41235cd7277299cb74ead47def3771885948719e24075ea3bf37580f3af7ae2/diff:/var/lib/docker/overlay2/ed0438e8e2c27b9d62ad21a0761237c350a2ffc9e52f47c019e4f627091c832e/diff:/var/lib/docker/overlay2/0c27c8229b31eafc57ab739b44962dcc07b72f3d8950888873ecb3cfd385032f/diff:/var/lib/docker/overlay2/0957cbcca052cd58bcf9a3d945b0e6876b0df79c1c534da1872c3415a019427d/diff:/var/lib/docker/overlay2/b621414d53d71349c07df8ed45e3e04b2e97bfbaf4bf0d86463f46e0f810eeb4/diff:/var/lib/docker/overlay2/ad521bc47f0bb44262358cf47c3d81a544d098494cf24a5b510620d34eb9c353/diff:/var/lib/docker/overlay2/081501d5bfbd927e69c10eb320513c7c0d5f00bea8cf9e55faa90579fd33adf4/diff:/var/lib/docker/overlay2/fb1ba66bee5568f5700c72865d020d4171a62bfdd099c3cc05b9a253d36a35a4/diff:/var/lib/docker/overlay2/06bcc6b3adeca727d554f1a745ee33242dfe1b3c6392023ac947666057303288/diff:/var/lib/docker/overlay2/1c5397d63d893202dffde29013ee826fb695bda26c718ee03ddde376be4da0a3/diff:/var/lib/docker/overlay2/76075fb7fd3c6b3fb116fb3b464e220918e56d94461c61af9a1aff288ebdba60/diff:/var/lib/docker/overlay2/43d1026bb7b618393912ecc9ddf57b604336184d5f8dc70bcf6332b5f08a3e8d/diff:/var/lib/docker/overlay2/ee27d1fba3deaca0556f7bab171cb3368f169011dd132cf335b5308728f6db8f/diff:/var/lib/docker/overlay2/464d3ec8d86ff31dcb5063ea25521368ea8e9c7964f65e15ff5e0e1ecdbe991e/diff:/var/lib/docker/overlay2/a4a80c33c8b78f68bdc9dbd5903cc2ba1d48e78b9a97d43acb018823ece8e6cb/diff:/var/lib/docker/overlay2/6494f2f1693cff8b16d51fa95620eb0bb691a76fb39b5175d953649577791297/diff:/var/lib/docker/overlay2/9d49e146f82eb5fc4fd81613538e9c5f5f95091fbbc8c49729c6c9140ae356de/diff:/var/lib/docker/overlay2/2934818c52bcd017abe000e71342d67fbc9ccb7dbc165ce05e3250e2110229a5/diff:/var/lib/docker/overlay2/651ca06b2bf75e2122855264287fc937f30d2b49229d628909895be7128b4eb6/diff:/var/lib/docker/overlay2/c93bab59be44fa1b66689dc059d26742d00d2e787d06c3236e1f116199c9807e/diff:/var/lib/docker/overlay2/d0a8e2a0c7e0df172f7a8ebe75e2dce371bb6cc65531b06799bc677c5b5e3627/diff:/var/lib/docker/overlay2/7d14bac240e0d7936351e3fac80b7fbe2a209f4de8992091c4f75e41f9627852/diff:/var/lib/docker/overlay2/d6b192ea137a4ae95e309d263ee8c890e35da02aacd9bdcf5adbd4c28a0c0a3f/diff:/var/lib/docker/overlay2/335bfb632ab7723e25fb5dc7b67389e6ec38178ef10bfbf83337501403e61574/diff:/var/lib/docker/overlay2/0293c7e3472da58f51cbdf15fb293ff71e32c1f80f83f00fb09f8941deef5e43/diff:/var/lib/docker/overlay2/55faa8b47bcb0dd29c3836580f451a0461dd499065af9c830beff6e8329ab484/diff:/var/lib/docker/overlay2/afcb6e109c1ba7d71b8a8b7e573d4ce04f22da3fe0ee523359db5cfb95e65bb6/diff:/var/lib/docker/overlay2/b42eefd9bf6629ae9d16e7aba6ba3939d37816aba7a0999f6d639012a3119be1/diff:/var/lib/docker/overlay2/a9832c8f81ee889a622ce4d95d9f4bab2f91d30e18f69bfd7cfc385c781068d4/diff:/var/lib/docker/overlay2/224041c135f13881a98b9e833584bedab81d5650061457f522a1ebd1daa2c77a/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:2df36adfe1af661aebb75a0db796b074bb8f861fbc8f98f6f642570692b3b133\",\n\t\t\t\"sha256:f499c7d34e01d860492ef1cc34b7d7e1319b3c3c81ee7d23258b21605b5902ca\",\n\t\t\t\"sha256:c4bf1d4e5d4adb566b173a0769d247f67c5dd8ff90dfdcebd8c7060f1c06caa9\",\n\t\t\t\"sha256:15259abd479904cbe0d8d421e5b05b2e5745e2bf82e62cdd7fb6d3eafbe4168a\",\n\t\t\t\"sha256:6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a\",\n\t\t\t\"sha256:2d6ad1b66f5660dd860c1fe2d90d26398fcfab4dc1c87c3d5e7c0fc24f8d6fb2\",\n\t\t\t\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\",\n\t\t\t\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\",\n\t\t\t\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\",\n\t\t\t\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\",\n\t\t\t\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\",\n\t\t\t\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\",\n\t\t\t\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\",\n\t\t\t\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\",\n\t\t\t\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\",\n\t\t\t\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\",\n\t\t\t\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\",\n\t\t\t\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\",\n\t\t\t\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\",\n\t\t\t\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\",\n\t\t\t\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\",\n\t\t\t\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\",\n\t\t\t\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\",\n\t\t\t\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\",\n\t\t\t\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\",\n\t\t\t\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\",\n\t\t\t\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\",\n\t\t\t\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\",\n\t\t\t\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\",\n\t\t\t\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\",\n\t\t\t\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\",\n\t\t\t\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\",\n\t\t\t\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\",\n\t\t\t\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\",\n\t\t\t\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\",\n\t\t\t\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\",\n\t\t\t\"sha256:6cf0f8f815d5371cf5c04e7ebf76c62467948d693b8343184d1446036980d261\",\n\t\t\t\"sha256:7cbffcbb09fc5e9d00372e80990016609c09cc3113429ddc951c4a19b1a5ec72\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/image-with-platform.json",
    "content": "{\n\t\"Id\": \"sha256:44cc64492fb6a6d78d3e6d087f380ae6e479aa1b2c79823b32cdacfcc2f3d715\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:base\",\n\t\t\"paketo-buildpacks/builder:base-platform-api-0.2\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buidpacks/cnb@sha256:5b03a853e636b78c44e475bbc514e2b7b140cc41cca8ab907e9753431ae8c0b0\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=1000\",\n\t\t\t\"CNB_GROUP_ID=1000\",\n\t\t\t\"CNB_STACK_ID=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:2d153261a5e359c632a17377cfb5d1986c27b96c8b6e95334bf80f1029dbd4bb\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core\\\",\\\"version\\\":\\\"0.0.9\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.201\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-runtime\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.196\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-sdk\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-execute\\\",\\\"version\\\":\\\"0.0.180\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-execute\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-publish\\\",\\\"version\\\":\\\"0.0.121\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-publish\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.196\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-aspnet\\\"},{\\\"id\\\":\\\"paketo-buildpacks/java-native-image\\\",\\\"version\\\":\\\"4.7.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/java-native-image\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot\\\"},{\\\"id\\\":\\\"paketo-buildpacks/executable-jar\\\",\\\"version\\\":\\\"3.1.3\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/executable-jar\\\"},{\\\"id\\\":\\\"paketo-buildpacks/graalvm\\\",\\\"version\\\":\\\"4.1.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/graalvm\\\"},{\\\"id\\\":\\\"paketo-buildpacks/gradle\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/gradle\\\"},{\\\"id\\\":\\\"paketo-buildpacks/leiningen\\\",\\\"version\\\":\\\"1.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/leiningen\\\"},{\\\"id\\\":\\\"paketo-buildpacks/sbt\\\",\\\"version\\\":\\\"3.6.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/sbt\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot-native-image\\\",\\\"version\\\":\\\"2.0.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot-native-image\\\"},{\\\"id\\\":\\\"paketo-buildpacks/environment-variables\\\",\\\"version\\\":\\\"2.1.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/environment-variables\\\"},{\\\"id\\\":\\\"paketo-buildpacks/image-labels\\\",\\\"version\\\":\\\"2.0.7\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/image-labels\\\"},{\\\"id\\\":\\\"paketo-buildpacks/maven\\\",\\\"version\\\":\\\"3.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/maven\\\"},{\\\"id\\\":\\\"paketo-buildpacks/java\\\",\\\"version\\\":\\\"4.10.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/java\\\"},{\\\"id\\\":\\\"paketo-buildpacks/ca-certificates\\\",\\\"version\\\":\\\"1.0.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/ca-certificates\\\"},{\\\"id\\\":\\\"paketo-buildpacks/environment-variables\\\",\\\"version\\\":\\\"2.1.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/environment-variables\\\"},{\\\"id\\\":\\\"paketo-buildpacks/executable-jar\\\",\\\"version\\\":\\\"3.1.3\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/executable-jar\\\"},{\\\"id\\\":\\\"paketo-buildpacks/procfile\\\",\\\"version\\\":\\\"3.0.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/procfile\\\"},{\\\"id\\\":\\\"paketo-buildpacks/apache-tomcat\\\",\\\"version\\\":\\\"3.2.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/apache-tomcat\\\"},{\\\"id\\\":\\\"paketo-buildpacks/gradle\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/gradle\\\"},{\\\"id\\\":\\\"paketo-buildpacks/maven\\\",\\\"version\\\":\\\"3.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/maven\\\"},{\\\"id\\\":\\\"paketo-buildpacks/sbt\\\",\\\"version\\\":\\\"3.6.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/sbt\\\"},{\\\"id\\\":\\\"paketo-buildpacks/bellsoft-liberica\\\",\\\"version\\\":\\\"6.2.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/bellsoft-liberica\\\"},{\\\"id\\\":\\\"paketo-buildpacks/google-stackdriver\\\",\\\"version\\\":\\\"2.16.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/google-stackdriver\\\"},{\\\"id\\\":\\\"paketo-buildpacks/image-labels\\\",\\\"version\\\":\\\"2.0.7\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/image-labels\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dist-zip\\\",\\\"version\\\":\\\"2.2.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dist-zip\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot\\\"},{\\\"id\\\":\\\"paketo-buildpacks/jmx\\\",\\\"version\\\":\\\"2.1.4\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/jmx\\\"},{\\\"id\\\":\\\"paketo-buildpacks/leiningen\\\",\\\"version\\\":\\\"1.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/leiningen\\\"}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run:base-cnb\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.7.2\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.3\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.102\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.2.15\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.2.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.101\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.6\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\\\"}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.118\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.68\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.115\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.127\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.122\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.4\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\\\"}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.105\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.89\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\\\"}},\\\"org.cloudfoundry.icu\\\":{\\\"0.0.43\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.1.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.158\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\\\"},\\\"0.0.163\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v2.0.8\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\\\"}},\\\"org.cloudfoundry.npm\\\":{\\\"0.1.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.2.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.2.13\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.3.18\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\\\"}},\\\"org.cloudfoundry.yarn-install\\\":{\\\"0.1.10\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\",\n\t\t\t\"io.buildpacks.stack.mixins\": \"[\\\"build:git\\\",\\\"build:build-essential\\\"]\"\n\t\t}\n\t},\n\t\"Architecture\": \"arm64\",\n\t\"Os\": \"linux\",\n  \"Variant\": \"v1\",\n\t\"Size\": 688884758,\n\t\"VirtualSize\": 688884758,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/6a79181b2840da2706624f46ce5abd4448973b4f951925d5a276b273256063b2/diff:/var/lib/docker/overlay2/429419a203100f60ab16ec6c879fce975c8138422b9053f80accd6124c730fc2/diff:/var/lib/docker/overlay2/6e45ed6daf4f4f3b90fd1ec5fa958775000875661d3e8be3f1af218d192b058d/diff:/var/lib/docker/overlay2/22928ad308cdd55b3fe849d92b6e38c6bc303ba7c9beb8c0e79aa958e16b1864/diff:/var/lib/docker/overlay2/2ca9ec213226a1604f57c8e141d6f1168134a5cb2ccd8f91ee9be5a39036e6bf/diff:/var/lib/docker/overlay2/96ae944fe00ec20cf5b4441b112ebcc9395faaf08108c9ee38c62e1da33af1c8/diff:/var/lib/docker/overlay2/13ee52e300e476e27350c9ac6274dedf26af85c3079b42a41f9dfc92eff57a80/diff:/var/lib/docker/overlay2/223edb4cc62a2ba2b8bda866905a55c4798c6c32e31d22d60e6ed4f3169ce85e/diff:/var/lib/docker/overlay2/a41235cd7277299cb74ead47def3771885948719e24075ea3bf37580f3af7ae2/diff:/var/lib/docker/overlay2/ed0438e8e2c27b9d62ad21a0761237c350a2ffc9e52f47c019e4f627091c832e/diff:/var/lib/docker/overlay2/0c27c8229b31eafc57ab739b44962dcc07b72f3d8950888873ecb3cfd385032f/diff:/var/lib/docker/overlay2/0957cbcca052cd58bcf9a3d945b0e6876b0df79c1c534da1872c3415a019427d/diff:/var/lib/docker/overlay2/b621414d53d71349c07df8ed45e3e04b2e97bfbaf4bf0d86463f46e0f810eeb4/diff:/var/lib/docker/overlay2/ad521bc47f0bb44262358cf47c3d81a544d098494cf24a5b510620d34eb9c353/diff:/var/lib/docker/overlay2/081501d5bfbd927e69c10eb320513c7c0d5f00bea8cf9e55faa90579fd33adf4/diff:/var/lib/docker/overlay2/fb1ba66bee5568f5700c72865d020d4171a62bfdd099c3cc05b9a253d36a35a4/diff:/var/lib/docker/overlay2/06bcc6b3adeca727d554f1a745ee33242dfe1b3c6392023ac947666057303288/diff:/var/lib/docker/overlay2/1c5397d63d893202dffde29013ee826fb695bda26c718ee03ddde376be4da0a3/diff:/var/lib/docker/overlay2/76075fb7fd3c6b3fb116fb3b464e220918e56d94461c61af9a1aff288ebdba60/diff:/var/lib/docker/overlay2/43d1026bb7b618393912ecc9ddf57b604336184d5f8dc70bcf6332b5f08a3e8d/diff:/var/lib/docker/overlay2/ee27d1fba3deaca0556f7bab171cb3368f169011dd132cf335b5308728f6db8f/diff:/var/lib/docker/overlay2/464d3ec8d86ff31dcb5063ea25521368ea8e9c7964f65e15ff5e0e1ecdbe991e/diff:/var/lib/docker/overlay2/a4a80c33c8b78f68bdc9dbd5903cc2ba1d48e78b9a97d43acb018823ece8e6cb/diff:/var/lib/docker/overlay2/6494f2f1693cff8b16d51fa95620eb0bb691a76fb39b5175d953649577791297/diff:/var/lib/docker/overlay2/9d49e146f82eb5fc4fd81613538e9c5f5f95091fbbc8c49729c6c9140ae356de/diff:/var/lib/docker/overlay2/2934818c52bcd017abe000e71342d67fbc9ccb7dbc165ce05e3250e2110229a5/diff:/var/lib/docker/overlay2/651ca06b2bf75e2122855264287fc937f30d2b49229d628909895be7128b4eb6/diff:/var/lib/docker/overlay2/c93bab59be44fa1b66689dc059d26742d00d2e787d06c3236e1f116199c9807e/diff:/var/lib/docker/overlay2/d0a8e2a0c7e0df172f7a8ebe75e2dce371bb6cc65531b06799bc677c5b5e3627/diff:/var/lib/docker/overlay2/7d14bac240e0d7936351e3fac80b7fbe2a209f4de8992091c4f75e41f9627852/diff:/var/lib/docker/overlay2/d6b192ea137a4ae95e309d263ee8c890e35da02aacd9bdcf5adbd4c28a0c0a3f/diff:/var/lib/docker/overlay2/335bfb632ab7723e25fb5dc7b67389e6ec38178ef10bfbf83337501403e61574/diff:/var/lib/docker/overlay2/0293c7e3472da58f51cbdf15fb293ff71e32c1f80f83f00fb09f8941deef5e43/diff:/var/lib/docker/overlay2/55faa8b47bcb0dd29c3836580f451a0461dd499065af9c830beff6e8329ab484/diff:/var/lib/docker/overlay2/afcb6e109c1ba7d71b8a8b7e573d4ce04f22da3fe0ee523359db5cfb95e65bb6/diff:/var/lib/docker/overlay2/b42eefd9bf6629ae9d16e7aba6ba3939d37816aba7a0999f6d639012a3119be1/diff:/var/lib/docker/overlay2/a9832c8f81ee889a622ce4d95d9f4bab2f91d30e18f69bfd7cfc385c781068d4/diff:/var/lib/docker/overlay2/224041c135f13881a98b9e833584bedab81d5650061457f522a1ebd1daa2c77a/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:2df36adfe1af661aebb75a0db796b074bb8f861fbc8f98f6f642570692b3b133\",\n\t\t\t\"sha256:f499c7d34e01d860492ef1cc34b7d7e1319b3c3c81ee7d23258b21605b5902ca\",\n\t\t\t\"sha256:c4bf1d4e5d4adb566b173a0769d247f67c5dd8ff90dfdcebd8c7060f1c06caa9\",\n\t\t\t\"sha256:15259abd479904cbe0d8d421e5b05b2e5745e2bf82e62cdd7fb6d3eafbe4168a\",\n\t\t\t\"sha256:6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a\",\n\t\t\t\"sha256:2d6ad1b66f5660dd860c1fe2d90d26398fcfab4dc1c87c3d5e7c0fc24f8d6fb2\",\n\t\t\t\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\",\n\t\t\t\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\",\n\t\t\t\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\",\n\t\t\t\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\",\n\t\t\t\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\",\n\t\t\t\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\",\n\t\t\t\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\",\n\t\t\t\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\",\n\t\t\t\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\",\n\t\t\t\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\",\n\t\t\t\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\",\n\t\t\t\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\",\n\t\t\t\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\",\n\t\t\t\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\",\n\t\t\t\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\",\n\t\t\t\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\",\n\t\t\t\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\",\n\t\t\t\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\",\n\t\t\t\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\",\n\t\t\t\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\",\n\t\t\t\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\",\n\t\t\t\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\",\n\t\t\t\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\",\n\t\t\t\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\",\n\t\t\t\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\",\n\t\t\t\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\",\n\t\t\t\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\",\n\t\t\t\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\",\n\t\t\t\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\",\n\t\t\t\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\",\n\t\t\t\"sha256:6cf0f8f815d5371cf5c04e7ebf76c62467948d693b8343184d1446036980d261\",\n\t\t\t\"sha256:7cbffcbb09fc5e9d00372e80990016609c09cc3113429ddc951c4a19b1a5ec72\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/image-with-run-image-different-registry.json",
    "content": "{\n\t\"Id\": \"sha256:44cc64492fb6a6d78d3e6d087f380ae6e479aa1b2c79823b32cdacfcc2f3d715\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:base\",\n\t\t\"paketo-buildpacks/builder:base-platform-api-0.2\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buidpacks/cnb@sha256:5b03a853e636b78c44e475bbc514e2b7b140cc41cca8ab907e9753431ae8c0b0\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=1000\",\n\t\t\t\"CNB_GROUP_ID=1000\",\n\t\t\t\"CNB_STACK_ID=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:2d153261a5e359c632a17377cfb5d1986c27b96c8b6e95334bf80f1029dbd4bb\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.1.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.2.13\\\"},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.2.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.3.18\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.4\\\"},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.2.14\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.2.15\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.1.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.102\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v2.0.8\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.1.14\\\"},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.6\\\"},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\"},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\"},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\"}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"example.com/custom/run:latest\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.7.2\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.3\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.102\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.2.15\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.2.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.101\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.6\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\\\"}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.118\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.68\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.115\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.127\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.122\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.4\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\\\"}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.105\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.89\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\\\"}},\\\"org.cloudfoundry.icu\\\":{\\\"0.0.43\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.1.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.158\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\\\"},\\\"0.0.163\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v2.0.8\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\\\"}},\\\"org.cloudfoundry.npm\\\":{\\\"0.1.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.2.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.2.13\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.3.18\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\\\"}},\\\"org.cloudfoundry.yarn-install\\\":{\\\"0.1.10\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\",\n\t\t\t\"io.buildpacks.stack.mixins\": \"[\\\"build:git\\\",\\\"build:build-essential\\\"]\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 688884758,\n\t\"VirtualSize\": 688884758,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/6a79181b2840da2706624f46ce5abd4448973b4f951925d5a276b273256063b2/diff:/var/lib/docker/overlay2/429419a203100f60ab16ec6c879fce975c8138422b9053f80accd6124c730fc2/diff:/var/lib/docker/overlay2/6e45ed6daf4f4f3b90fd1ec5fa958775000875661d3e8be3f1af218d192b058d/diff:/var/lib/docker/overlay2/22928ad308cdd55b3fe849d92b6e38c6bc303ba7c9beb8c0e79aa958e16b1864/diff:/var/lib/docker/overlay2/2ca9ec213226a1604f57c8e141d6f1168134a5cb2ccd8f91ee9be5a39036e6bf/diff:/var/lib/docker/overlay2/96ae944fe00ec20cf5b4441b112ebcc9395faaf08108c9ee38c62e1da33af1c8/diff:/var/lib/docker/overlay2/13ee52e300e476e27350c9ac6274dedf26af85c3079b42a41f9dfc92eff57a80/diff:/var/lib/docker/overlay2/223edb4cc62a2ba2b8bda866905a55c4798c6c32e31d22d60e6ed4f3169ce85e/diff:/var/lib/docker/overlay2/a41235cd7277299cb74ead47def3771885948719e24075ea3bf37580f3af7ae2/diff:/var/lib/docker/overlay2/ed0438e8e2c27b9d62ad21a0761237c350a2ffc9e52f47c019e4f627091c832e/diff:/var/lib/docker/overlay2/0c27c8229b31eafc57ab739b44962dcc07b72f3d8950888873ecb3cfd385032f/diff:/var/lib/docker/overlay2/0957cbcca052cd58bcf9a3d945b0e6876b0df79c1c534da1872c3415a019427d/diff:/var/lib/docker/overlay2/b621414d53d71349c07df8ed45e3e04b2e97bfbaf4bf0d86463f46e0f810eeb4/diff:/var/lib/docker/overlay2/ad521bc47f0bb44262358cf47c3d81a544d098494cf24a5b510620d34eb9c353/diff:/var/lib/docker/overlay2/081501d5bfbd927e69c10eb320513c7c0d5f00bea8cf9e55faa90579fd33adf4/diff:/var/lib/docker/overlay2/fb1ba66bee5568f5700c72865d020d4171a62bfdd099c3cc05b9a253d36a35a4/diff:/var/lib/docker/overlay2/06bcc6b3adeca727d554f1a745ee33242dfe1b3c6392023ac947666057303288/diff:/var/lib/docker/overlay2/1c5397d63d893202dffde29013ee826fb695bda26c718ee03ddde376be4da0a3/diff:/var/lib/docker/overlay2/76075fb7fd3c6b3fb116fb3b464e220918e56d94461c61af9a1aff288ebdba60/diff:/var/lib/docker/overlay2/43d1026bb7b618393912ecc9ddf57b604336184d5f8dc70bcf6332b5f08a3e8d/diff:/var/lib/docker/overlay2/ee27d1fba3deaca0556f7bab171cb3368f169011dd132cf335b5308728f6db8f/diff:/var/lib/docker/overlay2/464d3ec8d86ff31dcb5063ea25521368ea8e9c7964f65e15ff5e0e1ecdbe991e/diff:/var/lib/docker/overlay2/a4a80c33c8b78f68bdc9dbd5903cc2ba1d48e78b9a97d43acb018823ece8e6cb/diff:/var/lib/docker/overlay2/6494f2f1693cff8b16d51fa95620eb0bb691a76fb39b5175d953649577791297/diff:/var/lib/docker/overlay2/9d49e146f82eb5fc4fd81613538e9c5f5f95091fbbc8c49729c6c9140ae356de/diff:/var/lib/docker/overlay2/2934818c52bcd017abe000e71342d67fbc9ccb7dbc165ce05e3250e2110229a5/diff:/var/lib/docker/overlay2/651ca06b2bf75e2122855264287fc937f30d2b49229d628909895be7128b4eb6/diff:/var/lib/docker/overlay2/c93bab59be44fa1b66689dc059d26742d00d2e787d06c3236e1f116199c9807e/diff:/var/lib/docker/overlay2/d0a8e2a0c7e0df172f7a8ebe75e2dce371bb6cc65531b06799bc677c5b5e3627/diff:/var/lib/docker/overlay2/7d14bac240e0d7936351e3fac80b7fbe2a209f4de8992091c4f75e41f9627852/diff:/var/lib/docker/overlay2/d6b192ea137a4ae95e309d263ee8c890e35da02aacd9bdcf5adbd4c28a0c0a3f/diff:/var/lib/docker/overlay2/335bfb632ab7723e25fb5dc7b67389e6ec38178ef10bfbf83337501403e61574/diff:/var/lib/docker/overlay2/0293c7e3472da58f51cbdf15fb293ff71e32c1f80f83f00fb09f8941deef5e43/diff:/var/lib/docker/overlay2/55faa8b47bcb0dd29c3836580f451a0461dd499065af9c830beff6e8329ab484/diff:/var/lib/docker/overlay2/afcb6e109c1ba7d71b8a8b7e573d4ce04f22da3fe0ee523359db5cfb95e65bb6/diff:/var/lib/docker/overlay2/b42eefd9bf6629ae9d16e7aba6ba3939d37816aba7a0999f6d639012a3119be1/diff:/var/lib/docker/overlay2/a9832c8f81ee889a622ce4d95d9f4bab2f91d30e18f69bfd7cfc385c781068d4/diff:/var/lib/docker/overlay2/224041c135f13881a98b9e833584bedab81d5650061457f522a1ebd1daa2c77a/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:2df36adfe1af661aebb75a0db796b074bb8f861fbc8f98f6f642570692b3b133\",\n\t\t\t\"sha256:f499c7d34e01d860492ef1cc34b7d7e1319b3c3c81ee7d23258b21605b5902ca\",\n\t\t\t\"sha256:c4bf1d4e5d4adb566b173a0769d247f67c5dd8ff90dfdcebd8c7060f1c06caa9\",\n\t\t\t\"sha256:15259abd479904cbe0d8d421e5b05b2e5745e2bf82e62cdd7fb6d3eafbe4168a\",\n\t\t\t\"sha256:6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a\",\n\t\t\t\"sha256:2d6ad1b66f5660dd860c1fe2d90d26398fcfab4dc1c87c3d5e7c0fc24f8d6fb2\",\n\t\t\t\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\",\n\t\t\t\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\",\n\t\t\t\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\",\n\t\t\t\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\",\n\t\t\t\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\",\n\t\t\t\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\",\n\t\t\t\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\",\n\t\t\t\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\",\n\t\t\t\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\",\n\t\t\t\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\",\n\t\t\t\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\",\n\t\t\t\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\",\n\t\t\t\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\",\n\t\t\t\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\",\n\t\t\t\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\",\n\t\t\t\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\",\n\t\t\t\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\",\n\t\t\t\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\",\n\t\t\t\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\",\n\t\t\t\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\",\n\t\t\t\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\",\n\t\t\t\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\",\n\t\t\t\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\",\n\t\t\t\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\",\n\t\t\t\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\",\n\t\t\t\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\",\n\t\t\t\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\",\n\t\t\t\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\",\n\t\t\t\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\",\n\t\t\t\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\",\n\t\t\t\"sha256:6cf0f8f815d5371cf5c04e7ebf76c62467948d693b8343184d1446036980d261\",\n\t\t\t\"sha256:7cbffcbb09fc5e9d00372e80990016609c09cc3113429ddc951c4a19b1a5ec72\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/image-with-run-image-digest.json",
    "content": "{\n\t\"Id\": \"sha256:44cc64492fb6a6d78d3e6d087f380ae6e479aa1b2c79823b32cdacfcc2f3d715\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:base\",\n\t\t\"paketo-buildpacks/builder:base-platform-api-0.2\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buidpacks/cnb@sha256:5b03a853e636b78c44e475bbc514e2b7b140cc41cca8ab907e9753431ae8c0b0\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=1000\",\n\t\t\t\"CNB_GROUP_ID=1000\",\n\t\t\t\"CNB_STACK_ID=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:2d153261a5e359c632a17377cfb5d1986c27b96c8b6e95334bf80f1029dbd4bb\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.1.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.2.13\\\"},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.2.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.3.18\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.4\\\"},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.2.14\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.2.15\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.1.11\\\"},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.102\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v2.0.8\\\"},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.1.14\\\"},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.6\\\"},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.1.12\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\"},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\"},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\"}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.7.2\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.3\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.102\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.2.15\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.2.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.101\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.6\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\\\"}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.118\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.68\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.115\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.127\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.122\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.4\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\\\"}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.105\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.89\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\\\"}},\\\"org.cloudfoundry.icu\\\":{\\\"0.0.43\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.1.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.158\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\\\"},\\\"0.0.163\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v2.0.8\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\\\"}},\\\"org.cloudfoundry.npm\\\":{\\\"0.1.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.2.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.2.13\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.3.18\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\\\"}},\\\"org.cloudfoundry.yarn-install\\\":{\\\"0.1.10\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\",\n\t\t\t\"io.buildpacks.stack.mixins\": \"[\\\"build:git\\\",\\\"build:build-essential\\\"]\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 688884758,\n\t\"VirtualSize\": 688884758,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/6a79181b2840da2706624f46ce5abd4448973b4f951925d5a276b273256063b2/diff:/var/lib/docker/overlay2/429419a203100f60ab16ec6c879fce975c8138422b9053f80accd6124c730fc2/diff:/var/lib/docker/overlay2/6e45ed6daf4f4f3b90fd1ec5fa958775000875661d3e8be3f1af218d192b058d/diff:/var/lib/docker/overlay2/22928ad308cdd55b3fe849d92b6e38c6bc303ba7c9beb8c0e79aa958e16b1864/diff:/var/lib/docker/overlay2/2ca9ec213226a1604f57c8e141d6f1168134a5cb2ccd8f91ee9be5a39036e6bf/diff:/var/lib/docker/overlay2/96ae944fe00ec20cf5b4441b112ebcc9395faaf08108c9ee38c62e1da33af1c8/diff:/var/lib/docker/overlay2/13ee52e300e476e27350c9ac6274dedf26af85c3079b42a41f9dfc92eff57a80/diff:/var/lib/docker/overlay2/223edb4cc62a2ba2b8bda866905a55c4798c6c32e31d22d60e6ed4f3169ce85e/diff:/var/lib/docker/overlay2/a41235cd7277299cb74ead47def3771885948719e24075ea3bf37580f3af7ae2/diff:/var/lib/docker/overlay2/ed0438e8e2c27b9d62ad21a0761237c350a2ffc9e52f47c019e4f627091c832e/diff:/var/lib/docker/overlay2/0c27c8229b31eafc57ab739b44962dcc07b72f3d8950888873ecb3cfd385032f/diff:/var/lib/docker/overlay2/0957cbcca052cd58bcf9a3d945b0e6876b0df79c1c534da1872c3415a019427d/diff:/var/lib/docker/overlay2/b621414d53d71349c07df8ed45e3e04b2e97bfbaf4bf0d86463f46e0f810eeb4/diff:/var/lib/docker/overlay2/ad521bc47f0bb44262358cf47c3d81a544d098494cf24a5b510620d34eb9c353/diff:/var/lib/docker/overlay2/081501d5bfbd927e69c10eb320513c7c0d5f00bea8cf9e55faa90579fd33adf4/diff:/var/lib/docker/overlay2/fb1ba66bee5568f5700c72865d020d4171a62bfdd099c3cc05b9a253d36a35a4/diff:/var/lib/docker/overlay2/06bcc6b3adeca727d554f1a745ee33242dfe1b3c6392023ac947666057303288/diff:/var/lib/docker/overlay2/1c5397d63d893202dffde29013ee826fb695bda26c718ee03ddde376be4da0a3/diff:/var/lib/docker/overlay2/76075fb7fd3c6b3fb116fb3b464e220918e56d94461c61af9a1aff288ebdba60/diff:/var/lib/docker/overlay2/43d1026bb7b618393912ecc9ddf57b604336184d5f8dc70bcf6332b5f08a3e8d/diff:/var/lib/docker/overlay2/ee27d1fba3deaca0556f7bab171cb3368f169011dd132cf335b5308728f6db8f/diff:/var/lib/docker/overlay2/464d3ec8d86ff31dcb5063ea25521368ea8e9c7964f65e15ff5e0e1ecdbe991e/diff:/var/lib/docker/overlay2/a4a80c33c8b78f68bdc9dbd5903cc2ba1d48e78b9a97d43acb018823ece8e6cb/diff:/var/lib/docker/overlay2/6494f2f1693cff8b16d51fa95620eb0bb691a76fb39b5175d953649577791297/diff:/var/lib/docker/overlay2/9d49e146f82eb5fc4fd81613538e9c5f5f95091fbbc8c49729c6c9140ae356de/diff:/var/lib/docker/overlay2/2934818c52bcd017abe000e71342d67fbc9ccb7dbc165ce05e3250e2110229a5/diff:/var/lib/docker/overlay2/651ca06b2bf75e2122855264287fc937f30d2b49229d628909895be7128b4eb6/diff:/var/lib/docker/overlay2/c93bab59be44fa1b66689dc059d26742d00d2e787d06c3236e1f116199c9807e/diff:/var/lib/docker/overlay2/d0a8e2a0c7e0df172f7a8ebe75e2dce371bb6cc65531b06799bc677c5b5e3627/diff:/var/lib/docker/overlay2/7d14bac240e0d7936351e3fac80b7fbe2a209f4de8992091c4f75e41f9627852/diff:/var/lib/docker/overlay2/d6b192ea137a4ae95e309d263ee8c890e35da02aacd9bdcf5adbd4c28a0c0a3f/diff:/var/lib/docker/overlay2/335bfb632ab7723e25fb5dc7b67389e6ec38178ef10bfbf83337501403e61574/diff:/var/lib/docker/overlay2/0293c7e3472da58f51cbdf15fb293ff71e32c1f80f83f00fb09f8941deef5e43/diff:/var/lib/docker/overlay2/55faa8b47bcb0dd29c3836580f451a0461dd499065af9c830beff6e8329ab484/diff:/var/lib/docker/overlay2/afcb6e109c1ba7d71b8a8b7e573d4ce04f22da3fe0ee523359db5cfb95e65bb6/diff:/var/lib/docker/overlay2/b42eefd9bf6629ae9d16e7aba6ba3939d37816aba7a0999f6d639012a3119be1/diff:/var/lib/docker/overlay2/a9832c8f81ee889a622ce4d95d9f4bab2f91d30e18f69bfd7cfc385c781068d4/diff:/var/lib/docker/overlay2/224041c135f13881a98b9e833584bedab81d5650061457f522a1ebd1daa2c77a/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:2df36adfe1af661aebb75a0db796b074bb8f861fbc8f98f6f642570692b3b133\",\n\t\t\t\"sha256:f499c7d34e01d860492ef1cc34b7d7e1319b3c3c81ee7d23258b21605b5902ca\",\n\t\t\t\"sha256:c4bf1d4e5d4adb566b173a0769d247f67c5dd8ff90dfdcebd8c7060f1c06caa9\",\n\t\t\t\"sha256:15259abd479904cbe0d8d421e5b05b2e5745e2bf82e62cdd7fb6d3eafbe4168a\",\n\t\t\t\"sha256:6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a\",\n\t\t\t\"sha256:2d6ad1b66f5660dd860c1fe2d90d26398fcfab4dc1c87c3d5e7c0fc24f8d6fb2\",\n\t\t\t\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\",\n\t\t\t\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\",\n\t\t\t\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\",\n\t\t\t\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\",\n\t\t\t\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\",\n\t\t\t\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\",\n\t\t\t\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\",\n\t\t\t\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\",\n\t\t\t\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\",\n\t\t\t\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\",\n\t\t\t\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\",\n\t\t\t\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\",\n\t\t\t\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\",\n\t\t\t\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\",\n\t\t\t\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\",\n\t\t\t\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\",\n\t\t\t\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\",\n\t\t\t\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\",\n\t\t\t\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\",\n\t\t\t\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\",\n\t\t\t\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\",\n\t\t\t\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\",\n\t\t\t\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\",\n\t\t\t\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\",\n\t\t\t\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\",\n\t\t\t\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\",\n\t\t\t\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\",\n\t\t\t\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\",\n\t\t\t\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\",\n\t\t\t\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\",\n\t\t\t\"sha256:6cf0f8f815d5371cf5c04e7ebf76c62467948d693b8343184d1446036980d261\",\n\t\t\t\"sha256:7cbffcbb09fc5e9d00372e80990016609c09cc3113429ddc951c4a19b1a5ec72\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/image.json",
    "content": "{\n\t\"Id\": \"sha256:44cc64492fb6a6d78d3e6d087f380ae6e479aa1b2c79823b32cdacfcc2f3d715\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:base\",\n\t\t\"paketo-buildpacks/builder:base-platform-api-0.2\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buidpacks/cnb@sha256:5b03a853e636b78c44e475bbc514e2b7b140cc41cca8ab907e9753431ae8c0b0\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"Container\": \"\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": null,\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": null\n\t},\n\t\"DockerVersion\": \"\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=1000\",\n\t\t\t\"CNB_GROUP_ID=1000\",\n\t\t\t\"CNB_STACK_ID=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:2d153261a5e359c632a17377cfb5d1986c27b96c8b6e95334bf80f1029dbd4bb\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core\\\",\\\"version\\\":\\\"0.0.9\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.201\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-runtime\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.196\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-sdk\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-execute\\\",\\\"version\\\":\\\"0.0.180\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-execute\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-publish\\\",\\\"version\\\":\\\"0.0.121\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-publish\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.196\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dotnet-core-aspnet\\\"},{\\\"id\\\":\\\"paketo-buildpacks/java-native-image\\\",\\\"version\\\":\\\"4.7.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/java-native-image\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot\\\"},{\\\"id\\\":\\\"paketo-buildpacks/executable-jar\\\",\\\"version\\\":\\\"3.1.3\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/executable-jar\\\"},{\\\"id\\\":\\\"paketo-buildpacks/graalvm\\\",\\\"version\\\":\\\"4.1.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/graalvm\\\"},{\\\"id\\\":\\\"paketo-buildpacks/gradle\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/gradle\\\"},{\\\"id\\\":\\\"paketo-buildpacks/leiningen\\\",\\\"version\\\":\\\"1.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/leiningen\\\"},{\\\"id\\\":\\\"paketo-buildpacks/sbt\\\",\\\"version\\\":\\\"3.6.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/sbt\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot-native-image\\\",\\\"version\\\":\\\"2.0.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot-native-image\\\"},{\\\"id\\\":\\\"paketo-buildpacks/environment-variables\\\",\\\"version\\\":\\\"2.1.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/environment-variables\\\"},{\\\"id\\\":\\\"paketo-buildpacks/image-labels\\\",\\\"version\\\":\\\"2.0.7\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/image-labels\\\"},{\\\"id\\\":\\\"paketo-buildpacks/maven\\\",\\\"version\\\":\\\"3.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/maven\\\"},{\\\"id\\\":\\\"paketo-buildpacks/java\\\",\\\"version\\\":\\\"4.10.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/java\\\"},{\\\"id\\\":\\\"paketo-buildpacks/ca-certificates\\\",\\\"version\\\":\\\"1.0.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/ca-certificates\\\"},{\\\"id\\\":\\\"paketo-buildpacks/environment-variables\\\",\\\"version\\\":\\\"2.1.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/environment-variables\\\"},{\\\"id\\\":\\\"paketo-buildpacks/executable-jar\\\",\\\"version\\\":\\\"3.1.3\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/executable-jar\\\"},{\\\"id\\\":\\\"paketo-buildpacks/procfile\\\",\\\"version\\\":\\\"3.0.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/procfile\\\"},{\\\"id\\\":\\\"paketo-buildpacks/apache-tomcat\\\",\\\"version\\\":\\\"3.2.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/apache-tomcat\\\"},{\\\"id\\\":\\\"paketo-buildpacks/gradle\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/gradle\\\"},{\\\"id\\\":\\\"paketo-buildpacks/maven\\\",\\\"version\\\":\\\"3.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/maven\\\"},{\\\"id\\\":\\\"paketo-buildpacks/sbt\\\",\\\"version\\\":\\\"3.6.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/sbt\\\"},{\\\"id\\\":\\\"paketo-buildpacks/bellsoft-liberica\\\",\\\"version\\\":\\\"6.2.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/bellsoft-liberica\\\"},{\\\"id\\\":\\\"paketo-buildpacks/google-stackdriver\\\",\\\"version\\\":\\\"2.16.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/google-stackdriver\\\"},{\\\"id\\\":\\\"paketo-buildpacks/image-labels\\\",\\\"version\\\":\\\"2.0.7\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/image-labels\\\"},{\\\"id\\\":\\\"paketo-buildpacks/dist-zip\\\",\\\"version\\\":\\\"2.2.2\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/dist-zip\\\"},{\\\"id\\\":\\\"paketo-buildpacks/spring-boot\\\",\\\"version\\\":\\\"3.5.0\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/spring-boot\\\"},{\\\"id\\\":\\\"paketo-buildpacks/jmx\\\",\\\"version\\\":\\\"2.1.4\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/jmx\\\"},{\\\"id\\\":\\\"paketo-buildpacks/leiningen\\\",\\\"version\\\":\\\"1.2.1\\\",\\\"homepage\\\":\\\"https://github.com/paketo-buildpacks/leiningen\\\"}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run:base-cnb\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.7.2\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.3\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.9.0 (git sha: d42c384a39f367588f2653f2a99702db910e5ad7)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.102\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.2.15\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.2.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.101\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.6\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.158\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.icu\\\",\\\"version\\\":\\\"0.0.43\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.127\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.118\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.122\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.68\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.115\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\\\"}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.118\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.68\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.115\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.127\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.122\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.4\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.89\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.105\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.101\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\\\"}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.105\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.89\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.tiny\\\"}],\\\"layerDiffID\\\":\\\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\\\"}},\\\"org.cloudfoundry.icu\\\":{\\\"0.0.43\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.1.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.158\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\\\"},\\\"0.0.163\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v2.0.8\\\":{\\\"api\\\":\\\"0.2\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn-install\\\",\\\"version\\\":\\\"0.1.10\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.163\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.1.3\\\"}]}],\\\"layerDiffID\\\":\\\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\\\"}},\\\"org.cloudfoundry.npm\\\":{\\\"0.1.3\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.2.14\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.1.12\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.1.11\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.2.13\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.3.18\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"},{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"}],\\\"layerDiffID\\\":\\\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\\\"}},\\\"org.cloudfoundry.yarn-install\\\":{\\\"0.1.10\\\":{\\\"api\\\":\\\"0.2\\\",\\\"stacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.stacks.cflinuxfs3\\\"},{\\\"id\\\":\\\"io.buildpacks.stacks.bionic\\\"}],\\\"layerDiffID\\\":\\\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\",\n\t\t\t\"io.buildpacks.stack.mixins\": \"[\\\"build:git\\\",\\\"build:build-essential\\\"]\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 688884758,\n\t\"VirtualSize\": 688884758,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/6a79181b2840da2706624f46ce5abd4448973b4f951925d5a276b273256063b2/diff:/var/lib/docker/overlay2/429419a203100f60ab16ec6c879fce975c8138422b9053f80accd6124c730fc2/diff:/var/lib/docker/overlay2/6e45ed6daf4f4f3b90fd1ec5fa958775000875661d3e8be3f1af218d192b058d/diff:/var/lib/docker/overlay2/22928ad308cdd55b3fe849d92b6e38c6bc303ba7c9beb8c0e79aa958e16b1864/diff:/var/lib/docker/overlay2/2ca9ec213226a1604f57c8e141d6f1168134a5cb2ccd8f91ee9be5a39036e6bf/diff:/var/lib/docker/overlay2/96ae944fe00ec20cf5b4441b112ebcc9395faaf08108c9ee38c62e1da33af1c8/diff:/var/lib/docker/overlay2/13ee52e300e476e27350c9ac6274dedf26af85c3079b42a41f9dfc92eff57a80/diff:/var/lib/docker/overlay2/223edb4cc62a2ba2b8bda866905a55c4798c6c32e31d22d60e6ed4f3169ce85e/diff:/var/lib/docker/overlay2/a41235cd7277299cb74ead47def3771885948719e24075ea3bf37580f3af7ae2/diff:/var/lib/docker/overlay2/ed0438e8e2c27b9d62ad21a0761237c350a2ffc9e52f47c019e4f627091c832e/diff:/var/lib/docker/overlay2/0c27c8229b31eafc57ab739b44962dcc07b72f3d8950888873ecb3cfd385032f/diff:/var/lib/docker/overlay2/0957cbcca052cd58bcf9a3d945b0e6876b0df79c1c534da1872c3415a019427d/diff:/var/lib/docker/overlay2/b621414d53d71349c07df8ed45e3e04b2e97bfbaf4bf0d86463f46e0f810eeb4/diff:/var/lib/docker/overlay2/ad521bc47f0bb44262358cf47c3d81a544d098494cf24a5b510620d34eb9c353/diff:/var/lib/docker/overlay2/081501d5bfbd927e69c10eb320513c7c0d5f00bea8cf9e55faa90579fd33adf4/diff:/var/lib/docker/overlay2/fb1ba66bee5568f5700c72865d020d4171a62bfdd099c3cc05b9a253d36a35a4/diff:/var/lib/docker/overlay2/06bcc6b3adeca727d554f1a745ee33242dfe1b3c6392023ac947666057303288/diff:/var/lib/docker/overlay2/1c5397d63d893202dffde29013ee826fb695bda26c718ee03ddde376be4da0a3/diff:/var/lib/docker/overlay2/76075fb7fd3c6b3fb116fb3b464e220918e56d94461c61af9a1aff288ebdba60/diff:/var/lib/docker/overlay2/43d1026bb7b618393912ecc9ddf57b604336184d5f8dc70bcf6332b5f08a3e8d/diff:/var/lib/docker/overlay2/ee27d1fba3deaca0556f7bab171cb3368f169011dd132cf335b5308728f6db8f/diff:/var/lib/docker/overlay2/464d3ec8d86ff31dcb5063ea25521368ea8e9c7964f65e15ff5e0e1ecdbe991e/diff:/var/lib/docker/overlay2/a4a80c33c8b78f68bdc9dbd5903cc2ba1d48e78b9a97d43acb018823ece8e6cb/diff:/var/lib/docker/overlay2/6494f2f1693cff8b16d51fa95620eb0bb691a76fb39b5175d953649577791297/diff:/var/lib/docker/overlay2/9d49e146f82eb5fc4fd81613538e9c5f5f95091fbbc8c49729c6c9140ae356de/diff:/var/lib/docker/overlay2/2934818c52bcd017abe000e71342d67fbc9ccb7dbc165ce05e3250e2110229a5/diff:/var/lib/docker/overlay2/651ca06b2bf75e2122855264287fc937f30d2b49229d628909895be7128b4eb6/diff:/var/lib/docker/overlay2/c93bab59be44fa1b66689dc059d26742d00d2e787d06c3236e1f116199c9807e/diff:/var/lib/docker/overlay2/d0a8e2a0c7e0df172f7a8ebe75e2dce371bb6cc65531b06799bc677c5b5e3627/diff:/var/lib/docker/overlay2/7d14bac240e0d7936351e3fac80b7fbe2a209f4de8992091c4f75e41f9627852/diff:/var/lib/docker/overlay2/d6b192ea137a4ae95e309d263ee8c890e35da02aacd9bdcf5adbd4c28a0c0a3f/diff:/var/lib/docker/overlay2/335bfb632ab7723e25fb5dc7b67389e6ec38178ef10bfbf83337501403e61574/diff:/var/lib/docker/overlay2/0293c7e3472da58f51cbdf15fb293ff71e32c1f80f83f00fb09f8941deef5e43/diff:/var/lib/docker/overlay2/55faa8b47bcb0dd29c3836580f451a0461dd499065af9c830beff6e8329ab484/diff:/var/lib/docker/overlay2/afcb6e109c1ba7d71b8a8b7e573d4ce04f22da3fe0ee523359db5cfb95e65bb6/diff:/var/lib/docker/overlay2/b42eefd9bf6629ae9d16e7aba6ba3939d37816aba7a0999f6d639012a3119be1/diff:/var/lib/docker/overlay2/a9832c8f81ee889a622ce4d95d9f4bab2f91d30e18f69bfd7cfc385c781068d4/diff:/var/lib/docker/overlay2/224041c135f13881a98b9e833584bedab81d5650061457f522a1ebd1daa2c77a/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/f5d133c5929da8cc8266cbbc3e36f924f4a9c835f943fb436445a26b7e1bcc56/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:2df36adfe1af661aebb75a0db796b074bb8f861fbc8f98f6f642570692b3b133\",\n\t\t\t\"sha256:f499c7d34e01d860492ef1cc34b7d7e1319b3c3c81ee7d23258b21605b5902ca\",\n\t\t\t\"sha256:c4bf1d4e5d4adb566b173a0769d247f67c5dd8ff90dfdcebd8c7060f1c06caa9\",\n\t\t\t\"sha256:15259abd479904cbe0d8d421e5b05b2e5745e2bf82e62cdd7fb6d3eafbe4168a\",\n\t\t\t\"sha256:6aa3691a73805f608e5fce69fb6bc89aec8362f58a6b4be2682515e9cfa3cc1a\",\n\t\t\t\"sha256:2d6ad1b66f5660dd860c1fe2d90d26398fcfab4dc1c87c3d5e7c0fc24f8d6fb2\",\n\t\t\t\"sha256:ff29efc56c31eeccc79a33c6e4abd7b1ab3547d95e1cf83974af65a493576c41\",\n\t\t\t\"sha256:b87e68574cc7dccbe974fa760702ef650711036bf144fd9da1f3a2d8f6ac335f\",\n\t\t\t\"sha256:04559213a01cfac69a8d6a6facb58b8681666525c74f605207c40a61a0f4c9b7\",\n\t\t\t\"sha256:467c0082c57b80b48487a9b8429887c0744ddc5b066b3f7678866bde89b78ab2\",\n\t\t\t\"sha256:352a299d6af4773322ed3643d8f98b01aad6f15d838d1852e52a0a3ca56c6efb\",\n\t\t\t\"sha256:486b2abf434bb90cf04bab74f2f8bd2eb488ff90632b56eac4bddcbbf02e8151\",\n\t\t\t\"sha256:3f50d3a0e1a969a9606b59e5295842d731e425108cb349ce6c69a5b30ea1bab9\",\n\t\t\t\"sha256:c10732392b97c121a78a5f20201c2a5e834a2b8677196cdd49260a489a54fd22\",\n\t\t\t\"sha256:c185540c10fea822c6db1b987fcfe22b55a4662648124b98475db4c9dcddb2ab\",\n\t\t\t\"sha256:73b1a8ac1f7fca3d545766ce7fd3c56b40a63724ab78e464d71a29da0c6ac31c\",\n\t\t\t\"sha256:da62dec6eb4ed884952a1b867fd89e3bfe3c510e5c849cc0ac7050ff867a2469\",\n\t\t\t\"sha256:76fe727e4aafc7f56f01282296ab736521c38b9d19c1ae5ebb193f9cd55fa109\",\n\t\t\t\"sha256:a9c9bbbd69c212b7ab3c1a7f03011ccc4d99a6fce1bf1c785325c7bcad789e62\",\n\t\t\t\"sha256:b7b78159dfdaa0dd484c58652e02fa6b755abfd0adb88f106d16178144e46f33\",\n\t\t\t\"sha256:aa0effdf787ecfe74d60d6771006717fd1a9ce1ce0a8161624baa61b68120357\",\n\t\t\t\"sha256:a0a2f7c467efbb8b1ac222f09013b88b68f3c117ec6b6e9dc95564be50f271ab\",\n\t\t\t\"sha256:a0715e661e13d7d3ded5bdc068edd01e5b3aa0e2805152f4c8a1428b4e0673df\",\n\t\t\t\"sha256:6aae3a2d671d369eec34dc9146ef267d06c87461f271fbfbe9136775ecf5dfb8\",\n\t\t\t\"sha256:cb21f14e306d94e437c5418d275bcc6efcea6bc9b3d26a400bdf54fa62242c24\",\n\t\t\t\"sha256:c9da8171f5ca048109ffba5e940e3a7d2db567eda281f92b0eb483173df06add\",\n\t\t\t\"sha256:11486cb955594f9d43909b60f94209bb6854f502a5a093207b657afbaa38a777\",\n\t\t\t\"sha256:243bbd007cb0ee99b704bfe0cf62e1301baa4095ab4c39b01293787a0e4234f1\",\n\t\t\t\"sha256:6aefa0ba7ce01584b4a531b18e36470298cee3b30ecae0e0c64b532a5cebd6e7\",\n\t\t\t\"sha256:a06615b5adc1a3afb7abd524e82f6900a28910927fcf0d4e9b85fd1fcbeb53ad\",\n\t\t\t\"sha256:26d6f1e76275d17860005f7ab9b74fdd2283fcf84e0446bd88d49a6b4e9609f9\",\n\t\t\t\"sha256:55f7c052cf70c8ca01b8e241c0c5c8a9675599d4904c69bfb961a472e246238d\",\n\t\t\t\"sha256:d9958b816a9ad179fca8c18d17c07e9814b152d461c685e1443bec6f990ab990\",\n\t\t\t\"sha256:52142799a4b687fe6e5cf397c41064499ea6cc554b94904d46c1acade998e11f\",\n\t\t\t\"sha256:48063dcdd043f9c88604d10fe9542569be8f8111d46806c96b08d77763ffa347\",\n\t\t\t\"sha256:70cf83155575fdb607f23ace41e31b1d5cb1c24dbbbf56f71c383b583724d339\",\n\t\t\t\"sha256:6cf0f8f815d5371cf5c04e7ebf76c62467948d693b8343184d1446036980d261\",\n\t\t\t\"sha256:7cbffcbb09fc5e9d00372e80990016609c09cc3113429ddc951c4a19b1a5ec72\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-bind-mounts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/analyzer\",\n    \"-daemon\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"/tmp/launch-cache:/launch-cache\",\n      \"/tmp/work-layers:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-cache-volumes.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/analyzer\",\n    \"-daemon\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"launch-volume:/launch-cache\",\n      \"work-volume-layers:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-local.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/analyzer\",\n    \"-daemon\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/alt.sock:/var/run/docker.sock\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-inherit-remote.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/analyzer\",\n    \"-daemon\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"DOCKER_HOST=tcp://192.168.1.2:2376\",\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer-security-opts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/analyzer\",\n    \"-daemon\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=user:USER\",\n      \"label=role:ROLE\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-analyzer.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/analyzer\",\n    \"-daemon\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-app-dir.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/builder\",\n    \"-app\",\n    \"/application\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/application\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-bind-mounts.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/builder\",\n    \"-app\",\n    \"/workspace\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/tmp/work-app:/workspace\",\n      \"/tmp/work-layers:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder-cache-volumes.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/builder\",\n    \"-app\",\n    \"/workspace\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"work-volume-app:/workspace\",\n      \"work-volume-layers:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-builder.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/builder\",\n    \"-app\",\n    \"/workspace\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-app-dir.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/application\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/application\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-bindings.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"/host/src/path:/container/dest/path:ro\",\n      \"volume-name:/container/volume/path:rw\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-bind-mounts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/tmp/work-app:/workspace\",\n      \"/tmp/work-layers:/layers\",\n      \"/tmp/build-cache:/cache\",\n      \"/tmp/launch-cache:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-cache-volumes.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"work-volume-app:/workspace\",\n      \"work-volume-layers:/layers\",\n      \"build-volume:/cache\",\n      \"launch-volume:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-clean-cache.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"-skip-restore\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-created-date.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\",\n    \"SOURCE_DATE_EPOCH=1593606896\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-local.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/alt.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-inherit-remote.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"DOCKER_HOST=tcp://192.168.1.2:2376\",\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-network.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"NetworkMode\": \"test\",\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-platform-api-0.3.json",
    "content": "{\n  \"User\" : \"root\",\n  \"Image\" : \"pack.local/ephemeral-builder\",\n  \"Cmd\" : [ \"/cnb/lifecycle/creator\", \"-app\", \"/workspace\", \"-platform\", \"/platform\", \"-run-image\", \"docker.io/cloudfoundry/run:latest\", \"-layers\", \"/layers\", \"-cache-dir\", \"/cache\", \"-launch-cache\", \"/launch-cache\", \"-daemon\", \"docker.io/library/my-application:latest\" ],\n  \"Env\" : [ \"CNB_PLATFORM_API=0.3\" ],\n  \"Labels\" : {\n    \"author\" : \"spring-boot\"\n  },\n  \"HostConfig\" : {\n    \"Binds\" : [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator-security-opts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=user:USER\",\n      \"label=role:ROLE\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-creator.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/creator\",\n    \"-app\",\n    \"/workspace\",\n    \"-platform\",\n    \"/platform\",\n    \"-run-image\",\n    \"docker.io/cloudfoundry/run:latest\",\n    \"-layers\",\n    \"/layers\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-daemon\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"/var/run/docker.sock:/var/run/docker.sock\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-app-dir.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/detector\",\n    \"-app\",\n    \"/application\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/application\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-bind-mounts.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/detector\",\n    \"-app\",\n    \"/workspace\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/tmp/work-app:/workspace\",\n      \"/tmp/work-layers:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector-cache-volumes.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/detector\",\n    \"-app\",\n    \"/workspace\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"work-volume-app:/workspace\",\n      \"work-volume-layers:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-detector.json",
    "content": "{\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/detector\",\n    \"-app\",\n    \"/workspace\",\n    \"-layers\",\n    \"/layers\",\n    \"-platform\",\n    \"/platform\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-app-dir.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/application\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-app-aaaaaaaaaa:/application\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-bind-mounts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"/tmp/work-app:/workspace\",\n      \"/tmp/build-cache:/cache\",\n      \"/tmp/launch-cache:/launch-cache\",\n      \"/tmp/work-layers:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-cache-volumes.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"work-volume-app:/workspace\",\n      \"build-volume:/cache\",\n      \"launch-volume:/launch-cache\",\n      \"work-volume-layers:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-created-date.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\",\n    \"SOURCE_DATE_EPOCH=1593606896\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-local.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/alt.sock:/var/run/docker.sock\",\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-inherit-remote.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"DOCKER_HOST=tcp://192.168.1.2:2376\",\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter-security-opts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=user:USER\",\n      \"label=role:ROLE\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-exporter.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/exporter\",\n    \"-daemon\",\n    \"-app\",\n    \"/workspace\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-launch-cache\",\n    \"/launch-cache\",\n    \"-layers\",\n    \"/layers\",\n    \"docker.io/library/my-application:latest\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-app-aaaaaaaaaa:/workspace\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-cache-b35197ac41ea.launch:/launch-cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-bind-mounts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/restorer\",\n    \"-daemon\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-layers\",\n    \"/layers\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"/tmp/build-cache:/cache\",\n      \"/tmp/work-layers:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-cache-volumes.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/restorer\",\n    \"-daemon\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-layers\",\n    \"/layers\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"build-volume:/cache\",\n      \"work-volume-layers:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-local.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/restorer\",\n    \"-daemon\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-layers\",\n    \"/layers\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/alt.sock:/var/run/docker.sock\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-inherit-remote.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/restorer\",\n    \"-daemon\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-layers\",\n    \"/layers\"\n  ],\n  \"Env\": [\n    \"DOCKER_HOST=tcp://192.168.1.2:2376\",\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer-security-opts.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/restorer\",\n    \"-daemon\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-layers\",\n    \"/layers\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=user:USER\",\n      \"label=role:ROLE\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/lifecycle-restorer.json",
    "content": "{\n  \"User\": \"root\",\n  \"Image\": \"pack.local/ephemeral-builder\",\n  \"Cmd\": [\n    \"/cnb/lifecycle/restorer\",\n    \"-daemon\",\n    \"-cache-dir\",\n    \"/cache\",\n    \"-layers\",\n    \"/layers\"\n  ],\n  \"Env\": [\n    \"CNB_PLATFORM_API=0.8\"\n  ],\n  \"Labels\": {\n    \"author\": \"spring-boot\"\n  },\n  \"HostConfig\": {\n    \"Binds\": [\n      \"/var/run/docker.sock:/var/run/docker.sock\",\n      \"pack-cache-b35197ac41ea.build:/cache\",\n      \"pack-layers-aaaaaaaaaa:/layers\"\n    ],\n    \"SecurityOpt\" : [\n      \"label=disable\"\n    ]\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/order.toml",
    "content": "[[order]]\n\n  [[order.group]]\n    id = \"example/buildpack1\"\n    version = \"0.0.1\"\n\n  [[order.group]]\n    id = \"example/buildpack2\"\n    version = \"0.0.2\"\n\n  [[order.group]]\n    id = \"example/buildpack3\"\n    version = \"0.0.3\"\n\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/print-stream-build-log.txt",
    "content": "Building image 'docker.io/library/my-app:latest'\n\n > Pulling builder image 'docker.io/cnb/builder' ..................................................\n > Pulled builder image '00000001'\n > Pulling run image 'docker.io/cnb/runner' for platform 'linux/arm64/v1' ..................................................\n > Pulled run image '00000002'\n > Executing lifecycle version v0.5.0\n > Using build cache volume 'pack-abc.cache'\n\n > Running alphabet\n    [alphabet]    one\n    [alphabet]    two\n    [alphabet]    three\n\n > Running basket\n    [basket]      spring\n    [basket]      boot\n\nSuccessfully built image 'docker.io/library/my-app:latest'\n\nSuccessfully created image tag 'docker.io/library/my-app:1.0'\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/run-image-with-bad-stack.json",
    "content": "{\n\t\"Id\": \"sha256:9b450bffdb05bcf660d464d0bfdf344ee6ca38e9b8de4f408c8080b0c9319349\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:latest\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buildpacks/run@sha256:715806bb793b66e3fc1a5a8f5584c6a1b6db05425e573887673bddcf426f1b90\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"2019-10-30T19:34:56.296666503Z\",\n\t\"Container\": \"84597380a7968131ab47dd1b8183a96dcfe9e1e4acff1efe5824dcd762184a67\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"84597380a796\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/sh\",\n\t\t\t\"-c\",\n\t\t\t\"#(nop) \",\n\t\t\t\"LABEL io.buildpacks.stack.id=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t}\n\t},\n\t\"DockerVersion\": \"18.09.6\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"cflinuxfs3 base image with buildpacks for Java, .NET, NodeJS, Python, Golang, PHP, HTTPD and NGINX\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true}],\\\"groups\\\":[{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"optional\\\":true}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\"}]}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run:full-cnb\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.5.0\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.1\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.5.0 (git sha: c9cfac75b49609524e1ea33f809c12071406547c)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.87\\\":{\\\"layerDiffID\\\":\\\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.0.114\\\":{\\\"layerDiffID\\\":\\\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\\\"}},\\\"org.cloudfoundry.conda\\\":{\\\"0.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.0.92\\\":{\\\"layerDiffID\\\":\\\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.51\\\":{\\\"layerDiffID\\\":\\\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.0.89\\\":{\\\"layerDiffID\\\":\\\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.2\\\":{\\\"layerDiffID\\\":\\\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\"}]}]}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.18\\\":{\\\"layerDiffID\\\":\\\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.66\\\":{\\\"layerDiffID\\\":\\\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.55\\\":{\\\"layerDiffID\\\":\\\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\"}]}]}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.48\\\":{\\\"layerDiffID\\\":\\\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.44\\\":{\\\"layerDiffID\\\":\\\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.0.40\\\":{\\\"layerDiffID\\\":\\\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\\\"}},\\\"org.cloudfoundry.httpd\\\":{\\\"0.0.21\\\":{\\\"layerDiffID\\\":\\\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.0.72\\\":{\\\"layerDiffID\\\":\\\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\\\"}},\\\"org.cloudfoundry.nginx\\\":{\\\"0.0.25\\\":{\\\"layerDiffID\\\":\\\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.85\\\":{\\\"layerDiffID\\\":\\\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v0.0.3\\\":{\\\"layerDiffID\\\":\\\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\"}]}]}},\\\"org.cloudfoundry.npm\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\\\"}},\\\"org.cloudfoundry.php\\\":{\\\"v0.0.0-RC1\\\":{\\\"layerDiffID\\\":\\\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]}]}},\\\"org.cloudfoundry.php-composer\\\":{\\\"0.0.16\\\":{\\\"layerDiffID\\\":\\\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\\\"}},\\\"org.cloudfoundry.php-dist\\\":{\\\"0.0.30\\\":{\\\"layerDiffID\\\":\\\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\\\"}},\\\"org.cloudfoundry.php-web\\\":{\\\"0.0.24\\\":{\\\"layerDiffID\\\":\\\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\\\"}},\\\"org.cloudfoundry.pip\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\\\"}},\\\"org.cloudfoundry.pipenv\\\":{\\\"0.0.38\\\":{\\\"layerDiffID\\\":\\\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\\\"}},\\\"org.cloudfoundry.python\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\"},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\"}]}]}},\\\"org.cloudfoundry.python-runtime\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.0.100\\\":{\\\"layerDiffID\\\":\\\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.0.97\\\":{\\\"layerDiffID\\\":\\\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.1.9\\\":{\\\"layerDiffID\\\":\\\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\\\"}},\\\"org.cloudfoundry.yarn\\\":{\\\"0.0.58\\\":{\\\"layerDiffID\\\":\\\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cfwindowsfs3\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 1559461360,\n\t\"VirtualSize\": 1559461360,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/58e30cd9f3a4da4e0d30f20c3b50de7655e261fb3d32f04818f1bd960c1e8b6c/diff:/var/lib/docker/overlay2/ad95d738069aa405ff17a9ebb1fdc32f8490b0dd885c3ba3a28e2c3b25d64641/diff:/var/lib/docker/overlay2/74d2896cfe9efc6945ff18870a7213583b987ecf4306e189ff6b793f77af5dcd/diff:/var/lib/docker/overlay2/1052615e5c240724e10928048f735cc9e7a7676a9af5f173b895df57c6921a40/diff:/var/lib/docker/overlay2/b5a62216c4282e7568e84427073f096551977c8c6f80d3a04ebb04c25730edde/diff:/var/lib/docker/overlay2/016a36bf7d7d7258eca08da62c01e47bf8e531531f914dde7cae33e191ab2218/diff:/var/lib/docker/overlay2/a585012bf1cf9da0472b2bbe86c4919355593e1a02cf399a9b012928eb816bcd/diff:/var/lib/docker/overlay2/b4aa8b70bd59d7b7dc6d6fb2e655c2334dc8360c764232f83d036d1f241e3298/diff:/var/lib/docker/overlay2/5f4cab16092522163e2dba6587b48d53ee3b09c8778b0736999bc120dd3753b1/diff:/var/lib/docker/overlay2/90e60622603d230f238976f4d9f65797fc9f070df62b1d2ccad0cefe4e205b43/diff:/var/lib/docker/overlay2/c43877934a580e47cc477ed46e71246468d7b6d7151abc5f1a97bb1e8c8104cf/diff:/var/lib/docker/overlay2/8734b165cabb3ff234a08d488f622135aeae9b7347cf41273445ff7d07aa4565/diff:/var/lib/docker/overlay2/2743cd9d4b7da84925b1b530732dad97108fe77e75865de580255579ba2cdb92/diff:/var/lib/docker/overlay2/68308d057b24bbcde7a4880f5db0e653743debdcc0ff3e736d1776296c4168a1/diff:/var/lib/docker/overlay2/7a4411dc4ac1ed7a1da9aabf088985b8b131e0db047e513f9890eb9c001c1895/diff:/var/lib/docker/overlay2/7f7c262fea8dea5ec86507188848ea391354a76468b09ec93523920e18a400ea/diff:/var/lib/docker/overlay2/8b3bfa567fb956204ad866e49489dacd2fdf5fbfa4f9b05ed3668e1106a5383b/diff:/var/lib/docker/overlay2/31bbc4f1616a35b7ce157266e44513963502e30d836a8fd7b7ee18436a8c46cf/diff:/var/lib/docker/overlay2/149b8e9f1142cdf6dcdfe17ea286ec17197f1a329cf23d5c82958a2032facf54/diff:/var/lib/docker/overlay2/92fb1e680083eb8314c5310bf10ced63ec2b0a98afbf84cc5175a98b3d44507a/diff:/var/lib/docker/overlay2/175a35b6f7af6eb91ca500dbd3d7e798f6d174cf8549881ffe5eed8e92a70b9f/diff:/var/lib/docker/overlay2/48ca54bbd27f7df19acf2b6cc719d05dd3b63f8133038a55d216a4498d4dc913/diff:/var/lib/docker/overlay2/ffe3cc3b93c9030f9dcb0e64c258d1e554f1f0cf27a0f8d4e98bb7ece5ffe882/diff:/var/lib/docker/overlay2/1fb2d962bb27e95c40a9a2c1aa910ca847d186d04e3d7dcdf93967101cc30dde/diff:/var/lib/docker/overlay2/10b34138f9e9e8d70c684d0a564452b1309363441b9d7e048f75e0e1179411dc/diff:/var/lib/docker/overlay2/1d888c7e9c62c22ccda6478f03f3df4b43d43fa3b32a2c2fdc9345fdc7193cd9/diff:/var/lib/docker/overlay2/649fc275c002d7336b277365636e1c8e5651bb3ed1557806d26dd6dfa1d9119a/diff:/var/lib/docker/overlay2/4484c2c0ee4a20aa17017c8cd54c842c876fea32afb297e88614d759ec5410dc/diff:/var/lib/docker/overlay2/bd5f374e0ea6749c90535d778f2689c076b7290ad9d3f050af0a40c9626fdea4/diff:/var/lib/docker/overlay2/c6ba97531b15be65bccaf7ebc866d8bc0b88ce838b224aceb196a55824b289a5/diff:/var/lib/docker/overlay2/6c65fab249fe652cd20a6391b2e0786379b6d2c7d4fde02914dfb4fac84035bd/diff:/var/lib/docker/overlay2/f391b54493024e0183331b8ec7835107bc1b84b8a6e77d852f5357724eb940ff/diff:/var/lib/docker/overlay2/8044f9e3ceb529c80531fa2fe52ad550286f788e69843f235e7d756b90c213b8/diff:/var/lib/docker/overlay2/7d3b5539c46c9f0e7c4f6f733f435d1bf6428a8ca81ba71f4da1031cef58aa6c/diff:/var/lib/docker/overlay2/b8080b36b0ddec4e4d738571ddf9d89815f6a95a555d282cfebb73519b4835a0/diff:/var/lib/docker/overlay2/8a737007d5862aa43119254122eb7050c8bd110a3b653c8d6afca23e76fc4042/diff:/var/lib/docker/overlay2/3bb8f3670831e2031be2173381caf02874ad72e664716a990a330bcc3454f4a2/diff:/var/lib/docker/overlay2/cbd675efde19ccac72d3566404e5df8b152a9063c1668d8154711c7db398f852/diff:/var/lib/docker/overlay2/84fb9095136cb645f7f15aeeeba1db6fae3999cb48a559daf8dd46bf3befbeba/diff:/var/lib/docker/overlay2/cbc51912822c4a3fb8624e0cf678e5dedeb76dc2fa0e5bc56f3cbfbfefb26d68/diff:/var/lib/docker/overlay2/d08d5bdcf39aaf46bdf1e0f4576bb64931af646213ff350065b4d306e00f7e28/diff:/var/lib/docker/overlay2/cf180c218fe181bdf836065c5e85103816ea9e8dbb8ab54fb311209c33455eb2/diff:/var/lib/docker/overlay2/b0aef801fd38973eaf116001e05e7c3f8e2eb58ccc7ed37a4bd8d4fcc2ad172b/diff:/var/lib/docker/overlay2/f73c585ae34bd962e1fee2c3e2d95d47b9daf68b23cf469fb13bc3282cf77238/diff:/var/lib/docker/overlay2/c071c8471b26e55a90b6573a21c581dec43b6c7683a3fe87cb33a0734c83342a/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:733a8e5ce32984099ef675fce04730f6e2a6dcfdf5bd292fea01a8f936265342\",\n\t\t\t\"sha256:7755b972f0b4f49de73ef5114fb3ba9c69d80f217e80da99f56f0d0a5dcb3d70\",\n\t\t\t\"sha256:8f0b2d09ab4b38530a1630403967d11a601e56e02e79d3f56370d34fd071fe38\",\n\t\t\t\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\",\n\t\t\t\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\",\n\t\t\t\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\",\n\t\t\t\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\",\n\t\t\t\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\",\n\t\t\t\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\",\n\t\t\t\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\",\n\t\t\t\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\",\n\t\t\t\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\",\n\t\t\t\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\",\n\t\t\t\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\",\n\t\t\t\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\",\n\t\t\t\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\",\n\t\t\t\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\",\n\t\t\t\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\",\n\t\t\t\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\",\n\t\t\t\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\",\n\t\t\t\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\",\n\t\t\t\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\",\n\t\t\t\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\",\n\t\t\t\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\",\n\t\t\t\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\",\n\t\t\t\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\",\n\t\t\t\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\",\n\t\t\t\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\",\n\t\t\t\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\",\n\t\t\t\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\",\n\t\t\t\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\",\n\t\t\t\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\",\n\t\t\t\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\",\n\t\t\t\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\",\n\t\t\t\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\",\n\t\t\t\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\",\n\t\t\t\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\",\n\t\t\t\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\",\n\t\t\t\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\",\n\t\t\t\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\",\n\t\t\t\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\",\n\t\t\t\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\",\n\t\t\t\"sha256:f8b5dcfa1d082af23bb2b2c08526131921329d48d1614d9f2f163a997176087a\",\n\t\t\t\"sha256:ee13e75c33e0af49fbf6c3aaa5bbd102fc468c2d554c4f94763d35a33964dfe4\",\n\t\t\t\"sha256:2571abab1776d4c2e427fba10d61531afff2ab0789f89ef46ce925b6a5d98e0f\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/run-image-with-platform.json",
    "content": "{\n\t\"Id\": \"sha256:1332879bc8e38793a45ebe5a750f2a1c35df07ec2aa9c18f694644a9de77359b\",\n\t\"RepoTags\": [\n\t\t\"cloudfoundry/run:base-cnb\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"cloudfoundry/run@sha256:fb5ecb90a42b2067a859aab23fc1f5e9d9c2589d07ba285608879e7baa415aad\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"2020-03-20T20:18:18.117972538Z\",\n\t\"Container\": \"91d1af87c3bb6163cd9c7cb21e6891cd25f5fa3c7417779047776e288c0bc234\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"91d1af87c3bb\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/sh\",\n\t\t\t\"-c\",\n\t\t\t\"#(nop) \",\n\t\t\t\"LABEL io.buildpacks.stack.id=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\"\n\t\t}\n\t},\n\t\"DockerVersion\": \"18.09.6\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\"\n\t\t}\n\t},\n\t\"Architecture\": \"arm64\",\n\t\"Os\": \"linux\",\n  \"Variant\": \"v1\",\n\t\"Size\": 71248531,\n\t\"VirtualSize\": 71248531,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/17f0a4530fbc3e2982f9dc8feb8c8ddc124473bdd50130dae20856ac597d82dd/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:c1daeb79beb276c7441d9a1d7281433e9a7edb9f652b8996ecc62b51e88a47b2\",\n\t\t\t\"sha256:eb195d29dc1aa6e4239f00e7868deebc5ac12bebe76104e0b774c1ef29ca78e3\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/run-image.json",
    "content": "{\n\t\"Id\": \"sha256:1332879bc8e38793a45ebe5a750f2a1c35df07ec2aa9c18f694644a9de77359b\",\n\t\"RepoTags\": [\n\t\t\"cloudfoundry/run:base-cnb\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"cloudfoundry/run@sha256:fb5ecb90a42b2067a859aab23fc1f5e9d9c2589d07ba285608879e7baa415aad\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"2020-03-20T20:18:18.117972538Z\",\n\t\"Container\": \"91d1af87c3bb6163cd9c7cb21e6891cd25f5fa3c7417779047776e288c0bc234\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"91d1af87c3bb\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/sh\",\n\t\t\t\"-c\",\n\t\t\t\"#(nop) \",\n\t\t\t\"LABEL io.buildpacks.stack.id=io.buildpacks.stacks.bionic\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\"\n\t\t}\n\t},\n\t\"DockerVersion\": \"18.09.6\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"1000:1000\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/bash\"\n\t\t],\n\t\t\"ArgsEscaped\": true,\n\t\t\"Image\": \"sha256:fbe314bcb23f15a2a09603b6620acd67c332fd08fbf2a7bc3db8fb2f5078d994\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"io.buildpacks.stacks.bionic\"\n\t\t}\n\t},\n\t\"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n\t\"Size\": 71248531,\n\t\"VirtualSize\": 71248531,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/17f0a4530fbc3e2982f9dc8feb8c8ddc124473bdd50130dae20856ac597d82dd/diff:/var/lib/docker/overlay2/73dfd4e2075fccb239b3d5e9b33b32b8e410bdc3cd5a620b41346f44cc5c51f7/diff:/var/lib/docker/overlay2/b3924ed7c91730f6714d33c455db888604b59ab093033b3f59ac16ecdd777987/diff:/var/lib/docker/overlay2/e36a32cd0ab20b216a8db1a8a166b17464399e4d587d22504088a7a6ef0a68a4/diff:/var/lib/docker/overlay2/3334e94fe191333b65f571912c0fcfbbf31aeb090a2fb9b4cfdbc32a37c0fe5f/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/8d3f9e3c00bc5072f8051ec7884500ca394f2331d8bcc9452f68d04531f50f82/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:c8be1b8f4d60d99c281fc2db75e0f56df42a83ad2f0b091621ce19357e19d853\",\n\t\t\t\"sha256:977183d4e9995d9cd5ffdfc0f29e911ec9de777bcb0f507895daa1068477f76f\",\n\t\t\t\"sha256:6597da2e2e52f4d438ad49a14ca79324f130a9ea08745505aa174a8db51cb79d\",\n\t\t\t\"sha256:16542a8fc3be1bfaff6ed1daa7922e7c3b47b6c3a8d98b7fca58b9517bb99b75\",\n\t\t\t\"sha256:c1daeb79beb276c7441d9a1d7281433e9a7edb9f652b8996ecc62b51e88a47b2\",\n\t\t\t\"sha256:eb195d29dc1aa6e4239f00e7868deebc5ac12bebe76104e0b774c1ef29ca78e3\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/auth-token.json",
    "content": "{\n\t\"identitytoken\": \"tokenvalue\"\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/auth-user-full.json",
    "content": "{\n\t\"username\": \"user\",\n\t\"password\": \"secret\",\n\t\"email\": \"docker@example.com\",\n\t\"serveraddress\": \"https://docker.example.com\"\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/auth-user-minimal.json",
    "content": "{\n\t\"username\": \"user\",\n\t\"password\": \"secret\"\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/docker-credential-test.bat",
    "content": "@echo off\n\nset /p registryUrl=\n\nif \"%registryUrl%\" == \"user.example.com\" (\n    echo {\n    echo   \"ServerURL\": \"%registryUrl%\",\n    echo   \"Username\": \"username\",\n    echo   \"Secret\": \"secret\"\n    echo }\n    exit /b 0\n)\n\nif \"%registryUrl%\" == \"token.example.com\" (\n    echo {\n    echo   \"ServerURL\": \"%registryUrl%\",\n    echo   \"Username\": \"<token>\",\n    echo   \"Secret\": \"secret\"\n    echo }\n    exit /b 0\n)\n\nif \"%registryUrl%\" == \"url.missing.example.com\" (\n    echo no credentials server URL >&2\n    exit /b 1\n)\n\nif \"%registryUrl%\" == \"username.missing.example.com\" (\n    echo no credentials username >&2\n    exit /b 1\n)\n\nif \"%registryUrl%\" == \"credentials.missing.example.com\" (\n    echo credentials not found in native keychain >&2\n    exit /b 1\n)\n\necho Unknown error >&2\nexit /b 1\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/docker-credential-test.sh",
    "content": "#!/bin/sh\n\nread -r registryUrl\n\nif [ \"$registryUrl\" = \"user.example.com\" ]; then\n\tcat <<EOF\n{\n  \"ServerURL\": \"${registryUrl}\",\n  \"Username\": \"username\",\n  \"Secret\": \"secret\"\n}\nEOF\n\texit 0\nfi\n\nif [ \"$registryUrl\" = \"token.example.com\" ]; then\n\tcat <<EOF\n{\n  \"ServerURL\": \"${registryUrl}\",\n  \"Username\": \"<token>\",\n  \"Secret\": \"secret\"\n}\nEOF\n\texit 0\nfi\n\nif [ \"$registryUrl\" = \"url.missing.example.com\" ]; then\n  echo \"no credentials server URL\" >&2\n\texit 1\nfi\n\nif [ \"$registryUrl\" = \"username.missing.example.com\" ]; then\n  echo \"no credentials username\" >&2\n\texit 1\nfi\n\nif [ \"$registryUrl\" = \"credentials.missing.example.com\" ]; then\n  echo \"credentials not found in native keychain\" >&2\n\texit 1\nfi\n\necho \"Unknown error\" >&2\nexit 1\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-auth/config.json",
    "content": "{\n  \"auths\": {\n    \"https://index.docker.io/v1/\": {\n      \"auth\": \"dXNlcm5hbWU6AABwYXNzAHdvcmQAAA==\",\n      \"email\": \"test@example.com\"\n    },\n    \"custom-registry.example.com\": {\n      \"auth\": \"Y3VzdG9tVXNlcjpjdXN0b21QYXNz\"\n    },\n    \"my-registry.example.com\": {\n      \"username\": \"user\",\n      \"password\": \"password\"\n    }\n  },\n  \"credsStore\": \"desktop\",\n  \"credHelpers\": {\n    \"gcr.io\": \"gcr\",\n    \"ecr.us-east-1.amazonaws.com\": \"ecr-login\",\n    \"azurecr.io\": \"acr-env\"\n  }\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-context/config.json",
    "content": "{\n  \"currentContext\": \"test-context\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-context/contexts/meta/ea1b2003cc8155cb8af43960c89a4c1e28777d6fd848ff3422cf375329c2626d/meta.json",
    "content": "{\n  \"Name\": \"test-context\",\n  \"Metadata\": {\n    \"Description\": \"A context for testing\"\n  },\n  \"Endpoints\": {\n    \"docker\": {\n      \"Host\": \"unix:///home/user/.docker/docker.sock\",\n      \"SkipTLSVerify\": true\n    }\n  }\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-default-context/config.json",
    "content": "{\n  \"currentContext\": \"default\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-default-context/contexts/meta/ea1b2003cc8155cb8af43960c89a4c1e28777d6fd848ff3422cf375329c2626d/meta.json",
    "content": "{\n  \"Name\": \"test-context\",\n  \"Metadata\": {\n    \"Description\": \"A context for testing\"\n  },\n  \"Endpoints\": {\n    \"docker\": {\n      \"Host\": \"unix:///home/user/.docker/docker.sock\",\n      \"SkipTLSVerify\": false\n    }\n  }\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-default-context/contexts/tls/ea1b2003cc8155cb8af43960c89a4c1e28777d6fd848ff3422cf375329c2626d/docker/cert.pem",
    "content": ""
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/with-default-context/contexts/tls/ea1b2003cc8155cb8af43960c89a4c1e28777d6fd848ff3422cf375329c2626d/docker/key.pem",
    "content": ""
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/configuration/without-context/config.json",
    "content": "{\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/container-wait-response.json",
    "content": "{\n\t\"StatusCode\": 1\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/create-container-response.json",
    "content": " {\n\t\"Id\": \"e90e34656806\",\n\t\"Warnings\": []\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/load-error.json",
    "content": "{\"errorDetail\":{\"message\":\"max depth exceeded\"}}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/load-stream.json",
    "content": "{\"stream\":\"Loaded image: pack.local/builder/auqfjjbaod:latest\\n\"}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/pull-stream.json",
    "content": "{\n\t\"status\": \"Pulling from paketo-buildpacks/cnb\",\n\t\"id\": \"base\"\n}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":487,\"total\":850},\"progress\":\"[============================\\u003e                      ]     487B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":485,\"total\":35355},\"progress\":\"[\\u003e                                                  ]     485B/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":35355,\"total\":35355},\"progress\":\"[==================================================\\u003e]  35.35kB/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":277600,\"total\":26683298},\"progress\":\"[\\u003e                                                  ]  277.6kB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":850,\"total\":850},\"progress\":\"[==================================================\\u003e]     850B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2218692,\"total\":26683298},\"progress\":\"[====\\u003e                                              ]  2.219MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4160196,\"total\":26683298},\"progress\":\"[=======\\u003e                                           ]   4.16MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6109892,\"total\":26683298},\"progress\":\"[===========\\u003e                                       ]   6.11MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":7772868,\"total\":26683298},\"progress\":\"[==============\\u003e                                    ]  7.773MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":9444036,\"total\":26683298},\"progress\":\"[=================\\u003e                                 ]  9.444MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":163,\"total\":163},\"progress\":\"[==================================================\\u003e]     163B/163B\",\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":10832580,\"total\":26683298},\"progress\":\"[====================\\u003e                              ]  10.83MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":531179,\"total\":88111129},\"progress\":\"[\\u003e                                                  ]  531.2kB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11668164,\"total\":26683298},\"progress\":\"[=====================\\u003e                             ]  11.67MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1604331,\"total\":88111129},\"progress\":\"[\\u003e                                                  ]  1.604MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":12495556,\"total\":26683298},\"progress\":\"[=======================\\u003e                           ]   12.5MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3209963,\"total\":88111129},\"progress\":\"[=\\u003e                                                 ]   3.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13331140,\"total\":26683298},\"progress\":\"[========================\\u003e                          ]  13.33MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4283115,\"total\":88111129},\"progress\":\"[==\\u003e                                                ]  4.283MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":14166724,\"total\":26683298},\"progress\":\"[==========================\\u003e                        ]  14.17MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5888747,\"total\":88111129},\"progress\":\"[===\\u003e                                               ]  5.889MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":15280836,\"total\":26683298},\"progress\":\"[============================\\u003e                      ]  15.28MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":14318,\"total\":1391657},\"progress\":\"[\\u003e                                                  ]  14.32kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6961899,\"total\":88111129},\"progress\":\"[===\\u003e                                               ]  6.962MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16116420,\"total\":26683298},\"progress\":\"[==============================\\u003e                    ]  16.12MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":936688,\"total\":1391657},\"progress\":\"[=================================\\u003e                 ]  936.7kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":8022763,\"total\":88111129},\"progress\":\"[====\\u003e                                              ]  8.023MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16931524,\"total\":26683298},\"progress\":\"[===============================\\u003e                   ]  16.93MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":18045636,\"total\":26683298},\"progress\":\"[=================================\\u003e                 ]  18.05MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":9632491,\"total\":88111129},\"progress\":\"[=====\\u003e                                             ]  9.632MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":10709739,\"total\":88111129},\"progress\":\"[======\\u003e                                            ]  10.71MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":19143364,\"total\":26683298},\"progress\":\"[===================================\\u003e               ]  19.14MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11778795,\"total\":88111129},\"progress\":\"[======\\u003e                                            ]  11.78MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":20249284,\"total\":26683298},\"progress\":\"[=====================================\\u003e             ]  20.25MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":12851947,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  12.85MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":21072580,\"total\":26683298},\"progress\":\"[=======================================\\u003e           ]  21.07MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":14133,\"total\":1328346},\"progress\":\"[\\u003e                                                  ]  14.13kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13933291,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  13.93MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":21908164,\"total\":26683298},\"progress\":\"[=========================================\\u003e         ]  21.91MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":973511,\"total\":1328346},\"progress\":\"[====================================\\u003e              ]  973.5kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":15014635,\"total\":88111129},\"progress\":\"[========\\u003e                                          ]  15.01MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":22747844,\"total\":26683298},\"progress\":\"[==========================================\\u003e        ]  22.75MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16075499,\"total\":88111129},\"progress\":\"[=========\\u003e                                         ]  16.08MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23575236,\"total\":26683298},\"progress\":\"[============================================\\u003e      ]  23.58MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":24414916,\"total\":26683298},\"progress\":\"[=============================================\\u003e     ]  24.41MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":17132267,\"total\":88111129},\"progress\":\"[=========\\u003e                                         ]  17.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":25250500,\"total\":26683298},\"progress\":\"[===============================================\\u003e   ]  25.25MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":18213611,\"total\":88111129},\"progress\":\"[==========\\u003e                                        ]  18.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":26073796,\"total\":26683298},\"progress\":\"[================================================\\u003e  ]  26.07MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":19286763,\"total\":88111129},\"progress\":\"[==========\\u003e                                        ]  19.29MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":490,\"total\":4478},\"progress\":\"[=====\\u003e                                             ]     490B/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4478,\"total\":4478},\"progress\":\"[==================================================\\u003e]  4.478kB/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":20892395,\"total\":88111129},\"progress\":\"[===========\\u003e                                       ]  20.89MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":294912,\"total\":26683298},\"progress\":\"[\\u003e                                                  ]  294.9kB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23050987,\"total\":88111129},\"progress\":\"[=============\\u003e                                     ]  23.05MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":2654208,\"total\":26683298},\"progress\":\"[====\\u003e                                              ]  2.654MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":25205483,\"total\":88111129},\"progress\":\"[==============\\u003e                                    ]  25.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":6193152,\"total\":26683298},\"progress\":\"[===========\\u003e                                       ]  6.193MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":27355883,\"total\":88111129},\"progress\":\"[===============\\u003e                                   ]  27.36MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":8552448,\"total\":26683298},\"progress\":\"[================\\u003e                                  ]  8.552MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":197,\"total\":197},\"progress\":\"[==================================================\\u003e]     197B/197B\",\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":11796480,\"total\":26683298},\"progress\":\"[======================\\u003e                            ]   11.8MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":29510379,\"total\":88111129},\"progress\":\"[================\\u003e                                  ]  29.51MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":277600,\"total\":27504647},\"progress\":\"[\\u003e                                                  ]  277.6kB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":15040512,\"total\":26683298},\"progress\":\"[============================\\u003e                      ]  15.04MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1391300,\"total\":27504647},\"progress\":\"[==\\u003e                                                ]  1.391MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":31132395,\"total\":88111129},\"progress\":\"[=================\\u003e                                 ]  31.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":17989632,\"total\":26683298},\"progress\":\"[=================================\\u003e                 ]  17.99MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":32754411,\"total\":88111129},\"progress\":\"[==================\\u003e                                ]  32.75MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2230980,\"total\":27504647},\"progress\":\"[====\\u003e                                              ]  2.231MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":22118400,\"total\":26683298},\"progress\":\"[=========================================\\u003e         ]  22.12MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":33835755,\"total\":88111129},\"progress\":\"[===================\\u003e                               ]  33.84MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3078852,\"total\":27504647},\"progress\":\"[=====\\u003e                                             ]  3.079MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":24477696,\"total\":26683298},\"progress\":\"[=============================================\\u003e     ]  24.48MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5205016},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":34917099,\"total\":88111129},\"progress\":\"[===================\\u003e                               ]  34.92MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3922628,\"total\":27504647},\"progress\":\"[=======\\u003e                                           ]  3.923MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":912096,\"total\":5205016},\"progress\":\"[========\\u003e                                          ]  912.1kB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":26247168,\"total\":26683298},\"progress\":\"[=================================================\\u003e ]  26.25MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4487876,\"total\":27504647},\"progress\":\"[========\\u003e                                          ]  4.488MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":35986155,\"total\":88111129},\"progress\":\"[====================\\u003e                              ]  35.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":26683298,\"total\":26683298},\"progress\":\"[==================================================\\u003e]  26.68MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1805024,\"total\":5205016},\"progress\":\"[=================\\u003e                                 ]  1.805MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5044932,\"total\":27504647},\"progress\":\"[=========\\u003e                                         ]  5.045MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":36522731,\"total\":88111129},\"progress\":\"[====================\\u003e                              ]  36.52MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2550496,\"total\":5205016},\"progress\":\"[========================\\u003e                          ]   2.55MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5601988,\"total\":27504647},\"progress\":\"[==========\\u003e                                        ]  5.602MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3381984,\"total\":5205016},\"progress\":\"[================================\\u003e                  ]  3.382MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":37063403,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]  37.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6159044,\"total\":27504647},\"progress\":\"[===========\\u003e                                       ]  6.159MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4152032,\"total\":5205016},\"progress\":\"[=======================================\\u003e           ]  4.152MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":37604075,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]   37.6MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32768,\"total\":35355},\"progress\":\"[==============================================\\u003e    ]  32.77kB/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":35355,\"total\":35355},\"progress\":\"[==================================================\\u003e]  35.35kB/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5004000,\"total\":5205016},\"progress\":\"[================================================\\u003e  ]  5.004MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6716100,\"total\":27504647},\"progress\":\"[============\\u003e                                      ]  6.716MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":38144747,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]  38.14MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":850,\"total\":850},\"progress\":\"[==================================================\\u003e]     850B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":850,\"total\":850},\"progress\":\"[==================================================\\u003e]     850B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":7293636,\"total\":27504647},\"progress\":\"[=============\\u003e                                     ]  7.294MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":39213803,\"total\":88111129},\"progress\":\"[======================\\u003e                            ]  39.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":8129220,\"total\":27504647},\"progress\":\"[==============\\u003e                                    ]  8.129MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":163,\"total\":163},\"progress\":\"[==================================================\\u003e]     163B/163B\",\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":163,\"total\":163},\"progress\":\"[==================================================\\u003e]     163B/163B\",\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":40295147,\"total\":88111129},\"progress\":\"[======================\\u003e                            ]   40.3MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":8964804,\"total\":27504647},\"progress\":\"[================\\u003e                                  ]  8.965MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":9800388,\"total\":27504647},\"progress\":\"[=================\\u003e                                 ]    9.8MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":41368299,\"total\":88111129},\"progress\":\"[=======================\\u003e                           ]  41.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49680,\"total\":4964709},\"progress\":\"[\\u003e                                                  ]  49.68kB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":10635972,\"total\":27504647},\"progress\":\"[===================\\u003e                               ]  10.64MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":908013,\"total\":4964709},\"progress\":\"[=========\\u003e                                         ]    908kB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":41908971,\"total\":88111129},\"progress\":\"[=======================\\u003e                           ]  41.91MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11193028,\"total\":27504647},\"progress\":\"[====================\\u003e                              ]  11.19MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2038509,\"total\":4964709},\"progress\":\"[====================\\u003e                              ]  2.039MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":42449643,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  42.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11750084,\"total\":27504647},\"progress\":\"[=====================\\u003e                             ]  11.75MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3316461,\"total\":4964709},\"progress\":\"[=================================\\u003e                 ]  3.316MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4791021,\"total\":4964709},\"progress\":\"[================================================\\u003e  ]  4.791MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":12315332,\"total\":27504647},\"progress\":\"[======================\\u003e                            ]  12.32MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":42990315,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  42.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13155012,\"total\":27504647},\"progress\":\"[=======================\\u003e                           ]  13.16MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":43530987,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  43.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13990596,\"total\":27504647},\"progress\":\"[=========================\\u003e                         ]  13.99MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":44063467,\"total\":88111129},\"progress\":\"[=========================\\u003e                         ]  44.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":15112900,\"total\":27504647},\"progress\":\"[===========================\\u003e                       ]  15.11MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":45132523,\"total\":88111129},\"progress\":\"[=========================\\u003e                         ]  45.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16235204,\"total\":27504647},\"progress\":\"[=============================\\u003e                     ]  16.24MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52418,\"total\":5149051},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1195147,\"total\":5149051},\"progress\":\"[===========\\u003e                                       ]  1.195MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16792260,\"total\":27504647},\"progress\":\"[==============================\\u003e                    ]  16.79MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":45673195,\"total\":88111129},\"progress\":\"[=========================\\u003e                         ]  45.67MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2702475,\"total\":5149051},\"progress\":\"[==========================\\u003e                        ]  2.702MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4078320,\"total\":5149051},\"progress\":\"[=======================================\\u003e           ]  4.078MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":17349316,\"total\":27504647},\"progress\":\"[===============================\\u003e                   ]  17.35MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":46213867,\"total\":88111129},\"progress\":\"[==========================\\u003e                        ]  46.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":17918660,\"total\":27504647},\"progress\":\"[================================\\u003e                  ]  17.92MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":19040964,\"total\":27504647},\"progress\":\"[==================================\\u003e                ]  19.04MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":47295211,\"total\":88111129},\"progress\":\"[==========================\\u003e                        ]   47.3MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":20183748,\"total\":27504647},\"progress\":\"[====================================\\u003e              ]  20.18MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":48368363,\"total\":88111129},\"progress\":\"[===========================\\u003e                       ]  48.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":21301956,\"total\":27504647},\"progress\":\"[======================================\\u003e            ]   21.3MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":22432452,\"total\":27504647},\"progress\":\"[========================================\\u003e          ]  22.43MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":38884,\"total\":3855277},\"progress\":\"[\\u003e                                                  ]  38.88kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49445611,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  49.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":977632,\"total\":3855277},\"progress\":\"[============\\u003e                                      ]  977.6kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23268036,\"total\":27504647},\"progress\":\"[==========================================\\u003e        ]  23.27MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49986283,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  49.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1895136,\"total\":3855277},\"progress\":\"[========================\\u003e                          ]  1.895MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23833284,\"total\":27504647},\"progress\":\"[===========================================\\u003e       ]  23.83MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2939616,\"total\":3855277},\"progress\":\"[======================================\\u003e            ]   2.94MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":24390340,\"total\":27504647},\"progress\":\"[============================================\\u003e      ]  24.39MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":50518763,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  50.52MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":24947396,\"total\":27504647},\"progress\":\"[=============================================\\u003e     ]  24.95MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":51059435,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  51.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":25803460,\"total\":27504647},\"progress\":\"[==============================================\\u003e    ]   25.8MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":26942148,\"total\":27504647},\"progress\":\"[================================================\\u003e  ]  26.94MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52140779,\"total\":88111129},\"progress\":\"[=============================\\u003e                     ]  52.14MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":27504647,\"total\":27504647},\"progress\":\"[==================================================\\u003e]   27.5MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":53222123,\"total\":88111129},\"progress\":\"[==============================\\u003e                    ]  53.22MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":51194,\"total\":4983195},\"progress\":\"[\\u003e                                                  ]  51.19kB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":54299371,\"total\":88111129},\"progress\":\"[==============================\\u003e                    ]   54.3MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1268464,\"total\":4983195},\"progress\":\"[============\\u003e                                      ]  1.268MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":54827755,\"total\":88111129},\"progress\":\"[===============================\\u003e                   ]  54.83MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2767600,\"total\":4983195},\"progress\":\"[===========================\\u003e                       ]  2.768MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4528880,\"total\":4983195},\"progress\":\"[=============================================\\u003e     ]  4.529MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":55368427,\"total\":88111129},\"progress\":\"[===============================\\u003e                   ]  55.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":63614,\"total\":6103207},\"progress\":\"[\\u003e                                                  ]  63.61kB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":56449771,\"total\":88111129},\"progress\":\"[================================\\u003e                  ]  56.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1530606,\"total\":6103207},\"progress\":\"[============\\u003e                                      ]  1.531MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3193582,\"total\":6103207},\"progress\":\"[==========================\\u003e                        ]  3.194MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":56990443,\"total\":88111129},\"progress\":\"[================================\\u003e                  ]  56.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4786926,\"total\":6103207},\"progress\":\"[=======================================\\u003e           ]  4.787MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":57531115,\"total\":88111129},\"progress\":\"[================================\\u003e                  ]  57.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":489,\"total\":787},\"progress\":\"[===============================\\u003e                   ]     489B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":58612459,\"total\":88111129},\"progress\":\"[=================================\\u003e                 ]  58.61MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":787,\"total\":787},\"progress\":\"[==================================================\\u003e]     787B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":60213995,\"total\":88111129},\"progress\":\"[==================================\\u003e                ]  60.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":61827819,\"total\":88111129},\"progress\":\"[===================================\\u003e               ]  61.83MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":63449835,\"total\":88111129},\"progress\":\"[====================================\\u003e              ]  63.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":65071851,\"total\":88111129},\"progress\":\"[====================================\\u003e              ]  65.07MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49803,\"total\":4894860},\"progress\":\"[\\u003e                                                  ]   49.8kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49681,\"total\":4953791},\"progress\":\"[\\u003e                                                  ]  49.68kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":912099,\"total\":4894860},\"progress\":\"[=========\\u003e                                         ]  912.1kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":66145003,\"total\":88111129},\"progress\":\"[=====================================\\u003e             ]  66.15MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":748270,\"total\":4953791},\"progress\":\"[=======\\u003e                                           ]  748.3kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1702627,\"total\":4894860},\"progress\":\"[=================\\u003e                                 ]  1.703MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":67205867,\"total\":88111129},\"progress\":\"[======================================\\u003e            ]  67.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1678062,\"total\":4953791},\"progress\":\"[================\\u003e                                  ]  1.678MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2194147,\"total\":4894860},\"progress\":\"[======================\\u003e                            ]  2.194MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":67746539,\"total\":88111129},\"progress\":\"[======================================\\u003e            ]  67.75MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2648814,\"total\":4953791},\"progress\":\"[==========================\\u003e                        ]  2.649MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2743011,\"total\":4894860},\"progress\":\"[============================\\u003e                      ]  2.743MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":68287211,\"total\":88111129},\"progress\":\"[======================================\\u003e            ]  68.29MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3697390,\"total\":4953791},\"progress\":\"[=====================================\\u003e             ]  3.697MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3381987,\"total\":4894860},\"progress\":\"[==================================\\u003e                ]  3.382MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4774638,\"total\":4953791},\"progress\":\"[================================================\\u003e  ]  4.775MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":68827883,\"total\":88111129},\"progress\":\"[=======================================\\u003e           ]  68.83MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4953791,\"total\":4953791},\"progress\":\"[==================================================\\u003e]  4.954MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4004579,\"total\":4894860},\"progress\":\"[========================================\\u003e          ]  4.005MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4893411,\"total\":4894860},\"progress\":\"[=================================================\\u003e ]  4.893MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":69909227,\"total\":88111129},\"progress\":\"[=======================================\\u003e           ]  69.91MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":71527147,\"total\":88111129},\"progress\":\"[========================================\\u003e          ]  71.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":73149163,\"total\":88111129},\"progress\":\"[=========================================\\u003e         ]  73.15MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":74771179,\"total\":88111129},\"progress\":\"[==========================================\\u003e        ]  74.77MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":63573,\"total\":6137526},\"progress\":\"[\\u003e                                                  ]  63.57kB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":75311851,\"total\":88111129},\"progress\":\"[==========================================\\u003e        ]  75.31MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1317559,\"total\":6137526},\"progress\":\"[==========\\u003e                                        ]  1.318MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2710199,\"total\":6137526},\"progress\":\"[======================\\u003e                            ]   2.71MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":38729,\"total\":3854415},\"progress\":\"[\\u003e                                                  ]  38.73kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":76368619,\"total\":88111129},\"progress\":\"[===========================================\\u003e       ]  76.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3783351,\"total\":6137526},\"progress\":\"[==============================\\u003e                    ]  3.783MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":658157,\"total\":3854415},\"progress\":\"[========\\u003e                                          ]  658.2kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4520631,\"total\":6137526},\"progress\":\"[====================================\\u003e              ]  4.521MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1350381,\"total\":3854415},\"progress\":\"[=================\\u003e                                 ]   1.35MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5364407,\"total\":6137526},\"progress\":\"[===========================================\\u003e       ]  5.364MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":77445867,\"total\":88111129},\"progress\":\"[===========================================\\u003e       ]  77.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2153197,\"total\":3854415},\"progress\":\"[===========================\\u003e                       ]  2.153MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":77986539,\"total\":88111129},\"progress\":\"[============================================\\u003e      ]  77.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3021549,\"total\":3854415},\"progress\":\"[=======================================\\u003e           ]  3.022MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":79067883,\"total\":88111129},\"progress\":\"[============================================\\u003e      ]  79.07MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":80149227,\"total\":88111129},\"progress\":\"[=============================================\\u003e     ]  80.15MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":81767147,\"total\":88111129},\"progress\":\"[==============================================\\u003e    ]  81.77MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5222290},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1055455,\"total\":5222290},\"progress\":\"[==========\\u003e                                        ]  1.055MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":83372779,\"total\":88111129},\"progress\":\"[===============================================\\u003e   ]  83.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2333407,\"total\":5222290},\"progress\":\"[======================\\u003e                            ]  2.333MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":35991,\"total\":3564359},\"progress\":\"[\\u003e                                                  ]  35.99kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":84454123,\"total\":88111129},\"progress\":\"[===============================================\\u003e   ]  84.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3300063,\"total\":5222290},\"progress\":\"[===============================\\u003e                   ]    3.3MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":752366,\"total\":3564359},\"progress\":\"[==========\\u003e                                        ]  752.4kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3979999,\"total\":5222290},\"progress\":\"[======================================\\u003e            ]   3.98MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1743598,\"total\":3564359},\"progress\":\"[========================\\u003e                          ]  1.744MB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":85527275,\"total\":88111129},\"progress\":\"[================================================\\u003e  ]  85.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4537055,\"total\":5222290},\"progress\":\"[===========================================\\u003e       ]  4.537MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2833134,\"total\":3564359},\"progress\":\"[=======================================\\u003e           ]  2.833MB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5077727,\"total\":5222290},\"progress\":\"[================================================\\u003e  ]  5.078MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":86067947,\"total\":88111129},\"progress\":\"[================================================\\u003e  ]  86.07MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":87132907,\"total\":88111129},\"progress\":\"[=================================================\\u003e ]  87.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":557056,\"total\":88111129},\"progress\":\"[\\u003e                                                  ]  557.1kB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52418,\"total\":5120108},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":489,\"total\":790},\"progress\":\"[==============================\\u003e                    ]     489B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5013504,\"total\":88111129},\"progress\":\"[==\\u003e                                                ]  5.014MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":790,\"total\":790},\"progress\":\"[==================================================\\u003e]     790B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1764079,\"total\":5120108},\"progress\":\"[=================\\u003e                                 ]  1.764MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":8355840,\"total\":88111129},\"progress\":\"[====\\u003e                                              ]  8.356MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3635951,\"total\":5120108},\"progress\":\"[===================================\\u003e               ]  3.636MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":11141120,\"total\":88111129},\"progress\":\"[======\\u003e                                            ]  11.14MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5117023},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":13369344,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  13.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1596142,\"total\":5117023},\"progress\":\"[===============\\u003e                                   ]  1.596MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":13926400,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  13.93MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3242734,\"total\":5117023},\"progress\":\"[===============================\\u003e                   ]  3.243MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":55157,\"total\":5384215},\"progress\":\"[\\u003e                                                  ]  55.16kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4635374,\"total\":5117023},\"progress\":\"[=============================================\\u003e     ]  4.635MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":15040512,\"total\":88111129},\"progress\":\"[========\\u003e                                          ]  15.04MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":989937,\"total\":5384215},\"progress\":\"[=========\\u003e                                         ]  989.9kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":15597568,\"total\":88111129},\"progress\":\"[========\\u003e                                          ]   15.6MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2558705,\"total\":5384215},\"progress\":\"[=======================\\u003e                           ]  2.559MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":18382848,\"total\":88111129},\"progress\":\"[==========\\u003e                                        ]  18.38MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4311793,\"total\":5384215},\"progress\":\"[========================================\\u003e          ]  4.312MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":53788,\"total\":5252487},\"progress\":\"[\\u003e                                                  ]  53.79kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":22839296,\"total\":88111129},\"progress\":\"[============\\u003e                                      ]  22.84MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5212913,\"total\":5384215},\"progress\":\"[================================================\\u003e  ]  5.213MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":846577,\"total\":5252487},\"progress\":\"[========\\u003e                                          ]  846.6kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":26181632,\"total\":88111129},\"progress\":\"[==============\\u003e                                    ]  26.18MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2628337,\"total\":5252487},\"progress\":\"[=========================\\u003e                         ]  2.628MB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":30638080,\"total\":88111129},\"progress\":\"[=================\\u003e                                 ]  30.64MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4340465,\"total\":5252487},\"progress\":\"[=========================================\\u003e         ]   4.34MB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":33423360,\"total\":88111129},\"progress\":\"[==================\\u003e                                ]  33.42MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":51204,\"total\":5015856},\"progress\":\"[\\u003e                                                  ]   51.2kB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":36208640,\"total\":88111129},\"progress\":\"[====================\\u003e                              ]  36.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1624816,\"total\":5015856},\"progress\":\"[================\\u003e                                  ]  1.625MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":38436864,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]  38.44MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3373808,\"total\":5015856},\"progress\":\"[=================================\\u003e                 ]  3.374MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":40665088,\"total\":88111129},\"progress\":\"[=======================\\u003e                           ]  40.67MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":53910,\"total\":5310566},\"progress\":\"[\\u003e                                                  ]  53.91kB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4905712,\"total\":5015856},\"progress\":\"[================================================\\u003e  ]  4.906MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1313521,\"total\":5310566},\"progress\":\"[============\\u003e                                      ]  1.314MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":44007424,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  44.01MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":46792704,\"total\":88111129},\"progress\":\"[==========================\\u003e                        ]  46.79MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3082993,\"total\":5310566},\"progress\":\"[=============================\\u003e                     ]  3.083MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49836,\"total\":4915049},\"progress\":\"[\\u003e                                                  ]  49.84kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4373233,\"total\":5310566},\"progress\":\"[=========================================\\u003e         ]  4.373MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":48463872,\"total\":88111129},\"progress\":\"[===========================\\u003e                       ]  48.46MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":711407,\"total\":4915049},\"progress\":\"[=======\\u003e                                           ]  711.4kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1710831,\"total\":4915049},\"progress\":\"[=================\\u003e                                 ]  1.711MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":52363264,\"total\":88111129},\"progress\":\"[=============================\\u003e                     ]  52.36MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3504879,\"total\":4915049},\"progress\":\"[===================================\\u003e               ]  3.505MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":55705600,\"total\":88111129},\"progress\":\"[===============================\\u003e                   ]  55.71MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4905711,\"total\":4915049},\"progress\":\"[=================================================\\u003e ]  4.906MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":58490880,\"total\":88111129},\"progress\":\"[=================================\\u003e                 ]  58.49MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5119213},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":61276160,\"total\":88111129},\"progress\":\"[==================================\\u003e                ]  61.28MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1333999,\"total\":5119213},\"progress\":\"[=============\\u003e                                     ]  1.334MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2657007,\"total\":5119213},\"progress\":\"[=========================\\u003e                         ]  2.657MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":64061440,\"total\":88111129},\"progress\":\"[====================================\\u003e              ]  64.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4344559,\"total\":5119213},\"progress\":\"[==========================================\\u003e        ]  4.345MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":66289664,\"total\":88111129},\"progress\":\"[=====================================\\u003e             ]  66.29MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":70746112,\"total\":88111129},\"progress\":\"[========================================\\u003e          ]  70.75MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":73531392,\"total\":88111129},\"progress\":\"[=========================================\\u003e         ]  73.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":77430784,\"total\":88111129},\"progress\":\"[===========================================\\u003e       ]  77.43MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":488,\"total\":1069},\"progress\":\"[======================\\u003e                            ]     488B/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":80216064,\"total\":88111129},\"progress\":\"[=============================================\\u003e     ]  80.22MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1069,\"total\":1069},\"progress\":\"[==================================================\\u003e]  1.069kB/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":32,\"total\":32},\"progress\":\"[==================================================\\u003e]      32B/32B\",\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":81887232,\"total\":88111129},\"progress\":\"[==============================================\\u003e    ]  81.89MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":83558400,\"total\":88111129},\"progress\":\"[===============================================\\u003e   ]  83.56MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":85229568,\"total\":88111129},\"progress\":\"[================================================\\u003e  ]  85.23MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":86900736,\"total\":88111129},\"progress\":\"[=================================================\\u003e ]   86.9MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":88014848,\"total\":88111129},\"progress\":\"[=================================================\\u003e ]  88.01MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":88111129,\"total\":88111129},\"progress\":\"[==================================================\\u003e]  88.11MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32768,\"total\":1391657},\"progress\":\"[=\\u003e                                                 ]  32.77kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":1391657},\"progress\":\"[===========\\u003e                                       ]  327.7kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1391657,\"total\":1391657},\"progress\":\"[==================================================\\u003e]  1.392MB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1391657,\"total\":1391657},\"progress\":\"[==================================================\\u003e]  1.392MB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32768,\"total\":1328346},\"progress\":\"[=\\u003e                                                 ]  32.77kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":753664,\"total\":1328346},\"progress\":\"[============================\\u003e                      ]  753.7kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1328346,\"total\":1328346},\"progress\":\"[==================================================\\u003e]  1.328MB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1328346,\"total\":1328346},\"progress\":\"[==================================================\\u003e]  1.328MB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4478,\"total\":4478},\"progress\":\"[==================================================\\u003e]  4.478kB/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4478,\"total\":4478},\"progress\":\"[==================================================\\u003e]  4.478kB/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":197,\"total\":197},\"progress\":\"[==================================================\\u003e]     197B/197B\",\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":197,\"total\":197},\"progress\":\"[==================================================\\u003e]     197B/197B\",\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":294912,\"total\":27504647},\"progress\":\"[\\u003e                                                  ]  294.9kB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":589824,\"total\":27504647},\"progress\":\"[=\\u003e                                                 ]  589.8kB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5013504,\"total\":27504647},\"progress\":\"[=========\\u003e                                         ]  5.014MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":9142272,\"total\":27504647},\"progress\":\"[================\\u003e                                  ]  9.142MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":13565952,\"total\":27504647},\"progress\":\"[========================\\u003e                          ]  13.57MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":16515072,\"total\":27504647},\"progress\":\"[==============================\\u003e                    ]  16.52MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":18579456,\"total\":27504647},\"progress\":\"[=================================\\u003e                 ]  18.58MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":21528576,\"total\":27504647},\"progress\":\"[=======================================\\u003e           ]  21.53MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":25657344,\"total\":27504647},\"progress\":\"[==============================================\\u003e    ]  25.66MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":27504647,\"total\":27504647},\"progress\":\"[==================================================\\u003e]   27.5MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5205016},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1048576,\"total\":5205016},\"progress\":\"[==========\\u003e                                        ]  1.049MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5205016,\"total\":5205016},\"progress\":\"[==================================================\\u003e]  5.205MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4964709},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1245184,\"total\":4964709},\"progress\":\"[============\\u003e                                      ]  1.245MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4964709,\"total\":4964709},\"progress\":\"[==================================================\\u003e]  4.965MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5149051},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":393216,\"total\":5149051},\"progress\":\"[===\\u003e                                               ]  393.2kB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5149051,\"total\":5149051},\"progress\":\"[==================================================\\u003e]  5.149MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":3855277},\"progress\":\"[\\u003e                                                  ]  65.54kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":851968,\"total\":3855277},\"progress\":\"[===========\\u003e                                       ]    852kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3855277,\"total\":3855277},\"progress\":\"[==================================================\\u003e]  3.855MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3855277,\"total\":3855277},\"progress\":\"[==================================================\\u003e]  3.855MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4983195},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":4983195},\"progress\":\"[===\\u003e                                               ]  327.7kB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4980736,\"total\":4983195},\"progress\":\"[=================================================\\u003e ]  4.981MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4983195,\"total\":4983195},\"progress\":\"[==================================================\\u003e]  4.983MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":6103207},\"progress\":\"[\\u003e                                                  ]  65.54kB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":6103207},\"progress\":\"[==\\u003e                                                ]  327.7kB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3670016,\"total\":6103207},\"progress\":\"[==============================\\u003e                    ]   3.67MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":6103207,\"total\":6103207},\"progress\":\"[==================================================\\u003e]  6.103MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":787,\"total\":787},\"progress\":\"[==================================================\\u003e]     787B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":787,\"total\":787},\"progress\":\"[==================================================\\u003e]     787B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4894860},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":4894860},\"progress\":\"[===\\u003e                                               ]  327.7kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3735552,\"total\":4894860},\"progress\":\"[======================================\\u003e            ]  3.736MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4894860,\"total\":4894860},\"progress\":\"[==================================================\\u003e]  4.895MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4953791},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":4953791},\"progress\":\"[===\\u003e                                               ]  327.7kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4325376,\"total\":4953791},\"progress\":\"[===========================================\\u003e       ]  4.325MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4953791,\"total\":4953791},\"progress\":\"[==================================================\\u003e]  4.954MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":6137526},\"progress\":\"[\\u003e                                                  ]  65.54kB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":6137526},\"progress\":\"[==\\u003e                                                ]  327.7kB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3801088,\"total\":6137526},\"progress\":\"[==============================\\u003e                    ]  3.801MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":6137526,\"total\":6137526},\"progress\":\"[==================================================\\u003e]  6.138MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":3854415},\"progress\":\"[\\u003e                                                  ]  65.54kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":851968,\"total\":3854415},\"progress\":\"[===========\\u003e                                       ]    852kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3854415,\"total\":3854415},\"progress\":\"[==================================================\\u003e]  3.854MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3854415,\"total\":3854415},\"progress\":\"[==================================================\\u003e]  3.854MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5222290},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":458752,\"total\":5222290},\"progress\":\"[====\\u003e                                              ]  458.8kB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4849664,\"total\":5222290},\"progress\":\"[==============================================\\u003e    ]   4.85MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5222290,\"total\":5222290},\"progress\":\"[==================================================\\u003e]  5.222MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":3564359},\"progress\":\"[\\u003e                                                  ]  65.54kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":3564359},\"progress\":\"[====\\u003e                                              ]  327.7kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3564359,\"total\":3564359},\"progress\":\"[==================================================\\u003e]  3.564MB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":790,\"total\":790},\"progress\":\"[==================================================\\u003e]     790B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":790,\"total\":790},\"progress\":\"[==================================================\\u003e]     790B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5120108},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5120108},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5111808,\"total\":5120108},\"progress\":\"[=================================================\\u003e ]  5.112MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5120108,\"total\":5120108},\"progress\":\"[==================================================\\u003e]   5.12MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5117023},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":655360,\"total\":5117023},\"progress\":\"[======\\u003e                                            ]  655.4kB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4259840,\"total\":5117023},\"progress\":\"[=========================================\\u003e         ]   4.26MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5117023,\"total\":5117023},\"progress\":\"[==================================================\\u003e]  5.117MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5384215},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5384215},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5177344,\"total\":5384215},\"progress\":\"[================================================\\u003e  ]  5.177MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5384215,\"total\":5384215},\"progress\":\"[==================================================\\u003e]  5.384MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5252487},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":655360,\"total\":5252487},\"progress\":\"[======\\u003e                                            ]  655.4kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5252487,\"total\":5252487},\"progress\":\"[==================================================\\u003e]  5.252MB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5015856},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5015856},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3997696,\"total\":5015856},\"progress\":\"[=======================================\\u003e           ]  3.998MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5015856,\"total\":5015856},\"progress\":\"[==================================================\\u003e]  5.016MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5310566},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":393216,\"total\":5310566},\"progress\":\"[===\\u003e                                               ]  393.2kB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3407872,\"total\":5310566},\"progress\":\"[================================\\u003e                  ]  3.408MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5310566,\"total\":5310566},\"progress\":\"[==================================================\\u003e]  5.311MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4915049},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":786432,\"total\":4915049},\"progress\":\"[========\\u003e                                          ]  786.4kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4915049,\"total\":4915049},\"progress\":\"[==================================================\\u003e]  4.915MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4915049,\"total\":4915049},\"progress\":\"[==================================================\\u003e]  4.915MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5119213},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5119213},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4390912,\"total\":5119213},\"progress\":\"[==========================================\\u003e        ]  4.391MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5119213,\"total\":5119213},\"progress\":\"[==================================================\\u003e]  5.119MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":395,\"total\":395},\"progress\":\"[==================================================\\u003e]     395B/395B\",\"id\":\"272cdf839cbb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":395,\"total\":395},\"progress\":\"[==================================================\\u003e]     395B/395B\",\"id\":\"272cdf839cbb\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":155,\"total\":155},\"progress\":\"[==================================================\\u003e]     155B/155B\",\"id\":\"50d054c97f4f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":155,\"total\":155},\"progress\":\"[==================================================\\u003e]     155B/155B\",\"id\":\"50d054c97f4f\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1069,\"total\":1069},\"progress\":\"[==================================================\\u003e]  1.069kB/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1069,\"total\":1069},\"progress\":\"[==================================================\\u003e]  1.069kB/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32,\"total\":32},\"progress\":\"[==================================================\\u003e]      32B/32B\",\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32,\"total\":32},\"progress\":\"[==================================================\\u003e]      32B/32B\",\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Digest: sha256:4acb6bfd6c4f0cabaf7f3690e444afe51f1c7de54d51da7e63fac709c56f1c30\"}\n{\"status\":\"Status: Downloaded newer image for paketo-buildpacks/cnb:base\"}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/pull-update-full.json",
    "content": "{\n\t\"status\": \"Extracting\",\n\t\"progressDetail\": {\n\t\t\"current\": 16,\n\t\t\"total\": 32\n\t},\n\t\"progress\": \"[==================================================\\u003e]      32B/32B\",\n\t\"id\": \"4f4fb700ef54\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/pull-update-minimal.json",
    "content": "{\n\t\"status\": \"Status: Downloaded newer image for paketo-buildpacks/cnb:base\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/pull-with-empty-details.json",
    "content": "{\n\t\"status\": \"Pulling fs layer\",\n\t\"progressDetail\": {\n\t},\n\t\"id\": \"d837a2a1365e\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/push-stream-with-error.json",
    "content": "{\n\t\"status\":\"The push refers to repository [localhost:5000/ubuntu]\"\n}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"782f5f011dda\"}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"90ac32a0d9ab\"}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"d42a4fdf4b2a\"}\n{\"errorDetail\":{\"message\":\"test message\"},\"error\":\"test error\"}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/push-stream.json",
    "content": "{\n\t\"status\":\"The push refers to repository [localhost:5000/ubuntu]\"\n}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"782f5f011dda\"}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"90ac32a0d9ab\"}\n{\"status\":\"Preparing\",\"progressDetail\":{},\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":512,\"total\":7},\"progress\":\"[==================================================\\u003e]     512B\",\"id\":\"782f5f011dda\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":512,\"total\":811},\"progress\":\"[===============================\\u003e                   ]     512B/811B\",\"id\":\"90ac32a0d9ab\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":3072,\"total\":7},\"progress\":\"[==================================================\\u003e]  3.072kB\",\"id\":\"782f5f011dda\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":15360,\"total\":811},\"progress\":\"[==================================================\\u003e]  15.36kB\",\"id\":\"90ac32a0d9ab\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":543232,\"total\":72874905},\"progress\":\"[\\u003e                                                  ]  543.2kB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushed\",\"progressDetail\":{},\"id\":\"90ac32a0d9ab\"}\n{\"status\":\"Pushed\",\"progressDetail\":{},\"id\":\"782f5f011dda\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":2713600,\"total\":72874905},\"progress\":\"[=\\u003e                                                 ]  2.714MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":4870656,\"total\":72874905},\"progress\":\"[===\\u003e                                               ]  4.871MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":7069184,\"total\":72874905},\"progress\":\"[====\\u003e                                              ]  7.069MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":9238528,\"total\":72874905},\"progress\":\"[======\\u003e                                            ]  9.239MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":11354112,\"total\":72874905},\"progress\":\"[=======\\u003e                                           ]  11.35MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":13582336,\"total\":72874905},\"progress\":\"[=========\\u003e                                         ]  13.58MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":16336248,\"total\":72874905},\"progress\":\"[===========\\u003e                                       ]  16.34MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":19036160,\"total\":72874905},\"progress\":\"[=============\\u003e                                     ]  19.04MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":21762560,\"total\":72874905},\"progress\":\"[==============\\u003e                                    ]  21.76MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":24480256,\"total\":72874905},\"progress\":\"[================\\u003e                                  ]  24.48MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":28756480,\"total\":72874905},\"progress\":\"[===================\\u003e                               ]  28.76MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":32001024,\"total\":72874905},\"progress\":\"[=====================\\u003e                             ]     32MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":34195456,\"total\":72874905},\"progress\":\"[=======================\\u003e                           ]   34.2MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":36393984,\"total\":72874905},\"progress\":\"[========================\\u003e                          ]  36.39MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":38587904,\"total\":72874905},\"progress\":\"[==========================\\u003e                        ]  38.59MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":41290752,\"total\":72874905},\"progress\":\"[============================\\u003e                      ]  41.29MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":43487744,\"total\":72874905},\"progress\":\"[=============================\\u003e                     ]  43.49MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":45683200,\"total\":72874905},\"progress\":\"[===============================\\u003e                   ]  45.68MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":48413184,\"total\":72874905},\"progress\":\"[=================================\\u003e                 ]  48.41MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":51119104,\"total\":72874905},\"progress\":\"[===================================\\u003e               ]  51.12MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":53327360,\"total\":72874905},\"progress\":\"[====================================\\u003e              ]  53.33MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":54964224,\"total\":72874905},\"progress\":\"[=====================================\\u003e             ]  54.96MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":57169408,\"total\":72874905},\"progress\":\"[=======================================\\u003e           ]  57.17MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":59355825,\"total\":72874905},\"progress\":\"[========================================\\u003e          ]  59.36MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":62002592,\"total\":72874905},\"progress\":\"[==========================================\\u003e        ]     62MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":64700928,\"total\":72874905},\"progress\":\"[============================================\\u003e      ]   64.7MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":67435688,\"total\":72874905},\"progress\":\"[==============================================\\u003e    ]  67.44MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":70095743,\"total\":72874905},\"progress\":\"[================================================\\u003e  ]   70.1MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":72823808,\"total\":72874905},\"progress\":\"[=================================================\\u003e ]  72.82MB/72.87MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushing\",\"progressDetail\":{\"current\":75247104,\"total\":72874905},\"progress\":\"[==================================================\\u003e]  75.25MB\",\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"Pushed\",\"progressDetail\":{},\"id\":\"d42a4fdf4b2a\"}\n{\"status\":\"latest: digest: sha256:2e70e9c81838224b5311970dbf7ed16802fbfe19e7a70b3cbfa3d7522aa285b4 size: 943\"}\n{\"progressDetail\":{},\"aux\":{\"Tag\":\"latest\",\"Digest\":\"sha256:2e70e9c81838224b5311970dbf7ed16802fbfe19e7a70b3cbfa3d7522aa285b4\",\"Size\":943}}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/transport/errors.json",
    "content": "{\n\t\"errors\": [\n\t\t{\n\t\t\t\"code\": \"TEST1\",\n\t\t\t\"message\": \"Test One\",\n\t\t\t\"detail\": 123\n\t\t},\n\t\t{\n\t\t\t\"code\": \"TEST2\",\n\t\t\t\"message\": \"Test Two\",\n\t\t\t\"detail\": \"fail\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/transport/message-and-errors.json",
    "content": "{\n  \"message\": \"test message\",\n  \"errors\": [\n    {\n      \"code\": \"TEST1\",\n      \"message\": \"Test One\",\n      \"detail\": 123\n    },\n    {\n      \"code\": \"TEST2\",\n      \"message\": \"Test Two\",\n      \"detail\": \"fail\"\n    }\n  ]\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/transport/message.json",
    "content": "{\n\t\"message\": \"test message\"\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/transport/proxy-error.txt",
    "content": "Some kind of proxy auth problem!\n\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-config.json",
    "content": "{\n\t\"User\": \"root\",\n\t\"Image\": \"docker.io/library/ubuntu:bionic\",\n\t\"Cmd\": [\n\t\t\"ls\",\n\t\t\"-l\",\n\t\t\"-h\"\n\t],\n\t\"Env\": [\n\t\t\"name1=value1\",\n\t\t\"name2=value2\"\n\t],\n\t\"Labels\": {\n\t\t\"spring\": \"boot\"\n\t},\n\t\"HostConfig\": {\n\t\t\"Binds\": [\n\t\t\t\"bind-source:bind-dest\"\n\t\t],\n\t\t\"NetworkMode\": \"test\",\n\t\t\"SecurityOpt\": [\n\t\t\t\"option=value\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-status-error.json",
    "content": "{\n\t\"StatusCode\": 1,\n\t\"Error\": {\n\t\t\"Message\": \"error detail\"\n\t}\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/container-status-success.json",
    "content": "{\n\t\"StatusCode\": 0\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/distribution-manifest-list.json",
    "content": "{\n\t\"schemaVersion\": 2,\n\t\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\",\n\t\"manifests\": [\n\t\t{\n\t\t\t\"mediaType\": \"application/vnd.docker.distribution.manifest.v2+json\",\n\t\t\t\"size\": 428,\n\t\t\t\"digest\": \"sha256:6dba064234a3aa60f7da2e0f1f8b86dccb7df2841136f577b08bd6a89004cb23\",\n\t\t\t\"platform\": {\n\t\t\t\t\"architecture\": \"amd64\",\n\t\t\t\t\"os\": \"linux\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"mediaType\": \"application/vnd.docker.distribution.manifest.v2+json\",\n\t\t\t\"size\": 428,\n\t\t\t\"digest\": \"sha256:c036aba2c51a86a7a338f60af4730df725c2abff1b8b565d753896fd9533dfad\",\n\t\t\t\"platform\": {\n\t\t\t\t\"architecture\": \"arm64\",\n\t\t\t\t\"os\": \"linux\"\n\t\t\t}\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/distribution-manifest.json",
    "content": "{\n\t\"schemaVersion\": 2,\n\t\"mediaType\": \"application/vnd.docker.distribution.manifest.v2+json\",\n\t\"config\": {\n\t\t\"mediaType\": \"application/vnd.docker.container.image.v1+json\",\n\t\t\"size\": 1175,\n\t\t\"digest\": \"sha256:b2160a0f9037918d3ca2270fb90f656f425760b337a5ed3813c3a48c09825065\"\n\t},\n\t\"layers\": [\n\t\t{\n\t\t\t\"mediaType\": \"application/vnd.docker.image.rootfs.diff.tar.gzip\",\n\t\t\t\"size\": 4872935,\n\t\t\t\"digest\": \"sha256:13ac7da0441b95b1960de1b87ed2c1ef129026cc69b926ffbe734a7dcc4fa40c\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-archive-config.json",
    "content": "{\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t}\n\t},\n\t\"Created\": \"1980-01-01T00:00:01Z\",\n\t\"History\": [\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t},\n\t\t{\n\n\t\t}\n\t],\n  \"Architecture\": \"amd64\",\n\t\"Os\": \"linux\",\n  \"Variant\": \"v1\",\n\t\"RootFS\": {\n\t\t\"diff_ids\": [\n\t\t\t\"sha256:733a8e5ce32984099ef675fce04730f6e2a6dcfdf5bd292fea01a8f936265342\",\n\t\t\t\"sha256:7755b972f0b4f49de73ef5114fb3ba9c69d80f217e80da99f56f0d0a5dcb3d70\",\n\t\t\t\"sha256:8f0b2d09ab4b38530a1630403967d11a601e56e02e79d3f56370d34fd071fe38\",\n\t\t\t\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\",\n\t\t\t\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\",\n\t\t\t\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\",\n\t\t\t\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\",\n\t\t\t\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\",\n\t\t\t\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\",\n\t\t\t\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\",\n\t\t\t\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\",\n\t\t\t\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\",\n\t\t\t\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\",\n\t\t\t\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\",\n\t\t\t\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\",\n\t\t\t\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\",\n\t\t\t\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\",\n\t\t\t\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\",\n\t\t\t\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\",\n\t\t\t\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\",\n\t\t\t\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\",\n\t\t\t\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\",\n\t\t\t\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\",\n\t\t\t\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\",\n\t\t\t\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\",\n\t\t\t\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\",\n\t\t\t\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\",\n\t\t\t\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\",\n\t\t\t\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\",\n\t\t\t\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\",\n\t\t\t\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\",\n\t\t\t\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\",\n\t\t\t\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\",\n\t\t\t\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\",\n\t\t\t\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\",\n\t\t\t\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\",\n\t\t\t\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\",\n\t\t\t\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\",\n\t\t\t\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\",\n\t\t\t\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\",\n\t\t\t\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\",\n\t\t\t\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\",\n\t\t\t\"sha256:f8b5dcfa1d082af23bb2b2c08526131921329d48d1614d9f2f163a997176087a\",\n\t\t\t\"sha256:ee13e75c33e0af49fbf6c3aaa5bbd102fc468c2d554c4f94763d35a33964dfe4\",\n\t\t\t\"sha256:2571abab1776d4c2e427fba10d61531afff2ab0789f89ef46ce925b6a5d98e0f\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\",\n\t\t\t\"sha256:bb09e17fd1bd2ee47155f1349645fcd9fff31e1247c7ed99cad469f1c16a4216\"\n\t\t]\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-archive-index.json",
    "content": "{\n\t\"schemaVersion\": 2,\n\t\"manifests\": [\n\t\t{\n\t\t\t\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\",\n\t\t\t\"digest\": \"sha256:3bbe02431d8e5124ffe816ec27bf6508b50edd1d10218be1a03e799a186b9004\",\n\t\t\t\"size\": 529,\n\t\t\t\"annotations\": {\n\t\t\t\t\"containerd.io/distribution.source.gcr.io\": \"paketo-buildpacks/adoptium\",\n\t\t\t\t\"io.containerd.image.name\": \"docker.io/paketobuildpacks/adoptium:latest\",\n\t\t\t\t\"org.opencontainers.image.ref.name\": \"latest\"\n\t\t\t}\n\t\t}\n\t]\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-archive-manifest.json",
    "content": "[\n\t{\n\t\t\"Config\": \"416c76dc7f691f91e80516ff039e056f32f996b59af4b1cb8114e6ae8171a374.json\",\n\t\t\"Layers\": [\n\t\t\t\"blank_0\",\n\t\t\t\"blank_1\",\n\t\t\t\"blank_2\",\n\t\t\t\"blank_3\",\n\t\t\t\"blank_4\",\n\t\t\t\"blank_5\",\n\t\t\t\"blank_6\",\n\t\t\t\"blank_7\",\n\t\t\t\"blank_8\",\n\t\t\t\"blank_9\",\n\t\t\t\"blank_10\",\n\t\t\t\"blank_11\",\n\t\t\t\"blank_12\",\n\t\t\t\"blank_13\",\n\t\t\t\"blank_14\",\n\t\t\t\"blank_15\",\n\t\t\t\"blank_16\",\n\t\t\t\"blank_17\",\n\t\t\t\"blank_18\",\n\t\t\t\"blank_19\",\n\t\t\t\"blank_20\",\n\t\t\t\"blank_21\",\n\t\t\t\"blank_22\",\n\t\t\t\"blank_23\",\n\t\t\t\"blank_24\",\n\t\t\t\"blank_25\",\n\t\t\t\"blank_26\",\n\t\t\t\"blank_27\",\n\t\t\t\"blank_28\",\n\t\t\t\"blank_29\",\n\t\t\t\"blank_30\",\n\t\t\t\"blank_31\",\n\t\t\t\"blank_32\",\n\t\t\t\"blank_33\",\n\t\t\t\"blank_34\",\n\t\t\t\"blank_35\",\n\t\t\t\"blank_36\",\n\t\t\t\"blank_37\",\n\t\t\t\"blank_38\",\n\t\t\t\"blank_39\",\n\t\t\t\"blank_40\",\n\t\t\t\"blank_41\",\n\t\t\t\"blank_42\",\n\t\t\t\"blank_43\",\n\t\t\t\"blank_44\",\n\t\t\t\"blank_45\",\n\t\t\t\"bb09e17fd1bd2ee47155f1349645fcd9fff31e1247c7ed99cad469f1c16a4216.tar\"\n\t\t],\n\t\t\"RepoTags\": [\n\t\t\t\"pack.local/builder/6b7874626575656b6162:latest\"\n\t\t]\n\t}\n]\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-config.json",
    "content": "{\n\t\"Hostname\": \"\",\n\t\"Domainname\": \"\",\n\t\"User\": \"vcap\",\n\t\"AttachStdin\": false,\n\t\"AttachStdout\": false,\n\t\"AttachStderr\": false,\n\t\"Tty\": false,\n\t\"OpenStdin\": false,\n\t\"StdinOnce\": false,\n\t\"Env\": [\n\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\"CNB_USER_ID=2000\",\n\t\t\"CNB_GROUP_ID=2000\",\n\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t],\n\t\"Cmd\": null,\n\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\"Volumes\": null,\n\t\"WorkingDir\": \"/layers\",\n\t\"Entrypoint\": null,\n\t\"OnBuild\": null,\n\t\"Labels\": {\n\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"cflinuxfs3 base image with buildpacks for Java, .NET, NodeJS, Python, Golang, PHP, HTTPD and NGINX\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true}],\\\"groups\\\":[{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"optional\\\":true}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\"}]}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run:full-cnb\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.5.0\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.1\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.5.0 (git sha: c9cfac75b49609524e1ea33f809c12071406547c)\\\"}}\",\n\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.87\\\":{\\\"layerDiffID\\\":\\\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.0.114\\\":{\\\"layerDiffID\\\":\\\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\\\"}},\\\"org.cloudfoundry.conda\\\":{\\\"0.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.0.92\\\":{\\\"layerDiffID\\\":\\\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.51\\\":{\\\"layerDiffID\\\":\\\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.0.89\\\":{\\\"layerDiffID\\\":\\\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.2\\\":{\\\"layerDiffID\\\":\\\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\"}]}]}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.18\\\":{\\\"layerDiffID\\\":\\\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.66\\\":{\\\"layerDiffID\\\":\\\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.55\\\":{\\\"layerDiffID\\\":\\\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\"}]}]}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.48\\\":{\\\"layerDiffID\\\":\\\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.44\\\":{\\\"layerDiffID\\\":\\\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.0.40\\\":{\\\"layerDiffID\\\":\\\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\\\"}},\\\"org.cloudfoundry.httpd\\\":{\\\"0.0.21\\\":{\\\"layerDiffID\\\":\\\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.0.72\\\":{\\\"layerDiffID\\\":\\\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\\\"}},\\\"org.cloudfoundry.nginx\\\":{\\\"0.0.25\\\":{\\\"layerDiffID\\\":\\\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.85\\\":{\\\"layerDiffID\\\":\\\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v0.0.3\\\":{\\\"layerDiffID\\\":\\\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\"}]}]}},\\\"org.cloudfoundry.npm\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\\\"}},\\\"org.cloudfoundry.php\\\":{\\\"v0.0.0-RC1\\\":{\\\"layerDiffID\\\":\\\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]}]}},\\\"org.cloudfoundry.php-composer\\\":{\\\"0.0.16\\\":{\\\"layerDiffID\\\":\\\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\\\"}},\\\"org.cloudfoundry.php-dist\\\":{\\\"0.0.30\\\":{\\\"layerDiffID\\\":\\\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\\\"}},\\\"org.cloudfoundry.php-web\\\":{\\\"0.0.24\\\":{\\\"layerDiffID\\\":\\\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\\\"}},\\\"org.cloudfoundry.pip\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\\\"}},\\\"org.cloudfoundry.pipenv\\\":{\\\"0.0.38\\\":{\\\"layerDiffID\\\":\\\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\\\"}},\\\"org.cloudfoundry.python\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\"},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\"}]}]}},\\\"org.cloudfoundry.python-runtime\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.0.100\\\":{\\\"layerDiffID\\\":\\\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.0.97\\\":{\\\"layerDiffID\\\":\\\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.1.9\\\":{\\\"layerDiffID\\\":\\\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\\\"}},\\\"org.cloudfoundry.yarn\\\":{\\\"0.0.58\\\":{\\\"layerDiffID\\\":\\\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\\\"}}}\",\n\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\"}]}]\",\n\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-empty-os.json",
    "content": "{\n  \"Id\": \"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\",\n  \"RepoTags\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1\"\n  ],\n  \"RepoDigests\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder@sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\"\n  ],\n  \"Parent\": \"\",\n  \"Comment\": \"\",\n  \"DockerVersion\": \"\",\n  \"Author\": \"\",\n  \"Config\": null,\n  \"Architecture\": \"\",\n  \"Os\": \"\",\n  \"Size\": 166797518,\n  \"GraphDriver\": {\n    \"Data\": null,\n    \"Name\": \"overlayfs\"\n  },\n  \"RootFS\": {},\n  \"Metadata\": {\n    \"LastTagTime\": \"2025-04-10T22:41:27.520294922Z\"\n  },\n  \"Descriptor\": {\n    \"mediaType\": \"application/vnd.oci.image.index.v1+json\",\n    \"digest\": \"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\",\n    \"size\": 513\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-manifest.json",
    "content": "{\n\t\"schemaVersion\": 2,\n\t\"mediaType\": \"application/vnd.oci.image.manifest.v1+json\",\n\t\"config\": {\n\t\t\"mediaType\": \"application/vnd.oci.image.config.v1+json\",\n\t\t\"digest\": \"sha256:ee382dc5c080aa6af5ea716041eaa4442c9d461520388627dfe51709c679043e\",\n\t\t\"size\": 849,\n\t\t\"platform\": {\n\t\t\t\"architecture\": \"amd64\",\n\t\t\t\"os\": \"linux\"\n\t\t}\n\t},\n\t\"layers\": [\n\t\t{\n\t\t\t\"mediaType\": \"application/vnd.oci.image.layer.v1.tar\",\n\t\t\t\"digest\": \"sha256:5caae51697b248b905dca1a4160864b0e1a15c300981736555cdce6567e8d477\",\n\t\t\t\"size\": 6656\n\t\t}\n\t]\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-no-descriptor.json",
    "content": "{\n  \"Id\": \"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\",\n  \"RepoTags\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1\"\n  ],\n  \"RepoDigests\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder@sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\"\n  ],\n  \"Parent\": \"\",\n  \"Comment\": \"\",\n  \"DockerVersion\": \"\",\n  \"Author\": \"\",\n  \"Config\": null,\n  \"Architecture\": \"\",\n  \"Os\": \"\",\n  \"Size\": 166797518,\n  \"GraphDriver\": {\n    \"Data\": null,\n    \"Name\": \"overlayfs\"\n  },\n  \"RootFS\": {},\n  \"Metadata\": {\n    \"LastTagTime\": \"2025-04-10T22:41:27.520294922Z\"\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-no-digest.json",
    "content": "{\n  \"Id\": \"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\",\n  \"RepoTags\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1\"\n  ],\n  \"Parent\": \"\",\n  \"Comment\": \"\",\n  \"DockerVersion\": \"\",\n  \"Author\": \"\",\n  \"Config\": null,\n  \"Architecture\": \"\",\n  \"Os\": \"\",\n  \"Size\": 166797518,\n  \"GraphDriver\": {\n    \"Data\": null,\n    \"Name\": \"overlayfs\"\n  },\n  \"RootFS\": {},\n  \"Metadata\": {\n    \"LastTagTime\": \"2025-04-10T22:41:27.520294922Z\"\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-non-default-os.json",
    "content": "{\n  \"Id\": \"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\",\n  \"RepoTags\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder:0.0.1\"\n  ],\n  \"RepoDigests\": [\n    \"ghcr.io/spring-io/spring-boot-cnb-test-builder@sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\"\n  ],\n  \"Parent\": \"\",\n  \"Comment\": \"\",\n  \"DockerVersion\": \"\",\n  \"Author\": \"\",\n  \"Config\": null,\n  \"Architecture\": \"\",\n  \"Os\": \"windows\",\n  \"Size\": 166797518,\n  \"GraphDriver\": {\n    \"Data\": null,\n    \"Name\": \"overlayfs\"\n  },\n  \"RootFS\": {},\n  \"Metadata\": {\n    \"LastTagTime\": \"2025-04-10T22:41:27.520294922Z\"\n  },\n  \"Descriptor\": {\n    \"mediaType\": \"application/vnd.oci.image.index.v1+json\",\n    \"digest\": \"sha256:21635a6b4880772f3fabbf8b660907fa38636558cf787cc26f1779fc4b4e2cba\",\n    \"size\": 513\n  }\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image-platform.json",
    "content": "{\n\t\"Id\": \"sha256:9b450bffdb05bcf660d464d0bfdf344ee6ca38e9b8de4f408c8080b0c9319349\",\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:latest\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buildpacks/cnb@sha256:915802bb193b66e3fc1a5a8f5584c6a1b6db05425e573887673bddcf426f1b90\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"2019-10-30T19:34:56.296666503Z\",\n\t\"Container\": \"84597380a7968131ab47dd1b8183a96dcfe9e1e4acff1efe5824dcd762184a67\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"84597380a796\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/sh\",\n\t\t\t\"-c\",\n\t\t\t\"#(nop) \",\n\t\t\t\"LABEL io.buildpacks.stack.id=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t}\n\t},\n\t\"DockerVersion\": \"18.09.6\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"cflinuxfs3 base image with buildpacks for Java, .NET, NodeJS, Python, Golang, PHP, HTTPD and NGINX\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true}],\\\"groups\\\":[{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"optional\\\":true}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\"}]}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run:full-cnb\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.5.0\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.1\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.5.0 (git sha: c9cfac75b49609524e1ea33f809c12071406547c)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.87\\\":{\\\"layerDiffID\\\":\\\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.0.114\\\":{\\\"layerDiffID\\\":\\\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\\\"}},\\\"org.cloudfoundry.conda\\\":{\\\"0.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.0.92\\\":{\\\"layerDiffID\\\":\\\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.51\\\":{\\\"layerDiffID\\\":\\\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.0.89\\\":{\\\"layerDiffID\\\":\\\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.2\\\":{\\\"layerDiffID\\\":\\\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\"}]}]}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.18\\\":{\\\"layerDiffID\\\":\\\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.66\\\":{\\\"layerDiffID\\\":\\\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.55\\\":{\\\"layerDiffID\\\":\\\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\"}]}]}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.48\\\":{\\\"layerDiffID\\\":\\\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.44\\\":{\\\"layerDiffID\\\":\\\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.0.40\\\":{\\\"layerDiffID\\\":\\\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\\\"}},\\\"org.cloudfoundry.httpd\\\":{\\\"0.0.21\\\":{\\\"layerDiffID\\\":\\\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.0.72\\\":{\\\"layerDiffID\\\":\\\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\\\"}},\\\"org.cloudfoundry.nginx\\\":{\\\"0.0.25\\\":{\\\"layerDiffID\\\":\\\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.85\\\":{\\\"layerDiffID\\\":\\\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v0.0.3\\\":{\\\"layerDiffID\\\":\\\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\"}]}]}},\\\"org.cloudfoundry.npm\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\\\"}},\\\"org.cloudfoundry.php\\\":{\\\"v0.0.0-RC1\\\":{\\\"layerDiffID\\\":\\\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]}]}},\\\"org.cloudfoundry.php-composer\\\":{\\\"0.0.16\\\":{\\\"layerDiffID\\\":\\\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\\\"}},\\\"org.cloudfoundry.php-dist\\\":{\\\"0.0.30\\\":{\\\"layerDiffID\\\":\\\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\\\"}},\\\"org.cloudfoundry.php-web\\\":{\\\"0.0.24\\\":{\\\"layerDiffID\\\":\\\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\\\"}},\\\"org.cloudfoundry.pip\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\\\"}},\\\"org.cloudfoundry.pipenv\\\":{\\\"0.0.38\\\":{\\\"layerDiffID\\\":\\\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\\\"}},\\\"org.cloudfoundry.python\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\"},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\"}]}]}},\\\"org.cloudfoundry.python-runtime\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.0.100\\\":{\\\"layerDiffID\\\":\\\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.0.97\\\":{\\\"layerDiffID\\\":\\\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.1.9\\\":{\\\"layerDiffID\\\":\\\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\\\"}},\\\"org.cloudfoundry.yarn\\\":{\\\"0.0.58\\\":{\\\"layerDiffID\\\":\\\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t}\n\t},\n\t\"Os\": \"linux\",\n  \"Architecture\": \"arm64\",\n  \"Variant\": \"v1\",\n  \"Size\": 1559461360,\n\t\"VirtualSize\": 1559461360,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/58e30cd9f3a4da4e0d30f20c3b50de7655e261fb3d32f04818f1bd960c1e8b6c/diff:/var/lib/docker/overlay2/ad95d738069aa405ff17a9ebb1fdc32f8490b0dd885c3ba3a28e2c3b25d64641/diff:/var/lib/docker/overlay2/74d2896cfe9efc6945ff18870a7213583b987ecf4306e189ff6b793f77af5dcd/diff:/var/lib/docker/overlay2/1052615e5c240724e10928048f735cc9e7a7676a9af5f173b895df57c6921a40/diff:/var/lib/docker/overlay2/b5a62216c4282e7568e84427073f096551977c8c6f80d3a04ebb04c25730edde/diff:/var/lib/docker/overlay2/016a36bf7d7d7258eca08da62c01e47bf8e531531f914dde7cae33e191ab2218/diff:/var/lib/docker/overlay2/a585012bf1cf9da0472b2bbe86c4919355593e1a02cf399a9b012928eb816bcd/diff:/var/lib/docker/overlay2/b4aa8b70bd59d7b7dc6d6fb2e655c2334dc8360c764232f83d036d1f241e3298/diff:/var/lib/docker/overlay2/5f4cab16092522163e2dba6587b48d53ee3b09c8778b0736999bc120dd3753b1/diff:/var/lib/docker/overlay2/90e60622603d230f238976f4d9f65797fc9f070df62b1d2ccad0cefe4e205b43/diff:/var/lib/docker/overlay2/c43877934a580e47cc477ed46e71246468d7b6d7151abc5f1a97bb1e8c8104cf/diff:/var/lib/docker/overlay2/8734b165cabb3ff234a08d488f622135aeae9b7347cf41273445ff7d07aa4565/diff:/var/lib/docker/overlay2/2743cd9d4b7da84925b1b530732dad97108fe77e75865de580255579ba2cdb92/diff:/var/lib/docker/overlay2/68308d057b24bbcde7a4880f5db0e653743debdcc0ff3e736d1776296c4168a1/diff:/var/lib/docker/overlay2/7a4411dc4ac1ed7a1da9aabf088985b8b131e0db047e513f9890eb9c001c1895/diff:/var/lib/docker/overlay2/7f7c262fea8dea5ec86507188848ea391354a76468b09ec93523920e18a400ea/diff:/var/lib/docker/overlay2/8b3bfa567fb956204ad866e49489dacd2fdf5fbfa4f9b05ed3668e1106a5383b/diff:/var/lib/docker/overlay2/31bbc4f1616a35b7ce157266e44513963502e30d836a8fd7b7ee18436a8c46cf/diff:/var/lib/docker/overlay2/149b8e9f1142cdf6dcdfe17ea286ec17197f1a329cf23d5c82958a2032facf54/diff:/var/lib/docker/overlay2/92fb1e680083eb8314c5310bf10ced63ec2b0a98afbf84cc5175a98b3d44507a/diff:/var/lib/docker/overlay2/175a35b6f7af6eb91ca500dbd3d7e798f6d174cf8549881ffe5eed8e92a70b9f/diff:/var/lib/docker/overlay2/48ca54bbd27f7df19acf2b6cc719d05dd3b63f8133038a55d216a4498d4dc913/diff:/var/lib/docker/overlay2/ffe3cc3b93c9030f9dcb0e64c258d1e554f1f0cf27a0f8d4e98bb7ece5ffe882/diff:/var/lib/docker/overlay2/1fb2d962bb27e95c40a9a2c1aa910ca847d186d04e3d7dcdf93967101cc30dde/diff:/var/lib/docker/overlay2/10b34138f9e9e8d70c684d0a564452b1309363441b9d7e048f75e0e1179411dc/diff:/var/lib/docker/overlay2/1d888c7e9c62c22ccda6478f03f3df4b43d43fa3b32a2c2fdc9345fdc7193cd9/diff:/var/lib/docker/overlay2/649fc275c002d7336b277365636e1c8e5651bb3ed1557806d26dd6dfa1d9119a/diff:/var/lib/docker/overlay2/4484c2c0ee4a20aa17017c8cd54c842c876fea32afb297e88614d759ec5410dc/diff:/var/lib/docker/overlay2/bd5f374e0ea6749c90535d778f2689c076b7290ad9d3f050af0a40c9626fdea4/diff:/var/lib/docker/overlay2/c6ba97531b15be65bccaf7ebc866d8bc0b88ce838b224aceb196a55824b289a5/diff:/var/lib/docker/overlay2/6c65fab249fe652cd20a6391b2e0786379b6d2c7d4fde02914dfb4fac84035bd/diff:/var/lib/docker/overlay2/f391b54493024e0183331b8ec7835107bc1b84b8a6e77d852f5357724eb940ff/diff:/var/lib/docker/overlay2/8044f9e3ceb529c80531fa2fe52ad550286f788e69843f235e7d756b90c213b8/diff:/var/lib/docker/overlay2/7d3b5539c46c9f0e7c4f6f733f435d1bf6428a8ca81ba71f4da1031cef58aa6c/diff:/var/lib/docker/overlay2/b8080b36b0ddec4e4d738571ddf9d89815f6a95a555d282cfebb73519b4835a0/diff:/var/lib/docker/overlay2/8a737007d5862aa43119254122eb7050c8bd110a3b653c8d6afca23e76fc4042/diff:/var/lib/docker/overlay2/3bb8f3670831e2031be2173381caf02874ad72e664716a990a330bcc3454f4a2/diff:/var/lib/docker/overlay2/cbd675efde19ccac72d3566404e5df8b152a9063c1668d8154711c7db398f852/diff:/var/lib/docker/overlay2/84fb9095136cb645f7f15aeeeba1db6fae3999cb48a559daf8dd46bf3befbeba/diff:/var/lib/docker/overlay2/cbc51912822c4a3fb8624e0cf678e5dedeb76dc2fa0e5bc56f3cbfbfefb26d68/diff:/var/lib/docker/overlay2/d08d5bdcf39aaf46bdf1e0f4576bb64931af646213ff350065b4d306e00f7e28/diff:/var/lib/docker/overlay2/cf180c218fe181bdf836065c5e85103816ea9e8dbb8ab54fb311209c33455eb2/diff:/var/lib/docker/overlay2/b0aef801fd38973eaf116001e05e7c3f8e2eb58ccc7ed37a4bd8d4fcc2ad172b/diff:/var/lib/docker/overlay2/f73c585ae34bd962e1fee2c3e2d95d47b9daf68b23cf469fb13bc3282cf77238/diff:/var/lib/docker/overlay2/c071c8471b26e55a90b6573a21c581dec43b6c7683a3fe87cb33a0734c83342a/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:733a8e5ce32984099ef675fce04730f6e2a6dcfdf5bd292fea01a8f936265342\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/image.json",
    "content": "{\n\t\"Id\": \"sha256:9b450bffdb05bcf660d464d0bfdf344ee6ca38e9b8de4f408c8080b0c9319349\",\n\t\"Descriptor\": {\n\t\t\"mediaType\": \"application/vnd.oci.image.manifest.v1+json\",\n\t\t\"digest\": \"sha256:c0537ff6a5218ef531ece93d4984efc99bbf3f7497c0a7726c88e2bb7584dc96\",\n\t\t\"size\": 424,\n\t\t\"urls\": [\n\t\t\t\"https://example.com\"\n\t\t],\n\t\t\"annotations\": {\n\t\t\t\"com.docker.official-images.bashbrew.arch\": \"amd64\",\n\t\t\t\"org.opencontainers.image.version\": \"24.04\"\n\t\t},\n\t\t\"data\": null,\n\t\t\"platform\": {\n\t\t\t\"architecture\": \"arm\",\n\t\t\t\"os\": \"windows\",\n\t\t\t\"os.version\": \"10.0.19041.1165\",\n\t\t\t\"os.features\": [\n\t\t\t],\n\t\t\t\"variant\": \"v7\"\n\t\t},\n\t\t\"artifactType\": null\n\t},\n\t\"RepoTags\": [\n\t\t\"paketo-buildpacks/cnb:latest\"\n\t],\n\t\"RepoDigests\": [\n\t\t\"paketo-buildpacks/cnb@sha256:915802bb193b66e3fc1a5a8f5584c6a1b6db05425e573887673bddcf426f1b90\"\n\t],\n\t\"Parent\": \"\",\n\t\"Comment\": \"\",\n\t\"Created\": \"2019-10-30T19:34:56.296666503Z\",\n\t\"Container\": \"84597380a7968131ab47dd1b8183a96dcfe9e1e4acff1efe5824dcd762184a67\",\n\t\"ContainerConfig\": {\n\t\t\"Hostname\": \"84597380a796\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"/bin/sh\",\n\t\t\t\"-c\",\n\t\t\t\"#(nop) \",\n\t\t\t\"LABEL io.buildpacks.stack.id=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t}\n\t},\n\t\"DockerVersion\": \"18.09.6\",\n\t\"Author\": \"\",\n\t\"Config\": {\n\t\t\"Hostname\": \"\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"vcap\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": false,\n\t\t\"AttachStderr\": false,\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"CNB_USER_ID=2000\",\n\t\t\t\"CNB_GROUP_ID=2000\",\n\t\t\t\"CNB_STACK_ID=org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t],\n\t\t\"Cmd\": null,\n\t\t\"Image\": \"sha256:523c8ade6e06f814469b2cf04c8045a74becee17088955f2657958476d3fba1f\",\n\t\t\"Volumes\": null,\n\t\t\"WorkingDir\": \"/layers\",\n\t\t\"Entrypoint\": null,\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"io.buildpacks.builder.metadata\": \"{\\\"description\\\":\\\"cflinuxfs3 base image with buildpacks for Java, .NET, NodeJS, Python, Golang, PHP, HTTPD and NGINX\\\",\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"latest\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\",\\\"latest\\\":true}],\\\"groups\\\":[{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"version\\\":\\\"v1.0.87\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\",\\\"version\\\":\\\"v1.0.53\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"version\\\":\\\"v1.0.114\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\",\\\"version\\\":\\\"v1.0.72\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"version\\\":\\\"v1.1.9\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"version\\\":\\\"v1.0.97\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"version\\\":\\\"v1.0.89\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"version\\\":\\\"v1.0.37\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"version\\\":\\\"v1.0.92\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"version\\\":\\\"v1.0.40\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"version\\\":\\\"v1.0.94\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"version\\\":\\\"v1.0.100\\\",\\\"optional\\\":true}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\",\\\"version\\\":\\\"v0.0.3\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\",\\\"version\\\":\\\"v0.0.1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\",\\\"version\\\":\\\"v0.0.2\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\",\\\"version\\\":\\\"v0.0.0-RC1\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\"}]},{\\\"buildpacks\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\"}]}],\\\"stack\\\":{\\\"runImage\\\":{\\\"image\\\":\\\"cloudfoundry/run:full-cnb\\\",\\\"mirrors\\\":null}},\\\"lifecycle\\\":{\\\"version\\\":\\\"0.5.0\\\",\\\"api\\\":{\\\"buildpack\\\":\\\"0.2\\\",\\\"platform\\\":\\\"0.1\\\"}},\\\"createdBy\\\":{\\\"name\\\":\\\"Pack CLI\\\",\\\"version\\\":\\\"v0.5.0 (git sha: c9cfac75b49609524e1ea33f809c12071406547c)\\\"}}\",\n\t\t\t\"io.buildpacks.buildpack.layers\": \"{\\\"org.cloudfoundry.archiveexpanding\\\":{\\\"v1.0.87\\\":{\\\"layerDiffID\\\":\\\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\\\"}},\\\"org.cloudfoundry.azureapplicationinsights\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\\\"}},\\\"org.cloudfoundry.buildsystem\\\":{\\\"v1.0.114\\\":{\\\"layerDiffID\\\":\\\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\\\"}},\\\"org.cloudfoundry.conda\\\":{\\\"0.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\\\"}},\\\"org.cloudfoundry.debug\\\":{\\\"v1.0.92\\\":{\\\"layerDiffID\\\":\\\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\\\"}},\\\"org.cloudfoundry.dep\\\":{\\\"0.0.51\\\":{\\\"layerDiffID\\\":\\\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\\\"}},\\\"org.cloudfoundry.distzip\\\":{\\\"v1.0.89\\\":{\\\"layerDiffID\\\":\\\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\\\"}},\\\"org.cloudfoundry.dotnet-core\\\":{\\\"v0.0.2\\\":{\\\"layerDiffID\\\":\\\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-runtime\\\",\\\"version\\\":\\\"0.0.66\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-aspnet\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-sdk\\\",\\\"version\\\":\\\"0.0.55\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-build\\\",\\\"version\\\":\\\"0.0.18\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core-conf\\\",\\\"version\\\":\\\"0.0.57\\\"}]}]}},\\\"org.cloudfoundry.dotnet-core-aspnet\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\\\"}},\\\"org.cloudfoundry.dotnet-core-build\\\":{\\\"0.0.18\\\":{\\\"layerDiffID\\\":\\\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\\\"}},\\\"org.cloudfoundry.dotnet-core-conf\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\\\"}},\\\"org.cloudfoundry.dotnet-core-runtime\\\":{\\\"0.0.66\\\":{\\\"layerDiffID\\\":\\\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\\\"}},\\\"org.cloudfoundry.dotnet-core-sdk\\\":{\\\"0.0.55\\\":{\\\"layerDiffID\\\":\\\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\\\"}},\\\"org.cloudfoundry.go\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.go-mod\\\",\\\"version\\\":\\\"0.0.44\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go-compiler\\\",\\\"version\\\":\\\"0.0.48\\\"},{\\\"id\\\":\\\"org.cloudfoundry.dep\\\",\\\"version\\\":\\\"0.0.51\\\"}]}]}},\\\"org.cloudfoundry.go-compiler\\\":{\\\"0.0.48\\\":{\\\"layerDiffID\\\":\\\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\\\"}},\\\"org.cloudfoundry.go-mod\\\":{\\\"0.0.44\\\":{\\\"layerDiffID\\\":\\\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\\\"}},\\\"org.cloudfoundry.googlestackdriver\\\":{\\\"v1.0.40\\\":{\\\"layerDiffID\\\":\\\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\\\"}},\\\"org.cloudfoundry.httpd\\\":{\\\"0.0.21\\\":{\\\"layerDiffID\\\":\\\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\\\"}},\\\"org.cloudfoundry.jdbc\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\\\"}},\\\"org.cloudfoundry.jmx\\\":{\\\"v1.0.94\\\":{\\\"layerDiffID\\\":\\\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\\\"}},\\\"org.cloudfoundry.jvmapplication\\\":{\\\"v1.0.72\\\":{\\\"layerDiffID\\\":\\\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\\\"}},\\\"org.cloudfoundry.nginx\\\":{\\\"0.0.25\\\":{\\\"layerDiffID\\\":\\\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\\\"}},\\\"org.cloudfoundry.node-engine\\\":{\\\"0.0.85\\\":{\\\"layerDiffID\\\":\\\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\\\"}},\\\"org.cloudfoundry.nodejs\\\":{\\\"v0.0.3\\\":{\\\"layerDiffID\\\":\\\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.yarn\\\",\\\"version\\\":\\\"0.0.58\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.node-engine\\\",\\\"version\\\":\\\"0.0.85\\\"},{\\\"id\\\":\\\"org.cloudfoundry.npm\\\",\\\"version\\\":\\\"0.0.53\\\"}]}]}},\\\"org.cloudfoundry.npm\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\\\"}},\\\"org.cloudfoundry.openjdk\\\":{\\\"v1.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\\\"}},\\\"org.cloudfoundry.php\\\":{\\\"v0.0.0-RC1\\\":{\\\"layerDiffID\\\":\\\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\",\\\"version\\\":\\\"0.0.21\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php-dist\\\",\\\"version\\\":\\\"0.0.30\\\"},{\\\"id\\\":\\\"org.cloudfoundry.php-composer\\\",\\\"version\\\":\\\"0.0.16\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\",\\\"version\\\":\\\"0.0.25\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.php-web\\\",\\\"version\\\":\\\"0.0.24\\\"}]}]}},\\\"org.cloudfoundry.php-composer\\\":{\\\"0.0.16\\\":{\\\"layerDiffID\\\":\\\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\\\"}},\\\"org.cloudfoundry.php-dist\\\":{\\\"0.0.30\\\":{\\\"layerDiffID\\\":\\\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\\\"}},\\\"org.cloudfoundry.php-web\\\":{\\\"0.0.24\\\":{\\\"layerDiffID\\\":\\\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\\\"}},\\\"org.cloudfoundry.pip\\\":{\\\"0.0.53\\\":{\\\"layerDiffID\\\":\\\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\\\"}},\\\"org.cloudfoundry.pipenv\\\":{\\\"0.0.38\\\":{\\\"layerDiffID\\\":\\\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\\\"}},\\\"org.cloudfoundry.procfile\\\":{\\\"v1.0.37\\\":{\\\"layerDiffID\\\":\\\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\\\"}},\\\"org.cloudfoundry.python\\\":{\\\"v0.0.1\\\":{\\\"layerDiffID\\\":\\\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\\\",\\\"order\\\":[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python-runtime\\\",\\\"version\\\":\\\"0.0.57\\\"},{\\\"id\\\":\\\"org.cloudfoundry.pipenv\\\",\\\"version\\\":\\\"0.0.38\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.pip\\\",\\\"version\\\":\\\"0.0.53\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.conda\\\",\\\"version\\\":\\\"0.0.37\\\"}]}]}},\\\"org.cloudfoundry.python-runtime\\\":{\\\"0.0.57\\\":{\\\"layerDiffID\\\":\\\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\\\"}},\\\"org.cloudfoundry.springautoreconfiguration\\\":{\\\"v1.0.100\\\":{\\\"layerDiffID\\\":\\\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\\\"}},\\\"org.cloudfoundry.springboot\\\":{\\\"v1.0.97\\\":{\\\"layerDiffID\\\":\\\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\\\"}},\\\"org.cloudfoundry.tomcat\\\":{\\\"v1.1.9\\\":{\\\"layerDiffID\\\":\\\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\\\"}},\\\"org.cloudfoundry.yarn\\\":{\\\"0.0.58\\\":{\\\"layerDiffID\\\":\\\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\\\"}}}\",\n\t\t\t\"io.buildpacks.buildpack.order\": \"[{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.archiveexpanding\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.openjdk\\\"},{\\\"id\\\":\\\"org.cloudfoundry.buildsystem\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jvmapplication\\\"},{\\\"id\\\":\\\"org.cloudfoundry.tomcat\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springboot\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.distzip\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.procfile\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.azureapplicationinsights\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.debug\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.googlestackdriver\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jdbc\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.jmx\\\",\\\"optional\\\":true},{\\\"id\\\":\\\"org.cloudfoundry.springautoreconfiguration\\\",\\\"optional\\\":true}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nodejs\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.python\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.go\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.dotnet-core\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.php\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.httpd\\\"}]},{\\\"group\\\":[{\\\"id\\\":\\\"org.cloudfoundry.nginx\\\"}]}]\",\n\t\t\t\"io.buildpacks.stack.id\": \"org.cloudfoundry.stacks.cflinuxfs3\"\n\t\t}\n\t},\n\t\"Os\": \"linux\",\n  \"Architecture\": \"amd64\",\n  \"Variant\": \"v1\",\n  \"Size\": 1559461360,\n\t\"VirtualSize\": 1559461360,\n\t\"GraphDriver\": {\n\t\t\"Data\": {\n\t\t\t\"LowerDir\": \"/var/lib/docker/overlay2/58e30cd9f3a4da4e0d30f20c3b50de7655e261fb3d32f04818f1bd960c1e8b6c/diff:/var/lib/docker/overlay2/ad95d738069aa405ff17a9ebb1fdc32f8490b0dd885c3ba3a28e2c3b25d64641/diff:/var/lib/docker/overlay2/74d2896cfe9efc6945ff18870a7213583b987ecf4306e189ff6b793f77af5dcd/diff:/var/lib/docker/overlay2/1052615e5c240724e10928048f735cc9e7a7676a9af5f173b895df57c6921a40/diff:/var/lib/docker/overlay2/b5a62216c4282e7568e84427073f096551977c8c6f80d3a04ebb04c25730edde/diff:/var/lib/docker/overlay2/016a36bf7d7d7258eca08da62c01e47bf8e531531f914dde7cae33e191ab2218/diff:/var/lib/docker/overlay2/a585012bf1cf9da0472b2bbe86c4919355593e1a02cf399a9b012928eb816bcd/diff:/var/lib/docker/overlay2/b4aa8b70bd59d7b7dc6d6fb2e655c2334dc8360c764232f83d036d1f241e3298/diff:/var/lib/docker/overlay2/5f4cab16092522163e2dba6587b48d53ee3b09c8778b0736999bc120dd3753b1/diff:/var/lib/docker/overlay2/90e60622603d230f238976f4d9f65797fc9f070df62b1d2ccad0cefe4e205b43/diff:/var/lib/docker/overlay2/c43877934a580e47cc477ed46e71246468d7b6d7151abc5f1a97bb1e8c8104cf/diff:/var/lib/docker/overlay2/8734b165cabb3ff234a08d488f622135aeae9b7347cf41273445ff7d07aa4565/diff:/var/lib/docker/overlay2/2743cd9d4b7da84925b1b530732dad97108fe77e75865de580255579ba2cdb92/diff:/var/lib/docker/overlay2/68308d057b24bbcde7a4880f5db0e653743debdcc0ff3e736d1776296c4168a1/diff:/var/lib/docker/overlay2/7a4411dc4ac1ed7a1da9aabf088985b8b131e0db047e513f9890eb9c001c1895/diff:/var/lib/docker/overlay2/7f7c262fea8dea5ec86507188848ea391354a76468b09ec93523920e18a400ea/diff:/var/lib/docker/overlay2/8b3bfa567fb956204ad866e49489dacd2fdf5fbfa4f9b05ed3668e1106a5383b/diff:/var/lib/docker/overlay2/31bbc4f1616a35b7ce157266e44513963502e30d836a8fd7b7ee18436a8c46cf/diff:/var/lib/docker/overlay2/149b8e9f1142cdf6dcdfe17ea286ec17197f1a329cf23d5c82958a2032facf54/diff:/var/lib/docker/overlay2/92fb1e680083eb8314c5310bf10ced63ec2b0a98afbf84cc5175a98b3d44507a/diff:/var/lib/docker/overlay2/175a35b6f7af6eb91ca500dbd3d7e798f6d174cf8549881ffe5eed8e92a70b9f/diff:/var/lib/docker/overlay2/48ca54bbd27f7df19acf2b6cc719d05dd3b63f8133038a55d216a4498d4dc913/diff:/var/lib/docker/overlay2/ffe3cc3b93c9030f9dcb0e64c258d1e554f1f0cf27a0f8d4e98bb7ece5ffe882/diff:/var/lib/docker/overlay2/1fb2d962bb27e95c40a9a2c1aa910ca847d186d04e3d7dcdf93967101cc30dde/diff:/var/lib/docker/overlay2/10b34138f9e9e8d70c684d0a564452b1309363441b9d7e048f75e0e1179411dc/diff:/var/lib/docker/overlay2/1d888c7e9c62c22ccda6478f03f3df4b43d43fa3b32a2c2fdc9345fdc7193cd9/diff:/var/lib/docker/overlay2/649fc275c002d7336b277365636e1c8e5651bb3ed1557806d26dd6dfa1d9119a/diff:/var/lib/docker/overlay2/4484c2c0ee4a20aa17017c8cd54c842c876fea32afb297e88614d759ec5410dc/diff:/var/lib/docker/overlay2/bd5f374e0ea6749c90535d778f2689c076b7290ad9d3f050af0a40c9626fdea4/diff:/var/lib/docker/overlay2/c6ba97531b15be65bccaf7ebc866d8bc0b88ce838b224aceb196a55824b289a5/diff:/var/lib/docker/overlay2/6c65fab249fe652cd20a6391b2e0786379b6d2c7d4fde02914dfb4fac84035bd/diff:/var/lib/docker/overlay2/f391b54493024e0183331b8ec7835107bc1b84b8a6e77d852f5357724eb940ff/diff:/var/lib/docker/overlay2/8044f9e3ceb529c80531fa2fe52ad550286f788e69843f235e7d756b90c213b8/diff:/var/lib/docker/overlay2/7d3b5539c46c9f0e7c4f6f733f435d1bf6428a8ca81ba71f4da1031cef58aa6c/diff:/var/lib/docker/overlay2/b8080b36b0ddec4e4d738571ddf9d89815f6a95a555d282cfebb73519b4835a0/diff:/var/lib/docker/overlay2/8a737007d5862aa43119254122eb7050c8bd110a3b653c8d6afca23e76fc4042/diff:/var/lib/docker/overlay2/3bb8f3670831e2031be2173381caf02874ad72e664716a990a330bcc3454f4a2/diff:/var/lib/docker/overlay2/cbd675efde19ccac72d3566404e5df8b152a9063c1668d8154711c7db398f852/diff:/var/lib/docker/overlay2/84fb9095136cb645f7f15aeeeba1db6fae3999cb48a559daf8dd46bf3befbeba/diff:/var/lib/docker/overlay2/cbc51912822c4a3fb8624e0cf678e5dedeb76dc2fa0e5bc56f3cbfbfefb26d68/diff:/var/lib/docker/overlay2/d08d5bdcf39aaf46bdf1e0f4576bb64931af646213ff350065b4d306e00f7e28/diff:/var/lib/docker/overlay2/cf180c218fe181bdf836065c5e85103816ea9e8dbb8ab54fb311209c33455eb2/diff:/var/lib/docker/overlay2/b0aef801fd38973eaf116001e05e7c3f8e2eb58ccc7ed37a4bd8d4fcc2ad172b/diff:/var/lib/docker/overlay2/f73c585ae34bd962e1fee2c3e2d95d47b9daf68b23cf469fb13bc3282cf77238/diff:/var/lib/docker/overlay2/c071c8471b26e55a90b6573a21c581dec43b6c7683a3fe87cb33a0734c83342a/diff\",\n\t\t\t\"MergedDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/merged\",\n\t\t\t\"UpperDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/diff\",\n\t\t\t\"WorkDir\": \"/var/lib/docker/overlay2/41ced64ea40f3382f7a475030a5bc89b9c86e2a03d43031c5eba3c5c72616c2b/work\"\n\t\t},\n\t\t\"Name\": \"overlay2\"\n\t},\n\t\"RootFS\": {\n\t\t\"Type\": \"layers\",\n\t\t\"Layers\": [\n\t\t\t\"sha256:733a8e5ce32984099ef675fce04730f6e2a6dcfdf5bd292fea01a8f936265342\",\n\t\t\t\"sha256:7755b972f0b4f49de73ef5114fb3ba9c69d80f217e80da99f56f0d0a5dcb3d70\",\n\t\t\t\"sha256:8f0b2d09ab4b38530a1630403967d11a601e56e02e79d3f56370d34fd071fe38\",\n\t\t\t\"sha256:8debe4b6b4290dbbfecea9edea61c22fb455e69e3cbc7d63b17f8e1ab8ea669b\",\n\t\t\t\"sha256:0c6ddab305e5452850f3c09fe15310dff8dc7221702d736dc7705882c1df9658\",\n\t\t\t\"sha256:a9527973bb5d7ccdf88b5be8eb81e024094be1709df659af3127865463c1c188\",\n\t\t\t\"sha256:480cd420e43c6895240c87c88969b87417549c02393cde1b6f71a3a3d5a2a620\",\n\t\t\t\"sha256:391d950d763a33d8ae0373f218aa59907599f51e42cd864129591887e1291034\",\n\t\t\t\"sha256:5b3ec0a6ed9e3de93bb082151f56b1cde5d7e31f2809039a1b5b55a5052fe873\",\n\t\t\t\"sha256:ef935546e2c99da3e8962f2eb3cd6813e9e9a8b19bc8d15b56d1cac37f0342d5\",\n\t\t\t\"sha256:6d644992d62bd09a2bbf490b7fe3aa1e35e6d0d2479583c2decec7092f193310\",\n\t\t\t\"sha256:59d817c36a25078c8ec1f6de0d8336aec598037f89708ed13dbf661557a25084\",\n\t\t\t\"sha256:6636ce01d12372e56a89ec77ea8d9ed510f8c701df1220750add4613764c05a4\",\n\t\t\t\"sha256:96c7f369c29bbf11b971e4dbb6473e8991b666f9de046a414317634eb0a25d2a\",\n\t\t\t\"sha256:3544ba1fa82d1e89619ed04c2485fab3445b1603959d224792d1183dd658033d\",\n\t\t\t\"sha256:12d99406b52b526af152628cd72ba6eacf5d18484dc79cfdacd4b38a21620a2b\",\n\t\t\t\"sha256:3b3cda9eceb0fca56c274e3be93daf53f59501e6b3628fabbaea8ea416eb757a\",\n\t\t\t\"sha256:27ad0fc48c381eb77f69b4e80edccb4d8a2399f5cebd5a8c5a3e1c32313343a6\",\n\t\t\t\"sha256:52845fb94361dad36cc4136e49b92c79ca59c16c579e2f51df0c58ba355c4367\",\n\t\t\t\"sha256:7bf3a57229276fb913155b077d00a18ec6cba92c7f062728ca1c3bc3503c0b55\",\n\t\t\t\"sha256:e5df92d3db931488225ca9f7290de0334225d4bd7c48fc2dcd380d0921bb6680\",\n\t\t\t\"sha256:290ac64fbae3288821551371c8dda38fcf5dfa063a54cb270dcc395a090f5173\",\n\t\t\t\"sha256:996aee90e29ed78d80a5a0c0e50d60a732a18fddae06f87b68bef183beddd2c4\",\n\t\t\t\"sha256:30f6a316d4da01d694d8c17aa84b37f468cccc7184248e255486eb3095ebb87c\",\n\t\t\t\"sha256:c694476a7241ba4e4a0663606d4d6eec7ed8624252c010fbef2713968e8f9436\",\n\t\t\t\"sha256:ab9aaff2160873663388faea6d987cd8f2b5935137b81c64fde145bf2a330d54\",\n\t\t\t\"sha256:e1f3ab860045b96235cbc1b89a3e73add955a303eb42905b570b6012b73b9184\",\n\t\t\t\"sha256:0b260d90d097379d4351132b45110d013b98f4a335795baeb95788fcebcb7f3c\",\n\t\t\t\"sha256:f0f5ecd72b4e0a38d3ad73b5756d8f209955932e9615715502a61dffe56f401a\",\n\t\t\t\"sha256:b4cd790490e41c808e8d65f9ac8f2e58c79bc1a9919a713c4519e77b26dc2053\",\n\t\t\t\"sha256:16b88c0e7f950c32c7496117d1efad90a8557a2badcb267d99a19676b1f0b76a\",\n\t\t\t\"sha256:49d36ba00b17fb605f374ca7877ae129678de925d10fd1955f07c2b6f74dd1c9\",\n\t\t\t\"sha256:b31d189a88ca43fee6077c25bcb623582d569193ed6ac11b4e5623558911e3de\",\n\t\t\t\"sha256:3ecfd2822cf64c609c9c8489e2accfbc0b1de0f2a3637ff1b5d30768fb34b40c\",\n\t\t\t\"sha256:a7f09c3e09b29c5503962a068f29e8726cb91d1dbce2fab688aee0a98189b2be\",\n\t\t\t\"sha256:3d12e651068a0ff19afdd568b5d14ee5292f849542b31d6c9b099a09344e1f4d\",\n\t\t\t\"sha256:f01e41975a9335f5983021b081bc700e46b85efb262670223c4db61eea0a3ebd\",\n\t\t\t\"sha256:2b1b655bb8752f631e786c4c55670315d8569acccfe26402942977c216f2803a\",\n\t\t\t\"sha256:0943c634f5c24311ebdeca6fef5682a4a374c89a831700d188bff7f987470004\",\n\t\t\t\"sha256:9a183e56c86d376b408bdf922746d0a657f62b0e18c7c8f82a496b87710c576f\",\n\t\t\t\"sha256:d919f3c2f534ddbb0b6057f82bca36051ce80a2a9cd3016c320ae276884311f5\",\n\t\t\t\"sha256:108a3eb288f8094aab6ffd822c593902e48e85c8a37b7da2bd21b15f785d92c5\",\n\t\t\t\"sha256:f8b5dcfa1d082af23bb2b2c08526131921329d48d1614d9f2f163a997176087a\",\n\t\t\t\"sha256:ee13e75c33e0af49fbf6c3aaa5bbd102fc468c2d554c4f94763d35a33964dfe4\",\n\t\t\t\"sha256:2571abab1776d4c2e427fba10d61531afff2ab0789f89ef46ce925b6a5d98e0f\",\n\t\t\t\"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef\"\n\t\t]\n\t},\n\t\"Metadata\": {\n\t\t\"LastTagTime\": \"0001-01-01T00:00:00Z\"\n\t}\n}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/manifest.json",
    "content": "[\n\t{\n\t\t\"Config\": \"fdc5f384ea0818dd99462e53bf2088a0fa42ad4de5878fdf078935192604da6d.json\",\n\t\t\"Layers\": [\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"\",\n\t\t\t\"/e39b9186d3d35693645f81db5ec6ced177c4da2d26f71a55de7834fc3b161a60.tar\",\n\t\t\t\"/791b31c608b369f0d6e23aaf55dd6bae76ffd92292afd3eb4dd35f8a389636fb.tar\",\n\t\t\t\"/66d1ab676a2ecb3852104177d2fd9499d90bbbd97984bccb62180502e15a7086.tar\",\n\t\t\t\"/b5787d8d30d02769ebbe6b1ac32d37764feef3cd5cdc68aeffd72bb27d1886e5.tar\"\n\t\t],\n\t\t\"RepoTags\": [\n\t\t\t\"pack.local/builder/6b7874626575656b6162:latest\"\n\t\t]\n\t}\n]\n\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/docker/type/minimal-image-config.json",
    "content": "{\n\t\"Hostname\": \"\",\n\t\"Domainname\": \"\",\n\t\"User\": \"\",\n\t\"AttachStdin\": false,\n\t\"AttachStdout\": false,\n\t\"AttachStderr\": false,\n\t\"Tty\": false,\n\t\"OpenStdin\": false,\n\t\"StdinOnce\": false,\n\t\"Env\": null,\n\t\"Cmd\": null,\n\t\"Image\": \"\",\n\t\"Volumes\": null,\n\t\"WorkingDir\": \"\",\n\t\"Entrypoint\": null,\n\t\"OnBuild\": null,\n\t\"Labels\": null\n}"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/json/stream.json",
    "content": "{\n\t\"status\": \"Pulling from paketo-buildpacks/cnb\",\n\t\"id\": \"base\"\n}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Pulling fs layer\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Waiting\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":487,\"total\":850},\"progress\":\"[============================\\u003e                      ]     487B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":485,\"total\":35355},\"progress\":\"[\\u003e                                                  ]     485B/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":35355,\"total\":35355},\"progress\":\"[==================================================\\u003e]  35.35kB/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":277600,\"total\":26683298},\"progress\":\"[\\u003e                                                  ]  277.6kB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":850,\"total\":850},\"progress\":\"[==================================================\\u003e]     850B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2218692,\"total\":26683298},\"progress\":\"[====\\u003e                                              ]  2.219MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4160196,\"total\":26683298},\"progress\":\"[=======\\u003e                                           ]   4.16MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6109892,\"total\":26683298},\"progress\":\"[===========\\u003e                                       ]   6.11MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":7772868,\"total\":26683298},\"progress\":\"[==============\\u003e                                    ]  7.773MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":9444036,\"total\":26683298},\"progress\":\"[=================\\u003e                                 ]  9.444MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":163,\"total\":163},\"progress\":\"[==================================================\\u003e]     163B/163B\",\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":10832580,\"total\":26683298},\"progress\":\"[====================\\u003e                              ]  10.83MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":531179,\"total\":88111129},\"progress\":\"[\\u003e                                                  ]  531.2kB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11668164,\"total\":26683298},\"progress\":\"[=====================\\u003e                             ]  11.67MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1604331,\"total\":88111129},\"progress\":\"[\\u003e                                                  ]  1.604MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":12495556,\"total\":26683298},\"progress\":\"[=======================\\u003e                           ]   12.5MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3209963,\"total\":88111129},\"progress\":\"[=\\u003e                                                 ]   3.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13331140,\"total\":26683298},\"progress\":\"[========================\\u003e                          ]  13.33MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4283115,\"total\":88111129},\"progress\":\"[==\\u003e                                                ]  4.283MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":14166724,\"total\":26683298},\"progress\":\"[==========================\\u003e                        ]  14.17MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5888747,\"total\":88111129},\"progress\":\"[===\\u003e                                               ]  5.889MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":15280836,\"total\":26683298},\"progress\":\"[============================\\u003e                      ]  15.28MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":14318,\"total\":1391657},\"progress\":\"[\\u003e                                                  ]  14.32kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6961899,\"total\":88111129},\"progress\":\"[===\\u003e                                               ]  6.962MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16116420,\"total\":26683298},\"progress\":\"[==============================\\u003e                    ]  16.12MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":936688,\"total\":1391657},\"progress\":\"[=================================\\u003e                 ]  936.7kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":8022763,\"total\":88111129},\"progress\":\"[====\\u003e                                              ]  8.023MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16931524,\"total\":26683298},\"progress\":\"[===============================\\u003e                   ]  16.93MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":18045636,\"total\":26683298},\"progress\":\"[=================================\\u003e                 ]  18.05MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":9632491,\"total\":88111129},\"progress\":\"[=====\\u003e                                             ]  9.632MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":10709739,\"total\":88111129},\"progress\":\"[======\\u003e                                            ]  10.71MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":19143364,\"total\":26683298},\"progress\":\"[===================================\\u003e               ]  19.14MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11778795,\"total\":88111129},\"progress\":\"[======\\u003e                                            ]  11.78MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":20249284,\"total\":26683298},\"progress\":\"[=====================================\\u003e             ]  20.25MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":12851947,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  12.85MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":21072580,\"total\":26683298},\"progress\":\"[=======================================\\u003e           ]  21.07MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":14133,\"total\":1328346},\"progress\":\"[\\u003e                                                  ]  14.13kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13933291,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  13.93MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":21908164,\"total\":26683298},\"progress\":\"[=========================================\\u003e         ]  21.91MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":973511,\"total\":1328346},\"progress\":\"[====================================\\u003e              ]  973.5kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":15014635,\"total\":88111129},\"progress\":\"[========\\u003e                                          ]  15.01MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":22747844,\"total\":26683298},\"progress\":\"[==========================================\\u003e        ]  22.75MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16075499,\"total\":88111129},\"progress\":\"[=========\\u003e                                         ]  16.08MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23575236,\"total\":26683298},\"progress\":\"[============================================\\u003e      ]  23.58MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":24414916,\"total\":26683298},\"progress\":\"[=============================================\\u003e     ]  24.41MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":17132267,\"total\":88111129},\"progress\":\"[=========\\u003e                                         ]  17.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":25250500,\"total\":26683298},\"progress\":\"[===============================================\\u003e   ]  25.25MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":18213611,\"total\":88111129},\"progress\":\"[==========\\u003e                                        ]  18.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":26073796,\"total\":26683298},\"progress\":\"[================================================\\u003e  ]  26.07MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":19286763,\"total\":88111129},\"progress\":\"[==========\\u003e                                        ]  19.29MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":490,\"total\":4478},\"progress\":\"[=====\\u003e                                             ]     490B/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4478,\"total\":4478},\"progress\":\"[==================================================\\u003e]  4.478kB/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":20892395,\"total\":88111129},\"progress\":\"[===========\\u003e                                       ]  20.89MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":294912,\"total\":26683298},\"progress\":\"[\\u003e                                                  ]  294.9kB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23050987,\"total\":88111129},\"progress\":\"[=============\\u003e                                     ]  23.05MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":2654208,\"total\":26683298},\"progress\":\"[====\\u003e                                              ]  2.654MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":25205483,\"total\":88111129},\"progress\":\"[==============\\u003e                                    ]  25.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":6193152,\"total\":26683298},\"progress\":\"[===========\\u003e                                       ]  6.193MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":27355883,\"total\":88111129},\"progress\":\"[===============\\u003e                                   ]  27.36MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":8552448,\"total\":26683298},\"progress\":\"[================\\u003e                                  ]  8.552MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":197,\"total\":197},\"progress\":\"[==================================================\\u003e]     197B/197B\",\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":11796480,\"total\":26683298},\"progress\":\"[======================\\u003e                            ]   11.8MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":29510379,\"total\":88111129},\"progress\":\"[================\\u003e                                  ]  29.51MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":277600,\"total\":27504647},\"progress\":\"[\\u003e                                                  ]  277.6kB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":15040512,\"total\":26683298},\"progress\":\"[============================\\u003e                      ]  15.04MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1391300,\"total\":27504647},\"progress\":\"[==\\u003e                                                ]  1.391MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":31132395,\"total\":88111129},\"progress\":\"[=================\\u003e                                 ]  31.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":17989632,\"total\":26683298},\"progress\":\"[=================================\\u003e                 ]  17.99MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":32754411,\"total\":88111129},\"progress\":\"[==================\\u003e                                ]  32.75MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2230980,\"total\":27504647},\"progress\":\"[====\\u003e                                              ]  2.231MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":22118400,\"total\":26683298},\"progress\":\"[=========================================\\u003e         ]  22.12MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":33835755,\"total\":88111129},\"progress\":\"[===================\\u003e                               ]  33.84MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3078852,\"total\":27504647},\"progress\":\"[=====\\u003e                                             ]  3.079MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":24477696,\"total\":26683298},\"progress\":\"[=============================================\\u003e     ]  24.48MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5205016},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":34917099,\"total\":88111129},\"progress\":\"[===================\\u003e                               ]  34.92MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3922628,\"total\":27504647},\"progress\":\"[=======\\u003e                                           ]  3.923MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":912096,\"total\":5205016},\"progress\":\"[========\\u003e                                          ]  912.1kB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":26247168,\"total\":26683298},\"progress\":\"[=================================================\\u003e ]  26.25MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4487876,\"total\":27504647},\"progress\":\"[========\\u003e                                          ]  4.488MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":35986155,\"total\":88111129},\"progress\":\"[====================\\u003e                              ]  35.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":26683298,\"total\":26683298},\"progress\":\"[==================================================\\u003e]  26.68MB/26.68MB\",\"id\":\"5667fdb72017\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1805024,\"total\":5205016},\"progress\":\"[=================\\u003e                                 ]  1.805MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5044932,\"total\":27504647},\"progress\":\"[=========\\u003e                                         ]  5.045MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":36522731,\"total\":88111129},\"progress\":\"[====================\\u003e                              ]  36.52MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2550496,\"total\":5205016},\"progress\":\"[========================\\u003e                          ]   2.55MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5601988,\"total\":27504647},\"progress\":\"[==========\\u003e                                        ]  5.602MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3381984,\"total\":5205016},\"progress\":\"[================================\\u003e                  ]  3.382MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":37063403,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]  37.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6159044,\"total\":27504647},\"progress\":\"[===========\\u003e                                       ]  6.159MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4152032,\"total\":5205016},\"progress\":\"[=======================================\\u003e           ]  4.152MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":37604075,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]   37.6MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"5667fdb72017\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32768,\"total\":35355},\"progress\":\"[==============================================\\u003e    ]  32.77kB/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":35355,\"total\":35355},\"progress\":\"[==================================================\\u003e]  35.35kB/35.35kB\",\"id\":\"d83811f270d5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5004000,\"total\":5205016},\"progress\":\"[================================================\\u003e  ]  5.004MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":6716100,\"total\":27504647},\"progress\":\"[============\\u003e                                      ]  6.716MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":38144747,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]  38.14MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"d83811f270d5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":850,\"total\":850},\"progress\":\"[==================================================\\u003e]     850B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":850,\"total\":850},\"progress\":\"[==================================================\\u003e]     850B/850B\",\"id\":\"ee671aafb583\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":7293636,\"total\":27504647},\"progress\":\"[=============\\u003e                                     ]  7.294MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":39213803,\"total\":88111129},\"progress\":\"[======================\\u003e                            ]  39.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":8129220,\"total\":27504647},\"progress\":\"[==============\\u003e                                    ]  8.129MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"ee671aafb583\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":163,\"total\":163},\"progress\":\"[==================================================\\u003e]     163B/163B\",\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":163,\"total\":163},\"progress\":\"[==================================================\\u003e]     163B/163B\",\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":40295147,\"total\":88111129},\"progress\":\"[======================\\u003e                            ]   40.3MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":8964804,\"total\":27504647},\"progress\":\"[================\\u003e                                  ]  8.965MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"7fc152dfb3a6\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":9800388,\"total\":27504647},\"progress\":\"[=================\\u003e                                 ]    9.8MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":41368299,\"total\":88111129},\"progress\":\"[=======================\\u003e                           ]  41.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49680,\"total\":4964709},\"progress\":\"[\\u003e                                                  ]  49.68kB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":10635972,\"total\":27504647},\"progress\":\"[===================\\u003e                               ]  10.64MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":908013,\"total\":4964709},\"progress\":\"[=========\\u003e                                         ]    908kB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":41908971,\"total\":88111129},\"progress\":\"[=======================\\u003e                           ]  41.91MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11193028,\"total\":27504647},\"progress\":\"[====================\\u003e                              ]  11.19MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2038509,\"total\":4964709},\"progress\":\"[====================\\u003e                              ]  2.039MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":42449643,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  42.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":11750084,\"total\":27504647},\"progress\":\"[=====================\\u003e                             ]  11.75MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3316461,\"total\":4964709},\"progress\":\"[=================================\\u003e                 ]  3.316MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4791021,\"total\":4964709},\"progress\":\"[================================================\\u003e  ]  4.791MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":12315332,\"total\":27504647},\"progress\":\"[======================\\u003e                            ]  12.32MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":42990315,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  42.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13155012,\"total\":27504647},\"progress\":\"[=======================\\u003e                           ]  13.16MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":43530987,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  43.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":13990596,\"total\":27504647},\"progress\":\"[=========================\\u003e                         ]  13.99MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":44063467,\"total\":88111129},\"progress\":\"[=========================\\u003e                         ]  44.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":15112900,\"total\":27504647},\"progress\":\"[===========================\\u003e                       ]  15.11MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":45132523,\"total\":88111129},\"progress\":\"[=========================\\u003e                         ]  45.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16235204,\"total\":27504647},\"progress\":\"[=============================\\u003e                     ]  16.24MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52418,\"total\":5149051},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1195147,\"total\":5149051},\"progress\":\"[===========\\u003e                                       ]  1.195MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":16792260,\"total\":27504647},\"progress\":\"[==============================\\u003e                    ]  16.79MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":45673195,\"total\":88111129},\"progress\":\"[=========================\\u003e                         ]  45.67MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2702475,\"total\":5149051},\"progress\":\"[==========================\\u003e                        ]  2.702MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4078320,\"total\":5149051},\"progress\":\"[=======================================\\u003e           ]  4.078MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":17349316,\"total\":27504647},\"progress\":\"[===============================\\u003e                   ]  17.35MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":46213867,\"total\":88111129},\"progress\":\"[==========================\\u003e                        ]  46.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":17918660,\"total\":27504647},\"progress\":\"[================================\\u003e                  ]  17.92MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":19040964,\"total\":27504647},\"progress\":\"[==================================\\u003e                ]  19.04MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":47295211,\"total\":88111129},\"progress\":\"[==========================\\u003e                        ]   47.3MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":20183748,\"total\":27504647},\"progress\":\"[====================================\\u003e              ]  20.18MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":48368363,\"total\":88111129},\"progress\":\"[===========================\\u003e                       ]  48.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":21301956,\"total\":27504647},\"progress\":\"[======================================\\u003e            ]   21.3MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":22432452,\"total\":27504647},\"progress\":\"[========================================\\u003e          ]  22.43MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":38884,\"total\":3855277},\"progress\":\"[\\u003e                                                  ]  38.88kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49445611,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  49.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":977632,\"total\":3855277},\"progress\":\"[============\\u003e                                      ]  977.6kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23268036,\"total\":27504647},\"progress\":\"[==========================================\\u003e        ]  23.27MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49986283,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  49.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1895136,\"total\":3855277},\"progress\":\"[========================\\u003e                          ]  1.895MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":23833284,\"total\":27504647},\"progress\":\"[===========================================\\u003e       ]  23.83MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2939616,\"total\":3855277},\"progress\":\"[======================================\\u003e            ]   2.94MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":24390340,\"total\":27504647},\"progress\":\"[============================================\\u003e      ]  24.39MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":50518763,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  50.52MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":24947396,\"total\":27504647},\"progress\":\"[=============================================\\u003e     ]  24.95MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":51059435,\"total\":88111129},\"progress\":\"[============================\\u003e                      ]  51.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":25803460,\"total\":27504647},\"progress\":\"[==============================================\\u003e    ]   25.8MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":26942148,\"total\":27504647},\"progress\":\"[================================================\\u003e  ]  26.94MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52140779,\"total\":88111129},\"progress\":\"[=============================\\u003e                     ]  52.14MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":27504647,\"total\":27504647},\"progress\":\"[==================================================\\u003e]   27.5MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":53222123,\"total\":88111129},\"progress\":\"[==============================\\u003e                    ]  53.22MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":51194,\"total\":4983195},\"progress\":\"[\\u003e                                                  ]  51.19kB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":54299371,\"total\":88111129},\"progress\":\"[==============================\\u003e                    ]   54.3MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1268464,\"total\":4983195},\"progress\":\"[============\\u003e                                      ]  1.268MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":54827755,\"total\":88111129},\"progress\":\"[===============================\\u003e                   ]  54.83MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2767600,\"total\":4983195},\"progress\":\"[===========================\\u003e                       ]  2.768MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4528880,\"total\":4983195},\"progress\":\"[=============================================\\u003e     ]  4.529MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":55368427,\"total\":88111129},\"progress\":\"[===============================\\u003e                   ]  55.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":63614,\"total\":6103207},\"progress\":\"[\\u003e                                                  ]  63.61kB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":56449771,\"total\":88111129},\"progress\":\"[================================\\u003e                  ]  56.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1530606,\"total\":6103207},\"progress\":\"[============\\u003e                                      ]  1.531MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3193582,\"total\":6103207},\"progress\":\"[==========================\\u003e                        ]  3.194MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":56990443,\"total\":88111129},\"progress\":\"[================================\\u003e                  ]  56.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4786926,\"total\":6103207},\"progress\":\"[=======================================\\u003e           ]  4.787MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":57531115,\"total\":88111129},\"progress\":\"[================================\\u003e                  ]  57.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":489,\"total\":787},\"progress\":\"[===============================\\u003e                   ]     489B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":58612459,\"total\":88111129},\"progress\":\"[=================================\\u003e                 ]  58.61MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":787,\"total\":787},\"progress\":\"[==================================================\\u003e]     787B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":60213995,\"total\":88111129},\"progress\":\"[==================================\\u003e                ]  60.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":61827819,\"total\":88111129},\"progress\":\"[===================================\\u003e               ]  61.83MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":63449835,\"total\":88111129},\"progress\":\"[====================================\\u003e              ]  63.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":65071851,\"total\":88111129},\"progress\":\"[====================================\\u003e              ]  65.07MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49803,\"total\":4894860},\"progress\":\"[\\u003e                                                  ]   49.8kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49681,\"total\":4953791},\"progress\":\"[\\u003e                                                  ]  49.68kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":912099,\"total\":4894860},\"progress\":\"[=========\\u003e                                         ]  912.1kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":66145003,\"total\":88111129},\"progress\":\"[=====================================\\u003e             ]  66.15MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":748270,\"total\":4953791},\"progress\":\"[=======\\u003e                                           ]  748.3kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1702627,\"total\":4894860},\"progress\":\"[=================\\u003e                                 ]  1.703MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":67205867,\"total\":88111129},\"progress\":\"[======================================\\u003e            ]  67.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1678062,\"total\":4953791},\"progress\":\"[================\\u003e                                  ]  1.678MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2194147,\"total\":4894860},\"progress\":\"[======================\\u003e                            ]  2.194MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":67746539,\"total\":88111129},\"progress\":\"[======================================\\u003e            ]  67.75MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2648814,\"total\":4953791},\"progress\":\"[==========================\\u003e                        ]  2.649MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2743011,\"total\":4894860},\"progress\":\"[============================\\u003e                      ]  2.743MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":68287211,\"total\":88111129},\"progress\":\"[======================================\\u003e            ]  68.29MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3697390,\"total\":4953791},\"progress\":\"[=====================================\\u003e             ]  3.697MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3381987,\"total\":4894860},\"progress\":\"[==================================\\u003e                ]  3.382MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4774638,\"total\":4953791},\"progress\":\"[================================================\\u003e  ]  4.775MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":68827883,\"total\":88111129},\"progress\":\"[=======================================\\u003e           ]  68.83MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4953791,\"total\":4953791},\"progress\":\"[==================================================\\u003e]  4.954MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4004579,\"total\":4894860},\"progress\":\"[========================================\\u003e          ]  4.005MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4893411,\"total\":4894860},\"progress\":\"[=================================================\\u003e ]  4.893MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":69909227,\"total\":88111129},\"progress\":\"[=======================================\\u003e           ]  69.91MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":71527147,\"total\":88111129},\"progress\":\"[========================================\\u003e          ]  71.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":73149163,\"total\":88111129},\"progress\":\"[=========================================\\u003e         ]  73.15MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":74771179,\"total\":88111129},\"progress\":\"[==========================================\\u003e        ]  74.77MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":63573,\"total\":6137526},\"progress\":\"[\\u003e                                                  ]  63.57kB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":75311851,\"total\":88111129},\"progress\":\"[==========================================\\u003e        ]  75.31MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1317559,\"total\":6137526},\"progress\":\"[==========\\u003e                                        ]  1.318MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2710199,\"total\":6137526},\"progress\":\"[======================\\u003e                            ]   2.71MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":38729,\"total\":3854415},\"progress\":\"[\\u003e                                                  ]  38.73kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":76368619,\"total\":88111129},\"progress\":\"[===========================================\\u003e       ]  76.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3783351,\"total\":6137526},\"progress\":\"[==============================\\u003e                    ]  3.783MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":658157,\"total\":3854415},\"progress\":\"[========\\u003e                                          ]  658.2kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4520631,\"total\":6137526},\"progress\":\"[====================================\\u003e              ]  4.521MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1350381,\"total\":3854415},\"progress\":\"[=================\\u003e                                 ]   1.35MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5364407,\"total\":6137526},\"progress\":\"[===========================================\\u003e       ]  5.364MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":77445867,\"total\":88111129},\"progress\":\"[===========================================\\u003e       ]  77.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2153197,\"total\":3854415},\"progress\":\"[===========================\\u003e                       ]  2.153MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":77986539,\"total\":88111129},\"progress\":\"[============================================\\u003e      ]  77.99MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3021549,\"total\":3854415},\"progress\":\"[=======================================\\u003e           ]  3.022MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":79067883,\"total\":88111129},\"progress\":\"[============================================\\u003e      ]  79.07MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":80149227,\"total\":88111129},\"progress\":\"[=============================================\\u003e     ]  80.15MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":81767147,\"total\":88111129},\"progress\":\"[==============================================\\u003e    ]  81.77MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5222290},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1055455,\"total\":5222290},\"progress\":\"[==========\\u003e                                        ]  1.055MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":83372779,\"total\":88111129},\"progress\":\"[===============================================\\u003e   ]  83.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2333407,\"total\":5222290},\"progress\":\"[======================\\u003e                            ]  2.333MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":35991,\"total\":3564359},\"progress\":\"[\\u003e                                                  ]  35.99kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":84454123,\"total\":88111129},\"progress\":\"[===============================================\\u003e   ]  84.45MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3300063,\"total\":5222290},\"progress\":\"[===============================\\u003e                   ]    3.3MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":752366,\"total\":3564359},\"progress\":\"[==========\\u003e                                        ]  752.4kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3979999,\"total\":5222290},\"progress\":\"[======================================\\u003e            ]   3.98MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1743598,\"total\":3564359},\"progress\":\"[========================\\u003e                          ]  1.744MB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":85527275,\"total\":88111129},\"progress\":\"[================================================\\u003e  ]  85.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4537055,\"total\":5222290},\"progress\":\"[===========================================\\u003e       ]  4.537MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2833134,\"total\":3564359},\"progress\":\"[=======================================\\u003e           ]  2.833MB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5077727,\"total\":5222290},\"progress\":\"[================================================\\u003e  ]  5.078MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":86067947,\"total\":88111129},\"progress\":\"[================================================\\u003e  ]  86.07MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":87132907,\"total\":88111129},\"progress\":\"[=================================================\\u003e ]  87.13MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":557056,\"total\":88111129},\"progress\":\"[\\u003e                                                  ]  557.1kB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52418,\"total\":5120108},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":489,\"total\":790},\"progress\":\"[==============================\\u003e                    ]     489B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5013504,\"total\":88111129},\"progress\":\"[==\\u003e                                                ]  5.014MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":790,\"total\":790},\"progress\":\"[==================================================\\u003e]     790B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1764079,\"total\":5120108},\"progress\":\"[=================\\u003e                                 ]  1.764MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":8355840,\"total\":88111129},\"progress\":\"[====\\u003e                                              ]  8.356MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3635951,\"total\":5120108},\"progress\":\"[===================================\\u003e               ]  3.636MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":11141120,\"total\":88111129},\"progress\":\"[======\\u003e                                            ]  11.14MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5117023},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":13369344,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  13.37MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1596142,\"total\":5117023},\"progress\":\"[===============\\u003e                                   ]  1.596MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":13926400,\"total\":88111129},\"progress\":\"[=======\\u003e                                           ]  13.93MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3242734,\"total\":5117023},\"progress\":\"[===============================\\u003e                   ]  3.243MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":55157,\"total\":5384215},\"progress\":\"[\\u003e                                                  ]  55.16kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4635374,\"total\":5117023},\"progress\":\"[=============================================\\u003e     ]  4.635MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":15040512,\"total\":88111129},\"progress\":\"[========\\u003e                                          ]  15.04MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":989937,\"total\":5384215},\"progress\":\"[=========\\u003e                                         ]  989.9kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":15597568,\"total\":88111129},\"progress\":\"[========\\u003e                                          ]   15.6MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2558705,\"total\":5384215},\"progress\":\"[=======================\\u003e                           ]  2.559MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":18382848,\"total\":88111129},\"progress\":\"[==========\\u003e                                        ]  18.38MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4311793,\"total\":5384215},\"progress\":\"[========================================\\u003e          ]  4.312MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":53788,\"total\":5252487},\"progress\":\"[\\u003e                                                  ]  53.79kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":22839296,\"total\":88111129},\"progress\":\"[============\\u003e                                      ]  22.84MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":5212913,\"total\":5384215},\"progress\":\"[================================================\\u003e  ]  5.213MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":846577,\"total\":5252487},\"progress\":\"[========\\u003e                                          ]  846.6kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":26181632,\"total\":88111129},\"progress\":\"[==============\\u003e                                    ]  26.18MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2628337,\"total\":5252487},\"progress\":\"[=========================\\u003e                         ]  2.628MB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":30638080,\"total\":88111129},\"progress\":\"[=================\\u003e                                 ]  30.64MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4340465,\"total\":5252487},\"progress\":\"[=========================================\\u003e         ]   4.34MB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":33423360,\"total\":88111129},\"progress\":\"[==================\\u003e                                ]  33.42MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":51204,\"total\":5015856},\"progress\":\"[\\u003e                                                  ]   51.2kB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":36208640,\"total\":88111129},\"progress\":\"[====================\\u003e                              ]  36.21MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1624816,\"total\":5015856},\"progress\":\"[================\\u003e                                  ]  1.625MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":38436864,\"total\":88111129},\"progress\":\"[=====================\\u003e                             ]  38.44MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3373808,\"total\":5015856},\"progress\":\"[=================================\\u003e                 ]  3.374MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":40665088,\"total\":88111129},\"progress\":\"[=======================\\u003e                           ]  40.67MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":53910,\"total\":5310566},\"progress\":\"[\\u003e                                                  ]  53.91kB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4905712,\"total\":5015856},\"progress\":\"[================================================\\u003e  ]  4.906MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1313521,\"total\":5310566},\"progress\":\"[============\\u003e                                      ]  1.314MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":44007424,\"total\":88111129},\"progress\":\"[========================\\u003e                          ]  44.01MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":46792704,\"total\":88111129},\"progress\":\"[==========================\\u003e                        ]  46.79MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3082993,\"total\":5310566},\"progress\":\"[=============================\\u003e                     ]  3.083MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":49836,\"total\":4915049},\"progress\":\"[\\u003e                                                  ]  49.84kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4373233,\"total\":5310566},\"progress\":\"[=========================================\\u003e         ]  4.373MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":48463872,\"total\":88111129},\"progress\":\"[===========================\\u003e                       ]  48.46MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":711407,\"total\":4915049},\"progress\":\"[=======\\u003e                                           ]  711.4kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1710831,\"total\":4915049},\"progress\":\"[=================\\u003e                                 ]  1.711MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":52363264,\"total\":88111129},\"progress\":\"[=============================\\u003e                     ]  52.36MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":3504879,\"total\":4915049},\"progress\":\"[===================================\\u003e               ]  3.505MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":55705600,\"total\":88111129},\"progress\":\"[===============================\\u003e                   ]  55.71MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4905711,\"total\":4915049},\"progress\":\"[=================================================\\u003e ]  4.906MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":58490880,\"total\":88111129},\"progress\":\"[=================================\\u003e                 ]  58.49MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":52419,\"total\":5119213},\"progress\":\"[\\u003e                                                  ]  52.42kB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":61276160,\"total\":88111129},\"progress\":\"[==================================\\u003e                ]  61.28MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1333999,\"total\":5119213},\"progress\":\"[=============\\u003e                                     ]  1.334MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":2657007,\"total\":5119213},\"progress\":\"[=========================\\u003e                         ]  2.657MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":64061440,\"total\":88111129},\"progress\":\"[====================================\\u003e              ]  64.06MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":4344559,\"total\":5119213},\"progress\":\"[==========================================\\u003e        ]  4.345MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":66289664,\"total\":88111129},\"progress\":\"[=====================================\\u003e             ]  66.29MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":70746112,\"total\":88111129},\"progress\":\"[========================================\\u003e          ]  70.75MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":73531392,\"total\":88111129},\"progress\":\"[=========================================\\u003e         ]  73.53MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":77430784,\"total\":88111129},\"progress\":\"[===========================================\\u003e       ]  77.43MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":488,\"total\":1069},\"progress\":\"[======================\\u003e                            ]     488B/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":80216064,\"total\":88111129},\"progress\":\"[=============================================\\u003e     ]  80.22MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":1069,\"total\":1069},\"progress\":\"[==================================================\\u003e]  1.069kB/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Downloading\",\"progressDetail\":{\"current\":32,\"total\":32},\"progress\":\"[==================================================\\u003e]      32B/32B\",\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Verifying Checksum\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Download complete\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":81887232,\"total\":88111129},\"progress\":\"[==============================================\\u003e    ]  81.89MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":83558400,\"total\":88111129},\"progress\":\"[===============================================\\u003e   ]  83.56MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":85229568,\"total\":88111129},\"progress\":\"[================================================\\u003e  ]  85.23MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":86900736,\"total\":88111129},\"progress\":\"[=================================================\\u003e ]   86.9MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":88014848,\"total\":88111129},\"progress\":\"[=================================================\\u003e ]  88.01MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":88111129,\"total\":88111129},\"progress\":\"[==================================================\\u003e]  88.11MB/88.11MB\",\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"4ab897fa6fbf\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32768,\"total\":1391657},\"progress\":\"[=\\u003e                                                 ]  32.77kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":1391657},\"progress\":\"[===========\\u003e                                       ]  327.7kB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1391657,\"total\":1391657},\"progress\":\"[==================================================\\u003e]  1.392MB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1391657,\"total\":1391657},\"progress\":\"[==================================================\\u003e]  1.392MB/1.392MB\",\"id\":\"d837a2a1365e\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"d837a2a1365e\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32768,\"total\":1328346},\"progress\":\"[=\\u003e                                                 ]  32.77kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":753664,\"total\":1328346},\"progress\":\"[============================\\u003e                      ]  753.7kB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1328346,\"total\":1328346},\"progress\":\"[==================================================\\u003e]  1.328MB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1328346,\"total\":1328346},\"progress\":\"[==================================================\\u003e]  1.328MB/1.328MB\",\"id\":\"988ae18fe41a\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"988ae18fe41a\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4478,\"total\":4478},\"progress\":\"[==================================================\\u003e]  4.478kB/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4478,\"total\":4478},\"progress\":\"[==================================================\\u003e]  4.478kB/4.478kB\",\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"eeb8ef83b565\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":197,\"total\":197},\"progress\":\"[==================================================\\u003e]     197B/197B\",\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":197,\"total\":197},\"progress\":\"[==================================================\\u003e]     197B/197B\",\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"357fefdf9bc9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":294912,\"total\":27504647},\"progress\":\"[\\u003e                                                  ]  294.9kB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":589824,\"total\":27504647},\"progress\":\"[=\\u003e                                                 ]  589.8kB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5013504,\"total\":27504647},\"progress\":\"[=========\\u003e                                         ]  5.014MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":9142272,\"total\":27504647},\"progress\":\"[================\\u003e                                  ]  9.142MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":13565952,\"total\":27504647},\"progress\":\"[========================\\u003e                          ]  13.57MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":16515072,\"total\":27504647},\"progress\":\"[==============================\\u003e                    ]  16.52MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":18579456,\"total\":27504647},\"progress\":\"[=================================\\u003e                 ]  18.58MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":21528576,\"total\":27504647},\"progress\":\"[=======================================\\u003e           ]  21.53MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":25657344,\"total\":27504647},\"progress\":\"[==============================================\\u003e    ]  25.66MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":27504647,\"total\":27504647},\"progress\":\"[==================================================\\u003e]   27.5MB/27.5MB\",\"id\":\"45b746196f82\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"45b746196f82\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5205016},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1048576,\"total\":5205016},\"progress\":\"[==========\\u003e                                        ]  1.049MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5205016,\"total\":5205016},\"progress\":\"[==================================================\\u003e]  5.205MB/5.205MB\",\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"fbf4ce20f8c2\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4964709},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1245184,\"total\":4964709},\"progress\":\"[============\\u003e                                      ]  1.245MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4964709,\"total\":4964709},\"progress\":\"[==================================================\\u003e]  4.965MB/4.965MB\",\"id\":\"90aca3c647fe\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"90aca3c647fe\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5149051},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":393216,\"total\":5149051},\"progress\":\"[===\\u003e                                               ]  393.2kB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5149051,\"total\":5149051},\"progress\":\"[==================================================\\u003e]  5.149MB/5.149MB\",\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"1dd62f37c84c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":3855277},\"progress\":\"[\\u003e                                                  ]  65.54kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":851968,\"total\":3855277},\"progress\":\"[===========\\u003e                                       ]    852kB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3855277,\"total\":3855277},\"progress\":\"[==================================================\\u003e]  3.855MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3855277,\"total\":3855277},\"progress\":\"[==================================================\\u003e]  3.855MB/3.855MB\",\"id\":\"3192b2fa42db\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"3192b2fa42db\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4983195},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":4983195},\"progress\":\"[===\\u003e                                               ]  327.7kB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4980736,\"total\":4983195},\"progress\":\"[=================================================\\u003e ]  4.981MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4983195,\"total\":4983195},\"progress\":\"[==================================================\\u003e]  4.983MB/4.983MB\",\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"ae190b8f66a7\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":6103207},\"progress\":\"[\\u003e                                                  ]  65.54kB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":6103207},\"progress\":\"[==\\u003e                                                ]  327.7kB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3670016,\"total\":6103207},\"progress\":\"[==============================\\u003e                    ]   3.67MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":6103207,\"total\":6103207},\"progress\":\"[==================================================\\u003e]  6.103MB/6.103MB\",\"id\":\"97bb6e138460\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"97bb6e138460\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":787,\"total\":787},\"progress\":\"[==================================================\\u003e]     787B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":787,\"total\":787},\"progress\":\"[==================================================\\u003e]     787B/787B\",\"id\":\"2edb982d5170\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"2edb982d5170\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4894860},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":4894860},\"progress\":\"[===\\u003e                                               ]  327.7kB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3735552,\"total\":4894860},\"progress\":\"[======================================\\u003e            ]  3.736MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4894860,\"total\":4894860},\"progress\":\"[==================================================\\u003e]  4.895MB/4.895MB\",\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"7ddc8e6d6da9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4953791},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":4953791},\"progress\":\"[===\\u003e                                               ]  327.7kB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4325376,\"total\":4953791},\"progress\":\"[===========================================\\u003e       ]  4.325MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4953791,\"total\":4953791},\"progress\":\"[==================================================\\u003e]  4.954MB/4.954MB\",\"id\":\"0df6fd234b59\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"0df6fd234b59\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":6137526},\"progress\":\"[\\u003e                                                  ]  65.54kB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":6137526},\"progress\":\"[==\\u003e                                                ]  327.7kB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3801088,\"total\":6137526},\"progress\":\"[==============================\\u003e                    ]  3.801MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":6137526,\"total\":6137526},\"progress\":\"[==================================================\\u003e]  6.138MB/6.138MB\",\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"8fc1ba8efe21\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":3854415},\"progress\":\"[\\u003e                                                  ]  65.54kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":851968,\"total\":3854415},\"progress\":\"[===========\\u003e                                       ]    852kB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3854415,\"total\":3854415},\"progress\":\"[==================================================\\u003e]  3.854MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3854415,\"total\":3854415},\"progress\":\"[==================================================\\u003e]  3.854MB/3.854MB\",\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"1f6f45e783b5\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5222290},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":458752,\"total\":5222290},\"progress\":\"[====\\u003e                                              ]  458.8kB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4849664,\"total\":5222290},\"progress\":\"[==============================================\\u003e    ]   4.85MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5222290,\"total\":5222290},\"progress\":\"[==================================================\\u003e]  5.222MB/5.222MB\",\"id\":\"43ea61082f68\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"43ea61082f68\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":3564359},\"progress\":\"[\\u003e                                                  ]  65.54kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":3564359},\"progress\":\"[====\\u003e                                              ]  327.7kB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3564359,\"total\":3564359},\"progress\":\"[==================================================\\u003e]  3.564MB/3.564MB\",\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"b8cf53bbc6ba\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":790,\"total\":790},\"progress\":\"[==================================================\\u003e]     790B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":790,\"total\":790},\"progress\":\"[==================================================\\u003e]     790B/790B\",\"id\":\"25efb07e4521\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"25efb07e4521\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5120108},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5120108},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5111808,\"total\":5120108},\"progress\":\"[=================================================\\u003e ]  5.112MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5120108,\"total\":5120108},\"progress\":\"[==================================================\\u003e]   5.12MB/5.12MB\",\"id\":\"1c3245356213\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"1c3245356213\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5117023},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":655360,\"total\":5117023},\"progress\":\"[======\\u003e                                            ]  655.4kB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4259840,\"total\":5117023},\"progress\":\"[=========================================\\u003e         ]   4.26MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5117023,\"total\":5117023},\"progress\":\"[==================================================\\u003e]  5.117MB/5.117MB\",\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"61ebb123c1eb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5384215},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5384215},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5177344,\"total\":5384215},\"progress\":\"[================================================\\u003e  ]  5.177MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5384215,\"total\":5384215},\"progress\":\"[==================================================\\u003e]  5.384MB/5.384MB\",\"id\":\"0964b769d2c9\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"0964b769d2c9\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5252487},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":655360,\"total\":5252487},\"progress\":\"[======\\u003e                                            ]  655.4kB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5252487,\"total\":5252487},\"progress\":\"[==================================================\\u003e]  5.252MB/5.252MB\",\"id\":\"87f7843f43cd\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"87f7843f43cd\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5015856},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5015856},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3997696,\"total\":5015856},\"progress\":\"[=======================================\\u003e           ]  3.998MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5015856,\"total\":5015856},\"progress\":\"[==================================================\\u003e]  5.016MB/5.016MB\",\"id\":\"a89dbf94d794\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"a89dbf94d794\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5310566},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":393216,\"total\":5310566},\"progress\":\"[===\\u003e                                               ]  393.2kB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":3407872,\"total\":5310566},\"progress\":\"[================================\\u003e                  ]  3.408MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5310566,\"total\":5310566},\"progress\":\"[==================================================\\u003e]  5.311MB/5.311MB\",\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"f0d43ddca77f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":4915049},\"progress\":\"[\\u003e                                                  ]  65.54kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":786432,\"total\":4915049},\"progress\":\"[========\\u003e                                          ]  786.4kB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4915049,\"total\":4915049},\"progress\":\"[==================================================\\u003e]  4.915MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4915049,\"total\":4915049},\"progress\":\"[==================================================\\u003e]  4.915MB/4.915MB\",\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"7c674f0cb40c\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":65536,\"total\":5119213},\"progress\":\"[\\u003e                                                  ]  65.54kB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":327680,\"total\":5119213},\"progress\":\"[===\\u003e                                               ]  327.7kB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":4390912,\"total\":5119213},\"progress\":\"[==========================================\\u003e        ]  4.391MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":5119213,\"total\":5119213},\"progress\":\"[==================================================\\u003e]  5.119MB/5.119MB\",\"id\":\"b48a885b52bc\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"b48a885b52bc\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":395,\"total\":395},\"progress\":\"[==================================================\\u003e]     395B/395B\",\"id\":\"272cdf839cbb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":395,\"total\":395},\"progress\":\"[==================================================\\u003e]     395B/395B\",\"id\":\"272cdf839cbb\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"272cdf839cbb\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":155,\"total\":155},\"progress\":\"[==================================================\\u003e]     155B/155B\",\"id\":\"50d054c97f4f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":155,\"total\":155},\"progress\":\"[==================================================\\u003e]     155B/155B\",\"id\":\"50d054c97f4f\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"50d054c97f4f\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1069,\"total\":1069},\"progress\":\"[==================================================\\u003e]  1.069kB/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":1069,\"total\":1069},\"progress\":\"[==================================================\\u003e]  1.069kB/1.069kB\",\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"4c6bbd90b64d\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32,\"total\":32},\"progress\":\"[==================================================\\u003e]      32B/32B\",\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Extracting\",\"progressDetail\":{\"current\":32,\"total\":32},\"progress\":\"[==================================================\\u003e]      32B/32B\",\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Pull complete\",\"progressDetail\":{},\"id\":\"4f4fb700ef54\"}\n{\"status\":\"Digest: sha256:4acb6bfd6c4f0cabaf7f3690e444afe51f1c7de54d51da7e63fac709c56f1c30\"}\n{\"status\":\"Status: Downloaded newer image for paketo-buildpacks/cnb:base\"}\n"
  },
  {
    "path": "buildpack/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/json/test-mapped-object.json",
    "content": "{\n\t\"string\": \"stringvalue\",\n\t\"stringarray\": [\n\t\t\"a\",\n\t\t\"b\"\n\t],\n\t\"StartsWithUppercase\": \"value\",\n\t\"person\": {\n\t\t\"name\": {\n\t\t\t\"title\": \"dr\",\n\t\t\t\"first\": \"spring\",\n\t\t\t\"last\": \"boot\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.springframework.boot.build.properties.BuildProperties\nimport org.springframework.boot.build.properties.BuildType\n\nplugins {\n\tid \"java\"\n\tid \"eclipse\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.integration-test\"\n}\n\ndescription = \"Spring Boot CLI\"\n\nsourceSets {\n\tmain {\n\t\tjava {\n\t\t\tsrcDir file(\"src/json-shade/java\")\n\t\t}\n\t}\n}\n\nconfigurations {\n\tloader\n\ttestRepository\n\tcompileOnlyProject\n\tcompileClasspath.extendsFrom(compileOnlyProject)\n}\n\ndependencies {\n\tcompileOnlyProject(project(\":core:spring-boot\"))\n\n\timplementation(project(\":loader:spring-boot-loader-tools\"))\n\timplementation(\"jline:jline\")\n\timplementation(\"net.sf.jopt-simple:jopt-simple\")\n\timplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\timplementation(\"org.slf4j:slf4j-simple\")\n\timplementation(\"org.springframework:spring-core\")\n\timplementation(\"org.springframework.security:spring-security-crypto\")\n\n\tintTestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\tloader(project(\":loader:spring-boot-loader\"))\n\n\ttestImplementation(project(\":core:spring-boot\"))\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\ntasks.register(\"fullJar\", Jar) {\n\tdependsOn configurations.loader\n\tarchiveClassifier = \"full\"\n\tentryCompression = \"stored\"\n\tfrom(configurations.runtimeClasspath) {\n\t\tinto \"BOOT-INF/lib\"\n\t}\n\tfrom(sourceSets.main.output) {\n\t\tinto \"BOOT-INF/classes\"\n\t}\n\tfrom {\n\t\tzipTree(configurations.loader.singleFile).matching {\n\t\t\texclude \"META-INF/LICENSE.txt\"\n\t\t\texclude \"META-INF/NOTICE.txt\"\n\t\t\texclude \"META-INF/spring-boot.properties\"\n\t\t}\n\t}\n\tmanifest {\n\t\tattributes(\n\t\t\t\"Main-Class\": \"org.springframework.boot.loader.launch.JarLauncher\",\n\t\t\t\"Start-Class\": \"org.springframework.boot.cli.SpringCli\"\n\t\t)\n\t}\n}\n\ndef configureArchive(archive) {\n\tarchive.archiveClassifier = \"bin\"\n\tarchive.into \"spring-${project.version}\"\n\tarchive.from(fullJar) {\n\t\trename {\n\t\t\tit.replace(\"-full\", \"\")\n\t\t}\n\t\tinto \"lib/\"\n\t}\n\tarchive.from(file(\"src/main/content\")) {\n\t\tdirPermissions { unix(0755) }\n\t\tfilePermissions { unix(0644) }\n\t}\n\tarchive.from(file(\"src/main/executablecontent\")) {\n\t\tfilePermissions { unix(0755) }\n\t}\n}\n\ntasks.register(\"zip\", Zip) {\n\tarchiveClassifier = \"bin\"\n\tconfigureArchive it\n}\n\nintTest {\n\tdependsOn zip\n}\n\ntasks.register(\"tar\", Tar) {\n\tcompression = \"gzip\"\n\tarchiveExtension = \"tar.gz\"\n\tconfigureArchive it\n}\n\nif (BuildProperties.get(project).buildType() == BuildType.OPEN_SOURCE) {\n\tdef homebrewFormula = tasks.register(\"homebrewFormula\", org.springframework.boot.build.cli.HomebrewFormula) {\n\t\tdependsOn tar\n\t\toutputDir = layout.buildDirectory.dir(\"homebrew\")\n\t\ttemplate = file(\"src/main/homebrew/spring-boot.rb\")\n\t\tarchive = tar.archiveFile\n\t}\n\n\tpublishing {\n\t\tpublications {\n\t\t\tgetByName(\"maven\") {\n\t\t\t\tartifact(homebrewFormula.map { it.outputDir.file(\"spring-boot.rb\") }) { formula ->\n\t\t\t\t\tformula.classifier = \"homebrew\"\n\t\t\t\t\tformula.extension = \"rb\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\npublishing {\n\tpublications {\n\t\tgetByName(\"maven\") {\n\t\t\tartifact fullJar\n\t\t\tartifact tar\n\t\t\tartifact zip\n\t\t}\n\t}\n}\n\neclipse.classpath { // https://github.com/eclipse/buildship/issues/939\n\tplusConfigurations += [ configurations.compileOnlyProject ]\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileIntTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/intTest/java/org/springframework/boot/cli/CommandLineIT.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.cli.infrastructure.CommandLineInvoker;\nimport org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration Tests for the command line application.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass CommandLineIT {\n\n\tprivate CommandLineInvoker cli;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File tempDir) {\n\t\tthis.cli = new CommandLineInvoker(tempDir);\n\t}\n\n\t@Test\n\tvoid hintProducesListOfValidCommands() throws IOException, InterruptedException {\n\t\tInvocation cli = this.cli.invoke(\"hint\");\n\t\tassertThat(cli.await()).isEqualTo(0);\n\t\tassertThat(cli.getErrorOutput()).isEmpty();\n\t\tassertThat(cli.getStandardOutputLines()).hasSize(5);\n\t}\n\n\t@Test\n\tvoid invokingWithNoArgumentsDisplaysHelp() throws IOException, InterruptedException {\n\t\tInvocation cli = this.cli.invoke();\n\t\tassertThat(cli.await()).isEqualTo(1);\n\t\tassertThat(cli.getErrorOutput()).isEmpty();\n\t\tassertThat(cli.getStandardOutput()).startsWith(\"usage:\");\n\t}\n\n\t@Test\n\tvoid unrecognizedCommandsAreHandledGracefully() throws IOException, InterruptedException {\n\t\tInvocation cli = this.cli.invoke(\"not-a-real-command\");\n\t\tassertThat(cli.await()).isEqualTo(1);\n\t\tassertThat(cli.getErrorOutput()).contains(\"'not-a-real-command' is not a valid command\");\n\t\tassertThat(cli.getStandardOutput()).isEmpty();\n\t}\n\n\t@Test\n\tvoid version() throws IOException, InterruptedException {\n\t\tInvocation cli = this.cli.invoke(\"version\");\n\t\tassertThat(cli.await()).isEqualTo(0);\n\t\tassertThat(cli.getErrorOutput()).isEmpty();\n\t\tassertThat(cli.getStandardOutput()).startsWith(\"Spring CLI v\");\n\t}\n\n\t@Test\n\tvoid help() throws IOException, InterruptedException {\n\t\tInvocation cli = this.cli.invoke(\"help\");\n\t\tassertThat(cli.await()).isEqualTo(1);\n\t\tassertThat(cli.getErrorOutput()).isEmpty();\n\t\tassertThat(cli.getStandardOutput()).startsWith(\"usage:\");\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/intTest/java/org/springframework/boot/cli/infrastructure/CommandLineInvoker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.infrastructure;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Utility to invoke the command line in the same way as a user would, i.e. through the\n * shell script in the package's bin directory.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\npublic final class CommandLineInvoker {\n\n\tprivate final File workingDirectory;\n\n\tprivate final File temp;\n\n\tpublic CommandLineInvoker(File temp) {\n\t\tthis(new File(\".\"), temp);\n\t}\n\n\tpublic CommandLineInvoker(File workingDirectory, File temp) {\n\t\tthis.workingDirectory = workingDirectory;\n\t\tthis.temp = temp;\n\t}\n\n\tpublic Invocation invoke(String... args) throws IOException {\n\t\treturn new Invocation(runCliProcess(args));\n\t}\n\n\tprivate Process runCliProcess(String... args) throws IOException {\n\t\tPath m2 = this.temp.toPath().resolve(\".m2\");\n\t\tFiles.createDirectories(m2);\n\t\tFiles.copy(Paths.get(\"src\", \"intTest\", \"resources\", \"settings.xml\"), m2.resolve(\"settings.xml\"),\n\t\t\t\tStandardCopyOption.REPLACE_EXISTING);\n\t\tList<String> command = new ArrayList<>();\n\t\tcommand.add(findLaunchScript().getAbsolutePath());\n\t\tcommand.addAll(Arrays.asList(args));\n\t\tProcessBuilder processBuilder = new ProcessBuilder(command).directory(this.workingDirectory);\n\t\tprocessBuilder.environment().put(\"JAVA_OPTS\", \"-Duser.home=\" + this.temp);\n\t\tprocessBuilder.environment().put(\"JAVA_HOME\", System.getProperty(\"java.home\"));\n\t\treturn processBuilder.start();\n\t}\n\n\tprivate File findLaunchScript() throws IOException {\n\t\tFile unpacked = new File(this.temp, \"unpacked-cli\");\n\t\tif (!unpacked.isDirectory()) {\n\t\t\tFile zip = new File(new BuildOutput(getClass()).getRootLocation(),\n\t\t\t\t\t\"distributions/spring-boot-cli-\" + Versions.getBootVersion() + \"-bin.zip\");\n\t\t\ttry (ZipInputStream input = new ZipInputStream(new FileInputStream(zip))) {\n\t\t\t\tZipEntry entry;\n\t\t\t\twhile ((entry = input.getNextEntry()) != null) {\n\t\t\t\t\tFile file = new File(unpacked, entry.getName());\n\t\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\t\tfile.mkdirs();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfile.getParentFile().mkdirs();\n\t\t\t\t\t\ttry (FileOutputStream output = new FileOutputStream(file)) {\n\t\t\t\t\t\t\tStreamUtils.copy(input, output);\n\t\t\t\t\t\t\tif (entry.getName().endsWith(\"/bin/spring\")) {\n\t\t\t\t\t\t\t\tfile.setExecutable(true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tFile bin = new File(unpacked.listFiles()[0], \"bin\");\n\t\tFile launchScript = new File(bin, isWindows() ? \"spring.bat\" : \"spring\");\n\t\tAssert.state(launchScript.exists() && launchScript.isFile(),\n\t\t\t\t() -> \"Could not find CLI launch script \" + launchScript.getAbsolutePath());\n\t\treturn launchScript;\n\t}\n\n\tprivate boolean isWindows() {\n\t\treturn File.separatorChar == '\\\\';\n\t}\n\n\t/**\n\t * An ongoing Process invocation.\n\t */\n\tpublic static final class Invocation {\n\n\t\tprivate final StringBuffer err = new StringBuffer();\n\n\t\tprivate final StringBuffer out = new StringBuffer();\n\n\t\tprivate final StringBuffer combined = new StringBuffer();\n\n\t\tprivate final Process process;\n\n\t\tprivate final List<Thread> streamReaders = new ArrayList<>();\n\n\t\tpublic Invocation(Process process) {\n\t\t\tthis.process = process;\n\t\t\tthis.streamReaders\n\t\t\t\t.add(new Thread(new StreamReadingRunnable(this.process.getErrorStream(), this.err, this.combined)));\n\t\t\tthis.streamReaders\n\t\t\t\t.add(new Thread(new StreamReadingRunnable(this.process.getInputStream(), this.out, this.combined)));\n\t\t\tfor (Thread streamReader : this.streamReaders) {\n\t\t\t\tstreamReader.start();\n\t\t\t}\n\t\t}\n\n\t\tpublic String getOutput() {\n\t\t\treturn postProcessLines(getLines(this.combined));\n\t\t}\n\n\t\tpublic String getErrorOutput() {\n\t\t\treturn postProcessLines(getLines(this.err));\n\t\t}\n\n\t\tpublic String getStandardOutput() {\n\t\t\treturn postProcessLines(getStandardOutputLines());\n\t\t}\n\n\t\tpublic List<String> getStandardOutputLines() {\n\t\t\treturn getLines(this.out);\n\t\t}\n\n\t\tprivate String postProcessLines(List<String> lines) {\n\t\t\tStringWriter out = new StringWriter();\n\t\t\tPrintWriter printOut = new PrintWriter(out);\n\t\t\tfor (String line : lines) {\n\t\t\t\tif (!line.startsWith(\"Maven settings decryption failed\")) {\n\t\t\t\t\tprintOut.println(line);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out.toString();\n\t\t}\n\n\t\tprivate List<String> getLines(StringBuffer buffer) {\n\t\t\tBufferedReader reader = new BufferedReader(new StringReader(buffer.toString()));\n\t\t\treturn reader.lines().filter((line) -> !line.startsWith(\"Picked up \")).toList();\n\t\t}\n\n\t\tpublic int await() throws InterruptedException {\n\t\t\tfor (Thread streamReader : this.streamReaders) {\n\t\t\t\tstreamReader.join();\n\t\t\t}\n\t\t\treturn this.process.waitFor();\n\t\t}\n\n\t\t/**\n\t\t * {@link Runnable} to copy stream output.\n\t\t */\n\t\tprivate final class StreamReadingRunnable implements Runnable {\n\n\t\t\tprivate final InputStream stream;\n\n\t\t\tprivate final StringBuffer[] outputs;\n\n\t\t\tprivate final byte[] buffer = new byte[4096];\n\n\t\t\tprivate StreamReadingRunnable(InputStream stream, StringBuffer... outputs) {\n\t\t\t\tthis.stream = stream;\n\t\t\t\tthis.outputs = outputs;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tint read;\n\t\t\t\ttry {\n\t\t\t\t\twhile ((read = this.stream.read(this.buffer)) > 0) {\n\t\t\t\t\t\tfor (StringBuffer output : this.outputs) {\n\t\t\t\t\t\t\toutput.append(new String(this.buffer, 0, read));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t// Allow thread to die\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/intTest/java/org/springframework/boot/cli/infrastructure/Versions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.infrastructure;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.Properties;\n\n/**\n * Provides access to the current Boot version by referring to {@code gradle.properties}.\n *\n * @author Andy Wilkinson\n */\nfinal class Versions {\n\n\tprivate Versions() {\n\t}\n\n\tstatic String getBootVersion() {\n\t\tProperties gradleProperties = new Properties();\n\t\ttry (FileInputStream input = new FileInputStream(\"../../gradle.properties\")) {\n\t\t\tgradleProperties.load(input);\n\t\t\treturn gradleProperties.getProperty(\"version\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/intTest/resources/settings.xml",
    "content": "<settings>\n\t<localRepository>../../../../build/local-m2-repository\n\t</localRepository>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>cli-test-repo</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>local.central</id>\n\t\t\t\t\t<url>file:../../../../build/test-repository</url>\n\t\t\t\t\t<releases>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</releases>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>thymeleaf-snapshot</id>\n\t\t\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t\t\t\t<releases>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</releases>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t</profile>\n\t</profiles>\n</settings>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/README.adoc",
    "content": "## Shaded JSON\n\nThis source was originally taken from `com.vaadin.external.google:android-json` which\nprovides a clean room re-implementation of the `org.json` APIs and does not include the\n\"Do not use for evil\" clause.\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/JSON.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.json;\n\nclass JSON {\n\n\tstatic double checkDouble(double d) throws JSONException {\n\t\tif (Double.isInfinite(d) || Double.isNaN(d)) {\n\t\t\tthrow new JSONException(\"Forbidden numeric value: \" + d);\n\t\t}\n\t\treturn d;\n\t}\n\n\tstatic Boolean toBoolean(Object value) {\n\t\tif (value instanceof Boolean) {\n\t\t\treturn (Boolean) value;\n\t\t}\n\t\tif (value instanceof String stringValue) {\n\t\t\tif (\"true\".equalsIgnoreCase(stringValue)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\"false\".equalsIgnoreCase(stringValue)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Double toDouble(Object value) {\n\t\tif (value instanceof Double) {\n\t\t\treturn (Double) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).doubleValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn Double.valueOf((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Integer toInteger(Object value) {\n\t\tif (value instanceof Integer) {\n\t\t\treturn (Integer) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).intValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn (int) Double.parseDouble((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Long toLong(Object value) {\n\t\tif (value instanceof Long) {\n\t\t\treturn (Long) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).longValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn (long) Double.parseDouble((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic String toString(Object value) {\n\t\tif (value instanceof String) {\n\t\t\treturn (String) value;\n\t\t}\n\t\tif (value != null) {\n\t\t\treturn String.valueOf(value);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static JSONException typeMismatch(Object indexOrName, Object actual, String requiredType)\n\t\t\tthrows JSONException {\n\t\tif (actual == null) {\n\t\t\tthrow new JSONException(\"Value at \" + indexOrName + \" is null.\");\n\t\t}\n\t\tthrow new JSONException(\"Value \" + actual + \" at \" + indexOrName + \" of type \" + actual.getClass().getName()\n\t\t\t\t+ \" cannot be converted to \" + requiredType);\n\t}\n\n\tpublic static JSONException typeMismatch(Object actual, String requiredType) throws JSONException {\n\t\tif (actual == null) {\n\t\t\tthrow new JSONException(\"Value is null.\");\n\t\t}\n\t\tthrow new JSONException(\"Value \" + actual + \" of type \" + actual.getClass().getName()\n\t\t\t\t+ \" cannot be converted to \" + requiredType);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/JSONArray.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.json;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * A dense indexed sequence of values. Values may be any mix of {@link JSONObject\n * JSONObjects}, other {@link JSONArray JSONArrays}, Strings, Booleans, Integers, Longs,\n * Doubles, {@code null} or {@link JSONObject#NULL}. Values may not be\n * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not\n * listed here.\n * <p>\n * {@code JSONArray} has the same type coercion behavior and optional/mandatory accessors\n * as {@link JSONObject}. See that class' documentation for details.\n * <p>\n * <strong>Warning:</strong> this class represents null in two incompatible ways: the\n * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.\n * In particular, {@code get} fails if the requested index holds the null reference, but\n * succeeds if it holds {@code JSONObject.NULL}.\n * <p>\n * Instances of this class are not thread safe. Although this class is nonfinal, it was\n * not designed for inheritance and should not be subclassed. In particular, self-use by\n * overridable methods is not specified. See <i>Effective Java</i> Item 17, \"Design and\n * Document or inheritance or else prohibit it\" for further information.\n */\npublic class JSONArray {\n\n\tprivate final List<Object> values;\n\n\t/**\n\t * Creates a {@code JSONArray} with no values.\n\t */\n\tpublic JSONArray() {\n\t\tthis.values = new ArrayList<>();\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} by copying all values from the given collection.\n\t * @param copyFrom a collection whose values are of supported types. Unsupported\n\t * values are not permitted and will yield an array in an inconsistent state.\n\t */\n\t/* Accept a raw type for API compatibility */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic JSONArray(Collection copyFrom) {\n\t\tthis();\n\t\tif (copyFrom != null) {\n\t\t\tfor (Iterator it = copyFrom.iterator(); it.hasNext();) {\n\t\t\t\tput(JSONObject.wrap(it.next()));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the next array in the tokener.\n\t * @param readFrom a tokener whose nextValue() method will yield a {@code JSONArray}.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code JSONArray}.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray(JSONTokener readFrom) throws JSONException {\n\t\t/*\n\t\t * Getting the parser to populate this could get tricky. Instead, just parse to\n\t\t * temporary JSONArray and then steal the data from that.\n\t\t */\n\t\tObject object = readFrom.nextValue();\n\t\tif (object instanceof JSONArray) {\n\t\t\tthis.values = ((JSONArray) object).values;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the JSON string.\n\t * @param json a JSON-encoded string containing an array.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray(String json) throws JSONException {\n\t\tthis(new JSONTokener(json));\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the given primitive array.\n\t * @param array a primitive array\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray(Object array) throws JSONException {\n\t\tif (!array.getClass().isArray()) {\n\t\t\tthrow new JSONException(\"Not a primitive array: \" + array.getClass());\n\t\t}\n\t\tfinal int length = Array.getLength(array);\n\t\tthis.values = new ArrayList<>(length);\n\t\tfor (int i = 0; i < length; ++i) {\n\t\t\tput(JSONObject.wrap(Array.get(array, i)));\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of values in this array.\n\t * @return the length of this array\n\t */\n\tpublic int length() {\n\t\treturn this.values.size();\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(boolean value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(double value) throws JSONException {\n\t\tthis.values.add(JSON.checkDouble(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(int value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(long value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be\n\t * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. Unsupported\n\t * values are not permitted and will cause the array to be in an inconsistent state.\n\t * @return this array.\n\t */\n\tpublic JSONArray put(Object value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, boolean value) throws JSONException {\n\t\treturn put(index, (Boolean) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, double value) throws JSONException {\n\t\treturn put(index, (Double) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, int value) throws JSONException {\n\t\treturn put(index, (Integer) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, long value) throws JSONException {\n\t\treturn put(index, (Long) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be\n\t * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, Object value) throws JSONException {\n\t\tif (value instanceof Number) {\n\t\t\t// deviate from the original by checking all Numbers, not just floats &\n\t\t\t// doubles\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\t\twhile (this.values.size() <= index) {\n\t\t\tthis.values.add(null);\n\t\t}\n\t\tthis.values.set(index, value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns true if this array has no value at {@code index}, or if its value is the\n\t * {@code null} reference or {@link JSONObject#NULL}.\n\t * @param index the index to set the value to\n\t * @return true if this array has no value at {@code index}\n\t */\n\tpublic boolean isNull(int index) {\n\t\tObject value = opt(index);\n\t\treturn value == null || value == JSONObject.NULL;\n\t}\n\n\t/**\n\t * Returns the value at {@code index}.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index}.\n\t * @throws JSONException if this array has no value at {@code index}, or if that value\n\t * is the {@code null} reference. This method returns normally if the value is\n\t * {@code JSONObject#NULL}.\n\t */\n\tpublic Object get(int index) throws JSONException {\n\t\ttry {\n\t\t\tObject value = this.values.get(index);\n\t\t\tif (value == null) {\n\t\t\t\tthrow new JSONException(\"Value at \" + index + \" is null.\");\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcatch (IndexOutOfBoundsException e) {\n\t\t\tthrow new JSONException(\"Index \" + index + \" out of range [0..\" + this.values.size() + \")\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index}, or null if the array has no value at\n\t * {@code index}.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index} or {@code null}\n\t */\n\tpublic Object opt(int index) {\n\t\tif (index < 0 || index >= this.values.size()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.values.get(index);\n\t}\n\n\t/**\n\t * Removes and returns the value at {@code index}, or null if the array has no value\n\t * at {@code index}.\n\t * @param index the index of the value to remove\n\t * @return the previous value at {@code index}\n\t */\n\tpublic Object remove(int index) {\n\t\tif (index < 0 || index >= this.values.size()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.values.remove(index);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a boolean.\n\t */\n\tpublic boolean getBoolean(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"boolean\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean. Returns false otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code false}\n\t */\n\tpublic boolean optBoolean(int index) {\n\t\treturn optBoolean(index, false);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic boolean optBoolean(int index, boolean fallback) {\n\t\tObject object = opt(index);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a double.\n\t */\n\tpublic double getDouble(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tDouble result = JSON.toDouble(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"double\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double. Returns {@code NaN} otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code NaN}\n\t */\n\tpublic double optDouble(int index) {\n\t\treturn optDouble(index, Double.NaN);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic double optDouble(int index, double fallback) {\n\t\tObject object = opt(index);\n\t\tDouble result = JSON.toDouble(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to an int.\n\t */\n\tpublic int getInt(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tInteger result = JSON.toInteger(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"int\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int. Returns 0 otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code 0}\n\t */\n\tpublic int optInt(int index) {\n\t\treturn optInt(index, 0);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic int optInt(int index, int fallback) {\n\t\tObject object = opt(index);\n\t\tInteger result = JSON.toInteger(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a long.\n\t */\n\tpublic long getLong(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tLong result = JSON.toLong(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"long\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long. Returns 0 otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code 0}\n\t */\n\tpublic long optLong(int index) {\n\t\treturn optLong(index, 0L);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic long optLong(int index, long fallback) {\n\t\tObject object = opt(index);\n\t\tLong result = JSON.toLong(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if no such value exists.\n\t */\n\tpublic String getString(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tString result = JSON.toString(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"String\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary. Returns\n\t * the empty string if no such value exists.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or an empty string\n\t */\n\tpublic String optString(int index) {\n\t\treturn optString(index, \"\");\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary. Returns\n\t * {@code fallback} if no such value exists.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic String optString(int index, String fallback) {\n\t\tObject object = opt(index);\n\t\tString result = JSON.toString(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONArray}.\n\t * @param index the index to get the value from\n\t * @return the array at {@code index}\n\t * @throws JSONException if the value doesn't exist or is not a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray getJSONArray(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tif (object instanceof JSONArray) {\n\t\t\treturn (JSONArray) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(index, object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONArray}. Returns null otherwise.\n\t * @param index the index to get the value from\n\t * @return the array at {@code index} or {@code null}\n\t */\n\tpublic JSONArray optJSONArray(int index) {\n\t\tObject object = opt(index);\n\t\treturn object instanceof JSONArray ? (JSONArray) object : null;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONObject}.\n\t * @param index the index to get the value from\n\t * @return the object at {@code index}\n\t * @throws JSONException if the value doesn't exist or is not a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject getJSONObject(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tif (object instanceof JSONObject) {\n\t\t\treturn (JSONObject) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(index, object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONObject}. Returns null otherwise.\n\t * @param index the index to get the value from\n\t * @return the object at {@code index} or {@code null}\n\t */\n\tpublic JSONObject optJSONObject(int index) {\n\t\tObject object = opt(index);\n\t\treturn object instanceof JSONObject ? (JSONObject) object : null;\n\t}\n\n\t/**\n\t * Returns a new object whose values are the values in this array, and whose names are\n\t * the values in {@code names}. Names and values are paired up by index from 0 through\n\t * to the shorter array's length. Names that are not strings will be coerced to\n\t * strings. This method returns null if either array is empty.\n\t * @param names the property names\n\t * @return a json object\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONObject toJSONObject(JSONArray names) throws JSONException {\n\t\tJSONObject result = new JSONObject();\n\t\tint length = Math.min(names.length(), this.values.size());\n\t\tif (length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString name = JSON.toString(names.opt(i));\n\t\t\tresult.put(name, opt(i));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a new string by alternating this array's values with {@code\n\t * separator}. This array's string values are quoted and have their special characters\n\t * escaped. For example, the array containing the strings '12\" pizza', 'taco' and\n\t * 'soda' joined on '+' returns this: <pre>\"12\\\" pizza\"+\"taco\"+\"soda\"</pre>\n\t * @param separator the separator to use\n\t * @return the joined value\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String join(String separator) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer();\n\t\tstringer.open(JSONStringer.Scope.NULL, \"\");\n\t\tfor (int i = 0, size = this.values.size(); i < size; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tstringer.out.append(separator);\n\t\t\t}\n\t\t\tstringer.value(this.values.get(i));\n\t\t}\n\t\tstringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, \"\");\n\t\treturn stringer.out.toString();\n\t}\n\n\t/**\n\t * Encodes this array as a compact JSON string, such as: <pre>[94043,90210]</pre>\n\t * @return a compact JSON string representation of this array\n\t */\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\twriteTo(stringer);\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Encodes this array as a human-readable JSON string for debugging, such as: <pre>\n\t * [\n\t *     94043,\n\t *     90210\n\t * ]</pre>\n\t * @param indentSpaces the number of spaces to indent for each level of nesting.\n\t * @return a human-readable JSON string of this array\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String toString(int indentSpaces) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer(indentSpaces);\n\t\twriteTo(stringer);\n\t\treturn stringer.toString();\n\t}\n\n\tvoid writeTo(JSONStringer stringer) throws JSONException {\n\t\tstringer.array();\n\t\tfor (Object value : this.values) {\n\t\t\tstringer.value(value);\n\t\t}\n\t\tstringer.endArray();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\treturn o instanceof JSONArray && ((JSONArray) o).values.equals(this.values);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\t// diverge from the original, which doesn't implement hashCode\n\t\treturn this.values.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/JSONException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.json;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Thrown to indicate a problem with the JSON API. Such problems include:\n * <ul>\n * <li>Attempts to parse or construct malformed documents\n * <li>Use of null as a name\n * <li>Use of numeric types not available to JSON, such as {@link Double#isNaN() NaNs} or\n * {@link Double#isInfinite() infinities}.\n * <li>Lookups using an out of range index or nonexistent name\n * <li>Type mismatches on lookups\n * </ul>\n * <p>\n * Although this is a checked exception, it is rarely recoverable. Most callers should\n * simply wrap this exception in an unchecked exception and rethrow: <pre class=\"code\">\n *     public JSONArray toJSONObject() {\n *     try {\n *         JSONObject result = new JSONObject();\n *         ...\n *     } catch (JSONException e) {\n *         throw new RuntimeException(e);\n *     }\n * }</pre>\n */\npublic class JSONException extends Exception {\n\n\tpublic JSONException(String s) {\n\t\tsuper(s);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/JSONObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.json;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * A modifiable set of name/value mappings. Names are unique, non-null strings. Values may\n * be any mix of {@link JSONObject JSONObjects}, {@link JSONArray JSONArrays}, Strings,\n * Booleans, Integers, Longs, Doubles or {@link #NULL}. Values may not be {@code null},\n * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not\n * listed here.\n * <p>\n * This class can coerce values to another type when requested.\n * <ul>\n * <li>When the requested type is a boolean, strings will be coerced using a\n * case-insensitive comparison to \"true\" and \"false\".\n * <li>When the requested type is a double, other {@link Number} types will be coerced\n * using {@link Number#doubleValue() doubleValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be.\n * <li>When the requested type is an int, other {@link Number} types will be coerced using\n * {@link Number#intValue() intValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be, and then cast to int.\n * <li><a id=\"lossy\">When the requested type is a long, other {@link Number} types will be\n * coerced using {@link Number#longValue() longValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be, and then cast to long. This two-step conversion\n * is lossy for very large values. For example, the string \"9223372036854775806\" yields\n * the long 9223372036854775807.</a>\n * <li>When the requested type is a String, other non-null values will be coerced using\n * {@link String#valueOf(Object)}. Although null cannot be coerced, the sentinel value\n * {@link JSONObject#NULL} is coerced to the string \"null\".\n * </ul>\n * <p>\n * This class can look up both mandatory and optional values:\n * <ul>\n * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This fails with a\n * {@code JSONException} if the requested name has no value or if the value cannot be\n * coerced to the requested type.\n * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This returns a\n * system- or user-supplied default if the requested name has no value or if the value\n * cannot be coerced to the requested type.\n * </ul>\n * <p>\n * <strong>Warning:</strong> this class represents null in two incompatible ways: the\n * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.\n * In particular, calling {@code put(name, null)} removes the named entry from the object\n * but {@code put(name, JSONObject.NULL)} stores an entry whose value is\n * {@code JSONObject.NULL}.\n * <p>\n * Instances of this class are not thread safe. Although this class is nonfinal, it was\n * not designed for inheritance and should not be subclassed. In particular, self-use by\n * overrideable methods is not specified. See <i>Effective Java</i> Item 17, \"Design and\n * Document or inheritance or else prohibit it\" for further information.\n */\npublic class JSONObject {\n\n\tprivate static final Double NEGATIVE_ZERO = -0d;\n\n\t/**\n\t * A sentinel value used to explicitly define a name with no value. Unlike\n\t * {@code null}, names with this value:\n\t * <ul>\n\t * <li>show up in the {@link #names} array\n\t * <li>show up in the {@link #keys} iterator\n\t * <li>return {@code true} for {@link #has(String)}\n\t * <li>do not throw on {@link #get(String)}\n\t * <li>are included in the encoded JSON string.\n\t * </ul>\n\t * <p>\n\t * This value violates the general contract of {@link Object#equals} by returning true\n\t * when compared to {@code null}. Its {@link #toString} method returns \"null\".\n\t */\n\tpublic static final Object NULL = new Object() {\n\n\t\t@Override\n\t\tpublic boolean equals(Object o) {\n\t\t\treturn o == this || o == null; // API specifies this broken equals\n\t\t\t\t\t\t\t\t\t\t\t// implementation\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"null\";\n\t\t}\n\n\t};\n\n\tprivate final Map<String, Object> nameValuePairs;\n\n\t/**\n\t * Creates a {@code JSONObject} with no name/value mappings.\n\t */\n\tpublic JSONObject() {\n\t\tthis.nameValuePairs = new LinkedHashMap<>();\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} by copying all name/value mappings from the given\n\t * map.\n\t * @param copyFrom a map whose keys are of type {@link String} and whose values are of\n\t * supported types.\n\t * @throws NullPointerException if any of the map's keys are null.\n\t */\n\t/* (accept a raw type for API compatibility) */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic JSONObject(Map copyFrom) {\n\t\tthis();\n\t\tMap<?, ?> contentsTyped = copyFrom;\n\t\tfor (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {\n\t\t\t/*\n\t\t\t * Deviate from the original by checking that keys are non-null and of the\n\t\t\t * proper type. (We still defer validating the values).\n\t\t\t */\n\t\t\tString key = (String) entry.getKey();\n\t\t\tif (key == null) {\n\t\t\t\tthrow new NullPointerException(\"key == null\");\n\t\t\t}\n\t\t\tthis.nameValuePairs.put(key, wrap(entry.getValue()));\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} with name/value mappings from the next object in\n\t * the tokener.\n\t * @param readFrom a tokener whose nextValue() method will yield a {@code JSONObject}.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.\n\t */\n\tpublic JSONObject(JSONTokener readFrom) throws JSONException {\n\t\t/*\n\t\t * Getting the parser to populate this could get tricky. Instead, just parse to\n\t\t * temporary JSONObject and then steal the data from that.\n\t\t */\n\t\tObject object = readFrom.nextValue();\n\t\tif (object instanceof JSONObject) {\n\t\t\tthis.nameValuePairs = ((JSONObject) object).nameValuePairs;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} with name/value mappings from the JSON string.\n\t * @param json a JSON-encoded string containing an object.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject(String json) throws JSONException {\n\t\tthis(new JSONTokener(json));\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} by copying mappings for the listed names from the\n\t * given object. Names that aren't present in {@code copyFrom} will be skipped.\n\t * @param copyFrom the source\n\t * @param names the property names\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject(JSONObject copyFrom, String[] names) throws JSONException {\n\t\tthis();\n\t\tfor (String name : names) {\n\t\t\tObject value = copyFrom.opt(name);\n\t\t\tif (value != null) {\n\t\t\t\tthis.nameValuePairs.put(name, value);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of name/value mappings in this object.\n\t * @return the number of name/value mappings in this object\n\t */\n\tpublic int length() {\n\t\treturn this.nameValuePairs.size();\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, boolean value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, double value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), JSON.checkDouble(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, int value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, long value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name. If the value is {@code null}, any existing mapping for {@code name}\n\t * is removed.\n\t * @param name the name of the property\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link #NULL}, or {@code null}. May not be {@link Double#isNaN()\n\t * NaNs} or {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, Object value) throws JSONException {\n\t\tif (value == null) {\n\t\t\tthis.nameValuePairs.remove(name);\n\t\t\treturn this;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\t// deviate from the original by checking all Numbers, not just floats &\n\t\t\t// doubles\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Equivalent to {@code put(name, value)} when both parameters are non-null; does\n\t * nothing otherwise.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject putOpt(String name, Object value) throws JSONException {\n\t\tif (name == null || value == null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn put(name, value);\n\t}\n\n\t/**\n\t * Appends {@code value} to the array already mapped to {@code name}. If this object\n\t * has no mapping for {@code name}, this inserts a new mapping. If the mapping exists\n\t * but its value is not an array, the existing and new values are inserted in order\n\t * into a new array which is itself mapped to {@code name}. In aggregate, this allows\n\t * values to be added to a mapping one at a time.\n\t * @param name the name of the property\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject accumulate(String name, Object value) throws JSONException {\n\t\tObject current = this.nameValuePairs.get(checkName(name));\n\t\tif (current == null) {\n\t\t\treturn put(name, value);\n\t\t}\n\n\t\t// check in accumulate, since array.put(Object) doesn't do any checking\n\t\tif (value instanceof Number) {\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\n\t\tif (current instanceof JSONArray array) {\n\t\t\tarray.put(value);\n\t\t}\n\t\telse {\n\t\t\tJSONArray array = new JSONArray();\n\t\t\tarray.put(current);\n\t\t\tarray.put(value);\n\t\t\tthis.nameValuePairs.put(name, array);\n\t\t}\n\t\treturn this;\n\t}\n\n\tString checkName(String name) throws JSONException {\n\t\tif (name == null) {\n\t\t\tthrow new JSONException(\"Names must be non-null\");\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * Removes the named mapping if it exists; does nothing otherwise.\n\t * @param name the name of the property\n\t * @return the value previously mapped by {@code name}, or null if there was no such\n\t * mapping.\n\t */\n\tpublic Object remove(String name) {\n\t\treturn this.nameValuePairs.remove(name);\n\t}\n\n\t/**\n\t * Returns true if this object has no mapping for {@code name} or if it has a mapping\n\t * whose value is {@link #NULL}.\n\t * @param name the name of the property\n\t * @return true if this object has no mapping for {@code name}\n\t */\n\tpublic boolean isNull(String name) {\n\t\tObject value = this.nameValuePairs.get(name);\n\t\treturn value == null || value == NULL;\n\t}\n\n\t/**\n\t * Returns true if this object has a mapping for {@code name}. The mapping may be\n\t * {@link #NULL}.\n\t * @param name the name of the property\n\t * @return true if this object has a mapping for {@code name}\n\t */\n\tpublic boolean has(String name) {\n\t\treturn this.nameValuePairs.containsKey(name);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if no such mapping exists.\n\t */\n\tpublic Object get(String name) throws JSONException {\n\t\tObject result = this.nameValuePairs.get(name);\n\t\tif (result == null) {\n\t\t\tthrow new JSONException(\"No value for \" + name);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name}, or null if no such mapping exists.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic Object opt(String name) {\n\t\treturn this.nameValuePairs.get(name);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a\n\t * boolean.\n\t */\n\tpublic boolean getBoolean(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"boolean\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean. Returns false otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic boolean optBoolean(String name) {\n\t\treturn optBoolean(name, false);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic boolean optBoolean(String name, boolean fallback) {\n\t\tObject object = opt(name);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a\n\t * double.\n\t */\n\tpublic double getDouble(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tDouble result = JSON.toDouble(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"double\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double. Returns {@code NaN} otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code NaN}\n\t */\n\tpublic double optDouble(String name) {\n\t\treturn optDouble(name, Double.NaN);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic double optDouble(String name, double fallback) {\n\t\tObject object = opt(name);\n\t\tDouble result = JSON.toDouble(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to an int.\n\t */\n\tpublic int getInt(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tInteger result = JSON.toInteger(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"int\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int. Returns 0 otherwise.\n\t * @param name the name of the property\n\t * @return the value of {@code 0}\n\t */\n\tpublic int optInt(String name) {\n\t\treturn optInt(name, 0);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic int optInt(String name, int fallback) {\n\t\tObject object = opt(name);\n\t\tInteger result = JSON.toInteger(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Note that JSON represents numbers as doubles, so this is\n\t * <a href=\"#lossy\">lossy</a>; use strings to transfer numbers over JSON.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a long.\n\t */\n\tpublic long getLong(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tLong result = JSON.toLong(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"long\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as\n\t * doubles, so this is <a href=\"#lossy\">lossy</a>; use strings to transfer numbers via\n\t * JSON.\n\t * @param name the name of the property\n\t * @return the value or {@code 0L}\n\t */\n\tpublic long optLong(String name) {\n\t\treturn optLong(name, 0L);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents\n\t * numbers as doubles, so this is <a href=\"#lossy\">lossy</a>; use strings to transfer\n\t * numbers over JSON.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic long optLong(String name, long fallback) {\n\t\tObject object = opt(name);\n\t\tLong result = JSON.toLong(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if no such mapping exists.\n\t */\n\tpublic String getString(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tString result = JSON.toString(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"String\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * Returns the empty string if no such mapping exists.\n\t * @param name the name of the property\n\t * @return the value or an empty string\n\t */\n\tpublic String optString(String name) {\n\t\treturn optString(name, \"\");\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * Returns {@code fallback} if no such mapping exists.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic String optString(String name, String fallback) {\n\t\tObject object = opt(name);\n\t\tString result = JSON.toString(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONArray}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or is not a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray getJSONArray(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tif (object instanceof JSONArray) {\n\t\t\treturn (JSONArray) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(name, object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONArray}. Returns null otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic JSONArray optJSONArray(String name) {\n\t\tObject object = opt(name);\n\t\treturn object instanceof JSONArray ? (JSONArray) object : null;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONObject}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or is not a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject getJSONObject(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tif (object instanceof JSONObject) {\n\t\t\treturn (JSONObject) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(name, object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONObject}. Returns null otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic JSONObject optJSONObject(String name) {\n\t\tObject object = opt(name);\n\t\treturn object instanceof JSONObject ? (JSONObject) object : null;\n\t}\n\n\t/**\n\t * Returns an array with the values corresponding to {@code names}. The array contains\n\t * null for names that aren't mapped. This method returns null if {@code names} is\n\t * either null or empty.\n\t * @param names the names of the properties\n\t * @return the array\n\t */\n\tpublic JSONArray toJSONArray(JSONArray names) {\n\t\tJSONArray result = new JSONArray();\n\t\tif (names == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint length = names.length();\n\t\tif (length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString name = JSON.toString(names.opt(i));\n\t\t\tresult.put(opt(name));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns an iterator of the {@code String} names in this object. The returned\n\t * iterator supports {@link Iterator#remove() remove}, which will remove the\n\t * corresponding mapping from this object. If this object is modified after the\n\t * iterator is returned, the iterator's behavior is undefined. The order of the keys\n\t * is undefined.\n\t * @return the keys\n\t */\n\t/* Return a raw type for API compatibility */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Iterator keys() {\n\t\treturn this.nameValuePairs.keySet().iterator();\n\t}\n\n\t/**\n\t * Returns an array containing the string names in this object. This method returns\n\t * null if this object contains no mappings.\n\t * @return the array\n\t */\n\tpublic JSONArray names() {\n\t\treturn this.nameValuePairs.isEmpty() ? null : new JSONArray(new ArrayList<>(this.nameValuePairs.keySet()));\n\t}\n\n\t/**\n\t * Encodes this object as a compact JSON string, such as:\n\t * <pre>{\"query\":\"Pizza\",\"locations\":[94043,90210]}</pre>\n\t * @return a string representation of the object.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\twriteTo(stringer);\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Encodes this object as a human-readable JSON string for debugging, such as: <pre>\n\t * {\n\t *     \"query\": \"Pizza\",\n\t *     \"locations\": [\n\t *         94043,\n\t *         90210\n\t *     ]\n\t * }</pre>\n\t * @param indentSpaces the number of spaces to indent for each level of nesting.\n\t * @return a string representation of the object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic String toString(int indentSpaces) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer(indentSpaces);\n\t\twriteTo(stringer);\n\t\treturn stringer.toString();\n\t}\n\n\tvoid writeTo(JSONStringer stringer) throws JSONException {\n\t\tstringer.object();\n\t\tfor (Map.Entry<String, Object> entry : this.nameValuePairs.entrySet()) {\n\t\t\tstringer.key(entry.getKey()).value(entry.getValue());\n\t\t}\n\t\tstringer.endObject();\n\t}\n\n\t/**\n\t * Encodes the number as a JSON string.\n\t * @param number a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return the encoded value\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic static String numberToString(Number number) throws JSONException {\n\t\tif (number == null) {\n\t\t\tthrow new JSONException(\"Number must be non-null\");\n\t\t}\n\n\t\tdouble doubleValue = number.doubleValue();\n\t\tJSON.checkDouble(doubleValue);\n\n\t\t// the original returns \"-0\" instead of \"-0.0\" for negative zero\n\t\tif (number.equals(NEGATIVE_ZERO)) {\n\t\t\treturn \"-0\";\n\t\t}\n\n\t\tlong longValue = number.longValue();\n\t\tif (doubleValue == longValue) {\n\t\t\treturn Long.toString(longValue);\n\t\t}\n\n\t\treturn number.toString();\n\t}\n\n\t/**\n\t * Encodes {@code data} as a JSON string. This applies quotes and any necessary\n\t * character escaping.\n\t * @param data the string to encode. Null will be interpreted as an empty string.\n\t * @return the quoted value\n\t */\n\tpublic static String quote(String data) {\n\t\tif (data == null) {\n\t\t\treturn \"\\\"\\\"\";\n\t\t}\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\tstringer.open(JSONStringer.Scope.NULL, \"\");\n\t\t\tstringer.value(data);\n\t\t\tstringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, \"\");\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\tthrow new AssertionError();\n\t\t}\n\t}\n\n\t/**\n\t * Wraps the given object if necessary.\n\t * <p>\n\t * If the object is null or, returns {@link #NULL}. If the object is a\n\t * {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. If the object is\n\t * {@code NULL}, no wrapping is necessary. If the object is an array or\n\t * {@code Collection}, returns an equivalent {@code JSONArray}. If the object is a\n\t * {@code Map}, returns an equivalent {@code JSONObject}. If the object is a primitive\n\t * wrapper type or {@code String}, returns the object. Otherwise if the object is from\n\t * a {@code java} package, returns the result of {@code toString}. If wrapping fails,\n\t * returns null.\n\t * @param o the object to wrap\n\t * @return the wrapped object\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Object wrap(Object o) {\n\t\tif (o == null) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif (o instanceof JSONArray || o instanceof JSONObject) {\n\t\t\treturn o;\n\t\t}\n\t\tif (o.equals(NULL)) {\n\t\t\treturn o;\n\t\t}\n\t\ttry {\n\t\t\tif (o instanceof Collection) {\n\t\t\t\treturn new JSONArray((Collection) o);\n\t\t\t}\n\t\t\telse if (o.getClass().isArray()) {\n\t\t\t\treturn new JSONArray(o);\n\t\t\t}\n\t\t\tif (o instanceof Map) {\n\t\t\t\treturn new JSONObject((Map) o);\n\t\t\t}\n\t\t\tif (o instanceof Boolean || o instanceof Byte || o instanceof Character || o instanceof Double\n\t\t\t\t\t|| o instanceof Float || o instanceof Integer || o instanceof Long || o instanceof Short\n\t\t\t\t\t|| o instanceof String) {\n\t\t\t\treturn o;\n\t\t\t}\n\t\t\tif (o.getClass().getPackage().getName().startsWith(\"java.\")) {\n\t\t\t\treturn o.toString();\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/JSONStringer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.json;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most application\n * developers should use those methods directly and disregard this API. For example:<pre>\n * JSONObject object = ...\n * String json = object.toString();</pre>\n * <p>\n * Stringers only encode well-formed JSON strings. In particular:\n * <ul>\n * <li>The stringer must have exactly one top-level array or object.\n * <li>Lexical scopes must be balanced: every call to {@link #array} must have a matching\n * call to {@link #endArray} and every call to {@link #object} must have a matching call\n * to {@link #endObject}.\n * <li>Arrays may not contain keys (property names).\n * <li>Objects must alternate keys (property names) and values.\n * <li>Values are inserted with either literal {@link #value(Object) value} calls, or by\n * nesting arrays or objects.\n * </ul>\n * Calls that would result in a malformed JSON string will fail with a\n * {@link JSONException}.\n * <p>\n * This class provides no facility for pretty-printing (ie. indenting) output. To encode\n * indented output, use {@link JSONObject#toString(int)} or\n * {@link JSONArray#toString(int)}.\n * <p>\n * Some implementations of the API support at most 20 levels of nesting. Attempts to\n * create more than 20 levels of nesting may fail with a {@link JSONException}.\n * <p>\n * Each stringer may be used to encode a single top level value. Instances of this class\n * are not thread safe. Although this class is nonfinal, it was not designed for\n * inheritance and should not be subclassed. In particular, self-use by overrideable\n * methods is not specified. See <i>Effective Java</i> Item 17, \"Design and Document or\n * inheritance or else prohibit it\" for further information.\n */\npublic class JSONStringer {\n\n\t/**\n\t * The output data, containing at most one top-level array or object.\n\t */\n\tfinal StringBuilder out = new StringBuilder();\n\n\t/**\n\t * Lexical scoping elements within this stringer, necessary to insert the appropriate\n\t * separator characters (i.e. commas and colons) and to detect nesting errors.\n\t */\n\tenum Scope {\n\n\t\t/**\n\t\t * An array with no elements requires no separators or newlines before it is\n\t\t * closed.\n\t\t */\n\t\tEMPTY_ARRAY,\n\n\t\t/**\n\t\t * An array with at least one value requires a comma and newline before the next\n\t\t * element.\n\t\t */\n\t\tNONEMPTY_ARRAY,\n\n\t\t/**\n\t\t * An object with no keys or values requires no separators or newlines before it\n\t\t * is closed.\n\t\t */\n\t\tEMPTY_OBJECT,\n\n\t\t/**\n\t\t * An object whose most recent element is a key. The next element must be a value.\n\t\t */\n\t\tDANGLING_KEY,\n\n\t\t/**\n\t\t * An object with at least one name/value pair requires a comma and newline before\n\t\t * the next element.\n\t\t */\n\t\tNONEMPTY_OBJECT,\n\n\t\t/**\n\t\t * A special bracketless array needed by JSONStringer.join() and\n\t\t * JSONObject.quote() only. Not used for JSON encoding.\n\t\t */\n\t\tNULL\n\n\t}\n\n\t/**\n\t * Unlike the original implementation, this stack isn't limited to 20 levels of\n\t * nesting.\n\t */\n\tprivate final List<Scope> stack = new ArrayList<>();\n\n\t/**\n\t * A string containing a full set of spaces for a single level of indentation, or null\n\t * for no pretty printing.\n\t */\n\tprivate final String indent;\n\n\tpublic JSONStringer() {\n\t\tthis.indent = null;\n\t}\n\n\tJSONStringer(int indentSpaces) {\n\t\tchar[] indentChars = new char[indentSpaces];\n\t\tArrays.fill(indentChars, ' ');\n\t\tthis.indent = new String(indentChars);\n\t}\n\n\t/**\n\t * Begins encoding a new array. Each call to this method must be paired with a call to\n\t * {@link #endArray}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer array() throws JSONException {\n\t\treturn open(Scope.EMPTY_ARRAY, \"[\");\n\t}\n\n\t/**\n\t * Ends encoding the current array.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer endArray() throws JSONException {\n\t\treturn close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, \"]\");\n\t}\n\n\t/**\n\t * Begins encoding a new object. Each call to this method must be paired with a call\n\t * to {@link #endObject}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer object() throws JSONException {\n\t\treturn open(Scope.EMPTY_OBJECT, \"{\");\n\t}\n\n\t/**\n\t * Ends encoding the current object.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer endObject() throws JSONException {\n\t\treturn close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, \"}\");\n\t}\n\n\t/**\n\t * Enters a new scope by appending any necessary whitespace and the given bracket.\n\t * @param empty any necessary whitespace\n\t * @param openBracket the open bracket\n\t * @return this object\n\t * @throws JSONException if processing of json failed\n\t */\n\tJSONStringer open(Scope empty, String openBracket) throws JSONException {\n\t\tif (this.stack.isEmpty() && !this.out.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem: multiple top-level roots\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.stack.add(empty);\n\t\tthis.out.append(openBracket);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Closes the current scope by appending any necessary whitespace and the given\n\t * bracket.\n\t * @param empty any necessary whitespace\n\t * @param nonempty the current scope\n\t * @param closeBracket the close bracket\n\t * @return the JSON stringer\n\t * @throws JSONException if processing of json failed\n\t */\n\tJSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {\n\t\tScope context = peek();\n\t\tif (context != nonempty && context != empty) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\n\t\tthis.stack.remove(this.stack.size() - 1);\n\t\tif (context == nonempty) {\n\t\t\tnewline();\n\t\t}\n\t\tthis.out.append(closeBracket);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the value on the top of the stack.\n\t * @return the scope\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate Scope peek() throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\treturn this.stack.get(this.stack.size() - 1);\n\t}\n\n\t/**\n\t * Replace the value on the top of the stack with the given value.\n\t * @param topOfStack the scope at the top of the stack\n\t */\n\tprivate void replaceTop(Scope topOfStack) {\n\t\tthis.stack.set(this.stack.size() - 1, topOfStack);\n\t}\n\n\t/**\n\t * Encodes {@code value}.\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double or null. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(Object value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\n\t\tif (value instanceof JSONArray) {\n\t\t\t((JSONArray) value).writeTo(this);\n\t\t\treturn this;\n\t\t}\n\t\telse if (value instanceof JSONObject) {\n\t\t\t((JSONObject) value).writeTo(this);\n\t\t\treturn this;\n\t\t}\n\n\t\tbeforeValue();\n\n\t\tif (value == null || value instanceof Boolean || value == JSONObject.NULL) {\n\t\t\tthis.out.append(value);\n\n\t\t}\n\t\telse if (value instanceof Number) {\n\t\t\tthis.out.append(JSONObject.numberToString((Number) value));\n\n\t\t}\n\t\telse {\n\t\t\tstring(value.toString());\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value the value to encode\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(boolean value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(double value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(JSONObject.numberToString(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value the value to encode\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(long value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(value);\n\t\treturn this;\n\t}\n\n\tprivate void string(String value) {\n\t\tthis.out.append(\"\\\"\");\n\t\tfor (int i = 0, length = value.length(); i < length; i++) {\n\t\t\tchar c = value.charAt(i);\n\n\t\t\t/*\n\t\t\t * From RFC 4627, \"All Unicode characters may be placed within the quotation\n\t\t\t * marks except for the characters that must be escaped: quotation mark,\n\t\t\t * reverse solidus, and the control characters (U+0000 through U+001F).\"\n\t\t\t */\n\t\t\tswitch (c) {\n\t\t\t\tcase '\"', '\\\\', '/' -> this.out.append('\\\\').append(c);\n\t\t\t\tcase '\\t' -> this.out.append(\"\\\\t\");\n\t\t\t\tcase '\\b' -> this.out.append(\"\\\\b\");\n\t\t\t\tcase '\\n' -> this.out.append(\"\\\\n\");\n\t\t\t\tcase '\\r' -> this.out.append(\"\\\\r\");\n\t\t\t\tcase '\\f' -> this.out.append(\"\\\\f\");\n\t\t\t\tdefault -> {\n\t\t\t\t\tif (c <= 0x1F) {\n\t\t\t\t\t\tthis.out.append(String.format(\"\\\\u%04x\", (int) c));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.out.append(c);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tthis.out.append(\"\\\"\");\n\t}\n\n\tprivate void newline() {\n\t\tif (this.indent == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.out.append(\"\\n\");\n\t\tthis.out.append(this.indent.repeat(this.stack.size()));\n\t}\n\n\t/**\n\t * Encodes the key (property name) to this stringer.\n\t * @param name the name of the forthcoming value. May not be null.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer key(String name) throws JSONException {\n\t\tif (name == null) {\n\t\t\tthrow new JSONException(\"Names must be non-null\");\n\t\t}\n\t\tbeforeKey();\n\t\tstring(name);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Inserts any necessary separators and whitespace before a name. Also adjusts the\n\t * stack to expect the key's value.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate void beforeKey() throws JSONException {\n\t\tScope context = peek();\n\t\tif (context == Scope.NONEMPTY_OBJECT) { // first in object\n\t\t\tthis.out.append(',');\n\t\t}\n\t\telse if (context != Scope.EMPTY_OBJECT) { // not in an object!\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tnewline();\n\t\treplaceTop(Scope.DANGLING_KEY);\n\t}\n\n\t/**\n\t * Inserts any necessary separators and whitespace before a literal value, inline\n\t * array, or inline object. Also adjusts the stack to expect either a closing bracket\n\t * or another element.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate void beforeValue() throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\n\t\tScope context = peek();\n\t\tif (context == Scope.EMPTY_ARRAY) { // first in array\n\t\t\treplaceTop(Scope.NONEMPTY_ARRAY);\n\t\t\tnewline();\n\t\t}\n\t\telse if (context == Scope.NONEMPTY_ARRAY) { // another in array\n\t\t\tthis.out.append(',');\n\t\t\tnewline();\n\t\t}\n\t\telse if (context == Scope.DANGLING_KEY) { // value for key\n\t\t\tthis.out.append(this.indent == null ? \":\" : \": \");\n\t\t\treplaceTop(Scope.NONEMPTY_OBJECT);\n\t\t}\n\t\telse if (context != Scope.NULL) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the encoded JSON string.\n\t * <p>\n\t * If invoked with unterminated arrays or unclosed objects, this method's return value\n\t * is undefined.\n\t * <p>\n\t * <strong>Warning:</strong> although it contradicts the general contract of\n\t * {@link Object#toString}, this method returns null if the stringer contains no data.\n\t * @return the encoded JSON string.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn this.out.isEmpty() ? null : this.out.toString();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/JSONTokener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.json;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Parses a JSON (<a href=\"https://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>) encoded\n * string into the corresponding object. Most clients of this class will use only need the\n * {@link #JSONTokener(String) constructor} and {@link #nextValue} method. Example usage:\n * <pre>\n * String json = \"{\"\n *         + \"  \\\"query\\\": \\\"Pizza\\\", \"\n *         + \"  \\\"locations\\\": [ 94043, 90210 ] \"\n *         + \"}\";\n *\n * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();\n * String query = object.getString(\"query\");\n * JSONArray locations = object.getJSONArray(\"locations\");</pre>\n * <p>\n * For best interoperability and performance use JSON that complies with RFC 4627, such as\n * that generated by {@link JSONStringer}. For legacy reasons this parser is lenient, so a\n * successful parse does not indicate that the input string was valid JSON. All the\n * following syntax errors will be ignored:\n * <ul>\n * <li>End of line comments starting with {@code //} or {@code #} and ending with a\n * newline character.\n * <li>C-style comments starting with {@code /*} and ending with {@code *}{@code /}. Such\n * comments may not be nested.\n * <li>Strings that are unquoted or {@code 'single quoted'}.\n * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.\n * <li>Octal integers prefixed with {@code 0}.\n * <li>Array elements separated by {@code ;}.\n * <li>Unnecessary array separators. These are interpreted as if null was the omitted\n * value.\n * <li>Key-value pairs separated by {@code =} or {@code =>}.\n * <li>Key-value pairs separated by {@code ;}.\n * </ul>\n * <p>\n * Each tokener may be used to parse a single JSON string. Instances of this class are not\n * thread safe. Although this class is nonfinal, it was not designed for inheritance and\n * should not be subclassed. In particular, self-use by overrideable methods is not\n * specified. See <i>Effective Java</i> Item 17, \"Design and Document or inheritance or\n * else prohibit it\" for further information.\n */\npublic class JSONTokener {\n\n\t/**\n\t * The input JSON.\n\t */\n\tprivate final String in;\n\n\t/**\n\t * The index of the next character to be returned by {@link #next}. When the input is\n\t * exhausted, this equals the input's length.\n\t */\n\tprivate int pos;\n\n\t/**\n\t * @param in JSON encoded string. Null is not permitted and will yield a tokener that\n\t * throws {@code NullPointerExceptions} when methods are called.\n\t */\n\tpublic JSONTokener(String in) {\n\t\t// consume an optional byte order mark (BOM) if it exists\n\t\tif (in != null && in.startsWith(\"\\ufeff\")) {\n\t\t\tin = in.substring(1);\n\t\t}\n\t\tthis.in = in;\n\t}\n\n\t/**\n\t * Returns the next value from the input.\n\t * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,\n\t * Double or {@link JSONObject#NULL}.\n\t * @throws JSONException if the input is malformed.\n\t */\n\tpublic Object nextValue() throws JSONException {\n\t\tint c = nextCleanInternal();\n\t\tswitch (c) {\n\t\t\tcase -1:\n\t\t\t\tthrow syntaxError(\"End of input\");\n\n\t\t\tcase '{':\n\t\t\t\treturn readObject();\n\n\t\t\tcase '[':\n\t\t\t\treturn readArray();\n\n\t\t\tcase '\\'', '\"':\n\t\t\t\treturn nextString((char) c);\n\n\t\t\tdefault:\n\t\t\t\tthis.pos--;\n\t\t\t\treturn readLiteral();\n\t\t}\n\t}\n\n\tprivate int nextCleanInternal() throws JSONException {\n\t\twhile (this.pos < this.in.length()) {\n\t\t\tint c = this.in.charAt(this.pos++);\n\t\t\tswitch (c) {\n\t\t\t\tcase '\\t', ' ', '\\n', '\\r':\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcase '/':\n\t\t\t\t\tif (this.pos == this.in.length()) {\n\t\t\t\t\t\treturn c;\n\t\t\t\t\t}\n\n\t\t\t\t\tchar peek = this.in.charAt(this.pos);\n\t\t\t\t\tswitch (peek) {\n\t\t\t\t\t\tcase '*':\n\t\t\t\t\t\t\t// skip a /* c-style comment */\n\t\t\t\t\t\t\tthis.pos++;\n\t\t\t\t\t\t\tint commentEnd = this.in.indexOf(\"*/\", this.pos);\n\t\t\t\t\t\t\tif (commentEnd == -1) {\n\t\t\t\t\t\t\t\tthrow syntaxError(\"Unterminated comment\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.pos = commentEnd + 2;\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tcase '/':\n\t\t\t\t\t\t\t// skip a // end-of-line comment\n\t\t\t\t\t\t\tthis.pos++;\n\t\t\t\t\t\t\tskipToEndOfLine();\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn c;\n\t\t\t\t\t}\n\n\t\t\t\tcase '#':\n\t\t\t\t\t/*\n\t\t\t\t\t * Skip a # hash end-of-line comment. The JSON RFC doesn't specify\n\t\t\t\t\t * this behavior, but it's required to parse existing documents. See\n\t\t\t\t\t * https://b/2571423.\n\t\t\t\t\t */\n\t\t\t\t\tskipToEndOfLine();\n\t\t\t\t\tcontinue;\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn c;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Advances the position until after the next newline character. If the line is\n\t * terminated by \"\\r\\n\", the '\\n' must be consumed as whitespace by the caller.\n\t */\n\tprivate void skipToEndOfLine() {\n\t\tfor (; this.pos < this.in.length(); this.pos++) {\n\t\t\tchar c = this.in.charAt(this.pos);\n\t\t\tif (c == '\\r' || c == '\\n') {\n\t\t\t\tthis.pos++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the string up to but not including {@code quote}, unescaping any character\n\t * escape sequences encountered along the way. The opening quote should have already\n\t * been read. This consumes the closing quote, but does not include it in the returned\n\t * string.\n\t * @param quote either ' or \".\n\t * @return the string up to but not including {@code quote}\n\t * @throws NumberFormatException if any unicode escape sequences are malformed.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String nextString(char quote) throws JSONException {\n\t\t/*\n\t\t * For strings that are free of escape sequences, we can just extract the result\n\t\t * as a substring of the input. But if we encounter an escape sequence, we need to\n\t\t * use a StringBuilder to compose the result.\n\t\t */\n\t\tStringBuilder builder = null;\n\n\t\t/* the index of the first character not yet appended to the builder. */\n\t\tint start = this.pos;\n\n\t\twhile (this.pos < this.in.length()) {\n\t\t\tint c = this.in.charAt(this.pos++);\n\t\t\tif (c == quote) {\n\t\t\t\tif (builder == null) {\n\t\t\t\t\t// a new string avoids leaking memory\n\t\t\t\t\treturn new String(this.in.substring(start, this.pos - 1));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuilder.append(this.in, start, this.pos - 1);\n\t\t\t\t\treturn builder.toString();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (c == '\\\\') {\n\t\t\t\tif (this.pos == this.in.length()) {\n\t\t\t\t\tthrow syntaxError(\"Unterminated escape sequence\");\n\t\t\t\t}\n\t\t\t\tif (builder == null) {\n\t\t\t\t\tbuilder = new StringBuilder();\n\t\t\t\t}\n\t\t\t\tbuilder.append(this.in, start, this.pos - 1);\n\t\t\t\tbuilder.append(readEscapeCharacter());\n\t\t\t\tstart = this.pos;\n\t\t\t}\n\t\t}\n\n\t\tthrow syntaxError(\"Unterminated string\");\n\t}\n\n\t/**\n\t * Unescapes the character identified by the character or characters that immediately\n\t * follow a backslash. The backslash '\\' should have already been read. This supports\n\t * both unicode escapes \"u000A\" and two-character escapes \"\\n\".\n\t * @return the unescaped char\n\t * @throws NumberFormatException if any unicode escape sequences are malformed.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate char readEscapeCharacter() throws JSONException {\n\t\tchar escaped = this.in.charAt(this.pos++);\n\t\tswitch (escaped) {\n\t\t\tcase 'u':\n\t\t\t\tif (this.pos + 4 > this.in.length()) {\n\t\t\t\t\tthrow syntaxError(\"Unterminated escape sequence\");\n\t\t\t\t}\n\t\t\t\tString hex = this.in.substring(this.pos, this.pos + 4);\n\t\t\t\tthis.pos += 4;\n\t\t\t\treturn (char) Integer.parseInt(hex, 16);\n\n\t\t\tcase 't':\n\t\t\t\treturn '\\t';\n\n\t\t\tcase 'b':\n\t\t\t\treturn '\\b';\n\n\t\t\tcase 'n':\n\t\t\t\treturn '\\n';\n\n\t\t\tcase 'r':\n\t\t\t\treturn '\\r';\n\n\t\t\tcase 'f':\n\t\t\t\treturn '\\f';\n\n\t\t\tcase '\\'', '\"', '\\\\':\n\t\t\tdefault:\n\t\t\t\treturn escaped;\n\t\t}\n\t}\n\n\t/**\n\t * Reads a null, boolean, numeric or unquoted string literal value. Numeric values\n\t * will be returned as an Integer, Long, or Double, in that order of preference.\n\t * @return a literal value\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate Object readLiteral() throws JSONException {\n\t\tString literal = nextToInternal(\"{}[]/\\\\:,=;# \\t\\f\");\n\n\t\tif (literal.isEmpty()) {\n\t\t\tthrow syntaxError(\"Expected literal value\");\n\t\t}\n\t\telse if (\"null\".equalsIgnoreCase(literal)) {\n\t\t\treturn JSONObject.NULL;\n\t\t}\n\t\telse if (\"true\".equalsIgnoreCase(literal)) {\n\t\t\treturn Boolean.TRUE;\n\t\t}\n\t\telse if (\"false\".equalsIgnoreCase(literal)) {\n\t\t\treturn Boolean.FALSE;\n\t\t}\n\n\t\t/* try to parse as an integral type... */\n\t\tif (literal.indexOf('.') == -1) {\n\t\t\tint base = 10;\n\t\t\tString number = literal;\n\t\t\tif (number.startsWith(\"0x\") || number.startsWith(\"0X\")) {\n\t\t\t\tnumber = number.substring(2);\n\t\t\t\tbase = 16;\n\t\t\t}\n\t\t\telse if (number.startsWith(\"0\") && number.length() > 1) {\n\t\t\t\tnumber = number.substring(1);\n\t\t\t\tbase = 8;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tlong longValue = Long.parseLong(number, base);\n\t\t\t\tif (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {\n\t\t\t\t\treturn (int) longValue;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn longValue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (NumberFormatException e) {\n\t\t\t\t/*\n\t\t\t\t * This only happens for integral numbers greater than Long.MAX_VALUE,\n\t\t\t\t * numbers in exponential form (5e-10) and unquoted strings. Fall through\n\t\t\t\t * to try floating point.\n\t\t\t\t */\n\t\t\t}\n\t\t}\n\n\t\t/* ...next try to parse as a floating point... */\n\t\ttry {\n\t\t\treturn Double.valueOf(literal);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\t// Ignore\n\t\t}\n\n\t\t/* ... finally give up. We have an unquoted string */\n\t\treturn new String(literal); // a new string avoids leaking memory\n\t}\n\n\t/**\n\t * Returns the string up to but not including any of the given characters or a newline\n\t * character. This does not consume the excluded character.\n\t * @return the string up to but not including any of the given characters or a newline\n\t * character\n\t */\n\tprivate String nextToInternal(String excluded) {\n\t\tint start = this.pos;\n\t\tfor (; this.pos < this.in.length(); this.pos++) {\n\t\t\tchar c = this.in.charAt(this.pos);\n\t\t\tif (c == '\\r' || c == '\\n' || excluded.indexOf(c) != -1) {\n\t\t\t\treturn this.in.substring(start, this.pos);\n\t\t\t}\n\t\t}\n\t\treturn this.in.substring(start);\n\t}\n\n\t/**\n\t * Reads a sequence of key/value pairs and the trailing closing brace '}' of an\n\t * object. The opening brace '{' should have already been read.\n\t * @return an object\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate JSONObject readObject() throws JSONException {\n\t\tJSONObject result = new JSONObject();\n\n\t\t/* Peek to see if this is the empty object. */\n\t\tint first = nextCleanInternal();\n\t\tif (first == '}') {\n\t\t\treturn result;\n\t\t}\n\t\telse if (first != -1) {\n\t\t\tthis.pos--;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tObject name = nextValue();\n\t\t\tif (!(name instanceof String)) {\n\t\t\t\tif (name == null) {\n\t\t\t\t\tthrow syntaxError(\"Names cannot be null\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow syntaxError(\n\t\t\t\t\t\t\t\"Names must be strings, but \" + name + \" is of type \" + name.getClass().getName());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Expect the name/value separator to be either a colon ':', an equals sign\n\t\t\t * '=', or an arrow \"=>\". The last two are bogus but we include them because\n\t\t\t * that's what the original implementation did.\n\t\t\t */\n\t\t\tint separator = nextCleanInternal();\n\t\t\tif (separator != ':' && separator != '=') {\n\t\t\t\tthrow syntaxError(\"Expected ':' after \" + name);\n\t\t\t}\n\t\t\tif (this.pos < this.in.length() && this.in.charAt(this.pos) == '>') {\n\t\t\t\tthis.pos++;\n\t\t\t}\n\n\t\t\tresult.put((String) name, nextValue());\n\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase '}':\n\t\t\t\t\treturn result;\n\t\t\t\tcase ';', ',':\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow syntaxError(\"Unterminated object\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reads a sequence of values and the trailing closing brace ']' of an array. The\n\t * opening brace '[' should have already been read. Note that \"[]\" yields an empty\n\t * array, but \"[,]\" returns a two-element array equivalent to \"[null,null]\".\n\t * @return an array\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate JSONArray readArray() throws JSONException {\n\t\tJSONArray result = new JSONArray();\n\n\t\t/* to cover input that ends with \",]\". */\n\t\tboolean hasTrailingSeparator = false;\n\n\t\twhile (true) {\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase -1:\n\t\t\t\t\tthrow syntaxError(\"Unterminated array\");\n\t\t\t\tcase ']':\n\t\t\t\t\tif (hasTrailingSeparator) {\n\t\t\t\t\t\tresult.put(null);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\tcase ',', ';':\n\t\t\t\t\t/* A separator without a value first means \"null\". */\n\t\t\t\t\tresult.put(null);\n\t\t\t\t\thasTrailingSeparator = true;\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.pos--;\n\t\t\t}\n\n\t\t\tresult.put(nextValue());\n\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase ']':\n\t\t\t\t\treturn result;\n\t\t\t\tcase ',', ';':\n\t\t\t\t\thasTrailingSeparator = true;\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow syntaxError(\"Unterminated array\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns an exception containing the given message plus the current position and the\n\t * entire input string.\n\t * @param message the message\n\t * @return an exception\n\t */\n\tpublic JSONException syntaxError(String message) {\n\t\treturn new JSONException(message + this);\n\t}\n\n\t/**\n\t * Returns the current position and the entire input string.\n\t * @return the current position and the entire input string.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\t// consistent with the original implementation\n\t\treturn \" at character \" + this.pos + \" of \" + this.in;\n\t}\n\n\t/*\n\t * Legacy APIs.\n\t *\n\t * None of the methods below are on the critical path of parsing JSON documents. They\n\t * exist only because they were exposed by the original implementation and may be used\n\t * by some clients.\n\t */\n\n\tpublic boolean more() {\n\t\treturn this.pos < this.in.length();\n\t}\n\n\tpublic char next() {\n\t\treturn this.pos < this.in.length() ? this.in.charAt(this.pos++) : '\\0';\n\t}\n\n\tpublic char next(char c) throws JSONException {\n\t\tchar result = next();\n\t\tif (result != c) {\n\t\t\tthrow syntaxError(\"Expected \" + c + \" but was \" + result);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic char nextClean() throws JSONException {\n\t\tint nextCleanInt = nextCleanInternal();\n\t\treturn nextCleanInt == -1 ? '\\0' : (char) nextCleanInt;\n\t}\n\n\tpublic String next(int length) throws JSONException {\n\t\tif (this.pos + length > this.in.length()) {\n\t\t\tthrow syntaxError(length + \" is out of bounds\");\n\t\t}\n\t\tString result = this.in.substring(this.pos, this.pos + length);\n\t\tthis.pos += length;\n\t\treturn result;\n\t}\n\n\tpublic String nextTo(String excluded) {\n\t\tif (excluded == null) {\n\t\t\tthrow new NullPointerException(\"excluded == null\");\n\t\t}\n\t\treturn nextToInternal(excluded).trim();\n\t}\n\n\tpublic String nextTo(char excluded) {\n\t\treturn nextToInternal(String.valueOf(excluded)).trim();\n\t}\n\n\tpublic void skipPast(String thru) {\n\t\tint thruStart = this.in.indexOf(thru, this.pos);\n\t\tthis.pos = thruStart == -1 ? this.in.length() : (thruStart + thru.length());\n\t}\n\n\tpublic char skipTo(char to) {\n\t\tint index = this.in.indexOf(to, this.pos);\n\t\tif (index != -1) {\n\t\t\tthis.pos = index;\n\t\t\treturn to;\n\t\t}\n\t\telse {\n\t\t\treturn '\\0';\n\t\t}\n\t}\n\n\tpublic void back() {\n\t\tif (--this.pos == -1) {\n\t\t\tthis.pos = 0;\n\t\t}\n\t}\n\n\tpublic static int dehexchar(char hex) {\n\t\tif (hex >= '0' && hex <= '9') {\n\t\t\treturn hex - '0';\n\t\t}\n\t\telse if (hex >= 'A' && hex <= 'F') {\n\t\t\treturn hex - 'A' + 10;\n\t\t}\n\t\telse if (hex >= 'a' && hex <= 'f') {\n\t\t\treturn hex - 'a' + 10;\n\t\t}\n\t\telse {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/json-shade/java/org/springframework/boot/cli/json/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullUnmarked\npackage org.springframework.boot.cli.json;\n\nimport org.jspecify.annotations.NullUnmarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/content/INSTALL.txt",
    "content": "SPRING BOOT CLI - INSTALLATION\n==============================\n\nThank you for downloading the Spring Boot CLI tool. Please follow these instructions\nin order to complete your installation.\n\n\nPrerequisites\n-------------\nSpring Boot CLI requires Java JDK 17 or above in order to run.\n\nThe CLI will use whatever JDK it finds on your path, to check that you have an appropriate\nversion you should run:\n\n\tjava -version\n\nAlternatively, you can set the JAVA_HOME environment variable to point a suitable JDK.\n\n\nEnvironment Variables\n---------------------\nNo specific environment variables are required to run the CLI, however, you may want to\nset SPRING_HOME to point to a specific installation. You should also add SPRING_HOME/bin\nto your PATH environment variable.\n\n\nShell Completion\n----------------\nShell auto-completion scripts are provided for BASH and ZSH. Add symlinks to the appropriate\nlocation for your environment. For example, something like:\n\n  ln -s ./shell-completion/bash/spring /etc/bash_completion.d/spring\n  ln -s ./shell-completion/zsh/_spring /usr/local/share/zsh/site-functions/_spring\n\n\nChecking Your Installation\n--------------------------\nTo test if you have successfully installed the CLI you can run the following command:\n\n\tspring --version\n\n\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/content/LICENCE.txt",
    "content": "Copyright 2012-2013 the original author or authors.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/content/bin/spring.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n:setSpringHome\n@rem Setup SPRING_HOME if not already defined\nif defined SPRING_HOME goto setJavaHome\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset SPRING_HOME=%DIRNAME%\\..\n\n:setJavaHome\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto runSpring\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\nif exist \"%JAVA_EXE%\" goto runSpring\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\ngoto fail\n\n:runSpring\n@rem Get command-line arguments, handling Windows variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%SPRING_HOME%\\lib\\*\n\"%JAVA_EXE%\" %JAVA_OPTS% -cp \"%CLASSPATH%\" org.springframework.boot.loader.launch.JarLauncher %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable SPRING_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%SPRING_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/content/legal/open_source_licenses.txt",
    "content": "open_source_licenses.txt\n\nSpring Boot CLI\n==================================================================\n\nVMware makes available all content in this download (\"Content\").\nUnless otherwise indicated below, the Content is provided to you under\nthe terms and conditions of the Apache License 2.0 (the \"License\"). A\ncopy of the license is available in the file called LICENSE.txt or you\n may obtain a copy of the License at\n\n    https://www.apache.org/licenses/LICENSE-2.0\n\nThe following copyright statements and licenses apply to various open\nsource software packages (or portions thereof) that are distributed with\nthis content.\n\n\n=================================================================\nTABLE OF CONTENTS\n=================================================================\n\n\nThe following is a listing of the open source components detailed in this\ndocument.  This list is provided for your convenience; please read further if\nyou wish to review the copyright notice(s) and the full text of the license\nassociated with each component.\n\n\nSECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES\n\n   >>> JLine (jline:jline)\n   >>> JOpt Simple (net.sf.jopt-simple:jopt-simple)\n   >>> ASM 4.0 (org.ow2.asm:asm)\n\n\nSECTION 2: Apache License, V2.0\n\n   >>> JSON library from Android SDK (com.vaadin.external.google:android-json)\n   >>> Apache Commons Codec (commons-codec:commons-codec)\n   >>> Apache HttpClient (org.apache.httpcomponents:httpclient)\n   >>> Apache HttpCore (org.apache.httpcomponents:httpcore)\n   >>> Plexus Cipher: encryption/decryption Component (org.sonatype.plexus:plexus-cipher)\n   >>> Plexus Security Dispatcher Component (org.sonatype.plexus:plexus-sec-dispatcher)\n   >>> Apache Commons Logging (commons-logging:commons-logging)\n   >>> Apache Groovy (org.apache.groovy:groovy)\n   >>> Maven Aether Provider (org.apache.maven:maven-aether-provider)\n   >>> Maven Model (org.apache.maven:maven-model)\n   >>> Maven Model Builder (org.apache.maven:maven-model-builder)\n   >>> Maven Repository Metadata Model (org.apache.maven:maven-repository-metadata)\n   >>> Maven Settings (org.apache.maven:maven-settings)\n   >>> Maven Settings Builder (org.apache.maven:maven-settings-builder)\n   >>> Plexus :: Component Annotations (org.codehaus.plexus:plexus-component-annotations)\n   >>> Plexus Common Utilities (org.codehaus.plexus:plexus-utils)\n   >>> Plexus Component API (org.codehaus.plexus:plexus-component-api)\n   >>> Plexus Interpolation API (org.codehaus.plexus:plexus-interpolation)\n\n\nSECTION 3: Eclipse Public License, Version 1.0\n\n   >>> Aether API (org.eclipse.aether:aether-api)\n   >>> Aether Connector Basic (org.eclipse.aether:aether-connector-basic)\n   >>> Aether Implementation (org.eclipse.aether:aether-impl)\n   >>> Aether SPI (org.eclipse.aether:aether-spi)\n   >>> Aether Transport File (org.eclipse.aether:aether-transport-file)\n   >>> Aether Transport HTTP (org.eclipse.aether:aether-transport-http)\n   >>> Aether Utilities (org.eclipse.aether:aether-util)\n\n\n\n--------------- SECTION 1:  BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES ----------\n\nBSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES are applicable to the following component(s).\n\n\n>>> JLine (jline:jline)\n\nCopyright (c) 2002-2006, Marc Prud'hommeaux <mwp1@cornell.edu>\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or\nwithout modification, are permitted provided that the following\nconditions are met:\n\nRedistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright\nnotice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with\nthe distribution.\n\nNeither the name of JLine nor the names of its contributors\nmay be used to endorse or promote products derived from this\nsoftware without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\nBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\nEVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\nOR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\nPROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\nAND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\nOF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n>>> net.sf.jopt-simple:jopt-simple:4.5\n\nThe MIT License (MIT)\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n\n>>> org.ow2.asm:asm\n\nCopyright (c) 2000-2011 INRIA, France Telecom\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holders nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGE.\n\n\n\n--------------- SECTION 2: Apache License, V2.0 ----------\n\nApache License, V2.0 is applicable to the following component(s).\n\n\n>>> org.apache.httpcomponents:httpclient\n>>> org.apache.httpcomponents:httpcore\n>>> org.sonatype.plexus:plexus-cipher\n>>> org.sonatype.plexus:plexus-sec-dispatcher\n>>> commons-logging:commons-logging\n>>> org.apache.groovy:groovy\n>>> org.apache.maven:maven-aether-provider\n>>> org.apache.maven:maven-model\n>>> org.apache.maven:maven-model-builder\n>>> org.apache.maven:maven-repository-metadata\n>>> org.apache.maven:maven-settings\n>>> org.apache.maven:maven-settings-builder\n>>> org.codehaus.plexus:plexus-component-annotations\n>>> org.codehaus.plexus:plexus-utils\n>>> org.codehaus.plexus:plexus-component-api\n>>> org.codehaus.plexus:plexus-interpolation\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttps://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License\n\n>>> CGLIB 3.0 (cglib:cglib:3.0):\n\nPer the LICENSE file in the CGLIB JAR distribution downloaded from\nhttps://sourceforge.net/projects/cglib/files/cglib3/3.0/cglib-3.0.jar/download,\nCGLIB 3.0 is licensed under the Apache License, version 2.0, the text of which\nis included above.\n\n\n--------------- SECTION 3: Eclipse Public License, Version 1.0 ----------\n\nEclipse Public License, Version 1.0 is applicable to the following component(s).\n\n>>> org.eclipse.aether:aether-api\n>>> org.eclipse.aether:aether-connector-basic\n>>> org.eclipse.aether:aether-impl\n>>> org.eclipse.aether:aether-spi\n>>> org.eclipse.aether:aether-transport-file\n>>> org.eclipse.aether:aether-transport-http\n>>> org.eclipse.aether:aether-util\n\nThe Eclipse Foundation makes available all content in this plug-in (\"Content\").\nUnless otherwise  indicated below, the Content is provided to you under the terms\nand conditions  of the Eclipse Public License Version 1.0 (\"EPL\").  A copy of the\nEPL is available  at https://www.eclipse.org/legal/epl-v10.html.\n\nFor purposes of the EPL, \"Program\" will mean the Content.\n\nIf you did not receive this Content directly from the Eclipse Foundation, the\nContent is  being redistributed by another party (\"Redistributor\") and different\nterms and conditions may apply to your use of any object code in the Content.\nCheck the Redistributor's license that was provided with the Content.  If no such\nlicense exists, contact the Redistributor.  Unless otherwise indicated below, the\nterms and conditions of the EPL still apply to any source code in the Content and\nsuch source code may be obtained at https://www.eclipse.org/\n\n\n\n===========================================================================\n\nTo the extent any open source subcomponents are licensed under the EPL and/or\nother similar licenses that require the source code and/or modifications to\nsource code to be made available (as would be noted above), you may obtain a\ncopy of the source code corresponding to the binaries for such open source\ncomponents and modifications thereto, if any, (the \"Source Files\"), by\ndownloading the Source Files from https://github.com/spring-projects/spring-boot,\nor by sending a request, with your name and address to:\n\n    VMware, Inc., 875 Howard St,\n    San Francisco, CA 94103\n    United States of America\n\nor email ask@spring.io.  All such requests should clearly specify:\n\n    OPEN SOURCE FILES REQUEST\n    Attention General Counsel\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/content/shell-completion/bash/spring",
    "content": "# bash completion for spring\n# Installation: source this file locally in a terminal or from\n# ~/.bashrc or put it in /etc/bash_completions.d (debian)\n\n_spring()\n{\n\tlocal cur prev help helps words cword command commands i\n\n\t_get_comp_words_by_ref cur prev words cword\n\n\tCOMPREPLY=()\n\n\twhile read -r line; do\n\t\treply=`echo \"$line\" | awk '{print $1;}'`\n\t\tCOMPREPLY+=(\"$reply\")\n\tdone < <(spring hint ${cword} ${words[*]})\n\n\tif [ $cword -ne 1 ]; then\n\t\t_filedir\n\tfi\n\n} && complete -F _spring spring\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/content/shell-completion/zsh/_spring",
    "content": "#compdef spring 'spring'\n#autoload\n\n_spring() {\n\n\tlocal cword\n\tlet cword=CURRENT-1\n\n\tlocal hints\n\thints=()\n\n\tlocal reply\n\twhile read -r line; do\n\t\treply=`echo \"$line\" | awk '{printf $1 \":\"; for (i=2; i<NF; i++) printf $i \" \"; print $NF}'`\n\t\thints+=(\"$reply\")\n\tdone < <(spring hint ${cword} ${words[*]})\n\n\tif ((cword == 1)) {\n\t\t_describe -t commands 'commands' hints\n\t\treturn 0\n\t}\n\n\t_describe -t options 'options' hints\n\t_files\n\n\treturn 0\n}\n\n_spring \"$@\"\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/executablecontent/bin/spring",
    "content": "#!/usr/bin/env bash\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\ndarwin=false\ncase \"$(uname)\" in\n\tCYGWIN*)\n\t\tcygwin=true\n\t\t;;\n\n\tMINGW*)\n\t\tcygwin=true\n\t\t;;\n\n\tDarwin*)\n\t\tdarwin=true\n\t\t;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n\t[ -n \"${JAVA_HOME}\" ] && JAVA_HOME=$(cygpath --unix \"${JAVA_HOME}\")\nfi\n\n# Attempt to find JAVA_HOME if not already set\nif [ -z \"${JAVA_HOME}\" ]; then\n\tif ${darwin} ; then\n\t\tif [[ -z \"${JAVA_HOME}\" && -f \"/usr/libexec/java_home\" ]]; then\n\t\t\tJAVA_HOME=$(/usr/libexec/java_home)\n\t\t\texport JAVA_HOME\n\t\tfi\n\t\tif [[ -z \"${JAVA_HOME}\" && -d \"/Library/Java/Home\" ]]; then\n\t\t\texport JAVA_HOME=\"/Library/Java/Home\"\n\t\tfi\n\t\tif [[ -z \"${JAVA_HOME}\" && -d \"/System/Library/Frameworks/JavaVM.framework/Home\" ]]; then\n\t\t\texport JAVA_HOME=\"/System/Library/Frameworks/JavaVM.framework/Home\"\n\t\tfi\n\telse\n\t\tjavaExecutable=\"$(command -v javac)\"\n\t\tif [[ -z \"$javaExecutable\" || \"$(expr \"${javaExecutable}\" : '\\([^ ]*\\)')\" = \"no\" ]]; then\n\t\t\techo \"JAVA_HOME not set and cannot find javac to deduce location, please set JAVA_HOME.\"\n\t\t\texit 1\n\t\tfi\n\t\t# readlink(1) is not available as standard on Solaris 10.\n\t\treadLink=\"$(command -v readlink)\"\n\t\t[ \"$(expr \"${readLink}\" : '\\([^ ]*\\)')\" = \"no\" ] && {\n\t\t\techo \"JAVA_HOME not set and readlink not available, please set JAVA_HOME.\"\n\t\t\texit 1\n\t\t}\n\t\tjavaExecutable=\"$(readlink -f \"${javaExecutable}\")\"\n\t\tjavaHome=\"$(dirname \"${javaExecutable}\")\"\n\t\tjavaHome=$(expr \"$javaHome\" : '\\(.*\\)/bin')\n\t\tJAVA_HOME=\"${javaHome}\"\n\t\texport JAVA_HOME\n\tfi\nfi\n\n# Sanity check that we have java\nif [ ! -f \"${JAVA_HOME}/bin/java\" ]; then\n\tcat <<-JAVA_HOME_NOT_SET_TXT\n\n\t======================================================================================================\n\t Please ensure that your JAVA_HOME points to a valid Java SDK.\n\t You are currently pointing to:\n\n\t  ${JAVA_HOME}\n\n\t This does not seem to be valid. Please rectify and restart.\n\t======================================================================================================\n\n\tJAVA_HOME_NOT_SET_TXT\n\texit 1\nfi\n\n# Attempt to find SPRING_HOME if not already set\nif [ -z \"${SPRING_HOME}\" ]; then\n\t# Resolve links: $0 may be a link\n\tPRG=\"$0\"\n\t# Need this for relative symlinks.\n\twhile [ -h \"$PRG\" ] ; do\n\t\tls=$(ls -ld \"$PRG\")\n\t\tlink=$(expr \"$ls\" : '.*-> \\(.*\\)$')\n\t\tif expr \"$link\" : '/.*' > /dev/null; then\n\t\t\tPRG=\"$link\"\n\t\telse\n\t\t\tPRG=$(dirname \"$PRG\")\"/$link\"\n\t\tfi\n\tdone\n\tSAVED=\"$(pwd)\"\n\tcd \"$(dirname \"${PRG}\")/../\" > /dev/null || exit 1\n\tSPRING_HOME=\"$(pwd -P)\"\n\texport SPRING_HOME\n\tcd \"$SAVED\" > /dev/null || exit 1\nfi\n\nif [ ! -d \"${SPRING_HOME}\" ]; then\n\techo \"Not a directory: SPRING_HOME=${SPRING_HOME}\"\n\techo \"Please rectify and restart.\"\n\texit 2\nfi\n\n[[ \"${cygwin}\" == \"true\" ]] && SPRINGPATH=$(cygpath \"${SPRING_HOME}\") || SPRINGPATH=$SPRING_HOME\nCLASSPATH=${SPRINGPATH}/bin\nif [ -d \"${SPRINGPATH}/ext\" ]; then\n\tCLASSPATH=$CLASSPATH:${SPRINGPATH}/ext\nfi\nfor f in \"${SPRINGPATH}\"/lib/*; do\n\t[[ \"${cygwin}\" == \"true\" ]] && LIBFILE=$(cygpath \"$f\") || LIBFILE=$f\n\tCLASSPATH=$CLASSPATH:$LIBFILE\ndone\n\nif $cygwin; then\n\tSPRING_HOME=$(cygpath --path --mixed \"$SPRING_HOME\")\n\tCLASSPATH=$(cygpath --path --mixed \"$CLASSPATH\")\nfi\n\nIFS=\" \" read -r -a javaOpts <<< \"$JAVA_OPTS\"\nexec \"${JAVA_HOME}/bin/java\" \"${javaOpts[@]}\" -cp \"$CLASSPATH\" org.springframework.boot.loader.launch.JarLauncher \"$@\"\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/homebrew/spring-boot.rb",
    "content": "require 'formula'\n\nclass SpringBoot < Formula\n  homepage 'https://spring.io/projects/spring-boot'\n  url '${repo}/org/springframework/boot/spring-boot-cli/${version}/spring-boot-cli-${version}-bin.tar.gz'\n  version '${version}'\n  sha256 '${hash}'\n\n  def install\n    libexec.install Dir[\"./*\"]\n    (bin/\"spring\").write_env_script libexec/\"bin/spring\", {}\n\n    bash_comp = libexec/\"shell-completion/bash/spring\"\n    zsh_comp  = libexec/\"shell-completion/zsh/_spring\"\n\n    bash_completion.install bash_comp if bash_comp.exist?\n    zsh_completion.install  zsh_comp  if zsh_comp.exist?\n  end\nend\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/DefaultCommandFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.CommandFactory;\nimport org.springframework.boot.cli.command.core.VersionCommand;\nimport org.springframework.boot.cli.command.encodepassword.EncodePasswordCommand;\nimport org.springframework.boot.cli.command.init.InitCommand;\n\n/**\n * Default implementation of {@link CommandFactory}.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\npublic class DefaultCommandFactory implements CommandFactory {\n\n\tprivate static final List<Command> DEFAULT_COMMANDS;\n\n\tstatic {\n\t\tList<Command> defaultCommands = new ArrayList<>();\n\t\tdefaultCommands.add(new VersionCommand());\n\t\tdefaultCommands.add(new InitCommand());\n\t\tdefaultCommands.add(new EncodePasswordCommand());\n\t\tDEFAULT_COMMANDS = Collections.unmodifiableList(defaultCommands);\n\t}\n\n\t@Override\n\tpublic Collection<Command> getCommands() {\n\t\treturn DEFAULT_COMMANDS;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/SpringCli.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.ServiceLoader;\n\nimport org.springframework.boot.cli.command.CommandFactory;\nimport org.springframework.boot.cli.command.CommandRunner;\nimport org.springframework.boot.cli.command.core.HelpCommand;\nimport org.springframework.boot.cli.command.core.HintCommand;\nimport org.springframework.boot.cli.command.core.VersionCommand;\nimport org.springframework.boot.cli.command.shell.ShellCommand;\nimport org.springframework.boot.loader.tools.LogbackInitializer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.SystemPropertyUtils;\n\n/**\n * Spring Command Line Interface. This is the main entry-point for the Spring command line\n * application.\n *\n * @author Phillip Webb\n * @since 1.0.0\n * @see #main(String...)\n * @see CommandRunner\n */\npublic final class SpringCli {\n\n\tprivate SpringCli() {\n\t}\n\n\tpublic static void main(String... args) {\n\t\tSystem.setProperty(\"java.awt.headless\", Boolean.toString(true));\n\t\tLogbackInitializer.initialize();\n\n\t\tCommandRunner runner = new CommandRunner(\"spring\");\n\t\tClassUtils.overrideThreadContextClassLoader(createExtendedClassLoader(runner));\n\t\trunner.addCommand(new HelpCommand(runner));\n\t\taddServiceLoaderCommands(runner);\n\t\trunner.addCommand(new ShellCommand());\n\t\trunner.addCommand(new HintCommand(runner));\n\t\trunner.setOptionCommands(HelpCommand.class, VersionCommand.class);\n\t\trunner.setHiddenCommands(HintCommand.class);\n\n\t\tint exitCode = runner.runAndHandleErrors(args);\n\t\tif (exitCode != 0) {\n\t\t\t// If successful, leave it to run in case it's a server app\n\t\t\tSystem.exit(exitCode);\n\t\t}\n\t}\n\n\tprivate static void addServiceLoaderCommands(CommandRunner runner) {\n\t\tServiceLoader<CommandFactory> factories = ServiceLoader.load(CommandFactory.class);\n\t\tfor (CommandFactory factory : factories) {\n\t\t\trunner.addCommands(factory.getCommands());\n\t\t}\n\t}\n\n\tprivate static URLClassLoader createExtendedClassLoader(CommandRunner runner) {\n\t\treturn new URLClassLoader(getExtensionURLs(), runner.getClass().getClassLoader());\n\t}\n\n\tprivate static URL[] getExtensionURLs() {\n\t\tList<URL> urls = new ArrayList<>();\n\t\tString home = SystemPropertyUtils.resolvePlaceholders(\"${spring.home:${SPRING_HOME:.}}\");\n\t\tFile extDirectory = new File(new File(home, \"lib\"), \"ext\");\n\t\tif (extDirectory.isDirectory()) {\n\t\t\tFile[] files = extDirectory.listFiles();\n\t\t\tAssert.state(files != null, \"'files' must not be null\");\n\t\t\tfor (File file : files) {\n\t\t\t\tif (file.getName().endsWith(\".jar\")) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\turls.add(file.toURI().toURL());\n\t\t\t\t\t}\n\t\t\t\t\tcatch (MalformedURLException ex) {\n\t\t\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn urls.toArray(new URL[0]);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/AbstractCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.options.OptionHelp;\n\n/**\n * Abstract {@link Command} implementation.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @since 1.0.0\n */\npublic abstract class AbstractCommand implements Command {\n\n\tprivate final String name;\n\n\tprivate final String description;\n\n\t/**\n\t * Create a new {@link AbstractCommand} instance.\n\t * @param name the name of the command\n\t * @param description the command description\n\t */\n\tprotected AbstractCommand(String name, String description) {\n\t\tthis.name = name;\n\t\tthis.description = description;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\t@Override\n\tpublic @Nullable String getUsageHelp() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable String getHelp() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Collection<OptionHelp> getOptionsHelp() {\n\t\treturn Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic @Nullable Collection<HelpExample> getExamples() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/Command.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.options.OptionHelp;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * A single command that can be run from the CLI.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @since 1.0.0\n * @see #run(String...)\n */\npublic interface Command {\n\n\t/**\n\t * Returns the name of the command.\n\t * @return the command's name\n\t */\n\tString getName();\n\n\t/**\n\t * Returns a description of the command.\n\t * @return the command's description\n\t */\n\tString getDescription();\n\n\t/**\n\t * Returns usage help for the command. This should be a simple one-line string\n\t * describing basic usage. e.g. '[options] &lt;file&gt;'. Do not include the name of\n\t * the command in this string.\n\t * @return the command's usage help\n\t */\n\t@Nullable String getUsageHelp();\n\n\t/**\n\t * Gets full help text for the command, e.g. a longer description and one line per\n\t * option.\n\t * @return the command's help text\n\t */\n\t@Nullable String getHelp();\n\n\t/**\n\t * Returns help for each supported option.\n\t * @return help for each of the command's options\n\t */\n\tCollection<OptionHelp> getOptionsHelp();\n\n\t/**\n\t * Return some examples for the command.\n\t * @return the command's examples\n\t */\n\t@Nullable Collection<HelpExample> getExamples();\n\n\t/**\n\t * Run the command.\n\t * @param args command arguments (this will not include the command itself)\n\t * @return the outcome of the command\n\t * @throws Exception if the command fails\n\t */\n\tExitStatus run(String... args) throws Exception;\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CommandException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Runtime exception wrapper that defines additional {@link Option}s that are understood\n * by the {@link CommandRunner}.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class CommandException extends RuntimeException {\n\n\tprivate static final long serialVersionUID = 0L;\n\n\tprivate final EnumSet<Option> options;\n\n\t/**\n\t * Create a new {@link CommandException} with the specified options.\n\t * @param options the exception options\n\t */\n\tpublic CommandException(Option... options) {\n\t\tthis.options = asEnumSet(options);\n\t}\n\n\t/**\n\t * Create a new {@link CommandException} with the specified options.\n\t * @param message the exception message to display to the user\n\t * @param options the exception options\n\t */\n\tpublic CommandException(String message, Option... options) {\n\t\tsuper(message);\n\t\tthis.options = asEnumSet(options);\n\t}\n\n\t/**\n\t * Create a new {@link CommandException} with the specified options.\n\t * @param message the exception message to display to the user\n\t * @param cause the underlying cause\n\t * @param options the exception options\n\t */\n\tpublic CommandException(String message, Throwable cause, Option... options) {\n\t\tsuper(message, cause);\n\t\tthis.options = asEnumSet(options);\n\t}\n\n\t/**\n\t * Create a new {@link CommandException} with the specified options.\n\t * @param cause the underlying cause\n\t * @param options the exception options\n\t */\n\tpublic CommandException(Throwable cause, Option... options) {\n\t\tsuper(cause);\n\t\tthis.options = asEnumSet(options);\n\t}\n\n\tprivate EnumSet<Option> asEnumSet(Option @Nullable [] options) {\n\t\tif (options == null || options.length == 0) {\n\t\t\treturn EnumSet.noneOf(Option.class);\n\t\t}\n\t\treturn EnumSet.copyOf(Arrays.asList(options));\n\t}\n\n\t/**\n\t * Returns a set of options that are understood by the {@link CommandRunner}.\n\t * @return the options understood by the runner\n\t */\n\tpublic Set<Option> getOptions() {\n\t\treturn Collections.unmodifiableSet(this.options);\n\t}\n\n\t/**\n\t * Specific options understood by the {@link CommandRunner}.\n\t */\n\tpublic enum Option {\n\n\t\t/**\n\t\t * Hide the exception message.\n\t\t */\n\t\tHIDE_MESSAGE,\n\n\t\t/**\n\t\t * Print basic CLI usage information.\n\t\t */\n\t\tSHOW_USAGE,\n\n\t\t/**\n\t\t * Print the stack-trace of the exception.\n\t\t */\n\t\tSTACK_TRACE,\n\n\t\t/**\n\t\t * Re-throw the exception rather than dealing with it.\n\t\t */\n\t\tRETHROW\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CommandFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.Collection;\nimport java.util.ServiceLoader;\n\n/**\n * Factory used to create CLI {@link Command}s. Intended for use with a Java\n * {@link ServiceLoader}.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@FunctionalInterface\npublic interface CommandFactory {\n\n\t/**\n\t * Returns the CLI {@link Command}s.\n\t * @return the commands\n\t */\n\tCollection<Command> getCommands();\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CommandRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.Log;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Main class used to run {@link Command}s.\n *\n * @author Phillip Webb\n * @since 1.0.0\n * @see #addCommand(Command)\n * @see CommandRunner#runAndHandleErrors(String[])\n */\npublic class CommandRunner implements Iterable<Command> {\n\n\tprivate static final Set<CommandException.Option> NO_EXCEPTION_OPTIONS = EnumSet\n\t\t.noneOf(CommandException.Option.class);\n\n\tprivate final String name;\n\n\tprivate final List<Command> commands = new ArrayList<>();\n\n\tprivate Class<?>[] optionCommandClasses = {};\n\n\tprivate Class<?>[] hiddenCommandClasses = {};\n\n\t/**\n\t * Create a new {@link CommandRunner} instance.\n\t * @param name the name of the runner or {@code null}\n\t */\n\tpublic CommandRunner(@Nullable String name) {\n\t\tthis.name = StringUtils.hasLength(name) ? name + \" \" : \"\";\n\t}\n\n\t/**\n\t * Return the name of the runner or an empty string. Non-empty names will include a\n\t * trailing space character so that they can be used as a prefix.\n\t * @return the name of the runner\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Add the specified commands.\n\t * @param commands the commands to add\n\t */\n\tpublic void addCommands(Iterable<Command> commands) {\n\t\tAssert.notNull(commands, \"'commands' must not be null\");\n\t\tfor (Command command : commands) {\n\t\t\taddCommand(command);\n\t\t}\n\t}\n\n\t/**\n\t * Add the specified command.\n\t * @param command the command to add.\n\t */\n\tpublic void addCommand(Command command) {\n\t\tAssert.notNull(command, \"'command' must not be null\");\n\t\tthis.commands.add(command);\n\t}\n\n\t/**\n\t * Set the command classes which should be considered option commands. An option\n\t * command is a special type of command that usually makes more sense to present as if\n\t * it is an option. For example '--version'.\n\t * @param commandClasses the classes of option commands.\n\t * @see #isOptionCommand(Command)\n\t */\n\tpublic void setOptionCommands(Class<?>... commandClasses) {\n\t\tAssert.notNull(commandClasses, \"'commandClasses' must not be null\");\n\t\tthis.optionCommandClasses = commandClasses;\n\t}\n\n\t/**\n\t * Set the command classes which should be hidden (i.e. executed but not displayed in\n\t * the available commands list).\n\t * @param commandClasses the classes of hidden commands\n\t */\n\tpublic void setHiddenCommands(Class<?>... commandClasses) {\n\t\tAssert.notNull(commandClasses, \"'commandClasses' must not be null\");\n\t\tthis.hiddenCommandClasses = commandClasses;\n\t}\n\n\t/**\n\t * Returns if the specified command is an option command.\n\t * @param command the command to test\n\t * @return {@code true} if the command is an option command\n\t * @see #setOptionCommands(Class...)\n\t */\n\tpublic boolean isOptionCommand(Command command) {\n\t\treturn isCommandInstanceOf(command, this.optionCommandClasses);\n\t}\n\n\tprivate boolean isHiddenCommand(Command command) {\n\t\treturn isCommandInstanceOf(command, this.hiddenCommandClasses);\n\t}\n\n\tprivate boolean isCommandInstanceOf(Command command, Class<?>[] commandClasses) {\n\t\tfor (Class<?> commandClass : commandClasses) {\n\t\t\tif (commandClass.isInstance(command)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic Iterator<Command> iterator() {\n\t\treturn getCommands().iterator();\n\t}\n\n\tprotected final List<Command> getCommands() {\n\t\treturn Collections.unmodifiableList(this.commands);\n\t}\n\n\t/**\n\t * Find a command by name.\n\t * @param name the name of the command\n\t * @return the command or {@code null} if not found\n\t */\n\tpublic @Nullable Command findCommand(String name) {\n\t\tfor (Command candidate : this.commands) {\n\t\t\tString candidateName = candidate.getName();\n\t\t\tif (candidateName.equals(name) || (isOptionCommand(candidate) && (\"--\" + candidateName).equals(name))) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Run the appropriate and handle and errors.\n\t * @param args the input arguments\n\t * @return a return status code (non boot is used to indicate an error)\n\t */\n\tpublic int runAndHandleErrors(String... args) {\n\t\tString[] argsWithoutDebugFlags = removeDebugFlags(args);\n\t\tboolean debug = argsWithoutDebugFlags.length != args.length;\n\t\tif (debug) {\n\t\t\tSystem.setProperty(\"debug\", \"true\");\n\t\t}\n\t\ttry {\n\t\t\tExitStatus result = run(argsWithoutDebugFlags);\n\t\t\t// The caller will hang up if it gets a non-zero status\n\t\t\tif (result != null && result.isHangup()) {\n\t\t\t\treturn (result.getCode() > 0) ? result.getCode() : 0;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t\tcatch (NoArgumentsException ex) {\n\t\t\tshowUsage();\n\t\t\treturn 1;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn handleError(debug, ex);\n\t\t}\n\t}\n\n\tprivate String[] removeDebugFlags(String[] args) {\n\t\tList<String> rtn = new ArrayList<>(args.length);\n\t\tboolean appArgsDetected = false;\n\t\tfor (String arg : args) {\n\t\t\t// Allow apps to have a --debug argument\n\t\t\tappArgsDetected |= \"--\".equals(arg);\n\t\t\tif (\"--debug\".equals(arg) && !appArgsDetected) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trtn.add(arg);\n\t\t}\n\t\treturn StringUtils.toStringArray(rtn);\n\t}\n\n\t/**\n\t * Parse the arguments and run a suitable command.\n\t * @param args the arguments\n\t * @return the outcome of the command\n\t * @throws Exception if the command fails\n\t */\n\tprotected ExitStatus run(String... args) throws Exception {\n\t\tif (args.length == 0) {\n\t\t\tthrow new NoArgumentsException();\n\t\t}\n\t\tString commandName = args[0];\n\t\tString[] commandArguments = Arrays.copyOfRange(args, 1, args.length);\n\t\tCommand command = findCommand(commandName);\n\t\tif (command == null) {\n\t\t\tthrow new NoSuchCommandException(commandName);\n\t\t}\n\t\tbeforeRun(command);\n\t\ttry {\n\t\t\treturn command.run(commandArguments);\n\t\t}\n\t\tfinally {\n\t\t\tafterRun(command);\n\t\t}\n\t}\n\n\t/**\n\t * Subclass hook called before a command is run.\n\t * @param command the command about to run\n\t */\n\tprotected void beforeRun(Command command) {\n\t}\n\n\t/**\n\t * Subclass hook called after a command has run.\n\t * @param command the command that has run\n\t */\n\tprotected void afterRun(Command command) {\n\t}\n\n\tprivate int handleError(boolean debug, Exception ex) {\n\t\tSet<CommandException.Option> options = NO_EXCEPTION_OPTIONS;\n\t\tif (ex instanceof CommandException commandException) {\n\t\t\toptions = commandException.getOptions();\n\t\t\tif (options.contains(CommandException.Option.RETHROW)) {\n\t\t\t\tthrow commandException;\n\t\t\t}\n\t\t}\n\t\tboolean couldNotShowMessage = false;\n\t\tif (!options.contains(CommandException.Option.HIDE_MESSAGE)) {\n\t\t\tcouldNotShowMessage = !errorMessage(ex.getMessage());\n\t\t}\n\t\tif (options.contains(CommandException.Option.SHOW_USAGE)) {\n\t\t\tshowUsage();\n\t\t}\n\t\tif (debug || couldNotShowMessage || options.contains(CommandException.Option.STACK_TRACE)) {\n\t\t\tprintStackTrace(ex);\n\t\t}\n\t\treturn 1;\n\t}\n\n\tprotected boolean errorMessage(@Nullable String message) {\n\t\tLog.error((message != null) ? message : \"Unexpected error\");\n\t\treturn message != null;\n\t}\n\n\tprotected void showUsage() {\n\t\tLog.infoPrint(\"usage: \" + this.name);\n\t\tfor (Command command : this.commands) {\n\t\t\tif (isOptionCommand(command)) {\n\t\t\t\tLog.infoPrint(\"[--\" + command.getName() + \"] \");\n\t\t\t}\n\t\t}\n\t\tLog.info(\"\");\n\t\tLog.info(\"       <command> [<args>]\");\n\t\tLog.info(\"\");\n\t\tLog.info(\"Available commands are:\");\n\t\tfor (Command command : this.commands) {\n\t\t\tif (!isOptionCommand(command) && !isHiddenCommand(command)) {\n\t\t\t\tString usageHelp = command.getUsageHelp();\n\t\t\t\tString description = command.getDescription();\n\t\t\t\tLog.info(String.format(\"%n  %1$s %2$-15s%n    %3$s\", command.getName(),\n\t\t\t\t\t\t(usageHelp != null) ? usageHelp : \"\", (description != null) ? description : \"\"));\n\t\t\t}\n\t\t}\n\t\tLog.info(\"\");\n\t\tLog.info(\"Common options:\");\n\t\tLog.info(String.format(\"%n  %1$s %2$-15s%n    %3$s\", \"--debug\", \"Verbose mode\",\n\t\t\t\t\"Print additional status information for the command you are running\"));\n\t\tLog.info(\"\");\n\t\tLog.info(\"\");\n\t\tLog.info(\"See '\" + this.name + \"help <command>' for more information on a specific command.\");\n\t}\n\n\tprotected void printStackTrace(Exception ex) {\n\t\tLog.error(\"\");\n\t\tLog.error(ex);\n\t\tLog.error(\"\");\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/HelpExample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\n/**\n * An example that can be displayed in the help.\n *\n * @author Phillip Webb\n * @since 1.2.0\n */\npublic class HelpExample {\n\n\tprivate final String description;\n\n\tprivate final String example;\n\n\t/**\n\t * Create a new {@link HelpExample} instance.\n\t * @param description the description (in the form \"to ....\")\n\t * @param example the example\n\t */\n\tpublic HelpExample(String description, String example) {\n\t\tthis.description = description;\n\t\tthis.example = example;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic String getExample() {\n\t\treturn this.example;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/NoArgumentsException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\n/**\n * Exception used to indicate that no arguments were specified.\n *\n * @author Phillip Webb\n */\nclass NoArgumentsException extends CommandException {\n\n\tprivate static final long serialVersionUID = 1L;\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/NoHelpCommandArgumentsException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\n/**\n * Exception used to when the help command is called without arguments.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class NoHelpCommandArgumentsException extends CommandException {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic NoHelpCommandArgumentsException() {\n\t\tsuper(Option.SHOW_USAGE, Option.HIDE_MESSAGE);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/NoSuchCommandException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\n/**\n * Exception used when a command is not found.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class NoSuchCommandException extends CommandException {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic NoSuchCommandException(String name) {\n\t\tsuper(String.format(\"'%1$s' is not a valid command. See 'help'.\", name));\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/OptionParsingCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.cli.command.options.OptionHandler;\nimport org.springframework.boot.cli.command.options.OptionHelp;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * Base class for a {@link Command} that parse options using an {@link OptionHandler}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @since 1.0.0\n * @see OptionHandler\n */\npublic abstract class OptionParsingCommand extends AbstractCommand {\n\n\tprivate final OptionHandler handler;\n\n\tprotected OptionParsingCommand(String name, String description, OptionHandler handler) {\n\t\tsuper(name, description);\n\t\tthis.handler = handler;\n\t}\n\n\t@Override\n\tpublic String getHelp() {\n\t\treturn this.handler.getHelp();\n\t}\n\n\t@Override\n\tpublic Collection<OptionHelp> getOptionsHelp() {\n\t\treturn this.handler.getOptionsHelp();\n\t}\n\n\t@Override\n\tpublic final ExitStatus run(String... args) throws Exception {\n\t\treturn this.handler.run(args);\n\t}\n\n\tprotected OptionHandler getHandler() {\n\t\treturn this.handler;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/core/HelpCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.core;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.CommandRunner;\nimport org.springframework.boot.cli.command.HelpExample;\nimport org.springframework.boot.cli.command.NoHelpCommandArgumentsException;\nimport org.springframework.boot.cli.command.NoSuchCommandException;\nimport org.springframework.boot.cli.command.options.OptionHelp;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.Log;\n\n/**\n * Internal {@link Command} used for 'help' requests.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class HelpCommand extends AbstractCommand {\n\n\tprivate final CommandRunner commandRunner;\n\n\tpublic HelpCommand(CommandRunner commandRunner) {\n\t\tsuper(\"help\", \"Get help on commands\");\n\t\tthis.commandRunner = commandRunner;\n\t}\n\n\t@Override\n\tpublic String getUsageHelp() {\n\t\treturn \"command\";\n\t}\n\n\t@Override\n\tpublic @Nullable String getHelp() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Collection<OptionHelp> getOptionsHelp() {\n\t\tList<OptionHelp> help = new ArrayList<>();\n\t\tfor (Command command : this.commandRunner) {\n\t\t\tif (isHelpShown(command)) {\n\t\t\t\thelp.add(new OptionHelp() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Set<String> getOptions() {\n\t\t\t\t\t\treturn Collections.singleton(command.getName());\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic String getUsageHelp() {\n\t\t\t\t\t\treturn command.getDescription();\n\t\t\t\t\t}\n\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn help;\n\t}\n\n\tprivate boolean isHelpShown(Command command) {\n\t\treturn !(command instanceof HelpCommand) && !(command instanceof HintCommand);\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\tif (args.length == 0) {\n\t\t\tthrow new NoHelpCommandArgumentsException();\n\t\t}\n\t\tString commandName = args[0];\n\t\tfor (Command command : this.commandRunner) {\n\t\t\tif (command.getName().equals(commandName)) {\n\t\t\t\tLog.info(this.commandRunner.getName() + command.getName() + \" - \" + command.getDescription());\n\t\t\t\tLog.info(\"\");\n\t\t\t\tif (command.getUsageHelp() != null) {\n\t\t\t\t\tLog.info(\"usage: \" + this.commandRunner.getName() + command.getName() + \" \"\n\t\t\t\t\t\t\t+ command.getUsageHelp());\n\t\t\t\t\tLog.info(\"\");\n\t\t\t\t}\n\t\t\t\tif (command.getHelp() != null) {\n\t\t\t\t\tLog.info(command.getHelp());\n\t\t\t\t}\n\t\t\t\tCollection<HelpExample> examples = command.getExamples();\n\t\t\t\tif (examples != null) {\n\t\t\t\t\tLog.info((examples.size() != 1) ? \"examples:\" : \"example:\");\n\t\t\t\t\tLog.info(\"\");\n\t\t\t\t\tfor (HelpExample example : examples) {\n\t\t\t\t\t\tLog.info(\"    \" + example.getDescription() + \":\");\n\t\t\t\t\t\tLog.info(\"        $ \" + example.getExample());\n\t\t\t\t\t\tLog.info(\"\");\n\t\t\t\t\t}\n\t\t\t\t\tLog.info(\"\");\n\t\t\t\t}\n\t\t\t\treturn ExitStatus.OK;\n\t\t\t}\n\t\t}\n\t\tthrow new NoSuchCommandException(commandName);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/core/HintCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.core;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.CommandRunner;\nimport org.springframework.boot.cli.command.options.OptionHelp;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.Log;\n\n/**\n * Internal {@link Command} to provide hints for shell auto-completion. Expects to be\n * called with the current index followed by a list of arguments already typed.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class HintCommand extends AbstractCommand {\n\n\tprivate final CommandRunner commandRunner;\n\n\tpublic HintCommand(CommandRunner commandRunner) {\n\t\tsuper(\"hint\", \"Provides hints for shell auto-completion\");\n\t\tthis.commandRunner = commandRunner;\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\ttry {\n\t\t\tint index = (args.length != 0) ? Integer.parseInt(args[0]) - 1 : 0;\n\t\t\tList<String> arguments = new ArrayList<>(args.length);\n\t\t\tfor (int i = 2; i < args.length; i++) {\n\t\t\t\targuments.add(args[i]);\n\t\t\t}\n\t\t\tString starting = \"\";\n\t\t\tif (index < arguments.size()) {\n\t\t\t\tstarting = arguments.remove(index);\n\t\t\t}\n\t\t\tif (index == 0) {\n\t\t\t\tshowCommandHints(starting);\n\t\t\t}\n\t\t\telse if (!arguments.isEmpty() && !starting.isEmpty()) {\n\t\t\t\tString command = arguments.remove(0);\n\t\t\t\tshowCommandOptionHints(command, Collections.unmodifiableList(arguments), starting);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Swallow and provide no hints\n\t\t\treturn ExitStatus.ERROR;\n\t\t}\n\t\treturn ExitStatus.OK;\n\t}\n\n\tprivate void showCommandHints(String starting) {\n\t\tfor (Command command : this.commandRunner) {\n\t\t\tif (isHintMatch(command, starting)) {\n\t\t\t\tLog.info(command.getName() + \" \" + command.getDescription());\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isHintMatch(Command command, String starting) {\n\t\tif (command instanceof HintCommand) {\n\t\t\treturn false;\n\t\t}\n\t\treturn command.getName().startsWith(starting)\n\t\t\t\t|| (this.commandRunner.isOptionCommand(command) && (\"--\" + command.getName()).startsWith(starting));\n\t}\n\n\tprivate void showCommandOptionHints(String commandName, List<String> specifiedArguments, String starting) {\n\t\tCommand command = this.commandRunner.findCommand(commandName);\n\t\tif (command != null) {\n\t\t\tfor (OptionHelp help : command.getOptionsHelp()) {\n\t\t\t\tif (!alreadyUsed(help, specifiedArguments)) {\n\t\t\t\t\tfor (String option : help.getOptions()) {\n\t\t\t\t\t\tif (option.startsWith(starting)) {\n\t\t\t\t\t\t\tLog.info(option + \" \" + help.getUsageHelp());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean alreadyUsed(OptionHelp help, List<String> specifiedArguments) {\n\t\tfor (String argument : specifiedArguments) {\n\t\t\tif (help.getOptions().contains(argument)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/core/VersionCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.core;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.Log;\n\n/**\n * {@link Command} to display the 'version' number.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class VersionCommand extends AbstractCommand {\n\n\tpublic VersionCommand() {\n\t\tsuper(\"version\", \"Show the version\");\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) {\n\t\tLog.info(\"Spring CLI v\" + getClass().getPackage().getImplementationVersion());\n\t\treturn ExitStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/core/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core CLI commands.\n */\n@NullMarked\npackage org.springframework.boot.cli.command.core;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/encodepassword/EncodePasswordCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.encodepassword;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport joptsimple.OptionSet;\nimport joptsimple.OptionSpec;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.HelpExample;\nimport org.springframework.boot.cli.command.OptionParsingCommand;\nimport org.springframework.boot.cli.command.options.OptionHandler;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.Log;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.factory.PasswordEncoderFactories;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Command} to encode passwords for use with Spring Security.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 2.0.0\n */\npublic class EncodePasswordCommand extends OptionParsingCommand {\n\n\tprivate static final Map<String, Supplier<PasswordEncoder>> ENCODERS;\n\n\tstatic {\n\t\tMap<String, Supplier<PasswordEncoder>> encoders = new LinkedHashMap<>();\n\t\tencoders.put(\"default\", PasswordEncoderFactories::createDelegatingPasswordEncoder);\n\t\tencoders.put(\"bcrypt\", BCryptPasswordEncoder::new);\n\t\tencoders.put(\"pbkdf2\", Pbkdf2PasswordEncoder::defaultsForSpringSecurity_v5_8);\n\t\tENCODERS = Collections.unmodifiableMap(encoders);\n\t}\n\n\tpublic EncodePasswordCommand() {\n\t\tsuper(\"encodepassword\", \"Encode a password for use with Spring Security\", new EncodePasswordOptionHandler());\n\t}\n\n\t@Override\n\tpublic String getUsageHelp() {\n\t\treturn \"[options] <password to encode>\";\n\t}\n\n\t@Override\n\tpublic Collection<HelpExample> getExamples() {\n\t\tList<HelpExample> examples = new ArrayList<>();\n\t\texamples.add(new HelpExample(\"To encode a password with the default (bcrypt) encoder\",\n\t\t\t\t\"spring encodepassword mypassword\"));\n\t\texamples.add(new HelpExample(\"To encode a password with pbkdf2\", \"spring encodepassword -a pbkdf2 mypassword\"));\n\t\treturn examples;\n\t}\n\n\tprivate static final class EncodePasswordOptionHandler extends OptionHandler {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> algorithm;\n\n\t\t@Override\n\t\tprotected void options() {\n\t\t\tthis.algorithm = option(Arrays.asList(\"algorithm\", \"a\"),\n\t\t\t\t\t\"The algorithm to use. Supported algorithms: \"\n\t\t\t\t\t\t\t+ StringUtils.collectionToDelimitedString(ENCODERS.keySet(), \", \")\n\t\t\t\t\t\t\t+ \". The default algorithm uses bcrypt\")\n\t\t\t\t.withRequiredArg()\n\t\t\t\t.defaultsTo(\"default\");\n\t\t}\n\n\t\t@Override\n\t\tprotected ExitStatus run(OptionSet options) {\n\t\t\tif (options.nonOptionArguments().size() != 1) {\n\t\t\t\tLog.error(\"A single password option must be provided\");\n\t\t\t\treturn ExitStatus.ERROR;\n\t\t\t}\n\t\t\tString algorithm = options.valueOf(this.algorithm);\n\t\t\tString password = (String) options.nonOptionArguments().get(0);\n\t\t\tSupplier<PasswordEncoder> encoder = ENCODERS.get(algorithm);\n\t\t\tif (encoder == null) {\n\t\t\t\tLog.error(\"Unknown algorithm, valid options are: \"\n\t\t\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(ENCODERS.keySet()));\n\t\t\t\treturn ExitStatus.ERROR;\n\t\t\t}\n\t\t\tLog.info(encoder.get().encode(password));\n\t\t\treturn ExitStatus.OK;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/encodepassword/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CLI command for password encoding.\n */\n@NullMarked\npackage org.springframework.boot.cli.command.encodepassword;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/Dependency.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provide some basic information about a dependency.\n *\n * @author Stephane Nicoll\n */\nfinal class Dependency {\n\n\tprivate final @Nullable String id;\n\n\tprivate final @Nullable String name;\n\n\tprivate final @Nullable String description;\n\n\tDependency(@Nullable String id, @Nullable String name, @Nullable String description) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.description = description;\n\t}\n\n\t@Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\t@Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Nullable String getDescription() {\n\t\treturn this.description;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport joptsimple.OptionSet;\nimport joptsimple.OptionSpec;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.HelpExample;\nimport org.springframework.boot.cli.command.OptionParsingCommand;\nimport org.springframework.boot.cli.command.options.OptionHandler;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.Log;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Command} that initializes a project using Spring initializr.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Vignesh Thangavel Ilangovan\n * @since 1.2.0\n */\npublic class InitCommand extends OptionParsingCommand {\n\n\tpublic InitCommand() {\n\t\tthis(new InitOptionHandler(new InitializrService()));\n\t}\n\n\tpublic InitCommand(InitOptionHandler handler) {\n\t\tsuper(\"init\", \"Initialize a new project using Spring Initializr (start.spring.io)\", handler);\n\t}\n\n\t@Override\n\tpublic String getUsageHelp() {\n\t\treturn \"[options] [location]\";\n\t}\n\n\t@Override\n\tpublic Collection<HelpExample> getExamples() {\n\t\tList<HelpExample> examples = new ArrayList<>();\n\t\texamples.add(new HelpExample(\"To list all the capabilities of the service\", \"spring init --list\"));\n\t\texamples.add(new HelpExample(\"To creates a default project\", \"spring init\"));\n\t\texamples.add(new HelpExample(\"To create a web my-app.zip\", \"spring init -d=web my-app.zip\"));\n\t\texamples.add(new HelpExample(\"To create a web/data-jpa gradle project unpacked\",\n\t\t\t\t\"spring init -d=web,jpa --build=gradle my-dir\"));\n\t\treturn examples;\n\t}\n\n\t/**\n\t * {@link OptionHandler} for {@link InitCommand}.\n\t */\n\tstatic class InitOptionHandler extends OptionHandler {\n\n\t\t/**\n\t\t * Mapping from camelCase options advertised by the service to our kebab-case\n\t\t * options.\n\t\t */\n\t\tprivate static final Map<String, String> CAMEL_CASE_OPTIONS;\n\t\tstatic {\n\t\t\tMap<String, String> options = new HashMap<>();\n\t\t\toptions.put(\"--groupId\", \"--group-id\");\n\t\t\toptions.put(\"--artifactId\", \"--artifact-id\");\n\t\t\toptions.put(\"--packageName\", \"--package-name\");\n\t\t\toptions.put(\"--javaVersion\", \"--java-version\");\n\t\t\toptions.put(\"--bootVersion\", \"--boot-version\");\n\t\t\tCAMEL_CASE_OPTIONS = Collections.unmodifiableMap(options);\n\t\t}\n\n\t\tprivate final ServiceCapabilitiesReportGenerator serviceCapabilitiesReport;\n\n\t\tprivate final ProjectGenerator projectGenerator;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> target;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<Void> listCapabilities;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> groupId;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> artifactId;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> version;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> name;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> description;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> packageName;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> type;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> packaging;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> build;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> format;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> javaVersion;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> language;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> bootVersion;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<String> dependencies;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<Void> extract;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate OptionSpec<Void> force;\n\n\t\tInitOptionHandler(InitializrService initializrService) {\n\t\t\tsuper(InitOptionHandler::processArgument);\n\t\t\tthis.serviceCapabilitiesReport = new ServiceCapabilitiesReportGenerator(initializrService);\n\t\t\tthis.projectGenerator = new ProjectGenerator(initializrService);\n\t\t}\n\n\t\t@Override\n\t\tprotected void options() {\n\t\t\tthis.target = option(Arrays.asList(\"target\"), \"URL of the service to use\").withRequiredArg()\n\t\t\t\t.defaultsTo(ProjectGenerationRequest.DEFAULT_SERVICE_URL);\n\t\t\tthis.listCapabilities = option(Arrays.asList(\"list\"),\n\t\t\t\t\t\"List the capabilities of the service. Use it to discover the \"\n\t\t\t\t\t\t\t+ \"dependencies and the types that are available\");\n\t\t\tprojectGenerationOptions();\n\t\t\totherOptions();\n\t\t}\n\n\t\tprivate void projectGenerationOptions() {\n\t\t\tthis.groupId = option(Arrays.asList(\"group-id\", \"g\"), \"Project coordinates (for example 'org.test')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.artifactId = option(Arrays.asList(\"artifact-id\", \"a\"),\n\t\t\t\t\t\"Project coordinates; infer archive name (for example 'test')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.version = option(Arrays.asList(\"version\", \"v\"), \"Project version (for example '0.0.1-SNAPSHOT')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.name = option(Arrays.asList(\"name\", \"n\"), \"Project name; infer application name\").withRequiredArg();\n\t\t\tthis.description = option(\"description\", \"Project description\").withRequiredArg();\n\t\t\tthis.packageName = option(Arrays.asList(\"package-name\"), \"Package name\").withRequiredArg();\n\t\t\tthis.type = option(Arrays.asList(\"type\", \"t\"),\n\t\t\t\t\t\"Project type. Not normally needed if you use --build \"\n\t\t\t\t\t\t\t+ \"and/or --format. Check the capabilities of the service (--list) for more details\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.packaging = option(Arrays.asList(\"packaging\", \"p\"), \"Project packaging (for example 'jar')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.build = option(\"build\", \"Build system to use (for example 'maven' or 'gradle')\").withRequiredArg()\n\t\t\t\t.defaultsTo(\"gradle\");\n\t\t\tthis.format = option(\"format\", \"Format of the generated content (for example 'build' for a build file, \"\n\t\t\t\t\t+ \"'project' for a project archive)\")\n\t\t\t\t.withRequiredArg()\n\t\t\t\t.defaultsTo(\"project\");\n\t\t\tthis.javaVersion = option(Arrays.asList(\"java-version\", \"j\"), \"Language level (for example '1.8')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.language = option(Arrays.asList(\"language\", \"l\"), \"Programming language  (for example 'java')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.bootVersion = option(Arrays.asList(\"boot-version\", \"b\"),\n\t\t\t\t\t\"Spring Boot version (for example '1.2.0.RELEASE')\")\n\t\t\t\t.withRequiredArg();\n\t\t\tthis.dependencies = option(Arrays.asList(\"dependencies\", \"d\"),\n\t\t\t\t\t\"Comma-separated list of dependency identifiers to include in the generated project\")\n\t\t\t\t.withRequiredArg();\n\t\t}\n\n\t\tprivate void otherOptions() {\n\t\t\tthis.extract = option(Arrays.asList(\"extract\", \"x\"),\n\t\t\t\t\t\"Extract the project archive. Inferred if a location is specified without an extension\");\n\t\t\tthis.force = option(Arrays.asList(\"force\", \"f\"), \"Force overwrite of existing files\");\n\t\t}\n\n\t\t@Override\n\t\tprotected ExitStatus run(OptionSet options) throws Exception {\n\t\t\ttry {\n\t\t\t\tif (options.has(this.listCapabilities)) {\n\t\t\t\t\tgenerateReport(options);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tgenerateProject(options);\n\t\t\t\t}\n\t\t\t\treturn ExitStatus.OK;\n\t\t\t}\n\t\t\tcatch (ReportableException ex) {\n\t\t\t\tLog.error(ex.getMessage());\n\t\t\t\treturn ExitStatus.ERROR;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tLog.error(ex);\n\t\t\t\treturn ExitStatus.ERROR;\n\t\t\t}\n\t\t}\n\n\t\tprivate void generateReport(OptionSet options) throws IOException {\n\t\t\tLog.info(this.serviceCapabilitiesReport.generate(options.valueOf(this.target)));\n\t\t}\n\n\t\tprotected void generateProject(OptionSet options) throws IOException {\n\t\t\tProjectGenerationRequest request = createProjectGenerationRequest(options);\n\t\t\tthis.projectGenerator.generateProject(request, options.has(this.force));\n\t\t}\n\n\t\tprotected ProjectGenerationRequest createProjectGenerationRequest(OptionSet options) {\n\t\t\tList<?> nonOptionArguments = new ArrayList<Object>(options.nonOptionArguments());\n\t\t\tAssert.state(nonOptionArguments.size() <= 1, \"Only the target location may be specified\");\n\t\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\t\trequest.setServiceUrl(options.valueOf(this.target));\n\t\t\tif (options.has(this.bootVersion)) {\n\t\t\t\trequest.setBootVersion(options.valueOf(this.bootVersion));\n\t\t\t}\n\t\t\tif (options.has(this.dependencies)) {\n\t\t\t\tfor (String dep : options.valueOf(this.dependencies).split(\",\")) {\n\t\t\t\t\trequest.getDependencies().add(dep.trim());\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (options.has(this.javaVersion)) {\n\t\t\t\trequest.setJavaVersion(options.valueOf(this.javaVersion));\n\t\t\t}\n\t\t\tif (options.has(this.packageName)) {\n\t\t\t\trequest.setPackageName(options.valueOf(this.packageName));\n\t\t\t}\n\t\t\trequest.setBuild(options.valueOf(this.build));\n\t\t\trequest.setFormat(options.valueOf(this.format));\n\t\t\trequest.setDetectType(options.has(this.build) || options.has(this.format));\n\t\t\tif (options.has(this.type)) {\n\t\t\t\trequest.setType(options.valueOf(this.type));\n\t\t\t}\n\t\t\tif (options.has(this.packaging)) {\n\t\t\t\trequest.setPackaging(options.valueOf(this.packaging));\n\t\t\t}\n\t\t\tif (options.has(this.language)) {\n\t\t\t\trequest.setLanguage(options.valueOf(this.language));\n\t\t\t}\n\t\t\tif (options.has(this.groupId)) {\n\t\t\t\trequest.setGroupId(options.valueOf(this.groupId));\n\t\t\t}\n\t\t\tif (options.has(this.artifactId)) {\n\t\t\t\trequest.setArtifactId(options.valueOf(this.artifactId));\n\t\t\t}\n\t\t\tif (options.has(this.name)) {\n\t\t\t\trequest.setName(options.valueOf(this.name));\n\t\t\t}\n\t\t\tif (options.has(this.version)) {\n\t\t\t\trequest.setVersion(options.valueOf(this.version));\n\t\t\t}\n\t\t\tif (options.has(this.description)) {\n\t\t\t\trequest.setDescription(options.valueOf(this.description));\n\t\t\t}\n\t\t\trequest.setExtract(options.has(this.extract));\n\t\t\tif (nonOptionArguments.size() == 1) {\n\t\t\t\tString output = (String) nonOptionArguments.get(0);\n\t\t\t\trequest.setOutput(output);\n\t\t\t}\n\t\t\treturn request;\n\t\t}\n\n\t\tprivate static String processArgument(String argument) {\n\t\t\tfor (Map.Entry<String, String> entry : CAMEL_CASE_OPTIONS.entrySet()) {\n\t\t\t\tString name = entry.getKey();\n\t\t\t\tif (argument.startsWith(name + \" \") || argument.startsWith(name + \"=\")) {\n\t\t\t\t\treturn entry.getValue() + argument.substring(name.length());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn argument;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitializrService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.classic.methods.HttpGet;\nimport org.apache.hc.client5.http.classic.methods.HttpUriRequest;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.core5.http.ClassicHttpResponse;\nimport org.apache.hc.core5.http.ContentType;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.HttpEntity;\nimport org.apache.hc.core5.http.HttpHeaders;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.message.BasicHeader;\nimport org.apache.hc.core5.http.message.StatusLine;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.json.JSONException;\nimport org.springframework.boot.cli.json.JSONObject;\nimport org.springframework.boot.cli.util.Log;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Invokes the initializr service over HTTP.\n *\n * @author Stephane Nicoll\n */\nclass InitializrService {\n\n\tprivate static final String FILENAME_HEADER_PREFIX = \"filename=\\\"\";\n\n\t/**\n\t * Accept header to use to retrieve the JSON meta-data.\n\t */\n\tpublic static final String ACCEPT_META_DATA = \"application/vnd.initializr.v2.1+\"\n\t\t\t+ \"json,application/vnd.initializr.v2+json\";\n\n\t/**\n\t * Accept header to use to retrieve the service capabilities of the service. If the\n\t * service does not offer such feature, the JSON meta-data are retrieved instead.\n\t */\n\tpublic static final String ACCEPT_SERVICE_CAPABILITIES = \"text/plain,\" + ACCEPT_META_DATA;\n\n\t/**\n\t * Late binding HTTP client.\n\t */\n\tprivate @Nullable HttpClient http;\n\n\tInitializrService() {\n\t}\n\n\tInitializrService(HttpClient http) {\n\t\tthis.http = http;\n\t}\n\n\tprotected HttpClient getHttp() {\n\t\tif (this.http == null) {\n\t\t\tthis.http = HttpClientBuilder.create().useSystemProperties().build();\n\t\t}\n\t\treturn this.http;\n\t}\n\n\t/**\n\t * Generate a project based on the specified {@link ProjectGenerationRequest}.\n\t * @param request the generation request\n\t * @return an entity defining the project\n\t * @throws IOException if generation fails\n\t */\n\tProjectGenerationResponse generate(ProjectGenerationRequest request) throws IOException {\n\t\tLog.info(\"Using service at \" + request.getServiceUrl());\n\t\tInitializrServiceMetadata metadata = loadMetadata(request.getServiceUrl());\n\t\tURI url = request.generateUrl(metadata);\n\t\tClassicHttpResponse httpResponse = executeProjectGenerationRequest(url);\n\t\tHttpEntity httpEntity = httpResponse.getEntity();\n\t\tvalidateResponse(httpResponse, request.getServiceUrl());\n\t\treturn createResponse(httpResponse, httpEntity);\n\t}\n\n\t/**\n\t * Load the {@link InitializrServiceMetadata} at the specified url.\n\t * @param serviceUrl to url of the initializer service\n\t * @return the metadata describing the service\n\t * @throws IOException if the service's metadata cannot be loaded\n\t */\n\tInitializrServiceMetadata loadMetadata(String serviceUrl) throws IOException {\n\t\tClassicHttpResponse httpResponse = executeInitializrMetadataRetrieval(serviceUrl);\n\t\tvalidateResponse(httpResponse, serviceUrl);\n\t\treturn parseJsonMetadata(httpResponse.getEntity());\n\t}\n\n\t/**\n\t * Loads the service capabilities of the service at the specified URL. If the service\n\t * supports generating a textual representation of the capabilities, it is returned,\n\t * otherwise {@link InitializrServiceMetadata} is returned.\n\t * @param serviceUrl to url of the initializer service\n\t * @return the service capabilities (as a String) or the\n\t * {@link InitializrServiceMetadata} describing the service\n\t * @throws IOException if the service capabilities cannot be loaded\n\t */\n\tObject loadServiceCapabilities(String serviceUrl) throws IOException {\n\t\tHttpGet request = new HttpGet(serviceUrl);\n\t\trequest.setHeader(new BasicHeader(HttpHeaders.ACCEPT, ACCEPT_SERVICE_CAPABILITIES));\n\t\tClassicHttpResponse httpResponse = execute(request, URI.create(serviceUrl), \"retrieve help\");\n\t\tvalidateResponse(httpResponse, serviceUrl);\n\t\tHttpEntity httpEntity = httpResponse.getEntity();\n\t\tContentType contentType = ContentType.create(httpEntity.getContentType());\n\t\tif (contentType.getMimeType().equals(\"text/plain\")) {\n\t\t\treturn getContent(httpEntity);\n\t\t}\n\t\treturn parseJsonMetadata(httpEntity);\n\t}\n\n\tprivate InitializrServiceMetadata parseJsonMetadata(HttpEntity httpEntity) throws IOException {\n\t\ttry {\n\t\t\treturn new InitializrServiceMetadata(getContentAsJson(httpEntity));\n\t\t}\n\t\tcatch (JSONException ex) {\n\t\t\tthrow new ReportableException(\"Invalid content received from server (\" + ex.getMessage() + \")\", ex);\n\t\t}\n\t}\n\n\tprivate void validateResponse(ClassicHttpResponse httpResponse, String serviceUrl) {\n\t\tif (httpResponse.getEntity() == null) {\n\t\t\tthrow new ReportableException(\"No content received from server '\" + serviceUrl + \"'\");\n\t\t}\n\t\tif (httpResponse.getCode() != 200) {\n\t\t\tthrow createException(serviceUrl, httpResponse);\n\t\t}\n\t}\n\n\tprivate ProjectGenerationResponse createResponse(ClassicHttpResponse httpResponse, HttpEntity httpEntity)\n\t\t\tthrows IOException {\n\t\tProjectGenerationResponse response = new ProjectGenerationResponse(\n\t\t\t\tContentType.create(httpEntity.getContentType()));\n\t\tresponse.setContent(FileCopyUtils.copyToByteArray(httpEntity.getContent()));\n\t\tString fileName = extractFileName(httpResponse.getFirstHeader(\"Content-Disposition\"));\n\t\tif (fileName != null) {\n\t\t\tresponse.setFileName(fileName);\n\t\t}\n\t\treturn response;\n\t}\n\n\t/**\n\t * Request the creation of the project using the specified URL.\n\t * @param url the URL\n\t * @return the response\n\t */\n\tprivate ClassicHttpResponse executeProjectGenerationRequest(URI url) {\n\t\treturn execute(new HttpGet(url), url, \"generate project\");\n\t}\n\n\t/**\n\t * Retrieves the meta-data of the service at the specified URL.\n\t * @param url the URL\n\t * @return the response\n\t */\n\tprivate ClassicHttpResponse executeInitializrMetadataRetrieval(String url) {\n\t\tHttpGet request = new HttpGet(url);\n\t\trequest.setHeader(new BasicHeader(HttpHeaders.ACCEPT, ACCEPT_META_DATA));\n\t\treturn execute(request, URI.create(url), \"retrieve metadata\");\n\t}\n\n\tprivate ClassicHttpResponse execute(HttpUriRequest request, URI url, String description) {\n\t\ttry {\n\t\t\tHttpHost host = HttpHost.create(url);\n\t\t\trequest.addHeader(\"User-Agent\", \"SpringBootCli/\" + getClass().getPackage().getImplementationVersion());\n\t\t\treturn getHttp().executeOpen(host, request, null);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new ReportableException(\n\t\t\t\t\t\"Failed to \" + description + \" from service at '\" + url + \"' (\" + ex.getMessage() + \")\");\n\t\t}\n\t}\n\n\tprivate ReportableException createException(String url, ClassicHttpResponse httpResponse) {\n\t\tStatusLine statusLine = new StatusLine(httpResponse);\n\t\tString message = \"Initializr service call failed using '\" + url + \"' - service returned \"\n\t\t\t\t+ statusLine.getReasonPhrase();\n\t\tString error = extractMessage(httpResponse.getEntity());\n\t\tif (StringUtils.hasText(error)) {\n\t\t\tmessage += \": '\" + error + \"'\";\n\t\t}\n\t\telse {\n\t\t\tint statusCode = statusLine.getStatusCode();\n\t\t\tmessage += \" (unexpected \" + statusCode + \" error)\";\n\t\t}\n\t\tthrow new ReportableException(message);\n\t}\n\n\tprivate @Nullable String extractMessage(@Nullable HttpEntity entity) {\n\t\tif (entity != null) {\n\t\t\ttry {\n\t\t\t\tJSONObject error = getContentAsJson(entity);\n\t\t\t\tif (error.has(\"message\")) {\n\t\t\t\t\treturn error.getString(\"message\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate JSONObject getContentAsJson(HttpEntity entity) throws IOException, JSONException {\n\t\treturn new JSONObject(getContent(entity));\n\t}\n\n\tprivate String getContent(HttpEntity entity) throws IOException {\n\t\tContentType contentType = ContentType.create(entity.getContentType());\n\t\tCharset charset = contentType.getCharset();\n\t\tcharset = (charset != null) ? charset : StandardCharsets.UTF_8;\n\t\tbyte[] content = FileCopyUtils.copyToByteArray(entity.getContent());\n\t\treturn new String(content, charset);\n\t}\n\n\tprivate @Nullable String extractFileName(@Nullable Header header) {\n\t\tif (header != null) {\n\t\t\tString value = header.getValue();\n\t\t\tint start = value.indexOf(FILENAME_HEADER_PREFIX);\n\t\t\tif (start != -1) {\n\t\t\t\tvalue = value.substring(start + FILENAME_HEADER_PREFIX.length());\n\t\t\t\tint end = value.indexOf('\\\"');\n\t\t\t\tif (end != -1) {\n\t\t\t\t\treturn value.substring(0, end);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/InitializrServiceMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.json.JSONArray;\nimport org.springframework.boot.cli.json.JSONException;\nimport org.springframework.boot.cli.json.JSONObject;\nimport org.springframework.util.Assert;\n\n/**\n * Define the metadata available for a particular service instance.\n *\n * @author Stephane Nicoll\n */\nclass InitializrServiceMetadata {\n\n\tprivate static final String DEPENDENCIES_EL = \"dependencies\";\n\n\tprivate static final String TYPE_EL = \"type\";\n\n\tprivate static final String VALUES_EL = \"values\";\n\n\tprivate static final String NAME_ATTRIBUTE = \"name\";\n\n\tprivate static final String ID_ATTRIBUTE = \"id\";\n\n\tprivate static final String DESCRIPTION_ATTRIBUTE = \"description\";\n\n\tprivate static final String ACTION_ATTRIBUTE = \"action\";\n\n\tprivate static final String DEFAULT_ATTRIBUTE = \"default\";\n\n\tprivate final Map<String, Dependency> dependencies;\n\n\tprivate final MetadataHolder<String, ProjectType> projectTypes;\n\n\tprivate final Map<String, String> defaults;\n\n\t/**\n\t * Creates a new instance using the specified root {@link JSONObject}.\n\t * @param root the root JSONObject\n\t * @throws JSONException on JSON parsing failure\n\t */\n\tInitializrServiceMetadata(JSONObject root) throws JSONException {\n\t\tthis.dependencies = parseDependencies(root);\n\t\tthis.projectTypes = parseProjectTypes(root);\n\t\tthis.defaults = Collections.unmodifiableMap(parseDefaults(root));\n\t}\n\n\tInitializrServiceMetadata(ProjectType defaultProjectType) {\n\t\tthis.dependencies = new HashMap<>();\n\t\tthis.projectTypes = new MetadataHolder<>();\n\t\tthis.projectTypes.getContent().put(defaultProjectType.getId(), defaultProjectType);\n\t\tthis.projectTypes.setDefaultItem(defaultProjectType);\n\t\tthis.defaults = new HashMap<>();\n\t}\n\n\t/**\n\t * Return the dependencies supported by the service.\n\t * @return the supported dependencies\n\t */\n\tCollection<Dependency> getDependencies() {\n\t\treturn this.dependencies.values();\n\t}\n\n\t/**\n\t * Return the dependency with the specified id or {@code null} if no such dependency\n\t * exists.\n\t * @param id the id\n\t * @return the dependency or {@code null}\n\t */\n\t@Nullable Dependency getDependency(String id) {\n\t\treturn this.dependencies.get(id);\n\t}\n\n\t/**\n\t * Return the project types supported by the service.\n\t * @return the supported project types\n\t */\n\tMap<String, ProjectType> getProjectTypes() {\n\t\treturn this.projectTypes.getContent();\n\t}\n\n\t/**\n\t * Return the default type to use or {@code null} if the metadata does not define any\n\t * default.\n\t * @return the default project type or {@code null}\n\t */\n\t@Nullable ProjectType getDefaultType() {\n\t\tif (this.projectTypes.getDefaultItem() != null) {\n\t\t\treturn this.projectTypes.getDefaultItem();\n\t\t}\n\t\tString defaultTypeId = getDefaults().get(\"type\");\n\t\tif (defaultTypeId != null) {\n\t\t\treturn this.projectTypes.getContent().get(defaultTypeId);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the defaults applicable to the service.\n\t * @return the defaults of the service\n\t */\n\tMap<String, String> getDefaults() {\n\t\treturn this.defaults;\n\t}\n\n\tprivate Map<String, Dependency> parseDependencies(JSONObject root) throws JSONException {\n\t\tMap<String, Dependency> result = new HashMap<>();\n\t\tif (!root.has(DEPENDENCIES_EL)) {\n\t\t\treturn result;\n\t\t}\n\t\tJSONObject dependencies = root.getJSONObject(DEPENDENCIES_EL);\n\t\tJSONArray array = dependencies.getJSONArray(VALUES_EL);\n\t\tfor (int i = 0; i < array.length(); i++) {\n\t\t\tJSONObject group = array.getJSONObject(i);\n\t\t\tparseGroup(group, result);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate MetadataHolder<String, ProjectType> parseProjectTypes(JSONObject root) throws JSONException {\n\t\tMetadataHolder<String, ProjectType> result = new MetadataHolder<>();\n\t\tif (!root.has(TYPE_EL)) {\n\t\t\treturn result;\n\t\t}\n\t\tJSONObject type = root.getJSONObject(TYPE_EL);\n\t\tJSONArray array = type.getJSONArray(VALUES_EL);\n\t\tString defaultType = (type.has(DEFAULT_ATTRIBUTE) ? type.getString(DEFAULT_ATTRIBUTE) : null);\n\t\tfor (int i = 0; i < array.length(); i++) {\n\t\t\tJSONObject typeJson = array.getJSONObject(i);\n\t\t\tProjectType projectType = parseType(typeJson, defaultType);\n\t\t\tresult.getContent().put(projectType.getId(), projectType);\n\t\t\tif (projectType.isDefaultType()) {\n\t\t\t\tresult.setDefaultItem(projectType);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate Map<String, String> parseDefaults(JSONObject root) throws JSONException {\n\t\tMap<String, String> result = new HashMap<>();\n\t\tIterator<?> keys = root.keys();\n\t\twhile (keys.hasNext()) {\n\t\t\tString key = (String) keys.next();\n\t\t\tObject o = root.get(key);\n\t\t\tif (o instanceof JSONObject child) {\n\t\t\t\tif (child.has(DEFAULT_ATTRIBUTE)) {\n\t\t\t\t\tresult.put(key, child.getString(DEFAULT_ATTRIBUTE));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate void parseGroup(JSONObject group, Map<String, Dependency> dependencies) throws JSONException {\n\t\tif (group.has(VALUES_EL)) {\n\t\t\tJSONArray content = group.getJSONArray(VALUES_EL);\n\t\t\tfor (int i = 0; i < content.length(); i++) {\n\t\t\t\tDependency dependency = parseDependency(content.getJSONObject(i));\n\t\t\t\tdependencies.put(dependency.getId(), dependency);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Dependency parseDependency(JSONObject object) throws JSONException {\n\t\tString id = getStringValue(object, ID_ATTRIBUTE, null);\n\t\tString name = getStringValue(object, NAME_ATTRIBUTE, null);\n\t\tString description = getStringValue(object, DESCRIPTION_ATTRIBUTE, null);\n\t\treturn new Dependency(id, name, description);\n\t}\n\n\tprivate ProjectType parseType(JSONObject object, @Nullable String defaultId) throws JSONException {\n\t\tString id = getStringValue(object, ID_ATTRIBUTE, null);\n\t\tString name = getStringValue(object, NAME_ATTRIBUTE, null);\n\t\tString action = getStringValue(object, ACTION_ATTRIBUTE, null);\n\t\tAssert.state(id != null, \"'id' must not be null\");\n\t\tboolean defaultType = id.equals(defaultId);\n\t\tMap<String, String> tags = new HashMap<>();\n\t\tif (object.has(\"tags\")) {\n\t\t\tJSONObject jsonTags = object.getJSONObject(\"tags\");\n\t\t\ttags.putAll(parseStringItems(jsonTags));\n\t\t}\n\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\tAssert.state(action != null, \"'action' must not be null\");\n\t\treturn new ProjectType(id, name, action, defaultType, tags);\n\t}\n\n\tprivate @Nullable String getStringValue(JSONObject object, String name, @Nullable String defaultValue)\n\t\t\tthrows JSONException {\n\t\treturn object.has(name) ? object.getString(name) : defaultValue;\n\t}\n\n\tprivate Map<String, String> parseStringItems(JSONObject json) throws JSONException {\n\t\tMap<String, String> result = new HashMap<>();\n\t\tfor (Iterator<?> iterator = json.keys(); iterator.hasNext();) {\n\t\t\tString key = (String) iterator.next();\n\t\t\tObject value = json.get(key);\n\t\t\tif (value instanceof String string) {\n\t\t\t\tresult.put(key, string);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static final class MetadataHolder<K, T> {\n\n\t\tprivate final Map<K, T> content;\n\n\t\tprivate @Nullable T defaultItem;\n\n\t\tprivate MetadataHolder() {\n\t\t\tthis.content = new HashMap<>();\n\t\t}\n\n\t\tMap<K, T> getContent() {\n\t\t\treturn this.content;\n\t\t}\n\n\t\t@Nullable T getDefaultItem() {\n\t\t\treturn this.defaultItem;\n\t\t}\n\n\t\tvoid setDefaultItem(@Nullable T defaultItem) {\n\t\t\tthis.defaultItem = defaultItem;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerationRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.hc.core5.net.URIBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Represent the settings to apply to generating the project.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ProjectGenerationRequest {\n\n\tpublic static final String DEFAULT_SERVICE_URL = \"https://start.spring.io\";\n\n\tprivate String serviceUrl = DEFAULT_SERVICE_URL;\n\n\tprivate @Nullable String output;\n\n\tprivate boolean extract;\n\n\tprivate @Nullable String groupId;\n\n\tprivate @Nullable String artifactId;\n\n\tprivate @Nullable String version;\n\n\tprivate @Nullable String name;\n\n\tprivate @Nullable String description;\n\n\tprivate @Nullable String packageName;\n\n\tprivate @Nullable String type;\n\n\tprivate @Nullable String packaging;\n\n\tprivate @Nullable String build;\n\n\tprivate @Nullable String format;\n\n\tprivate boolean detectType;\n\n\tprivate @Nullable String javaVersion;\n\n\tprivate @Nullable String language;\n\n\tprivate @Nullable String bootVersion;\n\n\tprivate final List<String> dependencies = new ArrayList<>();\n\n\t/**\n\t * The URL of the service to use.\n\t * @return the service URL\n\t * @see #DEFAULT_SERVICE_URL\n\t */\n\tString getServiceUrl() {\n\t\treturn this.serviceUrl;\n\t}\n\n\tvoid setServiceUrl(String serviceUrl) {\n\t\tthis.serviceUrl = serviceUrl;\n\t}\n\n\t/**\n\t * The location of the generated project.\n\t * @return the location of the generated project\n\t */\n\t@Nullable String getOutput() {\n\t\treturn this.output;\n\t}\n\n\tvoid setOutput(@Nullable String output) {\n\t\tif (output != null && output.endsWith(\"/\")) {\n\t\t\tthis.output = output.substring(0, output.length() - 1);\n\t\t\tthis.extract = true;\n\t\t}\n\t\telse {\n\t\t\tthis.output = output;\n\t\t}\n\t}\n\n\t/**\n\t * Whether the project archive should be extracted in the output location. If the\n\t * {@link #getOutput() output} ends with \"/\", the project is extracted automatically.\n\t * @return {@code true} if the archive should be extracted, otherwise {@code false}\n\t */\n\tboolean isExtract() {\n\t\treturn this.extract;\n\t}\n\n\tvoid setExtract(boolean extract) {\n\t\tthis.extract = extract;\n\t}\n\n\t/**\n\t * The groupId to use or {@code null} if it should not be customized.\n\t * @return the groupId or {@code null}\n\t */\n\t@Nullable String getGroupId() {\n\t\treturn this.groupId;\n\t}\n\n\tvoid setGroupId(@Nullable String groupId) {\n\t\tthis.groupId = groupId;\n\t}\n\n\t/**\n\t * The artifactId to use or {@code null} if it should not be customized.\n\t * @return the artifactId or {@code null}\n\t */\n\t@Nullable String getArtifactId() {\n\t\treturn this.artifactId;\n\t}\n\n\tvoid setArtifactId(@Nullable String artifactId) {\n\t\tthis.artifactId = artifactId;\n\t}\n\n\t/**\n\t * The artifact version to use or {@code null} if it should not be customized.\n\t * @return the artifact version or {@code null}\n\t */\n\t@Nullable String getVersion() {\n\t\treturn this.version;\n\t}\n\n\tvoid setVersion(@Nullable String version) {\n\t\tthis.version = version;\n\t}\n\n\t/**\n\t * The name to use or {@code null} if it should not be customized.\n\t * @return the name or {@code null}\n\t */\n\t@Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tvoid setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * The description to use or {@code null} if it should not be customized.\n\t * @return the description or {@code null}\n\t */\n\t@Nullable String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tvoid setDescription(@Nullable String description) {\n\t\tthis.description = description;\n\t}\n\n\t/**\n\t * Return the package name or {@code null} if it should not be customized.\n\t * @return the package name or {@code null}\n\t */\n\t@Nullable String getPackageName() {\n\t\treturn this.packageName;\n\t}\n\n\tvoid setPackageName(@Nullable String packageName) {\n\t\tthis.packageName = packageName;\n\t}\n\n\t/**\n\t * The type of project to generate. Should match one of the advertised type that the\n\t * service supports. If not set, the default is retrieved from the service metadata.\n\t * @return the project type\n\t */\n\t@Nullable String getType() {\n\t\treturn this.type;\n\t}\n\n\tvoid setType(@Nullable String type) {\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * The packaging type or {@code null} if it should not be customized.\n\t * @return the packaging type or {@code null}\n\t */\n\t@Nullable String getPackaging() {\n\t\treturn this.packaging;\n\t}\n\n\tvoid setPackaging(@Nullable String packaging) {\n\t\tthis.packaging = packaging;\n\t}\n\n\t/**\n\t * The build type to use. Ignored if a type is set. Can be used alongside the\n\t * {@link #getFormat() format} to identify the type to use.\n\t * @return the build type\n\t */\n\t@Nullable String getBuild() {\n\t\treturn this.build;\n\t}\n\n\tvoid setBuild(@Nullable String build) {\n\t\tthis.build = build;\n\t}\n\n\t/**\n\t * The project format to use. Ignored if a type is set. Can be used alongside the\n\t * {@link #getBuild() build} to identify the type to use.\n\t * @return the project format\n\t */\n\t@Nullable String getFormat() {\n\t\treturn this.format;\n\t}\n\n\tvoid setFormat(@Nullable String format) {\n\t\tthis.format = format;\n\t}\n\n\t/**\n\t * Whether the type should be detected based on the build and format value.\n\t * @return {@code true} if type detection will be performed, otherwise {@code false}\n\t */\n\tboolean isDetectType() {\n\t\treturn this.detectType;\n\t}\n\n\tvoid setDetectType(boolean detectType) {\n\t\tthis.detectType = detectType;\n\t}\n\n\t/**\n\t * The Java version to use or {@code null} if it should not be customized.\n\t * @return the Java version or {@code null}\n\t */\n\t@Nullable String getJavaVersion() {\n\t\treturn this.javaVersion;\n\t}\n\n\tvoid setJavaVersion(@Nullable String javaVersion) {\n\t\tthis.javaVersion = javaVersion;\n\t}\n\n\t/**\n\t * The programming language to use or {@code null} if it should not be customized.\n\t * @return the programming language or {@code null}\n\t */\n\t@Nullable String getLanguage() {\n\t\treturn this.language;\n\t}\n\n\tvoid setLanguage(@Nullable String language) {\n\t\tthis.language = language;\n\t}\n\n\t/**\n\t * The Spring Boot version to use or {@code null} if it should not be customized.\n\t * @return the Spring Boot version or {@code null}\n\t */\n\t@Nullable String getBootVersion() {\n\t\treturn this.bootVersion;\n\t}\n\n\tvoid setBootVersion(@Nullable String bootVersion) {\n\t\tthis.bootVersion = bootVersion;\n\t}\n\n\t/**\n\t * The identifiers of the dependencies to include in the project.\n\t * @return the dependency identifiers\n\t */\n\tList<String> getDependencies() {\n\t\treturn this.dependencies;\n\t}\n\n\t/**\n\t * Generates the URI to use to generate a project represented by this request.\n\t * @param metadata the metadata that describes the service\n\t * @return the project generation URI\n\t */\n\tURI generateUrl(InitializrServiceMetadata metadata) {\n\t\ttry {\n\t\t\tURIBuilder builder = new URIBuilder(this.serviceUrl);\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tif (builder.getPath() != null) {\n\t\t\t\tsb.append(builder.getPath());\n\t\t\t}\n\n\t\t\tProjectType projectType = determineProjectType(metadata);\n\t\t\tthis.type = projectType.getId();\n\t\t\tsb.append(projectType.getAction());\n\t\t\tbuilder.setPath(sb.toString());\n\n\t\t\tif (!this.dependencies.isEmpty()) {\n\t\t\t\tbuilder.setParameter(\"dependencies\", StringUtils.collectionToCommaDelimitedString(this.dependencies));\n\t\t\t}\n\n\t\t\tif (this.groupId != null) {\n\t\t\t\tbuilder.setParameter(\"groupId\", this.groupId);\n\t\t\t}\n\t\t\tString resolvedArtifactId = resolveArtifactId();\n\t\t\tif (resolvedArtifactId != null) {\n\t\t\t\tbuilder.setParameter(\"artifactId\", resolvedArtifactId);\n\t\t\t}\n\t\t\tif (this.version != null) {\n\t\t\t\tbuilder.setParameter(\"version\", this.version);\n\t\t\t}\n\t\t\tif (this.name != null) {\n\t\t\t\tbuilder.setParameter(\"name\", this.name);\n\t\t\t}\n\t\t\tif (this.description != null) {\n\t\t\t\tbuilder.setParameter(\"description\", this.description);\n\t\t\t}\n\t\t\tif (this.packageName != null) {\n\t\t\t\tbuilder.setParameter(\"packageName\", this.packageName);\n\t\t\t}\n\t\t\tif (this.type != null) {\n\t\t\t\tbuilder.setParameter(\"type\", projectType.getId());\n\t\t\t}\n\t\t\tif (this.packaging != null) {\n\t\t\t\tbuilder.setParameter(\"packaging\", this.packaging);\n\t\t\t}\n\t\t\tif (this.javaVersion != null) {\n\t\t\t\tbuilder.setParameter(\"javaVersion\", this.javaVersion);\n\t\t\t}\n\t\t\tif (this.language != null) {\n\t\t\t\tbuilder.setParameter(\"language\", this.language);\n\t\t\t}\n\t\t\tif (this.bootVersion != null) {\n\t\t\t\tbuilder.setParameter(\"bootVersion\", this.bootVersion);\n\t\t\t}\n\n\t\t\treturn builder.build();\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new ReportableException(\"Invalid service URL (\" + ex.getMessage() + \")\");\n\t\t}\n\t}\n\n\tprotected ProjectType determineProjectType(InitializrServiceMetadata metadata) {\n\t\tif (this.type != null) {\n\t\t\tProjectType result = metadata.getProjectTypes().get(this.type);\n\t\t\tif (result == null) {\n\t\t\t\tthrow new ReportableException(\n\t\t\t\t\t\t(\"No project type with id '\" + this.type + \"' - check the service capabilities (--list)\"));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\telse if (isDetectType()) {\n\t\t\tMap<String, ProjectType> types = new HashMap<>(metadata.getProjectTypes());\n\t\t\tif (this.build != null) {\n\t\t\t\tfilter(types, \"build\", this.build);\n\t\t\t}\n\t\t\tif (this.format != null) {\n\t\t\t\tfilter(types, \"format\", this.format);\n\t\t\t}\n\t\t\tif (types.size() == 1) {\n\t\t\t\treturn types.values().iterator().next();\n\t\t\t}\n\t\t\telse if (types.isEmpty()) {\n\t\t\t\tthrow new ReportableException(\"No type found with build '\" + this.build + \"' and format '\" + this.format\n\t\t\t\t\t\t+ \"' check the service capabilities (--list)\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new ReportableException(\"Multiple types found with build '\" + this.build + \"' and format '\"\n\t\t\t\t\t\t+ this.format + \"' use --type with a more specific value \" + types.keySet());\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tProjectType defaultType = metadata.getDefaultType();\n\t\t\tif (defaultType == null) {\n\t\t\t\tthrow new ReportableException((\"No project type is set and no default is defined. \"\n\t\t\t\t\t\t+ \"Check the service capabilities (--list)\"));\n\t\t\t}\n\t\t\treturn defaultType;\n\t\t}\n\t}\n\n\t/**\n\t * Resolve the artifactId to use or {@code null} if it should not be customized.\n\t * @return the artifactId\n\t */\n\tprotected @Nullable String resolveArtifactId() {\n\t\tif (this.artifactId != null) {\n\t\t\treturn this.artifactId;\n\t\t}\n\t\tif (this.output != null) {\n\t\t\tint i = this.output.lastIndexOf('.');\n\t\t\treturn (i != -1) ? this.output.substring(0, i) : this.output;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static void filter(Map<String, ProjectType> projects, String tag, String tagValue) {\n\t\tprojects.entrySet().removeIf((entry) -> !tagValue.equals(entry.getValue().getTags().get(tag)));\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerationResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport org.apache.hc.core5.http.ContentType;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Represent the response of a {@link ProjectGenerationRequest}.\n *\n * @author Stephane Nicoll\n */\nclass ProjectGenerationResponse {\n\n\tprivate final ContentType contentType;\n\n\tprivate byte @Nullable [] content;\n\n\tprivate @Nullable String fileName;\n\n\tProjectGenerationResponse(ContentType contentType) {\n\t\tthis.contentType = contentType;\n\t}\n\n\t/**\n\t * Return the {@link ContentType} of this instance.\n\t * @return the content type\n\t */\n\tContentType getContentType() {\n\t\treturn this.contentType;\n\t}\n\n\t/**\n\t * The generated project archive or file.\n\t * @return the content\n\t */\n\tbyte @Nullable [] getContent() {\n\t\treturn this.content;\n\t}\n\n\tvoid setContent(byte @Nullable [] content) {\n\t\tthis.content = content;\n\t}\n\n\t/**\n\t * The preferred file name to use to store the entity on disk or {@code null} if no\n\t * preferred value has been set.\n\t * @return the file name, or {@code null}\n\t */\n\t@Nullable String getFileName() {\n\t\treturn this.fileName;\n\t}\n\n\tvoid setFileName(@Nullable String fileName) {\n\t\tthis.fileName = fileName;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.util.Log;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Helper class used to generate the project.\n *\n * @author Stephane Nicoll\n */\nclass ProjectGenerator {\n\n\tprivate static final String ZIP_MIME_TYPE = \"application/zip\";\n\n\tprivate final InitializrService initializrService;\n\n\tProjectGenerator(InitializrService initializrService) {\n\t\tthis.initializrService = initializrService;\n\t}\n\n\tvoid generateProject(ProjectGenerationRequest request, boolean force) throws IOException {\n\t\tProjectGenerationResponse response = this.initializrService.generate(request);\n\t\tString fileName = (request.getOutput() != null) ? request.getOutput() : response.getFileName();\n\t\tif (shouldExtract(request, response)) {\n\t\t\tif (isZipArchive(response)) {\n\t\t\t\textractProject(response, request.getOutput(), force);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tLog.info(\"Could not extract '\" + response.getContentType() + \"'\");\n\t\t\t\t// Use value from the server since we can't extract it\n\t\t\t\tfileName = response.getFileName();\n\t\t\t}\n\t\t}\n\t\tif (fileName == null) {\n\t\t\tthrow new ReportableException(\"Could not save the project, the server did not set a preferred \"\n\t\t\t\t\t+ \"file name and no location was set. Specify the output location for the project.\");\n\t\t}\n\t\twriteProject(response, fileName, force);\n\t}\n\n\t/**\n\t * Detect if the project should be extracted.\n\t * @param request the generation request\n\t * @param response the generation response\n\t * @return if the project should be extracted\n\t */\n\tprivate boolean shouldExtract(ProjectGenerationRequest request, ProjectGenerationResponse response) {\n\t\tif (request.isExtract()) {\n\t\t\treturn true;\n\t\t}\n\t\t// explicit name hasn't been provided for an archive and there is no extension\n\t\treturn isZipArchive(response) && request.getOutput() != null && !request.getOutput().contains(\".\");\n\t}\n\n\tprivate boolean isZipArchive(ProjectGenerationResponse entity) {\n\t\tif (entity.getContentType() != null) {\n\t\t\ttry {\n\t\t\t\treturn ZIP_MIME_TYPE.equals(entity.getContentType().getMimeType());\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate void extractProject(ProjectGenerationResponse entity, @Nullable String output, boolean overwrite)\n\t\t\tthrows IOException {\n\t\tFile outputDirectory = (output != null) ? new File(output) : new File(System.getProperty(\"user.dir\"));\n\t\tif (!outputDirectory.exists()) {\n\t\t\toutputDirectory.mkdirs();\n\t\t}\n\t\tbyte[] content = entity.getContent();\n\t\tAssert.state(content != null, \"'content' must not be null\");\n\t\ttry (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(content))) {\n\t\t\textractFromStream(zipStream, overwrite, outputDirectory);\n\t\t\tfixExecutableFlag(outputDirectory, \"mvnw\");\n\t\t\tfixExecutableFlag(outputDirectory, \"gradlew\");\n\t\t\tLog.info(\"Project extracted to '\" + outputDirectory.getAbsolutePath() + \"'\");\n\t\t}\n\t}\n\n\tprivate void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputDirectory)\n\t\t\tthrows IOException {\n\t\tZipEntry entry = zipStream.getNextEntry();\n\t\tString canonicalOutputPath = outputDirectory.getCanonicalPath() + File.separator;\n\t\twhile (entry != null) {\n\t\t\tFile file = new File(outputDirectory, entry.getName());\n\t\t\tString canonicalEntryPath = file.getCanonicalPath();\n\t\t\tif (!canonicalEntryPath.startsWith(canonicalOutputPath)) {\n\t\t\t\tthrow new ReportableException(\"Entry '\" + entry.getName() + \"' would be written to '\"\n\t\t\t\t\t\t+ canonicalEntryPath + \"'. This is outside the output location of '\" + canonicalOutputPath\n\t\t\t\t\t\t+ \"'. Verify your target server configuration.\");\n\t\t\t}\n\t\t\tif (file.exists() && !overwrite) {\n\t\t\t\tthrow new ReportableException((file.isDirectory() ? \"Directory\" : \"File\") + \" '\" + file.getName()\n\t\t\t\t\t\t+ \"' already exists. Use --force if you want to overwrite or \"\n\t\t\t\t\t\t+ \"specify an alternate location.\");\n\t\t\t}\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\tFileCopyUtils.copy(StreamUtils.nonClosing(zipStream), new FileOutputStream(file));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfile.mkdir();\n\t\t\t}\n\t\t\tzipStream.closeEntry();\n\t\t\tentry = zipStream.getNextEntry();\n\t\t}\n\t}\n\n\tprivate void writeProject(ProjectGenerationResponse entity, String output, boolean overwrite) throws IOException {\n\t\tFile outputFile = new File(output);\n\t\tif (outputFile.exists()) {\n\t\t\tif (!overwrite) {\n\t\t\t\tthrow new ReportableException(\n\t\t\t\t\t\t\"File '\" + outputFile.getName() + \"' already exists. Use --force if you want to \"\n\t\t\t\t\t\t\t\t+ \"overwrite or specify an alternate location.\");\n\t\t\t}\n\t\t\tif (!outputFile.delete()) {\n\t\t\t\tthrow new ReportableException(\"Failed to delete existing file \" + outputFile.getPath());\n\t\t\t}\n\t\t}\n\t\tbyte[] content = entity.getContent();\n\t\tAssert.state(content != null, \"'content' must not be null\");\n\t\tFileCopyUtils.copy(content, outputFile);\n\t\tLog.info(\"Content saved to '\" + output + \"'\");\n\t}\n\n\tprivate void fixExecutableFlag(File dir, String fileName) {\n\t\tFile f = new File(dir, fileName);\n\t\tif (f.exists()) {\n\t\t\tf.setExecutable(true, false);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Represent a project type that is supported by a service.\n *\n * @author Stephane Nicoll\n */\nclass ProjectType {\n\n\tprivate final String id;\n\n\tprivate final String name;\n\n\tprivate final String action;\n\n\tprivate final boolean defaultType;\n\n\tprivate final Map<String, String> tags = new HashMap<>();\n\n\tProjectType(String id, String name, String action, boolean defaultType, @Nullable Map<String, String> tags) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.action = action;\n\t\tthis.defaultType = defaultType;\n\t\tif (tags != null) {\n\t\t\tthis.tags.putAll(tags);\n\t\t}\n\t}\n\n\tString getId() {\n\t\treturn this.id;\n\t}\n\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\tString getAction() {\n\t\treturn this.action;\n\t}\n\n\tboolean isDefaultType() {\n\t\treturn this.defaultType;\n\t}\n\n\tMap<String, String> getTags() {\n\t\treturn Collections.unmodifiableMap(this.tags);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ReportableException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\n/**\n * Exception with a message that can be reported to the user.\n *\n * @author Stephane Nicoll\n * @since 1.2.0\n */\npublic class ReportableException extends RuntimeException {\n\n\tpublic ReportableException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic ReportableException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ServiceCapabilitiesReportGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\n/**\n * A helper class generating a report from the meta-data of a particular service.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass ServiceCapabilitiesReportGenerator {\n\n\tprivate static final String NEW_LINE = System.lineSeparator();\n\n\tprivate final InitializrService initializrService;\n\n\t/**\n\t * Creates an instance using the specified {@link InitializrService}.\n\t * @param initializrService the initializr service\n\t */\n\tServiceCapabilitiesReportGenerator(InitializrService initializrService) {\n\t\tthis.initializrService = initializrService;\n\t}\n\n\t/**\n\t * Generate a report for the specified service. The report contains the available\n\t * capabilities as advertised by the root endpoint.\n\t * @param url the url of the service\n\t * @return the report that describes the service\n\t * @throws IOException if the report cannot be generated\n\t */\n\tString generate(String url) throws IOException {\n\t\tObject content = this.initializrService.loadServiceCapabilities(url);\n\t\tif (content instanceof InitializrServiceMetadata metadata) {\n\t\t\treturn generateHelp(url, metadata);\n\t\t}\n\t\treturn content.toString();\n\t}\n\n\tprivate String generateHelp(String url, InitializrServiceMetadata metadata) {\n\t\tString header = \"Capabilities of \" + url;\n\t\tStringBuilder report = new StringBuilder();\n\t\treport.append(\"=\".repeat(header.length())).append(NEW_LINE);\n\t\treport.append(header).append(NEW_LINE);\n\t\treport.append(\"=\".repeat(header.length())).append(NEW_LINE);\n\t\treport.append(NEW_LINE);\n\t\treportAvailableDependencies(metadata, report);\n\t\treport.append(NEW_LINE);\n\t\treportAvailableProjectTypes(metadata, report);\n\t\treport.append(NEW_LINE);\n\t\treportDefaults(report, metadata);\n\t\treturn report.toString();\n\t}\n\n\tprivate void reportAvailableDependencies(InitializrServiceMetadata metadata, StringBuilder report) {\n\t\treport.append(\"Available dependencies:\").append(NEW_LINE);\n\t\treport.append(\"-----------------------\").append(NEW_LINE);\n\t\tList<Dependency> dependencies = getSortedDependencies(metadata);\n\t\tfor (Dependency dependency : dependencies) {\n\t\t\treport.append(dependency.getId()).append(\" - \").append(dependency.getName());\n\t\t\tif (dependency.getDescription() != null) {\n\t\t\t\treport.append(\": \").append(dependency.getDescription());\n\t\t\t}\n\t\t\treport.append(NEW_LINE);\n\t\t}\n\t}\n\n\tprivate List<Dependency> getSortedDependencies(InitializrServiceMetadata metadata) {\n\t\tList<Dependency> dependencies = new ArrayList<>(metadata.getDependencies());\n\t\tdependencies.sort(Comparator.comparing(Dependency::getId));\n\t\treturn dependencies;\n\t}\n\n\tprivate void reportAvailableProjectTypes(InitializrServiceMetadata metadata, StringBuilder report) {\n\t\treport.append(\"Available project types:\").append(NEW_LINE);\n\t\treport.append(\"------------------------\").append(NEW_LINE);\n\t\tSortedSet<Entry<String, ProjectType>> entries = new TreeSet<>(Entry.comparingByKey());\n\t\tentries.addAll(metadata.getProjectTypes().entrySet());\n\t\tfor (Entry<String, ProjectType> entry : entries) {\n\t\t\tProjectType type = entry.getValue();\n\t\t\treport.append(entry.getKey()).append(\" -  \").append(type.getName());\n\t\t\tif (!type.getTags().isEmpty()) {\n\t\t\t\treportTags(report, type);\n\t\t\t}\n\t\t\tif (type.isDefaultType()) {\n\t\t\t\treport.append(\" (default)\");\n\t\t\t}\n\t\t\treport.append(NEW_LINE);\n\t\t}\n\t}\n\n\tprivate void reportTags(StringBuilder report, ProjectType type) {\n\t\tMap<String, String> tags = type.getTags();\n\t\tIterator<Map.Entry<String, String>> iterator = tags.entrySet().iterator();\n\t\treport.append(\" [\");\n\t\twhile (iterator.hasNext()) {\n\t\t\tMap.Entry<String, String> entry = iterator.next();\n\t\t\treport.append(entry.getKey()).append(\":\").append(entry.getValue());\n\t\t\tif (iterator.hasNext()) {\n\t\t\t\treport.append(\", \");\n\t\t\t}\n\t\t}\n\t\treport.append(\"]\");\n\t}\n\n\tprivate void reportDefaults(StringBuilder report, InitializrServiceMetadata metadata) {\n\t\treport.append(\"Defaults:\").append(NEW_LINE);\n\t\treport.append(\"---------\").append(NEW_LINE);\n\t\tList<String> defaultsKeys = new ArrayList<>(metadata.getDefaults().keySet());\n\t\tCollections.sort(defaultsKeys);\n\t\tfor (String defaultsKey : defaultsKeys) {\n\t\t\tString defaultsValue = metadata.getDefaults().get(defaultsKey);\n\t\t\treport.append(defaultsKey).append(\": \").append(defaultsValue).append(NEW_LINE);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CLI command for initializing a new application using Spring Initializr.\n */\n@NullMarked\npackage org.springframework.boot.cli.command.init;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/OptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.options;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Function;\n\nimport joptsimple.BuiltinHelpFormatter;\nimport joptsimple.HelpFormatter;\nimport joptsimple.OptionDescriptor;\nimport joptsimple.OptionParser;\nimport joptsimple.OptionSet;\nimport joptsimple.OptionSpecBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.OptionParsingCommand;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * Delegate used by {@link OptionParsingCommand} to parse options and run the command.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see OptionParsingCommand\n * @see #run(OptionSet)\n */\npublic class OptionHandler {\n\n\tprivate final Function<String, String> argumentProcessor;\n\n\tprivate @Nullable OptionParser parser;\n\n\tprivate @Nullable String help;\n\n\tprivate @Nullable Collection<OptionHelp> optionHelp;\n\n\t/**\n\t * Create a new {@link OptionHandler} instance.\n\t */\n\tpublic OptionHandler() {\n\t\tthis(Function.identity());\n\t}\n\n\t/**\n\t * Create a new {@link OptionHandler} instance with an argument processor.\n\t * @param argumentProcessor strategy that can be used to manipulate arguments before\n\t * they are used.\n\t */\n\tpublic OptionHandler(Function<String, String> argumentProcessor) {\n\t\tthis.argumentProcessor = argumentProcessor;\n\t}\n\n\tpublic OptionSpecBuilder option(String name, String description) {\n\t\treturn getParser().accepts(name, description);\n\t}\n\n\tpublic OptionSpecBuilder option(List<String> aliases, String description) {\n\t\treturn getParser().acceptsAll(aliases, description);\n\t}\n\n\tpublic OptionParser getParser() {\n\t\tif (this.parser == null) {\n\t\t\tthis.parser = new OptionParser();\n\t\t\toptions();\n\t\t}\n\t\treturn this.parser;\n\t}\n\n\tprotected void options() {\n\t}\n\n\tpublic final ExitStatus run(String... args) throws Exception {\n\t\tString[] argsToUse = args.clone();\n\t\tfor (int i = 0; i < argsToUse.length; i++) {\n\t\t\tif (\"-cp\".equals(argsToUse[i])) {\n\t\t\t\targsToUse[i] = \"--cp\";\n\t\t\t}\n\t\t\targsToUse[i] = this.argumentProcessor.apply(argsToUse[i]);\n\t\t}\n\t\tOptionSet options = getParser().parse(argsToUse);\n\t\treturn run(options);\n\t}\n\n\t/**\n\t * Run the command using the specified parsed {@link OptionSet}.\n\t * @param options the parsed option set\n\t * @return an ExitStatus\n\t * @throws Exception in case of errors\n\t */\n\tprotected ExitStatus run(OptionSet options) throws Exception {\n\t\treturn ExitStatus.OK;\n\t}\n\n\tpublic String getHelp() {\n\t\tif (this.help == null) {\n\t\t\tgetParser().formatHelpWith(new BuiltinHelpFormatter(80, 2));\n\t\t\tOutputStream out = new ByteArrayOutputStream();\n\t\t\ttry {\n\t\t\t\tgetParser().printHelpOn(out);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\treturn \"Help not available\";\n\t\t\t}\n\t\t\tthis.help = out.toString().replace(\" --cp \", \" -cp  \");\n\t\t}\n\t\treturn this.help;\n\t}\n\n\tpublic Collection<OptionHelp> getOptionsHelp() {\n\t\tif (this.optionHelp == null) {\n\t\t\tOptionHelpFormatter formatter = new OptionHelpFormatter();\n\t\t\tgetParser().formatHelpWith(formatter);\n\t\t\ttry {\n\t\t\t\tgetParser().printHelpOn(new ByteArrayOutputStream());\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore and provide no hints\n\t\t\t}\n\t\t\tthis.optionHelp = formatter.getOptionHelp();\n\t\t}\n\t\treturn this.optionHelp;\n\t}\n\n\tprivate static final class OptionHelpFormatter implements HelpFormatter {\n\n\t\tprivate final List<OptionHelp> help = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic String format(Map<String, ? extends OptionDescriptor> options) {\n\t\t\tComparator<OptionDescriptor> comparator = Comparator\n\t\t\t\t.comparing((optionDescriptor) -> optionDescriptor.options().iterator().next());\n\t\t\tSet<OptionDescriptor> sorted = new TreeSet<>(comparator);\n\t\t\tsorted.addAll(options.values());\n\t\t\tfor (OptionDescriptor descriptor : sorted) {\n\t\t\t\tif (!descriptor.representsNonOptions()) {\n\t\t\t\t\tthis.help.add(new OptionHelpAdapter(descriptor));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tCollection<OptionHelp> getOptionHelp() {\n\t\t\treturn Collections.unmodifiableList(this.help);\n\t\t}\n\n\t}\n\n\tprivate static class OptionHelpAdapter implements OptionHelp {\n\n\t\tprivate final Set<String> options;\n\n\t\tprivate final String description;\n\n\t\tOptionHelpAdapter(OptionDescriptor descriptor) {\n\t\t\tthis.options = new LinkedHashSet<>();\n\t\t\tfor (String option : descriptor.options()) {\n\t\t\t\tString prefix = (option.length() != 1) ? \"--\" : \"-\";\n\t\t\t\tthis.options.add(prefix + option);\n\t\t\t}\n\t\t\tif (this.options.contains(\"--cp\")) {\n\t\t\t\tthis.options.remove(\"--cp\");\n\t\t\t\tthis.options.add(\"-cp\");\n\t\t\t}\n\t\t\tthis.description = descriptor.description();\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> getOptions() {\n\t\t\treturn this.options;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsageHelp() {\n\t\t\treturn this.description;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/OptionHelp.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.options;\n\nimport java.util.Set;\n\n/**\n * Help for a specific option.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic interface OptionHelp {\n\n\t/**\n\t * Returns the set of options that are mutually synonymous.\n\t * @return the options\n\t */\n\tSet<String> getOptions();\n\n\t/**\n\t * Returns usage help for the option.\n\t * @return the usage help\n\t */\n\tString getUsageHelp();\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for handling command line options.\n */\n@NullMarked\npackage org.springframework.boot.cli.command.options;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Command infrastructure for the CLI.\n */\n@NullMarked\npackage org.springframework.boot.cli.command;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/AnsiString.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport jline.Terminal;\nimport org.fusesource.jansi.Ansi;\nimport org.fusesource.jansi.AnsiRenderer.Code;\n\n/**\n * Simple utility class to build an ANSI string when supported by the {@link Terminal}.\n *\n * @author Phillip Webb\n */\nclass AnsiString {\n\n\tprivate final Terminal terminal;\n\n\tprivate final StringBuilder value = new StringBuilder();\n\n\t/**\n\t * Create a new {@link AnsiString} for the given {@link Terminal}.\n\t * @param terminal the terminal used to test if {@link Terminal#isAnsiSupported() ANSI\n\t * is supported}.\n\t */\n\tAnsiString(Terminal terminal) {\n\t\tthis.terminal = terminal;\n\t}\n\n\t/**\n\t * Append text with the given ANSI codes.\n\t * @param text the text to append\n\t * @param codes the ANSI codes\n\t * @return this string\n\t */\n\tAnsiString append(String text, Code... codes) {\n\t\tif (codes.length == 0 || !isAnsiSupported()) {\n\t\t\tthis.value.append(text);\n\t\t\treturn this;\n\t\t}\n\t\tAnsi ansi = Ansi.ansi();\n\t\tfor (Code code : codes) {\n\t\t\tansi = applyCode(ansi, code);\n\t\t}\n\t\tthis.value.append(ansi.a(text).reset().toString());\n\t\treturn this;\n\t}\n\n\tprivate Ansi applyCode(Ansi ansi, Code code) {\n\t\tif (code.isColor()) {\n\t\t\tif (code.isBackground()) {\n\t\t\t\treturn ansi.bg(code.getColor());\n\t\t\t}\n\t\t\treturn ansi.fg(code.getColor());\n\t\t}\n\t\treturn ansi.a(code.getAttribute());\n\t}\n\n\tprivate boolean isAnsiSupported() {\n\t\treturn this.terminal.isAnsiSupported();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value.toString();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ClearCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport jline.console.ConsoleReader;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * Clear the {@link Shell} screen.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\nclass ClearCommand extends AbstractCommand {\n\n\tprivate final ConsoleReader consoleReader;\n\n\tClearCommand(ConsoleReader consoleReader) {\n\t\tsuper(\"clear\", \"Clear the screen\");\n\t\tthis.consoleReader = consoleReader;\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\tthis.consoleReader.setPrompt(\"\");\n\t\tthis.consoleReader.clearScreen();\n\t\treturn ExitStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/CommandCompleter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport jline.console.ConsoleReader;\nimport jline.console.completer.AggregateCompleter;\nimport jline.console.completer.ArgumentCompleter;\nimport jline.console.completer.ArgumentCompleter.ArgumentDelimiter;\nimport jline.console.completer.Completer;\nimport jline.console.completer.FileNameCompleter;\nimport jline.console.completer.StringsCompleter;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.options.OptionHelp;\nimport org.springframework.boot.cli.util.Log;\nimport org.springframework.util.StringUtils;\n\n/**\n * JLine {@link Completer} for Spring Boot {@link Command}s.\n *\n * @author Jon Brisbin\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class CommandCompleter extends StringsCompleter {\n\n\tprivate final Map<String, Completer> commandCompleters = new HashMap<>();\n\n\tprivate final List<Command> commands = new ArrayList<>();\n\n\tprivate final ConsoleReader console;\n\n\tpublic CommandCompleter(ConsoleReader consoleReader, ArgumentDelimiter argumentDelimiter,\n\t\t\tIterable<Command> commands) {\n\t\tthis.console = consoleReader;\n\t\tList<String> names = new ArrayList<>();\n\t\tfor (Command command : commands) {\n\t\t\tthis.commands.add(command);\n\t\t\tnames.add(command.getName());\n\t\t\tList<String> options = new ArrayList<>();\n\t\t\tfor (OptionHelp optionHelp : command.getOptionsHelp()) {\n\t\t\t\toptions.addAll(optionHelp.getOptions());\n\t\t\t}\n\t\t\tAggregateCompleter argumentCompleters = new AggregateCompleter(new StringsCompleter(options),\n\t\t\t\t\tnew FileNameCompleter());\n\t\t\tArgumentCompleter argumentCompleter = new ArgumentCompleter(argumentDelimiter, argumentCompleters);\n\t\t\targumentCompleter.setStrict(false);\n\t\t\tthis.commandCompleters.put(command.getName(), argumentCompleter);\n\t\t}\n\t\tgetStrings().addAll(names);\n\t}\n\n\t@Override\n\tpublic int complete(String buffer, int cursor, List<CharSequence> candidates) {\n\t\tint completionIndex = super.complete(buffer, cursor, candidates);\n\t\tint spaceIndex = buffer.indexOf(' ');\n\t\tString commandName = ((spaceIndex != -1) ? buffer.substring(0, spaceIndex) : \"\");\n\t\tif (StringUtils.hasText(commandName)) {\n\t\t\tfor (Command command : this.commands) {\n\t\t\t\tif (command.getName().equals(commandName)) {\n\t\t\t\t\tif (cursor == buffer.length() && buffer.endsWith(\" \")) {\n\t\t\t\t\t\tprintUsage(command);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tCompleter completer = this.commandCompleters.get(command.getName());\n\t\t\t\t\tif (completer != null) {\n\t\t\t\t\t\tcompletionIndex = completer.complete(buffer, cursor, candidates);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn completionIndex;\n\t}\n\n\tprivate void printUsage(Command command) {\n\t\ttry {\n\t\t\tint maxOptionsLength = 0;\n\t\t\tList<OptionHelpLine> optionHelpLines = new ArrayList<>();\n\t\t\tfor (OptionHelp optionHelp : command.getOptionsHelp()) {\n\t\t\t\tOptionHelpLine optionHelpLine = new OptionHelpLine(optionHelp);\n\t\t\t\toptionHelpLines.add(optionHelpLine);\n\t\t\t\tmaxOptionsLength = Math.max(maxOptionsLength, optionHelpLine.getOptions().length());\n\t\t\t}\n\n\t\t\tthis.console.println();\n\t\t\tthis.console.println(\"Usage:\");\n\t\t\tthis.console.println(command.getName() + \" \" + command.getUsageHelp());\n\t\t\tfor (OptionHelpLine optionHelpLine : optionHelpLines) {\n\t\t\t\tthis.console.println(String.format(\"\\t%\" + maxOptionsLength + \"s: %s\", optionHelpLine.getOptions(),\n\t\t\t\t\t\toptionHelpLine.getUsage()));\n\t\t\t}\n\t\t\tthis.console.drawLine();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tLog.error(ex.getMessage() + \" (\" + ex.getClass().getName() + \")\");\n\t\t}\n\t}\n\n\t/**\n\t * Encapsulated options and usage help.\n\t */\n\tprivate static class OptionHelpLine {\n\n\t\tprivate final String options;\n\n\t\tprivate final String usage;\n\n\t\tOptionHelpLine(OptionHelp optionHelp) {\n\t\t\tthis.options = String.join(\", \", optionHelp.getOptions());\n\t\t\tthis.usage = optionHelp.getUsageHelp();\n\t\t}\n\n\t\tString getOptions() {\n\t\t\treturn this.options;\n\t\t}\n\n\t\tString getUsage() {\n\t\t\treturn this.usage;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/EscapeAwareWhiteSpaceArgumentDelimiter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport jline.console.completer.ArgumentCompleter.ArgumentList;\nimport jline.console.completer.ArgumentCompleter.WhitespaceArgumentDelimiter;\n\n/**\n * Escape aware variant of {@link WhitespaceArgumentDelimiter}.\n *\n * @author Phillip Webb\n */\nclass EscapeAwareWhiteSpaceArgumentDelimiter extends WhitespaceArgumentDelimiter {\n\n\t@Override\n\tpublic boolean isEscaped(CharSequence buffer, int pos) {\n\t\treturn (isEscapeChar(buffer, pos - 1));\n\t}\n\n\tprivate boolean isEscapeChar(CharSequence buffer, int pos) {\n\t\tif (pos >= 0) {\n\t\t\tfor (char c : getEscapeChars()) {\n\t\t\t\tif (buffer.charAt(pos) == c) {\n\t\t\t\t\treturn !isEscapeChar(buffer, pos - 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean isQuoted(CharSequence buffer, int pos) {\n\t\tint closingQuote = searchBackwards(buffer, pos - 1, getQuoteChars());\n\t\tif (closingQuote == -1) {\n\t\t\treturn false;\n\t\t}\n\t\tint openingQuote = searchBackwards(buffer, closingQuote - 1, buffer.charAt(closingQuote));\n\t\tif (openingQuote == -1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn isQuoted(buffer, openingQuote - 1);\n\t}\n\n\tprivate int searchBackwards(CharSequence buffer, int pos, char... chars) {\n\t\twhile (pos >= 0) {\n\t\t\tfor (char c : chars) {\n\t\t\t\tif (buffer.charAt(pos) == c && !isEscaped(buffer, pos)) {\n\t\t\t\t\treturn pos;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpos--;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tString[] parseArguments(String line) {\n\t\tArgumentList delimit = delimit(line, 0);\n\t\treturn cleanArguments(delimit.getArguments());\n\t}\n\n\tprivate String[] cleanArguments(String[] arguments) {\n\t\tString[] cleanArguments = new String[arguments.length];\n\t\tfor (int i = 0; i < arguments.length; i++) {\n\t\t\tcleanArguments[i] = cleanArgument(arguments[i]);\n\t\t}\n\t\treturn cleanArguments;\n\t}\n\n\tprivate String cleanArgument(String argument) {\n\t\tfor (char c : getQuoteChars()) {\n\t\t\tString quote = String.valueOf(c);\n\t\t\tif (argument.startsWith(quote) && argument.endsWith(quote)) {\n\t\t\t\treturn replaceEscapes(argument.substring(1, argument.length() - 1));\n\t\t\t}\n\t\t}\n\t\treturn replaceEscapes(argument);\n\t}\n\n\tprivate String replaceEscapes(String string) {\n\t\tstring = string.replace(\"\\\\ \", \" \");\n\t\tstring = string.replace(\"\\\\\\\\\", \"\\\\\");\n\t\tstring = string.replace(\"\\\\t\", \"\\t\");\n\t\tstring = string.replace(\"\\\\\\\"\", \"\\\"\");\n\t\tstring = string.replace(\"\\\\'\", \"'\");\n\t\treturn string;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ExitCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * {@link Command} to quit the {@link Shell}.\n *\n * @author Phillip Webb\n */\nclass ExitCommand extends AbstractCommand {\n\n\tExitCommand() {\n\t\tsuper(\"exit\", \"Quit the embedded shell\");\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\tthrow new ShellExitException();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ForkProcessCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.options.OptionHelp;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.loader.tools.JavaExecutable;\n\n/**\n * Decorate an existing command to run it by forking the current java process.\n *\n * @author Phillip Webb\n */\nclass ForkProcessCommand extends RunProcessCommand {\n\n\tprivate static final String MAIN_CLASS = \"org.springframework.boot.loader.launch.JarLauncher\";\n\n\tprivate final Command command;\n\n\tForkProcessCommand(Command command) {\n\t\tsuper(new JavaExecutable().toString());\n\t\tthis.command = command;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.command.getName();\n\t}\n\n\t@Override\n\tpublic String getDescription() {\n\t\treturn this.command.getDescription();\n\t}\n\n\t@Override\n\tpublic @Nullable String getUsageHelp() {\n\t\treturn this.command.getUsageHelp();\n\t}\n\n\t@Override\n\tpublic @Nullable String getHelp() {\n\t\treturn this.command.getHelp();\n\t}\n\n\t@Override\n\tpublic Collection<OptionHelp> getOptionsHelp() {\n\t\treturn this.command.getOptionsHelp();\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\tList<String> fullArgs = new ArrayList<>();\n\t\tfullArgs.add(\"-cp\");\n\t\tfullArgs.add(System.getProperty(\"java.class.path\"));\n\t\tfullArgs.add(MAIN_CLASS);\n\t\tfullArgs.add(this.command.getName());\n\t\tfullArgs.addAll(Arrays.asList(args));\n\t\trun(fullArgs);\n\t\treturn ExitStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/PromptCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * {@link Command} to change the {@link Shell} prompt.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\npublic class PromptCommand extends AbstractCommand {\n\n\tprivate final ShellPrompts prompts;\n\n\tpublic PromptCommand(ShellPrompts shellPrompts) {\n\t\tsuper(\"prompt\", \"Change the prompt used with the current 'shell' command. \"\n\t\t\t\t+ \"Execute with no arguments to return to the previous value.\");\n\t\tthis.prompts = shellPrompts;\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... strings) throws Exception {\n\t\tif (strings.length > 0) {\n\t\t\tfor (String string : strings) {\n\t\t\t\tthis.prompts.pushPrompt(string + \" \");\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthis.prompts.popPrompt();\n\t\t}\n\t\treturn ExitStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/RunProcessCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.loader.tools.RunProcess;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Special {@link Command} used to run a process from the shell. NOTE: this command is not\n * directly installed into the shell.\n *\n * @author Phillip Webb\n */\nclass RunProcessCommand extends AbstractCommand {\n\n\tprivate final String[] command;\n\n\tprivate volatile @Nullable RunProcess process;\n\n\tRunProcessCommand(String... command) {\n\t\tsuper(\"\", \"\");\n\t\tthis.command = command;\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\treturn run(Arrays.asList(args));\n\t}\n\n\tprotected ExitStatus run(Collection<String> args) throws IOException {\n\t\tRunProcess process = new RunProcess(this.command);\n\t\tthis.process = process;\n\t\tint code = process.run(true, StringUtils.toStringArray(args));\n\t\tif (code == 0) {\n\t\t\treturn ExitStatus.OK;\n\t\t}\n\t\telse {\n\t\t\treturn new ExitStatus(code, \"EXTERNAL_ERROR\");\n\t\t}\n\t}\n\n\tboolean handleSigInt() {\n\t\tRunProcess process = this.process;\n\t\tAssert.state(process != null, \"'process' must not be null\");\n\t\treturn process.handleSigInt();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/Shell.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ServiceLoader;\nimport java.util.Set;\n\nimport jline.console.ConsoleReader;\nimport jline.console.completer.CandidateListCompletionHandler;\nimport org.fusesource.jansi.AnsiRenderer.Code;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.CommandFactory;\nimport org.springframework.boot.cli.command.CommandRunner;\nimport org.springframework.boot.cli.command.core.HelpCommand;\nimport org.springframework.boot.cli.command.core.VersionCommand;\nimport org.springframework.boot.loader.tools.SignalUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A shell for Spring Boot. Drops the user into an event loop (REPL) where command line\n * completion and history are available without relying on OS shell features.\n *\n * @author Jon Brisbin\n * @author Dave Syer\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class Shell {\n\n\tprivate static final Set<Class<?>> NON_FORKED_COMMANDS;\n\n\tstatic {\n\t\tSet<Class<?>> nonForked = new HashSet<>();\n\t\tnonForked.add(VersionCommand.class);\n\t\tNON_FORKED_COMMANDS = Collections.unmodifiableSet(nonForked);\n\t}\n\n\tprivate final ShellCommandRunner commandRunner;\n\n\tprivate final ConsoleReader consoleReader;\n\n\tprivate final EscapeAwareWhiteSpaceArgumentDelimiter argumentDelimiter = new EscapeAwareWhiteSpaceArgumentDelimiter();\n\n\tprivate final ShellPrompts prompts = new ShellPrompts();\n\n\t/**\n\t * Create a new {@link Shell} instance.\n\t * @throws IOException in case of I/O errors\n\t */\n\tShell() throws IOException {\n\t\tattachSignalHandler();\n\t\tthis.consoleReader = new ConsoleReader();\n\t\tthis.commandRunner = createCommandRunner();\n\t\tinitializeConsoleReader();\n\t}\n\n\tprivate ShellCommandRunner createCommandRunner() {\n\t\tShellCommandRunner runner = new ShellCommandRunner();\n\t\trunner.addCommand(new HelpCommand(runner));\n\t\trunner.addCommands(getCommands());\n\t\trunner.addAliases(\"exit\", \"quit\");\n\t\trunner.addAliases(\"help\", \"?\");\n\t\trunner.addAliases(\"clear\", \"cls\");\n\t\treturn runner;\n\t}\n\n\tprivate Iterable<Command> getCommands() {\n\t\tList<Command> commands = new ArrayList<>();\n\t\tServiceLoader<CommandFactory> factories = ServiceLoader.load(CommandFactory.class, getClass().getClassLoader());\n\t\tfor (CommandFactory factory : factories) {\n\t\t\tfor (Command command : factory.getCommands()) {\n\t\t\t\tcommands.add(convertToForkCommand(command));\n\t\t\t}\n\t\t}\n\t\tcommands.add(new PromptCommand(this.prompts));\n\t\tcommands.add(new ClearCommand(this.consoleReader));\n\t\tcommands.add(new ExitCommand());\n\t\treturn commands;\n\t}\n\n\tprivate Command convertToForkCommand(Command command) {\n\t\tfor (Class<?> nonForked : NON_FORKED_COMMANDS) {\n\t\t\tif (nonForked.isInstance(command)) {\n\t\t\t\treturn command;\n\t\t\t}\n\t\t}\n\t\treturn new ForkProcessCommand(command);\n\t}\n\n\tprivate void initializeConsoleReader() {\n\t\tthis.consoleReader.setHistoryEnabled(true);\n\t\tthis.consoleReader.setBellEnabled(false);\n\t\tthis.consoleReader.setExpandEvents(false);\n\t\tthis.consoleReader\n\t\t\t.addCompleter(new CommandCompleter(this.consoleReader, this.argumentDelimiter, this.commandRunner));\n\t\tthis.consoleReader.setCompletionHandler(new CandidateListCompletionHandler());\n\t}\n\n\tprivate void attachSignalHandler() {\n\t\tSignalUtils.attachSignalHandler(this::handleSigInt);\n\t}\n\n\t/**\n\t * Run the shell until the user exists.\n\t * @throws Exception on error\n\t */\n\tpublic void run() throws Exception {\n\t\tprintBanner();\n\t\ttry {\n\t\t\trunInputLoop();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (!(ex instanceof ShellExitException)) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void printBanner() {\n\t\tString version = getClass().getPackage().getImplementationVersion();\n\t\tversion = (version != null) ? \" (v\" + version + \")\" : \"\";\n\t\tSystem.out.println(ansi(\"Spring Boot\", Code.BOLD).append(version, Code.FAINT));\n\t\tSystem.out.println(ansi(\"Hit TAB to complete. Type 'help' and hit RETURN for help, and 'exit' to quit.\"));\n\t}\n\n\tprivate void runInputLoop() throws Exception {\n\t\tString line;\n\t\twhile ((line = this.consoleReader.readLine(getPrompt())) != null) {\n\t\t\twhile (line.endsWith(\"\\\\\")) {\n\t\t\t\tline = line.substring(0, line.length() - 1);\n\t\t\t\tline += this.consoleReader.readLine(\"> \");\n\t\t\t}\n\t\t\tif (StringUtils.hasLength(line)) {\n\t\t\t\tString[] args = this.argumentDelimiter.parseArguments(line);\n\t\t\t\tthis.commandRunner.runAndHandleErrors(args);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String getPrompt() {\n\t\tString prompt = this.prompts.getPrompt();\n\t\treturn ansi(prompt, Code.FG_BLUE).toString();\n\t}\n\n\tprivate AnsiString ansi(String text, Code... codes) {\n\t\treturn new AnsiString(this.consoleReader.getTerminal()).append(text, codes);\n\t}\n\n\t/**\n\t * Final handle an interrupt signal (CTRL-C).\n\t */\n\tprotected void handleSigInt() {\n\t\tif (this.commandRunner.handleSigInt()) {\n\t\t\treturn;\n\t\t}\n\t\tSystem.out.println(String.format(\"%nThanks for using Spring Boot\"));\n\t\tSystem.exit(1);\n\t}\n\n\t/**\n\t * Extension of {@link CommandRunner} to deal with {@link RunProcessCommand}s and\n\t * aliases.\n\t */\n\tprivate static class ShellCommandRunner extends CommandRunner {\n\n\t\tprivate volatile @Nullable Command lastCommand;\n\n\t\tprivate final Map<String, String> aliases = new HashMap<>();\n\n\t\tShellCommandRunner() {\n\t\t\tsuper(null);\n\t\t}\n\n\t\tvoid addAliases(String command, String... aliases) {\n\t\t\tfor (String alias : aliases) {\n\t\t\t\tthis.aliases.put(alias, command);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Command findCommand(String name) {\n\t\t\tif (name.startsWith(\"!\")) {\n\t\t\t\treturn new RunProcessCommand(name.substring(1));\n\t\t\t}\n\t\t\tif (this.aliases.containsKey(name)) {\n\t\t\t\tname = this.aliases.get(name);\n\t\t\t}\n\t\t\treturn super.findCommand(name);\n\t\t}\n\n\t\t@Override\n\t\tprotected void beforeRun(Command command) {\n\t\t\tthis.lastCommand = command;\n\t\t}\n\n\t\t@Override\n\t\tprotected void afterRun(Command command) {\n\t\t}\n\n\t\tboolean handleSigInt() {\n\t\t\tCommand command = this.lastCommand;\n\t\t\tif (command instanceof RunProcessCommand runProcessCommand) {\n\t\t\t\treturn runProcessCommand.handleSigInt();\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ShellCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * {@link Command} to start a nested REPL shell.\n *\n * @author Phillip Webb\n * @since 1.0.0\n * @see Shell\n */\npublic class ShellCommand extends AbstractCommand {\n\n\tpublic ShellCommand() {\n\t\tsuper(\"shell\", \"Start a nested shell\");\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\tnew Shell().run();\n\t\treturn ExitStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ShellExitException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport org.springframework.boot.cli.command.CommandException;\n\n/**\n * Exception used to stop the {@link Shell}.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class ShellExitException extends CommandException {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tpublic ShellExitException() {\n\t\tsuper(Option.RETHROW);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ShellPrompts.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\n\n/**\n * Abstraction to manage a stack of prompts.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class ShellPrompts {\n\n\tprivate static final String DEFAULT_PROMPT = \"$ \";\n\n\tprivate final Deque<String> prompts = new ArrayDeque<>();\n\n\t/**\n\t * Push a new prompt to be used by the shell.\n\t * @param prompt the prompt\n\t * @see #popPrompt()\n\t */\n\tpublic void pushPrompt(String prompt) {\n\t\tthis.prompts.push(prompt);\n\t}\n\n\t/**\n\t * Pop a previously pushed prompt, returning to the previous value.\n\t * @see #pushPrompt(String)\n\t */\n\tpublic void popPrompt() {\n\t\tif (!this.prompts.isEmpty()) {\n\t\t\tthis.prompts.pop();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the current prompt.\n\t * @return the current prompt\n\t */\n\tpublic String getPrompt() {\n\t\treturn this.prompts.isEmpty() ? DEFAULT_PROMPT : this.prompts.peek();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for running a nested shell in the CLI.\n */\n@NullMarked\npackage org.springframework.boot.cli.command.shell;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/status/ExitStatus.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.status;\n\n/**\n * Encapsulation of the outcome of a command.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see ExitStatus#OK\n * @see ExitStatus#ERROR\n */\npublic final class ExitStatus {\n\n\t/**\n\t * Generic \"OK\" exit status with zero exit code and {@literal hangup=false}.\n\t */\n\tpublic static final ExitStatus OK = new ExitStatus(0, \"OK\");\n\n\t/**\n\t * Generic \"not OK\" exit status with non-zero exit code and {@literal hangup=true}.\n\t */\n\tpublic static final ExitStatus ERROR = new ExitStatus(-1, \"ERROR\", true);\n\n\tprivate final int code;\n\n\tprivate final String name;\n\n\tprivate final boolean hangup;\n\n\t/**\n\t * Create a new {@link ExitStatus} instance.\n\t * @param code the exit code\n\t * @param name the name\n\t */\n\tpublic ExitStatus(int code, String name) {\n\t\tthis(code, name, false);\n\t}\n\n\t/**\n\t * Create a new {@link ExitStatus} instance.\n\t * @param code the exit code\n\t * @param name the name\n\t * @param hangup true if it is OK for the caller to hangup\n\t */\n\tpublic ExitStatus(int code, String name, boolean hangup) {\n\t\tthis.code = code;\n\t\tthis.name = name;\n\t\tthis.hangup = hangup;\n\t}\n\n\t/**\n\t * An exit code appropriate for use in {@code System.exit()}.\n\t * @return an exit code\n\t */\n\tpublic int getCode() {\n\t\treturn this.code;\n\t}\n\n\t/**\n\t * A name describing the outcome.\n\t * @return a name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Flag to signal that the caller can (or should) hangup. A server process with\n\t * non-daemon threads should set this to false.\n\t * @return the flag\n\t */\n\tpublic boolean isHangup() {\n\t\treturn this.hangup;\n\t}\n\n\t/**\n\t * Convert the existing code to a hangup.\n\t * @return a new ExitStatus with hangup=true\n\t */\n\tpublic ExitStatus hangup() {\n\t\treturn new ExitStatus(this.code, this.name, true);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \":\" + getCode();\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/status/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * CLI command status.\n */\n@NullMarked\npackage org.springframework.boot.cli.command.status;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Main entry point of the Spring Boot CLI.\n */\n@NullMarked\npackage org.springframework.boot.cli;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/util/Log.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.util;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Simple logger used by the CLI.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic abstract class Log {\n\n\tprivate static @Nullable LogListener listener;\n\n\tpublic static void info(@Nullable String message) {\n\t\tSystem.out.println(message);\n\t\tif (listener != null) {\n\t\t\tlistener.info(message);\n\t\t}\n\t}\n\n\tpublic static void infoPrint(@Nullable String message) {\n\t\tSystem.out.print(message);\n\t\tif (listener != null) {\n\t\t\tlistener.infoPrint(message);\n\t\t}\n\t}\n\n\tpublic static void error(@Nullable String message) {\n\t\tSystem.err.println(message);\n\t\tif (listener != null) {\n\t\t\tlistener.error(message);\n\t\t}\n\t}\n\n\tpublic static void error(Exception ex) {\n\t\tex.printStackTrace(System.err);\n\t\tif (listener != null) {\n\t\t\tlistener.error(ex);\n\t\t}\n\t}\n\n\tstatic void setListener(@Nullable LogListener listener) {\n\t\tLog.listener = listener;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/util/LogListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.util;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Listener that can be attached to the {@link Log} to capture calls.\n *\n * @author Phillip Webb\n */\ninterface LogListener {\n\n\tvoid info(@Nullable String message);\n\n\tvoid infoPrint(@Nullable String message);\n\n\tvoid error(@Nullable String message);\n\n\tvoid error(Exception ex);\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utility classes for the CLI.\n */\n@NullMarked\npackage org.springframework.boot.cli.util;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "cli/spring-boot-cli/src/main/resources/META-INF/services/org.springframework.boot.cli.command.CommandFactory",
    "content": "org.springframework.boot.cli.DefaultCommandFactory\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/cli/command/CustomCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage cli.command;\n\nimport org.springframework.boot.cli.command.AbstractCommand;\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\n/**\n * @author Dave Syer\n */\npublic class CustomCommand extends AbstractCommand {\n\n\tpublic CustomCommand() {\n\t\tsuper(\"custom\", \"Custom command added in tests\");\n\t}\n\n\t@Override\n\tpublic ExitStatus run(String... args) throws Exception {\n\t\tSystem.err.println(\"Custom Command Hello\");\n\t\treturn ExitStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/cli/command/CustomCommandFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage cli.command;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.springframework.boot.cli.command.Command;\nimport org.springframework.boot.cli.command.CommandFactory;\n\n/**\n * @author Dave Syer\n */\npublic class CustomCommandFactory implements CommandFactory {\n\n\t@Override\n\tpublic Collection<Command> getCommands() {\n\t\treturn Collections.singleton(new CustomCommand());\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/CommandRunnerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CommandRunner}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass CommandRunnerIntegrationTests {\n\n\t@BeforeEach\n\tvoid clearDebug() {\n\t\tSystem.clearProperty(\"debug\");\n\t}\n\n\t@Test\n\tvoid debugEnabledAndArgumentRemovedWhenNotAnApplicationArgument() {\n\t\tCommandRunner runner = new CommandRunner(\"spring\");\n\t\tArgHandlingCommand command = new ArgHandlingCommand();\n\t\trunner.addCommand(command);\n\t\trunner.runAndHandleErrors(\"args\", \"samples/app.groovy\", \"--debug\");\n\t\tassertThat(command.args).containsExactly(\"samples/app.groovy\");\n\t\tassertThat(System.getProperty(\"debug\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid debugNotEnabledAndArgumentRetainedWhenAnApplicationArgument() {\n\t\tCommandRunner runner = new CommandRunner(\"spring\");\n\t\tArgHandlingCommand command = new ArgHandlingCommand();\n\t\trunner.addCommand(command);\n\t\trunner.runAndHandleErrors(\"args\", \"samples/app.groovy\", \"--\", \"--debug\");\n\t\tassertThat(command.args).containsExactly(\"samples/app.groovy\", \"--\", \"--debug\");\n\t\tassertThat(System.getProperty(\"debug\")).isNull();\n\t}\n\n\tstatic class ArgHandlingCommand extends AbstractCommand {\n\n\t\tprivate String @Nullable [] args;\n\n\t\tArgHandlingCommand() {\n\t\t\tsuper(\"args\", \"\");\n\t\t}\n\n\t\t@Override\n\t\tpublic ExitStatus run(String... args) throws Exception {\n\t\t\tthis.args = args;\n\t\t\treturn ExitStatus.OK;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/CommandRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport java.util.EnumSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.cli.command.core.HelpCommand;\nimport org.springframework.boot.cli.command.core.HintCommand;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.lenient;\n\n/**\n * Tests for {@link CommandRunner}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n */\n@ExtendWith(MockitoExtension.class)\nclass CommandRunnerTests {\n\n\tprivate CommandRunner commandRunner;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Command regularCommand;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Command anotherCommand;\n\n\tprivate final Set<Call> calls = EnumSet.noneOf(Call.class);\n\n\tprivate ClassLoader loader;\n\n\t@AfterEach\n\tvoid close() {\n\t\tThread.currentThread().setContextClassLoader(this.loader);\n\t\tSystem.clearProperty(\"debug\");\n\t}\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.loader = Thread.currentThread().getContextClassLoader();\n\t\tthis.commandRunner = new CommandRunner(\"spring\") {\n\n\t\t\t@Override\n\t\t\tprotected void showUsage() {\n\t\t\t\tCommandRunnerTests.this.calls.add(Call.SHOW_USAGE);\n\t\t\t\tsuper.showUsage();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected boolean errorMessage(@Nullable String message) {\n\t\t\t\tCommandRunnerTests.this.calls.add(Call.ERROR_MESSAGE);\n\t\t\t\treturn super.errorMessage(message);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected void printStackTrace(Exception ex) {\n\t\t\t\tCommandRunnerTests.this.calls.add(Call.PRINT_STACK_TRACE);\n\t\t\t\tsuper.printStackTrace(ex);\n\t\t\t}\n\t\t};\n\t\tlenient().doReturn(\"another\").when(this.anotherCommand).getName();\n\t\tlenient().doReturn(\"command\").when(this.regularCommand).getName();\n\t\tlenient().doReturn(\"A regular command\").when(this.regularCommand).getDescription();\n\t\tthis.commandRunner.addCommand(this.regularCommand);\n\t\tthis.commandRunner.addCommand(new HelpCommand(this.commandRunner));\n\t\tthis.commandRunner.addCommand(new HintCommand(this.commandRunner));\n\t}\n\n\t@Test\n\tvoid runWithoutArguments() {\n\t\tassertThatExceptionOfType(NoArgumentsException.class).isThrownBy(this.commandRunner::run);\n\t}\n\n\t@Test\n\tvoid runCommand() throws Exception {\n\t\tthis.commandRunner.run(\"command\", \"--arg1\", \"arg2\");\n\t\tthen(this.regularCommand).should().run(\"--arg1\", \"arg2\");\n\t}\n\n\t@Test\n\tvoid missingCommand() {\n\t\tassertThatExceptionOfType(NoSuchCommandException.class).isThrownBy(() -> this.commandRunner.run(\"missing\"));\n\t}\n\n\t@Test\n\tvoid appArguments() throws Exception {\n\t\tthis.commandRunner.runAndHandleErrors(\"command\", \"--\", \"--debug\", \"bar\");\n\t\tthen(this.regularCommand).should().run(\"--\", \"--debug\", \"bar\");\n\t\t// When handled by the command itself it shouldn't cause the system property to be\n\t\t// set\n\t\tassertThat(System.getProperty(\"debug\")).isNull();\n\t}\n\n\t@Test\n\tvoid handlesSuccess() {\n\t\tint status = this.commandRunner.runAndHandleErrors(\"command\");\n\t\tassertThat(status).isZero();\n\t\tassertThat(this.calls).isEmpty();\n\t}\n\n\t@Test\n\tvoid handlesNoSuchCommand() {\n\t\tint status = this.commandRunner.runAndHandleErrors(\"missing\");\n\t\tassertThat(status).isOne();\n\t\tassertThat(this.calls).containsOnly(Call.ERROR_MESSAGE);\n\t}\n\n\t@Test\n\tvoid handlesRegularExceptionWithMessage() throws Exception {\n\t\twillThrow(new RuntimeException(\"With Message\")).given(this.regularCommand).run();\n\t\tint status = this.commandRunner.runAndHandleErrors(\"command\");\n\t\tassertThat(status).isOne();\n\t\tassertThat(this.calls).containsOnly(Call.ERROR_MESSAGE);\n\t}\n\n\t@Test\n\tvoid handlesRegularExceptionWithoutMessage() throws Exception {\n\t\twillThrow(new RuntimeException()).given(this.regularCommand).run();\n\t\tint status = this.commandRunner.runAndHandleErrors(\"command\");\n\t\tassertThat(status).isOne();\n\t\tassertThat(this.calls).containsOnly(Call.ERROR_MESSAGE, Call.PRINT_STACK_TRACE);\n\t}\n\n\t@Test\n\tvoid handlesExceptionWithDashDashDebug() throws Exception {\n\t\twillThrow(new RuntimeException()).given(this.regularCommand).run();\n\t\tint status = this.commandRunner.runAndHandleErrors(\"command\", \"--debug\");\n\t\tassertThat(System.getProperty(\"debug\")).isEqualTo(\"true\");\n\t\tassertThat(status).isOne();\n\t\tassertThat(this.calls).containsOnly(Call.ERROR_MESSAGE, Call.PRINT_STACK_TRACE);\n\t}\n\n\t@Test\n\tvoid exceptionMessages() {\n\t\tassertThat(new NoSuchCommandException(\"name\").getMessage())\n\t\t\t.isEqualTo(\"'name' is not a valid command. See 'help'.\");\n\t}\n\n\t@Test\n\tvoid help() throws Exception {\n\t\tthis.commandRunner.run(\"help\", \"command\");\n\t\tthen(this.regularCommand).should().getHelp();\n\t}\n\n\t@Test\n\tvoid helpNoCommand() {\n\t\tassertThatExceptionOfType(NoHelpCommandArgumentsException.class)\n\t\t\t.isThrownBy(() -> this.commandRunner.run(\"help\"));\n\t}\n\n\t@Test\n\tvoid helpUnknownCommand() {\n\t\tassertThatExceptionOfType(NoSuchCommandException.class)\n\t\t\t.isThrownBy(() -> this.commandRunner.run(\"help\", \"missing\"));\n\t}\n\n\tprivate enum Call {\n\n\t\tSHOW_USAGE, ERROR_MESSAGE, PRINT_STACK_TRACE\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/OptionParsingCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cli.command.options.OptionHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OptionParsingCommand}.\n *\n * @author Dave Syer\n */\nclass OptionParsingCommandTests {\n\n\t@Test\n\tvoid optionHelp() {\n\t\tOptionHandler handler = new OptionHandler();\n\t\thandler.option(\"bar\", \"Bar\");\n\t\tOptionParsingCommand command = new TestOptionParsingCommand(\"foo\", \"Foo\", handler);\n\t\tassertThat(command.getHelp()).contains(\"--bar\");\n\t}\n\n\tstatic class TestOptionParsingCommand extends OptionParsingCommand {\n\n\t\tTestOptionParsingCommand(String name, String description, OptionHandler handler) {\n\t\t\tsuper(name, description, handler);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/encodepassword/EncodePasswordCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.encodepassword;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.cli.command.status.ExitStatus;\nimport org.springframework.boot.cli.util.MockLog;\nimport org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.factory.PasswordEncoderFactories;\nimport org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link EncodePasswordCommand}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@ExtendWith(MockitoExtension.class)\nclass EncodePasswordCommandTests {\n\n\tprivate MockLog log;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.log = MockLog.attach();\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tMockLog.clear();\n\t}\n\n\t@Test\n\tvoid encodeWithNoAlgorithmShouldUseBcrypt() throws Exception {\n\t\tEncodePasswordCommand command = new EncodePasswordCommand();\n\t\tExitStatus status = command.run(\"boot\");\n\t\tthen(this.log).should().info(assertArg((message) -> {\n\t\t\tassertThat(message).startsWith(\"{bcrypt}\");\n\t\t\tassertThat(PasswordEncoderFactories.createDelegatingPasswordEncoder().matches(\"boot\", message)).isTrue();\n\t\t}));\n\t\tassertThat(status).isEqualTo(ExitStatus.OK);\n\t}\n\n\t@Test\n\tvoid encodeWithDefaultShouldUseBcrypt() throws Exception {\n\t\tEncodePasswordCommand command = new EncodePasswordCommand();\n\t\tExitStatus status = command.run(\"-a\", \"default\", \"boot\");\n\t\tthen(this.log).should().info(assertArg((message) -> {\n\t\t\tassertThat(message).startsWith(\"{bcrypt}\");\n\t\t\tassertThat(PasswordEncoderFactories.createDelegatingPasswordEncoder().matches(\"boot\", message)).isTrue();\n\t\t}));\n\t\tassertThat(status).isEqualTo(ExitStatus.OK);\n\t}\n\n\t@Test\n\tvoid encodeWithBCryptShouldUseBCrypt() throws Exception {\n\t\tEncodePasswordCommand command = new EncodePasswordCommand();\n\t\tExitStatus status = command.run(\"-a\", \"bcrypt\", \"boot\");\n\t\tthen(this.log).should().info(assertArg((message) -> {\n\t\t\tassertThat(message).doesNotStartWith(\"{\");\n\t\t\tassertThat(new BCryptPasswordEncoder().matches(\"boot\", message)).isTrue();\n\t\t}));\n\t\tassertThat(status).isEqualTo(ExitStatus.OK);\n\t}\n\n\t@Test\n\tvoid encodeWithPbkdf2ShouldUsePbkdf2() throws Exception {\n\t\tEncodePasswordCommand command = new EncodePasswordCommand();\n\t\tExitStatus status = command.run(\"-a\", \"pbkdf2\", \"boot\");\n\t\tthen(this.log).should().info(assertArg((message) -> {\n\t\t\tassertThat(message).doesNotStartWith(\"{\");\n\t\t\tassertThat(Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8().matches(\"boot\", message)).isTrue();\n\t\t}));\n\t\tassertThat(status).isEqualTo(ExitStatus.OK);\n\t}\n\n\t@Test\n\tvoid encodeWithUnknownAlgorithmShouldExitWithError() throws Exception {\n\t\tEncodePasswordCommand command = new EncodePasswordCommand();\n\t\tExitStatus status = command.run(\"--algorithm\", \"bad\", \"boot\");\n\t\tthen(this.log).should().error(\"Unknown algorithm, valid options are: default,bcrypt,pbkdf2\");\n\t\tassertThat(status).isEqualTo(ExitStatus.ERROR);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/AbstractHttpClientMockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.classic.methods.HttpGet;\nimport org.apache.hc.core5.http.ClassicHttpResponse;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.HttpEntity;\nimport org.apache.hc.core5.http.HttpHeaders;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.message.BasicHeader;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.jspecify.annotations.Nullable;\nimport org.mockito.ArgumentMatcher;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.StreamUtils;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Abstract base class for tests that use a mock {@link HttpClient}.\n *\n * @author Stephane Nicoll\n */\npublic abstract class AbstractHttpClientMockTests {\n\n\tprotected final HttpClient http = mock(HttpClient.class);\n\n\tprotected void mockSuccessfulMetadataTextGet() throws IOException {\n\t\tmockSuccessfulMetadataGet(\"metadata/service-metadata-2.1.0.txt\", \"text/plain\", true);\n\t}\n\n\tprotected void mockSuccessfulMetadataGet(boolean serviceCapabilities) throws IOException {\n\t\tmockSuccessfulMetadataGet(\"metadata/service-metadata-2.1.0.json\", \"application/vnd.initializr.v2.1+json\",\n\t\t\t\tserviceCapabilities);\n\t}\n\n\tprotected void mockSuccessfulMetadataGetV2(boolean serviceCapabilities) throws IOException {\n\t\tmockSuccessfulMetadataGet(\"metadata/service-metadata-2.0.0.json\", \"application/vnd.initializr.v2+json\",\n\t\t\t\tserviceCapabilities);\n\t}\n\n\tprotected void mockSuccessfulMetadataGet(String contentPath, String contentType, boolean serviceCapabilities)\n\t\t\tthrows IOException {\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tbyte[] content = readClasspathResource(contentPath);\n\t\tmockHttpEntity(response, content, contentType);\n\t\tmockStatus(response, 200);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), argThat(getForMetadata(serviceCapabilities)), isNull()))\n\t\t\t.willReturn(response);\n\t}\n\n\tprotected byte[] readClasspathResource(String contentPath) throws IOException {\n\t\tResource resource = new ClassPathResource(contentPath);\n\t\treturn StreamUtils.copyToByteArray(resource.getInputStream());\n\t}\n\n\tprotected void mockSuccessfulProjectGeneration(MockHttpProjectGenerationRequest request) throws IOException {\n\t\t// Required for project generation as the metadata is read first\n\t\tmockSuccessfulMetadataGet(false);\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tmockHttpEntity(response, request.content, request.contentType);\n\t\tmockStatus(response, 200);\n\t\tString header = (request.fileName != null) ? contentDispositionValue(request.fileName) : null;\n\t\tmockHttpHeader(response, \"Content-Disposition\", header);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), argThat(getForNonMetadata()), isNull())).willReturn(response);\n\t}\n\n\tprotected void mockProjectGenerationError(int status, @Nullable String message) throws IOException, JSONException {\n\t\t// Required for project generation as the metadata is read first\n\t\tmockSuccessfulMetadataGet(false);\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tmockHttpEntity(response, createJsonError(status, message).getBytes(), \"application/json\");\n\t\tmockStatus(response, status);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), isA(HttpGet.class), isNull())).willReturn(response);\n\t}\n\n\tprotected void mockMetadataGetError(int status, String message) throws IOException, JSONException {\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tmockHttpEntity(response, createJsonError(status, message).getBytes(), \"application/json\");\n\t\tmockStatus(response, status);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), isA(HttpGet.class), isNull())).willReturn(response);\n\t}\n\n\tprotected HttpEntity mockHttpEntity(ClassicHttpResponse response, byte[] content, @Nullable String contentType) {\n\t\ttry {\n\t\t\tHttpEntity entity = mock(HttpEntity.class);\n\t\t\tgiven(entity.getContent()).willReturn(new ByteArrayInputStream(content));\n\t\t\tHeader contentTypeHeader = (contentType != null) ? new BasicHeader(\"Content-Type\", contentType) : null;\n\t\t\tgiven(entity.getContentType())\n\t\t\t\t.willReturn((contentTypeHeader != null) ? contentTypeHeader.getValue() : null);\n\t\t\tgiven(response.getEntity()).willReturn(entity);\n\t\t\treturn entity;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Should not happen\", ex);\n\t\t}\n\t}\n\n\tprotected void mockStatus(ClassicHttpResponse response, int status) {\n\t\tgiven(response.getCode()).willReturn(status);\n\t}\n\n\tprotected void mockHttpHeader(ClassicHttpResponse response, String headerName, @Nullable String value) {\n\t\tHeader header = (value != null) ? new BasicHeader(headerName, value) : null;\n\t\tgiven(response.getFirstHeader(headerName)).willReturn(header);\n\t}\n\n\tprivate ArgumentMatcher<HttpGet> getForMetadata(boolean serviceCapabilities) {\n\t\tif (!serviceCapabilities) {\n\t\t\treturn new HasAcceptHeader(InitializrService.ACCEPT_META_DATA, true);\n\t\t}\n\t\treturn new HasAcceptHeader(InitializrService.ACCEPT_SERVICE_CAPABILITIES, true);\n\t}\n\n\tprivate ArgumentMatcher<HttpGet> getForNonMetadata() {\n\t\treturn new HasAcceptHeader(InitializrService.ACCEPT_META_DATA, false);\n\t}\n\n\tprivate String contentDispositionValue(String fileName) {\n\t\treturn \"attachment; filename=\\\"\" + fileName + \"\\\"\";\n\t}\n\n\tprivate String createJsonError(int status, @Nullable String message) throws JSONException {\n\t\tJSONObject json = new JSONObject();\n\t\tjson.put(\"status\", status);\n\t\tif (message != null) {\n\t\t\tjson.put(\"message\", message);\n\t\t}\n\t\treturn json.toString();\n\t}\n\n\tstatic class MockHttpProjectGenerationRequest {\n\n\t\t@Nullable String contentType;\n\n\t\t@Nullable String fileName;\n\n\t\tbyte[] content = new byte[] { 0, 0, 0, 0 };\n\n\t\tMockHttpProjectGenerationRequest(@Nullable String contentType, @Nullable String fileName) {\n\t\t\tthis(contentType, fileName, new byte[] { 0, 0, 0, 0 });\n\t\t}\n\n\t\tMockHttpProjectGenerationRequest(@Nullable String contentType, @Nullable String fileName, byte[] content) {\n\t\t\tthis.contentType = (contentType != null) ? contentType : \"application/text\";\n\t\t\tthis.fileName = fileName;\n\t\t\tthis.content = content;\n\t\t}\n\n\t}\n\n\tstatic class HasAcceptHeader implements ArgumentMatcher<HttpGet> {\n\n\t\tprivate final String value;\n\n\t\tprivate final boolean shouldMatch;\n\n\t\tHasAcceptHeader(String value, boolean shouldMatch) {\n\t\t\tthis.value = value;\n\t\t\tthis.shouldMatch = shouldMatch;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(HttpGet get) {\n\t\t\tif (get == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tHeader acceptHeader = get.getFirstHeader(HttpHeaders.ACCEPT);\n\t\t\tif (this.shouldMatch) {\n\t\t\t\treturn acceptHeader != null && this.value.equals(acceptHeader.getValue());\n\t\t\t}\n\t\t\treturn acceptHeader == null || !this.value.equals(acceptHeader.getValue());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport joptsimple.OptionSet;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.cli.command.status.ExitStatus;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link InitCommand}\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Vignesh Thangavel Ilangovan\n */\n@ExtendWith(MockitoExtension.class)\nclass InitCommandTests extends AbstractHttpClientMockTests {\n\n\tprivate final TestableInitCommandOptionHandler handler;\n\n\tprivate final InitCommand command;\n\n\tInitCommandTests() {\n\t\tInitializrService initializrService = new InitializrService(this.http);\n\t\tthis.handler = new TestableInitCommandOptionHandler(initializrService);\n\t\tthis.command = new InitCommand(this.handler);\n\t}\n\n\t@Test\n\tvoid listServiceCapabilitiesText() throws Exception {\n\t\tmockSuccessfulMetadataTextGet();\n\t\tthis.command.run(\"--list\", \"--target=https://fake-service\");\n\t}\n\n\t@Test\n\tvoid listServiceCapabilities() throws Exception {\n\t\tmockSuccessfulMetadataGet(true);\n\t\tthis.command.run(\"--list\", \"--target=https://fake-service\");\n\t}\n\n\t@Test\n\tvoid listServiceCapabilitiesV2() throws Exception {\n\t\tmockSuccessfulMetadataGetV2(true);\n\t\tthis.command.run(\"--list\", \"--target=https://fake-service\");\n\t}\n\n\t@Test\n\tvoid generateProject() throws Exception {\n\t\tString fileName = UUID.randomUUID() + \".zip\";\n\t\tFile file = new File(fileName);\n\t\tassertThat(file).as(\"file should not exist\").doesNotExist();\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", fileName);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\ttry {\n\t\t\tassertThat(this.command.run()).isEqualTo(ExitStatus.OK);\n\t\t\tassertThat(file).as(\"file should have been created\").exists();\n\t\t}\n\t\tfinally {\n\t\t\tassertThat(file.delete()).as(\"failed to delete test file\").isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid generateProjectNoFileNameAvailable() throws Exception {\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", null);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run()).isEqualTo(ExitStatus.ERROR);\n\t}\n\n\t@Test\n\tvoid generateProjectAndExtract(@TempDir File tempDir) throws Exception {\n\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", \"demo.zip\",\n\t\t\t\tarchive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run(\"--extract\", tempDir.getAbsolutePath())).isEqualTo(ExitStatus.OK);\n\t\tFile archiveFile = new File(tempDir, \"test.txt\");\n\t\tassertThat(archiveFile).exists();\n\t}\n\n\t@Test\n\tvoid generateProjectAndExtractWillNotWriteEntriesOutsideOutputLocation(@TempDir File tempDir) throws Exception {\n\t\tbyte[] archive = createFakeZipArchive(\"../outside.txt\", \"Fake content\");\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", \"demo.zip\",\n\t\t\t\tarchive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run(\"--extract\", tempDir.getAbsolutePath())).isEqualTo(ExitStatus.ERROR);\n\t\tFile archiveFile = new File(tempDir.getParentFile(), \"outside.txt\");\n\t\tassertThat(archiveFile).doesNotExist();\n\t}\n\n\t@Test\n\tvoid generateProjectAndExtractWithConvention(@TempDir File tempDir) throws Exception {\n\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", \"demo.zip\",\n\t\t\t\tarchive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run(tempDir.getAbsolutePath() + \"/\")).isEqualTo(ExitStatus.OK);\n\t\tFile archiveFile = new File(tempDir, \"test.txt\");\n\t\tassertThat(archiveFile).exists();\n\t}\n\n\t@Test\n\tvoid generateProjectArchiveExtractedByDefault() throws Exception {\n\t\tString fileName = UUID.randomUUID().toString();\n\t\tassertThat(fileName).as(\"No dot in filename\").doesNotContain(\".\");\n\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", \"demo.zip\",\n\t\t\t\tarchive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tFile file = new File(fileName);\n\t\tFile archiveFile = new File(file, \"test.txt\");\n\t\ttry {\n\t\t\tassertThat(this.command.run(fileName)).isEqualTo(ExitStatus.OK);\n\t\t\tassertThat(archiveFile).exists();\n\t\t}\n\t\tfinally {\n\t\t\tarchiveFile.delete();\n\t\t\tfile.delete();\n\t\t}\n\t}\n\n\t@Test\n\tvoid generateProjectFileSavedAsFileByDefault() throws Exception {\n\t\tString fileName = UUID.randomUUID().toString();\n\t\tString content = \"Fake Content\";\n\t\tbyte[] archive = content.getBytes();\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/octet-stream\",\n\t\t\t\t\"pom.xml\", archive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tFile file = new File(fileName);\n\t\ttry {\n\t\t\tassertThat(this.command.run(fileName)).isEqualTo(ExitStatus.OK);\n\t\t\tassertThat(file).as(\"File not saved properly\").exists();\n\t\t\tassertThat(file).as(\"Should not be a directory\").isFile();\n\t\t}\n\t\tfinally {\n\t\t\tfile.delete();\n\t\t}\n\t}\n\n\t@Test\n\tvoid generateProjectAndExtractUnsupportedArchive(@TempDir File tempDir) throws Exception {\n\t\tString fileName = UUID.randomUUID() + \".zip\";\n\t\tFile file = new File(fileName);\n\t\tassertThat(file).as(\"file should not exist\").doesNotExist();\n\t\ttry {\n\t\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/foobar\",\n\t\t\t\t\tfileName, archive);\n\t\t\tmockSuccessfulProjectGeneration(request);\n\t\t\tassertThat(this.command.run(\"--extract\", tempDir.getAbsolutePath())).isEqualTo(ExitStatus.OK);\n\t\t\tassertThat(file).as(\"file should have been saved instead\").exists();\n\t\t}\n\t\tfinally {\n\t\t\tassertThat(file.delete()).as(\"failed to delete test file\").isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid generateProjectAndExtractUnknownContentType(@TempDir File tempDir) {\n\t\tString fileName = UUID.randomUUID() + \".zip\";\n\t\tFile file = new File(fileName);\n\t\tassertThat(file).as(\"file should not exist\").doesNotExist();\n\t\ttry {\n\t\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(null, fileName, archive);\n\t\t\tmockSuccessfulProjectGeneration(request);\n\t\t\tassertThat(this.command.run(\"--extract\", tempDir.getAbsolutePath())).isEqualTo(ExitStatus.OK);\n\t\t\tassertThat(file).as(\"file should have been saved instead\").exists();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tfail(null, ex);\n\t\t}\n\t\tfinally {\n\t\t\tassertThat(file.delete()).as(\"failed to delete test file\").isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid fileNotOverwrittenByDefault(@TempDir File tempDir) throws Exception {\n\t\tFile file = new File(tempDir, \"test.file\");\n\t\tfile.createNewFile();\n\t\tlong fileLength = file.length();\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\",\n\t\t\t\tfile.getAbsolutePath());\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run()).as(\"Should have failed\").isEqualTo(ExitStatus.ERROR);\n\t\tassertThat(file.length()).as(\"File should not have changed\").isEqualTo(fileLength);\n\t}\n\n\t@Test\n\tvoid overwriteFile(@TempDir File tempDir) throws Exception {\n\t\tFile file = new File(tempDir, \"test.file\");\n\t\tfile.createNewFile();\n\t\tlong fileLength = file.length();\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\",\n\t\t\t\tfile.getAbsolutePath());\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run(\"--force\")).isEqualTo(ExitStatus.OK);\n\t\tassertThat(fileLength).as(\"File should have changed\").isNotEqualTo(file.length());\n\t}\n\n\t@Test\n\tvoid fileInArchiveNotOverwrittenByDefault(@TempDir File tempDir) throws Exception {\n\t\tFile conflict = new File(tempDir, \"test.txt\");\n\t\tassertThat(conflict.createNewFile()).as(\"Should have been able to create file\").isTrue();\n\t\tlong fileLength = conflict.length();\n\t\t// also contains test.txt\n\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", \"demo.zip\",\n\t\t\t\tarchive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run(\"--extract\", tempDir.getAbsolutePath())).isEqualTo(ExitStatus.ERROR);\n\t\tassertThat(conflict.length()).as(\"File should not have changed\").isEqualTo(fileLength);\n\t}\n\n\t@Test\n\tvoid parseProjectOptions() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"-g=org.demo\", \"-a=acme\", \"-v=1.2.3-SNAPSHOT\", \"-n=acme-sample\",\n\t\t\t\t\"--description=Acme sample project\", \"--package-name=demo.foo\", \"-t=ant-project\", \"--build=grunt\",\n\t\t\t\t\"--format=web\", \"-p=war\", \"-j=1.9\", \"-l=groovy\", \"-b=1.2.0.RELEASE\", \"-d=web,data-jpa\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getGroupId()).isEqualTo(\"org.demo\");\n\t\tassertThat(this.handler.lastRequest.getArtifactId()).isEqualTo(\"acme\");\n\t\tassertThat(this.handler.lastRequest.getVersion()).isEqualTo(\"1.2.3-SNAPSHOT\");\n\t\tassertThat(this.handler.lastRequest.getName()).isEqualTo(\"acme-sample\");\n\t\tassertThat(this.handler.lastRequest.getDescription()).isEqualTo(\"Acme sample project\");\n\t\tassertThat(this.handler.lastRequest.getPackageName()).isEqualTo(\"demo.foo\");\n\t\tassertThat(this.handler.lastRequest.getType()).isEqualTo(\"ant-project\");\n\t\tassertThat(this.handler.lastRequest.getBuild()).isEqualTo(\"grunt\");\n\t\tassertThat(this.handler.lastRequest.getFormat()).isEqualTo(\"web\");\n\t\tassertThat(this.handler.lastRequest.getPackaging()).isEqualTo(\"war\");\n\t\tassertThat(this.handler.lastRequest.getJavaVersion()).isEqualTo(\"1.9\");\n\t\tassertThat(this.handler.lastRequest.getLanguage()).isEqualTo(\"groovy\");\n\t\tassertThat(this.handler.lastRequest.getBootVersion()).isEqualTo(\"1.2.0.RELEASE\");\n\t\tList<String> dependencies = this.handler.lastRequest.getDependencies();\n\t\tassertThat(dependencies).hasSize(2);\n\t\tassertThat(dependencies).contains(\"web\");\n\t\tassertThat(dependencies).contains(\"data-jpa\");\n\t}\n\n\t@Test\n\tvoid parseProjectWithCamelCaseOptions() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"--groupId=org.demo\", \"--artifactId=acme\", \"--version=1.2.3-SNAPSHOT\", \"--name=acme-sample\",\n\t\t\t\t\"--description=Acme sample project\", \"--packageName=demo.foo\", \"--type=ant-project\", \"--build=grunt\",\n\t\t\t\t\"--format=web\", \"--packaging=war\", \"--javaVersion=1.9\", \"--language=groovy\",\n\t\t\t\t\"--bootVersion=1.2.0.RELEASE\", \"--dependencies=web,data-jpa\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getGroupId()).isEqualTo(\"org.demo\");\n\t\tassertThat(this.handler.lastRequest.getArtifactId()).isEqualTo(\"acme\");\n\t\tassertThat(this.handler.lastRequest.getVersion()).isEqualTo(\"1.2.3-SNAPSHOT\");\n\t\tassertThat(this.handler.lastRequest.getName()).isEqualTo(\"acme-sample\");\n\t\tassertThat(this.handler.lastRequest.getDescription()).isEqualTo(\"Acme sample project\");\n\t\tassertThat(this.handler.lastRequest.getPackageName()).isEqualTo(\"demo.foo\");\n\t\tassertThat(this.handler.lastRequest.getType()).isEqualTo(\"ant-project\");\n\t\tassertThat(this.handler.lastRequest.getBuild()).isEqualTo(\"grunt\");\n\t\tassertThat(this.handler.lastRequest.getFormat()).isEqualTo(\"web\");\n\t\tassertThat(this.handler.lastRequest.getPackaging()).isEqualTo(\"war\");\n\t\tassertThat(this.handler.lastRequest.getJavaVersion()).isEqualTo(\"1.9\");\n\t\tassertThat(this.handler.lastRequest.getLanguage()).isEqualTo(\"groovy\");\n\t\tassertThat(this.handler.lastRequest.getBootVersion()).isEqualTo(\"1.2.0.RELEASE\");\n\t\tList<String> dependencies = this.handler.lastRequest.getDependencies();\n\t\tassertThat(dependencies).hasSize(2);\n\t\tassertThat(dependencies).contains(\"web\");\n\t\tassertThat(dependencies).contains(\"data-jpa\");\n\t}\n\n\t@Test\n\tvoid parseProjectWithKebabCaseOptions() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"--group-id=org.demo\", \"--artifact-id=acme\", \"--version=1.2.3-SNAPSHOT\", \"--name=acme-sample\",\n\t\t\t\t\"--description=Acme sample project\", \"--package-name=demo.foo\", \"--type=ant-project\", \"--build=grunt\",\n\t\t\t\t\"--format=web\", \"--packaging=war\", \"--java-version=1.9\", \"--language=groovy\",\n\t\t\t\t\"--boot-version=1.2.0.RELEASE\", \"--dependencies=web,data-jpa\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getGroupId()).isEqualTo(\"org.demo\");\n\t\tassertThat(this.handler.lastRequest.getArtifactId()).isEqualTo(\"acme\");\n\t\tassertThat(this.handler.lastRequest.getVersion()).isEqualTo(\"1.2.3-SNAPSHOT\");\n\t\tassertThat(this.handler.lastRequest.getName()).isEqualTo(\"acme-sample\");\n\t\tassertThat(this.handler.lastRequest.getDescription()).isEqualTo(\"Acme sample project\");\n\t\tassertThat(this.handler.lastRequest.getPackageName()).isEqualTo(\"demo.foo\");\n\t\tassertThat(this.handler.lastRequest.getType()).isEqualTo(\"ant-project\");\n\t\tassertThat(this.handler.lastRequest.getBuild()).isEqualTo(\"grunt\");\n\t\tassertThat(this.handler.lastRequest.getFormat()).isEqualTo(\"web\");\n\t\tassertThat(this.handler.lastRequest.getPackaging()).isEqualTo(\"war\");\n\t\tassertThat(this.handler.lastRequest.getJavaVersion()).isEqualTo(\"1.9\");\n\t\tassertThat(this.handler.lastRequest.getLanguage()).isEqualTo(\"groovy\");\n\t\tassertThat(this.handler.lastRequest.getBootVersion()).isEqualTo(\"1.2.0.RELEASE\");\n\t\tList<String> dependencies = this.handler.lastRequest.getDependencies();\n\t\tassertThat(dependencies).hasSize(2);\n\t\tassertThat(dependencies).contains(\"web\");\n\t\tassertThat(dependencies).contains(\"data-jpa\");\n\t}\n\n\t@Test\n\tvoid overwriteFileInArchive(@TempDir File tempDir) throws Exception {\n\t\tFile conflict = new File(tempDir, \"test.txt\");\n\t\tassertThat(conflict.createNewFile()).as(\"Should have been able to create file\").isTrue();\n\t\tlong fileLength = conflict.length();\n\t\t// also contains test.txt\n\t\tbyte[] archive = createFakeZipArchive(\"test.txt\", \"Fake content\");\n\t\tMockHttpProjectGenerationRequest request = new MockHttpProjectGenerationRequest(\"application/zip\", \"demo.zip\",\n\t\t\t\tarchive);\n\t\tmockSuccessfulProjectGeneration(request);\n\t\tassertThat(this.command.run(\"--force\", \"--extract\", tempDir.getAbsolutePath())).isEqualTo(ExitStatus.OK);\n\t\tassertThat(fileLength).as(\"File should have changed\").isNotEqualTo(conflict.length());\n\t}\n\n\t@Test\n\tvoid parseTypeOnly() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"-t=ant-project\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getBuild()).isEqualTo(\"gradle\");\n\t\tassertThat(this.handler.lastRequest.getFormat()).isEqualTo(\"project\");\n\t\tassertThat(this.handler.lastRequest.isDetectType()).isFalse();\n\t\tassertThat(this.handler.lastRequest.getType()).isEqualTo(\"ant-project\");\n\t}\n\n\t@Test\n\tvoid parseBuildOnly() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"--build=ant\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getBuild()).isEqualTo(\"ant\");\n\t\tassertThat(this.handler.lastRequest.getFormat()).isEqualTo(\"project\");\n\t\tassertThat(this.handler.lastRequest.isDetectType()).isTrue();\n\t\tassertThat(this.handler.lastRequest.getType()).isNull();\n\t}\n\n\t@Test\n\tvoid parseFormatOnly() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"--format=web\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getBuild()).isEqualTo(\"gradle\");\n\t\tassertThat(this.handler.lastRequest.getFormat()).isEqualTo(\"web\");\n\t\tassertThat(this.handler.lastRequest.isDetectType()).isTrue();\n\t\tassertThat(this.handler.lastRequest.getType()).isNull();\n\t}\n\n\t@Test\n\tvoid parseLocation() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"foobar.zip\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getOutput()).isEqualTo(\"foobar.zip\");\n\t}\n\n\t@Test\n\tvoid parseLocationWithSlash() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tthis.command.run(\"foobar/\");\n\t\tassertThat(this.handler.lastRequest).isNotNull();\n\t\tassertThat(this.handler.lastRequest.getOutput()).isEqualTo(\"foobar\");\n\t\tassertThat(this.handler.lastRequest.isExtract()).isTrue();\n\t}\n\n\t@Test\n\tvoid parseMoreThanOneArg() throws Exception {\n\t\tthis.handler.disableProjectGeneration();\n\t\tassertThat(this.command.run(\"foobar\", \"barfoo\")).isEqualTo(ExitStatus.ERROR);\n\t}\n\n\t@Test\n\tvoid userAgent() throws Exception {\n\t\tthis.command.run(\"--list\", \"--target=https://fake-service\");\n\t\tthen(this.http).should()\n\t\t\t.executeOpen(any(HttpHost.class), assertArg((request) -> assertThat(\n\t\t\t\t\trequest.getHeaders(\"User-Agent\")[0].getValue().startsWith(\"SpringBootCli/\"))), isNull());\n\t}\n\n\tprivate byte[] createFakeZipArchive(String fileName, String content) throws IOException {\n\t\ttry (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {\n\t\t\ttry (ZipOutputStream zos = new ZipOutputStream(bos)) {\n\t\t\t\tZipEntry entry = new ZipEntry(fileName);\n\t\t\t\tzos.putNextEntry(entry);\n\t\t\t\tzos.write(content.getBytes());\n\t\t\t\tzos.closeEntry();\n\t\t\t\treturn bos.toByteArray();\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic class TestableInitCommandOptionHandler extends InitCommand.InitOptionHandler {\n\n\t\tprivate boolean disableProjectGeneration;\n\n\t\tprivate @Nullable ProjectGenerationRequest lastRequest;\n\n\t\tTestableInitCommandOptionHandler(InitializrService initializrService) {\n\t\t\tsuper(initializrService);\n\t\t}\n\n\t\tvoid disableProjectGeneration() {\n\t\t\tthis.disableProjectGeneration = true;\n\t\t}\n\n\t\t@Override\n\t\tprotected void generateProject(OptionSet options) throws IOException {\n\t\t\tthis.lastRequest = createProjectGenerationRequest(options);\n\t\t\tif (!this.disableProjectGeneration) {\n\t\t\t\tsuper.generateProject(options);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitializrServiceMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cli.json.JSONException;\nimport org.springframework.boot.cli.json.JSONObject;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InitializrServiceMetadata}.\n *\n * @author Stephane Nicoll\n */\nclass InitializrServiceMetadataTests {\n\n\t@Test\n\tvoid parseDefaults() throws Exception {\n\t\tInitializrServiceMetadata metadata = createInstance(\"2.0.0\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"bootVersion\", \"1.1.8.RELEASE\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"javaVersion\", \"1.7\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"groupId\", \"org.test\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"name\", \"demo\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"description\", \"Demo project for Spring Boot\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"packaging\", \"jar\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"language\", \"java\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"artifactId\", \"demo\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"packageName\", \"demo\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"type\", \"maven-project\");\n\t\tassertThat(metadata.getDefaults()).containsEntry(\"version\", \"0.0.1-SNAPSHOT\");\n\t\tassertThat(metadata.getDefaults()).as(\"Wrong number of defaults\").hasSize(11);\n\t}\n\n\t@Test\n\tvoid parseDependencies() throws Exception {\n\t\tInitializrServiceMetadata metadata = createInstance(\"2.0.0\");\n\t\tassertThat(metadata.getDependencies()).hasSize(5);\n\n\t\t// Security description\n\t\tDependency aop = metadata.getDependency(\"aop\");\n\t\tassertThat(aop).isNotNull();\n\t\tassertThat(aop.getName()).isEqualTo(\"AOP\");\n\t\tDependency security = metadata.getDependency(\"security\");\n\t\tassertThat(security).isNotNull();\n\t\tassertThat(security.getName()).isEqualTo(\"Security\");\n\t\tassertThat(security.getDescription()).isEqualTo(\"Security description\");\n\t\tDependency jdbc = metadata.getDependency(\"jdbc\");\n\t\tassertThat(jdbc).isNotNull();\n\t\tassertThat(jdbc.getName()).isEqualTo(\"JDBC\");\n\t\tDependency dataJpa = metadata.getDependency(\"data-jpa\");\n\t\tassertThat(dataJpa).isNotNull();\n\t\tassertThat(dataJpa.getName()).isEqualTo(\"JPA\");\n\t\tDependency dataMongodb = metadata.getDependency(\"data-mongodb\");\n\t\tassertThat(dataMongodb).isNotNull();\n\t\tassertThat(dataMongodb.getName()).isEqualTo(\"MongoDB\");\n\t}\n\n\t@Test\n\tvoid parseTypes() throws Exception {\n\t\tInitializrServiceMetadata metadata = createInstance(\"2.0.0\");\n\t\tProjectType projectType = metadata.getProjectTypes().get(\"maven-project\");\n\t\tassertThat(projectType).isNotNull();\n\t\tassertThat(projectType.getTags()).containsEntry(\"build\", \"maven\");\n\t\tassertThat(projectType.getTags()).containsEntry(\"format\", \"project\");\n\t}\n\n\tprivate static InitializrServiceMetadata createInstance(String version) throws JSONException {\n\t\ttry {\n\t\t\treturn new InitializrServiceMetadata(readJson(version));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to read json\", ex);\n\t\t}\n\t}\n\n\tprivate static JSONObject readJson(String version) throws IOException, JSONException {\n\t\tResource resource = new ClassPathResource(\"metadata/service-metadata-\" + version + \".json\");\n\t\ttry (InputStream stream = resource.getInputStream()) {\n\t\t\treturn new JSONObject(StreamUtils.copyToString(stream, StandardCharsets.UTF_8));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/InitializrServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport org.apache.hc.client5.http.classic.methods.HttpGet;\nimport org.apache.hc.core5.http.ClassicHttpResponse;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link InitializrService}\n *\n * @author Stephane Nicoll\n */\nclass InitializrServiceTests extends AbstractHttpClientMockTests {\n\n\tprivate final InitializrService invoker = new InitializrService(this.http);\n\n\t@Test\n\tvoid loadMetadata() throws Exception {\n\t\tmockSuccessfulMetadataGet(false);\n\t\tInitializrServiceMetadata metadata = this.invoker.loadMetadata(\"https://foo/bar\");\n\t\tassertThat(metadata).isNotNull();\n\t}\n\n\t@Test\n\tvoid generateSimpleProject() throws Exception {\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tMockHttpProjectGenerationRequest mockHttpRequest = new MockHttpProjectGenerationRequest(\"application/xml\",\n\t\t\t\t\"foo.zip\");\n\t\tProjectGenerationResponse entity = generateProject(request, mockHttpRequest);\n\t\tassertProjectEntity(entity, mockHttpRequest.contentType, mockHttpRequest.fileName);\n\t}\n\n\t@Test\n\tvoid generateProjectCustomTargetFilename() throws Exception {\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\trequest.setOutput(\"bar.zip\");\n\t\tMockHttpProjectGenerationRequest mockHttpRequest = new MockHttpProjectGenerationRequest(\"application/xml\",\n\t\t\t\tnull);\n\t\tProjectGenerationResponse entity = generateProject(request, mockHttpRequest);\n\t\tassertProjectEntity(entity, mockHttpRequest.contentType, null);\n\t}\n\n\t@Test\n\tvoid generateProjectNoDefaultFileName() throws Exception {\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tMockHttpProjectGenerationRequest mockHttpRequest = new MockHttpProjectGenerationRequest(\"application/xml\",\n\t\t\t\tnull);\n\t\tProjectGenerationResponse entity = generateProject(request, mockHttpRequest);\n\t\tassertProjectEntity(entity, mockHttpRequest.contentType, null);\n\t}\n\n\t@Test\n\tvoid generateProjectBadRequest() throws Exception {\n\t\tString jsonMessage = \"Unknown dependency foo:bar\";\n\t\tmockProjectGenerationError(400, jsonMessage);\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\trequest.getDependencies().add(\"foo:bar\");\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.invoker.generate(request))\n\t\t\t.withMessageContaining(jsonMessage);\n\t}\n\n\t@Test\n\tvoid generateProjectBadRequestNoExtraMessage() throws Exception {\n\t\tmockProjectGenerationError(400, null);\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.invoker.generate(request))\n\t\t\t.withMessageContaining(\"unexpected 400 error\");\n\t}\n\n\t@Test\n\tvoid generateProjectNoContent() throws Exception {\n\t\tmockSuccessfulMetadataGet(false);\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tmockStatus(response, 500);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), isA(HttpGet.class), isNull())).willReturn(response);\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.invoker.generate(request))\n\t\t\t.withMessageContaining(\"No content received from server\");\n\t}\n\n\t@Test\n\tvoid loadMetadataBadRequest() throws Exception {\n\t\tString jsonMessage = \"whatever error on the server\";\n\t\tmockMetadataGetError(500, jsonMessage);\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.invoker.generate(request))\n\t\t\t.withMessageContaining(jsonMessage);\n\t}\n\n\t@Test\n\tvoid loadMetadataInvalidJson() throws Exception {\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tmockHttpEntity(response, \"Foo-Bar-Not-JSON\".getBytes(), \"application/json\");\n\t\tmockStatus(response, 200);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), isA(HttpGet.class), isNull())).willReturn(response);\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.invoker.generate(request))\n\t\t\t.withMessageContaining(\"Invalid content received from server\");\n\t}\n\n\t@Test\n\tvoid loadMetadataNoContent() throws Exception {\n\t\tClassicHttpResponse response = mock(ClassicHttpResponse.class);\n\t\tmockStatus(response, 500);\n\t\tgiven(this.http.executeOpen(any(HttpHost.class), isA(HttpGet.class), isNull())).willReturn(response);\n\t\tProjectGenerationRequest request = new ProjectGenerationRequest();\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.invoker.generate(request))\n\t\t\t.withMessageContaining(\"No content received from server\");\n\t}\n\n\tprivate ProjectGenerationResponse generateProject(ProjectGenerationRequest request,\n\t\t\tMockHttpProjectGenerationRequest mockRequest) throws Exception {\n\t\tmockSuccessfulProjectGeneration(mockRequest);\n\t\tProjectGenerationResponse entity = this.invoker.generate(request);\n\t\tassertThat(entity.getContent()).as(\"wrong body content\").isEqualTo(mockRequest.content);\n\t\treturn entity;\n\t}\n\n\tprivate static void assertProjectEntity(ProjectGenerationResponse entity, @Nullable String mimeType,\n\t\t\t@Nullable String fileName) {\n\t\tif (mimeType == null) {\n\t\t\tassertThat(entity.getContentType()).isNull();\n\t\t}\n\t\telse {\n\t\t\tassertThat(entity.getContentType().getMimeType()).isEqualTo(mimeType);\n\t\t}\n\t\tassertThat(entity.getFileName()).isEqualTo(fileName);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/ProjectGenerationRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cli.json.JSONException;\nimport org.springframework.boot.cli.json.JSONObject;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ProjectGenerationRequest}.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ProjectGenerationRequestTests {\n\n\tpublic static final Map<String, String> EMPTY_TAGS = Collections.emptyMap();\n\n\tprivate final ProjectGenerationRequest request = new ProjectGenerationRequest();\n\n\t@Test\n\tvoid defaultSettings() {\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata())).isEqualTo(createDefaultUrl(\"?type=test-type\"));\n\t}\n\n\t@Test\n\tvoid customServer() throws URISyntaxException {\n\t\tString customServerUrl = \"https://foo:8080/initializr\";\n\t\tthis.request.setServiceUrl(customServerUrl);\n\t\tthis.request.getDependencies().add(\"security\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(new URI(customServerUrl + \"/starter.zip?dependencies=security&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid customBootVersion() {\n\t\tthis.request.setBootVersion(\"1.2.0.RELEASE\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?type=test-type&bootVersion=1.2.0.RELEASE\"));\n\t}\n\n\t@Test\n\tvoid singleDependency() {\n\t\tthis.request.getDependencies().add(\"web\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?dependencies=web&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid multipleDependencies() {\n\t\tthis.request.getDependencies().add(\"web\");\n\t\tthis.request.getDependencies().add(\"data-jpa\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?dependencies=web%2Cdata-jpa&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid customJavaVersion() {\n\t\tthis.request.setJavaVersion(\"1.8\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?type=test-type&javaVersion=1.8\"));\n\t}\n\n\t@Test\n\tvoid customPackageName() {\n\t\tthis.request.setPackageName(\"demo.foo\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?packageName=demo.foo&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid customType() throws URISyntaxException {\n\t\tProjectType projectType = new ProjectType(\"custom\", \"Custom Type\", \"/foo\", true, EMPTY_TAGS);\n\t\tInitializrServiceMetadata metadata = new InitializrServiceMetadata(projectType);\n\t\tthis.request.setType(\"custom\");\n\t\tthis.request.getDependencies().add(\"data-rest\");\n\t\tassertThat(this.request.generateUrl(metadata)).isEqualTo(\n\t\t\t\tnew URI(ProjectGenerationRequest.DEFAULT_SERVICE_URL + \"/foo?dependencies=data-rest&type=custom\"));\n\t}\n\n\t@Test\n\tvoid customPackaging() {\n\t\tthis.request.setPackaging(\"war\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?type=test-type&packaging=war\"));\n\t}\n\n\t@Test\n\tvoid customLanguage() {\n\t\tthis.request.setLanguage(\"groovy\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?type=test-type&language=groovy\"));\n\t}\n\n\t@Test\n\tvoid customProjectInfo() {\n\t\tthis.request.setGroupId(\"org.acme\");\n\t\tthis.request.setArtifactId(\"sample\");\n\t\tthis.request.setVersion(\"1.0.1-SNAPSHOT\");\n\t\tthis.request.setDescription(\"Spring Boot Test\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?groupId=org.acme&artifactId=sample&version=1.0.1-SNAPSHOT\"\n\t\t\t\t\t+ \"&description=Spring%20Boot%20Test&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid outputCustomizeArtifactId() {\n\t\tthis.request.setOutput(\"my-project\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?artifactId=my-project&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid outputArchiveCustomizeArtifactId() {\n\t\tthis.request.setOutput(\"my-project.zip\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?artifactId=my-project&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid outputArchiveWithDotsCustomizeArtifactId() {\n\t\tthis.request.setOutput(\"my.nice.project.zip\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?artifactId=my.nice.project&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid outputDoesNotOverrideCustomArtifactId() {\n\t\tthis.request.setOutput(\"my-project\");\n\t\tthis.request.setArtifactId(\"my-id\");\n\t\tassertThat(this.request.generateUrl(createDefaultMetadata()))\n\t\t\t.isEqualTo(createDefaultUrl(\"?artifactId=my-id&type=test-type\"));\n\t}\n\n\t@Test\n\tvoid buildNoMatch() throws Exception {\n\t\tInitializrServiceMetadata metadata = readMetadata();\n\t\tsetBuildAndFormat(\"does-not-exist\", null);\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.request.generateUrl(metadata))\n\t\t\t.withMessageContaining(\"does-not-exist\");\n\t}\n\n\t@Test\n\tvoid buildMultipleMatch() throws Exception {\n\t\tInitializrServiceMetadata metadata = readMetadata(\"types-conflict\");\n\t\tsetBuildAndFormat(\"gradle\", null);\n\t\tassertThatExceptionOfType(ReportableException.class).isThrownBy(() -> this.request.generateUrl(metadata))\n\t\t\t.withMessageContaining(\"gradle-project\")\n\t\t\t.withMessageContaining(\"gradle-project-2\");\n\t}\n\n\t@Test\n\tvoid buildOneMatch() throws Exception {\n\t\tInitializrServiceMetadata metadata = readMetadata();\n\t\tsetBuildAndFormat(\"gradle\", null);\n\t\tassertThat(this.request.generateUrl(metadata)).isEqualTo(createDefaultUrl(\"?type=gradle-project\"));\n\t}\n\n\t@Test\n\tvoid typeAndBuildAndFormat() throws Exception {\n\t\tInitializrServiceMetadata metadata = readMetadata();\n\t\tsetBuildAndFormat(\"gradle\", \"project\");\n\t\tthis.request.setType(\"maven-build\");\n\t\tassertThat(this.request.generateUrl(metadata)).isEqualTo(createUrl(\"/pom.xml?type=maven-build\"));\n\t}\n\n\t@Test\n\tvoid invalidType() {\n\t\tthis.request.setType(\"does-not-exist\");\n\t\tassertThatExceptionOfType(ReportableException.class)\n\t\t\t.isThrownBy(() -> this.request.generateUrl(createDefaultMetadata()));\n\t}\n\n\t@Test\n\tvoid noTypeAndNoDefault() {\n\t\tassertThatExceptionOfType(ReportableException.class)\n\t\t\t.isThrownBy(() -> this.request.generateUrl(readMetadata(\"types-conflict\")))\n\t\t\t.withMessageContaining(\"no default is defined\");\n\t}\n\n\tprivate static URI createUrl(String actionAndParam) {\n\t\ttry {\n\t\t\treturn new URI(ProjectGenerationRequest.DEFAULT_SERVICE_URL + actionAndParam);\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate static URI createDefaultUrl(String param) {\n\t\treturn createUrl(\"/starter.zip\" + param);\n\t}\n\n\tvoid setBuildAndFormat(@Nullable String build, @Nullable String format) {\n\t\tthis.request.setBuild((build != null) ? build : \"maven\");\n\t\tthis.request.setFormat((format != null) ? format : \"project\");\n\t\tthis.request.setDetectType(true);\n\t}\n\n\tprivate static InitializrServiceMetadata createDefaultMetadata() {\n\t\tProjectType projectType = new ProjectType(\"test-type\", \"The test type\", \"/starter.zip\", true, EMPTY_TAGS);\n\t\treturn new InitializrServiceMetadata(projectType);\n\t}\n\n\tprivate static InitializrServiceMetadata readMetadata() throws JSONException {\n\t\treturn readMetadata(\"2.0.0\");\n\t}\n\n\tprivate static InitializrServiceMetadata readMetadata(String version) throws JSONException {\n\t\ttry {\n\t\t\tResource resource = new ClassPathResource(\"metadata/service-metadata-\" + version + \".json\");\n\t\t\tString content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);\n\t\t\tJSONObject json = new JSONObject(content);\n\t\t\treturn new InitializrServiceMetadata(json);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to read metadata\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/init/ServiceCapabilitiesReportGeneratorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.init;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServiceCapabilitiesReportGenerator}\n *\n * @author Stephane Nicoll\n */\nclass ServiceCapabilitiesReportGeneratorTests extends AbstractHttpClientMockTests {\n\n\tprivate final ServiceCapabilitiesReportGenerator command = new ServiceCapabilitiesReportGenerator(\n\t\t\tnew InitializrService(this.http));\n\n\t@Test\n\tvoid listMetadataFromServer() throws IOException {\n\t\tmockSuccessfulMetadataTextGet();\n\t\tString expected = new String(readClasspathResource(\"metadata/service-metadata-2.1.0.txt\"));\n\t\tString content = this.command.generate(\"http://localhost\");\n\t\tassertThat(content).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid listMetadata() throws IOException {\n\t\tmockSuccessfulMetadataGet(true);\n\t\tdoTestGenerateCapabilitiesFromJson();\n\t}\n\n\t@Test\n\tvoid listMetadataV2() throws IOException {\n\t\tmockSuccessfulMetadataGetV2(true);\n\t\tdoTestGenerateCapabilitiesFromJson();\n\t}\n\n\tprivate void doTestGenerateCapabilitiesFromJson() throws IOException {\n\t\tString content = this.command.generate(\"http://localhost\");\n\t\tassertThat(content).contains(\"aop - AOP\");\n\t\tassertThat(content).contains(\"security - Security: Security description\");\n\t\tassertThat(content).contains(\"type: maven-project\");\n\t\tassertThat(content).contains(\"packaging: jar\");\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/command/shell/EscapeAwareWhiteSpaceArgumentDelimiterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.command.shell;\n\nimport jline.console.completer.ArgumentCompleter.ArgumentList;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EscapeAwareWhiteSpaceArgumentDelimiter}.\n *\n * @author Phillip Webb\n */\nclass EscapeAwareWhiteSpaceArgumentDelimiterTests {\n\n\tprivate final EscapeAwareWhiteSpaceArgumentDelimiter delimiter = new EscapeAwareWhiteSpaceArgumentDelimiter();\n\n\t@Test\n\tvoid simple() {\n\t\tString s = \"one two\";\n\t\tassertThat(this.delimiter.delimit(s, 0).getArguments()).containsExactly(\"one\", \"two\");\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\"one\", \"two\");\n\t\tassertThat(this.delimiter.isDelimiter(s, 2)).isFalse();\n\t\tassertThat(this.delimiter.isDelimiter(s, 3)).isTrue();\n\t\tassertThat(this.delimiter.isDelimiter(s, 4)).isFalse();\n\t}\n\n\t@Test\n\tvoid escaped() {\n\t\tString s = \"o\\\\ ne two\";\n\t\tassertThat(this.delimiter.delimit(s, 0).getArguments()).containsExactly(\"o\\\\ ne\", \"two\");\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\"o ne\", \"two\");\n\t\tassertThat(this.delimiter.isDelimiter(s, 2)).isFalse();\n\t\tassertThat(this.delimiter.isDelimiter(s, 3)).isFalse();\n\t\tassertThat(this.delimiter.isDelimiter(s, 4)).isFalse();\n\t\tassertThat(this.delimiter.isDelimiter(s, 5)).isTrue();\n\t}\n\n\t@Test\n\tvoid quoted() {\n\t\tString s = \"'o ne' 't w o'\";\n\t\tassertThat(this.delimiter.delimit(s, 0).getArguments()).containsExactly(\"'o ne'\", \"'t w o'\");\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\"o ne\", \"t w o\");\n\t}\n\n\t@Test\n\tvoid doubleQuoted() {\n\t\tString s = \"\\\"o ne\\\" \\\"t w o\\\"\";\n\t\tassertThat(this.delimiter.delimit(s, 0).getArguments()).containsExactly(\"\\\"o ne\\\"\", \"\\\"t w o\\\"\");\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\"o ne\", \"t w o\");\n\t}\n\n\t@Test\n\tvoid nestedQuotes() {\n\t\tString s = \"\\\"o 'n''e\\\" 't \\\"w o'\";\n\t\tassertThat(this.delimiter.delimit(s, 0).getArguments()).containsExactly(\"\\\"o 'n''e\\\"\", \"'t \\\"w o'\");\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\"o 'n''e\", \"t \\\"w o\");\n\t}\n\n\t@Test\n\tvoid escapedQuotes() {\n\t\tString s = \"\\\\'a b\";\n\t\tArgumentList argumentList = this.delimiter.delimit(s, 0);\n\t\tassertThat(argumentList.getArguments()).isEqualTo(new String[] { \"\\\\'a\", \"b\" });\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\"'a\", \"b\");\n\t}\n\n\t@Test\n\tvoid escapes() {\n\t\tString s = \"\\\\ \\\\\\\\.\\\\\\\\\\\\t\";\n\t\tassertThat(this.delimiter.parseArguments(s)).containsExactly(\" \\\\.\\\\\\t\");\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/java/org/springframework/boot/cli/util/MockLog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cli.util;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Mock log for testing message output.\n *\n * @author Phillip Webb\n */\npublic interface MockLog extends LogListener {\n\n\tstatic MockLog attach() {\n\t\tMockLog log = mock(MockLog.class);\n\t\tLog.setListener(log);\n\t\treturn log;\n\t}\n\n\tstatic void clear() {\n\t\tLog.setListener(null);\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/plugins/custom/META-INF/services/org.springframework.boot.cli.CommandFactory",
    "content": "cli.command.CustomCommandFactory\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/plugins/custom/custom/0.0.1/custom-0.0.1.pom",
    "content": ""
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/.m2/settings.xml",
    "content": "<settings xmlns=\"http://maven.apache.org/SETTINGS/1.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/SETTINGS/1.0.0\n\t\thttps://maven.apache.org/xsd/settings-1.0.0.xsd\">\n\t<localRepository>build/local-m2-repository</localRepository>\n\t<mirrors>\n\t\t<mirror>\n\t\t\t<id>central-mirror</id>\n\t\t\t<url>https://central-mirror.example.com/maven2</url>\n\t\t\t<mirrorOf>central</mirrorOf>\n\t\t</mirror>\n\t</mirrors>\n\t<servers>\n\t\t<server>\n\t\t\t<id>central-mirror</id>\n\t\t\t<username>user</username>\n\t\t\t<password>password</password>\n\t\t</server>\n\t</servers>\n\t<proxies>\n\t\t<proxy>\n\t\t\t<active>true</active>\n\t\t\t<protocol>http</protocol>\n\t\t\t<host>proxy.example.com</host>\n\t\t\t<port>3128</port>\n\t\t\t<username>user</username>\n\t\t\t<password>password</password>\n\t\t</proxy>\n\t</proxies>\n</settings>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/classloader-test-app.groovy",
    "content": "import org.springframework.util.*\n\n@Component\npublic class Test implements CommandLineRunner {\n\n\tpublic void run(String... args) throws Exception {\n\t\tprintln \"HasClasses-\" + ClassUtils.isPresent(\"missing\", null) + \"-\" +\n\t\t\tClassUtils.isPresent(\"org.springframework.boot.SpringApplication\", null) + \"-\" +\n\t\t\tClassUtils.isPresent(args[0], null)\n\t}\n\n}\n\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/commands/closure.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ncommand(\"foo\") { args ->\n\tprintln \"Hello Foo\"\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/commands/command.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test.command\n\nclass TestCommand implements Command {\n\n\tString name = \"foo\"\n\n\tString description = \"My script command\"\n\n\tString help = \"No options\"\n\n\tString usageHelp = \"Not very useful\"\n\t\n\tCollection<String> optionsHelp = [\"No options\"]\n\t\n\tboolean optionCommand = false\n\n\tvoid run(String... args) {\n\t\tprintln \"Hello ${args[0]}\"\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/commands/handler.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test.command\n\n@Grab(\"org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r\")\nimport org.eclipse.jgit.api.Git\n\n\nclass TestCommand extends OptionHandler {\n\t\n\tString name = \"foo\"\n\n\tvoid options() {\n\t\toption \"foo\", \"Foo set\"\n\t}\n\n\tvoid run(OptionSet options) {\n\t\t// Demonstrate use of Grape.grab to load dependencies before running\n\t\tprintln \"Clean: \" + Git.open(\"..\" as File).status().call().isClean()\n\t\tprintln \"Hello ${options.nonOptionArguments()}: ${options.has('foo')}\"\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/commands/options.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n def foo() {\n\t \"Foo\"\n }\n\ncommand(\"foo\") {\n\n\toptions {\n\t\toption \"foo\", \"A foo of type String\"\n\t\toption \"bar\", \"Bar has a value\" withOptionalArg() ofType Integer\n\t}\n\n\trun { options ->\n\t\tprintln \"Hello ${foo()}: bar=${options.valueOf('bar')}\"\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/dependency-customizer-tests/resource1.txt",
    "content": ""
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/dependency-customizer-tests/resource2.txt",
    "content": ""
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/dir-sample/code/app.groovy",
    "content": "package org.test\n\n@Component\nclass Example implements CommandLineRunner {\n\n\t@Autowired\n\tprivate MyService myService\n\n\tvoid run(String... args) {\n\t\tprintln \"Hello ${this.myService.sayWorld()} From ${getClass().getClassLoader().getResource('samples/app.groovy')}\" \n\t}\n}\n\n\n@Service\nclass MyService {\n\n\tString sayWorld() {\n\t\treturn \"World!\"\n\t}\n}\n\n\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/foo.pom",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project\n\t\txmlns=\"http://maven.apache.org/POM/4.0.0\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"\n\t\t\t\thttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>foo</groupId>\n\t<artifactId>foo</artifactId>\n\t<packaging>jar</packaging>\n\t<version>1.0</version>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/grab-samples/customDependencyManagement.groovy",
    "content": "@DependencyManagementBom('test:child:1.0.0')\n@Grab('ejb-api')\nclass CustomDependencyManagement {\n\n}"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/grab-samples/duplicateDependencyManagementBom.groovy",
    "content": "@DependencyManagementBom(\"foo:bar:1.0\")\n@DependencyManagementBom(\"alpha:bravo:2.0\")\nclass DuplicateDependencyManagement {\n\n}"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/grab-samples/grab.groovy",
    "content": "@Grab('jackson-core')\nclass GrabTest {\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/grab-samples/repository/test/child/1.0.0/child-1.0.0.pom",
    "content": "<project>\n\t<parent>\n\t\t<groupId>test</groupId>\n\t\t<artifactId>parent</artifactId>\n\t\t<version>1.0.0</version>\n\t</parent>\n\n\t<artifactId>child</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>pom</packaging>\n\n\t<modelVersion>4.0.0</modelVersion>\n</project>"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/grab-samples/repository/test/parent/1.0.0/parent-1.0.0.pom",
    "content": "<project>\n\t<groupId>test</groupId>\n\t<artifactId>parent</artifactId>\n\t<version>1.0.0</version>\n\t<packaging>pom</packaging>\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>javax.ejb</groupId>\n\t\t\t\t<artifactId>ejb-api</artifactId>\n\t\t\t\t<version>3.0</version>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n</project>"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/grab.groovy",
    "content": "@GrabResolver(name=\"test\", root=\"file:./src/test/plugins\")\n@Grab(\"custom:custom:0.0.1\")\n@Controller\nclass Foo {}\n\nprintln \"Hello Grab\""
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/init.groovy",
    "content": "println \"Hello Init\""
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/maven-settings/active-profile-repositories/.m2/settings.xml",
    "content": "<settings>\n\n\t<mirrors>\n\t\t<mirror>\n\t\t\t<id>my-mirror</id>\n\t\t\t<url>https://maven.example.com/mirror</url>\n\t\t\t<mirrorOf>my-server</mirrorOf>\n\t\t</mirror>\n\t</mirrors>\n\n\t<servers>\n\t\t<server>\n\t\t\t<id>my-server</id>\n\t\t\t<username>tester</username>\n\t\t\t<password>secret</password>\n\t\t</server>\n\t</servers>\n\n\t<proxies>\n\t\t<proxy>\n\t\t\t<id>my-proxy</id>\n\t\t\t<active>true</active>\n\t\t\t<protocol>http</protocol>\n\t\t\t<host>proxy.example.com</host>\n\t\t\t<port>8080</port>\n\t\t\t<username>proxyuser</username>\n\t\t\t<password>somepassword</password>\n\t\t</proxy>\n\t</proxies>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>active-by-default</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>active-by-default</id>\n\t\t\t\t\t<url>maven.example.com/activeByDefault</url>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>active-by-property</id>\n\t\t\t<activation>\n      \t\t\t<property>\n        \t\t\t<name>foo</name>\n        \t\t\t<value>bar</value>\n      \t\t\t</property>\n\t\t\t</activation>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>active-by-property</id>\n\t\t\t\t\t<url>maven.example.com/activeByProperty</url>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>interpolation-profile</id>\n\t\t\t<activation>\n      \t\t\t<property>\n        \t\t\t<name>interpolate</name>\n        \t\t\t<value>true</value>\n      \t\t\t</property>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<repo.base>maven.example.com</repo.base>\n\t\t\t\t<repo.content>${repo.base}/content</repo.content>\n\t\t\t</properties>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>interpolate-releases</id>\n\t\t\t\t\t<url>${repo.content}/releases</url>\n\t\t\t\t\t<releases>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t\t<updatePolicy>never</updatePolicy>\n\t\t\t\t\t</releases>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>interpolate-snapshots</id>\n\t\t\t\t\t<url>${repo.content}/snapshots</url>\n\t\t\t\t\t<releases>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</releases>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t</profile>\n\t</profiles>\n\n</settings>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/maven-settings/basic/.m2/settings.xml",
    "content": "<settings>\n\n\t<mirrors>\n\t\t<mirror>\n\t\t\t<id>my-mirror</id>\n\t\t\t<url>https://maven.example.com/mirror</url>\n\t\t\t<mirrorOf>my-server</mirrorOf>\n\t\t</mirror>\n\t</mirrors>\n\n\t<servers>\n\t\t<server>\n\t\t\t<id>my-server</id>\n\t\t\t<username>tester</username>\n\t\t\t<password>secret</password>\n\t\t</server>\n\t</servers>\n\n\t<proxies>\n\t\t<proxy>\n\t\t\t<id>my-proxy</id>\n\t\t\t<active>true</active>\n\t\t\t<protocol>http</protocol>\n\t\t\t<host>proxy.example.com</host>\n\t\t\t<port>8080</port>\n\t\t\t<username>proxyuser</username>\n\t\t\t<password>somepassword</password>\n\t\t</proxy>\n\t</proxies>\n\n\t<profiles>\n\t\t<profile>\n    \t\t<id>test-profile</id>\n    \t\t<activation>\n\t        \t<file>\n\t            \t<exists>${user.home}/.m2/some_file</exists>\n\t        \t</file>\n    \t\t</activation>\n\t    \t<repositories>\n\t        \t<repository>\n\t            \t<id>example-repository</id>\n\t            \t<url>https://repo.example.com</url>\n\t        \t</repository>\n\t    \t</repositories>\n\t\t</profile>\n\t</profiles>\n\n</settings>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings-security.xml",
    "content": "<settingsSecurity>\n\t<master>{oAyWuFO63U8HHgiplpqtgXih0/pwcRA0d+uA+Z7TBEk=}</master>\n</settingsSecurity>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/maven-settings/encrypted/.m2/settings.xml",
    "content": "<settings>\n\n\t<mirrors>\n\t\t<mirror>\n\t\t\t<id>my-mirror</id>\n\t\t\t<url>https://maven.example.com/mirror</url>\n\t\t\t<mirrorOf>my-server</mirrorOf>\n\t\t</mirror>\n\t</mirrors>\n\n\t<servers>\n\t\t<server>\n\t\t\t<id>my-server</id>\n\t\t\t<username>tester</username>\n\t\t\t<password>{Ur5BpeQGlYUHhXsHahO/HbMBcPSFSUtN5gbWuFFPYGw=}</password>\n\t\t</server>\n\t</servers>\n\n\t<proxies>\n\t\t<proxy>\n\t\t\t<id>my-proxy</id>\n\t\t\t<active>true</active>\n\t\t\t<protocol>http</protocol>\n\t\t\t<host>proxy.example.com</host>\n\t\t\t<port>8080</port>\n\t\t\t<username>proxyuser</username>\n\t\t\t<password>{3iRQQyaIUgQHwH8uzTvr9/52pZAjLOTWz/SlWDB7CM4=}</password>\n\t\t</proxy>\n\t</proxies>\n\n</settings>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/maven-settings/property-interpolation/.m2/settings.xml",
    "content": "<settings xmlns=\"http://maven.apache.org/SETTINGS/1.0.0\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/SETTINGS/1.0.0\n\t\thttps://maven.apache.org/xsd/settings-1.0.0.xsd\">\n\n\t<localRepository>${foo}/repository</localRepository>\n\n</settings>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/metadata/service-metadata-2.0.0.json",
    "content": "{\n\t\"_links\": {\n\t\t\"maven-build\": {\n\t\t\t\"href\": \"http://localhost:8080/pom.xml?{dependencies,type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"maven-project\": {\n\t\t\t\"href\": \"http://localhost:8080/starter.zip{?dependencies,type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"gradle-build\": {\n\t\t\t\"href\": \"http://localhost:8080/build.gradle{?dependencies,type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"gradle-project\": {\n\t\t\t\"href\": \"http://localhost:8080/starter.zip{?dependencies,type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t}\n\t},\n\t\"dependencies\": {\n\t\t\"type\": \"hierarchical-multi-select\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"name\": \"Core\",\n\t\t\t\t\"values\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"Security\",\n\t\t\t\t\t\t\"id\": \"security\",\n\t\t\t\t\t\t\"description\": \"Security description\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"AOP\",\n\t\t\t\t\t\t\"id\": \"aop\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"Data\",\n\t\t\t\t\"values\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"JDBC\",\n\t\t\t\t\t\t\"id\": \"jdbc\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"JPA\",\n\t\t\t\t\t\t\"id\": \"data-jpa\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"MongoDB\",\n\t\t\t\t\t\t\"id\": \"data-mongodb\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t},\n\t\"type\": {\n\t\t\"type\": \"action\",\n\t\t\"default\": \"maven-project\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"maven-build\",\n\t\t\t\t\"name\": \"Maven POM\",\n\t\t\t\t\"action\": \"/pom.xml\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"build\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"maven-project\",\n\t\t\t\t\"name\": \"Maven Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-build\",\n\t\t\t\t\"name\": \"Gradle Config\",\n\t\t\t\t\"action\": \"/build.gradle\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"build\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-project\",\n\t\t\t\t\"name\": \"Gradle Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t},\n\t\"packaging\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"jar\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"jar\",\n\t\t\t\t\"name\": \"Jar\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"war\",\n\t\t\t\t\"name\": \"War\"\n\t\t\t}\n\t\t]\n\t},\n\t\"javaVersion\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"1.7\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"1.6\",\n\t\t\t\t\"name\": \"1.6\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.7\",\n\t\t\t\t\"name\": \"1.7\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.8\",\n\t\t\t\t\"name\": \"1.8\"\n\t\t\t}\n\t\t]\n\t},\n\t\"language\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"java\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"groovy\",\n\t\t\t\t\"name\": \"Groovy\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"java\",\n\t\t\t\t\"name\": \"Java\"\n\t\t\t}\n\t\t]\n\t},\n\t\"bootVersion\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"1.1.8.RELEASE\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"1.2.0.BUILD-SNAPSHOT\",\n\t\t\t\t\"name\": \"1.2.0 (SNAPSHOT)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.1.8.RELEASE\",\n\t\t\t\t\"name\": \"1.1.8\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.1.8.BUILD-SNAPSHOT\",\n\t\t\t\t\"name\": \"1.1.8 (SNAPSHOT)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.0.2.RELEASE\",\n\t\t\t\t\"name\": \"1.0.2\"\n\t\t\t}\n\t\t]\n\t},\n\t\"groupId\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"org.test\"\n\t},\n\t\"artifactId\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t},\n\t\"version\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"0.0.1-SNAPSHOT\"\n\t},\n\t\"name\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t},\n\t\"description\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"Demo project for Spring Boot\"\n\t},\n\t\"packageName\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t}\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/metadata/service-metadata-2.1.0.json",
    "content": "{\n\t\"_links\": {\n\t\t\"maven-build\": {\n\t\t\t\"href\": \"http://localhost:8080/pom.xml?type=maven-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"maven-project\": {\n\t\t\t\"href\": \"http://localhost:8080/starter.zip?type=maven-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"gradle-build\": {\n\t\t\t\"href\": \"http://localhost:8080/build.gradle?type=gradle-build{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"gradle-project\": {\n\t\t\t\"href\": \"http://localhost:8080/starter.zip?type=gradle-project{&dependencies,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t}\n\t},\n\t\"dependencies\": {\n\t\t\"type\": \"hierarchical-multi-select\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"name\": \"Core\",\n\t\t\t\t\"values\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"Security\",\n\t\t\t\t\t\t\"id\": \"security\",\n\t\t\t\t\t\t\"description\": \"Security description\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"AOP\",\n\t\t\t\t\t\t\"id\": \"aop\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"Data\",\n\t\t\t\t\"values\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"JDBC\",\n\t\t\t\t\t\t\"id\": \"jdbc\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"JPA\",\n\t\t\t\t\t\t\"id\": \"data-jpa\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"MongoDB\",\n\t\t\t\t\t\t\"id\": \"data-mongodb\",\n\t\t\t\t\t    \"versionRange\": \"1.1.7.RELEASE\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t},\n\t\"type\": {\n\t\t\"type\": \"action\",\n\t\t\"default\": \"maven-project\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"maven-build\",\n\t\t\t\t\"name\": \"Maven POM\",\n\t\t\t\t\"action\": \"/pom.xml\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"build\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"maven-project\",\n\t\t\t\t\"name\": \"Maven Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-build\",\n\t\t\t\t\"name\": \"Gradle Config\",\n\t\t\t\t\"action\": \"/build.gradle\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"build\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-project\",\n\t\t\t\t\"name\": \"Gradle Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t},\n\t\"packaging\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"jar\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"jar\",\n\t\t\t\t\"name\": \"Jar\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"war\",\n\t\t\t\t\"name\": \"War\"\n\t\t\t}\n\t\t]\n\t},\n\t\"javaVersion\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"1.7\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"1.6\",\n\t\t\t\t\"name\": \"1.6\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.7\",\n\t\t\t\t\"name\": \"1.7\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.8\",\n\t\t\t\t\"name\": \"1.8\"\n\t\t\t}\n\t\t]\n\t},\n\t\"language\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"java\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"groovy\",\n\t\t\t\t\"name\": \"Groovy\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"java\",\n\t\t\t\t\"name\": \"Java\"\n\t\t\t}\n\t\t]\n\t},\n\t\"bootVersion\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"1.1.8.RELEASE\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"1.2.0.BUILD-SNAPSHOT\",\n\t\t\t\t\"name\": \"1.2.0 (SNAPSHOT)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.1.8.RELEASE\",\n\t\t\t\t\"name\": \"1.1.8\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.1.8.BUILD-SNAPSHOT\",\n\t\t\t\t\"name\": \"1.1.8 (SNAPSHOT)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.0.2.RELEASE\",\n\t\t\t\t\"name\": \"1.0.2\"\n\t\t\t}\n\t\t]\n\t},\n\t\"groupId\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"org.test\"\n\t},\n\t\"artifactId\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t},\n\t\"version\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"0.0.1-SNAPSHOT\"\n\t},\n\t\"name\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t},\n\t\"description\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"Demo project for Spring Boot\"\n\t},\n\t\"packageName\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t}\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/metadata/service-metadata-2.1.0.txt",
    "content": ""
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/metadata/service-metadata-types-conflict.json",
    "content": "{\n\t\"_links\": {\n\t\t\"maven-build\": {\n\t\t\t\"href\": \"http://localhost:8080/pom.xml?style={dependencies}{&type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"maven-project\": {\n\t\t\t\"href\": \"http://localhost:8080/starter.zip?style={dependencies}{&type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"gradle-build\": {\n\t\t\t\"href\": \"http://localhost:8080/build.gradle?style={dependencies}{&type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t},\n\t\t\"gradle-project\": {\n\t\t\t\"href\": \"http://localhost:8080/starter.zip?style={dependencies}{&type,packaging,javaVersion,language,bootVersion,groupId,artifactId,version,name,description,packageName}\",\n\t\t\t\"templated\": true\n\t\t}\n\t},\n\t\"dependencies\": {\n\t\t\"type\": \"hierarchical-multi-select\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"name\": \"Core\",\n\t\t\t\t\"values\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"Security\",\n\t\t\t\t\t\t\"id\": \"security\",\n\t\t\t\t\t\t\"description\": \"Security description\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"AOP\",\n\t\t\t\t\t\t\"id\": \"aop\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"name\": \"Data\",\n\t\t\t\t\"values\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"JDBC\",\n\t\t\t\t\t\t\"id\": \"jdbc\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"JPA\",\n\t\t\t\t\t\t\"id\": \"data-jpa\"\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\t\"name\": \"MongoDB\",\n\t\t\t\t\t\t\"id\": \"data-mongodb\"\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t},\n\t\"type\": {\n\t\t\"type\": \"action\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"maven-build\",\n\t\t\t\t\"name\": \"Maven POM\",\n\t\t\t\t\"action\": \"/pom.xml\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"build\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"maven-project\",\n\t\t\t\t\"name\": \"Maven Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"maven-project-2\",\n\t\t\t\t\"name\": \"Another Maven Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"maven\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-build\",\n\t\t\t\t\"name\": \"Gradle Config\",\n\t\t\t\t\"action\": \"/build.gradle\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"build\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-project\",\n\t\t\t\t\"name\": \"Gradle Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"gradle-project-2\",\n\t\t\t\t\"name\": \"Another Gradle Project\",\n\t\t\t\t\"action\": \"/starter.zip\",\n\t\t\t\t\"tags\": {\n\t\t\t\t\t\"build\": \"gradle\",\n\t\t\t\t\t\"format\": \"project\"\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t},\n\t\"packaging\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"jar\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"jar\",\n\t\t\t\t\"name\": \"Jar\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"war\",\n\t\t\t\t\"name\": \"War\"\n\t\t\t}\n\t\t]\n\t},\n\t\"javaVersion\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"1.7\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"1.6\",\n\t\t\t\t\"name\": \"1.6\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.7\",\n\t\t\t\t\"name\": \"1.7\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.8\",\n\t\t\t\t\"name\": \"1.8\"\n\t\t\t}\n\t\t]\n\t},\n\t\"language\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"java\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"groovy\",\n\t\t\t\t\"name\": \"Groovy\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"java\",\n\t\t\t\t\"name\": \"Java\"\n\t\t\t}\n\t\t]\n\t},\n\t\"bootVersion\": {\n\t\t\"type\": \"single-select\",\n\t\t\"default\": \"1.1.8.RELEASE\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"id\": \"1.2.0.BUILD-SNAPSHOT\",\n\t\t\t\t\"name\": \"1.2.0 (SNAPSHOT)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.1.8.RELEASE\",\n\t\t\t\t\"name\": \"1.1.8\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.1.8.BUILD-SNAPSHOT\",\n\t\t\t\t\"name\": \"1.1.8 (SNAPSHOT)\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"id\": \"1.0.2.RELEASE\",\n\t\t\t\t\"name\": \"1.0.2\"\n\t\t\t}\n\t\t]\n\t},\n\t\"groupId\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"org.test\"\n\t},\n\t\"artifactId\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t},\n\t\"version\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"0.0.1-SNAPSHOT\"\n\t},\n\t\"name\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t},\n\t\"description\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"Demo project for Spring Boot\"\n\t},\n\t\"packageName\": {\n\t\t\"type\": \"text\",\n\t\t\"default\": \"demo\"\n\t}\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/repro-samples/data-jpa.groovy",
    "content": "@Grab('spring-boot-starter-data-jpa')\n@Grab('h2')\nclass Sample implements CommandLineRunner {\n\n\t// No Data JPA-based logic. We just want to check that the dependencies are\n\t// resolved correctly and that the app runs\n\n\t@Override\n\tvoid run(String... args) {\n\t\tprintln \"Hello World\"\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/repro-samples/grab-ant-builder.groovy",
    "content": "@Grab(\"org.apache.groovy:groovy-ant:4.0.1\")\nimport groovy.ant.AntBuilder\n\n@RestController\nclass MainController {\n\n\t@RequestMapping(\"/\")\n\tdef home() {\n\t\tnew AntBuilder().echo(message:\"Hello world\")\n\t\t[message: \"Hello World\"]\n\t}\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/repro-samples/secure.groovy",
    "content": "package org.test\n\n// No security features added just a test that the dependencies are resolved\n@Grab(\"spring-boot-starter-security\")\n\n@Controller\nclass Sample implements CommandLineRunner {\n\n\t@Override\n\tvoid run(String... args) {\n\t\tprintln \"Hello World\"\n\t}\n}\n\n\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/one/alpha/nested/excluded",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/one/alpha/nested/fileA",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/one/bravo/fileC",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/one/bravo/nested/fileB",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/one/fileD",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/three",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/two/.file",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/two/bravo/fileE",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/resource-matcher/two/fileF",
    "content": "\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/run-command/quiet.groovy",
    "content": "package org.test\n\n@Component\nclass Example implements CommandLineRunner {\n\n\tvoid run(String... args) {\n\t\tprint \"Ssshh\"\n\t}\n\n}"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/schema-all.sql",
    "content": "CREATE TABLE FOO (\n  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n  name VARCHAR(30)\n);\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/scripts/closure.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ndef foo() {\n\t\"Foo\"\n}\n \ncommand(\"foo\") { options ->\n\tdef foo = foo()\n\tprintln \"Hello ${foo} ${options.nonOptionArguments()}: ${options.has('foo')} ${options.valueOf('bar')}\"\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/scripts/command.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test.command\n\nimport java.util.Collection\n\nclass TestCommand implements Command {\n\n\tString name = \"foo\"\n\n\tString description = \"My script command\"\n\n\tString help = \"No options\"\n\n\tString usageHelp = \"Not very useful\"\n\t\n\tCollection<String> optionsHelp = [\"No options\"]\n\t\n\tboolean optionCommand = false\n\n\tvoid run(String... args) {\n\t\tprintln \"Hello ${args[0]}\"\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/scripts/commands.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ncommand(\"foo\") { args ->\n\n\tprintln \"Hello Command\"\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/scripts/handler.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.test.command\n\n@Grab(\"org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r\")\nimport org.eclipse.jgit.api.Git\n\n\nclass TestCommand extends OptionHandler {\n\t\n\tString name = \"foo\"\n\n\tvoid options() {\n\t\toption \"foo\", \"Foo set\"\n\t}\n\n\tvoid run(OptionSet options) {\n\t\t// Demonstrate use of Grape.grab to load dependencies before running\n\t\tprintln \"Clean: \" + Git.open(\"..\" as File).status().call().isClean()\n\t\tprintln \"Hello ${options.nonOptionArguments()}: ${options.has('foo')}\"\n\t}\n\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/scripts/options.groovy",
    "content": "/*\n * Copyright 2012-2013 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ncommand(\"foo\") {\n\toptions {\n\t\toption \"foo\", \"Some foo description\" withOptionalArg()\n\t\toption \"bar\", \"Some bar\" withOptionalArg()\n\t}\n\trun { options -> println \"Hello ${options.nonOptionArguments()}: ${options.has('foo')} ${options.valueOf('bar')}\" }\n}\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/templates/home.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"https://www.thymeleaf.org\">\n<head>\n<title th:text=\"${title}\">Title</title>\n<link rel=\"stylesheet\" th:href=\"@{/resources/css/bootstrap.min.css}\"\n\thref=\"../../resources/css/bootstrap.min.css\" />\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"navbar\">\n\t\t\t<div class=\"navbar-inner\">\n\t\t\t\t<a class=\"brand\" href=\"https://www.thymeleaf.org\"> Thymeleaf -\n\t\t\t\t\tPlain </a>\n\t\t\t\t<ul class=\"nav\">\n\t\t\t\t\t<li><a th:href=\"@{/}\" href=\"home.html\"> Home </a></li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t\t<h1 th:text=\"${title}\">Title</h1>\n\t\t<div th:text=\"${message}\">Fake content</div>\n\t\t<div id=\"created\" th:text=\"${#dates.format(date)}\">July 11,\n\t\t\t2012 2:17:16 PM CDT</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "cli/spring-boot-cli/src/test/resources/templates/test.txt",
    "content": "Hello ${message}!"
  },
  {
    "path": "config/checkstyle/checkstyle-header.txt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n"
  },
  {
    "path": "config/checkstyle/checkstyle-suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE suppressions PUBLIC\n\t\t\"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"\n\t\t\"https://checkstyle.org/dtds/suppressions_1_2.dtd\">\n<suppressions>\n\t<suppress files=\"ConditionEvaluationReportLoggerTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"ConditionEvaluationReportLoggingListenerTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"ConditionEvaluationReportLoggingProcessorTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LoggingApplicationListenerTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LogbackInitializer\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LogbackLoggingSystem\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LogbackLoggingSystemTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LogbackLoggingSystemParallelInitializationTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LogbackConfigurationAotContributionTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"MetricsAutoConfigurationMeterRegistryPostProcessorIntegrationTests\\.java\" checks=\"IllegalImport\" message=\"LoggerFactory\"/>\n\t<suppress files=\"SpringApplicationTests\\.java\" checks=\"FinalClass\" />\n\t<suppress files=\".+Configuration\\.java\" checks=\"HideUtilityClassConstructor\" />\n\t<suppress files=\".+Application\\.java\" checks=\"HideUtilityClassConstructor\" />\n\t<suppress files=\"SignalUtils\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"OrderedFilter\\.java\" checks=\"InterfaceIsType\" />\n\t<suppress files=\"OrderedWebFilter\\.java\" checks=\"InterfaceIsType\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]main[\\\\/]java[\\\\/]sample[\\\\/]\" checks=\"ImportControl\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]test(Fixtures)?[\\\\/]java[\\\\/]\" checks=\"Javadoc*\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]test[\\\\/]java[\\\\/]\" id=\"mainCodeIllegalImportCheck\" />\n\t<suppress files=\"[\\\\/]autoconfigure[\\\\/].*Properties\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\"[\\\\/]spring-boot-docs[\\\\/]\" checks=\"JavadocPackage|JavadocType|JavadocVariable|SpringDeprecatedCheck\" />\n\t<suppress files=\"[\\\\/]spring-boot-docs[\\\\/]\" checks=\"SpringJavadoc\" message=\"\\@since\" />\n\t<suppress files=\"[\\\\/]spring-boot-docs[\\\\/].*jooq\" checks=\"AvoidStaticImport\" />\n\t<suppress files=\"[\\\\/]spring-boot-docs[\\\\/].*MyConfiguration__BeanDefinitions\" checks=\"JavadocMethod|SpringHideUtilityClassConstructor\" />\n\t<suppress files=\"[\\\\/]smoke-test[\\\\/]\" checks=\"JavadocType\" />\n\t<suppress files=\"[\\\\/]smoke-test[\\\\/]\" checks=\"ImportControl\" />\n\t<suppress files=\"[\\\\/]smoke-test[\\\\/].*SamplePulsarApplicationTests\" checks=\"SpringHideUtilityClassConstructor\" />\n\t<suppress files=\"[\\\\/]smoke-test[\\\\/]\" id=\"mainCodeIllegalImportCheck\" />\n\t<suppress files=\"[\\\\/]system-test[\\\\/]spring-boot-deployment-system-tests[\\\\/]\" checks=\"JavadocPackage|JavadocType\" />\n\t<suppress files=\"Ansi.*\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\"Ansi.*\\.java\" checks=\"JavadocStyle\" />\n\t<suppress files=\"LogLevel\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\"HelpMojo\\.java\" checks=\".*\"/>\n\t<suppress files=\"[\\\\/]org.springframework.boot.cli.json[\\\\/].*\\.java$\" checks=\".*\" />\n\t<suppress files=\"[\\\\/]org.springframework.boot.configurationmetadata.json[\\\\/].*\\.java$\" checks=\".*\" />\n\t<suppress files=\"[\\\\/]org.springframework.boot.configurationprocessor.json[\\\\/].*\\.java$\" checks=\".*\" />\n\t<suppress files=\"TripType\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\"Rating\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\"Direction\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\"LoggingApplicationListenerIntegrationTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"SpringBootJoranConfiguratorTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"LogbackMetricsAutoConfiguration\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"RemoteUrlPropertyExtractorTests\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"SampleLog4j2Application\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"SampleLogbackApplication\\.java\" checks=\"IllegalImport\" />\n\t<suppress files=\"OutputCaptureRuleTests\" checks=\"SpringJUnit5\" />\n\t<suppress files=\"[\\\\/]smoke-test[\\\\/]\" checks=\"SpringJavadoc\" message=\"\\@since\" />\n\t<suppress files=\"[\\\\/]smoke-test[\\\\/]spring-boot-smoke-test-testng[\\\\/]\" checks=\"SpringJUnit5\" />\n\t<suppress files=\"[\\\\/]test-support[\\\\/]\" checks=\"SpringJavadoc\" message=\"\\@since\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]dockerTest[\\\\/]java[\\\\/]\" checks=\"JavadocPackage\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]dockerTest[\\\\/]java[\\\\/]\" checks=\"SpringJavadoc\" message=\"\\@since\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]intTest[\\\\/]java[\\\\/]\" checks=\"JavadocPackage\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]intTest[\\\\/]java[\\\\/]\" checks=\"SpringJavadoc\" message=\"\\@since\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]systemTest[\\\\/]java[\\\\/]\" checks=\"JavadocPackage\" />\n\t<suppress files=\"[\\\\/]src[\\\\/]systemTest[\\\\/]java[\\\\/]\" checks=\"SpringJavadoc\" message=\"\\@since\" />\n\t<suppress files=\"ValidatorPropertiesWithDefaultValues\\.java\" checks=\"SpringMethodVisibility\" />\n\t<suppress files=\"DevToolsTestApplication\\.java\" checks=\"SpringMethodVisibility\" />\n\t<suppress files=\"DevToolsR2dbcAutoConfigurationTests\" checks=\"HideUtilityClassConstructor\" />\n\t<suppress files=\"FailureAnalyzers\\.java\" checks=\"RedundantModifier\" />\n\t<suppress files=\"SpringBootVersion\" checks=\"JavadocPackage\" />\n\t<suppress files=\"SpringBootProviderVersion\" checks=\"JavadocPackage\" />\n\t<suppress files=\"spring-boot-configuration-processor[\\\\/]src[\\\\/]test[\\\\/]java[\\\\/]org[\\\\/]springframework[\\\\/]boot[\\\\/]configurationsample[\\\\/]\" checks=\"SpringDeprecatedCheck\"/>\n\t<suppress files=\"ImportTestcontainersTests\\.java\" checks=\"InterfaceIsType\" />\n\t<suppress files=\"MyContainers\\.java\" checks=\"InterfaceIsType\" />\n\t<suppress files=\"LoadTimeWeaverAwareConsumerContainers\\.java\" checks=\"InterfaceIsType\" />\n\t<suppress files=\"ConfigurationPropertyCaching\\.java\" checks=\"SpringJavadoc\" message=\"\\@since\"/>\n\t<suppress files=\"StructuredLoggingJsonMembersCustomizer\\.java\" checks=\"SpringJavadoc\" message=\"\\@since\"/>\n\t<suppress files=\"FieldValues\\.java\" checks=\"SimplifyBooleanExpression\" />\n\t<suppress files=\"TestPrintStream\\.java\" id=\"staticAssertJ\"/>\n\t<suppress files=\"ItemMetadataAssert\\.java\" id=\"staticAssertJ\"/>\n\t<suppress files=\"SpringApplicationShutdownHookInstance\\.java\" id=\"staticAssertJ\"/>\n\t<!-- jspecify: https://github.com/spring-io/spring-javaformat/issues/454 -->\n\t<!-- We can't use full \"'...' is preceded with whitespace\" as it fails on other locales -->\n\t<suppress files=\"PemPrivateKeyParser\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<suppress files=\"Bindable\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<suppress files=\"LambdaSafe\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<suppress files=\"ConditionMessage\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<suppress files=\"EntityManagerFactoryBuilder\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<suppress files=\"DockerApi\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<suppress files=\"InvocationContext\\.java\" checks=\"NoWhitespaceBefore\" message=\"'...'\"/>\n\t<!-- https://github.com/apache/logging-log4j2/issues/2769#issuecomment-3049020222 -->\n\t<suppress files=\"SpringProfileArbiter\\.java\" checks=\"SpringMethodVisibility\"/>\n\t<suppress files=\"StructuredLogLayout\\.java\" checks=\"SpringMethodVisibility\"/>\n</suppressions>\n"
  },
  {
    "path": "config/checkstyle/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n\t\t\"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\"\n\t\t\"https://checkstyle.org/dtds/configuration_1_3.dtd\">\n<module name=\"com.puppycrawl.tools.checkstyle.Checker\">\n\t<module name=\"SuppressionFilter\">\n\t\t<property name=\"file\" value=\"${config_loc}/checkstyle-suppressions.xml\"/>\n\t</module>\n\t<module name=\"io.spring.javaformat.checkstyle.SpringChecks\">\n\t\t<property name=\"avoidStaticImportExcludes\"\n\t\t\tvalue=\"org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration\" />\n\t</module>\n\t<module name=\"io.spring.javaformat.checkstyle.check.SpringHeaderCheck\">\n\t\t<property name=\"headerFile\" value=\"${config_loc}/checkstyle-header.txt\"/>\n\t</module>\n\t<module name=\"com.puppycrawl.tools.checkstyle.TreeWalker\">\n\t\t<module name=\"io.spring.javaformat.checkstyle.check.SpringDeprecatedCheck\" />\n\t\t<module name=\"io.spring.javaformat.checkstyle.check.SpringJUnit5Check\" />\n\t\t<module name=\"ExplicitInitialization\" />\n\t\t<module\n\t\t\tname=\"com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck\">\n\t\t\t<property name=\"regexp\" value=\"true\" />\n\t\t\t<property name=\"illegalPkgs\"\n\t\t\t\tvalue=\"^sun.*, ^org\\.apache\\.commons\\.(?!compress|dbcp2|logging|pool2).*, ^com\\.datastax\\.oss\\.driver\\.shaded.*, ^com\\.google\\.common.*, ^io\\.micrometer\\.core\\.lang.*, ^io\\.micrometer\\.shaded.*, ^org\\.jetbrains\\.annotations.*, ^org\\.testcontainers\\.shaded.*,\n\t\t\t\t^org\\.apache\\.commons\\.compress\\.utils\" />\n\t\t\t<property name=\"illegalClasses\"\n\t\t\t\tvalue=\"^com\\.hazelcast\\.util\\.Base64, ^org\\.junit\\.rules\\.ExpectedException, ^org\\.mockito\\.InjectMocks, ^org\\.slf4j\\.LoggerFactory, ^org.springframework.context.annotation.ScannedGenericBeanDefinition, ^(?!org\\.springframework\\.core\\.).*ResolvableType, ^(?!org\\.springframework\\.util\\.).*ReflectionUtils, ^reactor\\.core\\.support\\.Assert\"/>\n\t\t</module>\n\t\t<module\n\t\t\tname=\"com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck\">\n\t\t\t<property name=\"id\" value=\"mainCodeIllegalImportCheck\"/>\n\t\t\t<property name=\"regexp\" value=\"true\" />\n\t\t\t<property name=\"illegalClasses\"\n\t\t\t\tvalue=\"javax.annotation.PostConstruct, jakarta.annotation.PostConstruct\"/>\n\t\t\t<property name=\"illegalPkgs\"\n\t\t\t\tvalue=\"^io\\.opentelemetry\\.semconv.*, ^org\\.gradle\\.(?!api).*\\.tasks.*\"/>\n\t\t</module>\n\t\t<module\n\t\t\tname=\"com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheck\">\n\t\t\t<property name=\"file\"\n\t\t\t\tvalue=\"${config_loc}/import-control.xml\" />\n\t\t\t<property name=\"path\" value=\"^.*[\\\\/]src[\\\\/]main[\\\\/].*$\" />\n\t\t</module>\n\t\t<module name=\"com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck\">\n\t\t\t<property name=\"maximum\" value=\"0\"/>\n\t\t\t<property name=\"format\" value=\"org\\.junit\\.Assert|org\\.junit\\.jupiter\\.api\\.Assertions\" />\n\t\t\t<property name=\"message\"\n\t\t\t\tvalue=\"Please use AssertJ imports.\" />\n\t\t\t<property name=\"ignoreComments\" value=\"true\" />\n\t\t</module>\n\t\t<module\n\t\t\tname=\"com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck\">\n\t\t\t<property name=\"maximum\" value=\"0\" />\n\t\t\t<property name=\"format\"\n\t\t\t\tvalue=\"assertThatExceptionOfType\\((NullPointerException|IllegalArgumentException|IOException|IllegalStateException)\\.class\\)\" />\n\t\t\t<property name=\"message\"\n\t\t\t\tvalue=\"Please use specialized AssertJ assertThat*Exception method.\" />\n\t\t\t<property name=\"ignoreComments\" value=\"true\" />\n\t\t</module>\n\t\t<module\n\t\t\tname=\"com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck\">\n\t\t\t<property name=\"maximum\" value=\"0\" />\n\t\t\t<property name=\"format\"\n\t\t\t\t\t  value=\"assertThatThrownBy\\(\" />\n\t\t\t<property name=\"message\"\n\t\t\t\t\t  value=\"Please use AssertJ assertThatExceptionOfType method.\" />\n\t\t\t<property name=\"ignoreComments\" value=\"true\" />\n\t\t</module>\n \t\t<module name=\"com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck\">\n \t\t\t<property name=\"maximum\" value=\"0\"/>\n\t\t\t<property name=\"format\" value=\"org\\.mockito\\.(Mockito|BDDMockito)\\.(when|doThrow|doAnswer|doReturn|verify|verifyNoInteractions|verifyNoMoreInteractions)\" />\n\t\t\t<property name=\"message\"\n\t\t\t\tvalue=\"Please use BDD-style (given, when, then) using BDDMockito imports.\" />\n\t\t\t<property name=\"ignoreComments\" value=\"true\" />\n\t\t</module>\n\t\t<module name=\"com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck\">\n\t\t\t<property name=\"maximum\" value=\"0\"/>\n\t\t\t<property name=\"format\" value=\"(List|Map|Set)\\.of\\(\\)\" />\n\t\t\t<property name=\"message\"\n\t\t\t\t\t  value=\"Please use Collections.emptyList()/emptyMap()/emptySet() for creating empty lists/maps/sets.\" />\n\t\t\t<property name=\"ignoreComments\" value=\"true\" />\n\t\t</module>\n\t\t<module name=\"com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck\">\n\t\t\t<property name=\"id\" value=\"staticAssertJ\"/>\n\t\t\t<property name=\"maximum\" value=\"0\"/>\n\t\t\t<property name=\"format\" value=\"import org\\.assertj\\.core\\.api\\.Assertions;\" />\n\t\t\t<property name=\"message\"\n\t\t\t\tvalue=\"Please use static AssertJ imports.\" />\n\t\t\t<property name=\"ignoreComments\" value=\"true\" />\n\t\t</module>\n\t\t<module name=\"io.spring.javaformat.checkstyle.check.SpringJavadocCheck\">\n\t\t\t<property name=\"publicOnlySinceTags\" value=\"true\" />\n\t\t\t<property name=\"requireSinceTag\" value=\"true\" />\n\t\t</module>\n\t</module>\n</module>\n"
  },
  {
    "path": "config/checkstyle/import-control.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE import-control PUBLIC \"-//Checkstyle//DTD ImportControl Configuration 1.4//EN\" \"https://checkstyle.org/dtds/import_control_1_4.dtd\">\n<import-control pkg=\"org.springframework.boot\">\n\n\t<!-- Only use Micrometer Observation -->\n\t<allow pkg=\"io.micrometer.observation\" />\n\t<disallow pkg=\"io.micrometer\" />\n\n\t<!-- Improve DevEx with fluent APIs -->\n\t<allow class=\"org.springframework.lang.CheckReturnValue\" />\n\n\t<!-- Use JSpecify for nullability (not Spring)  -->\n\t<allow class=\"org.springframework.lang.Contract\" />\n\t<disallow pkg=\"org.springframework.lang\" />\n\n\t<!-- Allow other imports -->\n\t<allow pkg=\".*\" regex=\"true\" />\n\n\t<!-- Keep foundation packages away from 'org.springframework.boot' package -->\n\t<subpackage name=\"ansi\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"availability\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"bootstrap\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"context\">\n\t\t<subpackage name=\"properties\">\n\t\t\t<subpackage name=\"bind\">\n\t\t\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"source\">\n\t\t\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t\t\t</subpackage>\n\t\t</subpackage>\n\t</subpackage>\n\t<subpackage name=\"env\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"info\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"io\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"ssl\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"origin\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\t<subpackage name=\"util\">\n\t\t<disallow pkg=\"org.springframework.boot\" exact-match=\"true\"/>\n\t</subpackage>\n\n\t<!-- Open direct use of micrometer to specific subpackages  -->\n\t<subpackage name=\"metrics\">\n\t\t<allow pkg=\"io.micrometer\" />\n\t</subpackage>\n\t<subpackage name=\".*\\.metrics\" regex=\"true\">\n\t\t<allow pkg=\"io.micrometer\" />\n\t</subpackage>\n\t<subpackage name=\"(.*\\.autoconfigure|autoconfigure)(\\..*)?\" regex=\"true\">\n\t\t<allow pkg=\"io.micrometer\" />\n\t</subpackage>\n\t<subpackage name=\"docs\">\n\t\t<allow pkg=\"io.micrometer\" />\n\t</subpackage>\n\t<subpackage name=\"test\">\n\t\t<subpackage name=\"autoconfigure\">\n\t\t\t<subpackage name=\"actuate\">\n\t\t\t\t<allow pkg=\"io.micrometer\" />\n\t\t\t</subpackage>\n\t\t</subpackage>\n\t</subpackage>\n\n\t<!-- Keep logging focused on lower level packages (binding and AOT) -->\n\t<subpackage name=\"logging\">\n\t\t<allow pkg=\"org.springframework.boot.context.properties\" />\n\t\t<allow pkg=\"org.springframework.boot.context.properties.bind\" />\n\t\t<allow pkg=\"org.springframework.context.aot\" />\n\t\t<disallow pkg=\"org.springframework.context\" />\n\t\t<disallow pkg=\"org.springframework.boot.context\" />\n\t</subpackage>\n\n\t<!-- Web related concerns -->\n\t<subpackage name=\"web\">\n\n\t\t<!-- Lock things down -->\n\t\t<disallow pkg=\"org.springframework.boot.web\" />\n\t\t<disallow pkg=\"org.springframework.web.servlet\" />\n\t\t<disallow pkg=\"jakarta.servlet\" />\n\n\t\t<!-- Common -->\n\t\t<subpackage name=\"context\">\n\t\t\t<allow pkg=\"org.springframework.context\" />\n\t\t\t<subpackage name=\"servlet\">\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t</subpackage>\n\t\t</subpackage>\n\t\t<subpackage name=\"server\">\n\t\t\t<allow pkg=\"org.springframework.boot.web.error\" />\n\t\t\t<allow pkg=\"org.springframework.boot.web.server\" />\n\t\t\t<disallow pkg=\"org.springframework.context\" />\n\t\t\t<subpackage name=\"autoconfigure\">\n\t\t\t\t<allow pkg=\"org.springframework.context\" />\n\t\t\t\t<subpackage name=\"servlet\">\n\t\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t\t</subpackage>\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"client\">\n\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.context\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"context\">\n\t\t\t\t<allow pkg=\"org.springframework.context\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"reactive\">\n\t\t\t\t<subpackage name=\"context\">\n\t\t\t\t\t<allow pkg=\"org.springframework.context\" />\n\t\t\t\t\t<allow pkg=\"org.springframework.web.context\" />\n\t\t\t\t\t<allow pkg=\"org.springframework.boot.web.context.reactive\" />\n\t\t\t\t</subpackage>\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"servlet\">\n\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t\t<subpackage name=\"context\">\n\t\t\t\t\t<allow pkg=\"org.springframework.context\" />\n\t\t\t\t\t<allow pkg=\"org.springframework.web.context\" />\n\t\t\t\t\t<allow pkg=\"org.springframework.boot.web.context.servlet\" />\n\t\t\t\t</subpackage>\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"test\">\n\t\t\t\t<allow pkg=\".*\" regex=\"true\" />\n\t\t\t</subpackage>\n\t\t</subpackage>\n\n\t\t<!-- Servlet -->\n\t\t<subpackage name=\"servlet\">\n\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t<subpackage name=\"filter\">\n\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"support\">\n\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.error\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.context.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"view\">\n\t\t\t\t<allow pkg=\"org.springframework.web.servlet\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"error\">\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.error\" />\n\t\t\t\t<allow pkg=\"org.springframework.web.servlet\" />\n\t\t\t</subpackage>\n\t\t</subpackage>\n\n\t\t<!-- Reactive -->\n\t\t<subpackage name=\"reactive\">\n\t\t\t<subpackage name=\"context\">\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.context\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"error\">\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.error\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"result\">\n\t\t\t\t<subpackage name=\"view\">\n\t\t\t\t\t<allow pkg=\"org.springframework.boot.web.reactive.result.view\" />\n\t\t\t\t</subpackage>\n\t\t\t</subpackage>\n\t\t</subpackage>\n\n\t</subpackage>\n\n\t<!-- Actuator endpoint infrastructure -->\n\t<subpackage name=\"actuate\">\n\t\t<subpackage name=\"endpoint\">\n\t\t\t<disallow pkg=\"org.springframework.http\" />\n\t\t\t<disallow pkg=\"org.springframework.web\" />\n\t\t\t<subpackage name=\"web\">\n\t\t\t\t<allow pkg=\"org.springframework.http\" />\n\t\t\t\t<allow pkg=\"org.springframework.web\" />\n\t\t\t\t<subpackage name=\"servlet\">\n\t\t\t\t\t<disallow pkg=\"org.springframework.web.reactive\" />\n\t\t\t\t</subpackage>\n\t\t\t\t<subpackage name=\"reactive\">\n\t\t\t\t\t<disallow pkg=\"org.springframework.web.servlet\" />\n\t\t\t\t</subpackage>\n\t\t\t</subpackage>\n\t\t</subpackage>\n\t</subpackage>\n\n\t<!-- Web Servers -->\n\t<subpackage name=\"tomcat|undertow|jetty|reactor\" regex=\"true\">\n\t\t\t<allow pkg=\"org.springframework.boot.web.server\" />\n\t\t\t<disallow pkg=\"org.springframework.boot.web\" />\n\t\t\t<disallow pkg=\"org.springframework.web.servlet\" />\n\t\t\t<disallow pkg=\"org.springframework.web.reactive\" />\n\t\t<subpackage name=\"servlet\">\n\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t<allow pkg=\"org.springframework.boot.web.server\" />\n\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t<allow pkg=\"org.springframework.boot.web.error\" />\n\t\t\t<allow pkg=\"org.springframework.web.servlet\" />\n\t\t</subpackage>\n\t\t<subpackage name=\"reactive\">\n\t\t\t<allow pkg=\"org.springframework.boot.web.server\" />\n\t\t\t<allow pkg=\"org.springframework.boot.web.codec\" />\n\t\t\t<allow pkg=\"org.springframework.boot.web.reactive\" />\n\t\t\t<allow pkg=\"org.springframework.web.reactive\" />\n\t\t</subpackage>\n\t\t<subpackage name=\"autoconfigure\">\n\t\t\t<subpackage name=\"servlet\">\n\t\t\t\t<allow pkg=\"jakarta.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.servlet\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.error\" />\n\t\t\t\t<allow pkg=\"org.springframework.web.servlet\" />\n\t\t\t</subpackage>\n\t\t\t<subpackage name=\"reactive\">\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.codec\" />\n\t\t\t\t<allow pkg=\"org.springframework.boot.web.reactive\" />\n\t\t\t\t<allow pkg=\"org.springframework.web.reactive\" />\n\t\t\t</subpackage>\n\t\t</subpackage>\n\t</subpackage>\n\n</import-control>\n"
  },
  {
    "path": "config/detekt/config.yml",
    "content": "config:\n  validation: true\n  warningsAsErrors: true\nconsole-reports:\n  active: true\n  exclude:\n    - 'ProjectStatisticsReport'\n    - 'ComplexityReport'\n    - 'NotificationReport'\n    - 'FindingsReport'\n    - 'FileBasedFindingsReport'\nprocessors:\n  active: false\nnaming:\n  MatchingDeclarationName:\n    active: true\nstyle:\n  MaxLineLength:\n    active: true\n  NewLineAtEndOfFile:\n    active: true\n  UnusedImport:\n    active: true\n  WildcardImport:\n    active: true\n"
  },
  {
    "path": "config/nohttp/allowlist.lines",
    "content": "^http://ganglia.sourceforge.net.*\n^http://livereload.com/.*\n^http://schemas.xmlsoap.org/.*\n^http://www.jdotsoft.com.*\n^http://www.liquibase.org/xml/ns/dbchangelog/.*\n^http://www.w3.org/2000/09/xmldsig.*\n^http://www.jooq.org/xsd/jooq-runtime-.*\n"
  },
  {
    "path": "config/nohttp/checkstyle.xml",
    "content": "<!DOCTYPE module PUBLIC \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n\t\t\"https://www.puppycrawl.com/dtds/configuration_1_3.dtd\">\n<module name=\"Checker\">\n\t<property name=\"charset\" value=\"UTF-8\"/>\n\t<property name=\"fileExtensions\" value=\"\"/>\n\t<module name=\"io.spring.nohttp.checkstyle.check.NoHttpCheck\">\n\t\t<property name=\"allowlistFileName\" value=\"${config_loc}/allowlist.lines\"/>\n\t</module>\n\t<module name=\"SuppressionFilter\">\n\t\t<property name=\"file\" value=\"${config_loc}/suppressions.xml\"/>\n\t</module>\n\t<module name=\"SuppressWithPlainTextCommentFilter\"/>\n</module>\n"
  },
  {
    "path": "config/nohttp/suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE suppressions PUBLIC\n\t\"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN\"\n\t\"https://checkstyle.org/dtds/suppressions_1_2.dtd\">\n<suppressions>\n\t<suppress files=\"[\\\\/]transaction-logs[\\\\/]\" checks=\"NoHttp\" />\n\t<suppress files=\"[\\\\/]build.log\" checks=\"NoHttp\" />\n\t<suppress files=\".+\\.(jar|git|ico|p12|gif|jks|jpg|svg)\" checks=\"NoHttp\" />\n\t<suppress files=\"jquery.validate.js\" checks=\"NoHttp\" />\n\t<suppress files=\"jquery-[0-9]\\.[0-9]\\.[0-9].js\" checks=\"NoHttp\" />\n\t<suppress files=\"[\\\\/]spring-boot-project.setup\" checks=\"NoHttp\" />\n\t<suppress files=\"DockerHostTests\\.java\" checks=\"NoHttp\" />\n\t<suppress files=\"cyclonedx\\.json\" checks=\"NoHttp\" />\n\t<suppress files=\"spdx\\.json\" checks=\"NoHttp\" />\n\t<suppress files=\"syft\\.json\" checks=\"NoHttp\" />\n</suppressions>\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Configuration Metadata\"\n\nsourceSets {\n\tmain {\n\t\tjava {\n\t\t\tsrcDir file(\"src/json-shade/java\")\n\t\t}\n\t}\n}\n\ndependencies {\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.springframework:spring-core\")\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/README.adoc",
    "content": "## Shaded JSON\n\nThis source was originally taken from `com.vaadin.external.google:android-json` which\nprovides a clean room re-implementation of the `org.json` APIs and does not include the\n\"Do not use for evil\" clause.\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/java/org/springframework/boot/configurationmetadata/json/JSON.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.json;\n\nclass JSON {\n\n\tstatic double checkDouble(double d) throws JSONException {\n\t\tif (Double.isInfinite(d) || Double.isNaN(d)) {\n\t\t\tthrow new JSONException(\"Forbidden numeric value: \" + d);\n\t\t}\n\t\treturn d;\n\t}\n\n\tstatic Boolean toBoolean(Object value) {\n\t\tif (value instanceof Boolean) {\n\t\t\treturn (Boolean) value;\n\t\t}\n\t\tif (value instanceof String stringValue) {\n\t\t\tif (\"true\".equalsIgnoreCase(stringValue)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\"false\".equalsIgnoreCase(stringValue)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Double toDouble(Object value) {\n\t\tif (value instanceof Double) {\n\t\t\treturn (Double) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).doubleValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn Double.valueOf((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Integer toInteger(Object value) {\n\t\tif (value instanceof Integer) {\n\t\t\treturn (Integer) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).intValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn (int) Double.parseDouble((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Long toLong(Object value) {\n\t\tif (value instanceof Long) {\n\t\t\treturn (Long) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).longValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn (long) Double.parseDouble((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic String toString(Object value) {\n\t\tif (value instanceof String) {\n\t\t\treturn (String) value;\n\t\t}\n\t\tif (value != null) {\n\t\t\treturn String.valueOf(value);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static JSONException typeMismatch(Object indexOrName, Object actual, String requiredType)\n\t\t\tthrows JSONException {\n\t\tif (actual == null) {\n\t\t\tthrow new JSONException(\"Value at \" + indexOrName + \" is null.\");\n\t\t}\n\t\tthrow new JSONException(\"Value \" + actual + \" at \" + indexOrName + \" of type \" + actual.getClass().getName()\n\t\t\t\t+ \" cannot be converted to \" + requiredType);\n\t}\n\n\tpublic static JSONException typeMismatch(Object actual, String requiredType) throws JSONException {\n\t\tif (actual == null) {\n\t\t\tthrow new JSONException(\"Value is null.\");\n\t\t}\n\t\tthrow new JSONException(\"Value \" + actual + \" of type \" + actual.getClass().getName()\n\t\t\t\t+ \" cannot be converted to \" + requiredType);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/java/org/springframework/boot/configurationmetadata/json/JSONArray.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.json;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * A dense indexed sequence of values. Values may be any mix of {@link JSONObject\n * JSONObjects}, other {@link JSONArray JSONArrays}, Strings, Booleans, Integers, Longs,\n * Doubles, {@code null} or {@link JSONObject#NULL}. Values may not be\n * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not\n * listed here.\n * <p>\n * {@code JSONArray} has the same type coercion behavior and optional/mandatory accessors\n * as {@link JSONObject}. See that class' documentation for details.\n * <p>\n * <strong>Warning:</strong> this class represents null in two incompatible ways: the\n * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.\n * In particular, {@code get} fails if the requested index holds the null reference, but\n * succeeds if it holds {@code JSONObject.NULL}.\n * <p>\n * Instances of this class are not thread safe. Although this class is nonfinal, it was\n * not designed for inheritance and should not be subclassed. In particular, self-use by\n * overridable methods is not specified. See <i>Effective Java</i> Item 17, \"Design and\n * Document or inheritance or else prohibit it\" for further information.\n */\npublic class JSONArray {\n\n\tprivate final List<Object> values;\n\n\t/**\n\t * Creates a {@code JSONArray} with no values.\n\t */\n\tpublic JSONArray() {\n\t\tthis.values = new ArrayList<>();\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} by copying all values from the given collection.\n\t * @param copyFrom a collection whose values are of supported types. Unsupported\n\t * values are not permitted and will yield an array in an inconsistent state.\n\t */\n\t/* Accept a raw type for API compatibility */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic JSONArray(Collection copyFrom) {\n\t\tthis();\n\t\tif (copyFrom != null) {\n\t\t\tfor (Iterator it = copyFrom.iterator(); it.hasNext();) {\n\t\t\t\tput(JSONObject.wrap(it.next()));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the next array in the tokener.\n\t * @param readFrom a tokener whose nextValue() method will yield a {@code JSONArray}.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code JSONArray}.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray(JSONTokener readFrom) throws JSONException {\n\t\t/*\n\t\t * Getting the parser to populate this could get tricky. Instead, just parse to\n\t\t * temporary JSONArray and then steal the data from that.\n\t\t */\n\t\tObject object = readFrom.nextValue();\n\t\tif (object instanceof JSONArray) {\n\t\t\tthis.values = ((JSONArray) object).values;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the JSON string.\n\t * @param json a JSON-encoded string containing an array.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray(String json) throws JSONException {\n\t\tthis(new JSONTokener(json));\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the given primitive array.\n\t * @param array a primitive array\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray(Object array) throws JSONException {\n\t\tif (!array.getClass().isArray()) {\n\t\t\tthrow new JSONException(\"Not a primitive array: \" + array.getClass());\n\t\t}\n\t\tfinal int length = Array.getLength(array);\n\t\tthis.values = new ArrayList<>(length);\n\t\tfor (int i = 0; i < length; ++i) {\n\t\t\tput(JSONObject.wrap(Array.get(array, i)));\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of values in this array.\n\t * @return the length of this array\n\t */\n\tpublic int length() {\n\t\treturn this.values.size();\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(boolean value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(double value) throws JSONException {\n\t\tthis.values.add(JSON.checkDouble(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(int value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(long value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be\n\t * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. Unsupported\n\t * values are not permitted and will cause the array to be in an inconsistent state.\n\t * @return this array.\n\t */\n\tpublic JSONArray put(Object value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, boolean value) throws JSONException {\n\t\treturn put(index, (Boolean) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, double value) throws JSONException {\n\t\treturn put(index, (Double) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, int value) throws JSONException {\n\t\treturn put(index, (Integer) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, long value) throws JSONException {\n\t\treturn put(index, (Long) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be\n\t * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, Object value) throws JSONException {\n\t\tif (value instanceof Number) {\n\t\t\t// deviate from the original by checking all Numbers, not just floats &\n\t\t\t// doubles\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\t\twhile (this.values.size() <= index) {\n\t\t\tthis.values.add(null);\n\t\t}\n\t\tthis.values.set(index, value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns true if this array has no value at {@code index}, or if its value is the\n\t * {@code null} reference or {@link JSONObject#NULL}.\n\t * @param index the index to set the value to\n\t * @return true if this array has no value at {@code index}\n\t */\n\tpublic boolean isNull(int index) {\n\t\tObject value = opt(index);\n\t\treturn value == null || value == JSONObject.NULL;\n\t}\n\n\t/**\n\t * Returns the value at {@code index}.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index}.\n\t * @throws JSONException if this array has no value at {@code index}, or if that value\n\t * is the {@code null} reference. This method returns normally if the value is\n\t * {@code JSONObject#NULL}.\n\t */\n\tpublic Object get(int index) throws JSONException {\n\t\ttry {\n\t\t\tObject value = this.values.get(index);\n\t\t\tif (value == null) {\n\t\t\t\tthrow new JSONException(\"Value at \" + index + \" is null.\");\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcatch (IndexOutOfBoundsException e) {\n\t\t\tthrow new JSONException(\"Index \" + index + \" out of range [0..\" + this.values.size() + \")\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index}, or null if the array has no value at\n\t * {@code index}.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index} or {@code null}\n\t */\n\tpublic Object opt(int index) {\n\t\tif (index < 0 || index >= this.values.size()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.values.get(index);\n\t}\n\n\t/**\n\t * Removes and returns the value at {@code index}, or null if the array has no value\n\t * at {@code index}.\n\t * @param index the index of the value to remove\n\t * @return the previous value at {@code index}\n\t */\n\tpublic Object remove(int index) {\n\t\tif (index < 0 || index >= this.values.size()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.values.remove(index);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a boolean.\n\t */\n\tpublic boolean getBoolean(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"boolean\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean. Returns false otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code false}\n\t */\n\tpublic boolean optBoolean(int index) {\n\t\treturn optBoolean(index, false);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic boolean optBoolean(int index, boolean fallback) {\n\t\tObject object = opt(index);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a double.\n\t */\n\tpublic double getDouble(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tDouble result = JSON.toDouble(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"double\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double. Returns {@code NaN} otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code NaN}\n\t */\n\tpublic double optDouble(int index) {\n\t\treturn optDouble(index, Double.NaN);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic double optDouble(int index, double fallback) {\n\t\tObject object = opt(index);\n\t\tDouble result = JSON.toDouble(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to an int.\n\t */\n\tpublic int getInt(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tInteger result = JSON.toInteger(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"int\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int. Returns 0 otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code 0}\n\t */\n\tpublic int optInt(int index) {\n\t\treturn optInt(index, 0);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic int optInt(int index, int fallback) {\n\t\tObject object = opt(index);\n\t\tInteger result = JSON.toInteger(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a long.\n\t */\n\tpublic long getLong(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tLong result = JSON.toLong(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"long\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long. Returns 0 otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code 0}\n\t */\n\tpublic long optLong(int index) {\n\t\treturn optLong(index, 0L);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic long optLong(int index, long fallback) {\n\t\tObject object = opt(index);\n\t\tLong result = JSON.toLong(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if no such value exists.\n\t */\n\tpublic String getString(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tString result = JSON.toString(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"String\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary. Returns\n\t * the empty string if no such value exists.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or an empty string\n\t */\n\tpublic String optString(int index) {\n\t\treturn optString(index, \"\");\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary. Returns\n\t * {@code fallback} if no such value exists.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic String optString(int index, String fallback) {\n\t\tObject object = opt(index);\n\t\tString result = JSON.toString(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONArray}.\n\t * @param index the index to get the value from\n\t * @return the array at {@code index}\n\t * @throws JSONException if the value doesn't exist or is not a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray getJSONArray(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tif (object instanceof JSONArray) {\n\t\t\treturn (JSONArray) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(index, object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONArray}. Returns null otherwise.\n\t * @param index the index to get the value from\n\t * @return the array at {@code index} or {@code null}\n\t */\n\tpublic JSONArray optJSONArray(int index) {\n\t\tObject object = opt(index);\n\t\treturn object instanceof JSONArray ? (JSONArray) object : null;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONObject}.\n\t * @param index the index to get the value from\n\t * @return the object at {@code index}\n\t * @throws JSONException if the value doesn't exist or is not a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject getJSONObject(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tif (object instanceof JSONObject) {\n\t\t\treturn (JSONObject) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(index, object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONObject}. Returns null otherwise.\n\t * @param index the index to get the value from\n\t * @return the object at {@code index} or {@code null}\n\t */\n\tpublic JSONObject optJSONObject(int index) {\n\t\tObject object = opt(index);\n\t\treturn object instanceof JSONObject ? (JSONObject) object : null;\n\t}\n\n\t/**\n\t * Returns a new object whose values are the values in this array, and whose names are\n\t * the values in {@code names}. Names and values are paired up by index from 0 through\n\t * to the shorter array's length. Names that are not strings will be coerced to\n\t * strings. This method returns null if either array is empty.\n\t * @param names the property names\n\t * @return a json object\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONObject toJSONObject(JSONArray names) throws JSONException {\n\t\tJSONObject result = new JSONObject();\n\t\tint length = Math.min(names.length(), this.values.size());\n\t\tif (length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString name = JSON.toString(names.opt(i));\n\t\t\tresult.put(name, opt(i));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a new string by alternating this array's values with {@code\n\t * separator}. This array's string values are quoted and have their special characters\n\t * escaped. For example, the array containing the strings '12\" pizza', 'taco' and\n\t * 'soda' joined on '+' returns this: <pre>\"12\\\" pizza\"+\"taco\"+\"soda\"</pre>\n\t * @param separator the separator to use\n\t * @return the joined value\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String join(String separator) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer();\n\t\tstringer.open(JSONStringer.Scope.NULL, \"\");\n\t\tfor (int i = 0, size = this.values.size(); i < size; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tstringer.out.append(separator);\n\t\t\t}\n\t\t\tstringer.value(this.values.get(i));\n\t\t}\n\t\tstringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, \"\");\n\t\treturn stringer.out.toString();\n\t}\n\n\t/**\n\t * Encodes this array as a compact JSON string, such as: <pre>[94043,90210]</pre>\n\t * @return a compact JSON string representation of this array\n\t */\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\twriteTo(stringer);\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Encodes this array as a human-readable JSON string for debugging, such as: <pre>\n\t * [\n\t *     94043,\n\t *     90210\n\t * ]</pre>\n\t * @param indentSpaces the number of spaces to indent for each level of nesting.\n\t * @return a human-readable JSON string of this array\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String toString(int indentSpaces) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer(indentSpaces);\n\t\twriteTo(stringer);\n\t\treturn stringer.toString();\n\t}\n\n\tvoid writeTo(JSONStringer stringer) throws JSONException {\n\t\tstringer.array();\n\t\tfor (Object value : this.values) {\n\t\t\tstringer.value(value);\n\t\t}\n\t\tstringer.endArray();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\treturn o instanceof JSONArray && ((JSONArray) o).values.equals(this.values);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\t// diverge from the original, which doesn't implement hashCode\n\t\treturn this.values.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/java/org/springframework/boot/configurationmetadata/json/JSONException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.json;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Thrown to indicate a problem with the JSON API. Such problems include:\n * <ul>\n * <li>Attempts to parse or construct malformed documents\n * <li>Use of null as a name\n * <li>Use of numeric types not available to JSON, such as {@link Double#isNaN() NaNs} or\n * {@link Double#isInfinite() infinities}.\n * <li>Lookups using an out of range index or nonexistent name\n * <li>Type mismatches on lookups\n * </ul>\n * <p>\n * Although this is a checked exception, it is rarely recoverable. Most callers should\n * simply wrap this exception in an unchecked exception and rethrow: <pre class=\"code\">\n *     public JSONArray toJSONObject() {\n *     try {\n *         JSONObject result = new JSONObject();\n *         ...\n *     } catch (JSONException e) {\n *         throw new RuntimeException(e);\n *     }\n * }</pre>\n */\npublic class JSONException extends Exception {\n\n\tpublic JSONException(String s) {\n\t\tsuper(s);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/java/org/springframework/boot/configurationmetadata/json/JSONObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.json;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * A modifiable set of name/value mappings. Names are unique, non-null strings. Values may\n * be any mix of {@link JSONObject JSONObjects}, {@link JSONArray JSONArrays}, Strings,\n * Booleans, Integers, Longs, Doubles or {@link #NULL}. Values may not be {@code null},\n * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not\n * listed here.\n * <p>\n * This class can coerce values to another type when requested.\n * <ul>\n * <li>When the requested type is a boolean, strings will be coerced using a\n * case-insensitive comparison to \"true\" and \"false\".\n * <li>When the requested type is a double, other {@link Number} types will be coerced\n * using {@link Number#doubleValue() doubleValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be.\n * <li>When the requested type is an int, other {@link Number} types will be coerced using\n * {@link Number#intValue() intValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be, and then cast to int.\n * <li><a id=\"lossy\">When the requested type is a long, other {@link Number} types will be\n * coerced using {@link Number#longValue() longValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be, and then cast to long. This two-step conversion\n * is lossy for very large values. For example, the string \"9223372036854775806\" yields\n * the long 9223372036854775807.</a>\n * <li>When the requested type is a String, other non-null values will be coerced using\n * {@link String#valueOf(Object)}. Although null cannot be coerced, the sentinel value\n * {@link JSONObject#NULL} is coerced to the string \"null\".\n * </ul>\n * <p>\n * This class can look up both mandatory and optional values:\n * <ul>\n * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This fails with a\n * {@code JSONException} if the requested name has no value or if the value cannot be\n * coerced to the requested type.\n * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This returns a\n * system- or user-supplied default if the requested name has no value or if the value\n * cannot be coerced to the requested type.\n * </ul>\n * <p>\n * <strong>Warning:</strong> this class represents null in two incompatible ways: the\n * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.\n * In particular, calling {@code put(name, null)} removes the named entry from the object\n * but {@code put(name, JSONObject.NULL)} stores an entry whose value is\n * {@code JSONObject.NULL}.\n * <p>\n * Instances of this class are not thread safe. Although this class is nonfinal, it was\n * not designed for inheritance and should not be subclassed. In particular, self-use by\n * overrideable methods is not specified. See <i>Effective Java</i> Item 17, \"Design and\n * Document or inheritance or else prohibit it\" for further information.\n */\npublic class JSONObject {\n\n\tprivate static final Double NEGATIVE_ZERO = -0d;\n\n\t/**\n\t * A sentinel value used to explicitly define a name with no value. Unlike\n\t * {@code null}, names with this value:\n\t * <ul>\n\t * <li>show up in the {@link #names} array\n\t * <li>show up in the {@link #keys} iterator\n\t * <li>return {@code true} for {@link #has(String)}\n\t * <li>do not throw on {@link #get(String)}\n\t * <li>are included in the encoded JSON string.\n\t * </ul>\n\t * <p>\n\t * This value violates the general contract of {@link Object#equals} by returning true\n\t * when compared to {@code null}. Its {@link #toString} method returns \"null\".\n\t */\n\tpublic static final Object NULL = new Object() {\n\n\t\t@Override\n\t\tpublic boolean equals(Object o) {\n\t\t\treturn o == this || o == null; // API specifies this broken equals\n\t\t\t\t\t\t\t\t\t\t\t// implementation\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"null\";\n\t\t}\n\n\t};\n\n\tprivate final Map<String, Object> nameValuePairs;\n\n\t/**\n\t * Creates a {@code JSONObject} with no name/value mappings.\n\t */\n\tpublic JSONObject() {\n\t\tthis.nameValuePairs = new LinkedHashMap<>();\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} by copying all name/value mappings from the given\n\t * map.\n\t * @param copyFrom a map whose keys are of type {@link String} and whose values are of\n\t * supported types.\n\t * @throws NullPointerException if any of the map's keys are null.\n\t */\n\t/* (accept a raw type for API compatibility) */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic JSONObject(Map copyFrom) {\n\t\tthis();\n\t\tMap<?, ?> contentsTyped = copyFrom;\n\t\tfor (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {\n\t\t\t/*\n\t\t\t * Deviate from the original by checking that keys are non-null and of the\n\t\t\t * proper type. (We still defer validating the values).\n\t\t\t */\n\t\t\tString key = (String) entry.getKey();\n\t\t\tif (key == null) {\n\t\t\t\tthrow new NullPointerException(\"key == null\");\n\t\t\t}\n\t\t\tthis.nameValuePairs.put(key, wrap(entry.getValue()));\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} with name/value mappings from the next object in\n\t * the tokener.\n\t * @param readFrom a tokener whose nextValue() method will yield a {@code JSONObject}.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.\n\t */\n\tpublic JSONObject(JSONTokener readFrom) throws JSONException {\n\t\t/*\n\t\t * Getting the parser to populate this could get tricky. Instead, just parse to\n\t\t * temporary JSONObject and then steal the data from that.\n\t\t */\n\t\tObject object = readFrom.nextValue();\n\t\tif (object instanceof JSONObject) {\n\t\t\tthis.nameValuePairs = ((JSONObject) object).nameValuePairs;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} with name/value mappings from the JSON string.\n\t * @param json a JSON-encoded string containing an object.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject(String json) throws JSONException {\n\t\tthis(new JSONTokener(json));\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} by copying mappings for the listed names from the\n\t * given object. Names that aren't present in {@code copyFrom} will be skipped.\n\t * @param copyFrom the source\n\t * @param names the property names\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject(JSONObject copyFrom, String[] names) throws JSONException {\n\t\tthis();\n\t\tfor (String name : names) {\n\t\t\tObject value = copyFrom.opt(name);\n\t\t\tif (value != null) {\n\t\t\t\tthis.nameValuePairs.put(name, value);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of name/value mappings in this object.\n\t * @return the number of name/value mappings in this object\n\t */\n\tpublic int length() {\n\t\treturn this.nameValuePairs.size();\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, boolean value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, double value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), JSON.checkDouble(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, int value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, long value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name. If the value is {@code null}, any existing mapping for {@code name}\n\t * is removed.\n\t * @param name the name of the property\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link #NULL}, or {@code null}. May not be {@link Double#isNaN()\n\t * NaNs} or {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, Object value) throws JSONException {\n\t\tif (value == null) {\n\t\t\tthis.nameValuePairs.remove(name);\n\t\t\treturn this;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\t// deviate from the original by checking all Numbers, not just floats &\n\t\t\t// doubles\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Equivalent to {@code put(name, value)} when both parameters are non-null; does\n\t * nothing otherwise.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject putOpt(String name, Object value) throws JSONException {\n\t\tif (name == null || value == null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn put(name, value);\n\t}\n\n\t/**\n\t * Appends {@code value} to the array already mapped to {@code name}. If this object\n\t * has no mapping for {@code name}, this inserts a new mapping. If the mapping exists\n\t * but its value is not an array, the existing and new values are inserted in order\n\t * into a new array which is itself mapped to {@code name}. In aggregate, this allows\n\t * values to be added to a mapping one at a time.\n\t * @param name the name of the property\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject accumulate(String name, Object value) throws JSONException {\n\t\tObject current = this.nameValuePairs.get(checkName(name));\n\t\tif (current == null) {\n\t\t\treturn put(name, value);\n\t\t}\n\n\t\t// check in accumulate, since array.put(Object) doesn't do any checking\n\t\tif (value instanceof Number) {\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\n\t\tif (current instanceof JSONArray array) {\n\t\t\tarray.put(value);\n\t\t}\n\t\telse {\n\t\t\tJSONArray array = new JSONArray();\n\t\t\tarray.put(current);\n\t\t\tarray.put(value);\n\t\t\tthis.nameValuePairs.put(name, array);\n\t\t}\n\t\treturn this;\n\t}\n\n\tString checkName(String name) throws JSONException {\n\t\tif (name == null) {\n\t\t\tthrow new JSONException(\"Names must be non-null\");\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * Removes the named mapping if it exists; does nothing otherwise.\n\t * @param name the name of the property\n\t * @return the value previously mapped by {@code name}, or null if there was no such\n\t * mapping.\n\t */\n\tpublic Object remove(String name) {\n\t\treturn this.nameValuePairs.remove(name);\n\t}\n\n\t/**\n\t * Returns true if this object has no mapping for {@code name} or if it has a mapping\n\t * whose value is {@link #NULL}.\n\t * @param name the name of the property\n\t * @return true if this object has no mapping for {@code name}\n\t */\n\tpublic boolean isNull(String name) {\n\t\tObject value = this.nameValuePairs.get(name);\n\t\treturn value == null || value == NULL;\n\t}\n\n\t/**\n\t * Returns true if this object has a mapping for {@code name}. The mapping may be\n\t * {@link #NULL}.\n\t * @param name the name of the property\n\t * @return true if this object has a mapping for {@code name}\n\t */\n\tpublic boolean has(String name) {\n\t\treturn this.nameValuePairs.containsKey(name);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if no such mapping exists.\n\t */\n\tpublic Object get(String name) throws JSONException {\n\t\tObject result = this.nameValuePairs.get(name);\n\t\tif (result == null) {\n\t\t\tthrow new JSONException(\"No value for \" + name);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name}, or null if no such mapping exists.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic Object opt(String name) {\n\t\treturn this.nameValuePairs.get(name);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a\n\t * boolean.\n\t */\n\tpublic boolean getBoolean(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"boolean\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean. Returns false otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic boolean optBoolean(String name) {\n\t\treturn optBoolean(name, false);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic boolean optBoolean(String name, boolean fallback) {\n\t\tObject object = opt(name);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a\n\t * double.\n\t */\n\tpublic double getDouble(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tDouble result = JSON.toDouble(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"double\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double. Returns {@code NaN} otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code NaN}\n\t */\n\tpublic double optDouble(String name) {\n\t\treturn optDouble(name, Double.NaN);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic double optDouble(String name, double fallback) {\n\t\tObject object = opt(name);\n\t\tDouble result = JSON.toDouble(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to an int.\n\t */\n\tpublic int getInt(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tInteger result = JSON.toInteger(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"int\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int. Returns 0 otherwise.\n\t * @param name the name of the property\n\t * @return the value of {@code 0}\n\t */\n\tpublic int optInt(String name) {\n\t\treturn optInt(name, 0);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic int optInt(String name, int fallback) {\n\t\tObject object = opt(name);\n\t\tInteger result = JSON.toInteger(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Note that JSON represents numbers as doubles, so this is\n\t * <a href=\"#lossy\">lossy</a>; use strings to transfer numbers over JSON.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a long.\n\t */\n\tpublic long getLong(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tLong result = JSON.toLong(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"long\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as\n\t * doubles, so this is <a href=\"#lossy\">lossy</a>; use strings to transfer numbers via\n\t * JSON.\n\t * @param name the name of the property\n\t * @return the value or {@code 0L}\n\t */\n\tpublic long optLong(String name) {\n\t\treturn optLong(name, 0L);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents\n\t * numbers as doubles, so this is <a href=\"#lossy\">lossy</a>; use strings to transfer\n\t * numbers over JSON.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic long optLong(String name, long fallback) {\n\t\tObject object = opt(name);\n\t\tLong result = JSON.toLong(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if no such mapping exists.\n\t */\n\tpublic String getString(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tString result = JSON.toString(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"String\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * Returns the empty string if no such mapping exists.\n\t * @param name the name of the property\n\t * @return the value or an empty string\n\t */\n\tpublic String optString(String name) {\n\t\treturn optString(name, \"\");\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * Returns {@code fallback} if no such mapping exists.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic String optString(String name, String fallback) {\n\t\tObject object = opt(name);\n\t\tString result = JSON.toString(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONArray}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or is not a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray getJSONArray(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tif (object instanceof JSONArray) {\n\t\t\treturn (JSONArray) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(name, object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONArray}. Returns null otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic JSONArray optJSONArray(String name) {\n\t\tObject object = opt(name);\n\t\treturn object instanceof JSONArray ? (JSONArray) object : null;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONObject}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or is not a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject getJSONObject(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tif (object instanceof JSONObject) {\n\t\t\treturn (JSONObject) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(name, object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONObject}. Returns null otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic JSONObject optJSONObject(String name) {\n\t\tObject object = opt(name);\n\t\treturn object instanceof JSONObject ? (JSONObject) object : null;\n\t}\n\n\t/**\n\t * Returns an array with the values corresponding to {@code names}. The array contains\n\t * null for names that aren't mapped. This method returns null if {@code names} is\n\t * either null or empty.\n\t * @param names the names of the properties\n\t * @return the array\n\t */\n\tpublic JSONArray toJSONArray(JSONArray names) {\n\t\tJSONArray result = new JSONArray();\n\t\tif (names == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint length = names.length();\n\t\tif (length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString name = JSON.toString(names.opt(i));\n\t\t\tresult.put(opt(name));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns an iterator of the {@code String} names in this object. The returned\n\t * iterator supports {@link Iterator#remove() remove}, which will remove the\n\t * corresponding mapping from this object. If this object is modified after the\n\t * iterator is returned, the iterator's behavior is undefined. The order of the keys\n\t * is undefined.\n\t * @return the keys\n\t */\n\t/* Return a raw type for API compatibility */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Iterator keys() {\n\t\treturn this.nameValuePairs.keySet().iterator();\n\t}\n\n\t/**\n\t * Returns an array containing the string names in this object. This method returns\n\t * null if this object contains no mappings.\n\t * @return the array\n\t */\n\tpublic JSONArray names() {\n\t\treturn this.nameValuePairs.isEmpty() ? null : new JSONArray(new ArrayList<>(this.nameValuePairs.keySet()));\n\t}\n\n\t/**\n\t * Encodes this object as a compact JSON string, such as:\n\t * <pre>{\"query\":\"Pizza\",\"locations\":[94043,90210]}</pre>\n\t * @return a string representation of the object.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\twriteTo(stringer);\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Encodes this object as a human-readable JSON string for debugging, such as: <pre>\n\t * {\n\t *     \"query\": \"Pizza\",\n\t *     \"locations\": [\n\t *         94043,\n\t *         90210\n\t *     ]\n\t * }</pre>\n\t * @param indentSpaces the number of spaces to indent for each level of nesting.\n\t * @return a string representation of the object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic String toString(int indentSpaces) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer(indentSpaces);\n\t\twriteTo(stringer);\n\t\treturn stringer.toString();\n\t}\n\n\tvoid writeTo(JSONStringer stringer) throws JSONException {\n\t\tstringer.object();\n\t\tfor (Map.Entry<String, Object> entry : this.nameValuePairs.entrySet()) {\n\t\t\tstringer.key(entry.getKey()).value(entry.getValue());\n\t\t}\n\t\tstringer.endObject();\n\t}\n\n\t/**\n\t * Encodes the number as a JSON string.\n\t * @param number a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return the encoded value\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic static String numberToString(Number number) throws JSONException {\n\t\tif (number == null) {\n\t\t\tthrow new JSONException(\"Number must be non-null\");\n\t\t}\n\n\t\tdouble doubleValue = number.doubleValue();\n\t\tJSON.checkDouble(doubleValue);\n\n\t\t// the original returns \"-0\" instead of \"-0.0\" for negative zero\n\t\tif (number.equals(NEGATIVE_ZERO)) {\n\t\t\treturn \"-0\";\n\t\t}\n\n\t\tlong longValue = number.longValue();\n\t\tif (doubleValue == longValue) {\n\t\t\treturn Long.toString(longValue);\n\t\t}\n\n\t\treturn number.toString();\n\t}\n\n\t/**\n\t * Encodes {@code data} as a JSON string. This applies quotes and any necessary\n\t * character escaping.\n\t * @param data the string to encode. Null will be interpreted as an empty string.\n\t * @return the quoted value\n\t */\n\tpublic static String quote(String data) {\n\t\tif (data == null) {\n\t\t\treturn \"\\\"\\\"\";\n\t\t}\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\tstringer.open(JSONStringer.Scope.NULL, \"\");\n\t\t\tstringer.value(data);\n\t\t\tstringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, \"\");\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\tthrow new AssertionError();\n\t\t}\n\t}\n\n\t/**\n\t * Wraps the given object if necessary.\n\t * <p>\n\t * If the object is null or, returns {@link #NULL}. If the object is a\n\t * {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. If the object is\n\t * {@code NULL}, no wrapping is necessary. If the object is an array or\n\t * {@code Collection}, returns an equivalent {@code JSONArray}. If the object is a\n\t * {@code Map}, returns an equivalent {@code JSONObject}. If the object is a primitive\n\t * wrapper type or {@code String}, returns the object. Otherwise if the object is from\n\t * a {@code java} package, returns the result of {@code toString}. If wrapping fails,\n\t * returns null.\n\t * @param o the object to wrap\n\t * @return the wrapped object\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Object wrap(Object o) {\n\t\tif (o == null) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif (o instanceof JSONArray || o instanceof JSONObject) {\n\t\t\treturn o;\n\t\t}\n\t\tif (o.equals(NULL)) {\n\t\t\treturn o;\n\t\t}\n\t\ttry {\n\t\t\tif (o instanceof Collection) {\n\t\t\t\treturn new JSONArray((Collection) o);\n\t\t\t}\n\t\t\telse if (o.getClass().isArray()) {\n\t\t\t\treturn new JSONArray(o);\n\t\t\t}\n\t\t\tif (o instanceof Map) {\n\t\t\t\treturn new JSONObject((Map) o);\n\t\t\t}\n\t\t\tif (o instanceof Boolean || o instanceof Byte || o instanceof Character || o instanceof Double\n\t\t\t\t\t|| o instanceof Float || o instanceof Integer || o instanceof Long || o instanceof Short\n\t\t\t\t\t|| o instanceof String) {\n\t\t\t\treturn o;\n\t\t\t}\n\t\t\tif (o.getClass().getPackage().getName().startsWith(\"java.\")) {\n\t\t\t\treturn o.toString();\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/java/org/springframework/boot/configurationmetadata/json/JSONStringer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.json;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most application\n * developers should use those methods directly and disregard this API. For example:<pre>\n * JSONObject object = ...\n * String json = object.toString();</pre>\n * <p>\n * Stringers only encode well-formed JSON strings. In particular:\n * <ul>\n * <li>The stringer must have exactly one top-level array or object.\n * <li>Lexical scopes must be balanced: every call to {@link #array} must have a matching\n * call to {@link #endArray} and every call to {@link #object} must have a matching call\n * to {@link #endObject}.\n * <li>Arrays may not contain keys (property names).\n * <li>Objects must alternate keys (property names) and values.\n * <li>Values are inserted with either literal {@link #value(Object) value} calls, or by\n * nesting arrays or objects.\n * </ul>\n * Calls that would result in a malformed JSON string will fail with a\n * {@link JSONException}.\n * <p>\n * This class provides no facility for pretty-printing (ie. indenting) output. To encode\n * indented output, use {@link JSONObject#toString(int)} or\n * {@link JSONArray#toString(int)}.\n * <p>\n * Some implementations of the API support at most 20 levels of nesting. Attempts to\n * create more than 20 levels of nesting may fail with a {@link JSONException}.\n * <p>\n * Each stringer may be used to encode a single top level value. Instances of this class\n * are not thread safe. Although this class is nonfinal, it was not designed for\n * inheritance and should not be subclassed. In particular, self-use by overrideable\n * methods is not specified. See <i>Effective Java</i> Item 17, \"Design and Document or\n * inheritance or else prohibit it\" for further information.\n */\npublic class JSONStringer {\n\n\t/**\n\t * The output data, containing at most one top-level array or object.\n\t */\n\tfinal StringBuilder out = new StringBuilder();\n\n\t/**\n\t * Lexical scoping elements within this stringer, necessary to insert the appropriate\n\t * separator characters (i.e. commas and colons) and to detect nesting errors.\n\t */\n\tenum Scope {\n\n\t\t/**\n\t\t * An array with no elements requires no separators or newlines before it is\n\t\t * closed.\n\t\t */\n\t\tEMPTY_ARRAY,\n\n\t\t/**\n\t\t * An array with at least one value requires a comma and newline before the next\n\t\t * element.\n\t\t */\n\t\tNONEMPTY_ARRAY,\n\n\t\t/**\n\t\t * An object with no keys or values requires no separators or newlines before it\n\t\t * is closed.\n\t\t */\n\t\tEMPTY_OBJECT,\n\n\t\t/**\n\t\t * An object whose most recent element is a key. The next element must be a value.\n\t\t */\n\t\tDANGLING_KEY,\n\n\t\t/**\n\t\t * An object with at least one name/value pair requires a comma and newline before\n\t\t * the next element.\n\t\t */\n\t\tNONEMPTY_OBJECT,\n\n\t\t/**\n\t\t * A special bracketless array needed by JSONStringer.join() and\n\t\t * JSONObject.quote() only. Not used for JSON encoding.\n\t\t */\n\t\tNULL\n\n\t}\n\n\t/**\n\t * Unlike the original implementation, this stack isn't limited to 20 levels of\n\t * nesting.\n\t */\n\tprivate final List<Scope> stack = new ArrayList<>();\n\n\t/**\n\t * A string containing a full set of spaces for a single level of indentation, or null\n\t * for no pretty printing.\n\t */\n\tprivate final String indent;\n\n\tpublic JSONStringer() {\n\t\tthis.indent = null;\n\t}\n\n\tJSONStringer(int indentSpaces) {\n\t\tchar[] indentChars = new char[indentSpaces];\n\t\tArrays.fill(indentChars, ' ');\n\t\tthis.indent = new String(indentChars);\n\t}\n\n\t/**\n\t * Begins encoding a new array. Each call to this method must be paired with a call to\n\t * {@link #endArray}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer array() throws JSONException {\n\t\treturn open(Scope.EMPTY_ARRAY, \"[\");\n\t}\n\n\t/**\n\t * Ends encoding the current array.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer endArray() throws JSONException {\n\t\treturn close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, \"]\");\n\t}\n\n\t/**\n\t * Begins encoding a new object. Each call to this method must be paired with a call\n\t * to {@link #endObject}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer object() throws JSONException {\n\t\treturn open(Scope.EMPTY_OBJECT, \"{\");\n\t}\n\n\t/**\n\t * Ends encoding the current object.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer endObject() throws JSONException {\n\t\treturn close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, \"}\");\n\t}\n\n\t/**\n\t * Enters a new scope by appending any necessary whitespace and the given bracket.\n\t * @param empty any necessary whitespace\n\t * @param openBracket the open bracket\n\t * @return this object\n\t * @throws JSONException if processing of json failed\n\t */\n\tJSONStringer open(Scope empty, String openBracket) throws JSONException {\n\t\tif (this.stack.isEmpty() && !this.out.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem: multiple top-level roots\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.stack.add(empty);\n\t\tthis.out.append(openBracket);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Closes the current scope by appending any necessary whitespace and the given\n\t * bracket.\n\t * @param empty any necessary whitespace\n\t * @param nonempty the current scope\n\t * @param closeBracket the close bracket\n\t * @return the JSON stringer\n\t * @throws JSONException if processing of json failed\n\t */\n\tJSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {\n\t\tScope context = peek();\n\t\tif (context != nonempty && context != empty) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\n\t\tthis.stack.remove(this.stack.size() - 1);\n\t\tif (context == nonempty) {\n\t\t\tnewline();\n\t\t}\n\t\tthis.out.append(closeBracket);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the value on the top of the stack.\n\t * @return the scope\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate Scope peek() throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\treturn this.stack.get(this.stack.size() - 1);\n\t}\n\n\t/**\n\t * Replace the value on the top of the stack with the given value.\n\t * @param topOfStack the scope at the top of the stack\n\t */\n\tprivate void replaceTop(Scope topOfStack) {\n\t\tthis.stack.set(this.stack.size() - 1, topOfStack);\n\t}\n\n\t/**\n\t * Encodes {@code value}.\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double or null. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(Object value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\n\t\tif (value instanceof JSONArray) {\n\t\t\t((JSONArray) value).writeTo(this);\n\t\t\treturn this;\n\t\t}\n\t\telse if (value instanceof JSONObject) {\n\t\t\t((JSONObject) value).writeTo(this);\n\t\t\treturn this;\n\t\t}\n\n\t\tbeforeValue();\n\n\t\tif (value == null || value instanceof Boolean || value == JSONObject.NULL) {\n\t\t\tthis.out.append(value);\n\n\t\t}\n\t\telse if (value instanceof Number) {\n\t\t\tthis.out.append(JSONObject.numberToString((Number) value));\n\n\t\t}\n\t\telse {\n\t\t\tstring(value.toString());\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value the value to encode\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(boolean value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(double value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(JSONObject.numberToString(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value the value to encode\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(long value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(value);\n\t\treturn this;\n\t}\n\n\tprivate void string(String value) {\n\t\tthis.out.append(\"\\\"\");\n\t\tfor (int i = 0, length = value.length(); i < length; i++) {\n\t\t\tchar c = value.charAt(i);\n\n\t\t\t/*\n\t\t\t * From RFC 4627, \"All Unicode characters may be placed within the quotation\n\t\t\t * marks except for the characters that must be escaped: quotation mark,\n\t\t\t * reverse solidus, and the control characters (U+0000 through U+001F).\"\n\t\t\t */\n\t\t\tswitch (c) {\n\t\t\t\tcase '\"', '\\\\', '/' -> this.out.append('\\\\').append(c);\n\t\t\t\tcase '\\t' -> this.out.append(\"\\\\t\");\n\t\t\t\tcase '\\b' -> this.out.append(\"\\\\b\");\n\t\t\t\tcase '\\n' -> this.out.append(\"\\\\n\");\n\t\t\t\tcase '\\r' -> this.out.append(\"\\\\r\");\n\t\t\t\tcase '\\f' -> this.out.append(\"\\\\f\");\n\t\t\t\tdefault -> {\n\t\t\t\t\tif (c <= 0x1F) {\n\t\t\t\t\t\tthis.out.append(String.format(\"\\\\u%04x\", (int) c));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.out.append(c);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tthis.out.append(\"\\\"\");\n\t}\n\n\tprivate void newline() {\n\t\tif (this.indent == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.out.append(\"\\n\");\n\t\tthis.out.append(this.indent.repeat(this.stack.size()));\n\t}\n\n\t/**\n\t * Encodes the key (property name) to this stringer.\n\t * @param name the name of the forthcoming value. May not be null.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer key(String name) throws JSONException {\n\t\tif (name == null) {\n\t\t\tthrow new JSONException(\"Names must be non-null\");\n\t\t}\n\t\tbeforeKey();\n\t\tstring(name);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Inserts any necessary separators and whitespace before a name. Also adjusts the\n\t * stack to expect the key's value.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate void beforeKey() throws JSONException {\n\t\tScope context = peek();\n\t\tif (context == Scope.NONEMPTY_OBJECT) { // first in object\n\t\t\tthis.out.append(',');\n\t\t}\n\t\telse if (context != Scope.EMPTY_OBJECT) { // not in an object!\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tnewline();\n\t\treplaceTop(Scope.DANGLING_KEY);\n\t}\n\n\t/**\n\t * Inserts any necessary separators and whitespace before a literal value, inline\n\t * array, or inline object. Also adjusts the stack to expect either a closing bracket\n\t * or another element.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate void beforeValue() throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\n\t\tScope context = peek();\n\t\tif (context == Scope.EMPTY_ARRAY) { // first in array\n\t\t\treplaceTop(Scope.NONEMPTY_ARRAY);\n\t\t\tnewline();\n\t\t}\n\t\telse if (context == Scope.NONEMPTY_ARRAY) { // another in array\n\t\t\tthis.out.append(',');\n\t\t\tnewline();\n\t\t}\n\t\telse if (context == Scope.DANGLING_KEY) { // value for key\n\t\t\tthis.out.append(this.indent == null ? \":\" : \": \");\n\t\t\treplaceTop(Scope.NONEMPTY_OBJECT);\n\t\t}\n\t\telse if (context != Scope.NULL) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the encoded JSON string.\n\t * <p>\n\t * If invoked with unterminated arrays or unclosed objects, this method's return value\n\t * is undefined.\n\t * <p>\n\t * <strong>Warning:</strong> although it contradicts the general contract of\n\t * {@link Object#toString}, this method returns null if the stringer contains no data.\n\t * @return the encoded JSON string.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn this.out.isEmpty() ? null : this.out.toString();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/json-shade/java/org/springframework/boot/configurationmetadata/json/JSONTokener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.json;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Parses a JSON (<a href=\"https://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>) encoded\n * string into the corresponding object. Most clients of this class will use only need the\n * {@link #JSONTokener(String) constructor} and {@link #nextValue} method. Example usage:\n * <pre>\n * String json = \"{\"\n *         + \"  \\\"query\\\": \\\"Pizza\\\", \"\n *         + \"  \\\"locations\\\": [ 94043, 90210 ] \"\n *         + \"}\";\n *\n * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();\n * String query = object.getString(\"query\");\n * JSONArray locations = object.getJSONArray(\"locations\");</pre>\n * <p>\n * For best interoperability and performance use JSON that complies with RFC 4627, such as\n * that generated by {@link JSONStringer}. For legacy reasons this parser is lenient, so a\n * successful parse does not indicate that the input string was valid JSON. All the\n * following syntax errors will be ignored:\n * <ul>\n * <li>End of line comments starting with {@code //} or {@code #} and ending with a\n * newline character.\n * <li>C-style comments starting with {@code /*} and ending with {@code *}{@code /}. Such\n * comments may not be nested.\n * <li>Strings that are unquoted or {@code 'single quoted'}.\n * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.\n * <li>Octal integers prefixed with {@code 0}.\n * <li>Array elements separated by {@code ;}.\n * <li>Unnecessary array separators. These are interpreted as if null was the omitted\n * value.\n * <li>Key-value pairs separated by {@code =} or {@code =>}.\n * <li>Key-value pairs separated by {@code ;}.\n * </ul>\n * <p>\n * Each tokener may be used to parse a single JSON string. Instances of this class are not\n * thread safe. Although this class is nonfinal, it was not designed for inheritance and\n * should not be subclassed. In particular, self-use by overrideable methods is not\n * specified. See <i>Effective Java</i> Item 17, \"Design and Document or inheritance or\n * else prohibit it\" for further information.\n */\npublic class JSONTokener {\n\n\t/**\n\t * The input JSON.\n\t */\n\tprivate final String in;\n\n\t/**\n\t * The index of the next character to be returned by {@link #next}. When the input is\n\t * exhausted, this equals the input's length.\n\t */\n\tprivate int pos;\n\n\t/**\n\t * @param in JSON encoded string. Null is not permitted and will yield a tokener that\n\t * throws {@code NullPointerExceptions} when methods are called.\n\t */\n\tpublic JSONTokener(String in) {\n\t\t// consume an optional byte order mark (BOM) if it exists\n\t\tif (in != null && in.startsWith(\"\\ufeff\")) {\n\t\t\tin = in.substring(1);\n\t\t}\n\t\tthis.in = in;\n\t}\n\n\t/**\n\t * Returns the next value from the input.\n\t * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,\n\t * Double or {@link JSONObject#NULL}.\n\t * @throws JSONException if the input is malformed.\n\t */\n\tpublic Object nextValue() throws JSONException {\n\t\tint c = nextCleanInternal();\n\t\tswitch (c) {\n\t\t\tcase -1:\n\t\t\t\tthrow syntaxError(\"End of input\");\n\n\t\t\tcase '{':\n\t\t\t\treturn readObject();\n\n\t\t\tcase '[':\n\t\t\t\treturn readArray();\n\n\t\t\tcase '\\'', '\"':\n\t\t\t\treturn nextString((char) c);\n\n\t\t\tdefault:\n\t\t\t\tthis.pos--;\n\t\t\t\treturn readLiteral();\n\t\t}\n\t}\n\n\tprivate int nextCleanInternal() throws JSONException {\n\t\twhile (this.pos < this.in.length()) {\n\t\t\tint c = this.in.charAt(this.pos++);\n\t\t\tswitch (c) {\n\t\t\t\tcase '\\t', ' ', '\\n', '\\r':\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcase '/':\n\t\t\t\t\tif (this.pos == this.in.length()) {\n\t\t\t\t\t\treturn c;\n\t\t\t\t\t}\n\n\t\t\t\t\tchar peek = this.in.charAt(this.pos);\n\t\t\t\t\tswitch (peek) {\n\t\t\t\t\t\tcase '*':\n\t\t\t\t\t\t\t// skip a /* c-style comment */\n\t\t\t\t\t\t\tthis.pos++;\n\t\t\t\t\t\t\tint commentEnd = this.in.indexOf(\"*/\", this.pos);\n\t\t\t\t\t\t\tif (commentEnd == -1) {\n\t\t\t\t\t\t\t\tthrow syntaxError(\"Unterminated comment\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.pos = commentEnd + 2;\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tcase '/':\n\t\t\t\t\t\t\t// skip a // end-of-line comment\n\t\t\t\t\t\t\tthis.pos++;\n\t\t\t\t\t\t\tskipToEndOfLine();\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn c;\n\t\t\t\t\t}\n\n\t\t\t\tcase '#':\n\t\t\t\t\t/*\n\t\t\t\t\t * Skip a # hash end-of-line comment. The JSON RFC doesn't specify\n\t\t\t\t\t * this behavior, but it's required to parse existing documents. See\n\t\t\t\t\t * https://b/2571423.\n\t\t\t\t\t */\n\t\t\t\t\tskipToEndOfLine();\n\t\t\t\t\tcontinue;\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn c;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Advances the position until after the next newline character. If the line is\n\t * terminated by \"\\r\\n\", the '\\n' must be consumed as whitespace by the caller.\n\t */\n\tprivate void skipToEndOfLine() {\n\t\tfor (; this.pos < this.in.length(); this.pos++) {\n\t\t\tchar c = this.in.charAt(this.pos);\n\t\t\tif (c == '\\r' || c == '\\n') {\n\t\t\t\tthis.pos++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the string up to but not including {@code quote}, unescaping any character\n\t * escape sequences encountered along the way. The opening quote should have already\n\t * been read. This consumes the closing quote, but does not include it in the returned\n\t * string.\n\t * @param quote either ' or \".\n\t * @return the string up to but not including {@code quote}\n\t * @throws NumberFormatException if any unicode escape sequences are malformed.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String nextString(char quote) throws JSONException {\n\t\t/*\n\t\t * For strings that are free of escape sequences, we can just extract the result\n\t\t * as a substring of the input. But if we encounter an escape sequence, we need to\n\t\t * use a StringBuilder to compose the result.\n\t\t */\n\t\tStringBuilder builder = null;\n\n\t\t/* the index of the first character not yet appended to the builder. */\n\t\tint start = this.pos;\n\n\t\twhile (this.pos < this.in.length()) {\n\t\t\tint c = this.in.charAt(this.pos++);\n\t\t\tif (c == quote) {\n\t\t\t\tif (builder == null) {\n\t\t\t\t\t// a new string avoids leaking memory\n\t\t\t\t\treturn new String(this.in.substring(start, this.pos - 1));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuilder.append(this.in, start, this.pos - 1);\n\t\t\t\t\treturn builder.toString();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (c == '\\\\') {\n\t\t\t\tif (this.pos == this.in.length()) {\n\t\t\t\t\tthrow syntaxError(\"Unterminated escape sequence\");\n\t\t\t\t}\n\t\t\t\tif (builder == null) {\n\t\t\t\t\tbuilder = new StringBuilder();\n\t\t\t\t}\n\t\t\t\tbuilder.append(this.in, start, this.pos - 1);\n\t\t\t\tbuilder.append(readEscapeCharacter());\n\t\t\t\tstart = this.pos;\n\t\t\t}\n\t\t}\n\n\t\tthrow syntaxError(\"Unterminated string\");\n\t}\n\n\t/**\n\t * Unescapes the character identified by the character or characters that immediately\n\t * follow a backslash. The backslash '\\' should have already been read. This supports\n\t * both unicode escapes \"u000A\" and two-character escapes \"\\n\".\n\t * @return the unescaped char\n\t * @throws NumberFormatException if any unicode escape sequences are malformed.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate char readEscapeCharacter() throws JSONException {\n\t\tchar escaped = this.in.charAt(this.pos++);\n\t\tswitch (escaped) {\n\t\t\tcase 'u':\n\t\t\t\tif (this.pos + 4 > this.in.length()) {\n\t\t\t\t\tthrow syntaxError(\"Unterminated escape sequence\");\n\t\t\t\t}\n\t\t\t\tString hex = this.in.substring(this.pos, this.pos + 4);\n\t\t\t\tthis.pos += 4;\n\t\t\t\treturn (char) Integer.parseInt(hex, 16);\n\n\t\t\tcase 't':\n\t\t\t\treturn '\\t';\n\n\t\t\tcase 'b':\n\t\t\t\treturn '\\b';\n\n\t\t\tcase 'n':\n\t\t\t\treturn '\\n';\n\n\t\t\tcase 'r':\n\t\t\t\treturn '\\r';\n\n\t\t\tcase 'f':\n\t\t\t\treturn '\\f';\n\n\t\t\tcase '\\'', '\"', '\\\\':\n\t\t\tdefault:\n\t\t\t\treturn escaped;\n\t\t}\n\t}\n\n\t/**\n\t * Reads a null, boolean, numeric or unquoted string literal value. Numeric values\n\t * will be returned as an Integer, Long, or Double, in that order of preference.\n\t * @return a literal value\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate Object readLiteral() throws JSONException {\n\t\tString literal = nextToInternal(\"{}[]/\\\\:,=;# \\t\\f\");\n\n\t\tif (literal.isEmpty()) {\n\t\t\tthrow syntaxError(\"Expected literal value\");\n\t\t}\n\t\telse if (\"null\".equalsIgnoreCase(literal)) {\n\t\t\treturn JSONObject.NULL;\n\t\t}\n\t\telse if (\"true\".equalsIgnoreCase(literal)) {\n\t\t\treturn Boolean.TRUE;\n\t\t}\n\t\telse if (\"false\".equalsIgnoreCase(literal)) {\n\t\t\treturn Boolean.FALSE;\n\t\t}\n\n\t\t/* try to parse as an integral type... */\n\t\tif (literal.indexOf('.') == -1) {\n\t\t\tint base = 10;\n\t\t\tString number = literal;\n\t\t\tif (number.startsWith(\"0x\") || number.startsWith(\"0X\")) {\n\t\t\t\tnumber = number.substring(2);\n\t\t\t\tbase = 16;\n\t\t\t}\n\t\t\telse if (number.startsWith(\"0\") && number.length() > 1) {\n\t\t\t\tnumber = number.substring(1);\n\t\t\t\tbase = 8;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tlong longValue = Long.parseLong(number, base);\n\t\t\t\tif (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {\n\t\t\t\t\treturn (int) longValue;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn longValue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (NumberFormatException e) {\n\t\t\t\t/*\n\t\t\t\t * This only happens for integral numbers greater than Long.MAX_VALUE,\n\t\t\t\t * numbers in exponential form (5e-10) and unquoted strings. Fall through\n\t\t\t\t * to try floating point.\n\t\t\t\t */\n\t\t\t}\n\t\t}\n\n\t\t/* ...next try to parse as a floating point... */\n\t\ttry {\n\t\t\treturn Double.valueOf(literal);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\t// Ignore\n\t\t}\n\n\t\t/* ... finally give up. We have an unquoted string */\n\t\treturn new String(literal); // a new string avoids leaking memory\n\t}\n\n\t/**\n\t * Returns the string up to but not including any of the given characters or a newline\n\t * character. This does not consume the excluded character.\n\t * @return the string up to but not including any of the given characters or a newline\n\t * character\n\t */\n\tprivate String nextToInternal(String excluded) {\n\t\tint start = this.pos;\n\t\tfor (; this.pos < this.in.length(); this.pos++) {\n\t\t\tchar c = this.in.charAt(this.pos);\n\t\t\tif (c == '\\r' || c == '\\n' || excluded.indexOf(c) != -1) {\n\t\t\t\treturn this.in.substring(start, this.pos);\n\t\t\t}\n\t\t}\n\t\treturn this.in.substring(start);\n\t}\n\n\t/**\n\t * Reads a sequence of key/value pairs and the trailing closing brace '}' of an\n\t * object. The opening brace '{' should have already been read.\n\t * @return an object\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate JSONObject readObject() throws JSONException {\n\t\tJSONObject result = new JSONObject();\n\n\t\t/* Peek to see if this is the empty object. */\n\t\tint first = nextCleanInternal();\n\t\tif (first == '}') {\n\t\t\treturn result;\n\t\t}\n\t\telse if (first != -1) {\n\t\t\tthis.pos--;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tObject name = nextValue();\n\t\t\tif (!(name instanceof String)) {\n\t\t\t\tif (name == null) {\n\t\t\t\t\tthrow syntaxError(\"Names cannot be null\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow syntaxError(\n\t\t\t\t\t\t\t\"Names must be strings, but \" + name + \" is of type \" + name.getClass().getName());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Expect the name/value separator to be either a colon ':', an equals sign\n\t\t\t * '=', or an arrow \"=>\". The last two are bogus but we include them because\n\t\t\t * that's what the original implementation did.\n\t\t\t */\n\t\t\tint separator = nextCleanInternal();\n\t\t\tif (separator != ':' && separator != '=') {\n\t\t\t\tthrow syntaxError(\"Expected ':' after \" + name);\n\t\t\t}\n\t\t\tif (this.pos < this.in.length() && this.in.charAt(this.pos) == '>') {\n\t\t\t\tthis.pos++;\n\t\t\t}\n\n\t\t\tresult.put((String) name, nextValue());\n\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase '}':\n\t\t\t\t\treturn result;\n\t\t\t\tcase ';', ',':\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow syntaxError(\"Unterminated object\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reads a sequence of values and the trailing closing brace ']' of an array. The\n\t * opening brace '[' should have already been read. Note that \"[]\" yields an empty\n\t * array, but \"[,]\" returns a two-element array equivalent to \"[null,null]\".\n\t * @return an array\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate JSONArray readArray() throws JSONException {\n\t\tJSONArray result = new JSONArray();\n\n\t\t/* to cover input that ends with \",]\". */\n\t\tboolean hasTrailingSeparator = false;\n\n\t\twhile (true) {\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase -1:\n\t\t\t\t\tthrow syntaxError(\"Unterminated array\");\n\t\t\t\tcase ']':\n\t\t\t\t\tif (hasTrailingSeparator) {\n\t\t\t\t\t\tresult.put(null);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\tcase ',', ';':\n\t\t\t\t\t/* A separator without a value first means \"null\". */\n\t\t\t\t\tresult.put(null);\n\t\t\t\t\thasTrailingSeparator = true;\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.pos--;\n\t\t\t}\n\n\t\t\tresult.put(nextValue());\n\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase ']':\n\t\t\t\t\treturn result;\n\t\t\t\tcase ',', ';':\n\t\t\t\t\thasTrailingSeparator = true;\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow syntaxError(\"Unterminated array\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns an exception containing the given message plus the current position and the\n\t * entire input string.\n\t * @param message the message\n\t * @return an exception\n\t */\n\tpublic JSONException syntaxError(String message) {\n\t\treturn new JSONException(message + this);\n\t}\n\n\t/**\n\t * Returns the current position and the entire input string.\n\t * @return the current position and the entire input string.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\t// consistent with the original implementation\n\t\treturn \" at character \" + this.pos + \" of \" + this.in;\n\t}\n\n\t/*\n\t * Legacy APIs.\n\t *\n\t * None of the methods below are on the critical path of parsing JSON documents. They\n\t * exist only because they were exposed by the original implementation and may be used\n\t * by some clients.\n\t */\n\n\tpublic boolean more() {\n\t\treturn this.pos < this.in.length();\n\t}\n\n\tpublic char next() {\n\t\treturn this.pos < this.in.length() ? this.in.charAt(this.pos++) : '\\0';\n\t}\n\n\tpublic char next(char c) throws JSONException {\n\t\tchar result = next();\n\t\tif (result != c) {\n\t\t\tthrow syntaxError(\"Expected \" + c + \" but was \" + result);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic char nextClean() throws JSONException {\n\t\tint nextCleanInt = nextCleanInternal();\n\t\treturn nextCleanInt == -1 ? '\\0' : (char) nextCleanInt;\n\t}\n\n\tpublic String next(int length) throws JSONException {\n\t\tif (this.pos + length > this.in.length()) {\n\t\t\tthrow syntaxError(length + \" is out of bounds\");\n\t\t}\n\t\tString result = this.in.substring(this.pos, this.pos + length);\n\t\tthis.pos += length;\n\t\treturn result;\n\t}\n\n\tpublic String nextTo(String excluded) {\n\t\tif (excluded == null) {\n\t\t\tthrow new NullPointerException(\"excluded == null\");\n\t\t}\n\t\treturn nextToInternal(excluded).trim();\n\t}\n\n\tpublic String nextTo(char excluded) {\n\t\treturn nextToInternal(String.valueOf(excluded)).trim();\n\t}\n\n\tpublic void skipPast(String thru) {\n\t\tint thruStart = this.in.indexOf(thru, this.pos);\n\t\tthis.pos = thruStart == -1 ? this.in.length() : (thruStart + thru.length());\n\t}\n\n\tpublic char skipTo(char to) {\n\t\tint index = this.in.indexOf(to, this.pos);\n\t\tif (index != -1) {\n\t\t\tthis.pos = index;\n\t\t\treturn to;\n\t\t}\n\t\telse {\n\t\t\treturn '\\0';\n\t\t}\n\t}\n\n\tpublic void back() {\n\t\tif (--this.pos == -1) {\n\t\t\tthis.pos = 0;\n\t\t}\n\t}\n\n\tpublic static int dehexchar(char hex) {\n\t\tif (hex >= '0' && hex <= '9') {\n\t\t\treturn hex - '0';\n\t\t}\n\t\telse if (hex >= 'A' && hex <= 'F') {\n\t\t\treturn hex - 'A' + 10;\n\t\t}\n\t\telse if (hex >= 'a' && hex <= 'f') {\n\t\t\treturn hex - 'a' + 10;\n\t\t}\n\t\telse {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Gather a collection of {@link ConfigurationMetadataProperty properties} that are\n * sharing a {@link #getId() common prefix}. Provide access to all the\n * {@link ConfigurationMetadataSource sources} that have contributed properties to the\n * group.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class ConfigurationMetadataGroup implements Serializable {\n\n\tprivate final String id;\n\n\tprivate final Map<String, ConfigurationMetadataSource> sources = new HashMap<>();\n\n\tprivate final Map<String, ConfigurationMetadataProperty> properties = new HashMap<>();\n\n\tpublic ConfigurationMetadataGroup(String id) {\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * Return the id of the group, used as a common prefix for all properties associated\n\t * to it.\n\t * @return the id of the group\n\t */\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\t/**\n\t * Return the {@link ConfigurationMetadataSource sources} defining the properties of\n\t * this group.\n\t * @return the sources of the group\n\t */\n\tpublic Map<String, ConfigurationMetadataSource> getSources() {\n\t\treturn this.sources;\n\t}\n\n\t/**\n\t * Return the {@link ConfigurationMetadataProperty properties} defined in this group.\n\t * <p>\n\t * A property may appear more than once for a given source, potentially with\n\t * conflicting type or documentation. This is a \"merged\" view of the properties of\n\t * this group.\n\t * @return the properties of the group\n\t * @see ConfigurationMetadataSource#getProperties()\n\t */\n\tpublic Map<String, ConfigurationMetadataProperty> getProperties() {\n\t\treturn this.properties;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataHint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * A raw view of a hint used for parsing only.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationMetadataHint {\n\n\tprivate static final String KEY_SUFFIX = \".keys\";\n\n\tprivate static final String VALUE_SUFFIX = \".values\";\n\n\tprivate String id;\n\n\tprivate final List<ValueHint> valueHints = new ArrayList<>();\n\n\tprivate final List<ValueProvider> valueProviders = new ArrayList<>();\n\n\tboolean isMapKeyHints() {\n\t\treturn (this.id != null && this.id.endsWith(KEY_SUFFIX));\n\t}\n\n\tboolean isMapValueHints() {\n\t\treturn (this.id != null && this.id.endsWith(VALUE_SUFFIX));\n\t}\n\n\tString resolveId() {\n\t\tif (isMapKeyHints()) {\n\t\t\treturn this.id.substring(0, this.id.length() - KEY_SUFFIX.length());\n\t\t}\n\t\tif (isMapValueHints()) {\n\t\t\treturn this.id.substring(0, this.id.length() - VALUE_SUFFIX.length());\n\t\t}\n\t\treturn this.id;\n\t}\n\n\tString getId() {\n\t\treturn this.id;\n\t}\n\n\tvoid setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tList<ValueHint> getValueHints() {\n\t\treturn this.valueHints;\n\t}\n\n\tList<ValueProvider> getValueProviders() {\n\t\treturn this.valueProviders;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataItem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\n/**\n * An extension of {@link ConfigurationMetadataProperty} that provides a reference to its\n * source.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationMetadataItem extends ConfigurationMetadataProperty {\n\n\tprivate String sourceType;\n\n\tprivate String sourceMethod;\n\n\t/**\n\t * The class name of the source that contributed this property. For example, if the\n\t * property was from a class annotated with {@code @ConfigurationProperties} this\n\t * attribute would contain the fully qualified name of that class.\n\t * @return the source type\n\t */\n\tString getSourceType() {\n\t\treturn this.sourceType;\n\t}\n\n\tvoid setSourceType(String sourceType) {\n\t\tthis.sourceType = sourceType;\n\t}\n\n\t/**\n\t * The full name of the method (including parenthesis and argument types) that\n\t * contributed this property. For example, the name of a getter in a\n\t * {@code @ConfigurationProperties} annotated class.\n\t * @return the source method\n\t */\n\tString getSourceMethod() {\n\t\treturn this.sourceMethod;\n\t}\n\n\tvoid setSourceMethod(String sourceMethod) {\n\t\tthis.sourceMethod = sourceMethod;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\n\n/**\n * Define a configuration property. Each property is fully identified by its\n * {@link #getId() id} which is composed of a namespace prefix (the\n * {@link ConfigurationMetadataGroup#getId() group id}), if any and the {@link #getName()\n * name} of the property.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class ConfigurationMetadataProperty implements Serializable {\n\n\tprivate String id;\n\n\tprivate String name;\n\n\tprivate String type;\n\n\tprivate String description;\n\n\tprivate String shortDescription;\n\n\tprivate Object defaultValue;\n\n\tprivate final Hints hints = new Hints();\n\n\tprivate Deprecation deprecation;\n\n\t/**\n\t * The full identifier of the property, in lowercase dashed form (e.g.\n\t * my.group.simple-property)\n\t * @return the property id\n\t */\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * The name of the property, in lowercase dashed form (e.g. simple-property). If this\n\t * item does not belong to any group, the id is returned.\n\t * @return the property name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * The class name of the data type of the property. For example,\n\t * {@code java.lang.String}.\n\t * <p>\n\t * For consistency, the type of a primitive is specified using its wrapper\n\t * counterpart, i.e. {@code boolean} becomes {@code java.lang.Boolean}. If the type\n\t * holds generic information, these are provided as well, i.e. a {@code HashMap} of\n\t * String to Integer would be defined as {@code java.util.HashMap\n\t * <java.lang.String,java.lang.Integer>}.\n\t * <p>\n\t * Note that this class may be a complex type that gets converted from a String as\n\t * values are bound.\n\t * @return the property type\n\t */\n\tpublic String getType() {\n\t\treturn this.type;\n\t}\n\n\tpublic void setType(String type) {\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * A description of the property, if any. Can be multi-lines.\n\t * @return the property description\n\t * @see #getShortDescription()\n\t */\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\t/**\n\t * A single-line, single-sentence description of this property, if any.\n\t * @return the property short description\n\t * @see #getDescription()\n\t */\n\tpublic String getShortDescription() {\n\t\treturn this.shortDescription;\n\t}\n\n\tpublic void setShortDescription(String shortDescription) {\n\t\tthis.shortDescription = shortDescription;\n\t}\n\n\t/**\n\t * The default value, if any.\n\t * @return the default value\n\t */\n\tpublic Object getDefaultValue() {\n\t\treturn this.defaultValue;\n\t}\n\n\tpublic void setDefaultValue(Object defaultValue) {\n\t\tthis.defaultValue = defaultValue;\n\t}\n\n\t/**\n\t * Return the hints of this item.\n\t * @return the hints\n\t */\n\tpublic Hints getHints() {\n\t\treturn this.hints;\n\t}\n\n\t/**\n\t * The {@link Deprecation} for this property, if any.\n\t * @return the deprecation\n\t * @see #isDeprecated()\n\t */\n\tpublic Deprecation getDeprecation() {\n\t\treturn this.deprecation;\n\t}\n\n\tpublic void setDeprecation(Deprecation deprecation) {\n\t\tthis.deprecation = deprecation;\n\t}\n\n\t/**\n\t * Specify if the property is deprecated.\n\t * @return if the property is deprecated\n\t * @see #getDeprecation()\n\t */\n\tpublic boolean isDeprecated() {\n\t\treturn this.deprecation != null;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.util.Map;\n\n/**\n * A repository of configuration metadata.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\npublic interface ConfigurationMetadataRepository {\n\n\t/**\n\t * Defines the name of the \"root\" group, that is the group that gathers all the\n\t * properties that aren't attached to a specific group.\n\t */\n\tString ROOT_GROUP = \"_ROOT_GROUP_\";\n\n\t/**\n\t * Return the groups, indexed by id.\n\t * @return all configuration meta-data groups\n\t */\n\tMap<String, ConfigurationMetadataGroup> getAllGroups();\n\n\t/**\n\t * Return the properties, indexed by id.\n\t * @return all configuration meta-data properties\n\t */\n\tMap<String, ConfigurationMetadataProperty> getAllProperties();\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataRepositoryJsonBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Load a {@link ConfigurationMetadataRepository} from the content of arbitrary\n * resource(s).\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\npublic final class ConfigurationMetadataRepositoryJsonBuilder {\n\n\tprivate final Charset defaultCharset;\n\n\tprivate final JsonReader reader = new JsonReader();\n\n\tprivate final List<SimpleConfigurationMetadataRepository> repositories = new ArrayList<>();\n\n\tprivate ConfigurationMetadataRepositoryJsonBuilder(Charset defaultCharset) {\n\t\tthis.defaultCharset = defaultCharset;\n\t}\n\n\t/**\n\t * Add the content of a {@link ConfigurationMetadataRepository} defined by the\n\t * specified {@link InputStream} JSON document using the default charset. If this\n\t * metadata repository holds items that were loaded previously, these are ignored.\n\t * <p>\n\t * Leaves the stream open when done.\n\t * @param inputStream the source input stream\n\t * @return this builder\n\t * @throws IOException in case of I/O errors\n\t */\n\tpublic ConfigurationMetadataRepositoryJsonBuilder withJsonResource(InputStream inputStream) throws IOException {\n\t\treturn withJsonResource(inputStream, this.defaultCharset);\n\t}\n\n\t/**\n\t * Add the content of a {@link ConfigurationMetadataRepository} defined by the\n\t * specified {@link InputStream} JSON document using the specified {@link Charset}. If\n\t * this metadata repository holds items that were loaded previously, these are\n\t * ignored.\n\t * <p>\n\t * Leaves the stream open when done.\n\t * @param inputStream the source input stream\n\t * @param charset the charset of the input\n\t * @return this builder\n\t * @throws IOException in case of I/O errors\n\t */\n\tpublic ConfigurationMetadataRepositoryJsonBuilder withJsonResource(InputStream inputStream, Charset charset)\n\t\t\tthrows IOException {\n\t\tif (inputStream == null) {\n\t\t\tthrow new IllegalArgumentException(\"InputStream must not be null.\");\n\t\t}\n\t\tthis.repositories.add(add(inputStream, charset));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build a {@link ConfigurationMetadataRepository} with the current state of this\n\t * builder.\n\t * @return this builder\n\t */\n\tpublic ConfigurationMetadataRepository build() {\n\t\tSimpleConfigurationMetadataRepository result = new SimpleConfigurationMetadataRepository();\n\t\tfor (SimpleConfigurationMetadataRepository repository : this.repositories) {\n\t\t\tresult.include(repository);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate SimpleConfigurationMetadataRepository add(InputStream in, Charset charset) throws IOException {\n\t\ttry {\n\t\t\tRawConfigurationMetadata metadata = this.reader.read(in, charset);\n\t\t\treturn create(metadata);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow ex;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to read configuration metadata\", ex);\n\t\t}\n\t}\n\n\tprivate SimpleConfigurationMetadataRepository create(RawConfigurationMetadata metadata) {\n\t\tSimpleConfigurationMetadataRepository repository = new SimpleConfigurationMetadataRepository();\n\t\trepository.add(metadata.getSources());\n\t\tfor (ConfigurationMetadataItem item : metadata.getItems()) {\n\t\t\tConfigurationMetadataSource source = metadata.getSource(item);\n\t\t\trepository.add(item, source);\n\t\t}\n\t\tMap<String, ConfigurationMetadataProperty> allProperties = repository.getAllProperties();\n\t\tfor (ConfigurationMetadataHint hint : metadata.getHints()) {\n\t\t\tConfigurationMetadataProperty property = allProperties.get(hint.getId());\n\t\t\tif (property != null) {\n\t\t\t\taddValueHints(property, hint);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tString id = hint.resolveId();\n\t\t\t\tproperty = allProperties.get(id);\n\t\t\t\tif (property != null) {\n\t\t\t\t\tif (hint.isMapKeyHints()) {\n\t\t\t\t\t\taddMapHints(property, hint);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\taddValueHints(property, hint);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn repository;\n\t}\n\n\tprivate void addValueHints(ConfigurationMetadataProperty property, ConfigurationMetadataHint hint) {\n\t\tproperty.getHints().getValueHints().addAll(hint.getValueHints());\n\t\tproperty.getHints().getValueProviders().addAll(hint.getValueProviders());\n\t}\n\n\tprivate void addMapHints(ConfigurationMetadataProperty property, ConfigurationMetadataHint hint) {\n\t\tproperty.getHints().getKeyHints().addAll(hint.getValueHints());\n\t\tproperty.getHints().getKeyProviders().addAll(hint.getValueProviders());\n\t}\n\n\t/**\n\t * Create a new builder instance using {@link StandardCharsets#UTF_8} as the default\n\t * charset and the specified JSON resource.\n\t * @param inputStreams the source input streams\n\t * @return a new {@link ConfigurationMetadataRepositoryJsonBuilder} instance.\n\t * @throws IOException on error\n\t */\n\tpublic static ConfigurationMetadataRepositoryJsonBuilder create(InputStream... inputStreams) throws IOException {\n\t\tConfigurationMetadataRepositoryJsonBuilder builder = create();\n\t\tfor (InputStream inputStream : inputStreams) {\n\t\t\tbuilder = builder.withJsonResource(inputStream);\n\t\t}\n\t\treturn builder;\n\t}\n\n\t/**\n\t * Create a new builder instance using {@link StandardCharsets#UTF_8} as the default\n\t * charset.\n\t * @return a new {@link ConfigurationMetadataRepositoryJsonBuilder} instance.\n\t */\n\tpublic static ConfigurationMetadataRepositoryJsonBuilder create() {\n\t\treturn create(StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * Create a new builder instance using the specified default {@link Charset}.\n\t * @param defaultCharset the default charset to use\n\t * @return a new {@link ConfigurationMetadataRepositoryJsonBuilder} instance.\n\t */\n\tpublic static ConfigurationMetadataRepositoryJsonBuilder create(Charset defaultCharset) {\n\t\treturn new ConfigurationMetadataRepositoryJsonBuilder(defaultCharset);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A source of configuration metadata. Also defines where the source is declared, for\n * instance if it is defined as a {@code @Bean}.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class ConfigurationMetadataSource implements Serializable {\n\n\tprivate String groupId;\n\n\tprivate String type;\n\n\tprivate String description;\n\n\tprivate String shortDescription;\n\n\tprivate String sourceType;\n\n\tprivate String sourceMethod;\n\n\tprivate final Map<String, ConfigurationMetadataProperty> properties = new HashMap<>();\n\n\t/**\n\t * The identifier of the group to which this source is associated.\n\t * @return the group id\n\t */\n\tpublic String getGroupId() {\n\t\treturn this.groupId;\n\t}\n\n\tvoid setGroupId(String groupId) {\n\t\tthis.groupId = groupId;\n\t}\n\n\t/**\n\t * The type of the source. Usually this is the fully qualified name of a class that\n\t * defines configuration items. This class may or may not be available at runtime.\n\t * @return the type\n\t */\n\tpublic String getType() {\n\t\treturn this.type;\n\t}\n\n\tvoid setType(String type) {\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * A description of this source, if any. Can be multi-lines.\n\t * @return the description\n\t * @see #getShortDescription()\n\t */\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tvoid setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\t/**\n\t * A single-line, single-sentence description of this source, if any.\n\t * @return the short description\n\t * @see #getDescription()\n\t */\n\tpublic String getShortDescription() {\n\t\treturn this.shortDescription;\n\t}\n\n\tpublic void setShortDescription(String shortDescription) {\n\t\tthis.shortDescription = shortDescription;\n\t}\n\n\t/**\n\t * The type where this source is defined. This can be identical to the\n\t * {@link #getType() type} if the source is self-defined.\n\t * @return the source type\n\t */\n\tpublic String getSourceType() {\n\t\treturn this.sourceType;\n\t}\n\n\tvoid setSourceType(String sourceType) {\n\t\tthis.sourceType = sourceType;\n\t}\n\n\t/**\n\t * The method name that defines this source, if any.\n\t * @return the source method\n\t */\n\tpublic String getSourceMethod() {\n\t\treturn this.sourceMethod;\n\t}\n\n\tvoid setSourceMethod(String sourceMethod) {\n\t\tthis.sourceMethod = sourceMethod;\n\t}\n\n\t/**\n\t * Return the properties defined by this source.\n\t * @return the properties\n\t */\n\tpublic Map<String, ConfigurationMetadataProperty> getProperties() {\n\t\treturn this.properties;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/Deprecation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\n\n/**\n * Indicate that a property is deprecated. Provide additional information about the\n * deprecation.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class Deprecation implements Serializable {\n\n\tprivate Level level = Level.WARNING;\n\n\tprivate String reason;\n\n\tprivate String shortReason;\n\n\tprivate String replacement;\n\n\t/**\n\t * Define the {@link Level} of deprecation.\n\t * @return the deprecation level\n\t */\n\tpublic Level getLevel() {\n\t\treturn this.level;\n\t}\n\n\tpublic void setLevel(Level level) {\n\t\tthis.level = level;\n\t}\n\n\t/**\n\t * A reason why the related property is deprecated, if any. Can be multi-lines.\n\t * @return the deprecation reason\n\t * @see #getShortReason()\n\t */\n\tpublic String getReason() {\n\t\treturn this.reason;\n\t}\n\n\tpublic void setReason(String reason) {\n\t\tthis.reason = reason;\n\t}\n\n\t/**\n\t * A single-line, single-sentence reason why the related property is deprecated, if\n\t * any.\n\t * @return the short deprecation reason\n\t * @see #getReason()\n\t */\n\tpublic String getShortReason() {\n\t\treturn this.shortReason;\n\t}\n\n\tpublic void setShortReason(String shortReason) {\n\t\tthis.shortReason = shortReason;\n\t}\n\n\t/**\n\t * The full name of the property that replaces the related deprecated property, if\n\t * any.\n\t * @return the replacement property name\n\t */\n\tpublic String getReplacement() {\n\t\treturn this.replacement;\n\t}\n\n\tpublic void setReplacement(String replacement) {\n\t\tthis.replacement = replacement;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Deprecation{level='\" + this.level + '\\'' + \", reason='\" + this.reason + '\\'' + \", replacement='\"\n\t\t\t\t+ this.replacement + '\\'' + '}';\n\t}\n\n\t/**\n\t * Define the deprecation level.\n\t */\n\tpublic enum Level {\n\n\t\t/**\n\t\t * The property is still bound.\n\t\t */\n\t\tWARNING,\n\n\t\t/**\n\t\t * The property has been removed and is no longer bound.\n\t\t */\n\t\tERROR\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/Hints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Hints of an item to provide the list of values and/or the name of the provider\n * responsible to identify suitable values. If the type of the related item is a\n * {@link java.util.Map} it can have both key and value hints.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\npublic class Hints {\n\n\tprivate final List<ValueHint> keyHints = new ArrayList<>();\n\n\tprivate final List<ValueProvider> keyProviders = new ArrayList<>();\n\n\tprivate final List<ValueHint> valueHints = new ArrayList<>();\n\n\tprivate final List<ValueProvider> valueProviders = new ArrayList<>();\n\n\t/**\n\t * The list of well-defined keys, if any. Only applicable if the type of the related\n\t * item is a {@link java.util.Map}. If no extra {@link ValueProvider provider} is\n\t * specified, these values are to be considered a closed-set of the available keys for\n\t * the map.\n\t * @return the key hints\n\t */\n\tpublic List<ValueHint> getKeyHints() {\n\t\treturn this.keyHints;\n\t}\n\n\t/**\n\t * The value providers that are applicable to the keys of this item. Only applicable\n\t * if the type of the related item is a {@link java.util.Map}. Only one\n\t * {@link ValueProvider} is enabled for a key: the first in the list that is supported\n\t * should be used.\n\t * @return the key providers\n\t */\n\tpublic List<ValueProvider> getKeyProviders() {\n\t\treturn this.keyProviders;\n\t}\n\n\t/**\n\t * The list of well-defined values, if any. If no extra {@link ValueProvider provider}\n\t * is specified, these values are to be considered a closed-set of the available\n\t * values for this item.\n\t * @return the value hints\n\t */\n\tpublic List<ValueHint> getValueHints() {\n\t\treturn this.valueHints;\n\t}\n\n\t/**\n\t * The value providers that are applicable to this item. Only one\n\t * {@link ValueProvider} is enabled for an item: the first in the list that is\n\t * supported should be used.\n\t * @return the value providers\n\t */\n\tpublic List<ValueProvider> getValueProviders() {\n\t\treturn this.valueProviders;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/JsonReader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Locale;\n\nimport org.springframework.boot.configurationmetadata.json.JSONArray;\nimport org.springframework.boot.configurationmetadata.json.JSONObject;\n\n/**\n * Read standard JSON metadata format as {@link ConfigurationMetadataRepository}.\n *\n * @author Stephane Nicoll\n */\nclass JsonReader {\n\n\tprivate static final int BUFFER_SIZE = 4096;\n\n\tprivate final SentenceExtractor sentenceExtractor = new SentenceExtractor();\n\n\tRawConfigurationMetadata read(InputStream in, Charset charset) throws IOException {\n\t\ttry {\n\t\t\tJSONObject json = readJson(in, charset);\n\t\t\tList<ConfigurationMetadataSource> groups = parseAllSources(json);\n\t\t\tList<ConfigurationMetadataItem> items = parseAllItems(json);\n\t\t\tList<ConfigurationMetadataHint> hints = parseAllHints(json);\n\t\t\treturn new RawConfigurationMetadata(groups, items, hints);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof IOException ioException) {\n\t\t\t\tthrow ioException;\n\t\t\t}\n\t\t\tif (ex instanceof RuntimeException runtimeException) {\n\t\t\t\tthrow runtimeException;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate List<ConfigurationMetadataSource> parseAllSources(JSONObject root) throws Exception {\n\t\tList<ConfigurationMetadataSource> result = new ArrayList<>();\n\t\tif (!root.has(\"groups\")) {\n\t\t\treturn result;\n\t\t}\n\t\tJSONArray sources = root.getJSONArray(\"groups\");\n\t\tfor (int i = 0; i < sources.length(); i++) {\n\t\t\tJSONObject source = sources.getJSONObject(i);\n\t\t\tresult.add(parseSource(source));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate List<ConfigurationMetadataItem> parseAllItems(JSONObject root) throws Exception {\n\t\tList<ConfigurationMetadataItem> result = new ArrayList<>();\n\t\tif (!root.has(\"properties\")) {\n\t\t\treturn result;\n\t\t}\n\t\tJSONArray items = root.getJSONArray(\"properties\");\n\t\tfor (int i = 0; i < items.length(); i++) {\n\t\t\tJSONObject item = items.getJSONObject(i);\n\t\t\tresult.add(parseItem(item));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate List<ConfigurationMetadataHint> parseAllHints(JSONObject root) throws Exception {\n\t\tList<ConfigurationMetadataHint> result = new ArrayList<>();\n\t\tif (!root.has(\"hints\")) {\n\t\t\treturn result;\n\t\t}\n\t\tJSONArray items = root.getJSONArray(\"hints\");\n\t\tfor (int i = 0; i < items.length(); i++) {\n\t\t\tJSONObject item = items.getJSONObject(i);\n\t\t\tresult.add(parseHint(item));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate ConfigurationMetadataSource parseSource(JSONObject json) throws Exception {\n\t\tConfigurationMetadataSource source = new ConfigurationMetadataSource();\n\t\tsource.setGroupId(json.getString(\"name\"));\n\t\tsource.setType(json.optString(\"type\", null));\n\t\tString description = json.optString(\"description\", null);\n\t\tsource.setDescription(description);\n\t\tsource.setShortDescription(this.sentenceExtractor.getFirstSentence(description));\n\t\tsource.setSourceType(json.optString(\"sourceType\", null));\n\t\tsource.setSourceMethod(json.optString(\"sourceMethod\", null));\n\t\treturn source;\n\t}\n\n\tprivate ConfigurationMetadataItem parseItem(JSONObject json) throws Exception {\n\t\tConfigurationMetadataItem item = new ConfigurationMetadataItem();\n\t\titem.setId(json.getString(\"name\"));\n\t\titem.setType(json.optString(\"type\", null));\n\t\tString description = json.optString(\"description\", null);\n\t\titem.setDescription(description);\n\t\titem.setShortDescription(this.sentenceExtractor.getFirstSentence(description));\n\t\titem.setDefaultValue(readItemValue(json.opt(\"defaultValue\")));\n\t\titem.setDeprecation(parseDeprecation(json));\n\t\titem.setSourceType(json.optString(\"sourceType\", null));\n\t\titem.setSourceMethod(json.optString(\"sourceMethod\", null));\n\t\treturn item;\n\t}\n\n\tprivate ConfigurationMetadataHint parseHint(JSONObject json) throws Exception {\n\t\tConfigurationMetadataHint hint = new ConfigurationMetadataHint();\n\t\thint.setId(json.getString(\"name\"));\n\t\tif (json.has(\"values\")) {\n\t\t\tJSONArray values = json.getJSONArray(\"values\");\n\t\t\tfor (int i = 0; i < values.length(); i++) {\n\t\t\t\tJSONObject value = values.getJSONObject(i);\n\t\t\t\tValueHint valueHint = new ValueHint();\n\t\t\t\tvalueHint.setValue(readItemValue(value.get(\"value\")));\n\t\t\t\tString description = value.optString(\"description\", null);\n\t\t\t\tvalueHint.setDescription(description);\n\t\t\t\tvalueHint.setShortDescription(this.sentenceExtractor.getFirstSentence(description));\n\t\t\t\thint.getValueHints().add(valueHint);\n\t\t\t}\n\t\t}\n\t\tif (json.has(\"providers\")) {\n\t\t\tJSONArray providers = json.getJSONArray(\"providers\");\n\t\t\tfor (int i = 0; i < providers.length(); i++) {\n\t\t\t\tJSONObject provider = providers.getJSONObject(i);\n\t\t\t\tValueProvider valueProvider = new ValueProvider();\n\t\t\t\tvalueProvider.setName(provider.getString(\"name\"));\n\t\t\t\tif (provider.has(\"parameters\")) {\n\t\t\t\t\tJSONObject parameters = provider.getJSONObject(\"parameters\");\n\t\t\t\t\tIterator<?> keys = parameters.keys();\n\t\t\t\t\twhile (keys.hasNext()) {\n\t\t\t\t\t\tString key = (String) keys.next();\n\t\t\t\t\t\tvalueProvider.getParameters().put(key, readItemValue(parameters.get(key)));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\thint.getValueProviders().add(valueProvider);\n\t\t\t}\n\t\t}\n\t\treturn hint;\n\t}\n\n\tprivate Deprecation parseDeprecation(JSONObject object) throws Exception {\n\t\tif (object.has(\"deprecation\")) {\n\t\t\tJSONObject deprecationJsonObject = object.getJSONObject(\"deprecation\");\n\t\t\tDeprecation deprecation = new Deprecation();\n\t\t\tdeprecation.setLevel(parseDeprecationLevel(deprecationJsonObject.optString(\"level\", null)));\n\t\t\tString reason = deprecationJsonObject.optString(\"reason\", null);\n\t\t\tdeprecation.setReason(reason);\n\t\t\tdeprecation.setShortReason(this.sentenceExtractor.getFirstSentence(reason));\n\t\t\tdeprecation.setReplacement(deprecationJsonObject.optString(\"replacement\", null));\n\t\t\treturn deprecation;\n\t\t}\n\t\treturn object.optBoolean(\"deprecated\") ? new Deprecation() : null;\n\t}\n\n\tprivate Deprecation.Level parseDeprecationLevel(String value) {\n\t\tif (value != null) {\n\t\t\ttry {\n\t\t\t\treturn Deprecation.Level.valueOf(value.toUpperCase(Locale.ENGLISH));\n\t\t\t}\n\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\t// let's use the default\n\t\t\t}\n\t\t}\n\t\treturn Deprecation.Level.WARNING;\n\t}\n\n\tprivate Object readItemValue(Object value) throws Exception {\n\t\tif (value instanceof JSONArray array) {\n\t\t\tObject[] content = new Object[array.length()];\n\t\t\tfor (int i = 0; i < array.length(); i++) {\n\t\t\t\tcontent[i] = array.get(i);\n\t\t\t}\n\t\t\treturn content;\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate JSONObject readJson(InputStream in, Charset charset) throws Exception {\n\t\ttry (in) {\n\t\t\tStringBuilder out = new StringBuilder();\n\t\t\tInputStreamReader reader = new InputStreamReader(in, charset);\n\t\t\tchar[] buffer = new char[BUFFER_SIZE];\n\t\t\tint bytesRead;\n\t\t\twhile ((bytesRead = reader.read(buffer)) != -1) {\n\t\t\t\tout.append(buffer, 0, bytesRead);\n\t\t\t}\n\t\t\treturn new JSONObject(out.toString());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/RawConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\n\n/**\n * A raw metadata structure. Used to initialize a {@link ConfigurationMetadataRepository}.\n *\n * @author Stephane Nicoll\n */\nclass RawConfigurationMetadata {\n\n\tprivate final List<ConfigurationMetadataSource> sources;\n\n\tprivate final List<ConfigurationMetadataItem> items;\n\n\tprivate final List<ConfigurationMetadataHint> hints;\n\n\tRawConfigurationMetadata(List<ConfigurationMetadataSource> sources, List<ConfigurationMetadataItem> items,\n\t\t\tList<ConfigurationMetadataHint> hints) {\n\t\tthis.sources = new ArrayList<>(sources);\n\t\tthis.items = new ArrayList<>(items);\n\t\tthis.hints = new ArrayList<>(hints);\n\t\tfor (ConfigurationMetadataItem item : this.items) {\n\t\t\tresolveName(item);\n\t\t}\n\t}\n\n\tList<ConfigurationMetadataSource> getSources() {\n\t\treturn this.sources;\n\t}\n\n\tConfigurationMetadataSource getSource(ConfigurationMetadataItem item) {\n\t\tif (item.getSourceType() == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.sources.stream()\n\t\t\t.filter((candidate) -> item.getSourceType().equals(candidate.getType())\n\t\t\t\t\t&& item.getId().startsWith(candidate.getGroupId()))\n\t\t\t.max(Comparator.comparingInt((candidate) -> candidate.getGroupId().length()))\n\t\t\t.orElse(null);\n\t}\n\n\tList<ConfigurationMetadataItem> getItems() {\n\t\treturn this.items;\n\t}\n\n\tList<ConfigurationMetadataHint> getHints() {\n\t\treturn this.hints;\n\t}\n\n\t/**\n\t * Resolve the name of an item against this instance.\n\t * @param item the item to resolve\n\t * @see ConfigurationMetadataProperty#setName(String)\n\t */\n\tprivate void resolveName(ConfigurationMetadataItem item) {\n\t\titem.setName(item.getId()); // fallback\n\t\tConfigurationMetadataSource source = getSource(item);\n\t\tif (source != null) {\n\t\t\tString groupId = source.getGroupId();\n\t\t\tString dottedPrefix = groupId + \".\";\n\t\t\tString id = item.getId();\n\t\t\tif (hasLength(groupId) && id.startsWith(dottedPrefix)) {\n\t\t\t\tString name = id.substring(dottedPrefix.length());\n\t\t\t\titem.setName(name);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static boolean hasLength(String string) {\n\t\treturn (string != null && !string.isEmpty());\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/SentenceExtractor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.text.BreakIterator;\nimport java.util.Arrays;\nimport java.util.Locale;\nimport java.util.stream.Collectors;\n\n/**\n * Utility to extract the first sentence of a text.\n *\n * @author Stephane Nicoll\n */\nclass SentenceExtractor {\n\n\tString getFirstSentence(String text) {\n\t\tif (text == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint dot = text.indexOf('.');\n\t\tif (dot != -1) {\n\t\t\tBreakIterator breakIterator = BreakIterator.getSentenceInstance(Locale.US);\n\t\t\tbreakIterator.setText(text);\n\t\t\tString sentence = text.substring(breakIterator.first(), breakIterator.next());\n\t\t\treturn removeSpaceBetweenLine(sentence.trim());\n\t\t}\n\t\telse {\n\t\t\tString[] lines = text.split(System.lineSeparator());\n\t\t\treturn lines[0].trim();\n\t\t}\n\t}\n\n\tprivate String removeSpaceBetweenLine(String text) {\n\t\tString[] lines = text.split(System.lineSeparator());\n\t\treturn Arrays.stream(lines).map(String::trim).collect(Collectors.joining(\" \"));\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/SimpleConfigurationMetadataRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * The default {@link ConfigurationMetadataRepository} implementation.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class SimpleConfigurationMetadataRepository implements ConfigurationMetadataRepository, Serializable {\n\n\tprivate final Map<String, ConfigurationMetadataGroup> allGroups = new HashMap<>();\n\n\t@Override\n\tpublic Map<String, ConfigurationMetadataGroup> getAllGroups() {\n\t\treturn Collections.unmodifiableMap(this.allGroups);\n\t}\n\n\t@Override\n\tpublic Map<String, ConfigurationMetadataProperty> getAllProperties() {\n\t\tMap<String, ConfigurationMetadataProperty> properties = new HashMap<>();\n\t\tfor (ConfigurationMetadataGroup group : this.allGroups.values()) {\n\t\t\tproperties.putAll(group.getProperties());\n\t\t}\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Register the specified {@link ConfigurationMetadataSource sources}.\n\t * @param sources the sources to add\n\t */\n\tpublic void add(Collection<ConfigurationMetadataSource> sources) {\n\t\tfor (ConfigurationMetadataSource source : sources) {\n\t\t\tString groupId = source.getGroupId();\n\t\t\tConfigurationMetadataGroup group = this.allGroups.computeIfAbsent(groupId,\n\t\t\t\t\t(key) -> new ConfigurationMetadataGroup(groupId));\n\t\t\tString sourceType = source.getType();\n\t\t\tif (sourceType != null) {\n\t\t\t\taddOrMergeSource(group.getSources(), sourceType, source);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add a {@link ConfigurationMetadataProperty} with the\n\t * {@link ConfigurationMetadataSource source} that defines it, if any.\n\t * @param property the property to add\n\t * @param source the source\n\t */\n\tpublic void add(ConfigurationMetadataProperty property, ConfigurationMetadataSource source) {\n\t\tif (source != null) {\n\t\t\tsource.getProperties().putIfAbsent(property.getId(), property);\n\t\t}\n\t\tgetGroup(source).getProperties().putIfAbsent(property.getId(), property);\n\t}\n\n\t/**\n\t * Merge the content of the specified repository to this repository.\n\t * @param repository the repository to include\n\t */\n\tpublic void include(ConfigurationMetadataRepository repository) {\n\t\tfor (ConfigurationMetadataGroup group : repository.getAllGroups().values()) {\n\t\t\tConfigurationMetadataGroup existingGroup = this.allGroups.get(group.getId());\n\t\t\tif (existingGroup == null) {\n\t\t\t\tthis.allGroups.put(group.getId(), group);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Merge properties\n\t\t\t\tgroup.getProperties().forEach((name, value) -> existingGroup.getProperties().putIfAbsent(name, value));\n\t\t\t\t// Merge sources\n\t\t\t\tgroup.getSources().forEach((name, value) -> addOrMergeSource(existingGroup.getSources(), name, value));\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate ConfigurationMetadataGroup getGroup(ConfigurationMetadataSource source) {\n\t\tif (source == null) {\n\t\t\treturn this.allGroups.computeIfAbsent(ROOT_GROUP, (key) -> new ConfigurationMetadataGroup(ROOT_GROUP));\n\t\t}\n\t\treturn this.allGroups.get(source.getGroupId());\n\t}\n\n\tprivate void addOrMergeSource(Map<String, ConfigurationMetadataSource> sources, String name,\n\t\t\tConfigurationMetadataSource source) {\n\t\tConfigurationMetadataSource existingSource = sources.get(name);\n\t\tif (existingSource == null) {\n\t\t\tsources.put(name, source);\n\t\t}\n\t\telse {\n\t\t\tsource.getProperties().forEach((k, v) -> existingSource.getProperties().putIfAbsent(k, v));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ValueHint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\n\n/**\n * Hint for a value a given property may have. Provide the value and an optional\n * description.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class ValueHint implements Serializable {\n\n\tprivate Object value;\n\n\tprivate String description;\n\n\tprivate String shortDescription;\n\n\t/**\n\t * Return the hint value.\n\t * @return the value\n\t */\n\tpublic Object getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(Object value) {\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * A description of this value, if any. Can be multi-lines.\n\t * @return the description\n\t * @see #getShortDescription()\n\t */\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\t/**\n\t * A single-line, single-sentence description of this hint, if any.\n\t * @return the short description\n\t * @see #getDescription()\n\t */\n\tpublic String getShortDescription() {\n\t\treturn this.shortDescription;\n\t}\n\n\tpublic void setShortDescription(String shortDescription) {\n\t\tthis.shortDescription = shortDescription;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"ValueHint{value=\" + this.value + \", description='\" + this.description + '\\'' + '}';\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/ValueProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.Serializable;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * Define a component that is able to provide the values of a property.\n * <p>\n * Each provider is defined by a {@code name} and can have an arbitrary number of\n * {@code parameters}. The available providers are defined in the Spring Boot\n * documentation.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class ValueProvider implements Serializable {\n\n\tprivate String name;\n\n\tprivate final Map<String, Object> parameters = new LinkedHashMap<>();\n\n\t/**\n\t * Return the name of the provider.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * Return the parameters.\n\t * @return the parameters\n\t */\n\tpublic Map<String, Object> getParameters() {\n\t\treturn this.parameters;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"ValueProvider{name='\" + this.name + \", parameters=\" + this.parameters + '}';\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/main/java/org/springframework/boot/configurationmetadata/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot configuration meta-data parser.\n */\npackage org.springframework.boot.configurationmetadata;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/java/org/springframework/boot/configurationmetadata/AbstractConfigurationMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base for configuration meta-data tests.\n *\n * @author Stephane Nicoll\n */\npublic abstract class AbstractConfigurationMetadataTests {\n\n\tprotected void assertSource(ConfigurationMetadataSource actual, String groupId, String type, String sourceType) {\n\t\tassertThat(actual).isNotNull();\n\t\tassertThat(actual.getGroupId()).isEqualTo(groupId);\n\t\tassertThat(actual.getType()).isEqualTo(type);\n\t\tassertThat(actual.getSourceType()).isEqualTo(sourceType);\n\t}\n\n\tprotected void assertProperty(ConfigurationMetadataProperty actual, String id, String name, Class<?> type,\n\t\t\tObject defaultValue) {\n\t\tassertThat(actual).isNotNull();\n\t\tassertThat(actual.getId()).isEqualTo(id);\n\t\tassertThat(actual.getName()).isEqualTo(name);\n\t\tString typeName = (type != null) ? type.getName() : null;\n\t\tassertThat(actual.getType()).isEqualTo(typeName);\n\t\tassertThat(actual.getDefaultValue()).isEqualTo(defaultValue);\n\t}\n\n\tprotected void assertItem(ConfigurationMetadataItem actual, String sourceType) {\n\t\tassertThat(actual).isNotNull();\n\t\tassertThat(actual.getSourceType()).isEqualTo(sourceType);\n\t}\n\n\tprotected InputStream getInputStreamFor(String name) throws IOException {\n\t\tResource r = new ClassPathResource(\"metadata/configuration-metadata-\" + name + \".json\");\n\t\treturn r.getInputStream();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/java/org/springframework/boot/configurationmetadata/ConfigurationMetadataRepositoryJsonBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigurationMetadataRepository}.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationMetadataRepositoryJsonBuilderTests extends AbstractConfigurationMetadataTests {\n\n\t@Test\n\tvoid nullResource() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(null));\n\t}\n\n\t@Test\n\tvoid simpleRepository() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(foo).build();\n\t\t\tvalidateFoo(repo);\n\t\t\tassertThat(repo.getAllGroups()).hasSize(1);\n\t\t\tcontains(repo.getAllProperties(), \"spring.foo.name\", \"spring.foo.description\", \"spring.foo.counter\");\n\t\t\tassertThat(repo.getAllProperties()).hasSize(3);\n\t\t}\n\t}\n\n\t@Test\n\tvoid hintsOnMaps() throws IOException {\n\t\ttry (InputStream map = getInputStreamFor(\"map\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(map).build();\n\t\t\tvalidateMap(repo);\n\t\t\tassertThat(repo.getAllGroups()).hasSize(1);\n\t\t\tcontains(repo.getAllProperties(), \"spring.map.first\", \"spring.map.second\", \"spring.map.keys\",\n\t\t\t\t\t\"spring.map.values\");\n\t\t\tassertThat(repo.getAllProperties()).hasSize(4);\n\t\t}\n\t}\n\n\t@Test\n\tvoid severalRepositoriesNoConflict() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\"); InputStream bar = getInputStreamFor(\"bar\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(foo, bar).build();\n\t\t\tvalidateFoo(repo);\n\t\t\tvalidateBar(repo);\n\t\t\tassertThat(repo.getAllGroups()).hasSize(2);\n\t\t\tcontains(repo.getAllProperties(), \"spring.foo.name\", \"spring.foo.description\", \"spring.foo.counter\",\n\t\t\t\t\t\"spring.bar.name\", \"spring.bar.description\", \"spring.bar.counter\");\n\t\t\tassertThat(repo.getAllProperties()).hasSize(6);\n\t\t}\n\t}\n\n\t@Test\n\tvoid repositoryWithRoot() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\"); InputStream root = getInputStreamFor(\"root\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(foo, root).build();\n\t\t\tvalidateFoo(repo);\n\t\t\tassertThat(repo.getAllGroups()).hasSize(2);\n\n\t\t\tcontains(repo.getAllProperties(), \"spring.foo.name\", \"spring.foo.description\", \"spring.foo.counter\",\n\t\t\t\t\t\"spring.root.name\", \"spring.root2.name\");\n\t\t\tassertThat(repo.getAllProperties()).hasSize(5);\n\t\t}\n\t}\n\n\t@Test\n\tvoid severalRepositoriesIdenticalGroups() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\"); InputStream foo2 = getInputStreamFor(\"foo2\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(foo, foo2).build();\n\t\t\tIterable<String> allKeys = Arrays.asList(\"spring.foo.name\", \"spring.foo.description\", \"spring.foo.counter\",\n\t\t\t\t\t\"spring.foo.enabled\", \"spring.foo.type\");\n\t\t\tassertThat(repo.getAllProperties()).containsOnlyKeys(allKeys);\n\t\t\tassertThat(repo.getAllGroups()).containsOnlyKeys(\"spring.foo\");\n\t\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"spring.foo\");\n\t\t\tassertThat(group.getProperties()).containsOnlyKeys(allKeys);\n\t\t\tassertThat(group.getSources()).containsOnlyKeys(\"org.acme.Foo\", \"org.acme.Foo2\",\n\t\t\t\t\t\"org.springframework.boot.FooProperties\");\n\t\t\tassertThat(group.getSources().get(\"org.acme.Foo\").getProperties()).containsOnlyKeys(\"spring.foo.name\",\n\t\t\t\t\t\"spring.foo.description\");\n\t\t\tassertThat(group.getSources().get(\"org.acme.Foo2\").getProperties()).containsOnlyKeys(\"spring.foo.enabled\",\n\t\t\t\t\t\"spring.foo.type\");\n\t\t\tassertThat(group.getSources().get(\"org.springframework.boot.FooProperties\").getProperties())\n\t\t\t\t.containsOnlyKeys(\"spring.foo.name\", \"spring.foo.counter\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid severalRepositoriesIdenticalGroupsWithSameType() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\"); InputStream foo3 = getInputStreamFor(\"foo3\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(foo, foo3).build();\n\t\t\tIterable<String> allKeys = Arrays.asList(\"spring.foo.name\", \"spring.foo.description\", \"spring.foo.counter\",\n\t\t\t\t\t\"spring.foo.enabled\", \"spring.foo.type\");\n\t\t\tassertThat(repo.getAllProperties()).containsOnlyKeys(allKeys);\n\t\t\tassertThat(repo.getAllGroups()).containsOnlyKeys(\"spring.foo\");\n\t\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"spring.foo\");\n\t\t\tassertThat(group.getProperties()).containsOnlyKeys(allKeys);\n\t\t\tassertThat(group.getSources()).containsOnlyKeys(\"org.acme.Foo\", \"org.springframework.boot.FooProperties\");\n\t\t\tassertThat(group.getSources().get(\"org.acme.Foo\").getProperties()).containsOnlyKeys(\"spring.foo.name\",\n\t\t\t\t\t\"spring.foo.description\", \"spring.foo.enabled\", \"spring.foo.type\");\n\t\t\tassertThat(group.getSources().get(\"org.springframework.boot.FooProperties\").getProperties())\n\t\t\t\t.containsOnlyKeys(\"spring.foo.name\", \"spring.foo.counter\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid severalRepositoriesIdenticalGroupsWithSameTypeDoesNotOverrideSource() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\"); InputStream foo3 = getInputStreamFor(\"foo3\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(foo, foo3).build();\n\t\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"spring.foo\");\n\t\t\tConfigurationMetadataSource fooSource = group.getSources().get(\"org.acme.Foo\");\n\t\t\tassertThat(fooSource.getSourceMethod()).isEqualTo(\"foo()\");\n\t\t\tassertThat(fooSource.getDescription()).isEqualTo(\"This is Foo.\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid emptyGroups() throws IOException {\n\t\ttry (InputStream in = getInputStreamFor(\"empty-groups\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(in).build();\n\t\t\tvalidateEmptyGroup(repo);\n\t\t\tassertThat(repo.getAllGroups()).hasSize(1);\n\t\t\tcontains(repo.getAllProperties(), \"name\", \"title\");\n\t\t\tassertThat(repo.getAllProperties()).hasSize(2);\n\t\t}\n\t}\n\n\t@Test\n\tvoid multiGroups() throws IOException {\n\t\ttry (InputStream in = getInputStreamFor(\"multi-groups\")) {\n\t\t\tConfigurationMetadataRepository repo = ConfigurationMetadataRepositoryJsonBuilder.create(in).build();\n\t\t\tassertThat(repo.getAllGroups()).containsOnlyKeys(\"test.group.one.retry\", \"test.group.two.retry\",\n\t\t\t\t\t\"test.group.one.retry.specific\");\n\t\t\tConfigurationMetadataGroup one = repo.getAllGroups().get(\"test.group.one.retry\");\n\t\t\tassertThat(one.getSources()).containsOnlyKeys(\"com.example.Retry\");\n\t\t\tassertThat(one.getProperties()).containsOnlyKeys(\"test.group.one.retry.enabled\");\n\t\t\tConfigurationMetadataGroup two = repo.getAllGroups().get(\"test.group.two.retry\");\n\t\t\tassertThat(two.getSources()).containsOnlyKeys(\"com.example.Retry\");\n\t\t\tassertThat(two.getProperties()).containsOnlyKeys(\"test.group.two.retry.enabled\");\n\t\t\tConfigurationMetadataGroup oneSpecific = repo.getAllGroups().get(\"test.group.one.retry.specific\");\n\t\t\tassertThat(oneSpecific.getSources()).containsOnlyKeys(\"com.example.Retry\");\n\t\t\tassertThat(oneSpecific.getProperties()).containsOnlyKeys(\"test.group.one.retry.specific.enabled\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid builderInstancesAreIsolated() throws IOException {\n\t\ttry (InputStream foo = getInputStreamFor(\"foo\"); InputStream bar = getInputStreamFor(\"bar\")) {\n\t\t\tConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create();\n\t\t\tConfigurationMetadataRepository firstRepo = builder.withJsonResource(foo).build();\n\t\t\tvalidateFoo(firstRepo);\n\t\t\tConfigurationMetadataRepository secondRepo = builder.withJsonResource(bar).build();\n\t\t\tvalidateFoo(secondRepo);\n\t\t\tvalidateBar(secondRepo);\n\t\t\t// first repo not impacted by second build\n\t\t\tassertThat(secondRepo).isNotEqualTo(firstRepo);\n\t\t\tassertThat(firstRepo.getAllGroups()).hasSize(1);\n\t\t\tassertThat(firstRepo.getAllProperties()).hasSize(3);\n\t\t\tassertThat(secondRepo.getAllGroups()).hasSize(2);\n\t\t\tassertThat(secondRepo.getAllProperties()).hasSize(6);\n\t\t}\n\t}\n\n\tprivate void validateFoo(ConfigurationMetadataRepository repo) {\n\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"spring.foo\");\n\t\tcontains(group.getSources(), \"org.acme.Foo\", \"org.springframework.boot.FooProperties\");\n\t\tConfigurationMetadataSource source = group.getSources().get(\"org.acme.Foo\");\n\t\tcontains(source.getProperties(), \"spring.foo.name\", \"spring.foo.description\");\n\t\tassertThat(source.getProperties()).hasSize(2);\n\t\tConfigurationMetadataSource source2 = group.getSources().get(\"org.springframework.boot.FooProperties\");\n\t\tcontains(source2.getProperties(), \"spring.foo.name\", \"spring.foo.counter\");\n\t\tassertThat(source2.getProperties()).hasSize(2);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"spring.foo.name\"), 0, 0);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"spring.foo.description\"), 0, 0);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"spring.foo.counter\"), 1, 1);\n\t}\n\n\tprivate void validateBar(ConfigurationMetadataRepository repo) {\n\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"spring.bar\");\n\t\tcontains(group.getSources(), \"org.acme.Bar\", \"org.springframework.boot.BarProperties\");\n\t\tConfigurationMetadataSource source = group.getSources().get(\"org.acme.Bar\");\n\t\tcontains(source.getProperties(), \"spring.bar.name\", \"spring.bar.description\");\n\t\tassertThat(source.getProperties()).hasSize(2);\n\t\tConfigurationMetadataSource source2 = group.getSources().get(\"org.springframework.boot.BarProperties\");\n\t\tcontains(source2.getProperties(), \"spring.bar.name\", \"spring.bar.counter\");\n\t\tassertThat(source2.getProperties()).hasSize(2);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"spring.bar.name\"), 0, 0);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"spring.bar.description\"), 2, 2);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"spring.bar.counter\"), 0, 0);\n\t}\n\n\tprivate void validateMap(ConfigurationMetadataRepository repo) {\n\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"spring.map\");\n\t\tConfigurationMetadataSource source = group.getSources().get(\"org.acme.Map\");\n\t\tcontains(source.getProperties(), \"spring.map.first\", \"spring.map.second\", \"spring.map.keys\",\n\t\t\t\t\"spring.map.values\");\n\t\tassertThat(source.getProperties()).hasSize(4);\n\t\tConfigurationMetadataProperty first = repo.getAllProperties().get(\"spring.map.first\");\n\t\tassertThat(first.getHints().getKeyHints()).hasSize(2);\n\t\tassertThat(first.getHints().getValueProviders()).isEmpty();\n\t\tassertThat(first.getHints().getKeyHints().get(0).getValue()).isEqualTo(\"one\");\n\t\tassertThat(first.getHints().getKeyHints().get(0).getDescription()).isEqualTo(\"First.\");\n\t\tassertThat(first.getHints().getKeyHints().get(1).getValue()).isEqualTo(\"two\");\n\t\tassertThat(first.getHints().getKeyHints().get(1).getDescription()).isEqualTo(\"Second.\");\n\t\tConfigurationMetadataProperty second = repo.getAllProperties().get(\"spring.map.second\");\n\t\tassertThat(second.getHints().getValueHints()).hasSize(2);\n\t\tassertThat(second.getHints().getValueProviders()).isEmpty();\n\t\tassertThat(second.getHints().getValueHints().get(0).getValue()).isEqualTo(\"42\");\n\t\tassertThat(second.getHints().getValueHints().get(0).getDescription()).isEqualTo(\"Choose me.\");\n\t\tassertThat(second.getHints().getValueHints().get(1).getValue()).isEqualTo(\"24\");\n\t\tassertThat(second.getHints().getValueHints().get(1).getDescription()).isNull();\n\t\tConfigurationMetadataProperty keys = repo.getAllProperties().get(\"spring.map.keys\");\n\t\tassertThat(keys.getHints().getValueHints()).isEmpty();\n\t\tassertThat(keys.getHints().getValueProviders()).hasSize(1);\n\t\tassertThat(keys.getHints().getValueProviders().get(0).getName()).isEqualTo(\"any\");\n\t\tConfigurationMetadataProperty values = repo.getAllProperties().get(\"spring.map.values\");\n\t\tassertThat(values.getHints().getValueHints()).isEmpty();\n\t\tassertThat(values.getHints().getValueProviders()).hasSize(1);\n\t\tassertThat(values.getHints().getValueProviders().get(0).getName()).isEqualTo(\"handle-as\");\n\t\tassertThat(values.getHints().getValueProviders().get(0).getParameters()).hasSize(1);\n\t\tassertThat(values.getHints().getValueProviders().get(0).getParameters()).containsEntry(\"target\",\n\t\t\t\t\"java.lang.Integer\");\n\t}\n\n\tprivate void validateEmptyGroup(ConfigurationMetadataRepository repo) {\n\t\tConfigurationMetadataGroup group = repo.getAllGroups().get(\"\");\n\t\tcontains(group.getSources(), \"org.acme.Foo\", \"org.acme.Bar\");\n\t\tConfigurationMetadataSource source = group.getSources().get(\"org.acme.Foo\");\n\t\tcontains(source.getProperties(), \"name\");\n\t\tassertThat(source.getProperties()).hasSize(1);\n\t\tConfigurationMetadataSource source2 = group.getSources().get(\"org.acme.Bar\");\n\t\tcontains(source2.getProperties(), \"title\");\n\t\tassertThat(source2.getProperties()).hasSize(1);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"name\"), 0, 0);\n\t\tvalidatePropertyHints(repo.getAllProperties().get(\"title\"), 0, 0);\n\t}\n\n\tprivate void validatePropertyHints(ConfigurationMetadataProperty property, int valueHints, int valueProviders) {\n\t\tassertThat(property.getHints().getValueHints()).hasSize(valueHints);\n\t\tassertThat(property.getHints().getValueProviders()).hasSize(valueProviders);\n\t}\n\n\tprivate void contains(Map<String, ?> source, String... keys) {\n\t\tfor (String key : keys) {\n\t\t\tassertThat(source).containsKey(key);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/java/org/springframework/boot/configurationmetadata/JsonReaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationmetadata.json.JSONException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link JsonReader}.\n *\n * @author Stephane Nicoll\n */\nclass JsonReaderTests extends AbstractConfigurationMetadataTests {\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\tprivate final JsonReader reader = new JsonReader();\n\n\t@Test\n\tvoid emptyMetadata() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"empty\");\n\t\tassertThat(rawMetadata.getSources()).isEmpty();\n\t\tassertThat(rawMetadata.getItems()).isEmpty();\n\t}\n\n\t@Test\n\tvoid invalidMetadata() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> readFor(\"invalid\")).withCauseInstanceOf(JSONException.class);\n\t}\n\n\t@Test\n\tvoid emptyGroupName() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"empty-groups\");\n\t\tList<ConfigurationMetadataItem> items = rawMetadata.getItems();\n\t\tassertThat(items).hasSize(2);\n\n\t\tConfigurationMetadataItem name = items.get(0);\n\t\tassertProperty(name, \"name\", \"name\", String.class, null);\n\t\tConfigurationMetadataItem dotTitle = items.get(1);\n\t\tassertProperty(dotTitle, \"title\", \"title\", String.class, null);\n\t}\n\n\t@Test\n\tvoid simpleMetadata() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"foo\");\n\t\tList<ConfigurationMetadataSource> sources = rawMetadata.getSources();\n\t\tassertThat(sources).hasSize(2);\n\t\tList<ConfigurationMetadataItem> items = rawMetadata.getItems();\n\t\tassertThat(items).hasSize(4);\n\t\tList<ConfigurationMetadataHint> hints = rawMetadata.getHints();\n\t\tassertThat(hints).hasSize(1);\n\n\t\tConfigurationMetadataSource source = sources.get(0);\n\t\tassertSource(source, \"spring.foo\", \"org.acme.Foo\", \"org.acme.config.FooApp\");\n\t\tassertThat(source.getSourceMethod()).isEqualTo(\"foo()\");\n\t\tassertThat(source.getDescription()).isEqualTo(\"This is Foo.\");\n\t\tassertThat(source.getShortDescription()).isEqualTo(\"This is Foo.\");\n\n\t\tConfigurationMetadataItem item = items.get(0);\n\t\tassertProperty(item, \"spring.foo.name\", \"name\", String.class, null);\n\t\tassertItem(item, \"org.acme.Foo\");\n\t\tConfigurationMetadataItem item2 = items.get(1);\n\t\tassertProperty(item2, \"spring.foo.description\", \"description\", String.class, \"FooBar\");\n\t\tassertThat(item2.getDescription()).isEqualTo(\"Foo description.\");\n\t\tassertThat(item2.getShortDescription()).isEqualTo(\"Foo description.\");\n\t\tassertThat(item2.getSourceMethod()).isNull();\n\t\tassertItem(item2, \"org.acme.Foo\");\n\n\t\tConfigurationMetadataHint hint = hints.get(0);\n\t\tassertThat(hint.getId()).isEqualTo(\"spring.foo.counter\");\n\t\tassertThat(hint.getValueHints()).hasSize(1);\n\t\tValueHint valueHint = hint.getValueHints().get(0);\n\t\tassertThat(valueHint.getValue()).isEqualTo(42);\n\t\tassertThat(valueHint.getDescription())\n\t\t\t.isEqualTo(\"Because that's the answer to any question, choose it. \\nReally.\");\n\t\tassertThat(valueHint.getShortDescription()).isEqualTo(\"Because that's the answer to any question, choose it.\");\n\t\tassertThat(hint.getValueProviders()).hasSize(1);\n\t\tValueProvider valueProvider = hint.getValueProviders().get(0);\n\t\tassertThat(valueProvider.getName()).isEqualTo(\"handle-as\");\n\t\tassertThat(valueProvider.getParameters()).hasSize(1);\n\t\tassertThat(valueProvider.getParameters()).containsEntry(\"target\", Integer.class.getName());\n\t}\n\n\t@Test\n\tvoid metadataHints() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"bar\");\n\t\tList<ConfigurationMetadataHint> hints = rawMetadata.getHints();\n\t\tassertThat(hints).hasSize(1);\n\n\t\tConfigurationMetadataHint hint = hints.get(0);\n\t\tassertThat(hint.getId()).isEqualTo(\"spring.bar.description\");\n\t\tassertThat(hint.getValueHints()).hasSize(2);\n\t\tValueHint valueHint = hint.getValueHints().get(0);\n\t\tassertThat(valueHint.getValue()).isEqualTo(\"one\");\n\t\tassertThat(valueHint.getDescription()).isEqualTo(\"One.\");\n\t\tValueHint valueHint2 = hint.getValueHints().get(1);\n\t\tassertThat(valueHint2.getValue()).isEqualTo(\"two\");\n\t\tassertThat(valueHint2.getDescription()).isNull();\n\n\t\tassertThat(hint.getValueProviders()).hasSize(2);\n\t\tValueProvider valueProvider = hint.getValueProviders().get(0);\n\t\tassertThat(valueProvider.getName()).isEqualTo(\"handle-as\");\n\t\tassertThat(valueProvider.getParameters()).hasSize(1);\n\t\tassertThat(valueProvider.getParameters()).containsEntry(\"target\", String.class.getName());\n\t\tValueProvider valueProvider2 = hint.getValueProviders().get(1);\n\t\tassertThat(valueProvider2.getName()).isEqualTo(\"any\");\n\t\tassertThat(valueProvider2.getParameters()).isEmpty();\n\t}\n\n\t@Test\n\tvoid rootMetadata() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"root\");\n\t\tList<ConfigurationMetadataSource> sources = rawMetadata.getSources();\n\t\tassertThat(sources).isEmpty();\n\t\tList<ConfigurationMetadataItem> items = rawMetadata.getItems();\n\t\tassertThat(items).hasSize(2);\n\t\tConfigurationMetadataItem item = items.get(0);\n\t\tassertProperty(item, \"spring.root.name\", \"spring.root.name\", String.class, null);\n\t}\n\n\t@Test\n\tvoid deprecatedMetadata() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"deprecated\");\n\t\tList<ConfigurationMetadataItem> items = rawMetadata.getItems();\n\t\tassertThat(items).hasSize(5);\n\n\t\tConfigurationMetadataItem item = items.get(0);\n\t\tassertProperty(item, \"server.port\", \"server.port\", Integer.class, null);\n\t\tassertThat(item.isDeprecated()).isTrue();\n\t\tassertThat(item.getDeprecation().getReason()).isEqualTo(\"Server namespace has moved to spring.server\");\n\t\tassertThat(item.getDeprecation().getShortReason()).isEqualTo(\"Server namespace has moved to spring.server\");\n\t\tassertThat(item.getDeprecation().getReplacement()).isEqualTo(\"server.spring.port\");\n\t\tassertThat(item.getDeprecation().getLevel()).isEqualTo(Deprecation.Level.WARNING);\n\n\t\tConfigurationMetadataItem item2 = items.get(1);\n\t\tassertProperty(item2, \"server.cluster-name\", \"server.cluster-name\", String.class, null);\n\t\tassertThat(item2.isDeprecated()).isTrue();\n\t\tassertThat(item2.getDeprecation().getReason()).isNull();\n\t\tassertThat(item2.getDeprecation().getShortReason()).isNull();\n\t\tassertThat(item2.getDeprecation().getReplacement()).isNull();\n\t\tassertThat(item.getDeprecation().getLevel()).isEqualTo(Deprecation.Level.WARNING);\n\n\t\tConfigurationMetadataItem item3 = items.get(2);\n\t\tassertProperty(item3, \"spring.server.name\", \"spring.server.name\", String.class, null);\n\t\tassertThat(item3.isDeprecated()).isFalse();\n\t\tassertThat(item3.getDeprecation()).isNull();\n\n\t\tConfigurationMetadataItem item4 = items.get(3);\n\t\tassertProperty(item4, \"spring.server-name\", \"spring.server-name\", String.class, null);\n\t\tassertThat(item4.isDeprecated()).isTrue();\n\t\tassertThat(item4.getDeprecation().getReason()).isNull();\n\t\tassertThat(item2.getDeprecation().getShortReason()).isNull();\n\t\tassertThat(item4.getDeprecation().getReplacement()).isEqualTo(\"spring.server.name\");\n\t\tassertThat(item4.getDeprecation().getLevel()).isEqualTo(Deprecation.Level.ERROR);\n\n\t\tConfigurationMetadataItem item5 = items.get(4);\n\t\tassertProperty(item5, \"spring.server-name2\", \"spring.server-name2\", String.class, null);\n\t\tassertThat(item5.isDeprecated()).isTrue();\n\t\tassertThat(item5.getDeprecation().getReason()).isNull();\n\t\tassertThat(item2.getDeprecation().getShortReason()).isNull();\n\t\tassertThat(item5.getDeprecation().getReplacement()).isEqualTo(\"spring.server.name\");\n\t\tassertThat(item5.getDeprecation().getLevel()).isEqualTo(Deprecation.Level.WARNING);\n\t}\n\n\t@Test\n\tvoid multiGroupsMetadata() throws IOException {\n\t\tRawConfigurationMetadata rawMetadata = readFor(\"multi-groups\");\n\t\tList<ConfigurationMetadataItem> items = rawMetadata.getItems();\n\t\tassertThat(items).hasSize(3);\n\n\t\tConfigurationMetadataItem item = items.get(0);\n\t\tassertThat(item.getName()).isEqualTo(\"enabled\");\n\t\tassertThat(item.getSourceType()).isEqualTo(\"com.example.Retry\");\n\n\t\tConfigurationMetadataItem item2 = items.get(1);\n\t\tassertThat(item2.getName()).isEqualTo(\"enabled\");\n\t\tassertThat(item2.getSourceType()).isEqualTo(\"com.example.Retry\");\n\n\t\tConfigurationMetadataItem item3 = items.get(2);\n\t\tassertThat(item3.getName()).isEqualTo(\"enabled\");\n\t\tassertThat(item3.getSourceType()).isEqualTo(\"com.example.Retry\");\n\t}\n\n\tRawConfigurationMetadata readFor(String path) throws IOException {\n\t\treturn this.reader.read(getInputStreamFor(path), DEFAULT_CHARSET);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/java/org/springframework/boot/configurationmetadata/SentenceExtractorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SentenceExtractor}.\n *\n * @author Stephane Nicoll\n */\nclass SentenceExtractorTests {\n\n\tprivate static final String NEW_LINE = System.lineSeparator();\n\n\tprivate final SentenceExtractor extractor = new SentenceExtractor();\n\n\t@Test\n\tvoid extractFirstSentence() {\n\t\tString sentence = this.extractor.getFirstSentence(\"My short description. More stuff.\");\n\t\tassertThat(sentence).isEqualTo(\"My short description.\");\n\t}\n\n\t@Test\n\tvoid extractFirstSentenceNewLineBeforeDot() {\n\t\tString sentence = this.extractor\n\t\t\t.getFirstSentence(\"My short\" + NEW_LINE + \"description.\" + NEW_LINE + \"More stuff.\");\n\t\tassertThat(sentence).isEqualTo(\"My short description.\");\n\t}\n\n\t@Test\n\tvoid extractFirstSentenceNewLineBeforeDotWithSpaces() {\n\t\tString sentence = this.extractor\n\t\t\t.getFirstSentence(\"My short  \" + NEW_LINE + \" description.  \" + NEW_LINE + \"More stuff.\");\n\t\tassertThat(sentence).isEqualTo(\"My short description.\");\n\t}\n\n\t@Test\n\tvoid extractFirstSentenceNoDot() {\n\t\tString sentence = this.extractor.getFirstSentence(\"My short description\");\n\t\tassertThat(sentence).isEqualTo(\"My short description\");\n\t}\n\n\t@Test\n\tvoid extractFirstSentenceNoDotMultipleLines() {\n\t\tString sentence = this.extractor.getFirstSentence(\"My short description \" + NEW_LINE + \" More stuff\");\n\t\tassertThat(sentence).isEqualTo(\"My short description\");\n\t}\n\n\t@Test\n\tvoid extractFirstSentenceNull() {\n\t\tassertThat(this.extractor.getFirstSentence(null)).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-bar.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"spring.bar\",\n      \"type\": \"org.acme.Bar\",\n      \"sourceType\": \"org.acme.config.BarApp\",\n      \"sourceMethod\": \"bar()\",\n      \"description\": \"This is Bar.\"\n    },\n    {\n      \"name\": \"spring.bar\",\n      \"type\": \"org.springframework.boot.BarProperties\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"spring.bar.name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Bar\"\n    },\n    {\n      \"name\": \"spring.bar.description\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Bar\",\n      \"description\": \"Bar description.\",\n      \"defaultValue\": \"BarFoo\"\n    },\n    {\n      \"name\": \"spring.bar.name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.BarProperties\"\n    },\n    {\n      \"name\": \"spring.bar.counter\",\n      \"type\": \"java.lang.Integer\",\n      \"sourceType\": \"org.springframework.boot.BarProperties\",\n      \"defaultValue\": 0\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.bar.description\",\n      \"values\": [\n        {\n          \"value\": \"one\",\n          \"description\": \"One.\"\n        },\n        {\n          \"value\": \"two\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.lang.String\"\n          }\n        },\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-deprecated.json",
    "content": "{\n\t\"properties\": [\n\t\t{\n\t\t\t\"name\": \"server.port\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"reason\": \"Server namespace has moved to spring.server\",\n\t\t\t\t\"replacement\": \"server.spring.port\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"server.cluster-name\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"deprecated\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.server.name\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"deprecated\": false\n\t\t},\n    {\n      \"name\": \"spring.server-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.server.name\"\n      }\n    },\n    {\n      \"name\": \"spring.server-name2\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"INVALID\",\n        \"replacement\": \"spring.server.name\"\n      }\n    }\n\t]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-empty-groups.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"\",\n      \"type\": \"org.acme.Foo\",\n      \"sourceType\": \"org.acme.config.FooApp\",\n      \"sourceMethod\": \"foo()\",\n      \"description\": \"This is Foo.\"\n    },\n    {\n      \"name\": \"\",\n      \"type\": \"org.acme.Bar\",\n      \"sourceType\": \"org.acme.config.FooApp\",\n      \"sourceMethod\": \"bar()\",\n      \"description\": \"This is Bar.\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Foo\"\n    },\n    {\n      \"name\": \"title\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Bar\"\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-empty.json",
    "content": "{\n  \"foo\": \"bar\"\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-foo.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"spring.foo\",\n      \"type\": \"org.acme.Foo\",\n      \"sourceType\": \"org.acme.config.FooApp\",\n      \"sourceMethod\": \"foo()\",\n      \"description\": \"This is Foo.\"\n    },\n    {\n      \"name\": \"spring.foo\",\n      \"type\": \"org.springframework.boot.FooProperties\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"spring.foo.name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Foo\"\n    },\n    {\n      \"name\": \"spring.foo.description\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Foo\",\n      \"description\": \"Foo description.\",\n      \"defaultValue\": \"FooBar\"\n    },\n    {\n      \"name\": \"spring.foo.name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.FooProperties\"\n    },\n    {\n      \"name\": \"spring.foo.counter\",\n      \"type\": \"java.lang.Integer\",\n      \"sourceType\": \"org.springframework.boot.FooProperties\",\n      \"defaultValue\": 0\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.foo.counter\",\n      \"values\": [\n        {\n          \"value\": 42,\n          \"description\": \"Because that's the answer to any question, choose it. \\nReally.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.lang.Integer\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-foo2.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"spring.foo\",\n      \"type\": \"org.acme.Foo2\",\n      \"sourceType\": \"org.acme.config.FooApp\",\n      \"sourceMethod\": \"foo2()\",\n      \"description\": \"This is Foo2.\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"spring.foo.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.acme.Foo2\"\n    },\n    {\n      \"name\": \"spring.foo.type\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Foo2\"\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-foo3.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"spring.foo\",\n      \"type\": \"org.acme.Foo\",\n      \"sourceType\": \"org.acme.config.FooApp\",\n      \"sourceMethod\": \"foo3()\",\n      \"description\": \"This is Foo3.\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"spring.foo.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.acme.Foo\"\n    },\n    {\n      \"name\": \"spring.foo.type\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Foo\"\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-invalid.json",
    "content": "{\n  \"properties\": [\n    {\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Invalid\"\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-map.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"spring.map\",\n      \"type\": \"org.acme.Map\",\n      \"sourceType\": \"org.acme.config.MapApp\",\n      \"sourceMethod\": \"map()\",\n      \"description\": \"This is Map.\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"spring.map.first\",\n      \"type\": \"java.util.Map<String,String>\",\n      \"sourceType\": \"org.acme.Map\"\n    },\n    {\n      \"name\": \"spring.map.second\",\n      \"type\": \"java.util.Map<String,String>\",\n      \"sourceType\": \"org.acme.Map\"\n    },\n    {\n      \"name\": \"spring.map.keys\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Map\"\n    },\n    {\n      \"name\": \"spring.map.values\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.acme.Map\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.map.first.keys\",\n      \"values\": [\n        {\n          \"value\": \"one\",\n          \"description\": \"First.\"\n        },\n        {\n          \"value\": \"two\",\n          \"description\": \"Second.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.map.second.values\",\n      \"values\": [\n        {\n          \"value\": \"42\",\n          \"description\": \"Choose me.\"\n        },\n        {\n          \"value\": \"24\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.map.keys\",\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.map.values\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.lang.Integer\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-multi-groups.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"test.group.one.retry\",\n      \"type\": \"com.example.Retry\",\n      \"sourceType\": \"org.acme.config.TestApp\",\n      \"sourceMethod\": \"one()\"\n    },\n    {\n      \"name\": \"test.group.two.retry\",\n      \"type\": \"com.example.Retry\",\n      \"sourceType\": \"org.acme.config.TestApp\",\n      \"sourceMethod\": \"two()\"\n    },\n    {\n      \"name\": \"test.group.one.retry.specific\",\n      \"type\": \"com.example.Retry\",\n      \"sourceType\": \"org.acme.config.TestApp\",\n      \"sourceMethod\": \"two()\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"test.group.one.retry.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether publishing retries are enabled.\",\n      \"sourceType\": \"com.example.Retry\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"test.group.two.retry.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether publishing retries are enabled.\",\n      \"sourceType\": \"com.example.Retry\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"test.group.one.retry.specific.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether publishing retries are enabled.\",\n      \"sourceType\": \"com.example.Retry\",\n      \"defaultValue\": false\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata/src/test/resources/metadata/configuration-metadata-root.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.root.name\",\n      \"type\": \"java.lang.String\"\n    },\n    {\n      \"name\": \"spring.root2.name\"\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/build.gradle",
    "content": "import groovy.xml.XmlSlurper\n\n/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Configuration Metadata Changelog Generator\"\n\ndependencies {\n\timplementation(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\timplementation(project(\":configuration-metadata:spring-boot-configuration-metadata\"))\n\n\ttestImplementation(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nif (project.hasProperty(\"oldVersion\") && project.hasProperty(\"newVersion\")) {\n\tconfigurations {\n\t\toldMetadata {\n\t\t\ttransitive = false\n\t\t}\n\t\tnewMetadata {\n\t\t\ttransitive = false\n\t\t}\n\t}\n\tconfigurations.oldMetadata.dependencies.addAllLater(bootArtifactsFromBom(oldVersion))\n\tconfigurations.newMetadata.dependencies.addAllLater(bootArtifactsFromBom(newVersion))\n\tdef prepareOldMetadata = tasks.register(\"prepareOldMetadata\", Sync) {\n\t\tfrom(configurations.oldMetadata)\n\t\tdestinationDir = project.file(\"build/configuration-metadata-diff/$oldVersion\")\n\t}\n\tdef prepareNewMetadata = tasks.register(\"prepareNewMetadata\", Sync) {\n\t\tfrom(configurations.newMetadata)\n\t\tdestinationDir = project.file(\"build/configuration-metadata-diff/$newVersion\")\n\t}\n\ttasks.register(\"generate\", JavaExec) {\n\t\tinputs.files(prepareOldMetadata, prepareNewMetadata)\n\t\toutputs.file(project.file(\"build/configuration-metadata-changelog.adoc\"))\n\t\tclasspath = sourceSets.main.runtimeClasspath\n\t\tmainClass = 'org.springframework.boot.configurationmetadata.changelog.ChangelogGenerator'\n\t\targs = [project.file(\"build/configuration-metadata-diff/$oldVersion\"), project.file(\"build/configuration-metadata-diff/$newVersion\"), project.file(\"build/configuration-metadata-changelog.adoc\")]\n\t}\n}\n\ndef bootArtifactsFromBom(def version) {\n\tproject.provider {\n\t\tdef bomDependency = project.dependencies.create(\"org.springframework.boot:spring-boot-dependencies:$version@pom\")\n\t\tdef bom = new XmlSlurper().parse(configurations.detachedConfiguration(bomDependency).singleFile)\n\t\treturn bom.dependencyManagement.dependencies.dependency\n\t\t\t\t.findAll { it.groupId == \"org.springframework.boot\" }\n\t\t\t\t.collect { project.dependencies.create(\"org.springframework.boot:${it.artifactId}:$version\") }\n\t}\t\t\t\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/Changelog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.configurationmetadata.Deprecation.Level;\n\n/**\n * A changelog containing differences computed from two repositories of configuration\n * metadata.\n *\n * @param oldVersionNumber the name of the old version\n * @param newVersionNumber the name of the new version\n * @param differences the differences\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Yoobin Yoon\n */\nrecord Changelog(String oldVersionNumber, String newVersionNumber, List<Difference> differences) {\n\n\tstatic Changelog of(String oldVersionNumber, ConfigurationMetadataRepository oldMetadata, String newVersionNumber,\n\t\t\tConfigurationMetadataRepository newMetadata) {\n\t\treturn new Changelog(oldVersionNumber, newVersionNumber, computeDifferences(oldMetadata, newMetadata));\n\t}\n\n\tstatic List<Difference> computeDifferences(ConfigurationMetadataRepository oldMetadata,\n\t\t\tConfigurationMetadataRepository newMetadata) {\n\t\tList<String> seenIds = new ArrayList<>();\n\t\tList<Difference> differences = new ArrayList<>();\n\t\tfor (ConfigurationMetadataProperty oldProperty : oldMetadata.getAllProperties().values()) {\n\t\t\tString id = oldProperty.getId();\n\t\t\tseenIds.add(id);\n\t\t\tConfigurationMetadataProperty newProperty = newMetadata.getAllProperties().get(id);\n\t\t\tDifference difference = Difference.compute(oldProperty, newProperty);\n\t\t\tif (difference != null) {\n\t\t\t\tdifferences.add(difference);\n\t\t\t}\n\t\t}\n\t\tfor (ConfigurationMetadataProperty newProperty : newMetadata.getAllProperties().values()) {\n\t\t\tif (!seenIds.contains(newProperty.getId())) {\n\t\t\t\tif (!newProperty.isDeprecated()) {\n\t\t\t\t\tdifferences.add(new Difference(DifferenceType.ADDED, null, newProperty));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tDifferenceType differenceType = (newProperty.getDeprecation().getLevel() == Level.ERROR)\n\t\t\t\t\t\t\t? DifferenceType.DELETED : DifferenceType.ADDED;\n\t\t\t\t\tdifferences.add(new Difference(differenceType, null, newProperty));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn List.copyOf(differences);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/ChangelogGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;\n\n/**\n * Generates a configuration metadata changelog. Requires three arguments:\n *\n * <ol>\n * <li>The path of a directory containing jar files of the old version\n * <li>The path of a directory containing jar files of the new version\n * <li>The path of a file to which the asciidoc changelog will be written\n * </ol>\n *\n * The name of each directory will be used as version numbers in generated changelog.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic final class ChangelogGenerator {\n\n\tprivate ChangelogGenerator() {\n\t}\n\n\tpublic static void main(String[] args) throws IOException {\n\t\tgenerate(new File(args[0]), new File(args[1]), new File(args[2]));\n\t}\n\n\tprivate static void generate(File oldDir, File newDir, File out) throws IOException {\n\t\tString oldVersionNumber = oldDir.getName();\n\t\tConfigurationMetadataRepository oldMetadata = buildRepository(oldDir);\n\t\tString newVersionNumber = newDir.getName();\n\t\tConfigurationMetadataRepository newMetadata = buildRepository(newDir);\n\t\tChangelog changelog = Changelog.of(oldVersionNumber, oldMetadata, newVersionNumber, newMetadata);\n\t\ttry (ChangelogWriter writer = new ChangelogWriter(out)) {\n\t\t\twriter.write(changelog);\n\t\t}\n\t\tSystem.out.println(\"%nConfiguration metadata changelog written to '%s'\".formatted(out));\n\t}\n\n\tstatic ConfigurationMetadataRepository buildRepository(File directory) {\n\t\tConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create();\n\t\tFile[] files = directory.listFiles();\n\t\tif (files == null) {\n\t\t\tthrow new IllegalStateException(\"'files' must not be null\");\n\t\t}\n\t\tfor (File file : files) {\n\t\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\t\tJarEntry metadataEntry = jarFile.getJarEntry(\"META-INF/spring-configuration-metadata.json\");\n\t\t\t\tif (metadataEntry != null) {\n\t\t\t\t\tbuilder.withJsonResource(jarFile.getInputStream(metadataEntry));\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/ChangelogWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.text.BreakIterator;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\nimport org.springframework.boot.configurationmetadata.Deprecation;\n\n/**\n * Writes a {@link Changelog} using asciidoc markup.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass ChangelogWriter implements AutoCloseable {\n\n\tprivate static final Comparator<ConfigurationMetadataProperty> COMPARING_ID = Comparator\n\t\t.comparing(ConfigurationMetadataProperty::getId);\n\n\tprivate final PrintWriter out;\n\n\tChangelogWriter(File out) throws IOException {\n\t\tthis(new FileWriter(out));\n\t}\n\n\tChangelogWriter(Writer out) {\n\t\tthis.out = new PrintWriter(out);\n\t}\n\n\tvoid write(Changelog changelog) {\n\t\tString oldVersionNumber = changelog.oldVersionNumber();\n\t\tString newVersionNumber = changelog.newVersionNumber();\n\t\tMap<DifferenceType, List<Difference>> differencesByType = collateByType(changelog);\n\t\twrite(\"Configuration property changes between `%s` and `%s`%n\", oldVersionNumber, newVersionNumber);\n\t\twrite(\"%n%n%n== Default Changed in %s%n%n\", newVersionNumber);\n\t\twriteDefaultChanged(differencesByType.get(DifferenceType.DEFAULT_CHANGED));\n\t\twrite(\"%n%n%n== Deprecated in %s%n%n\", newVersionNumber);\n\t\twriteDeprecated(differencesByType.get(DifferenceType.DEPRECATED));\n\t\twrite(\"%n%n%n== Added in %s%n%n\", newVersionNumber);\n\t\twriteAdded(differencesByType.get(DifferenceType.ADDED));\n\t\twrite(\"%n%n%n== Removed in %s%n%n\", newVersionNumber);\n\t\twriteRemoved(differencesByType.get(DifferenceType.DELETED), differencesByType.get(DifferenceType.DEPRECATED));\n\t}\n\n\tprivate Map<DifferenceType, List<Difference>> collateByType(Changelog differences) {\n\t\tMap<DifferenceType, List<Difference>> byType = new HashMap<>();\n\t\tfor (DifferenceType type : DifferenceType.values()) {\n\t\t\tbyType.put(type, new ArrayList<>());\n\t\t}\n\t\tfor (Difference difference : differences.differences()) {\n\t\t\tbyType.get(difference.type()).add(difference);\n\t\t}\n\t\treturn byType;\n\t}\n\n\tprivate void writeDeprecated(List<Difference> differences) {\n\t\tList<Difference> rows = sortProperties(differences, Difference::newProperty).stream()\n\t\t\t.filter(this::isDeprecatedInRelease)\n\t\t\t.toList();\n\t\twriteTable(\"| Key | Replacement | Reason\", rows, this::writeDeprecated);\n\t}\n\n\tprivate void writeDeprecated(Difference difference) {\n\t\twriteDeprecatedPropertyRow(difference.newProperty());\n\t}\n\n\tprivate void writeDefaultChanged(List<Difference> differences) {\n\t\tList<Difference> rows = sortProperties(differences, Difference::newProperty);\n\t\twriteTable(\"| Key | Old Default | New Default\", rows, this::writeDefaultChanged);\n\t}\n\n\tprivate void writeDefaultChanged(Difference difference) {\n\t\twriteCell(monospace(difference.newProperty().getId()));\n\t\twriteCell(monospace(asString(difference.oldProperty().getDefaultValue())));\n\t\twriteCell(monospace(asString(difference.newProperty().getDefaultValue())));\n\t}\n\n\tprivate void writeAdded(List<Difference> differences) {\n\t\tList<Difference> rows = sortProperties(differences, Difference::newProperty);\n\t\twriteTable(\"| Key | Default value | Description\", rows, this::writeAdded);\n\t}\n\n\tprivate void writeAdded(Difference difference) {\n\t\tConfigurationMetadataProperty property = difference.newProperty();\n\t\twriteCell(monospace(property.getId()) + (property.isDeprecated() ? \" (deprecated)\" : \"\"));\n\t\twriteCell(monospace(asString(property.getDefaultValue())));\n\t\twriteCell(property.getShortDescription());\n\t}\n\n\tprivate void writeRemoved(List<Difference> deleted, List<Difference> deprecated) {\n\t\tList<Difference> rows = getRemoved(deleted, deprecated);\n\t\twriteTable(\"| Key | Replacement | Reason\", rows, this::writeRemoved);\n\t}\n\n\tprivate List<Difference> getRemoved(List<Difference> deleted, List<Difference> deprecated) {\n\t\tList<Difference> result = new ArrayList<>(deleted);\n\t\tdeprecated.stream().filter(Predicate.not(this::isDeprecatedInRelease)).forEach(result::remove);\n\t\treturn sortProperties(result,\n\t\t\t\t(difference) -> getFirstNonNull(difference, Difference::oldProperty, Difference::newProperty));\n\t}\n\n\tprivate void writeRemoved(Difference difference) {\n\t\twriteDeprecatedPropertyRow(getFirstNonNull(difference, Difference::newProperty, Difference::oldProperty));\n\t}\n\n\tprivate List<Difference> sortProperties(List<Difference> differences,\n\t\t\tFunction<Difference, ConfigurationMetadataProperty> extractor) {\n\t\treturn differences.stream().sorted(Comparator.comparing(extractor, COMPARING_ID)).toList();\n\t}\n\n\t@SafeVarargs\n\t@SuppressWarnings(\"varargs\")\n\tprivate <T, P> P getFirstNonNull(T t, Function<T, P>... extractors) {\n\t\treturn Stream.of(extractors)\n\t\t\t.map((extractor) -> extractor.apply(t))\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprivate void writeTable(String header, List<Difference> rows, Consumer<Difference> action) {\n\t\tif (rows.isEmpty()) {\n\t\t\twrite(\"_None_.%n\");\n\t\t}\n\t\telse {\n\t\t\twriteTableBreak();\n\t\t\twrite(header + \"%n%n\");\n\t\t\tfor (Iterator<Difference> iterator = rows.iterator(); iterator.hasNext();) {\n\t\t\t\taction.accept(iterator.next());\n\t\t\t\twrite((!iterator.hasNext()) ? null : \"%n\");\n\t\t\t}\n\t\t\twriteTableBreak();\n\t\t}\n\t}\n\n\tprivate void writeTableBreak() {\n\t\twrite(\"|======================%n\");\n\t}\n\n\tprivate void writeDeprecatedPropertyRow(ConfigurationMetadataProperty property) {\n\t\tDeprecation deprecation = (property.getDeprecation() != null) ? property.getDeprecation() : new Deprecation();\n\t\twriteCell(monospace(property.getId()));\n\t\twriteCell(monospace(deprecation.getReplacement()));\n\t\twriteCell(getFirstSentence(deprecation.getReason()));\n\t}\n\n\tprivate String getFirstSentence(String text) {\n\t\tif (text == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint dot = text.indexOf('.');\n\t\tif (dot != -1) {\n\t\t\tBreakIterator breakIterator = BreakIterator.getSentenceInstance(Locale.US);\n\t\t\tbreakIterator.setText(text);\n\t\t\tString sentence = text.substring(breakIterator.first(), breakIterator.next()).trim();\n\t\t\treturn removeSpaceBetweenLine(sentence);\n\t\t}\n\t\tString[] lines = text.split(System.lineSeparator());\n\t\treturn lines[0].trim();\n\t}\n\n\tprivate String removeSpaceBetweenLine(String text) {\n\t\tString[] lines = text.split(System.lineSeparator());\n\t\treturn Arrays.stream(lines).map(String::trim).collect(Collectors.joining(\" \"));\n\t}\n\n\tprivate boolean isDeprecatedInRelease(Difference difference) {\n\t\tDeprecation deprecation = difference.newProperty().getDeprecation();\n\t\treturn (deprecation != null) && (deprecation.getLevel() != Deprecation.Level.ERROR);\n\t}\n\n\tprivate String monospace(String value) {\n\t\treturn (value != null) ? \"`%s`\".formatted(value) : null;\n\t}\n\n\tprivate void writeCell(String content) {\n\t\tif (content == null) {\n\t\t\twrite(\"|%n\");\n\t\t}\n\t\telse {\n\t\t\tString escaped = escapeForTableCell(content);\n\t\t\twrite(\"| %s%n\".formatted(escaped));\n\t\t}\n\t}\n\n\tprivate String escapeForTableCell(String content) {\n\t\treturn content.replace(\"|\", \"\\\\|\").replace(\"%\", \"%%\");\n\t}\n\n\tprivate void write(String format, Object... args) {\n\t\tif (format != null) {\n\t\t\tObject[] strings = Arrays.stream(args).map(this::asString).toArray();\n\t\t\tthis.out.append(format.formatted(strings));\n\t\t}\n\t}\n\n\tprivate String asString(Object value) {\n\t\tif (value instanceof Object[] array) {\n\t\t\treturn Stream.of(array).map(this::asString).collect(Collectors.joining(\", \"));\n\t\t}\n\t\treturn (value != null) ? value.toString() : null;\n\t}\n\n\t@Override\n\tpublic void close() {\n\t\tthis.out.close();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/Difference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.util.Objects;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\nimport org.springframework.boot.configurationmetadata.Deprecation.Level;\n\n/**\n * A difference in the metadata.\n *\n * @param type the type of the difference\n * @param oldProperty the old property\n * @param newProperty the new property\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nrecord Difference(DifferenceType type, ConfigurationMetadataProperty oldProperty,\n\t\tConfigurationMetadataProperty newProperty) {\n\n\tstatic Difference compute(ConfigurationMetadataProperty oldProperty, ConfigurationMetadataProperty newProperty) {\n\t\tif (newProperty == null) {\n\t\t\tif (!(oldProperty.isDeprecated() && oldProperty.getDeprecation().getLevel() == Level.ERROR)) {\n\t\t\t\treturn new Difference(DifferenceType.DELETED, oldProperty, null);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tif (newProperty.isDeprecated() && !oldProperty.isDeprecated()) {\n\t\t\tLevel level = newProperty.getDeprecation().getLevel();\n\t\t\tDifferenceType differenceType = (level == Level.WARNING) ? DifferenceType.DEPRECATED\n\t\t\t\t\t: DifferenceType.DELETED;\n\t\t\treturn new Difference(differenceType, oldProperty, newProperty);\n\t\t}\n\t\tif (oldProperty.isDeprecated() && oldProperty.getDeprecation().getLevel() == Level.WARNING\n\t\t\t\t&& newProperty.isDeprecated() && newProperty.getDeprecation().getLevel() == Level.ERROR) {\n\t\t\treturn new Difference(DifferenceType.DELETED, oldProperty, newProperty);\n\t\t}\n\t\tif (!Objects.deepEquals(oldProperty.getDefaultValue(), newProperty.getDefaultValue())) {\n\t\t\treturn new Difference(DifferenceType.DEFAULT_CHANGED, oldProperty, newProperty);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/DifferenceType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\n/**\n * The type of a difference in the metadata.\n *\n * @author Andy Wilkinson\n */\nenum DifferenceType {\n\n\t/**\n\t * The entry has been added.\n\t */\n\tADDED,\n\n\t/**\n\t * The entry has been made deprecated. It may or may not still exist in the previous\n\t * version.\n\t */\n\tDEPRECATED,\n\n\t/**\n\t * The entry has been deleted.\n\t */\n\tDELETED,\n\n\t/**\n\t * The entry's default value has changed. The entry exists in both the previous and\n\t * current versions, but its default value is different.\n\t */\n\tDEFAULT_CHANGED\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/main/java/org/springframework/boot/configurationmetadata/changelog/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot configuration metadata changelog generator.\n */\npackage org.springframework.boot.configurationmetadata.changelog;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/java/org/springframework/boot/configurationmetadata/changelog/ChangelogGeneratorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ChangelogGenerator}.\n *\n * @author Phillip Webb\n */\nclass ChangelogGeneratorTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid generateChangeLog() throws IOException {\n\t\tFile oldJars = new File(this.temp, \"1.0\");\n\t\taddJar(oldJars, \"sample-1.0.json\");\n\t\tFile newJars = new File(this.temp, \"2.0\");\n\t\taddJar(newJars, \"sample-2.0.json\");\n\t\tFile out = new File(this.temp, \"changes.adoc\");\n\t\tString[] args = new String[] { oldJars.getAbsolutePath(), newJars.getAbsolutePath(), out.getAbsolutePath() };\n\t\tChangelogGenerator.main(args);\n\t\tassertThat(out).usingCharset(StandardCharsets.UTF_8)\n\t\t\t.hasSameTextualContentAs(new File(\"src/test/resources/sample.adoc\"));\n\t}\n\n\tprivate void addJar(File directory, String filename) throws IOException {\n\t\tdirectory.mkdirs();\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(new File(directory, \"sample.jar\")))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"META-INF/spring-configuration-metadata.json\"));\n\t\t\ttry (InputStream in = new FileInputStream(\"src/test/resources/\" + filename)) {\n\t\t\t\tin.transferTo(out);\n\t\t\t\tout.closeEntry();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/java/org/springframework/boot/configurationmetadata/changelog/ChangelogTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Changelog}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Yoobin Yoon\n */\nclass ChangelogTests {\n\n\t@Test\n\tvoid diffContainsDifferencesBetweenLeftAndRightInputs() {\n\t\tChangelog differences = TestChangelog.load();\n\t\tassertThat(differences).isNotNull();\n\t\tassertThat(differences.oldVersionNumber()).isEqualTo(\"1.0\");\n\t\tassertThat(differences.newVersionNumber()).isEqualTo(\"2.0\");\n\t\tassertThat(differences.differences()).hasSize(9);\n\t\tList<Difference> added = differences.differences()\n\t\t\t.stream()\n\t\t\t.filter((difference) -> difference.type() == DifferenceType.ADDED)\n\t\t\t.toList();\n\t\tassertThat(added).hasSize(2)\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.newProperty(), \"test.add\", String.class, \"new\"))\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.newProperty(), \"test.add.deprecated\", String.class, \"test2\"));\n\t\tList<Difference> deleted = differences.differences()\n\t\t\t.stream()\n\t\t\t.filter((difference) -> difference.type() == DifferenceType.DELETED)\n\t\t\t.toList();\n\t\tassertThat(deleted).hasSize(4)\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.oldProperty(), \"test.replace\", String.class, \"replace\"))\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.oldProperty(), \"test.delete\", String.class, \"delete\"))\n\t\t\t.anySatisfy(\n\t\t\t\t\t(entry) -> assertProperty(entry.newProperty(), \"test.delete.deprecated\", String.class, \"delete\"))\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.newProperty(), \"test.removed.directly\", String.class,\n\t\t\t\t\t\"directlyRemoved\"));\n\t\tList<Difference> deprecated = differences.differences()\n\t\t\t.stream()\n\t\t\t.filter((difference) -> difference.type() == DifferenceType.DEPRECATED)\n\t\t\t.toList();\n\t\tassertThat(deprecated).hasSize(1);\n\t\tassertProperty(deprecated.get(0).oldProperty(), \"test.deprecate\", String.class, \"wrong\");\n\t\tassertProperty(deprecated.get(0).newProperty(), \"test.deprecate\", String.class, \"wrong\");\n\t\tList<Difference> defaultChanged = differences.differences()\n\t\t\t.stream()\n\t\t\t.filter((difference) -> difference.type() == DifferenceType.DEFAULT_CHANGED)\n\t\t\t.toList();\n\t\tassertThat(defaultChanged).hasSize(2)\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.newProperty(), \"test.default.array.change\", String[].class,\n\t\t\t\t\tnew String[] { \"b\", \"a\" }))\n\t\t\t.anySatisfy((entry) -> assertProperty(entry.newProperty(), \"test.default.change\", String.class, \"new\"));\n\t}\n\n\tprivate void assertProperty(ConfigurationMetadataProperty property, String id, Class<?> type, Object defaultValue) {\n\t\tassertThat(property).isNotNull();\n\t\tassertThat(property.getId()).isEqualTo(id);\n\t\tassertThat(property.getType()).isEqualTo(type.getCanonicalName());\n\t\tassertThat(property.getDefaultValue()).isEqualTo(defaultValue);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/java/org/springframework/boot/configurationmetadata/changelog/ChangelogWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.io.File;\nimport java.io.StringWriter;\nimport java.nio.charset.StandardCharsets;\n\nimport org.assertj.core.util.Files;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ChangelogWriter}.\n *\n * @author Phillip Webb\n */\nclass ChangelogWriterTests {\n\n\t@Test\n\tvoid writeChangelog() {\n\t\tStringWriter out = new StringWriter();\n\t\ttry (ChangelogWriter writer = new ChangelogWriter(out)) {\n\t\t\twriter.write(TestChangelog.load());\n\t\t}\n\t\tString expected = Files.contentOf(new File(\"src/test/resources/sample.adoc\"), StandardCharsets.UTF_8);\n\t\tassertThat(out).hasToString(expected);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/java/org/springframework/boot/configurationmetadata/changelog/DifferenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Difference}.\n *\n * @author Stephane Nicoll\n */\nclass DifferenceTests {\n\n\tprivate static ConfigurationMetadataProperty createProperty(String id, Object defaultValue) {\n\t\tConfigurationMetadataProperty property = new ConfigurationMetadataProperty();\n\t\tproperty.setId(id);\n\t\tproperty.setDefaultValue(defaultValue);\n\t\treturn property;\n\t}\n\n\t@Nested\n\tclass DefaultChangedTests {\n\n\t\t@Test\n\t\tvoid sameValueComputesNoDifference() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", \"test\"),\n\t\t\t\t\tcreateProperty(\"test.id\", \"test\"));\n\t\t\tassertThat(difference).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid bothNullComputesNoDifference() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", null),\n\t\t\t\t\tcreateProperty(\"test.id\", null));\n\t\t\tassertThat(difference).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid nullThenNotNullDefaultChanged() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", null),\n\t\t\t\t\tcreateProperty(\"test.id\", \"test\"));\n\t\t\tassertThat(difference).isNotNull();\n\t\t\tassertThat(difference.type()).isEqualTo(DifferenceType.DEFAULT_CHANGED);\n\t\t}\n\n\t\t@Test\n\t\tvoid notNullThenNullDefaultChanged() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", \"test\"),\n\t\t\t\t\tcreateProperty(\"test.id\", null));\n\t\t\tassertThat(difference).isNotNull();\n\t\t\tassertThat(difference.type()).isEqualTo(DifferenceType.DEFAULT_CHANGED);\n\t\t}\n\n\t\t@Test\n\t\tvoid arrayEqualsComputesNoDifference() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", new Object[] { \"one\", \"two\" }),\n\t\t\t\t\tcreateProperty(\"test.id\", new Object[] { \"one\", \"two\" }));\n\t\t\tassertThat(difference).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid arrayOrderChangedComputesDefaultChanged() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", new Object[] { \"one\", \"two\" }),\n\t\t\t\t\tcreateProperty(\"test.id\", new Object[] { \"two\", \"one\" }));\n\t\t\tassertThat(difference).isNotNull();\n\t\t\tassertThat(difference.type()).isEqualTo(DifferenceType.DEFAULT_CHANGED);\n\t\t}\n\n\t\t@Test\n\t\tvoid arrayAdditionalValueComputesDefaultChanged() {\n\t\t\tDifference difference = Difference.compute(createProperty(\"test.id\", new Object[] { \"one\", \"two\" }),\n\t\t\t\t\tcreateProperty(\"test.id\", new Object[] { \"one\", \"two\", \"three\" }));\n\t\t\tassertThat(difference).isNotNull();\n\t\t\tassertThat(difference.type()).isEqualTo(DifferenceType.DEFAULT_CHANGED);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/java/org/springframework/boot/configurationmetadata/changelog/TestChangelog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationmetadata.changelog;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;\n\n/**\n * Factory to create test {@link Changelog} instance.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nfinal class TestChangelog {\n\n\tprivate TestChangelog() {\n\t}\n\n\tstatic Changelog load() {\n\t\tConfigurationMetadataRepository previousRepository = load(\"sample-1.0.json\");\n\t\tConfigurationMetadataRepository repository = load(\"sample-2.0.json\");\n\t\treturn Changelog.of(\"1.0\", previousRepository, \"2.0\", repository);\n\t}\n\n\tprivate static ConfigurationMetadataRepository load(String filename) {\n\t\ttry (InputStream inputStream = new FileInputStream(\"src/test/resources/\" + filename)) {\n\t\t\treturn ConfigurationMetadataRepositoryJsonBuilder.create(inputStream).build();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/resources/sample-1.0.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"test.equal\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test equality.\",\n      \"defaultValue\": \"test\"\n    },\n    {\n      \"name\": \"test.default.change\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test default value change.\",\n      \"defaultValue\": \"old\"\n    },\n    {\n      \"name\": \"test.default.array.change\",\n      \"type\": \"java.lang.String[]\",\n      \"description\": \"Test default array value change.\",\n      \"defaultValue\": [\"a\", \"b\"]\n    },\n    {\n      \"name\": \"test.replace\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test Replace.\",\n      \"defaultValue\": \"replace\"\n    },\n    {\n      \"name\": \"test.deprecate\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test deprecate.\",\n      \"defaultValue\": \"wrong\"\n    },\n    {\n      \"name\": \"test.delete\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test delete.\",\n      \"defaultValue\": \"delete\"\n    },\n    {\n      \"name\": \"test.delete.deprecated\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test delete deprecated.\",\n      \"defaultValue\": \"delete\",\n      \"deprecation\": {\n        \"level\": \"warning\"\n      }\n    },\n    {\n      \"name\": \"test.delete.error\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test delete error.\",\n      \"defaultValue\": \"delete\",\n      \"deprecation\": {\n        \"level\": \"error\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/resources/sample-2.0.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"test.add\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test add.\",\n      \"defaultValue\": \"new\"\n    },\n    {\n      \"name\": \"test.default.change\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test default value change.\",\n      \"defaultValue\": \"new\"\n    },\n    {\n      \"name\": \"test.default.array.change\",\n      \"type\": \"java.lang.String[]\",\n      \"description\": \"Test default array value change.\",\n      \"defaultValue\": [\"b\", \"a\"]\n    },\n    {\n      \"name\": \"test.replace\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"test.add\"\n      }\n    },\n    {\n      \"name\": \"test.add.deprecated\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test add deprecated.\",\n      \"defaultValue\": \"test2\",\n      \"deprecation\": {\n        \"replacement\": \"test.equal\",\n        \"reason\": \"Deprecated  in favor of Equal\"\n      }\n    },\n    {\n      \"name\": \"test.equal\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test equality.\",\n      \"defaultValue\": \"test\"\n    },\n    {\n      \"name\": \"test.deprecate\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test deprecate.\",\n      \"defaultValue\": \"wrong\",\n      \"deprecation\": {\n        \"level\": \"warn\"\n      }\n    },\n    {\n      \"name\": \"test.delete.deprecated\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test delete deprecated.\",\n      \"defaultValue\": \"delete\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"test.add\",\n        \"reason\": \"it was just bad\"\n      }\n    },\n    {\n      \"name\": \"test.removed.directly\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Test property removed without prior deprecation.\",\n      \"defaultValue\": \"directlyRemoved\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"test.new.property\",\n        \"reason\": \"removed in third-party library without deprecation\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-metadata-changelog-generator/src/test/resources/sample.adoc",
    "content": "Configuration property changes between `1.0` and `2.0`\n\n\n\n== Default Changed in 2.0\n\n|======================\n| Key | Old Default | New Default\n\n| `test.default.array.change`\n| `a, b`\n| `b, a`\n\n| `test.default.change`\n| `old`\n| `new`\n|======================\n\n\n\n== Deprecated in 2.0\n\n|======================\n| Key | Replacement | Reason\n\n| `test.deprecate`\n|\n|\n|======================\n\n\n\n== Added in 2.0\n\n|======================\n| Key | Default value | Description\n\n| `test.add`\n| `new`\n| Test add.\n\n| `test.add.deprecated` (deprecated)\n| `test2`\n| Test add deprecated.\n|======================\n\n\n\n== Removed in 2.0\n\n|======================\n| Key | Replacement | Reason\n\n| `test.delete`\n|\n|\n\n| `test.delete.deprecated`\n| `test.add`\n| it was just bad\n\n| `test.removed.directly`\n| `test.new.property`\n| removed in third-party library without deprecation\n\n| `test.replace`\n| `test.add`\n|\n|======================\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.annotation-processor\"\n}\n\ndescription = \"Spring Boot Configuration Annotation Processor\"\n\nsourceSets {\n\tmain {\n\t\tjava {\n\t\t\tsrcDir file(\"src/json-shade/java\")\n\t\t}\n\t}\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\ndependencies {\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305:3.0.2\")\n\ttestCompileOnly(\"org.jspecify:jspecify\")\n\n\ttestImplementation(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"jakarta.validation:jakarta.validation-api\")\n\ttestImplementation(\"org.projectlombok:lombok\")\n\ttestImplementation(\"org.apache.commons:commons-dbcp2\")\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/README.adoc",
    "content": "## Shaded JSON\n\nThis source was originally taken from `com.vaadin.external.google:android-json` which\nprovides a clean room re-implementation of the `org.json` APIs and does not include the\n\"Do not use for evil\" clause.\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSON.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.json;\n\nclass JSON {\n\n\tstatic double checkDouble(double d) throws JSONException {\n\t\tif (Double.isInfinite(d) || Double.isNaN(d)) {\n\t\t\tthrow new JSONException(\"Forbidden numeric value: \" + d);\n\t\t}\n\t\treturn d;\n\t}\n\n\tstatic Boolean toBoolean(Object value) {\n\t\tif (value instanceof Boolean) {\n\t\t\treturn (Boolean) value;\n\t\t}\n\t\tif (value instanceof String stringValue) {\n\t\t\tif (\"true\".equalsIgnoreCase(stringValue)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\"false\".equalsIgnoreCase(stringValue)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Double toDouble(Object value) {\n\t\tif (value instanceof Double) {\n\t\t\treturn (Double) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).doubleValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn Double.valueOf((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Integer toInteger(Object value) {\n\t\tif (value instanceof Integer) {\n\t\t\treturn (Integer) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).intValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn (int) Double.parseDouble((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic Long toLong(Object value) {\n\t\tif (value instanceof Long) {\n\t\t\treturn (Long) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).longValue();\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\ttry {\n\t\t\t\treturn (long) Double.parseDouble((String) value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic String toString(Object value) {\n\t\tif (value instanceof String) {\n\t\t\treturn (String) value;\n\t\t}\n\t\tif (value != null) {\n\t\t\treturn String.valueOf(value);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static JSONException typeMismatch(Object indexOrName, Object actual, String requiredType)\n\t\t\tthrows JSONException {\n\t\tif (actual == null) {\n\t\t\tthrow new JSONException(\"Value at \" + indexOrName + \" is null.\");\n\t\t}\n\t\tthrow new JSONException(\"Value \" + actual + \" at \" + indexOrName + \" of type \" + actual.getClass().getName()\n\t\t\t\t+ \" cannot be converted to \" + requiredType);\n\t}\n\n\tpublic static JSONException typeMismatch(Object actual, String requiredType) throws JSONException {\n\t\tif (actual == null) {\n\t\t\tthrow new JSONException(\"Value is null.\");\n\t\t}\n\t\tthrow new JSONException(\"Value \" + actual + \" of type \" + actual.getClass().getName()\n\t\t\t\t+ \" cannot be converted to \" + requiredType);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONArray.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.json;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * A dense indexed sequence of values. Values may be any mix of {@link JSONObject\n * JSONObjects}, other {@link JSONArray JSONArrays}, Strings, Booleans, Integers, Longs,\n * Doubles, {@code null} or {@link JSONObject#NULL}. Values may not be\n * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not\n * listed here.\n * <p>\n * {@code JSONArray} has the same type coercion behavior and optional/mandatory accessors\n * as {@link JSONObject}. See that class' documentation for details.\n * <p>\n * <strong>Warning:</strong> this class represents null in two incompatible ways: the\n * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.\n * In particular, {@code get} fails if the requested index holds the null reference, but\n * succeeds if it holds {@code JSONObject.NULL}.\n * <p>\n * Instances of this class are not thread safe. Although this class is nonfinal, it was\n * not designed for inheritance and should not be subclassed. In particular, self-use by\n * overridable methods is not specified. See <i>Effective Java</i> Item 17, \"Design and\n * Document or inheritance or else prohibit it\" for further information.\n */\npublic class JSONArray {\n\n\tprivate final List<Object> values;\n\n\t/**\n\t * Creates a {@code JSONArray} with no values.\n\t */\n\tpublic JSONArray() {\n\t\tthis.values = new ArrayList<>();\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} by copying all values from the given collection.\n\t * @param copyFrom a collection whose values are of supported types. Unsupported\n\t * values are not permitted and will yield an array in an inconsistent state.\n\t */\n\t/* Accept a raw type for API compatibility */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic JSONArray(Collection copyFrom) {\n\t\tthis();\n\t\tif (copyFrom != null) {\n\t\t\tfor (Iterator it = copyFrom.iterator(); it.hasNext();) {\n\t\t\t\tput(JSONObject.wrap(it.next()));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the next array in the tokener.\n\t * @param readFrom a tokener whose nextValue() method will yield a {@code JSONArray}.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code JSONArray}.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray(JSONTokener readFrom) throws JSONException {\n\t\t/*\n\t\t * Getting the parser to populate this could get tricky. Instead, just parse to\n\t\t * temporary JSONArray and then steal the data from that.\n\t\t */\n\t\tObject object = readFrom.nextValue();\n\t\tif (object instanceof JSONArray) {\n\t\t\tthis.values = ((JSONArray) object).values;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the JSON string.\n\t * @param json a JSON-encoded string containing an array.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray(String json) throws JSONException {\n\t\tthis(new JSONTokener(json));\n\t}\n\n\t/**\n\t * Creates a new {@code JSONArray} with values from the given primitive array.\n\t * @param array a primitive array\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray(Object array) throws JSONException {\n\t\tif (!array.getClass().isArray()) {\n\t\t\tthrow new JSONException(\"Not a primitive array: \" + array.getClass());\n\t\t}\n\t\tfinal int length = Array.getLength(array);\n\t\tthis.values = new ArrayList<>(length);\n\t\tfor (int i = 0; i < length; ++i) {\n\t\t\tput(JSONObject.wrap(Array.get(array, i)));\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of values in this array.\n\t * @return the length of this array\n\t */\n\tpublic int length() {\n\t\treturn this.values.size();\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(boolean value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(double value) throws JSONException {\n\t\tthis.values.add(JSON.checkDouble(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(int value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value the value\n\t * @return this array.\n\t */\n\tpublic JSONArray put(long value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Appends {@code value} to the end of this array.\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be\n\t * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}. Unsupported\n\t * values are not permitted and will cause the array to be in an inconsistent state.\n\t * @return this array.\n\t */\n\tpublic JSONArray put(Object value) {\n\t\tthis.values.add(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, boolean value) throws JSONException {\n\t\treturn put(index, (Boolean) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, double value) throws JSONException {\n\t\treturn put(index, (Double) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, int value) throws JSONException {\n\t\treturn put(index, (Integer) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value the value\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, long value) throws JSONException {\n\t\treturn put(index, (Long) value);\n\t}\n\n\t/**\n\t * Sets the value at {@code index} to {@code value}, null padding this array to the\n\t * required length if necessary. If a value already exists at {@code\n\t * index}, it will be replaced.\n\t * @param index the index to set the value to\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link JSONObject#NULL}, or {@code null}. May not be\n\t * {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.\n\t * @return this array.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONArray put(int index, Object value) throws JSONException {\n\t\tif (value instanceof Number) {\n\t\t\t// deviate from the original by checking all Numbers, not just floats &\n\t\t\t// doubles\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\t\twhile (this.values.size() <= index) {\n\t\t\tthis.values.add(null);\n\t\t}\n\t\tthis.values.set(index, value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns true if this array has no value at {@code index}, or if its value is the\n\t * {@code null} reference or {@link JSONObject#NULL}.\n\t * @param index the index to set the value to\n\t * @return true if this array has no value at {@code index}\n\t */\n\tpublic boolean isNull(int index) {\n\t\tObject value = opt(index);\n\t\treturn value == null || value == JSONObject.NULL;\n\t}\n\n\t/**\n\t * Returns the value at {@code index}.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index}.\n\t * @throws JSONException if this array has no value at {@code index}, or if that value\n\t * is the {@code null} reference. This method returns normally if the value is\n\t * {@code JSONObject#NULL}.\n\t */\n\tpublic Object get(int index) throws JSONException {\n\t\ttry {\n\t\t\tObject value = this.values.get(index);\n\t\t\tif (value == null) {\n\t\t\t\tthrow new JSONException(\"Value at \" + index + \" is null.\");\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\t\tcatch (IndexOutOfBoundsException e) {\n\t\t\tthrow new JSONException(\"Index \" + index + \" out of range [0..\" + this.values.size() + \")\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index}, or null if the array has no value at\n\t * {@code index}.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index} or {@code null}\n\t */\n\tpublic Object opt(int index) {\n\t\tif (index < 0 || index >= this.values.size()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.values.get(index);\n\t}\n\n\t/**\n\t * Removes and returns the value at {@code index}, or null if the array has no value\n\t * at {@code index}.\n\t * @param index the index of the value to remove\n\t * @return the previous value at {@code index}\n\t */\n\tpublic Object remove(int index) {\n\t\tif (index < 0 || index >= this.values.size()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.values.remove(index);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean.\n\t * @param index the index to get the value from\n\t * @return the value at {@code index}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a boolean.\n\t */\n\tpublic boolean getBoolean(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"boolean\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean. Returns false otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code false}\n\t */\n\tpublic boolean optBoolean(int index) {\n\t\treturn optBoolean(index, false);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a boolean or can be coerced\n\t * to a boolean. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic boolean optBoolean(int index, boolean fallback) {\n\t\tObject object = opt(index);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a double.\n\t */\n\tpublic double getDouble(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tDouble result = JSON.toDouble(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"double\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double. Returns {@code NaN} otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code NaN}\n\t */\n\tpublic double optDouble(int index) {\n\t\treturn optDouble(index, Double.NaN);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a double or can be coerced\n\t * to a double. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic double optDouble(int index, double fallback) {\n\t\tObject object = opt(index);\n\t\tDouble result = JSON.toDouble(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to an int.\n\t */\n\tpublic int getInt(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tInteger result = JSON.toInteger(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"int\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int. Returns 0 otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code 0}\n\t */\n\tpublic int optInt(int index) {\n\t\treturn optInt(index, 0);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is an int or can be coerced to\n\t * an int. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic int optInt(int index, int fallback) {\n\t\tObject object = opt(index);\n\t\tInteger result = JSON.toInteger(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if the value at {@code index} doesn't exist or cannot be\n\t * coerced to a long.\n\t */\n\tpublic long getLong(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tLong result = JSON.toLong(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"long\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long. Returns 0 otherwise.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or {@code 0}\n\t */\n\tpublic long optLong(int index) {\n\t\treturn optLong(index, 0L);\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a long or can be coerced to\n\t * a long. Returns {@code fallback} otherwise.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic long optLong(int index, long fallback) {\n\t\tObject object = opt(index);\n\t\tLong result = JSON.toLong(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary.\n\t * @param index the index to get the value from\n\t * @return the {@code value}\n\t * @throws JSONException if no such value exists.\n\t */\n\tpublic String getString(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tString result = JSON.toString(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(index, object, \"String\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary. Returns\n\t * the empty string if no such value exists.\n\t * @param index the index to get the value from\n\t * @return the {@code value} or an empty string\n\t */\n\tpublic String optString(int index) {\n\t\treturn optString(index, \"\");\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists, coercing it if necessary. Returns\n\t * {@code fallback} if no such value exists.\n\t * @param index the index to get the value from\n\t * @param fallback the fallback value\n\t * @return the value at {@code index} of {@code fallback}\n\t */\n\tpublic String optString(int index, String fallback) {\n\t\tObject object = opt(index);\n\t\tString result = JSON.toString(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONArray}.\n\t * @param index the index to get the value from\n\t * @return the array at {@code index}\n\t * @throws JSONException if the value doesn't exist or is not a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray getJSONArray(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tif (object instanceof JSONArray) {\n\t\t\treturn (JSONArray) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(index, object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONArray}. Returns null otherwise.\n\t * @param index the index to get the value from\n\t * @return the array at {@code index} or {@code null}\n\t */\n\tpublic JSONArray optJSONArray(int index) {\n\t\tObject object = opt(index);\n\t\treturn object instanceof JSONArray ? (JSONArray) object : null;\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONObject}.\n\t * @param index the index to get the value from\n\t * @return the object at {@code index}\n\t * @throws JSONException if the value doesn't exist or is not a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject getJSONObject(int index) throws JSONException {\n\t\tObject object = get(index);\n\t\tif (object instanceof JSONObject) {\n\t\t\treturn (JSONObject) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(index, object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value at {@code index} if it exists and is a {@code\n\t * JSONObject}. Returns null otherwise.\n\t * @param index the index to get the value from\n\t * @return the object at {@code index} or {@code null}\n\t */\n\tpublic JSONObject optJSONObject(int index) {\n\t\tObject object = opt(index);\n\t\treturn object instanceof JSONObject ? (JSONObject) object : null;\n\t}\n\n\t/**\n\t * Returns a new object whose values are the values in this array, and whose names are\n\t * the values in {@code names}. Names and values are paired up by index from 0 through\n\t * to the shorter array's length. Names that are not strings will be coerced to\n\t * strings. This method returns null if either array is empty.\n\t * @param names the property names\n\t * @return a json object\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONObject toJSONObject(JSONArray names) throws JSONException {\n\t\tJSONObject result = new JSONObject();\n\t\tint length = Math.min(names.length(), this.values.size());\n\t\tif (length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString name = JSON.toString(names.opt(i));\n\t\t\tresult.put(name, opt(i));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a new string by alternating this array's values with {@code\n\t * separator}. This array's string values are quoted and have their special characters\n\t * escaped. For example, the array containing the strings '12\" pizza', 'taco' and\n\t * 'soda' joined on '+' returns this: <pre>\"12\\\" pizza\"+\"taco\"+\"soda\"</pre>\n\t * @param separator the separator to use\n\t * @return the joined value\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String join(String separator) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer();\n\t\tstringer.open(JSONStringer.Scope.NULL, \"\");\n\t\tfor (int i = 0, size = this.values.size(); i < size; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tstringer.out.append(separator);\n\t\t\t}\n\t\t\tstringer.value(this.values.get(i));\n\t\t}\n\t\tstringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, \"\");\n\t\treturn stringer.out.toString();\n\t}\n\n\t/**\n\t * Encodes this array as a compact JSON string, such as: <pre>[94043,90210]</pre>\n\t * @return a compact JSON string representation of this array\n\t */\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\twriteTo(stringer);\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Encodes this array as a human-readable JSON string for debugging, such as: <pre>\n\t * [\n\t *     94043,\n\t *     90210\n\t * ]</pre>\n\t * @param indentSpaces the number of spaces to indent for each level of nesting.\n\t * @return a human-readable JSON string of this array\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String toString(int indentSpaces) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer(indentSpaces);\n\t\twriteTo(stringer);\n\t\treturn stringer.toString();\n\t}\n\n\tvoid writeTo(JSONStringer stringer) throws JSONException {\n\t\tstringer.array();\n\t\tfor (Object value : this.values) {\n\t\t\tstringer.value(value);\n\t\t}\n\t\tstringer.endArray();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\treturn o instanceof JSONArray && ((JSONArray) o).values.equals(this.values);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\t// diverge from the original, which doesn't implement hashCode\n\t\treturn this.values.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONException.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.json;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Thrown to indicate a problem with the JSON API. Such problems include:\n * <ul>\n * <li>Attempts to parse or construct malformed documents\n * <li>Use of null as a name\n * <li>Use of numeric types not available to JSON, such as {@link Double#isNaN() NaNs} or\n * {@link Double#isInfinite() infinities}.\n * <li>Lookups using an out of range index or nonexistent name\n * <li>Type mismatches on lookups\n * </ul>\n * <p>\n * Although this is a checked exception, it is rarely recoverable. Most callers should\n * simply wrap this exception in an unchecked exception and rethrow: <pre class=\"code\">\n *     public JSONArray toJSONObject() {\n *     try {\n *         JSONObject result = new JSONObject();\n *         ...\n *     } catch (JSONException e) {\n *         throw new RuntimeException(e);\n *     }\n * }</pre>\n */\npublic class JSONException extends Exception {\n\n\tpublic JSONException(String s) {\n\t\tsuper(s);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONObject.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.json;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * A modifiable set of name/value mappings. Names are unique, non-null strings. Values may\n * be any mix of {@link JSONObject JSONObjects}, {@link JSONArray JSONArrays}, Strings,\n * Booleans, Integers, Longs, Doubles or {@link #NULL}. Values may not be {@code null},\n * {@link Double#isNaN() NaNs}, {@link Double#isInfinite() infinities}, or of any type not\n * listed here.\n * <p>\n * This class can coerce values to another type when requested.\n * <ul>\n * <li>When the requested type is a boolean, strings will be coerced using a\n * case-insensitive comparison to \"true\" and \"false\".\n * <li>When the requested type is a double, other {@link Number} types will be coerced\n * using {@link Number#doubleValue() doubleValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be.\n * <li>When the requested type is an int, other {@link Number} types will be coerced using\n * {@link Number#intValue() intValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be, and then cast to int.\n * <li><a id=\"lossy\">When the requested type is a long, other {@link Number} types will be\n * coerced using {@link Number#longValue() longValue}. Strings that can be coerced using\n * {@link Double#valueOf(String)} will be, and then cast to long. This two-step conversion\n * is lossy for very large values. For example, the string \"9223372036854775806\" yields\n * the long 9223372036854775807.</a>\n * <li>When the requested type is a String, other non-null values will be coerced using\n * {@link String#valueOf(Object)}. Although null cannot be coerced, the sentinel value\n * {@link JSONObject#NULL} is coerced to the string \"null\".\n * </ul>\n * <p>\n * This class can look up both mandatory and optional values:\n * <ul>\n * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This fails with a\n * {@code JSONException} if the requested name has no value or if the value cannot be\n * coerced to the requested type.\n * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This returns a\n * system- or user-supplied default if the requested name has no value or if the value\n * cannot be coerced to the requested type.\n * </ul>\n * <p>\n * <strong>Warning:</strong> this class represents null in two incompatible ways: the\n * standard Java {@code null} reference, and the sentinel value {@link JSONObject#NULL}.\n * In particular, calling {@code put(name, null)} removes the named entry from the object\n * but {@code put(name, JSONObject.NULL)} stores an entry whose value is\n * {@code JSONObject.NULL}.\n * <p>\n * Instances of this class are not thread safe. Although this class is nonfinal, it was\n * not designed for inheritance and should not be subclassed. In particular, self-use by\n * overrideable methods is not specified. See <i>Effective Java</i> Item 17, \"Design and\n * Document or inheritance or else prohibit it\" for further information.\n */\npublic class JSONObject {\n\n\tprivate static final Double NEGATIVE_ZERO = -0d;\n\n\t/**\n\t * A sentinel value used to explicitly define a name with no value. Unlike\n\t * {@code null}, names with this value:\n\t * <ul>\n\t * <li>show up in the {@link #names} array\n\t * <li>show up in the {@link #keys} iterator\n\t * <li>return {@code true} for {@link #has(String)}\n\t * <li>do not throw on {@link #get(String)}\n\t * <li>are included in the encoded JSON string.\n\t * </ul>\n\t * <p>\n\t * This value violates the general contract of {@link Object#equals} by returning true\n\t * when compared to {@code null}. Its {@link #toString} method returns \"null\".\n\t */\n\tpublic static final Object NULL = new Object() {\n\n\t\t@Override\n\t\tpublic boolean equals(Object o) {\n\t\t\treturn o == this || o == null; // API specifies this broken equals\n\t\t\t\t\t\t\t\t\t\t\t// implementation\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"null\";\n\t\t}\n\n\t};\n\n\tprivate final Map<String, Object> nameValuePairs;\n\n\t/**\n\t * Creates a {@code JSONObject} with no name/value mappings.\n\t */\n\tpublic JSONObject() {\n\t\tthis.nameValuePairs = new LinkedHashMap<>();\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} by copying all name/value mappings from the given\n\t * map.\n\t * @param copyFrom a map whose keys are of type {@link String} and whose values are of\n\t * supported types.\n\t * @throws NullPointerException if any of the map's keys are null.\n\t */\n\t/* (accept a raw type for API compatibility) */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic JSONObject(Map copyFrom) {\n\t\tthis();\n\t\tMap<?, ?> contentsTyped = copyFrom;\n\t\tfor (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {\n\t\t\t/*\n\t\t\t * Deviate from the original by checking that keys are non-null and of the\n\t\t\t * proper type. (We still defer validating the values).\n\t\t\t */\n\t\t\tString key = (String) entry.getKey();\n\t\t\tif (key == null) {\n\t\t\t\tthrow new NullPointerException(\"key == null\");\n\t\t\t}\n\t\t\tthis.nameValuePairs.put(key, wrap(entry.getValue()));\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} with name/value mappings from the next object in\n\t * the tokener.\n\t * @param readFrom a tokener whose nextValue() method will yield a {@code JSONObject}.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.\n\t */\n\tpublic JSONObject(JSONTokener readFrom) throws JSONException {\n\t\t/*\n\t\t * Getting the parser to populate this could get tricky. Instead, just parse to\n\t\t * temporary JSONObject and then steal the data from that.\n\t\t */\n\t\tObject object = readFrom.nextValue();\n\t\tif (object instanceof JSONObject) {\n\t\t\tthis.nameValuePairs = ((JSONObject) object).nameValuePairs;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} with name/value mappings from the JSON string.\n\t * @param json a JSON-encoded string containing an object.\n\t * @throws JSONException if the parse fails or doesn't yield a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject(String json) throws JSONException {\n\t\tthis(new JSONTokener(json));\n\t}\n\n\t/**\n\t * Creates a new {@code JSONObject} by copying mappings for the listed names from the\n\t * given object. Names that aren't present in {@code copyFrom} will be skipped.\n\t * @param copyFrom the source\n\t * @param names the property names\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject(JSONObject copyFrom, String[] names) throws JSONException {\n\t\tthis();\n\t\tfor (String name : names) {\n\t\t\tObject value = copyFrom.opt(name);\n\t\t\tif (value != null) {\n\t\t\t\tthis.nameValuePairs.put(name, value);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of name/value mappings in this object.\n\t * @return the number of name/value mappings in this object\n\t */\n\tpublic int length() {\n\t\treturn this.nameValuePairs.size();\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, boolean value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, double value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), JSON.checkDouble(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, int value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, long value) throws JSONException {\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with\n\t * the same name. If the value is {@code null}, any existing mapping for {@code name}\n\t * is removed.\n\t * @param name the name of the property\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link #NULL}, or {@code null}. May not be {@link Double#isNaN()\n\t * NaNs} or {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject put(String name, Object value) throws JSONException {\n\t\tif (value == null) {\n\t\t\tthis.nameValuePairs.remove(name);\n\t\t\treturn this;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\t// deviate from the original by checking all Numbers, not just floats &\n\t\t\t// doubles\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\t\tthis.nameValuePairs.put(checkName(name), value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Equivalent to {@code put(name, value)} when both parameters are non-null; does\n\t * nothing otherwise.\n\t * @param name the name of the property\n\t * @param value the value of the property\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject putOpt(String name, Object value) throws JSONException {\n\t\tif (name == null || value == null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn put(name, value);\n\t}\n\n\t/**\n\t * Appends {@code value} to the array already mapped to {@code name}. If this object\n\t * has no mapping for {@code name}, this inserts a new mapping. If the mapping exists\n\t * but its value is not an array, the existing and new values are inserted in order\n\t * into a new array which is itself mapped to {@code name}. In aggregate, this allows\n\t * values to be added to a mapping one at a time.\n\t * @param name the name of the property\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double, {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic JSONObject accumulate(String name, Object value) throws JSONException {\n\t\tObject current = this.nameValuePairs.get(checkName(name));\n\t\tif (current == null) {\n\t\t\treturn put(name, value);\n\t\t}\n\n\t\t// check in accumulate, since array.put(Object) doesn't do any checking\n\t\tif (value instanceof Number) {\n\t\t\tJSON.checkDouble(((Number) value).doubleValue());\n\t\t}\n\n\t\tif (current instanceof JSONArray array) {\n\t\t\tarray.put(value);\n\t\t}\n\t\telse {\n\t\t\tJSONArray array = new JSONArray();\n\t\t\tarray.put(current);\n\t\t\tarray.put(value);\n\t\t\tthis.nameValuePairs.put(name, array);\n\t\t}\n\t\treturn this;\n\t}\n\n\tString checkName(String name) throws JSONException {\n\t\tif (name == null) {\n\t\t\tthrow new JSONException(\"Names must be non-null\");\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * Removes the named mapping if it exists; does nothing otherwise.\n\t * @param name the name of the property\n\t * @return the value previously mapped by {@code name}, or null if there was no such\n\t * mapping.\n\t */\n\tpublic Object remove(String name) {\n\t\treturn this.nameValuePairs.remove(name);\n\t}\n\n\t/**\n\t * Returns true if this object has no mapping for {@code name} or if it has a mapping\n\t * whose value is {@link #NULL}.\n\t * @param name the name of the property\n\t * @return true if this object has no mapping for {@code name}\n\t */\n\tpublic boolean isNull(String name) {\n\t\tObject value = this.nameValuePairs.get(name);\n\t\treturn value == null || value == NULL;\n\t}\n\n\t/**\n\t * Returns true if this object has a mapping for {@code name}. The mapping may be\n\t * {@link #NULL}.\n\t * @param name the name of the property\n\t * @return true if this object has a mapping for {@code name}\n\t */\n\tpublic boolean has(String name) {\n\t\treturn this.nameValuePairs.containsKey(name);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if no such mapping exists.\n\t */\n\tpublic Object get(String name) throws JSONException {\n\t\tObject result = this.nameValuePairs.get(name);\n\t\tif (result == null) {\n\t\t\tthrow new JSONException(\"No value for \" + name);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name}, or null if no such mapping exists.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic Object opt(String name) {\n\t\treturn this.nameValuePairs.get(name);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a\n\t * boolean.\n\t */\n\tpublic boolean getBoolean(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"boolean\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean. Returns false otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic boolean optBoolean(String name) {\n\t\treturn optBoolean(name, false);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a boolean or can be\n\t * coerced to a boolean. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic boolean optBoolean(String name, boolean fallback) {\n\t\tObject object = opt(name);\n\t\tBoolean result = JSON.toBoolean(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a\n\t * double.\n\t */\n\tpublic double getDouble(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tDouble result = JSON.toDouble(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"double\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double. Returns {@code NaN} otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code NaN}\n\t */\n\tpublic double optDouble(String name) {\n\t\treturn optDouble(name, Double.NaN);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a double or can be\n\t * coerced to a double. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic double optDouble(String name, double fallback) {\n\t\tObject object = opt(name);\n\t\tDouble result = JSON.toDouble(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to an int.\n\t */\n\tpublic int getInt(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tInteger result = JSON.toInteger(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"int\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int. Returns 0 otherwise.\n\t * @param name the name of the property\n\t * @return the value of {@code 0}\n\t */\n\tpublic int optInt(String name) {\n\t\treturn optInt(name, 0);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is an int or can be\n\t * coerced to an int. Returns {@code fallback} otherwise.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic int optInt(String name, int fallback) {\n\t\tObject object = opt(name);\n\t\tInteger result = JSON.toInteger(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Note that JSON represents numbers as doubles, so this is\n\t * <a href=\"#lossy\">lossy</a>; use strings to transfer numbers over JSON.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or cannot be coerced to a long.\n\t */\n\tpublic long getLong(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tLong result = JSON.toLong(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"long\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Returns 0 otherwise. Note that JSON represents numbers as\n\t * doubles, so this is <a href=\"#lossy\">lossy</a>; use strings to transfer numbers via\n\t * JSON.\n\t * @param name the name of the property\n\t * @return the value or {@code 0L}\n\t */\n\tpublic long optLong(String name) {\n\t\treturn optLong(name, 0L);\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a long or can be\n\t * coerced to a long. Returns {@code fallback} otherwise. Note that JSON represents\n\t * numbers as doubles, so this is <a href=\"#lossy\">lossy</a>; use strings to transfer\n\t * numbers over JSON.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic long optLong(String name, long fallback) {\n\t\tObject object = opt(name);\n\t\tLong result = JSON.toLong(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if no such mapping exists.\n\t */\n\tpublic String getString(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tString result = JSON.toString(object);\n\t\tif (result == null) {\n\t\t\tthrow JSON.typeMismatch(name, object, \"String\");\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * Returns the empty string if no such mapping exists.\n\t * @param name the name of the property\n\t * @return the value or an empty string\n\t */\n\tpublic String optString(String name) {\n\t\treturn optString(name, \"\");\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists, coercing it if necessary.\n\t * Returns {@code fallback} if no such mapping exists.\n\t * @param name the name of the property\n\t * @param fallback a fallback value\n\t * @return the value or {@code fallback}\n\t */\n\tpublic String optString(String name, String fallback) {\n\t\tObject object = opt(name);\n\t\tString result = JSON.toString(object);\n\t\treturn result != null ? result : fallback;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONArray}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or is not a {@code\n\t *     JSONArray}.\n\t */\n\tpublic JSONArray getJSONArray(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tif (object instanceof JSONArray) {\n\t\t\treturn (JSONArray) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(name, object, \"JSONArray\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONArray}. Returns null otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic JSONArray optJSONArray(String name) {\n\t\tObject object = opt(name);\n\t\treturn object instanceof JSONArray ? (JSONArray) object : null;\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONObject}.\n\t * @param name the name of the property\n\t * @return the value\n\t * @throws JSONException if the mapping doesn't exist or is not a {@code\n\t *     JSONObject}.\n\t */\n\tpublic JSONObject getJSONObject(String name) throws JSONException {\n\t\tObject object = get(name);\n\t\tif (object instanceof JSONObject) {\n\t\t\treturn (JSONObject) object;\n\t\t}\n\t\telse {\n\t\t\tthrow JSON.typeMismatch(name, object, \"JSONObject\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the value mapped by {@code name} if it exists and is a {@code\n\t * JSONObject}. Returns null otherwise.\n\t * @param name the name of the property\n\t * @return the value or {@code null}\n\t */\n\tpublic JSONObject optJSONObject(String name) {\n\t\tObject object = opt(name);\n\t\treturn object instanceof JSONObject ? (JSONObject) object : null;\n\t}\n\n\t/**\n\t * Returns an array with the values corresponding to {@code names}. The array contains\n\t * null for names that aren't mapped. This method returns null if {@code names} is\n\t * either null or empty.\n\t * @param names the names of the properties\n\t * @return the array\n\t */\n\tpublic JSONArray toJSONArray(JSONArray names) {\n\t\tJSONArray result = new JSONArray();\n\t\tif (names == null) {\n\t\t\treturn null;\n\t\t}\n\t\tint length = names.length();\n\t\tif (length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tString name = JSON.toString(names.opt(i));\n\t\t\tresult.put(opt(name));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns an iterator of the {@code String} names in this object. The returned\n\t * iterator supports {@link Iterator#remove() remove}, which will remove the\n\t * corresponding mapping from this object. If this object is modified after the\n\t * iterator is returned, the iterator's behavior is undefined. The order of the keys\n\t * is undefined.\n\t * @return the keys\n\t */\n\t/* Return a raw type for API compatibility */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic Iterator keys() {\n\t\treturn this.nameValuePairs.keySet().iterator();\n\t}\n\n\t/**\n\t * Returns an array containing the string names in this object. This method returns\n\t * null if this object contains no mappings.\n\t * @return the array\n\t */\n\tpublic JSONArray names() {\n\t\treturn this.nameValuePairs.isEmpty() ? null : new JSONArray(new ArrayList<>(this.nameValuePairs.keySet()));\n\t}\n\n\t/**\n\t * Encodes this object as a compact JSON string, such as:\n\t * <pre>{\"query\":\"Pizza\",\"locations\":[94043,90210]}</pre>\n\t * @return a string representation of the object.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\twriteTo(stringer);\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Encodes this object as a human-readable JSON string for debugging, such as: <pre>\n\t * {\n\t *     \"query\": \"Pizza\",\n\t *     \"locations\": [\n\t *         94043,\n\t *         90210\n\t *     ]\n\t * }</pre>\n\t * @param indentSpaces the number of spaces to indent for each level of nesting.\n\t * @return a string representation of the object.\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic String toString(int indentSpaces) throws JSONException {\n\t\tJSONStringer stringer = new JSONStringer(indentSpaces);\n\t\twriteTo(stringer);\n\t\treturn stringer.toString();\n\t}\n\n\tvoid writeTo(JSONStringer stringer) throws JSONException {\n\t\tstringer.object();\n\t\tfor (Map.Entry<String, Object> entry : this.nameValuePairs.entrySet()) {\n\t\t\tstringer.key(entry.getKey()).value(entry.getValue());\n\t\t}\n\t\tstringer.endObject();\n\t}\n\n\t/**\n\t * Encodes the number as a JSON string.\n\t * @param number a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return the encoded value\n\t * @throws JSONException if an error occurs\n\t */\n\tpublic static String numberToString(Number number) throws JSONException {\n\t\tif (number == null) {\n\t\t\tthrow new JSONException(\"Number must be non-null\");\n\t\t}\n\n\t\tdouble doubleValue = number.doubleValue();\n\t\tJSON.checkDouble(doubleValue);\n\n\t\t// the original returns \"-0\" instead of \"-0.0\" for negative zero\n\t\tif (number.equals(NEGATIVE_ZERO)) {\n\t\t\treturn \"-0\";\n\t\t}\n\n\t\tlong longValue = number.longValue();\n\t\tif (doubleValue == longValue) {\n\t\t\treturn Long.toString(longValue);\n\t\t}\n\n\t\treturn number.toString();\n\t}\n\n\t/**\n\t * Encodes {@code data} as a JSON string. This applies quotes and any necessary\n\t * character escaping.\n\t * @param data the string to encode. Null will be interpreted as an empty string.\n\t * @return the quoted value\n\t */\n\tpublic static String quote(String data) {\n\t\tif (data == null) {\n\t\t\treturn \"\\\"\\\"\";\n\t\t}\n\t\ttry {\n\t\t\tJSONStringer stringer = new JSONStringer();\n\t\t\tstringer.open(JSONStringer.Scope.NULL, \"\");\n\t\t\tstringer.value(data);\n\t\t\tstringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, \"\");\n\t\t\treturn stringer.toString();\n\t\t}\n\t\tcatch (JSONException e) {\n\t\t\tthrow new AssertionError();\n\t\t}\n\t}\n\n\t/**\n\t * Wraps the given object if necessary.\n\t * <p>\n\t * If the object is null or, returns {@link #NULL}. If the object is a\n\t * {@code JSONArray} or {@code JSONObject}, no wrapping is necessary. If the object is\n\t * {@code NULL}, no wrapping is necessary. If the object is an array or\n\t * {@code Collection}, returns an equivalent {@code JSONArray}. If the object is a\n\t * {@code Map}, returns an equivalent {@code JSONObject}. If the object is a primitive\n\t * wrapper type or {@code String}, returns the object. Otherwise if the object is from\n\t * a {@code java} package, returns the result of {@code toString}. If wrapping fails,\n\t * returns null.\n\t * @param o the object to wrap\n\t * @return the wrapped object\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static Object wrap(Object o) {\n\t\tif (o == null) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif (o instanceof JSONArray || o instanceof JSONObject) {\n\t\t\treturn o;\n\t\t}\n\t\tif (o.equals(NULL)) {\n\t\t\treturn o;\n\t\t}\n\t\ttry {\n\t\t\tif (o instanceof Collection) {\n\t\t\t\treturn new JSONArray((Collection) o);\n\t\t\t}\n\t\t\telse if (o.getClass().isArray()) {\n\t\t\t\treturn new JSONArray(o);\n\t\t\t}\n\t\t\tif (o instanceof Map) {\n\t\t\t\treturn new JSONObject((Map) o);\n\t\t\t}\n\t\t\tif (o instanceof Boolean || o instanceof Byte || o instanceof Character || o instanceof Double\n\t\t\t\t\t|| o instanceof Float || o instanceof Integer || o instanceof Long || o instanceof Short\n\t\t\t\t\t|| o instanceof String) {\n\t\t\t\treturn o;\n\t\t\t}\n\t\t\tif (o.getClass().getPackage().getName().startsWith(\"java.\")) {\n\t\t\t\treturn o.toString();\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONStringer.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.json;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most application\n * developers should use those methods directly and disregard this API. For example:<pre>\n * JSONObject object = ...\n * String json = object.toString();</pre>\n * <p>\n * Stringers only encode well-formed JSON strings. In particular:\n * <ul>\n * <li>The stringer must have exactly one top-level array or object.\n * <li>Lexical scopes must be balanced: every call to {@link #array} must have a matching\n * call to {@link #endArray} and every call to {@link #object} must have a matching call\n * to {@link #endObject}.\n * <li>Arrays may not contain keys (property names).\n * <li>Objects must alternate keys (property names) and values.\n * <li>Values are inserted with either literal {@link #value(Object) value} calls, or by\n * nesting arrays or objects.\n * </ul>\n * Calls that would result in a malformed JSON string will fail with a\n * {@link JSONException}.\n * <p>\n * This class provides no facility for pretty-printing (ie. indenting) output. To encode\n * indented output, use {@link JSONObject#toString(int)} or\n * {@link JSONArray#toString(int)}.\n * <p>\n * Some implementations of the API support at most 20 levels of nesting. Attempts to\n * create more than 20 levels of nesting may fail with a {@link JSONException}.\n * <p>\n * Each stringer may be used to encode a single top level value. Instances of this class\n * are not thread safe. Although this class is nonfinal, it was not designed for\n * inheritance and should not be subclassed. In particular, self-use by overrideable\n * methods is not specified. See <i>Effective Java</i> Item 17, \"Design and Document or\n * inheritance or else prohibit it\" for further information.\n */\npublic class JSONStringer {\n\n\t/**\n\t * The output data, containing at most one top-level array or object.\n\t */\n\tfinal StringBuilder out = new StringBuilder();\n\n\t/**\n\t * Lexical scoping elements within this stringer, necessary to insert the appropriate\n\t * separator characters (i.e. commas and colons) and to detect nesting errors.\n\t */\n\tenum Scope {\n\n\t\t/**\n\t\t * An array with no elements requires no separators or newlines before it is\n\t\t * closed.\n\t\t */\n\t\tEMPTY_ARRAY,\n\n\t\t/**\n\t\t * An array with at least one value requires a comma and newline before the next\n\t\t * element.\n\t\t */\n\t\tNONEMPTY_ARRAY,\n\n\t\t/**\n\t\t * An object with no keys or values requires no separators or newlines before it\n\t\t * is closed.\n\t\t */\n\t\tEMPTY_OBJECT,\n\n\t\t/**\n\t\t * An object whose most recent element is a key. The next element must be a value.\n\t\t */\n\t\tDANGLING_KEY,\n\n\t\t/**\n\t\t * An object with at least one name/value pair requires a comma and newline before\n\t\t * the next element.\n\t\t */\n\t\tNONEMPTY_OBJECT,\n\n\t\t/**\n\t\t * A special bracketless array needed by JSONStringer.join() and\n\t\t * JSONObject.quote() only. Not used for JSON encoding.\n\t\t */\n\t\tNULL\n\n\t}\n\n\t/**\n\t * Unlike the original implementation, this stack isn't limited to 20 levels of\n\t * nesting.\n\t */\n\tprivate final List<Scope> stack = new ArrayList<>();\n\n\t/**\n\t * A string containing a full set of spaces for a single level of indentation, or null\n\t * for no pretty printing.\n\t */\n\tprivate final String indent;\n\n\tpublic JSONStringer() {\n\t\tthis.indent = null;\n\t}\n\n\tJSONStringer(int indentSpaces) {\n\t\tchar[] indentChars = new char[indentSpaces];\n\t\tArrays.fill(indentChars, ' ');\n\t\tthis.indent = new String(indentChars);\n\t}\n\n\t/**\n\t * Begins encoding a new array. Each call to this method must be paired with a call to\n\t * {@link #endArray}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer array() throws JSONException {\n\t\treturn open(Scope.EMPTY_ARRAY, \"[\");\n\t}\n\n\t/**\n\t * Ends encoding the current array.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer endArray() throws JSONException {\n\t\treturn close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, \"]\");\n\t}\n\n\t/**\n\t * Begins encoding a new object. Each call to this method must be paired with a call\n\t * to {@link #endObject}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer object() throws JSONException {\n\t\treturn open(Scope.EMPTY_OBJECT, \"{\");\n\t}\n\n\t/**\n\t * Ends encoding the current object.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer endObject() throws JSONException {\n\t\treturn close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, \"}\");\n\t}\n\n\t/**\n\t * Enters a new scope by appending any necessary whitespace and the given bracket.\n\t * @param empty any necessary whitespace\n\t * @param openBracket the open bracket\n\t * @return this object\n\t * @throws JSONException if processing of json failed\n\t */\n\tJSONStringer open(Scope empty, String openBracket) throws JSONException {\n\t\tif (this.stack.isEmpty() && !this.out.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem: multiple top-level roots\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.stack.add(empty);\n\t\tthis.out.append(openBracket);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Closes the current scope by appending any necessary whitespace and the given\n\t * bracket.\n\t * @param empty any necessary whitespace\n\t * @param nonempty the current scope\n\t * @param closeBracket the close bracket\n\t * @return the JSON stringer\n\t * @throws JSONException if processing of json failed\n\t */\n\tJSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {\n\t\tScope context = peek();\n\t\tif (context != nonempty && context != empty) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\n\t\tthis.stack.remove(this.stack.size() - 1);\n\t\tif (context == nonempty) {\n\t\t\tnewline();\n\t\t}\n\t\tthis.out.append(closeBracket);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the value on the top of the stack.\n\t * @return the scope\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate Scope peek() throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\treturn this.stack.get(this.stack.size() - 1);\n\t}\n\n\t/**\n\t * Replace the value on the top of the stack with the given value.\n\t * @param topOfStack the scope at the top of the stack\n\t */\n\tprivate void replaceTop(Scope topOfStack) {\n\t\tthis.stack.set(this.stack.size() - 1, topOfStack);\n\t}\n\n\t/**\n\t * Encodes {@code value}.\n\t * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer,\n\t * Long, Double or null. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(Object value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\n\t\tif (value instanceof JSONArray) {\n\t\t\t((JSONArray) value).writeTo(this);\n\t\t\treturn this;\n\t\t}\n\t\telse if (value instanceof JSONObject) {\n\t\t\t((JSONObject) value).writeTo(this);\n\t\t\treturn this;\n\t\t}\n\n\t\tbeforeValue();\n\n\t\tif (value == null || value instanceof Boolean || value == JSONObject.NULL) {\n\t\t\tthis.out.append(value);\n\n\t\t}\n\t\telse if (value instanceof Number) {\n\t\t\tthis.out.append(JSONObject.numberToString((Number) value));\n\n\t\t}\n\t\telse {\n\t\t\tstring(value.toString());\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value the value to encode\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(boolean value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value a finite value. May not be {@link Double#isNaN() NaNs} or\n\t * {@link Double#isInfinite() infinities}.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(double value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(JSONObject.numberToString(value));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Encodes {@code value} to this stringer.\n\t * @param value the value to encode\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer value(long value) throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tbeforeValue();\n\t\tthis.out.append(value);\n\t\treturn this;\n\t}\n\n\tprivate void string(String value) {\n\t\tthis.out.append(\"\\\"\");\n\t\tfor (int i = 0, length = value.length(); i < length; i++) {\n\t\t\tchar c = value.charAt(i);\n\n\t\t\t/*\n\t\t\t * From RFC 4627, \"All Unicode characters may be placed within the quotation\n\t\t\t * marks except for the characters that must be escaped: quotation mark,\n\t\t\t * reverse solidus, and the control characters (U+0000 through U+001F).\"\n\t\t\t */\n\t\t\tswitch (c) {\n\t\t\t\tcase '\"', '\\\\', '/' -> this.out.append('\\\\').append(c);\n\t\t\t\tcase '\\t' -> this.out.append(\"\\\\t\");\n\t\t\t\tcase '\\b' -> this.out.append(\"\\\\b\");\n\t\t\t\tcase '\\n' -> this.out.append(\"\\\\n\");\n\t\t\t\tcase '\\r' -> this.out.append(\"\\\\r\");\n\t\t\t\tcase '\\f' -> this.out.append(\"\\\\f\");\n\t\t\t\tdefault -> {\n\t\t\t\t\tif (c <= 0x1F) {\n\t\t\t\t\t\tthis.out.append(String.format(\"\\\\u%04x\", (int) c));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.out.append(c);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tthis.out.append(\"\\\"\");\n\t}\n\n\tprivate void newline() {\n\t\tif (this.indent == null) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.out.append(\"\\n\");\n\t\tthis.out.append(this.indent.repeat(this.stack.size()));\n\t}\n\n\t/**\n\t * Encodes the key (property name) to this stringer.\n\t * @param name the name of the forthcoming value. May not be null.\n\t * @return this stringer.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic JSONStringer key(String name) throws JSONException {\n\t\tif (name == null) {\n\t\t\tthrow new JSONException(\"Names must be non-null\");\n\t\t}\n\t\tbeforeKey();\n\t\tstring(name);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Inserts any necessary separators and whitespace before a name. Also adjusts the\n\t * stack to expect the key's value.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate void beforeKey() throws JSONException {\n\t\tScope context = peek();\n\t\tif (context == Scope.NONEMPTY_OBJECT) { // first in object\n\t\t\tthis.out.append(',');\n\t\t}\n\t\telse if (context != Scope.EMPTY_OBJECT) { // not in an object!\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t\tnewline();\n\t\treplaceTop(Scope.DANGLING_KEY);\n\t}\n\n\t/**\n\t * Inserts any necessary separators and whitespace before a literal value, inline\n\t * array, or inline object. Also adjusts the stack to expect either a closing bracket\n\t * or another element.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate void beforeValue() throws JSONException {\n\t\tif (this.stack.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\n\t\tScope context = peek();\n\t\tif (context == Scope.EMPTY_ARRAY) { // first in array\n\t\t\treplaceTop(Scope.NONEMPTY_ARRAY);\n\t\t\tnewline();\n\t\t}\n\t\telse if (context == Scope.NONEMPTY_ARRAY) { // another in array\n\t\t\tthis.out.append(',');\n\t\t\tnewline();\n\t\t}\n\t\telse if (context == Scope.DANGLING_KEY) { // value for key\n\t\t\tthis.out.append(this.indent == null ? \":\" : \": \");\n\t\t\treplaceTop(Scope.NONEMPTY_OBJECT);\n\t\t}\n\t\telse if (context != Scope.NULL) {\n\t\t\tthrow new JSONException(\"Nesting problem\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the encoded JSON string.\n\t * <p>\n\t * If invoked with unterminated arrays or unclosed objects, this method's return value\n\t * is undefined.\n\t * <p>\n\t * <strong>Warning:</strong> although it contradicts the general contract of\n\t * {@link Object#toString}, this method returns null if the stringer contains no data.\n\t * @return the encoded JSON string.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn this.out.isEmpty() ? null : this.out.toString();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/json-shade/java/org/springframework/boot/configurationprocessor/json/JSONTokener.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.json;\n\n// Note: this class was written without inspecting the non-free org.json source code.\n\n/**\n * Parses a JSON (<a href=\"https://www.ietf.org/rfc/rfc4627.txt\">RFC 4627</a>) encoded\n * string into the corresponding object. Most clients of this class will use only need the\n * {@link #JSONTokener(String) constructor} and {@link #nextValue} method. Example usage:\n * <pre>\n * String json = \"{\"\n *         + \"  \\\"query\\\": \\\"Pizza\\\", \"\n *         + \"  \\\"locations\\\": [ 94043, 90210 ] \"\n *         + \"}\";\n *\n * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();\n * String query = object.getString(\"query\");\n * JSONArray locations = object.getJSONArray(\"locations\");</pre>\n * <p>\n * For best interoperability and performance use JSON that complies with RFC 4627, such as\n * that generated by {@link JSONStringer}. For legacy reasons this parser is lenient, so a\n * successful parse does not indicate that the input string was valid JSON. All the\n * following syntax errors will be ignored:\n * <ul>\n * <li>End of line comments starting with {@code //} or {@code #} and ending with a\n * newline character.\n * <li>C-style comments starting with {@code /*} and ending with {@code *}{@code /}. Such\n * comments may not be nested.\n * <li>Strings that are unquoted or {@code 'single quoted'}.\n * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.\n * <li>Octal integers prefixed with {@code 0}.\n * <li>Array elements separated by {@code ;}.\n * <li>Unnecessary array separators. These are interpreted as if null was the omitted\n * value.\n * <li>Key-value pairs separated by {@code =} or {@code =>}.\n * <li>Key-value pairs separated by {@code ;}.\n * </ul>\n * <p>\n * Each tokener may be used to parse a single JSON string. Instances of this class are not\n * thread safe. Although this class is nonfinal, it was not designed for inheritance and\n * should not be subclassed. In particular, self-use by overrideable methods is not\n * specified. See <i>Effective Java</i> Item 17, \"Design and Document or inheritance or\n * else prohibit it\" for further information.\n */\npublic class JSONTokener {\n\n\t/**\n\t * The input JSON.\n\t */\n\tprivate final String in;\n\n\t/**\n\t * The index of the next character to be returned by {@link #next}. When the input is\n\t * exhausted, this equals the input's length.\n\t */\n\tprivate int pos;\n\n\t/**\n\t * @param in JSON encoded string. Null is not permitted and will yield a tokener that\n\t * throws {@code NullPointerExceptions} when methods are called.\n\t */\n\tpublic JSONTokener(String in) {\n\t\t// consume an optional byte order mark (BOM) if it exists\n\t\tif (in != null && in.startsWith(\"\\ufeff\")) {\n\t\t\tin = in.substring(1);\n\t\t}\n\t\tthis.in = in;\n\t}\n\n\t/**\n\t * Returns the next value from the input.\n\t * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long,\n\t * Double or {@link JSONObject#NULL}.\n\t * @throws JSONException if the input is malformed.\n\t */\n\tpublic Object nextValue() throws JSONException {\n\t\tint c = nextCleanInternal();\n\t\tswitch (c) {\n\t\t\tcase -1:\n\t\t\t\tthrow syntaxError(\"End of input\");\n\n\t\t\tcase '{':\n\t\t\t\treturn readObject();\n\n\t\t\tcase '[':\n\t\t\t\treturn readArray();\n\n\t\t\tcase '\\'', '\"':\n\t\t\t\treturn nextString((char) c);\n\n\t\t\tdefault:\n\t\t\t\tthis.pos--;\n\t\t\t\treturn readLiteral();\n\t\t}\n\t}\n\n\tprivate int nextCleanInternal() throws JSONException {\n\t\twhile (this.pos < this.in.length()) {\n\t\t\tint c = this.in.charAt(this.pos++);\n\t\t\tswitch (c) {\n\t\t\t\tcase '\\t', ' ', '\\n', '\\r':\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcase '/':\n\t\t\t\t\tif (this.pos == this.in.length()) {\n\t\t\t\t\t\treturn c;\n\t\t\t\t\t}\n\n\t\t\t\t\tchar peek = this.in.charAt(this.pos);\n\t\t\t\t\tswitch (peek) {\n\t\t\t\t\t\tcase '*':\n\t\t\t\t\t\t\t// skip a /* c-style comment */\n\t\t\t\t\t\t\tthis.pos++;\n\t\t\t\t\t\t\tint commentEnd = this.in.indexOf(\"*/\", this.pos);\n\t\t\t\t\t\t\tif (commentEnd == -1) {\n\t\t\t\t\t\t\t\tthrow syntaxError(\"Unterminated comment\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis.pos = commentEnd + 2;\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tcase '/':\n\t\t\t\t\t\t\t// skip a // end-of-line comment\n\t\t\t\t\t\t\tthis.pos++;\n\t\t\t\t\t\t\tskipToEndOfLine();\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\treturn c;\n\t\t\t\t\t}\n\n\t\t\t\tcase '#':\n\t\t\t\t\t/*\n\t\t\t\t\t * Skip a # hash end-of-line comment. The JSON RFC doesn't specify\n\t\t\t\t\t * this behavior, but it's required to parse existing documents. See\n\t\t\t\t\t * https://b/2571423.\n\t\t\t\t\t */\n\t\t\t\t\tskipToEndOfLine();\n\t\t\t\t\tcontinue;\n\n\t\t\t\tdefault:\n\t\t\t\t\treturn c;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Advances the position until after the next newline character. If the line is\n\t * terminated by \"\\r\\n\", the '\\n' must be consumed as whitespace by the caller.\n\t */\n\tprivate void skipToEndOfLine() {\n\t\tfor (; this.pos < this.in.length(); this.pos++) {\n\t\t\tchar c = this.in.charAt(this.pos);\n\t\t\tif (c == '\\r' || c == '\\n') {\n\t\t\t\tthis.pos++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the string up to but not including {@code quote}, unescaping any character\n\t * escape sequences encountered along the way. The opening quote should have already\n\t * been read. This consumes the closing quote, but does not include it in the returned\n\t * string.\n\t * @param quote either ' or \".\n\t * @return the string up to but not including {@code quote}\n\t * @throws NumberFormatException if any unicode escape sequences are malformed.\n\t * @throws JSONException if processing of json failed\n\t */\n\tpublic String nextString(char quote) throws JSONException {\n\t\t/*\n\t\t * For strings that are free of escape sequences, we can just extract the result\n\t\t * as a substring of the input. But if we encounter an escape sequence, we need to\n\t\t * use a StringBuilder to compose the result.\n\t\t */\n\t\tStringBuilder builder = null;\n\n\t\t/* the index of the first character not yet appended to the builder. */\n\t\tint start = this.pos;\n\n\t\twhile (this.pos < this.in.length()) {\n\t\t\tint c = this.in.charAt(this.pos++);\n\t\t\tif (c == quote) {\n\t\t\t\tif (builder == null) {\n\t\t\t\t\t// a new string avoids leaking memory\n\t\t\t\t\treturn new String(this.in.substring(start, this.pos - 1));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuilder.append(this.in, start, this.pos - 1);\n\t\t\t\t\treturn builder.toString();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (c == '\\\\') {\n\t\t\t\tif (this.pos == this.in.length()) {\n\t\t\t\t\tthrow syntaxError(\"Unterminated escape sequence\");\n\t\t\t\t}\n\t\t\t\tif (builder == null) {\n\t\t\t\t\tbuilder = new StringBuilder();\n\t\t\t\t}\n\t\t\t\tbuilder.append(this.in, start, this.pos - 1);\n\t\t\t\tbuilder.append(readEscapeCharacter());\n\t\t\t\tstart = this.pos;\n\t\t\t}\n\t\t}\n\n\t\tthrow syntaxError(\"Unterminated string\");\n\t}\n\n\t/**\n\t * Unescapes the character identified by the character or characters that immediately\n\t * follow a backslash. The backslash '\\' should have already been read. This supports\n\t * both unicode escapes \"u000A\" and two-character escapes \"\\n\".\n\t * @return the unescaped char\n\t * @throws NumberFormatException if any unicode escape sequences are malformed.\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate char readEscapeCharacter() throws JSONException {\n\t\tchar escaped = this.in.charAt(this.pos++);\n\t\tswitch (escaped) {\n\t\t\tcase 'u':\n\t\t\t\tif (this.pos + 4 > this.in.length()) {\n\t\t\t\t\tthrow syntaxError(\"Unterminated escape sequence\");\n\t\t\t\t}\n\t\t\t\tString hex = this.in.substring(this.pos, this.pos + 4);\n\t\t\t\tthis.pos += 4;\n\t\t\t\treturn (char) Integer.parseInt(hex, 16);\n\n\t\t\tcase 't':\n\t\t\t\treturn '\\t';\n\n\t\t\tcase 'b':\n\t\t\t\treturn '\\b';\n\n\t\t\tcase 'n':\n\t\t\t\treturn '\\n';\n\n\t\t\tcase 'r':\n\t\t\t\treturn '\\r';\n\n\t\t\tcase 'f':\n\t\t\t\treturn '\\f';\n\n\t\t\tcase '\\'', '\"', '\\\\':\n\t\t\tdefault:\n\t\t\t\treturn escaped;\n\t\t}\n\t}\n\n\t/**\n\t * Reads a null, boolean, numeric or unquoted string literal value. Numeric values\n\t * will be returned as an Integer, Long, or Double, in that order of preference.\n\t * @return a literal value\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate Object readLiteral() throws JSONException {\n\t\tString literal = nextToInternal(\"{}[]/\\\\:,=;# \\t\\f\");\n\n\t\tif (literal.isEmpty()) {\n\t\t\tthrow syntaxError(\"Expected literal value\");\n\t\t}\n\t\telse if (\"null\".equalsIgnoreCase(literal)) {\n\t\t\treturn JSONObject.NULL;\n\t\t}\n\t\telse if (\"true\".equalsIgnoreCase(literal)) {\n\t\t\treturn Boolean.TRUE;\n\t\t}\n\t\telse if (\"false\".equalsIgnoreCase(literal)) {\n\t\t\treturn Boolean.FALSE;\n\t\t}\n\n\t\t/* try to parse as an integral type... */\n\t\tif (literal.indexOf('.') == -1) {\n\t\t\tint base = 10;\n\t\t\tString number = literal;\n\t\t\tif (number.startsWith(\"0x\") || number.startsWith(\"0X\")) {\n\t\t\t\tnumber = number.substring(2);\n\t\t\t\tbase = 16;\n\t\t\t}\n\t\t\telse if (number.startsWith(\"0\") && number.length() > 1) {\n\t\t\t\tnumber = number.substring(1);\n\t\t\t\tbase = 8;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tlong longValue = Long.parseLong(number, base);\n\t\t\t\tif (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {\n\t\t\t\t\treturn (int) longValue;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn longValue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (NumberFormatException e) {\n\t\t\t\t/*\n\t\t\t\t * This only happens for integral numbers greater than Long.MAX_VALUE,\n\t\t\t\t * numbers in exponential form (5e-10) and unquoted strings. Fall through\n\t\t\t\t * to try floating point.\n\t\t\t\t */\n\t\t\t}\n\t\t}\n\n\t\t/* ...next try to parse as a floating point... */\n\t\ttry {\n\t\t\treturn Double.valueOf(literal);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\t// Ignore\n\t\t}\n\n\t\t/* ... finally give up. We have an unquoted string */\n\t\treturn new String(literal); // a new string avoids leaking memory\n\t}\n\n\t/**\n\t * Returns the string up to but not including any of the given characters or a newline\n\t * character. This does not consume the excluded character.\n\t * @return the string up to but not including any of the given characters or a newline\n\t * character\n\t */\n\tprivate String nextToInternal(String excluded) {\n\t\tint start = this.pos;\n\t\tfor (; this.pos < this.in.length(); this.pos++) {\n\t\t\tchar c = this.in.charAt(this.pos);\n\t\t\tif (c == '\\r' || c == '\\n' || excluded.indexOf(c) != -1) {\n\t\t\t\treturn this.in.substring(start, this.pos);\n\t\t\t}\n\t\t}\n\t\treturn this.in.substring(start);\n\t}\n\n\t/**\n\t * Reads a sequence of key/value pairs and the trailing closing brace '}' of an\n\t * object. The opening brace '{' should have already been read.\n\t * @return an object\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate JSONObject readObject() throws JSONException {\n\t\tJSONObject result = new JSONObject();\n\n\t\t/* Peek to see if this is the empty object. */\n\t\tint first = nextCleanInternal();\n\t\tif (first == '}') {\n\t\t\treturn result;\n\t\t}\n\t\telse if (first != -1) {\n\t\t\tthis.pos--;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tObject name = nextValue();\n\t\t\tif (!(name instanceof String)) {\n\t\t\t\tif (name == null) {\n\t\t\t\t\tthrow syntaxError(\"Names cannot be null\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow syntaxError(\n\t\t\t\t\t\t\t\"Names must be strings, but \" + name + \" is of type \" + name.getClass().getName());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Expect the name/value separator to be either a colon ':', an equals sign\n\t\t\t * '=', or an arrow \"=>\". The last two are bogus but we include them because\n\t\t\t * that's what the original implementation did.\n\t\t\t */\n\t\t\tint separator = nextCleanInternal();\n\t\t\tif (separator != ':' && separator != '=') {\n\t\t\t\tthrow syntaxError(\"Expected ':' after \" + name);\n\t\t\t}\n\t\t\tif (this.pos < this.in.length() && this.in.charAt(this.pos) == '>') {\n\t\t\t\tthis.pos++;\n\t\t\t}\n\n\t\t\tresult.put((String) name, nextValue());\n\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase '}':\n\t\t\t\t\treturn result;\n\t\t\t\tcase ';', ',':\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow syntaxError(\"Unterminated object\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Reads a sequence of values and the trailing closing brace ']' of an array. The\n\t * opening brace '[' should have already been read. Note that \"[]\" yields an empty\n\t * array, but \"[,]\" returns a two-element array equivalent to \"[null,null]\".\n\t * @return an array\n\t * @throws JSONException if processing of json failed\n\t */\n\tprivate JSONArray readArray() throws JSONException {\n\t\tJSONArray result = new JSONArray();\n\n\t\t/* to cover input that ends with \",]\". */\n\t\tboolean hasTrailingSeparator = false;\n\n\t\twhile (true) {\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase -1:\n\t\t\t\t\tthrow syntaxError(\"Unterminated array\");\n\t\t\t\tcase ']':\n\t\t\t\t\tif (hasTrailingSeparator) {\n\t\t\t\t\t\tresult.put(null);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\tcase ',', ';':\n\t\t\t\t\t/* A separator without a value first means \"null\". */\n\t\t\t\t\tresult.put(null);\n\t\t\t\t\thasTrailingSeparator = true;\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.pos--;\n\t\t\t}\n\n\t\t\tresult.put(nextValue());\n\n\t\t\tswitch (nextCleanInternal()) {\n\t\t\t\tcase ']':\n\t\t\t\t\treturn result;\n\t\t\t\tcase ',', ';':\n\t\t\t\t\thasTrailingSeparator = true;\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow syntaxError(\"Unterminated array\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns an exception containing the given message plus the current position and the\n\t * entire input string.\n\t * @param message the message\n\t * @return an exception\n\t */\n\tpublic JSONException syntaxError(String message) {\n\t\treturn new JSONException(message + this);\n\t}\n\n\t/**\n\t * Returns the current position and the entire input string.\n\t * @return the current position and the entire input string.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\t// consistent with the original implementation\n\t\treturn \" at character \" + this.pos + \" of \" + this.in;\n\t}\n\n\t/*\n\t * Legacy APIs.\n\t *\n\t * None of the methods below are on the critical path of parsing JSON documents. They\n\t * exist only because they were exposed by the original implementation and may be used\n\t * by some clients.\n\t */\n\n\tpublic boolean more() {\n\t\treturn this.pos < this.in.length();\n\t}\n\n\tpublic char next() {\n\t\treturn this.pos < this.in.length() ? this.in.charAt(this.pos++) : '\\0';\n\t}\n\n\tpublic char next(char c) throws JSONException {\n\t\tchar result = next();\n\t\tif (result != c) {\n\t\t\tthrow syntaxError(\"Expected \" + c + \" but was \" + result);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic char nextClean() throws JSONException {\n\t\tint nextCleanInt = nextCleanInternal();\n\t\treturn nextCleanInt == -1 ? '\\0' : (char) nextCleanInt;\n\t}\n\n\tpublic String next(int length) throws JSONException {\n\t\tif (this.pos + length > this.in.length()) {\n\t\t\tthrow syntaxError(length + \" is out of bounds\");\n\t\t}\n\t\tString result = this.in.substring(this.pos, this.pos + length);\n\t\tthis.pos += length;\n\t\treturn result;\n\t}\n\n\tpublic String nextTo(String excluded) {\n\t\tif (excluded == null) {\n\t\t\tthrow new NullPointerException(\"excluded == null\");\n\t\t}\n\t\treturn nextToInternal(excluded).trim();\n\t}\n\n\tpublic String nextTo(char excluded) {\n\t\treturn nextToInternal(String.valueOf(excluded)).trim();\n\t}\n\n\tpublic void skipPast(String thru) {\n\t\tint thruStart = this.in.indexOf(thru, this.pos);\n\t\tthis.pos = thruStart == -1 ? this.in.length() : (thruStart + thru.length());\n\t}\n\n\tpublic char skipTo(char to) {\n\t\tint index = this.in.indexOf(to, this.pos);\n\t\tif (index != -1) {\n\t\t\tthis.pos = index;\n\t\t\treturn to;\n\t\t}\n\t\telse {\n\t\t\treturn '\\0';\n\t\t}\n\t}\n\n\tpublic void back() {\n\t\tif (--this.pos == -1) {\n\t\t\tthis.pos = 0;\n\t\t}\n\t}\n\n\tpublic static int dehexchar(char hex) {\n\t\tif (hex >= '0' && hex <= '9') {\n\t\t\treturn hex - '0';\n\t\t}\n\t\telse if (hex >= 'A' && hex <= 'F') {\n\t\t\treturn hex - 'A' + 10;\n\t\t}\n\t\telse if (hex >= 'a' && hex <= 'f') {\n\t\t\treturn hex - 'a' + 10;\n\t\t}\n\t\telse {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.time.Duration;\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.util.ElementFilter;\nimport javax.tools.Diagnostic.Kind;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.InvalidConfigurationMetadataException;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemIgnore;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\n\n/**\n * Annotation {@link Processor} that writes meta-data file for\n * {@code @ConfigurationProperties}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Kris De Volder\n * @author Jonas Keßler\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 1.2.0\n */\n@SupportedAnnotationTypes({ ConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.AUTO_CONFIGURATION_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.CONFIGURATION_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.CONTROLLER_ENDPOINT_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.ENDPOINT_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.JMX_ENDPOINT_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.REST_CONTROLLER_ENDPOINT_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.SERVLET_ENDPOINT_ANNOTATION,\n\t\tConfigurationMetadataAnnotationProcessor.WEB_ENDPOINT_ANNOTATION })\npublic class ConfigurationMetadataAnnotationProcessor extends AbstractProcessor {\n\n\tstatic final String ADDITIONAL_METADATA_LOCATIONS_OPTION = \"org.springframework.boot.configurationprocessor.additionalMetadataLocations\";\n\n\tstatic final String CONFIGURATION_PROPERTIES_ANNOTATION = \"org.springframework.boot.context.properties.ConfigurationProperties\";\n\n\tstatic final String CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION = \"org.springframework.boot.context.properties.ConfigurationPropertiesSource\";\n\n\tstatic final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = \"org.springframework.boot.context.properties.NestedConfigurationProperty\";\n\n\tstatic final String DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION = \"org.springframework.boot.context.properties.DeprecatedConfigurationProperty\";\n\n\tstatic final String CONSTRUCTOR_BINDING_ANNOTATION = \"org.springframework.boot.context.properties.bind.ConstructorBinding\";\n\n\tstatic final String AUTOWIRED_ANNOTATION = \"org.springframework.beans.factory.annotation.Autowired\";\n\n\tstatic final String DEFAULT_VALUE_ANNOTATION = \"org.springframework.boot.context.properties.bind.DefaultValue\";\n\n\tstatic final String AUTO_CONFIGURATION_ANNOTATION = \"org.springframework.boot.autoconfigure.AutoConfiguration\";\n\n\tstatic final String CONFIGURATION_ANNOTATION = \"org.springframework.context.annotation.Configuration\";\n\n\tstatic final String CONTROLLER_ENDPOINT_ANNOTATION = \"org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint\";\n\n\tstatic final String ENDPOINT_ANNOTATION = \"org.springframework.boot.actuate.endpoint.annotation.Endpoint\";\n\n\tstatic final String JMX_ENDPOINT_ANNOTATION = \"org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint\";\n\n\tstatic final String REST_CONTROLLER_ENDPOINT_ANNOTATION = \"org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint\";\n\n\tstatic final String SERVLET_ENDPOINT_ANNOTATION = \"org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint\";\n\n\tstatic final String WEB_ENDPOINT_ANNOTATION = \"org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint\";\n\n\tstatic final String READ_OPERATION_ANNOTATION = \"org.springframework.boot.actuate.endpoint.annotation.ReadOperation\";\n\n\tstatic final String NAME_ANNOTATION = \"org.springframework.boot.context.properties.bind.Name\";\n\n\tstatic final String ENDPOINT_ACCESS_ENUM = \"org.springframework.boot.actuate.endpoint.Access\";\n\n\tprivate static final Set<String> SUPPORTED_OPTIONS = Set.of(ADDITIONAL_METADATA_LOCATIONS_OPTION);\n\n\tprivate MetadataStore metadataStore;\n\n\tprivate MetadataCollectors metadataCollectors;\n\n\tprivate MetadataCollector metadataCollector;\n\n\tprivate MetadataGenerationEnvironment metadataEnv;\n\n\tprotected String configurationPropertiesAnnotation() {\n\t\treturn CONFIGURATION_PROPERTIES_ANNOTATION;\n\t}\n\n\tprotected String configurationPropertiesSourceAnnotation() {\n\t\treturn CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION;\n\t}\n\n\tprotected String nestedConfigurationPropertyAnnotation() {\n\t\treturn NESTED_CONFIGURATION_PROPERTY_ANNOTATION;\n\t}\n\n\tprotected String deprecatedConfigurationPropertyAnnotation() {\n\t\treturn DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION;\n\t}\n\n\tprotected String constructorBindingAnnotation() {\n\t\treturn CONSTRUCTOR_BINDING_ANNOTATION;\n\t}\n\n\tprotected String autowiredAnnotation() {\n\t\treturn AUTOWIRED_ANNOTATION;\n\t}\n\n\tprotected String defaultValueAnnotation() {\n\t\treturn DEFAULT_VALUE_ANNOTATION;\n\t}\n\n\tprotected Set<String> endpointAnnotations() {\n\t\treturn Set.of(CONTROLLER_ENDPOINT_ANNOTATION, ENDPOINT_ANNOTATION, JMX_ENDPOINT_ANNOTATION,\n\t\t\t\tREST_CONTROLLER_ENDPOINT_ANNOTATION, SERVLET_ENDPOINT_ANNOTATION, WEB_ENDPOINT_ANNOTATION);\n\t}\n\n\tprotected String readOperationAnnotation() {\n\t\treturn READ_OPERATION_ANNOTATION;\n\t}\n\n\tprotected String nameAnnotation() {\n\t\treturn NAME_ANNOTATION;\n\t}\n\n\tprotected String endpointAccessEnum() {\n\t\treturn ENDPOINT_ACCESS_ENUM;\n\t}\n\n\t@Override\n\tpublic SourceVersion getSupportedSourceVersion() {\n\t\treturn SourceVersion.latestSupported();\n\t}\n\n\t@Override\n\tpublic Set<String> getSupportedOptions() {\n\t\treturn SUPPORTED_OPTIONS;\n\t}\n\n\t@Override\n\tpublic synchronized void init(ProcessingEnvironment env) {\n\t\tsuper.init(env);\n\t\tTypeUtils typeUtils = new TypeUtils(env);\n\t\tthis.metadataStore = new MetadataStore(env, typeUtils);\n\t\tthis.metadataCollectors = new MetadataCollectors(env, typeUtils);\n\t\tthis.metadataCollector = this.metadataCollectors.getModuleMetadataCollector();\n\t\tthis.metadataEnv = new MetadataGenerationEnvironment(env, configurationPropertiesAnnotation(),\n\t\t\t\tconfigurationPropertiesSourceAnnotation(), nestedConfigurationPropertyAnnotation(),\n\t\t\t\tdeprecatedConfigurationPropertyAnnotation(), constructorBindingAnnotation(), autowiredAnnotation(),\n\t\t\t\tdefaultValueAnnotation(), endpointAnnotations(), readOperationAnnotation(), nameAnnotation());\n\t}\n\n\t@Override\n\tpublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n\t\tthis.metadataCollectors.processing(roundEnv);\n\t\tTypeElement annotationType = this.metadataEnv.getConfigurationPropertiesAnnotationElement();\n\t\tif (annotationType != null) { // Is @ConfigurationProperties available\n\t\t\tfor (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) {\n\t\t\t\tprocessElement(element);\n\t\t\t}\n\t\t}\n\t\tTypeElement sourceAnnotationType = this.metadataEnv.getConfigurationPropertiesSourceAnnotationElement();\n\t\tif (sourceAnnotationType != null) { // Is @ConfigurationPropertiesSource available\n\t\t\tfor (Element element : roundEnv.getElementsAnnotatedWith(sourceAnnotationType)) {\n\t\t\t\tif (element instanceof TypeElement typeElement) {\n\t\t\t\t\tMetadataCollector metadataCollector = this.metadataCollectors.getMetadataCollector(typeElement);\n\t\t\t\t\tprocessSourceElement(metadataCollector, \"\", typeElement);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSet<TypeElement> endpointTypes = this.metadataEnv.getEndpointAnnotationElements();\n\t\tif (!endpointTypes.isEmpty()) { // Are endpoint annotations available\n\t\t\tfor (TypeElement endpointType : endpointTypes) {\n\t\t\t\tgetElementsAnnotatedOrMetaAnnotatedWith(roundEnv, endpointType).forEach(this::processEndpoint);\n\t\t\t}\n\t\t}\n\t\tif (roundEnv.processingOver()) {\n\t\t\ttry {\n\t\t\t\twriteSourceMetadata();\n\t\t\t\twriteMetadata();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to write metadata\", ex);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Map<Element, List<Element>> getElementsAnnotatedOrMetaAnnotatedWith(RoundEnvironment roundEnv,\n\t\t\tTypeElement annotation) {\n\t\tMap<Element, List<Element>> result = new LinkedHashMap<>();\n\t\tfor (Element element : roundEnv.getRootElements()) {\n\t\t\tList<Element> annotations = this.metadataEnv.getElementsAnnotatedOrMetaAnnotatedWith(element, annotation);\n\t\t\tif (!annotations.isEmpty()) {\n\t\t\t\tresult.put(element, annotations);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate void processElement(Element element) {\n\t\ttry {\n\t\t\tAnnotationMirror annotation = this.metadataEnv.getConfigurationPropertiesAnnotation(element);\n\t\t\tif (annotation != null) {\n\t\t\t\tString prefix = getPrefix(annotation);\n\t\t\t\tif (element instanceof TypeElement typeElement) {\n\t\t\t\t\tprocessAnnotatedTypeElement(prefix, typeElement, new ArrayDeque<>());\n\t\t\t\t}\n\t\t\t\telse if (element instanceof ExecutableElement executableElement) {\n\t\t\t\t\tprocessExecutableElement(prefix, executableElement, new ArrayDeque<>());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Error processing configuration meta-data on \" + element, ex);\n\t\t}\n\t}\n\n\tprivate void processAnnotatedTypeElement(String prefix, TypeElement element, Deque<TypeElement> seen) {\n\t\tString type = this.metadataEnv.getTypeUtils().getQualifiedName(element);\n\t\tthis.metadataCollector.add(ItemMetadata.newGroup(prefix, type, type, null));\n\t\tprocessTypeElement(prefix, element, null, seen);\n\t}\n\n\tprivate void processExecutableElement(String prefix, ExecutableElement element, Deque<TypeElement> seen) {\n\t\tif ((!element.getModifiers().contains(Modifier.PRIVATE))\n\t\t\t\t&& (TypeKind.VOID != element.getReturnType().getKind())) {\n\t\t\tElement returns = this.processingEnv.getTypeUtils().asElement(element.getReturnType());\n\t\t\tif (returns instanceof TypeElement typeElement) {\n\t\t\t\tItemMetadata group = ItemMetadata.newGroup(prefix,\n\t\t\t\t\t\tthis.metadataEnv.getTypeUtils().getQualifiedName(returns),\n\t\t\t\t\t\tthis.metadataEnv.getTypeUtils().getQualifiedName(element.getEnclosingElement()),\n\t\t\t\t\t\telement.toString());\n\t\t\t\tif (this.metadataCollector.hasSimilarGroup(group)) {\n\t\t\t\t\tthis.processingEnv.getMessager()\n\t\t\t\t\t\t.printMessage(Kind.ERROR,\n\t\t\t\t\t\t\t\t\"Duplicate @ConfigurationProperties definition for prefix '\" + prefix + \"'\", element);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.metadataCollector.add(group);\n\t\t\t\t\tprocessTypeElement(prefix, typeElement, element, seen);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void processTypeElement(String prefix, TypeElement element, ExecutableElement source,\n\t\t\tDeque<TypeElement> seen) {\n\t\tif (!seen.contains(element)) {\n\t\t\tseen.push(element);\n\t\t\tnew PropertyDescriptorResolver(this.metadataEnv).resolve(element, source).forEach((descriptor) -> {\n\t\t\t\tthis.metadataCollector.add(descriptor.resolveItemMetadata(prefix, this.metadataEnv));\n\t\t\t\tItemHint itemHint = descriptor.resolveItemHint(prefix, this.metadataEnv);\n\t\t\t\tif (itemHint != null) {\n\t\t\t\t\tthis.metadataCollector.add(itemHint);\n\t\t\t\t}\n\t\t\t\tif (descriptor.isNested(this.metadataEnv)) {\n\t\t\t\t\tTypeElement nestedTypeElement = (TypeElement) this.metadataEnv.getTypeUtils()\n\t\t\t\t\t\t.asElement(descriptor.getType());\n\t\t\t\t\tString nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, descriptor.getName());\n\t\t\t\t\tprocessTypeElement(nestedPrefix, nestedTypeElement, source, seen);\n\t\t\t\t}\n\t\t\t});\n\t\t\tseen.pop();\n\t\t}\n\t}\n\n\tprivate void processSourceElement(MetadataCollector metadataCollector, String prefix, TypeElement element) {\n\t\tnew PropertyDescriptorResolver(this.metadataEnv).resolve(element, null).forEach((descriptor) -> {\n\t\t\tmetadataCollector.add(descriptor.resolveItemMetadata(prefix, this.metadataEnv));\n\t\t\tif (descriptor.isNested(this.metadataEnv)) {\n\t\t\t\tTypeElement nestedTypeElement = (TypeElement) this.metadataEnv.getTypeUtils()\n\t\t\t\t\t.asElement(descriptor.getType());\n\t\t\t\tString nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, descriptor.getName());\n\t\t\t\tprocessSourceElement(metadataCollector, nestedPrefix, nestedTypeElement);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void processEndpoint(Element element, List<Element> annotations) {\n\t\ttry {\n\t\t\tString annotationName = this.metadataEnv.getTypeUtils().getQualifiedName(annotations.get(0));\n\t\t\tAnnotationMirror annotation = this.metadataEnv.getAnnotation(element, annotationName);\n\t\t\tif (element instanceof TypeElement typeElement) {\n\t\t\t\tprocessEndpoint(annotation, typeElement);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Error processing configuration meta-data on \" + element, ex);\n\t\t}\n\t}\n\n\tprivate void processEndpoint(AnnotationMirror annotation, TypeElement element) {\n\t\tMap<String, Object> elementValues = this.metadataEnv.getAnnotationElementValues(annotation);\n\t\tString endpointId = (String) elementValues.get(\"id\");\n\t\tif (endpointId == null || endpointId.isEmpty()) {\n\t\t\treturn; // Can't process that endpoint\n\t\t}\n\t\tString endpointKey = ItemMetadata.newItemMetadataPrefix(\"management.endpoint.\", endpointId);\n\t\tString defaultAccess = elementValues.getOrDefault(\"defaultAccess\", \"unrestricted\")\n\t\t\t.toString()\n\t\t\t.toLowerCase(Locale.ENGLISH);\n\t\tString type = this.metadataEnv.getTypeUtils().getQualifiedName(element);\n\t\tthis.metadataCollector.addIfAbsent(ItemMetadata.newGroup(endpointKey, type, type, null));\n\t\tItemMetadata accessProperty = ItemMetadata.newProperty(endpointKey, \"access\", endpointAccessEnum(), type, null,\n\t\t\t\t\"Permitted level of access for the %s endpoint.\".formatted(endpointId), defaultAccess, null);\n\t\tthis.metadataCollector.add(accessProperty,\n\t\t\t\t(existing) -> checkDefaultAccessValueMatchesExisting(existing, defaultAccess, type));\n\t\tif (hasMainReadOperation(element)) {\n\t\t\tthis.metadataCollector.addIfAbsent(ItemMetadata.newProperty(endpointKey, \"cache.time-to-live\",\n\t\t\t\t\tDuration.class.getName(), type, null, \"Maximum time that a response can be cached.\", \"0ms\", null));\n\t\t}\n\t}\n\n\tprivate void checkDefaultAccessValueMatchesExisting(ItemMetadata existing, String defaultAccess,\n\t\t\tString sourceType) {\n\t\tString existingDefaultAccess = (String) existing.getDefaultValue();\n\t\tif (!Objects.equals(defaultAccess, existingDefaultAccess)) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Existing property '%s' from type %s has a conflicting value. Existing value: %s, new value from type %s: %s\"\n\t\t\t\t\t\t.formatted(existing.getName(), existing.getSourceType(), existingDefaultAccess, sourceType,\n\t\t\t\t\t\t\t\tdefaultAccess));\n\t\t}\n\t}\n\n\tprivate boolean hasMainReadOperation(TypeElement element) {\n\t\tfor (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {\n\t\t\tif (this.metadataEnv.getReadOperationAnnotation(method) != null\n\t\t\t\t\t&& (TypeKind.VOID != method.getReturnType().getKind()) && hasNoOrOptionalParameters(method)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean hasNoOrOptionalParameters(ExecutableElement method) {\n\t\tfor (VariableElement parameter : method.getParameters()) {\n\t\t\tif (!this.metadataEnv.hasNullableAnnotation(parameter)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate String getPrefix(AnnotationMirror annotation) {\n\t\tString prefix = this.metadataEnv.getAnnotationElementStringValue(annotation, \"prefix\");\n\t\tif (prefix != null) {\n\t\t\treturn prefix;\n\t\t}\n\t\treturn this.metadataEnv.getAnnotationElementStringValue(annotation, \"value\");\n\t}\n\n\tprotected void writeSourceMetadata() throws Exception {\n\t\tfor (TypeElement sourceType : this.metadataCollectors.getSourceTypes()) {\n\t\t\tConfigurationMetadata metadata = this.metadataCollectors.getMetadataCollector(sourceType).getMetadata();\n\t\t\tmetadata = mergeAdditionalMetadata(metadata, () -> this.metadataStore.readAdditionalMetadata(sourceType));\n\t\t\tremoveIgnored(metadata);\n\t\t\tif (!metadata.getItems().isEmpty()) {\n\t\t\t\tthis.metadataStore.writeMetadata(metadata, sourceType);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected ConfigurationMetadata writeMetadata() throws Exception {\n\t\tConfigurationMetadata metadata = this.metadataCollector.getMetadata();\n\t\tmetadata = mergeAdditionalMetadata(metadata, () -> this.metadataStore.readAdditionalMetadata());\n\t\tremoveIgnored(metadata);\n\t\tif (!metadata.getItems().isEmpty()) {\n\t\t\tthis.metadataStore.writeMetadata(metadata);\n\t\t\treturn metadata;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void removeIgnored(ConfigurationMetadata metadata) {\n\t\tfor (ItemIgnore itemIgnore : metadata.getIgnored()) {\n\t\t\tmetadata.removeMetadata(itemIgnore.getType(), itemIgnore.getName());\n\t\t}\n\t}\n\n\tprivate ConfigurationMetadata mergeAdditionalMetadata(ConfigurationMetadata metadata,\n\t\t\tSupplier<ConfigurationMetadata> additionalMetadataSupplier) {\n\t\ttry {\n\t\t\tConfigurationMetadata additionalMetadata = additionalMetadataSupplier.get();\n\t\t\tif (additionalMetadata != null) {\n\t\t\t\tConfigurationMetadata merged = new ConfigurationMetadata(metadata);\n\t\t\t\tmerged.merge(additionalMetadata);\n\t\t\t\treturn merged;\n\t\t\t}\n\t\t\treturn metadata;\n\t\t}\n\t\tcatch (InvalidConfigurationMetadataException ex) {\n\t\t\tlog(ex.getKind(), ex.getMessage());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogWarning(\"Unable to merge additional metadata\");\n\t\t\tlogWarning(getStackTrace(ex));\n\t\t}\n\t\treturn metadata;\n\t}\n\n\tprivate String getStackTrace(Exception ex) {\n\t\tStringWriter writer = new StringWriter();\n\t\tex.printStackTrace(new PrintWriter(writer, true));\n\t\treturn writer.toString();\n\t}\n\n\tprivate void logWarning(String msg) {\n\t\tlog(Kind.WARNING, msg);\n\t}\n\n\tprivate void log(Kind kind, String msg) {\n\t\tthis.processingEnv.getMessager().printMessage(kind, msg);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConfigurationPropertiesSourceResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.tools.FileObject;\nimport javax.tools.StandardLocation;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;\nimport org.springframework.boot.configurationprocessor.support.ConventionUtils;\n\n/**\n * Resolve source configuration metadata for arbitrary types.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationPropertiesSourceResolver {\n\n\tprivate final ProcessingEnvironment processingEnvironment;\n\n\tprivate final TypeUtils typeUtils;\n\n\tConfigurationPropertiesSourceResolver(ProcessingEnvironment processingEnvironment, TypeUtils typeUtils) {\n\t\tthis.typeUtils = typeUtils;\n\t\tthis.processingEnvironment = processingEnvironment;\n\t}\n\n\t/**\n\t * Resolve the {@link SourceMetadata} for the specified type. If the type has no\n\t * source metadata, return an {@link SourceMetadata#EMPTY} source.\n\t * @param typeElement the type to discover source metadata from\n\t * @return the source metadata for the specified type\n\t */\n\tSourceMetadata resolveSource(TypeElement typeElement) {\n\t\tConfigurationMetadata configurationMetadata = resolveConfigurationMetadata(typeElement);\n\t\treturn (configurationMetadata != null)\n\t\t\t\t? new SourceMetadata(configurationMetadata.getItems(), configurationMetadata.getHints())\n\t\t\t\t: SourceMetadata.EMPTY;\n\t}\n\n\tprivate ConfigurationMetadata resolveConfigurationMetadata(TypeElement type) {\n\t\ttry {\n\t\t\tString sourceLocation = MetadataStore.SOURCE_METADATA_PATH.apply(type, this.typeUtils);\n\t\t\tFileObject resource = this.processingEnvironment.getFiler()\n\t\t\t\t.getResource(StandardLocation.CLASS_PATH, \"\", sourceLocation);\n\t\t\treturn (resource != null) ? new JsonMarshaller().read(resource.openInputStream()) : null;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Additional source of metadata.\n\t */\n\tstatic final class SourceMetadata {\n\n\t\t/**\n\t\t * An empty source metadata.\n\t\t */\n\t\tpublic static final SourceMetadata EMPTY = new SourceMetadata(Collections.emptyList(), Collections.emptyList());\n\n\t\tprivate final Map<String, ItemMetadata> items;\n\n\t\tprivate final Map<String, ItemHint> hints;\n\n\t\tprivate SourceMetadata(List<ItemMetadata> items, List<ItemHint> hints) {\n\t\t\tthis.items = items.stream()\n\t\t\t\t.collect(Collectors.toMap((item) -> ConventionUtils.toDashedCase(item.getName()), Function.identity()));\n\t\t\tthis.hints = hints.stream()\n\t\t\t\t.collect(Collectors.toMap((item) -> ConventionUtils.toDashedCase(item.getName()), Function.identity()));\n\t\t}\n\n\t\t/**\n\t\t * Create a {@link PropertyDescriptor} for the given property name.\n\t\t * @param name the name of a property\n\t\t * @param propertyDescriptor the descriptor of the property\n\t\t * @return a property descriptor that applies additional source metadata if\n\t\t * necessary\n\t\t */\n\t\tPropertyDescriptor createPropertyDescriptor(String name, PropertyDescriptor propertyDescriptor) {\n\t\t\tString key = ConventionUtils.toDashedCase(name);\n\t\t\tif (this.items.containsKey(key)) {\n\t\t\t\tItemMetadata itemMetadata = this.items.get(key);\n\t\t\t\tItemHint itemHint = this.hints.get(key);\n\t\t\t\treturn new SourcePropertyDescriptor(propertyDescriptor, itemMetadata, itemHint);\n\t\t\t}\n\t\t\treturn propertyDescriptor;\n\t\t}\n\n\t\t/**\n\t\t * Create a {@link PropertyDescriptor} for the given property name.\n\t\t * @param name the name of a property\n\t\t * @param regularDescriptor a function to get the descriptor\n\t\t * @return a property descriptor that applies additional source metadata if\n\t\t * necessary\n\t\t */\n\t\tPropertyDescriptor createPropertyDescriptor(String name,\n\t\t\t\tFunction<String, PropertyDescriptor> regularDescriptor) {\n\t\t\treturn createPropertyDescriptor(name, regularDescriptor.apply(name));\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@link PropertyDescriptor} that applies source metadata.\n\t */\n\tstatic class SourcePropertyDescriptor extends PropertyDescriptor {\n\n\t\tprivate final PropertyDescriptor delegate;\n\n\t\tprivate final ItemMetadata sourceItemMetadata;\n\n\t\tprivate final ItemHint sourceItemHint;\n\n\t\tSourcePropertyDescriptor(PropertyDescriptor delegate, ItemMetadata sourceItemMetadata,\n\t\t\t\tItemHint sourceItemHint) {\n\t\t\tsuper(delegate.getName(), delegate.getType(), delegate.getDeclaringElement(), delegate.getGetter());\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.sourceItemMetadata = sourceItemMetadata;\n\t\t\tthis.sourceItemHint = sourceItemHint;\n\t\t}\n\n\t\t@Override\n\t\tprotected ItemHint resolveItemHint(String prefix, MetadataGenerationEnvironment environment) {\n\t\t\treturn (this.sourceItemHint != null) ? this.sourceItemHint.applyPrefix(prefix)\n\t\t\t\t\t: super.resolveItemHint(prefix, environment);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean isMarkedAsNested(MetadataGenerationEnvironment environment) {\n\t\t\treturn this.delegate.isMarkedAsNested(environment);\n\t\t}\n\n\t\t@Override\n\t\tprotected String resolveDescription(MetadataGenerationEnvironment environment) {\n\t\t\tString description = this.delegate.resolveDescription(environment);\n\t\t\treturn (description != null) ? description : this.sourceItemMetadata.getDescription();\n\t\t}\n\n\t\t@Override\n\t\tprotected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {\n\t\t\tObject defaultValue = this.delegate.resolveDefaultValue(environment);\n\t\t\treturn (defaultValue != null) ? defaultValue : this.sourceItemMetadata.getDefaultValue();\n\t\t}\n\n\t\t@Override\n\t\tprotected ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment) {\n\t\t\tItemDeprecation itemDeprecation = this.delegate.resolveItemDeprecation(environment);\n\t\t\treturn (itemDeprecation != null) ? itemDeprecation : this.sourceItemMetadata.getDeprecation();\n\t\t}\n\n\t\t@Override\n\t\tboolean isProperty(MetadataGenerationEnvironment environment) {\n\t\t\treturn this.delegate.isProperty(environment);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\n\n/**\n * A {@link PropertyDescriptor} for a constructor parameter.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ConstructorParameterPropertyDescriptor extends ParameterPropertyDescriptor {\n\n\tprivate final ExecutableElement setter;\n\n\tprivate final VariableElement field;\n\n\tConstructorParameterPropertyDescriptor(String name, TypeMirror type, VariableElement parameter,\n\t\t\tTypeElement declaringElement, ExecutableElement getter, ExecutableElement setter, VariableElement field) {\n\t\tsuper(name, type, parameter, declaringElement, getter);\n\t\tthis.setter = setter;\n\t\tthis.field = field;\n\t}\n\n\t@Override\n\tprotected ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment) {\n\t\treturn resolveItemDeprecation(environment, getGetter(), this.setter, this.field);\n\t}\n\n\t@Override\n\tprotected boolean isMarkedAsNested(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getNestedConfigurationPropertyAnnotation(this.field) != null\n\t\t\t\t|| environment.getNestedConfigurationPropertyAnnotation(getGetter()) != null;\n\t}\n\n\t@Override\n\tprotected String resolveDescription(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getTypeUtils().getJavaDoc(this.field);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/JavaBeanPropertyDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\n\n/**\n * A {@link PropertyDescriptor} for a standard JavaBean property.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass JavaBeanPropertyDescriptor extends PropertyDescriptor {\n\n\tprivate final ExecutableElement setter;\n\n\tprivate final VariableElement field;\n\n\tprivate final ExecutableElement factoryMethod;\n\n\tJavaBeanPropertyDescriptor(String name, TypeMirror type, TypeElement declaringElement, ExecutableElement getter,\n\t\t\tExecutableElement setter, VariableElement field, ExecutableElement factoryMethod) {\n\t\tsuper(name, type, declaringElement, getter);\n\t\tthis.setter = setter;\n\t\tthis.field = field;\n\t\tthis.factoryMethod = factoryMethod;\n\t}\n\n\tExecutableElement getSetter() {\n\t\treturn this.setter;\n\t}\n\n\t@Override\n\tprotected boolean isMarkedAsNested(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getNestedConfigurationPropertyAnnotation(this.field) != null\n\t\t\t\t|| environment.getNestedConfigurationPropertyAnnotation(getGetter()) != null;\n\t}\n\n\t@Override\n\tprotected String resolveDescription(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getTypeUtils().getJavaDoc(this.field);\n\t}\n\n\t@Override\n\tprotected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getFieldDefaultValue(getDeclaringElement(), this.field);\n\t}\n\n\t@Override\n\tprotected ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment) {\n\t\treturn resolveItemDeprecation(environment, getGetter(), this.setter, this.field, this.factoryMethod);\n\t}\n\n\t@Override\n\tpublic boolean isProperty(MetadataGenerationEnvironment env) {\n\t\tboolean isCollection = env.getTypeUtils().isCollectionOrMap(getType());\n\t\tboolean hasGetter = getGetter() != null;\n\t\tboolean hasSetter = getSetter() != null;\n\t\treturn !env.isExcluded(getType()) && hasGetter && (hasSetter || isCollection);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/LombokPropertyDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Map;\n\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\n\n/**\n * A {@link PropertyDescriptor} for a Lombok field.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass LombokPropertyDescriptor extends PropertyDescriptor {\n\n\tprivate static final String LOMBOK_DATA_ANNOTATION = \"lombok.Data\";\n\n\tprivate static final String LOMBOK_VALUE_ANNOTATION = \"lombok.Value\";\n\n\tprivate static final String LOMBOK_GETTER_ANNOTATION = \"lombok.Getter\";\n\n\tprivate static final String LOMBOK_SETTER_ANNOTATION = \"lombok.Setter\";\n\n\tprivate static final String LOMBOK_ACCESS_LEVEL_PUBLIC = \"PUBLIC\";\n\n\tprivate final ExecutableElement setter;\n\n\tprivate final VariableElement field;\n\n\tprivate final ExecutableElement factoryMethod;\n\n\tLombokPropertyDescriptor(String name, TypeMirror type, TypeElement declaringElement, ExecutableElement getter,\n\t\t\tExecutableElement setter, VariableElement field, ExecutableElement factoryMethod) {\n\t\tsuper(name, type, declaringElement, getter);\n\t\tthis.factoryMethod = factoryMethod;\n\t\tthis.field = field;\n\t\tthis.setter = setter;\n\t}\n\n\tVariableElement getField() {\n\t\treturn this.field;\n\t}\n\n\t@Override\n\tprotected boolean isMarkedAsNested(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getNestedConfigurationPropertyAnnotation(getField()) != null;\n\t}\n\n\t@Override\n\tprotected String resolveDescription(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getTypeUtils().getJavaDoc(this.field);\n\t}\n\n\t@Override\n\tprotected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getFieldDefaultValue(getDeclaringElement(), this.field);\n\t}\n\n\t@Override\n\tprotected ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment) {\n\t\treturn resolveItemDeprecation(environment, getGetter(), this.setter, this.field, this.factoryMethod);\n\t}\n\n\t@Override\n\tpublic boolean isProperty(MetadataGenerationEnvironment env) {\n\t\tif (!hasLombokPublicAccessor(env, true)) {\n\t\t\treturn false;\n\t\t}\n\t\tboolean isCollection = env.getTypeUtils().isCollectionOrMap(getType());\n\t\treturn !env.isExcluded(getType()) && (hasSetter(env) || isCollection);\n\t}\n\n\t@Override\n\tpublic boolean isNested(MetadataGenerationEnvironment environment) {\n\t\treturn hasLombokPublicAccessor(environment, true) && super.isNested(environment);\n\t}\n\n\tprivate boolean hasSetter(MetadataGenerationEnvironment env) {\n\t\tboolean nonFinalPublicField = !getField().getModifiers().contains(Modifier.FINAL)\n\t\t\t\t&& hasLombokPublicAccessor(env, false);\n\t\treturn this.setter != null || nonFinalPublicField;\n\t}\n\n\t/**\n\t * Determine if the current {@link #getField() field} defines a public accessor using\n\t * lombok annotations.\n\t * @param env the {@link MetadataGenerationEnvironment}\n\t * @param getter {@code true} to look for the read accessor, {@code false} for the\n\t * write accessor\n\t * @return {@code true} if this field has a public accessor of the specified type\n\t */\n\tprivate boolean hasLombokPublicAccessor(MetadataGenerationEnvironment env, boolean getter) {\n\t\tString annotation = (getter ? LOMBOK_GETTER_ANNOTATION : LOMBOK_SETTER_ANNOTATION);\n\t\tAnnotationMirror lombokMethodAnnotationOnField = env.getAnnotation(getField(), annotation);\n\t\tif (lombokMethodAnnotationOnField != null) {\n\t\t\treturn isAccessLevelPublic(env, lombokMethodAnnotationOnField);\n\t\t}\n\t\tAnnotationMirror lombokMethodAnnotationOnElement = env.getAnnotation(getDeclaringElement(), annotation);\n\t\tif (lombokMethodAnnotationOnElement != null) {\n\t\t\treturn isAccessLevelPublic(env, lombokMethodAnnotationOnElement);\n\t\t}\n\t\treturn (env.hasAnnotation(getDeclaringElement(), LOMBOK_DATA_ANNOTATION)\n\t\t\t\t|| env.hasAnnotation(getDeclaringElement(), LOMBOK_VALUE_ANNOTATION));\n\t}\n\n\tprivate boolean isAccessLevelPublic(MetadataGenerationEnvironment env, AnnotationMirror lombokAnnotation) {\n\t\tMap<String, Object> values = env.getAnnotationElementValues(lombokAnnotation);\n\t\tObject value = values.get(\"value\");\n\t\treturn (value == null || value.toString().equals(LOMBOK_ACCESS_LEVEL_PUBLIC));\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataCollector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\n\n/**\n * Used by {@link ConfigurationMetadataAnnotationProcessor} to collect\n * {@link ConfigurationMetadata}.\n *\n * @author Andy Wilkinson\n * @author Kris De Volder\n * @author Moritz Halbritter\n * @author Stephane Nicoll\n */\nclass MetadataCollector {\n\n\tprivate final Predicate<ItemMetadata> mergeRequired;\n\n\tprivate final ConfigurationMetadata previousMetadata;\n\n\tprivate final Set<ItemMetadata> metadataItems = new LinkedHashSet<>();\n\n\tprivate final Set<ItemHint> metadataHints = new LinkedHashSet<>();\n\n\t/**\n\t * Creates a new {@code MetadataProcessor} instance.\n\t * @param mergeRequired specify whether an item can be merged\n\t * @param previousMetadata any previous metadata or {@code null}\n\t */\n\tMetadataCollector(Predicate<ItemMetadata> mergeRequired, ConfigurationMetadata previousMetadata) {\n\t\tthis.mergeRequired = mergeRequired;\n\t\tthis.previousMetadata = previousMetadata;\n\t}\n\n\tvoid add(ItemMetadata metadata) {\n\t\tthis.metadataItems.add(metadata);\n\t}\n\n\tvoid add(ItemMetadata metadata, Consumer<ItemMetadata> onConflict) {\n\t\tItemMetadata existing = find(metadata.getName());\n\t\tif (existing != null) {\n\t\t\tonConflict.accept(existing);\n\t\t\treturn;\n\t\t}\n\t\tadd(metadata);\n\t}\n\n\tboolean addIfAbsent(ItemMetadata metadata) {\n\t\tItemMetadata existing = find(metadata.getName());\n\t\tif (existing != null) {\n\t\t\treturn false;\n\t\t}\n\t\tadd(metadata);\n\t\treturn true;\n\t}\n\n\tvoid add(ItemHint itemHint) {\n\t\tthis.metadataHints.add(itemHint);\n\t}\n\n\tboolean hasSimilarGroup(ItemMetadata metadata) {\n\t\tif (!metadata.isOfItemType(ItemMetadata.ItemType.GROUP)) {\n\t\t\tthrow new IllegalStateException(\"item \" + metadata + \" must be a group\");\n\t\t}\n\t\tfor (ItemMetadata existing : this.metadataItems) {\n\t\t\tif (existing.isOfItemType(ItemMetadata.ItemType.GROUP) && existing.getName().equals(metadata.getName())\n\t\t\t\t\t&& existing.getType().equals(metadata.getType())) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tConfigurationMetadata getMetadata() {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tfor (ItemMetadata item : this.metadataItems) {\n\t\t\tmetadata.add(item);\n\t\t}\n\t\tfor (ItemHint metadataHint : this.metadataHints) {\n\t\t\tmetadata.add(metadataHint);\n\t\t}\n\t\tif (this.previousMetadata != null) {\n\t\t\tList<ItemMetadata> items = this.previousMetadata.getItems();\n\t\t\tfor (ItemMetadata item : items) {\n\t\t\t\tif (this.mergeRequired.test(item)) {\n\t\t\t\t\tmetadata.addIfMissing(item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn metadata;\n\t}\n\n\tprivate ItemMetadata find(String name) {\n\t\treturn this.metadataItems.stream()\n\t\t\t.filter((candidate) -> name.equals(candidate.getName()))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataCollectors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\n\n/**\n * Container for {@link MetadataCollector}. Usually, either metadata for the whole module\n * or metadata for types is generated. This makes sure to record types that have been\n * processed and determine if previous metadata should be merged.\n *\n * @author Stephane Nicoll\n */\nclass MetadataCollectors {\n\n\tprivate final ProcessingEnvironment processingEnvironment;\n\n\tprivate final TypeUtils typeUtils;\n\n\tprivate final MetadataStore metadataStore;\n\n\tprivate final MetadataCollector metadataCollector;\n\n\tprivate final Set<String> processedSourceTypes = new HashSet<>();\n\n\tprivate final Map<TypeElement, MetadataCollector> metadataTypeCollectors = new HashMap<>();\n\n\tMetadataCollectors(ProcessingEnvironment processingEnvironment, TypeUtils typeUtils) {\n\t\tthis.processingEnvironment = processingEnvironment;\n\t\tthis.typeUtils = typeUtils;\n\t\tthis.metadataStore = new MetadataStore(this.processingEnvironment, this.typeUtils);\n\t\tthis.metadataCollector = new MetadataCollector(this::shouldBeMerged, this.metadataStore.readMetadata());\n\t}\n\n\tvoid processing(RoundEnvironment roundEnv) {\n\t\tfor (Element element : roundEnv.getRootElements()) {\n\t\t\tif (element instanceof TypeElement) {\n\t\t\t\tthis.processedSourceTypes.add(this.typeUtils.getQualifiedName(element));\n\t\t\t}\n\t\t}\n\t}\n\n\tMetadataCollector getModuleMetadataCollector() {\n\t\treturn this.metadataCollector;\n\t}\n\n\tMetadataCollector getMetadataCollector(TypeElement element) {\n\t\treturn this.metadataTypeCollectors.computeIfAbsent(element,\n\t\t\t\t(ignored) -> new MetadataCollector(this::shouldBeMerged, this.metadataStore.readMetadata(element)));\n\t}\n\n\tSet<TypeElement> getSourceTypes() {\n\t\treturn this.metadataTypeCollectors.keySet();\n\t}\n\n\tprivate boolean shouldBeMerged(ItemMetadata itemMetadata) {\n\t\tString sourceType = itemMetadata.getSourceType();\n\t\treturn (sourceType != null && !deletedInCurrentBuild(sourceType) && !processedInCurrentBuild(sourceType));\n\t}\n\n\tprivate boolean deletedInCurrentBuild(String sourceType) {\n\t\treturn this.processingEnvironment.getElementUtils().getTypeElement(sourceType.replace('$', '.')) == null;\n\t}\n\n\tprivate boolean processedInCurrentBuild(String sourceType) {\n\t\treturn this.processedSourceTypes.contains(sourceType);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport javax.annotation.processing.Messager;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.AnnotationValue;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.Elements;\n\nimport org.springframework.boot.configurationprocessor.ConfigurationPropertiesSourceResolver.SourceMetadata;\nimport org.springframework.boot.configurationprocessor.fieldvalues.FieldValuesParser;\nimport org.springframework.boot.configurationprocessor.fieldvalues.javac.JavaCompilerFieldValuesParser;\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\n\n/**\n * Provide utilities to detect and validate configuration properties.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass MetadataGenerationEnvironment {\n\n\tprivate static final String NULLABLE_ANNOTATION = \"org.jspecify.annotations.Nullable\";\n\n\tprivate static final Set<String> TYPE_EXCLUDES = Set.of(\"com.zaxxer.hikari.IConnectionCustomizer\",\n\t\t\t\"groovy.lang.MetaClass\", \"groovy.text.markup.MarkupTemplateEngine\", \"java.io.Writer\", \"java.io.PrintWriter\",\n\t\t\t\"java.lang.ClassLoader\", \"java.util.concurrent.ThreadFactory\", \"jakarta.jms.XAConnectionFactory\",\n\t\t\t\"javax.sql.DataSource\", \"javax.sql.XADataSource\", \"org.apache.tomcat.jdbc.pool.PoolConfiguration\",\n\t\t\t\"org.apache.tomcat.jdbc.pool.Validator\", \"org.flywaydb.core.api.callback.FlywayCallback\",\n\t\t\t\"org.flywaydb.core.api.resolver.MigrationResolver\");\n\n\tprivate static final Set<String> DEPRECATION_EXCLUDES = Set.of(\n\t\t\t\"org.apache.commons.dbcp2.BasicDataSource#getPassword\",\n\t\t\t\"org.apache.commons.dbcp2.BasicDataSource#getUsername\");\n\n\tprivate final TypeUtils typeUtils;\n\n\tprivate final Elements elements;\n\n\tprivate final Messager messager;\n\n\tprivate final FieldValuesParser fieldValuesParser;\n\n\tprivate final ConfigurationPropertiesSourceResolver sourceResolver;\n\n\tprivate final Map<TypeElement, Map<String, Object>> defaultValues = new HashMap<>();\n\n\tprivate final Map<TypeElement, SourceMetadata> sources = new HashMap<>();\n\n\tprivate final String configurationPropertiesAnnotation;\n\n\tprivate final String nestedConfigurationPropertyAnnotation;\n\n\tprivate final String configurationPropertiesSourceAnnotation;\n\n\tprivate final String deprecatedConfigurationPropertyAnnotation;\n\n\tprivate final String constructorBindingAnnotation;\n\n\tprivate final String defaultValueAnnotation;\n\n\tprivate final Set<String> endpointAnnotations;\n\n\tprivate final String readOperationAnnotation;\n\n\tprivate final String nameAnnotation;\n\n\tprivate final String autowiredAnnotation;\n\n\tMetadataGenerationEnvironment(ProcessingEnvironment environment, String configurationPropertiesAnnotation,\n\t\t\tString configurationPropertiesSourceAnnotation, String nestedConfigurationPropertyAnnotation,\n\t\t\tString deprecatedConfigurationPropertyAnnotation, String constructorBindingAnnotation,\n\t\t\tString autowiredAnnotation, String defaultValueAnnotation, Set<String> endpointAnnotations,\n\t\t\tString readOperationAnnotation, String nameAnnotation) {\n\t\tthis.typeUtils = new TypeUtils(environment);\n\t\tthis.elements = environment.getElementUtils();\n\t\tthis.messager = environment.getMessager();\n\t\tthis.fieldValuesParser = resolveFieldValuesParser(environment);\n\t\tthis.sourceResolver = new ConfigurationPropertiesSourceResolver(environment, this.typeUtils);\n\t\tthis.configurationPropertiesAnnotation = configurationPropertiesAnnotation;\n\t\tthis.configurationPropertiesSourceAnnotation = configurationPropertiesSourceAnnotation;\n\t\tthis.nestedConfigurationPropertyAnnotation = nestedConfigurationPropertyAnnotation;\n\t\tthis.deprecatedConfigurationPropertyAnnotation = deprecatedConfigurationPropertyAnnotation;\n\t\tthis.constructorBindingAnnotation = constructorBindingAnnotation;\n\t\tthis.autowiredAnnotation = autowiredAnnotation;\n\t\tthis.defaultValueAnnotation = defaultValueAnnotation;\n\t\tthis.endpointAnnotations = endpointAnnotations;\n\t\tthis.readOperationAnnotation = readOperationAnnotation;\n\t\tthis.nameAnnotation = nameAnnotation;\n\t}\n\n\tprivate static FieldValuesParser resolveFieldValuesParser(ProcessingEnvironment env) {\n\t\ttry {\n\t\t\treturn new JavaCompilerFieldValuesParser(env);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn FieldValuesParser.NONE;\n\t\t}\n\t}\n\n\tTypeUtils getTypeUtils() {\n\t\treturn this.typeUtils;\n\t}\n\n\tMessager getMessager() {\n\t\treturn this.messager;\n\t}\n\n\t/**\n\t * Return the default value of the given {@code field}.\n\t * @param type the type to consider\n\t * @param field the field or {@code null} if it is not available\n\t * @return the default value or {@code null} if the field does not exist or no default\n\t * value has been detected\n\t */\n\tObject getFieldDefaultValue(TypeElement type, VariableElement field) {\n\t\treturn (field != null) ? this.defaultValues.computeIfAbsent(type, this::resolveFieldValues)\n\t\t\t.get(field.getSimpleName().toString()) : null;\n\t}\n\n\t/**\n\t * Resolve the {@link SourceMetadata} for the specified property.\n\t * @param field the field of the property (can be {@code null})\n\t * @param getter the getter of the property (can be {@code null})\n\t * @return the {@link SourceMetadata} for the specified property\n\t */\n\tSourceMetadata resolveSourceMetadata(VariableElement field, ExecutableElement getter) {\n\t\tif (field != null && field.getEnclosingElement() instanceof TypeElement type) {\n\t\t\treturn this.sources.computeIfAbsent(type, this.sourceResolver::resolveSource);\n\t\t}\n\t\tif (getter != null && getter.getEnclosingElement() instanceof TypeElement type) {\n\t\t\treturn this.sources.computeIfAbsent(type, this.sourceResolver::resolveSource);\n\t\t}\n\t\treturn SourceMetadata.EMPTY;\n\t}\n\n\tboolean isExcluded(TypeMirror type) {\n\t\tif (type == null) {\n\t\t\treturn false;\n\t\t}\n\t\tString typeName = type.toString();\n\t\tif (typeName.endsWith(\"[]\")) {\n\t\t\ttypeName = typeName.substring(0, typeName.length() - 2);\n\t\t}\n\t\treturn TYPE_EXCLUDES.contains(typeName);\n\t}\n\n\tboolean isDeprecated(Element element) {\n\t\tif (element == null) {\n\t\t\treturn false;\n\t\t}\n\t\tString elementName = element.getEnclosingElement() + \"#\" + element.getSimpleName();\n\t\tif (DEPRECATION_EXCLUDES.contains(elementName)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (isElementDeprecated(element)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (element instanceof VariableElement || element instanceof ExecutableElement) {\n\t\t\treturn isElementDeprecated(element.getEnclosingElement());\n\t\t}\n\t\treturn false;\n\t}\n\n\tItemDeprecation resolveItemDeprecation(Element element) {\n\t\tAnnotationMirror annotation = getAnnotation(element, this.deprecatedConfigurationPropertyAnnotation);\n\t\tString reason = null;\n\t\tString replacement = null;\n\t\tString since = null;\n\t\tif (annotation != null) {\n\t\t\treason = getAnnotationElementStringValue(annotation, \"reason\");\n\t\t\treplacement = getAnnotationElementStringValue(annotation, \"replacement\");\n\t\t\tsince = getAnnotationElementStringValue(annotation, \"since\");\n\t\t}\n\t\treturn new ItemDeprecation(reason, replacement, since);\n\t}\n\n\tboolean hasConstructorBindingAnnotation(ExecutableElement element) {\n\t\treturn hasAnnotation(element, this.constructorBindingAnnotation, true);\n\t}\n\n\tboolean hasAutowiredAnnotation(ExecutableElement element) {\n\t\treturn hasAnnotation(element, this.autowiredAnnotation);\n\t}\n\n\tboolean hasAnnotation(Element element, String type) {\n\t\treturn hasAnnotation(element, type, false);\n\t}\n\n\tboolean hasAnnotation(Element element, String type, boolean considerMetaAnnotations) {\n\t\tif (element != null) {\n\t\t\tfor (AnnotationMirror annotation : element.getAnnotationMirrors()) {\n\t\t\t\tif (type.equals(annotation.getAnnotationType().toString())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (considerMetaAnnotations) {\n\t\t\t\tSet<Element> seen = new HashSet<>();\n\t\t\t\tfor (AnnotationMirror annotation : element.getAnnotationMirrors()) {\n\t\t\t\t\tif (hasMetaAnnotation(annotation.getAnnotationType().asElement(), type, seen)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean hasMetaAnnotation(Element annotationElement, String type, Set<Element> seen) {\n\t\tif (seen.add(annotationElement)) {\n\t\t\tfor (AnnotationMirror annotation : annotationElement.getAnnotationMirrors()) {\n\t\t\t\tDeclaredType annotationType = annotation.getAnnotationType();\n\t\t\t\tif (type.equals(annotationType.toString())\n\t\t\t\t\t\t|| hasMetaAnnotation(annotationType.asElement(), type, seen)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tAnnotationMirror getAnnotation(Element element, String type) {\n\t\tif (element != null) {\n\t\t\tfor (AnnotationMirror annotation : element.getAnnotationMirrors()) {\n\t\t\t\tif (type.equals(annotation.getAnnotationType().toString())) {\n\t\t\t\t\treturn annotation;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate AnnotationMirror getTypeUseAnnotation(Element element, String type) {\n\t\tif (element != null) {\n\t\t\tfor (AnnotationMirror annotation : element.asType().getAnnotationMirrors()) {\n\t\t\t\tif (type.equals(annotation.getAnnotationType().toString())) {\n\t\t\t\t\treturn annotation;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Collect the annotations that are annotated or meta-annotated with the specified\n\t * {@link TypeElement annotation}.\n\t * @param element the element to inspect\n\t * @param annotationType the annotation to discover\n\t * @return the annotations that are annotated or meta-annotated with this annotation\n\t */\n\tList<Element> getElementsAnnotatedOrMetaAnnotatedWith(Element element, TypeElement annotationType) {\n\t\tLinkedList<Element> stack = new LinkedList<>();\n\t\tstack.push(element);\n\t\tcollectElementsAnnotatedOrMetaAnnotatedWith(annotationType, stack);\n\t\tstack.removeFirst();\n\t\treturn Collections.unmodifiableList(stack);\n\t}\n\n\tprivate boolean collectElementsAnnotatedOrMetaAnnotatedWith(TypeElement annotationType, LinkedList<Element> stack) {\n\t\tElement element = stack.peekLast();\n\t\tfor (AnnotationMirror annotation : this.elements.getAllAnnotationMirrors(element)) {\n\t\t\tElement annotationElement = annotation.getAnnotationType().asElement();\n\t\t\tif (!stack.contains(annotationElement)) {\n\t\t\t\tstack.addLast(annotationElement);\n\t\t\t\tif (annotationElement.equals(annotationType)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (!collectElementsAnnotatedOrMetaAnnotatedWith(annotationType, stack)) {\n\t\t\t\t\tstack.removeLast();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tMap<String, Object> getAnnotationElementValues(AnnotationMirror annotation) {\n\t\tMap<String, Object> values = new LinkedHashMap<>();\n\t\tannotation.getElementValues()\n\t\t\t.forEach((name, value) -> values.put(name.getSimpleName().toString(), getAnnotationValue(value)));\n\t\treturn values;\n\t}\n\n\tString getAnnotationElementStringValue(AnnotationMirror annotation, String name) {\n\t\treturn annotation.getElementValues()\n\t\t\t.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((element) -> element.getKey().getSimpleName().toString().equals(name))\n\t\t\t.map((element) -> asString(getAnnotationValue(element.getValue())))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprivate Object getAnnotationValue(AnnotationValue annotationValue) {\n\t\tObject value = annotationValue.getValue();\n\t\tif (value instanceof List) {\n\t\t\tList<Object> values = new ArrayList<>();\n\t\t\t((List<?>) value).forEach((v) -> values.add(((AnnotationValue) v).getValue()));\n\t\t\treturn values;\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate String asString(Object value) {\n\t\treturn (value == null || value.toString().isEmpty()) ? null : (String) value;\n\t}\n\n\tTypeElement getConfigurationPropertiesAnnotationElement() {\n\t\treturn this.elements.getTypeElement(this.configurationPropertiesAnnotation);\n\t}\n\n\tAnnotationMirror getConfigurationPropertiesAnnotation(Element element) {\n\t\treturn getAnnotation(element, this.configurationPropertiesAnnotation);\n\t}\n\n\tTypeElement getConfigurationPropertiesSourceAnnotationElement() {\n\t\treturn this.elements.getTypeElement(this.configurationPropertiesSourceAnnotation);\n\t}\n\n\tAnnotationMirror getNestedConfigurationPropertyAnnotation(Element element) {\n\t\treturn getAnnotation(element, this.nestedConfigurationPropertyAnnotation);\n\t}\n\n\tAnnotationMirror getDefaultValueAnnotation(Element element) {\n\t\treturn getAnnotation(element, this.defaultValueAnnotation);\n\t}\n\n\tSet<TypeElement> getEndpointAnnotationElements() {\n\t\treturn this.endpointAnnotations.stream()\n\t\t\t.map(this.elements::getTypeElement)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.collect(Collectors.toSet());\n\t}\n\n\tAnnotationMirror getReadOperationAnnotation(Element element) {\n\t\treturn getAnnotation(element, this.readOperationAnnotation);\n\t}\n\n\tAnnotationMirror getNameAnnotation(Element element) {\n\t\treturn getAnnotation(element, this.nameAnnotation);\n\t}\n\n\tboolean hasNullableAnnotation(Element element) {\n\t\treturn getTypeUseAnnotation(element, NULLABLE_ANNOTATION) != null;\n\t}\n\n\tprivate boolean isElementDeprecated(Element element) {\n\t\treturn hasAnnotation(element, \"java.lang.Deprecated\")\n\t\t\t\t|| hasAnnotation(element, this.deprecatedConfigurationPropertyAnnotation);\n\t}\n\n\tprivate Map<String, Object> resolveFieldValues(TypeElement element) {\n\t\tMap<String, Object> values = new LinkedHashMap<>();\n\t\tresolveFieldValuesFor(values, element);\n\t\treturn values;\n\t}\n\n\tprivate void resolveFieldValuesFor(Map<String, Object> values, TypeElement element) {\n\t\ttry {\n\t\t\tthis.fieldValuesParser.getFieldValues(element).forEach((name, value) -> {\n\t\t\t\tif (!values.containsKey(name)) {\n\t\t\t\t\tvalues.put(name, value);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// continue\n\t\t}\n\t\tElement superType = this.typeUtils.asElement(element.getSuperclass());\n\t\tif (superType instanceof TypeElement && superType.asType().getKind() != TypeKind.NONE) {\n\t\t\tresolveFieldValuesFor(values, (TypeElement) superType);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/MetadataStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.function.BiFunction;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.TypeElement;\nimport javax.tools.Diagnostic;\nimport javax.tools.FileObject;\nimport javax.tools.StandardLocation;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.InvalidConfigurationMetadataException;\nimport org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;\n\n/**\n * A {@code MetadataStore} is responsible for the storage of metadata on the filesystem.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass MetadataStore {\n\n\tstatic final String METADATA_PATH = \"META-INF/spring-configuration-metadata.json\";\n\n\tstatic final BiFunction<TypeElement, TypeUtils, String> SOURCE_METADATA_PATH = (type,\n\t\t\ttypeUtils) -> \"META-INF/spring/configuration-metadata/%s.json\".formatted(typeUtils.getQualifiedName(type));\n\n\tprivate static final String ADDITIONAL_METADATA_PATH = \"META-INF/additional-spring-configuration-metadata.json\";\n\n\tstatic final BiFunction<TypeElement, TypeUtils, String> ADDITIONAL_SOURCE_METADATA_PATH = (type,\n\t\t\ttypeUtils) -> \"META-INF/spring/configuration-metadata/additional/%s.json\"\n\t\t\t\t.formatted(typeUtils.getQualifiedName(type));\n\n\tprivate static final String RESOURCES_DIRECTORY = \"resources\";\n\n\tprivate static final String CLASSES_DIRECTORY = \"classes\";\n\n\tprivate final ProcessingEnvironment environment;\n\n\tprivate final TypeUtils typeUtils;\n\n\tMetadataStore(ProcessingEnvironment environment, TypeUtils typeUtils) {\n\t\tthis.environment = environment;\n\t\tthis.typeUtils = typeUtils;\n\t}\n\n\t/**\n\t * Read the existing {@link ConfigurationMetadata} of the current module or\n\t * {@code null} if it is not available yet.\n\t * @return the metadata or {@code null} if none is present\n\t */\n\tConfigurationMetadata readMetadata() {\n\t\treturn readMetadata(METADATA_PATH);\n\t}\n\n\t/**\n\t * Read the existing {@link ConfigurationMetadata} for the specified type or\n\t * {@code null} if it is not available yet.\n\t * @param typeElement the type to read metadata for\n\t * @return the metadata for the given type or {@code null}\n\t */\n\tConfigurationMetadata readMetadata(TypeElement typeElement) {\n\t\treturn readMetadata(SOURCE_METADATA_PATH.apply(typeElement, this.typeUtils));\n\t}\n\n\tprivate ConfigurationMetadata readMetadata(String location) {\n\t\ttry {\n\t\t\treturn readMetadata(location, getMetadataResource(location).openInputStream());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Write the module {@link ConfigurationMetadata} to the filesystem.\n\t * @param metadata the metadata to write\n\t * @throws IOException when the write fails\n\t */\n\tvoid writeMetadata(ConfigurationMetadata metadata) throws IOException {\n\t\twriteMetadata(metadata, () -> createMetadataResource(METADATA_PATH));\n\t}\n\n\t/**\n\t * Write the {@link ConfigurationMetadata} for the {@link TypeElement} to the\n\t * filesystem.\n\t * @param metadata the metadata to write\n\t * @param typeElement the type to write metadata for\n\t * @throws IOException when the write fails\n\t */\n\tvoid writeMetadata(ConfigurationMetadata metadata, TypeElement typeElement) throws IOException {\n\t\twriteMetadata(metadata, () -> createMetadataResource(SOURCE_METADATA_PATH.apply(typeElement, this.typeUtils)));\n\t}\n\n\t/**\n\t * Write the metadata to the {@link FileObject} provided by the given supplier.\n\t * @param metadata the metadata to provide\n\t * @param fileObjectProvider a supplier for the {@link FileObject} to use\n\t */\n\tprivate void writeMetadata(ConfigurationMetadata metadata, FileObjectSupplier fileObjectProvider)\n\t\t\tthrows IOException {\n\t\tif (!metadata.getItems().isEmpty()) {\n\t\t\ttry (OutputStream outputStream = fileObjectProvider.get().openOutputStream()) {\n\t\t\t\tnew JsonMarshaller().write(metadata, outputStream);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Read additional {@link ConfigurationMetadata} for the current module or\n\t * {@code null}.\n\t * @return additional metadata or {@code null} if none is present\n\t */\n\tConfigurationMetadata readAdditionalMetadata() {\n\t\treturn readAdditionalMetadata(ADDITIONAL_METADATA_PATH);\n\t}\n\n\t/**\n\t * Read additional {@link ConfigurationMetadata} for the {@link TypeElement} or\n\t * {@code null}.\n\t * @param typeElement the type to get additional metadata for\n\t * @return additional metadata for the given type or {@code null} if none is present\n\t */\n\tConfigurationMetadata readAdditionalMetadata(TypeElement typeElement) {\n\t\treturn readAdditionalMetadata(ADDITIONAL_SOURCE_METADATA_PATH.apply(typeElement, this.typeUtils));\n\t}\n\n\tprivate ConfigurationMetadata readAdditionalMetadata(String location) {\n\t\ttry {\n\t\t\tInputStream in = getAdditionalMetadataStream(location);\n\t\t\treturn readMetadata(location, in);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate ConfigurationMetadata readMetadata(String location, InputStream in) {\n\t\ttry (in) {\n\t\t\treturn new JsonMarshaller().read(in);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new InvalidConfigurationMetadataException(\n\t\t\t\t\t\"Invalid additional meta-data in '\" + location + \"': \" + ex.getMessage(), Diagnostic.Kind.ERROR);\n\t\t}\n\t}\n\n\tprivate FileObject getMetadataResource(String location) throws IOException {\n\t\treturn this.environment.getFiler().getResource(StandardLocation.CLASS_OUTPUT, \"\", location);\n\t}\n\n\tprivate FileObject createMetadataResource(String location) throws IOException {\n\t\treturn this.environment.getFiler().createResource(StandardLocation.CLASS_OUTPUT, \"\", location);\n\t}\n\n\tprivate InputStream getAdditionalMetadataStream(String additionalMetadataLocation) throws IOException {\n\t\t// Most build systems will have copied the file to the class output location\n\t\tFileObject fileObject = this.environment.getFiler()\n\t\t\t.getResource(StandardLocation.CLASS_OUTPUT, \"\", additionalMetadataLocation);\n\t\tInputStream inputStream = getMetadataStream(fileObject);\n\t\tif (inputStream != null) {\n\t\t\treturn inputStream;\n\t\t}\n\t\ttry {\n\t\t\tFile file = locateAdditionalMetadataFile(new File(fileObject.toUri()), additionalMetadataLocation);\n\t\t\treturn (file.exists() ? new FileInputStream(file) : fileObject.toUri().toURL().openStream());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new FileNotFoundException();\n\t\t}\n\t}\n\n\tprivate InputStream getMetadataStream(FileObject fileObject) {\n\t\ttry {\n\t\t\treturn fileObject.openInputStream();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tFile locateAdditionalMetadataFile(File standardLocation, String additionalMetadataLocation) throws IOException {\n\t\tif (standardLocation.exists()) {\n\t\t\treturn standardLocation;\n\t\t}\n\t\tString locations = this.environment.getOptions()\n\t\t\t.get(ConfigurationMetadataAnnotationProcessor.ADDITIONAL_METADATA_LOCATIONS_OPTION);\n\t\tif (locations != null) {\n\t\t\tfor (String location : locations.split(\",\")) {\n\t\t\t\tFile candidate = new File(location, additionalMetadataLocation);\n\t\t\t\tif (candidate.isFile()) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new File(locateGradleResourcesDirectory(standardLocation), additionalMetadataLocation);\n\t}\n\n\tprivate File locateGradleResourcesDirectory(File standardAdditionalMetadataLocation) throws FileNotFoundException {\n\t\tString path = standardAdditionalMetadataLocation.getPath();\n\t\tint index = path.lastIndexOf(CLASSES_DIRECTORY);\n\t\tif (index < 0) {\n\t\t\tthrow new FileNotFoundException();\n\t\t}\n\t\tString buildDirectoryPath = path.substring(0, index);\n\t\tFile classOutputLocation = standardAdditionalMetadataLocation.getParentFile().getParentFile();\n\t\treturn new File(buildDirectoryPath, RESOURCES_DIRECTORY + '/' + classOutputLocation.getName());\n\t}\n\n\t/**\n\t * Internal callback that can throw an {@link IOException}.\n\t */\n\tprivate interface FileObjectSupplier {\n\n\t\tFileObject get() throws IOException;\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/ParameterPropertyDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.PrimitiveType;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.TypeKindVisitor8;\nimport javax.tools.Diagnostic.Kind;\n\n/**\n * {@link PropertyDescriptor} created from a constructor or record parameter.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nabstract class ParameterPropertyDescriptor extends PropertyDescriptor {\n\n\tprivate final VariableElement parameter;\n\n\tParameterPropertyDescriptor(String name, TypeMirror type, VariableElement parameter, TypeElement declaringElement,\n\t\t\tExecutableElement getter) {\n\t\tsuper(name, type, declaringElement, getter);\n\t\tthis.parameter = parameter;\n\n\t}\n\n\tfinal VariableElement getParameter() {\n\t\treturn this.parameter;\n\t}\n\n\t@Override\n\tprotected Object resolveDefaultValue(MetadataGenerationEnvironment environment) {\n\t\tObject defaultValue = getDefaultValueFromAnnotation(environment, getParameter());\n\t\treturn (defaultValue != null) ? defaultValue\n\t\t\t\t: getParameter().asType().accept(DefaultPrimitiveTypeVisitor.INSTANCE, null);\n\t}\n\n\tprivate Object getDefaultValueFromAnnotation(MetadataGenerationEnvironment environment, Element element) {\n\t\tAnnotationMirror annotation = environment.getDefaultValueAnnotation(element);\n\t\tList<String> defaultValue = getDefaultValue(environment, annotation);\n\t\tif (defaultValue != null) {\n\t\t\tTypeMirror specificType = determineSpecificType(environment);\n\t\t\ttry {\n\t\t\t\tList<Object> coerced = defaultValue.stream().map((value) -> coerceValue(specificType, value)).toList();\n\t\t\t\treturn (coerced.size() != 1) ? coerced : coerced.get(0);\n\t\t\t}\n\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\tenvironment.getMessager().printMessage(Kind.ERROR, ex.getMessage(), element, annotation);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate List<String> getDefaultValue(MetadataGenerationEnvironment environment, AnnotationMirror annotation) {\n\t\tif (annotation == null) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<String, Object> values = environment.getAnnotationElementValues(annotation);\n\t\treturn (List<String>) values.get(\"value\");\n\t}\n\n\tprivate TypeMirror determineSpecificType(MetadataGenerationEnvironment environment) {\n\t\tTypeMirror parameterType = getParameter().asType();\n\t\tTypeMirror elementType = environment.getTypeUtils().extractElementType(parameterType);\n\t\tparameterType = (elementType != null) ? elementType : parameterType;\n\t\tPrimitiveType primitiveType = environment.getTypeUtils().getPrimitiveType(parameterType);\n\t\treturn (primitiveType != null) ? primitiveType : parameterType;\n\t}\n\n\tprivate Object coerceValue(TypeMirror type, String value) {\n\t\tObject coercedValue = type.accept(DefaultValueCoercionTypeVisitor.INSTANCE, value);\n\t\treturn (coercedValue != null) ? coercedValue : value;\n\t}\n\n\t@Override\n\tpublic boolean isProperty(MetadataGenerationEnvironment env) {\n\t\treturn !isNested(env); // We must be able to bind it to build the object.\n\t}\n\n\t/**\n\t * Visitor that gets the default value for primitives.\n\t */\n\tprivate static final class DefaultPrimitiveTypeVisitor extends TypeKindVisitor8<Object, Void> {\n\n\t\tstatic final DefaultPrimitiveTypeVisitor INSTANCE = new DefaultPrimitiveTypeVisitor();\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsBoolean(PrimitiveType type, Void parameter) {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsByte(PrimitiveType type, Void parameter) {\n\t\t\treturn (byte) 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsShort(PrimitiveType type, Void parameter) {\n\t\t\treturn (short) 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsInt(PrimitiveType type, Void parameter) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsLong(PrimitiveType type, Void parameter) {\n\t\t\treturn 0L;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsChar(PrimitiveType type, Void parameter) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsFloat(PrimitiveType type, Void parameter) {\n\t\t\treturn 0F;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsDouble(PrimitiveType type, Void parameter) {\n\t\t\treturn 0D;\n\t\t}\n\n\t}\n\n\t/**\n\t * Visitor that gets the default using coercion.\n\t */\n\tprivate static final class DefaultValueCoercionTypeVisitor extends TypeKindVisitor8<Object, String> {\n\n\t\tstatic final DefaultValueCoercionTypeVisitor INSTANCE = new DefaultValueCoercionTypeVisitor();\n\n\t\tprivate <T extends Number> T parseNumber(String value, Function<String, T> parser,\n\t\t\t\tPrimitiveType primitiveType) {\n\t\t\ttry {\n\t\t\t\treturn parser.apply(value);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\tString.format(\"Invalid %s representation '%s'\", primitiveType, value));\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsBoolean(PrimitiveType type, String value) {\n\t\t\treturn Boolean.parseBoolean(value);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsByte(PrimitiveType type, String value) {\n\t\t\treturn parseNumber(value, Byte::parseByte, type);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsShort(PrimitiveType type, String value) {\n\t\t\treturn parseNumber(value, Short::parseShort, type);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsInt(PrimitiveType type, String value) {\n\t\t\treturn parseNumber(value, Integer::parseInt, type);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsLong(PrimitiveType type, String value) {\n\t\t\treturn parseNumber(value, Long::parseLong, type);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsChar(PrimitiveType type, String value) {\n\t\t\tif (value.length() > 1) {\n\t\t\t\tthrow new IllegalArgumentException(String.format(\"Invalid character representation '%s'\", value));\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsFloat(PrimitiveType type, String value) {\n\t\t\treturn parseNumber(value, Float::parseFloat, type);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object visitPrimitiveAsDouble(PrimitiveType type, String value) {\n\t\t\treturn parseNumber(value, Double::parseDouble, type);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/PropertyDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ElementKind;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\n\n/**\n * Description of a property that can be candidate for metadata generation.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nabstract class PropertyDescriptor {\n\n\tprivate final String name;\n\n\tprivate final TypeMirror type;\n\n\tprivate final TypeElement declaringElement;\n\n\tprivate final ExecutableElement getter;\n\n\t/**\n\t * Create a new {@link PropertyDescriptor} instance.\n\t * @param name the property name\n\t * @param type the property type\n\t * @param declaringElement the element that declared the item\n\t * @param getter the getter for the property or {@code null}\n\t */\n\tPropertyDescriptor(String name, TypeMirror type, TypeElement declaringElement, ExecutableElement getter) {\n\t\tthis.declaringElement = declaringElement;\n\t\tthis.name = name;\n\t\tthis.type = type;\n\t\tthis.getter = getter;\n\t}\n\n\t/**\n\t * Return the name of the property.\n\t * @return the property name\n\t */\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the type of the property.\n\t * @return the property type\n\t */\n\tTypeMirror getType() {\n\t\treturn this.type;\n\t}\n\n\t/**\n\t * Return the element that declared the property.\n\t * @return the declaring element\n\t */\n\tprotected final TypeElement getDeclaringElement() {\n\t\treturn this.declaringElement;\n\t}\n\n\t/**\n\t * Return the getter for the property.\n\t * @return the getter or {@code null}\n\t */\n\tprotected final ExecutableElement getGetter() {\n\t\treturn this.getter;\n\t}\n\n\t/**\n\t * Resolve the {@link ItemMetadata} for this property.\n\t * @param prefix the property prefix\n\t * @param environment the metadata generation environment\n\t * @return the item metadata or {@code null}\n\t */\n\tfinal ItemMetadata resolveItemMetadata(String prefix, MetadataGenerationEnvironment environment) {\n\t\tif (isNested(environment)) {\n\t\t\treturn resolveItemMetadataGroup(prefix, environment);\n\t\t}\n\t\tif (isProperty(environment)) {\n\t\t\treturn resolveItemMetadataProperty(prefix, environment);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Resolve the {@link ItemHint} for this property.\n\t * @param prefix the property prefix\n\t * @param environment the metadata generation environment\n\t * @return the item hint or {@code null}\n\t */\n\tprotected ItemHint resolveItemHint(String prefix, MetadataGenerationEnvironment environment) {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return if this is a nested property.\n\t * @param environment the metadata generation environment\n\t * @return if the property is nested\n\t * @see #isMarkedAsNested(MetadataGenerationEnvironment)\n\t */\n\tboolean isNested(MetadataGenerationEnvironment environment) {\n\t\tElement typeElement = environment.getTypeUtils().asElement(getType());\n\t\tif (!(typeElement instanceof TypeElement) || typeElement.getKind() == ElementKind.ENUM\n\t\t\t\t|| environment.getConfigurationPropertiesAnnotation(getGetter()) != null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (isMarkedAsNested(environment)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn !isCyclePresent(typeElement, getDeclaringElement())\n\t\t\t\t&& isParentTheSame(environment, typeElement, getDeclaringElement());\n\t}\n\n\t/**\n\t * Return if this property has been explicitly marked as nested (for example using an\n\t * annotation}.\n\t * @param environment the metadata generation environment\n\t * @return if the property has been marked as nested\n\t */\n\tprotected abstract boolean isMarkedAsNested(MetadataGenerationEnvironment environment);\n\n\tprivate boolean isCyclePresent(Element returnType, Element element) {\n\t\tif (!(element.getEnclosingElement() instanceof TypeElement)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (element.getEnclosingElement().equals(returnType)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn isCyclePresent(returnType, element.getEnclosingElement());\n\t}\n\n\tprivate boolean isParentTheSame(MetadataGenerationEnvironment environment, Element returnType,\n\t\t\tTypeElement element) {\n\t\tif (returnType == null || element == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturnType = getTopLevelType(returnType);\n\t\tElement candidate = element;\n\t\twhile (candidate instanceof TypeElement) {\n\t\t\tif (returnType.equals(getTopLevelType(candidate))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcandidate = environment.getTypeUtils().asElement(((TypeElement) candidate).getSuperclass());\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Element getTopLevelType(Element element) {\n\t\tif (!(element.getEnclosingElement() instanceof TypeElement)) {\n\t\t\treturn element;\n\t\t}\n\t\treturn getTopLevelType(element.getEnclosingElement());\n\t}\n\n\tprivate ItemMetadata resolveItemMetadataGroup(String prefix, MetadataGenerationEnvironment environment) {\n\t\tElement propertyElement = environment.getTypeUtils().asElement(getType());\n\t\tString nestedPrefix = ConfigurationMetadata.nestedPrefix(prefix, getName());\n\t\tString dataType = environment.getTypeUtils().getQualifiedName(propertyElement);\n\t\tString ownerType = environment.getTypeUtils().getQualifiedName(getDeclaringElement());\n\t\tString sourceMethod = (getGetter() != null) ? getGetter().toString() : null;\n\t\treturn ItemMetadata.newGroup(nestedPrefix, dataType, ownerType, sourceMethod);\n\t}\n\n\tprivate ItemMetadata resolveItemMetadataProperty(String prefix, MetadataGenerationEnvironment environment) {\n\t\tString dataType = resolveType(environment);\n\t\tString ownerType = environment.getTypeUtils().getQualifiedName(getDeclaringElement());\n\t\tString description = resolveDescription(environment);\n\t\tObject defaultValue = resolveDefaultValue(environment);\n\t\tItemDeprecation deprecation = resolveItemDeprecation(environment);\n\t\treturn ItemMetadata.newProperty(prefix, getName(), dataType, ownerType, null, description, defaultValue,\n\t\t\t\tdeprecation);\n\t}\n\n\tprotected final ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment,\n\t\t\tElement... elements) {\n\t\tboolean deprecated = Arrays.stream(elements).anyMatch(environment::isDeprecated);\n\t\treturn deprecated ? environment.resolveItemDeprecation(getGetter()) : null;\n\t}\n\n\tprivate String resolveType(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getTypeUtils().getType(getDeclaringElement(), getType());\n\t}\n\n\t/**\n\t * Resolve the property description.\n\t * @param environment the metadata generation environment\n\t * @return the property description\n\t */\n\tprotected abstract String resolveDescription(MetadataGenerationEnvironment environment);\n\n\t/**\n\t * Resolve the default value for this property.\n\t * @param environment the metadata generation environment\n\t * @return the default value or {@code null}\n\t */\n\tprotected abstract Object resolveDefaultValue(MetadataGenerationEnvironment environment);\n\n\t/**\n\t * Resolve the {@link ItemDeprecation} for this property.\n\t * @param environment the metadata generation environment\n\t * @return the deprecation or {@code null}\n\t */\n\tprotected abstract ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment);\n\n\t/**\n\t * Return true if this descriptor is for a property.\n\t * @param environment the metadata generation environment\n\t * @return if this is a property\n\t */\n\tabstract boolean isProperty(MetadataGenerationEnvironment environment);\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/PropertyDescriptorResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.NestingKind;\nimport javax.lang.model.element.RecordComponentElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.ElementFilter;\n\nimport org.springframework.boot.configurationprocessor.ConfigurationPropertiesSourceResolver.SourceMetadata;\n\n/**\n * Resolve {@link PropertyDescriptor} instances.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Pavel Anisimov\n */\nclass PropertyDescriptorResolver {\n\n\tprivate final MetadataGenerationEnvironment environment;\n\n\tPropertyDescriptorResolver(MetadataGenerationEnvironment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * Return the {@link PropertyDescriptor} instances that are valid candidates for the\n\t * specified {@link TypeElement type} based on the specified {@link ExecutableElement\n\t * factory method}, if any.\n\t * @param type the target type\n\t * @param factoryMethod the method that triggered the metadata for that {@code type}\n\t * or {@code null}\n\t * @return the candidate properties for metadata generation\n\t */\n\tStream<PropertyDescriptor> resolve(TypeElement type, ExecutableElement factoryMethod) {\n\t\tTypeElementMembers members = new TypeElementMembers(this.environment, type);\n\t\tif (factoryMethod != null) {\n\t\t\treturn resolveJavaBeanProperties(type, members, factoryMethod);\n\t\t}\n\t\treturn resolve(Bindable.of(type, this.environment), members);\n\t}\n\n\tprivate Stream<PropertyDescriptor> resolve(Bindable bindable, TypeElementMembers members) {\n\t\tif (bindable.isConstructorBindingEnabled()) {\n\t\t\tExecutableElement bindConstructor = bindable.getBindConstructor();\n\t\t\treturn (bindConstructor != null)\n\t\t\t\t\t? resolveConstructorBoundProperties(bindable.getType(), members, bindConstructor) : Stream.empty();\n\t\t}\n\t\treturn resolveJavaBeanProperties(bindable.getType(), members, null);\n\t}\n\n\tprivate Stream<PropertyDescriptor> resolveConstructorBoundProperties(TypeElement declaringElement,\n\t\t\tTypeElementMembers members, ExecutableElement bindConstructor) {\n\t\tMap<String, PropertyDescriptor> candidates = new LinkedHashMap<>();\n\t\tbindConstructor.getParameters().forEach((parameter) -> {\n\t\t\tPropertyDescriptor descriptor = extracted(declaringElement, members, parameter);\n\t\t\tregister(candidates, descriptor);\n\t\t});\n\t\treturn candidates.values().stream();\n\t}\n\n\tprivate PropertyDescriptor extracted(TypeElement declaringElement, TypeElementMembers members,\n\t\t\tVariableElement parameter) {\n\t\tString parameterName = parameter.getSimpleName().toString();\n\t\tString name = getPropertyName(parameter, parameterName);\n\t\tTypeMirror type = parameter.asType();\n\t\tExecutableElement getter = members.getPublicGetter(parameterName, type);\n\t\tExecutableElement setter = members.getPublicSetter(parameterName, type);\n\t\tVariableElement field = members.getFields().get(parameterName);\n\t\tRecordComponentElement recordComponent = members.getRecordComponents().get(parameterName);\n\t\tSourceMetadata sourceMetadata = this.environment.resolveSourceMetadata(field, getter);\n\t\tPropertyDescriptor propertyDescriptor = (recordComponent != null)\n\t\t\t\t? new RecordParameterPropertyDescriptor(name, type, parameter, declaringElement, getter,\n\t\t\t\t\t\trecordComponent)\n\t\t\t\t: new ConstructorParameterPropertyDescriptor(name, type, parameter, declaringElement, getter, setter,\n\t\t\t\t\t\tfield);\n\t\treturn sourceMetadata.createPropertyDescriptor(name, propertyDescriptor);\n\t}\n\n\tprivate String getPropertyName(VariableElement parameter, String fallback) {\n\t\tAnnotationMirror nameAnnotation = this.environment.getNameAnnotation(parameter);\n\t\tif (nameAnnotation != null) {\n\t\t\treturn this.environment.getAnnotationElementStringValue(nameAnnotation, \"value\");\n\t\t}\n\t\treturn fallback;\n\t}\n\n\tprivate Stream<PropertyDescriptor> resolveJavaBeanProperties(TypeElement declaringElement,\n\t\t\tTypeElementMembers members, ExecutableElement factoryMethod) {\n\t\t// First check if we have regular java bean properties there\n\t\tMap<String, PropertyDescriptor> candidates = new LinkedHashMap<>();\n\t\tmembers.getPublicGetters().forEach((name, getters) -> {\n\t\t\tVariableElement field = members.getFields().get(name);\n\t\t\tExecutableElement getter = findMatchingGetter(members, getters, field);\n\t\t\tTypeMirror propertyType = getter.getReturnType();\n\t\t\tSourceMetadata sourceMetadata = this.environment.resolveSourceMetadata(field, getter);\n\t\t\tregister(candidates,\n\t\t\t\t\tsourceMetadata.createPropertyDescriptor(getPropertyName(field, name),\n\t\t\t\t\t\t\t(propertyName) -> new JavaBeanPropertyDescriptor(propertyName, propertyType,\n\t\t\t\t\t\t\t\t\tdeclaringElement, getter, members.getPublicSetter(name, propertyType), field,\n\t\t\t\t\t\t\t\t\tfactoryMethod)));\n\t\t});\n\t\t// Then check for Lombok ones\n\t\tmembers.getFields().forEach((name, field) -> {\n\t\t\tTypeMirror propertyType = field.asType();\n\t\t\tExecutableElement getter = members.getPublicGetter(name, propertyType);\n\t\t\tExecutableElement setter = members.getPublicSetter(name, propertyType);\n\t\t\tSourceMetadata sourceMetadata = this.environment.resolveSourceMetadata(field, getter);\n\t\t\tregister(candidates,\n\t\t\t\t\tsourceMetadata.createPropertyDescriptor(getPropertyName(field, name),\n\t\t\t\t\t\t\t(propertyName) -> new LombokPropertyDescriptor(propertyName, propertyType, declaringElement,\n\t\t\t\t\t\t\t\t\tgetter, setter, field, factoryMethod)));\n\t\t});\n\t\treturn candidates.values().stream();\n\t}\n\n\tprivate ExecutableElement findMatchingGetter(TypeElementMembers members, List<ExecutableElement> candidates,\n\t\t\tVariableElement field) {\n\t\tif (candidates.size() > 1 && field != null) {\n\t\t\treturn members.getMatchingGetter(candidates, field.asType());\n\t\t}\n\t\treturn candidates.get(0);\n\t}\n\n\tprivate void register(Map<String, PropertyDescriptor> candidates, PropertyDescriptor descriptor) {\n\t\tif (!candidates.containsKey(descriptor.getName()) && isCandidate(descriptor)) {\n\t\t\tcandidates.put(descriptor.getName(), descriptor);\n\t\t}\n\t}\n\n\tprivate boolean isCandidate(PropertyDescriptor descriptor) {\n\t\treturn descriptor.isProperty(this.environment) || descriptor.isNested(this.environment);\n\t}\n\n\t/**\n\t * Wrapper around a {@link TypeElement} that could be bound.\n\t */\n\tprivate static class Bindable {\n\n\t\tprivate final TypeElement type;\n\n\t\tprivate final List<ExecutableElement> constructors;\n\n\t\tprivate final List<ExecutableElement> boundConstructors;\n\n\t\tBindable(TypeElement type, List<ExecutableElement> constructors, List<ExecutableElement> boundConstructors) {\n\t\t\tthis.type = type;\n\t\t\tthis.constructors = constructors;\n\t\t\tthis.boundConstructors = boundConstructors;\n\t\t}\n\n\t\tTypeElement getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tboolean isConstructorBindingEnabled() {\n\t\t\treturn !this.boundConstructors.isEmpty();\n\t\t}\n\n\t\tExecutableElement getBindConstructor() {\n\t\t\tif (this.boundConstructors.isEmpty()) {\n\t\t\t\treturn findBoundConstructor();\n\t\t\t}\n\t\t\tif (this.boundConstructors.size() == 1) {\n\t\t\t\treturn this.boundConstructors.get(0);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate ExecutableElement findBoundConstructor() {\n\t\t\tExecutableElement boundConstructor = null;\n\t\t\tfor (ExecutableElement candidate : this.constructors) {\n\t\t\t\tif (!candidate.getParameters().isEmpty()) {\n\t\t\t\t\tif (boundConstructor != null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tboundConstructor = candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn boundConstructor;\n\t\t}\n\n\t\tstatic Bindable of(TypeElement type, MetadataGenerationEnvironment env) {\n\t\t\tList<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());\n\t\t\tList<ExecutableElement> boundConstructors = getBoundConstructors(type, env, constructors);\n\t\t\treturn new Bindable(type, constructors, boundConstructors);\n\t\t}\n\n\t\tprivate static List<ExecutableElement> getBoundConstructors(TypeElement type, MetadataGenerationEnvironment env,\n\t\t\t\tList<ExecutableElement> constructors) {\n\t\t\tExecutableElement bindConstructor = deduceBindConstructor(type, constructors, env);\n\t\t\tif (bindConstructor != null) {\n\t\t\t\treturn Collections.singletonList(bindConstructor);\n\t\t\t}\n\t\t\treturn constructors.stream().filter(env::hasConstructorBindingAnnotation).toList();\n\t\t}\n\n\t\tprivate static ExecutableElement deduceBindConstructor(TypeElement type, List<ExecutableElement> constructors,\n\t\t\t\tMetadataGenerationEnvironment env) {\n\t\t\tif (constructors.size() == 1) {\n\t\t\t\tExecutableElement candidate = constructors.get(0);\n\t\t\t\tif (!candidate.getParameters().isEmpty() && !env.hasAutowiredAnnotation(candidate)) {\n\t\t\t\t\tif (type.getNestingKind() == NestingKind.MEMBER\n\t\t\t\t\t\t\t&& candidate.getModifiers().contains(Modifier.PRIVATE)) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/RecordParameterPropertyDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.RecordComponentElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\n\n/**\n * A {@link PropertyDescriptor} for a record parameter.\n *\n * @author Stephane Nicoll\n * @author Pavel Anisimov\n * @author Phillip Webb\n */\nclass RecordParameterPropertyDescriptor extends ParameterPropertyDescriptor {\n\n\tprivate final RecordComponentElement recordComponent;\n\n\tRecordParameterPropertyDescriptor(String name, TypeMirror type, VariableElement parameter,\n\t\t\tTypeElement declaringElement, ExecutableElement getter, RecordComponentElement recordComponent) {\n\t\tsuper(name, type, parameter, declaringElement, getter);\n\t\tthis.recordComponent = recordComponent;\n\t}\n\n\t@Override\n\tprotected ItemDeprecation resolveItemDeprecation(MetadataGenerationEnvironment environment) {\n\t\treturn resolveItemDeprecation(environment, getGetter());\n\t}\n\n\t@Override\n\tprotected boolean isMarkedAsNested(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getNestedConfigurationPropertyAnnotation(this.recordComponent) != null;\n\t}\n\n\t@Override\n\tprotected String resolveDescription(MetadataGenerationEnvironment environment) {\n\t\treturn environment.getTypeUtils().getJavaDoc(this.recordComponent);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeElementMembers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.RecordComponentElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.ElementFilter;\n\n/**\n * Provides access to relevant {@link TypeElement} members.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Pavel Anisimov\n */\nclass TypeElementMembers {\n\n\tprivate static final String OBJECT_CLASS_NAME = Object.class.getName();\n\n\tprivate static final String RECORD_CLASS_NAME = Record.class.getName();\n\n\tprivate final MetadataGenerationEnvironment env;\n\n\tprivate final TypeElement targetType;\n\n\tprivate final boolean isRecord;\n\n\tprivate final Map<String, VariableElement> fields = new LinkedHashMap<>();\n\n\tprivate final Map<String, RecordComponentElement> recordComponents = new LinkedHashMap<>();\n\n\tprivate final Map<String, List<ExecutableElement>> publicGetters = new LinkedHashMap<>();\n\n\tprivate final Map<String, List<ExecutableElement>> publicSetters = new LinkedHashMap<>();\n\n\tTypeElementMembers(MetadataGenerationEnvironment env, TypeElement targetType) {\n\t\tthis.env = env;\n\t\tthis.targetType = targetType;\n\t\tthis.isRecord = RECORD_CLASS_NAME.equals(targetType.getSuperclass().toString());\n\t\tprocess(targetType);\n\t}\n\n\tprivate void process(TypeElement element) {\n\t\tfor (VariableElement field : ElementFilter.fieldsIn(element.getEnclosedElements())) {\n\t\t\tprocessField(field);\n\t\t}\n\t\tfor (RecordComponentElement recordComponent : ElementFilter.recordComponentsIn(element.getEnclosedElements())) {\n\t\t\tprocessRecordComponent(recordComponent);\n\t\t}\n\t\tfor (ExecutableElement method : ElementFilter.methodsIn(element.getEnclosedElements())) {\n\t\t\tprocessMethod(method);\n\t\t}\n\t\tElement superType = this.env.getTypeUtils().asElement(element.getSuperclass());\n\t\tif (superType instanceof TypeElement && !OBJECT_CLASS_NAME.equals(superType.toString())\n\t\t\t\t&& !RECORD_CLASS_NAME.equals(superType.toString())) {\n\t\t\tprocess((TypeElement) superType);\n\t\t}\n\t}\n\n\tprivate void processMethod(ExecutableElement method) {\n\t\tif (isPublic(method)) {\n\t\t\tString name = method.getSimpleName().toString();\n\t\t\tif (isGetter(method)) {\n\t\t\t\tString propertyName = getAccessorName(name);\n\t\t\t\tList<ExecutableElement> matchingGetters = this.publicGetters.computeIfAbsent(propertyName,\n\t\t\t\t\t\t(k) -> new ArrayList<>());\n\t\t\t\tTypeMirror returnType = method.getReturnType();\n\t\t\t\tif (getMatchingGetter(matchingGetters, returnType) == null) {\n\t\t\t\t\tmatchingGetters.add(method);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (isSetter(method)) {\n\t\t\t\tString propertyName = getAccessorName(name);\n\t\t\t\tList<ExecutableElement> matchingSetters = this.publicSetters.computeIfAbsent(propertyName,\n\t\t\t\t\t\t(k) -> new ArrayList<>());\n\t\t\t\tTypeMirror paramType = method.getParameters().get(0).asType();\n\t\t\t\tif (getMatchingSetter(matchingSetters, paramType) == null) {\n\t\t\t\t\tmatchingSetters.add(method);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isPublic(ExecutableElement method) {\n\t\tSet<Modifier> modifiers = method.getModifiers();\n\t\treturn modifiers.contains(Modifier.PUBLIC) && !modifiers.contains(Modifier.ABSTRACT)\n\t\t\t\t&& !modifiers.contains(Modifier.STATIC);\n\t}\n\n\tExecutableElement getMatchingGetter(List<ExecutableElement> candidates, TypeMirror type) {\n\t\treturn getMatchingAccessor(candidates, type, ExecutableElement::getReturnType);\n\t}\n\n\tprivate ExecutableElement getMatchingSetter(List<ExecutableElement> candidates, TypeMirror type) {\n\t\treturn getMatchingAccessor(candidates, type, (candidate) -> candidate.getParameters().get(0).asType());\n\t}\n\n\tprivate ExecutableElement getMatchingAccessor(List<ExecutableElement> candidates, TypeMirror type,\n\t\t\tFunction<ExecutableElement, TypeMirror> typeExtractor) {\n\t\tfor (ExecutableElement candidate : candidates) {\n\t\t\tTypeMirror candidateType = typeExtractor.apply(candidate);\n\t\t\tif (this.env.getTypeUtils().isSameType(candidateType, type)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isGetter(ExecutableElement method) {\n\t\tboolean hasParameters = !method.getParameters().isEmpty();\n\t\tboolean returnsVoid = TypeKind.VOID == method.getReturnType().getKind();\n\t\tif (hasParameters || returnsVoid) {\n\t\t\treturn false;\n\t\t}\n\t\tString name = method.getSimpleName().toString();\n\t\tif (this.isRecord && this.fields.containsKey(name)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (name.startsWith(\"get\") && name.length() > 3) || (name.startsWith(\"is\") && name.length() > 2);\n\t}\n\n\tprivate boolean isSetter(ExecutableElement method) {\n\t\tif (this.isRecord) {\n\t\t\treturn false;\n\t\t}\n\t\tfinal String name = method.getSimpleName().toString();\n\t\treturn (name.startsWith(\"set\") && name.length() > 3 && method.getParameters().size() == 1\n\t\t\t\t&& isSetterReturnType(method));\n\t}\n\n\tprivate boolean isSetterReturnType(ExecutableElement method) {\n\t\tTypeMirror returnType = method.getReturnType();\n\t\tif (TypeKind.VOID == returnType.getKind()) {\n\t\t\treturn true;\n\t\t}\n\t\tif (TypeKind.DECLARED == returnType.getKind()\n\t\t\t\t&& this.env.getTypeUtils().isSameType(method.getEnclosingElement().asType(), returnType)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (TypeKind.TYPEVAR == returnType.getKind()) {\n\t\t\tString resolvedType = this.env.getTypeUtils().getType(this.targetType, returnType);\n\t\t\treturn (resolvedType != null\n\t\t\t\t\t&& resolvedType.equals(this.env.getTypeUtils().getQualifiedName(this.targetType)));\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate String getAccessorName(String methodName) {\n\t\tif (this.isRecord && this.fields.containsKey(methodName)) {\n\t\t\treturn methodName;\n\t\t}\n\t\tif (methodName.startsWith(\"is\")) {\n\t\t\treturn lowerCaseFirstCharacter(methodName.substring(2));\n\t\t}\n\t\tif (methodName.startsWith(\"get\") || methodName.startsWith(\"set\")) {\n\t\t\treturn lowerCaseFirstCharacter(methodName.substring(3));\n\t\t}\n\t\tthrow new IllegalStateException(\"methodName must start with 'is', 'get' or 'set', was '\" + methodName + \"'\");\n\t}\n\n\tprivate String lowerCaseFirstCharacter(String string) {\n\t\treturn Character.toLowerCase(string.charAt(0)) + string.substring(1);\n\t}\n\n\tprivate void processField(VariableElement field) {\n\t\tString name = field.getSimpleName().toString();\n\t\tthis.fields.putIfAbsent(name, field);\n\t}\n\n\tprivate void processRecordComponent(RecordComponentElement recordComponent) {\n\t\tString name = recordComponent.getSimpleName().toString();\n\t\tthis.recordComponents.putIfAbsent(name, recordComponent);\n\t}\n\n\tMap<String, VariableElement> getFields() {\n\t\treturn Collections.unmodifiableMap(this.fields);\n\t}\n\n\tMap<String, RecordComponentElement> getRecordComponents() {\n\t\treturn Collections.unmodifiableMap(this.recordComponents);\n\t}\n\n\tMap<String, List<ExecutableElement>> getPublicGetters() {\n\t\treturn Collections.unmodifiableMap(this.publicGetters);\n\t}\n\n\tExecutableElement getPublicGetter(String name, TypeMirror type) {\n\t\tList<ExecutableElement> candidates = this.publicGetters.get(name);\n\t\treturn getPublicAccessor(candidates, type, (specificType) -> getMatchingGetter(candidates, specificType));\n\t}\n\n\tExecutableElement getPublicSetter(String name, TypeMirror type) {\n\t\tList<ExecutableElement> candidates = this.publicSetters.get(name);\n\t\treturn getPublicAccessor(candidates, type, (specificType) -> getMatchingSetter(candidates, specificType));\n\t}\n\n\tprivate ExecutableElement getPublicAccessor(List<ExecutableElement> candidates, TypeMirror type,\n\t\t\tFunction<TypeMirror, ExecutableElement> matchingAccessorExtractor) {\n\t\tif (candidates != null) {\n\t\t\tExecutableElement matching = matchingAccessorExtractor.apply(type);\n\t\t\tif (matching != null) {\n\t\t\t\treturn matching;\n\t\t\t}\n\t\t\tTypeMirror alternative = this.env.getTypeUtils().getWrapperOrPrimitiveFor(type);\n\t\t\tif (alternative != null) {\n\t\t\t\treturn matchingAccessorExtractor.apply(alternative);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.RecordComponentElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.ArrayType;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.PrimitiveType;\nimport javax.lang.model.type.TypeKind;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.type.TypeVariable;\nimport javax.lang.model.util.SimpleTypeVisitor8;\nimport javax.lang.model.util.Types;\n\n/**\n * Type Utilities.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Pavel Anisimov\n * @author Dmytro Nosan\n */\nclass TypeUtils {\n\n\tprivate static final Map<TypeKind, Class<?>> PRIMITIVE_WRAPPERS;\n\n\tstatic {\n\t\tMap<TypeKind, Class<?>> wrappers = new EnumMap<>(TypeKind.class);\n\t\twrappers.put(TypeKind.BOOLEAN, Boolean.class);\n\t\twrappers.put(TypeKind.BYTE, Byte.class);\n\t\twrappers.put(TypeKind.CHAR, Character.class);\n\t\twrappers.put(TypeKind.DOUBLE, Double.class);\n\t\twrappers.put(TypeKind.FLOAT, Float.class);\n\t\twrappers.put(TypeKind.INT, Integer.class);\n\t\twrappers.put(TypeKind.LONG, Long.class);\n\t\twrappers.put(TypeKind.SHORT, Short.class);\n\t\tPRIMITIVE_WRAPPERS = Collections.unmodifiableMap(wrappers);\n\t}\n\n\tprivate static final Map<String, TypeKind> WRAPPER_TO_PRIMITIVE;\n\n\tstatic {\n\t\tMap<String, TypeKind> primitives = new HashMap<>();\n\t\tPRIMITIVE_WRAPPERS.forEach((kind, wrapperClass) -> primitives.put(wrapperClass.getName(), kind));\n\t\tWRAPPER_TO_PRIMITIVE = primitives;\n\t}\n\n\tprivate final ProcessingEnvironment env;\n\n\tprivate final Types types;\n\n\tprivate final TypeExtractor typeExtractor;\n\n\tprivate final TypeMirror collectionType;\n\n\tprivate final TypeMirror mapType;\n\n\tprivate final Map<TypeElement, TypeDescriptor> typeDescriptors = new HashMap<>();\n\n\tTypeUtils(ProcessingEnvironment env) {\n\t\tthis.env = env;\n\t\tthis.types = env.getTypeUtils();\n\t\tthis.typeExtractor = new TypeExtractor(this.types);\n\t\tthis.collectionType = getDeclaredType(this.types, Collection.class, 1);\n\t\tthis.mapType = getDeclaredType(this.types, Map.class, 2);\n\t}\n\n\tprivate TypeMirror getDeclaredType(Types types, Class<?> typeClass, int numberOfTypeArgs) {\n\t\tTypeMirror[] typeArgs = new TypeMirror[numberOfTypeArgs];\n\t\tArrays.setAll(typeArgs, (i) -> types.getWildcardType(null, null));\n\t\tTypeElement typeElement = this.env.getElementUtils().getTypeElement(typeClass.getName());\n\t\ttry {\n\t\t\treturn types.getDeclaredType(typeElement, typeArgs);\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\t// Try again without generics for older Java versions\n\t\t\treturn types.getDeclaredType(typeElement);\n\t\t}\n\t}\n\n\tboolean isSameType(TypeMirror t1, TypeMirror t2) {\n\t\treturn this.types.isSameType(t1, t2);\n\t}\n\n\tElement asElement(TypeMirror type) {\n\t\treturn this.types.asElement(type);\n\t}\n\n\t/**\n\t * Return the qualified name of the specified element.\n\t * @param element the element to handle\n\t * @return the fully qualified name of the element, suitable for a call to\n\t * {@link Class#forName(String)}\n\t */\n\tString getQualifiedName(Element element) {\n\t\treturn this.typeExtractor.getQualifiedName(element);\n\t}\n\n\t/**\n\t * Return the type of the specified {@link TypeMirror} including all its generic\n\t * information.\n\t * @param element the {@link TypeElement} in which this {@code type} is declared\n\t * @param type the type to handle\n\t * @return a representation of the type including all its generic information\n\t */\n\tString getType(TypeElement element, TypeMirror type) {\n\t\tif (type == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn type.accept(this.typeExtractor, resolveTypeDescriptor(element));\n\t}\n\n\t/**\n\t * Extract the target element type from the specified container type or {@code null}\n\t * if no element type was found.\n\t * @param type a type, potentially wrapping an element type\n\t * @return the element type or {@code null} if no specific type was found\n\t */\n\tTypeMirror extractElementType(TypeMirror type) {\n\t\tif (!this.env.getTypeUtils().isAssignable(type, this.collectionType)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn getCollectionElementType(type);\n\t}\n\n\tprivate TypeMirror getCollectionElementType(TypeMirror type) {\n\t\tif (((TypeElement) this.types.asElement(type)).getQualifiedName().contentEquals(Collection.class.getName())) {\n\t\t\tDeclaredType declaredType = (DeclaredType) type;\n\t\t\t// raw type, just \"Collection\"\n\t\t\tif (declaredType.getTypeArguments().isEmpty()) {\n\t\t\t\treturn this.types.getDeclaredType(this.env.getElementUtils().getTypeElement(Object.class.getName()));\n\t\t\t}\n\t\t\t// return type argument to Collection<...>\n\t\t\treturn declaredType.getTypeArguments().get(0);\n\t\t}\n\n\t\t// recursively walk the supertypes, looking for Collection<...>\n\t\tfor (TypeMirror superType : this.env.getTypeUtils().directSupertypes(type)) {\n\t\t\tif (this.types.isAssignable(superType, this.collectionType)) {\n\t\t\t\treturn getCollectionElementType(superType);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tboolean isCollectionOrMap(TypeMirror type) {\n\t\treturn this.env.getTypeUtils().isAssignable(type, this.collectionType)\n\t\t\t\t|| this.env.getTypeUtils().isAssignable(type, this.mapType);\n\t}\n\n\tString getJavaDoc(Element element) {\n\t\tif (element instanceof RecordComponentElement) {\n\t\t\treturn getJavaDoc((RecordComponentElement) element);\n\t\t}\n\t\tString javadoc = (element != null) ? this.env.getElementUtils().getDocComment(element) : null;\n\t\tjavadoc = (javadoc != null) ? cleanUpJavaDoc(javadoc) : null;\n\t\treturn (javadoc == null || javadoc.isEmpty()) ? null : javadoc;\n\t}\n\n\t/**\n\t * Return the {@link PrimitiveType} of the specified type or {@code null} if the type\n\t * does not represent a valid wrapper type.\n\t * @param typeMirror a type\n\t * @return the primitive type or {@code null} if the type is not a wrapper type\n\t */\n\tPrimitiveType getPrimitiveType(TypeMirror typeMirror) {\n\t\tif (getPrimitiveFor(typeMirror) != null) {\n\t\t\treturn this.types.unboxedType(typeMirror);\n\t\t}\n\t\treturn null;\n\t}\n\n\tTypeMirror getWrapperOrPrimitiveFor(TypeMirror typeMirror) {\n\t\tClass<?> candidate = getWrapperFor(typeMirror);\n\t\tif (candidate != null) {\n\t\t\treturn this.env.getElementUtils().getTypeElement(candidate.getName()).asType();\n\t\t}\n\t\tTypeKind primitiveKind = getPrimitiveFor(typeMirror);\n\t\tif (primitiveKind != null) {\n\t\t\treturn this.env.getTypeUtils().getPrimitiveType(primitiveKind);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Class<?> getWrapperFor(TypeMirror type) {\n\t\treturn PRIMITIVE_WRAPPERS.get(type.getKind());\n\t}\n\n\tprivate TypeKind getPrimitiveFor(TypeMirror type) {\n\t\treturn WRAPPER_TO_PRIMITIVE.get(type.toString());\n\t}\n\n\tprivate TypeDescriptor resolveTypeDescriptor(TypeElement element) {\n\t\tif (this.typeDescriptors.containsKey(element)) {\n\t\t\treturn this.typeDescriptors.get(element);\n\t\t}\n\t\treturn createTypeDescriptor(element);\n\t}\n\n\tprivate TypeDescriptor createTypeDescriptor(TypeElement element) {\n\t\tTypeDescriptor descriptor = new TypeDescriptor();\n\t\tprocess(descriptor, element.asType());\n\t\tthis.typeDescriptors.put(element, descriptor);\n\t\treturn descriptor;\n\t}\n\n\tprivate void process(TypeDescriptor descriptor, TypeMirror type) {\n\t\tif (type.getKind() == TypeKind.DECLARED) {\n\t\t\tDeclaredType declaredType = (DeclaredType) type;\n\t\t\tDeclaredType freshType = (DeclaredType) this.env.getElementUtils()\n\t\t\t\t.getTypeElement(this.types.asElement(type).toString())\n\t\t\t\t.asType();\n\t\t\tList<? extends TypeMirror> arguments = declaredType.getTypeArguments();\n\t\t\tfor (int i = 0; i < arguments.size(); i++) {\n\t\t\t\tTypeMirror specificType = arguments.get(i);\n\t\t\t\tTypeMirror signatureType = freshType.getTypeArguments().get(i);\n\t\t\t\tdescriptor.registerIfNecessary(signatureType, specificType);\n\t\t\t}\n\t\t\tTypeElement element = (TypeElement) this.types.asElement(type);\n\t\t\tprocess(descriptor, element.getSuperclass());\n\t\t}\n\t}\n\n\tprivate String getJavaDoc(RecordComponentElement recordComponent) {\n\t\tString recordJavadoc = this.env.getElementUtils().getDocComment(recordComponent.getEnclosingElement());\n\t\tif (recordJavadoc != null) {\n\t\t\tPattern paramJavadocPattern = paramJavadocPattern(recordComponent.getSimpleName().toString());\n\t\t\tMatcher paramJavadocMatcher = paramJavadocPattern.matcher(recordJavadoc);\n\t\t\tif (paramJavadocMatcher.find()) {\n\t\t\t\tString paramJavadoc = cleanUpJavaDoc(paramJavadocMatcher.group());\n\t\t\t\treturn paramJavadoc.isEmpty() ? null : paramJavadoc;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Pattern paramJavadocPattern(String paramName) {\n\t\tString pattern = String.format(\"(?<=@param +%s).*?(?=([\\r\\n]+ *@)|$)\", paramName);\n\t\treturn Pattern.compile(pattern, Pattern.DOTALL);\n\t}\n\n\tprivate String cleanUpJavaDoc(String javadoc) {\n\t\tStringBuilder result = new StringBuilder(javadoc.length());\n\t\tchar lastChar = '.';\n\t\tfor (int i = 0; i < javadoc.length(); i++) {\n\t\t\tchar ch = javadoc.charAt(i);\n\t\t\tch = (ch == '\\r' || ch == '\\n') ? ' ' : ch;\n\t\t\tboolean repeatedSpace = (ch == ' ' && lastChar == ' ');\n\t\t\tif (!repeatedSpace) {\n\t\t\t\tresult.append(ch);\n\t\t\t\tlastChar = ch;\n\t\t\t}\n\t\t}\n\t\treturn result.toString().trim();\n\t}\n\n\t/**\n\t * A visitor that extracts the fully qualified name of a type, including generic\n\t * information.\n\t */\n\tprivate static class TypeExtractor extends SimpleTypeVisitor8<String, TypeDescriptor> {\n\n\t\tprivate final Types types;\n\n\t\tTypeExtractor(Types types) {\n\t\t\tthis.types = types;\n\t\t}\n\n\t\t@Override\n\t\tpublic String visitDeclared(DeclaredType type, TypeDescriptor descriptor) {\n\t\t\tTypeElement enclosingElement = getEnclosingTypeElement(type);\n\t\t\tString qualifiedName = determineQualifiedName(type, enclosingElement);\n\t\t\tif (type.getTypeArguments().isEmpty()) {\n\t\t\t\treturn qualifiedName;\n\t\t\t}\n\t\t\tStringBuilder name = new StringBuilder();\n\t\t\tname.append(qualifiedName);\n\t\t\tname.append(\"<\")\n\t\t\t\t.append(type.getTypeArguments()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map((t) -> visit(t, descriptor))\n\t\t\t\t\t.collect(Collectors.joining(\",\")))\n\t\t\t\t.append(\">\");\n\t\t\treturn name.toString();\n\t\t}\n\n\t\tprivate String determineQualifiedName(DeclaredType type, TypeElement enclosingElement) {\n\t\t\tif (enclosingElement != null) {\n\t\t\t\treturn getQualifiedName(enclosingElement) + \"$\" + type.asElement().getSimpleName();\n\t\t\t}\n\t\t\treturn getQualifiedName(type.asElement());\n\t\t}\n\n\t\t@Override\n\t\tpublic String visitTypeVariable(TypeVariable typeVariable, TypeDescriptor descriptor) {\n\t\t\tTypeMirror resolvedGeneric = descriptor.resolveGeneric(typeVariable);\n\t\t\tif (resolvedGeneric != null) {\n\t\t\t\tif (resolvedGeneric instanceof TypeVariable resolveTypeVariable) {\n\t\t\t\t\t// Still unresolved, let's use the upper bound, checking first if\n\t\t\t\t\t// a cycle may exist\n\t\t\t\t\tif (!hasCycle(resolveTypeVariable)) {\n\t\t\t\t\t\treturn visit(resolveTypeVariable.getUpperBound(), descriptor);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn visit(resolvedGeneric, descriptor);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Fallback to simple representation of the upper bound\n\t\t\treturn defaultAction(typeVariable.getUpperBound(), descriptor);\n\t\t}\n\n\t\tprivate boolean hasCycle(TypeVariable variable) {\n\t\t\tTypeMirror upperBound = variable.getUpperBound();\n\t\t\tif (upperBound instanceof DeclaredType declaredType) {\n\t\t\t\treturn declaredType.getTypeArguments().stream().anyMatch((candidate) -> candidate.equals(variable));\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic String visitArray(ArrayType t, TypeDescriptor descriptor) {\n\t\t\treturn t.getComponentType().accept(this, descriptor) + \"[]\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String visitPrimitive(PrimitiveType t, TypeDescriptor descriptor) {\n\t\t\treturn this.types.boxedClass(t).getQualifiedName().toString();\n\t\t}\n\n\t\t@Override\n\t\tprotected String defaultAction(TypeMirror t, TypeDescriptor descriptor) {\n\t\t\treturn t.toString();\n\t\t}\n\n\t\tString getQualifiedName(Element element) {\n\t\t\tif (element == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tTypeElement enclosingElement = getEnclosingTypeElement(element.asType());\n\t\t\tif (enclosingElement != null) {\n\t\t\t\treturn getQualifiedName(enclosingElement) + \"$\"\n\t\t\t\t\t\t+ ((DeclaredType) element.asType()).asElement().getSimpleName();\n\t\t\t}\n\t\t\tif (element instanceof TypeElement typeElement) {\n\t\t\t\treturn typeElement.getQualifiedName().toString();\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Could not extract qualified name from \" + element);\n\t\t}\n\n\t\tprivate TypeElement getEnclosingTypeElement(TypeMirror type) {\n\t\t\tif (type instanceof DeclaredType declaredType) {\n\t\t\t\tElement enclosingElement = declaredType.asElement().getEnclosingElement();\n\t\t\t\tif (enclosingElement instanceof TypeElement typeElement) {\n\t\t\t\t\treturn typeElement;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Descriptor for a given type.\n\t */\n\tstatic class TypeDescriptor {\n\n\t\tprivate final Map<TypeVariable, TypeMirror> generics = new HashMap<>();\n\n\t\tTypeMirror resolveGeneric(TypeVariable typeVariable) {\n\t\t\tTypeMirror resolved = this.generics.get(typeVariable);\n\t\t\tif (resolved != typeVariable && resolved instanceof TypeVariable resolvedTypeVariable) {\n\t\t\t\treturn resolveGeneric(resolvedTypeVariable);\n\t\t\t}\n\t\t\treturn resolved;\n\t\t}\n\n\t\tprivate void registerIfNecessary(TypeMirror variable, TypeMirror resolution) {\n\t\t\tif (variable instanceof TypeVariable typeVariable) {\n\t\t\t\tthis.generics.put(typeVariable, resolution);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/FieldValuesParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport javax.lang.model.element.TypeElement;\n\nimport org.springframework.boot.configurationprocessor.fieldvalues.javac.JavaCompilerFieldValuesParser;\n\n/**\n * Parser which can be used to obtain the field values from an {@link TypeElement}.\n *\n * @author Phillip Webb\n * @since 1.1.2\n * @see JavaCompilerFieldValuesParser\n */\n@FunctionalInterface\npublic interface FieldValuesParser {\n\n\t/**\n\t * Implementation of {@link FieldValuesParser} that always returns an empty result.\n\t */\n\tFieldValuesParser NONE = (element) -> Collections.emptyMap();\n\n\t/**\n\t * Return the field values for the given element.\n\t * @param element the element to inspect\n\t * @return a map of field names to values.\n\t * @throws Exception if the values cannot be extracted\n\t */\n\tMap<String, Object> getFieldValues(TypeElement element) throws Exception;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/ExpressionTree.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Reflection based access to {@code com.sun.source.tree.ExpressionTree}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass ExpressionTree extends ReflectionWrapper {\n\n\tprivate final Class<?> literalTreeType = findClass(\"com.sun.source.tree.LiteralTree\");\n\n\tprivate final Method literalValueMethod = findMethod(this.literalTreeType, \"getValue\");\n\n\tprivate final Class<?> methodInvocationTreeType = findClass(\"com.sun.source.tree.MethodInvocationTree\");\n\n\tprivate final Method methodInvocationArgumentsMethod = findMethod(this.methodInvocationTreeType, \"getArguments\");\n\n\tprivate final Class<?> memberSelectTreeType = findClass(\"com.sun.source.tree.MemberSelectTree\");\n\n\tprivate final Method memberSelectTreeExpressionMethod = findMethod(this.memberSelectTreeType, \"getExpression\");\n\n\tprivate final Method memberSelectTreeIdentifierMethod = findMethod(this.memberSelectTreeType, \"getIdentifier\");\n\n\tprivate final Class<?> newArrayTreeType = findClass(\"com.sun.source.tree.NewArrayTree\");\n\n\tprivate final Method arrayValueMethod = findMethod(this.newArrayTreeType, \"getInitializers\");\n\n\tExpressionTree(Object instance) {\n\t\tsuper(\"com.sun.source.tree.ExpressionTree\", instance);\n\t}\n\n\tString getKind() throws Exception {\n\t\treturn findMethod(\"getKind\").invoke(getInstance()).toString();\n\t}\n\n\tObject getLiteralValue() throws Exception {\n\t\tif (this.literalTreeType.isAssignableFrom(getInstance().getClass())) {\n\t\t\treturn this.literalValueMethod.invoke(getInstance());\n\t\t}\n\t\treturn null;\n\t}\n\n\tObject getFactoryValue() throws Exception {\n\t\tif (this.methodInvocationTreeType.isAssignableFrom(getInstance().getClass())) {\n\t\t\tList<?> arguments = (List<?>) this.methodInvocationArgumentsMethod.invoke(getInstance());\n\t\t\tif (arguments.size() == 1) {\n\t\t\t\treturn new ExpressionTree(arguments.get(0)).getLiteralValue();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tMember getSelectedMember() throws Exception {\n\t\tif (this.memberSelectTreeType.isAssignableFrom(getInstance().getClass())) {\n\t\t\tString expression = this.memberSelectTreeExpressionMethod.invoke(getInstance()).toString();\n\t\t\tString identifier = this.memberSelectTreeIdentifierMethod.invoke(getInstance()).toString();\n\t\t\tif (expression != null && identifier != null) {\n\t\t\t\treturn new Member(expression, identifier);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tList<? extends ExpressionTree> getArrayExpression() throws Exception {\n\t\tif (this.newArrayTreeType.isAssignableFrom(getInstance().getClass())) {\n\t\t\tList<?> elements = (List<?>) this.arrayValueMethod.invoke(getInstance());\n\t\t\tList<ExpressionTree> result = new ArrayList<>();\n\t\t\tif (elements == null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tfor (Object element : elements) {\n\t\t\t\tresult.add(new ExpressionTree(element));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\treturn null;\n\t}\n\n\trecord Member(String expression, String identifier) {\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.Modifier;\nimport javax.lang.model.element.TypeElement;\n\nimport org.springframework.boot.configurationprocessor.fieldvalues.FieldValuesParser;\nimport org.springframework.boot.configurationprocessor.fieldvalues.javac.ExpressionTree.Member;\nimport org.springframework.boot.configurationprocessor.support.ConventionUtils;\n\n/**\n * {@link FieldValuesParser} implementation for the standard Java compiler.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 1.2.0\n */\npublic class JavaCompilerFieldValuesParser implements FieldValuesParser {\n\n\tprivate final Trees trees;\n\n\tpublic JavaCompilerFieldValuesParser(ProcessingEnvironment env) throws Exception {\n\t\tthis.trees = Trees.instance(env);\n\t}\n\n\t@Override\n\tpublic Map<String, Object> getFieldValues(TypeElement element) throws Exception {\n\t\tTree tree = this.trees.getTree(element);\n\t\tif (tree != null) {\n\t\t\tFieldCollector fieldCollector = new FieldCollector();\n\t\t\ttree.accept(fieldCollector);\n\t\t\treturn fieldCollector.getFieldValues();\n\t\t}\n\t\treturn Collections.emptyMap();\n\t}\n\n\t/**\n\t * {@link TreeVisitor} to collect fields.\n\t */\n\tprivate static final class FieldCollector implements TreeVisitor {\n\n\t\tprivate static final Map<String, Class<?>> WRAPPER_TYPES;\n\n\t\tstatic {\n\t\t\tMap<String, Class<?>> types = new HashMap<>();\n\t\t\ttypes.put(\"boolean\", Boolean.class);\n\t\t\ttypes.put(Boolean.class.getName(), Boolean.class);\n\t\t\ttypes.put(\"byte\", Byte.class);\n\t\t\ttypes.put(Byte.class.getName(), Byte.class);\n\t\t\ttypes.put(\"short\", Short.class);\n\t\t\ttypes.put(Short.class.getName(), Short.class);\n\t\t\ttypes.put(\"int\", Integer.class);\n\t\t\ttypes.put(Integer.class.getName(), Integer.class);\n\t\t\ttypes.put(\"long\", Long.class);\n\t\t\ttypes.put(Long.class.getName(), Long.class);\n\t\t\tWRAPPER_TYPES = Collections.unmodifiableMap(types);\n\t\t}\n\n\t\tprivate static final Map<Class<?>, Object> DEFAULT_TYPE_VALUES;\n\n\t\tstatic {\n\t\t\tMap<Class<?>, Object> values = new HashMap<>();\n\t\t\tvalues.put(Boolean.class, false);\n\t\t\tvalues.put(Byte.class, (byte) 0);\n\t\t\tvalues.put(Short.class, (short) 0);\n\t\t\tvalues.put(Integer.class, 0);\n\t\t\tvalues.put(Long.class, (long) 0);\n\t\t\tDEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values);\n\t\t}\n\n\t\tprivate static final Map<String, Object> WELL_KNOWN_STATIC_FINALS;\n\n\t\tstatic {\n\t\t\tMap<String, Object> values = new HashMap<>();\n\t\t\tvalues.put(\"Boolean.TRUE\", true);\n\t\t\tvalues.put(\"Boolean.FALSE\", false);\n\t\t\tvalues.put(\"StandardCharsets.ISO_8859_1\", \"ISO-8859-1\");\n\t\t\tvalues.put(\"StandardCharsets.UTF_8\", \"UTF-8\");\n\t\t\tvalues.put(\"StandardCharsets.UTF_16\", \"UTF-16\");\n\t\t\tvalues.put(\"StandardCharsets.US_ASCII\", \"US-ASCII\");\n\t\t\tvalues.put(\"Duration.ZERO\", 0);\n\t\t\tvalues.put(\"Period.ZERO\", 0);\n\t\t\tWELL_KNOWN_STATIC_FINALS = Collections.unmodifiableMap(values);\n\t\t}\n\n\t\tprivate static final String DURATION_OF = \"Duration.of\";\n\n\t\tprivate static final Map<String, String> DURATION_SUFFIX;\n\n\t\tstatic {\n\t\t\tMap<String, String> values = new HashMap<>();\n\t\t\tvalues.put(\"Nanos\", \"ns\");\n\t\t\tvalues.put(\"Millis\", \"ms\");\n\t\t\tvalues.put(\"Seconds\", \"s\");\n\t\t\tvalues.put(\"Minutes\", \"m\");\n\t\t\tvalues.put(\"Hours\", \"h\");\n\t\t\tvalues.put(\"Days\", \"d\");\n\t\t\tDURATION_SUFFIX = Collections.unmodifiableMap(values);\n\t\t}\n\n\t\tprivate static final String PERIOD_OF = \"Period.of\";\n\n\t\tprivate static final Map<String, String> PERIOD_SUFFIX;\n\n\t\tstatic {\n\t\t\tMap<String, String> values = new HashMap<>();\n\t\t\tvalues.put(\"Days\", \"d\");\n\t\t\tvalues.put(\"Weeks\", \"w\");\n\t\t\tvalues.put(\"Months\", \"m\");\n\t\t\tvalues.put(\"Years\", \"y\");\n\t\t\tPERIOD_SUFFIX = Collections.unmodifiableMap(values);\n\t\t}\n\n\t\tprivate static final String DATA_SIZE_OF = \"DataSize.of\";\n\n\t\tprivate static final Map<String, String> DATA_SIZE_SUFFIX;\n\n\t\tstatic {\n\t\t\tMap<String, String> values = new HashMap<>();\n\t\t\tvalues.put(\"Bytes\", \"B\");\n\t\t\tvalues.put(\"Kilobytes\", \"KB\");\n\t\t\tvalues.put(\"Megabytes\", \"MB\");\n\t\t\tvalues.put(\"Gigabytes\", \"GB\");\n\t\t\tvalues.put(\"Terabytes\", \"TB\");\n\t\t\tDATA_SIZE_SUFFIX = Collections.unmodifiableMap(values);\n\t\t}\n\n\t\tprivate final Map<String, Object> fieldValues = new HashMap<>();\n\n\t\tprivate final Map<String, Object> staticFinals = new HashMap<>();\n\n\t\t@Override\n\t\tpublic void visitVariable(VariableTree variable) throws Exception {\n\t\t\tSet<Modifier> flags = variable.getModifierFlags();\n\t\t\tif (flags.contains(Modifier.STATIC) && flags.contains(Modifier.FINAL)) {\n\t\t\t\tthis.staticFinals.put(variable.getName(), getValue(variable));\n\t\t\t}\n\t\t\tif (!flags.contains(Modifier.FINAL)) {\n\t\t\t\tthis.fieldValues.put(variable.getName(), getValue(variable));\n\t\t\t}\n\t\t}\n\n\t\tprivate Object getValue(VariableTree variable) throws Exception {\n\t\t\tExpressionTree initializer = variable.getInitializer();\n\t\t\tClass<?> wrapperType = WRAPPER_TYPES.get(variable.getType());\n\t\t\tObject defaultValue = DEFAULT_TYPE_VALUES.get(wrapperType);\n\t\t\tif (initializer != null) {\n\t\t\t\treturn getValue(variable.getType(), initializer, defaultValue);\n\t\t\t}\n\t\t\treturn defaultValue;\n\t\t}\n\n\t\tprivate Object getValue(String variableType, ExpressionTree expression, Object defaultValue) throws Exception {\n\t\t\tObject literalValue = expression.getLiteralValue();\n\t\t\tif (literalValue != null) {\n\t\t\t\treturn literalValue;\n\t\t\t}\n\t\t\tObject factoryValue = expression.getFactoryValue();\n\t\t\tif (factoryValue != null) {\n\t\t\t\treturn getFactoryValue(expression, factoryValue);\n\t\t\t}\n\t\t\tList<? extends ExpressionTree> arrayValues = expression.getArrayExpression();\n\t\t\tif (arrayValues != null) {\n\t\t\t\tObject[] result = new Object[arrayValues.size()];\n\t\t\t\tfor (int i = 0; i < arrayValues.size(); i++) {\n\t\t\t\t\tObject value = getValue(variableType, arrayValues.get(i), null);\n\t\t\t\t\tif (value == null) { // One of the elements could not be resolved\n\t\t\t\t\t\treturn defaultValue;\n\t\t\t\t\t}\n\t\t\t\t\tresult[i] = value;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tif (expression.getKind().equals(\"IDENTIFIER\")) {\n\t\t\t\treturn this.staticFinals.get(expression.toString());\n\t\t\t}\n\t\t\tif (expression.getKind().equals(\"MEMBER_SELECT\")) {\n\t\t\t\tObject value = WELL_KNOWN_STATIC_FINALS.get(expression.toString());\n\t\t\t\tif (value != null) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t\tMember selectedMember = expression.getSelectedMember();\n\t\t\t\t// Type matching the expression, assuming an enum\n\t\t\t\tif (selectedMember != null && selectedMember.expression().equals(variableType)) {\n\t\t\t\t\treturn ConventionUtils.toDashedCase(selectedMember.identifier().toLowerCase(Locale.ENGLISH));\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate Object getFactoryValue(ExpressionTree expression, Object factoryValue) {\n\t\t\tObject durationValue = getFactoryValue(expression, factoryValue, DURATION_OF, DURATION_SUFFIX);\n\t\t\tif (durationValue != null) {\n\t\t\t\treturn durationValue;\n\t\t\t}\n\t\t\tObject dataSizeValue = getFactoryValue(expression, factoryValue, DATA_SIZE_OF, DATA_SIZE_SUFFIX);\n\t\t\tif (dataSizeValue != null) {\n\t\t\t\treturn dataSizeValue;\n\t\t\t}\n\t\t\tObject periodValue = getFactoryValue(expression, factoryValue, PERIOD_OF, PERIOD_SUFFIX);\n\t\t\tif (periodValue != null) {\n\t\t\t\treturn periodValue;\n\t\t\t}\n\t\t\treturn factoryValue;\n\t\t}\n\n\t\tprivate Object getFactoryValue(ExpressionTree expression, Object factoryValue, String prefix,\n\t\t\t\tMap<String, String> suffixMapping) {\n\t\t\tObject instance = expression.getInstance();\n\t\t\tif (instance != null && instance.toString().startsWith(prefix)) {\n\t\t\t\tString type = instance.toString();\n\t\t\t\ttype = type.substring(prefix.length(), type.indexOf('('));\n\t\t\t\tString suffix = suffixMapping.get(type);\n\t\t\t\treturn (suffix != null) ? factoryValue + suffix : null;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tMap<String, Object> getFieldValues() {\n\t\t\treturn this.fieldValues;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/ReflectionWrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport java.lang.reflect.Method;\n\n/**\n * Base class for reflection based wrappers. Used to access internal Java classes without\n * needing tools.jar on the classpath.\n *\n * @author Phillip Webb\n */\nclass ReflectionWrapper {\n\n\tprivate final Class<?> type;\n\n\tprivate final Object instance;\n\n\tReflectionWrapper(String type, Object instance) {\n\t\tthis.type = findClass(instance.getClass().getClassLoader(), type);\n\t\tthis.instance = this.type.cast(instance);\n\t}\n\n\tprotected final Object getInstance() {\n\t\treturn this.instance;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.instance.toString();\n\t}\n\n\tprotected Class<?> findClass(String name) {\n\t\treturn findClass(getInstance().getClass().getClassLoader(), name);\n\t}\n\n\tprotected Method findMethod(String name, Class<?>... parameterTypes) {\n\t\treturn findMethod(this.type, name, parameterTypes);\n\t}\n\n\tprotected static Class<?> findClass(ClassLoader classLoader, String name) {\n\t\ttry {\n\t\t\treturn Class.forName(name, false, classLoader);\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprotected static Method findMethod(Class<?> type, String name, Class<?>... parameterTypes) {\n\t\ttry {\n\t\t\treturn type.getMethod(name, parameterTypes);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/Tree.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Proxy;\n\n/**\n * Reflection based access to {@code com.sun.source.tree.Tree}.\n *\n * @author Phillip Webb\n */\nclass Tree extends ReflectionWrapper {\n\n\tprivate final Class<?> treeVisitorType = findClass(\"com.sun.source.tree.TreeVisitor\");\n\n\tprivate final Method acceptMethod = findMethod(\"accept\", this.treeVisitorType, Object.class);\n\n\tprivate final Method getClassTreeMembers = findMethod(findClass(\"com.sun.source.tree.ClassTree\"), \"getMembers\");\n\n\tTree(Object instance) {\n\t\tsuper(\"com.sun.source.tree.Tree\", instance);\n\t}\n\n\tvoid accept(TreeVisitor visitor) throws Exception {\n\t\tthis.acceptMethod.invoke(getInstance(), Proxy.newProxyInstance(getInstance().getClass().getClassLoader(),\n\t\t\t\tnew Class<?>[] { this.treeVisitorType }, new TreeVisitorInvocationHandler(visitor)), 0);\n\t}\n\n\t/**\n\t * {@link InvocationHandler} to call the {@link TreeVisitor}.\n\t */\n\tprivate class TreeVisitorInvocationHandler implements InvocationHandler {\n\n\t\tprivate TreeVisitor treeVisitor;\n\n\t\tTreeVisitorInvocationHandler(TreeVisitor treeVisitor) {\n\t\t\tthis.treeVisitor = treeVisitor;\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tpublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\t\tif (method.getName().equals(\"visitClass\") && (Integer) args[1] == 0) {\n\t\t\t\tIterable members = (Iterable) Tree.this.getClassTreeMembers.invoke(args[0]);\n\t\t\t\tfor (Object member : members) {\n\t\t\t\t\tif (member != null) {\n\t\t\t\t\t\tTree.this.acceptMethod.invoke(member, proxy, ((Integer) args[1]) + 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (method.getName().equals(\"visitVariable\")) {\n\t\t\t\tthis.treeVisitor.visitVariable(new VariableTree(args[0]));\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/TreeVisitor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\n/**\n * Reflection base alternative for {@code com.sun.source.tree.TreeVisitor}.\n *\n * @author Phillip Webb\n */\ninterface TreeVisitor {\n\n\tvoid visitVariable(VariableTree variable) throws Exception;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/Trees.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.lang.model.element.Element;\n\n/**\n * Reflection based access to {@code com.sun.source.util.Trees}.\n *\n * @author Phillip Webb\n */\nfinal class Trees extends ReflectionWrapper {\n\n\tprivate Trees(Object instance) {\n\t\tsuper(\"com.sun.source.util.Trees\", instance);\n\t}\n\n\tTree getTree(Element element) throws Exception {\n\t\tObject tree = findMethod(\"getTree\", Element.class).invoke(getInstance(), element);\n\t\treturn (tree != null) ? new Tree(tree) : null;\n\t}\n\n\tstatic Trees instance(ProcessingEnvironment env) throws Exception {\n\t\ttry {\n\t\t\tClassLoader classLoader = env.getClass().getClassLoader();\n\t\t\tClass<?> type = findClass(classLoader, \"com.sun.source.util.Trees\");\n\t\t\tMethod method = findMethod(type, \"instance\", ProcessingEnvironment.class);\n\t\t\treturn new Trees(method.invoke(null, env));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn instance(unwrap(env));\n\t\t}\n\t}\n\n\tprivate static ProcessingEnvironment unwrap(ProcessingEnvironment wrapper) throws Exception {\n\t\tField delegateField = wrapper.getClass().getDeclaredField(\"delegate\");\n\t\tdelegateField.setAccessible(true);\n\t\treturn (ProcessingEnvironment) delegateField.get(wrapper);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/VariableTree.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport javax.lang.model.element.Modifier;\n\n/**\n * Reflection based access to {@code com.sun.source.tree.VariableTree}.\n *\n * @author Phillip Webb\n */\nclass VariableTree extends ReflectionWrapper {\n\n\tVariableTree(Object instance) {\n\t\tsuper(\"com.sun.source.tree.VariableTree\", instance);\n\t}\n\n\tString getName() throws Exception {\n\t\treturn findMethod(\"getName\").invoke(getInstance()).toString();\n\t}\n\n\tString getType() throws Exception {\n\t\treturn findMethod(\"getType\").invoke(getInstance()).toString();\n\t}\n\n\tExpressionTree getInitializer() throws Exception {\n\t\tObject instance = findMethod(\"getInitializer\").invoke(getInstance());\n\t\treturn (instance != null) ? new ExpressionTree(instance) : null;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tSet<Modifier> getModifierFlags() throws Exception {\n\t\tObject modifiers = findMethod(\"getModifiers\").invoke(getInstance());\n\t\tif (modifiers == null) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t\treturn (Set<Modifier>) findMethod(findClass(\"com.sun.source.tree.ModifiersTree\"), \"getFlags\").invoke(modifiers);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Field value parsing for the standard Java compiler.\n */\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/fieldvalues/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Abstraction for field value parsing.\n */\npackage org.springframework.boot.configurationprocessor.fieldvalues;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\nimport org.springframework.boot.configurationprocessor.support.ConventionUtils;\n\n/**\n * Configuration meta-data.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 1.2.0\n * @see ItemMetadata\n */\npublic class ConfigurationMetadata {\n\n\tprivate final Map<String, List<ItemMetadata>> items;\n\n\tprivate final Map<String, List<ItemHint>> hints;\n\n\tprivate final Map<String, List<ItemIgnore>> ignored;\n\n\tpublic ConfigurationMetadata() {\n\t\tthis.items = new LinkedHashMap<>();\n\t\tthis.hints = new LinkedHashMap<>();\n\t\tthis.ignored = new LinkedHashMap<>();\n\t}\n\n\tpublic ConfigurationMetadata(ConfigurationMetadata metadata) {\n\t\tthis.items = new LinkedHashMap<>(metadata.items);\n\t\tthis.hints = new LinkedHashMap<>(metadata.hints);\n\t\tthis.ignored = new LinkedHashMap<>(metadata.ignored);\n\t}\n\n\t/**\n\t * Add item meta-data.\n\t * @param itemMetadata the meta-data to add\n\t */\n\tpublic void add(ItemMetadata itemMetadata) {\n\t\tadd(this.items, itemMetadata.getName(), itemMetadata, false);\n\t}\n\n\t/**\n\t * Add item meta-data if it's not already present.\n\t * @param itemMetadata the meta-data to add\n\t * @since 2.4.0\n\t */\n\tpublic void addIfMissing(ItemMetadata itemMetadata) {\n\t\tadd(this.items, itemMetadata.getName(), itemMetadata, true);\n\t}\n\n\t/**\n\t * Add item hint.\n\t * @param itemHint the item hint to add\n\t */\n\tpublic void add(ItemHint itemHint) {\n\t\tadd(this.hints, itemHint.getName(), itemHint, false);\n\t}\n\n\t/**\n\t * Add item ignore.\n\t * @param itemIgnore the item ignore to add\n\t * @since 3.5.0\n\t */\n\tpublic void add(ItemIgnore itemIgnore) {\n\t\tadd(this.ignored, itemIgnore.getName(), itemIgnore, false);\n\t}\n\n\t/**\n\t * Remove item meta-data for the given item type and name.\n\t * @param itemType the item type\n\t * @param name the name\n\t * @since 3.5.0\n\t */\n\tpublic void removeMetadata(ItemType itemType, String name) {\n\t\tList<ItemMetadata> metadata = this.items.get(name);\n\t\tif (metadata == null) {\n\t\t\treturn;\n\t\t}\n\t\tmetadata.removeIf((item) -> item.isOfItemType(itemType));\n\t\tif (metadata.isEmpty()) {\n\t\t\tthis.items.remove(name);\n\t\t}\n\t}\n\n\t/**\n\t * Merge the content from another {@link ConfigurationMetadata}.\n\t * @param metadata the {@link ConfigurationMetadata} instance to merge\n\t */\n\tpublic void merge(ConfigurationMetadata metadata) {\n\t\tfor (ItemMetadata additionalItem : metadata.getItems()) {\n\t\t\tmergeItemMetadata(additionalItem);\n\t\t}\n\t\tfor (ItemHint itemHint : metadata.getHints()) {\n\t\t\tadd(itemHint);\n\t\t}\n\t\tfor (ItemIgnore itemIgnore : metadata.getIgnored()) {\n\t\t\tadd(itemIgnore);\n\t\t}\n\t}\n\n\t/**\n\t * Return item meta-data.\n\t * @return the items\n\t */\n\tpublic List<ItemMetadata> getItems() {\n\t\treturn flattenValues(this.items);\n\t}\n\n\t/**\n\t * Return hint meta-data.\n\t * @return the hints\n\t */\n\tpublic List<ItemHint> getHints() {\n\t\treturn flattenValues(this.hints);\n\t}\n\n\t/**\n\t * Return ignore meta-data.\n\t * @return the ignores\n\t */\n\tpublic List<ItemIgnore> getIgnored() {\n\t\treturn flattenValues(this.ignored);\n\t}\n\n\tprotected void mergeItemMetadata(ItemMetadata metadata) {\n\t\tItemMetadata matching = findMatchingItemMetadata(metadata);\n\t\tif (matching != null) {\n\t\t\tif (metadata.getDescription() != null) {\n\t\t\t\tmatching.setDescription(metadata.getDescription());\n\t\t\t}\n\t\t\tif (metadata.getDefaultValue() != null) {\n\t\t\t\tmatching.setDefaultValue(metadata.getDefaultValue());\n\t\t\t}\n\t\t\tItemDeprecation deprecation = metadata.getDeprecation();\n\t\t\tItemDeprecation matchingDeprecation = matching.getDeprecation();\n\t\t\tif (deprecation != null) {\n\t\t\t\tif (matchingDeprecation == null) {\n\t\t\t\t\tmatching.setDeprecation(deprecation);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (deprecation.getReason() != null) {\n\t\t\t\t\t\tmatchingDeprecation.setReason(deprecation.getReason());\n\t\t\t\t\t}\n\t\t\t\t\tif (deprecation.getReplacement() != null) {\n\t\t\t\t\t\tmatchingDeprecation.setReplacement(deprecation.getReplacement());\n\t\t\t\t\t}\n\t\t\t\t\tif (deprecation.getLevel() != null) {\n\t\t\t\t\t\tmatchingDeprecation.setLevel(deprecation.getLevel());\n\t\t\t\t\t}\n\t\t\t\t\tif (deprecation.getSince() != null) {\n\t\t\t\t\t\tmatchingDeprecation.setSince(deprecation.getSince());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tadd(this.items, metadata.getName(), metadata, false);\n\t\t}\n\t}\n\n\tprivate <K, V> void add(Map<K, List<V>> map, K key, V value, boolean ifMissing) {\n\t\tList<V> values = map.computeIfAbsent(key, (k) -> new ArrayList<>());\n\t\tif (!ifMissing || values.isEmpty()) {\n\t\t\tvalues.add(value);\n\t\t}\n\t}\n\n\tprivate ItemMetadata findMatchingItemMetadata(ItemMetadata metadata) {\n\t\tList<ItemMetadata> candidates = this.items.get(metadata.getName());\n\t\tif (candidates == null || candidates.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tcandidates = new ArrayList<>(candidates);\n\t\tcandidates.removeIf((itemMetadata) -> !itemMetadata.hasSameType(metadata));\n\t\tif (candidates.size() > 1 && metadata.getType() != null) {\n\t\t\tcandidates.removeIf((itemMetadata) -> !metadata.getType().equals(itemMetadata.getType()));\n\t\t}\n\t\tif (candidates.size() == 1) {\n\t\t\treturn candidates.get(0);\n\t\t}\n\t\tfor (ItemMetadata candidate : candidates) {\n\t\t\tif (nullSafeEquals(candidate.getSourceType(), metadata.getSourceType())) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean nullSafeEquals(Object o1, Object o2) {\n\t\tif (o1 == o2) {\n\t\t\treturn true;\n\t\t}\n\t\treturn o1 != null && o1.equals(o2);\n\t}\n\n\tpublic static String nestedPrefix(String prefix, String name) {\n\t\tString nestedPrefix = (prefix != null) ? prefix : \"\";\n\t\tString dashedName = ConventionUtils.toDashedCase(name);\n\t\tnestedPrefix += nestedPrefix.isEmpty() ? dashedName : \".\" + dashedName;\n\t\treturn nestedPrefix;\n\t}\n\n\tprivate static <T extends Comparable<T>> List<T> flattenValues(Map<?, List<T>> map) {\n\t\tList<T> content = new ArrayList<>();\n\t\tfor (List<T> values : map.values()) {\n\t\t\tcontent.addAll(values);\n\t\t}\n\t\tCollections.sort(content);\n\t\treturn content;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder result = new StringBuilder();\n\t\tresult.append(String.format(\"items: %n\"));\n\t\tthis.items.values().forEach((itemMetadata) -> result.append(\"\\t\").append(String.format(\"%s%n\", itemMetadata)));\n\t\treturn result.toString();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/InvalidConfigurationMetadataException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport javax.tools.Diagnostic;\n\n/**\n * Thrown to indicate that some meta-data is invalid. Define the severity to determine\n * whether it has to fail the build.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@SuppressWarnings(\"serial\")\npublic class InvalidConfigurationMetadataException extends RuntimeException {\n\n\tprivate final Diagnostic.Kind kind;\n\n\tpublic InvalidConfigurationMetadataException(String message, Diagnostic.Kind kind) {\n\t\tsuper(message);\n\t\tthis.kind = kind;\n\t}\n\n\tpublic Diagnostic.Kind getKind() {\n\t\treturn this.kind;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemDeprecation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\n/**\n * Describe an item deprecation.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 1.3.0\n */\npublic class ItemDeprecation {\n\n\tprivate String reason;\n\n\tprivate String replacement;\n\n\tprivate String since;\n\n\tprivate String level;\n\n\tpublic ItemDeprecation() {\n\t\tthis(null, null, null);\n\t}\n\n\tpublic ItemDeprecation(String reason, String replacement, String since) {\n\t\tthis(reason, replacement, since, null);\n\t}\n\n\tpublic ItemDeprecation(String reason, String replacement, String since, String level) {\n\t\tthis.reason = reason;\n\t\tthis.replacement = replacement;\n\t\tthis.since = since;\n\t\tthis.level = level;\n\t}\n\n\tpublic String getReason() {\n\t\treturn this.reason;\n\t}\n\n\tpublic void setReason(String reason) {\n\t\tthis.reason = reason;\n\t}\n\n\tpublic String getReplacement() {\n\t\treturn this.replacement;\n\t}\n\n\tpublic void setReplacement(String replacement) {\n\t\tthis.replacement = replacement;\n\t}\n\n\tpublic String getSince() {\n\t\treturn this.since;\n\t}\n\n\tpublic void setSince(String since) {\n\t\tthis.since = since;\n\t}\n\n\tpublic String getLevel() {\n\t\treturn this.level;\n\t}\n\n\tpublic void setLevel(String level) {\n\t\tthis.level = level;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif (this == o) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tItemDeprecation other = (ItemDeprecation) o;\n\t\treturn nullSafeEquals(this.reason, other.reason) && nullSafeEquals(this.replacement, other.replacement)\n\t\t\t\t&& nullSafeEquals(this.level, other.level) && nullSafeEquals(this.since, other.since);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = nullSafeHashCode(this.reason);\n\t\tresult = 31 * result + nullSafeHashCode(this.replacement);\n\t\tresult = 31 * result + nullSafeHashCode(this.level);\n\t\tresult = 31 * result + nullSafeHashCode(this.since);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"ItemDeprecation{reason='\" + this.reason + '\\'' + \", replacement='\" + this.replacement + '\\''\n\t\t\t\t+ \", level='\" + this.level + '\\'' + \", since='\" + this.since + '\\'' + '}';\n\t}\n\n\tprivate boolean nullSafeEquals(Object o1, Object o2) {\n\t\tif (o1 == o2) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o1 == null || o2 == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn o1.equals(o2);\n\t}\n\n\tprivate int nullSafeHashCode(Object o) {\n\t\treturn (o != null) ? o.hashCode() : 0;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemHint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.configurationprocessor.support.ConventionUtils;\n\n/**\n * Provide hints on an {@link ItemMetadata}. Defines the list of possible values for a\n * particular item as {@link ItemHint.ValueHint} instances.\n * <p>\n * The {@code name} of the hint is the name of the related property with one major\n * exception for map types as both the keys and values of the map can have hints. In such\n * a case, the hint should be suffixed by \".keys\" or \".values\" respectively. Creating a\n * hint for a map using its property name is therefore invalid.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\npublic class ItemHint implements Comparable<ItemHint> {\n\n\tprivate final String name;\n\n\tprivate final List<ValueHint> values;\n\n\tprivate final List<ValueProvider> providers;\n\n\tpublic ItemHint(String name, List<ValueHint> values, List<ValueProvider> providers) {\n\t\tthis.name = toCanonicalName(name);\n\t\tthis.values = (values != null) ? new ArrayList<>(values) : new ArrayList<>();\n\t\tthis.providers = (providers != null) ? new ArrayList<>(providers) : new ArrayList<>();\n\t}\n\n\tprivate String toCanonicalName(String name) {\n\t\tint dot = name.lastIndexOf('.');\n\t\tif (dot != -1) {\n\t\t\tString prefix = name.substring(0, dot);\n\t\t\tString originalName = name.substring(dot);\n\t\t\treturn prefix + ConventionUtils.toDashedCase(originalName);\n\t\t}\n\t\treturn ConventionUtils.toDashedCase(name);\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic List<ValueHint> getValues() {\n\t\treturn Collections.unmodifiableList(this.values);\n\t}\n\n\tpublic List<ValueProvider> getProviders() {\n\t\treturn Collections.unmodifiableList(this.providers);\n\t}\n\n\t/**\n\t * Return an {@link ItemHint} with the given prefix applied.\n\t * @param prefix the prefix to apply\n\t * @return a new {@link ItemHint} with the same of this instance whose property name\n\t * has the prefix applied to it\n\t */\n\tpublic ItemHint applyPrefix(String prefix) {\n\t\treturn new ItemHint(ConventionUtils.toDashedCase(prefix) + \".\" + this.name, this.values, this.providers);\n\t}\n\n\t@Override\n\tpublic int compareTo(ItemHint other) {\n\t\treturn getName().compareTo(other.getName());\n\t}\n\n\tpublic static ItemHint newHint(String name, ValueHint... values) {\n\t\treturn new ItemHint(name, Arrays.asList(values), Collections.emptyList());\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"ItemHint{name='\" + this.name + \"', values=\" + this.values + \", providers=\" + this.providers + '}';\n\t}\n\n\t/**\n\t * A hint for a value.\n\t */\n\tpublic static class ValueHint {\n\n\t\tprivate final Object value;\n\n\t\tprivate final String description;\n\n\t\tpublic ValueHint(Object value, String description) {\n\t\t\tthis.value = value;\n\t\t\tthis.description = description;\n\t\t}\n\n\t\tpublic Object getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tpublic String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"ValueHint{value=\" + this.value + \", description='\" + this.description + '\\'' + '}';\n\t\t}\n\n\t}\n\n\t/**\n\t * A value provider.\n\t */\n\tpublic static class ValueProvider {\n\n\t\tprivate final String name;\n\n\t\tprivate final Map<String, Object> parameters;\n\n\t\tpublic ValueProvider(String name, Map<String, Object> parameters) {\n\t\t\tthis.name = name;\n\t\t\tthis.parameters = parameters;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic Map<String, Object> getParameters() {\n\t\t\treturn this.parameters;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"ValueProvider{name='\" + this.name + \"', parameters=\" + this.parameters + '}';\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemIgnore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.Objects;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\n\n/**\n * Ignored item.\n *\n * @author Moritz Halbritter\n * @since 3.5.0\n */\npublic final class ItemIgnore implements Comparable<ItemIgnore> {\n\n\tprivate final ItemType type;\n\n\tprivate final String name;\n\n\tprivate ItemIgnore(ItemType type, String name) {\n\t\tif (type == null) {\n\t\t\tthrow new IllegalArgumentException(\"'type' must not be null\");\n\t\t}\n\t\tif (name == null) {\n\t\t\tthrow new IllegalArgumentException(\"'name' must not be null\");\n\t\t}\n\t\tthis.type = type;\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic ItemType getType() {\n\t\treturn this.type;\n\t}\n\n\t@Override\n\tpublic int compareTo(ItemIgnore other) {\n\t\treturn getName().compareTo(other.getName());\n\t}\n\n\t/**\n\t * Create an ignore for a property with the given name.\n\t * @param name the name\n\t * @return the item ignore\n\t */\n\tpublic static ItemIgnore forProperty(String name) {\n\t\treturn new ItemIgnore(ItemType.PROPERTY, name);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tItemIgnore that = (ItemIgnore) o;\n\t\treturn this.type == that.type && Objects.equals(this.name, that.name);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.type, this.name);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"ItemIgnore{\" + \"type=\" + this.type + \", name='\" + this.name + '\\'' + '}';\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/ItemMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.Locale;\n\nimport org.springframework.boot.configurationprocessor.support.ConventionUtils;\n\n/**\n * A group or property meta-data item from some {@link ConfigurationMetadata}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 1.2.0\n * @see ConfigurationMetadata\n */\npublic final class ItemMetadata implements Comparable<ItemMetadata> {\n\n\tprivate final ItemType itemType;\n\n\tprivate String name;\n\n\tprivate String type;\n\n\tprivate String description;\n\n\tprivate String sourceType;\n\n\tprivate String sourceMethod;\n\n\tprivate Object defaultValue;\n\n\tprivate ItemDeprecation deprecation;\n\n\tItemMetadata(ItemType itemType, String prefix, String name, String type, String sourceType, String sourceMethod,\n\t\t\tString description, Object defaultValue, ItemDeprecation deprecation) {\n\t\tthis.itemType = itemType;\n\t\tthis.name = buildName(prefix, name);\n\t\tthis.type = type;\n\t\tthis.sourceType = sourceType;\n\t\tthis.sourceMethod = sourceMethod;\n\t\tthis.description = description;\n\t\tthis.defaultValue = defaultValue;\n\t\tthis.deprecation = deprecation;\n\t}\n\n\tprivate String buildName(String prefix, String name) {\n\t\tStringBuilder fullName = new StringBuilder();\n\t\tif (prefix != null) {\n\t\t\tif (prefix.endsWith(\".\")) {\n\t\t\t\tprefix = prefix.substring(0, prefix.length() - 1);\n\t\t\t}\n\t\t\tfullName.append(prefix);\n\t\t}\n\t\tif (name != null) {\n\t\t\tif (!fullName.isEmpty()) {\n\t\t\t\tfullName.append('.');\n\t\t\t}\n\t\t\tfullName.append(ConventionUtils.toDashedCase(name));\n\t\t}\n\t\treturn fullName.toString();\n\t}\n\n\tpublic boolean isOfItemType(ItemType itemType) {\n\t\treturn this.itemType == itemType;\n\t}\n\n\tpublic boolean hasSameType(ItemMetadata metadata) {\n\t\treturn this.itemType == metadata.itemType;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getType() {\n\t\treturn this.type;\n\t}\n\n\tpublic void setType(String type) {\n\t\tthis.type = type;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic String getSourceType() {\n\t\treturn this.sourceType;\n\t}\n\n\tpublic void setSourceType(String sourceType) {\n\t\tthis.sourceType = sourceType;\n\t}\n\n\tpublic String getSourceMethod() {\n\t\treturn this.sourceMethod;\n\t}\n\n\tpublic void setSourceMethod(String sourceMethod) {\n\t\tthis.sourceMethod = sourceMethod;\n\t}\n\n\tpublic Object getDefaultValue() {\n\t\treturn this.defaultValue;\n\t}\n\n\tpublic void setDefaultValue(Object defaultValue) {\n\t\tthis.defaultValue = defaultValue;\n\t}\n\n\tpublic ItemDeprecation getDeprecation() {\n\t\treturn this.deprecation;\n\t}\n\n\tpublic void setDeprecation(ItemDeprecation deprecation) {\n\t\tthis.deprecation = deprecation;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object o) {\n\t\tif (this == o) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tItemMetadata other = (ItemMetadata) o;\n\t\tboolean result = true;\n\t\tresult = result && nullSafeEquals(this.itemType, other.itemType);\n\t\tresult = result && nullSafeEquals(this.name, other.name);\n\t\tresult = result && nullSafeEquals(this.type, other.type);\n\t\tresult = result && nullSafeEquals(this.description, other.description);\n\t\tresult = result && nullSafeEquals(this.sourceType, other.sourceType);\n\t\tresult = result && nullSafeEquals(this.sourceMethod, other.sourceMethod);\n\t\tresult = result && nullSafeEquals(this.defaultValue, other.defaultValue);\n\t\tresult = result && nullSafeEquals(this.deprecation, other.deprecation);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = nullSafeHashCode(this.itemType);\n\t\tresult = 31 * result + nullSafeHashCode(this.name);\n\t\tresult = 31 * result + nullSafeHashCode(this.type);\n\t\tresult = 31 * result + nullSafeHashCode(this.description);\n\t\tresult = 31 * result + nullSafeHashCode(this.sourceType);\n\t\tresult = 31 * result + nullSafeHashCode(this.sourceMethod);\n\t\tresult = 31 * result + nullSafeHashCode(this.defaultValue);\n\t\tresult = 31 * result + nullSafeHashCode(this.deprecation);\n\t\treturn result;\n\t}\n\n\tprivate boolean nullSafeEquals(Object o1, Object o2) {\n\t\tif (o1 == o2) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o1 == null || o2 == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn o1.equals(o2);\n\t}\n\n\tprivate int nullSafeHashCode(Object o) {\n\t\treturn (o != null) ? o.hashCode() : 0;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder string = new StringBuilder(this.name);\n\t\tbuildToStringProperty(string, \"type\", this.type);\n\t\tbuildToStringProperty(string, \"sourceType\", this.sourceType);\n\t\tbuildToStringProperty(string, \"description\", this.description);\n\t\tbuildToStringProperty(string, \"defaultValue\", this.defaultValue);\n\t\tbuildToStringProperty(string, \"deprecation\", this.deprecation);\n\t\treturn string.toString();\n\t}\n\n\tprivate void buildToStringProperty(StringBuilder string, String property, Object value) {\n\t\tif (value != null) {\n\t\t\tstring.append(\" \").append(property).append(\":\").append(value);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int compareTo(ItemMetadata o) {\n\t\treturn getName().compareTo(o.getName());\n\t}\n\n\tpublic static ItemMetadata newGroup(String name, String type, String sourceType, String sourceMethod) {\n\t\treturn new ItemMetadata(ItemType.GROUP, name, null, type, sourceType, sourceMethod, null, null, null);\n\t}\n\n\tpublic static ItemMetadata newProperty(String prefix, String name, String type, String sourceType,\n\t\t\tString sourceMethod, String description, Object defaultValue, ItemDeprecation deprecation) {\n\t\treturn new ItemMetadata(ItemType.PROPERTY, prefix, name, type, sourceType, sourceMethod, description,\n\t\t\t\tdefaultValue, deprecation);\n\t}\n\n\tpublic static String newItemMetadataPrefix(String prefix, String suffix) {\n\t\treturn prefix.toLowerCase(Locale.ENGLISH) + ConventionUtils.toDashedCase(suffix);\n\t}\n\n\t/**\n\t * The item type.\n\t */\n\tpublic enum ItemType {\n\n\t\t/**\n\t\t * Group item type.\n\t\t */\n\t\tGROUP,\n\n\t\t/**\n\t\t * Property item type.\n\t\t */\n\t\tPROPERTY\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.lang.reflect.Array;\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.configurationprocessor.json.JSONArray;\nimport org.springframework.boot.configurationprocessor.json.JSONObject;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\n\n/**\n * Converter to change meta-data objects into JSON objects.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass JsonConverter {\n\n\tprivate static final ItemMetadataComparator ITEM_COMPARATOR = new ItemMetadataComparator();\n\n\tJSONArray toJsonArray(ConfigurationMetadata metadata, ItemType itemType) throws Exception {\n\t\tJSONArray jsonArray = new JSONArray();\n\t\tList<ItemMetadata> items = metadata.getItems()\n\t\t\t.stream()\n\t\t\t.filter((item) -> item.isOfItemType(itemType))\n\t\t\t.sorted(ITEM_COMPARATOR)\n\t\t\t.toList();\n\t\tfor (ItemMetadata item : items) {\n\t\t\tif (item.isOfItemType(itemType)) {\n\t\t\t\tjsonArray.put(toJsonObject(item));\n\t\t\t}\n\t\t}\n\t\treturn jsonArray;\n\t}\n\n\tJSONArray toJsonArray(Collection<ItemHint> hints) throws Exception {\n\t\tJSONArray jsonArray = new JSONArray();\n\t\tfor (ItemHint hint : hints) {\n\t\t\tjsonArray.put(toJsonObject(hint));\n\t\t}\n\t\treturn jsonArray;\n\t}\n\n\tJSONObject toJsonObject(Collection<ItemIgnore> ignored) throws Exception {\n\t\tJSONObject result = new JSONObject();\n\t\tresult.put(\"properties\", ignoreToJsonArray(\n\t\t\t\tignored.stream().filter((itemIgnore) -> itemIgnore.getType() == ItemType.PROPERTY).toList()));\n\t\treturn result;\n\t}\n\n\tprivate JSONArray ignoreToJsonArray(Collection<ItemIgnore> ignored) throws Exception {\n\t\tJSONArray result = new JSONArray();\n\t\tfor (ItemIgnore itemIgnore : ignored) {\n\t\t\tresult.put(toJsonObject(itemIgnore));\n\t\t}\n\t\treturn result;\n\t}\n\n\tJSONObject toJsonObject(ItemMetadata item) throws Exception {\n\t\tJSONObject jsonObject = new JSONObject();\n\t\tjsonObject.put(\"name\", item.getName());\n\t\tjsonObject.putOpt(\"type\", item.getType());\n\t\tjsonObject.putOpt(\"description\", item.getDescription());\n\t\tjsonObject.putOpt(\"sourceType\", item.getSourceType());\n\t\tjsonObject.putOpt(\"sourceMethod\", item.getSourceMethod());\n\t\tObject defaultValue = item.getDefaultValue();\n\t\tif (defaultValue != null) {\n\t\t\tputDefaultValue(jsonObject, defaultValue);\n\t\t}\n\t\tItemDeprecation deprecation = item.getDeprecation();\n\t\tif (deprecation != null) {\n\t\t\tjsonObject.put(\"deprecated\", true); // backward compatibility\n\t\t\tJSONObject deprecationJsonObject = new JSONObject();\n\t\t\tif (deprecation.getLevel() != null) {\n\t\t\t\tdeprecationJsonObject.put(\"level\", deprecation.getLevel());\n\t\t\t}\n\t\t\tif (deprecation.getReason() != null) {\n\t\t\t\tdeprecationJsonObject.put(\"reason\", deprecation.getReason());\n\t\t\t}\n\t\t\tif (deprecation.getReplacement() != null) {\n\t\t\t\tdeprecationJsonObject.put(\"replacement\", deprecation.getReplacement());\n\t\t\t}\n\t\t\tif (deprecation.getSince() != null) {\n\t\t\t\tdeprecationJsonObject.put(\"since\", deprecation.getSince());\n\t\t\t}\n\t\t\tjsonObject.put(\"deprecation\", deprecationJsonObject);\n\t\t}\n\t\treturn jsonObject;\n\t}\n\n\tprivate JSONObject toJsonObject(ItemHint hint) throws Exception {\n\t\tJSONObject jsonObject = new JSONObject();\n\t\tjsonObject.put(\"name\", hint.getName());\n\t\tif (!hint.getValues().isEmpty()) {\n\t\t\tjsonObject.put(\"values\", getItemHintValues(hint));\n\t\t}\n\t\tif (!hint.getProviders().isEmpty()) {\n\t\t\tjsonObject.put(\"providers\", getItemHintProviders(hint));\n\t\t}\n\t\treturn jsonObject;\n\t}\n\n\tprivate JSONObject toJsonObject(ItemIgnore ignore) throws Exception {\n\t\tJSONObject jsonObject = new JSONObject();\n\t\tjsonObject.put(\"name\", ignore.getName());\n\t\treturn jsonObject;\n\t}\n\n\tprivate JSONArray getItemHintValues(ItemHint hint) throws Exception {\n\t\tJSONArray values = new JSONArray();\n\t\tfor (ItemHint.ValueHint value : hint.getValues()) {\n\t\t\tvalues.put(getItemHintValue(value));\n\t\t}\n\t\treturn values;\n\t}\n\n\tprivate JSONObject getItemHintValue(ItemHint.ValueHint value) throws Exception {\n\t\tJSONObject result = new JSONObject();\n\t\tputHintValue(result, value.getValue());\n\t\tresult.putOpt(\"description\", value.getDescription());\n\t\treturn result;\n\t}\n\n\tprivate JSONArray getItemHintProviders(ItemHint hint) throws Exception {\n\t\tJSONArray providers = new JSONArray();\n\t\tfor (ItemHint.ValueProvider provider : hint.getProviders()) {\n\t\t\tproviders.put(getItemHintProvider(provider));\n\t\t}\n\t\treturn providers;\n\t}\n\n\tprivate JSONObject getItemHintProvider(ItemHint.ValueProvider provider) throws Exception {\n\t\tJSONObject result = new JSONObject();\n\t\tresult.put(\"name\", provider.getName());\n\t\tif (provider.getParameters() != null && !provider.getParameters().isEmpty()) {\n\t\t\tJSONObject parameters = new JSONObject();\n\t\t\tfor (Map.Entry<String, Object> entry : provider.getParameters().entrySet()) {\n\t\t\t\tparameters.put(entry.getKey(), extractItemValue(entry.getValue()));\n\t\t\t}\n\t\t\tresult.put(\"parameters\", parameters);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate void putHintValue(JSONObject jsonObject, Object value) throws Exception {\n\t\tObject hintValue = extractItemValue(value);\n\t\tjsonObject.put(\"value\", hintValue);\n\t}\n\n\tprivate void putDefaultValue(JSONObject jsonObject, Object value) throws Exception {\n\t\tObject defaultValue = extractItemValue(value);\n\t\tjsonObject.put(\"defaultValue\", defaultValue);\n\t}\n\n\tprivate Object extractItemValue(Object value) {\n\t\tObject defaultValue = value;\n\t\tif (value.getClass().isArray()) {\n\t\t\tJSONArray array = new JSONArray();\n\t\t\tint length = Array.getLength(value);\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tarray.put(Array.get(value, i));\n\t\t\t}\n\t\t\tdefaultValue = array;\n\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n\tprivate static final class ItemMetadataComparator implements Comparator<ItemMetadata> {\n\n\t\tprivate static final Comparator<ItemMetadata> GROUP = Comparator.comparing(ItemMetadata::getName)\n\t\t\t.thenComparing(ItemMetadata::getSourceType, Comparator.nullsFirst(Comparator.naturalOrder()));\n\n\t\tprivate static final Comparator<ItemMetadata> ITEM = Comparator.comparing(ItemMetadataComparator::isDeprecated)\n\t\t\t.thenComparing(ItemMetadata::getName)\n\t\t\t.thenComparing(ItemMetadata::getSourceType, Comparator.nullsFirst(Comparator.naturalOrder()));\n\n\t\t@Override\n\t\tpublic int compare(ItemMetadata o1, ItemMetadata o2) {\n\t\t\tif (o1.isOfItemType(ItemType.GROUP)) {\n\t\t\t\treturn GROUP.compare(o1, o2);\n\t\t\t}\n\t\t\treturn ITEM.compare(o1, o2);\n\t\t}\n\n\t\tprivate static boolean isDeprecated(ItemMetadata item) {\n\t\t\treturn item.getDeprecation() != null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshaller.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.springframework.boot.configurationprocessor.json.JSONArray;\nimport org.springframework.boot.configurationprocessor.json.JSONException;\nimport org.springframework.boot.configurationprocessor.json.JSONObject;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\n\n/**\n * Marshaller to read and write {@link ConfigurationMetadata} as JSON.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 1.2.0\n */\npublic class JsonMarshaller {\n\n\tpublic void write(ConfigurationMetadata metadata, OutputStream outputStream) throws IOException {\n\t\ttry {\n\t\t\tJSONObject object = new JSONObject();\n\t\t\tJsonConverter converter = new JsonConverter();\n\t\t\tobject.put(\"groups\", converter.toJsonArray(metadata, ItemType.GROUP));\n\t\t\tobject.put(\"properties\", converter.toJsonArray(metadata, ItemType.PROPERTY));\n\t\t\tobject.put(\"hints\", converter.toJsonArray(metadata.getHints()));\n\t\t\tobject.put(\"ignored\", converter.toJsonObject(metadata.getIgnored()));\n\t\t\toutputStream.write(object.toString(2).getBytes(StandardCharsets.UTF_8));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof IOException ioException) {\n\t\t\t\tthrow ioException;\n\t\t\t}\n\t\t\tif (ex instanceof RuntimeException runtimeException) {\n\t\t\t\tthrow runtimeException;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tpublic ConfigurationMetadata read(InputStream inputStream) throws Exception {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tJSONObject object = new JSONObject(toString(inputStream));\n\t\tJsonPath path = JsonPath.root();\n\t\tcheckAllowedKeys(object, path, \"groups\", \"properties\", \"hints\", \"ignored\");\n\t\tJSONArray groups = object.optJSONArray(\"groups\");\n\t\tif (groups != null) {\n\t\t\tfor (int i = 0; i < groups.length(); i++) {\n\t\t\t\tmetadata\n\t\t\t\t\t.add(toItemMetadata((JSONObject) groups.get(i), path.resolve(\"groups\").index(i), ItemType.GROUP));\n\t\t\t}\n\t\t}\n\t\tJSONArray properties = object.optJSONArray(\"properties\");\n\t\tif (properties != null) {\n\t\t\tfor (int i = 0; i < properties.length(); i++) {\n\t\t\t\tmetadata.add(toItemMetadata((JSONObject) properties.get(i), path.resolve(\"properties\").index(i),\n\t\t\t\t\t\tItemType.PROPERTY));\n\t\t\t}\n\t\t}\n\t\tJSONArray hints = object.optJSONArray(\"hints\");\n\t\tif (hints != null) {\n\t\t\tfor (int i = 0; i < hints.length(); i++) {\n\t\t\t\tmetadata.add(toItemHint((JSONObject) hints.get(i), path.resolve(\"hints\").index(i)));\n\t\t\t}\n\t\t}\n\t\tJSONObject ignored = object.optJSONObject(\"ignored\");\n\t\tif (ignored != null) {\n\t\t\tJsonPath ignoredPath = path.resolve(\"ignored\");\n\t\t\tcheckAllowedKeys(ignored, ignoredPath, \"properties\");\n\t\t\taddIgnoredProperties(metadata, ignored, ignoredPath);\n\t\t}\n\t\treturn metadata;\n\t}\n\n\tprivate void addIgnoredProperties(ConfigurationMetadata metadata, JSONObject ignored, JsonPath path)\n\t\t\tthrows JSONException {\n\t\tJSONArray properties = ignored.optJSONArray(\"properties\");\n\t\tif (properties == null) {\n\t\t\treturn;\n\t\t}\n\t\tfor (int i = 0; i < properties.length(); i++) {\n\t\t\tJSONObject jsonObject = properties.getJSONObject(i);\n\t\t\tcheckAllowedKeys(jsonObject, path.resolve(\"properties\").index(i), \"name\");\n\t\t\tmetadata.add(ItemIgnore.forProperty(jsonObject.getString(\"name\")));\n\t\t}\n\t}\n\n\tprivate ItemMetadata toItemMetadata(JSONObject object, JsonPath path, ItemType itemType) throws Exception {\n\t\tswitch (itemType) {\n\t\t\tcase GROUP -> checkAllowedKeys(object, path, \"name\", \"type\", \"description\", \"sourceType\", \"sourceMethod\");\n\t\t\tcase PROPERTY -> checkAllowedKeys(object, path, \"name\", \"type\", \"description\", \"sourceType\", \"defaultValue\",\n\t\t\t\t\t\"deprecation\", \"deprecated\");\n\t\t}\n\t\tString name = object.getString(\"name\");\n\t\tString type = object.optString(\"type\", null);\n\t\tString description = object.optString(\"description\", null);\n\t\tString sourceType = object.optString(\"sourceType\", null);\n\t\tString sourceMethod = object.optString(\"sourceMethod\", null);\n\t\tObject defaultValue = readItemValue(object.opt(\"defaultValue\"));\n\t\tItemDeprecation deprecation = toItemDeprecation(object, path);\n\t\treturn new ItemMetadata(itemType, name, null, type, sourceType, sourceMethod, description, defaultValue,\n\t\t\t\tdeprecation);\n\t}\n\n\tprivate ItemDeprecation toItemDeprecation(JSONObject object, JsonPath path) throws Exception {\n\t\tif (object.has(\"deprecation\")) {\n\t\t\tJSONObject deprecationJsonObject = object.getJSONObject(\"deprecation\");\n\t\t\tcheckAllowedKeys(deprecationJsonObject, path.resolve(\"deprecation\"), \"level\", \"reason\", \"replacement\",\n\t\t\t\t\t\"since\");\n\t\t\tItemDeprecation deprecation = new ItemDeprecation();\n\t\t\tdeprecation.setLevel(deprecationJsonObject.optString(\"level\", null));\n\t\t\tdeprecation.setReason(deprecationJsonObject.optString(\"reason\", null));\n\t\t\tdeprecation.setReplacement(deprecationJsonObject.optString(\"replacement\", null));\n\t\t\tdeprecation.setSince(deprecationJsonObject.optString(\"since\", null));\n\t\t\treturn deprecation;\n\t\t}\n\t\treturn object.optBoolean(\"deprecated\") ? new ItemDeprecation() : null;\n\t}\n\n\tprivate ItemHint toItemHint(JSONObject object, JsonPath path) throws Exception {\n\t\tcheckAllowedKeys(object, path, \"name\", \"values\", \"providers\");\n\t\tString name = object.getString(\"name\");\n\t\tList<ItemHint.ValueHint> values = new ArrayList<>();\n\t\tif (object.has(\"values\")) {\n\t\t\tJSONArray valuesArray = object.getJSONArray(\"values\");\n\t\t\tfor (int i = 0; i < valuesArray.length(); i++) {\n\t\t\t\tvalues.add(toValueHint((JSONObject) valuesArray.get(i), path.resolve(\"values\").index(i)));\n\t\t\t}\n\t\t}\n\t\tList<ItemHint.ValueProvider> providers = new ArrayList<>();\n\t\tif (object.has(\"providers\")) {\n\t\t\tJSONArray providersObject = object.getJSONArray(\"providers\");\n\t\t\tfor (int i = 0; i < providersObject.length(); i++) {\n\t\t\t\tproviders.add(toValueProvider((JSONObject) providersObject.get(i), path.resolve(\"providers\").index(i)));\n\t\t\t}\n\t\t}\n\t\treturn new ItemHint(name, values, providers);\n\t}\n\n\tprivate ItemHint.ValueHint toValueHint(JSONObject object, JsonPath path) throws Exception {\n\t\tcheckAllowedKeys(object, path, \"value\", \"description\");\n\t\tObject value = readItemValue(object.get(\"value\"));\n\t\tString description = object.optString(\"description\", null);\n\t\treturn new ItemHint.ValueHint(value, description);\n\t}\n\n\tprivate ItemHint.ValueProvider toValueProvider(JSONObject object, JsonPath path) throws Exception {\n\t\tcheckAllowedKeys(object, path, \"name\", \"parameters\");\n\t\tString name = object.getString(\"name\");\n\t\tMap<String, Object> parameters = new HashMap<>();\n\t\tif (object.has(\"parameters\")) {\n\t\t\tJSONObject parametersObject = object.getJSONObject(\"parameters\");\n\t\t\tfor (Iterator<?> iterator = parametersObject.keys(); iterator.hasNext();) {\n\t\t\t\tString key = (String) iterator.next();\n\t\t\t\tObject value = readItemValue(parametersObject.get(key));\n\t\t\t\tparameters.put(key, value);\n\t\t\t}\n\t\t}\n\t\treturn new ItemHint.ValueProvider(name, parameters);\n\t}\n\n\tprivate Object readItemValue(Object value) throws Exception {\n\t\tif (value instanceof JSONArray array) {\n\t\t\tObject[] content = new Object[array.length()];\n\t\t\tfor (int i = 0; i < array.length(); i++) {\n\t\t\t\tcontent[i] = array.get(i);\n\t\t\t}\n\t\t\treturn content;\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate String toString(InputStream inputStream) throws IOException {\n\t\treturn new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void checkAllowedKeys(JSONObject object, JsonPath path, String... allowedKeys) {\n\t\tSet<String> availableKeys = new TreeSet<>();\n\t\tobject.keys().forEachRemaining((key) -> availableKeys.add((String) key));\n\t\tArrays.stream(allowedKeys).forEach(availableKeys::remove);\n\t\tif (!availableKeys.isEmpty()) {\n\t\t\tthrow new IllegalStateException(\"Expected only keys %s, but found additional keys %s. Path: %s\"\n\t\t\t\t.formatted(new TreeSet<>(Arrays.asList(allowedKeys)), availableKeys, path));\n\t\t}\n\t}\n\n\tprivate static final class JsonPath {\n\n\t\tprivate final String path;\n\n\t\tprivate JsonPath(String path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tJsonPath resolve(String path) {\n\t\t\tif (this.path.endsWith(\".\")) {\n\t\t\t\treturn new JsonPath(this.path + path);\n\t\t\t}\n\t\t\treturn new JsonPath(this.path + \".\" + path);\n\t\t}\n\n\t\tJsonPath index(int index) {\n\t\t\treturn resolve(\"[%d]\".formatted(index));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.path;\n\t\t}\n\n\t\tstatic JsonPath root() {\n\t\t\treturn new JsonPath(\".\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/metadata/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The configuration properties meta-data model and JSON writing support.\n */\npackage org.springframework.boot.configurationprocessor.metadata;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Annotation processor to create {@code @ConfigurationProperties} meta-data files.\n */\npackage org.springframework.boot.configurationprocessor;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/support/ConventionUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.support;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\n\n/**\n * Convention utilities.\n *\n * @author Stephane Nicoll\n * @since 3.4.0\n */\npublic abstract class ConventionUtils {\n\n\tprivate static final Set<Character> SEPARATORS;\n\n\tstatic {\n\t\tList<Character> chars = Arrays.asList('-', '_');\n\t\tSEPARATORS = Collections.unmodifiableSet(new HashSet<>(chars));\n\t}\n\n\t/**\n\t * Return the idiomatic metadata format for the given {@code value}.\n\t * @param value a value\n\t * @return the idiomatic format for the value, or the value itself if it already\n\t * complies with the idiomatic metadata format.\n\t */\n\tpublic static String toDashedCase(String value) {\n\t\tStringBuilder dashed = new StringBuilder();\n\t\tCharacter previous = null;\n\t\tfor (int i = 0; i < value.length(); i++) {\n\t\t\tchar current = value.charAt(i);\n\t\t\tif (SEPARATORS.contains(current)) {\n\t\t\t\tdashed.append(\"-\");\n\t\t\t}\n\t\t\telse if (Character.isUpperCase(current) && previous != null && !SEPARATORS.contains(previous)) {\n\t\t\t\tdashed.append(\"-\").append(current);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdashed.append(current);\n\t\t\t}\n\t\t\tprevious = current;\n\n\t\t}\n\t\treturn dashed.toString().toLowerCase(Locale.ENGLISH);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/support/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for configuration metadata processing.\n */\npackage org.springframework.boot.configurationprocessor.support;\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/resources/META-INF/gradle/incremental.annotation.processors",
    "content": "org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor,aggregating"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor",
    "content": "org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/AbstractMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.test.CompiledMetadataReader;\nimport org.springframework.boot.configurationprocessor.test.TestConfigurationMetadataAnnotationProcessor;\nimport org.springframework.core.test.tools.ResourceFile;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\n/**\n * Base test infrastructure for metadata generation tests.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\npublic abstract class AbstractMetadataGenerationTests {\n\n\tprivate static final String ADDITIONAL_METADATA_FILE = \"META-INF/additional-spring-configuration-metadata.json\";\n\n\tprotected ConfigurationMetadata compile(Class<?>... types) {\n\t\tTestCompiler compiler = TestCompiler.forSystem().withSources(sourceFilesOf(types));\n\t\treturn compile(compiler);\n\t}\n\n\tprotected ConfigurationMetadata compile(String additionalMetadata, Class<?> type, Class<?>... types) {\n\t\tTestCompiler compiler = TestCompiler.forSystem()\n\t\t\t.withSources(sourceFilesOf(type))\n\t\t\t.withSources(sourceFilesOf(types))\n\t\t\t.withResources(ResourceFile.of(ADDITIONAL_METADATA_FILE, additionalMetadata));\n\t\treturn compile(compiler);\n\t}\n\n\tprotected ConfigurationMetadata compile(String... source) {\n\t\tTestCompiler compiler = TestCompiler.forSystem().withSources(sourceFilesOf(source));\n\t\treturn compile(compiler);\n\t}\n\n\tprivate ConfigurationMetadata compile(TestCompiler compiler) {\n\t\tTestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor();\n\t\tcompiler = compiler.withProcessors(processor);\n\t\tAtomicReference<ConfigurationMetadata> configurationMetadata = new AtomicReference<>();\n\t\tcompiler.compile((compiled) -> configurationMetadata.set(CompiledMetadataReader.getMetadata(compiled)));\n\t\treturn configurationMetadata.get();\n\t}\n\n\tprivate List<SourceFile> sourceFilesOf(Class<?>... types) {\n\t\treturn Arrays.stream(types).map(SourceFile::forTestClass).toList();\n\t}\n\n\tprivate List<SourceFile> sourceFilesOf(String... content) {\n\t\treturn Arrays.stream(content).map(SourceFile::of).toList();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.time.temporal.ChronoField;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Arrays;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemIgnore;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationprocessor.test.CompiledMetadataReader;\nimport org.springframework.boot.configurationprocessor.test.TestConfigurationMetadataAnnotationProcessor;\nimport org.springframework.boot.configurationsample.deprecation.Dbcp2Configuration;\nimport org.springframework.boot.configurationsample.method.NestedPropertiesMethod;\nimport org.springframework.boot.configurationsample.method.NestedPropertiesMethodImmutable;\nimport org.springframework.boot.configurationsample.record.ExampleRecord;\nimport org.springframework.boot.configurationsample.record.NestedPropertiesRecord;\nimport org.springframework.boot.configurationsample.record.RecordWithGetter;\nimport org.springframework.boot.configurationsample.recursive.RecursiveProperties;\nimport org.springframework.boot.configurationsample.simple.ClassWithNestedProperties;\nimport org.springframework.boot.configurationsample.simple.DeprecatedFieldSingleProperty;\nimport org.springframework.boot.configurationsample.simple.DeprecatedRecord;\nimport org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty;\nimport org.springframework.boot.configurationsample.simple.DescriptionProperties;\nimport org.springframework.boot.configurationsample.simple.HierarchicalProperties;\nimport org.springframework.boot.configurationsample.simple.HierarchicalPropertiesGrandparent;\nimport org.springframework.boot.configurationsample.simple.HierarchicalPropertiesParent;\nimport org.springframework.boot.configurationsample.simple.IgnoredProperties;\nimport org.springframework.boot.configurationsample.simple.InnerClassWithPrivateConstructor;\nimport org.springframework.boot.configurationsample.simple.NotAnnotated;\nimport org.springframework.boot.configurationsample.simple.SimpleArrayProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleCollectionProperties;\nimport org.springframework.boot.configurationsample.simple.SimplePrefixValueProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleTypeProperties;\nimport org.springframework.boot.configurationsample.source.ConcreteProperties;\nimport org.springframework.boot.configurationsample.source.ConcreteSource;\nimport org.springframework.boot.configurationsample.source.ConcreteSourceAnnotated;\nimport org.springframework.boot.configurationsample.source.ConventionSource;\nimport org.springframework.boot.configurationsample.source.ConventionSourceAnnotated;\nimport org.springframework.boot.configurationsample.source.ImmutableSource;\nimport org.springframework.boot.configurationsample.source.ImmutableSourceAnnotated;\nimport org.springframework.boot.configurationsample.source.LombokSource;\nimport org.springframework.boot.configurationsample.source.LombokSourceAnnotated;\nimport org.springframework.boot.configurationsample.source.ParentWithHintProperties;\nimport org.springframework.boot.configurationsample.source.RecordSource;\nimport org.springframework.boot.configurationsample.source.RecordSourceAnnotated;\nimport org.springframework.boot.configurationsample.source.SimpleSource;\nimport org.springframework.boot.configurationsample.source.SimpleSourceAnnotated;\nimport org.springframework.boot.configurationsample.source.generation.AbstractPropertiesSource;\nimport org.springframework.boot.configurationsample.source.generation.ConfigurationPropertySourcesContainer;\nimport org.springframework.boot.configurationsample.source.generation.ConfigurationPropertySourcesContainer.First;\nimport org.springframework.boot.configurationsample.source.generation.ConfigurationPropertySourcesContainer.Second;\nimport org.springframework.boot.configurationsample.source.generation.ConfigurationPropertySourcesContainer.Third;\nimport org.springframework.boot.configurationsample.source.generation.ImmutablePropertiesSource;\nimport org.springframework.boot.configurationsample.source.generation.LombokPropertiesSource;\nimport org.springframework.boot.configurationsample.source.generation.NestedPropertiesSource;\nimport org.springframework.boot.configurationsample.source.generation.RecordPropertiesSources;\nimport org.springframework.boot.configurationsample.source.generation.SimplePropertiesSource;\nimport org.springframework.boot.configurationsample.specific.AnnotatedGetter;\nimport org.springframework.boot.configurationsample.specific.BoxingPojo;\nimport org.springframework.boot.configurationsample.specific.BuilderPojo;\nimport org.springframework.boot.configurationsample.specific.DeprecatedLessPreciseTypePojo;\nimport org.springframework.boot.configurationsample.specific.DeprecatedSimplePojo;\nimport org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo;\nimport org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties;\nimport org.springframework.boot.configurationsample.specific.EmptyDefaultValueProperties;\nimport org.springframework.boot.configurationsample.specific.EnumValuesPojo;\nimport org.springframework.boot.configurationsample.specific.ExcludedTypesPojo;\nimport org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig;\nimport org.springframework.boot.configurationsample.specific.InnerClassHierarchicalProperties;\nimport org.springframework.boot.configurationsample.specific.InnerClassProperties;\nimport org.springframework.boot.configurationsample.specific.InnerClassRootConfig;\nimport org.springframework.boot.configurationsample.specific.InvalidAccessorProperties;\nimport org.springframework.boot.configurationsample.specific.InvalidDefaultValueCharacterProperties;\nimport org.springframework.boot.configurationsample.specific.InvalidDefaultValueFloatingPointProperties;\nimport org.springframework.boot.configurationsample.specific.InvalidDefaultValueNumberProperties;\nimport org.springframework.boot.configurationsample.specific.InvalidDoubleRegistrationProperties;\nimport org.springframework.boot.configurationsample.specific.SimplePojo;\nimport org.springframework.boot.configurationsample.specific.StaticAccessor;\nimport org.springframework.core.test.tools.CompilationException;\nimport org.springframework.core.test.tools.Compiled;\nimport org.springframework.core.test.tools.ResourceFile;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ConfigurationMetadataAnnotationProcessor}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Kris De Volder\n * @author Jonas Keßler\n * @author Pavel Anisimov\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass ConfigurationMetadataAnnotationProcessorTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid supportedAnnotations() {\n\t\tassertThat(new ConfigurationMetadataAnnotationProcessor().getSupportedAnnotationTypes())\n\t\t\t.containsExactlyInAnyOrder(\"org.springframework.boot.autoconfigure.AutoConfiguration\",\n\t\t\t\t\t\"org.springframework.boot.context.properties.ConfigurationProperties\",\n\t\t\t\t\t\"org.springframework.boot.context.properties.ConfigurationPropertiesSource\",\n\t\t\t\t\t\"org.springframework.context.annotation.Configuration\",\n\t\t\t\t\t\"org.springframework.boot.actuate.endpoint.annotation.Endpoint\",\n\t\t\t\t\t\"org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint\",\n\t\t\t\t\t\"org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint\",\n\t\t\t\t\t\"org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint\",\n\t\t\t\t\t\"org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint\",\n\t\t\t\t\t\"org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint\");\n\t}\n\n\t@Test\n\tvoid notAnnotated() {\n\t\tConfigurationMetadata metadata = compile(NotAnnotated.class);\n\t\tassertThat(metadata).isNull();\n\t}\n\n\t@Test\n\tvoid simpleProperties() {\n\t\tConfigurationMetadata metadata = compile(SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"simple\").fromSource(SimpleProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.the-name\", String.class)\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"The name of this simple properties.\")\n\t\t\t.withDefaultValue(\"boot\")\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"A simple flag.\")\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.comparator\"));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"simple.counter\"));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"simple.size\"));\n\t}\n\n\t@Test\n\tvoid simplePrefixValueProperties() {\n\t\tConfigurationMetadata metadata = compile(SimplePrefixValueProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"simple\").fromSource(SimplePrefixValueProperties.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"simple.name\", String.class).fromSource(SimplePrefixValueProperties.class));\n\t}\n\n\t@Test\n\tvoid simpleTypeProperties() {\n\t\tConfigurationMetadata metadata = compile(SimpleTypeProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"simple.type\").fromSource(SimpleTypeProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-string\", String.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-byte\", Byte.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"simple.type.my-primitive-byte\", Byte.class).withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-char\", Character.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-primitive-char\", Character.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-boolean\", Boolean.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"simple.type.my-primitive-boolean\", Boolean.class).withDefaultValue(false));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-short\", Short.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"simple.type.my-primitive-short\", Short.class).withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-integer\", Integer.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"simple.type.my-primitive-integer\", Integer.class).withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-long\", Long.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"simple.type.my-primitive-long\", Long.class).withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-double\", Double.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-primitive-double\", Double.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-float\", Float.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.type.my-primitive-float\", Float.class));\n\t\tassertThat(metadata.getItems()).hasSize(18);\n\t}\n\n\t@Test\n\tvoid hierarchicalProperties() {\n\t\tConfigurationMetadata metadata = compile(HierarchicalProperties.class, HierarchicalPropertiesParent.class,\n\t\t\t\tHierarchicalPropertiesGrandparent.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"hierarchical\").fromSource(HierarchicalProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"hierarchical.first\", String.class)\n\t\t\t.withDefaultValue(\"one\")\n\t\t\t.fromSource(HierarchicalProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"hierarchical.second\", String.class)\n\t\t\t.withDefaultValue(\"two\")\n\t\t\t.fromSource(HierarchicalProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"hierarchical.third\", String.class)\n\t\t\t.withDefaultValue(\"three\")\n\t\t\t.fromSource(HierarchicalProperties.class));\n\t}\n\n\t@Test\n\tvoid enumValues() {\n\t\tConfigurationMetadata metadata = compile(EnumValuesPojo.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"test\").fromSource(EnumValuesPojo.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"test.seconds\", ChronoUnit.class).withDefaultValue(\"seconds\"));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"test.hour-of-day\", ChronoField.class).withDefaultValue(\"hour-of-day\"));\n\t}\n\n\t@Test\n\tvoid descriptionProperties() {\n\t\tConfigurationMetadata metadata = compile(DescriptionProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"description\").fromSource(DescriptionProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"description.simple\", String.class)\n\t\t\t.fromSource(DescriptionProperties.class)\n\t\t\t.withDescription(\"A simple description.\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"description.multi-line\", String.class)\n\t\t\t.fromSource(DescriptionProperties.class)\n\t\t\t.withDescription(\n\t\t\t\t\t\"This is a lengthy description that spans across multiple lines to showcase that the line separators are cleaned automatically.\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"description.multi-line-whitespace\", String.class)\n\t\t\t.fromSource(DescriptionProperties.class)\n\t\t\t.withDescription(\"This is an example of a description with unusual whitespace after a new line.\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"deprecation\")\n\tvoid deprecatedProperties() {\n\t\tClass<?> type = org.springframework.boot.configurationsample.simple.DeprecatedProperties.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"deprecated\").fromSource(type));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"deprecated.name\", String.class).fromSource(type).withDeprecation());\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"deprecated.description\", String.class).fromSource(type).withDeprecation());\n\t}\n\n\t@Test\n\tvoid singleDeprecatedProperty() {\n\t\tClass<?> type = DeprecatedSingleProperty.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"singledeprecated\").fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"singledeprecated.new-name\", String.class).fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"singledeprecated.name\", String.class)\n\t\t\t.fromSource(type)\n\t\t\t.withDeprecation(\"renamed\", \"singledeprecated.new-name\", \"1.2.3\"));\n\t}\n\n\t@Test\n\tvoid singleDeprecatedFieldProperty() {\n\t\tClass<?> type = DeprecatedFieldSingleProperty.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"singlefielddeprecated\").fromSource(type));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"singlefielddeprecated.name\", String.class).fromSource(type).withDeprecation());\n\t}\n\n\t@Test\n\tvoid deprecatedOnUnrelatedSetter() {\n\t\tClass<?> type = DeprecatedUnrelatedMethodPojo.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"not.deprecated\").fromSource(type));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"not.deprecated.counter\", Integer.class).withNoDeprecation().fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"not.deprecated.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.withNoDeprecation()\n\t\t\t.fromSource(type));\n\t}\n\n\t@Test\n\tvoid deprecatedWithLessPreciseType() {\n\t\tClass<?> type = DeprecatedLessPreciseTypePojo.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"not.deprecated\").fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"not.deprecated.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.withNoDeprecation()\n\t\t\t.fromSource(type));\n\t}\n\n\t@Test\n\tvoid deprecatedPropertyOnRecord() {\n\t\tClass<?> type = DeprecatedRecord.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"deprecated-record\").fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"deprecated-record.alpha\", String.class)\n\t\t\t.fromSource(type)\n\t\t\t.withDeprecation(\"some-reason\", null, null));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"deprecated-record.bravo\", String.class).fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"deprecated-record.named.charlie\", String.class)\n\t\t\t.fromSource(type)\n\t\t\t.withDeprecation(\"another-reason\", null, null));\n\t}\n\n\t@Test\n\tvoid typBoxing() {\n\t\tClass<?> type = BoxingPojo.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"boxing\").fromSource(type));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"boxing.flag\", Boolean.class).withDefaultValue(false).fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"boxing.another-flag\", Boolean.class).fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"boxing.counter\", Integer.class).fromSource(type));\n\t}\n\n\t@Test\n\tvoid parseCollectionConfig() {\n\t\tConfigurationMetadata metadata = compile(SimpleCollectionProperties.class);\n\t\t// getter and setter\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.integers-to-names\",\n\t\t\t\t\"java.util.Map<java.lang.Integer,java.lang.String>\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.longs\", \"java.util.Collection<java.lang.Long>\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.floats\", \"java.util.List<java.lang.Float>\"));\n\t\t// getter only\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.names-to-integers\",\n\t\t\t\t\"java.util.Map<java.lang.String,java.lang.Integer>\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.bytes\", \"java.util.Collection<java.lang.Byte>\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.doubles\", \"java.util.List<java.lang.Double>\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"collection.names-to-holders\",\n\t\t\t\t\"java.util.Map<java.lang.String,org.springframework.boot.configurationsample.simple.SimpleCollectionProperties$Holder<java.lang.String>>\"));\n\t}\n\n\t@Test\n\tvoid parseArrayConfig() {\n\t\tConfigurationMetadata metadata = compile(SimpleArrayProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"array\").ofType(SimpleArrayProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"array.primitive\", \"java.lang.Integer[]\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"array.simple\", \"java.lang.String[]\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"array.inner\",\n\t\t\t\t\"org.springframework.boot.configurationsample.simple.SimpleArrayProperties$Holder[]\"));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"array.name-to-integer\", \"java.util.Map<java.lang.String,java.lang.Integer>[]\"));\n\t\tassertThat(metadata.getItems()).hasSize(5);\n\t}\n\n\t@Test\n\tvoid annotatedGetter() {\n\t\tConfigurationMetadata metadata = compile(AnnotatedGetter.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"specific\").fromSource(AnnotatedGetter.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"specific.name\", String.class).fromSource(AnnotatedGetter.class));\n\t}\n\n\t@Test\n\tvoid staticAccessor() {\n\t\tConfigurationMetadata metadata = compile(StaticAccessor.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"specific\").fromSource(StaticAccessor.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"specific.counter\", Integer.class)\n\t\t\t.fromSource(StaticAccessor.class)\n\t\t\t.withDefaultValue(42));\n\t\tassertThat(metadata)\n\t\t\t.doesNotHave(Metadata.withProperty(\"specific.name\", String.class).fromSource(StaticAccessor.class));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid innerClassRootConfig() {\n\t\tConfigurationMetadata metadata = compile(InnerClassRootConfig.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.name\"));\n\t}\n\n\t@Test\n\tvoid innerClassProperties() {\n\t\tConfigurationMetadata metadata = compile(InnerClassProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config\").fromSource(InnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.first\")\n\t\t\t.ofType(InnerClassProperties.Foo.class)\n\t\t\t.fromSource(InnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.first.name\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.first.bar.name\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.the-second\", InnerClassProperties.Foo.class)\n\t\t\t.fromSource(InnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.the-second.name\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.the-second.bar.name\"));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"config.third\").ofType(SimplePojo.class).fromSource(InnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.third.value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.fourth\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withGroup(\"config.fourth\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.fifth\")\n\t\t\t.ofType(DeprecatedSimplePojo.class)\n\t\t\t.fromSource(InnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.fifth.value\").withDeprecation());\n\t}\n\n\t@Test\n\tvoid innerClassPropertiesHierarchical() {\n\t\tConfigurationMetadata metadata = compile(InnerClassHierarchicalProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.foo\").ofType(InnerClassHierarchicalProperties.Foo.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"config.foo.bar\").ofType(InnerClassHierarchicalProperties.Bar.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"config.foo.bar.baz\").ofType(InnerClassHierarchicalProperties.Foo.Baz.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.foo.bar.baz.blah\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.foo.bar.bling\"));\n\t}\n\n\t@Test\n\tvoid innerClassAnnotatedGetterConfig() {\n\t\tConfigurationMetadata metadata = compile(InnerClassAnnotatedGetterConfig.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"specific.value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.name\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"specific.foo\"));\n\t}\n\n\t@Test\n\tvoid nestedClassMethod() {\n\t\tConfigurationMetadata metadata = compile(NestedPropertiesMethod.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"method-nested.nested\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"method-nested.nested.my-nested-property\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"method-nested.inner.nested\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"method-nested.inner.nested.my-nested-property\"));\n\t}\n\n\t@Test\n\tvoid nestedClassMethodImmutable() {\n\t\tConfigurationMetadata metadata = compile(NestedPropertiesMethodImmutable.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"immutable-nested.nested\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"immutable-nested.nested.my-nested-property\"));\n\t}\n\n\t@Test\n\tvoid nestedClassChildProperties() {\n\t\tConfigurationMetadata metadata = compile(ClassWithNestedProperties.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"nestedChildProps\").fromSource(ClassWithNestedProperties.NestedChildClass.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"nestedChildProps.child-class-property\", Integer.class)\n\t\t\t.fromSource(ClassWithNestedProperties.NestedChildClass.class)\n\t\t\t.withDefaultValue(20));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"nestedChildProps.parent-class-property\", Integer.class)\n\t\t\t.fromSource(ClassWithNestedProperties.NestedChildClass.class)\n\t\t\t.withDefaultValue(10));\n\t}\n\n\t@Test\n\tvoid builderPojo() {\n\t\tConfigurationMetadata metadata = compile(BuilderPojo.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"builder.name\"));\n\t}\n\n\t@Test\n\tvoid excludedTypesPojo() {\n\t\tConfigurationMetadata metadata = compile(ExcludedTypesPojo.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"excluded.name\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"excluded.class-loader\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"excluded.data-source\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"excluded.print-writer\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"excluded.writer\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"excluded.writer-array\"));\n\t}\n\n\t@Test\n\tvoid invalidAccessor() {\n\t\tConfigurationMetadata metadata = compile(InvalidAccessorProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config\"));\n\t\tassertThat(metadata.getItems()).hasSize(1);\n\t}\n\n\t@Test\n\tvoid doubleRegistration() {\n\t\tConfigurationMetadata metadata = compile(DoubleRegistrationProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"one\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"two\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"one.value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"two.value\"));\n\t\tassertThat(metadata.getItems()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid invalidDoubleRegistration() {\n\t\tassertThatExceptionOfType(CompilationException.class)\n\t\t\t.isThrownBy(() -> compile(InvalidDoubleRegistrationProperties.class))\n\t\t\t.withMessageContaining(\"Unable to compile source\");\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithInvalidDefaultValueOnNumber() {\n\t\tassertThatExceptionOfType(CompilationException.class)\n\t\t\t.isThrownBy(() -> compile(InvalidDefaultValueNumberProperties.class))\n\t\t\t.withMessageContaining(\"Unable to compile source\");\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithInvalidDefaultValueOnFloatingPoint() {\n\t\tassertThatExceptionOfType(CompilationException.class)\n\t\t\t.isThrownBy(() -> compile(InvalidDefaultValueFloatingPointProperties.class))\n\t\t\t.withMessageContaining(\"Unable to compile source\");\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithInvalidDefaultValueOnCharacter() {\n\t\tassertThatExceptionOfType(CompilationException.class)\n\t\t\t.isThrownBy(() -> compile(InvalidDefaultValueCharacterProperties.class))\n\t\t\t.withMessageContaining(\"Unable to compile source\");\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithEmptyDefaultValueOnProperty() {\n\t\tConfigurationMetadata metadata = compile(EmptyDefaultValueProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"test.name\"));\n\t\tItemMetadata nameMetadata = metadata.getItems()\n\t\t\t.stream()\n\t\t\t.filter((item) -> item.getName().equals(\"test.name\"))\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tassertThat(nameMetadata.getDefaultValue()).isNull();\n\t}\n\n\t@Test\n\tvoid recursivePropertiesDoNotCauseAStackOverflow() {\n\t\tcompile(RecursiveProperties.class);\n\t}\n\n\t@Test\n\tvoid recordProperties() {\n\t\tString source = \"\"\"\n\t\t\t\t@org.springframework.boot.configurationsample.TestConfigurationProperties(\"implicit\")\n\t\t\t\tpublic record ExampleRecord(String someString, Integer someInteger) {\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tConfigurationMetadata metadata = compile(source);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"implicit.some-string\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"implicit.some-integer\"));\n\t}\n\n\t@Test\n\tvoid recordPropertiesWithDefaultValues() {\n\t\tString source = \"\"\"\n\t\t\t\t@org.springframework.boot.configurationsample.TestConfigurationProperties(\"record.defaults\")\n\t\t\t\tpublic record ExampleRecord(\n\t\t\t\t\t@org.springframework.boot.configurationsample.TestDefaultValue(\"An1s9n\") String someString,\n\t\t\t\t\t@org.springframework.boot.configurationsample.TestDefaultValue(\"594\") Integer someInteger) {\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tConfigurationMetadata metadata = compile(source);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"record.defaults.some-string\", String.class).withDefaultValue(\"An1s9n\"));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"record.defaults.some-integer\", Integer.class).withDefaultValue(594));\n\t}\n\n\t@Test\n\tvoid multiConstructorRecordProperties() {\n\t\tString source = \"\"\"\n\t\t\t\t@org.springframework.boot.configurationsample.TestConfigurationProperties(\"multi\")\n\t\t\t\tpublic record ExampleRecord(String someString, Integer someInteger) {\n\t\t\t\t\t@org.springframework.boot.configurationsample.TestConstructorBinding\n\t\t\t\t\tpublic ExampleRecord(String someString) {\n\t\t\t\t\t\tthis(someString, 42);\n\t\t\t\t\t}\n\t\t\t\t\tpublic ExampleRecord(Integer someInteger) {\n\t\t\t\t\t\tthis(\"someString\", someInteger);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tConfigurationMetadata metadata = compile(source);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"multi.some-string\"));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"multi.some-integer\"));\n\t}\n\n\t@Test\n\tvoid innerClassWithPrivateConstructor() {\n\t\tConfigurationMetadata metadata = compile(InnerClassWithPrivateConstructor.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.nested.name\"));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"config.nested.ignored\"));\n\t}\n\n\t@Test\n\tvoid recordWithGetter() {\n\t\tConfigurationMetadata metadata = compile(RecordWithGetter.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record-with-getter.alpha\"));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"record-with-getter.bravo\"));\n\t}\n\n\t@Test\n\tvoid recordNested() {\n\t\tConfigurationMetadata metadata = compile(NestedPropertiesRecord.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"record-nested.nested\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record-nested.nested.my-nested-property\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"record-nested.inner.nested\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record-nested.inner.nested.my-nested-property\"));\n\t}\n\n\t@Test\n\tvoid shouldNotMarkDbcp2UsernameOrPasswordAsDeprecated() {\n\t\tConfigurationMetadata metadata = compile(Dbcp2Configuration.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"spring.datasource.dbcp2.username\").withNoDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(\"spring.datasource.dbcp2.password\").withNoDeprecation());\n\t}\n\n\t@Test\n\tvoid recordPropertiesWithDescriptions() {\n\t\tConfigurationMetadata metadata = compile(ExampleRecord.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record.descriptions.some-string\", String.class)\n\t\t\t.withDescription(\"very long description that doesn't fit single line and is indented\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record.descriptions.some-integer\", Integer.class)\n\t\t\t.withDescription(\"description with @param and @ pitfalls\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record.descriptions.some-boolean\", Boolean.class)\n\t\t\t.withDescription(\"description with extra spaces\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record.descriptions.some-long\", Long.class)\n\t\t\t.withDescription(\"description without space after asterisk\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record.descriptions.some-byte\", Byte.class)\n\t\t\t.withDescription(\"last description in Javadoc\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"record.descriptions.named.record.component\", String.class)\n\t\t\t.withDescription(\"description of a named component\"));\n\t}\n\n\t@Test\n\tvoid shouldIgnoreProperties() {\n\t\tString additionalMetadata = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"ignored\": {\n\t\t\t\t\t\t\"properties\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"name\": \"ignored.prop3\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, IgnoredProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"ignored.prop1\", String.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"ignored.prop2\", String.class));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"ignored.prop3\", String.class));\n\t\tassertThat(metadata.getIgnored()).containsExactly(ItemIgnore.forProperty(\"ignored.prop3\"));\n\t}\n\n\t@Nested\n\tclass SourceTests {\n\n\t\t@Test\n\t\tvoid javaBeansSourceIsMergedWithNestedConfigurationProperty() {\n\t\t\tConfigurationMetadata metadata = compile(SimpleSourceAnnotated.class, SimpleSource.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example.nested\", SimpleSource.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.name\", String.class).withDescription(\"Name description.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.description\", String.class)\n\t\t\t\t\t.withDescription(\"Description description.\")\n\t\t\t\t\t.withDefaultValue(\"Hello World\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.type\", String.class)\n\t\t\t\t\t.withDescription(\"A property with a fixed set of values.\")\n\t\t\t\t\t.withDefaultValue(\"single\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid lombokSourceIsMergedWithNestedConfigurationProperty() {\n\t\t\tConfigurationMetadata metadata = compile(LombokSourceAnnotated.class, LombokSource.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example.nested\", LombokSource.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.name\", String.class).withDescription(\"Name description.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.description\", String.class)\n\t\t\t\t\t.withDescription(\"Description description.\")\n\t\t\t\t\t.withDefaultValue(\"Hello World\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.type\", String.class)\n\t\t\t\t\t.withDescription(\"A property with a fixed set of values.\")\n\t\t\t\t\t.withDefaultValue(\"single\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid immutableSourceIsMergedWithNestedConfigurationProperty() {\n\t\t\tConfigurationMetadata metadata = compile(ImmutableSourceAnnotated.class, ImmutableSource.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example.nested\", ImmutableSource.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.name\", String.class).withDescription(\"Name description.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.description\", String.class)\n\t\t\t\t\t.withDescription(\"Description description.\")\n\t\t\t\t\t.withDefaultValue(\"Hello World\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.type\", String.class)\n\t\t\t\t\t.withDescription(\"A property with a fixed set of values.\")\n\t\t\t\t\t.withDefaultValue(\"single\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid recordSourceIsMergedWithNestedConfigurationProperty() {\n\t\t\tConfigurationMetadata metadata = compile(RecordSourceAnnotated.class, RecordSource.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example.nested\", RecordSource.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.name\", String.class).withDescription(\"Name description.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.description\", String.class)\n\t\t\t\t\t.withDescription(\"Description description.\")\n\t\t\t\t\t.withDefaultValue(\"Hello World\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.type\", String.class)\n\t\t\t\t\t.withDescription(\"A property with a fixed set of values.\")\n\t\t\t\t\t.withDefaultValue(\"single\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid sourceIsMergedWithConfigurationProperties() {\n\t\t\tConfigurationMetadata metadata = compile(ParentWithHintProperties.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example\", ParentWithHintProperties.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.name\", String.class).withDescription(\"Name description.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.description\", String.class)\n\t\t\t\t\t.withDescription(\"Description description.\")\n\t\t\t\t\t.withDefaultValue(\"Hello World\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.type\", String.class)\n\t\t\t\t\t.withDescription(\"A property with a fixed set of values.\")\n\t\t\t\t\t.withDefaultValue(\"single\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.enabled\", Boolean.class)\n\t\t\t\t\t.withDescription(\"Whether this is enabled.\")\n\t\t\t\t\t.withDefaultValue(false));\n\t\t}\n\n\t\t@Test\n\t\tvoid sourceHintIsMergedWithNestedConfigurationProperty() {\n\t\t\tConfigurationMetadata metadata = compile(SimpleSourceAnnotated.class);\n\t\t\tassertThat(metadata).has(Metadata.withHint(\"example.nested.type\")\n\t\t\t\t.withValue(0, \"auto\", \"Detect the type automatically.\")\n\t\t\t\t.withValue(1, \"single\", \"Single type.\")\n\t\t\t\t.withValue(2, \"multi\", \"Multi type.\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid sourceHintIsMergedWithConfigurationProperties() {\n\t\t\tConfigurationMetadata metadata = compile(ParentWithHintProperties.class);\n\t\t\tassertThat(metadata).has(Metadata.withHint(\"example.type\")\n\t\t\t\t.withValue(0, \"auto\", \"Detect the type automatically.\")\n\t\t\t\t.withValue(1, \"single\", \"Single type.\")\n\t\t\t\t.withValue(2, \"multi\", \"Multi type.\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid sourceWithNonCanonicalMetadataIsDiscovered() {\n\t\t\tConfigurationMetadata metadata = compile(ConventionSourceAnnotated.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example.nested\", ConventionSource.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.first-name\", String.class).withDescription(\"Camel case.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.last-name\", String.class)\n\t\t\t\t\t.withDescription(\"Canonical format.\"));\n\t\t\tassertThat(metadata.getItems()).hasSize(4);\n\t\t}\n\n\t\t@Test\n\t\tvoid sourceFromParentClasIsDiscoveredForConcreteSource() {\n\t\t\tConfigurationMetadata metadata = compile(ConcreteSourceAnnotated.class, ConcreteSource.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example\", ConcreteSourceAnnotated.class))\n\t\t\t\t.has(Metadata.withGroup(\"example.nested\", ConcreteSource.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.enabled\", Boolean.class)\n\t\t\t\t\t.withDescription(\"Whether the feature is enabled.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.username\", String.class)\n\t\t\t\t\t.withDescription(\"User name.\")\n\t\t\t\t\t.withDefaultValue(\"user\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.nested.password\", String.class).withDescription(\"Password.\"));\n\t\t\tassertThat(metadata.getItems()).hasSize(5);\n\t\t}\n\n\t\t@Test\n\t\tvoid sourceFromParentClasIsDiscoveredForConfigurationProperties() {\n\t\t\tConfigurationMetadata metadata = compile(ConcreteProperties.class);\n\t\t\tassertThat(metadata).has(Metadata.withGroup(\"example\", ConcreteProperties.class))\n\t\t\t\t.has(Metadata.withProperty(\"example.enabled\", Boolean.class)\n\t\t\t\t\t.withDescription(\"Whether the feature is enabled.\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.username\", String.class)\n\t\t\t\t\t.withDescription(\"User name.\")\n\t\t\t\t\t.withDefaultValue(\"user\"))\n\t\t\t\t.has(Metadata.withProperty(\"example.password\", String.class).withDescription(\"Password.\"));\n\t\t\tassertThat(metadata.getItems()).hasSize(4);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass SourceGenerationTests {\n\n\t\t@Test\n\t\tvoid simplePropertiesSource() {\n\t\t\tcompile(withTestClasses(SimplePropertiesSource.class), (compiled) -> {\n\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(SimplePropertiesSource.class));\n\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"));\n\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\tassertThat(metadata.getHints()).isEmpty();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid simplePropertiesSourceWithAdditionalMetadataIsMerged() {\n\t\t\tString additionalMetadata = \"\"\"\n\t\t\t\t\t{\n\t\t\t\t\t   \"properties\": [\n\t\t\t\t\t\t {\n\t\t\t\t\t\t   \"name\": \"custom\",\n\t\t\t\t\t\t   \"type\": \"java.lang.Integer\",\n\t\t\t\t\t\t   \"description\": \"Custom property description.\"\n\t\t\t\t\t\t }\n\t\t\t\t\t   ]\n\t\t\t\t\t }\"\"\";\n\t\t\tcompile(withTestClasses(SimplePropertiesSource.class)\n\t\t\t\t.andThen(withAdditionalMetadata(SimplePropertiesSource.class, additionalMetadata)), (compiled) -> {\n\t\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\t\tgetSourceMetadataLocation(SimplePropertiesSource.class));\n\t\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"))\n\t\t\t\t\t\t.has(Metadata.withProperty(\"custom\")\n\t\t\t\t\t\t\t.ofType(Integer.class)\n\t\t\t\t\t\t\t.withDescription(\"Custom property description.\"));\n\t\t\t\t\tassertThat(metadata.getItems()).hasSize(3);\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid simplePropertiesSourceWithAdditionalMetadataHintIsMerged() {\n\t\t\tString additionalMetadata = \"\"\"\n\t\t\t\t\t{\n\t\t\t\t\t \"hints\": [\n\t\t\t\t\t   {\n\t\t\t\t\t\t \"name\": \"name\",\n\t\t\t\t\t\t \"values\": [\n\t\t\t\t\t\t   { \"value\": \"boot\", \"description\": \"Spring Boot.\" },\n\t\t\t\t\t\t   { \"value\": \"framework\", \"description\": \"Spring Framework.\" }\n\t\t\t\t\t\t ]\n\t\t\t\t\t   }\n\t\t\t\t\t ]\n\t\t\t\t\t}\"\"\";\n\t\t\tcompile(withTestClasses(SimplePropertiesSource.class)\n\t\t\t\t.andThen(withAdditionalMetadata(SimplePropertiesSource.class, additionalMetadata)), (compiled) -> {\n\t\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\t\tgetSourceMetadataLocation(SimplePropertiesSource.class));\n\t\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"))\n\t\t\t\t\t\t.has(Metadata.withHint(\"name\")\n\t\t\t\t\t\t\t.withValue(0, \"boot\", \"Spring Boot.\")\n\t\t\t\t\t\t\t.withValue(1, \"framework\", \"Spring Framework.\"));\n\t\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\t\tassertThat(metadata.getHints()).hasSize(1);\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid simplePropertiesSourceWithAdditionalMetadataCanBeOverridden() {\n\t\t\tString additionalMetadata = \"\"\"\n\t\t\t\t\t{\n\t\t\t\t\t   \"properties\": [\n\t\t\t\t\t\t {\n\t\t\t\t\t\t   \"name\": \"name\",\n\t\t\t\t\t\t   \"description\": \"Custom description.\"\n\t\t\t\t\t\t }\n\t\t\t\t\t   ]\n\t\t\t\t\t }\"\"\";\n\t\t\tcompile(withTestClasses(SimplePropertiesSource.class)\n\t\t\t\t.andThen(withAdditionalMetadata(SimplePropertiesSource.class, additionalMetadata)), (compiled) -> {\n\t\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\t\tgetSourceMetadataLocation(SimplePropertiesSource.class));\n\t\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t\t.withDescription(\"Custom description.\"))\n\t\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"));\n\t\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid lombokPropertiesSource() {\n\t\t\tcompile(withTestClasses(LombokPropertiesSource.class), (compiled) -> {\n\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(LombokPropertiesSource.class));\n\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"));\n\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\tassertThat(metadata.getHints()).isEmpty();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid immutablePropertiesSource() {\n\t\t\tcompile(withTestClasses(ImmutablePropertiesSource.class), (compiled) -> {\n\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(ImmutablePropertiesSource.class));\n\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"));\n\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\tassertThat(metadata.getHints()).isEmpty();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid recordPropertiesSource() {\n\t\t\tcompile(withTestClasses(RecordPropertiesSources.class), (compiled) -> {\n\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(RecordPropertiesSources.class));\n\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"));\n\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\tassertThat(metadata.getHints()).isEmpty();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid abstractPropertiesSource() {\n\t\t\tcompile(withTestClasses(AbstractPropertiesSource.class), (compiled) -> {\n\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(AbstractPropertiesSource.class));\n\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\")\n\t\t\t\t\t\t.ofType(String.class)\n\t\t\t\t\t\t.withDefaultValue(\"boot\")\n\t\t\t\t\t\t.withDescription(\"Description of this simple property.\"))\n\t\t\t\t\t.has(Metadata.withProperty(\"enabled\")\n\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t.withDefaultValue(false)\n\t\t\t\t\t\t.withDescription(\"Whether it is enabled.\"));\n\t\t\t\tassertThat(metadata.getItems()).hasSize(2);\n\t\t\t\tassertThat(metadata.getHints()).isEmpty();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid nonRootConfigurationPropertiesSources() {\n\t\t\tcompile(withTestClasses(ConfigurationPropertySourcesContainer.class), (compiled) -> {\n\t\t\t\tassertThat(CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(ConfigurationPropertySourcesContainer.class)))\n\t\t\t\t\t.isNull();\n\t\t\t\tConfigurationMetadata firstMetadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(First.class));\n\t\t\t\tassertThat(firstMetadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\").ofType(String.class).withDescription(\"A name.\"));\n\t\t\t\tassertThat(firstMetadata.getItems()).hasSize(1);\n\t\t\t\tassertThat(firstMetadata.getHints()).isEmpty();\n\t\t\t\tConfigurationMetadata secondMetadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(Second.class));\n\t\t\t\tassertThat(secondMetadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"visible\")\n\t\t\t\t\t\t.ofType(Boolean.class)\n\t\t\t\t\t\t.withDefaultValue(true)\n\t\t\t\t\t\t.withDescription(\"Whether this is visible.\"));\n\t\t\t\tassertThat(secondMetadata.getItems()).hasSize(1);\n\t\t\t\tassertThat(secondMetadata.getHints()).isEmpty();\n\t\t\t\tassertThat(CompiledMetadataReader.getMetadata(compiled, getSourceMetadataLocation(Third.class)))\n\t\t\t\t\t.isNull();\n\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid nestedPropertiesSource() {\n\t\t\tcompile(withTestClasses(NestedPropertiesSource.class), (compiled) -> {\n\t\t\t\tConfigurationMetadata metadata = CompiledMetadataReader.getMetadata(compiled,\n\t\t\t\t\t\tgetSourceMetadataLocation(NestedPropertiesSource.class));\n\t\t\t\tassertThat(metadata).isNotNull()\n\t\t\t\t\t.has(Metadata.withProperty(\"name\").ofType(String.class).withDescription(\"A name.\"))\n\t\t\t\t\t.has(Metadata.withGroup(\"nested\").ofType(NestedPropertiesSource.Nested.class))\n\t\t\t\t\t.has(Metadata.withProperty(\"nested.name\").ofType(String.class).withDescription(\"Another name.\"));\n\t\t\t\tassertThat(metadata.getItems()).hasSize(3);\n\t\t\t});\n\t\t}\n\n\t\tprivate String getSourceMetadataLocation(Class<?> type) {\n\t\t\treturn \"META-INF/spring/configuration-metadata/%s.json\".formatted(type.getName());\n\t\t}\n\n\t\tprivate void compile(Function<TestCompiler, TestCompiler> configuration, Consumer<Compiled> compiled) {\n\t\t\tTestCompiler testCompiler = TestCompiler.forSystem();\n\t\t\tconfiguration.apply(testCompiler)\n\t\t\t\t.withProcessors(new TestConfigurationMetadataAnnotationProcessor())\n\t\t\t\t.compile(compiled);\n\t\t}\n\n\t\tprivate Function<TestCompiler, TestCompiler> withTestClasses(Class<?>... testClasses) {\n\t\t\treturn (compiler) -> compiler\n\t\t\t\t.withSources(Arrays.stream(testClasses).map(SourceFile::forTestClass).toList());\n\t\t}\n\n\t\tprivate Function<TestCompiler, TestCompiler> withAdditionalMetadata(Class<?> type, String content) {\n\t\t\tString location = \"META-INF/spring/configuration-metadata/additional/%s.json\".formatted(type.getName());\n\t\t\treturn (compiler) -> compiler.withResources(ResourceFile.of(location, content));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConstructorParameterPropertyDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.util.ElementFilter;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationsample.immutable.ImmutableCollectionProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutableInnerClassProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutablePrimitiveProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutablePrimitiveWithDefaultsProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutablePrimitiveWrapperWithDefaultsProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConstructorParameterPropertyDescriptor}.\n *\n * @author Stephane Nicoll\n */\nclass ConstructorParameterPropertyDescriptorTests extends PropertyDescriptorTests {\n\n\t@Test\n\tvoid constructorParameterSimpleProperty() {\n\t\tprocess(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableSimpleProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"theName\");\n\t\t\tassertThat(property.getParameter()).hasToString(\"theName\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getTheName\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isTrue();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterNestedPropertySameClass() {\n\t\tprocess(ImmutableInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableInnerClassProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"first\");\n\t\t\tassertThat(property.getParameter()).hasToString(\"first\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getFirst\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterNestedPropertyWithAnnotation() {\n\t\tprocess(ImmutableInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableInnerClassProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"third\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"third\");\n\t\t\tassertThat(property.getParameter()).hasToString(\"third\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getThird\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterSimplePropertyWithNoAccessorShouldBeExposed() {\n\t\tprocess(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableSimpleProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"counter\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"counter\");\n\t\t\tassertThat(property.getParameter()).hasToString(\"counter\");\n\t\t\tassertThat(property.getGetter()).isNull();\n\t\t\tassertThat(property.isProperty(metadataEnv)).isTrue();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterMetadataSimpleProperty() {\n\t\tprocess(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableSimpleProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"counter\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasName(\"test.counter\")\n\t\t\t\t.hasType(Long.class)\n\t\t\t\t.hasSourceType(ImmutableSimpleProperties.class)\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterMetadataNestedGroup() {\n\t\tprocess(ImmutableInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableInnerClassProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertItemMetadata(metadataEnv, property).isGroup()\n\t\t\t\t.hasName(\"test.first\")\n\t\t\t\t.hasType(\"org.springframework.boot.configurationsample.immutable.ImmutableInnerClassProperties$Foo\")\n\t\t\t\t.hasSourceType(ImmutableInnerClassProperties.class)\n\t\t\t\t.hasSourceMethod(\"getFirst()\")\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterDeprecatedPropertyOnGetter() {\n\t\tprocess(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableSimpleProperties.class);\n\t\t\tExecutableElement getter = getMethod(ownerElement, \"isFlag\");\n\t\t\tVariableElement field = getField(ownerElement, \"flag\");\n\t\t\tVariableElement constructorParameter = getConstructorParameter(ownerElement, \"flag\");\n\t\t\tConstructorParameterPropertyDescriptor property = new ConstructorParameterPropertyDescriptor(\"flag\",\n\t\t\t\t\tfield.asType(), constructorParameter, ownerElement, getter, null, field);\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().isDeprecatedWithNoInformation();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithDescription() {\n\t\tprocess(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableSimpleProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasDescription(\"The name of this simple properties.\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithDefaultValue() {\n\t\tprocess(ImmutableSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableSimpleProperties.class);\n\t\t\tConstructorParameterPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().hasDefaultValue(\"boot\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithPrimitiveTypes() {\n\t\tprocess(ImmutablePrimitiveProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveProperties.class);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"flag\")).hasDefaultValue(false);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"octet\")).hasDefaultValue((byte) 0);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"letter\")).hasDefaultValue(null);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"number\"))\n\t\t\t\t.hasDefaultValue((short) 0);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"counter\")).hasDefaultValue(0);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"value\")).hasDefaultValue(0L);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"percentage\")).hasDefaultValue(0F);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"ratio\")).hasDefaultValue(0D);\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithPrimitiveTypesAndDefaultValues() {\n\t\tprocess(ImmutablePrimitiveWithDefaultsProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWithDefaultsProperties.class);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"flag\")).hasDefaultValue(true);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"octet\"))\n\t\t\t\t.hasDefaultValue((byte) 120);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"letter\")).hasDefaultValue(\"a\");\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"number\"))\n\t\t\t\t.hasDefaultValue((short) 1000);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"counter\")).hasDefaultValue(42);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"value\")).hasDefaultValue(2000L);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"percentage\")).hasDefaultValue(0.5F);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"ratio\")).hasDefaultValue(42.42);\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithPrimitiveWrapperTypesAndDefaultValues() {\n\t\tprocess(ImmutablePrimitiveWrapperWithDefaultsProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutablePrimitiveWrapperWithDefaultsProperties.class);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"flag\")).hasDefaultValue(true);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"octet\"))\n\t\t\t\t.hasDefaultValue((byte) 120);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"letter\")).hasDefaultValue(\"a\");\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"number\"))\n\t\t\t\t.hasDefaultValue((short) 1000);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"counter\")).hasDefaultValue(42);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"value\")).hasDefaultValue(2000L);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"percentage\")).hasDefaultValue(0.5F);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"ratio\")).hasDefaultValue(42.42);\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithCollectionTypesAndDefaultValues() {\n\t\tprocess(ImmutableCollectionProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(ImmutableCollectionProperties.class);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"names\")).hasDefaultValue(null);\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"flags\"))\n\t\t\t\t.hasDefaultValue(Arrays.asList(true, false));\n\t\t\tassertItemMetadata(metadataEnv, createPropertyDescriptor(ownerElement, \"durations\"))\n\t\t\t\t.hasDefaultValue(Arrays.asList(\"10s\", \"1m\", \"1h\"));\n\t\t});\n\t}\n\n\tprotected ConstructorParameterPropertyDescriptor createPropertyDescriptor(TypeElement ownerElement, String name) {\n\t\tVariableElement constructorParameter = getConstructorParameter(ownerElement, name);\n\t\tVariableElement field = getField(ownerElement, name);\n\t\tExecutableElement getter = getMethod(ownerElement, createAccessorMethodName(\"get\", name));\n\t\tExecutableElement setter = getMethod(ownerElement, createAccessorMethodName(\"set\", name));\n\t\treturn new ConstructorParameterPropertyDescriptor(name, field.asType(), constructorParameter, ownerElement,\n\t\t\t\tgetter, setter, field);\n\t}\n\n\tprivate VariableElement getConstructorParameter(TypeElement ownerElement, String name) {\n\t\tList<ExecutableElement> constructors = ElementFilter.constructorsIn(ownerElement.getEnclosedElements())\n\t\t\t.stream()\n\t\t\t.filter((constructor) -> !constructor.getParameters().isEmpty())\n\t\t\t.toList();\n\t\tif (constructors.size() != 1) {\n\t\t\tthrow new IllegalStateException(\"No candidate constructor for \" + ownerElement);\n\t\t}\n\t\treturn constructors.get(0)\n\t\t\t.getParameters()\n\t\t\t.stream()\n\t\t\t.filter((parameter) -> parameter.getSimpleName().toString().equals(name))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/DeducedImmutablePropertiesMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.immutable.DeducedImmutableClassProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for immutable properties deduced because they're nested.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass DeducedImmutablePropertiesMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid immutableSimpleProperties() {\n\t\tConfigurationMetadata metadata = compile(DeducedImmutableClassProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"test\").fromSource(DeducedImmutableClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"test.nested\", DeducedImmutableClassProperties.Nested.class)\n\t\t\t.fromSource(DeducedImmutableClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"test.nested.name\", String.class)\n\t\t\t.fromSource(DeducedImmutableClassProperties.Nested.class));\n\t\tItemMetadata nestedMetadata = metadata.getItems()\n\t\t\t.stream()\n\t\t\t.filter((item) -> item.getName().equals(\"test.nested\"))\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tassertThat(nestedMetadata.getDefaultValue()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/EndpointMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.time.Duration;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.TestAccess;\nimport org.springframework.boot.configurationsample.endpoint.CamelCaseEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.CustomPropertiesEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.EnabledEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.NoAccessEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.NullableParameterEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.ReadOnlyAccessEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.SimpleEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.SimpleEndpoint2;\nimport org.springframework.boot.configurationsample.endpoint.SimpleEndpoint3;\nimport org.springframework.boot.configurationsample.endpoint.SpecificEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.UnrestrictedAccessEndpoint;\nimport org.springframework.boot.configurationsample.endpoint.incremental.IncrementalEndpoint;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatRuntimeException;\n\n/**\n * Metadata generation tests for Actuator endpoints.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Wonyong Hwang\n */\nclass EndpointMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid simpleEndpoint() {\n\t\tConfigurationMetadata metadata = compile(SimpleEndpoint.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.simple\").fromSource(SimpleEndpoint.class));\n\t\tassertThat(metadata).has(access(\"simple\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata).has(cacheTtl(\"simple\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid enabledEndpoint() {\n\t\tConfigurationMetadata metadata = compile(EnabledEndpoint.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.enabled\").fromSource(EnabledEndpoint.class));\n\t\tassertThat(metadata).has(access(\"enabled\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid noAccessEndpoint() {\n\t\tConfigurationMetadata metadata = compile(NoAccessEndpoint.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.noaccess\").fromSource(NoAccessEndpoint.class));\n\t\tassertThat(metadata).has(access(\"noaccess\", TestAccess.NONE));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid readOnlyAccessEndpoint() {\n\t\tConfigurationMetadata metadata = compile(ReadOnlyAccessEndpoint.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.readonlyaccess\").fromSource(ReadOnlyAccessEndpoint.class));\n\t\tassertThat(metadata).has(access(\"readonlyaccess\", TestAccess.READ_ONLY));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid unrestrictedAccessEndpoint() {\n\t\tConfigurationMetadata metadata = compile(UnrestrictedAccessEndpoint.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.unrestrictedaccess\")\n\t\t\t.fromSource(UnrestrictedAccessEndpoint.class));\n\t\tassertThat(metadata).has(access(\"unrestrictedaccess\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid customPropertiesEndpoint() {\n\t\tConfigurationMetadata metadata = compile(CustomPropertiesEndpoint.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.customprops\").fromSource(CustomPropertiesEndpoint.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"management.endpoint.customprops.name\")\n\t\t\t.ofType(String.class)\n\t\t\t.withDefaultValue(\"test\"));\n\t\tassertThat(metadata).has(access(\"customprops\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata).has(cacheTtl(\"customprops\"));\n\t\tassertThat(metadata.getItems()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid specificEndpoint() {\n\t\tConfigurationMetadata metadata = compile(SpecificEndpoint.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.specific\").fromSource(SpecificEndpoint.class));\n\t\tassertThat(metadata).has(access(\"specific\", TestAccess.READ_ONLY));\n\t\tassertThat(metadata).has(cacheTtl(\"specific\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid camelCaseEndpoint() {\n\t\tConfigurationMetadata metadata = compile(CamelCaseEndpoint.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.pascal-case\").fromSource(CamelCaseEndpoint.class));\n\t\tassertThat(metadata).has(defaultAccess(\"PascalCase\", \"pascal-case\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid incrementalEndpointBuildChangeDefaultAccess() {\n\t\tTestProject project = new TestProject(IncrementalEndpoint.class);\n\t\tConfigurationMetadata metadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.incremental\").fromSource(IncrementalEndpoint.class));\n\t\tassertThat(metadata).has(access(\"incremental\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata).has(cacheTtl(\"incremental\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t\tproject.replaceText(IncrementalEndpoint.class, \"id = \\\"incremental\\\"\",\n\t\t\t\t\"id = \\\"incremental\\\", defaultAccess = org.springframework.boot.configurationsample.TestAccess.NONE\");\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.incremental\").fromSource(IncrementalEndpoint.class));\n\t\tassertThat(metadata).has(access(\"incremental\", TestAccess.NONE));\n\t\tassertThat(metadata).has(cacheTtl(\"incremental\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid incrementalEndpointBuildChangeCacheFlag() {\n\t\tTestProject project = new TestProject(IncrementalEndpoint.class);\n\t\tConfigurationMetadata metadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.incremental\").fromSource(IncrementalEndpoint.class));\n\t\tassertThat(metadata).has(access(\"incremental\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata).has(cacheTtl(\"incremental\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t\tproject.replaceText(IncrementalEndpoint.class, \"@Nullable String param\", \"String param\");\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.incremental\").fromSource(IncrementalEndpoint.class));\n\t\tassertThat(metadata).has(access(\"incremental\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata.getItems()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid incrementalEndpointBuildChangeAccessOfSpecificEndpoint() {\n\t\tTestProject project = new TestProject(SpecificEndpoint.class);\n\t\tConfigurationMetadata metadata = project.compile();\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.specific\").fromSource(SpecificEndpoint.class));\n\t\tassertThat(metadata).has(access(\"specific\", TestAccess.READ_ONLY));\n\t\tassertThat(metadata).has(cacheTtl(\"specific\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t\tproject.replaceText(SpecificEndpoint.class, \"defaultAccess = TestAccess.READ_ONLY\",\n\t\t\t\t\"defaultAccess = TestAccess.NONE\");\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.specific\").fromSource(SpecificEndpoint.class));\n\t\tassertThat(metadata).has(access(\"specific\", TestAccess.NONE));\n\t\tassertThat(metadata).has(cacheTtl(\"specific\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid shouldTolerateEndpointWithSameId() {\n\t\tConfigurationMetadata metadata = compile(SimpleEndpoint.class, SimpleEndpoint2.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"management.endpoint.simple\").fromSource(SimpleEndpoint.class));\n\t\tassertThat(metadata).has(defaultAccess(\"simple\", \"simple\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata).has(cacheTtl(\"simple\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid shouldFailIfEndpointWithSameIdButWithConflictingEnabledByDefaultSetting() {\n\t\tassertThatRuntimeException().isThrownBy(() -> compile(SimpleEndpoint.class, SimpleEndpoint3.class))\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(IllegalStateException.class)\n\t\t\t.withMessage(\n\t\t\t\t\t\"Existing property 'management.endpoint.simple.access' from type org.springframework.boot.configurationsample.endpoint.SimpleEndpoint has a conflicting value. Existing value: unrestricted, new value from type org.springframework.boot.configurationsample.endpoint.SimpleEndpoint3: none\");\n\t}\n\n\t@Test\n\tvoid endpointWithNullableParameter() {\n\t\tConfigurationMetadata metadata = compile(NullableParameterEndpoint.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withGroup(\"management.endpoint.nullable\").fromSource(NullableParameterEndpoint.class));\n\t\tassertThat(metadata).has(access(\"nullable\", TestAccess.UNRESTRICTED));\n\t\tassertThat(metadata).has(cacheTtl(\"nullable\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\tprivate Metadata.MetadataItemCondition access(String endpointId, TestAccess defaultValue) {\n\t\treturn defaultAccess(endpointId, endpointId, defaultValue);\n\t}\n\n\tprivate Metadata.MetadataItemCondition defaultAccess(String endpointId, String endpointSuffix,\n\t\t\tTestAccess defaultValue) {\n\t\treturn Metadata.withAccess(\"management.endpoint.\" + endpointSuffix + \".access\")\n\t\t\t.withDefaultValue(defaultValue.name().toLowerCase(Locale.ENGLISH))\n\t\t\t.withDescription(\"Permitted level of access for the %s endpoint.\".formatted(endpointId));\n\t}\n\n\tprivate Metadata.MetadataItemCondition cacheTtl(String endpointId) {\n\t\treturn Metadata.withProperty(\"management.endpoint.\" + endpointId + \".cache.time-to-live\")\n\t\t\t.ofType(Duration.class)\n\t\t\t.withDefaultValue(\"0ms\")\n\t\t\t.withDescription(\"Maximum time that a response can be cached.\");\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/GenericsMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.generic.AbstractGenericProperties;\nimport org.springframework.boot.configurationsample.generic.ComplexGenericProperties;\nimport org.springframework.boot.configurationsample.generic.ConcreteBuilderProperties;\nimport org.springframework.boot.configurationsample.generic.GenericConfig;\nimport org.springframework.boot.configurationsample.generic.SimpleGenericProperties;\nimport org.springframework.boot.configurationsample.generic.UnresolvedGenericProperties;\nimport org.springframework.boot.configurationsample.generic.UpperBoundGenericPojo;\nimport org.springframework.boot.configurationsample.generic.WildcardConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for generics handling.\n *\n * @author Stephane Nicoll\n */\nclass GenericsMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid simpleGenericProperties() {\n\t\tConfigurationMetadata metadata = compile(AbstractGenericProperties.class, SimpleGenericProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic\").fromSource(SimpleGenericProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"generic.name\", String.class)\n\t\t\t.fromSource(SimpleGenericProperties.class)\n\t\t\t.withDescription(\"Generic name.\")\n\t\t\t.withDefaultValue(null));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"generic.mappings\", \"java.util.Map<java.lang.Integer,java.time.Duration>\")\n\t\t\t\t.fromSource(SimpleGenericProperties.class)\n\t\t\t\t.withDescription(\"Generic mappings.\")\n\t\t\t\t.withDefaultValue(null));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid complexGenericProperties() {\n\t\tConfigurationMetadata metadata = compile(ComplexGenericProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic\").fromSource(ComplexGenericProperties.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic.test\")\n\t\t\t.ofType(UpperBoundGenericPojo.class)\n\t\t\t.fromSource(ComplexGenericProperties.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"generic.test.mappings\", \"java.util.Map<java.lang.Enum<T>,java.lang.String>\")\n\t\t\t\t.fromSource(UpperBoundGenericPojo.class));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid unresolvedGenericProperties() {\n\t\tConfigurationMetadata metadata = compile(AbstractGenericProperties.class, UnresolvedGenericProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic\").fromSource(UnresolvedGenericProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"generic.name\", String.class)\n\t\t\t.fromSource(UnresolvedGenericProperties.class)\n\t\t\t.withDescription(\"Generic name.\")\n\t\t\t.withDefaultValue(null));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"generic.mappings\", \"java.util.Map<java.lang.Number,java.lang.Object>\")\n\t\t\t\t.fromSource(UnresolvedGenericProperties.class)\n\t\t\t\t.withDescription(\"Generic mappings.\")\n\t\t\t\t.withDefaultValue(null));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid genericTypes() {\n\t\tConfigurationMetadata metadata = compile(GenericConfig.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic\")\n\t\t\t.ofType(\"org.springframework.boot.configurationsample.generic.GenericConfig\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic.foo\")\n\t\t\t.ofType(\"org.springframework.boot.configurationsample.generic.GenericConfig$Foo\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic.foo.bar\")\n\t\t\t.ofType(\"org.springframework.boot.configurationsample.generic.GenericConfig$Bar\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"generic.foo.bar.biz\")\n\t\t\t.ofType(\"org.springframework.boot.configurationsample.generic.GenericConfig$Bar$Biz\"));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"generic.foo.name\").ofType(String.class).fromSource(GenericConfig.Foo.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"generic.foo.string-to-bar\")\n\t\t\t.ofType(\"java.util.Map<java.lang.String,org.springframework.boot.configurationsample.generic.GenericConfig$Bar<java.lang.Integer>>\")\n\t\t\t.fromSource(GenericConfig.Foo.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"generic.foo.string-to-integer\")\n\t\t\t.ofType(\"java.util.Map<java.lang.String,java.lang.Integer>\")\n\t\t\t.fromSource(GenericConfig.Foo.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"generic.foo.bar.name\")\n\t\t\t.ofType(\"java.lang.String\")\n\t\t\t.fromSource(GenericConfig.Bar.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"generic.foo.bar.biz.name\")\n\t\t\t.ofType(\"java.lang.String\")\n\t\t\t.fromSource(GenericConfig.Bar.Biz.class));\n\t\tassertThat(metadata.getItems()).hasSize(9);\n\t}\n\n\t@Test\n\tvoid wildcardTypes() {\n\t\tConfigurationMetadata metadata = compile(WildcardConfig.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"wildcard\").ofType(WildcardConfig.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"wildcard.string-to-number\")\n\t\t\t.ofType(\"java.util.Map<java.lang.String,? extends java.lang.Number>\")\n\t\t\t.fromSource(WildcardConfig.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"wildcard.integers\")\n\t\t\t.ofType(\"java.util.List<? super java.lang.Integer>\")\n\t\t\t.fromSource(WildcardConfig.class));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid builderPatternWithGenericReturnType() {\n\t\tConfigurationMetadata metadata = compile(ConcreteBuilderProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"builder\").fromSource(ConcreteBuilderProperties.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"builder.number\", Integer.class).fromSource(ConcreteBuilderProperties.class));\n\t\tassertThat(metadata).has(\n\t\t\t\tMetadata.withProperty(\"builder.description\", String.class).fromSource(ConcreteBuilderProperties.class));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ImmutablePropertiesMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for immutable properties.\n *\n * @author Stephane Nicoll\n */\nclass ImmutablePropertiesMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid immutableSimpleProperties() {\n\t\tConfigurationMetadata metadata = compile(ImmutableSimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"immutable\").fromSource(ImmutableSimpleProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"immutable.the-name\", String.class)\n\t\t\t.fromSource(ImmutableSimpleProperties.class)\n\t\t\t.withDescription(\"The name of this simple properties.\")\n\t\t\t.withDefaultValue(\"boot\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"immutable.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.fromSource(ImmutableSimpleProperties.class)\n\t\t\t.withDescription(\"A simple flag.\")\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(\"immutable.comparator\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"immutable.counter\"));\n\t\tassertThat(metadata.getItems()).hasSize(5);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/IncrementalBuildMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.incremental.BarProperties;\nimport org.springframework.boot.configurationsample.incremental.FooProperties;\nimport org.springframework.boot.configurationsample.incremental.RenamedBarProperties;\nimport org.springframework.boot.configurationsample.simple.ClassWithNestedProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for incremental builds.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass IncrementalBuildMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid incrementalBuild() throws Exception {\n\t\tTestProject project = new TestProject(FooProperties.class, BarProperties.class);\n\t\tConfigurationMetadata metadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"foo.counter\").fromSource(FooProperties.class).withDefaultValue(0));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"bar.counter\").fromSource(BarProperties.class).withDefaultValue(0));\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"foo.counter\").fromSource(FooProperties.class).withDefaultValue(0));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"bar.counter\").fromSource(BarProperties.class).withDefaultValue(0));\n\t\tproject.addSourceCode(BarProperties.class, BarProperties.class.getResourceAsStream(\"BarProperties.snippet\"));\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata).has(Metadata.withProperty(\"bar.extra\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.counter\").withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"bar.counter\").withDefaultValue(0));\n\t\tproject.revert(BarProperties.class);\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"bar.extra\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.counter\").withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"bar.counter\").withDefaultValue(0));\n\t}\n\n\t@Test\n\tvoid incrementalBuildAnnotationRemoved() {\n\t\tTestProject project = new TestProject(FooProperties.class, BarProperties.class);\n\t\tConfigurationMetadata metadata = project.compile();\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.counter\").withDefaultValue(0));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"bar.counter\").withDefaultValue(0));\n\t\tproject.replaceText(BarProperties.class, \"@TestConfigurationProperties\", \"//@TestConfigurationProperties\");\n\t\tproject.replaceText(FooProperties.class, \"@TestConfigurationProperties\", \"//@TestConfigurationProperties\");\n\t\tmetadata = project.compile();\n\t\tassertThat(metadata).isNull();\n\t}\n\n\t@Test\n\tvoid incrementalBuildTypeRenamed() {\n\t\tTestProject project = new TestProject(FooProperties.class, BarProperties.class);\n\t\tConfigurationMetadata metadata = project.compile();\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"foo.counter\").fromSource(FooProperties.class).withDefaultValue(0));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"bar.counter\").fromSource(BarProperties.class).withDefaultValue(0));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"bar.counter\").fromSource(RenamedBarProperties.class));\n\t\tproject.delete(BarProperties.class);\n\t\tproject.add(RenamedBarProperties.class);\n\t\tmetadata = project.compile(metadata);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"foo.counter\").fromSource(FooProperties.class).withDefaultValue(0));\n\t\tassertThat(metadata)\n\t\t\t.doesNotHave(Metadata.withProperty(\"bar.counter\").fromSource(BarProperties.class).withDefaultValue(0));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"bar.counter\").withDefaultValue(0).fromSource(RenamedBarProperties.class));\n\t}\n\n\t@Test\n\tvoid incrementalBuildDoesNotDeleteItems() {\n\t\tTestProject project = new TestProject(ClassWithNestedProperties.class, FooProperties.class);\n\t\tConfigurationMetadata initialMetadata = project.compile();\n\t\tConfigurationMetadata updatedMetadata = project.compile();\n\t\tassertThat(initialMetadata.getItems()).isEqualTo(updatedMetadata.getItems());\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/InheritanceMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.inheritance.ChildProperties;\nimport org.springframework.boot.configurationsample.inheritance.ChildPropertiesConfig;\nimport org.springframework.boot.configurationsample.inheritance.OverrideChildProperties;\nimport org.springframework.boot.configurationsample.inheritance.OverrideChildPropertiesConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass InheritanceMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid childProperties() {\n\t\tConfigurationMetadata metadata = compile(ChildPropertiesConfig.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"inheritance\").fromSource(ChildPropertiesConfig.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"inheritance.nest\").fromSource(ChildProperties.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"inheritance.child-nest\").fromSource(ChildProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.bool-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.int-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.long-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.nest.bool-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.nest.int-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.child-nest.bool-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.child-nest.int-value\"));\n\t}\n\n\t@Test\n\tvoid overrideChildProperties() {\n\t\tConfigurationMetadata metadata = compile(OverrideChildPropertiesConfig.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"inheritance\").fromSource(OverrideChildPropertiesConfig.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"inheritance.nest\").fromSource(OverrideChildProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.bool-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.int-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.long-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.nest.bool-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.nest.int-value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"inheritance.nest.long-value\"));\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/JavaBeanPropertyDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty;\nimport org.springframework.boot.configurationsample.simple.SimpleCollectionProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleTypeProperties;\nimport org.springframework.boot.configurationsample.specific.InnerClassProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JavaBeanPropertyDescriptor}.\n *\n * @author Stephane Nicoll\n */\nclass JavaBeanPropertyDescriptorTests extends PropertyDescriptorTests {\n\n\t@Test\n\tvoid javaBeanSimpleProperty() {\n\t\tprocess(SimpleTypeProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleTypeProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"myString\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"myString\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getMyString\");\n\t\t\tassertThat(property.getSetter().getSimpleName()).hasToString(\"setMyString\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isTrue();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanCollectionProperty() {\n\t\tprocess(SimpleCollectionProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleCollectionProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"doubles\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"doubles\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getDoubles\");\n\t\t\tassertThat(property.getSetter()).isNull();\n\t\t\tassertThat(property.isProperty(metadataEnv)).isTrue();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanNestedPropertySameClass() {\n\t\tprocess(InnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(InnerClassProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"first\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getFirst\");\n\t\t\tassertThat(property.getSetter()).isNull();\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanNestedPropertyWithAnnotation() {\n\t\tprocess(InnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(InnerClassProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"third\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"third\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getThird\");\n\t\t\tassertThat(property.getSetter()).isNull();\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanSimplePropertyWithOnlyGetterShouldNotBeExposed() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tExecutableElement getter = getMethod(ownerElement, \"getSize\");\n\t\t\tVariableElement field = getField(ownerElement, \"size\");\n\t\t\tJavaBeanPropertyDescriptor property = new JavaBeanPropertyDescriptor(\"size\", field.asType(), ownerElement,\n\t\t\t\t\tgetter, null, field, getter);\n\t\t\tassertThat(property.getName()).isEqualTo(\"size\");\n\t\t\tassertThat(property.getGetter().getSimpleName()).hasToString(\"getSize\");\n\t\t\tassertThat(property.getSetter()).isNull();\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanSimplePropertyWithOnlySetterShouldNotBeExposed() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tVariableElement field = getField(ownerElement, \"counter\");\n\t\t\tJavaBeanPropertyDescriptor property = new JavaBeanPropertyDescriptor(\"counter\", field.asType(),\n\t\t\t\t\townerElement, null, getMethod(ownerElement, \"setCounter\"), field, null);\n\t\t\tassertThat(property.getName()).isEqualTo(\"counter\");\n\t\t\tassertThat(property.getGetter()).isNull();\n\t\t\tassertThat(property.getSetter().getSimpleName()).hasToString(\"setCounter\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanMetadataSimpleProperty() {\n\t\tprocess(SimpleTypeProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleTypeProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"myString\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasName(\"test.my-string\")\n\t\t\t\t.hasType(String.class)\n\t\t\t\t.hasSourceType(SimpleTypeProperties.class)\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanMetadataCollectionProperty() {\n\t\tprocess(SimpleCollectionProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleCollectionProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"doubles\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasName(\"test.doubles\")\n\t\t\t\t.hasType(\"java.util.List<java.lang.Double>\")\n\t\t\t\t.hasSourceType(SimpleCollectionProperties.class)\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanMetadataNestedGroup() {\n\t\tprocess(InnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(InnerClassProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertItemMetadata(metadataEnv, property).isGroup()\n\t\t\t\t.hasName(\"test.first\")\n\t\t\t\t.hasType(\"org.springframework.boot.configurationsample.specific.InnerClassProperties$Foo\")\n\t\t\t\t.hasSourceType(InnerClassProperties.class)\n\t\t\t\t.hasSourceMethod(\"getFirst()\")\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanMetadataNotACandidatePropertyShouldReturnNull() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tVariableElement field = getField(ownerElement, \"counter\");\n\t\t\tJavaBeanPropertyDescriptor property = new JavaBeanPropertyDescriptor(\"counter\", field.asType(),\n\t\t\t\t\townerElement, null, getMethod(ownerElement, \"setCounter\"), field, null);\n\t\t\tassertThat(property.resolveItemMetadata(\"test\", metadataEnv)).isNull();\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"deprecation\")\n\tvoid javaBeanDeprecatedPropertyOnClass() {\n\t\tprocess(org.springframework.boot.configurationsample.simple.DeprecatedProperties.class,\n\t\t\t\t(roundEnv, metadataEnv) -> {\n\t\t\t\t\tTypeElement ownerElement = roundEnv\n\t\t\t\t\t\t.getRootElement(org.springframework.boot.configurationsample.simple.DeprecatedProperties.class);\n\t\t\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"name\");\n\t\t\t\t\tassertItemMetadata(metadataEnv, property).isProperty().isDeprecatedWithNoInformation();\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanMetadataDeprecatedPropertyWithAnnotation() {\n\t\tprocess(DeprecatedSingleProperty.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(DeprecatedSingleProperty.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"name\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.isDeprecatedWithReason(\"renamed\")\n\t\t\t\t.isDeprecatedWithReplacement(\"singledeprecated.new-name\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanDeprecatedPropertyOnGetter() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"flag\", \"isFlag\", \"setFlag\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().isDeprecatedWithNoInformation();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanDeprecatedPropertyOnSetter() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().isDeprecatedWithNoInformation();\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanPropertyWithDescription() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasDescription(\"The name of this simple properties.\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaBeanPropertyWithDefaultValue() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tJavaBeanPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().hasDefaultValue(\"boot\");\n\t\t});\n\t}\n\n\tprotected JavaBeanPropertyDescriptor createPropertyDescriptor(TypeElement ownerElement, String name) {\n\t\treturn createPropertyDescriptor(ownerElement, name, createAccessorMethodName(\"get\", name),\n\t\t\t\tcreateAccessorMethodName(\"set\", name));\n\t}\n\n\tprotected JavaBeanPropertyDescriptor createPropertyDescriptor(TypeElement ownerElement, String name,\n\t\t\tString getterName, String setterName) {\n\t\tExecutableElement getter = getMethod(ownerElement, getterName);\n\t\tExecutableElement setter = getMethod(ownerElement, setterName);\n\t\tVariableElement field = getField(ownerElement, name);\n\t\treturn new JavaBeanPropertyDescriptor(name, getter.getReturnType(), ownerElement, getter, setter, field, null);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/LombokMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteDataProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteDefaultProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteExplicitProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokAccessLevelProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokInnerClassWithGetterProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleValueProperties;\nimport org.springframework.boot.configurationsample.lombok.SimpleLombokPojo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for Lombok classes.\n *\n * @author Stephane Nicoll\n */\nclass LombokMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid lombokDataProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokSimpleDataProperties.class);\n\t\tassertSimpleLombokProperties(metadata, LombokSimpleDataProperties.class, \"data\");\n\t}\n\n\t@Test\n\tvoid lombokValueProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokSimpleValueProperties.class);\n\t\tassertSimpleLombokProperties(metadata, LombokSimpleValueProperties.class, \"value\");\n\t}\n\n\t@Test\n\tvoid lombokSimpleProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokSimpleProperties.class);\n\t\tassertSimpleLombokProperties(metadata, LombokSimpleProperties.class, \"simple\");\n\t}\n\n\t@Test\n\tvoid lombokExplicitProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokExplicitProperties.class);\n\t\tassertSimpleLombokProperties(metadata, LombokExplicitProperties.class, \"explicit\");\n\t\tassertThat(metadata.getItems()).hasSize(6);\n\t}\n\n\t@Test\n\tvoid lombokAccessLevelProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokAccessLevelProperties.class);\n\t\tassertAccessLevelLombokProperties(metadata, LombokAccessLevelProperties.class, \"accesslevel\", 2);\n\t}\n\n\t@Test\n\tvoid lombokAccessLevelOverwriteDataProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokAccessLevelOverwriteDataProperties.class);\n\t\tassertAccessLevelOverwriteLombokProperties(metadata, LombokAccessLevelOverwriteDataProperties.class,\n\t\t\t\t\"accesslevel.overwrite.data\");\n\t}\n\n\t@Test\n\tvoid lombokAccessLevelOverwriteExplicitProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokAccessLevelOverwriteExplicitProperties.class);\n\t\tassertAccessLevelOverwriteLombokProperties(metadata, LombokAccessLevelOverwriteExplicitProperties.class,\n\t\t\t\t\"accesslevel.overwrite.explicit\");\n\t}\n\n\t@Test\n\tvoid lombokAccessLevelOverwriteDefaultProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokAccessLevelOverwriteDefaultProperties.class);\n\t\tassertAccessLevelOverwriteLombokProperties(metadata, LombokAccessLevelOverwriteDefaultProperties.class,\n\t\t\t\t\"accesslevel.overwrite.default\");\n\t}\n\n\t@Test\n\tvoid lombokInnerClassProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokInnerClassProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config\").fromSource(LombokInnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.first\")\n\t\t\t.ofType(LombokInnerClassProperties.Foo.class)\n\t\t\t.fromSource(LombokInnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.first.name\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.first.bar.name\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.second\", LombokInnerClassProperties.Foo.class)\n\t\t\t.fromSource(LombokInnerClassProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.second.name\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.second.bar.name\"));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.third\")\n\t\t\t.ofType(SimpleLombokPojo.class)\n\t\t\t.fromSource(LombokInnerClassProperties.class));\n\t\t// For some reason the annotation processor resolves a type for SimpleLombokPojo\n\t\t// that is resolved (compiled) and the source annotations are gone. Because we\n\t\t// don't see the @Data annotation anymore, no field is harvested. What is crazy is\n\t\t// that a sample project works fine so this seems to be related to the unit test\n\t\t// environment for some reason. assertThat(metadata,\n\t\t// containsProperty(\"config.third.value\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.fourth\"));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withGroup(\"config.fourth\"));\n\t}\n\n\t@Test\n\tvoid lombokInnerClassWithGetterProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokInnerClassWithGetterProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config\").fromSource(LombokInnerClassWithGetterProperties.class));\n\t\tassertThat(metadata).has(Metadata.withGroup(\"config.first\")\n\t\t\t.ofType(LombokInnerClassWithGetterProperties.Foo.class)\n\t\t\t.fromSourceMethod(\"getFirst()\")\n\t\t\t.fromSource(LombokInnerClassWithGetterProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"config.first.name\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\tprivate void assertSimpleLombokProperties(ConfigurationMetadata metadata, Class<?> source, String prefix) {\n\t\tassertThat(metadata).has(Metadata.withGroup(prefix).fromSource(source));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(prefix + \".id\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(prefix + \".name\", String.class)\n\t\t\t.fromSource(source)\n\t\t\t.withDescription(\"Name description.\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(prefix + \".description\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(prefix + \".counter\"));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(prefix + \".number\").fromSource(source).withDefaultValue(0).withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(prefix + \".items\"));\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(prefix + \".ignored\"));\n\t}\n\n\tprivate void assertAccessLevelOverwriteLombokProperties(ConfigurationMetadata metadata, Class<?> source,\n\t\t\tString prefix) {\n\t\tassertAccessLevelLombokProperties(metadata, source, prefix, 7);\n\t}\n\n\tprivate void assertAccessLevelLombokProperties(ConfigurationMetadata metadata, Class<?> source, String prefix,\n\t\t\tint countNameFields) {\n\t\tassertThat(metadata).has(Metadata.withGroup(prefix).fromSource(source));\n\t\tfor (int i = 0; i < countNameFields; i++) {\n\t\t\tassertThat(metadata).has(Metadata.withProperty(prefix + \".name\" + i, String.class));\n\t\t}\n\t\tassertThat(metadata.getItems()).hasSize(1 + countNameFields);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/LombokPropertyDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationsample.lombok.LombokDefaultValueProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokDeprecatedSingleProperty;\nimport org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleValueProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleProperties;\nimport org.springframework.boot.configurationsample.specific.InnerClassProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LombokPropertyDescriptor}.\n *\n * @author Stephane Nicoll\n */\nclass LombokPropertyDescriptorTests extends PropertyDescriptorTests {\n\n\t@Test\n\tvoid lombokSimpleProperty() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"name\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"name\");\n\t\t\tassertThat(property.getField().getSimpleName()).hasToString(\"name\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isTrue();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokCollectionProperty() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"items\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"items\");\n\t\t\tassertThat(property.getField().getSimpleName()).hasToString(\"items\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isTrue();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokNestedPropertySameClass() {\n\t\tprocess(LombokInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokInnerClassProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"first\");\n\t\t\tassertThat(property.getField().getSimpleName()).hasToString(\"first\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokNestedPropertyWithAnnotation() {\n\t\tprocess(LombokInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokInnerClassProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"third\");\n\t\t\tassertThat(property.getName()).isEqualTo(\"third\");\n\t\t\tassertThat(property.getField().getSimpleName()).hasToString(\"third\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokSimplePropertyWithOnlyGetterOnClassShouldNotBeExposed() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"ignored\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokSimplePropertyWithOnlyGetterOnDataClassShouldNotBeExposed() {\n\t\tprocess(LombokSimpleDataProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleDataProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"ignored\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokSimplePropertyWithOnlyGetterOnValueClassShouldNotBeExposed() {\n\t\tprocess(LombokSimpleValueProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleValueProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"ignored\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokSimplePropertyWithOnlyGetterOnFieldShouldNotBeExposed() {\n\t\tprocess(LombokExplicitProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokExplicitProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"ignoredOnlyGetter\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokSimplePropertyWithOnlySetterOnFieldShouldNotBeExposed() {\n\t\tprocess(LombokExplicitProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokExplicitProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"ignoredOnlySetter\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokMetadataSimpleProperty() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"description\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasName(\"test.description\")\n\t\t\t\t.hasType(String.class)\n\t\t\t\t.hasSourceType(LombokSimpleProperties.class)\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokMetadataCollectionProperty() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"items\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty()\n\t\t\t\t.hasName(\"test.items\")\n\t\t\t\t.hasType(\"java.util.List<java.lang.String>\")\n\t\t\t\t.hasSourceType(LombokSimpleProperties.class)\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokMetadataNestedGroup() {\n\t\tprocess(LombokInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokInnerClassProperties.class);\n\t\t\tVariableElement field = getField(ownerElement, \"third\");\n\t\t\tExecutableElement getter = getMethod(ownerElement, \"getThird\");\n\t\t\tLombokPropertyDescriptor property = new LombokPropertyDescriptor(\"third\", field.asType(), ownerElement,\n\t\t\t\t\tgetter, null, field, null);\n\t\t\tassertItemMetadata(metadataEnv, property).isGroup()\n\t\t\t\t.hasName(\"test.third\")\n\t\t\t\t.hasType(\"org.springframework.boot.configurationsample.lombok.SimpleLombokPojo\")\n\t\t\t\t.hasSourceType(LombokInnerClassProperties.class)\n\t\t\t\t.hasSourceMethod(\"getThird()\")\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokMetadataNestedGroupNoGetter() {\n\t\tprocess(LombokInnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokInnerClassProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertItemMetadata(metadataEnv, property).isGroup()\n\t\t\t\t.hasName(\"test.first\")\n\t\t\t\t.hasType(\"org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties$Foo\")\n\t\t\t\t.hasSourceType(LombokInnerClassProperties.class)\n\t\t\t\t.hasSourceMethod(null)\n\t\t\t\t.hasNoDescription()\n\t\t\t\t.isNotDeprecated();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokMetadataNotACandidatePropertyShouldReturnNull() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"ignored\");\n\t\t\tassertThat(property.resolveItemMetadata(\"test\", metadataEnv)).isNull();\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"deprecation\")\n\tvoid lombokDeprecatedPropertyOnClass() {\n\t\tprocess(org.springframework.boot.configurationsample.lombok.LombokDeprecatedProperties.class,\n\t\t\t\t(roundEnv, metadataEnv) -> {\n\t\t\t\t\tTypeElement ownerElement = roundEnv.getRootElement(\n\t\t\t\t\t\t\torg.springframework.boot.configurationsample.lombok.LombokDeprecatedProperties.class);\n\t\t\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"name\");\n\t\t\t\t\tassertItemMetadata(metadataEnv, property).isProperty().isDeprecatedWithNoInformation();\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid lombokDeprecatedPropertyOnField() {\n\t\tprocess(LombokDeprecatedSingleProperty.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokDeprecatedSingleProperty.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"name\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().isDeprecatedWithNoInformation();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokPropertyWithDescription() {\n\t\tprocess(LombokSimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokSimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"name\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().hasDescription(\"Name description.\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokPropertyWithDefaultValue() {\n\t\tprocess(LombokDefaultValueProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(LombokDefaultValueProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"description\");\n\t\t\tassertItemMetadata(metadataEnv, property).isProperty().hasDefaultValue(\"my description\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokPropertyNotCandidate() {\n\t\tprocess(SimpleProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(SimpleProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"theName\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid lombokNestedPropertyNotCandidate() {\n\t\tprocess(InnerClassProperties.class, (roundEnv, metadataEnv) -> {\n\t\t\tTypeElement ownerElement = roundEnv.getRootElement(InnerClassProperties.class);\n\t\t\tLombokPropertyDescriptor property = createPropertyDescriptor(ownerElement, \"first\");\n\t\t\tassertThat(property.isProperty(metadataEnv)).isFalse();\n\t\t\tassertThat(property.isNested(metadataEnv)).isFalse();\n\t\t});\n\t}\n\n\tprotected LombokPropertyDescriptor createPropertyDescriptor(TypeElement ownerElement, String name) {\n\t\tVariableElement field = getField(ownerElement, name);\n\t\tExecutableElement getter = getMethod(ownerElement, createAccessorMethodName(\"get\", name));\n\t\tExecutableElement setter = getMethod(ownerElement, createAccessorMethodName(\"set\", name));\n\t\treturn new LombokPropertyDescriptor(name, field.asType(), ownerElement, getter, setter, field, null);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MergeMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.json.JSONArray;\nimport org.springframework.boot.configurationprocessor.json.JSONObject;\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationprocessor.metadata.TestJsonConverter;\nimport org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty;\nimport org.springframework.boot.configurationsample.simple.SimpleProperties;\nimport org.springframework.boot.configurationsample.specific.SimpleConflictingProperties;\nimport org.springframework.core.test.tools.CompilationException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Metadata generation tests for merging additional metadata.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass MergeMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid mergingOfAdditionalProperty() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(null, \"foo\", \"java.lang.String\",\n\t\t\t\tAdditionalMetadata.class.getName(), null, null, null, null);\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.comparator\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo\", String.class).fromSource(AdditionalMetadata.class));\n\t}\n\n\t@Test\n\tvoid mergingOfAdditionalPropertyMatchingGroup() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(null, \"simple\", \"java.lang.String\", null, null, null, null,\n\t\t\t\tnull);\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"simple\").fromSource(SimpleProperties.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple\", String.class));\n\t}\n\n\t@Test\n\tvoid mergeExistingPropertyDefaultValue() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(\"simple\", \"flag\", null, null, null, null, true, null);\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.flag\", Boolean.class)\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"A simple flag.\")\n\t\t\t.withDeprecation()\n\t\t\t.withDefaultValue(true));\n\t\tassertThat(metadata.getItems()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid mergeExistingPropertyWithSeveralCandidates() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(\"simple\", \"flag\", Boolean.class.getName(), null, null, null,\n\t\t\t\ttrue, null);\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class,\n\t\t\t\tSimpleConflictingProperties.class);\n\t\tassertThat(metadata.getItems()).hasSize(6);\n\t\tList<ItemMetadata> items = metadata.getItems()\n\t\t\t.stream()\n\t\t\t.filter((item) -> item.getName().equals(\"simple.flag\"))\n\t\t\t.toList();\n\t\tassertThat(items).hasSize(2);\n\t\tItemMetadata matchingProperty = items.stream()\n\t\t\t.filter((item) -> item.getType().equals(Boolean.class.getName()))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t\tassertThat(matchingProperty).isNotNull();\n\t\tassertThat(matchingProperty.getDefaultValue()).isEqualTo(true);\n\t\tassertThat(matchingProperty.getSourceType()).isEqualTo(SimpleProperties.class.getName());\n\t\tassertThat(matchingProperty.getDescription()).isEqualTo(\"A simple flag.\");\n\t\tItemMetadata nonMatchingProperty = items.stream()\n\t\t\t.filter((item) -> item.getType().equals(String.class.getName()))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t\tassertThat(nonMatchingProperty).isNotNull();\n\t\tassertThat(nonMatchingProperty.getDefaultValue()).isEqualTo(\"hello\");\n\t\tassertThat(nonMatchingProperty.getSourceType()).isEqualTo(SimpleConflictingProperties.class.getName());\n\t\tassertThat(nonMatchingProperty.getDescription()).isNull();\n\t}\n\n\t@Test\n\tvoid mergeExistingPropertyDescription() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(\"simple\", \"comparator\", null, null, null, \"A nice comparator.\",\n\t\t\t\tnull, null);\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.comparator\", \"java.util.Comparator<?>\")\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"A nice comparator.\"));\n\t\tassertThat(metadata.getItems()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid mergeExistingPropertyDeprecation() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(\"simple\", \"comparator\", null, null, null, null, null,\n\t\t\t\tnew ItemDeprecation(\"Don't use this.\", \"simple.complex-comparator\", \"1.2.3\", \"error\"));\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.comparator\", \"java.util.Comparator<?>\")\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDeprecation(\"Don't use this.\", \"simple.complex-comparator\", \"1.2.3\", \"error\"));\n\t\tassertThat(metadata.getItems()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid mergeExistingPropertyDeprecationOverride() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(\"singledeprecated\", \"name\", null, null, null, null, null,\n\t\t\t\tnew ItemDeprecation(\"Don't use this.\", \"single.name\", \"1.2.3\"));\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, DeprecatedSingleProperty.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"singledeprecated.name\", String.class.getName())\n\t\t\t.fromSource(DeprecatedSingleProperty.class)\n\t\t\t.withDeprecation(\"Don't use this.\", \"single.name\", \"1.2.3\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid mergeExistingPropertyDeprecationOverrideLevel() throws Exception {\n\t\tItemMetadata property = ItemMetadata.newProperty(\"singledeprecated\", \"name\", null, null, null, null, null,\n\t\t\t\tnew ItemDeprecation(null, null, null, \"error\"));\n\t\tString additionalMetadata = buildAdditionalMetadata(property);\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, DeprecatedSingleProperty.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"singledeprecated.name\", String.class.getName())\n\t\t\t.fromSource(DeprecatedSingleProperty.class)\n\t\t\t.withDeprecation(\"renamed\", \"singledeprecated.new-name\", \"1.2.3\", \"error\"));\n\t\tassertThat(metadata.getItems()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid mergeOfInvalidAdditionalMetadata() {\n\t\tString metadata = \"Hello World\";\n\t\tassertThatExceptionOfType(CompilationException.class)\n\t\t\t.isThrownBy(() -> compile(metadata, SimpleProperties.class))\n\t\t\t.withMessageContaining(\"Invalid additional meta-data\");\n\t}\n\n\t@Test\n\tvoid mergingOfSimpleHint() throws Exception {\n\t\tString hints = buildAdditionalHints(ItemHint.newHint(\"simple.the-name\",\n\t\t\t\tnew ItemHint.ValueHint(\"boot\", \"Bla bla\"), new ItemHint.ValueHint(\"spring\", null)));\n\t\tConfigurationMetadata metadata = compile(hints, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.the-name\", String.class)\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"The name of this simple properties.\")\n\t\t\t.withDefaultValue(\"boot\")\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withHint(\"simple.the-name\").withValue(0, \"boot\", \"Bla bla\").withValue(1, \"spring\", null));\n\t}\n\n\t@Test\n\tvoid mergingOfHintWithNonCanonicalName() throws Exception {\n\t\tString hints = buildAdditionalHints(\n\t\t\t\tItemHint.newHint(\"simple.theName\", new ItemHint.ValueHint(\"boot\", \"Bla bla\")));\n\t\tConfigurationMetadata metadata = compile(hints, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.the-name\", String.class)\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"The name of this simple properties.\")\n\t\t\t.withDefaultValue(\"boot\")\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withHint(\"simple.the-name\").withValue(0, \"boot\", \"Bla bla\"));\n\t}\n\n\t@Test\n\tvoid mergingOfHintWithProvider() throws Exception {\n\t\tString hints = buildAdditionalHints(new ItemHint(\"simple.theName\", Collections.emptyList(),\n\t\t\t\tArrays.asList(new ItemHint.ValueProvider(\"first\", Collections.singletonMap(\"target\", \"org.foo\")),\n\t\t\t\t\t\tnew ItemHint.ValueProvider(\"second\", null))));\n\t\tConfigurationMetadata metadata = compile(hints, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.the-name\", String.class)\n\t\t\t.fromSource(SimpleProperties.class)\n\t\t\t.withDescription(\"The name of this simple properties.\")\n\t\t\t.withDefaultValue(\"boot\")\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(\n\t\t\t\tMetadata.withHint(\"simple.the-name\").withProvider(\"first\", \"target\", \"org.foo\").withProvider(\"second\"));\n\t}\n\n\t@Test\n\tvoid mergingOfAdditionalDeprecation() throws Exception {\n\t\tString deprecations = buildPropertyDeprecations(\n\t\t\t\tItemMetadata.newProperty(\"simple\", \"wrongName\", \"java.lang.String\", null, null, null, null,\n\t\t\t\t\t\tnew ItemDeprecation(\"Lame name.\", \"simple.the-name\", \"1.2.3\")));\n\t\tConfigurationMetadata metadata = compile(deprecations, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.wrong-name\", String.class)\n\t\t\t.withDeprecation(\"Lame name.\", \"simple.the-name\", \"1.2.3\"));\n\t}\n\n\t@Test\n\tvoid mergingOfAdditionalMetadata() throws Exception {\n\t\tJSONObject property = new JSONObject();\n\t\tproperty.put(\"name\", \"foo\");\n\t\tproperty.put(\"type\", \"java.lang.String\");\n\t\tproperty.put(\"sourceType\", AdditionalMetadata.class.getName());\n\t\tJSONArray properties = new JSONArray();\n\t\tproperties.put(property);\n\t\tJSONObject json = new JSONObject();\n\t\tjson.put(\"properties\", properties);\n\t\tString additionalMetadata = json.toString();\n\t\tConfigurationMetadata metadata = compile(additionalMetadata, SimpleProperties.class);\n\t\tassertThat(metadata).has(Metadata.withProperty(\"simple.comparator\"));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo\", String.class).fromSource(AdditionalMetadata.class));\n\t}\n\n\tprivate String buildAdditionalMetadata(ItemMetadata... metadata) throws Exception {\n\t\tTestJsonConverter converter = new TestJsonConverter();\n\t\tJSONObject additionalMetadata = new JSONObject();\n\t\tJSONArray properties = new JSONArray();\n\t\tfor (ItemMetadata itemMetadata : metadata) {\n\t\t\tproperties.put(converter.toJsonObject(itemMetadata));\n\t\t}\n\t\tadditionalMetadata.put(\"properties\", properties);\n\t\treturn additionalMetadata.toString();\n\t}\n\n\tprivate String buildAdditionalHints(ItemHint... hints) throws Exception {\n\t\tTestJsonConverter converter = new TestJsonConverter();\n\t\tJSONObject additionalMetadata = new JSONObject();\n\t\tadditionalMetadata.put(\"hints\", converter.toJsonArray(Arrays.asList(hints)));\n\t\treturn additionalMetadata.toString();\n\t}\n\n\tprivate String buildPropertyDeprecations(ItemMetadata... items) throws Exception {\n\t\tJSONArray propertiesArray = new JSONArray();\n\t\tfor (ItemMetadata item : items) {\n\t\t\tJSONObject jsonObject = new JSONObject();\n\t\t\tjsonObject.put(\"name\", item.getName());\n\t\t\tif (item.getType() != null) {\n\t\t\t\tjsonObject.put(\"type\", item.getType());\n\t\t\t}\n\t\t\tItemDeprecation deprecation = item.getDeprecation();\n\t\t\tif (deprecation != null) {\n\t\t\t\tJSONObject deprecationJson = new JSONObject();\n\t\t\t\tif (deprecation.getReason() != null) {\n\t\t\t\t\tdeprecationJson.put(\"reason\", deprecation.getReason());\n\t\t\t\t}\n\t\t\t\tif (deprecation.getReplacement() != null) {\n\t\t\t\t\tdeprecationJson.put(\"replacement\", deprecation.getReplacement());\n\t\t\t\t}\n\t\t\t\tif (deprecation.getSince() != null) {\n\t\t\t\t\tdeprecationJson.put(\"since\", deprecation.getSince());\n\t\t\t\t}\n\t\t\t\tjsonObject.put(\"deprecation\", deprecationJson);\n\t\t\t}\n\t\t\tpropertiesArray.put(jsonObject);\n\n\t\t}\n\t\tJSONObject additionalMetadata = new JSONObject();\n\t\tadditionalMetadata.put(\"properties\", propertiesArray);\n\t\treturn additionalMetadata.toString();\n\t}\n\n\tstatic class AdditionalMetadata {\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MetadataCollectorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.io.ByteArrayInputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint.ValueHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetadataCollector}.\n *\n * @author Stephane Nicoll\n */\nclass MetadataCollectorTests {\n\n\tprivate static final Predicate<ItemMetadata> NO_MERGE = (metadata) -> false;\n\n\tprivate static final ConfigurationMetadata SINGLE_ITEM_METADATA = readMetadata(\"\"\"\n\t\t\t{\n\t\t\t\t\"properties\": [\n\t\t\t\t\t{ \"name\": \"name\", \"type\": \"java.lang.String\" }\n\t\t\t\t]\n\t\t\t}\n\t\t\t\"\"\");\n\n\t@Test\n\tvoid addSingleItemMetadata() {\n\t\tMetadataCollector collector = createSimpleCollector();\n\t\tcollector.add(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tassertThat(collector.getMetadata()).has(Metadata.withProperty(\"name\", String.class));\n\t}\n\n\t@Test\n\tvoid addIfAbsentAddsPropertyIfItDoesNotExist() {\n\t\tMetadataCollector collector = createSimpleCollector();\n\t\tcollector.addIfAbsent(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tConfigurationMetadata metadata = collector.getMetadata();\n\t\tassertThat(metadata).has(Metadata.withProperty(\"name\", String.class));\n\t\tassertThat(metadata.getItems()).hasSize(1);\n\t}\n\n\t@Test\n\tvoid addIfAbsentIgnoresExistingProperty() {\n\t\tMetadataCollector collector = createSimpleCollector();\n\t\tcollector.addIfAbsent(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tcollector.addIfAbsent(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tcollector.addIfAbsent(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tConfigurationMetadata metadata = collector.getMetadata();\n\t\tassertThat(metadata).has(Metadata.withProperty(\"name\", String.class));\n\t\tassertThat(metadata.getItems()).hasSize(1);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid addNewMetadataDoesNotInvokeConflictResolution() {\n\t\tMetadataCollector collector = createSimpleCollector();\n\t\tConsumer<ItemMetadata> conflictResolution = mock(Consumer.class);\n\t\tcollector.add(SINGLE_ITEM_METADATA.getItems().get(0), conflictResolution);\n\t\tthen(conflictResolution).shouldHaveNoInteractions();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid addMetadataWithExistingInstanceInvokesConflictResolution() {\n\t\tMetadataCollector collector = createSimpleCollector();\n\t\tItemMetadata metadata = SINGLE_ITEM_METADATA.getItems().get(0);\n\t\tcollector.add(metadata);\n\t\tConsumer<ItemMetadata> conflictResolution = mock(Consumer.class);\n\t\tcollector.add(metadata, conflictResolution);\n\t\tthen(conflictResolution).should().accept(metadata);\n\t}\n\n\t@Test\n\tvoid addSingleItemHint() {\n\t\tMetadataCollector collector = createSimpleCollector();\n\t\tcollector.add(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tValueHint firstValueHint = new ValueHint(\"one\", \"First.\");\n\t\tValueHint secondValueHint = new ValueHint(\"two\", \"Second.\");\n\t\tItemHint itemHint = new ItemHint(\"name\", List.of(firstValueHint, secondValueHint), Collections.emptyList());\n\t\tcollector.add(itemHint);\n\t\tassertThat(collector.getMetadata())\n\t\t\t.has(Metadata.withHint(\"name\").withValue(0, \"one\", \"First.\").withValue(1, \"two\", \"Second.\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getMetadataDoesNotInvokeMergeFunctionIfPreviousMetadataIsNull() {\n\t\tPredicate<ItemMetadata> mergedRequired = mock(Predicate.class);\n\t\tMetadataCollector collector = new MetadataCollector(mergedRequired, null);\n\t\tcollector.add(SINGLE_ITEM_METADATA.getItems().get(0));\n\t\tcollector.getMetadata();\n\t\tthen(mergedRequired).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getMetadataAddPreviousItemIfMergeFunctionReturnsTrue() {\n\t\tPredicate<ItemMetadata> mergedRequired = mock(Predicate.class);\n\t\tItemMetadata itemMetadata = SINGLE_ITEM_METADATA.getItems().get(0);\n\t\tgiven(mergedRequired.test(itemMetadata)).willReturn(true);\n\t\tMetadataCollector collector = new MetadataCollector(mergedRequired, SINGLE_ITEM_METADATA);\n\t\tassertThat(collector.getMetadata()).has(Metadata.withProperty(\"name\", String.class));\n\t\tthen(mergedRequired).should().test(itemMetadata);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getMetadataDoesNotAddPreviousItemIfMergeFunctionReturnsFalse() {\n\t\tPredicate<ItemMetadata> mergedRequired = mock(Predicate.class);\n\t\tItemMetadata itemMetadata = SINGLE_ITEM_METADATA.getItems().get(0);\n\t\tgiven(mergedRequired.test(itemMetadata)).willReturn(false);\n\t\tMetadataCollector collector = new MetadataCollector(mergedRequired, SINGLE_ITEM_METADATA);\n\t\tassertThat(collector.getMetadata().getItems()).isEmpty();\n\t\tthen(mergedRequired).should().test(itemMetadata);\n\t}\n\n\tprivate MetadataCollector createSimpleCollector() {\n\t\treturn new MetadataCollector(NO_MERGE, null);\n\t}\n\n\tprivate static ConfigurationMetadata readMetadata(String json) {\n\t\ttry {\n\t\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\t\treturn marshaller.read(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid JSON: \" + json, ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MetadataGenerationEnvironmentFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport javax.annotation.processing.ProcessingEnvironment;\n\nimport org.springframework.boot.configurationprocessor.test.TestConfigurationMetadataAnnotationProcessor;\n\n/**\n * A factory for {@link MetadataGenerationEnvironment} against test annotations.\n *\n * @author Stephane Nicoll\n */\nclass MetadataGenerationEnvironmentFactory implements Function<ProcessingEnvironment, MetadataGenerationEnvironment> {\n\n\t@Override\n\tpublic MetadataGenerationEnvironment apply(ProcessingEnvironment environment) {\n\t\tSet<String> endpointAnnotations = new HashSet<>(\n\t\t\t\tArrays.asList(TestConfigurationMetadataAnnotationProcessor.CONTROLLER_ENDPOINT_ANNOTATION,\n\t\t\t\t\t\tTestConfigurationMetadataAnnotationProcessor.ENDPOINT_ANNOTATION,\n\t\t\t\t\t\tTestConfigurationMetadataAnnotationProcessor.REST_CONTROLLER_ENDPOINT_ANNOTATION,\n\t\t\t\t\t\tTestConfigurationMetadataAnnotationProcessor.SERVLET_ENDPOINT_ANNOTATION,\n\t\t\t\t\t\tTestConfigurationMetadataAnnotationProcessor.WEB_ENDPOINT_ANNOTATION));\n\t\treturn new MetadataGenerationEnvironment(environment,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.NESTED_CONFIGURATION_PROPERTY_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.CONSTRUCTOR_BINDING_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.AUTOWIRED_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.DEFAULT_VALUE_ANNOTATION, endpointAnnotations,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.READ_OPERATION_ANNOTATION,\n\t\t\t\tTestConfigurationMetadataAnnotationProcessor.NAME_ANNOTATION);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MetadataStoreTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport javax.annotation.processing.ProcessingEnvironment;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetadataStore}.\n *\n * @author Andy Wilkinson\n */\nclass MetadataStoreTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprivate final ProcessingEnvironment environment = mock(ProcessingEnvironment.class);\n\n\tprivate final MetadataStore metadataStore = new MetadataStore(this.environment, mock(TypeUtils.class));\n\n\t@Test\n\tvoid additionalMetadataIsLocatedInMavenBuild() throws IOException {\n\t\tFile app = new File(this.tempDir, \"app\");\n\t\tFile classesLocation = new File(app, \"target/classes\");\n\t\tFile metaInf = new File(classesLocation, \"META-INF\");\n\t\tmetaInf.mkdirs();\n\t\tFile additionalMetadata = new File(metaInf, \"additional-spring-configuration-metadata.json\");\n\t\tadditionalMetadata.createNewFile();\n\t\tassertThat(this.metadataStore.locateAdditionalMetadataFile(\n\t\t\t\tnew File(classesLocation, \"META-INF/additional-spring-configuration-metadata.json\"),\n\t\t\t\t\"META-INF/additional-spring-configuration-metadata.json\"))\n\t\t\t.isEqualTo(additionalMetadata);\n\t}\n\n\t@Test\n\tvoid additionalMetadataIsLocatedInGradle3Build() throws IOException {\n\t\tFile app = new File(this.tempDir, \"app\");\n\t\tFile classesLocation = new File(app, \"build/classes/main\");\n\t\tFile resourcesLocation = new File(app, \"build/resources/main\");\n\t\tFile metaInf = new File(resourcesLocation, \"META-INF\");\n\t\tmetaInf.mkdirs();\n\t\tFile additionalMetadata = new File(metaInf, \"additional-spring-configuration-metadata.json\");\n\t\tadditionalMetadata.createNewFile();\n\t\tassertThat(this.metadataStore.locateAdditionalMetadataFile(\n\t\t\t\tnew File(classesLocation, \"META-INF/additional-spring-configuration-metadata.json\"),\n\t\t\t\t\"META-INF/additional-spring-configuration-metadata.json\"))\n\t\t\t.isEqualTo(additionalMetadata);\n\t}\n\n\t@Test\n\tvoid additionalMetadataIsLocatedInGradle4Build() throws IOException {\n\t\tFile app = new File(this.tempDir, \"app\");\n\t\tFile classesLocation = new File(app, \"build/classes/java/main\");\n\t\tFile resourcesLocation = new File(app, \"build/resources/main\");\n\t\tFile metaInf = new File(resourcesLocation, \"META-INF\");\n\t\tmetaInf.mkdirs();\n\t\tFile additionalMetadata = new File(metaInf, \"additional-spring-configuration-metadata.json\");\n\t\tadditionalMetadata.createNewFile();\n\t\tassertThat(this.metadataStore.locateAdditionalMetadataFile(\n\t\t\t\tnew File(classesLocation, \"META-INF/additional-spring-configuration-metadata.json\"),\n\t\t\t\t\"META-INF/additional-spring-configuration-metadata.json\"))\n\t\t\t.isEqualTo(additionalMetadata);\n\t}\n\n\t@Test\n\tvoid additionalMetadataIsLocatedUsingLocationsOption() throws IOException {\n\t\tFile app = new File(this.tempDir, \"app\");\n\t\tFile location = new File(app, \"src/main/resources\");\n\t\tFile metaInf = new File(location, \"META-INF\");\n\t\tmetaInf.mkdirs();\n\t\tFile additionalMetadata = new File(metaInf, \"additional-spring-configuration-metadata.json\");\n\t\tadditionalMetadata.createNewFile();\n\t\tgiven(this.environment.getOptions()).willReturn(\n\t\t\t\tCollections.singletonMap(ConfigurationMetadataAnnotationProcessor.ADDITIONAL_METADATA_LOCATIONS_OPTION,\n\t\t\t\t\t\tlocation.getAbsolutePath()));\n\t\tassertThat(this.metadataStore.locateAdditionalMetadataFile(new File(app, \"foo\"),\n\t\t\t\t\"META-INF/additional-spring-configuration-metadata.json\"))\n\t\t\t.isEqualTo(additionalMetadata);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MethodBasedMetadataGenerationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.method.DeprecatedMethodConfig;\nimport org.springframework.boot.configurationsample.method.EmptyTypeMethodConfig;\nimport org.springframework.boot.configurationsample.method.InvalidMethodConfig;\nimport org.springframework.boot.configurationsample.method.MethodAndClassConfig;\nimport org.springframework.boot.configurationsample.method.PackagePrivateMethodConfig;\nimport org.springframework.boot.configurationsample.method.PrivateMethodConfig;\nimport org.springframework.boot.configurationsample.method.ProtectedMethodConfig;\nimport org.springframework.boot.configurationsample.method.PublicMethodConfig;\nimport org.springframework.boot.configurationsample.method.SingleConstructorMethodConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for types defined by {@code @Bean} methods.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass MethodBasedMetadataGenerationTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid publicMethodConfig() {\n\t\tmethodConfig(PublicMethodConfig.class, PublicMethodConfig.Foo.class);\n\t}\n\n\t@Test\n\tvoid protectedMethodConfig() {\n\t\tmethodConfig(ProtectedMethodConfig.class, ProtectedMethodConfig.Foo.class);\n\t}\n\n\t@Test\n\tvoid packagePrivateMethodConfig() {\n\t\tmethodConfig(PackagePrivateMethodConfig.class, PackagePrivateMethodConfig.Foo.class);\n\t}\n\n\tprivate void methodConfig(Class<?> config, Class<?> properties) {\n\t\tConfigurationMetadata metadata = compile(config);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"foo\").fromSource(config));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.name\", String.class).fromSource(properties));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"foo.flag\", Boolean.class).withDefaultValue(false).fromSource(properties));\n\t}\n\n\t@Test\n\tvoid privateMethodConfig() {\n\t\tConfigurationMetadata metadata = compile(PrivateMethodConfig.class);\n\t\tassertThat(metadata).isNull();\n\t}\n\n\t@Test\n\tvoid invalidMethodConfig() {\n\t\tConfigurationMetadata metadata = compile(InvalidMethodConfig.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"something.name\", String.class).fromSource(InvalidMethodConfig.class));\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"invalid.name\"));\n\t}\n\n\t@Test\n\tvoid methodAndClassConfig() {\n\t\tConfigurationMetadata metadata = compile(MethodAndClassConfig.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"conflict.name\", String.class).fromSource(MethodAndClassConfig.Foo.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"conflict.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.fromSource(MethodAndClassConfig.Foo.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"conflict.value\", String.class).fromSource(MethodAndClassConfig.class));\n\t}\n\n\t@Test\n\tvoid singleConstructorMethodConfig() {\n\t\tConfigurationMetadata metadata = compile(SingleConstructorMethodConfig.class);\n\t\tassertThat(metadata).doesNotHave(Metadata.withProperty(\"foo.my-service\", Object.class)\n\t\t\t.fromSource(SingleConstructorMethodConfig.Foo.class));\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"foo.name\", String.class).fromSource(SingleConstructorMethodConfig.Foo.class));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.fromSource(SingleConstructorMethodConfig.Foo.class));\n\t}\n\n\t@Test\n\tvoid emptyTypeMethodConfig() {\n\t\tConfigurationMetadata metadata = compile(EmptyTypeMethodConfig.class);\n\t\tassertThat(metadata).isNotEqualTo(Metadata.withProperty(\"something.foo\"));\n\t}\n\n\t@Test\n\tvoid deprecatedMethodConfig() {\n\t\tClass<DeprecatedMethodConfig> type = DeprecatedMethodConfig.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"foo\").fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.name\", String.class)\n\t\t\t.fromSource(DeprecatedMethodConfig.Foo.class)\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.fromSource(DeprecatedMethodConfig.Foo.class)\n\t\t\t.withDeprecation());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"deprecation\")\n\tvoid deprecatedMethodConfigOnClass() {\n\t\tClass<?> type = org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.class;\n\t\tConfigurationMetadata metadata = compile(type);\n\t\tassertThat(metadata).has(Metadata.withGroup(\"foo\").fromSource(type));\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.name\", String.class)\n\t\t\t.fromSource(org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.Foo.class)\n\t\t\t.withDeprecation());\n\t\tassertThat(metadata).has(Metadata.withProperty(\"foo.flag\", Boolean.class)\n\t\t\t.withDefaultValue(false)\n\t\t\t.fromSource(org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.Foo.class)\n\t\t\t.withDeprecation());\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/NameAnnotationPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.Metadata;\nimport org.springframework.boot.configurationsample.name.ConstructorParameterNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.name.JavaBeanNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.name.LombokNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.name.RecordComponentNameAnnotationProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Metadata generation tests for using {@code @Name}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass NameAnnotationPropertiesTests extends AbstractMetadataGenerationTests {\n\n\t@Test\n\tvoid constructorParameterNameAnnotationProperties() {\n\t\tConfigurationMetadata metadata = compile(ConstructorParameterNameAnnotationProperties.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"named.import\", String.class)\n\t\t\t\t.fromSource(ConstructorParameterNameAnnotationProperties.class)\n\t\t\t\t.withDescription(\"Imports to apply.\"))\n\t\t\t.has(Metadata.withProperty(\"named.default\", Boolean.class)\n\t\t\t\t.fromSource(ConstructorParameterNameAnnotationProperties.class)\n\t\t\t\t.withDefaultValue(\"Whether default mode is enabled.\")\n\t\t\t\t.withDefaultValue(true));\n\t}\n\n\t@Test\n\tvoid recordComponentNameAnnotationProperties() {\n\t\tConfigurationMetadata metadata = compile(RecordComponentNameAnnotationProperties.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"named.import\", String.class)\n\t\t\t\t.fromSource(RecordComponentNameAnnotationProperties.class)\n\t\t\t\t.withDescription(\"Imports to apply.\"))\n\t\t\t.has(Metadata.withProperty(\"named.default\", Boolean.class)\n\t\t\t\t.fromSource(RecordComponentNameAnnotationProperties.class)\n\t\t\t\t.withDefaultValue(\"Whether default mode is enabled.\")\n\t\t\t\t.withDefaultValue(true));\n\t}\n\n\t@Test\n\tvoid javaBeanNameAnnotationProperties() {\n\t\tConfigurationMetadata metadata = compile(JavaBeanNameAnnotationProperties.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"named.import\", String.class)\n\t\t\t\t.fromSource(JavaBeanNameAnnotationProperties.class)\n\t\t\t\t.withDescription(\"Imports to apply.\"))\n\t\t\t.has(Metadata.withProperty(\"named.default\", Boolean.class)\n\t\t\t\t.fromSource(JavaBeanNameAnnotationProperties.class)\n\t\t\t\t.withDefaultValue(\"Whether default mode is enabled.\")\n\t\t\t\t.withDefaultValue(true));\n\t}\n\n\t@Test\n\tvoid lombokNameAnnotationProperties() {\n\t\tConfigurationMetadata metadata = compile(LombokNameAnnotationProperties.class);\n\t\tassertThat(metadata)\n\t\t\t.has(Metadata.withProperty(\"named.import\", String.class)\n\t\t\t\t.fromSource(LombokNameAnnotationProperties.class)\n\t\t\t\t.withDescription(\"Imports to apply.\"))\n\t\t\t.has(Metadata.withProperty(\"named.default\", Boolean.class)\n\t\t\t\t.fromSource(LombokNameAnnotationProperties.class)\n\t\t\t\t.withDefaultValue(\"Whether default mode is enabled.\")\n\t\t\t\t.withDefaultValue(true));\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/PropertyDescriptorResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport javax.lang.model.element.TypeElement;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.test.RoundEnvironmentTester;\nimport org.springframework.boot.configurationprocessor.test.TestableAnnotationProcessor;\nimport org.springframework.boot.configurationsample.immutable.ImmutableClassConstructorBindingProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutableDeducedConstructorBindingProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutableMultiConstructorProperties;\nimport org.springframework.boot.configurationsample.immutable.ImmutableSimpleProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokExplicitProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleProperties;\nimport org.springframework.boot.configurationsample.lombok.LombokSimpleValueProperties;\nimport org.springframework.boot.configurationsample.name.ConstructorParameterNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.name.JavaBeanNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.name.LombokNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.name.RecordComponentNameAnnotationProperties;\nimport org.springframework.boot.configurationsample.simple.AutowiredProperties;\nimport org.springframework.boot.configurationsample.simple.HierarchicalProperties;\nimport org.springframework.boot.configurationsample.simple.HierarchicalPropertiesGrandparent;\nimport org.springframework.boot.configurationsample.simple.HierarchicalPropertiesParent;\nimport org.springframework.boot.configurationsample.simple.SimpleProperties;\nimport org.springframework.boot.configurationsample.specific.TwoConstructorsExample;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertyDescriptorResolver}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Yanming Zhou\n */\nclass PropertyDescriptorResolverTests {\n\n\t@Test\n\tvoid propertiesWithJavaBeanProperties() {\n\t\tprocess(SimpleProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsExactly(\"theName\", \"flag\", \"comparator\")));\n\t}\n\n\t@Test\n\tvoid propertiesWithJavaBeanHierarchicalProperties() {\n\t\tprocess(HierarchicalProperties.class,\n\t\t\t\tArrays.asList(HierarchicalPropertiesParent.class, HierarchicalPropertiesGrandparent.class),\n\t\t\t\t(type, metadataEnv) -> {\n\t\t\t\t\tPropertyDescriptorResolver resolver = new PropertyDescriptorResolver(metadataEnv);\n\t\t\t\t\tassertThat(resolver.resolve(type, null).map(PropertyDescriptor::getName)).containsExactly(\"third\",\n\t\t\t\t\t\t\t\"second\", \"first\");\n\t\t\t\t\tassertThat(resolver.resolve(type, null)\n\t\t\t\t\t\t.map((descriptor) -> descriptor.getGetter().getEnclosingElement().getSimpleName().toString()))\n\t\t\t\t\t\t.containsExactly(\"HierarchicalProperties\", \"HierarchicalPropertiesParent\",\n\t\t\t\t\t\t\t\t\"HierarchicalPropertiesParent\");\n\t\t\t\t\tList<ItemMetadata> itemMetadataList = resolver.resolve(type, null)\n\t\t\t\t\t\t.map((descriptor) -> descriptor.resolveItemMetadata(\"test\", metadataEnv))\n\t\t\t\t\t\t.toList();\n\t\t\t\t\tassertThat(itemMetadataList).map(ItemMetadata::getDefaultValue)\n\t\t\t\t\t\t.containsExactly(\"three\", \"two\", \"one\");\n\t\t\t\t\tassertThat(itemMetadataList).map(ItemMetadata::getDescription)\n\t\t\t\t\t\t.containsExactly(\"Concrete property.\", \"Parent property.\", \"Grandparent property.\");\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid propertiesWithLombokGetterSetterAtClassLevel() {\n\t\tprocess(LombokSimpleProperties.class, propertyNames(\n\t\t\t\t(stream) -> assertThat(stream).containsExactly(\"name\", \"description\", \"counter\", \"number\", \"items\")));\n\t}\n\n\t@Test\n\tvoid propertiesWithLombokGetterSetterAtFieldLevel() {\n\t\tprocess(LombokExplicitProperties.class, propertyNames(\n\t\t\t\t(stream) -> assertThat(stream).containsExactly(\"name\", \"description\", \"counter\", \"number\", \"items\")));\n\t}\n\n\t@Test\n\tvoid propertiesWithLombokDataClass() {\n\t\tprocess(LombokSimpleDataProperties.class, propertyNames(\n\t\t\t\t(stream) -> assertThat(stream).containsExactly(\"name\", \"description\", \"counter\", \"number\", \"items\")));\n\t}\n\n\t@Test\n\tvoid propertiesWithLombokValueClass() {\n\t\tprocess(LombokSimpleValueProperties.class, propertyNames(\n\t\t\t\t(stream) -> assertThat(stream).containsExactly(\"name\", \"description\", \"counter\", \"number\", \"items\")));\n\t}\n\n\t@Test\n\tvoid propertiesWithDeducedConstructorBinding() {\n\t\tprocess(ImmutableDeducedConstructorBindingProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsExactly(\"theName\", \"flag\")));\n\t\tprocess(ImmutableDeducedConstructorBindingProperties.class,\n\t\t\t\tproperties((stream) -> assertThat(stream).isNotEmpty()\n\t\t\t\t\t.allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor)));\n\t}\n\n\t@Test\n\tvoid propertiesWithConstructorWithConstructorBinding() {\n\t\tprocess(ImmutableSimpleProperties.class, propertyNames(\n\t\t\t\t(stream) -> assertThat(stream).containsExactly(\"theName\", \"flag\", \"comparator\", \"counter\")));\n\t\tprocess(ImmutableSimpleProperties.class, properties((stream) -> assertThat(stream).isNotEmpty()\n\t\t\t.allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor)));\n\t}\n\n\t@Test\n\tvoid propertiesWithConstructorAndClassConstructorBinding() {\n\t\tprocess(ImmutableClassConstructorBindingProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsExactly(\"name\", \"description\")));\n\t\tprocess(ImmutableClassConstructorBindingProperties.class, properties((stream) -> assertThat(stream).isNotEmpty()\n\t\t\t.allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor)));\n\t}\n\n\t@Test\n\tvoid propertiesWithAutowiredConstructor() {\n\t\tprocess(AutowiredProperties.class, propertyNames((stream) -> assertThat(stream).containsExactly(\"theName\")));\n\t\tprocess(AutowiredProperties.class, properties((stream) -> assertThat(stream).isNotEmpty()\n\t\t\t.allMatch((predicate) -> predicate instanceof JavaBeanPropertyDescriptor)));\n\t}\n\n\t@Test\n\tvoid propertiesWithMultiConstructor() {\n\t\tprocess(ImmutableMultiConstructorProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsExactly(\"name\", \"description\")));\n\t\tprocess(ImmutableMultiConstructorProperties.class, properties((stream) -> assertThat(stream).isNotEmpty()\n\t\t\t.allMatch((predicate) -> predicate instanceof ConstructorParameterPropertyDescriptor)));\n\t}\n\n\t@Test\n\tvoid propertiesWithMultiConstructorNoDirective() {\n\t\tprocess(TwoConstructorsExample.class, propertyNames((stream) -> assertThat(stream).containsExactly(\"name\")));\n\t\tprocess(TwoConstructorsExample.class,\n\t\t\t\tproperties((stream) -> assertThat(stream).element(0).isInstanceOf(JavaBeanPropertyDescriptor.class)));\n\t}\n\n\t@Test\n\tvoid constructorParameterPropertyWithNameAnnotationParameter() {\n\t\tprocess(ConstructorParameterNameAnnotationProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsOnly(\"import\", \"default\")));\n\t}\n\n\t@Test\n\tvoid recordComponentPropertyWithNameAnnotationParameter() {\n\t\tprocess(RecordComponentNameAnnotationProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsOnly(\"import\", \"default\")));\n\t}\n\n\t@Test\n\tvoid javaBeanPropertyWithNameAnnotationParameter() {\n\t\tprocess(JavaBeanNameAnnotationProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsOnly(\"import\", \"default\")));\n\t}\n\n\t@Test\n\tvoid lombokPropertyWithNameAnnotationParameter() {\n\t\tprocess(LombokNameAnnotationProperties.class,\n\t\t\t\tpropertyNames((stream) -> assertThat(stream).containsOnly(\"import\", \"default\")));\n\t}\n\n\tprivate BiConsumer<TypeElement, MetadataGenerationEnvironment> properties(\n\t\t\tConsumer<Stream<PropertyDescriptor>> stream) {\n\t\treturn (element, metadataEnv) -> {\n\t\t\tPropertyDescriptorResolver resolver = new PropertyDescriptorResolver(metadataEnv);\n\t\t\tstream.accept(resolver.resolve(element, null));\n\t\t};\n\t}\n\n\tprivate BiConsumer<TypeElement, MetadataGenerationEnvironment> propertyNames(Consumer<Stream<String>> stream) {\n\t\treturn properties((result) -> stream.accept(result.map(PropertyDescriptor::getName)));\n\t}\n\n\tprivate void process(Class<?> target, BiConsumer<TypeElement, MetadataGenerationEnvironment> consumer) {\n\t\tprocess(target, Collections.emptyList(), consumer);\n\t}\n\n\tprivate void process(Class<?> target, Collection<Class<?>> additionalClasses,\n\t\t\tBiConsumer<TypeElement, MetadataGenerationEnvironment> consumer) {\n\t\tBiConsumer<RoundEnvironmentTester, MetadataGenerationEnvironment> internalConsumer = (roundEnv,\n\t\t\t\tmetadataEnv) -> {\n\t\t\tTypeElement element = roundEnv.getRootElement(target);\n\t\t\tconsumer.accept(element, metadataEnv);\n\t\t};\n\t\tTestableAnnotationProcessor<MetadataGenerationEnvironment> processor = new TestableAnnotationProcessor<>(\n\t\t\t\tinternalConsumer, new MetadataGenerationEnvironmentFactory());\n\t\tSourceFile targetSource = SourceFile.forTestClass(target);\n\t\tList<SourceFile> additionalSource = additionalClasses.stream().map(SourceFile::forTestClass).toList();\n\t\tTestCompiler compiler = TestCompiler.forSystem()\n\t\t\t.withProcessors(processor)\n\t\t\t.withSources(targetSource)\n\t\t\t.withSources(additionalSource);\n\t\tcompiler.compile((compiled) -> {\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/PropertyDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.util.function.BiConsumer;\n\nimport javax.lang.model.element.ExecutableElement;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.util.ElementFilter;\n\nimport org.springframework.boot.configurationprocessor.test.ItemMetadataAssert;\nimport org.springframework.boot.configurationprocessor.test.RoundEnvironmentTester;\nimport org.springframework.boot.configurationprocessor.test.TestableAnnotationProcessor;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\n/**\n * Base test infrastructure to test {@link PropertyDescriptor} implementations.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\npublic abstract class PropertyDescriptorTests {\n\n\tprotected String createAccessorMethodName(String prefix, String name) {\n\t\tchar[] chars = name.toCharArray();\n\t\tchars[0] = Character.toUpperCase(chars[0]);\n\t\treturn prefix + new String(chars, 0, chars.length);\n\t}\n\n\tprotected ExecutableElement getMethod(TypeElement element, String name) {\n\t\treturn ElementFilter.methodsIn(element.getEnclosedElements())\n\t\t\t.stream()\n\t\t\t.filter((method) -> method.getSimpleName().toString().equals(name))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprotected VariableElement getField(TypeElement element, String name) {\n\t\treturn ElementFilter.fieldsIn(element.getEnclosedElements())\n\t\t\t.stream()\n\t\t\t.filter((method) -> method.getSimpleName().toString().equals(name))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprotected ItemMetadataAssert assertItemMetadata(MetadataGenerationEnvironment metadataEnv,\n\t\t\tPropertyDescriptor property) {\n\t\treturn new ItemMetadataAssert(property.resolveItemMetadata(\"test\", metadataEnv));\n\t}\n\n\tprotected void process(Class<?> target,\n\t\t\tBiConsumer<RoundEnvironmentTester, MetadataGenerationEnvironment> consumer) {\n\t\tTestableAnnotationProcessor<MetadataGenerationEnvironment> processor = new TestableAnnotationProcessor<>(\n\t\t\t\tconsumer, new MetadataGenerationEnvironmentFactory());\n\t\tTestCompiler compiler = TestCompiler.forSystem()\n\t\t\t.withProcessors(processor)\n\t\t\t.withSources(SourceFile.forTestClass(target));\n\t\tcompiler.compile((compiled) -> {\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TestProject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.UncheckedIOException;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;\nimport org.springframework.boot.configurationprocessor.test.CompiledMetadataReader;\nimport org.springframework.boot.configurationprocessor.test.TestConfigurationMetadataAnnotationProcessor;\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\nimport org.springframework.core.test.tools.ResourceFile;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.SourceFiles;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * A TestProject contains a copy of a subset of test sample code.\n * <p>\n * Why a copy? Because when doing incremental build testing, we need to make modifications\n * to the contents of the 'test project'. But we don't want to actually modify the\n * original content itself.\n *\n * @author Kris De Volder\n * @author Scott Frederick\n */\npublic class TestProject {\n\n\tprivate static final Class<?>[] ALWAYS_INCLUDE = { TestConfigurationProperties.class,\n\t\t\tTestNestedConfigurationProperty.class };\n\n\tprivate SourceFiles sources;\n\n\tpublic TestProject(Class<?>... classes) {\n\t\tthis.sources = SourceFiles.none().and(sourceFilesOf(ALWAYS_INCLUDE)).and(sourceFilesOf(classes));\n\t}\n\n\tpublic ConfigurationMetadata compile() {\n\t\treturn compile(null);\n\t}\n\n\tpublic ConfigurationMetadata compile(ConfigurationMetadata previousMetadata) {\n\t\tTestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor();\n\t\tTestCompiler compiler = TestCompiler.forSystem().withProcessors(processor);\n\t\tif (previousMetadata != null) {\n\t\t\tcompiler = compiler.withResources(\n\t\t\t\t\tResourceFile.of(\"META-INF/spring-configuration-metadata.json\", asBytes(previousMetadata)));\n\t\t}\n\t\tAtomicReference<ConfigurationMetadata> configurationMetadata = new AtomicReference<>();\n\t\tcompiler.compile(this.sources,\n\t\t\t\t(compiled) -> configurationMetadata.set(CompiledMetadataReader.getMetadata(compiled)));\n\t\treturn configurationMetadata.get();\n\t}\n\n\tprivate byte[] asBytes(ConfigurationMetadata previousMetadata) {\n\t\tByteArrayOutputStream output = new ByteArrayOutputStream();\n\t\ttry {\n\t\t\tnew JsonMarshaller().write(previousMetadata, output);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t\treturn output.toByteArray();\n\t}\n\n\t/**\n\t * Add source code at the end of file, just before last '}'\n\t * @param target the target\n\t * @param snippetStream the snippet stream\n\t * @throws Exception if the source cannot be added\n\t */\n\tpublic void addSourceCode(Class<?> target, InputStream snippetStream) throws Exception {\n\t\tSourceFile sourceFile = SourceFile.forTestClass(target);\n\t\tString contents = sourceFile.getContent();\n\t\tint insertAt = contents.lastIndexOf('}');\n\t\tString additionalSource = FileCopyUtils.copyToString(new InputStreamReader(snippetStream));\n\t\tcontents = contents.substring(0, insertAt) + additionalSource + contents.substring(insertAt);\n\t\tthis.sources = this.sources.and(SourceFile.of(contents));\n\t}\n\n\t/**\n\t * Delete source file for given class from project.\n\t * @param type the class to delete\n\t */\n\tpublic void delete(Class<?> type) {\n\t\tSourceFile[] newSources = this.sources.stream()\n\t\t\t.filter((sourceFile) -> !sourceFile.getPath().equals(SourceFile.forTestClass(type).getPath()))\n\t\t\t.toArray(SourceFile[]::new);\n\t\tthis.sources = SourceFiles.of(newSources);\n\t}\n\n\t/**\n\t * Restore source code of given class to its original contents.\n\t * @param type the class to revert\n\t */\n\tpublic void revert(Class<?> type) {\n\t\tAssert.isTrue(this.sources.stream().anyMatch((sourceFile) -> sourceFile.getClassName().equals(type.getName())),\n\t\t\t\t\"Source file for type '\" + type + \"' does not exist\");\n\t\tthis.sources = this.sources.and(SourceFile.forTestClass(type));\n\t}\n\n\t/**\n\t * Add source code of given class to this project.\n\t * @param type the class to add\n\t */\n\tpublic void add(Class<?> type) {\n\t\tAssert.isTrue(this.sources.stream().noneMatch((sourceFile) -> sourceFile.getClassName().equals(type.getName())),\n\t\t\t\t\"Source file for type '\" + type + \"' already exists\");\n\t\tthis.sources = this.sources.and(SourceFile.forTestClass(type));\n\t}\n\n\tpublic void replaceText(Class<?> type, String find, String replace) {\n\t\tSourceFile sourceFile = SourceFile.forTestClass(type);\n\t\tString contents = sourceFile.getContent().replace(find, replace);\n\t\tthis.sources = this.sources.and(SourceFile.of(contents));\n\t}\n\n\tprivate List<SourceFile> sourceFilesOf(Class<?>... types) {\n\t\treturn Arrays.stream(types).map(SourceFile::forTestClass).toList();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/TypeUtilsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor;\n\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.element.VariableElement;\nimport javax.lang.model.type.TypeMirror;\nimport javax.lang.model.util.ElementFilter;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.test.RoundEnvironmentTester;\nimport org.springframework.boot.configurationprocessor.test.TestableAnnotationProcessor;\nimport org.springframework.boot.configurationsample.generic.AbstractGenericProperties;\nimport org.springframework.boot.configurationsample.generic.AbstractIntermediateGenericProperties;\nimport org.springframework.boot.configurationsample.generic.MixGenericNameProperties;\nimport org.springframework.boot.configurationsample.generic.SimpleGenericProperties;\nimport org.springframework.boot.configurationsample.generic.UnresolvedGenericProperties;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TypeUtils}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass TypeUtilsTests {\n\n\t@Test\n\tvoid resolveTypeOnConcreteClass() {\n\t\tprocess(SimpleGenericProperties.class, (roundEnv, typeUtils) -> {\n\t\t\tTypeElement typeElement = roundEnv.getRootElement(SimpleGenericProperties.class);\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"name\")).hasToString(String.class.getName());\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"mappings\"))\n\t\t\t\t.hasToString(constructMapType(Integer.class, Duration.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid resolveTypeOnIntermediateClass() {\n\t\tprocess(AbstractIntermediateGenericProperties.class, (roundEnv, typeUtils) -> {\n\t\t\tTypeElement typeElement = roundEnv.getRootElement(AbstractIntermediateGenericProperties.class);\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"name\")).hasToString(String.class.getName());\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"mappings\"))\n\t\t\t\t.hasToString(constructMapType(Integer.class, Object.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid resolveTypeWithOnlyGenerics() {\n\t\tprocess(AbstractGenericProperties.class, (roundEnv, typeUtils) -> {\n\t\t\tTypeElement typeElement = roundEnv.getRootElement(AbstractGenericProperties.class);\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"name\")).hasToString(Object.class.getName());\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"mappings\"))\n\t\t\t\t.hasToString(constructMapType(Object.class, Object.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid resolveTypeWithUnresolvedGenericProperties() {\n\t\tprocess(UnresolvedGenericProperties.class, (roundEnv, typeUtils) -> {\n\t\t\tTypeElement typeElement = roundEnv.getRootElement(UnresolvedGenericProperties.class);\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"name\")).hasToString(String.class.getName());\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"mappings\"))\n\t\t\t\t.hasToString(constructMapType(Number.class, Object.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid resolvedTypeMixGenericNamePropertiesProperties() {\n\t\tprocess(MixGenericNameProperties.class, (roundEnv, typeUtils) -> {\n\t\t\tTypeElement typeElement = roundEnv.getRootElement(MixGenericNameProperties.class);\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"name\")).hasToString(String.class.getName());\n\t\t\tassertThat(getTypeOfField(typeUtils, typeElement, \"mappings\"))\n\t\t\t\t.hasToString(constructMapType(Number.class, Object.class));\n\t\t});\n\t}\n\n\tprivate void process(Class<?> target, BiConsumer<RoundEnvironmentTester, TypeUtils> consumer) {\n\t\tTestableAnnotationProcessor<TypeUtils> processor = new TestableAnnotationProcessor<>(consumer, TypeUtils::new);\n\t\tTestCompiler compiler = TestCompiler.forSystem()\n\t\t\t.withProcessors(processor)\n\t\t\t.withSources(SourceFile.forTestClass(target));\n\t\tcompiler.compile((compiled) -> {\n\t\t});\n\t}\n\n\tprivate String constructMapType(Class<?> keyType, Class<?> valueType) {\n\t\treturn \"%s<%s,%s>\".formatted(Map.class.getName(), keyType.getName(), valueType.getName());\n\t}\n\n\tprivate String getTypeOfField(TypeUtils typeUtils, TypeElement typeElement, String name) {\n\t\tTypeMirror field = findField(typeUtils, typeElement, name);\n\t\tif (field == null) {\n\t\t\tthrow new IllegalStateException(\"Unable to find field '\" + name + \"' in \" + typeElement);\n\t\t}\n\t\treturn typeUtils.getType(typeElement, field);\n\t}\n\n\tprivate TypeMirror findField(TypeUtils typeUtils, TypeElement typeElement, String name) {\n\t\tfor (VariableElement variableElement : ElementFilter.fieldsIn(typeElement.getEnclosedElements())) {\n\t\t\tif (variableElement.getSimpleName().contentEquals(name)) {\n\t\t\t\treturn variableElement.asType();\n\t\t\t}\n\t\t}\n\t\tTypeMirror superclass = typeElement.getSuperclass();\n\t\tif (superclass != null && !superclass.toString().equals(Object.class.getName())) {\n\t\t\treturn findField(typeUtils, (TypeElement) typeUtils.asElement(superclass), name);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/AbstractFieldValuesProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationsample.fieldvalues.FieldValues;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for {@link FieldValuesParser} tests.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\npublic abstract class AbstractFieldValuesProcessorTests {\n\n\tprotected abstract FieldValuesParser createProcessor(ProcessingEnvironment env);\n\n\t@Test\n\tvoid getFieldValues() {\n\t\tTestProcessor processor = new TestProcessor();\n\t\tTestCompiler compiler = TestCompiler.forSystem()\n\t\t\t.withProcessors(processor)\n\t\t\t.withSources(SourceFile.forTestClass(FieldValues.class));\n\t\tcompiler.compile((compiled) -> {\n\t\t});\n\t\tMap<String, Object> values = processor.getValues();\n\t\tassertThat(values.get(\"stringNone\")).isNull();\n\t\tassertThat(values.get(\"stringConst\")).isEqualTo(\"c\");\n\t\tassertThat(values.get(\"bool\")).isEqualTo(true);\n\t\tassertThat(values.get(\"boolNone\")).isEqualTo(false);\n\t\tassertThat(values.get(\"boolConst\")).isEqualTo(true);\n\t\tassertThat(values.get(\"boolInverted\")).isNull();\n\t\tassertThat(values.get(\"boolObject\")).isEqualTo(true);\n\t\tassertThat(values.get(\"boolObjectNone\")).isNull();\n\t\tassertThat(values.get(\"boolObjectConst\")).isEqualTo(true);\n\t\tassertThat(values.get(\"integer\")).isEqualTo(1);\n\t\tassertThat(values.get(\"integerNone\")).isEqualTo(0);\n\t\tassertThat(values.get(\"integerConst\")).isEqualTo(2);\n\t\tassertThat(values.get(\"integerArithmetic\")).isNull();\n\t\tassertThat(values.get(\"integerMax\")).isNull();\n\t\tassertThat(values.get(\"integerObject\")).isEqualTo(3);\n\t\tassertThat(values.get(\"integerObjectNone\")).isNull();\n\t\tassertThat(values.get(\"integerObjectConst\")).isEqualTo(4);\n\t\tassertThat(values.get(\"charset\")).isEqualTo(\"US-ASCII\");\n\t\tassertThat(values.get(\"charsetConst\")).isEqualTo(\"UTF-8\");\n\t\tassertThat(values.get(\"mimeType\")).isEqualTo(\"text/html\");\n\t\tassertThat(values.get(\"mimeTypeConst\")).isEqualTo(\"text/plain\");\n\t\tassertThat(values.get(\"object\")).isEqualTo(123);\n\t\tassertThat(values.get(\"objectNone\")).isNull();\n\t\tassertThat(values.get(\"objectConst\")).isEqualTo(\"c\");\n\t\tassertThat(values.get(\"objectInstance\")).isNull();\n\t\tassertThat(values.get(\"stringArray\")).isEqualTo(new Object[] { \"FOO\", \"BAR\" });\n\t\tassertThat(values.get(\"stringArrayNone\")).isNull();\n\t\tassertThat(values.get(\"stringEmptyArray\")).isEqualTo(new Object[0]);\n\t\tassertThat(values.get(\"stringArrayConst\")).isEqualTo(new Object[] { \"OK\", \"KO\" });\n\t\tassertThat(values.get(\"stringArrayConstElements\")).isEqualTo(new Object[] { \"c\" });\n\t\tassertThat(values.get(\"integerArray\")).isEqualTo(new Object[] { 42, 24 });\n\t\tassertThat(values.get(\"intArrayUnsupportedExpression\")).isNull();\n\t\tassertThat(values.get(\"unknownArray\")).isNull();\n\t\tassertThat(values.get(\"durationNone\")).isNull();\n\t\tassertThat(values.get(\"durationNanos\")).isEqualTo(\"5ns\");\n\t\tassertThat(values.get(\"durationMillis\")).isEqualTo(\"10ms\");\n\t\tassertThat(values.get(\"durationSeconds\")).isEqualTo(\"20s\");\n\t\tassertThat(values.get(\"durationMinutes\")).isEqualTo(\"30m\");\n\t\tassertThat(values.get(\"durationHours\")).isEqualTo(\"40h\");\n\t\tassertThat(values.get(\"durationDays\")).isEqualTo(\"50d\");\n\t\tassertThat(values.get(\"durationZero\")).isEqualTo(0);\n\t\tassertThat(values.get(\"dataSizeNone\")).isNull();\n\t\tassertThat(values.get(\"dataSizeBytes\")).isEqualTo(\"5B\");\n\t\tassertThat(values.get(\"dataSizeKilobytes\")).isEqualTo(\"10KB\");\n\t\tassertThat(values.get(\"dataSizeMegabytes\")).isEqualTo(\"20MB\");\n\t\tassertThat(values.get(\"dataSizeGigabytes\")).isEqualTo(\"30GB\");\n\t\tassertThat(values.get(\"dataSizeTerabytes\")).isEqualTo(\"40TB\");\n\t\tassertThat(values.get(\"periodNone\")).isNull();\n\t\tassertThat(values.get(\"periodDays\")).isEqualTo(\"3d\");\n\t\tassertThat(values.get(\"periodWeeks\")).isEqualTo(\"2w\");\n\t\tassertThat(values.get(\"periodMonths\")).isEqualTo(\"10m\");\n\t\tassertThat(values.get(\"periodYears\")).isEqualTo(\"15y\");\n\t\tassertThat(values.get(\"periodZero\")).isEqualTo(0);\n\t\tassertThat(values.get(\"enumNone\")).isNull();\n\t\tassertThat(values.get(\"enumSimple\")).isEqualTo(\"seconds\");\n\t\tassertThat(values.get(\"enumQualified\")).isEqualTo(\"hour-of-day\");\n\t\tassertThat(values.get(\"enumWithIndirection\")).isNull();\n\t\tassertThat(values.get(\"memberSelectInt\")).isNull();\n\t}\n\n\t@SupportedAnnotationTypes({ \"org.springframework.boot.configurationsample.TestConfigurationProperties\" })\n\t@SupportedSourceVersion(SourceVersion.RELEASE_6)\n\tprivate final class TestProcessor extends AbstractProcessor {\n\n\t\tprivate FieldValuesParser processor;\n\n\t\tprivate final Map<String, Object> values = new HashMap<>();\n\n\t\t@Override\n\t\tpublic synchronized void init(ProcessingEnvironment env) {\n\t\t\tthis.processor = createProcessor(env);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n\t\t\tfor (TypeElement annotation : annotations) {\n\t\t\t\tfor (Element element : roundEnv.getElementsAnnotatedWith(annotation)) {\n\t\t\t\t\tif (element instanceof TypeElement typeElement) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tthis.values.putAll(this.processor.getFieldValues(typeElement));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tMap<String, Object> getValues() {\n\t\t\treturn this.values;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/fieldvalues/javac/JavaCompilerFieldValuesProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.fieldvalues.javac;\n\nimport javax.annotation.processing.ProcessingEnvironment;\n\nimport org.opentest4j.TestAbortedException;\n\nimport org.springframework.boot.configurationprocessor.fieldvalues.AbstractFieldValuesProcessorTests;\nimport org.springframework.boot.configurationprocessor.fieldvalues.FieldValuesParser;\n\n/**\n * Tests for {@link JavaCompilerFieldValuesParser}.\n *\n * @author Phillip Webb\n */\nclass JavaCompilerFieldValuesProcessorTests extends AbstractFieldValuesProcessorTests {\n\n\t@Override\n\tprotected FieldValuesParser createProcessor(ProcessingEnvironment env) {\n\t\ttry {\n\t\t\treturn new JavaCompilerFieldValuesParser(env);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow new TestAbortedException();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/ItemHintTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint.ValueHint;\nimport org.springframework.boot.configurationprocessor.metadata.ItemHint.ValueProvider;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ItemHint}.\n *\n * @author Stephane Nicoll\n */\nclass ItemHintTests {\n\n\t@Test\n\tvoid prefixIsAppliedWithValueHint() {\n\t\tValueHint firstValueHint = new ValueHint(\"one\", \"First.\");\n\t\tValueHint secondValueHint = new ValueHint(\"two\", \"Second.\");\n\t\tItemHint itemHint = new ItemHint(\"name\", List.of(firstValueHint, secondValueHint), Collections.emptyList());\n\t\tItemHint prefixedItemHint = itemHint.applyPrefix(\"example\");\n\t\tassertThat(itemHint).isNotSameAs(prefixedItemHint);\n\t\tassertThat(prefixedItemHint.getName()).isEqualTo(\"example.name\");\n\t\tassertThat(prefixedItemHint.getValues()).containsExactly(firstValueHint, secondValueHint);\n\t\tassertThat(prefixedItemHint.getProviders()).isEmpty();\n\t}\n\n\t@Test\n\tvoid prefixIsAppliedWithValueProvider() {\n\t\tValueProvider firstValueProvider = new ValueProvider(\"class-reference\", Map.of(\"target\", String.class));\n\t\tValueProvider secondValueProvider = new ValueProvider(\"any\", Collections.emptyMap());\n\t\tItemHint itemHint = new ItemHint(\"name\", Collections.emptyList(),\n\t\t\t\tList.of(firstValueProvider, secondValueProvider));\n\t\tItemHint prefixedItemHint = itemHint.applyPrefix(\"example\");\n\t\tassertThat(itemHint).isNotSameAs(prefixedItemHint);\n\t\tassertThat(prefixedItemHint.getName()).isEqualTo(\"example.name\");\n\t\tassertThat(prefixedItemHint.getValues()).isEmpty();\n\t\tassertThat(prefixedItemHint.getProviders()).containsExactly(firstValueProvider, secondValueProvider);\n\t}\n\n\t@Test\n\tvoid prefixIsAppliedWithConvention() {\n\t\tItemHint itemHint = new ItemHint(\"name\", Collections.emptyList(), Collections.emptyList());\n\t\tItemHint prefixedItemHint = itemHint.applyPrefix(\"example.nestedType\");\n\t\tassertThat(prefixedItemHint.getName()).isEqualTo(\"example.nested-type.name\");\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/ItemMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ItemMetadata}.\n *\n * @author Stephane Nicoll\n */\nclass ItemMetadataTests {\n\n\t@Test\n\tvoid newItemMetadataPrefixWithCapitalizedPrefix() {\n\t\tassertThat(newItemMetadataPrefix(\"Prefix.\", \"value\")).isEqualTo(\"prefix.value\");\n\t}\n\n\t@Test\n\tvoid newItemMetadataPrefixWithCamelCaseSuffix() {\n\t\tassertThat(newItemMetadataPrefix(\"prefix.\", \"myValue\")).isEqualTo(\"prefix.my-value\");\n\t}\n\n\t@Test\n\tvoid newItemMetadataPrefixWithUpperCamelCaseSuffix() {\n\t\tassertThat(newItemMetadataPrefix(\"prefix.\", \"MyValue\")).isEqualTo(\"prefix.my-value\");\n\t}\n\n\tprivate String newItemMetadataPrefix(String prefix, String suffix) {\n\t\treturn ItemMetadata.newItemMetadataPrefix(prefix, suffix);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/JsonMarshallerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Tests for {@link JsonMarshaller}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass JsonMarshallerTests {\n\n\t@Test\n\tvoid marshallAndUnmarshal() throws Exception {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemMetadata.newProperty(\"a\", \"b\", StringBuffer.class.getName(), InputStream.class.getName(), null,\n\t\t\t\t\"desc\", \"x\", new ItemDeprecation(\"Deprecation comment\", \"b.c.d\", \"1.2.3\")));\n\t\tmetadata.add(ItemMetadata.newProperty(\"b.c.d\", null, null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"c\", null, null, null, null, null, 123, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"d\", null, null, null, null, null, true, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"e\", null, null, null, null, null, new String[] { \"y\", \"n\" }, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"f\", null, null, null, null, null, new Boolean[] { true, false }, null));\n\t\tmetadata.add(ItemMetadata.newGroup(\"d\", null, null, null));\n\t\tmetadata.add(ItemMetadata.newGroup(\"e\", null, null, \"sourceMethod\"));\n\t\tmetadata.add(ItemHint.newHint(\"a.b\"));\n\t\tmetadata.add(ItemHint.newHint(\"c\", new ItemHint.ValueHint(123, \"hey\"), new ItemHint.ValueHint(456, null)));\n\t\tmetadata.add(new ItemHint(\"d\", null,\n\t\t\t\tArrays.asList(new ItemHint.ValueProvider(\"first\", Collections.singletonMap(\"target\", \"foo\")),\n\t\t\t\t\t\tnew ItemHint.ValueProvider(\"second\", null))));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tConfigurationMetadata read = marshaller.read(new ByteArrayInputStream(outputStream.toByteArray()));\n\t\tassertThat(read).has(Metadata.withProperty(\"a.b\", StringBuffer.class)\n\t\t\t.fromSource(InputStream.class)\n\t\t\t.withDescription(\"desc\")\n\t\t\t.withDefaultValue(\"x\")\n\t\t\t.withDeprecation(\"Deprecation comment\", \"b.c.d\", \"1.2.3\"));\n\t\tassertThat(read).has(Metadata.withProperty(\"b.c.d\"));\n\t\tassertThat(read).has(Metadata.withProperty(\"c\").withDefaultValue(123));\n\t\tassertThat(read).has(Metadata.withProperty(\"d\").withDefaultValue(true));\n\t\tassertThat(read).has(Metadata.withProperty(\"e\").withDefaultValue(new String[] { \"y\", \"n\" }));\n\t\tassertThat(read).has(Metadata.withProperty(\"f\").withDefaultValue(new Object[] { true, false }));\n\t\tassertThat(read).has(Metadata.withGroup(\"d\"));\n\t\tassertThat(read).has(Metadata.withGroup(\"e\").fromSourceMethod(\"sourceMethod\"));\n\t\tassertThat(read).has(Metadata.withHint(\"a.b\"));\n\t\tassertThat(read).has(Metadata.withHint(\"c\").withValue(0, 123, \"hey\").withValue(1, 456, null));\n\t\tassertThat(read).has(Metadata.withHint(\"d\").withProvider(\"first\", \"target\", \"foo\").withProvider(\"second\"));\n\t}\n\n\t@Test\n\tvoid marshallOrderItems() throws IOException {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemHint.newHint(\"fff\"));\n\t\tmetadata.add(ItemHint.newHint(\"eee\"));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"bbb\", null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"aaa\", null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.alpha\", \"ddd\", null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.alpha\", \"ccc\", null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newGroup(\"com.acme.bravo\", \"com.example.AnotherTestProperties\", null, null));\n\t\tmetadata.add(ItemMetadata.newGroup(\"com.acme.alpha\", \"com.example.TestProperties\", null, null));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tString json = outputStream.toString();\n\t\tassertThat(json).containsSubsequence(\"\\\"groups\\\"\", \"\\\"com.acme.alpha\\\"\", \"\\\"com.acme.bravo\\\"\", \"\\\"properties\\\"\",\n\t\t\t\t\"\\\"com.example.alpha.ccc\\\"\", \"\\\"com.example.alpha.ddd\\\"\", \"\\\"com.example.bravo.aaa\\\"\",\n\t\t\t\t\"\\\"com.example.bravo.bbb\\\"\", \"\\\"hints\\\"\", \"\\\"eee\\\"\", \"\\\"fff\\\"\");\n\t}\n\n\t@Test\n\tvoid marshallPutDeprecatedItemsAtTheEnd() throws IOException {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"bbb\", null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"aaa\", null, null, null, null, null,\n\t\t\t\tnew ItemDeprecation(null, null, null, \"warning\")));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.alpha\", \"ddd\", null, null, null, null, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.alpha\", \"ccc\", null, null, null, null, null,\n\t\t\t\tnew ItemDeprecation(null, null, null, \"warning\")));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tString json = outputStream.toString();\n\t\tassertThat(json).containsSubsequence(\"\\\"properties\\\"\", \"\\\"com.example.alpha.ddd\\\"\", \"\\\"com.example.bravo.bbb\\\"\",\n\t\t\t\t\"\\\"com.example.alpha.ccc\\\"\", \"\\\"com.example.bravo.aaa\\\"\");\n\t}\n\n\t@Test\n\tvoid orderingForSameGroupNames() throws IOException {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemMetadata.newGroup(\"com.acme.alpha\", null, \"com.example.Foo\", null));\n\t\tmetadata.add(ItemMetadata.newGroup(\"com.acme.alpha\", null, \"com.example.Bar\", null));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tString json = outputStream.toString();\n\t\tassertThat(json).containsSubsequence(\"\\\"groups\\\"\", \"\\\"name\\\": \\\"com.acme.alpha\\\"\",\n\t\t\t\t\"\\\"sourceType\\\": \\\"com.example.Bar\\\"\", \"\\\"name\\\": \\\"com.acme.alpha\\\"\",\n\t\t\t\t\"\\\"sourceType\\\": \\\"com.example.Foo\\\"\");\n\t}\n\n\t@Test\n\tvoid orderingForSamePropertyNames() throws IOException {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"aaa\", \"java.lang.Boolean\", \"com.example.Foo\", null,\n\t\t\t\tnull, null, null));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"aaa\", \"java.lang.Integer\", \"com.example.Bar\", null,\n\t\t\t\tnull, null, null));\n\t\tmetadata\n\t\t\t.add(ItemMetadata.newProperty(\"com.example.alpha\", \"ddd\", null, \"com.example.Bar\", null, null, null, null));\n\t\tmetadata\n\t\t\t.add(ItemMetadata.newProperty(\"com.example.alpha\", \"ccc\", null, \"com.example.Foo\", null, null, null, null));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tString json = outputStream.toString();\n\t\tassertThat(json).containsSubsequence(\"\\\"groups\\\"\", \"\\\"properties\\\"\", \"\\\"com.example.alpha.ccc\\\"\",\n\t\t\t\t\"com.example.Foo\", \"\\\"com.example.alpha.ddd\\\"\", \"com.example.Bar\", \"\\\"com.example.bravo.aaa\\\"\",\n\t\t\t\t\"com.example.Bar\", \"\\\"com.example.bravo.aaa\\\"\", \"com.example.Foo\");\n\t}\n\n\t@Test\n\tvoid orderingForSameGroupWithNullSourceType() throws IOException {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemMetadata.newGroup(\"com.acme.alpha\", null, \"com.example.Foo\", null));\n\t\tmetadata.add(ItemMetadata.newGroup(\"com.acme.alpha\", null, null, null));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tString json = outputStream.toString();\n\t\tassertThat(json).containsSubsequence(\"\\\"groups\\\"\", \"\\\"name\\\": \\\"com.acme.alpha\\\"\",\n\t\t\t\t\"\\\"name\\\": \\\"com.acme.alpha\\\"\", \"\\\"sourceType\\\": \\\"com.example.Foo\\\"\");\n\t}\n\n\t@Test\n\tvoid orderingForSamePropertyNamesWithNullSourceType() throws IOException {\n\t\tConfigurationMetadata metadata = new ConfigurationMetadata();\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"aaa\", \"java.lang.Boolean\", null, null, null, null,\n\t\t\t\tnull));\n\t\tmetadata.add(ItemMetadata.newProperty(\"com.example.bravo\", \"aaa\", \"java.lang.Integer\", \"com.example.Bar\", null,\n\t\t\t\tnull, null, null));\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\tmarshaller.write(metadata, outputStream);\n\t\tString json = outputStream.toString();\n\t\tassertThat(json).containsSubsequence(\"\\\"groups\\\"\", \"\\\"properties\\\"\", \"\\\"com.example.bravo.aaa\\\"\",\n\t\t\t\t\"\\\"java.lang.Boolean\\\"\", \"\\\"com.example.bravo.aaa\\\"\", \"\\\"java.lang.Integer\\\"\", \"\\\"com.example.Bar\");\n\t}\n\n\t@Test\n\tvoid shouldReadIgnoredProperties() throws Exception {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"ignored\": {\n\t\t\t\t\t\t\"properties\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"name\": \"prop1\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"name\": \"prop2\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tConfigurationMetadata metadata = read(json);\n\t\tassertThat(metadata.getIgnored()).containsExactly(ItemIgnore.forProperty(\"prop1\"),\n\t\t\t\tItemIgnore.forProperty(\"prop2\"));\n\t}\n\n\t@Test\n\tvoid shouldCheckRootFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [], \"properties\": [], \"hints\": [], \"ignored\": {}, \"dummy\": []\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [groups, hints, ignored, properties], but found additional keys [dummy]. Path: .\");\n\t}\n\n\t@Test\n\tvoid shouldCheckGroupFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"g\",\n\t\t\t\t\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\t\t\t\t\"description\": \"Some description\",\n\t\t\t\t\t\t\t\"sourceType\": \"java.lang.String\",\n\t\t\t\t\t\t\t\"sourceMethod\": \"some()\",\n\t\t\t\t\t\t\t\"dummy\": \"dummy\"\n\t\t\t\t\t\t}\n\t\t\t\t\t], \"properties\": [], \"hints\": []\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [description, name, sourceMethod, sourceType, type], but found additional keys [dummy]. Path: .groups.[0]\");\n\t}\n\n\t@Test\n\tvoid shouldCheckPropertyFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [], \"properties\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\t\t\t\t\"description\": \"Some description\",\n\t\t\t\t\t\t\t\"sourceType\": \"java.lang.String\",\n\t\t\t\t\t\t\t\"defaultValue\": \"value\",\n\t\t\t\t\t\t\t\"deprecation\": {\n\t\t\t\t\t\t\t\t\"level\": \"warning\",\n\t\t\t\t\t\t\t\t\"reason\": \"some reason\",\n\t\t\t\t\t\t\t\t\"replacement\": \"name-new\",\n\t\t\t\t\t\t\t\t\"since\": \"v17\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"deprecated\": true,\n\t\t\t\t\t\t\t\"dummy\": \"dummy\"\n\t\t\t\t\t\t}\n\t\t\t\t\t], \"hints\": []\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [defaultValue, deprecated, deprecation, description, name, sourceType, type], but found additional keys [dummy]. Path: .properties.[0]\");\n\t}\n\n\t@Test\n\tvoid shouldCheckPropertyDeprecationFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [], \"properties\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\t\t\t\t\"description\": \"Some description\",\n\t\t\t\t\t\t\t\"sourceType\": \"java.lang.String\",\n\t\t\t\t\t\t\t\"defaultValue\": \"value\",\n\t\t\t\t\t\t\t\"deprecation\": {\n\t\t\t\t\t\t\t\t\"level\": \"warning\",\n\t\t\t\t\t\t\t\t\"reason\": \"some reason\",\n\t\t\t\t\t\t\t\t\"replacement\": \"name-new\",\n\t\t\t\t\t\t\t\t\"since\": \"v17\",\n\t\t\t\t\t\t\t\t\"dummy\": \"dummy\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"deprecated\": true\n\t\t\t\t\t\t}\n\t\t\t\t\t], \"hints\": []\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [level, reason, replacement, since], but found additional keys [dummy]. Path: .properties.[0].deprecation\");\n\t}\n\n\t@Test\n\tvoid shouldCheckHintFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [], \"properties\": [], \"hints\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\"values\": [],\n\t\t\t\t\t\t\t\"providers\": [],\n\t\t\t\t\t\t\t\"dummy\": \"dummy\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [name, providers, values], but found additional keys [dummy]. Path: .hints.[0]\");\n\t}\n\n\t@Test\n\tvoid shouldCheckHintValueFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [], \"properties\": [], \"hints\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\"values\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"value\": \"value\",\n\t\t\t\t\t\t\t\t\t\"description\": \"some description\",\n\t\t\t\t\t\t\t\t\t\"dummy\": \"dummy\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"providers\": []\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [description, value], but found additional keys [dummy]. Path: .hints.[0].values.[0]\");\n\t}\n\n\t@Test\n\tvoid shouldCheckHintProviderFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"groups\": [], \"properties\": [], \"hints\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\"values\": [],\n\t\t\t\t\t\t\t\"providers\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"name\",\n\t\t\t\t\t\t\t\t\t\"parameters\": {\n\t\t\t\t\t\t\t\t\t\t\"target\": \"jakarta.servlet.http.HttpServlet\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"dummy\": \"dummy\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Expected only keys [name, parameters], but found additional keys [dummy]. Path: .hints.[0].providers.[0]\");\n\t}\n\n\t@Test\n\tvoid shouldCheckIgnoredFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"ignored\": {\n\t\t\t\t\t\t\"properties\": [],\n\t\t\t\t\t\t\"dummy\": {}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\"Expected only keys [properties], but found additional keys [dummy]. Path: .ignored\");\n\t}\n\n\t@Test\n\tvoid shouldCheckIgnoredPropertiesFields() {\n\t\tString json = \"\"\"\n\t\t\t\t{\n\t\t\t\t\t\"ignored\": {\n\t\t\t\t\t\t\"properties\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"name\": \"prop1\",\n\t\t\t\t\t\t\t\t\"dummy\": true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\"\"\";\n\t\tassertThatException().isThrownBy(() -> read(json))\n\t\t\t.withMessage(\"Expected only keys [name], but found additional keys [dummy]. Path: .ignored.properties.[0]\");\n\t}\n\n\tprivate ConfigurationMetadata read(String json) throws Exception {\n\t\tJsonMarshaller marshaller = new JsonMarshaller();\n\t\treturn marshaller.read(new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)));\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/Metadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.Condition;\nimport org.hamcrest.collection.IsMapContaining;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\nimport org.springframework.boot.configurationsample.TestAccess;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * AssertJ {@link Condition} to help test {@link ConfigurationMetadata}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\npublic final class Metadata {\n\n\tprivate Metadata() {\n\t}\n\n\tpublic static MetadataItemCondition withGroup(String name) {\n\t\treturn new MetadataItemCondition(ItemType.GROUP, name);\n\t}\n\n\tpublic static MetadataItemCondition withGroup(String name, Class<?> type) {\n\t\treturn new MetadataItemCondition(ItemType.GROUP, name).ofType(type);\n\t}\n\n\tpublic static MetadataItemCondition withGroup(String name, String type) {\n\t\treturn new MetadataItemCondition(ItemType.GROUP, name).ofType(type);\n\t}\n\n\tpublic static MetadataItemCondition withProperty(String name) {\n\t\treturn new MetadataItemCondition(ItemType.PROPERTY, name);\n\t}\n\n\tpublic static MetadataItemCondition withProperty(String name, Class<?> type) {\n\t\treturn new MetadataItemCondition(ItemType.PROPERTY, name).ofType(type);\n\t}\n\n\tpublic static MetadataItemCondition withProperty(String name, String type) {\n\t\treturn new MetadataItemCondition(ItemType.PROPERTY, name).ofType(type);\n\t}\n\n\tpublic static Metadata.MetadataItemCondition withEnabledFlag(String key) {\n\t\treturn withProperty(key).ofType(Boolean.class);\n\t}\n\n\tpublic static Metadata.MetadataItemCondition withAccess(String key) {\n\t\treturn withProperty(key).ofType(TestAccess.class);\n\t}\n\n\tpublic static MetadataHintCondition withHint(String name) {\n\t\treturn new MetadataHintCondition(name);\n\t}\n\n\tpublic static class MetadataItemCondition extends Condition<ConfigurationMetadata> {\n\n\t\tprivate final ItemType itemType;\n\n\t\tprivate final String name;\n\n\t\tprivate final String type;\n\n\t\tprivate final Class<?> sourceType;\n\n\t\tprivate final String sourceMethod;\n\n\t\tprivate final String description;\n\n\t\tprivate final Object defaultValue;\n\n\t\tprivate final ItemDeprecation deprecation;\n\n\t\tpublic MetadataItemCondition(ItemType itemType, String name) {\n\t\t\tthis(itemType, name, null, null, null, null, null, null);\n\t\t}\n\n\t\tpublic MetadataItemCondition(ItemType itemType, String name, String type, Class<?> sourceType,\n\t\t\t\tString sourceMethod, String description, Object defaultValue, ItemDeprecation deprecation) {\n\t\t\tthis.itemType = itemType;\n\t\t\tthis.name = name;\n\t\t\tthis.type = type;\n\t\t\tthis.sourceType = sourceType;\n\t\t\tthis.sourceMethod = sourceMethod;\n\t\t\tthis.description = description;\n\t\t\tthis.defaultValue = defaultValue;\n\t\t\tthis.deprecation = deprecation;\n\t\t\tdescribedAs(createDescription());\n\t\t}\n\n\t\tprivate String createDescription() {\n\t\t\tStringBuilder description = new StringBuilder();\n\t\t\tdescription.append(\"an item named '\").append(this.name).append(\"'\");\n\t\t\tif (this.type != null) {\n\t\t\t\tdescription.append(\" with dataType:\").append(this.type);\n\t\t\t}\n\t\t\tif (this.sourceType != null) {\n\t\t\t\tdescription.append(\" with sourceType:\").append(this.sourceType);\n\t\t\t}\n\t\t\tif (this.sourceMethod != null) {\n\t\t\t\tdescription.append(\" with sourceMethod:\").append(this.sourceMethod);\n\t\t\t}\n\t\t\tif (this.defaultValue != null) {\n\t\t\t\tdescription.append(\" with defaultValue:\").append(this.defaultValue);\n\t\t\t}\n\t\t\tif (this.description != null) {\n\t\t\t\tdescription.append(\" with description:\").append(this.description);\n\t\t\t}\n\t\t\tif (this.deprecation != null) {\n\t\t\t\tdescription.append(\" with deprecation:\").append(this.deprecation);\n\t\t\t}\n\t\t\treturn description.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(ConfigurationMetadata value) {\n\t\t\tItemMetadata itemMetadata = findItem(value, this.name);\n\t\t\tif (itemMetadata == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.type != null && !this.type.equals(itemMetadata.getType())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.sourceType != null && !this.sourceType.getName().equals(itemMetadata.getSourceType())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.sourceMethod != null && !this.sourceMethod.equals(itemMetadata.getSourceMethod())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.defaultValue != null\n\t\t\t\t\t&& !ObjectUtils.nullSafeEquals(this.defaultValue, itemMetadata.getDefaultValue())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.defaultValue == null && itemMetadata.getDefaultValue() != null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.description != null && !this.description.equals(itemMetadata.getDescription())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.deprecation == null && itemMetadata.getDeprecation() != null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.deprecation == null || this.deprecation.equals(itemMetadata.getDeprecation());\n\t\t}\n\n\t\tpublic MetadataItemCondition ofType(Class<?> dataType) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, dataType.getName(), this.sourceType,\n\t\t\t\t\tthis.sourceMethod, this.description, this.defaultValue, this.deprecation);\n\t\t}\n\n\t\tpublic MetadataItemCondition ofType(String dataType) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, dataType, this.sourceType, this.sourceMethod,\n\t\t\t\t\tthis.description, this.defaultValue, this.deprecation);\n\t\t}\n\n\t\tpublic MetadataItemCondition fromSource(Class<?> sourceType) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, this.type, sourceType, this.sourceMethod,\n\t\t\t\t\tthis.description, this.defaultValue, this.deprecation);\n\t\t}\n\n\t\tpublic MetadataItemCondition fromSourceMethod(String sourceMethod) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, this.type, this.sourceType, sourceMethod,\n\t\t\t\t\tthis.description, this.defaultValue, this.deprecation);\n\t\t}\n\n\t\tpublic MetadataItemCondition withDescription(String description) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, this.type, this.sourceType, this.sourceMethod,\n\t\t\t\t\tdescription, this.defaultValue, this.deprecation);\n\t\t}\n\n\t\tpublic MetadataItemCondition withDefaultValue(Object defaultValue) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, this.type, this.sourceType, this.sourceMethod,\n\t\t\t\t\tthis.description, defaultValue, this.deprecation);\n\t\t}\n\n\t\tpublic MetadataItemCondition withDeprecation() {\n\t\t\treturn withDeprecation(null, null, null, null);\n\t\t}\n\n\t\tpublic MetadataItemCondition withDeprecation(String reason, String replacement, String since) {\n\t\t\treturn withDeprecation(reason, replacement, since, null);\n\t\t}\n\n\t\tpublic MetadataItemCondition withDeprecation(String reason, String replacement, String since, String level) {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, this.type, this.sourceType, this.sourceMethod,\n\t\t\t\t\tthis.description, this.defaultValue, new ItemDeprecation(reason, replacement, since, level));\n\t\t}\n\n\t\tpublic MetadataItemCondition withNoDeprecation() {\n\t\t\treturn new MetadataItemCondition(this.itemType, this.name, this.type, this.sourceType, this.sourceMethod,\n\t\t\t\t\tthis.description, this.defaultValue, null);\n\t\t}\n\n\t\tprivate ItemMetadata findItem(ConfigurationMetadata metadata, String name) {\n\t\t\tList<ItemMetadata> candidates = metadata.getItems()\n\t\t\t\t.stream()\n\t\t\t\t.filter((item) -> item.isOfItemType(this.itemType) && name.equals(item.getName()))\n\t\t\t\t.toList();\n\t\t\tif (candidates.size() > 1) {\n\t\t\t\tthrow new IllegalStateException(\"More than one metadata item with name '\" + name + \"': \" + candidates);\n\t\t\t}\n\t\t\treturn (candidates.size() == 1) ? candidates.get(0) : null;\n\t\t}\n\n\t}\n\n\tpublic static class MetadataHintCondition extends Condition<ConfigurationMetadata> {\n\n\t\tprivate final String name;\n\n\t\tprivate final List<ItemHintValueCondition> valueConditions;\n\n\t\tprivate final List<ItemHintProviderCondition> providerConditions;\n\n\t\tpublic MetadataHintCondition(String name) {\n\t\t\tthis.name = name;\n\t\t\tthis.valueConditions = Collections.emptyList();\n\t\t\tthis.providerConditions = Collections.emptyList();\n\t\t}\n\n\t\tpublic MetadataHintCondition(String name, List<ItemHintValueCondition> valueConditions,\n\t\t\t\tList<ItemHintProviderCondition> providerConditions) {\n\t\t\tthis.name = name;\n\t\t\tthis.valueConditions = valueConditions;\n\t\t\tthis.providerConditions = providerConditions;\n\t\t\tdescribedAs(createDescription());\n\t\t}\n\n\t\tprivate String createDescription() {\n\t\t\tStringBuilder description = new StringBuilder();\n\t\t\tdescription.append(\"a hints name '\").append(this.name).append(\"'\");\n\t\t\tif (!this.valueConditions.isEmpty()) {\n\t\t\t\tdescription.append(\" with values:\").append(this.valueConditions);\n\t\t\t}\n\t\t\tif (!this.providerConditions.isEmpty()) {\n\t\t\t\tdescription.append(\" with providers:\").append(this.providerConditions);\n\t\t\t}\n\t\t\treturn description.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(ConfigurationMetadata metadata) {\n\t\t\tItemHint itemHint = getFirstHintWithName(metadata, this.name);\n\t\t\tif (itemHint == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn matches(itemHint, this.valueConditions) && matches(itemHint, this.providerConditions);\n\t\t}\n\n\t\tprivate boolean matches(ItemHint itemHint, List<? extends Condition<ItemHint>> conditions) {\n\t\t\tfor (Condition<ItemHint> condition : conditions) {\n\t\t\t\tif (!condition.matches(itemHint)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate ItemHint getFirstHintWithName(ConfigurationMetadata metadata, String name) {\n\t\t\tfor (ItemHint hint : metadata.getHints()) {\n\t\t\t\tif (name.equals(hint.getName())) {\n\t\t\t\t\treturn hint;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic MetadataHintCondition withValue(int index, Object value, String description) {\n\t\t\treturn new MetadataHintCondition(this.name,\n\t\t\t\t\tadd(this.valueConditions, new ItemHintValueCondition(index, value, description)),\n\t\t\t\t\tthis.providerConditions);\n\t\t}\n\n\t\tpublic MetadataHintCondition withProvider(String provider) {\n\t\t\treturn withProvider(this.providerConditions.size(), provider, null);\n\t\t}\n\n\t\tpublic MetadataHintCondition withProvider(String provider, String key, Object value) {\n\t\t\treturn withProvider(this.providerConditions.size(), provider, Collections.singletonMap(key, value));\n\t\t}\n\n\t\tpublic MetadataHintCondition withProvider(int index, String provider, Map<String, Object> parameters) {\n\t\t\treturn new MetadataHintCondition(this.name, this.valueConditions,\n\t\t\t\t\tadd(this.providerConditions, new ItemHintProviderCondition(index, provider, parameters)));\n\t\t}\n\n\t\tprivate <T> List<T> add(List<T> items, T item) {\n\t\t\tList<T> result = new ArrayList<>(items);\n\t\t\tresult.add(item);\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tstatic class ItemHintValueCondition extends Condition<ItemHint> {\n\n\t\tprivate final int index;\n\n\t\tprivate final Object value;\n\n\t\tprivate final String description;\n\n\t\tItemHintValueCondition(int index, Object value, String description) {\n\t\t\tthis.index = index;\n\t\t\tthis.value = value;\n\t\t\tthis.description = description;\n\t\t\tdescribedAs(createDescription());\n\t\t}\n\n\t\tprivate String createDescription() {\n\t\t\tStringBuilder description = new StringBuilder();\n\t\t\tdescription.append(\"value hint at index '\").append(this.index).append(\"'\");\n\t\t\tif (this.value != null) {\n\t\t\t\tdescription.append(\" with value:\").append(this.value);\n\t\t\t}\n\t\t\tif (this.description != null) {\n\t\t\t\tdescription.append(\" with description:\").append(this.description);\n\t\t\t}\n\t\t\treturn description.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(ItemHint value) {\n\t\t\tif (this.index + 1 > value.getValues().size()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tItemHint.ValueHint valueHint = value.getValues().get(this.index);\n\t\t\tif (this.value != null && !this.value.equals(valueHint.getValue())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.description == null || this.description.equals(valueHint.getDescription());\n\t\t}\n\n\t}\n\n\tstatic class ItemHintProviderCondition extends Condition<ItemHint> {\n\n\t\tprivate final int index;\n\n\t\tprivate final String name;\n\n\t\tprivate final Map<String, Object> parameters;\n\n\t\tItemHintProviderCondition(int index, String name, Map<String, Object> parameters) {\n\t\t\tthis.index = index;\n\t\t\tthis.name = name;\n\t\t\tthis.parameters = parameters;\n\t\t\tdescribedAs(createDescription());\n\t\t}\n\n\t\tString createDescription() {\n\t\t\tStringBuilder description = new StringBuilder();\n\t\t\tdescription.append(\"value provider\");\n\t\t\tif (this.name != null) {\n\t\t\t\tdescription.append(\" with name:\").append(this.name);\n\t\t\t}\n\t\t\tif (this.parameters != null) {\n\t\t\t\tdescription.append(\" with parameters:\").append(this.parameters);\n\t\t\t}\n\t\t\treturn description.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(ItemHint hint) {\n\t\t\tif (this.index + 1 > hint.getProviders().size()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tItemHint.ValueProvider valueProvider = hint.getProviders().get(this.index);\n\t\t\tif (this.name != null && !this.name.equals(valueProvider.getName())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (this.parameters != null) {\n\t\t\t\tfor (Map.Entry<String, Object> entry : this.parameters.entrySet()) {\n\t\t\t\t\tif (!IsMapContaining.hasEntry(entry.getKey(), entry.getValue())\n\t\t\t\t\t\t.matches(valueProvider.getParameters())) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/metadata/TestJsonConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.metadata;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.configurationprocessor.json.JSONArray;\nimport org.springframework.boot.configurationprocessor.json.JSONObject;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\n\n/**\n * {@link JsonConverter} for use in tests.\n *\n * @author Phillip Webb\n */\npublic class TestJsonConverter extends JsonConverter {\n\n\t@Override\n\tpublic JSONArray toJsonArray(ConfigurationMetadata metadata, ItemType itemType) throws Exception {\n\t\treturn super.toJsonArray(metadata, itemType);\n\t}\n\n\t@Override\n\tpublic JSONArray toJsonArray(Collection<ItemHint> hints) throws Exception {\n\t\treturn super.toJsonArray(hints);\n\t}\n\n\t@Override\n\tpublic JSONObject toJsonObject(ItemMetadata item) throws Exception {\n\t\treturn super.toJsonObject(item);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/support/ConventionUtilsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.support;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConventionUtils}.\n *\n * @author Stephane Nicoll\n */\nclass ConventionUtilsTests {\n\n\t@Test\n\tvoid toDashedCaseCamelCase() {\n\t\tassertThat(toDashedCase(\"simpleCamelCase\")).isEqualTo(\"simple-camel-case\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseUpperCamelCaseSuffix() {\n\t\tassertThat(toDashedCase(\"myDLQ\")).isEqualTo(\"my-d-l-q\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseUpperCamelCaseMiddle() {\n\t\tassertThat(toDashedCase(\"someDLQKey\")).isEqualTo(\"some-d-l-q-key\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseWordsUnderscore() {\n\t\tassertThat(toDashedCase(\"Word_With_underscore\")).isEqualTo(\"word-with-underscore\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseWordsSeveralUnderscores() {\n\t\tassertThat(toDashedCase(\"Word___With__underscore\")).isEqualTo(\"word---with--underscore\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseLowerCaseUnderscore() {\n\t\tassertThat(toDashedCase(\"lower_underscore\")).isEqualTo(\"lower-underscore\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseUpperUnderscoreSuffix() {\n\t\tassertThat(toDashedCase(\"my_DLQ\")).isEqualTo(\"my-d-l-q\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseUpperUnderscoreMiddle() {\n\t\tassertThat(toDashedCase(\"some_DLQ_key\")).isEqualTo(\"some-d-l-q-key\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseMultipleUnderscores() {\n\t\tassertThat(toDashedCase(\"super___crazy\")).isEqualTo(\"super---crazy\");\n\t}\n\n\t@Test\n\tvoid toDashedCaseLowercase() {\n\t\tassertThat(toDashedCase(\"lowercase\")).isEqualTo(\"lowercase\");\n\t}\n\n\tprivate String toDashedCase(String name) {\n\t\treturn ConventionUtils.toDashedCase(name);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/test/CompiledMetadataReader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.test;\n\nimport java.io.InputStream;\n\nimport org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.JsonMarshaller;\nimport org.springframework.core.test.tools.Compiled;\nimport org.springframework.core.test.tools.TestCompiler;\n\n/**\n * Read the contents of metadata generated from the {@link TestCompiler}.\n *\n * @author Scott Frederick\n * @author Stephane Nicoll\n */\npublic final class CompiledMetadataReader {\n\n\tprivate static final String METADATA_FILE = \"META-INF/spring-configuration-metadata.json\";\n\n\tprivate CompiledMetadataReader() {\n\t}\n\n\tpublic static ConfigurationMetadata getMetadata(Compiled compiled) {\n\t\treturn getMetadata(compiled, METADATA_FILE);\n\t}\n\n\tpublic static ConfigurationMetadata getMetadata(Compiled compiled, String location) {\n\t\tInputStream inputStream = compiled.getClassLoader().getResourceAsStream(location);\n\t\ttry {\n\t\t\tif (inputStream != null) {\n\t\t\t\treturn new JsonMarshaller().read(inputStream);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(\"Failed to read metadata fom '%s'\".formatted(location), ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/test/ItemMetadataAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.test;\n\nimport java.util.function.Function;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.assertj.core.api.Assertions;\nimport org.assertj.core.api.ObjectAssert;\n\nimport org.springframework.boot.configurationprocessor.metadata.ItemDeprecation;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata;\nimport org.springframework.boot.configurationprocessor.metadata.ItemMetadata.ItemType;\n\n/**\n * AssertJ assert for {@link ItemMetadata}.\n *\n * @author Stephane Nicoll\n * @author Stefano Cordio\n */\npublic class ItemMetadataAssert extends AbstractAssert<ItemMetadataAssert, ItemMetadata>\n\t\timplements AssertProvider<ItemMetadataAssert> {\n\n\tpublic ItemMetadataAssert(ItemMetadata itemMetadata) {\n\t\tsuper(itemMetadata, ItemMetadataAssert.class);\n\t\tisNotNull();\n\t}\n\n\tpublic ItemMetadataAssert isProperty() {\n\t\textracting((actual) -> actual.isOfItemType(ItemType.PROPERTY)).isEqualTo(true);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert isGroup() {\n\t\textracting((actual) -> actual.isOfItemType(ItemType.GROUP)).isEqualTo(true);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert hasName(String name) {\n\t\textracting(ItemMetadata::getName).isEqualTo(name);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert hasType(String type) {\n\t\textracting(ItemMetadata::getType).isEqualTo(type);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert hasType(Class<?> type) {\n\t\treturn hasType(type.getName());\n\t}\n\n\tpublic ItemMetadataAssert hasDescription(String description) {\n\t\textracting(ItemMetadata::getDescription).isEqualTo(description);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert hasNoDescription() {\n\t\treturn hasDescription(null);\n\t}\n\n\tpublic ItemMetadataAssert hasSourceType(String type) {\n\t\textracting(ItemMetadata::getSourceType).isEqualTo(type);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert hasSourceType(Class<?> type) {\n\t\treturn hasSourceType(type.getName());\n\t}\n\n\tpublic ItemMetadataAssert hasSourceMethod(String method) {\n\t\textracting(ItemMetadata::getSourceMethod).isEqualTo(method);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert hasDefaultValue(Object defaultValue) {\n\t\textracting(ItemMetadata::getDefaultValue).isEqualTo(defaultValue);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert isDeprecatedWithNoInformation() {\n\t\tassertItemDeprecation();\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert isDeprecatedWithReason(String reason) {\n\t\tassertItemDeprecation().extracting(ItemDeprecation::getReason).isEqualTo(reason);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert isDeprecatedWithReplacement(String replacement) {\n\t\tassertItemDeprecation().extracting(ItemDeprecation::getReplacement).isEqualTo(replacement);\n\t\treturn this;\n\t}\n\n\tpublic ItemMetadataAssert isNotDeprecated() {\n\t\textracting(ItemMetadata::getDeprecation).isNull();\n\t\treturn this;\n\t}\n\n\tprivate ObjectAssert<ItemDeprecation> assertItemDeprecation() {\n\t\tObjectAssert<ItemDeprecation> itemDeprecationAssert = extracting(ItemMetadata::getDeprecation);\n\t\titemDeprecationAssert.extracting(ItemDeprecation::getLevel).isNull();\n\t\treturn itemDeprecationAssert;\n\t}\n\n\tprivate <T> ObjectAssert<T> extracting(Function<ItemMetadata, T> extractor) {\n\t\treturn extracting(extractor, Assertions::assertThat);\n\t}\n\n\t@Override\n\tpublic ItemMetadataAssert assertThat() {\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/test/RoundEnvironmentTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.test;\n\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.lang.model.element.TypeElement;\n\n/**\n * A tester utility for {@link RoundEnvironment}.\n *\n * @author Stephane Nicoll\n */\npublic class RoundEnvironmentTester {\n\n\tprivate final RoundEnvironment roundEnvironment;\n\n\tRoundEnvironmentTester(RoundEnvironment roundEnvironment) {\n\t\tthis.roundEnvironment = roundEnvironment;\n\t}\n\n\t/**\n\t * Return the root {@link TypeElement} for the specified {@code type}.\n\t * @param type the type of the class\n\t * @return the {@link TypeElement}\n\t */\n\tpublic TypeElement getRootElement(Class<?> type) {\n\t\treturn (TypeElement) this.roundEnvironment.getRootElements()\n\t\t\t.stream()\n\t\t\t.filter((element) -> element.toString().equals(type.getName()))\n\t\t\t.findFirst()\n\t\t\t.orElseThrow(() -> new IllegalStateException(\n\t\t\t\t\t\"No element found for \" + type + \" make sure it is included in the list of classes to compile\"));\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/test/TestConfigurationMetadataAnnotationProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.test;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\n\nimport org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor;\n\n/**\n * Test {@link ConfigurationMetadataAnnotationProcessor}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Kris De Volder\n * @author Scott Frederick\n */\n@SupportedAnnotationTypes({ TestConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.CONTROLLER_ENDPOINT_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.ENDPOINT_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.JMX_ENDPOINT_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.REST_CONTROLLER_ENDPOINT_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.SERVLET_ENDPOINT_ANNOTATION,\n\t\tTestConfigurationMetadataAnnotationProcessor.WEB_ENDPOINT_ANNOTATION,\n\t\t\"org.springframework.context.annotation.Configuration\" })\n@SupportedSourceVersion(SourceVersion.RELEASE_6)\npublic class TestConfigurationMetadataAnnotationProcessor extends ConfigurationMetadataAnnotationProcessor {\n\n\tpublic static final String CONFIGURATION_PROPERTIES_ANNOTATION = \"org.springframework.boot.configurationsample.TestConfigurationProperties\";\n\n\tpublic static final String CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION = \"org.springframework.boot.configurationsample.TestConfigurationPropertiesSource\";\n\n\tpublic static final String NESTED_CONFIGURATION_PROPERTY_ANNOTATION = \"org.springframework.boot.configurationsample.TestNestedConfigurationProperty\";\n\n\tpublic static final String DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION = \"org.springframework.boot.configurationsample.TestDeprecatedConfigurationProperty\";\n\n\tpublic static final String CONSTRUCTOR_BINDING_ANNOTATION = \"org.springframework.boot.configurationsample.TestConstructorBinding\";\n\n\tpublic static final String AUTOWIRED_ANNOTATION = \"org.springframework.boot.configurationsample.TestAutowired\";\n\n\tpublic static final String DEFAULT_VALUE_ANNOTATION = \"org.springframework.boot.configurationsample.TestDefaultValue\";\n\n\tpublic static final String CONTROLLER_ENDPOINT_ANNOTATION = \"org.springframework.boot.configurationsample.TestControllerEndpoint\";\n\n\tpublic static final String ENDPOINT_ANNOTATION = \"org.springframework.boot.configurationsample.TestEndpoint\";\n\n\tpublic static final String JMX_ENDPOINT_ANNOTATION = \"org.springframework.boot.configurationsample.TestJmxEndpoint\";\n\n\tpublic static final String REST_CONTROLLER_ENDPOINT_ANNOTATION = \"org.springframework.boot.configurationsample.TestRestControllerEndpoint\";\n\n\tpublic static final String SERVLET_ENDPOINT_ANNOTATION = \"org.springframework.boot.configurationsample.TestServletEndpoint\";\n\n\tpublic static final String WEB_ENDPOINT_ANNOTATION = \"org.springframework.boot.configurationsample.TestWebEndpoint\";\n\n\tpublic static final String READ_OPERATION_ANNOTATION = \"org.springframework.boot.configurationsample.TestReadOperation\";\n\n\tpublic static final String NAME_ANNOTATION = \"org.springframework.boot.configurationsample.TestName\";\n\n\tpublic static final String ENDPOINT_ACCESS_ENUM = \"org.springframework.boot.configurationsample.TestAccess\";\n\n\tpublic TestConfigurationMetadataAnnotationProcessor() {\n\t}\n\n\t@Override\n\tprotected String configurationPropertiesAnnotation() {\n\t\treturn CONFIGURATION_PROPERTIES_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String configurationPropertiesSourceAnnotation() {\n\t\treturn CONFIGURATION_PROPERTIES_SOURCE_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String nestedConfigurationPropertyAnnotation() {\n\t\treturn NESTED_CONFIGURATION_PROPERTY_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String deprecatedConfigurationPropertyAnnotation() {\n\t\treturn DEPRECATED_CONFIGURATION_PROPERTY_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String constructorBindingAnnotation() {\n\t\treturn CONSTRUCTOR_BINDING_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String autowiredAnnotation() {\n\t\treturn AUTOWIRED_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String defaultValueAnnotation() {\n\t\treturn DEFAULT_VALUE_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected Set<String> endpointAnnotations() {\n\t\treturn new HashSet<>(Arrays.asList(CONTROLLER_ENDPOINT_ANNOTATION, ENDPOINT_ANNOTATION, JMX_ENDPOINT_ANNOTATION,\n\t\t\t\tREST_CONTROLLER_ENDPOINT_ANNOTATION, SERVLET_ENDPOINT_ANNOTATION, WEB_ENDPOINT_ANNOTATION));\n\t}\n\n\t@Override\n\tprotected String readOperationAnnotation() {\n\t\treturn READ_OPERATION_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String nameAnnotation() {\n\t\treturn NAME_ANNOTATION;\n\t}\n\n\t@Override\n\tprotected String endpointAccessEnum() {\n\t\treturn ENDPOINT_ACCESS_ENUM;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/test/TestableAnnotationProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.test;\n\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.ProcessingEnvironment;\nimport javax.annotation.processing.Processor;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.annotation.processing.SupportedSourceVersion;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.TypeElement;\n\n/**\n * A testable {@link Processor}.\n *\n * @param <T> the type of element to help writing assertions\n * @author Stephane Nicoll\n */\n@SupportedAnnotationTypes(\"*\")\n@SupportedSourceVersion(SourceVersion.RELEASE_8)\npublic class TestableAnnotationProcessor<T> extends AbstractProcessor {\n\n\tprivate final BiConsumer<RoundEnvironmentTester, T> consumer;\n\n\tprivate final Function<ProcessingEnvironment, T> factory;\n\n\tprivate T target;\n\n\tpublic TestableAnnotationProcessor(BiConsumer<RoundEnvironmentTester, T> consumer,\n\t\t\tFunction<ProcessingEnvironment, T> factory) {\n\t\tthis.consumer = consumer;\n\t\tthis.factory = factory;\n\t}\n\n\t@Override\n\tpublic synchronized void init(ProcessingEnvironment env) {\n\t\tthis.target = this.factory.apply(env);\n\t}\n\n\t@Override\n\tpublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n\t\tRoundEnvironmentTester tester = new RoundEnvironmentTester(roundEnv);\n\t\tif (!roundEnv.getRootElements().isEmpty()) {\n\t\t\tthis.consumer.accept(tester, this.target);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestAccess.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\n/**\n * Alternative to Spring Boot's {@code @Access} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Andy Wilkinson\n */\npublic enum TestAccess {\n\n\tNONE,\n\n\tREAD_ONLY,\n\n\tUNRESTRICTED\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestAutowired.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Framework's {@code @Autowired} for testing (removes the need for\n * a dependency on the real annotation).\n *\n * @author Madhura Bhave\n */\n@Target({ ElementType.TYPE, ElementType.CONSTRUCTOR })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestAutowired {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ConfigurationProperties} for testing (removes the\n * need for a dependency on the real annotation).\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConfigurationProperties {\n\n\tString value() default \"\";\n\n\tString prefix() default \"\";\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestConfigurationPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ConfigurationProperties} for testing (removes the\n * need for a dependency on the real annotation).\n *\n * @author Stephane Nicoll\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConfigurationPropertiesSource {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestConstructorBinding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ConstructorBinding} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Stephane Nicoll\n */\n@Target({ ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConstructorBinding {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ControllerEndpoint} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestControllerEndpoint {\n\n\tString id() default \"\";\n\n\t@Deprecated\n\tboolean enableByDefault() default true;\n\n\tTestAccess defaultAccess() default TestAccess.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestDefaultValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @DefaultValue} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Stephane Nicoll\n * @author Pavel Anisimov\n */\n@Target({ ElementType.PARAMETER })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestDefaultValue {\n\n\tString[] value() default {};\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestDeprecatedConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @DeprecatedConfigurationProperty} for testing\n * (removes the need for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestDeprecatedConfigurationProperty {\n\n\t/**\n\t * The reason for the deprecation.\n\t * @return the deprecation reason\n\t */\n\tString reason() default \"\";\n\n\t/**\n\t * The field that should be used instead (if any).\n\t * @return the replacement field\n\t */\n\tString replacement() default \"\";\n\n\t/**\n\t * The version in which the property became deprecated.\n\t * @return the version\n\t */\n\tString since() default \"\";\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @Endpoint} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Stephane Nicoll\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestEndpoint {\n\n\tString id() default \"\";\n\n\tTestAccess defaultAccess() default TestAccess.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestJmxEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @JmxEndpoint} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestJmxEndpoint {\n\n\tString id() default \"\";\n\n\tTestAccess defaultAccess() default TestAccess.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @Name} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.PARAMETER, ElementType.FIELD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestName {\n\n\tString value();\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestNestedConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @NestedConfigurationProperty} for testing (removes\n * the need for a dependency on the real annotation).\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 1.2.0\n */\n@Target({ ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestNestedConfigurationProperty {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestReadOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ReadOperation} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Stephane Nicoll\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestReadOperation {\n\n\tString[] produces() default {};\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestRestControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @RestControllerEndpoint} for testing (removes the\n * need for a dependency on the real annotation).\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestRestControllerEndpoint {\n\n\tString id() default \"\";\n\n\tTestAccess defaultAccess() default TestAccess.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestServletEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ServletEndpoint} for testing (removes the need for\n * a dependency on the real annotation).\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestServletEndpoint {\n\n\tString id() default \"\";\n\n\tTestAccess defaultAccess() default TestAccess.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/TestWebEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @WebEndpoint} for testing (removes the need for a\n * dependency on the real annotation).\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestWebEndpoint {\n\n\tString id() default \"\";\n\n\tTestAccess defaultAccess() default TestAccess.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/deprecation/Dbcp2Configuration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.deprecation;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Test configuration for DBCP2 {@link BasicDataSource}.\n *\n * @author Moritz Halbritter\n */\npublic class Dbcp2Configuration {\n\n\t@TestConfigurationProperties(\"spring.datasource.dbcp2\")\n\tBasicDataSource basicDataSource() {\n\t\treturn new BasicDataSource();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/CamelCaseEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\n\n/**\n * An endpoint with an upper camel case id.\n *\n * @author Stephane Nicoll\n */\n@TestEndpoint(id = \"PascalCase\")\npublic class CamelCaseEndpoint {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/CustomPropertiesEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * An endpoint with additional custom properties.\n *\n * @author Stephane Nicoll\n */\n@TestEndpoint(id = \"customprops\")\n@TestConfigurationProperties(\"management.endpoint.customprops\")\npublic class CustomPropertiesEndpoint {\n\n\tprivate String name = \"test\";\n\n\t@TestReadOperation\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/EnabledEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * An endpoint that is enabled unless configured explicitly.\n *\n * @author Stephane Nicoll\n */\n@TestEndpoint(id = \"enabled\")\npublic class EnabledEndpoint {\n\n\tpublic String someMethod() {\n\t\treturn \"not a read operation\";\n\t}\n\n\t@TestReadOperation\n\tpublic String retrieve(String parameter, Integer anotherParameter) {\n\t\treturn \"not a main read operation\";\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/NoAccessEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestAccess;\nimport org.springframework.boot.configurationsample.TestEndpoint;\n\n/**\n * An endpoint with no permitted access unless configured explicitly.\n *\n * @author Andy Wilkinson\n */\n@TestEndpoint(id = \"noaccess\", defaultAccess = TestAccess.NONE)\npublic class NoAccessEndpoint {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/NullableParameterEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * An endpoint that uses {@code Nullable} to signal an optional parameter.\n *\n * @author Wonyong Hwang\n */\n@TestEndpoint(id = \"nullable\")\npublic class NullableParameterEndpoint {\n\n\t@TestReadOperation\n\tpublic String invoke(@Nullable String parameter) {\n\t\treturn \"test with \" + parameter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/ReadOnlyAccessEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestAccess;\nimport org.springframework.boot.configurationsample.TestEndpoint;\n\n/**\n * An endpoint with read-only access unless configured explicitly.\n *\n * @author Andy Wilkinson\n */\n@TestEndpoint(id = \"readonlyaccess\", defaultAccess = TestAccess.READ_ONLY)\npublic class ReadOnlyAccessEndpoint {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/SimpleEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * A simple endpoint with no default override.\n *\n * @author Stephane Nicoll\n */\n@TestEndpoint(id = \"simple\")\npublic class SimpleEndpoint {\n\n\t@TestReadOperation\n\tpublic String invoke() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/SimpleEndpoint2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * A simple endpoint with no default override, with the same id as {@link SimpleEndpoint}.\n *\n * @author Moritz Halbritter\n */\n@TestEndpoint(id = \"simple\")\npublic class SimpleEndpoint2 {\n\n\t@TestReadOperation\n\tpublic String invoke() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/SimpleEndpoint3.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestAccess;\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * A simple endpoint with no default override, with the same id as {@link SimpleEndpoint},\n * but with no access by default.\n *\n * @author Moritz Halbritter\n */\n@TestEndpoint(id = \"simple\", defaultAccess = TestAccess.NONE)\npublic class SimpleEndpoint3 {\n\n\t@TestReadOperation\n\tpublic String invoke() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/SpecificEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.configurationsample.TestAccess;\nimport org.springframework.boot.configurationsample.TestReadOperation;\nimport org.springframework.boot.configurationsample.TestWebEndpoint;\n\n/**\n * A meta-annotated endpoint. Also with a package private read operation that has an\n * optional argument.\n *\n * @author Stephane Nicoll\n */\n@TestWebEndpoint(id = \"specific\", defaultAccess = TestAccess.READ_ONLY)\npublic class SpecificEndpoint {\n\n\t@TestReadOperation\n\tString invoke(@Nullable String param) {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/UnrestrictedAccessEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\n\n/**\n * An endpoint with unrestricted access unless configured explicitly.\n *\n * @author Andy Wilkinson\n */\n@TestEndpoint(id = \"unrestrictedaccess\")\npublic class UnrestrictedAccessEndpoint {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/incremental/IncrementalEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint.incremental;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.configurationsample.TestEndpoint;\nimport org.springframework.boot.configurationsample.TestReadOperation;\n\n/**\n * An endpoint that is enabled by default.\n *\n * @author Stephane Nicoll\n */\n@TestEndpoint(id = \"incremental\")\npublic class IncrementalEndpoint {\n\n\t@TestReadOperation\n\tpublic String invoke(@Nullable String param) {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/endpoint/incremental/IncrementalSpecificEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.endpoint.incremental;\n\nimport org.springframework.boot.configurationsample.TestJmxEndpoint;\n\n/**\n * A meta-annotated endpoint.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\n@TestJmxEndpoint(id = \"incremental\")\npublic class IncrementalSpecificEndpoint {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/FieldValues.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.fieldvalues;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Sample object containing fields with initial values.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\n@TestConfigurationProperties\npublic class FieldValues {\n\n\tprivate static final String STRING_CONST = \"c\";\n\n\tprivate static final boolean BOOLEAN_CONST = true;\n\n\tprivate static final Boolean BOOLEAN_OBJ_CONST = true;\n\n\tprivate static final int INTEGER_CONST = 2;\n\n\tprivate static final Integer INTEGER_OBJ_CONST = 4;\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\tprivate static final MimeType DEFAULT_MIME_TYPE = MimeType.valueOf(\"text/plain\");\n\n\tprivate static final String[] STRING_ARRAY_CONST = new String[] { \"OK\", \"KO\" };\n\n\tprivate String string = \"1\";\n\n\tprivate String stringNone;\n\n\tprivate String stringConst = STRING_CONST;\n\n\tprivate boolean bool = true;\n\n\tprivate boolean boolNone;\n\n\tprivate boolean boolConst = BOOLEAN_CONST;\n\n\tprivate boolean boolInverted = !false;\n\n\tprivate Boolean boolObject = Boolean.TRUE;\n\n\tprivate Boolean boolObjectNone;\n\n\tprivate Boolean boolObjectConst = BOOLEAN_OBJ_CONST;\n\n\tprivate int integer = 1;\n\n\tprivate int integerNone;\n\n\tprivate int integerConst = INTEGER_CONST;\n\n\tprivate int integerArithmetic = 10 * 10;\n\n\tprivate int integerMax = Math.max(10, 20);\n\n\tprivate Integer integerObject = 3;\n\n\tprivate Integer integerObjectNone;\n\n\tprivate Integer integerObjectConst = INTEGER_OBJ_CONST;\n\n\tprivate Charset charset = StandardCharsets.US_ASCII;\n\n\tprivate Charset charsetConst = DEFAULT_CHARSET;\n\n\tprivate MimeType mimeType = MimeType.valueOf(\"text/html\");\n\n\tprivate MimeType mimeTypeConst = DEFAULT_MIME_TYPE;\n\n\tprivate Object object = 123;\n\n\tprivate Object objectNone;\n\n\tprivate Object objectConst = STRING_CONST;\n\n\tprivate Object objectInstance = new StringBuffer();\n\n\tprivate String[] stringArray = new String[] { \"FOO\", \"BAR\" };\n\n\tprivate String[] stringArrayNone;\n\n\tprivate String[] stringEmptyArray = new String[0];\n\n\tprivate String[] stringArrayConst = STRING_ARRAY_CONST;\n\n\tprivate String[] stringArrayConstElements = new String[] { STRING_CONST };\n\n\tprivate Integer[] integerArray = new Integer[] { 42, 24 };\n\n\tprivate int[] intArrayUnsupportedExpression = new int[] { 10 + 10 };\n\n\tprivate UnknownElementType[] unknownArray = new UnknownElementType[] { new UnknownElementType() };\n\n\tprivate Duration durationNone;\n\n\tprivate Duration durationNanos = Duration.ofNanos(5);\n\n\tprivate Duration durationMillis = Duration.ofMillis(10);\n\n\tprivate Duration durationSeconds = Duration.ofSeconds(20);\n\n\tprivate Duration durationMinutes = Duration.ofMinutes(30);\n\n\tprivate Duration durationHours = Duration.ofHours(40);\n\n\tprivate Duration durationDays = Duration.ofDays(50);\n\n\tprivate Duration durationZero = Duration.ZERO;\n\n\tprivate DataSize dataSizeNone;\n\n\tprivate DataSize dataSizeBytes = DataSize.ofBytes(5);\n\n\tprivate DataSize dataSizeKilobytes = DataSize.ofKilobytes(10);\n\n\tprivate DataSize dataSizeMegabytes = DataSize.ofMegabytes(20);\n\n\tprivate DataSize dataSizeGigabytes = DataSize.ofGigabytes(30);\n\n\tprivate DataSize dataSizeTerabytes = DataSize.ofTerabytes(40);\n\n\tprivate Period periodNone;\n\n\tprivate Period periodDays = Period.ofDays(3);\n\n\tprivate Period periodWeeks = Period.ofWeeks(2);\n\n\tprivate Period periodMonths = Period.ofMonths(10);\n\n\tprivate Period periodYears = Period.ofYears(15);\n\n\tprivate Period periodZero = Period.ZERO;\n\n\tprivate ChronoUnit enumNone;\n\n\tprivate ChronoUnit enumSimple = ChronoUnit.SECONDS;\n\n\tprivate java.time.temporal.ChronoField enumQualified = java.time.temporal.ChronoField.HOUR_OF_DAY;\n\n\tprivate ChronoUnit enumWithIndirection = SampleOptions.DEFAULT_UNIT;\n\n\tprivate int memberSelectInt = SampleOptions.DEFAULT_MAX_RETRIES;\n\n\tpublic static class SampleOptions {\n\n\t\tstatic final Integer DEFAULT_MAX_RETRIES = 20;\n\n\t\tstatic final ChronoUnit DEFAULT_UNIT = ChronoUnit.SECONDS;\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/fieldvalues/UnknownElementType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.fieldvalues;\n\n/**\n * Type used to check unknown array element types.\n *\n * @author Phillip Webb\n */\npublic class UnknownElementType {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/AbstractGenericProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A base properties class with generics.\n *\n * @param <A> name type\n * @param <B> mapping key type\n * @param <C> mapping value type\n * @author Stephane Nicoll\n */\npublic class AbstractGenericProperties<A, B, C> {\n\n\t/**\n\t * Generic name.\n\t */\n\tprivate A name;\n\n\t/**\n\t * Generic mappings.\n\t */\n\tprivate final Map<B, C> mappings = new HashMap<>();\n\n\tpublic A getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(A name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Map<B, C> getMappings() {\n\t\treturn this.mappings;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/AbstractIntermediateGenericProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\n/**\n * An intermediate layer that resolves some of the generics from the parent but not all.\n *\n * @param <C> mapping value type\n * @author Stephane Nicoll\n */\npublic abstract class AbstractIntermediateGenericProperties<C> extends AbstractGenericProperties<String, Integer, C> {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/ComplexGenericProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n/**\n * More advanced generic setup.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"generic\")\npublic class ComplexGenericProperties {\n\n\t@TestNestedConfigurationProperty\n\tprivate final UpperBoundGenericPojo<Test> test = new UpperBoundGenericPojo<>();\n\n\tpublic UpperBoundGenericPojo<Test> getTest() {\n\t\treturn this.test;\n\t}\n\n\tpublic enum Test {\n\n\t\tONE, TWO, THREE\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/ConcreteBuilderProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Builder pattern with a resolved generic\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"builder\")\npublic class ConcreteBuilderProperties extends GenericBuilderProperties<ConcreteBuilderProperties> {\n\n\tprivate String description;\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic ConcreteBuilderProperties setDescription(String description) {\n\t\tthis.description = description;\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/GenericBuilderProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\n/**\n * A configuration properties that uses the builder pattern with a generic.\n *\n * @param <T> the type of the return type\n * @author Stephane Nicoll\n */\npublic class GenericBuilderProperties<T extends GenericBuilderProperties<T>> {\n\n\tprivate int number;\n\n\tpublic int getNumber() {\n\t\treturn this.number;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic T setNumber(int number) {\n\t\tthis.number = number;\n\t\treturn (T) this;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/GenericConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n/**\n * Demonstrate that only relevant generics are stored in the metadata.\n *\n * @param <T> the type of the config\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"generic\")\npublic class GenericConfig<T> {\n\n\tprivate final Foo foo = new Foo();\n\n\tpublic Foo getFoo() {\n\t\treturn this.foo;\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\t@TestNestedConfigurationProperty\n\t\tprivate final Bar<String> bar = new Bar<>();\n\n\t\tprivate final Map<String, Bar<Integer>> stringToBar = new HashMap<>();\n\n\t\tprivate final Map<String, Integer> stringToInteger = new HashMap<>();\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Bar<String> getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tpublic Map<String, Bar<Integer>> getStringToBar() {\n\t\t\treturn this.stringToBar;\n\t\t}\n\n\t\tpublic Map<String, Integer> getStringToInteger() {\n\t\t\treturn this.stringToInteger;\n\t\t}\n\n\t}\n\n\tpublic static class Bar<U> {\n\n\t\tprivate String name;\n\n\t\t@TestNestedConfigurationProperty\n\t\tprivate final Biz<String> biz = new Biz<>();\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Biz<String> getBiz() {\n\t\t\treturn this.biz;\n\t\t}\n\n\t\tpublic static class Biz<V> {\n\n\t\t\tprivate String name;\n\n\t\t\tpublic String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic void setName(String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/MixGenericNameProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\n/**\n * Properties with unresolved generic types that use identical generic parameter names but\n * differ in their positions.\n *\n * @param <C> mapping name type\n * @param <B> mapping value type\n * @author Dmytro Nosan\n */\npublic class MixGenericNameProperties<B, C extends Number> extends AbstractGenericProperties<String, C, B> {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/SimpleGenericProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Simple properties with resolved generic information.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"generic\")\npublic class SimpleGenericProperties extends AbstractIntermediateGenericProperties<Duration> {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/UnresolvedGenericProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Properties with unresolved generic information.\n *\n * @param <B> mapping key type\n * @param <C> mapping value type\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"generic\")\npublic class UnresolvedGenericProperties<B extends Number, C> extends AbstractGenericProperties<String, B, C> {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/UpperBoundGenericPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A pojo with a complex generic signature.\n *\n * @param <T> the generic type\n * @author Stephane Nicoll\n */\npublic class UpperBoundGenericPojo<T extends Enum<T>> {\n\n\tprivate final Map<T, String> mappings = new HashMap<>();\n\n\tpublic Map<T, String> getMappings() {\n\t\treturn this.mappings;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/WildcardConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.generic;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrate properties with a wildcard type.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"wildcard\")\npublic class WildcardConfig {\n\n\tprivate Map<String, ? extends Number> stringToNumber;\n\n\tprivate List<? super Integer> integers;\n\n\tpublic Map<String, ? extends Number> getStringToNumber() {\n\t\treturn this.stringToNumber;\n\t}\n\n\tpublic void setStringToNumber(Map<String, ? extends Number> stringToNumber) {\n\t\tthis.stringToNumber = stringToNumber;\n\t}\n\n\tpublic List<? super Integer> getIntegers() {\n\t\treturn this.integers;\n\t}\n\n\tpublic void setIntegers(List<? super Integer> integers) {\n\t\tthis.integers = integers;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/DeducedImmutableClassProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Inner properties, in immutable format.\n *\n * @author Phillip Webb\n */\n@TestConfigurationProperties(\"test\")\npublic class DeducedImmutableClassProperties {\n\n\tprivate final Nested nested;\n\n\tpublic DeducedImmutableClassProperties(@TestDefaultValue Nested nested) {\n\t\tthis.nested = nested;\n\t}\n\n\tpublic Nested getNested() {\n\t\treturn this.nested;\n\t}\n\n\tpublic static class Nested {\n\n\t\tprivate final String name;\n\n\t\tpublic Nested(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutableClassConstructorBindingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\n/**\n * Simple immutable properties with several constructors.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class ImmutableClassConstructorBindingProperties {\n\n\tprivate final String name;\n\n\tprivate final String description;\n\n\tpublic ImmutableClassConstructorBindingProperties(String name, String description) {\n\t\tthis.name = name;\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutableCollectionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Simple immutable properties with collections types and defaults.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class ImmutableCollectionProperties {\n\n\tprivate final List<String> names;\n\n\tprivate final List<Boolean> flags;\n\n\tprivate final List<Duration> durations;\n\n\tpublic ImmutableCollectionProperties(List<String> names, @TestDefaultValue({ \"true\", \"false\" }) List<Boolean> flags,\n\t\t\t@TestDefaultValue({ \"10s\", \"1m\", \"1h\" }) List<Duration> durations) {\n\t\tthis.names = names;\n\t\tthis.flags = flags;\n\t\tthis.durations = durations;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutableDeducedConstructorBindingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * @author Madhura Bhave\n */\n@TestConfigurationProperties(\"immutable\")\npublic class ImmutableDeducedConstructorBindingProperties {\n\n\t/**\n\t * The name of these properties.\n\t */\n\tprivate final String theName;\n\n\t/**\n\t * A simple flag.\n\t */\n\tprivate final boolean flag;\n\n\tpublic ImmutableDeducedConstructorBindingProperties(@TestDefaultValue(\"boot\") String theName, boolean flag) {\n\t\tthis.theName = theName;\n\t\tthis.flag = flag;\n\t}\n\n\tpublic String getTheName() {\n\t\treturn this.theName;\n\t}\n\n\tpublic boolean isFlag() {\n\t\treturn this.flag;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutableInnerClassProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\nimport org.springframework.boot.configurationsample.specific.SimplePojo;\n\n/**\n * Inner properties, in immutable format.\n *\n * @author Stephane Nicoll\n */\npublic class ImmutableInnerClassProperties {\n\n\tprivate final Foo first;\n\n\tprivate Foo second;\n\n\t@TestNestedConfigurationProperty\n\tprivate final SimplePojo third;\n\n\tprivate final Fourth fourth;\n\n\tpublic ImmutableInnerClassProperties(Foo first, Foo second, SimplePojo third, Fourth fourth) {\n\t\tthis.first = first;\n\t\tthis.second = second;\n\t\tthis.third = third;\n\t\tthis.fourth = fourth;\n\t}\n\n\tpublic Foo getFirst() {\n\t\treturn this.first;\n\t}\n\n\tpublic Foo getTheSecond() {\n\t\treturn this.second;\n\t}\n\n\tpublic void setTheSecond(Foo second) {\n\t\tthis.second = second;\n\t}\n\n\tpublic SimplePojo getThird() {\n\t\treturn this.third;\n\t}\n\n\tpublic Fourth getFourth() {\n\t\treturn this.fourth;\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate final Bar bar = new Bar();\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Bar getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tpublic static class Bar {\n\n\t\t\tprivate String name;\n\n\t\t\tpublic String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic void setName(String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic enum Fourth {\n\n\t\tYES, NO\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutableMultiConstructorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport org.springframework.boot.configurationsample.TestConstructorBinding;\n\n/**\n * Simple immutable properties with several constructors.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class ImmutableMultiConstructorProperties {\n\n\tprivate final String name;\n\n\t/**\n\t * Test description.\n\t */\n\tprivate final String description;\n\n\tpublic ImmutableMultiConstructorProperties(String name) {\n\t\tthis(name, null);\n\t}\n\n\t@TestConstructorBinding\n\tpublic ImmutableMultiConstructorProperties(String name, String description) {\n\t\tthis.name = name;\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutablePrimitiveProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\n/**\n * Simple immutable properties with primitive types.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class ImmutablePrimitiveProperties {\n\n\tprivate final boolean flag;\n\n\tprivate final byte octet;\n\n\tprivate final char letter;\n\n\tprivate final short number;\n\n\tprivate final int counter;\n\n\tprivate final long value;\n\n\tprivate final float percentage;\n\n\tprivate final double ratio;\n\n\tpublic ImmutablePrimitiveProperties(boolean flag, byte octet, char letter, short number, int counter, long value,\n\t\t\tfloat percentage, double ratio) {\n\t\tthis.flag = flag;\n\t\tthis.octet = octet;\n\t\tthis.letter = letter;\n\t\tthis.number = number;\n\t\tthis.counter = counter;\n\t\tthis.value = value;\n\t\tthis.percentage = percentage;\n\t\tthis.ratio = ratio;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutablePrimitiveWithDefaultsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Simple immutable properties with primitive types and defaults.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class ImmutablePrimitiveWithDefaultsProperties {\n\n\tprivate final boolean flag;\n\n\tprivate final byte octet;\n\n\tprivate final char letter;\n\n\tprivate final short number;\n\n\tprivate final int counter;\n\n\tprivate final long value;\n\n\tprivate final float percentage;\n\n\tprivate final double ratio;\n\n\tpublic ImmutablePrimitiveWithDefaultsProperties(@TestDefaultValue(\"true\") boolean flag,\n\t\t\t@TestDefaultValue(\"120\") byte octet, @TestDefaultValue(\"a\") char letter,\n\t\t\t@TestDefaultValue(\"1000\") short number, @TestDefaultValue(\"42\") int counter,\n\t\t\t@TestDefaultValue(\"2000\") long value, @TestDefaultValue(\"0.5\") float percentage,\n\t\t\t@TestDefaultValue(\"42.42\") double ratio) {\n\t\tthis.flag = flag;\n\t\tthis.octet = octet;\n\t\tthis.letter = letter;\n\t\tthis.number = number;\n\t\tthis.counter = counter;\n\t\tthis.value = value;\n\t\tthis.percentage = percentage;\n\t\tthis.ratio = ratio;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutablePrimitiveWrapperWithDefaultsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Simple immutable properties with primitive wrapper types and defaults.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class ImmutablePrimitiveWrapperWithDefaultsProperties {\n\n\tprivate final Boolean flag;\n\n\tprivate final Byte octet;\n\n\tprivate final Character letter;\n\n\tprivate final Short number;\n\n\tprivate final Integer counter;\n\n\tprivate final Long value;\n\n\tprivate final Float percentage;\n\n\tprivate final Double ratio;\n\n\tpublic ImmutablePrimitiveWrapperWithDefaultsProperties(@TestDefaultValue(\"true\") Boolean flag,\n\t\t\t@TestDefaultValue(\"120\") Byte octet, @TestDefaultValue(\"a\") Character letter,\n\t\t\t@TestDefaultValue(\"1000\") Short number, @TestDefaultValue(\"42\") Integer counter,\n\t\t\t@TestDefaultValue(\"2000\") Long value, @TestDefaultValue(\"0.5\") Float percentage,\n\t\t\t@TestDefaultValue(\"42.42\") Double ratio) {\n\t\tthis.flag = flag;\n\t\tthis.octet = octet;\n\t\tthis.letter = letter;\n\t\tthis.number = number;\n\t\tthis.counter = counter;\n\t\tthis.value = value;\n\t\tthis.percentage = percentage;\n\t\tthis.ratio = ratio;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/immutable/ImmutableSimpleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.immutable;\n\nimport java.util.Comparator;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestConstructorBinding;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Simple properties, in immutable format.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"immutable\")\npublic class ImmutableSimpleProperties {\n\n\t/**\n\t * The name of this simple properties.\n\t */\n\tprivate final String theName;\n\n\t/**\n\t * A simple flag.\n\t */\n\tprivate final boolean flag;\n\n\t// An interface can still be injected because it might have a converter\n\tprivate final Comparator<?> comparator;\n\n\t// Even if it is not exposed, we're still offering a way to bind the value through the\n\t// constructor, so it should be present in the metadata\n\t@SuppressWarnings(\"unused\")\n\tprivate final Long counter;\n\n\t@TestConstructorBinding\n\tpublic ImmutableSimpleProperties(@TestDefaultValue(\"boot\") String theName, boolean flag, Comparator<?> comparator,\n\t\t\tLong counter) {\n\t\tthis.theName = theName;\n\t\tthis.flag = flag;\n\t\tthis.comparator = comparator;\n\t\tthis.counter = counter;\n\t}\n\n\tpublic String getTheName() {\n\t\treturn this.theName;\n\t}\n\n\t@Deprecated\n\tpublic boolean isFlag() {\n\t\treturn this.flag;\n\t}\n\n\tpublic Comparator<?> getComparator() {\n\t\treturn this.comparator;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/incremental/BarProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.incremental;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"bar\")\npublic class BarProperties {\n\n\tprivate String name;\n\n\tprivate String description;\n\n\t/**\n\t * A nice counter description.\n\t */\n\tprivate Integer counter = 0;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic Integer getCounter() {\n\t\treturn this.counter;\n\t}\n\n\tpublic void setCounter(Integer counter) {\n\t\tthis.counter = counter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/incremental/FooProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.incremental;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"foo\")\npublic class FooProperties {\n\n\tprivate String name;\n\n\tprivate String description;\n\n\t/**\n\t * A nice counter description.\n\t */\n\tprivate Integer counter = 0;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic Integer getCounter() {\n\t\treturn this.counter;\n\t}\n\n\tpublic void setCounter(Integer counter) {\n\t\tthis.counter = counter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/incremental/RenamedBarProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.incremental;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"bar\")\npublic class RenamedBarProperties {\n\n\tprivate String name;\n\n\tprivate String description;\n\n\t/**\n\t * A nice counter description.\n\t */\n\tprivate Integer counter = 0;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic Integer getCounter() {\n\t\treturn this.counter;\n\t}\n\n\tpublic void setCounter(Integer counter) {\n\t\tthis.counter = counter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/inheritance/BaseProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.inheritance;\n\npublic class BaseProperties {\n\n\tprivate boolean boolValue;\n\n\tprivate int intValue;\n\n\tprivate final Nest nest = new Nest();\n\n\tpublic boolean isBoolValue() {\n\t\treturn this.boolValue;\n\t}\n\n\tpublic void setBoolValue(boolean boolValue) {\n\t\tthis.boolValue = boolValue;\n\t}\n\n\tpublic int getIntValue() {\n\t\treturn this.intValue;\n\t}\n\n\tpublic void setIntValue(int intValue) {\n\t\tthis.intValue = intValue;\n\t}\n\n\tpublic Nest getNest() {\n\t\treturn this.nest;\n\t}\n\n\tpublic static class Nest {\n\n\t\tprivate boolean boolValue;\n\n\t\tprivate int intValue;\n\n\t\tpublic boolean isBoolValue() {\n\t\t\treturn this.boolValue;\n\t\t}\n\n\t\tpublic void setBoolValue(boolean boolValue) {\n\t\t\tthis.boolValue = boolValue;\n\t\t}\n\n\t\tpublic int getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tpublic void setIntValue(int intValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/inheritance/ChildProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.inheritance;\n\npublic class ChildProperties extends BaseProperties {\n\n\tprivate long longValue;\n\n\tprivate final NestInChild childNest = new NestInChild();\n\n\tpublic long getLongValue() {\n\t\treturn this.longValue;\n\t}\n\n\tpublic void setLongValue(long longValue) {\n\t\tthis.longValue = longValue;\n\t}\n\n\tpublic NestInChild getChildNest() {\n\t\treturn this.childNest;\n\t}\n\n\tpublic static class NestInChild {\n\n\t\tprivate boolean boolValue;\n\n\t\tprivate int intValue;\n\n\t\tpublic boolean isBoolValue() {\n\t\t\treturn this.boolValue;\n\t\t}\n\n\t\tpublic void setBoolValue(boolean boolValue) {\n\t\t\tthis.boolValue = boolValue;\n\t\t}\n\n\t\tpublic int getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tpublic void setIntValue(int intValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/inheritance/ChildPropertiesConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.inheritance;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\npublic class ChildPropertiesConfig {\n\n\t@TestConfigurationProperties(\"inheritance\")\n\tpublic ChildProperties childConfig() {\n\t\treturn new ChildProperties();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/inheritance/OverrideChildProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.inheritance;\n\npublic class OverrideChildProperties extends BaseProperties {\n\n\tprivate long longValue;\n\n\tprivate final CustomNest nest = new CustomNest();\n\n\tpublic long getLongValue() {\n\t\treturn this.longValue;\n\t}\n\n\tpublic void setLongValue(long longValue) {\n\t\tthis.longValue = longValue;\n\t}\n\n\t@Override\n\tpublic CustomNest getNest() {\n\t\treturn this.nest;\n\t}\n\n\tpublic static class CustomNest extends Nest {\n\n\t\tprivate long longValue;\n\n\t\tpublic long getLongValue() {\n\t\t\treturn this.longValue;\n\t\t}\n\n\t\tpublic void setLongValue(long longValue) {\n\t\t\tthis.longValue = longValue;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/inheritance/OverrideChildPropertiesConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.inheritance;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\npublic class OverrideChildPropertiesConfig {\n\n\t@TestConfigurationProperties(\"inheritance\")\n\tpublic OverrideChildProperties overrideChildProperties() {\n\t\treturn new OverrideChildProperties();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteDataProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.AccessLevel;\nimport lombok.Data;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using Lombok @Data on element level and overwriting behaviour\n * with @Getter and @Setter at field level.\n *\n * @author Jonas Keßler\n */\n@Data\n@TestConfigurationProperties(\"accesslevel.overwrite.data\")\n@SuppressWarnings({ \"unused\", \"deprecation\" })\npublic class LombokAccessLevelOverwriteDataProperties {\n\n\tprivate String name0;\n\n\t@Getter(AccessLevel.PUBLIC)\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name1;\n\n\t@Getter(AccessLevel.PUBLIC)\n\tprivate String name2;\n\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name3;\n\n\t@Getter\n\t@Setter\n\tprivate String name4;\n\n\t@Getter\n\tprivate String name5;\n\n\t@Setter\n\tprivate String name6;\n\n\t/*\n\t * AccessLevel.NONE\n\t */\n\t@Getter(AccessLevel.NONE)\n\t@Setter(AccessLevel.NONE)\n\tprivate String ignoredAccessLevelNone;\n\n\t@Getter(AccessLevel.NONE)\n\tprivate String ignoredGetterAccessLevelNone;\n\n\t@Setter(AccessLevel.NONE)\n\tprivate String ignoredSetterAccessLevelNone;\n\n\t/*\n\t * AccessLevel.PRIVATE\n\t */\n\t@Getter(AccessLevel.PRIVATE)\n\t@Setter(AccessLevel.PRIVATE)\n\tprivate String ignoredAccessLevelPrivate;\n\n\t@Getter(AccessLevel.PRIVATE)\n\tprivate String ignoredGetterAccessLevelPrivate;\n\n\t@Setter(AccessLevel.PRIVATE)\n\tprivate String ignoredSetterAccessLevelPrivate;\n\n\t/*\n\t * AccessLevel.PACKAGE\n\t */\n\t@Getter(AccessLevel.PACKAGE)\n\t@Setter(AccessLevel.PACKAGE)\n\tprivate String ignoredAccessLevelPackage;\n\n\t@Getter(AccessLevel.PACKAGE)\n\tprivate String ignoredGetterAccessLevelPackage;\n\n\t@Setter(AccessLevel.PACKAGE)\n\tprivate String ignoredSetterAccessLevelPackage;\n\n\t/*\n\t * AccessLevel.PROTECTED\n\t */\n\t@Getter(AccessLevel.PROTECTED)\n\t@Setter(AccessLevel.PROTECTED)\n\tprivate String ignoredAccessLevelProtected;\n\n\t@Getter(AccessLevel.PROTECTED)\n\tprivate String ignoredGetterAccessLevelProtected;\n\n\t@Setter(AccessLevel.PROTECTED)\n\tprivate String ignoredSetterAccessLevelProtected;\n\n\t/*\n\t * AccessLevel.MODULE\n\t */\n\t@Getter(AccessLevel.MODULE)\n\t@Setter(AccessLevel.MODULE)\n\tprivate String ignoredAccessLevelModule;\n\n\t@Getter(AccessLevel.MODULE)\n\tprivate String ignoredGetterAccessLevelModule;\n\n\t@Setter(AccessLevel.MODULE)\n\tprivate String ignoredSetterAccessLevelModule;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteDefaultProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using lombok @Getter and @Setter without explicitly defining\n * AccessLevel on element level and overwriting behaviour at field level.\n *\n * @author Jonas Keßler\n */\n@Getter\n@Setter\n@TestConfigurationProperties(\"accesslevel.overwrite.default\")\n@SuppressWarnings(\"deprecation\")\npublic class LombokAccessLevelOverwriteDefaultProperties {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate String name0;\n\n\t@Getter(AccessLevel.PUBLIC)\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name1;\n\n\t@Getter(AccessLevel.PUBLIC)\n\tprivate String name2;\n\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name3;\n\n\t@Getter\n\t@Setter\n\tprivate String name4;\n\n\t@Getter\n\tprivate String name5;\n\n\t@Setter\n\tprivate String name6;\n\n\t/*\n\t * AccessLevel.NONE\n\t */\n\t@Getter(AccessLevel.NONE)\n\t@Setter(AccessLevel.NONE)\n\tprivate String ignoredAccessLevelNone;\n\n\t/*\n\t * AccessLevel.PRIVATE\n\t */\n\t@Getter(AccessLevel.PRIVATE)\n\t@Setter(AccessLevel.PRIVATE)\n\tprivate String ignoredAccessLevelPrivate;\n\n\t/*\n\t * AccessLevel.PACKAGE\n\t */\n\t@Getter(AccessLevel.PACKAGE)\n\t@Setter(AccessLevel.PACKAGE)\n\tprivate String ignoredAccessLevelPackage;\n\n\t/*\n\t * AccessLevel.PROTECTED\n\t */\n\t@Getter(AccessLevel.PROTECTED)\n\t@Setter(AccessLevel.PROTECTED)\n\tprivate String ignoredAccessLevelProtected;\n\n\t/*\n\t * AccessLevel.MODULE\n\t */\n\t@Getter(AccessLevel.MODULE)\n\t@Setter(AccessLevel.MODULE)\n\tprivate String ignoredAccessLevelModule;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelOverwriteExplicitProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using lombok @Getter and @Setter with explicitly defining\n * AccessLevel.PUBLIC on element level and overwriting behaviour at field level.\n *\n * @author Jonas Keßler\n */\n@Getter(AccessLevel.PUBLIC)\n@Setter(AccessLevel.PUBLIC)\n@TestConfigurationProperties(\"accesslevel.overwrite.explicit\")\n@SuppressWarnings({ \"unused\", \"deprecation\" })\npublic class LombokAccessLevelOverwriteExplicitProperties {\n\n\tprivate String name0;\n\n\t@Getter(AccessLevel.PUBLIC)\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name1;\n\n\t@Getter(AccessLevel.PUBLIC)\n\tprivate String name2;\n\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name3;\n\n\t@Getter\n\t@Setter\n\tprivate String name4;\n\n\t@Getter\n\tprivate String name5;\n\n\t@Setter\n\tprivate String name6;\n\n\t/*\n\t * AccessLevel.NONE\n\t */\n\t@Getter(AccessLevel.NONE)\n\t@Setter(AccessLevel.NONE)\n\tprivate String ignoredAccessLevelNone;\n\n\t/*\n\t * AccessLevel.PRIVATE\n\t */\n\t@Getter(AccessLevel.PRIVATE)\n\t@Setter(AccessLevel.PRIVATE)\n\tprivate String ignoredAccessLevelPrivate;\n\n\t/*\n\t * AccessLevel.PACKAGE\n\t */\n\t@Getter(AccessLevel.PACKAGE)\n\t@Setter(AccessLevel.PACKAGE)\n\tprivate String ignoredAccessLevelPackage;\n\n\t/*\n\t * AccessLevel.PROTECTED\n\t */\n\t@Getter(AccessLevel.PROTECTED)\n\t@Setter(AccessLevel.PROTECTED)\n\tprivate String ignoredAccessLevelProtected;\n\n\t/*\n\t * AccessLevel.MODULE\n\t */\n\t@Getter(AccessLevel.MODULE)\n\t@Setter(AccessLevel.MODULE)\n\tprivate String ignoredAccessLevelModule;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokAccessLevelProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties without lombok annotations at element level.\n *\n * @author Jonas Keßler\n */\n@TestConfigurationProperties(\"accesslevel\")\n@SuppressWarnings(\"deprecation\")\npublic class LombokAccessLevelProperties {\n\n\t@Getter(AccessLevel.PUBLIC)\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String name0;\n\n\t@Getter\n\t@Setter\n\tprivate String name1;\n\n\t/*\n\t * AccessLevel.NONE\n\t */\n\t@Getter(AccessLevel.NONE)\n\t@Setter(AccessLevel.NONE)\n\tprivate String ignoredAccessLevelNone;\n\n\t/*\n\t * AccessLevel.PRIVATE\n\t */\n\t@Getter(AccessLevel.PRIVATE)\n\t@Setter(AccessLevel.PRIVATE)\n\tprivate String ignoredAccessLevelPrivate;\n\n\t/*\n\t * AccessLevel.PACKAGE\n\t */\n\t@Getter(AccessLevel.PACKAGE)\n\t@Setter(AccessLevel.PACKAGE)\n\tprivate String ignoredAccessLevelPackage;\n\n\t/*\n\t * AccessLevel.PROTECTED\n\t */\n\t@Getter(AccessLevel.PROTECTED)\n\t@Setter(AccessLevel.PROTECTED)\n\tprivate String ignoredAccessLevelProtected;\n\n\t/*\n\t * AccessLevel.MODULE\n\t */\n\t@Getter(AccessLevel.MODULE)\n\t@Setter(AccessLevel.MODULE)\n\tprivate String ignoredAccessLevelModule;\n\n\t/*\n\t * Either PUBLIC getter or setter explicitly defined\n\t */\n\t@Getter(AccessLevel.PUBLIC)\n\tprivate String ignoredOnlyPublicGetter;\n\n\t@Setter(AccessLevel.PUBLIC)\n\tprivate String ignoredOnlyPublicSetter;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokDefaultValueProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.Data;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties with default values.\n *\n * @author Stephane Nicoll\n */\n@Data\n@TestConfigurationProperties(\"default\")\n@SuppressWarnings(\"unused\")\npublic class LombokDefaultValueProperties {\n\n\tprivate String description = \"my description\";\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokDeprecatedProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Deprecated configuration properties.\n *\n * @author Stephane Nicoll\n * @deprecated deprecated\n */\n@Getter\n@Setter\n@TestConfigurationProperties(\"deprecated\")\n@Deprecated\n@SuppressWarnings(\"unused\")\npublic class LombokDeprecatedProperties {\n\n\tprivate String name;\n\n\tprivate String description;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokDeprecatedSingleProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.Data;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties with a single deprecated element.\n *\n * @author Stephane Nicoll\n */\n@Data\n@TestConfigurationProperties(\"singledeprecated\")\n@SuppressWarnings(\"unused\")\npublic class LombokDeprecatedSingleProperty {\n\n\t@Deprecated\n\tprivate String name;\n\n\tprivate String description;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokExplicitProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using lombok @Getter/@Setter at field level.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"explicit\")\npublic class LombokExplicitProperties {\n\n\t@Getter\n\tprivate final String id = \"super-id\";\n\n\t/**\n\t * Name description.\n\t */\n\t@Getter\n\t@Setter\n\tprivate String name;\n\n\t@Getter\n\t@Setter\n\tprivate String description;\n\n\t@Getter\n\t@Setter\n\tprivate Integer counter;\n\n\t@Deprecated\n\t@Getter\n\t@Setter\n\tprivate Integer number = 0;\n\n\t@Getter\n\tprivate final List<String> items = new ArrayList<>();\n\n\t// Should be ignored if no annotation is set\n\t@SuppressWarnings(\"unused\")\n\tprivate String ignored;\n\n\t@Getter\n\tprivate String ignoredOnlyGetter;\n\n\t@Setter\n\tprivate String ignoredOnlySetter;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokInnerClassProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.Data;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n/**\n * Demonstrate the auto-detection of inner config classes using Lombok.\n *\n * @author Stephane Nicoll\n */\n@Data\n@TestConfigurationProperties(\"config\")\n@SuppressWarnings(\"unused\")\npublic class LombokInnerClassProperties {\n\n\tprivate final Foo first = new Foo();\n\n\tprivate Foo second = new Foo();\n\n\t@TestNestedConfigurationProperty\n\tprivate final SimpleLombokPojo third = new SimpleLombokPojo();\n\n\tprivate Fourth fourth;\n\n\t// Only there to record the source method\n\tpublic SimpleLombokPojo getThird() {\n\t\treturn this.third;\n\t}\n\n\t@Data\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate final Bar bar = new Bar();\n\n\t\t@Data\n\t\tpublic static class Bar {\n\n\t\t\tprivate String name;\n\n\t\t}\n\n\t}\n\n\tpublic enum Fourth {\n\n\t\tYES, NO\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokInnerClassWithGetterProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.Data;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@Data\n@TestConfigurationProperties(\"config\")\n@SuppressWarnings(\"unused\")\npublic class LombokInnerClassWithGetterProperties {\n\n\tprivate final Foo first = new Foo();\n\n\tpublic Foo getFirst() {\n\t\treturn this.first;\n\t}\n\n\t@Data\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokSimpleDataProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Data;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using lombok @Data.\n *\n * @author Stephane Nicoll\n */\n@Data\n@TestConfigurationProperties(\"data\")\n@SuppressWarnings(\"unused\")\npublic class LombokSimpleDataProperties {\n\n\tprivate final String id = \"super-id\";\n\n\t/**\n\t * Name description.\n\t */\n\tprivate String name;\n\n\tprivate String description;\n\n\tprivate Integer counter;\n\n\t@Deprecated\n\tprivate Integer number = 0;\n\n\tprivate final List<String> items = new ArrayList<>();\n\n\tprivate final String ignored = \"foo\";\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokSimpleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using lombok @Getter/@Setter at class level.\n *\n * @author Stephane Nicoll\n */\n@Getter\n@Setter\n@TestConfigurationProperties(\"simple\")\n@SuppressWarnings(\"unused\")\npublic class LombokSimpleProperties {\n\n\tprivate final String id = \"super-id\";\n\n\t/**\n\t * Name description.\n\t */\n\tprivate String name;\n\n\tprivate String description;\n\n\tprivate Integer counter;\n\n\t@Deprecated\n\tprivate Integer number = 0;\n\n\tprivate final List<String> items = new ArrayList<>();\n\n\tprivate final String ignored = \"foo\";\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/LombokSimpleValueProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport lombok.Value;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties using Lombok {@code @Value}.\n *\n * @author Mark Jeffrey\n */\n@Value\n@TestConfigurationProperties(\"value\")\n@SuppressWarnings(\"unused\")\npublic class LombokSimpleValueProperties {\n\n\tprivate final String id = \"super-id\";\n\n\t/**\n\t * Name description.\n\t */\n\tprivate String name;\n\n\tprivate String description;\n\n\tprivate Integer counter;\n\n\t@Deprecated\n\tprivate Integer number = 0;\n\n\tprivate final List<String> items = new ArrayList<>();\n\n\tprivate final String ignored = \"foo\";\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/lombok/SimpleLombokPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.lombok;\n\nimport lombok.Data;\n\n/**\n * Lombok POJO for use with samples.\n *\n * @author Stephane Nicoll\n */\n@Data\n@SuppressWarnings(\"unused\")\npublic class SimpleLombokPojo {\n\n\tprivate int value;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/DeprecatedClassMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing method configuration with deprecated class.\n *\n * @author Stephane Nicoll\n * @deprecated deprecated\n */\n@Deprecated\npublic class DeprecatedClassMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/DeprecatedMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing deprecated method configuration.\n *\n * @author Stephane Nicoll\n */\npublic class DeprecatedMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\t@Deprecated\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/EmptyTypeMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing method configuration.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"something\")\npublic class EmptyTypeMethodConfig {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@TestConfigurationProperties(\"something\")\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tstatic class Foo {\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/InvalidMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing invalid method configuration.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"something\")\npublic class InvalidMethodConfig {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@TestConfigurationProperties(\"invalid\")\n\tInvalidMethodConfig foo() {\n\t\treturn new InvalidMethodConfig();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/MethodAndClassConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing mixed method and class configuration.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"conflict\")\npublic class MethodAndClassConfig {\n\n\tprivate String value;\n\n\tpublic String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@TestConfigurationProperties(\"conflict\")\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/NestedPropertiesMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(\"method-nested\")\npublic class NestedPropertiesMethod {\n\n\tprivate String myProperty;\n\n\tprivate final NestedProperty nested = new NestedProperty();\n\n\tprivate final Inner inner = new Inner();\n\n\tpublic String getMyProperty() {\n\t\treturn this.myProperty;\n\t}\n\n\tpublic void setMyProperty(String myProperty) {\n\t\tthis.myProperty = myProperty;\n\t}\n\n\t@TestNestedConfigurationProperty\n\tpublic NestedProperty getNested() {\n\t\treturn this.nested;\n\t}\n\n\tpublic Inner getInner() {\n\t\treturn this.inner;\n\t}\n\n\tpublic static class Inner {\n\n\t\tprivate String myInnerProperty;\n\n\t\tprivate final NestedProperty nested = new NestedProperty();\n\n\t\tpublic String getMyInnerProperty() {\n\t\t\treturn this.myInnerProperty;\n\t\t}\n\n\t\tpublic void setMyInnerProperty(String myInnerProperty) {\n\t\t\tthis.myInnerProperty = myInnerProperty;\n\t\t}\n\n\t\t@TestNestedConfigurationProperty\n\t\tpublic NestedProperty getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/NestedPropertiesMethodImmutable.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(\"immutable-nested\")\npublic class NestedPropertiesMethodImmutable {\n\n\tprivate final NestedProperty nested;\n\n\tNestedPropertiesMethodImmutable(NestedProperty nested) {\n\t\tthis.nested = nested;\n\n\t}\n\n\t@TestNestedConfigurationProperty\n\tpublic NestedProperty getNested() {\n\t\treturn this.nested;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/NestedProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\npublic class NestedProperty {\n\n\tprivate String myNestedProperty;\n\n\tpublic String getMyNestedProperty() {\n\t\treturn this.myNestedProperty;\n\t}\n\n\tpublic void setMyNestedProperty(String myNestedProperty) {\n\t\tthis.myNestedProperty = myNestedProperty;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/PackagePrivateMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing package-private method configuration.\n *\n * @author Andy Wilkinson\n */\npublic class PackagePrivateMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\tFoo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/PrivateMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing private method configuration.\n *\n * @author Andy Wilkinson\n */\npublic class PrivateMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\tprivate Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/ProtectedMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing protected method configuration.\n *\n * @author Andy Wilkinson\n */\npublic class ProtectedMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\tprotected Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/PublicMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing public method configuration.\n *\n * @author Stephane Nicoll\n */\npublic class PublicMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/method/SingleConstructorMethodConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.method;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample for testing method configuration that uses a constructor that should not be\n * associated to constructor binding.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"unused\")\npublic class SingleConstructorMethodConfig {\n\n\t@TestConfigurationProperties(\"foo\")\n\tpublic Foo foo() {\n\t\treturn new Foo(new Object());\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate boolean flag;\n\n\t\tprivate final Object myService;\n\n\t\tpublic Foo(Object myService) {\n\t\t\tthis.myService = myService;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic boolean isFlag() {\n\t\t\treturn this.flag;\n\t\t}\n\n\t\tpublic void setFlag(boolean flag) {\n\t\t\tthis.flag = flag;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/ConstructorParameterNameAnnotationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.name;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\nimport org.springframework.boot.configurationsample.TestName;\n\n/**\n * Constructor properties making use of {@code @Name}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"named\")\npublic class ConstructorParameterNameAnnotationProperties {\n\n\t/**\n\t * Imports to apply.\n\t */\n\tprivate final String imports;\n\n\t/**\n\t * Whether default mode is enabled.\n\t */\n\tprivate final boolean defaultValue;\n\n\tpublic ConstructorParameterNameAnnotationProperties(@TestName(\"import\") String imports,\n\t\t\t@TestName(\"default\") @TestDefaultValue(\"true\") boolean defaultValue) {\n\t\tthis.imports = imports;\n\t\tthis.defaultValue = defaultValue;\n\t}\n\n\tpublic String getImports() {\n\t\treturn this.imports;\n\t}\n\n\tpublic boolean isDefaultValue() {\n\t\treturn this.defaultValue;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/JavaBeanNameAnnotationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.name;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestName;\n\n/**\n * Java bean properties making use of {@code @Name}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"named\")\npublic class JavaBeanNameAnnotationProperties {\n\n\t/**\n\t * Imports to apply.\n\t */\n\t@TestName(\"import\")\n\tprivate String imports;\n\n\t/**\n\t * Whether default mode is enabled.\n\t */\n\t@TestName(\"default\")\n\tprivate boolean defaultValue = true;\n\n\tpublic String getImports() {\n\t\treturn this.imports;\n\t}\n\n\tpublic void setImports(String imports) {\n\t\tthis.imports = imports;\n\t}\n\n\tpublic boolean isDefaultValue() {\n\t\treturn this.defaultValue;\n\t}\n\n\tpublic void setDefaultValue(boolean defaultValue) {\n\t\tthis.defaultValue = defaultValue;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/LombokNameAnnotationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.name;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestName;\n\n/**\n * Lombok properties making use of {@code @Name}.\n *\n * @author Stephane Nicoll\n */\n@Getter\n@Setter\n@TestConfigurationProperties(\"named\")\npublic class LombokNameAnnotationProperties {\n\n\t/**\n\t * Imports to apply.\n\t */\n\t@TestName(\"import\")\n\tprivate String imports;\n\n\t/**\n\t * Whether default mode is enabled.\n\t */\n\t@TestName(\"default\")\n\tprivate boolean defaultValue = true;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/name/RecordComponentNameAnnotationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.name;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\nimport org.springframework.boot.configurationsample.TestName;\n\n/**\n * Record properties making use of {@code @Name}.\n *\n * @param imports Imports to apply.\n * @param defaultValue Whether default mode is enabled.\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"named\")\npublic record RecordComponentNameAnnotationProperties(@TestName(\"import\") String imports,\n\t\t@TestName(\"default\") @TestDefaultValue(\"true\") boolean defaultValue) {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/record/ExampleRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.record;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestName;\n\n/**\n * Example Record Javadoc sample\n *\n * @param someString very long description that doesn't fit single line and is indented\n * @param someInteger description with @param and @ pitfalls\n * @param someBoolean description with extra spaces\n * @param someLong description without space after asterisk\n * @param namedComponent description of a named component\n * @param someByte last description in Javadoc\n * @since 1.0.0\n * @author Pavel Anisimov\n */\n@TestConfigurationProperties(\"record.descriptions\")\npublic record ExampleRecord(String someString, Integer someInteger, Boolean someBoolean, Long someLong,\n\t\t@TestName(\"named.record.component\") String namedComponent, Byte someByte) {\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/record/NestedPropertiesRecord.java",
    "content": "/*\r\n * Copyright 2012-present the original author or authors.\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      https://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\npackage org.springframework.boot.configurationsample.record;\r\n\r\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\r\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\r\n\r\n@TestConfigurationProperties(\"record-nested\")\r\npublic record NestedPropertiesRecord(String myProperty, @TestNestedConfigurationProperty NestedRecord nested,\r\n\t\tInnerPropertiesRecord inner) {\r\n\r\n\tpublic record InnerPropertiesRecord(String myInnerProperty, @TestNestedConfigurationProperty NestedRecord nested) {\r\n\t}\r\n\r\n}\r\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/record/NestedRecord.java",
    "content": "/*\r\n * Copyright 2012-present the original author or authors.\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      https://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\npackage org.springframework.boot.configurationsample.record;\r\n\r\npublic record NestedRecord(String myNestedProperty) {\r\n\r\n}\r\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/record/RecordWithGetter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.record;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"record-with-getter\")\npublic record RecordWithGetter(String alpha) {\n\n\tpublic String getBravo() {\n\t\treturn this.alpha;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/recursive/RecursiveProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.recursive;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"prefix\")\npublic class RecursiveProperties {\n\n\tprivate RecursiveProperties recursive;\n\n\tpublic RecursiveProperties getRecursive() {\n\t\treturn this.recursive;\n\t}\n\n\tpublic void setRecursive(RecursiveProperties recursive) {\n\t\tthis.recursive = recursive;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/AutowiredProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestAutowired;\n\n/**\n * Properties with autowired constructor.\n *\n * @author Madhura Bhave\n */\npublic class AutowiredProperties {\n\n\t/**\n\t * The name of this simple properties.\n\t */\n\tprivate String theName;\n\n\t@TestAutowired\n\tpublic AutowiredProperties(String theName) {\n\t\tthis.theName = theName;\n\t}\n\n\tpublic String getTheName() {\n\t\treturn this.theName;\n\t}\n\n\tpublic void setTheName(String name) {\n\t\tthis.theName = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/ClassWithNestedProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Class with nested configuration properties.\n *\n * @author Hrishikesh Joshi\n */\npublic class ClassWithNestedProperties {\n\n\tpublic static class NestedParentClass {\n\n\t\tprivate int parentClassProperty = 10;\n\n\t\tpublic int getParentClassProperty() {\n\t\t\treturn this.parentClassProperty;\n\t\t}\n\n\t\tpublic void setParentClassProperty(int parentClassProperty) {\n\t\t\tthis.parentClassProperty = parentClassProperty;\n\t\t}\n\n\t}\n\n\t@TestConfigurationProperties(\"nestedChildProps\")\n\tpublic static class NestedChildClass extends NestedParentClass {\n\n\t\tprivate int childClassProperty = 20;\n\n\t\tpublic int getChildClassProperty() {\n\t\t\treturn this.childClassProperty;\n\t\t}\n\n\t\tpublic void setChildClassProperty(int childClassProperty) {\n\t\t\tthis.childClassProperty = childClassProperty;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedFieldSingleProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties with a single deprecated element.\n *\n * @author Andy Wilkinson\n */\n@TestConfigurationProperties(\"singlefielddeprecated\")\npublic class DeprecatedFieldSingleProperty {\n\n\t@Deprecated\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Deprecated configuration properties.\n *\n * @author Stephane Nicoll\n * @deprecated deprecated\n */\n@Deprecated\n@TestConfigurationProperties(\"deprecated\")\npublic class DeprecatedProperties {\n\n\tprivate String name;\n\n\tprivate String description;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDeprecatedConfigurationProperty;\nimport org.springframework.boot.configurationsample.TestName;\n\n/**\n * Configuration properties as record with deprecated property.\n *\n * @param alpha alpha property, deprecated\n * @param bravo bravo property\n * @param charlie charlie property, named, deprecated\n * @author Moritz Halbritter\n */\n@TestConfigurationProperties(\"deprecated-record\")\npublic record DeprecatedRecord(String alpha, String bravo, @TestName(\"named.charlie\") String charlie) {\n\n\t@Deprecated\n\t@TestDeprecatedConfigurationProperty(reason = \"some-reason\")\n\tpublic String alpha() {\n\t\treturn this.alpha;\n\t}\n\n\t@Deprecated\n\t@TestDeprecatedConfigurationProperty(reason = \"another-reason\")\n\tpublic String charlie() {\n\t\treturn this.charlie;\n\t}\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DeprecatedSingleProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDeprecatedConfigurationProperty;\n\n/**\n * Configuration properties with a single deprecated element.\n *\n * @author Phillip Webb\n */\n@TestConfigurationProperties(\"singledeprecated\")\npublic class DeprecatedSingleProperty {\n\n\tprivate String newName;\n\n\t@Deprecated\n\t@TestDeprecatedConfigurationProperty(reason = \"renamed\", replacement = \"singledeprecated.new-name\", since = \"1.2.3\")\n\tpublic String getName() {\n\t\treturn getNewName();\n\t}\n\n\t@Deprecated\n\tpublic void setName(String name) {\n\t\tsetNewName(name);\n\t}\n\n\tpublic String getNewName() {\n\t\treturn this.newName;\n\t}\n\n\tpublic void setNewName(String newName) {\n\t\tthis.newName = newName;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/DescriptionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties with various description styles.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"description\")\npublic class DescriptionProperties {\n\n\t/**\n\t * A simple description.\n\t */\n\tprivate String simple;\n\n\t/**\n\t * This is a lengthy description that spans across multiple lines to showcase that the\n\t * line separators are cleaned automatically.\n\t */\n\tprivate String multiLine;\n\n\t// @formatter:off\n\t/**\n\t * This is an example of a description\n\t *with unusual whitespace after a new line.\n\t */\n\tprivate String multiLineWhitespace;\n\t// @formatter:on\n\n\tpublic String getSimple() {\n\t\treturn this.simple;\n\t}\n\n\tpublic void setSimple(String simple) {\n\t\tthis.simple = simple;\n\t}\n\n\tpublic String getMultiLine() {\n\t\treturn this.multiLine;\n\t}\n\n\tpublic void setMultiLine(String multiLine) {\n\t\tthis.multiLine = multiLine;\n\t}\n\n\tpublic String getMultiLineWhitespace() {\n\t\treturn this.multiLineWhitespace;\n\t}\n\n\tpublic void setMultiLineWhitespace(String multiLineWhitespace) {\n\t\tthis.multiLineWhitespace = multiLineWhitespace;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/HierarchicalProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties with inherited values.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"hierarchical\")\npublic class HierarchicalProperties extends HierarchicalPropertiesParent {\n\n\t/**\n\t * Concrete property.\n\t */\n\tprivate String third = \"three\";\n\n\tpublic String getThird() {\n\t\treturn this.third;\n\t}\n\n\tpublic void setThird(String third) {\n\t\tthis.third = third;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/HierarchicalPropertiesGrandparent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\n/**\n * Grandparent for {@link HierarchicalProperties}.\n *\n * @author Stephane Nicoll\n */\npublic abstract class HierarchicalPropertiesGrandparent {\n\n\t/**\n\t * Grandparent property.\n\t */\n\tprivate String first = \"one\";\n\n\tpublic String getFirst() {\n\t\treturn this.first;\n\t}\n\n\tpublic void setFirst(String first) {\n\t\tthis.first = first;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/HierarchicalPropertiesParent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\n/**\n * Parent for {@link HierarchicalProperties}.\n *\n * @author Stephane Nicoll\n */\npublic abstract class HierarchicalPropertiesParent extends HierarchicalPropertiesGrandparent {\n\n\t/**\n\t * Parent property.\n\t */\n\tprivate String second = \"two\";\n\n\tpublic String getSecond() {\n\t\treturn this.second;\n\t}\n\n\tpublic void setSecond(String second) {\n\t\tthis.second = second;\n\t}\n\n\t// Overridden properties should belong to this class, not\n\t// HierarchicalPropertiesGrandparent\n\n\t@Override\n\tpublic String getFirst() {\n\t\treturn super.getFirst();\n\t}\n\n\t@Override\n\tpublic void setFirst(String first) {\n\t\tsuper.setFirst(first);\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/IgnoredProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Configuration properties where some of them are being ignored.\n *\n * @author Moritz Halbritter\n */\n@TestConfigurationProperties(\"ignored\")\npublic class IgnoredProperties {\n\n\tprivate String prop1;\n\n\tprivate String prop2;\n\n\tprivate String prop3;\n\n\tpublic String getProp1() {\n\t\treturn this.prop1;\n\t}\n\n\tpublic void setProp1(String prop1) {\n\t\tthis.prop1 = prop1;\n\t}\n\n\tpublic String getProp2() {\n\t\treturn this.prop2;\n\t}\n\n\tpublic void setProp2(String prop2) {\n\t\tthis.prop2 = prop2;\n\t}\n\n\tpublic String getProp3() {\n\t\treturn this.prop3;\n\t}\n\n\tpublic void setProp3(String prop3) {\n\t\tthis.prop3 = prop3;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/InnerClassWithPrivateConstructor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Nested properties with a private constructor.\n *\n * @author Phillip Webb\n */\n@TestConfigurationProperties(\"config\")\npublic class InnerClassWithPrivateConstructor {\n\n\tprivate Nested nested = new Nested(\"whatever\");\n\n\tpublic Nested getNested() {\n\t\treturn this.nested;\n\t}\n\n\tpublic void setNested(Nested nested) {\n\t\tthis.nested = nested;\n\t}\n\n\tpublic static final class Nested {\n\n\t\tprivate String name;\n\n\t\tprivate Nested(String ignored) {\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/NotAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\n/**\n * This has no annotation on purpose to check that no meta-data is generated.\n *\n * @author Stephane Nicoll\n */\npublic class NotAnnotated {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/SimpleArrayProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport java.util.Map;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Properties with array.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"array\")\npublic class SimpleArrayProperties {\n\n\tprivate int[] primitive;\n\n\tprivate String[] simple;\n\n\tprivate Holder[] inner;\n\n\tprivate Map<String, Integer>[] nameToInteger;\n\n\tpublic int[] getPrimitive() {\n\t\treturn this.primitive;\n\t}\n\n\tpublic void setPrimitive(int[] primitive) {\n\t\tthis.primitive = primitive;\n\t}\n\n\tpublic String[] getSimple() {\n\t\treturn this.simple;\n\t}\n\n\tpublic void setSimple(String[] simple) {\n\t\tthis.simple = simple;\n\t}\n\n\tpublic Holder[] getInner() {\n\t\treturn this.inner;\n\t}\n\n\tpublic void setInner(Holder[] inner) {\n\t\tthis.inner = inner;\n\t}\n\n\tpublic Map<String, Integer>[] getNameToInteger() {\n\t\treturn this.nameToInteger;\n\t}\n\n\tpublic void setNameToInteger(Map<String, Integer>[] nameToInteger) {\n\t\tthis.nameToInteger = nameToInteger;\n\t}\n\n\tstatic class Holder {\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/SimpleCollectionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Properties with collections.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"collection\")\npublic class SimpleCollectionProperties {\n\n\tprivate Map<Integer, String> integersToNames;\n\n\tprivate Collection<Long> longs;\n\n\tprivate List<Float> floats;\n\n\tprivate final Map<String, Integer> namesToIntegers = new HashMap<>();\n\n\tprivate final Collection<Byte> bytes = new LinkedHashSet<>();\n\n\tprivate final List<Double> doubles = new ArrayList<>();\n\n\tprivate final Map<String, Holder<String>> namesToHolders = new HashMap<>();\n\n\tpublic Map<Integer, String> getIntegersToNames() {\n\t\treturn this.integersToNames;\n\t}\n\n\tpublic void setIntegersToNames(Map<Integer, String> integersToNames) {\n\t\tthis.integersToNames = integersToNames;\n\t}\n\n\tpublic Collection<Long> getLongs() {\n\t\treturn this.longs;\n\t}\n\n\tpublic void setLongs(Collection<Long> longs) {\n\t\tthis.longs = longs;\n\t}\n\n\tpublic List<Float> getFloats() {\n\t\treturn this.floats;\n\t}\n\n\tpublic void setFloats(List<Float> floats) {\n\t\tthis.floats = floats;\n\t}\n\n\tpublic Map<String, Integer> getNamesToIntegers() {\n\t\treturn this.namesToIntegers;\n\t}\n\n\tpublic Collection<Byte> getBytes() {\n\t\treturn this.bytes;\n\t}\n\n\tpublic List<Double> getDoubles() {\n\t\treturn this.doubles;\n\t}\n\n\tpublic Map<String, Holder<String>> getNamesToHolders() {\n\t\treturn this.namesToHolders;\n\t}\n\n\tpublic static class Holder<T> {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate T target;\n\n\t\tpublic void setTarget(T target) {\n\t\t\tthis.target = target;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/SimplePrefixValueProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Properties with a simple prefix.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"simple\")\npublic class SimplePrefixValueProperties {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/SimpleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport java.beans.FeatureDescriptor;\nimport java.util.Comparator;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Simple properties.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"simple\")\npublic class SimpleProperties {\n\n\t/**\n\t * The name of this simple properties.\n\t */\n\tprivate String theName = \"boot\";\n\n\t// isFlag is also detected\n\t/**\n\t * A simple flag.\n\t */\n\tprivate boolean flag;\n\n\t// An interface can still be injected because it might have a converter\n\tprivate Comparator<?> comparator;\n\n\t// There is only a getter on this instance but we don't know what to do with it ->\n\t// ignored\n\tprivate FeatureDescriptor featureDescriptor;\n\n\t// There is only a setter on this \"simple\" property --> ignored\n\t@SuppressWarnings(\"unused\")\n\tprivate Long counter;\n\n\t// There is only a getter on this \"simple\" property --> ignored\n\tprivate Integer size;\n\n\tpublic String getTheName() {\n\t\treturn this.theName;\n\t}\n\n\t@Deprecated\n\tpublic void setTheName(String name) {\n\t\tthis.theName = name;\n\t}\n\n\t@Deprecated\n\tpublic boolean isFlag() {\n\t\treturn this.flag;\n\t}\n\n\tpublic void setFlag(boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n\tpublic Comparator<?> getComparator() {\n\t\treturn this.comparator;\n\t}\n\n\tpublic void setComparator(Comparator<?> comparator) {\n\t\tthis.comparator = comparator;\n\t}\n\n\tpublic FeatureDescriptor getFeatureDescriptor() {\n\t\treturn this.featureDescriptor;\n\t}\n\n\tpublic void setCounter(Long counter) {\n\t\tthis.counter = counter;\n\t}\n\n\tpublic Integer getSize() {\n\t\treturn this.size;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/simple/SimpleTypeProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.simple;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Expose simple types to make sure these are detected properly.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"simple.type\")\npublic class SimpleTypeProperties {\n\n\tprivate String myString;\n\n\tprivate Byte myByte;\n\n\tprivate byte myPrimitiveByte;\n\n\tprivate Character myChar;\n\n\tprivate char myPrimitiveChar;\n\n\tprivate Boolean myBoolean;\n\n\tprivate boolean myPrimitiveBoolean;\n\n\tprivate Short myShort;\n\n\tprivate short myPrimitiveShort;\n\n\tprivate Integer myInteger;\n\n\tprivate int myPrimitiveInteger;\n\n\tprivate Long myLong;\n\n\tprivate long myPrimitiveLong;\n\n\tprivate Double myDouble;\n\n\tprivate double myPrimitiveDouble;\n\n\tprivate Float myFloat;\n\n\tprivate float myPrimitiveFloat;\n\n\tpublic String getMyString() {\n\t\treturn this.myString;\n\t}\n\n\tpublic void setMyString(String myString) {\n\t\tthis.myString = myString;\n\t}\n\n\tpublic Byte getMyByte() {\n\t\treturn this.myByte;\n\t}\n\n\tpublic void setMyByte(Byte myByte) {\n\t\tthis.myByte = myByte;\n\t}\n\n\tpublic byte getMyPrimitiveByte() {\n\t\treturn this.myPrimitiveByte;\n\t}\n\n\tpublic void setMyPrimitiveByte(byte myPrimitiveByte) {\n\t\tthis.myPrimitiveByte = myPrimitiveByte;\n\t}\n\n\tpublic Character getMyChar() {\n\t\treturn this.myChar;\n\t}\n\n\tpublic void setMyChar(Character myChar) {\n\t\tthis.myChar = myChar;\n\t}\n\n\tpublic char getMyPrimitiveChar() {\n\t\treturn this.myPrimitiveChar;\n\t}\n\n\tpublic void setMyPrimitiveChar(char myPrimitiveChar) {\n\t\tthis.myPrimitiveChar = myPrimitiveChar;\n\t}\n\n\tpublic Boolean getMyBoolean() {\n\t\treturn this.myBoolean;\n\t}\n\n\tpublic void setMyBoolean(Boolean myBoolean) {\n\t\tthis.myBoolean = myBoolean;\n\t}\n\n\tpublic boolean isMyPrimitiveBoolean() {\n\t\treturn this.myPrimitiveBoolean;\n\t}\n\n\tpublic void setMyPrimitiveBoolean(boolean myPrimitiveBoolean) {\n\t\tthis.myPrimitiveBoolean = myPrimitiveBoolean;\n\t}\n\n\tpublic Short getMyShort() {\n\t\treturn this.myShort;\n\t}\n\n\tpublic void setMyShort(Short myShort) {\n\t\tthis.myShort = myShort;\n\t}\n\n\tpublic short getMyPrimitiveShort() {\n\t\treturn this.myPrimitiveShort;\n\t}\n\n\tpublic void setMyPrimitiveShort(short myPrimitiveShort) {\n\t\tthis.myPrimitiveShort = myPrimitiveShort;\n\t}\n\n\tpublic Integer getMyInteger() {\n\t\treturn this.myInteger;\n\t}\n\n\tpublic void setMyInteger(Integer myInteger) {\n\t\tthis.myInteger = myInteger;\n\t}\n\n\tpublic int getMyPrimitiveInteger() {\n\t\treturn this.myPrimitiveInteger;\n\t}\n\n\tpublic void setMyPrimitiveInteger(int myPrimitiveInteger) {\n\t\tthis.myPrimitiveInteger = myPrimitiveInteger;\n\t}\n\n\tpublic Long getMyLong() {\n\t\treturn this.myLong;\n\t}\n\n\tpublic void setMyLong(Long myLong) {\n\t\tthis.myLong = myLong;\n\t}\n\n\tpublic long getMyPrimitiveLong() {\n\t\treturn this.myPrimitiveLong;\n\t}\n\n\tpublic void setMyPrimitiveLong(long myPrimitiveLong) {\n\t\tthis.myPrimitiveLong = myPrimitiveLong;\n\t}\n\n\tpublic Double getMyDouble() {\n\t\treturn this.myDouble;\n\t}\n\n\tpublic void setMyDouble(Double myDouble) {\n\t\tthis.myDouble = myDouble;\n\t}\n\n\tpublic double getMyPrimitiveDouble() {\n\t\treturn this.myPrimitiveDouble;\n\t}\n\n\tpublic void setMyPrimitiveDouble(double myPrimitiveDouble) {\n\t\tthis.myPrimitiveDouble = myPrimitiveDouble;\n\t}\n\n\tpublic Float getMyFloat() {\n\t\treturn this.myFloat;\n\t}\n\n\tpublic void setMyFloat(Float myFloat) {\n\t\tthis.myFloat = myFloat;\n\t}\n\n\tpublic float getMyPrimitiveFloat() {\n\t\treturn this.myPrimitiveFloat;\n\t}\n\n\tpublic void setMyPrimitiveFloat(float myPrimitiveFloat) {\n\t\tthis.myPrimitiveFloat = myPrimitiveFloat;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/BaseSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\n/**\n * Test properties contributed by a parent source.\n */\npublic abstract class BaseSource {\n\n\tprivate boolean enabled;\n\n\tprivate String username;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(String username) {\n\t\tthis.username = username;\n\t}\n\n\tprotected abstract String getPassword();\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ConcreteProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"example\")\npublic class ConcreteProperties extends BaseSource {\n\n\t/**\n\t * Password.\n\t */\n\tprivate String password;\n\n\t@Override\n\tpublic String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ConcreteSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\npublic class ConcreteSource extends BaseSource {\n\n\t/**\n\t * Password.\n\t */\n\tprivate String password;\n\n\t@Override\n\tpublic String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ConcreteSourceAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(\"example\")\npublic class ConcreteSourceAnnotated {\n\n\t@TestNestedConfigurationProperty\n\tprivate final ConcreteSource nested = new ConcreteSource();\n\n\tpublic ConcreteSource getNested() {\n\t\treturn this.nested;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ConventionSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\n/**\n * Test various convention-based lookups.\n */\npublic class ConventionSource {\n\n\tprivate String firstName;\n\n\tprivate String lastName;\n\n\tpublic String getFirstName() {\n\t\treturn this.firstName;\n\t}\n\n\tpublic void setFirstName(String firstName) {\n\t\tthis.firstName = firstName;\n\t}\n\n\tpublic String getLastName() {\n\t\treturn this.lastName;\n\t}\n\n\tpublic void setLastName(String lastName) {\n\t\tthis.lastName = lastName;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ConventionSourceAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(prefix = \"example\")\npublic class ConventionSourceAnnotated {\n\n\t@TestNestedConfigurationProperty\n\tprivate final ConventionSource nested = new ConventionSource();\n\n\tpublic ConventionSource getNested() {\n\t\treturn this.nested;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ImmutableSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\n/**\n * Immutable type with manual metadata. This illustrates the case where the type of a\n * property is defined in a separate class and source-based metadata cannot be discovered.\n */\npublic class ImmutableSource {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate final String name;\n\n\t@SuppressWarnings(\"unused\")\n\tprivate final String description;\n\n\t@SuppressWarnings(\"unused\")\n\tprivate final String type;\n\n\tpublic ImmutableSource(String name, String description, String type) {\n\t\tthis.name = name;\n\t\tthis.description = description;\n\t\tthis.type = type;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ImmutableSourceAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(\"example\")\npublic class ImmutableSourceAnnotated {\n\n\t@TestNestedConfigurationProperty\n\tprivate final ImmutableSource nested;\n\n\tpublic ImmutableSourceAnnotated(ImmutableSource nested) {\n\t\tthis.nested = nested;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/LombokSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n * Type using lombok with manual metadata. This illustrates the case where the type of a\n * property is defined in a separate class and source-based metadata cannot be discovered.\n */\n@Getter\n@Setter\npublic class LombokSource {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"unused\")\n\tprivate String description;\n\n\t@SuppressWarnings(\"unused\")\n\tprivate String type;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/LombokSourceAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport lombok.Getter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@Getter\n@TestConfigurationProperties(\"example\")\npublic class LombokSourceAnnotated {\n\n\t@TestNestedConfigurationProperty\n\tprivate final LombokSource nested = new LombokSource();\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/ParentWithHintProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n@TestConfigurationProperties(\"example\")\npublic class ParentWithHintProperties extends SimpleSource {\n\n\t/**\n\t * Whether this is enabled.\n\t */\n\tprivate boolean enabled;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/RecordSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\n/*\n * Record type with manual metadata. This illustrates the case where the type of a\n * property is defined in a separate class and source-based metadata cannot be discovered.\n */\npublic record RecordSource(String name, String description, String type) {\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/RecordSourceAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(\"example\")\npublic record RecordSourceAnnotated(@TestNestedConfigurationProperty RecordSource nested) {\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/SimpleSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\n/**\n * Type with manual metadata. This illustrates the case where the type of a property is\n * defined in a separate class and source-based metadata cannot be discovered.\n */\npublic class SimpleSource {\n\n\tprivate String name;\n\n\tprivate String description;\n\n\tprivate String type;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic String getType() {\n\t\treturn this.type;\n\t}\n\n\tpublic void setType(String type) {\n\t\tthis.type = type;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/SimpleSourceAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n@TestConfigurationProperties(\"example\")\npublic class SimpleSourceAnnotated {\n\n\t@TestNestedConfigurationProperty\n\tprivate final SimpleSource nested = new SimpleSource();\n\n\tpublic SimpleSource getNested() {\n\t\treturn this.nested;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/AbstractPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\n\n@TestConfigurationPropertiesSource\npublic abstract class AbstractPropertiesSource {\n\n\t/**\n\t * Description of this simple property.\n\t */\n\tprivate String name = \"boot\";\n\n\t/**\n\t * Whether it is enabled.\n\t */\n\tprivate boolean enabled;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/ConfigurationPropertySourcesContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\n\npublic class ConfigurationPropertySourcesContainer {\n\n\t@TestConfigurationPropertiesSource\n\tpublic static class First {\n\n\t\t/**\n\t\t * A name.\n\t\t */\n\t\tprivate String name;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t@TestConfigurationPropertiesSource\n\tpublic static class Second {\n\n\t\t/**\n\t\t * Whether this is visible.\n\t\t */\n\t\tprivate boolean visible = true;\n\n\t\tpublic boolean isVisible() {\n\t\t\treturn this.visible;\n\t\t}\n\n\t\tpublic void setVisible(boolean visible) {\n\t\t\tthis.visible = visible;\n\t\t}\n\n\t}\n\n\tpublic static class Third {\n\n\t\tprivate String shouldBeIgnored;\n\n\t\tpublic String getShouldBeIgnored() {\n\t\t\treturn this.shouldBeIgnored;\n\t\t}\n\n\t\tpublic void setShouldBeIgnored(String shouldBeIgnored) {\n\t\t\tthis.shouldBeIgnored = shouldBeIgnored;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/ImmutablePropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n@TestConfigurationPropertiesSource\npublic class ImmutablePropertiesSource {\n\n\t/**\n\t * Description of this simple property.\n\t */\n\t@SuppressWarnings(\"unused\")\n\tprivate final String name;\n\n\t/**\n\t * Whether it is enabled.\n\t */\n\t@SuppressWarnings(\"unused\")\n\tprivate final boolean enabled;\n\n\tpublic ImmutablePropertiesSource(@TestDefaultValue(\"boot\") String name, boolean enabled) {\n\t\tthis.name = name;\n\t\tthis.enabled = enabled;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/LombokPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\n\n@Getter\n@Setter\n@TestConfigurationPropertiesSource\npublic class LombokPropertiesSource {\n\n\t/**\n\t * Description of this simple property.\n\t */\n\t@SuppressWarnings(\"unused\")\n\tprivate String name = \"boot\";\n\n\t/**\n\t * Whether it is enabled.\n\t */\n\t@SuppressWarnings(\"unused\")\n\tprivate boolean enabled;\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/NestedPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\n\n@TestConfigurationPropertiesSource\npublic class NestedPropertiesSource {\n\n\t/**\n\t * A name.\n\t */\n\tprivate String name;\n\n\tprivate final Nested nested = new Nested();\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Nested getNested() {\n\t\treturn this.nested;\n\t}\n\n\tpublic static class Nested {\n\n\t\t/**\n\t\t * Another name.\n\t\t */\n\t\tprivate String name;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/RecordPropertiesSources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Sample record properties source.\n *\n * @param name Description of this simple property.\n * @param enabled Whether it is enabled.\n * @author Stephane Nicoll\n */\n@TestConfigurationPropertiesSource\npublic record RecordPropertiesSources(@TestDefaultValue(\"boot\") String name, boolean enabled) {\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/source/generation/SimplePropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.source.generation;\n\nimport org.springframework.boot.configurationsample.TestConfigurationPropertiesSource;\n\n@TestConfigurationPropertiesSource\npublic class SimplePropertiesSource {\n\n\t/**\n\t * Description of this simple property.\n\t */\n\tprivate String name = \"boot\";\n\n\t/**\n\t * Whether it is enabled.\n\t */\n\tprivate boolean enabled;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/AnnotatedGetter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport jakarta.validation.constraints.NotEmpty;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * An annotated getter with {@code NotEmpty} that triggers a different class type in the\n * compiler. See #11512\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"specific\")\npublic class AnnotatedGetter {\n\n\tprivate String name;\n\n\t@NotEmpty\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/BoxingPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrate the use of boxing/unboxing. Even if the type does not strictly match, it\n * should still be detected.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"boxing\")\npublic class BoxingPojo {\n\n\tprivate boolean flag;\n\n\tprivate Boolean anotherFlag;\n\n\tprivate Integer counter;\n\n\tpublic boolean isFlag() {\n\t\treturn this.flag;\n\t}\n\n\t// Setter use Boolean\n\tpublic void setFlag(Boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n\tpublic boolean isAnotherFlag() {\n\t\treturn Boolean.TRUE.equals(this.anotherFlag);\n\t}\n\n\tpublic void setAnotherFlag(boolean anotherFlag) {\n\t\tthis.anotherFlag = anotherFlag;\n\t}\n\n\tpublic Integer getCounter() {\n\t\treturn this.counter;\n\t}\n\n\t// Setter use int\n\tpublic void setCounter(int counter) {\n\t\tthis.counter = counter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/BuilderPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample with builder style setters.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"builder\")\npublic class BuilderPojo {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic BuilderPojo setName(String name) {\n\t\tthis.name = name;\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/DeprecatedLessPreciseTypePojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrate that deprecating accessor with not the same type is not taken into account\n * to detect the deprecated flag.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"not.deprecated\")\npublic class DeprecatedLessPreciseTypePojo {\n\n\tprivate boolean flag;\n\n\t@Deprecated\n\tpublic Boolean getFlag() {\n\t\treturn this.flag;\n\t}\n\n\tpublic boolean isFlag() {\n\t\treturn this.flag;\n\t}\n\n\tpublic void setFlag(boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n\t@Deprecated\n\tpublic void setFlag(Boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/DeprecatedSimplePojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\n/**\n * POJO for use with samples needing a deprecated value.\n *\n * @author Jared Bates\n */\npublic class DeprecatedSimplePojo {\n\n\tprivate int value;\n\n\t@Deprecated\n\tpublic int getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(int value) {\n\t\tthis.value = value;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/DeprecatedUnrelatedMethodPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrate that an unrelated setter is not taken into account to detect the deprecated\n * flag.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"not.deprecated\")\npublic class DeprecatedUnrelatedMethodPojo {\n\n\tprivate Integer counter;\n\n\tprivate boolean flag;\n\n\tpublic Integer getCounter() {\n\t\treturn this.counter;\n\t}\n\n\tpublic void setCounter(Integer counter) {\n\t\tthis.counter = counter;\n\t}\n\n\t@Deprecated\n\tpublic void setCounter(String counterAsString) {\n\t\tthis.counter = Integer.valueOf(counterAsString);\n\t}\n\n\tpublic boolean isFlag() {\n\t\treturn this.flag;\n\t}\n\n\tpublic void setFlag(boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n\t@Deprecated\n\tpublic void setFlag(Boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/DoubleRegistrationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Test that the same type can be registered several times if the prefix is different.\n *\n * @author Stephane Nicoll\n */\npublic class DoubleRegistrationProperties {\n\n\t@TestConfigurationProperties(\"one\")\n\tpublic SimplePojo one() {\n\t\treturn new SimplePojo();\n\t}\n\n\t@TestConfigurationProperties(\"two\")\n\tpublic SimplePojo two() {\n\t\treturn new SimplePojo();\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/EmptyDefaultValueProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestConstructorBinding;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Demonstrates that an empty default value on a property leads to no default value.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"test\")\npublic class EmptyDefaultValueProperties {\n\n\tprivate final String name;\n\n\t@TestConstructorBinding\n\tpublic EmptyDefaultValueProperties(@TestDefaultValue String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/EnumValuesPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport java.time.temporal.ChronoField;\nimport java.time.temporal.ChronoUnit;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample config for enum and default values.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"test\")\npublic class EnumValuesPojo {\n\n\tprivate ChronoUnit seconds = ChronoUnit.SECONDS;\n\n\tprivate ChronoField hourOfDay = ChronoField.HOUR_OF_DAY;\n\n\tpublic ChronoUnit getSeconds() {\n\t\treturn this.seconds;\n\t}\n\n\tpublic void setSeconds(ChronoUnit seconds) {\n\t\tthis.seconds = seconds;\n\t}\n\n\tpublic ChronoField getHourOfDay() {\n\t\treturn this.hourOfDay;\n\t}\n\n\tpublic void setHourOfDay(ChronoField hourOfDay) {\n\t\tthis.hourOfDay = hourOfDay;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/ExcludedTypesPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport java.io.PrintWriter;\nimport java.io.Writer;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample config with types that should not be added to the meta-data as we have no way to\n * bind them from simple strings.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"excluded\")\npublic class ExcludedTypesPojo {\n\n\tprivate String name;\n\n\tprivate ClassLoader classLoader;\n\n\tprivate DataSource dataSource;\n\n\tprivate PrintWriter printWriter;\n\n\tprivate Writer writer;\n\n\tprivate Writer[] writerArray;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic ClassLoader getClassLoader() {\n\t\treturn this.classLoader;\n\t}\n\n\tpublic void setClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\tpublic DataSource getDataSource() {\n\t\treturn this.dataSource;\n\t}\n\n\tpublic void setDataSource(DataSource dataSource) {\n\t\tthis.dataSource = dataSource;\n\t}\n\n\tpublic PrintWriter getPrintWriter() {\n\t\treturn this.printWriter;\n\t}\n\n\tpublic void setPrintWriter(PrintWriter printWriter) {\n\t\tthis.printWriter = printWriter;\n\t}\n\n\tpublic Writer getWriter() {\n\t\treturn this.writer;\n\t}\n\n\tpublic void setWriter(Writer writer) {\n\t\tthis.writer = writer;\n\t}\n\n\tpublic Writer[] getWriterArray() {\n\t\treturn this.writerArray;\n\t}\n\n\tpublic void setWriterArray(Writer[] writerArray) {\n\t\tthis.writerArray = writerArray;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InnerClassAnnotatedGetterConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrate that a method that exposes a root group within an annotated class is\n * ignored as it should.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"specific\")\npublic class InnerClassAnnotatedGetterConfig {\n\n\tprivate String value;\n\n\tpublic String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@TestConfigurationProperties(\"foo\")\n\tpublic Foo getFoo() {\n\t\treturn new Foo();\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InnerClassHierarchicalProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrate inner classes end up in metadata regardless of position in hierarchy and\n * without the use of {@code @NestedConfigurationProperty}.\n *\n * @author Madhura Bhave\n */\n@TestConfigurationProperties(\"config\")\npublic class InnerClassHierarchicalProperties {\n\n\tprivate Foo foo;\n\n\tpublic Foo getFoo() {\n\t\treturn this.foo;\n\t}\n\n\tpublic void setFoo(Foo foo) {\n\t\tthis.foo = foo;\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate Bar bar;\n\n\t\tpublic Bar getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tpublic void setBar(Bar bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tpublic static class Baz {\n\n\t\t\tprivate String blah;\n\n\t\t\tpublic String getBlah() {\n\t\t\t\treturn this.blah;\n\t\t\t}\n\n\t\t\tpublic void setBlah(String blah) {\n\t\t\t\tthis.blah = blah;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Bar {\n\n\t\tprivate String bling;\n\n\t\tprivate Foo.Baz baz;\n\n\t\tpublic String getBling() {\n\t\t\treturn this.bling;\n\t\t}\n\n\t\tpublic void setBling(String foo) {\n\t\t\tthis.bling = foo;\n\t\t}\n\n\t\tpublic Foo.Baz getBaz() {\n\t\t\treturn this.baz;\n\t\t}\n\n\t\tpublic void setBaz(Foo.Baz baz) {\n\t\t\tthis.baz = baz;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InnerClassProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestNestedConfigurationProperty;\n\n/**\n * Demonstrate the auto-detection of inner config classes.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"config\")\npublic class InnerClassProperties {\n\n\tprivate final Foo first = new Foo();\n\n\tprivate Foo second = new Foo();\n\n\t@TestNestedConfigurationProperty\n\tprivate final SimplePojo third = new SimplePojo();\n\n\tprivate Fourth fourth;\n\n\tprivate final DeprecatedSimplePojo fifth = new DeprecatedSimplePojo();\n\n\tpublic Foo getFirst() {\n\t\treturn this.first;\n\t}\n\n\tpublic Foo getTheSecond() {\n\t\treturn this.second;\n\t}\n\n\tpublic void setTheSecond(Foo second) {\n\t\tthis.second = second;\n\t}\n\n\tpublic SimplePojo getThird() {\n\t\treturn this.third;\n\t}\n\n\tpublic Fourth getFourth() {\n\t\treturn this.fourth;\n\t}\n\n\tpublic void setFourth(Fourth fourth) {\n\t\tthis.fourth = fourth;\n\t}\n\n\t@TestNestedConfigurationProperty\n\tpublic DeprecatedSimplePojo getFifth() {\n\t\treturn this.fifth;\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tprivate final Bar bar = new Bar();\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Bar getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tpublic static class Bar {\n\n\t\t\tprivate String name;\n\n\t\t\tpublic String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic void setName(String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic enum Fourth {\n\n\t\tYES, NO\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InnerClassRootConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Sample with a simple inner class config.\n *\n * @author Stephane Nicoll\n */\npublic class InnerClassRootConfig {\n\n\t@TestConfigurationProperties(\"config\")\n\tpublic static class Config {\n\n\t\tprivate String name;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InvalidAccessorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Demonstrates that invalid accessors are ignored.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"config\")\npublic class InvalidAccessorProperties {\n\n\tprivate String name;\n\n\tprivate boolean flag;\n\n\tpublic void set(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String get() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setFlag(boolean flag) {\n\t\tthis.flag = flag;\n\t}\n\n\tpublic boolean is() {\n\t\treturn this.flag;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InvalidDefaultValueCharacterProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestConstructorBinding;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Demonstrates that an invalid default character value leads to a compilation failure.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"test\")\npublic class InvalidDefaultValueCharacterProperties {\n\n\tprivate final char letter;\n\n\t@TestConstructorBinding\n\tpublic InvalidDefaultValueCharacterProperties(@TestDefaultValue(\"bad\") char letter) {\n\t\tthis.letter = letter;\n\t}\n\n\tpublic char getLetter() {\n\t\treturn this.letter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InvalidDefaultValueFloatingPointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Demonstrates that an invalid default floating point value leads to a compilation\n * failure.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"test\")\npublic class InvalidDefaultValueFloatingPointProperties {\n\n\tprivate final Double ratio;\n\n\tpublic InvalidDefaultValueFloatingPointProperties(@TestDefaultValue(\"55.55.33\") Double ratio) {\n\t\tthis.ratio = ratio;\n\t}\n\n\tpublic Double getRatio() {\n\t\treturn this.ratio;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InvalidDefaultValueNumberProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.TestDefaultValue;\n\n/**\n * Demonstrates that an invalid default number value leads to a compilation failure.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"test\")\npublic class InvalidDefaultValueNumberProperties {\n\n\tprivate final int counter;\n\n\tpublic InvalidDefaultValueNumberProperties(@TestDefaultValue(\"invalid\") int counter) {\n\t\tthis.counter = counter;\n\t}\n\n\tpublic int getCounter() {\n\t\treturn this.counter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/InvalidDoubleRegistrationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * Test that compilation fails if the same type is registered twice with the same prefix.\n *\n * @author Stephane Nicoll\n */\npublic class InvalidDoubleRegistrationProperties {\n\n\t@TestConfigurationProperties(\"foo\")\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\t@TestConfigurationProperties(\"foo\")\n\tpublic static class Foo {\n\n\t\tprivate String name;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/MatchingConstructorNoDirectiveProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\n/**\n * Simple properties with a constructor but no binding directive.\n *\n * @author Stephane Nicoll\n */\npublic class MatchingConstructorNoDirectiveProperties {\n\n\tprivate String name;\n\n\tpublic MatchingConstructorNoDirectiveProperties(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/SimpleConflictingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\nimport org.springframework.boot.configurationsample.simple.SimpleProperties;\n\n/**\n * Properties that conflict with {@link SimpleProperties}.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"simple\")\npublic class SimpleConflictingProperties {\n\n\tprivate String flag = \"hello\";\n\n\tpublic String getFlag() {\n\t\treturn this.flag;\n\t}\n\n\tpublic void setFlag(String flag) {\n\t\tthis.flag = flag;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/SimplePojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\n/**\n * POJO for use with samples.\n *\n * @author Stephane Nicoll\n */\npublic class SimplePojo {\n\n\tprivate int value;\n\n\tpublic int getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(int value) {\n\t\tthis.value = value;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/StaticAccessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\nimport org.springframework.boot.configurationsample.TestConfigurationProperties;\n\n/**\n * A property that is exposed by static accessors.\n *\n * @author Stephane Nicoll\n */\n@TestConfigurationProperties(\"specific\")\npublic class StaticAccessor {\n\n\tprivate static String name;\n\n\tprivate int counter = 42;\n\n\tpublic static String getName() {\n\t\treturn name;\n\t}\n\n\tpublic static void setName(String name) {\n\t\tStaticAccessor.name = name;\n\t}\n\n\tpublic int getCounter() {\n\t\treturn this.counter;\n\t}\n\n\tpublic void setCounter(int counter) {\n\t\tthis.counter = counter;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/TwoConstructorsExample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationsample.specific;\n\n/**\n * A type with more than one constructor.\n *\n * @author Stephane Nicoll\n */\npublic class TwoConstructorsExample {\n\n\tprivate String name;\n\n\tpublic TwoConstructorsExample() {\n\t}\n\n\tpublic TwoConstructorsExample(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/META-INF/spring/configuration-metadata/org.springframework.boot.configurationsample.source.BaseSource.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether the feature is enabled.\"\n    },\n    {\n      \"name\": \"username\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"User name.\",\n      \"defaultValue\": \"user\"\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/META-INF/spring/configuration-metadata/org.springframework.boot.configurationsample.source.ConventionSource.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"firstName\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Camel case.\"\n    },\n    {\n      \"name\": \"last-name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Canonical format.\"\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/META-INF/spring/configuration-metadata/org.springframework.boot.configurationsample.source.ImmutableSource.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Name description.\"\n    },\n    {\n      \"name\": \"description\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Description description.\",\n      \"defaultValue\": \"Hello World\"\n    },\n    {\n      \"name\": \"type\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"A property with a fixed set of values.\",\n      \"defaultValue\": \"single\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"type\",\n      \"values\": [\n        {\n          \"value\": \"auto\",\n          \"description\": \"Detect the type automatically.\"\n        },\n        {\n          \"value\": \"single\",\n          \"description\": \"Single type.\"\n        },\n        {\n          \"value\": \"multi\",\n          \"description\": \"Multi type.\"\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/META-INF/spring/configuration-metadata/org.springframework.boot.configurationsample.source.LombokSource.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Name description.\"\n    },\n    {\n      \"name\": \"description\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Description description.\",\n      \"defaultValue\": \"Hello World\"\n    },\n    {\n      \"name\": \"type\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"A property with a fixed set of values.\",\n      \"defaultValue\": \"single\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"type\",\n      \"values\": [\n        {\n          \"value\": \"auto\",\n          \"description\": \"Detect the type automatically.\"\n        },\n        {\n          \"value\": \"single\",\n          \"description\": \"Single type.\"\n        },\n        {\n          \"value\": \"multi\",\n          \"description\": \"Multi type.\"\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/META-INF/spring/configuration-metadata/org.springframework.boot.configurationsample.source.RecordSource.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Name description.\"\n    },\n    {\n      \"name\": \"description\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Description description.\",\n      \"defaultValue\": \"Hello World\"\n    },\n    {\n      \"name\": \"type\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"A property with a fixed set of values.\",\n      \"defaultValue\": \"single\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"type\",\n      \"values\": [\n        {\n          \"value\": \"auto\",\n          \"description\": \"Detect the type automatically.\"\n        },\n        {\n          \"value\": \"single\",\n          \"description\": \"Single type.\"\n        },\n        {\n          \"value\": \"multi\",\n          \"description\": \"Multi type.\"\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/META-INF/spring/configuration-metadata/org.springframework.boot.configurationsample.source.SimpleSource.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Name description.\"\n    },\n    {\n      \"name\": \"description\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Description description.\",\n      \"defaultValue\": \"Hello World\"\n    },\n    {\n      \"name\": \"type\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"A property with a fixed set of values.\",\n      \"defaultValue\": \"single\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"type\",\n      \"values\": [\n        {\n          \"value\": \"auto\",\n          \"description\": \"Detect the type automatically.\"\n        },\n        {\n          \"value\": \"single\",\n          \"description\": \"Single type.\"\n        },\n        {\n          \"value\": \"multi\",\n          \"description\": \"Multi type.\"\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "configuration-metadata/spring-boot-configuration-processor/src/test/resources/org/springframework/boot/configurationsample/incremental/BarProperties.snippet",
    "content": "\tprivate String extra;\n\n\tpublic String getExtra() {\n\t\treturn extra;\n\t}\n\n\tpublic void setExtra(String extra) {\n\t\tthis.extra = extra;\n\t}\n"
  },
  {
    "path": "core/spring-boot/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"org.jetbrains.dokka\"\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot\"\n\ndependencies {\n\tannotationProcessor(\"org.apache.logging.log4j:log4j-core\")\n\n\tapi(\"org.springframework:spring-core\")\n\tapi(\"org.springframework:spring-context\")\n\n\toptional(\"ch.qos.logback:logback-classic\")\n\toptional(\"com.google.code.gson:gson\")\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"jakarta.validation:jakarta.validation-api\")\n\toptional(\"org.apache.groovy:groovy\")\n\toptional(\"org.apache.logging.log4j:log4j-api\")\n\toptional(\"org.apache.logging.log4j:log4j-core\")\n\toptional(\"org.apache.logging.log4j:log4j-jul\")\n\toptional(\"org.crac:crac\")\n\toptional(\"org.jetbrains.kotlin:kotlin-reflect\")\n\toptional(\"org.jetbrains.kotlin:kotlin-stdlib\")\n\toptional(\"org.slf4j:jul-to-slf4j\")\n\toptional(\"org.springframework:spring-test\")\n\toptional(\"org.springframework:spring-web\")\n\toptional(\"org.yaml:snakeyaml\")\n\toptional(\"tools.jackson.core:jackson-databind\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestFixturesCompileOnly(project(\":test-support:spring-boot-test-support\"))\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestImplementation(\"jakarta.annotation:jakarta.annotation-api\")\n\ttestImplementation(\"jakarta.inject:jakarta.inject-api\")\n\ttestImplementation(\"org.apache.groovy:groovy-xml\")\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\ttestImplementation(\"org.apache.tomcat:tomcat-jdbc\")\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-core\")\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\ttestImplementation(\"org.codehaus.janino:janino\")\n\ttestImplementation(\"org.eclipse.jetty:jetty-client\")\n\ttestImplementation(\"org.eclipse.jetty.http2:jetty-http2-client\")\n\ttestImplementation(\"org.eclipse.jetty.http2:jetty-http2-client-transport\")\n\ttestImplementation(\"org.hibernate.validator:hibernate-validator\")\n\ttestImplementation(\"org.jboss.logging:jboss-logging\")\n\ttestImplementation(\"org.springframework.data:spring-data-r2dbc\")\n}\n\ndef syncJavaTemplates = tasks.register(\"syncJavaTemplates\", Sync) {\n\tfrom(\"src/main/javaTemplates\")\n\tinto(\"build/generated-sources/main\")\n\tdef properties = [\"springBootVersion\": project.version]\n\texpand(properties)\n\tinputs.properties(properties)\n}\n\ntasks.named(\"checkFormatMain\") {\n\t// Add the templates to check that the input is correctly formatted\n\tsource(fileTree(\"src/main/javaTemplates\"))\n}\n\ntasks.named(\"compileJava\") {\n\t// Provide the project coordinates to the `GraalVmProcessor`:\n\toptions.compilerArgs << '-Alog4j.graalvm.groupId=org.springframework.boot'\n\toptions.compilerArgs << '-Alog4j.graalvm.artifactId=spring-boot-log4j'\n}\n\nplugins.withType(EclipsePlugin) {\n\teclipse {\n\t\tsynchronizationTasks syncJavaTemplates\n\t}\n}\n\nsourceSets {\n\tmain {\n\t\tjava {\n\t\t\tsrcDirs syncJavaTemplates\n\t\t}\n\t}\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/AotInitializerNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\n/**\n * Exception thrown when the AOT initializer couldn't be found.\n *\n * @author Moritz Halbritter\n * @since 3.2.6\n */\npublic class AotInitializerNotFoundException extends RuntimeException {\n\n\tprivate final Class<?> mainClass;\n\n\tpublic AotInitializerNotFoundException(Class<?> mainClass, String initializerClassName) {\n\t\tsuper(\"Startup with AOT mode enabled failed: AOT initializer %s could not be found\"\n\t\t\t.formatted(initializerClassName));\n\t\tthis.mainClass = mainClass;\n\t}\n\n\tpublic Class<?> getMainClass() {\n\t\treturn this.mainClass;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ApplicationArguments.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides access to the arguments that were used to run a {@link SpringApplication}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic interface ApplicationArguments {\n\n\t/**\n\t * Return the raw unprocessed arguments that were passed to the application.\n\t * @return the arguments\n\t */\n\tString[] getSourceArgs();\n\n\t/**\n\t * Return the names of all option arguments. For example, if the arguments were\n\t * \"--foo=bar --debug\" would return the values {@code [\"foo\", \"debug\"]}.\n\t * @return the option names or an empty set\n\t */\n\tSet<String> getOptionNames();\n\n\t/**\n\t * Return whether the set of option arguments parsed from the arguments contains an\n\t * option with the given name.\n\t * @param name the name to check\n\t * @return {@code true} if the arguments contain an option with the given name\n\t */\n\tboolean containsOption(String name);\n\n\t/**\n\t * Return the collection of values associated with the arguments option having the\n\t * given name.\n\t * <ul>\n\t * <li>if the option is present and has no argument (e.g.: \"--foo\"), return an empty\n\t * collection ({@code []})</li>\n\t * <li>if the option is present and has a single value (e.g. \"--foo=bar\"), return a\n\t * collection having one element ({@code [\"bar\"]})</li>\n\t * <li>if the option is present and has multiple values (e.g. \"--foo=bar --foo=baz\"),\n\t * return a collection having elements for each value ({@code [\"bar\", \"baz\"]})</li>\n\t * <li>if the option is not present, return {@code null}</li>\n\t * </ul>\n\t * @param name the name of the option\n\t * @return a list of option values for the given name\n\t */\n\t@Nullable List<String> getOptionValues(String name);\n\n\t/**\n\t * Return the collection of non-option arguments parsed.\n\t * @return the non-option arguments or an empty list\n\t */\n\tList<String> getNonOptionArgs();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ApplicationContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\n/**\n * Strategy interface for creating the {@link ConfigurableApplicationContext} used by a\n * {@link SpringApplication}. Created contexts should be returned in their default form,\n * with the {@code SpringApplication} responsible for configuring and refreshing the\n * context.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.4.0\n */\n@FunctionalInterface\npublic interface ApplicationContextFactory {\n\n\t/**\n\t * A default {@link ApplicationContextFactory} implementation that will create an\n\t * appropriate context for the {@link WebApplicationType}.\n\t */\n\tApplicationContextFactory DEFAULT = new DefaultApplicationContextFactory();\n\n\t/**\n\t * Return the {@link Environment} type expected to be set on the\n\t * {@link #create(WebApplicationType) created} application context. The result of this\n\t * method can be used to convert an existing environment instance to the correct type.\n\t * @param webApplicationType the web application type or {@code null}\n\t * @return the expected application context type or {@code null} to use the default\n\t * @since 2.6.14\n\t */\n\tdefault @Nullable Class<? extends ConfigurableEnvironment> getEnvironmentType(\n\t\t\t@Nullable WebApplicationType webApplicationType) {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create a new {@link Environment} to be set on the\n\t * {@link #create(WebApplicationType) created} application context. The result of this\n\t * method must match the type returned by\n\t * {@link #getEnvironmentType(WebApplicationType)}.\n\t * @param webApplicationType the web application type or {@code null}\n\t * @return an environment instance or {@code null} to use the default\n\t * @since 2.6.14\n\t */\n\tdefault @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Creates the {@link ConfigurableApplicationContext application context} for a\n\t * {@link SpringApplication}, respecting the given {@code webApplicationType}.\n\t * @param webApplicationType the web application type\n\t * @return the newly created application context\n\t */\n\t@Nullable ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType);\n\n\t/**\n\t * Creates an {@code ApplicationContextFactory} that will create contexts by\n\t * instantiating the given {@code contextClass} through its primary constructor.\n\t * @param contextClass the context class\n\t * @return the factory that will instantiate the context class\n\t * @see BeanUtils#instantiateClass(Class)\n\t */\n\tstatic ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {\n\t\treturn of(() -> BeanUtils.instantiateClass(contextClass));\n\t}\n\n\t/**\n\t * Creates an {@code ApplicationContextFactory} that will create contexts by calling\n\t * the given {@link Supplier}.\n\t * @param supplier the context supplier, for example\n\t * {@code AnnotationConfigApplicationContext::new}\n\t * @return the factory that will instantiate the context class\n\t */\n\tstatic ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {\n\t\treturn (webApplicationType) -> supplier.get();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ApplicationEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.core.env.ConfigurablePropertyResolver;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * {@link StandardEnvironment} for typical use in a typical {@link SpringApplication}.\n *\n * @author Phillip Webb\n */\nclass ApplicationEnvironment extends StandardEnvironment {\n\n\t@Override\n\tprotected @Nullable String doGetActiveProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected @Nullable String doGetDefaultProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {\n\t\treturn ConfigurationPropertySources.createPropertyResolver(propertySources);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ApplicationInfoPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.boot.system.ApplicationPid;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link PropertySource} which provides information about the application, like the\n * process ID (PID) or the version.\n *\n * @author Moritz Halbritter\n */\nclass ApplicationInfoPropertySource extends MapPropertySource implements PropertySourceInfo {\n\n\tstatic final String NAME = \"applicationInfo\";\n\n\tApplicationInfoPropertySource(@Nullable Class<?> mainClass) {\n\t\tsuper(NAME, getProperties(readVersion(mainClass)));\n\t}\n\n\tApplicationInfoPropertySource(@Nullable String applicationVersion) {\n\t\tsuper(NAME, getProperties(applicationVersion));\n\t}\n\n\t@Override\n\tpublic boolean isImmutable() {\n\t\treturn true;\n\t}\n\n\tprivate static Map<String, Object> getProperties(@Nullable String applicationVersion) {\n\t\tMap<String, Object> result = new HashMap<>();\n\t\tif (StringUtils.hasText(applicationVersion)) {\n\t\t\tresult.put(\"spring.application.version\", applicationVersion);\n\t\t}\n\t\tApplicationPid applicationPid = new ApplicationPid();\n\t\tLong pid = applicationPid.toLong();\n\t\tif (pid != null) {\n\t\t\tresult.put(\"spring.application.pid\", pid);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static @Nullable String readVersion(@Nullable Class<?> applicationClass) {\n\t\tPackage sourcePackage = (applicationClass != null) ? applicationClass.getPackage() : null;\n\t\treturn (sourcePackage != null) ? sourcePackage.getImplementationVersion() : null;\n\t}\n\n\t/**\n\t * Moves the {@link ApplicationInfoPropertySource} to the end of the environment's\n\t * property sources.\n\t * @param environment the environment\n\t */\n\tstatic void moveToEnd(ConfigurableEnvironment environment) {\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tPropertySource<?> propertySource = propertySources.remove(NAME);\n\t\tif (propertySource != null) {\n\t\t\tpropertySources.addLast(propertySource);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ApplicationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.Banner.Mode;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * Spring application properties.\n *\n * @author Moritz Halbritter\n */\nclass ApplicationProperties {\n\n\t/**\n\t * Whether bean definition overriding, by registering a definition with the same name\n\t * as an existing definition, is allowed.\n\t */\n\tprivate boolean allowBeanDefinitionOverriding;\n\n\t/**\n\t * Whether to allow circular references between beans and automatically try to resolve\n\t * them.\n\t */\n\tprivate boolean allowCircularReferences;\n\n\t/**\n\t * Mode used to display the banner when the application runs.\n\t */\n\tprivate Banner.@Nullable Mode bannerMode;\n\n\t/**\n\t * Whether to keep the application alive even if there are no more non-daemon threads.\n\t */\n\tprivate boolean keepAlive;\n\n\t/**\n\t * Whether initialization should be performed lazily.\n\t */\n\tprivate boolean lazyInitialization;\n\n\t/**\n\t * Whether to log information about the application when it starts.\n\t */\n\tprivate boolean logStartupInfo = true;\n\n\t/**\n\t * Whether the application should have a shutdown hook registered.\n\t */\n\tprivate boolean registerShutdownHook = true;\n\n\t/**\n\t * Sources (class names, package names, or XML resource locations) to include in the\n\t * ApplicationContext.\n\t */\n\tprivate Set<String> sources = new LinkedHashSet<>();\n\n\t/**\n\t * Flag to explicitly request a specific type of web application. If not set,\n\t * auto-detected based on the classpath.\n\t */\n\tprivate @Nullable WebApplicationType webApplicationType;\n\n\tboolean isAllowBeanDefinitionOverriding() {\n\t\treturn this.allowBeanDefinitionOverriding;\n\t}\n\n\tvoid setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {\n\t\tthis.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;\n\t}\n\n\tboolean isAllowCircularReferences() {\n\t\treturn this.allowCircularReferences;\n\t}\n\n\tvoid setAllowCircularReferences(boolean allowCircularReferences) {\n\t\tthis.allowCircularReferences = allowCircularReferences;\n\t}\n\n\tMode getBannerMode(Environment environment) {\n\t\tif (this.bannerMode != null) {\n\t\t\treturn this.bannerMode;\n\t\t}\n\t\tString applicationPropertyName = LoggingSystemProperty.CONSOLE_STRUCTURED_FORMAT.getApplicationPropertyName();\n\t\tAssert.state(applicationPropertyName != null, \"applicationPropertyName must not be null\");\n\t\tboolean structuredLoggingEnabled = environment.containsProperty(applicationPropertyName);\n\t\treturn (structuredLoggingEnabled) ? Mode.OFF : Banner.Mode.CONSOLE;\n\t}\n\n\tvoid setBannerMode(@Nullable Mode bannerMode) {\n\t\tthis.bannerMode = bannerMode;\n\t}\n\n\tboolean isKeepAlive() {\n\t\treturn this.keepAlive;\n\t}\n\n\tvoid setKeepAlive(boolean keepAlive) {\n\t\tthis.keepAlive = keepAlive;\n\t}\n\n\tboolean isLazyInitialization() {\n\t\treturn this.lazyInitialization;\n\t}\n\n\tvoid setLazyInitialization(boolean lazyInitialization) {\n\t\tthis.lazyInitialization = lazyInitialization;\n\t}\n\n\tboolean isLogStartupInfo() {\n\t\treturn this.logStartupInfo;\n\t}\n\n\tvoid setLogStartupInfo(boolean logStartupInfo) {\n\t\tthis.logStartupInfo = logStartupInfo;\n\t}\n\n\tboolean isRegisterShutdownHook() {\n\t\treturn this.registerShutdownHook;\n\t}\n\n\tvoid setRegisterShutdownHook(boolean registerShutdownHook) {\n\t\tthis.registerShutdownHook = registerShutdownHook;\n\t}\n\n\tSet<String> getSources() {\n\t\treturn this.sources;\n\t}\n\n\tvoid setSources(Set<String> sources) {\n\t\tthis.sources = new LinkedHashSet<>(sources);\n\t}\n\n\t@Nullable WebApplicationType getWebApplicationType() {\n\t\treturn this.webApplicationType;\n\t}\n\n\tvoid setWebApplicationType(@Nullable WebApplicationType webApplicationType) {\n\t\tthis.webApplicationType = webApplicationType;\n\t}\n\n\tstatic class ApplicationPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tBindableRuntimeHintsRegistrar.forTypes(ApplicationProperties.class).registerHints(hints, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ApplicationRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Interface used to indicate that a bean should <em>run</em> when it is contained within\n * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined\n * within the same application context and can be ordered using the {@link Ordered}\n * interface or {@link Order @Order} annotation.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see CommandLineRunner\n */\n@FunctionalInterface\npublic interface ApplicationRunner extends Runner {\n\n\t/**\n\t * Callback used to run the bean.\n\t * @param args incoming application arguments\n\t * @throws Exception on error\n\t */\n\tvoid run(ApplicationArguments args) throws Exception;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/Banner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.PrintStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\n\n/**\n * Interface class for writing a banner programmatically.\n *\n * @author Phillip Webb\n * @author Michael Stummvoll\n * @author Jeremy Rickard\n * @since 1.2.0\n */\n@FunctionalInterface\npublic interface Banner {\n\n\t/**\n\t * Print the banner to the specified print stream.\n\t * @param environment the spring environment\n\t * @param sourceClass the source class for the application or {@code null}\n\t * @param out the output print stream\n\t */\n\tvoid printBanner(Environment environment, @Nullable Class<?> sourceClass, PrintStream out);\n\n\t/**\n\t * An enumeration of possible values for configuring the Banner.\n\t */\n\tenum Mode {\n\n\t\t/**\n\t\t * Disable printing of the banner.\n\t\t */\n\t\tOFF,\n\n\t\t/**\n\t\t * Print the banner to System.out.\n\t\t */\n\t\tCONSOLE,\n\n\t\t/**\n\t\t * Print the banner to the log file.\n\t\t */\n\t\tLOG\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/BeanDefinitionLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\nimport groovy.lang.Closure;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.BeanDefinitionStoreException;\nimport org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;\nimport org.springframework.beans.factory.support.AbstractBeanDefinitionReader;\nimport org.springframework.beans.factory.support.BeanDefinitionReader;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.xml.XmlBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;\nimport org.springframework.core.type.filter.TypeFilter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Loads bean definitions from underlying sources, including XML and JavaConfig. Acts as a\n * simple facade over {@link AnnotatedBeanDefinitionReader},\n * {@link XmlBeanDefinitionReader} and {@link ClassPathBeanDefinitionScanner}. See\n * {@link SpringApplication} for the types of sources that are supported.\n *\n * @author Phillip Webb\n * @author Vladislav Kisel\n * @author Sebastien Deleuze\n * @see #setBeanNameGenerator(BeanNameGenerator)\n */\nclass BeanDefinitionLoader {\n\n\tprivate static final Pattern GROOVY_CLOSURE_PATTERN = Pattern.compile(\".*\\\\$_.*closure.*\");\n\n\tprivate final Object[] sources;\n\n\tprivate final AnnotatedBeanDefinitionReader annotatedReader;\n\n\tprivate final AbstractBeanDefinitionReader xmlReader;\n\n\tprivate final @Nullable BeanDefinitionReader groovyReader;\n\n\tprivate final ClassPathBeanDefinitionScanner scanner;\n\n\tprivate @Nullable ResourceLoader resourceLoader;\n\n\t/**\n\t * Create a new {@link BeanDefinitionLoader} that will load beans into the specified\n\t * {@link BeanDefinitionRegistry}.\n\t * @param registry the bean definition registry that will contain the loaded beans\n\t * @param sources the bean sources\n\t */\n\tBeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {\n\t\tAssert.notNull(registry, \"'registry' must not be null\");\n\t\tAssert.notEmpty(sources, \"'sources' must not be empty\");\n\t\tthis.sources = sources;\n\t\tthis.annotatedReader = new AnnotatedBeanDefinitionReader(registry);\n\t\tthis.xmlReader = new XmlBeanDefinitionReader(registry);\n\t\tthis.groovyReader = isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null;\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(registry);\n\t\tthis.scanner.addExcludeFilter(new ClassExcludeFilter(sources));\n\t}\n\n\t/**\n\t * Set the bean name generator to be used by the underlying readers and scanner.\n\t * @param beanNameGenerator the bean name generator\n\t */\n\tvoid setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {\n\t\tthis.annotatedReader.setBeanNameGenerator(beanNameGenerator);\n\t\tthis.scanner.setBeanNameGenerator(beanNameGenerator);\n\t\tthis.xmlReader.setBeanNameGenerator(beanNameGenerator);\n\t}\n\n\t/**\n\t * Set the resource loader to be used by the underlying readers and scanner.\n\t * @param resourceLoader the resource loader\n\t */\n\tvoid setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t\tthis.scanner.setResourceLoader(resourceLoader);\n\t\tthis.xmlReader.setResourceLoader(resourceLoader);\n\t}\n\n\t/**\n\t * Set the environment to be used by the underlying readers and scanner.\n\t * @param environment the environment\n\t */\n\tvoid setEnvironment(ConfigurableEnvironment environment) {\n\t\tthis.annotatedReader.setEnvironment(environment);\n\t\tthis.scanner.setEnvironment(environment);\n\t\tthis.xmlReader.setEnvironment(environment);\n\t}\n\n\t/**\n\t * Load the sources into the reader.\n\t */\n\tvoid load() {\n\t\tfor (Object source : this.sources) {\n\t\t\tload(source);\n\t\t}\n\t}\n\n\tprivate void load(Object source) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tif (source instanceof Class<?> type) {\n\t\t\tload(type);\n\t\t\treturn;\n\t\t}\n\t\tif (source instanceof Resource resource) {\n\t\t\tload(resource);\n\t\t\treturn;\n\t\t}\n\t\tif (source instanceof Package pack) {\n\t\t\tload(pack);\n\t\t\treturn;\n\t\t}\n\t\tif (source instanceof CharSequence sequence) {\n\t\t\tload(sequence);\n\t\t\treturn;\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Invalid source type \" + source.getClass());\n\t}\n\n\tprivate void load(Class<?> source) {\n\t\tif (this.groovyReader != null && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {\n\t\t\t// Any GroovyLoaders added in beans{} DSL can contribute beans here\n\t\t\tGroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);\n\t\t\t((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());\n\t\t}\n\t\tif (isEligible(source)) {\n\t\t\tthis.annotatedReader.register(source);\n\t\t}\n\t}\n\n\tprivate void load(Resource source) {\n\t\tString filename = source.getFilename();\n\t\tAssert.state(filename != null, \"Source has no filename\");\n\t\tif (filename.endsWith(\".groovy\")) {\n\t\t\tif (this.groovyReader == null) {\n\t\t\t\tthrow new BeanDefinitionStoreException(\"Cannot load Groovy beans without Groovy on classpath\");\n\t\t\t}\n\t\t\tthis.groovyReader.loadBeanDefinitions(source);\n\t\t}\n\t\telse {\n\t\t\tthis.xmlReader.loadBeanDefinitions(source);\n\t\t}\n\t}\n\n\tprivate void load(Package source) {\n\t\tthis.scanner.scan(source.getName());\n\t}\n\n\tprivate void load(CharSequence source) {\n\t\tString resolvedSource = this.scanner.getEnvironment().resolvePlaceholders(source.toString());\n\t\t// Attempt as a Class\n\t\ttry {\n\t\t\tload(ClassUtils.forName(resolvedSource, null));\n\t\t\treturn;\n\t\t}\n\t\tcatch (IllegalArgumentException | ClassNotFoundException ex) {\n\t\t\t// swallow exception and continue\n\t\t}\n\t\t// Attempt as Resources\n\t\tif (loadAsResources(resolvedSource)) {\n\t\t\treturn;\n\t\t}\n\t\t// Attempt as package\n\t\tPackage packageResource = findPackage(resolvedSource);\n\t\tif (packageResource != null) {\n\t\t\tload(packageResource);\n\t\t\treturn;\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Invalid source '\" + resolvedSource + \"'\");\n\t}\n\n\tprivate boolean loadAsResources(String resolvedSource) {\n\t\tboolean foundCandidate = false;\n\t\tResource[] resources = findResources(resolvedSource);\n\t\tfor (Resource resource : resources) {\n\t\t\tif (isLoadCandidate(resource)) {\n\t\t\t\tfoundCandidate = true;\n\t\t\t\tload(resource);\n\t\t\t}\n\t\t}\n\t\treturn foundCandidate;\n\t}\n\n\tprivate boolean isGroovyPresent() {\n\t\treturn ClassUtils.isPresent(\"groovy.lang.MetaClass\", null);\n\t}\n\n\tprivate Resource[] findResources(String source) {\n\t\tResourceLoader loader = (this.resourceLoader != null) ? this.resourceLoader\n\t\t\t\t: new PathMatchingResourcePatternResolver();\n\t\ttry {\n\t\t\tif (loader instanceof ResourcePatternResolver resolver) {\n\t\t\t\treturn resolver.getResources(source);\n\t\t\t}\n\t\t\treturn new Resource[] { loader.getResource(source) };\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Error reading source '\" + source + \"'\");\n\t\t}\n\t}\n\n\tprivate boolean isLoadCandidate(@Nullable Resource resource) {\n\t\tif (resource == null || !resource.exists()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (resource instanceof ClassPathResource classPathResource) {\n\t\t\t// A simple package without a '.' may accidentally get loaded as an XML\n\t\t\t// document if we're not careful. The result of getInputStream() will be\n\t\t\t// a file list of the package content. We double-check here that it's not\n\t\t\t// actually a package.\n\t\t\tString path = classPathResource.getPath();\n\t\t\tif (path.indexOf('.') == -1) {\n\t\t\t\ttry {\n\t\t\t\t\treturn getClass().getClassLoader().getDefinedPackage(path) == null;\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate @Nullable Package findPackage(CharSequence source) {\n\t\tPackage pkg = getClass().getClassLoader().getDefinedPackage(source.toString());\n\t\tif (pkg != null) {\n\t\t\treturn pkg;\n\t\t}\n\t\ttry {\n\t\t\t// Attempt to find a class in this package\n\t\t\tResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader());\n\t\t\tResource[] resources = resolver\n\t\t\t\t.getResources(ClassUtils.convertClassNameToResourcePath(source.toString()) + \"/*.class\");\n\t\t\tfor (Resource resource : resources) {\n\t\t\t\tString filename = resource.getFilename();\n\t\t\t\tAssert.state(filename != null, \"No filename available\");\n\t\t\t\tString className = StringUtils.stripFilenameExtension(filename);\n\t\t\t\tload(Class.forName(source + \".\" + className));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// swallow exception and continue\n\t\t}\n\t\treturn getClass().getClassLoader().getDefinedPackage(source.toString());\n\t}\n\n\t/**\n\t * Check whether the bean is eligible for registration.\n\t * @param type candidate bean type\n\t * @return true if the given bean type is eligible for registration, i.e. not a groovy\n\t * closure nor an anonymous class\n\t */\n\tprivate boolean isEligible(Class<?> type) {\n\t\treturn !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));\n\t}\n\n\tprivate boolean isGroovyClosure(Class<?> type) {\n\t\treturn GROOVY_CLOSURE_PATTERN.matcher(type.getName()).matches();\n\t}\n\n\tprivate boolean hasNoConstructors(Class<?> type) {\n\t\tConstructor<?>[] constructors = type.getDeclaredConstructors();\n\t\treturn ObjectUtils.isEmpty(constructors);\n\t}\n\n\t/**\n\t * Simple {@link TypeFilter} used to ensure that specified {@link Class} sources are\n\t * not accidentally re-added during scanning.\n\t */\n\tprivate static class ClassExcludeFilter extends AbstractTypeHierarchyTraversingFilter {\n\n\t\tprivate final Set<String> classNames = new HashSet<>();\n\n\t\tClassExcludeFilter(Object... sources) {\n\t\t\tsuper(false, false);\n\t\t\tfor (Object source : sources) {\n\t\t\t\tif (source instanceof Class<?> classSource) {\n\t\t\t\t\tthis.classNames.add(classSource.getName());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matchClassName(String className) {\n\t\t\treturn this.classNames.contains(className);\n\t\t}\n\n\t}\n\n\t/**\n\t * Source for Bean definitions defined in Groovy.\n\t */\n\t@FunctionalInterface\n\tprotected interface GroovyBeanDefinitionSource {\n\n\t\tClosure<?> getBeans();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ClearCachesApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link ApplicationListener} to cleanup caches once the context is loaded.\n *\n * @author Phillip Webb\n */\nclass ClearCachesApplicationListener implements ApplicationListener<ContextRefreshedEvent> {\n\n\t@Override\n\tpublic void onApplicationEvent(ContextRefreshedEvent event) {\n\t\tReflectionUtils.clearCache();\n\t\tclearClassLoaderCaches(Thread.currentThread().getContextClassLoader());\n\t}\n\n\tprivate void clearClassLoaderCaches(@Nullable ClassLoader classLoader) {\n\t\tif (classLoader == null) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tMethod clearCacheMethod = classLoader.getClass().getDeclaredMethod(\"clearCache\");\n\t\t\tclearCacheMethod.invoke(classLoader);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\tclearClassLoaderCaches(classLoader.getParent());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/CommandLineRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Interface used to indicate that a bean should <em>run</em> when it is contained within\n * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined\n * within the same application context and can be ordered using the {@link Ordered}\n * interface or {@link Order @Order} annotation.\n * <p>\n * If you need access to {@link ApplicationArguments} instead of the raw String array\n * consider using {@link ApplicationRunner}.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see ApplicationRunner\n */\n@FunctionalInterface\npublic interface CommandLineRunner extends Runner {\n\n\t/**\n\t * Callback used to run the bean.\n\t * @param args incoming main method arguments\n\t * @throws Exception on error\n\t */\n\tvoid run(String... args) throws Exception;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/DefaultApplicationArguments.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.SimpleCommandLinePropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * Default implementation of {@link ApplicationArguments}.\n *\n * @author Phillip Webb\n * @since 1.4.1\n */\npublic class DefaultApplicationArguments implements ApplicationArguments {\n\n\tprivate final Source source;\n\n\tprivate final String[] args;\n\n\tpublic DefaultApplicationArguments(String... args) {\n\t\tAssert.notNull(args, \"'args' must not be null\");\n\t\tthis.source = new Source(args);\n\t\tthis.args = args;\n\t}\n\n\t@Override\n\tpublic String[] getSourceArgs() {\n\t\treturn this.args;\n\t}\n\n\t@Override\n\tpublic Set<String> getOptionNames() {\n\t\tString[] names = this.source.getPropertyNames();\n\t\treturn Collections.unmodifiableSet(new HashSet<>(Arrays.asList(names)));\n\t}\n\n\t@Override\n\tpublic boolean containsOption(String name) {\n\t\treturn this.source.containsProperty(name);\n\t}\n\n\t@Override\n\tpublic @Nullable List<String> getOptionValues(String name) {\n\t\tList<String> values = this.source.getOptionValues(name);\n\t\treturn (values != null) ? Collections.unmodifiableList(values) : null;\n\t}\n\n\t@Override\n\tpublic List<String> getNonOptionArgs() {\n\t\treturn this.source.getNonOptionArgs();\n\t}\n\n\tprivate static class Source extends SimpleCommandLinePropertySource {\n\n\t\tSource(String[] args) {\n\t\t\tsuper(args);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> getNonOptionArgs() {\n\t\t\treturn super.getNonOptionArgs();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable List<String> getOptionValues(String name) {\n\t\t\treturn super.getOptionValues(name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/DefaultApplicationContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.function.BiFunction;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.lang.Contract;\n\n/**\n * Default {@link ApplicationContextFactory} implementation that will create an\n * appropriate context for the {@link WebApplicationType}.\n *\n * @author Phillip Webb\n */\nclass DefaultApplicationContextFactory implements ApplicationContextFactory {\n\n\t// Method reference is not detected with correct nullability\n\t@SuppressWarnings(\"NullAway\")\n\t@Override\n\tpublic @Nullable Class<? extends ConfigurableEnvironment> getEnvironmentType(\n\t\t\t@Nullable WebApplicationType webApplicationType) {\n\t\treturn getFromSpringFactories(webApplicationType, ApplicationContextFactory::getEnvironmentType, null);\n\t}\n\n\t// Method reference is not detected with correct nullability\n\t@SuppressWarnings(\"NullAway\")\n\t@Override\n\tpublic @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {\n\t\treturn getFromSpringFactories(webApplicationType, ApplicationContextFactory::createEnvironment, null);\n\t}\n\n\t// Method reference is not detected with correct nullability\n\t@SuppressWarnings(\"NullAway\")\n\t@Override\n\tpublic ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) {\n\t\ttry {\n\t\t\treturn getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,\n\t\t\t\t\tthis::createDefaultApplicationContext);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable create a default ApplicationContext instance, \"\n\t\t\t\t\t+ \"you may need a custom ApplicationContextFactory\", ex);\n\t\t}\n\t}\n\n\tprivate ConfigurableApplicationContext createDefaultApplicationContext() {\n\t\tif (!AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn new AnnotationConfigApplicationContext();\n\t\t}\n\t\treturn new GenericApplicationContext();\n\t}\n\n\t@Contract(\"_, _, !null -> !null\")\n\tprivate <T> @Nullable T getFromSpringFactories(@Nullable WebApplicationType webApplicationType,\n\t\t\tBiFunction<ApplicationContextFactory, @Nullable WebApplicationType, @Nullable T> action,\n\t\t\t@Nullable Supplier<T> defaultResult) {\n\t\tfor (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\tT result = action.apply(candidate, webApplicationType);\n\t\t\tif (result != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t\treturn (defaultResult != null) ? defaultResult.get() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/EnvironmentConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.reflect.Constructor;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\n/**\n * Utility class for converting one type of {@link Environment} to another.\n *\n * @author Ethan Rubinson\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nfinal class EnvironmentConverter {\n\n\tprivate static final String CONFIGURABLE_WEB_ENVIRONMENT_CLASS = \"org.springframework.web.context.ConfigurableWebEnvironment\";\n\n\tprivate static final Set<String> SERVLET_ENVIRONMENT_SOURCE_NAMES;\n\n\tstatic {\n\t\tSet<String> names = new HashSet<>();\n\t\tnames.add(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME);\n\t\tnames.add(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME);\n\t\tnames.add(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME);\n\t\tSERVLET_ENVIRONMENT_SOURCE_NAMES = Collections.unmodifiableSet(names);\n\t}\n\n\tprivate final ClassLoader classLoader;\n\n\t/**\n\t * Creates a new {@link EnvironmentConverter} that will use the given\n\t * {@code classLoader} during conversion.\n\t * @param classLoader the class loader to use\n\t */\n\tEnvironmentConverter(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t/**\n\t * Converts the given {@code environment} to the given {@link StandardEnvironment}\n\t * type. If the environment is already of the same type, no conversion is performed\n\t * and it is returned unchanged.\n\t * @param environment the Environment to convert\n\t * @param type the type to convert the Environment to\n\t * @return the converted Environment\n\t */\n\tConfigurableEnvironment convertEnvironmentIfNecessary(ConfigurableEnvironment environment,\n\t\t\tClass<? extends ConfigurableEnvironment> type) {\n\t\tif (type.equals(environment.getClass())) {\n\t\t\treturn environment;\n\t\t}\n\t\treturn convertEnvironment(environment, type);\n\t}\n\n\tprivate ConfigurableEnvironment convertEnvironment(ConfigurableEnvironment environment,\n\t\t\tClass<? extends ConfigurableEnvironment> type) {\n\t\tConfigurableEnvironment result = createEnvironment(type);\n\t\tresult.setActiveProfiles(environment.getActiveProfiles());\n\t\tresult.setConversionService(environment.getConversionService());\n\t\tcopyPropertySources(environment, result);\n\t\treturn result;\n\t}\n\n\tprivate ConfigurableEnvironment createEnvironment(Class<? extends ConfigurableEnvironment> type) {\n\t\ttry {\n\t\t\tConstructor<? extends ConfigurableEnvironment> constructor = type.getDeclaredConstructor();\n\t\t\tReflectionUtils.makeAccessible(constructor);\n\t\t\treturn constructor.newInstance();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn new ApplicationEnvironment();\n\t\t}\n\t}\n\n\tprivate void copyPropertySources(ConfigurableEnvironment source, ConfigurableEnvironment target) {\n\t\tremovePropertySources(target.getPropertySources(), isServletEnvironment(target.getClass(), this.classLoader));\n\t\tfor (PropertySource<?> propertySource : source.getPropertySources()) {\n\t\t\tif (!SERVLET_ENVIRONMENT_SOURCE_NAMES.contains(propertySource.getName())) {\n\t\t\t\ttarget.getPropertySources().addLast(propertySource);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isServletEnvironment(Class<?> conversionType, ClassLoader classLoader) {\n\t\ttry {\n\t\t\tClass<?> webEnvironmentClass = ClassUtils.forName(CONFIGURABLE_WEB_ENVIRONMENT_CLASS, classLoader);\n\t\t\treturn webEnvironmentClass.isAssignableFrom(conversionType);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate void removePropertySources(MutablePropertySources propertySources, boolean isServletEnvironment) {\n\t\tSet<String> names = new HashSet<>();\n\t\tfor (PropertySource<?> propertySource : propertySources) {\n\t\t\tnames.add(propertySource.getName());\n\t\t}\n\t\tfor (String name : names) {\n\t\t\tif (!isServletEnvironment || !SERVLET_ENVIRONMENT_SOURCE_NAMES.contains(name)) {\n\t\t\t\tpropertySources.remove(name);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/EnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\n/**\n * Allows for customization of the application's {@link Environment} prior to the\n * application context being refreshed.\n * <p>\n * EnvironmentPostProcessor implementations have to be registered in\n * {@code META-INF/spring.factories}, using the fully qualified name of this class as the\n * key. Implementations may implement the {@link org.springframework.core.Ordered Ordered}\n * interface or use an {@link org.springframework.core.annotation.Order @Order} annotation\n * if they wish to be invoked in specific order.\n * <p>\n * {@code EnvironmentPostProcessor} implementations may optionally take the following\n * constructor parameters:\n * <ul>\n * <li>{@link DeferredLogFactory} - A factory that can be used to create loggers with\n * output deferred until the application has been fully prepared (allowing the environment\n * itself to configure logging levels).</li>\n * <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to\n * store objects that may be expensive to create, or need to be shared\n * ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>\n * </ul>\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface EnvironmentPostProcessor {\n\n\t/**\n\t * Post-process the given {@code environment}.\n\t * @param environment the environment to post-process\n\t * @param application the application to which the environment belongs\n\t */\n\tvoid postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ExitCodeEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Event fired when an application exit code has been determined from an\n * {@link ExitCodeGenerator}.\n *\n * @author Phillip Webb\n * @since 1.3.2\n */\npublic class ExitCodeEvent extends ApplicationEvent {\n\n\tprivate final int exitCode;\n\n\t/**\n\t * Create a new {@link ExitCodeEvent} instance.\n\t * @param source the source of the event\n\t * @param exitCode the exit code\n\t */\n\tpublic ExitCodeEvent(Object source, int exitCode) {\n\t\tsuper(source);\n\t\tthis.exitCode = exitCode;\n\t}\n\n\t/**\n\t * Return the exit code that will be used to exit the JVM.\n\t * @return the exit code\n\t */\n\tpublic int getExitCode() {\n\t\treturn this.exitCode;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ExitCodeExceptionMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\n/**\n * Strategy interface that can be used to provide a mapping between exceptions and exit\n * codes.\n *\n * @author Phillip Webb\n * @since 1.3.2\n */\n@FunctionalInterface\npublic interface ExitCodeExceptionMapper {\n\n\t/**\n\t * Returns the exit code that should be returned from the application.\n\t * @param exception the exception causing the application to exit\n\t * @return the exit code or {@code 0}.\n\t */\n\tint getExitCode(Throwable exception);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\n/**\n * Interface used to generate an 'exit code' from a running command line\n * {@link SpringApplication}. Can be used on exceptions as well as directly on beans.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see SpringApplication#exit(org.springframework.context.ApplicationContext,\n * ExitCodeGenerator...)\n */\n@FunctionalInterface\npublic interface ExitCodeGenerator {\n\n\t/**\n\t * Returns the exit code that should be returned from the application.\n\t * @return the exit code.\n\t */\n\tint getExitCode();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ExitCodeGenerators.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.Assert;\n\n/**\n * Maintains an ordered collection of {@link ExitCodeGenerator} instances and allows the\n * final exit code to be calculated. Generators are ordered by {@link Order @Order} and\n * {@link Ordered}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author GenKui Du\n * @see #getExitCode()\n * @see ExitCodeGenerator\n */\nclass ExitCodeGenerators implements Iterable<ExitCodeGenerator> {\n\n\tprivate final List<ExitCodeGenerator> generators = new ArrayList<>();\n\n\tvoid addAll(Throwable exception, ExitCodeExceptionMapper... mappers) {\n\t\tAssert.notNull(exception, \"'exception' must not be null\");\n\t\tAssert.notNull(mappers, \"'mappers' must not be null\");\n\t\taddAll(exception, Arrays.asList(mappers));\n\t}\n\n\tvoid addAll(Throwable exception, Iterable<? extends ExitCodeExceptionMapper> mappers) {\n\t\tAssert.notNull(exception, \"'exception' must not be null\");\n\t\tAssert.notNull(mappers, \"'mappers' must not be null\");\n\t\tfor (ExitCodeExceptionMapper mapper : mappers) {\n\t\t\tadd(exception, mapper);\n\t\t}\n\t}\n\n\tvoid add(Throwable exception, ExitCodeExceptionMapper mapper) {\n\t\tAssert.notNull(exception, \"'exception' must not be null\");\n\t\tAssert.notNull(mapper, \"'mapper' must not be null\");\n\t\tadd(new MappedExitCodeGenerator(exception, mapper));\n\t}\n\n\tvoid addAll(ExitCodeGenerator... generators) {\n\t\tAssert.notNull(generators, \"'generators' must not be null\");\n\t\taddAll(Arrays.asList(generators));\n\t}\n\n\tvoid addAll(Iterable<? extends ExitCodeGenerator> generators) {\n\t\tAssert.notNull(generators, \"'generators' must not be null\");\n\t\tfor (ExitCodeGenerator generator : generators) {\n\t\t\tadd(generator);\n\t\t}\n\t}\n\n\tvoid add(ExitCodeGenerator generator) {\n\t\tAssert.notNull(generator, \"'generator' must not be null\");\n\t\tthis.generators.add(generator);\n\t\tAnnotationAwareOrderComparator.sort(this.generators);\n\t}\n\n\t@Override\n\tpublic Iterator<ExitCodeGenerator> iterator() {\n\t\treturn this.generators.iterator();\n\t}\n\n\t/**\n\t * Get the final exit code that should be returned. The final exit code is the first\n\t * non-zero exit code that is {@link ExitCodeGenerator#getExitCode generated}.\n\t * @return the final exit code.\n\t */\n\tint getExitCode() {\n\t\tint exitCode = 0;\n\t\tfor (ExitCodeGenerator generator : this.generators) {\n\t\t\ttry {\n\t\t\t\tint value = generator.getExitCode();\n\t\t\t\tif (value != 0) {\n\t\t\t\t\texitCode = value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\texitCode = 1;\n\t\t\t\tex.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn exitCode;\n\t}\n\n\t/**\n\t * Adapts an {@link ExitCodeExceptionMapper} to an {@link ExitCodeGenerator}.\n\t */\n\tprivate static class MappedExitCodeGenerator implements ExitCodeGenerator {\n\n\t\tprivate final Throwable exception;\n\n\t\tprivate final ExitCodeExceptionMapper mapper;\n\n\t\tMappedExitCodeGenerator(Throwable exception, ExitCodeExceptionMapper mapper) {\n\t\t\tthis.exception = exception;\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getExitCode() {\n\t\t\treturn this.mapper.getExitCode(this.exception);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link BeanFactoryPostProcessor} to set lazy-init on bean definitions that are not\n * {@link LazyInitializationExcludeFilter excluded} and have not already had a value\n * explicitly set.\n * <p>\n * Note that {@link SmartInitializingSingleton SmartInitializingSingletons} are\n * automatically excluded from lazy initialization to ensure that their\n * {@link SmartInitializingSingleton#afterSingletonsInstantiated() callback method} is\n * invoked.\n * <p>\n * Beans that are in the {@link BeanDefinition#ROLE_INFRASTRUCTURE infrastructure role}\n * are automatically excluded from lazy initialization, too.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Tyler Van Gorder\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 2.2.0\n * @see LazyInitializationExcludeFilter\n */\npublic final class LazyInitializationBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {\n\n\t@Override\n\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\tCollection<LazyInitializationExcludeFilter> filters = getFilters(beanFactory);\n\t\tfor (String beanName : beanFactory.getBeanDefinitionNames()) {\n\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n\t\t\tif (beanDefinition instanceof AbstractBeanDefinition abstractBeanDefinition) {\n\t\t\t\tpostProcess(beanFactory, filters, beanName, abstractBeanDefinition);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Collection<LazyInitializationExcludeFilter> getFilters(ConfigurableListableBeanFactory beanFactory) {\n\t\t// Take care not to force the eager init of factory beans when getting filters\n\t\tArrayList<LazyInitializationExcludeFilter> filters = new ArrayList<>(\n\t\t\t\tbeanFactory.getBeansOfType(LazyInitializationExcludeFilter.class, false, false).values());\n\t\tfilters.add(LazyInitializationExcludeFilter.forBeanTypes(SmartInitializingSingleton.class));\n\t\tfilters.add(new InfrastructureRoleLazyInitializationExcludeFilter());\n\t\treturn filters;\n\t}\n\n\tprivate void postProcess(ConfigurableListableBeanFactory beanFactory,\n\t\t\tCollection<LazyInitializationExcludeFilter> filters, String beanName,\n\t\t\tAbstractBeanDefinition beanDefinition) {\n\t\tBoolean lazyInit = beanDefinition.getLazyInit();\n\t\tif (lazyInit != null) {\n\t\t\treturn;\n\t\t}\n\t\tClass<?> beanType = getBeanType(beanFactory, beanName);\n\t\tif (!isExcluded(filters, beanName, beanDefinition, beanType)) {\n\t\t\tbeanDefinition.setLazyInit(true);\n\t\t}\n\t}\n\n\tprivate @Nullable Class<?> getBeanType(ConfigurableListableBeanFactory beanFactory, String beanName) {\n\t\ttry {\n\t\t\treturn beanFactory.getType(beanName, false);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate boolean isExcluded(Collection<LazyInitializationExcludeFilter> filters, String beanName,\n\t\t\tAbstractBeanDefinition beanDefinition, @Nullable Class<?> beanType) {\n\t\tif (beanType != null) {\n\t\t\tfor (LazyInitializationExcludeFilter filter : filters) {\n\t\t\t\tif (filter.isExcluded(beanName, beanDefinition, beanType)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n\t/**\n\t * Excludes all {@link BeanDefinition bean definitions} which have the infrastructure\n\t * role from lazy initialization.\n\t */\n\tprivate static final class InfrastructureRoleLazyInitializationExcludeFilter\n\t\t\timplements LazyInitializationExcludeFilter {\n\n\t\t@Override\n\t\tpublic boolean isExcluded(String beanName, BeanDefinition beanDefinition, Class<?> beanType) {\n\t\t\treturn beanDefinition.getRole() == BeanDefinition.ROLE_INFRASTRUCTURE;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/LazyInitializationExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\n\n/**\n * Filter that can be used to exclude beans definitions from having their\n * {@link AbstractBeanDefinition#setLazyInit(boolean) lazy-init} set by the\n * {@link LazyInitializationBeanFactoryPostProcessor}.\n * <p>\n * Primarily intended to allow downstream projects to deal with edge-cases in which it is\n * not easy to support lazy-loading (such as in DSLs that dynamically create additional\n * beans). Adding an instance of this filter to the application context can be used for\n * these edge cases.\n * <p>\n * A typical example would be something like this: <pre>\n * &#64;Bean\n * public static LazyInitializationExcludeFilter integrationLazyInitializationExcludeFilter() {\n *   return LazyInitializationExcludeFilter.forBeanTypes(IntegrationFlow.class);\n * }\n * </pre>\n * <p>\n * NOTE: Beans of this type will be instantiated very early in the spring application\n * lifecycle so they should generally be declared static and not have any dependencies.\n *\n * @author Tyler Van Gorder\n * @author Philip Webb\n * @since 2.2.0\n */\n@FunctionalInterface\npublic interface LazyInitializationExcludeFilter {\n\n\t/**\n\t * Returns {@code true} if the specified bean definition should be excluded from\n\t * having {@code lazy-init} automatically set.\n\t * @param beanName the bean name\n\t * @param beanDefinition the bean definition\n\t * @param beanType the bean type\n\t * @return {@code true} if {@code lazy-init} should not be automatically set\n\t */\n\tboolean isExcluded(String beanName, BeanDefinition beanDefinition, Class<?> beanType);\n\n\t/**\n\t * Factory method that creates a filter for the given bean types.\n\t * @param types the filtered types\n\t * @return a new filter instance\n\t */\n\tstatic LazyInitializationExcludeFilter forBeanTypes(Class<?>... types) {\n\t\treturn (beanName, beanDefinition, beanType) -> {\n\t\t\tfor (Class<?> type : types) {\n\t\t\t\tif (type.isAssignableFrom(beanType)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.InputStream;\nimport java.io.PrintStream;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ansi.AnsiPropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Banner implementation that prints from a source text {@link Resource}.\n *\n * @author Phillip Webb\n * @author Vedran Pavic\n * @author Toshiaki Maki\n * @author Krzysztof Krason\n * @author Moritz Halbritter\n * @since 1.2.0\n */\npublic class ResourceBanner implements Banner {\n\n\tprivate static final Log logger = LogFactory.getLog(ResourceBanner.class);\n\n\tprivate final Resource resource;\n\n\tpublic ResourceBanner(Resource resource) {\n\t\tAssert.notNull(resource, \"'resource' must not be null\");\n\t\tAssert.isTrue(resource.exists(), \"'resource' must exist\");\n\t\tthis.resource = resource;\n\t}\n\n\t@Override\n\tpublic void printBanner(Environment environment, @Nullable Class<?> sourceClass, PrintStream out) {\n\t\ttry (InputStream input = this.resource.getInputStream()) {\n\t\t\tString banner = StreamUtils.copyToString(input,\n\t\t\t\t\tenvironment.getProperty(\"spring.banner.charset\", Charset.class, StandardCharsets.UTF_8));\n\t\t\tfor (PropertyResolver resolver : getPropertyResolvers(environment, sourceClass)) {\n\t\t\t\tbanner = resolver.resolvePlaceholders(banner);\n\t\t\t}\n\t\t\tout.println(banner);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.warn(LogMessage.format(\"Banner not printable: %s (%s: '%s')\", this.resource, ex.getClass(),\n\t\t\t\t\tex.getMessage()), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Return a mutable list of the {@link PropertyResolver} instances that will be used\n\t * to resolve placeholders.\n\t * @param environment the environment\n\t * @param sourceClass the source class\n\t * @return a mutable list of property resolvers\n\t */\n\tprotected List<PropertyResolver> getPropertyResolvers(Environment environment, @Nullable Class<?> sourceClass) {\n\t\tList<PropertyResolver> resolvers = new ArrayList<>();\n\t\tresolvers.add(new PropertySourcesPropertyResolver(createNullDefaultSources(environment, sourceClass)));\n\t\tresolvers.add(new PropertySourcesPropertyResolver(createEmptyDefaultSources(environment, sourceClass)));\n\t\treturn resolvers;\n\t}\n\n\tprivate MutablePropertySources createNullDefaultSources(Environment environment, @Nullable Class<?> sourceClass) {\n\t\tMutablePropertySources nullDefaultSources = new MutablePropertySources();\n\t\tif (environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\tconfigurableEnvironment.getPropertySources().forEach(nullDefaultSources::addLast);\n\t\t}\n\t\tnullDefaultSources.addLast(getTitleSource(sourceClass, null));\n\t\tnullDefaultSources.addLast(getAnsiSource());\n\t\tnullDefaultSources.addLast(getVersionSource(environment, null));\n\t\treturn nullDefaultSources;\n\t}\n\n\tprivate MutablePropertySources createEmptyDefaultSources(Environment environment, @Nullable Class<?> sourceClass) {\n\t\tMutablePropertySources emptyDefaultSources = new MutablePropertySources();\n\t\temptyDefaultSources.addLast(getTitleSource(sourceClass, \"\"));\n\t\temptyDefaultSources.addLast(getVersionSource(environment, \"\"));\n\t\treturn emptyDefaultSources;\n\t}\n\n\tprivate MapWithNullsPropertySource getTitleSource(@Nullable Class<?> sourceClass, @Nullable String defaultValue) {\n\t\tString applicationTitle = getApplicationTitle(sourceClass);\n\t\tMap<String, @Nullable Object> titleMap = Collections.singletonMap(\"application.title\",\n\t\t\t\t(applicationTitle != null) ? applicationTitle : defaultValue);\n\t\treturn new MapWithNullsPropertySource(\"title\", titleMap);\n\t}\n\n\t/**\n\t * Return the application title that should be used for the source class. By default\n\t * will use {@link Package#getImplementationTitle()}.\n\t * @param sourceClass the source class\n\t * @return the application title\n\t */\n\tprotected @Nullable String getApplicationTitle(@Nullable Class<?> sourceClass) {\n\t\tPackage sourcePackage = (sourceClass != null) ? sourceClass.getPackage() : null;\n\t\treturn (sourcePackage != null) ? sourcePackage.getImplementationTitle() : null;\n\t}\n\n\tprivate AnsiPropertySource getAnsiSource() {\n\t\treturn new AnsiPropertySource(\"ansi\", true);\n\t}\n\n\tprivate MapWithNullsPropertySource getVersionSource(Environment environment, @Nullable String defaultValue) {\n\t\treturn new MapWithNullsPropertySource(\"version\", getVersionsMap(environment, defaultValue));\n\t}\n\n\tprivate Map<String, @Nullable Object> getVersionsMap(Environment environment, @Nullable String defaultValue) {\n\t\tString appVersion = getApplicationVersion(environment);\n\t\tString bootVersion = getBootVersion();\n\t\tMap<String, @Nullable Object> versions = new HashMap<>();\n\t\tversions.put(\"application.version\", getVersionString(appVersion, false, defaultValue));\n\t\tversions.put(\"spring-boot.version\", getVersionString(bootVersion, false, defaultValue));\n\t\tversions.put(\"application.formatted-version\", getVersionString(appVersion, true, defaultValue));\n\t\tversions.put(\"spring-boot.formatted-version\", getVersionString(bootVersion, true, defaultValue));\n\t\treturn versions;\n\t}\n\n\tprivate @Nullable String getApplicationVersion(Environment environment) {\n\t\treturn environment.getProperty(\"spring.application.version\");\n\t}\n\n\tprotected @Nullable String getBootVersion() {\n\t\treturn SpringBootVersion.getVersion();\n\t}\n\n\tprivate @Nullable String getVersionString(@Nullable String version, boolean format, @Nullable String fallback) {\n\t\tif (version == null) {\n\t\t\treturn fallback;\n\t\t}\n\t\treturn format ? \" (v\" + version + \")\" : version;\n\t}\n\n\t/**\n\t * Like {@link MapPropertySource}, but allows {@code null} as map values.\n\t */\n\tprivate static class MapWithNullsPropertySource extends EnumerablePropertySource<Map<String, @Nullable Object>> {\n\n\t\tMapWithNullsPropertySource(String name, Map<String, @Nullable Object> source) {\n\t\t\tsuper(name, source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getPropertyNames() {\n\t\t\treturn StringUtils.toStringArray(this.source.keySet());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\treturn this.source.get(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean containsProperty(String name) {\n\t\t\treturn this.source.containsKey(name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/Runner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\n/**\n * Marker interface for runners.\n *\n * @author Tadaya Tsuyukubo\n * @see ApplicationRunner\n * @see CommandLineRunner\n */\ninterface Runner {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.StackWalker.StackFrame;\nimport java.lang.management.ManagementFactory;\nimport java.lang.reflect.Method;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.IdentityHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.crac.management.CRaCMXBean;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;\nimport org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.beans.factory.xml.XmlBeanDefinitionReader;\nimport org.springframework.boot.Banner.Mode;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.BootstrapRegistryInitializer;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.env.DefaultPropertiesPropertySource;\nimport org.springframework.boot.system.JavaVersion;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.ConfigurationClassPostProcessor;\nimport org.springframework.context.aot.AotApplicationContextInitializer;\nimport org.springframework.context.event.ApplicationContextEvent;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.GenericTypeResolver;\nimport org.springframework.core.NativeDetector;\nimport org.springframework.core.OrderComparator;\nimport org.springframework.core.OrderComparator.OrderSourceProvider;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.CommandLinePropertySource;\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.SimpleCommandLinePropertySource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.core.metrics.ApplicationStartup;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.ThrowingConsumer;\nimport org.springframework.util.function.ThrowingSupplier;\n\n/**\n * Class that can be used to bootstrap and launch a Spring application from a Java main\n * method. By default class will perform the following steps to bootstrap your\n * application:\n *\n * <ul>\n * <li>Create an appropriate {@link ApplicationContext} instance (depending on your\n * classpath)</li>\n * <li>Register a {@link CommandLinePropertySource} to expose command line arguments as\n * Spring properties</li>\n * <li>Refresh the application context, loading all singleton beans</li>\n * <li>Trigger any {@link CommandLineRunner} beans</li>\n * </ul>\n *\n * In most circumstances the static {@link #run(Class, String[])} method can be called\n * directly from your {@literal main} method to bootstrap your application:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * &#064;EnableAutoConfiguration\n * public class MyApplication  {\n *\n *   // ... Bean definitions\n *\n *   public static void main(String[] args) {\n *     SpringApplication.run(MyApplication.class, args);\n *   }\n * }\n * </pre>\n *\n * <p>\n * For more advanced configuration a {@link SpringApplication} instance can be created and\n * customized before being run:\n *\n * <pre class=\"code\">\n * public static void main(String[] args) {\n *   SpringApplication application = new SpringApplication(MyApplication.class);\n *   // ... customize application settings here\n *   application.run(args)\n * }\n * </pre>\n *\n * {@link SpringApplication}s can read beans from a variety of different sources. It is\n * generally recommended that a single {@code @Configuration} class is used to bootstrap\n * your application, however, you may also set {@link #getSources() sources} from:\n * <ul>\n * <li>The fully qualified class name to be loaded by\n * {@link AnnotatedBeanDefinitionReader}</li>\n * <li>The location of an XML resource to be loaded by {@link XmlBeanDefinitionReader}, or\n * a groovy script to be loaded by {@link GroovyBeanDefinitionReader}</li>\n * <li>The name of a package to be scanned by {@link ClassPathBeanDefinitionScanner}</li>\n * </ul>\n *\n * Configuration properties are also bound to the {@link SpringApplication}. This makes it\n * possible to set {@link SpringApplication} properties dynamically, like additional\n * sources (\"spring.main.sources\" - a CSV list) the flag to indicate a web environment\n * (\"spring.main.web-application-type=none\") or the flag to switch off the banner\n * (\"spring.main.banner-mode=off\").\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Christian Dupuis\n * @author Stephane Nicoll\n * @author Jeremy Rickard\n * @author Craig Burke\n * @author Michael Simons\n * @author Madhura Bhave\n * @author Brian Clozel\n * @author Ethan Rubinson\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Tadaya Tsuyukubo\n * @author Lasse Wulff\n * @author Yanming Zhou\n * @since 1.0.0\n * @see #run(Class, String[])\n * @see #run(Class[], String[])\n * @see #SpringApplication(Class...)\n */\npublic class SpringApplication {\n\n\t/**\n\t * Default banner location.\n\t */\n\tpublic static final String BANNER_LOCATION_PROPERTY_VALUE = SpringApplicationBannerPrinter.DEFAULT_BANNER_LOCATION;\n\n\t/**\n\t * Banner location property key.\n\t */\n\tpublic static final String BANNER_LOCATION_PROPERTY = SpringApplicationBannerPrinter.BANNER_LOCATION_PROPERTY;\n\n\tprivate static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = \"java.awt.headless\";\n\n\tprivate static final Log logger = LogFactory.getLog(SpringApplication.class);\n\n\tstatic final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();\n\n\tprivate static final ThreadLocal<SpringApplicationHook> applicationHook = new ThreadLocal<>();\n\n\tprivate final Set<Class<?>> primarySources;\n\n\tprivate @Nullable Class<?> mainApplicationClass;\n\n\tprivate boolean addCommandLineProperties = true;\n\n\tprivate boolean addConversionService = true;\n\n\tprivate @Nullable Banner banner;\n\n\tprivate @Nullable ResourceLoader resourceLoader;\n\n\tprivate @Nullable BeanNameGenerator beanNameGenerator;\n\n\tprivate @Nullable ConfigurableEnvironment environment;\n\n\tprivate boolean headless = true;\n\n\tprivate List<ApplicationContextInitializer<?>> initializers = new ArrayList<>();\n\n\tprivate List<ApplicationListener<?>> listeners = new ArrayList<>();\n\n\tprivate @Nullable Map<String, Object> defaultProperties;\n\n\tprivate final List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;\n\n\tprivate Set<String> additionalProfiles = Collections.emptySet();\n\n\tprivate boolean isCustomEnvironment;\n\n\tprivate @Nullable String environmentPrefix;\n\n\tprivate ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;\n\n\tprivate ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;\n\n\tfinal ApplicationProperties properties = new ApplicationProperties();\n\n\t/**\n\t * Create a new {@link SpringApplication} instance. The application context will load\n\t * beans from the specified primary sources (see {@link SpringApplication class-level}\n\t * documentation for details). The instance can be customized before calling\n\t * {@link #run(String...)}.\n\t * @param primarySources the primary bean sources\n\t * @see #run(Class, String[])\n\t * @see #SpringApplication(ResourceLoader, Class...)\n\t * @see #setSources(Set)\n\t */\n\tpublic SpringApplication(Class<?>... primarySources) {\n\t\tthis(null, primarySources);\n\t}\n\n\t/**\n\t * Create a new {@link SpringApplication} instance. The application context will load\n\t * beans from the specified primary sources (see {@link SpringApplication class-level}\n\t * documentation for details). The instance can be customized before calling\n\t * {@link #run(String...)}.\n\t * @param resourceLoader the resource loader to use\n\t * @param primarySources the primary bean sources\n\t * @see #run(Class, String[])\n\t * @see #setSources(Set)\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic SpringApplication(@Nullable ResourceLoader resourceLoader, Class<?>... primarySources) {\n\t\tthis.resourceLoader = resourceLoader;\n\t\tAssert.notNull(primarySources, \"'primarySources' must not be null\");\n\t\tthis.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));\n\t\tthis.properties.setWebApplicationType(WebApplicationType.deduce());\n\t\tthis.bootstrapRegistryInitializers = new ArrayList<>(\n\t\t\t\tgetSpringFactoriesInstances(BootstrapRegistryInitializer.class));\n\t\tsetInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));\n\t\tsetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));\n\t\tthis.mainApplicationClass = deduceMainApplicationClass();\n\t}\n\n\tprivate @Nullable Class<?> deduceMainApplicationClass() {\n\t\treturn StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)\n\t\t\t.walk(this::findMainClass)\n\t\t\t.orElse(null);\n\t}\n\n\tprivate Optional<Class<?>> findMainClass(Stream<StackFrame> stack) {\n\t\treturn stack.filter((frame) -> Objects.equals(frame.getMethodName(), \"main\"))\n\t\t\t.findFirst()\n\t\t\t.map(StackWalker.StackFrame::getDeclaringClass);\n\t}\n\n\t/**\n\t * Run the Spring application, creating and refreshing a new\n\t * {@link ApplicationContext}.\n\t * @param args the application arguments (usually passed from a Java main method)\n\t * @return a running {@link ApplicationContext}\n\t */\n\tpublic ConfigurableApplicationContext run(String... args) {\n\t\tStartup startup = Startup.create();\n\t\tif (this.properties.isRegisterShutdownHook()) {\n\t\t\tSpringApplication.shutdownHook.enableShutdownHookAddition();\n\t\t}\n\t\tDefaultBootstrapContext bootstrapContext = createBootstrapContext();\n\t\tConfigurableApplicationContext context = null;\n\t\tconfigureHeadlessProperty();\n\t\tSpringApplicationRunListeners listeners = getRunListeners(args);\n\t\tlisteners.starting(bootstrapContext, this.mainApplicationClass);\n\t\ttry {\n\t\t\tApplicationArguments applicationArguments = new DefaultApplicationArguments(args);\n\t\t\tConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);\n\t\t\tBanner printedBanner = printBanner(environment);\n\t\t\tcontext = createApplicationContext();\n\t\t\tcontext.setApplicationStartup(this.applicationStartup);\n\t\t\tprepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);\n\t\t\trefreshContext(context);\n\t\t\tafterRefresh(context, applicationArguments);\n\t\t\tDuration timeTakenToStarted = startup.started();\n\t\t\tif (this.properties.isLogStartupInfo()) {\n\t\t\t\tnew StartupInfoLogger(this.mainApplicationClass, environment).logStarted(getApplicationLog(), startup);\n\t\t\t}\n\t\t\tlisteners.started(context, timeTakenToStarted);\n\t\t\tcallRunners(context, applicationArguments);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow handleRunFailure(context, ex, listeners);\n\t\t}\n\t\ttry {\n\t\t\tif (context.isRunning()) {\n\t\t\t\tlisteners.ready(context, startup.ready());\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow handleRunFailure(context, ex, null);\n\t\t}\n\t\treturn context;\n\t}\n\n\tprivate DefaultBootstrapContext createBootstrapContext() {\n\t\tDefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\t\tthis.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));\n\t\treturn bootstrapContext;\n\t}\n\n\tprivate ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,\n\t\t\tDefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {\n\t\t// Create and configure the environment\n\t\tConfigurableEnvironment environment = getOrCreateEnvironment();\n\t\tconfigureEnvironment(environment, applicationArguments.getSourceArgs());\n\t\tConfigurationPropertySources.attach(environment);\n\t\tlisteners.environmentPrepared(bootstrapContext, environment);\n\t\tApplicationInfoPropertySource.moveToEnd(environment);\n\t\tDefaultPropertiesPropertySource.moveToEnd(environment);\n\t\tAssert.state(!environment.containsProperty(\"spring.main.environment-prefix\"),\n\t\t\t\t\"Environment prefix cannot be set via properties.\");\n\t\tbindToSpringApplication(environment);\n\t\tif (!this.isCustomEnvironment) {\n\t\t\tEnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());\n\t\t\tenvironment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());\n\t\t}\n\t\tConfigurationPropertySources.attach(environment);\n\t\treturn environment;\n\t}\n\n\tprivate Class<? extends ConfigurableEnvironment> deduceEnvironmentClass() {\n\t\tWebApplicationType webApplicationType = this.properties.getWebApplicationType();\n\t\tClass<? extends ConfigurableEnvironment> environmentType = this.applicationContextFactory\n\t\t\t.getEnvironmentType(webApplicationType);\n\t\tif (environmentType == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {\n\t\t\tenvironmentType = ApplicationContextFactory.DEFAULT.getEnvironmentType(webApplicationType);\n\t\t}\n\t\treturn (environmentType != null) ? environmentType : ApplicationEnvironment.class;\n\t}\n\n\tprivate void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,\n\t\t\tConfigurableEnvironment environment, SpringApplicationRunListeners listeners,\n\t\t\tApplicationArguments applicationArguments, @Nullable Banner printedBanner) {\n\t\tcontext.setEnvironment(environment);\n\t\tpostProcessApplicationContext(context);\n\t\taddAotGeneratedInitializerIfNecessary(this.initializers);\n\t\tapplyInitializers(context);\n\t\tlisteners.contextPrepared(context);\n\t\tbootstrapContext.close(context);\n\t\tif (this.properties.isLogStartupInfo()) {\n\t\t\tlogStartupInfo(context);\n\t\t\tlogStartupProfileInfo(context);\n\t\t}\n\t\t// Add boot specific singleton beans\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tbeanFactory.registerSingleton(\"springApplicationArguments\", applicationArguments);\n\t\tif (printedBanner != null) {\n\t\t\tbeanFactory.registerSingleton(\"springBootBanner\", printedBanner);\n\t\t}\n\t\tif (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {\n\t\t\tautowireCapableBeanFactory.setAllowCircularReferences(this.properties.isAllowCircularReferences());\n\t\t\tif (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {\n\t\t\t\tlistableBeanFactory.setAllowBeanDefinitionOverriding(this.properties.isAllowBeanDefinitionOverriding());\n\t\t\t}\n\t\t}\n\t\tif (this.properties.isLazyInitialization()) {\n\t\t\tcontext.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());\n\t\t}\n\t\tif (this.properties.isKeepAlive()) {\n\t\t\tcontext.addApplicationListener(new KeepAlive());\n\t\t}\n\t\tcontext.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));\n\t\tif (!AotDetector.useGeneratedArtifacts()) {\n\t\t\t// Load the sources\n\t\t\tSet<Object> sources = getAllSources();\n\t\t\tAssert.state(!ObjectUtils.isEmpty(sources), \"No sources defined\");\n\t\t\tload(context, sources.toArray(new Object[0]));\n\t\t}\n\t\tlisteners.contextLoaded(context);\n\t}\n\n\tprivate void addAotGeneratedInitializerIfNecessary(List<ApplicationContextInitializer<?>> initializers) {\n\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\tList<ApplicationContextInitializer<?>> aotInitializers = new ArrayList<>(\n\t\t\t\t\tinitializers.stream().filter(AotApplicationContextInitializer.class::isInstance).toList());\n\t\t\tif (aotInitializers.isEmpty()) {\n\t\t\t\tAssert.state(this.mainApplicationClass != null, \"No application main class found\");\n\t\t\t\tString initializerClassName = this.mainApplicationClass.getName() + \"__ApplicationContextInitializer\";\n\t\t\t\tif (!ClassUtils.isPresent(initializerClassName, getClassLoader())) {\n\t\t\t\t\tthrow new AotInitializerNotFoundException(this.mainApplicationClass, initializerClassName);\n\t\t\t\t}\n\t\t\t\taotInitializers.add(AotApplicationContextInitializer.forInitializerClasses(initializerClassName));\n\t\t\t}\n\t\t\tinitializers.removeAll(aotInitializers);\n\t\t\tinitializers.addAll(0, aotInitializers);\n\t\t}\n\t\tif (NativeDetector.inNativeImage()) {\n\t\t\tNativeImageRequirementsException.throwIfNotMet();\n\t\t}\n\t}\n\n\tprivate void refreshContext(ConfigurableApplicationContext context) {\n\t\tif (this.properties.isRegisterShutdownHook()) {\n\t\t\tshutdownHook.registerApplicationContext(context);\n\t\t}\n\t\trefresh(context);\n\t}\n\n\tprivate void configureHeadlessProperty() {\n\t\tSystem.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,\n\t\t\t\tSystem.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));\n\t}\n\n\tprivate SpringApplicationRunListeners getRunListeners(String[] args) {\n\t\tArgumentResolver argumentResolver = ArgumentResolver.of(SpringApplication.class, this);\n\t\targumentResolver = argumentResolver.and(String[].class, args);\n\t\tList<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(SpringApplicationRunListener.class,\n\t\t\t\targumentResolver);\n\t\tSpringApplicationHook hook = applicationHook.get();\n\t\tSpringApplicationRunListener hookListener = (hook != null) ? hook.getRunListener(this) : null;\n\t\tif (hookListener != null) {\n\t\t\tlisteners = new ArrayList<>(listeners);\n\t\t\tlisteners.add(hookListener);\n\t\t}\n\t\treturn new SpringApplicationRunListeners(logger, listeners, this.applicationStartup);\n\t}\n\n\tprivate <T> List<T> getSpringFactoriesInstances(Class<T> type) {\n\t\treturn getSpringFactoriesInstances(type, null);\n\t}\n\n\tprivate <T> List<T> getSpringFactoriesInstances(Class<T> type, @Nullable ArgumentResolver argumentResolver) {\n\t\treturn SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);\n\t}\n\n\tprivate ConfigurableEnvironment getOrCreateEnvironment() {\n\t\tif (this.environment != null) {\n\t\t\treturn this.environment;\n\t\t}\n\t\tWebApplicationType webApplicationType = this.properties.getWebApplicationType();\n\t\tConfigurableEnvironment environment = this.applicationContextFactory.createEnvironment(webApplicationType);\n\t\tif (environment == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {\n\t\t\tenvironment = ApplicationContextFactory.DEFAULT.createEnvironment(webApplicationType);\n\t\t}\n\t\treturn (environment != null) ? environment : new ApplicationEnvironment();\n\t}\n\n\t/**\n\t * Template method delegating to\n\t * {@link #configurePropertySources(ConfigurableEnvironment, String[])} and\n\t * {@link #configureProfiles(ConfigurableEnvironment, String[])} in that order.\n\t * Override this method for complete control over Environment customization, or one of\n\t * the above for fine-grained control over property sources or profiles, respectively.\n\t * @param environment this application's environment\n\t * @param args arguments passed to the {@code run} method\n\t * @see #configureProfiles(ConfigurableEnvironment, String[])\n\t * @see #configurePropertySources(ConfigurableEnvironment, String[])\n\t */\n\tprotected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {\n\t\tif (this.addConversionService) {\n\t\t\tenvironment.setConversionService(new ApplicationConversionService());\n\t\t}\n\t\tconfigurePropertySources(environment, args);\n\t\tconfigureProfiles(environment, args);\n\t}\n\n\t/**\n\t * Add, remove or re-order any {@link PropertySource}s in this application's\n\t * environment.\n\t * @param environment this application's environment\n\t * @param args arguments passed to the {@code run} method\n\t * @see #configureEnvironment(ConfigurableEnvironment, String[])\n\t */\n\tprotected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tif (!CollectionUtils.isEmpty(this.defaultProperties)) {\n\t\t\tDefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);\n\t\t}\n\t\tif (this.addCommandLineProperties && args.length > 0) {\n\t\t\tString name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;\n\t\t\tPropertySource<?> source = sources.get(name);\n\t\t\tif (source != null) {\n\t\t\t\tCompositePropertySource composite = new CompositePropertySource(name);\n\t\t\t\tcomposite\n\t\t\t\t\t.addPropertySource(new SimpleCommandLinePropertySource(\"springApplicationCommandLineArgs\", args));\n\t\t\t\tcomposite.addPropertySource(source);\n\t\t\t\tsources.replace(name, composite);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsources.addFirst(new SimpleCommandLinePropertySource(args));\n\t\t\t}\n\t\t}\n\t\tenvironment.getPropertySources().addLast(new ApplicationInfoPropertySource(this.mainApplicationClass));\n\t}\n\n\t/**\n\t * Configure which profiles are active (or active by default) for this application\n\t * environment. Additional profiles may be activated during configuration file\n\t * processing through the {@code spring.profiles.active} property.\n\t * @param environment this application's environment\n\t * @param args arguments passed to the {@code run} method\n\t * @see #configureEnvironment(ConfigurableEnvironment, String[])\n\t */\n\tprotected void configureProfiles(ConfigurableEnvironment environment, String[] args) {\n\t}\n\n\t/**\n\t * Bind the environment to the {@link ApplicationProperties}.\n\t * @param environment the environment to bind\n\t */\n\tprotected void bindToSpringApplication(ConfigurableEnvironment environment) {\n\t\ttry {\n\t\t\tBinder.get(environment).bind(\"spring.main\", Bindable.ofInstance(this.properties));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Cannot bind to SpringApplication\", ex);\n\t\t}\n\t}\n\n\tprivate @Nullable Banner printBanner(ConfigurableEnvironment environment) {\n\t\tif (this.properties.getBannerMode(environment) == Banner.Mode.OFF) {\n\t\t\treturn null;\n\t\t}\n\t\tResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader\n\t\t\t\t: new DefaultResourceLoader(null);\n\t\tSpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);\n\t\tif (this.properties.getBannerMode(environment) == Mode.LOG) {\n\t\t\treturn bannerPrinter.print(environment, this.mainApplicationClass, logger);\n\t\t}\n\t\treturn bannerPrinter.print(environment, this.mainApplicationClass, System.out);\n\t}\n\n\t/**\n\t * Strategy method used to create the {@link ApplicationContext}. By default this\n\t * method will respect any explicitly set application context class or factory before\n\t * falling back to a suitable default.\n\t * @return the application context (not yet refreshed)\n\t * @see #setApplicationContextFactory(ApplicationContextFactory)\n\t */\n\tprotected ConfigurableApplicationContext createApplicationContext() {\n\t\tConfigurableApplicationContext context = this.applicationContextFactory\n\t\t\t.create(this.properties.getWebApplicationType());\n\t\tAssert.state(context != null, \"ApplicationContextFactory created null context\");\n\t\treturn context;\n\t}\n\n\t/**\n\t * Apply any relevant post-processing to the {@link ApplicationContext}. Subclasses\n\t * can apply additional processing as required.\n\t * @param context the application context\n\t */\n\tprotected void postProcessApplicationContext(ConfigurableApplicationContext context) {\n\t\tif (this.beanNameGenerator != null) {\n\t\t\tcontext.getBeanFactory()\n\t\t\t\t.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator);\n\t\t}\n\t\tif (this.resourceLoader != null) {\n\t\t\tif (context instanceof GenericApplicationContext genericApplicationContext) {\n\t\t\t\tgenericApplicationContext.setResourceLoader(this.resourceLoader);\n\t\t\t}\n\t\t\tif (context instanceof DefaultResourceLoader defaultResourceLoader) {\n\t\t\t\tdefaultResourceLoader.setClassLoader(this.resourceLoader.getClassLoader());\n\t\t\t}\n\t\t}\n\t\tif (this.addConversionService) {\n\t\t\tcontext.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());\n\t\t}\n\t}\n\n\t/**\n\t * Apply any {@link ApplicationContextInitializer}s to the context before it is\n\t * refreshed.\n\t * @param context the configured ApplicationContext (not refreshed yet)\n\t * @see ConfigurableApplicationContext#refresh()\n\t */\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprotected void applyInitializers(ConfigurableApplicationContext context) {\n\t\tfor (ApplicationContextInitializer initializer : getInitializers()) {\n\t\t\tClass<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),\n\t\t\t\t\tApplicationContextInitializer.class);\n\t\t\tAssert.state(requiredType != null,\n\t\t\t\t\t() -> \"No generic type found for initializr of type \" + initializer.getClass());\n\t\t\tAssert.state(requiredType.isInstance(context), \"Unable to call initializer\");\n\t\t\tinitializer.initialize(context);\n\t\t}\n\t}\n\n\t/**\n\t * Called to log startup information, subclasses may override to add additional\n\t * logging.\n\t * @param context the application context\n\t * @since 3.4.0\n\t */\n\tprotected void logStartupInfo(ConfigurableApplicationContext context) {\n\t\tboolean isRoot = context.getParent() == null;\n\t\tif (isRoot) {\n\t\t\tnew StartupInfoLogger(this.mainApplicationClass, context.getEnvironment()).logStarting(getApplicationLog());\n\t\t}\n\t}\n\n\t/**\n\t * Called to log active profile information.\n\t * @param context the application context\n\t */\n\tprotected void logStartupProfileInfo(ConfigurableApplicationContext context) {\n\t\tLog log = getApplicationLog();\n\t\tif (log.isInfoEnabled()) {\n\t\t\tList<String> activeProfiles = quoteProfiles(context.getEnvironment().getActiveProfiles());\n\t\t\tif (ObjectUtils.isEmpty(activeProfiles)) {\n\t\t\t\tList<String> defaultProfiles = quoteProfiles(context.getEnvironment().getDefaultProfiles());\n\t\t\t\tString message = String.format(\"%s default %s: \", defaultProfiles.size(),\n\t\t\t\t\t\t(defaultProfiles.size() <= 1) ? \"profile\" : \"profiles\");\n\t\t\t\tlog.info(\"No active profile set, falling back to \" + message\n\t\t\t\t\t\t+ StringUtils.collectionToDelimitedString(defaultProfiles, \", \"));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tString message = (activeProfiles.size() == 1) ? \"1 profile is active: \"\n\t\t\t\t\t\t: activeProfiles.size() + \" profiles are active: \";\n\t\t\t\tlog.info(\"The following \" + message + StringUtils.collectionToDelimitedString(activeProfiles, \", \"));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate List<String> quoteProfiles(String[] profiles) {\n\t\treturn Arrays.stream(profiles).map((profile) -> \"\\\"\" + profile + \"\\\"\").toList();\n\t}\n\n\t/**\n\t * Returns the {@link Log} for the application. By default will be deduced.\n\t * @return the application log\n\t */\n\tprotected Log getApplicationLog() {\n\t\tif (this.mainApplicationClass == null) {\n\t\t\treturn logger;\n\t\t}\n\t\treturn LogFactory.getLog(this.mainApplicationClass);\n\t}\n\n\t/**\n\t * Load beans into the application context.\n\t * @param context the context to load beans into\n\t * @param sources the sources to load\n\t */\n\tprotected void load(ApplicationContext context, Object[] sources) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Loading source \" + StringUtils.arrayToCommaDelimitedString(sources));\n\t\t}\n\t\tBeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);\n\t\tif (this.beanNameGenerator != null) {\n\t\t\tloader.setBeanNameGenerator(this.beanNameGenerator);\n\t\t}\n\t\tif (this.resourceLoader != null) {\n\t\t\tloader.setResourceLoader(this.resourceLoader);\n\t\t}\n\t\tif (this.environment != null) {\n\t\t\tloader.setEnvironment(this.environment);\n\t\t}\n\t\tloader.load();\n\t}\n\n\t/**\n\t * The ResourceLoader that will be used in the ApplicationContext.\n\t * @return the resourceLoader the resource loader that will be used in the\n\t * ApplicationContext (or {@code null} if the default)\n\t */\n\tpublic @Nullable ResourceLoader getResourceLoader() {\n\t\treturn this.resourceLoader;\n\t}\n\n\t/**\n\t * Either the ClassLoader that will be used in the ApplicationContext (if\n\t * {@link #setResourceLoader(ResourceLoader) resourceLoader} is set), or the context\n\t * class loader (if not null), or the loader of the Spring {@link ClassUtils} class.\n\t * @return a ClassLoader (never null)\n\t */\n\tpublic ClassLoader getClassLoader() {\n\t\tif (this.resourceLoader != null) {\n\t\t\tClassLoader classLoader = this.resourceLoader.getClassLoader();\n\t\t\tAssert.state(classLoader != null, \"No classloader found\");\n\t\t\treturn classLoader;\n\t\t}\n\t\tClassLoader classLoader = ClassUtils.getDefaultClassLoader();\n\t\tAssert.state(classLoader != null, \"No classloader found\");\n\t\treturn classLoader;\n\t}\n\n\t/**\n\t * Get the bean definition registry.\n\t * @param context the application context\n\t * @return the BeanDefinitionRegistry if it can be determined\n\t */\n\tprivate BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {\n\t\tif (context instanceof BeanDefinitionRegistry registry) {\n\t\t\treturn registry;\n\t\t}\n\t\tif (context instanceof AbstractApplicationContext abstractApplicationContext) {\n\t\t\treturn (BeanDefinitionRegistry) abstractApplicationContext.getBeanFactory();\n\t\t}\n\t\tthrow new IllegalStateException(\"Could not locate BeanDefinitionRegistry\");\n\t}\n\n\t/**\n\t * Factory method used to create the {@link BeanDefinitionLoader}.\n\t * @param registry the bean definition registry\n\t * @param sources the sources to load\n\t * @return the {@link BeanDefinitionLoader} that will be used to load beans\n\t */\n\tprotected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {\n\t\treturn new BeanDefinitionLoader(registry, sources);\n\t}\n\n\t/**\n\t * Refresh the underlying {@link ApplicationContext}.\n\t * @param applicationContext the application context to refresh\n\t */\n\tprotected void refresh(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.refresh();\n\t}\n\n\t/**\n\t * Called after the context has been refreshed.\n\t * @param context the application context\n\t * @param args the application arguments\n\t */\n\tprotected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {\n\t}\n\n\tprivate void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) {\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tString[] beanNames = beanFactory.getBeanNamesForType(Runner.class);\n\t\tMap<Runner, String> instancesToBeanNames = new IdentityHashMap<>();\n\t\tfor (String beanName : beanNames) {\n\t\t\tinstancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName);\n\t\t}\n\t\tComparator<Object> comparator = getOrderComparator(beanFactory)\n\t\t\t.withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames));\n\t\tinstancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args));\n\t}\n\n\tprivate OrderComparator getOrderComparator(ConfigurableListableBeanFactory beanFactory) {\n\t\tComparator<?> dependencyComparator = (beanFactory instanceof DefaultListableBeanFactory defaultListableBeanFactory)\n\t\t\t\t? defaultListableBeanFactory.getDependencyComparator() : null;\n\t\treturn (dependencyComparator instanceof OrderComparator orderComparator) ? orderComparator\n\t\t\t\t: AnnotationAwareOrderComparator.INSTANCE;\n\t}\n\n\tprivate void callRunner(Runner runner, ApplicationArguments args) {\n\t\tif (runner instanceof ApplicationRunner) {\n\t\t\tcallRunner(ApplicationRunner.class, runner, (applicationRunner) -> applicationRunner.run(args));\n\t\t}\n\t\tif (runner instanceof CommandLineRunner) {\n\t\t\tcallRunner(CommandLineRunner.class, runner,\n\t\t\t\t\t(commandLineRunner) -> commandLineRunner.run(args.getSourceArgs()));\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <R extends Runner> void callRunner(Class<R> type, Runner runner, ThrowingConsumer<R> call) {\n\t\tcall.throwing(\n\t\t\t\t(message, ex) -> new IllegalStateException(\"Failed to execute \" + ClassUtils.getShortName(type), ex))\n\t\t\t.accept((R) runner);\n\t}\n\n\tprivate RuntimeException handleRunFailure(@Nullable ConfigurableApplicationContext context, Throwable exception,\n\t\t\t@Nullable SpringApplicationRunListeners listeners) {\n\t\tif (exception instanceof AbandonedRunException abandonedRunException) {\n\t\t\treturn abandonedRunException;\n\t\t}\n\t\ttry {\n\t\t\ttry {\n\t\t\t\thandleExitCode(context, exception);\n\t\t\t\tif (listeners != null) {\n\t\t\t\t\tlisteners.failed(context, exception);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\treportFailure(getExceptionReporters(context), exception);\n\t\t\t\tif (context != null) {\n\t\t\t\t\tcontext.close();\n\t\t\t\t\tshutdownHook.deregisterFailedApplicationContext(context);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.warn(\"Unable to close ApplicationContext\", ex);\n\t\t}\n\t\treturn (exception instanceof RuntimeException runtimeException) ? runtimeException\n\t\t\t\t: new IllegalStateException(exception);\n\t}\n\n\tprivate Collection<SpringBootExceptionReporter> getExceptionReporters(\n\t\t\t@Nullable ConfigurableApplicationContext context) {\n\t\ttry {\n\t\t\tArgumentResolver argumentResolver = (context != null)\n\t\t\t\t\t? ArgumentResolver.of(ConfigurableApplicationContext.class, context) : ArgumentResolver.none();\n\t\t\treturn getSpringFactoriesInstances(SpringBootExceptionReporter.class, argumentResolver);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t}\n\n\tprivate void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters, Throwable failure) {\n\t\ttry {\n\t\t\tfor (SpringBootExceptionReporter reporter : exceptionReporters) {\n\t\t\t\tif (reporter.reportException(failure)) {\n\t\t\t\t\tregisterLoggedException(failure);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Continue with normal handling of the original failure\n\t\t}\n\t\tif (logger.isErrorEnabled()) {\n\t\t\tif (NativeDetector.inNativeImage()) {\n\t\t\t\t// Depending on how early the failure was, logging may not work in a\n\t\t\t\t// native image so we output the stack trace directly to System.out\n\t\t\t\t// instead.\n\t\t\t\tSystem.out.println(\"Application run failed\");\n\t\t\t\tfailure.printStackTrace(System.out);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.error(\"Application run failed\", failure);\n\t\t\t}\n\t\t\tregisterLoggedException(failure);\n\t\t}\n\t}\n\n\t/**\n\t * Register that the given exception has been logged. By default, if the running in\n\t * the main thread, this method will suppress additional printing of the stacktrace.\n\t * @param exception the exception that was logged\n\t */\n\tprotected void registerLoggedException(Throwable exception) {\n\t\tSpringBootExceptionHandler handler = getSpringBootExceptionHandler();\n\t\tif (handler != null) {\n\t\t\thandler.registerLoggedException(exception);\n\t\t}\n\t}\n\n\tprivate void handleExitCode(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\tint exitCode = getExitCodeFromException(context, exception);\n\t\tif (exitCode != 0) {\n\t\t\tif (context != null) {\n\t\t\t\tcontext.publishEvent(new ExitCodeEvent(context, exitCode));\n\t\t\t}\n\t\t\tSpringBootExceptionHandler handler = getSpringBootExceptionHandler();\n\t\t\tif (handler != null) {\n\t\t\t\thandler.registerExitCode(exitCode);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate int getExitCodeFromException(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\tint exitCode = getExitCodeFromMappedException(context, exception);\n\t\tif (exitCode == 0) {\n\t\t\texitCode = getExitCodeFromExitCodeGeneratorException(exception);\n\t\t}\n\t\treturn exitCode;\n\t}\n\n\tprivate int getExitCodeFromMappedException(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\tif (context == null || !context.isActive()) {\n\t\t\treturn 0;\n\t\t}\n\t\tExitCodeGenerators generators = new ExitCodeGenerators();\n\t\tCollection<ExitCodeExceptionMapper> beans = context.getBeansOfType(ExitCodeExceptionMapper.class).values();\n\t\tgenerators.addAll(exception, beans);\n\t\treturn generators.getExitCode();\n\t}\n\n\tprivate int getExitCodeFromExitCodeGeneratorException(@Nullable Throwable exception) {\n\t\tif (exception == null) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (exception instanceof ExitCodeGenerator generator) {\n\t\t\treturn generator.getExitCode();\n\t\t}\n\t\treturn getExitCodeFromExitCodeGeneratorException(exception.getCause());\n\t}\n\n\t@Nullable SpringBootExceptionHandler getSpringBootExceptionHandler() {\n\t\tif (isMainThread(Thread.currentThread())) {\n\t\t\treturn SpringBootExceptionHandler.forCurrentThread();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isMainThread(Thread currentThread) {\n\t\treturn (\"main\".equals(currentThread.getName()) || \"restartedMain\".equals(currentThread.getName()))\n\t\t\t\t&& \"main\".equals(currentThread.getThreadGroup().getName());\n\t}\n\n\t/**\n\t * Returns the main application class that has been deduced or explicitly configured.\n\t * @return the main application class or {@code null}\n\t */\n\tpublic @Nullable Class<?> getMainApplicationClass() {\n\t\treturn this.mainApplicationClass;\n\t}\n\n\t/**\n\t * Set a specific main application class that will be used as a log source and to\n\t * obtain version information. By default the main application class will be deduced.\n\t * Can be set to {@code null} if there is no explicit application class.\n\t * @param mainApplicationClass the mainApplicationClass to set or {@code null}\n\t */\n\tpublic void setMainApplicationClass(@Nullable Class<?> mainApplicationClass) {\n\t\tthis.mainApplicationClass = mainApplicationClass;\n\t}\n\n\t/**\n\t * Returns the type of web application that is being run.\n\t * @return the type of web application\n\t * @since 2.0.0\n\t */\n\tpublic @Nullable WebApplicationType getWebApplicationType() {\n\t\treturn this.properties.getWebApplicationType();\n\t}\n\n\t/**\n\t * Sets the type of web application to be run. If not explicitly set the type of web\n\t * application will be deduced based on the classpath.\n\t * @param webApplicationType the web application type\n\t * @since 2.0.0\n\t */\n\tpublic void setWebApplicationType(WebApplicationType webApplicationType) {\n\t\tAssert.notNull(webApplicationType, \"'webApplicationType' must not be null\");\n\t\tthis.properties.setWebApplicationType(webApplicationType);\n\t}\n\n\t/**\n\t * Sets if bean definition overriding, by registering a definition with the same name\n\t * as an existing definition, should be allowed. Defaults to {@code false}.\n\t * @param allowBeanDefinitionOverriding if overriding is allowed\n\t * @since 2.1.0\n\t * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean)\n\t */\n\tpublic void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {\n\t\tthis.properties.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding);\n\t}\n\n\t/**\n\t * Sets whether to allow circular references between beans and automatically try to\n\t * resolve them. Defaults to {@code false}.\n\t * @param allowCircularReferences if circular references are allowed\n\t * @since 2.6.0\n\t * @see AbstractAutowireCapableBeanFactory#setAllowCircularReferences(boolean)\n\t */\n\tpublic void setAllowCircularReferences(boolean allowCircularReferences) {\n\t\tthis.properties.setAllowCircularReferences(allowCircularReferences);\n\t}\n\n\t/**\n\t * Sets if beans should be initialized lazily. Defaults to {@code false}.\n\t * @param lazyInitialization if initialization should be lazy\n\t * @since 2.2\n\t * @see BeanDefinition#setLazyInit(boolean)\n\t */\n\tpublic void setLazyInitialization(boolean lazyInitialization) {\n\t\tthis.properties.setLazyInitialization(lazyInitialization);\n\t}\n\n\t/**\n\t * Sets if the application is headless and should not instantiate AWT. Defaults to\n\t * {@code true} to prevent java icons appearing.\n\t * @param headless if the application is headless\n\t */\n\tpublic void setHeadless(boolean headless) {\n\t\tthis.headless = headless;\n\t}\n\n\t/**\n\t * Sets if the created {@link ApplicationContext} should have a shutdown hook\n\t * registered. Defaults to {@code true} to ensure that JVM shutdowns are handled\n\t * gracefully.\n\t * @param registerShutdownHook if the shutdown hook should be registered\n\t * @see #getShutdownHandlers()\n\t */\n\tpublic void setRegisterShutdownHook(boolean registerShutdownHook) {\n\t\tthis.properties.setRegisterShutdownHook(registerShutdownHook);\n\t}\n\n\t/**\n\t * Sets the {@link Banner} instance which will be used to print the banner when no\n\t * static banner file is provided.\n\t * @param banner the Banner instance to use\n\t */\n\tpublic void setBanner(Banner banner) {\n\t\tthis.banner = banner;\n\t}\n\n\t/**\n\t * Sets the mode used to display the banner when the application runs. Defaults to\n\t * {@code Banner.Mode.CONSOLE}.\n\t * @param bannerMode the mode used to display the banner\n\t */\n\tpublic void setBannerMode(Banner.Mode bannerMode) {\n\t\tthis.properties.setBannerMode(bannerMode);\n\t}\n\n\t/**\n\t * Sets if the application information should be logged when the application starts.\n\t * Defaults to {@code true}.\n\t * @param logStartupInfo if startup info should be logged.\n\t */\n\tpublic void setLogStartupInfo(boolean logStartupInfo) {\n\t\tthis.properties.setLogStartupInfo(logStartupInfo);\n\t}\n\n\t/**\n\t * Sets if a {@link CommandLinePropertySource} should be added to the application\n\t * context in order to expose arguments. Defaults to {@code true}.\n\t * @param addCommandLineProperties if command line arguments should be exposed\n\t */\n\tpublic void setAddCommandLineProperties(boolean addCommandLineProperties) {\n\t\tthis.addCommandLineProperties = addCommandLineProperties;\n\t}\n\n\t/**\n\t * Sets if the {@link ApplicationConversionService} should be added to the application\n\t * context's {@link Environment}.\n\t * @param addConversionService if the application conversion service should be added\n\t * @since 2.1.0\n\t */\n\tpublic void setAddConversionService(boolean addConversionService) {\n\t\tthis.addConversionService = addConversionService;\n\t}\n\n\t/**\n\t * Adds {@link BootstrapRegistryInitializer} instances that can be used to initialize\n\t * the {@link BootstrapRegistry}.\n\t * @param bootstrapRegistryInitializer the bootstrap registry initializer to add\n\t * @since 2.4.5\n\t */\n\tpublic void addBootstrapRegistryInitializer(BootstrapRegistryInitializer bootstrapRegistryInitializer) {\n\t\tAssert.notNull(bootstrapRegistryInitializer, \"'bootstrapRegistryInitializer' must not be null\");\n\t\tthis.bootstrapRegistryInitializers.addAll(Arrays.asList(bootstrapRegistryInitializer));\n\t}\n\n\t/**\n\t * Set default environment properties which will be used in addition to those in the\n\t * existing {@link Environment}.\n\t * @param defaultProperties the additional properties to set\n\t */\n\tpublic void setDefaultProperties(Map<String, Object> defaultProperties) {\n\t\tthis.defaultProperties = defaultProperties;\n\t}\n\n\t/**\n\t * Convenient alternative to {@link #setDefaultProperties(Map)}.\n\t * @param defaultProperties some {@link Properties}\n\t */\n\tpublic void setDefaultProperties(Properties defaultProperties) {\n\t\tthis.defaultProperties = new HashMap<>();\n\t\tfor (Object key : Collections.list(defaultProperties.propertyNames())) {\n\t\t\tthis.defaultProperties.put((String) key, defaultProperties.get(key));\n\t\t}\n\t}\n\n\t/**\n\t * Set additional profile values to use (on top of those set in system or command line\n\t * properties).\n\t * @param profiles the additional profiles to set\n\t */\n\tpublic void setAdditionalProfiles(String... profiles) {\n\t\tthis.additionalProfiles = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(profiles)));\n\t}\n\n\t/**\n\t * Return an immutable set of any additional profiles in use.\n\t * @return the additional profiles\n\t */\n\tpublic Set<String> getAdditionalProfiles() {\n\t\treturn this.additionalProfiles;\n\t}\n\n\t/**\n\t * Sets the bean name generator that should be used when generating bean names.\n\t * @param beanNameGenerator the bean name generator\n\t */\n\tpublic void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {\n\t\tthis.beanNameGenerator = beanNameGenerator;\n\t}\n\n\t/**\n\t * Sets the underlying environment that should be used with the created application\n\t * context.\n\t * @param environment the environment\n\t */\n\tpublic void setEnvironment(@Nullable ConfigurableEnvironment environment) {\n\t\tthis.isCustomEnvironment = true;\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * Add additional items to the primary sources that will be added to an\n\t * ApplicationContext when {@link #run(String...)} is called.\n\t * <p>\n\t * The sources here are added to those that were set in the constructor. Most users\n\t * should consider using {@link #getSources()}/{@link #setSources(Set)} rather than\n\t * calling this method.\n\t * @param additionalPrimarySources the additional primary sources to add\n\t * @see #SpringApplication(Class...)\n\t * @see #getSources()\n\t * @see #setSources(Set)\n\t * @see #getAllSources()\n\t */\n\tpublic void addPrimarySources(Collection<Class<?>> additionalPrimarySources) {\n\t\tthis.primarySources.addAll(additionalPrimarySources);\n\t}\n\n\t/**\n\t * Returns a mutable set of the sources that will be added to an ApplicationContext\n\t * when {@link #run(String...)} is called.\n\t * <p>\n\t * Sources set here will be used in addition to any primary sources set in the\n\t * constructor.\n\t * @return the application sources.\n\t * @see #SpringApplication(Class...)\n\t * @see #getAllSources()\n\t */\n\tpublic Set<String> getSources() {\n\t\treturn this.properties.getSources();\n\t}\n\n\t/**\n\t * Set additional sources that will be used to create an ApplicationContext. A source\n\t * can be: a class name, package name, or an XML resource location.\n\t * <p>\n\t * Sources set here will be used in addition to any primary sources set in the\n\t * constructor.\n\t * @param sources the application sources to set\n\t * @see #SpringApplication(Class...)\n\t * @see #getAllSources()\n\t */\n\tpublic void setSources(Set<String> sources) {\n\t\tAssert.notNull(sources, \"'sources' must not be null\");\n\t\tthis.properties.setSources(sources);\n\t}\n\n\t/**\n\t * Return an immutable set of all the sources that will be added to an\n\t * ApplicationContext when {@link #run(String...)} is called. This method combines any\n\t * primary sources specified in the constructor with any additional ones that have\n\t * been {@link #setSources(Set) explicitly set}.\n\t * @return an immutable set of all sources\n\t */\n\tpublic Set<Object> getAllSources() {\n\t\tSet<Object> allSources = new LinkedHashSet<>();\n\t\tif (!CollectionUtils.isEmpty(this.primarySources)) {\n\t\t\tallSources.addAll(this.primarySources);\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.properties.getSources())) {\n\t\t\tallSources.addAll(this.properties.getSources());\n\t\t}\n\t\treturn Collections.unmodifiableSet(allSources);\n\t}\n\n\t/**\n\t * Sets the {@link ResourceLoader} that should be used when loading resources.\n\t * @param resourceLoader the resource loader\n\t */\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t/**\n\t * Return a prefix that should be applied when obtaining configuration properties from\n\t * the system environment.\n\t * @return the environment property prefix\n\t * @since 2.5.0\n\t */\n\tpublic @Nullable String getEnvironmentPrefix() {\n\t\treturn this.environmentPrefix;\n\t}\n\n\t/**\n\t * Set the prefix that should be applied when obtaining configuration properties from\n\t * the system environment.\n\t * @param environmentPrefix the environment property prefix to set\n\t * @since 2.5.0\n\t */\n\tpublic void setEnvironmentPrefix(String environmentPrefix) {\n\t\tthis.environmentPrefix = environmentPrefix;\n\t}\n\n\t/**\n\t * Sets the factory that will be called to create the application context. If not set,\n\t * defaults to a factory that will create a context that is appropriate for the\n\t * application's type (a reactive web application, a servlet web application, or a\n\t * non-web application).\n\t * @param applicationContextFactory the factory for the context\n\t * @since 2.4.0\n\t */\n\tpublic void setApplicationContextFactory(@Nullable ApplicationContextFactory applicationContextFactory) {\n\t\tthis.applicationContextFactory = (applicationContextFactory != null) ? applicationContextFactory\n\t\t\t\t: ApplicationContextFactory.DEFAULT;\n\t}\n\n\t/**\n\t * Sets the {@link ApplicationContextInitializer} that will be applied to the Spring\n\t * {@link ApplicationContext}.\n\t * @param initializers the initializers to set\n\t */\n\tpublic void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {\n\t\tthis.initializers = new ArrayList<>(initializers);\n\t}\n\n\t/**\n\t * Add {@link ApplicationContextInitializer}s to be applied to the Spring\n\t * {@link ApplicationContext}.\n\t * @param initializers the initializers to add\n\t */\n\tpublic void addInitializers(ApplicationContextInitializer<?>... initializers) {\n\t\tthis.initializers.addAll(Arrays.asList(initializers));\n\t}\n\n\t/**\n\t * Returns read-only ordered Set of the {@link ApplicationContextInitializer}s that\n\t * will be applied to the Spring {@link ApplicationContext}.\n\t * @return the initializers\n\t */\n\tpublic Set<ApplicationContextInitializer<?>> getInitializers() {\n\t\treturn asUnmodifiableOrderedSet(this.initializers);\n\t}\n\n\t/**\n\t * Sets the {@link ApplicationListener}s that will be applied to the SpringApplication\n\t * and registered with the {@link ApplicationContext}.\n\t * @param listeners the listeners to set\n\t */\n\tpublic void setListeners(Collection<? extends ApplicationListener<?>> listeners) {\n\t\tthis.listeners = new ArrayList<>(listeners);\n\t}\n\n\t/**\n\t * Add {@link ApplicationListener}s to be applied to the SpringApplication and\n\t * registered with the {@link ApplicationContext}.\n\t * @param listeners the listeners to add\n\t */\n\tpublic void addListeners(ApplicationListener<?>... listeners) {\n\t\tthis.listeners.addAll(Arrays.asList(listeners));\n\t}\n\n\t/**\n\t * Returns read-only ordered Set of the {@link ApplicationListener}s that will be\n\t * applied to the SpringApplication and registered with the {@link ApplicationContext}\n\t * .\n\t * @return the listeners\n\t */\n\tpublic Set<ApplicationListener<?>> getListeners() {\n\t\treturn asUnmodifiableOrderedSet(this.listeners);\n\t}\n\n\t/**\n\t * Set the {@link ApplicationStartup} to use for collecting startup metrics.\n\t * @param applicationStartup the application startup to use\n\t * @since 2.4.0\n\t */\n\tpublic void setApplicationStartup(ApplicationStartup applicationStartup) {\n\t\tthis.applicationStartup = (applicationStartup != null) ? applicationStartup : ApplicationStartup.DEFAULT;\n\t}\n\n\t/**\n\t * Returns the {@link ApplicationStartup} used for collecting startup metrics.\n\t * @return the application startup\n\t * @since 2.4.0\n\t */\n\tpublic ApplicationStartup getApplicationStartup() {\n\t\treturn this.applicationStartup;\n\t}\n\n\t/**\n\t * Whether to keep the application alive even if there are no more non-daemon threads.\n\t * @return whether to keep the application alive even if there are no more non-daemon\n\t * threads\n\t * @since 3.2.0\n\t */\n\tpublic boolean isKeepAlive() {\n\t\treturn this.properties.isKeepAlive();\n\t}\n\n\t/**\n\t * Set whether to keep the application alive even if there are no more non-daemon\n\t * threads.\n\t * @param keepAlive whether to keep the application alive even if there are no more\n\t * non-daemon threads\n\t * @since 3.2.0\n\t */\n\tpublic void setKeepAlive(boolean keepAlive) {\n\t\tthis.properties.setKeepAlive(keepAlive);\n\t}\n\n\t/**\n\t * Return a {@link SpringApplicationShutdownHandlers} instance that can be used to add\n\t * or remove handlers that perform actions before the JVM is shutdown.\n\t * @return a {@link SpringApplicationShutdownHandlers} instance\n\t * @since 2.5.1\n\t */\n\tpublic static SpringApplicationShutdownHandlers getShutdownHandlers() {\n\t\treturn shutdownHook.getHandlers();\n\t}\n\n\t/**\n\t * Static helper that can be used to run a {@link SpringApplication} from the\n\t * specified source using default settings.\n\t * @param primarySource the primary source to load\n\t * @param args the application arguments (usually passed from a Java main method)\n\t * @return the running {@link ApplicationContext}\n\t */\n\tpublic static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {\n\t\treturn run(new Class<?>[] { primarySource }, args);\n\t}\n\n\t/**\n\t * Static helper that can be used to run a {@link SpringApplication} from the\n\t * specified sources using default settings and user supplied arguments.\n\t * @param primarySources the primary sources to load\n\t * @param args the application arguments (usually passed from a Java main method)\n\t * @return the running {@link ApplicationContext}\n\t */\n\tpublic static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {\n\t\treturn new SpringApplication(primarySources).run(args);\n\t}\n\n\t/**\n\t * A basic main that can be used to launch an application. This method is useful when\n\t * application sources are defined through a {@literal --spring.main.sources} command\n\t * line argument.\n\t * <p>\n\t * Most developers will want to define their own main method and call the\n\t * {@link #run(Class, String...) run} method instead.\n\t * @param args command line arguments\n\t * @throws Exception if the application cannot be started\n\t * @see SpringApplication#run(Class[], String[])\n\t * @see SpringApplication#run(Class, String...)\n\t */\n\tpublic static void main(String[] args) throws Exception {\n\t\tSpringApplication.run(new Class<?>[0], args);\n\t}\n\n\t/**\n\t * Static helper that can be used to exit a {@link SpringApplication} and obtain a\n\t * code indicating success (0) or otherwise. Does not throw exceptions but should\n\t * print stack traces of any encountered. Applies the specified\n\t * {@link ExitCodeGenerator ExitCodeGenerators} in addition to any Spring beans that\n\t * implement {@link ExitCodeGenerator}. When multiple generators are available, the\n\t * first non-zero exit code is used. Generators are ordered based on their\n\t * {@link Ordered} implementation and {@link Order @Order} annotation.\n\t * @param context the context to close if possible\n\t * @param exitCodeGenerators exit code generators\n\t * @return the outcome (0 if successful)\n\t */\n\tpublic static int exit(ApplicationContext context, ExitCodeGenerator... exitCodeGenerators) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tint exitCode = 0;\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tExitCodeGenerators generators = new ExitCodeGenerators();\n\t\t\t\tCollection<ExitCodeGenerator> beans = context.getBeansOfType(ExitCodeGenerator.class).values();\n\t\t\t\tgenerators.addAll(exitCodeGenerators);\n\t\t\t\tgenerators.addAll(beans);\n\t\t\t\texitCode = generators.getExitCode();\n\t\t\t\tif (exitCode != 0) {\n\t\t\t\t\tcontext.publishEvent(new ExitCodeEvent(context, exitCode));\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tclose(context);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tex.printStackTrace();\n\t\t\texitCode = (exitCode != 0) ? exitCode : 1;\n\t\t}\n\t\treturn exitCode;\n\t}\n\n\t/**\n\t * Create an application from an existing {@code main} method that can run with\n\t * additional {@code @Configuration} or bean classes. This method can be helpful when\n\t * writing a test harness that needs to start an application with additional\n\t * configuration.\n\t * @param main the main method entry point that runs the {@link SpringApplication}\n\t * @return a {@link SpringApplication.Augmented} instance that can be used to add\n\t * configuration and run the application\n\t * @since 3.1.0\n\t * @see #withHook(SpringApplicationHook, Runnable)\n\t */\n\tpublic static SpringApplication.Augmented from(ThrowingConsumer<String[]> main) {\n\t\tAssert.notNull(main, \"'main' must not be null\");\n\t\treturn new Augmented(main, Collections.emptySet(), Collections.emptySet());\n\t}\n\n\t/**\n\t * Perform the given action with the given {@link SpringApplicationHook} attached if\n\t * the action triggers an {@link SpringApplication#run(String...) application run}.\n\t * @param hook the hook to apply\n\t * @param action the action to run\n\t * @since 3.0.0\n\t * @see #withHook(SpringApplicationHook, ThrowingSupplier)\n\t */\n\tpublic static void withHook(SpringApplicationHook hook, Runnable action) {\n\t\twithHook(hook, () -> {\n\t\t\taction.run();\n\t\t\treturn Void.class;\n\t\t});\n\t}\n\n\t/**\n\t * Perform the given action with the given {@link SpringApplicationHook} attached if\n\t * the action triggers an {@link SpringApplication#run(String...) application run}.\n\t * @param <T> the result type\n\t * @param hook the hook to apply\n\t * @param action the action to run\n\t * @return the result of the action\n\t * @since 3.0.0\n\t * @see #withHook(SpringApplicationHook, Runnable)\n\t */\n\tpublic static <T> T withHook(SpringApplicationHook hook, ThrowingSupplier<T> action) {\n\t\tapplicationHook.set(hook);\n\t\ttry {\n\t\t\treturn action.get();\n\t\t}\n\t\tfinally {\n\t\t\tapplicationHook.remove();\n\t\t}\n\t}\n\n\tprivate static void close(ApplicationContext context) {\n\t\tif (context instanceof ConfigurableApplicationContext closable) {\n\t\t\tclosable.close();\n\t\t}\n\t}\n\n\tprivate static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {\n\t\tList<E> list = new ArrayList<>(elements);\n\t\tlist.sort(AnnotationAwareOrderComparator.INSTANCE);\n\t\treturn new LinkedHashSet<>(list);\n\t}\n\n\t/**\n\t * Used to configure and run an augmented {@link SpringApplication} where additional\n\t * configuration should be applied.\n\t *\n\t * @since 3.1.0\n\t */\n\tpublic static class Augmented {\n\n\t\tprivate final ThrowingConsumer<String[]> main;\n\n\t\tprivate final Set<Class<?>> sources;\n\n\t\tprivate final Set<String> additionalProfiles;\n\n\t\tAugmented(ThrowingConsumer<String[]> main, Set<Class<?>> sources, Set<String> additionalProfiles) {\n\t\t\tthis.main = main;\n\t\t\tthis.sources = Set.copyOf(sources);\n\t\t\tthis.additionalProfiles = additionalProfiles;\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link SpringApplication.Augmented} instance with additional\n\t\t * sources that should be applied when the application runs.\n\t\t * @param sources the sources that should be applied\n\t\t * @return a new {@link SpringApplication.Augmented} instance\n\t\t */\n\t\tpublic Augmented with(Class<?>... sources) {\n\t\t\tLinkedHashSet<Class<?>> merged = new LinkedHashSet<>(this.sources);\n\t\t\tmerged.addAll(Arrays.asList(sources));\n\t\t\treturn new Augmented(this.main, merged, this.additionalProfiles);\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link SpringApplication.Augmented} instance with additional\n\t\t * profiles that should be applied when the application runs.\n\t\t * @param profiles the profiles that should be applied\n\t\t * @return a new {@link SpringApplication.Augmented} instance\n\t\t * @since 3.4.0\n\t\t */\n\t\tpublic Augmented withAdditionalProfiles(String... profiles) {\n\t\t\tSet<String> merged = new LinkedHashSet<>(this.additionalProfiles);\n\t\t\tmerged.addAll(Arrays.asList(profiles));\n\t\t\treturn new Augmented(this.main, this.sources, merged);\n\t\t}\n\n\t\t/**\n\t\t * Run the application using the given args.\n\t\t * @param args the main method args\n\t\t * @return the running {@link ApplicationContext}\n\t\t */\n\t\tpublic SpringApplication.Running run(String... args) {\n\t\t\tRunListener runListener = new RunListener();\n\t\t\tSpringApplicationHook hook = new SingleUseSpringApplicationHook((springApplication) -> {\n\t\t\t\tspringApplication.addPrimarySources(this.sources);\n\t\t\t\tspringApplication.setAdditionalProfiles(this.additionalProfiles.toArray(String[]::new));\n\t\t\t\treturn runListener;\n\t\t\t});\n\t\t\twithHook(hook, () -> this.main.accept(args));\n\t\t\treturn runListener;\n\t\t}\n\n\t\t/**\n\t\t * {@link SpringApplicationRunListener} to capture {@link Running} application\n\t\t * details.\n\t\t */\n\t\tprivate static final class RunListener implements SpringApplicationRunListener, Running {\n\n\t\t\tprivate final List<ConfigurableApplicationContext> contexts = Collections\n\t\t\t\t.synchronizedList(new ArrayList<>());\n\n\t\t\t@Override\n\t\t\tpublic void contextLoaded(ConfigurableApplicationContext context) {\n\t\t\t\tthis.contexts.add(context);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\t\t\tList<ConfigurableApplicationContext> rootContexts = this.contexts.stream()\n\t\t\t\t\t.filter((context) -> context.getParent() == null)\n\t\t\t\t\t.toList();\n\t\t\t\tAssert.state(!rootContexts.isEmpty(), \"No root application context located\");\n\t\t\t\tAssert.state(rootContexts.size() == 1, \"No unique root application context located\");\n\t\t\t\treturn rootContexts.get(0);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Provides access to details of a {@link SpringApplication} run using\n\t * {@link Augmented#run(String...)}.\n\t *\n\t * @since 3.1.0\n\t */\n\tpublic interface Running {\n\n\t\t/**\n\t\t * Return the root {@link ConfigurableApplicationContext} of the running\n\t\t * application.\n\t\t * @return the root application context\n\t\t */\n\t\tConfigurableApplicationContext getApplicationContext();\n\n\t}\n\n\t/**\n\t * {@link BeanFactoryPostProcessor} to re-order our property sources below any\n\t * {@code @PropertySource} items added by the {@link ConfigurationClassPostProcessor}.\n\t */\n\tprivate static class PropertySourceOrderingBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tPropertySourceOrderingBeanFactoryPostProcessor(ConfigurableApplicationContext context) {\n\t\t\tthis.context = context;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t\tDefaultPropertiesPropertySource.moveToEnd(this.context.getEnvironment());\n\t\t}\n\n\t}\n\n\t/**\n\t * Exception that can be thrown to silently exit a running {@link SpringApplication}\n\t * without handling run failures.\n\t *\n\t * @since 3.0.0\n\t */\n\tpublic static class AbandonedRunException extends RuntimeException {\n\n\t\tprivate final @Nullable ConfigurableApplicationContext applicationContext;\n\n\t\t/**\n\t\t * Create a new {@link AbandonedRunException} instance.\n\t\t */\n\t\tpublic AbandonedRunException() {\n\t\t\tthis(null);\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link AbandonedRunException} instance with the given application\n\t\t * context.\n\t\t * @param applicationContext the application context that was available when the\n\t\t * run was abandoned\n\t\t */\n\t\tpublic AbandonedRunException(@Nullable ConfigurableApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t/**\n\t\t * Return the application context that was available when the run was abandoned or\n\t\t * {@code null} if no context was available.\n\t\t * @return the application context\n\t\t */\n\t\tpublic @Nullable ConfigurableApplicationContext getApplicationContext() {\n\t\t\treturn this.applicationContext;\n\t\t}\n\n\t}\n\n\t/**\n\t * Exception which is thrown if GraalVM's native-image requirements aren't met.\n\t */\n\tstatic final class NativeImageRequirementsException extends RuntimeException {\n\n\t\tprivate static final JavaVersion MINIMUM_REQUIRED_JAVA_VERSION = JavaVersion.TWENTY_FIVE;\n\n\t\tprivate static final JavaVersion CURRENT_JAVA_VERSION = JavaVersion.getJavaVersion();\n\n\t\tNativeImageRequirementsException(String message) {\n\t\t\tsuper(message);\n\t\t}\n\n\t\tstatic void throwIfNotMet() {\n\t\t\tif (CURRENT_JAVA_VERSION.isOlderThan(MINIMUM_REQUIRED_JAVA_VERSION)) {\n\t\t\t\tthrow new NativeImageRequirementsException(\"Native Image requirements not met. \"\n\t\t\t\t\t\t+ \"Native Image must support at least Java %s but Java %s was detected\"\n\t\t\t\t\t\t\t.formatted(MINIMUM_REQUIRED_JAVA_VERSION, CURRENT_JAVA_VERSION));\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SpringApplicationHook} decorator that ensures the hook is only used once.\n\t */\n\tprivate static final class SingleUseSpringApplicationHook implements SpringApplicationHook {\n\n\t\tprivate final AtomicBoolean used = new AtomicBoolean();\n\n\t\tprivate final SpringApplicationHook delegate;\n\n\t\tprivate SingleUseSpringApplicationHook(SpringApplicationHook delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SpringApplicationRunListener getRunListener(SpringApplication springApplication) {\n\t\t\treturn this.used.compareAndSet(false, true) ? this.delegate.getRunListener(springApplication) : null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Starts a non-daemon thread to keep the JVM alive on {@link ContextRefreshedEvent}.\n\t * Stops the thread on {@link ContextClosedEvent}.\n\t */\n\tprivate static final class KeepAlive implements ApplicationListener<ApplicationContextEvent> {\n\n\t\tprivate final AtomicReference<@Nullable Thread> thread = new AtomicReference<>();\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationContextEvent event) {\n\t\t\tif (event instanceof ContextRefreshedEvent) {\n\t\t\t\tstartKeepAliveThread();\n\t\t\t}\n\t\t\telse if (event instanceof ContextClosedEvent) {\n\t\t\t\tstopKeepAliveThread();\n\t\t\t}\n\t\t}\n\n\t\tprivate void startKeepAliveThread() {\n\t\t\tThread thread = new Thread(() -> {\n\t\t\t\twhile (true) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tThread.sleep(Long.MAX_VALUE);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (this.thread.compareAndSet(null, thread)) {\n\t\t\t\tthread.setDaemon(false);\n\t\t\t\tthread.setName(\"keep-alive\");\n\t\t\t\tthread.start();\n\t\t\t}\n\t\t}\n\n\t\tprivate void stopKeepAliveThread() {\n\t\t\tThread thread = this.thread.getAndSet(null);\n\t\t\tif (thread == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthread.interrupt();\n\t\t}\n\n\t}\n\n\t/**\n\t * Strategy used to handle startup concerns.\n\t */\n\tabstract static class Startup {\n\n\t\tprivate @Nullable Duration timeTakenToStarted;\n\n\t\tprotected abstract long startTime();\n\n\t\tprotected abstract @Nullable Long processUptime();\n\n\t\tprotected abstract String action();\n\n\t\tfinal Duration started() {\n\t\t\tlong now = System.currentTimeMillis();\n\t\t\tthis.timeTakenToStarted = Duration.ofMillis(now - startTime());\n\t\t\treturn this.timeTakenToStarted;\n\t\t}\n\n\t\tDuration timeTakenToStarted() {\n\t\t\tAssert.state(this.timeTakenToStarted != null,\n\t\t\t\t\t\"timeTakenToStarted is not set. Make sure to call started() before this method\");\n\t\t\treturn this.timeTakenToStarted;\n\t\t}\n\n\t\tprivate Duration ready() {\n\t\t\tlong now = System.currentTimeMillis();\n\t\t\treturn Duration.ofMillis(now - startTime());\n\t\t}\n\n\t\tstatic Startup create() {\n\t\t\tClassLoader classLoader = Startup.class.getClassLoader();\n\t\t\treturn (ClassUtils.isPresent(\"jdk.crac.management.CRaCMXBean\", classLoader)\n\t\t\t\t\t&& ClassUtils.isPresent(\"org.crac.management.CRaCMXBean\", classLoader))\n\t\t\t\t\t\t\t? new CoordinatedRestoreAtCheckpointStartup() : new StandardStartup();\n\t\t}\n\n\t}\n\n\t/**\n\t * Standard {@link Startup} implementation.\n\t */\n\tprivate static final class StandardStartup extends Startup {\n\n\t\tprivate final Long startTime = System.currentTimeMillis();\n\n\t\t@Override\n\t\tprotected long startTime() {\n\t\t\treturn this.startTime;\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable Long processUptime() {\n\t\t\ttry {\n\t\t\t\treturn ManagementFactory.getRuntimeMXBean().getUptime();\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected String action() {\n\t\t\treturn \"Started\";\n\t\t}\n\n\t}\n\n\t/**\n\t * Coordinated-Restore-At-Checkpoint {@link Startup} implementation.\n\t */\n\tprivate static final class CoordinatedRestoreAtCheckpointStartup extends Startup {\n\n\t\tprivate final StandardStartup fallback = new StandardStartup();\n\n\t\t@Override\n\t\tprotected @Nullable Long processUptime() {\n\t\t\tLong uptime = CRaCMXBean.getCRaCMXBean().getUptimeSinceRestore();\n\t\t\treturn (uptime >= 0) ? uptime : this.fallback.processUptime();\n\t\t}\n\n\t\t@Override\n\t\tprotected String action() {\n\t\t\treturn (restoreTime() >= 0) ? \"Restored\" : this.fallback.action();\n\t\t}\n\n\t\tprivate long restoreTime() {\n\t\t\treturn CRaCMXBean.getCRaCMXBean().getRestoreTime();\n\t\t}\n\n\t\t@Override\n\t\tprotected long startTime() {\n\t\t\tlong restoreTime = restoreTime();\n\t\t\treturn (restoreTime >= 0) ? restoreTime : this.fallback.startTime();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link OrderSourceProvider} used to obtain factory method and target type order\n\t * sources. Based on internal {@link DefaultListableBeanFactory} code.\n\t */\n\tprivate static class FactoryAwareOrderSourceProvider implements OrderSourceProvider {\n\n\t\tprivate final ConfigurableBeanFactory beanFactory;\n\n\t\tprivate final Map<?, String> instancesToBeanNames;\n\n\t\tFactoryAwareOrderSourceProvider(ConfigurableBeanFactory beanFactory, Map<?, String> instancesToBeanNames) {\n\t\t\tthis.beanFactory = beanFactory;\n\t\t\tthis.instancesToBeanNames = instancesToBeanNames;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getOrderSource(Object obj) {\n\t\t\tString beanName = this.instancesToBeanNames.get(obj);\n\t\t\treturn (beanName != null) ? getOrderSource(beanName, obj.getClass()) : null;\n\t\t}\n\n\t\tprivate @Nullable Object getOrderSource(String beanName, Class<?> instanceType) {\n\t\t\ttry {\n\t\t\t\tRootBeanDefinition beanDefinition = (RootBeanDefinition) this.beanFactory\n\t\t\t\t\t.getMergedBeanDefinition(beanName);\n\t\t\t\tMethod factoryMethod = beanDefinition.getResolvedFactoryMethod();\n\t\t\t\tClass<?> targetType = beanDefinition.getTargetType();\n\t\t\t\ttargetType = (targetType != instanceType) ? targetType : null;\n\t\t\t\treturn Stream.of(factoryMethod, targetType).filter(Objects::nonNull).toArray();\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.reflect.Method;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\n\nimport org.springframework.boot.SpringApplication.AbandonedRunException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.aot.ContextAotProcessor;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.ThrowingSupplier;\n\n/**\n * Entry point for AOT processing of a {@link SpringApplication}.\n * <p>\n * <strong>For internal use only.</strong>\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.0.0\n */\npublic class SpringApplicationAotProcessor extends ContextAotProcessor {\n\n\tprivate final String[] applicationArgs;\n\n\t/**\n\t * Create a new processor for the specified application and settings.\n\t * @param application the application main class\n\t * @param settings the general AOT processor settings\n\t * @param applicationArgs the arguments to provide to the main method\n\t */\n\tpublic SpringApplicationAotProcessor(Class<?> application, Settings settings, String[] applicationArgs) {\n\t\tsuper(application, settings);\n\t\tthis.applicationArgs = applicationArgs;\n\t}\n\n\t@Override\n\tprotected GenericApplicationContext prepareApplicationContext(Class<?> application) {\n\t\treturn new AotProcessorHook(application).run(() -> {\n\t\t\tMethod mainMethod = getMainMethod(application);\n\t\t\tmainMethod.setAccessible(true);\n\t\t\tif (mainMethod.getParameterCount() == 0) {\n\t\t\t\tReflectionUtils.invokeMethod(mainMethod, null);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tReflectionUtils.invokeMethod(mainMethod, null, new Object[] { this.applicationArgs });\n\t\t\t}\n\t\t\treturn Void.class;\n\t\t});\n\t}\n\n\tprivate static Method getMainMethod(Class<?> application) throws Exception {\n\t\ttry {\n\t\t\treturn application.getDeclaredMethod(\"main\", String[].class);\n\t\t}\n\t\tcatch (NoSuchMethodException ex) {\n\t\t\treturn application.getDeclaredMethod(\"main\");\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tint requiredArgs = 6;\n\t\tAssert.state(args.length >= requiredArgs, () -> \"Usage: \" + SpringApplicationAotProcessor.class.getName()\n\t\t\t\t+ \" <applicationMainClass> <sourceOutput> <resourceOutput> <classOutput> <groupId> <artifactId> <originalArgs...>\");\n\t\tClass<?> application = Class.forName(args[0]);\n\t\tSettings settings = Settings.builder()\n\t\t\t.sourceOutput(Paths.get(args[1]))\n\t\t\t.resourceOutput(Paths.get(args[2]))\n\t\t\t.classOutput(Paths.get(args[3]))\n\t\t\t.groupId((StringUtils.hasText(args[4])) ? args[4] : \"unspecified\")\n\t\t\t.artifactId(args[5])\n\t\t\t.build();\n\t\tString[] applicationArgs = (args.length > requiredArgs) ? Arrays.copyOfRange(args, requiredArgs, args.length)\n\t\t\t\t: new String[0];\n\t\tnew SpringApplicationAotProcessor(application, settings, applicationArgs).process();\n\t}\n\n\t/**\n\t * {@link SpringApplicationHook} used to capture the {@link ApplicationContext} and\n\t * trigger early exit of main method.\n\t */\n\tprivate static final class AotProcessorHook implements SpringApplicationHook {\n\n\t\tprivate final Class<?> application;\n\n\t\tprivate AotProcessorHook(Class<?> application) {\n\t\t\tthis.application = application;\n\t\t}\n\n\t\t@Override\n\t\tpublic SpringApplicationRunListener getRunListener(SpringApplication application) {\n\t\t\treturn new SpringApplicationRunListener() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void contextLoaded(ConfigurableApplicationContext context) {\n\t\t\t\t\tthrow new AbandonedRunException(context);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\tprivate <T> GenericApplicationContext run(ThrowingSupplier<T> action) {\n\t\t\ttry {\n\t\t\t\tSpringApplication.withHook(this, action);\n\t\t\t}\n\t\t\tcatch (AbandonedRunException ex) {\n\t\t\t\tApplicationContext context = ex.getApplicationContext();\n\t\t\t\tAssert.state(context instanceof GenericApplicationContext,\n\t\t\t\t\t\t() -> \"AOT processing requires a GenericApplicationContext but got a \"\n\t\t\t\t\t\t\t\t+ ((context != null) ? context.getClass().getName() : \"null\"));\n\t\t\t\treturn (GenericApplicationContext) context;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"No application context available after calling main method of '%s'. Does it run a SpringApplication?\"\n\t\t\t\t\t\t.formatted(this.application.getName()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * Class used by {@link SpringApplication} to print the application banner.\n *\n * @author Phillip Webb\n */\nclass SpringApplicationBannerPrinter {\n\n\tstatic final String BANNER_LOCATION_PROPERTY = \"spring.banner.location\";\n\n\tstatic final String DEFAULT_BANNER_LOCATION = \"banner.txt\";\n\n\tprivate static final Banner DEFAULT_BANNER = new SpringBootBanner();\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final @Nullable Banner fallbackBanner;\n\n\tSpringApplicationBannerPrinter(ResourceLoader resourceLoader, @Nullable Banner fallbackBanner) {\n\t\tthis.resourceLoader = resourceLoader;\n\t\tthis.fallbackBanner = fallbackBanner;\n\t}\n\n\tBanner print(Environment environment, @Nullable Class<?> sourceClass, Log logger) {\n\t\tBanner banner = getBanner(environment);\n\t\ttry {\n\t\t\tlogger.info(createStringFromBanner(banner, environment, sourceClass));\n\t\t}\n\t\tcatch (UnsupportedEncodingException ex) {\n\t\t\tlogger.warn(\"Failed to create String for banner\", ex);\n\t\t}\n\t\treturn new PrintedBanner(banner, sourceClass);\n\t}\n\n\tBanner print(Environment environment, @Nullable Class<?> sourceClass, PrintStream out) {\n\t\tBanner banner = getBanner(environment);\n\t\tbanner.printBanner(environment, sourceClass, out);\n\t\treturn new PrintedBanner(banner, sourceClass);\n\t}\n\n\tprivate Banner getBanner(Environment environment) {\n\t\tBanner textBanner = getTextBanner(environment);\n\t\tif (textBanner != null) {\n\t\t\treturn textBanner;\n\t\t}\n\t\tif (this.fallbackBanner != null) {\n\t\t\treturn this.fallbackBanner;\n\t\t}\n\t\treturn DEFAULT_BANNER;\n\t}\n\n\tprivate @Nullable Banner getTextBanner(Environment environment) {\n\t\tString location = environment.getProperty(BANNER_LOCATION_PROPERTY, DEFAULT_BANNER_LOCATION);\n\t\tResource resource = this.resourceLoader.getResource(location);\n\t\ttry {\n\t\t\tif (resource.exists() && !resource.getURL().toExternalForm().contains(\"liquibase-core\")) {\n\t\t\t\treturn new ResourceBanner(resource);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String createStringFromBanner(Banner banner, Environment environment,\n\t\t\t@Nullable Class<?> mainApplicationClass) throws UnsupportedEncodingException {\n\t\tString charset = environment.getProperty(\"spring.banner.charset\", StandardCharsets.UTF_8.name());\n\t\tByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n\t\ttry (PrintStream out = new PrintStream(byteArrayOutputStream, false, charset)) {\n\t\t\tbanner.printBanner(environment, mainApplicationClass, out);\n\t\t}\n\t\treturn byteArrayOutputStream.toString(charset);\n\t}\n\n\t/**\n\t * Decorator that allows a {@link Banner} to be printed again without needing to\n\t * specify the source class.\n\t */\n\tprivate static class PrintedBanner implements Banner {\n\n\t\tprivate final Banner banner;\n\n\t\tprivate final @Nullable Class<?> sourceClass;\n\n\t\tPrintedBanner(Banner banner, @Nullable Class<?> sourceClass) {\n\t\t\tthis.banner = banner;\n\t\t\tthis.sourceClass = sourceClass;\n\t\t}\n\n\t\t@Override\n\t\tpublic void printBanner(Environment environment, @Nullable Class<?> sourceClass, PrintStream out) {\n\t\t\tsourceClass = (sourceClass != null) ? sourceClass : this.sourceClass;\n\t\t\tthis.banner.printBanner(environment, sourceClass, out);\n\t\t}\n\n\t}\n\n\tstatic class SpringApplicationBannerPrinterRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(DEFAULT_BANNER_LOCATION);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationHook.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Low-level hook that can be used to attach a {@link SpringApplicationRunListener} to a\n * {@link SpringApplication} in order to observe or modify its behavior. Hooks are managed\n * on a per-thread basis providing isolation when multiple applications are executed in\n * parallel.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.0.0\n * @see SpringApplication#withHook\n */\n@FunctionalInterface\npublic interface SpringApplicationHook {\n\n\t/**\n\t * Return the {@link SpringApplicationRunListener} that should be hooked into the\n\t * given {@link SpringApplication}.\n\t * @param springApplication the source {@link SpringApplication} instance\n\t * @return the {@link SpringApplicationRunListener} to attach or {@code null}\n\t */\n\t@Nullable SpringApplicationRunListener getRunListener(SpringApplication springApplication);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * Listener for the {@link SpringApplication} {@code run} method.\n * {@link SpringApplicationRunListener}s are loaded through the\n * {@link SpringFactoriesLoader} and should declare a public constructor that accepts a\n * {@link SpringApplication} instance and a {@code String[]} of arguments. A new\n * {@link SpringApplicationRunListener} instance will be created for each run.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Chris Bono\n * @since 1.0.0\n */\npublic interface SpringApplicationRunListener {\n\n\t/**\n\t * Called immediately when the run method has first started. Can be used for very\n\t * early initialization.\n\t * @param bootstrapContext the bootstrap context\n\t */\n\tdefault void starting(ConfigurableBootstrapContext bootstrapContext) {\n\t}\n\n\t/**\n\t * Called once the environment has been prepared, but before the\n\t * {@link ApplicationContext} has been created.\n\t * @param bootstrapContext the bootstrap context\n\t * @param environment the environment\n\t */\n\tdefault void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,\n\t\t\tConfigurableEnvironment environment) {\n\t}\n\n\t/**\n\t * Called once the {@link ApplicationContext} has been created and prepared, but\n\t * before sources have been loaded.\n\t * @param context the application context\n\t */\n\tdefault void contextPrepared(ConfigurableApplicationContext context) {\n\t}\n\n\t/**\n\t * Called once the application context has been loaded but before it has been\n\t * refreshed.\n\t * @param context the application context\n\t */\n\tdefault void contextLoaded(ConfigurableApplicationContext context) {\n\t}\n\n\t/**\n\t * The context has been refreshed and the application has started but\n\t * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner\n\t * ApplicationRunners} have not been called.\n\t * @param context the application context.\n\t * @param timeTaken the time taken to start the application or {@code null} if unknown\n\t * @since 2.6.0\n\t */\n\tdefault void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {\n\t}\n\n\t/**\n\t * Called immediately before the run method finishes, when the application context has\n\t * been refreshed and all {@link CommandLineRunner CommandLineRunners} and\n\t * {@link ApplicationRunner ApplicationRunners} have been called.\n\t * @param context the application context.\n\t * @param timeTaken the time taken for the application to be ready or {@code null} if\n\t * unknown\n\t * @since 2.6.0\n\t */\n\tdefault void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {\n\t}\n\n\t/**\n\t * Called when a failure occurs when running the application.\n\t * @param context the application context or {@code null} if a failure occurred before\n\t * the context was created\n\t * @param exception the failure\n\t * @since 2.0.0\n\t */\n\tdefault void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationRunListeners.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.metrics.ApplicationStartup;\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * A collection of {@link SpringApplicationRunListener}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Chris Bono\n */\nclass SpringApplicationRunListeners {\n\n\tprivate final Log log;\n\n\tprivate final List<SpringApplicationRunListener> listeners;\n\n\tprivate final ApplicationStartup applicationStartup;\n\n\tSpringApplicationRunListeners(Log log, List<SpringApplicationRunListener> listeners,\n\t\t\tApplicationStartup applicationStartup) {\n\t\tthis.log = log;\n\t\tthis.listeners = List.copyOf(listeners);\n\t\tthis.applicationStartup = applicationStartup;\n\t}\n\n\tvoid starting(ConfigurableBootstrapContext bootstrapContext, @Nullable Class<?> mainApplicationClass) {\n\t\tdoWithListeners(\"spring.boot.application.starting\", (listener) -> listener.starting(bootstrapContext),\n\t\t\t\t(step) -> {\n\t\t\t\t\tif (mainApplicationClass != null) {\n\t\t\t\t\t\tstep.tag(\"mainApplicationClass\", mainApplicationClass.getName());\n\t\t\t\t\t}\n\t\t\t\t});\n\t}\n\n\tvoid environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {\n\t\tdoWithListeners(\"spring.boot.application.environment-prepared\",\n\t\t\t\t(listener) -> listener.environmentPrepared(bootstrapContext, environment));\n\t}\n\n\tvoid contextPrepared(ConfigurableApplicationContext context) {\n\t\tdoWithListeners(\"spring.boot.application.context-prepared\", (listener) -> listener.contextPrepared(context));\n\t}\n\n\tvoid contextLoaded(ConfigurableApplicationContext context) {\n\t\tdoWithListeners(\"spring.boot.application.context-loaded\", (listener) -> listener.contextLoaded(context));\n\t}\n\n\tvoid started(ConfigurableApplicationContext context, Duration timeTaken) {\n\t\tdoWithListeners(\"spring.boot.application.started\", (listener) -> listener.started(context, timeTaken));\n\t}\n\n\tvoid ready(ConfigurableApplicationContext context, Duration timeTaken) {\n\t\tdoWithListeners(\"spring.boot.application.ready\", (listener) -> listener.ready(context, timeTaken));\n\t}\n\n\tvoid failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\tdoWithListeners(\"spring.boot.application.failed\",\n\t\t\t\t(listener) -> callFailedListener(listener, context, exception), (step) -> {\n\t\t\t\t\tstep.tag(\"exception\", exception.getClass().toString());\n\t\t\t\t\tString message = exception.getMessage();\n\t\t\t\t\tif (message != null) {\n\t\t\t\t\t\tstep.tag(\"message\", message);\n\t\t\t\t\t}\n\t\t\t\t});\n\t}\n\n\tprivate void callFailedListener(SpringApplicationRunListener listener,\n\t\t\t@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\ttry {\n\t\t\tlistener.failed(context, exception);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tif (exception == null) {\n\t\t\t\tReflectionUtils.rethrowRuntimeException(ex);\n\t\t\t}\n\t\t\tif (this.log.isDebugEnabled()) {\n\t\t\t\tthis.log.error(\"Error handling failed\", ex);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tString message = ex.getMessage();\n\t\t\t\tmessage = (message != null) ? message : \"no error message\";\n\t\t\t\tthis.log.warn(\"Error handling failed (\" + message + \")\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {\n\t\tdoWithListeners(stepName, listenerAction, null);\n\t}\n\n\tprivate void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,\n\t\t\t@Nullable Consumer<StartupStep> stepAction) {\n\t\tStartupStep step = this.applicationStartup.start(stepName);\n\t\tthis.listeners.forEach(listenerAction);\n\t\tif (stepAction != null) {\n\t\t\tstepAction.accept(step);\n\t\t}\n\t\tstep.end();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHandlers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Interface that can be used to add or remove code that should run when the JVM is\n * shutdown. Shutdown handlers are similar to JVM {@link Runtime#addShutdownHook(Thread)\n * shutdown hooks} except that they run sequentially rather than concurrently.\n * <p>\n * Shutdown handlers are guaranteed to be called only after registered\n * {@link ApplicationContext} instances have been closed and are no longer active.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.5.1\n * @see SpringApplication#getShutdownHandlers()\n * @see SpringApplication#setRegisterShutdownHook(boolean)\n */\npublic interface SpringApplicationShutdownHandlers {\n\n\t/**\n\t * Add an action to the handlers that will be run when the JVM exits.\n\t * @param action the action to add\n\t */\n\tvoid add(Runnable action);\n\n\t/**\n\t * Remove a previously added an action so that it no longer runs when the JVM exits.\n\t * @param action the action to remove\n\t */\n\tvoid remove(Runnable action);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringApplicationShutdownHook.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.WeakHashMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link Runnable} to be used as a {@link Runtime#addShutdownHook(Thread) shutdown\n * hook} to perform graceful shutdown of Spring Boot applications. This hook tracks\n * registered application contexts as well as any actions registered via\n * {@link SpringApplication#getShutdownHandlers()}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Brian Clozel\n */\nclass SpringApplicationShutdownHook implements Runnable {\n\n\tprivate static final int SLEEP = 50;\n\n\tprivate static final long TIMEOUT = TimeUnit.MINUTES.toMillis(10);\n\n\tprivate static final Log logger = LogFactory.getLog(SpringApplicationShutdownHook.class);\n\n\tprivate final Handlers handlers = new Handlers();\n\n\tprivate final Set<ConfigurableApplicationContext> contexts = new LinkedHashSet<>();\n\n\tprivate final Set<ConfigurableApplicationContext> closedContexts = Collections.newSetFromMap(new WeakHashMap<>());\n\n\tprivate final ApplicationContextClosedListener contextCloseListener = new ApplicationContextClosedListener();\n\n\tprivate final AtomicBoolean shutdownHookAdded = new AtomicBoolean();\n\n\tprivate volatile boolean shutdownHookAdditionEnabled;\n\n\tprivate boolean inProgress;\n\n\tSpringApplicationShutdownHandlers getHandlers() {\n\t\treturn this.handlers;\n\t}\n\n\tvoid enableShutdownHookAddition() {\n\t\tthis.shutdownHookAdditionEnabled = true;\n\t}\n\n\tvoid registerApplicationContext(ConfigurableApplicationContext context) {\n\t\taddRuntimeShutdownHookIfNecessary();\n\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\tassertNotInProgress();\n\t\t\tcontext.addApplicationListener(this.contextCloseListener);\n\t\t\tthis.contexts.add(context);\n\t\t}\n\t}\n\n\tprivate void addRuntimeShutdownHookIfNecessary() {\n\t\tif (this.shutdownHookAdditionEnabled && this.shutdownHookAdded.compareAndSet(false, true)) {\n\t\t\taddRuntimeShutdownHook();\n\t\t}\n\t}\n\n\tvoid addRuntimeShutdownHook() {\n\t\tRuntime.getRuntime().addShutdownHook(new Thread(this, \"SpringApplicationShutdownHook\"));\n\t}\n\n\tvoid deregisterFailedApplicationContext(ConfigurableApplicationContext applicationContext) {\n\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\tAssert.state(!applicationContext.isActive(), \"Cannot unregister active application context\");\n\t\t\tSpringApplicationShutdownHook.this.contexts.remove(applicationContext);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\tSet<ConfigurableApplicationContext> contexts;\n\t\tSet<ConfigurableApplicationContext> closedContexts;\n\t\tList<Handler> handlers;\n\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\tthis.inProgress = true;\n\t\t\tcontexts = new LinkedHashSet<>(this.contexts);\n\t\t\tclosedContexts = new LinkedHashSet<>(this.closedContexts);\n\t\t\thandlers = new ArrayList<>(this.handlers.getActions());\n\t\t\tCollections.reverse(handlers);\n\t\t}\n\t\tcontexts.forEach(this::closeAndWait);\n\t\tclosedContexts.forEach(this::closeAndWait);\n\t\thandlers.forEach(Handler::run);\n\t}\n\n\tboolean isApplicationContextRegistered(ConfigurableApplicationContext context) {\n\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\treturn this.contexts.contains(context);\n\t\t}\n\t}\n\n\tvoid reset() {\n\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\tthis.contexts.clear();\n\t\t\tthis.closedContexts.clear();\n\t\t\tthis.handlers.getActions().clear();\n\t\t\tthis.inProgress = false;\n\t\t}\n\t}\n\n\t/**\n\t * Call {@link ConfigurableApplicationContext#close()} and wait until the context\n\t * becomes inactive. We can't assume that just because the close method returns that\n\t * the context is actually inactive. It could be that another thread is still in the\n\t * process of disposing beans.\n\t * @param context the context to clean\n\t */\n\tprivate void closeAndWait(ConfigurableApplicationContext context) {\n\t\tif (!context.isActive()) {\n\t\t\treturn;\n\t\t}\n\t\tcontext.close();\n\t\ttry {\n\t\t\tint waited = 0;\n\t\t\twhile (context.isActive()) {\n\t\t\t\tif (waited > TIMEOUT) {\n\t\t\t\t\tthrow new TimeoutException();\n\t\t\t\t}\n\t\t\t\tThread.sleep(SLEEP);\n\t\t\t\twaited += SLEEP;\n\t\t\t}\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tlogger.warn(\"Interrupted waiting for application context \" + context + \" to become inactive\");\n\t\t}\n\t\tcatch (TimeoutException ex) {\n\t\t\tlogger.warn(\"Timed out waiting for application context \" + context + \" to become inactive\", ex);\n\t\t}\n\t}\n\n\tprivate void assertNotInProgress() {\n\t\tAssert.state(!SpringApplicationShutdownHook.this.inProgress, \"Shutdown in progress\");\n\t}\n\n\t/**\n\t * The handler actions for this shutdown hook.\n\t */\n\tprivate final class Handlers implements SpringApplicationShutdownHandlers, Runnable {\n\n\t\tprivate final Set<Handler> actions = new LinkedHashSet<>();\n\n\t\t@Override\n\t\tpublic void add(Runnable action) {\n\t\t\tAssert.notNull(action, \"'action' must not be null\");\n\t\t\taddRuntimeShutdownHookIfNecessary();\n\t\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\t\tassertNotInProgress();\n\t\t\t\tthis.actions.add(new Handler(action));\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void remove(Runnable action) {\n\t\t\tAssert.notNull(action, \"'action' must not be null\");\n\t\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\t\tassertNotInProgress();\n\t\t\t\tthis.actions.remove(new Handler(action));\n\t\t\t}\n\t\t}\n\n\t\tSet<Handler> getActions() {\n\t\t\treturn this.actions;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tSpringApplicationShutdownHook.this.run();\n\t\t\tSpringApplicationShutdownHook.this.reset();\n\t\t}\n\n\t}\n\n\t/**\n\t * A single handler that uses object identity for {@link #equals(Object)} and\n\t * {@link #hashCode()}.\n\t *\n\t * @param runnable the handler runner\n\t */\n\trecord Handler(Runnable runnable) {\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn System.identityHashCode(this.runnable);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.runnable == ((Handler) obj).runnable;\n\t\t}\n\n\t\tvoid run() {\n\t\t\tthis.runnable.run();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ApplicationListener} to track closed contexts.\n\t */\n\tprivate final class ApplicationContextClosedListener implements ApplicationListener<ContextClosedEvent> {\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextClosedEvent event) {\n\t\t\t// The ContextClosedEvent is fired at the start of a call to {@code close()}\n\t\t\t// and if that happens in a different thread then the context may still be\n\t\t\t// active. Rather than just removing the context, we add it to a {@code\n\t\t\t// closedContexts} set. This is weak set so that the context can be GC'd once\n\t\t\t// the {@code close()} method returns.\n\t\t\tsynchronized (SpringApplicationShutdownHook.class) {\n\t\t\t\tApplicationContext applicationContext = event.getApplicationContext();\n\t\t\t\tSpringApplicationShutdownHook.this.contexts.remove(applicationContext);\n\t\t\t\tSpringApplicationShutdownHook.this.closedContexts\n\t\t\t\t\t.add((ConfigurableApplicationContext) applicationContext);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.PrintStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ansi.AnsiColor;\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiStyle;\nimport org.springframework.core.env.Environment;\n\n/**\n * Default Banner implementation which writes the 'Spring' banner.\n *\n * @author Phillip Webb\n */\nclass SpringBootBanner implements Banner {\n\n\tprivate static final String BANNER = \"\"\"\n\t\t\t  .   ____          _            __ _ _\n\t\t\t /\\\\\\\\ / ___'_ __ _ _(_)_ __  __ _ \\\\ \\\\ \\\\ \\\\\n\t\t\t( ( )\\\\___ | '_ | '_| | '_ \\\\/ _` | \\\\ \\\\ \\\\ \\\\\n\t\t\t \\\\\\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n\t\t\t  '  |____| .__|_| |_|_| |_\\\\__, | / / / /\n\t\t\t =========|_|==============|___/=/_/_/_/\n\t\t\t\"\"\";\n\n\tprivate static final String SPRING_BOOT = \" :: Spring Boot :: \";\n\n\tprivate static final int STRAP_LINE_SIZE = 42;\n\n\t@Override\n\tpublic void printBanner(Environment environment, @Nullable Class<?> sourceClass, PrintStream printStream) {\n\t\tprintStream.println();\n\t\tprintStream.println(BANNER);\n\t\tString version = String.format(\" (v%s)\", SpringBootVersion.getVersion());\n\t\tString padding = \" \".repeat(Math.max(0, STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())));\n\t\tprintStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding,\n\t\t\t\tAnsiStyle.FAINT, version));\n\t\tprintStream.println();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringBootConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Indexed;\n\n/**\n * Indicates that a class provides Spring Boot application\n * {@link Configuration @Configuration}. Can be used as an alternative to the Spring's\n * standard {@code @Configuration} annotation so that configuration can be found\n * automatically (for example in tests).\n * <p>\n * Application should only ever include <em>one</em> {@code @SpringBootConfiguration} and\n * most idiomatic Spring Boot applications will inherit it from\n * {@code @SpringBootApplication}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.4.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Configuration\n@Indexed\npublic @interface SpringBootConfiguration {\n\n\t/**\n\t * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce\n\t * bean lifecycle behavior, e.g. to return shared singleton bean instances even in\n\t * case of direct {@code @Bean} method calls in user code. This feature requires\n\t * method interception, implemented through a runtime-generated CGLIB subclass which\n\t * comes with limitations such as the configuration class and its methods not being\n\t * allowed to declare {@code final}.\n\t * <p>\n\t * The default is {@code true}, allowing for 'inter-bean references' within the\n\t * configuration class as well as for external calls to this configuration's\n\t * {@code @Bean} methods, e.g. from another configuration class. If this is not needed\n\t * since each of this particular configuration's {@code @Bean} methods is\n\t * self-contained and designed as a plain factory method for container use, switch\n\t * this flag to {@code false} in order to avoid CGLIB subclass processing.\n\t * <p>\n\t * Turning off bean method interception effectively processes {@code @Bean} methods\n\t * individually like when declared on non-{@code @Configuration} classes, a.k.a.\n\t * \"@Bean Lite Mode\" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally\n\t * equivalent to removing the {@code @Configuration} stereotype.\n\t * @return whether to proxy {@code @Bean} methods\n\t * @since 2.2\n\t */\n\t@AliasFor(annotation = Configuration.class)\n\tboolean proxyBeanMethods() default true;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringBootExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link UncaughtExceptionHandler} to suppress handling already logged exceptions and\n * dealing with system exit.\n *\n * @author Phillip Webb\n */\nclass SpringBootExceptionHandler implements UncaughtExceptionHandler {\n\n\tprivate static final Set<String> LOG_CONFIGURATION_MESSAGES;\n\n\tstatic {\n\t\tSet<String> messages = new HashSet<>();\n\t\tmessages.add(\"Logback configuration error detected\");\n\t\tLOG_CONFIGURATION_MESSAGES = Collections.unmodifiableSet(messages);\n\t}\n\n\tprivate static final LoggedExceptionHandlerThreadLocal handler = new LoggedExceptionHandlerThreadLocal();\n\n\tprivate final @Nullable UncaughtExceptionHandler parent;\n\n\tprivate final List<Throwable> loggedExceptions = new ArrayList<>();\n\n\tprivate int exitCode;\n\n\tSpringBootExceptionHandler(@Nullable UncaughtExceptionHandler parent) {\n\t\tthis.parent = parent;\n\t}\n\n\tvoid registerLoggedException(Throwable exception) {\n\t\tthis.loggedExceptions.add(exception);\n\t}\n\n\tvoid registerExitCode(int exitCode) {\n\t\tthis.exitCode = exitCode;\n\t}\n\n\t@Override\n\tpublic void uncaughtException(Thread thread, Throwable ex) {\n\t\ttry {\n\t\t\tif (isPassedToParent(ex) && this.parent != null) {\n\t\t\t\tthis.parent.uncaughtException(thread, ex);\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tthis.loggedExceptions.clear();\n\t\t\tif (this.exitCode != 0) {\n\t\t\t\tSystem.exit(this.exitCode);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isPassedToParent(Throwable ex) {\n\t\treturn isLogConfigurationMessage(ex) || !isRegistered(ex);\n\t}\n\n\t/**\n\t * Check if the exception is a log configuration message, i.e. the log call might not\n\t * have actually output anything.\n\t * @param ex the source exception\n\t * @return {@code true} if the exception contains a log configuration message\n\t */\n\tprivate boolean isLogConfigurationMessage(@Nullable Throwable ex) {\n\t\tif (ex == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (ex instanceof InvocationTargetException) {\n\t\t\treturn isLogConfigurationMessage(ex.getCause());\n\t\t}\n\t\tString message = ex.getMessage();\n\t\tif (message != null) {\n\t\t\tfor (String candidate : LOG_CONFIGURATION_MESSAGES) {\n\t\t\t\tif (message.contains(candidate)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isRegistered(@Nullable Throwable ex) {\n\t\tif (ex == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.loggedExceptions.contains(ex)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (ex instanceof InvocationTargetException) {\n\t\t\treturn isRegistered(ex.getCause());\n\t\t}\n\t\treturn false;\n\t}\n\n\tstatic SpringBootExceptionHandler forCurrentThread() {\n\t\treturn handler.get();\n\t}\n\n\t/**\n\t * Thread local used to attach and track handlers.\n\t */\n\tprivate static final class LoggedExceptionHandlerThreadLocal extends ThreadLocal<SpringBootExceptionHandler> {\n\n\t\t@Override\n\t\tprotected SpringBootExceptionHandler initialValue() {\n\t\t\tSpringBootExceptionHandler handler = new SpringBootExceptionHandler(\n\t\t\t\t\tThread.currentThread().getUncaughtExceptionHandler());\n\t\t\tThread.currentThread().setUncaughtExceptionHandler(handler);\n\t\t\treturn handler;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/SpringBootExceptionReporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * Callback interface used to support custom reporting of {@link SpringApplication}\n * startup errors. {@link SpringBootExceptionReporter reporters} are loaded through the\n * {@link SpringFactoriesLoader} and must declare a public constructor with a single\n * {@link ConfigurableApplicationContext} parameter.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see ApplicationContextAware\n */\n@FunctionalInterface\npublic interface SpringBootExceptionReporter {\n\n\t/**\n\t * Report a startup failure to the user.\n\t * @param failure the source failure\n\t * @return {@code true} if the failure was reported or {@code false} if default\n\t * reporting should occur.\n\t */\n\tboolean reportException(Throwable failure);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/StartupInfoLogger.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.concurrent.Callable;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.SpringApplication.Startup;\nimport org.springframework.boot.system.ApplicationHome;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Logs application information on startup.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Moritz Halbritter\n */\nclass StartupInfoLogger {\n\n\tprivate final @Nullable Class<?> sourceClass;\n\n\tprivate final Environment environment;\n\n\tStartupInfoLogger(@Nullable Class<?> sourceClass, Environment environment) {\n\t\tthis.sourceClass = sourceClass;\n\t\tthis.environment = environment;\n\t}\n\n\tvoid logStarting(Log applicationLog) {\n\t\tAssert.notNull(applicationLog, \"'applicationLog' must not be null\");\n\t\tapplicationLog.info(LogMessage.of(this::getStartingMessage));\n\t\tapplicationLog.debug(LogMessage.of(this::getRunningMessage));\n\t}\n\n\tvoid logStarted(Log applicationLog, Startup startup) {\n\t\tif (applicationLog.isInfoEnabled()) {\n\t\t\tapplicationLog.info(getStartedMessage(startup));\n\t\t}\n\t}\n\n\tprivate CharSequence getStartingMessage() {\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\"Starting\");\n\t\tappendAotMode(message);\n\t\tappendApplicationName(message);\n\t\tappendApplicationVersion(message);\n\t\tappendJavaVersion(message);\n\t\tappendPid(message);\n\t\tappendContext(message);\n\t\treturn message;\n\t}\n\n\tprivate CharSequence getRunningMessage() {\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\"Running with Spring Boot\");\n\t\tappendVersion(message, getClass());\n\t\tmessage.append(\", Spring\");\n\t\tappendVersion(message, ApplicationContext.class);\n\t\treturn message;\n\t}\n\n\tprivate CharSequence getStartedMessage(Startup startup) {\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(startup.action());\n\t\tappendApplicationName(message);\n\t\tmessage.append(\" in \");\n\t\tmessage.append(startup.timeTakenToStarted().toMillis() / 1000.0);\n\t\tmessage.append(\" seconds\");\n\t\tLong uptimeMs = startup.processUptime();\n\t\tif (uptimeMs != null) {\n\t\t\tdouble uptime = uptimeMs / 1000.0;\n\t\t\tmessage.append(\" (process running for \").append(uptime).append(\")\");\n\t\t}\n\t\treturn message;\n\t}\n\n\tprivate void appendAotMode(StringBuilder message) {\n\t\tappend(message, \"\", () -> AotDetector.useGeneratedArtifacts() ? \"AOT-processed\" : null);\n\t}\n\n\tprivate void appendApplicationName(StringBuilder message) {\n\t\tappend(message, \"\",\n\t\t\t\t() -> (this.sourceClass != null) ? ClassUtils.getShortName(this.sourceClass) : \"application\");\n\t}\n\n\tprivate void appendVersion(StringBuilder message, Class<?> source) {\n\t\tappend(message, \"v\", () -> source.getPackage().getImplementationVersion());\n\t}\n\n\tprivate void appendApplicationVersion(StringBuilder message) {\n\t\tappend(message, \"v\", () -> this.environment.getProperty(\"spring.application.version\"));\n\t}\n\n\tprivate void appendPid(StringBuilder message) {\n\t\tappend(message, \"with PID \", () -> this.environment.getProperty(\"spring.application.pid\"));\n\t}\n\n\tprivate void appendContext(StringBuilder message) {\n\t\tStringBuilder context = new StringBuilder();\n\t\tApplicationHome home = new ApplicationHome(this.sourceClass);\n\t\tif (home.getSource() != null) {\n\t\t\tcontext.append(home.getSource().getAbsolutePath());\n\t\t}\n\t\tappend(context, \"started by \", () -> System.getProperty(\"user.name\"));\n\t\tappend(context, \"in \", () -> System.getProperty(\"user.dir\"));\n\t\tif (!context.isEmpty()) {\n\t\t\tmessage.append(\" (\");\n\t\t\tmessage.append(context);\n\t\t\tmessage.append(\")\");\n\t\t}\n\t}\n\n\tprivate void appendJavaVersion(StringBuilder message) {\n\t\tappend(message, \"using Java \", () -> System.getProperty(\"java.version\"));\n\t}\n\n\tprivate void append(StringBuilder message, String prefix, Callable<@Nullable Object> call) {\n\t\tappend(message, prefix, call, \"\");\n\t}\n\n\tprivate void append(StringBuilder message, String prefix, Callable<@Nullable Object> call, String defaultValue) {\n\t\tObject result = callIfPossible(call);\n\t\tString value = (result != null) ? result.toString() : null;\n\t\tif (!StringUtils.hasLength(value)) {\n\t\t\tvalue = defaultValue;\n\t\t}\n\t\tif (StringUtils.hasLength(value)) {\n\t\t\tmessage.append((!message.isEmpty()) ? \" \" : \"\");\n\t\t\tmessage.append(prefix);\n\t\t\tmessage.append(value);\n\t\t}\n\t}\n\n\tprivate @Nullable Object callIfPossible(Callable<@Nullable Object> call) {\n\t\ttry {\n\t\t\treturn call.call();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/WebApplicationType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.ClassUtils;\n\n/**\n * An enumeration of possible types of web application.\n *\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic enum WebApplicationType {\n\n\t/**\n\t * The application should not run as a web application and should not start an\n\t * embedded web server.\n\t */\n\tNONE,\n\n\t/**\n\t * The application should run as a servlet-based web application and should start an\n\t * embedded servlet web server.\n\t */\n\tSERVLET,\n\n\t/**\n\t * The application should run as a reactive web application and should start an\n\t * embedded reactive web server.\n\t */\n\tREACTIVE;\n\n\tprivate static final String[] SERVLET_INDICATOR_CLASSES = { \"jakarta.servlet.Servlet\",\n\t\t\t\"org.springframework.web.context.ConfigurableWebApplicationContext\" };\n\n\t/**\n\t * Deduce the {@link WebApplicationType} from the current classpath.\n\t * @return the deduced web application\n\t * @since 4.0.1\n\t */\n\tpublic static WebApplicationType deduce() {\n\t\tfor (Deducer deducer : SpringFactoriesLoader.forDefaultResourceLocation().load(Deducer.class)) {\n\t\t\tWebApplicationType deduced = deducer.deduceWebApplicationType();\n\t\t\tif (deduced != null) {\n\t\t\t\treturn deduced;\n\t\t\t}\n\t\t}\n\t\treturn isServletApplication() ? WebApplicationType.SERVLET : WebApplicationType.NONE;\n\t}\n\n\tprivate static boolean isServletApplication() {\n\t\tfor (String servletIndicatorClass : SERVLET_INDICATOR_CLASSES) {\n\t\t\tif (!ClassUtils.isPresent(servletIndicatorClass, null)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tstatic class WebApplicationTypeRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tfor (String servletIndicatorClass : SERVLET_INDICATOR_CLASSES) {\n\t\t\t\tregisterTypeIfPresent(servletIndicatorClass, classLoader, hints);\n\t\t\t}\n\t\t}\n\n\t\tprivate void registerTypeIfPresent(String typeName, @Nullable ClassLoader classLoader, RuntimeHints hints) {\n\t\t\tif (ClassUtils.isPresent(typeName, classLoader)) {\n\t\t\t\thints.reflection().registerType(TypeReference.of(typeName));\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Strategy that may be implemented by a module that can deduce the\n\t * {@link WebApplicationType}.\n\t *\n\t * @since 4.0.1\n\t */\n\t@FunctionalInterface\n\tpublic interface Deducer {\n\n\t\t/**\n\t\t * Deduce the web application type.\n\t\t * @return the deduced web application type or {@code null}\n\t\t */\n\t\t@Nullable WebApplicationType deduceWebApplicationType();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.admin;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * An MBean contract to control and monitor a running {@code SpringApplication} over JMX.\n * Intended for internal use only.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\npublic interface SpringApplicationAdminMXBean {\n\n\t/**\n\t * Specify if the application has fully started and is now ready.\n\t * @return {@code true} if the application is ready\n\t * @see org.springframework.boot.context.event.ApplicationReadyEvent\n\t */\n\tboolean isReady();\n\n\t/**\n\t * Specify if the application runs in an embedded web container. Return {@code false}\n\t * on a web application that hasn't fully started yet, so it is preferable to wait for\n\t * the application to be {@link #isReady() ready}.\n\t * @return {@code true} if the application runs in an embedded web container\n\t * @see #isReady()\n\t */\n\tboolean isEmbeddedWebApplication();\n\n\t/**\n\t * Return the value of the specified key from the application\n\t * {@link org.springframework.core.env.Environment Environment}.\n\t * @param key the property key\n\t * @return the property value or {@code null} if it does not exist\n\t */\n\t@Nullable String getProperty(String key);\n\n\t/**\n\t * Shutdown the application.\n\t * @see org.springframework.context.ConfigurableApplicationContext#close()\n\t */\n\tvoid shutdown();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.admin;\n\nimport java.lang.management.ManagementFactory;\n\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.event.GenericApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.util.Assert;\n\n/**\n * Register a {@link SpringApplicationAdminMXBean} implementation to the platform\n * {@link MBeanServer}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 1.3.0\n */\npublic class SpringApplicationAdminMXBeanRegistrar implements ApplicationContextAware, GenericApplicationListener,\n\t\tEnvironmentAware, InitializingBean, DisposableBean {\n\n\tprivate static final Log logger = LogFactory.getLog(SpringApplicationAdmin.class);\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate Environment environment = new StandardEnvironment();\n\n\tprivate final ObjectName objectName;\n\n\tprivate boolean ready;\n\n\tpublic SpringApplicationAdminMXBeanRegistrar(String name) throws MalformedObjectNameException {\n\t\tthis.objectName = new ObjectName(name);\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tAssert.state(applicationContext instanceof ConfigurableApplicationContext,\n\t\t\t\t\"'applicationContext' must be a ConfigurableApplicationContext\");\n\t\tthis.applicationContext = (ConfigurableApplicationContext) applicationContext;\n\t}\n\n\t@Override\n\tpublic void setEnvironment(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic boolean supportsEventType(ResolvableType eventType) {\n\t\tClass<?> type = eventType.getRawClass();\n\t\tif (type == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn ApplicationReadyEvent.class.isAssignableFrom(type);\n\t}\n\n\t@Override\n\tpublic boolean supportsSourceType(@Nullable Class<?> sourceType) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\tif (event instanceof ApplicationReadyEvent readyEvent) {\n\t\t\tonApplicationReadyEvent(readyEvent);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n\tvoid onApplicationReadyEvent(ApplicationReadyEvent event) {\n\t\tif (this.applicationContext.equals(event.getApplicationContext())) {\n\t\t\tthis.ready = true;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tMBeanServer server = ManagementFactory.getPlatformMBeanServer();\n\t\tserver.registerMBean(new SpringApplicationAdmin(), this.objectName);\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Application Admin MBean registered with name '\" + this.objectName + \"'\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tManagementFactory.getPlatformMBeanServer().unregisterMBean(this.objectName);\n\t}\n\n\tprivate final class SpringApplicationAdmin implements SpringApplicationAdminMXBean {\n\n\t\t@Override\n\t\tpublic boolean isReady() {\n\t\t\treturn SpringApplicationAdminMXBeanRegistrar.this.ready;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isEmbeddedWebApplication() {\n\t\t\treturn SpringApplicationAdminMXBeanRegistrar.this.environment instanceof ConfigurableEnvironment configurableEnvironment\n\t\t\t\t\t&& configurableEnvironment.getPropertySources().get(\"server.ports\") != null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getProperty(String key) {\n\t\t\treturn SpringApplicationAdminMXBeanRegistrar.this.environment.getProperty(key);\n\t\t}\n\n\t\t@Override\n\t\tpublic void shutdown() {\n\t\t\tlogger.info(\"Application shutdown requested.\");\n\t\t\tSpringApplicationAdminMXBeanRegistrar.this.applicationContext.close();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/admin/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Administration support for Spring Boot applications.\n */\n@NullMarked\npackage org.springframework.boot.admin;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/Ansi8BitColor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link AnsiElement} implementation for ANSI 8-bit foreground or background color codes.\n *\n * @author Toshiaki Maki\n * @author Phillip Webb\n * @since 2.2.0\n * @see #foreground(int)\n * @see #background(int)\n */\npublic final class Ansi8BitColor implements AnsiElement {\n\n\tprivate final String prefix;\n\n\tprivate final int code;\n\n\t/**\n\t * Create a new {@link Ansi8BitColor} instance.\n\t * @param prefix the prefix escape chars\n\t * @param code color code (must be 0-255)\n\t * @throws IllegalArgumentException if color code is not between 0 and 255.\n\t */\n\tprivate Ansi8BitColor(String prefix, int code) {\n\t\tAssert.isTrue(code >= 0 && code <= 255, \"'code' must be between 0 and 255\");\n\t\tthis.prefix = prefix;\n\t\tthis.code = code;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tAnsi8BitColor other = (Ansi8BitColor) obj;\n\t\treturn this.prefix.equals(other.prefix) && this.code == other.code;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.prefix.hashCode() * 31 + this.code;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.prefix + this.code;\n\t}\n\n\t/**\n\t * Return a foreground ANSI color code instance for the given code.\n\t * @param code the color code\n\t * @return an ANSI color code instance\n\t */\n\tpublic static Ansi8BitColor foreground(int code) {\n\t\treturn new Ansi8BitColor(\"38;5;\", code);\n\t}\n\n\t/**\n\t * Return a background ANSI color code instance for the given code.\n\t * @param code the color code\n\t * @return an ANSI color code instance\n\t */\n\tpublic static Ansi8BitColor background(int code) {\n\t\treturn new Ansi8BitColor(\"48;5;\", code);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/AnsiBackground.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\n/**\n * {@link AnsiElement Ansi} background colors.\n *\n * @author Phillip Webb\n * @author Geoffrey Chandler\n * @since 1.3.0\n */\npublic enum AnsiBackground implements AnsiElement {\n\n\tDEFAULT(\"49\"),\n\n\tBLACK(\"40\"),\n\n\tRED(\"41\"),\n\n\tGREEN(\"42\"),\n\n\tYELLOW(\"43\"),\n\n\tBLUE(\"44\"),\n\n\tMAGENTA(\"45\"),\n\n\tCYAN(\"46\"),\n\n\tWHITE(\"47\"),\n\n\tBRIGHT_BLACK(\"100\"),\n\n\tBRIGHT_RED(\"101\"),\n\n\tBRIGHT_GREEN(\"102\"),\n\n\tBRIGHT_YELLOW(\"103\"),\n\n\tBRIGHT_BLUE(\"104\"),\n\n\tBRIGHT_MAGENTA(\"105\"),\n\n\tBRIGHT_CYAN(\"106\"),\n\n\tBRIGHT_WHITE(\"107\");\n\n\tprivate final String code;\n\n\tAnsiBackground(String code) {\n\t\tthis.code = code;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.code;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/AnsiColor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\n/**\n * {@link AnsiElement Ansi} colors.\n *\n * @author Phillip Webb\n * @author Geoffrey Chandler\n * @since 1.3.0\n */\npublic enum AnsiColor implements AnsiElement {\n\n\tDEFAULT(\"39\"),\n\n\tBLACK(\"30\"),\n\n\tRED(\"31\"),\n\n\tGREEN(\"32\"),\n\n\tYELLOW(\"33\"),\n\n\tBLUE(\"34\"),\n\n\tMAGENTA(\"35\"),\n\n\tCYAN(\"36\"),\n\n\tWHITE(\"37\"),\n\n\tBRIGHT_BLACK(\"90\"),\n\n\tBRIGHT_RED(\"91\"),\n\n\tBRIGHT_GREEN(\"92\"),\n\n\tBRIGHT_YELLOW(\"93\"),\n\n\tBRIGHT_BLUE(\"94\"),\n\n\tBRIGHT_MAGENTA(\"95\"),\n\n\tBRIGHT_CYAN(\"96\"),\n\n\tBRIGHT_WHITE(\"97\");\n\n\tprivate final String code;\n\n\tAnsiColor(String code) {\n\t\tthis.code = code;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.code;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/AnsiElement.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\n/**\n * An ANSI encodable element.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic interface AnsiElement {\n\n\t/**\n\t * @return the ANSI escape code\n\t */\n\t@Override\n\tString toString();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/AnsiOutput.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport java.io.Console;\nimport java.lang.reflect.Method;\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Generates ANSI encoded output, automatically attempting to detect if the terminal\n * supports ANSI.\n *\n * @author Phillip Webb\n * @author Yong-Hyun Kim\n * @since 1.0.0\n */\npublic abstract class AnsiOutput {\n\n\tprivate static final String ENCODE_JOIN = \";\";\n\n\tprivate static Enabled enabled = Enabled.DETECT;\n\n\tprivate static @Nullable Boolean consoleAvailable;\n\n\tprivate static @Nullable Boolean ansiCapable;\n\n\tprivate static final String OPERATING_SYSTEM_NAME = System.getProperty(\"os.name\").toLowerCase(Locale.ENGLISH);\n\n\tprivate static final String ENCODE_START = \"\\033[\";\n\n\tprivate static final String ENCODE_END = \"m\";\n\n\tprivate static final String RESET = \"0;\" + AnsiColor.DEFAULT;\n\n\t/**\n\t * Sets if ANSI output is enabled.\n\t * @param enabled if ANSI is enabled, disabled or detected\n\t */\n\tpublic static void setEnabled(Enabled enabled) {\n\t\tAssert.notNull(enabled, \"'enabled' must not be null\");\n\t\tAnsiOutput.enabled = enabled;\n\t}\n\n\t/**\n\t * Returns if ANSI output is enabled\n\t * @return if ANSI enabled, disabled or detected\n\t */\n\tpublic static Enabled getEnabled() {\n\t\treturn AnsiOutput.enabled;\n\t}\n\n\t/**\n\t * Sets if the System.console() is known to be available.\n\t * @param consoleAvailable if the console is known to be available or {@code null} to\n\t * use standard detection logic.\n\t */\n\tpublic static void setConsoleAvailable(@Nullable Boolean consoleAvailable) {\n\t\tAnsiOutput.consoleAvailable = consoleAvailable;\n\t}\n\n\t/**\n\t * Encode a single {@link AnsiElement} if output is enabled.\n\t * @param element the element to encode\n\t * @return the encoded element or an empty string\n\t */\n\tpublic static String encode(AnsiElement element) {\n\t\tif (isEnabled()) {\n\t\t\treturn ENCODE_START + element + ENCODE_END;\n\t\t}\n\t\treturn \"\";\n\t}\n\n\t/**\n\t * Create a new ANSI string from the specified elements. Any {@link AnsiElement}s will\n\t * be encoded as required.\n\t * @param elements the elements to encode\n\t * @return a string of the encoded elements\n\t */\n\tpublic static String toString(Object... elements) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tif (isEnabled()) {\n\t\t\tbuildEnabled(sb, elements);\n\t\t}\n\t\telse {\n\t\t\tbuildDisabled(sb, elements);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\tprivate static void buildEnabled(StringBuilder sb, Object[] elements) {\n\t\tboolean writingAnsi = false;\n\t\tboolean containsEncoding = false;\n\t\tfor (Object element : elements) {\n\t\t\tif (element instanceof AnsiElement) {\n\t\t\t\tcontainsEncoding = true;\n\t\t\t\tif (!writingAnsi) {\n\t\t\t\t\tsb.append(ENCODE_START);\n\t\t\t\t\twritingAnsi = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsb.append(ENCODE_JOIN);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (writingAnsi) {\n\t\t\t\t\tsb.append(ENCODE_END);\n\t\t\t\t\twritingAnsi = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsb.append(element);\n\t\t}\n\t\tif (containsEncoding) {\n\t\t\tsb.append(writingAnsi ? ENCODE_JOIN : ENCODE_START);\n\t\t\tsb.append(RESET);\n\t\t\tsb.append(ENCODE_END);\n\t\t}\n\t}\n\n\tprivate static void buildDisabled(StringBuilder sb, @Nullable Object[] elements) {\n\t\tfor (Object element : elements) {\n\t\t\tif (!(element instanceof AnsiElement) && element != null) {\n\t\t\t\tsb.append(element);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static boolean isEnabled() {\n\t\tif (enabled == Enabled.DETECT) {\n\t\t\tif (ansiCapable == null) {\n\t\t\t\tansiCapable = detectIfAnsiCapable();\n\t\t\t}\n\t\t\treturn ansiCapable;\n\t\t}\n\t\treturn enabled == Enabled.ALWAYS;\n\t}\n\n\tprivate static boolean detectIfAnsiCapable() {\n\t\ttry {\n\t\t\tif (Boolean.FALSE.equals(consoleAvailable)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (consoleAvailable == null) {\n\t\t\t\tConsole console = System.console();\n\t\t\t\tif (console == null) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tMethod isTerminalMethod = ClassUtils.getMethodIfAvailable(Console.class, \"isTerminal\");\n\t\t\t\tif (isTerminalMethod != null) {\n\t\t\t\t\tBoolean isTerminal = (Boolean) isTerminalMethod.invoke(console);\n\t\t\t\t\tif (Boolean.FALSE.equals(isTerminal)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn !(OPERATING_SYSTEM_NAME.contains(\"win\"));\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Possible values to pass to {@link AnsiOutput#setEnabled}. Determines when to output\n\t * ANSI escape sequences for coloring application output.\n\t */\n\tpublic enum Enabled {\n\n\t\t/**\n\t\t * Try to detect whether ANSI coloring capabilities are available. The default\n\t\t * value for {@link AnsiOutput}.\n\t\t */\n\t\tDETECT,\n\n\t\t/**\n\t\t * Enable ANSI-colored output.\n\t\t */\n\t\tALWAYS,\n\n\t\t/**\n\t\t * Disable ANSI-colored output.\n\t\t */\n\t\tNEVER\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/AnsiPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.IntFunction;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link PropertyResolver} for {@link AnsiStyle}, {@link AnsiColor},\n * {@link AnsiBackground} and {@link Ansi8BitColor} elements. Supports properties of the\n * form {@code AnsiStyle.BOLD}, {@code AnsiColor.RED} or {@code AnsiBackground.GREEN}.\n * Also supports a prefix of {@code Ansi.} which is an aggregation of everything (with\n * background colors prefixed {@code BG_}).\n * <p>\n * ANSI 8-bit color codes can be used with {@code AnsiColor} and {@code AnsiBackground}.\n * For example, {@code AnsiColor.208} will render orange text.\n * <a href=\"https://en.wikipedia.org/wiki/ANSI_escape_code\">Wikipedia</a> has a complete\n * list of the 8-bit color codes that can be used.\n *\n * @author Phillip Webb\n * @author Toshiaki Maki\n * @since 1.3.0\n */\npublic class AnsiPropertySource extends PropertySource<AnsiElement> {\n\n\tprivate static final Iterable<Mapping> MAPPINGS;\n\n\tstatic {\n\t\tList<Mapping> mappings = new ArrayList<>();\n\t\tmappings.add(new EnumMapping<>(\"AnsiStyle.\", AnsiStyle.class));\n\t\tmappings.add(new EnumMapping<>(\"AnsiColor.\", AnsiColor.class));\n\t\tmappings.add(new Ansi8BitColorMapping(\"AnsiColor.\", Ansi8BitColor::foreground));\n\t\tmappings.add(new EnumMapping<>(\"AnsiBackground.\", AnsiBackground.class));\n\t\tmappings.add(new Ansi8BitColorMapping(\"AnsiBackground.\", Ansi8BitColor::background));\n\t\tmappings.add(new EnumMapping<>(\"Ansi.\", AnsiStyle.class));\n\t\tmappings.add(new EnumMapping<>(\"Ansi.\", AnsiColor.class));\n\t\tmappings.add(new EnumMapping<>(\"Ansi.BG_\", AnsiBackground.class));\n\t\tMAPPINGS = Collections.unmodifiableList(mappings);\n\t}\n\n\tprivate final boolean encode;\n\n\t/**\n\t * Create a new {@link AnsiPropertySource} instance.\n\t * @param name the name of the property source\n\t * @param encode if the output should be encoded\n\t */\n\tpublic AnsiPropertySource(String name, boolean encode) {\n\t\tsuper(name);\n\t\tthis.encode = encode;\n\t}\n\n\t@Override\n\tpublic @Nullable Object getProperty(String name) {\n\t\tif (StringUtils.hasLength(name)) {\n\t\t\tfor (Mapping mapping : MAPPINGS) {\n\t\t\t\tString prefix = mapping.getPrefix();\n\t\t\t\tif (name.startsWith(prefix)) {\n\t\t\t\t\tString postfix = name.substring(prefix.length());\n\t\t\t\t\tAnsiElement element = mapping.getElement(postfix);\n\t\t\t\t\tif (element != null) {\n\t\t\t\t\t\treturn (this.encode) ? AnsiOutput.encode(element) : element;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Mapping between a name and the pseudo property source.\n\t */\n\tprivate abstract static class Mapping {\n\n\t\tprivate final String prefix;\n\n\t\tMapping(String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t\tString getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tabstract @Nullable AnsiElement getElement(String postfix);\n\n\t}\n\n\t/**\n\t * {@link Mapping} for {@link AnsiElement} enums.\n\t */\n\tprivate static class EnumMapping<E extends Enum<E> & AnsiElement> extends Mapping {\n\n\t\tprivate final Set<E> enums;\n\n\t\tEnumMapping(String prefix, Class<E> enumType) {\n\t\t\tsuper(prefix);\n\t\t\tthis.enums = EnumSet.allOf(enumType);\n\t\t}\n\n\t\t@Override\n\t\t@Nullable AnsiElement getElement(String postfix) {\n\t\t\tfor (Enum<?> candidate : this.enums) {\n\t\t\t\tif (candidate.name().equals(postfix)) {\n\t\t\t\t\treturn (AnsiElement) candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Mapping} for {@link Ansi8BitColor}.\n\t */\n\tprivate static class Ansi8BitColorMapping extends Mapping {\n\n\t\tprivate final IntFunction<Ansi8BitColor> factory;\n\n\t\tAnsi8BitColorMapping(String prefix, IntFunction<Ansi8BitColor> factory) {\n\t\t\tsuper(prefix);\n\t\t\tthis.factory = factory;\n\t\t}\n\n\t\t@Override\n\t\t@Nullable AnsiElement getElement(String postfix) {\n\t\t\tif (containsOnlyDigits(postfix)) {\n\t\t\t\ttry {\n\t\t\t\t\treturn this.factory.apply(Integer.parseInt(postfix));\n\t\t\t\t}\n\t\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate boolean containsOnlyDigits(String postfix) {\n\t\t\tfor (int i = 0; i < postfix.length(); i++) {\n\t\t\t\tif (!Character.isDigit(postfix.charAt(i))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn !postfix.isEmpty();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/AnsiStyle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\n/**\n * {@link AnsiElement Ansi} styles.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic enum AnsiStyle implements AnsiElement {\n\n\tNORMAL(\"0\"),\n\n\tBOLD(\"1\"),\n\n\tFAINT(\"2\"),\n\n\tITALIC(\"3\"),\n\n\tUNDERLINE(\"4\"),\n\n\tREVERSE(\"7\");\n\n\tprivate final String code;\n\n\tAnsiStyle(String code) {\n\t\tthis.code = code;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.code;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ansi/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes to provide ANSI color output.\n *\n * @see org.springframework.boot.ansi.AnsiOutput\n */\n@NullMarked\npackage org.springframework.boot.ansi;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/ApplicationAvailability.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Provides {@link AvailabilityState availability state} information for the application.\n * <p>\n * Components can inject this class to get the current state information. To update the\n * state of the application an {@link AvailabilityChangeEvent} should be\n * {@link ApplicationContext#publishEvent published} to the application context with\n * directly or through {@link AvailabilityChangeEvent#publish}.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface ApplicationAvailability {\n\n\t/**\n\t * Return the {@link LivenessState} of the application.\n\t * @return the liveness state\n\t */\n\tdefault LivenessState getLivenessState() {\n\t\treturn getState(LivenessState.class, LivenessState.BROKEN);\n\t}\n\n\t/**\n\t * Return the {@link ReadinessState} of the application.\n\t * @return the readiness state\n\t */\n\tdefault ReadinessState getReadinessState() {\n\t\treturn getState(ReadinessState.class, ReadinessState.REFUSING_TRAFFIC);\n\t}\n\n\t/**\n\t * Return {@link AvailabilityState} information for the application.\n\t * @param <S> the state type\n\t * @param stateType the state type\n\t * @param defaultState the default state to return if no event of the given type has\n\t * been published yet (must not be {@code null}).\n\t * @return the readiness state\n\t * @see #getState(Class)\n\t */\n\t<S extends AvailabilityState> S getState(Class<S> stateType, S defaultState);\n\n\t/**\n\t * Return {@link AvailabilityState} information for the application.\n\t * @param <S> the state type\n\t * @param stateType the state type\n\t * @return the readiness state or {@code null} if no event of the given type has been\n\t * published yet\n\t * @see #getState(Class, AvailabilityState)\n\t */\n\t<S extends AvailabilityState> @Nullable S getState(Class<S> stateType);\n\n\t/**\n\t * Return the last {@link AvailabilityChangeEvent} received for a given state type.\n\t * @param <S> the state type\n\t * @param stateType the state type\n\t * @return the readiness state or {@code null} if no event of the given type has been\n\t * published yet\n\t */\n\t<S extends AvailabilityState> @Nullable AvailabilityChangeEvent<S> getLastChangeEvent(Class<S> stateType);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/ApplicationAvailabilityBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.util.Assert;\n\n/**\n * Bean that provides an {@link ApplicationAvailability} implementation by listening for\n * {@link AvailabilityChangeEvent change events}.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 2.3.0\n * @see ApplicationAvailability\n */\npublic class ApplicationAvailabilityBean\n\t\timplements ApplicationAvailability, ApplicationListener<AvailabilityChangeEvent<?>> {\n\n\tprivate final Map<Class<? extends AvailabilityState>, AvailabilityChangeEvent<?>> events = new ConcurrentHashMap<>();\n\n\tprivate final Log logger;\n\n\tpublic ApplicationAvailabilityBean() {\n\t\tthis(LogFactory.getLog(ApplicationAvailabilityBean.class));\n\t}\n\n\tApplicationAvailabilityBean(Log logger) {\n\t\tthis.logger = logger;\n\t}\n\n\t@Override\n\tpublic <S extends AvailabilityState> S getState(Class<S> stateType, S defaultState) {\n\t\tAssert.notNull(stateType, \"'stateType' must not be null\");\n\t\tAssert.notNull(defaultState, \"'defaultState' must not be null\");\n\t\tS state = getState(stateType);\n\t\treturn (state != null) ? state : defaultState;\n\t}\n\n\t@Override\n\tpublic <S extends AvailabilityState> @Nullable S getState(Class<S> stateType) {\n\t\tAvailabilityChangeEvent<S> event = getLastChangeEvent(stateType);\n\t\treturn (event != null) ? event.getState() : null;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <S extends AvailabilityState> @Nullable AvailabilityChangeEvent<S> getLastChangeEvent(Class<S> stateType) {\n\t\treturn (AvailabilityChangeEvent<S>) this.events.get(stateType);\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(AvailabilityChangeEvent<?> event) {\n\t\tClass<? extends AvailabilityState> type = getStateType(event.getState());\n\t\tif (this.logger.isDebugEnabled()) {\n\t\t\tthis.logger.debug(getLogMessage(type, event));\n\t\t}\n\t\tthis.events.put(type, event);\n\t}\n\n\tprivate <S extends AvailabilityState> Object getLogMessage(Class<S> type, AvailabilityChangeEvent<?> event) {\n\t\tAvailabilityChangeEvent<S> lastChangeEvent = getLastChangeEvent(type);\n\t\tStringBuilder message = new StringBuilder(\n\t\t\t\t\"Application availability state \" + type.getSimpleName() + \" changed\");\n\t\tmessage.append((lastChangeEvent != null) ? \" from \" + lastChangeEvent.getState() : \"\");\n\t\tmessage.append(\" to \" + event.getState());\n\t\tmessage.append(getSourceDescription(event.getSource()));\n\t\treturn message;\n\t}\n\n\tprivate String getSourceDescription(@Nullable Object source) {\n\t\tif (source == null || source instanceof ApplicationEventPublisher) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn \": \" + ((source instanceof Throwable) ? source : source.getClass().getName());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Class<? extends AvailabilityState> getStateType(AvailabilityState state) {\n\t\tClass<?> type = (state instanceof Enum<?> enumState) ? enumState.getDeclaringClass() : state.getClass();\n\t\treturn (Class<? extends AvailabilityState>) type;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/AvailabilityChangeEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.PayloadApplicationEvent;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ApplicationEvent} sent when the {@link AvailabilityState} of the application\n * changes.\n * <p>\n * Any application component can send such events to update the state of the application.\n *\n * @param <S> the availability state type\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class AvailabilityChangeEvent<S extends AvailabilityState> extends PayloadApplicationEvent<S> {\n\n\t/**\n\t * Create a new {@link AvailabilityChangeEvent} instance.\n\t * @param source the source of the event\n\t * @param state the availability state (never {@code null})\n\t */\n\tpublic AvailabilityChangeEvent(Object source, S state) {\n\t\tsuper(source, state);\n\t}\n\n\t/**\n\t * Return the changed availability state.\n\t * @return the availability state\n\t */\n\tpublic S getState() {\n\t\treturn getPayload();\n\t}\n\n\t@Override\n\tpublic ResolvableType getResolvableType() {\n\t\treturn ResolvableType.forClassWithGenerics(getClass(), getStateType());\n\t}\n\n\tprivate Class<?> getStateType() {\n\t\tS state = getState();\n\t\tif (state instanceof Enum<?> enumState) {\n\t\t\treturn enumState.getDeclaringClass();\n\t\t}\n\t\treturn state.getClass();\n\t}\n\n\t/**\n\t * Convenience method that can be used to publish an {@link AvailabilityChangeEvent}\n\t * to the given application context.\n\t * @param <S> the availability state type\n\t * @param context the context used to publish the event\n\t * @param state the changed availability state\n\t */\n\tpublic static <S extends AvailabilityState> void publish(ApplicationContext context, S state) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tpublish(context, context, state);\n\t}\n\n\t/**\n\t * Convenience method that can be used to publish an {@link AvailabilityChangeEvent}\n\t * to the given application context.\n\t * @param <S> the availability state type\n\t * @param publisher the publisher used to publish the event\n\t * @param source the source of the event\n\t * @param state the changed availability state\n\t */\n\tpublic static <S extends AvailabilityState> void publish(ApplicationEventPublisher publisher, Object source,\n\t\t\tS state) {\n\t\tAssert.notNull(publisher, \"'publisher' must not be null\");\n\t\tpublisher.publishEvent(new AvailabilityChangeEvent<>(source, state));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/AvailabilityState.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\n/**\n * Tagging interface used on {@link ApplicationAvailability} states. This interface is\n * usually implemented on an {@code enum} type.\n *\n * @author Phillip Webb\n * @since 2.3.0\n * @see LivenessState\n * @see ReadinessState\n */\npublic interface AvailabilityState {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/LivenessState.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\n/**\n * \"Liveness\" state of the application.\n * <p>\n * An application is considered live when it's running with a correct internal state.\n * \"Liveness\" failure means that the internal state of the application is broken and we\n * cannot recover from it. As a result, the platform should restart the application.\n *\n * @author Brian Clozel\n * @since 2.3.0\n */\npublic enum LivenessState implements AvailabilityState {\n\n\t/**\n\t * The application is running and its internal state is correct.\n\t */\n\tCORRECT,\n\n\t/**\n\t * The application is running but its internal state is broken.\n\t */\n\tBROKEN\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/ReadinessState.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\n/**\n * \"Readiness\" state of the application.\n * <p>\n * An application is considered ready when it's {@link LivenessState live} and willing to\n * accept traffic. \"Readiness\" failure means that the application is not able to accept\n * traffic and that the infrastructure should stop routing requests to it.\n *\n * @author Brian Clozel\n * @since 2.3.0\n */\npublic enum ReadinessState implements AvailabilityState {\n\n\t/**\n\t * The application is ready to receive traffic.\n\t */\n\tACCEPTING_TRAFFIC,\n\n\t/**\n\t * The application is not willing to receive traffic.\n\t */\n\tREFUSING_TRAFFIC\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/availability/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for describing the availability of Spring Boot applications.\n */\n@NullMarked\npackage org.springframework.boot.availability;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/BootstrapContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\n\n/**\n * A simple bootstrap context that is available during startup and {@link Environment}\n * post-processing up to the point that the {@link ApplicationContext} is prepared.\n * <p>\n * Provides lazy access to singletons that may be expensive to create, or need to be\n * shared before the {@link ApplicationContext} is available.\n * <p>\n * Instances are registered by type. The contact may return {@code null} values when a\n * type has been registered but no value is actually supplied.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @since 2.4.0\n * @see BootstrapRegistry\n */\npublic interface BootstrapContext {\n\n\t/**\n\t * Return an instance from the context if the type has been registered. The instance\n\t * will be created if it hasn't been accessed previously.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @return the instance managed by the context, which may be {@code null}\n\t * @throws IllegalStateException if the type has not been registered\n\t */\n\t<T> @Nullable T get(Class<T> type) throws IllegalStateException;\n\n\t/**\n\t * Return an instance from the context if the type has been registered. The instance\n\t * will be created if it hasn't been accessed previously.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @param other the instance to use if the type has not been registered\n\t * @return the instance, which may be {@code null}\n\t */\n\t<T> @Nullable T getOrElse(Class<T> type, @Nullable T other);\n\n\t/**\n\t * Return an instance from the context if the type has been registered. The instance\n\t * will be created if it hasn't been accessed previously.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @param other a supplier for the instance to use if the type has not been registered\n\t * @return the instance, which may be {@code null}\n\t */\n\t<T> @Nullable T getOrElseSupply(Class<T> type, Supplier<@Nullable T> other);\n\n\t/**\n\t * Return an instance from the context if the type has been registered. The instance\n\t * will be created if it hasn't been accessed previously.\n\t * @param <T> the instance type\n\t * @param <X> the exception to throw if the type is not registered\n\t * @param type the instance type\n\t * @param exceptionSupplier the supplier which will return the exception to be thrown\n\t * @return the instance managed by the context, which may be {@code null}\n\t * @throws X if the type has not been registered\n\t */\n\t<T, X extends Throwable> @Nullable T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier)\n\t\t\tthrows X;\n\n\t/**\n\t * Return if a registration exists for the given type.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @return {@code true} if the type has already been registered\n\t */\n\t<T> boolean isRegistered(Class<T> type);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/BootstrapContextClosedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * {@link ApplicationEvent} published by a {@link BootstrapContext} when it's closed.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see BootstrapRegistry#addCloseListener(org.springframework.context.ApplicationListener)\n */\npublic class BootstrapContextClosedEvent extends ApplicationEvent {\n\n\tprivate final ConfigurableApplicationContext applicationContext;\n\n\tBootstrapContextClosedEvent(BootstrapContext source, ConfigurableApplicationContext applicationContext) {\n\t\tsuper(source);\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t/**\n\t * Return the {@link BootstrapContext} that was closed.\n\t * @return the bootstrap context\n\t */\n\tpublic BootstrapContext getBootstrapContext() {\n\t\treturn (BootstrapContext) this.source;\n\t}\n\n\t/**\n\t * Return the prepared application context.\n\t * @return the application context\n\t */\n\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/BootstrapRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * A simple object registry that is available during startup and {@link Environment}\n * post-processing up to the point that the {@link ApplicationContext} is prepared.\n * <p>\n * Can be used to register instances that may be expensive to create, or need to be shared\n * before the {@link ApplicationContext} is available.\n * <p>\n * The registry uses {@link Class} as a key, meaning that only a single instance of a\n * given type can be stored.\n * <p>\n * The {@link #addCloseListener(ApplicationListener)} method can be used to add a listener\n * that can perform actions when {@link BootstrapContext} has been closed and the\n * {@link ApplicationContext} is fully prepared. For example, an instance may choose to\n * register itself as a regular Spring bean so that it is available for the application to\n * use.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see BootstrapContext\n * @see ConfigurableBootstrapContext\n */\npublic interface BootstrapRegistry {\n\n\t/**\n\t * Register a specific type with the registry. If the specified type has already been\n\t * registered and has not been obtained as a {@link Scope#SINGLETON singleton}, it\n\t * will be replaced.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @param instanceSupplier the instance supplier\n\t */\n\t<T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier);\n\n\t/**\n\t * Register a specific type with the registry if one is not already present.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @param instanceSupplier the instance supplier\n\t */\n\t<T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier);\n\n\t/**\n\t * Return if a registration exists for the given type.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @return {@code true} if the type has already been registered\n\t */\n\t<T> boolean isRegistered(Class<T> type);\n\n\t/**\n\t * Return any existing {@link InstanceSupplier} for the given type.\n\t * @param <T> the instance type\n\t * @param type the instance type\n\t * @return the registered {@link InstanceSupplier} or {@code null}\n\t */\n\t<T> @Nullable InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type);\n\n\t/**\n\t * Add an {@link ApplicationListener} that will be called with a\n\t * {@link BootstrapContextClosedEvent} when the {@link BootstrapContext} is closed and\n\t * the {@link ApplicationContext} has been prepared.\n\t * @param listener the listener to add\n\t */\n\tvoid addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);\n\n\t/**\n\t * Supplier used to provide the actual instance when needed.\n\t *\n\t * @param <T> the instance type\n\t * @see Scope\n\t */\n\t@FunctionalInterface\n\tinterface InstanceSupplier<T> {\n\n\t\t/**\n\t\t * Factory method used to create the instance when needed.\n\t\t * @param context the {@link BootstrapContext} which may be used to obtain other\n\t\t * bootstrap instances.\n\t\t * @return the instance or {@code null}\n\t\t */\n\t\t@Nullable T get(BootstrapContext context);\n\n\t\t/**\n\t\t * Return the scope of the supplied instance.\n\t\t * @return the scope\n\t\t */\n\t\tdefault Scope getScope() {\n\t\t\treturn Scope.SINGLETON;\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link InstanceSupplier} with an updated {@link Scope}.\n\t\t * @param scope the new scope\n\t\t * @return a new {@link InstanceSupplier} instance with the new scope\n\t\t */\n\t\tdefault InstanceSupplier<T> withScope(Scope scope) {\n\t\t\tAssert.notNull(scope, \"'scope' must not be null\");\n\t\t\tInstanceSupplier<T> parent = this;\n\t\t\treturn new InstanceSupplier<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable T get(BootstrapContext context) {\n\t\t\t\t\treturn parent.get(context);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Scope getScope() {\n\t\t\t\t\treturn scope;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Factory method that can be used to create an {@link InstanceSupplier} for a\n\t\t * given instance.\n\t\t * @param <T> the instance type\n\t\t * @param instance the instance\n\t\t * @return a new {@link InstanceSupplier}\n\t\t */\n\t\tstatic <T> InstanceSupplier<T> of(@Nullable T instance) {\n\t\t\treturn (registry) -> instance;\n\t\t}\n\n\t\t/**\n\t\t * Factory method that can be used to create an {@link InstanceSupplier} from a\n\t\t * {@link Supplier}.\n\t\t * @param <T> the instance type\n\t\t * @param supplier the supplier that will provide the instance\n\t\t * @return a new {@link InstanceSupplier}\n\t\t */\n\t\tstatic <T> InstanceSupplier<T> from(@Nullable Supplier<T> supplier) {\n\t\t\treturn (registry) -> (supplier != null) ? supplier.get() : null;\n\t\t}\n\n\t}\n\n\t/**\n\t * The scope of an instance.\n\t */\n\tenum Scope {\n\n\t\t/**\n\t\t * A singleton instance. The {@link InstanceSupplier} will be called only once and\n\t\t * the same instance will be returned each time.\n\t\t */\n\t\tSINGLETON,\n\n\t\t/**\n\t\t * A prototype instance. The {@link InstanceSupplier} will be called whenever an\n\t\t * instance is needed.\n\t\t */\n\t\tPROTOTYPE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/BootstrapRegistryInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\n/**\n * Callback interface that can be used to initialize a {@link BootstrapRegistry} before it\n * is used.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see BootstrapRegistry\n */\n@FunctionalInterface\npublic interface BootstrapRegistryInitializer {\n\n\t/**\n\t * Initialize the given {@link BootstrapRegistry} with any required registrations.\n\t * @param registry the registry to initialize\n\t */\n\tvoid initialize(BootstrapRegistry registry);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/ConfigurableBootstrapContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\n/**\n * A {@link BootstrapContext} that also provides configuration methods through the\n * {@link BootstrapRegistry} interface.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see BootstrapRegistry\n * @see BootstrapContext\n * @see DefaultBootstrapContext\n */\npublic interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/DefaultBootstrapContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.ApplicationEventMulticaster;\nimport org.springframework.context.event.SimpleApplicationEventMulticaster;\nimport org.springframework.util.Assert;\n\n/**\n * Default {@link ConfigurableBootstrapContext} implementation.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DefaultBootstrapContext implements ConfigurableBootstrapContext {\n\n\tprivate final Map<Class<?>, InstanceSupplier<?>> instanceSuppliers = new HashMap<>();\n\n\tprivate final Map<Class<?>, Object> instances = new HashMap<>();\n\n\tprivate final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();\n\n\t@Override\n\tpublic <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier) {\n\t\tregister(type, instanceSupplier, true);\n\t}\n\n\t@Override\n\tpublic <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier) {\n\t\tregister(type, instanceSupplier, false);\n\t}\n\n\tprivate <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier, boolean replaceExisting) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tAssert.notNull(instanceSupplier, \"'instanceSupplier' must not be null\");\n\t\tsynchronized (this.instanceSuppliers) {\n\t\t\tboolean alreadyRegistered = this.instanceSuppliers.containsKey(type);\n\t\t\tif (replaceExisting || !alreadyRegistered) {\n\t\t\t\tAssert.state(!this.instances.containsKey(type), () -> type.getName() + \" has already been created\");\n\t\t\t\tthis.instanceSuppliers.put(type, instanceSupplier);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T> boolean isRegistered(Class<T> type) {\n\t\tsynchronized (this.instanceSuppliers) {\n\t\t\treturn this.instanceSuppliers.containsKey(type);\n\t\t}\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> @Nullable InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type) {\n\t\tsynchronized (this.instanceSuppliers) {\n\t\t\treturn (InstanceSupplier<T>) this.instanceSuppliers.get(type);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener) {\n\t\tthis.events.addApplicationListener(listener);\n\t}\n\n\t@Override\n\tpublic <T> @Nullable T get(Class<T> type) throws IllegalStateException {\n\t\treturn getOrElseThrow(type, () -> new IllegalStateException(type.getName() + \" has not been registered\"));\n\t}\n\n\t@Override\n\tpublic <T> @Nullable T getOrElse(Class<T> type, @Nullable T other) {\n\t\tSupplier<@Nullable T> supplier = () -> other;\n\t\treturn getOrElseSupply(type, supplier);\n\t}\n\n\t@Override\n\tpublic <T> @Nullable T getOrElseSupply(Class<T> type, Supplier<@Nullable T> other) {\n\t\tsynchronized (this.instanceSuppliers) {\n\t\t\tInstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);\n\t\t\treturn (instanceSupplier != null) ? getInstance(type, instanceSupplier) : other.get();\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T, X extends Throwable> @Nullable T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier)\n\t\t\tthrows X {\n\t\tsynchronized (this.instanceSuppliers) {\n\t\t\tInstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);\n\t\t\tif (instanceSupplier == null) {\n\t\t\t\tthrow exceptionSupplier.get();\n\t\t\t}\n\t\t\treturn getInstance(type, instanceSupplier);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T getInstance(Class<T> type, InstanceSupplier<?> instanceSupplier) {\n\t\tT instance = (T) this.instances.get(type);\n\t\tif (instance == null) {\n\t\t\tinstance = (T) instanceSupplier.get(this);\n\t\t\tif (instance == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (instanceSupplier.getScope() == Scope.SINGLETON) {\n\t\t\t\tthis.instances.put(type, instance);\n\t\t\t}\n\t\t}\n\t\treturn instance;\n\t}\n\n\t/**\n\t * Method to be called when {@link BootstrapContext} is closed and the\n\t * {@link ApplicationContext} is prepared.\n\t * @param applicationContext the prepared context\n\t */\n\tpublic void close(ConfigurableApplicationContext applicationContext) {\n\t\tthis.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/bootstrap/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Bootstrap concerns to support the creation of potentially expensive singletons while\n * the application starts.\n */\n@NullMarked\npackage org.springframework.boot.bootstrap;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.builder;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link ApplicationContextInitializer} for setting the parent context. Also publishes\n * {@link ParentContextAvailableEvent} when the context is refreshed to signal to other\n * listeners that the context is available and has a parent.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\npublic class ParentContextApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {\n\n\tprivate int order = Ordered.HIGHEST_PRECEDENCE;\n\n\tprivate final ApplicationContext parent;\n\n\tpublic ParentContextApplicationContextInitializer(ApplicationContext parent) {\n\t\tthis.parent = parent;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tif (applicationContext != this.parent) {\n\t\t\tapplicationContext.setParent(this.parent);\n\t\t\tapplicationContext.addApplicationListener(EventPublisher.INSTANCE);\n\t\t}\n\t}\n\n\tprivate static final class EventPublisher implements ApplicationListener<ContextRefreshedEvent>, Ordered {\n\n\t\tprivate static final EventPublisher INSTANCE = new EventPublisher();\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextRefreshedEvent event) {\n\t\t\tApplicationContext context = event.getApplicationContext();\n\t\t\tif (context instanceof ConfigurableApplicationContext configurableApplicationContext\n\t\t\t\t\t&& context == event.getSource()) {\n\t\t\t\tcontext.publishEvent(new ParentContextAvailableEvent(configurableApplicationContext));\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ApplicationEvent} fired when a parent context is available.\n\t */\n\tpublic static class ParentContextAvailableEvent extends ApplicationEvent {\n\n\t\tpublic ParentContextAvailableEvent(ConfigurableApplicationContext applicationContext) {\n\t\t\tsuper(applicationContext);\n\t\t}\n\n\t\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\t\treturn (ConfigurableApplicationContext) getSource();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/builder/ParentContextCloserApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.builder;\n\nimport java.lang.ref.WeakReference;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.boot.builder.ParentContextApplicationContextInitializer.ParentContextAvailableEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Listener that closes the application context if its parent is closed. It listens for\n * refresh events and grabs the current context from there, and then listens for closed\n * events and propagates it down the hierarchy.\n *\n * @author Dave Syer\n * @author Eric Bottard\n * @since 1.0.0\n */\npublic class ParentContextCloserApplicationListener\n\t\timplements ApplicationListener<ParentContextAvailableEvent>, ApplicationContextAware, Ordered {\n\n\tprivate static final int ORDER = Ordered.LOWEST_PRECEDENCE - 10;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext context;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext context) throws BeansException {\n\t\tthis.context = context;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ParentContextAvailableEvent event) {\n\t\tmaybeInstallListenerInParent(event.getApplicationContext());\n\t}\n\n\tprivate void maybeInstallListenerInParent(ConfigurableApplicationContext child) {\n\t\tif (child == this.context && child.getParent() instanceof ConfigurableApplicationContext parent) {\n\t\t\tparent.addApplicationListener(createContextCloserListener(child));\n\t\t}\n\t}\n\n\t/**\n\t * Subclasses may override to create their own subclass of ContextCloserListener. This\n\t * still enforces the use of a weak reference.\n\t * @param child the child context\n\t * @return the {@link ContextCloserListener} to use\n\t */\n\tprotected ContextCloserListener createContextCloserListener(ConfigurableApplicationContext child) {\n\t\treturn new ContextCloserListener(child);\n\t}\n\n\t/**\n\t * {@link ApplicationListener} to close the context.\n\t */\n\tprotected static class ContextCloserListener implements ApplicationListener<ContextClosedEvent> {\n\n\t\tprivate final WeakReference<ConfigurableApplicationContext> childContext;\n\n\t\tpublic ContextCloserListener(ConfigurableApplicationContext childContext) {\n\t\t\tthis.childContext = new WeakReference<>(childContext);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextClosedEvent event) {\n\t\t\tConfigurableApplicationContext context = this.childContext.get();\n\t\t\tif ((context != null) && (event.getApplicationContext() == context.getParent()) && context.isActive()) {\n\t\t\t\tcontext.close();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (obj instanceof ContextCloserListener other) {\n\t\t\t\treturn ObjectUtils.nullSafeEquals(this.childContext.get(), other.childContext.get());\n\t\t\t}\n\t\t\treturn super.equals(obj);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn ObjectUtils.nullSafeHashCode(this.childContext.get());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.builder;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.BootstrapRegistryInitializer;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.metrics.ApplicationStartup;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Builder for {@link SpringApplication} and {@link ApplicationContext} instances with\n * convenient fluent API and context hierarchy support. Simple example of a context\n * hierarchy:\n *\n * <pre class=\"code\">\n * new SpringApplicationBuilder(ParentConfig.class).child(ChildConfig.class).run(args);\n * </pre>\n *\n * Another common use case is setting active profiles and default properties to set up the\n * environment for an application:\n *\n * <pre class=\"code\">\n * new SpringApplicationBuilder(Application.class).profiles(&quot;server&quot;)\n * \t\t.properties(&quot;transport=local&quot;).run(args);\n * </pre>\n *\n * <p>\n * If your needs are simpler, consider using the static convenience methods in\n * SpringApplication instead.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 1.0.0\n * @see SpringApplication\n */\npublic class SpringApplicationBuilder {\n\n\tprivate final SpringApplication application;\n\n\tprivate volatile @Nullable ConfigurableApplicationContext context;\n\n\tprivate @Nullable SpringApplicationBuilder parent;\n\n\tprivate final AtomicBoolean running = new AtomicBoolean();\n\n\tprivate final Set<Class<?>> sources = new LinkedHashSet<>();\n\n\tprivate final Map<String, Object> defaultProperties = new LinkedHashMap<>();\n\n\tprivate @Nullable ConfigurableEnvironment environment;\n\n\tprivate Set<String> additionalProfiles = new LinkedHashSet<>();\n\n\tprivate boolean registerShutdownHookApplied;\n\n\tprivate boolean configuredAsChild;\n\n\tpublic SpringApplicationBuilder(Class<?>... sources) {\n\t\tthis(null, sources);\n\t}\n\n\tpublic SpringApplicationBuilder(@Nullable ResourceLoader resourceLoader, Class<?>... sources) {\n\t\tthis.application = createSpringApplication(resourceLoader, sources);\n\t}\n\n\t/**\n\t * Creates a new {@link SpringApplication} instance from the given sources using the\n\t * given {@link ResourceLoader}. Subclasses may override in order to provide a custom\n\t * subclass of {@link SpringApplication}.\n\t * @param resourceLoader the resource loader or {@code null}\n\t * @param sources the sources\n\t * @return the {@link SpringApplication} instance\n\t * @since 2.6.0\n\t */\n\tprotected SpringApplication createSpringApplication(@Nullable ResourceLoader resourceLoader, Class<?>... sources) {\n\t\treturn new SpringApplication(resourceLoader, sources);\n\t}\n\n\t/**\n\t * Accessor for the current application context.\n\t * @return the current application context (or {@code null} if not yet running)\n\t */\n\tpublic @Nullable ConfigurableApplicationContext context() {\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Accessor for the current application.\n\t * @return the current application (never null)\n\t */\n\tpublic SpringApplication application() {\n\t\treturn this.application;\n\t}\n\n\t/**\n\t * Create an application context (and its parent if specified) with the command line\n\t * args provided. The parent is run first with the same arguments if it has not yet\n\t * been started.\n\t * @param args the command line arguments\n\t * @return an application context created from the current state\n\t */\n\tpublic ConfigurableApplicationContext run(String... args) {\n\t\tif (this.running.get()) {\n\t\t\tConfigurableApplicationContext context = this.context;\n\t\t\tAssert.state(context != null, \"No context set\");\n\t\t\t// If already created we just return the existing context\n\t\t\treturn context;\n\t\t}\n\t\tconfigureAsChildIfNecessary(args);\n\t\tif (this.running.compareAndSet(false, true)) {\n\t\t\t// If not already running copy the sources over and then run.\n\t\t\tthis.context = build().run(args);\n\t\t}\n\t\tConfigurableApplicationContext context = this.context;\n\t\tAssert.state(context != null, \"No context set\");\n\t\treturn context;\n\t}\n\n\tprivate void configureAsChildIfNecessary(String... args) {\n\t\tif (this.parent != null && !this.configuredAsChild) {\n\t\t\tthis.configuredAsChild = true;\n\t\t\tif (!this.registerShutdownHookApplied) {\n\t\t\t\tthis.application.setRegisterShutdownHook(false);\n\t\t\t}\n\t\t\tinitializers(new ParentContextApplicationContextInitializer(this.parent.run(args)));\n\t\t}\n\t}\n\n\t/**\n\t * Returns a fully configured {@link SpringApplication} that is ready to run.\n\t * @return the fully configured {@link SpringApplication}.\n\t */\n\tpublic SpringApplication build() {\n\t\treturn build(new String[0]);\n\t}\n\n\t/**\n\t * Returns a fully configured {@link SpringApplication} that is ready to run. Any\n\t * parent that has been configured will be run with the given {@code args}.\n\t * @param args the parent's args\n\t * @return the fully configured {@link SpringApplication}.\n\t */\n\tpublic SpringApplication build(String... args) {\n\t\tconfigureAsChildIfNecessary(args);\n\t\tthis.application.addPrimarySources(this.sources);\n\t\treturn this.application;\n\t}\n\n\t/**\n\t * Create a child application with the provided sources. Default args and environment\n\t * are copied down into the child, but everything else is a clean sheet.\n\t * @param sources the sources for the application (Spring configuration)\n\t * @return the child application builder\n\t */\n\tpublic SpringApplicationBuilder child(Class<?>... sources) {\n\t\tSpringApplicationBuilder child = new SpringApplicationBuilder();\n\t\tchild.sources(sources);\n\n\t\t// Copy environment stuff from parent to child\n\t\tchild.properties(this.defaultProperties)\n\t\t\t.environment(this.environment)\n\t\t\t.additionalProfiles(this.additionalProfiles);\n\t\tchild.parent = this;\n\n\t\t// It's not possible if embedded web server are enabled to support web contexts as\n\t\t// parents because the servlets cannot be initialized at the right point in\n\t\t// lifecycle.\n\t\tweb(WebApplicationType.NONE);\n\n\t\t// Probably not interested in multiple banners\n\t\tbannerMode(Banner.Mode.OFF);\n\n\t\t// Make sure sources get copied over\n\t\tthis.application.addPrimarySources(this.sources);\n\n\t\treturn child;\n\t}\n\n\t/**\n\t * Add a parent application with the provided sources. Default args and environment\n\t * are copied up into the parent, but everything else is a clean sheet.\n\t * @param sources the sources for the application (Spring configuration)\n\t * @return the parent builder\n\t */\n\tpublic SpringApplicationBuilder parent(Class<?>... sources) {\n\t\tif (this.parent == null) {\n\t\t\tthis.parent = new SpringApplicationBuilder(sources).web(WebApplicationType.NONE)\n\t\t\t\t.properties(this.defaultProperties)\n\t\t\t\t.environment(this.environment);\n\t\t}\n\t\telse {\n\t\t\tthis.parent.sources(sources);\n\t\t}\n\t\treturn this.parent;\n\t}\n\n\tprivate SpringApplicationBuilder runAndExtractParent(String... args) {\n\t\tif (this.context == null) {\n\t\t\trun(args);\n\t\t}\n\t\tif (this.parent != null) {\n\t\t\treturn this.parent;\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"No parent defined yet (please use the other overloaded parent methods to set one)\");\n\t}\n\n\t/**\n\t * Add an already running parent context to an existing application.\n\t * @param parent the parent context\n\t * @return the current builder (not the parent)\n\t */\n\tpublic SpringApplicationBuilder parent(ConfigurableApplicationContext parent) {\n\t\tthis.parent = new SpringApplicationBuilder();\n\t\tthis.parent.context = parent;\n\t\tthis.parent.running.set(true);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Create a sibling application (one with the same parent). A side effect of calling\n\t * this method is that the current application (and its parent) are started without\n\t * any arguments if they are not already running. To supply arguments when starting\n\t * the current application and its parent use {@link #sibling(Class[], String...)}\n\t * instead.\n\t * @param sources the sources for the application (Spring configuration)\n\t * @return the new sibling builder\n\t */\n\tpublic SpringApplicationBuilder sibling(Class<?>... sources) {\n\t\treturn runAndExtractParent().child(sources);\n\t}\n\n\t/**\n\t * Create a sibling application (one with the same parent). A side effect of calling\n\t * this method is that the current application (and its parent) are started if they\n\t * are not already running.\n\t * @param sources the sources for the application (Spring configuration)\n\t * @param args the command line arguments to use when starting the current app and its\n\t * parent\n\t * @return the new sibling builder\n\t */\n\tpublic SpringApplicationBuilder sibling(Class<?>[] sources, String... args) {\n\t\treturn runAndExtractParent(args).child(sources);\n\t}\n\n\t/**\n\t * Explicitly set the factory used to create the application context.\n\t * @param factory the factory to use\n\t * @return the current builder\n\t * @since 2.4.0\n\t */\n\tpublic SpringApplicationBuilder contextFactory(ApplicationContextFactory factory) {\n\t\tthis.application.setApplicationContextFactory(factory);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add more sources (configuration classes and components) to this application.\n\t * @param sources the sources to add\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder sources(Class<?>... sources) {\n\t\tthis.sources.addAll(new LinkedHashSet<>(Arrays.asList(sources)));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Flag to explicitly request a specific type of web application. Auto-detected based\n\t * on the classpath if not set.\n\t * @param webApplicationType the type of web application\n\t * @return the current builder\n\t * @since 2.0.0\n\t */\n\tpublic SpringApplicationBuilder web(WebApplicationType webApplicationType) {\n\t\tthis.application.setWebApplicationType(webApplicationType);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Flag to indicate the startup information should be logged.\n\t * @param logStartupInfo the flag to set. Default true.\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder logStartupInfo(boolean logStartupInfo) {\n\t\tthis.application.setLogStartupInfo(logStartupInfo);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the {@link Banner} instance which will be used to print the banner when no\n\t * static banner file is provided.\n\t * @param banner the banner to use\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder banner(Banner banner) {\n\t\tthis.application.setBanner(banner);\n\t\treturn this;\n\t}\n\n\tpublic SpringApplicationBuilder bannerMode(Banner.Mode bannerMode) {\n\t\tthis.application.setBannerMode(bannerMode);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets if the application is headless and should not instantiate AWT. Defaults to\n\t * {@code true} to prevent java icons appearing.\n\t * @param headless if the application is headless\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder headless(boolean headless) {\n\t\tthis.application.setHeadless(headless);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets if the created {@link ApplicationContext} should have a shutdown hook\n\t * registered.\n\t * @param registerShutdownHook if the shutdown hook should be registered\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder registerShutdownHook(boolean registerShutdownHook) {\n\t\tthis.registerShutdownHookApplied = true;\n\t\tthis.application.setRegisterShutdownHook(registerShutdownHook);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Fixes the main application class that is used to anchor the startup messages.\n\t * @param mainApplicationClass the class to use.\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder main(Class<?> mainApplicationClass) {\n\t\tthis.application.setMainApplicationClass(mainApplicationClass);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Flag to indicate that command line arguments should be added to the environment.\n\t * @param addCommandLineProperties the flag to set. Default true.\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder addCommandLineProperties(boolean addCommandLineProperties) {\n\t\tthis.application.setAddCommandLineProperties(addCommandLineProperties);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Flag to indicate if the {@link ApplicationConversionService} should be added to the\n\t * application context's {@link Environment}.\n\t * @param addConversionService if the conversion service should be added.\n\t * @return the current builder\n\t * @since 2.1.0\n\t */\n\tpublic SpringApplicationBuilder setAddConversionService(boolean addConversionService) {\n\t\tthis.application.setAddConversionService(addConversionService);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds {@link BootstrapRegistryInitializer} instances that can be used to initialize\n\t * the {@link BootstrapRegistry}.\n\t * @param bootstrapRegistryInitializer the bootstrap registry initializer to add\n\t * @return the current builder\n\t * @since 2.4.5\n\t */\n\tpublic SpringApplicationBuilder addBootstrapRegistryInitializer(\n\t\t\tBootstrapRegistryInitializer bootstrapRegistryInitializer) {\n\t\tthis.application.addBootstrapRegistryInitializer(bootstrapRegistryInitializer);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Flag to control whether the application should be initialized lazily.\n\t * @param lazyInitialization the flag to set. Defaults to false.\n\t * @return the current builder\n\t * @since 2.2\n\t */\n\tpublic SpringApplicationBuilder lazyInitialization(boolean lazyInitialization) {\n\t\tthis.application.setLazyInitialization(lazyInitialization);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Default properties for the environment in the form {@code key=value} or\n\t * {@code key:value}. Multiple calls to this method are cumulative and will not clear\n\t * any previously set properties.\n\t * @param defaultProperties the properties to set.\n\t * @return the current builder\n\t * @see SpringApplicationBuilder#properties(Properties)\n\t * @see SpringApplicationBuilder#properties(Map)\n\t */\n\tpublic SpringApplicationBuilder properties(String... defaultProperties) {\n\t\treturn properties(getMapFromKeyValuePairs(defaultProperties));\n\t}\n\n\tprivate Map<String, Object> getMapFromKeyValuePairs(String[] properties) {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tfor (String property : properties) {\n\t\t\tint index = lowestIndexOf(property, \":\", \"=\");\n\t\t\tString key = (index > 0) ? property.substring(0, index) : property;\n\t\t\tString value = (index > 0) ? property.substring(index + 1) : \"\";\n\t\t\tmap.put(key, value);\n\t\t}\n\t\treturn map;\n\t}\n\n\tprivate int lowestIndexOf(String property, String... candidates) {\n\t\tint index = -1;\n\t\tfor (String candidate : candidates) {\n\t\t\tint candidateIndex = property.indexOf(candidate);\n\t\t\tif (candidateIndex > 0) {\n\t\t\t\tindex = (index != -1) ? Math.min(index, candidateIndex) : candidateIndex;\n\t\t\t}\n\t\t}\n\t\treturn index;\n\t}\n\n\t/**\n\t * Default properties for the environment.Multiple calls to this method are cumulative\n\t * and will not clear any previously set properties.\n\t * @param defaultProperties the properties to set.\n\t * @return the current builder\n\t * @see SpringApplicationBuilder#properties(String...)\n\t * @see SpringApplicationBuilder#properties(Map)\n\t */\n\tpublic SpringApplicationBuilder properties(Properties defaultProperties) {\n\t\treturn properties(getMapFromProperties(defaultProperties));\n\t}\n\n\tprivate Map<String, Object> getMapFromProperties(Properties properties) {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tfor (Object key : Collections.list(properties.propertyNames())) {\n\t\t\tmap.put((String) key, properties.get(key));\n\t\t}\n\t\treturn map;\n\t}\n\n\t/**\n\t * Default properties for the environment. Multiple calls to this method are\n\t * cumulative and will not clear any previously set properties.\n\t * @param defaults the default properties\n\t * @return the current builder\n\t * @see SpringApplicationBuilder#properties(String...)\n\t * @see SpringApplicationBuilder#properties(Properties)\n\t */\n\tpublic SpringApplicationBuilder properties(Map<String, Object> defaults) {\n\t\tthis.defaultProperties.putAll(defaults);\n\t\tthis.application.setDefaultProperties(this.defaultProperties);\n\t\tif (this.parent != null) {\n\t\t\tthis.parent.properties(this.defaultProperties);\n\t\t\tthis.parent.environment(this.environment);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add to the active Spring profiles for this app (and its parent and children).\n\t * @param profiles the profiles to add.\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder profiles(String... profiles) {\n\t\tthis.additionalProfiles.addAll(Arrays.asList(profiles));\n\t\tthis.application.setAdditionalProfiles(StringUtils.toStringArray(this.additionalProfiles));\n\t\treturn this;\n\t}\n\n\tprivate SpringApplicationBuilder additionalProfiles(Collection<String> additionalProfiles) {\n\t\tthis.additionalProfiles = new LinkedHashSet<>(additionalProfiles);\n\t\tthis.application.setAdditionalProfiles(StringUtils.toStringArray(this.additionalProfiles));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Bean name generator for automatically generated bean names in the application\n\t * context.\n\t * @param beanNameGenerator the generator to set.\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder beanNameGenerator(BeanNameGenerator beanNameGenerator) {\n\t\tthis.application.setBeanNameGenerator(beanNameGenerator);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Environment for the application context.\n\t * @param environment the environment to set\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder environment(@Nullable ConfigurableEnvironment environment) {\n\t\tthis.application.setEnvironment(environment);\n\t\tthis.environment = environment;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Prefix that should be applied when obtaining configuration properties from the\n\t * system environment.\n\t * @param environmentPrefix the environment property prefix to set\n\t * @return the current builder\n\t * @since 2.5.0\n\t */\n\tpublic SpringApplicationBuilder environmentPrefix(String environmentPrefix) {\n\t\tthis.application.setEnvironmentPrefix(environmentPrefix);\n\t\treturn this;\n\t}\n\n\t/**\n\t * {@link ResourceLoader} for the application context. If a custom class loader is\n\t * needed, this is where it would be added.\n\t * @param resourceLoader the resource loader to set.\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder resourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.application.setResourceLoader(resourceLoader);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add some initializers to the application (applied to the {@link ApplicationContext}\n\t * before any bean definitions are loaded).\n\t * @param initializers some initializers to add\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder initializers(ApplicationContextInitializer<?>... initializers) {\n\t\tthis.application.addInitializers(initializers);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add some listeners to the application (listening for SpringApplication events as\n\t * well as regular Spring events once the context is running). Any listeners that are\n\t * also {@link ApplicationContextInitializer} will be added to the\n\t * {@link #initializers(ApplicationContextInitializer...) initializers} automatically.\n\t * @param listeners some listeners to add\n\t * @return the current builder\n\t */\n\tpublic SpringApplicationBuilder listeners(ApplicationListener<?>... listeners) {\n\t\tthis.application.addListeners(listeners);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Configure the {@link ApplicationStartup} to be used with the\n\t * {@link ApplicationContext} for collecting startup metrics.\n\t * @param applicationStartup the application startup to use\n\t * @return the current builder\n\t * @since 2.4.0\n\t */\n\tpublic SpringApplicationBuilder applicationStartup(ApplicationStartup applicationStartup) {\n\t\tthis.application.setApplicationStartup(applicationStartup);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Whether to allow circular references between beans and automatically try to resolve\n\t * them.\n\t * @param allowCircularReferences whether circular references are allowed\n\t * @return the current builder\n\t * @since 2.6.0\n\t * @see AbstractAutowireCapableBeanFactory#setAllowCircularReferences(boolean)\n\t */\n\tpublic SpringApplicationBuilder allowCircularReferences(boolean allowCircularReferences) {\n\t\tthis.application.setAllowCircularReferences(allowCircularReferences);\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/builder/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Fluent 'builder' style API to construct a\n * {@link org.springframework.boot.SpringApplication}.\n *\n * @see org.springframework.boot.builder.SpringApplicationBuilder\n */\n@NullMarked\npackage org.springframework.boot.builder;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloud;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;\nimport org.springframework.boot.json.JsonParser;\nimport org.springframework.boot.json.JsonParserFactory;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.CommandLinePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertiesPropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link EnvironmentPostProcessor} that knows where to find VCAP (a.k.a. Cloud\n * Foundry) metadata in the existing environment. It parses out the VCAP_APPLICATION and\n * VCAP_SERVICES metadata and dumps it in a form that is easily consumed by\n * {@link Environment} users. If the app is running in Cloud Foundry then both metadata\n * items are JSON objects encoded in OS environment variables. VCAP_APPLICATION is a\n * shallow hash with basic information about the application (name, instance id, instance\n * index, etc.), and VCAP_SERVICES is a hash of lists where the keys are service labels\n * and the values are lists of hashes of service instance metadata. Examples are:\n *\n * <pre class=\"code\">\n * VCAP_APPLICATION: {\"instance_id\":\"2ce0ac627a6c8e47e936d829a3a47b5b\",\"instance_index\":0,\n *   \"version\":\"0138c4a6-2a73-416b-aca0-572c09f7ca53\",\"name\":\"foo\",\n *   \"uris\":[\"foo.cfapps.io\"], ...}\n * VCAP_SERVICES: {\"rds-mysql-1.0\":[{\"name\":\"mysql\",\"label\":\"rds-mysql-1.0\",\"plan\":\"10mb\",\n *   \"credentials\":{\"name\":\"d04fb13d27d964c62b267bbba1cffb9da\",\"hostname\":\"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\",\n *   \"host\":\"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\",\"port\":3306,\"user\":\"urpRuqTf8Cpe6\",\n *   \"username\":\"urpRuqTf8Cpe6\",\"password\":\"pxLsGVpsC9A5S\"}\n * }]}\n * </pre>\n *\n * These objects are flattened into properties. The VCAP_APPLICATION object goes straight\n * to {@code vcap.application.*} in a fairly obvious way, and the VCAP_SERVICES object is\n * unwrapped so that it is a hash of objects with key equal to the service instance name\n * (e.g. \"mysql\" in the example above), and value equal to that instances properties, and\n * then flattened in the same way. E.g.\n *\n * <pre class=\"code\">\n * vcap.application.instance_id: 2ce0ac627a6c8e47e936d829a3a47b5b\n * vcap.application.version: 0138c4a6-2a73-416b-aca0-572c09f7ca53\n * vcap.application.name: foo\n * vcap.application.uris[0]: foo.cfapps.io\n *\n * vcap.services.mysql.name: mysql\n * vcap.services.mysql.label: rds-mysql-1.0\n * vcap.services.mysql.credentials.name: d04fb13d27d964c62b267bbba1cffb9da\n * vcap.services.mysql.credentials.port: 3306\n * vcap.services.mysql.credentials.host: mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\n * vcap.services.mysql.credentials.username: urpRuqTf8Cpe6\n * vcap.services.mysql.credentials.password: pxLsGVpsC9A5S\n * ...\n * </pre>\n *\n * N.B. this initializer is mainly intended for informational use (the application and\n * instance ids are particularly useful). For service binding you might find that Spring\n * Cloud is more convenient and more robust against potential changes in Cloud Foundry.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 1.3.0\n */\npublic class CloudFoundryVcapEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\tprivate final Log logger;\n\n\t// Before ConfigDataEnvironmentPostProcessor so values there can use these\n\tprivate int order = ConfigDataEnvironmentPostProcessor.ORDER - 5;\n\n\t/**\n\t * Create a new {@link CloudFoundryVcapEnvironmentPostProcessor} instance.\n\t * @param logFactory the log factory to use\n\t * @since 3.0.0\n\t */\n\tpublic CloudFoundryVcapEnvironmentPostProcessor(DeferredLogFactory logFactory) {\n\t\tthis.logger = logFactory.getLog(CloudFoundryVcapEnvironmentPostProcessor.class);\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) {\n\t\t\tProperties properties = new Properties();\n\t\t\tJsonParser jsonParser = JsonParserFactory.getJsonParser();\n\t\t\taddWithPrefix(properties, getPropertiesFromApplication(environment, jsonParser), \"vcap.application.\");\n\t\t\taddWithPrefix(properties, getPropertiesFromServices(environment, jsonParser), \"vcap.services.\");\n\t\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\t\tPropertiesPropertySource vcapSource = new PropertiesPropertySource(\"vcap\", properties);\n\t\t\tif (propertySources.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {\n\t\t\t\tpropertySources.addAfter(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME, vcapSource);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpropertySources.addFirst(vcapSource);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addWithPrefix(Properties properties, Properties other, String prefix) {\n\t\tfor (String key : other.stringPropertyNames()) {\n\t\t\tString prefixed = prefix + key;\n\t\t\tproperties.setProperty(prefixed, other.getProperty(key));\n\t\t}\n\t}\n\n\tprivate Properties getPropertiesFromApplication(Environment environment, JsonParser parser) {\n\t\tProperties properties = new Properties();\n\t\ttry {\n\t\t\tString property = environment.getProperty(\"VCAP_APPLICATION\", \"{}\");\n\t\t\tMap<String, Object> map = parser.parseMap(property);\n\t\t\textractPropertiesFromApplication(properties, map);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.logger.error(\"Could not parse VCAP_APPLICATION\", ex);\n\t\t}\n\t\treturn properties;\n\t}\n\n\tprivate Properties getPropertiesFromServices(Environment environment, JsonParser parser) {\n\t\tProperties properties = new Properties();\n\t\ttry {\n\t\t\tString property = environment.getProperty(\"VCAP_SERVICES\", \"{}\");\n\t\t\tMap<String, Object> map = parser.parseMap(property);\n\t\t\textractPropertiesFromServices(properties, map);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.logger.error(\"Could not parse VCAP_SERVICES\", ex);\n\t\t}\n\t\treturn properties;\n\t}\n\n\tprivate void extractPropertiesFromApplication(Properties properties, @Nullable Map<String, Object> map) {\n\t\tif (map != null) {\n\t\t\tflatten(properties, map, \"\");\n\t\t}\n\t}\n\n\tprivate void extractPropertiesFromServices(Properties properties, @Nullable Map<String, Object> map) {\n\t\tif (map != null) {\n\t\t\tfor (Object services : map.values()) {\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tList<Object> list = (List<Object>) services;\n\t\t\t\tfor (Object object : list) {\n\t\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\t\tMap<String, Object> service = (Map<String, Object>) object;\n\t\t\t\t\tString key = (String) service.get(\"name\");\n\t\t\t\t\tif (key == null) {\n\t\t\t\t\t\tkey = (String) service.get(\"label\");\n\t\t\t\t\t}\n\t\t\t\t\tflatten(properties, service, key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void flatten(Properties properties, Map<String, Object> input, @Nullable String path) {\n\t\tinput.forEach((key, value) -> {\n\t\t\tString name = getPropertyName(path, key);\n\t\t\tif (value instanceof Map) {\n\t\t\t\t// Need a compound key\n\t\t\t\tflatten(properties, (Map<String, Object>) value, name);\n\t\t\t}\n\t\t\telse if (value instanceof Collection<?> collection) {\n\t\t\t\t// Need a compound key\n\t\t\t\tproperties.put(name, StringUtils.collectionToCommaDelimitedString(collection));\n\t\t\t\tint count = 0;\n\t\t\t\tfor (Object item : collection) {\n\t\t\t\t\tString itemKey = \"[\" + (count++) + \"]\";\n\t\t\t\t\tflatten(properties, Collections.singletonMap(itemKey, item), name);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (value instanceof String) {\n\t\t\t\tproperties.put(name, value);\n\t\t\t}\n\t\t\telse if (value instanceof Number || value instanceof Boolean) {\n\t\t\t\tproperties.put(name, value.toString());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tproperties.put(name, (value != null) ? value : \"\");\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate String getPropertyName(@Nullable String path, String key) {\n\t\tif (!StringUtils.hasText(path)) {\n\t\t\treturn key;\n\t\t}\n\t\tif (key.startsWith(\"[\")) {\n\t\t\treturn path + key;\n\t\t}\n\t\treturn path + \".\" + key;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/cloud/CloudPlatform.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloud;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * Simple detection for well known cloud platforms. Detection can be forced using the\n * {@code \"spring.main.cloud-platform\"} configuration property.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n * @author Nguyen Sach\n * @since 1.3.0\n */\npublic enum CloudPlatform {\n\n\t/**\n\t * No Cloud platform. Useful when false-positives are detected.\n\t */\n\tNONE {\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isUsingForwardHeaders() {\n\t\t\treturn false;\n\t\t}\n\t},\n\n\t/**\n\t * Cloud Foundry platform.\n\t */\n\tCLOUD_FOUNDRY {\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\treturn environment.containsProperty(\"VCAP_APPLICATION\") || environment.containsProperty(\"VCAP_SERVICES\");\n\t\t}\n\n\t},\n\n\t/**\n\t * Heroku platform.\n\t */\n\tHEROKU {\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\treturn environment.containsProperty(\"DYNO\");\n\t\t}\n\n\t},\n\n\t/**\n\t * SAP Cloud platform.\n\t */\n\tSAP {\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\treturn environment.containsProperty(\"HC_LANDSCAPE\");\n\t\t}\n\n\t},\n\n\t/**\n\t * Nomad platform.\n\t * @since 3.1.0\n\t */\n\tNOMAD {\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\treturn environment.containsProperty(\"NOMAD_ALLOC_ID\");\n\t\t}\n\n\t},\n\n\t/**\n\t * Kubernetes platform.\n\t */\n\tKUBERNETES {\n\n\t\tprivate static final String KUBERNETES_SERVICE_HOST = \"KUBERNETES_SERVICE_HOST\";\n\n\t\tprivate static final String KUBERNETES_SERVICE_PORT = \"KUBERNETES_SERVICE_PORT\";\n\n\t\tprivate static final String SERVICE_HOST_SUFFIX = \"_SERVICE_HOST\";\n\n\t\tprivate static final String SERVICE_PORT_SUFFIX = \"_SERVICE_PORT\";\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\tif (environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\t\treturn isAutoDetected(configurableEnvironment);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate boolean isAutoDetected(ConfigurableEnvironment environment) {\n\t\t\tPropertySource<?> environmentPropertySource = environment.getPropertySources()\n\t\t\t\t.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);\n\t\t\tif (environmentPropertySource != null) {\n\t\t\t\tif (environmentPropertySource.containsProperty(KUBERNETES_SERVICE_HOST)\n\t\t\t\t\t\t&& environmentPropertySource.containsProperty(KUBERNETES_SERVICE_PORT)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (environmentPropertySource instanceof EnumerablePropertySource<?> enumerablePropertySource) {\n\t\t\t\t\treturn isAutoDetected(enumerablePropertySource);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate boolean isAutoDetected(EnumerablePropertySource<?> environmentPropertySource) {\n\t\t\tfor (String propertyName : environmentPropertySource.getPropertyNames()) {\n\t\t\t\tif (propertyName.endsWith(SERVICE_HOST_SUFFIX)) {\n\t\t\t\t\tString serviceName = propertyName.substring(0,\n\t\t\t\t\t\t\tpropertyName.length() - SERVICE_HOST_SUFFIX.length());\n\t\t\t\t\tif (environmentPropertySource.getProperty(serviceName + SERVICE_PORT_SUFFIX) != null) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t},\n\n\t/**\n\t * Azure App Service platform.\n\t */\n\tAZURE_APP_SERVICE {\n\n\t\tprivate final List<String> azureEnvVariables = Arrays.asList(\"WEBSITE_SITE_NAME\", \"WEBSITE_INSTANCE_ID\",\n\t\t\t\t\"WEBSITE_RESOURCE_GROUP\", \"WEBSITE_SKU\");\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\treturn this.azureEnvVariables.stream().allMatch(environment::containsProperty);\n\t\t}\n\n\t},\n\n\t/**\n\t * Amazon Web Services (AWS) Elastic Container Service (ECS) platform.\n\t * @since 4.0.0\n\t */\n\tAWS_ECS {\n\n\t\t@Override\n\t\tpublic boolean isDetected(Environment environment) {\n\t\t\tString awsExecutionEnv = environment.getProperty(\"AWS_EXECUTION_ENV\");\n\t\t\treturn (awsExecutionEnv != null) && awsExecutionEnv.startsWith(\"AWS_ECS\");\n\t\t}\n\n\t};\n\n\tprivate static final String PROPERTY_NAME = \"spring.main.cloud-platform\";\n\n\t/**\n\t * Determines if the platform is active (i.e. the application is running in it).\n\t * @param environment the environment\n\t * @return if the platform is active.\n\t */\n\tpublic boolean isActive(Environment environment) {\n\t\tString platformProperty = environment.getProperty(PROPERTY_NAME);\n\t\treturn isEnforced(platformProperty) || (platformProperty == null && isDetected(environment));\n\t}\n\n\t/**\n\t * Determines if the platform is enforced by looking at the\n\t * {@code \"spring.main.cloud-platform\"} configuration property.\n\t * @param environment the environment\n\t * @return if the platform is enforced\n\t * @since 2.3.0\n\t */\n\tpublic boolean isEnforced(Environment environment) {\n\t\treturn isEnforced(environment.getProperty(PROPERTY_NAME));\n\t}\n\n\t/**\n\t * Determines if the platform is enforced by looking at the\n\t * {@code \"spring.main.cloud-platform\"} configuration property.\n\t * @param binder the binder\n\t * @return if the platform is enforced\n\t * @since 2.4.0\n\t */\n\tpublic boolean isEnforced(Binder binder) {\n\t\treturn isEnforced(binder.bind(PROPERTY_NAME, String.class).orElse(null));\n\t}\n\n\tprivate boolean isEnforced(@Nullable String platform) {\n\t\treturn name().equalsIgnoreCase(platform);\n\t}\n\n\t/**\n\t * Determines if the platform is detected by looking for platform-specific environment\n\t * variables.\n\t * @param environment the environment\n\t * @return if the platform is auto-detected.\n\t * @since 2.3.0\n\t */\n\tpublic abstract boolean isDetected(Environment environment);\n\n\t/**\n\t * Returns if the platform is behind a load balancer and uses\n\t * {@literal X-Forwarded-For} headers.\n\t * @return if {@literal X-Forwarded-For} headers are used\n\t */\n\tpublic boolean isUsingForwardHeaders() {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the active {@link CloudPlatform} or {@code null} if one is not active.\n\t * @param environment the environment\n\t * @return the {@link CloudPlatform} or {@code null}\n\t */\n\tpublic static @Nullable CloudPlatform getActive(@Nullable Environment environment) {\n\t\tif (environment != null) {\n\t\t\tfor (CloudPlatform cloudPlatform : values()) {\n\t\t\t\tif (cloudPlatform.isActive(environment)) {\n\t\t\t\t\treturn cloudPlatform;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/cloud/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Low level support for Cloud deployments.\n */\n@NullMarked\npackage org.springframework.boot.cloud;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/ApplicationPidFileWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.SpringApplicationEvent;\nimport org.springframework.boot.system.ApplicationPid;\nimport org.springframework.boot.system.SystemProperties;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * An {@link ApplicationListener} that saves application PID into file. This application\n * listener will be triggered exactly once per JVM, and the file name can be overridden at\n * runtime with a System property or environment variable named \"PIDFILE\" (or \"pidfile\")\n * or using a {@code spring.pid.file} property in the Spring {@link Environment}.\n * <p>\n * If PID file can not be created no exception is reported. This behavior can be changed\n * by assigning {@code true} to System property or environment variable named\n * {@code PID_FAIL_ON_WRITE_ERROR} (or \"pid_fail_on_write_error\") or to\n * {@code spring.pid.fail-on-write-error} property in the Spring {@link Environment}.\n * <p>\n * Note: access to the Spring {@link Environment} is only possible when the\n * {@link #setTriggerEventType(Class) triggerEventType} is set to\n * {@link ApplicationEnvironmentPreparedEvent}, {@link ApplicationReadyEvent}, or\n * {@link ApplicationPreparedEvent}.\n *\n * @author Jakub Kubrynski\n * @author Dave Syer\n * @author Phillip Webb\n * @author Tomasz Przybyla\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class ApplicationPidFileWriter implements ApplicationListener<SpringApplicationEvent>, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(ApplicationPidFileWriter.class);\n\n\tprivate static final String DEFAULT_FILE_NAME = \"application.pid\";\n\n\tprivate static final List<Property> FILE_PROPERTIES;\n\n\tstatic {\n\t\tList<Property> properties = new ArrayList<>();\n\t\tproperties.add(new SpringProperty(\"spring.pid.\", \"file\"));\n\t\tproperties.add(new SpringProperty(\"spring.\", \"pidfile\"));\n\t\tproperties.add(new SystemProperty(\"PIDFILE\"));\n\t\tFILE_PROPERTIES = Collections.unmodifiableList(properties);\n\t}\n\n\tprivate static final List<Property> FAIL_ON_WRITE_ERROR_PROPERTIES;\n\n\tstatic {\n\t\tList<Property> properties = new ArrayList<>();\n\t\tproperties.add(new SpringProperty(\"spring.pid.\", \"fail-on-write-error\"));\n\t\tproperties.add(new SystemProperty(\"PID_FAIL_ON_WRITE_ERROR\"));\n\t\tFAIL_ON_WRITE_ERROR_PROPERTIES = Collections.unmodifiableList(properties);\n\t}\n\n\tprivate static final AtomicBoolean created = new AtomicBoolean();\n\n\tprivate int order = Ordered.HIGHEST_PRECEDENCE + 13;\n\n\tprivate final File file;\n\n\tprivate Class<? extends SpringApplicationEvent> triggerEventType = ApplicationPreparedEvent.class;\n\n\t/**\n\t * Create a new {@link ApplicationPidFileWriter} instance using the filename\n\t * 'application.pid'.\n\t */\n\tpublic ApplicationPidFileWriter() {\n\t\tthis(new File(DEFAULT_FILE_NAME));\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationPidFileWriter} instance with a specified filename.\n\t * @param filename the name of file containing pid\n\t */\n\tpublic ApplicationPidFileWriter(String filename) {\n\t\tthis(new File(filename));\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationPidFileWriter} instance with a specified file.\n\t * @param file the file containing pid\n\t */\n\tpublic ApplicationPidFileWriter(File file) {\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tthis.file = file;\n\t}\n\n\t/**\n\t * Sets the type of application event that will trigger writing of the PID file.\n\t * Defaults to {@link ApplicationPreparedEvent}. NOTE: If you use the\n\t * {@link org.springframework.boot.context.event.ApplicationStartingEvent} to trigger\n\t * the write, you will not be able to specify the PID filename in the Spring\n\t * {@link Environment}.\n\t * @param triggerEventType the trigger event type\n\t */\n\tpublic void setTriggerEventType(Class<? extends SpringApplicationEvent> triggerEventType) {\n\t\tAssert.notNull(triggerEventType, \"'triggerEventType' must not be null\");\n\t\tthis.triggerEventType = triggerEventType;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(SpringApplicationEvent event) {\n\t\tif (this.triggerEventType.isInstance(event) && created.compareAndSet(false, true)) {\n\t\t\ttry {\n\t\t\t\twritePidFile(event);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tString message = String.format(\"Cannot create pid file %s\", this.file);\n\t\t\t\tif (failOnWriteError(event)) {\n\t\t\t\t\tthrow new IllegalStateException(message, ex);\n\t\t\t\t}\n\t\t\t\tlogger.warn(message, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void writePidFile(SpringApplicationEvent event) throws IOException {\n\t\tFile pidFile = this.file;\n\t\tString override = getProperty(event, FILE_PROPERTIES);\n\t\tif (override != null) {\n\t\t\tpidFile = new File(override);\n\t\t}\n\t\tnew ApplicationPid().write(pidFile);\n\t\tpidFile.deleteOnExit();\n\t}\n\n\tprivate boolean failOnWriteError(SpringApplicationEvent event) {\n\t\tString value = getProperty(event, FAIL_ON_WRITE_ERROR_PROPERTIES);\n\t\treturn Boolean.parseBoolean(value);\n\t}\n\n\tprivate @Nullable String getProperty(SpringApplicationEvent event, List<Property> candidates) {\n\t\tfor (Property candidate : candidates) {\n\t\t\tString value = candidate.getValue(event);\n\t\t\tif (value != null) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Reset the created flag for testing purposes.\n\t */\n\tprotected static void reset() {\n\t\tcreated.set(false);\n\t}\n\n\t/**\n\t * Provides access to a property value.\n\t */\n\tprivate interface Property {\n\n\t\t@Nullable String getValue(SpringApplicationEvent event);\n\n\t}\n\n\t/**\n\t * {@link Property} obtained from Spring's {@link Environment}.\n\t */\n\tprivate static class SpringProperty implements Property {\n\n\t\tprivate final String prefix;\n\n\t\tprivate final String key;\n\n\t\tSpringProperty(String prefix, String key) {\n\t\t\tthis.prefix = prefix;\n\t\t\tthis.key = key;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getValue(SpringApplicationEvent event) {\n\t\t\tEnvironment environment = getEnvironment(event);\n\t\t\tif (environment == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn environment.getProperty(this.prefix + this.key);\n\t\t}\n\n\t\tprivate @Nullable Environment getEnvironment(SpringApplicationEvent event) {\n\t\t\tif (event instanceof ApplicationEnvironmentPreparedEvent environmentPreparedEvent) {\n\t\t\t\treturn environmentPreparedEvent.getEnvironment();\n\t\t\t}\n\t\t\tif (event instanceof ApplicationPreparedEvent preparedEvent) {\n\t\t\t\treturn preparedEvent.getApplicationContext().getEnvironment();\n\t\t\t}\n\t\t\tif (event instanceof ApplicationReadyEvent readyEvent) {\n\t\t\t\treturn readyEvent.getApplicationContext().getEnvironment();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Property} obtained from {@link SystemProperties}.\n\t */\n\tprivate static class SystemProperty implements Property {\n\n\t\tprivate final String[] properties;\n\n\t\tSystemProperty(String name) {\n\t\t\tthis.properties = new String[] { name.toUpperCase(Locale.ENGLISH), name.toLowerCase(Locale.ENGLISH) };\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getValue(SpringApplicationEvent event) {\n\t\t\treturn SystemProperties.get(this.properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/ConfigurationWarningsApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationContextInitializer} to report warnings for common misconfiguration\n * mistakes.\n *\n * @author Phillip Webb\n * @since 1.2.0\n */\npublic class ConfigurationWarningsApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\tprivate static final Log logger = LogFactory.getLog(ConfigurationWarningsApplicationContextInitializer.class);\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext context) {\n\t\tcontext.addBeanFactoryPostProcessor(new ConfigurationWarningsPostProcessor(getChecks()));\n\t}\n\n\t/**\n\t * Returns the checks that should be applied.\n\t * @return the checks to apply\n\t */\n\tprotected Check[] getChecks() {\n\t\treturn new Check[] { new ComponentScanPackageCheck() };\n\t}\n\n\t/**\n\t * {@link BeanDefinitionRegistryPostProcessor} to report warnings.\n\t */\n\tprotected static final class ConfigurationWarningsPostProcessor\n\t\t\timplements PriorityOrdered, BeanDefinitionRegistryPostProcessor {\n\n\t\tprivate final Check[] checks;\n\n\t\tpublic ConfigurationWarningsPostProcessor(Check[] checks) {\n\t\t\tthis.checks = checks;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.LOWEST_PRECEDENCE - 1;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n\t\t\tfor (Check check : this.checks) {\n\t\t\t\tString message = check.getWarning(registry);\n\t\t\t\tif (StringUtils.hasLength(message)) {\n\t\t\t\t\twarn(message);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\tprivate void warn(String message) {\n\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(String.format(\"%n%n** WARNING ** : %s%n%n\", message));\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * A single check that can be applied.\n\t */\n\t@FunctionalInterface\n\tprotected interface Check {\n\n\t\t/**\n\t\t * Returns a warning if the check fails or {@code null} if there are no problems.\n\t\t * @param registry the {@link BeanDefinitionRegistry}\n\t\t * @return a warning message or {@code null}\n\t\t */\n\t\t@Nullable String getWarning(BeanDefinitionRegistry registry);\n\n\t}\n\n\t/**\n\t * {@link Check} for {@code @ComponentScan} on problematic package.\n\t */\n\tprotected static class ComponentScanPackageCheck implements Check {\n\n\t\tprivate static final Set<String> PROBLEM_PACKAGES;\n\n\t\tstatic {\n\t\t\tSet<String> packages = new HashSet<>();\n\t\t\tpackages.add(\"org.springframework\");\n\t\t\tpackages.add(\"org\");\n\t\t\tPROBLEM_PACKAGES = Collections.unmodifiableSet(packages);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getWarning(BeanDefinitionRegistry registry) {\n\t\t\tSet<String> scannedPackages = getComponentScanningPackages(registry);\n\t\t\tList<String> problematicPackages = getProblematicPackages(scannedPackages);\n\t\t\tif (problematicPackages.isEmpty()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn \"Your ApplicationContext is unlikely to start due to a @ComponentScan of \"\n\t\t\t\t\t+ StringUtils.collectionToDelimitedString(problematicPackages, \", \") + \".\";\n\t\t}\n\n\t\tprotected Set<String> getComponentScanningPackages(BeanDefinitionRegistry registry) {\n\t\t\tSet<String> packages = new LinkedHashSet<>();\n\t\t\tString[] names = registry.getBeanDefinitionNames();\n\t\t\tfor (String name : names) {\n\t\t\t\tBeanDefinition definition = registry.getBeanDefinition(name);\n\t\t\t\tif (definition instanceof AnnotatedBeanDefinition annotatedDefinition) {\n\t\t\t\t\taddComponentScanningPackages(packages, annotatedDefinition.getMetadata());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn packages;\n\t\t}\n\n\t\tprivate void addComponentScanningPackages(Set<String> packages, AnnotationMetadata metadata) {\n\t\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t\t.fromMap(metadata.getAnnotationAttributes(ComponentScan.class.getName(), true));\n\t\t\tif (attributes != null) {\n\t\t\t\taddPackages(packages, attributes.getStringArray(\"value\"));\n\t\t\t\taddPackages(packages, attributes.getStringArray(\"basePackages\"));\n\t\t\t\taddClasses(packages, attributes.getStringArray(\"basePackageClasses\"));\n\t\t\t\tif (packages.isEmpty()) {\n\t\t\t\t\tpackages.add(ClassUtils.getPackageName(metadata.getClassName()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void addPackages(Set<String> packages, String @Nullable [] values) {\n\t\t\tif (values != null) {\n\t\t\t\tCollections.addAll(packages, values);\n\t\t\t}\n\t\t}\n\n\t\tprivate void addClasses(Set<String> packages, String @Nullable [] values) {\n\t\t\tif (values != null) {\n\t\t\t\tfor (String value : values) {\n\t\t\t\t\tpackages.add(ClassUtils.getPackageName(value));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate List<String> getProblematicPackages(Set<String> scannedPackages) {\n\t\t\tList<String> problematicPackages = new ArrayList<>();\n\t\t\tfor (String scannedPackage : scannedPackages) {\n\t\t\t\tif (isProblematicPackage(scannedPackage)) {\n\t\t\t\t\tproblematicPackages.add(getDisplayName(scannedPackage));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn problematicPackages;\n\t\t}\n\n\t\tprivate boolean isProblematicPackage(@Nullable String scannedPackage) {\n\t\t\tif (scannedPackage == null || scannedPackage.isEmpty()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn PROBLEM_PACKAGES.contains(scannedPackage);\n\t\t}\n\n\t\tprivate String getDisplayName(@Nullable String scannedPackage) {\n\t\t\tif (scannedPackage == null || scannedPackage.isEmpty()) {\n\t\t\t\treturn \"the default package\";\n\t\t\t}\n\t\t\treturn \"'\" + scannedPackage + \"'\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/ContextIdApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationContextInitializer} that sets the Spring\n * {@link ApplicationContext#getId() ApplicationContext ID}. The\n * {@code spring.application.name} property is used to create the ID. If the property is\n * not set {@code application} is used.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 1.0.0\n */\npublic class ContextIdApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE - 10;\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tContextId contextId = getContextId(applicationContext);\n\t\tapplicationContext.setId(contextId.getId());\n\t\tapplicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(), contextId);\n\t}\n\n\tprivate ContextId getContextId(ConfigurableApplicationContext applicationContext) {\n\t\tApplicationContext parent = applicationContext.getParent();\n\t\tif (parent != null && parent.containsBean(ContextId.class.getName())) {\n\t\t\treturn parent.getBean(ContextId.class).createChildId();\n\t\t}\n\t\treturn new ContextId(getApplicationId(applicationContext.getEnvironment()));\n\t}\n\n\tprivate String getApplicationId(ConfigurableEnvironment environment) {\n\t\tString name = environment.getProperty(\"spring.application.name\");\n\t\treturn StringUtils.hasText(name) ? name : \"application\";\n\t}\n\n\t/**\n\t * The ID of a context.\n\t */\n\tstatic class ContextId {\n\n\t\tprivate final AtomicLong children = new AtomicLong();\n\n\t\tprivate final String id;\n\n\t\tContextId(String id) {\n\t\t\tthis.id = id;\n\t\t}\n\n\t\tContextId createChildId() {\n\t\t\treturn new ContextId(this.id + \"-\" + this.children.incrementAndGet());\n\t\t}\n\n\t\tString getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/FileEncodingApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * An {@link ApplicationListener} that halts application startup if the system file\n * encoding does not match an expected value set in the environment. By default has no\n * effect, but if you set {@code spring.mandatory_file_encoding} (or some camelCase or\n * UPPERCASE variant of that) to the name of a character encoding (e.g. \"UTF-8\") then this\n * initializer throws an exception when the {@code file.encoding} System property does not\n * equal it.\n *\n * <p>\n * The System property {@code file.encoding} is normally set by the JVM in response to the\n * {@code LANG} or {@code LC_ALL} environment variables. It is used (along with other\n * platform-dependent variables keyed off those environment variables) to encode JVM\n * arguments as well as file names and paths. In most cases you can override the file\n * encoding System property on the command line (with standard JVM features), but also\n * consider setting the {@code LANG} environment variable to an explicit\n * character-encoding value (e.g. \"en_GB.UTF-8\").\n *\n * @author Dave Syer\n * @author Madhura Bhave\n * @since 1.0.0\n */\npublic class FileEncodingApplicationListener\n\t\timplements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(FileEncodingApplicationListener.class);\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\tConfigurableEnvironment environment = event.getEnvironment();\n\t\tString desired = environment.getProperty(\"spring.mandatory-file-encoding\");\n\t\tif (desired == null) {\n\t\t\treturn;\n\t\t}\n\t\tString encoding = System.getProperty(\"file.encoding\");\n\t\tif (encoding != null && !desired.equalsIgnoreCase(encoding)) {\n\t\t\tif (logger.isErrorEnabled()) {\n\t\t\t\tlogger.error(\"System property 'file.encoding' is currently '\" + encoding + \"'. It should be '\" + desired\n\t\t\t\t\t\t+ \"' (as defined in 'spring.mandatoryFileEncoding').\");\n\t\t\t\tlogger.error(\"Environment variable LANG is '\" + System.getenv(\"LANG\")\n\t\t\t\t\t\t+ \"'. You could use a locale setting that matches encoding='\" + desired + \"'.\");\n\t\t\t\tlogger.error(\"Environment variable LC_ALL is '\" + System.getenv(\"LC_ALL\")\n\t\t\t\t\t\t+ \"'. You could use a locale setting that matches encoding='\" + desired + \"'.\");\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"The Java Virtual Machine has not been configured to use the \"\n\t\t\t\t\t+ \"desired default character encoding (\" + desired + \").\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/TypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.io.IOException;\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.filter.TypeFilter;\n\n/**\n * Provides exclusion {@link TypeFilter TypeFilters} that are loaded from the\n * {@link BeanFactory} and automatically applied to {@code SpringBootApplication}\n * scanning. Can also be used directly with {@code @ComponentScan} as follows:\n * <pre class=\"code\">\n * &#064;ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))\n * </pre>\n * <p>\n * Implementations should provide a subclass registered with {@link BeanFactory} and\n * override the {@link #match(MetadataReader, MetadataReaderFactory)} method. They should\n * also implement a valid {@link #hashCode() hashCode} and {@link #equals(Object) equals}\n * methods so that they can be used as part of Spring test's application context caches.\n * <p>\n * Note that {@code TypeExcludeFilters} are initialized very early in the application\n * lifecycle, they should generally not have dependencies on any other beans. They are\n * primarily used internally to support {@code spring-boot-test}.\n *\n * @author Phillip Webb\n * @since 1.4.0\n */\npublic class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanFactory beanFactory;\n\n\tprivate @Nullable Collection<TypeExcludeFilter> delegates;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\tif (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {\n\t\t\tfor (TypeExcludeFilter delegate : getDelegates()) {\n\t\t\t\tif (delegate.match(metadataReader, metadataReaderFactory)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Collection<TypeExcludeFilter> getDelegates() {\n\t\tCollection<TypeExcludeFilter> delegates = this.delegates;\n\t\tif (delegates == null) {\n\t\t\tdelegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();\n\t\t\tthis.delegates = delegates;\n\t\t}\n\t\treturn delegates;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tthrow new IllegalStateException(\"TypeExcludeFilter \" + getClass() + \" has not implemented equals\");\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tthrow new IllegalStateException(\"TypeExcludeFilter \" + getClass() + \" has not implemented hashCode\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/annotation/Configurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.UnaryOperator;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.OrderComparator;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * A set of {@link Configuration @Configuration} classes that can be registered in\n * {@link ApplicationContext}. Classes can be returned from one or more\n * {@link Configurations} instances by using {@link #getClasses(Configurations[])}. The\n * resulting array follows the ordering rules usually applied by the\n * {@link ApplicationContext} and/or custom {@link ImportSelector} implementations.\n * <p>\n * This class is primarily intended for use with tests that need to specify configuration\n * classes but can't use {@link org.springframework.test.context.junit4.SpringRunner}.\n * <p>\n * Implementations of this class should be annotated with {@link Order @Order} or\n * implement {@link Ordered}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see UserConfigurations\n */\npublic abstract class Configurations {\n\n\tprivate static final Comparator<Object> COMPARATOR = OrderComparator.INSTANCE\n\t\t.thenComparing((other) -> other.getClass().getName());\n\n\tprivate final @Nullable UnaryOperator<Collection<Class<?>>> sorter;\n\n\tprivate final Set<Class<?>> classes;\n\n\tprivate final @Nullable Function<Class<?>, String> beanNameGenerator;\n\n\t/**\n\t * Create a new {@link Configurations} instance.\n\t * @param classes the configuration classes\n\t */\n\tprotected Configurations(Collection<Class<?>> classes) {\n\t\tAssert.notNull(classes, \"'classes' must not be null\");\n\t\tthis.sorter = null;\n\t\tthis.classes = Collections.unmodifiableSet(new LinkedHashSet<>(classes));\n\t\tthis.beanNameGenerator = null;\n\t}\n\n\t/**\n\t * Create a new {@link Configurations} instance.\n\t * @param sorter a {@link UnaryOperator} used to sort the configurations\n\t * @param classes the configuration classes\n\t * @param beanNameGenerator an optional function used to generate the bean name\n\t * @since 3.4.0\n\t */\n\tprotected Configurations(@Nullable UnaryOperator<Collection<Class<?>>> sorter, Collection<Class<?>> classes,\n\t\t\t@Nullable Function<Class<?>, String> beanNameGenerator) {\n\t\tAssert.notNull(classes, \"'classes' must not be null\");\n\t\tthis.sorter = (sorter != null) ? sorter : UnaryOperator.identity();\n\t\tCollection<Class<?>> sorted = this.sorter.apply(classes);\n\t\tthis.classes = Collections.unmodifiableSet(new LinkedHashSet<>(sorted));\n\t\tthis.beanNameGenerator = beanNameGenerator;\n\t}\n\n\tprotected final Set<Class<?>> getClasses() {\n\t\treturn this.classes;\n\t}\n\n\t/**\n\t * Merge configurations from another source of the same type.\n\t * @param other the other {@link Configurations} (must be of the same type as this\n\t * instance)\n\t * @return a new configurations instance (must be of the same type as this instance)\n\t */\n\tprotected Configurations merge(Configurations other) {\n\t\tSet<Class<?>> mergedClasses = new LinkedHashSet<>(getClasses());\n\t\tmergedClasses.addAll(other.getClasses());\n\t\tif (this.sorter != null) {\n\t\t\tmergedClasses = new LinkedHashSet<>(this.sorter.apply(mergedClasses));\n\t\t}\n\t\treturn merge(mergedClasses);\n\t}\n\n\t/**\n\t * Merge configurations.\n\t * @param mergedClasses the merged classes\n\t * @return a new configurations instance (must be of the same type as this instance)\n\t */\n\tprotected abstract Configurations merge(Set<Class<?>> mergedClasses);\n\n\t/**\n\t * Return the bean name that should be used for the given configuration class or\n\t * {@code null} to use the default name.\n\t * @param beanClass the bean class\n\t * @return the bean name\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable String getBeanName(Class<?> beanClass) {\n\t\treturn (this.beanNameGenerator != null) ? this.beanNameGenerator.apply(beanClass) : null;\n\t}\n\n\t/**\n\t * Return the classes from all the specified configurations in the order that they\n\t * would be registered.\n\t * @param configurations the source configuration\n\t * @return configuration classes in registration order\n\t */\n\tpublic static Class<?>[] getClasses(Configurations... configurations) {\n\t\treturn getClasses(Arrays.asList(configurations));\n\t}\n\n\t/**\n\t * Return the classes from all the specified configurations in the order that they\n\t * would be registered.\n\t * @param configurations the source configuration\n\t * @return configuration classes in registration order\n\t */\n\tpublic static Class<?>[] getClasses(Collection<Configurations> configurations) {\n\t\tList<Configurations> collated = collate(configurations);\n\t\tLinkedHashSet<Class<?>> classes = collated.stream()\n\t\t\t.flatMap(Configurations::streamClasses)\n\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t\treturn ClassUtils.toClassArray(classes);\n\t}\n\n\t/**\n\t * Collate the given configuration by sorting and merging them.\n\t * @param configurations the source configuration\n\t * @return the collated configurations\n\t * @since 3.4.0\n\t */\n\tpublic static List<Configurations> collate(Collection<Configurations> configurations) {\n\t\tLinkedList<Configurations> collated = new LinkedList<>();\n\t\tfor (Configurations configuration : sortConfigurations(configurations)) {\n\t\t\tif (collated.isEmpty() || collated.getLast().getClass() != configuration.getClass()) {\n\t\t\t\tcollated.add(configuration);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcollated.set(collated.size() - 1, collated.getLast().merge(configuration));\n\t\t\t}\n\t\t}\n\t\treturn collated;\n\t}\n\n\tprivate static List<Configurations> sortConfigurations(Collection<Configurations> configurations) {\n\t\tList<Configurations> sorted = new ArrayList<>(configurations);\n\t\tsorted.sort(COMPARATOR);\n\t\treturn sorted;\n\t}\n\n\tprivate static Stream<Class<?>> streamClasses(Configurations configurations) {\n\t\treturn configurations.getClasses().stream();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/annotation/DeterminableImports.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.util.Set;\n\nimport org.springframework.beans.factory.Aware;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.type.AnnotationMetadata;\n\n/**\n * Interface that can be implemented by {@link ImportSelector} and\n * {@link ImportBeanDefinitionRegistrar} implementations when they can determine imports\n * early. The {@link ImportSelector} and {@link ImportBeanDefinitionRegistrar} interfaces\n * are quite flexible which can make it hard to tell exactly what bean definitions they\n * will add. This interface should be used when an implementation consistently results in\n * the same imports, given the same source.\n * <p>\n * Using {@link DeterminableImports} is particularly useful when working with Spring's\n * testing support. It allows for better generation of {@link ApplicationContext} cache\n * keys.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.5.0\n */\n@FunctionalInterface\npublic interface DeterminableImports {\n\n\t/**\n\t * Return a set of objects that represent the imports. Objects within the returned\n\t * {@code Set} must implement a valid {@link Object#hashCode() hashCode} and\n\t * {@link Object#equals(Object) equals}.\n\t * <p>\n\t * Imports from multiple {@link DeterminableImports} instances may be combined by the\n\t * caller to create a complete set.\n\t * <p>\n\t * Unlike {@link ImportSelector} and {@link ImportBeanDefinitionRegistrar} any\n\t * {@link Aware} callbacks will not be invoked before this method is called.\n\t * @param metadata the source meta-data\n\t * @return a key representing the annotations that actually drive the import\n\t */\n\tSet<Object> determineImports(AnnotationMetadata metadata);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/annotation/ImportCandidates.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.UrlResource;\nimport org.springframework.util.Assert;\n\n/**\n * Contains {@code @Configuration} import candidates, usually auto-configurations.\n *\n * The {@link #load(Class, ClassLoader)} method can be used to discover the import\n * candidates.\n *\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @since 2.7.0\n */\npublic final class ImportCandidates implements Iterable<String> {\n\n\tprivate static final String LOCATION = \"META-INF/spring/%s.imports\";\n\n\tprivate static final String COMMENT_START = \"#\";\n\n\tprivate final List<String> candidates;\n\n\tprivate ImportCandidates(List<String> candidates) {\n\t\tAssert.notNull(candidates, \"'candidates' must not be null\");\n\t\tthis.candidates = Collections.unmodifiableList(candidates);\n\t}\n\n\t@Override\n\tpublic Iterator<String> iterator() {\n\t\treturn this.candidates.iterator();\n\t}\n\n\t/**\n\t * Returns the list of loaded import candidates.\n\t * @return the list of import candidates\n\t */\n\tpublic List<String> getCandidates() {\n\t\treturn this.candidates;\n\t}\n\n\t/**\n\t * Loads the names of import candidates from the classpath. The names of the import\n\t * candidates are stored in files named\n\t * {@code META-INF/spring/full-qualified-annotation-name.imports} on the classpath.\n\t * Every line contains the full qualified name of the candidate class. Comments are\n\t * supported using the # character.\n\t * @param annotation annotation to load\n\t * @param classLoader class loader to use for loading\n\t * @return list of names of annotated classes\n\t */\n\tpublic static ImportCandidates load(Class<?> annotation, @Nullable ClassLoader classLoader) {\n\t\tAssert.notNull(annotation, \"'annotation' must not be null\");\n\t\tClassLoader classLoaderToUse = decideClassloader(classLoader);\n\t\tString location = String.format(LOCATION, annotation.getName());\n\t\tEnumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);\n\t\tList<String> importCandidates = new ArrayList<>();\n\t\twhile (urls.hasMoreElements()) {\n\t\t\tURL url = urls.nextElement();\n\t\t\timportCandidates.addAll(readCandidateConfigurations(url));\n\t\t}\n\t\treturn new ImportCandidates(importCandidates);\n\t}\n\n\tprivate static ClassLoader decideClassloader(@Nullable ClassLoader classLoader) {\n\t\tif (classLoader == null) {\n\t\t\treturn ImportCandidates.class.getClassLoader();\n\t\t}\n\t\treturn classLoader;\n\t}\n\n\tprivate static Enumeration<URL> findUrlsInClasspath(ClassLoader classLoader, String location) {\n\t\ttry {\n\t\t\treturn classLoader.getResources(location);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to load configurations from location [\" + location + \"]\", ex);\n\t\t}\n\t}\n\n\tprivate static List<String> readCandidateConfigurations(URL url) {\n\t\ttry (BufferedReader reader = new BufferedReader(\n\t\t\t\tnew InputStreamReader(new UrlResource(url).getInputStream(), StandardCharsets.UTF_8))) {\n\t\t\tList<String> candidates = new ArrayList<>();\n\t\t\tString line;\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tline = stripComment(line);\n\t\t\t\tline = line.trim();\n\t\t\t\tif (line.isEmpty()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcandidates.add(line);\n\t\t\t}\n\t\t\treturn candidates;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Unable to load configurations from location [\" + url + \"]\", ex);\n\t\t}\n\t}\n\n\tprivate static String stripComment(String line) {\n\t\tint commentStart = line.indexOf(COMMENT_START);\n\t\tif (commentStart == -1) {\n\t\t\treturn line;\n\t\t}\n\t\treturn line.substring(0, commentStart);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/annotation/UserConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Set;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\n\n/**\n * {@link Configurations} representing user-defined {@code @Configuration} classes (i.e.\n * those defined in classes usually written by the user).\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class UserConfigurations extends Configurations implements PriorityOrdered {\n\n\tprotected UserConfigurations(Collection<Class<?>> classes) {\n\t\tsuper(classes);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tprotected UserConfigurations merge(Set<Class<?>> mergedClasses) {\n\t\treturn new UserConfigurations(mergedClasses);\n\t}\n\n\tpublic static UserConfigurations of(Class<?>... classes) {\n\t\treturn new UserConfigurations(Arrays.asList(classes));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/annotation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to Spring's {@link org.springframework.context.ApplicationContext}\n * annotations.\n */\n@NullMarked\npackage org.springframework.boot.context.annotation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigData.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration data that has been loaded from a {@link ConfigDataResource} and may\n * ultimately contribute {@link PropertySource property sources} to Spring's\n * {@link Environment}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n * @see ConfigDataLocationResolver\n * @see ConfigDataLoader\n */\npublic final class ConfigData {\n\n\tprivate final List<PropertySource<?>> propertySources;\n\n\tprivate final PropertySourceOptions propertySourceOptions;\n\n\t/**\n\t * A {@link ConfigData} instance that contains no data.\n\t */\n\tpublic static final ConfigData EMPTY = new ConfigData(Collections.emptySet());\n\n\t/**\n\t * Create a new {@link ConfigData} instance with the same options applied to each\n\t * source.\n\t * @param propertySources the config data property sources in ascending priority\n\t * order.\n\t * @param options the config data options applied to each source\n\t * @see #ConfigData(Collection, PropertySourceOptions)\n\t */\n\tpublic ConfigData(Collection<? extends PropertySource<?>> propertySources, Option... options) {\n\t\tthis(propertySources, PropertySourceOptions.always(Options.of(options)));\n\t}\n\n\t/**\n\t * Create a new {@link ConfigData} instance with specific property source options.\n\t * @param propertySources the config data property sources in ascending priority\n\t * order.\n\t * @param propertySourceOptions the property source options\n\t * @since 2.4.5\n\t */\n\tpublic ConfigData(Collection<? extends PropertySource<?>> propertySources,\n\t\t\tPropertySourceOptions propertySourceOptions) {\n\t\tAssert.notNull(propertySources, \"'propertySources' must not be null\");\n\t\tAssert.notNull(propertySourceOptions, \"'propertySourceOptions' must not be null\");\n\t\tthis.propertySources = Collections.unmodifiableList(new ArrayList<>(propertySources));\n\t\tthis.propertySourceOptions = propertySourceOptions;\n\t}\n\n\t/**\n\t * Return the configuration data property sources in ascending priority order. If the\n\t * same key is contained in more than one of the sources, then the later source will\n\t * win.\n\t * @return the config data property sources\n\t */\n\tpublic List<PropertySource<?>> getPropertySources() {\n\t\treturn this.propertySources;\n\t}\n\n\t/**\n\t * Return the {@link Options config data options} that apply to the given source.\n\t * @param propertySource the property source to check\n\t * @return the options that apply\n\t * @since 2.4.5\n\t */\n\tpublic Options getOptions(PropertySource<?> propertySource) {\n\t\tOptions options = this.propertySourceOptions.get(propertySource);\n\t\treturn (options != null) ? options : Options.NONE;\n\t}\n\n\t/**\n\t * Strategy interface used to supply {@link Options} for a given\n\t * {@link PropertySource}.\n\t *\n\t * @since 2.4.5\n\t */\n\t@FunctionalInterface\n\tpublic interface PropertySourceOptions {\n\n\t\t/**\n\t\t * {@link PropertySourceOptions} instance that always returns\n\t\t * {@link Options#NONE}.\n\t\t * @since 2.4.6\n\t\t */\n\t\tPropertySourceOptions ALWAYS_NONE = new AlwaysPropertySourceOptions(Options.NONE);\n\n\t\t/**\n\t\t * Return the options that should apply for the given property source.\n\t\t * @param propertySource the property source\n\t\t * @return the options to apply\n\t\t */\n\t\t@Nullable Options get(PropertySource<?> propertySource);\n\n\t\t/**\n\t\t * Create a new {@link PropertySourceOptions} instance that always returns the\n\t\t * same options regardless of the property source.\n\t\t * @param options the options to return\n\t\t * @return a new {@link PropertySourceOptions} instance\n\t\t */\n\t\tstatic PropertySourceOptions always(Option... options) {\n\t\t\treturn always(Options.of(options));\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link PropertySourceOptions} instance that always returns the\n\t\t * same options regardless of the property source.\n\t\t * @param options the options to return\n\t\t * @return a new {@link PropertySourceOptions} instance\n\t\t */\n\t\tstatic PropertySourceOptions always(Options options) {\n\t\t\tif (options == Options.NONE) {\n\t\t\t\treturn ALWAYS_NONE;\n\t\t\t}\n\t\t\treturn new AlwaysPropertySourceOptions(options);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link PropertySourceOptions} that always returns the same result.\n\t */\n\tprivate static class AlwaysPropertySourceOptions implements PropertySourceOptions {\n\n\t\tprivate final Options options;\n\n\t\tAlwaysPropertySourceOptions(Options options) {\n\t\t\tthis.options = options;\n\t\t}\n\n\t\t@Override\n\t\tpublic Options get(PropertySource<?> propertySource) {\n\t\t\treturn this.options;\n\t\t}\n\n\t}\n\n\t/**\n\t * A set of {@link Option} flags.\n\t *\n\t * @since 2.4.5\n\t */\n\tpublic static final class Options {\n\n\t\t/**\n\t\t * No options.\n\t\t */\n\t\tpublic static final Options NONE = new Options(Collections.emptySet());\n\n\t\tprivate final Set<Option> options;\n\n\t\tprivate Options(Set<Option> options) {\n\t\t\tthis.options = Collections.unmodifiableSet(options);\n\t\t}\n\n\t\tSet<Option> asSet() {\n\t\t\treturn this.options;\n\t\t}\n\n\t\t/**\n\t\t * Returns if the given option is contained in this set.\n\t\t * @param option the option to check\n\t\t * @return {@code true} of the option is present\n\t\t */\n\t\tpublic boolean contains(Option option) {\n\t\t\treturn this.options.contains(option);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tOptions other = (Options) obj;\n\t\t\treturn this.options.equals(other.options);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.options.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.options.toString();\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link Options} instance that contains the options in this set\n\t\t * excluding the given option.\n\t\t * @param option the option to exclude\n\t\t * @return a new {@link Options} instance\n\t\t */\n\t\tpublic Options without(Option option) {\n\t\t\treturn copy((options) -> options.remove(option));\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link Options} instance that contains the options in this set\n\t\t * including the given option.\n\t\t * @param option the option to include\n\t\t * @return a new {@link Options} instance\n\t\t */\n\t\tpublic Options with(Option option) {\n\t\t\treturn copy((options) -> options.add(option));\n\t\t}\n\n\t\tprivate Options copy(Consumer<EnumSet<Option>> processor) {\n\t\t\tEnumSet<Option> options = (!this.options.isEmpty()) ? EnumSet.copyOf(this.options)\n\t\t\t\t\t: EnumSet.noneOf(Option.class);\n\t\t\tprocessor.accept(options);\n\t\t\treturn new Options(options);\n\t\t}\n\n\t\t/**\n\t\t * Create a new instance with the given {@link Option} values.\n\t\t * @param options the options to include\n\t\t * @return a new {@link Options} instance\n\t\t */\n\t\tpublic static Options of(Option... options) {\n\t\t\tAssert.notNull(options, \"'options' must not be null\");\n\t\t\tif (options.length == 0) {\n\t\t\t\treturn NONE;\n\t\t\t}\n\t\t\treturn new Options(EnumSet.copyOf(Arrays.asList(options)));\n\t\t}\n\n\t}\n\n\t/**\n\t * Option flags that can be applied.\n\t */\n\tpublic enum Option {\n\n\t\t/**\n\t\t * Ignore all imports properties from the source.\n\t\t */\n\t\tIGNORE_IMPORTS,\n\n\t\t/**\n\t\t * Ignore all profile activation and include properties.\n\t\t * @since 2.4.3\n\t\t */\n\t\tIGNORE_PROFILES,\n\n\t\t/**\n\t\t * Indicates that the source is \"profile specific\" and should be included after\n\t\t * profile specific sibling imports.\n\t\t * @since 2.4.5\n\t\t */\n\t\tPROFILE_SPECIFIC\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataActivationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.style.ToStringCreator;\n\n/**\n * Context information used when determining when to activate\n * {@link ConfigDataEnvironmentContributor contributed} {@link ConfigData}.\n *\n * @author Phillip Webb\n */\nclass ConfigDataActivationContext {\n\n\tprivate final @Nullable CloudPlatform cloudPlatform;\n\n\tprivate final @Nullable Profiles profiles;\n\n\t/**\n\t * Create a new {@link ConfigDataActivationContext} instance before any profiles have\n\t * been activated.\n\t * @param environment the source environment\n\t * @param binder a binder providing access to relevant config data contributions\n\t */\n\tConfigDataActivationContext(Environment environment, Binder binder) {\n\t\tthis.cloudPlatform = deduceCloudPlatform(environment, binder);\n\t\tthis.profiles = null;\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataActivationContext} instance with the given\n\t * {@link CloudPlatform} and {@link Profiles}.\n\t * @param cloudPlatform the cloud platform\n\t * @param profiles the profiles\n\t */\n\tConfigDataActivationContext(@Nullable CloudPlatform cloudPlatform, @Nullable Profiles profiles) {\n\t\tthis.cloudPlatform = cloudPlatform;\n\t\tthis.profiles = profiles;\n\t}\n\n\tprivate @Nullable CloudPlatform deduceCloudPlatform(Environment environment, Binder binder) {\n\t\tfor (CloudPlatform candidate : CloudPlatform.values()) {\n\t\t\tif (candidate.isEnforced(binder)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn CloudPlatform.getActive(environment);\n\t}\n\n\t/**\n\t * Return a new {@link ConfigDataActivationContext} with specific profiles.\n\t * @param profiles the profiles\n\t * @return a new {@link ConfigDataActivationContext} with specific profiles\n\t */\n\tConfigDataActivationContext withProfiles(Profiles profiles) {\n\t\treturn new ConfigDataActivationContext(this.cloudPlatform, profiles);\n\t}\n\n\t/**\n\t * Return the active {@link CloudPlatform} or {@code null}.\n\t * @return the active cloud platform\n\t */\n\t@Nullable CloudPlatform getCloudPlatform() {\n\t\treturn this.cloudPlatform;\n\t}\n\n\t/**\n\t * Return profile information if it is available.\n\t * @return profile information or {@code null}\n\t */\n\t@Nullable Profiles getProfiles() {\n\t\treturn this.profiles;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tcreator.append(\"cloudPlatform\", this.cloudPlatform);\n\t\tcreator.append(\"profiles\", this.profiles);\n\t\treturn creator.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.Scope;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributors.BinderOption;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.PlaceholdersResolver;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.env.DefaultPropertiesPropertySource;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Wrapper around a {@link ConfigurableEnvironment} that can be used to import and apply\n * {@link ConfigData}. Configures the initial set of\n * {@link ConfigDataEnvironmentContributors} by wrapping property sources from the Spring\n * {@link Environment} and adding the initial set of locations.\n * <p>\n * The initial locations can be influenced through the {@link #LOCATION_PROPERTY},\n * {@value #ADDITIONAL_LOCATION_PROPERTY} and {@value #IMPORT_PROPERTY} properties. If no\n * explicit properties are set, the {@link #DEFAULT_SEARCH_LOCATIONS} will be used.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Nan Chiu\n */\nclass ConfigDataEnvironment {\n\n\t/**\n\t * Property used override the imported locations.\n\t */\n\tstatic final String LOCATION_PROPERTY = \"spring.config.location\";\n\n\t/**\n\t * Property used to provide additional locations to import.\n\t */\n\tstatic final String ADDITIONAL_LOCATION_PROPERTY = \"spring.config.additional-location\";\n\n\t/**\n\t * Property used to provide additional locations to import.\n\t */\n\tstatic final String IMPORT_PROPERTY = \"spring.config.import\";\n\n\t/**\n\t * Property used to determine what action to take when a\n\t * {@code ConfigDataNotFoundAction} is thrown.\n\t * @see ConfigDataNotFoundAction\n\t */\n\tstatic final String ON_NOT_FOUND_PROPERTY = \"spring.config.on-not-found\";\n\n\t/**\n\t * Default search locations used if not {@link #LOCATION_PROPERTY} is found.\n\t */\n\tstatic final ConfigDataLocation[] DEFAULT_SEARCH_LOCATIONS;\n\tstatic {\n\t\tList<ConfigDataLocation> locations = new ArrayList<>();\n\t\tlocations.add(ConfigDataLocation.of(\"optional:classpath:/;optional:classpath:/config/\"));\n\t\tlocations.add(ConfigDataLocation.of(\"optional:file:./;optional:file:./config/;optional:file:./config/*/\"));\n\t\tDEFAULT_SEARCH_LOCATIONS = locations.toArray(new ConfigDataLocation[0]);\n\t}\n\n\tprivate static final ConfigDataLocation[] EMPTY_LOCATIONS = new ConfigDataLocation[0];\n\n\tprivate static final Bindable<ConfigDataLocation[]> CONFIG_DATA_LOCATION_ARRAY = Bindable\n\t\t.of(ConfigDataLocation[].class);\n\n\tprivate static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);\n\n\tprivate static final BinderOption[] ALLOW_INACTIVE_BINDING = {};\n\n\tprivate static final BinderOption[] DENY_INACTIVE_BINDING = { BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE };\n\n\tprivate final DeferredLogFactory logFactory;\n\n\tprivate final Log logger;\n\n\tprivate final ConfigDataNotFoundAction notFoundAction;\n\n\tprivate final ConfigurableBootstrapContext bootstrapContext;\n\n\tprivate final ConfigurableEnvironment environment;\n\n\tprivate final ConfigDataLocationResolvers resolvers;\n\n\tprivate final Collection<String> additionalProfiles;\n\n\tprivate final ConfigDataEnvironmentUpdateListener environmentUpdateListener;\n\n\tprivate final ConfigDataLoaders loaders;\n\n\tprivate final ConfigDataEnvironmentContributors contributors;\n\n\t/**\n\t * Create a new {@link ConfigDataEnvironment} instance.\n\t * @param logFactory the deferred log factory\n\t * @param bootstrapContext the bootstrap context\n\t * @param environment the Spring {@link Environment}.\n\t * @param resourceLoader {@link ResourceLoader} to load resource locations\n\t * @param additionalProfiles any additional profiles to activate\n\t * @param environmentUpdateListener optional\n\t * {@link ConfigDataEnvironmentUpdateListener} that can be used to track\n\t * {@link Environment} updates.\n\t */\n\tConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,\n\t\t\tConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles,\n\t\t\t@Nullable ConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\tBinder binder = Binder.get(environment);\n\t\tthis.logFactory = logFactory;\n\t\tthis.logger = logFactory.getLog(getClass());\n\t\tthis.notFoundAction = binder.bind(ON_NOT_FOUND_PROPERTY, ConfigDataNotFoundAction.class)\n\t\t\t.orElse(ConfigDataNotFoundAction.FAIL);\n\t\tthis.bootstrapContext = bootstrapContext;\n\t\tthis.environment = environment;\n\t\tthis.resolvers = createConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader);\n\t\tthis.additionalProfiles = additionalProfiles;\n\t\tthis.environmentUpdateListener = (environmentUpdateListener != null) ? environmentUpdateListener\n\t\t\t\t: ConfigDataEnvironmentUpdateListener.NONE;\n\t\tthis.loaders = new ConfigDataLoaders(logFactory, bootstrapContext,\n\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader()));\n\t\tthis.contributors = createContributors(binder);\n\t}\n\n\tprotected ConfigDataLocationResolvers createConfigDataLocationResolvers(DeferredLogFactory logFactory,\n\t\t\tConfigurableBootstrapContext bootstrapContext, Binder binder, ResourceLoader resourceLoader) {\n\t\treturn new ConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader,\n\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader()));\n\t}\n\n\tprivate ConfigDataEnvironmentContributors createContributors(Binder binder) {\n\t\tthis.logger.trace(\"Building config data environment contributors\");\n\t\tMutablePropertySources propertySources = this.environment.getPropertySources();\n\t\tList<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(propertySources.size() + 10);\n\t\tPropertySource<?> defaultPropertySource = null;\n\t\tfor (PropertySource<?> propertySource : propertySources) {\n\t\t\tif (DefaultPropertiesPropertySource.hasMatchingName(propertySource)) {\n\t\t\t\tdefaultPropertySource = propertySource;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.logger.trace(LogMessage.format(\"Creating wrapped config data contributor for '%s'\",\n\t\t\t\t\t\tpropertySource.getName()));\n\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofExisting(propertySource,\n\t\t\t\t\t\tthis.environment.getConversionService()));\n\t\t\t}\n\t\t}\n\t\tcontributors.addAll(getInitialImportContributors(binder));\n\t\tif (defaultPropertySource != null) {\n\t\t\tthis.logger.trace(\"Creating wrapped config data contributor for default property source\");\n\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofExisting(defaultPropertySource,\n\t\t\t\t\tthis.environment.getConversionService()));\n\t\t}\n\t\treturn createContributors(contributors);\n\t}\n\n\tprotected ConfigDataEnvironmentContributors createContributors(\n\t\t\tList<ConfigDataEnvironmentContributor> contributors) {\n\t\treturn new ConfigDataEnvironmentContributors(this.logFactory, this.bootstrapContext, contributors,\n\t\t\t\tthis.environment.getConversionService(), this.environmentUpdateListener);\n\t}\n\n\tConfigDataEnvironmentContributors getContributors() {\n\t\treturn this.contributors;\n\t}\n\n\tprivate List<ConfigDataEnvironmentContributor> getInitialImportContributors(Binder binder) {\n\t\tList<ConfigDataEnvironmentContributor> initialContributors = new ArrayList<>();\n\t\taddInitialImportContributors(initialContributors, binder, IMPORT_PROPERTY, EMPTY_LOCATIONS, false);\n\t\taddInitialImportContributors(initialContributors, binder, ADDITIONAL_LOCATION_PROPERTY, EMPTY_LOCATIONS, true);\n\t\taddInitialImportContributors(initialContributors, binder, LOCATION_PROPERTY, DEFAULT_SEARCH_LOCATIONS, true);\n\t\treturn initialContributors;\n\t}\n\n\tprivate void addInitialImportContributors(List<ConfigDataEnvironmentContributor> initialContributors, Binder binder,\n\t\t\tString propertyName, ConfigDataLocation[] defaultValue, boolean registerIndividually) {\n\t\tConfigDataLocation[] locations = binder.bind(propertyName, CONFIG_DATA_LOCATION_ARRAY).orElse(defaultValue);\n\t\tif (registerIndividually) {\n\t\t\tfor (int i = locations.length - 1; i >= 0; i--) {\n\t\t\t\taddInitialImportContributors(initialContributors, List.of(locations[i]));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\taddInitialImportContributors(initialContributors, List.of(locations));\n\t\t}\n\t}\n\n\tprivate void addInitialImportContributors(List<ConfigDataEnvironmentContributor> initialContributors,\n\t\t\tList<ConfigDataLocation> locations) {\n\t\tif (!locations.isEmpty()) {\n\t\t\tthis.logger.trace(LogMessage.format(\"Adding initial config data import from locations %s\", locations));\n\t\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImports(locations,\n\t\t\t\t\tthis.environment.getConversionService());\n\t\t\tinitialContributors.add(contributor);\n\t\t}\n\t}\n\n\t/**\n\t * Process all contributions and apply any newly imported property sources to the\n\t * {@link Environment}.\n\t */\n\tvoid processAndApply() {\n\t\tConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers,\n\t\t\t\tthis.loaders);\n\t\tregisterBootstrapBinder(this.contributors, null, DENY_INACTIVE_BINDING);\n\t\tConfigDataEnvironmentContributors contributors = processInitial(this.contributors, importer);\n\t\tConfigDataActivationContext activationContext = createActivationContext(\n\t\t\t\tcontributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));\n\t\tcontributors = processWithoutProfiles(contributors, importer, activationContext);\n\t\tactivationContext = withProfiles(contributors, activationContext);\n\t\tcontributors = processWithProfiles(contributors, importer, activationContext);\n\t\tapplyToEnvironment(contributors, activationContext, importer.getLoadedLocations(),\n\t\t\t\timporter.getOptionalLocations());\n\t}\n\n\tprivate ConfigDataEnvironmentContributors processInitial(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataImporter importer) {\n\t\tthis.logger.trace(\"Processing initial config data environment contributors without activation context\");\n\t\tcontributors = contributors.withProcessedImports(importer, null);\n\t\tregisterBootstrapBinder(contributors, null, DENY_INACTIVE_BINDING);\n\t\treturn contributors;\n\t}\n\n\tprivate ConfigDataActivationContext createActivationContext(Binder initialBinder) {\n\t\tthis.logger.trace(\"Creating config data activation context from initial contributions\");\n\t\ttry {\n\t\t\treturn new ConfigDataActivationContext(this.environment, initialBinder);\n\t\t}\n\t\tcatch (BindException ex) {\n\t\t\tif (ex.getCause() instanceof InactiveConfigDataAccessException inactiveException) {\n\t\t\t\tthrow inactiveException;\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate ConfigDataEnvironmentContributors processWithoutProfiles(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataImporter importer, ConfigDataActivationContext activationContext) {\n\t\tthis.logger.trace(\"Processing config data environment contributors with initial activation context\");\n\t\tcontributors = contributors.withProcessedImports(importer, activationContext);\n\t\tregisterBootstrapBinder(contributors, activationContext, DENY_INACTIVE_BINDING);\n\t\treturn contributors;\n\t}\n\n\tprivate ConfigDataActivationContext withProfiles(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataActivationContext activationContext) {\n\t\tthis.logger.trace(\"Deducing profiles from current config data environment contributors\");\n\t\tBinder binder = contributors.getBinder(activationContext,\n\t\t\t\t(contributor) -> !contributor.hasConfigDataOption(ConfigData.Option.IGNORE_PROFILES),\n\t\t\t\tBinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);\n\t\ttry {\n\t\t\tSet<String> additionalProfiles = new LinkedHashSet<>(this.additionalProfiles);\n\t\t\tadditionalProfiles.addAll(getIncludedProfiles(contributors, activationContext));\n\t\t\tProfiles profiles = new Profiles(this.environment, binder, additionalProfiles);\n\t\t\treturn activationContext.withProfiles(profiles);\n\t\t}\n\t\tcatch (BindException ex) {\n\t\t\tif (ex.getCause() instanceof InactiveConfigDataAccessException inactiveException) {\n\t\t\t\tthrow inactiveException;\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate Collection<? extends String> getIncludedProfiles(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataActivationContext activationContext) {\n\t\tPlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tcontributors, activationContext, null, true, this.environment.getConversionService());\n\t\tSet<String> result = new LinkedHashSet<>();\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\tConfigurationPropertySource source = contributor.getConfigurationPropertySource();\n\t\t\tif (source != null && !contributor.hasConfigDataOption(ConfigData.Option.IGNORE_PROFILES)) {\n\t\t\t\tBinder binder = new Binder(Collections.singleton(source), placeholdersResolver);\n\t\t\t\tbinder.bind(Profiles.INCLUDE_PROFILES, STRING_LIST, ProfilesValidator.get(binder))\n\t\t\t\t\t.ifBound((includes) -> {\n\t\t\t\t\t\tif (!contributor.isActive(activationContext)) {\n\t\t\t\t\t\t\tInactiveConfigDataAccessException.throwIfPropertyFound(contributor,\n\t\t\t\t\t\t\t\t\tProfiles.INCLUDE_PROFILES);\n\t\t\t\t\t\t\tInactiveConfigDataAccessException.throwIfPropertyFound(contributor,\n\t\t\t\t\t\t\t\t\tProfiles.INCLUDE_PROFILES.append(\"[0]\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult.addAll(includes);\n\t\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate ConfigDataEnvironmentContributors processWithProfiles(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataImporter importer, ConfigDataActivationContext activationContext) {\n\t\tthis.logger.trace(\"Processing config data environment contributors with profile activation context\");\n\t\tcontributors = contributors.withProcessedImports(importer, activationContext);\n\t\tregisterBootstrapBinder(contributors, activationContext, ALLOW_INACTIVE_BINDING);\n\t\treturn contributors;\n\t}\n\n\tprivate void registerBootstrapBinder(ConfigDataEnvironmentContributors contributors,\n\t\t\t@Nullable ConfigDataActivationContext activationContext, BinderOption... binderOptions) {\n\t\tthis.bootstrapContext.register(Binder.class,\n\t\t\t\tInstanceSupplier.from(() -> contributors.getBinder(activationContext, binderOptions))\n\t\t\t\t\t.withScope(Scope.PROTOTYPE));\n\t}\n\n\tprivate void applyToEnvironment(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataActivationContext activationContext, Set<ConfigDataLocation> loadedLocations,\n\t\t\tSet<ConfigDataLocation> optionalLocations) {\n\t\tcheckForInvalidProperties(contributors);\n\t\tcheckMandatoryLocations(contributors, activationContext, loadedLocations, optionalLocations);\n\t\tMutablePropertySources propertySources = this.environment.getPropertySources();\n\t\tapplyContributor(contributors, activationContext, propertySources);\n\t\tDefaultPropertiesPropertySource.moveToEnd(propertySources);\n\t\tProfiles profiles = activationContext.getProfiles();\n\t\tAssert.state(profiles != null, \"'profiles' must not be null\");\n\t\tthis.logger.trace(LogMessage.format(\"Setting default profiles: %s\", profiles.getDefault()));\n\t\tthis.environment.setDefaultProfiles(StringUtils.toStringArray(profiles.getDefault()));\n\t\tthis.logger.trace(LogMessage.format(\"Setting active profiles: %s\", profiles.getActive()));\n\t\tthis.environment.setActiveProfiles(StringUtils.toStringArray(profiles.getActive()));\n\t\tthis.environmentUpdateListener.onSetProfiles(profiles);\n\t}\n\n\tprivate void applyContributor(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataActivationContext activationContext, MutablePropertySources propertySources) {\n\t\tthis.logger.trace(\"Applying config data environment contributions\");\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\tPropertySource<?> propertySource = contributor.getPropertySource();\n\t\t\tif (contributor.getKind() == ConfigDataEnvironmentContributor.Kind.BOUND_IMPORT && propertySource != null) {\n\t\t\t\tif (!contributor.isActive(activationContext)) {\n\t\t\t\t\tthis.logger\n\t\t\t\t\t\t.trace(LogMessage.format(\"Skipping inactive property source '%s'\", propertySource.getName()));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.logger\n\t\t\t\t\t\t.trace(LogMessage.format(\"Adding imported property source '%s'\", propertySource.getName()));\n\t\t\t\t\tpropertySources.addLast(propertySource);\n\t\t\t\t\tthis.environmentUpdateListener.onPropertySourceAdded(propertySource, contributor.getLocation(),\n\t\t\t\t\t\t\tcontributor.getResource());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void checkForInvalidProperties(ConfigDataEnvironmentContributors contributors) {\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\tInvalidConfigDataPropertyException.throwIfPropertyFound(contributor);\n\t\t}\n\t}\n\n\tprivate void checkMandatoryLocations(ConfigDataEnvironmentContributors contributors,\n\t\t\tConfigDataActivationContext activationContext, Set<ConfigDataLocation> loadedLocations,\n\t\t\tSet<ConfigDataLocation> optionalLocations) {\n\t\tSet<ConfigDataLocation> mandatoryLocations = new LinkedHashSet<>();\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\tif (contributor.isActive(activationContext)) {\n\t\t\t\tmandatoryLocations.addAll(getMandatoryImports(contributor));\n\t\t\t}\n\t\t}\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\tif (contributor.getLocation() != null) {\n\t\t\t\tmandatoryLocations.remove(contributor.getLocation());\n\t\t\t}\n\t\t}\n\t\tmandatoryLocations.removeAll(loadedLocations);\n\t\tmandatoryLocations.removeAll(optionalLocations);\n\t\tif (!mandatoryLocations.isEmpty()) {\n\t\t\tfor (ConfigDataLocation mandatoryLocation : mandatoryLocations) {\n\t\t\t\tthis.notFoundAction.handle(this.logger, new ConfigDataLocationNotFoundException(mandatoryLocation));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Set<ConfigDataLocation> getMandatoryImports(ConfigDataEnvironmentContributor contributor) {\n\t\tList<ConfigDataLocation> imports = contributor.getImports();\n\t\tSet<ConfigDataLocation> mandatoryLocations = new LinkedHashSet<>(imports.size());\n\t\tfor (ConfigDataLocation location : imports) {\n\t\t\tif (!location.isOptional()) {\n\t\t\t\tmandatoryLocations.add(location);\n\t\t\t}\n\t\t}\n\t\treturn mandatoryLocations;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.PlaceholdersResolver;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * A single element that may directly or indirectly contribute configuration data to the\n * {@link Environment}. There are several {@link Kind kinds} of contributor, all are\n * immutable and will be replaced with new versions as imports are processed.\n * <p>\n * Contributors may provide a set of imports that should be processed and ultimately\n * turned into children. There are two distinct import phases:\n * <ul>\n * <li>{@link ImportPhase#BEFORE_PROFILE_ACTIVATION Before} profiles have been\n * activated.</li>\n * <li>{@link ImportPhase#AFTER_PROFILE_ACTIVATION After} profiles have been\n * activated.</li>\n * </ul>\n * In each phase <em>all</em> imports will be resolved before they are loaded.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Nan Chiu\n */\nclass ConfigDataEnvironmentContributor implements Iterable<ConfigDataEnvironmentContributor> {\n\n\tprivate static final ConfigData.Options EMPTY_LOCATION_OPTIONS = ConfigData.Options\n\t\t.of(ConfigData.Option.IGNORE_IMPORTS);\n\n\tprivate final @Nullable ConfigDataLocation location;\n\n\tprivate final @Nullable ConfigDataResource resource;\n\n\tprivate final boolean fromProfileSpecificImport;\n\n\tprivate final @Nullable PropertySource<?> propertySource;\n\n\tprivate final @Nullable ConfigurationPropertySource configurationPropertySource;\n\n\tprivate final @Nullable ConfigDataProperties properties;\n\n\tprivate final ConfigData.Options configDataOptions;\n\n\tprivate final Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children;\n\n\tprivate final Kind kind;\n\n\tprivate final ConversionService conversionService;\n\n\t/**\n\t * Create a new {@link ConfigDataEnvironmentContributor} instance.\n\t * @param kind the contributor kind\n\t * @param location the location of this contributor\n\t * @param resource the resource that contributed the data or {@code null}\n\t * @param fromProfileSpecificImport if the contributor is from a profile specific\n\t * import\n\t * @param propertySource the property source for the data or {@code null}\n\t * @param configurationPropertySource the configuration property source for the data\n\t * or {@code null}\n\t * @param properties the config data properties or {@code null}\n\t * @param configDataOptions any config data options that should apply\n\t * @param children the children of this contributor at each {@link ImportPhase}\n\t * @param conversionService the conversion service to use\n\t */\n\tConfigDataEnvironmentContributor(Kind kind, @Nullable ConfigDataLocation location,\n\t\t\t@Nullable ConfigDataResource resource, boolean fromProfileSpecificImport,\n\t\t\t@Nullable PropertySource<?> propertySource,\n\t\t\t@Nullable ConfigurationPropertySource configurationPropertySource,\n\t\t\t@Nullable ConfigDataProperties properties, ConfigData.@Nullable Options configDataOptions,\n\t\t\t@Nullable Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children,\n\t\t\tConversionService conversionService) {\n\t\tthis.kind = kind;\n\t\tthis.location = location;\n\t\tthis.resource = resource;\n\t\tthis.fromProfileSpecificImport = fromProfileSpecificImport;\n\t\tthis.properties = properties;\n\t\tthis.propertySource = propertySource;\n\t\tthis.configurationPropertySource = configurationPropertySource;\n\t\tthis.configDataOptions = (configDataOptions != null) ? configDataOptions : ConfigData.Options.NONE;\n\t\tthis.children = (children != null) ? children : Collections.emptyMap();\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t/**\n\t * Return the contributor kind.\n\t * @return the kind of contributor\n\t */\n\tKind getKind() {\n\t\treturn this.kind;\n\t}\n\n\t@Nullable ConfigDataLocation getLocation() {\n\t\treturn this.location;\n\t}\n\n\t/**\n\t * Return if this contributor is currently active.\n\t * @param activationContext the activation context\n\t * @return if the contributor is active\n\t */\n\tboolean isActive(@Nullable ConfigDataActivationContext activationContext) {\n\t\tif (this.kind == Kind.UNBOUND_IMPORT) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.properties == null || this.properties.isActive(activationContext);\n\t}\n\n\t/**\n\t * Return the resource that contributed this instance.\n\t * @return the resource or {@code null}\n\t */\n\t@Nullable ConfigDataResource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t/**\n\t * Return if the contributor is from a profile specific import.\n\t * @return if the contributor is profile specific\n\t */\n\tboolean isFromProfileSpecificImport() {\n\t\treturn this.fromProfileSpecificImport;\n\t}\n\n\t/**\n\t * Return the property source for this contributor.\n\t * @return the property source or {@code null}\n\t */\n\t@Nullable PropertySource<?> getPropertySource() {\n\t\treturn this.propertySource;\n\t}\n\n\t/**\n\t * Return the configuration property source for this contributor.\n\t * @return the configuration property source or {@code null}\n\t */\n\t@Nullable ConfigurationPropertySource getConfigurationPropertySource() {\n\t\treturn this.configurationPropertySource;\n\t}\n\n\t/**\n\t * Return if the contributor has a specific config data option.\n\t * @param option the option to check\n\t * @return {@code true} if the option is present\n\t */\n\tboolean hasConfigDataOption(ConfigData.Option option) {\n\t\treturn this.configDataOptions.contains(option);\n\t}\n\n\tConfigDataEnvironmentContributor withoutConfigDataOption(ConfigData.Option option) {\n\t\treturn new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource,\n\t\t\t\tthis.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, this.properties,\n\t\t\t\tthis.configDataOptions.without(option), this.children, this.conversionService);\n\t}\n\n\t/**\n\t * Return any imports requested by this contributor.\n\t * @return the imports\n\t */\n\tList<ConfigDataLocation> getImports() {\n\t\treturn (this.properties != null) ? this.properties.getImports() : Collections.emptyList();\n\t}\n\n\t/**\n\t * Return true if this contributor has imports that have not yet been processed in the\n\t * given phase.\n\t * @param importPhase the import phase\n\t * @return if there are unprocessed imports\n\t */\n\tboolean hasUnprocessedImports(ImportPhase importPhase) {\n\t\tif (getImports().isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn !this.children.containsKey(importPhase);\n\t}\n\n\t/**\n\t * Return children of this contributor for the given phase.\n\t * @param importPhase the import phase\n\t * @return a list of children\n\t */\n\tList<ConfigDataEnvironmentContributor> getChildren(ImportPhase importPhase) {\n\t\treturn this.children.getOrDefault(importPhase, Collections.emptyList());\n\t}\n\n\t/**\n\t * Returns a {@link Stream} that traverses this contributor and all its children in\n\t * priority order.\n\t * @return the stream\n\t */\n\tStream<ConfigDataEnvironmentContributor> stream() {\n\t\treturn StreamSupport.stream(spliterator(), false);\n\t}\n\n\t/**\n\t * Returns an {@link Iterator} that traverses this contributor and all its children in\n\t * priority order.\n\t * @return the iterator\n\t * @see java.lang.Iterable#iterator()\n\t */\n\t@Override\n\tpublic Iterator<ConfigDataEnvironmentContributor> iterator() {\n\t\treturn new ContributorIterator();\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataEnvironmentContributor} with bound\n\t * {@link ConfigDataProperties}.\n\t * @param contributors the contributors used for binding\n\t * @param activationContext the activation context\n\t * @return a new contributor instance\n\t */\n\tConfigDataEnvironmentContributor withBoundProperties(Iterable<ConfigDataEnvironmentContributor> contributors,\n\t\t\t@Nullable ConfigDataActivationContext activationContext) {\n\t\tConfigurationPropertySource configurationPropertySource = getConfigurationPropertySource();\n\t\tAssert.state(configurationPropertySource != null, \"'configurationPropertySource' must not be null\");\n\t\tIterable<ConfigurationPropertySource> sources = Collections.singleton(configurationPropertySource);\n\t\tPlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tcontributors, activationContext, this, true, this.conversionService);\n\t\tBinder binder = new Binder(sources, placeholdersResolver, null, null, null);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tif (properties != null && this.configDataOptions.contains(ConfigData.Option.IGNORE_IMPORTS)) {\n\t\t\tproperties = properties.withoutImports();\n\t\t}\n\t\treturn new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, this.location, this.resource,\n\t\t\t\tthis.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, properties,\n\t\t\t\tthis.configDataOptions, null, this.conversionService);\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataEnvironmentContributor} instance with a new set of\n\t * children for the given phase.\n\t * @param importPhase the import phase\n\t * @param children the new children\n\t * @return a new contributor instance\n\t */\n\tConfigDataEnvironmentContributor withChildren(ImportPhase importPhase,\n\t\t\tList<ConfigDataEnvironmentContributor> children) {\n\t\tMap<ImportPhase, List<ConfigDataEnvironmentContributor>> updatedChildren = new LinkedHashMap<>(this.children);\n\t\tupdatedChildren.put(importPhase, children);\n\t\tif (importPhase == ImportPhase.AFTER_PROFILE_ACTIVATION) {\n\t\t\tmoveProfileSpecific(updatedChildren);\n\t\t}\n\t\treturn new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource,\n\t\t\t\tthis.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, this.properties,\n\t\t\t\tthis.configDataOptions, updatedChildren, this.conversionService);\n\t}\n\n\tprivate void moveProfileSpecific(Map<ImportPhase, List<ConfigDataEnvironmentContributor>> children) {\n\t\tList<ConfigDataEnvironmentContributor> before = children.get(ImportPhase.BEFORE_PROFILE_ACTIVATION);\n\t\tif (!hasAnyProfileSpecificChildren(before)) {\n\t\t\treturn;\n\t\t}\n\t\tList<ConfigDataEnvironmentContributor> updatedBefore = new ArrayList<>(before.size());\n\t\tList<ConfigDataEnvironmentContributor> updatedAfter = new ArrayList<>();\n\t\tfor (ConfigDataEnvironmentContributor contributor : before) {\n\t\t\tupdatedBefore.add(moveProfileSpecificChildren(contributor, updatedAfter));\n\t\t}\n\t\tupdatedAfter.addAll(children.getOrDefault(ImportPhase.AFTER_PROFILE_ACTIVATION, Collections.emptyList()));\n\t\tchildren.put(ImportPhase.BEFORE_PROFILE_ACTIVATION, updatedBefore);\n\t\tchildren.put(ImportPhase.AFTER_PROFILE_ACTIVATION, updatedAfter);\n\t}\n\n\tprivate ConfigDataEnvironmentContributor moveProfileSpecificChildren(ConfigDataEnvironmentContributor contributor,\n\t\t\tList<ConfigDataEnvironmentContributor> removed) {\n\t\tfor (ImportPhase importPhase : ImportPhase.values()) {\n\t\t\tList<ConfigDataEnvironmentContributor> children = contributor.getChildren(importPhase);\n\t\t\tList<ConfigDataEnvironmentContributor> updatedChildren = new ArrayList<>(children.size());\n\t\t\tfor (ConfigDataEnvironmentContributor child : children) {\n\t\t\t\tif (child.hasConfigDataOption(ConfigData.Option.PROFILE_SPECIFIC)) {\n\t\t\t\t\tremoved.add(child.withoutConfigDataOption(ConfigData.Option.PROFILE_SPECIFIC));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tupdatedChildren.add(child);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontributor = contributor.withChildren(importPhase, updatedChildren);\n\t\t}\n\t\treturn contributor;\n\t}\n\n\t@Contract(\"null -> false\")\n\tprivate boolean hasAnyProfileSpecificChildren(@Nullable List<ConfigDataEnvironmentContributor> contributors) {\n\t\tif (CollectionUtils.isEmpty(contributors)) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\tfor (ImportPhase importPhase : ImportPhase.values()) {\n\t\t\t\tif (contributor.getChildren(importPhase)\n\t\t\t\t\t.stream()\n\t\t\t\t\t.anyMatch((child) -> child.hasConfigDataOption(ConfigData.Option.PROFILE_SPECIFIC))) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataEnvironmentContributor} instance where an existing\n\t * child is replaced.\n\t * @param existing the existing node that should be replaced\n\t * @param replacement the replacement node that should be used instead\n\t * @return a new {@link ConfigDataEnvironmentContributor} instance\n\t */\n\tConfigDataEnvironmentContributor withReplacement(ConfigDataEnvironmentContributor existing,\n\t\t\tConfigDataEnvironmentContributor replacement) {\n\t\tif (this == existing) {\n\t\t\treturn replacement;\n\t\t}\n\t\tMap<ImportPhase, List<ConfigDataEnvironmentContributor>> updatedChildren = new LinkedHashMap<>(\n\t\t\t\tthis.children.size());\n\t\tthis.children.forEach((importPhase, contributors) -> {\n\t\t\tList<ConfigDataEnvironmentContributor> updatedContributors = new ArrayList<>(contributors.size());\n\t\t\tfor (ConfigDataEnvironmentContributor contributor : contributors) {\n\t\t\t\tupdatedContributors.add(contributor.withReplacement(existing, replacement));\n\t\t\t}\n\t\t\tupdatedChildren.put(importPhase, Collections.unmodifiableList(updatedContributors));\n\t\t});\n\t\treturn new ConfigDataEnvironmentContributor(this.kind, this.location, this.resource,\n\t\t\t\tthis.fromProfileSpecificImport, this.propertySource, this.configurationPropertySource, this.properties,\n\t\t\t\tthis.configDataOptions, updatedChildren, this.conversionService);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tbuildToString(\"\", builder);\n\t\treturn builder.toString();\n\t}\n\n\tprivate void buildToString(String prefix, StringBuilder builder) {\n\t\tbuilder.append(prefix);\n\t\tbuilder.append(this.kind);\n\t\tbuilder.append(\" \");\n\t\tbuilder.append(this.location);\n\t\tbuilder.append(\" \");\n\t\tbuilder.append(this.resource);\n\t\tbuilder.append(\" \");\n\t\tbuilder.append(this.configDataOptions);\n\t\tbuilder.append(\"\\n\");\n\t\tfor (ConfigDataEnvironmentContributor child : this.children.getOrDefault(ImportPhase.BEFORE_PROFILE_ACTIVATION,\n\t\t\t\tCollections.emptyList())) {\n\t\t\tchild.buildToString(prefix + \"    \", builder);\n\t\t}\n\t\tfor (ConfigDataEnvironmentContributor child : this.children.getOrDefault(ImportPhase.AFTER_PROFILE_ACTIVATION,\n\t\t\t\tCollections.emptyList())) {\n\t\t\tchild.buildToString(prefix + \"    \", builder);\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to create a {@link Kind#ROOT root} contributor.\n\t * @param contributors the immediate children of the root\n\t * @param conversionService the conversion service to use\n\t * @return a new {@link ConfigDataEnvironmentContributor} instance\n\t */\n\tstatic ConfigDataEnvironmentContributor of(List<ConfigDataEnvironmentContributor> contributors,\n\t\t\tConversionService conversionService) {\n\t\tMap<ImportPhase, List<ConfigDataEnvironmentContributor>> children = new LinkedHashMap<>();\n\t\tchildren.put(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.unmodifiableList(contributors));\n\t\treturn new ConfigDataEnvironmentContributor(Kind.ROOT, null, null, false, null, null, null, null, children,\n\t\t\t\tconversionService);\n\t}\n\n\t/**\n\t * Factory method to create a {@link Kind#INITIAL_IMPORT initial import} contributor.\n\t * This contributor is used to trigger initial imports of additional contributors. It\n\t * does not contribute any properties itself.\n\t * @param initialImports the initial import locations (with placeholders resolved)\n\t * @param conversionService the conversion service to use\n\t * @return a new {@link ConfigDataEnvironmentContributor} instance\n\t */\n\tstatic ConfigDataEnvironmentContributor ofInitialImports(List<ConfigDataLocation> initialImports,\n\t\t\tConversionService conversionService) {\n\t\tConfigDataProperties properties = new ConfigDataProperties(initialImports, null);\n\t\treturn new ConfigDataEnvironmentContributor(Kind.INITIAL_IMPORT, null, null, false, null, null, properties,\n\t\t\t\tnull, null, conversionService);\n\t}\n\n\t/**\n\t * Factory method to create a contributor that wraps an {@link Kind#EXISTING existing}\n\t * property source. The contributor provides access to existing properties, but\n\t * doesn't actively import any additional contributors.\n\t * @param propertySource the property source to wrap\n\t * @param conversionService the conversion service to use\n\t * @return a new {@link ConfigDataEnvironmentContributor} instance\n\t */\n\tstatic ConfigDataEnvironmentContributor ofExisting(PropertySource<?> propertySource,\n\t\t\tConversionService conversionService) {\n\t\treturn new ConfigDataEnvironmentContributor(Kind.EXISTING, null, null, false, propertySource,\n\t\t\t\tasConfigurationPropertySource(propertySource), null, null, null, conversionService);\n\t}\n\n\t/**\n\t * Factory method to create an {@link Kind#UNBOUND_IMPORT unbound import} contributor.\n\t * This contributor has been actively imported from another contributor and may itself\n\t * import further contributors later.\n\t * @param location the location of this contributor\n\t * @param resource the config data resource\n\t * @param profileSpecific if the contributor is from a profile specific import\n\t * @param configData the config data\n\t * @param propertySourceIndex the index of the property source that should be used\n\t * @param conversionService the conversion service to use\n\t * @param environmentUpdateListener the environment update listener\n\t * @return a new {@link ConfigDataEnvironmentContributor} instance\n\t */\n\tstatic ConfigDataEnvironmentContributor ofUnboundImport(@Nullable ConfigDataLocation location,\n\t\t\t@Nullable ConfigDataResource resource, boolean profileSpecific, ConfigData configData,\n\t\t\tint propertySourceIndex, ConversionService conversionService,\n\t\t\tConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\tPropertySource<?> propertySource = configData.getPropertySources().get(propertySourceIndex);\n\t\tConfigData.Options options = configData.getOptions(propertySource);\n\t\toptions = environmentUpdateListener.onConfigDataOptions(configData, propertySource, options);\n\t\treturn new ConfigDataEnvironmentContributor(Kind.UNBOUND_IMPORT, location, resource, profileSpecific,\n\t\t\t\tpropertySource, asConfigurationPropertySource(propertySource), null, options, null, conversionService);\n\t}\n\n\tprivate static @Nullable ConfigurationPropertySource asConfigurationPropertySource(\n\t\t\tPropertySource<?> propertySource) {\n\t\tConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(propertySource);\n\t\tif (configurationPropertySource != null && propertySource instanceof PropertySourceInfo propertySourceInfo) {\n\t\t\tconfigurationPropertySource = configurationPropertySource.withPrefix(propertySourceInfo.getPrefix());\n\t\t}\n\t\treturn configurationPropertySource;\n\t}\n\n\t/**\n\t * Factory method to create an {@link Kind#EMPTY_LOCATION empty location} contributor.\n\t * @param location the location of this contributor\n\t * @param profileSpecific if the contributor is from a profile specific import\n\t * @param conversionService the conversion service to use\n\t * @return a new {@link ConfigDataEnvironmentContributor} instance\n\t */\n\tstatic ConfigDataEnvironmentContributor ofEmptyLocation(ConfigDataLocation location, boolean profileSpecific,\n\t\t\tConversionService conversionService) {\n\t\treturn new ConfigDataEnvironmentContributor(Kind.EMPTY_LOCATION, location, null, profileSpecific, null, null,\n\t\t\t\tnull, EMPTY_LOCATION_OPTIONS, null, conversionService);\n\t}\n\n\t/**\n\t * The various kinds of contributor.\n\t */\n\tenum Kind {\n\n\t\t/**\n\t\t * A root contributor used contain the initial set of children.\n\t\t */\n\t\tROOT,\n\n\t\t/**\n\t\t * An initial import that needs to be processed.\n\t\t */\n\t\tINITIAL_IMPORT,\n\n\t\t/**\n\t\t * An existing property source that contributes properties but no imports.\n\t\t */\n\t\tEXISTING,\n\n\t\t/**\n\t\t * A contributor with {@link ConfigData} imported from another contributor but not\n\t\t * yet bound.\n\t\t */\n\t\tUNBOUND_IMPORT,\n\n\t\t/**\n\t\t * A contributor with {@link ConfigData} imported from another contributor that\n\t\t * has been.\n\t\t */\n\t\tBOUND_IMPORT,\n\n\t\t/**\n\t\t * A valid location that contained nothing to load.\n\t\t */\n\t\tEMPTY_LOCATION\n\n\t}\n\n\t/**\n\t * Import phases that can be used when obtaining imports.\n\t */\n\tenum ImportPhase {\n\n\t\t/**\n\t\t * The phase before profiles have been activated.\n\t\t */\n\t\tBEFORE_PROFILE_ACTIVATION,\n\n\t\t/**\n\t\t * The phase after profiles have been activated.\n\t\t */\n\t\tAFTER_PROFILE_ACTIVATION;\n\n\t\t/**\n\t\t * Return the {@link ImportPhase} based on the given activation context.\n\t\t * @param activationContext the activation context\n\t\t * @return the import phase\n\t\t */\n\t\tstatic ImportPhase get(@Nullable ConfigDataActivationContext activationContext) {\n\t\t\tif (activationContext != null && activationContext.getProfiles() != null) {\n\t\t\t\treturn AFTER_PROFILE_ACTIVATION;\n\t\t\t}\n\t\t\treturn BEFORE_PROFILE_ACTIVATION;\n\t\t}\n\n\t}\n\n\t/**\n\t * Iterator that traverses the contributor tree.\n\t */\n\tprivate final class ContributorIterator implements Iterator<ConfigDataEnvironmentContributor> {\n\n\t\tprivate @Nullable ImportPhase phase;\n\n\t\tprivate Iterator<ConfigDataEnvironmentContributor> children;\n\n\t\tprivate Iterator<ConfigDataEnvironmentContributor> current;\n\n\t\tprivate @Nullable ConfigDataEnvironmentContributor next;\n\n\t\tprivate ContributorIterator() {\n\t\t\tthis.phase = ImportPhase.AFTER_PROFILE_ACTIVATION;\n\t\t\tthis.children = getChildren(this.phase).iterator();\n\t\t\tthis.current = Collections.emptyIterator();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasNext() {\n\t\t\treturn fetchIfNecessary() != null;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigDataEnvironmentContributor next() {\n\t\t\tConfigDataEnvironmentContributor next = fetchIfNecessary();\n\t\t\tif (next == null) {\n\t\t\t\tthrow new NoSuchElementException();\n\t\t\t}\n\t\t\tthis.next = null;\n\t\t\treturn next;\n\t\t}\n\n\t\tprivate @Nullable ConfigDataEnvironmentContributor fetchIfNecessary() {\n\t\t\tif (this.next != null) {\n\t\t\t\treturn this.next;\n\t\t\t}\n\t\t\tif (this.current.hasNext()) {\n\t\t\t\tthis.next = this.current.next();\n\t\t\t\treturn this.next;\n\t\t\t}\n\t\t\tif (this.children.hasNext()) {\n\t\t\t\tthis.current = this.children.next().iterator();\n\t\t\t\treturn fetchIfNecessary();\n\t\t\t}\n\t\t\tif (this.phase == ImportPhase.AFTER_PROFILE_ACTIVATION) {\n\t\t\t\tthis.phase = ImportPhase.BEFORE_PROFILE_ACTIVATION;\n\t\t\t\tthis.children = getChildren(this.phase).iterator();\n\t\t\t\treturn fetchIfNecessary();\n\t\t\t}\n\t\t\tif (this.phase == ImportPhase.BEFORE_PROFILE_ACTIVATION) {\n\t\t\t\tthis.phase = null;\n\t\t\t\tthis.next = ConfigDataEnvironmentContributor.this;\n\t\t\t\treturn this.next;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;\nimport org.springframework.boot.context.properties.bind.PlaceholdersResolver;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.PropertyPlaceholderHelper;\nimport org.springframework.util.SystemPropertyUtils;\n\n/**\n * {@link PlaceholdersResolver} backed by one or more\n * {@link ConfigDataEnvironmentContributor} instances.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\nclass ConfigDataEnvironmentContributorPlaceholdersResolver implements PlaceholdersResolver {\n\n\tprivate final Iterable<ConfigDataEnvironmentContributor> contributors;\n\n\tprivate final @Nullable ConfigDataActivationContext activationContext;\n\n\tprivate final boolean failOnResolveFromInactiveContributor;\n\n\tprivate final PropertyPlaceholderHelper helper;\n\n\tprivate final @Nullable ConfigDataEnvironmentContributor activeContributor;\n\n\tprivate final ConversionService conversionService;\n\n\tConfigDataEnvironmentContributorPlaceholdersResolver(Iterable<ConfigDataEnvironmentContributor> contributors,\n\t\t\t@Nullable ConfigDataActivationContext activationContext,\n\t\t\t@Nullable ConfigDataEnvironmentContributor activeContributor, boolean failOnResolveFromInactiveContributor,\n\t\t\tConversionService conversionService) {\n\t\tthis.contributors = contributors;\n\t\tthis.activationContext = activationContext;\n\t\tthis.activeContributor = activeContributor;\n\t\tthis.failOnResolveFromInactiveContributor = failOnResolveFromInactiveContributor;\n\t\tthis.conversionService = conversionService;\n\t\tthis.helper = new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,\n\t\t\t\tSystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR,\n\t\t\t\tSystemPropertyUtils.ESCAPE_CHARACTER, true);\n\t}\n\n\t@Override\n\tpublic @Nullable Object resolvePlaceholders(@Nullable Object value) {\n\t\tif (value instanceof String string) {\n\t\t\treturn this.helper.replacePlaceholders(string, this::resolvePlaceholder);\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate @Nullable String resolvePlaceholder(String placeholder) {\n\t\tObject result = null;\n\t\tfor (ConfigDataEnvironmentContributor contributor : this.contributors) {\n\t\t\tPropertySource<?> propertySource = contributor.getPropertySource();\n\t\t\tObject value = (propertySource != null) ? propertySource.getProperty(placeholder) : null;\n\t\t\tif (value != null && !isActive(contributor)) {\n\t\t\t\tif (this.failOnResolveFromInactiveContributor) {\n\t\t\t\t\tConfigDataResource resource = contributor.getResource();\n\t\t\t\t\tAssert.state(propertySource != null, \"'propertySource' can't be null here\");\n\t\t\t\t\tOrigin origin = OriginLookup.getOrigin(propertySource, placeholder);\n\t\t\t\t\tthrow new InactiveConfigDataAccessException(propertySource, resource, placeholder, origin);\n\t\t\t\t}\n\t\t\t\tvalue = null;\n\t\t\t}\n\t\t\tresult = (result != null) ? result : value;\n\t\t}\n\t\treturn (result != null) ? convertValueIfNecessary(result) : null;\n\t}\n\n\tprivate boolean isActive(ConfigDataEnvironmentContributor contributor) {\n\t\tif (contributor == this.activeContributor) {\n\t\t\treturn true;\n\t\t}\n\t\tif (contributor.getKind() != Kind.UNBOUND_IMPORT) {\n\t\t\treturn contributor.isActive(this.activationContext);\n\t\t}\n\t\treturn contributor.withBoundProperties(this.contributors, this.activationContext)\n\t\t\t.isActive(this.activationContext);\n\t}\n\n\tprivate @Nullable String convertValueIfNecessary(Object value) {\n\t\treturn (value instanceof String string) ? string : this.conversionService.convert(value, String.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.ImportPhase;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.PlaceholdersResolver;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * An immutable tree structure of {@link ConfigDataEnvironmentContributors} used to\n * process imports.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataEnvironmentContributors implements Iterable<ConfigDataEnvironmentContributor> {\n\n\tprivate static final Predicate<ConfigDataEnvironmentContributor> NO_CONTRIBUTOR_FILTER = (contributor) -> true;\n\n\tprivate final Log logger;\n\n\tprivate final ConfigDataEnvironmentContributor root;\n\n\tprivate final ConfigurableBootstrapContext bootstrapContext;\n\n\tprivate final ConversionService conversionService;\n\n\tprivate final ConfigDataEnvironmentUpdateListener environmentUpdateListener;\n\n\t/**\n\t * Create a new {@link ConfigDataEnvironmentContributors} instance.\n\t * @param logFactory the log factory\n\t * @param bootstrapContext the bootstrap context\n\t * @param contributors the initial set of contributors\n\t * @param conversionService the conversion service to use\n\t * @param environmentUpdateListener the environment update listener\n\t */\n\tConfigDataEnvironmentContributors(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,\n\t\t\tList<ConfigDataEnvironmentContributor> contributors, ConversionService conversionService,\n\t\t\tConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\tthis.logger = logFactory.getLog(getClass());\n\t\tthis.bootstrapContext = bootstrapContext;\n\t\tthis.root = ConfigDataEnvironmentContributor.of(contributors, conversionService);\n\t\tthis.conversionService = conversionService;\n\t\tthis.environmentUpdateListener = environmentUpdateListener;\n\t}\n\n\tprivate ConfigDataEnvironmentContributors(Log logger, ConfigurableBootstrapContext bootstrapContext,\n\t\t\tConfigDataEnvironmentContributor root, ConversionService conversionService,\n\t\t\tConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\tthis.logger = logger;\n\t\tthis.bootstrapContext = bootstrapContext;\n\t\tthis.root = root;\n\t\tthis.conversionService = conversionService;\n\t\tthis.environmentUpdateListener = environmentUpdateListener;\n\t}\n\n\t/**\n\t * Processes imports from all active contributors and return a new\n\t * {@link ConfigDataEnvironmentContributors} instance.\n\t * @param importer the importer used to import {@link ConfigData}\n\t * @param activationContext the current activation context or {@code null} if the\n\t * context has not yet been created\n\t * @return a {@link ConfigDataEnvironmentContributors} instance with all relevant\n\t * imports have been processed\n\t */\n\tConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter importer,\n\t\t\t@Nullable ConfigDataActivationContext activationContext) {\n\t\tImportPhase importPhase = ImportPhase.get(activationContext);\n\t\tthis.logger.trace(LogMessage.format(\"Processing imports for phase %s. %s\", importPhase,\n\t\t\t\t(activationContext != null) ? activationContext : \"no activation context\"));\n\t\tConfigDataEnvironmentContributors result = this;\n\t\tint processed = 0;\n\t\twhile (true) {\n\t\t\tConfigDataEnvironmentContributor contributor = getNextToProcess(result, activationContext, importPhase);\n\t\t\tif (contributor == null) {\n\t\t\t\tthis.logger.trace(LogMessage.format(\"Processed imports for of %d contributors\", processed));\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tif (contributor.getKind() == Kind.UNBOUND_IMPORT) {\n\t\t\t\tConfigDataEnvironmentContributor bound = contributor.withBoundProperties(result, activationContext);\n\t\t\t\tresult = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,\n\t\t\t\t\t\tresult.getRoot().withReplacement(contributor, bound), this.conversionService,\n\t\t\t\t\t\tthis.environmentUpdateListener);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(\n\t\t\t\t\tresult, contributor, activationContext);\n\t\t\tConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);\n\t\t\tList<ConfigDataLocation> imports = contributor.getImports();\n\t\t\tthis.logger.trace(LogMessage.format(\"Processing imports %s\", imports));\n\t\t\tMap<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext,\n\t\t\t\t\tlocationResolverContext, loaderContext, imports);\n\t\t\tthis.logger.trace(LogMessage.of(() -> getImportedMessage(imported.keySet())));\n\t\t\tConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase,\n\t\t\t\t\tasContributors(imported));\n\t\t\tresult = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext,\n\t\t\t\t\tresult.getRoot().withReplacement(contributor, contributorAndChildren), this.conversionService,\n\t\t\t\t\tthis.environmentUpdateListener);\n\t\t\tprocessed++;\n\t\t}\n\t}\n\n\tprivate CharSequence getImportedMessage(Set<ConfigDataResolutionResult> results) {\n\t\tif (results.isEmpty()) {\n\t\t\treturn \"Nothing imported\";\n\t\t}\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\"Imported \" + results.size() + \" resource\" + ((results.size() != 1) ? \"s \" : \" \"));\n\t\tmessage.append(results.stream().map(ConfigDataResolutionResult::getResource).toList());\n\t\treturn message;\n\t}\n\n\tprotected final ConfigurableBootstrapContext getBootstrapContext() {\n\t\treturn this.bootstrapContext;\n\t}\n\n\tprivate @Nullable ConfigDataEnvironmentContributor getNextToProcess(ConfigDataEnvironmentContributors contributors,\n\t\t\t@Nullable ConfigDataActivationContext activationContext, ImportPhase importPhase) {\n\t\tfor (ConfigDataEnvironmentContributor contributor : contributors.getRoot()) {\n\t\t\tif (contributor.getKind() == Kind.UNBOUND_IMPORT\n\t\t\t\t\t|| isActiveWithUnprocessedImports(activationContext, importPhase, contributor)) {\n\t\t\t\treturn contributor;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isActiveWithUnprocessedImports(@Nullable ConfigDataActivationContext activationContext,\n\t\t\tImportPhase importPhase, ConfigDataEnvironmentContributor contributor) {\n\t\treturn contributor.isActive(activationContext) && contributor.hasUnprocessedImports(importPhase);\n\t}\n\n\tprivate List<ConfigDataEnvironmentContributor> asContributors(\n\t\t\tMap<ConfigDataResolutionResult, ConfigData> imported) {\n\t\tList<ConfigDataEnvironmentContributor> contributors = new ArrayList<>(imported.size() * 5);\n\t\timported.forEach((resolutionResult, data) -> {\n\t\t\tConfigDataLocation location = resolutionResult.getLocation();\n\t\t\tConfigDataResource resource = resolutionResult.getResource();\n\t\t\tboolean profileSpecific = resolutionResult.isProfileSpecific();\n\t\t\tif (data.getPropertySources().isEmpty()) {\n\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofEmptyLocation(location, profileSpecific,\n\t\t\t\t\t\tthis.conversionService));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (int i = data.getPropertySources().size() - 1; i >= 0; i--) {\n\t\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(location, resource,\n\t\t\t\t\t\t\tprofileSpecific, data, i, this.conversionService, this.environmentUpdateListener));\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn Collections.unmodifiableList(contributors);\n\t}\n\n\t/**\n\t * Returns the root contributor.\n\t * @return the root contributor.\n\t */\n\tConfigDataEnvironmentContributor getRoot() {\n\t\treturn this.root;\n\t}\n\n\t/**\n\t * Return a {@link Binder} backed by the contributors.\n\t * @param activationContext the activation context\n\t * @param options binder options to apply\n\t * @return a binder instance\n\t */\n\tBinder getBinder(@Nullable ConfigDataActivationContext activationContext, BinderOption... options) {\n\t\treturn getBinder(activationContext, NO_CONTRIBUTOR_FILTER, options);\n\t}\n\n\t/**\n\t * Return a {@link Binder} backed by the contributors.\n\t * @param activationContext the activation context\n\t * @param filter a filter used to limit the contributors\n\t * @param options binder options to apply\n\t * @return a binder instance\n\t */\n\tBinder getBinder(@Nullable ConfigDataActivationContext activationContext,\n\t\t\tPredicate<ConfigDataEnvironmentContributor> filter, BinderOption... options) {\n\t\treturn getBinder(activationContext, filter, asBinderOptionsSet(options));\n\t}\n\n\tprivate Set<BinderOption> asBinderOptionsSet(BinderOption... options) {\n\t\treturn ObjectUtils.isEmpty(options) ? EnumSet.noneOf(BinderOption.class)\n\t\t\t\t: EnumSet.copyOf(Arrays.asList(options));\n\t}\n\n\tprivate Binder getBinder(@Nullable ConfigDataActivationContext activationContext,\n\t\t\tPredicate<ConfigDataEnvironmentContributor> filter, Set<BinderOption> options) {\n\t\tboolean failOnInactiveSource = options.contains(BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);\n\t\tIterable<ConfigurationPropertySource> sources = () -> getBinderSources(\n\t\t\t\tfilter.and((contributor) -> failOnInactiveSource || contributor.isActive(activationContext)));\n\t\tPlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(this.root,\n\t\t\t\tactivationContext, null, failOnInactiveSource, this.conversionService);\n\t\tBindHandler bindHandler = !failOnInactiveSource ? null : new InactiveSourceChecker(activationContext);\n\t\treturn new Binder(sources, placeholdersResolver, null, null, bindHandler);\n\t}\n\n\tprivate Iterator<ConfigurationPropertySource> getBinderSources(Predicate<ConfigDataEnvironmentContributor> filter) {\n\t\treturn this.root.stream()\n\t\t\t.filter(this::hasConfigurationPropertySource)\n\t\t\t.filter(filter)\n\t\t\t.map(ConfigDataEnvironmentContributor::getConfigurationPropertySource)\n\t\t\t.iterator();\n\t}\n\n\tprivate boolean hasConfigurationPropertySource(ConfigDataEnvironmentContributor contributor) {\n\t\treturn contributor.getConfigurationPropertySource() != null;\n\t}\n\n\t@Override\n\tpublic Iterator<ConfigDataEnvironmentContributor> iterator() {\n\t\treturn this.root.iterator();\n\t}\n\n\t/**\n\t * {@link ConfigDataLocationResolverContext} for a contributor.\n\t */\n\tprivate static class ContributorDataLoaderContext implements ConfigDataLoaderContext {\n\n\t\tprivate final ConfigDataEnvironmentContributors contributors;\n\n\t\tContributorDataLoaderContext(ConfigDataEnvironmentContributors contributors) {\n\t\t\tthis.contributors = contributors;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurableBootstrapContext getBootstrapContext() {\n\t\t\treturn this.contributors.getBootstrapContext();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ConfigDataLocationResolverContext} for a contributor.\n\t */\n\tprivate static class ContributorConfigDataLocationResolverContext implements ConfigDataLocationResolverContext {\n\n\t\tprivate final ConfigDataEnvironmentContributors contributors;\n\n\t\tprivate final ConfigDataEnvironmentContributor contributor;\n\n\t\tprivate final @Nullable ConfigDataActivationContext activationContext;\n\n\t\tprivate volatile @Nullable Binder binder;\n\n\t\tContributorConfigDataLocationResolverContext(ConfigDataEnvironmentContributors contributors,\n\t\t\t\tConfigDataEnvironmentContributor contributor, @Nullable ConfigDataActivationContext activationContext) {\n\t\t\tthis.contributors = contributors;\n\t\t\tthis.contributor = contributor;\n\t\t\tthis.activationContext = activationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic Binder getBinder() {\n\t\t\tBinder binder = this.binder;\n\t\t\tif (binder == null) {\n\t\t\t\tbinder = this.contributors.getBinder(this.activationContext);\n\t\t\t\tthis.binder = binder;\n\t\t\t}\n\t\t\treturn binder;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConfigDataResource getParent() {\n\t\t\treturn this.contributor.getResource();\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurableBootstrapContext getBootstrapContext() {\n\t\t\treturn this.contributors.getBootstrapContext();\n\t\t}\n\n\t}\n\n\tprivate class InactiveSourceChecker implements BindHandler {\n\n\t\tprivate final @Nullable ConfigDataActivationContext activationContext;\n\n\t\tInactiveSourceChecker(@Nullable ConfigDataActivationContext activationContext) {\n\t\t\tthis.activationContext = activationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t\tObject result) {\n\t\t\tfor (ConfigDataEnvironmentContributor contributor : ConfigDataEnvironmentContributors.this) {\n\t\t\t\tif (!contributor.isActive(this.activationContext)) {\n\t\t\t\t\tInactiveConfigDataAccessException.throwIfPropertyFound(contributor, name);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\t/**\n\t * Binder options that can be used with\n\t * {@link ConfigDataEnvironmentContributors#getBinder(ConfigDataActivationContext, BinderOption...)}.\n\t */\n\tenum BinderOption {\n\n\t\t/**\n\t\t * Throw an exception if an inactive contributor contains a bound value.\n\t\t */\n\t\tFAIL_ON_BIND_TO_INACTIVE_SOURCE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link EnvironmentPostProcessor} that loads and applies {@link ConfigData} to Spring's\n * {@link Environment}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Nguyen Bao Sach\n * @since 2.4.0\n */\npublic class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\t/**\n\t * The default order for the processor.\n\t */\n\tpublic static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 10;\n\n\t/**\n\t * Property used to determine what action to take when a\n\t * {@code ConfigDataLocationNotFoundException} is thrown.\n\t * @see ConfigDataNotFoundAction\n\t */\n\tpublic static final String ON_LOCATION_NOT_FOUND_PROPERTY = ConfigDataEnvironment.ON_NOT_FOUND_PROPERTY;\n\n\tprivate final DeferredLogFactory logFactory;\n\n\tprivate final Log logger;\n\n\tprivate final ConfigurableBootstrapContext bootstrapContext;\n\n\tprivate final @Nullable ConfigDataEnvironmentUpdateListener environmentUpdateListener;\n\n\tpublic ConfigDataEnvironmentPostProcessor(DeferredLogFactory logFactory,\n\t\t\tConfigurableBootstrapContext bootstrapContext) {\n\t\tthis(logFactory, bootstrapContext, null);\n\t}\n\n\tprivate ConfigDataEnvironmentPostProcessor(DeferredLogFactory logFactory,\n\t\t\tConfigurableBootstrapContext bootstrapContext,\n\t\t\t@Nullable ConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\tthis.logFactory = logFactory;\n\t\tthis.logger = logFactory.getLog(getClass());\n\t\tthis.bootstrapContext = bootstrapContext;\n\t\tthis.environmentUpdateListener = environmentUpdateListener;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tpostProcessEnvironment(environment, application.getResourceLoader(), application.getAdditionalProfiles());\n\t}\n\n\tvoid postProcessEnvironment(ConfigurableEnvironment environment, @Nullable ResourceLoader resourceLoader,\n\t\t\tCollection<String> additionalProfiles) {\n\t\tthis.logger.trace(\"Post-processing environment to add config data\");\n\t\tresourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();\n\t\tgetConfigDataEnvironment(environment, resourceLoader, additionalProfiles).processAndApply();\n\t}\n\n\tConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,\n\t\t\tCollection<String> additionalProfiles) {\n\t\treturn new ConfigDataEnvironment(this.logFactory, this.bootstrapContext, environment, resourceLoader,\n\t\t\t\tadditionalProfiles, this.environmentUpdateListener);\n\t}\n\n\t/**\n\t * Apply {@link ConfigData} post-processing to an existing {@link Environment}. This\n\t * method can be useful when working with an {@link Environment} that has been created\n\t * directly and not necessarily as part of a {@link SpringApplication}.\n\t * @param environment the environment to apply {@link ConfigData} to\n\t */\n\tpublic static void applyTo(ConfigurableEnvironment environment) {\n\t\tapplyTo(environment, null, null, Collections.emptyList());\n\t}\n\n\t/**\n\t * Apply {@link ConfigData} post-processing to an existing {@link Environment}. This\n\t * method can be useful when working with an {@link Environment} that has been created\n\t * directly and not necessarily as part of a {@link SpringApplication}.\n\t * @param environment the environment to apply {@link ConfigData} to\n\t * @param resourceLoader the resource loader to use\n\t * @param bootstrapContext the bootstrap context to use or {@code null} to use a\n\t * throw-away context\n\t * @param additionalProfiles any additional profiles that should be applied\n\t */\n\tpublic static void applyTo(ConfigurableEnvironment environment, ResourceLoader resourceLoader,\n\t\t\t@Nullable ConfigurableBootstrapContext bootstrapContext, String... additionalProfiles) {\n\t\tapplyTo(environment, resourceLoader, bootstrapContext, Arrays.asList(additionalProfiles));\n\t}\n\n\t/**\n\t * Apply {@link ConfigData} post-processing to an existing {@link Environment}. This\n\t * method can be useful when working with an {@link Environment} that has been created\n\t * directly and not necessarily as part of a {@link SpringApplication}.\n\t * @param environment the environment to apply {@link ConfigData} to\n\t * @param resourceLoader the resource loader to use\n\t * @param bootstrapContext the bootstrap context to use or {@code null} to use a\n\t * throw-away context\n\t * @param additionalProfiles any additional profiles that should be applied\n\t */\n\tpublic static void applyTo(ConfigurableEnvironment environment, @Nullable ResourceLoader resourceLoader,\n\t\t\t@Nullable ConfigurableBootstrapContext bootstrapContext, Collection<String> additionalProfiles) {\n\t\tDeferredLogFactory logFactory = Supplier::get;\n\t\tbootstrapContext = (bootstrapContext != null) ? bootstrapContext : new DefaultBootstrapContext();\n\t\tConfigDataEnvironmentPostProcessor postProcessor = new ConfigDataEnvironmentPostProcessor(logFactory,\n\t\t\t\tbootstrapContext);\n\t\tpostProcessor.postProcessEnvironment(environment, resourceLoader, additionalProfiles);\n\t}\n\n\t/**\n\t * Apply {@link ConfigData} post-processing to an existing {@link Environment}. This\n\t * method can be useful when working with an {@link Environment} that has been created\n\t * directly and not necessarily as part of a {@link SpringApplication}.\n\t * @param environment the environment to apply {@link ConfigData} to\n\t * @param resourceLoader the resource loader to use\n\t * @param bootstrapContext the bootstrap context to use or {@code null} to use a\n\t * throw-away context\n\t * @param additionalProfiles any additional profiles that should be applied\n\t * @param environmentUpdateListener optional\n\t * {@link ConfigDataEnvironmentUpdateListener} that can be used to track\n\t * {@link Environment} updates.\n\t */\n\tpublic static void applyTo(ConfigurableEnvironment environment, @Nullable ResourceLoader resourceLoader,\n\t\t\t@Nullable ConfigurableBootstrapContext bootstrapContext, Collection<String> additionalProfiles,\n\t\t\tConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\tDeferredLogFactory logFactory = Supplier::get;\n\t\tbootstrapContext = (bootstrapContext != null) ? bootstrapContext : new DefaultBootstrapContext();\n\t\tConfigDataEnvironmentPostProcessor postProcessor = new ConfigDataEnvironmentPostProcessor(logFactory,\n\t\t\t\tbootstrapContext, environmentUpdateListener);\n\t\tpostProcessor.postProcessEnvironment(environment, resourceLoader, additionalProfiles);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironmentUpdateListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.EventListener;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.config.ConfigData.Options;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * {@link EventListener} to listen to {@link Environment} updates triggered by the\n * {@link ConfigDataEnvironmentPostProcessor}.\n *\n * @author Phillip Webb\n * @since 2.4.2\n */\npublic interface ConfigDataEnvironmentUpdateListener extends EventListener {\n\n\t/**\n\t * A {@link ConfigDataEnvironmentUpdateListener} that does nothing.\n\t */\n\tConfigDataEnvironmentUpdateListener NONE = new ConfigDataEnvironmentUpdateListener() {\n\t};\n\n\t/**\n\t * Called when a new {@link PropertySource} is added to the {@link Environment}.\n\t * @param propertySource the {@link PropertySource} that was added\n\t * @param location the original {@link ConfigDataLocation} of the source.\n\t * @param resource the {@link ConfigDataResource} of the source.\n\t */\n\tdefault void onPropertySourceAdded(PropertySource<?> propertySource, @Nullable ConfigDataLocation location,\n\t\t\t@Nullable ConfigDataResource resource) {\n\t}\n\n\t/**\n\t * Called when {@link Environment} profiles are set.\n\t * @param profiles the profiles being set\n\t */\n\tdefault void onSetProfiles(Profiles profiles) {\n\t}\n\n\t/**\n\t * Called when config data options are obtained for a particular property source.\n\t * @param configData the config data\n\t * @param propertySource the property source\n\t * @param options the options as provided by\n\t * {@link ConfigData#getOptions(PropertySource)}\n\t * @return the actual options that should be used\n\t * @since 3.5.1\n\t */\n\tdefault ConfigData.Options onConfigDataOptions(ConfigData configData, PropertySource<?> propertySource,\n\t\t\tOptions options) {\n\t\treturn options;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Abstract base class for configuration data exceptions.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic abstract class ConfigDataException extends RuntimeException {\n\n\t/**\n\t * Create a new {@link ConfigDataException} instance.\n\t * @param message the exception message\n\t * @param cause the exception cause\n\t */\n\tprotected ConfigDataException(String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataImporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Imports {@link ConfigData} by {@link ConfigDataLocationResolver resolving} and\n * {@link ConfigDataLoader loading} locations. {@link ConfigDataResource resources} are\n * tracked to ensure that they are not imported multiple times.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataImporter {\n\n\tprivate final Log logger;\n\n\tprivate final ConfigDataLocationResolvers resolvers;\n\n\tprivate final ConfigDataLoaders loaders;\n\n\tprivate final ConfigDataNotFoundAction notFoundAction;\n\n\tprivate final Set<ConfigDataResource> loaded = new HashSet<>();\n\n\tprivate final Set<ConfigDataLocation> loadedLocations = new HashSet<>();\n\n\tprivate final Set<ConfigDataLocation> optionalLocations = new HashSet<>();\n\n\t/**\n\t * Create a new {@link ConfigDataImporter} instance.\n\t * @param logFactory the log factory\n\t * @param notFoundAction the action to take when a location cannot be found\n\t * @param resolvers the config data location resolvers\n\t * @param loaders the config data loaders\n\t */\n\tConfigDataImporter(DeferredLogFactory logFactory, ConfigDataNotFoundAction notFoundAction,\n\t\t\tConfigDataLocationResolvers resolvers, ConfigDataLoaders loaders) {\n\t\tthis.logger = logFactory.getLog(getClass());\n\t\tthis.resolvers = resolvers;\n\t\tthis.loaders = loaders;\n\t\tthis.notFoundAction = notFoundAction;\n\t}\n\n\t/**\n\t * Resolve and load the given list of locations, filtering any that have been\n\t * previously loaded.\n\t * @param activationContext the activation context\n\t * @param locationResolverContext the location resolver context\n\t * @param loaderContext the loader context\n\t * @param locations the locations to resolve\n\t * @return a map of the loaded locations and data\n\t */\n\tMap<ConfigDataResolutionResult, ConfigData> resolveAndLoad(@Nullable ConfigDataActivationContext activationContext,\n\t\t\tConfigDataLocationResolverContext locationResolverContext, ConfigDataLoaderContext loaderContext,\n\t\t\tList<ConfigDataLocation> locations) {\n\t\ttry {\n\t\t\tProfiles profiles = (activationContext != null) ? activationContext.getProfiles() : null;\n\t\t\tList<ConfigDataResolutionResult> resolved = resolve(locationResolverContext, profiles, locations);\n\t\t\treturn load(loaderContext, resolved);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"IO error on loading imports from \" + locations, ex);\n\t\t}\n\t}\n\n\tprivate List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext locationResolverContext,\n\t\t\t@Nullable Profiles profiles, List<ConfigDataLocation> locations) {\n\t\tList<ConfigDataResolutionResult> resolved = new ArrayList<>(locations.size());\n\t\tfor (ConfigDataLocation location : locations) {\n\t\t\tresolved.addAll(resolve(locationResolverContext, profiles, location));\n\t\t}\n\t\treturn Collections.unmodifiableList(resolved);\n\t}\n\n\tprivate List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext locationResolverContext,\n\t\t\t@Nullable Profiles profiles, ConfigDataLocation location) {\n\t\ttry {\n\t\t\treturn this.resolvers.resolve(locationResolverContext, location, profiles);\n\t\t}\n\t\tcatch (ConfigDataNotFoundException ex) {\n\t\t\thandle(ex, location, null);\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t}\n\n\tprivate Map<ConfigDataResolutionResult, ConfigData> load(ConfigDataLoaderContext loaderContext,\n\t\t\tList<ConfigDataResolutionResult> candidates) throws IOException {\n\t\tMap<ConfigDataResolutionResult, ConfigData> result = new LinkedHashMap<>();\n\t\tfor (int i = candidates.size() - 1; i >= 0; i--) {\n\t\t\tConfigDataResolutionResult candidate = candidates.get(i);\n\t\t\tConfigDataLocation location = candidate.getLocation();\n\t\t\tConfigDataResource resource = candidate.getResource();\n\t\t\tthis.logger.trace(LogMessage.format(\"Considering resource %s from location %s\", resource, location));\n\t\t\tif (resource.isOptional()) {\n\t\t\t\tthis.optionalLocations.add(location);\n\t\t\t}\n\t\t\tif (this.loaded.contains(resource)) {\n\t\t\t\tthis.logger\n\t\t\t\t\t.trace(LogMessage.format(\"Already loaded resource %s ignoring location %s\", resource, location));\n\t\t\t\tthis.loadedLocations.add(location);\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttry {\n\t\t\t\t\tConfigData loaded = this.loaders.load(loaderContext, resource);\n\t\t\t\t\tif (loaded != null) {\n\t\t\t\t\t\tthis.logger.trace(LogMessage.format(\"Loaded resource %s from location %s\", resource, location));\n\t\t\t\t\t\tthis.loaded.add(resource);\n\t\t\t\t\t\tthis.loadedLocations.add(location);\n\t\t\t\t\t\tresult.put(candidate, loaded);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ConfigDataNotFoundException ex) {\n\t\t\t\t\thandle(ex, location, resource);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n\tprivate void handle(ConfigDataNotFoundException ex, ConfigDataLocation location,\n\t\t\t@Nullable ConfigDataResource resource) {\n\t\tif (ex instanceof ConfigDataResourceNotFoundException notFoundException) {\n\t\t\tex = notFoundException.withLocation(location);\n\t\t}\n\t\tgetNotFoundAction(location, resource).handle(this.logger, ex);\n\t}\n\n\tprivate ConfigDataNotFoundAction getNotFoundAction(ConfigDataLocation location,\n\t\t\t@Nullable ConfigDataResource resource) {\n\t\tif (location.isOptional() || (resource != null && resource.isOptional())) {\n\t\t\treturn ConfigDataNotFoundAction.IGNORE;\n\t\t}\n\t\treturn this.notFoundAction;\n\t}\n\n\tSet<ConfigDataLocation> getLoadedLocations() {\n\t\treturn this.loadedLocations;\n\t}\n\n\tSet<ConfigDataLocation> getOptionalLocations() {\n\t\treturn this.optionalLocations;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\n\n/**\n * Strategy class that can be used to load {@link ConfigData} for a given\n * {@link ConfigDataResource}. Implementations should be added as {@code spring.factories}\n * entries. The following constructor parameter types are supported:\n * <ul>\n * <li>{@link DeferredLogFactory} - if the loader needs deferred logging</li>\n * <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to\n * store objects that may be expensive to create, or need to be shared\n * ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>\n * </ul>\n * <p>\n * Multiple loaders cannot claim the same resource.\n *\n * @param <R> the resource type\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic interface ConfigDataLoader<R extends ConfigDataResource> {\n\n\t/**\n\t * Returns if the specified resource can be loaded by this instance.\n\t * @param context the loader context\n\t * @param resource the resource to check.\n\t * @return if the resource is supported by this loader\n\t */\n\tdefault boolean isLoadable(ConfigDataLoaderContext context, R resource) {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Load {@link ConfigData} for the given resource.\n\t * @param context the loader context\n\t * @param resource the resource to load\n\t * @return the loaded config data or {@code null} if the location should be skipped\n\t * @throws IOException on IO error\n\t * @throws ConfigDataResourceNotFoundException if the resource cannot be found\n\t */\n\t@Nullable ConfigData load(ConfigDataLoaderContext context, R resource)\n\t\t\tthrows IOException, ConfigDataResourceNotFoundException;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLoaderContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\n\n/**\n * Context provided to {@link ConfigDataLoader} methods.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic interface ConfigDataLoaderContext {\n\n\t/**\n\t * Provides access to the {@link ConfigurableBootstrapContext} shared across all\n\t * {@link EnvironmentPostProcessor EnvironmentPostProcessors}.\n\t * @return the bootstrap context\n\t */\n\tConfigurableBootstrapContext getBootstrapContext();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLoaders.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\n\n/**\n * A collection of {@link ConfigDataLoader} instances loaded through\n * {@code spring.factories}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataLoaders {\n\n\tprivate final Log logger;\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate final List<ConfigDataLoader> loaders;\n\n\tprivate final List<Class<?>> resourceTypes;\n\n\t/**\n\t * Create a new {@link ConfigDataLoaders} instance.\n\t * @param logFactory the deferred log factory\n\t * @param bootstrapContext the bootstrap context\n\t * @param springFactoriesLoader the loader to use\n\t */\n\tConfigDataLoaders(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,\n\t\t\tSpringFactoriesLoader springFactoriesLoader) {\n\t\tthis.logger = logFactory.getLog(getClass());\n\t\tArgumentResolver argumentResolver = ArgumentResolver.of(DeferredLogFactory.class, logFactory);\n\t\targumentResolver = argumentResolver.and(ConfigurableBootstrapContext.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.and(BootstrapContext.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.andSupplied(Log.class, () -> {\n\t\t\tthrow new IllegalArgumentException(\"Log types cannot be injected, please use DeferredLogFactory\");\n\t\t});\n\t\tthis.loaders = springFactoriesLoader.load(ConfigDataLoader.class, argumentResolver);\n\t\tthis.resourceTypes = getResourceTypes(this.loaders);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate List<Class<?>> getResourceTypes(List<ConfigDataLoader> loaders) {\n\t\tList<Class<?>> resourceTypes = new ArrayList<>(loaders.size());\n\t\tfor (ConfigDataLoader<?> loader : loaders) {\n\t\t\tresourceTypes.add(getResourceType(loader));\n\t\t}\n\t\treturn Collections.unmodifiableList(resourceTypes);\n\t}\n\n\tprivate Class<?> getResourceType(ConfigDataLoader<?> loader) {\n\t\tClass<?> generic = ResolvableType.forClass(loader.getClass()).as(ConfigDataLoader.class).resolveGeneric();\n\t\tAssert.state(generic != null, \"'generic' must not be null\");\n\t\treturn generic;\n\t}\n\n\t/**\n\t * Load {@link ConfigData} using the first appropriate {@link ConfigDataLoader}.\n\t * @param <R> the resource type\n\t * @param context the loader context\n\t * @param resource the resource to load\n\t * @return the loaded {@link ConfigData}\n\t * @throws IOException on IO error\n\t */\n\t<R extends ConfigDataResource> @Nullable ConfigData load(ConfigDataLoaderContext context, R resource)\n\t\t\tthrows IOException {\n\t\tConfigDataLoader<R> loader = getLoader(context, resource);\n\t\tthis.logger.trace(LogMessage.of(() -> \"Loading \" + resource + \" using loader \" + loader.getClass().getName()));\n\t\treturn loader.load(context, resource);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <R extends ConfigDataResource> ConfigDataLoader<R> getLoader(ConfigDataLoaderContext context, R resource) {\n\t\tConfigDataLoader<R> result = null;\n\t\tfor (int i = 0; i < this.loaders.size(); i++) {\n\t\t\tConfigDataLoader<R> candidate = this.loaders.get(i);\n\t\t\tif (this.resourceTypes.get(i).isInstance(resource)) {\n\t\t\t\tif (candidate.isLoadable(context, resource)) {\n\t\t\t\t\tif (result != null) {\n\t\t\t\t\t\tthrow new IllegalStateException(\"Multiple loaders found for resource '\" + resource + \"' [\"\n\t\t\t\t\t\t\t\t+ candidate.getClass().getName() + \",\" + result.getClass().getName() + \"]\");\n\t\t\t\t\t}\n\t\t\t\t\tresult = candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tAssert.state(result != null, () -> \"No loader found for resource '\" + resource + \"'\");\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A user specified location that can be {@link ConfigDataLocationResolver resolved} to\n * one or more {@link ConfigDataResource config data resources}. A\n * {@link ConfigDataLocation} is a simple wrapper around a {@link String} value. The exact\n * format of the value will depend on the underlying technology, but is usually a URL like\n * syntax consisting of a prefix and path. For example, {@code crypt:somehost/somepath}.\n * <p>\n * Locations can be mandatory or {@link #isOptional() optional}. Optional locations are\n * prefixed with {@code optional:}.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic final class ConfigDataLocation implements OriginProvider {\n\n\tprivate static final ConfigDataLocation EMPTY = new ConfigDataLocation(false, \"\", null);\n\n\t/**\n\t * Prefix used to indicate that a {@link ConfigDataResource} is optional.\n\t */\n\tpublic static final String OPTIONAL_PREFIX = \"optional:\";\n\n\tprivate final boolean optional;\n\n\tprivate final String value;\n\n\tprivate final @Nullable Origin origin;\n\n\tprivate ConfigDataLocation(boolean optional, String value, @Nullable Origin origin) {\n\t\tthis.value = value;\n\t\tthis.optional = optional;\n\t\tthis.origin = origin;\n\t}\n\n\t/**\n\t * Return if the location is optional and should ignore\n\t * {@link ConfigDataNotFoundException}.\n\t * @return if the location is optional\n\t */\n\tpublic boolean isOptional() {\n\t\treturn this.optional;\n\t}\n\n\t/**\n\t * Return the value of the location (always excluding any user specified\n\t * {@code optional:} prefix).\n\t * @return the location value\n\t */\n\tpublic String getValue() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Return if {@link #getValue()} has the specified prefix.\n\t * @param prefix the prefix to check\n\t * @return if the value has the prefix\n\t */\n\tpublic boolean hasPrefix(String prefix) {\n\t\treturn this.value.startsWith(prefix);\n\t}\n\n\t/**\n\t * Return {@link #getValue()} with the specified prefix removed. If the location does\n\t * not have the given prefix then the {@link #getValue()} is returned unchanged.\n\t * @param prefix the prefix to check\n\t * @return the value with the prefix removed\n\t */\n\tpublic String getNonPrefixedValue(String prefix) {\n\t\treturn (!hasPrefix(prefix)) ? this.value : this.value.substring(prefix.length());\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t/**\n\t * Return an array of {@link ConfigDataLocation} elements built by splitting this\n\t * {@link ConfigDataLocation} around a delimiter of {@code \";\"}.\n\t * @return the split locations\n\t * @since 2.4.7\n\t */\n\tpublic ConfigDataLocation[] split() {\n\t\treturn split(\";\");\n\t}\n\n\t/**\n\t * Return an array of {@link ConfigDataLocation} elements built by splitting this\n\t * {@link ConfigDataLocation} around the specified delimiter.\n\t * @param delimiter the delimiter to split on\n\t * @return the split locations\n\t * @since 2.4.7\n\t */\n\tpublic ConfigDataLocation[] split(String delimiter) {\n\t\tAssert.state(!this.value.isEmpty(), \"Unable to split empty locations\");\n\t\tString[] values = StringUtils.delimitedListToStringArray(toString(), delimiter);\n\t\tConfigDataLocation[] result = new ConfigDataLocation[values.length];\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tint index = i;\n\t\t\tConfigDataLocation configDataLocation = of(values[index]);\n\t\t\tresult[i] = configDataLocation.withOrigin(getOrigin());\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataLocation} with a specific {@link Origin}.\n\t * @param origin the origin to set\n\t * @return a new {@link ConfigDataLocation} instance.\n\t */\n\tConfigDataLocation withOrigin(@Nullable Origin origin) {\n\t\treturn new ConfigDataLocation(this.optional, this.value, origin);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tConfigDataLocation other = (ConfigDataLocation) obj;\n\t\treturn this.value.equals(other.value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (!this.optional) ? this.value : OPTIONAL_PREFIX + this.value;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link ConfigDataLocation} from a string.\n\t * @param location the location string\n\t * @return the {@link ConfigDataLocation} (which may be empty)\n\t */\n\tpublic static ConfigDataLocation of(@Nullable String location) {\n\t\tboolean optional = location != null && location.startsWith(OPTIONAL_PREFIX);\n\t\tString value = (location != null && optional) ? location.substring(OPTIONAL_PREFIX.length()) : location;\n\t\treturn (StringUtils.hasText(value)) ? new ConfigDataLocation(optional, value, null) : EMPTY;\n\t}\n\n\tstatic boolean isNotEmpty(@Nullable ConfigDataLocation location) {\n\t\treturn (location != null) && !location.getValue().isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.origin.Origin;\n\n/**\n * {@link BindHandler} to set the {@link Origin} of bound {@link ConfigDataLocation}\n * objects.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ConfigDataLocationBindHandler extends AbstractBindHandler {\n\n\t@Override\n\tpublic @Nullable Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tObject result) {\n\t\tOriginMapper originMapper = new OriginMapper(context.getConfigurationProperty());\n\t\tif (result instanceof ConfigDataLocation location) {\n\t\t\treturn originMapper.map(location);\n\t\t}\n\t\tif (result instanceof List<?> locations) {\n\t\t\treturn locations.stream().map(originMapper::mapIfPossible).collect(Collectors.toCollection(ArrayList::new));\n\t\t}\n\t\tif (result instanceof ConfigDataLocation[] locations) {\n\t\t\treturn Arrays.stream(locations).map(originMapper::mapIfPossible).toArray(ConfigDataLocation[]::new);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate record OriginMapper(@Nullable ConfigurationProperty property) {\n\n\t\t@Nullable Object mapIfPossible(@Nullable Object object) {\n\t\t\treturn (object instanceof ConfigDataLocation location) ? map(location) : object;\n\t\t}\n\n\t\t@Nullable ConfigDataLocation map(@Nullable ConfigDataLocation location) {\n\t\t\tif (location == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tOrigin origin = Origin.from(location);\n\t\t\treturn (origin != null) ? location : location.withOrigin(Origin.from(property()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigDataNotFoundException} thrown when a {@link ConfigDataLocation} cannot be\n * found.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class ConfigDataLocationNotFoundException extends ConfigDataNotFoundException {\n\n\tprivate final ConfigDataLocation location;\n\n\t/**\n\t * Create a new {@link ConfigDataLocationNotFoundException} instance.\n\t * @param location the location that could not be found\n\t */\n\tpublic ConfigDataLocationNotFoundException(ConfigDataLocation location) {\n\t\tthis(location, null);\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataLocationNotFoundException} instance.\n\t * @param location the location that could not be found\n\t * @param cause the exception cause\n\t */\n\tpublic ConfigDataLocationNotFoundException(ConfigDataLocation location, @Nullable Throwable cause) {\n\t\tthis(location, getMessage(location), cause);\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataLocationNotFoundException} instance.\n\t * @param location the location that could not be found\n\t * @param message the exception message\n\t * @param cause the exception cause\n\t * @since 2.4.7\n\t */\n\tpublic ConfigDataLocationNotFoundException(ConfigDataLocation location, String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t\tAssert.notNull(location, \"'location' must not be null\");\n\t\tthis.location = location;\n\t}\n\n\t/**\n\t * Return the location that could not be found.\n\t * @return the location\n\t */\n\tpublic ConfigDataLocation getLocation() {\n\t\treturn this.location;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn Origin.from(this.location);\n\t}\n\n\t@Override\n\tpublic String getReferenceDescription() {\n\t\treturn getReferenceDescription(this.location);\n\t}\n\n\tprivate static String getMessage(ConfigDataLocation location) {\n\t\treturn String.format(\"Config data %s cannot be found\", getReferenceDescription(location));\n\t}\n\n\tprivate static String getReferenceDescription(ConfigDataLocation location) {\n\t\treturn String.format(\"location '%s'\", location);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * Strategy interface used to resolve {@link ConfigDataLocation locations} into one or\n * more {@link ConfigDataResource resources}. Implementations should be added as a\n * {@code spring.factories} entries. The following constructor parameter types are\n * supported:\n * <ul>\n * <li>{@link DeferredLogFactory} - if the resolver needs deferred logging</li>\n * <li>{@link Binder} - if the resolver needs to obtain values from the initial\n * {@link Environment}</li>\n * <li>{@link ResourceLoader} - if the resolver needs a resource loader</li>\n * <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to\n * store objects that may be expensive to create, or need to be shared\n * ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>\n * </ul>\n * <p>\n * Resolvers may implement {@link Ordered} or use the {@link Order @Order} annotation. The\n * first resolver that supports the given location will be used.\n *\n * @param <R> the location type\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic interface ConfigDataLocationResolver<R extends ConfigDataResource> {\n\n\t/**\n\t * Returns if the specified location address can be resolved by this resolver.\n\t * @param context the location resolver context\n\t * @param location the location to check.\n\t * @return if the location is supported by this resolver\n\t */\n\tboolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location);\n\n\t/**\n\t * Resolve a {@link ConfigDataLocation} into one or more {@link ConfigDataResource}\n\t * instances.\n\t * @param context the location resolver context\n\t * @param location the location that should be resolved\n\t * @return a list of {@link ConfigDataResource resources} in ascending priority order.\n\t * @throws ConfigDataLocationNotFoundException on a non-optional location that cannot\n\t * be found\n\t * @throws ConfigDataResourceNotFoundException if a resolved resource cannot be found\n\t */\n\tList<R> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location)\n\t\t\tthrows ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException;\n\n\t/**\n\t * Resolve a {@link ConfigDataLocation} into one or more {@link ConfigDataResource}\n\t * instances based on available profiles. This method is called once profiles have\n\t * been deduced from the contributed values. By default this method returns an empty\n\t * list.\n\t * @param context the location resolver context\n\t * @param location the location that should be resolved\n\t * @param profiles profile information\n\t * @return a list of resolved locations in ascending priority order.\n\t * @throws ConfigDataLocationNotFoundException on a non-optional location that cannot\n\t * be found\n\t */\n\tdefault List<R> resolveProfileSpecific(ConfigDataLocationResolverContext context, ConfigDataLocation location,\n\t\t\tProfiles profiles) throws ConfigDataLocationNotFoundException {\n\t\treturn Collections.emptyList();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolverContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.properties.bind.Binder;\n\n/**\n * Context provided to {@link ConfigDataLocationResolver} methods.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic interface ConfigDataLocationResolverContext {\n\n\t/**\n\t * Provides access to a binder that can be used to obtain previously contributed\n\t * values.\n\t * @return a binder instance\n\t */\n\tBinder getBinder();\n\n\t/**\n\t * Provides access to the parent {@link ConfigDataResource} that triggered the resolve\n\t * or {@code null} if there is no available parent.\n\t * @return the parent location\n\t */\n\t@Nullable ConfigDataResource getParent();\n\n\t/**\n\t * Provides access to the {@link ConfigurableBootstrapContext} shared across all\n\t * {@link EnvironmentPostProcessor EnvironmentPostProcessors}.\n\t * @return the bootstrap context\n\t */\n\tConfigurableBootstrapContext getBootstrapContext();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationResolvers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\n\n/**\n * A collection of {@link ConfigDataLocationResolver} instances loaded via\n * {@code spring.factories}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataLocationResolvers {\n\n\tprivate final List<ConfigDataLocationResolver<?>> resolvers;\n\n\t/**\n\t * Create a new {@link ConfigDataLocationResolvers} instance.\n\t * @param logFactory a {@link DeferredLogFactory} used to inject {@link Log} instances\n\t * @param bootstrapContext the bootstrap context\n\t * @param binder a binder providing values from the initial {@link Environment}\n\t * @param resourceLoader {@link ResourceLoader} to load resource locations\n\t * @param springFactoriesLoader to load {@link ConfigDataLocationResolver} instances\n\t */\n\tConfigDataLocationResolvers(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,\n\t\t\tBinder binder, ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader) {\n\t\tArgumentResolver argumentResolver = ArgumentResolver.of(DeferredLogFactory.class, logFactory);\n\t\targumentResolver = argumentResolver.and(Binder.class, binder);\n\t\targumentResolver = argumentResolver.and(ResourceLoader.class, resourceLoader);\n\t\targumentResolver = argumentResolver.and(ConfigurableBootstrapContext.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.and(BootstrapContext.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.andSupplied(Log.class, () -> {\n\t\t\tthrow new IllegalArgumentException(\"Log types cannot be injected, please use DeferredLogFactory\");\n\t\t});\n\t\tthis.resolvers = reorder(springFactoriesLoader.load(ConfigDataLocationResolver.class, argumentResolver));\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate List<ConfigDataLocationResolver<?>> reorder(List<ConfigDataLocationResolver> resolvers) {\n\t\tList<ConfigDataLocationResolver<?>> reordered = new ArrayList<>(resolvers.size());\n\t\tConfigDataLocationResolver<?> standardConfigDataLocationResolver = null;\n\t\tfor (ConfigDataLocationResolver<?> resolver : resolvers) {\n\t\t\tif (resolver instanceof StandardConfigDataLocationResolver) {\n\t\t\t\tstandardConfigDataLocationResolver = resolver;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treordered.add(resolver);\n\t\t\t}\n\t\t}\n\t\tif (standardConfigDataLocationResolver != null) {\n\t\t\treordered.add(standardConfigDataLocationResolver);\n\t\t}\n\t\treturn Collections.unmodifiableList(reordered);\n\t}\n\n\tList<ConfigDataResolutionResult> resolve(ConfigDataLocationResolverContext context,\n\t\t\t@Nullable ConfigDataLocation location, @Nullable Profiles profiles) {\n\t\tif (location == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tfor (ConfigDataLocationResolver<?> resolver : getResolvers()) {\n\t\t\tif (resolver.isResolvable(context, location)) {\n\t\t\t\treturn resolve(resolver, context, location, profiles);\n\t\t\t}\n\t\t}\n\t\tthrow new UnsupportedConfigDataLocationException(location);\n\t}\n\n\tprivate List<ConfigDataResolutionResult> resolve(ConfigDataLocationResolver<?> resolver,\n\t\t\tConfigDataLocationResolverContext context, ConfigDataLocation location, @Nullable Profiles profiles) {\n\t\tList<ConfigDataResolutionResult> resolved = resolve(location, false, () -> resolver.resolve(context, location));\n\t\tif (profiles == null) {\n\t\t\treturn resolved;\n\t\t}\n\t\tList<ConfigDataResolutionResult> profileSpecific = resolve(location, true,\n\t\t\t\t() -> resolver.resolveProfileSpecific(context, location, profiles));\n\t\treturn merge(resolved, profileSpecific);\n\t}\n\n\tprivate List<ConfigDataResolutionResult> resolve(ConfigDataLocation location, boolean profileSpecific,\n\t\t\tSupplier<List<? extends ConfigDataResource>> resolveAction) {\n\t\tList<ConfigDataResource> resources = nonNullList(resolveAction.get());\n\t\tList<ConfigDataResolutionResult> resolved = new ArrayList<>(resources.size());\n\t\tfor (ConfigDataResource resource : resources) {\n\t\t\tresolved.add(new ConfigDataResolutionResult(location, resource, profileSpecific));\n\t\t}\n\t\treturn resolved;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> List<T> nonNullList(@Nullable List<? extends T> list) {\n\t\treturn (list != null) ? (List<T>) list : Collections.emptyList();\n\t}\n\n\tprivate <T> List<T> merge(List<T> list1, List<T> list2) {\n\t\tList<T> merged = new ArrayList<>(list1.size() + list2.size());\n\t\tmerged.addAll(list1);\n\t\tmerged.addAll(list2);\n\t\treturn merged;\n\t}\n\n\t/**\n\t * Return the resolvers managed by this object.\n\t * @return the resolvers\n\t */\n\tList<ConfigDataLocationResolver<?>> getResolvers() {\n\t\treturn this.resolvers;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.support.FilePatternResourceHintsRegistrar;\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * {@link RuntimeHintsRegistrar} implementation for application configuration.\n *\n * @author Stephane Nicoll\n * @see FilePatternResourceHintsRegistrar\n */\nclass ConfigDataLocationRuntimeHints implements RuntimeHintsRegistrar {\n\n\tprivate static final Log logger = LogFactory.getLog(ConfigDataLocationRuntimeHints.class);\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tList<String> fileNames = getFileNames(classLoader);\n\t\tList<String> locations = getLocations(classLoader);\n\t\tList<String> extensions = getExtensions(classLoader);\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Registering application configuration hints for \" + fileNames + \"(\" + extensions + \") at \"\n\t\t\t\t\t+ locations);\n\t\t}\n\t\tFilePatternResourceHintsRegistrar.forClassPathLocations(locations)\n\t\t\t.withFilePrefixes(fileNames)\n\t\t\t.withFileExtensions(extensions)\n\t\t\t.registerHints(hints.resources(), classLoader);\n\t}\n\n\t/**\n\t * Get the application file names to consider.\n\t * @param classLoader the classloader to use\n\t * @return the configuration file names\n\t */\n\tprotected List<String> getFileNames(@Nullable ClassLoader classLoader) {\n\t\treturn Arrays.asList(StandardConfigDataLocationResolver.DEFAULT_CONFIG_NAMES);\n\t}\n\n\t/**\n\t * Get the locations to consider. A location is a classpath location that may or may\n\t * not use the standard {@code classpath:} prefix.\n\t * @param classLoader the classloader to use\n\t * @return the configuration file locations\n\t */\n\tprotected List<String> getLocations(@Nullable ClassLoader classLoader) {\n\t\tList<String> classpathLocations = new ArrayList<>();\n\t\tfor (ConfigDataLocation candidate : ConfigDataEnvironment.DEFAULT_SEARCH_LOCATIONS) {\n\t\t\tfor (ConfigDataLocation configDataLocation : candidate.split()) {\n\t\t\t\tString location = configDataLocation.getValue();\n\t\t\t\tif (location.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {\n\t\t\t\t\tclasspathLocations.add(location);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn classpathLocations;\n\t}\n\n\t/**\n\t * Get the application file extensions to consider. A valid extension starts with a\n\t * dot.\n\t * @param classLoader the classloader to use\n\t * @return the configuration file extensions\n\t */\n\tprotected List<String> getExtensions(@Nullable ClassLoader classLoader) {\n\t\tList<String> extensions = new ArrayList<>();\n\t\tList<PropertySourceLoader> propertySourceLoaders = getSpringFactoriesLoader(classLoader)\n\t\t\t.load(PropertySourceLoader.class);\n\t\tfor (PropertySourceLoader propertySourceLoader : propertySourceLoaders) {\n\t\t\tfor (String fileExtension : propertySourceLoader.getFileExtensions()) {\n\t\t\t\tString candidate = \".\" + fileExtension;\n\t\t\t\tif (!extensions.contains(candidate)) {\n\t\t\t\t\textensions.add(candidate);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn extensions;\n\t}\n\n\tprotected SpringFactoriesLoader getSpringFactoriesLoader(@Nullable ClassLoader classLoader) {\n\t\treturn SpringFactoriesLoader.forDefaultResourceLocation(classLoader);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.apache.commons.logging.Log;\n\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Action to take when an uncaught {@link ConfigDataNotFoundException} is thrown.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic enum ConfigDataNotFoundAction {\n\n\t/**\n\t * Throw the exception to fail startup.\n\t */\n\tFAIL {\n\n\t\t@Override\n\t\tvoid handle(Log logger, ConfigDataNotFoundException ex) {\n\t\t\tthrow ex;\n\t\t}\n\n\t},\n\n\t/**\n\t * Ignore the exception and continue processing the remaining locations.\n\t */\n\tIGNORE {\n\n\t\t@Override\n\t\tvoid handle(Log logger, ConfigDataNotFoundException ex) {\n\t\t\tlogger.trace(LogMessage.format(\"Ignoring missing config data %s\", ex.getReferenceDescription()));\n\t\t}\n\n\t};\n\n\t/**\n\t * Handle the given exception.\n\t * @param logger the logger used for output {@code ConfigDataLocation})\n\t * @param ex the exception to handle\n\t */\n\tabstract void handle(Log logger, ConfigDataNotFoundException ex);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.OriginProvider;\n\n/**\n * {@link ConfigDataNotFoundException} thrown when a {@link ConfigData} cannot be found.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic abstract class ConfigDataNotFoundException extends ConfigDataException implements OriginProvider {\n\n\t/**\n\t * Create a new {@link ConfigDataNotFoundException} instance.\n\t * @param message the exception message\n\t * @param cause the exception cause\n\t */\n\tConfigDataNotFoundException(String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n\t/**\n\t * Return a description of actual referenced item that could not be found.\n\t * @return a description of the referenced items\n\t */\n\tpublic abstract String getReferenceDescription();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.origin.Origin;\n\n/**\n * An implementation of {@link AbstractFailureAnalyzer} to analyze failures caused by\n * {@link ConfigDataNotFoundException}.\n *\n * @author Michal Mlak\n * @author Phillip Webb\n */\nclass ConfigDataNotFoundFailureAnalyzer extends AbstractFailureAnalyzer<ConfigDataNotFoundException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, ConfigDataNotFoundException cause) {\n\t\tConfigDataLocation location = getLocation(cause);\n\t\tOrigin origin = Origin.from(location);\n\t\tString message = String.format(\"Config data %s does not exist\", cause.getReferenceDescription());\n\t\tStringBuilder action = new StringBuilder(\"Check that the value \");\n\t\tif (location != null) {\n\t\t\taction.append(String.format(\"'%s' \", location));\n\t\t}\n\t\tif (origin != null) {\n\t\t\taction.append(String.format(\"at %s \", origin));\n\t\t}\n\t\taction.append(\"is correct\");\n\t\tif (location != null && !location.isOptional()) {\n\t\t\taction.append(String.format(\", or prefix it with '%s'\", ConfigDataLocation.OPTIONAL_PREFIX));\n\t\t}\n\t\treturn new FailureAnalysis(message, action.toString(), cause);\n\t}\n\n\tprivate @Nullable ConfigDataLocation getLocation(ConfigDataNotFoundException cause) {\n\t\tif (cause instanceof ConfigDataLocationNotFoundException locationNotFoundException) {\n\t\t\treturn locationNotFoundException.getLocation();\n\t\t}\n\t\tif (cause instanceof ConfigDataResourceNotFoundException resourceNotFoundException) {\n\t\t\treturn resourceNotFoundException.getLocation();\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Bound properties used when working with {@link ConfigData}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Yanming Zhou\n */\nclass ConfigDataProperties {\n\n\tprivate static final ConfigurationPropertyName NAME = ConfigurationPropertyName.of(\"spring.config\");\n\n\tprivate static final Bindable<ConfigDataProperties> BINDABLE_PROPERTIES = Bindable.of(ConfigDataProperties.class);\n\n\tprivate final List<ConfigDataLocation> imports;\n\n\tprivate final @Nullable Activate activate;\n\n\t/**\n\t * Create a new {@link ConfigDataProperties} instance.\n\t * @param imports the imports requested\n\t * @param activate the activate properties\n\t */\n\tConfigDataProperties(@Nullable @Name(\"import\") List<ConfigDataLocation> imports, @Nullable Activate activate) {\n\t\tthis.imports = (imports != null) ? imports.stream().filter(ConfigDataLocation::isNotEmpty).toList()\n\t\t\t\t: Collections.emptyList();\n\t\tthis.activate = activate;\n\t}\n\n\t/**\n\t * Return any additional imports requested.\n\t * @return the requested imports\n\t */\n\tList<ConfigDataLocation> getImports() {\n\t\treturn this.imports;\n\t}\n\n\t/**\n\t * Return {@code true} if the properties indicate that the config data property source\n\t * is active for the given activation context.\n\t * @param activationContext the activation context\n\t * @return {@code true} if the config data property source is active\n\t */\n\tboolean isActive(@Nullable ConfigDataActivationContext activationContext) {\n\t\treturn this.activate == null || this.activate.isActive(activationContext);\n\t}\n\n\t/**\n\t * Return a new variant of these properties without any imports.\n\t * @return a new {@link ConfigDataProperties} instance\n\t */\n\tConfigDataProperties withoutImports() {\n\t\treturn new ConfigDataProperties(null, this.activate);\n\t}\n\n\t/**\n\t * Factory method used to create {@link ConfigDataProperties} from the given\n\t * {@link Binder}.\n\t * @param binder the binder used to bind the properties\n\t * @return a {@link ConfigDataProperties} instance or {@code null}\n\t */\n\tstatic @Nullable ConfigDataProperties get(Binder binder) {\n\t\treturn binder.bind(NAME, BINDABLE_PROPERTIES, new ConfigDataLocationBindHandler()).orElse(null);\n\t}\n\n\t/**\n\t * Activate properties used to determine when a config data property source is active.\n\t */\n\tstatic class Activate {\n\n\t\tprivate final @Nullable CloudPlatform onCloudPlatform;\n\n\t\tprivate final String @Nullable [] onProfile;\n\n\t\t/**\n\t\t * Create a new {@link Activate} instance.\n\t\t * @param onCloudPlatform the cloud platform required for activation\n\t\t * @param onProfile the profile expression required for activation\n\t\t */\n\t\tActivate(@Nullable CloudPlatform onCloudPlatform, String @Nullable [] onProfile) {\n\t\t\tthis.onProfile = onProfile;\n\t\t\tthis.onCloudPlatform = onCloudPlatform;\n\t\t}\n\n\t\t/**\n\t\t * Return {@code true} if the properties indicate that the config data property\n\t\t * source is active for the given activation context.\n\t\t * @param activationContext the activation context\n\t\t * @return {@code true} if the config data property source is active\n\t\t */\n\t\tboolean isActive(@Nullable ConfigDataActivationContext activationContext) {\n\t\t\tif (activationContext == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tCloudPlatform cloudPlatform = activationContext.getCloudPlatform();\n\t\t\tboolean activate = isActive((cloudPlatform != null) ? cloudPlatform : CloudPlatform.NONE);\n\t\t\tactivate = activate && isActive(activationContext.getProfiles());\n\t\t\treturn activate;\n\t\t}\n\n\t\tprivate boolean isActive(CloudPlatform cloudPlatform) {\n\t\t\treturn this.onCloudPlatform == null || this.onCloudPlatform == cloudPlatform;\n\t\t}\n\n\t\tprivate boolean isActive(@Nullable Profiles profiles) {\n\t\t\treturn ObjectUtils.isEmpty(this.onProfile)\n\t\t\t\t\t|| (profiles != null && matchesActiveProfiles(profiles::isAccepted));\n\t\t}\n\n\t\tprivate boolean matchesActiveProfiles(Predicate<String> activeProfiles) {\n\t\t\tAssert.state(this.onProfile != null, \"'this.onProfile' must not be null\");\n\t\t\treturn org.springframework.core.env.Profiles.of(this.onProfile).matches(activeProfiles);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataPropertiesRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link RuntimeHintsRegistrar} for {@link ConfigDataProperties}.\n *\n * @author Moritz Halbritter\n */\nclass ConfigDataPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tBindableRuntimeHintsRegistrar.forTypes(ConfigDataProperties.class).registerHints(hints);\n\t\tMethod method = ReflectionUtils.findMethod(ConfigDataLocation.class, \"of\", String.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\thints.reflection().registerMethod(method, ExecutableMode.INVOKE);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResolutionResult.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\n/**\n * Result returned from {@link ConfigDataLocationResolvers} containing both the\n * {@link ConfigDataResource} and the original {@link ConfigDataLocation}.\n *\n * @author Phillip Webb\n */\nclass ConfigDataResolutionResult {\n\n\tprivate final ConfigDataLocation location;\n\n\tprivate final ConfigDataResource resource;\n\n\tprivate final boolean profileSpecific;\n\n\tConfigDataResolutionResult(ConfigDataLocation location, ConfigDataResource resource, boolean profileSpecific) {\n\t\tthis.location = location;\n\t\tthis.resource = resource;\n\t\tthis.profileSpecific = profileSpecific;\n\t}\n\n\tConfigDataLocation getLocation() {\n\t\treturn this.location;\n\t}\n\n\tConfigDataResource getResource() {\n\t\treturn this.resource;\n\t}\n\n\tboolean isProfileSpecific() {\n\t\treturn this.profileSpecific;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\n/**\n * A single resource from which {@link ConfigData} can be loaded. Implementations must\n * implement a valid {@link #equals(Object) equals}, {@link #hashCode() hashCode} and\n * {@link #toString() toString} methods.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic abstract class ConfigDataResource {\n\n\tprivate final boolean optional;\n\n\t/**\n\t * Create a new non-optional {@link ConfigDataResource} instance.\n\t */\n\tpublic ConfigDataResource() {\n\t\tthis(false);\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataResource} instance.\n\t * @param optional if the resource is optional\n\t * @since 2.4.6\n\t */\n\tprotected ConfigDataResource(boolean optional) {\n\t\tthis.optional = optional;\n\t}\n\n\tboolean isOptional() {\n\t\treturn this.optional;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataResourceNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigDataNotFoundException} thrown when a {@link ConfigDataResource} cannot be\n * found.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class ConfigDataResourceNotFoundException extends ConfigDataNotFoundException {\n\n\tprivate final ConfigDataResource resource;\n\n\tprivate final @Nullable ConfigDataLocation location;\n\n\t/**\n\t * Create a new {@link ConfigDataResourceNotFoundException} instance.\n\t * @param resource the resource that could not be found\n\t */\n\tpublic ConfigDataResourceNotFoundException(ConfigDataResource resource) {\n\t\tthis(resource, null);\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataResourceNotFoundException} instance.\n\t * @param resource the resource that could not be found\n\t * @param cause the exception cause\n\t */\n\tpublic ConfigDataResourceNotFoundException(ConfigDataResource resource, @Nullable Throwable cause) {\n\t\tthis(resource, null, cause);\n\t}\n\n\tprivate ConfigDataResourceNotFoundException(ConfigDataResource resource, @Nullable ConfigDataLocation location,\n\t\t\t@Nullable Throwable cause) {\n\t\tsuper(getMessage(resource, location), cause);\n\t\tAssert.notNull(resource, \"'resource' must not be null\");\n\t\tthis.resource = resource;\n\t\tthis.location = location;\n\t}\n\n\t/**\n\t * Return the resource that could not be found.\n\t * @return the resource\n\t */\n\tpublic ConfigDataResource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t/**\n\t * Return the original location that was resolved to determine the resource.\n\t * @return the location or {@code null} if no location is available\n\t */\n\tpublic @Nullable ConfigDataLocation getLocation() {\n\t\treturn this.location;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn Origin.from(this.location);\n\t}\n\n\t@Override\n\tpublic String getReferenceDescription() {\n\t\treturn getReferenceDescription(this.resource, this.location);\n\t}\n\n\t/**\n\t * Create a new {@link ConfigDataResourceNotFoundException} instance with a location.\n\t * @param location the location to set\n\t * @return a new {@link ConfigDataResourceNotFoundException} instance\n\t */\n\tConfigDataResourceNotFoundException withLocation(ConfigDataLocation location) {\n\t\treturn new ConfigDataResourceNotFoundException(this.resource, location, getCause());\n\t}\n\n\tprivate static String getMessage(ConfigDataResource resource, @Nullable ConfigDataLocation location) {\n\t\treturn String.format(\"Config data %s cannot be found\", getReferenceDescription(resource, location));\n\t}\n\n\tprivate static String getReferenceDescription(ConfigDataResource resource, @Nullable ConfigDataLocation location) {\n\t\tString description = String.format(\"resource '%s'\", resource);\n\t\tif (location != null) {\n\t\t\tdescription += String.format(\" via location '%s'\", location);\n\t\t}\n\t\treturn description;\n\t}\n\n\t/**\n\t * Throw a {@link ConfigDataNotFoundException} if the specified {@link Path} does not\n\t * exist.\n\t * @param resource the config data resource\n\t * @param pathToCheck the path to check\n\t */\n\tpublic static void throwIfDoesNotExist(ConfigDataResource resource, Path pathToCheck) {\n\t\tthrowIfNot(resource, Files.exists(pathToCheck));\n\t}\n\n\t/**\n\t * Throw a {@link ConfigDataNotFoundException} if the specified {@link File} does not\n\t * exist.\n\t * @param resource the config data resource\n\t * @param fileToCheck the file to check\n\t */\n\tpublic static void throwIfDoesNotExist(ConfigDataResource resource, File fileToCheck) {\n\t\tthrowIfNot(resource, fileToCheck.exists());\n\t}\n\n\t/**\n\t * Throw a {@link ConfigDataNotFoundException} if the specified {@link Resource} does\n\t * not exist.\n\t * @param resource the config data resource\n\t * @param resourceToCheck the resource to check\n\t */\n\tpublic static void throwIfDoesNotExist(ConfigDataResource resource, Resource resourceToCheck) {\n\t\tthrowIfNot(resource, resourceToCheck.exists());\n\t}\n\n\tprivate static void throwIfNot(ConfigDataResource resource, boolean check) {\n\t\tif (!check) {\n\t\t\tthrow new ConfigDataResourceNotFoundException(resource);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigTreeConfigDataLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.util.Collections;\n\nimport org.springframework.boot.env.ConfigTreePropertySource;\nimport org.springframework.boot.env.ConfigTreePropertySource.Option;\n\n/**\n * {@link ConfigDataLoader} for config tree locations.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class ConfigTreeConfigDataLoader implements ConfigDataLoader<ConfigTreeConfigDataResource> {\n\n\t@Override\n\tpublic ConfigData load(ConfigDataLoaderContext context, ConfigTreeConfigDataResource resource)\n\t\t\tthrows IOException, ConfigDataResourceNotFoundException {\n\t\tPath path = resource.getPath();\n\t\tConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, path);\n\t\tString name = \"Config tree '\" + path + \"'\";\n\t\tConfigTreePropertySource source = new ConfigTreePropertySource(name, path, Option.AUTO_TRIM_TRAILING_NEW_LINE);\n\t\treturn new ConfigData(Collections.singletonList(source));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigTreeConfigDataLocationResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.context.config.LocationResourceLoader.ResourceType;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigDataLocationResolver} for config tree locations.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class ConfigTreeConfigDataLocationResolver implements ConfigDataLocationResolver<ConfigTreeConfigDataResource> {\n\n\tprivate static final String PREFIX = \"configtree:\";\n\n\tprivate final LocationResourceLoader resourceLoader;\n\n\tpublic ConfigTreeConfigDataLocationResolver(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = new LocationResourceLoader(resourceLoader);\n\t}\n\n\t@Override\n\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\treturn location.hasPrefix(PREFIX);\n\t}\n\n\t@Override\n\tpublic List<ConfigTreeConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation location) {\n\t\ttry {\n\t\t\treturn resolve(location.getNonPrefixedValue(PREFIX));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new ConfigDataLocationNotFoundException(location, ex);\n\t\t}\n\t}\n\n\tprivate List<ConfigTreeConfigDataResource> resolve(String location) throws IOException {\n\t\tAssert.state(location.endsWith(\"/\"),\n\t\t\t\t() -> String.format(\"Config tree location '%s' must end with '/'\", location));\n\t\tif (!this.resourceLoader.isPattern(location)) {\n\t\t\treturn Collections.singletonList(new ConfigTreeConfigDataResource(location));\n\t\t}\n\t\tResource[] resources = this.resourceLoader.getResources(location, ResourceType.DIRECTORY);\n\t\tList<ConfigTreeConfigDataResource> resolved = new ArrayList<>(resources.length);\n\t\tfor (Resource resource : resources) {\n\t\t\tresolved.add(new ConfigTreeConfigDataResource(resource.getFile().toPath()));\n\t\t}\n\t\treturn resolved;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigTreeConfigDataResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Objects;\n\nimport org.springframework.boot.env.ConfigTreePropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigDataResource} backed by a config tree directory.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.4.0\n * @see ConfigTreePropertySource\n */\npublic class ConfigTreeConfigDataResource extends ConfigDataResource {\n\n\tprivate final Path path;\n\n\tConfigTreeConfigDataResource(String path) {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tthis.path = Paths.get(path).toAbsolutePath();\n\t}\n\n\tConfigTreeConfigDataResource(Path path) {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tthis.path = path.toAbsolutePath();\n\t}\n\n\tPath getPath() {\n\t\treturn this.path;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tConfigTreeConfigDataResource other = (ConfigTreeConfigDataResource) obj;\n\t\treturn Objects.equals(this.path, other.path);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.path.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"config tree [\" + this.path + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/FileHint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * User-provided hint for file attributes, like extension or encoding.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nfinal class FileHint {\n\n\tprivate static final FileHint NONE = new FileHint(Collections.emptyMap());\n\n\tprivate final Map<String, String> attributes;\n\n\tprivate FileHint(Map<String, String> attributes) {\n\t\tthis.attributes = attributes;\n\t}\n\n\t/**\n\t * Return {@code true} if the hint is present.\n\t * @return if the hint is present\n\t */\n\tboolean isPresent() {\n\t\treturn getExtension() != null || getEncoding() != null;\n\t}\n\n\t/**\n\t * Returns the extension.\n\t * @return the extension\n\t */\n\t@Nullable String getExtension() {\n\t\tString extension = this.attributes.get(\"extension\");\n\t\tif (extension == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (!extension.startsWith(\".\")) {\n\t\t\treturn null;\n\t\t}\n\t\treturn extension;\n\t}\n\n\t/**\n\t * Return the extension from the hint or return the {@code fallback} if the extension\n\t * is not present.\n\t * @param fallback the fallback extension\n\t * @return the extension either from the hint or fallback\n\t */\n\tString getExtensionOrElse(String fallback) {\n\t\tString extension = getExtension();\n\t\treturn (extension != null) ? extension : fallback;\n\t}\n\n\t/**\n\t * Returns the encoding.\n\t * @return the encoding\n\t */\n\t@Nullable String getEncoding() {\n\t\treturn this.attributes.get(\"encoding\");\n\t}\n\n\t/**\n\t * Returns the encoding as a {@link Charset}.\n\t * @return the encoding as a {@link Charset}\n\t */\n\t@Nullable Charset getEncodingAsCharset() {\n\t\tString encoding = getEncoding();\n\t\treturn (encoding != null) ? Charset.forName(encoding) : null;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"FileHint{attributes=\" + this.attributes + '}';\n\t}\n\n\t/**\n\t * Return the {@link FileHint} from the given value.\n\t * @param value the source value\n\t * @return the {@link FileHint}\n\t */\n\tstatic FileHint from(String value) {\n\t\tif (!hasBrackets(value)) {\n\t\t\treturn NONE;\n\t\t}\n\t\tList<String> betweenBrackets = findBetweenBrackets(value);\n\t\tMap<String, String> attributes = new HashMap<>();\n\t\tfor (String entry : betweenBrackets) {\n\t\t\tString cleaned = entry.trim();\n\t\t\tif (cleaned.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tint equals = cleaned.indexOf('=');\n\t\t\tif (equals == -1) {\n\t\t\t\tattributes.put(\"extension\", cleaned);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tattributes.put(cleaned.substring(0, equals).trim(), cleaned.substring(equals + 1).trim());\n\t\t\t}\n\t\t}\n\t\treturn new FileHint(Collections.unmodifiableMap(attributes));\n\t}\n\n\tprivate static List<String> findBetweenBrackets(String value) {\n\t\tList<String> collected = new ArrayList<>();\n\t\tStringBuilder buffer = new StringBuilder();\n\t\tint brackets = 0;\n\t\tfor (int i = 0; i < value.length(); i++) {\n\t\t\tchar c = value.charAt(i);\n\t\t\tif (c == '[') {\n\t\t\t\tif (brackets > 0) {\n\t\t\t\t\tbuffer.append(c);\n\t\t\t\t}\n\t\t\t\tbrackets++;\n\t\t\t}\n\t\t\telse if (c == ']') {\n\t\t\t\tbrackets--;\n\t\t\t\tif (brackets > 0) {\n\t\t\t\t\tbuffer.append(c);\n\t\t\t\t}\n\t\t\t\telse if (brackets == 0 && !buffer.isEmpty()) {\n\t\t\t\t\tcollected.add(buffer.toString());\n\t\t\t\t\tbuffer.setLength(0);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (brackets > 0) {\n\t\t\t\tbuffer.append(c);\n\t\t\t}\n\t\t}\n\t\treturn collected;\n\t}\n\n\t/**\n\t * Remove any hint from the given value.\n\t * @param value the source value\n\t * @return the value without any hint\n\t */\n\tstatic String removeFrom(String value) {\n\t\tif (!hasBrackets(value)) {\n\t\t\treturn value;\n\t\t}\n\t\tStringBuilder result = new StringBuilder();\n\t\tint brackets = 0;\n\t\tfor (int i = 0; i < value.length(); i++) {\n\t\t\tchar c = value.charAt(i);\n\t\t\tif (c == '[') {\n\t\t\t\tbrackets++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (c == ']') {\n\t\t\t\tbrackets--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (brackets <= 0) {\n\t\t\t\tresult.append(c);\n\t\t\t}\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\tprivate static boolean hasBrackets(String value) {\n\t\treturn value.indexOf('[') != -1 && value.indexOf(']') != -1;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/InactiveConfigDataAccessException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * Exception thrown when an attempt is made to resolve a property against an inactive\n * {@link ConfigData} property source. Used to ensure that a user doesn't accidentally\n * attempt to specify a properties that can never be resolved.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic class InactiveConfigDataAccessException extends ConfigDataException {\n\n\tprivate final PropertySource<?> propertySource;\n\n\tprivate final @Nullable ConfigDataResource location;\n\n\tprivate final String propertyName;\n\n\tprivate final @Nullable Origin origin;\n\n\t/**\n\t * Create a new {@link InactiveConfigDataAccessException} instance.\n\t * @param propertySource the inactive property source\n\t * @param location the {@link ConfigDataResource} of the property source or\n\t * {@code null} if the source was not loaded from {@link ConfigData}.\n\t * @param propertyName the name of the property\n\t * @param origin the origin or the property or {@code null}\n\t */\n\tInactiveConfigDataAccessException(PropertySource<?> propertySource, @Nullable ConfigDataResource location,\n\t\t\tString propertyName, @Nullable Origin origin) {\n\t\tsuper(getMessage(propertySource, location, propertyName, origin), null);\n\t\tthis.propertySource = propertySource;\n\t\tthis.location = location;\n\t\tthis.propertyName = propertyName;\n\t\tthis.origin = origin;\n\t}\n\n\tprivate static String getMessage(PropertySource<?> propertySource, @Nullable ConfigDataResource location,\n\t\t\tString propertyName, @Nullable Origin origin) {\n\t\tStringBuilder message = new StringBuilder(\"Inactive property source '\");\n\t\tmessage.append(propertySource.getName());\n\t\tif (location != null) {\n\t\t\tmessage.append(\"' imported from location '\");\n\t\t\tmessage.append(location);\n\t\t}\n\t\tmessage.append(\"' cannot contain property '\");\n\t\tmessage.append(propertyName);\n\t\tmessage.append(\"'\");\n\t\tif (origin != null) {\n\t\t\tmessage.append(\" [origin: \");\n\t\t\tmessage.append(origin);\n\t\t\tmessage.append(\"]\");\n\t\t}\n\t\treturn message.toString();\n\t}\n\n\t/**\n\t * Return the inactive property source that contained the property.\n\t * @return the property source\n\t */\n\tpublic PropertySource<?> getPropertySource() {\n\t\treturn this.propertySource;\n\t}\n\n\t/**\n\t * Return the {@link ConfigDataResource} of the property source or {@code null} if the\n\t * source was not loaded from {@link ConfigData}.\n\t * @return the config data location or {@code null}\n\t */\n\tpublic @Nullable ConfigDataResource getLocation() {\n\t\treturn this.location;\n\t}\n\n\t/**\n\t * Return the name of the property.\n\t * @return the property name\n\t */\n\tpublic String getPropertyName() {\n\t\treturn this.propertyName;\n\t}\n\n\t/**\n\t * Return the origin or the property or {@code null}.\n\t * @return the property origin\n\t */\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t/**\n\t * Throw an {@link InactiveConfigDataAccessException} if the given\n\t * {@link ConfigDataEnvironmentContributor} contains the property.\n\t * @param contributor the contributor to check\n\t * @param name the name to check\n\t */\n\tstatic void throwIfPropertyFound(ConfigDataEnvironmentContributor contributor, ConfigurationPropertyName name) {\n\t\tConfigurationPropertySource source = contributor.getConfigurationPropertySource();\n\t\tConfigurationProperty property = (source != null) ? source.getConfigurationProperty(name) : null;\n\t\tif (property != null) {\n\t\t\tPropertySource<?> propertySource = contributor.getPropertySource();\n\t\t\tConfigDataResource location = contributor.getResource();\n\t\t\tAssert.state(propertySource != null, \"'propertySource' must not be null\");\n\t\t\tthrow new InactiveConfigDataAccessException(propertySource, location, name.toString(),\n\t\t\t\t\tproperty.getOrigin());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/InvalidConfigDataPropertyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.core.env.AbstractEnvironment;\n\n/**\n * Exception thrown if an invalid property is found when processing config data.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic class InvalidConfigDataPropertyException extends ConfigDataException {\n\n\tprivate static final Map<ConfigurationPropertyName, ConfigurationPropertyName> ERRORS;\n\tstatic {\n\t\tMap<ConfigurationPropertyName, ConfigurationPropertyName> errors = new LinkedHashMap<>();\n\t\terrors.put(ConfigurationPropertyName.of(\"spring.profiles\"),\n\t\t\t\tConfigurationPropertyName.of(\"spring.config.activate.on-profile\"));\n\t\terrors.put(ConfigurationPropertyName.of(\"spring.profiles[0]\"),\n\t\t\t\tConfigurationPropertyName.of(\"spring.config.activate.on-profile\"));\n\t\tERRORS = Collections.unmodifiableMap(errors);\n\t}\n\n\tprivate static final Set<ConfigurationPropertyName> PROFILE_SPECIFIC_ERRORS;\n\tstatic {\n\t\tSet<ConfigurationPropertyName> errors = new LinkedHashSet<>();\n\t\terrors.add(Profiles.INCLUDE_PROFILES);\n\t\terrors.add(Profiles.INCLUDE_PROFILES.append(\"[0]\"));\n\t\terrors.add(ConfigurationPropertyName.of(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME));\n\t\terrors.add(ConfigurationPropertyName.of(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME + \"[0]\"));\n\t\terrors.add(ConfigurationPropertyName.of(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME));\n\t\terrors.add(ConfigurationPropertyName.of(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME + \"[0]\"));\n\t\tPROFILE_SPECIFIC_ERRORS = Collections.unmodifiableSet(errors);\n\t}\n\n\tprivate final ConfigurationProperty property;\n\n\tprivate final @Nullable ConfigurationPropertyName replacement;\n\n\tprivate final @Nullable ConfigDataResource location;\n\n\tInvalidConfigDataPropertyException(ConfigurationProperty property, boolean profileSpecific,\n\t\t\t@Nullable ConfigurationPropertyName replacement, @Nullable ConfigDataResource location) {\n\t\tsuper(getMessage(property, profileSpecific, replacement, location), null);\n\t\tthis.property = property;\n\t\tthis.replacement = replacement;\n\t\tthis.location = location;\n\t}\n\n\t/**\n\t * Return source property that caused the exception.\n\t * @return the invalid property\n\t */\n\tpublic ConfigurationProperty getProperty() {\n\t\treturn this.property;\n\t}\n\n\t/**\n\t * Return the {@link ConfigDataResource} of the invalid property or {@code null} if\n\t * the source was not loaded from {@link ConfigData}.\n\t * @return the config data location or {@code null}\n\t */\n\tpublic @Nullable ConfigDataResource getLocation() {\n\t\treturn this.location;\n\t}\n\n\t/**\n\t * Return the replacement property that should be used instead or {@code null} if not\n\t * replacement is available.\n\t * @return the replacement property name\n\t */\n\tpublic @Nullable ConfigurationPropertyName getReplacement() {\n\t\treturn this.replacement;\n\t}\n\n\t/**\n\t * Throw an {@link InvalidConfigDataPropertyException} if the given\n\t * {@link ConfigDataEnvironmentContributor} contains any invalid property.\n\t * @param contributor the contributor to check\n\t */\n\tstatic void throwIfPropertyFound(ConfigDataEnvironmentContributor contributor) {\n\t\tConfigurationPropertySource propertySource = contributor.getConfigurationPropertySource();\n\t\tif (propertySource != null) {\n\t\t\tERRORS.forEach((name, replacement) -> {\n\t\t\t\tConfigurationProperty property = propertySource.getConfigurationProperty(name);\n\t\t\t\tif (property != null) {\n\t\t\t\t\tthrow new InvalidConfigDataPropertyException(property, false, replacement,\n\t\t\t\t\t\t\tcontributor.getResource());\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (contributor.isFromProfileSpecificImport()\n\t\t\t\t\t&& !contributor.hasConfigDataOption(ConfigData.Option.IGNORE_PROFILES)) {\n\t\t\t\tPROFILE_SPECIFIC_ERRORS.forEach((name) -> {\n\t\t\t\t\tConfigurationProperty property = propertySource.getConfigurationProperty(name);\n\t\t\t\t\tif (property != null) {\n\t\t\t\t\t\tthrow new InvalidConfigDataPropertyException(property, true, null, contributor.getResource());\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static String getMessage(ConfigurationProperty property, boolean profileSpecific,\n\t\t\t@Nullable ConfigurationPropertyName replacement, @Nullable ConfigDataResource location) {\n\t\tStringBuilder message = new StringBuilder(\"Property '\");\n\t\tmessage.append(property.getName());\n\t\tif (location != null) {\n\t\t\tmessage.append(\"' imported from location '\");\n\t\t\tmessage.append(location);\n\t\t}\n\t\tmessage.append(\"' is invalid\");\n\t\tif (profileSpecific) {\n\t\t\tmessage.append(\" in a profile specific resource\");\n\t\t}\n\t\tif (replacement != null) {\n\t\t\tmessage.append(\" and should be replaced with '\");\n\t\t\tmessage.append(replacement);\n\t\t\tmessage.append(\"'\");\n\t\t}\n\t\tif (property.getOrigin() != null) {\n\t\t\tmessage.append(\" [origin: \");\n\t\t\tmessage.append(property.getOrigin());\n\t\t\tmessage.append(\"]\");\n\t\t}\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/LocationResourceLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.FilenameFilter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ResourceUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Strategy interface for loading resources from a location. Supports single resource and\n * simple wildcard directory patterns.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass LocationResourceLoader {\n\n\tprivate static final Resource[] EMPTY_RESOURCES = {};\n\n\tprivate static final Comparator<File> FILE_PATH_COMPARATOR = Comparator.comparing(File::getAbsolutePath);\n\n\tprivate static final Comparator<File> FILE_NAME_COMPARATOR = Comparator.comparing(File::getName);\n\n\tprivate final ResourceLoader resourceLoader;\n\n\t/**\n\t * Create a new {@link LocationResourceLoader} instance.\n\t * @param resourceLoader the underlying resource loader\n\t */\n\tLocationResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t/**\n\t * Returns if the location contains a pattern.\n\t * @param location the location to check\n\t * @return if the location is a pattern\n\t */\n\tboolean isPattern(String location) {\n\t\treturn StringUtils.hasLength(location) && location.contains(\"*\");\n\t}\n\n\t/**\n\t * Get a single resource from a non-pattern location.\n\t * @param location the location\n\t * @return the resource\n\t * @see #isPattern(String)\n\t */\n\tResource getResource(String location) {\n\t\tvalidateNonPattern(location);\n\t\tlocation = StringUtils.cleanPath(location);\n\t\tif (!ResourceUtils.isUrl(location)) {\n\t\t\tlocation = ResourceUtils.FILE_URL_PREFIX + location;\n\t\t}\n\t\treturn this.resourceLoader.getResource(location);\n\t}\n\n\tprivate void validateNonPattern(String location) {\n\t\tAssert.state(!isPattern(location), () -> String.format(\"Location '%s' must not be a pattern\", location));\n\t}\n\n\t/**\n\t * Get a multiple resources from a location pattern.\n\t * @param location the location pattern\n\t * @param type the type of resource to return\n\t * @return the resources\n\t * @see #isPattern(String)\n\t */\n\tResource[] getResources(String location, ResourceType type) {\n\t\tvalidatePattern(location, type);\n\t\tString directoryPath = location.substring(0, location.indexOf(\"*/\"));\n\t\tString fileName = location.substring(location.lastIndexOf(\"/\") + 1);\n\t\tResource resource = getResource(directoryPath);\n\t\tif (!resource.exists()) {\n\t\t\treturn EMPTY_RESOURCES;\n\t\t}\n\t\tFile file = getFile(location, resource);\n\t\tif (!file.isDirectory()) {\n\t\t\treturn EMPTY_RESOURCES;\n\t\t}\n\t\tFile[] subDirectories = file.listFiles(this::isVisibleDirectory);\n\t\tif (subDirectories == null) {\n\t\t\treturn EMPTY_RESOURCES;\n\t\t}\n\t\tArrays.sort(subDirectories, FILE_PATH_COMPARATOR);\n\t\tif (type == ResourceType.DIRECTORY) {\n\t\t\treturn Arrays.stream(subDirectories).map(FileSystemResource::new).toArray(Resource[]::new);\n\t\t}\n\t\tList<Resource> resources = new ArrayList<>();\n\t\tFilenameFilter filter = (dir, name) -> name.equals(fileName);\n\t\tfor (File subDirectory : subDirectories) {\n\t\t\tFile[] files = subDirectory.listFiles(filter);\n\t\t\tif (files != null) {\n\t\t\t\tArrays.sort(files, FILE_NAME_COMPARATOR);\n\t\t\t\tArrays.stream(files).map(FileSystemResource::new).forEach(resources::add);\n\t\t\t}\n\t\t}\n\t\treturn resources.toArray(EMPTY_RESOURCES);\n\t}\n\n\tprivate void validatePattern(String location, ResourceType type) {\n\t\tAssert.state(isPattern(location), () -> String.format(\"Location '%s' must be a pattern\", location));\n\t\tAssert.state(!location.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX),\n\t\t\t\t() -> String.format(\"Location '%s' cannot use classpath wildcards\", location));\n\t\tAssert.state(StringUtils.countOccurrencesOf(location, \"*\") == 1,\n\t\t\t\t() -> String.format(\"Location '%s' cannot contain multiple wildcards\", location));\n\t\tString directoryPath = (type != ResourceType.DIRECTORY) ? location.substring(0, location.lastIndexOf(\"/\") + 1)\n\t\t\t\t: location;\n\t\tAssert.state(directoryPath.endsWith(\"*/\"), () -> String.format(\"Location '%s' must end with '*/'\", location));\n\t}\n\n\tprivate File getFile(String patternLocation, Resource resource) {\n\t\ttry {\n\t\t\treturn resource.getFile();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to load config data resource from pattern '\" + patternLocation + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate boolean isVisibleDirectory(File file) {\n\t\treturn file.isDirectory() && !file.getName().startsWith(\"..\");\n\t}\n\n\t/**\n\t * Resource types that can be returned.\n\t */\n\tenum ResourceType {\n\n\t\t/**\n\t\t * Return file resources.\n\t\t */\n\t\tFILE,\n\n\t\t/**\n\t\t * Return directory resources.\n\t\t */\n\t\tDIRECTORY\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/Profiles.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.env.AbstractEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provides access to environment profiles that have either been set directly on the\n * {@link Environment} or will be set based on configuration data property values.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic class Profiles implements Iterable<String> {\n\n\t/**\n\t * Name of property to set to specify additionally included active profiles.\n\t */\n\tpublic static final String INCLUDE_PROFILES_PROPERTY_NAME = \"spring.profiles.include\";\n\n\tstatic final ConfigurationPropertyName INCLUDE_PROFILES = ConfigurationPropertyName\n\t\t.of(Profiles.INCLUDE_PROFILES_PROPERTY_NAME);\n\n\tprivate static final Bindable<MultiValueMap<String, String>> STRING_STRINGS_MAP = Bindable\n\t\t.of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class));\n\n\tprivate static final Bindable<Set<String>> STRING_SET = Bindable.setOf(String.class);\n\n\tprivate final MultiValueMap<String, String> groups;\n\n\tprivate final List<String> activeProfiles;\n\n\tprivate final List<String> defaultProfiles;\n\n\t/**\n\t * Create a new {@link Profiles} instance based on the {@link Environment} and\n\t * {@link Binder}.\n\t * @param environment the source environment\n\t * @param binder the binder for profile properties\n\t * @param additionalProfiles any additional active profiles\n\t */\n\tProfiles(Environment environment, Binder binder, @Nullable Collection<String> additionalProfiles) {\n\t\tProfilesValidator validator = ProfilesValidator.get(binder);\n\t\tif (additionalProfiles != null) {\n\t\t\tvalidator.validate(additionalProfiles, () -> \"Invalid profile property value found in additional profiles\");\n\t\t}\n\t\tthis.groups = binder.bind(\"spring.profiles.group\", STRING_STRINGS_MAP, validator)\n\t\t\t.orElseGet(LinkedMultiValueMap::new);\n\t\tthis.activeProfiles = expandProfiles(getActivatedProfiles(environment, binder, validator, additionalProfiles));\n\t\tthis.defaultProfiles = expandProfiles(getDefaultProfiles(environment, binder, validator));\n\t}\n\n\tprivate List<String> getActivatedProfiles(Environment environment, Binder binder, ProfilesValidator validator,\n\t\t\t@Nullable Collection<String> additionalProfiles) {\n\t\treturn asUniqueItemList(getProfiles(environment, binder, validator, Type.ACTIVE), additionalProfiles);\n\t}\n\n\tprivate List<String> getDefaultProfiles(Environment environment, Binder binder, ProfilesValidator validator) {\n\t\treturn asUniqueItemList(getProfiles(environment, binder, validator, Type.DEFAULT));\n\t}\n\n\tprivate Collection<String> getProfiles(Environment environment, Binder binder, ProfilesValidator validator,\n\t\t\tType type) {\n\t\tString environmentPropertyValue = environment.getProperty(type.getName());\n\t\tSet<String> environmentPropertyProfiles = (!StringUtils.hasLength(environmentPropertyValue))\n\t\t\t\t? Collections.emptySet()\n\t\t\t\t: StringUtils.commaDelimitedListToSet(StringUtils.trimAllWhitespace(environmentPropertyValue));\n\t\tvalidator.validate(environmentPropertyProfiles,\n\t\t\t\t() -> \"Invalid profile property value found in Environment under '%s'\".formatted(type.getName()));\n\t\tSet<String> environmentProfiles = new LinkedHashSet<>(Arrays.asList(type.get(environment)));\n\t\tBindResult<Set<String>> boundProfiles = binder.bind(type.getName(), STRING_SET, validator);\n\t\tif (hasProgrammaticallySetProfiles(type, environmentPropertyValue, environmentPropertyProfiles,\n\t\t\t\tenvironmentProfiles)) {\n\t\t\tif (!type.isMergeWithEnvironmentProfiles() || !boundProfiles.isBound()) {\n\t\t\t\treturn environmentProfiles;\n\t\t\t}\n\t\t\treturn boundProfiles.map((bound) -> merge(environmentProfiles, bound)).get();\n\t\t}\n\t\treturn boundProfiles.orElse(type.getDefaultValue());\n\t}\n\n\tprivate boolean hasProgrammaticallySetProfiles(Type type, @Nullable String environmentPropertyValue,\n\t\t\tSet<String> environmentPropertyProfiles, Set<String> environmentProfiles) {\n\t\tif (!StringUtils.hasLength(environmentPropertyValue)) {\n\t\t\treturn !type.getDefaultValue().equals(environmentProfiles);\n\t\t}\n\t\tif (type.getDefaultValue().equals(environmentProfiles)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn !environmentPropertyProfiles.equals(environmentProfiles);\n\t}\n\n\tprivate Set<String> merge(Set<String> environmentProfiles, Set<String> bound) {\n\t\tSet<String> result = new LinkedHashSet<>(environmentProfiles);\n\t\tresult.addAll(bound);\n\t\treturn result;\n\t}\n\n\tprivate List<String> expandProfiles(@Nullable List<String> profiles) {\n\t\tDeque<String> stack = new ArrayDeque<>();\n\t\tasReversedList(profiles).forEach(stack::push);\n\t\tSet<String> expandedProfiles = new LinkedHashSet<>();\n\t\twhile (!stack.isEmpty()) {\n\t\t\tString current = stack.pop();\n\t\t\tif (expandedProfiles.add(current)) {\n\t\t\t\tasReversedList(this.groups.get(current)).forEach(stack::push);\n\t\t\t}\n\t\t}\n\t\treturn asUniqueItemList(expandedProfiles);\n\t}\n\n\tprivate List<String> asReversedList(@Nullable List<String> list) {\n\t\tif (CollectionUtils.isEmpty(list)) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<String> reversed = new ArrayList<>(list);\n\t\tCollections.reverse(reversed);\n\t\treturn reversed;\n\t}\n\n\tprivate List<String> asUniqueItemList(Collection<String> profiles) {\n\t\treturn asUniqueItemList(profiles, null);\n\t}\n\n\tprivate List<String> asUniqueItemList(Collection<String> profiles, @Nullable Collection<String> additional) {\n\t\tLinkedHashSet<String> uniqueItems = new LinkedHashSet<>();\n\t\tif (!CollectionUtils.isEmpty(additional)) {\n\t\t\tuniqueItems.addAll(additional);\n\t\t}\n\t\tuniqueItems.addAll(profiles);\n\t\treturn Collections.unmodifiableList(new ArrayList<>(uniqueItems));\n\t}\n\n\t/**\n\t * Return an iterator for all {@link #getAccepted() accepted profiles}.\n\t */\n\t@Override\n\tpublic Iterator<String> iterator() {\n\t\treturn getAccepted().iterator();\n\t}\n\n\t/**\n\t * Return the active profiles.\n\t * @return the active profiles\n\t */\n\tpublic List<String> getActive() {\n\t\treturn this.activeProfiles;\n\t}\n\n\t/**\n\t * Return the default profiles.\n\t * @return the active profiles\n\t */\n\tpublic List<String> getDefault() {\n\t\treturn this.defaultProfiles;\n\t}\n\n\t/**\n\t * Return the accepted profiles.\n\t * @return the accepted profiles\n\t */\n\tpublic List<String> getAccepted() {\n\t\treturn (!this.activeProfiles.isEmpty()) ? this.activeProfiles : this.defaultProfiles;\n\t}\n\n\t/**\n\t * Return if the given profile is active.\n\t * @param profile the profile to test\n\t * @return if the profile is active\n\t */\n\tpublic boolean isAccepted(String profile) {\n\t\treturn getAccepted().contains(profile);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tcreator.append(\"active\", getActive().toString());\n\t\tcreator.append(\"default\", getDefault().toString());\n\t\tcreator.append(\"accepted\", getAccepted().toString());\n\t\treturn creator.toString();\n\t}\n\n\t/**\n\t * A profiles type that can be obtained.\n\t */\n\tprivate enum Type {\n\n\t\tACTIVE(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, Environment::getActiveProfiles, true,\n\t\t\t\tCollections.emptySet()),\n\n\t\tDEFAULT(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, Environment::getDefaultProfiles, false,\n\t\t\t\tCollections.singleton(\"default\"));\n\n\t\tprivate final Function<Environment, String[]> getter;\n\n\t\tprivate final boolean mergeWithEnvironmentProfiles;\n\n\t\tprivate final String name;\n\n\t\tprivate final Set<String> defaultValue;\n\n\t\tType(String name, Function<Environment, String[]> getter, boolean mergeWithEnvironmentProfiles,\n\t\t\t\tSet<String> defaultValue) {\n\t\t\tthis.name = name;\n\t\t\tthis.getter = getter;\n\t\t\tthis.mergeWithEnvironmentProfiles = mergeWithEnvironmentProfiles;\n\t\t\tthis.defaultValue = defaultValue;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tString[] get(Environment environment) {\n\t\t\treturn this.getter.apply(environment);\n\t\t}\n\n\t\tSet<String> getDefaultValue() {\n\t\t\treturn this.defaultValue;\n\t\t}\n\n\t\tboolean isMergeWithEnvironmentProfiles() {\n\t\t\treturn this.mergeWithEnvironmentProfiles;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/ProfilesValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link BindHandler} that validates profile names.\n *\n * @author Sijun Yang\n * @author Phillip Webb\n */\nfinal class ProfilesValidator implements BindHandler {\n\n\tprivate static final String ALLOWED_CHARS = \"-_.+@\";\n\n\tprivate final boolean validate;\n\n\tprivate ProfilesValidator(boolean validate) {\n\t\tthis.validate = validate;\n\t}\n\n\t@Override\n\tpublic Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {\n\t\tvalidate(result);\n\t\treturn result;\n\t}\n\n\tvoid validate(Object value, Supplier<String> wrappedExceptionMessage) {\n\t\ttry {\n\t\t\tvalidate(value);\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\tthrow new IllegalStateException(wrappedExceptionMessage.get(), ex);\n\t\t}\n\t}\n\n\tprivate void validate(@Nullable Object value) {\n\t\tif (!this.validate) {\n\t\t\treturn;\n\t\t}\n\t\tif (value instanceof Collection<?> list) {\n\t\t\tlist.forEach(this::validate);\n\t\t\treturn;\n\t\t}\n\t\tif (value instanceof Map<?, ?> map) {\n\t\t\tmap.forEach((k, v) -> validate(v));\n\t\t\treturn;\n\t\t}\n\t\tString profile = (value != null) ? value.toString() : null;\n\t\tAssert.state(StringUtils.hasText(profile), \"Invalid empty profile\");\n\t\tfor (int i = 0; i < profile.length(); i++) {\n\t\t\tint codePoint = profile.codePointAt(i);\n\t\t\tboolean isAllowedChar = ALLOWED_CHARS.indexOf(codePoint) != -1;\n\t\t\tAssert.state(isAllowedChar || Character.isLetterOrDigit(codePoint),\n\t\t\t\t\t() -> \"Profile '%s' must contain a letter, digit or allowed char (%s)\".formatted(profile,\n\t\t\t\t\t\t\tArrays.stream(ALLOWED_CHARS.split(\"\")).collect(Collectors.joining(\"', '\", \"'\", \"'\"))));\n\t\t\tAssert.state((i > 0 && i < profile.length() - 1) || Character.isLetterOrDigit(codePoint),\n\t\t\t\t\t() -> \"Profile '%s' must start and end with a letter or digit\".formatted(profile));\n\t\t}\n\n\t}\n\n\tstatic ProfilesValidator get(Binder binder) {\n\t\treturn new ProfilesValidator(binder.bind(\"spring.profiles.validate\", Boolean.class).orElse(true));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.springframework.boot.context.config.ConfigData.Option;\nimport org.springframework.boot.context.config.ConfigData.PropertySourceOptions;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedResource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link ConfigDataLoader} for {@link Resource} backed locations.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic class StandardConfigDataLoader implements ConfigDataLoader<StandardConfigDataResource> {\n\n\tprivate static final PropertySourceOptions PROFILE_SPECIFIC = PropertySourceOptions.always(Option.PROFILE_SPECIFIC);\n\n\tprivate static final PropertySourceOptions NON_PROFILE_SPECIFIC = PropertySourceOptions.ALWAYS_NONE;\n\n\t@Override\n\tpublic ConfigData load(ConfigDataLoaderContext context, StandardConfigDataResource resource)\n\t\t\tthrows IOException, ConfigDataNotFoundException {\n\t\tif (resource.isEmptyDirectory()) {\n\t\t\treturn ConfigData.EMPTY;\n\t\t}\n\t\tConfigDataResourceNotFoundException.throwIfDoesNotExist(resource, resource.getResource());\n\t\tStandardConfigDataReference reference = resource.getReference();\n\t\tResource originTrackedResource = OriginTrackedResource.of(resource.getResource(),\n\t\t\t\tOrigin.from(reference.getConfigDataLocation()));\n\t\tString name = String.format(\"Config resource '%s' via location '%s'\", resource,\n\t\t\t\treference.getConfigDataLocation());\n\t\tList<PropertySource<?>> propertySources = reference.getPropertySourceLoader()\n\t\t\t.load(name, originTrackedResource, reference.getEncoding());\n\t\tPropertySourceOptions options = (resource.getProfile() != null) ? PROFILE_SPECIFIC : NON_PROFILE_SPECIFIC;\n\t\treturn new ConfigData(propertySources, options);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataLocationResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.config.LocationResourceLoader.ResourceType;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.ResourceUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ConfigDataLocationResolver} for standard locations.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Sijun Yang\n * @since 2.4.0\n */\npublic class StandardConfigDataLocationResolver\n\t\timplements ConfigDataLocationResolver<StandardConfigDataResource>, Ordered {\n\n\tprivate static final String PREFIX = \"resource:\";\n\n\tstatic final String CONFIG_NAME_PROPERTY = \"spring.config.name\";\n\n\tstatic final String[] DEFAULT_CONFIG_NAMES = { \"application\" };\n\n\tprivate static final Pattern URL_PREFIX = Pattern.compile(\"^([a-zA-Z][a-zA-Z0-9*]*?:)(.*$)\");\n\n\tprivate static final @Nullable String NO_PROFILE = null;\n\n\tprivate final Log logger;\n\n\tprivate final List<PropertySourceLoader> propertySourceLoaders;\n\n\tprivate final String[] configNames;\n\n\tprivate final LocationResourceLoader resourceLoader;\n\n\t/**\n\t * Create a new {@link StandardConfigDataLocationResolver} instance.\n\t * @param logFactory the factory for loggers to use\n\t * @param binder a binder backed by the initial {@link Environment}\n\t * @param resourceLoader a {@link ResourceLoader} used to load resources\n\t */\n\tpublic StandardConfigDataLocationResolver(DeferredLogFactory logFactory, Binder binder,\n\t\t\tResourceLoader resourceLoader) {\n\t\tthis.logger = logFactory.getLog(StandardConfigDataLocationResolver.class);\n\t\tthis.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,\n\t\t\t\tresourceLoader.getClassLoader());\n\t\tthis.configNames = getConfigNames(binder);\n\t\tthis.resourceLoader = new LocationResourceLoader(resourceLoader);\n\t}\n\n\tprivate String[] getConfigNames(Binder binder) {\n\t\tString[] configNames = binder.bind(CONFIG_NAME_PROPERTY, String[].class).orElse(DEFAULT_CONFIG_NAMES);\n\t\tfor (String configName : configNames) {\n\t\t\tvalidateConfigName(configName);\n\t\t}\n\t\treturn configNames;\n\t}\n\n\tprivate void validateConfigName(String name) {\n\t\tAssert.state(!name.contains(\"*\"), () -> \"Config name '\" + name + \"' cannot contain '*'\");\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic List<StandardConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation location) throws ConfigDataNotFoundException {\n\t\treturn resolve(getReferences(context, location.split()));\n\t}\n\n\tprivate Set<StandardConfigDataReference> getReferences(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation[] configDataLocations) {\n\t\tSet<StandardConfigDataReference> references = new LinkedHashSet<>();\n\t\tfor (ConfigDataLocation configDataLocation : configDataLocations) {\n\t\t\treferences.addAll(getReferences(context, configDataLocation));\n\t\t}\n\t\treturn references;\n\t}\n\n\tprivate Set<StandardConfigDataReference> getReferences(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation configDataLocation) {\n\t\tString resourceLocation = getResourceLocation(context, configDataLocation);\n\t\ttry {\n\t\t\tif (isDirectory(resourceLocation)) {\n\t\t\t\treturn getReferencesForDirectory(configDataLocation, resourceLocation, NO_PROFILE);\n\t\t\t}\n\t\t\treturn getReferencesForFile(configDataLocation, resourceLocation, NO_PROFILE);\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load config data from '\" + configDataLocation + \"'\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<StandardConfigDataResource> resolveProfileSpecific(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation location, Profiles profiles) {\n\t\treturn resolve(getProfileSpecificReferences(context, location.split(), profiles));\n\t}\n\n\tprivate Set<StandardConfigDataReference> getProfileSpecificReferences(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation[] configDataLocations, Profiles profiles) {\n\t\tSet<StandardConfigDataReference> references = new LinkedHashSet<>();\n\t\tfor (String profile : profiles) {\n\t\t\tfor (ConfigDataLocation configDataLocation : configDataLocations) {\n\t\t\t\tString resourceLocation = getResourceLocation(context, configDataLocation);\n\t\t\t\treferences.addAll(getReferences(configDataLocation, resourceLocation, profile));\n\t\t\t}\n\t\t}\n\t\treturn references;\n\t}\n\n\tprivate String getResourceLocation(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation configDataLocation) {\n\t\tString resourceLocation = configDataLocation.getNonPrefixedValue(PREFIX);\n\t\tboolean isFixedPath = resourceLocation.startsWith(\"/\") || URL_PREFIX.matcher(resourceLocation).matches();\n\t\tif (isFixedPath) {\n\t\t\treturn resourceLocation;\n\t\t}\n\t\tConfigDataResource parent = context.getParent();\n\t\tif (parent instanceof StandardConfigDataResource resource) {\n\t\t\tString parentResourceLocation = resource.getReference().getResourceLocation();\n\t\t\tString parentDirectory = parentResourceLocation.substring(0, parentResourceLocation.lastIndexOf(\"/\") + 1);\n\t\t\treturn parentDirectory + resourceLocation;\n\t\t}\n\t\treturn resourceLocation;\n\t}\n\n\tprivate Set<StandardConfigDataReference> getReferences(ConfigDataLocation configDataLocation,\n\t\t\tString resourceLocation, String profile) {\n\t\tif (isDirectory(resourceLocation)) {\n\t\t\treturn getReferencesForDirectory(configDataLocation, resourceLocation, profile);\n\t\t}\n\t\treturn getReferencesForFile(configDataLocation, resourceLocation, profile);\n\t}\n\n\tprivate Set<StandardConfigDataReference> getReferencesForDirectory(ConfigDataLocation configDataLocation,\n\t\t\tString directory, @Nullable String profile) {\n\t\tSet<StandardConfigDataReference> references = new LinkedHashSet<>();\n\t\tfor (String name : this.configNames) {\n\t\t\tDeque<StandardConfigDataReference> referencesForName = getReferencesForConfigName(name, configDataLocation,\n\t\t\t\t\tdirectory, profile);\n\t\t\treferences.addAll(referencesForName);\n\t\t}\n\t\treturn references;\n\t}\n\n\tprivate Deque<StandardConfigDataReference> getReferencesForConfigName(String name,\n\t\t\tConfigDataLocation configDataLocation, String directory, @Nullable String profile) {\n\t\tDeque<StandardConfigDataReference> references = new ArrayDeque<>();\n\t\tfor (PropertySourceLoader propertySourceLoader : this.propertySourceLoaders) {\n\t\t\tfor (String extension : propertySourceLoader.getFileExtensions()) {\n\t\t\t\tStandardConfigDataReference reference = new StandardConfigDataReference(configDataLocation, directory,\n\t\t\t\t\t\tdirectory + name, profile, extension, propertySourceLoader, null);\n\t\t\t\tif (!references.contains(reference)) {\n\t\t\t\t\treferences.addFirst(reference);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn references;\n\t}\n\n\tprivate Set<StandardConfigDataReference> getReferencesForFile(ConfigDataLocation configDataLocation, String file,\n\t\t\t@Nullable String profile) {\n\t\tFileHint fileHint = FileHint.from(file);\n\t\tfile = FileHint.removeFrom(file);\n\t\tboolean hasFileHintExtension = fileHint.getExtension() != null;\n\t\tif (hasFileHintExtension) {\n\t\t\tfile = file + fileHint.getExtension();\n\t\t}\n\t\tfor (PropertySourceLoader propertySourceLoader : this.propertySourceLoaders) {\n\t\t\tString fileExtension = getLoadableFileExtension(propertySourceLoader, file);\n\t\t\tif (fileExtension != null) {\n\t\t\t\tString root = file.substring(0, file.length() - fileExtension.length() - 1);\n\t\t\t\tStandardConfigDataReference reference = new StandardConfigDataReference(configDataLocation, null, root,\n\t\t\t\t\t\tprofile, (!hasFileHintExtension) ? fileExtension : null, propertySourceLoader,\n\t\t\t\t\t\tfileHint.getEncodingAsCharset());\n\t\t\t\treturn Collections.singleton(reference);\n\t\t\t}\n\t\t}\n\t\tif (configDataLocation.isOptional()) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t\tif (configDataLocation.hasPrefix(PREFIX) || configDataLocation.hasPrefix(ResourceUtils.FILE_URL_PREFIX)\n\t\t\t\t|| configDataLocation.hasPrefix(ResourceUtils.CLASSPATH_URL_PREFIX)\n\t\t\t\t|| configDataLocation.toString().indexOf(':') == -1) {\n\t\t\tthrow new IllegalStateException(\"File extension is not known to any PropertySourceLoader. \"\n\t\t\t\t\t+ \"If the location is meant to reference a directory, it must end in '/' or File.separator\");\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Incorrect ConfigDataLocationResolver chosen or file extension is not known to any PropertySourceLoader. \"\n\t\t\t\t\t\t+ \"If the location is meant to reference a directory, it must end in '/' or File.separator. \"\n\t\t\t\t\t\t+ \"The location is being resolved using the StandardConfigDataLocationResolver, \"\n\t\t\t\t\t\t+ \"check the location prefix if a different resolver is expected\");\n\t}\n\n\tprivate @Nullable String getLoadableFileExtension(PropertySourceLoader loader, String file) {\n\t\tfor (String fileExtension : loader.getFileExtensions()) {\n\t\t\tif (StringUtils.endsWithIgnoreCase(file, fileExtension)) {\n\t\t\t\treturn fileExtension;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isDirectory(String resourceLocation) {\n\t\treturn resourceLocation.endsWith(\"/\") || resourceLocation.endsWith(File.separator);\n\t}\n\n\tprivate List<StandardConfigDataResource> resolve(Set<StandardConfigDataReference> references) {\n\t\tList<StandardConfigDataResource> resolved = new ArrayList<>();\n\t\tfor (StandardConfigDataReference reference : references) {\n\t\t\tresolved.addAll(resolve(reference));\n\t\t}\n\t\tif (resolved.isEmpty()) {\n\t\t\tresolved.addAll(resolveEmptyDirectories(references));\n\t\t}\n\t\treturn resolved;\n\t}\n\n\tprivate Collection<StandardConfigDataResource> resolveEmptyDirectories(\n\t\t\tSet<StandardConfigDataReference> references) {\n\t\tSet<StandardConfigDataResource> empty = new LinkedHashSet<>();\n\t\tfor (StandardConfigDataReference reference : references) {\n\t\t\tif (reference.getDirectory() != null) {\n\t\t\t\tempty.addAll(resolveEmptyDirectories(reference));\n\t\t\t}\n\t\t}\n\t\treturn empty;\n\t}\n\n\tprivate Set<StandardConfigDataResource> resolveEmptyDirectories(StandardConfigDataReference reference) {\n\t\tif (!this.resourceLoader.isPattern(reference.getResourceLocation())) {\n\t\t\treturn resolveNonPatternEmptyDirectories(reference);\n\t\t}\n\t\treturn resolvePatternEmptyDirectories(reference);\n\t}\n\n\tprivate Set<StandardConfigDataResource> resolveNonPatternEmptyDirectories(StandardConfigDataReference reference) {\n\t\tString directory = reference.getDirectory();\n\t\tAssert.state(directory != null, \"'directory' must not be null\");\n\t\tResource resource = this.resourceLoader.getResource(directory);\n\t\treturn (resource instanceof ClassPathResource || !resource.exists()) ? Collections.emptySet()\n\t\t\t\t: Collections.singleton(new StandardConfigDataResource(reference, resource, true));\n\t}\n\n\tprivate Set<StandardConfigDataResource> resolvePatternEmptyDirectories(StandardConfigDataReference reference) {\n\t\tString directory = reference.getDirectory();\n\t\tAssert.state(directory != null, \"'directory' must not be null\");\n\t\tResource[] subdirectories = this.resourceLoader.getResources(directory, ResourceType.DIRECTORY);\n\t\tConfigDataLocation location = reference.getConfigDataLocation();\n\t\tif (!location.isOptional() && ObjectUtils.isEmpty(subdirectories)) {\n\t\t\tString message = String.format(\"Config data location '%s' contains no subdirectories\", location);\n\t\t\tthrow new ConfigDataLocationNotFoundException(location, message, null);\n\t\t}\n\t\treturn Arrays.stream(subdirectories)\n\t\t\t.filter(Resource::exists)\n\t\t\t.map((resource) -> new StandardConfigDataResource(reference, resource, true))\n\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t}\n\n\tprivate List<StandardConfigDataResource> resolve(StandardConfigDataReference reference) {\n\t\tif (!this.resourceLoader.isPattern(reference.getResourceLocation())) {\n\t\t\treturn resolveNonPattern(reference);\n\t\t}\n\t\treturn resolvePattern(reference);\n\t}\n\n\tprivate List<StandardConfigDataResource> resolveNonPattern(StandardConfigDataReference reference) {\n\t\tResource resource = this.resourceLoader.getResource(reference.getResourceLocation());\n\t\tif (!resource.exists() && reference.isSkippable()) {\n\t\t\tlogSkippingResource(reference);\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\treturn Collections.singletonList(createConfigResourceLocation(reference, resource));\n\t}\n\n\tprivate List<StandardConfigDataResource> resolvePattern(StandardConfigDataReference reference) {\n\t\tList<StandardConfigDataResource> resolved = new ArrayList<>();\n\t\tfor (Resource resource : this.resourceLoader.getResources(reference.getResourceLocation(), ResourceType.FILE)) {\n\t\t\tif (!resource.exists() && reference.isSkippable()) {\n\t\t\t\tlogSkippingResource(reference);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresolved.add(createConfigResourceLocation(reference, resource));\n\t\t\t}\n\t\t}\n\t\treturn resolved;\n\t}\n\n\tprivate void logSkippingResource(StandardConfigDataReference reference) {\n\t\tthis.logger.trace(LogMessage.format(\"Skipping missing resource %s\", reference));\n\t}\n\n\tprivate StandardConfigDataResource createConfigResourceLocation(StandardConfigDataReference reference,\n\t\t\tResource resource) {\n\t\treturn new StandardConfigDataResource(reference, resource);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataReference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.nio.charset.Charset;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.util.StringUtils;\n\n/**\n * A reference expanded from the original {@link ConfigDataLocation} that can ultimately\n * be resolved to one or more {@link StandardConfigDataResource resources}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass StandardConfigDataReference {\n\n\tprivate final ConfigDataLocation configDataLocation;\n\n\tprivate final String resourceLocation;\n\n\tprivate final @Nullable String directory;\n\n\tprivate final @Nullable String profile;\n\n\tprivate final PropertySourceLoader propertySourceLoader;\n\n\tprivate final @Nullable Charset encoding;\n\n\t/**\n\t * Create a new {@link StandardConfigDataReference} instance.\n\t * @param configDataLocation the original location passed to the resolver\n\t * @param directory the directory of the resource or {@code null} if the reference is\n\t * to a file\n\t * @param root the root of the resource location\n\t * @param profile the profile being loaded\n\t * @param extension the file extension for the resource\n\t * @param propertySourceLoader the property source loader that should be used for this\n\t * reference\n\t * @param encoding the encoding of the resource\n\t */\n\tStandardConfigDataReference(ConfigDataLocation configDataLocation, @Nullable String directory, String root,\n\t\t\t@Nullable String profile, @Nullable String extension, PropertySourceLoader propertySourceLoader,\n\t\t\t@Nullable Charset encoding) {\n\t\tthis.configDataLocation = configDataLocation;\n\t\tString profileSuffix = (StringUtils.hasText(profile)) ? \"-\" + profile : \"\";\n\t\tthis.resourceLocation = root + profileSuffix + ((extension != null) ? \".\" + extension : \"\");\n\t\tthis.directory = directory;\n\t\tthis.profile = profile;\n\t\tthis.propertySourceLoader = propertySourceLoader;\n\t\tthis.encoding = encoding;\n\t}\n\n\tConfigDataLocation getConfigDataLocation() {\n\t\treturn this.configDataLocation;\n\t}\n\n\tString getResourceLocation() {\n\t\treturn this.resourceLocation;\n\t}\n\n\tboolean isMandatoryDirectory() {\n\t\treturn !this.configDataLocation.isOptional() && this.directory != null;\n\t}\n\n\t@Nullable String getDirectory() {\n\t\treturn this.directory;\n\t}\n\n\t@Nullable String getProfile() {\n\t\treturn this.profile;\n\t}\n\n\t@Nullable Charset getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\tboolean isSkippable() {\n\t\treturn this.configDataLocation.isOptional() || this.directory != null || this.profile != null;\n\t}\n\n\tPropertySourceLoader getPropertySourceLoader() {\n\t\treturn this.propertySourceLoader;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif ((obj == null) || (getClass() != obj.getClass())) {\n\t\t\treturn false;\n\t\t}\n\t\tStandardConfigDataReference other = (StandardConfigDataReference) obj;\n\t\treturn this.resourceLocation.equals(other.resourceLocation);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.resourceLocation.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.resourceLocation;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/StandardConfigDataResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.FileUrlResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigDataResource} backed by a {@link Resource}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class StandardConfigDataResource extends ConfigDataResource {\n\n\tprivate final StandardConfigDataReference reference;\n\n\tprivate final Resource resource;\n\n\tprivate final boolean emptyDirectory;\n\n\t/**\n\t * Create a new {@link StandardConfigDataResource} instance.\n\t * @param reference the resource reference\n\t * @param resource the underlying resource\n\t */\n\tStandardConfigDataResource(StandardConfigDataReference reference, Resource resource) {\n\t\tthis(reference, resource, false);\n\t}\n\n\t/**\n\t * Create a new {@link StandardConfigDataResource} instance.\n\t * @param reference the resource reference\n\t * @param resource the underlying resource\n\t * @param emptyDirectory if the resource is an empty directory that we know exists\n\t */\n\tStandardConfigDataResource(StandardConfigDataReference reference, Resource resource, boolean emptyDirectory) {\n\t\tAssert.notNull(reference, \"'reference' must not be null\");\n\t\tAssert.notNull(resource, \"'resource' must not be null\");\n\t\tthis.reference = reference;\n\t\tthis.resource = resource;\n\t\tthis.emptyDirectory = emptyDirectory;\n\t}\n\n\tStandardConfigDataReference getReference() {\n\t\treturn this.reference;\n\t}\n\n\t/**\n\t * Return the underlying Spring {@link Resource} being loaded.\n\t * @return the underlying resource\n\t * @since 2.4.2\n\t */\n\tpublic Resource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t/**\n\t * Return the profile or {@code null} if the resource is not profile specific.\n\t * @return the profile or {@code null}\n\t * @since 2.4.6\n\t */\n\tpublic @Nullable String getProfile() {\n\t\treturn this.reference.getProfile();\n\t}\n\n\tboolean isEmptyDirectory() {\n\t\treturn this.emptyDirectory;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tStandardConfigDataResource other = (StandardConfigDataResource) obj;\n\t\treturn (this.emptyDirectory == other.emptyDirectory) && isSameUnderlyingResource(this.resource, other.resource);\n\t}\n\n\tprivate boolean isSameUnderlyingResource(Resource ours, Resource other) {\n\t\treturn ours.equals(other) || isSameFile(getUnderlyingFile(ours), getUnderlyingFile(other));\n\t}\n\n\tprivate boolean isSameFile(@Nullable File ours, @Nullable File other) {\n\t\treturn (ours != null) && ours.equals(other);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tFile underlyingFile = getUnderlyingFile(this.resource);\n\t\treturn (underlyingFile != null) ? underlyingFile.hashCode() : this.resource.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tif (this.resource instanceof FileSystemResource || this.resource instanceof FileUrlResource) {\n\t\t\ttry {\n\t\t\t\treturn \"file [\" + this.resource.getFile() + \"]\";\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn this.resource.toString();\n\t}\n\n\tprivate @Nullable File getUnderlyingFile(Resource resource) {\n\t\ttry {\n\t\t\tif (resource instanceof ClassPathResource || resource instanceof FileSystemResource\n\t\t\t\t\t|| resource instanceof FileUrlResource) {\n\t\t\t\treturn resource.getFile().getAbsoluteFile();\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/SystemEnvironmentConfigDataLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.springframework.core.env.PropertySource;\n\n/**\n * {@link ConfigDataLoader} to load data from system environment variables.\n *\n * @author Moritz Halbritter\n */\nclass SystemEnvironmentConfigDataLoader implements ConfigDataLoader<SystemEnvironmentConfigDataResource> {\n\n\t@Override\n\tpublic ConfigData load(ConfigDataLoaderContext context, SystemEnvironmentConfigDataResource resource)\n\t\t\tthrows IOException, ConfigDataResourceNotFoundException {\n\t\tList<PropertySource<?>> loaded = resource.load();\n\t\tif (loaded == null) {\n\t\t\tthrow new ConfigDataResourceNotFoundException(resource);\n\t\t}\n\t\treturn new ConfigData(loaded);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/SystemEnvironmentConfigDataLocationResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * {@link ConfigDataLocationResolver} to resolve {@code env:} locations.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass SystemEnvironmentConfigDataLocationResolver\n\t\timplements ConfigDataLocationResolver<SystemEnvironmentConfigDataResource> {\n\n\tprivate static final String PREFIX = \"env:\";\n\n\tprivate static final String DEFAULT_EXTENSION = \".properties\";\n\n\tprivate final List<PropertySourceLoader> loaders;\n\n\tprivate final Function<String, @Nullable String> environment;\n\n\tSystemEnvironmentConfigDataLocationResolver() {\n\t\tthis.loaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());\n\t\tthis.environment = System::getenv;\n\t}\n\n\tSystemEnvironmentConfigDataLocationResolver(List<PropertySourceLoader> loaders,\n\t\t\tFunction<String, @Nullable String> environment) {\n\t\tthis.loaders = loaders;\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\treturn location.hasPrefix(PREFIX);\n\t}\n\n\t@Override\n\tpublic List<SystemEnvironmentConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation location)\n\t\t\tthrows ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException {\n\t\tString value = location.getNonPrefixedValue(PREFIX);\n\t\tFileHint fileHint = FileHint.from(value);\n\t\tString variableName = FileHint.removeFrom(value);\n\t\tPropertySourceLoader loader = getLoader(fileHint.getExtensionOrElse(DEFAULT_EXTENSION));\n\t\tif (hasEnvVariable(variableName)) {\n\t\t\treturn List.of(new SystemEnvironmentConfigDataResource(variableName, loader, this.environment,\n\t\t\t\t\tfileHint.getEncodingAsCharset()));\n\t\t}\n\t\tif (location.isOptional()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tthrow new ConfigDataLocationNotFoundException(location,\n\t\t\t\t\"Environment variable '%s' is not set\".formatted(variableName), null);\n\t}\n\n\tprivate PropertySourceLoader getLoader(String extension) {\n\t\textension = (!extension.startsWith(\".\")) ? extension : extension.substring(1);\n\t\tfor (PropertySourceLoader loader : this.loaders) {\n\t\t\tfor (String supportedExtension : loader.getFileExtensions()) {\n\t\t\t\tif (supportedExtension.equalsIgnoreCase(extension)) {\n\t\t\t\t\treturn loader;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"File extension '%s' is not known to any PropertySourceLoader\".formatted(extension));\n\t}\n\n\tprivate boolean hasEnvVariable(String variableName) {\n\t\treturn this.environment.apply(variableName) != null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/SystemEnvironmentConfigDataResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ConfigDataResource} used by {@link SystemEnvironmentConfigDataLoader}.\n *\n * @author Moritz Halbritter\n */\nclass SystemEnvironmentConfigDataResource extends ConfigDataResource {\n\n\tprivate final String variableName;\n\n\tprivate final PropertySourceLoader loader;\n\n\tprivate final Function<String, @Nullable String> environment;\n\n\tprivate final @Nullable Charset encoding;\n\n\tSystemEnvironmentConfigDataResource(String variableName, PropertySourceLoader loader,\n\t\t\tFunction<String, @Nullable String> environment, @Nullable Charset encoding) {\n\t\tthis.variableName = variableName;\n\t\tthis.loader = loader;\n\t\tthis.environment = environment;\n\t\tthis.encoding = encoding;\n\t}\n\n\tString getVariableName() {\n\t\treturn this.variableName;\n\t}\n\n\tPropertySourceLoader getLoader() {\n\t\treturn this.loader;\n\t}\n\n\t@Nullable List<PropertySource<?>> load() throws IOException {\n\t\tString content = this.environment.apply(this.variableName);\n\t\treturn (content != null)\n\t\t\t\t? this.loader.load(StringUtils.capitalize(toString()), asResource(content), this.encoding) : null;\n\t}\n\n\tprivate ByteArrayResource asResource(String content) {\n\t\treturn new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tSystemEnvironmentConfigDataResource other = (SystemEnvironmentConfigDataResource) obj;\n\t\treturn Objects.equals(this.loader.getClass(), other.loader.getClass())\n\t\t\t\t&& Objects.equals(this.variableName, other.variableName);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.variableName, this.loader.getClass());\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"system environment variable [\" + this.variableName + \"] content loaded using \"\n\t\t\t\t+ ClassUtils.getShortName(this.loader.getClass());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/UnsupportedConfigDataLocationException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\n/**\n * Exception throw if a {@link ConfigDataLocation} is not supported.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.4.0\n */\npublic class UnsupportedConfigDataLocationException extends ConfigDataException {\n\n\tprivate final ConfigDataLocation location;\n\n\t/**\n\t * Create a new {@link UnsupportedConfigDataLocationException} instance.\n\t * @param location the unsupported location\n\t */\n\tUnsupportedConfigDataLocationException(ConfigDataLocation location) {\n\t\tsuper(\"Unsupported config data location '\" + location + \"'\", null);\n\t\tthis.location = location;\n\t}\n\n\t/**\n\t * Return the unsupported location reference.\n\t * @return the unsupported location reference\n\t */\n\tpublic ConfigDataLocation getLocation() {\n\t\treturn this.location;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/config/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * External configuration support allowing 'application.properties' to be loaded and used\n * within a Spring Boot application.\n *\n * @see org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor\n */\n@NullMarked\npackage org.springframework.boot.context.config;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationContextInitializedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Event published when a {@link SpringApplication} is starting up and the\n * {@link ApplicationContext} is prepared and ApplicationContextInitializers have been\n * called but before any bean definitions are loaded.\n *\n * @author Artsiom Yudovin\n * @since 2.1.0\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationContextInitializedEvent extends SpringApplicationEvent {\n\n\tprivate final ConfigurableApplicationContext context;\n\n\t/**\n\t * Create a new {@link ApplicationContextInitializedEvent} instance.\n\t * @param application the current application\n\t * @param args the arguments the application is running with\n\t * @param context the context that has been initialized\n\t */\n\tpublic ApplicationContextInitializedEvent(SpringApplication application, String[] args,\n\t\t\tConfigurableApplicationContext context) {\n\t\tsuper(application, args);\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * Return the application context.\n\t * @return the context\n\t */\n\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\treturn this.context;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationEnvironmentPreparedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\n/**\n * Event published when a {@link SpringApplication} is starting up and the\n * {@link Environment} is first available for inspection and modification.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationEnvironmentPreparedEvent extends SpringApplicationEvent {\n\n\tprivate final ConfigurableBootstrapContext bootstrapContext;\n\n\tprivate final ConfigurableEnvironment environment;\n\n\t/**\n\t * Create a new {@link ApplicationEnvironmentPreparedEvent} instance.\n\t * @param bootstrapContext the bootstrap context\n\t * @param application the current application\n\t * @param args the arguments the application is running with\n\t * @param environment the environment that was just created\n\t */\n\tpublic ApplicationEnvironmentPreparedEvent(ConfigurableBootstrapContext bootstrapContext,\n\t\t\tSpringApplication application, String[] args, ConfigurableEnvironment environment) {\n\t\tsuper(application, args);\n\t\tthis.bootstrapContext = bootstrapContext;\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * Return the bootstrap context.\n\t * @return the bootstrap context\n\t * @since 2.4.0\n\t */\n\tpublic ConfigurableBootstrapContext getBootstrapContext() {\n\t\treturn this.bootstrapContext;\n\t}\n\n\t/**\n\t * Return the environment.\n\t * @return the environment\n\t */\n\tpublic ConfigurableEnvironment getEnvironment() {\n\t\treturn this.environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationFailedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Event published by a {@link SpringApplication} when it fails to start.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see ApplicationReadyEvent\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationFailedEvent extends SpringApplicationEvent {\n\n\tprivate final @Nullable ConfigurableApplicationContext context;\n\n\tprivate final Throwable exception;\n\n\t/**\n\t * Create a new {@link ApplicationFailedEvent} instance.\n\t * @param application the current application\n\t * @param args the arguments the application was running with\n\t * @param context the context that was being created (maybe null)\n\t * @param exception the exception that caused the error\n\t */\n\tpublic ApplicationFailedEvent(SpringApplication application, String[] args,\n\t\t\t@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\tsuper(application, args);\n\t\tthis.context = context;\n\t\tthis.exception = exception;\n\t}\n\n\t/**\n\t * Return the application context.\n\t * @return the context or {@code null}\n\t */\n\tpublic @Nullable ConfigurableApplicationContext getApplicationContext() {\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Return the exception that caused the failure.\n\t * @return the exception\n\t */\n\tpublic Throwable getException() {\n\t\treturn this.exception;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationPreparedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\n\n/**\n * Event published as when a {@link SpringApplication} is starting up and the\n * {@link ApplicationContext} is fully prepared but not refreshed. The bean definitions\n * will be loaded and the {@link Environment} is ready for use at this stage.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationPreparedEvent extends SpringApplicationEvent {\n\n\tprivate final ConfigurableApplicationContext context;\n\n\t/**\n\t * Create a new {@link ApplicationPreparedEvent} instance.\n\t * @param application the current application\n\t * @param args the arguments the application is running with\n\t * @param context the ApplicationContext about to be refreshed\n\t */\n\tpublic ApplicationPreparedEvent(SpringApplication application, String[] args,\n\t\t\tConfigurableApplicationContext context) {\n\t\tsuper(application, args);\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * Return the application context.\n\t * @return the context\n\t */\n\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\treturn this.context;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationReadyEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Event published as late as conceivably possible to indicate that the application is\n * ready to service requests. The source of the event is the {@link SpringApplication}\n * itself, but beware of modifying its internal state since all initialization steps will\n * have been completed by then.\n *\n * @author Stephane Nicoll\n * @author Chris Bono\n * @since 1.3.0\n * @see ApplicationFailedEvent\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationReadyEvent extends SpringApplicationEvent {\n\n\tprivate final ConfigurableApplicationContext context;\n\n\tprivate final @Nullable Duration timeTaken;\n\n\t/**\n\t * Create a new {@link ApplicationReadyEvent} instance.\n\t * @param application the current application\n\t * @param args the arguments the application is running with\n\t * @param context the context that was being created\n\t * @param timeTaken the time taken to get the application ready to service requests\n\t * @since 2.6.0\n\t */\n\tpublic ApplicationReadyEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context,\n\t\t\t@Nullable Duration timeTaken) {\n\t\tsuper(application, args);\n\t\tthis.context = context;\n\t\tthis.timeTaken = timeTaken;\n\t}\n\n\t/**\n\t * Return the application context.\n\t * @return the context\n\t */\n\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Return the time taken for the application to be ready to service requests, or\n\t * {@code null} if unknown.\n\t * @return the time taken to be ready to service requests\n\t * @since 2.6.0\n\t */\n\tpublic @Nullable Duration getTimeTaken() {\n\t\treturn this.timeTaken;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationStartedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Event published once the application context has been refreshed but before any\n * {@link ApplicationRunner application} and {@link CommandLineRunner command line}\n * runners have been called.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationStartedEvent extends SpringApplicationEvent {\n\n\tprivate final ConfigurableApplicationContext context;\n\n\tprivate final @Nullable Duration timeTaken;\n\n\t/**\n\t * Create a new {@link ApplicationStartedEvent} instance.\n\t * @param application the current application\n\t * @param args the arguments the application is running with\n\t * @param context the context that was being created\n\t * @param timeTaken the time taken to start the application\n\t * @since 2.6.0\n\t */\n\tpublic ApplicationStartedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context,\n\t\t\t@Nullable Duration timeTaken) {\n\t\tsuper(application, args);\n\t\tthis.context = context;\n\t\tthis.timeTaken = timeTaken;\n\t}\n\n\t/**\n\t * Return the application context.\n\t * @return the context\n\t */\n\tpublic ConfigurableApplicationContext getApplicationContext() {\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Return the time taken to start the application, or {@code null} if unknown.\n\t * @return the startup time\n\t * @since 2.6.0\n\t */\n\tpublic @Nullable Duration getTimeTaken() {\n\t\treturn this.timeTaken;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/ApplicationStartingEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.env.Environment;\n\n/**\n * Event published as early as conceivably possible as soon as a {@link SpringApplication}\n * has been started - before the {@link Environment} or {@link ApplicationContext} is\n * available, but after the {@link ApplicationListener}s have been registered. The source\n * of the event is the {@link SpringApplication} itself, but beware of using its internal\n * state too much at this early stage since it might be modified later in the lifecycle.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 1.5.0\n */\n@SuppressWarnings(\"serial\")\npublic class ApplicationStartingEvent extends SpringApplicationEvent {\n\n\tprivate final ConfigurableBootstrapContext bootstrapContext;\n\n\t/**\n\t * Create a new {@link ApplicationStartingEvent} instance.\n\t * @param bootstrapContext the bootstrap context\n\t * @param application the current application\n\t * @param args the arguments the application is running with\n\t */\n\tpublic ApplicationStartingEvent(ConfigurableBootstrapContext bootstrapContext, SpringApplication application,\n\t\t\tString[] args) {\n\t\tsuper(application, args);\n\t\tthis.bootstrapContext = bootstrapContext;\n\t}\n\n\t/**\n\t * Return the bootstrap context.\n\t * @return the bootstrap context\n\t * @since 2.4.0\n\t */\n\tpublic ConfigurableBootstrapContext getBootstrapContext() {\n\t\treturn this.bootstrapContext;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport java.time.Duration;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplicationRunListener;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.LivenessState;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.ApplicationEventMulticaster;\nimport org.springframework.context.event.SimpleApplicationEventMulticaster;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.util.ErrorHandler;\n\n/**\n * {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s.\n * <p>\n * Uses an internal {@link ApplicationEventMulticaster} for the events that are fired\n * before the context is actually refreshed.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @author Brian Clozel\n * @author Chris Bono\n */\nclass EventPublishingRunListener implements SpringApplicationRunListener, Ordered {\n\n\tprivate final SpringApplication application;\n\n\tprivate final String[] args;\n\n\tprivate final SimpleApplicationEventMulticaster initialMulticaster;\n\n\tEventPublishingRunListener(SpringApplication application, String[] args) {\n\t\tthis.application = application;\n\t\tthis.args = args;\n\t\tthis.initialMulticaster = new SimpleApplicationEventMulticaster();\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void starting(ConfigurableBootstrapContext bootstrapContext) {\n\t\tmulticastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));\n\t}\n\n\t@Override\n\tpublic void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,\n\t\t\tConfigurableEnvironment environment) {\n\t\tmulticastInitialEvent(\n\t\t\t\tnew ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));\n\t}\n\n\t@Override\n\tpublic void contextPrepared(ConfigurableApplicationContext context) {\n\t\tmulticastInitialEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));\n\t}\n\n\t@Override\n\tpublic void contextLoaded(ConfigurableApplicationContext context) {\n\t\tfor (ApplicationListener<?> listener : this.application.getListeners()) {\n\t\t\tif (listener instanceof ApplicationContextAware contextAware) {\n\t\t\t\tcontextAware.setApplicationContext(context);\n\t\t\t}\n\t\t\tcontext.addApplicationListener(listener);\n\t\t}\n\t\tmulticastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context));\n\t}\n\n\t@Override\n\tpublic void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {\n\t\tcontext.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));\n\t\tAvailabilityChangeEvent.publish(context, LivenessState.CORRECT);\n\t}\n\n\t@Override\n\tpublic void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {\n\t\tcontext.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));\n\t\tAvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);\n\t}\n\n\t@Override\n\tpublic void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\tApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);\n\t\tif (context != null && context.isActive()) {\n\t\t\t// Listeners have been registered to the application context so we should\n\t\t\t// use it at this point if we can\n\t\t\tcontext.publishEvent(event);\n\t\t}\n\t\telse {\n\t\t\t// An inactive context may not have a multicaster so we use our multicaster to\n\t\t\t// call all the context's listeners instead\n\t\t\tif (context instanceof AbstractApplicationContext abstractApplicationContext) {\n\t\t\t\tfor (ApplicationListener<?> listener : abstractApplicationContext.getApplicationListeners()) {\n\t\t\t\t\tthis.initialMulticaster.addApplicationListener(listener);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.initialMulticaster.setErrorHandler(new LoggingErrorHandler());\n\t\t\tthis.initialMulticaster.multicastEvent(event);\n\t\t}\n\t}\n\n\tprivate void multicastInitialEvent(ApplicationEvent event) {\n\t\trefreshApplicationListeners();\n\t\tthis.initialMulticaster.multicastEvent(event);\n\t}\n\n\tprivate void refreshApplicationListeners() {\n\t\tthis.application.getListeners().forEach(this.initialMulticaster::addApplicationListener);\n\t}\n\n\tprivate static final class LoggingErrorHandler implements ErrorHandler {\n\n\t\tprivate static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);\n\n\t\t@Override\n\t\tpublic void handleError(Throwable throwable) {\n\t\t\tlogger.warn(\"Error calling ApplicationEventListener\", throwable);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/SpringApplicationEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Base class for {@link ApplicationEvent} related to a {@link SpringApplication}.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@SuppressWarnings(\"serial\")\npublic abstract class SpringApplicationEvent extends ApplicationEvent {\n\n\tprivate final String[] args;\n\n\tpublic SpringApplicationEvent(SpringApplication application, String[] args) {\n\t\tsuper(application);\n\t\tthis.args = args;\n\t}\n\n\tpublic SpringApplication getSpringApplication() {\n\t\treturn (SpringApplication) getSource();\n\t}\n\n\tpublic final String[] getArgs() {\n\t\treturn this.args;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/event/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * {@link org.springframework.context.ApplicationEvent ApplicationEvents} triggered by\n * Spring Boot.\n */\n@NullMarked\npackage org.springframework.boot.context.event;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.logging;\n\nimport java.io.FileNotFoundException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.BiConsumer;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerGroup;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.GenericApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link ApplicationListener} that configures the {@link LoggingSystem}. If the\n * environment contains a {@code logging.config} property it will be used to bootstrap the\n * logging system, otherwise a default configuration is used. Regardless, logging levels\n * will be customized if the environment contains {@code logging.level.*} entries and\n * logging groups can be defined with {@code logging.group}.\n * <p>\n * Debug and trace logging for Spring, Tomcat, Jetty and Hibernate will be enabled when\n * the environment contains {@code debug} or {@code trace} properties that aren't set to\n * {@code \"false\"} (i.e. if you start your application using\n * {@literal java -jar myapp.jar [--debug | --trace]}). If you prefer to ignore these\n * properties you can set {@link #setParseArgs(boolean) parseArgs} to {@code false}.\n * <p>\n * By default, log output is only written to the console. If a log file is required, the\n * {@code logging.file.path} and {@code logging.file.name} properties can be used.\n * <p>\n * Some system properties may be set as side effects, and these can be useful if the\n * logging configuration supports placeholders (i.e. log4j or logback):\n * <ul>\n * <li>{@code LOG_FILE} is set to the value of path of the log file that should be written\n * (if any).</li>\n * <li>{@code PID} is set to the value of the current process ID if it can be determined.\n * </li>\n * </ul>\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author HaiTao Zhang\n * @since 2.0.0\n * @see LoggingSystem#get(ClassLoader)\n */\npublic class LoggingApplicationListener implements GenericApplicationListener {\n\n\tprivate static final ConfigurationPropertyName LOGGING_LEVEL = ConfigurationPropertyName.of(\"logging.level\");\n\n\tprivate static final ConfigurationPropertyName LOGGING_GROUP = ConfigurationPropertyName.of(\"logging.group\");\n\n\tprivate static final Bindable<Map<String, LogLevel>> STRING_LOGLEVEL_MAP = Bindable.mapOf(String.class,\n\t\t\tLogLevel.class);\n\n\tprivate static final Bindable<Map<String, List<String>>> STRING_STRINGS_MAP = Bindable\n\t\t.of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class).asMap());\n\n\t/**\n\t * The default order for the LoggingApplicationListener.\n\t */\n\tpublic static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20;\n\n\t/**\n\t * The name of the Spring property that contains a reference to the logging\n\t * configuration to load.\n\t */\n\tpublic static final String CONFIG_PROPERTY = \"logging.config\";\n\n\t/**\n\t * The name of the Spring property that controls the registration of a shutdown hook\n\t * to shut down the logging system when the JVM exits.\n\t * @see LoggingSystem#getShutdownHandler\n\t */\n\tpublic static final String REGISTER_SHUTDOWN_HOOK_PROPERTY = \"logging.register-shutdown-hook\";\n\n\t/**\n\t * The name of the {@link LoggingSystem} bean.\n\t */\n\tpublic static final String LOGGING_SYSTEM_BEAN_NAME = \"springBootLoggingSystem\";\n\n\t/**\n\t * The name of the {@link LogFile} bean.\n\t * @since 2.2.0\n\t */\n\tpublic static final String LOG_FILE_BEAN_NAME = \"springBootLogFile\";\n\n\t/**\n\t * The name of the {@link LoggerGroups} bean.\n\t * @since 2.2.0\n\t */\n\tpublic static final String LOGGER_GROUPS_BEAN_NAME = \"springBootLoggerGroups\";\n\n\t/**\n\t * The name of the {@link Lifecycle} bean used to handle cleanup.\n\t */\n\tprivate static final String LOGGING_LIFECYCLE_BEAN_NAME = \"springBootLoggingLifecycle\";\n\n\tprivate static final Map<String, List<String>> DEFAULT_GROUP_LOGGERS;\n\tstatic {\n\t\tMultiValueMap<String, String> loggers = new LinkedMultiValueMap<>();\n\t\tloggers.add(\"web\", \"org.springframework.core.codec\");\n\t\tloggers.add(\"web\", \"org.springframework.http\");\n\t\tloggers.add(\"web\", \"org.springframework.web\");\n\t\tloggers.add(\"web\", \"org.springframework.boot.actuate.endpoint.web\");\n\t\tloggers.add(\"web\", \"org.springframework.boot.web.servlet.ServletContextInitializerBeans\");\n\t\tloggers.add(\"sql\", \"org.springframework.jdbc.core\");\n\t\tloggers.add(\"sql\", \"org.hibernate.SQL\");\n\t\tloggers.add(\"sql\", \"org.jooq.tools.LoggerListener\");\n\t\tDEFAULT_GROUP_LOGGERS = Collections.unmodifiableMap(loggers);\n\t}\n\n\tprivate static final Map<LogLevel, List<String>> SPRING_BOOT_LOGGING_LOGGERS;\n\tstatic {\n\t\tMultiValueMap<LogLevel, String> loggers = new LinkedMultiValueMap<>();\n\t\tloggers.add(LogLevel.DEBUG, \"sql\");\n\t\tloggers.add(LogLevel.DEBUG, \"web\");\n\t\tloggers.add(LogLevel.DEBUG, \"org.springframework.boot\");\n\t\tloggers.add(LogLevel.TRACE, \"org.springframework\");\n\t\tloggers.add(LogLevel.TRACE, \"org.apache.tomcat\");\n\t\tloggers.add(LogLevel.TRACE, \"org.apache.catalina\");\n\t\tloggers.add(LogLevel.TRACE, \"org.eclipse.jetty\");\n\t\tloggers.add(LogLevel.TRACE, \"org.hibernate.tool.hbm2ddl\");\n\t\tSPRING_BOOT_LOGGING_LOGGERS = Collections.unmodifiableMap(loggers);\n\t}\n\n\tprivate static final Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,\n\t\t\tApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ContextClosedEvent.class,\n\t\t\tApplicationFailedEvent.class };\n\n\tprivate static final Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class };\n\n\tprivate static final AtomicBoolean shutdownHookRegistered = new AtomicBoolean();\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\tprivate @Nullable LoggingSystem loggingSystem;\n\n\tprivate @Nullable LogFile logFile;\n\n\tprivate @Nullable LoggerGroups loggerGroups;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\tprivate boolean parseArgs = true;\n\n\tprivate @Nullable LogLevel springBootLogging;\n\n\t@Override\n\tpublic boolean supportsEventType(ResolvableType resolvableType) {\n\t\treturn isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);\n\t}\n\n\t@Override\n\tpublic boolean supportsSourceType(@Nullable Class<?> sourceType) {\n\t\treturn isAssignableFrom(sourceType, SOURCE_TYPES);\n\t}\n\n\tprivate boolean isAssignableFrom(@Nullable Class<?> type, Class<?>... supportedTypes) {\n\t\tif (type != null) {\n\t\t\tfor (Class<?> supportedType : supportedTypes) {\n\t\t\t\tif (supportedType.isAssignableFrom(type)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\tif (event instanceof ApplicationStartingEvent startingEvent) {\n\t\t\tonApplicationStartingEvent(startingEvent);\n\t\t}\n\t\telse if (event instanceof ApplicationEnvironmentPreparedEvent environmentPreparedEvent) {\n\t\t\tonApplicationEnvironmentPreparedEvent(environmentPreparedEvent);\n\t\t}\n\t\telse if (event instanceof ApplicationPreparedEvent preparedEvent) {\n\t\t\tonApplicationPreparedEvent(preparedEvent);\n\t\t}\n\t\telse if (event instanceof ContextClosedEvent contextClosedEvent) {\n\t\t\tonContextClosedEvent(contextClosedEvent);\n\t\t}\n\t\telse if (event instanceof ApplicationFailedEvent) {\n\t\t\tonApplicationFailedEvent();\n\t\t}\n\t}\n\n\tprivate void onApplicationStartingEvent(ApplicationStartingEvent event) {\n\t\tthis.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());\n\t\tthis.loggingSystem.beforeInitialize();\n\t}\n\n\tprivate void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\tSpringApplication springApplication = event.getSpringApplication();\n\t\tif (this.loggingSystem == null) {\n\t\t\tthis.loggingSystem = LoggingSystem.get(springApplication.getClassLoader());\n\t\t}\n\t\tinitialize(event.getEnvironment(), springApplication.getClassLoader());\n\t}\n\n\tprivate void onApplicationPreparedEvent(ApplicationPreparedEvent event) {\n\t\tConfigurableApplicationContext applicationContext = event.getApplicationContext();\n\t\tConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();\n\t\tif (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {\n\t\t\tAssert.state(this.loggingSystem != null, \"loggingSystem is not set\");\n\t\t\tbeanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);\n\t\t}\n\t\tif (this.logFile != null && !beanFactory.containsBean(LOG_FILE_BEAN_NAME)) {\n\t\t\tbeanFactory.registerSingleton(LOG_FILE_BEAN_NAME, this.logFile);\n\t\t}\n\t\tif (this.loggerGroups != null && !beanFactory.containsBean(LOGGER_GROUPS_BEAN_NAME)) {\n\t\t\tbeanFactory.registerSingleton(LOGGER_GROUPS_BEAN_NAME, this.loggerGroups);\n\t\t}\n\t\tif (!beanFactory.containsBean(LOGGING_LIFECYCLE_BEAN_NAME) && applicationContext.getParent() == null) {\n\t\t\tbeanFactory.registerSingleton(LOGGING_LIFECYCLE_BEAN_NAME, new Lifecycle());\n\t\t}\n\t}\n\n\tprivate void onContextClosedEvent(ContextClosedEvent event) {\n\t\tApplicationContext applicationContext = event.getApplicationContext();\n\t\tif (applicationContext.getParent() != null || applicationContext.containsBean(LOGGING_LIFECYCLE_BEAN_NAME)) {\n\t\t\treturn;\n\t\t}\n\t\tcleanupLoggingSystem();\n\t}\n\n\tvoid cleanupLoggingSystem() {\n\t\tif (this.loggingSystem != null) {\n\t\t\tthis.loggingSystem.cleanUp();\n\t\t}\n\t}\n\n\tprivate void onApplicationFailedEvent() {\n\t\tcleanupLoggingSystem();\n\t}\n\n\t/**\n\t * Initialize the logging system according to preferences expressed through the\n\t * {@link Environment} and the classpath.\n\t * @param environment the environment\n\t * @param classLoader the classloader\n\t */\n\tprotected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {\n\t\tgetLoggingSystemProperties(environment).apply();\n\t\tthis.logFile = LogFile.get(environment);\n\t\tif (this.logFile != null) {\n\t\t\tthis.logFile.applyToSystemProperties();\n\t\t}\n\t\tthis.loggerGroups = new LoggerGroups(DEFAULT_GROUP_LOGGERS);\n\t\tinitializeEarlyLoggingLevel(environment);\n\t\tAssert.state(this.loggingSystem != null, \"loggingSystem is not set\");\n\t\tinitializeSystem(environment, this.loggingSystem, this.logFile);\n\t\tinitializeFinalLoggingLevels(environment, this.loggingSystem);\n\t\tregisterShutdownHookIfNecessary(environment, this.loggingSystem);\n\t}\n\n\tprivate LoggingSystemProperties getLoggingSystemProperties(ConfigurableEnvironment environment) {\n\t\treturn (this.loggingSystem != null) ? this.loggingSystem.getSystemProperties(environment)\n\t\t\t\t: new LoggingSystemProperties(environment);\n\t}\n\n\tprivate void initializeEarlyLoggingLevel(ConfigurableEnvironment environment) {\n\t\tif (this.parseArgs && this.springBootLogging == null) {\n\t\t\tif (isSet(environment, \"debug\")) {\n\t\t\t\tthis.springBootLogging = LogLevel.DEBUG;\n\t\t\t}\n\t\t\tif (isSet(environment, \"trace\")) {\n\t\t\t\tthis.springBootLogging = LogLevel.TRACE;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isSet(ConfigurableEnvironment environment, String property) {\n\t\tString value = environment.getProperty(property);\n\t\treturn (value != null && !value.equals(\"false\"));\n\t}\n\n\tprivate void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system,\n\t\t\t@Nullable LogFile logFile) {\n\t\tString logConfig = environment.getProperty(CONFIG_PROPERTY);\n\t\tif (StringUtils.hasLength(logConfig)) {\n\t\t\tlogConfig = logConfig.strip();\n\t\t}\n\t\ttry {\n\t\t\tLoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);\n\t\t\tif (ignoreLogConfig(logConfig)) {\n\t\t\t\tsystem.initialize(initializationContext, null, logFile);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsystem.initialize(initializationContext, logConfig, logFile);\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tThrowable exceptionToReport = ex;\n\t\t\twhile (exceptionToReport != null && !(exceptionToReport instanceof FileNotFoundException)) {\n\t\t\t\texceptionToReport = exceptionToReport.getCause();\n\t\t\t}\n\t\t\texceptionToReport = (exceptionToReport != null) ? exceptionToReport : ex;\n\t\t\t// NOTE: We can't use the logger here to report the problem\n\t\t\tSystem.err.println(\"Logging system failed to initialize using configuration from '\" + logConfig + \"'\");\n\t\t\texceptionToReport.printStackTrace(System.err);\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate boolean ignoreLogConfig(@Nullable String logConfig) {\n\t\treturn !StringUtils.hasLength(logConfig) || logConfig.startsWith(\"-D\");\n\t}\n\n\tprivate void initializeFinalLoggingLevels(ConfigurableEnvironment environment, LoggingSystem system) {\n\t\tbindLoggerGroups(environment);\n\t\tif (this.springBootLogging != null) {\n\t\t\tinitializeSpringBootLogging(system, this.springBootLogging);\n\t\t}\n\t\tsetLogLevels(system, environment);\n\t}\n\n\tprivate void bindLoggerGroups(ConfigurableEnvironment environment) {\n\t\tif (this.loggerGroups != null) {\n\t\t\tBinder binder = Binder.get(environment);\n\t\t\tbinder.bind(LOGGING_GROUP, STRING_STRINGS_MAP).ifBound(this.loggerGroups::putAll);\n\t\t}\n\t}\n\n\t/**\n\t * Initialize loggers based on the {@link #setSpringBootLogging(LogLevel)\n\t * springBootLogging} setting. By default this implementation will pick an appropriate\n\t * set of loggers to configure based on the level.\n\t * @param system the logging system\n\t * @param springBootLogging the spring boot logging level requested\n\t * @since 2.2.0\n\t */\n\tprotected void initializeSpringBootLogging(LoggingSystem system, LogLevel springBootLogging) {\n\t\tBiConsumer<String, @Nullable LogLevel> configurer = getLogLevelConfigurer(system);\n\t\tSPRING_BOOT_LOGGING_LOGGERS.getOrDefault(springBootLogging, Collections.emptyList())\n\t\t\t.forEach((name) -> configureLogLevel(name, springBootLogging, configurer));\n\t}\n\n\t/**\n\t * Set logging levels based on relevant {@link Environment} properties.\n\t * @param system the logging system\n\t * @param environment the environment\n\t * @since 2.2.0\n\t */\n\tprotected void setLogLevels(LoggingSystem system, ConfigurableEnvironment environment) {\n\t\tBiConsumer<String, @Nullable LogLevel> customizer = getLogLevelConfigurer(system);\n\t\tBinder binder = Binder.get(environment);\n\t\tMap<String, LogLevel> levels = binder.bind(LOGGING_LEVEL, STRING_LOGLEVEL_MAP).orElseGet(Collections::emptyMap);\n\t\tlevels.forEach((name, level) -> configureLogLevel(name, level, customizer));\n\t}\n\n\tprivate void configureLogLevel(String name, LogLevel level, BiConsumer<String, @Nullable LogLevel> configurer) {\n\t\tif (this.loggerGroups != null) {\n\t\t\tLoggerGroup group = this.loggerGroups.get(name);\n\t\t\tif (group != null && group.hasMembers()) {\n\t\t\t\tgroup.configureLogLevel(level, configurer);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tconfigurer.accept(name, level);\n\t}\n\n\tprivate BiConsumer<String, @Nullable LogLevel> getLogLevelConfigurer(LoggingSystem system) {\n\t\treturn (name, level) -> {\n\t\t\ttry {\n\t\t\t\tname = name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME) ? null : name;\n\t\t\t\tsystem.setLogLevel(name, level);\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\tthis.logger.error(LogMessage.format(\"Cannot set level '%s' for '%s'\", level, name));\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate void registerShutdownHookIfNecessary(Environment environment, LoggingSystem loggingSystem) {\n\t\tif (environment.getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, true)) {\n\t\t\tRunnable shutdownHandler = loggingSystem.getShutdownHandler();\n\t\t\tif (shutdownHandler != null && shutdownHookRegistered.compareAndSet(false, true)) {\n\t\t\t\tregisterShutdownHook(shutdownHandler);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid registerShutdownHook(Runnable shutdownHandler) {\n\t\tSpringApplication.getShutdownHandlers().add(shutdownHandler);\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Sets a custom logging level to be used for Spring Boot and related libraries.\n\t * @param springBootLogging the logging level\n\t */\n\tpublic void setSpringBootLogging(LogLevel springBootLogging) {\n\t\tthis.springBootLogging = springBootLogging;\n\t}\n\n\t/**\n\t * Sets if initialization arguments should be parsed for {@literal debug} and\n\t * {@literal trace} properties (usually defined from {@literal --debug} or\n\t * {@literal --trace} command line args). Defaults to {@code true}.\n\t * @param parseArgs if arguments should be parsed\n\t */\n\tpublic void setParseArgs(boolean parseArgs) {\n\t\tthis.parseArgs = parseArgs;\n\t}\n\n\tprivate final class Lifecycle implements SmartLifecycle {\n\n\t\tprivate volatile boolean running;\n\n\t\t@Override\n\t\tpublic void start() {\n\t\t\tthis.running = true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void stop() {\n\t\t\tthis.running = false;\n\t\t\tcleanupLoggingSystem();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isRunning() {\n\t\t\treturn this.running;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getPhase() {\n\t\t\t// Shutdown late and always after WebServerStartStopLifecycle\n\t\t\treturn Integer.MIN_VALUE + 1;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Logging integration with Spring's Application Context.\n */\n@NullMarked\npackage org.springframework.boot.context.logging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/metrics/buffering/BufferedStartupStep.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.metrics.buffering;\n\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.util.Assert;\n\n/**\n * {@link StartupStep} implementation to be buffered by\n * {@link BufferingApplicationStartup}. Its processing time is recorded using\n * {@link System#nanoTime()}.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass BufferedStartupStep implements StartupStep {\n\n\tprivate final String name;\n\n\tprivate final long id;\n\n\tprivate final @Nullable BufferedStartupStep parent;\n\n\tprivate final List<Tag> tags = new ArrayList<>();\n\n\tprivate final Consumer<BufferedStartupStep> recorder;\n\n\tprivate final Instant startTime;\n\n\tprivate final AtomicBoolean ended = new AtomicBoolean();\n\n\tBufferedStartupStep(@Nullable BufferedStartupStep parent, String name, long id, Instant startTime,\n\t\t\tConsumer<BufferedStartupStep> recorder) {\n\t\tthis.parent = parent;\n\t\tthis.name = name;\n\t\tthis.id = id;\n\t\tthis.startTime = startTime;\n\t\tthis.recorder = recorder;\n\t}\n\n\t@Nullable BufferedStartupStep getParent() {\n\t\treturn this.parent;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic long getId() {\n\t\treturn this.id;\n\t}\n\n\tInstant getStartTime() {\n\t\treturn this.startTime;\n\t}\n\n\t@Override\n\tpublic @Nullable Long getParentId() {\n\t\treturn (this.parent != null) ? this.parent.getId() : null;\n\t}\n\n\t@Override\n\tpublic Tags getTags() {\n\t\treturn Collections.unmodifiableList(this.tags)::iterator;\n\t}\n\n\t@Override\n\tpublic StartupStep tag(String key, Supplier<String> value) {\n\t\treturn tag(key, value.get());\n\t}\n\n\t@Override\n\tpublic StartupStep tag(String key, String value) {\n\t\tAssert.state(!this.ended.get(), \"StartupStep has already ended.\");\n\t\tthis.tags.add(new DefaultTag(key, value));\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic void end() {\n\t\tthis.ended.set(true);\n\t\tthis.recorder.accept(this);\n\t}\n\n\tboolean isEnded() {\n\t\treturn this.ended.get();\n\t}\n\n\tstatic class DefaultTag implements Tag {\n\n\t\tprivate final String key;\n\n\t\tprivate final String value;\n\n\t\tDefaultTag(String key, String value) {\n\t\t\tthis.key = key;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getKey() {\n\t\t\treturn this.key;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/metrics/buffering/BufferingApplicationStartup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.metrics.buffering;\n\nimport java.time.Clock;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.metrics.buffering.StartupTimeline.TimelineEvent;\nimport org.springframework.core.metrics.ApplicationStartup;\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ApplicationStartup} implementation that buffers {@link StartupStep steps} and\n * records their timestamp as well as their processing time.\n * <p>\n * Once recording has been {@link #startRecording() started}, steps are buffered up until\n * the configured {@link #BufferingApplicationStartup(int) capacity}; after that, new\n * steps are not recorded.\n * <p>\n * There are several ways to keep the buffer size low:\n * <ul>\n * <li>configuring {@link #addFilter(Predicate) filters} to only record steps that are\n * relevant to us.\n * <li>{@link #drainBufferedTimeline() draining} the buffered steps.\n * </ul>\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class BufferingApplicationStartup implements ApplicationStartup {\n\n\tprivate final int capacity;\n\n\tprivate final Clock clock;\n\n\tprivate Instant startTime;\n\n\tprivate final AtomicInteger idSeq = new AtomicInteger();\n\n\tprivate Predicate<StartupStep> filter = (step) -> true;\n\n\tprivate final AtomicReference<@Nullable BufferedStartupStep> current = new AtomicReference<>();\n\n\tprivate final AtomicInteger estimatedSize = new AtomicInteger();\n\n\tprivate final ConcurrentLinkedQueue<TimelineEvent> events = new ConcurrentLinkedQueue<>();\n\n\t/**\n\t * Create a new buffered {@link ApplicationStartup} with a limited capacity and starts\n\t * the recording of steps.\n\t * @param capacity the configured capacity; once reached, new steps are not recorded.\n\t */\n\tpublic BufferingApplicationStartup(int capacity) {\n\t\tthis(capacity, Clock.systemDefaultZone());\n\t}\n\n\tBufferingApplicationStartup(int capacity, Clock clock) {\n\t\tthis.capacity = capacity;\n\t\tthis.clock = clock;\n\t\tthis.startTime = clock.instant();\n\t}\n\n\t/**\n\t * Start the recording of steps and mark the beginning of the {@link StartupTimeline}.\n\t * The class constructor already implicitly calls this, but it is possible to reset it\n\t * as long as steps have not been recorded already.\n\t * @throws IllegalStateException if called and {@link StartupStep} have been recorded\n\t * already.\n\t */\n\tpublic void startRecording() {\n\t\tAssert.state(this.events.isEmpty(), \"Cannot restart recording once steps have been buffered\");\n\t\tthis.startTime = this.clock.instant();\n\t}\n\n\t/**\n\t * Add a predicate filter to the list of existing ones.\n\t * <p>\n\t * A {@link StartupStep step} that doesn't match all filters will not be recorded.\n\t * @param filter the predicate filter to add.\n\t */\n\tpublic void addFilter(Predicate<StartupStep> filter) {\n\t\tthis.filter = this.filter.and(filter);\n\t}\n\n\t@Override\n\tpublic StartupStep start(String name) {\n\t\tint id = this.idSeq.getAndIncrement();\n\t\tInstant start = this.clock.instant();\n\t\twhile (true) {\n\t\t\tBufferedStartupStep current = this.current.get();\n\t\t\tBufferedStartupStep parent = getLatestActive(current);\n\t\t\tBufferedStartupStep next = new BufferedStartupStep(parent, name, id, start, this::record);\n\t\t\tif (this.current.compareAndSet(current, next)) {\n\t\t\t\treturn next;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void record(BufferedStartupStep step) {\n\t\tif (this.filter.test(step) && this.estimatedSize.get() < this.capacity) {\n\t\t\tthis.estimatedSize.incrementAndGet();\n\t\t\tthis.events.add(new TimelineEvent(step, this.clock.instant()));\n\t\t}\n\t\twhile (true) {\n\t\t\tBufferedStartupStep current = this.current.get();\n\t\t\tBufferedStartupStep next = getLatestActive(current);\n\t\t\tif (this.current.compareAndSet(current, next)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate @Nullable BufferedStartupStep getLatestActive(@Nullable BufferedStartupStep step) {\n\t\twhile (step != null && step.isEnded()) {\n\t\t\tstep = step.getParent();\n\t\t}\n\t\treturn step;\n\t}\n\n\t/**\n\t * Return the {@link StartupTimeline timeline} as a snapshot of currently buffered\n\t * steps.\n\t * <p>\n\t * This will not remove steps from the buffer, see {@link #drainBufferedTimeline()}\n\t * for its counterpart.\n\t * @return a snapshot of currently buffered steps.\n\t */\n\tpublic StartupTimeline getBufferedTimeline() {\n\t\treturn new StartupTimeline(this.startTime, new ArrayList<>(this.events));\n\t}\n\n\t/**\n\t * Return the {@link StartupTimeline timeline} by pulling steps from the buffer.\n\t * <p>\n\t * This removes steps from the buffer, see {@link #getBufferedTimeline()} for its\n\t * read-only counterpart.\n\t * @return buffered steps drained from the buffer.\n\t */\n\tpublic StartupTimeline drainBufferedTimeline() {\n\t\tList<TimelineEvent> events = new ArrayList<>();\n\t\tIterator<TimelineEvent> iterator = this.events.iterator();\n\t\twhile (iterator.hasNext()) {\n\t\t\tevents.add(iterator.next());\n\t\t\titerator.remove();\n\t\t}\n\t\tthis.estimatedSize.set(0);\n\t\treturn new StartupTimeline(this.startTime, events);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/metrics/buffering/StartupTimeline.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.metrics.buffering;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.core.metrics.StartupStep;\n\n/**\n * Represent the timeline of {@link StartupStep steps} recorded by\n * {@link BufferingApplicationStartup}. Each {@link TimelineEvent} has a start and end\n * time as well as a duration measured with nanosecond precision.\n *\n * @author Brian Clozel\n * @since 2.4.0\n */\npublic class StartupTimeline {\n\n\tprivate final Instant startTime;\n\n\tprivate final List<TimelineEvent> events;\n\n\tStartupTimeline(Instant startTime, List<TimelineEvent> events) {\n\t\tthis.startTime = startTime;\n\t\tthis.events = Collections.unmodifiableList(events);\n\t}\n\n\t/**\n\t * Return the start time of this timeline.\n\t * @return the start time\n\t */\n\tpublic Instant getStartTime() {\n\t\treturn this.startTime;\n\t}\n\n\t/**\n\t * Return the recorded events.\n\t * @return the events\n\t */\n\tpublic List<TimelineEvent> getEvents() {\n\t\treturn this.events;\n\t}\n\n\t/**\n\t * Event on the current {@link StartupTimeline}. Each event has a start/end time, a\n\t * precise duration and the complete {@link StartupStep} information associated with\n\t * it.\n\t */\n\tpublic static class TimelineEvent {\n\n\t\tprivate final BufferedStartupStep step;\n\n\t\tprivate final Instant endTime;\n\n\t\tprivate final Duration duration;\n\n\t\tTimelineEvent(BufferedStartupStep step, Instant endTime) {\n\t\t\tthis.step = step;\n\t\t\tthis.endTime = endTime;\n\t\t\tthis.duration = Duration.between(step.getStartTime(), endTime);\n\t\t}\n\n\t\t/**\n\t\t * Return the start time of this event.\n\t\t * @return the start time\n\t\t */\n\t\tpublic Instant getStartTime() {\n\t\t\treturn this.step.getStartTime();\n\t\t}\n\n\t\t/**\n\t\t * Return the end time of this event.\n\t\t * @return the end time\n\t\t */\n\t\tpublic Instant getEndTime() {\n\t\t\treturn this.endTime;\n\t\t}\n\n\t\t/**\n\t\t * Return the duration of this event, i.e. the processing time of the associated\n\t\t * {@link StartupStep} with nanoseconds precision.\n\t\t * @return the event duration\n\t\t */\n\t\tpublic Duration getDuration() {\n\t\t\treturn this.duration;\n\t\t}\n\n\t\t/**\n\t\t * Return the {@link StartupStep} information for this event.\n\t\t * @return the step information.\n\t\t */\n\t\tpublic StartupStep getStartupStep() {\n\t\t\treturn this.step;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/metrics/buffering/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * {@link org.springframework.core.metrics.ApplicationStartup} implementation for\n * buffering steps and measuring their processing time.\n */\n@NullMarked\npackage org.springframework.boot.context.metrics.buffering;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to Spring's {@link org.springframework.context.ApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/BindMethodAttribute.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.AttributeAccessor;\n\n/**\n * Allows a {@link BindMethod} value to be stored and retrieved from an\n * {@link AttributeAccessor}.\n *\n * @author Phillip Webb\n */\nfinal class BindMethodAttribute {\n\n\tstatic final String NAME = BindMethod.class.getName();\n\n\tprivate BindMethodAttribute() {\n\t}\n\n\tstatic @Nullable BindMethod get(ApplicationContext applicationContext, String beanName) {\n\t\treturn (applicationContext instanceof ConfigurableApplicationContext configurableApplicationContext)\n\t\t\t\t? get(configurableApplicationContext.getBeanFactory(), beanName) : null;\n\t}\n\n\tstatic @Nullable BindMethod get(ConfigurableListableBeanFactory beanFactory, String beanName) {\n\t\treturn (!beanFactory.containsBeanDefinition(beanName)) ? null : get(beanFactory.getBeanDefinition(beanName));\n\t}\n\n\tstatic @Nullable BindMethod get(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) {\n\t\treturn (!beanDefinitionRegistry.containsBeanDefinition(beanName)) ? null\n\t\t\t\t: get(beanDefinitionRegistry.getBeanDefinition(beanName));\n\t}\n\n\tstatic @Nullable BindMethod get(AttributeAccessor attributes) {\n\t\treturn (BindMethod) attributes.getAttribute(NAME);\n\t}\n\n\tstatic void set(AttributeAccessor attributes, BindMethod bindMethod) {\n\t\tattributes.setAttribute(NAME, bindMethod);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/BoundConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.Assert;\n\n/**\n * Bean to record and provide bound\n * {@link ConfigurationProperties @ConfigurationProperties}.\n *\n * @author Madhura Bhave\n * @since 2.3.0\n */\npublic class BoundConfigurationProperties {\n\n\tprivate final Map<ConfigurationPropertyName, ConfigurationProperty> properties = new LinkedHashMap<>();\n\n\t/**\n\t * The bean name that this class is registered with.\n\t */\n\tprivate static final String BEAN_NAME = BoundConfigurationProperties.class.getName();\n\n\tvoid add(ConfigurationProperty configurationProperty) {\n\t\tthis.properties.put(configurationProperty.getName(), configurationProperty);\n\t}\n\n\t/**\n\t * Get the configuration property bound to the given name.\n\t * @param name the property name\n\t * @return the bound property or {@code null}\n\t */\n\tpublic @Nullable ConfigurationProperty get(ConfigurationPropertyName name) {\n\t\treturn this.properties.get(name);\n\t}\n\n\t/**\n\t * Get all bound properties.\n\t * @return a map of all bound properties\n\t */\n\tpublic Map<ConfigurationPropertyName, ConfigurationProperty> getAll() {\n\t\treturn Collections.unmodifiableMap(this.properties);\n\t}\n\n\t/**\n\t * Return the {@link BoundConfigurationProperties} from the given\n\t * {@link ApplicationContext} if it is available.\n\t * @param context the context to search\n\t * @return a {@link BoundConfigurationProperties} or {@code null}\n\t */\n\tpublic static @Nullable BoundConfigurationProperties get(ApplicationContext context) {\n\t\treturn (!context.containsBeanDefinition(BEAN_NAME)) ? null\n\t\t\t\t: context.getBean(BEAN_NAME, BoundConfigurationProperties.class);\n\t}\n\n\tstatic void register(BeanDefinitionRegistry registry) {\n\t\tAssert.notNull(registry, \"'registry' must not be null\");\n\t\tif (!registry.containsBeanDefinition(BEAN_NAME)) {\n\t\t\tBeanDefinition definition = BeanDefinitionBuilder.rootBeanDefinition(BoundConfigurationProperties.class)\n\t\t\t\t.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t\t\t\t.getBeanDefinition();\n\t\t\tregistry.registerBeanDefinition(BEAN_NAME, definition);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Indexed;\n\n/**\n * Annotation for externalized configuration. Add this to a class definition or a\n * {@code @Bean} method in a {@code @Configuration} class if you want to bind and validate\n * some external Properties (e.g. from a .properties file).\n * <p>\n * Binding is either performed by calling setters on the annotated class or, if\n * {@link ConstructorBinding @ConstructorBinding} is in use, by binding to the constructor\n * parameters.\n * <p>\n * Note that contrary to {@code @Value}, SpEL expressions are not evaluated since property\n * values are externalized.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see ConfigurationPropertiesScan\n * @see ConstructorBinding\n * @see ConfigurationPropertiesBindingPostProcessor\n * @see EnableConfigurationProperties\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Indexed\npublic @interface ConfigurationProperties {\n\n\t/**\n\t * The prefix of the properties that are valid to bind to this object. Synonym for\n\t * {@link #prefix()}. A valid prefix is defined by one or more words separated with\n\t * dots (e.g. {@code \"acme.system.feature\"}).\n\t * @return the prefix of the properties to bind\n\t */\n\t@AliasFor(\"prefix\")\n\tString value() default \"\";\n\n\t/**\n\t * The prefix of the properties that are valid to bind to this object. Synonym for\n\t * {@link #value()}. A valid prefix is defined by one or more words separated with\n\t * dots (e.g. {@code \"acme.system.feature\"}).\n\t * @return the prefix of the properties to bind\n\t */\n\t@AliasFor(\"value\")\n\tString prefix() default \"\";\n\n\t/**\n\t * Flag to indicate that when binding to this object invalid fields should be ignored.\n\t * Invalid means invalid according to the binder that is used, and usually this means\n\t * fields of the wrong type (or that cannot be coerced into the correct type).\n\t * @return the flag value (default false)\n\t */\n\tboolean ignoreInvalidFields() default false;\n\n\t/**\n\t * Flag to indicate that when binding to this object unknown fields should be ignored.\n\t * An unknown field could be a sign of a mistake in the Properties.\n\t * @return the flag value (default true)\n\t */\n\tboolean ignoreUnknownFields() default true;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.context.properties.bind.BindConstructorProvider;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.annotation.Validated;\n\n/**\n * Provides access to {@link ConfigurationProperties @ConfigurationProperties} bean\n * details, regardless of if the annotation was used directly or on a {@link Bean @Bean}\n * factory method. This class can be used to access {@link #getAll(ApplicationContext)\n * all} configuration properties beans in an ApplicationContext, or\n * {@link #get(ApplicationContext, Object, String) individual beans} on a case-by-case\n * basis (for example, in a {@link BeanPostProcessor}).\n *\n * @author Phillip Webb\n * @since 2.2.0\n * @see #getAll(ApplicationContext)\n * @see #get(ApplicationContext, Object, String)\n */\npublic final class ConfigurationPropertiesBean {\n\n\tprivate static final org.springframework.boot.context.properties.bind.BindMethod JAVA_BEAN_BIND_METHOD = //\n\t\t\torg.springframework.boot.context.properties.bind.BindMethod.JAVA_BEAN;\n\n\tprivate static final org.springframework.boot.context.properties.bind.BindMethod VALUE_OBJECT_BIND_METHOD = //\n\t\t\torg.springframework.boot.context.properties.bind.BindMethod.VALUE_OBJECT;\n\n\tprivate final String name;\n\n\tprivate final @Nullable Object instance;\n\n\tprivate final Bindable<?> bindTarget;\n\n\tprivate ConfigurationPropertiesBean(String name, @Nullable Object instance, Bindable<?> bindTarget) {\n\t\tthis.name = name;\n\t\tthis.instance = instance;\n\t\tthis.bindTarget = bindTarget;\n\t}\n\n\t/**\n\t * Return the name of the Spring bean.\n\t * @return the bean name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the actual Spring bean instance.\n\t * @return the bean instance\n\t */\n\tpublic @Nullable Object getInstance() {\n\t\treturn this.instance;\n\t}\n\n\t/**\n\t * Return the bean type.\n\t * @return the bean type\n\t */\n\tClass<?> getType() {\n\t\tClass<?> resolved = this.bindTarget.getType().resolve();\n\t\tAssert.state(resolved != null, \"'resolved' must not be null\");\n\t\treturn resolved;\n\t}\n\n\t/**\n\t * Return the {@link ConfigurationProperties} annotation for the bean. The annotation\n\t * may be defined on the bean itself or from the factory method that create the bean\n\t * (usually a {@link Bean @Bean} method).\n\t * @return the configuration properties annotation\n\t */\n\tpublic ConfigurationProperties getAnnotation() {\n\t\tConfigurationProperties annotation = this.bindTarget.getAnnotation(ConfigurationProperties.class);\n\t\tAssert.state(annotation != null, \"'annotation' must not be null\");\n\t\treturn annotation;\n\t}\n\n\t/**\n\t * Return a {@link Bindable} instance suitable that can be used as a target for the\n\t * {@link Binder}.\n\t * @return a bind target for use with the {@link Binder}\n\t */\n\tpublic Bindable<?> asBindTarget() {\n\t\treturn this.bindTarget;\n\t}\n\n\t/**\n\t * Return all {@link ConfigurationProperties @ConfigurationProperties} beans contained\n\t * in the given application context. Both directly annotated beans, as well as beans\n\t * that have {@link ConfigurationProperties @ConfigurationProperties} annotated\n\t * factory methods are included.\n\t * @param applicationContext the source application context\n\t * @return a map of all configuration properties beans keyed by the bean name\n\t */\n\tpublic static Map<String, ConfigurationPropertiesBean> getAll(ApplicationContext applicationContext) {\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tif (applicationContext instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\treturn getAll(configurableContext);\n\t\t}\n\t\tMap<String, ConfigurationPropertiesBean> propertiesBeans = new LinkedHashMap<>();\n\t\tapplicationContext.getBeansWithAnnotation(ConfigurationProperties.class).forEach((name, instance) -> {\n\t\t\tConfigurationPropertiesBean propertiesBean = get(applicationContext, instance, name);\n\t\t\tif (propertiesBean != null) {\n\t\t\t\tpropertiesBeans.put(name, propertiesBean);\n\t\t\t}\n\t\t});\n\t\treturn propertiesBeans;\n\t}\n\n\tprivate static Map<String, ConfigurationPropertiesBean> getAll(ConfigurableApplicationContext applicationContext) {\n\t\tMap<String, ConfigurationPropertiesBean> propertiesBeans = new LinkedHashMap<>();\n\t\tConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();\n\t\tIterator<String> beanNames = beanFactory.getBeanNamesIterator();\n\t\twhile (beanNames.hasNext()) {\n\t\t\tString beanName = beanNames.next();\n\t\t\tif (isConfigurationPropertiesBean(beanFactory, beanName)) {\n\t\t\t\ttry {\n\t\t\t\t\tObject bean = beanFactory.getBean(beanName);\n\t\t\t\t\tConfigurationPropertiesBean propertiesBean = get(applicationContext, bean, beanName);\n\t\t\t\t\tif (propertiesBean != null) {\n\t\t\t\t\t\tpropertiesBeans.put(beanName, propertiesBean);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn propertiesBeans;\n\t}\n\n\tprivate static boolean isConfigurationPropertiesBean(ConfigurableListableBeanFactory beanFactory, String beanName) {\n\t\ttry {\n\t\t\tif (beanFactory.getBeanDefinition(beanName).isAbstract()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (beanFactory.findAnnotationOnBean(beanName, ConfigurationProperties.class) != null) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tMethod factoryMethod = findFactoryMethod(beanFactory, beanName);\n\t\t\treturn findMergedAnnotation(factoryMethod, ConfigurationProperties.class).isPresent();\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Return a {@link ConfigurationPropertiesBean @ConfigurationPropertiesBean} instance\n\t * for the given bean details or {@code null} if the bean is not a\n\t * {@link ConfigurationProperties @ConfigurationProperties} object. Annotations are\n\t * considered both on the bean itself, as well as any factory method (for example a\n\t * {@link Bean @Bean} method).\n\t * @param applicationContext the source application context\n\t * @param bean the bean to consider\n\t * @param beanName the bean name\n\t * @return a configuration properties bean or {@code null} if the neither the bean nor\n\t * factory method are annotated with\n\t * {@link ConfigurationProperties @ConfigurationProperties}\n\t */\n\tpublic static @Nullable ConfigurationPropertiesBean get(ApplicationContext applicationContext, Object bean,\n\t\t\tString beanName) {\n\t\tMethod factoryMethod = findFactoryMethod(applicationContext, beanName);\n\t\tBindable<Object> bindTarget = createBindTarget(bean, bean.getClass(), factoryMethod);\n\t\tif (bindTarget == null) {\n\t\t\treturn null;\n\t\t}\n\t\tbindTarget = bindTarget.withBindMethod(BindMethodAttribute.get(applicationContext, beanName));\n\t\tif (bindTarget.getBindMethod() == null && factoryMethod != null) {\n\t\t\tbindTarget = bindTarget.withBindMethod(JAVA_BEAN_BIND_METHOD);\n\t\t}\n\t\tif (bindTarget.getBindMethod() != VALUE_OBJECT_BIND_METHOD) {\n\t\t\tbindTarget = bindTarget.withExistingValue(bean);\n\t\t}\n\t\treturn create(beanName, bean, bindTarget);\n\t}\n\n\tprivate static @Nullable Method findFactoryMethod(ApplicationContext applicationContext, String beanName) {\n\t\tif (applicationContext instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\treturn findFactoryMethod(configurableContext, beanName);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static @Nullable Method findFactoryMethod(ConfigurableApplicationContext applicationContext,\n\t\t\tString beanName) {\n\t\treturn findFactoryMethod(applicationContext.getBeanFactory(), beanName);\n\t}\n\n\tprivate static @Nullable Method findFactoryMethod(ConfigurableListableBeanFactory beanFactory, String beanName) {\n\t\tif (beanFactory.containsBeanDefinition(beanName)) {\n\t\t\tBeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);\n\t\t\tif (beanDefinition instanceof RootBeanDefinition rootBeanDefinition) {\n\t\t\t\treturn rootBeanDefinition.getResolvedFactoryMethod();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic ConfigurationPropertiesBean forValueObject(Class<?> beanType, String beanName) {\n\t\tBindable<Object> bindTarget = createBindTarget(null, beanType, null);\n\t\tAssert.state(bindTarget != null && deduceBindMethod(bindTarget) == VALUE_OBJECT_BIND_METHOD,\n\t\t\t\t() -> \"Bean '\" + beanName + \"' is not a @ConfigurationProperties value object\");\n\t\treturn create(beanName, null, bindTarget.withBindMethod(VALUE_OBJECT_BIND_METHOD));\n\t}\n\n\tprivate static @Nullable Bindable<Object> createBindTarget(@Nullable Object bean, Class<?> beanType,\n\t\t\t@Nullable Method factoryMethod) {\n\t\tResolvableType type = (factoryMethod != null) ? ResolvableType.forMethodReturnType(factoryMethod)\n\t\t\t\t: ResolvableType.forClass(beanType);\n\t\tAnnotation[] annotations = findAnnotations(bean, beanType, factoryMethod);\n\t\treturn (annotations != null) ? Bindable.of(type).withAnnotations(annotations) : null;\n\t}\n\n\tprivate static Annotation @Nullable [] findAnnotations(@Nullable Object instance, Class<?> type,\n\t\t\t@Nullable Method factory) {\n\t\tConfigurationProperties annotation = findAnnotation(instance, type, factory, ConfigurationProperties.class);\n\t\tif (annotation == null) {\n\t\t\treturn null;\n\t\t}\n\t\tValidated validated = findAnnotation(instance, type, factory, Validated.class);\n\t\treturn (validated != null) ? new Annotation[] { annotation, validated } : new Annotation[] { annotation };\n\t}\n\n\tprivate static <A extends Annotation> @Nullable A findAnnotation(@Nullable Object instance, Class<?> type,\n\t\t\t@Nullable Method factory, Class<A> annotationType) {\n\t\tMergedAnnotation<A> annotation = MergedAnnotation.missing();\n\t\tif (factory != null) {\n\t\t\tannotation = findMergedAnnotation(factory, annotationType);\n\t\t}\n\t\tif (!annotation.isPresent()) {\n\t\t\tannotation = findMergedAnnotation(type, annotationType);\n\t\t}\n\t\tif (!annotation.isPresent() && AopUtils.isAopProxy(instance)) {\n\t\t\tannotation = MergedAnnotations.from(AopUtils.getTargetClass(instance), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.get(annotationType);\n\t\t}\n\t\treturn annotation.isPresent() ? annotation.synthesize() : null;\n\t}\n\n\tprivate static <A extends Annotation> MergedAnnotation<A> findMergedAnnotation(@Nullable AnnotatedElement element,\n\t\t\tClass<A> annotationType) {\n\t\treturn (element != null) ? MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY).get(annotationType)\n\t\t\t\t: MergedAnnotation.missing();\n\t}\n\n\t@Contract(\"_, _, !null -> !null\")\n\tprivate static @Nullable ConfigurationPropertiesBean create(String name, @Nullable Object instance,\n\t\t\t@Nullable Bindable<Object> bindTarget) {\n\t\treturn (bindTarget != null) ? new ConfigurationPropertiesBean(name, instance, bindTarget) : null;\n\t}\n\n\t/**\n\t * Deduce the {@code BindMethod} that should be used for the given type.\n\t * @param type the source type\n\t * @return the bind method to use\n\t */\n\tstatic org.springframework.boot.context.properties.bind.BindMethod deduceBindMethod(Class<?> type) {\n\t\treturn deduceBindMethod(BindConstructorProvider.DEFAULT.getBindConstructor(type, false));\n\t}\n\n\t/**\n\t * Deduce the {@code BindMethod} that should be used for the given {@link Bindable}.\n\t * @param bindable the source bindable\n\t * @return the bind method to use\n\t */\n\tstatic org.springframework.boot.context.properties.bind.BindMethod deduceBindMethod(Bindable<Object> bindable) {\n\t\treturn deduceBindMethod(BindConstructorProvider.DEFAULT.getBindConstructor(bindable, false));\n\t}\n\n\tprivate static org.springframework.boot.context.properties.bind.BindMethod deduceBindMethod(\n\t\t\t@Nullable Constructor<?> bindConstructor) {\n\t\treturn (bindConstructor != null) ? VALUE_OBJECT_BIND_METHOD : JAVA_BEAN_BIND_METHOD;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link BeanFactoryInitializationAotProcessor} that contributes runtime hints for\n * configuration properties-annotated beans.\n *\n * @author Stephane Nicoll\n * @author Christoph Strobl\n * @author Sebastien Deleuze\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor {\n\n\t@Override\n\tpublic @Nullable ConfigurationPropertiesReflectionHintsContribution processAheadOfTime(\n\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\tString[] beanNames = beanFactory.getBeanNamesForAnnotation(ConfigurationProperties.class);\n\t\tList<Bindable<?>> bindables = new ArrayList<>();\n\t\tfor (String beanName : beanNames) {\n\t\t\tClass<?> beanType = beanFactory.getType(beanName, false);\n\t\t\tif (beanType != null) {\n\t\t\t\tBindMethod bindMethod = beanFactory.containsBeanDefinition(beanName)\n\t\t\t\t\t\t? (BindMethod) beanFactory.getBeanDefinition(beanName).getAttribute(BindMethod.class.getName())\n\t\t\t\t\t\t: null;\n\t\t\t\tbindables.add(Bindable.of(ClassUtils.getUserClass(beanType))\n\t\t\t\t\t.withBindMethod((bindMethod != null) ? bindMethod : BindMethod.JAVA_BEAN));\n\t\t\t}\n\t\t}\n\t\treturn (!bindables.isEmpty()) ? new ConfigurationPropertiesReflectionHintsContribution(bindables) : null;\n\t}\n\n\tstatic final class ConfigurationPropertiesReflectionHintsContribution\n\t\t\timplements BeanFactoryInitializationAotContribution {\n\n\t\tprivate final List<Bindable<?>> bindables;\n\n\t\tprivate ConfigurationPropertiesReflectionHintsContribution(List<Bindable<?>> bindables) {\n\t\t\tthis.bindables = bindables;\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\tBindableRuntimeHintsRegistrar.forBindables(this.bindables)\n\t\t\t\t.registerHints(generationContext.getRuntimeHints());\n\t\t}\n\n\t\tIterable<Bindable<?>> getBindables() {\n\t\t\treturn this.bindables;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.support.BeanDefinitionReaderUtils;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.AnnotationScopeMetadataResolver;\nimport org.springframework.context.annotation.ScopeMetadata;\nimport org.springframework.context.annotation.ScopeMetadataResolver;\nimport org.springframework.context.annotation.ScopedProxyMode;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Delegate used by {@link EnableConfigurationPropertiesRegistrar} and\n * {@link ConfigurationPropertiesScanRegistrar} to register a bean definition for a\n * {@link ConfigurationProperties @ConfigurationProperties} class.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nfinal class ConfigurationPropertiesBeanRegistrar {\n\n\tprivate static final ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();\n\n\tprivate final BeanDefinitionRegistry registry;\n\n\tprivate final BeanFactory beanFactory;\n\n\tConfigurationPropertiesBeanRegistrar(BeanDefinitionRegistry registry) {\n\t\tthis.registry = registry;\n\t\tthis.beanFactory = (BeanFactory) this.registry;\n\t}\n\n\tvoid register(Class<?> type) {\n\t\tMergedAnnotation<ConfigurationProperties> annotation = MergedAnnotations\n\t\t\t.from(type, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(ConfigurationProperties.class);\n\t\tregister(type, annotation);\n\t}\n\n\tvoid register(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {\n\t\tString name = getName(type, annotation);\n\t\tif (!containsBeanDefinition(name)) {\n\t\t\tregisterBeanDefinition(name, type, annotation);\n\t\t}\n\t}\n\n\tprivate String getName(Class<?> type, MergedAnnotation<ConfigurationProperties> annotation) {\n\t\tString prefix = annotation.isPresent() ? annotation.getString(\"prefix\") : \"\";\n\t\treturn (StringUtils.hasText(prefix) ? prefix + \"-\" + type.getName() : type.getName());\n\t}\n\n\tprivate boolean containsBeanDefinition(String name) {\n\t\treturn (this.beanFactory instanceof ListableBeanFactory listableBeanFactory\n\t\t\t\t&& listableBeanFactory.containsBeanDefinition(name));\n\t}\n\n\tprivate void registerBeanDefinition(String beanName, Class<?> type,\n\t\t\tMergedAnnotation<ConfigurationProperties> annotation) {\n\t\tAssert.state(annotation.isPresent(), () -> \"No \" + ConfigurationProperties.class.getSimpleName()\n\t\t\t\t+ \" annotation found on  '\" + type.getName() + \"'.\");\n\t\ttry {\n\t\t\tBeanDefinitionHolder beanDefinition = createBeanDefinition(beanName, type);\n\t\t\tBeanDefinitionReaderUtils.registerBeanDefinition(beanDefinition, this.registry);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to create configuration properties bean definition '%s' (%s)\".formatted(beanName, type),\n\t\t\t\t\tex);\n\t\t}\n\t}\n\n\tprivate BeanDefinitionHolder createBeanDefinition(String beanName, Class<?> type) {\n\t\tAnnotatedGenericBeanDefinition definition = new AnnotatedGenericBeanDefinition(type);\n\t\tAnnotationConfigUtils.processCommonDefinitionAnnotations(definition);\n\t\tBindMethod bindMethod = ConfigurationPropertiesBean.deduceBindMethod(type);\n\t\tBindMethodAttribute.set(definition, bindMethod);\n\t\tif (bindMethod == BindMethod.VALUE_OBJECT) {\n\t\t\tdefinition.setInstanceSupplier(() -> ConstructorBound.from(this.beanFactory, beanName, type));\n\t\t}\n\t\tScopeMetadata metadata = scopeMetadataResolver.resolveScopeMetadata(definition);\n\t\tdefinition.setScope(metadata.getScopeName());\n\t\tBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(definition, beanName);\n\t\treturn applyScopedProxyMode(metadata, definitionHolder, this.registry);\n\t}\n\n\tstatic BeanDefinitionHolder applyScopedProxyMode(ScopeMetadata metadata, BeanDefinitionHolder definition,\n\t\t\tBeanDefinitionRegistry registry) {\n\t\tScopedProxyMode mode = metadata.getScopedProxyMode();\n\t\tif (mode != ScopedProxyMode.NO) {\n\t\t\treturn ScopedProxyUtils.createScopedProxy(definition, registry, mode == ScopedProxyMode.TARGET_CLASS);\n\t\t}\n\t\treturn definition;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.function.Predicate;\n\nimport javax.lang.model.element.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GeneratedMethod;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.InstanceSupplier;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.javapoet.CodeBlock;\n\n/**\n * {@link BeanRegistrationAotProcessor} for immutable configuration properties.\n *\n * @author Stephane Nicoll\n * @see ConstructorBound\n */\nclass ConfigurationPropertiesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {\n\n\t@Override\n\tpublic @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n\t\tif (!isImmutableConfigurationPropertiesBeanDefinition(registeredBean.getMergedBeanDefinition())) {\n\t\t\treturn null;\n\t\t}\n\t\treturn BeanRegistrationAotContribution.withCustomCodeFragments(\n\t\t\t\t(codeFragments) -> new ConfigurationPropertiesBeanRegistrationCodeFragments(codeFragments,\n\t\t\t\t\t\tregisteredBean));\n\n\t}\n\n\tprivate boolean isImmutableConfigurationPropertiesBeanDefinition(BeanDefinition beanDefinition) {\n\t\treturn BindMethod.VALUE_OBJECT.equals(BindMethodAttribute.get(beanDefinition));\n\t}\n\n\tprivate static class ConfigurationPropertiesBeanRegistrationCodeFragments\n\t\t\textends BeanRegistrationCodeFragmentsDecorator {\n\n\t\tprivate static final String REGISTERED_BEAN_PARAMETER_NAME = \"registeredBean\";\n\n\t\tprivate final RegisteredBean registeredBean;\n\n\t\tConfigurationPropertiesBeanRegistrationCodeFragments(BeanRegistrationCodeFragments codeFragments,\n\t\t\t\tRegisteredBean registeredBean) {\n\t\t\tsuper(codeFragments);\n\t\t\tthis.registeredBean = registeredBean;\n\t\t}\n\n\t\t@Override\n\t\tpublic CodeBlock generateSetBeanDefinitionPropertiesCode(GenerationContext generationContext,\n\t\t\t\tBeanRegistrationCode beanRegistrationCode, RootBeanDefinition beanDefinition,\n\t\t\t\tPredicate<String> attributeFilter) {\n\t\t\treturn super.generateSetBeanDefinitionPropertiesCode(generationContext, beanRegistrationCode,\n\t\t\t\t\tbeanDefinition, attributeFilter.or(BindMethodAttribute.NAME::equals));\n\t\t}\n\n\t\t@Override\n\t\tpublic ClassName getTarget(RegisteredBean registeredBean) {\n\t\t\treturn ClassName.get(this.registeredBean.getBeanClass());\n\t\t}\n\n\t\t@Override\n\t\tpublic CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,\n\t\t\t\tBeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {\n\t\t\tGeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add(\"getInstance\", (method) -> {\n\t\t\t\tClass<?> beanClass = this.registeredBean.getBeanClass();\n\t\t\t\tmethod.addJavadoc(\"Get the bean instance for '$L'.\", this.registeredBean.getBeanName())\n\t\t\t\t\t.addModifiers(Modifier.PRIVATE, Modifier.STATIC)\n\t\t\t\t\t.returns(beanClass)\n\t\t\t\t\t.addParameter(RegisteredBean.class, REGISTERED_BEAN_PARAMETER_NAME)\n\t\t\t\t\t.addStatement(\"$T beanFactory = registeredBean.getBeanFactory()\", BeanFactory.class)\n\t\t\t\t\t.addStatement(\"$T beanName = registeredBean.getBeanName()\", String.class)\n\t\t\t\t\t.addStatement(\"$T<?> beanClass = registeredBean.getBeanClass()\", Class.class)\n\t\t\t\t\t.addStatement(\"return ($T) $T.from(beanFactory, beanName, beanClass)\", beanClass,\n\t\t\t\t\t\t\tConstructorBound.class);\n\t\t\t});\n\t\t\treturn CodeBlock.of(\"$T.of($T::$L)\", InstanceSupplier.class, beanRegistrationCode.getClassName(),\n\t\t\t\t\tgeneratedMethod.getName());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Exception thrown when {@link ConfigurationProperties @ConfigurationProperties} binding\n * fails.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class ConfigurationPropertiesBindException extends BeanCreationException {\n\n\tprivate final ConfigurationPropertiesBean bean;\n\n\tConfigurationPropertiesBindException(ConfigurationPropertiesBean bean, Exception cause) {\n\t\tsuper(bean.getName(), getMessage(bean), cause);\n\t\tthis.bean = bean;\n\t}\n\n\t/**\n\t * Return the bean type that was being bound.\n\t * @return the bean type\n\t */\n\tpublic Class<?> getBeanType() {\n\t\treturn this.bean.getType();\n\t}\n\n\t/**\n\t * Return the configuration properties annotation that triggered the binding.\n\t * @return the configuration properties annotation\n\t */\n\tpublic ConfigurationProperties getAnnotation() {\n\t\treturn this.bean.getAnnotation();\n\t}\n\n\tprivate static String getMessage(ConfigurationPropertiesBean bean) {\n\t\tConfigurationProperties annotation = bean.getAnnotation();\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\"Could not bind properties to '\");\n\t\tmessage.append(ClassUtils.getShortName(bean.getType())).append(\"' : \");\n\t\tmessage.append(\"prefix=\").append(annotation.prefix());\n\t\tmessage.append(\", ignoreInvalidFields=\").append(annotation.ignoreInvalidFields());\n\t\tmessage.append(\", ignoreUnknownFields=\").append(annotation.ignoreUnknownFields());\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindHandlerAdvisor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindHandler;\n\n/**\n * Allows additional functionality to be applied to the {@link BindHandler} used by the\n * {@link ConfigurationPropertiesBindingPostProcessor}.\n *\n * @author Phillip Webb\n * @since 2.1.0\n * @see AbstractBindHandler\n */\n@FunctionalInterface\npublic interface ConfigurationPropertiesBindHandlerAdvisor {\n\n\t/**\n\t * Apply additional functionality to the source bind handler.\n\t * @param bindHandler the source bind handler\n\t * @return a replacement bind handler that delegates to the source and provides\n\t * additional functionality\n\t */\n\tBindHandler apply(BindHandler bindHandler);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.PropertyEditorRegistry;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Bindable.BindRestriction;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.BoundPropertiesTrackingBindHandler;\nimport org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;\nimport org.springframework.boot.context.properties.bind.handler.IgnoreErrorsBindHandler;\nimport org.springframework.boot.context.properties.bind.handler.IgnoreTopLevelConverterNotFoundBindHandler;\nimport org.springframework.boot.context.properties.bind.handler.NoUnboundElementsBindHandler;\nimport org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.UnboundElementsSourceFilter;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.annotation.Validated;\n\n/**\n * Internal class used by the {@link ConfigurationPropertiesBindingPostProcessor} to\n * handle the actual {@link ConfigurationProperties @ConfigurationProperties} binding.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ConfigurationPropertiesBinder {\n\n\tprivate static final String BEAN_NAME = \"org.springframework.boot.context.internalConfigurationPropertiesBinder\";\n\n\tprivate static final String VALIDATOR_BEAN_NAME = EnableConfigurationProperties.VALIDATOR_BEAN_NAME;\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final PropertySources propertySources;\n\n\tprivate final @Nullable Validator configurationPropertiesValidator;\n\n\tprivate final boolean jsr303Present;\n\n\tprivate volatile @Nullable List<ConfigurationPropertiesBindHandlerAdvisor> bindHandlerAdvisors;\n\n\tprivate volatile @Nullable Binder binder;\n\n\tConfigurationPropertiesBinder(ApplicationContext applicationContext) {\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.propertySources = new PropertySourcesDeducer(applicationContext).getPropertySources();\n\t\tthis.configurationPropertiesValidator = getConfigurationPropertiesValidator(applicationContext);\n\t\tthis.jsr303Present = ConfigurationPropertiesJsr303Validator.isJsr303Present(applicationContext);\n\t}\n\n\tBindResult<?> bind(ConfigurationPropertiesBean propertiesBean) {\n\t\tBindable<?> target = propertiesBean.asBindTarget();\n\t\tConfigurationProperties annotation = propertiesBean.getAnnotation();\n\t\tBindHandler bindHandler = getBindHandler(target, annotation);\n\t\treturn getBinder().bind(annotation.prefix(), target, bindHandler);\n\t}\n\n\tObject bindOrCreate(ConfigurationPropertiesBean propertiesBean) {\n\t\tBindable<?> target = propertiesBean.asBindTarget();\n\t\tConfigurationProperties annotation = propertiesBean.getAnnotation();\n\t\tBindHandler bindHandler = getBindHandler(target, annotation);\n\t\treturn getBinder().bindOrCreate(annotation.prefix(), target, bindHandler);\n\t}\n\n\tprivate @Nullable Validator getConfigurationPropertiesValidator(ApplicationContext applicationContext) {\n\t\tif (applicationContext.containsBean(VALIDATOR_BEAN_NAME)) {\n\t\t\treturn applicationContext.getBean(VALIDATOR_BEAN_NAME, Validator.class);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate <T> BindHandler getBindHandler(Bindable<T> target, ConfigurationProperties annotation) {\n\t\tList<Validator> validators = getValidators(target);\n\t\tBindHandler handler = getHandler();\n\t\thandler = new ConfigurationPropertiesBindHandler(handler);\n\t\tif (annotation.ignoreInvalidFields()) {\n\t\t\thandler = new IgnoreErrorsBindHandler(handler);\n\t\t}\n\t\tif (!annotation.ignoreUnknownFields()) {\n\t\t\tUnboundElementsSourceFilter filter = new UnboundElementsSourceFilter();\n\t\t\thandler = new NoUnboundElementsBindHandler(handler, filter);\n\t\t}\n\t\tif (!validators.isEmpty()) {\n\t\t\thandler = new ValidationBindHandler(handler, validators.toArray(new Validator[0]));\n\t\t}\n\t\tfor (ConfigurationPropertiesBindHandlerAdvisor advisor : getBindHandlerAdvisors()) {\n\t\t\thandler = advisor.apply(handler);\n\t\t}\n\t\treturn handler;\n\t}\n\n\tprivate List<ConfigurationPropertiesBindHandlerAdvisor> getBindHandlerAdvisors() {\n\t\tList<ConfigurationPropertiesBindHandlerAdvisor> bindHandlerAdvisors = this.bindHandlerAdvisors;\n\t\tif (bindHandlerAdvisors == null) {\n\t\t\tbindHandlerAdvisors = this.applicationContext\n\t\t\t\t.getBeanProvider(ConfigurationPropertiesBindHandlerAdvisor.class)\n\t\t\t\t.orderedStream()\n\t\t\t\t.toList();\n\t\t\tthis.bindHandlerAdvisors = bindHandlerAdvisors;\n\t\t}\n\t\treturn bindHandlerAdvisors;\n\t}\n\n\tprivate IgnoreTopLevelConverterNotFoundBindHandler getHandler() {\n\t\tBoundConfigurationProperties bound = BoundConfigurationProperties.get(this.applicationContext);\n\t\treturn (bound != null)\n\t\t\t\t? new IgnoreTopLevelConverterNotFoundBindHandler(new BoundPropertiesTrackingBindHandler(bound::add))\n\t\t\t\t: new IgnoreTopLevelConverterNotFoundBindHandler();\n\t}\n\n\tprivate List<Validator> getValidators(Bindable<?> target) {\n\t\tList<Validator> validators = new ArrayList<>(3);\n\t\tif (this.configurationPropertiesValidator != null) {\n\t\t\tvalidators.add(this.configurationPropertiesValidator);\n\t\t}\n\t\tif (this.jsr303Present && target.getAnnotation(Validated.class) != null) {\n\t\t\tClass<?> resolved = target.getType().resolve();\n\t\t\tAssert.state(resolved != null, \"'resolved' must not be null\");\n\t\t\tvalidators.add(getJsr303Validator(resolved));\n\t\t}\n\t\tValidator selfValidator = getSelfValidator(target);\n\t\tif (selfValidator != null) {\n\t\t\tvalidators.add(selfValidator);\n\t\t}\n\t\treturn validators;\n\t}\n\n\tprivate @Nullable Validator getSelfValidator(Bindable<?> target) {\n\t\tif (target.getValue() != null) {\n\t\t\tObject value = target.getValue().get();\n\t\t\treturn (value instanceof Validator validator) ? validator : null;\n\t\t}\n\t\tClass<?> type = target.getType().resolve();\n\t\tif (type != null && Validator.class.isAssignableFrom(type)) {\n\t\t\treturn new SelfValidatingConstructorBoundBindableValidator(type);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Validator getJsr303Validator(Class<?> type) {\n\t\treturn new ConfigurationPropertiesJsr303Validator(this.applicationContext, type);\n\t}\n\n\tprivate Binder getBinder() {\n\t\tBinder binder = this.binder;\n\t\tif (binder == null) {\n\t\t\tbinder = new Binder(getConfigurationPropertySources(), getPropertySourcesPlaceholdersResolver(),\n\t\t\t\t\tgetConversionServices(), getPropertyEditorInitializer(), null, null);\n\t\t\tthis.binder = binder;\n\t\t}\n\t\treturn binder;\n\t}\n\n\tprivate Iterable<ConfigurationPropertySource> getConfigurationPropertySources() {\n\t\treturn ConfigurationPropertySources.from(this.propertySources);\n\t}\n\n\tprivate PropertySourcesPlaceholdersResolver getPropertySourcesPlaceholdersResolver() {\n\t\treturn new PropertySourcesPlaceholdersResolver(this.propertySources);\n\t}\n\n\tprivate @Nullable List<ConversionService> getConversionServices() {\n\t\treturn new ConversionServiceDeducer(this.applicationContext).getConversionServices();\n\t}\n\n\tprivate @Nullable Consumer<PropertyEditorRegistry> getPropertyEditorInitializer() {\n\t\tif (this.applicationContext instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\treturn configurableContext.getBeanFactory()::copyRegisteredEditorsTo;\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic void register(BeanDefinitionRegistry registry) {\n\t\tif (!registry.containsBeanDefinition(BEAN_NAME)) {\n\t\t\tBeanDefinition definition = BeanDefinitionBuilder\n\t\t\t\t.rootBeanDefinition(ConfigurationPropertiesBinderFactory.class)\n\t\t\t\t.getBeanDefinition();\n\t\t\tdefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\t\t\tregistry.registerBeanDefinition(BEAN_NAME, definition);\n\t\t}\n\t}\n\n\tstatic ConfigurationPropertiesBinder get(BeanFactory beanFactory) {\n\t\treturn beanFactory.getBean(BEAN_NAME, ConfigurationPropertiesBinder.class);\n\t}\n\n\t/**\n\t * {@link BindHandler} to deal with\n\t * {@link ConfigurationProperties @ConfigurationProperties} concerns.\n\t */\n\tprivate static class ConfigurationPropertiesBindHandler extends AbstractBindHandler {\n\n\t\tConfigurationPropertiesBindHandler(BindHandler handler) {\n\t\t\tsuper(handler);\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {\n\t\t\treturn isConfigurationProperties(target.getType().resolve())\n\t\t\t\t\t? target.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY) : target;\n\t\t}\n\n\t\tprivate boolean isConfigurationProperties(@Nullable Class<?> target) {\n\t\t\treturn target != null && MergedAnnotations.from(target).isPresent(ConfigurationProperties.class);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link FactoryBean} to create the {@link ConfigurationPropertiesBinder}.\n\t */\n\tstatic class ConfigurationPropertiesBinderFactory\n\t\t\timplements FactoryBean<ConfigurationPropertiesBinder>, ApplicationContextAware {\n\n\t\tprivate @Nullable ConfigurationPropertiesBinder binder;\n\n\t\t@Override\n\t\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\t\tthis.binder = (this.binder != null) ? this.binder : new ConfigurationPropertiesBinder(applicationContext);\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn ConfigurationPropertiesBinder.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurationPropertiesBinder getObject() throws Exception {\n\t\t\tAssert.state(this.binder != null, \"Binder was not created due to missing setApplicationContext call\");\n\t\t\treturn this.binder;\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@code Validator} for a constructor-bound {@code Bindable} where the type being\n\t * bound is itself a {@code Validator} implementation.\n\t */\n\tstatic class SelfValidatingConstructorBoundBindableValidator implements Validator {\n\n\t\tprivate final Class<?> type;\n\n\t\tSelfValidatingConstructorBoundBindableValidator(Class<?> type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supports(Class<?> candidate) {\n\t\t\treturn candidate.isAssignableFrom(this.type);\n\t\t}\n\n\t\t@Override\n\t\tpublic void validate(Object target, Errors errors) {\n\t\t\t((Validator) target).validate(target, errors);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBinding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Qualifier for beans that are needed to configure the binding of\n * {@link ConfigurationProperties @ConfigurationProperties} (e.g. Converters).\n * <p>\n * {@link Bean @Bean} methods that declare a {@code @ConfigurationPropertiesBinding} bean\n * should be {@code static} to ensure that \"bean is not eligible for getting processed by\n * all BeanPostProcessors\" warnings are not produced.\n *\n * @author Dave Syer\n * @since 1.3.0\n */\n@Qualifier(ConfigurationPropertiesBinding.VALUE)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface ConfigurationPropertiesBinding {\n\n\t/**\n\t * Concrete value for the {@link Qualifier @Qualifier}.\n\t */\n\tString VALUE = \"org.springframework.boot.context.properties.ConfigurationPropertiesBinding\";\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.util.Assert;\n\n/**\n * {@link BeanPostProcessor} to bind {@link PropertySources} to beans annotated with\n * {@link ConfigurationProperties @ConfigurationProperties}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Christian Dupuis\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 1.0.0\n */\npublic class ConfigurationPropertiesBindingPostProcessor\n\t\timplements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {\n\n\t/**\n\t * The bean name that this post-processor is registered with.\n\t */\n\tpublic static final String BEAN_NAME = ConfigurationPropertiesBindingPostProcessor.class.getName();\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext applicationContext;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanDefinitionRegistry registry;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigurationPropertiesBinder binder;\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\t// We can't use constructor injection of the application context because\n\t\t// it causes eager factory bean initialization\n\t\tthis.registry = (BeanDefinitionRegistry) this.applicationContext.getAutowireCapableBeanFactory();\n\t\tthis.binder = ConfigurationPropertiesBinder.get(this.applicationContext);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE + 1;\n\t}\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (!hasBoundValueObject(beanName)) {\n\t\t\tbind(ConfigurationPropertiesBean.get(this.applicationContext, bean, beanName));\n\t\t}\n\t\treturn bean;\n\t}\n\n\tprivate boolean hasBoundValueObject(String beanName) {\n\t\treturn BindMethod.VALUE_OBJECT.equals(BindMethodAttribute.get(this.registry, beanName));\n\t}\n\n\tprivate void bind(@Nullable ConfigurationPropertiesBean bean) {\n\t\tif (bean == null) {\n\t\t\treturn;\n\t\t}\n\t\tAssert.state(bean.asBindTarget().getBindMethod() != BindMethod.VALUE_OBJECT,\n\t\t\t\t\"Cannot bind @ConfigurationProperties for bean '\" + bean.getName()\n\t\t\t\t\t\t+ \"'. Ensure that @ConstructorBinding has not been applied to regular bean\");\n\t\ttry {\n\t\t\tthis.binder.bind(bean);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new ConfigurationPropertiesBindException(bean, ex);\n\t\t}\n\t}\n\n\t/**\n\t * Register a {@link ConfigurationPropertiesBindingPostProcessor} bean if one is not\n\t * already registered.\n\t * @param registry the bean definition registry\n\t * @since 2.2.0\n\t */\n\tpublic static void register(BeanDefinitionRegistry registry) {\n\t\tAssert.notNull(registry, \"'registry' must not be null\");\n\t\tif (!registry.containsBeanDefinition(BEAN_NAME)) {\n\t\t\tBeanDefinition definition = BeanDefinitionBuilder\n\t\t\t\t.rootBeanDefinition(ConfigurationPropertiesBindingPostProcessor.class)\n\t\t\t\t.getBeanDefinition();\n\t\t\tdefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\t\t\tregistry.registerBeanDefinition(BEAN_NAME, definition);\n\t\t}\n\t\tConfigurationPropertiesBinder.register(registry);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesCharSequenceToObjectConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\n\n/**\n * Copy of package-private\n * {@code org.springframework.boot.convert.CharSequenceToObjectConverter}, renamed for\n * differentiation.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nfinal class ConfigurationPropertiesCharSequenceToObjectConverter implements ConditionalGenericConverter {\n\n\tprivate static final TypeDescriptor STRING = TypeDescriptor.valueOf(String.class);\n\n\tprivate static final TypeDescriptor BYTE_ARRAY = TypeDescriptor.valueOf(byte[].class);\n\n\tprivate static final Set<ConvertiblePair> TYPES;\n\n\tprivate final ThreadLocal<Boolean> disable = new ThreadLocal<>();\n\n\tstatic {\n\t\tTYPES = Collections.singleton(new ConvertiblePair(CharSequence.class, Object.class));\n\t}\n\n\tprivate final ConversionService conversionService;\n\n\tConfigurationPropertiesCharSequenceToObjectConverter(ConversionService conversionService) {\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn TYPES;\n\t}\n\n\t@Override\n\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (sourceType.getType() == String.class || this.disable.get() == Boolean.TRUE) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.disable.set(Boolean.TRUE);\n\t\ttry {\n\t\t\tboolean canDirectlyConvertCharSequence = this.conversionService.canConvert(sourceType, targetType);\n\t\t\tif (canDirectlyConvertCharSequence && !isStringConversionBetter(sourceType, targetType)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.conversionService.canConvert(STRING, targetType);\n\t\t}\n\t\tfinally {\n\t\t\tthis.disable.remove();\n\t\t}\n\t}\n\n\t/**\n\t * Return if String based conversion is better based on the target type. This is\n\t * required when ObjectTo... conversion produces incorrect results.\n\t * @param sourceType the source type to test\n\t * @param targetType the target type to test\n\t * @return if string conversion is better\n\t */\n\tprivate boolean isStringConversionBetter(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (this.conversionService instanceof ApplicationConversionService applicationConversionService) {\n\t\t\tif (applicationConversionService.isConvertViaObjectSourceType(sourceType, targetType)) {\n\t\t\t\t// If an ObjectTo... converter is being used then there might be a\n\t\t\t\t// better StringTo... version\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t// StringToArrayConverter / StringToCollectionConverter are better than\n\t\t// ObjectToArrayConverter / ObjectToCollectionConverter\n\t\treturn (targetType.isArray() || targetType.isCollection()) && !targetType.equals(BYTE_ARRAY);\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this.conversionService.convert(source.toString(), STRING, targetType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesJsr303Validator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.boot.validation.MessageInterpolatorFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\n\n/**\n * Validator that supports configuration classes annotated with\n * {@link Validated @Validated}.\n *\n * @author Phillip Webb\n */\nfinal class ConfigurationPropertiesJsr303Validator implements Validator {\n\n\tprivate static final String[] VALIDATOR_CLASSES = { \"jakarta.validation.Validator\",\n\t\t\t\"jakarta.validation.ValidatorFactory\", \"jakarta.validation.bootstrap.GenericBootstrap\" };\n\n\tprivate final Delegate delegate;\n\n\tprivate final Class<?> validatedType;\n\n\tConfigurationPropertiesJsr303Validator(ApplicationContext applicationContext, Class<?> validatedType) {\n\t\tthis.delegate = new Delegate(applicationContext);\n\t\tthis.validatedType = validatedType;\n\t}\n\n\t@Override\n\tpublic boolean supports(Class<?> type) {\n\t\treturn this.validatedType.equals(type) && this.delegate.supports(type);\n\t}\n\n\t@Override\n\tpublic void validate(Object target, Errors errors) {\n\t\tthis.delegate.validate(target, errors);\n\t}\n\n\tstatic boolean isJsr303Present(ApplicationContext applicationContext) {\n\t\tClassLoader classLoader = applicationContext.getClassLoader();\n\t\tfor (String validatorClass : VALIDATOR_CLASSES) {\n\t\t\tif (!ClassUtils.isPresent(validatorClass, classLoader)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate static class Delegate extends LocalValidatorFactoryBean {\n\n\t\tDelegate(ApplicationContext applicationContext) {\n\t\t\tsetApplicationContext(applicationContext);\n\t\t\tsetMessageInterpolator(new MessageInterpolatorFactory(applicationContext).getObject());\n\t\t\tafterPropertiesSet();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScan.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Component;\n\n/**\n * Configures the base packages used when scanning for\n * {@link ConfigurationProperties @ConfigurationProperties} classes. One of\n * {@link #basePackageClasses()}, {@link #basePackages()} or its alias {@link #value()}\n * may be specified to define specific packages to scan. If specific packages are not\n * defined scanning will occur from the package of the class with this annotation.\n * <p>\n * Note: Classes annotated or meta-annotated with {@link Component @Component} will not be\n * picked up by this annotation.\n *\n * @author Madhura Bhave\n * @since 2.2.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(ConfigurationPropertiesScanRegistrar.class)\n@EnableConfigurationProperties\npublic @interface ConfigurationPropertiesScan {\n\n\t/**\n\t * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation\n\t * declarations e.g.: {@code @ConfigurationPropertiesScan(\"org.my.pkg\")} instead of\n\t * {@code @ConfigurationPropertiesScan(basePackages=\"org.my.pkg\")}.\n\t * @return the base packages to scan\n\t */\n\t@AliasFor(\"basePackages\")\n\tString[] value() default {};\n\n\t/**\n\t * Base packages to scan for configuration properties. {@link #value()} is an alias\n\t * for (and mutually exclusive with) this attribute.\n\t * <p>\n\t * Use {@link #basePackageClasses()} for a type-safe alternative to String-based\n\t * package names.\n\t * @return the base packages to scan\n\t */\n\t@AliasFor(\"value\")\n\tString[] basePackages() default {};\n\n\t/**\n\t * Type-safe alternative to {@link #basePackages()} for specifying the packages to\n\t * scan for configuration properties. The package of each class specified will be\n\t * scanned.\n\t * <p>\n\t * Consider creating a special no-op marker class or interface in each package that\n\t * serves no purpose other than being referenced by this attribute.\n\t * @return classes from the base packages to scan\n\t */\n\tClass<?>[] basePackageClasses() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} for registering\n * {@link ConfigurationProperties @ConfigurationProperties} bean definitions through\n * scanning.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ConfigurationPropertiesScanRegistrar implements ImportBeanDefinitionRegistrar {\n\n\tprivate final Environment environment;\n\n\tprivate final @Nullable ResourceLoader resourceLoader;\n\n\tConfigurationPropertiesScanRegistrar(Environment environment, @Nullable ResourceLoader resourceLoader) {\n\t\tthis.environment = environment;\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tSet<String> packagesToScan = getPackagesToScan(importingClassMetadata);\n\t\tscan(registry, packagesToScan);\n\t}\n\n\tprivate Set<String> getPackagesToScan(AnnotationMetadata metadata) {\n\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t.fromMap(metadata.getAnnotationAttributes(ConfigurationPropertiesScan.class.getName()));\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tString[] basePackages = attributes.getStringArray(\"basePackages\");\n\t\tClass<?>[] basePackageClasses = attributes.getClassArray(\"basePackageClasses\");\n\t\tSet<String> packagesToScan = new LinkedHashSet<>(Arrays.asList(basePackages));\n\t\tfor (Class<?> basePackageClass : basePackageClasses) {\n\t\t\tpackagesToScan.add(ClassUtils.getPackageName(basePackageClass));\n\t\t}\n\t\tif (packagesToScan.isEmpty()) {\n\t\t\tpackagesToScan.add(ClassUtils.getPackageName(metadata.getClassName()));\n\t\t}\n\t\tpackagesToScan.removeIf((candidate) -> !StringUtils.hasText(candidate));\n\t\treturn packagesToScan;\n\t}\n\n\tprivate void scan(BeanDefinitionRegistry registry, Set<String> packages) {\n\t\tConfigurationPropertiesBeanRegistrar registrar = new ConfigurationPropertiesBeanRegistrar(registry);\n\t\tClassPathScanningCandidateComponentProvider scanner = getScanner(registry);\n\t\tfor (String basePackage : packages) {\n\t\t\tfor (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {\n\t\t\t\tString beanClassName = candidate.getBeanClassName();\n\t\t\t\tAssert.state(beanClassName != null, \"'beanClassName' must not be null\");\n\t\t\t\tregister(registrar, beanClassName);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ClassPathScanningCandidateComponentProvider getScanner(BeanDefinitionRegistry registry) {\n\t\tClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);\n\t\tscanner.setEnvironment(this.environment);\n\t\tscanner.setResourceLoader(this.resourceLoader);\n\t\tscanner.addIncludeFilter(new AnnotationTypeFilter(ConfigurationProperties.class));\n\t\tTypeExcludeFilter typeExcludeFilter = new TypeExcludeFilter();\n\t\ttypeExcludeFilter.setBeanFactory((BeanFactory) registry);\n\t\tscanner.addExcludeFilter(typeExcludeFilter);\n\t\treturn scanner;\n\t}\n\n\tprivate void register(ConfigurationPropertiesBeanRegistrar registrar, String className) throws LinkageError {\n\t\ttry {\n\t\t\tregister(registrar, ClassUtils.forName(className, null));\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate void register(ConfigurationPropertiesBeanRegistrar registrar, Class<?> type) {\n\t\tif (!isComponent(type)) {\n\t\t\tregistrar.register(type);\n\t\t}\n\t}\n\n\tprivate boolean isComponent(Class<?> type) {\n\t\treturn MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).isPresent(Component.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Indicates that the annotated type is a source of configuration properties metadata.\n * <p>\n * This annotation has no effect on the actual binding process, but serves as a hint to\n * the {@code spring-boot-configuration-processor} to generate full metadata for the type.\n * <p>\n * Typically, this annotation is only required for types located in a different module\n * than the {@code @ConfigurationProperties} class that references them. When both types\n * are in the same module, the annotation processor can automatically discover full\n * metadata as long as the source is available.\n * <p>\n * Use this annotation when metadata for types located outside the module is needed:\n * <ol>\n * <li>Nested types annotated by {@code @NestedConfigurationProperty}</li>\n * <li>Base classes that a {@code @ConfigurationProperties}-annotated type extends\n * from</li>\n * </ol>\n * <p>\n * In the example below, {@code ServerProperties} is located in module \"A\" and\n * {@code Host} in module \"B\":<pre><code class=\"java\">\n * &#064;ConfigurationProperties(\"example.server\")\n * class ServerProperties {\n *\n *     &#064;NestedConfigurationProperty\n *     private final Host host = new Host();\n *\n *     public Host getHost() { ... }\n *\n *     // Other properties, getter, setter.\n *\n * }</code></pre>\n * <p>\n * Properties from {@code Host} are detected as they are based on the type, but\n * description and default value are not. To fix this, add the\n * {@code spring-boot-configuration-processor} to module \"B\" if it is not present already\n * and update {@code Host} as follows::<pre><code class=\"java\">\n * &#064;ConfigurationPropertiesSource\n * class Host {\n *\n *     /**\n *      * URL to use.\n *      *&#47;\n *     private String url = \"https://example.com\";\n *\n *     // Other properties, getter, setter.\n *\n * }</code></pre>\n * <p>\n * Similarly the metadata of a base class that a\n * {@code @ConfigurationProperties}-annotated type extends from can also be detected.\n * Consider the following example:<pre><code class=\"java\">\n * &#064;ConfigurationProperties(\"example.client.github\")\n * class GitHubClientProperties extends AbstractClientProperties {\n *\n *     // Additional properties, getter, setter.\n *\n * }</code></pre>\n * <p>\n * As with nested types, adding {@code @ConfigurationPropertiesSource} to\n * {@code AbstractClientProperties} and the {@code spring-boot-configuration-processor} to\n * its module ensures full metadata generation.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface ConfigurationPropertiesSource {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConstructorBound.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\n\n/**\n * Helper class to programmatically bind configuration properties that use constructor\n * injection.\n *\n * @author Stephane Nicoll\n * @since 3.0.0\n * @see ConstructorBinding\n */\npublic abstract class ConstructorBound {\n\n\t/**\n\t * Create an immutable {@link ConfigurationProperties} instance for the specified\n\t * {@code beanName} and {@code beanType} using the specified {@link BeanFactory}.\n\t * @param beanFactory the bean factory to use\n\t * @param beanName the name of the bean\n\t * @param beanType the type of the bean\n\t * @return an instance from the specified bean\n\t */\n\tpublic static Object from(BeanFactory beanFactory, String beanName, Class<?> beanType) {\n\t\tConfigurationPropertiesBean bean = ConfigurationPropertiesBean.forValueObject(beanType, beanName);\n\t\tConfigurationPropertiesBinder binder = ConfigurationPropertiesBinder.get(beanFactory);\n\t\ttry {\n\t\t\treturn binder.bindOrCreate(bean);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new ConfigurationPropertiesBindException(bean, ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/ConversionServiceDeducer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.format.support.FormattingConversionService;\n\n/**\n * Utility to deduce the {@link ConversionService} to use for configuration properties\n * binding.\n *\n * @author Phillip Webb\n */\nclass ConversionServiceDeducer {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tConversionServiceDeducer(ApplicationContext applicationContext) {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Nullable List<ConversionService> getConversionServices() {\n\t\tif (hasUserDefinedConfigurationServiceBean()) {\n\t\t\treturn Collections.singletonList(this.applicationContext\n\t\t\t\t.getBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));\n\t\t}\n\t\tif (this.applicationContext instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\treturn getConversionServices(configurableContext);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<ConversionService> getConversionServices(ConfigurableApplicationContext applicationContext) {\n\t\tList<ConversionService> conversionServices = new ArrayList<>();\n\t\tFormattingConversionService beansConverterService = new FormattingConversionService();\n\t\tMap<String, Object> converterBeans = addBeans(applicationContext, beansConverterService);\n\t\tif (!converterBeans.isEmpty()) {\n\t\t\tconversionServices.add(beansConverterService);\n\t\t}\n\t\tif (applicationContext.getBeanFactory().getConversionService() != null) {\n\t\t\tconversionServices.add(applicationContext.getBeanFactory().getConversionService());\n\t\t}\n\t\tif (!converterBeans.isEmpty()) {\n\t\t\t// Converters beans used to be added to a custom ApplicationConversionService\n\t\t\t// after the BeanFactory's ConversionService. For backwards compatibility, we\n\t\t\t// add an ApplicationConversationService as a fallback in the same place in\n\t\t\t// the list.\n\t\t\tconversionServices.add(ApplicationConversionService.getSharedInstance());\n\t\t}\n\t\treturn conversionServices;\n\t}\n\n\tprivate Map<String, Object> addBeans(ConfigurableApplicationContext applicationContext,\n\t\t\tFormattingConversionService converterService) {\n\t\tDefaultConversionService.addCollectionConverters(converterService);\n\t\tconverterService.addConverter(new ConfigurationPropertiesCharSequenceToObjectConverter(converterService));\n\t\treturn ApplicationConversionService.addBeans(converterService, applicationContext.getBeanFactory(),\n\t\t\t\tConfigurationPropertiesBinding.VALUE);\n\t}\n\n\tprivate boolean hasUserDefinedConfigurationServiceBean() {\n\t\tString beanName = ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME;\n\t\treturn this.applicationContext.containsBean(beanName) && this.applicationContext.getAutowireCapableBeanFactory()\n\t\t\t.isTypeMatch(beanName, ConversionService.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/DeprecatedConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Indicates that a getter in a {@link ConfigurationProperties @ConfigurationProperties}\n * object is deprecated. This annotation has no bearing on the actual binding processes,\n * but it is used by the {@code spring-boot-configuration-processor} to add deprecation\n * meta-data.\n * <p>\n * This annotation <strong>must</strong> be used on the getter of the deprecated element.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 1.3.0\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DeprecatedConfigurationProperty {\n\n\t/**\n\t * The reason for the deprecation.\n\t * @return the deprecation reason\n\t */\n\tString reason() default \"\";\n\n\t/**\n\t * The field that should be used instead (if any).\n\t * @return the replacement field\n\t */\n\tString replacement() default \"\";\n\n\t/**\n\t * The version in which the property became deprecated.\n\t * @return the version\n\t */\n\tString since() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/EnableConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Enable support for {@link ConfigurationProperties @ConfigurationProperties} annotated\n * beans. {@code @ConfigurationProperties} beans can be registered in the standard way\n * (for example using {@link Bean @Bean} methods) or, for convenience, can be specified\n * directly on this annotation.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(EnableConfigurationPropertiesRegistrar.class)\npublic @interface EnableConfigurationProperties {\n\n\t/**\n\t * The bean name of the configuration properties validator.\n\t * @since 2.2.0\n\t */\n\tString VALIDATOR_BEAN_NAME = \"configurationPropertiesValidator\";\n\n\t/**\n\t * Convenient way to quickly register\n\t * {@link ConfigurationProperties @ConfigurationProperties} annotated beans with\n\t * Spring. Standard Spring Beans will also be scanned regardless of this value.\n\t * @return {@code @ConfigurationProperties} annotated beans to register\n\t */\n\tClass<?>[] value() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.Conventions;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.type.AnnotationMetadata;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} for\n * {@link EnableConfigurationProperties @EnableConfigurationProperties}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {\n\n\tprivate static final String METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME = Conventions\n\t\t.getQualifiedAttributeName(EnableConfigurationPropertiesRegistrar.class, \"methodValidationExcludeFilter\");\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {\n\t\tregisterInfrastructureBeans(registry);\n\t\tregisterMethodValidationExcludeFilter(registry);\n\t\tConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);\n\t\tgetTypes(metadata).forEach(beanRegistrar::register);\n\t}\n\n\tprivate Set<Class<?>> getTypes(AnnotationMetadata metadata) {\n\t\treturn metadata.getAnnotations()\n\t\t\t.stream(EnableConfigurationProperties.class)\n\t\t\t.flatMap((annotation) -> Arrays.stream(annotation.getClassArray(MergedAnnotation.VALUE)))\n\t\t\t.filter((type) -> void.class != type)\n\t\t\t.collect(Collectors.toSet());\n\t}\n\n\tstatic void registerInfrastructureBeans(BeanDefinitionRegistry registry) {\n\t\tConfigurationPropertiesBindingPostProcessor.register(registry);\n\t\tBoundConfigurationProperties.register(registry);\n\t}\n\n\tstatic void registerMethodValidationExcludeFilter(BeanDefinitionRegistry registry) {\n\t\tif (!registry.containsBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME)) {\n\t\t\tBeanDefinition definition = BeanDefinitionBuilder\n\t\t\t\t.rootBeanDefinition(MethodValidationExcludeFilter.class, \"byAnnotation\")\n\t\t\t\t.addConstructorArgValue(ConfigurationProperties.class)\n\t\t\t\t.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t\t\t\t.getBeanDefinition();\n\t\t\tregistry.registerBeanDefinition(METHOD_VALIDATION_EXCLUDE_FILTER_BEAN_NAME, definition);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/IncompatibleConfigurationException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Exception thrown when the application has configured an incompatible set of\n * {@link ConfigurationProperties} keys.\n *\n * @author Brian Clozel\n * @since 2.4.0\n */\npublic class IncompatibleConfigurationException extends RuntimeException {\n\n\tprivate final List<String> incompatibleKeys;\n\n\tpublic IncompatibleConfigurationException(String... incompatibleKeys) {\n\t\tsuper(\"The following configuration properties have incompatible values: \" + Arrays.toString(incompatibleKeys));\n\t\tthis.incompatibleKeys = Arrays.asList(incompatibleKeys);\n\t}\n\n\tpublic Collection<String> getIncompatibleKeys() {\n\t\treturn this.incompatibleKeys;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/IncompatibleConfigurationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * A {@code FailureAnalyzer} that performs analysis of failures caused by a\n * {@code IncompatibleConfigurationException}.\n *\n * @author Brian Clozel\n */\nclass IncompatibleConfigurationFailureAnalyzer extends AbstractFailureAnalyzer<IncompatibleConfigurationException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, IncompatibleConfigurationException cause) {\n\t\tString action = String.format(\"Review the docs for %s and change the configured values.\",\n\t\t\t\tString.join(\", \", cause.getIncompatibleKeys()));\n\t\treturn new FailureAnalysis(cause.getMessage(), action, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/NestedConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.context.properties.bind.Nested;\n\n/**\n * Indicates that a property in a {@link ConfigurationProperties @ConfigurationProperties}\n * object should be treated as if it were a nested type. This annotation has no bearing on\n * the actual binding processes, but it is used by the\n * {@code spring-boot-configuration-processor} as a hint that a property is not bound as a\n * single value. When this is specified, a nested group is created for the property and\n * its type is harvested.\n * <p>\n * In the example below, {@code Host} is flagged as a nested property using its field and\n * an {@code example.server.host} nested group is created with any property that\n * {@code Host} defines:<pre><code class=\"java\">\n * &#064;ConfigurationProperties(\"example.server\")\n * class ServerProperties {\n *\n *     &#064;NestedConfigurationProperty\n *     private final Host host = new Host();\n *\n *     public Host getHost() { ... }\n *\n *     // Other properties, getter, setter.\n *\n * }</code></pre>\n * <p>\n * The annotation can also be specified on a getter method. If you use records, you can\n * annotate the record component.\n * <p>\n * This has no effect on collections and maps as these types are automatically identified.\n * Also, the annotation is not necessary if the target type is an inner class of the\n * {@link ConfigurationProperties @ConfigurationProperties} object. In the example below,\n * {@code Host} is detected as a nested type as it is defined as an inner class:\n * <pre><code class=\"java\">\n * &#064;ConfigurationProperties(\"example.server\")\n * class ServerProperties {\n *\n *     private final Host host = new Host();\n *\n *     public Host getHost() { ... }\n *\n *     // Other properties, getter, setter.\n *\n *     public static class Host {\n *\n *         // properties, getter, setter.\n *\n *     }\n *\n * }</code></pre>\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Jared Bates\n * @since 1.2.0\n */\n@Target({ ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Nested\npublic @interface NestedConfigurationProperty {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/NotConstructorBoundInjectionFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.reflect.Constructor;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InjectionPoint;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.analyzer.AbstractInjectionFailureAnalyzer;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.lang.Contract;\n\n/**\n * An {@link AbstractInjectionFailureAnalyzer} for\n * {@link ConfigurationProperties @ConfigurationProperties} that are intended to use\n * {@link ConstructorBinding constructor binding} but did not.\n *\n * @author Andy Wilkinson\n */\nclass NotConstructorBoundInjectionFailureAnalyzer\n\t\textends AbstractInjectionFailureAnalyzer<NoSuchBeanDefinitionException> implements Ordered {\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause,\n\t\t\t@Nullable String description) {\n\t\tInjectionPoint injectionPoint = findInjectionPoint(rootFailure);\n\t\tif (isConstructorBindingConfigurationProperties(injectionPoint)) {\n\t\t\tString simpleName = injectionPoint.getMember().getDeclaringClass().getSimpleName();\n\t\t\tString action = \"Update your configuration so that \" + simpleName + \" is defined via @\"\n\t\t\t\t\t+ ConfigurationPropertiesScan.class.getSimpleName() + \" or @\"\n\t\t\t\t\t+ EnableConfigurationProperties.class.getSimpleName() + \".\";\n\t\t\treturn new FailureAnalysis(\n\t\t\t\t\tsimpleName + \" is annotated with @\" + ConstructorBinding.class.getSimpleName()\n\t\t\t\t\t\t\t+ \" but it is defined as a regular bean which caused dependency injection to fail.\",\n\t\t\t\t\taction, cause);\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Contract(\"null -> false\")\n\tprivate boolean isConstructorBindingConfigurationProperties(@Nullable InjectionPoint injectionPoint) {\n\t\treturn injectionPoint != null && injectionPoint.getMember() instanceof Constructor<?> constructor\n\t\t\t\t&& isConstructorBindingConfigurationProperties(constructor);\n\t}\n\n\tprivate boolean isConstructorBindingConfigurationProperties(Constructor<?> constructor) {\n\t\tClass<?> declaringClass = constructor.getDeclaringClass();\n\t\tBindMethod bindMethod = ConfigurationPropertiesBean.deduceBindMethod(declaringClass);\n\t\treturn MergedAnnotations.from(declaringClass, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.isPresent(ConfigurationProperties.class) && bindMethod == BindMethod.VALUE_OBJECT;\n\t}\n\n\tprivate @Nullable InjectionPoint findInjectionPoint(Throwable failure) {\n\t\tUnsatisfiedDependencyException unsatisfiedDependencyException = findCause(failure,\n\t\t\t\tUnsatisfiedDependencyException.class);\n\t\tif (unsatisfiedDependencyException == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn unsatisfiedDependencyException.getInjectionPoint();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.NoSuchElementException;\nimport java.util.function.BiFunction;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * Utility that can be used to map values from a supplied source to a destination.\n * Primarily intended to be help when mapping from\n * {@link ConfigurationProperties @ConfigurationProperties} to third-party classes.\n * <p>\n * Can filter values based on predicates and adapt values if needed. For example:\n * <pre class=\"code\">\n * PropertyMapper map = PropertyMapper.get();\n * map.from(source::getName)\n *   .to(destination::setName);\n * map.from(source::getTimeout)\n *   .when(this::thisYear)\n *   .asInt(Duration::getSeconds)\n *   .to(destination::setTimeoutSecs);\n * map.from(source::isEnabled)\n *   .whenFalse().\n *   .toCall(destination::disable);\n * </pre>\n * <p>\n * Mappings can ultimately be applied to a {@link Source#to(Consumer) setter}, trigger a\n * {@link Source#toCall(Runnable) method call} or create a\n * {@link Source#toInstance(Function) new instance}.\n * <p>\n * By default {@code null} values and any {@link NullPointerException} thrown from the\n * supplier are filtered and will not be applied to consumers. If you want to apply nulls,\n * you can use {@link Source#always()}.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Chris Bono\n * @author Moritz Halbritter\n * @since 2.0.0\n */\npublic final class PropertyMapper {\n\n\tprivate static final PropertyMapper INSTANCE = new PropertyMapper(null, null);\n\n\tprivate final @Nullable PropertyMapper parent;\n\n\tprivate final @Nullable SourceOperator sourceOperator;\n\n\tprivate PropertyMapper(@Nullable PropertyMapper parent, @Nullable SourceOperator sourceOperator) {\n\t\tthis.parent = parent;\n\t\tthis.sourceOperator = sourceOperator;\n\t}\n\n\t/**\n\t * Return a new {@link PropertyMapper} instance that applies the given\n\t * {@link SourceOperator} to every source.\n\t * @param operator the source operator to apply\n\t * @return a new property mapper instance\n\t */\n\tpublic PropertyMapper alwaysApplying(SourceOperator operator) {\n\t\tAssert.notNull(operator, \"'operator' must not be null\");\n\t\treturn new PropertyMapper(this, operator);\n\t}\n\n\t/**\n\t * Return a new {@link Source} from the specified value that can be used to perform\n\t * the mapping.\n\t * @param <T> the source type\n\t * @param value the value\n\t * @return a {@link Source} that can be used to complete the mapping\n\t */\n\tpublic <T> Source<T> from(@Nullable T value) {\n\t\treturn from(() -> value);\n\t}\n\n\t/**\n\t * Return a new {@link Source} from the specified value supplier that can be used to\n\t * perform the mapping.\n\t * @param <T> the source type\n\t * @param supplier the value supplier\n\t * @return a {@link Source} that can be used to complete the mapping\n\t * @see #from(Object)\n\t */\n\tpublic <T> Source<T> from(Supplier<? extends @Nullable T> supplier) {\n\t\tAssert.notNull(supplier, \"'supplier' must not be null\");\n\t\tSource<T> source = getSource(supplier);\n\t\tif (this.sourceOperator != null) {\n\t\t\tsource = this.sourceOperator.apply(source);\n\t\t}\n\t\treturn source;\n\t}\n\n\tprivate <T> Source<T> getSource(Supplier<? extends @Nullable T> supplier) {\n\t\tif (this.parent != null) {\n\t\t\treturn this.parent.from(supplier);\n\t\t}\n\t\treturn new Source<>(SingletonSupplier.of(supplier), (value) -> true);\n\t}\n\n\t/**\n\t * Return the property mapper.\n\t * @return the property mapper\n\t */\n\tpublic static PropertyMapper get() {\n\t\treturn INSTANCE;\n\t}\n\n\t/**\n\t * An operation that can be applied to a {@link Source}.\n\t */\n\t@FunctionalInterface\n\tpublic interface SourceOperator {\n\n\t\t/**\n\t\t * Apply the operation to the given source.\n\t\t * @param <T> the source type\n\t\t * @param source the source to operate on\n\t\t * @return the updated source\n\t\t */\n\t\t<T> Source<T> apply(Source<T> source);\n\n\t}\n\n\t/**\n\t * A source that is in the process of being mapped.\n\t *\n\t * @param <T> the source type\n\t */\n\tpublic static final class Source<T> {\n\n\t\tprivate final Supplier<? extends @Nullable T> supplier;\n\n\t\tprivate final Predicate<T> predicate;\n\n\t\tprivate Source(Supplier<? extends @Nullable T> supplier, Predicate<T> predicate) {\n\t\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\t\tthis.supplier = supplier;\n\t\t\tthis.predicate = predicate;\n\t\t}\n\n\t\t/**\n\t\t * Return a source that will use the given supplier to obtain a fallback value to\n\t\t * use in place of {@code null}.\n\t\t * @param fallback the fallback supplier\n\t\t * @return a new {@link Source} instance\n\t\t * @since 4.0.0\n\t\t */\n\t\tpublic Source<T> orFrom(Supplier<? extends @Nullable T> fallback) {\n\t\t\tAssert.notNull(fallback, \"'fallback' must not be null\");\n\t\t\tSupplier<@Nullable T> supplier = () -> {\n\t\t\t\tT value = getValue();\n\t\t\t\treturn (value != null) ? value : fallback.get();\n\t\t\t};\n\t\t\treturn new Source<>(supplier, this.predicate);\n\t\t}\n\n\t\t/**\n\t\t * Return an adapted version of the source with {@link Integer} type.\n\t\t * @param <R> the resulting type\n\t\t * @param adapter an adapter to convert the current value to a number.\n\t\t * @return a new adapted source instance\n\t\t */\n\t\tpublic <R extends Number> Source<Integer> asInt(Adapter<? super T, ? extends R> adapter) {\n\t\t\treturn as(adapter).as(Number::intValue);\n\t\t}\n\n\t\t/**\n\t\t * Return an adapted version of the source changed through the given adapter\n\t\t * function.\n\t\t * @param <R> the resulting type\n\t\t * @param adapter the adapter to apply\n\t\t * @return a new adapted source instance\n\t\t */\n\t\tpublic <R> Source<R> as(Adapter<? super T, ? extends R> adapter) {\n\t\t\tAssert.notNull(adapter, \"'adapter' must not be null\");\n\t\t\tSupplier<@Nullable R> supplier = () -> {\n\t\t\t\tT value = getValue();\n\t\t\t\treturn (value != null && this.predicate.test(value)) ? adapter.adapt(value) : null;\n\t\t\t};\n\t\t\tPredicate<R> predicate = (adaptedValue) -> {\n\t\t\t\tT value = getValue();\n\t\t\t\treturn value != null && this.predicate.test(value);\n\t\t\t};\n\t\t\treturn new Source<>(supplier, predicate);\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that will only map values that are\n\t\t * {@code true}.\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic Source<T> whenTrue() {\n\t\t\treturn when(Boolean.TRUE::equals);\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that will only map values that are\n\t\t * {@code false}.\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic Source<T> whenFalse() {\n\t\t\treturn when(Boolean.FALSE::equals);\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that will only map values that have a\n\t\t * {@code toString()} containing actual text.\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic Source<T> whenHasText() {\n\t\t\treturn when((value) -> StringUtils.hasText(value.toString()));\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that will only map values equal to the\n\t\t * specified {@code object}.\n\t\t * @param object the object to match\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic Source<T> whenEqualTo(@Nullable Object object) {\n\t\t\treturn when((value) -> value.equals(object));\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that will only map values that are an\n\t\t * instance of the given type.\n\t\t * @param <R> the target type\n\t\t * @param target the target type to match\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic <R extends T> Source<R> whenInstanceOf(Class<R> target) {\n\t\t\tAssert.notNull(target, \"'target' must not be null\");\n\t\t\treturn when(target::isInstance).as(target::cast);\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that won't map values that match the\n\t\t * given predicate.\n\t\t * @param predicate the predicate used to filter values\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic Source<T> whenNot(Predicate<T> predicate) {\n\t\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\t\treturn when(predicate.negate());\n\t\t}\n\n\t\t/**\n\t\t * Return a filtered version of the source that won't map values that don't match\n\t\t * the given predicate.\n\t\t * @param predicate the predicate used to filter values\n\t\t * @return a new filtered source instance\n\t\t */\n\t\tpublic Source<T> when(Predicate<T> predicate) {\n\t\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\t\treturn new Source<>(this.supplier, this.predicate.and(predicate));\n\t\t}\n\n\t\t/**\n\t\t * Complete the mapping by passing any non-filtered value to the specified\n\t\t * consumer. The method is designed to be used with mutable objects.\n\t\t * @param consumer the consumer that should accept the value if it's not been\n\t\t * filtered\n\t\t */\n\t\tpublic void to(Consumer<? super T> consumer) {\n\t\t\tAssert.notNull(consumer, \"'consumer' must not be null\");\n\t\t\tT value = getValue();\n\t\t\tif (value != null && test(value)) {\n\t\t\t\tconsumer.accept(value);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Complete the mapping for any non-filtered value by applying the given function\n\t\t * to an existing instance and returning a new one. For filtered values, the\n\t\t * {@code instance} parameter is returned unchanged. The method is designed to be\n\t\t * used with immutable objects.\n\t\t * @param <R> the result type\n\t\t * @param instance the current instance\n\t\t * @param mapper the mapping function\n\t\t * @return a new mapped instance or the original instance\n\t\t * @since 3.0.0\n\t\t */\n\t\tpublic <R> R to(R instance, BiFunction<R, ? super T, R> mapper) {\n\t\t\tAssert.notNull(instance, \"'instance' must not be null\");\n\t\t\tAssert.notNull(mapper, \"'mapper' must not be null\");\n\t\t\tT value = getValue();\n\t\t\tif (value != null && test(value)) {\n\t\t\t\treturn mapper.apply(instance, value);\n\t\t\t}\n\t\t\treturn instance;\n\t\t}\n\n\t\t/**\n\t\t * Complete the mapping by creating a new instance from the non-filtered value.\n\t\t * @param <R> the resulting type\n\t\t * @param factory the factory used to create the instance\n\t\t * @return the instance\n\t\t * @throws NoSuchElementException if the value has been filtered\n\t\t */\n\t\tpublic <R> R toInstance(Function<? super T, R> factory) {\n\t\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\t\tT value = getValue();\n\t\t\tif (value != null && test(value)) {\n\t\t\t\treturn factory.apply(value);\n\t\t\t}\n\t\t\tthrow new NoSuchElementException(\"No value present\");\n\t\t}\n\n\t\t/**\n\t\t * Complete the mapping by calling the specified method when the value has not\n\t\t * been filtered.\n\t\t * @param runnable the method to call if the value has not been filtered\n\t\t */\n\t\tpublic void toCall(Runnable runnable) {\n\t\t\tAssert.notNull(runnable, \"'runnable' must not be null\");\n\t\t\tT value = getValue();\n\t\t\tif (value != null && test(value)) {\n\t\t\t\trunnable.run();\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Return a version of this source that can be used to always complete mappings,\n\t\t * even if values are {@code null}.\n\t\t * @return a new {@link Always} instance\n\t\t * @since 4.0.0\n\t\t */\n\t\tpublic Always<T> always() {\n\t\t\tSupplier<@Nullable T> getValue = this::getValue;\n\t\t\treturn new Always<>(getValue, this::test);\n\t\t}\n\n\t\tprivate @Nullable T getValue() {\n\t\t\ttry {\n\t\t\t\treturn this.supplier.get();\n\t\t\t}\n\t\t\tcatch (NullPointerException ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean test(T value) {\n\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\treturn this.predicate.test(value);\n\t\t}\n\n\t\t/**\n\t\t * Adapter used to adapt a value and possibly return a {@code null} result.\n\t\t *\n\t\t * @param <T> the source type\n\t\t * @param <R> the result type\n\t\t * @since 4.0.0\n\t\t */\n\t\t@FunctionalInterface\n\t\tpublic interface Adapter<T, R> {\n\n\t\t\t/**\n\t\t\t * Adapt the given value.\n\t\t\t * @param value the value to adapt\n\t\t\t * @return an adapted value or {@code null}\n\t\t\t */\n\t\t\t@Nullable R adapt(T value);\n\n\t\t}\n\n\t\t/**\n\t\t * Allow source mapping to complete using methods that accept nulls.\n\t\t *\n\t\t * @param <T> the source type\n\t\t * @since 4.0.0\n\t\t */\n\t\tpublic static class Always<T> {\n\n\t\t\tprivate final Supplier<@Nullable T> supplier;\n\n\t\t\tprivate final Predicate<T> predicate;\n\n\t\t\tAlways(Supplier<@Nullable T> supplier, Predicate<T> predicate) {\n\t\t\t\tthis.supplier = supplier;\n\t\t\t\tthis.predicate = predicate;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Return an adapted version of the source changed through the given adapter\n\t\t\t * function.\n\t\t\t * @param <R> the resulting type\n\t\t\t * @param adapter the adapter to apply\n\t\t\t * @return a new adapted source instance\n\t\t\t */\n\t\t\tpublic <R> Always<R> as(Adapter<? super T, ? extends R> adapter) {\n\t\t\t\tAssert.notNull(adapter, \"'adapter' must not be null\");\n\t\t\t\tSupplier<@Nullable R> supplier = () -> {\n\t\t\t\t\tT value = getValue();\n\t\t\t\t\treturn (value == null || test(value)) ? adapter.adapt(value) : null;\n\t\t\t\t};\n\t\t\t\tPredicate<R> predicate = (adaptedValue) -> {\n\t\t\t\t\tT value = getValue();\n\t\t\t\t\treturn value == null || test(value);\n\t\t\t\t};\n\t\t\t\treturn new Always<>(supplier, predicate);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Complete the mapping by passing any non-filtered value to the specified\n\t\t\t * consumer. The method is designed to be used with mutable objects.\n\t\t\t * @param consumer the consumer that should accept the value if it's not been\n\t\t\t * filtered\n\t\t\t */\n\t\t\tpublic void to(Consumer<@Nullable ? super T> consumer) {\n\t\t\t\tAssert.notNull(consumer, \"'consumer' must not be null\");\n\t\t\t\tT value = getValue();\n\t\t\t\tif (value == null || test(value)) {\n\t\t\t\t\tconsumer.accept(value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Complete the mapping for any non-filtered value by applying the given\n\t\t\t * function to an existing instance and returning a new one. For filtered\n\t\t\t * values, the {@code instance} parameter is returned unchanged. The method is\n\t\t\t * designed to be used with immutable objects.\n\t\t\t * @param <R> the result type\n\t\t\t * @param instance the current instance\n\t\t\t * @param mapper the mapping function\n\t\t\t * @return a new mapped instance or the original instance\n\t\t\t */\n\t\t\tpublic <R> R to(R instance, Mapper<R, ? super T> mapper) {\n\t\t\t\tAssert.notNull(instance, \"'instance' must not be null\");\n\t\t\t\tAssert.notNull(mapper, \"'mapper' must not be null\");\n\t\t\t\tT value = getValue();\n\t\t\t\tif (value == null || test(value)) {\n\t\t\t\t\treturn mapper.map(instance, value);\n\t\t\t\t}\n\t\t\t\treturn instance;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Complete the mapping by creating a new instance from the non-filtered\n\t\t\t * value.\n\t\t\t * @param <R> the resulting type\n\t\t\t * @param factory the factory used to create the instance\n\t\t\t * @return the instance\n\t\t\t * @throws NoSuchElementException if the value has been filtered\n\t\t\t */\n\t\t\tpublic <R> R toInstance(Factory<? super T, ? extends R> factory) {\n\t\t\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\t\t\tT value = getValue();\n\t\t\t\tif (value == null || test(value)) {\n\t\t\t\t\treturn factory.create(value);\n\t\t\t\t}\n\t\t\t\tthrow new NoSuchElementException(\"No value present\");\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Complete the mapping by calling the specified method when the value has not\n\t\t\t * been filtered.\n\t\t\t * @param runnable the method to call if the value has not been filtered\n\t\t\t */\n\t\t\tpublic void toCall(Runnable runnable) {\n\t\t\t\tAssert.notNull(runnable, \"'runnable' must not be null\");\n\t\t\t\tT value = getValue();\n\t\t\t\tif (value == null || test(value)) {\n\t\t\t\t\trunnable.run();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate @Nullable T getValue() {\n\t\t\t\treturn this.supplier.get();\n\t\t\t}\n\n\t\t\tprivate boolean test(T value) {\n\t\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\t\treturn this.predicate.test(value);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Adapter that support nullable values.\n\t\t\t *\n\t\t\t * @param <T> the source type\n\t\t\t * @param <R> the result type\n\t\t\t */\n\t\t\t@FunctionalInterface\n\t\t\tpublic interface Adapter<T, R> {\n\n\t\t\t\t/**\n\t\t\t\t * Adapt the given value.\n\t\t\t\t * @param value the value to adapt\n\t\t\t\t * @return an adapted value or {@code null}\n\t\t\t\t */\n\t\t\t\t@Nullable R adapt(@Nullable T value);\n\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Factory that supports nullable values.\n\t\t\t *\n\t\t\t * @param <T> the source type\n\t\t\t * @param <R> the result type\n\t\t\t */\n\t\t\t@FunctionalInterface\n\t\t\tpublic interface Factory<T, R extends @Nullable Object> {\n\n\t\t\t\t/**\n\t\t\t\t * Create a new instance for the given nullable value.\n\t\t\t\t * @param value the value used to create the instance (may be\n\t\t\t\t * {@code null})\n\t\t\t\t * @return the resulting instance\n\t\t\t\t */\n\t\t\t\tR create(@Nullable T value);\n\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Mapper that supports nullable values.\n\t\t\t *\n\t\t\t * @param <T> the source type\n\t\t\t * @param <R> the result type\n\t\t\t */\n\t\t\t@FunctionalInterface\n\t\t\tpublic interface Mapper<R extends @Nullable Object, T> {\n\n\t\t\t\t/**\n\t\t\t\t * Map an existing instance for the given nullable value.\n\t\t\t\t * @param instance the existing instance\n\t\t\t\t * @param value the value to map (may be {@code null})\n\t\t\t\t * @return the resulting mapped instance\n\t\t\t\t */\n\t\t\t\tR map(R instance, @Nullable T value);\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/PropertySourcesDeducer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.util.Assert;\n\n/**\n * Utility to deduce the {@link PropertySources} to use for configuration binding.\n *\n * @author Phillip Webb\n */\nclass PropertySourcesDeducer {\n\n\tprivate static final Log logger = LogFactory.getLog(PropertySourcesDeducer.class);\n\n\tprivate final ApplicationContext applicationContext;\n\n\tPropertySourcesDeducer(ApplicationContext applicationContext) {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\tPropertySources getPropertySources() {\n\t\tPropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer();\n\t\tif (configurer != null) {\n\t\t\treturn configurer.getAppliedPropertySources();\n\t\t}\n\t\tMutablePropertySources sources = extractEnvironmentPropertySources();\n\t\tAssert.state(sources != null,\n\t\t\t\t\"Unable to obtain PropertySources from PropertySourcesPlaceholderConfigurer or Environment\");\n\t\treturn sources;\n\t}\n\n\tprivate @Nullable PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() {\n\t\t// Take care not to cause early instantiation of all FactoryBeans\n\t\tMap<String, PropertySourcesPlaceholderConfigurer> beans = this.applicationContext\n\t\t\t.getBeansOfType(PropertySourcesPlaceholderConfigurer.class, false, false);\n\t\tif (beans.size() == 1) {\n\t\t\treturn beans.values().iterator().next();\n\t\t}\n\t\tif (beans.size() > 1 && logger.isWarnEnabled()) {\n\t\t\tlogger.warn(\"Multiple PropertySourcesPlaceholderConfigurer beans registered \" + beans.keySet()\n\t\t\t\t\t+ \", falling back to Environment\");\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable MutablePropertySources extractEnvironmentPropertySources() {\n\t\tEnvironment environment = this.applicationContext.getEnvironment();\n\t\tif (environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\treturn configurableEnvironment.getPropertySources();\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AbstractBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.util.Assert;\n\n/**\n * Abstract base class for {@link BindHandler} implementations.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic abstract class AbstractBindHandler implements BindHandler {\n\n\tprivate final BindHandler parent;\n\n\t/**\n\t * Create a new binding handler instance.\n\t */\n\tpublic AbstractBindHandler() {\n\t\tthis(BindHandler.DEFAULT);\n\t}\n\n\t/**\n\t * Create a new binding handler instance with a specific parent.\n\t * @param parent the parent handler\n\t */\n\tpublic AbstractBindHandler(BindHandler parent) {\n\t\tAssert.notNull(parent, \"'parent' must not be null\");\n\t\tthis.parent = parent;\n\t}\n\n\t@Override\n\tpublic <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {\n\t\treturn this.parent.onStart(name, target, context);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tObject result) {\n\t\treturn this.parent.onSuccess(name, target, context, result);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tException error) throws Exception {\n\t\treturn this.parent.onFailure(name, target, context, error);\n\t}\n\n\t@Override\n\tpublic void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t@Nullable Object result) throws Exception {\n\t\tthis.parent.onFinish(name, target, context, result);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AggregateBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\n\n/**\n * Internal strategy used by {@link Binder} to bind aggregates (Maps, Lists, Arrays).\n *\n * @param <T> the type being bound\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nabstract class AggregateBinder<T> {\n\n\tprivate final Context context;\n\n\tAggregateBinder(Context context) {\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * Determine if recursive binding is supported.\n\t * @param source the configuration property source or {@code null} for all sources.\n\t * @return if recursive binding is supported\n\t */\n\tprotected abstract boolean isAllowRecursiveBinding(@Nullable ConfigurationPropertySource source);\n\n\t/**\n\t * Perform binding for the aggregate.\n\t * @param name the configuration property name to bind\n\t * @param target the target to bind\n\t * @param elementBinder an element binder\n\t * @return the bound aggregate or null\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tfinal @Nullable Object bind(ConfigurationPropertyName name, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder) {\n\t\tObject result = bindAggregate(name, target, elementBinder);\n\t\tSupplier<?> value = target.getValue();\n\t\tif (result == null || value == null) {\n\t\t\treturn result;\n\t\t}\n\t\treturn merge((Supplier<T>) value, (T) result);\n\t}\n\n\t/**\n\t * Perform the actual aggregate binding.\n\t * @param name the configuration property name to bind\n\t * @param target the target to bind\n\t * @param elementBinder an element binder\n\t * @return the bound result\n\t */\n\tprotected abstract @Nullable Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder);\n\n\t/**\n\t * Merge any additional elements into the existing aggregate.\n\t * @param existing the supplier for the existing value\n\t * @param additional the additional elements to merge\n\t * @return the merged result\n\t */\n\tprotected abstract T merge(Supplier<T> existing, T additional);\n\n\t/**\n\t * Return the context being used by this binder.\n\t * @return the context\n\t */\n\tprotected final Context getContext() {\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Internal class used to supply the aggregate and cache the value.\n\t *\n\t * @param <T> the aggregate type\n\t */\n\tprotected static class AggregateSupplier<T> {\n\n\t\tprivate final Supplier<T> supplier;\n\n\t\tprivate @Nullable T supplied;\n\n\t\tpublic AggregateSupplier(Supplier<T> supplier) {\n\t\t\tthis.supplier = supplier;\n\t\t}\n\n\t\tpublic T get() {\n\t\t\tif (this.supplied == null) {\n\t\t\t\tthis.supplied = this.supplier.get();\n\t\t\t}\n\t\t\treturn this.supplied;\n\t\t}\n\n\t\tpublic boolean wasSupplied() {\n\t\t\treturn this.supplied != null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/AggregateElementBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\n\n/**\n * Binder that can be used by {@link AggregateBinder} implementations to recursively bind\n * elements.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@FunctionalInterface\ninterface AggregateElementBinder {\n\n\t/**\n\t * Bind the given name to a target bindable.\n\t * @param name the name to bind\n\t * @param target the target bindable\n\t * @return a bound object or {@code null}\n\t */\n\tdefault @Nullable Object bind(ConfigurationPropertyName name, Bindable<?> target) {\n\t\treturn bind(name, target, null);\n\t}\n\n\t/**\n\t * Bind the given name to a target bindable using optionally limited to a single\n\t * source.\n\t * @param name the name to bind\n\t * @param target the target bindable\n\t * @param source the source of the elements or {@code null} to use all sources\n\t * @return a bound object or {@code null}\n\t */\n\t@Nullable Object bind(ConfigurationPropertyName name, Bindable<?> target, @Nullable ConfigurationPropertySource source);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ArrayBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.core.ResolvableType;\n\n/**\n * {@link AggregateBinder} for arrays.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ArrayBinder extends IndexedElementsBinder<Object> {\n\n\tArrayBinder(Context context) {\n\t\tsuper(context);\n\t}\n\n\t@Override\n\tprotected @Nullable Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder) {\n\t\tIndexedCollectionSupplier result = new IndexedCollectionSupplier(ArrayList::new);\n\t\tResolvableType aggregateType = target.getType();\n\t\tResolvableType elementType = target.getType().getComponentType();\n\t\tbindIndexed(name, target, elementBinder, aggregateType, elementType, result);\n\t\tif (result.wasSupplied()) {\n\t\t\tList<Object> list = (List<Object>) result.get();\n\t\t\tObject array = Array.newInstance(elementType.resolve(), list.size());\n\t\t\tfor (int i = 0; i < list.size(); i++) {\n\t\t\t\tArray.set(array, i, list.get(i));\n\t\t\t}\n\t\t\treturn array;\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected Object merge(Supplier<Object> existing, Object additional) {\n\t\treturn additional;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConstructorProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Constructor;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Strategy interface used to determine a specific constructor to use when binding.\n *\n * @author Madhura Bhave\n * @since 2.2.1\n */\n@FunctionalInterface\npublic interface BindConstructorProvider {\n\n\t/**\n\t * Default {@link BindConstructorProvider} implementation that only returns a value\n\t * when there's a single constructor and when the bindable has no existing value.\n\t */\n\tBindConstructorProvider DEFAULT = new DefaultBindConstructorProvider();\n\n\t/**\n\t * Return the bind constructor to use for the given type, or {@code null} if\n\t * constructor binding is not supported.\n\t * @param type the type to check\n\t * @param isNestedConstructorBinding if this binding is nested within a constructor\n\t * binding\n\t * @return the bind constructor or {@code null}\n\t * @since 3.0.0\n\t */\n\tdefault @Nullable Constructor<?> getBindConstructor(Class<?> type, boolean isNestedConstructorBinding) {\n\t\treturn getBindConstructor(Bindable.of(type), isNestedConstructorBinding);\n\t}\n\n\t/**\n\t * Return the bind constructor to use for the given bindable, or {@code null} if\n\t * constructor binding is not supported.\n\t * @param bindable the bindable to check\n\t * @param isNestedConstructorBinding if this binding is nested within a constructor\n\t * binding\n\t * @return the bind constructor or {@code null}\n\t */\n\t@Nullable Constructor<?> getBindConstructor(Bindable<?> bindable, boolean isNestedConstructorBinding);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\n\n/**\n * Context information for use by {@link BindHandler BindHandlers}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic interface BindContext {\n\n\t/**\n\t * Return the source binder that is performing the bind operation.\n\t * @return the source binder\n\t */\n\tBinder getBinder();\n\n\t/**\n\t * Return the current depth of the binding. Root binding starts with a depth of\n\t * {@code 0}. Each subsequent property binding increases the depth by {@code 1}.\n\t * @return the depth of the current binding\n\t */\n\tint getDepth();\n\n\t/**\n\t * Return an {@link Iterable} of the {@link ConfigurationPropertySource sources} being\n\t * used by the {@link Binder}.\n\t * @return the sources\n\t */\n\tIterable<ConfigurationPropertySource> getSources();\n\n\t/**\n\t * Return the {@link ConfigurationProperty} actually being bound or {@code null} if\n\t * the property has not yet been determined.\n\t * @return the configuration property (may be {@code null}).\n\t */\n\t@Nullable ConfigurationProperty getConfigurationProperty();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.beans.PropertyEditor;\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.PropertyEditorRegistry;\nimport org.springframework.beans.SimpleTypeConverter;\nimport org.springframework.beans.propertyeditors.CustomBooleanEditor;\nimport org.springframework.beans.propertyeditors.CustomNumberEditor;\nimport org.springframework.beans.propertyeditors.FileEditor;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.ConversionException;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\nimport org.springframework.core.convert.support.GenericConversionService;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Utility to handle any conversion needed during binding. This class is not thread-safe\n * and so a new instance is created for each top-level bind.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nfinal class BindConverter {\n\n\tprivate static @Nullable BindConverter sharedInstance;\n\n\tprivate final List<ConversionService> delegates;\n\n\tprivate BindConverter(@Nullable List<ConversionService> conversionServices,\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer) {\n\t\tList<ConversionService> delegates = new ArrayList<>();\n\t\tdelegates.add(new TypeConverterConversionService(propertyEditorInitializer));\n\t\tboolean hasApplication = false;\n\t\tif (!CollectionUtils.isEmpty(conversionServices)) {\n\t\t\tfor (ConversionService conversionService : conversionServices) {\n\t\t\t\tdelegates.add(conversionService);\n\t\t\t\thasApplication = hasApplication || conversionService instanceof ApplicationConversionService;\n\t\t\t}\n\t\t}\n\t\tif (!hasApplication) {\n\t\t\tdelegates.add(ApplicationConversionService.getSharedInstance());\n\t\t}\n\t\tthis.delegates = Collections.unmodifiableList(delegates);\n\t}\n\n\tboolean canConvert(@Nullable Object source, ResolvableType targetType, Annotation... targetAnnotations) {\n\t\treturn canConvert(TypeDescriptor.forObject(source),\n\t\t\t\tnew ResolvableTypeDescriptor(targetType, targetAnnotations));\n\t}\n\n\tprivate boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tfor (ConversionService service : this.delegates) {\n\t\t\tif (service.canConvert(sourceType, targetType)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t<T> @Nullable T convert(@Nullable Object source, Bindable<T> target) {\n\t\treturn convert(source, target.getType(), target.getAnnotations());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t<T> @Nullable T convert(@Nullable Object source, ResolvableType targetType, Annotation... targetAnnotations) {\n\t\tTypeDescriptor sourceType = (source != null) ? TypeDescriptor.forObject(source) : null;\n\t\treturn (T) convert(source, sourceType, new ResolvableTypeDescriptor(targetType, targetAnnotations));\n\t}\n\n\tprivate @Nullable Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType,\n\t\t\tTypeDescriptor targetType) {\n\t\tConversionException failure = null;\n\t\tfor (ConversionService delegate : this.delegates) {\n\t\t\ttry {\n\t\t\t\tif (delegate.canConvert(sourceType, targetType)) {\n\t\t\t\t\treturn delegate.convert(source, sourceType, targetType);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ConversionException ex) {\n\t\t\t\tif (failure == null && ex instanceof ConversionFailedException) {\n\t\t\t\t\tfailure = ex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow (failure != null) ? failure : new ConverterNotFoundException(sourceType, targetType);\n\t}\n\n\tstatic BindConverter get(@Nullable List<ConversionService> conversionServices,\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer) {\n\t\tboolean sharedApplicationConversionService = (conversionServices == null) || (conversionServices.size() == 1\n\t\t\t\t&& conversionServices.get(0) == ApplicationConversionService.getSharedInstance());\n\t\tif (propertyEditorInitializer == null && sharedApplicationConversionService) {\n\t\t\treturn getSharedInstance();\n\t\t}\n\t\treturn new BindConverter(conversionServices, propertyEditorInitializer);\n\t}\n\n\tprivate static BindConverter getSharedInstance() {\n\t\tif (sharedInstance == null) {\n\t\t\tsharedInstance = new BindConverter(null, null);\n\t\t}\n\t\treturn sharedInstance;\n\t}\n\n\t/**\n\t * A {@link TypeDescriptor} backed by a {@link ResolvableType}.\n\t */\n\tprivate static class ResolvableTypeDescriptor extends TypeDescriptor {\n\n\t\tResolvableTypeDescriptor(ResolvableType resolvableType, Annotation[] annotations) {\n\t\t\tsuper(resolvableType, null, annotations);\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@link ConversionService} implementation that delegates to a\n\t * {@link SimpleTypeConverter}. Allows {@link PropertyEditor} based conversion for\n\t * simple types, arrays and collections.\n\t */\n\tprivate static class TypeConverterConversionService extends GenericConversionService {\n\n\t\tTypeConverterConversionService(@Nullable Consumer<PropertyEditorRegistry> initializer) {\n\t\t\tApplicationConversionService.addDelimitedStringConverters(this);\n\t\t\taddConverter(new TypeConverterConverter(initializer));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\t// Prefer conversion service to handle things like String to char[].\n\t\t\tif (isPrimitiveArray(targetType)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn super.canConvert(sourceType, targetType);\n\t\t}\n\n\t\tprivate static boolean isPrimitiveArray(TypeDescriptor targetType) {\n\t\t\tif (!targetType.isArray()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tTypeDescriptor elementTypeDescriptor = targetType.getElementTypeDescriptor();\n\t\t\tAssert.state(elementTypeDescriptor != null, \"'elementTypeDescriptor' must not be null\");\n\t\t\treturn elementTypeDescriptor.isPrimitive();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ConditionalGenericConverter} that delegates to {@link SimpleTypeConverter}.\n\t */\n\tprivate static class TypeConverterConverter implements ConditionalGenericConverter {\n\n\t\tprivate static final Set<Class<?>> EXCLUDED_EDITORS;\n\t\tstatic {\n\t\t\tSet<Class<?>> excluded = new HashSet<>();\n\t\t\texcluded.add(CustomNumberEditor.class);\n\t\t\texcluded.add(CustomBooleanEditor.class);\n\t\t\texcluded.add(FileEditor.class);\n\t\t\tEXCLUDED_EDITORS = Collections.unmodifiableSet(excluded);\n\t\t}\n\n\t\tprivate final @Nullable Consumer<PropertyEditorRegistry> initializer;\n\n\t\t// SimpleTypeConverter is not thread-safe to use for conversion but we can use it\n\t\t// in a thread-safe way to check if conversion is possible.\n\t\tprivate final SimpleTypeConverter matchesOnlyTypeConverter;\n\n\t\tTypeConverterConverter(@Nullable Consumer<PropertyEditorRegistry> initializer) {\n\t\t\tthis.initializer = initializer;\n\t\t\tthis.matchesOnlyTypeConverter = createTypeConverter();\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\t\treturn Set.of(new ConvertiblePair(String.class, Object.class),\n\t\t\t\t\tnew ConvertiblePair(String.class, Resource[].class),\n\t\t\t\t\tnew ConvertiblePair(String.class, Collection.class));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tClass<?> type = targetType.getType();\n\t\t\tif (type == null || type == Object.class || Map.class.isAssignableFrom(type)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (Collection.class.isAssignableFrom(type)) {\n\t\t\t\tTypeDescriptor elementType = targetType.getElementTypeDescriptor();\n\t\t\t\tif (elementType == null || (!Resource.class.isAssignableFrom(elementType.getType()))) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tPropertyEditor editor = this.matchesOnlyTypeConverter.getDefaultEditor(type);\n\t\t\tif (editor == null) {\n\t\t\t\teditor = this.matchesOnlyTypeConverter.findCustomEditor(type, null);\n\t\t\t}\n\t\t\tif (editor == null && String.class != type) {\n\t\t\t\teditor = BeanUtils.findEditorByConvention(type);\n\t\t\t}\n\t\t\treturn (editor != null && !EXCLUDED_EDITORS.contains(editor.getClass()));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn createTypeConverter().convertIfNecessary(source, targetType.getType(), targetType);\n\t\t}\n\n\t\tprivate SimpleTypeConverter createTypeConverter() {\n\t\t\tSimpleTypeConverter typeConverter = new SimpleTypeConverter();\n\t\t\tif (this.initializer != null) {\n\t\t\t\tthis.initializer.accept(typeConverter);\n\t\t\t}\n\t\t\treturn typeConverter;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\n\n/**\n * Exception thrown when binding fails.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class BindException extends RuntimeException implements OriginProvider {\n\n\tprivate final Bindable<?> target;\n\n\tprivate final @Nullable ConfigurationProperty property;\n\n\tprivate final ConfigurationPropertyName name;\n\n\tBindException(ConfigurationPropertyName name, Bindable<?> target, @Nullable ConfigurationProperty property,\n\t\t\t@Nullable Throwable cause) {\n\t\tsuper(buildMessage(name, target), cause);\n\t\tthis.name = name;\n\t\tthis.target = target;\n\t\tthis.property = property;\n\t}\n\n\t/**\n\t * Return the name of the configuration property being bound.\n\t * @return the configuration property name\n\t */\n\tpublic ConfigurationPropertyName getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the target being bound.\n\t * @return the bind target\n\t */\n\tpublic Bindable<?> getTarget() {\n\t\treturn this.target;\n\t}\n\n\t/**\n\t * Return the configuration property name of the item that was being bound.\n\t * @return the configuration property name\n\t */\n\tpublic @Nullable ConfigurationProperty getProperty() {\n\t\treturn this.property;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn Origin.from(this.name);\n\t}\n\n\tprivate static String buildMessage(@Nullable ConfigurationPropertyName name, Bindable<?> target) {\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\"Failed to bind properties\");\n\t\tmessage.append((name != null) ? \" under '\" + name + \"'\" : \"\");\n\t\tmessage.append(\" to \").append(target.getType());\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\n\n/**\n * Callback interface that can be used to handle additional logic during element\n * {@link Binder binding}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic interface BindHandler {\n\n\t/**\n\t * Default no-op bind handler.\n\t */\n\tBindHandler DEFAULT = new BindHandler() {\n\n\t};\n\n\t/**\n\t * Called when binding of an element starts but before any result has been determined.\n\t * @param <T> the bindable source type\n\t * @param name the name of the element being bound\n\t * @param target the item being bound\n\t * @param context the bind context\n\t * @return the actual item that should be used for binding (may be {@code null})\n\t */\n\tdefault <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {\n\t\treturn target;\n\t}\n\n\t/**\n\t * Called when binding of an element ends with a successful result. Implementations\n\t * may change the ultimately returned result or perform addition validation.\n\t * @param name the name of the element being bound\n\t * @param target the item being bound\n\t * @param context the bind context\n\t * @param result the bound result (never {@code null})\n\t * @return the actual result that should be used (may be {@code null})\n\t */\n\tdefault @Nullable Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tObject result) {\n\t\treturn result;\n\t}\n\n\t/**\n\t * Called when binding of an element ends with an unbound result and a newly created\n\t * instance is about to be returned. Implementations may change the ultimately\n\t * returned result or perform addition validation.\n\t * @param name the name of the element being bound\n\t * @param target the item being bound\n\t * @param context the bind context\n\t * @param result the newly created instance (never {@code null})\n\t * @return the actual result that should be used (must not be {@code null})\n\t * @since 2.2.2\n\t */\n\tdefault Object onCreate(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {\n\t\treturn result;\n\t}\n\n\t/**\n\t * Called when binding fails for any reason (including failures from\n\t * {@link #onSuccess} or {@link #onCreate} calls). Implementations may choose to\n\t * swallow exceptions and return an alternative result.\n\t * @param name the name of the element being bound\n\t * @param target the item being bound\n\t * @param context the bind context\n\t * @param error the cause of the error (if the exception stands it may be re-thrown)\n\t * @return the actual result that should be used (may be {@code null}).\n\t * @throws Exception if the binding isn't valid\n\t */\n\tdefault @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tException error) throws Exception {\n\t\tthrow error;\n\t}\n\n\t/**\n\t * Called when binding finishes with either bound or unbound result. This method will\n\t * not be called when binding failed, even if a handler returns a result from\n\t * {@link #onFailure}.\n\t * @param name the name of the element being bound\n\t * @param target the item being bound\n\t * @param context the bind context\n\t * @param result the bound result (may be {@code null})\n\t * @throws Exception if the binding isn't valid\n\t */\n\tdefault void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t@Nullable Object result) throws Exception {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\n/**\n * Configuration property binding methods.\n *\n * @author Andy Wilkinson\n * @since 3.0.8\n */\npublic enum BindMethod {\n\n\t/**\n\t * Java Bean using getter/setter binding.\n\t */\n\tJAVA_BEAN,\n\n\t/**\n\t * Value object using constructor binding.\n\t */\n\tVALUE_OBJECT\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindResult.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.NoSuchElementException;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A container object to return the result of a {@link Binder} bind operation. May contain\n * either a successfully bound object or an empty result.\n *\n * @param <T> the result type\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic final class BindResult<T> {\n\n\tprivate static final BindResult<?> UNBOUND = new BindResult<>(null);\n\n\tprivate final @Nullable T value;\n\n\tprivate BindResult(@Nullable T value) {\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Return the object that was bound or throw a {@link NoSuchElementException} if no\n\t * value was bound.\n\t * @return the bound value (never {@code null})\n\t * @throws NoSuchElementException if no value was bound\n\t * @see #isBound()\n\t */\n\tpublic T get() throws NoSuchElementException {\n\t\tif (this.value == null) {\n\t\t\tthrow new NoSuchElementException(\"No value bound\");\n\t\t}\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Returns {@code true} if a result was bound.\n\t * @return if a result was bound\n\t */\n\tpublic boolean isBound() {\n\t\treturn (this.value != null);\n\t}\n\n\t/**\n\t * Invoke the specified consumer with the bound value, or do nothing if no value has\n\t * been bound.\n\t * @param consumer block to execute if a value has been bound\n\t */\n\tpublic void ifBound(Consumer<? super T> consumer) {\n\t\tAssert.notNull(consumer, \"'consumer' must not be null\");\n\t\tif (this.value != null) {\n\t\t\tconsumer.accept(this.value);\n\t\t}\n\t}\n\n\t/**\n\t * Apply the provided mapping function to the bound value, or return an updated\n\t * unbound result if no value has been bound.\n\t * @param <U> the type of the result of the mapping function\n\t * @param mapper a mapping function to apply to the bound value. The mapper will not\n\t * be invoked if no value has been bound.\n\t * @return an {@code BindResult} describing the result of applying a mapping function\n\t * to the value of this {@code BindResult}.\n\t */\n\tpublic <U> BindResult<U> map(Function<? super T, ? extends U> mapper) {\n\t\tAssert.notNull(mapper, \"'mapper' must not be null\");\n\t\treturn of((this.value != null) ? mapper.apply(this.value) : null);\n\t}\n\n\t/**\n\t * Return the object that was bound, or {@code other} if no value has been bound.\n\t * @param other the value to be returned if there is no bound value (may be\n\t * {@code null})\n\t * @return the value, if bound, otherwise {@code other}\n\t */\n\t@Contract(\"!null -> !null\")\n\tpublic @Nullable T orElse(@Nullable T other) {\n\t\treturn (this.value != null) ? this.value : other;\n\t}\n\n\t/**\n\t * Return the object that was bound, or the result of invoking {@code other} if no\n\t * value has been bound.\n\t * @param other a {@link Supplier} of the value to be returned if there is no bound\n\t * value\n\t * @return the value, if bound, otherwise the supplied {@code other}\n\t */\n\tpublic T orElseGet(Supplier<? extends T> other) {\n\t\treturn (this.value != null) ? this.value : other.get();\n\t}\n\n\t/**\n\t * Return the object that was bound, or throw an exception to be created by the\n\t * provided supplier if no value has been bound.\n\t * @param <X> the type of the exception to be thrown\n\t * @param exceptionSupplier the supplier which will return the exception to be thrown\n\t * @return the present value\n\t * @throws X if there is no value present\n\t */\n\tpublic <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {\n\t\tif (this.value == null) {\n\t\t\tthrow exceptionSupplier.get();\n\t\t}\n\t\treturn this.value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn ObjectUtils.nullSafeEquals(this.value, ((BindResult<?>) obj).value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHashCode(this.value);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <T> BindResult<T> of(@Nullable T value) {\n\t\tif (value == null) {\n\t\t\treturn (BindResult<T>) UNBOUND;\n\t\t}\n\t\treturn new BindResult<>(value);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Bindable.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Array;\nimport java.util.Arrays;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Source that can be bound by a {@link Binder}.\n *\n * @param <T> the source type\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see Bindable#of(Class)\n * @see Bindable#of(ResolvableType)\n */\npublic final class Bindable<T> {\n\n\tprivate static final Annotation[] NO_ANNOTATIONS = {};\n\n\tprivate static final EnumSet<BindRestriction> NO_BIND_RESTRICTIONS = EnumSet.noneOf(BindRestriction.class);\n\n\tprivate final ResolvableType type;\n\n\tprivate final ResolvableType boxedType;\n\n\tprivate final @Nullable Supplier<T> value;\n\n\tprivate final Annotation[] annotations;\n\n\tprivate final EnumSet<BindRestriction> bindRestrictions;\n\n\tprivate final @Nullable BindMethod bindMethod;\n\n\tprivate Bindable(ResolvableType type, ResolvableType boxedType, @Nullable Supplier<T> value,\n\t\t\tAnnotation[] annotations, EnumSet<BindRestriction> bindRestrictions, @Nullable BindMethod bindMethod) {\n\t\tthis.type = type;\n\t\tthis.boxedType = boxedType;\n\t\tthis.value = value;\n\t\tthis.annotations = annotations;\n\t\tthis.bindRestrictions = bindRestrictions;\n\t\tthis.bindMethod = bindMethod;\n\t}\n\n\t/**\n\t * Return the type of the item to bind.\n\t * @return the type being bound\n\t */\n\tpublic ResolvableType getType() {\n\t\treturn this.type;\n\t}\n\n\t/**\n\t * Return the boxed type of the item to bind.\n\t * @return the boxed type for the item being bound\n\t */\n\tpublic ResolvableType getBoxedType() {\n\t\treturn this.boxedType;\n\t}\n\n\t/**\n\t * Return a supplier that provides the object value or {@code null}.\n\t * @return the value or {@code null}\n\t */\n\tpublic @Nullable Supplier<T> getValue() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Return any associated annotations that could affect binding.\n\t * @return the associated annotations\n\t */\n\tpublic Annotation[] getAnnotations() {\n\t\treturn this.annotations;\n\t}\n\n\t/**\n\t * Return a single associated annotations that could affect binding.\n\t * @param <A> the annotation type\n\t * @param type annotation type\n\t * @return the associated annotation or {@code null}\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <A extends Annotation> @Nullable A getAnnotation(Class<A> type) {\n\t\tfor (Annotation annotation : this.annotations) {\n\t\t\tif (type.isInstance(annotation)) {\n\t\t\t\treturn (A) annotation;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns {@code true} if the specified bind restriction has been added.\n\t * @param bindRestriction the bind restriction to check\n\t * @return if the bind restriction has been added\n\t * @since 2.5.0\n\t */\n\tpublic boolean hasBindRestriction(BindRestriction bindRestriction) {\n\t\treturn this.bindRestrictions.contains(bindRestriction);\n\t}\n\n\t/**\n\t * Returns the {@link BindMethod method} to be used to bind this bindable, or\n\t * {@code null} if no specific binding method is required.\n\t * @return the bind method or {@code null}\n\t * @since 3.0.8\n\t */\n\tpublic @Nullable BindMethod getBindMethod() {\n\t\treturn this.bindMethod;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tBindable<?> other = (Bindable<?>) obj;\n\t\tboolean result = true;\n\t\tresult = result && nullSafeEquals(this.type.resolve(), other.type.resolve());\n\t\tresult = result && nullSafeEquals(this.annotations, other.annotations);\n\t\tresult = result && nullSafeEquals(this.bindRestrictions, other.bindRestrictions);\n\t\tresult = result && nullSafeEquals(this.bindMethod, other.bindMethod);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHash(this.type, this.annotations, this.bindRestrictions, this.bindMethod);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tcreator.append(\"type\", this.type);\n\t\tcreator.append(\"value\", (this.value != null) ? \"provided\" : \"none\");\n\t\tcreator.append(\"annotations\", this.annotations);\n\t\tcreator.append(\"bindMethod\", this.bindMethod);\n\t\treturn creator.toString();\n\t}\n\n\tprivate boolean nullSafeEquals(@Nullable Object o1, @Nullable Object o2) {\n\t\treturn ObjectUtils.nullSafeEquals(o1, o2);\n\t}\n\n\t/**\n\t * Create an updated {@link Bindable} instance with the specified annotations.\n\t * @param annotations the annotations\n\t * @return an updated {@link Bindable}\n\t */\n\tpublic Bindable<T> withAnnotations(Annotation @Nullable ... annotations) {\n\t\treturn new Bindable<>(this.type, this.boxedType, this.value,\n\t\t\t\t(annotations != null) ? annotations : NO_ANNOTATIONS, NO_BIND_RESTRICTIONS, this.bindMethod);\n\t}\n\n\t/**\n\t * Create an updated {@link Bindable} instance with an existing value. Implies that\n\t * Java Bean binding will be used.\n\t * @param existingValue the existing value\n\t * @return an updated {@link Bindable}\n\t */\n\tpublic Bindable<T> withExistingValue(@Nullable T existingValue) {\n\t\tAssert.isTrue(existingValue == null || this.type.isArray() || boxedTypeIsInstanceOf(existingValue),\n\t\t\t\t() -> \"'existingValue' must be an instance of \" + this.type);\n\t\tAssert.state(this.bindMethod != BindMethod.VALUE_OBJECT,\n\t\t\t\t() -> \"An existing value cannot be provided when binding as a value object\");\n\t\tSupplier<T> value = (existingValue != null) ? () -> existingValue : null;\n\t\treturn new Bindable<>(this.type, this.boxedType, value, this.annotations, this.bindRestrictions,\n\t\t\t\tBindMethod.JAVA_BEAN);\n\t}\n\n\tprivate boolean boxedTypeIsInstanceOf(T existingValue) {\n\t\tClass<?> resolved = this.boxedType.resolve();\n\t\treturn resolved != null && resolved.isInstance(existingValue);\n\t}\n\n\t/**\n\t * Create an updated {@link Bindable} instance with a value supplier.\n\t * @param suppliedValue the supplier for the value\n\t * @return an updated {@link Bindable}\n\t */\n\tpublic Bindable<T> withSuppliedValue(@Nullable Supplier<T> suppliedValue) {\n\t\treturn new Bindable<>(this.type, this.boxedType, suppliedValue, this.annotations, this.bindRestrictions,\n\t\t\t\tthis.bindMethod);\n\t}\n\n\t/**\n\t * Create an updated {@link Bindable} instance with additional bind restrictions.\n\t * @param additionalRestrictions any additional restrictions to apply\n\t * @return an updated {@link Bindable}\n\t * @since 2.5.0\n\t */\n\tpublic Bindable<T> withBindRestrictions(BindRestriction... additionalRestrictions) {\n\t\tEnumSet<BindRestriction> bindRestrictions = EnumSet.copyOf(this.bindRestrictions);\n\t\tbindRestrictions.addAll(Arrays.asList(additionalRestrictions));\n\t\treturn new Bindable<>(this.type, this.boxedType, this.value, this.annotations, bindRestrictions,\n\t\t\t\tthis.bindMethod);\n\t}\n\n\t/**\n\t * Create an updated {@link Bindable} instance with a specific bind method. To use\n\t * {@link BindMethod#VALUE_OBJECT value object binding}, the current instance must not\n\t * have an existing or supplied value.\n\t * @param bindMethod the method to use to bind the bindable\n\t * @return an updated {@link Bindable}\n\t * @since 3.0.8\n\t */\n\tpublic Bindable<T> withBindMethod(@Nullable BindMethod bindMethod) {\n\t\tAssert.state(bindMethod != BindMethod.VALUE_OBJECT || this.value == null,\n\t\t\t\t() -> \"Value object binding cannot be used with an existing or supplied value\");\n\t\treturn new Bindable<>(this.type, this.boxedType, this.value, this.annotations, this.bindRestrictions,\n\t\t\t\tbindMethod);\n\t}\n\n\t/**\n\t * Create a new {@link Bindable} of the type of the specified instance with an\n\t * existing value equal to the instance.\n\t * @param <T> the source type\n\t * @param instance the instance (must not be {@code null})\n\t * @return a {@link Bindable} instance\n\t * @see #of(ResolvableType)\n\t * @see #withExistingValue(Object)\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> Bindable<T> ofInstance(T instance) {\n\t\tAssert.notNull(instance, \"'instance' must not be null\");\n\t\tClass<T> type = (Class<T>) instance.getClass();\n\t\treturn of(type).withExistingValue(instance);\n\t}\n\n\t/**\n\t * Create a new {@link Bindable} of the specified type.\n\t * @param <T> the source type\n\t * @param type the type (must not be {@code null})\n\t * @return a {@link Bindable} instance\n\t * @see #of(ResolvableType)\n\t */\n\tpublic static <T> Bindable<T> of(Class<T> type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\treturn of(ResolvableType.forClass(type));\n\t}\n\n\t/**\n\t * Create a new {@link Bindable} {@link List} of the specified element type.\n\t * @param <E> the element type\n\t * @param elementType the list element type\n\t * @return a {@link Bindable} instance\n\t */\n\tpublic static <E> Bindable<List<E>> listOf(Class<E> elementType) {\n\t\treturn of(ResolvableType.forClassWithGenerics(List.class, elementType));\n\t}\n\n\t/**\n\t * Create a new {@link Bindable} {@link Set} of the specified element type.\n\t * @param <E> the element type\n\t * @param elementType the set element type\n\t * @return a {@link Bindable} instance\n\t */\n\tpublic static <E> Bindable<Set<E>> setOf(Class<E> elementType) {\n\t\treturn of(ResolvableType.forClassWithGenerics(Set.class, elementType));\n\t}\n\n\t/**\n\t * Create a new {@link Bindable} {@link Map} of the specified key and value type.\n\t * @param <K> the key type\n\t * @param <V> the value type\n\t * @param keyType the map key type\n\t * @param valueType the map value type\n\t * @return a {@link Bindable} instance\n\t */\n\tpublic static <K, V> Bindable<Map<K, V>> mapOf(Class<K> keyType, Class<V> valueType) {\n\t\treturn of(ResolvableType.forClassWithGenerics(Map.class, keyType, valueType));\n\t}\n\n\t/**\n\t * Create a new {@link Bindable} of the specified type.\n\t * @param <T> the source type\n\t * @param type the type (must not be {@code null})\n\t * @return a {@link Bindable} instance\n\t * @see #of(Class)\n\t */\n\tpublic static <T> Bindable<T> of(ResolvableType type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tResolvableType boxedType = box(type);\n\t\treturn new Bindable<>(type, boxedType, null, NO_ANNOTATIONS, NO_BIND_RESTRICTIONS, null);\n\t}\n\n\tprivate static ResolvableType box(ResolvableType type) {\n\t\tClass<?> resolved = type.resolve();\n\t\tif (resolved != null && resolved.isPrimitive()) {\n\t\t\tObject array = Array.newInstance(resolved, 1);\n\t\t\tClass<?> wrapperType = Array.get(array, 0).getClass();\n\t\t\treturn ResolvableType.forClass(wrapperType);\n\t\t}\n\t\tif (resolved != null && resolved.isArray()) {\n\t\t\treturn ResolvableType.forArrayComponent(box(type.getComponentType()));\n\t\t}\n\t\treturn type;\n\t}\n\n\t/**\n\t * Restrictions that can be applied when binding values.\n\t *\n\t * @since 2.5.0\n\t */\n\tpublic enum BindRestriction {\n\n\t\t/**\n\t\t * Do not bind direct {@link ConfigurationProperty} matches.\n\t\t */\n\t\tNO_DIRECT_PROPERTY\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport kotlin.jvm.JvmClassMappingKt;\nimport kotlin.reflect.KClass;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.context.properties.bind.JavaBeanBinder.BeanProperties;\nimport org.springframework.boot.context.properties.bind.JavaBeanBinder.BeanProperty;\nimport org.springframework.core.KotlinDetector;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link RuntimeHintsRegistrar} that can be used to register {@link ReflectionHints} for\n * {@link Bindable} types, discovering any nested type it may expose through a property.\n * <p>\n * This class can be used as a base-class, or instantiated using the {@code forTypes} and\n * {@code forBindables} factory methods.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Sebastien Deleuze\n * @author Phillip Webb\n * @since 3.0.0\n */\npublic class BindableRuntimeHintsRegistrar implements RuntimeHintsRegistrar {\n\n\tprivate static final Log logger = LogFactory.getLog(BindableRuntimeHintsRegistrar.class);\n\n\tprivate final Bindable<?>[] bindables;\n\n\t/**\n\t * Create a new {@link BindableRuntimeHintsRegistrar} for the specified types.\n\t * @param types the types to process\n\t */\n\tprotected BindableRuntimeHintsRegistrar(Class<?>... types) {\n\t\tthis(Stream.of(types).map(Bindable::of).toArray(Bindable[]::new));\n\t}\n\n\t/**\n\t * Create a new {@link BindableRuntimeHintsRegistrar} for the specified bindables.\n\t * @param bindables the bindables to process\n\t * @since 3.0.8\n\t */\n\tprotected BindableRuntimeHintsRegistrar(Bindable<?>... bindables) {\n\t\tthis.bindables = bindables;\n\t}\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tregisterHints(hints);\n\t}\n\n\t/**\n\t * Contribute hints to the given {@link RuntimeHints} instance.\n\t * @param hints the hints contributed so far for the deployment unit\n\t */\n\tpublic void registerHints(RuntimeHints hints) {\n\t\tfor (Bindable<?> bindable : this.bindables) {\n\t\t\ttry {\n\t\t\t\tnew Processor(bindable).process(hints.reflection());\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlogger.debug(\"Skipping hints for \" + bindable, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Create a new {@link BindableRuntimeHintsRegistrar} for the specified types.\n\t * @param types the types to process\n\t * @return a new {@link BindableRuntimeHintsRegistrar} instance\n\t */\n\tpublic static BindableRuntimeHintsRegistrar forTypes(Iterable<Class<?>> types) {\n\t\tAssert.notNull(types, \"'types' must not be null\");\n\t\treturn forTypes(StreamSupport.stream(types.spliterator(), false).toArray(Class<?>[]::new));\n\t}\n\n\t/**\n\t * Create a new {@link BindableRuntimeHintsRegistrar} for the specified types.\n\t * @param types the types to process\n\t * @return a new {@link BindableRuntimeHintsRegistrar} instance\n\t */\n\tpublic static BindableRuntimeHintsRegistrar forTypes(Class<?>... types) {\n\t\treturn new BindableRuntimeHintsRegistrar(types);\n\t}\n\n\t/**\n\t * Create a new {@link BindableRuntimeHintsRegistrar} for the specified bindables.\n\t * @param bindables the bindables to process\n\t * @return a new {@link BindableRuntimeHintsRegistrar} instance\n\t * @since 3.0.8\n\t */\n\tpublic static BindableRuntimeHintsRegistrar forBindables(Iterable<Bindable<?>> bindables) {\n\t\tAssert.notNull(bindables, \"'bindables' must not be null\");\n\t\treturn forBindables(StreamSupport.stream(bindables.spliterator(), false).toArray(Bindable[]::new));\n\t}\n\n\t/**\n\t * Create a new {@link BindableRuntimeHintsRegistrar} for the specified bindables.\n\t * @param bindables the bindables to process\n\t * @return a new {@link BindableRuntimeHintsRegistrar} instance\n\t * @since 3.0.8\n\t */\n\tpublic static BindableRuntimeHintsRegistrar forBindables(Bindable<?>... bindables) {\n\t\treturn new BindableRuntimeHintsRegistrar(bindables);\n\t}\n\n\t/**\n\t * Processor used to register the hints.\n\t */\n\tprivate static final class Processor {\n\n\t\tprivate final Class<?> type;\n\n\t\tprivate final @Nullable Constructor<?> bindConstructor;\n\n\t\tprivate final BeanProperties bean;\n\n\t\tprivate final Set<Class<?>> seen;\n\n\t\tProcessor(Bindable<?> bindable) {\n\t\t\tthis(bindable, false, new HashSet<>());\n\t\t}\n\n\t\tprivate Processor(Bindable<?> bindable, boolean nestedType, Set<Class<?>> seen) {\n\t\t\tthis.type = getRawClass(bindable);\n\t\t\tthis.bindConstructor = (bindable.getBindMethod() != BindMethod.JAVA_BEAN)\n\t\t\t\t\t? BindConstructorProvider.DEFAULT.getBindConstructor(getBindableType(bindable), nestedType) : null;\n\t\t\tthis.bean = JavaBeanBinder.BeanProperties.of(bindable);\n\t\t\tthis.seen = seen;\n\t\t}\n\n\t\tprivate static Class<?> getBindableType(Bindable<?> bindable) {\n\t\t\tClass<?> resolved = bindable.getType().resolve();\n\t\t\tAssert.state(resolved != null, \"'resolved' must not be null\");\n\t\t\treturn resolved;\n\t\t}\n\n\t\tprivate static Class<?> getRawClass(Bindable<?> bindable) {\n\t\t\tClass<?> rawClass = bindable.getType().getRawClass();\n\t\t\tAssert.state(rawClass != null, \"'rawClass' must not be null\");\n\t\t\treturn rawClass;\n\t\t}\n\n\t\tvoid process(ReflectionHints hints) {\n\t\t\tif (this.seen.contains(this.type)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.seen.add(this.type);\n\t\t\thandleConstructor(hints);\n\t\t\tif (this.bindConstructor != null) {\n\t\t\t\thandleValueObjectProperties(hints);\n\t\t\t}\n\t\t\telse if (this.bean != null && !this.bean.getProperties().isEmpty()) {\n\t\t\t\thandleJavaBeanProperties(hints);\n\t\t\t}\n\t\t}\n\n\t\tprivate void handleConstructor(ReflectionHints hints) {\n\t\t\tif (this.bindConstructor != null) {\n\t\t\t\tif (KotlinDetector.isKotlinType(this.bindConstructor.getDeclaringClass())) {\n\t\t\t\t\tKotlinDelegate.handleConstructor(hints, this.bindConstructor);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\thints.registerConstructor(this.bindConstructor, ExecutableMode.INVOKE);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tArrays.stream(this.type.getDeclaredConstructors())\n\t\t\t\t.filter(this::hasNoParameters)\n\t\t\t\t.findFirst()\n\t\t\t\t.ifPresent((constructor) -> hints.registerConstructor(constructor, ExecutableMode.INVOKE));\n\t\t}\n\n\t\tprivate boolean hasNoParameters(Constructor<?> candidate) {\n\t\t\treturn candidate.getParameterCount() == 0;\n\t\t}\n\n\t\tprivate void handleValueObjectProperties(ReflectionHints hints) {\n\t\t\tAssert.state(this.bindConstructor != null, \"'bindConstructor' must not be null\");\n\t\t\tfor (int i = 0; i < this.bindConstructor.getParameterCount(); i++) {\n\t\t\t\tString propertyName = this.bindConstructor.getParameters()[i].getName();\n\t\t\t\tResolvableType propertyType = ResolvableType.forConstructorParameter(this.bindConstructor, i);\n\t\t\t\thandleProperty(hints, propertyName, propertyType);\n\t\t\t}\n\t\t}\n\n\t\tprivate void handleJavaBeanProperties(ReflectionHints hints) {\n\t\t\tMap<String, BeanProperty> properties = this.bean.getProperties();\n\t\t\tproperties.forEach((name, property) -> {\n\t\t\t\tMethod getter = property.getGetter();\n\t\t\t\tif (getter != null) {\n\t\t\t\t\thints.registerMethod(getter, ExecutableMode.INVOKE);\n\t\t\t\t}\n\t\t\t\tMethod setter = property.getSetter();\n\t\t\t\tif (setter != null) {\n\t\t\t\t\thints.registerMethod(setter, ExecutableMode.INVOKE);\n\t\t\t\t}\n\t\t\t\tField field = property.getField();\n\t\t\t\tif (field != null) {\n\t\t\t\t\thints.registerField(field);\n\t\t\t\t}\n\t\t\t\thandleProperty(hints, name, property.getType());\n\t\t\t});\n\t\t}\n\n\t\tprivate void handleProperty(ReflectionHints hints, String propertyName, ResolvableType propertyType) {\n\t\t\tClass<?> propertyClass = propertyType.resolve();\n\t\t\tif (propertyClass == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (propertyClass.equals(this.type)) {\n\t\t\t\treturn; // Prevent infinite recursion\n\t\t\t}\n\t\t\tClass<?> componentType = getComponentClass(propertyType);\n\t\t\tif (componentType != null) {\n\t\t\t\t// Can be a list of simple types\n\t\t\t\tif (!isJavaType(componentType)) {\n\t\t\t\t\tprocessNested(componentType, hints);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (isNestedType(propertyName, propertyClass)) {\n\t\t\t\tprocessNested(propertyClass, hints);\n\t\t\t}\n\t\t}\n\n\t\tprivate void processNested(Class<?> type, ReflectionHints hints) {\n\t\t\tnew Processor(Bindable.of(type), true, this.seen).process(hints);\n\t\t}\n\n\t\tprivate @Nullable Class<?> getComponentClass(ResolvableType type) {\n\t\t\tResolvableType componentType = getComponentType(type);\n\t\t\tif (componentType == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (isContainer(componentType)) {\n\t\t\t\t// Resolve nested generics like Map<String, List<SomeType>>\n\t\t\t\treturn getComponentClass(componentType);\n\t\t\t}\n\t\t\treturn componentType.toClass();\n\t\t}\n\n\t\tprivate @Nullable ResolvableType getComponentType(ResolvableType type) {\n\t\t\tif (type.isArray()) {\n\t\t\t\treturn type.getComponentType();\n\t\t\t}\n\t\t\tif (isCollection(type)) {\n\t\t\t\treturn type.asCollection().getGeneric();\n\t\t\t}\n\t\t\tif (isMap(type)) {\n\t\t\t\treturn type.asMap().getGeneric(1);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate boolean isContainer(ResolvableType type) {\n\t\t\treturn type.isArray() || isCollection(type) || isMap(type);\n\t\t}\n\n\t\tprivate boolean isCollection(ResolvableType type) {\n\t\t\treturn Collection.class.isAssignableFrom(type.toClass());\n\t\t}\n\n\t\tprivate boolean isMap(ResolvableType type) {\n\t\t\treturn Map.class.isAssignableFrom(type.toClass());\n\t\t}\n\n\t\t/**\n\t\t * Specify whether the specified property refer to a nested type. A nested type\n\t\t * represents a sub-namespace that need to be fully resolved. Nested types are\n\t\t * either inner classes or annotated with {@link NestedConfigurationProperty}.\n\t\t * @param propertyName the name of the property\n\t\t * @param propertyType the type of the property\n\t\t * @return whether the specified {@code propertyType} is a nested type\n\t\t */\n\t\tprivate boolean isNestedType(String propertyName, Class<?> propertyType) {\n\t\t\tClass<?> declaringClass = propertyType.getDeclaringClass();\n\t\t\tif (declaringClass != null && isNested(declaringClass, this.type)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tField field = ReflectionUtils.findField(this.type, propertyName);\n\t\t\treturn (field != null) && MergedAnnotations.from(field).isPresent(Nested.class);\n\t\t}\n\n\t\tprivate static boolean isNested(Class<?> type, Class<?> candidate) {\n\t\t\tif (type.isAssignableFrom(candidate)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn (candidate.getDeclaringClass() != null && isNested(type, candidate.getDeclaringClass()));\n\t\t}\n\n\t\tprivate boolean isJavaType(Class<?> candidate) {\n\t\t\treturn candidate.getPackageName().startsWith(\"java.\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Inner class to avoid a hard dependency on Kotlin at runtime.\n\t */\n\tprivate static final class KotlinDelegate {\n\n\t\tstatic void handleConstructor(ReflectionHints hints, Constructor<?> constructor) {\n\t\t\tKClass<?> kClass = JvmClassMappingKt.getKotlinClass(constructor.getDeclaringClass());\n\t\t\tif (kClass.isData()) {\n\t\t\t\thints.registerType(constructor.getDeclaringClass(), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t\t}\n\t\t\telse {\n\t\t\t\thints.registerConstructor(constructor, ExecutableMode.INVOKE);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Binder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.ArrayDeque;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.PropertyEditorRegistry;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.context.properties.bind.Bindable.BindRestriction;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyCaching;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyState;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.env.Environment;\nimport org.springframework.format.support.DefaultFormattingConversionService;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ConcurrentReferenceHashMap;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A container object which Binds objects from one or more\n * {@link ConfigurationPropertySource ConfigurationPropertySources}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class Binder {\n\n\tprivate static final Set<Class<?>> NON_BEAN_CLASSES = Collections\n\t\t.unmodifiableSet(new HashSet<>(Arrays.asList(Object.class, Class.class)));\n\n\tprivate final Iterable<ConfigurationPropertySource> sources;\n\n\tprivate final PlaceholdersResolver placeholdersResolver;\n\n\tprivate final BindConverter bindConverter;\n\n\tprivate final BindHandler defaultBindHandler;\n\n\tprivate final Map<@Nullable BindMethod, List<DataObjectBinder>> dataObjectBinders;\n\n\tprivate final Map<Object, Object> cache = new ConcurrentReferenceHashMap<>();\n\n\tprivate final ConfigurationPropertyCaching configurationPropertyCaching;\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources. A\n\t * {@link DefaultFormattingConversionService} will be used for all conversion.\n\t * @param sources the sources used for binding\n\t */\n\tpublic Binder(ConfigurationPropertySource... sources) {\n\t\tthis(sourcesAsList(sources), null, null, null);\n\t}\n\n\tprivate static List<ConfigurationPropertySource> sourcesAsList(ConfigurationPropertySource[] sources) {\n\t\tAssert.notNull(sources, \"'sources' must not be null\");\n\t\treturn Arrays.asList(sources);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources. A\n\t * {@link DefaultFormattingConversionService} will be used for all conversion.\n\t * @param sources the sources used for binding\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources) {\n\t\tthis(sources, null, null, null);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources.\n\t * @param sources the sources used for binding\n\t * @param placeholdersResolver strategy to resolve any property placeholders\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources, @Nullable PlaceholdersResolver placeholdersResolver) {\n\t\tthis(sources, placeholdersResolver, null, null);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources.\n\t * @param sources the sources used for binding\n\t * @param placeholdersResolver strategy to resolve any property placeholders\n\t * @param conversionService the conversion service to convert values (or {@code null}\n\t * to use {@link ApplicationConversionService})\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources, @Nullable PlaceholdersResolver placeholdersResolver,\n\t\t\t@Nullable ConversionService conversionService) {\n\t\tthis(sources, placeholdersResolver, conversionService, null);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources.\n\t * @param sources the sources used for binding\n\t * @param placeholdersResolver strategy to resolve any property placeholders\n\t * @param conversionService the conversion service to convert values (or {@code null}\n\t * to use {@link ApplicationConversionService})\n\t * @param propertyEditorInitializer initializer used to configure the property editors\n\t * that can convert values (or {@code null} if no initialization is required). Often\n\t * used to call {@link ConfigurableListableBeanFactory#copyRegisteredEditorsTo}.\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources, @Nullable PlaceholdersResolver placeholdersResolver,\n\t\t\t@Nullable ConversionService conversionService,\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer) {\n\t\tthis(sources, placeholdersResolver, conversionService, propertyEditorInitializer, null);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources.\n\t * @param sources the sources used for binding\n\t * @param placeholdersResolver strategy to resolve any property placeholders\n\t * @param conversionService the conversion service to convert values (or {@code null}\n\t * to use {@link ApplicationConversionService})\n\t * @param propertyEditorInitializer initializer used to configure the property editors\n\t * that can convert values (or {@code null} if no initialization is required). Often\n\t * used to call {@link ConfigurableListableBeanFactory#copyRegisteredEditorsTo}.\n\t * @param defaultBindHandler the default bind handler to use if none is specified when\n\t * binding\n\t * @since 2.2.0\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources, @Nullable PlaceholdersResolver placeholdersResolver,\n\t\t\t@Nullable ConversionService conversionService,\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer,\n\t\t\t@Nullable BindHandler defaultBindHandler) {\n\t\tthis(sources, placeholdersResolver, conversionService, propertyEditorInitializer, defaultBindHandler, null);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources.\n\t * @param sources the sources used for binding\n\t * @param placeholdersResolver strategy to resolve any property placeholders\n\t * @param conversionService the conversion service to convert values (or {@code null}\n\t * to use {@link ApplicationConversionService})\n\t * @param propertyEditorInitializer initializer used to configure the property editors\n\t * that can convert values (or {@code null} if no initialization is required). Often\n\t * used to call {@link ConfigurableListableBeanFactory#copyRegisteredEditorsTo}.\n\t * @param defaultBindHandler the default bind handler to use if none is specified when\n\t * binding\n\t * @param constructorProvider the constructor provider which provides the bind\n\t * constructor to use when binding\n\t * @since 2.2.1\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources, @Nullable PlaceholdersResolver placeholdersResolver,\n\t\t\t@Nullable ConversionService conversionService,\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer,\n\t\t\t@Nullable BindHandler defaultBindHandler, @Nullable BindConstructorProvider constructorProvider) {\n\t\tthis(sources, placeholdersResolver,\n\t\t\t\t(conversionService != null) ? Collections.singletonList(conversionService)\n\t\t\t\t\t\t: (List<ConversionService>) null,\n\t\t\t\tpropertyEditorInitializer, defaultBindHandler, constructorProvider);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance for the specified sources.\n\t * @param sources the sources used for binding\n\t * @param placeholdersResolver strategy to resolve any property placeholders\n\t * @param conversionServices the conversion services to convert values (or\n\t * {@code null} to use {@link ApplicationConversionService})\n\t * @param propertyEditorInitializer initializer used to configure the property editors\n\t * that can convert values (or {@code null} if no initialization is required). Often\n\t * used to call {@link ConfigurableListableBeanFactory#copyRegisteredEditorsTo}.\n\t * @param defaultBindHandler the default bind handler to use if none is specified when\n\t * binding\n\t * @param constructorProvider the constructor provider which provides the bind\n\t * constructor to use when binding\n\t * @since 2.5.0\n\t */\n\tpublic Binder(Iterable<ConfigurationPropertySource> sources, @Nullable PlaceholdersResolver placeholdersResolver,\n\t\t\t@Nullable List<ConversionService> conversionServices,\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer,\n\t\t\t@Nullable BindHandler defaultBindHandler, @Nullable BindConstructorProvider constructorProvider) {\n\t\tAssert.notNull(sources, \"'sources' must not be null\");\n\t\tfor (ConfigurationPropertySource source : sources) {\n\t\t\tAssert.notNull(source, \"'sources' must not contain null elements\");\n\t\t}\n\t\tthis.sources = sources;\n\t\tthis.configurationPropertyCaching = ConfigurationPropertyCaching.get(sources);\n\t\tthis.placeholdersResolver = (placeholdersResolver != null) ? placeholdersResolver : PlaceholdersResolver.NONE;\n\t\tthis.bindConverter = BindConverter.get(conversionServices, propertyEditorInitializer);\n\t\tthis.defaultBindHandler = (defaultBindHandler != null) ? defaultBindHandler : BindHandler.DEFAULT;\n\t\tif (constructorProvider == null) {\n\t\t\tconstructorProvider = BindConstructorProvider.DEFAULT;\n\t\t}\n\t\tValueObjectBinder valueObjectBinder = new ValueObjectBinder(constructorProvider);\n\t\tJavaBeanBinder javaBeanBinder = JavaBeanBinder.INSTANCE;\n\t\tMap<@Nullable BindMethod, List<DataObjectBinder>> dataObjectBinders = new HashMap<>();\n\t\tdataObjectBinders.put(BindMethod.VALUE_OBJECT, List.of(valueObjectBinder));\n\t\tdataObjectBinders.put(BindMethod.JAVA_BEAN, List.of(javaBeanBinder));\n\t\tdataObjectBinders.put(null, List.of(valueObjectBinder, javaBeanBinder));\n\t\tthis.dataObjectBinders = Collections.unmodifiableMap(dataObjectBinders);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Class} using this binder's\n\t * {@link ConfigurationPropertySource property sources}.\n\t * @param name the configuration property name to bind\n\t * @param target the target class\n\t * @param <T> the bound type\n\t * @return the binding result (never {@code null})\n\t * @see #bind(ConfigurationPropertyName, Bindable, BindHandler)\n\t */\n\tpublic <T> BindResult<T> bind(String name, Class<T> target) {\n\t\treturn bind(name, Bindable.of(target));\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param <T> the bound type\n\t * @return the binding result (never {@code null})\n\t * @see #bind(ConfigurationPropertyName, Bindable, BindHandler)\n\t */\n\tpublic <T> BindResult<T> bind(String name, Bindable<T> target) {\n\t\treturn bind(ConfigurationPropertyName.of(name), target, null);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param <T> the bound type\n\t * @return the binding result (never {@code null})\n\t * @see #bind(ConfigurationPropertyName, Bindable, BindHandler)\n\t */\n\tpublic <T> BindResult<T> bind(ConfigurationPropertyName name, Bindable<T> target) {\n\t\treturn bind(name, target, null);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param handler the bind handler (may be {@code null})\n\t * @param <T> the bound type\n\t * @return the binding result (never {@code null})\n\t */\n\tpublic <T> BindResult<T> bind(String name, Bindable<T> target, @Nullable BindHandler handler) {\n\t\treturn bind(ConfigurationPropertyName.of(name), target, handler);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param handler the bind handler (may be {@code null})\n\t * @param <T> the bound type\n\t * @return the binding result (never {@code null})\n\t */\n\tpublic <T> BindResult<T> bind(ConfigurationPropertyName name, Bindable<T> target, @Nullable BindHandler handler) {\n\t\tT bound = bind(name, target, handler, false);\n\t\treturn BindResult.of(bound);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Class} using this binder's\n\t * {@link ConfigurationPropertySource property sources} or create a new instance of\n\t * the specified target {@link Class} if the result of the binding is {@code null}.\n\t * @param name the configuration property name to bind\n\t * @param target the target class\n\t * @param <T> the bound type\n\t * @return the bound or created object\n\t * @since 2.2.0\n\t * @see #bind(ConfigurationPropertyName, Bindable, BindHandler)\n\t */\n\tpublic <T> T bindOrCreate(String name, Class<T> target) {\n\t\treturn bindOrCreate(name, Bindable.of(target));\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources} or create a new instance using\n\t * the type of the {@link Bindable} if the result of the binding is {@code null}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param <T> the bound type\n\t * @return the bound or created object\n\t * @since 2.2.0\n\t * @see #bindOrCreate(ConfigurationPropertyName, Bindable, BindHandler)\n\t */\n\tpublic <T> T bindOrCreate(String name, Bindable<T> target) {\n\t\treturn bindOrCreate(ConfigurationPropertyName.of(name), target, null);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources} or create a new instance using\n\t * the type of the {@link Bindable} if the result of the binding is {@code null}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param handler the bind handler\n\t * @param <T> the bound type\n\t * @return the bound or created object\n\t * @since 2.2.0\n\t * @see #bindOrCreate(ConfigurationPropertyName, Bindable, BindHandler)\n\t */\n\tpublic <T> T bindOrCreate(String name, Bindable<T> target, BindHandler handler) {\n\t\treturn bindOrCreate(ConfigurationPropertyName.of(name), target, handler);\n\t}\n\n\t/**\n\t * Bind the specified target {@link Bindable} using this binder's\n\t * {@link ConfigurationPropertySource property sources} or create a new instance using\n\t * the type of the {@link Bindable} if the result of the binding is {@code null}.\n\t * @param name the configuration property name to bind\n\t * @param target the target bindable\n\t * @param handler the bind handler (may be {@code null})\n\t * @param <T> the bound or created type\n\t * @return the bound or created object\n\t * @since 2.2.0\n\t */\n\t@SuppressWarnings(\"NullAway\") // https://github.com/uber/NullAway/issues/1232\n\tpublic <T> T bindOrCreate(ConfigurationPropertyName name, Bindable<T> target, @Nullable BindHandler handler) {\n\t\treturn bind(name, target, handler, true);\n\t}\n\n\t@Contract(\"_, _, _, true -> !null\")\n\tprivate <T> @Nullable T bind(ConfigurationPropertyName name, Bindable<T> target, @Nullable BindHandler handler,\n\t\t\tboolean create) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(target, \"'target' must not be null\");\n\t\thandler = (handler != null) ? handler : this.defaultBindHandler;\n\t\tContext context = new Context();\n\t\treturn bind(name, target, handler, context, false, create);\n\t}\n\n\t@Contract(\"_, _, _, _, _, true -> !null\")\n\tprivate <T> @Nullable T bind(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,\n\t\t\tContext context, boolean allowRecursiveBinding, boolean create) {\n\t\ttry (ConfigurationPropertyCaching.CacheOverride cacheOverride = this.configurationPropertyCaching.override()) {\n\t\t\ttry {\n\t\t\t\tBindable<T> replacementTarget = handler.onStart(name, target, context);\n\t\t\t\tif (replacementTarget == null) {\n\t\t\t\t\treturn handleBindResult(name, target, handler, context, null, create);\n\t\t\t\t}\n\t\t\t\ttarget = replacementTarget;\n\t\t\t\tObject bound = bindObject(name, target, handler, context, allowRecursiveBinding);\n\t\t\t\treturn handleBindResult(name, target, handler, context, bound, create);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn handleBindError(name, target, handler, context, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Contract(\"_, _, _, _, _, true -> null\")\n\tprivate <T> @Nullable T handleBindResult(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,\n\t\t\tContext context, @Nullable Object result, boolean create) throws Exception {\n\t\tif (result != null) {\n\t\t\tresult = handler.onSuccess(name, target, context, result);\n\t\t\tresult = context.getConverter().convert(result, target);\n\t\t}\n\t\tif (result == null && create) {\n\t\t\tresult = fromDataObjectBinders(target.getBindMethod(),\n\t\t\t\t\t(dataObjectBinder) -> dataObjectBinder.create(target, context));\n\t\t\tif (result == null) {\n\t\t\t\tIllegalStateException ex = new IllegalStateException(\n\t\t\t\t\t\t\"Unable to create instance for \" + target.getType());\n\t\t\t\tList<DataObjectBinder> dataObjectBinders = this.dataObjectBinders.get(target.getBindMethod());\n\t\t\t\tAssert.state(dataObjectBinders != null, \"'dataObjectBinders' must not be null\");\n\t\t\t\tdataObjectBinders\n\t\t\t\t\t.forEach((dataObjectBinder) -> dataObjectBinder.onUnableToCreateInstance(target, context, ex));\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tresult = handler.onCreate(name, target, context, result);\n\t\t\tresult = context.getConverter().convert(result, target);\n\t\t}\n\t\thandler.onFinish(name, target, context, result);\n\t\treturn context.getConverter().convert(result, target);\n\t}\n\n\tprivate <T> @Nullable T handleBindError(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,\n\t\t\tContext context, Exception error) {\n\t\ttry {\n\t\t\tObject result = handler.onFailure(name, target, context, error);\n\t\t\treturn context.getConverter().convert(result, target);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof BindException bindException) {\n\t\t\t\tthrow bindException;\n\t\t\t}\n\t\t\tthrow new BindException(name, target, context.getConfigurationProperty(), ex);\n\t\t}\n\t}\n\n\tprivate <T> @Nullable Object bindObject(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,\n\t\t\tContext context, boolean allowRecursiveBinding) {\n\t\tConfigurationProperty property = findProperty(name, target, context);\n\t\tif (property == null && context.depth != 0 && containsNoDescendantOf(context.getSources(), name)) {\n\t\t\treturn null;\n\t\t}\n\t\tAggregateBinder<?> aggregateBinder = getAggregateBinder(target, context);\n\t\tif (aggregateBinder != null) {\n\t\t\treturn bindAggregate(name, target, handler, context, aggregateBinder);\n\t\t}\n\t\tif (property != null) {\n\t\t\ttry {\n\t\t\t\treturn bindProperty(target, context, property);\n\t\t\t}\n\t\t\tcatch (ConverterNotFoundException ex) {\n\t\t\t\t// We might still be able to bind it using the recursive binders\n\t\t\t\tboolean fallbackToDefaultValue = ObjectUtils.isEmpty(property.getValue());\n\t\t\t\tObject instance = bindDataObject(name, target, handler, context, allowRecursiveBinding,\n\t\t\t\t\t\tfallbackToDefaultValue);\n\t\t\t\tif (instance != null) {\n\t\t\t\t\treturn instance;\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t\treturn bindDataObject(name, target, handler, context, allowRecursiveBinding, false);\n\t}\n\n\tprivate @Nullable AggregateBinder<?> getAggregateBinder(Bindable<?> target, Context context) {\n\t\tClass<?> resolvedType = target.getType().resolve(Object.class);\n\t\tif (Map.class.isAssignableFrom(resolvedType)) {\n\t\t\treturn new MapBinder(context);\n\t\t}\n\t\tif (Collection.class.isAssignableFrom(resolvedType)) {\n\t\t\treturn new CollectionBinder(context);\n\t\t}\n\t\tif (target.getType().isArray()) {\n\t\t\treturn new ArrayBinder(context);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate <T> @Nullable Object bindAggregate(ConfigurationPropertyName name, Bindable<T> target, BindHandler handler,\n\t\t\tContext context, AggregateBinder<?> aggregateBinder) {\n\t\tAggregateElementBinder elementBinder = (itemName, itemTarget, source) -> {\n\t\t\tboolean allowRecursiveBinding = aggregateBinder.isAllowRecursiveBinding(source);\n\t\t\tSupplier<?> supplier = () -> bind(itemName, itemTarget, handler, context, allowRecursiveBinding, false);\n\t\t\treturn context.withSource(source, supplier);\n\t\t};\n\t\tSupplier<@Nullable Object> supplier = () -> aggregateBinder.bind(name, target, elementBinder);\n\t\treturn context.withIncreasedDepth(supplier);\n\t}\n\n\tprivate <T> @Nullable ConfigurationProperty findProperty(ConfigurationPropertyName name, Bindable<T> target,\n\t\t\tContext context) {\n\t\tif (name.isEmpty() || target.hasBindRestriction(BindRestriction.NO_DIRECT_PROPERTY)) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (ConfigurationPropertySource source : context.getSources()) {\n\t\t\tConfigurationProperty property = source.getConfigurationProperty(name);\n\t\t\tif (property != null) {\n\t\t\t\treturn property;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate <T> @Nullable Object bindProperty(Bindable<T> target, Context context, ConfigurationProperty property) {\n\t\tcontext.setConfigurationProperty(property);\n\t\tObject result = property.getValue();\n\t\tresult = this.placeholdersResolver.resolvePlaceholders(result);\n\t\tresult = context.getConverter().convert(result, target);\n\t\treturn result;\n\t}\n\n\tprivate @Nullable Object bindDataObject(ConfigurationPropertyName name, Bindable<?> target, BindHandler handler,\n\t\t\tContext context, boolean allowRecursiveBinding, boolean fallbackToDefaultValue) {\n\t\tif (isUnbindableBean(name, target, context)) {\n\t\t\treturn null;\n\t\t}\n\t\tClass<?> type = target.getType().resolve(Object.class);\n\t\tBindMethod bindMethod = target.getBindMethod();\n\t\tif (!allowRecursiveBinding && context.isBindingDataObject(type)) {\n\t\t\treturn null;\n\t\t}\n\t\tDataObjectPropertyBinder propertyBinder = (propertyName, propertyTarget) -> bind(name.append(propertyName),\n\t\t\t\tpropertyTarget, handler, context, false, false);\n\t\tSupplier<@Nullable Object> supplier = () -> fromDataObjectBinders(bindMethod,\n\t\t\t\t(dataObjectBinder) -> dataObjectBinder.bind(name, target, context, propertyBinder,\n\t\t\t\t\t\tfallbackToDefaultValue));\n\t\treturn context.withDataObject(type, supplier);\n\t}\n\n\tprivate @Nullable Object fromDataObjectBinders(@Nullable BindMethod bindMethod,\n\t\t\tFunction<DataObjectBinder, @Nullable Object> operation) {\n\t\tList<DataObjectBinder> dataObjectBinders = this.dataObjectBinders.get(bindMethod);\n\t\tAssert.state(dataObjectBinders != null, \"'dataObjectBinders' must not be null\");\n\t\tfor (DataObjectBinder dataObjectBinder : dataObjectBinders) {\n\t\t\tObject bound = operation.apply(dataObjectBinder);\n\t\t\tif (bound != null) {\n\t\t\t\treturn bound;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isUnbindableBean(ConfigurationPropertyName name, Bindable<?> target, Context context) {\n\t\tfor (ConfigurationPropertySource source : context.getSources()) {\n\t\t\tif (source.containsDescendantOf(name) == ConfigurationPropertyState.PRESENT) {\n\t\t\t\t// We know there are properties to bind so we can't bypass anything\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tClass<?> resolved = target.getType().resolve(Object.class);\n\t\tif (resolved.isPrimitive() || NON_BEAN_CLASSES.contains(resolved)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn resolved.getName().startsWith(\"java.\");\n\t}\n\n\tprivate boolean containsNoDescendantOf(Iterable<ConfigurationPropertySource> sources,\n\t\t\tConfigurationPropertyName name) {\n\t\tfor (ConfigurationPropertySource source : sources) {\n\t\t\tif (source.containsDescendantOf(name) != ConfigurationPropertyState.ABSENT) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance from the specified environment.\n\t * @param environment the environment source (must have attached\n\t * {@link ConfigurationPropertySources})\n\t * @return a {@link Binder} instance\n\t */\n\tpublic static Binder get(Environment environment) {\n\t\treturn get(environment, null);\n\t}\n\n\t/**\n\t * Create a new {@link Binder} instance from the specified environment.\n\t * @param environment the environment source (must have attached\n\t * {@link ConfigurationPropertySources})\n\t * @param defaultBindHandler the default bind handler to use if none is specified when\n\t * binding\n\t * @return a {@link Binder} instance\n\t * @since 2.2.0\n\t */\n\tpublic static Binder get(Environment environment, @Nullable BindHandler defaultBindHandler) {\n\t\tIterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);\n\t\tPropertySourcesPlaceholdersResolver placeholdersResolver = new PropertySourcesPlaceholdersResolver(environment);\n\t\treturn new Binder(sources, placeholdersResolver, null, null, defaultBindHandler);\n\t}\n\n\t/**\n\t * Context used when binding and the {@link BindContext} implementation.\n\t */\n\tfinal class Context implements BindContext {\n\n\t\tprivate int depth;\n\n\t\tprivate final List<ConfigurationPropertySource> source = Arrays.asList((ConfigurationPropertySource) null);\n\n\t\tprivate int sourcePushCount;\n\n\t\tprivate final Deque<Class<?>> dataObjectBindings = new ArrayDeque<>();\n\n\t\tprivate final Deque<Class<?>> constructorBindings = new ArrayDeque<>();\n\n\t\tprivate @Nullable ConfigurationProperty configurationProperty;\n\n\t\tprivate void increaseDepth() {\n\t\t\tthis.depth++;\n\t\t}\n\n\t\tprivate void decreaseDepth() {\n\t\t\tthis.depth--;\n\t\t}\n\n\t\tprivate <T> T withSource(@Nullable ConfigurationPropertySource source, Supplier<T> supplier) {\n\t\t\tif (source == null) {\n\t\t\t\treturn supplier.get();\n\t\t\t}\n\t\t\tConfigurationPropertySource previous = this.source.get(0);\n\t\t\tthis.source.set(0, source);\n\t\t\tthis.sourcePushCount++;\n\t\t\ttry {\n\t\t\t\treturn supplier.get();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.sourcePushCount--;\n\t\t\t\tthis.source.set(0, previous);\n\t\t\t}\n\t\t}\n\n\t\tprivate <T> @Nullable T withDataObject(Class<?> type, Supplier<@Nullable T> supplier) {\n\t\t\tthis.dataObjectBindings.push(type);\n\t\t\ttry {\n\t\t\t\treturn withIncreasedDepth(supplier);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.dataObjectBindings.pop();\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isBindingDataObject(Class<?> type) {\n\t\t\treturn this.dataObjectBindings.contains(type);\n\t\t}\n\n\t\tprivate <T> @Nullable T withIncreasedDepth(Supplier<@Nullable T> supplier) {\n\t\t\tincreaseDepth();\n\t\t\ttry {\n\t\t\t\treturn supplier.get();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tdecreaseDepth();\n\t\t\t}\n\t\t}\n\n\t\tvoid setConfigurationProperty(ConfigurationProperty configurationProperty) {\n\t\t\tthis.configurationProperty = configurationProperty;\n\t\t}\n\n\t\tvoid clearConfigurationProperty() {\n\t\t\tthis.configurationProperty = null;\n\t\t}\n\n\t\tvoid pushConstructorBoundTypes(Class<?> value) {\n\t\t\tthis.constructorBindings.push(value);\n\t\t}\n\n\t\tboolean isNestedConstructorBinding() {\n\t\t\treturn !this.constructorBindings.isEmpty();\n\t\t}\n\n\t\tvoid popConstructorBoundTypes() {\n\t\t\tthis.constructorBindings.pop();\n\t\t}\n\n\t\tPlaceholdersResolver getPlaceholdersResolver() {\n\t\t\treturn Binder.this.placeholdersResolver;\n\t\t}\n\n\t\tBindConverter getConverter() {\n\t\t\treturn Binder.this.bindConverter;\n\t\t}\n\n\t\tMap<Object, Object> getCache() {\n\t\t\treturn Binder.this.cache;\n\t\t}\n\n\t\t@Override\n\t\tpublic Binder getBinder() {\n\t\t\treturn Binder.this;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getDepth() {\n\t\t\treturn this.depth;\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterable<ConfigurationPropertySource> getSources() {\n\t\t\tif (this.sourcePushCount > 0) {\n\t\t\t\treturn this.source;\n\t\t\t}\n\t\t\treturn Binder.this.sources;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConfigurationProperty getConfigurationProperty() {\n\t\t\treturn this.configurationProperty;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BoundPropertiesTrackingBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.util.Assert;\n\n/**\n * {@link BindHandler} that can be used to track bound configuration properties.\n *\n * @author Madhura Bhave\n * @since 2.3.0\n */\npublic class BoundPropertiesTrackingBindHandler extends AbstractBindHandler {\n\n\tprivate final Consumer<ConfigurationProperty> consumer;\n\n\tpublic BoundPropertiesTrackingBindHandler(Consumer<ConfigurationProperty> consumer) {\n\t\tAssert.notNull(consumer, \"'consumer' must not be null\");\n\t\tthis.consumer = consumer;\n\t}\n\n\t@Override\n\tpublic @Nullable Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tObject result) {\n\t\tif (context.getConfigurationProperty() != null && name.equals(context.getConfigurationProperty().getName())) {\n\t\t\tthis.consumer.accept(context.getConfigurationProperty());\n\t\t}\n\t\treturn super.onSuccess(name, target, context, result);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/CollectionBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.core.ResolvableType;\n\n/**\n * {@link AggregateBinder} for collections.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass CollectionBinder extends IndexedElementsBinder<Collection<Object>> {\n\n\tCollectionBinder(Context context) {\n\t\tsuper(context);\n\t}\n\n\t@Override\n\tprotected @Nullable Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder) {\n\t\tResolvableType aggregateType = ResolvableType.forClassWithGenerics(List.class,\n\t\t\t\ttarget.getType().asCollection().getGenerics());\n\t\tResolvableType elementType = target.getType().asCollection().getGeneric();\n\t\tIndexedCollectionSupplier result = new IndexedCollectionSupplier(\n\t\t\t\t() -> CollectionFactory.createCollection(List.class, elementType.resolve(), 0));\n\t\tbindIndexed(name, target, elementBinder, aggregateType, elementType, result);\n\t\tif (result.wasSupplied()) {\n\t\t\treturn result.get();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected Collection<Object> merge(Supplier<Collection<Object>> existing, Collection<Object> additional) {\n\t\tCollection<Object> existingCollection = getExistingIfPossible(existing);\n\t\tif (existingCollection == null) {\n\t\t\treturn additional;\n\t\t}\n\t\ttry {\n\t\t\texistingCollection.clear();\n\t\t\texistingCollection.addAll(additional);\n\t\t\treturn copyIfPossible(existingCollection);\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\treturn createNewCollection(additional);\n\t\t}\n\t}\n\n\tprivate @Nullable Collection<Object> getExistingIfPossible(Supplier<Collection<Object>> existing) {\n\t\ttry {\n\t\t\treturn existing.get();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate Collection<Object> copyIfPossible(Collection<Object> collection) {\n\t\ttry {\n\t\t\treturn createNewCollection(collection);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn collection;\n\t\t}\n\t}\n\n\tprivate Collection<Object> createNewCollection(Collection<Object> collection) {\n\t\tCollection<Object> result = CollectionFactory.createCollection(collection.getClass(), collection.size());\n\t\tresult.addAll(collection);\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ConstructorBinding.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation that can be used to indicate which constructor to use when binding\n * configuration properties using constructor arguments rather than by calling setters. A\n * single parameterized constructor implicitly indicates that constructor binding should\n * be used unless the constructor is annotated with {@code @Autowired}.\n *\n * @author Phillip Webb\n * @since 3.0.0\n */\n@Target({ ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface ConstructorBinding {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DataObjectBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\n\n/**\n * Internal strategy used by {@link Binder} to bind data objects. A data object is an\n * object composed itself of recursively bound properties.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see JavaBeanBinder\n * @see ValueObjectBinder\n */\ninterface DataObjectBinder {\n\n\t/**\n\t * Return a bound instance or {@code null} if the {@link DataObjectBinder} does not\n\t * support the specified {@link Bindable}.\n\t * @param <T> the source type\n\t * @param name the name being bound\n\t * @param target the bindable to bind\n\t * @param context the bind context\n\t * @param propertyBinder property binder\n\t * @param fallbackToDefaultValue if an attempt should be made to return a new default\n\t * value when no values are bound\n\t * @return a bound instance or {@code null}\n\t */\n\t<T> @Nullable T bind(ConfigurationPropertyName name, Bindable<T> target, Context context,\n\t\t\tDataObjectPropertyBinder propertyBinder, boolean fallbackToDefaultValue);\n\n\t/**\n\t * Return a newly created instance or {@code null} if the {@link DataObjectBinder}\n\t * does not support the specified {@link Bindable}.\n\t * @param <T> the source type\n\t * @param target the bindable to create\n\t * @param context the bind context\n\t * @return the created instance\n\t */\n\t<T> @Nullable T create(Bindable<T> target, Context context);\n\n\t/**\n\t * Callback that can be used to add additional suppressed exceptions when an instance\n\t * cannot be created.\n\t * @param <T> the source type\n\t * @param target the bindable that was being created\n\t * @param context the bind context\n\t * @param exception the exception about to be thrown\n\t */\n\tdefault <T> void onUnableToCreateInstance(Bindable<T> target, Context context, RuntimeException exception) {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DataObjectPropertyBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Binder that can be used by {@link DataObjectBinder} implementations to bind the data\n * object properties.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\ninterface DataObjectPropertyBinder {\n\n\t/**\n\t * Bind the given property.\n\t * @param propertyName the property name (in lowercase dashed form, e.g.\n\t * {@code first-name})\n\t * @param target the target bindable\n\t * @return the bound value or {@code null}\n\t */\n\t@Nullable Object bindProperty(String propertyName, Bindable<?> target);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DataObjectPropertyName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\n/**\n * Internal utility to help when dealing with data object property names.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.2.3\n * @see DataObjectBinder\n */\npublic abstract class DataObjectPropertyName {\n\n\tprivate DataObjectPropertyName() {\n\t}\n\n\t/**\n\t * Return the specified Java Bean property name in dashed form.\n\t * @param name the source name\n\t * @return the dashed from\n\t */\n\tpublic static String toDashedForm(String name) {\n\t\tStringBuilder result = new StringBuilder(name.length());\n\t\tboolean inIndex = false;\n\t\tfor (int i = 0; i < name.length(); i++) {\n\t\t\tchar ch = name.charAt(i);\n\t\t\tif (inIndex) {\n\t\t\t\tresult.append(ch);\n\t\t\t\tif (ch == ']') {\n\t\t\t\t\tinIndex = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (ch == '[') {\n\t\t\t\t\tinIndex = true;\n\t\t\t\t\tresult.append(ch);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tch = (ch != '_') ? ch : '-';\n\t\t\t\t\tif (Character.isUpperCase(ch) && !result.isEmpty() && result.charAt(result.length() - 1) != '-') {\n\t\t\t\t\t\tresult.append('-');\n\t\t\t\t\t}\n\t\t\t\t\tresult.append(Character.toLowerCase(ch));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DefaultBindConstructorProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.KotlinDetector;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Default {@link BindConstructorProvider} implementation.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass DefaultBindConstructorProvider implements BindConstructorProvider {\n\n\t@Override\n\tpublic @Nullable Constructor<?> getBindConstructor(Bindable<?> bindable, boolean isNestedConstructorBinding) {\n\t\tConstructors constructors = Constructors.getConstructors(bindable.getType().resolve(),\n\t\t\t\tisNestedConstructorBinding);\n\t\tif (constructors.getBind() != null && constructors.isDeducedBindConstructor()\n\t\t\t\t&& !constructors.isImmutableType()) {\n\t\t\tif (bindable.getValue() != null && bindable.getValue().get() != null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn constructors.getBind();\n\t}\n\n\t@Override\n\tpublic @Nullable Constructor<?> getBindConstructor(Class<?> type, boolean isNestedConstructorBinding) {\n\t\tConstructors constructors = Constructors.getConstructors(type, isNestedConstructorBinding);\n\t\treturn constructors.getBind();\n\t}\n\n\t/**\n\t * Data holder for autowired and bind constructors.\n\t */\n\tstatic final class Constructors {\n\n\t\tprivate static final Constructors NONE = new Constructors(false, null, false, false);\n\n\t\tprivate final boolean hasAutowired;\n\n\t\tprivate final @Nullable Constructor<?> bind;\n\n\t\tprivate final boolean deducedBindConstructor;\n\n\t\tprivate final boolean immutableType;\n\n\t\tprivate Constructors(boolean hasAutowired, @Nullable Constructor<?> bind, boolean deducedBindConstructor,\n\t\t\t\tboolean immutableType) {\n\t\t\tthis.hasAutowired = hasAutowired;\n\t\t\tthis.bind = bind;\n\t\t\tthis.deducedBindConstructor = deducedBindConstructor;\n\t\t\tthis.immutableType = immutableType;\n\t\t}\n\n\t\tboolean hasAutowired() {\n\t\t\treturn this.hasAutowired;\n\t\t}\n\n\t\t@Nullable Constructor<?> getBind() {\n\t\t\treturn this.bind;\n\t\t}\n\n\t\tboolean isDeducedBindConstructor() {\n\t\t\treturn this.deducedBindConstructor;\n\t\t}\n\n\t\tboolean isImmutableType() {\n\t\t\treturn this.immutableType;\n\t\t}\n\n\t\tstatic Constructors getConstructors(@Nullable Class<?> type, boolean isNestedConstructorBinding) {\n\t\t\tif (type == null) {\n\t\t\t\treturn NONE;\n\t\t\t}\n\t\t\tboolean hasAutowiredConstructor = isAutowiredPresent(type);\n\t\t\tConstructor<?>[] candidates = getCandidateConstructors(type);\n\t\t\tMergedAnnotations[] candidateAnnotations = getAnnotations(candidates);\n\t\t\tboolean deducedBindConstructor = false;\n\t\t\tboolean immutableType = type.isRecord();\n\t\t\tConstructor<?> bind = getConstructorBindingAnnotated(type, candidates, candidateAnnotations);\n\t\t\tif (bind == null && !hasAutowiredConstructor) {\n\t\t\t\tbind = deduceBindConstructor(type, candidates);\n\t\t\t\tdeducedBindConstructor = bind != null;\n\t\t\t}\n\t\t\tif (bind == null && !hasAutowiredConstructor && isKotlinType(type)) {\n\t\t\t\tbind = deduceKotlinBindConstructor(type);\n\t\t\t\tdeducedBindConstructor = bind != null;\n\t\t\t}\n\t\t\tif (bind != null || isNestedConstructorBinding) {\n\t\t\t\tAssert.state(!hasAutowiredConstructor,\n\t\t\t\t\t\t() -> type.getName() + \" declares @ConstructorBinding and @Autowired constructor\");\n\t\t\t}\n\t\t\treturn new Constructors(hasAutowiredConstructor, bind, deducedBindConstructor, immutableType);\n\t\t}\n\n\t\tprivate static boolean isAutowiredPresent(Class<?> type) {\n\t\t\tif (Stream.of(type.getDeclaredConstructors())\n\t\t\t\t.map(MergedAnnotations::from)\n\t\t\t\t.anyMatch((annotations) -> annotations.isPresent(Autowired.class))) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tClass<?> userClass = ClassUtils.getUserClass(type);\n\t\t\treturn (userClass != type) && isAutowiredPresent(userClass);\n\t\t}\n\n\t\tprivate static Constructor<?>[] getCandidateConstructors(Class<?> type) {\n\t\t\tif (isInnerClass(type)) {\n\t\t\t\treturn new Constructor<?>[0];\n\t\t\t}\n\t\t\treturn Arrays.stream(type.getDeclaredConstructors())\n\t\t\t\t.filter(Constructors::isNonSynthetic)\n\t\t\t\t.toArray(Constructor[]::new);\n\t\t}\n\n\t\tprivate static boolean isInnerClass(Class<?> type) {\n\t\t\ttry {\n\t\t\t\treturn type.getDeclaredField(\"this$0\").isSynthetic();\n\t\t\t}\n\t\t\tcatch (NoSuchFieldException ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tprivate static boolean isNonSynthetic(Constructor<?> constructor) {\n\t\t\treturn !constructor.isSynthetic();\n\t\t}\n\n\t\tprivate static MergedAnnotations[] getAnnotations(Constructor<?>[] candidates) {\n\t\t\tMergedAnnotations[] candidateAnnotations = new MergedAnnotations[candidates.length];\n\t\t\tfor (int i = 0; i < candidates.length; i++) {\n\t\t\t\tcandidateAnnotations[i] = MergedAnnotations.from(candidates[i], SearchStrategy.SUPERCLASS);\n\t\t\t}\n\t\t\treturn candidateAnnotations;\n\t\t}\n\n\t\tprivate static @Nullable Constructor<?> getConstructorBindingAnnotated(Class<?> type,\n\t\t\t\tConstructor<?>[] candidates, MergedAnnotations[] mergedAnnotations) {\n\t\t\tConstructor<?> result = null;\n\t\t\tfor (int i = 0; i < candidates.length; i++) {\n\t\t\t\tif (mergedAnnotations[i].isPresent(ConstructorBinding.class)) {\n\t\t\t\t\tAssert.state(candidates[i].getParameterCount() > 0,\n\t\t\t\t\t\t\t() -> type.getName() + \" declares @ConstructorBinding on a no-args constructor\");\n\t\t\t\t\tAssert.state(result == null,\n\t\t\t\t\t\t\t() -> type.getName() + \" has more than one @ConstructorBinding constructor\");\n\t\t\t\t\tresult = candidates[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\n\t\t}\n\n\t\tprivate static @Nullable Constructor<?> deduceBindConstructor(Class<?> type, Constructor<?>[] candidates) {\n\t\t\tif (candidates.length == 1 && candidates[0].getParameterCount() > 0) {\n\t\t\t\tif (type.isMemberClass() && Modifier.isPrivate(candidates[0].getModifiers())) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\treturn candidates[0];\n\t\t\t}\n\t\t\tConstructor<?> result = null;\n\t\t\tfor (Constructor<?> candidate : candidates) {\n\t\t\t\tif (!Modifier.isPrivate(candidate.getModifiers())) {\n\t\t\t\t\tif (result != null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tresult = candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn (result != null && result.getParameterCount() > 0) ? result : null;\n\t\t}\n\n\t\tprivate static boolean isKotlinType(Class<?> type) {\n\t\t\treturn KotlinDetector.isKotlinPresent() && KotlinDetector.isKotlinType(type);\n\t\t}\n\n\t\tprivate static @Nullable Constructor<?> deduceKotlinBindConstructor(Class<?> type) {\n\t\t\tConstructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(type);\n\t\t\tif (primaryConstructor != null && primaryConstructor.getParameterCount() > 0) {\n\t\t\t\treturn primaryConstructor;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/DefaultValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation that can be used to specify the default value when binding to an immutable\n * property. This annotation can also be used with nested properties to indicate that a\n * value should always be bound (rather than binding {@code null}). The value from this\n * annotation will only be used if the property is not found in the property sources used\n * by the {@link Binder}. For example, if the property is present in the\n * {@link org.springframework.core.env.Environment} when binding to\n * {@link org.springframework.boot.context.properties.ConfigurationProperties @ConfigurationProperties},\n * the default value for the property will not be used even if the property value is\n * empty.\n * <p>\n * NOTE: This annotation does not support property placeholder resolution and the value\n * must be constant.\n *\n * @author Madhura Bhave\n * @author Pavel Anisimov\n * @since 2.2.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.PARAMETER })\n@Documented\npublic @interface DefaultValue {\n\n\t/**\n\t * The default value of the property. Can be an array of values for collection or\n\t * array-based properties.\n\t * @return the default value of the property.\n\t */\n\tString[] value() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/IndexedElementsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.IterableConfigurationPropertySource;\nimport org.springframework.core.ResolvableType;\n\n/**\n * Base class for {@link AggregateBinder AggregateBinders} that read a sequential run of\n * indexed items.\n *\n * @param <T> the type being bound\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nabstract class IndexedElementsBinder<T> extends AggregateBinder<T> {\n\n\tprivate static final String[] INDEXES;\n\tstatic {\n\t\tINDEXES = new String[10];\n\t\tfor (int i = 0; i < INDEXES.length; i++) {\n\t\t\tINDEXES[i] = \"[\" + i + \"]\";\n\t\t}\n\t}\n\n\tIndexedElementsBinder(Context context) {\n\t\tsuper(context);\n\t}\n\n\t@Override\n\tprotected boolean isAllowRecursiveBinding(@Nullable ConfigurationPropertySource source) {\n\t\treturn source == null || source instanceof IterableConfigurationPropertySource;\n\t}\n\n\t/**\n\t * Bind indexed elements to the supplied collection.\n\t * @param name the name of the property to bind\n\t * @param target the target bindable\n\t * @param elementBinder the binder to use for elements\n\t * @param aggregateType the aggregate type, may be a collection or an array\n\t * @param elementType the element type\n\t * @param result the destination for results\n\t */\n\tprotected final void bindIndexed(ConfigurationPropertyName name, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder, ResolvableType aggregateType, ResolvableType elementType,\n\t\t\tIndexedCollectionSupplier result) {\n\t\tfor (ConfigurationPropertySource source : getContext().getSources()) {\n\t\t\tbindIndexed(source, name, target, elementBinder, result, aggregateType, elementType);\n\t\t\tif (result.wasSupplied() && result.get() != null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void bindIndexed(ConfigurationPropertySource source, ConfigurationPropertyName root, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder, IndexedCollectionSupplier collection, ResolvableType aggregateType,\n\t\t\tResolvableType elementType) {\n\t\tConfigurationProperty property = source.getConfigurationProperty(root);\n\t\tif (property != null) {\n\t\t\tgetContext().setConfigurationProperty(property);\n\t\t\tbindValue(target, collection.get(), aggregateType, elementType, property.getValue());\n\t\t}\n\t\telse {\n\t\t\tbindIndexed(source, root, elementBinder, collection, elementType);\n\t\t}\n\t}\n\n\tprivate void bindValue(Bindable<?> target, Collection<Object> collection, ResolvableType aggregateType,\n\t\t\tResolvableType elementType, @Nullable Object value) {\n\t\tif (value == null || (value instanceof CharSequence charSequence && charSequence.isEmpty())) {\n\t\t\treturn;\n\t\t}\n\t\tObject aggregate = convert(value, aggregateType, target.getAnnotations());\n\t\tResolvableType collectionType = ResolvableType.forClassWithGenerics(collection.getClass(), elementType);\n\t\tCollection<Object> elements = convert(aggregate, collectionType);\n\t\tif (elements != null) {\n\t\t\tcollection.addAll(elements);\n\t\t}\n\t}\n\n\tprivate void bindIndexed(ConfigurationPropertySource source, ConfigurationPropertyName root,\n\t\t\tAggregateElementBinder elementBinder, IndexedCollectionSupplier collection, ResolvableType elementType) {\n\t\tSet<String> knownIndexedChildren = new HashSet<>();\n\t\tif (source instanceof IterableConfigurationPropertySource iterableSource) {\n\t\t\tknownIndexedChildren = getKnownIndexedChildren(iterableSource, root);\n\t\t}\n\t\tfor (int i = 0; i < Integer.MAX_VALUE; i++) {\n\t\t\tConfigurationPropertyName name = appendIndex(root, i);\n\t\t\tObject value = elementBinder.bind(name, Bindable.of(elementType), source);\n\t\t\tif (value == null) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tknownIndexedChildren.remove(name.getLastElement(Form.UNIFORM));\n\t\t\tcollection.get().add(value);\n\t\t}\n\t\tif (source instanceof IterableConfigurationPropertySource iterableSource) {\n\t\t\tassertNoUnboundChildren(knownIndexedChildren, iterableSource, root);\n\t\t}\n\t}\n\n\tprivate Set<String> getKnownIndexedChildren(IterableConfigurationPropertySource source,\n\t\t\tConfigurationPropertyName root) {\n\t\tSet<String> knownIndexedChildren = new HashSet<>();\n\t\tfor (ConfigurationPropertyName name : source.filter(root::isAncestorOf)) {\n\t\t\tConfigurationPropertyName choppedName = name.chop(root.getNumberOfElements() + 1);\n\t\t\tif (choppedName.isLastElementIndexed()) {\n\t\t\t\tknownIndexedChildren.add(choppedName.getLastElement(Form.UNIFORM));\n\t\t\t}\n\t\t}\n\t\treturn knownIndexedChildren;\n\t}\n\n\tprivate void assertNoUnboundChildren(Set<String> unboundIndexedChildren, IterableConfigurationPropertySource source,\n\t\t\tConfigurationPropertyName root) {\n\t\tif (unboundIndexedChildren.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tSet<ConfigurationProperty> unboundProperties = new TreeSet<>();\n\t\tfor (ConfigurationPropertyName name : source.filter(root::isAncestorOf)) {\n\t\t\tConfigurationPropertyName choppedName = name.chop(root.getNumberOfElements() + 1);\n\t\t\tif (choppedName.isLastElementIndexed()\n\t\t\t\t\t&& unboundIndexedChildren.contains(choppedName.getLastElement(Form.UNIFORM))) {\n\t\t\t\tunboundProperties.add(source.getConfigurationProperty(name));\n\t\t\t}\n\t\t}\n\t\tif (!unboundProperties.isEmpty()) {\n\t\t\tthrow new UnboundConfigurationPropertiesException(unboundProperties);\n\t\t}\n\t}\n\n\tprivate ConfigurationPropertyName appendIndex(ConfigurationPropertyName root, int i) {\n\t\treturn root.append((i < INDEXES.length) ? INDEXES[i] : \"[\" + i + \"]\");\n\t}\n\n\tprivate <C> @Nullable C convert(@Nullable Object value, ResolvableType type, Annotation... annotations) {\n\t\tvalue = getContext().getPlaceholdersResolver().resolvePlaceholders(value);\n\t\treturn getContext().getConverter().convert(value, type, annotations);\n\t}\n\n\t/**\n\t * {@link AggregateBinder.AggregateSupplier AggregateSupplier} for an indexed\n\t * collection.\n\t */\n\tprotected static class IndexedCollectionSupplier extends AggregateSupplier<Collection<Object>> {\n\n\t\tpublic IndexedCollectionSupplier(Supplier<Collection<Object>> supplier) {\n\t\t\tsuper(supplier);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/JavaBeanBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.beans.Introspector;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyState;\nimport org.springframework.core.BridgeMethodResolver;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * {@link DataObjectBinder} for mutable Java Beans.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Lasse Wulff\n */\nclass JavaBeanBinder implements DataObjectBinder {\n\n\tprivate static final String HAS_KNOWN_BINDABLE_PROPERTIES_CACHE = JavaBeanBinder.class.getName()\n\t\t\t+ \".HAS_KNOWN_BINDABLE_PROPERTIES_CACHE\";\n\n\tstatic final JavaBeanBinder INSTANCE = new JavaBeanBinder();\n\n\t@Override\n\tpublic <T> @Nullable T bind(ConfigurationPropertyName name, Bindable<T> target, Context context,\n\t\t\tDataObjectPropertyBinder propertyBinder, boolean fallbackToDefaultValue) {\n\t\tboolean hasKnownBindableProperties = target.getValue() != null && hasKnownBindableProperties(name, context);\n\t\tBean<T> bean = Bean.get(target, context, hasKnownBindableProperties);\n\t\tif (bean == null) {\n\t\t\treturn null;\n\t\t}\n\t\tBeanSupplier<T> beanSupplier = bean.getSupplier(target);\n\t\tboolean bound = bind(propertyBinder, bean, beanSupplier, context);\n\t\treturn (bound ? beanSupplier.get() : null);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> @Nullable T create(Bindable<T> target, Context context) {\n\t\tClass<T> type = (Class<T>) target.getType().resolve();\n\t\treturn (type != null) ? BeanUtils.instantiateClass(type) : null;\n\t}\n\n\tprivate boolean hasKnownBindableProperties(ConfigurationPropertyName name, Context context) {\n\t\tMap<ConfigurationPropertyName, Boolean> cache = getHasKnownBindablePropertiesCache(context);\n\t\tBoolean hasKnownBindableProperties = cache.get(name);\n\t\tif (hasKnownBindableProperties == null) {\n\t\t\thasKnownBindableProperties = computeHasKnownBindableProperties(name, context);\n\t\t\tcache.put(name, hasKnownBindableProperties);\n\t\t}\n\t\treturn hasKnownBindableProperties;\n\t}\n\n\tprivate boolean computeHasKnownBindableProperties(ConfigurationPropertyName name, Context context) {\n\t\tfor (ConfigurationPropertySource source : context.getSources()) {\n\t\t\tif (source.containsDescendantOf(name) == ConfigurationPropertyState.PRESENT) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<ConfigurationPropertyName, Boolean> getHasKnownBindablePropertiesCache(Context context) {\n\t\tObject cache = context.getCache().get(HAS_KNOWN_BINDABLE_PROPERTIES_CACHE);\n\t\tif (cache == null) {\n\t\t\tcache = new ConcurrentHashMap<ConfigurationPropertyName, Boolean>();\n\t\t\tcontext.getCache().put(HAS_KNOWN_BINDABLE_PROPERTIES_CACHE, cache);\n\t\t}\n\t\treturn (Map<ConfigurationPropertyName, Boolean>) cache;\n\t}\n\n\tprivate <T> boolean bind(DataObjectPropertyBinder propertyBinder, Bean<T> bean, BeanSupplier<T> beanSupplier,\n\t\t\tContext context) {\n\t\tboolean bound = false;\n\t\tfor (BeanProperty beanProperty : bean.getProperties().values()) {\n\t\t\tbound |= bind(beanSupplier, propertyBinder, beanProperty);\n\t\t\tcontext.clearConfigurationProperty();\n\t\t}\n\t\treturn bound;\n\t}\n\n\tprivate <T> boolean bind(BeanSupplier<T> beanSupplier, DataObjectPropertyBinder propertyBinder,\n\t\t\tBeanProperty property) {\n\t\tString propertyName = determinePropertyName(property);\n\t\tResolvableType type = property.getType();\n\t\tSupplier<Object> value = property.getValue(beanSupplier);\n\t\tAnnotation[] annotations = property.getAnnotations();\n\t\tObject bound = propertyBinder.bindProperty(propertyName,\n\t\t\t\tBindable.of(type).withSuppliedValue(value).withAnnotations(annotations));\n\t\tif (bound == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (property.isSettable()) {\n\t\t\tproperty.setValue(beanSupplier, bound);\n\t\t}\n\t\telse if (value == null || !bound.equals(value.get())) {\n\t\t\tthrow new IllegalStateException(\"No setter found for property: \" + property.getName());\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate String determinePropertyName(BeanProperty property) {\n\t\treturn Arrays.stream((property.getAnnotations() != null) ? property.getAnnotations() : new Annotation[0])\n\t\t\t.filter((annotation) -> annotation.annotationType() == Name.class)\n\t\t\t.findFirst()\n\t\t\t.map(Name.class::cast)\n\t\t\t.map(Name::value)\n\t\t\t.orElse(property.getName());\n\t}\n\n\t/**\n\t * The properties of a bean that may be bound.\n\t */\n\tstatic class BeanProperties {\n\n\t\tprivate final Map<String, BeanProperty> properties = new LinkedHashMap<>();\n\n\t\tprivate final ResolvableType type;\n\n\t\tprivate final Class<?> resolvedType;\n\n\t\tBeanProperties(ResolvableType type, Class<?> resolvedType) {\n\t\t\tthis.type = type;\n\t\t\tthis.resolvedType = resolvedType;\n\t\t\taddProperties(resolvedType);\n\t\t}\n\n\t\tprivate void addProperties(Class<?> type) {\n\t\t\twhile (type != null && !Object.class.equals(type)) {\n\t\t\t\tMethod[] declaredMethods = getSorted(type, this::getDeclaredMethods, Method::getName);\n\t\t\t\tField[] declaredFields = getSorted(type, Class::getDeclaredFields, Field::getName);\n\t\t\t\taddProperties(declaredMethods, declaredFields);\n\t\t\t\ttype = type.getSuperclass();\n\t\t\t}\n\t\t}\n\n\t\tprivate Method[] getDeclaredMethods(Class<?> type) {\n\t\t\tMethod[] methods = type.getDeclaredMethods();\n\t\t\tSet<Method> result = new LinkedHashSet<>(methods.length);\n\t\t\tfor (Method method : methods) {\n\t\t\t\tresult.add(BridgeMethodResolver.findBridgedMethod(method));\n\t\t\t}\n\t\t\treturn result.toArray(new Method[0]);\n\t\t}\n\n\t\tprivate <S, E> E[] getSorted(S source, Function<S, E[]> elements, Function<E, String> name) {\n\t\t\tE[] result = elements.apply(source);\n\t\t\tArrays.sort(result, Comparator.comparing(name));\n\t\t\treturn result;\n\t\t}\n\n\t\tprotected void addProperties(Method[] declaredMethods, Field[] declaredFields) {\n\t\t\t@Nullable Method[] methods = new Method[declaredMethods.length];\n\t\t\tfor (int i = 0; i < declaredMethods.length; i++) {\n\t\t\t\tmethods[i] = isCandidate(declaredMethods[i]) ? declaredMethods[i] : null;\n\t\t\t}\n\t\t\tfor (Method method : methods) {\n\t\t\t\taddMethodIfPossible(method, \"is\", 0, BeanProperty::addGetter);\n\t\t\t}\n\t\t\tfor (Method method : methods) {\n\t\t\t\taddMethodIfPossible(method, \"get\", 0, BeanProperty::addGetter);\n\t\t\t}\n\t\t\tfor (Method method : methods) {\n\t\t\t\taddMethodIfPossible(method, \"set\", 1, BeanProperty::addSetter);\n\t\t\t}\n\t\t\tfor (Field field : declaredFields) {\n\t\t\t\taddField(field);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isCandidate(Method method) {\n\t\t\tint modifiers = method.getModifiers();\n\t\t\treturn !Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers) && !Modifier.isAbstract(modifiers)\n\t\t\t\t\t&& !Modifier.isStatic(modifiers) && !method.isBridge()\n\t\t\t\t\t&& !Object.class.equals(method.getDeclaringClass())\n\t\t\t\t\t&& !Class.class.equals(method.getDeclaringClass()) && method.getName().indexOf('$') == -1;\n\t\t}\n\n\t\tprivate void addMethodIfPossible(@Nullable Method method, String prefix, int parameterCount,\n\t\t\t\tBiConsumer<BeanProperty, Method> consumer) {\n\t\t\tif (method != null && method.getParameterCount() == parameterCount && method.getName().startsWith(prefix)\n\t\t\t\t\t&& method.getName().length() > prefix.length()) {\n\t\t\t\tString propertyName = Introspector.decapitalize(method.getName().substring(prefix.length()));\n\t\t\t\tconsumer.accept(this.properties.computeIfAbsent(propertyName, this::getBeanProperty), method);\n\t\t\t}\n\t\t}\n\n\t\tprivate BeanProperty getBeanProperty(String name) {\n\t\t\treturn new BeanProperty(name, this.type);\n\t\t}\n\n\t\tprivate void addField(Field field) {\n\t\t\tBeanProperty property = this.properties.get(field.getName());\n\t\t\tif (property != null) {\n\t\t\t\tproperty.addField(field);\n\t\t\t}\n\t\t}\n\n\t\tprotected final ResolvableType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tprotected final Class<?> getResolvedType() {\n\t\t\treturn this.resolvedType;\n\t\t}\n\n\t\tfinal Map<String, BeanProperty> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tstatic BeanProperties of(Bindable<?> bindable) {\n\t\t\tResolvableType type = bindable.getType();\n\t\t\tClass<?> resolvedType = type.resolve(Object.class);\n\t\t\treturn new BeanProperties(type, resolvedType);\n\t\t}\n\n\t}\n\n\t/**\n\t * The bean being bound.\n\t *\n\t * @param <T> the bean type\n\t */\n\tstatic class Bean<T> extends BeanProperties {\n\n\t\tBean(ResolvableType type, Class<?> resolvedType) {\n\t\t\tsuper(type, resolvedType);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tBeanSupplier<T> getSupplier(Bindable<T> target) {\n\t\t\treturn new BeanSupplier<>(() -> {\n\t\t\t\tT instance = null;\n\t\t\t\tif (target.getValue() != null) {\n\t\t\t\t\tinstance = target.getValue().get();\n\t\t\t\t}\n\t\t\t\tif (instance == null) {\n\t\t\t\t\tinstance = (T) BeanUtils.instantiateClass(getResolvedType());\n\t\t\t\t}\n\t\t\t\treturn instance;\n\t\t\t});\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tstatic <T> @Nullable Bean<T> get(Bindable<T> bindable, Context context, boolean canCallGetValue) {\n\t\t\tResolvableType type = bindable.getType();\n\t\t\tClass<?> resolvedType = type.resolve(Object.class);\n\t\t\tSupplier<T> value = bindable.getValue();\n\t\t\tT instance = null;\n\t\t\tif (canCallGetValue && value != null) {\n\t\t\t\tinstance = value.get();\n\t\t\t\tresolvedType = (instance != null) ? instance.getClass() : resolvedType;\n\t\t\t}\n\t\t\tif (instance == null && !isInstantiable(resolvedType)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tMap<CacheKey, Bean<?>> cache = getCache(context);\n\t\t\tCacheKey cacheKey = new CacheKey(type, resolvedType);\n\t\t\tBean<?> bean = cache.get(cacheKey);\n\t\t\tif (bean == null) {\n\t\t\t\tbean = new Bean<>(type, resolvedType);\n\t\t\t\tcache.put(cacheKey, bean);\n\t\t\t}\n\t\t\treturn (Bean<T>) bean;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate static Map<CacheKey, Bean<?>> getCache(Context context) {\n\t\t\tMap<CacheKey, Bean<?>> cache = (Map<CacheKey, Bean<?>>) context.getCache().get(Bean.class);\n\t\t\tif (cache == null) {\n\t\t\t\tcache = new ConcurrentHashMap<>();\n\t\t\t\tcontext.getCache().put(Bean.class, cache);\n\t\t\t}\n\t\t\treturn cache;\n\t\t}\n\n\t\tprivate static boolean isInstantiable(Class<?> type) {\n\t\t\tif (type.isInterface()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\ttype.getDeclaredConstructor();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tprivate record CacheKey(ResolvableType type, Class<?> resolvedType) {\n\n\t\t}\n\n\t}\n\n\tprivate static class BeanSupplier<T> implements Supplier<T> {\n\n\t\tprivate final Supplier<T> factory;\n\n\t\tprivate @Nullable T instance;\n\n\t\tBeanSupplier(Supplier<T> factory) {\n\t\t\tthis.factory = factory;\n\t\t}\n\n\t\t@Override\n\t\tpublic T get() {\n\t\t\tif (this.instance == null) {\n\t\t\t\tthis.instance = this.factory.get();\n\t\t\t}\n\t\t\treturn this.instance;\n\t\t}\n\n\t}\n\n\t/**\n\t * A bean property being bound.\n\t */\n\tstatic class BeanProperty {\n\n\t\tprivate final String name;\n\n\t\tprivate final ResolvableType declaringClassType;\n\n\t\tprivate @Nullable Method getter;\n\n\t\tprivate @Nullable Method setter;\n\n\t\tprivate @Nullable Field field;\n\n\t\tBeanProperty(String name, ResolvableType declaringClassType) {\n\t\t\tthis.name = DataObjectPropertyName.toDashedForm(name);\n\t\t\tthis.declaringClassType = declaringClassType;\n\t\t}\n\n\t\tvoid addGetter(Method getter) {\n\t\t\tif (this.getter == null || this.getter.getName().startsWith(\"is\")) {\n\t\t\t\tthis.getter = getter;\n\t\t\t}\n\t\t}\n\n\t\tvoid addSetter(Method setter) {\n\t\t\tif (this.setter == null || isBetterSetter(setter)) {\n\t\t\t\tthis.setter = setter;\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isBetterSetter(Method setter) {\n\t\t\treturn this.getter != null && this.getter.getReturnType().equals(setter.getParameterTypes()[0]);\n\t\t}\n\n\t\tvoid addField(Field field) {\n\t\t\tif (this.field == null) {\n\t\t\t\tthis.field = field;\n\t\t\t}\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tResolvableType getType() {\n\t\t\tif (this.setter != null) {\n\t\t\t\tMethodParameter methodParameter = new MethodParameter(this.setter, 0);\n\t\t\t\treturn ResolvableType.forMethodParameter(methodParameter, this.declaringClassType);\n\t\t\t}\n\t\t\tAssert.state(this.getter != null, \"'getter' must not be null\");\n\t\t\tMethodParameter methodParameter = new MethodParameter(this.getter, -1);\n\t\t\treturn ResolvableType.forMethodParameter(methodParameter, this.declaringClassType);\n\t\t}\n\n\t\tAnnotation @Nullable [] getAnnotations() {\n\t\t\ttry {\n\t\t\t\treturn (this.field != null) ? this.field.getDeclaredAnnotations() : null;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t@Nullable Supplier<Object> getValue(Supplier<?> instance) {\n\t\t\tif (this.getter == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn () -> {\n\t\t\t\tAssert.state(this.getter != null, \"'getter' must not be null\");\n\t\t\t\ttry {\n\t\t\t\t\tthis.getter.setAccessible(true);\n\t\t\t\t\treturn this.getter.invoke(instance.get());\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tif (isUninitializedKotlinProperty(ex)) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tthrow new IllegalStateException(\"Unable to get value for property \" + this.name, ex);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tprivate boolean isUninitializedKotlinProperty(Exception ex) {\n\t\t\treturn (ex instanceof InvocationTargetException invocationTargetException)\n\t\t\t\t\t&& \"kotlin.UninitializedPropertyAccessException\"\n\t\t\t\t\t\t.equals(invocationTargetException.getTargetException().getClass().getName());\n\t\t}\n\n\t\tboolean isSettable() {\n\t\t\treturn this.setter != null;\n\t\t}\n\n\t\tvoid setValue(Supplier<?> instance, Object value) {\n\t\t\tAssert.state(this.setter != null, \"'setter' must not be null\");\n\t\t\ttry {\n\t\t\t\tthis.setter.setAccessible(true);\n\t\t\t\tthis.setter.invoke(instance.get(), value);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to set value for property \" + this.name, ex);\n\t\t\t}\n\t\t}\n\n\t\t@Nullable Method getGetter() {\n\t\t\treturn this.getter;\n\t\t}\n\n\t\t@Nullable Method getSetter() {\n\t\t\treturn this.setter;\n\t\t}\n\n\t\t@Nullable Field getField() {\n\t\t\treturn this.field;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/MapBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.Collection;\nimport java.util.EnumMap;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyState;\nimport org.springframework.boot.context.properties.source.IterableConfigurationPropertySource;\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.core.ResolvableType;\n\n/**\n * {@link AggregateBinder} for Maps.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass MapBinder extends AggregateBinder<Map<Object, Object>> {\n\n\tprivate static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable.mapOf(String.class, String.class);\n\n\tMapBinder(Context context) {\n\t\tsuper(context);\n\t}\n\n\t@Override\n\tprotected boolean isAllowRecursiveBinding(@Nullable ConfigurationPropertySource source) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tprotected @Nullable Object bindAggregate(ConfigurationPropertyName name, Bindable<?> target,\n\t\t\tAggregateElementBinder elementBinder) {\n\t\tBindable<?> resolvedTarget = resolveTarget(target);\n\t\tboolean hasDescendants = hasDescendants(name);\n\t\tif (!hasDescendants && !ConfigurationPropertyName.EMPTY.equals(name)) {\n\t\t\tfor (ConfigurationPropertySource source : getContext().getSources()) {\n\t\t\t\tConfigurationProperty property = source.getConfigurationProperty(name);\n\t\t\t\tif (property != null) {\n\t\t\t\t\tgetContext().setConfigurationProperty(property);\n\t\t\t\t\tObject result = getContext().getPlaceholdersResolver().resolvePlaceholders(property.getValue());\n\t\t\t\t\treturn getContext().getConverter().convert(result, target);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tMap<Object, Object> map = createMap(target);\n\t\tfor (ConfigurationPropertySource source : getContext().getSources()) {\n\t\t\tif (!ConfigurationPropertyName.EMPTY.equals(name)) {\n\t\t\t\tsource = source.filter(name::isAncestorOf);\n\t\t\t}\n\t\t\tnew EntryBinder(name, resolvedTarget, elementBinder).bindEntries(source, map);\n\t\t}\n\t\treturn map.isEmpty() ? null : map;\n\t}\n\n\tprivate Map<Object, Object> createMap(Bindable<?> target) {\n\t\tClass<?> mapType = (target.getValue() != null) ? Map.class : target.getType().resolve(Object.class);\n\t\tif (EnumMap.class.isAssignableFrom(mapType)) {\n\t\t\tClass<?> keyType = target.getType().asMap().resolveGeneric(0);\n\t\t\treturn CollectionFactory.createMap(mapType, keyType, 0);\n\t\t}\n\t\treturn CollectionFactory.createMap(mapType, 0);\n\t}\n\n\tprivate boolean hasDescendants(ConfigurationPropertyName name) {\n\t\tfor (ConfigurationPropertySource source : getContext().getSources()) {\n\t\t\tif (source.containsDescendantOf(name) == ConfigurationPropertyState.PRESENT) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Bindable<?> resolveTarget(Bindable<?> target) {\n\t\tClass<?> type = target.getType().resolve(Object.class);\n\t\tif (Properties.class.isAssignableFrom(type)) {\n\t\t\treturn STRING_STRING_MAP;\n\t\t}\n\t\treturn target;\n\t}\n\n\t@Override\n\tprotected Map<Object, Object> merge(Supplier<Map<Object, Object>> existing, Map<Object, Object> additional) {\n\t\tMap<Object, Object> existingMap = getExistingIfPossible(existing);\n\t\tif (existingMap == null) {\n\t\t\treturn additional;\n\t\t}\n\t\ttry {\n\t\t\texistingMap.putAll(additional);\n\t\t\treturn copyIfPossible(existingMap);\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\tMap<Object, Object> result = createNewMap(additional.getClass(), existingMap);\n\t\t\tresult.putAll(additional);\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tprivate @Nullable Map<Object, Object> getExistingIfPossible(Supplier<Map<Object, Object>> existing) {\n\t\ttry {\n\t\t\treturn existing.get();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate Map<Object, Object> copyIfPossible(Map<Object, Object> map) {\n\t\ttry {\n\t\t\treturn createNewMap(map.getClass(), map);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn map;\n\t\t}\n\t}\n\n\tprivate Map<Object, Object> createNewMap(Class<?> mapClass, Map<Object, Object> map) {\n\t\tMap<Object, Object> result = CollectionFactory.createMap(mapClass, map.size());\n\t\tresult.putAll(map);\n\t\treturn result;\n\t}\n\n\tprivate class EntryBinder {\n\n\t\tprivate final ConfigurationPropertyName root;\n\n\t\tprivate final AggregateElementBinder elementBinder;\n\n\t\tprivate final ResolvableType mapType;\n\n\t\tprivate final ResolvableType keyType;\n\n\t\tprivate final ResolvableType valueType;\n\n\t\tprivate final Class<?> resolvedValueType;\n\n\t\tprivate final boolean valueTreatedAsNestedMap;\n\n\t\tprivate final Bindable<Object> bindableMapType;\n\n\t\tprivate final Bindable<Object> bindableValueType;\n\n\t\tEntryBinder(ConfigurationPropertyName root, Bindable<?> target, AggregateElementBinder elementBinder) {\n\t\t\tthis.root = root;\n\t\t\tthis.elementBinder = elementBinder;\n\t\t\tthis.mapType = target.getType().asMap();\n\t\t\tthis.keyType = this.mapType.getGeneric(0);\n\t\t\tthis.valueType = this.mapType.getGeneric(1);\n\t\t\tthis.resolvedValueType = this.valueType.resolve(Object.class);\n\t\t\tthis.valueTreatedAsNestedMap = Object.class.equals(this.resolvedValueType);\n\t\t\tthis.bindableMapType = Bindable.of(this.mapType);\n\t\t\tthis.bindableValueType = Bindable.of(this.valueType);\n\t\t}\n\n\t\tvoid bindEntries(ConfigurationPropertySource source, Map<Object, Object> map) {\n\t\t\tif (source instanceof IterableConfigurationPropertySource iterableSource) {\n\t\t\t\tfor (ConfigurationPropertyName name : iterableSource) {\n\t\t\t\t\tConfigurationPropertyName entryName = getEntryName(source, name);\n\t\t\t\t\tObject key = getContext().getConverter().convert(getKeyName(entryName), this.keyType);\n\t\t\t\t\tBindable<?> valueBindable = getValueBindable(name);\n\t\t\t\t\tmap.computeIfAbsent(key, (k) -> this.elementBinder.bind(entryName, valueBindable));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate Bindable<?> getValueBindable(ConfigurationPropertyName name) {\n\t\t\treturn (!isParentOf(name) && this.valueTreatedAsNestedMap) ? this.bindableMapType : this.bindableValueType;\n\t\t}\n\n\t\tprivate ConfigurationPropertyName getEntryName(ConfigurationPropertySource source,\n\t\t\t\tConfigurationPropertyName name) {\n\t\t\tif (Collection.class.isAssignableFrom(this.resolvedValueType) || this.valueType.isArray()) {\n\t\t\t\treturn chopNameAtNumericIndex(name);\n\t\t\t}\n\t\t\tif (!isParentOf(name) && (this.valueTreatedAsNestedMap || !isScalarValue(source, name))) {\n\t\t\t\treturn name.chop(this.root.getNumberOfElements() + 1);\n\t\t\t}\n\t\t\treturn name;\n\t\t}\n\n\t\tprivate boolean isParentOf(ConfigurationPropertyName name) {\n\t\t\treturn this.root.isParentOf(name);\n\t\t}\n\n\t\tprivate ConfigurationPropertyName chopNameAtNumericIndex(ConfigurationPropertyName name) {\n\t\t\tint start = this.root.getNumberOfElements() + 1;\n\t\t\tint size = name.getNumberOfElements();\n\t\t\tfor (int i = start; i < size; i++) {\n\t\t\t\tif (name.isNumericIndex(i)) {\n\t\t\t\t\treturn name.chop(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn name;\n\t\t}\n\n\t\tprivate boolean isScalarValue(ConfigurationPropertySource source, ConfigurationPropertyName name) {\n\t\t\tClass<?> resolved = this.valueType.resolve(Object.class);\n\t\t\tif (!resolved.getName().startsWith(\"java.lang\") && !resolved.isEnum()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tConfigurationProperty property = source.getConfigurationProperty(name);\n\t\t\tif (property == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tObject value = property.getValue();\n\t\t\tvalue = getContext().getPlaceholdersResolver().resolvePlaceholders(value);\n\t\t\treturn getContext().getConverter().canConvert(value, this.valueType);\n\t\t}\n\n\t\tprivate String getKeyName(ConfigurationPropertyName name) {\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tfor (int i = this.root.getNumberOfElements(); i < name.getNumberOfElements(); i++) {\n\t\t\t\tif (!result.isEmpty()) {\n\t\t\t\t\tresult.append('.');\n\t\t\t\t}\n\t\t\t\tresult.append(name.getElement(i, Form.ORIGINAL));\n\t\t\t}\n\t\t\treturn result.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Name.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation that can be used to specify the name when binding to a property. This\n * annotation may be required when binding to names that clash with reserved language\n * keywords.\n * <p>\n * When naming a JavaBean-based property, annotate the field. When naming a\n * constructor-bound property, annotate the constructor parameter or record component.\n *\n * @author Phillip Webb\n * @author Lasse Wulff\n * @since 2.4.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.PARAMETER })\n@Documented\npublic @interface Name {\n\n\t/**\n\t * The name of the property to use for binding.\n\t * @return the property name\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/Nested.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Meta-annotation that should be added to annotations that indicate a field is a nested\n * type. Used to ensure that correct reflection hints are registered.\n *\n * @author Phillip Webb\n * @since 3.0.0\n * @see BindableRuntimeHintsRegistrar\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.ANNOTATION_TYPE)\n@Documented\npublic @interface Nested {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/PlaceholdersResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertyResolver;\n\n/**\n * Optional strategy that used by a {@link Binder} to resolve property placeholders.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see PropertySourcesPlaceholdersResolver\n */\n@FunctionalInterface\npublic interface PlaceholdersResolver {\n\n\t/**\n\t * No-op {@link PropertyResolver}.\n\t */\n\tPlaceholdersResolver NONE = (value) -> value;\n\n\t/**\n\t * Called to resolve any placeholders in the given value.\n\t * @param value the source value\n\t * @return a value with placeholders resolved\n\t */\n\t@Nullable Object resolvePlaceholders(@Nullable Object value);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.util.Assert;\nimport org.springframework.util.PropertyPlaceholderHelper;\nimport org.springframework.util.SystemPropertyUtils;\n\n/**\n * {@link PlaceholdersResolver} to resolve placeholders from {@link PropertySources}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class PropertySourcesPlaceholdersResolver implements PlaceholdersResolver {\n\n\tprivate final @Nullable Iterable<PropertySource<?>> sources;\n\n\tprivate final PropertyPlaceholderHelper helper;\n\n\tpublic PropertySourcesPlaceholdersResolver(Environment environment) {\n\t\tthis(getSources(environment), null);\n\t}\n\n\tpublic PropertySourcesPlaceholdersResolver(@Nullable Iterable<PropertySource<?>> sources) {\n\t\tthis(sources, null);\n\t}\n\n\tpublic PropertySourcesPlaceholdersResolver(@Nullable Iterable<PropertySource<?>> sources,\n\t\t\t@Nullable PropertyPlaceholderHelper helper) {\n\t\tthis.sources = sources;\n\t\tthis.helper = (helper != null) ? helper\n\t\t\t\t: new PropertyPlaceholderHelper(SystemPropertyUtils.PLACEHOLDER_PREFIX,\n\t\t\t\t\t\tSystemPropertyUtils.PLACEHOLDER_SUFFIX, SystemPropertyUtils.VALUE_SEPARATOR,\n\t\t\t\t\t\tSystemPropertyUtils.ESCAPE_CHARACTER, true);\n\t}\n\n\t@Override\n\tpublic @Nullable Object resolvePlaceholders(@Nullable Object value) {\n\t\tif (value instanceof String string) {\n\t\t\treturn this.helper.replacePlaceholders(string, this::resolvePlaceholder);\n\t\t}\n\t\treturn value;\n\t}\n\n\tprotected @Nullable String resolvePlaceholder(String placeholder) {\n\t\tif (this.sources != null) {\n\t\t\tfor (PropertySource<?> source : this.sources) {\n\t\t\t\tObject value = source.getProperty(placeholder);\n\t\t\t\tif (value != null) {\n\t\t\t\t\treturn String.valueOf(value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static PropertySources getSources(Environment environment) {\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tAssert.isInstanceOf(ConfigurableEnvironment.class, environment,\n\t\t\t\t\"'environment' must be a ConfigurableEnvironment\");\n\t\treturn ((ConfigurableEnvironment) environment).getPropertySources();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/UnboundConfigurationPropertiesException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\n\n/**\n * {@link BindException} thrown when {@link ConfigurationPropertySource} elements were\n * left unbound.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class UnboundConfigurationPropertiesException extends RuntimeException {\n\n\tprivate final Set<ConfigurationProperty> unboundProperties;\n\n\tpublic UnboundConfigurationPropertiesException(Set<ConfigurationProperty> unboundProperties) {\n\t\tsuper(buildMessage(unboundProperties));\n\t\tthis.unboundProperties = Collections.unmodifiableSet(unboundProperties);\n\t}\n\n\tpublic Set<ConfigurationProperty> getUnboundProperties() {\n\t\treturn this.unboundProperties;\n\t}\n\n\tprivate static String buildMessage(Set<ConfigurationProperty> unboundProperties) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tbuilder.append(\"The elements [\");\n\t\tString message = unboundProperties.stream().map((p) -> p.getName().toString()).collect(Collectors.joining(\",\"));\n\t\tbuilder.append(message).append(\"] were left unbound.\");\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/ValueObjectBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Array;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Consumer;\n\nimport kotlin.reflect.KFunction;\nimport kotlin.reflect.KParameter;\nimport kotlin.reflect.jvm.ReflectJvmMapping;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.context.properties.bind.Binder.Context;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.KotlinDetector;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.convert.ConversionException;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\n\n/**\n * {@link DataObjectBinder} for immutable value objects.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Ondřej Světlík\n */\nclass ValueObjectBinder implements DataObjectBinder {\n\n\tprivate static final Log logger = LogFactory.getLog(ValueObjectBinder.class);\n\n\tprivate final BindConstructorProvider constructorProvider;\n\n\tValueObjectBinder(BindConstructorProvider constructorProvider) {\n\t\tthis.constructorProvider = constructorProvider;\n\t}\n\n\t@Override\n\tpublic <T> @Nullable T bind(ConfigurationPropertyName name, Bindable<T> target, Binder.Context context,\n\t\t\tDataObjectPropertyBinder propertyBinder, boolean fallbackToDefaultValue) {\n\t\tValueObject<T> valueObject = ValueObject.get(target, context, this.constructorProvider, Discoverer.LENIENT);\n\t\tif (valueObject != null) {\n\t\t\tClass<?> targetType = target.getType().resolve();\n\t\t\tAssert.state(targetType != null, \"'targetType' must not be null\");\n\t\t\tcontext.pushConstructorBoundTypes(targetType);\n\t\t\tList<ConstructorParameter> parameters = valueObject.getConstructorParameters();\n\t\t\tList<@Nullable Object> args = new ArrayList<>(parameters.size());\n\t\t\tboolean bound = false;\n\t\t\tfor (ConstructorParameter parameter : parameters) {\n\t\t\t\tObject arg = parameter.bind(propertyBinder);\n\t\t\t\tbound = bound || arg != null;\n\t\t\t\targ = (arg != null) ? arg : getDefaultValue(context, parameter);\n\t\t\t\targs.add(arg);\n\t\t\t}\n\t\t\tcontext.clearConfigurationProperty();\n\t\t\tcontext.popConstructorBoundTypes();\n\t\t\tif (bound) {\n\t\t\t\treturn valueObject.instantiate(args);\n\t\t\t}\n\t\t}\n\t\tif (fallbackToDefaultValue) {\n\t\t\treturn getNewDefaultValueInstanceIfPossible(context, target.getType());\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic <T> @Nullable T create(Bindable<T> target, Binder.Context context) {\n\t\tValueObject<T> valueObject = ValueObject.get(target, context, this.constructorProvider, Discoverer.LENIENT);\n\t\tif (valueObject == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<ConstructorParameter> parameters = valueObject.getConstructorParameters();\n\t\tList<@Nullable Object> args = new ArrayList<>(parameters.size());\n\t\tfor (ConstructorParameter parameter : parameters) {\n\t\t\targs.add(getDefaultValue(context, parameter));\n\t\t}\n\t\treturn valueObject.instantiate(args);\n\t}\n\n\t@Override\n\tpublic <T> void onUnableToCreateInstance(Bindable<T> target, Context context, RuntimeException exception) {\n\t\ttry {\n\t\t\tValueObject.get(target, context, this.constructorProvider, Discoverer.STRICT);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\texception.addSuppressed(ex);\n\t\t}\n\t}\n\n\tprivate <T> @Nullable T getDefaultValue(Binder.Context context, ConstructorParameter parameter) {\n\t\tResolvableType type = parameter.getType();\n\t\tAnnotation[] annotations = parameter.getAnnotations();\n\t\tfor (Annotation annotation : annotations) {\n\t\t\tif (annotation instanceof DefaultValue defaultValueAnnotation) {\n\t\t\t\tString[] defaultValue = defaultValueAnnotation.value();\n\t\t\t\tif (defaultValue.length == 0) {\n\t\t\t\t\treturn getNewDefaultValueInstanceIfPossible(context, type);\n\t\t\t\t}\n\t\t\t\treturn convertDefaultValue(context.getConverter(), defaultValue, type, annotations);\n\t\t\t}\n\t\t}\n\t\treturn context.getConverter().convert(null, type);\n\t}\n\n\tprivate <T> @Nullable T convertDefaultValue(BindConverter converter, String[] defaultValue, ResolvableType type,\n\t\t\tAnnotation[] annotations) {\n\t\ttry {\n\t\t\treturn converter.convert(defaultValue, type, annotations);\n\t\t}\n\t\tcatch (ConversionException ex) {\n\t\t\t// Try again in case ArrayToObjectConverter is not in play\n\t\t\tif (defaultValue.length == 1) {\n\t\t\t\treturn converter.convert(defaultValue[0], type, annotations);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T getNewDefaultValueInstanceIfPossible(Binder.Context context, ResolvableType type) {\n\t\tClass<T> resolved = (Class<T>) type.resolve();\n\t\tAssert.state(resolved == null || isEmptyDefaultValueAllowed(resolved),\n\t\t\t\t() -> \"Parameter of type \" + type + \" must have a non-empty default value.\");\n\t\tif (resolved != null) {\n\t\t\tif (Optional.class == resolved) {\n\t\t\t\treturn (T) Optional.empty();\n\t\t\t}\n\t\t\tif (Collection.class.isAssignableFrom(resolved)) {\n\t\t\t\treturn (T) CollectionFactory.createCollection(resolved, 0);\n\t\t\t}\n\t\t\tif (EnumMap.class.isAssignableFrom(resolved)) {\n\t\t\t\tClass<?> keyType = type.asMap().resolveGeneric(0);\n\t\t\t\treturn (T) CollectionFactory.createMap(resolved, keyType, 0);\n\t\t\t}\n\t\t\tif (Map.class.isAssignableFrom(resolved)) {\n\t\t\t\treturn (T) CollectionFactory.createMap(resolved, 0);\n\t\t\t}\n\t\t\tif (resolved.isArray()) {\n\t\t\t\treturn (T) Array.newInstance(resolved.getComponentType(), 0);\n\t\t\t}\n\t\t}\n\t\tT instance = create(Bindable.of(type), context);\n\t\tif (instance != null) {\n\t\t\treturn instance;\n\t\t}\n\t\treturn (resolved != null) ? BeanUtils.instantiateClass(resolved) : null;\n\t}\n\n\tprivate boolean isEmptyDefaultValueAllowed(Class<?> type) {\n\t\treturn (Optional.class == type || isAggregate(type))\n\t\t\t\t|| !(type.isPrimitive() || type.isEnum() || type.getName().startsWith(\"java.lang\"));\n\t}\n\n\tprivate boolean isAggregate(Class<?> type) {\n\t\treturn type.isArray() || Map.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type);\n\t}\n\n\t/**\n\t * The value object being bound.\n\t *\n\t * @param <T> the value object type\n\t */\n\tprivate abstract static class ValueObject<T> {\n\n\t\tprivate static final Object NONE = new Object();\n\n\t\tprivate final Constructor<T> constructor;\n\n\t\tprotected ValueObject(Constructor<T> constructor) {\n\t\t\tthis.constructor = constructor;\n\t\t}\n\n\t\tT instantiate(List<@Nullable Object> args) {\n\t\t\treturn BeanUtils.instantiateClass(this.constructor, args.toArray());\n\t\t}\n\n\t\tabstract List<ConstructorParameter> getConstructorParameters();\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tstatic <T> @Nullable ValueObject<T> get(Bindable<T> bindable, Binder.Context context,\n\t\t\t\tBindConstructorProvider constructorProvider, ParameterNameDiscoverer parameterNameDiscoverer) {\n\t\t\tClass<T> resolvedType = (Class<T>) bindable.getType().resolve();\n\t\t\tif (resolvedType == null || resolvedType.isEnum() || Modifier.isAbstract(resolvedType.getModifiers())) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tMap<CacheKey, Object> cache = getCache(context);\n\t\t\tCacheKey cacheKey = new CacheKey(bindable, constructorProvider, parameterNameDiscoverer);\n\t\t\tObject valueObject = cache.get(cacheKey);\n\t\t\tif (valueObject == null) {\n\t\t\t\tvalueObject = get(bindable, context, constructorProvider, parameterNameDiscoverer, resolvedType);\n\t\t\t\tcache.put(cacheKey, (valueObject != null) ? valueObject : NONE);\n\t\t\t}\n\t\t\treturn (valueObject != NONE) ? (ValueObject<T>) valueObject : null;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate static <T> @Nullable ValueObject<T> get(Bindable<T> bindable, Binder.Context context,\n\t\t\t\tBindConstructorProvider constructorProvider, ParameterNameDiscoverer parameterNameDiscoverer,\n\t\t\t\tClass<T> resolvedType) {\n\t\t\tConstructor<?> bindConstructor = constructorProvider.getBindConstructor(bindable,\n\t\t\t\t\tcontext.isNestedConstructorBinding());\n\t\t\tif (bindConstructor == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (KotlinDetector.isKotlinType(resolvedType)) {\n\t\t\t\treturn KotlinValueObject.get((Constructor<T>) bindConstructor, bindable.getType(),\n\t\t\t\t\t\tparameterNameDiscoverer);\n\t\t\t}\n\t\t\treturn DefaultValueObject.get(bindConstructor, bindable.getType(), parameterNameDiscoverer);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate static Map<CacheKey, Object> getCache(Context context) {\n\t\t\tMap<CacheKey, Object> cache = (Map<CacheKey, Object>) context.getCache().get(ValueObject.class);\n\t\t\tif (cache == null) {\n\t\t\t\tcache = new ConcurrentHashMap<>();\n\t\t\t\tcontext.getCache().put(ValueObject.class, cache);\n\t\t\t}\n\t\t\treturn cache;\n\t\t}\n\n\t\tprivate record CacheKey(Bindable<?> bindable, BindConstructorProvider constructorProvider,\n\t\t\t\tParameterNameDiscoverer parameterNameDiscoverer) {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@link ValueObject} implementation that is aware of Kotlin specific constructs.\n\t */\n\tprivate static final class KotlinValueObject<T> extends ValueObject<T> {\n\n\t\tprivate static final Annotation[] ANNOTATION_ARRAY = new Annotation[0];\n\n\t\tprivate final List<ConstructorParameter> constructorParameters;\n\n\t\tprivate KotlinValueObject(Constructor<T> primaryConstructor, KFunction<T> kotlinConstructor,\n\t\t\t\tResolvableType type) {\n\t\t\tsuper(primaryConstructor);\n\t\t\tthis.constructorParameters = parseConstructorParameters(kotlinConstructor, type);\n\t\t}\n\n\t\tprivate List<ConstructorParameter> parseConstructorParameters(KFunction<T> kotlinConstructor,\n\t\t\t\tResolvableType type) {\n\t\t\tList<KParameter> parameters = kotlinConstructor.getParameters();\n\t\t\tList<ConstructorParameter> result = new ArrayList<>(parameters.size());\n\t\t\tfor (KParameter parameter : parameters) {\n\t\t\t\tString name = getParameterName(parameter);\n\t\t\t\tResolvableType parameterType = ResolvableType\n\t\t\t\t\t.forType(ReflectJvmMapping.getJavaType(parameter.getType()), type);\n\t\t\t\tAnnotation[] annotations = parameter.getAnnotations().toArray(ANNOTATION_ARRAY);\n\t\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\t\tresult.add(new ConstructorParameter(name, parameterType, annotations));\n\t\t\t}\n\t\t\treturn Collections.unmodifiableList(result);\n\t\t}\n\n\t\tprivate @Nullable String getParameterName(KParameter parameter) {\n\t\t\treturn MergedAnnotations.from(parameter, parameter.getAnnotations().toArray(ANNOTATION_ARRAY))\n\t\t\t\t.get(Name.class)\n\t\t\t\t.getValue(MergedAnnotation.VALUE, String.class)\n\t\t\t\t.orElseGet(parameter::getName);\n\t\t}\n\n\t\t@Override\n\t\tList<ConstructorParameter> getConstructorParameters() {\n\t\t\treturn this.constructorParameters;\n\t\t}\n\n\t\tstatic <T> @Nullable ValueObject<T> get(Constructor<T> bindConstructor, ResolvableType type,\n\t\t\t\tParameterNameDiscoverer parameterNameDiscoverer) {\n\t\t\tKFunction<T> kotlinConstructor = ReflectJvmMapping.getKotlinFunction(bindConstructor);\n\t\t\tif (kotlinConstructor != null) {\n\t\t\t\treturn new KotlinValueObject<>(bindConstructor, kotlinConstructor, type);\n\t\t\t}\n\t\t\treturn DefaultValueObject.get(bindConstructor, type, parameterNameDiscoverer);\n\t\t}\n\n\t}\n\n\t/**\n\t * A default {@link ValueObject} implementation that uses only standard Java\n\t * reflection calls.\n\t */\n\tprivate static final class DefaultValueObject<T> extends ValueObject<T> {\n\n\t\tprivate final List<ConstructorParameter> constructorParameters;\n\n\t\tprivate DefaultValueObject(Constructor<T> constructor, List<ConstructorParameter> constructorParameters) {\n\t\t\tsuper(constructor);\n\t\t\tthis.constructorParameters = constructorParameters;\n\t\t}\n\n\t\t@Override\n\t\tList<ConstructorParameter> getConstructorParameters() {\n\t\t\treturn this.constructorParameters;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tstatic <T> @Nullable ValueObject<T> get(Constructor<?> bindConstructor, ResolvableType type,\n\t\t\t\tParameterNameDiscoverer parameterNameDiscoverer) {\n\t\t\t@Nullable String @Nullable [] names = parameterNameDiscoverer.getParameterNames(bindConstructor);\n\t\t\tif (names == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tList<ConstructorParameter> constructorParameters = parseConstructorParameters(bindConstructor, type, names);\n\t\t\treturn new DefaultValueObject<>((Constructor<T>) bindConstructor, constructorParameters);\n\t\t}\n\n\t\tprivate static List<ConstructorParameter> parseConstructorParameters(Constructor<?> constructor,\n\t\t\t\tResolvableType type, @Nullable String[] names) {\n\t\t\tParameter[] parameters = constructor.getParameters();\n\t\t\tList<ConstructorParameter> result = new ArrayList<>(parameters.length);\n\t\t\tfor (int i = 0; i < parameters.length; i++) {\n\t\t\t\tString name = MergedAnnotations.from(parameters[i])\n\t\t\t\t\t.get(Name.class)\n\t\t\t\t\t.getValue(MergedAnnotation.VALUE, String.class)\n\t\t\t\t\t.orElse(names[i]);\n\t\t\t\tResolvableType parameterType = ResolvableType.forMethodParameter(new MethodParameter(constructor, i),\n\t\t\t\t\t\ttype);\n\t\t\t\tAnnotation[] annotations = parameters[i].getDeclaredAnnotations();\n\t\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\t\tresult.add(new ConstructorParameter(name, parameterType, annotations));\n\t\t\t}\n\t\t\treturn Collections.unmodifiableList(result);\n\t\t}\n\n\t}\n\n\t/**\n\t * A constructor parameter being bound.\n\t */\n\tprivate static class ConstructorParameter {\n\n\t\tprivate final String name;\n\n\t\tprivate final ResolvableType type;\n\n\t\tprivate final Annotation[] annotations;\n\n\t\tConstructorParameter(String name, ResolvableType type, Annotation[] annotations) {\n\t\t\tthis.name = DataObjectPropertyName.toDashedForm(name);\n\t\t\tthis.type = type;\n\t\t\tthis.annotations = annotations;\n\t\t}\n\n\t\t@Nullable Object bind(DataObjectPropertyBinder propertyBinder) {\n\t\t\treturn propertyBinder.bindProperty(this.name, Bindable.of(this.type).withAnnotations(this.annotations));\n\t\t}\n\n\t\tAnnotation[] getAnnotations() {\n\t\t\treturn this.annotations;\n\t\t}\n\n\t\tResolvableType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ParameterNameDiscoverer} used for value data object binding.\n\t */\n\tstatic final class Discoverer implements ParameterNameDiscoverer {\n\n\t\tprivate static final ParameterNameDiscoverer DEFAULT_DELEGATE = new DefaultParameterNameDiscoverer();\n\n\t\tprivate static final ParameterNameDiscoverer LENIENT = new Discoverer(DEFAULT_DELEGATE, (message) -> {\n\t\t});\n\n\t\tprivate static final ParameterNameDiscoverer STRICT = new Discoverer(DEFAULT_DELEGATE, (message) -> {\n\t\t\tthrow new IllegalStateException(message.toString());\n\t\t});\n\n\t\tprivate final ParameterNameDiscoverer delegate;\n\n\t\tprivate final Consumer<LogMessage> noParameterNamesHandler;\n\n\t\tprivate Discoverer(ParameterNameDiscoverer delegate, Consumer<LogMessage> noParameterNamesHandler) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.noParameterNamesHandler = noParameterNamesHandler;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getParameterNames(Method method) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String @Nullable [] getParameterNames(Constructor<?> constructor) {\n\t\t\t@Nullable String @Nullable [] names = this.delegate.getParameterNames(constructor);\n\t\t\tif (names != null) {\n\t\t\t\treturn names;\n\t\t\t}\n\t\t\tLogMessage message = LogMessage.format(\n\t\t\t\t\t\"Unable to use value object binding with constructor [%s] as parameter names cannot be discovered. \"\n\t\t\t\t\t\t\t+ \"Ensure that the compiler uses the '-parameters' flag\",\n\t\t\t\t\tconstructor);\n\t\t\tthis.noParameterNamesHandler.accept(message);\n\t\t\tlogger.debug(message);\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/handler/IgnoreErrorsBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\n\n/**\n * {@link BindHandler} that can be used to ignore binding errors.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class IgnoreErrorsBindHandler extends AbstractBindHandler {\n\n\tpublic IgnoreErrorsBindHandler() {\n\t}\n\n\tpublic IgnoreErrorsBindHandler(BindHandler parent) {\n\t\tsuper(parent);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tException error) throws Exception {\n\t\treturn (target.getValue() != null) ? target.getValue().get() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/handler/IgnoreTopLevelConverterNotFoundBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.core.convert.ConverterNotFoundException;\n\n/**\n * {@link BindHandler} that can be used to ignore top-level\n * {@link ConverterNotFoundException}s.\n *\n * @author Madhura Bhave\n * @since 2.0.1\n */\npublic class IgnoreTopLevelConverterNotFoundBindHandler extends AbstractBindHandler {\n\n\t/**\n\t * Create a new {@link IgnoreTopLevelConverterNotFoundBindHandler} instance.\n\t */\n\tpublic IgnoreTopLevelConverterNotFoundBindHandler() {\n\t}\n\n\t/**\n\t * Create a new {@link IgnoreTopLevelConverterNotFoundBindHandler} instance with a\n\t * specific parent.\n\t * @param parent the parent handler\n\t */\n\tpublic IgnoreTopLevelConverterNotFoundBindHandler(BindHandler parent) {\n\t\tsuper(parent);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tException error) throws Exception {\n\t\tif (context.getDepth() == 0 && error instanceof ConverterNotFoundException) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow error;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/handler/NoUnboundElementsBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.UnboundConfigurationPropertiesException;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.IterableConfigurationPropertySource;\n\n/**\n * {@link BindHandler} to enforce that all configuration properties under the root name\n * have been bound.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class NoUnboundElementsBindHandler extends AbstractBindHandler {\n\n\tprivate final Set<ConfigurationPropertyName> boundNames = new HashSet<>();\n\n\tprivate final Set<ConfigurationPropertyName> attemptedNames = new HashSet<>();\n\n\tprivate final Function<ConfigurationPropertySource, Boolean> filter;\n\n\tNoUnboundElementsBindHandler() {\n\t\tthis(BindHandler.DEFAULT, (configurationPropertySource) -> true);\n\t}\n\n\tpublic NoUnboundElementsBindHandler(BindHandler parent) {\n\t\tthis(parent, (configurationPropertySource) -> true);\n\t}\n\n\tpublic NoUnboundElementsBindHandler(BindHandler parent, Function<ConfigurationPropertySource, Boolean> filter) {\n\t\tsuper(parent);\n\t\tthis.filter = filter;\n\t}\n\n\t@Override\n\tpublic <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {\n\t\tthis.attemptedNames.add(name);\n\t\treturn super.onStart(name, target, context);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tObject result) {\n\t\tthis.boundNames.add(name);\n\t\treturn super.onSuccess(name, target, context, result);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tException error) throws Exception {\n\t\tif (error instanceof UnboundConfigurationPropertiesException) {\n\t\t\tthrow error;\n\t\t}\n\t\treturn super.onFailure(name, target, context, error);\n\t}\n\n\t@Override\n\tpublic void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t@Nullable Object result) throws Exception {\n\t\tif (context.getDepth() == 0) {\n\t\t\tcheckNoUnboundElements(name, context);\n\t\t}\n\t}\n\n\tprivate void checkNoUnboundElements(ConfigurationPropertyName name, BindContext context) {\n\t\tSet<ConfigurationProperty> unbound = new TreeSet<>();\n\t\tfor (ConfigurationPropertySource source : context.getSources()) {\n\t\t\tif (source instanceof IterableConfigurationPropertySource && this.filter.apply(source)) {\n\t\t\t\tcollectUnbound(name, unbound, (IterableConfigurationPropertySource) source);\n\t\t\t}\n\t\t}\n\t\tif (!unbound.isEmpty()) {\n\t\t\tthrow new UnboundConfigurationPropertiesException(unbound);\n\t\t}\n\t}\n\n\tprivate void collectUnbound(ConfigurationPropertyName name, Set<ConfigurationProperty> unbound,\n\t\t\tIterableConfigurationPropertySource source) {\n\t\tIterableConfigurationPropertySource filtered = source.filter((candidate) -> isUnbound(name, candidate));\n\t\tfor (ConfigurationPropertyName unboundName : filtered) {\n\t\t\ttry {\n\t\t\t\tunbound.add(\n\t\t\t\t\t\tsource.filter((candidate) -> isUnbound(name, candidate)).getConfigurationProperty(unboundName));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isUnbound(ConfigurationPropertyName name, ConfigurationPropertyName candidate) {\n\t\tif (name.isAncestorOf(candidate)) {\n\t\t\treturn !this.boundNames.contains(candidate) && !isOverriddenCollectionElement(candidate);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isOverriddenCollectionElement(ConfigurationPropertyName candidate) {\n\t\tint lastIndex = candidate.getNumberOfElements() - 1;\n\t\tif (candidate.isLastElementIndexed()) {\n\t\t\tConfigurationPropertyName propertyName = candidate.chop(lastIndex);\n\t\t\treturn this.boundNames.contains(propertyName);\n\t\t}\n\t\tIndexed indexed = getIndexed(candidate);\n\t\tif (indexed != null) {\n\t\t\tString zeroethProperty = indexed.getName() + \"[0]\";\n\t\t\tif (this.boundNames.contains(ConfigurationPropertyName.of(zeroethProperty))) {\n\t\t\t\tString nestedZeroethProperty = zeroethProperty + \".\" + indexed.getNestedPropertyName();\n\t\t\t\treturn isCandidateValidPropertyName(nestedZeroethProperty);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isCandidateValidPropertyName(String nestedZeroethProperty) {\n\t\treturn this.attemptedNames.contains(ConfigurationPropertyName.of(nestedZeroethProperty));\n\t}\n\n\tprivate @Nullable Indexed getIndexed(ConfigurationPropertyName candidate) {\n\t\tfor (int i = 0; i < candidate.getNumberOfElements(); i++) {\n\t\t\tif (candidate.isNumericIndex(i)) {\n\t\t\t\treturn new Indexed(candidate.chop(i).toString(),\n\t\t\t\t\t\tcandidate.getElement(i + 1, ConfigurationPropertyName.Form.UNIFORM));\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static final class Indexed {\n\n\t\tprivate final String name;\n\n\t\tprivate final String nestedPropertyName;\n\n\t\tprivate Indexed(String name, String nestedPropertyName) {\n\t\t\tthis.name = name;\n\t\t\tthis.nestedPropertyName = nestedPropertyName;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tString getNestedPropertyName() {\n\t\t\treturn this.nestedPropertyName;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/handler/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General {@link org.springframework.boot.context.properties.bind.BindHandler\n * BindHandler} implementations.\n */\n@NullMarked\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for {@code @ConfigurationProperties} binding.\n */\n@NullMarked\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/BindValidationException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Error thrown when validation fails during a bind operation.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see ValidationErrors\n * @see ValidationBindHandler\n */\npublic class BindValidationException extends RuntimeException {\n\n\tprivate final ValidationErrors validationErrors;\n\n\tBindValidationException(ValidationErrors validationErrors) {\n\t\tsuper(getMessage(validationErrors));\n\t\tAssert.notNull(validationErrors, \"'validationErrors' must not be null\");\n\t\tthis.validationErrors = validationErrors;\n\t}\n\n\t/**\n\t * Return the validation errors that caused the exception.\n\t * @return the validationErrors the validation errors\n\t */\n\tpublic ValidationErrors getValidationErrors() {\n\t\treturn this.validationErrors;\n\t}\n\n\tprivate static String getMessage(@Nullable ValidationErrors errors) {\n\t\tStringBuilder message = new StringBuilder(\"Binding validation errors\");\n\t\tif (errors != null) {\n\t\t\tmessage.append(\" on \").append(errors.getName());\n\t\t\terrors.getAllErrors().forEach((error) -> message.append(String.format(\"%n   - %s\", error)));\n\t\t}\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/OriginTrackedFieldError.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.lang.Contract;\nimport org.springframework.validation.FieldError;\n\n/**\n * {@link FieldError} implementation that tracks the source {@link Origin}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nfinal class OriginTrackedFieldError extends FieldError implements OriginProvider {\n\n\tprivate final @Nullable Origin origin;\n\n\tprivate OriginTrackedFieldError(FieldError fieldError, @Nullable Origin origin) {\n\t\tsuper(fieldError.getObjectName(), fieldError.getField(), fieldError.getRejectedValue(),\n\t\t\t\tfieldError.isBindingFailure(), fieldError.getCodes(), fieldError.getArguments(),\n\t\t\t\tfieldError.getDefaultMessage());\n\t\tthis.origin = origin;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tif (this.origin == null) {\n\t\t\treturn super.toString();\n\t\t}\n\t\treturn super.toString() + \"; origin \" + this.origin;\n\t}\n\n\t@Contract(\"!null, _ -> !null\")\n\tstatic @Nullable FieldError of(@Nullable FieldError fieldError, @Nullable Origin origin) {\n\t\tif (fieldError == null || origin == null) {\n\t\t\treturn fieldError;\n\t\t}\n\t\treturn new OriginTrackedFieldError(fieldError, origin);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.NotReadablePropertyException;\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.DataObjectPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.validation.AbstractBindingResult;\nimport org.springframework.validation.BeanPropertyBindingResult;\nimport org.springframework.validation.Validator;\n\n/**\n * {@link BindHandler} to apply {@link Validator Validators} to bound results.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class ValidationBindHandler extends AbstractBindHandler {\n\n\tprivate final Validator[] validators;\n\n\tprivate final Map<ConfigurationPropertyName, ResolvableType> boundTypes = new LinkedHashMap<>();\n\n\tprivate final Map<ConfigurationPropertyName, Object> boundResults = new LinkedHashMap<>();\n\n\tprivate final Set<ConfigurationProperty> boundProperties = new LinkedHashSet<>();\n\n\tprivate @Nullable BindValidationException exception;\n\n\tpublic ValidationBindHandler(Validator... validators) {\n\t\tthis.validators = validators;\n\t}\n\n\tpublic ValidationBindHandler(BindHandler parent, Validator... validators) {\n\t\tsuper(parent);\n\t\tthis.validators = validators;\n\t}\n\n\t@Override\n\tpublic <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {\n\t\tthis.boundTypes.put(name, target.getType());\n\t\treturn super.onStart(name, target, context);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tObject result) {\n\t\tthis.boundResults.put(name, result);\n\t\tif (context.getConfigurationProperty() != null) {\n\t\t\tthis.boundProperties.add(context.getConfigurationProperty());\n\t\t}\n\t\treturn super.onSuccess(name, target, context, result);\n\t}\n\n\t@Override\n\tpublic @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\tException error) throws Exception {\n\t\tObject result = super.onFailure(name, target, context, error);\n\t\tif (result != null) {\n\t\t\tclear();\n\t\t\tthis.boundResults.put(name, result);\n\t\t}\n\t\tvalidate(name, target, context, result);\n\t\treturn result;\n\t}\n\n\tprivate void clear() {\n\t\tthis.boundTypes.clear();\n\t\tthis.boundResults.clear();\n\t\tthis.boundProperties.clear();\n\t\tthis.exception = null;\n\t}\n\n\t@Override\n\tpublic void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t@Nullable Object result) throws Exception {\n\t\tvalidate(name, target, context, result);\n\t\tsuper.onFinish(name, target, context, result);\n\t}\n\n\tprivate void validate(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t@Nullable Object result) {\n\t\tif (this.exception == null) {\n\t\t\tObject validationTarget = getValidationTarget(target, context, result);\n\t\t\tClass<?> validationType = target.getBoxedType().resolve();\n\t\t\tif (validationTarget != null) {\n\t\t\t\tAssert.state(validationType != null, \"'validationType' must not be null\");\n\t\t\t\tvalidateAndPush(name, validationTarget, validationType);\n\t\t\t}\n\t\t}\n\t\tif (context.getDepth() == 0 && this.exception != null) {\n\t\t\tthrow this.exception;\n\t\t}\n\t}\n\n\tprivate @Nullable Object getValidationTarget(Bindable<?> target, BindContext context, @Nullable Object result) {\n\t\tif (result != null) {\n\t\t\treturn result;\n\t\t}\n\t\tif (context.getDepth() == 0 && target.getValue() != null) {\n\t\t\treturn target.getValue().get();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void validateAndPush(ConfigurationPropertyName name, Object target, Class<?> type) {\n\t\tValidationResult result = null;\n\t\tfor (Validator validator : this.validators) {\n\t\t\tif (validator.supports(type)) {\n\t\t\t\tresult = (result != null) ? result : new ValidationResult(name, target);\n\t\t\t\tvalidator.validate(target, result);\n\t\t\t}\n\t\t}\n\t\tif (result != null && result.hasErrors()) {\n\t\t\tthis.exception = new BindValidationException(result.getValidationErrors());\n\t\t}\n\t}\n\n\t/**\n\t * {@link AbstractBindingResult} implementation backed by the bound properties.\n\t */\n\tprivate class ValidationResult extends BeanPropertyBindingResult {\n\n\t\tprivate final ConfigurationPropertyName name;\n\n\t\tprotected ValidationResult(ConfigurationPropertyName name, Object target) {\n\t\t\tsuper(target, \"\");\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getObjectName() {\n\t\t\treturn this.name.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Class<?> getFieldType(@Nullable String field) {\n\t\t\tResolvableType type = getBoundField(ValidationBindHandler.this.boundTypes, field);\n\t\t\tClass<?> resolved = (type != null) ? type.resolve() : null;\n\t\t\tif (resolved != null) {\n\t\t\t\treturn resolved;\n\t\t\t}\n\t\t\treturn super.getFieldType(field);\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable Object getActualFieldValue(String field) {\n\t\t\tObject boundField = getBoundField(ValidationBindHandler.this.boundResults, field);\n\t\t\tif (boundField != null) {\n\t\t\t\treturn boundField;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn super.getActualFieldValue(field);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tif (isPropertyNotReadable(ex)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isPropertyNotReadable(Throwable ex) {\n\t\t\twhile (ex != null) {\n\t\t\t\tif (ex instanceof NotReadablePropertyException) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tex = ex.getCause();\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate <T> @Nullable T getBoundField(Map<ConfigurationPropertyName, T> boundFields, @Nullable String field) {\n\t\t\tif (field == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tConfigurationPropertyName name = getName(field);\n\t\t\t\tT bound = boundFields.get(name);\n\t\t\t\tif (bound != null) {\n\t\t\t\t\treturn bound;\n\t\t\t\t}\n\t\t\t\tif (name.hasIndexedElement()) {\n\t\t\t\t\tfor (Map.Entry<ConfigurationPropertyName, T> entry : boundFields.entrySet()) {\n\t\t\t\t\t\tif (isFieldNameMatch(entry.getKey(), name)) {\n\t\t\t\t\t\t\treturn entry.getValue();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate boolean isFieldNameMatch(ConfigurationPropertyName name, ConfigurationPropertyName fieldName) {\n\t\t\tif (name.getNumberOfElements() != fieldName.getNumberOfElements()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (int i = 0; i < name.getNumberOfElements(); i++) {\n\t\t\t\tString element = name.getElement(i, Form.ORIGINAL);\n\t\t\t\tString fieldElement = fieldName.getElement(i, Form.ORIGINAL);\n\t\t\t\tif (!ObjectUtils.nullSafeEquals(element, fieldElement)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate ConfigurationPropertyName getName(String field) {\n\t\t\treturn this.name.append(DataObjectPropertyName.toDashedForm(field));\n\t\t}\n\n\t\tValidationErrors getValidationErrors() {\n\t\t\tSet<ConfigurationProperty> boundProperties = ValidationBindHandler.this.boundProperties.stream()\n\t\t\t\t.filter((property) -> this.name.isAncestorOf(property.getName()))\n\t\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t\t\treturn new ValidationErrors(this.name, boundProperties, getAllErrors());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/ValidationErrors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\n\n/**\n * A collection of {@link ObjectError ObjectErrors} caused by bind validation failures.\n * Where possible, included {@link FieldError FieldErrors} will be OriginProvider.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class ValidationErrors implements Iterable<ObjectError> {\n\n\tprivate final ConfigurationPropertyName name;\n\n\tprivate final Set<ConfigurationProperty> boundProperties;\n\n\tprivate final List<ObjectError> errors;\n\n\tValidationErrors(ConfigurationPropertyName name, Set<ConfigurationProperty> boundProperties,\n\t\t\tList<ObjectError> errors) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(boundProperties, \"'boundProperties' must not be null\");\n\t\tAssert.notNull(errors, \"'errors' must not be null\");\n\t\tthis.name = name;\n\t\tthis.boundProperties = Collections.unmodifiableSet(boundProperties);\n\t\tthis.errors = convertErrors(name, boundProperties, errors);\n\t}\n\n\tprivate List<ObjectError> convertErrors(ConfigurationPropertyName name, Set<ConfigurationProperty> boundProperties,\n\t\t\tList<ObjectError> errors) {\n\t\tList<ObjectError> converted = new ArrayList<>(errors.size());\n\t\tfor (ObjectError error : errors) {\n\t\t\tconverted.add(convertError(name, boundProperties, error));\n\t\t}\n\t\treturn Collections.unmodifiableList(converted);\n\t}\n\n\tprivate ObjectError convertError(ConfigurationPropertyName name, Set<ConfigurationProperty> boundProperties,\n\t\t\tObjectError error) {\n\t\tif (error instanceof FieldError fieldError) {\n\t\t\treturn convertFieldError(name, boundProperties, fieldError);\n\t\t}\n\t\treturn error;\n\t}\n\n\tprivate FieldError convertFieldError(ConfigurationPropertyName name, Set<ConfigurationProperty> boundProperties,\n\t\t\tFieldError error) {\n\t\tif (error instanceof OriginProvider) {\n\t\t\treturn error;\n\t\t}\n\t\treturn OriginTrackedFieldError.of(error, findFieldErrorOrigin(name, boundProperties, error));\n\t}\n\n\tprivate @Nullable Origin findFieldErrorOrigin(ConfigurationPropertyName name,\n\t\t\tSet<ConfigurationProperty> boundProperties, FieldError error) {\n\t\tfor (ConfigurationProperty boundProperty : boundProperties) {\n\t\t\tif (isForError(name, boundProperty.getName(), error)) {\n\t\t\t\treturn Origin.from(boundProperty);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isForError(ConfigurationPropertyName name, ConfigurationPropertyName boundPropertyName,\n\t\t\tFieldError error) {\n\t\treturn name.isParentOf(boundPropertyName)\n\t\t\t\t&& boundPropertyName.getLastElement(Form.UNIFORM).equalsIgnoreCase(error.getField());\n\t}\n\n\t/**\n\t * Return the name of the item that was being validated.\n\t * @return the name of the item\n\t */\n\tpublic ConfigurationPropertyName getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the properties that were bound before validation failed.\n\t * @return the boundProperties\n\t */\n\tpublic Set<ConfigurationProperty> getBoundProperties() {\n\t\treturn this.boundProperties;\n\t}\n\n\tpublic boolean hasErrors() {\n\t\treturn !this.errors.isEmpty();\n\t}\n\n\t/**\n\t * Return the list of all validation errors.\n\t * @return the errors\n\t */\n\tpublic List<ObjectError> getAllErrors() {\n\t\treturn this.errors;\n\t}\n\n\t@Override\n\tpublic Iterator<ObjectError> iterator() {\n\t\treturn this.errors.iterator();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Binding validation support.\n */\n@NullMarked\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for external configuration properties.\n *\n * @see org.springframework.boot.context.properties.ConfigurationProperties\n * @see org.springframework.boot.context.properties.EnableConfigurationProperties\n */\n@NullMarked\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/AliasedConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A {@link ConfigurationPropertySource} supporting name aliases.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AliasedConfigurationPropertySource implements ConfigurationPropertySource {\n\n\tprivate final ConfigurationPropertySource source;\n\n\tprivate final ConfigurationPropertyNameAliases aliases;\n\n\tAliasedConfigurationPropertySource(ConfigurationPropertySource source, ConfigurationPropertyNameAliases aliases) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(aliases, \"'aliases' must not be null\");\n\t\tthis.source = source;\n\t\tthis.aliases = aliases;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tConfigurationProperty result = getSource().getConfigurationProperty(name);\n\t\tif (result == null) {\n\t\t\tConfigurationPropertyName aliasedName = getAliases().getNameForAlias(name);\n\t\t\tresult = (aliasedName != null) ? getSource().getConfigurationProperty(aliasedName) : null;\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tConfigurationPropertyState result = this.source.containsDescendantOf(name);\n\t\tif (result != ConfigurationPropertyState.ABSENT) {\n\t\t\treturn result;\n\t\t}\n\t\tfor (ConfigurationPropertyName alias : getAliases().getAliases(name)) {\n\t\t\tConfigurationPropertyState aliasResult = this.source.containsDescendantOf(alias);\n\t\t\tif (aliasResult != ConfigurationPropertyState.ABSENT) {\n\t\t\t\treturn aliasResult;\n\t\t\t}\n\t\t}\n\t\tfor (ConfigurationPropertyName from : getAliases()) {\n\t\t\tfor (ConfigurationPropertyName alias : getAliases().getAliases(from)) {\n\t\t\t\tif (name.isAncestorOf(alias)) {\n\t\t\t\t\tif (this.source.getConfigurationProperty(from) != null) {\n\t\t\t\t\t\treturn ConfigurationPropertyState.PRESENT;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn ConfigurationPropertyState.ABSENT;\n\t}\n\n\t@Override\n\tpublic @Nullable Object getUnderlyingSource() {\n\t\treturn this.source.getUnderlyingSource();\n\t}\n\n\tprotected ConfigurationPropertySource getSource() {\n\t\treturn this.source;\n\t}\n\n\tprotected ConfigurationPropertyNameAliases getAliases() {\n\t\treturn this.aliases;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/AliasedIterableConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.springframework.util.CollectionUtils;\n\n/**\n * A {@link IterableConfigurationPropertySource} supporting name aliases.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AliasedIterableConfigurationPropertySource extends AliasedConfigurationPropertySource\n\t\timplements IterableConfigurationPropertySource {\n\n\tAliasedIterableConfigurationPropertySource(IterableConfigurationPropertySource source,\n\t\t\tConfigurationPropertyNameAliases aliases) {\n\t\tsuper(source, aliases);\n\t}\n\n\t@Override\n\tpublic Stream<ConfigurationPropertyName> stream() {\n\t\treturn getSource().stream().flatMap(this::addAliases);\n\t}\n\n\tprivate Stream<ConfigurationPropertyName> addAliases(ConfigurationPropertyName name) {\n\t\tStream<ConfigurationPropertyName> names = Stream.of(name);\n\t\tList<ConfigurationPropertyName> aliases = getAliases().getAliases(name);\n\t\tif (CollectionUtils.isEmpty(aliases)) {\n\t\t\treturn names;\n\t\t}\n\t\treturn Stream.concat(names, aliases.stream());\n\t}\n\n\t@Override\n\tprotected IterableConfigurationPropertySource getSource() {\n\t\treturn (IterableConfigurationPropertySource) super.getSource();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/CachingConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Interface used to indicate that a {@link ConfigurationPropertySource} supports\n * {@link ConfigurationPropertyCaching}.\n *\n * @author Phillip Webb\n */\ninterface CachingConfigurationPropertySource {\n\n\t/**\n\t * Return {@link ConfigurationPropertyCaching} for this source.\n\t * @return source caching\n\t */\n\tConfigurationPropertyCaching getCaching();\n\n\t/**\n\t * Find {@link ConfigurationPropertyCaching} for the given source.\n\t * @param source the configuration property source\n\t * @return a {@link ConfigurationPropertyCaching} instance or {@code null} if the\n\t * source does not support caching.\n\t */\n\tstatic @Nullable ConfigurationPropertyCaching find(@Nullable ConfigurationPropertySource source) {\n\t\tif (source instanceof CachingConfigurationPropertySource cachingSource) {\n\t\t\treturn cachingSource.getCaching();\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A single configuration property obtained from a {@link ConfigurationPropertySource}\n * consisting of a {@link #getName() name}, {@link #getValue() value} and optional\n * {@link #getOrigin() origin}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic final class ConfigurationProperty implements OriginProvider, Comparable<ConfigurationProperty> {\n\n\tprivate final ConfigurationPropertyName name;\n\n\tprivate final Object value;\n\n\tprivate final @Nullable ConfigurationPropertySource source;\n\n\tprivate final @Nullable Origin origin;\n\n\tpublic ConfigurationProperty(ConfigurationPropertyName name, Object value, @Nullable Origin origin) {\n\t\tthis(null, name, value, origin);\n\t}\n\n\tprivate ConfigurationProperty(@Nullable ConfigurationPropertySource source, ConfigurationPropertyName name,\n\t\t\tObject value, @Nullable Origin origin) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\tthis.source = source;\n\t\tthis.name = name;\n\t\tthis.value = value;\n\t\tthis.origin = origin;\n\t}\n\n\t/**\n\t * Return the {@link ConfigurationPropertySource} that provided the property or\n\t * {@code null} if the source is unknown.\n\t * @return the configuration property source\n\t * @since 2.6.0\n\t */\n\tpublic @Nullable ConfigurationPropertySource getSource() {\n\t\treturn this.source;\n\t}\n\n\t/**\n\t * Return the name of the configuration property.\n\t * @return the configuration property name\n\t */\n\tpublic ConfigurationPropertyName getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the value of the configuration property.\n\t * @return the configuration property value\n\t */\n\tpublic Object getValue() {\n\t\treturn this.value;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tConfigurationProperty other = (ConfigurationProperty) obj;\n\t\tboolean result = true;\n\t\tresult = result && ObjectUtils.nullSafeEquals(this.name, other.name);\n\t\tresult = result && ObjectUtils.nullSafeEquals(this.value, other.value);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = ObjectUtils.nullSafeHashCode(this.name);\n\t\tresult = 31 * result + ObjectUtils.nullSafeHashCode(this.value);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new ToStringCreator(this).append(\"name\", this.name)\n\t\t\t.append(\"value\", this.value)\n\t\t\t.append(\"origin\", this.origin)\n\t\t\t.toString();\n\t}\n\n\t@Override\n\tpublic int compareTo(ConfigurationProperty other) {\n\t\treturn this.name.compareTo(other.name);\n\t}\n\n\t@Contract(\"_, !null -> !null\")\n\tstatic @Nullable ConfigurationProperty of(ConfigurationPropertyName name, @Nullable OriginTrackedValue value) {\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ConfigurationProperty(name, value.getValue(), value.getOrigin());\n\t}\n\n\t@Contract(\"_, _, !null, _ -> !null\")\n\tstatic @Nullable ConfigurationProperty of(@Nullable ConfigurationPropertySource source,\n\t\t\tConfigurationPropertyName name, @Nullable Object value, @Nullable Origin origin) {\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ConfigurationProperty(source, name, value, origin);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyCaching.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * Interface that can be used to control configuration property source caches.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface ConfigurationPropertyCaching {\n\n\t/**\n\t * Enable caching with an unlimited time-to-live.\n\t */\n\tvoid enable();\n\n\t/**\n\t * Disable caching.\n\t */\n\tvoid disable();\n\n\t/**\n\t * Set amount of time that an item can live in the cache. Calling this method will\n\t * also enable the cache.\n\t * @param timeToLive the time to live value.\n\t */\n\tvoid setTimeToLive(Duration timeToLive);\n\n\t/**\n\t * Clear the cache and force it to be reloaded on next access.\n\t */\n\tvoid clear();\n\n\t/**\n\t * Override caching to temporarily enable it. Once caching is no longer needed the\n\t * returned {@link CacheOverride} should be closed to restore previous cache settings.\n\t * @return a {@link CacheOverride}\n\t * @since 3.5.0\n\t */\n\tCacheOverride override();\n\n\t/**\n\t * Get for all configuration property sources in the environment.\n\t * @param environment the spring environment\n\t * @return a caching instance that controls all sources in the environment\n\t */\n\tstatic ConfigurationPropertyCaching get(Environment environment) {\n\t\treturn get(environment, null);\n\t}\n\n\t/**\n\t * Get for a specific configuration property source in the environment.\n\t * @param environment the spring environment\n\t * @param underlyingSource the\n\t * {@link ConfigurationPropertySource#getUnderlyingSource() underlying source} that\n\t * must match\n\t * @return a caching instance that controls the matching source\n\t */\n\tstatic ConfigurationPropertyCaching get(Environment environment, @Nullable Object underlyingSource) {\n\t\tIterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);\n\t\treturn get(sources, underlyingSource);\n\t}\n\n\t/**\n\t * Get for all specified configuration property sources.\n\t * @param sources the configuration property sources\n\t * @return a caching instance that controls the sources\n\t */\n\tstatic ConfigurationPropertyCaching get(Iterable<ConfigurationPropertySource> sources) {\n\t\treturn get(sources, null);\n\t}\n\n\t/**\n\t * Get for a specific configuration property source in the specified configuration\n\t * property sources.\n\t * @param sources the configuration property sources\n\t * @param underlyingSource the\n\t * {@link ConfigurationPropertySource#getUnderlyingSource() underlying source} that\n\t * must match\n\t * @return a caching instance that controls the matching source\n\t */\n\tstatic ConfigurationPropertyCaching get(Iterable<ConfigurationPropertySource> sources,\n\t\t\t@Nullable Object underlyingSource) {\n\t\tAssert.notNull(sources, \"'sources' must not be null\");\n\t\tif (underlyingSource == null) {\n\t\t\treturn new ConfigurationPropertySourcesCaching(sources);\n\t\t}\n\t\tfor (ConfigurationPropertySource source : sources) {\n\t\t\tif (source.getUnderlyingSource() == underlyingSource) {\n\t\t\t\tConfigurationPropertyCaching caching = CachingConfigurationPropertySource.find(source);\n\t\t\t\tif (caching != null) {\n\t\t\t\t\treturn caching;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Unable to find cache from configuration property sources\");\n\t}\n\n\t/**\n\t * {@link AutoCloseable} used to control a\n\t * {@link ConfigurationPropertyCaching#override() cache override}.\n\t *\n\t * @since 3.5.0\n\t */\n\tinterface CacheOverride extends AutoCloseable {\n\n\t\t@Override\n\t\tvoid close();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.function.IntFunction;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A configuration property name composed of elements separated by dots. User created\n * names may contain the characters \"{@code a-z}\" \"{@code 0-9}\" and \"{@code -}\", they must\n * be lower-case and must start with an alphanumeric character. The \"{@code -}\" is used\n * purely for formatting, i.e. \"{@code foo-bar}\" and \"{@code foobar}\" are considered\n * equivalent.\n * <p>\n * The \"{@code [}\" and \"{@code ]}\" characters may be used to indicate an associative\n * index(i.e. a {@link Map} key or a {@link Collection} index). Indexes names are not\n * restricted and are considered case-sensitive.\n * <p>\n * Here are some typical examples:\n * <ul>\n * <li>{@code spring.main.banner-mode}</li>\n * <li>{@code server.hosts[0].name}</li>\n * <li>{@code log[org.springboot].level}</li>\n * </ul>\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see #of(CharSequence)\n * @see ConfigurationPropertySource\n */\npublic final class ConfigurationPropertyName implements Comparable<ConfigurationPropertyName> {\n\n\tprivate static final String EMPTY_STRING = \"\";\n\n\t/**\n\t * An empty {@link ConfigurationPropertyName}.\n\t */\n\tpublic static final ConfigurationPropertyName EMPTY = new ConfigurationPropertyName(Elements.EMPTY);\n\n\tprivate final Elements elements;\n\n\tprivate final @Nullable CharSequence[] uniformElements;\n\n\tprivate int hashCode;\n\n\tprivate @Nullable String[] string = new String[ToStringFormat.values().length];\n\n\tprivate @Nullable Boolean hasDashedElement;\n\n\tprivate @Nullable ConfigurationPropertyName systemEnvironmentLegacyName;\n\n\tprivate ConfigurationPropertyName(Elements elements) {\n\t\tthis.elements = elements;\n\t\tthis.uniformElements = new CharSequence[elements.getSize()];\n\t}\n\n\t/**\n\t * Returns {@code true} if this {@link ConfigurationPropertyName} is empty.\n\t * @return {@code true} if the name is empty\n\t */\n\tpublic boolean isEmpty() {\n\t\treturn this.elements.getSize() == 0;\n\t}\n\n\t/**\n\t * Return if the last element in the name is indexed.\n\t * @return {@code true} if the last element is indexed\n\t */\n\tpublic boolean isLastElementIndexed() {\n\t\tint size = getNumberOfElements();\n\t\treturn (size > 0 && isIndexed(size - 1));\n\t}\n\n\t/**\n\t * Return {@code true} if any element in the name is indexed.\n\t * @return if the element has one or more indexed elements\n\t * @since 2.2.10\n\t */\n\tpublic boolean hasIndexedElement() {\n\t\tfor (int i = 0; i < getNumberOfElements(); i++) {\n\t\t\tif (isIndexed(i)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return if the element in the name is indexed.\n\t * @param elementIndex the index of the element\n\t * @return {@code true} if the element is indexed\n\t */\n\tboolean isIndexed(int elementIndex) {\n\t\treturn this.elements.getType(elementIndex).isIndexed();\n\t}\n\n\t/**\n\t * Return if the element in the name is indexed and numeric.\n\t * @param elementIndex the index of the element\n\t * @return {@code true} if the element is indexed and numeric\n\t */\n\tpublic boolean isNumericIndex(int elementIndex) {\n\t\treturn this.elements.getType(elementIndex) == ElementType.NUMERICALLY_INDEXED;\n\t}\n\n\t/**\n\t * Return the last element in the name in the given form.\n\t * @param form the form to return\n\t * @return the last element\n\t */\n\tpublic String getLastElement(Form form) {\n\t\tint size = getNumberOfElements();\n\t\treturn (size != 0) ? getElement(size - 1, form) : EMPTY_STRING;\n\t}\n\n\t/**\n\t * Return an element in the name in the given form.\n\t * @param elementIndex the element index\n\t * @param form the form to return\n\t * @return the last element\n\t */\n\tpublic String getElement(int elementIndex, Form form) {\n\t\tCharSequence element = this.elements.get(elementIndex);\n\t\tElementType type = this.elements.getType(elementIndex);\n\t\tif (type.isIndexed()) {\n\t\t\treturn element.toString();\n\t\t}\n\t\tif (form == Form.ORIGINAL) {\n\t\t\tif (type != ElementType.NON_UNIFORM) {\n\t\t\t\treturn element.toString();\n\t\t\t}\n\t\t\treturn convertToOriginalForm(element).toString();\n\t\t}\n\t\tif (form == Form.DASHED) {\n\t\t\tif (type == ElementType.UNIFORM || type == ElementType.DASHED) {\n\t\t\t\treturn element.toString();\n\t\t\t}\n\t\t\treturn convertToDashedElement(element).toString();\n\t\t}\n\t\tCharSequence uniformElement = this.uniformElements[elementIndex];\n\t\tif (uniformElement == null) {\n\t\t\tuniformElement = (type != ElementType.UNIFORM) ? convertToUniformElement(element) : element;\n\t\t\tthis.uniformElements[elementIndex] = uniformElement.toString();\n\t\t}\n\t\treturn uniformElement.toString();\n\t}\n\n\tprivate CharSequence convertToOriginalForm(CharSequence element) {\n\t\treturn convertElement(element, false,\n\t\t\t\t(ch, i) -> ch == '_' || ElementsParser.isValidChar(Character.toLowerCase(ch), i));\n\t}\n\n\tprivate CharSequence convertToDashedElement(CharSequence element) {\n\t\treturn convertElement(element, true, ElementsParser::isValidChar);\n\t}\n\n\tprivate CharSequence convertToUniformElement(CharSequence element) {\n\t\treturn convertElement(element, true, (ch, i) -> ElementsParser.isAlphaNumeric(ch));\n\t}\n\n\tprivate CharSequence convertElement(CharSequence element, boolean lowercase, ElementCharPredicate filter) {\n\t\tStringBuilder result = new StringBuilder(element.length());\n\t\tfor (int i = 0; i < element.length(); i++) {\n\t\t\tchar ch = lowercase ? Character.toLowerCase(element.charAt(i)) : element.charAt(i);\n\t\t\tif (filter.test(ch, i)) {\n\t\t\t\tresult.append(ch);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the total number of elements in the name.\n\t * @return the number of elements\n\t */\n\tpublic int getNumberOfElements() {\n\t\treturn this.elements.getSize();\n\t}\n\n\t/**\n\t * Create a new {@link ConfigurationPropertyName} by appending the given suffix.\n\t * @param suffix the elements to append\n\t * @return a new {@link ConfigurationPropertyName}\n\t * @throws InvalidConfigurationPropertyNameException if the result is not valid\n\t */\n\tpublic ConfigurationPropertyName append(@Nullable String suffix) {\n\t\tif (!StringUtils.hasLength(suffix)) {\n\t\t\treturn this;\n\t\t}\n\t\tElements additionalElements = probablySingleElementOf(suffix);\n\t\treturn new ConfigurationPropertyName(this.elements.append(additionalElements));\n\t}\n\n\t/**\n\t * Create a new {@link ConfigurationPropertyName} by appending the given suffix.\n\t * @param suffix the elements to append\n\t * @return a new {@link ConfigurationPropertyName}\n\t * @since 2.5.0\n\t */\n\tpublic ConfigurationPropertyName append(@Nullable ConfigurationPropertyName suffix) {\n\t\tif (suffix == null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new ConfigurationPropertyName(this.elements.append(suffix.elements));\n\t}\n\n\t/**\n\t * Return the parent of this {@link ConfigurationPropertyName} or\n\t * {@link ConfigurationPropertyName#EMPTY} if there is no parent.\n\t * @return the parent name\n\t */\n\tpublic ConfigurationPropertyName getParent() {\n\t\tint numberOfElements = getNumberOfElements();\n\t\treturn (numberOfElements <= 1) ? EMPTY : chop(numberOfElements - 1);\n\t}\n\n\t/**\n\t * Return a new {@link ConfigurationPropertyName} by chopping this name to the given\n\t * {@code size}. For example, {@code chop(1)} on the name {@code foo.bar} will return\n\t * {@code foo}.\n\t * @param size the size to chop\n\t * @return the chopped name\n\t */\n\tpublic ConfigurationPropertyName chop(int size) {\n\t\tif (size >= getNumberOfElements()) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new ConfigurationPropertyName(this.elements.chop(size));\n\t}\n\n\t/**\n\t * Return a new {@link ConfigurationPropertyName} by based on this name offset by\n\t * specific element index. For example, {@code subName(1)} on the name {@code foo.bar}\n\t * will return {@code bar}.\n\t * @param offset the element offset\n\t * @return the sub name\n\t * @since 2.5.0\n\t */\n\tpublic ConfigurationPropertyName subName(int offset) {\n\t\tif (offset == 0) {\n\t\t\treturn this;\n\t\t}\n\t\tif (offset == getNumberOfElements()) {\n\t\t\treturn EMPTY;\n\t\t}\n\t\tif (offset < 0 || offset > getNumberOfElements()) {\n\t\t\tthrow new IndexOutOfBoundsException(\"Offset: \" + offset + \", NumberOfElements: \" + getNumberOfElements());\n\t\t}\n\t\treturn new ConfigurationPropertyName(this.elements.subElements(offset));\n\t}\n\n\t/**\n\t * Returns {@code true} if this element is an immediate parent of the specified name.\n\t * @param name the name to check\n\t * @return {@code true} if this name is an ancestor\n\t */\n\tpublic boolean isParentOf(ConfigurationPropertyName name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tif (getNumberOfElements() != name.getNumberOfElements() - 1) {\n\t\t\treturn false;\n\t\t}\n\t\treturn isAncestorOf(name);\n\t}\n\n\t/**\n\t * Returns {@code true} if this element is an ancestor (immediate or nested parent) of\n\t * the specified name.\n\t * @param name the name to check\n\t * @return {@code true} if this name is an ancestor\n\t */\n\tpublic boolean isAncestorOf(ConfigurationPropertyName name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tif (getNumberOfElements() >= name.getNumberOfElements()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn endsWithElementsEqualTo(name);\n\t}\n\n\t@Override\n\tpublic int compareTo(ConfigurationPropertyName other) {\n\t\treturn compare(this, other);\n\t}\n\n\tprivate int compare(ConfigurationPropertyName n1, ConfigurationPropertyName n2) {\n\t\tint l1 = n1.getNumberOfElements();\n\t\tint l2 = n2.getNumberOfElements();\n\t\tint i1 = 0;\n\t\tint i2 = 0;\n\t\twhile (i1 < l1 || i2 < l2) {\n\t\t\ttry {\n\t\t\t\tElementType type1 = (i1 < l1) ? n1.elements.getType(i1) : null;\n\t\t\t\tElementType type2 = (i2 < l2) ? n2.elements.getType(i2) : null;\n\t\t\t\tString e1 = (i1 < l1) ? n1.getElement(i1++, Form.UNIFORM) : null;\n\t\t\t\tString e2 = (i2 < l2) ? n2.getElement(i2++, Form.UNIFORM) : null;\n\t\t\t\tint result = compare(e1, type1, e2, type2);\n\t\t\t\tif (result != 0) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (ArrayIndexOutOfBoundsException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tprivate int compare(@Nullable String e1, @Nullable ElementType type1, @Nullable String e2,\n\t\t\t@Nullable ElementType type2) {\n\t\tif (e1 == null) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (e2 == null) {\n\t\t\treturn 1;\n\t\t}\n\t\tAssert.state(type1 != null, \"'type1' must not be null\");\n\t\tAssert.state(type2 != null, \"'type2' must not be null\");\n\t\tint result = Boolean.compare(type2.isIndexed(), type1.isIndexed());\n\t\tif (result != 0) {\n\t\t\treturn result;\n\t\t}\n\t\tif (type1 == ElementType.NUMERICALLY_INDEXED && type2 == ElementType.NUMERICALLY_INDEXED) {\n\t\t\tlong v1 = Long.parseLong(e1);\n\t\t\tlong v2 = Long.parseLong(e2);\n\t\t\treturn Long.compare(v1, v2);\n\t\t}\n\t\treturn e1.compareTo(e2);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tConfigurationPropertyName other = (ConfigurationPropertyName) obj;\n\t\tif (getNumberOfElements() != other.getNumberOfElements()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.elements.canShortcutWithSource(ElementType.UNIFORM)\n\t\t\t\t&& other.elements.canShortcutWithSource(ElementType.UNIFORM)) {\n\t\t\treturn toString().equals(other.toString());\n\t\t}\n\t\tif (hashCode() != other.hashCode()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (toStringMatches(toString(), other.toString())) {\n\t\t\treturn true;\n\t\t}\n\t\treturn endsWithElementsEqualTo(other);\n\t}\n\n\tprivate boolean toStringMatches(String s1, String s2) {\n\t\treturn s1.hashCode() == s2.hashCode() && s1.equals(s2);\n\t}\n\n\tprivate boolean endsWithElementsEqualTo(ConfigurationPropertyName name) {\n\t\tfor (int i = this.elements.getSize() - 1; i >= 0; i--) {\n\t\t\tif (elementDiffers(this.elements, name.elements, i)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate boolean elementDiffers(Elements e1, Elements e2, int i) {\n\t\tElementType type1 = e1.getType(i);\n\t\tElementType type2 = e2.getType(i);\n\t\tif (type1.allowsFastEqualityCheck() && type2.allowsFastEqualityCheck()) {\n\t\t\treturn !fastElementEquals(e1, e2, i);\n\t\t}\n\t\tif (type1.allowsDashIgnoringEqualityCheck() && type2.allowsDashIgnoringEqualityCheck()) {\n\t\t\treturn !dashIgnoringElementEquals(e1, e2, i);\n\t\t}\n\t\treturn !defaultElementEquals(e1, e2, i);\n\t}\n\n\tprivate boolean fastElementEquals(Elements e1, Elements e2, int i) {\n\t\tint length1 = e1.getLength(i);\n\t\tint length2 = e2.getLength(i);\n\t\tif (length1 == length2) {\n\t\t\tint i1 = 0;\n\t\t\twhile (length1-- != 0) {\n\t\t\t\tchar ch1 = e1.charAt(i, i1);\n\t\t\t\tchar ch2 = e2.charAt(i, i1);\n\t\t\t\tif (ch1 != ch2) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\ti1++;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean dashIgnoringElementEquals(Elements e1, Elements e2, int i) {\n\t\tint l1 = e1.getLength(i);\n\t\tint l2 = e2.getLength(i);\n\t\tint i1 = 0;\n\t\tint i2 = 0;\n\t\twhile (i1 < l1) {\n\t\t\tif (i2 >= l2) {\n\t\t\t\treturn remainderIsDashes(e1, i, i1);\n\t\t\t}\n\t\t\tchar ch1 = e1.charAt(i, i1);\n\t\t\tchar ch2 = e2.charAt(i, i2);\n\t\t\tif (ch1 == '-') {\n\t\t\t\ti1++;\n\t\t\t}\n\t\t\telse if (ch2 == '-') {\n\t\t\t\ti2++;\n\t\t\t}\n\t\t\telse if (ch1 != ch2) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\ti1++;\n\t\t\t\ti2++;\n\t\t\t}\n\t\t}\n\t\tif (i2 < l2) {\n\t\t\tif (e2.getType(i).isIndexed()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdo {\n\t\t\t\tchar ch2 = e2.charAt(i, i2++);\n\t\t\t\tif (ch2 != '-') {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\twhile (i2 < l2);\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate boolean defaultElementEquals(Elements e1, Elements e2, int i) {\n\t\tint l1 = e1.getLength(i);\n\t\tint l2 = e2.getLength(i);\n\t\tboolean indexed1 = e1.getType(i).isIndexed();\n\t\tboolean indexed2 = e2.getType(i).isIndexed();\n\t\tint i1 = 0;\n\t\tint i2 = 0;\n\t\twhile (i1 < l1) {\n\t\t\tif (i2 >= l2) {\n\t\t\t\treturn remainderIsNotAlphanumeric(e1, i, i1);\n\t\t\t}\n\t\t\tchar ch1 = indexed1 ? e1.charAt(i, i1) : Character.toLowerCase(e1.charAt(i, i1));\n\t\t\tchar ch2 = indexed2 ? e2.charAt(i, i2) : Character.toLowerCase(e2.charAt(i, i2));\n\t\t\tif (!indexed1 && !ElementsParser.isAlphaNumeric(ch1)) {\n\t\t\t\ti1++;\n\t\t\t}\n\t\t\telse if (!indexed2 && !ElementsParser.isAlphaNumeric(ch2)) {\n\t\t\t\ti2++;\n\t\t\t}\n\t\t\telse if (ch1 != ch2) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse {\n\t\t\t\ti1++;\n\t\t\t\ti2++;\n\t\t\t}\n\t\t}\n\t\tif (i2 < l2) {\n\t\t\treturn remainderIsNotAlphanumeric(e2, i, i2);\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate boolean remainderIsNotAlphanumeric(Elements elements, int element, int index) {\n\t\tif (elements.getType(element).isIndexed()) {\n\t\t\treturn false;\n\t\t}\n\t\tint length = elements.getLength(element);\n\t\tdo {\n\t\t\tchar c = Character.toLowerCase(elements.charAt(element, index++));\n\t\t\tif (ElementsParser.isAlphaNumeric(c)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\twhile (index < length);\n\t\treturn true;\n\t}\n\n\tprivate boolean remainderIsDashes(Elements elements, int element, int index) {\n\t\tif (elements.getType(element).isIndexed()) {\n\t\t\treturn false;\n\t\t}\n\t\tint length = elements.getLength(element);\n\t\tdo {\n\t\t\tchar c = elements.charAt(element, index++);\n\t\t\tif (c != '-') {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\twhile (index < length);\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint hashCode = this.hashCode;\n\t\tElements elements = this.elements;\n\t\tif (hashCode == 0 && elements.getSize() != 0) {\n\t\t\tfor (int elementIndex = 0; elementIndex < elements.getSize(); elementIndex++) {\n\t\t\t\thashCode = 31 * hashCode + elements.hashCode(elementIndex);\n\t\t\t}\n\t\t\tthis.hashCode = hashCode;\n\t\t}\n\t\treturn hashCode;\n\t}\n\n\t@Nullable ConfigurationPropertyName asSystemEnvironmentLegacyName() {\n\t\tConfigurationPropertyName name = this.systemEnvironmentLegacyName;\n\t\tif (name == null) {\n\t\t\tname = ConfigurationPropertyName\n\t\t\t\t.ofIfValid(buildSimpleToString('.', (i) -> getElement(i, Form.DASHED).replace('-', '.')));\n\t\t\tthis.systemEnvironmentLegacyName = (name != null) ? name : EMPTY;\n\t\t}\n\t\treturn (name != EMPTY) ? name : null;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn toString(ToStringFormat.DEFAULT, false);\n\t}\n\n\tString toString(ToStringFormat format, boolean upperCase) {\n\t\tString string = this.string[format.ordinal()];\n\t\tif (string == null) {\n\t\t\tstring = buildToString(format);\n\t\t\tthis.string[format.ordinal()] = string;\n\t\t}\n\t\treturn (!upperCase) ? string : string.toUpperCase(Locale.ENGLISH);\n\t}\n\n\tprivate String buildToString(ToStringFormat format) {\n\t\treturn switch (format) {\n\t\t\tcase DEFAULT -> buildDefaultToString();\n\t\t\tcase SYSTEM_ENVIRONMENT -> buildSimpleToString('_', (i) -> getElement(i, Form.UNIFORM));\n\t\t\tcase LEGACY_SYSTEM_ENVIRONMENT ->\n\t\t\t\tbuildSimpleToString('_', (i) -> getElement(i, Form.ORIGINAL).replace('-', '_'));\n\t\t};\n\t}\n\n\tprivate String buildDefaultToString() {\n\t\tif (this.elements.canShortcutWithSource(ElementType.UNIFORM, ElementType.DASHED)) {\n\t\t\treturn this.elements.getSource().toString();\n\t\t}\n\t\tint elements = getNumberOfElements();\n\t\tStringBuilder result = new StringBuilder(elements * 8);\n\t\tfor (int i = 0; i < elements; i++) {\n\t\t\tboolean indexed = isIndexed(i);\n\t\t\tif (!result.isEmpty() && !indexed) {\n\t\t\t\tresult.append('.');\n\t\t\t}\n\t\t\tif (indexed) {\n\t\t\t\tresult.append('[');\n\t\t\t\tresult.append(getElement(i, Form.ORIGINAL));\n\t\t\t\tresult.append(']');\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.append(getElement(i, Form.DASHED));\n\t\t\t}\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\tprivate String buildSimpleToString(char joinChar, IntFunction<String> elementConverter) {\n\t\tStringBuilder result = new StringBuilder();\n\t\tfor (int i = 0; i < getNumberOfElements(); i++) {\n\t\t\tif (!result.isEmpty()) {\n\t\t\t\tresult.append(joinChar);\n\t\t\t}\n\t\t\tresult.append(elementConverter.apply(i));\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\tboolean hasDashedElement() {\n\t\tBoolean hasDashedElement = this.hasDashedElement;\n\t\tif (hasDashedElement != null) {\n\t\t\treturn hasDashedElement;\n\t\t}\n\t\tfor (int i = 0; i < getNumberOfElements(); i++) {\n\t\t\tif (getElement(i, Form.DASHED).indexOf('-') != -1) {\n\t\t\t\tthis.hasDashedElement = true;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tthis.hasDashedElement = false;\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns if the given name is valid. If this method returns {@code true} then the\n\t * name may be used with {@link #of(CharSequence)} without throwing an exception.\n\t * @param name the name to test\n\t * @return {@code true} if the name is valid\n\t */\n\tpublic static boolean isValid(@Nullable CharSequence name) {\n\t\treturn of(name, true) != null;\n\t}\n\n\t/**\n\t * Return a {@link ConfigurationPropertyName} for the specified string.\n\t * @param name the source name\n\t * @return a {@link ConfigurationPropertyName} instance\n\t * @throws InvalidConfigurationPropertyNameException if the name is not valid\n\t */\n\t@SuppressWarnings(\"NullAway\") // See https://github.com/uber/NullAway/issues/1232\n\tpublic static ConfigurationPropertyName of(@Nullable CharSequence name) {\n\t\treturn of(name, false);\n\t}\n\n\t/**\n\t * Return a {@link ConfigurationPropertyName} for the specified string or {@code null}\n\t * if the name is not valid.\n\t * @param name the source name\n\t * @return a {@link ConfigurationPropertyName} instance\n\t * @since 2.3.1\n\t */\n\tpublic static @Nullable ConfigurationPropertyName ofIfValid(@Nullable CharSequence name) {\n\t\treturn of(name, true);\n\t}\n\n\t/**\n\t * Return a {@link ConfigurationPropertyName} for the specified string.\n\t * @param name the source name\n\t * @param returnNullIfInvalid if null should be returned if the name is not valid\n\t * @return a {@link ConfigurationPropertyName} instance\n\t * @throws InvalidConfigurationPropertyNameException if the name is not valid and\n\t * {@code returnNullIfInvalid} is {@code false}\n\t */\n\t@Contract(\"_, false -> !null\")\n\tstatic @Nullable ConfigurationPropertyName of(@Nullable CharSequence name, boolean returnNullIfInvalid) {\n\t\tElements elements = elementsOf(name, returnNullIfInvalid, ElementsParser.DEFAULT_CAPACITY);\n\t\treturn (elements != null) ? new ConfigurationPropertyName(elements) : null;\n\t}\n\n\t@SuppressWarnings(\"NullAway\") // See https://github.com/uber/NullAway/issues/1232\n\tprivate static Elements probablySingleElementOf(CharSequence name) {\n\t\treturn elementsOf(name, false, 1);\n\t}\n\n\t@Contract(\"_, false, _ -> !null\")\n\tprivate static @Nullable Elements elementsOf(@Nullable CharSequence name, boolean returnNullIfInvalid,\n\t\t\tint parserCapacity) {\n\t\tif (name == null) {\n\t\t\tAssert.isTrue(returnNullIfInvalid, \"'name' must not be null\");\n\t\t\treturn null;\n\t\t}\n\t\tif (name.isEmpty()) {\n\t\t\treturn Elements.EMPTY;\n\t\t}\n\t\tif (name.charAt(0) == '.' || name.charAt(name.length() - 1) == '.') {\n\t\t\tif (returnNullIfInvalid) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow new InvalidConfigurationPropertyNameException(name, Collections.singletonList('.'));\n\t\t}\n\t\tElements elements = new ElementsParser(name, '.', parserCapacity).parse();\n\t\tfor (int i = 0; i < elements.getSize(); i++) {\n\t\t\tif (elements.getType(i) == ElementType.NON_UNIFORM) {\n\t\t\t\tif (returnNullIfInvalid) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tthrow new InvalidConfigurationPropertyNameException(name, getInvalidChars(elements, i));\n\t\t\t}\n\t\t}\n\t\treturn elements;\n\t}\n\n\tprivate static List<Character> getInvalidChars(Elements elements, int index) {\n\t\tList<Character> invalidChars = new ArrayList<>();\n\t\tfor (int charIndex = 0; charIndex < elements.getLength(index); charIndex++) {\n\t\t\tchar ch = elements.charAt(index, charIndex);\n\t\t\tif (!ElementsParser.isValidChar(ch, charIndex)) {\n\t\t\t\tinvalidChars.add(ch);\n\t\t\t}\n\t\t}\n\t\treturn invalidChars;\n\t}\n\n\t/**\n\t * Create a {@link ConfigurationPropertyName} by adapting the given source. See\n\t * {@link #adapt(CharSequence, char, Function)} for details.\n\t * @param name the name to parse\n\t * @param separator the separator used to split the name\n\t * @return a {@link ConfigurationPropertyName}\n\t */\n\tpublic static ConfigurationPropertyName adapt(CharSequence name, char separator) {\n\t\treturn adapt(name, separator, null);\n\t}\n\n\t/**\n\t * Create a {@link ConfigurationPropertyName} by adapting the given source. The name\n\t * is split into elements around the given {@code separator}. This method is more\n\t * lenient than {@link #of} in that it allows mixed case names and '{@code _}'\n\t * characters. Other invalid characters are stripped out during parsing.\n\t * <p>\n\t * The {@code elementValueProcessor} function may be used if additional processing is\n\t * required on the extracted element values.\n\t * @param name the name to parse\n\t * @param separator the separator used to split the name\n\t * @param elementValueProcessor a function to process element values\n\t * @return a {@link ConfigurationPropertyName}\n\t */\n\tstatic ConfigurationPropertyName adapt(CharSequence name, char separator,\n\t\t\t@Nullable Function<CharSequence, CharSequence> elementValueProcessor) {\n\t\tAssert.notNull(name, \"Name must not be null\");\n\t\tif (name.isEmpty()) {\n\t\t\treturn EMPTY;\n\t\t}\n\t\tElements elements = new ElementsParser(name, separator).parse(elementValueProcessor);\n\t\tif (elements.getSize() == 0) {\n\t\t\treturn EMPTY;\n\t\t}\n\t\treturn new ConfigurationPropertyName(elements);\n\t}\n\n\t/**\n\t * The various forms that a non-indexed element value can take.\n\t */\n\tpublic enum Form {\n\n\t\t/**\n\t\t * The original form as specified when the name was created or adapted. For\n\t\t * example:\n\t\t * <ul>\n\t\t * <li>\"{@code foo-bar}\" = \"{@code foo-bar}\"</li>\n\t\t * <li>\"{@code fooBar}\" = \"{@code fooBar}\"</li>\n\t\t * <li>\"{@code foo_bar}\" = \"{@code foo_bar}\"</li>\n\t\t * <li>\"{@code [Foo.bar]}\" = \"{@code Foo.bar}\"</li>\n\t\t * </ul>\n\t\t */\n\t\tORIGINAL,\n\n\t\t/**\n\t\t * The dashed configuration form (used for toString; lower-case with only\n\t\t * alphanumeric characters and dashes).\n\t\t * <ul>\n\t\t * <li>\"{@code foo-bar}\" = \"{@code foo-bar}\"</li>\n\t\t * <li>\"{@code fooBar}\" = \"{@code foobar}\"</li>\n\t\t * <li>\"{@code foo_bar}\" = \"{@code foobar}\"</li>\n\t\t * <li>\"{@code [Foo.bar]}\" = \"{@code Foo.bar}\"</li>\n\t\t * </ul>\n\t\t */\n\t\tDASHED,\n\n\t\t/**\n\t\t * The uniform configuration form (used for equals/hashCode; lower-case with only\n\t\t * alphanumeric characters).\n\t\t * <ul>\n\t\t * <li>\"{@code foo-bar}\" = \"{@code foobar}\"</li>\n\t\t * <li>\"{@code fooBar}\" = \"{@code foobar}\"</li>\n\t\t * <li>\"{@code foo_bar}\" = \"{@code foobar}\"</li>\n\t\t * <li>\"{@code [Foo.bar]}\" = \"{@code Foo.bar}\"</li>\n\t\t * </ul>\n\t\t */\n\t\tUNIFORM\n\n\t}\n\n\t/**\n\t * Allows access to the individual elements that make up the name. We store the\n\t * indexes in arrays rather than a list of object in order to conserve memory.\n\t */\n\tprivate static class Elements {\n\n\t\tprivate static final int[] NO_POSITION = {};\n\n\t\tprivate static final ElementType[] NO_TYPE = {};\n\n\t\tpublic static final Elements EMPTY = new Elements(\"\", 0, NO_POSITION, NO_POSITION, NO_TYPE, null, null);\n\n\t\tprivate final CharSequence source;\n\n\t\tprivate final int size;\n\n\t\tprivate final int[] start;\n\n\t\tprivate final int[] end;\n\n\t\tprivate final ElementType[] type;\n\n\t\tprivate final int[] hashCode;\n\n\t\t/**\n\t\t * Contains any resolved elements or can be {@code null} if there aren't any.\n\t\t * Resolved elements allow us to modify the element values in some way (or example\n\t\t * when adapting with a mapping function, or when append has been called). Note\n\t\t * that this array is not used as a cache, in fact, when it's not null then\n\t\t * {@link #canShortcutWithSource} will always return false which may hurt\n\t\t * performance.\n\t\t */\n\t\tprivate final @Nullable CharSequence @Nullable [] resolved;\n\n\t\tElements(CharSequence source, int size, int[] start, int[] end, ElementType[] type, int @Nullable [] hashCode,\n\t\t\t\tCharSequence @Nullable [] resolved) {\n\t\t\tthis.source = source;\n\t\t\tthis.size = size;\n\t\t\tthis.start = start;\n\t\t\tthis.end = end;\n\t\t\tthis.type = type;\n\t\t\tthis.hashCode = (hashCode != null) ? hashCode : new int[size];\n\t\t\tthis.resolved = resolved;\n\t\t}\n\n\t\tElements append(Elements additional) {\n\t\t\tint size = this.size + additional.size;\n\t\t\tElementType[] type = new ElementType[size];\n\t\t\tint[] hashCode = new int[size];\n\t\t\tSystem.arraycopy(this.type, 0, type, 0, this.size);\n\t\t\tSystem.arraycopy(additional.type, 0, type, this.size, additional.size);\n\t\t\tSystem.arraycopy(this.hashCode, 0, hashCode, 0, this.size);\n\t\t\tSystem.arraycopy(additional.hashCode, 0, hashCode, this.size, additional.size);\n\t\t\tCharSequence[] resolved = newResolved(0, size);\n\t\t\tfor (int i = 0; i < additional.size; i++) {\n\t\t\t\tresolved[this.size + i] = additional.get(i);\n\t\t\t}\n\t\t\treturn new Elements(this.source, size, this.start, this.end, type, hashCode, resolved);\n\t\t}\n\n\t\tElements chop(int size) {\n\t\t\tCharSequence[] resolved = newResolved(0, size);\n\t\t\treturn new Elements(this.source, size, this.start, this.end, this.type, this.hashCode, resolved);\n\t\t}\n\n\t\tElements subElements(int offset) {\n\t\t\tint size = this.size - offset;\n\t\t\tCharSequence[] resolved = newResolved(offset, size);\n\t\t\tint[] start = new int[size];\n\t\t\tSystem.arraycopy(this.start, offset, start, 0, size);\n\t\t\tint[] end = new int[size];\n\t\t\tSystem.arraycopy(this.end, offset, end, 0, size);\n\t\t\tElementType[] type = new ElementType[size];\n\t\t\tSystem.arraycopy(this.type, offset, type, 0, size);\n\t\t\tint[] hashCode = new int[size];\n\t\t\tSystem.arraycopy(this.hashCode, offset, hashCode, 0, size);\n\t\t\treturn new Elements(this.source, size, start, end, type, hashCode, resolved);\n\t\t}\n\n\t\tprivate CharSequence[] newResolved(int offset, int size) {\n\t\t\tCharSequence[] resolved = new CharSequence[size];\n\t\t\tif (this.resolved != null) {\n\t\t\t\tSystem.arraycopy(this.resolved, offset, resolved, 0, Math.min(size, this.size));\n\t\t\t}\n\t\t\treturn resolved;\n\t\t}\n\n\t\tint getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t\tCharSequence get(int index) {\n\t\t\tif (this.resolved != null) {\n\t\t\t\tCharSequence element = this.resolved[index];\n\t\t\t\tif (element != null) {\n\t\t\t\t\treturn element;\n\t\t\t\t}\n\t\t\t}\n\t\t\tint start = this.start[index];\n\t\t\tint end = this.end[index];\n\t\t\treturn this.source.subSequence(start, end);\n\t\t}\n\n\t\tint getLength(int index) {\n\t\t\tif (this.resolved != null) {\n\t\t\t\tCharSequence element = this.resolved[index];\n\t\t\t\tif (element != null) {\n\t\t\t\t\treturn element.length();\n\t\t\t\t}\n\t\t\t}\n\t\t\tint start = this.start[index];\n\t\t\tint end = this.end[index];\n\t\t\treturn end - start;\n\t\t}\n\n\t\tchar charAt(int index, int charIndex) {\n\t\t\tif (this.resolved != null) {\n\t\t\t\tCharSequence element = this.resolved[index];\n\t\t\t\tif (element != null) {\n\t\t\t\t\treturn element.charAt(charIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t\tint start = this.start[index];\n\t\t\treturn this.source.charAt(start + charIndex);\n\t\t}\n\n\t\tElementType getType(int index) {\n\t\t\treturn this.type[index];\n\t\t}\n\n\t\tint hashCode(int index) {\n\t\t\tint hashCode = this.hashCode[index];\n\t\t\tif (hashCode == 0) {\n\t\t\t\tboolean indexed = getType(index).isIndexed();\n\t\t\t\tint length = getLength(index);\n\t\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\t\tchar ch = charAt(index, i);\n\t\t\t\t\tif (!indexed) {\n\t\t\t\t\t\tch = Character.toLowerCase(ch);\n\t\t\t\t\t}\n\t\t\t\t\tif (ElementsParser.isAlphaNumeric(ch)) {\n\t\t\t\t\t\thashCode = 31 * hashCode + ch;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.hashCode[index] = hashCode;\n\t\t\t}\n\t\t\treturn hashCode;\n\t\t}\n\n\t\tCharSequence getSource() {\n\t\t\treturn this.source;\n\t\t}\n\n\t\t/**\n\t\t * Returns if the element source can be used as a shortcut for an operation such\n\t\t * as {@code equals} or {@code toString}.\n\t\t * @param requiredType the required type\n\t\t * @return {@code true} if all elements match at least one of the types\n\t\t */\n\t\tboolean canShortcutWithSource(ElementType requiredType) {\n\t\t\treturn canShortcutWithSource(requiredType, requiredType);\n\t\t}\n\n\t\t/**\n\t\t * Returns if the element source can be used as a shortcut for an operation such\n\t\t * as {@code equals} or {@code toString}.\n\t\t * @param requiredType the required type\n\t\t * @param alternativeType and alternative required type\n\t\t * @return {@code true} if all elements match at least one of the types\n\t\t */\n\t\tboolean canShortcutWithSource(ElementType requiredType, ElementType alternativeType) {\n\t\t\tif (this.resolved != null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (int i = 0; i < this.size; i++) {\n\t\t\t\tElementType type = this.type[i];\n\t\t\t\tif (type != requiredType && type != alternativeType) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (i > 0 && this.end[i - 1] + 1 != this.start[i]) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n\t/**\n\t * Main parsing logic used to convert a {@link CharSequence} to {@link Elements}.\n\t */\n\tprivate static class ElementsParser {\n\n\t\tprivate static final int DEFAULT_CAPACITY = 6;\n\n\t\tprivate final CharSequence source;\n\n\t\tprivate final char separator;\n\n\t\tprivate int size;\n\n\t\tprivate int[] start;\n\n\t\tprivate int[] end;\n\n\t\tprivate ElementType[] type;\n\n\t\tprivate CharSequence @Nullable [] resolved;\n\n\t\tElementsParser(CharSequence source, char separator) {\n\t\t\tthis(source, separator, DEFAULT_CAPACITY);\n\t\t}\n\n\t\tElementsParser(CharSequence source, char separator, int capacity) {\n\t\t\tthis.source = source;\n\t\t\tthis.separator = separator;\n\t\t\tthis.start = new int[capacity];\n\t\t\tthis.end = new int[capacity];\n\t\t\tthis.type = new ElementType[capacity];\n\t\t}\n\n\t\tElements parse() {\n\t\t\treturn parse(null);\n\t\t}\n\n\t\tElements parse(@Nullable Function<CharSequence, CharSequence> valueProcessor) {\n\t\t\tint length = this.source.length();\n\t\t\tint openBracketCount = 0;\n\t\t\tint start = 0;\n\t\t\tElementType type = ElementType.EMPTY;\n\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\tchar ch = this.source.charAt(i);\n\t\t\t\tif (ch == '[') {\n\t\t\t\t\tif (openBracketCount == 0) {\n\t\t\t\t\t\tadd(start, i, type, valueProcessor);\n\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\ttype = ElementType.NUMERICALLY_INDEXED;\n\t\t\t\t\t}\n\t\t\t\t\topenBracketCount++;\n\t\t\t\t}\n\t\t\t\telse if (ch == ']') {\n\t\t\t\t\topenBracketCount--;\n\t\t\t\t\tif (openBracketCount == 0) {\n\t\t\t\t\t\tadd(start, i, type, valueProcessor);\n\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\ttype = ElementType.EMPTY;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!type.isIndexed() && ch == this.separator) {\n\t\t\t\t\tadd(start, i, type, valueProcessor);\n\t\t\t\t\tstart = i + 1;\n\t\t\t\t\ttype = ElementType.EMPTY;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttype = updateType(type, ch, i - start);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (openBracketCount != 0) {\n\t\t\t\ttype = ElementType.NON_UNIFORM;\n\t\t\t}\n\t\t\tadd(start, length, type, valueProcessor);\n\t\t\treturn new Elements(this.source, this.size, this.start, this.end, this.type, null, this.resolved);\n\t\t}\n\n\t\tprivate ElementType updateType(ElementType existingType, char ch, int index) {\n\t\t\tif (existingType.isIndexed()) {\n\t\t\t\tif (existingType == ElementType.NUMERICALLY_INDEXED && !isNumeric(ch)) {\n\t\t\t\t\treturn ElementType.INDEXED;\n\t\t\t\t}\n\t\t\t\treturn existingType;\n\t\t\t}\n\t\t\tif (existingType == ElementType.EMPTY && isValidChar(ch, index)) {\n\t\t\t\treturn (index == 0) ? ElementType.UNIFORM : ElementType.NON_UNIFORM;\n\t\t\t}\n\t\t\tif (existingType == ElementType.UNIFORM && ch == '-') {\n\t\t\t\treturn ElementType.DASHED;\n\t\t\t}\n\t\t\tif (!isValidChar(ch, index)) {\n\t\t\t\tif (existingType == ElementType.EMPTY && !isValidChar(Character.toLowerCase(ch), index)) {\n\t\t\t\t\treturn ElementType.EMPTY;\n\t\t\t\t}\n\t\t\t\treturn ElementType.NON_UNIFORM;\n\t\t\t}\n\t\t\treturn existingType;\n\t\t}\n\n\t\tprivate void add(int start, int end, ElementType type,\n\t\t\t\t@Nullable Function<CharSequence, CharSequence> valueProcessor) {\n\t\t\tif ((end - start) < 1 || type == ElementType.EMPTY) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.start.length == this.size) {\n\t\t\t\tthis.start = expand(this.start);\n\t\t\t\tthis.end = expand(this.end);\n\t\t\t\tthis.type = expand(this.type);\n\t\t\t\tthis.resolved = expand(this.resolved);\n\t\t\t}\n\t\t\tif (valueProcessor != null) {\n\t\t\t\tif (this.resolved == null) {\n\t\t\t\t\tthis.resolved = new CharSequence[this.start.length];\n\t\t\t\t}\n\t\t\t\tCharSequence resolved = valueProcessor.apply(this.source.subSequence(start, end));\n\t\t\t\tElements resolvedElements = new ElementsParser(resolved, '.').parse();\n\t\t\t\tAssert.state(resolvedElements.getSize() == 1, \"Resolved element must not contain multiple elements\");\n\t\t\t\tthis.resolved[this.size] = resolvedElements.get(0);\n\t\t\t\ttype = resolvedElements.getType(0);\n\t\t\t}\n\t\t\tthis.start[this.size] = start;\n\t\t\tthis.end[this.size] = end;\n\t\t\tthis.type[this.size] = type;\n\t\t\tthis.size++;\n\t\t}\n\n\t\tprivate int[] expand(int[] src) {\n\t\t\tint[] dest = new int[src.length + DEFAULT_CAPACITY];\n\t\t\tSystem.arraycopy(src, 0, dest, 0, src.length);\n\t\t\treturn dest;\n\t\t}\n\n\t\tprivate ElementType[] expand(ElementType[] src) {\n\t\t\tElementType[] dest = new ElementType[src.length + DEFAULT_CAPACITY];\n\t\t\tSystem.arraycopy(src, 0, dest, 0, src.length);\n\t\t\treturn dest;\n\t\t}\n\n\t\tprivate CharSequence @Nullable [] expand(CharSequence @Nullable [] src) {\n\t\t\tif (src == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tCharSequence[] dest = new CharSequence[src.length + DEFAULT_CAPACITY];\n\t\t\tSystem.arraycopy(src, 0, dest, 0, src.length);\n\t\t\treturn dest;\n\t\t}\n\n\t\tstatic boolean isValidChar(char ch, int index) {\n\t\t\treturn isAlpha(ch) || isNumeric(ch) || (index != 0 && ch == '-');\n\t\t}\n\n\t\tstatic boolean isAlphaNumeric(char ch) {\n\t\t\treturn isAlpha(ch) || isNumeric(ch);\n\t\t}\n\n\t\tprivate static boolean isAlpha(char ch) {\n\t\t\treturn ch >= 'a' && ch <= 'z';\n\t\t}\n\n\t\tprivate static boolean isNumeric(char ch) {\n\t\t\treturn ch >= '0' && ch <= '9';\n\t\t}\n\n\t}\n\n\t/**\n\t * The various types of element that we can detect.\n\t */\n\tprivate enum ElementType {\n\n\t\t/**\n\t\t * The element is logically empty (contains no valid chars).\n\t\t */\n\t\tEMPTY(false),\n\n\t\t/**\n\t\t * The element is a uniform name (a-z, 0-9, no dashes, lowercase).\n\t\t */\n\t\tUNIFORM(false),\n\n\t\t/**\n\t\t * The element is almost uniform, but it contains (but does not start with) at\n\t\t * least one dash.\n\t\t */\n\t\tDASHED(false),\n\n\t\t/**\n\t\t * The element contains non-uniform characters and will need to be converted.\n\t\t */\n\t\tNON_UNIFORM(false),\n\n\t\t/**\n\t\t * The element is non-numerically indexed.\n\t\t */\n\t\tINDEXED(true),\n\n\t\t/**\n\t\t * The element is numerically indexed.\n\t\t */\n\t\tNUMERICALLY_INDEXED(true);\n\n\t\tprivate final boolean indexed;\n\n\t\tElementType(boolean indexed) {\n\t\t\tthis.indexed = indexed;\n\t\t}\n\n\t\tpublic boolean isIndexed() {\n\t\t\treturn this.indexed;\n\t\t}\n\n\t\tpublic boolean allowsFastEqualityCheck() {\n\t\t\treturn this == UNIFORM || this == NUMERICALLY_INDEXED;\n\t\t}\n\n\t\tpublic boolean allowsDashIgnoringEqualityCheck() {\n\t\t\treturn allowsFastEqualityCheck() || this == DASHED;\n\t\t}\n\n\t}\n\n\t/**\n\t * Predicate used to filter element chars.\n\t */\n\tprivate interface ElementCharPredicate {\n\n\t\tboolean test(char ch, int index);\n\n\t}\n\n\t/**\n\t * Formats for {@code toString}.\n\t */\n\tenum ToStringFormat {\n\n\t\tDEFAULT, SYSTEM_ENVIRONMENT, LEGACY_SYSTEM_ENVIRONMENT\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameAliases.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * Maintains a mapping of {@link ConfigurationPropertyName} aliases.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see ConfigurationPropertySource#withAliases(ConfigurationPropertyNameAliases)\n */\npublic final class ConfigurationPropertyNameAliases implements Iterable<ConfigurationPropertyName> {\n\n\tprivate final MultiValueMap<ConfigurationPropertyName, ConfigurationPropertyName> aliases = new LinkedMultiValueMap<>();\n\n\tpublic ConfigurationPropertyNameAliases() {\n\t}\n\n\tpublic ConfigurationPropertyNameAliases(String name, String... aliases) {\n\t\taddAliases(name, aliases);\n\t}\n\n\tpublic ConfigurationPropertyNameAliases(ConfigurationPropertyName name, ConfigurationPropertyName... aliases) {\n\t\taddAliases(name, aliases);\n\t}\n\n\tpublic void addAliases(String name, String... aliases) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(aliases, \"'aliases' must not be null\");\n\t\taddAliases(ConfigurationPropertyName.of(name),\n\t\t\t\tArrays.stream(aliases).map(ConfigurationPropertyName::of).toArray(ConfigurationPropertyName[]::new));\n\t}\n\n\tpublic void addAliases(ConfigurationPropertyName name, ConfigurationPropertyName... aliases) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(aliases, \"'aliases' must not be null\");\n\t\tthis.aliases.addAll(name, Arrays.asList(aliases));\n\t}\n\n\tpublic List<ConfigurationPropertyName> getAliases(ConfigurationPropertyName name) {\n\t\treturn this.aliases.getOrDefault(name, Collections.emptyList());\n\t}\n\n\tpublic @Nullable ConfigurationPropertyName getNameForAlias(ConfigurationPropertyName alias) {\n\t\treturn this.aliases.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((e) -> e.getValue().contains(alias))\n\t\t\t.map(Map.Entry::getKey)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t@Override\n\tpublic Iterator<ConfigurationPropertyName> iterator() {\n\t\treturn this.aliases.keySet().iterator();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * A source of {@link ConfigurationProperty ConfigurationProperties}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see ConfigurationPropertyName\n * @see OriginTrackedValue\n * @see #getConfigurationProperty(ConfigurationPropertyName)\n */\n@FunctionalInterface\npublic interface ConfigurationPropertySource {\n\n\t/**\n\t * Return a single {@link ConfigurationProperty} from the source or {@code null} if no\n\t * property can be found.\n\t * @param name the name of the property\n\t * @return the associated object or {@code null}.\n\t */\n\t@Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name);\n\n\t/**\n\t * Returns if the source contains any descendants of the specified name. May return\n\t * {@link ConfigurationPropertyState#PRESENT} or\n\t * {@link ConfigurationPropertyState#ABSENT} if an answer can be determined or\n\t * {@link ConfigurationPropertyState#UNKNOWN} if it's not possible to determine a\n\t * definitive answer.\n\t * @param name the name to check\n\t * @return if the source contains any descendants\n\t */\n\tdefault ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\treturn ConfigurationPropertyState.UNKNOWN;\n\t}\n\n\t/**\n\t * Return a filtered variant of this source, containing only names that match the\n\t * given {@link Predicate}.\n\t * @param filter the filter to match\n\t * @return a filtered {@link ConfigurationPropertySource} instance\n\t */\n\tdefault ConfigurationPropertySource filter(Predicate<ConfigurationPropertyName> filter) {\n\t\treturn new FilteredConfigurationPropertiesSource(this, filter);\n\t}\n\n\t/**\n\t * Return a variant of this source that supports name aliases.\n\t * @param aliases a function that returns a stream of aliases for any given name\n\t * @return a {@link ConfigurationPropertySource} instance supporting name aliases\n\t */\n\tdefault ConfigurationPropertySource withAliases(ConfigurationPropertyNameAliases aliases) {\n\t\treturn new AliasedConfigurationPropertySource(this, aliases);\n\t}\n\n\t/**\n\t * Return a variant of this source that supports a prefix.\n\t * @param prefix the prefix for properties in the source\n\t * @return a {@link ConfigurationPropertySource} instance supporting a prefix\n\t * @since 2.5.0\n\t */\n\tdefault ConfigurationPropertySource withPrefix(@Nullable String prefix) {\n\t\treturn (StringUtils.hasText(prefix)) ? new PrefixedConfigurationPropertySource(this, prefix) : this;\n\t}\n\n\t/**\n\t * Return the underlying source that is actually providing the properties.\n\t * @return the underlying property source or {@code null}.\n\t */\n\tdefault @Nullable Object getUnderlyingSource() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return a single new {@link ConfigurationPropertySource} adapted from the given\n\t * Spring {@link PropertySource} or {@code null} if the source cannot be adapted.\n\t * @param source the Spring property source to adapt\n\t * @return an adapted source or {@code null} {@link SpringConfigurationPropertySource}\n\t * @since 2.4.0\n\t */\n\tstatic @Nullable ConfigurationPropertySource from(PropertySource<?> source) {\n\t\tif (source instanceof ConfigurationPropertySourcesPropertySource) {\n\t\t\treturn null;\n\t\t}\n\t\treturn SpringConfigurationPropertySource.from(source);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.ConfigurablePropertyResolver;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySource.StubPropertySource;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\n\n/**\n * Provides access to {@link ConfigurationPropertySource ConfigurationPropertySources}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic final class ConfigurationPropertySources {\n\n\t/**\n\t * The name of the {@link PropertySource} {@link #attach(Environment) adapter}.\n\t */\n\tprivate static final String ATTACHED_PROPERTY_SOURCE_NAME = \"configurationProperties\";\n\n\tprivate ConfigurationPropertySources() {\n\t}\n\n\t/**\n\t * Create a new {@link PropertyResolver} that resolves property values against an\n\t * underlying set of {@link PropertySources}. Provides an\n\t * {@link ConfigurationPropertySource} aware and optimized alternative to\n\t * {@link PropertySourcesPropertyResolver}.\n\t * @param propertySources the set of {@link PropertySource} objects to use\n\t * @return a {@link ConfigurablePropertyResolver} implementation\n\t * @since 2.5.0\n\t */\n\tpublic static ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {\n\t\treturn new ConfigurationPropertySourcesPropertyResolver(propertySources);\n\t}\n\n\t/**\n\t * Determines if the specific {@link PropertySource} is the\n\t * {@link ConfigurationPropertySource} that was {@link #attach(Environment) attached}\n\t * to the {@link Environment}.\n\t * @param propertySource the property source to test\n\t * @return {@code true} if this is the attached {@link ConfigurationPropertySource}\n\t */\n\tpublic static boolean isAttachedConfigurationPropertySource(PropertySource<?> propertySource) {\n\t\treturn ATTACHED_PROPERTY_SOURCE_NAME.equals(propertySource.getName());\n\t}\n\n\t/**\n\t * Attach a {@link ConfigurationPropertySource} support to the specified\n\t * {@link Environment}. Adapts each {@link PropertySource} managed by the environment\n\t * to a {@link ConfigurationPropertySource} and allows classic\n\t * {@link PropertySourcesPropertyResolver} calls to resolve using\n\t * {@link ConfigurationPropertyName configuration property names}.\n\t * <p>\n\t * The attached resolver will dynamically track any additions or removals from the\n\t * underlying {@link Environment} property sources.\n\t * @param environment the source environment (must be an instance of\n\t * {@link ConfigurableEnvironment})\n\t * @see #get(Environment)\n\t */\n\tpublic static void attach(Environment environment) {\n\t\tAssert.isInstanceOf(ConfigurableEnvironment.class, environment);\n\t\tMutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();\n\t\tPropertySource<?> attached = getAttached(sources);\n\t\tif (!isUsingSources(attached, sources)) {\n\t\t\tattached = new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tnew SpringConfigurationPropertySources(sources));\n\t\t}\n\t\tsources.remove(ATTACHED_PROPERTY_SOURCE_NAME);\n\t\tsources.addFirst(attached);\n\t}\n\n\t@Contract(\"null, _ -> false\")\n\tprivate static boolean isUsingSources(@Nullable PropertySource<?> attached, MutablePropertySources sources) {\n\t\treturn attached instanceof ConfigurationPropertySourcesPropertySource\n\t\t\t\t&& ((SpringConfigurationPropertySources) attached.getSource()).isUsingSources(sources);\n\t}\n\n\tstatic @Nullable PropertySource<?> getAttached(@Nullable MutablePropertySources sources) {\n\t\treturn (sources != null) ? sources.get(ATTACHED_PROPERTY_SOURCE_NAME) : null;\n\t}\n\n\t/**\n\t * Return a set of {@link ConfigurationPropertySource} instances that have previously\n\t * been {@link #attach(Environment) attached} to the {@link Environment}.\n\t * @param environment the source environment (must be an instance of\n\t * {@link ConfigurableEnvironment})\n\t * @return an iterable set of configuration property sources\n\t * @throws IllegalStateException if not configuration property sources have been\n\t * attached\n\t */\n\tpublic static Iterable<ConfigurationPropertySource> get(Environment environment) {\n\t\tAssert.isInstanceOf(ConfigurableEnvironment.class, environment);\n\t\tMutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();\n\t\tConfigurationPropertySourcesPropertySource attached = (ConfigurationPropertySourcesPropertySource) sources\n\t\t\t.get(ATTACHED_PROPERTY_SOURCE_NAME);\n\t\tif (attached == null) {\n\t\t\treturn from(sources);\n\t\t}\n\t\treturn attached.getSource();\n\t}\n\n\t/**\n\t * Return {@link Iterable} containing a single new {@link ConfigurationPropertySource}\n\t * adapted from the given Spring {@link PropertySource}. The single element can be\n\t * {@code null} if the source cannot be adapted.\n\t * @param source the Spring property source to adapt\n\t * @return an {@link Iterable} containing a single newly adapted\n\t * {@link SpringConfigurationPropertySource}\n\t */\n\tpublic static Iterable<@Nullable ConfigurationPropertySource> from(PropertySource<?> source) {\n\t\treturn Collections.singleton(ConfigurationPropertySource.from(source));\n\t}\n\n\t/**\n\t * Return {@link Iterable} containing new {@link ConfigurationPropertySource}\n\t * instances adapted from the given Spring {@link PropertySource PropertySources}.\n\t * <p>\n\t * This method will flatten any nested property sources and will filter all\n\t * {@link StubPropertySource stub property sources}. Updates to the underlying source,\n\t * identified by changes in the sources returned by its iterator, will be\n\t * automatically tracked. The underlying source should be thread safe, for example a\n\t * {@link MutablePropertySources}\n\t * @param sources the Spring property sources to adapt\n\t * @return an {@link Iterable} containing newly adapted\n\t * {@link SpringConfigurationPropertySource} instances\n\t */\n\tpublic static Iterable<ConfigurationPropertySource> from(Iterable<PropertySource<?>> sources) {\n\t\treturn new SpringConfigurationPropertySources(sources);\n\t}\n\n\tprivate static Stream<PropertySource<?>> streamPropertySources(PropertySources sources) {\n\t\treturn sources.stream()\n\t\t\t.flatMap(ConfigurationPropertySources::flatten)\n\t\t\t.filter(ConfigurationPropertySources::isIncluded);\n\t}\n\n\tprivate static Stream<PropertySource<?>> flatten(PropertySource<?> source) {\n\t\tif (source.getSource() instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\treturn streamPropertySources(configurableEnvironment.getPropertySources());\n\t\t}\n\t\treturn Stream.of(source);\n\t}\n\n\tprivate static boolean isIncluded(PropertySource<?> source) {\n\t\treturn !(source instanceof StubPropertySource)\n\t\t\t\t&& !(source instanceof ConfigurationPropertySourcesPropertySource);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesCaching.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link ConfigurationPropertyCaching} for an {@link Iterable iterable} set of\n * {@link ConfigurationPropertySource} instances.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertySourcesCaching implements ConfigurationPropertyCaching {\n\n\tprivate final @Nullable Iterable<ConfigurationPropertySource> sources;\n\n\tConfigurationPropertySourcesCaching(@Nullable Iterable<ConfigurationPropertySource> sources) {\n\t\tthis.sources = sources;\n\t}\n\n\t@Override\n\tpublic void enable() {\n\t\tforEach(ConfigurationPropertyCaching::enable);\n\t}\n\n\t@Override\n\tpublic void disable() {\n\t\tforEach(ConfigurationPropertyCaching::disable);\n\t}\n\n\t@Override\n\tpublic void setTimeToLive(Duration timeToLive) {\n\t\tforEach((caching) -> caching.setTimeToLive(timeToLive));\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tforEach(ConfigurationPropertyCaching::clear);\n\t}\n\n\t@Override\n\tpublic CacheOverride override() {\n\t\tCacheOverrides override = new CacheOverrides();\n\t\tforEach(override::add);\n\t\treturn override;\n\t}\n\n\tprivate void forEach(Consumer<ConfigurationPropertyCaching> action) {\n\t\tif (this.sources != null) {\n\t\t\tfor (ConfigurationPropertySource source : this.sources) {\n\t\t\t\tConfigurationPropertyCaching caching = CachingConfigurationPropertySource.find(source);\n\t\t\t\tif (caching != null) {\n\t\t\t\t\taction.accept(caching);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Composite {@link CacheOverride}.\n\t */\n\tprivate final class CacheOverrides implements CacheOverride {\n\n\t\tprivate List<CacheOverride> overrides = new ArrayList<>();\n\n\t\tvoid add(ConfigurationPropertyCaching caching) {\n\t\t\tthis.overrides.add(caching.override());\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t\tthis.overrides.forEach(CacheOverride::close);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.env.AbstractPropertyResolver;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\n\n/**\n * Alternative {@link PropertySourcesPropertyResolver} implementation that recognizes\n * {@link ConfigurationPropertySourcesPropertySource} and saves duplicate calls to the\n * underlying sources if the name is a value {@link ConfigurationPropertyName}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertySourcesPropertyResolver extends AbstractPropertyResolver {\n\n\tprivate final MutablePropertySources propertySources;\n\n\tprivate final DefaultResolver defaultResolver;\n\n\tConfigurationPropertySourcesPropertyResolver(MutablePropertySources propertySources) {\n\t\tthis.propertySources = propertySources;\n\t\tthis.defaultResolver = new DefaultResolver(propertySources);\n\t}\n\n\t@Override\n\tpublic boolean containsProperty(String key) {\n\t\tConfigurationPropertySourcesPropertySource attached = getAttached();\n\t\tif (attached != null) {\n\t\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(key, true);\n\t\t\tif (name != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn attached.findConfigurationProperty(name) != null;\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this.defaultResolver.containsProperty(key);\n\t}\n\n\t@Override\n\tpublic @Nullable String getProperty(String key) {\n\t\treturn getProperty(key, String.class, true);\n\t}\n\n\t@Override\n\tpublic <T> @Nullable T getProperty(String key, Class<T> targetValueType) {\n\t\treturn getProperty(key, targetValueType, true);\n\t}\n\n\t@Override\n\tprotected @Nullable String getPropertyAsRawString(String key) {\n\t\treturn getProperty(key, String.class, false);\n\t}\n\n\tprivate <T> @Nullable T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {\n\t\tObject value = findPropertyValue(key);\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (resolveNestedPlaceholders && value instanceof String string) {\n\t\t\tvalue = resolveNestedPlaceholders(string);\n\t\t}\n\t\ttry {\n\t\t\treturn convertValueIfNecessary(value, targetValueType);\n\t\t}\n\t\tcatch (ConversionFailedException ex) {\n\t\t\tException wrappedCause = new InvalidConfigurationPropertyValueException(key, value,\n\t\t\t\t\t\"Failed to convert to type \" + ex.getTargetType(), ex.getCause());\n\t\t\tthrow new ConversionFailedException(ex.getSourceType(), ex.getTargetType(), ex.getValue(), wrappedCause);\n\t\t}\n\t}\n\n\tprivate @Nullable Object findPropertyValue(String key) {\n\t\tConfigurationPropertySourcesPropertySource attached = getAttached();\n\t\tif (attached != null) {\n\t\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(key, true);\n\t\t\tif (name != null) {\n\t\t\t\ttry {\n\t\t\t\t\tConfigurationProperty configurationProperty = attached.findConfigurationProperty(name);\n\t\t\t\t\treturn (configurationProperty != null) ? configurationProperty.getValue() : null;\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this.defaultResolver.getProperty(key, Object.class, false);\n\t}\n\n\tprivate @Nullable ConfigurationPropertySourcesPropertySource getAttached() {\n\t\tConfigurationPropertySourcesPropertySource attached = (ConfigurationPropertySourcesPropertySource) ConfigurationPropertySources\n\t\t\t.getAttached(this.propertySources);\n\t\tIterable<ConfigurationPropertySource> attachedSource = (attached != null) ? attached.getSource() : null;\n\t\tif ((attachedSource instanceof SpringConfigurationPropertySources springSource)\n\t\t\t\t&& springSource.isUsingSources(this.propertySources)) {\n\t\t\treturn attached;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Default {@link PropertySourcesPropertyResolver} used if\n\t * {@link ConfigurationPropertySources} is not attached.\n\t */\n\tstatic class DefaultResolver extends PropertySourcesPropertyResolver {\n\n\t\tDefaultResolver(PropertySources propertySources) {\n\t\t\tsuper(propertySources);\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> @Nullable T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {\n\t\t\treturn super.getProperty(key, targetValueType, resolveNestedPlaceholders);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * {@link PropertySource} that exposes {@link ConfigurationPropertySource} instances so\n * that they can be used with a {@link PropertyResolver} or added to the\n * {@link Environment}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigurationPropertySourcesPropertySource extends PropertySource<Iterable<ConfigurationPropertySource>>\n\t\timplements OriginLookup<String> {\n\n\tConfigurationPropertySourcesPropertySource(String name, Iterable<ConfigurationPropertySource> source) {\n\t\tsuper(name, source);\n\t}\n\n\t@Override\n\tpublic boolean containsProperty(String name) {\n\t\treturn findConfigurationProperty(name) != null;\n\t}\n\n\t@Override\n\tpublic @Nullable Object getProperty(String name) {\n\t\tConfigurationProperty configurationProperty = findConfigurationProperty(name);\n\t\treturn (configurationProperty != null) ? configurationProperty.getValue() : null;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin(String name) {\n\t\treturn Origin.from(findConfigurationProperty(name));\n\t}\n\n\tprivate @Nullable ConfigurationProperty findConfigurationProperty(String name) {\n\t\ttry {\n\t\t\treturn findConfigurationProperty(ConfigurationPropertyName.of(name, true));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Nullable ConfigurationProperty findConfigurationProperty(@Nullable ConfigurationPropertyName name) {\n\t\tif (name == null) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (ConfigurationPropertySource configurationPropertySource : getSource()) {\n\t\t\tConfigurationProperty configurationProperty = configurationPropertySource.getConfigurationProperty(name);\n\t\t\tif (configurationProperty != null) {\n\t\t\t\treturn configurationProperty;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/ConfigurationPropertyState.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.function.Predicate;\n\nimport org.springframework.util.Assert;\n\n/**\n * The state of content from a {@link ConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic enum ConfigurationPropertyState {\n\n\t/**\n\t * The {@link ConfigurationPropertySource} has at least one matching\n\t * {@link ConfigurationProperty}.\n\t */\n\tPRESENT,\n\n\t/**\n\t * The {@link ConfigurationPropertySource} has no matching\n\t * {@link ConfigurationProperty ConfigurationProperties}.\n\t */\n\tABSENT,\n\n\t/**\n\t * It's not possible to determine if {@link ConfigurationPropertySource} has matching\n\t * {@link ConfigurationProperty ConfigurationProperties} or not.\n\t */\n\tUNKNOWN;\n\n\t/**\n\t * Search the given iterable using a predicate to determine if content is\n\t * {@link #PRESENT} or {@link #ABSENT}.\n\t * @param <T> the data type\n\t * @param source the source iterable to search\n\t * @param predicate the predicate used to test for presence\n\t * @return {@link #PRESENT} if the iterable contains a matching item, otherwise\n\t * {@link #ABSENT}.\n\t */\n\tstatic <T> ConfigurationPropertyState search(Iterable<T> source, Predicate<T> predicate) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\tfor (T item : source) {\n\t\t\tif (predicate.test(item)) {\n\t\t\t\treturn PRESENT;\n\t\t\t}\n\t\t}\n\t\treturn ABSENT;\n\t}\n\n\t/**\n\t * Search the given iterable using a predicate to determine if content is\n\t * {@link #PRESENT} or {@link #ABSENT}.\n\t * @param <T> the data type\n\t * @param source the source iterable to search\n\t * @param startInclusive the first index to cover\n\t * @param endExclusive index immediately past the last index to cover\n\t * @param predicate the predicate used to test for presence\n\t * @return {@link #PRESENT} if the iterable contains a matching item, otherwise\n\t * {@link #ABSENT}.\n\t */\n\tstatic <T> ConfigurationPropertyState search(T[] source, int startInclusive, int endExclusive,\n\t\t\tPredicate<T> predicate) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\tfor (int i = startInclusive; i < endExclusive; i++) {\n\t\t\tif (predicate.test(source[i])) {\n\t\t\t\treturn PRESENT;\n\t\t\t}\n\t\t}\n\t\treturn ABSENT;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/DefaultPropertyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Default {@link PropertyMapper} implementation. Names are mapped by removing invalid\n * characters and converting to lower case. For example \"{@code my.server_name.PORT}\" is\n * mapped to \"{@code my.servername.port}\".\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see PropertyMapper\n * @see SpringConfigurationPropertySource\n */\nfinal class DefaultPropertyMapper implements PropertyMapper {\n\n\tpublic static final PropertyMapper INSTANCE = new DefaultPropertyMapper();\n\n\tprivate @Nullable LastMapping<ConfigurationPropertyName, List<String>> lastMappedConfigurationPropertyName;\n\n\tprivate @Nullable LastMapping<String, ConfigurationPropertyName> lastMappedPropertyName;\n\n\tprivate DefaultPropertyMapper() {\n\t}\n\n\t@Override\n\tpublic List<String> map(ConfigurationPropertyName configurationPropertyName) {\n\t\t// Use a local copy in case another thread changes things\n\t\tLastMapping<ConfigurationPropertyName, List<String>> last = this.lastMappedConfigurationPropertyName;\n\t\tif (last != null && last.isFrom(configurationPropertyName)) {\n\t\t\treturn last.getMapping();\n\t\t}\n\t\tString convertedName = configurationPropertyName.toString();\n\t\tList<String> mapping = Collections.singletonList(convertedName);\n\t\tthis.lastMappedConfigurationPropertyName = new LastMapping<>(configurationPropertyName, mapping);\n\t\treturn mapping;\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyName map(String propertySourceName) {\n\t\t// Use a local copy in case another thread changes things\n\t\tLastMapping<String, ConfigurationPropertyName> last = this.lastMappedPropertyName;\n\t\tif (last != null && last.isFrom(propertySourceName)) {\n\t\t\treturn last.getMapping();\n\t\t}\n\t\tConfigurationPropertyName mapping = tryMap(propertySourceName);\n\t\tthis.lastMappedPropertyName = new LastMapping<>(propertySourceName, mapping);\n\t\treturn mapping;\n\t}\n\n\tprivate ConfigurationPropertyName tryMap(String propertySourceName) {\n\t\ttry {\n\t\t\tConfigurationPropertyName convertedName = ConfigurationPropertyName.adapt(propertySourceName, '.');\n\t\t\tif (!convertedName.isEmpty()) {\n\t\t\t\treturn convertedName;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn ConfigurationPropertyName.EMPTY;\n\t}\n\n\tprivate static class LastMapping<T, M> {\n\n\t\tprivate final T from;\n\n\t\tprivate final M mapping;\n\n\t\tLastMapping(T from, M mapping) {\n\t\t\tthis.from = from;\n\t\t\tthis.mapping = mapping;\n\t\t}\n\n\t\tboolean isFrom(T from) {\n\t\t\treturn ObjectUtils.nullSafeEquals(from, this.from);\n\t\t}\n\n\t\tM getMapping() {\n\t\t\treturn this.mapping;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/FilteredConfigurationPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A filtered {@link ConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass FilteredConfigurationPropertiesSource implements ConfigurationPropertySource {\n\n\tprivate final ConfigurationPropertySource source;\n\n\tprivate final Predicate<ConfigurationPropertyName> filter;\n\n\tFilteredConfigurationPropertiesSource(ConfigurationPropertySource source,\n\t\t\tPredicate<ConfigurationPropertyName> filter) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(filter, \"'filter' must not be null\");\n\t\tthis.source = source;\n\t\tthis.filter = filter;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\tboolean filtered = getFilter().test(name);\n\t\treturn filtered ? getSource().getConfigurationProperty(name) : null;\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\tConfigurationPropertyState result = this.source.containsDescendantOf(name);\n\t\tif (result == ConfigurationPropertyState.PRESENT) {\n\t\t\t// We can't be sure a contained descendant won't be filtered\n\t\t\treturn ConfigurationPropertyState.UNKNOWN;\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic @Nullable Object getUnderlyingSource() {\n\t\treturn this.source.getUnderlyingSource();\n\t}\n\n\tprotected ConfigurationPropertySource getSource() {\n\t\treturn this.source;\n\t}\n\n\tprotected Predicate<ConfigurationPropertyName> getFilter() {\n\t\treturn this.filter;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.source.toString() + \" (filtered)\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/FilteredIterableConfigurationPropertiesSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Arrays;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A filtered {@link IterableConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass FilteredIterableConfigurationPropertiesSource extends FilteredConfigurationPropertiesSource\n\t\timplements IterableConfigurationPropertySource {\n\n\tprivate ConfigurationPropertyName @Nullable [] filteredNames;\n\n\tprivate int numberOfFilteredNames;\n\n\tFilteredIterableConfigurationPropertiesSource(IterableConfigurationPropertySource source,\n\t\t\tPredicate<ConfigurationPropertyName> filter) {\n\t\tsuper(source, filter);\n\t\t@Nullable ConfigurationPropertyName[] filterableNames = getFilterableNames(source);\n\t\tif (filterableNames != null) {\n\t\t\tthis.filteredNames = new ConfigurationPropertyName[filterableNames.length];\n\t\t\tthis.numberOfFilteredNames = 0;\n\t\t\tfor (ConfigurationPropertyName name : filterableNames) {\n\t\t\t\tif (name == null) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (filter.test(name)) {\n\t\t\t\t\tthis.filteredNames[this.numberOfFilteredNames++] = name;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate @Nullable ConfigurationPropertyName @Nullable [] getFilterableNames(\n\t\t\tIterableConfigurationPropertySource source) {\n\t\tif (source instanceof SpringIterableConfigurationPropertySource springPropertySource\n\t\t\t\t&& springPropertySource.isImmutablePropertySource()) {\n\t\t\treturn springPropertySource.getConfigurationPropertyNames();\n\t\t}\n\t\tif (source instanceof FilteredIterableConfigurationPropertiesSource filteredSource) {\n\t\t\treturn filteredSource.filteredNames;\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Stream<ConfigurationPropertyName> stream() {\n\t\tif (this.filteredNames != null) {\n\t\t\treturn Arrays.stream(this.filteredNames, 0, this.numberOfFilteredNames);\n\t\t}\n\t\treturn getSource().stream().filter(getFilter());\n\t}\n\n\t@Override\n\tprotected IterableConfigurationPropertySource getSource() {\n\t\treturn (IterableConfigurationPropertySource) super.getSource();\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\tif (this.filteredNames != null) {\n\t\t\treturn ConfigurationPropertyState.search(this.filteredNames, 0, this.numberOfFilteredNames,\n\t\t\t\t\tname::isAncestorOf);\n\t\t}\n\t\treturn ConfigurationPropertyState.search(this, name::isAncestorOf);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyNameException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.List;\n\n/**\n * Exception thrown when {@link ConfigurationPropertyName} has invalid characters.\n *\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class InvalidConfigurationPropertyNameException extends RuntimeException {\n\n\tprivate final CharSequence name;\n\n\tprivate final List<Character> invalidCharacters;\n\n\tpublic InvalidConfigurationPropertyNameException(CharSequence name, List<Character> invalidCharacters) {\n\t\tsuper(\"Configuration property name '\" + name + \"' is not valid\");\n\t\tthis.name = name;\n\t\tthis.invalidCharacters = invalidCharacters;\n\t}\n\n\tpublic List<Character> getInvalidCharacters() {\n\t\treturn this.invalidCharacters;\n\t}\n\n\tpublic CharSequence getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic static void throwIfHasInvalidChars(CharSequence name, List<Character> invalidCharacters) {\n\t\tif (!invalidCharacters.isEmpty()) {\n\t\t\tthrow new InvalidConfigurationPropertyNameException(name, invalidCharacters);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/InvalidConfigurationPropertyValueException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Exception thrown when a configuration property value is invalid.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class InvalidConfigurationPropertyValueException extends RuntimeException {\n\n\tprivate final String name;\n\n\tprivate final @Nullable Object value;\n\n\tprivate final @Nullable String reason;\n\n\t/**\n\t * Creates a new instance for the specified property {@code name} and {@code value},\n\t * including a {@code reason} why the value is invalid.\n\t * @param name the name of the property in canonical format\n\t * @param value the value of the property, can be {@code null}\n\t * @param reason a human-readable text that describes why the reason is invalid.\n\t * Starts with an upper-case and ends with a dot. Several sentences and carriage\n\t * returns are allowed.\n\t */\n\tpublic InvalidConfigurationPropertyValueException(String name, @Nullable Object value, @Nullable String reason) {\n\t\tthis(name, value, reason, null);\n\t}\n\n\tInvalidConfigurationPropertyValueException(String name, @Nullable Object value, @Nullable String reason,\n\t\t\t@Nullable Throwable cause) {\n\t\tsuper(\"Property \" + name + \" with value '\" + value + \"' is invalid: \" + reason, cause);\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.name = name;\n\t\tthis.value = value;\n\t\tthis.reason = reason;\n\t}\n\n\t/**\n\t * Return the name of the property.\n\t * @return the property name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the invalid value, can be {@code null}.\n\t * @return the invalid value\n\t */\n\tpublic @Nullable Object getValue() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Return the reason why the value is invalid.\n\t * @return the reason\n\t */\n\tpublic @Nullable String getReason() {\n\t\treturn this.reason;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/IterableConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Iterator;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link ConfigurationPropertySource} with a fully {@link Iterable} set of entries.\n * Implementations of this interface <strong>must</strong> be able to iterate over all\n * contained configuration properties. Any {@code non-null} result from\n * {@link #getConfigurationProperty(ConfigurationPropertyName)} must also have an\n * equivalent entry in the {@link #iterator() iterator}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @see ConfigurationPropertyName\n * @see OriginTrackedValue\n * @see #getConfigurationProperty(ConfigurationPropertyName)\n * @see #iterator()\n * @see #stream()\n */\npublic interface IterableConfigurationPropertySource\n\t\textends ConfigurationPropertySource, Iterable<ConfigurationPropertyName> {\n\n\t/**\n\t * Return an iterator for the {@link ConfigurationPropertyName names} managed by this\n\t * source.\n\t * @return an iterator (never {@code null})\n\t */\n\t@Override\n\tdefault Iterator<ConfigurationPropertyName> iterator() {\n\t\treturn stream().iterator();\n\t}\n\n\t/**\n\t * Returns a sequential {@code Stream} for the {@link ConfigurationPropertyName names}\n\t * managed by this source.\n\t * @return a stream of names (never {@code null})\n\t */\n\tStream<ConfigurationPropertyName> stream();\n\n\t@Override\n\tdefault ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\treturn ConfigurationPropertyState.search(this, name::isAncestorOf);\n\t}\n\n\t@Override\n\tdefault IterableConfigurationPropertySource filter(Predicate<ConfigurationPropertyName> filter) {\n\t\treturn new FilteredIterableConfigurationPropertiesSource(this, filter);\n\t}\n\n\t@Override\n\tdefault IterableConfigurationPropertySource withAliases(ConfigurationPropertyNameAliases aliases) {\n\t\treturn new AliasedIterableConfigurationPropertySource(this, aliases);\n\t}\n\n\t@Override\n\tdefault IterableConfigurationPropertySource withPrefix(@Nullable String prefix) {\n\t\treturn (StringUtils.hasText(prefix)) ? new PrefixedIterableConfigurationPropertySource(this, prefix) : this;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link ConfigurationPropertySource} backed by a {@link Map} and using standard name\n * mapping rules.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class MapConfigurationPropertySource implements IterableConfigurationPropertySource {\n\n\tprivate static final PropertyMapper[] DEFAULT_MAPPERS = { DefaultPropertyMapper.INSTANCE };\n\n\tprivate final Map<String, Object> source;\n\n\tprivate final IterableConfigurationPropertySource delegate;\n\n\t/**\n\t * Create a new empty {@link MapConfigurationPropertySource} instance.\n\t */\n\tpublic MapConfigurationPropertySource() {\n\t\tthis(Collections.emptyMap());\n\t}\n\n\t/**\n\t * Create a new {@link MapConfigurationPropertySource} instance with entries copies\n\t * from the specified map.\n\t * @param map the source map\n\t */\n\tpublic MapConfigurationPropertySource(Map<?, ?> map) {\n\t\tthis.source = new LinkedHashMap<>();\n\t\tMapPropertySource mapPropertySource = new MapPropertySource(\"source\", this.source);\n\t\tthis.delegate = new SpringIterableConfigurationPropertySource(mapPropertySource, false, DEFAULT_MAPPERS);\n\t\tputAll(map);\n\t}\n\n\t/**\n\t * Add all entries from the specified map.\n\t * @param map the source map\n\t */\n\tpublic void putAll(Map<?, ?> map) {\n\t\tAssert.notNull(map, \"'map' must not be null\");\n\t\tassertNotReadOnlySystemAttributesMap(map);\n\t\tmap.forEach(this::put);\n\t}\n\n\t/**\n\t * Add an individual entry.\n\t * @param name the name\n\t * @param value the value\n\t */\n\tpublic void put(Object name, Object value) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.source.put(name.toString(), value);\n\t}\n\n\t@Override\n\tpublic Object getUnderlyingSource() {\n\t\treturn this.source;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\treturn this.delegate.getConfigurationProperty(name);\n\t}\n\n\t@Override\n\tpublic Iterator<ConfigurationPropertyName> iterator() {\n\t\treturn this.delegate.iterator();\n\t}\n\n\t@Override\n\tpublic Stream<ConfigurationPropertyName> stream() {\n\t\treturn this.delegate.stream();\n\t}\n\n\tprivate void assertNotReadOnlySystemAttributesMap(Map<?, ?> map) {\n\t\ttry {\n\t\t\tmap.size();\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Security restricted maps are not supported\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\n\n/**\n * Exception thrown when more than one mutually exclusive configuration property has been\n * configured.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.6.0\n */\n@SuppressWarnings(\"serial\")\npublic class MutuallyExclusiveConfigurationPropertiesException extends RuntimeException {\n\n\tprivate final Set<String> configuredNames;\n\n\tprivate final Set<String> mutuallyExclusiveNames;\n\n\t/**\n\t * Creates a new instance for mutually exclusive configuration properties when two or\n\t * more of those properties have been configured.\n\t * @param configuredNames the names of the properties that have been configured\n\t * @param mutuallyExclusiveNames the names of the properties that are mutually\n\t * exclusive\n\t */\n\tpublic MutuallyExclusiveConfigurationPropertiesException(Collection<String> configuredNames,\n\t\t\tCollection<String> mutuallyExclusiveNames) {\n\t\tthis(asSet(configuredNames), asSet(mutuallyExclusiveNames));\n\t}\n\n\tprivate MutuallyExclusiveConfigurationPropertiesException(Set<String> configuredNames,\n\t\t\tSet<String> mutuallyExclusiveNames) {\n\t\tsuper(buildMessage(mutuallyExclusiveNames, configuredNames));\n\t\tthis.configuredNames = configuredNames;\n\t\tthis.mutuallyExclusiveNames = mutuallyExclusiveNames;\n\t}\n\n\t/**\n\t * Return the names of the properties that have been configured.\n\t * @return the names of the configured properties\n\t */\n\tpublic Set<String> getConfiguredNames() {\n\t\treturn this.configuredNames;\n\t}\n\n\t/**\n\t * Return the names of the properties that are mutually exclusive.\n\t * @return the names of the mutually exclusive properties\n\t */\n\tpublic Set<String> getMutuallyExclusiveNames() {\n\t\treturn this.mutuallyExclusiveNames;\n\t}\n\n\t@Contract(\"null -> null; !null -> !null\")\n\tprivate static @Nullable Set<String> asSet(@Nullable Collection<String> collection) {\n\t\treturn (collection != null) ? new LinkedHashSet<>(collection) : null;\n\t}\n\n\tprivate static String buildMessage(Set<String> mutuallyExclusiveNames, Set<String> configuredNames) {\n\t\tAssert.isTrue(configuredNames != null && configuredNames.size() > 1,\n\t\t\t\t\"'configuredNames' must contain 2 or more names\");\n\t\tAssert.isTrue(mutuallyExclusiveNames != null && mutuallyExclusiveNames.size() > 1,\n\t\t\t\t\"'mutuallyExclusiveNames' must contain 2 or more names\");\n\t\treturn \"The configuration properties '\" + String.join(\", \", mutuallyExclusiveNames)\n\t\t\t\t+ \"' are mutually exclusive and '\" + String.join(\", \", configuredNames)\n\t\t\t\t+ \"' have been configured together\";\n\t}\n\n\t/**\n\t * Throw a new {@link MutuallyExclusiveConfigurationPropertiesException} if multiple\n\t * non-null values are defined in a set of entries.\n\t * @param entries a consumer used to populate the entries to check\n\t */\n\tpublic static void throwIfMultipleNonNullValuesIn(Consumer<Map<String, @Nullable Object>> entries) {\n\t\tPredicate<@Nullable Object> isNonNull = Objects::nonNull;\n\t\tthrowIfMultipleMatchingValuesIn(entries, isNonNull);\n\t}\n\n\t/**\n\t * Throw a new {@link MutuallyExclusiveConfigurationPropertiesException} if multiple\n\t * values are defined in a set of entries that match the given predicate.\n\t * @param <V> the value type\n\t * @param entries a consumer used to populate the entries to check\n\t * @param predicate the predicate used to check for matching values\n\t * @since 3.3.7\n\t */\n\tpublic static <V> void throwIfMultipleMatchingValuesIn(Consumer<Map<String, @Nullable V>> entries,\n\t\t\tPredicate<@Nullable V> predicate) {\n\t\tMap<String, V> map = new LinkedHashMap<>();\n\t\tentries.accept(map);\n\t\tSet<String> configuredNames = map.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((entry) -> predicate.test(entry.getValue()))\n\t\t\t.map(Map.Entry::getKey)\n\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t\tif (configuredNames.size() > 1) {\n\t\t\tthrow new MutuallyExclusiveConfigurationPropertiesException(configuredNames, map.keySet());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A {@link ConfigurationPropertySource} supporting a prefix.\n *\n * @author Madhura Bhave\n */\nclass PrefixedConfigurationPropertySource implements ConfigurationPropertySource {\n\n\tprivate final ConfigurationPropertySource source;\n\n\tprivate final ConfigurationPropertyName prefix;\n\n\tPrefixedConfigurationPropertySource(ConfigurationPropertySource source, String prefix) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.hasText(prefix, \"'prefix' must not be empty\");\n\t\tthis.source = source;\n\t\tthis.prefix = ConfigurationPropertyName.of(prefix);\n\t}\n\n\tprotected final ConfigurationPropertyName getPrefix() {\n\t\treturn this.prefix;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\tConfigurationProperty configurationProperty = this.source.getConfigurationProperty(getPrefixedName(name));\n\t\tif (configurationProperty == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn ConfigurationProperty.of(configurationProperty.getSource(), name, configurationProperty.getValue(),\n\t\t\t\tconfigurationProperty.getOrigin());\n\t}\n\n\tprivate ConfigurationPropertyName getPrefixedName(ConfigurationPropertyName name) {\n\t\treturn this.prefix.append(name);\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\treturn this.source.containsDescendantOf(getPrefixedName(name));\n\t}\n\n\t@Override\n\tpublic @Nullable Object getUnderlyingSource() {\n\t\treturn this.source.getUnderlyingSource();\n\t}\n\n\tprotected ConfigurationPropertySource getSource() {\n\t\treturn this.source;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PrefixedIterableConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.stream.Stream;\n\n/**\n * An iterable {@link PrefixedConfigurationPropertySource}.\n *\n * @author Madhura Bhave\n */\nclass PrefixedIterableConfigurationPropertySource extends PrefixedConfigurationPropertySource\n\t\timplements IterableConfigurationPropertySource {\n\n\tPrefixedIterableConfigurationPropertySource(IterableConfigurationPropertySource source, String prefix) {\n\t\tsuper(source, prefix);\n\t}\n\n\t@Override\n\tpublic Stream<ConfigurationPropertyName> stream() {\n\t\treturn getSource().stream().map(this::stripPrefix);\n\t}\n\n\tprivate ConfigurationPropertyName stripPrefix(ConfigurationPropertyName name) {\n\t\treturn (getPrefix().isAncestorOf(name)) ? name.subName(getPrefix().getNumberOfElements()) : name;\n\t}\n\n\t@Override\n\tprotected IterableConfigurationPropertySource getSource() {\n\t\treturn (IterableConfigurationPropertySource) super.getSource();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/PropertyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.List;\nimport java.util.function.BiPredicate;\n\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * Strategy used to provide a mapping between a {@link PropertySource} and a\n * {@link ConfigurationPropertySource}.\n * <p>\n * Mappings should be provided for both {@link ConfigurationPropertyName\n * ConfigurationPropertyName} types and {@code String} based names. This allows the\n * {@link SpringConfigurationPropertySource} to first attempt any direct mappings (i.e.\n * map the {@link ConfigurationPropertyName} directly to the {@link PropertySource} name)\n * before falling back to {@link EnumerablePropertySource enumerating} property names,\n * mapping them to a {@link ConfigurationPropertyName} and checking for applicability. See\n * {@link SpringConfigurationPropertySource} for more details.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see SpringConfigurationPropertySource\n */\ninterface PropertyMapper {\n\n\t/**\n\t * The default ancestor of check.\n\t */\n\tBiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> DEFAULT_ANCESTOR_OF_CHECK = ConfigurationPropertyName::isAncestorOf;\n\n\t/**\n\t * Provide mappings from a {@link ConfigurationPropertySource}\n\t * {@link ConfigurationPropertyName}.\n\t * @param configurationPropertyName the name to map\n\t * @return the mapped names or an empty list\n\t */\n\tList<String> map(ConfigurationPropertyName configurationPropertyName);\n\n\t/**\n\t * Provide mappings from a {@link PropertySource} property name.\n\t * @param propertySourceName the name to map\n\t * @return the mapped configuration property name or\n\t * {@link ConfigurationPropertyName#EMPTY}\n\t */\n\tConfigurationPropertyName map(String propertySourceName);\n\n\t/**\n\t * Returns a {@link BiPredicate} that can be used to check if one name is an ancestor\n\t * of another when considering the mapping rules.\n\t * @return a predicate that can be used to check if one name is an ancestor of another\n\t */\n\tdefault BiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> getAncestorOfCheck() {\n\t\treturn DEFAULT_ANCESTOR_OF_CHECK;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SoftReferenceConfigurationPropertyCache.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.lang.ref.SoftReference;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Simple cache that uses a {@link SoftReference} to cache a value for as long as\n * possible.\n *\n * @param <T> the value type\n * @author Phillip Webb\n */\nclass SoftReferenceConfigurationPropertyCache<T> implements ConfigurationPropertyCaching {\n\n\tprivate static final Duration UNLIMITED = Duration.ZERO;\n\n\tstatic final CacheOverride NO_OP_OVERRIDE = () -> {\n\t};\n\n\tprivate final boolean neverExpire;\n\n\tprivate volatile @Nullable Duration timeToLive;\n\n\tprivate volatile SoftReference<@Nullable T> value = new SoftReference<>(null);\n\n\tprivate volatile @Nullable Instant lastAccessed = now();\n\n\tSoftReferenceConfigurationPropertyCache(boolean neverExpire) {\n\t\tthis.neverExpire = neverExpire;\n\t}\n\n\t@Override\n\tpublic void enable() {\n\t\tthis.timeToLive = UNLIMITED;\n\t}\n\n\t@Override\n\tpublic void disable() {\n\t\tthis.timeToLive = null;\n\t}\n\n\t@Override\n\tpublic void setTimeToLive(@Nullable Duration timeToLive) {\n\t\tthis.timeToLive = (timeToLive == null || timeToLive.isZero()) ? null : timeToLive;\n\t}\n\n\t@Override\n\tpublic void clear() {\n\t\tthis.lastAccessed = null;\n\t}\n\n\t@Override\n\tpublic CacheOverride override() {\n\t\tif (this.neverExpire) {\n\t\t\treturn NO_OP_OVERRIDE;\n\t\t}\n\t\tActiveCacheOverride override = new ActiveCacheOverride(this);\n\t\tif (override.timeToLive() == null) {\n\t\t\t// Ensure we don't use stale data on the first access\n\t\t\tclear();\n\t\t}\n\t\tthis.timeToLive = UNLIMITED;\n\t\treturn override;\n\t}\n\n\tvoid restore(ActiveCacheOverride override) {\n\t\tthis.timeToLive = override.timeToLive();\n\t\tthis.lastAccessed = override.lastAccessed();\n\t}\n\n\t/**\n\t * Get a value from the cache, creating it if necessary.\n\t * @param factory a factory used to create the item if there is no reference to it.\n\t * @param refreshAction action called to refresh the value if it has expired\n\t * @return the value from the cache\n\t */\n\tT get(Supplier<T> factory, UnaryOperator<T> refreshAction) {\n\t\tT value = getValue();\n\t\tif (value == null) {\n\t\t\tvalue = refreshAction.apply(factory.get());\n\t\t\tsetValue(value);\n\t\t}\n\t\telse if (hasExpired()) {\n\t\t\tvalue = refreshAction.apply(value);\n\t\t\tsetValue(value);\n\t\t}\n\t\tif (!this.neverExpire) {\n\t\t\tthis.lastAccessed = now();\n\t\t}\n\t\treturn value;\n\t}\n\n\tprivate boolean hasExpired() {\n\t\tif (this.neverExpire) {\n\t\t\treturn false;\n\t\t}\n\t\tDuration timeToLive = this.timeToLive;\n\t\tInstant lastAccessed = this.lastAccessed;\n\t\tif (timeToLive == null || lastAccessed == null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn !UNLIMITED.equals(timeToLive) && now().isAfter(lastAccessed.plus(timeToLive));\n\t}\n\n\tprotected Instant now() {\n\t\treturn Instant.now();\n\t}\n\n\tprotected @Nullable T getValue() {\n\t\treturn this.value.get();\n\t}\n\n\tprotected void setValue(T value) {\n\t\tthis.value = new SoftReference<>(value);\n\t}\n\n\t/**\n\t * An active {@link CacheOverride} with a stored time-to-live.\n\t */\n\tprivate record ActiveCacheOverride(SoftReferenceConfigurationPropertyCache<?> cache, @Nullable Duration timeToLive,\n\t\t\t@Nullable Instant lastAccessed, AtomicBoolean active) implements CacheOverride {\n\n\t\tActiveCacheOverride(SoftReferenceConfigurationPropertyCache<?> cache) {\n\t\t\tthis(cache, cache.timeToLive, cache.lastAccessed, new AtomicBoolean());\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t\tif (active().compareAndSet(false, true)) {\n\t\t\t\tthis.cache.restore(this);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Random;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigurationPropertySource} backed by a non-enumerable Spring\n * {@link PropertySource} or a restricted {@link EnumerablePropertySource} implementation\n * (such as a security restricted {@code systemEnvironment} source). A\n * {@link PropertySource} is adapted with the help of a {@link PropertyMapper} which\n * provides the mapping rules for individual properties.\n * <p>\n * Each {@link ConfigurationPropertySource#getConfigurationProperty\n * getConfigurationProperty} call attempts to\n * {@link PropertyMapper#map(ConfigurationPropertyName) map} the\n * {@link ConfigurationPropertyName} to one or more {@code String} based names. This\n * allows fast property resolution for well-formed property sources.\n * <p>\n * When possible the {@link SpringIterableConfigurationPropertySource} will be used in\n * preference to this implementation since it supports full \"relaxed\" style resolution.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see #from(PropertySource)\n * @see PropertyMapper\n * @see SpringIterableConfigurationPropertySource\n */\nclass SpringConfigurationPropertySource implements ConfigurationPropertySource {\n\n\tprivate static final PropertyMapper[] DEFAULT_MAPPERS = { DefaultPropertyMapper.INSTANCE };\n\n\tprivate static final PropertyMapper[] SYSTEM_ENVIRONMENT_MAPPERS = { SystemEnvironmentPropertyMapper.INSTANCE,\n\t\t\tDefaultPropertyMapper.INSTANCE };\n\n\tprivate final PropertySource<?> propertySource;\n\n\tprivate final boolean systemEnvironmentSource;\n\n\tprivate final PropertyMapper[] mappers;\n\n\t/**\n\t * Create a new {@link SpringConfigurationPropertySource} implementation.\n\t * @param propertySource the source property source\n\t * @param systemEnvironmentSource if the source is from the system environment\n\t * @param mappers the property mappers\n\t */\n\tSpringConfigurationPropertySource(PropertySource<?> propertySource, boolean systemEnvironmentSource,\n\t\t\tPropertyMapper... mappers) {\n\t\tAssert.notNull(propertySource, \"'propertySource' must not be null\");\n\t\tAssert.isTrue(mappers.length > 0, \"'mappers' must contain at least one item\");\n\t\tthis.propertySource = propertySource;\n\t\tthis.systemEnvironmentSource = systemEnvironmentSource;\n\t\tthis.mappers = mappers;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(@Nullable ConfigurationPropertyName name) {\n\t\tif (name == null) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (PropertyMapper mapper : this.mappers) {\n\t\t\ttry {\n\t\t\t\tfor (String candidate : mapper.map(name)) {\n\t\t\t\t\tObject value = getPropertySourceProperty(candidate);\n\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\tOrigin origin = PropertySourceOrigin.get(this.propertySource, candidate);\n\t\t\t\t\t\treturn ConfigurationProperty.of(this, name, value, origin);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprotected final @Nullable Object getPropertySourceProperty(String name) {\n\t\t// Save calls to SystemEnvironmentPropertySource.resolvePropertyName(...)\n\t\t// since we've already done the mapping\n\t\tPropertySource<?> propertySource = getPropertySource();\n\t\treturn (!this.systemEnvironmentSource) ? propertySource.getProperty(name)\n\t\t\t\t: getSystemEnvironmentProperty(((SystemEnvironmentPropertySource) propertySource).getSource(), name);\n\t}\n\n\t@Nullable Object getSystemEnvironmentProperty(Map<String, Object> systemEnvironment, String name) {\n\t\tObject value = systemEnvironment.get(name);\n\t\treturn (value != null) ? value : systemEnvironment.get(name.toLowerCase(Locale.ROOT));\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\tPropertySource<?> source = getPropertySource();\n\t\tObject underlyingSource = source.getSource();\n\t\tif (underlyingSource instanceof Random) {\n\t\t\treturn containsDescendantOfForRandom(\"random\", name);\n\t\t}\n\t\tif (underlyingSource instanceof PropertySource<?> underlyingPropertySource\n\t\t\t\t&& underlyingPropertySource.getSource() instanceof Random) {\n\t\t\t// Assume wrapped random sources use the source name as the prefix\n\t\t\treturn containsDescendantOfForRandom(source.getName(), name);\n\t\t}\n\t\treturn ConfigurationPropertyState.UNKNOWN;\n\t}\n\n\tprivate static ConfigurationPropertyState containsDescendantOfForRandom(String prefix,\n\t\t\tConfigurationPropertyName name) {\n\t\tif (name.getNumberOfElements() > 1 && name.getElement(0, Form.DASHED).equals(prefix)) {\n\t\t\treturn ConfigurationPropertyState.PRESENT;\n\t\t}\n\t\treturn ConfigurationPropertyState.ABSENT;\n\t}\n\n\t@Override\n\tpublic Object getUnderlyingSource() {\n\t\treturn this.propertySource;\n\t}\n\n\tprotected PropertySource<?> getPropertySource() {\n\t\treturn this.propertySource;\n\t}\n\n\tprotected final boolean isSystemEnvironmentSource() {\n\t\treturn this.systemEnvironmentSource;\n\t}\n\n\tprotected final PropertyMapper[] getMappers() {\n\t\treturn this.mappers;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.propertySource.toString();\n\t}\n\n\t/**\n\t * Create a new {@link SpringConfigurationPropertySource} for the specified\n\t * {@link PropertySource}.\n\t * @param source the source Spring {@link PropertySource}\n\t * @return a {@link SpringConfigurationPropertySource} or\n\t * {@link SpringIterableConfigurationPropertySource} instance\n\t */\n\tstatic SpringConfigurationPropertySource from(PropertySource<?> source) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tboolean systemEnvironmentSource = isSystemEnvironmentPropertySource(source);\n\t\tPropertyMapper[] mappers = (!systemEnvironmentSource) ? DEFAULT_MAPPERS : SYSTEM_ENVIRONMENT_MAPPERS;\n\t\treturn (!isFullEnumerable(source))\n\t\t\t\t? new SpringConfigurationPropertySource(source, systemEnvironmentSource, mappers)\n\t\t\t\t: new SpringIterableConfigurationPropertySource((EnumerablePropertySource<?>) source,\n\t\t\t\t\t\tsystemEnvironmentSource, mappers);\n\t}\n\n\tprivate static boolean isSystemEnvironmentPropertySource(PropertySource<?> source) {\n\t\tString name = source.getName();\n\t\treturn (source instanceof SystemEnvironmentPropertySource)\n\t\t\t\t&& (StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME.equals(name)\n\t\t\t\t\t\t|| name.endsWith(\"-\" + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME));\n\t}\n\n\tprivate static boolean isFullEnumerable(PropertySource<?> source) {\n\t\tPropertySource<?> rootSource = getRootSource(source);\n\t\tif (rootSource.getSource() instanceof Map<?, ?> map) {\n\t\t\t// Check we're not security restricted\n\t\t\ttry {\n\t\t\t\tmap.size();\n\t\t\t}\n\t\t\tcatch (UnsupportedOperationException ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn (source instanceof EnumerablePropertySource);\n\t}\n\n\tprivate static PropertySource<?> getRootSource(PropertySource<?> source) {\n\t\twhile (source.getSource() instanceof PropertySource<?> propertySource) {\n\t\t\tsource = propertySource;\n\t\t}\n\t\treturn source;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySource.StubPropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ConcurrentReferenceHashMap;\nimport org.springframework.util.ConcurrentReferenceHashMap.ReferenceType;\n\n/**\n * Adapter to convert Spring's {@link MutablePropertySources} to\n * {@link ConfigurationPropertySource ConfigurationPropertySources}.\n *\n * @author Phillip Webb\n */\nclass SpringConfigurationPropertySources implements Iterable<ConfigurationPropertySource> {\n\n\tprivate final Iterable<PropertySource<?>> sources;\n\n\tprivate final Map<PropertySource<?>, ConfigurationPropertySource> cache = new ConcurrentReferenceHashMap<>(16,\n\t\t\tReferenceType.SOFT);\n\n\tSpringConfigurationPropertySources(Iterable<PropertySource<?>> sources) {\n\t\tAssert.notNull(sources, \"'sources' must not be null\");\n\t\tthis.sources = sources;\n\t}\n\n\tboolean isUsingSources(Iterable<PropertySource<?>> sources) {\n\t\treturn this.sources == sources;\n\t}\n\n\t@Override\n\tpublic Iterator<ConfigurationPropertySource> iterator() {\n\t\treturn new SourcesIterator(this.sources.iterator(), this::adapt);\n\t}\n\n\tprivate ConfigurationPropertySource adapt(PropertySource<?> source) {\n\t\tConfigurationPropertySource result = this.cache.get(source);\n\t\t// Most PropertySources test equality only using the source name, so we need to\n\t\t// check the actual source hasn't also changed.\n\t\tif (result != null && result.getUnderlyingSource() == source) {\n\t\t\treturn result;\n\t\t}\n\t\tresult = SpringConfigurationPropertySource.from(source);\n\t\tif (source instanceof PropertySourceInfo propertySourceInfo) {\n\t\t\tresult = result.withPrefix(propertySourceInfo.getPrefix());\n\t\t}\n\t\tthis.cache.put(source, result);\n\t\treturn result;\n\t}\n\n\tprivate static class SourcesIterator implements Iterator<ConfigurationPropertySource> {\n\n\t\tprivate final Deque<Iterator<PropertySource<?>>> iterators;\n\n\t\tprivate @Nullable ConfigurationPropertySource next;\n\n\t\tprivate final Function<PropertySource<?>, ConfigurationPropertySource> adapter;\n\n\t\tSourcesIterator(Iterator<PropertySource<?>> iterator,\n\t\t\t\tFunction<PropertySource<?>, ConfigurationPropertySource> adapter) {\n\t\t\tthis.iterators = new ArrayDeque<>(4);\n\t\t\tthis.iterators.push(iterator);\n\t\t\tthis.adapter = adapter;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasNext() {\n\t\t\treturn fetchNext() != null;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurationPropertySource next() {\n\t\t\tConfigurationPropertySource next = fetchNext();\n\t\t\tif (next == null) {\n\t\t\t\tthrow new NoSuchElementException();\n\t\t\t}\n\t\t\tthis.next = null;\n\t\t\treturn next;\n\t\t}\n\n\t\tprivate @Nullable ConfigurationPropertySource fetchNext() {\n\t\t\tif (this.next == null) {\n\t\t\t\tif (this.iterators.isEmpty()) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (!this.iterators.peek().hasNext()) {\n\t\t\t\t\tthis.iterators.pop();\n\t\t\t\t\treturn fetchNext();\n\t\t\t\t}\n\t\t\t\tPropertySource<?> candidate = this.iterators.peek().next();\n\t\t\t\tif (candidate.getSource() instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\t\t\tpush(configurableEnvironment);\n\t\t\t\t\treturn fetchNext();\n\t\t\t\t}\n\t\t\t\tif (isIgnored(candidate)) {\n\t\t\t\t\treturn fetchNext();\n\t\t\t\t}\n\t\t\t\tthis.next = this.adapter.apply(candidate);\n\t\t\t}\n\t\t\treturn this.next;\n\t\t}\n\n\t\tprivate void push(ConfigurableEnvironment environment) {\n\t\t\tthis.iterators.push(environment.getPropertySources().iterator());\n\t\t}\n\n\t\tprivate boolean isIgnored(PropertySource<?> candidate) {\n\t\t\treturn (candidate instanceof StubPropertySource\n\t\t\t\t\t|| candidate instanceof ConfigurationPropertySourcesPropertySource);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.ConcurrentModificationException;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.BiPredicate;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ConcurrentReferenceHashMap;\n\n/**\n * {@link ConfigurationPropertySource} backed by an {@link EnumerablePropertySource}.\n * Extends {@link SpringConfigurationPropertySource} with full \"relaxed\" mapping support.\n * In order to use this adapter the underlying {@link PropertySource} must be fully\n * enumerable. A security restricted {@link SystemEnvironmentPropertySource} cannot be\n * adapted.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see PropertyMapper\n */\nclass SpringIterableConfigurationPropertySource extends SpringConfigurationPropertySource\n\t\timplements IterableConfigurationPropertySource, CachingConfigurationPropertySource {\n\n\tprivate final BiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> ancestorOfCheck;\n\n\tprivate final SoftReferenceConfigurationPropertyCache<Cache> cache;\n\n\tprivate volatile @Nullable ConfigurationPropertyName @Nullable [] configurationPropertyNames;\n\n\tprivate final @Nullable Map<ConfigurationPropertyName, ConfigurationPropertyState> containsDescendantOfCache;\n\n\tSpringIterableConfigurationPropertySource(EnumerablePropertySource<?> propertySource,\n\t\t\tboolean systemEnvironmentSource, PropertyMapper... mappers) {\n\t\tsuper(propertySource, systemEnvironmentSource, mappers);\n\t\tassertEnumerablePropertySource();\n\t\tboolean immutable = isImmutablePropertySource();\n\t\tthis.ancestorOfCheck = getAncestorOfCheck(mappers);\n\t\tthis.cache = new SoftReferenceConfigurationPropertyCache<>(immutable);\n\t\tthis.containsDescendantOfCache = (!systemEnvironmentSource) ? null : new ConcurrentReferenceHashMap<>();\n\t}\n\n\tprivate BiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> getAncestorOfCheck(\n\t\t\tPropertyMapper[] mappers) {\n\t\tBiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> ancestorOfCheck = mappers[0]\n\t\t\t.getAncestorOfCheck();\n\t\tfor (int i = 1; i < mappers.length; i++) {\n\t\t\tancestorOfCheck = ancestorOfCheck.or(mappers[i].getAncestorOfCheck());\n\t\t}\n\t\treturn ancestorOfCheck;\n\t}\n\n\tprivate void assertEnumerablePropertySource() {\n\t\tif (getPropertySource() instanceof MapPropertySource mapSource) {\n\t\t\ttry {\n\t\t\t\tmapSource.getSource().size();\n\t\t\t}\n\t\t\tcatch (UnsupportedOperationException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"PropertySource must be fully enumerable\");\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyCaching getCaching() {\n\t\treturn this.cache;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(@Nullable ConfigurationPropertyName name) {\n\t\tif (name == null) {\n\t\t\treturn null;\n\t\t}\n\t\tConfigurationProperty configurationProperty = super.getConfigurationProperty(name);\n\t\tif (configurationProperty != null) {\n\t\t\treturn configurationProperty;\n\t\t}\n\t\tfor (String candidate : getCache().getMapped(name)) {\n\t\t\tObject value = getPropertySourceProperty(candidate);\n\t\t\tif (value != null) {\n\t\t\t\tOrigin origin = PropertySourceOrigin.get(getPropertySource(), candidate);\n\t\t\t\treturn ConfigurationProperty.of(this, name, value, origin);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected @Nullable Object getSystemEnvironmentProperty(Map<String, Object> systemEnvironment, String name) {\n\t\treturn getCache().getSystemEnvironmentProperty(name);\n\t}\n\n\t@Override\n\tpublic Stream<ConfigurationPropertyName> stream() {\n\t\t@Nullable ConfigurationPropertyName[] names = getConfigurationPropertyNames();\n\t\treturn Arrays.stream(names).filter(Objects::nonNull);\n\t}\n\n\t@Override\n\tpublic Iterator<ConfigurationPropertyName> iterator() {\n\t\treturn new ConfigurationPropertyNamesIterator(getConfigurationPropertyNames());\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\tConfigurationPropertyState result = super.containsDescendantOf(name);\n\t\tif (result != ConfigurationPropertyState.UNKNOWN) {\n\t\t\treturn result;\n\t\t}\n\t\tif (this.ancestorOfCheck == PropertyMapper.DEFAULT_ANCESTOR_OF_CHECK) {\n\t\t\tSet<ConfigurationPropertyName> descendants = getCache().getDescendants();\n\t\t\tif (descendants != null) {\n\t\t\t\tif (name.isEmpty() && !descendants.isEmpty()) {\n\t\t\t\t\treturn ConfigurationPropertyState.PRESENT;\n\t\t\t\t}\n\t\t\t\treturn !descendants.contains(name) ? ConfigurationPropertyState.ABSENT\n\t\t\t\t\t\t: ConfigurationPropertyState.PRESENT;\n\t\t\t}\n\t\t}\n\t\tresult = (this.containsDescendantOfCache != null) ? this.containsDescendantOfCache.get(name) : null;\n\t\tif (result == null) {\n\t\t\tresult = (!ancestorOfCheck(name)) ? ConfigurationPropertyState.ABSENT : ConfigurationPropertyState.PRESENT;\n\t\t\tif (this.containsDescendantOfCache != null) {\n\t\t\t\tthis.containsDescendantOfCache.put(name, result);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate boolean ancestorOfCheck(ConfigurationPropertyName name) {\n\t\t@Nullable ConfigurationPropertyName[] candidates = getConfigurationPropertyNames();\n\t\tfor (ConfigurationPropertyName candidate : candidates) {\n\t\t\tif (candidate != null && this.ancestorOfCheck.test(name, candidate)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Nullable ConfigurationPropertyName[] getConfigurationPropertyNames() {\n\t\tif (!isImmutablePropertySource()) {\n\t\t\treturn getCache().getConfigurationPropertyNames(getPropertySource().getPropertyNames());\n\t\t}\n\t\t@Nullable ConfigurationPropertyName[] configurationPropertyNames = this.configurationPropertyNames;\n\t\tif (configurationPropertyNames == null) {\n\t\t\tconfigurationPropertyNames = getCache()\n\t\t\t\t.getConfigurationPropertyNames(getPropertySource().getPropertyNames());\n\t\t\tthis.configurationPropertyNames = configurationPropertyNames;\n\t\t}\n\t\treturn configurationPropertyNames;\n\t}\n\n\tprivate Cache getCache() {\n\t\treturn this.cache.get(this::createCache, this::updateCache);\n\t}\n\n\tprivate Cache createCache() {\n\t\tboolean immutable = isImmutablePropertySource();\n\t\tboolean captureDescendants = this.ancestorOfCheck == PropertyMapper.DEFAULT_ANCESTOR_OF_CHECK;\n\t\treturn new Cache(getMappers(), immutable, captureDescendants, isSystemEnvironmentSource());\n\t}\n\n\tprivate Cache updateCache(Cache cache) {\n\t\tcache.update(getPropertySource());\n\t\treturn cache;\n\t}\n\n\tboolean isImmutablePropertySource() {\n\t\tEnumerablePropertySource<?> source = getPropertySource();\n\t\tif (source instanceof PropertySourceInfo propertySourceInfo) {\n\t\t\treturn propertySourceInfo.isImmutable();\n\t\t}\n\t\tif (StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME.equals(source.getName())) {\n\t\t\treturn source.getSource() == System.getenv();\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tprotected EnumerablePropertySource<?> getPropertySource() {\n\t\treturn (EnumerablePropertySource<?>) super.getPropertySource();\n\t}\n\n\tprivate static class Cache {\n\n\t\tprivate static final ConfigurationPropertyName[] EMPTY_NAMES_ARRAY = {};\n\n\t\tprivate final PropertyMapper[] mappers;\n\n\t\tprivate final boolean immutable;\n\n\t\tprivate final boolean captureDescendants;\n\n\t\tprivate final boolean systemEnvironmentSource;\n\n\t\tprivate volatile @Nullable Data data;\n\n\t\tCache(PropertyMapper[] mappers, boolean immutable, boolean captureDescendants,\n\t\t\t\tboolean systemEnvironmentSource) {\n\t\t\tthis.mappers = mappers;\n\t\t\tthis.immutable = immutable;\n\t\t\tthis.captureDescendants = captureDescendants;\n\t\t\tthis.systemEnvironmentSource = systemEnvironmentSource;\n\t\t}\n\n\t\tvoid update(EnumerablePropertySource<?> propertySource) {\n\t\t\tif (this.data == null || !this.immutable) {\n\t\t\t\tint count = 0;\n\t\t\t\twhile (true) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttryUpdate(propertySource);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ConcurrentModificationException ex) {\n\t\t\t\t\t\tif (count++ > 10) {\n\t\t\t\t\t\t\tthrow ex;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void tryUpdate(EnumerablePropertySource<?> propertySource) {\n\t\t\tData data = this.data;\n\t\t\tString[] lastUpdated = (data != null) ? data.lastUpdated() : null;\n\t\t\tString[] propertyNames = propertySource.getPropertyNames();\n\t\t\tif (lastUpdated != null && Arrays.equals(lastUpdated, propertyNames)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tint size = propertyNames.length;\n\t\t\tMap<ConfigurationPropertyName, Set<String>> mappings = cloneOrCreate(\n\t\t\t\t\t(data != null) ? data.mappings() : null, size);\n\t\t\tMap<String, ConfigurationPropertyName> reverseMappings = cloneOrCreate(\n\t\t\t\t\t(data != null) ? data.reverseMappings() : null, size);\n\t\t\tSet<ConfigurationPropertyName> descendants = (!this.captureDescendants) ? null : new HashSet<>();\n\t\t\tMap<String, Object> systemEnvironmentCopy = (!this.systemEnvironmentSource) ? null\n\t\t\t\t\t: copySource(propertySource);\n\t\t\tfor (PropertyMapper propertyMapper : this.mappers) {\n\t\t\t\tfor (String propertyName : propertyNames) {\n\t\t\t\t\tif (!reverseMappings.containsKey(propertyName)) {\n\t\t\t\t\t\tConfigurationPropertyName configurationPropertyName = propertyMapper.map(propertyName);\n\t\t\t\t\t\tif (configurationPropertyName != null && !configurationPropertyName.isEmpty()) {\n\t\t\t\t\t\t\tadd(mappings, configurationPropertyName, propertyName);\n\t\t\t\t\t\t\treverseMappings.put(propertyName, configurationPropertyName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (String propertyName : propertyNames) {\n\t\t\t\taddParents(descendants, reverseMappings.get(propertyName));\n\t\t\t}\n\t\t\tConfigurationPropertyName[] configurationPropertyNames = this.immutable\n\t\t\t\t\t? reverseMappings.values().toArray(new ConfigurationPropertyName[0]) : null;\n\t\t\tlastUpdated = this.immutable ? null : propertyNames;\n\t\t\tthis.data = new Data(mappings, reverseMappings, descendants, configurationPropertyNames,\n\t\t\t\t\tsystemEnvironmentCopy, lastUpdated);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate HashMap<String, Object> copySource(EnumerablePropertySource<?> propertySource) {\n\t\t\treturn new HashMap<>((Map<String, Object>) propertySource.getSource());\n\t\t}\n\n\t\tprivate <K, V> Map<K, V> cloneOrCreate(@Nullable Map<K, V> source, int size) {\n\t\t\treturn (source != null) ? new LinkedHashMap<>(source) : new LinkedHashMap<>(size);\n\t\t}\n\n\t\tprivate void addParents(@Nullable Set<ConfigurationPropertyName> descendants,\n\t\t\t\t@Nullable ConfigurationPropertyName name) {\n\t\t\tif (descendants == null || name == null || name.isEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tConfigurationPropertyName parent = name.getParent();\n\t\t\twhile (!parent.isEmpty()) {\n\t\t\t\tif (!descendants.add(parent)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tparent = parent.getParent();\n\t\t\t}\n\t\t}\n\n\t\tprivate <K, T> void add(Map<K, Set<T>> map, K key, T value) {\n\t\t\tmap.computeIfAbsent(key, (k) -> new HashSet<>()).add(value);\n\t\t}\n\n\t\tSet<String> getMapped(ConfigurationPropertyName configurationPropertyName) {\n\t\t\tData data = this.data;\n\t\t\tAssert.state(data != null, \"'data' must not be null\");\n\t\t\treturn data.mappings().getOrDefault(configurationPropertyName, Collections.emptySet());\n\t\t}\n\n\t\t@Nullable ConfigurationPropertyName[] getConfigurationPropertyNames(String[] propertyNames) {\n\t\t\tData data = this.data;\n\t\t\tAssert.state(data != null, \"'data' must not be null\");\n\t\t\t@Nullable ConfigurationPropertyName[] names = data.configurationPropertyNames();\n\t\t\tif (names != null) {\n\t\t\t\treturn names;\n\t\t\t}\n\t\t\tMap<String, ConfigurationPropertyName> reverseMappings = data.reverseMappings();\n\t\t\tif (reverseMappings == null || reverseMappings.isEmpty()) {\n\t\t\t\treturn EMPTY_NAMES_ARRAY;\n\t\t\t}\n\t\t\tnames = new ConfigurationPropertyName[propertyNames.length];\n\t\t\tfor (int i = 0; i < propertyNames.length; i++) {\n\t\t\t\tnames[i] = reverseMappings.get(propertyNames[i]);\n\t\t\t}\n\t\t\treturn names;\n\t\t}\n\n\t\t@Nullable Set<ConfigurationPropertyName> getDescendants() {\n\t\t\tData data = this.data;\n\t\t\tAssert.state(data != null, \"'data' must not be null\");\n\t\t\treturn data.descendants();\n\t\t}\n\n\t\t@Nullable Object getSystemEnvironmentProperty(String name) {\n\t\t\tData data = this.data;\n\t\t\tAssert.state(data != null, \"'data' must not be null\");\n\t\t\tMap<String, Object> systemEnvironmentCopy = data.systemEnvironmentCopy();\n\t\t\tAssert.state(systemEnvironmentCopy != null, \"'systemEnvironmentCopy' must not be null\");\n\t\t\treturn systemEnvironmentCopy.get(name);\n\t\t}\n\n\t\tprivate record Data(Map<ConfigurationPropertyName, Set<String>> mappings,\n\t\t\t\tMap<String, ConfigurationPropertyName> reverseMappings,\n\t\t\t\t@Nullable Set<ConfigurationPropertyName> descendants,\n\t\t\t\tConfigurationPropertyName @Nullable [] configurationPropertyNames,\n\t\t\t\t@Nullable Map<String, Object> systemEnvironmentCopy, String @Nullable [] lastUpdated) {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * ConfigurationPropertyNames iterator backed by an array.\n\t */\n\tprivate static class ConfigurationPropertyNamesIterator implements Iterator<ConfigurationPropertyName> {\n\n\t\tprivate final @Nullable ConfigurationPropertyName[] names;\n\n\t\tprivate int index;\n\n\t\tConfigurationPropertyNamesIterator(@Nullable ConfigurationPropertyName[] names) {\n\t\t\tthis.names = names;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasNext() {\n\t\t\tskipNulls();\n\t\t\treturn this.index < this.names.length;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConfigurationPropertyName next() {\n\t\t\tskipNulls();\n\t\t\tif (this.index >= this.names.length) {\n\t\t\t\tthrow new NoSuchElementException();\n\t\t\t}\n\t\t\treturn this.names[this.index++];\n\t\t}\n\n\t\tprivate void skipNulls() {\n\t\t\twhile (this.index < this.names.length) {\n\t\t\t\tif (this.names[this.index] != null) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.index++;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.function.BiPredicate;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.ToStringFormat;\nimport org.springframework.util.ConcurrentReferenceHashMap;\n\n/**\n * {@link PropertyMapper} for system environment variables. Names are mapped by removing\n * invalid characters, converting to lower case and replacing \"{@code _}\" with\n * \"{@code .}\". For example, \"{@code SERVER_PORT}\" is mapped to \"{@code server.port}\". In\n * addition, numeric elements are mapped to indexes (e.g. \"{@code HOST_0}\" is mapped to\n * \"{@code host[0]}\").\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see PropertyMapper\n * @see SpringConfigurationPropertySource\n */\nfinal class SystemEnvironmentPropertyMapper implements PropertyMapper {\n\n\tpublic static final PropertyMapper INSTANCE = new SystemEnvironmentPropertyMapper();\n\n\tprivate final Map<String, ConfigurationPropertyName> propertySourceNameCache = new ConcurrentReferenceHashMap<>();\n\n\t@Override\n\tpublic List<String> map(ConfigurationPropertyName configurationPropertyName) {\n\t\tList<String> mapped = new ArrayList<>(4);\n\t\taddIfMissing(mapped, configurationPropertyName.toString(ToStringFormat.SYSTEM_ENVIRONMENT, true));\n\t\taddIfMissing(mapped, configurationPropertyName.toString(ToStringFormat.LEGACY_SYSTEM_ENVIRONMENT, true));\n\t\taddIfMissing(mapped, configurationPropertyName.toString(ToStringFormat.SYSTEM_ENVIRONMENT, false));\n\t\taddIfMissing(mapped, configurationPropertyName.toString(ToStringFormat.LEGACY_SYSTEM_ENVIRONMENT, false));\n\t\treturn mapped;\n\t}\n\n\tprivate void addIfMissing(List<String> list, String value) {\n\t\tif (!list.contains(value)) {\n\t\t\tlist.add(value);\n\t\t}\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyName map(String propertySourceName) {\n\t\tConfigurationPropertyName configurationPropertyName = this.propertySourceNameCache.get(propertySourceName);\n\t\tif (configurationPropertyName == null) {\n\t\t\tconfigurationPropertyName = convertName(propertySourceName);\n\t\t\tthis.propertySourceNameCache.put(propertySourceName, configurationPropertyName);\n\t\t}\n\t\treturn configurationPropertyName;\n\t}\n\n\tprivate ConfigurationPropertyName convertName(String propertySourceName) {\n\t\ttry {\n\t\t\treturn ConfigurationPropertyName.adapt(propertySourceName, '_', this::processElementValue);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn ConfigurationPropertyName.EMPTY;\n\t\t}\n\t}\n\n\tprivate CharSequence processElementValue(CharSequence value) {\n\t\tString result = value.toString().toLowerCase(Locale.ENGLISH);\n\t\treturn isNumber(result) ? \"[\" + result + \"]\" : result;\n\t}\n\n\tprivate static boolean isNumber(String string) {\n\t\treturn string.chars().allMatch(Character::isDigit);\n\t}\n\n\t@Override\n\tpublic BiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> getAncestorOfCheck() {\n\t\treturn this::isAncestorOf;\n\t}\n\n\tprivate boolean isAncestorOf(ConfigurationPropertyName name, ConfigurationPropertyName candidate) {\n\t\treturn name.isAncestorOf(candidate) || isLegacyAncestorOf(name, candidate);\n\t}\n\n\tprivate boolean isLegacyAncestorOf(ConfigurationPropertyName name, ConfigurationPropertyName candidate) {\n\t\tif (!name.hasDashedElement()) {\n\t\t\treturn false;\n\t\t}\n\t\tConfigurationPropertyName legacyCompatibleName = name.asSystemEnvironmentLegacyName();\n\t\treturn legacyCompatibleName != null && legacyCompatibleName.isAncestorOf(candidate);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/UnboundElementsSourceFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * Function used to determine if a {@link ConfigurationPropertySource} should be included\n * when determining unbound elements. If the underlying {@link PropertySource} is a\n * systemEnvironment or systemProperties property source, it will not be considered for\n * unbound element failures.\n *\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class UnboundElementsSourceFilter implements Function<ConfigurationPropertySource, Boolean> {\n\n\tprivate static final Set<String> BENIGN_PROPERTY_SOURCE_NAMES = Collections\n\t\t.unmodifiableSet(new HashSet<>(Arrays.asList(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tStandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)));\n\n\t@Override\n\tpublic Boolean apply(ConfigurationPropertySource configurationPropertySource) {\n\t\tObject underlyingSource = configurationPropertySource.getUnderlyingSource();\n\t\tif (underlyingSource instanceof PropertySource<?> propertySource) {\n\t\t\tString name = propertySource.getName();\n\t\t\treturn !BENIGN_PROPERTY_SOURCE_NAMES.contains(name);\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/context/properties/source/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sources for external configuration properties.\n *\n * @see org.springframework.boot.context.properties.source.ConfigurationPropertySource\n */\n@NullMarked\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/ApplicationConversionService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Annotation;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.BiFunction;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalConverter;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.ConverterFactory;\nimport org.springframework.core.convert.converter.ConverterRegistry;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.format.AnnotationFormatterFactory;\nimport org.springframework.format.Formatter;\nimport org.springframework.format.FormatterRegistry;\nimport org.springframework.format.Parser;\nimport org.springframework.format.Printer;\nimport org.springframework.format.support.DefaultFormattingConversionService;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.StringValueResolver;\n\n/**\n * A specialization of {@link FormattingConversionService} configured by default with\n * converters and formatters appropriate for most Spring Boot applications.\n * <p>\n * Designed for direct instantiation but also exposes the static\n * {@link #addApplicationConverters} and\n * {@link #addApplicationFormatters(FormatterRegistry)} utility methods for ad-hoc use\n * against registry instance.\n *\n * @author Phillip Webb\n * @author Shixiong Guo\n * @since 2.0.0\n */\npublic class ApplicationConversionService extends FormattingConversionService {\n\n\tprivate static final ResolvableType STRING = ResolvableType.forClass(String.class);\n\n\tprivate static volatile @Nullable ApplicationConversionService sharedInstance;\n\n\tprivate final boolean unmodifiable;\n\n\tpublic ApplicationConversionService() {\n\t\tthis(null);\n\t}\n\n\tpublic ApplicationConversionService(@Nullable StringValueResolver embeddedValueResolver) {\n\t\tthis(embeddedValueResolver, false);\n\t}\n\n\tprivate ApplicationConversionService(@Nullable StringValueResolver embeddedValueResolver, boolean unmodifiable) {\n\t\tif (embeddedValueResolver != null) {\n\t\t\tsetEmbeddedValueResolver(embeddedValueResolver);\n\t\t}\n\t\tconfigure(this);\n\t\tthis.unmodifiable = unmodifiable;\n\t}\n\n\t@Override\n\tpublic void addPrinter(Printer<?> printer) {\n\t\tassertModifiable();\n\t\tsuper.addPrinter(printer);\n\t}\n\n\t@Override\n\tpublic void addParser(Parser<?> parser) {\n\t\tassertModifiable();\n\t\tsuper.addParser(parser);\n\t}\n\n\t@Override\n\tpublic void addFormatter(Formatter<?> formatter) {\n\t\tassertModifiable();\n\t\tsuper.addFormatter(formatter);\n\t}\n\n\t@Override\n\tpublic void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {\n\t\tassertModifiable();\n\t\tsuper.addFormatterForFieldType(fieldType, formatter);\n\t}\n\n\t@Override\n\tpublic void addConverter(Converter<?, ?> converter) {\n\t\tassertModifiable();\n\t\tsuper.addConverter(converter);\n\t}\n\n\t@Override\n\tpublic void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) {\n\t\tassertModifiable();\n\t\tsuper.addFormatterForFieldType(fieldType, printer, parser);\n\t}\n\n\t@Override\n\tpublic void addFormatterForFieldAnnotation(\n\t\t\tAnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory) {\n\t\tassertModifiable();\n\t\tsuper.addFormatterForFieldAnnotation(annotationFormatterFactory);\n\t}\n\n\t@Override\n\tpublic <S, T> void addConverter(Class<S> sourceType, Class<T> targetType,\n\t\t\tConverter<? super S, ? extends T> converter) {\n\t\tassertModifiable();\n\t\tsuper.addConverter(sourceType, targetType, converter);\n\t}\n\n\t@Override\n\tpublic void addConverter(GenericConverter converter) {\n\t\tassertModifiable();\n\t\tsuper.addConverter(converter);\n\t}\n\n\t@Override\n\tpublic void addConverterFactory(ConverterFactory<?, ?> factory) {\n\t\tassertModifiable();\n\t\tsuper.addConverterFactory(factory);\n\t}\n\n\t@Override\n\tpublic void removeConvertible(Class<?> sourceType, Class<?> targetType) {\n\t\tassertModifiable();\n\t\tsuper.removeConvertible(sourceType, targetType);\n\t}\n\n\tprivate void assertModifiable() {\n\t\tif (this.unmodifiable) {\n\t\t\tthrow new UnsupportedOperationException(\"This ApplicationConversionService cannot be modified\");\n\t\t}\n\t}\n\n\t/**\n\t * Return {@code true} if objects of {@code sourceType} can be converted to the\n\t * {@code targetType} and the converter has {@code Object.class} as a supported source\n\t * type.\n\t * @param sourceType the source type to test\n\t * @param targetType the target type to test\n\t * @return if conversion happens through an {@code ObjectTo...} converter\n\t * @since 2.4.3\n\t */\n\tpublic boolean isConvertViaObjectSourceType(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tGenericConverter converter = getConverter(sourceType, targetType);\n\t\tSet<ConvertiblePair> pairs = (converter != null) ? converter.getConvertibleTypes() : null;\n\t\tif (pairs != null) {\n\t\t\tfor (ConvertiblePair pair : pairs) {\n\t\t\t\tif (Object.class.equals(pair.getSourceType())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return a shared default application {@code ConversionService} instance, lazily\n\t * building it once needed.\n\t * <p>\n\t * Note: This method actually returns an {@link ApplicationConversionService}\n\t * instance. However, the {@code ConversionService} signature has been preserved for\n\t * binary compatibility.\n\t * @return the shared {@code ApplicationConversionService} instance (never\n\t * {@code null})\n\t */\n\tpublic static ConversionService getSharedInstance() {\n\t\tApplicationConversionService sharedInstance = ApplicationConversionService.sharedInstance;\n\t\tif (sharedInstance == null) {\n\t\t\tsynchronized (ApplicationConversionService.class) {\n\t\t\t\tsharedInstance = ApplicationConversionService.sharedInstance;\n\t\t\t\tif (sharedInstance == null) {\n\t\t\t\t\tsharedInstance = new ApplicationConversionService(null, true);\n\t\t\t\t\tApplicationConversionService.sharedInstance = sharedInstance;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn sharedInstance;\n\t}\n\n\t/**\n\t * Configure the given {@link FormatterRegistry} with formatters and converters\n\t * appropriate for most Spring Boot applications.\n\t * @param registry the registry of converters to add to (must also be castable to\n\t * ConversionService, e.g. being a {@link ConfigurableConversionService})\n\t * @throws ClassCastException if the given FormatterRegistry could not be cast to a\n\t * ConversionService\n\t */\n\tpublic static void configure(FormatterRegistry registry) {\n\t\tDefaultConversionService.addDefaultConverters(registry);\n\t\tDefaultFormattingConversionService.addDefaultFormatters(registry);\n\t\taddApplicationFormatters(registry);\n\t\taddApplicationConverters(registry);\n\t}\n\n\t/**\n\t * Add converters useful for most Spring Boot applications.\n\t * @param registry the registry of converters to add to (must also be castable to\n\t * ConversionService, e.g. being a {@link ConfigurableConversionService})\n\t * @throws ClassCastException if the given ConverterRegistry could not be cast to a\n\t * ConversionService\n\t */\n\tpublic static void addApplicationConverters(ConverterRegistry registry) {\n\t\taddDelimitedStringConverters(registry);\n\t\tregistry.addConverter(new StringToDurationConverter());\n\t\tregistry.addConverter(new DurationToStringConverter());\n\t\tregistry.addConverter(new NumberToDurationConverter());\n\t\tregistry.addConverter(new DurationToNumberConverter());\n\t\tregistry.addConverter(new StringToPeriodConverter());\n\t\tregistry.addConverter(new PeriodToStringConverter());\n\t\tregistry.addConverter(new NumberToPeriodConverter());\n\t\tregistry.addConverter(new StringToDataSizeConverter());\n\t\tregistry.addConverter(new NumberToDataSizeConverter());\n\t\tregistry.addConverter(new StringToFileConverter());\n\t\tregistry.addConverter(new InputStreamSourceToByteArrayConverter());\n\t\tregistry.addConverterFactory(new LenientStringToEnumConverterFactory());\n\t\tregistry.addConverterFactory(new LenientBooleanToEnumConverterFactory());\n\t\tif (registry instanceof ConversionService conversionService) {\n\t\t\taddApplicationConverters(registry, conversionService);\n\t\t}\n\t}\n\n\tprivate static void addApplicationConverters(ConverterRegistry registry, ConversionService conversionService) {\n\t\tregistry.addConverter(new CharSequenceToObjectConverter(conversionService));\n\t}\n\n\t/**\n\t * Add converters to support delimited strings.\n\t * @param registry the registry of converters to add to (must also be castable to\n\t * ConversionService, e.g. being a {@link ConfigurableConversionService})\n\t * @throws ClassCastException if the given ConverterRegistry could not be cast to a\n\t * ConversionService\n\t */\n\tpublic static void addDelimitedStringConverters(ConverterRegistry registry) {\n\t\tConversionService service = (ConversionService) registry;\n\t\tregistry.addConverter(new ArrayToDelimitedStringConverter(service));\n\t\tregistry.addConverter(new CollectionToDelimitedStringConverter(service));\n\t\tregistry.addConverter(new DelimitedStringToArrayConverter(service));\n\t\tregistry.addConverter(new DelimitedStringToCollectionConverter(service));\n\t}\n\n\t/**\n\t * Add formatters useful for most Spring Boot applications.\n\t * @param registry the service to register default formatters with\n\t */\n\tpublic static void addApplicationFormatters(FormatterRegistry registry) {\n\t\tregistry.addFormatter(new CharArrayFormatter());\n\t\tregistry.addFormatter(new InetAddressFormatter());\n\t\tregistry.addFormatter(new IsoOffsetFormatter());\n\t}\n\n\t/**\n\t * Add {@link Printer}, {@link Parser}, {@link Formatter}, {@link Converter},\n\t * {@link ConverterFactory}, {@link GenericConverter}, and beans from the specified\n\t * bean factory.\n\t * @param registry the service to register beans with\n\t * @param beanFactory the bean factory to get the beans from\n\t * @since 2.2.0\n\t */\n\tpublic static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {\n\t\taddBeans(registry, beanFactory, null);\n\t}\n\n\t/**\n\t * Add {@link Printer}, {@link Parser}, {@link Formatter}, {@link Converter},\n\t * {@link ConverterFactory}, {@link GenericConverter}, and beans from the specified\n\t * bean factory.\n\t * @param registry the service to register beans with\n\t * @param beanFactory the bean factory to get the beans from\n\t * @param qualifier the qualifier required on the beans or {@code null}\n\t * @return the beans that were added\n\t * @since 3.5.0\n\t */\n\tpublic static Map<String, Object> addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory,\n\t\t\t@Nullable String qualifier) {\n\t\tConfigurableListableBeanFactory configurableBeanFactory = getConfigurableListableBeanFactory(beanFactory);\n\t\tMap<String, Object> beans = getBeans(beanFactory, qualifier);\n\t\tbeans.forEach((beanName, bean) -> {\n\t\t\tBeanDefinition beanDefinition = (configurableBeanFactory != null)\n\t\t\t\t\t? configurableBeanFactory.getMergedBeanDefinition(beanName) : null;\n\t\t\tResolvableType type = (beanDefinition != null) ? beanDefinition.getResolvableType() : null;\n\t\t\taddBean(registry, bean, type);\n\t\t});\n\t\treturn beans;\n\t}\n\n\tprivate static @Nullable ConfigurableListableBeanFactory getConfigurableListableBeanFactory(\n\t\t\tListableBeanFactory beanFactory) {\n\t\tif (beanFactory instanceof ConfigurableApplicationContext applicationContext) {\n\t\t\treturn applicationContext.getBeanFactory();\n\t\t}\n\t\tif (beanFactory instanceof ConfigurableListableBeanFactory configurableListableBeanFactory) {\n\t\t\treturn configurableListableBeanFactory;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static Map<String, Object> getBeans(ListableBeanFactory beanFactory, @Nullable String qualifier) {\n\t\tMap<String, Object> beans = new LinkedHashMap<>();\n\t\tbeans.putAll(getBeans(beanFactory, Printer.class, qualifier));\n\t\tbeans.putAll(getBeans(beanFactory, Parser.class, qualifier));\n\t\tbeans.putAll(getBeans(beanFactory, Formatter.class, qualifier));\n\t\tbeans.putAll(getBeans(beanFactory, Converter.class, qualifier));\n\t\tbeans.putAll(getBeans(beanFactory, ConverterFactory.class, qualifier));\n\t\tbeans.putAll(getBeans(beanFactory, GenericConverter.class, qualifier));\n\t\treturn beans;\n\t}\n\n\tprivate static <T> Map<String, T> getBeans(ListableBeanFactory beanFactory, Class<T> type,\n\t\t\t@Nullable String qualifier) {\n\t\treturn (!StringUtils.hasLength(qualifier)) ? beanFactory.getBeansOfType(type)\n\t\t\t\t: BeanFactoryAnnotationUtils.qualifiedBeansOfType(beanFactory, type, qualifier);\n\t}\n\n\tstatic void addBean(FormatterRegistry registry, Object bean, @Nullable ResolvableType beanType) {\n\t\tif (bean instanceof GenericConverter converterBean) {\n\t\t\taddBean(registry, converterBean, beanType, GenericConverter.class, registry::addConverter, (Runnable) null);\n\t\t}\n\t\telse if (bean instanceof Converter<?, ?> converterBean) {\n\t\t\tAssert.state(beanType != null, \"beanType is missing\");\n\t\t\taddBeanWithType(registry, converterBean, beanType, Converter.class, registry::addConverter,\n\t\t\t\t\tConverterBeanAdapter::new);\n\t\t}\n\t\telse if (bean instanceof ConverterFactory<?, ?> converterBean) {\n\t\t\tAssert.state(beanType != null, \"beanType is missing\");\n\t\t\taddBeanWithType(registry, converterBean, beanType, ConverterFactory.class, registry::addConverterFactory,\n\t\t\t\t\tConverterFactoryBeanAdapter::new);\n\t\t}\n\t\telse if (bean instanceof Formatter<?> formatterBean) {\n\t\t\taddBean(registry, formatterBean, beanType, Formatter.class, registry::addFormatter, () -> {\n\t\t\t\tAssert.state(beanType != null, \"beanType is missing\");\n\t\t\t\tregistry.addConverter(new PrinterBeanAdapter(formatterBean, beanType));\n\t\t\t\tregistry.addConverter(new ParserBeanAdapter(formatterBean, beanType));\n\t\t\t});\n\t\t}\n\t\telse if (bean instanceof Printer<?> printerBean) {\n\t\t\tAssert.state(beanType != null, \"beanType is missing\");\n\t\t\taddBeanWithType(registry, printerBean, beanType, Printer.class, registry::addPrinter,\n\t\t\t\t\tPrinterBeanAdapter::new);\n\t\t}\n\t\telse if (bean instanceof Parser<?> parserBean) {\n\t\t\tAssert.state(beanType != null, \"beanType is missing\");\n\t\t\taddBeanWithType(registry, parserBean, beanType, Parser.class, registry::addParser, ParserBeanAdapter::new);\n\t\t}\n\t}\n\n\tprivate static <B, T> void addBeanWithType(FormatterRegistry registry, B bean, ResolvableType beanType,\n\t\t\tClass<T> type, Consumer<B> standardRegistrar,\n\t\t\tBiFunction<B, ResolvableType, BeanAdapter<?>> beanAdapterFactory) {\n\t\taddBean(registry, bean, beanType, type, standardRegistrar,\n\t\t\t\t() -> registry.addConverter(beanAdapterFactory.apply(bean, beanType)));\n\t}\n\n\tprivate static <B, T> void addBean(FormatterRegistry registry, B bean, @Nullable ResolvableType beanType,\n\t\t\tClass<T> type, Consumer<B> standardRegistrar, @Nullable Runnable beanAdapterRegistrar) {\n\t\tif (beanType != null && beanAdapterRegistrar != null\n\t\t\t\t&& ResolvableType.forInstance(bean).as(type).hasUnresolvableGenerics()) {\n\t\t\tbeanAdapterRegistrar.run();\n\t\t\treturn;\n\t\t}\n\t\tstandardRegistrar.accept(bean);\n\t}\n\n\t/**\n\t * Base class for adapters that adapt a bean to a {@link GenericConverter}.\n\t *\n\t * @param <B> the base type of the bean\n\t */\n\tabstract static class BeanAdapter<B> implements ConditionalGenericConverter {\n\n\t\tprivate final B bean;\n\n\t\tprivate final ResolvableTypePair types;\n\n\t\tBeanAdapter(B bean, ResolvableType beanType) {\n\t\t\tAssert.isInstanceOf(beanType.toClass(), bean);\n\t\t\tResolvableType type = ResolvableType.forClass(getClass()).as(BeanAdapter.class).getGeneric();\n\t\t\tResolvableType[] generics = beanType.as(type.toClass()).getGenerics();\n\t\t\tthis.bean = bean;\n\t\t\tthis.types = getResolvableTypePair(generics);\n\t\t}\n\n\t\tprotected ResolvableTypePair getResolvableTypePair(ResolvableType[] generics) {\n\t\t\treturn new ResolvableTypePair(generics[0], generics[1]);\n\t\t}\n\n\t\tprotected B bean() {\n\t\t\treturn this.bean;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\t\treturn Set.of(new ConvertiblePair(this.types.source().toClass(), this.types.target().toClass()));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn (this.types.target().toClass() == targetType.getObjectType()\n\t\t\t\t\t&& matchesTargetType(targetType.getResolvableType()));\n\t\t}\n\n\t\tprivate boolean matchesTargetType(ResolvableType targetType) {\n\t\t\tResolvableType ours = this.types.target();\n\t\t\treturn targetType.getType() instanceof Class || targetType.isAssignableFrom(ours)\n\t\t\t\t\t|| this.types.target().hasUnresolvableGenerics();\n\t\t}\n\n\t\tprotected final boolean conditionalConverterCandidateMatches(Object conditionalConverterCandidate,\n\t\t\t\tTypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn (conditionalConverterCandidate instanceof ConditionalConverter conditionalConverter)\n\t\t\t\t\t? conditionalConverter.matches(sourceType, targetType) : true;\n\t\t}\n\n\t\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t\tprotected final @Nullable Object convert(@Nullable Object source, TypeDescriptor targetType,\n\t\t\t\tConverter<?, ?> converter) {\n\t\t\treturn (source != null) ? ((Converter) converter).convert(source) : convertNull(targetType);\n\t\t}\n\n\t\tprivate @Nullable Object convertNull(TypeDescriptor targetType) {\n\t\t\treturn (targetType.getObjectType() != Optional.class) ? null : Optional.empty();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.types + \" : \" + this.bean;\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts a {@link Printer} bean to a {@link GenericConverter}.\n\t */\n\tstatic class PrinterBeanAdapter extends BeanAdapter<Printer<?>> {\n\n\t\tPrinterBeanAdapter(Printer<?> bean, ResolvableType beanType) {\n\t\t\tsuper(bean, beanType);\n\t\t}\n\n\t\t@Override\n\t\tprotected ResolvableTypePair getResolvableTypePair(ResolvableType[] generics) {\n\t\t\treturn new ResolvableTypePair(generics[0], STRING);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn (source != null) ? print(source) : \"\";\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate String print(Object object) {\n\t\t\treturn ((Printer<Object>) bean()).print(object, LocaleContextHolder.getLocale());\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts a {@link Parser} bean to a {@link GenericConverter}.\n\t */\n\tstatic class ParserBeanAdapter extends BeanAdapter<Parser<?>> {\n\n\t\tParserBeanAdapter(Parser<?> bean, ResolvableType beanType) {\n\t\t\tsuper(bean, beanType);\n\t\t}\n\n\t\t@Override\n\t\tprotected ResolvableTypePair getResolvableTypePair(ResolvableType[] generics) {\n\t\t\treturn new ResolvableTypePair(STRING, generics[0]);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tString text = (String) source;\n\t\t\treturn (!StringUtils.hasText(text)) ? null : parse(text);\n\t\t}\n\n\t\tprivate Object parse(String text) {\n\t\t\ttry {\n\t\t\t\treturn bean().parse(text, LocaleContextHolder.getLocale());\n\t\t\t}\n\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Parse attempt failed for value [\" + text + \"]\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts a {@link Converter} bean to a {@link GenericConverter}.\n\t */\n\tstatic final class ConverterBeanAdapter extends BeanAdapter<Converter<?, ?>> {\n\n\t\tConverterBeanAdapter(Converter<?, ?> bean, ResolvableType beanType) {\n\t\t\tsuper(bean, beanType);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn super.matches(sourceType, targetType)\n\t\t\t\t\t&& conditionalConverterCandidateMatches(bean(), sourceType, targetType);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn convert(source, targetType, bean());\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts a {@link ConverterFactory} bean to a {@link GenericConverter}.\n\t */\n\tprivate static final class ConverterFactoryBeanAdapter extends BeanAdapter<ConverterFactory<?, ?>> {\n\n\t\tConverterFactoryBeanAdapter(ConverterFactory<?, ?> bean, ResolvableType beanType) {\n\t\t\tsuper(bean, beanType);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn super.matches(sourceType, targetType)\n\t\t\t\t\t&& conditionalConverterCandidateMatches(bean(), sourceType, targetType)\n\t\t\t\t\t&& conditionalConverterCandidateMatches(getConverter(targetType::getType), sourceType, targetType);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn convert(source, targetType, getConverter(targetType::getObjectType));\n\t\t}\n\n\t\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t\tprivate Converter<Object, ?> getConverter(Supplier<Class<?>> typeSupplier) {\n\t\t\treturn ((ConverterFactory) bean()).getConverter(typeSupplier.get());\n\t\t}\n\n\t}\n\n\t/**\n\t * Convertible type information as extracted from bean generics.\n\t *\n\t * @param source the source type\n\t * @param target the target type\n\t */\n\trecord ResolvableTypePair(ResolvableType source, ResolvableType target) {\n\n\t\tResolvableTypePair {\n\t\t\tAssert.notNull(source.resolve(), \"'source' cannot be resolved\");\n\t\t\tAssert.notNull(target.resolve(), \"'target' cannot be resolved\");\n\t\t}\n\n\t\t@Override\n\t\tpublic final String toString() {\n\t\t\treturn source() + \" -> \" + target();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/ArrayToDelimitedStringConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Converts an array to a delimited String.\n *\n * @author Phillip Webb\n */\nfinal class ArrayToDelimitedStringConverter implements ConditionalGenericConverter {\n\n\tprivate final CollectionToDelimitedStringConverter delegate;\n\n\tArrayToDelimitedStringConverter(ConversionService conversionService) {\n\t\tthis.delegate = new CollectionToDelimitedStringConverter(conversionService);\n\t}\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Object[].class, String.class));\n\t}\n\n\t@Override\n\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn this.delegate.matches(sourceType, targetType);\n\t}\n\n\t@Override\n\tpublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tList<Object> list = Arrays.asList(ObjectUtils.toObjectArray(source));\n\t\treturn this.delegate.convert(list, sourceType, targetType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/CharArrayFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.text.ParseException;\nimport java.util.Locale;\n\nimport org.springframework.format.Formatter;\n\n/**\n * {@link Formatter} for {@code char[]}.\n *\n * @author Phillip Webb\n */\nfinal class CharArrayFormatter implements Formatter<char[]> {\n\n\t@Override\n\tpublic String print(char[] object, Locale locale) {\n\t\treturn new String(object);\n\t}\n\n\t@Override\n\tpublic char[] parse(String text, Locale locale) throws ParseException {\n\t\treturn text.toCharArray();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/CharSequenceToObjectConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\n\n/**\n * {@link ConditionalGenericConverter} to convert {@link CharSequence} type by delegating\n * to existing {@link String} converters.\n *\n * @author Phillip Webb\n */\nclass CharSequenceToObjectConverter implements ConditionalGenericConverter {\n\n\tprivate static final TypeDescriptor STRING = TypeDescriptor.valueOf(String.class);\n\n\tprivate static final TypeDescriptor BYTE_ARRAY = TypeDescriptor.valueOf(byte[].class);\n\n\tprivate static final Set<ConvertiblePair> TYPES;\n\n\tprivate final ThreadLocal<Boolean> disable = new ThreadLocal<>();\n\n\tstatic {\n\t\tTYPES = Collections.singleton(new ConvertiblePair(CharSequence.class, Object.class));\n\t}\n\n\tprivate final ConversionService conversionService;\n\n\tCharSequenceToObjectConverter(ConversionService conversionService) {\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn TYPES;\n\t}\n\n\t@Override\n\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (sourceType.getType() == String.class || this.disable.get() == Boolean.TRUE) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.disable.set(Boolean.TRUE);\n\t\ttry {\n\t\t\tboolean canDirectlyConvertCharSequence = this.conversionService.canConvert(sourceType, targetType);\n\t\t\tif (canDirectlyConvertCharSequence && !isStringConversionBetter(sourceType, targetType)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.conversionService.canConvert(STRING, targetType);\n\t\t}\n\t\tfinally {\n\t\t\tthis.disable.remove();\n\t\t}\n\t}\n\n\t/**\n\t * Return if String based conversion is better based on the target type. This is\n\t * required when ObjectTo... conversion produces incorrect results.\n\t * @param sourceType the source type to test\n\t * @param targetType the target type to test\n\t * @return if string conversion is better\n\t */\n\tprivate boolean isStringConversionBetter(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (this.conversionService instanceof ApplicationConversionService applicationConversionService) {\n\t\t\tif (applicationConversionService.isConvertViaObjectSourceType(sourceType, targetType)) {\n\t\t\t\t// If an ObjectTo... converter is being used then there might be a better\n\t\t\t\t// StringTo... version\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tif ((targetType.isArray() || targetType.isCollection()) && !targetType.equals(BYTE_ARRAY)) {\n\t\t\t// StringToArrayConverter / StringToCollectionConverter are better than\n\t\t\t// ObjectToArrayConverter / ObjectToCollectionConverter\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn this.conversionService.convert((source != null) ? source.toString() : null, STRING, targetType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/CollectionToDelimitedStringConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\nimport org.springframework.lang.Contract;\n\n/**\n * Converts a Collection to a delimited String.\n *\n * @author Phillip Webb\n */\nfinal class CollectionToDelimitedStringConverter implements ConditionalGenericConverter {\n\n\tprivate final ConversionService conversionService;\n\n\tCollectionToDelimitedStringConverter(ConversionService conversionService) {\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Collection.class, String.class));\n\t}\n\n\t@Override\n\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tTypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();\n\t\tif (targetType == null || sourceElementType == null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this.conversionService.canConvert(sourceElementType, targetType)\n\t\t\t\t|| sourceElementType.getType().isAssignableFrom(targetType.getType());\n\t}\n\n\t@Override\n\t@Contract(\"!null, _, _ -> !null\")\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\tCollection<?> sourceCollection = (Collection<?>) source;\n\t\treturn convert(sourceCollection, sourceType, targetType);\n\t}\n\n\tprivate Object convert(Collection<?> source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source.isEmpty()) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn source.stream()\n\t\t\t.map((element) -> convertElement(element, sourceType, targetType))\n\t\t\t.collect(Collectors.joining(getDelimiter(sourceType)));\n\t}\n\n\tprivate CharSequence getDelimiter(TypeDescriptor sourceType) {\n\t\tDelimiter annotation = sourceType.getAnnotation(Delimiter.class);\n\t\treturn (annotation != null) ? annotation.value() : \",\";\n\t}\n\n\tprivate String convertElement(Object element, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn String\n\t\t\t.valueOf(this.conversionService.convert(element, sourceType.elementTypeDescriptor(element), targetType));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DataSizeUnit.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\n/**\n * Annotation that can be used to change the default unit used when converting a\n * {@link DataSize}.\n *\n * @author Stephane Nicoll\n * @since 2.1.0\n */\n@Target({ ElementType.FIELD, ElementType.PARAMETER })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DataSizeUnit {\n\n\t/**\n\t * The {@link DataUnit} to use if one is not specified.\n\t * @return the data unit\n\t */\n\tDataUnit value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DelimitedStringToArrayConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.reflect.Array;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Converts a {@link Delimiter delimited} String to an Array.\n *\n * @author Phillip Webb\n */\nfinal class DelimitedStringToArrayConverter implements ConditionalGenericConverter {\n\n\tprivate final ConversionService conversionService;\n\n\tDelimitedStringToArrayConverter(ConversionService conversionService) {\n\t\tAssert.notNull(conversionService, \"'conversionService' must not be null\");\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(String.class, Object[].class));\n\t}\n\n\t@Override\n\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn targetType.getElementTypeDescriptor() == null\n\t\t\t\t|| this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert((String) source, sourceType, targetType);\n\t}\n\n\tprivate Object convert(String source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tDelimiter delimiter = targetType.getAnnotation(Delimiter.class);\n\t\tString[] elements = getElements(source, (delimiter != null) ? delimiter.value() : \",\");\n\t\tTypeDescriptor elementDescriptor = targetType.getElementTypeDescriptor();\n\t\tAssert.state(elementDescriptor != null, \"elementDescriptor is missing\");\n\t\tObject target = Array.newInstance(elementDescriptor.getType(), elements.length);\n\t\tfor (int i = 0; i < elements.length; i++) {\n\t\t\tString sourceElement = elements[i];\n\t\t\tObject targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, elementDescriptor);\n\t\t\tArray.set(target, i, targetElement);\n\t\t}\n\t\treturn target;\n\t}\n\n\tprivate String[] getElements(String source, String delimiter) {\n\t\treturn StringUtils.delimitedListToStringArray(source, Delimiter.NONE.equals(delimiter) ? null : delimiter);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DelimitedStringToCollectionConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalGenericConverter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Converts a {@link Delimiter delimited} String to a Collection.\n *\n * @author Phillip Webb\n */\nfinal class DelimitedStringToCollectionConverter implements ConditionalGenericConverter {\n\n\tprivate final ConversionService conversionService;\n\n\tDelimitedStringToCollectionConverter(ConversionService conversionService) {\n\t\tAssert.notNull(conversionService, \"'conversionService' must not be null\");\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(String.class, Collection.class));\n\t}\n\n\t@Override\n\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn targetType.getElementTypeDescriptor() == null\n\t\t\t\t|| this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert((String) source, sourceType, targetType);\n\t}\n\n\tprivate Object convert(String source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tDelimiter delimiter = targetType.getAnnotation(Delimiter.class);\n\t\tString[] elements = getElements(source, (delimiter != null) ? delimiter.value() : \",\");\n\t\tTypeDescriptor elementDescriptor = targetType.getElementTypeDescriptor();\n\t\tCollection<Object> target = createCollection(targetType, elementDescriptor, elements.length);\n\t\tStream<Object> stream = Arrays.stream(elements).map(String::trim);\n\t\tif (elementDescriptor != null) {\n\t\t\tstream = stream.map((element) -> this.conversionService.convert(element, sourceType, elementDescriptor));\n\t\t}\n\t\tstream.forEach(target::add);\n\t\treturn target;\n\t}\n\n\tprivate Collection<Object> createCollection(TypeDescriptor targetType, @Nullable TypeDescriptor elementDescriptor,\n\t\t\tint length) {\n\t\treturn CollectionFactory.createCollection(targetType.getType(),\n\t\t\t\t(elementDescriptor != null) ? elementDescriptor.getType() : null, length);\n\t}\n\n\tprivate String[] getElements(String source, String delimiter) {\n\t\treturn StringUtils.delimitedListToStringArray(source, Delimiter.NONE.equals(delimiter) ? null : delimiter);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/Delimiter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Declares a field or method parameter should be converted to collection using the\n * specified delimiter.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })\npublic @interface Delimiter {\n\n\t/**\n\t * A delimiter value used to indicate that no delimiter is required and the result\n\t * should be a single element containing the entire string.\n\t */\n\tString NONE = \"\";\n\n\t/**\n\t * The delimiter to use or {@code NONE} if the entire contents should be treated as a\n\t * single element.\n\t * @return the delimiter\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DurationFormat.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.time.Duration;\n\n/**\n * Annotation that can be used to indicate the format to use when converting a\n * {@link Duration}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@Target({ ElementType.FIELD, ElementType.PARAMETER })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DurationFormat {\n\n\t/**\n\t * The duration format style.\n\t * @return the duration format style.\n\t */\n\tDurationStyle value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DurationStyle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Duration format styles.\n *\n * @author Phillip Webb\n * @author Valentine Wu\n * @since 2.0.0\n */\npublic enum DurationStyle {\n\n\t/**\n\t * Simple formatting, for example '1s'.\n\t */\n\tSIMPLE(\"^([+-]?\\\\d+)([a-zA-Z]{0,2})$\") {\n\n\t\t@Override\n\t\tpublic Duration parse(String value, @Nullable ChronoUnit unit) {\n\t\t\ttry {\n\t\t\t\tMatcher matcher = matcher(value);\n\t\t\t\tAssert.state(matcher.matches(), \"Does not match simple duration pattern\");\n\t\t\t\tString suffix = matcher.group(2);\n\t\t\t\treturn (StringUtils.hasLength(suffix) ? Unit.fromSuffix(suffix) : Unit.fromChronoUnit(unit))\n\t\t\t\t\t.parse(matcher.group(1));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"'\" + value + \"' is not a valid simple duration\", ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String print(Duration value, @Nullable ChronoUnit unit) {\n\t\t\treturn Unit.fromChronoUnit(unit).print(value);\n\t\t}\n\n\t},\n\n\t/**\n\t * ISO-8601 formatting.\n\t */\n\tISO8601(\"^[+-]?[pP].*$\") {\n\n\t\t@Override\n\t\tpublic Duration parse(String value, @Nullable ChronoUnit unit) {\n\t\t\ttry {\n\t\t\t\treturn Duration.parse(value);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"'\" + value + \"' is not a valid ISO-8601 duration\", ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String print(Duration value, @Nullable ChronoUnit unit) {\n\t\t\treturn value.toString();\n\t\t}\n\n\t};\n\n\tprivate final Pattern pattern;\n\n\tDurationStyle(String pattern) {\n\t\tthis.pattern = Pattern.compile(pattern);\n\t}\n\n\tprotected final boolean matches(String value) {\n\t\treturn this.pattern.matcher(value).matches();\n\t}\n\n\tprotected final Matcher matcher(String value) {\n\t\treturn this.pattern.matcher(value);\n\t}\n\n\t/**\n\t * Parse the given value to a duration.\n\t * @param value the value to parse\n\t * @return a duration\n\t */\n\tpublic Duration parse(String value) {\n\t\treturn parse(value, null);\n\t}\n\n\t/**\n\t * Parse the given value to a duration.\n\t * @param value the value to parse\n\t * @param unit the duration unit to use if the value doesn't specify one ({@code null}\n\t * will default to ms)\n\t * @return a duration\n\t */\n\tpublic abstract Duration parse(String value, @Nullable ChronoUnit unit);\n\n\t/**\n\t * Print the specified duration.\n\t * @param value the value to print\n\t * @return the printed result\n\t */\n\tpublic String print(Duration value) {\n\t\treturn print(value, null);\n\t}\n\n\t/**\n\t * Print the specified duration using the given unit.\n\t * @param value the value to print\n\t * @param unit the value to use for printing\n\t * @return the printed result\n\t */\n\tpublic abstract String print(Duration value, @Nullable ChronoUnit unit);\n\n\t/**\n\t * Detect the style then parse the value to return a duration.\n\t * @param value the value to parse\n\t * @return the parsed duration\n\t * @throws IllegalArgumentException if the value is not a known style or cannot be\n\t * parsed\n\t */\n\tpublic static Duration detectAndParse(String value) {\n\t\treturn detectAndParse(value, null);\n\t}\n\n\t/**\n\t * Detect the style then parse the value to return a duration.\n\t * @param value the value to parse\n\t * @param unit the duration unit to use if the value doesn't specify one ({@code null}\n\t * will default to ms)\n\t * @return the parsed duration\n\t * @throws IllegalArgumentException if the value is not a known style or cannot be\n\t * parsed\n\t */\n\tpublic static Duration detectAndParse(String value, @Nullable ChronoUnit unit) {\n\t\treturn detect(value).parse(value, unit);\n\t}\n\n\t/**\n\t * Detect the style from the given source value.\n\t * @param value the source value\n\t * @return the duration style\n\t * @throws IllegalArgumentException if the value is not a known style\n\t */\n\tpublic static DurationStyle detect(String value) {\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\tfor (DurationStyle candidate : values()) {\n\t\t\tif (candidate.matches(value)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalArgumentException(\"'\" + value + \"' is not a valid duration\");\n\t}\n\n\t/**\n\t * Units that we support.\n\t */\n\tenum Unit {\n\n\t\t/**\n\t\t * Nanoseconds.\n\t\t */\n\t\tNANOS(ChronoUnit.NANOS, \"ns\", Duration::toNanos),\n\n\t\t/**\n\t\t * Microseconds.\n\t\t */\n\t\tMICROS(ChronoUnit.MICROS, \"us\", (duration) -> duration.toNanos() / 1000L),\n\n\t\t/**\n\t\t * Milliseconds.\n\t\t */\n\t\tMILLIS(ChronoUnit.MILLIS, \"ms\", Duration::toMillis),\n\n\t\t/**\n\t\t * Seconds.\n\t\t */\n\t\tSECONDS(ChronoUnit.SECONDS, \"s\", Duration::getSeconds),\n\n\t\t/**\n\t\t * Minutes.\n\t\t */\n\t\tMINUTES(ChronoUnit.MINUTES, \"m\", Duration::toMinutes),\n\n\t\t/**\n\t\t * Hours.\n\t\t */\n\t\tHOURS(ChronoUnit.HOURS, \"h\", Duration::toHours),\n\n\t\t/**\n\t\t * Days.\n\t\t */\n\t\tDAYS(ChronoUnit.DAYS, \"d\", Duration::toDays);\n\n\t\tprivate final ChronoUnit chronoUnit;\n\n\t\tprivate final String suffix;\n\n\t\tprivate final Function<Duration, Long> longValue;\n\n\t\tUnit(ChronoUnit chronoUnit, String suffix, Function<Duration, Long> toUnit) {\n\t\t\tthis.chronoUnit = chronoUnit;\n\t\t\tthis.suffix = suffix;\n\t\t\tthis.longValue = toUnit;\n\t\t}\n\n\t\tpublic Duration parse(String value) {\n\t\t\treturn Duration.of(Long.parseLong(value), this.chronoUnit);\n\t\t}\n\n\t\tpublic String print(Duration value) {\n\t\t\treturn longValue(value) + this.suffix;\n\t\t}\n\n\t\tpublic long longValue(Duration value) {\n\t\t\treturn this.longValue.apply(value);\n\t\t}\n\n\t\tpublic static Unit fromChronoUnit(@Nullable ChronoUnit chronoUnit) {\n\t\t\tif (chronoUnit == null) {\n\t\t\t\treturn Unit.MILLIS;\n\t\t\t}\n\t\t\tfor (Unit candidate : values()) {\n\t\t\t\tif (candidate.chronoUnit == chronoUnit) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"Unknown unit \" + chronoUnit);\n\t\t}\n\n\t\tpublic static Unit fromSuffix(String suffix) {\n\t\t\tfor (Unit candidate : values()) {\n\t\t\t\tif (candidate.suffix.equalsIgnoreCase(suffix)) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"Unknown unit '\" + suffix + \"'\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DurationToNumberConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link Converter} to convert from a {@link Duration} to a {@link Number}.\n *\n * @author Phillip Webb\n * @see DurationFormat\n * @see DurationUnit\n */\nfinal class DurationToNumberConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Duration.class, Number.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert((Duration) source, getDurationUnit(sourceType), targetType.getObjectType());\n\t}\n\n\tprivate @Nullable ChronoUnit getDurationUnit(TypeDescriptor sourceType) {\n\t\tDurationUnit annotation = sourceType.getAnnotation(DurationUnit.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate Object convert(Duration source, @Nullable ChronoUnit unit, Class<?> type) {\n\t\ttry {\n\t\t\treturn type.getConstructor(String.class)\n\t\t\t\t.newInstance(String.valueOf(DurationStyle.Unit.fromChronoUnit(unit).longValue(source)));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tReflectionUtils.rethrowRuntimeException(ex);\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DurationToStringConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\n\n/**\n * {@link Converter} to convert from a {@link Duration} to a {@link String}.\n *\n * @author Phillip Webb\n * @see DurationFormat\n * @see DurationUnit\n */\nfinal class DurationToStringConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Duration.class, String.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert((Duration) source, getDurationStyle(sourceType), getDurationUnit(sourceType));\n\t}\n\n\tprivate @Nullable ChronoUnit getDurationUnit(TypeDescriptor sourceType) {\n\t\tDurationUnit annotation = sourceType.getAnnotation(DurationUnit.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate @Nullable DurationStyle getDurationStyle(TypeDescriptor sourceType) {\n\t\tDurationFormat annotation = sourceType.getAnnotation(DurationFormat.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate String convert(Duration source, @Nullable DurationStyle style, @Nullable ChronoUnit unit) {\n\t\tstyle = (style != null) ? style : DurationStyle.ISO8601;\n\t\treturn style.print(source, unit);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/DurationUnit.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\n/**\n * Annotation that can be used to change the default unit used when converting a\n * {@link Duration}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@Target({ ElementType.FIELD, ElementType.PARAMETER })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DurationUnit {\n\n\t/**\n\t * The duration unit to use if one is not specified.\n\t * @return the duration unit\n\t */\n\tChronoUnit value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/InetAddressFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.text.ParseException;\nimport java.util.Locale;\n\nimport org.springframework.format.Formatter;\n\n/**\n * {@link Formatter} for {@link InetAddress}.\n *\n * @author Phillip Webb\n */\nfinal class InetAddressFormatter implements Formatter<InetAddress> {\n\n\t@Override\n\tpublic String print(InetAddress object, Locale locale) {\n\t\treturn object.getHostAddress();\n\t}\n\n\t@Override\n\tpublic InetAddress parse(String text, Locale locale) throws ParseException {\n\t\ttry {\n\t\t\treturn InetAddress.getByName(text);\n\t\t}\n\t\tcatch (UnknownHostException ex) {\n\t\t\tthrow new IllegalStateException(\"Unknown host \" + text, ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/InputStreamSourceToByteArrayConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * {@link Converter} to convert from an {@link InputStreamSource} to a {@code byte[]}.\n *\n * @author Phillip Webb\n */\nclass InputStreamSourceToByteArrayConverter implements Converter<InputStreamSource, byte[]> {\n\n\t@Override\n\tpublic byte[] convert(InputStreamSource source) {\n\t\ttry {\n\t\t\treturn FileCopyUtils.copyToByteArray(source.getInputStream());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to read from \" + getName(source), ex);\n\t\t}\n\t}\n\n\tprivate String getName(InputStreamSource source) {\n\t\tOrigin origin = Origin.from(source);\n\t\tif (origin != null) {\n\t\t\treturn origin.toString();\n\t\t}\n\t\tif (source instanceof Resource resource) {\n\t\t\treturn resource.getDescription();\n\t\t}\n\t\treturn \"input stream source\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/IsoOffsetFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.text.ParseException;\nimport java.time.OffsetDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Locale;\n\nimport org.springframework.format.Formatter;\n\n/**\n * A {@link Formatter} for {@link OffsetDateTime} that uses\n * {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME ISO offset formatting}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass IsoOffsetFormatter implements Formatter<OffsetDateTime> {\n\n\t@Override\n\tpublic String print(OffsetDateTime object, Locale locale) {\n\t\treturn DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(object);\n\t}\n\n\t@Override\n\tpublic OffsetDateTime parse(String text, Locale locale) throws ParseException {\n\t\treturn OffsetDateTime.parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/LenientBooleanToEnumConverterFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\n/**\n * Converter to support mapping of YAML style {@code \"false\"} and {@code \"true\"} to enums\n * {@code ON} and {@code OFF}.\n *\n * @author Madhura Bhave\n */\nfinal class LenientBooleanToEnumConverterFactory extends LenientObjectToEnumConverterFactory<Boolean> {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/LenientObjectToEnumConverterFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.ConverterFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * Abstract base class for converting from a type to a {@link java.lang.Enum}.\n *\n * @param <T> the source type\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@SuppressWarnings(\"rawtypes\")\nabstract class LenientObjectToEnumConverterFactory<T> implements ConverterFactory<T, Enum<?>> {\n\n\tprivate static final Map<String, List<String>> ALIASES;\n\n\tstatic {\n\t\tMultiValueMap<String, String> aliases = new LinkedMultiValueMap<>();\n\t\taliases.add(\"true\", \"on\");\n\t\taliases.add(\"false\", \"off\");\n\t\tALIASES = Collections.unmodifiableMap(aliases);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <E extends Enum<?>> Converter<T, E> getConverter(Class<E> targetType) {\n\t\tClass<?> enumType = targetType;\n\t\twhile (enumType != null && !enumType.isEnum()) {\n\t\t\tenumType = enumType.getSuperclass();\n\t\t}\n\t\tAssert.notNull(enumType, () -> \"The target type \" + targetType.getName() + \" does not refer to an enum\");\n\t\treturn new LenientToEnumConverter<>((Class<E>) enumType);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate class LenientToEnumConverter<E extends Enum> implements Converter<T, @Nullable E> {\n\n\t\tprivate final Class<E> enumType;\n\n\t\tLenientToEnumConverter(Class<E> enumType) {\n\t\t\tthis.enumType = enumType;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable E convert(T source) {\n\t\t\tString value = source.toString().trim();\n\t\t\tif (value.isEmpty()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn (E) Enum.valueOf(this.enumType, value);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn findEnum(value);\n\t\t\t}\n\t\t}\n\n\t\tprivate E findEnum(String value) {\n\t\t\tString name = getCanonicalName(value);\n\t\t\tList<String> aliases = ALIASES.getOrDefault(name, Collections.emptyList());\n\t\t\tfor (E candidate : (Set<E>) EnumSet.allOf(this.enumType)) {\n\t\t\t\tString candidateName = getCanonicalName(candidate.name());\n\t\t\t\tif (name.equals(candidateName) || aliases.contains(candidateName)) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"No enum constant \" + this.enumType.getCanonicalName() + \".\" + value);\n\t\t}\n\n\t\tprivate String getCanonicalName(String name) {\n\t\t\tStringBuilder canonicalName = new StringBuilder(name.length());\n\t\t\tname.chars()\n\t\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t\t.map(Character::toLowerCase)\n\t\t\t\t.forEach((c) -> canonicalName.append((char) c));\n\t\t\treturn canonicalName.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/LenientStringToEnumConverterFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\n/**\n * Converts from a String to a {@link java.lang.Enum} with lenient conversion rules.\n * Specifically:\n * <ul>\n * <li>Uses a case insensitive search</li>\n * <li>Does not consider {@code '_'}, {@code '$'} or other special characters</li>\n * <li>Allows mapping of {@code \"false\"} and {@code \"true\"} to enums {@code ON} and\n * {@code OFF}</li>\n * </ul>\n *\n * @author Phillip Webb\n */\nfinal class LenientStringToEnumConverterFactory extends LenientObjectToEnumConverterFactory<String> {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/NumberToDataSizeConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link Converter} to convert from a {@link Number} to a {@link DataSize}.\n *\n * @author Stephane Nicoll\n * @see DataSizeUnit\n */\nfinal class NumberToDataSizeConverter implements GenericConverter {\n\n\tprivate final StringToDataSizeConverter delegate = new StringToDataSizeConverter();\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Number.class, DataSize.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn this.delegate.convert((source != null) ? source.toString() : null, TypeDescriptor.valueOf(String.class),\n\t\t\t\ttargetType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/NumberToDurationConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\n\n/**\n * {@link Converter} to convert from a {@link Number} to a {@link Duration}. Supports\n * {@link Duration#parse(CharSequence)} as well a more readable {@code 10s} form.\n *\n * @author Phillip Webb\n * @see DurationFormat\n * @see DurationUnit\n */\nfinal class NumberToDurationConverter implements GenericConverter {\n\n\tprivate final StringToDurationConverter delegate = new StringToDurationConverter();\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Number.class, Duration.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn this.delegate.convert((source != null) ? source.toString() : null, TypeDescriptor.valueOf(String.class),\n\t\t\t\ttargetType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/NumberToPeriodConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\n\n/**\n * {@link Converter} to convert from a {@link Number} to a {@link Period}. Supports\n * {@link Period#parse(CharSequence)} as well a more readable {@code 10m} form.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @see PeriodFormat\n * @see PeriodUnit\n */\nfinal class NumberToPeriodConverter implements GenericConverter {\n\n\tprivate final StringToPeriodConverter delegate = new StringToPeriodConverter();\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Number.class, Period.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\treturn this.delegate.convert((source != null) ? source.toString() : null, TypeDescriptor.valueOf(String.class),\n\t\t\t\ttargetType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/PeriodFormat.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.time.Period;\n\n/**\n * Annotation that can be used to indicate the format to use when converting a\n * {@link Period}.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @since 2.3.0\n */\n@Target({ ElementType.FIELD, ElementType.PARAMETER })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface PeriodFormat {\n\n\t/**\n\t * The {@link Period} format style.\n\t * @return the period format style.\n\t */\n\tPeriodStyle value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/PeriodStyle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A standard set of {@link Period} units.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @author Valentine Wu\n * @since 2.3.0\n * @see Period\n */\npublic enum PeriodStyle {\n\n\t/**\n\t * Simple formatting, for example '1d'.\n\t */\n\tSIMPLE(\"^\" + \"(?:([-+]?[0-9]+)Y)?\" + \"(?:([-+]?[0-9]+)M)?\" + \"(?:([-+]?[0-9]+)W)?\" + \"(?:([-+]?[0-9]+)D)?\" + \"$\",\n\t\t\tPattern.CASE_INSENSITIVE) {\n\n\t\t@Override\n\t\tpublic Period parse(String value, @Nullable ChronoUnit unit) {\n\t\t\ttry {\n\t\t\t\tif (NUMERIC.matcher(value).matches()) {\n\t\t\t\t\treturn Unit.fromChronoUnit(unit).parse(value);\n\t\t\t\t}\n\t\t\t\tMatcher matcher = matcher(value);\n\t\t\t\tAssert.state(matcher.matches(), \"Does not match simple period pattern\");\n\t\t\t\tAssert.isTrue(hasAtLeastOneGroupValue(matcher), () -> \"'\" + value + \"' is not a valid simple period\");\n\t\t\t\tint years = parseInt(matcher, 1);\n\t\t\t\tint months = parseInt(matcher, 2);\n\t\t\t\tint weeks = parseInt(matcher, 3);\n\t\t\t\tint days = parseInt(matcher, 4);\n\t\t\t\treturn Period.of(years, months, Math.addExact(Math.multiplyExact(weeks, 7), days));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"'\" + value + \"' is not a valid simple period\", ex);\n\t\t\t}\n\t\t}\n\n\t\tboolean hasAtLeastOneGroupValue(Matcher matcher) {\n\t\t\tfor (int i = 0; i < matcher.groupCount(); i++) {\n\t\t\t\tif (matcher.group(i + 1) != null) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate int parseInt(Matcher matcher, int group) {\n\t\t\tString value = matcher.group(group);\n\t\t\treturn (value != null) ? Integer.parseInt(value) : 0;\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matches(String value) {\n\t\t\treturn NUMERIC.matcher(value).matches() || matcher(value).matches();\n\t\t}\n\n\t\t@Override\n\t\tpublic String print(Period value, @Nullable ChronoUnit unit) {\n\t\t\tif (value.isZero()) {\n\t\t\t\treturn Unit.fromChronoUnit(unit).print(value);\n\t\t\t}\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tappend(result, value, Unit.YEARS);\n\t\t\tappend(result, value, Unit.MONTHS);\n\t\t\tappend(result, value, Unit.DAYS);\n\t\t\treturn result.toString();\n\t\t}\n\n\t\tprivate void append(StringBuilder result, Period value, Unit unit) {\n\t\t\tif (!unit.isZero(value)) {\n\t\t\t\tresult.append(unit.print(value));\n\t\t\t}\n\t\t}\n\n\t},\n\n\t/**\n\t * ISO-8601 formatting.\n\t */\n\tISO8601(\"^[+-]?P.*$\", Pattern.CASE_INSENSITIVE) {\n\n\t\t@Override\n\t\tpublic Period parse(String value, @Nullable ChronoUnit unit) {\n\t\t\ttry {\n\t\t\t\treturn Period.parse(value);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"'\" + value + \"' is not a valid ISO-8601 period\", ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String print(Period value, @Nullable ChronoUnit unit) {\n\t\t\treturn value.toString();\n\t\t}\n\n\t};\n\n\tprivate static final Pattern NUMERIC = Pattern.compile(\"^[-+]?[0-9]+$\");\n\n\tprivate final Pattern pattern;\n\n\tPeriodStyle(String pattern, int flags) {\n\t\tthis.pattern = Pattern.compile(pattern, flags);\n\t}\n\n\tprotected boolean matches(String value) {\n\t\treturn this.pattern.matcher(value).matches();\n\t}\n\n\tprotected final Matcher matcher(String value) {\n\t\treturn this.pattern.matcher(value);\n\t}\n\n\t/**\n\t * Parse the given value to a Period.\n\t * @param value the value to parse\n\t * @return a period\n\t */\n\tpublic Period parse(String value) {\n\t\treturn parse(value, null);\n\t}\n\n\t/**\n\t * Parse the given value to a period.\n\t * @param value the value to parse\n\t * @param unit the period unit to use if the value doesn't specify one ({@code null}\n\t * will default to d)\n\t * @return a period\n\t */\n\tpublic abstract Period parse(String value, @Nullable ChronoUnit unit);\n\n\t/**\n\t * Print the specified period.\n\t * @param value the value to print\n\t * @return the printed result\n\t */\n\tpublic String print(Period value) {\n\t\treturn print(value, null);\n\t}\n\n\t/**\n\t * Print the specified period using the given unit.\n\t * @param value the value to print\n\t * @param unit the value to use for printing\n\t * @return the printed result\n\t */\n\tpublic abstract String print(Period value, @Nullable ChronoUnit unit);\n\n\t/**\n\t * Detect the style then parse the value to return a period.\n\t * @param value the value to parse\n\t * @return the parsed period\n\t * @throws IllegalArgumentException if the value is not a known style or cannot be\n\t * parsed\n\t */\n\tpublic static Period detectAndParse(String value) {\n\t\treturn detectAndParse(value, null);\n\t}\n\n\t/**\n\t * Detect the style then parse the value to return a period.\n\t * @param value the value to parse\n\t * @param unit the period unit to use if the value doesn't specify one ({@code null}\n\t * will default to ms)\n\t * @return the parsed period\n\t * @throws IllegalArgumentException if the value is not a known style or cannot be\n\t * parsed\n\t */\n\tpublic static Period detectAndParse(String value, @Nullable ChronoUnit unit) {\n\t\treturn detect(value).parse(value, unit);\n\t}\n\n\t/**\n\t * Detect the style from the given source value.\n\t * @param value the source value\n\t * @return the period style\n\t * @throws IllegalArgumentException if the value is not a known style\n\t */\n\tpublic static PeriodStyle detect(String value) {\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\tfor (PeriodStyle candidate : values()) {\n\t\t\tif (candidate.matches(value)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalArgumentException(\"'\" + value + \"' is not a valid period\");\n\t}\n\n\tprivate enum Unit {\n\n\t\t/**\n\t\t * Days, represented by suffix {@code d}.\n\t\t */\n\t\tDAYS(ChronoUnit.DAYS, \"d\", Period::getDays, Period::ofDays),\n\n\t\t/**\n\t\t * Weeks, represented by suffix {@code w}.\n\t\t */\n\t\tWEEKS(ChronoUnit.WEEKS, \"w\", null, Period::ofWeeks),\n\n\t\t/**\n\t\t * Months, represented by suffix {@code m}.\n\t\t */\n\t\tMONTHS(ChronoUnit.MONTHS, \"m\", Period::getMonths, Period::ofMonths),\n\n\t\t/**\n\t\t * Years, represented by suffix {@code y}.\n\t\t */\n\t\tYEARS(ChronoUnit.YEARS, \"y\", Period::getYears, Period::ofYears);\n\n\t\tprivate final ChronoUnit chronoUnit;\n\n\t\tprivate final String suffix;\n\n\t\tprivate final @Nullable Function<Period, Integer> intValue;\n\n\t\tprivate final Function<Integer, Period> factory;\n\n\t\tUnit(ChronoUnit chronoUnit, String suffix, @Nullable Function<Period, Integer> intValue,\n\t\t\t\tFunction<Integer, Period> factory) {\n\t\t\tthis.chronoUnit = chronoUnit;\n\t\t\tthis.suffix = suffix;\n\t\t\tthis.intValue = intValue;\n\t\t\tthis.factory = factory;\n\t\t}\n\n\t\tprivate Period parse(String value) {\n\t\t\treturn this.factory.apply(Integer.parseInt(value));\n\t\t}\n\n\t\tprivate String print(Period value) {\n\t\t\treturn intValue(value) + this.suffix;\n\t\t}\n\n\t\tprivate boolean isZero(Period value) {\n\t\t\treturn intValue(value) == 0;\n\t\t}\n\n\t\tprivate int intValue(Period value) {\n\t\t\tAssert.state(this.intValue != null, () -> \"intValue cannot be extracted from \" + name());\n\t\t\treturn this.intValue.apply(value);\n\t\t}\n\n\t\tprivate static Unit fromChronoUnit(@Nullable ChronoUnit chronoUnit) {\n\t\t\tif (chronoUnit == null) {\n\t\t\t\treturn Unit.DAYS;\n\t\t\t}\n\t\t\tfor (Unit candidate : values()) {\n\t\t\t\tif (candidate.chronoUnit == chronoUnit) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"Unsupported unit \" + chronoUnit);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/PeriodToStringConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link Converter} to convert from a {@link Period} to a {@link String}.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @see PeriodFormat\n * @see PeriodUnit\n */\nfinal class PeriodToStringConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(Period.class, String.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (ObjectUtils.isEmpty(source)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert((Period) source, getPeriodStyle(sourceType), getPeriodUnit(sourceType));\n\t}\n\n\tprivate @Nullable PeriodStyle getPeriodStyle(TypeDescriptor sourceType) {\n\t\tPeriodFormat annotation = sourceType.getAnnotation(PeriodFormat.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate String convert(Period source, @Nullable PeriodStyle style, @Nullable ChronoUnit unit) {\n\t\tstyle = (style != null) ? style : PeriodStyle.ISO8601;\n\t\treturn style.print(source, unit);\n\t}\n\n\tprivate @Nullable ChronoUnit getPeriodUnit(TypeDescriptor sourceType) {\n\t\tPeriodUnit annotation = sourceType.getAnnotation(PeriodUnit.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/PeriodUnit.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\n\n/**\n * Annotation that can be used to change the default unit used when converting a\n * {@link Period}.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @since 2.3.0\n */\n@Target({ ElementType.FIELD, ElementType.PARAMETER })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface PeriodUnit {\n\n\t/**\n\t * The Period unit to use if one is not specified.\n\t * @return the Period unit\n\t */\n\tChronoUnit value();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/StringToDataSizeConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\n/**\n * {@link Converter} to convert from a {@link String} to a {@link DataSize}. Supports\n * {@link DataSize#parse(CharSequence)}.\n *\n * @author Stephane Nicoll\n * @see DataSizeUnit\n */\nfinal class StringToDataSizeConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(String.class, DataSize.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (ObjectUtils.isEmpty(source)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert(source.toString(), getDataUnit(targetType));\n\t}\n\n\tprivate @Nullable DataUnit getDataUnit(TypeDescriptor targetType) {\n\t\tDataSizeUnit annotation = targetType.getAnnotation(DataSizeUnit.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate DataSize convert(String source, @Nullable DataUnit unit) {\n\t\treturn DataSize.parse(source, unit);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/StringToDurationConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link Converter} to convert from a {@link String} to a {@link Duration}. Supports\n * {@link Duration#parse(CharSequence)} as well a more readable {@code 10s} form.\n *\n * @author Phillip Webb\n * @see DurationFormat\n * @see DurationUnit\n */\nfinal class StringToDurationConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(String.class, Duration.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (ObjectUtils.isEmpty(source)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert(source.toString(), getStyle(targetType), getDurationUnit(targetType));\n\t}\n\n\tprivate @Nullable DurationStyle getStyle(TypeDescriptor targetType) {\n\t\tDurationFormat annotation = targetType.getAnnotation(DurationFormat.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate @Nullable ChronoUnit getDurationUnit(TypeDescriptor targetType) {\n\t\tDurationUnit annotation = targetType.getAnnotation(DurationUnit.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate Duration convert(String source, @Nullable DurationStyle style, @Nullable ChronoUnit unit) {\n\t\tstyle = (style != null) ? style : DurationStyle.detect(source);\n\t\treturn style.parse(source, unit);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/StringToFileConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link Converter} to convert from a {@link String} to a {@link File}. Supports basic\n * file conversion as well as file URLs.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass StringToFileConverter implements Converter<String, File> {\n\n\t@Override\n\tpublic File convert(String source) {\n\t\treturn getFile(ApplicationResourceLoader.get().getResource(source));\n\t}\n\n\tprivate File getFile(Resource resource) {\n\t\ttry {\n\t\t\treturn resource.getFile();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Could not retrieve file for \" + resource + \": \" + ex.getMessage());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/StringToPeriodConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link Converter} to convert from a {@link String} to a {@link Period}. Supports\n * {@link Period#parse(CharSequence)} as well a more readable form.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @see PeriodFormat\n * @see PeriodUnit\n */\nfinal class StringToPeriodConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<GenericConverter.ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new GenericConverter.ConvertiblePair(String.class, Period.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (ObjectUtils.isEmpty(source)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn convert(source.toString(), getStyle(targetType), getPeriodUnit(targetType));\n\t}\n\n\tprivate @Nullable PeriodStyle getStyle(TypeDescriptor targetType) {\n\t\tPeriodFormat annotation = targetType.getAnnotation(PeriodFormat.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate @Nullable ChronoUnit getPeriodUnit(TypeDescriptor targetType) {\n\t\tPeriodUnit annotation = targetType.getAnnotation(PeriodUnit.class);\n\t\treturn (annotation != null) ? annotation.value() : null;\n\t}\n\n\tprivate Period convert(String source, @Nullable PeriodStyle style, @Nullable ChronoUnit unit) {\n\t\tstyle = (style != null) ? style : PeriodStyle.detect(source);\n\t\treturn style.parse(source, unit);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/convert/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for type conversion.\n */\n@NullMarked\npackage org.springframework.boot.convert;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/AbstractFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * Abstract base class for most {@code FailureAnalyzer} implementations.\n *\n * @param <T> the type of exception to analyze\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 1.4.0\n */\npublic abstract class AbstractFailureAnalyzer<T extends Throwable> implements FailureAnalyzer {\n\n\t@Override\n\tpublic @Nullable FailureAnalysis analyze(Throwable failure) {\n\t\tT cause = findCause(failure, getCauseType());\n\t\treturn (cause != null) ? analyze(failure, cause) : null;\n\t}\n\n\t/**\n\t * Returns an analysis of the given {@code rootFailure}, or {@code null} if no\n\t * analysis was possible.\n\t * @param rootFailure the root failure passed to the analyzer\n\t * @param cause the actual found cause\n\t * @return the analysis or {@code null}\n\t */\n\tprotected abstract @Nullable FailureAnalysis analyze(Throwable rootFailure, T cause);\n\n\t/**\n\t * Return the cause type being handled by the analyzer. By default the class generic\n\t * is used.\n\t * @return the cause type\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprotected Class<? extends T> getCauseType() {\n\t\tClass<? extends T> type = (Class<? extends T>) ResolvableType\n\t\t\t.forClass(AbstractFailureAnalyzer.class, getClass())\n\t\t\t.resolveGeneric();\n\t\tAssert.state(type != null, \"Unable to resolve generic\");\n\t\treturn type;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected final <E extends Throwable> @Nullable E findCause(@Nullable Throwable failure, Class<E> type) {\n\t\twhile (failure != null) {\n\t\t\tif (type.isInstance(failure)) {\n\t\t\t\treturn (E) failure;\n\t\t\t}\n\t\t\tfailure = failure.getCause();\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalysis.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * The result of analyzing a failure.\n *\n * @author Andy Wilkinson\n * @since 1.4.0\n */\npublic class FailureAnalysis {\n\n\tprivate final String description;\n\n\tprivate final @Nullable String action;\n\n\tprivate final Throwable cause;\n\n\t/**\n\t * Creates a new {@code FailureAnalysis} with the given {@code description} and\n\t * {@code action}, if any, that the user should take to address the problem. The\n\t * failure had the given underlying {@code cause}.\n\t * @param description the description\n\t * @param action the action\n\t * @param cause the cause\n\t */\n\tpublic FailureAnalysis(@Nullable String description, @Nullable String action, Throwable cause) {\n\t\tthis.description = (description != null) ? description : \"\";\n\t\tthis.action = action;\n\t\tthis.cause = cause;\n\t}\n\n\t/**\n\t * Returns a description of the failure.\n\t * @return the description\n\t */\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\t/**\n\t * Returns the action, if any, to be taken to address the failure.\n\t * @return the action or {@code null}\n\t */\n\tpublic @Nullable String getAction() {\n\t\treturn this.action;\n\t}\n\n\t/**\n\t * Returns the cause of the failure.\n\t * @return the cause\n\t */\n\tpublic Throwable getCause() {\n\t\treturn this.cause;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalysisReporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\n/**\n * Reports a {@code FailureAnalysis} to the user.\n *\n * @author Andy Wilkinson\n * @since 1.4.0\n */\n@FunctionalInterface\npublic interface FailureAnalysisReporter {\n\n\t/**\n\t * Reports the given {@code failureAnalysis} to the user.\n\t * @param analysis the analysis\n\t */\n\tvoid report(FailureAnalysis analysis);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzedException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link RuntimeException} that includes a {@link FailureAnalysis}.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic class FailureAnalyzedException extends RuntimeException {\n\n\tprivate final @Nullable String action;\n\n\t/**\n\t * Create a new {@link FailureAnalyzedException} instance.\n\t * @param description the {@link FailureAnalysis} description\n\t * @param action the {@link FailureAnalysis} action\n\t */\n\tpublic FailureAnalyzedException(String description, @Nullable String action) {\n\t\tsuper(description);\n\t\tthis.action = action;\n\t}\n\n\t/**\n\t * Create a new {@link FailureAnalyzedException} instance.\n\t * @param description the {@link FailureAnalysis} description\n\t * @param action the {@link FailureAnalysis} action\n\t * @param cause the cause of the exception\n\t */\n\tpublic FailureAnalyzedException(String description, @Nullable String action, Throwable cause) {\n\t\tsuper(description, cause);\n\t\tthis.action = action;\n\t}\n\n\t/**\n\t * Return the {@link FailureAnalysis} to use for this exception.\n\t * @return the failure analysis\n\t */\n\tpublic FailureAnalysis analysis() {\n\t\treturn new FailureAnalysis(getMessage(), this.action, this);\n\t}\n\n\tstatic @Nullable FailureAnalysis analyze(Throwable failure) {\n\t\twhile (failure != null) {\n\t\t\tif (failure instanceof FailureAnalyzedException failureAnalyzedException) {\n\t\t\t\treturn failureAnalyzedException.analysis();\n\t\t\t}\n\t\t\tfailure = failure.getCause();\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@code FailureAnalyzer} is used to analyze a failure and provide diagnostic\n * information that can be displayed to the user.\n *\n * @author Andy Wilkinson\n * @since 1.4.0\n */\n@FunctionalInterface\npublic interface FailureAnalyzer {\n\n\t/**\n\t * Returns an analysis of the given {@code failure}, or {@code null} if no analysis\n\t * was possible.\n\t * @param failure the failure\n\t * @return the analysis or {@code null}\n\t */\n\t@Nullable FailureAnalysis analyze(Throwable failure);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.SpringBootExceptionReporter;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.core.io.support.SpringFactoriesLoader.FailureHandler;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Utility to trigger {@link FailureAnalyzer} and {@link FailureAnalysisReporter}\n * instances loaded from {@code spring.factories}.\n * <p>\n * A {@code FailureAnalyzer} that requires access to the {@link BeanFactory} or\n * {@link Environment} in order to perform its analysis can implement a constructor that\n * accepts arguments of one or both of these types.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nfinal class FailureAnalyzers implements SpringBootExceptionReporter {\n\n\tprivate static final Log logger = LogFactory.getLog(FailureAnalyzers.class);\n\n\tprivate final SpringFactoriesLoader springFactoriesLoader;\n\n\tprivate final List<FailureAnalyzer> analyzers;\n\n\tpublic FailureAnalyzers(@Nullable ConfigurableApplicationContext context) {\n\t\tthis(context,\n\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation((context != null) ? context.getClassLoader() : null));\n\t}\n\n\tFailureAnalyzers(@Nullable ConfigurableApplicationContext context, SpringFactoriesLoader springFactoriesLoader) {\n\t\tthis.springFactoriesLoader = springFactoriesLoader;\n\t\tthis.analyzers = loadFailureAnalyzers(context, this.springFactoriesLoader);\n\t}\n\n\tprivate static List<FailureAnalyzer> loadFailureAnalyzers(@Nullable ConfigurableApplicationContext context,\n\t\t\tSpringFactoriesLoader springFactoriesLoader) {\n\t\tList<FailureAnalyzer> analyzers = new ArrayList<>(springFactoriesLoader.load(FailureAnalyzer.class,\n\t\t\t\tgetArgumentResolver(context), FailureHandler.logging(logger)));\n\t\tanalyzers.add(FailureAnalyzedException::analyze);\n\t\treturn Collections.unmodifiableList(analyzers);\n\t}\n\n\tprivate static @Nullable ArgumentResolver getArgumentResolver(@Nullable ConfigurableApplicationContext context) {\n\t\tif (context == null) {\n\t\t\treturn null;\n\t\t}\n\t\tArgumentResolver argumentResolver = ArgumentResolver.of(BeanFactory.class, context.getBeanFactory());\n\t\targumentResolver = argumentResolver.and(Environment.class, context.getEnvironment());\n\t\treturn argumentResolver;\n\t}\n\n\t@Override\n\tpublic boolean reportException(Throwable failure) {\n\t\tFailureAnalysis analysis = analyze(failure, this.analyzers);\n\t\treturn report(analysis);\n\t}\n\n\tprivate @Nullable FailureAnalysis analyze(Throwable failure, List<FailureAnalyzer> analyzers) {\n\t\tfor (FailureAnalyzer analyzer : analyzers) {\n\t\t\ttry {\n\t\t\t\tFailureAnalysis analysis = analyzer.analyze(failure);\n\t\t\t\tif (analysis != null) {\n\t\t\t\t\treturn analysis;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tlogger.trace(LogMessage.format(\"FailureAnalyzer %s failed\", analyzer), ex);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean report(@Nullable FailureAnalysis analysis) {\n\t\tList<FailureAnalysisReporter> reporters = this.springFactoriesLoader.load(FailureAnalysisReporter.class);\n\t\tif (analysis == null || reporters.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (FailureAnalysisReporter reporter : reporters) {\n\t\t\treporter.report(analysis);\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/LoggingFailureAnalysisReporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link FailureAnalysisReporter} that logs the failure analysis.\n *\n * @author Andy Wilkinson\n * @since 1.4.0\n */\npublic final class LoggingFailureAnalysisReporter implements FailureAnalysisReporter {\n\n\tprivate static final Log logger = LogFactory.getLog(LoggingFailureAnalysisReporter.class);\n\n\t@Override\n\tpublic void report(FailureAnalysis failureAnalysis) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Application failed to start due to an exception\", failureAnalysis.getCause());\n\t\t}\n\t\tif (logger.isErrorEnabled()) {\n\t\t\tlogger.error(buildMessage(failureAnalysis));\n\t\t}\n\t}\n\n\tprivate String buildMessage(FailureAnalysis failureAnalysis) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tbuilder.append(String.format(\"%n%n\"));\n\t\tbuilder.append(String.format(\"***************************%n\"));\n\t\tbuilder.append(String.format(\"APPLICATION FAILED TO START%n\"));\n\t\tbuilder.append(String.format(\"***************************%n%n\"));\n\t\tbuilder.append(String.format(\"Description:%n%n\"));\n\t\tbuilder.append(String.format(\"%s%n\", failureAnalysis.getDescription()));\n\t\tif (StringUtils.hasText(failureAnalysis.getAction())) {\n\t\t\tbuilder.append(String.format(\"%nAction:%n%n\"));\n\t\t\tbuilder.append(String.format(\"%s%n\", failureAnalysis.getAction()));\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/AbstractInjectionFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanInstantiationException;\nimport org.springframework.beans.factory.InjectionPoint;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Abstract base class for a {@link FailureAnalyzer} that handles some kind of injection\n * failure.\n *\n * @param <T> the type of exception to analyze\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 1.4.1\n */\npublic abstract class AbstractInjectionFailureAnalyzer<T extends Throwable> extends AbstractFailureAnalyzer<T> {\n\n\t@Override\n\tprotected final @Nullable FailureAnalysis analyze(Throwable rootFailure, T cause) {\n\t\treturn analyze(rootFailure, cause, getDescription(rootFailure));\n\t}\n\n\tprivate @Nullable String getDescription(Throwable rootFailure) {\n\t\tUnsatisfiedDependencyException unsatisfiedDependency = findMostNestedCause(rootFailure,\n\t\t\t\tUnsatisfiedDependencyException.class);\n\t\tif (unsatisfiedDependency != null) {\n\t\t\treturn getDescription(unsatisfiedDependency);\n\t\t}\n\t\tBeanInstantiationException beanInstantiationException = findMostNestedCause(rootFailure,\n\t\t\t\tBeanInstantiationException.class);\n\t\tif (beanInstantiationException != null) {\n\t\t\treturn getDescription(beanInstantiationException);\n\t\t}\n\t\treturn null;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <C extends Exception> @Nullable C findMostNestedCause(Throwable root, Class<C> type) {\n\t\tThrowable candidate = root;\n\t\tC result = null;\n\t\twhile (candidate != null) {\n\t\t\tif (type.isAssignableFrom(candidate.getClass())) {\n\t\t\t\tresult = (C) candidate;\n\t\t\t}\n\t\t\tcandidate = candidate.getCause();\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate @Nullable String getDescription(UnsatisfiedDependencyException ex) {\n\t\tInjectionPoint injectionPoint = ex.getInjectionPoint();\n\t\tif (injectionPoint != null) {\n\t\t\tif (injectionPoint.getField() != null) {\n\t\t\t\treturn String.format(\"Field %s in %s\", injectionPoint.getField().getName(),\n\t\t\t\t\t\tinjectionPoint.getField().getDeclaringClass().getName());\n\t\t\t}\n\t\t\tif (injectionPoint.getMethodParameter() != null) {\n\t\t\t\tif (injectionPoint.getMethodParameter().getConstructor() != null) {\n\t\t\t\t\treturn String.format(\"Parameter %d of constructor in %s\",\n\t\t\t\t\t\t\tinjectionPoint.getMethodParameter().getParameterIndex(),\n\t\t\t\t\t\t\tinjectionPoint.getMethodParameter().getDeclaringClass().getName());\n\t\t\t\t}\n\t\t\t\tMethod method = injectionPoint.getMethodParameter().getMethod();\n\t\t\t\tAssert.state(method != null, \"Neither constructor nor method is available\");\n\t\t\t\treturn String.format(\"Parameter %d of method %s in %s\",\n\t\t\t\t\t\tinjectionPoint.getMethodParameter().getParameterIndex(), method.getName(),\n\t\t\t\t\t\tinjectionPoint.getMethodParameter().getDeclaringClass().getName());\n\t\t\t}\n\t\t}\n\t\treturn ex.getResourceDescription();\n\t}\n\n\tprivate String getDescription(BeanInstantiationException ex) {\n\t\tif (ex.getConstructingMethod() != null) {\n\t\t\treturn String.format(\"Method %s in %s\", ex.getConstructingMethod().getName(),\n\t\t\t\t\tex.getConstructingMethod().getDeclaringClass().getName());\n\t\t}\n\t\tif (ex.getConstructor() != null) {\n\t\t\treturn String.format(\"Constructor in %s\",\n\t\t\t\t\tClassUtils.getUserClass(ex.getConstructor().getDeclaringClass()).getName());\n\t\t}\n\t\treturn ex.getBeanClass().getName();\n\t}\n\n\t/**\n\t * Returns an analysis of the given {@code rootFailure}, or {@code null} if no\n\t * analysis was possible.\n\t * @param rootFailure the root failure passed to the analyzer\n\t * @param cause the actual found cause\n\t * @param description the description of the injection point or {@code null}\n\t * @return the analysis or {@code null}\n\t */\n\tprotected abstract @Nullable FailureAnalysis analyze(Throwable rootFailure, T cause, @Nullable String description);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/AotInitializerNotFoundFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.springframework.boot.AotInitializerNotFoundException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a\n * {@link AotInitializerNotFoundException}.\n *\n * @author Moritz Halbritter\n */\nclass AotInitializerNotFoundFailureAnalyzer extends AbstractFailureAnalyzer<AotInitializerNotFoundException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, AotInitializerNotFoundException cause) {\n\t\treturn new FailureAnalysis(cause.getMessage(), \"Consider the following:\\n\"\n\t\t\t\t+ \"\\tDid you build the application with enabled AOT processing?\\n\"\n\t\t\t\t+ \"\\tIs the main class %s correct?\\n\".formatted(cause.getMainClass().getName())\n\t\t\t\t+ \"\\tIf you want to run the application in regular mode, remove the system property 'spring.aot.enabled'\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.InjectionPoint;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a\n * {@link BeanCurrentlyInCreationException}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass BeanCurrentlyInCreationFailureAnalyzer extends AbstractFailureAnalyzer<BeanCurrentlyInCreationException> {\n\n\tprivate final @Nullable AbstractAutowireCapableBeanFactory beanFactory;\n\n\tBeanCurrentlyInCreationFailureAnalyzer(BeanFactory beanFactory) {\n\t\tif (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {\n\t\t\tthis.beanFactory = autowireCapableBeanFactory;\n\t\t}\n\t\telse {\n\t\t\tthis.beanFactory = null;\n\t\t}\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, BeanCurrentlyInCreationException cause) {\n\t\tDependencyCycle dependencyCycle = findCycle(rootFailure);\n\t\tif (dependencyCycle == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new FailureAnalysis(buildMessage(dependencyCycle), action(), cause);\n\t}\n\n\tprivate String action() {\n\t\tif (this.beanFactory != null && this.beanFactory.isAllowCircularReferences()) {\n\t\t\treturn \"Despite circular references being allowed, the dependency cycle between beans could not be \"\n\t\t\t\t\t+ \"broken. Update your application to remove the dependency cycle.\";\n\t\t}\n\t\treturn \"Relying upon circular references is discouraged and they are prohibited by default. \"\n\t\t\t\t+ \"Update your application to remove the dependency cycle between beans. \"\n\t\t\t\t+ \"As a last resort, it may be possible to break the cycle automatically by setting \"\n\t\t\t\t+ \"spring.main.allow-circular-references to true.\";\n\t}\n\n\tprivate @Nullable DependencyCycle findCycle(Throwable rootFailure) {\n\t\tList<BeanInCycle> beansInCycle = new ArrayList<>();\n\t\tThrowable candidate = rootFailure;\n\t\tint cycleStart = -1;\n\t\twhile (candidate != null) {\n\t\t\tBeanInCycle beanInCycle = BeanInCycle.get(candidate);\n\t\t\tif (beanInCycle != null) {\n\t\t\t\tint index = beansInCycle.indexOf(beanInCycle);\n\t\t\t\tif (index == -1) {\n\t\t\t\t\tbeansInCycle.add(beanInCycle);\n\t\t\t\t}\n\t\t\t\tcycleStart = (cycleStart != -1) ? cycleStart : index;\n\t\t\t}\n\t\t\tcandidate = candidate.getCause();\n\t\t}\n\t\tif (cycleStart == -1) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new DependencyCycle(beansInCycle, cycleStart);\n\t}\n\n\tprivate String buildMessage(DependencyCycle dependencyCycle) {\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\n\t\t\t\tString.format(\"The dependencies of some of the beans in the application context form a cycle:%n%n\"));\n\t\tList<BeanInCycle> beansInCycle = dependencyCycle.getBeansInCycle();\n\t\tboolean singleBean = beansInCycle.size() == 1;\n\t\tint cycleStart = dependencyCycle.getCycleStart();\n\t\tfor (int i = 0; i < beansInCycle.size(); i++) {\n\t\t\tBeanInCycle beanInCycle = beansInCycle.get(i);\n\t\t\tif (i == cycleStart) {\n\t\t\t\tmessage.append(String.format(singleBean ? \"┌──->──┐%n\" : \"┌─────┐%n\"));\n\t\t\t}\n\t\t\telse if (i > 0) {\n\t\t\t\tString leftSide = (i < cycleStart) ? \" \" : \"↑\";\n\t\t\t\tmessage.append(String.format(\"%s     ↓%n\", leftSide));\n\t\t\t}\n\t\t\tString leftSide = (i < cycleStart) ? \" \" : \"|\";\n\t\t\tmessage.append(String.format(\"%s  %s%n\", leftSide, beanInCycle));\n\t\t}\n\t\tmessage.append(String.format(singleBean ? \"└──<-──┘%n\" : \"└─────┘%n\"));\n\t\treturn message.toString();\n\t}\n\n\tprivate static final class DependencyCycle {\n\n\t\tprivate final List<BeanInCycle> beansInCycle;\n\n\t\tprivate final int cycleStart;\n\n\t\tprivate DependencyCycle(List<BeanInCycle> beansInCycle, int cycleStart) {\n\t\t\tthis.beansInCycle = beansInCycle;\n\t\t\tthis.cycleStart = cycleStart;\n\t\t}\n\n\t\tList<BeanInCycle> getBeansInCycle() {\n\t\t\treturn this.beansInCycle;\n\t\t}\n\n\t\tint getCycleStart() {\n\t\t\treturn this.cycleStart;\n\t\t}\n\n\t}\n\n\tprivate static final class BeanInCycle {\n\n\t\tprivate final @Nullable String name;\n\n\t\tprivate final String description;\n\n\t\tprivate BeanInCycle(BeanCreationException ex) {\n\t\t\tthis.name = ex.getBeanName();\n\t\t\tthis.description = determineDescription(ex);\n\t\t}\n\n\t\tprivate String determineDescription(BeanCreationException ex) {\n\t\t\tif (StringUtils.hasText(ex.getResourceDescription())) {\n\t\t\t\treturn String.format(\" defined in %s\", ex.getResourceDescription());\n\t\t\t}\n\t\t\tInjectionPoint failedInjectionPoint = findFailedInjectionPoint(ex);\n\t\t\tif (failedInjectionPoint != null && failedInjectionPoint.getField() != null) {\n\t\t\t\treturn String.format(\" (field %s)\", failedInjectionPoint.getField());\n\t\t\t}\n\t\t\treturn \"\";\n\t\t}\n\n\t\tprivate @Nullable InjectionPoint findFailedInjectionPoint(BeanCreationException ex) {\n\t\t\tif (ex instanceof UnsatisfiedDependencyException unsatisfiedDependencyException) {\n\t\t\t\treturn unsatisfiedDependencyException.getInjectionPoint();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn Objects.equals(this.name, ((BeanInCycle) obj).name);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Objects.hashCode(this.name);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name + this.description;\n\t\t}\n\n\t\tstatic @Nullable BeanInCycle get(Throwable ex) {\n\t\t\tif (ex instanceof BeanCreationException beanCreationException) {\n\t\t\t\treturn get(beanCreationException);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate static @Nullable BeanInCycle get(BeanCreationException ex) {\n\t\t\tif (StringUtils.hasText(ex.getBeanName())) {\n\t\t\t\treturn new BeanInCycle(ex);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\nimport org.springframework.beans.factory.support.BeanDefinitionOverrideException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a\n * {@link BeanDefinitionOverrideException}.\n *\n * @author Andy Wilkinson\n */\nclass BeanDefinitionOverrideFailureAnalyzer extends AbstractFailureAnalyzer<BeanDefinitionOverrideException> {\n\n\tprivate static final String ACTION = \"Consider renaming one of the beans or enabling \"\n\t\t\t+ \"overriding by setting spring.main.allow-bean-definition-overriding=true\";\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, BeanDefinitionOverrideException cause) {\n\t\treturn new FailureAnalysis(getDescription(cause), ACTION, cause);\n\t}\n\n\tprivate String getDescription(BeanDefinitionOverrideException ex) {\n\t\tStringWriter description = new StringWriter();\n\t\tPrintWriter printer = new PrintWriter(description);\n\t\tprinter.printf(\"The bean '%s'\", ex.getBeanName());\n\t\tif (ex.getBeanDefinition().getResourceDescription() != null) {\n\t\t\tprinter.printf(\", defined in %s,\", ex.getBeanDefinition().getResourceDescription());\n\t\t}\n\t\tprinter.print(\" could not be registered. A bean with that name has already been defined \");\n\t\tif (ex.getExistingDefinition().getResourceDescription() != null) {\n\t\t\tprinter.printf(\"in %s \", ex.getExistingDefinition().getResourceDescription());\n\t\t}\n\t\tprinter.print(\"and overriding is disabled.\");\n\t\treturn description.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BeanNotOfRequiredTypeFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.Proxy;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanNotOfRequiredTypeException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a\n * {@link BeanNotOfRequiredTypeException}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 1.4.0\n */\npublic class BeanNotOfRequiredTypeFailureAnalyzer extends AbstractFailureAnalyzer<BeanNotOfRequiredTypeException> {\n\n\tprivate static final String ACTION = \"Consider injecting the bean as one of its \"\n\t\t\t+ \"interfaces or forcing the use of CGLib-based \"\n\t\t\t+ \"proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.\";\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, BeanNotOfRequiredTypeException cause) {\n\t\tif (!Proxy.isProxyClass(cause.getActualType())) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new FailureAnalysis(getDescription(cause), ACTION, cause);\n\t}\n\n\tprivate String getDescription(BeanNotOfRequiredTypeException ex) {\n\t\tStringWriter description = new StringWriter();\n\t\tPrintWriter printer = new PrintWriter(description);\n\t\tprinter.printf(\"The bean '%s' could not be injected because it is a JDK dynamic proxy%n%n\", ex.getBeanName());\n\t\tprinter.printf(\"The bean is of type '%s' and implements:%n\", ex.getActualType().getName());\n\t\tfor (Class<?> actualTypeInterface : ex.getActualType().getInterfaces()) {\n\t\t\tprinter.println(\"\\t\" + actualTypeInterface.getName());\n\t\t}\n\t\tprinter.printf(\"%nExpected a bean of type '%s' which implements:%n\", ex.getRequiredType().getName());\n\t\tfor (Class<?> requiredTypeInterface : ex.getRequiredType().getInterfaces()) {\n\t\t\tprinter.println(\"\\t\" + requiredTypeInterface.getName());\n\t\t}\n\t\treturn description.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BindFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.UnboundConfigurationPropertiesException;\nimport org.springframework.boot.context.properties.bind.validation.BindValidationException;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a\n * {@link BindException} excluding {@link BindValidationException} and\n * {@link UnboundConfigurationPropertiesException}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass BindFailureAnalyzer extends AbstractFailureAnalyzer<BindException> {\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, BindException cause) {\n\t\tThrowable rootCause = cause.getCause();\n\t\tif (rootCause instanceof BindValidationException\n\t\t\t\t|| rootCause instanceof UnboundConfigurationPropertiesException) {\n\t\t\treturn null;\n\t\t}\n\t\treturn analyzeGenericBindException(rootFailure, cause);\n\t}\n\n\tprivate FailureAnalysis analyzeGenericBindException(Throwable rootFailure, BindException cause) {\n\t\tFailureAnalysis missingParametersAnalysis = MissingParameterNamesFailureAnalyzer\n\t\t\t.analyzeForMissingParameters(rootFailure);\n\t\tStringBuilder description = new StringBuilder(String.format(\"%s:%n\", cause.getMessage()));\n\t\tConfigurationProperty property = cause.getProperty();\n\t\tbuildDescription(description, property);\n\t\tdescription.append(String.format(\"%n    Reason: %s\", getMessage(cause)));\n\t\tif (missingParametersAnalysis != null) {\n\t\t\tMissingParameterNamesFailureAnalyzer.appendPossibility(description);\n\t\t}\n\t\treturn getFailureAnalysis(description.toString(), cause, missingParametersAnalysis);\n\t}\n\n\tprivate void buildDescription(StringBuilder description, @Nullable ConfigurationProperty property) {\n\t\tif (property != null) {\n\t\t\tdescription.append(String.format(\"%n    Property: %s\", property.getName()));\n\t\t\tdescription.append(String.format(\"%n    Value: \\\"%s\\\"\", property.getValue()));\n\t\t\tdescription.append(String.format(\"%n    Origin: %s\", property.getOrigin()));\n\t\t}\n\t}\n\n\tprivate String getMessage(BindException cause) {\n\t\tThrowable rootCause = getRootCause(cause.getCause());\n\t\tConversionFailedException conversionFailure = findCause(cause, ConversionFailedException.class);\n\t\tif (conversionFailure != null) {\n\t\t\tString message = \"failed to convert \" + conversionFailure.getSourceType() + \" to \"\n\t\t\t\t\t+ conversionFailure.getTargetType();\n\t\t\tif (rootCause != null) {\n\t\t\t\tmessage += \" (caused by \" + getExceptionTypeAndMessage(rootCause) + \")\";\n\t\t\t}\n\t\t\treturn message;\n\t\t}\n\t\tif (rootCause != null && StringUtils.hasText(rootCause.getMessage())) {\n\t\t\treturn getExceptionTypeAndMessage(rootCause);\n\t\t}\n\t\treturn getExceptionTypeAndMessage(cause);\n\t}\n\n\tprivate @Nullable Throwable getRootCause(@Nullable Throwable cause) {\n\t\tThrowable rootCause = cause;\n\t\twhile (rootCause != null && rootCause.getCause() != null) {\n\t\t\trootCause = rootCause.getCause();\n\t\t}\n\t\treturn rootCause;\n\t}\n\n\tprivate String getExceptionTypeAndMessage(Throwable ex) {\n\t\tString message = ex.getMessage();\n\t\treturn ex.getClass().getName() + (StringUtils.hasText(message) ? \": \" + message : \"\");\n\t}\n\n\tprivate FailureAnalysis getFailureAnalysis(String description, BindException cause,\n\t\t\t@Nullable FailureAnalysis missingParametersAnalysis) {\n\t\tStringBuilder action = new StringBuilder(\"Update your application's configuration\");\n\t\tCollection<String> validValues = findValidValues(cause);\n\t\tif (!validValues.isEmpty()) {\n\t\t\taction.append(String.format(\". The following values are valid:%n\"));\n\t\t\tvalidValues.forEach((value) -> action.append(String.format(\"%n    %s\", value)));\n\t\t}\n\t\tif (missingParametersAnalysis != null) {\n\t\t\taction.append(String.format(\"%n%n%s\", missingParametersAnalysis.getAction()));\n\t\t}\n\t\treturn new FailureAnalysis(description, action.toString(), cause);\n\t}\n\n\tprivate Collection<String> findValidValues(BindException ex) {\n\t\tConversionFailedException conversionFailure = findCause(ex, ConversionFailedException.class);\n\t\tif (conversionFailure != null) {\n\t\t\tObject[] enumConstants = conversionFailure.getTargetType().getType().getEnumConstants();\n\t\t\tif (enumConstants != null) {\n\t\t\t\treturn Stream.of(enumConstants).map(Object::toString).collect(Collectors.toCollection(TreeSet::new));\n\t\t\t}\n\t\t}\n\t\treturn Collections.emptySet();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/BindValidationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.validation.BindValidationException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of any bind validation\n * failures caused by {@link BindValidationException} or\n * {@link org.springframework.validation.BindException}.\n *\n * @author Madhura Bhave\n */\nclass BindValidationFailureAnalyzer extends AbstractFailureAnalyzer<Throwable> {\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, Throwable cause) {\n\t\tExceptionDetails details = getBindValidationExceptionDetails(rootFailure);\n\t\tif (details == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn analyzeBindValidationException(details);\n\t}\n\n\tprivate @Nullable ExceptionDetails getBindValidationExceptionDetails(Throwable rootFailure) {\n\t\tBindValidationException validationException = findCause(rootFailure, BindValidationException.class);\n\t\tif (validationException != null) {\n\t\t\tBindException bindException = findCause(rootFailure, BindException.class);\n\t\t\tList<ObjectError> errors = validationException.getValidationErrors().getAllErrors();\n\t\t\tAssert.state(bindException != null, \"BindException not found\");\n\t\t\treturn new ExceptionDetails(errors, bindException.getTarget().getType(), validationException);\n\t\t}\n\t\torg.springframework.validation.BindException bindException = findCause(rootFailure,\n\t\t\t\torg.springframework.validation.BindException.class);\n\t\tif (bindException != null) {\n\t\t\tList<ObjectError> errors = bindException.getAllErrors();\n\t\t\treturn new ExceptionDetails(errors, bindException.getTarget(), bindException);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate FailureAnalysis analyzeBindValidationException(ExceptionDetails details) {\n\t\tStringBuilder description = new StringBuilder(\n\t\t\t\tString.format(\"Binding to target %s failed:%n\", details.getTarget()));\n\t\tfor (ObjectError error : details.getErrors()) {\n\t\t\tif (error instanceof FieldError fieldError) {\n\t\t\t\tappendFieldError(description, fieldError);\n\t\t\t}\n\t\t\tdescription.append(String.format(\"%n    Reason: %s%n\", error.getDefaultMessage()));\n\t\t}\n\t\treturn getFailureAnalysis(description, details.getCause());\n\t}\n\n\tprivate void appendFieldError(StringBuilder description, FieldError error) {\n\t\tOrigin origin = Origin.from(error);\n\t\tdescription.append(String.format(\"%n    Property: %s\", error.getObjectName() + \".\" + error.getField()));\n\t\tdescription.append(String.format(\"%n    Value: \\\"%s\\\"\", error.getRejectedValue()));\n\t\tif (origin != null) {\n\t\t\tdescription.append(String.format(\"%n    Origin: %s\", origin));\n\t\t}\n\t}\n\n\tprivate FailureAnalysis getFailureAnalysis(Object description, Throwable cause) {\n\t\treturn new FailureAnalysis(description.toString(), \"Update your application's configuration\", cause);\n\t}\n\n\tprivate static class ExceptionDetails {\n\n\t\tprivate final List<ObjectError> errors;\n\n\t\tprivate final @Nullable Object target;\n\n\t\tprivate final Throwable cause;\n\n\t\tExceptionDetails(List<ObjectError> errors, @Nullable Object target, Throwable cause) {\n\t\t\tthis.errors = errors;\n\t\t\tthis.target = target;\n\t\t\tthis.cause = cause;\n\t\t}\n\n\t\t@Nullable Object getTarget() {\n\t\t\treturn this.target;\n\t\t}\n\n\t\tList<ObjectError> getErrors() {\n\t\t\treturn this.errors;\n\t\t}\n\n\t\tThrowable getCause() {\n\t\t\treturn this.cause;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyNameFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyNameException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by\n * {@link InvalidConfigurationPropertyNameException}.\n *\n * @author Madhura Bhave\n */\nclass InvalidConfigurationPropertyNameFailureAnalyzer\n\t\textends AbstractFailureAnalyzer<InvalidConfigurationPropertyNameException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, InvalidConfigurationPropertyNameException cause) {\n\t\tBeanCreationException exception = findCause(rootFailure, BeanCreationException.class);\n\t\tString action = String.format(\"Modify '%s' so that it conforms to the canonical names requirements.\",\n\t\t\t\tcause.getName());\n\t\treturn new FailureAnalysis(buildDescription(cause, exception), action, cause);\n\t}\n\n\tprivate String buildDescription(InvalidConfigurationPropertyNameException cause,\n\t\t\t@Nullable BeanCreationException exception) {\n\t\tStringBuilder description = new StringBuilder(\n\t\t\t\tString.format(\"Configuration property name '%s' is not valid:%n\", cause.getName()));\n\t\tString invalid = cause.getInvalidCharacters().stream().map(this::quote).collect(Collectors.joining(\", \"));\n\t\tdescription.append(String.format(\"%n    Invalid characters: %s\", invalid));\n\t\tif (exception != null) {\n\t\t\tdescription.append(String.format(\"%n    Bean: %s\", exception.getBeanName()));\n\t\t}\n\t\tdescription.append(String.format(\"%n    Reason: Canonical names should be \"\n\t\t\t\t+ \"kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter\"));\n\t\treturn description.toString();\n\t}\n\n\tprivate String quote(Character c) {\n\t\treturn \"'\" + c + \"'\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link FailureAnalyzer} that performs analysis of failures caused by an\n * {@link InvalidConfigurationPropertyValueException}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass InvalidConfigurationPropertyValueFailureAnalyzer\n\t\textends AbstractFailureAnalyzer<InvalidConfigurationPropertyValueException> {\n\n\tprivate final @Nullable ConfigurableEnvironment environment;\n\n\tInvalidConfigurationPropertyValueFailureAnalyzer(@Nullable Environment environment) {\n\t\tthis.environment = (ConfigurableEnvironment) environment;\n\t}\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, InvalidConfigurationPropertyValueException cause) {\n\t\tList<Descriptor> descriptors = getDescriptors(cause.getName());\n\t\tif (descriptors.isEmpty()) {\n\t\t\tdescriptors = List.of(new Descriptor(null, cause.getValue(), null));\n\t\t}\n\t\tStringBuilder description = new StringBuilder();\n\t\tappendDetails(description, cause, descriptors);\n\t\tappendReason(description, cause);\n\t\tappendAdditionalProperties(description, descriptors);\n\t\treturn new FailureAnalysis(description.toString(), getAction(cause), cause);\n\t}\n\n\tprivate List<Descriptor> getDescriptors(String propertyName) {\n\t\tSet<@Nullable Origin> seen = new HashSet<>();\n\t\treturn getPropertySources().filter((source) -> source.containsProperty(propertyName))\n\t\t\t.map((source) -> Descriptor.get(source, propertyName))\n\t\t\t.filter((descriptor) -> seen.add(getOrigin(descriptor)))\n\t\t\t.toList();\n\t}\n\n\tprivate @Nullable Origin getOrigin(@Nullable Descriptor descriptor) {\n\t\tif (descriptor == null) {\n\t\t\treturn null;\n\t\t}\n\t\tOrigin origin = descriptor.origin;\n\t\tif (origin instanceof PropertySourceOrigin propertySourceOrigin) {\n\t\t\torigin = propertySourceOrigin.getOrigin();\n\t\t}\n\t\treturn origin;\n\t}\n\n\tprivate Stream<PropertySource<?>> getPropertySources() {\n\t\treturn (this.environment != null) ? this.environment.getPropertySources().stream() : Stream.empty();\n\t}\n\n\tprivate void appendDetails(StringBuilder message, InvalidConfigurationPropertyValueException cause,\n\t\t\tList<Descriptor> descriptors) {\n\t\tDescriptor mainDescriptor = descriptors.get(0);\n\t\tmessage.append(\"Invalid value '\").append(mainDescriptor.getValue()).append(\"' for configuration property '\");\n\t\tmessage.append(cause.getName()).append(\"'\");\n\t\tmainDescriptor.appendOrigin(message);\n\t\tmessage.append(\".\");\n\t}\n\n\tprivate void appendReason(StringBuilder message, InvalidConfigurationPropertyValueException cause) {\n\t\tif (StringUtils.hasText(cause.getReason())) {\n\t\t\tmessage.append(String.format(\" Validation failed for the following reason:%n%n\"));\n\t\t\tmessage.append(cause.getReason());\n\t\t}\n\t\telse {\n\t\t\tmessage.append(\" No reason was provided.\");\n\t\t}\n\t}\n\n\tprivate void appendAdditionalProperties(StringBuilder message, List<Descriptor> descriptors) {\n\t\tList<Descriptor> others = descriptors.subList(1, descriptors.size());\n\t\tif (!others.isEmpty()) {\n\t\t\tmessage\n\t\t\t\t.append(String.format(\"%n%nAdditionally, this property is also set in the following property %s:%n%n\",\n\t\t\t\t\t\t(others.size() > 1) ? \"sources\" : \"source\"));\n\t\t\tfor (Descriptor other : others) {\n\t\t\t\tmessage.append(\"\\t- In '\").append(other.getPropertySource()).append(\"'\");\n\t\t\t\tmessage.append(\" with the value '\").append(other.getValue()).append(\"'\");\n\t\t\t\tother.appendOrigin(message);\n\t\t\t\tmessage.append(String.format(\".%n\"));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String getAction(InvalidConfigurationPropertyValueException cause) {\n\t\tStringBuilder action = new StringBuilder();\n\t\taction.append(\"Review the value of the property\");\n\t\tif (cause.getReason() != null) {\n\t\t\taction.append(\" with the provided reason\");\n\t\t}\n\t\taction.append(\".\");\n\t\treturn action.toString();\n\t}\n\n\tprivate static final class Descriptor {\n\n\t\tprivate final @Nullable String propertySource;\n\n\t\tprivate final @Nullable Object value;\n\n\t\tprivate final @Nullable Origin origin;\n\n\t\tprivate Descriptor(@Nullable String propertySource, @Nullable Object value, @Nullable Origin origin) {\n\t\t\tthis.propertySource = propertySource;\n\t\t\tthis.value = value;\n\t\t\tthis.origin = origin;\n\t\t}\n\n\t\t@Nullable String getPropertySource() {\n\t\t\treturn this.propertySource;\n\t\t}\n\n\t\t@Nullable Object getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid appendOrigin(StringBuilder message) {\n\t\t\tif (this.origin != null) {\n\t\t\t\tmessage.append(\" (originating from '\").append(this.origin).append(\"')\");\n\t\t\t}\n\t\t}\n\n\t\tstatic Descriptor get(PropertySource<?> source, String propertyName) {\n\t\t\tObject value = source.getProperty(propertyName);\n\t\t\tOrigin origin = OriginLookup.getOrigin(source, propertyName);\n\t\t\treturn new Descriptor(source.getName(), value, origin);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/MissingParameterNamesFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link FailureAnalyzer} for exceptions caused by missing parameter names. This analyzer\n * is ordered last, if other analyzers wish to also report parameter actions they can use\n * the {@link #analyzeForMissingParameters(Throwable)} static method.\n *\n * @author Phillip Webb\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass MissingParameterNamesFailureAnalyzer implements FailureAnalyzer {\n\n\tprivate static final String USE_PARAMETERS_MESSAGE = \"Ensure that the compiler uses the '-parameters' flag\";\n\n\tstatic final String POSSIBILITY = \"This may be due to missing parameter name information\";\n\n\tstatic final String ACTION = \"\"\"\n\t\t\tEnsure that your compiler is configured to use the '-parameters' flag.\n\t\t\tYou may need to update both your build tool settings as well as your IDE.\n\t\t\t(See https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-6.1-Release-Notes#parameter-name-retention)\n\t\t\t\t\t\t\t\"\"\";\n\n\t@Override\n\tpublic @Nullable FailureAnalysis analyze(Throwable failure) {\n\t\treturn analyzeForMissingParameters(failure);\n\t}\n\n\t/**\n\t * Analyze the given failure for missing parameter name exceptions.\n\t * @param failure the failure to analyze\n\t * @return a failure analysis or {@code null}\n\t */\n\tstatic @Nullable FailureAnalysis analyzeForMissingParameters(Throwable failure) {\n\t\treturn analyzeForMissingParameters(failure, failure, new HashSet<>());\n\t}\n\n\tprivate static @Nullable FailureAnalysis analyzeForMissingParameters(Throwable rootFailure,\n\t\t\t@Nullable Throwable cause, Set<Throwable> seen) {\n\t\tif (cause != null && seen.add(cause)) {\n\t\t\tif (isSpringParametersException(cause)) {\n\t\t\t\treturn getAnalysis(rootFailure, cause);\n\t\t\t}\n\t\t\tFailureAnalysis analysis = analyzeForMissingParameters(rootFailure, cause.getCause(), seen);\n\t\t\tif (analysis != null) {\n\t\t\t\treturn analysis;\n\t\t\t}\n\t\t\tfor (Throwable suppressed : cause.getSuppressed()) {\n\t\t\t\tanalysis = analyzeForMissingParameters(rootFailure, suppressed, seen);\n\t\t\t\tif (analysis != null) {\n\t\t\t\t\treturn analysis;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static boolean isSpringParametersException(Throwable failure) {\n\t\tString message = failure.getMessage();\n\t\treturn message != null && message.contains(USE_PARAMETERS_MESSAGE) && isSpringException(failure);\n\t}\n\n\tprivate static boolean isSpringException(Throwable failure) {\n\t\tStackTraceElement[] elements = failure.getStackTrace();\n\t\treturn elements.length > 0 && isSpringClass(elements[0].getClassName());\n\t}\n\n\tprivate static boolean isSpringClass(@Nullable String className) {\n\t\treturn className != null && className.startsWith(\"org.springframework.\");\n\t}\n\n\tprivate static FailureAnalysis getAnalysis(Throwable rootFailure, Throwable cause) {\n\t\tStringBuilder description = new StringBuilder(String.format(\"%s:%n\", cause.getMessage()));\n\t\tif (rootFailure != cause) {\n\t\t\tdescription.append(String.format(\"%n    Resulting Failure: %s\", getExceptionTypeAndMessage(rootFailure)));\n\t\t}\n\t\treturn new FailureAnalysis(description.toString(), ACTION, rootFailure);\n\t}\n\n\tprivate static String getExceptionTypeAndMessage(Throwable ex) {\n\t\tString message = ex.getMessage();\n\t\treturn ex.getClass().getName() + (StringUtils.hasText(message) ? \": \" + message : \"\");\n\t}\n\n\tstatic void appendPossibility(StringBuilder description) {\n\t\tif (!description.toString().endsWith(System.lineSeparator())) {\n\t\t\tdescription.append(\"%n\".formatted());\n\t\t}\n\t\tdescription.append(\"%n%s\".formatted(POSSIBILITY));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/MutuallyExclusiveConfigurationPropertiesFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * A {@link FailureAnalyzer} that performs analysis of failures caused by a\n * {@link MutuallyExclusiveConfigurationPropertiesException}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass MutuallyExclusiveConfigurationPropertiesFailureAnalyzer\n\t\textends AbstractFailureAnalyzer<MutuallyExclusiveConfigurationPropertiesException> {\n\n\tprivate final @Nullable ConfigurableEnvironment environment;\n\n\tMutuallyExclusiveConfigurationPropertiesFailureAnalyzer(@Nullable Environment environment) {\n\t\tthis.environment = (ConfigurableEnvironment) environment;\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure,\n\t\t\tMutuallyExclusiveConfigurationPropertiesException cause) {\n\t\tList<Descriptor> descriptors = new ArrayList<>();\n\t\tfor (String name : cause.getConfiguredNames()) {\n\t\t\tList<Descriptor> descriptorsForName = getDescriptors(name);\n\t\t\tif (descriptorsForName.isEmpty()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tdescriptors.addAll(descriptorsForName);\n\t\t}\n\t\tStringBuilder description = new StringBuilder();\n\t\tappendDetails(description, cause, descriptors);\n\t\treturn new FailureAnalysis(description.toString(),\n\t\t\t\t\"Update your configuration so that only one of the mutually exclusive properties is configured.\",\n\t\t\t\tcause);\n\t}\n\n\tprivate List<Descriptor> getDescriptors(String propertyName) {\n\t\treturn getPropertySources().filter((source) -> source.containsProperty(propertyName))\n\t\t\t.map((source) -> Descriptor.get(source, propertyName))\n\t\t\t.toList();\n\t}\n\n\tprivate Stream<PropertySource<?>> getPropertySources() {\n\t\tif (this.environment == null) {\n\t\t\treturn Stream.empty();\n\t\t}\n\t\treturn this.environment.getPropertySources()\n\t\t\t.stream()\n\t\t\t.filter((source) -> !ConfigurationPropertySources.isAttachedConfigurationPropertySource(source));\n\t}\n\n\tprivate void appendDetails(StringBuilder message, MutuallyExclusiveConfigurationPropertiesException cause,\n\t\t\tList<Descriptor> descriptors) {\n\t\tdescriptors.sort(Comparator.comparing((descriptor) -> descriptor.propertyName));\n\t\tmessage.append(String.format(\"The following configuration properties are mutually exclusive:%n%n\"));\n\t\tsortedStrings(cause.getMutuallyExclusiveNames())\n\t\t\t.forEach((name) -> message.append(String.format(\"\\t%s%n\", name)));\n\t\tmessage.append(String.format(\"%n\"));\n\t\tmessage.append(\n\t\t\t\tString.format(\"However, more than one of those properties has been configured at the same time:%n%n\"));\n\t\tSet<String> configuredDescriptions = sortedStrings(descriptors,\n\t\t\t\t(descriptor) -> String.format(\"\\t%s%s%n\", descriptor.propertyName,\n\t\t\t\t\t\t(descriptor.origin != null) ? \" (originating from '\" + descriptor.origin + \"')\" : \"\"));\n\t\tconfiguredDescriptions.forEach(message::append);\n\t}\n\n\tprivate Set<String> sortedStrings(Collection<String> input) {\n\t\treturn sortedStrings(input, Function.identity());\n\t}\n\n\tprivate <S> Set<String> sortedStrings(Collection<S> input, Function<S, String> converter) {\n\t\tTreeSet<String> results = new TreeSet<>();\n\t\tfor (S item : input) {\n\t\t\tresults.add(converter.apply(item));\n\t\t}\n\t\treturn results;\n\t}\n\n\tprivate static final class Descriptor {\n\n\t\tprivate final String propertyName;\n\n\t\tprivate final @Nullable Origin origin;\n\n\t\tprivate Descriptor(String propertyName, @Nullable Origin origin) {\n\t\t\tthis.propertyName = propertyName;\n\t\t\tthis.origin = origin;\n\t\t}\n\n\t\tstatic Descriptor get(PropertySource<?> source, String propertyName) {\n\t\t\tOrigin origin = OriginLookup.getOrigin(source, propertyName);\n\t\t\treturn new Descriptor(propertyName, origin);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.util.ClassUtils;\n\n/**\n * An {@link AbstractFailureAnalyzer} that analyzes {@link NoSuchMethodError\n * NoSuchMethodErrors}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodError> {\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchMethodError cause) {\n\t\tNoSuchMethodDescriptor callerDescriptor = getCallerMethodDescriptor(cause);\n\t\tif (callerDescriptor == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString message = cause.getMessage();\n\t\tNoSuchMethodDescriptor calledDescriptor = getNoSuchMethodDescriptor((message != null) ? message : \"\");\n\t\tif (calledDescriptor == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString description = getDescription(callerDescriptor, calledDescriptor);\n\t\tString action = getAction(callerDescriptor, calledDescriptor);\n\t\treturn new FailureAnalysis(description, action, cause);\n\t}\n\n\tprivate @Nullable NoSuchMethodDescriptor getCallerMethodDescriptor(NoSuchMethodError cause) {\n\t\tStackTraceElement firstStackTraceElement = cause.getStackTrace()[0];\n\t\tString message = firstStackTraceElement.toString();\n\t\tString className = firstStackTraceElement.getClassName();\n\t\treturn getDescriptorForClass(message, className);\n\t}\n\n\tprotected @Nullable NoSuchMethodDescriptor getNoSuchMethodDescriptor(String cause) {\n\t\tString message = cleanMessage(cause);\n\t\tString className = extractClassName(message);\n\t\treturn getDescriptorForClass(message, className);\n\t}\n\n\tprivate @Nullable NoSuchMethodDescriptor getDescriptorForClass(String message, @Nullable String className) {\n\t\tif (className == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<URL> candidates = findCandidates(className);\n\t\tif (candidates == null) {\n\t\t\treturn null;\n\t\t}\n\t\tClass<?> type = load(className);\n\t\tif (type == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<ClassDescriptor> typeHierarchy = getTypeHierarchy(type);\n\t\tif (typeHierarchy == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new NoSuchMethodDescriptor(message, className, candidates, typeHierarchy);\n\t}\n\n\tprivate String cleanMessage(String message) {\n\t\tint loadedFromIndex = message.indexOf(\" (loaded from\");\n\t\tif (loadedFromIndex == -1) {\n\t\t\treturn message;\n\t\t}\n\t\treturn message.substring(0, loadedFromIndex);\n\t}\n\n\tprivate @Nullable String extractClassName(String message) {\n\t\tif (message.startsWith(\"'\") && message.endsWith(\"'\")) {\n\t\t\tint splitIndex = message.indexOf(' ');\n\t\t\tif (splitIndex == -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tmessage = message.substring(splitIndex + 1);\n\t\t}\n\t\tint descriptorIndex = message.indexOf('(');\n\t\tif (descriptorIndex == -1) {\n\t\t\treturn null;\n\t\t}\n\t\tString classAndMethodName = message.substring(0, descriptorIndex);\n\t\tint methodNameIndex = classAndMethodName.lastIndexOf('.');\n\t\tif (methodNameIndex == -1) {\n\t\t\treturn null;\n\t\t}\n\t\tString className = classAndMethodName.substring(0, methodNameIndex);\n\t\treturn className.replace('/', '.');\n\t}\n\n\tprivate @Nullable List<URL> findCandidates(String className) {\n\t\ttry {\n\t\t\treturn Collections.list(NoSuchMethodFailureAnalyzer.class.getClassLoader()\n\t\t\t\t.getResources(ClassUtils.convertClassNameToResourcePath(className) + \".class\"));\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable Class<?> load(String className) {\n\t\ttry {\n\t\t\treturn Class.forName(className, false, getClass().getClassLoader());\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable List<ClassDescriptor> getTypeHierarchy(Class<?> type) {\n\t\ttry {\n\t\t\tList<ClassDescriptor> typeHierarchy = new ArrayList<>();\n\t\t\twhile (type != null && !type.equals(Object.class)) {\n\t\t\t\ttypeHierarchy.add(new ClassDescriptor(type.getCanonicalName(),\n\t\t\t\t\t\ttype.getProtectionDomain().getCodeSource().getLocation()));\n\t\t\t\ttype = type.getSuperclass();\n\t\t\t}\n\t\t\treturn typeHierarchy;\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate String getDescription(NoSuchMethodDescriptor callerDescriptor, NoSuchMethodDescriptor calledDescriptor) {\n\t\tStringWriter description = new StringWriter();\n\t\tPrintWriter writer = new PrintWriter(description);\n\t\twriter.println(\"An attempt was made to call a method that does not\"\n\t\t\t\t+ \" exist. The attempt was made from the following location:\");\n\t\twriter.println();\n\t\twriter.printf(\"    %s%n\", callerDescriptor.getErrorMessage());\n\t\twriter.println();\n\t\twriter.println(\"The following method did not exist:\");\n\t\twriter.println();\n\t\twriter.printf(\"    %s%n\", calledDescriptor.getErrorMessage());\n\t\twriter.println();\n\t\tif (callerDescriptor.getCandidateLocations().size() > 1) {\n\t\t\twriter.printf(\"The calling method's class, %s, is available from the following locations:%n\",\n\t\t\t\t\tcallerDescriptor.getClassName());\n\t\t\twriter.println();\n\t\t\tfor (URL candidate : callerDescriptor.getCandidateLocations()) {\n\t\t\t\twriter.printf(\"    %s%n\", candidate);\n\t\t\t}\n\t\t\twriter.println();\n\t\t\twriter.println(\"The calling method's class was loaded from the following location:\");\n\t\t\twriter.println();\n\t\t\twriter.printf(\"    %s%n\", callerDescriptor.getTypeHierarchy().get(0).getLocation());\n\t\t}\n\t\telse {\n\t\t\twriter.printf(\"The calling method's class, %s, was loaded from the following location:%n\",\n\t\t\t\t\tcallerDescriptor.getClassName());\n\t\t\twriter.println();\n\t\t\twriter.printf(\"    %s%n\", callerDescriptor.getCandidateLocations().get(0));\n\t\t}\n\t\twriter.println();\n\t\twriter.printf(\"The called method's class, %s, is available from the following locations:%n\",\n\t\t\t\tcalledDescriptor.getClassName());\n\t\twriter.println();\n\t\tfor (URL candidate : calledDescriptor.getCandidateLocations()) {\n\t\t\twriter.printf(\"    %s%n\", candidate);\n\t\t}\n\t\twriter.println();\n\t\twriter.println(\"The called method's class hierarchy was loaded from the following locations:\");\n\t\twriter.println();\n\t\tfor (ClassDescriptor type : calledDescriptor.getTypeHierarchy()) {\n\t\t\twriter.printf(\"    %s: %s%n\", type.getName(), type.getLocation());\n\t\t}\n\n\t\treturn description.toString();\n\t}\n\n\tprivate String getAction(NoSuchMethodDescriptor callerDescriptor, NoSuchMethodDescriptor calledDescriptor) {\n\t\tif (callerDescriptor.getClassName().equals(calledDescriptor.getClassName())) {\n\t\t\treturn \"Correct the classpath of your application so that it contains a single, compatible version of \"\n\t\t\t\t\t+ calledDescriptor.getClassName();\n\t\t}\n\t\telse {\n\t\t\treturn \"Correct the classpath of your application so that it contains compatible versions of the classes \"\n\t\t\t\t\t+ callerDescriptor.getClassName() + \" and \" + calledDescriptor.getClassName();\n\t\t}\n\t}\n\n\tprotected static class NoSuchMethodDescriptor {\n\n\t\tprivate final String errorMessage;\n\n\t\tprivate final String className;\n\n\t\tprivate final List<URL> candidateLocations;\n\n\t\tprivate final List<ClassDescriptor> typeHierarchy;\n\n\t\tpublic NoSuchMethodDescriptor(String errorMessage, String className, List<URL> candidateLocations,\n\t\t\t\tList<ClassDescriptor> typeHierarchy) {\n\t\t\tthis.errorMessage = errorMessage;\n\t\t\tthis.className = className;\n\t\t\tthis.candidateLocations = candidateLocations;\n\t\t\tthis.typeHierarchy = typeHierarchy;\n\t\t}\n\n\t\tpublic String getErrorMessage() {\n\t\t\treturn this.errorMessage;\n\t\t}\n\n\t\tpublic String getClassName() {\n\t\t\treturn this.className;\n\t\t}\n\n\t\tpublic List<URL> getCandidateLocations() {\n\t\t\treturn this.candidateLocations;\n\t\t}\n\n\t\tpublic List<ClassDescriptor> getTypeHierarchy() {\n\t\t\treturn this.typeHierarchy;\n\t\t}\n\n\t}\n\n\tprotected static class ClassDescriptor {\n\n\t\tprivate final String name;\n\n\t\tprivate final URL location;\n\n\t\tpublic ClassDescriptor(String name, URL location) {\n\t\t\tthis.name = name;\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic URL getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.NoUniqueBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link AbstractInjectionFailureAnalyzer} that performs analysis of failures caused\n * by a {@link NoUniqueBeanDefinitionException}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass NoUniqueBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyzer<NoUniqueBeanDefinitionException> {\n\n\tprivate final ConfigurableBeanFactory beanFactory;\n\n\tNoUniqueBeanDefinitionFailureAnalyzer(BeanFactory beanFactory) {\n\t\tAssert.isInstanceOf(ConfigurableBeanFactory.class, beanFactory);\n\t\tthis.beanFactory = (ConfigurableBeanFactory) beanFactory;\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoUniqueBeanDefinitionException cause,\n\t\t\t@Nullable String description) {\n\t\tString[] beanNames = extractBeanNames(cause);\n\t\tif (beanNames == null) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(String.format(\"%s required a single bean, but %d were found:%n\",\n\t\t\t\t(description != null) ? description : \"A component\", beanNames.length));\n\t\tfor (String beanName : beanNames) {\n\t\t\tbuildMessage(message, beanName);\n\t\t}\n\t\tMissingParameterNamesFailureAnalyzer.appendPossibility(message);\n\t\tStringBuilder action = new StringBuilder(\n\t\t\t\t\"Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, \"\n\t\t\t\t\t\t+ \"or using @Qualifier to identify the bean that should be consumed\");\n\t\taction.append(\"%n%n%s\".formatted(MissingParameterNamesFailureAnalyzer.ACTION));\n\t\treturn new FailureAnalysis(message.toString(), action.toString(), cause);\n\t}\n\n\tprivate void buildMessage(StringBuilder message, String beanName) {\n\t\ttry {\n\t\t\tBeanDefinition definition = this.beanFactory.getMergedBeanDefinition(beanName);\n\t\t\tmessage.append(getDefinitionDescription(beanName, definition));\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\tmessage.append(String.format(\"\\t- %s: a programmatically registered singleton%n\", beanName));\n\t\t}\n\t}\n\n\tprivate String getDefinitionDescription(String beanName, BeanDefinition definition) {\n\t\tif (StringUtils.hasText(definition.getFactoryMethodName())) {\n\t\t\treturn String.format(\"\\t- %s: defined by method '%s' in %s%n\", beanName, definition.getFactoryMethodName(),\n\t\t\t\t\tgetResourceDescription(definition));\n\t\t}\n\t\treturn String.format(\"\\t- %s: defined in %s%n\", beanName, getResourceDescription(definition));\n\t}\n\n\tprivate String getResourceDescription(BeanDefinition definition) {\n\t\tString resourceDescription = definition.getResourceDescription();\n\t\treturn (resourceDescription != null) ? resourceDescription : \"unknown location\";\n\t}\n\n\tprivate String @Nullable [] extractBeanNames(NoUniqueBeanDefinitionException cause) {\n\t\tString message = cause.getMessage();\n\t\tif (message == null) {\n\t\t\tmessage = \"\";\n\t\t}\n\t\tif (message.contains(\"but found\")) {\n\t\t\treturn StringUtils.commaDelimitedListToStringArray(message.substring(message.lastIndexOf(':') + 1).trim());\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/PatternParseFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.web.util.pattern.PatternParseException;\n\n/**\n * A {@code FailureAnalyzer} that performs analysis of failures caused by a\n * {@code PatternParseException}.\n *\n * @author Brian Clozel\n */\nclass PatternParseFailureAnalyzer extends AbstractFailureAnalyzer<PatternParseException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, PatternParseException cause) {\n\t\treturn new FailureAnalysis(\"Invalid mapping pattern detected:\\n\" + cause.toDetailedString(),\n\t\t\t\t\"Fix this pattern in your application or switch to the legacy parser implementation with \"\n\t\t\t\t\t\t+ \"'spring.mvc.pathmatch.matching-strategy=ant_path_matcher'.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/UnboundConfigurationPropertyFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.UnboundConfigurationPropertiesException;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.util.Assert;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by any\n * {@link UnboundConfigurationPropertiesException}.\n *\n * @author Madhura Bhave\n */\nclass UnboundConfigurationPropertyFailureAnalyzer\n\t\textends AbstractFailureAnalyzer<UnboundConfigurationPropertiesException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, UnboundConfigurationPropertiesException cause) {\n\t\tBindException exception = findCause(rootFailure, BindException.class);\n\t\tAssert.state(exception != null, \"BindException not found\");\n\t\treturn analyzeUnboundConfigurationPropertiesException(exception, cause);\n\t}\n\n\tprivate FailureAnalysis analyzeUnboundConfigurationPropertiesException(BindException cause,\n\t\t\tUnboundConfigurationPropertiesException exception) {\n\t\tStringBuilder description = new StringBuilder(\n\t\t\t\tString.format(\"Binding to target %s failed:%n\", cause.getTarget()));\n\t\tfor (ConfigurationProperty property : exception.getUnboundProperties()) {\n\t\t\tbuildDescription(description, property);\n\t\t\tdescription.append(String.format(\"%n    Reason: %s\", exception.getMessage()));\n\t\t}\n\t\treturn getFailureAnalysis(description, cause);\n\t}\n\n\tprivate void buildDescription(StringBuilder description, @Nullable ConfigurationProperty property) {\n\t\tif (property != null) {\n\t\t\tdescription.append(String.format(\"%n    Property: %s\", property.getName()));\n\t\t\tdescription.append(String.format(\"%n    Value: \\\"%s\\\"\", property.getValue()));\n\t\t\tdescription.append(String.format(\"%n    Origin: %s\", property.getOrigin()));\n\t\t}\n\t}\n\n\tprivate FailureAnalysis getFailureAnalysis(Object description, BindException cause) {\n\t\treturn new FailureAnalysis(description.toString(), \"Update your application's configuration\", cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/ValidationExceptionFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport jakarta.validation.NoProviderFoundException;\nimport jakarta.validation.ValidationException;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\n\n/**\n * A {@link FailureAnalyzer} that performs analysis of failures caused by a\n * {@link ValidationException}.\n *\n * @author Andy Wilkinson\n */\nclass ValidationExceptionFailureAnalyzer extends AbstractFailureAnalyzer<ValidationException> {\n\n\tprivate static final String JAVAX_MISSING_IMPLEMENTATION_MESSAGE = \"Unable to create a \"\n\t\t\t+ \"Configuration, because no Bean Validation provider could be found\";\n\n\tprivate static final String JAKARTA_MISSING_IMPLEMENTATION_MESSAGE = \"Unable to create a \"\n\t\t\t+ \"Configuration, because no Jakarta Bean Validation provider could be found\";\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, ValidationException cause) {\n\t\tString message = cause.getMessage();\n\t\tif (message == null) {\n\t\t\tmessage = \"\";\n\t\t}\n\t\tif (cause instanceof NoProviderFoundException || message.startsWith(JAVAX_MISSING_IMPLEMENTATION_MESSAGE)\n\t\t\t\t|| message.startsWith(JAKARTA_MISSING_IMPLEMENTATION_MESSAGE)) {\n\t\t\treturn new FailureAnalysis(\n\t\t\t\t\t\"The Bean Validation API is on the classpath but no implementation could be found\",\n\t\t\t\t\t\"Add an implementation, such as Hibernate Validator, to the classpath\", cause);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Internal {@link org.springframework.boot.diagnostics.FailureAnalyzer} implementations.\n */\n@NullMarked\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/diagnostics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for failure analysis and reporting.\n *\n * @see org.springframework.boot.diagnostics.FailureAnalyzer\n * @see org.springframework.boot.diagnostics.FailureAnalysisReporter\n */\n@NullMarked\npackage org.springframework.boot.diagnostics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/ConfigTreePropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.FileVisitOption;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link PropertySource} backed by a directory tree that contains files for each value.\n * The {@link PropertySource} will recursively scan a given source directory and expose a\n * property for each file found. The property name will be the filename, and the property\n * value will be the contents of the file.\n * <p>\n * Directories are only scanned when the source is first created. The directory is not\n * monitored for updates, so files should not be added or removed. However, the contents\n * of a file can be updated as long as the property source was created with a\n * {@link Option#ALWAYS_READ} option. Nested directories are included in the source, but\n * with a {@code '.'} rather than {@code '/'} used as the path separator.\n * <p>\n * Property values are returned as {@link Value} instances which allows them to be treated\n * either as an {@link InputStreamSource} or as a {@link CharSequence}. In addition, if\n * used with an {@link Environment} configured with an\n * {@link ApplicationConversionService}, property values can be converted to a\n * {@code String} or {@code byte[]}.\n * <p>\n * This property source is typically used to read Kubernetes {@code configMap} volume\n * mounts.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class ConfigTreePropertySource extends EnumerablePropertySource<Path>\n\t\timplements PropertySourceInfo, OriginLookup<String> {\n\n\tprivate static final int MAX_DEPTH = 100;\n\n\tprivate final Map<String, PropertyFile> propertyFiles;\n\n\tprivate final String[] names;\n\n\tprivate final Set<Option> options;\n\n\t/**\n\t * Create a new {@link ConfigTreePropertySource} instance.\n\t * @param name the name of the property source\n\t * @param sourceDirectory the underlying source directory\n\t */\n\tpublic ConfigTreePropertySource(String name, Path sourceDirectory) {\n\t\tthis(name, sourceDirectory, EnumSet.noneOf(Option.class));\n\t}\n\n\t/**\n\t * Create a new {@link ConfigTreePropertySource} instance.\n\t * @param name the name of the property source\n\t * @param sourceDirectory the underlying source directory\n\t * @param options the property source options\n\t */\n\tpublic ConfigTreePropertySource(String name, Path sourceDirectory, Option... options) {\n\t\tthis(name, sourceDirectory, EnumSet.copyOf(Arrays.asList(options)));\n\t}\n\n\tprivate ConfigTreePropertySource(String name, Path sourceDirectory, Set<Option> options) {\n\t\tsuper(name, sourceDirectory);\n\t\tAssert.isTrue(Files.exists(sourceDirectory),\n\t\t\t\t() -> \"'sourceDirectory' [%s] must exist\".formatted(sourceDirectory));\n\t\tAssert.isTrue(Files.isDirectory(sourceDirectory),\n\t\t\t\t() -> \"'sourceDirectory' [%s] must be a directory\".formatted(sourceDirectory));\n\t\tthis.propertyFiles = PropertyFile.findAll(sourceDirectory, options);\n\t\tthis.options = options;\n\t\tthis.names = StringUtils.toStringArray(this.propertyFiles.keySet());\n\t}\n\n\t@Override\n\tpublic String[] getPropertyNames() {\n\t\treturn this.names.clone();\n\t}\n\n\t@Override\n\tpublic @Nullable Value getProperty(String name) {\n\t\tPropertyFile propertyFile = this.propertyFiles.get(name);\n\t\treturn (propertyFile != null) ? propertyFile.getContent() : null;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin(String name) {\n\t\tPropertyFile propertyFile = this.propertyFiles.get(name);\n\t\treturn (propertyFile != null) ? propertyFile.getOrigin() : null;\n\t}\n\n\t@Override\n\tpublic boolean isImmutable() {\n\t\treturn !this.options.contains(Option.ALWAYS_READ);\n\t}\n\n\t/**\n\t * Property source options.\n\t */\n\tpublic enum Option {\n\n\t\t/**\n\t\t * Always read the value of the file when accessing the property value. When this\n\t\t * option is not set the property source will cache the value when it's first\n\t\t * read.\n\t\t */\n\t\tALWAYS_READ,\n\n\t\t/**\n\t\t * Convert file and directory names to lowercase.\n\t\t */\n\t\tUSE_LOWERCASE_NAMES,\n\n\t\t/**\n\t\t * Automatically attempt trim trailing new-line characters.\n\t\t */\n\t\tAUTO_TRIM_TRAILING_NEW_LINE\n\n\t}\n\n\t/**\n\t * A value returned from the property source which exposes the contents of the\n\t * property file. Values can either be treated as {@link CharSequence} or as an\n\t * {@link InputStreamSource}.\n\t */\n\tpublic interface Value extends CharSequence, InputStreamSource {\n\n\t}\n\n\t/**\n\t * A single property file that was found when the source was created.\n\t */\n\tprivate static final class PropertyFile {\n\n\t\tprivate static final Location START_OF_FILE = new Location(0, 0);\n\n\t\tprivate final Path path;\n\n\t\tprivate final FileSystemResource resource;\n\n\t\tprivate final Origin origin;\n\n\t\tprivate final @Nullable PropertyFileContent cachedContent;\n\n\t\tprivate final boolean autoTrimTrailingNewLine;\n\n\t\tprivate PropertyFile(Path path, Set<Option> options) {\n\t\t\tthis.path = path;\n\t\t\tthis.resource = new FileSystemResource(path);\n\t\t\tthis.origin = new TextResourceOrigin(this.resource, START_OF_FILE);\n\t\t\tthis.autoTrimTrailingNewLine = options.contains(Option.AUTO_TRIM_TRAILING_NEW_LINE);\n\t\t\tthis.cachedContent = options.contains(Option.ALWAYS_READ) ? null\n\t\t\t\t\t: new PropertyFileContent(path, this.resource, this.origin, true, this.autoTrimTrailingNewLine);\n\t\t}\n\n\t\tPropertyFileContent getContent() {\n\t\t\tif (this.cachedContent != null) {\n\t\t\t\treturn this.cachedContent;\n\t\t\t}\n\t\t\treturn new PropertyFileContent(this.path, this.resource, this.origin, false, this.autoTrimTrailingNewLine);\n\t\t}\n\n\t\tOrigin getOrigin() {\n\t\t\treturn this.origin;\n\t\t}\n\n\t\tstatic Map<String, PropertyFile> findAll(Path sourceDirectory, Set<Option> options) {\n\t\t\ttry {\n\t\t\t\tMap<String, PropertyFile> propertyFiles = new TreeMap<>();\n\t\t\t\ttry (Stream<Path> pathStream = Files.find(sourceDirectory, MAX_DEPTH, PropertyFile::isPropertyFile,\n\t\t\t\t\t\tFileVisitOption.FOLLOW_LINKS)) {\n\t\t\t\t\tpathStream.forEach((path) -> {\n\t\t\t\t\t\tString name = getName(sourceDirectory.relativize(path));\n\t\t\t\t\t\tif (StringUtils.hasText(name)) {\n\t\t\t\t\t\t\tif (options.contains(Option.USE_LOWERCASE_NAMES)) {\n\t\t\t\t\t\t\t\tname = name.toLowerCase(Locale.getDefault());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpropertyFiles.put(name, new PropertyFile(path, options));\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn Collections.unmodifiableMap(propertyFiles);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to find files in '\" + sourceDirectory + \"'\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate static boolean isPropertyFile(Path path, BasicFileAttributes attributes) {\n\t\t\treturn !hasHiddenPathElement(path) && (attributes.isRegularFile() || attributes.isSymbolicLink());\n\t\t}\n\n\t\tprivate static boolean hasHiddenPathElement(Path path) {\n\t\t\tfor (Path element : path) {\n\t\t\t\tif (element.toString().startsWith(\"..\")) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate static String getName(Path relativePath) {\n\t\t\tint nameCount = relativePath.getNameCount();\n\t\t\tif (nameCount == 1) {\n\t\t\t\treturn relativePath.toString();\n\t\t\t}\n\t\t\tStringBuilder name = new StringBuilder();\n\t\t\tfor (int i = 0; i < nameCount; i++) {\n\t\t\t\tname.append((i != 0) ? \".\" : \"\");\n\t\t\t\tname.append(relativePath.getName(i));\n\t\t\t}\n\t\t\treturn name.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * The contents of a found property file.\n\t */\n\tprivate static final class PropertyFileContent implements Value, OriginProvider {\n\n\t\tprivate final Path path;\n\n\t\tprivate final Lock resourceLock = new ReentrantLock();\n\n\t\tprivate final Resource resource;\n\n\t\tprivate final Origin origin;\n\n\t\tprivate final boolean cacheContent;\n\n\t\tprivate final boolean autoTrimTrailingNewLine;\n\n\t\tprivate volatile byte @Nullable [] content;\n\n\t\tprivate PropertyFileContent(Path path, Resource resource, Origin origin, boolean cacheContent,\n\t\t\t\tboolean autoTrimTrailingNewLine) {\n\t\t\tthis.path = path;\n\t\t\tthis.resource = resource;\n\t\t\tthis.origin = origin;\n\t\t\tthis.cacheContent = cacheContent;\n\t\t\tthis.autoTrimTrailingNewLine = autoTrimTrailingNewLine;\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin() {\n\t\t\treturn this.origin;\n\t\t}\n\n\t\t@Override\n\t\tpublic int length() {\n\t\t\treturn toString().length();\n\t\t}\n\n\t\t@Override\n\t\tpublic char charAt(int index) {\n\t\t\treturn toString().charAt(index);\n\t\t}\n\n\t\t@Override\n\t\tpublic CharSequence subSequence(int start, int end) {\n\t\t\treturn toString().subSequence(start, end);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tString string = new String(getBytes());\n\t\t\tif (this.autoTrimTrailingNewLine) {\n\t\t\t\tstring = autoTrimTrailingNewLine(string);\n\t\t\t}\n\t\t\treturn string;\n\t\t}\n\n\t\tprivate String autoTrimTrailingNewLine(String string) {\n\t\t\tif (!string.endsWith(\"\\n\")) {\n\t\t\t\treturn string;\n\t\t\t}\n\t\t\tint numberOfLines = 0;\n\t\t\tfor (int i = 0; i < string.length(); i++) {\n\t\t\t\tchar ch = string.charAt(i);\n\t\t\t\tif (ch == '\\n') {\n\t\t\t\t\tnumberOfLines++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (numberOfLines > 1) {\n\t\t\t\treturn string;\n\t\t\t}\n\t\t\treturn (string.endsWith(\"\\r\\n\")) ? string.substring(0, string.length() - 2)\n\t\t\t\t\t: string.substring(0, string.length() - 1);\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\tif (!this.cacheContent) {\n\t\t\t\tassertStillExists();\n\t\t\t\treturn this.resource.getInputStream();\n\t\t\t}\n\t\t\treturn new ByteArrayInputStream(getBytes());\n\t\t}\n\n\t\tprivate byte[] getBytes() {\n\t\t\ttry {\n\t\t\t\tif (!this.cacheContent) {\n\t\t\t\t\tassertStillExists();\n\t\t\t\t\treturn FileCopyUtils.copyToByteArray(this.resource.getInputStream());\n\t\t\t\t}\n\t\t\t\tbyte[] content = this.content;\n\t\t\t\tif (content == null) {\n\t\t\t\t\tassertStillExists();\n\t\t\t\t\tthis.resourceLock.lock();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontent = this.content;\n\t\t\t\t\t\tif (content == null) {\n\t\t\t\t\t\t\tcontent = FileCopyUtils.copyToByteArray(this.resource.getInputStream());\n\t\t\t\t\t\t\tthis.content = content;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\tthis.resourceLock.unlock();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn content;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate void assertStillExists() {\n\t\t\tAssert.state(Files.exists(this.path), () -> \"The property file '\" + this.path + \"' no longer exists\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/DefaultPropertiesPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link MapPropertySource} containing default properties contributed directly to a\n * {@code SpringApplication}. By convention, the {@link DefaultPropertiesPropertySource}\n * is always the last property source in the {@link Environment}.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class DefaultPropertiesPropertySource extends MapPropertySource {\n\n\t/**\n\t * The name of the 'default properties' property source.\n\t */\n\tpublic static final String NAME = \"defaultProperties\";\n\n\t/**\n\t * Create a new {@link DefaultPropertiesPropertySource} with the given {@code Map}\n\t * source.\n\t * @param source the source map\n\t */\n\tpublic DefaultPropertiesPropertySource(Map<String, Object> source) {\n\t\tsuper(NAME, source);\n\t}\n\n\t/**\n\t * Return {@code true} if the given source is named 'defaultProperties'.\n\t * @param propertySource the property source to check\n\t * @return {@code true} if the name matches\n\t */\n\tpublic static boolean hasMatchingName(@Nullable PropertySource<?> propertySource) {\n\t\treturn (propertySource != null) && propertySource.getName().equals(NAME);\n\t}\n\n\t/**\n\t * Create a new {@link DefaultPropertiesPropertySource} instance if the provided\n\t * source is not empty.\n\t * @param source the {@code Map} source\n\t * @param action the action used to consume the\n\t * {@link DefaultPropertiesPropertySource}\n\t */\n\tpublic static void ifNotEmpty(@Nullable Map<String, Object> source,\n\t\t\t@Nullable Consumer<DefaultPropertiesPropertySource> action) {\n\t\tif (!CollectionUtils.isEmpty(source) && action != null) {\n\t\t\taction.accept(new DefaultPropertiesPropertySource(source));\n\t\t}\n\t}\n\n\t/**\n\t * Add a new {@link DefaultPropertiesPropertySource} or merge with an existing one.\n\t * @param source the {@code Map} source\n\t * @param sources the existing sources\n\t * @since 2.4.4\n\t */\n\tpublic static void addOrMerge(Map<String, Object> source, MutablePropertySources sources) {\n\t\tif (!CollectionUtils.isEmpty(source)) {\n\t\t\tMap<String, Object> resultingSource = new HashMap<>();\n\t\t\tDefaultPropertiesPropertySource propertySource = new DefaultPropertiesPropertySource(resultingSource);\n\t\t\tif (sources.contains(NAME)) {\n\t\t\t\tmergeIfPossible(source, sources, resultingSource);\n\t\t\t\tsources.replace(NAME, propertySource);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresultingSource.putAll(source);\n\t\t\t\tsources.addLast(propertySource);\n\t\t\t}\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static void mergeIfPossible(Map<String, Object> source, MutablePropertySources sources,\n\t\t\tMap<String, Object> resultingSource) {\n\t\tPropertySource<?> existingSource = sources.get(NAME);\n\t\tif (existingSource != null) {\n\t\t\tObject underlyingSource = existingSource.getSource();\n\t\t\tif (underlyingSource instanceof Map) {\n\t\t\t\tresultingSource.putAll((Map<String, Object>) underlyingSource);\n\t\t\t}\n\t\t\tresultingSource.putAll(source);\n\t\t}\n\t}\n\n\t/**\n\t * Move the 'defaultProperties' property source so that it's the last source in the\n\t * given {@link ConfigurableEnvironment}.\n\t * @param environment the environment to update\n\t */\n\tpublic static void moveToEnd(ConfigurableEnvironment environment) {\n\t\tmoveToEnd(environment.getPropertySources());\n\t}\n\n\t/**\n\t * Move the 'defaultProperties' property source so that it's the last source in the\n\t * given {@link MutablePropertySources}.\n\t * @param propertySources the property sources to update\n\t */\n\tpublic static void moveToEnd(MutablePropertySources propertySources) {\n\t\tPropertySource<?> propertySource = propertySources.remove(NAME);\n\t\tif (propertySource != null) {\n\t\t\tpropertySources.addLast(propertySource);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\n/**\n * Allows for customization of the application's {@link Environment} prior to the\n * application context being refreshed.\n * <p>\n * EnvironmentPostProcessor implementations have to be registered in\n * {@code META-INF/spring.factories}, using the fully qualified name of this class as the\n * key. Implementations may implement the {@link org.springframework.core.Ordered Ordered}\n * interface or use an {@link org.springframework.core.annotation.Order @Order} annotation\n * if they wish to be invoked in specific order.\n * <p>\n * Since Spring Boot 2.4, {@code EnvironmentPostProcessor} implementations may optionally\n * take the following constructor parameters:\n * <ul>\n * <li>{@link DeferredLogFactory} - A factory that can be used to create loggers with\n * output deferred until the application has been fully prepared (allowing the environment\n * itself to configure logging levels).</li>\n * <li>{@link ConfigurableBootstrapContext} - A bootstrap context that can be used to\n * store objects that may be expensive to create, or need to be shared\n * ({@link BootstrapContext} or {@link BootstrapRegistry} may also be used).</li>\n * </ul>\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 1.3.0\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link org.springframework.boot.EnvironmentPostProcessor}\n */\n@FunctionalInterface\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic interface EnvironmentPostProcessor {\n\n\t/**\n\t * Post-process the given {@code environment}.\n\t * @param environment the environment to post-process\n\t * @param application the application to which the environment belongs\n\t */\n\tvoid postProcessEnvironment(ConfigurableEnvironment environment,\n\t\t\torg.springframework.boot.SpringApplication application);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedMapPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.core.env.MapPropertySource;\n\n/**\n * {@link OriginLookup} backed by a {@link Map} containing {@link OriginTrackedValue\n * OriginTrackedValues}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.0.0\n * @see OriginTrackedValue\n */\npublic final class OriginTrackedMapPropertySource extends MapPropertySource\n\t\timplements PropertySourceInfo, OriginLookup<String> {\n\n\tprivate final boolean immutable;\n\n\t/**\n\t * Create a new {@link OriginTrackedMapPropertySource} instance.\n\t * @param name the property source name\n\t * @param source the underlying map source\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic OriginTrackedMapPropertySource(String name, Map source) {\n\t\tthis(name, source, false);\n\t}\n\n\t/**\n\t * Create a new {@link OriginTrackedMapPropertySource} instance.\n\t * @param name the property source name\n\t * @param source the underlying map source\n\t * @param immutable if the underlying source is immutable and guaranteed not to change\n\t * @since 2.2.0\n\t */\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tpublic OriginTrackedMapPropertySource(String name, Map source, boolean immutable) {\n\t\tsuper(name, source);\n\t\tthis.immutable = immutable;\n\t}\n\n\t@Override\n\tpublic @Nullable Object getProperty(String name) {\n\t\tObject value = super.getProperty(name);\n\t\tif (value instanceof OriginTrackedValue originTrackedValue) {\n\t\t\treturn originTrackedValue.getValue();\n\t\t}\n\t\treturn value;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin(String name) {\n\t\tObject value = super.getProperty(name);\n\t\tif (value instanceof OriginTrackedValue originTrackedValue) {\n\t\t\treturn originTrackedValue.getOrigin();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean isImmutable() {\n\t\treturn this.immutable;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedPropertiesLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.LineNumberReader;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BooleanSupplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * Class to load {@code .properties} files into a map of {@code String} -&gt;\n * {@link OriginTrackedValue}. Also supports expansion of {@code name[]=a,b,c} list style\n * values.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Thiago Hirata\n * @author Guirong Hu\n * @author Moritz Halbritter\n */\nclass OriginTrackedPropertiesLoader {\n\n\tprivate final Resource resource;\n\n\t/**\n\t * Create a new {@link OriginTrackedPropertiesLoader} instance.\n\t * @param resource the resource of the {@code .properties} data\n\t */\n\tOriginTrackedPropertiesLoader(Resource resource) {\n\t\tAssert.notNull(resource, \"'resource' must not be null\");\n\t\tthis.resource = resource;\n\t}\n\n\t/**\n\t * Load {@code .properties} data and return a list of documents.\n\t * @param encoding the resource encoding. Uses ISO-8859-1 if {@code null}\n\t * @return the loaded properties\n\t * @throws IOException on read error\n\t */\n\tList<Document> load(@Nullable Charset encoding) throws IOException {\n\t\treturn load(encoding, true);\n\t}\n\n\t/**\n\t * Load {@code .properties} data and return a map of {@code String} ->\n\t * {@link OriginTrackedValue}.\n\t * @param encoding the resource encoding. Uses ISO-8859-1 if {@code null}\n\t * @param expandLists if list {@code name[]=a,b,c} shortcuts should be expanded\n\t * @return the loaded properties\n\t * @throws IOException on read error\n\t */\n\tList<Document> load(@Nullable Charset encoding, boolean expandLists) throws IOException {\n\t\tList<Document> documents = new ArrayList<>();\n\t\tDocument document = new Document();\n\t\tStringBuilder buffer = new StringBuilder();\n\t\ttry (CharacterReader reader = new CharacterReader(this.resource, encoding)) {\n\t\t\twhile (reader.read()) {\n\t\t\t\tif (reader.isCommentPrefixCharacter()) {\n\t\t\t\t\tchar commentPrefixCharacter = reader.getCharacter();\n\t\t\t\t\tif (isNewDocument(reader)) {\n\t\t\t\t\t\tif (!document.isEmpty()) {\n\t\t\t\t\t\t\tdocuments.add(document);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdocument = new Document();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (document.isEmpty() && !documents.isEmpty()) {\n\t\t\t\t\t\t\tdocument = documents.remove(documents.size() - 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treader.setLastLineCommentPrefixCharacter(commentPrefixCharacter);\n\t\t\t\t\t\treader.skipComment();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treader.setLastLineCommentPrefixCharacter(-1);\n\t\t\t\t\tloadKeyAndValue(expandLists, document, reader, buffer);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\tif (!document.isEmpty() && !documents.contains(document)) {\n\t\t\tdocuments.add(document);\n\t\t}\n\t\treturn documents;\n\t}\n\n\tprivate void loadKeyAndValue(boolean expandLists, Document document, CharacterReader reader, StringBuilder buffer)\n\t\t\tthrows IOException {\n\t\tString key = loadKey(buffer, reader).trim();\n\t\tif (expandLists && key.endsWith(\"[]\")) {\n\t\t\tkey = key.substring(0, key.length() - 2);\n\t\t\tint index = 0;\n\t\t\tdo {\n\t\t\t\tOriginTrackedValue value = loadValue(buffer, reader, true);\n\t\t\t\tdocument.put(key + \"[\" + (index++) + \"]\", value);\n\t\t\t\tif (!reader.isEndOfLine()) {\n\t\t\t\t\treader.read();\n\t\t\t\t}\n\t\t\t}\n\t\t\twhile (!reader.isEndOfLine());\n\t\t}\n\t\telse {\n\t\t\tOriginTrackedValue value = loadValue(buffer, reader, false);\n\t\t\tdocument.put(key, value);\n\t\t}\n\t}\n\n\tprivate String loadKey(StringBuilder buffer, CharacterReader reader) throws IOException {\n\t\tbuffer.setLength(0);\n\t\tboolean previousWhitespace = false;\n\t\twhile (!reader.isEndOfLine()) {\n\t\t\tif (reader.isPropertyDelimiter()) {\n\t\t\t\treader.read();\n\t\t\t\treturn buffer.toString();\n\t\t\t}\n\t\t\tif (!reader.isWhiteSpace() && previousWhitespace) {\n\t\t\t\treturn buffer.toString();\n\t\t\t}\n\t\t\tpreviousWhitespace = reader.isWhiteSpace();\n\t\t\tbuffer.append(reader.getCharacter());\n\t\t\treader.read();\n\t\t}\n\t\treturn buffer.toString();\n\t}\n\n\tprivate OriginTrackedValue loadValue(StringBuilder buffer, CharacterReader reader, boolean splitLists)\n\t\t\tthrows IOException {\n\t\tbuffer.setLength(0);\n\t\twhile (reader.isWhiteSpace() && !reader.isEndOfLine()) {\n\t\t\treader.read();\n\t\t}\n\t\tLocation location = reader.getLocation();\n\t\twhile (!reader.isEndOfLine() && !(splitLists && reader.isListDelimiter())) {\n\t\t\tbuffer.append(reader.getCharacter());\n\t\t\treader.read();\n\t\t}\n\t\tOrigin origin = new TextResourceOrigin(this.resource, location);\n\t\treturn OriginTrackedValue.of(buffer.toString(), origin);\n\t}\n\n\tprivate boolean isNewDocument(CharacterReader reader) throws IOException {\n\t\tif (reader.isSameLastLineCommentPrefix()) {\n\t\t\treturn false;\n\t\t}\n\t\tboolean result = reader.getLocation().getColumn() == 0;\n\t\tresult = result && readAndExpect(reader, reader::isHyphenCharacter);\n\t\tresult = result && readAndExpect(reader, reader::isHyphenCharacter);\n\t\tresult = result && readAndExpect(reader, reader::isHyphenCharacter);\n\t\tif (!reader.isEndOfLine()) {\n\t\t\treader.read();\n\t\t\treader.skipWhitespace();\n\t\t}\n\t\treturn result && reader.isEndOfLine();\n\t}\n\n\tprivate boolean readAndExpect(CharacterReader reader, BooleanSupplier check) throws IOException {\n\t\treader.read();\n\t\treturn check.getAsBoolean();\n\t}\n\n\t/**\n\t * Reads characters from the source resource, taking care of skipping comments,\n\t * handling multi-line values and tracking {@code '\\'} escapes.\n\t */\n\tprivate static class CharacterReader implements Closeable {\n\n\t\tprivate static final String[] ESCAPES = { \"trnf\", \"\\t\\r\\n\\f\" };\n\n\t\tprivate final LineNumberReader reader;\n\n\t\tprivate int columnNumber = -1;\n\n\t\tprivate boolean escaped;\n\n\t\tprivate int character;\n\n\t\tprivate int lastLineCommentPrefixCharacter;\n\n\t\tCharacterReader(Resource resource, @Nullable Charset encoding) throws IOException {\n\t\t\tthis.reader = new LineNumberReader(new InputStreamReader(resource.getInputStream(),\n\t\t\t\t\t(encoding != null) ? encoding : StandardCharsets.ISO_8859_1));\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tthis.reader.close();\n\t\t}\n\n\t\tboolean read() throws IOException {\n\t\t\tthis.escaped = false;\n\t\t\tthis.character = this.reader.read();\n\t\t\tthis.columnNumber++;\n\t\t\tif (this.columnNumber == 0) {\n\t\t\t\tskipWhitespace();\n\t\t\t}\n\t\t\tif (this.character == '\\\\') {\n\t\t\t\tthis.escaped = true;\n\t\t\t\treadEscaped();\n\t\t\t}\n\t\t\telse if (this.character == '\\n') {\n\t\t\t\tthis.columnNumber = -1;\n\t\t\t}\n\t\t\treturn !isEndOfFile();\n\t\t}\n\n\t\tprivate void skipWhitespace() throws IOException {\n\t\t\twhile (isWhiteSpace()) {\n\t\t\t\tthis.character = this.reader.read();\n\t\t\t\tthis.columnNumber++;\n\t\t\t}\n\t\t}\n\n\t\tprivate void setLastLineCommentPrefixCharacter(int lastLineCommentPrefixCharacter) {\n\t\t\tthis.lastLineCommentPrefixCharacter = lastLineCommentPrefixCharacter;\n\t\t}\n\n\t\tprivate void skipComment() throws IOException {\n\t\t\twhile (this.character != '\\n' && this.character != -1) {\n\t\t\t\tthis.character = this.reader.read();\n\t\t\t}\n\t\t\tthis.columnNumber = -1;\n\t\t}\n\n\t\tprivate void readEscaped() throws IOException {\n\t\t\tthis.character = this.reader.read();\n\t\t\tint escapeIndex = ESCAPES[0].indexOf(this.character);\n\t\t\tif (escapeIndex != -1) {\n\t\t\t\tthis.character = ESCAPES[1].charAt(escapeIndex);\n\t\t\t}\n\t\t\telse if (this.character == '\\n') {\n\t\t\t\tthis.columnNumber = -1;\n\t\t\t\tread();\n\t\t\t}\n\t\t\telse if (this.character == 'u') {\n\t\t\t\treadUnicode();\n\t\t\t}\n\t\t}\n\n\t\tprivate void readUnicode() throws IOException {\n\t\t\tthis.character = 0;\n\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\tint digit = this.reader.read();\n\t\t\t\tif (digit >= '0' && digit <= '9') {\n\t\t\t\t\tthis.character = (this.character << 4) + digit - '0';\n\t\t\t\t}\n\t\t\t\telse if (digit >= 'a' && digit <= 'f') {\n\t\t\t\t\tthis.character = (this.character << 4) + digit - 'a' + 10;\n\t\t\t\t}\n\t\t\t\telse if (digit >= 'A' && digit <= 'F') {\n\t\t\t\t\tthis.character = (this.character << 4) + digit - 'A' + 10;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IllegalStateException(\"Malformed \\\\uxxxx encoding.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tboolean isWhiteSpace() {\n\t\t\treturn !this.escaped && (this.character == ' ' || this.character == '\\t' || this.character == '\\f');\n\t\t}\n\n\t\tboolean isEndOfFile() {\n\t\t\treturn this.character == -1;\n\t\t}\n\n\t\tboolean isEndOfLine() {\n\t\t\treturn this.character == -1 || (!this.escaped && this.character == '\\n');\n\t\t}\n\n\t\tboolean isListDelimiter() {\n\t\t\treturn !this.escaped && this.character == ',';\n\t\t}\n\n\t\tboolean isPropertyDelimiter() {\n\t\t\treturn !this.escaped && (this.character == '=' || this.character == ':');\n\t\t}\n\n\t\tchar getCharacter() {\n\t\t\treturn (char) this.character;\n\t\t}\n\n\t\tLocation getLocation() {\n\t\t\treturn new Location(this.reader.getLineNumber(), this.columnNumber);\n\t\t}\n\n\t\tboolean isSameLastLineCommentPrefix() {\n\t\t\treturn this.lastLineCommentPrefixCharacter == this.character;\n\t\t}\n\n\t\tboolean isCommentPrefixCharacter() {\n\t\t\treturn this.character == '#' || this.character == '!';\n\t\t}\n\n\t\tboolean isHyphenCharacter() {\n\t\t\treturn this.character == '-';\n\t\t}\n\n\t}\n\n\t/**\n\t * A single document within the properties file.\n\t */\n\tstatic class Document {\n\n\t\tprivate final Map<String, OriginTrackedValue> values = new LinkedHashMap<>();\n\n\t\tvoid put(String key, OriginTrackedValue value) {\n\t\t\tif (!key.isEmpty()) {\n\t\t\t\tthis.values.put(key, value);\n\t\t\t}\n\t\t}\n\n\t\tboolean isEmpty() {\n\t\t\treturn this.values.isEmpty();\n\t\t}\n\n\t\tMap<String, OriginTrackedValue> asMap() {\n\t\t\treturn this.values;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedYamlLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\nimport org.yaml.snakeyaml.DumperOptions;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.BaseConstructor;\nimport org.yaml.snakeyaml.constructor.Constructor;\nimport org.yaml.snakeyaml.constructor.SafeConstructor;\nimport org.yaml.snakeyaml.error.Mark;\nimport org.yaml.snakeyaml.nodes.MappingNode;\nimport org.yaml.snakeyaml.nodes.Node;\nimport org.yaml.snakeyaml.nodes.NodeTuple;\nimport org.yaml.snakeyaml.nodes.ScalarNode;\nimport org.yaml.snakeyaml.nodes.SequenceNode;\nimport org.yaml.snakeyaml.nodes.Tag;\nimport org.yaml.snakeyaml.representer.Representer;\nimport org.yaml.snakeyaml.resolver.Resolver;\n\nimport org.springframework.beans.factory.config.YamlProcessor;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.core.io.Resource;\n\n/**\n * Class to load {@code .yml} files into a map of {@code String} to\n * {@link OriginTrackedValue}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass OriginTrackedYamlLoader extends YamlProcessor {\n\n\tprivate final Resource resource;\n\n\tOriginTrackedYamlLoader(Resource resource) {\n\t\tthis.resource = resource;\n\t\tsetResources(resource);\n\t}\n\n\t@Override\n\tprotected Yaml createYaml() {\n\t\tLoaderOptions loaderOptions = new LoaderOptions();\n\t\tloaderOptions.setAllowDuplicateKeys(false);\n\t\tloaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE);\n\t\tloaderOptions.setAllowRecursiveKeys(true);\n\t\tloaderOptions.setCodePointLimit(Integer.MAX_VALUE);\n\t\treturn createYaml(loaderOptions);\n\t}\n\n\tprivate Yaml createYaml(LoaderOptions loaderOptions) {\n\t\tBaseConstructor constructor = new OriginTrackingConstructor(loaderOptions);\n\t\tDumperOptions dumperOptions = new DumperOptions();\n\t\tRepresenter representer = new Representer(dumperOptions);\n\t\tNoTimestampResolver resolver = new NoTimestampResolver();\n\t\treturn new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);\n\t}\n\n\tList<Map<String, Object>> load() {\n\t\tList<Map<String, Object>> result = new ArrayList<>();\n\t\tprocess((properties, map) -> result.add(getFlattenedMap(map, true, \"\")));\n\t\treturn result;\n\t}\n\n\t/**\n\t * {@link Constructor} that tracks property origins.\n\t */\n\tprivate class OriginTrackingConstructor extends SafeConstructor {\n\n\t\tOriginTrackingConstructor(LoaderOptions loadingConfig) {\n\t\t\tsuper(loadingConfig);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getData() throws NoSuchElementException {\n\t\t\tObject data = super.getData();\n\t\t\tif (data instanceof CharSequence charSequence && charSequence.isEmpty()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn data;\n\t\t}\n\n\t\t@Override\n\t\tprotected Object constructObject(Node node) {\n\t\t\tif (node instanceof SequenceNode sequenceNode && sequenceNode.getValue().isEmpty()) {\n\t\t\t\treturn constructTrackedObject(node, \"\");\n\t\t\t}\n\t\t\tif (node instanceof ScalarNode) {\n\t\t\t\tif (!(node instanceof KeyScalarNode)) {\n\t\t\t\t\treturn constructTrackedObject(node, super.constructObject(node));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (node instanceof MappingNode mappingNode) {\n\t\t\t\treplaceMappingNodeKeys(mappingNode);\n\t\t\t}\n\t\t\treturn super.constructObject(node);\n\t\t}\n\n\t\tprivate void replaceMappingNodeKeys(MappingNode node) {\n\t\t\tList<NodeTuple> value = node.getValue();\n\t\t\tList<NodeTuple> newValue = new ArrayList<>(value.size());\n\t\t\tfor (NodeTuple tuple : value) {\n\t\t\t\tnewValue.add(KeyScalarNode.get(tuple));\n\t\t\t}\n\t\t\tnode.setValue(newValue);\n\t\t}\n\n\t\tprivate Object constructTrackedObject(Node node, Object value) {\n\t\t\tOrigin origin = getOrigin(node);\n\t\t\treturn OriginTrackedValue.of(getValue(value), origin);\n\t\t}\n\n\t\tprivate Object getValue(@Nullable Object value) {\n\t\t\treturn (value != null) ? value : \"\";\n\t\t}\n\n\t\tprivate Origin getOrigin(Node node) {\n\t\t\tMark mark = node.getStartMark();\n\t\t\tLocation location = new Location(mark.getLine(), mark.getColumn());\n\t\t\treturn new TextResourceOrigin(OriginTrackedYamlLoader.this.resource, location);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ScalarNode} that replaces the key node in a {@link NodeTuple}.\n\t */\n\tprivate static class KeyScalarNode extends ScalarNode {\n\n\t\tKeyScalarNode(ScalarNode node) {\n\t\t\tsuper(node.getTag(), node.getValue(), node.getStartMark(), node.getEndMark(), node.getScalarStyle());\n\t\t}\n\n\t\tstatic NodeTuple get(NodeTuple nodeTuple) {\n\t\t\tNode keyNode = nodeTuple.getKeyNode();\n\t\t\tNode valueNode = nodeTuple.getValueNode();\n\t\t\treturn new NodeTuple(KeyScalarNode.get(keyNode), valueNode);\n\t\t}\n\n\t\tprivate static Node get(Node node) {\n\t\t\tif (node instanceof ScalarNode scalarNode) {\n\t\t\t\treturn new KeyScalarNode(scalarNode);\n\t\t\t}\n\t\t\treturn node;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Resolver} that limits {@link Tag#TIMESTAMP} tags.\n\t */\n\tprivate static final class NoTimestampResolver extends Resolver {\n\n\t\t@Override\n\t\tpublic void addImplicitResolver(Tag tag, Pattern regexp, String first, int limit) {\n\t\t\tif (tag == Tag.TIMESTAMP) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsuper.addImplicitResolver(tag, regexp, first, limit);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/PropertiesPropertySourceLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.env.OriginTrackedPropertiesLoader.Document;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.EncodedResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\n\n/**\n * Strategy to load '.properties' files into a {@link PropertySource}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 1.0.0\n */\npublic class PropertiesPropertySourceLoader implements PropertySourceLoader {\n\n\tprivate static final String XML_FILE_EXTENSION = \".xml\";\n\n\t@Override\n\tpublic String[] getFileExtensions() {\n\t\treturn new String[] { \"properties\", \"xml\" };\n\t}\n\n\t@Override\n\tpublic List<PropertySource<?>> load(String name, Resource resource) throws IOException {\n\t\treturn load(name, resource, null);\n\t}\n\n\t@Override\n\tpublic List<PropertySource<?>> load(String name, Resource resource, @Nullable Charset encoding) throws IOException {\n\t\tList<Map<String, ?>> properties = loadProperties(resource, encoding);\n\t\tif (properties.isEmpty()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<PropertySource<?>> propertySources = new ArrayList<>(properties.size());\n\t\tfor (int i = 0; i < properties.size(); i++) {\n\t\t\tString documentNumber = (properties.size() != 1) ? \" (document #\" + i + \")\" : \"\";\n\t\t\tpropertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,\n\t\t\t\t\tCollections.unmodifiableMap(properties.get(i)), true));\n\t\t}\n\t\treturn propertySources;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate List<Map<String, ?>> loadProperties(Resource resource, @Nullable Charset encoding) throws IOException {\n\t\tString filename = resource.getFilename();\n\t\tList<Map<String, ?>> result = new ArrayList<>();\n\t\tif (filename != null && filename.endsWith(XML_FILE_EXTENSION)) {\n\t\t\tif (encoding == null) {\n\t\t\t\tresult.add((Map) PropertiesLoaderUtils.loadProperties(resource));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.add((Map) PropertiesLoaderUtils.loadProperties(new EncodedResource(resource, encoding)));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tList<Document> documents = new OriginTrackedPropertiesLoader(resource).load(encoding);\n\t\t\tdocuments.forEach((document) -> result.add(document.asMap()));\n\t\t}\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/PropertySourceInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertySource;\n\n/**\n * Interface that can be optionally implemented by a {@link PropertySource} to provide\n * additional information.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface PropertySourceInfo {\n\n\t/**\n\t * Return {@code true} if this lookup is immutable and has contents that will never\n\t * change.\n\t * @return if the lookup is immutable\n\t */\n\tdefault boolean isImmutable() {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return the implicit prefix that is applied when performing a lookup or {@code null}\n\t * if no prefix is used. Prefixes can be used to disambiguate keys that would\n\t * otherwise clash. For example, if multiple applications are running on the same\n\t * machine a different prefix can be set on each application to ensure that different\n\t * environment variables are used.\n\t * @return the prefix applied by the lookup class or {@code null}.\n\t */\n\tdefault @Nullable String getPrefix() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/PropertySourceLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * Strategy interface located through {@link SpringFactoriesLoader} and used to load a\n * {@link PropertySource}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic interface PropertySourceLoader {\n\n\t/**\n\t * Returns the file extensions that the loader supports (excluding the '.').\n\t * @return the file extensions\n\t */\n\tString[] getFileExtensions();\n\n\t/**\n\t * Load the resource into one or more property sources. Implementations may either\n\t * return a list containing a single source, or in the case of a multi-document format\n\t * such as yaml a source for each document in the resource.\n\t * @param name the root name of the property source. If multiple documents are loaded\n\t * an additional suffix should be added to the name for each source loaded.\n\t * @param resource the resource to load\n\t * @return a list property sources\n\t * @throws IOException if the source cannot be loaded\n\t */\n\tList<PropertySource<?>> load(String name, Resource resource) throws IOException;\n\n\t/**\n\t * Load the resource into one or more property sources. Implementations may either\n\t * return a list containing a single source, or in the case of a multi-document format\n\t * such as yaml a source for each document in the resource.\n\t * @param name the root name of the property source. If multiple documents are loaded\n\t * an additional suffix should be added to the name for each source loaded.\n\t * @param resource the resource to load\n\t * @param encoding encoding of the resource\n\t * @return a list property sources\n\t * @throws IOException if the source cannot be loaded\n\t * @since 4.1.0\n\t */\n\tdefault List<PropertySource<?>> load(String name, Resource resource, @Nullable Charset encoding)\n\t\t\tthrows IOException {\n\t\treturn load(name, resource);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/PropertySourceRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\n\n/**\n * {@link RuntimeHintsRegistrar} implementation for property source support.\n *\n * @author Stephane Nicoll\n */\nclass PropertySourceRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\thints.reflection()\n\t\t\t.registerTypeIfPresent(classLoader, \"org.yaml.snakeyaml.Yaml\",\n\t\t\t\t\t(typeHint) -> typeHint.onReachableType(TypeReference.of(YamlPropertySourceLoader.class)));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/RandomValuePropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.HexFormat;\nimport java.util.OptionalInt;\nimport java.util.OptionalLong;\nimport java.util.Random;\nimport java.util.UUID;\nimport java.util.function.Function;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link PropertySource} that returns a random value for any property that starts with\n * {@literal \"random.\"}. Where the \"unqualified property name\" is the portion of the\n * requested property name beyond the \"random.\" prefix, this {@link PropertySource}\n * returns:\n * <ul>\n * <li>When {@literal \"int\"}, a random {@link Integer} value, restricted by an optionally\n * specified range.</li>\n * <li>When {@literal \"long\"}, a random {@link Long} value, restricted by an optionally\n * specified range.</li>\n * <li>When {@literal \"uuid\"}, a random {@link UUID} value.</li>\n * <li>Otherwise, a {@code byte[]}.</li>\n * </ul>\n * The {@literal \"random.int\"} and {@literal \"random.long\"} properties supports a range\n * suffix whose syntax is:\n * <p>\n * {@code OPEN value (,max) CLOSE} where the {@code OPEN,CLOSE} are any character and\n * {@code value,max} are integers. If {@code max} is not provided, then 0 is used as the\n * lower bound and {@code value} is the upper bound. If {@code max} is provided then\n * {@code value} is the minimum value and {@code max} is the maximum (exclusive).\n *\n * @author Dave Syer\n * @author Matt Benson\n * @author Madhura Bhave\n * @author Moritz Halbritter\n * @since 1.0.0\n */\npublic class RandomValuePropertySource extends PropertySource<Random> {\n\n\t/**\n\t * Name of the random {@link PropertySource}.\n\t */\n\tpublic static final String RANDOM_PROPERTY_SOURCE_NAME = \"random\";\n\n\tprivate static final String PREFIX = \"random.\";\n\n\tprivate static final Log logger = LogFactory.getLog(RandomValuePropertySource.class);\n\n\tpublic RandomValuePropertySource() {\n\t\tthis(RANDOM_PROPERTY_SOURCE_NAME);\n\t}\n\n\tpublic RandomValuePropertySource(String name) {\n\t\tsuper(name, new Random());\n\t}\n\n\t@Override\n\tpublic @Nullable Object getProperty(String name) {\n\t\tif (!name.startsWith(PREFIX)) {\n\t\t\treturn null;\n\t\t}\n\t\tlogger.trace(LogMessage.format(\"Generating random property for '%s'\", name));\n\t\treturn getRandomValue(name.substring(PREFIX.length()));\n\t}\n\n\tprivate Object getRandomValue(String type) {\n\t\tif (type.equals(\"int\")) {\n\t\t\treturn getSource().nextInt();\n\t\t}\n\t\tif (type.equals(\"long\")) {\n\t\t\treturn getSource().nextLong();\n\t\t}\n\t\tString range = getRange(type, \"int\");\n\t\tif (range != null) {\n\t\t\treturn getNextIntInRange(Range.of(range, Integer::parseInt));\n\t\t}\n\t\trange = getRange(type, \"long\");\n\t\tif (range != null) {\n\t\t\treturn getNextLongInRange(Range.of(range, Long::parseLong));\n\t\t}\n\t\tif (type.equals(\"uuid\")) {\n\t\t\treturn UUID.randomUUID().toString();\n\t\t}\n\t\treturn getRandomBytes();\n\t}\n\n\tprivate @Nullable String getRange(String type, String prefix) {\n\t\tif (type.startsWith(prefix)) {\n\t\t\tint startIndex = prefix.length() + 1;\n\t\t\tif (type.length() > startIndex) {\n\t\t\t\treturn type.substring(startIndex, type.length() - 1);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate int getNextIntInRange(Range<Integer> range) {\n\t\tOptionalInt first = getSource().ints(1, range.getMin(), range.getMax()).findFirst();\n\t\tassertPresent(first.isPresent(), range);\n\t\treturn first.getAsInt();\n\t}\n\n\tprivate long getNextLongInRange(Range<Long> range) {\n\t\tOptionalLong first = getSource().longs(1, range.getMin(), range.getMax()).findFirst();\n\t\tassertPresent(first.isPresent(), range);\n\t\treturn first.getAsLong();\n\t}\n\n\tprivate void assertPresent(boolean present, Range<?> range) {\n\t\tAssert.state(present, () -> \"Could not get random number for range '\" + range + \"'\");\n\t}\n\n\tprivate Object getRandomBytes() {\n\t\tbyte[] bytes = new byte[16];\n\t\tgetSource().nextBytes(bytes);\n\t\treturn HexFormat.of().withLowerCase().formatHex(bytes);\n\t}\n\n\t/**\n\t * Add a {@link RandomValuePropertySource} to the given {@link Environment}.\n\t * @param environment the environment to add the random property source to\n\t */\n\tpublic static void addToEnvironment(ConfigurableEnvironment environment) {\n\t\taddToEnvironment(environment, logger);\n\t}\n\n\t/**\n\t * Add a {@link RandomValuePropertySource} to the given {@link Environment}.\n\t * @param environment the environment to add the random property source to\n\t * @param logger logger used for debug and trace information\n\t * @since 4.0.0\n\t */\n\tpublic static void addToEnvironment(ConfigurableEnvironment environment, Log logger) {\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tPropertySource<?> existing = sources.get(RANDOM_PROPERTY_SOURCE_NAME);\n\t\tif (existing != null) {\n\t\t\tlogger.trace(\"RandomValuePropertySource already present\");\n\t\t\treturn;\n\t\t}\n\t\tRandomValuePropertySource randomSource = new RandomValuePropertySource(RANDOM_PROPERTY_SOURCE_NAME);\n\t\tif (sources.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME) != null) {\n\t\t\tsources.addAfter(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, randomSource);\n\t\t}\n\t\telse {\n\t\t\tsources.addLast(randomSource);\n\t\t}\n\t\tlogger.trace(\"RandomValuePropertySource add to Environment\");\n\t}\n\n\tstatic final class Range<T extends Number> {\n\n\t\tprivate final String value;\n\n\t\tprivate final T min;\n\n\t\tprivate final T max;\n\n\t\tprivate Range(String value, T min, T max) {\n\t\t\tthis.value = value;\n\t\t\tthis.min = min;\n\t\t\tthis.max = max;\n\t\t}\n\n\t\tT getMin() {\n\t\t\treturn this.min;\n\t\t}\n\n\t\tT getMax() {\n\t\t\treturn this.max;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tstatic <T extends Number & Comparable<T>> Range<T> of(String value, Function<String, T> parse) {\n\t\t\tT zero = parse.apply(\"0\");\n\t\t\tString[] tokens = StringUtils.commaDelimitedListToStringArray(value);\n\t\t\tT min = parse.apply(tokens[0]);\n\t\t\tif (tokens.length == 1) {\n\t\t\t\tAssert.state(min.compareTo(zero) > 0, \"Bound must be positive.\");\n\t\t\t\treturn new Range<>(value, zero, min);\n\t\t\t}\n\t\t\tT max = parse.apply(tokens[1]);\n\t\t\tAssert.state(min.compareTo(max) < 0, \"Lower bound must be less than upper bound.\");\n\t\t\treturn new Range<>(value, min, max);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/YamlPropertySourceLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Strategy to load '.yml' (or '.yaml') files into a {@link PropertySource}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.0.0\n */\npublic class YamlPropertySourceLoader implements PropertySourceLoader {\n\n\t@Override\n\tpublic String[] getFileExtensions() {\n\t\treturn new String[] { \"yml\", \"yaml\" };\n\t}\n\n\t@Override\n\tpublic List<PropertySource<?>> load(String name, Resource resource) throws IOException {\n\t\tif (!ClassUtils.isPresent(\"org.yaml.snakeyaml.Yaml\", getClass().getClassLoader())) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Attempted to load \" + name + \" but snakeyaml was not found on the classpath\");\n\t\t}\n\t\tList<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();\n\t\tif (loaded.isEmpty()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());\n\t\tfor (int i = 0; i < loaded.size(); i++) {\n\t\t\tString documentNumber = (loaded.size() != 1) ? \" (document #\" + i + \")\" : \"\";\n\t\t\tpropertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,\n\t\t\t\t\tCollections.unmodifiableMap(loaded.get(i)), true));\n\t\t}\n\t\treturn propertySources;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/env/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring {@link org.springframework.core.env.Environment} support.\n */\n@NullMarked\npackage org.springframework.boot.env;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/BuildProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.time.DateTimeException;\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.info.BuildProperties.BuildPropertiesRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * Provide build-related information such as group and artifact.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@ImportRuntimeHints(BuildPropertiesRuntimeHints.class)\npublic class BuildProperties extends InfoProperties {\n\n\t/**\n\t * Create an instance with the specified entries.\n\t * @param entries the information to expose\n\t */\n\tpublic BuildProperties(Properties entries) {\n\t\tsuper(processEntries(entries));\n\t}\n\n\t/**\n\t * Return the groupId of the project or {@code null}.\n\t * @return the group\n\t */\n\tpublic @Nullable String getGroup() {\n\t\treturn get(\"group\");\n\t}\n\n\t/**\n\t * Return the artifactId of the project or {@code null}.\n\t * @return the artifact\n\t */\n\tpublic @Nullable String getArtifact() {\n\t\treturn get(\"artifact\");\n\t}\n\n\t/**\n\t * Return the name of the project or {@code null}.\n\t * @return the name\n\t */\n\tpublic @Nullable String getName() {\n\t\treturn get(\"name\");\n\t}\n\n\t/**\n\t * Return the version of the project or {@code null}.\n\t * @return the version\n\t */\n\tpublic @Nullable String getVersion() {\n\t\treturn get(\"version\");\n\t}\n\n\t/**\n\t * Return the timestamp of the build or {@code null}.\n\t * <p>\n\t * If the original value could not be parsed properly, it is still available with the\n\t * {@code time} key.\n\t * @return the build time\n\t * @see #get(String)\n\t */\n\tpublic @Nullable Instant getTime() {\n\t\treturn getInstant(\"time\");\n\t}\n\n\tprivate static Properties processEntries(Properties properties) {\n\t\tcoerceDate(properties, \"time\");\n\t\treturn properties;\n\t}\n\n\tprivate static void coerceDate(Properties properties, String key) {\n\t\tString value = properties.getProperty(key);\n\t\tif (value != null) {\n\t\t\ttry {\n\t\t\t\tString updatedValue = String\n\t\t\t\t\t.valueOf(DateTimeFormatter.ISO_INSTANT.parse(value, Instant::from).toEpochMilli());\n\t\t\t\tproperties.setProperty(key, updatedValue);\n\t\t\t}\n\t\t\tcatch (DateTimeException ex) {\n\t\t\t\t// Ignore and store the original value\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic class BuildPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"META-INF/build-info.properties\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/GitProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.time.format.DateTimeParseException;\nimport java.util.Objects;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.info.GitProperties.GitPropertiesRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * Provide git-related information such as commit id and time.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@ImportRuntimeHints(GitPropertiesRuntimeHints.class)\npublic class GitProperties extends InfoProperties {\n\n\tstatic final Set<Coercer> coercers = Set.of(Coercer.milliseconds(),\n\t\t\tCoercer.dateTimePattern(\"yyyy-MM-dd'T'HH:mm:ssXXX\"), Coercer.dateTimePattern(\"yyyy-MM-dd'T'HH:mm:ssZ\"));\n\n\tpublic GitProperties(Properties entries) {\n\t\tsuper(processEntries(entries));\n\t}\n\n\t/**\n\t * Return the name of the branch or {@code null}.\n\t * @return the branch\n\t */\n\tpublic @Nullable String getBranch() {\n\t\treturn get(\"branch\");\n\t}\n\n\t/**\n\t * Return the full id of the commit or {@code null}.\n\t * @return the full commit id\n\t */\n\tpublic @Nullable String getCommitId() {\n\t\treturn get(\"commit.id\");\n\t}\n\n\t/**\n\t * Return the abbreviated id of the commit or {@code null}.\n\t * @return the short commit id\n\t */\n\tpublic @Nullable String getShortCommitId() {\n\t\tString shortId = get(\"commit.id.abbrev\");\n\t\tif (shortId != null) {\n\t\t\treturn shortId;\n\t\t}\n\t\tString id = getCommitId();\n\t\tif (id == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (id.length() > 7) ? id.substring(0, 7) : id;\n\t}\n\n\t/**\n\t * Return the timestamp of the commit or {@code null}.\n\t * <p>\n\t * If the original value could not be parsed properly, it is still available with the\n\t * {@code commit.time} key.\n\t * @return the commit time\n\t * @see #get(String)\n\t */\n\tpublic @Nullable Instant getCommitTime() {\n\t\treturn getInstant(\"commit.time\");\n\t}\n\n\tprivate static Properties processEntries(Properties properties) {\n\t\tcoercePropertyToEpoch(properties, \"commit.time\");\n\t\tcoercePropertyToEpoch(properties, \"build.time\");\n\t\tObject commitId = properties.get(\"commit.id\");\n\t\tif (commitId != null) {\n\t\t\t// Can get converted into a map, so we copy the entry as a nested key\n\t\t\tproperties.put(\"commit.id.full\", commitId);\n\t\t}\n\t\treturn properties;\n\t}\n\n\tprivate static void coercePropertyToEpoch(Properties properties, String key) {\n\t\tString value = properties.getProperty(key);\n\t\tif (value != null) {\n\t\t\tproperties.setProperty(key,\n\t\t\t\t\tcoercers.stream()\n\t\t\t\t\t\t.map((coercer) -> coercer.apply(value))\n\t\t\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t\t\t.findFirst()\n\t\t\t\t\t\t.orElse(value));\n\t\t}\n\t}\n\n\t/**\n\t * {@link RuntimeHintsRegistrar} for git properties.\n\t */\n\tstatic class GitPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"git.properties\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Coercer used to convert a source value to epoch time.\n\t */\n\tprivate record Coercer(Function<String, @Nullable Long> action, Predicate<RuntimeException> ignoredExceptions) {\n\n\t\t/**\n\t\t * Attempt to convert the specified value to epoch time.\n\t\t * @param value the value to coerce to\n\t\t * @return the epoch time in milliseconds or {@code null}\n\t\t */\n\t\t@Nullable String apply(String value) {\n\t\t\ttry {\n\t\t\t\tLong result = this.action.apply(value);\n\t\t\t\treturn (result != null) ? String.valueOf(result) : null;\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\tif (this.ignoredExceptions.test(ex)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tstatic Coercer milliseconds() {\n\t\t\treturn new Coercer((value) -> Long.parseLong(value) * 1000, NumberFormatException.class::isInstance);\n\t\t}\n\n\t\tstatic Coercer dateTimePattern(String pattern) {\n\t\t\treturn new Coercer(\n\t\t\t\t\t(value) -> DateTimeFormatter.ofPattern(pattern).parse(value, Instant::from).toEpochMilli(),\n\t\t\t\t\tDateTimeParseException.class::isInstance);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/InfoProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.time.Instant;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertiesPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * Base class for components exposing unstructured data with dedicated methods for well\n * known keys.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\npublic class InfoProperties implements Iterable<InfoProperties.Entry> {\n\n\tprivate final Properties entries;\n\n\t/**\n\t * Create an instance with the specified entries.\n\t * @param entries the information to expose\n\t */\n\tpublic InfoProperties(Properties entries) {\n\t\tAssert.notNull(entries, \"'entries' must not be null\");\n\t\tthis.entries = copy(entries);\n\t}\n\n\t/**\n\t * Return the value of the specified property or {@code null}.\n\t * @param key the key of the property\n\t * @return the property value\n\t */\n\tpublic @Nullable String get(String key) {\n\t\treturn this.entries.getProperty(key);\n\t}\n\n\t/**\n\t * Return the value of the specified property as an {@link Instant} or {@code null} if\n\t * the value is not a valid {@link Long} representation of an epoch time.\n\t * @param key the key of the property\n\t * @return the property value\n\t */\n\tpublic @Nullable Instant getInstant(String key) {\n\t\tString s = get(key);\n\t\tif (s != null) {\n\t\t\ttry {\n\t\t\t\treturn Instant.ofEpochMilli(Long.parseLong(s));\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t// Not valid epoch time\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Iterator<Entry> iterator() {\n\t\treturn new PropertiesIterator(this.entries);\n\t}\n\n\t/**\n\t * Return a {@link PropertySource} of this instance.\n\t * @return a {@link PropertySource}\n\t */\n\tpublic PropertySource<?> toPropertySource() {\n\t\treturn new PropertiesPropertySource(getClass().getSimpleName(), copy(this.entries));\n\t}\n\n\tprivate Properties copy(Properties properties) {\n\t\tProperties copy = new Properties();\n\t\tcopy.putAll(properties);\n\t\treturn copy;\n\t}\n\n\tprivate static final class PropertiesIterator implements Iterator<Entry> {\n\n\t\tprivate final Iterator<Map.Entry<Object, Object>> iterator;\n\n\t\tprivate PropertiesIterator(Properties properties) {\n\t\t\tthis.iterator = properties.entrySet().iterator();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasNext() {\n\t\t\treturn this.iterator.hasNext();\n\t\t}\n\n\t\t@Override\n\t\tpublic Entry next() {\n\t\t\tMap.Entry<Object, Object> entry = this.iterator.next();\n\t\t\treturn new Entry((String) entry.getKey(), (String) entry.getValue());\n\t\t}\n\n\t\t@Override\n\t\tpublic void remove() {\n\t\t\tthrow new UnsupportedOperationException(\"InfoProperties are immutable.\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Property entry.\n\t */\n\tpublic static final class Entry {\n\n\t\tprivate final String key;\n\n\t\tprivate final String value;\n\n\t\tprivate Entry(String key, String value) {\n\t\t\tthis.key = key;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String getKey() {\n\t\t\treturn this.key;\n\t\t}\n\n\t\tpublic String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/JavaInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\n/**\n * Information about the Java environment the application is running in.\n *\n * @author Jonatan Ivanov\n * @author Stephane Nicoll\n * @since 2.6.0\n */\npublic class JavaInfo {\n\n\tprivate final String version;\n\n\tprivate final JavaVendorInfo vendor;\n\n\tprivate final JavaRuntimeEnvironmentInfo runtime;\n\n\tprivate final JavaVirtualMachineInfo jvm;\n\n\tpublic JavaInfo() {\n\t\tthis.version = System.getProperty(\"java.version\");\n\t\tthis.vendor = new JavaVendorInfo();\n\t\tthis.runtime = new JavaRuntimeEnvironmentInfo();\n\t\tthis.jvm = new JavaVirtualMachineInfo();\n\t}\n\n\tpublic String getVersion() {\n\t\treturn this.version;\n\t}\n\n\tpublic JavaVendorInfo getVendor() {\n\t\treturn this.vendor;\n\t}\n\n\tpublic JavaRuntimeEnvironmentInfo getRuntime() {\n\t\treturn this.runtime;\n\t}\n\n\tpublic JavaVirtualMachineInfo getJvm() {\n\t\treturn this.jvm;\n\t}\n\n\t/**\n\t * Information about the Java Vendor of the Java Runtime the application is running\n\t * in.\n\t *\n\t * @since 2.7.0\n\t */\n\tpublic static class JavaVendorInfo {\n\n\t\tprivate final String name;\n\n\t\tprivate final String version;\n\n\t\tpublic JavaVendorInfo() {\n\t\t\tthis.name = System.getProperty(\"java.vendor\");\n\t\t\tthis.version = System.getProperty(\"java.vendor.version\");\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t}\n\n\t/**\n\t * Information about the Java Runtime Environment the application is running in.\n\t */\n\tpublic static class JavaRuntimeEnvironmentInfo {\n\n\t\tprivate final String name;\n\n\t\tprivate final String version;\n\n\t\tpublic JavaRuntimeEnvironmentInfo() {\n\t\t\tthis.name = System.getProperty(\"java.runtime.name\");\n\t\t\tthis.version = System.getProperty(\"java.runtime.version\");\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t}\n\n\t/**\n\t * Information about the Java Virtual Machine the application is running in.\n\t */\n\tpublic static class JavaVirtualMachineInfo {\n\n\t\tprivate final String name;\n\n\t\tprivate final String vendor;\n\n\t\tprivate final String version;\n\n\t\tpublic JavaVirtualMachineInfo() {\n\t\t\tthis.name = System.getProperty(\"java.vm.name\");\n\t\t\tthis.vendor = System.getProperty(\"java.vm.vendor\");\n\t\t\tthis.version = System.getProperty(\"java.vm.version\");\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getVendor() {\n\t\t\treturn this.vendor;\n\t\t}\n\n\t\tpublic String getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/OsInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\n/**\n * Information about the Operating System the application is running on.\n *\n * @author Jonatan Ivanov\n * @since 2.7.0\n */\npublic class OsInfo {\n\n\tprivate final String name;\n\n\tprivate final String version;\n\n\tprivate final String arch;\n\n\tpublic OsInfo() {\n\t\tthis.name = System.getProperty(\"os.name\");\n\t\tthis.version = System.getProperty(\"os.version\");\n\t\tthis.arch = System.getProperty(\"os.arch\");\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getVersion() {\n\t\treturn this.version;\n\t}\n\n\tpublic String getArch() {\n\t\treturn this.arch;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/ProcessInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.lang.ProcessHandle.Info;\nimport java.lang.management.GarbageCollectorMXBean;\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.MemoryMXBean;\nimport java.lang.management.MemoryUsage;\nimport java.lang.management.PlatformManagedObject;\nimport java.lang.reflect.Method;\nimport java.nio.file.Path;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.util.List;\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ClassUtils;\n\n/**\n * Information about the process of the application.\n *\n * @author Jonatan Ivanov\n * @author Andrey Litvitski\n * @since 3.3.0\n */\npublic class ProcessInfo {\n\n\tprivate static final String VIRTUAL_THREAD_SCHEDULER_CLASS = \"jdk.management.VirtualThreadSchedulerMXBean\";\n\n\tprivate static final boolean VIRTUAL_THREAD_SCHEDULER_CLASS_PRESENT = ClassUtils\n\t\t.isPresent(VIRTUAL_THREAD_SCHEDULER_CLASS, null);\n\n\tprivate static final Runtime runtime = Runtime.getRuntime();\n\n\tprivate final long pid;\n\n\tprivate final long parentPid;\n\n\tprivate final @Nullable String owner;\n\n\tprivate final @Nullable Instant startTime;\n\n\tprivate final ZoneId timezone;\n\n\tprivate final Locale locale;\n\n\tprivate final String workingDirectory;\n\n\tpublic ProcessInfo() {\n\t\tProcessHandle process = ProcessHandle.current();\n\t\tthis.pid = process.pid();\n\t\tthis.parentPid = process.parent().map(ProcessHandle::pid).orElse(-1L);\n\t\tthis.owner = process.info().user().orElse(null);\n\t\tthis.startTime = process.info().startInstant().orElse(null);\n\t\tthis.timezone = ZoneId.systemDefault();\n\t\tthis.locale = Locale.getDefault();\n\t\tthis.workingDirectory = Path.of(\".\").toAbsolutePath().normalize().toString();\n\t}\n\n\t/**\n\t * Number of processors available to the process. This value may change between\n\t * invocations especially in (containerized) environments where resource usage can be\n\t * isolated (for example using control groups).\n\t * @return result of {@link Runtime#availableProcessors()}\n\t * @see Runtime#availableProcessors()\n\t */\n\tpublic int getCpus() {\n\t\treturn runtime.availableProcessors();\n\t}\n\n\t/**\n\t * Memory information for the process. These values can provide details about the\n\t * current memory usage and limits selected by the user or JVM ergonomics (init, max,\n\t * committed, used for heap and non-heap). If limits not set explicitly, it might not\n\t * be trivial to know what these values are runtime; especially in (containerized)\n\t * environments where resource usage can be isolated (for example using control\n\t * groups) or not necessarily trivial to discover. Other than that, these values can\n\t * indicate if the JVM can resize the heap (stop-the-world).\n\t * @return heap and non-heap memory information\n\t * @since 3.4.0\n\t * @see MemoryMXBean#getHeapMemoryUsage()\n\t * @see MemoryMXBean#getNonHeapMemoryUsage()\n\t * @see MemoryUsage\n\t */\n\tpublic MemoryInfo getMemory() {\n\t\treturn new MemoryInfo();\n\t}\n\n\t/**\n\t * Virtual threads information for the process. These values provide details about the\n\t * current state of virtual threads, including the number of mounted threads, queued\n\t * threads, the parallelism level, and the thread pool size.\n\t * @return an instance of {@link VirtualThreadsInfo} containing information about\n\t * virtual threads, or {@code null} if the VirtualThreadSchedulerMXBean is not\n\t * available\n\t * @since 3.5.0\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic @Nullable VirtualThreadsInfo getVirtualThreads() {\n\t\tif (!VIRTUAL_THREAD_SCHEDULER_CLASS_PRESENT) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tClass<PlatformManagedObject> mxbeanClass = (Class<PlatformManagedObject>) ClassUtils\n\t\t\t\t.forName(VIRTUAL_THREAD_SCHEDULER_CLASS, null);\n\t\t\tPlatformManagedObject mxbean = ManagementFactory.getPlatformMXBean(mxbeanClass);\n\t\t\tint mountedVirtualThreadCount = invokeMethod(mxbeanClass, mxbean, \"getMountedVirtualThreadCount\");\n\t\t\tlong queuedVirtualThreadCount = invokeMethod(mxbeanClass, mxbean, \"getQueuedVirtualThreadCount\");\n\t\t\tint parallelism = invokeMethod(mxbeanClass, mxbean, \"getParallelism\");\n\t\t\tint poolSize = invokeMethod(mxbeanClass, mxbean, \"getPoolSize\");\n\t\t\treturn new VirtualThreadsInfo(mountedVirtualThreadCount, queuedVirtualThreadCount, parallelism, poolSize);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> T invokeMethod(Class<?> mxbeanClass, Object mxbean, String name) throws ReflectiveOperationException {\n\t\tMethod method = mxbeanClass.getMethod(name);\n\t\treturn (T) method.invoke(mxbean);\n\t}\n\n\tpublic long getPid() {\n\t\treturn this.pid;\n\t}\n\n\tpublic long getParentPid() {\n\t\treturn this.parentPid;\n\t}\n\n\tpublic @Nullable String getOwner() {\n\t\treturn this.owner;\n\t}\n\n\t/**\n\t * Uptime of the process. Can be useful to see how long the process has been running\n\t * and to check how long ago the last deployment or restart happened.\n\t * @return duration since the process started, if available, otherwise {@code null}\n\t * @since 4.1.0\n\t */\n\tpublic @Nullable Duration getUptime() {\n\t\treturn (this.startTime != null) ? Duration.between(this.startTime, Instant.now()) : null;\n\t}\n\n\t/**\n\t * Time at which the process started. Can be useful to see when the process was\n\t * started and to check when the last deployment or restart happened.\n\t * @return the time when the process started, if available, otherwise {@code null}\n\t * @since 4.1.0\n\t * @see Info#startInstant()\n\t */\n\tpublic @Nullable Instant getStartTime() {\n\t\treturn this.startTime;\n\t}\n\n\t/**\n\t * Current time of the process. Can be useful to check if there is any clock-skew\n\t * issue and if the current time that the process knows is accurate enough.\n\t * @return the current time of the process\n\t * @since 4.1.0\n\t * @see Instant#now\n\t */\n\tpublic Instant getCurrentTime() {\n\t\treturn Instant.now();\n\t}\n\n\t/**\n\t * Timezone of the process. Can help to detect time and timezone related issues.\n\t * @return the timezone of the process\n\t * @since 4.1.0\n\t * @see ZoneId#systemDefault()\n\t */\n\tpublic ZoneId getTimezone() {\n\t\treturn this.timezone;\n\t}\n\n\t/**\n\t * Locale of the process. Can help to detect issues connected to language and country\n\t * settings.\n\t * @return the locale of the process\n\t * @since 4.1.0\n\t * @see Locale#getDefault()\n\t */\n\tpublic Locale getLocale() {\n\t\treturn this.locale;\n\t}\n\n\t/**\n\t * Working directory of the process. Can help to locate files that the process uses.\n\t * @return the absolute path of the working directory of the process\n\t * @since 4.1.0\n\t */\n\tpublic String getWorkingDirectory() {\n\t\treturn this.workingDirectory;\n\t}\n\n\t/**\n\t * Virtual threads information.\n\t *\n\t * @since 3.5.0\n\t */\n\tpublic static class VirtualThreadsInfo {\n\n\t\tprivate final int mounted;\n\n\t\tprivate final long queued;\n\n\t\tprivate final int parallelism;\n\n\t\tprivate final int poolSize;\n\n\t\tVirtualThreadsInfo(int mounted, long queued, int parallelism, int poolSize) {\n\t\t\tthis.mounted = mounted;\n\t\t\tthis.queued = queued;\n\t\t\tthis.parallelism = parallelism;\n\t\t\tthis.poolSize = poolSize;\n\t\t}\n\n\t\tpublic int getMounted() {\n\t\t\treturn this.mounted;\n\t\t}\n\n\t\tpublic long getQueued() {\n\t\t\treturn this.queued;\n\t\t}\n\n\t\tpublic int getParallelism() {\n\t\t\treturn this.parallelism;\n\t\t}\n\n\t\tpublic int getPoolSize() {\n\t\t\treturn this.poolSize;\n\t\t}\n\n\t}\n\n\t/**\n\t * Memory information.\n\t *\n\t * @since 3.4.0\n\t */\n\tpublic static class MemoryInfo {\n\n\t\tprivate static final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();\n\n\t\tprivate static final List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory\n\t\t\t.getGarbageCollectorMXBeans();\n\n\t\tprivate final MemoryUsageInfo heap;\n\n\t\tprivate final MemoryUsageInfo nonHeap;\n\n\t\tprivate final List<GarbageCollectorInfo> garbageCollectors;\n\n\t\tMemoryInfo() {\n\t\t\tthis.heap = new MemoryUsageInfo(memoryMXBean.getHeapMemoryUsage());\n\t\t\tthis.nonHeap = new MemoryUsageInfo(memoryMXBean.getNonHeapMemoryUsage());\n\t\t\tthis.garbageCollectors = garbageCollectorMXBeans.stream().map(GarbageCollectorInfo::new).toList();\n\t\t}\n\n\t\tpublic MemoryUsageInfo getHeap() {\n\t\t\treturn this.heap;\n\t\t}\n\n\t\tpublic MemoryUsageInfo getNonHeap() {\n\t\t\treturn this.nonHeap;\n\t\t}\n\n\t\t/**\n\t\t * Garbage Collector information for the process. This list provides details about\n\t\t * the currently used GC algorithms selected by the user or JVM ergonomics. It\n\t\t * might not be trivial to know the used GC algorithms since that usually depends\n\t\t * on the {@link Runtime#availableProcessors()} (see:\n\t\t * {@link ProcessInfo#getCpus()}) and the available memory (see:\n\t\t * {@link MemoryUsageInfo}).\n\t\t * @return {@link List} of {@link GarbageCollectorInfo}.\n\t\t * @since 3.5.0\n\t\t */\n\t\tpublic List<GarbageCollectorInfo> getGarbageCollectors() {\n\t\t\treturn this.garbageCollectors;\n\t\t}\n\n\t\tpublic static class MemoryUsageInfo {\n\n\t\t\tprivate final MemoryUsage memoryUsage;\n\n\t\t\tMemoryUsageInfo(MemoryUsage memoryUsage) {\n\t\t\t\tthis.memoryUsage = memoryUsage;\n\t\t\t}\n\n\t\t\tpublic long getInit() {\n\t\t\t\treturn this.memoryUsage.getInit();\n\t\t\t}\n\n\t\t\tpublic long getUsed() {\n\t\t\t\treturn this.memoryUsage.getUsed();\n\t\t\t}\n\n\t\t\tpublic long getCommitted() {\n\t\t\t\treturn this.memoryUsage.getCommitted();\n\t\t\t}\n\n\t\t\tpublic long getMax() {\n\t\t\t\treturn this.memoryUsage.getMax();\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Garbage collection information.\n\t\t *\n\t\t * @since 3.5.0\n\t\t */\n\t\tpublic static class GarbageCollectorInfo {\n\n\t\t\tprivate final String name;\n\n\t\t\tprivate final long collectionCount;\n\n\t\t\tGarbageCollectorInfo(GarbageCollectorMXBean garbageCollectorMXBean) {\n\t\t\t\tthis.name = garbageCollectorMXBean.getName();\n\t\t\t\tthis.collectionCount = garbageCollectorMXBean.getCollectionCount();\n\t\t\t}\n\n\t\t\tpublic String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic long getCollectionCount() {\n\t\t\t\treturn this.collectionCount;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/SslInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.cert.Certificate;\nimport java.security.cert.X509Certificate;\nimport java.time.Clock;\nimport java.time.Instant;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport javax.security.auth.x500.X500Principal;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.info.SslInfo.CertificateValidityInfo.Status;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Information about the certificates that the application uses.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n * @since 3.4.0\n */\npublic class SslInfo {\n\n\tprivate final SslBundles sslBundles;\n\n\tprivate final Clock clock;\n\n\t/**\n\t * Creates a new instance.\n\t * @param sslBundles the {@link SslBundles} to extract the info from\n\t * @since 4.0.0\n\t */\n\tpublic SslInfo(SslBundles sslBundles) {\n\t\tthis(sslBundles, Clock.systemDefaultZone());\n\t}\n\n\t/**\n\t * Creates a new instance.\n\t * @param sslBundles the {@link SslBundles} to extract the info from\n\t * @param clock the {@link Clock} to use\n\t * @since 4.0.0\n\t */\n\tpublic SslInfo(SslBundles sslBundles, Clock clock) {\n\t\tthis.sslBundles = sslBundles;\n\t\tthis.clock = clock;\n\t}\n\n\t/**\n\t * Returns information on all SSL bundles.\n\t * @return information on all SSL bundles\n\t */\n\tpublic List<BundleInfo> getBundles() {\n\t\treturn this.sslBundles.getBundleNames()\n\t\t\t.stream()\n\t\t\t.map((name) -> new BundleInfo(name, this.sslBundles.getBundle(name)))\n\t\t\t.toList();\n\t}\n\n\t/**\n\t * Returns an SSL bundle by name.\n\t * @param name the name of the SSL bundle\n\t * @return the {@link BundleInfo} for the given SSL bundle\n\t * @throws NoSuchSslBundleException if a bundle with the provided name does not exist\n\t * @since 3.5.0\n\t */\n\tpublic BundleInfo getBundle(String name) {\n\t\tSslBundle bundle = this.sslBundles.getBundle(name);\n\t\treturn new BundleInfo(name, bundle);\n\t}\n\n\t/**\n\t * Info about a single {@link SslBundle}.\n\t */\n\tpublic final class BundleInfo {\n\n\t\tprivate final String name;\n\n\t\tprivate final List<CertificateChainInfo> certificateChains;\n\n\t\tprivate final List<CertificateChainInfo> trustStoreCertificateChains;\n\n\t\tprivate BundleInfo(String name, SslBundle sslBundle) {\n\t\t\tthis.name = name;\n\t\t\tthis.certificateChains = extractCertificateChains(sslBundle.getStores().getKeyStore());\n\t\t\tthis.trustStoreCertificateChains = extractCertificateChains(sslBundle.getStores().getTrustStore());\n\t\t}\n\n\t\tprivate List<CertificateChainInfo> extractCertificateChains(@Nullable KeyStore keyStore) {\n\t\t\tif (keyStore == null) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn Collections.list(keyStore.aliases())\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map((alias) -> new CertificateChainInfo(keyStore, alias))\n\t\t\t\t\t.toList();\n\t\t\t}\n\t\t\tcatch (KeyStoreException ex) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic List<CertificateChainInfo> getCertificateChains() {\n\t\t\treturn this.certificateChains;\n\t\t}\n\n\t\tpublic List<CertificateChainInfo> getTrustStoreCertificateChains() {\n\t\t\treturn this.trustStoreCertificateChains;\n\t\t}\n\n\t}\n\n\t/**\n\t * Info about a single certificate chain.\n\t */\n\tpublic final class CertificateChainInfo {\n\n\t\tprivate final String alias;\n\n\t\tprivate final List<CertificateInfo> certificates;\n\n\t\tCertificateChainInfo(KeyStore keyStore, String alias) {\n\t\t\tthis.alias = alias;\n\t\t\tthis.certificates = extractCertificates(keyStore, alias);\n\t\t}\n\n\t\tprivate List<CertificateInfo> extractCertificates(KeyStore keyStore, String alias) {\n\t\t\ttry {\n\t\t\t\tList<CertificateInfo> certificates = readCertificateChain(keyStore, alias);\n\t\t\t\tif (certificates != null) {\n\t\t\t\t\treturn certificates;\n\t\t\t\t}\n\t\t\t\tList<CertificateInfo> certificate = readCertificate(keyStore, alias);\n\t\t\t\tif (certificate != null) {\n\t\t\t\t\treturn certificate;\n\t\t\t\t}\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\tcatch (KeyStoreException ex) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable List<CertificateInfo> readCertificate(KeyStore keyStore, String alias)\n\t\t\t\tthrows KeyStoreException {\n\t\t\tCertificate certificate = keyStore.getCertificate(alias);\n\t\t\treturn (certificate != null) ? List.of(new CertificateInfo(certificate)) : null;\n\t\t}\n\n\t\tprivate @Nullable List<CertificateInfo> readCertificateChain(KeyStore keyStore, String alias)\n\t\t\t\tthrows KeyStoreException {\n\t\t\tCertificate[] certificates = keyStore.getCertificateChain(alias);\n\t\t\treturn ObjectUtils.isEmpty(certificates) ? null\n\t\t\t\t\t: Arrays.stream(certificates).map(CertificateInfo::new).toList();\n\t\t}\n\n\t\tpublic String getAlias() {\n\t\t\treturn this.alias;\n\t\t}\n\n\t\tpublic List<CertificateInfo> getCertificates() {\n\t\t\treturn this.certificates;\n\t\t}\n\n\t}\n\n\t/**\n\t * Info about a certificate.\n\t */\n\tpublic final class CertificateInfo {\n\n\t\tprivate final @Nullable X509Certificate certificate;\n\n\t\tprivate CertificateInfo(Certificate certificate) {\n\t\t\tthis.certificate = (certificate instanceof X509Certificate x509Certificate) ? x509Certificate : null;\n\t\t}\n\n\t\tpublic @Nullable String getSubject() {\n\t\t\treturn extract(X509Certificate::getSubjectX500Principal, X500Principal::getName);\n\t\t}\n\n\t\tpublic @Nullable String getIssuer() {\n\t\t\treturn extract(X509Certificate::getIssuerX500Principal, X500Principal::getName);\n\t\t}\n\n\t\tpublic @Nullable String getSerialNumber() {\n\t\t\treturn extract(X509Certificate::getSerialNumber, (serial) -> serial.toString(16));\n\t\t}\n\n\t\tpublic @Nullable String getVersion() {\n\t\t\treturn extract((certificate) -> \"V\" + certificate.getVersion());\n\t\t}\n\n\t\tpublic @Nullable String getSignatureAlgorithmName() {\n\t\t\treturn extract(X509Certificate::getSigAlgName);\n\t\t}\n\n\t\tpublic @Nullable Instant getValidityStarts() {\n\t\t\treturn extract(X509Certificate::getNotBefore, Date::toInstant);\n\t\t}\n\n\t\tpublic @Nullable Instant getValidityEnds() {\n\t\t\treturn extract(X509Certificate::getNotAfter, Date::toInstant);\n\t\t}\n\n\t\tpublic @Nullable CertificateValidityInfo getValidity() {\n\t\t\treturn extract((certificate) -> {\n\t\t\t\tInstant starts = getValidityStarts();\n\t\t\t\tInstant ends = getValidityEnds();\n\t\t\t\tAssert.state(starts != null, \"Validity start not found\");\n\t\t\t\tAssert.state(ends != null, \"Validity end not found\");\n\t\t\t\tCertificateValidityInfo.Status validity = checkValidity(starts, ends);\n\t\t\t\treturn switch (validity) {\n\t\t\t\t\tcase VALID -> CertificateValidityInfo.VALID;\n\t\t\t\t\tcase EXPIRED -> new CertificateValidityInfo(Status.EXPIRED, \"Not valid after %s\", ends);\n\t\t\t\t\tcase NOT_YET_VALID ->\n\t\t\t\t\t\tnew CertificateValidityInfo(Status.NOT_YET_VALID, \"Not valid before %s\", starts);\n\t\t\t\t};\n\t\t\t});\n\t\t}\n\n\t\tprivate CertificateValidityInfo.Status checkValidity(Instant starts, Instant ends) {\n\t\t\tInstant now = SslInfo.this.clock.instant();\n\t\t\tif (now.isBefore(starts)) {\n\t\t\t\treturn CertificateValidityInfo.Status.NOT_YET_VALID;\n\t\t\t}\n\t\t\tif (now.isAfter(ends)) {\n\t\t\t\treturn CertificateValidityInfo.Status.EXPIRED;\n\t\t\t}\n\t\t\treturn CertificateValidityInfo.Status.VALID;\n\t\t}\n\n\t\tprivate <V, R> @Nullable R extract(Function<X509Certificate, V> valueExtractor,\n\t\t\t\tFunction<V, R> resultExtractor) {\n\t\t\treturn extract(valueExtractor.andThen(resultExtractor));\n\t\t}\n\n\t\tprivate <R> @Nullable R extract(Function<X509Certificate, R> extractor) {\n\t\t\treturn (this.certificate != null) ? extractor.apply(this.certificate) : null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Certificate validity info.\n\t */\n\tpublic static class CertificateValidityInfo {\n\n\t\tstatic final CertificateValidityInfo VALID = new CertificateValidityInfo(Status.VALID, null);\n\n\t\tprivate final Status status;\n\n\t\tprivate final @Nullable String message;\n\n\t\tCertificateValidityInfo(Status status, @Nullable String message, Object... messageArgs) {\n\t\t\tthis.status = status;\n\t\t\tthis.message = (message != null) ? message.formatted(messageArgs) : null;\n\t\t}\n\n\t\tpublic Status getStatus() {\n\t\t\treturn this.status;\n\t\t}\n\n\t\tpublic @Nullable String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\t/**\n\t\t * Validity Status.\n\t\t */\n\t\tpublic enum Status {\n\n\t\t\t/**\n\t\t\t * The certificate is valid.\n\t\t\t */\n\t\t\tVALID(true),\n\n\t\t\t/**\n\t\t\t * The certificate's validity date range is in the future.\n\t\t\t */\n\t\t\tNOT_YET_VALID(false),\n\n\t\t\t/**\n\t\t\t * The certificate's validity date range is in the past.\n\t\t\t */\n\t\t\tEXPIRED(false);\n\n\t\t\tprivate final boolean valid;\n\n\t\t\tStatus(boolean valid) {\n\t\t\t\tthis.valid = valid;\n\t\t\t}\n\n\t\t\tpublic boolean isValid() {\n\t\t\t\treturn this.valid;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/info/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for providing information about an application.\n */\n@NullMarked\npackage org.springframework.boot.info;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/io/ApplicationResourceLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ContextResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Class can be used to obtain {@link ResourceLoader ResourceLoaders} supporting\n * additional {@link ProtocolResolver ProtocolResolvers} registered in\n * {@code spring.factories}.\n * <p>\n * When not delegating to an existing resource loader, plain paths without a qualifier\n * will resolve to file system resources. This is different from\n * {@code DefaultResourceLoader}, which resolves unqualified paths to classpath resources.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 3.3.0\n */\npublic class ApplicationResourceLoader extends DefaultResourceLoader {\n\n\t@Override\n\tprotected Resource getResourceByPath(String path) {\n\t\treturn new ApplicationResource(path);\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver\n\t * ProtocolResolvers} registered in {@code spring.factories}. The factories file will\n\t * be resolved using the default class loader at the time this call is made. Resources\n\t * will be resolved using the default class loader at the time they are resolved.\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.4.0\n\t */\n\tpublic static ResourceLoader get() {\n\t\treturn get((ClassLoader) null);\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver\n\t * ProtocolResolvers} registered in {@code spring.factories}. The factories files and\n\t * resources will be resolved using the specified class loader.\n\t * @param classLoader the class loader to use or {@code null} to use the default class\n\t * loader\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.4.0\n\t */\n\tpublic static ResourceLoader get(@Nullable ClassLoader classLoader) {\n\t\treturn get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader));\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver\n\t * ProtocolResolvers} registered in {@code spring.factories}.\n\t * @param classLoader the class loader to use or {@code null} to use the default class\n\t * loader\n\t * @param springFactoriesLoader the {@link SpringFactoriesLoader} used to load\n\t * {@link ProtocolResolver ProtocolResolvers}\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.4.0\n\t */\n\tpublic static ResourceLoader get(@Nullable ClassLoader classLoader, SpringFactoriesLoader springFactoriesLoader) {\n\t\treturn get(classLoader, springFactoriesLoader, null);\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} supporting additional {@link ProtocolResolver\n\t * ProtocolResolvers} registered in {@code spring.factories}.\n\t * @param classLoader the class loader to use or {@code null} to use the default class\n\t * loader\n\t * @param springFactoriesLoader the {@link SpringFactoriesLoader} used to load\n\t * {@link ProtocolResolver ProtocolResolvers}\n\t * @param workingDirectory the working directory\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.5.0\n\t */\n\tpublic static ResourceLoader get(@Nullable ClassLoader classLoader, SpringFactoriesLoader springFactoriesLoader,\n\t\t\t@Nullable Path workingDirectory) {\n\t\treturn get(ApplicationFileSystemResourceLoader.get(classLoader, workingDirectory), springFactoriesLoader);\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} delegating to the given resource loader and\n\t * supporting additional {@link ProtocolResolver ProtocolResolvers} registered in\n\t * {@code spring.factories}. The factories file will be resolved using the default\n\t * class loader at the time this call is made.\n\t * @param resourceLoader the delegate resource loader\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.4.0\n\t */\n\tpublic static ResourceLoader get(ResourceLoader resourceLoader) {\n\t\treturn get(resourceLoader, false);\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} delegating to the given resource loader and\n\t * supporting additional {@link ProtocolResolver ProtocolResolvers} registered in\n\t * {@code spring.factories}. The factories file will be resolved using the default\n\t * class loader at the time this call is made.\n\t * @param resourceLoader the delegate resource loader\n\t * @param preferFileResolution if file based resolution is preferred when a suitable\n\t * {@link FilePathResolver} support the resource\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.4.1\n\t */\n\tpublic static ResourceLoader get(ResourceLoader resourceLoader, boolean preferFileResolution) {\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\treturn get(resourceLoader, SpringFactoriesLoader.forDefaultResourceLocation(resourceLoader.getClassLoader()),\n\t\t\t\tpreferFileResolution);\n\t}\n\n\t/**\n\t * Return a {@link ResourceLoader} delegating to the given resource loader and\n\t * supporting additional {@link ProtocolResolver ProtocolResolvers} registered in\n\t * {@code spring.factories}.\n\t * @param resourceLoader the delegate resource loader\n\t * @param springFactoriesLoader the {@link SpringFactoriesLoader} used to load\n\t * {@link ProtocolResolver ProtocolResolvers}\n\t * @return a {@link ResourceLoader} instance\n\t * @since 3.4.0\n\t */\n\tpublic static ResourceLoader get(ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader) {\n\t\treturn get(resourceLoader, springFactoriesLoader, false);\n\t}\n\n\tprivate static ResourceLoader get(ResourceLoader resourceLoader, SpringFactoriesLoader springFactoriesLoader,\n\t\t\tboolean preferFileResolution) {\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\tAssert.notNull(springFactoriesLoader, \"'springFactoriesLoader' must not be null\");\n\t\tList<ProtocolResolver> protocolResolvers = springFactoriesLoader.load(ProtocolResolver.class);\n\t\tList<FilePathResolver> filePathResolvers = (preferFileResolution)\n\t\t\t\t? springFactoriesLoader.load(FilePathResolver.class) : Collections.emptyList();\n\t\treturn new ProtocolResolvingResourceLoader(resourceLoader, protocolResolvers, filePathResolvers);\n\t}\n\n\t/**\n\t * Internal {@link ResourceLoader} used to load {@link ApplicationResource}.\n\t */\n\tprivate static final class ApplicationFileSystemResourceLoader extends DefaultResourceLoader {\n\n\t\tprivate static final ResourceLoader shared = new ApplicationFileSystemResourceLoader(null, null);\n\n\t\tprivate final @Nullable Path workingDirectory;\n\n\t\tprivate ApplicationFileSystemResourceLoader(@Nullable ClassLoader classLoader,\n\t\t\t\t@Nullable Path workingDirectory) {\n\t\t\tsuper(classLoader);\n\t\t\tthis.workingDirectory = workingDirectory;\n\t\t}\n\n\t\t@Override\n\t\tpublic Resource getResource(String location) {\n\t\t\tResource resource = super.getResource(location);\n\t\t\tif (this.workingDirectory == null) {\n\t\t\t\treturn resource;\n\t\t\t}\n\t\t\tif (!resource.isFile()) {\n\t\t\t\treturn resource;\n\t\t\t}\n\t\t\treturn resolveFile(resource, this.workingDirectory);\n\t\t}\n\n\t\tprivate Resource resolveFile(Resource resource, Path workingDirectory) {\n\t\t\ttry {\n\t\t\t\tFile file = resource.getFile();\n\t\t\t\treturn new ApplicationResource(workingDirectory.resolve(file.toPath()));\n\t\t\t}\n\t\t\tcatch (FileNotFoundException ex) {\n\t\t\t\treturn resource;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected Resource getResourceByPath(String path) {\n\t\t\treturn new ApplicationResource(path);\n\t\t}\n\n\t\tstatic ResourceLoader get(@Nullable ClassLoader classLoader, @Nullable Path workingDirectory) {\n\t\t\tif (classLoader == null && workingDirectory != null) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"It's not possible to use null as 'classLoader' but specify a 'workingDirectory'\");\n\t\t\t}\n\t\t\treturn (classLoader != null) ? new ApplicationFileSystemResourceLoader(classLoader, workingDirectory)\n\t\t\t\t\t: ApplicationFileSystemResourceLoader.shared;\n\t\t}\n\n\t}\n\n\t/**\n\t * Strategy interface registered in {@code spring.factories} and used by\n\t * {@link ApplicationResourceLoader} to determine the file path of loaded resource\n\t * when it can also be represented as a {@link FileSystemResource}.\n\t *\n\t * @author Phillip Webb\n\t * @since 3.4.5\n\t */\n\tpublic interface FilePathResolver {\n\n\t\t/**\n\t\t * Return the {@code path} of the given resource if it can also be represented as\n\t\t * a {@link FileSystemResource}.\n\t\t * @param location the location used to create the resource\n\t\t * @param resource the resource to check\n\t\t * @return the file path of the resource or {@code null} if the it is not possible\n\t\t * to represent the resource as a {@link FileSystemResource}.\n\t\t */\n\t\t@Nullable String resolveFilePath(String location, Resource resource);\n\n\t}\n\n\t/**\n\t * An application {@link Resource}.\n\t */\n\tprivate static final class ApplicationResource extends FileSystemResource implements ContextResource {\n\n\t\tApplicationResource(String path) {\n\t\t\tsuper(path);\n\t\t}\n\n\t\tApplicationResource(Path path) {\n\t\t\tsuper(path);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPathWithinContext() {\n\t\t\treturn getPath();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ResourceLoader} decorator that adds support for additional\n\t * {@link ProtocolResolver ProtocolResolvers}.\n\t */\n\tprivate static class ProtocolResolvingResourceLoader implements ResourceLoader {\n\n\t\tprivate final ResourceLoader resourceLoader;\n\n\t\tprivate final List<ProtocolResolver> protocolResolvers;\n\n\t\tprivate final List<FilePathResolver> filePathResolvers;\n\n\t\tProtocolResolvingResourceLoader(ResourceLoader resourceLoader, List<ProtocolResolver> protocolResolvers,\n\t\t\t\tList<FilePathResolver> filePathResolvers) {\n\t\t\tthis.resourceLoader = resourceLoader;\n\t\t\tthis.protocolResolvers = protocolResolvers;\n\t\t\tthis.filePathResolvers = filePathResolvers;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ClassLoader getClassLoader() {\n\t\t\treturn this.resourceLoader.getClassLoader();\n\t\t}\n\n\t\t@Override\n\t\tpublic Resource getResource(String location) {\n\t\t\tif (StringUtils.hasLength(location)) {\n\t\t\t\tfor (ProtocolResolver protocolResolver : this.protocolResolvers) {\n\t\t\t\t\tResource resource = protocolResolver.resolve(location, this);\n\t\t\t\t\tif (resource != null) {\n\t\t\t\t\t\treturn resource;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tResource resource = this.resourceLoader.getResource(location);\n\t\t\tString filePath = getFilePath(location, resource);\n\t\t\treturn (filePath != null) ? new ApplicationResource(filePath) : resource;\n\t\t}\n\n\t\tprivate @Nullable String getFilePath(String location, Resource resource) {\n\t\t\tfor (FilePathResolver filePathResolver : this.filePathResolvers) {\n\t\t\t\tString filePath = filePathResolver.resolveFilePath(location, resource);\n\t\t\t\tif (filePath != null) {\n\t\t\t\t\treturn filePath;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/io/Base64ProtocolResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.util.Base64;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link ProtocolResolver} for resources containing base 64 encoded text.\n *\n * @author Scott Frederick\n */\nclass Base64ProtocolResolver implements ProtocolResolver {\n\n\tprivate static final String BASE64_PREFIX = \"base64:\";\n\n\t@Override\n\tpublic @Nullable Resource resolve(String location, ResourceLoader resourceLoader) {\n\t\tif (location.startsWith(BASE64_PREFIX)) {\n\t\t\tString value = location.substring(BASE64_PREFIX.length());\n\t\t\treturn new ByteArrayResource(decode(value));\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static byte[] decode(String location) {\n\t\treturn Base64.getDecoder().decode(location);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/io/ClassPathResourceFilePathResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.io.ApplicationResourceLoader.FilePathResolver;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link FilePathResolver} for {@link ClassPathResource}.\n *\n * @author Phillip Webb\n */\nclass ClassPathResourceFilePathResolver implements ApplicationResourceLoader.FilePathResolver {\n\n\t@Override\n\tpublic @Nullable String resolveFilePath(String location, Resource resource) {\n\t\treturn (resource instanceof ClassPathResource && !isClassPathUrl(location)) ? location : null;\n\t}\n\n\tprivate boolean isClassPathUrl(String location) {\n\t\treturn location.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.util.List;\n\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * {@link ApplicationContextInitializer} that adds all {@link ProtocolResolver\n * ProtocolResolvers} registered in a {@code spring.factories} file.\n *\n * @author Scott Frederick\n */\nclass ProtocolResolverApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tSpringFactoriesLoader loader = SpringFactoriesLoader\n\t\t\t.forDefaultResourceLocation(applicationContext.getClassLoader());\n\t\tList<ProtocolResolver> protocolResolvers = loader.load(ProtocolResolver.class);\n\t\tprotocolResolvers.forEach(applicationContext::addProtocolResolver);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/io/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for loading resources.\n */\n@NullMarked\npackage org.springframework.boot.io;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/AbstractJsonParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Base class for parsers wrapped or implemented in this package.\n *\n * @author Anton Telechev\n * @author Phillip Webb\n * @since 2.0.1\n */\npublic abstract class AbstractJsonParser implements JsonParser {\n\n\tprotected final Map<String, Object> parseMap(@Nullable String json, Function<String, Map<String, Object>> parser) {\n\t\treturn trimParse(json, \"{\", parser);\n\t}\n\n\tprotected final List<Object> parseList(@Nullable String json, Function<String, List<Object>> parser) {\n\t\treturn trimParse(json, \"[\", parser);\n\t}\n\n\tprotected final <T> T trimParse(@Nullable String json, String prefix, Function<String, T> parser) {\n\t\tString trimmed = (json != null) ? json.trim() : \"\";\n\t\tif (trimmed.startsWith(prefix)) {\n\t\t\treturn parser.apply(trimmed);\n\t\t}\n\t\tthrow new JsonParseException();\n\t}\n\n\tprotected final <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) {\n\t\ttry {\n\t\t\treturn parser.call();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (check.isAssignableFrom(ex.getClass())) {\n\t\t\t\tthrow new JsonParseException(ex);\n\t\t\t}\n\t\t\tReflectionUtils.rethrowRuntimeException(ex);\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Really basic JSON parser for when you have nothing else available. Comes with some\n * limitations with respect to the JSON specification (e.g. only supports String values),\n * so users will probably prefer to have a library handle things instead (Jackson or Snake\n * YAML are supported).\n *\n * @author Dave Syer\n * @author Jean de Klerk\n * @author Stephane Nicoll\n * @since 1.2.0\n * @see JsonParserFactory\n */\npublic class BasicJsonParser extends AbstractJsonParser {\n\n\tprivate static final int MAX_DEPTH = 1000;\n\n\t@Override\n\tpublic Map<String, Object> parseMap(@Nullable String json) {\n\t\treturn tryParse(() -> parseMap(json, (jsonToParse) -> parseMapInternal(0, jsonToParse)), Exception.class);\n\t}\n\n\t@Override\n\tpublic List<Object> parseList(@Nullable String json) {\n\t\treturn tryParse(() -> parseList(json, (jsonToParse) -> parseListInternal(0, jsonToParse)), Exception.class);\n\t}\n\n\tprivate List<Object> parseListInternal(int nesting, String json) {\n\t\tList<Object> list = new ArrayList<>();\n\t\tjson = trimEdges(json, '[', ']').trim();\n\t\tfor (String value : tokenize(json)) {\n\t\t\tlist.add(parseInternal(nesting + 1, value));\n\t\t}\n\t\treturn list;\n\t}\n\n\tprivate Object parseInternal(int nesting, String json) {\n\t\tif (nesting > MAX_DEPTH) {\n\t\t\tthrow new IllegalStateException(\"JSON is too deeply nested\");\n\t\t}\n\t\tif (json.startsWith(\"[\")) {\n\t\t\treturn parseListInternal(nesting + 1, json);\n\t\t}\n\t\tif (json.startsWith(\"{\")) {\n\t\t\treturn parseMapInternal(nesting + 1, json);\n\t\t}\n\t\tif (json.startsWith(\"\\\"\")) {\n\t\t\treturn trimEdges(json, '\"', '\"');\n\t\t}\n\t\treturn parseNumber(json);\n\t}\n\n\tprivate Map<String, Object> parseMapInternal(int nesting, String json) {\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tjson = trimEdges(json, '{', '}').trim();\n\t\tfor (String pair : tokenize(json)) {\n\t\t\tString @Nullable [] split = StringUtils.split(pair, \":\");\n\t\t\tAssert.state(split != null, () -> \"Unable to parse '%s'\".formatted(pair));\n\t\t\t@Nullable String[] rawElement = StringUtils.trimArrayElements(split);\n\t\t\tString rawKey = rawElement[0];\n\t\t\tString rawValue = rawElement[1];\n\t\t\tAssert.state(rawKey != null, () -> \"rawKey is null in '%s'\".formatted(pair));\n\t\t\tAssert.state(rawKey.startsWith(\"\\\"\") && rawKey.endsWith(\"\\\"\"),\n\t\t\t\t\t\"Expecting double-quotes around field names\");\n\t\t\tString key = trimEdges(rawKey, '\"', '\"');\n\t\t\tAssert.state(rawValue != null, () -> \"rawValue is null in '%s'\".formatted(pair));\n\t\t\tObject value = parseInternal(nesting, rawValue);\n\t\t\tmap.put(key, value);\n\t\t}\n\t\treturn map;\n\t}\n\n\tprivate Object parseNumber(String json) {\n\t\ttry {\n\t\t\treturn Long.valueOf(json);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\ttry {\n\t\t\t\treturn Double.valueOf(json);\n\t\t\t}\n\t\t\tcatch (NumberFormatException ex2) {\n\t\t\t\treturn json;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static String trimTrailingCharacter(String string, char c) {\n\t\tif (!string.isEmpty() && string.charAt(string.length() - 1) == c) {\n\t\t\treturn string.substring(0, string.length() - 1);\n\t\t}\n\t\treturn string;\n\t}\n\n\tprivate static String trimLeadingCharacter(String string, char c) {\n\t\tif (!string.isEmpty() && string.charAt(0) == c) {\n\t\t\treturn string.substring(1);\n\t\t}\n\t\treturn string;\n\t}\n\n\tprivate static String trimEdges(String string, char leadingChar, char trailingChar) {\n\t\treturn trimTrailingCharacter(trimLeadingCharacter(string, leadingChar), trailingChar);\n\t}\n\n\tprivate List<String> tokenize(String json) {\n\t\tList<String> list = new ArrayList<>();\n\t\tTracking tracking = new Tracking();\n\t\tStringBuilder build = new StringBuilder();\n\t\tint index = 0;\n\t\twhile (index < json.length()) {\n\t\t\tchar ch = json.charAt(index);\n\t\t\tif (tracking.in(Tracked.ESCAPE)) {\n\t\t\t\tbuild.append(ch);\n\t\t\t\tindex++;\n\t\t\t\ttracking.set(Tracked.ESCAPE, 0);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tswitch (ch) {\n\t\t\t\tcase '{' -> tracking.update(Tracked.OBJECT, +1);\n\t\t\t\tcase '}' -> tracking.update(Tracked.OBJECT, -1);\n\t\t\t\tcase '[' -> tracking.update(Tracked.LIST, +1);\n\t\t\t\tcase ']' -> tracking.update(Tracked.LIST, -1);\n\t\t\t\tcase '\"' -> tracking.toggle(Tracked.VALUE);\n\t\t\t}\n\t\t\tif (ch == ',' && !tracking.in(Tracked.OBJECT, Tracked.LIST, Tracked.VALUE)) {\n\t\t\t\tlist.add(build.toString());\n\t\t\t\tbuild.setLength(0);\n\t\t\t}\n\t\t\telse if (ch == '\\\\') {\n\t\t\t\ttracking.set(Tracked.ESCAPE, 1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbuild.append(ch);\n\t\t\t}\n\t\t\tindex++;\n\t\t}\n\t\tif (!build.isEmpty()) {\n\t\t\tlist.add(build.toString().trim());\n\t\t}\n\t\treturn list;\n\t}\n\n\tprivate static final class Tracking {\n\n\t\tprivate final int[] counts = new int[Tracked.values().length];\n\n\t\tboolean in(Tracked... tracked) {\n\t\t\treturn Arrays.stream(tracked).mapToInt(this::get).anyMatch((i) -> i > 0);\n\t\t}\n\n\t\tvoid toggle(Tracked tracked) {\n\t\t\tset(tracked, (get(tracked) != 0) ? 0 : 1);\n\t\t}\n\n\t\tvoid update(Tracked tracked, int delta) {\n\t\t\tset(tracked, get(tracked) + delta);\n\t\t}\n\n\t\tprivate int get(Tracked tracked) {\n\t\t\treturn this.counts[tracked.ordinal()];\n\t\t}\n\n\t\tvoid set(Tracked tracked, int count) {\n\t\t\tthis.counts[tracked.ordinal()] = count;\n\t\t}\n\n\t}\n\n\tprivate enum Tracked {\n\n\t\tOBJECT, LIST, VALUE, ESCAPE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/GsonJsonParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.reflect.TypeToken;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Thin wrapper to adapt {@link Gson} to a {@link JsonParser}.\n *\n * @author Dave Syer\n * @author Jean de Klerk\n * @since 1.2.0\n * @see JsonParserFactory\n */\npublic class GsonJsonParser extends AbstractJsonParser {\n\n\tprivate static final TypeToken<?> MAP_TYPE = new MapTypeToken();\n\n\tprivate static final TypeToken<?> LIST_TYPE = new ListTypeToken();\n\n\tprivate final Gson gson = new GsonBuilder().create();\n\n\t@Override\n\tpublic Map<String, Object> parseMap(@Nullable String json) {\n\t\treturn tryParse(() -> parseMap(json, (trimmed) -> this.gson.fromJson(trimmed, MAP_TYPE.getType())),\n\t\t\t\tException.class);\n\t}\n\n\t@Override\n\tpublic List<Object> parseList(@Nullable String json) {\n\t\treturn tryParse(() -> parseList(json, (trimmed) -> this.gson.fromJson(trimmed, LIST_TYPE.getType())),\n\t\t\t\tException.class);\n\t}\n\n\tprivate static final class MapTypeToken extends TypeToken<Map<String, Object>> {\n\n\t}\n\n\tprivate static final class ListTypeToken extends TypeToken<List<Object>> {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JacksonJsonParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.type.TypeReference;\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * Thin wrapper to adapt Jackson 3 {@link JsonMapper} to {@link JsonParser}.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see JsonParserFactory\n */\npublic class JacksonJsonParser extends AbstractJsonParser {\n\n\tprivate static final MapTypeReference MAP_TYPE = new MapTypeReference();\n\n\tprivate static final ListTypeReference LIST_TYPE = new ListTypeReference();\n\n\tprivate @Nullable JsonMapper jsonMapper; // Late binding\n\n\t/**\n\t * Creates an instance with the specified {@link JsonMapper}.\n\t * @param jsonMapper the JSON mapper to use\n\t */\n\tpublic JacksonJsonParser(JsonMapper jsonMapper) {\n\t\tthis.jsonMapper = jsonMapper;\n\t}\n\n\t/**\n\t * Creates an instance with a default {@link JsonMapper} that is created lazily.\n\t */\n\tpublic JacksonJsonParser() {\n\t}\n\n\t@Override\n\tpublic Map<String, Object> parseMap(@Nullable String json) {\n\t\treturn tryParse(() -> getJsonMapper().readValue(json, MAP_TYPE), Exception.class);\n\t}\n\n\t@Override\n\tpublic List<Object> parseList(@Nullable String json) {\n\t\treturn tryParse(() -> getJsonMapper().readValue(json, LIST_TYPE), Exception.class);\n\t}\n\n\tprivate JsonMapper getJsonMapper() {\n\t\tif (this.jsonMapper == null) {\n\t\t\tthis.jsonMapper = new JsonMapper();\n\t\t}\n\t\treturn this.jsonMapper;\n\t}\n\n\tprivate static final class MapTypeReference extends TypeReference<Map<String, Object>> {\n\n\t}\n\n\tprivate static final class ListTypeReference extends TypeReference<List<Object>> {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JsonParseException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link IllegalArgumentException} thrown when source JSON is invalid.\n *\n * @author Anton Telechev\n * @author Phillip Webb\n * @since 2.0.1\n */\npublic class JsonParseException extends IllegalArgumentException {\n\n\tpublic JsonParseException() {\n\t\tthis(null);\n\t}\n\n\tpublic JsonParseException(@Nullable Throwable cause) {\n\t\tsuper(\"Cannot parse JSON\", cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JsonParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Parser that can read JSON formatted strings into {@link Map}s or {@link List}s.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see JsonParserFactory\n * @see BasicJsonParser\n * @see JacksonJsonParser\n * @see GsonJsonParser\n */\npublic interface JsonParser {\n\n\t/**\n\t * Parse the specified JSON string into a Map.\n\t * @param json the JSON to parse\n\t * @return the parsed JSON as a map\n\t * @throws JsonParseException if the JSON cannot be parsed\n\t */\n\tMap<String, Object> parseMap(@Nullable String json) throws JsonParseException;\n\n\t/**\n\t * Parse the specified JSON string into a List.\n\t * @param json the JSON to parse\n\t * @return the parsed JSON as a list\n\t * @throws JsonParseException if the JSON cannot be parsed\n\t */\n\tList<Object> parseList(@Nullable String json) throws JsonParseException;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JsonParserFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport org.springframework.util.ClassUtils;\n\n/**\n * Factory to create a {@link JsonParser}.\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see JacksonJsonParser\n * @see GsonJsonParser\n * @see BasicJsonParser\n */\npublic abstract class JsonParserFactory {\n\n\t/**\n\t * Static factory for the \"best\" JSON parser available on the classpath. Tries\n\t * Jackson, then Gson, and then falls back to the {@link BasicJsonParser}.\n\t * @return a {@link JsonParser}\n\t */\n\tpublic static JsonParser getJsonParser() {\n\t\tif (ClassUtils.isPresent(\"tools.jackson.databind.ObjectMapper\", null)) {\n\t\t\treturn new JacksonJsonParser();\n\t\t}\n\t\tif (ClassUtils.isPresent(\"com.google.gson.Gson\", null)) {\n\t\t\treturn new GsonJsonParser();\n\t\t}\n\t\treturn new BasicJsonParser();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JsonValueWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Path;\nimport java.util.ArrayDeque;\nimport java.util.Arrays;\nimport java.util.Deque;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter.MemberPath;\nimport org.springframework.boot.json.JsonWriter.NameProcessor;\nimport org.springframework.boot.json.JsonWriter.ValueProcessor;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * Internal class used by {@link JsonWriter} to handle the lower-level concerns of writing\n * JSON.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass JsonValueWriter {\n\n\tprivate static final int DEFAULT_MAX_NESTING_DEPTH = 500;\n\n\tprivate final Appendable out;\n\n\tprivate final int maxNestingDepth;\n\n\tprivate MemberPath path = MemberPath.ROOT;\n\n\tprivate final Deque<JsonWriterFiltersAndProcessors> filtersAndProcessors = new ArrayDeque<>();\n\n\tprivate final Deque<ActiveSeries> activeSeries = new ArrayDeque<>();\n\n\t/**\n\t * Create a new {@link JsonValueWriter} instance.\n\t * @param out the {@link Appendable} used to receive the JSON output\n\t */\n\tJsonValueWriter(Appendable out) {\n\t\tthis(out, DEFAULT_MAX_NESTING_DEPTH);\n\t}\n\n\t/**\n\t * Create a new {@link JsonValueWriter} instance.\n\t * @param out the {@link Appendable} used to receive the JSON output\n\t * @param maxNestingDepth the maximum allowed nesting depth for JSON objects and\n\t * arrays\n\t */\n\tJsonValueWriter(Appendable out, int maxNestingDepth) {\n\t\tthis.out = out;\n\t\tthis.maxNestingDepth = maxNestingDepth;\n\t}\n\n\tvoid pushProcessors(JsonWriterFiltersAndProcessors jsonProcessors) {\n\t\tthis.filtersAndProcessors.addLast(jsonProcessors);\n\t}\n\n\tvoid popProcessors() {\n\t\tthis.filtersAndProcessors.removeLast();\n\t}\n\n\t/**\n\t * Write a name value pair, or just a value if {@code name} is {@code null}.\n\t * @param <N> the name type in the pair\n\t * @param <V> the value type in the pair\n\t * @param name the name of the pair or {@code null} if only the value should be\n\t * written\n\t * @param value the value\n\t */\n\t<N, V> void write(@Nullable N name, @Nullable V value) {\n\t\tif (name != null) {\n\t\t\twritePair(name, value);\n\t\t}\n\t\telse {\n\t\t\twrite(value);\n\t\t}\n\t}\n\n\t/**\n\t * Write a value to the JSON output. The following value types are supported:\n\t * <ul>\n\t * <li>Any {@code null} value</li>\n\t * <li>A {@link WritableJson} instance</li>\n\t * <li>Any {@link Iterable} or Array (written as a JSON array)</li>\n\t * <li>A {@link Map} (written as a JSON object)</li>\n\t * <li>Any {@link Number}</li>\n\t * <li>A {@link Boolean}</li>\n\t * </ul>\n\t * All other values are written as JSON strings.\n\t * @param <V> the value type\n\t * @param value the value to write\n\t */\n\t<V> void write(@Nullable V value) {\n\t\tvalue = processValue(value);\n\t\tif (value == null) {\n\t\t\tappend(\"null\");\n\t\t}\n\t\telse if (value instanceof WritableJson writableJson) {\n\t\t\ttry {\n\t\t\t\twritableJson.to(this.out);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}\n\t\telse if (value instanceof Iterable<?> iterable && canWriteAsArray(iterable)) {\n\t\t\twriteArray(iterable::forEach);\n\t\t}\n\t\telse if (ObjectUtils.isArray(value)) {\n\t\t\twriteArray(Arrays.asList(ObjectUtils.toObjectArray(value))::forEach);\n\t\t}\n\t\telse if (value instanceof Map<?, ?> map) {\n\t\t\twriteObject(map::forEach);\n\t\t}\n\t\telse if (value instanceof Number || value instanceof Boolean) {\n\t\t\tappend(value.toString());\n\t\t}\n\t\telse {\n\t\t\twriteString(value);\n\t\t}\n\t}\n\n\tprivate boolean canWriteAsArray(Iterable<?> iterable) {\n\t\treturn !(iterable instanceof Path);\n\t}\n\n\t/**\n\t * Start a new {@link Series} (JSON object or array).\n\t * @param series the series to start\n\t * @see #end(Series)\n\t * @see #writePairs(Consumer)\n\t * @see #writeElements(Consumer)\n\t */\n\tvoid start(@Nullable Series series) {\n\t\tif (series != null) {\n\t\t\tint nestingDepth = this.activeSeries.size();\n\t\t\tAssert.state(nestingDepth <= this.maxNestingDepth,\n\t\t\t\t\t() -> \"JSON nesting depth (%s) exceeds maximum depth of %s (current path: %s)\"\n\t\t\t\t\t\t.formatted(nestingDepth, this.maxNestingDepth, this.path));\n\t\t\tthis.activeSeries.push(new ActiveSeries(series));\n\t\t\tappend(series.openChar);\n\t\t}\n\t}\n\n\t/**\n\t * End an active {@link Series} (JSON object or array).\n\t * @param series the series type being ended (must match {@link #start(Series)})\n\t * @see #start(Series)\n\t */\n\tvoid end(@Nullable Series series) {\n\t\tif (series != null) {\n\t\t\tthis.activeSeries.pop();\n\t\t\tappend(series.closeChar);\n\t\t}\n\t}\n\n\t/**\n\t * Write the specified elements to a newly started {@link Series#ARRAY array series}.\n\t * @param <E> the element type\n\t * @param elements a callback that will be used to provide each element. Typically a\n\t * {@code forEach} method reference.\n\t * @see #writeElements(Consumer)\n\t */\n\t<E> void writeArray(Consumer<Consumer<E>> elements) {\n\t\tstart(Series.ARRAY);\n\t\telements.accept(ThrowingConsumer.of(this::writeElement));\n\t\tend(Series.ARRAY);\n\t}\n\n\t/**\n\t * Write the specified elements to an already started {@link Series#ARRAY array\n\t * series}.\n\t * @param <E> the element type\n\t * @param elements a callback that will be used to provide each element. Typically a\n\t * {@code forEach} method reference.\n\t * @see #writeElements(Consumer)\n\t */\n\t<E> void writeElements(Consumer<Consumer<E>> elements) {\n\t\telements.accept(ThrowingConsumer.of(this::writeElement));\n\t}\n\n\t<E> void writeElement(E element) {\n\t\tActiveSeries activeSeries = this.activeSeries.peek();\n\t\tAssert.state(activeSeries != null, \"No series has been started\");\n\t\tthis.path = activeSeries.updatePath(this.path);\n\t\tactiveSeries.incrementIndexAndAddCommaIfRequired();\n\t\twrite(element);\n\t\tthis.path = activeSeries.restorePath(this.path);\n\t}\n\n\t/**\n\t * Write the specified pairs to a newly started {@link Series#OBJECT object series}.\n\t * @param <N> the name type in the pair\n\t * @param <V> the value type in the pair\n\t * @param pairs a callback that will be used to provide each pair. Typically a\n\t * {@code forEach} method reference.\n\t * @see #writePairs(Consumer)\n\t */\n\t<N, V> void writeObject(Consumer<BiConsumer<N, V>> pairs) {\n\t\tstart(Series.OBJECT);\n\t\tpairs.accept(this::writePair);\n\t\tend(Series.OBJECT);\n\t}\n\n\t/**\n\t * Write the specified pairs to an already started {@link Series#OBJECT object\n\t * series}.\n\t * @param <N> the name type in the pair\n\t * @param <V> the value type in the pair\n\t * @param pairs a callback that will be used to provide each pair. Typically a\n\t * {@code forEach} method reference.\n\t * @see #writePairs(Consumer)\n\t */\n\t<N, V> void writePairs(Consumer<BiConsumer<N, V>> pairs) {\n\t\tpairs.accept(this::writePair);\n\t}\n\n\tprivate <N, V> void writePair(N name, @Nullable V value) {\n\t\tthis.path = this.path.child(name.toString());\n\t\tif (!isFilteredPath()) {\n\t\t\tString processedName = processName(name.toString());\n\t\t\tActiveSeries activeSeries = this.activeSeries.peek();\n\t\t\tAssert.state(activeSeries != null, \"No series has been started\");\n\t\t\tactiveSeries.incrementIndexAndAddCommaIfRequired();\n\t\t\tAssert.state(activeSeries.addName(processedName),\n\t\t\t\t\t() -> \"The name '\" + processedName + \"' has already been written\");\n\t\t\twriteString(processedName);\n\t\t\tappend(\":\");\n\t\t\twrite(value);\n\t\t}\n\t\tthis.path = (this.path.parent() != null) ? this.path.parent() : MemberPath.ROOT;\n\t}\n\n\tprivate void writeString(Object value) {\n\t\ttry {\n\t\t\tthis.out.append('\"');\n\t\t\tString string = value.toString();\n\t\t\tfor (int i = 0; i < string.length(); i++) {\n\t\t\t\tchar ch = string.charAt(i);\n\t\t\t\tswitch (ch) {\n\t\t\t\t\tcase '\"' -> this.out.append(\"\\\\\\\"\");\n\t\t\t\t\tcase '\\\\' -> this.out.append(\"\\\\\\\\\");\n\t\t\t\t\tcase '\\b' -> this.out.append(\"\\\\b\");\n\t\t\t\t\tcase '\\f' -> this.out.append(\"\\\\f\");\n\t\t\t\t\tcase '\\n' -> this.out.append(\"\\\\n\");\n\t\t\t\t\tcase '\\r' -> this.out.append(\"\\\\r\");\n\t\t\t\t\tcase '\\t' -> this.out.append(\"\\\\t\");\n\t\t\t\t\tdefault -> {\n\t\t\t\t\t\tif (Character.isISOControl(ch)) {\n\t\t\t\t\t\t\tthis.out.append(\"\\\\u\");\n\t\t\t\t\t\t\tthis.out.append(String.format(\"%04X\", (int) ch));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.out.append(ch);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.out.append('\"');\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate void append(String value) {\n\t\ttry {\n\t\t\tthis.out.append(value);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\n\t}\n\n\tprivate void append(char ch) {\n\t\ttry {\n\t\t\tthis.out.append(ch);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate boolean isFilteredPath() {\n\t\tfor (JsonWriterFiltersAndProcessors filtersAndProcessors : this.filtersAndProcessors) {\n\t\t\tfor (Predicate<MemberPath> pathFilter : filtersAndProcessors.pathFilters()) {\n\t\t\t\tif (pathFilter.test(this.path)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate String processName(String name) {\n\t\tfor (JsonWriterFiltersAndProcessors filtersAndProcessors : this.filtersAndProcessors) {\n\t\t\tfor (NameProcessor nameProcessor : filtersAndProcessors.nameProcessors()) {\n\t\t\t\tname = processName(name, nameProcessor);\n\t\t\t}\n\t\t}\n\t\treturn name;\n\t}\n\n\tprivate String processName(String name, NameProcessor nameProcessor) {\n\t\tname = nameProcessor.processName(this.path, name);\n\t\tAssert.state(StringUtils.hasLength(name), \"NameProcessor \" + nameProcessor + \" returned an empty result\");\n\t\treturn name;\n\t}\n\n\tprivate <V> @Nullable V processValue(@Nullable V value) {\n\t\tfor (JsonWriterFiltersAndProcessors filtersAndProcessors : this.filtersAndProcessors) {\n\t\t\tfor (ValueProcessor<?> valueProcessor : filtersAndProcessors.valueProcessors()) {\n\t\t\t\tvalue = processValue(value, valueProcessor);\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n\n\t// Lambda isn't detected with the correct nullability\n\t@SuppressWarnings({ \"unchecked\", \"NullAway\" })\n\tprivate <V> @Nullable V processValue(@Nullable V value, ValueProcessor<?> valueProcessor) {\n\t\treturn (V) LambdaSafe\n\t\t\t.callback(ValueProcessor.class, valueProcessor, this.path, new @Nullable Object[] { value })\n\t\t\t.invokeAnd((call) -> call.processValue(this.path, value))\n\t\t\t.get(value);\n\t}\n\n\t/**\n\t * A series of items that can be written to the JSON output.\n\t */\n\tenum Series {\n\n\t\t/**\n\t\t * A JSON object series consisting of name/value pairs.\n\t\t */\n\t\tOBJECT('{', '}'),\n\n\t\t/**\n\t\t * A JSON array series consisting of elements.\n\t\t */\n\t\tARRAY('[', ']');\n\n\t\tfinal char openChar;\n\n\t\tfinal char closeChar;\n\n\t\tSeries(char openChar, char closeChar) {\n\t\t\tthis.openChar = openChar;\n\t\t\tthis.closeChar = closeChar;\n\t\t}\n\n\t}\n\n\t/**\n\t * Details of the currently active {@link Series}.\n\t */\n\tprivate final class ActiveSeries {\n\n\t\tprivate final Series series;\n\n\t\tprivate int index;\n\n\t\tprivate final Set<String> names = new HashSet<>();\n\n\t\tprivate ActiveSeries(Series series) {\n\t\t\tthis.series = series;\n\t\t}\n\n\t\tboolean addName(String processedName) {\n\t\t\treturn this.names.add(processedName);\n\t\t}\n\n\t\tMemberPath updatePath(MemberPath path) {\n\t\t\tif (this.series != Series.ARRAY) {\n\t\t\t\treturn path;\n\t\t\t}\n\t\t\treturn path.child(this.index);\n\t\t}\n\n\t\tMemberPath restorePath(MemberPath path) {\n\t\t\tif (this.series != Series.ARRAY) {\n\t\t\t\treturn path;\n\t\t\t}\n\t\t\treturn (path.parent() != null) ? path.parent() : MemberPath.ROOT;\n\t\t}\n\n\t\tvoid incrementIndexAndAddCommaIfRequired() {\n\t\t\tif (this.index > 0) {\n\t\t\t\tappend(',');\n\t\t\t}\n\t\t\tthis.index++;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JsonWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.NonNull;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonValueWriter.Series;\nimport org.springframework.boot.json.JsonWriter.Member.ValueExtractor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Interface that can be used to write JSON output. Typically used to generate JSON when a\n * dependency on a fully marshalling library (such as Jackson or Gson) cannot be assumed.\n * <p>\n * For standard Java types, the {@link #standard()} factory method may be used to obtain\n * an instance of this interface. It supports {@link String}, {@link Number} and\n * {@link Boolean} as well as {@link Collection}, {@code Array}, {@link Map} and\n * {@link WritableJson} types. Typical usage would be:\n *\n * <pre class=\"code\">\n * JsonWriter&lt;Map&lt;String,Object&gt;&gt; writer = JsonWriter.standard();\n * writer.write(Map.of(\"Hello\", \"World!\"), out);\n * </pre>\n * <p>\n * More complex mappings can be created using the {@link #of(Consumer)} method with a\n * callback to configure the {@link Members JSON members} that should be written. Typical\n * usage would be:\n *\n * <pre class=\"code\">\n * JsonWriter&lt;Person&gt; writer = JsonWriter.of((members) -&gt; {\n *     members.add(\"first\", Person::firstName);\n *     members.add(\"last\", Person::lastName);\n *     members.add(\"dob\", Person::dateOfBirth)\n *         .whenNotNull()\n *         .as(DateTimeFormatter.ISO_DATE::format);\n * });\n * writer.write(person, out);\n * </pre>\n * <p>\n * The {@link #writeToString(Object)} method can be used if you want to write the JSON\n * directly to a {@link String}. To write to other types of output, the\n * {@link #write(Object)} method may be used to obtain a {@link WritableJson} instance.\n *\n * @param <T> the type being written\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 3.4.0\n */\n@FunctionalInterface\npublic interface JsonWriter<T> {\n\n\t/**\n\t * Write the given instance to the provided {@link Appendable}.\n\t * @param instance the instance to write (may be {@code null}\n\t * @param out the output that should receive the JSON\n\t * @throws IOException on IO error\n\t */\n\tvoid write(@Nullable T instance, Appendable out) throws IOException;\n\n\t/**\n\t * Write the given instance to a JSON string.\n\t * @param instance the instance to write (may be {@code null})\n\t * @return the JSON string\n\t */\n\tdefault String writeToString(@Nullable T instance) {\n\t\treturn write(instance).toJsonString();\n\t}\n\n\t/**\n\t * Provide a {@link WritableJson} implementation that may be used to write the given\n\t * instance to various outputs.\n\t * @param instance the instance to write (may be {@code null})\n\t * @return a {@link WritableJson} instance that may be used to write the JSON\n\t */\n\tdefault WritableJson write(@Nullable T instance) {\n\t\treturn WritableJson.of((out) -> write(instance, out));\n\t}\n\n\t/**\n\t * Return a new {@link JsonWriter} instance that appends a new line after the JSON has\n\t * been written.\n\t * @return a new {@link JsonWriter} instance that appends a new line after the JSON\n\t */\n\tdefault JsonWriter<T> withNewLineAtEnd() {\n\t\treturn withSuffix(\"\\n\");\n\t}\n\n\t/**\n\t * Return a new {@link JsonWriter} instance that appends the given suffix after the\n\t * JSON has been written.\n\t * @param suffix the suffix to write, if any\n\t * @return a new {@link JsonWriter} instance that appends a suffix after the JSON\n\t */\n\tdefault JsonWriter<T> withSuffix(@Nullable String suffix) {\n\t\tif (!StringUtils.hasLength(suffix)) {\n\t\t\treturn this;\n\t\t}\n\t\treturn (instance, out) -> {\n\t\t\twrite(instance, out);\n\t\t\tout.append(suffix);\n\t\t};\n\t}\n\n\t/**\n\t * Factory method to return a {@link JsonWriter} for standard Java types. See\n\t * {@link JsonValueWriter class-level javadoc} for details.\n\t * @param <T> the type to write\n\t * @return a {@link JsonWriter} instance\n\t */\n\tstatic <T> JsonWriter<T> standard() {\n\t\treturn of(Members::add);\n\t}\n\n\t/**\n\t * Factory method to return a {@link JsonWriter} with specific {@link Members member\n\t * mapping}. See {@link JsonValueWriter class-level javadoc} and {@link Members} for\n\t * details.\n\t * @param <T> the type to write\n\t * @param members a consumer, which should configure the members\n\t * @return a {@link JsonWriter} instance\n\t * @see Members\n\t */\n\tstatic <T> JsonWriter<T> of(Consumer<Members<T>> members) {\n\t\t// Don't inline 'new Members' (must be outside of lambda)\n\t\tMembers<T> initializedMembers = new Members<>(members, false);\n\t\treturn (instance, out) -> initializedMembers.write(instance, new JsonValueWriter(out));\n\t}\n\n\t/**\n\t * Callback used to configure JSON members. Individual members can be declared using\n\t * the various {@code add(...)} methods. Typically, members are declared with a\n\t * {@code \"name\"} and a {@link Function} that will extract the value from the\n\t * instance. Members can also be declared using a static value or a {@link Supplier}.\n\t * The {@link #add(String)} and {@link #add()} methods may be used to access the\n\t * actual instance being written.\n\t * <p>\n\t * Members can be added without a {@code name} when a {@code Member.using(...)} method\n\t * is used to complete the definition.\n\t * <p>\n\t * Members can filtered using {@code Member.when} methods and adapted to different\n\t * types using {@link Member#as(Extractor) Member.as(...)}.\n\t *\n\t * @param <T> the type that will be written\n\t */\n\tfinal class Members<T> {\n\n\t\tprivate final List<Member<?>> members = new ArrayList<>();\n\n\t\tprivate final boolean contributesPair;\n\n\t\tprivate final @Nullable Series series;\n\n\t\tprivate final JsonWriterFiltersAndProcessors jsonProcessors = new JsonWriterFiltersAndProcessors();\n\n\t\tMembers(Consumer<Members<T>> members, boolean contributesToExistingSeries) {\n\t\t\tAssert.notNull(members, \"'members' must not be null\");\n\t\t\tmembers.accept(this);\n\t\t\tAssert.state(!this.members.isEmpty(), \"No members have been added\");\n\t\t\tthis.contributesPair = this.members.stream().anyMatch(Member::contributesPair);\n\t\t\tthis.series = (this.contributesPair && !contributesToExistingSeries) ? Series.OBJECT : null;\n\t\t\tif (this.contributesPair || this.members.size() > 1) {\n\t\t\t\tthis.members.forEach((member) -> Assert.state(member.contributesPair(),\n\t\t\t\t\t\t() -> String.format(\"%s does not contribute a named pair, ensure that all members have \"\n\t\t\t\t\t\t\t\t+ \"a name or call an appropriate 'using' method\", member)));\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Add a new member with access to the instance being written.\n\t\t * @param name the member name\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> add(String name) {\n\t\t\treturn add(name, (instance) -> instance);\n\t\t}\n\n\t\t/**\n\t\t * Add a new member with a static value.\n\t\t * @param <V> the value type\n\t\t * @param name the member name\n\t\t * @param value the member value\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <V> Member<V> add(String name, @Nullable V value) {\n\t\t\treturn add(name, (instance) -> value);\n\t\t}\n\n\t\t/**\n\t\t * Add a new member with a supplied value.\n\t\t * @param <V> the value type\n\t\t * @param name the member name\n\t\t * @param supplier a supplier of the value\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <V> Member<V> add(String name, Supplier<@Nullable V> supplier) {\n\t\t\tAssert.notNull(supplier, \"'supplier' must not be null\");\n\t\t\treturn add(name, (instance) -> supplier.get());\n\t\t}\n\n\t\t/**\n\t\t * Add a new member with an extracted value.\n\t\t * @param <V> the value type\n\t\t * @param name the member name\n\t\t * @param extractor {@link Extractor} to extract the value\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <V> Member<V> add(String name, Extractor<T, V> extractor) {\n\t\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\t\tAssert.notNull(extractor, \"'extractor' must not be null\");\n\t\t\treturn addMember(name, extractor);\n\t\t}\n\n\t\t/**\n\t\t * Add a new member with access to the instance being written. The member is added\n\t\t * without a name, so one of the {@code Member.using(...)} methods must be used to\n\t\t * complete the configuration.\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> add() {\n\t\t\treturn from((value) -> value);\n\t\t}\n\n\t\t/**\n\t\t * Add all entries from the given {@link Map} to the JSON.\n\t\t * @param <M> the map type\n\t\t * @param <K> the key type\n\t\t * @param <V> the value type\n\t\t * @param extractor {@link Extractor} to extract the map\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <M extends Map<K, V>, K, V> Member<M> addMapEntries(Extractor<T, M> extractor) {\n\t\t\treturn from(extractor).usingPairs(Map::forEach);\n\t\t}\n\n\t\t/**\n\t\t * Add members from a static value. One of the {@code Member.using(...)} methods\n\t\t * must be used to complete the configuration.\n\t\t * @param <V> the value type\n\t\t * @param value the member value\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <V> Member<V> from(@Nullable V value) {\n\t\t\treturn from((instance) -> value);\n\t\t}\n\n\t\t/**\n\t\t * Add members from a supplied value. One of the {@code Member.using(...)} methods\n\t\t * must be used to complete the configuration.\n\t\t * @param <V> the value type\n\t\t * @param supplier a supplier of the value\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <V> Member<V> from(Supplier<@Nullable V> supplier) {\n\t\t\tAssert.notNull(supplier, \"'supplier' must not be null\");\n\t\t\treturn from((instance) -> supplier.get());\n\t\t}\n\n\t\t/**\n\t\t * Add members from an extracted value. One of the {@code Member.using(...)}\n\t\t * methods must be used to complete the configuration.\n\t\t * @param <V> the value type\n\t\t * @param extractor {@link Extractor} to extract the value\n\t\t * @return the added {@link Member} which may be configured further\n\t\t */\n\t\tpublic <V> Member<V> from(Extractor<T, V> extractor) {\n\t\t\tAssert.notNull(extractor, \"'extractor' must not be null\");\n\t\t\treturn addMember(null, extractor);\n\t\t}\n\n\t\t/**\n\t\t * Add a filter that will be used to restrict the members written to the JSON.\n\t\t * @param predicate the predicate used to filter members\n\t\t */\n\t\tpublic void applyingPathFilter(Predicate<MemberPath> predicate) {\n\t\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\t\tthis.jsonProcessors.pathFilters().add(predicate);\n\t\t}\n\n\t\t/**\n\t\t * Add a {@link NameProcessor} to be applied when the JSON is written.\n\t\t * @param nameProcessor the name processor to add\n\t\t */\n\t\tpublic void applyingNameProcessor(NameProcessor nameProcessor) {\n\t\t\tAssert.notNull(nameProcessor, \"'nameProcessor' must not be null\");\n\t\t\tthis.jsonProcessors.nameProcessors().add(nameProcessor);\n\t\t}\n\n\t\t/**\n\t\t * Add a {@link ValueProcessor} to be applied when the JSON is written.\n\t\t * @param valueProcessor the value processor to add\n\t\t */\n\t\tpublic void applyingValueProcessor(ValueProcessor<?> valueProcessor) {\n\t\t\tAssert.notNull(valueProcessor, \"'valueProcessor' must not be null\");\n\t\t\tthis.jsonProcessors.valueProcessors().add(valueProcessor);\n\t\t}\n\n\t\tprivate <V> Member<V> addMember(@Nullable String name, Extractor<T, V> extractor) {\n\t\t\tMember<V> member = new Member<>(this.members.size(), name, ValueExtractor.of(extractor));\n\t\t\tthis.members.add(member);\n\t\t\treturn member;\n\t\t}\n\n\t\t/**\n\t\t * Writes the given instance using the configured {@link Member members}.\n\t\t * @param instance the instance to write\n\t\t * @param valueWriter the JSON value writer to use\n\t\t */\n\t\tvoid write(@Nullable T instance, JsonValueWriter valueWriter) {\n\t\t\tvalueWriter.pushProcessors(this.jsonProcessors);\n\t\t\tvalueWriter.start(this.series);\n\t\t\tfor (Member<?> member : this.members) {\n\t\t\t\tmember.write(instance, valueWriter);\n\t\t\t}\n\t\t\tvalueWriter.end(this.series);\n\t\t\tvalueWriter.popProcessors();\n\t\t}\n\n\t\t/**\n\t\t * Return if any of the members contributes a name/value pair to the JSON.\n\t\t * @return if a name/value pair is contributed\n\t\t */\n\t\tboolean contributesPair() {\n\t\t\treturn this.contributesPair;\n\t\t}\n\n\t}\n\n\t/**\n\t * A member that contributes JSON. Typically, a member will contribute a single\n\t * name/value pair based on an extracted value. They may also contribute more complex\n\t * JSON structures when configured with one of the {@code using(...)} methods.\n\t * <p>\n\t * The {@code when(...)} methods may be used to filter a member (omit it entirely from\n\t * the JSON). The {@link #as(Extractor)} method can be used to adapt to a different\n\t * type.\n\t *\n\t * @param <T> the member type\n\t */\n\tfinal class Member<T> {\n\n\t\tprivate final int index;\n\n\t\tprivate final @Nullable String name;\n\n\t\tprivate ValueExtractor<? extends @Nullable T> valueExtractor;\n\n\t\tprivate @Nullable BiConsumer<T, BiConsumer<?, ?>> pairs;\n\n\t\tprivate @Nullable Members<T> members;\n\n\t\tMember(int index, @Nullable String name, ValueExtractor<? extends @Nullable T> valueExtractor) {\n\t\t\tthis.index = index;\n\t\t\tthis.name = name;\n\t\t\tthis.valueExtractor = valueExtractor;\n\t\t}\n\n\t\t/**\n\t\t * Only include this member when its value is not {@code null}.\n\t\t * @return a {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> whenNotNull() {\n\t\t\treturn when(Objects::nonNull);\n\t\t}\n\n\t\t/**\n\t\t * Only include this member when an extracted value is not {@code null}.\n\t\t * @param extractor a function used to extract the value to test\n\t\t * @return a {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> whenNotNull(Function<@Nullable T, ?> extractor) {\n\t\t\tAssert.notNull(extractor, \"'extractor' must not be null\");\n\t\t\treturn when((instance) -> Objects.nonNull(extractor.apply(instance)));\n\t\t}\n\n\t\t/**\n\t\t * Only include this member when it is not {@code null} and has a\n\t\t * {@link Object#toString() toString()} that is not zero length.\n\t\t * @return a {@link Member} which may be configured further\n\t\t * @see StringUtils#hasLength(CharSequence)\n\t\t */\n\t\tpublic Member<T> whenHasLength() {\n\t\t\treturn when((instance) -> instance != null && StringUtils.hasLength(instance.toString()));\n\t\t}\n\n\t\t/**\n\t\t * Only include this member when it is not empty (See\n\t\t * {@link ObjectUtils#isEmpty(Object)} for details).\n\t\t * @return a {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> whenNotEmpty() {\n\t\t\tPredicate<@Nullable T> isEmpty = ObjectUtils::isEmpty;\n\t\t\treturn whenNot(isEmpty);\n\t\t}\n\n\t\t/**\n\t\t * Only include this member when the given predicate does not match.\n\t\t * @param predicate the predicate to test\n\t\t * @return a {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> whenNot(Predicate<@Nullable T> predicate) {\n\t\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\t\treturn when(predicate.negate());\n\t\t}\n\n\t\t/**\n\t\t * Only include this member when the given predicate matches.\n\t\t * @param predicate the predicate to test\n\t\t * @return a {@link Member} which may be configured further\n\t\t */\n\t\tpublic Member<T> when(Predicate<? super @Nullable T> predicate) {\n\t\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\t\tthis.valueExtractor = this.valueExtractor.when(predicate);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Adapt the value by applying the given {@link Function}.\n\t\t * @param <R> the result type\n\t\t * @param extractor a {@link Extractor} to adapt the value\n\t\t * @return a {@link Member} which may be configured further\n\t\t */\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic <R> Member<R> as(Extractor<T, R> extractor) {\n\t\t\tAssert.notNull(extractor, \"'adapter' must not be null\");\n\t\t\tMember<R> result = (Member<R>) this;\n\t\t\tresult.valueExtractor = this.valueExtractor.as(extractor::extract);\n\t\t\treturn result;\n\t\t}\n\n\t\t/**\n\t\t * Add JSON name/value pairs by extracting values from a series of elements.\n\t\t * Typically used with a {@link Iterable#forEach(Consumer)} call, for example:\n\t\t *\n\t\t * <pre class=\"code\">\n\t\t * members.add(Event::getTags).usingExtractedPairs(Iterable::forEach, pairExtractor);\n\t\t * </pre>\n\t\t * <p>\n\t\t * When used with a named member, the pairs will be added as a new JSON value\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"name\": {\n\t\t *     \"p1\": 1,\n\t\t *     \"p2\": 2\n\t\t *   }\n\t\t * }\n\t\t * </pre>\n\t\t *\n\t\t * When used with an unnamed member the pairs will be added to the existing JSON\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"p1\": 1,\n\t\t *   \"p2\": 2\n\t\t * }\n\t\t * </pre>\n\t\t * @param <E> the element type\n\t\t * @param elements callback used to provide the elements\n\t\t * @param extractor a {@link PairExtractor} used to extract the name/value pair\n\t\t * @return a {@link Member} which may be configured further\n\t\t * @see #usingExtractedPairs(BiConsumer, Function, Function)\n\t\t * @see #usingPairs(BiConsumer)\n\t\t */\n\t\tpublic <E> Member<T> usingExtractedPairs(BiConsumer<T, Consumer<E>> elements, PairExtractor<E> extractor) {\n\t\t\tAssert.notNull(elements, \"'elements' must not be null\");\n\t\t\tAssert.notNull(extractor, \"'extractor' must not be null\");\n\t\t\treturn usingExtractedPairs(elements, extractor::getName, extractor::getValue);\n\t\t}\n\n\t\t/**\n\t\t * Add JSON name/value pairs by extracting values from a series of elements.\n\t\t * Typically used with a {@link Iterable#forEach(Consumer)} call, for example:\n\t\t *\n\t\t * <pre class=\"code\">\n\t\t * members.add(Event::getTags).usingExtractedPairs(Iterable::forEach, Tag::getName, Tag::getValue);\n\t\t * </pre>\n\t\t * <p>\n\t\t * When used with a named member, the pairs will be added as a new JSON value\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"name\": {\n\t\t *     \"p1\": 1,\n\t\t *     \"p2\": 2\n\t\t *   }\n\t\t * }\n\t\t * </pre>\n\t\t *\n\t\t * When used with an unnamed member the pairs will be added to the existing JSON\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"p1\": 1,\n\t\t *   \"p2\": 2\n\t\t * }\n\t\t * </pre>\n\t\t * @param <E> the element type\n\t\t * @param <N> the name type\n\t\t * @param <V> the value type\n\t\t * @param elements callback used to provide the elements\n\t\t * @param nameExtractor {@link Function} used to extract the name\n\t\t * @param valueExtractor {@link Function} used to extract the value\n\t\t * @return a {@link Member} which may be configured further\n\t\t * @see #usingExtractedPairs(BiConsumer, PairExtractor)\n\t\t * @see #usingPairs(BiConsumer)\n\t\t */\n\t\tpublic <E, N, V> Member<T> usingExtractedPairs(BiConsumer<T, Consumer<E>> elements,\n\t\t\t\tFunction<E, N> nameExtractor, Function<E, V> valueExtractor) {\n\t\t\tAssert.notNull(elements, \"'elements' must not be null\");\n\t\t\tAssert.notNull(nameExtractor, \"'nameExtractor' must not be null\");\n\t\t\tAssert.notNull(valueExtractor, \"'valueExtractor' must not be null\");\n\t\t\treturn usingPairs((instance, pairsConsumer) -> elements.accept(instance, (element) -> {\n\t\t\t\tN name = nameExtractor.apply(element);\n\t\t\t\tV value = valueExtractor.apply(element);\n\t\t\t\tpairsConsumer.accept(name, value);\n\t\t\t}));\n\t\t}\n\n\t\t/**\n\t\t * Add JSON name/value pairs. Typically used with a\n\t\t * {@link Map#forEach(BiConsumer)} call, for example:\n\t\t *\n\t\t * <pre class=\"code\">\n\t\t * members.add(Event::getLabels).usingPairs(Map::forEach);\n\t\t * </pre>\n\t\t * <p>\n\t\t * When used with a named member, the pairs will be added as a new JSON value\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"name\": {\n\t\t *     \"p1\": 1,\n\t\t *     \"p2\": 2\n\t\t *   }\n\t\t * }\n\t\t * </pre>\n\t\t *\n\t\t * When used with an unnamed member the pairs will be added to the existing JSON\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"p1\": 1,\n\t\t *   \"p2\": 2\n\t\t * }\n\t\t * </pre>\n\t\t * @param <N> the name type\n\t\t * @param <V> the value type\n\t\t * @param pairs callback used to provide the pairs\n\t\t * @return a {@link Member} which may be configured further\n\t\t * @see #usingExtractedPairs(BiConsumer, PairExtractor)\n\t\t * @see #usingPairs(BiConsumer)\n\t\t */\n\t\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t\tpublic <N, V> Member<T> usingPairs(BiConsumer<T, BiConsumer<N, V>> pairs) {\n\t\t\tAssert.notNull(pairs, \"'pairs' must not be null\");\n\t\t\tAssert.state(this.pairs == null, \"Pairs cannot be declared multiple times\");\n\t\t\tAssert.state(this.members == null, \"Pairs cannot be declared when using members\");\n\t\t\tthis.pairs = (BiConsumer) pairs;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Add JSON based on further {@link Members} configuration. For example:\n\t\t *\n\t\t * <pre class=\"code\">\n\t\t * members.add(User::getName).usingMembers((personMembers) -> {\n\t\t *     personMembers.add(\"first\", Name::first);\n\t\t *     personMembers.add(\"last\", Name::last);\n\t\t * });\n\t\t * </pre>\n\t\t *\n\t\t * <p>\n\t\t * When used with a named member, the result will be added as a new JSON value\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"name\": {\n\t\t *     \"first\": \"Jane\",\n\t\t *     \"last\": \"Doe\"\n\t\t *   }\n\t\t * }\n\t\t * </pre>\n\t\t *\n\t\t * When used with an unnamed member the result will be added to the existing JSON\n\t\t * object:\n\t\t *\n\t\t * <pre>\n\t\t * {\n\t\t *   \"first\": \"John\",\n\t\t *   \"last\": \"Doe\"\n\t\t * }\n\t\t * </pre>\n\t\t * @param members callback to configure the members\n\t\t * @return a {@link Member} which may be configured further\n\t\t * @see #usingExtractedPairs(BiConsumer, PairExtractor)\n\t\t * @see #usingPairs(BiConsumer)\n\t\t */\n\t\tpublic Member<T> usingMembers(Consumer<Members<T>> members) {\n\t\t\tAssert.notNull(members, \"'members' must not be null\");\n\t\t\tAssert.state(this.members == null, \"Members cannot be declared multiple times\");\n\t\t\tAssert.state(this.pairs == null, \"Members cannot be declared when using pairs\");\n\t\t\tthis.members = new Members<>(members, this.name == null);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Writes the given instance using details configure by this member.\n\t\t * @param instance the instance to write\n\t\t * @param valueWriter the JSON value writer to use\n\t\t */\n\t\tvoid write(@Nullable Object instance, JsonValueWriter valueWriter) {\n\t\t\tT extracted = this.valueExtractor.extract(instance);\n\t\t\tif (ValueExtractor.skip(extracted)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tObject value = getValueToWrite(extracted, valueWriter);\n\t\t\tvalueWriter.write(this.name, value);\n\t\t}\n\n\t\tprivate @Nullable Object getValueToWrite(@Nullable T extracted, JsonValueWriter valueWriter) {\n\t\t\tWritableJson writableJson = getWritableJsonToWrite(extracted, valueWriter);\n\t\t\treturn (writableJson != null) ? WritableJson.of(writableJson) : extracted;\n\t\t}\n\n\t\tprivate @Nullable WritableJson getWritableJsonToWrite(@Nullable T extracted, JsonValueWriter valueWriter) {\n\t\t\tBiConsumer<T, BiConsumer<?, ?>> pairs = this.pairs;\n\t\t\tif (pairs != null) {\n\t\t\t\treturn (out) -> valueWriter.writePairs((outPairs) -> pairs.accept(extracted, outPairs));\n\t\t\t}\n\t\t\tMembers<T> members = this.members;\n\t\t\tif (members != null) {\n\t\t\t\treturn (out) -> members.write(extracted, valueWriter);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t/**\n\t\t * Whether this contributes one or more name/value pairs to the JSON.\n\t\t * @return whether a name/value pair is contributed\n\t\t */\n\t\tboolean contributesPair() {\n\t\t\treturn this.name != null || this.pairs != null || (this.members != null && this.members.contributesPair());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Member at index \" + this.index + ((this.name != null) ? \"{%s}\".formatted(this.name) : \"\");\n\t\t}\n\n\t\t/**\n\t\t * Internal class used to manage member value extraction and filtering.\n\t\t *\n\t\t * @param <T> the member type\n\t\t */\n\t\t@FunctionalInterface\n\t\tinterface ValueExtractor<T extends @Nullable Object> {\n\n\t\t\t/**\n\t\t\t * Represents a skipped value.\n\t\t\t */\n\t\t\tObject SKIP = new Object();\n\n\t\t\t/**\n\t\t\t * Extract the value from the given instance.\n\t\t\t * @param instance the source instance\n\t\t\t * @return the extracted value or {@link #SKIP}\n\t\t\t */\n\t\t\t@Nullable T extract(@Nullable Object instance);\n\n\t\t\t/**\n\t\t\t * Only extract when the given predicate matches.\n\t\t\t * @param predicate the predicate to test\n\t\t\t * @return a new {@link ValueExtractor}\n\t\t\t */\n\t\t\tdefault ValueExtractor<T> when(Predicate<? super @Nullable T> predicate) {\n\t\t\t\treturn (instance) -> test(extract(instance), predicate);\n\t\t\t}\n\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tprivate @Nullable T test(@Nullable T extracted, Predicate<? super @Nullable T> predicate) {\n\t\t\t\treturn (!skip(extracted) && predicate.test(extracted)) ? extracted : (T) SKIP;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Adapt the extracted value.\n\t\t\t * @param <R> the result type\n\t\t\t * @param extractor the extractor to use\n\t\t\t * @return a new {@link ValueExtractor}\n\t\t\t */\n\t\t\tdefault <R> ValueExtractor<R> as(Extractor<T, R> extractor) {\n\t\t\t\treturn (instance) -> apply(extract(instance), extractor);\n\t\t\t}\n\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tprivate <R> @Nullable R apply(@Nullable T value, Extractor<T, R> extractor) {\n\t\t\t\tif (skip(value)) {\n\t\t\t\t\treturn (R) SKIP;\n\t\t\t\t}\n\t\t\t\treturn (value != null) ? extractor.extract(value) : null;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Create a new {@link ValueExtractor} based on the given {@link Function}.\n\t\t\t * @param <S> the source type\n\t\t\t * @param <T> the extracted type\n\t\t\t * @param extractor the extractor to use\n\t\t\t * @return a new {@link ValueExtractor} instance\n\t\t\t */\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tstatic <S, T> ValueExtractor<T> of(Extractor<S, T> extractor) {\n\t\t\t\treturn (instance) -> {\n\t\t\t\t\tif (instance == null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\treturn (skip(instance)) ? (T) SKIP : extractor.extract((S) instance);\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Return if the extracted value should be skipped.\n\t\t\t * @param <T> the value type\n\t\t\t * @param extracted the value to test\n\t\t\t * @return if the value is to be skipped\n\t\t\t */\n\t\t\tstatic <T> boolean skip(@Nullable T extracted) {\n\t\t\t\treturn extracted == SKIP;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * A path used to identify a specific JSON member. Paths can be represented as strings\n\t * in form {@code \"my.json[1].item\"} where elements are separated by {@code '.' } or\n\t * {@code [<index>]}. Reserved characters are escaped using {@code '\\'}.\n\t *\n\t * @param parent the parent of this path\n\t * @param name the name of the member or {@code null} if the member is indexed. Path\n\t * names are provided as they were defined when the member was added and do not\n\t * include any {@link NameProcessor name processing}.\n\t * @param index the index of the member or {@link MemberPath#UNINDEXED}\n\t */\n\trecord MemberPath(@Nullable MemberPath parent, @Nullable String name, int index) {\n\n\t\tprivate static final String[] ESCAPED = { \"\\\\\", \".\", \"[\", \"]\" };\n\n\t\tpublic MemberPath {\n\t\t\tAssert.isTrue((name != null && index < 0) || (name == null && index >= 0),\n\t\t\t\t\t\"'name' and 'index' cannot be mixed\");\n\t\t}\n\n\t\t/**\n\t\t * Indicates that the member has no index.\n\t\t */\n\t\tpublic static final int UNINDEXED = -1;\n\n\t\t/**\n\t\t * The root of all member paths.\n\t\t */\n\t\tstatic final MemberPath ROOT = new MemberPath(null, \"\", UNINDEXED);\n\n\t\t/**\n\t\t * Create a new child from this path with the specified index.\n\t\t * @param index the index of the child\n\t\t * @return a new {@link MemberPath} instance\n\t\t */\n\t\tpublic MemberPath child(int index) {\n\t\t\treturn new MemberPath(this, null, index);\n\t\t}\n\n\t\t/**\n\t\t * Create a new child from this path with the specified name.\n\t\t * @param name the name of the child\n\t\t * @return a new {@link MemberPath} instance\n\t\t */\n\t\tpublic MemberPath child(String name) {\n\t\t\treturn (!StringUtils.hasLength(name)) ? this : new MemberPath(this, name, UNINDEXED);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn toString(true);\n\t\t}\n\n\t\t/**\n\t\t * Return a string representation of the path without any escaping.\n\t\t * @return the unescaped string representation\n\t\t */\n\t\tpublic String toUnescapedString() {\n\t\t\treturn toString(false);\n\t\t}\n\n\t\tprivate String toString(boolean escape) {\n\t\t\tStringBuilder string = new StringBuilder((this.parent != null) ? this.parent.toString(escape) : \"\");\n\t\t\tif (this.index >= 0) {\n\t\t\t\tstring.append(\"[\").append(this.index).append(\"]\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstring.append((!string.isEmpty()) ? \".\" : \"\").append((!escape) ? this.name : escape(this.name));\n\t\t\t}\n\t\t\treturn string.toString();\n\t\t}\n\n\t\tprivate @Nullable String escape(@Nullable String name) {\n\t\t\tif (name == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tfor (String escape : ESCAPED) {\n\t\t\t\tname = name.replace(escape, \"\\\\\" + escape);\n\t\t\t}\n\t\t\treturn name;\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link MemberPath} instance from the given string.\n\t\t * @param value the path value\n\t\t * @return a new {@link MemberPath} instance\n\t\t */\n\t\tpublic static MemberPath of(String value) {\n\t\t\tMemberPath path = MemberPath.ROOT;\n\t\t\tStringBuilder buffer = new StringBuilder();\n\t\t\tboolean escape = false;\n\t\t\tfor (char ch : value.toCharArray()) {\n\t\t\t\tif (!escape && ch == '\\\\') {\n\t\t\t\t\tescape = true;\n\t\t\t\t}\n\t\t\t\telse if (!escape && (ch == '.' || ch == '[')) {\n\t\t\t\t\tpath = path.child(buffer.toString());\n\t\t\t\t\tbuffer.setLength(0);\n\t\t\t\t}\n\t\t\t\telse if (!escape && ch == ']') {\n\t\t\t\t\tpath = path.child(Integer.parseUnsignedInt(buffer.toString()));\n\t\t\t\t\tbuffer.setLength(0);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuffer.append(ch);\n\t\t\t\t\tescape = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpath = path.child(buffer.toString());\n\t\t\treturn path;\n\t\t}\n\n\t}\n\n\t/**\n\t * Interface that can be used to extract name/value pairs from an element.\n\t *\n\t * @param <E> the element type\n\t */\n\tinterface PairExtractor<E> {\n\n\t\t/**\n\t\t * Extract the name.\n\t\t * @param <N> the name type\n\t\t * @param element the source element\n\t\t * @return the extracted name\n\t\t */\n\t\t<N> N getName(E element);\n\n\t\t/**\n\t\t * Extract the name.\n\t\t * @param <V> the value type\n\t\t * @param element the source element\n\t\t * @return the extracted value\n\t\t */\n\t\t<V> V getValue(E element);\n\n\t\t/**\n\t\t * Factory method to create a {@link PairExtractor} using distinct name and value\n\t\t * extraction functions.\n\t\t * @param <T> the element type\n\t\t * @param nameExtractor the name extractor\n\t\t * @param valueExtractor the value extraction\n\t\t * @return a new {@link PairExtractor} instance\n\t\t */\n\t\tstatic <T> PairExtractor<T> of(Function<T, ?> nameExtractor, Function<T, ?> valueExtractor) {\n\t\t\tAssert.notNull(nameExtractor, \"'nameExtractor' must not be null\");\n\t\t\tAssert.notNull(valueExtractor, \"'valueExtractor' must not be null\");\n\t\t\treturn new PairExtractor<>() {\n\n\t\t\t\t@Override\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tpublic <N> N getName(T instance) {\n\t\t\t\t\treturn (N) nameExtractor.apply(instance);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tpublic <V> V getValue(T instance) {\n\t\t\t\t\treturn (V) valueExtractor.apply(instance);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t/**\n\t * Callback interface that can be {@link Members#applyingNameProcessor(NameProcessor)\n\t * applied} to {@link Members} to change names or filter members.\n\t */\n\t@FunctionalInterface\n\tinterface NameProcessor {\n\n\t\t/**\n\t\t * Return a new name for the JSON member or {@code null} if the member should be\n\t\t * filtered entirely.\n\t\t * @param path the path of the member\n\t\t * @param existingName the existing and possibly already processed name.\n\t\t * @return the new name\n\t\t */\n\t\t@Nullable String processName(MemberPath path, String existingName);\n\n\t\t/**\n\t\t * Factory method to create a new {@link NameProcessor} for the given operation.\n\t\t * @param operation the operation to apply\n\t\t * @return a new {@link NameProcessor} instance\n\t\t */\n\t\tstatic NameProcessor of(UnaryOperator<String> operation) {\n\t\t\tAssert.notNull(operation, \"'operation' must not be null\");\n\t\t\treturn (path, existingName) -> operation.apply(existingName);\n\t\t}\n\n\t}\n\n\t/**\n\t * Callback interface that can be\n\t * {@link Members#applyingValueProcessor(ValueProcessor) applied} to {@link Members}\n\t * to process values before they are written. Typically used to filter values, for\n\t * example to reduce superfluous information or sanitize sensitive data.\n\t *\n\t * @param <T> the value type\n\t */\n\t@FunctionalInterface\n\tinterface ValueProcessor<T extends @Nullable Object> {\n\n\t\t/**\n\t\t * Process the value at the given path.\n\t\t * @param path the path of the member containing the value\n\t\t * @param value the value being written (may be {@code null})\n\t\t * @return the processed value\n\t\t */\n\t\t@Nullable T processValue(MemberPath path, @Nullable T value);\n\n\t\t/**\n\t\t * Return a new processor from this one that only applied to members with the\n\t\t * given path (ignoring escape characters).\n\t\t * @param path the patch to match\n\t\t * @return a new {@link ValueProcessor} that only applies when the path matches\n\t\t */\n\t\tdefault ValueProcessor<T> whenHasUnescapedPath(String path) {\n\t\t\treturn whenHasPath((candidate) -> candidate.toString(false).equals(path));\n\t\t}\n\n\t\t/**\n\t\t * Return a new processor from this one that only applied to members with the\n\t\t * given path.\n\t\t * @param path the patch to match\n\t\t * @return a new {@link ValueProcessor} that only applies when the path matches\n\t\t */\n\t\tdefault ValueProcessor<T> whenHasPath(String path) {\n\t\t\treturn whenHasPath(MemberPath.of(path)::equals);\n\t\t}\n\n\t\t/**\n\t\t * Return a new processor from this one that only applied to members that match\n\t\t * the given path predicate.\n\t\t * @param predicate the predicate that must match\n\t\t * @return a new {@link ValueProcessor} that only applies when the predicate\n\t\t * matches\n\t\t */\n\t\tdefault ValueProcessor<T> whenHasPath(Predicate<MemberPath> predicate) {\n\t\t\treturn (path, value) -> (predicate.test(path)) ? processValue(path, value) : value;\n\t\t}\n\n\t\t/**\n\t\t * Return a new processor from this one that only applies to member with values of\n\t\t * the given type.\n\t\t * @param type the type that must match\n\t\t * @return a new {@link ValueProcessor} that only applies when value is the given\n\t\t * type.\n\t\t */\n\t\tdefault ValueProcessor<T> whenInstanceOf(Class<?> type) {\n\t\t\tPredicate<@Nullable T> isInstance = type::isInstance;\n\t\t\treturn when(isInstance);\n\t\t}\n\n\t\t/**\n\t\t * Return a new processor from this one that only applies to member with values\n\t\t * that match the given predicate.\n\t\t * @param predicate the predicate that must match\n\t\t * @return a new {@link ValueProcessor} that only applies when the predicate\n\t\t * matches\n\t\t */\n\t\tdefault ValueProcessor<T> when(Predicate<@Nullable T> predicate) {\n\t\t\treturn (name, value) -> (predicate.test(value)) ? processValue(name, value) : value;\n\t\t}\n\n\t\t/**\n\t\t * Factory method to crate a new {@link ValueProcessor} that applies the given\n\t\t * action.\n\t\t * @param <T> the value type\n\t\t * @param type the value type\n\t\t * @param action the action to apply\n\t\t * @return a new {@link ValueProcessor} instance\n\t\t */\n\t\tstatic <T> ValueProcessor<T> of(Class<? extends T> type, UnaryOperator<@Nullable T> action) {\n\t\t\treturn of(action).whenInstanceOf(type);\n\t\t}\n\n\t\t/**\n\t\t * Factory method to crate a new {@link ValueProcessor} that applies the given\n\t\t * action.\n\t\t * @param <T> the value type\n\t\t * @param action the action to apply\n\t\t * @return a new {@link ValueProcessor} instance\n\t\t */\n\t\tstatic <T> ValueProcessor<T> of(UnaryOperator<@Nullable T> action) {\n\t\t\tAssert.notNull(action, \"'action' must not be null\");\n\t\t\treturn (name, value) -> action.apply(value);\n\t\t}\n\n\t}\n\n\t/**\n\t * Interface that can be used to extract one value from another.\n\t *\n\t * @param <T> the source type\n\t * @param <R> the result type\n\t */\n\t@FunctionalInterface\n\tinterface Extractor<T extends @Nullable Object, R extends @Nullable Object> {\n\n\t\t/**\n\t\t * Extract from the given value.\n\t\t * @param value the source value (never {@code null})\n\t\t * @return an extracted value or {@code null}\n\t\t */\n\t\t@Nullable R extract(@NonNull T value);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/JsonWriterFiltersAndProcessors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Predicate;\n\nimport org.springframework.boot.json.JsonWriter.MemberPath;\nimport org.springframework.boot.json.JsonWriter.NameProcessor;\nimport org.springframework.boot.json.JsonWriter.ValueProcessor;\n\n/**\n * Internal record used to hold {@link NameProcessor} and {@link ValueProcessor}\n * instances.\n *\n * @author Phillip Webb\n * @param pathFilters the path filters\n * @param nameProcessors the name processors\n * @param valueProcessors the value processors\n */\nrecord JsonWriterFiltersAndProcessors(List<Predicate<MemberPath>> pathFilters, List<NameProcessor> nameProcessors,\n\t\tList<ValueProcessor<?>> valueProcessors) {\n\n\tJsonWriterFiltersAndProcessors() {\n\t\tthis(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/WritableJson.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.UncheckedIOException;\nimport java.io.Writer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.core.io.WritableResource;\nimport org.springframework.util.Assert;\n\n/**\n * JSON content that can be written out.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 3.4.0\n * @see JsonWriter\n */\n@FunctionalInterface\npublic interface WritableJson {\n\n\t/**\n\t * Write the JSON to the provided {@link Appendable}.\n\t * @param out the {@link Appendable} to receive the JSON\n\t * @throws IOException on IO error\n\t */\n\tvoid to(Appendable out) throws IOException;\n\n\t/**\n\t * Write the JSON to a {@link String}.\n\t * @return the JSON string\n\t */\n\tdefault String toJsonString() {\n\t\ttry {\n\t\t\tStringBuilder stringBuilder = new StringBuilder();\n\t\t\tto(stringBuilder);\n\t\t\treturn stringBuilder.toString();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Write the JSON to a UTF-8 encoded byte array.\n\t * @return the JSON bytes\n\t */\n\tdefault byte[] toByteArray() {\n\t\treturn toByteArray(StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * Write the JSON to a byte array.\n\t * @param charset the charset\n\t * @return the JSON bytes\n\t */\n\tdefault byte[] toByteArray(Charset charset) {\n\t\tAssert.notNull(charset, \"'charset' must not be null\");\n\t\ttry (ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n\t\t\ttoWriter(new OutputStreamWriter(out, charset));\n\t\t\treturn out.toByteArray();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Write the JSON to the provided {@link WritableResource} using\n\t * {@link StandardCharsets#UTF_8 UTF8} encoding.\n\t * @param out the {@link OutputStream} to receive the JSON\n\t * @throws IOException on IO error\n\t */\n\tdefault void toResource(WritableResource out) throws IOException {\n\t\tAssert.notNull(out, \"'out' must not be null\");\n\t\ttry (OutputStream outputStream = out.getOutputStream()) {\n\t\t\ttoOutputStream(outputStream);\n\t\t}\n\t}\n\n\t/**\n\t * Write the JSON to the provided {@link WritableResource} using the given\n\t * {@link Charset}.\n\t * @param out the {@link OutputStream} to receive the JSON\n\t * @param charset the charset to use\n\t * @throws IOException on IO error\n\t */\n\tdefault void toResource(WritableResource out, Charset charset) throws IOException {\n\t\tAssert.notNull(out, \"'out' must not be null\");\n\t\tAssert.notNull(charset, \"'charset' must not be null\");\n\t\ttry (OutputStream outputStream = out.getOutputStream()) {\n\t\t\ttoOutputStream(outputStream, charset);\n\t\t}\n\t}\n\n\t/**\n\t * Write the JSON to the provided {@link OutputStream} using\n\t * {@link StandardCharsets#UTF_8 UTF8} encoding. The output stream will not be closed.\n\t * @param out the {@link OutputStream} to receive the JSON\n\t * @throws IOException on IO error\n\t * @see #toOutputStream(OutputStream, Charset)\n\t */\n\tdefault void toOutputStream(OutputStream out) throws IOException {\n\t\ttoOutputStream(out, StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * Write the JSON to the provided {@link OutputStream} using the given\n\t * {@link Charset}. The output stream will not be closed.\n\t * @param out the {@link OutputStream} to receive the JSON\n\t * @param charset the charset to use\n\t * @throws IOException on IO error\n\t */\n\tdefault void toOutputStream(OutputStream out, Charset charset) throws IOException {\n\t\tAssert.notNull(out, \"'out' must not be null\");\n\t\tAssert.notNull(charset, \"'charset' must not be null\");\n\t\ttoWriter(new OutputStreamWriter(out, charset));\n\t}\n\n\t/**\n\t * Write the JSON to the provided {@link Writer}. The writer will be flushed but not\n\t * closed.\n\t * @param out the {@link Writer} to receive the JSON\n\t * @throws IOException on IO error\n\t * @see #toOutputStream(OutputStream, Charset)\n\t */\n\tdefault void toWriter(Writer out) throws IOException {\n\t\tAssert.notNull(out, \"'out' must not be null\");\n\t\tto(out);\n\t\tout.flush();\n\t}\n\n\t/**\n\t * Factory method used to create a {@link WritableJson} with a sensible\n\t * {@link Object#toString()} that delegate to {@link WritableJson#toJsonString()}.\n\t * @param writableJson the source {@link WritableJson}\n\t * @return a new {@link WritableJson} with a sensible {@link Object#toString()}.\n\t */\n\tstatic WritableJson of(WritableJson writableJson) {\n\t\treturn new WritableJson() {\n\n\t\t\t@Override\n\t\t\tpublic void to(Appendable out) throws IOException {\n\t\t\t\twritableJson.to(out);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\treturn toJsonString();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/json/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for parsing JSON.\n *\n * @see org.springframework.boot.json.JsonParser\n */\n@NullMarked\npackage org.springframework.boot.json;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/AbstractLoggingSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.Comparator;\nimport java.util.EnumMap;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.SystemPropertyUtils;\n\n/**\n * Abstract base class for {@link LoggingSystem} implementations.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @since 1.0.0\n */\npublic abstract class AbstractLoggingSystem extends LoggingSystem {\n\n\tprotected static final Comparator<LoggerConfiguration> CONFIGURATION_COMPARATOR = new LoggerConfigurationComparator(\n\t\t\tROOT_LOGGER_NAME);\n\n\tprivate final ClassLoader classLoader;\n\n\tpublic AbstractLoggingSystem(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t@Override\n\tpublic void beforeInitialize() {\n\t}\n\n\t@Override\n\tpublic void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation,\n\t\t\t@Nullable LogFile logFile) {\n\t\tif (StringUtils.hasLength(configLocation)) {\n\t\t\tinitializeWithSpecificConfig(initializationContext, configLocation, logFile);\n\t\t\treturn;\n\t\t}\n\t\tinitializeWithConventions(initializationContext, logFile);\n\t}\n\n\tprivate void initializeWithSpecificConfig(LoggingInitializationContext initializationContext, String configLocation,\n\t\t\t@Nullable LogFile logFile) {\n\t\tconfigLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);\n\t\tloadConfiguration(initializationContext, configLocation, logFile);\n\t}\n\n\tprivate void initializeWithConventions(LoggingInitializationContext initializationContext,\n\t\t\t@Nullable LogFile logFile) {\n\t\tString config = getSelfInitializationConfig();\n\t\tif (config != null && logFile == null) {\n\t\t\t// self initialization has occurred, reinitialize in case of property changes\n\t\t\treinitialize(initializationContext);\n\t\t\treturn;\n\t\t}\n\t\tif (config == null) {\n\t\t\tconfig = getSpringInitializationConfig();\n\t\t}\n\t\tif (config != null) {\n\t\t\tloadConfiguration(initializationContext, config, logFile);\n\t\t\treturn;\n\t\t}\n\t\tloadDefaults(initializationContext, logFile);\n\t}\n\n\t/**\n\t * Return any self initialization config that has been applied. By default this method\n\t * checks {@link #getStandardConfigLocations()} and assumes that any file that exists\n\t * will have been applied.\n\t * @return the self initialization config or {@code null}\n\t */\n\tprotected @Nullable String getSelfInitializationConfig() {\n\t\treturn findConfig(getStandardConfigLocations());\n\t}\n\n\t/**\n\t * Return any spring specific initialization config that should be applied. By default\n\t * this method checks {@link #getSpringConfigLocations()}.\n\t * @return the spring initialization config or {@code null}\n\t */\n\tprotected @Nullable String getSpringInitializationConfig() {\n\t\treturn findConfig(getSpringConfigLocations());\n\t}\n\n\tprivate @Nullable String findConfig(String[] locations) {\n\t\tfor (String location : locations) {\n\t\t\tClassPathResource resource = new ClassPathResource(location, this.classLoader);\n\t\t\tif (resource.exists()) {\n\t\t\t\treturn \"classpath:\" + location;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the standard config locations for this system.\n\t * @return the standard config locations\n\t * @see #getSelfInitializationConfig()\n\t */\n\tprotected abstract String[] getStandardConfigLocations();\n\n\t/**\n\t * Return the spring config locations for this system. By default this method returns\n\t * a set of locations based on {@link #getStandardConfigLocations()}.\n\t * @return the spring config locations\n\t * @see #getSpringInitializationConfig()\n\t */\n\tprotected String[] getSpringConfigLocations() {\n\t\tString[] locations = getStandardConfigLocations();\n\t\tfor (int i = 0; i < locations.length; i++) {\n\t\t\tString extension = StringUtils.getFilenameExtension(locations[i]);\n\t\t\tint extensionLength = (extension != null) ? (extension.length() + 1) : 0;\n\t\t\tlocations[i] = locations[i].substring(0, locations[i].length() - extensionLength) + \"-spring.\" + extension;\n\t\t}\n\t\treturn locations;\n\t}\n\n\t/**\n\t * Load sensible defaults for the logging system.\n\t * @param initializationContext the logging initialization context\n\t * @param logFile the file to load or {@code null} if no log file is to be written\n\t */\n\tprotected abstract void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile);\n\n\t/**\n\t * Load a specific configuration.\n\t * @param initializationContext the logging initialization context\n\t * @param location the location of the configuration to load (never {@code null})\n\t * @param logFile the file to load or {@code null} if no log file is to be written\n\t */\n\tprotected abstract void loadConfiguration(LoggingInitializationContext initializationContext, String location,\n\t\t\t@Nullable LogFile logFile);\n\n\t/**\n\t * Reinitialize the logging system if required. Called when\n\t * {@link #getSelfInitializationConfig()} is used and the log file hasn't changed. May\n\t * be used to reload configuration (for example to pick up additional System\n\t * properties).\n\t * @param initializationContext the logging initialization context\n\t */\n\tprotected void reinitialize(LoggingInitializationContext initializationContext) {\n\t}\n\n\tprotected final ClassLoader getClassLoader() {\n\t\treturn this.classLoader;\n\t}\n\n\tprotected final String getPackagedConfigFile(String fileName) {\n\t\tString defaultPath = ClassUtils.getPackageName(getClass());\n\t\tdefaultPath = defaultPath.replace('.', '/');\n\t\tdefaultPath = defaultPath + \"/\" + fileName;\n\t\tdefaultPath = \"classpath:\" + defaultPath;\n\t\treturn defaultPath;\n\t}\n\n\tprotected final void applySystemProperties(Environment environment, @Nullable LogFile logFile) {\n\t\tnew LoggingSystemProperties(environment, getDefaultValueResolver(environment), null).apply(logFile);\n\t}\n\n\t/**\n\t * Return the default value resolver to use when resolving system properties.\n\t * @param environment the environment\n\t * @return the default value resolver\n\t * @since 3.2.0\n\t */\n\tprotected Function<@Nullable String, @Nullable String> getDefaultValueResolver(Environment environment) {\n\t\tString defaultLogCorrelationPattern = getDefaultLogCorrelationPattern();\n\t\treturn (name) -> {\n\t\t\tString applicationPropertyName = LoggingSystemProperty.CORRELATION_PATTERN.getApplicationPropertyName();\n\t\t\tAssert.state(applicationPropertyName != null, \"applicationPropertyName must not be null\");\n\t\t\tif (StringUtils.hasLength(defaultLogCorrelationPattern) && applicationPropertyName.equals(name)\n\t\t\t\t\t&& environment.getProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, Boolean.class, false)) {\n\t\t\t\treturn defaultLogCorrelationPattern;\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t}\n\n\t/**\n\t * Return the default log correlation pattern or {@code null} if log correlation\n\t * patterns are not supported.\n\t * @return the default log correlation pattern\n\t * @since 3.2.0\n\t */\n\tprotected @Nullable String getDefaultLogCorrelationPattern() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Maintains a mapping between native levels and {@link LogLevel}.\n\t *\n\t * @param <T> the native level type\n\t */\n\tprotected static class LogLevels<T> {\n\n\t\tprivate final Map<LogLevel, T> systemToNative;\n\n\t\tprivate final Map<T, LogLevel> nativeToSystem;\n\n\t\tpublic LogLevels() {\n\t\t\tthis.systemToNative = new EnumMap<>(LogLevel.class);\n\t\t\tthis.nativeToSystem = new HashMap<>();\n\t\t}\n\n\t\tpublic void map(LogLevel system, T nativeLevel) {\n\t\t\tthis.systemToNative.putIfAbsent(system, nativeLevel);\n\t\t\tthis.nativeToSystem.putIfAbsent(nativeLevel, system);\n\t\t}\n\n\t\tpublic @Nullable LogLevel convertNativeToSystem(T level) {\n\t\t\treturn this.nativeToSystem.get(level);\n\t\t}\n\n\t\tpublic @Nullable T convertSystemToNative(@Nullable LogLevel level) {\n\t\t\treturn this.systemToNative.get(level);\n\t\t}\n\n\t\tpublic Set<LogLevel> getSupported() {\n\t\t\treturn new LinkedHashSet<>(this.nativeToSystem.values());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/CorrelationIdFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.function.Predicate;\nimport java.util.function.UnaryOperator;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility class that can be used to format a correlation identifier for logging based on\n * <a href=\n * \"https://www.w3.org/TR/trace-context/#examples-of-http-traceparent-headers\">W3C</a>\n * recommendations.\n * <p>\n * The formatter can be configured with a comma-separated list of names and the expected\n * length of their resolved value. Each item should be specified in the form\n * {@code \"<name>(length)\"}. For example, {@code \"traceId(32),spanId(16)\"} specifies the\n * names {@code \"traceId\"} and {@code \"spanId\"} with expected lengths of {@code 32} and\n * {@code 16} respectively.\n * <p>\n * Correlation IDs are formatted as dash separated strings surrounded in square brackets.\n * Formatted output is always of a fixed width and with trailing space. Dashes are omitted\n * if none of the named items can be resolved.\n * <p>\n * The following example would return a formatted result of\n * {@code \"[01234567890123456789012345678901-0123456789012345] \"}: <pre class=\"code\">\n * CorrelationIdFormatter formatter = CorrelationIdFormatter.of(\"traceId(32),spanId(16)\");\n * Map&lt;String, String&gt; mdc = Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\");\n * return formatter.format(mdc::get);\n * </pre>\n * <p>\n * If {@link #of(String)} is called with an empty spec the {@link #DEFAULT} formatter will\n * be used.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see #of(String)\n * @see #of(Collection)\n */\npublic final class CorrelationIdFormatter {\n\n\t/**\n\t * Default {@link CorrelationIdFormatter}.\n\t */\n\tpublic static final CorrelationIdFormatter DEFAULT = CorrelationIdFormatter.of(\"traceId(32),spanId(16)\");\n\n\tprivate final List<Part> parts;\n\n\tprivate final String blank;\n\n\tprivate CorrelationIdFormatter(List<Part> parts) {\n\t\tthis.parts = parts;\n\t\tthis.blank = String.format(\"[%s] \", parts.stream().map(Part::blank).collect(Collectors.joining(\" \")));\n\t}\n\n\t/**\n\t * Format a correlation from the values in the given resolver.\n\t * @param resolver the resolver used to resolve named values\n\t * @return a formatted correlation id\n\t */\n\tpublic String format(UnaryOperator<@Nullable String> resolver) {\n\t\tStringBuilder result = new StringBuilder(this.blank.length());\n\t\tformatTo(resolver, result);\n\t\treturn result.toString();\n\t}\n\n\t/**\n\t * Format a correlation from the values in the given resolver and append it to the\n\t * given {@link Appendable}.\n\t * @param resolver the resolver used to resolve named values\n\t * @param appendable the appendable for the formatted correlation id\n\t */\n\tpublic void formatTo(UnaryOperator<@Nullable String> resolver, Appendable appendable) {\n\t\tPredicate<Part> canResolve = (part) -> StringUtils.hasLength(resolver.apply(part.name()));\n\t\ttry {\n\t\t\tif (this.parts.stream().anyMatch(canResolve)) {\n\t\t\t\tappendable.append('[');\n\t\t\t\tfor (Iterator<Part> iterator = this.parts.iterator(); iterator.hasNext();) {\n\t\t\t\t\tappendable.append(iterator.next().resolve(resolver));\n\t\t\t\t\tif (iterator.hasNext()) {\n\t\t\t\t\t\tappendable.append('-');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tappendable.append(\"] \");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tappendable.append(this.blank);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.parts.stream().map(Part::toString).collect(Collectors.joining(\",\"));\n\t}\n\n\t/**\n\t * Create a new {@link CorrelationIdFormatter} instance from the given specification.\n\t * @param spec a comma-separated specification\n\t * @return a new {@link CorrelationIdFormatter} instance\n\t */\n\tpublic static CorrelationIdFormatter of(@Nullable String spec) {\n\t\ttry {\n\t\t\treturn (!StringUtils.hasText(spec)) ? DEFAULT : of(List.of(spec.split(\",\")));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to parse correlation formatter spec '%s'\".formatted(spec), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Create a new {@link CorrelationIdFormatter} instance from the given specification.\n\t * @param spec a pre-separated specification\n\t * @return a new {@link CorrelationIdFormatter} instance\n\t */\n\tpublic static CorrelationIdFormatter of(String @Nullable [] spec) {\n\t\treturn of((spec != null) ? List.of(spec) : Collections.emptyList());\n\t}\n\n\t/**\n\t * Create a new {@link CorrelationIdFormatter} instance from the given specification.\n\t * @param spec a pre-separated specification\n\t * @return a new {@link CorrelationIdFormatter} instance\n\t */\n\tpublic static CorrelationIdFormatter of(Collection<String> spec) {\n\t\tif (CollectionUtils.isEmpty(spec)) {\n\t\t\treturn DEFAULT;\n\t\t}\n\t\tList<Part> parts = spec.stream().map(Part::of).toList();\n\t\treturn new CorrelationIdFormatter(parts);\n\t}\n\n\t/**\n\t * A part of the correlation id.\n\t *\n\t * @param name the name of the correlation part\n\t * @param length the expected length of the correlation part\n\t */\n\trecord Part(String name, int length) {\n\n\t\tprivate static final Pattern pattern = Pattern.compile(\"^(.+?)\\\\((\\\\d+)\\\\)$\");\n\n\t\tString resolve(UnaryOperator<@Nullable String> resolver) {\n\t\t\tString resolved = resolver.apply(name());\n\t\t\tif (resolved == null) {\n\t\t\t\treturn blank();\n\t\t\t}\n\t\t\tint padding = length() - resolved.length();\n\t\t\treturn (padding <= 0) ? resolved : resolved + \" \".repeat(padding);\n\t\t}\n\n\t\tString blank() {\n\t\t\treturn \" \".repeat(this.length);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"%s(%s)\".formatted(name(), length());\n\t\t}\n\n\t\tstatic Part of(String part) {\n\t\t\tMatcher matcher = pattern.matcher(part.trim());\n\t\t\tAssert.state(matcher.matches(), () -> \"Invalid specification part '%s'\".formatted(part));\n\t\t\tString name = matcher.group(1);\n\t\t\tint length = Integer.parseInt(matcher.group(2));\n\t\t\treturn new Part(name, length);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLog.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Deferred {@link Log} that can be used to store messages that shouldn't be written until\n * the logging system is fully initialized.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class DeferredLog implements Log {\n\n\tprivate @Nullable Log destination;\n\n\tprivate final @Nullable Supplier<Log> destinationSupplier;\n\n\tprivate final Lines lines;\n\n\t/**\n\t * Create a new {@link DeferredLog} instance.\n\t */\n\tpublic DeferredLog() {\n\t\tthis.destinationSupplier = null;\n\t\tthis.lines = new Lines();\n\t}\n\n\t/**\n\t * Create a new {@link DeferredLog} instance managed by a {@link DeferredLogFactory}.\n\t * @param destination the switch-over destination\n\t * @param lines the lines backing all related deferred logs\n\t * @since 2.4.0\n\t */\n\tDeferredLog(Supplier<Log> destination, Lines lines) {\n\t\tAssert.notNull(destination, \"'destination' must not be null\");\n\t\tthis.destinationSupplier = destination;\n\t\tthis.lines = lines;\n\t}\n\n\t@Override\n\tpublic boolean isTraceEnabled() {\n\t\tsynchronized (this.lines) {\n\t\t\treturn (this.destination == null) || this.destination.isTraceEnabled();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isDebugEnabled() {\n\t\tsynchronized (this.lines) {\n\t\t\treturn (this.destination == null) || this.destination.isDebugEnabled();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isInfoEnabled() {\n\t\tsynchronized (this.lines) {\n\t\t\treturn (this.destination == null) || this.destination.isInfoEnabled();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isWarnEnabled() {\n\t\tsynchronized (this.lines) {\n\t\t\treturn (this.destination == null) || this.destination.isWarnEnabled();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isErrorEnabled() {\n\t\tsynchronized (this.lines) {\n\t\t\treturn (this.destination == null) || this.destination.isErrorEnabled();\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isFatalEnabled() {\n\t\tsynchronized (this.lines) {\n\t\t\treturn (this.destination == null) || this.destination.isFatalEnabled();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void trace(Object message) {\n\t\tlog(LogLevel.TRACE, message, null);\n\t}\n\n\t@Override\n\tpublic void trace(Object message, @Nullable Throwable t) {\n\t\tlog(LogLevel.TRACE, message, t);\n\t}\n\n\t@Override\n\tpublic void debug(Object message) {\n\t\tlog(LogLevel.DEBUG, message, null);\n\t}\n\n\t@Override\n\tpublic void debug(Object message, @Nullable Throwable t) {\n\t\tlog(LogLevel.DEBUG, message, t);\n\t}\n\n\t@Override\n\tpublic void info(Object message) {\n\t\tlog(LogLevel.INFO, message, null);\n\t}\n\n\t@Override\n\tpublic void info(Object message, @Nullable Throwable t) {\n\t\tlog(LogLevel.INFO, message, t);\n\t}\n\n\t@Override\n\tpublic void warn(Object message) {\n\t\tlog(LogLevel.WARN, message, null);\n\t}\n\n\t@Override\n\tpublic void warn(Object message, @Nullable Throwable t) {\n\t\tlog(LogLevel.WARN, message, t);\n\t}\n\n\t@Override\n\tpublic void error(Object message) {\n\t\tlog(LogLevel.ERROR, message, null);\n\t}\n\n\t@Override\n\tpublic void error(Object message, @Nullable Throwable t) {\n\t\tlog(LogLevel.ERROR, message, t);\n\t}\n\n\t@Override\n\tpublic void fatal(Object message) {\n\t\tlog(LogLevel.FATAL, message, null);\n\t}\n\n\t@Override\n\tpublic void fatal(Object message, @Nullable Throwable t) {\n\t\tlog(LogLevel.FATAL, message, t);\n\t}\n\n\tprivate void log(LogLevel level, Object message, @Nullable Throwable t) {\n\t\tsynchronized (this.lines) {\n\t\t\tif (this.destination != null) {\n\t\t\t\tlevel.log(this.destination, message, t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.lines.add(this.destinationSupplier, level, message, t);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid switchOver() {\n\t\tsynchronized (this.lines) {\n\t\t\tAssert.state(this.destinationSupplier != null, \"destinationSupplier hasn't been set\");\n\t\t\tthis.destination = this.destinationSupplier.get();\n\t\t}\n\t}\n\n\t/**\n\t * Switch from deferred logging to immediate logging to the specified destination.\n\t * @param destination the new log destination\n\t * @since 2.1.0\n\t */\n\tpublic void switchTo(Class<?> destination) {\n\t\tswitchTo(LogFactory.getLog(destination));\n\t}\n\n\t/**\n\t * Switch from deferred logging to immediate logging to the specified destination.\n\t * @param destination the new log destination\n\t * @since 2.1.0\n\t */\n\tpublic void switchTo(Log destination) {\n\t\tsynchronized (this.lines) {\n\t\t\treplayTo(destination);\n\t\t\tthis.destination = destination;\n\t\t}\n\t}\n\n\t/**\n\t * Replay deferred logging to the specified destination.\n\t * @param destination the destination for the deferred log messages\n\t */\n\tpublic void replayTo(Class<?> destination) {\n\t\treplayTo(LogFactory.getLog(destination));\n\t}\n\n\t/**\n\t * Replay deferred logging to the specified destination.\n\t * @param destination the destination for the deferred log messages\n\t */\n\tpublic void replayTo(Log destination) {\n\t\tsynchronized (this.lines) {\n\t\t\tfor (Line line : this.lines) {\n\t\t\t\tline.getLevel().log(destination, line.getMessage(), line.getThrowable());\n\t\t\t}\n\t\t\tthis.lines.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Replay from a source log to a destination log when the source is deferred.\n\t * @param source the source logger\n\t * @param destination the destination logger class\n\t * @return the destination\n\t */\n\tpublic static Log replay(Log source, Class<?> destination) {\n\t\treturn replay(source, LogFactory.getLog(destination));\n\t}\n\n\t/**\n\t * Replay from a source log to a destination log when the source is deferred.\n\t * @param source the source logger\n\t * @param destination the destination logger\n\t * @return the destination\n\t */\n\tpublic static Log replay(Log source, Log destination) {\n\t\tif (source instanceof DeferredLog deferredLog) {\n\t\t\tdeferredLog.replayTo(destination);\n\t\t}\n\t\treturn destination;\n\t}\n\n\tstatic class Lines implements Iterable<Line> {\n\n\t\tprivate final List<Line> lines = new ArrayList<>();\n\n\t\tvoid add(@Nullable Supplier<Log> destinationSupplier, LogLevel level, Object message,\n\t\t\t\t@Nullable Throwable throwable) {\n\t\t\tthis.lines.add(new Line(destinationSupplier, level, message, throwable));\n\t\t}\n\n\t\tvoid clear() {\n\t\t\tthis.lines.clear();\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<Line> iterator() {\n\t\t\treturn this.lines.iterator();\n\t\t}\n\n\t}\n\n\tstatic class Line {\n\n\t\tprivate final @Nullable Supplier<Log> destinationSupplier;\n\n\t\tprivate final LogLevel level;\n\n\t\tprivate final Object message;\n\n\t\tprivate final @Nullable Throwable throwable;\n\n\t\tLine(@Nullable Supplier<Log> destinationSupplier, LogLevel level, Object message,\n\t\t\t\t@Nullable Throwable throwable) {\n\t\t\tthis.destinationSupplier = destinationSupplier;\n\t\t\tthis.level = level;\n\t\t\tthis.message = message;\n\t\t\tthis.throwable = throwable;\n\t\t}\n\n\t\tLog getDestination() {\n\t\t\tAssert.state(this.destinationSupplier != null, \"destinationSupplier hasn't been set\");\n\t\t\treturn this.destinationSupplier.get();\n\t\t}\n\n\t\tLogLevel getLevel() {\n\t\t\treturn this.level;\n\t\t}\n\n\t\tObject getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\t@Nullable Throwable getThrowable() {\n\t\t\treturn this.throwable;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLogFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\n/**\n * Factory that can be used to create multiple {@link DeferredLog} instances that will\n * switch over when appropriate.\n *\n * @author Phillip Webb\n * @since 2.4.0\n * @see DeferredLogs\n */\n@FunctionalInterface\npublic interface DeferredLogFactory {\n\n\t/**\n\t * Create a new {@link DeferredLog} for the given destination.\n\t * @param destination the ultimate log destination\n\t * @return a deferred log instance that will switch to the destination when\n\t * appropriate.\n\t */\n\tdefault Log getLog(Class<?> destination) {\n\t\treturn getLog(() -> LogFactory.getLog(destination));\n\t}\n\n\t/**\n\t * Create a new {@link DeferredLog} for the given destination.\n\t * @param destination the ultimate log destination\n\t * @return a deferred log instance that will switch to the destination when\n\t * appropriate.\n\t */\n\tdefault Log getLog(Log destination) {\n\t\treturn getLog(() -> destination);\n\t}\n\n\t/**\n\t * Create a new {@link DeferredLog} for the given destination.\n\t * @param destination the ultimate log destination\n\t * @return a deferred log instance that will switch to the destination when\n\t * appropriate.\n\t */\n\tLog getLog(Supplier<Log> destination);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/DeferredLogs.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.logging.DeferredLog.Line;\nimport org.springframework.boot.logging.DeferredLog.Lines;\n\n/**\n * A {@link DeferredLogFactory} implementation that manages a collection\n * {@link DeferredLog} instances.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic class DeferredLogs implements DeferredLogFactory {\n\n\tprivate final Lines lines = new Lines();\n\n\tprivate final List<DeferredLog> loggers = new ArrayList<>();\n\n\t/**\n\t * Create a new {@link DeferredLog} for the given destination.\n\t * @param destination the ultimate log destination\n\t * @return a deferred log instance that will switch to the destination when\n\t * appropriate.\n\t */\n\t@Override\n\tpublic Log getLog(Class<?> destination) {\n\t\treturn getLog(() -> LogFactory.getLog(destination));\n\t}\n\n\t/**\n\t * Create a new {@link DeferredLog} for the given destination.\n\t * @param destination the ultimate log destination\n\t * @return a deferred log instance that will switch to the destination when\n\t * appropriate.\n\t */\n\t@Override\n\tpublic Log getLog(Log destination) {\n\t\treturn getLog(() -> destination);\n\t}\n\n\t/**\n\t * Create a new {@link DeferredLog} for the given destination.\n\t * @param destination the ultimate log destination\n\t * @return a deferred log instance that will switch to the destination when\n\t * appropriate.\n\t */\n\t@Override\n\tpublic Log getLog(Supplier<Log> destination) {\n\t\tsynchronized (this.lines) {\n\t\t\tDeferredLog logger = new DeferredLog(destination, this.lines);\n\t\t\tthis.loggers.add(logger);\n\t\t\treturn logger;\n\t\t}\n\t}\n\n\t/**\n\t * Switch over all deferred logs to their supplied destination.\n\t */\n\tpublic void switchOverAll() {\n\t\tsynchronized (this.lines) {\n\t\t\tfor (Line line : this.lines) {\n\t\t\t\tline.getLevel().log(line.getDestination(), line.getMessage(), line.getThrowable());\n\t\t\t}\n\t\t\tfor (DeferredLog logger : this.loggers) {\n\t\t\t\tlogger.switchOver();\n\t\t\t}\n\t\t\tthis.lines.clear();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/DelegatingLoggingSystemFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link LoggingSystemFactory} that delegates to other factories.\n *\n * @author Phillip Webb\n */\nclass DelegatingLoggingSystemFactory implements LoggingSystemFactory {\n\n\tprivate final @Nullable Function<ClassLoader, @Nullable List<LoggingSystemFactory>> delegates;\n\n\t/**\n\t * Create a new {@link DelegatingLoggingSystemFactory} instance.\n\t * @param delegates a function that provides the delegates\n\t */\n\tDelegatingLoggingSystemFactory(@Nullable Function<ClassLoader, @Nullable List<LoggingSystemFactory>> delegates) {\n\t\tthis.delegates = delegates;\n\t}\n\n\t@Override\n\tpublic @Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader) {\n\t\tList<LoggingSystemFactory> delegates = (this.delegates != null) ? this.delegates.apply(classLoader) : null;\n\t\tif (delegates != null) {\n\t\t\tfor (LoggingSystemFactory delegate : delegates) {\n\t\t\t\tLoggingSystem loggingSystem = delegate.getLoggingSystem(classLoader);\n\t\t\t\tif (loggingSystem != null) {\n\t\t\t\t\treturn loggingSystem;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LogFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.File;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A reference to a log output file. Log output files are specified using\n * {@code logging.file.name} or {@code logging.file.path} {@link Environment} properties.\n * If the {@code logging.file.name} property is not specified {@code \"spring.log\"} will be\n * written in the {@code logging.file.path} directory.\n *\n * @author Phillip Webb\n * @author Christian Carriere-Tisseur\n * @since 1.2.1\n * @see #get(PropertyResolver)\n */\npublic class LogFile {\n\n\t/**\n\t * The name of the Spring property that contains the name of the log file. Names can\n\t * be an exact location or relative to the current directory.\n\t * @since 2.2.0\n\t */\n\tpublic static final String FILE_NAME_PROPERTY = \"logging.file.name\";\n\n\t/**\n\t * The name of the Spring property that contains the directory where log files are\n\t * written.\n\t * @since 2.2.0\n\t */\n\tpublic static final String FILE_PATH_PROPERTY = \"logging.file.path\";\n\n\tprivate final @Nullable String file;\n\n\tprivate final @Nullable String path;\n\n\t/**\n\t * Create a new {@link LogFile} instance.\n\t * @param file a reference to the file to write\n\t */\n\tLogFile(String file) {\n\t\tthis(file, null);\n\t}\n\n\t/**\n\t * Create a new {@link LogFile} instance.\n\t * @param file a reference to the file to write\n\t * @param path a reference to the logging path to use if {@code file} is not specified\n\t */\n\tLogFile(@Nullable String file, @Nullable String path) {\n\t\tAssert.isTrue(StringUtils.hasLength(file) || StringUtils.hasLength(path), \"'file' or 'path' must not be empty\");\n\t\tthis.file = file;\n\t\tthis.path = path;\n\t}\n\n\t/**\n\t * Apply log file details to {@code LOG_PATH} and {@code LOG_FILE} system properties.\n\t */\n\tpublic void applyToSystemProperties() {\n\t\tapplyTo(System.getProperties());\n\t}\n\n\t/**\n\t * Apply log file details to {@code LOG_PATH} and {@code LOG_FILE} map entries.\n\t * @param properties the properties to apply to\n\t */\n\tpublic void applyTo(Properties properties) {\n\t\tput(properties, LoggingSystemProperty.LOG_PATH, this.path);\n\t\tput(properties, LoggingSystemProperty.LOG_FILE, toString());\n\t}\n\n\tprivate void put(Properties properties, LoggingSystemProperty property, @Nullable String value) {\n\t\tif (StringUtils.hasLength(value)) {\n\t\t\tproperties.put(property.getEnvironmentVariableName(), value);\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tif (StringUtils.hasLength(this.file)) {\n\t\t\treturn this.file;\n\t\t}\n\t\treturn new File(this.path, \"spring.log\").getPath();\n\t}\n\n\t/**\n\t * Get a {@link LogFile} from the given Spring {@link Environment}.\n\t * @param propertyResolver the {@link PropertyResolver} used to obtain the logging\n\t * properties\n\t * @return a {@link LogFile} or {@code null} if the environment didn't contain any\n\t * suitable properties\n\t */\n\tpublic static @Nullable LogFile get(PropertyResolver propertyResolver) {\n\t\tString file = propertyResolver.getProperty(FILE_NAME_PROPERTY);\n\t\tString path = propertyResolver.getProperty(FILE_PATH_PROPERTY);\n\t\tif (StringUtils.hasLength(file) || StringUtils.hasLength(path)) {\n\t\t\treturn new LogFile(file, path);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LogLevel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Logging levels supported by a {@link LoggingSystem}.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic enum LogLevel {\n\n\tTRACE(Log::trace),\n\n\tDEBUG(Log::debug),\n\n\tINFO(Log::info),\n\n\tWARN(Log::warn),\n\n\tERROR(Log::error),\n\n\tFATAL(Log::fatal),\n\n\tOFF(null);\n\n\tprivate final @Nullable LogMethod logMethod;\n\n\tLogLevel(@Nullable LogMethod logMethod) {\n\t\tthis.logMethod = logMethod;\n\t}\n\n\t/**\n\t * Log a message to the given logger at this level.\n\t * @param logger the logger\n\t * @param message the message to log\n\t * @since 3.1.0\n\t */\n\tpublic void log(Log logger, Object message) {\n\t\tlog(logger, message, null);\n\t}\n\n\t/**\n\t * Log a message to the given logger at this level.\n\t * @param logger the logger\n\t * @param message the message to log\n\t * @param cause the cause to log\n\t * @since 3.1.0\n\t */\n\tpublic void log(@Nullable Log logger, Object message, @Nullable Throwable cause) {\n\t\tif (logger != null && this.logMethod != null) {\n\t\t\tthis.logMethod.log(logger, message, cause);\n\t\t}\n\t}\n\n\t@FunctionalInterface\n\tprivate interface LogMethod {\n\n\t\tvoid log(Log logger, Object message, @Nullable Throwable cause);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Immutable class that represents the configuration of a {@link LoggingSystem}'s logger.\n *\n * @author Ben Hale\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic final class LoggerConfiguration {\n\n\tprivate final String name;\n\n\tprivate final @Nullable LevelConfiguration levelConfiguration;\n\n\tprivate final LevelConfiguration inheritedLevelConfiguration;\n\n\t/**\n\t * Create a new {@link LoggerConfiguration instance}.\n\t * @param name the name of the logger\n\t * @param configuredLevel the configured level of the logger\n\t * @param effectiveLevel the effective level of the logger\n\t */\n\tpublic LoggerConfiguration(String name, @Nullable LogLevel configuredLevel, LogLevel effectiveLevel) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(effectiveLevel, \"'effectiveLevel' must not be null\");\n\t\tthis.name = name;\n\t\tthis.levelConfiguration = (configuredLevel != null) ? LevelConfiguration.of(configuredLevel) : null;\n\t\tthis.inheritedLevelConfiguration = LevelConfiguration.of(effectiveLevel);\n\t}\n\n\t/**\n\t * Create a new {@link LoggerConfiguration instance}.\n\t * @param name the name of the logger\n\t * @param levelConfiguration the level configuration\n\t * @param inheritedLevelConfiguration the inherited level configuration\n\t * @since 2.7.13\n\t */\n\tpublic LoggerConfiguration(String name, @Nullable LevelConfiguration levelConfiguration,\n\t\t\tLevelConfiguration inheritedLevelConfiguration) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(inheritedLevelConfiguration, \"'inheritedLevelConfiguration' must not be null\");\n\t\tthis.name = name;\n\t\tthis.levelConfiguration = levelConfiguration;\n\t\tthis.inheritedLevelConfiguration = inheritedLevelConfiguration;\n\t}\n\n\t/**\n\t * Returns the name of the logger.\n\t * @return the name of the logger\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Returns the configured level of the logger.\n\t * @return the configured level of the logger\n\t * @see #getLevelConfiguration(ConfigurationScope)\n\t */\n\tpublic @Nullable LogLevel getConfiguredLevel() {\n\t\tLevelConfiguration configuration = getLevelConfiguration(ConfigurationScope.DIRECT);\n\t\treturn (configuration != null) ? configuration.getLevel() : null;\n\t}\n\n\t/**\n\t * Returns the effective level of the logger.\n\t * @return the effective level of the logger\n\t * @see #getLevelConfiguration(ConfigurationScope)\n\t */\n\tpublic LogLevel getEffectiveLevel() {\n\t\treturn getLevelConfiguration().getLevel();\n\t}\n\n\t/**\n\t * Return the level configuration, considering inherited loggers.\n\t * @return the level configuration\n\t * @since 2.7.13\n\t */\n\tpublic LevelConfiguration getLevelConfiguration() {\n\t\tLevelConfiguration result = getLevelConfiguration(ConfigurationScope.INHERITED);\n\t\tAssert.state(result != null, \"Inherited level configuration must not be null\");\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the level configuration for the given scope.\n\t * @param scope the configuration scope\n\t * @return the level configuration or {@code null} for\n\t * {@link ConfigurationScope#DIRECT direct scope} results without applied\n\t * configuration\n\t * @since 2.7.13\n\t */\n\tpublic @Nullable LevelConfiguration getLevelConfiguration(ConfigurationScope scope) {\n\t\treturn (scope != ConfigurationScope.DIRECT) ? this.inheritedLevelConfiguration : this.levelConfiguration;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tLoggerConfiguration other = (LoggerConfiguration) obj;\n\t\treturn ObjectUtils.nullSafeEquals(this.name, other.name)\n\t\t\t\t&& ObjectUtils.nullSafeEquals(this.levelConfiguration, other.levelConfiguration)\n\t\t\t\t&& ObjectUtils.nullSafeEquals(this.inheritedLevelConfiguration, other.inheritedLevelConfiguration);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.name, this.levelConfiguration, this.inheritedLevelConfiguration);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"LoggerConfiguration [name=\" + this.name + \", levelConfiguration=\" + this.levelConfiguration\n\t\t\t\t+ \", inheritedLevelConfiguration=\" + this.inheritedLevelConfiguration + \"]\";\n\t}\n\n\t/**\n\t * Supported logger configuration scopes.\n\t *\n\t * @since 2.7.13\n\t */\n\tpublic enum ConfigurationScope {\n\n\t\t/**\n\t\t * Only return configuration that has been applied directly. Often referred to as\n\t\t * 'configured' or 'assigned' configuration.\n\t\t */\n\t\tDIRECT,\n\n\t\t/**\n\t\t * May return configuration that has been applied to a parent logger. Often\n\t\t * referred to as 'effective' configuration.\n\t\t */\n\t\tINHERITED\n\n\t}\n\n\t/**\n\t * Logger level configuration.\n\t *\n\t * @since 2.7.13\n\t */\n\tpublic static final class LevelConfiguration {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable LogLevel logLevel;\n\n\t\tprivate LevelConfiguration(String name, @Nullable LogLevel logLevel) {\n\t\t\tthis.name = name;\n\t\t\tthis.logLevel = logLevel;\n\t\t}\n\n\t\t/**\n\t\t * Return the name of the level.\n\t\t * @return the level name\n\t\t */\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t/**\n\t\t * Return the actual level value if possible.\n\t\t * @return the level value\n\t\t * @throws IllegalStateException if this is a {@link #isCustom() custom} level\n\t\t */\n\t\tpublic LogLevel getLevel() {\n\t\t\tAssert.state(this.logLevel != null, () -> \"Unable to provide LogLevel for '\" + this.name + \"'\");\n\t\t\treturn this.logLevel;\n\t\t}\n\n\t\t/**\n\t\t * Return if this is a custom level and cannot be represented by {@link LogLevel}.\n\t\t * @return if this is a custom level\n\t\t */\n\t\tpublic boolean isCustom() {\n\t\t\treturn this.logLevel == null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tLevelConfiguration other = (LevelConfiguration) obj;\n\t\t\treturn this.logLevel == other.logLevel && ObjectUtils.nullSafeEquals(this.name, other.name);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Objects.hash(this.logLevel, this.name);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"LevelConfiguration [name=\" + this.name + \", logLevel=\" + this.logLevel + \"]\";\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link LevelConfiguration} instance of the given {@link LogLevel}.\n\t\t * @param logLevel the log level\n\t\t * @return a new {@link LevelConfiguration} instance\n\t\t */\n\t\tpublic static LevelConfiguration of(LogLevel logLevel) {\n\t\t\tAssert.notNull(logLevel, \"'logLevel' must not be null\");\n\t\t\treturn new LevelConfiguration(logLevel.name(), logLevel);\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link LevelConfiguration} instance for a custom level name.\n\t\t * @param name the log level name\n\t\t * @return a new {@link LevelConfiguration} instance\n\t\t */\n\t\tpublic static LevelConfiguration ofCustom(String name) {\n\t\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\t\treturn new LevelConfiguration(name, null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggerConfigurationComparator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.Comparator;\n\nimport org.springframework.util.Assert;\n\n/**\n * An implementation of {@link Comparator} for comparing {@link LoggerConfiguration}s.\n * Sorts the \"root\" logger as the first logger and then lexically by name after that.\n *\n * @author Ben Hale\n */\nclass LoggerConfigurationComparator implements Comparator<LoggerConfiguration> {\n\n\tprivate final String rootLoggerName;\n\n\t/**\n\t * Create a new {@link LoggerConfigurationComparator} instance.\n\t * @param rootLoggerName the name of the \"root\" logger\n\t */\n\tLoggerConfigurationComparator(String rootLoggerName) {\n\t\tAssert.notNull(rootLoggerName, \"'rootLoggerName' must not be null\");\n\t\tthis.rootLoggerName = rootLoggerName;\n\t}\n\n\t@Override\n\tpublic int compare(LoggerConfiguration o1, LoggerConfiguration o2) {\n\t\tif (this.rootLoggerName.equals(o1.getName())) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (this.rootLoggerName.equals(o2.getName())) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn o1.getName().compareTo(o2.getName());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggerGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A single logger group.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.2.0\n */\npublic final class LoggerGroup {\n\n\tprivate final String name;\n\n\tprivate final List<String> members;\n\n\tprivate @Nullable LogLevel configuredLevel;\n\n\tLoggerGroup(String name, List<String> members) {\n\t\tthis.name = name;\n\t\tthis.members = Collections.unmodifiableList(new ArrayList<>(members));\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic List<String> getMembers() {\n\t\treturn this.members;\n\t}\n\n\tpublic boolean hasMembers() {\n\t\treturn !this.members.isEmpty();\n\t}\n\n\tpublic @Nullable LogLevel getConfiguredLevel() {\n\t\treturn this.configuredLevel;\n\t}\n\n\tpublic void configureLogLevel(@Nullable LogLevel level, BiConsumer<String, @Nullable LogLevel> configurer) {\n\t\tthis.configuredLevel = level;\n\t\tthis.members.forEach((name) -> configurer.accept(name, level));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggerGroups.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Logger groups configured through the Spring Environment.\n *\n * @author HaiTao Zhang\n * @author Phillip Webb\n * @since 2.2.0\n * @see LoggerGroup\n */\npublic final class LoggerGroups implements Iterable<LoggerGroup> {\n\n\tprivate final Map<String, LoggerGroup> groups = new ConcurrentHashMap<>();\n\n\tpublic LoggerGroups() {\n\t}\n\n\tpublic LoggerGroups(Map<String, List<String>> namesAndMembers) {\n\t\tputAll(namesAndMembers);\n\t}\n\n\tpublic void putAll(Map<String, List<String>> namesAndMembers) {\n\t\tnamesAndMembers.forEach(this::put);\n\t}\n\n\tprivate void put(String name, List<String> members) {\n\t\tput(new LoggerGroup(name, members));\n\t}\n\n\tprivate void put(LoggerGroup loggerGroup) {\n\t\tthis.groups.put(loggerGroup.getName(), loggerGroup);\n\t}\n\n\tpublic @Nullable LoggerGroup get(String name) {\n\t\treturn this.groups.get(name);\n\t}\n\n\t@Override\n\tpublic Iterator<LoggerGroup> iterator() {\n\t\treturn this.groups.values().iterator();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggingInitializationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\n/**\n * Context passed to the {@link LoggingSystem} during initialization.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class LoggingInitializationContext {\n\n\tprivate final @Nullable ConfigurableEnvironment environment;\n\n\t/**\n\t * Create a new {@link LoggingInitializationContext} instance.\n\t * @param environment the Spring environment.\n\t */\n\tpublic LoggingInitializationContext(@Nullable ConfigurableEnvironment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * Return the Spring environment if available.\n\t * @return the {@link Environment} or {@code null}\n\t */\n\tpublic @Nullable Environment getEnvironment() {\n\t\treturn this.environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.lang.reflect.Constructor;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Common abstraction over logging systems.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Ben Hale\n * @since 1.0.0\n */\npublic abstract class LoggingSystem {\n\n\t/**\n\t * A System property that can be used to indicate the {@link LoggingSystem} to use.\n\t */\n\tpublic static final String SYSTEM_PROPERTY = LoggingSystem.class.getName();\n\n\t/**\n\t * The value of the {@link #SYSTEM_PROPERTY} that can be used to indicate that no\n\t * {@link LoggingSystem} should be used.\n\t */\n\tpublic static final String NONE = \"none\";\n\n\t/**\n\t * The name used for the root logger. LoggingSystem implementations should ensure that\n\t * this is the name used to represent the root logger, regardless of the underlying\n\t * implementation.\n\t */\n\tpublic static final String ROOT_LOGGER_NAME = \"ROOT\";\n\n\tprivate static final LoggingSystemFactory SYSTEM_FACTORY = LoggingSystemFactory.fromSpringFactories();\n\n\t/**\n\t * The name of an {@link Environment} property used to indicate that a correlation ID\n\t * is expected to be logged at some point.\n\t * @since 3.2.0\n\t */\n\tpublic static final String EXPECT_CORRELATION_ID_PROPERTY = \"logging.expect-correlation-id\";\n\n\t/**\n\t * Return the {@link LoggingSystemProperties} that should be applied.\n\t * @param environment the {@link ConfigurableEnvironment} used to obtain value\n\t * @return the {@link LoggingSystemProperties} to apply\n\t * @since 2.4.0\n\t */\n\tpublic LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) {\n\t\treturn new LoggingSystemProperties(environment);\n\t}\n\n\t/**\n\t * Reset the logging system to be limit output. This method may be called before\n\t * {@link #initialize(LoggingInitializationContext, String, LogFile)} to reduce\n\t * logging noise until the system has been fully initialized.\n\t */\n\tpublic abstract void beforeInitialize();\n\n\t/**\n\t * Fully initialize the logging system.\n\t * @param initializationContext the logging initialization context\n\t * @param configLocation a log configuration location or {@code null} if default\n\t * initialization is required\n\t * @param logFile the log output file that should be written or {@code null} for\n\t * console only output\n\t */\n\tpublic void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation,\n\t\t\t@Nullable LogFile logFile) {\n\t}\n\n\t/**\n\t * Clean up the logging system. The default implementation does nothing. Subclasses\n\t * should override this method to perform any logging system-specific cleanup.\n\t */\n\tpublic void cleanUp() {\n\t}\n\n\t/**\n\t * Returns a {@link Runnable} that can handle shutdown of this logging system when the\n\t * JVM exits. The default implementation returns {@code null}, indicating that no\n\t * shutdown is required.\n\t * @return the shutdown handler, or {@code null}\n\t */\n\tpublic @Nullable Runnable getShutdownHandler() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns a set of the {@link LogLevel LogLevels} that are actually supported by the\n\t * logging system.\n\t * @return the supported levels\n\t */\n\tpublic Set<LogLevel> getSupportedLogLevels() {\n\t\treturn EnumSet.allOf(LogLevel.class);\n\t}\n\n\t/**\n\t * Sets the logging level for a given logger.\n\t * @param loggerName the name of the logger to set ({@code null} can be used for the\n\t * root logger).\n\t * @param level the log level ({@code null} can be used to remove any custom level for\n\t * the logger and use the default configuration instead)\n\t */\n\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\tthrow new UnsupportedOperationException(\"Unable to set log level\");\n\t}\n\n\t/**\n\t * Returns a collection of the current configuration for all a {@link LoggingSystem}'s\n\t * loggers.\n\t * @return the current configurations\n\t * @since 1.5.0\n\t */\n\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\tthrow new UnsupportedOperationException(\"Unable to get logger configurations\");\n\t}\n\n\t/**\n\t * Returns the current configuration for a {@link LoggingSystem}'s logger.\n\t * @param loggerName the name of the logger\n\t * @return the current configuration\n\t * @since 1.5.0\n\t */\n\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\tthrow new UnsupportedOperationException(\"Unable to get logger configuration\");\n\t}\n\n\t/**\n\t * Detect and return the logging system in use. Supports Logback and Java Logging.\n\t * @param classLoader the classloader\n\t * @return the logging system\n\t */\n\tpublic static LoggingSystem get(ClassLoader classLoader) {\n\t\tString loggingSystemClassName = System.getProperty(SYSTEM_PROPERTY);\n\t\tif (StringUtils.hasLength(loggingSystemClassName)) {\n\t\t\tif (NONE.equals(loggingSystemClassName)) {\n\t\t\t\treturn new NoOpLoggingSystem();\n\t\t\t}\n\t\t\treturn get(classLoader, loggingSystemClassName);\n\t\t}\n\t\tLoggingSystem loggingSystem = SYSTEM_FACTORY.getLoggingSystem(classLoader);\n\t\tAssert.state(loggingSystem != null, \"No suitable logging system located\");\n\t\treturn loggingSystem;\n\t}\n\n\tprivate static LoggingSystem get(ClassLoader classLoader, String loggingSystemClassName) {\n\t\ttry {\n\t\t\tClass<?> systemClass = ClassUtils.forName(loggingSystemClassName, classLoader);\n\t\t\tConstructor<?> constructor = systemClass.getDeclaredConstructor(ClassLoader.class);\n\t\t\tconstructor.setAccessible(true);\n\t\t\treturn (LoggingSystem) constructor.newInstance(classLoader);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * {@link LoggingSystem} that does nothing.\n\t */\n\tstatic class NoOpLoggingSystem extends LoggingSystem {\n\n\t\t@Override\n\t\tpublic void beforeInitialize() {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * Factory class used by {@link LoggingSystem#get(ClassLoader)} to find an actual\n * implementation.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic interface LoggingSystemFactory {\n\n\t/**\n\t * Return a logging system implementation or {@code null} if no logging system is\n\t * available.\n\t * @param classLoader the class loader to use\n\t * @return a logging system\n\t */\n\t@Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader);\n\n\t/**\n\t * Return a {@link LoggingSystemFactory} backed by {@code spring.factories}.\n\t * @return a {@link LoggingSystemFactory} instance\n\t */\n\tstatic LoggingSystemFactory fromSpringFactories() {\n\t\treturn new DelegatingLoggingSystemFactory(\n\t\t\t\t(classLoader) -> SpringFactoriesLoader.loadFactories(LoggingSystemFactory.class, classLoader));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.Console;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.system.ApplicationPid;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility to set system properties that can later be used by log configuration files.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Vedran Pavic\n * @author Robert Thornton\n * @author Eddú Meléndez\n * @author Jonatan Ivanov\n * @since 2.0.0\n * @see LoggingSystemProperty\n */\npublic class LoggingSystemProperties {\n\n\tprivate static final BiConsumer<String, @Nullable String> systemPropertySetter = (name, value) -> {\n\t\tif (System.getProperty(name) == null && value != null) {\n\t\t\tSystem.setProperty(name, value);\n\t\t}\n\t};\n\n\tprivate final Environment environment;\n\n\tprivate final Function<@Nullable String, @Nullable String> defaultValueResolver;\n\n\tprivate final BiConsumer<String, @Nullable String> setter;\n\n\t/**\n\t * Create a new {@link LoggingSystemProperties} instance.\n\t * @param environment the source environment\n\t */\n\tpublic LoggingSystemProperties(Environment environment) {\n\t\tthis(environment, null);\n\t}\n\n\t/**\n\t * Create a new {@link LoggingSystemProperties} instance.\n\t * @param environment the source environment\n\t * @param setter setter used to apply the property or {@code null} for system\n\t * properties\n\t * @since 2.4.2\n\t */\n\tpublic LoggingSystemProperties(Environment environment, @Nullable BiConsumer<String, @Nullable String> setter) {\n\t\tthis(environment, null, setter);\n\t}\n\n\t/**\n\t * Create a new {@link LoggingSystemProperties} instance.\n\t * @param environment the source environment\n\t * @param defaultValueResolver function used to resolve default values or {@code null}\n\t * @param setter setter used to apply the property or {@code null} for system\n\t * properties\n\t * @since 3.2.0\n\t */\n\tpublic LoggingSystemProperties(Environment environment,\n\t\t\t@Nullable Function<@Nullable String, @Nullable String> defaultValueResolver,\n\t\t\t@Nullable BiConsumer<String, @Nullable String> setter) {\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tthis.environment = environment;\n\t\tthis.defaultValueResolver = (defaultValueResolver != null) ? defaultValueResolver : (name) -> null;\n\t\tthis.setter = (setter != null) ? setter : systemPropertySetter;\n\t}\n\n\t/**\n\t * Returns the {@link Console} to use.\n\t * @return the {@link Console} to use\n\t * @since 3.5.0\n\t */\n\tprotected @Nullable Console getConsole() {\n\t\treturn System.console();\n\t}\n\n\tpublic final void apply() {\n\t\tapply(null);\n\t}\n\n\tpublic final void apply(@Nullable LogFile logFile) {\n\t\tPropertyResolver resolver = getPropertyResolver();\n\t\tapply(logFile, resolver);\n\t}\n\n\tprivate PropertyResolver getPropertyResolver() {\n\t\tif (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\tPropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(\n\t\t\t\t\tconfigurableEnvironment.getPropertySources());\n\t\t\tresolver.setConversionService(configurableEnvironment.getConversionService());\n\t\t\tresolver.setIgnoreUnresolvableNestedPlaceholders(true);\n\t\t\treturn resolver;\n\t\t}\n\t\treturn this.environment;\n\t}\n\n\tprotected void apply(@Nullable LogFile logFile, PropertyResolver resolver) {\n\t\tsetSystemProperty(LoggingSystemProperty.APPLICATION_NAME, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.APPLICATION_GROUP, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.PID, new ApplicationPid().toString());\n\t\tsetSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET, resolver, getDefaultConsoleCharset().name());\n\t\tsetSystemProperty(LoggingSystemProperty.FILE_CHARSET, resolver, getDefaultFileCharset().name());\n\t\tsetSystemProperty(LoggingSystemProperty.CONSOLE_THRESHOLD, resolver, this::thresholdMapper);\n\t\tsetSystemProperty(LoggingSystemProperty.FILE_THRESHOLD, resolver, this::thresholdMapper);\n\t\tsetSystemProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.FILE_PATTERN, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.CONSOLE_STRUCTURED_FORMAT, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.FILE_STRUCTURED_FORMAT, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.LEVEL_PATTERN, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.DATEFORMAT_PATTERN, resolver);\n\t\tsetSystemProperty(LoggingSystemProperty.CORRELATION_PATTERN, resolver);\n\t\tif (logFile != null) {\n\t\t\tlogFile.applyToSystemProperties();\n\t\t}\n\t\tif (!this.environment.getProperty(\"logging.console.enabled\", Boolean.class, true)) {\n\t\t\tsetSystemProperty(LoggingSystemProperty.CONSOLE_THRESHOLD.getEnvironmentVariableName(), \"OFF\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the default console charset.\n\t * @return the default console charset\n\t * @since 3.5.0\n\t */\n\tprotected Charset getDefaultConsoleCharset() {\n\t\tConsole console = getConsole();\n\t\treturn (console != null) ? console.charset() : Charset.defaultCharset();\n\t}\n\n\t/**\n\t * Returns the default file charset.\n\t * @return the default file charset\n\t * @since 3.5.0\n\t */\n\tprotected Charset getDefaultFileCharset() {\n\t\treturn StandardCharsets.UTF_8;\n\t}\n\n\tprivate void setSystemProperty(LoggingSystemProperty property, PropertyResolver resolver) {\n\t\tsetSystemProperty(property, resolver, (i) -> i);\n\t}\n\n\tprivate void setSystemProperty(LoggingSystemProperty property, PropertyResolver resolver,\n\t\t\tFunction<@Nullable String, @Nullable String> mapper) {\n\t\tsetSystemProperty(property, resolver, null, mapper);\n\t}\n\n\tprivate void setSystemProperty(LoggingSystemProperty property, PropertyResolver resolver, String defaultValue) {\n\t\tsetSystemProperty(property, resolver, defaultValue, (i) -> i);\n\t}\n\n\tprivate void setSystemProperty(LoggingSystemProperty property, PropertyResolver resolver,\n\t\t\t@Nullable String defaultValue, Function<@Nullable String, @Nullable String> mapper) {\n\t\tif (property.getIncludePropertyName() != null) {\n\t\t\tif (!resolver.getProperty(property.getIncludePropertyName(), Boolean.class, Boolean.TRUE)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tString applicationPropertyName = property.getApplicationPropertyName();\n\t\tString value = (applicationPropertyName != null) ? resolver.getProperty(applicationPropertyName) : null;\n\t\tvalue = (value != null) ? value : this.defaultValueResolver.apply(applicationPropertyName);\n\t\tvalue = (value != null) ? value : defaultValue;\n\t\tvalue = mapper.apply(value);\n\t\tsetSystemProperty(property.getEnvironmentVariableName(), value);\n\t\tif (property == LoggingSystemProperty.APPLICATION_NAME && StringUtils.hasText(value)) {\n\t\t\t// LOGGED_APPLICATION_NAME is deprecated for removal in 4.0.0\n\t\t\tsetSystemProperty(\"LOGGED_APPLICATION_NAME\", \"[%s] \".formatted(value));\n\t\t}\n\t}\n\n\tprivate void setSystemProperty(LoggingSystemProperty property, String value) {\n\t\tsetSystemProperty(property.getEnvironmentVariableName(), value);\n\t}\n\n\tprivate @Nullable String thresholdMapper(@Nullable String input) {\n\t\t// YAML converts an unquoted OFF to false\n\t\tif (\"false\".equals(input)) {\n\t\t\treturn \"OFF\";\n\t\t}\n\t\treturn input;\n\t}\n\n\t/**\n\t * Set a system property.\n\t * @param name the property name\n\t * @param value the value\n\t */\n\tprotected final void setSystemProperty(String name, @Nullable String value) {\n\t\tthis.setter.accept(name, value);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/LoggingSystemProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Logging system properties that can later be used by log configuration files.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see LoggingSystemProperties\n */\npublic enum LoggingSystemProperty {\n\n\t/**\n\t * Logging system property for the application name that should be logged.\n\t */\n\tAPPLICATION_NAME(\"APPLICATION_NAME\", \"spring.application.name\", \"logging.include-application-name\"),\n\n\t/**\n\t * Logging system property for the application group that should be logged.\n\t * @since 3.4.0\n\t */\n\tAPPLICATION_GROUP(\"APPLICATION_GROUP\", \"spring.application.group\", \"logging.include-application-group\"),\n\n\t/**\n\t * Logging system property for the process ID.\n\t */\n\tPID(\"PID\"),\n\n\t/**\n\t * Logging system property for the log file.\n\t */\n\tLOG_FILE(\"LOG_FILE\"),\n\n\t/**\n\t * Logging system property for the log path.\n\t */\n\tLOG_PATH(\"LOG_PATH\"),\n\n\t/**\n\t * Logging system property for the console log charset.\n\t */\n\tCONSOLE_CHARSET(\"CONSOLE_LOG_CHARSET\", \"logging.charset.console\"),\n\n\t/**\n\t * Logging system property for the file log charset.\n\t */\n\tFILE_CHARSET(\"FILE_LOG_CHARSET\", \"logging.charset.file\"),\n\n\t/**\n\t * Logging system property for the console log.\n\t */\n\tCONSOLE_THRESHOLD(\"CONSOLE_LOG_THRESHOLD\", \"logging.threshold.console\"),\n\n\t/**\n\t * Logging system property for the file log.\n\t */\n\tFILE_THRESHOLD(\"FILE_LOG_THRESHOLD\", \"logging.threshold.file\"),\n\n\t/**\n\t * Logging system property for the exception conversion word.\n\t */\n\tEXCEPTION_CONVERSION_WORD(\"LOG_EXCEPTION_CONVERSION_WORD\", \"logging.exception-conversion-word\"),\n\n\t/**\n\t * Logging system property for the console log pattern.\n\t */\n\tCONSOLE_PATTERN(\"CONSOLE_LOG_PATTERN\", \"logging.pattern.console\"),\n\n\t/**\n\t * Logging system property for the file log pattern.\n\t */\n\tFILE_PATTERN(\"FILE_LOG_PATTERN\", \"logging.pattern.file\"),\n\n\t/**\n\t * Logging system property for the console structured logging format.\n\t * @since 3.4.0\n\t */\n\tCONSOLE_STRUCTURED_FORMAT(\"CONSOLE_LOG_STRUCTURED_FORMAT\", \"logging.structured.format.console\"),\n\n\t/**\n\t * Logging system property for the file structured logging format.\n\t * @since 3.4.0\n\t */\n\tFILE_STRUCTURED_FORMAT(\"FILE_LOG_STRUCTURED_FORMAT\", \"logging.structured.format.file\"),\n\n\t/**\n\t * Logging system property for the log level pattern.\n\t */\n\tLEVEL_PATTERN(\"LOG_LEVEL_PATTERN\", \"logging.pattern.level\"),\n\n\t/**\n\t * Logging system property for the date-format pattern.\n\t */\n\tDATEFORMAT_PATTERN(\"LOG_DATEFORMAT_PATTERN\", \"logging.pattern.dateformat\"),\n\n\t/**\n\t * Logging system property for the correlation pattern.\n\t */\n\tCORRELATION_PATTERN(\"LOG_CORRELATION_PATTERN\", \"logging.pattern.correlation\");\n\n\tprivate final String environmentVariableName;\n\n\tprivate final @Nullable String applicationPropertyName;\n\n\tprivate final @Nullable String includePropertyName;\n\n\tLoggingSystemProperty(String environmentVariableName) {\n\t\tthis(environmentVariableName, null);\n\t}\n\n\tLoggingSystemProperty(String environmentVariableName, @Nullable String applicationPropertyName) {\n\t\tthis(environmentVariableName, applicationPropertyName, null);\n\t}\n\n\tLoggingSystemProperty(String environmentVariableName, @Nullable String applicationPropertyName,\n\t\t\t@Nullable String includePropertyName) {\n\t\tthis.environmentVariableName = environmentVariableName;\n\t\tthis.applicationPropertyName = applicationPropertyName;\n\t\tthis.includePropertyName = includePropertyName;\n\t}\n\n\t/**\n\t * Return the name of environment variable that can be used to access this property.\n\t * @return the environment variable name\n\t */\n\tpublic String getEnvironmentVariableName() {\n\t\treturn this.environmentVariableName;\n\t}\n\n\t/**\n\t * Return the application property name that can be used to set this property.\n\t * @return the application property name\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable String getApplicationPropertyName() {\n\t\treturn this.applicationPropertyName;\n\t}\n\n\t@Nullable String getIncludePropertyName() {\n\t\treturn this.includePropertyName;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/StackTracePrinter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\n\n/**\n * Interface that can be used to print the stack trace of a {@link Throwable}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n * @see StandardStackTracePrinter\n */\n@FunctionalInterface\npublic interface StackTracePrinter {\n\n\t/**\n\t * Return a {@link String} containing the printed stack trace for a given\n\t * {@link Throwable}.\n\t * @param throwable the throwable that should have its stack trace printed\n\t * @return the stack trace string\n\t */\n\tdefault String printStackTraceToString(Throwable throwable) {\n\t\ttry {\n\t\t\tStringBuilder out = new StringBuilder(4096);\n\t\t\tprintStackTrace(throwable, out);\n\t\t\treturn out.toString();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Prints a stack trace for the given {@link Throwable}.\n\t * @param throwable the throwable that should have its stack trace printed\n\t * @param out the destination to write output\n\t * @throws IOException on IO error\n\t */\n\tvoid printStackTrace(Throwable throwable, Appendable out) throws IOException;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/StandardStackTracePrinter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.IdentityHashMap;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.BiPredicate;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.function.ToIntFunction;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link StackTracePrinter} that prints a standard form stack trace. This printer\n * produces a result in a similar form to {@link Throwable#printStackTrace()}, but offers\n * more customization options.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic final class StandardStackTracePrinter implements StackTracePrinter {\n\n\tprivate static final String DEFAULT_LINE_SEPARATOR = System.lineSeparator();\n\n\tprivate static final ToIntFunction<StackTraceElement> DEFAULT_FRAME_HASHER = (frame) -> Objects\n\t\t.hash(frame.getClassName(), frame.getMethodName(), frame.getLineNumber());\n\n\tprivate static final int UNLIMITED = Integer.MAX_VALUE;\n\n\tprivate final EnumSet<Option> options;\n\n\tprivate final int maximumLength;\n\n\tprivate final String lineSeparator;\n\n\tprivate final Predicate<Throwable> filter;\n\n\tprivate final BiPredicate<Integer, StackTraceElement> frameFilter;\n\n\tprivate final Function<Throwable, String> formatter;\n\n\tprivate final Function<StackTraceElement, String> frameFormatter;\n\n\tprivate final @Nullable ToIntFunction<StackTraceElement> frameHasher;\n\n\tprivate StandardStackTracePrinter(EnumSet<Option> options, int maximumLength, @Nullable String lineSeparator,\n\t\t\t@Nullable Predicate<Throwable> filter, @Nullable BiPredicate<Integer, StackTraceElement> frameFilter,\n\t\t\t@Nullable Function<Throwable, String> formatter,\n\t\t\t@Nullable Function<StackTraceElement, String> frameFormatter,\n\t\t\t@Nullable ToIntFunction<StackTraceElement> frameHasher) {\n\t\tthis.options = options;\n\t\tthis.maximumLength = maximumLength;\n\t\tthis.lineSeparator = (lineSeparator != null) ? lineSeparator : DEFAULT_LINE_SEPARATOR;\n\t\tthis.filter = (filter != null) ? filter : (t) -> true;\n\t\tthis.frameFilter = (frameFilter != null) ? frameFilter : (i, t) -> true;\n\t\tthis.formatter = (formatter != null) ? formatter : Object::toString;\n\t\tthis.frameFormatter = (frameFormatter != null) ? frameFormatter : Object::toString;\n\t\tthis.frameHasher = frameHasher;\n\t}\n\n\t@Override\n\tpublic void printStackTrace(Throwable throwable, Appendable out) throws IOException {\n\t\tif (this.filter.test(throwable)) {\n\t\t\tSet<Throwable> seen = Collections.newSetFromMap(new IdentityHashMap<>());\n\t\t\tOutput output = new Output(out);\n\t\t\tPrint print = new Print(\"\", \"\", output);\n\t\t\tprintFullStackTrace(seen, print, new StackTrace(throwable), null);\n\t\t}\n\t}\n\n\tprivate void printFullStackTrace(Set<Throwable> seen, Print print, @Nullable StackTrace stackTrace,\n\t\t\t@Nullable StackTrace enclosing) throws IOException {\n\t\tif (stackTrace == null) {\n\t\t\treturn;\n\t\t}\n\t\tif (!seen.add(stackTrace.throwable())) {\n\t\t\tString hashPrefix = stackTrace.hashPrefix(this.frameHasher);\n\t\t\tString throwable = this.formatter.apply(stackTrace.throwable());\n\t\t\tprint.circularReference(hashPrefix, throwable);\n\t\t\treturn;\n\t\t}\n\t\tStackTrace cause = stackTrace.cause();\n\t\tif (!hasOption(Option.ROOT_FIRST)) {\n\t\t\tprintSingleStackTrace(seen, print, stackTrace, enclosing);\n\t\t\tprintFullStackTrace(seen, print.withCausedByCaption(cause), cause, stackTrace);\n\t\t}\n\t\telse {\n\t\t\tprintFullStackTrace(seen, print, cause, stackTrace);\n\t\t\tprintSingleStackTrace(seen, print.withWrappedByCaption(cause), stackTrace, enclosing);\n\t\t}\n\t}\n\n\tprivate void printSingleStackTrace(Set<Throwable> seen, Print print, StackTrace stackTrace,\n\t\t\t@Nullable StackTrace enclosing) throws IOException {\n\t\tString hashPrefix = stackTrace.hashPrefix(this.frameHasher);\n\t\tString throwable = this.formatter.apply(stackTrace.throwable());\n\t\tprint.thrown(hashPrefix, throwable);\n\t\tprintFrames(print, stackTrace, enclosing);\n\t\tif (!hasOption(Option.HIDE_SUPPRESSED)) {\n\t\t\tStackTrace[] suppressed = stackTrace.suppressed();\n\t\t\tif (suppressed != null) {\n\t\t\t\tfor (StackTrace suppressedStackTrace : suppressed) {\n\t\t\t\t\tprintFullStackTrace(seen, print.withSuppressedCaption(), suppressedStackTrace, stackTrace);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void printFrames(Print print, StackTrace stackTrace, @Nullable StackTrace enclosing) throws IOException {\n\t\tint commonFrames = (!hasOption(Option.SHOW_COMMON_FRAMES)) ? stackTrace.commonFramesCount(enclosing) : 0;\n\t\tint filteredFrames = 0;\n\t\tStackTraceElement[] frames = stackTrace.frames();\n\t\tif (frames != null) {\n\t\t\tfor (int i = 0; i < frames.length - commonFrames; i++) {\n\t\t\t\tStackTraceElement element = frames[i];\n\t\t\t\tif (!this.frameFilter.test(i, element)) {\n\t\t\t\t\tfilteredFrames++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tprint.omittedFilteredFrames(filteredFrames);\n\t\t\t\tfilteredFrames = 0;\n\t\t\t\tprint.at(this.frameFormatter.apply(element));\n\t\t\t}\n\t\t}\n\t\tprint.omittedFilteredFrames(filteredFrames);\n\t\tif (commonFrames != 0) {\n\t\t\tprint.omittedCommonFrames(commonFrames);\n\t\t}\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that will print all\n\t * common frames rather than replacing them with the {@literal \"... N more\"} message.\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withCommonFrames() {\n\t\treturn withOption(Option.SHOW_COMMON_FRAMES);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that will not print\n\t * {@link Throwable#getSuppressed() suppressed} items.\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withoutSuppressed() {\n\t\treturn withOption(Option.HIDE_SUPPRESSED);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that will use ellipses\n\t * to truncate output longer than the specified length.\n\t * @param maximumLength the maximum length that can be printed\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withMaximumLength(int maximumLength) {\n\t\tAssert.isTrue(maximumLength > 0, \"'maximumLength' must be positive\");\n\t\treturn new StandardStackTracePrinter(this.options, maximumLength, this.lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter, this.formatter, this.frameFormatter, this.frameHasher);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that filters frames\n\t * (including caused and suppressed) deeper than the specified maximum.\n\t * @param maximumThrowableDepth the maximum throwable depth\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withMaximumThrowableDepth(int maximumThrowableDepth) {\n\t\tAssert.isTrue(maximumThrowableDepth > 0, \"'maximumThrowableDepth' must be positive\");\n\t\treturn withFrameFilter((index, element) -> index < maximumThrowableDepth);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that will only include\n\t * throwables (excluding caused and suppressed) that match the given predicate.\n\t * @param predicate the predicate used to filter the throwable\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withFilter(Predicate<Throwable> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn new StandardStackTracePrinter(this.options, this.maximumLength, this.lineSeparator,\n\t\t\t\tthis.filter.and(predicate), this.frameFilter, this.formatter, this.frameFormatter, this.frameHasher);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that will only include\n\t * frames that match the given predicate.\n\t * @param predicate the predicate used to filter frames\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withFrameFilter(BiPredicate<Integer, StackTraceElement> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn new StandardStackTracePrinter(this.options, this.maximumLength, this.lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter.and(predicate), this.formatter, this.frameFormatter, this.frameHasher);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that prints the stack\n\t * trace using the specified line separator.\n\t * @param lineSeparator the line separator to use\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withLineSeparator(String lineSeparator) {\n\t\tAssert.notNull(lineSeparator, \"'lineSeparator' must not be null\");\n\t\treturn new StandardStackTracePrinter(this.options, this.maximumLength, lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter, this.formatter, this.frameFormatter, this.frameHasher);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that uses the\n\t * specified formatter to create a string representation of a throwable.\n\t * @param formatter the formatter to use\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t * @see #withLineSeparator(String)\n\t */\n\tpublic StandardStackTracePrinter withFormatter(Function<Throwable, String> formatter) {\n\t\tAssert.notNull(formatter, \"'formatter' must not be null\");\n\t\treturn new StandardStackTracePrinter(this.options, this.maximumLength, this.lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter, formatter, this.frameFormatter, this.frameHasher);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that uses the\n\t * specified formatter to create a string representation of a frame.\n\t * @param frameFormatter the frame formatter to use\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t * @see #withLineSeparator(String)\n\t */\n\tpublic StandardStackTracePrinter withFrameFormatter(Function<StackTraceElement, String> frameFormatter) {\n\t\tAssert.notNull(frameFormatter, \"'frameFormatter' must not be null\");\n\t\treturn new StandardStackTracePrinter(this.options, this.maximumLength, this.lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter, this.formatter, frameFormatter, this.frameHasher);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that generates and\n\t * prints hashes for each stacktrace.\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withHashes() {\n\t\treturn withHashes(true);\n\t}\n\n\t/**\n\t * Return a new {@link StandardStackTracePrinter} from this one that changes if hashes\n\t * should be generated and printed for each stacktrace.\n\t * @param hashes if hashes should be added\n\t * @return a new {@link StandardStackTracePrinter} instance\n\t */\n\tpublic StandardStackTracePrinter withHashes(boolean hashes) {\n\t\treturn withHashes((!hashes) ? null : DEFAULT_FRAME_HASHER);\n\t}\n\n\tpublic StandardStackTracePrinter withHashes(@Nullable ToIntFunction<StackTraceElement> frameHasher) {\n\t\treturn new StandardStackTracePrinter(this.options, this.maximumLength, this.lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter, this.formatter, this.frameFormatter, frameHasher);\n\t}\n\n\tprivate StandardStackTracePrinter withOption(Option option) {\n\t\tEnumSet<Option> options = EnumSet.copyOf(this.options);\n\t\toptions.add(option);\n\t\treturn new StandardStackTracePrinter(options, this.maximumLength, this.lineSeparator, this.filter,\n\t\t\t\tthis.frameFilter, this.formatter, this.frameFormatter, this.frameHasher);\n\t}\n\n\tprivate boolean hasOption(Option option) {\n\t\treturn this.options.contains(option);\n\t}\n\n\t/**\n\t * Return a {@link StandardStackTracePrinter} that prints the stack trace with the\n\t * root exception last (the same as {@link Throwable#printStackTrace()}).\n\t * @return a {@link StandardStackTracePrinter} that prints the stack trace root last\n\t */\n\tpublic static StandardStackTracePrinter rootLast() {\n\t\treturn new StandardStackTracePrinter(EnumSet.noneOf(Option.class), UNLIMITED, null, null, null, null, null,\n\t\t\t\tnull);\n\t}\n\n\t/**\n\t * Return a {@link StandardStackTracePrinter} that prints the stack trace with the\n\t * root exception first (the opposite of {@link Throwable#printStackTrace()}).\n\t * @return a {@link StandardStackTracePrinter} that prints the stack trace root first\n\t */\n\tpublic static StandardStackTracePrinter rootFirst() {\n\t\treturn new StandardStackTracePrinter(EnumSet.of(Option.ROOT_FIRST), UNLIMITED, null, null, null, null, null,\n\t\t\t\tnull);\n\t}\n\n\t/**\n\t * Options supported by this printer.\n\t */\n\tprivate enum Option {\n\n\t\tROOT_FIRST, SHOW_COMMON_FRAMES, HIDE_SUPPRESSED\n\n\t}\n\n\t/**\n\t * Prints the actual line output.\n\t */\n\tprivate record Print(String indent, String caption, Output output) {\n\n\t\tvoid circularReference(String hashPrefix, String throwable) throws IOException {\n\t\t\tthis.output.println(this.indent, this.caption + \"[CIRCULAR REFERENCE: \" + hashPrefix + throwable + \"]\");\n\t\t}\n\n\t\tvoid thrown(String hashPrefix, String throwable) throws IOException {\n\t\t\tthis.output.println(this.indent, this.caption + hashPrefix + throwable);\n\t\t}\n\n\t\tvoid at(String frame) throws IOException {\n\t\t\tthis.output.println(this.indent, \"\\tat \" + frame);\n\t\t}\n\n\t\tvoid omittedFilteredFrames(int filteredFrameCount) throws IOException {\n\t\t\tif (filteredFrameCount > 0) {\n\t\t\t\tthis.output.println(this.indent, \"\\t... \" + filteredFrameCount + \" filtered\");\n\t\t\t}\n\t\t}\n\n\t\tvoid omittedCommonFrames(int commonFrameCount) throws IOException {\n\t\t\tthis.output.println(this.indent, \"\\t... \" + commonFrameCount + \" more\");\n\t\t}\n\n\t\tPrint withCausedByCaption(@Nullable StackTrace causedBy) {\n\t\t\treturn withCaption(causedBy != null, \"\", \"Caused by: \");\n\t\t}\n\n\t\tPrint withWrappedByCaption(@Nullable StackTrace wrappedBy) {\n\t\t\treturn withCaption(wrappedBy != null, \"\", \"Wrapped by: \");\n\t\t}\n\n\t\tpublic Print withSuppressedCaption() {\n\t\t\treturn withCaption(true, \"\\t\", \"Suppressed: \");\n\t\t}\n\n\t\tprivate Print withCaption(boolean test, String extraIndent, String caption) {\n\t\t\treturn (test) ? new Print(this.indent + extraIndent, caption, this.output) : this;\n\t\t}\n\n\t}\n\n\t/**\n\t * Line-by-line output.\n\t */\n\tprivate class Output {\n\n\t\tprivate static final String ELLIPSIS = \"...\";\n\n\t\tprivate final Appendable out;\n\n\t\tprivate int remaining;\n\n\t\tOutput(Appendable out) {\n\t\t\tthis.out = out;\n\t\t\tthis.remaining = StandardStackTracePrinter.this.maximumLength - ELLIPSIS.length();\n\t\t}\n\n\t\tvoid println(String indent, String string) throws IOException {\n\t\t\tif (this.remaining > 0) {\n\t\t\t\tString line = indent + string + StandardStackTracePrinter.this.lineSeparator;\n\t\t\t\tif (line.length() > this.remaining) {\n\t\t\t\t\tline = line.substring(0, this.remaining) + ELLIPSIS;\n\t\t\t\t}\n\t\t\t\tthis.out.append(line);\n\t\t\t\tthis.remaining -= line.length();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Holds the stacktrace for a specific throwable and caches things that are expensive\n\t * to calculate.\n\t */\n\tprivate static final class StackTrace {\n\n\t\tprivate final Throwable throwable;\n\n\t\tprivate final StackTraceElement @Nullable [] frames;\n\n\t\tprivate StackTrace @Nullable [] suppressed;\n\n\t\tprivate @Nullable StackTrace cause;\n\n\t\tprivate @Nullable Integer hash;\n\n\t\tprivate @Nullable String hashPrefix;\n\n\t\tprivate StackTrace(Throwable throwable) {\n\t\t\tthis.throwable = throwable;\n\t\t\tthis.frames = (throwable != null) ? throwable.getStackTrace() : null;\n\t\t}\n\n\t\tThrowable throwable() {\n\t\t\treturn this.throwable;\n\t\t}\n\n\t\tStackTraceElement @Nullable [] frames() {\n\t\t\treturn this.frames;\n\t\t}\n\n\t\tint commonFramesCount(@Nullable StackTrace other) {\n\t\t\tif (other == null || this.frames == null || other.frames == null) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tint index = this.frames.length - 1;\n\t\t\tint otherIndex = other.frames.length - 1;\n\t\t\twhile (index >= 0 && otherIndex >= 0 && this.frames[index].equals(other.frames[otherIndex])) {\n\t\t\t\tindex--;\n\t\t\t\totherIndex--;\n\t\t\t}\n\t\t\treturn this.frames.length - 1 - index;\n\t\t}\n\n\t\tStackTrace @Nullable [] suppressed() {\n\t\t\tif (this.suppressed == null && this.throwable != null) {\n\t\t\t\tthis.suppressed = Arrays.stream(this.throwable.getSuppressed())\n\t\t\t\t\t.map(StackTrace::new)\n\t\t\t\t\t.toArray(StackTrace[]::new);\n\t\t\t}\n\t\t\treturn this.suppressed;\n\t\t}\n\n\t\t@Nullable StackTrace cause() {\n\t\t\tif (this.cause == null && this.throwable != null) {\n\t\t\t\tThrowable cause = this.throwable.getCause();\n\t\t\t\tthis.cause = (cause != null) ? new StackTrace(cause) : null;\n\t\t\t}\n\t\t\treturn this.cause;\n\t\t}\n\n\t\tString hashPrefix(@Nullable ToIntFunction<StackTraceElement> frameHasher) {\n\t\t\tif (frameHasher == null || throwable() == null) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tthis.hashPrefix = (this.hashPrefix != null) ? this.hashPrefix\n\t\t\t\t\t: String.format(\"<#%08x> \", hash(new HashSet<>(), frameHasher));\n\t\t\treturn this.hashPrefix;\n\t\t}\n\n\t\tprivate int hash(HashSet<Throwable> seen, ToIntFunction<StackTraceElement> frameHasher) {\n\t\t\tif (this.hash != null) {\n\t\t\t\treturn this.hash;\n\t\t\t}\n\t\t\tint hash = 0;\n\t\t\tStackTrace cause = cause();\n\t\t\tif (cause != null && seen.add(cause.throwable())) {\n\t\t\t\thash = cause.hash(seen, frameHasher);\n\t\t\t}\n\t\t\thash = 31 * hash + throwable().getClass().getName().hashCode();\n\t\t\tif (frames() != null) {\n\t\t\t\tfor (StackTraceElement frame : frames()) {\n\t\t\t\t\thash = 31 * hash + frameHasher.applyAsInt(frame);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.hash = hash;\n\t\t\treturn hash;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.java;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.logging.Level;\nimport java.util.logging.LogManager;\nimport java.util.logging.Logger;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.logging.AbstractLoggingSystem;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link LoggingSystem} for {@link Logger java.util.logging}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Ben Hale\n * @since 1.0.0\n */\npublic class JavaLoggingSystem extends AbstractLoggingSystem {\n\n\tprivate static final LogLevels<Level> LEVELS = new LogLevels<>();\n\n\tstatic {\n\t\tLEVELS.map(LogLevel.TRACE, Level.FINEST);\n\t\tLEVELS.map(LogLevel.DEBUG, Level.FINE);\n\t\tLEVELS.map(LogLevel.INFO, Level.INFO);\n\t\tLEVELS.map(LogLevel.WARN, Level.WARNING);\n\t\tLEVELS.map(LogLevel.ERROR, Level.SEVERE);\n\t\tLEVELS.map(LogLevel.FATAL, Level.SEVERE);\n\t\tLEVELS.map(LogLevel.OFF, Level.OFF);\n\t}\n\n\tprivate final Set<Logger> configuredLoggers = Collections.synchronizedSet(new HashSet<>());\n\n\tpublic JavaLoggingSystem(ClassLoader classLoader) {\n\t\tsuper(classLoader);\n\t}\n\n\t@Override\n\tprotected String[] getStandardConfigLocations() {\n\t\treturn new String[] { \"logging.properties\" };\n\t}\n\n\t@Override\n\tpublic void beforeInitialize() {\n\t\tsuper.beforeInitialize();\n\t\tLogger.getLogger(\"\").setLevel(Level.SEVERE);\n\t}\n\n\t@Override\n\tprotected void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile) {\n\t\tif (logFile != null) {\n\t\t\tloadConfiguration(getPackagedConfigFile(\"logging-file.properties\"), logFile);\n\t\t}\n\t\telse {\n\t\t\tloadConfiguration(getPackagedConfigFile(\"logging.properties\"), null);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void loadConfiguration(LoggingInitializationContext initializationContext, String location,\n\t\t\t@Nullable LogFile logFile) {\n\t\tloadConfiguration(location, logFile);\n\t}\n\n\tprotected void loadConfiguration(String location, @Nullable LogFile logFile) {\n\t\tAssert.notNull(location, \"'location' must not be null\");\n\t\ttry {\n\t\t\tResource resource = ApplicationResourceLoader.get().getResource(location);\n\t\t\tString configuration = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream()));\n\t\t\tif (logFile != null) {\n\t\t\t\tconfiguration = configuration.replace(\"${LOG_FILE}\", StringUtils.cleanPath(logFile.toString()));\n\t\t\t}\n\t\t\tLogManager.getLogManager().readConfiguration(new ByteArrayInputStream(configuration.getBytes()));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not initialize Java logging from \" + location, ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Set<LogLevel> getSupportedLogLevels() {\n\t\treturn LEVELS.getSupported();\n\t}\n\n\t@Override\n\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\tif (loggerName == null || ROOT_LOGGER_NAME.equals(loggerName)) {\n\t\t\tloggerName = \"\";\n\t\t}\n\t\tLogger logger = Logger.getLogger(loggerName);\n\t\tif (logger != null) {\n\t\t\tthis.configuredLoggers.add(logger);\n\t\t\tlogger.setLevel(LEVELS.convertSystemToNative(level));\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\tList<LoggerConfiguration> result = new ArrayList<>();\n\t\tEnumeration<String> names = LogManager.getLogManager().getLoggerNames();\n\t\twhile (names.hasMoreElements()) {\n\t\t\tresult.add(getLoggerConfiguration(names.nextElement()));\n\t\t}\n\t\tresult.sort(CONFIGURATION_COMPARATOR);\n\t\treturn Collections.unmodifiableList(result);\n\t}\n\n\t@Override\n\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\tLogger logger = Logger.getLogger(loggerName);\n\t\tif (logger == null) {\n\t\t\treturn null;\n\t\t}\n\t\tLogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());\n\t\tLogLevel effectiveLevel = LEVELS.convertNativeToSystem(getEffectiveLevel(logger));\n\t\tString name = (StringUtils.hasLength(logger.getName()) ? logger.getName() : ROOT_LOGGER_NAME);\n\t\tAssert.state(effectiveLevel != null, \"effectiveLevel must not be null\");\n\t\treturn new LoggerConfiguration(name, level, effectiveLevel);\n\t}\n\n\tprivate Level getEffectiveLevel(Logger root) {\n\t\tLogger logger = root;\n\t\twhile (logger.getLevel() == null) {\n\t\t\tlogger = logger.getParent();\n\t\t}\n\t\treturn logger.getLevel();\n\t}\n\n\t@Override\n\tpublic Runnable getShutdownHandler() {\n\t\treturn () -> LogManager.getLogManager().reset();\n\t}\n\n\t@Override\n\tpublic void cleanUp() {\n\t\tthis.configuredLoggers.clear();\n\t}\n\n\t/**\n\t * {@link LoggingSystemFactory} that returns {@link JavaLoggingSystem} if possible.\n\t */\n\t@Order(Ordered.LOWEST_PRECEDENCE - 1024)\n\tpublic static class Factory implements LoggingSystemFactory {\n\n\t\tprivate static final boolean PRESENT = ClassUtils.isPresent(\"java.util.logging.LogManager\",\n\t\t\t\tFactory.class.getClassLoader());\n\n\t\t@Override\n\t\tpublic @Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader) {\n\t\t\tif (PRESENT) {\n\t\t\t\treturn new JavaLoggingSystem(classLoader);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/java/JavaLoggingSystemRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.java;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * {@link RuntimeHintsRegistrar} implementation for {@link JavaLoggingSystem}.\n *\n * @author Moritz Halbritter\n */\nclass JavaLoggingSystemRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\thints.resources().registerPattern(\"org/springframework/boot/logging/java/logging.properties\");\n\t\thints.resources().registerPattern(\"org/springframework/boot/logging/java/logging-file.properties\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/java/SimpleFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.java;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Date;\nimport java.util.logging.Formatter;\nimport java.util.logging.LogRecord;\n\nimport org.springframework.boot.logging.LoggingSystemProperty;\n\n/**\n * Simple 'Java Logging' {@link Formatter}.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class SimpleFormatter extends Formatter {\n\n\tprivate static final String DEFAULT_FORMAT = \"[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL] - %8$s %4$s [%7$s] --- %3$s: %5$s%6$s%n\";\n\n\tprivate final String format = getOrUseDefault(\"LOG_FORMAT\", DEFAULT_FORMAT);\n\n\tprivate final String pid = getOrUseDefault(LoggingSystemProperty.PID.getEnvironmentVariableName(), \"????\");\n\n\t@Override\n\tpublic String format(LogRecord record) {\n\t\tDate date = new Date(record.getMillis());\n\t\tString source = record.getLoggerName();\n\t\tString loggerName = record.getLoggerName();\n\t\tString level = record.getLevel().getLocalizedName();\n\t\tString message = formatMessage(record);\n\t\tString throwable = getThrowable(record);\n\t\tString thread = getThreadName();\n\t\tString pid = this.pid;\n\t\treturn String.format(this.format, date, source, loggerName, level, message, throwable, thread, pid);\n\t}\n\n\tprivate String getThrowable(LogRecord record) {\n\t\tif (record.getThrown() == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tStringWriter stringWriter = new StringWriter();\n\t\tPrintWriter printWriter = new PrintWriter(stringWriter);\n\t\tprintWriter.println();\n\t\trecord.getThrown().printStackTrace(printWriter);\n\t\tprintWriter.close();\n\t\treturn stringWriter.toString();\n\t}\n\n\tprivate String getThreadName() {\n\t\tString name = Thread.currentThread().getName();\n\t\treturn (name != null) ? name : \"\";\n\t}\n\n\tprivate static String getOrUseDefault(String key, String defaultValue) {\n\t\tString value = null;\n\t\ttry {\n\t\t\tvalue = System.getenv(key);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// ignore\n\t\t}\n\t\tif (value == null) {\n\t\t\tvalue = defaultValue;\n\t\t}\n\t\treturn System.getProperty(key, value);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/java/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for 'Java Util Logging'.\n */\n@NullMarked\npackage org.springframework.boot.logging.java;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ColorConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.layout.PatternLayout;\nimport org.apache.logging.log4j.core.pattern.ConverterKeys;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternFormatter;\nimport org.apache.logging.log4j.core.pattern.PatternParser;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ansi.AnsiBackground;\nimport org.springframework.boot.ansi.AnsiColor;\nimport org.springframework.boot.ansi.AnsiElement;\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiStyle;\n\n/**\n * Log4j2 {@link LogEventPatternConverter} to color output using the {@link AnsiOutput}\n * class. One or more styling options can be provided to the converter, or if not\n * specified color styling will be picked based on the logging level. Supported options\n * include foreground colors (e.g. {@code red}, {@code bright_blue}), background colors\n * (e.g. {@code bg_red}, {@code bg_bright_green}), and text styles (e.g. {@code bold},\n * {@code underline}, {@code reverse}).\n *\n * @author Vladimir Tsanev\n * @since 1.3.0\n */\n@Plugin(name = \"color\", category = PatternConverter.CATEGORY)\n@ConverterKeys({ \"clr\", \"color\" })\npublic final class ColorConverter extends LogEventPatternConverter {\n\n\tprivate static final Map<String, AnsiElement> ELEMENTS;\n\n\tstatic {\n\t\tMap<String, AnsiElement> ansiElements = new HashMap<>();\n\t\tArrays.stream(AnsiColor.values())\n\t\t\t.filter((color) -> color != AnsiColor.DEFAULT)\n\t\t\t.forEach((color) -> ansiElements.put(color.name().toLowerCase(Locale.ROOT), color));\n\t\tArrays.stream(AnsiStyle.values())\n\t\t\t.forEach((style) -> ansiElements.put(style.name().toLowerCase(Locale.ROOT), style));\n\t\tArrays.stream(AnsiBackground.values())\n\t\t\t.filter((bg) -> bg != AnsiBackground.DEFAULT)\n\t\t\t.forEach((bg) -> ansiElements.put(\"bg_\" + bg.name().toLowerCase(Locale.ROOT), bg));\n\t\tELEMENTS = Collections.unmodifiableMap(ansiElements);\n\t}\n\n\tprivate static final Map<Integer, AnsiElement> LEVELS;\n\n\tstatic {\n\t\tMap<Integer, AnsiElement> ansiLevels = new HashMap<>();\n\t\tansiLevels.put(Level.FATAL.intLevel(), AnsiColor.RED);\n\t\tansiLevels.put(Level.ERROR.intLevel(), AnsiColor.RED);\n\t\tansiLevels.put(Level.WARN.intLevel(), AnsiColor.YELLOW);\n\t\tLEVELS = Collections.unmodifiableMap(ansiLevels);\n\t}\n\n\tprivate final List<PatternFormatter> formatters;\n\n\tprivate final List<AnsiElement> stylings;\n\n\tprivate ColorConverter(List<PatternFormatter> formatters, List<AnsiElement> stylings) {\n\t\tsuper(\"style\", \"style\");\n\t\tthis.formatters = formatters;\n\t\tthis.stylings = stylings;\n\t}\n\n\t@Override\n\tpublic boolean handlesThrowable() {\n\t\tfor (PatternFormatter formatter : this.formatters) {\n\t\t\tif (formatter.handlesThrowable()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn super.handlesThrowable();\n\t}\n\n\t@Override\n\tpublic void format(LogEvent event, StringBuilder toAppendTo) {\n\t\tStringBuilder buf = new StringBuilder();\n\t\tfor (PatternFormatter formatter : this.formatters) {\n\t\t\tformatter.format(event, buf);\n\t\t}\n\t\tif (!buf.isEmpty()) {\n\t\t\tif (this.stylings.isEmpty()) {\n\t\t\t\t// Assume highlighting\n\t\t\t\tAnsiElement element = LEVELS.get(event.getLevel().intLevel());\n\t\t\t\telement = (element != null) ? element : AnsiColor.GREEN;\n\t\t\t\tappendAnsiString(toAppendTo, buf.toString(), element);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tappendAnsiString(toAppendTo, buf.toString(), this.stylings.toArray(new AnsiElement[0]));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void appendAnsiString(StringBuilder toAppendTo, String in, AnsiElement element) {\n\t\ttoAppendTo.append(AnsiOutput.toString(element, in));\n\t}\n\n\tprotected void appendAnsiString(StringBuilder toAppendTo, String in, AnsiElement... elements) {\n\t\tObject[] ansiParams = new Object[elements.length + 1];\n\t\tSystem.arraycopy(elements, 0, ansiParams, 0, elements.length);\n\t\tansiParams[elements.length] = in;\n\t\ttoAppendTo.append(AnsiOutput.toString(ansiParams));\n\t}\n\n\t/**\n\t * Creates a new instance of the class. Required by Log4J2.\n\t * @param config the configuration\n\t * @param options the options\n\t * @return a new instance, or {@code null} if the options are invalid\n\t */\n\tpublic static @Nullable ColorConverter newInstance(@Nullable Configuration config, @Nullable String[] options) {\n\t\tif (options.length < 1) {\n\t\t\tLOGGER.error(\"Incorrect number of options on style. Expected at least 1, received {}\", options.length);\n\t\t\treturn null;\n\t\t}\n\t\tif (options[0] == null) {\n\t\t\tLOGGER.error(\"No pattern supplied on style\");\n\t\t\treturn null;\n\t\t}\n\t\tPatternParser parser = PatternLayout.createPatternParser(config);\n\t\tList<PatternFormatter> formatters = parser.parse(options[0]);\n\t\tList<AnsiElement> stylings = new ArrayList<>();\n\t\tif (options.length >= 2 && options[1] != null) {\n\t\t\tString[] optionParts = options[1].split(\",\");\n\t\t\tfor (String optionPart : optionParts) {\n\t\t\t\tAnsiElement element = ELEMENTS.get(optionPart.trim().toLowerCase(Locale.ROOT));\n\t\t\t\tif (element != null) {\n\t\t\t\t\tstylings.add(element);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new ColorConverter(formatters, stylings);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/CorrelationIdConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.pattern.ConverterKeys;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.apache.logging.log4j.core.pattern.MdcPatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternConverter;\nimport org.apache.logging.log4j.util.PerformanceSensitive;\nimport org.apache.logging.log4j.util.ReadOnlyStringMap;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.CorrelationIdFormatter;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Log4j2 {@link LogEventPatternConverter} to convert a {@link CorrelationIdFormatter}\n * pattern into formatted output using data from the {@link LogEvent#getContextData()\n * MDC}.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see MdcPatternConverter\n */\n@Plugin(name = \"CorrelationIdConverter\", category = PatternConverter.CATEGORY)\n@ConverterKeys(\"correlationId\")\n@PerformanceSensitive(\"allocation\")\npublic final class CorrelationIdConverter extends LogEventPatternConverter {\n\n\tprivate final CorrelationIdFormatter formatter;\n\n\tprivate CorrelationIdConverter(CorrelationIdFormatter formatter) {\n\t\tsuper(\"correlationId{%s}\".formatted(formatter), \"mdc\");\n\t\tthis.formatter = formatter;\n\t}\n\n\t@Override\n\tpublic void format(LogEvent event, StringBuilder toAppendTo) {\n\t\tReadOnlyStringMap contextData = event.getContextData();\n\t\tthis.formatter.formatTo(contextData::getValue, toAppendTo);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link CorrelationIdConverter}.\n\t * @param options options, may be null or first element contains name of property to\n\t * format.\n\t * @return instance of PropertiesPatternConverter.\n\t */\n\tpublic static CorrelationIdConverter newInstance(String @Nullable [] options) {\n\t\tString pattern = (!ObjectUtils.isEmpty(options)) ? options[0] : null;\n\t\treturn new CorrelationIdConverter(CorrelationIdFormatter.of(pattern));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.Marker;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.time.Instant;\nimport org.apache.logging.log4j.util.ReadOnlyStringMap;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.ContextPairs.Pairs;\nimport org.springframework.boot.logging.structured.ElasticCommonSchemaProperties;\nimport org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Log4j2 {@link StructuredLogFormatter} for\n * {@link CommonStructuredLogFormat#ELASTIC_COMMON_SCHEMA}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {\n\n\tElasticCommonSchemaStructuredLogFormatter(Environment environment, @Nullable StackTracePrinter stackTracePrinter,\n\t\t\tContextPairs contextPairs, StructuredLoggingJsonMembersCustomizer.Builder<?> customizerBuilder) {\n\t\tsuper((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, members),\n\t\t\t\tcustomizerBuilder.nested().build());\n\t}\n\n\tprivate static void jsonMembers(Environment environment, @Nullable StackTracePrinter stackTracePrinter,\n\t\t\tContextPairs contextPairs, JsonWriter.Members<LogEvent> members) {\n\t\tExtractor extractor = new Extractor(stackTracePrinter);\n\t\tmembers.add(\"@timestamp\", LogEvent::getInstant).as(ElasticCommonSchemaStructuredLogFormatter::asTimestamp);\n\t\tmembers.add(\"log\").usingMembers((log) -> {\n\t\t\tlog.add(\"level\", LogEvent::getLevel).as(Level::name);\n\t\t\tlog.add(\"logger\", LogEvent::getLoggerName);\n\t\t});\n\t\tmembers.add(\"process\").usingMembers((process) -> {\n\t\t\tprocess.add(\"pid\", environment.getProperty(\"spring.application.pid\", Long.class)).whenNotNull();\n\t\t\tprocess.add(\"thread\").usingMembers((thread) -> thread.add(\"name\", LogEvent::getThreadName));\n\t\t});\n\t\tElasticCommonSchemaProperties.get(environment).jsonMembers(members);\n\t\tmembers.add(\"message\", LogEvent::getMessage).as(StructuredMessage::get);\n\t\tmembers.from(LogEvent::getContextData)\n\t\t\t.usingPairs(contextPairs.nested(ElasticCommonSchemaStructuredLogFormatter::addContextDataPairs));\n\t\tmembers.from(LogEvent::getThrown)\n\t\t\t.whenNotNull()\n\t\t\t.usingMembers((thrownMembers) -> thrownMembers.add(\"error\").usingMembers((error) -> {\n\t\t\t\terror.add(\"type\", ObjectUtils::nullSafeClassName);\n\t\t\t\terror.add(\"message\", Throwable::getMessage);\n\t\t\t\terror.add(\"stack_trace\", extractor::stackTrace);\n\t\t\t}));\n\t\tmembers.add(\"tags\", LogEvent::getMarker)\n\t\t\t.whenNotNull()\n\t\t\t.as(ElasticCommonSchemaStructuredLogFormatter::getMarkers)\n\t\t\t.whenNotEmpty();\n\t\tmembers.add(\"ecs\").usingMembers((ecs) -> ecs.add(\"version\", \"8.11\"));\n\t}\n\n\tprivate static void addContextDataPairs(Pairs<ReadOnlyStringMap> contextPairs) {\n\t\tcontextPairs.add((contextData, pairs) -> contextData.forEach(pairs::accept));\n\t}\n\n\tprivate static java.time.Instant asTimestamp(Instant instant) {\n\t\treturn java.time.Instant.ofEpochMilli(instant.getEpochMillisecond()).plusNanos(instant.getNanoOfMillisecond());\n\t}\n\n\tprivate static Set<String> getMarkers(Marker marker) {\n\t\tSet<String> result = new TreeSet<>();\n\t\taddMarkers(result, marker);\n\t\treturn result;\n\t}\n\n\tprivate static void addMarkers(Set<String> result, Marker marker) {\n\t\tresult.add(marker.getName());\n\t\tif (marker.hasParents()) {\n\t\t\tfor (Marker parent : marker.getParents()) {\n\t\t\t\taddMarkers(result, parent);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/EnclosedInSquareBracketsConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.List;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.layout.PatternLayout;\nimport org.apache.logging.log4j.core.pattern.ConverterKeys;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternFormatter;\nimport org.apache.logging.log4j.core.pattern.PatternParser;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Log4j2 {@link LogEventPatternConverter} used to help format optional values that should\n * be shown enclosed in square brackets.\n *\n * @author Phillip Webb\n * @since 3.4.0\n */\n@Plugin(name = \"enclosedInSquareBrackets\", category = PatternConverter.CATEGORY)\n@ConverterKeys(\"esb\")\npublic final class EnclosedInSquareBracketsConverter extends LogEventPatternConverter {\n\n\tprivate final List<PatternFormatter> formatters;\n\n\tprivate EnclosedInSquareBracketsConverter(List<PatternFormatter> formatters) {\n\t\tsuper(\"enclosedInSquareBrackets\", null);\n\t\tthis.formatters = formatters;\n\t}\n\n\t@Override\n\tpublic void format(LogEvent event, StringBuilder toAppendTo) {\n\t\tStringBuilder buf = new StringBuilder();\n\t\tfor (PatternFormatter formatter : this.formatters) {\n\t\t\tformatter.format(event, buf);\n\t\t}\n\t\tif (buf.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\ttoAppendTo.append(\"[\");\n\t\ttoAppendTo.append(buf);\n\t\ttoAppendTo.append(\"] \");\n\t}\n\n\t/**\n\t * Creates a new instance of the class. Required by Log4J2.\n\t * @param config the configuration\n\t * @param options the options\n\t * @return a new instance, or {@code null} if the options are invalid\n\t */\n\tpublic static @Nullable EnclosedInSquareBracketsConverter newInstance(@Nullable Configuration config,\n\t\t\tString[] options) {\n\t\tif (options.length < 1) {\n\t\t\tLOGGER.error(\"Incorrect number of options on style. Expected at least 1, received {}\", options.length);\n\t\t\treturn null;\n\t\t}\n\t\tPatternParser parser = PatternLayout.createPatternParser(config);\n\t\tList<PatternFormatter> formatters = parser.parse(options[0]);\n\t\treturn new EnclosedInSquareBracketsConverter(formatters);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/ExtendedWhitespaceThrowablePatternConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.pattern.ConverterKeys;\nimport org.apache.logging.log4j.core.pattern.ExtendedThrowablePatternConverter;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternConverter;\nimport org.apache.logging.log4j.core.pattern.ThrowablePatternConverter;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link ThrowablePatternConverter} that adds some additional whitespace around the stack\n * trace.\n *\n * @author Vladimir Tsanev\n * @author Phillip Webb\n * @since 1.3.0\n */\n@Plugin(name = \"ExtendedWhitespaceThrowablePatternConverter\", category = PatternConverter.CATEGORY)\n@ConverterKeys({ \"xwEx\", \"xwThrowable\", \"xwException\" })\npublic final class ExtendedWhitespaceThrowablePatternConverter extends LogEventPatternConverter {\n\n\tprivate final ExtendedThrowablePatternConverter delegate;\n\n\tprivate final String separator;\n\n\tprivate ExtendedWhitespaceThrowablePatternConverter(Configuration configuration, @Nullable String[] options) {\n\t\tsuper(\"WhitespaceExtendedThrowable\", \"throwable\");\n\t\tthis.delegate = ExtendedThrowablePatternConverter.newInstance(configuration, options);\n\t\tthis.separator = this.delegate.getOptions().getSeparator();\n\t}\n\n\t@Override\n\tpublic void format(LogEvent event, StringBuilder buffer) {\n\t\tif (event.getThrown() != null) {\n\t\t\tbuffer.append(this.separator);\n\t\t\tthis.delegate.format(event, buffer);\n\t\t\tbuffer.append(this.separator);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean handlesThrowable() {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a new instance of the class. Required by Log4J2.\n\t * @param configuration current configuration\n\t * @param options pattern options, may be null. If first element is \"short\", only the\n\t * first line of the throwable will be formatted.\n\t * @return a new {@code WhitespaceThrowablePatternConverter}\n\t */\n\tpublic static ExtendedWhitespaceThrowablePatternConverter newInstance(Configuration configuration,\n\t\t\t@Nullable String[] options) {\n\t\treturn new ExtendedWhitespaceThrowablePatternConverter(configuration, options);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Extractor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.jspecify.annotations.Nullable;\nimport org.slf4j.event.LoggingEvent;\n\nimport org.springframework.boot.logging.StackTracePrinter;\n\n/**\n * Functions to extract items from {@link LoggingEvent}.\n *\n * @author Phillip Webb\n */\nclass Extractor {\n\n\tprivate final @Nullable StackTracePrinter stackTracePrinter;\n\n\tExtractor(@Nullable StackTracePrinter stackTracePrinter) {\n\t\tthis.stackTracePrinter = stackTracePrinter;\n\t}\n\n\tString messageAndStackTrace(LogEvent event) {\n\t\treturn event.getMessage().getFormattedMessage() + \"\\n\\n\" + stackTrace(event);\n\t}\n\n\t@Nullable String stackTrace(LogEvent event) {\n\t\treturn stackTrace(event.getThrown());\n\t}\n\n\t@Nullable String stackTrace(@Nullable Throwable throwable) {\n\t\tif (throwable == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this.stackTracePrinter != null) {\n\t\t\treturn this.stackTracePrinter.printStackTraceToString(throwable);\n\t\t}\n\t\treturn printStackTrace(throwable);\n\t}\n\n\tprivate static String printStackTrace(Throwable throwable) {\n\t\tStringWriter stringWriter = new StringWriter();\n\t\tthrowable.printStackTrace(new PrintWriter(stringWriter));\n\t\treturn stringWriter.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/GraylogExtendedLogFormatStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.math.BigDecimal;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.net.Severity;\nimport org.apache.logging.log4j.core.time.Instant;\nimport org.apache.logging.log4j.message.Message;\nimport org.apache.logging.log4j.util.ReadOnlyStringMap;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.json.WritableJson;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.ContextPairs.Joiner;\nimport org.springframework.boot.logging.structured.GraylogExtendedLogFormatProperties;\nimport org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Log4j2 {@link StructuredLogFormatter} for\n * {@link CommonStructuredLogFormat#GRAYLOG_EXTENDED_LOG_FORMAT}. Supports GELF version\n * 1.1.\n *\n * @author Samuel Lissner\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass GraylogExtendedLogFormatStructuredLogFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {\n\n\tprivate static final Log logger = LogFactory.getLog(GraylogExtendedLogFormatStructuredLogFormatter.class);\n\n\t/**\n\t * Allowed characters in field names are any word character (letter, number,\n\t * underscore), dashes and dots.\n\t */\n\tprivate static final Pattern FIELD_NAME_VALID_PATTERN = Pattern.compile(\"^[\\\\w.\\\\-]*$\");\n\n\t/**\n\t * Libraries SHOULD not allow to send id as additional field (\"_id\"). Graylog server\n\t * nodes omit this field automatically.\n\t */\n\tprivate static final Set<String> ADDITIONAL_FIELD_ILLEGAL_KEYS = Set.of(\"id\", \"_id\");\n\n\tGraylogExtendedLogFormatStructuredLogFormatter(Environment environment,\n\t\t\t@Nullable StackTracePrinter stackTracePrinter, ContextPairs contextPairs,\n\t\t\t@Nullable StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\tsuper((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, members), customizer);\n\t}\n\n\tprivate static void jsonMembers(Environment environment, @Nullable StackTracePrinter stackTracePrinter,\n\t\t\tContextPairs contextPairs, JsonWriter.Members<LogEvent> members) {\n\t\tExtractor extractor = new Extractor(stackTracePrinter);\n\t\tmembers.add(\"version\", \"1.1\");\n\t\tmembers.add(\"short_message\", LogEvent::getMessage)\n\t\t\t.as(GraylogExtendedLogFormatStructuredLogFormatter::getMessageText);\n\t\tmembers.add(\"timestamp\", LogEvent::getInstant)\n\t\t\t.as(GraylogExtendedLogFormatStructuredLogFormatter::formatTimeStamp);\n\t\tmembers.add(\"level\", GraylogExtendedLogFormatStructuredLogFormatter::convertLevel);\n\t\tmembers.add(\"_level_name\", LogEvent::getLevel).as(Level::name);\n\t\tmembers.add(\"_process_pid\", environment.getProperty(\"spring.application.pid\", Long.class)).whenNotNull();\n\t\tmembers.add(\"_process_thread_name\", LogEvent::getThreadName);\n\t\tGraylogExtendedLogFormatProperties.get(environment).jsonMembers(members);\n\t\tmembers.add(\"_log_logger\", LogEvent::getLoggerName);\n\t\tPredicate<@Nullable ReadOnlyStringMap> mapIsEmpty = (map) -> map == null || map.isEmpty();\n\t\tmembers.from(LogEvent::getContextData)\n\t\t\t.whenNot(mapIsEmpty)\n\t\t\t.usingPairs(contextPairs.flat(additionalFieldJoiner(),\n\t\t\t\t\tGraylogExtendedLogFormatStructuredLogFormatter::addContextDataPairs));\n\t\tFunction<@Nullable LogEvent, @Nullable Object> getThrown = (event) -> (event != null) ? event.getThrown()\n\t\t\t\t: null;\n\t\tmembers.add()\n\t\t\t.whenNotNull(getThrown)\n\t\t\t.usingMembers((thrownMembers) -> throwableMembers(thrownMembers, extractor));\n\t}\n\n\tprivate static String getMessageText(Message message) {\n\t\t// Always return text as a blank message will lead to a error as of Graylog v6\n\t\tString formattedMessage = message.getFormattedMessage();\n\t\treturn (!StringUtils.hasText(formattedMessage)) ? \"(blank)\" : formattedMessage;\n\t}\n\n\t/**\n\t * GELF requires \"seconds since UNIX epoch with optional <b>decimal places for\n\t * milliseconds</b>\". To comply with this requirement, we format a POSIX timestamp\n\t * with millisecond precision as e.g. \"1725459730385\" -> \"1725459730.385\"\n\t * @param timeStamp the timestamp of the log message.\n\t * @return the timestamp formatted as string with millisecond precision\n\t */\n\tprivate static WritableJson formatTimeStamp(Instant timeStamp) {\n\t\treturn (out) -> out.append(new BigDecimal(timeStamp.getEpochMillisecond()).movePointLeft(3).toPlainString());\n\t}\n\n\t/**\n\t * Converts the log4j2 event level to the Syslog event level code.\n\t * @param event the log event\n\t * @return an integer representing the syslog log level code\n\t * @see Severity class from Log4j2 which contains the conversion logic\n\t */\n\tprivate static int convertLevel(LogEvent event) {\n\t\treturn Severity.getSeverity(event.getLevel()).getCode();\n\t}\n\n\tprivate static void throwableMembers(Members<LogEvent> members, Extractor extractor) {\n\t\tmembers.add(\"full_message\", extractor::messageAndStackTrace);\n\t\tmembers.add(\"_error_type\", LogEvent::getThrown).whenNotNull().as(ObjectUtils::nullSafeClassName);\n\t\tmembers.add(\"_error_stack_trace\", extractor::stackTrace);\n\t\tmembers.add(\"_error_message\", (event) -> event.getThrown().getMessage());\n\t}\n\n\tprivate static void addContextDataPairs(ContextPairs.Pairs<ReadOnlyStringMap> contextPairs) {\n\t\tcontextPairs.add((contextData, pairs) -> contextData.forEach(pairs::accept));\n\t}\n\n\tprivate static Joiner additionalFieldJoiner() {\n\t\treturn (prefix, name) -> {\n\t\t\tname = prefix + name;\n\t\t\tif (!FIELD_NAME_VALID_PATTERN.matcher(name).matches()) {\n\t\t\t\tlogger.warn(LogMessage.format(\"'%s' is not a valid field name according to GELF standard\", name));\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (ADDITIONAL_FIELD_ILLEGAL_KEYS.contains(name)) {\n\t\t\t\tlogger.warn(LogMessage.format(\"'%s' is an illegal field name according to GELF standard\", name));\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn (!name.startsWith(\"_\")) ? \"_\" + name : name;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.logging.ConsoleHandler;\nimport java.util.logging.Handler;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.core.Filter;\nimport org.apache.logging.log4j.core.Logger;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.config.AbstractConfiguration;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.ConfigurationException;\nimport org.apache.logging.log4j.core.config.ConfigurationFactory;\nimport org.apache.logging.log4j.core.config.LoggerConfig;\nimport org.apache.logging.log4j.core.config.composite.CompositeConfiguration;\nimport org.apache.logging.log4j.core.filter.DenyAllFilter;\nimport org.apache.logging.log4j.core.util.NameUtil;\nimport org.apache.logging.log4j.jul.Log4jBridgeHandler;\nimport org.apache.logging.log4j.status.StatusConsoleListener;\nimport org.apache.logging.log4j.status.StatusLogger;\nimport org.apache.logging.log4j.util.PropertiesUtil;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.logging.AbstractLoggingSystem;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggerConfiguration.LevelConfiguration;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemFactory;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.core.Conventions;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link LoggingSystem} for <a href=\"https://logging.apache.org/log4j/2.x/\">Log4j 2</a>.\n *\n * @author Daniel Fullarton\n * @author Andy Wilkinson\n * @author Alexander Heusingfeld\n * @author Ben Hale\n * @author Ralph Goers\n * @author Piotr P. Karwasz\n * @since 1.2.0\n */\npublic class Log4J2LoggingSystem extends AbstractLoggingSystem {\n\n\tprivate static final String OPTIONAL_PREFIX = \"optional:\";\n\n\t/**\n\t * JUL handler that routes messages to the Log4j API (optional dependency).\n\t */\n\tstatic final String LOG4J_BRIDGE_HANDLER = \"org.apache.logging.log4j.jul.Log4jBridgeHandler\";\n\n\t/**\n\t * JUL LogManager that routes messages to the Log4j API as the backend.\n\t */\n\tstatic final String LOG4J_LOG_MANAGER = \"org.apache.logging.log4j.jul.LogManager\";\n\n\tstatic final String ENVIRONMENT_KEY = Conventions.getQualifiedAttributeName(Log4J2LoggingSystem.class,\n\t\t\t\"environment\");\n\n\tstatic final String STATUS_LISTENER_KEY = Conventions.getQualifiedAttributeName(Log4J2LoggingSystem.class,\n\t\t\t\"statusListener\");\n\n\tprivate static final LogLevels<Level> LEVELS = new LogLevels<>();\n\n\tstatic {\n\t\tLEVELS.map(LogLevel.TRACE, Level.TRACE);\n\t\tLEVELS.map(LogLevel.DEBUG, Level.DEBUG);\n\t\tLEVELS.map(LogLevel.INFO, Level.INFO);\n\t\tLEVELS.map(LogLevel.WARN, Level.WARN);\n\t\tLEVELS.map(LogLevel.ERROR, Level.ERROR);\n\t\tLEVELS.map(LogLevel.FATAL, Level.FATAL);\n\t\tLEVELS.map(LogLevel.OFF, Level.OFF);\n\t}\n\n\tprivate static final Filter FILTER = DenyAllFilter.newBuilder().build();\n\n\tprivate static final SpringEnvironmentPropertySource propertySource = new SpringEnvironmentPropertySource();\n\n\tprivate static final org.apache.logging.log4j.Logger statusLogger = StatusLogger.getLogger();\n\n\tprivate final LoggerContext loggerContext;\n\n\t/**\n\t * Create a new {@link Log4J2LoggingSystem} instance.\n\t * @param classLoader the class loader to use.\n\t * @throws IllegalArgumentException if the logger context is not a\n\t * {@link LoggerContext}.\n\t */\n\tLog4J2LoggingSystem(ClassLoader classLoader) {\n\t\tsuper(classLoader);\n\t\torg.apache.logging.log4j.spi.LoggerContext spiLoggerContext = LogManager.getContext(classLoader, false);\n\t\tAssert.isInstanceOf(LoggerContext.class, spiLoggerContext);\n\t\tthis.loggerContext = (LoggerContext) spiLoggerContext;\n\t}\n\n\t@Override\n\tpublic LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) {\n\t\treturn new Log4j2LoggingSystemProperties(environment, getDefaultValueResolver(environment), null);\n\t}\n\n\t@Override\n\tprotected String[] getStandardConfigLocations() {\n\t\t// With Log4J2 we use the ConfigurationFactory\n\t\tthrow new IllegalStateException(\"Standard config locations cannot be used with Log4J2\");\n\t}\n\n\t@Override\n\tprotected @Nullable String getSelfInitializationConfig() {\n\t\treturn getConfigLocation(getLoggerContext().getConfiguration());\n\t}\n\n\t@Override\n\tprotected @Nullable String getSpringInitializationConfig() {\n\t\tConfigurationFactory configurationFactory = ConfigurationFactory.getInstance();\n\t\ttry {\n\t\t\tConfiguration springConfiguration = configurationFactory.getConfiguration(getLoggerContext(), \"-spring\",\n\t\t\t\t\tnull, getClassLoader());\n\t\t\tString configLocation = getConfigLocation(springConfiguration);\n\t\t\treturn (configLocation != null && configLocation.contains(\"-spring\")) ? configLocation : null;\n\t\t}\n\t\tcatch (ConfigurationException ex) {\n\t\t\tstatusLogger.warn(\"Could not load Spring-specific Log4j Core configuration\", ex);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Return the configuration location. The result may be:\n\t * <ul>\n\t * <li>{@code null}: if DefaultConfiguration is used (no explicit config loaded)</li>\n\t * <li>A file path: if provided explicitly by the user</li>\n\t * <li>A URI: if loaded from the classpath default or a custom location</li>\n\t * </ul>\n\t * @param configuration the source configuration\n\t * @return the config location or {@code null}\n\t */\n\tprivate @Nullable String getConfigLocation(Configuration configuration) {\n\t\treturn configuration.getConfigurationSource().getLocation();\n\t}\n\n\t@Override\n\tpublic void beforeInitialize() {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tif (isAlreadyInitialized(loggerContext)) {\n\t\t\treturn;\n\t\t}\n\t\tif (!configureJdkLoggingBridgeHandler()) {\n\t\t\tsuper.beforeInitialize();\n\t\t}\n\t\tloggerContext.getConfiguration().addFilter(FILTER);\n\t}\n\n\tprivate boolean configureJdkLoggingBridgeHandler() {\n\t\ttry {\n\t\t\tif (isJulUsingASingleConsoleHandlerAtMost() && !isLog4jLogManagerInstalled()\n\t\t\t\t\t&& isLog4jBridgeHandlerAvailable()) {\n\t\t\t\tremoveDefaultRootHandler();\n\t\t\t\tLog4jBridgeHandler.install(false, null, true);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Ignore. No java.util.logging bridge is installed.\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isJulUsingASingleConsoleHandlerAtMost() {\n\t\tjava.util.logging.Logger rootLogger = java.util.logging.LogManager.getLogManager().getLogger(\"\");\n\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\treturn handlers.length == 0 || (handlers.length == 1 && handlers[0] instanceof ConsoleHandler);\n\t}\n\n\tprivate boolean isLog4jLogManagerInstalled() {\n\t\tfinal String logManagerClassName = java.util.logging.LogManager.getLogManager().getClass().getName();\n\t\treturn LOG4J_LOG_MANAGER.equals(logManagerClassName);\n\t}\n\n\tprivate boolean isLog4jBridgeHandlerAvailable() {\n\t\treturn ClassUtils.isPresent(LOG4J_BRIDGE_HANDLER, getClassLoader());\n\t}\n\n\tprivate void removeLog4jBridgeHandler() {\n\t\tremoveDefaultRootHandler();\n\t\tjava.util.logging.Logger rootLogger = java.util.logging.LogManager.getLogManager().getLogger(\"\");\n\t\tfor (final Handler handler : rootLogger.getHandlers()) {\n\t\t\tif (handler instanceof Log4jBridgeHandler) {\n\t\t\t\thandler.close();\n\t\t\t\trootLogger.removeHandler(handler);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void removeDefaultRootHandler() {\n\t\ttry {\n\t\t\tjava.util.logging.Logger rootLogger = java.util.logging.LogManager.getLogManager().getLogger(\"\");\n\t\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\t\tif (handlers.length == 1 && handlers[0] instanceof ConsoleHandler) {\n\t\t\t\trootLogger.removeHandler(handlers[0]);\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Ignore and continue\n\t\t}\n\t}\n\n\t@Override\n\tpublic void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation,\n\t\t\t@Nullable LogFile logFile) {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tif (isAlreadyInitialized(loggerContext)) {\n\t\t\treturn;\n\t\t}\n\t\tStatusConsoleListener listener = new StatusConsoleListener(Level.WARN);\n\t\tStatusLogger.getLogger().registerListener(listener);\n\t\tloggerContext.putObject(STATUS_LISTENER_KEY, listener);\n\t\tEnvironment environment = initializationContext.getEnvironment();\n\t\tif (environment != null) {\n\t\t\tloggerContext.putObject(ENVIRONMENT_KEY, environment);\n\t\t\tLog4J2LoggingSystem.propertySource.setEnvironment(environment);\n\t\t\tPropertiesUtil.getProperties().addPropertySource(Log4J2LoggingSystem.propertySource);\n\t\t}\n\t\tloggerContext.getConfiguration().removeFilter(FILTER);\n\t\tsuper.initialize(initializationContext, configLocation, logFile);\n\t\tmarkAsInitialized(loggerContext);\n\t}\n\n\t@Override\n\tprotected void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile) {\n\t\tString location = getPackagedConfigFile((logFile != null) ? \"log4j2-file.xml\" : \"log4j2.xml\");\n\t\tload(initializationContext, location, logFile);\n\t}\n\n\t@Override\n\tprotected void loadConfiguration(LoggingInitializationContext initializationContext, String location,\n\t\t\t@Nullable LogFile logFile) {\n\t\tload(initializationContext, location, logFile);\n\t}\n\n\tprivate void load(LoggingInitializationContext initializationContext, String location, @Nullable LogFile logFile) {\n\t\tList<String> overrides = getOverrides(initializationContext);\n\t\tEnvironment environment = initializationContext.getEnvironment();\n\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\tapplySystemProperties(environment, logFile);\n\t\treconfigure(location, overrides);\n\t}\n\n\tprivate List<String> getOverrides(LoggingInitializationContext initializationContext) {\n\t\tEnvironment environment = initializationContext.getEnvironment();\n\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\tBindResult<List<String>> overrides = Binder.get(environment)\n\t\t\t.bind(\"logging.log4j2.config.override\", Bindable.listOf(String.class));\n\t\treturn overrides.orElse(Collections.emptyList());\n\t}\n\n\tprivate void reconfigure(String location, List<String> overrides) {\n\t\tAssert.notNull(location, \"'location' must not be null\");\n\t\ttry {\n\t\t\tList<Configuration> configurations = new ArrayList<>();\n\t\t\tResourceLoader resourceLoader = ApplicationResourceLoader.get(getClassLoader());\n\t\t\tconfigurations.add(load(resourceLoader, location));\n\t\t\tfor (String override : overrides) {\n\t\t\t\tConfiguration overrideConfiguration = loadOverride(resourceLoader, override);\n\t\t\t\tif (overrideConfiguration != null) {\n\t\t\t\t\tconfigurations.add(overrideConfiguration);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.loggerContext.reconfigure(mergeConfigurations(configurations));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not initialize Log4J2 logging from %s%s\".formatted(location,\n\t\t\t\t\t(overrides.isEmpty() ? \"\" : \" with overrides \" + overrides)), ex);\n\t\t}\n\t}\n\n\tprivate Configuration load(ResourceLoader resourceLoader, String location) throws IOException {\n\t\tConfigurationFactory configurationFactory = ConfigurationFactory.getInstance();\n\t\tResource resource = resourceLoader.getResource(location);\n\t\tConfiguration configuration = configurationFactory.getConfiguration(getLoggerContext(), null, resource.getURI(),\n\t\t\t\tgetClassLoader());\n\t\t// The error handling in Log4j Core 2.25.x is not consistent, some loading and\n\t\t// parsing errors result in a null configuration, others in an exception.\n\t\tif (configuration == null) {\n\t\t\tthrow new ConfigurationException(\"Could not load Log4j Core configuration from \" + location);\n\t\t}\n\t\treturn configuration;\n\t}\n\n\tprivate @Nullable Configuration loadOverride(ResourceLoader resourceLoader, String location) throws IOException {\n\t\tif (location.startsWith(OPTIONAL_PREFIX)) {\n\t\t\tString actualLocation = location.substring(OPTIONAL_PREFIX.length());\n\t\t\tResource resource = resourceLoader.getResource(actualLocation);\n\t\t\ttry {\n\t\t\t\treturn (resource.exists()) ? load(resourceLoader, actualLocation) : null;\n\t\t\t}\n\t\t\tcatch (FileNotFoundException ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn load(resourceLoader, location);\n\t}\n\n\tprivate Configuration mergeConfigurations(List<Configuration> configurations) {\n\t\tif (configurations.size() == 1) {\n\t\t\treturn configurations.iterator().next();\n\t\t}\n\t\treturn new CompositeConfiguration(configurations.stream().map(AbstractConfiguration.class::cast).toList());\n\t}\n\n\t@Override\n\tprotected void reinitialize(LoggingInitializationContext initializationContext) {\n\t\tString currentLocation = getSelfInitializationConfig();\n\t\tAssert.notNull(currentLocation, \"'currentLocation' must not be null\");\n\t\tload(initializationContext, currentLocation, null);\n\t}\n\n\t@Override\n\tpublic Set<LogLevel> getSupportedLogLevels() {\n\t\treturn LEVELS.getSupported();\n\t}\n\n\t@Override\n\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel logLevel) {\n\t\tsetLogLevel(loggerName, LEVELS.convertSystemToNative(logLevel));\n\t}\n\n\tprivate void setLogLevel(@Nullable String loggerName, @Nullable Level level) {\n\t\tLoggerConfig logger = getLogger(loggerName);\n\t\tif (level == null) {\n\t\t\tclearLogLevel(loggerName, logger);\n\t\t}\n\t\telse {\n\t\t\tsetLogLevel(loggerName, logger, level);\n\t\t}\n\t\tgetLoggerContext().updateLoggers();\n\t}\n\n\tprivate void clearLogLevel(@Nullable String loggerName, @Nullable LoggerConfig logger) {\n\t\tif (logger == null) {\n\t\t\treturn;\n\t\t}\n\t\tif (logger instanceof LevelSetLoggerConfig) {\n\t\t\tgetLoggerContext().getConfiguration().removeLogger(loggerName);\n\t\t}\n\t\telse {\n\t\t\tlogger.setLevel(null);\n\t\t}\n\t}\n\n\tprivate void setLogLevel(@Nullable String loggerName, @Nullable LoggerConfig logger, Level level) {\n\t\tif (logger == null) {\n\t\t\tgetLoggerContext().getConfiguration()\n\t\t\t\t.addLogger(loggerName, new LevelSetLoggerConfig(loggerName, level, true));\n\t\t}\n\t\telse {\n\t\t\tlogger.setLevel(level);\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\tList<LoggerConfiguration> result = new ArrayList<>();\n\t\tgetAllLoggers().forEach((name, loggerConfig) -> result.add(convertLoggerConfig(name, loggerConfig)));\n\t\tresult.sort(CONFIGURATION_COMPARATOR);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\tLoggerConfig loggerConfig = getAllLoggers().get(loggerName);\n\t\treturn (loggerConfig != null) ? convertLoggerConfig(loggerName, loggerConfig) : null;\n\t}\n\n\tprivate Map<String, LoggerConfig> getAllLoggers() {\n\t\tMap<String, LoggerConfig> loggers = new LinkedHashMap<>();\n\t\tfor (Logger logger : getLoggerContext().getLoggers()) {\n\t\t\taddLogger(loggers, logger.getName());\n\t\t}\n\t\tgetLoggerContext().getConfiguration().getLoggers().keySet().forEach((name) -> addLogger(loggers, name));\n\t\treturn loggers;\n\t}\n\n\tprivate void addLogger(Map<String, LoggerConfig> loggers, String name) {\n\t\tConfiguration configuration = getLoggerContext().getConfiguration();\n\t\twhile (name != null) {\n\t\t\tloggers.computeIfAbsent(name, configuration::getLoggerConfig);\n\t\t\tname = getSubName(name);\n\t\t}\n\t}\n\n\tprivate @Nullable String getSubName(String name) {\n\t\tif (!StringUtils.hasLength(name)) {\n\t\t\treturn null;\n\t\t}\n\t\tint nested = name.lastIndexOf('$');\n\t\treturn (nested != -1) ? name.substring(0, nested) : NameUtil.getSubName(name);\n\t}\n\n\tprivate @Nullable LoggerConfiguration convertLoggerConfig(String name, @Nullable LoggerConfig loggerConfig) {\n\t\tif (loggerConfig == null) {\n\t\t\treturn null;\n\t\t}\n\t\tLevelConfiguration effectiveLevelConfiguration = getLevelConfiguration(loggerConfig.getLevel());\n\t\tif (!StringUtils.hasLength(name) || LogManager.ROOT_LOGGER_NAME.equals(name)) {\n\t\t\tname = ROOT_LOGGER_NAME;\n\t\t}\n\t\tboolean isAssigned = loggerConfig.getName().equals(name);\n\t\tLevelConfiguration assignedLevelConfiguration = (!isAssigned) ? null : effectiveLevelConfiguration;\n\t\treturn new LoggerConfiguration(name, assignedLevelConfiguration, effectiveLevelConfiguration);\n\t}\n\n\tprivate LevelConfiguration getLevelConfiguration(Level level) {\n\t\tLogLevel logLevel = LEVELS.convertNativeToSystem(level);\n\t\treturn (logLevel != null) ? LevelConfiguration.of(logLevel) : LevelConfiguration.ofCustom(level.name());\n\t}\n\n\t@Override\n\tpublic Runnable getShutdownHandler() {\n\t\treturn () -> getLoggerContext().stop();\n\t}\n\n\t@Override\n\tpublic void cleanUp() {\n\t\tif (isLog4jBridgeHandlerAvailable()) {\n\t\t\tremoveLog4jBridgeHandler();\n\t\t}\n\t\tsuper.cleanUp();\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tmarkAsUninitialized(loggerContext);\n\t\tStatusConsoleListener listener = (StatusConsoleListener) loggerContext.getObject(STATUS_LISTENER_KEY);\n\t\tif (listener != null) {\n\t\t\tStatusLogger.getLogger().removeListener(listener);\n\t\t\tloggerContext.removeObject(STATUS_LISTENER_KEY);\n\t\t}\n\t\tloggerContext.getConfiguration().removeFilter(FILTER);\n\t\tLog4J2LoggingSystem.propertySource.setEnvironment(null);\n\t\tloggerContext.removeObject(ENVIRONMENT_KEY);\n\t}\n\n\tprivate @Nullable LoggerConfig getLogger(@Nullable String name) {\n\t\tif (!StringUtils.hasLength(name) || ROOT_LOGGER_NAME.equals(name)) {\n\t\t\treturn findLogger(LogManager.ROOT_LOGGER_NAME);\n\t\t}\n\t\treturn findLogger(name);\n\t}\n\n\tprivate @Nullable LoggerConfig findLogger(String name) {\n\t\tConfiguration configuration = getLoggerContext().getConfiguration();\n\t\tif (configuration instanceof AbstractConfiguration abstractConfiguration) {\n\t\t\treturn abstractConfiguration.getLogger(name);\n\t\t}\n\t\treturn configuration.getLoggers().get(name);\n\t}\n\n\tLoggerContext getLoggerContext() {\n\t\treturn this.loggerContext;\n\t}\n\n\tprivate boolean isAlreadyInitialized(LoggerContext loggerContext) {\n\t\treturn LoggingSystem.class.getName().equals(loggerContext.getExternalContext());\n\t}\n\n\tprivate void markAsInitialized(LoggerContext loggerContext) {\n\t\tloggerContext.setExternalContext(LoggingSystem.class.getName());\n\t}\n\n\tprivate void markAsUninitialized(LoggerContext loggerContext) {\n\t\tloggerContext.setExternalContext(null);\n\t}\n\n\t@Override\n\tprotected String getDefaultLogCorrelationPattern() {\n\t\treturn \"%correlationId\";\n\t}\n\n\t/**\n\t * Get the Spring {@link Environment} attached to the given {@link LoggerContext} or\n\t * {@code null} if no environment is available.\n\t * @param loggerContext the logger context\n\t * @return the Spring {@link Environment} or {@code null}\n\t * @since 3.0.0\n\t */\n\tpublic static @Nullable Environment getEnvironment(@Nullable LoggerContext loggerContext) {\n\t\treturn (Environment) ((loggerContext != null) ? loggerContext.getObject(ENVIRONMENT_KEY) : null);\n\t}\n\n\t/**\n\t * {@link LoggingSystemFactory} that returns {@link Log4J2LoggingSystem} if possible.\n\t */\n\t@Order(0)\n\tpublic static class Factory implements LoggingSystemFactory {\n\n\t\tstatic final String LOG4J_CORE_CONTEXT_FACTORY = \"org.apache.logging.log4j.core.impl.Log4jContextFactory\";\n\n\t\tprivate static final boolean PRESENT = ClassUtils.isPresent(LOG4J_CORE_CONTEXT_FACTORY,\n\t\t\t\tFactory.class.getClassLoader());\n\n\t\t@Override\n\t\tpublic @Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader) {\n\t\t\tif (PRESENT) {\n\t\t\t\ttry {\n\t\t\t\t\treturn new Log4J2LoggingSystem(classLoader);\n\t\t\t\t}\n\t\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\t\t// Continue\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link LoggerConfig} used when the user has set a specific {@link Level}.\n\t */\n\tprivate static class LevelSetLoggerConfig extends LoggerConfig {\n\n\t\tLevelSetLoggerConfig(@Nullable String name, Level level, boolean additive) {\n\t\t\tsuper(name, level, additive);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link RuntimeHintsRegistrar} implementation for {@link Log4J2LoggingSystem}.\n *\n * @author Piotr P. Karwasz\n * @author Stephane Nicoll\n */\nclass Log4J2RuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tif (ClassUtils.isPresent(Log4J2LoggingSystem.Factory.LOG4J_CORE_CONTEXT_FACTORY, classLoader)) {\n\t\t\tregisterLog4j2Hints(hints, classLoader);\n\t\t}\n\t}\n\n\tprivate void registerLog4j2Hints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\thints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.Factory.LOG4J_CORE_CONTEXT_FACTORY);\n\t\t// Register default Log4j2 configuration files\n\t\thints.resources().registerPattern(\"org/springframework/boot/logging/log4j2/log4j2.xml\");\n\t\thints.resources().registerPattern(\"org/springframework/boot/logging/log4j2/log4j2-file.xml\");\n\t\thints.resources().registerPattern(\"log4j2.springboot\");\n\t\t// Declares the types that Log4j2LoggingSystem checks for existence reflectively.\n\t\thints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.LOG4J_BRIDGE_HANDLER);\n\t\thints.reflection().registerTypeIfPresent(classLoader, Log4J2LoggingSystem.LOG4J_LOG_MANAGER);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4j2LoggingSystemProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link LoggingSystemProperties} for Log4j2.\n *\n * @author HoJoo Moon\n * @since 4.1.0\n * @see RollingPolicySystemProperty\n */\npublic class Log4j2LoggingSystemProperties extends LoggingSystemProperties {\n\n\tpublic Log4j2LoggingSystemProperties(Environment environment) {\n\t\tsuper(environment);\n\t}\n\n\t/**\n\t * Create a new {@link Log4j2LoggingSystemProperties} instance.\n\t * @param environment the source environment\n\t * @param defaultValueResolver function used to resolve default values or {@code null}\n\t * @param setter setter used to apply the property or {@code null} for system\n\t * properties\n\t */\n\tpublic Log4j2LoggingSystemProperties(Environment environment,\n\t\t\tFunction<@Nullable String, @Nullable String> defaultValueResolver,\n\t\t\t@Nullable BiConsumer<String, @Nullable String> setter) {\n\t\tsuper(environment, defaultValueResolver, setter);\n\t}\n\n\t@Override\n\tprotected void apply(@Nullable LogFile logFile, PropertyResolver resolver) {\n\t\tsuper.apply(logFile, resolver);\n\t\tapplyRollingPolicyProperties(resolver);\n\t}\n\n\tprivate void applyRollingPolicyProperties(PropertyResolver resolver) {\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.FILE_NAME_PATTERN, resolver);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.MAX_FILE_SIZE, resolver, DataSize.class);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.MAX_HISTORY, resolver);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.STRATEGY, resolver);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.TIME_INTERVAL, resolver, Integer.class);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.TIME_MODULATE, resolver, Boolean.class);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.CRON, resolver);\n\t}\n\n\tprivate void applyRollingPolicy(RollingPolicySystemProperty property, PropertyResolver resolver) {\n\t\tapplyRollingPolicy(property, resolver, String.class);\n\t}\n\n\tprivate <T> void applyRollingPolicy(RollingPolicySystemProperty property, PropertyResolver resolver,\n\t\t\tClass<T> type) {\n\t\tT value = getProperty(resolver, property.getApplicationPropertyName(), type);\n\t\tif (value != null) {\n\t\t\tString stringValue = String.valueOf((value instanceof DataSize dataSize) ? dataSize.toBytes() : value);\n\t\t\tsetSystemProperty(property.getEnvironmentVariableName(), stringValue);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T getProperty(PropertyResolver resolver, String key, Class<T> type) {\n\t\ttry {\n\t\t\treturn resolver.getProperty(key, type);\n\t\t}\n\t\tcatch (ConversionFailedException | ConverterNotFoundException ex) {\n\t\t\tif (type != DataSize.class) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tString value = resolver.getProperty(key);\n\t\t\treturn (value != null) ? (T) DataSize.parse(value) : null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/LogstashStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.time.OffsetDateTime;\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Predicate;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.Marker;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.time.Instant;\nimport org.apache.logging.log4j.util.ReadOnlyStringMap;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Log4j2 {@link StructuredLogFormatter} for {@link CommonStructuredLogFormat#LOGSTASH}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass LogstashStructuredLogFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {\n\n\tLogstashStructuredLogFormatter(@Nullable StackTracePrinter stackTracePrinter, ContextPairs contextPairs,\n\t\t\t@Nullable StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\tsuper((members) -> jsonMembers(stackTracePrinter, contextPairs, members), customizer);\n\t}\n\n\tprivate static void jsonMembers(@Nullable StackTracePrinter stackTracePrinter, ContextPairs contextPairs,\n\t\t\tJsonWriter.Members<LogEvent> members) {\n\t\tExtractor extractor = new Extractor(stackTracePrinter);\n\t\tmembers.add(\"@timestamp\", LogEvent::getInstant).as(LogstashStructuredLogFormatter::asTimestamp);\n\t\tmembers.add(\"@version\", \"1\");\n\t\tmembers.add(\"message\", LogEvent::getMessage).as(StructuredMessage::get);\n\t\tmembers.add(\"logger_name\", LogEvent::getLoggerName);\n\t\tmembers.add(\"thread_name\", LogEvent::getThreadName);\n\t\tmembers.add(\"level\", LogEvent::getLevel).as(Level::name);\n\t\tmembers.add(\"level_value\", LogEvent::getLevel).as(Level::intLevel);\n\t\tPredicate<@Nullable ReadOnlyStringMap> mapIsEmpty = (map) -> map == null || map.isEmpty();\n\t\tmembers.from(LogEvent::getContextData)\n\t\t\t.whenNot(mapIsEmpty)\n\t\t\t.usingPairs(contextPairs.flat(\"_\", LogstashStructuredLogFormatter::addContextDataPairs));\n\t\tPredicate<@Nullable Set<String>> collectionIsEmpty = CollectionUtils::isEmpty;\n\t\tmembers.add(\"tags\", LogEvent::getMarker)\n\t\t\t.whenNotNull()\n\t\t\t.as(LogstashStructuredLogFormatter::getMarkers)\n\t\t\t.whenNot(collectionIsEmpty);\n\t\tmembers.add(\"stack_trace\", LogEvent::getThrown).whenNotNull().as(extractor::stackTrace);\n\t}\n\n\tprivate static String asTimestamp(Instant instant) {\n\t\tjava.time.Instant javaInstant = java.time.Instant.ofEpochMilli(instant.getEpochMillisecond())\n\t\t\t.plusNanos(instant.getNanoOfMillisecond());\n\t\tOffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(javaInstant, ZoneId.systemDefault());\n\t\treturn DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime);\n\t}\n\n\tprivate static void addContextDataPairs(ContextPairs.Pairs<ReadOnlyStringMap> contextPairs) {\n\t\tcontextPairs.add((contextData, pairs) -> contextData.forEach(pairs::accept));\n\t}\n\n\tprivate static Set<String> getMarkers(Marker marker) {\n\t\tSet<String> result = new TreeSet<>();\n\t\taddMarkers(result, marker);\n\t\treturn result;\n\t}\n\n\tprivate static void addMarkers(Set<String> result, Marker marker) {\n\t\tresult.add(marker.getName());\n\t\tif (marker.hasParents()) {\n\t\t\tfor (Marker parent : marker.getParents()) {\n\t\t\t\taddMarkers(result, parent);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/RollingPolicyStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\n/**\n * Available rolling policy strategies.\n *\n * @author Stephane Nicoll\n * @since 4.1.0\n */\npublic enum RollingPolicyStrategy {\n\n\t/**\n\t * Roll a file over based on its size.\n\t */\n\tSIZE,\n\n\t/**\n\t * Roll a file over based on time.\n\t */\n\tTIME,\n\n\t/**\n\t * Roll a file over based on its size and time.\n\t */\n\tSIZE_AND_TIME,\n\n\t/**\n\t * Roll a file over based on a cron schedule.\n\t */\n\tCRON\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/RollingPolicySystemProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\n/**\n * Log4j2 rolling policy system properties that can later be used by log configuration\n * files.\n *\n * @author HoJoo Moon\n * @author Stephane Nicoll\n * @since 4.1.0\n * @see Log4j2LoggingSystemProperties\n */\npublic enum RollingPolicySystemProperty {\n\n\t/**\n\t * Logging system property for the rolled-over log file name pattern.\n\t */\n\tFILE_NAME_PATTERN(\"file-name-pattern\"),\n\n\t/**\n\t * Logging system property for the file log max size.\n\t */\n\tMAX_FILE_SIZE(\"max-file-size\"),\n\n\t/**\n\t * Logging system property for the file log max history.\n\t */\n\tMAX_HISTORY(\"max-history\"),\n\n\t/**\n\t * Logging system property for the {@linkplain RollingPolicyStrategy rolling policy\n\t * strategy}.\n\t */\n\tSTRATEGY(\"strategy\"),\n\n\t/**\n\t * Logging system property for the rolling policy time interval.\n\t */\n\tTIME_INTERVAL(\"time-interval\"),\n\n\t/**\n\t * Logging system property for the rolling policy time modulate flag.\n\t */\n\tTIME_MODULATE(\"time-modulate\"),\n\n\t/**\n\t * Logging system property for the cron based schedule.\n\t */\n\tCRON(\"cron\");\n\n\tprivate final String environmentVariableName;\n\n\tprivate final String applicationPropertyName;\n\n\tRollingPolicySystemProperty(String applicationPropertyName) {\n\t\tthis.environmentVariableName = \"LOG4J2_ROLLINGPOLICY_\" + name();\n\t\tthis.applicationPropertyName = \"logging.log4j2.rollingpolicy.\" + applicationPropertyName;\n\t}\n\n\t/**\n\t * Return the name of environment variable that can be used to access this property.\n\t * @return the environment variable name\n\t */\n\tpublic String getEnvironmentVariableName() {\n\t\treturn this.environmentVariableName;\n\t}\n\n\tString getApplicationPropertyName() {\n\t\treturn this.applicationPropertyName;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootConfigurationFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.ConfigurationFactory;\nimport org.apache.logging.log4j.core.config.ConfigurationSource;\nimport org.apache.logging.log4j.core.config.DefaultConfiguration;\nimport org.apache.logging.log4j.core.config.Order;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Spring Boot {@link ConfigurationFactory} that customizes Log4J2's default configuration\n * to:\n *\n * <ol>\n * <li>Prevent logger warnings from being printed when the application first starts.\n * </ol>\n *\n * This factory is ordered last and is triggered by a {@code log4j2.springboot} classpath\n * resource (which is bundled in this jar). If the {@link Log4J2LoggingSystem} is active,\n * a {@link DefaultConfiguration} is returned with the expectation that the system will\n * later re-initialize Log4J2 with the correct configuration file.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\n@Plugin(name = \"SpringBootConfigurationFactory\", category = ConfigurationFactory.CATEGORY)\n@Order(0)\npublic class SpringBootConfigurationFactory extends ConfigurationFactory {\n\n\tprivate static final String[] TYPES = { \".springboot\" };\n\n\t@Override\n\tprotected String[] getSupportedTypes() {\n\t\treturn TYPES;\n\t}\n\n\t@Override\n\tpublic @Nullable Configuration getConfiguration(LoggerContext loggerContext, @Nullable ConfigurationSource source) {\n\t\tif (source == null || source == ConfigurationSource.NULL_SOURCE) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new DefaultConfiguration();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;\nimport org.apache.logging.log4j.util.BiConsumer;\nimport org.apache.logging.log4j.util.PropertySource;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Spring Boot {@link PropertySource} that disables Log4j2's shutdown hook.\n *\n * @author Andy Wilkinson\n * @since 2.5.2\n */\npublic class SpringBootPropertySource implements PropertySource {\n\n\tprivate static final String PREFIX = \"log4j.\";\n\n\tprivate final Map<String, String> properties = Collections\n\t\t.singletonMap(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, \"false\");\n\n\t@Override\n\tpublic void forEach(BiConsumer<String, String> action) {\n\t\tthis.properties.forEach(action);\n\t}\n\n\t@Override\n\tpublic CharSequence getNormalForm(Iterable<? extends CharSequence> tokens) {\n\t\treturn PREFIX + Util.joinAsCamelCase(tokens);\n\t}\n\n\t@Override\n\tpublic int getPriority() {\n\t\treturn -200;\n\t}\n\n\t@Override\n\tpublic @Nullable String getProperty(String key) {\n\t\treturn this.properties.get(key);\n\t}\n\n\t@Override\n\tpublic boolean containsProperty(String key) {\n\t\treturn this.properties.containsKey(key);\n\t}\n\n\t@Override\n\tpublic Collection<String> getPropertyNames() {\n\t\treturn this.properties.keySet();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringBootTriggeringPolicy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Objects;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.RollingFileManager;\nimport org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.Node;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.config.plugins.PluginAttribute;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;\nimport org.apache.logging.log4j.core.config.plugins.PluginConfiguration;\nimport org.apache.logging.log4j.core.util.Builder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.core.convert.ConversionException;\nimport org.springframework.util.Assert;\n\n/**\n * Factory for creating a standard Log4j2 {@link TriggeringPolicy} based on configuration\n * attributes. The supported strategies are {@code size}, {@code time},\n * {@code size-and-time}, and {@code cron}.\n *\n * @author HoJoo Moon\n * @author Stephane Nicoll\n * @since 4.1.0\n */\n@Plugin(name = \"SpringBootTriggeringPolicy\", category = Node.CATEGORY, elementType = \"TriggeringPolicy\",\n\t\tdeferChildren = true, printObject = true)\npublic abstract class SpringBootTriggeringPolicy implements TriggeringPolicy {\n\n\tprivate SpringBootTriggeringPolicy() {\n\t}\n\n\t@Override\n\tpublic void initialize(RollingFileManager manager) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic boolean isTriggeringEvent(LogEvent logEvent) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@PluginBuilderFactory\n\tpublic static SpringBootTriggeringPolicyBuilder newBuilder() {\n\t\treturn new SpringBootTriggeringPolicyBuilder();\n\t}\n\n\t/**\n\t * Builder for creating a {@link TriggeringPolicy}.\n\t */\n\tpublic static class SpringBootTriggeringPolicyBuilder implements Builder<TriggeringPolicy> {\n\n\t\tprivate static final String DEFAULT_STRATEGY = \"size\";\n\n\t\tprivate static final String DEFAULT_MAX_FILE_SIZE = \"10MB\";\n\n\t\tprivate static final String DEFAULT_TIME_INTERVAL = \"1\";\n\n\t\tprivate static final String DEFAULT_CRON_EXPRESSION = \"0 0 0 * * ?\";\n\n\t\t@PluginAttribute(\"strategy\")\n\t\tprivate @Nullable String strategy;\n\n\t\t@PluginAttribute(\"maxFileSize\")\n\t\tprivate @Nullable String maxFileSize;\n\n\t\t@PluginAttribute(\"timeInterval\")\n\t\tprivate @Nullable Integer timeInterval;\n\n\t\t@PluginAttribute(\"timeModulate\")\n\t\tprivate @Nullable Boolean timeModulate;\n\n\t\t@PluginAttribute(\"cronExpression\")\n\t\tprivate @Nullable String cronExpression;\n\n\t\t@PluginConfiguration\n\t\tprivate @Nullable Configuration configuration;\n\n\t\t@Override\n\t\tpublic TriggeringPolicy build() {\n\t\t\tRollingPolicyStrategy resolvedStrategy = getRollingPolicyStrategy();\n\t\t\treturn switch (resolvedStrategy) {\n\t\t\t\tcase TIME -> createTimePolicy();\n\t\t\t\tcase SIZE_AND_TIME -> CompositeTriggeringPolicy.createPolicy(createSizePolicy(), createTimePolicy());\n\t\t\t\tcase CRON -> createCronPolicy();\n\t\t\t\tcase SIZE -> createSizePolicy();\n\t\t\t};\n\t\t}\n\n\t\tprivate static RollingPolicyStrategy getRollingPolicyStrategy() {\n\t\t\tString resolvedStrategy = getSystemProperty(RollingPolicySystemProperty.STRATEGY, DEFAULT_STRATEGY);\n\t\t\ttry {\n\t\t\t\treturn Objects.requireNonNull(ApplicationConversionService.getSharedInstance()\n\t\t\t\t\t.convert(resolvedStrategy, RollingPolicyStrategy.class));\n\t\t\t}\n\t\t\tcatch (ConversionException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Unsupported rolling policy strategy '%s'\".formatted(resolvedStrategy));\n\t\t\t}\n\t\t}\n\n\t\tprivate TriggeringPolicy createSizePolicy() {\n\t\t\tString size = getSystemProperty(RollingPolicySystemProperty.MAX_FILE_SIZE, DEFAULT_MAX_FILE_SIZE);\n\t\t\treturn SizeBasedTriggeringPolicy.createPolicy(size);\n\t\t}\n\n\t\tprivate TriggeringPolicy createTimePolicy() {\n\t\t\tint interval = Integer\n\t\t\t\t.parseInt(getSystemProperty(RollingPolicySystemProperty.TIME_INTERVAL, DEFAULT_TIME_INTERVAL));\n\t\t\tboolean modulate = Boolean\n\t\t\t\t.parseBoolean(getSystemProperty(RollingPolicySystemProperty.TIME_MODULATE, Boolean.FALSE.toString()));\n\t\t\treturn TimeBasedTriggeringPolicy.newBuilder().withInterval(interval).withModulate(modulate).build();\n\t\t}\n\n\t\tprivate TriggeringPolicy createCronPolicy() {\n\t\t\tAssert.notNull(this.configuration, \"configuration must not be null\");\n\t\t\tConfiguration configuration = this.configuration;\n\n\t\t\tString schedule = getSystemProperty(RollingPolicySystemProperty.CRON, DEFAULT_CRON_EXPRESSION);\n\t\t\treturn CronTriggeringPolicy.createPolicy(configuration, null, schedule);\n\t\t}\n\n\t\tprivate static String getSystemProperty(RollingPolicySystemProperty property, String fallback) {\n\t\t\tString value = System.getProperty(property.getEnvironmentVariableName());\n\t\t\treturn (value != null) ? value : fallback;\n\t\t}\n\n\t\tSpringBootTriggeringPolicyBuilder setConfiguration(Configuration configuration) {\n\t\t\tthis.configuration = configuration;\n\t\t\treturn this;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringEnvironmentLookup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.config.LoggerContextAware;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.lookup.StrLookup;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * Lookup for Spring properties.\n *\n * @author Ralph Goers\n * @author Phillip Webb\n * @author Dmytro Nosan\n */\n@Plugin(name = \"spring\", category = StrLookup.CATEGORY)\nclass SpringEnvironmentLookup implements LoggerContextAware, StrLookup {\n\n\tprivate volatile @Nullable Environment environment;\n\n\t@Override\n\tpublic @Nullable String lookup(LogEvent event, String key) {\n\t\treturn lookup(key);\n\t}\n\n\t@Override\n\tpublic @Nullable String lookup(String key) {\n\t\tEnvironment environment = this.environment;\n\t\tAssert.state(environment != null,\n\t\t\t\t\"Unable to obtain Spring Environment from LoggerContext. \"\n\t\t\t\t\t\t+ \"This can happen if your log4j2 configuration filename does not end with '-spring' \"\n\t\t\t\t\t\t+ \"(for example using 'log4j2.xml' instead of 'log4j2-spring.xml')\");\n\t\treturn environment.getProperty(key);\n\t}\n\n\t@Override\n\tpublic void setLoggerContext(LoggerContext loggerContext) {\n\t\tthis.environment = Log4J2LoggingSystem.getEnvironment(loggerContext);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringEnvironmentPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.util.PropertySource;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\n\n/**\n * Returns properties from Spring.\n *\n * @author Ralph Goers\n */\nclass SpringEnvironmentPropertySource implements PropertySource {\n\n\t/**\n\t * System properties take precedence followed by properties in Log4j properties files.\n\t */\n\tprivate static final int PRIORITY = -100;\n\n\tprivate volatile @Nullable Environment environment;\n\n\t@Override\n\tpublic int getPriority() {\n\t\treturn PRIORITY;\n\t}\n\n\t@Override\n\tpublic @Nullable String getProperty(String key) {\n\t\tEnvironment environment = this.environment;\n\t\treturn (environment != null) ? environment.getProperty(key) : null;\n\t}\n\n\t@Override\n\tpublic boolean containsProperty(String key) {\n\t\tEnvironment environment = this.environment;\n\t\treturn environment != null && environment.containsProperty(key);\n\t}\n\n\tvoid setEnvironment(@Nullable Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/SpringProfileArbiter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.Logger;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.Node;\nimport org.apache.logging.log4j.core.config.arbiters.Arbiter;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;\nimport org.apache.logging.log4j.core.config.plugins.PluginConfiguration;\nimport org.apache.logging.log4j.core.config.plugins.PluginLoggerContext;\nimport org.apache.logging.log4j.status.StatusLogger;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.Profiles;\nimport org.springframework.util.StringUtils;\n\n/**\n * An Arbiter that uses the active Spring profile to determine if configuration should be\n * included.\n *\n * @author Ralph Goers\n */\n@Plugin(name = \"SpringProfile\", category = Node.CATEGORY, elementType = Arbiter.ELEMENT_TYPE, deferChildren = true,\n\t\tprintObject = true)\nfinal class SpringProfileArbiter implements Arbiter {\n\n\tprivate final @Nullable Environment environment;\n\n\tprivate final Profiles profiles;\n\n\tprivate SpringProfileArbiter(@Nullable Environment environment, String[] profiles) {\n\t\tthis.environment = environment;\n\t\tthis.profiles = Profiles.of(profiles);\n\t}\n\n\t@Override\n\tpublic boolean isCondition() {\n\t\treturn (this.environment != null) && this.environment.acceptsProfiles(this.profiles);\n\t}\n\n\t@PluginBuilderFactory\n\tstatic Builder newBuilder() {\n\t\treturn new Builder();\n\t}\n\n\t/**\n\t * Standard Builder to create the Arbiter.\n\t */\n\tstatic final class Builder implements org.apache.logging.log4j.core.util.Builder<SpringProfileArbiter> {\n\n\t\tprivate static final Logger statusLogger = StatusLogger.getLogger();\n\n\t\t@PluginBuilderAttribute\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String name;\n\n\t\t@PluginConfiguration\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate Configuration configuration;\n\n\t\t@PluginLoggerContext\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate LoggerContext loggerContext;\n\n\t\tprivate Builder() {\n\t\t}\n\n\t\t/**\n\t\t * Sets the profile name or expression.\n\t\t * @param name the profile name or expression\n\t\t * @return this\n\t\t * @see Profiles#of(String...)\n\t\t */\n\t\tpublic Builder setName(String name) {\n\t\t\tthis.name = name;\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic SpringProfileArbiter build() {\n\t\t\tEnvironment environment = Log4J2LoggingSystem.getEnvironment(this.loggerContext);\n\t\t\tif (environment == null) {\n\t\t\t\tstatusLogger.debug(\"Creating Arbiter without a Spring Environment\");\n\t\t\t}\n\t\t\tString name = this.configuration.getStrSubstitutor().replace(this.name);\n\t\t\tString[] profiles = trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));\n\t\t\treturn new SpringProfileArbiter(environment, profiles);\n\t\t}\n\n\t\t// The array has no nulls in it, but StringUtils.trimArrayElements return\n\t\t// @Nullable String[]\n\t\t@SuppressWarnings(\"NullAway\")\n\t\tprivate String[] trimArrayElements(String[] array) {\n\t\t\treturn StringUtils.trimArrayElements(array);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/StructuredLogLayout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.logging.log4j.core.Layout;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.config.Node;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;\nimport org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;\nimport org.apache.logging.log4j.core.config.plugins.PluginLoggerContext;\nimport org.apache.logging.log4j.core.layout.AbstractStringLayout;\n\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatterFactory;\nimport org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.boot.util.Instantiator;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Layout Log4j2 Layout} for structured logging.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @see StructuredLogFormatter\n */\n@Plugin(name = \"StructuredLogLayout\", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE)\nfinal class StructuredLogLayout extends AbstractStringLayout {\n\n\tprivate final StructuredLogFormatter<LogEvent> formatter;\n\n\tprivate StructuredLogLayout(Charset charset, StructuredLogFormatter<LogEvent> formatter) {\n\t\tsuper(charset);\n\t\tAssert.notNull(formatter, \"'formatter' must not be null\");\n\t\tthis.formatter = formatter;\n\t}\n\n\t@Override\n\tpublic String toSerializable(LogEvent event) {\n\t\treturn this.formatter.format(event);\n\t}\n\n\t@Override\n\tpublic byte[] toByteArray(LogEvent event) {\n\t\treturn this.formatter.formatAsBytes(event, (getCharset() != null) ? getCharset() : StandardCharsets.UTF_8);\n\t}\n\n\t@PluginBuilderFactory\n\tstatic StructuredLogLayout.Builder newBuilder() {\n\t\treturn new StructuredLogLayout.Builder();\n\t}\n\n\tstatic final class Builder implements org.apache.logging.log4j.core.util.Builder<StructuredLogLayout> {\n\n\t\t@PluginLoggerContext\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate LoggerContext loggerContext;\n\n\t\t@PluginBuilderAttribute\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String format;\n\n\t\t@PluginBuilderAttribute\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String charset = StandardCharsets.UTF_8.name();\n\n\t\tpublic Builder setFormat(String format) {\n\t\t\tthis.format = format;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder setCharset(String charset) {\n\t\t\tthis.charset = charset;\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic StructuredLogLayout build() {\n\t\t\tCharset charset = Charset.forName(this.charset);\n\t\t\tEnvironment environment = Log4J2LoggingSystem.getEnvironment(this.loggerContext);\n\t\t\tAssert.state(environment != null, \"Unable to find Spring Environment in logger context\");\n\t\t\tStructuredLogFormatter<LogEvent> formatter = new StructuredLogFormatterFactory<>(LogEvent.class,\n\t\t\t\t\tenvironment, null, this::addCommonFormatters)\n\t\t\t\t.get(this.format);\n\t\t\treturn new StructuredLogLayout(charset, formatter);\n\t\t}\n\n\t\tprivate void addCommonFormatters(CommonFormatters<LogEvent> commonFormatters) {\n\t\t\tcommonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA, this::createEcsFormatter);\n\t\t\tcommonFormatters.add(CommonStructuredLogFormat.GRAYLOG_EXTENDED_LOG_FORMAT, this::createGraylogFormatter);\n\t\t\tcommonFormatters.add(CommonStructuredLogFormat.LOGSTASH, this::createLogstashFormatter);\n\t\t}\n\n\t\tprivate ElasticCommonSchemaStructuredLogFormatter createEcsFormatter(Instantiator<?> instantiator) {\n\t\t\tEnvironment environment = instantiator.getArg(Environment.class);\n\t\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\t\tContextPairs contextPairs = instantiator.getArg(ContextPairs.class);\n\t\t\tStructuredLoggingJsonMembersCustomizer.Builder<?> jsonMembersCustomizerBuilder = instantiator\n\t\t\t\t.getArg(StructuredLoggingJsonMembersCustomizer.Builder.class);\n\t\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\t\tAssert.state(contextPairs != null, \"'contextPairs' must not be null\");\n\t\t\tAssert.state(jsonMembersCustomizerBuilder != null, \"'jsonMembersCustomizerBuilder' must not be null\");\n\t\t\treturn new ElasticCommonSchemaStructuredLogFormatter(environment, stackTracePrinter, contextPairs,\n\t\t\t\t\tjsonMembersCustomizerBuilder);\n\t\t}\n\n\t\tprivate GraylogExtendedLogFormatStructuredLogFormatter createGraylogFormatter(Instantiator<?> instantiator) {\n\t\t\tEnvironment environment = instantiator.getArg(Environment.class);\n\t\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\t\tContextPairs contextPairs = instantiator.getArg(ContextPairs.class);\n\t\t\tStructuredLoggingJsonMembersCustomizer<?> jsonMembersCustomizer = instantiator\n\t\t\t\t.getArg(StructuredLoggingJsonMembersCustomizer.class);\n\t\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\t\tAssert.state(contextPairs != null, \"'contextPairs' must not be null\");\n\t\t\treturn new GraylogExtendedLogFormatStructuredLogFormatter(environment, stackTracePrinter, contextPairs,\n\t\t\t\t\tjsonMembersCustomizer);\n\t\t}\n\n\t\tprivate LogstashStructuredLogFormatter createLogstashFormatter(Instantiator<?> instantiator) {\n\t\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\t\tContextPairs contextPairs = instantiator.getArg(ContextPairs.class);\n\t\t\tStructuredLoggingJsonMembersCustomizer<?> jsonMembersCustomizer = instantiator\n\t\t\t\t.getArg(StructuredLoggingJsonMembersCustomizer.class);\n\t\t\tAssert.state(contextPairs != null, \"'contextPairs' must not be null\");\n\t\t\treturn new LogstashStructuredLogFormatter(stackTracePrinter, contextPairs, jsonMembersCustomizer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/StructuredMessage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.io.IOException;\n\nimport org.apache.logging.log4j.message.Message;\nimport org.apache.logging.log4j.util.MultiFormatStringBuilderFormattable;\n\nimport org.springframework.boot.json.WritableJson;\n\n/**\n * Helper used to adapt {@link Message} for structured writing.\n *\n * @author Phillip Webb\n */\nfinal class StructuredMessage {\n\n\tprivate static final String JSON2 = \"JSON\";\n\n\tprivate static final String[] JSON = { JSON2 };\n\n\tprivate StructuredMessage() {\n\t}\n\n\tstatic Object get(Message message) {\n\t\tif (message instanceof MultiFormatStringBuilderFormattable multiFormatMessage\n\t\t\t\t&& hasJsonFormat(multiFormatMessage)) {\n\t\t\treturn WritableJson.of((out) -> formatTo(multiFormatMessage, out));\n\t\t}\n\t\treturn message.getFormattedMessage();\n\t}\n\n\tprivate static boolean hasJsonFormat(MultiFormatStringBuilderFormattable message) {\n\t\tfor (String format : message.getFormats()) {\n\t\t\tif (JSON2.equalsIgnoreCase(format)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static void formatTo(MultiFormatStringBuilderFormattable message, Appendable out) throws IOException {\n\t\tif (out instanceof StringBuilder stringBuilder) {\n\t\t\tmessage.formatTo(JSON, stringBuilder);\n\t\t}\n\t\telse {\n\t\t\tout.append(message.getFormattedMessage(JSON));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/WhitespaceThrowablePatternConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.plugins.Plugin;\nimport org.apache.logging.log4j.core.pattern.ConverterKeys;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.apache.logging.log4j.core.pattern.PatternConverter;\nimport org.apache.logging.log4j.core.pattern.ThrowablePatternConverter;\nimport org.apache.logging.log4j.core.pattern.VariablesNotEmptyReplacementConverter;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link ThrowablePatternConverter} that adds some additional whitespace around the stack\n * trace.\n *\n * @author Vladimir Tsanev\n * @since 1.3.0\n */\n@Plugin(name = \"WhitespaceThrowablePatternConverter\", category = PatternConverter.CATEGORY)\n@ConverterKeys({ \"wEx\", \"wThrowable\", \"wException\" })\npublic final class WhitespaceThrowablePatternConverter {\n\n\tprivate WhitespaceThrowablePatternConverter() {\n\t}\n\n\tpublic static LogEventPatternConverter newInstance(Configuration configuration, String @Nullable [] options) {\n\t\tfinal String nested = (options != null && options.length > 0) ? \"{\" + String.join(\"}{\", options) + \"}\" : \"\";\n\t\tfinal String pattern = \"%notEmpty{%n%ex\" + nested + \"%n}\";\n\t\treturn VariablesNotEmptyReplacementConverter.newInstance(configuration, new String[] { pattern });\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for the Log4j 2 logging library.\n */\n@NullMarked\npackage org.springframework.boot.logging.log4j2;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ColorConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.pattern.CompositeConverter;\n\nimport org.springframework.boot.ansi.AnsiBackground;\nimport org.springframework.boot.ansi.AnsiColor;\nimport org.springframework.boot.ansi.AnsiElement;\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiStyle;\n\n/**\n * Logback {@link CompositeConverter} to color output using the {@link AnsiOutput} class.\n * One or more styling options can be provided to the converter, or if not specified color\n * will be picked based on the logging level. Supported options include foreground colors\n * (e.g. {@code red}, {@code bright_blue}), background colors (e.g. {@code bg_red},\n * {@code bg_bright_green}), and text styles (e.g. {@code bold}, {@code underline},\n * {@code reverse}).\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class ColorConverter extends CompositeConverter<ILoggingEvent> {\n\n\tprivate static final Map<String, AnsiElement> ELEMENTS;\n\n\tstatic {\n\t\tMap<String, AnsiElement> ansiElements = new HashMap<>();\n\t\tArrays.stream(AnsiColor.values())\n\t\t\t.filter((color) -> color != AnsiColor.DEFAULT)\n\t\t\t.forEach((color) -> ansiElements.put(color.name().toLowerCase(Locale.ROOT), color));\n\t\tArrays.stream(AnsiStyle.values())\n\t\t\t.forEach((style) -> ansiElements.put(style.name().toLowerCase(Locale.ROOT), style));\n\t\tArrays.stream(AnsiBackground.values())\n\t\t\t.filter((bg) -> bg != AnsiBackground.DEFAULT)\n\t\t\t.forEach((bg) -> ansiElements.put(\"bg_\" + bg.name().toLowerCase(Locale.ROOT), bg));\n\t\tELEMENTS = Collections.unmodifiableMap(ansiElements);\n\t}\n\n\tprivate static final Map<Integer, AnsiElement> LEVELS;\n\n\tstatic {\n\t\tMap<Integer, AnsiElement> ansiLevels = new HashMap<>();\n\t\tansiLevels.put(Level.ERROR_INTEGER, AnsiColor.RED);\n\t\tansiLevels.put(Level.WARN_INTEGER, AnsiColor.YELLOW);\n\t\tLEVELS = Collections.unmodifiableMap(ansiLevels);\n\t}\n\n\t@Override\n\tprotected String transform(ILoggingEvent event, String in) {\n\t\tList<String> options = getOptionList();\n\t\tList<AnsiElement> elements = new ArrayList<>();\n\t\tif (options != null) {\n\t\t\tfor (String option : options) {\n\t\t\t\tString[] optionParts = option.split(\",\");\n\t\t\t\tfor (String optionPart : optionParts) {\n\t\t\t\t\tAnsiElement element = ELEMENTS.get(optionPart.trim().toLowerCase(Locale.ROOT));\n\t\t\t\t\tif (element != null) {\n\t\t\t\t\t\telements.add(element);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (elements.isEmpty()) {\n\t\t\t// Assume highlighting\n\t\t\tAnsiElement element = LEVELS.get(event.getLevel().toInteger());\n\t\t\telements.add((element != null) ? element : AnsiColor.GREEN);\n\t\t}\n\t\treturn toAnsiString(in, elements.toArray(new AnsiElement[0]));\n\t}\n\n\tprotected String toAnsiString(String in, AnsiElement element) {\n\t\treturn AnsiOutput.toString(element, in);\n\t}\n\n\tprotected String toAnsiString(String in, AnsiElement... elements) {\n\t\tObject[] ansiParams = new Object[elements.length + 1];\n\t\tSystem.arraycopy(elements, 0, ansiParams, 0, elements.length);\n\t\tansiParams[elements.length] = in;\n\t\treturn AnsiOutput.toString(ansiParams);\n\t}\n\n\tstatic String getName(AnsiElement element) {\n\t\treturn ELEMENTS.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((entry) -> entry.getValue().equals(element))\n\t\t\t.map(Map.Entry::getKey)\n\t\t\t.findFirst()\n\t\t\t.orElseThrow();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/CorrelationIdConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.Map;\n\nimport ch.qos.logback.classic.pattern.MDCConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.pattern.DynamicConverter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.CorrelationIdFormatter;\nimport org.springframework.core.env.Environment;\n\n/**\n * Logback {@link DynamicConverter} to convert a {@link CorrelationIdFormatter} pattern\n * into formatted output using data from the {@link ILoggingEvent#getMDCPropertyMap() MDC}\n * and {@link Environment}.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see MDCConverter\n */\npublic class CorrelationIdConverter extends DynamicConverter<ILoggingEvent> {\n\n\tprivate @Nullable CorrelationIdFormatter formatter;\n\n\t@Override\n\tpublic void start() {\n\t\tthis.formatter = CorrelationIdFormatter.of(getOptionList());\n\t\tsuper.start();\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.formatter = null;\n\t\tsuper.stop();\n\t}\n\n\t@Override\n\tpublic String convert(ILoggingEvent event) {\n\t\tif (this.formatter == null) {\n\t\t\treturn \"\";\n\t\t}\n\t\tMap<String, String> mdc = event.getMDCPropertyMap();\n\t\treturn this.formatter.format(mdc::get);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/DebugLogbackConfigurator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.function.Supplier;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.Appender;\nimport ch.qos.logback.core.pattern.Converter;\nimport ch.qos.logback.core.spi.LifeCycle;\nimport ch.qos.logback.core.status.InfoStatus;\nimport ch.qos.logback.core.status.Status;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Custom {@link LogbackConfigurator} used to add {@link Status Statuses} when Logback\n * debugging is enabled.\n *\n * @author Andy Wilkinson\n */\nclass DebugLogbackConfigurator extends LogbackConfigurator {\n\n\tDebugLogbackConfigurator(LoggerContext context) {\n\t\tsuper(context);\n\t}\n\n\t@Override\n\t<T extends Converter<?>> void conversionRule(String conversionWord, Class<T> converterClass,\n\t\t\tSupplier<T> converterSupplier) {\n\t\tinfo(\"Adding conversion rule of type '\" + converterClass.getName() + \"' for word '\" + conversionWord + \"'\");\n\t\tsuper.conversionRule(conversionWord, converterClass, converterSupplier);\n\t}\n\n\t@Override\n\tvoid appender(String name, Appender<?> appender) {\n\t\tinfo(\"Adding appender '\" + appender + \"' named '\" + name + \"'\");\n\t\tsuper.appender(name, appender);\n\t}\n\n\t@Override\n\tvoid logger(String name, @Nullable Level level, boolean additive, @Nullable Appender<ILoggingEvent> appender) {\n\t\tinfo(\"Configuring logger '\" + name + \"' with level '\" + level + \"'. Additive: \" + additive);\n\t\tif (appender != null) {\n\t\t\tinfo(\"Adding appender '\" + appender + \"' to logger '\" + name + \"'\");\n\t\t}\n\t\tsuper.logger(name, level, additive, appender);\n\t}\n\n\t@Override\n\tvoid start(LifeCycle lifeCycle) {\n\t\tinfo(\"Starting '\" + lifeCycle + \"'\");\n\t\tsuper.start(lifeCycle);\n\t}\n\n\tprivate void info(String message) {\n\t\tgetContext().getStatusManager().add(new InfoStatus(message, this));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/DefaultLogbackConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.Console;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.encoder.PatternLayoutEncoder;\nimport ch.qos.logback.classic.filter.ThresholdFilter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.Appender;\nimport ch.qos.logback.core.ConsoleAppender;\nimport ch.qos.logback.core.OutputStreamAppender;\nimport ch.qos.logback.core.encoder.Encoder;\nimport ch.qos.logback.core.rolling.RollingFileAppender;\nimport ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;\nimport ch.qos.logback.core.spi.ScanException;\nimport ch.qos.logback.core.util.FileSize;\nimport ch.qos.logback.core.util.OptionHelper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ansi.AnsiColor;\nimport org.springframework.boot.ansi.AnsiElement;\nimport org.springframework.boot.ansi.AnsiStyle;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.util.StringUtils;\n\n/**\n * Default logback configuration used by Spring Boot. Uses {@link LogbackConfigurator} to\n * improve startup time. See also the {@code base.xml}, {@code defaults.xml},\n * {@code console-appender.xml} and {@code file-appender.xml} files provided for classic\n * {@code logback.xml} use.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Vedran Pavic\n * @author Robert Thornton\n * @author Scott Frederick\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass DefaultLogbackConfiguration {\n\n\tprivate static final String DEFAULT_CHARSET = StandardCharsets.UTF_8.name();\n\n\tprivate static final String NAME_AND_GROUP = \"%esb(){APPLICATION_NAME}%esb{APPLICATION_GROUP}\";\n\n\tprivate static final String DATETIME = \"%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}\";\n\n\tprivate static final String DEFAULT_CONSOLE_LOG_PATTERN = faint(DATETIME) + \" \"\n\t\t\t+ colorByLevel(\"${LOG_LEVEL_PATTERN:-%5p}\") + \" \" + magenta(\"${PID:-}\") + \" \"\n\t\t\t+ faint(\"--- \" + NAME_AND_GROUP + \"[%15.15t] ${LOG_CORRELATION_PATTERN:-}\") + cyan(\"%-40.40logger{39}\")\n\t\t\t+ \" \" + faint(\":\") + \" %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\";\n\n\tstatic final String CONSOLE_LOG_PATTERN = \"${CONSOLE_LOG_PATTERN:-\" + DEFAULT_CONSOLE_LOG_PATTERN;\n\n\tprivate static final String DEFAULT_FILE_LOG_PATTERN = DATETIME + \" ${LOG_LEVEL_PATTERN:-%5p} ${PID:-} --- \"\n\t\t\t+ NAME_AND_GROUP + \"[%t] ${LOG_CORRELATION_PATTERN:-}\"\n\t\t\t+ \"%-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\";\n\n\tstatic final String FILE_LOG_PATTERN = \"${FILE_LOG_PATTERN:-\" + DEFAULT_FILE_LOG_PATTERN;\n\n\tprivate final @Nullable LogFile logFile;\n\n\tDefaultLogbackConfiguration(@Nullable LogFile logFile) {\n\t\tthis.logFile = logFile;\n\t}\n\n\tvoid apply(LogbackConfigurator config) {\n\t\tconfig.getConfigurationLock().lock();\n\t\ttry {\n\t\t\tdefaults(config);\n\t\t\tAppender<ILoggingEvent> consoleAppender = consoleAppender(config);\n\t\t\tif (this.logFile != null) {\n\t\t\t\tAppender<ILoggingEvent> fileAppender = fileAppender(config, this.logFile.toString());\n\t\t\t\tconfig.root(Level.INFO, consoleAppender, fileAppender);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconfig.root(Level.INFO, consoleAppender);\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tconfig.getConfigurationLock().unlock();\n\t\t}\n\t}\n\n\tprivate void defaults(LogbackConfigurator config) {\n\t\tconfig.conversionRule(\"clr\", ColorConverter.class, ColorConverter::new);\n\t\tconfig.conversionRule(\"correlationId\", CorrelationIdConverter.class, CorrelationIdConverter::new);\n\t\tconfig.conversionRule(\"esb\", EnclosedInSquareBracketsConverter.class, EnclosedInSquareBracketsConverter::new);\n\t\tconfig.conversionRule(\"wex\", WhitespaceThrowableProxyConverter.class, WhitespaceThrowableProxyConverter::new);\n\t\tconfig.conversionRule(\"wEx\", ExtendedWhitespaceThrowableProxyConverter.class,\n\t\t\t\tExtendedWhitespaceThrowableProxyConverter::new);\n\t\tputProperty(config, \"CONSOLE_LOG_PATTERN\", CONSOLE_LOG_PATTERN);\n\t\tputProperty(config, \"CONSOLE_LOG_CHARSET\", \"${CONSOLE_LOG_CHARSET:-\" + getConsoleCharset() + \"}\");\n\t\tputProperty(config, \"CONSOLE_LOG_THRESHOLD\", \"${CONSOLE_LOG_THRESHOLD:-TRACE}\");\n\t\tputProperty(config, \"CONSOLE_LOG_STRUCTURED_FORMAT\", \"${CONSOLE_LOG_STRUCTURED_FORMAT:-}\");\n\t\tputProperty(config, \"FILE_LOG_PATTERN\", FILE_LOG_PATTERN);\n\t\tputProperty(config, \"FILE_LOG_CHARSET\", \"${FILE_LOG_CHARSET:-\" + DEFAULT_CHARSET + \"}\");\n\t\tputProperty(config, \"FILE_LOG_THRESHOLD\", \"${FILE_LOG_THRESHOLD:-TRACE}\");\n\t\tputProperty(config, \"FILE_LOG_STRUCTURED_FORMAT\", \"${FILE_LOG_STRUCTURED_FORMAT:-}\");\n\t\tconfig.logger(\"org.apache.catalina.startup.DigesterFactory\", Level.ERROR);\n\t\tconfig.logger(\"org.apache.catalina.util.LifecycleBase\", Level.ERROR);\n\t\tconfig.logger(\"org.apache.coyote.http11.Http11NioProtocol\", Level.WARN);\n\t\tconfig.logger(\"org.apache.sshd.common.util.SecurityUtils\", Level.WARN);\n\t\tconfig.logger(\"org.apache.tomcat.util.net.NioSelectorPool\", Level.WARN);\n\t\tconfig.logger(\"org.eclipse.jetty.util.component.AbstractLifeCycle\", Level.ERROR);\n\t\tconfig.logger(\"org.hibernate.validator.internal.util.Version\", Level.WARN);\n\t\tconfig.logger(\"org.springframework.boot.actuate.endpoint.jmx\", Level.WARN);\n\t}\n\n\tprivate String getConsoleCharset() {\n\t\tConsole console = getConsole();\n\t\treturn (console != null) ? console.charset().name() : DEFAULT_CHARSET;\n\t}\n\n\t@Nullable Console getConsole() {\n\t\treturn System.console();\n\t}\n\n\tvoid putProperty(LogbackConfigurator config, String name, String val) {\n\t\tconfig.getContext().putProperty(name, resolve(config, val));\n\t}\n\n\tprivate Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {\n\t\tConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();\n\t\tcreateAppender(config, appender, \"CONSOLE\");\n\t\tconfig.appender(\"CONSOLE\", appender);\n\t\treturn appender;\n\t}\n\n\tprivate Appender<ILoggingEvent> fileAppender(LogbackConfigurator config, String logFile) {\n\t\tRollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();\n\t\tcreateAppender(config, appender, \"FILE\");\n\t\tappender.setFile(logFile);\n\t\tsetRollingPolicy(appender, config);\n\t\tconfig.appender(\"FILE\", appender);\n\t\treturn appender;\n\t}\n\n\tprivate void createAppender(LogbackConfigurator config, OutputStreamAppender<ILoggingEvent> appender, String type) {\n\t\tappender.addFilter(createThresholdFilter(config, type));\n\t\tEncoder<ILoggingEvent> encoder = createEncoder(config, type);\n\t\tappender.setEncoder(encoder);\n\t\tconfig.start(encoder);\n\t}\n\n\tprivate ThresholdFilter createThresholdFilter(LogbackConfigurator config, String type) {\n\t\tThresholdFilter filter = new ThresholdFilter();\n\t\tfilter.setLevel(resolve(config, \"${\" + type + \"_LOG_THRESHOLD}\"));\n\t\tfilter.start();\n\t\treturn filter;\n\t}\n\n\tprivate Encoder<ILoggingEvent> createEncoder(LogbackConfigurator config, String type) {\n\t\tCharset charset = resolveCharset(config, \"${\" + type + \"_LOG_CHARSET}\");\n\t\tString structuredLogFormat = resolve(config, \"${\" + type + \"_LOG_STRUCTURED_FORMAT}\");\n\t\tif (StringUtils.hasLength(structuredLogFormat)) {\n\t\t\tStructuredLogEncoder encoder = createStructuredLogEncoder(structuredLogFormat);\n\t\t\tencoder.setCharset(charset);\n\t\t\treturn encoder;\n\t\t}\n\t\tPatternLayoutEncoder encoder = new PatternLayoutEncoder();\n\t\tencoder.setCharset(charset);\n\t\tencoder.setPattern(resolve(config, \"${\" + type + \"_LOG_PATTERN}\"));\n\t\treturn encoder;\n\t}\n\n\tprivate StructuredLogEncoder createStructuredLogEncoder(String format) {\n\t\tStructuredLogEncoder encoder = new StructuredLogEncoder();\n\t\tencoder.setFormat(format);\n\t\treturn encoder;\n\t}\n\n\tprivate void setRollingPolicy(RollingFileAppender<ILoggingEvent> appender, LogbackConfigurator config) {\n\t\tSizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new SizeAndTimeBasedRollingPolicy<>();\n\t\trollingPolicy.setContext(config.getContext());\n\t\trollingPolicy.setFileNamePattern(\n\t\t\t\tresolve(config, \"${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}\"));\n\t\trollingPolicy\n\t\t\t.setCleanHistoryOnStart(resolveBoolean(config, \"${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}\"));\n\t\trollingPolicy.setMaxFileSize(resolveFileSize(config, \"${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}\"));\n\t\trollingPolicy.setTotalSizeCap(resolveFileSize(config, \"${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}\"));\n\t\trollingPolicy.setMaxHistory(resolveInt(config, \"${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}\"));\n\t\tappender.setRollingPolicy(rollingPolicy);\n\t\trollingPolicy.setParent(appender);\n\t\tconfig.start(rollingPolicy);\n\t}\n\n\tprivate boolean resolveBoolean(LogbackConfigurator config, String val) {\n\t\treturn Boolean.parseBoolean(resolve(config, val));\n\t}\n\n\tprivate int resolveInt(LogbackConfigurator config, String val) {\n\t\treturn Integer.parseInt(resolve(config, val));\n\t}\n\n\tprivate FileSize resolveFileSize(LogbackConfigurator config, String val) {\n\t\treturn FileSize.valueOf(resolve(config, val));\n\t}\n\n\tprivate Charset resolveCharset(LogbackConfigurator config, String val) {\n\t\treturn Charset.forName(resolve(config, val));\n\t}\n\n\tprivate String resolve(LogbackConfigurator config, String val) {\n\t\ttry {\n\t\t\treturn OptionHelper.substVars(val, config.getContext());\n\t\t}\n\t\tcatch (ScanException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate static String faint(String value) {\n\t\treturn color(value, AnsiStyle.FAINT);\n\t}\n\n\tprivate static String cyan(String value) {\n\t\treturn color(value, AnsiColor.CYAN);\n\t}\n\n\tprivate static String magenta(String value) {\n\t\treturn color(value, AnsiColor.MAGENTA);\n\t}\n\n\tprivate static String colorByLevel(String value) {\n\t\treturn \"%clr(\" + value + \"){}\";\n\t}\n\n\tprivate static String color(String value, AnsiElement ansiElement) {\n\t\treturn \"%clr(\" + value + \"){\" + ColorConverter.getName(ansiElement) + \"}\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ElasticCommonSchemaStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.Function;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.IThrowableProxy;\nimport org.jspecify.annotations.Nullable;\nimport org.slf4j.Marker;\nimport org.slf4j.event.KeyValuePair;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.PairExtractor;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.ElasticCommonSchemaProperties;\nimport org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.core.env.Environment;\n\n/**\n * Logback {@link StructuredLogFormatter} for\n * {@link CommonStructuredLogFormat#ELASTIC_COMMON_SCHEMA}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass ElasticCommonSchemaStructuredLogFormatter extends JsonWriterStructuredLogFormatter<ILoggingEvent> {\n\n\tprivate static final PairExtractor<KeyValuePair> keyValuePairExtractor = PairExtractor.of((pair) -> pair.key,\n\t\t\t(pair) -> pair.value);\n\n\tElasticCommonSchemaStructuredLogFormatter(Environment environment, @Nullable StackTracePrinter stackTracePrinter,\n\t\t\tContextPairs contextPairs, ThrowableProxyConverter throwableProxyConverter,\n\t\t\tStructuredLoggingJsonMembersCustomizer.Builder<?> customizerBuilder) {\n\t\tsuper((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, throwableProxyConverter, members),\n\t\t\t\tcustomizerBuilder.nested().build());\n\t}\n\n\tprivate static void jsonMembers(Environment environment, @Nullable StackTracePrinter stackTracePrinter,\n\t\t\tContextPairs contextPairs, ThrowableProxyConverter throwableProxyConverter,\n\t\t\tJsonWriter.Members<ILoggingEvent> members) {\n\t\tExtractor extractor = new Extractor(stackTracePrinter, throwableProxyConverter);\n\t\tmembers.add(\"@timestamp\", ILoggingEvent::getInstant);\n\t\tmembers.add(\"log\").usingMembers((log) -> {\n\t\t\tlog.add(\"level\", ILoggingEvent::getLevel);\n\t\t\tlog.add(\"logger\", ILoggingEvent::getLoggerName);\n\t\t});\n\t\tmembers.add(\"process\").usingMembers((process) -> {\n\t\t\tprocess.add(\"pid\", environment.getProperty(\"spring.application.pid\", Long.class)).whenNotNull();\n\t\t\tprocess.add(\"thread\").usingMembers((thread) -> thread.add(\"name\", ILoggingEvent::getThreadName));\n\t\t});\n\t\tElasticCommonSchemaProperties.get(environment).jsonMembers(members);\n\t\tmembers.add(\"message\", ILoggingEvent::getFormattedMessage);\n\t\tmembers.add().usingPairs(contextPairs.nested((pairs) -> {\n\t\t\tpairs.addMapEntries(ILoggingEvent::getMDCPropertyMap);\n\t\t\tpairs.add(ILoggingEvent::getKeyValuePairs, keyValuePairExtractor);\n\t\t}));\n\t\tFunction<@Nullable ILoggingEvent, @Nullable Object> getThrowableProxy = (event) -> (event != null)\n\t\t\t\t? event.getThrowableProxy() : null;\n\t\tmembers.add().whenNotNull(getThrowableProxy).usingMembers((throwableMembers) -> {\n\t\t\tthrowableMembers.add(\"error\").usingMembers((error) -> {\n\t\t\t\terror.add(\"type\", ILoggingEvent::getThrowableProxy).as(IThrowableProxy::getClassName);\n\t\t\t\terror.add(\"message\", ILoggingEvent::getThrowableProxy).as(IThrowableProxy::getMessage);\n\t\t\t\terror.add(\"stack_trace\", extractor::stackTrace);\n\t\t\t});\n\t\t});\n\t\tmembers.add(\"tags\", ILoggingEvent::getMarkerList)\n\t\t\t.whenNotNull()\n\t\t\t.as(ElasticCommonSchemaStructuredLogFormatter::getMarkers)\n\t\t\t.whenNotEmpty();\n\t\tmembers.add(\"ecs\").usingMembers((ecs) -> ecs.add(\"version\", \"8.11\"));\n\t}\n\n\tprivate static Set<String> getMarkers(List<Marker> markers) {\n\t\tSet<String> result = new TreeSet<>();\n\t\taddMarkers(result, markers.iterator());\n\t\treturn result;\n\t}\n\n\tprivate static void addMarkers(Set<String> result, Iterator<Marker> iterator) {\n\t\twhile (iterator.hasNext()) {\n\t\t\tMarker marker = iterator.next();\n\t\t\tresult.add(marker.getName());\n\t\t\tif (marker.hasReferences()) {\n\t\t\t\taddMarkers(result, marker.iterator());\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/EnclosedInSquareBracketsConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.pattern.CompositeConverter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Logback {@link CompositeConverter} used to help format optional values that should be\n * shown enclosed in square brackets.\n *\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic class EnclosedInSquareBracketsConverter extends CompositeConverter<ILoggingEvent> {\n\n\t@Override\n\tprotected String transform(ILoggingEvent event, @Nullable String in) {\n\t\tin = (!StringUtils.hasLength(in)) ? resolveFromFirstOption(event) : in;\n\t\treturn (!StringUtils.hasLength(in)) ? \"\" : \"[%s] \".formatted(in);\n\t}\n\n\tprivate @Nullable String resolveFromFirstOption(ILoggingEvent event) {\n\t\tString name = getFirstOption();\n\t\tif (name == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString value = event.getLoggerContextVO().getPropertyMap().get(name);\n\t\treturn (value != null) ? value : System.getProperty(name);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/ExtendedWhitespaceThrowableProxyConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.pattern.ExtendedThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.IThrowableProxy;\nimport ch.qos.logback.core.CoreConstants;\n\n/**\n * {@link ExtendedThrowableProxyConverter} that adds some additional whitespace around the\n * stack trace.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class ExtendedWhitespaceThrowableProxyConverter extends ExtendedThrowableProxyConverter {\n\n\t@Override\n\tprotected String throwableProxyToString(IThrowableProxy tp) {\n\t\treturn CoreConstants.LINE_SEPARATOR + super.throwableProxyToString(tp) + CoreConstants.LINE_SEPARATOR;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/Extractor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.IThrowableProxy;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.util.Assert;\n\n/**\n * Functions to extract items from {@link ILoggingEvent}.\n *\n * @author Phillip Webb\n */\nclass Extractor {\n\n\tprivate final @Nullable StackTracePrinter stackTracePrinter;\n\n\tprivate final ThrowableProxyConverter throwableProxyConverter;\n\n\tExtractor(@Nullable StackTracePrinter stackTracePrinter, ThrowableProxyConverter throwableProxyConverter) {\n\t\tthis.stackTracePrinter = stackTracePrinter;\n\t\tthis.throwableProxyConverter = throwableProxyConverter;\n\t}\n\n\tString messageAndStackTrace(ILoggingEvent event) {\n\t\treturn event.getFormattedMessage() + \"\\n\\n\" + stackTrace(event);\n\t}\n\n\tString stackTrace(ILoggingEvent event) {\n\t\tif (this.stackTracePrinter != null) {\n\t\t\tIThrowableProxy throwableProxy = event.getThrowableProxy();\n\t\t\tAssert.state(throwableProxy instanceof ThrowableProxy,\n\t\t\t\t\t\"Instance must be a ThrowableProxy in order to print exception\");\n\t\t\tThrowable throwable = ((ThrowableProxy) throwableProxy).getThrowable();\n\t\t\treturn this.stackTracePrinter.printStackTraceToString(throwable);\n\t\t}\n\t\treturn this.throwableProxyConverter.convert(event);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/GraylogExtendedLogFormatStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.math.BigDecimal;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.regex.Pattern;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.IThrowableProxy;\nimport ch.qos.logback.classic.util.LevelToSyslogSeverity;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.slf4j.event.KeyValuePair;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.json.JsonWriter.PairExtractor;\nimport org.springframework.boot.json.WritableJson;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.ContextPairs.Joiner;\nimport org.springframework.boot.logging.structured.GraylogExtendedLogFormatProperties;\nimport org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.StringUtils;\n\n/**\n * Logback {@link StructuredLogFormatter} for\n * {@link CommonStructuredLogFormat#GRAYLOG_EXTENDED_LOG_FORMAT}. Supports GELF version\n * 1.1.\n *\n * @author Samuel Lissner\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass GraylogExtendedLogFormatStructuredLogFormatter extends JsonWriterStructuredLogFormatter<ILoggingEvent> {\n\n\tprivate static final PairExtractor<KeyValuePair> keyValuePairExtractor = PairExtractor.of((pair) -> pair.key,\n\t\t\t(pair) -> pair.value);\n\n\tprivate static final Log logger = LogFactory.getLog(GraylogExtendedLogFormatStructuredLogFormatter.class);\n\n\t/**\n\t * Allowed characters in field names are any word character (letter, number,\n\t * underscore), dashes and dots.\n\t */\n\tprivate static final Pattern FIELD_NAME_VALID_PATTERN = Pattern.compile(\"^[\\\\w.\\\\-]*$\");\n\n\t/**\n\t * Libraries SHOULD not allow to send id as additional field (\"_id\"). Graylog server\n\t * nodes omit this field automatically.\n\t */\n\tprivate static final Set<String> ADDITIONAL_FIELD_ILLEGAL_KEYS = Set.of(\"id\", \"_id\");\n\n\tGraylogExtendedLogFormatStructuredLogFormatter(Environment environment,\n\t\t\t@Nullable StackTracePrinter stackTracePrinter, ContextPairs contextPairs,\n\t\t\tThrowableProxyConverter throwableProxyConverter,\n\t\t\t@Nullable StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\tsuper((members) -> jsonMembers(environment, stackTracePrinter, contextPairs, throwableProxyConverter, members),\n\t\t\t\tcustomizer);\n\t}\n\n\tprivate static void jsonMembers(Environment environment, @Nullable StackTracePrinter stackTracePrinter,\n\t\t\tContextPairs contextPairs, ThrowableProxyConverter throwableProxyConverter,\n\t\t\tJsonWriter.Members<ILoggingEvent> members) {\n\t\tExtractor extractor = new Extractor(stackTracePrinter, throwableProxyConverter);\n\t\tmembers.add(\"version\", \"1.1\");\n\t\tmembers.add(\"short_message\", ILoggingEvent::getFormattedMessage)\n\t\t\t.as(GraylogExtendedLogFormatStructuredLogFormatter::getMessageText);\n\t\tmembers.add(\"timestamp\", ILoggingEvent::getTimeStamp)\n\t\t\t.as(GraylogExtendedLogFormatStructuredLogFormatter::formatTimeStamp);\n\t\tmembers.add(\"level\", LevelToSyslogSeverity::convert);\n\t\tmembers.add(\"_level_name\", ILoggingEvent::getLevel);\n\t\tmembers.add(\"_process_pid\", environment.getProperty(\"spring.application.pid\", Long.class)).whenNotNull();\n\t\tmembers.add(\"_process_thread_name\", ILoggingEvent::getThreadName);\n\t\tGraylogExtendedLogFormatProperties.get(environment).jsonMembers(members);\n\t\tmembers.add(\"_log_logger\", ILoggingEvent::getLoggerName);\n\t\tmembers.add().usingPairs(contextPairs.flat(additionalFieldJoiner(), (pairs) -> {\n\t\t\tpairs.addMapEntries(ILoggingEvent::getMDCPropertyMap);\n\t\t\tpairs.add(ILoggingEvent::getKeyValuePairs, keyValuePairExtractor);\n\t\t}));\n\t\tFunction<@Nullable ILoggingEvent, @Nullable Object> getThrowableProxy = (event) -> (event != null)\n\t\t\t\t? event.getThrowableProxy() : null;\n\t\tmembers.add()\n\t\t\t.whenNotNull(getThrowableProxy)\n\t\t\t.usingMembers((throwableMembers) -> throwableMembers(throwableMembers, extractor));\n\t}\n\n\tprivate static String getMessageText(String formattedMessage) {\n\t\t// Always return text as a blank message will lead to a error as of Graylog v6\n\t\treturn (!StringUtils.hasText(formattedMessage)) ? \"(blank)\" : formattedMessage;\n\t}\n\n\t/**\n\t * GELF requires \"seconds since UNIX epoch with optional <b>decimal places for\n\t * milliseconds</b>\". To comply with this requirement, we format a POSIX timestamp\n\t * with millisecond precision as e.g. \"1725459730385\" -> \"1725459730.385\"\n\t * @param timeStamp the timestamp of the log message\n\t * @return the timestamp formatted as string with millisecond precision\n\t */\n\tprivate static WritableJson formatTimeStamp(long timeStamp) {\n\t\treturn (out) -> out.append(new BigDecimal(timeStamp).movePointLeft(3).toPlainString());\n\t}\n\n\tprivate static void throwableMembers(Members<ILoggingEvent> members, Extractor extractor) {\n\t\tmembers.add(\"full_message\", extractor::messageAndStackTrace);\n\t\tmembers.add(\"_error_type\", ILoggingEvent::getThrowableProxy).as(IThrowableProxy::getClassName);\n\t\tmembers.add(\"_error_stack_trace\", extractor::stackTrace);\n\t\tmembers.add(\"_error_message\", ILoggingEvent::getThrowableProxy).as(IThrowableProxy::getMessage);\n\t}\n\n\tprivate static Joiner additionalFieldJoiner() {\n\t\treturn (prefix, name) -> {\n\t\t\tname = prefix + name;\n\t\t\tif (!FIELD_NAME_VALID_PATTERN.matcher(name).matches()) {\n\t\t\t\tlogger.warn(LogMessage.format(\"'%s' is not a valid field name according to GELF standard\", name));\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (ADDITIONAL_FIELD_ILLEGAL_KEYS.contains(name)) {\n\t\t\t\tlogger.warn(LogMessage.format(\"'%s' is an illegal field name according to GELF standard\", name));\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn (!name.startsWith(\"_\")) ? \"_\" + name : name;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackConfigurator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.function.Supplier;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.Appender;\nimport ch.qos.logback.core.CoreConstants;\nimport ch.qos.logback.core.pattern.Converter;\nimport ch.qos.logback.core.spi.ContextAware;\nimport ch.qos.logback.core.spi.LifeCycle;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Allows programmatic configuration of logback which is usually faster than parsing XML.\n *\n * @author Phillip Webb\n */\nclass LogbackConfigurator {\n\n\tprivate final LoggerContext context;\n\n\tLogbackConfigurator(LoggerContext context) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tthis.context = context;\n\t}\n\n\tLoggerContext getContext() {\n\t\treturn this.context;\n\t}\n\n\tReentrantLock getConfigurationLock() {\n\t\treturn this.context.getConfigurationLock();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t<T extends Converter<?>> void conversionRule(String conversionWord, Class<T> converterClass,\n\t\t\tSupplier<T> converterSupplier) {\n\t\tAssert.hasLength(conversionWord, \"'conversionWord' must not be empty\");\n\t\tAssert.notNull(converterSupplier, \"'converterSupplier' must not be null\");\n\t\tMap<String, Supplier<?>> registry = (Map<String, Supplier<?>>) this.context\n\t\t\t.getObject(CoreConstants.PATTERN_RULE_REGISTRY_FOR_SUPPLIERS);\n\t\tif (registry == null) {\n\t\t\tregistry = new HashMap<>();\n\t\t\tthis.context.putObject(CoreConstants.PATTERN_RULE_REGISTRY_FOR_SUPPLIERS, registry);\n\t\t}\n\t\tregistry.put(conversionWord, converterSupplier);\n\t}\n\n\tvoid appender(String name, Appender<?> appender) {\n\t\tappender.setName(name);\n\t\tstart(appender);\n\t}\n\n\tvoid logger(String name, @Nullable Level level) {\n\t\tlogger(name, level, true);\n\t}\n\n\tvoid logger(String name, @Nullable Level level, boolean additive) {\n\t\tlogger(name, level, additive, null);\n\t}\n\n\tvoid logger(String name, @Nullable Level level, boolean additive, @Nullable Appender<ILoggingEvent> appender) {\n\t\tLogger logger = this.context.getLogger(name);\n\t\tif (level != null) {\n\t\t\tlogger.setLevel(level);\n\t\t}\n\t\tlogger.setAdditive(additive);\n\t\tif (appender != null) {\n\t\t\tlogger.addAppender(appender);\n\t\t}\n\t}\n\n\t@SafeVarargs\n\tfinal void root(@Nullable Level level, Appender<ILoggingEvent>... appenders) {\n\t\tLogger logger = this.context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);\n\t\tif (level != null) {\n\t\t\tlogger.setLevel(level);\n\t\t}\n\t\tfor (Appender<ILoggingEvent> appender : appenders) {\n\t\t\tlogger.addAppender(appender);\n\t\t}\n\t}\n\n\tvoid start(LifeCycle lifeCycle) {\n\t\tif (lifeCycle instanceof ContextAware contextAware) {\n\t\t\tcontextAware.setContext(this.context);\n\t\t}\n\t\tlifeCycle.start();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.PrintStream;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.logging.ConsoleHandler;\nimport java.util.logging.Handler;\nimport java.util.logging.LogManager;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.joran.JoranConfigurator;\nimport ch.qos.logback.classic.jul.LevelChangePropagator;\nimport ch.qos.logback.classic.spi.TurboFilterList;\nimport ch.qos.logback.classic.turbo.TurboFilter;\nimport ch.qos.logback.core.joran.spi.JoranException;\nimport ch.qos.logback.core.spi.FilterReply;\nimport ch.qos.logback.core.status.Status;\nimport ch.qos.logback.core.status.StatusUtil;\nimport ch.qos.logback.core.util.StatusPrinter2;\nimport org.jspecify.annotations.Nullable;\nimport org.slf4j.ILoggerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.Marker;\nimport org.slf4j.bridge.SLF4JBridgeHandler;\nimport org.slf4j.helpers.SubstituteLoggerFactory;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.logging.AbstractLoggingSystem;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemFactory;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link LoggingSystem} for <a href=\"https://logback.qos.ch\">logback</a>.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Ben Hale\n * @since 1.0.0\n */\npublic class LogbackLoggingSystem extends AbstractLoggingSystem implements BeanFactoryInitializationAotProcessor {\n\n\tprivate static final String BRIDGE_HANDLER = \"org.slf4j.bridge.SLF4JBridgeHandler\";\n\n\tprivate static final String CONFIGURATION_FILE_PROPERTY = \"logback.configurationFile\";\n\n\tprivate static final LogLevels<Level> LEVELS = createLogLevels();\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static LogLevels<Level> createLogLevels() {\n\t\tLogLevels<Level> levels = new LogLevels<>();\n\t\tlevels.map(LogLevel.TRACE, Level.TRACE);\n\t\tlevels.map(LogLevel.TRACE, Level.ALL);\n\t\tlevels.map(LogLevel.DEBUG, Level.DEBUG);\n\t\tlevels.map(LogLevel.INFO, Level.INFO);\n\t\tlevels.map(LogLevel.WARN, Level.WARN);\n\t\tlevels.map(LogLevel.ERROR, Level.ERROR);\n\t\tlevels.map(LogLevel.FATAL, Level.ERROR);\n\t\tlevels.map(LogLevel.OFF, Level.OFF);\n\t\treturn levels;\n\t}\n\n\tprivate static final TurboFilter SUPPRESS_ALL_FILTER = new TurboFilter() {\n\n\t\t@Override\n\t\tpublic FilterReply decide(Marker marker, ch.qos.logback.classic.Logger logger, Level level, String format,\n\t\t\t\tObject[] params, Throwable t) {\n\t\t\treturn FilterReply.DENY;\n\t\t}\n\n\t};\n\n\tprivate final StatusPrinter2 statusPrinter = new StatusPrinter2();\n\n\tpublic LogbackLoggingSystem(ClassLoader classLoader) {\n\t\tsuper(classLoader);\n\t}\n\n\t@Override\n\tpublic LoggingSystemProperties getSystemProperties(ConfigurableEnvironment environment) {\n\t\treturn new LogbackLoggingSystemProperties(environment, getDefaultValueResolver(environment), null);\n\t}\n\n\t@Override\n\tprotected String[] getStandardConfigLocations() {\n\t\treturn new String[] { \"logback-test.groovy\", \"logback-test.xml\", \"logback.groovy\", \"logback.xml\" };\n\t}\n\n\t@Override\n\tpublic void beforeInitialize() {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tif (isAlreadyInitialized(loggerContext)) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.beforeInitialize();\n\t\tconfigureJdkLoggingBridgeHandler();\n\t\tloggerContext.getTurboFilterList().add(SUPPRESS_ALL_FILTER);\n\t}\n\n\tprivate void configureJdkLoggingBridgeHandler() {\n\t\ttry {\n\t\t\tif (isBridgeJulIntoSlf4j()) {\n\t\t\t\tremoveJdkLoggingBridgeHandler();\n\t\t\t\tSLF4JBridgeHandler.install();\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Ignore. No java.util.logging bridge is installed.\n\t\t}\n\t}\n\n\tprivate boolean isBridgeJulIntoSlf4j() {\n\t\treturn isBridgeHandlerAvailable() && isJulUsingASingleConsoleHandlerAtMost();\n\t}\n\n\tprivate boolean isBridgeHandlerAvailable() {\n\t\treturn ClassUtils.isPresent(BRIDGE_HANDLER, getClassLoader());\n\t}\n\n\tprivate boolean isJulUsingASingleConsoleHandlerAtMost() {\n\t\tjava.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger(\"\");\n\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\treturn handlers.length == 0 || (handlers.length == 1 && handlers[0] instanceof ConsoleHandler);\n\t}\n\n\tprivate void removeJdkLoggingBridgeHandler() {\n\t\ttry {\n\t\t\tremoveDefaultRootHandler();\n\t\t\tSLF4JBridgeHandler.uninstall();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Ignore and continue\n\t\t}\n\t}\n\n\tprivate void removeDefaultRootHandler() {\n\t\ttry {\n\t\t\tjava.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger(\"\");\n\t\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\t\tif (handlers.length == 1 && handlers[0] instanceof ConsoleHandler) {\n\t\t\t\trootLogger.removeHandler(handlers[0]);\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Ignore and continue\n\t\t}\n\t}\n\n\t@Override\n\tpublic void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation,\n\t\t\t@Nullable LogFile logFile) {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tputInitializationContextObjects(loggerContext, initializationContext);\n\t\tif (isAlreadyInitialized(loggerContext)) {\n\t\t\treturn;\n\t\t}\n\t\tif (!initializeFromAotGeneratedArtifactsIfPossible(initializationContext, logFile)) {\n\t\t\tsuper.initialize(initializationContext, configLocation, logFile);\n\t\t}\n\t\tloggerContext.getTurboFilterList().remove(SUPPRESS_ALL_FILTER);\n\t\tmarkAsInitialized(loggerContext);\n\t\tif (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) {\n\t\t\tgetLogger(LogbackLoggingSystem.class.getName()).warn(\"Ignoring '\" + CONFIGURATION_FILE_PROPERTY\n\t\t\t\t\t+ \"' system property. Please use 'logging.config' instead.\");\n\t\t}\n\t}\n\n\tprivate boolean initializeFromAotGeneratedArtifactsIfPossible(LoggingInitializationContext initializationContext,\n\t\t\t@Nullable LogFile logFile) {\n\t\tif (!AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (initializationContext != null) {\n\t\t\tEnvironment environment = initializationContext.getEnvironment();\n\t\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\t\tapplySystemProperties(environment, logFile);\n\t\t}\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tstopAndReset(loggerContext);\n\t\twithLoggingSuppressed(() -> putInitializationContextObjects(loggerContext, initializationContext));\n\t\tSystemStatusListener.addTo(loggerContext);\n\t\tSpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);\n\t\tconfigurator.setContext(loggerContext);\n\t\tboolean configuredUsingAotGeneratedArtifacts = configurator.configureUsingAotGeneratedArtifacts();\n\t\tif (configuredUsingAotGeneratedArtifacts) {\n\t\t\treportConfigurationErrorsIfNecessary(loggerContext);\n\t\t}\n\t\treturn configuredUsingAotGeneratedArtifacts;\n\t}\n\n\t@Override\n\tprotected void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile) {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tstopAndReset(loggerContext);\n\t\twithLoggingSuppressed(() -> {\n\t\t\tboolean debug = Boolean.getBoolean(\"logback.debug\");\n\t\t\tputInitializationContextObjects(loggerContext, initializationContext);\n\t\t\tSystemStatusListener.addTo(loggerContext, debug);\n\t\t\tEnvironment environment = initializationContext.getEnvironment();\n\t\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\t\t// Apply system properties directly in case the same JVM runs multiple apps\n\t\t\tnew LogbackLoggingSystemProperties(environment, getDefaultValueResolver(environment),\n\t\t\t\t\tloggerContext::putProperty)\n\t\t\t\t.apply(logFile);\n\t\t\tLogbackConfigurator configurator = (!debug) ? new LogbackConfigurator(loggerContext)\n\t\t\t\t\t: new DebugLogbackConfigurator(loggerContext);\n\t\t\tnew DefaultLogbackConfiguration(logFile).apply(configurator);\n\t\t\tloggerContext.setPackagingDataEnabled(true);\n\t\t\tloggerContext.start();\n\t\t});\n\t}\n\n\t@Override\n\tprotected void loadConfiguration(LoggingInitializationContext initializationContext, String location,\n\t\t\t@Nullable LogFile logFile) {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tstopAndReset(loggerContext);\n\t\twithLoggingSuppressed(() -> {\n\t\t\tputInitializationContextObjects(loggerContext, initializationContext);\n\t\t\tif (initializationContext != null) {\n\t\t\t\tEnvironment environment = initializationContext.getEnvironment();\n\t\t\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\t\t\tapplySystemProperties(environment, logFile);\n\t\t\t}\n\t\t\tSystemStatusListener.addTo(loggerContext);\n\t\t\ttry {\n\t\t\t\tResource resource = ApplicationResourceLoader.get().getResource(location);\n\t\t\t\tconfigureByResourceUrl(initializationContext, loggerContext, resource.getURL());\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(\"Could not initialize Logback logging from \" + location, ex);\n\t\t\t}\n\t\t\tloggerContext.start();\n\t\t});\n\t\treportConfigurationErrorsIfNecessary(loggerContext);\n\t}\n\n\tprivate void reportConfigurationErrorsIfNecessary(LoggerContext loggerContext) {\n\t\tStringBuilder errors = new StringBuilder();\n\t\tList<Throwable> suppressedExceptions = new ArrayList<>();\n\t\tfor (Status status : loggerContext.getStatusManager().getCopyOfStatusList()) {\n\t\t\tif (status.getLevel() == Status.ERROR) {\n\t\t\t\terrors.append((!errors.isEmpty()) ? String.format(\"%n\") : \"\");\n\t\t\t\terrors.append(status);\n\t\t\t\tif (status.getThrowable() != null) {\n\t\t\t\t\tsuppressedExceptions.add(status.getThrowable());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (errors.isEmpty()) {\n\t\t\tif (!StatusUtil.contextHasStatusListener(loggerContext)) {\n\t\t\t\tthis.statusPrinter.printInCaseOfErrorsOrWarnings(loggerContext);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tIllegalStateException ex = new IllegalStateException(\n\t\t\t\tString.format(\"Logback configuration error detected: %n%s\", errors));\n\t\tsuppressedExceptions.forEach(ex::addSuppressed);\n\t\tthrow ex;\n\t}\n\n\tprivate void configureByResourceUrl(LoggingInitializationContext initializationContext, LoggerContext loggerContext,\n\t\t\tURL url) throws JoranException {\n\t\tJoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);\n\t\tconfigurator.setContext(loggerContext);\n\t\tconfigurator.doConfigure(url);\n\t}\n\n\tprivate void stopAndReset(LoggerContext loggerContext) {\n\t\tloggerContext.stop();\n\t\tloggerContext.reset();\n\t\tif (isBridgeHandlerInstalled()) {\n\t\t\taddLevelChangePropagator(loggerContext);\n\t\t}\n\t}\n\n\tprivate boolean isBridgeHandlerInstalled() {\n\t\tif (!isBridgeHandlerAvailable()) {\n\t\t\treturn false;\n\t\t}\n\t\tjava.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger(\"\");\n\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\treturn handlers.length == 1 && handlers[0] instanceof SLF4JBridgeHandler;\n\t}\n\n\tprivate void addLevelChangePropagator(LoggerContext loggerContext) {\n\t\tLevelChangePropagator levelChangePropagator = new LevelChangePropagator();\n\t\tlevelChangePropagator.setResetJUL(true);\n\t\tlevelChangePropagator.setContext(loggerContext);\n\t\tloggerContext.addListener(levelChangePropagator);\n\t}\n\n\t@Override\n\tpublic void cleanUp() {\n\t\tLoggerContext context = getLoggerContext();\n\t\tmarkAsUninitialized(context);\n\t\tsuper.cleanUp();\n\t\tif (isBridgeHandlerAvailable()) {\n\t\t\tremoveJdkLoggingBridgeHandler();\n\t\t}\n\t\tcontext.getStatusManager().clear();\n\t\tcontext.getTurboFilterList().remove(SUPPRESS_ALL_FILTER);\n\t}\n\n\t@Override\n\tprotected void reinitialize(LoggingInitializationContext initializationContext) {\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\tloggerContext.reset();\n\t\tloggerContext.getStatusManager().clear();\n\t\tString location = getSelfInitializationConfig();\n\t\tAssert.state(location != null, \"location must not be null\");\n\t\tloadConfiguration(initializationContext, location, null);\n\t}\n\n\tprivate void putInitializationContextObjects(LoggerContext loggerContext,\n\t\t\tLoggingInitializationContext initializationContext) {\n\t\twithLoggingSuppressed(\n\t\t\t\t() -> loggerContext.putObject(Environment.class.getName(), initializationContext.getEnvironment()));\n\t}\n\n\t@Override\n\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\tList<LoggerConfiguration> result = new ArrayList<>();\n\t\tfor (ch.qos.logback.classic.Logger logger : getLoggerContext().getLoggerList()) {\n\t\t\tresult.add(getLoggerConfiguration(logger));\n\t\t}\n\t\tresult.sort(CONFIGURATION_COMPARATOR);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\tString name = getLoggerName(loggerName);\n\t\tLoggerContext loggerContext = getLoggerContext();\n\t\treturn getLoggerConfiguration(loggerContext.exists(name));\n\t}\n\n\tprivate String getLoggerName(@Nullable String name) {\n\t\tif (!StringUtils.hasLength(name) || Logger.ROOT_LOGGER_NAME.equals(name)) {\n\t\t\treturn ROOT_LOGGER_NAME;\n\t\t}\n\t\treturn name;\n\t}\n\n\tprivate @Nullable LoggerConfiguration getLoggerConfiguration(ch.qos.logback.classic.@Nullable Logger logger) {\n\t\tif (logger == null) {\n\t\t\treturn null;\n\t\t}\n\t\tLogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());\n\t\tLogLevel effectiveLevel = LEVELS.convertNativeToSystem(logger.getEffectiveLevel());\n\t\tString name = getLoggerName(logger.getName());\n\t\tAssert.state(effectiveLevel != null, \"effectiveLevel must not be null\");\n\t\treturn new LoggerConfiguration(name, level, effectiveLevel);\n\t}\n\n\t@Override\n\tpublic Set<LogLevel> getSupportedLogLevels() {\n\t\treturn LEVELS.getSupported();\n\t}\n\n\t@Override\n\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\tch.qos.logback.classic.Logger logger = getLogger(loggerName);\n\t\tif (logger != null) {\n\t\t\tlogger.setLevel(LEVELS.convertSystemToNative(level));\n\t\t}\n\t}\n\n\t@Override\n\tpublic Runnable getShutdownHandler() {\n\t\treturn () -> getLoggerContext().stop();\n\t}\n\n\tprivate ch.qos.logback.classic.Logger getLogger(@Nullable String name) {\n\t\tLoggerContext factory = getLoggerContext();\n\t\treturn factory.getLogger(getLoggerName(name));\n\t}\n\n\tprivate LoggerContext getLoggerContext() {\n\t\tILoggerFactory factory = getLoggerFactory();\n\t\tAssert.state(factory instanceof LoggerContext,\n\t\t\t\t() -> String.format(\n\t\t\t\t\t\t\"LoggerFactory is not a Logback LoggerContext but Logback is on \"\n\t\t\t\t\t\t\t\t+ \"the classpath. Either remove Logback or the competing \"\n\t\t\t\t\t\t\t\t+ \"implementation (%s loaded from %s). If you are using \"\n\t\t\t\t\t\t\t\t+ \"WebLogic you will need to add 'org.slf4j' to \"\n\t\t\t\t\t\t\t\t+ \"prefer-application-packages in WEB-INF/weblogic.xml\",\n\t\t\t\t\t\tfactory.getClass(), getLocation(factory)));\n\t\treturn (LoggerContext) factory;\n\t}\n\n\tprivate ILoggerFactory getLoggerFactory() {\n\t\tILoggerFactory factory = LoggerFactory.getILoggerFactory();\n\t\twhile (factory instanceof SubstituteLoggerFactory) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(50);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tthrow new IllegalStateException(\"Interrupted while waiting for non-substitute logger factory\", ex);\n\t\t\t}\n\t\t\tfactory = LoggerFactory.getILoggerFactory();\n\t\t}\n\t\treturn factory;\n\t}\n\n\tprivate Object getLocation(ILoggerFactory factory) {\n\t\ttry {\n\t\t\tProtectionDomain protectionDomain = factory.getClass().getProtectionDomain();\n\t\t\tCodeSource codeSource = protectionDomain.getCodeSource();\n\t\t\tif (codeSource != null) {\n\t\t\t\treturn codeSource.getLocation();\n\t\t\t}\n\t\t}\n\t\tcatch (SecurityException ex) {\n\t\t\t// Unable to determine location\n\t\t}\n\t\treturn \"unknown location\";\n\t}\n\n\tprivate boolean isAlreadyInitialized(LoggerContext loggerContext) {\n\t\treturn loggerContext.getObject(LoggingSystem.class.getName()) != null;\n\t}\n\n\tprivate void markAsInitialized(LoggerContext loggerContext) {\n\t\tloggerContext.putObject(LoggingSystem.class.getName(), new Object());\n\t}\n\n\tprivate void markAsUninitialized(LoggerContext loggerContext) {\n\t\tloggerContext.removeObject(LoggingSystem.class.getName());\n\t}\n\n\t@Override\n\tprotected String getDefaultLogCorrelationPattern() {\n\t\treturn \"%correlationId\";\n\t}\n\n\t@Override\n\tpublic BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {\n\t\tString key = BeanFactoryInitializationAotContribution.class.getName();\n\t\tLoggerContext context = getLoggerContext();\n\t\tBeanFactoryInitializationAotContribution contribution = (BeanFactoryInitializationAotContribution) context\n\t\t\t.getObject(key);\n\t\tcontext.removeObject(key);\n\t\treturn contribution;\n\t}\n\n\tprivate void withLoggingSuppressed(Runnable action) {\n\t\tTurboFilterList turboFilters = getLoggerContext().getTurboFilterList();\n\t\tturboFilters.add(SUPPRESS_ALL_FILTER);\n\t\ttry {\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tturboFilters.remove(SUPPRESS_ALL_FILTER);\n\t\t}\n\t}\n\n\tvoid setStatusPrinterStream(PrintStream stream) {\n\t\tthis.statusPrinter.setPrintStream(stream);\n\t}\n\n\t/**\n\t * {@link LoggingSystemFactory} that returns {@link LogbackLoggingSystem} if possible.\n\t */\n\t@Order(Ordered.HIGHEST_PRECEDENCE + 1024)\n\tpublic static class Factory implements LoggingSystemFactory {\n\n\t\tprivate static final boolean PRESENT = ClassUtils.isPresent(\"ch.qos.logback.classic.LoggerContext\",\n\t\t\t\tFactory.class.getClassLoader());\n\n\t\t@Override\n\t\tpublic @Nullable LoggingSystem getLoggingSystem(ClassLoader classLoader) {\n\t\t\tif (PRESENT) {\n\t\t\t\treturn new LogbackLoggingSystem(classLoader);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystemProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.Console;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport ch.qos.logback.core.util.FileSize;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link LoggingSystemProperties} for Logback.\n *\n * @author Phillip Webb\n * @since 2.4.0\n * @see RollingPolicySystemProperty\n */\npublic class LogbackLoggingSystemProperties extends LoggingSystemProperties {\n\n\tprivate static final boolean JBOSS_LOGGING_PRESENT = ClassUtils.isPresent(\"org.jboss.logging.Logger\",\n\t\t\tLogbackLoggingSystemProperties.class.getClassLoader());\n\n\tpublic LogbackLoggingSystemProperties(Environment environment) {\n\t\tsuper(environment);\n\t}\n\n\t/**\n\t * Create a new {@link LogbackLoggingSystemProperties} instance.\n\t * @param environment the source environment\n\t * @param setter setter used to apply the property\n\t * @since 2.4.3\n\t */\n\tpublic LogbackLoggingSystemProperties(Environment environment,\n\t\t\t@Nullable BiConsumer<String, @Nullable String> setter) {\n\t\tsuper(environment, setter);\n\t}\n\n\t/**\n\t * Create a new {@link LoggingSystemProperties} instance.\n\t * @param environment the source environment\n\t * @param defaultValueResolver function used to resolve default values or {@code null}\n\t * @param setter setter used to apply the property or {@code null} for system\n\t * properties\n\t * @since 3.2.0\n\t */\n\tpublic LogbackLoggingSystemProperties(Environment environment,\n\t\t\t@Nullable Function<@Nullable String, @Nullable String> defaultValueResolver,\n\t\t\t@Nullable BiConsumer<String, @Nullable String> setter) {\n\t\tsuper(environment, defaultValueResolver, setter);\n\t}\n\n\t@Override\n\tprotected @Nullable Console getConsole() {\n\t\treturn super.getConsole();\n\t}\n\n\t@Override\n\tprotected void apply(@Nullable LogFile logFile, PropertyResolver resolver) {\n\t\tsuper.apply(logFile, resolver);\n\t\tapplyJBossLoggingProperties();\n\t\tapplyRollingPolicyProperties(resolver);\n\t}\n\n\tprivate void applyJBossLoggingProperties() {\n\t\tif (JBOSS_LOGGING_PRESENT) {\n\t\t\tsetSystemProperty(\"org.jboss.logging.provider\", \"slf4j\");\n\t\t}\n\t}\n\n\tprivate void applyRollingPolicyProperties(PropertyResolver resolver) {\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.FILE_NAME_PATTERN, resolver);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.CLEAN_HISTORY_ON_START, resolver);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.MAX_FILE_SIZE, resolver, DataSize.class);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.TOTAL_SIZE_CAP, resolver, DataSize.class);\n\t\tapplyRollingPolicy(RollingPolicySystemProperty.MAX_HISTORY, resolver);\n\t}\n\n\tprivate void applyRollingPolicy(RollingPolicySystemProperty property, PropertyResolver resolver) {\n\t\tapplyRollingPolicy(property, resolver, String.class);\n\t}\n\n\tprivate <T> void applyRollingPolicy(RollingPolicySystemProperty property, PropertyResolver resolver,\n\t\t\tClass<T> type) {\n\t\tT value = getProperty(resolver, property.getApplicationPropertyName(), type);\n\t\tif (value != null) {\n\t\t\tString stringValue = String.valueOf((value instanceof DataSize dataSize) ? dataSize.toBytes() : value);\n\t\t\tsetSystemProperty(property.getEnvironmentVariableName(), stringValue);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T getProperty(PropertyResolver resolver, String key, Class<T> type) {\n\t\ttry {\n\t\t\treturn resolver.getProperty(key, type);\n\t\t}\n\t\tcatch (ConversionFailedException | ConverterNotFoundException ex) {\n\t\t\tif (type != DataSize.class) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tString value = resolver.getProperty(key);\n\t\t\treturn (T) DataSize.ofBytes(FileSize.valueOf(value).getSize());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.pattern.SyslogStartConverter;\nimport ch.qos.logback.core.rolling.helper.DateTokenConverter;\nimport ch.qos.logback.core.rolling.helper.IntegerTokenConverter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link RuntimeHintsRegistrar} for Logback.\n *\n * @author Andy Wilkinson\n */\nclass LogbackRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tif (!ClassUtils.isPresent(\"ch.qos.logback.classic.LoggerContext\", classLoader)) {\n\t\t\treturn;\n\t\t}\n\t\tReflectionHints reflection = hints.reflection();\n\t\tregisterHintsForLogbackLoggingSystemTypeChecks(reflection, classLoader);\n\t\tregisterHintsForBuiltInLogbackConverters(reflection);\n\t\tregisterHintsForSpringBootConverters(reflection);\n\t}\n\n\tprivate void registerHintsForLogbackLoggingSystemTypeChecks(ReflectionHints reflection,\n\t\t\t@Nullable ClassLoader classLoader) {\n\t\treflection.registerType(LoggerContext.class);\n\t\treflection.registerTypeIfPresent(classLoader, \"org.slf4j.bridge.SLF4JBridgeHandler\", (typeHint) -> {\n\t\t});\n\t}\n\n\tprivate void registerHintsForBuiltInLogbackConverters(ReflectionHints reflection) {\n\t\tregisterForPublicConstructorInvocation(reflection, DateTokenConverter.class, IntegerTokenConverter.class,\n\t\t\t\tSyslogStartConverter.class);\n\t}\n\n\tprivate void registerHintsForSpringBootConverters(ReflectionHints reflection) {\n\t\tregisterForPublicConstructorInvocation(reflection, ColorConverter.class,\n\t\t\t\tEnclosedInSquareBracketsConverter.class, ExtendedWhitespaceThrowableProxyConverter.class,\n\t\t\t\tWhitespaceThrowableProxyConverter.class, CorrelationIdConverter.class);\n\t}\n\n\tprivate void registerForPublicConstructorInvocation(ReflectionHints reflection, Class<?>... classes) {\n\t\treflection.registerTypes(TypeReference.listOf(classes),\n\t\t\t\t(hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogstashStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport org.jspecify.annotations.Nullable;\nimport org.slf4j.Marker;\nimport org.slf4j.event.KeyValuePair;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.PairExtractor;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.JsonWriterStructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\n\n/**\n * Logback {@link StructuredLogFormatter} for {@link CommonStructuredLogFormat#LOGSTASH}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass LogstashStructuredLogFormatter extends JsonWriterStructuredLogFormatter<ILoggingEvent> {\n\n\tprivate static final PairExtractor<KeyValuePair> keyValuePairExtractor = PairExtractor.of((pair) -> pair.key,\n\t\t\t(pair) -> pair.value);\n\n\tLogstashStructuredLogFormatter(@Nullable StackTracePrinter stackTracePrinter, ContextPairs contextPairs,\n\t\t\tThrowableProxyConverter throwableProxyConverter,\n\t\t\t@Nullable StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\tsuper((members) -> jsonMembers(stackTracePrinter, contextPairs, throwableProxyConverter, members), customizer);\n\t}\n\n\tprivate static void jsonMembers(@Nullable StackTracePrinter stackTracePrinter, ContextPairs contextPairs,\n\t\t\tThrowableProxyConverter throwableProxyConverter, JsonWriter.Members<ILoggingEvent> members) {\n\t\tExtractor extractor = new Extractor(stackTracePrinter, throwableProxyConverter);\n\t\tmembers.add(\"@timestamp\", ILoggingEvent::getInstant).as(LogstashStructuredLogFormatter::asTimestamp);\n\t\tmembers.add(\"@version\", \"1\");\n\t\tmembers.add(\"message\", ILoggingEvent::getFormattedMessage);\n\t\tmembers.add(\"logger_name\", ILoggingEvent::getLoggerName);\n\t\tmembers.add(\"thread_name\", ILoggingEvent::getThreadName);\n\t\tmembers.add(\"level\", ILoggingEvent::getLevel);\n\t\tmembers.add(\"level_value\", ILoggingEvent::getLevel).as(Level::toInt);\n\t\tmembers.add().usingPairs(contextPairs.flat(\"_\", (pairs) -> {\n\t\t\tpairs.addMapEntries(ILoggingEvent::getMDCPropertyMap);\n\t\t\tpairs.add(ILoggingEvent::getKeyValuePairs, keyValuePairExtractor);\n\t\t}));\n\t\tmembers.add(\"tags\", ILoggingEvent::getMarkerList)\n\t\t\t.whenNotNull()\n\t\t\t.as(LogstashStructuredLogFormatter::getMarkers)\n\t\t\t.whenNotEmpty();\n\t\tFunction<@Nullable ILoggingEvent, @Nullable Object> getThrowableProxy = (event) -> (event != null)\n\t\t\t\t? event.getThrowableProxy() : null;\n\t\tmembers.add(\"stack_trace\", (event) -> event).whenNotNull(getThrowableProxy).as(extractor::stackTrace);\n\t}\n\n\tprivate static String asTimestamp(Instant instant) {\n\t\tOffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(instant, ZoneId.systemDefault());\n\t\treturn DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime);\n\t}\n\n\tprivate static Set<String> getMarkers(List<Marker> markers) {\n\t\tSet<String> result = new LinkedHashSet<>();\n\t\taddMarkers(result, markers.iterator());\n\t\treturn result;\n\t}\n\n\tprivate static void addMarkers(Set<String> result, Iterator<Marker> iterator) {\n\t\twhile (iterator.hasNext()) {\n\t\t\tMarker marker = iterator.next();\n\t\t\tresult.add(marker.getName());\n\t\t\tif (marker.hasReferences()) {\n\t\t\t\taddMarkers(result, marker.iterator());\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/RollingPolicySystemProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\n/**\n * Logback rolling policy system properties that can later be used by log configuration\n * files.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see LogbackLoggingSystemProperties\n */\npublic enum RollingPolicySystemProperty {\n\n\t/**\n\t * Logging system property for the rolled-over log file name pattern.\n\t */\n\tFILE_NAME_PATTERN(\"file-name-pattern\"),\n\n\t/**\n\t * Logging system property for the clean history on start flag.\n\t */\n\tCLEAN_HISTORY_ON_START(\"clean-history-on-start\"),\n\n\t/**\n\t * Logging system property for the file log max size.\n\t */\n\tMAX_FILE_SIZE(\"max-file-size\"),\n\n\t/**\n\t * Logging system property for the file total size cap.\n\t */\n\tTOTAL_SIZE_CAP(\"total-size-cap\"),\n\n\t/**\n\t * Logging system property for the file log max history.\n\t */\n\tMAX_HISTORY(\"max-history\");\n\n\tprivate final String environmentVariableName;\n\n\tprivate final String applicationPropertyName;\n\n\tRollingPolicySystemProperty(String applicationPropertyName) {\n\t\tthis.environmentVariableName = \"LOGBACK_ROLLINGPOLICY_\" + name();\n\t\tthis.applicationPropertyName = \"logging.logback.rollingpolicy.\" + applicationPropertyName;\n\t}\n\n\t/**\n\t * Return the name of environment variable that can be used to access this property.\n\t * @return the environment variable name\n\t */\n\tpublic String getEnvironmentVariableName() {\n\t\treturn this.environmentVariableName;\n\t}\n\n\tString getApplicationPropertyName() {\n\t\treturn this.applicationPropertyName;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/RootLogLevelConfigurator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.Configurator;\nimport ch.qos.logback.core.spi.ContextAwareBase;\nimport org.slf4j.Logger;\n\n/**\n * Logback {@link Configurator}, registered through {@code META-INF/services}, that sets\n * the root log level to {@link Level#INFO}.\n *\n * @author Andy Wilkinson\n * @since 3.1.0\n */\npublic class RootLogLevelConfigurator extends ContextAwareBase implements Configurator {\n\n\t@Override\n\tpublic ExecutionStatus configure(LoggerContext loggerContext) {\n\t\tloggerContext.getLogger(Logger.ROOT_LOGGER_NAME).setLevel(Level.INFO);\n\t\treturn ExecutionStatus.INVOKE_NEXT_IF_ANY;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringBootJoranConfigurator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.Serializable;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport ch.qos.logback.classic.joran.JoranConfigurator;\nimport ch.qos.logback.core.Context;\nimport ch.qos.logback.core.CoreConstants;\nimport ch.qos.logback.core.joran.spi.ElementSelector;\nimport ch.qos.logback.core.joran.spi.RuleStore;\nimport ch.qos.logback.core.joran.util.PropertySetter;\nimport ch.qos.logback.core.joran.util.beans.BeanDescription;\nimport ch.qos.logback.core.model.ComponentModel;\nimport ch.qos.logback.core.model.IncludeModel;\nimport ch.qos.logback.core.model.Model;\nimport ch.qos.logback.core.model.ModelUtil;\nimport ch.qos.logback.core.model.processor.DefaultProcessor;\nimport ch.qos.logback.core.model.processor.ModelInterpretationContext;\nimport ch.qos.logback.core.spi.ContextAware;\nimport ch.qos.logback.core.spi.ContextAwareBase;\nimport ch.qos.logback.core.util.AggregationType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GeneratedFiles.FileHandler;\nimport org.springframework.aot.generate.GeneratedFiles.Kind;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.core.NativeDetector;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.function.SingletonSupplier;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * Extended version of the Logback {@link JoranConfigurator} that adds additional Spring\n * Boot rules.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass SpringBootJoranConfigurator extends JoranConfigurator {\n\n\tprivate final LoggingInitializationContext initializationContext;\n\n\tSpringBootJoranConfigurator(LoggingInitializationContext initializationContext) {\n\t\tthis.initializationContext = initializationContext;\n\t}\n\n\t@Override\n\tprotected void sanityCheck(Model topModel) {\n\t\tsuper.sanityCheck(topModel);\n\t\tperformCheck(new SpringProfileIfNestedWithinSecondPhaseElementSanityChecker(), topModel);\n\t}\n\n\t@Override\n\tprotected void addModelHandlerAssociations(DefaultProcessor defaultProcessor) {\n\t\tdefaultProcessor.addHandler(SpringPropertyModel.class,\n\t\t\t\t(handlerContext, handlerMic) -> new SpringPropertyModelHandler(this.context,\n\t\t\t\t\t\tthis.initializationContext.getEnvironment()));\n\t\tdefaultProcessor.addHandler(SpringProfileModel.class,\n\t\t\t\t(handlerContext, handlerMic) -> new SpringProfileModelHandler(this.context,\n\t\t\t\t\t\tthis.initializationContext.getEnvironment()));\n\t\tsuper.addModelHandlerAssociations(defaultProcessor);\n\t}\n\n\t@Override\n\tpublic void addElementSelectorAndActionAssociations(RuleStore ruleStore) {\n\t\tsuper.addElementSelectorAndActionAssociations(ruleStore);\n\t\truleStore.addRule(new ElementSelector(\"configuration/springProperty\"), SpringPropertyAction::new);\n\t\truleStore.addRule(new ElementSelector(\"*/springProfile\"), SpringProfileAction::new);\n\t\truleStore.addTransparentPathPart(\"springProfile\");\n\t}\n\n\t@Override\n\tpublic void buildModelInterpretationContext() {\n\t\tsuper.buildModelInterpretationContext();\n\t\tthis.modelInterpretationContext.setConfiguratorSupplier(() -> {\n\t\t\tSpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(this.initializationContext);\n\t\t\tconfigurator.setContext(this.context);\n\t\t\treturn configurator;\n\t\t});\n\t}\n\n\tboolean configureUsingAotGeneratedArtifacts() {\n\t\tif (!new PatternRules(getContext()).load()) {\n\t\t\treturn false;\n\t\t}\n\t\tModel model = new ModelReader().read();\n\t\tprocessModel(model);\n\t\tregisterSafeConfiguration(model);\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void processModel(Model model) {\n\t\tsuper.processModel(model);\n\t\tif (!NativeDetector.inNativeImage() && isAotProcessingInProgress()) {\n\t\t\tgetContext().putObject(BeanFactoryInitializationAotContribution.class.getName(),\n\t\t\t\t\tnew LogbackConfigurationAotContribution(model, getModelInterpretationContext(), getContext()));\n\t\t}\n\t}\n\n\tprivate boolean isAotProcessingInProgress() {\n\t\treturn Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING);\n\t}\n\n\tstatic final class LogbackConfigurationAotContribution implements BeanFactoryInitializationAotContribution {\n\n\t\tprivate final ModelWriter modelWriter;\n\n\t\tprivate final PatternRules patternRules;\n\n\t\tprivate LogbackConfigurationAotContribution(Model model, ModelInterpretationContext interpretationContext,\n\t\t\t\tContext context) {\n\t\t\tthis.modelWriter = new ModelWriter(model, interpretationContext);\n\t\t\tthis.patternRules = new PatternRules(context);\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\tthis.modelWriter.writeTo(generationContext);\n\t\t\tthis.patternRules.save(generationContext);\n\t\t}\n\n\t}\n\n\tprivate static final class ModelWriter {\n\n\t\tprivate static final String MODEL_RESOURCE_LOCATION = \"META-INF/spring/logback-model\";\n\n\t\tprivate final Model model;\n\n\t\tprivate final ModelInterpretationContext modelInterpretationContext;\n\n\t\tprivate ModelWriter(Model model, ModelInterpretationContext modelInterpretationContext) {\n\t\t\tthis.model = model;\n\t\t\tthis.modelInterpretationContext = modelInterpretationContext;\n\t\t}\n\n\t\tprivate void writeTo(GenerationContext generationContext) {\n\t\t\tbyte[] serializedModel = serializeModel();\n\t\t\tgenerationContext.getGeneratedFiles()\n\t\t\t\t.handleFile(Kind.RESOURCE, MODEL_RESOURCE_LOCATION,\n\t\t\t\t\t\tnew RequireNewOrMatchingContentFileHandler(serializedModel));\n\t\t\tgenerationContext.getRuntimeHints().resources().registerPattern(MODEL_RESOURCE_LOCATION);\n\t\t\tReflectionHints reflectionHints = generationContext.getRuntimeHints().reflection();\n\t\t\tserializationTypes(this.model).forEach(reflectionHints::registerJavaSerialization);\n\t\t\treflectionTypes(this.model).forEach((type) -> generationContext.getRuntimeHints()\n\t\t\t\t.reflection()\n\t\t\t\t.registerType(TypeReference.of(type), MemberCategory.INVOKE_PUBLIC_METHODS,\n\t\t\t\t\t\tMemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));\n\t\t}\n\n\t\tprivate byte[] serializeModel() {\n\t\t\tByteArrayOutputStream bytes = new ByteArrayOutputStream();\n\t\t\ttry (ObjectOutputStream output = new ObjectOutputStream(bytes)) {\n\t\t\t\toutput.writeObject(this.model);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t\treturn bytes.toByteArray();\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate Set<Class<? extends Serializable>> serializationTypes(Model model) {\n\t\t\tSet<Class<? extends Serializable>> modelClasses = new HashSet<>();\n\t\t\tClass<?> candidate = model.getClass();\n\t\t\twhile (Model.class.isAssignableFrom(candidate)) {\n\t\t\t\tif (modelClasses.add((Class<? extends Model>) candidate)) {\n\t\t\t\t\tReflectionUtils.doWithFields(candidate, (field) -> {\n\t\t\t\t\t\tif (Modifier.isStatic(field.getModifiers())) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tReflectionUtils.makeAccessible(field);\n\t\t\t\t\t\tObject value = field.get(model);\n\t\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\t\tClass<?> fieldType = value.getClass();\n\t\t\t\t\t\t\tif (Serializable.class.isAssignableFrom(fieldType)) {\n\t\t\t\t\t\t\t\tmodelClasses.add((Class<? extends Serializable>) fieldType);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tcandidate = candidate.getSuperclass();\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (Model submodel : model.getSubModels()) {\n\t\t\t\tmodelClasses.addAll(serializationTypes(submodel));\n\t\t\t}\n\t\t\treturn modelClasses;\n\t\t}\n\n\t\tprivate Set<Class<?>> reflectionTypes(Model model) {\n\t\t\treturn reflectionTypes(model, () -> null);\n\t\t}\n\n\t\tprivate Set<Class<?>> reflectionTypes(Model model, Supplier<Object> parent) {\n\t\t\tSet<Class<?>> reflectionTypes = new HashSet<>();\n\t\t\tClass<?> componentType = determineType(model, parent);\n\t\t\tif (componentType != null) {\n\t\t\t\tprocessComponent(componentType, reflectionTypes);\n\t\t\t}\n\t\t\tSupplier<Object> componentSupplier = SingletonSupplier.of(() -> instantiate(componentType));\n\t\t\tfor (Model submodel : model.getSubModels()) {\n\t\t\t\treflectionTypes.addAll(reflectionTypes(submodel, componentSupplier));\n\t\t\t}\n\t\t\treturn reflectionTypes;\n\t\t}\n\n\t\tprivate @Nullable Class<?> determineType(Model model, Supplier<Object> parentSupplier) {\n\t\t\tString className = (model instanceof ComponentModel componentModel) ? componentModel.getClassName() : null;\n\t\t\tif (className != null) {\n\t\t\t\treturn loadImportType(className);\n\t\t\t}\n\t\t\tString tag = model.getTag();\n\t\t\tif (tag != null) {\n\t\t\t\tclassName = this.modelInterpretationContext.getDefaultNestedComponentRegistry()\n\t\t\t\t\t.findDefaultComponentTypeByTag(tag);\n\t\t\t\tif (className != null) {\n\t\t\t\t\treturn loadImportType(className);\n\t\t\t\t}\n\t\t\t\treturn inferTypeFromParent(parentSupplier, tag);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate Class<?> loadImportType(String className) {\n\t\t\treturn loadComponentType(this.modelInterpretationContext.getImport(className));\n\t\t}\n\n\t\tprivate @Nullable Class<?> inferTypeFromParent(Supplier<Object> parentSupplier, String tag) {\n\t\t\tObject parent = parentSupplier.get();\n\t\t\tif (parent != null) {\n\t\t\t\ttry {\n\t\t\t\t\tPropertySetter propertySetter = new PropertySetter(\n\t\t\t\t\t\t\tthis.modelInterpretationContext.getBeanDescriptionCache(), parent);\n\t\t\t\t\tClass<?> typeFromPropertySetter = propertySetter.getClassNameViaImplicitRules(tag,\n\t\t\t\t\t\t\tAggregationType.AS_COMPLEX_PROPERTY,\n\t\t\t\t\t\t\tthis.modelInterpretationContext.getDefaultNestedComponentRegistry());\n\t\t\t\t\treturn typeFromPropertySetter;\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate Class<?> loadComponentType(String componentType) {\n\t\t\ttry {\n\t\t\t\treturn ClassUtils.forName(this.modelInterpretationContext.subst(componentType),\n\t\t\t\t\t\tgetClass().getClassLoader());\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new RuntimeException(\"Failed to load component type '\" + componentType + \"'\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable Object instantiate(@Nullable Class<?> type) {\n\t\t\tif (type == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn type.getConstructor().newInstance();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprivate void processComponent(Class<?> componentType, Set<Class<?>> reflectionTypes) {\n\t\t\tBeanDescription beanDescription = this.modelInterpretationContext.getBeanDescriptionCache()\n\t\t\t\t.getBeanDescription(componentType);\n\t\t\treflectionTypes.addAll(parameterTypesNames(beanDescription.getPropertyNameToAdder().values()));\n\t\t\treflectionTypes.addAll(parameterTypesNames(beanDescription.getPropertyNameToSetter().values()));\n\t\t\treflectionTypes.add(componentType);\n\t\t}\n\n\t\tprivate Collection<Class<?>> parameterTypesNames(Collection<Method> methods) {\n\t\t\treturn methods.stream()\n\t\t\t\t.filter((method) -> !method.getDeclaringClass().equals(ContextAware.class)\n\t\t\t\t\t\t&& !method.getDeclaringClass().equals(ContextAwareBase.class))\n\t\t\t\t.map(Method::getParameterTypes)\n\t\t\t\t.flatMap(Stream::of)\n\t\t\t\t.filter((type) -> !type.isPrimitive() && !type.equals(String.class))\n\t\t\t\t.map((type) -> type.isArray() ? type.getComponentType() : type)\n\t\t\t\t.toList();\n\t\t}\n\n\t}\n\n\tprivate static final class ModelReader {\n\n\t\tprivate Model read() {\n\t\t\ttry (InputStream modelInput = getClass().getClassLoader()\n\t\t\t\t.getResourceAsStream(ModelWriter.MODEL_RESOURCE_LOCATION)) {\n\t\t\t\ttry (ObjectInputStream input = new ObjectInputStream(modelInput)) {\n\t\t\t\t\tModel model = (Model) input.readObject();\n\t\t\t\t\tModelUtil.resetForReuse(model);\n\t\t\t\t\tmarkIncludesAsHandled(model);\n\t\t\t\t\treturn model;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(\"Failed to load model from '\" + ModelWriter.MODEL_RESOURCE_LOCATION + \"'\",\n\t\t\t\t\t\tex);\n\t\t\t}\n\t\t}\n\n\t\tprivate void markIncludesAsHandled(Model model) {\n\t\t\tif (model instanceof IncludeModel) {\n\t\t\t\tmodel.markAsHandled();\n\t\t\t}\n\t\t\tfor (Model submodel : model.getSubModels()) {\n\t\t\t\tmarkIncludesAsHandled(submodel);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static final class PatternRules {\n\n\t\tprivate static final String RESOURCE_LOCATION = \"META-INF/spring/logback-pattern-rules\";\n\n\t\tprivate final Context context;\n\n\t\tprivate PatternRules(Context context) {\n\t\t\tthis.context = context;\n\t\t}\n\n\t\tprivate boolean load() {\n\t\t\ttry {\n\t\t\t\tClassPathResource resource = new ClassPathResource(RESOURCE_LOCATION);\n\t\t\t\tif (!resource.exists()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tProperties properties = PropertiesLoaderUtils.loadProperties(resource);\n\t\t\t\tMap<String, String> patternRuleRegistry = getRegistryMap();\n\t\t\t\tfor (String word : properties.stringPropertyNames()) {\n\t\t\t\t\tpatternRuleRegistry.put(word, properties.getProperty(word));\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate Map<String, String> getRegistryMap() {\n\t\t\tMap<String, String> patternRuleRegistry = (Map<String, String>) this.context\n\t\t\t\t.getObject(CoreConstants.PATTERN_RULE_REGISTRY);\n\t\t\tif (patternRuleRegistry == null) {\n\t\t\t\tpatternRuleRegistry = new HashMap<>();\n\t\t\t\tthis.context.putObject(CoreConstants.PATTERN_RULE_REGISTRY, patternRuleRegistry);\n\t\t\t}\n\t\t\treturn patternRuleRegistry;\n\t\t}\n\n\t\tprivate void save(GenerationContext generationContext) {\n\t\t\tMap<String, String> registryMap = getRegistryMap();\n\t\t\tbyte[] rules = asBytes(registryMap);\n\t\t\tgenerationContext.getGeneratedFiles()\n\t\t\t\t.handleFile(Kind.RESOURCE, RESOURCE_LOCATION, new RequireNewOrMatchingContentFileHandler(rules));\n\t\t\tgenerationContext.getRuntimeHints().resources().registerPattern(RESOURCE_LOCATION);\n\t\t\tfor (String ruleClassName : registryMap.values()) {\n\t\t\t\tgenerationContext.getRuntimeHints()\n\t\t\t\t\t.reflection()\n\t\t\t\t\t.registerType(TypeReference.of(ruleClassName), MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t\t}\n\t\t}\n\n\t\tprivate byte[] asBytes(Map<String, String> patternRuleRegistry) {\n\t\t\tProperties properties = CollectionFactory.createSortedProperties(true);\n\t\t\tpatternRuleRegistry.forEach(properties::setProperty);\n\t\t\tByteArrayOutputStream bytes = new ByteArrayOutputStream();\n\t\t\ttry {\n\t\t\t\tproperties.store(bytes, \"\");\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t\treturn bytes.toByteArray();\n\t\t}\n\n\t}\n\n\tprivate static final class RequireNewOrMatchingContentFileHandler implements ThrowingConsumer<FileHandler> {\n\n\t\tprivate final byte[] newContent;\n\n\t\tprivate RequireNewOrMatchingContentFileHandler(byte[] newContent) {\n\t\t\tthis.newContent = newContent;\n\t\t}\n\n\t\t@Override\n\t\tpublic void acceptWithException(FileHandler file) throws Exception {\n\t\t\tif (file.exists()) {\n\t\t\t\tInputStreamSource content = file.getContent();\n\t\t\t\tAssert.state(content != null, \"Unable to get file content\");\n\t\t\t\tbyte[] existingContent = content.getInputStream().readAllBytes();\n\t\t\t\tif (!Arrays.equals(this.newContent, existingContent)) {\n\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\"Logging configuration differs from the configuration that has already been written. \"\n\t\t\t\t\t\t\t\t\t+ \"Update your logging configuration so that it is the same for each context\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfile.create(new ByteArrayResource(this.newContent));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.core.joran.action.BaseModelAction;\nimport ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;\nimport ch.qos.logback.core.model.Model;\nimport org.xml.sax.Attributes;\n\n/**\n * Logback {@link BaseModelAction} for {@code <springProfile>} tags. Allows a section of a\n * Logback configuration to only be enabled when a specific profile is active.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n * @see SpringProfileModel\n * @see SpringProfileModelHandler\n */\nclass SpringProfileAction extends BaseModelAction {\n\n\t@Override\n\tprotected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,\n\t\t\tAttributes attributes) {\n\t\tSpringProfileModel model = new SpringProfileModel();\n\t\tmodel.setName(attributes.getValue(NAME_ATTRIBUTE));\n\t\treturn model;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileIfNestedWithinSecondPhaseElementSanityChecker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport ch.qos.logback.classic.joran.sanity.IfNestedWithinSecondPhaseElementSC;\nimport ch.qos.logback.classic.model.LoggerModel;\nimport ch.qos.logback.classic.model.RootLoggerModel;\nimport ch.qos.logback.core.joran.sanity.Pair;\nimport ch.qos.logback.core.joran.sanity.SanityChecker;\nimport ch.qos.logback.core.model.AppenderModel;\nimport ch.qos.logback.core.model.Model;\nimport ch.qos.logback.core.spi.ContextAwareBase;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link SanityChecker} to ensure that {@code springProfile} elements are not nested\n * within second-phase elements.\n *\n * @author Phillip Webb\n * @see IfNestedWithinSecondPhaseElementSC\n */\nclass SpringProfileIfNestedWithinSecondPhaseElementSanityChecker extends ContextAwareBase implements SanityChecker {\n\n\tprivate static final List<Class<? extends Model>> SECOND_PHASE_TYPES = List.of(AppenderModel.class,\n\t\t\tLoggerModel.class, RootLoggerModel.class);\n\n\t@Override\n\tpublic void check(@Nullable Model model) {\n\t\tif (model == null) {\n\t\t\treturn;\n\t\t}\n\t\tList<Model> models = new ArrayList<>();\n\t\tSECOND_PHASE_TYPES.forEach((type) -> deepFindAllModelsOfType(type, models, model));\n\t\tList<Pair<Model, Model>> nestedPairs = deepFindNestedSubModelsOfType(SpringProfileModel.class, models);\n\t\tif (!nestedPairs.isEmpty()) {\n\t\t\taddWarn(\"<springProfile> elements cannot be nested within an <appender>, <logger> or <root> element\");\n\t\t\tnestedPairs.forEach((nested) -> {\n\t\t\t\tModel first = nested.first;\n\t\t\t\tModel second = nested.second;\n\t\t\t\taddWarn(\"Element <%s> at line %s contains a nested <%s> element at line %s\".formatted(first.getTag(),\n\t\t\t\t\t\tfirst.getLineNumber(), second.getTag(), second.getLineNumber()));\n\t\t\t});\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileModel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.core.model.NamedModel;\n\n/**\n * Logback {@link NamedModel model} to support {@code <springProfile>} tags.\n *\n * @author Andy Wilkinson\n * @see SpringProfileAction\n * @see SpringProfileModelHandler\n */\nclass SpringProfileModel extends NamedModel {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringProfileModelHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.core.Context;\nimport ch.qos.logback.core.model.Model;\nimport ch.qos.logback.core.model.processor.ModelHandlerBase;\nimport ch.qos.logback.core.model.processor.ModelHandlerException;\nimport ch.qos.logback.core.model.processor.ModelInterpretationContext;\nimport ch.qos.logback.core.spi.ScanException;\nimport ch.qos.logback.core.util.OptionHelper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.Profiles;\nimport org.springframework.util.StringUtils;\n\n/**\n * Logback {@link ModelHandlerBase model handler} to support {@code <springProfile>} tags.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n * @see SpringProfileModel\n * @see SpringProfileAction\n */\nclass SpringProfileModelHandler extends ModelHandlerBase {\n\n\tprivate final @Nullable Environment environment;\n\n\tSpringProfileModelHandler(Context context, @Nullable Environment environment) {\n\t\tsuper(context);\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic void handle(ModelInterpretationContext intercon, Model model) throws ModelHandlerException {\n\t\tSpringProfileModel profileModel = (SpringProfileModel) model;\n\t\tif (!acceptsProfiles(intercon, profileModel)) {\n\t\t\tmodel.deepMarkAsSkipped();\n\t\t}\n\t}\n\n\tprivate boolean acceptsProfiles(ModelInterpretationContext ic, SpringProfileModel model) {\n\t\tif (this.environment == null) {\n\t\t\treturn false;\n\t\t}\n\t\tString[] profileNames = trimArrayElements(StringUtils.commaDelimitedListToStringArray(model.getName()));\n\t\tif (profileNames.length == 0) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (int i = 0; i < profileNames.length; i++) {\n\t\t\ttry {\n\t\t\t\tprofileNames[i] = OptionHelper.substVars(profileNames[i], ic, this.context);\n\t\t\t}\n\t\t\tcatch (ScanException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\t\treturn this.environment.acceptsProfiles(Profiles.of(profileNames));\n\t}\n\n\t// The array has no nulls in it, but StringUtils.trimArrayElements return\n\t// @Nullable String[]\n\t@SuppressWarnings(\"NullAway\")\n\tprivate String[] trimArrayElements(String[] array) {\n\t\treturn StringUtils.trimArrayElements(array);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringPropertyAction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.core.joran.action.BaseModelAction;\nimport ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;\nimport ch.qos.logback.core.model.Model;\nimport org.xml.sax.Attributes;\n\n/**\n * Logback {@link BaseModelAction} for {@code <springProperty>} tags. Allows Logback\n * properties to be sourced from the Spring environment.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @see SpringPropertyModel\n * @see SpringPropertyModelHandler\n */\nclass SpringPropertyAction extends BaseModelAction {\n\n\tprivate static final String SOURCE_ATTRIBUTE = \"source\";\n\n\tprivate static final String DEFAULT_VALUE_ATTRIBUTE = \"defaultValue\";\n\n\t@Override\n\tprotected Model buildCurrentModel(SaxEventInterpretationContext interpretationContext, String name,\n\t\t\tAttributes attributes) {\n\t\tSpringPropertyModel model = new SpringPropertyModel();\n\t\tmodel.setName(attributes.getValue(NAME_ATTRIBUTE));\n\t\tmodel.setSource(attributes.getValue(SOURCE_ATTRIBUTE));\n\t\tmodel.setScope(attributes.getValue(SCOPE_ATTRIBUTE));\n\t\tmodel.setDefaultValue(attributes.getValue(DEFAULT_VALUE_ATTRIBUTE));\n\t\treturn model;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringPropertyModel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.core.model.NamedModel;\n\n/**\n * Logback {@link NamedModel model} to support {@code <springProperty>} tags. Allows\n * Logback properties to be sourced from the Spring environment.\n *\n * @author Andy Wilkinson\n * @see SpringPropertyAction\n * @see SpringPropertyModelHandler\n */\nclass SpringPropertyModel extends NamedModel {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String scope;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String defaultValue;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String source;\n\n\tString getScope() {\n\t\treturn this.scope;\n\t}\n\n\tvoid setScope(String scope) {\n\t\tthis.scope = scope;\n\t}\n\n\tString getDefaultValue() {\n\t\treturn this.defaultValue;\n\t}\n\n\tvoid setDefaultValue(String defaultValue) {\n\t\tthis.defaultValue = defaultValue;\n\t}\n\n\tString getSource() {\n\t\treturn this.source;\n\t}\n\n\tvoid setSource(String source) {\n\t\tthis.source = source;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SpringPropertyModelHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.core.Context;\nimport ch.qos.logback.core.joran.action.ActionUtil;\nimport ch.qos.logback.core.joran.action.ActionUtil.Scope;\nimport ch.qos.logback.core.model.Model;\nimport ch.qos.logback.core.model.processor.ModelHandlerBase;\nimport ch.qos.logback.core.model.processor.ModelHandlerException;\nimport ch.qos.logback.core.model.processor.ModelInterpretationContext;\nimport ch.qos.logback.core.model.util.PropertyModelHandlerHelper;\nimport ch.qos.logback.core.util.OptionHelper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\n\n/**\n * Logback {@link ModelHandlerBase model handler} to support {@code <springProperty>}\n * tags. Allows Logback properties to be sourced from the Spring environment.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @see SpringPropertyAction\n * @see SpringPropertyModel\n */\nclass SpringPropertyModelHandler extends ModelHandlerBase {\n\n\tprivate final @Nullable Environment environment;\n\n\tSpringPropertyModelHandler(Context context, @Nullable Environment environment) {\n\t\tsuper(context);\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic void handle(ModelInterpretationContext intercon, Model model) throws ModelHandlerException {\n\t\tSpringPropertyModel propertyModel = (SpringPropertyModel) model;\n\t\tScope scope = ActionUtil.stringToScope(propertyModel.getScope());\n\t\tString defaultValue = propertyModel.getDefaultValue();\n\t\tString source = propertyModel.getSource();\n\t\tif (OptionHelper.isNullOrEmpty(propertyModel.getName()) || OptionHelper.isNullOrEmpty(source)) {\n\t\t\taddError(\"The \\\"name\\\" and \\\"source\\\" attributes of <springProperty> must be set\");\n\t\t}\n\t\tPropertyModelHandlerHelper.setProperty(intercon, propertyModel.getName(), getValue(source, defaultValue),\n\t\t\t\tscope);\n\t}\n\n\tprivate String getValue(String source, String defaultValue) {\n\t\tif (this.environment == null) {\n\t\t\taddWarn(\"No Spring Environment available to resolve \" + source);\n\t\t\treturn defaultValue;\n\t\t}\n\t\treturn this.environment.getProperty(source, defaultValue);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/StructuredLogEncoder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.encoder.Encoder;\nimport ch.qos.logback.core.encoder.EncoderBase;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.CommonStructuredLogFormat;\nimport org.springframework.boot.logging.structured.ContextPairs;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatterFactory;\nimport org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\nimport org.springframework.boot.util.Instantiator;\nimport org.springframework.boot.util.Instantiator.AvailableParameters;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Encoder Logback encoder} for structured logging.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 3.4.0\n * @see StructuredLogFormatter\n */\npublic class StructuredLogEncoder extends EncoderBase<ILoggingEvent> {\n\n\tprivate final ThrowableProxyConverter throwableProxyConverter = new ThrowableProxyConverter();\n\n\tprivate @Nullable String format;\n\n\tprivate @Nullable StructuredLogFormatter<ILoggingEvent> formatter;\n\n\tprivate @Nullable Charset charset = StandardCharsets.UTF_8;\n\n\tpublic void setFormat(String format) {\n\t\tthis.format = format;\n\t}\n\n\tpublic void setCharset(@Nullable Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tAssert.state(this.format != null, \"Format has not been set\");\n\t\tthis.formatter = createFormatter(this.format);\n\t\tsuper.start();\n\t\tthis.throwableProxyConverter.start();\n\t}\n\n\tprivate StructuredLogFormatter<ILoggingEvent> createFormatter(String format) {\n\t\tEnvironment environment = (Environment) getContext().getObject(Environment.class.getName());\n\t\tAssert.state(environment != null, \"Unable to find Spring Environment in logger context\");\n\t\treturn new StructuredLogFormatterFactory<>(ILoggingEvent.class, environment, this::addAvailableParameters,\n\t\t\t\tthis::addCommonFormatters)\n\t\t\t.get(format);\n\t}\n\n\tprivate void addAvailableParameters(AvailableParameters availableParameters) {\n\t\tavailableParameters.add(ThrowableProxyConverter.class, this.throwableProxyConverter);\n\t}\n\n\tprivate void addCommonFormatters(CommonFormatters<ILoggingEvent> commonFormatters) {\n\t\tcommonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA, this::createEcsFormatter);\n\t\tcommonFormatters.add(CommonStructuredLogFormat.GRAYLOG_EXTENDED_LOG_FORMAT, this::createGraylogFormatter);\n\t\tcommonFormatters.add(CommonStructuredLogFormat.LOGSTASH, this::createLogstashFormatter);\n\t}\n\n\tprivate StructuredLogFormatter<ILoggingEvent> createEcsFormatter(Instantiator<?> instantiator) {\n\t\tEnvironment environment = instantiator.getArg(Environment.class);\n\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\tContextPairs contextPairs = instantiator.getArg(ContextPairs.class);\n\t\tThrowableProxyConverter throwableProxyConverter = instantiator.getArg(ThrowableProxyConverter.class);\n\t\tStructuredLoggingJsonMembersCustomizer.Builder<?> jsonMembersCustomizerBuilder = instantiator\n\t\t\t.getArg(StructuredLoggingJsonMembersCustomizer.Builder.class);\n\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\tAssert.state(contextPairs != null, \"'contextPairs' must not be null\");\n\t\tAssert.state(throwableProxyConverter != null, \"'throwableProxyConverter' must not be null\");\n\t\tAssert.state(jsonMembersCustomizerBuilder != null, \"'jsonMembersCustomizerBuilder' must not be null\");\n\t\treturn new ElasticCommonSchemaStructuredLogFormatter(environment, stackTracePrinter, contextPairs,\n\t\t\t\tthrowableProxyConverter, jsonMembersCustomizerBuilder);\n\t}\n\n\tprivate StructuredLogFormatter<ILoggingEvent> createGraylogFormatter(Instantiator<?> instantiator) {\n\t\tEnvironment environment = instantiator.getArg(Environment.class);\n\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\tContextPairs contextPairs = instantiator.getArg(ContextPairs.class);\n\t\tThrowableProxyConverter throwableProxyConverter = instantiator.getArg(ThrowableProxyConverter.class);\n\t\tStructuredLoggingJsonMembersCustomizer<?> jsonMembersCustomizer = instantiator\n\t\t\t.getArg(StructuredLoggingJsonMembersCustomizer.class);\n\t\tAssert.state(environment != null, \"'environment' must not be null\");\n\t\tAssert.state(contextPairs != null, \"'contextPairs' must not be null\");\n\t\tAssert.state(throwableProxyConverter != null, \"'throwableProxyConverter' must not be null\");\n\t\treturn new GraylogExtendedLogFormatStructuredLogFormatter(environment, stackTracePrinter, contextPairs,\n\t\t\t\tthrowableProxyConverter, jsonMembersCustomizer);\n\t}\n\n\tprivate StructuredLogFormatter<ILoggingEvent> createLogstashFormatter(Instantiator<?> instantiator) {\n\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\tContextPairs contextPairs = instantiator.getArg(ContextPairs.class);\n\t\tThrowableProxyConverter throwableProxyConverter = instantiator.getArg(ThrowableProxyConverter.class);\n\t\tStructuredLoggingJsonMembersCustomizer<?> jsonMembersCustomizer = instantiator\n\t\t\t.getArg(StructuredLoggingJsonMembersCustomizer.class);\n\t\tAssert.state(contextPairs != null, \"'contextPairs' must not be null\");\n\t\tAssert.state(throwableProxyConverter != null, \"'throwableProxyConverter' must not be null\");\n\t\treturn new LogstashStructuredLogFormatter(stackTracePrinter, contextPairs, throwableProxyConverter,\n\t\t\t\tjsonMembersCustomizer);\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.throwableProxyConverter.stop();\n\t\tsuper.stop();\n\t}\n\n\t@Override\n\tpublic byte @Nullable [] headerBytes() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic byte[] encode(ILoggingEvent event) {\n\t\tAssert.state(this.formatter != null,\n\t\t\t\t\"formatter must not be null. Make sure to call start() before this method\");\n\t\treturn this.formatter.formatAsBytes(event, (this.charset != null) ? this.charset : StandardCharsets.UTF_8);\n\t}\n\n\t@Override\n\tpublic byte @Nullable [] footerBytes() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/SystemStatusListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.PrintStream;\nimport java.util.List;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.core.BasicStatusManager;\nimport ch.qos.logback.core.status.OnConsoleStatusListener;\nimport ch.qos.logback.core.status.Status;\nimport ch.qos.logback.core.status.StatusListener;\nimport ch.qos.logback.core.util.StatusListenerConfigHelper;\n\n/**\n * {@link StatusListener} used to print appropriate status messages to {@link System#out}\n * or {@link System#err}. Note that this class extends {@link OnConsoleStatusListener} so\n * that {@link BasicStatusManager#add(StatusListener)} does not add the same listener\n * twice. It also implements a version of retrospectivePrint that can filter status\n * messages by level.\n *\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\nfinal class SystemStatusListener extends OnConsoleStatusListener {\n\n\tprivate static final long RETROSPECTIVE_THRESHOLD = 300;\n\n\tprivate final boolean debug;\n\n\tprivate SystemStatusListener(boolean debug) {\n\t\tthis.debug = debug;\n\t\tsetResetResistant(false);\n\t\tsetRetrospective(0);\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tsuper.start();\n\t\tretrospectivePrint();\n\t}\n\n\tprivate void retrospectivePrint() {\n\t\tif (this.context == null) {\n\t\t\treturn;\n\t\t}\n\t\tlong now = System.currentTimeMillis();\n\t\tList<Status> statusList = this.context.getStatusManager().getCopyOfStatusList();\n\t\tstatusList.stream()\n\t\t\t.filter((status) -> getElapsedTime(status, now) < RETROSPECTIVE_THRESHOLD)\n\t\t\t.forEach(this::addStatusEvent);\n\t}\n\n\t@Override\n\tpublic void addStatusEvent(Status status) {\n\t\tif (this.debug || status.getLevel() >= Status.WARN) {\n\t\t\tsuper.addStatusEvent(status);\n\t\t}\n\t}\n\n\t@Override\n\tprotected PrintStream getPrintStream() {\n\t\treturn (!this.debug) ? System.err : System.out;\n\t}\n\n\tprivate static long getElapsedTime(Status status, long now) {\n\t\treturn now - status.getTimestamp();\n\t}\n\n\tstatic void addTo(LoggerContext loggerContext) {\n\t\taddTo(loggerContext, false);\n\t}\n\n\tstatic void addTo(LoggerContext loggerContext, boolean debug) {\n\t\tStatusListenerConfigHelper.addOnConsoleListenerInstance(loggerContext, new SystemStatusListener(debug));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/WhitespaceThrowableProxyConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.IThrowableProxy;\nimport ch.qos.logback.core.CoreConstants;\n\n/**\n * {@link ThrowableProxyConverter} that adds some additional whitespace around the stack\n * trace.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic class WhitespaceThrowableProxyConverter extends ThrowableProxyConverter {\n\n\t@Override\n\tprotected String throwableProxyToString(IThrowableProxy tp) {\n\t\treturn CoreConstants.LINE_SEPARATOR + super.throwableProxyToString(tp) + CoreConstants.LINE_SEPARATOR;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/logback/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for the Logback logging library.\n */\n@NullMarked\npackage org.springframework.boot.logging.logback;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support and abstractions across several logging libraries.\n *\n * @see org.springframework.boot.logging.LoggingSystem\n */\n@NullMarked\npackage org.springframework.boot.logging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/CommonStructuredLogFormat.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Common structured log formats supported by Spring Boot.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic enum CommonStructuredLogFormat {\n\n\t/**\n\t * <a href=\"https://www.elastic.co/guide/en/ecs/current/ecs-log.html\">Elastic Common\n\t * Schema</a> (ECS) log format.\n\t */\n\tELASTIC_COMMON_SCHEMA(\"ecs\"),\n\n\t/**\n\t * <a href=\"https://go2docs.graylog.org/current/getting_in_log_data/gelf.html\">Graylog\n\t * Extended Log Format</a> (GELF) log format.\n\t */\n\tGRAYLOG_EXTENDED_LOG_FORMAT(\"gelf\"),\n\n\t/**\n\t * The <a href=\n\t * \"https://github.com/logfellow/logstash-logback-encoder?tab=readme-ov-file#standard-fields\">Logstash</a>\n\t * log format.\n\t */\n\tLOGSTASH(\"logstash\");\n\n\tprivate final String id;\n\n\tCommonStructuredLogFormat(String id) {\n\t\tthis.id = id;\n\t}\n\n\t/**\n\t * Return the ID for this format.\n\t * @return the format identifier\n\t */\n\tString getId() {\n\t\treturn this.id;\n\t}\n\n\t/**\n\t * Find the {@link CommonStructuredLogFormat} for the given ID.\n\t * @param id the format identifier\n\t * @return the associated {@link CommonStructuredLogFormat} or {@code null}\n\t */\n\tstatic @Nullable CommonStructuredLogFormat forId(String id) {\n\t\tfor (CommonStructuredLogFormat candidate : values()) {\n\t\t\tif (candidate.getId().equalsIgnoreCase(id)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/ContextPairs.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.PairExtractor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Helper that can be used to add JSON pairs from context data (typically the logger MDC)\n * in the correct location (or drop them altogether).\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic class ContextPairs {\n\n\tprivate final boolean include;\n\n\tprivate final String prefix;\n\n\tContextPairs(boolean include, @Nullable String prefix) {\n\t\tthis.include = include;\n\t\tthis.prefix = (prefix != null) ? prefix : \"\";\n\t}\n\n\t/**\n\t * Add pairs using flat naming.\n\t * @param <T> the item type\n\t * @param delimiter the delimiter used if there is a prefix\n\t * @param pairs callback to add all the pairs\n\t * @return a {@link BiConsumer} for use with the {@link JsonWriter}\n\t */\n\tpublic <T> BiConsumer<T, BiConsumer<String, Object>> flat(String delimiter, Consumer<Pairs<T>> pairs) {\n\t\treturn flat(joinWith(delimiter), pairs);\n\t}\n\n\t/**\n\t * Add pairs using flat naming.\n\t * @param <T> the item type\n\t * @param joiner the function used to join the prefix and name\n\t * @param pairs callback to add all the pairs\n\t * @return a {@link BiConsumer} for use with the {@link JsonWriter}\n\t */\n\tpublic <T> BiConsumer<T, BiConsumer<String, Object>> flat(Joiner joiner, Consumer<Pairs<T>> pairs) {\n\t\treturn (!this.include) ? none() : new Pairs<>(joiner, pairs)::flat;\n\t}\n\n\t/**\n\t * Add pairs using nested naming (for example as used in ECS).\n\t * @param <T> the item type\n\t * @param pairs callback to add all the pairs\n\t * @return a {@link BiConsumer} for use with the {@link JsonWriter}\n\t */\n\tpublic <T> BiConsumer<T, BiConsumer<String, Object>> nested(Consumer<Pairs<T>> pairs) {\n\t\treturn (!this.include) ? none() : new Pairs<>(joinWith(\".\"), pairs)::nested;\n\t}\n\n\tprivate <T, V> BiConsumer<T, BiConsumer<String, V>> none() {\n\t\treturn (item, pairs) -> {\n\t\t};\n\t}\n\n\tprivate Joiner joinWith(String delimiter) {\n\t\treturn (prefix, name) -> {\n\t\t\tStringBuilder joined = new StringBuilder(prefix.length() + delimiter.length() + name.length());\n\t\t\tjoined.append(prefix);\n\t\t\tif (!prefix.isEmpty() && !prefix.endsWith(delimiter) && !name.startsWith(delimiter)) {\n\t\t\t\tjoined.append(delimiter);\n\t\t\t}\n\t\t\tjoined.append(name);\n\t\t\treturn joined.toString();\n\t\t};\n\t}\n\n\t/**\n\t * Joins a prefix and a name.\n\t */\n\t@FunctionalInterface\n\tpublic interface Joiner {\n\n\t\t/**\n\t\t * Joins the given prefix and name.\n\t\t * @param prefix the prefix\n\t\t * @param name the name\n\t\t * @return the joined result or {@code null}\n\t\t */\n\t\t@Nullable String join(String prefix, String name);\n\n\t}\n\n\t/**\n\t * Callback used to add pairs.\n\t *\n\t * @param <T> the item type\n\t */\n\tpublic class Pairs<T> {\n\n\t\tprivate final Joiner joiner;\n\n\t\tprivate final List<BiConsumer<T, BiConsumer<String, ?>>> addedPairs;\n\n\t\tPairs(Joiner joiner, Consumer<Pairs<T>> pairs) {\n\t\t\tthis.joiner = joiner;\n\t\t\tthis.addedPairs = new ArrayList<>();\n\t\t\tpairs.accept(this);\n\t\t}\n\n\t\t/**\n\t\t * Add pairs from map entries.\n\t\t * @param <V> the map value type\n\t\t * @param extractor the extractor used to provide the map\n\t\t */\n\t\t@SuppressWarnings(\"NullAway\") // Doesn't detect lambda with correct nullability\n\t\tpublic <V> void addMapEntries(Function<T, Map<String, V>> extractor) {\n\t\t\tadd(extractor.andThen(Map::entrySet), Map.Entry::getKey, Map.Entry::getValue);\n\t\t}\n\n\t\t/**\n\t\t * Add pairs from an iterable.\n\t\t * @param elementsExtractor the extractor used to provide the iterable\n\t\t * @param pairExtractor the extractor used to provide the name and value\n\t\t * @param <E> the element type\n\t\t */\n\t\tpublic <E> void add(Function<T, @Nullable Iterable<E>> elementsExtractor, PairExtractor<E> pairExtractor) {\n\t\t\tadd(elementsExtractor, pairExtractor::getName, pairExtractor::getValue);\n\t\t}\n\n\t\t/**\n\t\t * Add pairs from an iterable.\n\t\t * @param elementsExtractor the extractor used to provide the iterable\n\t\t * @param <E> the element type\n\t\t * @param <V> the value type\n\t\t * @param nameExtractor the extractor used to provide the name\n\t\t * @param valueExtractor the extractor used to provide the value\n\t\t */\n\t\tpublic <E, V> void add(Function<T, @Nullable Iterable<E>> elementsExtractor, Function<E, String> nameExtractor,\n\t\t\t\tFunction<E, V> valueExtractor) {\n\t\t\tadd((item, pairs) -> {\n\t\t\t\tIterable<E> elements = elementsExtractor.apply(item);\n\t\t\t\tif (elements != null) {\n\t\t\t\t\telements.forEach((element) -> {\n\t\t\t\t\t\tString name = nameExtractor.apply(element);\n\t\t\t\t\t\tV value = valueExtractor.apply(element);\n\t\t\t\t\t\tpairs.accept(name, value);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Add pairs using the given callback.\n\t\t * @param <V> the value type\n\t\t * @param pairs callback provided with the item and consumer that can be called to\n\t\t * actually add the pairs\n\t\t */\n\t\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t\tpublic <V> void add(BiConsumer<T, BiConsumer<String, V>> pairs) {\n\t\t\tthis.addedPairs.add((BiConsumer) pairs);\n\t\t}\n\n\t\tvoid flat(T item, BiConsumer<String, Object> pairs) {\n\t\t\tthis.addedPairs.forEach((action) -> action.accept(item, joining(pairs)));\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid nested(T item, BiConsumer<String, Object> pairs) {\n\t\t\tLinkedHashMap<String, Object> result = new LinkedHashMap<>();\n\t\t\tthis.addedPairs.forEach((addedPair) -> {\n\t\t\t\taddedPair.accept(item, joining((name, value) -> {\n\t\t\t\t\tStringBuilder part = new StringBuilder(name.length());\n\t\t\t\t\tint length = (!name.endsWith(\".\")) ? name.length() : name.length() - 1;\n\t\t\t\t\tMap<String, Object> destination = result;\n\t\t\t\t\tfor (int i = 0; i < length; i++) {\n\t\t\t\t\t\tchar ch = name.charAt(i);\n\t\t\t\t\t\tif (i == length - 1) {\n\t\t\t\t\t\t\tpart.append(ch);\n\t\t\t\t\t\t\tObject previous = destination.put(part.toString(), value);\n\t\t\t\t\t\t\tassertNotDuplicateNestedPairs(previous == null, name, length);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (ch == '.') {\n\t\t\t\t\t\t\tObject current = destination.computeIfAbsent(part.toString(),\n\t\t\t\t\t\t\t\t\t(key) -> new LinkedHashMap<>());\n\t\t\t\t\t\t\tassertNotDuplicateNestedPairs(current instanceof Map, name, i);\n\t\t\t\t\t\t\tdestination = (Map<String, Object>) current;\n\t\t\t\t\t\t\tpart.setLength(0);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tpart.append(ch);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\t});\n\t\t\tresult.forEach(pairs);\n\t\t}\n\n\t\tprivate void assertNotDuplicateNestedPairs(boolean expression, String name, int index) {\n\t\t\tAssert.state(expression,\n\t\t\t\t\t() -> \"Duplicate nested pairs added under '%s'\".formatted(name.substring(0, index)));\n\t\t}\n\n\t\tprivate <V> BiConsumer<String, V> joining(BiConsumer<String, V> pairs) {\n\t\t\treturn (name, value) -> {\n\t\t\t\tname = this.joiner.join(ContextPairs.this.prefix, (name != null) ? name : \"\");\n\t\t\t\tif (StringUtils.hasLength(name)) {\n\t\t\t\t\tpairs.accept(name, value);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/ElasticCommonSchemaProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * Properties for Elastic Common Schema structured logging.\n *\n * @param service service details\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic record ElasticCommonSchemaProperties(Service service) {\n\n\tstatic final ElasticCommonSchemaProperties NONE = new ElasticCommonSchemaProperties(Service.NONE);\n\n\tElasticCommonSchemaProperties withDefaults(Environment environment) {\n\t\tService service = this.service.withDefaults(environment);\n\t\treturn new ElasticCommonSchemaProperties(service);\n\t}\n\n\tstatic @Nullable String withFallbackProperty(Environment environment, @Nullable String value, String property) {\n\t\treturn (!StringUtils.hasLength(value)) ? environment.getProperty(property) : value;\n\t}\n\n\t/**\n\t * Add {@link JsonWriter} members for the service.\n\t * @param members the members to add to\n\t */\n\tpublic void jsonMembers(JsonWriter.Members<?> members) {\n\t\tthis.service.jsonMembers(members);\n\t}\n\n\t/**\n\t * Return a new {@link ElasticCommonSchemaProperties} from bound from properties in\n\t * the given {@link Environment}.\n\t * @param environment the source environment\n\t * @return a new {@link ElasticCommonSchemaProperties} instance\n\t */\n\tpublic static ElasticCommonSchemaProperties get(Environment environment) {\n\t\treturn Binder.get(environment)\n\t\t\t.bind(\"logging.structured.ecs\", ElasticCommonSchemaProperties.class)\n\t\t\t.orElse(NONE)\n\t\t\t.withDefaults(environment);\n\t}\n\n\t/**\n\t * Service details.\n\t *\n\t * @param name the application name\n\t * @param version the version of the application\n\t * @param environment the name of the environment the application is running in\n\t * @param nodeName the name of the node the application is running on\n\t */\n\tpublic record Service(@Nullable String name, @Nullable String version, @Nullable String environment,\n\t\t\t@Nullable String nodeName) {\n\n\t\tstatic final Service NONE = new Service(null, null, null, null);\n\n\t\t@SuppressWarnings(\"NullAway\") // Doesn't detect lambda with correct nullability\n\t\tvoid jsonMembers(Members<?> members) {\n\t\t\tmembers.add(\"service\").usingMembers((service) -> {\n\t\t\t\tservice.add(\"name\", this::name).whenHasLength();\n\t\t\t\tservice.add(\"version\", this::version).whenHasLength();\n\t\t\t\tservice.add(\"environment\", this::environment).whenHasLength();\n\t\t\t\tservice.add(\"node\").usingMembers((node) -> node.add(\"name\", this::nodeName).whenHasLength());\n\t\t\t});\n\t\t}\n\n\t\tService withDefaults(Environment environment) {\n\t\t\tString name = withFallbackProperty(environment, this.name, \"spring.application.name\");\n\t\t\tString version = withFallbackProperty(environment, this.version, \"spring.application.version\");\n\t\t\treturn new Service(name, version, this.environment, this.nodeName);\n\t\t}\n\n\t}\n\n\tstatic class ElasticCommonSchemaPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tBindableRuntimeHintsRegistrar.forTypes(ElasticCommonSchemaProperties.class)\n\t\t\t\t.registerHints(hints, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/GraylogExtendedLogFormatProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * Service details for Graylog Extended Log Format structured logging.\n *\n * @param host the application name\n * @param service the version of the application\n * @author Samuel Lissner\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic record GraylogExtendedLogFormatProperties(@Nullable String host, Service service) {\n\n\tstatic final GraylogExtendedLogFormatProperties NONE = new GraylogExtendedLogFormatProperties(null, null);\n\n\tpublic GraylogExtendedLogFormatProperties(@Nullable String host, @Nullable Service service) {\n\t\tthis.host = host;\n\t\tthis.service = (service != null) ? service : Service.NONE;\n\t}\n\n\tGraylogExtendedLogFormatProperties withDefaults(Environment environment) {\n\t\tString name = withFallbackProperty(environment, this.host, \"spring.application.name\");\n\t\tService service = this.service.withDefaults(environment);\n\t\treturn new GraylogExtendedLogFormatProperties(name, service);\n\t}\n\n\tstatic @Nullable String withFallbackProperty(Environment environment, @Nullable String value, String property) {\n\t\treturn (!StringUtils.hasLength(value)) ? environment.getProperty(property) : value;\n\t}\n\n\t/**\n\t * Add {@link JsonWriter} members for the service.\n\t * @param members the members to add to\n\t */\n\t@SuppressWarnings(\"NullAway\") // Doesn't detect lambda with correct nullability\n\tpublic void jsonMembers(JsonWriter.Members<?> members) {\n\t\tmembers.add(\"host\", this::host).whenHasLength();\n\t\tthis.service.jsonMembers(members);\n\t}\n\n\t/**\n\t * Return a new {@link GraylogExtendedLogFormatProperties} from bound from properties\n\t * in the given {@link Environment}.\n\t * @param environment the source environment\n\t * @return a new {@link GraylogExtendedLogFormatProperties} instance\n\t */\n\tpublic static GraylogExtendedLogFormatProperties get(Environment environment) {\n\t\treturn Binder.get(environment)\n\t\t\t.bind(\"logging.structured.gelf\", GraylogExtendedLogFormatProperties.class)\n\t\t\t.orElse(NONE)\n\t\t\t.withDefaults(environment);\n\t}\n\n\t/**\n\t * Service details.\n\t *\n\t * @param version the version of the application\n\t */\n\tpublic record Service(@Nullable String version) {\n\n\t\tstatic final Service NONE = new Service(null);\n\n\t\tService withDefaults(Environment environment) {\n\t\t\tString version = withFallbackProperty(environment, this.version, \"spring.application.version\");\n\t\t\treturn new Service(version);\n\t\t}\n\n\t\t@SuppressWarnings(\"NullAway\") // Doesn't detect lambda with correct nullability\n\t\tvoid jsonMembers(JsonWriter.Members<?> members) {\n\t\t\tmembers.add(\"_service_version\", this::version).whenHasLength();\n\t\t}\n\n\t}\n\n\tstatic class GraylogExtendedLogFormatPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tBindableRuntimeHintsRegistrar.forTypes(GraylogExtendedLogFormatProperties.class)\n\t\t\t\t.registerHints(hints, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/JsonWriterStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.nio.charset.Charset;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.util.LambdaSafe;\n\n/**\n * Base class for {@link StructuredLogFormatter} implementations that generates JSON using\n * a {@link JsonWriter}.\n *\n * @param <E> the log event type\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic abstract class JsonWriterStructuredLogFormatter<E> implements StructuredLogFormatter<E> {\n\n\tprivate final JsonWriter<E> jsonWriter;\n\n\t/**\n\t * Create a new {@link JsonWriterStructuredLogFormatter} instance with the given\n\t * members.\n\t * @param members a consumer, which should configure the members\n\t * @param customizer an optional customizer to apply\n\t */\n\tprotected JsonWriterStructuredLogFormatter(Consumer<Members<E>> members,\n\t\t\t@Nullable StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\tthis(JsonWriter.of(customized(members, customizer)).withNewLineAtEnd());\n\t}\n\n\tprivate static <E> Consumer<Members<E>> customized(Consumer<Members<E>> members,\n\t\t\t@Nullable StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\treturn (customizer != null) ? members.andThen(customizeWith(customizer)) : members;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <E> Consumer<Members<E>> customizeWith(StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\treturn (members) -> LambdaSafe.callback(StructuredLoggingJsonMembersCustomizer.class, customizer, members)\n\t\t\t.invoke((instance) -> instance.customize(members));\n\t}\n\n\t/**\n\t * Create a new {@link JsonWriterStructuredLogFormatter} instance with the given\n\t * {@link JsonWriter}.\n\t * @param jsonWriter the {@link JsonWriter}\n\t */\n\tprotected JsonWriterStructuredLogFormatter(JsonWriter<E> jsonWriter) {\n\t\tthis.jsonWriter = jsonWriter;\n\t}\n\n\t@Override\n\tpublic String format(E event) {\n\t\treturn this.jsonWriter.writeToString(event);\n\t}\n\n\t@Override\n\tpublic byte[] formatAsBytes(E event, Charset charset) {\n\t\treturn this.jsonWriter.write(event).toByteArray(charset);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.nio.charset.Charset;\n\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.core.env.Environment;\n\n/**\n * Formats a log event to a structured log message.\n * <p>\n * Implementing classes can declare the following parameter types in the constructor:\n * <ul>\n * <li>{@link Environment}</li>\n * <li>{@link StructuredLoggingJsonMembersCustomizer}</li>\n * <li>{@link StructuredLoggingJsonMembersCustomizer.Builder}</li>\n * <li>{@link StackTracePrinter} (may be {@code null})</li>\n * <li>{@link ContextPairs}</li>\n * </ul>\n * When using Logback, implementing classes can also use the following parameter types in\n * the constructor:\n * <ul>\n * <li>{@code ch.qos.logback.classic.pattern.ThrowableProxyConverter}</li>\n * </ul>\n *\n * @param <E> the log event type\n * @author Moritz Halbritter\n * @since 3.4.0\n */\n@FunctionalInterface\npublic interface StructuredLogFormatter<E> {\n\n\t/**\n\t * Formats the given log event to a String.\n\t * @param event the log event to write\n\t * @return the formatted log event String\n\t */\n\tString format(E event);\n\n\t/**\n\t * Formats the given log event to a byte array.\n\t * @param event the log event to write\n\t * @param charset the charset\n\t * @return the formatted log event bytes\n\t */\n\tdefault byte[] formatAsBytes(E event, Charset charset) {\n\t\treturn format(event).getBytes(charset);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.Context;\nimport org.springframework.boot.util.Instantiator;\nimport org.springframework.boot.util.Instantiator.AvailableParameters;\nimport org.springframework.boot.util.Instantiator.FailureHandler;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.core.GenericTypeResolver;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.util.Assert;\n\n/**\n * Factory that can be used to create a fully instantiated {@link StructuredLogFormatter}\n * for either a {@link CommonStructuredLogFormat#getId() common format} or a\n * fully-qualified class name.\n *\n * @param <E> the log even type\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 3.4.0\n * @see StructuredLogFormatter\n */\npublic class StructuredLogFormatterFactory<E> {\n\n\tprivate static final FailureHandler failureHandler = (type, implementationName, failure) -> {\n\t\tif (!(failure instanceof ClassNotFoundException)) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Unable to instantiate \" + implementationName + \" [\" + type.getName() + \"]\", failure);\n\t\t}\n\t};\n\n\tprivate final SpringFactoriesLoader factoriesLoader;\n\n\tprivate final Class<E> logEventType;\n\n\tprivate final Instantiator<?> instantiator;\n\n\tprivate final CommonFormatters<E> commonFormatters;\n\n\t/**\n\t * Create a new {@link StructuredLogFormatterFactory} instance.\n\t * @param logEventType the log event type\n\t * @param environment the Spring {@link Environment}\n\t * @param availableParameters callback used to configure available parameters for the\n\t * specific logging system\n\t * @param commonFormatters callback used to define supported common formatters\n\t */\n\tpublic StructuredLogFormatterFactory(Class<E> logEventType, Environment environment,\n\t\t\t@Nullable Consumer<AvailableParameters> availableParameters,\n\t\t\tConsumer<CommonFormatters<E>> commonFormatters) {\n\t\tthis(SpringFactoriesLoader.forDefaultResourceLocation(), logEventType, environment, availableParameters,\n\t\t\t\tcommonFormatters);\n\t}\n\n\tStructuredLogFormatterFactory(SpringFactoriesLoader factoriesLoader, Class<E> logEventType, Environment environment,\n\t\t\t@Nullable Consumer<AvailableParameters> availableParameters,\n\t\t\tConsumer<CommonFormatters<E>> commonFormatters) {\n\t\tStructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);\n\t\tthis.factoriesLoader = factoriesLoader;\n\t\tthis.logEventType = logEventType;\n\t\tthis.instantiator = new Instantiator<>(Object.class, (allAvailableParameters) -> {\n\t\t\tallAvailableParameters.add(Environment.class, environment);\n\t\t\tallAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.class,\n\t\t\t\t\tnew JsonMembersCustomizerBuilder(properties).build());\n\t\t\tallAvailableParameters.add(StructuredLoggingJsonMembersCustomizer.Builder.class,\n\t\t\t\t\tnew JsonMembersCustomizerBuilder(properties));\n\t\t\tallAvailableParameters.add(StackTracePrinter.class, (type) -> getStackTracePrinter(properties));\n\t\t\tallAvailableParameters.add(ContextPairs.class, (type) -> getContextPairs(properties));\n\t\t\tif (availableParameters != null) {\n\t\t\t\tavailableParameters.accept(allAvailableParameters);\n\t\t\t}\n\t\t}, failureHandler);\n\t\tthis.commonFormatters = new CommonFormatters<>();\n\t\tcommonFormatters.accept(this.commonFormatters);\n\t}\n\n\tprivate @Nullable StackTracePrinter getStackTracePrinter(@Nullable StructuredLoggingJsonProperties properties) {\n\t\treturn (properties != null && properties.stackTrace() != null) ? properties.stackTrace().createPrinter() : null;\n\t}\n\n\tprivate ContextPairs getContextPairs(@Nullable StructuredLoggingJsonProperties properties) {\n\t\tContext contextProperties = (properties != null) ? properties.context() : null;\n\t\tcontextProperties = (contextProperties != null) ? contextProperties : new Context(true, null);\n\t\treturn new ContextPairs(contextProperties.include(), contextProperties.prefix());\n\t}\n\n\t/**\n\t * Get a new {@link StructuredLogFormatter} instance for the specified format.\n\t * @param format the format requested (either a {@link CommonStructuredLogFormat} ID\n\t * or a fully-qualified class name)\n\t * @return a new {@link StructuredLogFormatter} instance\n\t * @throws IllegalArgumentException if the format is unknown\n\t */\n\tpublic StructuredLogFormatter<E> get(String format) {\n\t\tStructuredLogFormatter<E> formatter = this.commonFormatters.get(this.instantiator, format);\n\t\tformatter = (formatter != null) ? formatter : getUsingClassName(format);\n\t\tif (formatter != null) {\n\t\t\treturn formatter;\n\t\t}\n\t\tthrow new IllegalArgumentException(\n\t\t\t\t\"Unknown format '%s'. Values can be a valid fully-qualified class name or one of the common formats: %s\"\n\t\t\t\t\t.formatted(format, this.commonFormatters.getCommonNames()));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate @Nullable StructuredLogFormatter<E> getUsingClassName(String className) {\n\t\tObject formatter = this.instantiator.instantiate(className);\n\t\tif (formatter != null) {\n\t\t\tAssert.state(formatter instanceof StructuredLogFormatter,\n\t\t\t\t\t() -> \"'%s' is not a StructuredLogFormatter\".formatted(className));\n\t\t\tcheckTypeArgument(formatter);\n\t\t}\n\t\treturn (StructuredLogFormatter<E>) formatter;\n\t}\n\n\tprivate void checkTypeArgument(Object formatter) {\n\t\tClass<?> typeArgument = GenericTypeResolver.resolveTypeArgument(formatter.getClass(),\n\t\t\t\tStructuredLogFormatter.class);\n\t\tAssert.state(this.logEventType.equals(typeArgument),\n\t\t\t\t() -> \"Type argument of %s must be %s but was %s\".formatted(formatter.getClass().getName(),\n\t\t\t\t\t\tthis.logEventType.getName(), (typeArgument != null) ? typeArgument.getName() : \"null\"));\n\n\t}\n\n\t/**\n\t * Callback used for configure the {@link CommonFormatterFactory} to use for a given\n\t * {@link CommonStructuredLogFormat}.\n\t *\n\t * @param <E> the log event type\n\t */\n\tpublic static class CommonFormatters<E> {\n\n\t\tprivate final Map<CommonStructuredLogFormat, CommonFormatterFactory<E>> factories = new TreeMap<>();\n\n\t\t/**\n\t\t * Add the factory that should be used for the given\n\t\t * {@link CommonStructuredLogFormat}.\n\t\t * @param format the common structured log format\n\t\t * @param factory the factory to use\n\t\t */\n\t\tpublic void add(CommonStructuredLogFormat format, CommonFormatterFactory<E> factory) {\n\t\t\tthis.factories.put(format, factory);\n\t\t}\n\n\t\tCollection<String> getCommonNames() {\n\t\t\treturn this.factories.keySet().stream().map(CommonStructuredLogFormat::getId).toList();\n\t\t}\n\n\t\t@Nullable StructuredLogFormatter<E> get(Instantiator<?> instantiator, String format) {\n\t\t\tCommonStructuredLogFormat commonFormat = CommonStructuredLogFormat.forId(format);\n\t\t\tCommonFormatterFactory<E> factory = (commonFormat != null) ? this.factories.get(commonFormat) : null;\n\t\t\treturn (factory != null) ? factory.createFormatter(instantiator) : null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Factory used to create a {@link StructuredLogFormatter} for a given\n\t * {@link CommonStructuredLogFormat}.\n\t *\n\t * @param <E> the log event type\n\t */\n\t@FunctionalInterface\n\tpublic interface CommonFormatterFactory<E> {\n\n\t\t/**\n\t\t * Create the {@link StructuredLogFormatter} instance.\n\t\t * @param instantiator instantiator that can be used to obtain arguments\n\t\t * @return a new {@link StructuredLogFormatter} instance\n\t\t */\n\t\tStructuredLogFormatter<E> createFormatter(Instantiator<?> instantiator);\n\n\t}\n\n\t/**\n\t * {@link StructuredLoggingJsonMembersCustomizer.Builder} implementation.\n\t */\n\tclass JsonMembersCustomizerBuilder implements StructuredLoggingJsonMembersCustomizer.Builder<E> {\n\n\t\tprivate final @Nullable StructuredLoggingJsonProperties properties;\n\n\t\tprivate boolean nested;\n\n\t\tJsonMembersCustomizerBuilder(@Nullable StructuredLoggingJsonProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic JsonMembersCustomizerBuilder nested(boolean nested) {\n\t\t\tthis.nested = nested;\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic StructuredLoggingJsonMembersCustomizer<E> build() {\n\t\t\treturn (members) -> {\n\t\t\t\tList<StructuredLoggingJsonMembersCustomizer<?>> customizers = new ArrayList<>();\n\t\t\t\tif (this.properties != null) {\n\t\t\t\t\tcustomizers.add(new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\t\t\t\tStructuredLogFormatterFactory.this.instantiator, this.properties, this.nested));\n\t\t\t\t}\n\t\t\t\tcustomizers.addAll(loadStructuredLoggingJsonMembersCustomizers());\n\t\t\t\tinvokeCustomizers(members, customizers);\n\t\t\t};\n\t\t}\n\n\t\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t\tprivate List<StructuredLoggingJsonMembersCustomizer<?>> loadStructuredLoggingJsonMembersCustomizers() {\n\t\t\treturn (List) StructuredLogFormatterFactory.this.factoriesLoader.load(\n\t\t\t\t\tStructuredLoggingJsonMembersCustomizer.class,\n\t\t\t\t\tArgumentResolver.from(StructuredLogFormatterFactory.this.instantiator::getArg));\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate void invokeCustomizers(Members<E> members,\n\t\t\t\tList<StructuredLoggingJsonMembersCustomizer<?>> customizers) {\n\t\t\tLambdaSafe.callbacks(StructuredLoggingJsonMembersCustomizer.class, customizers, members)\n\t\t\t\t.withFilter(LambdaSafe.Filter.allowAll())\n\t\t\t\t.invoke((customizer) -> customizer.customize(members));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonMembersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.core.env.Environment;\n\n/**\n * Customizer that can be injected into {@link StructuredLogFormatter} implementations to\n * customize {@link JsonWriter} {@link Members}.\n * <p>\n * An implementation may be provided using the {@code logging.structured.json.customizer}\n * property. Alternatively, implementations can be registered in\n * {@code META-INF/spring.factories} under the key\n * {@code org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer}.\n * <p>\n * Implementing classes can declare the following parameter types in the constructor:\n * <ul>\n * <li>{@link Environment}</li>\n * </ul>\n * When using Logback, implementing classes can also use the following parameter types in\n * the constructor:\n * <ul>\n * <li>{@code ch.qos.logback.classic.pattern.ThrowableProxyConverter}</li>\n * </ul>\n *\n * @param <T> the type being written\n * @author Phillip Webb\n * @since 3.4.0\n * @see JsonWriterStructuredLogFormatter\n */\n@FunctionalInterface\npublic interface StructuredLoggingJsonMembersCustomizer<T> {\n\n\t/**\n\t * Customize the given {@link Members} instance.\n\t * @param members the members instance to customize\n\t */\n\tvoid customize(JsonWriter.Members<T> members);\n\n\t/**\n\t * Builder that can be injected into a {@link StructuredLogFormatter} to build the\n\t * {@link StructuredLoggingJsonMembersCustomizer} when specific settings are required.\n\t *\n\t * @param <T> the type being written\n\t * @since 3.5.4\n\t */\n\tinterface Builder<T> {\n\n\t\t/**\n\t\t * Use nested fields when adding JSON from user defined properties.\n\t\t * @return this builder\n\t\t */\n\t\tdefault Builder<T> nested() {\n\t\t\treturn nested(true);\n\t\t}\n\n\t\t/**\n\t\t * Set if nested fields should be used when adding JSON from user defined\n\t\t * properties.\n\t\t * @param nested if nested fields are to be used\n\t\t * @return this builder\n\t\t */\n\t\tBuilder<T> nested(boolean nested);\n\n\t\t/**\n\t\t * Build the {@link StructuredLoggingJsonMembersCustomizer}.\n\t\t * @return the built customizer\n\t\t */\n\t\tStructuredLoggingJsonMembersCustomizer<T> build();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.BiFunction;\nimport java.util.function.UnaryOperator;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.StandardStackTracePrinter;\nimport org.springframework.boot.util.Instantiator;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * Properties that can be used to customize structured logging JSON.\n *\n * @param include the paths that should be included. An empty set includes all names\n * @param exclude the paths that should be excluded. An empty set excludes nothing\n * @param rename a map of path to replacement names\n * @param add a map of additional elements {@link StructuredLoggingJsonMembersCustomizer}\n * @param stackTrace stack trace properties\n * @param customizer the fully qualified names of\n * {@link StructuredLoggingJsonMembersCustomizer} implementations\n * @param context context specific properties\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nrecord StructuredLoggingJsonProperties(Set<String> include, Set<String> exclude, Map<String, String> rename,\n\t\tMap<String, String> add, @Nullable StackTrace stackTrace, @Nullable Context context,\n\t\tSet<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer) {\n\n\tStructuredLoggingJsonProperties(Set<String> include, Set<String> exclude, Map<String, String> rename,\n\t\t\tMap<String, String> add, @Nullable StackTrace stackTrace, @Nullable Context context,\n\t\t\t@Nullable Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizer) {\n\t\tthis.include = include;\n\t\tthis.exclude = exclude;\n\t\tthis.rename = rename;\n\t\tthis.add = add;\n\t\tthis.stackTrace = stackTrace;\n\t\tthis.context = context;\n\t\tthis.customizer = (customizer != null) ? customizer : Collections.emptySet();\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tCollection<StructuredLoggingJsonMembersCustomizer<Object>> customizers(Instantiator<?> instantiator) {\n\t\treturn (List) customizer().stream().map(instantiator::instantiateType).toList();\n\t}\n\n\tstatic @Nullable StructuredLoggingJsonProperties get(Environment environment) {\n\t\treturn Binder.get(environment)\n\t\t\t.bind(\"logging.structured.json\", StructuredLoggingJsonProperties.class)\n\t\t\t.orElse(null);\n\t}\n\n\t/**\n\t * Properties to influence stack trace printing.\n\t *\n\t * @param printer the name of the printer to use. Can be {@code null},\n\t * {@code \"standard\"}, {@code \"logging-system\"}, or the fully-qualified class name of\n\t * a {@link StackTracePrinter} implementation. A {@code null} value will be treated as\n\t * {@code \"standard\"} when any other property is set, otherwise it will be treated as\n\t * {@code \"logging-system\"}. {@link StackTracePrinter} implementations may optionally\n\t * inject a {@link StandardStackTracePrinter} instance into their constructor which\n\t * will be configured from the properties.\n\t * @param root the root ordering (root first or root last)\n\t * @param maxLength the maximum length to print\n\t * @param maxThrowableDepth the maximum throwable depth to print\n\t * @param includeCommonFrames whether common frames should be included\n\t * @param includeHashes whether stack trace hashes should be included\n\t */\n\trecord StackTrace(@Nullable String printer, @Nullable Root root, @Nullable Integer maxLength,\n\t\t\t@Nullable Integer maxThrowableDepth, @Nullable Boolean includeCommonFrames,\n\t\t\t@Nullable Boolean includeHashes) {\n\n\t\t@Nullable StackTracePrinter createPrinter() {\n\t\t\tString name = sanitizePrinter();\n\t\t\tif (\"loggingsystem\".equals(name) || (name.isEmpty() && !hasAnyOtherProperty())) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tStandardStackTracePrinter standardPrinter = createStandardPrinter();\n\t\t\tif (\"standard\".equals(name) || name.isEmpty()) {\n\t\t\t\treturn standardPrinter;\n\t\t\t}\n\t\t\tAssert.state(printer() != null, \"'printer' must not be null\");\n\t\t\treturn (StackTracePrinter) new Instantiator<>(StackTracePrinter.class,\n\t\t\t\t\t(parameters) -> parameters.add(StandardStackTracePrinter.class, standardPrinter))\n\t\t\t\t.instantiate(printer());\n\t\t}\n\n\t\tboolean hasCustomPrinter() {\n\t\t\tString name = sanitizePrinter();\n\t\t\tif (name.isEmpty()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn !(\"loggingsystem\".equals(name) || \"standard\".equals(name));\n\t\t}\n\n\t\tprivate String sanitizePrinter() {\n\t\t\treturn Objects.toString(printer(), \"\").toLowerCase(Locale.ROOT).replace(\"-\", \"\");\n\t\t}\n\n\t\tprivate boolean hasAnyOtherProperty() {\n\t\t\treturn Stream.of(root(), maxLength(), maxThrowableDepth(), includeCommonFrames(), includeHashes())\n\t\t\t\t.anyMatch(Objects::nonNull);\n\t\t}\n\n\t\tprivate StandardStackTracePrinter createStandardPrinter() {\n\t\t\tStandardStackTracePrinter printer = (root() == Root.FIRST) ? StandardStackTracePrinter.rootFirst()\n\t\t\t\t\t: StandardStackTracePrinter.rootLast();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tprinter = map.from(this::maxLength).to(printer, StandardStackTracePrinter::withMaximumLength);\n\t\t\tprinter = map.from(this::maxThrowableDepth)\n\t\t\t\t.to(printer, StandardStackTracePrinter::withMaximumThrowableDepth);\n\t\t\tprinter = map.from(this::includeCommonFrames)\n\t\t\t\t.to(printer, apply(StandardStackTracePrinter::withCommonFrames));\n\t\t\tprinter = map.from(this::includeHashes).to(printer, apply(StandardStackTracePrinter::withHashes));\n\t\t\treturn printer;\n\t\t}\n\n\t\tprivate BiFunction<StandardStackTracePrinter, Boolean, StandardStackTracePrinter> apply(\n\t\t\t\tUnaryOperator<StandardStackTracePrinter> action) {\n\t\t\treturn (printer, value) -> (!value) ? printer : action.apply(printer);\n\t\t}\n\n\t\t/**\n\t\t * Root ordering.\n\t\t */\n\t\tenum Root {\n\n\t\t\tLAST, FIRST\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Properties that influence context values (usually elements propagated from the\n\t * logging MDC).\n\t *\n\t * @param include if context elements should be included\n\t * @param prefix the prefix to use for context elements\n\t * @since 3.5.0\n\t */\n\trecord Context(@DefaultValue(\"true\") boolean include, @Nullable String prefix) {\n\n\t}\n\n\tstatic class StructuredLoggingJsonPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tBindableRuntimeHintsRegistrar.forTypes(StructuredLoggingJsonProperties.class)\n\t\t\t\t.registerHints(hints, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link BeanFactoryInitializationAotProcessor} that registers {@link RuntimeHints} for\n * {@link StructuredLoggingJsonProperties}.\n *\n * @author Dmytro Nosan\n * @author Yanming Zhou\n * @author Phillip Webb\n */\nclass StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor\n\t\timplements BeanFactoryInitializationAotProcessor {\n\n\tprivate static final String ENVIRONMENT_BEAN_NAME = \"environment\";\n\n\t@Override\n\tpublic @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(\n\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\tEnvironment environment = beanFactory.getBean(ENVIRONMENT_BEAN_NAME, Environment.class);\n\t\tStructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);\n\t\tif (properties != null) {\n\t\t\tSet<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers = properties.customizer();\n\t\t\tString stackTracePrinter = getCustomStackTracePrinter(properties);\n\t\t\tif (stackTracePrinter != null || !customizers.isEmpty()) {\n\t\t\t\treturn new AotContribution(beanFactory.getBeanClassLoader(), customizers, stackTracePrinter);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static @Nullable String getCustomStackTracePrinter(StructuredLoggingJsonProperties properties) {\n\t\tStackTrace stackTrace = properties.stackTrace();\n\t\treturn (stackTrace != null && stackTrace.hasCustomPrinter()) ? stackTrace.printer() : null;\n\t}\n\n\tprivate static final class AotContribution implements BeanFactoryInitializationAotContribution {\n\n\t\tprivate final @Nullable ClassLoader classLoader;\n\n\t\tprivate final Set<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers;\n\n\t\tprivate final @Nullable String stackTracePrinter;\n\n\t\tprivate AotContribution(@Nullable ClassLoader classLoader,\n\t\t\t\tSet<Class<? extends StructuredLoggingJsonMembersCustomizer<?>>> customizers,\n\t\t\t\t@Nullable String stackTracePrinter) {\n\t\t\tthis.classLoader = classLoader;\n\t\t\tthis.customizers = customizers;\n\t\t\tthis.stackTracePrinter = stackTracePrinter;\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\tReflectionHints reflection = generationContext.getRuntimeHints().reflection();\n\t\t\tthis.customizers.forEach((customizer) -> reflection.registerType(customizer,\n\t\t\t\t\tMemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));\n\t\t\tif (this.stackTracePrinter != null) {\n\t\t\t\treflection.registerTypeIfPresent(this.classLoader, this.stackTracePrinter,\n\t\t\t\t\t\tMemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesJsonMembersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.Map;\n\nimport org.springframework.boot.json.JsonWriter.MemberPath;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.util.Instantiator;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link StructuredLoggingJsonMembersCustomizer} to apply\n * {@link StructuredLoggingJsonProperties}.\n *\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nclass StructuredLoggingJsonPropertiesJsonMembersCustomizer implements StructuredLoggingJsonMembersCustomizer<Object> {\n\n\tprivate final Instantiator<?> instantiator;\n\n\tprivate final StructuredLoggingJsonProperties properties;\n\n\tprivate final boolean nested;\n\n\tStructuredLoggingJsonPropertiesJsonMembersCustomizer(Instantiator<?> instantiator,\n\t\t\tStructuredLoggingJsonProperties properties, boolean nested) {\n\t\tthis.instantiator = instantiator;\n\t\tthis.properties = properties;\n\t\tthis.nested = nested;\n\t}\n\n\t@Override\n\tpublic void customize(Members<Object> members) {\n\t\tmembers.applyingPathFilter(this::filterPath);\n\t\tmembers.applyingNameProcessor(this::renameJsonMembers);\n\t\tMap<String, String> add = this.properties.add();\n\t\tif (!CollectionUtils.isEmpty(add)) {\n\t\t\tif (this.nested) {\n\t\t\t\tContextPairs contextPairs = new ContextPairs(true, \"\");\n\t\t\t\tmembers.add().usingPairs(contextPairs.nested((pairs) -> pairs.addMapEntries((source) -> add)));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tadd.forEach(members::add);\n\t\t\t}\n\t\t}\n\t\tthis.properties.customizers(this.instantiator).forEach((customizer) -> customizer.customize(members));\n\t}\n\n\tString renameJsonMembers(MemberPath path, String existingName) {\n\t\tMap<String, String> rename = this.properties.rename();\n\t\tString key = path.toUnescapedString();\n\t\treturn !CollectionUtils.isEmpty(rename) ? rename.getOrDefault(key, existingName) : existingName;\n\t}\n\n\tboolean filterPath(MemberPath path) {\n\t\tboolean included = CollectionUtils.isEmpty(this.properties.include())\n\t\t\t\t|| this.properties.include().contains(path.toUnescapedString());\n\t\tboolean excluded = !CollectionUtils.isEmpty(this.properties.exclude())\n\t\t\t\t&& this.properties.exclude().contains(path.toUnescapedString());\n\t\treturn (!included || excluded);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/logging/structured/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for structured logging.\n */\n@NullMarked\npackage org.springframework.boot.logging.structured;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/JarUri.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.net.URI;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Simple class that understands Jar URLs and can provide short descriptions.\n *\n * @author Phillip Webb\n */\nfinal class JarUri {\n\n\tprivate static final String JAR_SCHEME = \"jar:\";\n\n\tprivate static final String JAR_EXTENSION = \".jar\";\n\n\tprivate final String uri;\n\n\tprivate final String description;\n\n\tprivate JarUri(String uri) {\n\t\tthis.uri = uri;\n\t\tthis.description = extractDescription(uri);\n\t}\n\n\tprivate String extractDescription(String uri) {\n\t\turi = uri.substring(JAR_SCHEME.length());\n\t\tint firstDotJar = uri.indexOf(JAR_EXTENSION);\n\t\tString firstJar = getFilename(uri.substring(0, firstDotJar + JAR_EXTENSION.length()));\n\t\turi = uri.substring(firstDotJar + JAR_EXTENSION.length());\n\t\tint lastDotJar = uri.lastIndexOf(JAR_EXTENSION);\n\t\tif (lastDotJar == -1) {\n\t\t\treturn firstJar;\n\t\t}\n\t\treturn firstJar + uri.substring(0, lastDotJar + JAR_EXTENSION.length());\n\t}\n\n\tprivate String getFilename(String string) {\n\t\tint lastSlash = string.lastIndexOf('/');\n\t\treturn (lastSlash == -1) ? string : string.substring(lastSlash + 1);\n\t}\n\n\tString getDescription() {\n\t\treturn this.description;\n\t}\n\n\tString getDescription(String existing) {\n\t\treturn existing + \" from \" + this.description;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.uri;\n\t}\n\n\tstatic @Nullable JarUri from(URI uri) {\n\t\treturn from(uri.toString());\n\t}\n\n\tstatic @Nullable JarUri from(String uri) {\n\t\tif (uri.startsWith(JAR_SCHEME) && uri.contains(JAR_EXTENSION)) {\n\t\t\treturn new JarUri(uri);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/Origin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Interface that uniquely represents the origin of an item. For example, an item loaded\n * from a {@link File} may have an origin made up of the file name along with line/column\n * numbers.\n * <p>\n * Implementations must provide sensible {@code hashCode()}, {@code equals(...)} and\n * {@code #toString()} implementations.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.0.0\n * @see OriginProvider\n * @see TextResourceOrigin\n */\npublic interface Origin {\n\n\t/**\n\t * Return the parent origin for this instance if there is one. The parent origin\n\t * provides the origin of the item that created this one.\n\t * @return the parent origin or {@code null}\n\t * @since 2.4.0\n\t * @see Origin#parentsFrom(Object)\n\t */\n\tdefault @Nullable Origin getParent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Find the {@link Origin} that an object originated from. Checks if the source object\n\t * is an {@link Origin} or {@link OriginProvider} and also searches exception stacks.\n\t * @param source the source object or {@code null}\n\t * @return an {@link Origin} or {@code null}\n\t */\n\tstatic @Nullable Origin from(@Nullable Object source) {\n\t\tif (source instanceof Origin origin) {\n\t\t\treturn origin;\n\t\t}\n\t\tOrigin origin = null;\n\t\tif (source instanceof OriginProvider originProvider) {\n\t\t\torigin = originProvider.getOrigin();\n\t\t}\n\t\tif (origin == null && source instanceof Throwable throwable) {\n\t\t\treturn from(throwable.getCause());\n\t\t}\n\t\treturn origin;\n\t}\n\n\t/**\n\t * Find the parents of the {@link Origin} that an object originated from. Checks if\n\t * the source object is an {@link Origin} or {@link OriginProvider} and also searches\n\t * exception stacks. Provides a list of all parents up to root {@link Origin},\n\t * starting with the most immediate parent.\n\t * @param source the source object or {@code null}\n\t * @return a list of parents or an empty list if the source is {@code null}, has no\n\t * origin, or no parent\n\t * @since 2.4.0\n\t */\n\tstatic List<Origin> parentsFrom(@Nullable Object source) {\n\t\tOrigin origin = from(source);\n\t\tif (origin == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tSet<Origin> parents = new LinkedHashSet<>();\n\t\torigin = origin.getParent();\n\t\twhile (origin != null && !parents.contains(origin)) {\n\t\t\tparents.add(origin);\n\t\t\torigin = origin.getParent();\n\t\t}\n\t\treturn Collections.unmodifiableList(new ArrayList<>(parents));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/OriginLookup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * An interface that may be implemented by an object that can lookup {@link Origin}\n * information from a given key. Can be used to add origin support to existing classes.\n *\n * @param <K> the lookup key type\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface OriginLookup<K> {\n\n\t/**\n\t * Return the origin of the given key or {@code null} if the origin cannot be\n\t * determined.\n\t * @param key the key to lookup\n\t * @return the origin of the key or {@code null}\n\t */\n\t@Nullable Origin getOrigin(K key);\n\n\t/**\n\t * Attempt to look up the origin from the given source. If the source is not a\n\t * {@link OriginLookup} or if an exception occurs during lookup then {@code null} is\n\t * returned.\n\t * @param source the source object\n\t * @param key the key to lookup\n\t * @param <K> the key type\n\t * @return an {@link Origin} or {@code null}\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <K> @Nullable Origin getOrigin(@Nullable Object source, K key) {\n\t\tif (!(source instanceof OriginLookup)) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn ((OriginLookup<K>) source).getOrigin(key);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/OriginProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Interface to provide access to the origin of an item.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see Origin\n */\n@FunctionalInterface\npublic interface OriginProvider {\n\n\t/**\n\t * Return the source origin or {@code null} if the origin is not known.\n\t * @return the origin or {@code null}\n\t */\n\t@Nullable Origin getOrigin();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/OriginTrackedResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.channels.ReadableByteChannel;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.WritableResource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Decorator that can be used to add {@link Origin} information to a {@link Resource} or\n * {@link WritableResource}.\n *\n * @author Phillip Webb\n * @since 2.4.0\n * @see #of(Resource, Origin)\n * @see #of(WritableResource, Origin)\n * @see OriginProvider\n */\npublic class OriginTrackedResource implements Resource, OriginProvider {\n\n\tprivate final Resource resource;\n\n\tprivate final @Nullable Origin origin;\n\n\t/**\n\t * Create a new {@link OriginTrackedResource} instance.\n\t * @param resource the resource to track\n\t * @param origin the origin of the resource\n\t */\n\tOriginTrackedResource(Resource resource, @Nullable Origin origin) {\n\t\tAssert.notNull(resource, \"'resource' must not be null\");\n\t\tthis.resource = resource;\n\t\tthis.origin = origin;\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream() throws IOException {\n\t\treturn getResource().getInputStream();\n\t}\n\n\t@Override\n\tpublic boolean exists() {\n\t\treturn getResource().exists();\n\t}\n\n\t@Override\n\tpublic boolean isReadable() {\n\t\treturn getResource().isReadable();\n\t}\n\n\t@Override\n\tpublic boolean isOpen() {\n\t\treturn getResource().isOpen();\n\t}\n\n\t@Override\n\tpublic boolean isFile() {\n\t\treturn getResource().isFile();\n\t}\n\n\t@Override\n\tpublic URL getURL() throws IOException {\n\t\treturn getResource().getURL();\n\t}\n\n\t@Override\n\tpublic URI getURI() throws IOException {\n\t\treturn getResource().getURI();\n\t}\n\n\t@Override\n\tpublic File getFile() throws IOException {\n\t\treturn getResource().getFile();\n\t}\n\n\t@Override\n\tpublic ReadableByteChannel readableChannel() throws IOException {\n\t\treturn getResource().readableChannel();\n\t}\n\n\t@Override\n\tpublic long contentLength() throws IOException {\n\t\treturn getResource().contentLength();\n\t}\n\n\t@Override\n\tpublic long lastModified() throws IOException {\n\t\treturn getResource().lastModified();\n\t}\n\n\t@Override\n\tpublic Resource createRelative(String relativePath) throws IOException {\n\t\treturn getResource().createRelative(relativePath);\n\t}\n\n\t@Override\n\tpublic @Nullable String getFilename() {\n\t\treturn getResource().getFilename();\n\t}\n\n\t@Override\n\tpublic String getDescription() {\n\t\treturn getResource().getDescription();\n\t}\n\n\tpublic Resource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tOriginTrackedResource other = (OriginTrackedResource) obj;\n\t\treturn this.resource.equals(other) && ObjectUtils.nullSafeEquals(this.origin, other.origin);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = this.resource.hashCode();\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.origin);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.resource.toString();\n\t}\n\n\t/**\n\t * Return a new {@link OriginProvider origin tracked} version the given\n\t * {@link WritableResource}.\n\t * @param resource the tracked resource\n\t * @param origin the origin of the resource\n\t * @return an {@link OriginTrackedWritableResource} instance\n\t */\n\tpublic static OriginTrackedWritableResource of(WritableResource resource, Origin origin) {\n\t\treturn (OriginTrackedWritableResource) of((Resource) resource, origin);\n\t}\n\n\t/**\n\t * Return a new {@link OriginProvider origin tracked} version the given\n\t * {@link Resource}.\n\t * @param resource the tracked resource\n\t * @param origin the origin of the resource\n\t * @return an {@link OriginTrackedResource} instance\n\t */\n\tpublic static OriginTrackedResource of(Resource resource, @Nullable Origin origin) {\n\t\tif (resource instanceof WritableResource writableResource) {\n\t\t\treturn new OriginTrackedWritableResource(writableResource, origin);\n\t\t}\n\t\treturn new OriginTrackedResource(resource, origin);\n\t}\n\n\t/**\n\t * Variant of {@link OriginTrackedResource} for {@link WritableResource} instances.\n\t */\n\tpublic static class OriginTrackedWritableResource extends OriginTrackedResource implements WritableResource {\n\n\t\t/**\n\t\t * Create a new {@link OriginTrackedWritableResource} instance.\n\t\t * @param resource the resource to track\n\t\t * @param origin the origin of the resource\n\t\t */\n\t\tOriginTrackedWritableResource(WritableResource resource, @Nullable Origin origin) {\n\t\t\tsuper(resource, origin);\n\t\t}\n\n\t\t@Override\n\t\tpublic WritableResource getResource() {\n\t\t\treturn (WritableResource) super.getResource();\n\t\t}\n\n\t\t@Override\n\t\tpublic OutputStream getOutputStream() throws IOException {\n\t\t\treturn getResource().getOutputStream();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/OriginTrackedValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A wrapper for an {@link Object} value and {@link Origin}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.0.0\n * @see #of(Object)\n * @see #of(Object, Origin)\n */\npublic class OriginTrackedValue implements OriginProvider {\n\n\tprivate final Object value;\n\n\tprivate final @Nullable Origin origin;\n\n\tprivate OriginTrackedValue(Object value, @Nullable Origin origin) {\n\t\tthis.value = value;\n\t\tthis.origin = origin;\n\t}\n\n\t/**\n\t * Return the tracked value.\n\t * @return the tracked value\n\t */\n\tpublic Object getValue() {\n\t\treturn this.value;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn ObjectUtils.nullSafeEquals(this.value, ((OriginTrackedValue) obj).value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHashCode(this.value);\n\t}\n\n\t@Override\n\tpublic @Nullable String toString() {\n\t\treturn (this.value != null) ? this.value.toString() : null;\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tpublic static @Nullable OriginTrackedValue of(@Nullable Object value) {\n\t\treturn of(value, null);\n\t}\n\n\t/**\n\t * Create an {@link OriginTrackedValue} containing the specified {@code value} and\n\t * {@code origin}. If the source value implements {@link CharSequence} then so will\n\t * the resulting {@link OriginTrackedValue}.\n\t * @param value the source value\n\t * @param origin the origin\n\t * @return an {@link OriginTrackedValue} or {@code null} if the source value was\n\t * {@code null}.\n\t */\n\t@Contract(\"null, _ -> null; !null, _ -> !null\")\n\tpublic static @Nullable OriginTrackedValue of(@Nullable Object value, @Nullable Origin origin) {\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (value instanceof CharSequence charSequence) {\n\t\t\treturn new OriginTrackedCharSequence(charSequence, origin);\n\t\t}\n\t\treturn new OriginTrackedValue(value, origin);\n\t}\n\n\t/**\n\t * {@link OriginTrackedValue} for a {@link CharSequence}.\n\t */\n\tprivate static class OriginTrackedCharSequence extends OriginTrackedValue implements CharSequence {\n\n\t\tOriginTrackedCharSequence(CharSequence value, @Nullable Origin origin) {\n\t\t\tsuper(value, origin);\n\t\t}\n\n\t\t@Override\n\t\tpublic int length() {\n\t\t\treturn getValue().length();\n\t\t}\n\n\t\t@Override\n\t\tpublic char charAt(int index) {\n\t\t\treturn getValue().charAt(index);\n\t\t}\n\n\t\t@Override\n\t\tpublic CharSequence subSequence(int start, int end) {\n\t\t\treturn getValue().subSequence(start, end);\n\t\t}\n\n\t\t@Override\n\t\tpublic CharSequence getValue() {\n\t\t\treturn (CharSequence) super.getValue();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/PropertySourceOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Origin} from a {@link PropertySource}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class PropertySourceOrigin implements Origin, OriginProvider {\n\n\tprivate final PropertySource<?> propertySource;\n\n\tprivate final String propertyName;\n\n\tprivate final @Nullable Origin origin;\n\n\t/**\n\t * Create a new {@link PropertySourceOrigin} instance.\n\t * @param propertySource the property source\n\t * @param propertyName the name from the property source\n\t */\n\tpublic PropertySourceOrigin(PropertySource<?> propertySource, String propertyName) {\n\t\tthis(propertySource, propertyName, null);\n\t}\n\n\t/**\n\t * Create a new {@link PropertySourceOrigin} instance.\n\t * @param propertySource the property source\n\t * @param propertyName the name from the property source\n\t * @param origin the actual origin for the source if known\n\t * @since 3.2.8\n\t */\n\tpublic PropertySourceOrigin(PropertySource<?> propertySource, String propertyName, @Nullable Origin origin) {\n\t\tAssert.notNull(propertySource, \"'propertySource' must not be null\");\n\t\tAssert.hasLength(propertyName, \"'propertyName' must not be empty\");\n\t\tthis.propertySource = propertySource;\n\t\tthis.propertyName = propertyName;\n\t\tthis.origin = origin;\n\t}\n\n\t/**\n\t * Return the origin {@link PropertySource}.\n\t * @return the origin property source\n\t */\n\tpublic PropertySource<?> getPropertySource() {\n\t\treturn this.propertySource;\n\t}\n\n\t/**\n\t * Return the property name that was used when obtaining the original value from the\n\t * {@link #getPropertySource() property source}.\n\t * @return the origin property name\n\t */\n\tpublic String getPropertyName() {\n\t\treturn this.propertyName;\n\t}\n\n\t/**\n\t * Return the actual origin for the source if known.\n\t * @return the actual source origin\n\t * @since 3.2.8\n\t */\n\t@Override\n\tpublic @Nullable Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getParent() {\n\t\treturn (this.origin != null) ? this.origin.getParent() : null;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.origin != null) ? this.origin.toString()\n\t\t\t\t: \"\\\"\" + this.propertyName + \"\\\" from property source \\\"\" + this.propertySource.getName() + \"\\\"\";\n\t}\n\n\t/**\n\t * Get an {@link Origin} for the given {@link PropertySource} and\n\t * {@code propertyName}. Will either return an {@link OriginLookup} result or a\n\t * {@link PropertySourceOrigin}.\n\t * @param propertySource the origin property source\n\t * @param name the property name\n\t * @return the property origin\n\t */\n\tpublic static Origin get(PropertySource<?> propertySource, String name) {\n\t\tOrigin origin = OriginLookup.getOrigin(propertySource, name);\n\t\treturn (origin instanceof PropertySourceOrigin) ? origin\n\t\t\t\t: new PropertySourceOrigin(propertySource, name, origin);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/SystemEnvironmentOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link Origin} for an item loaded from the system environment. Provides access to the\n * original property name.\n *\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class SystemEnvironmentOrigin implements Origin {\n\n\tprivate final String property;\n\n\tpublic SystemEnvironmentOrigin(String property) {\n\t\tAssert.hasText(property, \"'property' must not be empty\");\n\t\tthis.property = property;\n\t}\n\n\tpublic String getProperty() {\n\t\treturn this.property;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tSystemEnvironmentOrigin other = (SystemEnvironmentOrigin) obj;\n\t\treturn ObjectUtils.nullSafeEquals(this.property, other.property);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHashCode(this.property);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"System Environment Property \\\"\" + this.property + \"\\\"\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/TextResourceOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link Origin} for an item loaded from a text resource. Provides access to the original\n * {@link Resource} that loaded the text and a {@link Location} within it. If the provided\n * resource provides an {@link Origin} (e.g. it is an {@link OriginTrackedResource}), then\n * it will be used as the {@link Origin#getParent() origin parent}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.0.0\n * @see OriginTrackedResource\n */\npublic class TextResourceOrigin implements Origin {\n\n\tprivate final @Nullable Resource resource;\n\n\tprivate final @Nullable Location location;\n\n\tpublic TextResourceOrigin(@Nullable Resource resource, @Nullable Location location) {\n\t\tthis.resource = resource;\n\t\tthis.location = location;\n\t}\n\n\t/**\n\t * Return the resource where the property originated.\n\t * @return the text resource or {@code null}\n\t */\n\tpublic @Nullable Resource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t/**\n\t * Return the location of the property within the source (if known).\n\t * @return the location or {@code null}\n\t */\n\tpublic @Nullable Location getLocation() {\n\t\treturn this.location;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getParent() {\n\t\treturn Origin.from(this.resource);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof TextResourceOrigin other) {\n\t\t\tboolean result = true;\n\t\t\tresult = result && ObjectUtils.nullSafeEquals(this.resource, other.resource);\n\t\t\tresult = result && ObjectUtils.nullSafeEquals(this.location, other.location);\n\t\t\treturn result;\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = 1;\n\t\tresult = 31 * result + ObjectUtils.nullSafeHashCode(this.resource);\n\t\tresult = 31 * result + ObjectUtils.nullSafeHashCode(this.location);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder result = new StringBuilder();\n\t\tresult.append(getResourceDescription(this.resource));\n\t\tif (this.location != null) {\n\t\t\tresult.append(\" - \").append(this.location);\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\tprivate String getResourceDescription(@Nullable Resource resource) {\n\t\tif (resource instanceof OriginTrackedResource originTrackedResource) {\n\t\t\treturn getResourceDescription(originTrackedResource.getResource());\n\t\t}\n\t\tif (resource == null) {\n\t\t\treturn \"unknown resource [?]\";\n\t\t}\n\t\tif (resource instanceof ClassPathResource classPathResource) {\n\t\t\treturn getResourceDescription(classPathResource);\n\t\t}\n\t\treturn resource.getDescription();\n\t}\n\n\tprivate String getResourceDescription(ClassPathResource resource) {\n\t\ttry {\n\t\t\tJarUri jarUri = JarUri.from(resource.getURI());\n\t\t\tif (jarUri != null) {\n\t\t\t\treturn jarUri.getDescription(resource.getDescription());\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn resource.getDescription();\n\t}\n\n\t/**\n\t * A location (line and column number) within the resource.\n\t */\n\tpublic static final class Location {\n\n\t\tprivate final int line;\n\n\t\tprivate final int column;\n\n\t\t/**\n\t\t * Create a new {@link Location} instance.\n\t\t * @param line the line number (zero indexed)\n\t\t * @param column the column number (zero indexed)\n\t\t */\n\t\tpublic Location(int line, int column) {\n\t\t\tthis.line = line;\n\t\t\tthis.column = column;\n\t\t}\n\n\t\t/**\n\t\t * Return the line of the text resource where the property originated.\n\t\t * @return the line number (zero indexed)\n\t\t */\n\t\tpublic int getLine() {\n\t\t\treturn this.line;\n\t\t}\n\n\t\t/**\n\t\t * Return the column of the text resource where the property originated.\n\t\t * @return the column number (zero indexed)\n\t\t */\n\t\tpublic int getColumn() {\n\t\t\treturn this.column;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tLocation other = (Location) obj;\n\t\t\tboolean result = true;\n\t\t\tresult = result && this.line == other.line;\n\t\t\tresult = result && this.column == other.column;\n\t\t\treturn result;\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn (31 * this.line) + this.column;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn (this.line + 1) + \":\" + (this.column + 1);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/origin/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for item origin tracking.\n * @see org.springframework.boot.origin.Origin\n */\n@NullMarked\npackage org.springframework.boot.origin;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core Spring Boot classes.\n *\n * @see org.springframework.boot.SpringApplication\n */\n@NullMarked\npackage org.springframework.boot;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/retry/RetryPolicySettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.retry;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.core.retry.RetryPolicy;\nimport org.springframework.core.retry.RetryPolicy.Builder;\n\n/**\n * Settings for a {@link RetryPolicy}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class RetryPolicySettings {\n\n\t/**\n\t * Default number of retry attempts.\n\t */\n\tpublic static final long DEFAULT_MAX_RETRIES = RetryPolicy.Builder.DEFAULT_MAX_RETRIES;\n\n\t/**\n\t * Default initial delay.\n\t */\n\tpublic static final Duration DEFAULT_DELAY = Duration.ofMillis(RetryPolicy.Builder.DEFAULT_DELAY);\n\n\t/**\n\t * Default multiplier, uses a fixed delay.\n\t */\n\tpublic static final double DEFAULT_MULTIPLIER = RetryPolicy.Builder.DEFAULT_MULTIPLIER;\n\n\t/**\n\t * Default maximum delay (infinite).\n\t */\n\tpublic static final Duration DEFAULT_MAX_DELAY = Duration.ofMillis(RetryPolicy.Builder.DEFAULT_MAX_DELAY);\n\n\tprivate List<Class<? extends Throwable>> exceptionIncludes = new ArrayList<>();\n\n\tprivate List<Class<? extends Throwable>> exceptionExcludes = new ArrayList<>();\n\n\tprivate @Nullable Predicate<Throwable> exceptionPredicate;\n\n\tprivate Long maxRetries = DEFAULT_MAX_RETRIES;\n\n\tprivate Duration delay = DEFAULT_DELAY;\n\n\tprivate @Nullable Duration jitter;\n\n\tprivate Double multiplier = DEFAULT_MULTIPLIER;\n\n\tprivate Duration maxDelay = DEFAULT_MAX_DELAY;\n\n\tprivate @Nullable Function<Builder, RetryPolicy> factory;\n\n\t/**\n\t * Create a {@link RetryPolicy} based on the state of this instance.\n\t * @return a {@link RetryPolicy}\n\t */\n\tpublic RetryPolicy createRetryPolicy() {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRetryPolicy.Builder builder = RetryPolicy.builder();\n\t\tmap.from(this::getExceptionIncludes).to(builder::includes);\n\t\tmap.from(this::getExceptionExcludes).to(builder::excludes);\n\t\tmap.from(this::getExceptionPredicate).to(builder::predicate);\n\t\tmap.from(this::getMaxRetries).to(builder::maxRetries);\n\t\tmap.from(this::getDelay).to(builder::delay);\n\t\tmap.from(this::getJitter).to(builder::jitter);\n\t\tmap.from(this::getMultiplier).to(builder::multiplier);\n\t\tmap.from(this::getMaxDelay).to(builder::maxDelay);\n\t\treturn (this.factory != null) ? this.factory.apply(builder) : builder.build();\n\t}\n\n\t/**\n\t * Return the applicable exception types to attempt a retry for.\n\t * <p>\n\t * The default is empty, leading to a retry attempt for any exception.\n\t * @return the applicable exception types\n\t */\n\tpublic List<Class<? extends Throwable>> getExceptionIncludes() {\n\t\treturn this.exceptionIncludes;\n\t}\n\n\t/**\n\t * Replace the applicable exception types to attempt a retry for by the given\n\t * {@code includes}. Alternatively consider using {@link #getExceptionIncludes()} to\n\t * mutate the existing list.\n\t * @param includes the applicable exception types\n\t */\n\tpublic void setExceptionIncludes(List<Class<? extends Throwable>> includes) {\n\t\tthis.exceptionIncludes = new ArrayList<>(includes);\n\t}\n\n\t/**\n\t * Return the non-applicable exception types to avoid a retry for.\n\t * <p>\n\t * The default is empty, leading to a retry attempt for any exception.\n\t * @return the non-applicable exception types\n\t */\n\tpublic List<Class<? extends Throwable>> getExceptionExcludes() {\n\t\treturn this.exceptionExcludes;\n\t}\n\n\t/**\n\t * Replace the non-applicable exception types to attempt a retry for by the given\n\t * {@code excludes}. Alternatively consider using {@link #getExceptionExcludes()} to\n\t * mutate the existing list.\n\t * @param excludes the non-applicable types\n\t */\n\tpublic void setExceptionExcludes(List<Class<? extends Throwable>> excludes) {\n\t\tthis.exceptionExcludes = new ArrayList<>(excludes);\n\t}\n\n\t/**\n\t * Return the predicate to use to determine whether to retry a failed operation based\n\t * on a given {@link Throwable}.\n\t * @return the predicate to use\n\t */\n\tpublic @Nullable Predicate<Throwable> getExceptionPredicate() {\n\t\treturn this.exceptionPredicate;\n\t}\n\n\t/**\n\t * Set the predicate to use to determine whether to retry a failed operation based on\n\t * a given {@link Throwable}.\n\t * @param exceptionPredicate the predicate to use\n\t */\n\tpublic void setExceptionPredicate(@Nullable Predicate<Throwable> exceptionPredicate) {\n\t\tthis.exceptionPredicate = exceptionPredicate;\n\t}\n\n\t/**\n\t * Return the maximum number of retry attempts.\n\t * @return the maximum number of retry attempts\n\t * @see #DEFAULT_MAX_RETRIES\n\t */\n\tpublic Long getMaxRetries() {\n\t\treturn this.maxRetries;\n\t}\n\n\t/**\n\t * Specify the maximum number of retry attempts.\n\t * @param maxRetries the maximum number of retry attempts (must be equal or greater\n\t * than zero)\n\t */\n\tpublic void setMaxRetries(Long maxRetries) {\n\t\tthis.maxRetries = maxRetries;\n\t}\n\n\t/**\n\t * Return the base delay after the initial invocation.\n\t * @return the base delay\n\t * @see #DEFAULT_DELAY\n\t */\n\tpublic Duration getDelay() {\n\t\treturn this.delay;\n\t}\n\n\t/**\n\t * Specify the base delay after the initial invocation.\n\t * <p>\n\t * If a {@linkplain #getMultiplier() multiplier} is specified, this serves as the\n\t * initial delay to multiply from.\n\t * @param delay the base delay (must be greater than or equal to zero)\n\t */\n\tpublic void setDelay(Duration delay) {\n\t\tthis.delay = delay;\n\t}\n\n\t/**\n\t * Return the jitter period to enable random retry attempts.\n\t * @return the jitter value\n\t */\n\tpublic @Nullable Duration getJitter() {\n\t\treturn this.jitter;\n\t}\n\n\t/**\n\t * Specify a jitter period for the base retry attempt, randomly subtracted or added to\n\t * the calculated delay, resulting in a value between {@code delay - jitter} and\n\t * {@code delay + jitter} but never below the {@linkplain #getDelay() base delay} or\n\t * above the {@linkplain #getMaxDelay() max delay}.\n\t * <p>\n\t * If a {@linkplain #getMultiplier() multiplier} is specified, it is applied to the\n\t * jitter value as well.\n\t * @param jitter the jitter value (must be positive)\n\t */\n\tpublic void setJitter(@Nullable Duration jitter) {\n\t\tthis.jitter = jitter;\n\t}\n\n\t/**\n\t * Return the value to multiply the current interval by for each attempt. The default\n\t * value, {@code 1.0}, effectively results in a fixed delay.\n\t * @return the value to multiply the current interval by for each attempt\n\t * @see #DEFAULT_MULTIPLIER\n\t */\n\tpublic Double getMultiplier() {\n\t\treturn this.multiplier;\n\t}\n\n\t/**\n\t * Specify a multiplier for a delay for the next retry attempt.\n\t * @param multiplier value to multiply the current interval by for each attempt (must\n\t * be greater than or equal to 1)\n\t */\n\tpublic void setMultiplier(Double multiplier) {\n\t\tthis.multiplier = multiplier;\n\t}\n\n\t/**\n\t * Return the maximum delay for any retry attempt.\n\t * @return the maximum delay\n\t */\n\tpublic Duration getMaxDelay() {\n\t\treturn this.maxDelay;\n\t}\n\n\t/**\n\t * Specify the maximum delay for any retry attempt, limiting how far\n\t * {@linkplain #getJitter() jitter} and the {@linkplain #getMultiplier() multiplier}\n\t * can increase the {@linkplain #getDelay() delay}.\n\t * <p>\n\t * The default is unlimited.\n\t * @param maxDelay the maximum delay (must be positive)\n\t * @see #DEFAULT_MAX_DELAY\n\t */\n\tpublic void setMaxDelay(Duration maxDelay) {\n\t\tthis.maxDelay = maxDelay;\n\t}\n\n\t/**\n\t * Set the factory to use to create the {@link RetryPolicy}, or {@code null} to use\n\t * the default. The function takes a {@link Builder RetryPolicy.Builder} initialized\n\t * with the state of this instance that can be further configured, or ignored to\n\t * restart from scratch.\n\t * @param factory a factory to customize the retry policy.\n\t */\n\tpublic void setFactory(@Nullable Function<RetryPolicy.Builder, RetryPolicy> factory) {\n\t\tthis.factory = factory;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/retry/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for core retry functionality.\n */\n@NullMarked\npackage org.springframework.boot.retry;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/AliasKeyManagerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.net.Socket;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.Principal;\nimport java.security.PrivateKey;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.X509Certificate;\nimport java.util.Arrays;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.KeyManagerFactorySpi;\nimport javax.net.ssl.ManagerFactoryParameters;\nimport javax.net.ssl.SSLEngine;\nimport javax.net.ssl.X509ExtendedKeyManager;\n\n/**\n * {@link KeyManagerFactory} that allows a configurable key alias to be used. Due to the\n * fact that the actual calls to retrieve the key by alias are done at request time the\n * approach is to wrap the actual key managers with a {@link AliasX509ExtendedKeyManager}.\n * The actual SPI has to be wrapped as well due to the fact that\n * {@link KeyManagerFactory#getKeyManagers()} is final.\n *\n * @author Scott Frederick\n */\nfinal class AliasKeyManagerFactory extends KeyManagerFactory {\n\n\tAliasKeyManagerFactory(KeyManagerFactory delegate, String alias, String algorithm) {\n\t\tsuper(new AliasKeyManagerFactorySpi(delegate, alias), delegate.getProvider(), algorithm);\n\t}\n\n\t/**\n\t * {@link KeyManagerFactorySpi} that allows a configurable key alias to be used.\n\t */\n\tprivate static final class AliasKeyManagerFactorySpi extends KeyManagerFactorySpi {\n\n\t\tprivate final KeyManagerFactory delegate;\n\n\t\tprivate final String alias;\n\n\t\tprivate AliasKeyManagerFactorySpi(KeyManagerFactory delegate, String alias) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.alias = alias;\n\t\t}\n\n\t\t@Override\n\t\tprotected void engineInit(KeyStore keyStore, char[] chars)\n\t\t\t\tthrows KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {\n\t\t\tthis.delegate.init(keyStore, chars);\n\t\t}\n\n\t\t@Override\n\t\tprotected void engineInit(ManagerFactoryParameters managerFactoryParameters)\n\t\t\t\tthrows InvalidAlgorithmParameterException {\n\t\t\tthrow new InvalidAlgorithmParameterException(\"Unsupported ManagerFactoryParameters\");\n\t\t}\n\n\t\t@Override\n\t\tprotected KeyManager[] engineGetKeyManagers() {\n\t\t\treturn Arrays.stream(this.delegate.getKeyManagers())\n\t\t\t\t.filter(X509ExtendedKeyManager.class::isInstance)\n\t\t\t\t.map(X509ExtendedKeyManager.class::cast)\n\t\t\t\t.map(this::wrap)\n\t\t\t\t.toArray(KeyManager[]::new);\n\t\t}\n\n\t\tprivate AliasKeyManagerFactory.AliasX509ExtendedKeyManager wrap(X509ExtendedKeyManager keyManager) {\n\t\t\treturn new AliasX509ExtendedKeyManager(keyManager, this.alias);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link X509ExtendedKeyManager} that allows a configurable key alias to be used.\n\t */\n\tstatic final class AliasX509ExtendedKeyManager extends X509ExtendedKeyManager {\n\n\t\tprivate final X509ExtendedKeyManager delegate;\n\n\t\tprivate final String alias;\n\n\t\tprivate AliasX509ExtendedKeyManager(X509ExtendedKeyManager keyManager, String alias) {\n\t\t\tthis.delegate = keyManager;\n\t\t\tthis.alias = alias;\n\t\t}\n\n\t\t@Override\n\t\tpublic String chooseEngineClientAlias(String[] strings, Principal[] principals, SSLEngine sslEngine) {\n\t\t\treturn this.delegate.chooseEngineClientAlias(strings, principals, sslEngine);\n\t\t}\n\n\t\t@Override\n\t\tpublic String chooseEngineServerAlias(String s, Principal[] principals, SSLEngine sslEngine) {\n\t\t\treturn this.alias;\n\t\t}\n\n\t\t@Override\n\t\tpublic String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {\n\t\t\treturn this.delegate.chooseClientAlias(keyType, issuers, socket);\n\t\t}\n\n\t\t@Override\n\t\tpublic String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {\n\t\t\treturn this.delegate.chooseServerAlias(keyType, issuers, socket);\n\t\t}\n\n\t\t@Override\n\t\tpublic X509Certificate[] getCertificateChain(String alias) {\n\t\t\treturn this.delegate.getCertificateChain(alias);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getClientAliases(String keyType, Principal[] issuers) {\n\t\t\treturn this.delegate.getClientAliases(keyType, issuers);\n\t\t}\n\n\t\t@Override\n\t\tpublic PrivateKey getPrivateKey(String alias) {\n\t\t\treturn this.delegate.getPrivateKey(alias);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getServerAliases(String keyType, Principal[] issuers) {\n\t\t\treturn this.delegate.getServerAliases(keyType, issuers);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/DefaultSslBundleRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\n\n/**\n * Default {@link SslBundleRegistry} implementation.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @author Jonatan Ivanov\n * @since 3.1.0\n */\npublic class DefaultSslBundleRegistry implements SslBundleRegistry, SslBundles {\n\n\tprivate static final Log logger = LogFactory.getLog(DefaultSslBundleRegistry.class);\n\n\tprivate final Map<String, RegisteredSslBundle> registeredBundles = new ConcurrentHashMap<>();\n\n\tprivate final List<BiConsumer<String, SslBundle>> registerHandlers = new CopyOnWriteArrayList<>();\n\n\tpublic DefaultSslBundleRegistry() {\n\t}\n\n\tpublic DefaultSslBundleRegistry(String name, SslBundle bundle) {\n\t\tregisterBundle(name, bundle);\n\t}\n\n\t@Override\n\tpublic void registerBundle(String name, SslBundle bundle) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(bundle, \"'bundle' must not be null\");\n\t\tRegisteredSslBundle previous = this.registeredBundles.putIfAbsent(name, new RegisteredSslBundle(name, bundle));\n\t\tAssert.state(previous == null, () -> \"Cannot replace existing SSL bundle '%s'\".formatted(name));\n\t\tthis.registerHandlers.forEach((handler) -> handler.accept(name, bundle));\n\t}\n\n\t@Override\n\tpublic void updateBundle(String name, SslBundle updatedBundle) {\n\t\tgetRegistered(name).update(updatedBundle);\n\t}\n\n\t@Override\n\tpublic SslBundle getBundle(String name) {\n\t\treturn getRegistered(name).getBundle();\n\t}\n\n\t@Override\n\tpublic void addBundleUpdateHandler(String name, Consumer<SslBundle> updateHandler) throws NoSuchSslBundleException {\n\t\tgetRegistered(name).addUpdateHandler(updateHandler);\n\t}\n\n\t@Override\n\tpublic void addBundleRegisterHandler(BiConsumer<String, SslBundle> registerHandler) {\n\t\tthis.registerHandlers.add(registerHandler);\n\t}\n\n\t@Override\n\tpublic List<String> getBundleNames() {\n\t\tList<String> names = new ArrayList<>(this.registeredBundles.keySet());\n\t\tCollections.sort(names);\n\t\treturn Collections.unmodifiableList(names);\n\t}\n\n\tprivate RegisteredSslBundle getRegistered(String name) throws NoSuchSslBundleException {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tRegisteredSslBundle registered = this.registeredBundles.get(name);\n\t\tif (registered == null) {\n\t\t\tthrow new NoSuchSslBundleException(name, \"SSL bundle name '%s' cannot be found\".formatted(name));\n\t\t}\n\t\treturn registered;\n\t}\n\n\tprivate static class RegisteredSslBundle {\n\n\t\tprivate final String name;\n\n\t\tprivate final List<Consumer<SslBundle>> updateHandlers = new CopyOnWriteArrayList<>();\n\n\t\tprivate volatile SslBundle bundle;\n\n\t\tRegisteredSslBundle(String name, SslBundle bundle) {\n\t\t\tthis.name = name;\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t\tvoid update(SslBundle updatedBundle) {\n\t\t\tAssert.notNull(updatedBundle, \"'updatedBundle' must not be null\");\n\t\t\tthis.bundle = updatedBundle;\n\t\t\tif (this.updateHandlers.isEmpty()) {\n\t\t\t\tlogger.warn(LogMessage.format(\n\t\t\t\t\t\t\"SSL bundle '%s' has been updated but may be in use by a technology that doesn't support SSL reloading\",\n\t\t\t\t\t\tthis.name));\n\t\t\t}\n\t\t\tthis.updateHandlers.forEach((handler) -> handler.accept(updatedBundle));\n\t\t}\n\n\t\tSslBundle getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tvoid addUpdateHandler(Consumer<SslBundle> updateHandler) {\n\t\t\tAssert.notNull(updateHandler, \"'updateHandler' must not be null\");\n\t\t\tthis.updateHandlers.add(updateHandler);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/DefaultSslManagerBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Default implementation of {@link SslManagerBundle}.\n *\n * @author Scott Frederick\n * @see SslManagerBundle#from(SslStoreBundle, SslBundleKey)\n */\nclass DefaultSslManagerBundle implements SslManagerBundle {\n\n\tprivate final SslStoreBundle storeBundle;\n\n\tprivate final SslBundleKey key;\n\n\tDefaultSslManagerBundle(@Nullable SslStoreBundle storeBundle, @Nullable SslBundleKey key) {\n\t\tthis.storeBundle = (storeBundle != null) ? storeBundle : SslStoreBundle.NONE;\n\t\tthis.key = (key != null) ? key : SslBundleKey.NONE;\n\t}\n\n\t@Override\n\tpublic KeyManagerFactory getKeyManagerFactory() {\n\t\ttry {\n\t\t\tKeyStore store = this.storeBundle.getKeyStore();\n\t\t\tthis.key.assertContainsAlias(store);\n\t\t\tString alias = this.key.getAlias();\n\t\t\tString algorithm = KeyManagerFactory.getDefaultAlgorithm();\n\t\t\tKeyManagerFactory factory = getKeyManagerFactoryInstance(algorithm);\n\t\t\tfactory = (alias != null) ? new AliasKeyManagerFactory(factory, alias, algorithm) : factory;\n\t\t\tString password = this.key.getPassword();\n\t\t\tpassword = (password != null) ? password : this.storeBundle.getKeyStorePassword();\n\t\t\tfactory.init(store, (password != null) ? password.toCharArray() : null);\n\t\t\treturn factory;\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow ex;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not load key manager factory: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic TrustManagerFactory getTrustManagerFactory() {\n\t\ttry {\n\t\t\tKeyStore store = this.storeBundle.getTrustStore();\n\t\t\tString algorithm = TrustManagerFactory.getDefaultAlgorithm();\n\t\t\tTrustManagerFactory factory = getTrustManagerFactoryInstance(algorithm);\n\t\t\tfactory.init(store);\n\t\t\treturn factory;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not load trust manager factory: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprotected KeyManagerFactory getKeyManagerFactoryInstance(String algorithm) throws NoSuchAlgorithmException {\n\t\treturn KeyManagerFactory.getInstance(algorithm);\n\t}\n\n\tprotected TrustManagerFactory getTrustManagerFactoryInstance(String algorithm) throws NoSuchAlgorithmException {\n\t\treturn TrustManagerFactory.getInstance(algorithm);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/FixedTrustManagerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.Provider;\n\nimport javax.net.ssl.ManagerFactoryParameters;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\nimport javax.net.ssl.TrustManagerFactorySpi;\n\n/**\n * {@link TrustManagerFactory} which uses a fixed set of {@link TrustManager\n * TrustManagers}.\n *\n * @author Moritz Halbritter\n */\nfinal class FixedTrustManagerFactory extends TrustManagerFactory {\n\n\tprivate static final Provider PROVIDER = new FixedTrustManagerFactoryProvider();\n\n\tprivate FixedTrustManagerFactory(FixedTrustManagersSpi spi, String algorithm) {\n\t\tsuper(spi, PROVIDER, algorithm);\n\t}\n\n\tstatic FixedTrustManagerFactory of(TrustManagerFactory trustManagerFactory, TrustManager... trustManagers) {\n\t\treturn new FixedTrustManagerFactory(new FixedTrustManagersSpi(trustManagers),\n\t\t\t\ttrustManagerFactory.getAlgorithm());\n\t}\n\n\tprivate static final class FixedTrustManagersSpi extends TrustManagerFactorySpi {\n\n\t\tprivate final TrustManager[] trustManagers;\n\n\t\tprivate FixedTrustManagersSpi(TrustManager[] trustManagers) {\n\t\t\tthis.trustManagers = trustManagers;\n\t\t}\n\n\t\t@Override\n\t\tprotected void engineInit(KeyStore ks) {\n\t\t}\n\n\t\t@Override\n\t\tprotected void engineInit(ManagerFactoryParameters spec) {\n\t\t}\n\n\t\t@Override\n\t\tprotected TrustManager[] engineGetTrustManagers() {\n\t\t\treturn this.trustManagers;\n\t\t}\n\n\t}\n\n\tprivate static class FixedTrustManagerFactoryProvider extends Provider {\n\n\t\tFixedTrustManagerFactoryProvider() {\n\t\t\tsuper(\"FixedTrustManagerFactory\", SpringBootProviderVersion.get(), \"\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/NoSuchSslBundleException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Exception indicating that an {@link SslBundle} was referenced with a name that does not\n * match any registered bundle.\n *\n * @author Scott Frederick\n * @since 3.1.0\n */\npublic class NoSuchSslBundleException extends RuntimeException {\n\n\tprivate final String bundleName;\n\n\t/**\n\t * Create a new {@code SslBundleNotFoundException} instance.\n\t * @param bundleName the name of the bundle that could not be found\n\t * @param message the exception message\n\t */\n\tpublic NoSuchSslBundleException(String bundleName, String message) {\n\t\tthis(bundleName, message, null);\n\t}\n\n\t/**\n\t * Create a new {@code SslBundleNotFoundException} instance.\n\t * @param bundleName the name of the bundle that could not be found\n\t * @param message the exception message\n\t * @param cause the exception cause\n\t */\n\tpublic NoSuchSslBundleException(String bundleName, String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.bundleName = bundleName;\n\t}\n\n\t/**\n\t * Return the name of the bundle that was not found.\n\t * @return the bundle name\n\t */\n\tpublic String getBundleName() {\n\t\treturn this.bundleName;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.UnrecoverableKeyException;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.StringUtils;\n\n/**\n * A bundle of trust material that can be used to establish an SSL connection.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 3.1.0\n */\npublic interface SslBundle {\n\n\t/**\n\t * The default protocol to use.\n\t */\n\tString DEFAULT_PROTOCOL = \"TLS\";\n\n\t/**\n\t * Return the {@link SslStoreBundle} that can be used to access this bundle's key and\n\t * trust stores.\n\t * @return the {@code SslStoreBundle} instance for this bundle\n\t */\n\tSslStoreBundle getStores();\n\n\t/**\n\t * Return a reference to the key that should be used for this bundle or\n\t * {@link SslBundleKey#NONE}.\n\t * @return a reference to the SSL key that should be used\n\t */\n\tSslBundleKey getKey();\n\n\t/**\n\t * Return {@link SslOptions} that should be applied when establishing the SSL\n\t * connection.\n\t * @return the options that should be applied\n\t */\n\tSslOptions getOptions();\n\n\t/**\n\t * Return the protocol to use when establishing the connection. Values should be\n\t * supported by {@link SSLContext#getInstance(String)}.\n\t * @return the SSL protocol\n\t * @see SSLContext#getInstance(String)\n\t */\n\tString getProtocol();\n\n\t/**\n\t * Return the {@link SslManagerBundle} that can be used to access this bundle's\n\t * {@link KeyManager key} and {@link TrustManager trust} managers.\n\t * @return the {@code SslManagerBundle} instance for this bundle\n\t */\n\tSslManagerBundle getManagers();\n\n\t/**\n\t * Factory method to create a new {@link SSLContext} for this bundle.\n\t * @return a new {@link SSLContext} instance\n\t */\n\tdefault SSLContext createSslContext() {\n\t\treturn getManagers().createSslContext(getProtocol());\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundle} instance.\n\t * @param stores the stores or {@code null}\n\t * @return a new {@link SslBundle} instance\n\t */\n\tstatic SslBundle of(@Nullable SslStoreBundle stores) {\n\t\treturn of(stores, null, null);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundle} instance.\n\t * @param stores the stores or {@code null}\n\t * @param key the key or {@code null}\n\t * @return a new {@link SslBundle} instance\n\t */\n\tstatic SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key) {\n\t\treturn of(stores, key, null);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundle} instance.\n\t * @param stores the stores or {@code null}\n\t * @param key the key or {@code null}\n\t * @param options the options or {@code null}\n\t * @return a new {@link SslBundle} instance\n\t */\n\tstatic SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key, @Nullable SslOptions options) {\n\t\treturn of(stores, key, options, null);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundle} instance.\n\t * @param stores the stores or {@code null}\n\t * @param key the key or {@code null}\n\t * @param options the options or {@code null}\n\t * @param protocol the protocol or {@code null}\n\t * @return a new {@link SslBundle} instance\n\t */\n\tstatic SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key, @Nullable SslOptions options,\n\t\t\t@Nullable String protocol) {\n\t\treturn of(stores, key, options, protocol, null);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundle} instance.\n\t * @param stores the stores or {@code null}\n\t * @param key the key or {@code null}\n\t * @param options the options or {@code null}\n\t * @param protocol the protocol or {@code null}\n\t * @param managers the managers or {@code null}\n\t * @return a new {@link SslBundle} instance\n\t */\n\tstatic SslBundle of(@Nullable SslStoreBundle stores, @Nullable SslBundleKey key, @Nullable SslOptions options,\n\t\t\t@Nullable String protocol, @Nullable SslManagerBundle managers) {\n\t\tSslManagerBundle managersToUse = (managers != null) ? managers : SslManagerBundle.from(stores, key);\n\t\treturn new SslBundle() {\n\n\t\t\t@Override\n\t\t\tpublic SslStoreBundle getStores() {\n\t\t\t\treturn (stores != null) ? stores : SslStoreBundle.NONE;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic SslBundleKey getKey() {\n\t\t\t\treturn (key != null) ? key : SslBundleKey.NONE;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic SslOptions getOptions() {\n\t\t\t\treturn (options != null) ? options : SslOptions.NONE;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getProtocol() {\n\t\t\t\treturn (!StringUtils.hasText(protocol)) ? DEFAULT_PROTOCOL : protocol;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic SslManagerBundle getManagers() {\n\t\t\t\treturn managersToUse;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\tToStringCreator creator = new ToStringCreator(this);\n\t\t\t\tcreator.append(\"key\", getKey());\n\t\t\t\tcreator.append(\"options\", getOptions());\n\t\t\t\tcreator.append(\"protocol\", getProtocol());\n\t\t\t\tcreator.append(\"stores\", getStores());\n\t\t\t\treturn creator.toString();\n\t\t\t}\n\n\t\t};\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundle} which uses the system defaults.\n\t * @return a new {@link SslBundle} instance\n\t * @since 3.5.0\n\t */\n\tstatic SslBundle systemDefault() {\n\t\ttry {\n\t\t\tKeyManagerFactory keyManagerFactory = KeyManagerFactory\n\t\t\t\t.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n\t\t\tkeyManagerFactory.init(null, null);\n\t\t\tTrustManagerFactory trustManagerFactory = TrustManagerFactory\n\t\t\t\t.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n\t\t\ttrustManagerFactory.init((KeyStore) null);\n\t\t\tSSLContext sslContext = SSLContext.getDefault();\n\t\t\treturn of(null, null, null, null, new SslManagerBundle() {\n\t\t\t\t@Override\n\t\t\t\tpublic KeyManagerFactory getKeyManagerFactory() {\n\t\t\t\t\treturn keyManagerFactory;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic TrustManagerFactory getTrustManagerFactory() {\n\t\t\t\t\treturn trustManagerFactory;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic SSLContext createSslContext(String protocol) {\n\t\t\t\t\treturn sslContext;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tcatch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException ex) {\n\t\t\tthrow new IllegalStateException(\"Could not initialize system default SslBundle: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslBundleKey.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A reference to a single key obtained via {@link SslBundle}.\n *\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic interface SslBundleKey {\n\n\t/**\n\t * {@link SslBundleKey} that returns no values.\n\t */\n\tSslBundleKey NONE = of(null, null);\n\n\t/**\n\t * Return the password that should be used to access the key or {@code null} if no\n\t * password is required.\n\t * @return the key password\n\t */\n\t@Nullable String getPassword();\n\n\t/**\n\t * Return the alias of the key or {@code null} if the key has no alias.\n\t * @return the key alias\n\t */\n\t@Nullable String getAlias();\n\n\t/**\n\t * Assert that the alias is contained in the given keystore.\n\t * @param keyStore the keystore to check\n\t */\n\tdefault void assertContainsAlias(@Nullable KeyStore keyStore) {\n\t\tString alias = getAlias();\n\t\tif (StringUtils.hasLength(alias) && keyStore != null) {\n\t\t\ttry {\n\t\t\t\tAssert.state(keyStore.containsAlias(alias),\n\t\t\t\t\t\t() -> String.format(\"Keystore does not contain alias '%s'\", alias));\n\t\t\t}\n\t\t\tcatch (KeyStoreException ex) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\tString.format(\"Could not determine if keystore contains alias '%s'\", alias), ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundleKey} instance.\n\t * @param password the password used to access the key\n\t * @return a new {@link SslBundleKey} instance\n\t */\n\tstatic SslBundleKey of(String password) {\n\t\treturn of(password, null);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslBundleKey} instance.\n\t * @param password the password used to access the key\n\t * @param alias the alias of the key\n\t * @return a new {@link SslBundleKey} instance\n\t */\n\tstatic SslBundleKey of(@Nullable String password, @Nullable String alias) {\n\t\treturn new SslBundleKey() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getPassword() {\n\t\t\t\treturn password;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getAlias() {\n\t\t\t\treturn alias;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\tToStringCreator creator = new ToStringCreator(this);\n\t\t\t\tcreator.append(\"alias\", alias);\n\t\t\t\tcreator.append(\"password\", (password != null) ? \"******\" : null);\n\t\t\t\treturn creator.toString();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslBundleRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\n/**\n * Interface that can be used to register an {@link SslBundle} for a given name.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 3.1.0\n */\npublic interface SslBundleRegistry {\n\n\t/**\n\t * Register a named {@link SslBundle}.\n\t * @param name the bundle name\n\t * @param bundle the bundle\n\t */\n\tvoid registerBundle(String name, SslBundle bundle);\n\n\t/**\n\t * Updates an {@link SslBundle}.\n\t * @param name the bundle name\n\t * @param updatedBundle the updated bundle\n\t * @throws NoSuchSslBundleException if the bundle cannot be found\n\t * @since 3.2.0\n\t */\n\tvoid updateBundle(String name, SslBundle updatedBundle) throws NoSuchSslBundleException;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslBundles.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\n/**\n * A managed set of {@link SslBundle} instances that can be retrieved by name.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Jonatan Ivanov\n * @since 3.1.0\n */\npublic interface SslBundles {\n\n\t/**\n\t * Return an {@link SslBundle} with the provided name.\n\t * @param name the bundle name\n\t * @return the bundle\n\t * @throws NoSuchSslBundleException if a bundle with the provided name does not exist\n\t */\n\tSslBundle getBundle(String name) throws NoSuchSslBundleException;\n\n\t/**\n\t * Add a handler that will be called each time the named bundle is updated.\n\t * @param name the bundle name\n\t * @param updateHandler the handler that should be called\n\t * @throws NoSuchSslBundleException if a bundle with the provided name does not exist\n\t * @since 3.2.0\n\t */\n\tvoid addBundleUpdateHandler(String name, Consumer<SslBundle> updateHandler) throws NoSuchSslBundleException;\n\n\t/**\n\t * Add a handler that will be called each time a bundle is registered. The handler\n\t * will be called with the bundle name and the bundle.\n\t * @param registerHandler the handler that should be called\n\t * @since 3.5.0\n\t */\n\tvoid addBundleRegisterHandler(BiConsumer<String, SslBundle> registerHandler);\n\n\t/**\n\t * Return the names of all bundles managed by this instance.\n\t * @return the bundle names\n\t * @since 3.4.0\n\t */\n\tList<String> getBundleNames();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslManagerBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.UnrecoverableKeyException;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A bundle of key and trust managers that can be used to establish an SSL connection.\n * Instances are usually created {@link #from(SslStoreBundle, SslBundleKey) from} an\n * {@link SslStoreBundle}.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 3.1.0\n * @see SslStoreBundle\n * @see SslBundle#getManagers()\n */\npublic interface SslManagerBundle {\n\n\t/**\n\t * Return the {@code KeyManager} instances used to establish identity.\n\t * @return the key managers\n\t */\n\tdefault KeyManager[] getKeyManagers() {\n\t\treturn getKeyManagerFactory().getKeyManagers();\n\t}\n\n\t/**\n\t * Return the {@code KeyManagerFactory} used to establish identity.\n\t * @return the key manager factory\n\t */\n\tKeyManagerFactory getKeyManagerFactory();\n\n\t/**\n\t * Return the {@link TrustManager} instances used to establish trust.\n\t * @return the trust managers\n\t */\n\tdefault TrustManager[] getTrustManagers() {\n\t\treturn getTrustManagerFactory().getTrustManagers();\n\t}\n\n\t/**\n\t * Return the {@link TrustManagerFactory} used to establish trust.\n\t * @return the trust manager factory\n\t */\n\tTrustManagerFactory getTrustManagerFactory();\n\n\t/**\n\t * Factory method to create a new {@link SSLContext} for the {@link #getKeyManagers()\n\t * key managers} and {@link #getTrustManagers() trust managers} managed by this\n\t * instance.\n\t * @param protocol the standard name of the SSL protocol. See\n\t * {@link SSLContext#getInstance(String)}\n\t * @return a new {@link SSLContext} instance\n\t */\n\tdefault SSLContext createSslContext(String protocol) {\n\t\ttry {\n\t\t\tSSLContext sslContext = SSLContext.getInstance(protocol);\n\t\t\tsslContext.init(getKeyManagers(), getTrustManagers(), null);\n\t\t\treturn sslContext;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not load SSL context: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslManagerBundle} instance.\n\t * @param keyManagerFactory the key manager factory\n\t * @param trustManagerFactory the trust manager factory\n\t * @return a new {@link SslManagerBundle} instance\n\t */\n\tstatic SslManagerBundle of(KeyManagerFactory keyManagerFactory, TrustManagerFactory trustManagerFactory) {\n\t\tAssert.notNull(keyManagerFactory, \"'keyManagerFactory' must not be null\");\n\t\tAssert.notNull(trustManagerFactory, \"'trustManagerFactory' must not be null\");\n\t\treturn new SslManagerBundle() {\n\n\t\t\t@Override\n\t\t\tpublic KeyManagerFactory getKeyManagerFactory() {\n\t\t\t\treturn keyManagerFactory;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic TrustManagerFactory getTrustManagerFactory() {\n\t\t\t\treturn trustManagerFactory;\n\t\t\t}\n\n\t\t};\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslManagerBundle} backed by the given\n\t * {@link SslBundle} and {@link SslBundleKey}.\n\t * @param storeBundle the SSL store bundle\n\t * @param key the key reference\n\t * @return a new {@link SslManagerBundle} instance\n\t */\n\tstatic SslManagerBundle from(@Nullable SslStoreBundle storeBundle, @Nullable SslBundleKey key) {\n\t\treturn new DefaultSslManagerBundle(storeBundle, key);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslManagerBundle} using the given\n\t * {@link TrustManagerFactory} and the default {@link KeyManagerFactory}.\n\t * @param trustManagerFactory the trust manager factory\n\t * @return a new {@link SslManagerBundle} instance\n\t * @since 3.5.0\n\t */\n\tstatic SslManagerBundle from(TrustManagerFactory trustManagerFactory) {\n\t\tAssert.notNull(trustManagerFactory, \"'trustManagerFactory' must not be null\");\n\t\tKeyManagerFactory defaultKeyManagerFactory = createDefaultKeyManagerFactory();\n\t\treturn of(defaultKeyManagerFactory, trustManagerFactory);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslManagerBundle} using the given\n\t * {@link TrustManager TrustManagers} and the default {@link KeyManagerFactory}.\n\t * @param trustManagers the trust managers to use\n\t * @return a new {@link SslManagerBundle} instance\n\t * @since 3.5.0\n\t */\n\tstatic SslManagerBundle from(TrustManager... trustManagers) {\n\t\tAssert.notNull(trustManagers, \"'trustManagers' must not be null\");\n\t\tKeyManagerFactory defaultKeyManagerFactory = createDefaultKeyManagerFactory();\n\t\tTrustManagerFactory defaultTrustManagerFactory = createDefaultTrustManagerFactory();\n\t\treturn of(defaultKeyManagerFactory, FixedTrustManagerFactory.of(defaultTrustManagerFactory, trustManagers));\n\t}\n\n\tprivate static TrustManagerFactory createDefaultTrustManagerFactory() {\n\t\tString defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();\n\t\tTrustManagerFactory trustManagerFactory;\n\t\ttry {\n\t\t\ttrustManagerFactory = TrustManagerFactory.getInstance(defaultAlgorithm);\n\t\t\ttrustManagerFactory.init((KeyStore) null);\n\t\t}\n\t\tcatch (NoSuchAlgorithmException | KeyStoreException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to create TrustManagerFactory for default '%s' algorithm\".formatted(defaultAlgorithm), ex);\n\t\t}\n\t\treturn trustManagerFactory;\n\t}\n\n\tprivate static KeyManagerFactory createDefaultKeyManagerFactory() {\n\t\tString defaultAlgorithm = KeyManagerFactory.getDefaultAlgorithm();\n\t\tKeyManagerFactory keyManagerFactory;\n\t\ttry {\n\t\t\tkeyManagerFactory = KeyManagerFactory.getInstance(defaultAlgorithm);\n\t\t\tkeyManagerFactory.init(null, null);\n\t\t}\n\t\tcatch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to create KeyManagerFactory for default '%s' algorithm\".formatted(defaultAlgorithm), ex);\n\t\t}\n\t\treturn keyManagerFactory;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslOptions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport javax.net.ssl.SSLEngine;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.style.ToStringCreator;\n\n/**\n * Configuration options that should be applied when establishing an SSL connection.\n *\n * @author Scott Frederick\n * @since 3.1.0\n * @see SslBundle#getOptions()\n */\npublic interface SslOptions {\n\n\t/**\n\t * {@link SslOptions} that returns {@code null} results.\n\t */\n\tSslOptions NONE = of(null, (Set<String>) null);\n\n\t/**\n\t * Return if any SSL options have been specified.\n\t * @return {@code true} if SSL options have been specified\n\t */\n\tdefault boolean isSpecified() {\n\t\treturn (getCiphers() != null) || (getEnabledProtocols() != null);\n\t}\n\n\t/**\n\t * Return the ciphers that can be used or {@code null}. The cipher names in this set\n\t * should be compatible with those supported by\n\t * {@link SSLEngine#getSupportedCipherSuites()}.\n\t * @return the ciphers that can be used or {@code null}\n\t */\n\tString @Nullable [] getCiphers();\n\n\t/**\n\t * Return the protocols that should be enabled or {@code null}. The protocols names in\n\t * this set should be compatible with those supported by\n\t * {@link SSLEngine#getSupportedProtocols()}.\n\t * @return the protocols to enable or {@code null}\n\t */\n\tString @Nullable [] getEnabledProtocols();\n\n\t/**\n\t * Factory method to create a new {@link SslOptions} instance.\n\t * @param ciphers the ciphers\n\t * @param enabledProtocols the enabled protocols\n\t * @return a new {@link SslOptions} instance\n\t */\n\tstatic SslOptions of(String @Nullable [] ciphers, String @Nullable [] enabledProtocols) {\n\t\treturn new SslOptions() {\n\n\t\t\t@Override\n\t\t\tpublic String @Nullable [] getCiphers() {\n\t\t\t\treturn ciphers;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String @Nullable [] getEnabledProtocols() {\n\t\t\t\treturn enabledProtocols;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\tToStringCreator creator = new ToStringCreator(this);\n\t\t\t\tcreator.append(\"ciphers\", ciphers);\n\t\t\t\tcreator.append(\"enabledProtocols\", enabledProtocols);\n\t\t\t\treturn creator.toString();\n\t\t\t}\n\n\t\t};\n\t}\n\n\t/**\n\t * Factory method to create a new {@link SslOptions} instance.\n\t * @param ciphers the ciphers\n\t * @param enabledProtocols the enabled protocols\n\t * @return a new {@link SslOptions} instance\n\t */\n\tstatic SslOptions of(@Nullable Set<String> ciphers, @Nullable Set<String> enabledProtocols) {\n\t\treturn of(toArray(ciphers), toArray(enabledProtocols));\n\t}\n\n\t/**\n\t * Helper method that provides a null-safe way to convert a {@code String[]} to a\n\t * {@link Collection} for client libraries to use.\n\t * @param array the array to convert\n\t * @return a collection or {@code null}\n\t */\n\tstatic @Nullable Set<String> asSet(String @Nullable [] array) {\n\t\treturn (array != null) ? Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(array))) : null;\n\t}\n\n\tprivate static String @Nullable [] toArray(@Nullable Collection<String> collection) {\n\t\treturn (collection != null) ? collection.toArray(String[]::new) : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/SslStoreBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.style.ToStringCreator;\n\n/**\n * A bundle of key and trust stores that can be used to establish an SSL connection.\n *\n * @author Scott Frederick\n * @since 3.1.0\n * @see SslBundle#getStores()\n */\npublic interface SslStoreBundle {\n\n\t/**\n\t * {@link SslStoreBundle} that returns {@code null} for each method.\n\t */\n\tSslStoreBundle NONE = of(null, null, null);\n\n\t/**\n\t * Return a key store generated from the trust material or {@code null}.\n\t * @return the key store\n\t */\n\t@Nullable KeyStore getKeyStore();\n\n\t/**\n\t * Return the password for the key in the key store or {@code null}.\n\t * @return the key password\n\t */\n\t@Nullable String getKeyStorePassword();\n\n\t/**\n\t * Return a trust store generated from the trust material or {@code null}.\n\t * @return the trust store\n\t */\n\t@Nullable KeyStore getTrustStore();\n\n\t/**\n\t * Factory method to create a new {@link SslStoreBundle} instance.\n\t * @param keyStore the key store or {@code null}\n\t * @param keyStorePassword the key store password or {@code null}\n\t * @param trustStore the trust store or {@code null}\n\t * @return a new {@link SslStoreBundle} instance\n\t */\n\tstatic SslStoreBundle of(@Nullable KeyStore keyStore, @Nullable String keyStorePassword,\n\t\t\t@Nullable KeyStore trustStore) {\n\t\treturn new SslStoreBundle() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable KeyStore getKeyStore() {\n\t\t\t\treturn keyStore;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable KeyStore getTrustStore() {\n\t\t\t\treturn trustStore;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getKeyStorePassword() {\n\t\t\t\treturn keyStorePassword;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\tToStringCreator creator = new ToStringCreator(this);\n\t\t\t\tcreator.append(\"keyStore.type\", (keyStore != null) ? keyStore.getType() : \"none\");\n\t\t\t\tcreator.append(\"keyStorePassword\", (keyStorePassword != null) ? \"******\" : null);\n\t\t\t\tcreator.append(\"trustStore.type\", (trustStore != null) ? trustStore.getType() : \"none\");\n\t\t\t\treturn creator.toString();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/jks/JksSslStoreBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.jks;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.cert.CertificateException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link SslStoreBundle} backed by a Java keystore.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 3.1.0\n */\npublic class JksSslStoreBundle implements SslStoreBundle {\n\n\tprivate final @Nullable JksSslStoreDetails keyStoreDetails;\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final SingletonSupplier<KeyStore> keyStore;\n\n\tprivate final SingletonSupplier<KeyStore> trustStore;\n\n\t/**\n\t * Create a new {@link JksSslStoreBundle} instance.\n\t * @param keyStoreDetails the key store details\n\t * @param trustStoreDetails the trust store details\n\t */\n\tpublic JksSslStoreBundle(@Nullable JksSslStoreDetails keyStoreDetails,\n\t\t\t@Nullable JksSslStoreDetails trustStoreDetails) {\n\t\tthis(keyStoreDetails, trustStoreDetails, ApplicationResourceLoader.get());\n\t}\n\n\t/**\n\t * Create a new {@link JksSslStoreBundle} instance.\n\t * @param keyStoreDetails the key store details\n\t * @param trustStoreDetails the trust store details\n\t * @param resourceLoader the resource loader used to load content\n\t * @since 3.3.5\n\t */\n\tpublic JksSslStoreBundle(@Nullable JksSslStoreDetails keyStoreDetails,\n\t\t\t@Nullable JksSslStoreDetails trustStoreDetails, ResourceLoader resourceLoader) {\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\tthis.keyStoreDetails = keyStoreDetails;\n\t\tthis.resourceLoader = resourceLoader;\n\t\tthis.keyStore = SingletonSupplier.of(() -> createKeyStore(\"key\", keyStoreDetails));\n\t\tthis.trustStore = SingletonSupplier.of(() -> createKeyStore(\"trust\", trustStoreDetails));\n\t}\n\n\t@Override\n\tpublic @Nullable KeyStore getKeyStore() {\n\t\treturn this.keyStore.get();\n\t}\n\n\t@Override\n\tpublic @Nullable String getKeyStorePassword() {\n\t\treturn (this.keyStoreDetails != null) ? this.keyStoreDetails.password() : null;\n\t}\n\n\t@Override\n\tpublic @Nullable KeyStore getTrustStore() {\n\t\treturn this.trustStore.get();\n\t}\n\n\tprivate @Nullable KeyStore createKeyStore(String name, @Nullable JksSslStoreDetails details) {\n\t\tif (details == null || details.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tString type = (!StringUtils.hasText(details.type())) ? KeyStore.getDefaultType() : details.type();\n\t\t\tchar[] password = (details.password() != null) ? details.password().toCharArray() : null;\n\t\t\tString location = details.location();\n\t\t\tKeyStore store = getKeyStoreInstance(type, details.provider());\n\t\t\tif (isHardwareKeystoreType(type)) {\n\t\t\t\tloadHardwareKeyStore(store, location, password);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tloadKeyStore(store, location, password);\n\t\t\t}\n\t\t\treturn store;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create %s store: %s\".formatted(name, ex.getMessage()), ex);\n\t\t}\n\t}\n\n\tprivate KeyStore getKeyStoreInstance(String type, @Nullable String provider)\n\t\t\tthrows KeyStoreException, NoSuchProviderException {\n\t\treturn (!StringUtils.hasText(provider)) ? KeyStore.getInstance(type) : KeyStore.getInstance(type, provider);\n\t}\n\n\tprivate boolean isHardwareKeystoreType(String type) {\n\t\treturn type.equalsIgnoreCase(\"PKCS11\");\n\t}\n\n\tprivate void loadHardwareKeyStore(KeyStore store, @Nullable String location, char @Nullable [] password)\n\t\t\tthrows IOException, NoSuchAlgorithmException, CertificateException {\n\t\tAssert.state(!StringUtils.hasText(location),\n\t\t\t\t() -> \"Location is '%s', but must be empty or null for PKCS11 hardware key stores\".formatted(location));\n\t\tstore.load(null, password);\n\t}\n\n\tprivate void loadKeyStore(KeyStore store, @Nullable String location, char @Nullable [] password) {\n\t\tAssert.state(StringUtils.hasText(location), () -> \"Location must not be empty or null\");\n\t\ttry {\n\t\t\ttry (InputStream stream = this.resourceLoader.getResource(location).getInputStream()) {\n\t\t\t\tstore.load(stream, password);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not load store from '\" + location + \"'\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tKeyStore keyStore = this.keyStore.get();\n\t\tcreator.append(\"keyStore.type\", (keyStore != null) ? keyStore.getType() : \"none\");\n\t\tString keyStorePassword = getKeyStorePassword();\n\t\tcreator.append(\"keyStorePassword\", (keyStorePassword != null) ? \"******\" : null);\n\t\tKeyStore trustStore = this.trustStore.get();\n\t\tcreator.append(\"trustStore.type\", (trustStore != null) ? trustStore.getType() : \"none\");\n\t\treturn creator.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/jks/JksSslStoreDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.jks;\n\nimport java.security.KeyStore;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Details for an individual trust or key store in a {@link JksSslStoreBundle}.\n *\n * @param type the key store type, for example {@code JKS} or {@code PKCS11}. A\n * {@code null} value will use {@link KeyStore#getDefaultType()}).\n * @param provider the name of the key store provider\n * @param location the location of the key store file or {@code null} if using a\n * {@code PKCS11} hardware store\n * @param password the password used to unlock the store or {@code null}\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic record JksSslStoreDetails(@Nullable String type, @Nullable String provider, @Nullable String location,\n\t\t@Nullable String password) {\n\n\t/**\n\t * Return a new {@link JksSslStoreDetails} instance with a new password.\n\t * @param password the new password\n\t * @return a new {@link JksSslStoreDetails} instance\n\t */\n\tpublic JksSslStoreDetails withPassword(String password) {\n\t\treturn new JksSslStoreDetails(this.type, this.provider, this.location, password);\n\t}\n\n\tboolean isEmpty() {\n\t\treturn isEmpty(this.type) && isEmpty(this.provider) && isEmpty(this.location);\n\t}\n\n\tprivate boolean isEmpty(@Nullable String value) {\n\t\treturn !StringUtils.hasText(value);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link JksSslStoreDetails} instance for the given\n\t * location.\n\t * @param location the location\n\t * @return a new {@link JksSslStoreDetails} instance.\n\t */\n\tpublic static JksSslStoreDetails forLocation(@Nullable String location) {\n\t\treturn new JksSslStoreDetails(null, null, location, null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/jks/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SSL trust material provider for Java KeyStores.\n */\n@NullMarked\npackage org.springframework.boot.ssl.jks;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Management of trust material that can be used to establish an SSL connection.\n */\n@NullMarked\npackage org.springframework.boot.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/LoadedPemSslStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.function.SingletonSupplier;\nimport org.springframework.util.function.ThrowingSupplier;\n\n/**\n * {@link PemSslStore} loaded from {@link PemSslStoreDetails}.\n *\n * @author Phillip Webb\n * @see PemSslStore#load(PemSslStoreDetails)\n */\nfinal class LoadedPemSslStore implements PemSslStore {\n\n\tprivate final PemSslStoreDetails details;\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final Supplier<CertificatesHolder> certificatesSupplier;\n\n\tprivate final Supplier<PrivateKeyHolder> privateKeySupplier;\n\n\tLoadedPemSslStore(PemSslStoreDetails details, ResourceLoader resourceLoader) {\n\t\tAssert.notNull(details, \"'details' must not be null\");\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\tthis.details = details;\n\t\tthis.resourceLoader = resourceLoader;\n\t\tthis.certificatesSupplier = supplier(() -> loadCertificates(details, resourceLoader));\n\t\tthis.privateKeySupplier = supplier(() -> loadPrivateKey(details, resourceLoader));\n\t}\n\n\tprivate static <T> Supplier<T> supplier(ThrowingSupplier<T> supplier) {\n\t\treturn SingletonSupplier.of(supplier.throwing(LoadedPemSslStore::asUncheckedIOException));\n\t}\n\n\tprivate static UncheckedIOException asUncheckedIOException(String message, Exception cause) {\n\t\treturn new UncheckedIOException(message, (IOException) cause);\n\t}\n\n\tprivate static CertificatesHolder loadCertificates(PemSslStoreDetails details, ResourceLoader resourceLoader)\n\t\t\tthrows IOException {\n\t\tPemContent pemContent = PemContent.load(details.certificates(), resourceLoader);\n\t\tif (pemContent == null) {\n\t\t\treturn new CertificatesHolder(null);\n\t\t}\n\t\treturn new CertificatesHolder(pemContent.getCertificates());\n\t}\n\n\tprivate static PrivateKeyHolder loadPrivateKey(PemSslStoreDetails details, ResourceLoader resourceLoader)\n\t\t\tthrows IOException {\n\t\tPemContent pemContent = PemContent.load(details.privateKey(), resourceLoader);\n\t\treturn new PrivateKeyHolder(\n\t\t\t\t(pemContent != null) ? pemContent.getPrivateKey(details.privateKeyPassword()) : null);\n\t}\n\n\t@Override\n\tpublic @Nullable String type() {\n\t\treturn this.details.type();\n\t}\n\n\t@Override\n\tpublic @Nullable String alias() {\n\t\treturn this.details.alias();\n\t}\n\n\t@Override\n\tpublic @Nullable String password() {\n\t\treturn this.details.password();\n\t}\n\n\t@Override\n\tpublic @Nullable List<X509Certificate> certificates() {\n\t\treturn this.certificatesSupplier.get().certificates();\n\t}\n\n\t@Override\n\tpublic @Nullable PrivateKey privateKey() {\n\t\treturn this.privateKeySupplier.get().privateKey();\n\t}\n\n\t@Override\n\tpublic PemSslStore withAlias(@Nullable String alias) {\n\t\treturn new LoadedPemSslStore(this.details.withAlias(alias), this.resourceLoader);\n\t}\n\n\t@Override\n\tpublic PemSslStore withPassword(@Nullable String password) {\n\t\treturn new LoadedPemSslStore(this.details.withPassword(password), this.resourceLoader);\n\t}\n\n\tprivate record PrivateKeyHolder(@Nullable PrivateKey privateKey) {\n\t}\n\n\tprivate record CertificatesHolder(@Nullable List<X509Certificate> certificates) {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemCertificateParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.ByteArrayInputStream;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Parser for X.509 certificates in PEM format.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n */\nfinal class PemCertificateParser {\n\n\tprivate static final String HEADER = \"-+BEGIN\\\\s+.*CERTIFICATE[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String BASE64_TEXT = \"([a-z0-9+/=\\\\r\\\\n]+)\";\n\n\tprivate static final String FOOTER = \"-+END\\\\s+.*CERTIFICATE[^-]*-+\";\n\n\tprivate static final Pattern PATTERN = Pattern.compile(HEADER + BASE64_TEXT + FOOTER, Pattern.CASE_INSENSITIVE);\n\n\tprivate PemCertificateParser() {\n\t}\n\n\t/**\n\t * Parse certificates from the specified string.\n\t * @param text the text to parse\n\t * @return the parsed certificates\n\t */\n\t@Contract(\"!null -> !null\")\n\tstatic @Nullable List<X509Certificate> parse(@Nullable String text) {\n\t\tif (text == null) {\n\t\t\treturn null;\n\t\t}\n\t\tCertificateFactory factory = getCertificateFactory();\n\t\tList<X509Certificate> certs = new ArrayList<>();\n\t\treadCertificates(text, factory, certs::add);\n\t\tAssert.state(!CollectionUtils.isEmpty(certs), \"Missing certificates or unrecognized format\");\n\t\treturn List.copyOf(certs);\n\t}\n\n\tprivate static CertificateFactory getCertificateFactory() {\n\t\ttry {\n\t\t\treturn CertificateFactory.getInstance(\"X.509\");\n\t\t}\n\t\tcatch (CertificateException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to get X.509 certificate factory\", ex);\n\t\t}\n\t}\n\n\tprivate static void readCertificates(String text, CertificateFactory factory, Consumer<X509Certificate> consumer) {\n\t\ttry {\n\t\t\tMatcher matcher = PATTERN.matcher(text);\n\t\t\twhile (matcher.find()) {\n\t\t\t\tString encodedText = matcher.group(1);\n\t\t\t\tbyte[] decodedBytes = decodeBase64(encodedText);\n\t\t\t\tByteArrayInputStream inputStream = new ByteArrayInputStream(decodedBytes);\n\t\t\t\twhile (inputStream.available() > 0) {\n\t\t\t\t\tconsumer.accept((X509Certificate) factory.generateCertificate(inputStream));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (CertificateException ex) {\n\t\t\tthrow new IllegalStateException(\"Error reading certificate: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate static byte[] decodeBase64(String content) {\n\t\tbyte[] bytes = content.replace(\"\\r\", \"\").replace(\"\\n\", \"\").getBytes();\n\t\treturn Base64.getDecoder().decode(bytes);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * PEM encoded content that can provide {@link X509Certificate certificates} and\n * {@link PrivateKey private keys}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic final class PemContent {\n\n\tprivate static final Pattern PEM_HEADER = Pattern.compile(\"-+BEGIN\\\\s+[^-]*-+\", Pattern.CASE_INSENSITIVE);\n\n\tprivate static final Pattern PEM_FOOTER = Pattern.compile(\"-+END\\\\s+[^-]*-+\", Pattern.CASE_INSENSITIVE);\n\n\tprivate final String text;\n\n\tprivate PemContent(String text) {\n\t\tthis.text = text.lines().map(String::trim).collect(Collectors.joining(\"\\n\"));\n\t}\n\n\t/**\n\t * Parse and return all {@link X509Certificate certificates} from the PEM content.\n\t * Most PEM files either contain a single certificate or a certificate chain.\n\t * @return the certificates\n\t * @throws IllegalStateException if no certificates could be loaded\n\t */\n\tpublic List<X509Certificate> getCertificates() {\n\t\treturn PemCertificateParser.parse(this.text);\n\t}\n\n\t/**\n\t * Parse and return the {@link PrivateKey private keys} from the PEM content.\n\t * @return the private keys\n\t * @throws IllegalStateException if no private key could be loaded\n\t */\n\tpublic @Nullable PrivateKey getPrivateKey() {\n\t\treturn getPrivateKey(null);\n\t}\n\n\t/**\n\t * Parse and return the {@link PrivateKey private keys} from the PEM content or\n\t * {@code null} if there is no private key.\n\t * @param password the password to decrypt the private keys or {@code null}\n\t * @return the private keys\n\t */\n\tpublic @Nullable PrivateKey getPrivateKey(@Nullable String password) {\n\t\treturn PemPrivateKeyParser.parse(this.text, password);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn Objects.equals(this.text, ((PemContent) obj).text);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.text);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.text;\n\t}\n\n\t/**\n\t * Load {@link PemContent} from the given content (either the PEM content itself or a\n\t * reference to the resource to load).\n\t * @param content the content to load\n\t * @param resourceLoader the resource loader used to load content\n\t * @return a new {@link PemContent} instance or {@code null}\n\t * @throws IOException on IO error\n\t */\n\tstatic @Nullable PemContent load(@Nullable String content, ResourceLoader resourceLoader) throws IOException {\n\t\tif (!StringUtils.hasLength(content)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (isPresentInText(content)) {\n\t\t\treturn new PemContent(content);\n\t\t}\n\t\ttry (InputStream in = resourceLoader.getResource(content).getInputStream()) {\n\t\t\treturn load(in);\n\t\t}\n\t\tcatch (IOException | UncheckedIOException ex) {\n\t\t\tthrow new IOException(\"Error reading certificate or key from file '%s'\".formatted(content), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Load {@link PemContent} from the given {@link Path}.\n\t * @param path a path to load the content from\n\t * @return the loaded PEM content\n\t * @throws IOException on IO error\n\t */\n\tpublic static PemContent load(Path path) throws IOException {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\ttry (InputStream in = Files.newInputStream(path, StandardOpenOption.READ)) {\n\t\t\treturn load(in);\n\t\t}\n\t}\n\n\t/**\n\t * Load {@link PemContent} from the given {@link InputStream}.\n\t * @param in an input stream to load the content from\n\t * @return the loaded PEM content\n\t * @throws IOException on IO error\n\t */\n\tpublic static PemContent load(InputStream in) throws IOException {\n\t\treturn of(StreamUtils.copyToString(in, StandardCharsets.UTF_8));\n\t}\n\n\t/**\n\t * Return a new {@link PemContent} instance containing the given text.\n\t * @param text the text containing PEM encoded content\n\t * @return a new {@link PemContent} instance\n\t */\n\t@Contract(\"!null -> !null\")\n\tpublic static @Nullable PemContent of(@Nullable String text) {\n\t\treturn (text != null) ? new PemContent(text) : null;\n\t}\n\n\t/**\n\t * Return if PEM content is present in the given text.\n\t * @param text the text to check\n\t * @return if the text includes PEM encoded content.\n\t */\n\tpublic static boolean isPresentInText(@Nullable String text) {\n\t\treturn text != null && PEM_HEADER.matcher(text).find() && PEM_FOOTER.matcher(text).find();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemPrivateKeyParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.security.AlgorithmParameters;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HexFormat;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiFunction;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.EncryptedPrivateKeyInfo;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.PBEKeySpec;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.pem.PemPrivateKeyParser.DerElement.TagType;\nimport org.springframework.boot.ssl.pem.PemPrivateKeyParser.DerElement.ValueType;\nimport org.springframework.util.Assert;\n\n/**\n * Parser for PKCS private key files in PEM format.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nfinal class PemPrivateKeyParser {\n\n\tprivate static final String PKCS1_RSA_HEADER = \"-+BEGIN\\\\s+RSA\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String PKCS1_RSA_FOOTER = \"-+END\\\\s+RSA\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String PKCS8_HEADER = \"-+BEGIN\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String PKCS8_FOOTER = \"-+END\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String PKCS8_ENCRYPTED_HEADER = \"-+BEGIN\\\\s+ENCRYPTED\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String PKCS8_ENCRYPTED_FOOTER = \"-+END\\\\s+ENCRYPTED\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String SEC1_EC_HEADER = \"-+BEGIN\\\\s+EC\\\\s+PRIVATE\\\\s+KEY[^-]*-+(?:\\\\s|\\\\r|\\\\n)+\";\n\n\tprivate static final String SEC1_EC_FOOTER = \"-+END\\\\s+EC\\\\s+PRIVATE\\\\s+KEY[^-]*-+\";\n\n\tprivate static final String BASE64_TEXT = \"([a-z0-9+/=\\\\r\\\\n]+)\";\n\n\tpublic static final int BASE64_TEXT_GROUP = 1;\n\n\tprivate static final EncodedOid RSA_ALGORITHM = EncodedOid.OID_1_2_840_113549_1_1_1;\n\n\tprivate static final EncodedOid ELLIPTIC_CURVE_ALGORITHM = EncodedOid.OID_1_2_840_10045_2_1;\n\n\tprivate static final EncodedOid ELLIPTIC_CURVE_384_BIT = EncodedOid.OID_1_3_132_0_34;\n\n\tprivate static final Map<EncodedOid, String> ALGORITHMS;\n\tstatic {\n\t\tMap<EncodedOid, String> algorithms = new HashMap<>();\n\t\talgorithms.put(EncodedOid.OID_1_2_840_113549_1_1_1, \"RSA\");\n\t\talgorithms.put(EncodedOid.OID_1_2_840_113549_1_1_10, \"RSA\");\n\t\talgorithms.put(EncodedOid.OID_1_2_840_10040_4_1, \"DSA\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_110, \"XDH\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_111, \"XDH\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_112, \"EdDSA\");\n\t\talgorithms.put(EncodedOid.OID_1_3_101_113, \"EdDSA\");\n\t\talgorithms.put(EncodedOid.OID_1_2_840_10045_2_1, \"EC\");\n\t\tALGORITHMS = Collections.unmodifiableMap(algorithms);\n\t}\n\n\tprivate static final List<PemParser> PEM_PARSERS;\n\tstatic {\n\t\tList<PemParser> parsers = new ArrayList<>();\n\t\tparsers.add(new PemParser(PKCS1_RSA_HEADER, PKCS1_RSA_FOOTER, PemPrivateKeyParser::createKeySpecForPkcs1Rsa,\n\t\t\t\t\"RSA\"));\n\t\tparsers.add(new PemParser(SEC1_EC_HEADER, SEC1_EC_FOOTER, PemPrivateKeyParser::createKeySpecForSec1Ec, \"EC\"));\n\t\tparsers.add(new PemParser(PKCS8_HEADER, PKCS8_FOOTER, PemPrivateKeyParser::createKeySpecForPkcs8, \"RSA\",\n\t\t\t\t\"RSASSA-PSS\", \"EC\", \"DSA\", \"EdDSA\", \"XDH\"));\n\t\tparsers.add(new PemParser(PKCS8_ENCRYPTED_HEADER, PKCS8_ENCRYPTED_FOOTER,\n\t\t\t\tPemPrivateKeyParser::createKeySpecForPkcs8Encrypted, \"RSA\", \"RSASSA-PSS\", \"EC\", \"DSA\", \"EdDSA\", \"XDH\"));\n\t\tPEM_PARSERS = Collections.unmodifiableList(parsers);\n\t}\n\n\tprivate PemPrivateKeyParser() {\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForPkcs1Rsa(byte[] bytes, @Nullable String password) {\n\t\treturn createKeySpecForAlgorithm(bytes, RSA_ALGORITHM, null);\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForSec1Ec(byte[] bytes, @Nullable String password) {\n\t\tDerElement ecPrivateKey = DerElement.of(bytes);\n\t\tAssert.state(ecPrivateKey != null, \"Unable to find private key\");\n\t\tAssert.state(ecPrivateKey.isType(ValueType.ENCODED, TagType.SEQUENCE),\n\t\t\t\t\"Key spec should be an ASN.1 encoded sequence\");\n\t\tDerElement version = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(version != null && version.isType(ValueType.PRIMITIVE, TagType.INTEGER),\n\t\t\t\t\"Key spec should start with version\");\n\t\tAssert.state(version.getContents().remaining() == 1 && version.getContents().get() == 1,\n\t\t\t\t\"Key spec version must be 1\");\n\t\tDerElement privateKey = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(privateKey != null && privateKey.isType(ValueType.PRIMITIVE, TagType.OCTET_STRING),\n\t\t\t\t\"Key spec should contain private key\");\n\t\tDerElement parameters = DerElement.of(ecPrivateKey.getContents());\n\t\treturn createKeySpecForAlgorithm(bytes, ELLIPTIC_CURVE_ALGORITHM, getEcParameters(parameters));\n\t}\n\n\tprivate static EncodedOid getEcParameters(@Nullable DerElement parameters) {\n\t\tif (parameters == null) {\n\t\t\treturn ELLIPTIC_CURVE_384_BIT;\n\t\t}\n\t\tAssert.state(parameters.isType(ValueType.ENCODED), \"Key spec should contain encoded parameters\");\n\t\tDerElement contents = DerElement.of(parameters.getContents());\n\t\tAssert.state(contents != null && contents.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),\n\t\t\t\t\"Key spec parameters should contain object identifier\");\n\t\treturn EncodedOid.of(contents);\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForAlgorithm(byte[] bytes, EncodedOid algorithm,\n\t\t\t@Nullable EncodedOid parameters) {\n\t\ttry {\n\t\t\tDerEncoder encoder = new DerEncoder();\n\t\t\tencoder.integer(0x00); // Version 0\n\t\t\tDerEncoder algorithmIdentifier = new DerEncoder();\n\t\t\talgorithmIdentifier.objectIdentifier(algorithm);\n\t\t\talgorithmIdentifier.objectIdentifier(parameters);\n\t\t\tencoder.sequence(algorithmIdentifier.toByteArray());\n\t\t\tencoder.octetString(bytes);\n\t\t\treturn new PKCS8EncodedKeySpec(encoder.toSequence());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForPkcs8(byte[] bytes, @Nullable String password) {\n\t\tDerElement ecPrivateKey = DerElement.of(bytes);\n\t\tAssert.state(ecPrivateKey != null, \"Unable to find private key\");\n\t\tAssert.state(ecPrivateKey.isType(ValueType.ENCODED, TagType.SEQUENCE),\n\t\t\t\t\"Key spec should be an ASN.1 encoded sequence\");\n\t\tDerElement version = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(version != null && version.isType(ValueType.PRIMITIVE, TagType.INTEGER),\n\t\t\t\t\"Key spec should start with version\");\n\t\tDerElement sequence = DerElement.of(ecPrivateKey.getContents());\n\t\tAssert.state(sequence != null && sequence.isType(ValueType.ENCODED, TagType.SEQUENCE),\n\t\t\t\t\"Key spec should contain private key\");\n\t\tDerElement algorithmId = DerElement.of(sequence.getContents());\n\t\tAssert.state(algorithmId != null && algorithmId.isType(ValueType.PRIMITIVE, TagType.OBJECT_IDENTIFIER),\n\t\t\t\t\"Key spec container object identifier\");\n\t\tString algorithmName = ALGORITHMS.get(EncodedOid.of(algorithmId));\n\t\treturn (algorithmName != null) ? new PKCS8EncodedKeySpec(bytes, algorithmName) : new PKCS8EncodedKeySpec(bytes);\n\t}\n\n\tprivate static PKCS8EncodedKeySpec createKeySpecForPkcs8Encrypted(byte[] bytes, @Nullable String password) {\n\t\treturn Pkcs8PrivateKeyDecryptor.decrypt(bytes, password);\n\t}\n\n\t/**\n\t * Parse a private key from the specified string.\n\t * @param text the text to parse\n\t * @return the parsed private key\n\t */\n\tstatic @Nullable PrivateKey parse(String text) {\n\t\treturn parse(text, null);\n\t}\n\n\t/**\n\t * Parse a private key from the specified string, using the provided password for\n\t * decryption if necessary.\n\t * @param text the text to parse\n\t * @param password the password used to decrypt an encrypted private key\n\t * @return the parsed private key\n\t */\n\tstatic @Nullable PrivateKey parse(@Nullable String text, @Nullable String password) {\n\t\tif (text == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tfor (PemParser pemParser : PEM_PARSERS) {\n\t\t\t\tPrivateKey privateKey = pemParser.parse(text, password);\n\t\t\t\tif (privateKey != null) {\n\t\t\t\t\treturn privateKey;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Error loading private key file: \" + ex.getMessage(), ex);\n\t\t}\n\t\tthrow new IllegalStateException(\"Missing private key or unrecognized format\");\n\t}\n\n\t/**\n\t * Parser for a specific PEM format.\n\t */\n\tprivate static class PemParser {\n\n\t\tprivate final Pattern pattern;\n\n\t\tprivate final BiFunction<byte[], @Nullable String, PKCS8EncodedKeySpec> keySpecFactory;\n\n\t\tprivate final String[] algorithms;\n\n\t\tPemParser(String header, String footer,\n\t\t\t\tBiFunction<byte[], @Nullable String, PKCS8EncodedKeySpec> keySpecFactory, String... algorithms) {\n\t\t\tthis.pattern = Pattern.compile(header + BASE64_TEXT + footer, Pattern.CASE_INSENSITIVE);\n\t\t\tthis.keySpecFactory = keySpecFactory;\n\t\t\tthis.algorithms = algorithms;\n\t\t}\n\n\t\t@Nullable PrivateKey parse(String text, @Nullable String password) {\n\t\t\tMatcher matcher = this.pattern.matcher(text);\n\t\t\treturn (!matcher.find()) ? null : parse(decodeBase64(matcher.group(BASE64_TEXT_GROUP)), password);\n\t\t}\n\n\t\tprivate static byte[] decodeBase64(String content) {\n\t\t\tbyte[] contentBytes = content.replace(\"\\r\", \"\").replace(\"\\n\", \"\").getBytes();\n\t\t\treturn Base64.getDecoder().decode(contentBytes);\n\t\t}\n\n\t\tprivate @Nullable PrivateKey parse(byte[] bytes, @Nullable String password) {\n\t\t\tPKCS8EncodedKeySpec keySpec = this.keySpecFactory.apply(bytes, password);\n\t\t\tif (keySpec.getAlgorithm() != null) {\n\t\t\t\ttry {\n\t\t\t\t\tKeyFactory keyFactory = KeyFactory.getInstance(keySpec.getAlgorithm());\n\t\t\t\t\treturn keyFactory.generatePrivate(keySpec);\n\t\t\t\t}\n\t\t\t\tcatch (InvalidKeySpecException | NoSuchAlgorithmException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (String algorithm : this.algorithms) {\n\t\t\t\ttry {\n\t\t\t\t\tKeyFactory keyFactory = KeyFactory.getInstance(algorithm);\n\t\t\t\t\treturn keyFactory.generatePrivate(keySpec);\n\t\t\t\t}\n\t\t\t\tcatch (InvalidKeySpecException | NoSuchAlgorithmException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Simple ASN.1 DER encoder.\n\t */\n\tstatic class DerEncoder {\n\n\t\tprivate final ByteArrayOutputStream stream = new ByteArrayOutputStream();\n\n\t\tvoid objectIdentifier(@Nullable EncodedOid encodedOid) throws IOException {\n\t\t\tint code = (encodedOid != null) ? 0x06 : 0x05;\n\t\t\tcodeLengthBytes(code, (encodedOid != null) ? encodedOid.toByteArray() : null);\n\t\t}\n\n\t\tvoid integer(int... encodedInteger) throws IOException {\n\t\t\tcodeLengthBytes(0x02, bytes(encodedInteger));\n\t\t}\n\n\t\tvoid octetString(byte[] bytes) throws IOException {\n\t\t\tcodeLengthBytes(0x04, bytes);\n\t\t}\n\n\t\tvoid sequence(byte[] bytes) throws IOException {\n\t\t\tcodeLengthBytes(0x30, bytes);\n\t\t}\n\n\t\tvoid codeLengthBytes(int code, byte @Nullable [] bytes) throws IOException {\n\t\t\tthis.stream.write(code);\n\t\t\tint length = (bytes != null) ? bytes.length : 0;\n\t\t\tif (length <= 127) {\n\t\t\t\tthis.stream.write(length & 0xFF);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tByteArrayOutputStream lengthStream = new ByteArrayOutputStream();\n\t\t\t\twhile (length != 0) {\n\t\t\t\t\tlengthStream.write(length & 0xFF);\n\t\t\t\t\tlength = length >> 8;\n\t\t\t\t}\n\t\t\t\tbyte[] lengthBytes = lengthStream.toByteArray();\n\t\t\t\tthis.stream.write(0x80 | lengthBytes.length);\n\t\t\t\tfor (int i = lengthBytes.length - 1; i >= 0; i--) {\n\t\t\t\t\tthis.stream.write(lengthBytes[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (bytes != null) {\n\t\t\t\tthis.stream.write(bytes);\n\t\t\t}\n\t\t}\n\n\t\tprivate static byte @Nullable [] bytes(int @Nullable ... elements) {\n\t\t\tif (elements == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tbyte[] result = new byte[elements.length];\n\t\t\tfor (int i = 0; i < elements.length; i++) {\n\t\t\t\tresult[i] = (byte) elements[i];\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tbyte[] toSequence() throws IOException {\n\t\t\tDerEncoder sequenceEncoder = new DerEncoder();\n\t\t\tsequenceEncoder.sequence(toByteArray());\n\t\t\treturn sequenceEncoder.toByteArray();\n\t\t}\n\n\t\tbyte[] toByteArray() {\n\t\t\treturn this.stream.toByteArray();\n\t\t}\n\n\t}\n\n\t/**\n\t * An ASN.1 DER encoded element.\n\t */\n\tstatic final class DerElement {\n\n\t\tprivate final ValueType valueType;\n\n\t\tprivate final long tagType;\n\n\t\tprivate final ByteBuffer contents;\n\n\t\tprivate DerElement(ByteBuffer bytes) {\n\t\t\tbyte b = bytes.get();\n\t\t\tthis.valueType = ((b & 0x20) == 0) ? ValueType.PRIMITIVE : ValueType.ENCODED;\n\t\t\tthis.tagType = decodeTagType(b, bytes);\n\t\t\tint length = decodeLength(bytes);\n\t\t\tbytes.limit(bytes.position() + length);\n\t\t\tthis.contents = bytes.slice();\n\t\t\tbytes.limit(bytes.capacity());\n\t\t\tbytes.position(bytes.position() + length);\n\t\t}\n\n\t\tprivate long decodeTagType(byte b, ByteBuffer bytes) {\n\t\t\tlong tagType = (b & 0x1F);\n\t\t\tif (tagType != 0x1F) {\n\t\t\t\treturn tagType;\n\t\t\t}\n\t\t\ttagType = 0;\n\t\t\tb = bytes.get();\n\t\t\twhile ((b & 0x80) != 0) {\n\t\t\t\ttagType <<= 7;\n\t\t\t\ttagType = tagType | (b & 0x7F);\n\t\t\t\tb = bytes.get();\n\t\t\t}\n\t\t\treturn tagType;\n\t\t}\n\n\t\tprivate int decodeLength(ByteBuffer bytes) {\n\t\t\tbyte b = bytes.get();\n\t\t\tif ((b & 0x80) == 0) {\n\t\t\t\treturn b & 0x7F;\n\t\t\t}\n\t\t\tint numberOfLengthBytes = (b & 0x7F);\n\t\t\tAssert.state(numberOfLengthBytes != 0, \"Infinite length encoding is not supported\");\n\t\t\tAssert.state(numberOfLengthBytes != 0x7F, \"Reserved length encoding is not supported\");\n\t\t\tAssert.state(numberOfLengthBytes <= 4, \"Length overflow\");\n\t\t\tint length = 0;\n\t\t\tfor (int i = 0; i < numberOfLengthBytes; i++) {\n\t\t\t\tlength <<= 8;\n\t\t\t\tlength |= (bytes.get() & 0xFF);\n\t\t\t}\n\t\t\treturn length;\n\t\t}\n\n\t\tboolean isType(ValueType valueType) {\n\t\t\treturn this.valueType == valueType;\n\t\t}\n\n\t\tboolean isType(ValueType valueType, TagType tagType) {\n\t\t\treturn this.valueType == valueType && this.tagType == tagType.getNumber();\n\t\t}\n\n\t\tByteBuffer getContents() {\n\t\t\treturn this.contents;\n\t\t}\n\n\t\tstatic @Nullable DerElement of(byte[] bytes) {\n\t\t\treturn of(ByteBuffer.wrap(bytes));\n\t\t}\n\n\t\tstatic @Nullable DerElement of(ByteBuffer bytes) {\n\t\t\treturn (bytes.remaining() > 0) ? new DerElement(bytes) : null;\n\t\t}\n\n\t\tenum ValueType {\n\n\t\t\tPRIMITIVE, ENCODED\n\n\t\t}\n\n\t\tenum TagType {\n\n\t\t\tINTEGER(0x02), OCTET_STRING(0x04), OBJECT_IDENTIFIER(0x06), SEQUENCE(0x10);\n\n\t\t\tprivate final int number;\n\n\t\t\tTagType(int number) {\n\t\t\t\tthis.number = number;\n\t\t\t}\n\n\t\t\tint getNumber() {\n\t\t\t\treturn this.number;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Decryptor for PKCS8 encoded private keys.\n\t */\n\tstatic class Pkcs8PrivateKeyDecryptor {\n\n\t\tpublic static final String PBES2_ALGORITHM = \"PBES2\";\n\n\t\tstatic PKCS8EncodedKeySpec decrypt(byte[] bytes, @Nullable String password) {\n\t\t\tAssert.state(password != null, \"Password is required for an encrypted private key\");\n\t\t\ttry {\n\t\t\t\tEncryptedPrivateKeyInfo keyInfo = new EncryptedPrivateKeyInfo(bytes);\n\t\t\t\tAlgorithmParameters algorithmParameters = keyInfo.getAlgParameters();\n\t\t\t\tString encryptionAlgorithm = getEncryptionAlgorithm(algorithmParameters, keyInfo.getAlgName());\n\t\t\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(encryptionAlgorithm);\n\t\t\t\tSecretKey key = keyFactory.generateSecret(new PBEKeySpec(password.toCharArray()));\n\t\t\t\tCipher cipher = Cipher.getInstance(encryptionAlgorithm);\n\t\t\t\tcipher.init(Cipher.DECRYPT_MODE, key, algorithmParameters);\n\t\t\t\treturn keyInfo.getKeySpec(cipher);\n\t\t\t}\n\t\t\tcatch (IOException | GeneralSecurityException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Error decrypting private key\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate static String getEncryptionAlgorithm(@Nullable AlgorithmParameters algParameters, String algName) {\n\t\t\tif (algParameters != null && PBES2_ALGORITHM.equals(algName)) {\n\t\t\t\treturn algParameters.toString();\n\t\t\t}\n\t\t\treturn algName;\n\t\t}\n\n\t}\n\n\t/**\n\t * ANS.1 encoded object identifier.\n\t */\n\tstatic final class EncodedOid {\n\n\t\tstatic final EncodedOid OID_1_2_840_10040_4_1 = EncodedOid.of(\"2a8648ce380401\");\n\t\tstatic final EncodedOid OID_1_2_840_113549_1_1_1 = EncodedOid.of(\"2A864886F70D010101\");\n\t\tstatic final EncodedOid OID_1_2_840_113549_1_1_10 = EncodedOid.of(\"2a864886f70d01010a\");\n\t\tstatic final EncodedOid OID_1_3_101_110 = EncodedOid.of(\"2b656e\");\n\t\tstatic final EncodedOid OID_1_3_101_111 = EncodedOid.of(\"2b656f\");\n\t\tstatic final EncodedOid OID_1_3_101_112 = EncodedOid.of(\"2b6570\");\n\t\tstatic final EncodedOid OID_1_3_101_113 = EncodedOid.of(\"2b6571\");\n\t\tstatic final EncodedOid OID_1_2_840_10045_2_1 = EncodedOid.of(\"2a8648ce3d0201\");\n\t\tstatic final EncodedOid OID_1_3_132_0_34 = EncodedOid.of(\"2b81040022\");\n\n\t\tprivate final byte[] value;\n\n\t\tprivate EncodedOid(byte[] value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tbyte[] toByteArray() {\n\t\t\treturn this.value.clone();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn Arrays.equals(this.value, ((EncodedOid) obj).value);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Arrays.hashCode(this.value);\n\t\t}\n\n\t\tstatic EncodedOid of(String hexString) {\n\t\t\treturn of(HexFormat.of().parseHex(hexString));\n\t\t}\n\n\t\tstatic EncodedOid of(DerElement derElement) {\n\t\t\treturn of(derElement.getContents());\n\t\t}\n\n\t\tstatic EncodedOid of(ByteBuffer byteBuffer) {\n\t\t\treturn of(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining());\n\t\t}\n\n\t\tstatic EncodedOid of(byte[] bytes) {\n\t\t\treturn of(bytes, 0, bytes.length);\n\t\t}\n\n\t\tstatic EncodedOid of(byte[] bytes, int off, int len) {\n\t\t\tbyte[] value = new byte[len];\n\t\t\tSystem.arraycopy(bytes, off, value, 0, len);\n\t\t\treturn new EncodedOid(value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.security.KeyStore;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\n\n/**\n * An individual trust or key store that has been loaded from PEM content.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see PemSslStoreDetails\n * @see PemContent\n */\npublic interface PemSslStore {\n\n\t/**\n\t * The key store type, for example {@code JKS} or {@code PKCS11}. A {@code null} value\n\t * will use {@link KeyStore#getDefaultType()}).\n\t * @return the key store type\n\t */\n\t@Nullable String type();\n\n\t/**\n\t * The alias used when setting entries in the {@link KeyStore}.\n\t * @return the alias\n\t */\n\t@Nullable String alias();\n\n\t/**\n\t * The password used when\n\t * {@link KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[])\n\t * setting key entries} in the {@link KeyStore}.\n\t * @return the password\n\t */\n\t@Nullable String password();\n\n\t/**\n\t * The certificates for this store. When a {@link #privateKey() private key} is\n\t * present the returned value is treated as a certificate chain, otherwise it is\n\t * treated a list of certificates that should all be registered.\n\t * @return the X509 certificates\n\t */\n\t@Nullable List<X509Certificate> certificates();\n\n\t/**\n\t * The private key for this store or {@code null}.\n\t * @return the private key\n\t */\n\t@Nullable PrivateKey privateKey();\n\n\t/**\n\t * Return a new {@link PemSslStore} instance with a new alias.\n\t * @param alias the new alias\n\t * @return a new {@link PemSslStore} instance\n\t */\n\tdefault PemSslStore withAlias(@Nullable String alias) {\n\t\tList<X509Certificate> certificates = certificates();\n\t\tAssert.notNull(certificates, \"'certificates' must not be null\");\n\t\treturn of(type(), alias, password(), certificates, privateKey());\n\t}\n\n\t/**\n\t * Return a new {@link PemSslStore} instance with a new password.\n\t * @param password the new password\n\t * @return a new {@link PemSslStore} instance\n\t */\n\tdefault PemSslStore withPassword(@Nullable String password) {\n\t\tList<X509Certificate> certificates = certificates();\n\t\tAssert.notNull(certificates, \"'certificates' must not be null\");\n\t\treturn of(type(), alias(), password, certificates, privateKey());\n\t}\n\n\t/**\n\t * Return a {@link PemSslStore} instance loaded using the given\n\t * {@link PemSslStoreDetails}.\n\t * @param details the PEM store details\n\t * @return a loaded {@link PemSslStore} or {@code null}.\n\t */\n\tstatic @Nullable PemSslStore load(@Nullable PemSslStoreDetails details) {\n\t\treturn load(details, ApplicationResourceLoader.get());\n\t}\n\n\t/**\n\t * Return a {@link PemSslStore} instance loaded using the given\n\t * {@link PemSslStoreDetails}.\n\t * @param details the PEM store details\n\t * @param resourceLoader the resource loader used to load content\n\t * @return a loaded {@link PemSslStore} or {@code null}.\n\t * @since 3.3.5\n\t */\n\tstatic @Nullable PemSslStore load(@Nullable PemSslStoreDetails details, ResourceLoader resourceLoader) {\n\t\tif (details == null || details.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new LoadedPemSslStore(details, resourceLoader);\n\t}\n\n\t/**\n\t * Factory method that can be used to create a new {@link PemSslStore} with the given\n\t * values.\n\t * @param type the key store type\n\t * @param certificates the certificates for this store\n\t * @param privateKey the private key\n\t * @return a new {@link PemSslStore} instance\n\t */\n\tstatic PemSslStore of(@Nullable String type, List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {\n\t\treturn of(type, null, null, certificates, privateKey);\n\t}\n\n\t/**\n\t * Factory method that can be used to create a new {@link PemSslStore} with the given\n\t * values.\n\t * @param certificates the certificates for this store\n\t * @param privateKey the private key\n\t * @return a new {@link PemSslStore} instance\n\t */\n\tstatic PemSslStore of(List<X509Certificate> certificates, @Nullable PrivateKey privateKey) {\n\t\treturn of(null, null, null, certificates, privateKey);\n\t}\n\n\t/**\n\t * Factory method that can be used to create a new {@link PemSslStore} with the given\n\t * values.\n\t * @param type the key store type\n\t * @param alias the alias used when setting entries in the {@link KeyStore}\n\t * @param password the password used\n\t * {@link KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[])\n\t * setting key entries} in the {@link KeyStore}\n\t * @param certificates the certificates for this store\n\t * @param privateKey the private key\n\t * @return a new {@link PemSslStore} instance\n\t */\n\tstatic PemSslStore of(@Nullable String type, @Nullable String alias, @Nullable String password,\n\t\t\tList<X509Certificate> certificates, @Nullable PrivateKey privateKey) {\n\t\tAssert.notEmpty(certificates, \"'certificates' must not be empty\");\n\t\treturn new PemSslStore() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String type() {\n\t\t\t\treturn type;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String alias() {\n\t\t\t\treturn alias;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String password() {\n\t\t\t\treturn password;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic List<X509Certificate> certificates() {\n\t\t\t\treturn certificates;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable PrivateKey privateKey() {\n\t\t\t\treturn privateKey;\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStoreBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.IOException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link SslStoreBundle} backed by PEM-encoded certificates and private keys.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 3.1.0\n */\npublic class PemSslStoreBundle implements SslStoreBundle {\n\n\tprivate static final String DEFAULT_ALIAS = \"ssl\";\n\n\tprivate final SingletonSupplier<KeyStore> keyStore;\n\n\tprivate final SingletonSupplier<KeyStore> trustStore;\n\n\t/**\n\t * Create a new {@link PemSslStoreBundle} instance.\n\t * @param keyStoreDetails the key store details\n\t * @param trustStoreDetails the trust store details\n\t */\n\tpublic PemSslStoreBundle(@Nullable PemSslStoreDetails keyStoreDetails,\n\t\t\t@Nullable PemSslStoreDetails trustStoreDetails) {\n\t\tthis(PemSslStore.load(keyStoreDetails), PemSslStore.load(trustStoreDetails));\n\t}\n\n\t/**\n\t * Create a new {@link PemSslStoreBundle} instance.\n\t * @param pemKeyStore the PEM key store\n\t * @param pemTrustStore the PEM trust store\n\t * @since 3.2.0\n\t */\n\tpublic PemSslStoreBundle(@Nullable PemSslStore pemKeyStore, @Nullable PemSslStore pemTrustStore) {\n\t\tthis.keyStore = SingletonSupplier.of(() -> createKeyStore(\"key\", pemKeyStore));\n\t\tthis.trustStore = SingletonSupplier.of(() -> createKeyStore(\"trust\", pemTrustStore));\n\t}\n\n\t@Override\n\tpublic @Nullable KeyStore getKeyStore() {\n\t\treturn this.keyStore.get();\n\t}\n\n\t@Override\n\tpublic @Nullable String getKeyStorePassword() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable KeyStore getTrustStore() {\n\t\treturn this.trustStore.get();\n\t}\n\n\tprivate static @Nullable KeyStore createKeyStore(String name, @Nullable PemSslStore pemSslStore) {\n\t\tif (pemSslStore == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tList<X509Certificate> certificates = pemSslStore.certificates();\n\t\t\tAssert.state(!ObjectUtils.isEmpty(certificates), \"Certificates must not be empty\");\n\t\t\tString alias = getAlias(pemSslStore);\n\t\t\tKeyStore store = createKeyStore(pemSslStore.type());\n\t\t\tPrivateKey privateKey = pemSslStore.privateKey();\n\t\t\tif (privateKey != null) {\n\t\t\t\taddPrivateKey(store, privateKey, alias, pemSslStore.password(), certificates);\n\t\t\t}\n\t\t\telse {\n\t\t\t\taddCertificates(store, certificates, alias);\n\t\t\t}\n\t\t\treturn store;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create %s store: %s\".formatted(name, ex.getMessage()), ex);\n\t\t}\n\t}\n\n\tprivate static String getAlias(PemSslStore pemSslStore) {\n\t\tString alias = pemSslStore.alias();\n\t\treturn (alias != null) ? alias : DEFAULT_ALIAS;\n\t}\n\n\tprivate static KeyStore createKeyStore(@Nullable String type)\n\t\t\tthrows KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {\n\t\tKeyStore store = KeyStore.getInstance(StringUtils.hasText(type) ? type : KeyStore.getDefaultType());\n\t\tstore.load(null);\n\t\treturn store;\n\t}\n\n\tprivate static void addPrivateKey(KeyStore keyStore, PrivateKey privateKey, String alias,\n\t\t\t@Nullable String keyPassword, List<X509Certificate> certificateChain) throws KeyStoreException {\n\t\tkeyStore.setKeyEntry(alias, privateKey, (keyPassword != null) ? keyPassword.toCharArray() : null,\n\t\t\t\tcertificateChain.toArray(X509Certificate[]::new));\n\t}\n\n\tprivate static void addCertificates(KeyStore keyStore, List<X509Certificate> certificates, String alias)\n\t\t\tthrows KeyStoreException {\n\t\tfor (int index = 0; index < certificates.size(); index++) {\n\t\t\tString entryAlias = alias + ((certificates.size() == 1) ? \"\" : \"-\" + index);\n\t\t\tX509Certificate certificate = certificates.get(index);\n\t\t\tkeyStore.setCertificateEntry(entryAlias, certificate);\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tKeyStore keyStore = this.keyStore.get();\n\t\tKeyStore trustStore = this.trustStore.get();\n\t\tcreator.append(\"keyStore.type\", (keyStore != null) ? keyStore.getType() : \"none\");\n\t\tcreator.append(\"keyStorePassword\", null);\n\t\tcreator.append(\"trustStore.type\", (trustStore != null) ? trustStore.getType() : \"none\");\n\t\treturn creator.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/PemSslStoreDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.security.KeyStore;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Details for an individual trust or key store in a {@link PemSslStoreBundle}.\n *\n * @param type the key store type, for example {@code JKS} or {@code PKCS11}. A\n * {@code null} value will use {@link KeyStore#getDefaultType()}).\n * @param alias the alias used when setting entries in the {@link KeyStore}\n * @param password the password used\n * {@link KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[])\n * setting key entries} in the {@link KeyStore}\n * @param certificates the certificates content (either the PEM content itself or a\n * reference to the resource to load). When a {@link #privateKey() private key} is present\n * this value is treated as a certificate chain, otherwise it is treated a list of\n * certificates that should all be registered.\n * @param privateKey the private key content (either the PEM content itself or a reference\n * to the resource to load)\n * @param privateKeyPassword a password used to decrypt an encrypted private key\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.1.0\n * @see PemSslStore#load(PemSslStoreDetails)\n */\npublic record PemSslStoreDetails(@Nullable String type, @Nullable String alias, @Nullable String password,\n\t\t@Nullable String certificates, @Nullable String privateKey, @Nullable String privateKeyPassword) {\n\n\t/**\n\t * Create a new {@link PemSslStoreDetails} instance.\n\t * @param type the key store type, for example {@code JKS} or {@code PKCS11}. A\n\t * {@code null} value will use {@link KeyStore#getDefaultType()}).\n\t * @param alias the alias used when setting entries in the {@link KeyStore}\n\t * @param password the password used\n\t * {@link KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[])\n\t * setting key entries} in the {@link KeyStore}\n\t * @param certificates the certificate content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @param privateKey the private key content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @param privateKeyPassword a password used to decrypt an encrypted private key\n\t * @since 3.2.0\n\t */\n\tpublic PemSslStoreDetails {\n\t}\n\n\t/**\n\t * Create a new {@link PemSslStoreDetails} instance.\n\t * @param type the key store type, for example {@code JKS} or {@code PKCS11}. A\n\t * {@code null} value will use {@link KeyStore#getDefaultType()}).\n\t * @param certificate the certificate content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @param privateKey the private key content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @param privateKeyPassword a password used to decrypt an encrypted private key\n\t */\n\tpublic PemSslStoreDetails(@Nullable String type, @Nullable String certificate, @Nullable String privateKey,\n\t\t\t@Nullable String privateKeyPassword) {\n\t\tthis(type, null, null, certificate, privateKey, privateKeyPassword);\n\t}\n\n\t/**\n\t * Create a new {@link PemSslStoreDetails} instance.\n\t * @param type the key store type, for example {@code JKS} or {@code PKCS11}. A\n\t * {@code null} value will use {@link KeyStore#getDefaultType()}).\n\t * @param certificate the certificate content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @param privateKey the private key content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t */\n\tpublic PemSslStoreDetails(@Nullable String type, @Nullable String certificate, @Nullable String privateKey) {\n\t\tthis(type, certificate, privateKey, null);\n\t}\n\n\t/**\n\t * Return a new {@link PemSslStoreDetails} instance with a new alias.\n\t * @param alias the new alias\n\t * @return a new {@link PemSslStoreDetails} instance\n\t * @since 3.2.0\n\t */\n\tpublic PemSslStoreDetails withAlias(@Nullable String alias) {\n\t\treturn new PemSslStoreDetails(this.type, alias, this.password, this.certificates, this.privateKey,\n\t\t\t\tthis.privateKeyPassword);\n\t}\n\n\t/**\n\t * Return a new {@link PemSslStoreDetails} instance with a new password.\n\t * @param password the new password\n\t * @return a new {@link PemSslStoreDetails} instance\n\t * @since 3.2.0\n\t */\n\tpublic PemSslStoreDetails withPassword(@Nullable String password) {\n\t\treturn new PemSslStoreDetails(this.type, this.alias, password, this.certificates, this.privateKey,\n\t\t\t\tthis.privateKeyPassword);\n\t}\n\n\t/**\n\t * Return a new {@link PemSslStoreDetails} instance with a new private key.\n\t * @param privateKey the new private key\n\t * @return a new {@link PemSslStoreDetails} instance\n\t */\n\tpublic PemSslStoreDetails withPrivateKey(@Nullable String privateKey) {\n\t\treturn new PemSslStoreDetails(this.type, this.alias, this.password, this.certificates, privateKey,\n\t\t\t\tthis.privateKeyPassword);\n\t}\n\n\t/**\n\t * Return a new {@link PemSslStoreDetails} instance with a new private key password.\n\t * @param privateKeyPassword the new private key password\n\t * @return a new {@link PemSslStoreDetails} instance\n\t */\n\tpublic PemSslStoreDetails withPrivateKeyPassword(@Nullable String privateKeyPassword) {\n\t\treturn new PemSslStoreDetails(this.type, this.alias, this.password, this.certificates, this.privateKey,\n\t\t\t\tprivateKeyPassword);\n\t}\n\n\tboolean isEmpty() {\n\t\treturn isEmpty(this.type) && isEmpty(this.certificates) && isEmpty(this.privateKey);\n\t}\n\n\tprivate boolean isEmpty(@Nullable String value) {\n\t\treturn !StringUtils.hasText(value);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link PemSslStoreDetails} instance for the given\n\t * certificate. <b>Note:</b> This method doesn't actually check if the provided value\n\t * only contains a single certificate. It is functionally equivalent to\n\t * {@link #forCertificates(String)}.\n\t * @param certificate the certificate content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @return a new {@link PemSslStoreDetails} instance.\n\t */\n\tpublic static PemSslStoreDetails forCertificate(@Nullable String certificate) {\n\t\treturn forCertificates(certificate);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link PemSslStoreDetails} instance for the given\n\t * certificates.\n\t * @param certificates the certificates content (either the PEM content itself or a\n\t * reference to the resource to load)\n\t * @return a new {@link PemSslStoreDetails} instance.\n\t * @since 3.2.0\n\t */\n\tpublic static PemSslStoreDetails forCertificates(@Nullable String certificates) {\n\t\treturn new PemSslStoreDetails(null, certificates, null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/ssl/pem/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SSL trust material provider for PEM-encoded certificates.\n */\n@NullMarked\npackage org.springframework.boot.ssl.pem;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/AnsiOutputApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * An {@link ApplicationListener} that configures {@link AnsiOutput} depending on the\n * value of the property {@code spring.output.ansi.enabled}. See {@link Enabled} for valid\n * values.\n *\n * @author Raphael von der Grün\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class AnsiOutputApplicationListener\n\t\timplements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\tConfigurableEnvironment environment = event.getEnvironment();\n\t\tBinder.get(environment)\n\t\t\t.bind(\"spring.output.ansi.enabled\", AnsiOutput.Enabled.class)\n\t\t\t.ifBound(AnsiOutput::setEnabled);\n\t\tAnsiOutput.setConsoleAvailable(environment.getProperty(\"spring.output.ansi.console-available\", Boolean.class));\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\t// Apply after EnvironmentPostProcessorApplicationListener\n\t\treturn EnvironmentPostProcessorApplicationListener.DEFAULT_ORDER + 1;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/EnvironmentPostProcessorApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport javax.lang.model.element.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.aot.generate.GeneratedClass;\nimport org.springframework.aot.generate.GeneratedTypeReference;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.beans.BeanInstantiationException;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.logging.DeferredLogs;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.SmartApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.javapoet.CodeBlock;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link SmartApplicationListener} used to trigger {@link EnvironmentPostProcessor\n * EnvironmentPostProcessors} registered in the {@code spring.factories} file.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {\n\n\tstatic final String AOT_FEATURE_NAME = \"EnvironmentPostProcessor\";\n\n\t/**\n\t * The default order for the processor.\n\t */\n\tpublic static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;\n\n\tprivate final DeferredLogs deferredLogs;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\tprivate final Function<@Nullable ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory;\n\n\t/**\n\t * Create a new {@link EnvironmentPostProcessorApplicationListener} with\n\t * {@link EnvironmentPostProcessor} classes loaded through {@code spring.factories}.\n\t */\n\tpublic EnvironmentPostProcessorApplicationListener() {\n\t\tthis(EnvironmentPostProcessorsFactory::fromSpringFactories);\n\t}\n\n\t/**\n\t * Create a new {@link EnvironmentPostProcessorApplicationListener} with post\n\t * processors created by the given factory.\n\t * @param postProcessorsFactory the post processors factory\n\t */\n\tprivate EnvironmentPostProcessorApplicationListener(\n\t\t\tFunction<@Nullable ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory) {\n\t\tthis.postProcessorsFactory = postProcessorsFactory;\n\t\tthis.deferredLogs = new DeferredLogs();\n\t}\n\n\t/**\n\t * Factory method that creates an {@link EnvironmentPostProcessorApplicationListener}\n\t * with a specific {@link EnvironmentPostProcessorsFactory}.\n\t * @param postProcessorsFactory the environment post processor factory\n\t * @return an {@link EnvironmentPostProcessorApplicationListener} instance\n\t */\n\tpublic static EnvironmentPostProcessorApplicationListener with(\n\t\t\tEnvironmentPostProcessorsFactory postProcessorsFactory) {\n\t\treturn new EnvironmentPostProcessorApplicationListener((classloader) -> postProcessorsFactory);\n\t}\n\n\t@Override\n\tpublic boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {\n\t\treturn ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)\n\t\t\t\t|| ApplicationPreparedEvent.class.isAssignableFrom(eventType)\n\t\t\t\t|| ApplicationFailedEvent.class.isAssignableFrom(eventType);\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\tif (event instanceof ApplicationEnvironmentPreparedEvent environmentPreparedEvent) {\n\t\t\tonApplicationEnvironmentPreparedEvent(environmentPreparedEvent);\n\t\t}\n\t\tif (event instanceof ApplicationPreparedEvent) {\n\t\t\tonApplicationPreparedEvent();\n\t\t}\n\t\tif (event instanceof ApplicationFailedEvent) {\n\t\t\tonApplicationFailedEvent();\n\t\t}\n\t}\n\n\tprivate void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\tConfigurableEnvironment environment = event.getEnvironment();\n\t\tSpringApplication application = event.getSpringApplication();\n\t\tList<EnvironmentPostProcessor> postProcessors = getEnvironmentPostProcessors(application.getResourceLoader(),\n\t\t\t\tevent.getBootstrapContext());\n\t\taddAotGeneratedEnvironmentPostProcessorIfNecessary(postProcessors, application);\n\t\tfor (EnvironmentPostProcessor postProcessor : postProcessors) {\n\t\t\tpostProcessor.postProcessEnvironment(environment, application);\n\t\t}\n\t}\n\n\tprivate void onApplicationPreparedEvent() {\n\t\tfinish();\n\t}\n\n\tprivate void onApplicationFailedEvent() {\n\t\tfinish();\n\t}\n\n\tprivate void finish() {\n\t\tthis.deferredLogs.switchOverAll();\n\t}\n\n\tList<EnvironmentPostProcessor> getEnvironmentPostProcessors(@Nullable ResourceLoader resourceLoader,\n\t\t\tConfigurableBootstrapContext bootstrapContext) {\n\t\tClassLoader classLoader = (resourceLoader != null) ? resourceLoader.getClassLoader() : null;\n\t\tEnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader);\n\t\treturn postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs, bootstrapContext);\n\t}\n\n\tprivate void addAotGeneratedEnvironmentPostProcessorIfNecessary(List<EnvironmentPostProcessor> postProcessors,\n\t\t\tSpringApplication springApplication) {\n\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\tClassLoader classLoader = (springApplication.getResourceLoader() != null)\n\t\t\t\t\t? springApplication.getResourceLoader().getClassLoader() : null;\n\t\t\tClass<?> mainApplicationClass = springApplication.getMainApplicationClass();\n\t\t\tAssert.state(mainApplicationClass != null, \"mainApplicationClass not found\");\n\t\t\tString postProcessorClassName = mainApplicationClass.getName() + \"__\" + AOT_FEATURE_NAME;\n\t\t\tif (ClassUtils.isPresent(postProcessorClassName, classLoader)) {\n\t\t\t\tpostProcessors.add(0, instantiateEnvironmentPostProcessor(postProcessorClassName, classLoader));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate EnvironmentPostProcessor instantiateEnvironmentPostProcessor(String postProcessorClassName,\n\t\t\t@Nullable ClassLoader classLoader) {\n\t\ttry {\n\t\t\tClass<?> initializerClass = ClassUtils.resolveClassName(postProcessorClassName, classLoader);\n\t\t\tAssert.isAssignable(EnvironmentPostProcessor.class, initializerClass);\n\t\t\treturn (EnvironmentPostProcessor) BeanUtils.instantiateClass(initializerClass);\n\t\t}\n\t\tcatch (BeanInstantiationException ex) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Failed to instantiate EnvironmentPostProcessor: \" + postProcessorClassName, ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t/**\n\t * Contribute a {@code <Application>__EnvironmentPostProcessor} class that stores AOT\n\t * optimizations.\n\t */\n\tstatic class EnvironmentBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor {\n\n\t\t@Override\n\t\tpublic @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(\n\t\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\t\tEnvironment environment = beanFactory.getBean(ConfigurableApplicationContext.ENVIRONMENT_BEAN_NAME,\n\t\t\t\t\tEnvironment.class);\n\t\t\tString[] activeProfiles = environment.getActiveProfiles();\n\t\t\tString[] defaultProfiles = environment.getDefaultProfiles();\n\t\t\tif (!ObjectUtils.isEmpty(activeProfiles) && !Arrays.equals(activeProfiles, defaultProfiles)) {\n\t\t\t\treturn new EnvironmentAotContribution(activeProfiles);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate static final class EnvironmentAotContribution implements BeanFactoryInitializationAotContribution {\n\n\t\tprivate static final String ENVIRONMENT_VARIABLE = \"environment\";\n\n\t\tprivate final String[] activeProfiles;\n\n\t\tprivate EnvironmentAotContribution(String[] activeProfiles) {\n\t\t\tthis.activeProfiles = activeProfiles;\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\tGeneratedClass generatedClass = generationContext.getGeneratedClasses()\n\t\t\t\t.addForFeature(AOT_FEATURE_NAME, (type) -> {\n\t\t\t\t\ttype.addModifiers(Modifier.PUBLIC);\n\t\t\t\t\ttype.addJavadoc(\"Configure the environment with AOT optimizations.\");\n\t\t\t\t\ttype.addSuperinterface(EnvironmentPostProcessor.class);\n\t\t\t\t});\n\t\t\tgeneratedClass.getMethods().add(\"postProcessEnvironment\", (method) -> {\n\t\t\t\tmethod.addModifiers(Modifier.PUBLIC);\n\t\t\t\tmethod.addAnnotation(Override.class);\n\t\t\t\tmethod.addParameter(ConfigurableEnvironment.class, ENVIRONMENT_VARIABLE);\n\t\t\t\tmethod.addParameter(SpringApplication.class, \"application\");\n\t\t\t\tmethod.addCode(generateActiveProfilesInitializeCode());\n\t\t\t});\n\t\t\tgenerationContext.getRuntimeHints()\n\t\t\t\t.reflection()\n\t\t\t\t.registerType(GeneratedTypeReference.of(generatedClass.getName()),\n\t\t\t\t\t\tMemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t}\n\n\t\tprivate CodeBlock generateActiveProfilesInitializeCode() {\n\t\t\tCodeBlock.Builder code = CodeBlock.builder();\n\t\t\tfor (String activeProfile : this.activeProfiles) {\n\t\t\t\tcode.addStatement(\"$L.addActiveProfile($S)\", ENVIRONMENT_VARIABLE, activeProfile);\n\t\t\t}\n\t\t\treturn code.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/EnvironmentPostProcessorsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * Factory interface used by the {@link EnvironmentPostProcessorApplicationListener} to\n * create the {@link EnvironmentPostProcessor} instances.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface EnvironmentPostProcessorsFactory {\n\n\t/**\n\t * Create all requested {@link EnvironmentPostProcessor} instances.\n\t * @param logFactory a deferred log factory\n\t * @param bootstrapContext a bootstrap context\n\t * @return the post processor instances\n\t */\n\tList<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,\n\t\t\tConfigurableBootstrapContext bootstrapContext);\n\n\t/**\n\t * Return a {@link EnvironmentPostProcessorsFactory} backed by\n\t * {@code spring.factories}.\n\t * @param classLoader the source class loader\n\t * @return an {@link EnvironmentPostProcessorsFactory} instance\n\t */\n\tstatic EnvironmentPostProcessorsFactory fromSpringFactories(@Nullable ClassLoader classLoader) {\n\t\treturn new SpringFactoriesEnvironmentPostProcessorsFactory(\n\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation(classLoader));\n\t}\n\n\t/**\n\t * Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post\n\t * processors from the given classes.\n\t * @param classes the post processor classes\n\t * @return an {@link EnvironmentPostProcessorsFactory} instance\n\t */\n\tstatic EnvironmentPostProcessorsFactory of(Class<?>... classes) {\n\t\treturn new ReflectionEnvironmentPostProcessorsFactory(classes);\n\t}\n\n\t/**\n\t * Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post\n\t * processors from the given class names.\n\t * @param classNames the post processor class names\n\t * @return an {@link EnvironmentPostProcessorsFactory} instance\n\t */\n\tstatic EnvironmentPostProcessorsFactory of(String... classNames) {\n\t\treturn of(null, classNames);\n\t}\n\n\t/**\n\t * Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post\n\t * processors from the given class names.\n\t * @param classLoader the source class loader\n\t * @param classNames the post processor class names\n\t * @return an {@link EnvironmentPostProcessorsFactory} instance\n\t */\n\tstatic EnvironmentPostProcessorsFactory of(@Nullable ClassLoader classLoader, String... classNames) {\n\t\treturn new ReflectionEnvironmentPostProcessorsFactory(classLoader, classNames);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/RandomValuePropertySourceEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport org.apache.commons.logging.Log;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.env.RandomValuePropertySource;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * {@link EnvironmentPostProcessor} to add the {@link RandomValuePropertySource}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class RandomValuePropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\t/**\n\t * The default order of this post-processor.\n\t */\n\tpublic static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 1;\n\n\tprivate final Log logger;\n\n\t/**\n\t * Create a new {@link RandomValuePropertySourceEnvironmentPostProcessor} instance.\n\t * @param logFactory the log factory to use\n\t * @since 3.0.0\n\t */\n\tpublic RandomValuePropertySourceEnvironmentPostProcessor(DeferredLogFactory logFactory) {\n\t\tthis.logger = logFactory.getLog(RandomValuePropertySourceEnvironmentPostProcessor.class);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tRandomValuePropertySource.addToEnvironment(environment, this.logger);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/ReflectionEnvironmentPostProcessorsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.boot.util.Instantiator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnvironmentPostProcessorsFactory} implementation that uses reflection to create\n * instances.\n *\n * @author Phillip Webb\n */\nclass ReflectionEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {\n\n\tprivate final @Nullable List<Class<?>> classes;\n\n\tprivate @Nullable ClassLoader classLoader;\n\n\tprivate @Nullable final List<String> classNames;\n\n\tReflectionEnvironmentPostProcessorsFactory(Class<?>... classes) {\n\t\tthis.classes = new ArrayList<>(Arrays.asList(classes));\n\t\tthis.classNames = null;\n\t}\n\n\tReflectionEnvironmentPostProcessorsFactory(@Nullable ClassLoader classLoader, String... classNames) {\n\t\tthis(classLoader, Arrays.asList(classNames));\n\t}\n\n\tReflectionEnvironmentPostProcessorsFactory(@Nullable ClassLoader classLoader, List<String> classNames) {\n\t\tthis.classes = null;\n\t\tthis.classLoader = classLoader;\n\t\tthis.classNames = classNames;\n\t}\n\n\t@Override\n\tpublic List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,\n\t\t\tConfigurableBootstrapContext bootstrapContext) {\n\t\tInstantiator<EnvironmentPostProcessor> instantiator = new Instantiator<>(EnvironmentPostProcessor.class,\n\t\t\t\t(parameters) -> {\n\t\t\t\t\tparameters.add(DeferredLogFactory.class, logFactory);\n\t\t\t\t\tparameters.add(Log.class, logFactory::getLog);\n\t\t\t\t\tparameters.add(ConfigurableBootstrapContext.class, bootstrapContext);\n\t\t\t\t\tparameters.add(BootstrapContext.class, bootstrapContext);\n\t\t\t\t\tparameters.add(BootstrapRegistry.class, bootstrapContext);\n\t\t\t\t});\n\t\tif (this.classes != null) {\n\t\t\treturn instantiator.instantiateTypes(this.classes);\n\t\t}\n\t\tAssert.state(this.classNames != null, \"'classNames' must not be null\");\n\t\treturn instantiator.instantiate(this.classLoader, this.classNames);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/SpringApplicationJsonEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.json.JsonParser;\nimport org.springframework.boot.json.JsonParserFactory;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\n/**\n * An {@link EnvironmentPostProcessor} that parses JSON from\n * {@code spring.application.json} or equivalently {@code SPRING_APPLICATION_JSON} and\n * adds it as a map property source to the {@link Environment}. The new properties are\n * added with higher priority than the system properties.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\npublic class SpringApplicationJsonEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\t/**\n\t * Name of the {@code spring.application.json} property.\n\t */\n\tpublic static final String SPRING_APPLICATION_JSON_PROPERTY = \"spring.application.json\";\n\n\t/**\n\t * Name of the {@code SPRING_APPLICATION_JSON} environment variable.\n\t */\n\tpublic static final String SPRING_APPLICATION_JSON_ENVIRONMENT_VARIABLE = \"SPRING_APPLICATION_JSON\";\n\n\tprivate static final String SERVLET_ENVIRONMENT_CLASS = \"org.springframework.web.\"\n\t\t\t+ \"context.support.StandardServletEnvironment\";\n\n\tprivate static final Set<String> SERVLET_ENVIRONMENT_PROPERTY_SOURCES = new LinkedHashSet<>(\n\t\t\tArrays.asList(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tStandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tStandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME));\n\n\t/**\n\t * The default order for the processor.\n\t */\n\tpublic static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 5;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tpropertySources.stream()\n\t\t\t.map(JsonPropertyValue::get)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.ifPresent((v) -> processJson(environment, v));\n\t}\n\n\tprivate void processJson(ConfigurableEnvironment environment, JsonPropertyValue propertyValue) {\n\t\tJsonParser parser = JsonParserFactory.getJsonParser();\n\t\tMap<String, Object> map = parser.parseMap(propertyValue.getJson());\n\t\tif (!map.isEmpty()) {\n\t\t\taddJsonPropertySource(environment, new JsonPropertySource(propertyValue, flatten(map)));\n\t\t}\n\t}\n\n\t/**\n\t * Flatten the map keys using period separator.\n\t * @param map the map that should be flattened\n\t * @return the flattened map\n\t */\n\tprivate Map<String, Object> flatten(Map<String, Object> map) {\n\t\tMap<String, Object> result = new LinkedHashMap<>();\n\t\tflatten(null, result, map);\n\t\treturn result;\n\t}\n\n\tprivate void flatten(@Nullable String prefix, Map<String, Object> result, Map<String, Object> map) {\n\t\tString namePrefix = (prefix != null) ? prefix + \".\" : \"\";\n\t\tmap.forEach((key, value) -> extract(namePrefix + key, result, value));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void extract(String name, Map<String, Object> result, Object value) {\n\t\tif (value instanceof Map<?, ?> map) {\n\t\t\tif (CollectionUtils.isEmpty(map)) {\n\t\t\t\tresult.put(name, value);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tflatten(name, result, (Map<String, Object>) value);\n\t\t}\n\t\telse if (value instanceof Collection<?> collection) {\n\t\t\tif (CollectionUtils.isEmpty(collection)) {\n\t\t\t\tresult.put(name, value);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tint index = 0;\n\t\t\tfor (Object object : collection) {\n\t\t\t\textract(name + \"[\" + index + \"]\", result, object);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tresult.put(name, value);\n\t\t}\n\t}\n\n\tprivate void addJsonPropertySource(ConfigurableEnvironment environment, PropertySource<?> source) {\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tString name = findPropertySource(sources);\n\t\tif (sources.contains(name)) {\n\t\t\tsources.addBefore(name, source);\n\t\t}\n\t\telse {\n\t\t\tsources.addFirst(source);\n\t\t}\n\t}\n\n\tprivate String findPropertySource(MutablePropertySources sources) {\n\t\tif (ClassUtils.isPresent(SERVLET_ENVIRONMENT_CLASS, null)) {\n\t\t\tPropertySource<?> servletPropertySource = sources.stream()\n\t\t\t\t.filter((source) -> SERVLET_ENVIRONMENT_PROPERTY_SOURCES.contains(source.getName()))\n\t\t\t\t.findFirst()\n\t\t\t\t.orElse(null);\n\t\t\tif (servletPropertySource != null) {\n\t\t\t\treturn servletPropertySource.getName();\n\t\t\t}\n\t\t}\n\t\treturn StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME;\n\t}\n\n\tprivate static class JsonPropertySource extends MapPropertySource implements OriginLookup<String> {\n\n\t\tprivate final JsonPropertyValue propertyValue;\n\n\t\tJsonPropertySource(JsonPropertyValue propertyValue, Map<String, Object> source) {\n\t\t\tsuper(SPRING_APPLICATION_JSON_PROPERTY, source);\n\t\t\tthis.propertyValue = propertyValue;\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String key) {\n\t\t\treturn this.propertyValue.getOrigin();\n\t\t}\n\n\t}\n\n\tprivate static class JsonPropertyValue {\n\n\t\tprivate static final String[] CANDIDATES = { SPRING_APPLICATION_JSON_PROPERTY,\n\t\t\t\tSPRING_APPLICATION_JSON_ENVIRONMENT_VARIABLE };\n\n\t\tprivate final PropertySource<?> propertySource;\n\n\t\tprivate final String propertyName;\n\n\t\tprivate final String json;\n\n\t\tJsonPropertyValue(PropertySource<?> propertySource, String propertyName, String json) {\n\t\t\tthis.propertySource = propertySource;\n\t\t\tthis.propertyName = propertyName;\n\t\t\tthis.json = json;\n\t\t}\n\n\t\tString getJson() {\n\t\t\treturn this.json;\n\t\t}\n\n\t\tOrigin getOrigin() {\n\t\t\treturn PropertySourceOrigin.get(this.propertySource, this.propertyName);\n\t\t}\n\n\t\tstatic @Nullable JsonPropertyValue get(PropertySource<?> propertySource) {\n\t\t\tfor (String candidate : CANDIDATES) {\n\t\t\t\tObject value = propertySource.getProperty(candidate);\n\t\t\t\tif (value instanceof String string && StringUtils.hasLength(string)) {\n\t\t\t\t\treturn new JsonPropertyValue(propertySource, candidate, string);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/SpringFactoriesEnvironmentPostProcessorsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\n\n/**\n * An {@link EnvironmentPostProcessorsFactory} that uses {@link SpringFactoriesLoader}.\n *\n * @author Andy Wilkinson\n */\nclass SpringFactoriesEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {\n\n\tprivate final SpringFactoriesLoader loader;\n\n\tSpringFactoriesEnvironmentPostProcessorsFactory(SpringFactoriesLoader loader) {\n\t\tthis.loader = loader;\n\t}\n\n\t@Override\n\tpublic List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,\n\t\t\tConfigurableBootstrapContext bootstrapContext) {\n\t\tArgumentResolver argumentResolver = ArgumentResolver.of(DeferredLogFactory.class, logFactory);\n\t\targumentResolver = argumentResolver.and(ConfigurableBootstrapContext.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.and(BootstrapContext.class, bootstrapContext);\n\t\targumentResolver = argumentResolver.and(BootstrapRegistry.class, bootstrapContext);\n\t\tList<Object> postProcessors = new ArrayList<>();\n\t\tpostProcessors.addAll(this.loader.load(EnvironmentPostProcessor.class, argumentResolver));\n\t\tpostProcessors.addAll(loadDeprecatedPostProcessors(argumentResolver));\n\t\tAnnotationAwareOrderComparator.sort(postProcessors);\n\t\treturn postProcessors.stream().map(Adapter::apply).collect(Collectors.toCollection(ArrayList::new));\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate List<org.springframework.boot.env.EnvironmentPostProcessor> loadDeprecatedPostProcessors(\n\t\t\tArgumentResolver argumentResolver) {\n\t\treturn this.loader.load(org.springframework.boot.env.EnvironmentPostProcessor.class, argumentResolver);\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\trecord Adapter(\n\t\t\torg.springframework.boot.env.EnvironmentPostProcessor postProcessor) implements EnvironmentPostProcessor {\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t\tthis.postProcessor.postProcessEnvironment(environment, application);\n\t\t}\n\n\t\tstatic EnvironmentPostProcessor apply(Object source) {\n\t\t\tif (source instanceof EnvironmentPostProcessor environmentPostProcessor) {\n\t\t\t\treturn environmentPostProcessor;\n\t\t\t}\n\t\t\treturn new Adapter((org.springframework.boot.env.EnvironmentPostProcessor) source);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/SystemEnvironmentPropertySourceEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.SystemEnvironmentOrigin;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link EnvironmentPostProcessor} that replaces the systemEnvironment\n * {@link SystemEnvironmentPropertySource} with an\n * {@link OriginAwareSystemEnvironmentPropertySource} that can track the\n * {@link SystemEnvironmentOrigin} for every system environment property.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\t/**\n\t * The default order for the processor.\n\t */\n\tpublic static final int DEFAULT_ORDER = SpringApplicationJsonEnvironmentPostProcessor.DEFAULT_ORDER - 1;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tpostProcessEnvironment(environment, application.getEnvironmentPrefix());\n\t}\n\n\tprivate void postProcessEnvironment(ConfigurableEnvironment environment, @Nullable String environmentPrefix) {\n\t\tString sourceName = StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME;\n\t\tPropertySource<?> propertySource = environment.getPropertySources().get(sourceName);\n\t\tif (propertySource != null) {\n\t\t\treplacePropertySource(environment, sourceName, propertySource, environmentPrefix);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void replacePropertySource(ConfigurableEnvironment environment, String sourceName,\n\t\t\tPropertySource<?> propertySource, @Nullable String environmentPrefix) {\n\t\tMap<String, Object> originalSource = (Map<String, Object>) propertySource.getSource();\n\t\tSystemEnvironmentPropertySource source = new OriginAwareSystemEnvironmentPropertySource(sourceName,\n\t\t\t\toriginalSource, environmentPrefix);\n\t\tenvironment.getPropertySources().replace(sourceName, source);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t/**\n\t * Post-process the given {@link ConfigurableEnvironment} by copying appropriate\n\t * settings from a parent {@link ConfigurableEnvironment}.\n\t * @param environment the environment to post-process\n\t * @param parentEnvironment the parent environment\n\t * @since 3.4.12\n\t */\n\tpublic static void postProcessEnvironment(ConfigurableEnvironment environment,\n\t\t\tConfigurableEnvironment parentEnvironment) {\n\t\tPropertySource<?> parentSystemEnvironmentPropertySource = parentEnvironment.getPropertySources()\n\t\t\t.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);\n\t\tif (parentSystemEnvironmentPropertySource instanceof OriginAwareSystemEnvironmentPropertySource parentOriginAwareSystemEnvironmentPropertySource) {\n\t\t\tnew SystemEnvironmentPropertySourceEnvironmentPostProcessor().postProcessEnvironment(environment,\n\t\t\t\t\tparentOriginAwareSystemEnvironmentPropertySource.getPrefix());\n\t\t}\n\t}\n\n\t/**\n\t * {@link SystemEnvironmentPropertySource} that also tracks {@link Origin}.\n\t */\n\tprotected static class OriginAwareSystemEnvironmentPropertySource extends SystemEnvironmentPropertySource\n\t\t\timplements PropertySourceInfo, OriginLookup<String> {\n\n\t\tprivate final @Nullable String prefix;\n\n\t\tOriginAwareSystemEnvironmentPropertySource(String name, Map<String, Object> source,\n\t\t\t\t@Nullable String environmentPrefix) {\n\t\t\tsuper(name, source);\n\t\t\tthis.prefix = determinePrefix(environmentPrefix);\n\t\t}\n\n\t\tprivate @Nullable String determinePrefix(@Nullable String environmentPrefix) {\n\t\t\tif (!StringUtils.hasText(environmentPrefix)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (environmentPrefix.endsWith(\".\") || environmentPrefix.endsWith(\"_\") || environmentPrefix.endsWith(\"-\")) {\n\t\t\t\treturn environmentPrefix.substring(0, environmentPrefix.length() - 1);\n\t\t\t}\n\t\t\treturn environmentPrefix;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean containsProperty(String name) {\n\t\t\treturn super.containsProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\treturn super.getProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getOrigin(String key) {\n\t\t\tString property = resolvePropertyName(key);\n\t\t\tif (super.containsProperty(property)) {\n\t\t\t\treturn new SystemEnvironmentOrigin(property);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isImmutable() {\n\t\t\treturn (Object) getSource() == System.getenv();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/support/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes supporting application concerns and the org.springframework.boot package.\n */\n@NullMarked\npackage org.springframework.boot.support;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/system/ApplicationHome.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.JarURLConnection;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.Enumeration;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provides access to the application home directory. Attempts to pick a sensible home for\n * both Jar Files, Exploded Archives and directly running applications.\n *\n * @author Phillip Webb\n * @author Raja Kolli\n * @since 2.0.0\n */\npublic class ApplicationHome {\n\n\tprivate final @Nullable File source;\n\n\tprivate final File dir;\n\n\t/**\n\t * Create a new {@link ApplicationHome} instance.\n\t */\n\tpublic ApplicationHome() {\n\t\tthis(null);\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationHome} instance for the specified source class.\n\t * @param sourceClass the source class or {@code null}\n\t */\n\tpublic ApplicationHome(@Nullable Class<?> sourceClass) {\n\t\tthis.source = findSource((sourceClass != null) ? sourceClass : getStartClass());\n\t\tthis.dir = findHomeDir(this.source);\n\t}\n\n\tprivate @Nullable Class<?> getStartClass() {\n\t\ttry {\n\t\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\t\treturn getStartClass(classLoader.getResources(\"META-INF/MANIFEST.MF\"));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable Class<?> getStartClass(Enumeration<URL> manifestResources) {\n\t\twhile (manifestResources.hasMoreElements()) {\n\t\t\ttry (InputStream inputStream = manifestResources.nextElement().openStream()) {\n\t\t\t\tManifest manifest = new Manifest(inputStream);\n\t\t\t\tString startClass = manifest.getMainAttributes().getValue(\"Start-Class\");\n\t\t\t\tif (startClass != null) {\n\t\t\t\t\treturn ClassUtils.forName(startClass, getClass().getClassLoader());\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable File findSource(@Nullable Class<?> sourceClass) {\n\t\ttry {\n\t\t\tProtectionDomain domain = (sourceClass != null) ? sourceClass.getProtectionDomain() : null;\n\t\t\tCodeSource codeSource = (domain != null) ? domain.getCodeSource() : null;\n\t\t\tURL location = (codeSource != null) ? codeSource.getLocation() : null;\n\t\t\tFile source = (location != null) ? findSource(location) : null;\n\t\t\tif (source != null && source.exists() && !isUnitTest()) {\n\t\t\t\treturn source.getAbsoluteFile();\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isUnitTest() {\n\t\ttry {\n\t\t\tStackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();\n\t\t\tfor (int i = stackTrace.length - 1; i >= 0; i--) {\n\t\t\t\tif (stackTrace[i].getClassName().startsWith(\"org.junit.\")) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate File findSource(URL location) throws IOException, URISyntaxException {\n\t\tURLConnection connection = location.openConnection();\n\t\tif (connection instanceof JarURLConnection jarURLConnection) {\n\t\t\treturn getRootJarFile(jarURLConnection.getJarFile());\n\t\t}\n\t\treturn new File(location.toURI());\n\t}\n\n\tprivate File getRootJarFile(JarFile jarFile) {\n\t\tString name = jarFile.getName();\n\t\tint separator = name.indexOf(\"!/\");\n\t\tif (separator > 0) {\n\t\t\tname = name.substring(0, separator);\n\t\t}\n\t\treturn new File(name);\n\t}\n\n\tprivate File findHomeDir(@Nullable File source) {\n\t\tFile homeDir = source;\n\t\thomeDir = (homeDir != null) ? homeDir : findDefaultHomeDir();\n\t\tif (homeDir.isFile()) {\n\t\t\thomeDir = homeDir.getParentFile();\n\t\t}\n\t\thomeDir = homeDir.exists() ? homeDir : new File(\".\");\n\t\treturn homeDir.getAbsoluteFile();\n\t}\n\n\tprivate File findDefaultHomeDir() {\n\t\tString userDir = System.getProperty(\"user.dir\");\n\t\treturn new File(StringUtils.hasLength(userDir) ? userDir : \".\");\n\t}\n\n\t/**\n\t * Returns the underlying source used to find the home directory. This is usually the\n\t * jar file or a directory. Can return {@code null} if the source cannot be\n\t * determined.\n\t * @return the underlying source or {@code null}\n\t */\n\tpublic @Nullable File getSource() {\n\t\treturn this.source;\n\t}\n\n\t/**\n\t * Returns the application home directory.\n\t * @return the home directory (never {@code null})\n\t */\n\tpublic File getDir() {\n\t\treturn this.dir;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getDir().toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/system/ApplicationPid.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * An application process ID.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class ApplicationPid {\n\n\tprivate static final PosixFilePermission[] WRITE_PERMISSIONS = { PosixFilePermission.OWNER_WRITE,\n\t\t\tPosixFilePermission.GROUP_WRITE, PosixFilePermission.OTHERS_WRITE };\n\n\tprivate final @Nullable Long pid;\n\n\tpublic ApplicationPid() {\n\t\tthis.pid = currentProcessPid();\n\t}\n\n\tprotected ApplicationPid(@Nullable Long pid) {\n\t\tthis.pid = pid;\n\t}\n\n\tprivate @Nullable Long currentProcessPid() {\n\t\ttry {\n\t\t\treturn ProcessHandle.current().pid();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Return if the application PID is available.\n\t * @return {@code true} if the PID is available\n\t * @since 3.4.0\n\t */\n\tpublic boolean isAvailable() {\n\t\treturn this.pid != null;\n\t}\n\n\t/**\n\t * Return the application PID as a {@link Long}.\n\t * @return the application PID or {@code null}\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable Long toLong() {\n\t\treturn this.pid;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof ApplicationPid other) {\n\t\t\treturn ObjectUtils.nullSafeEquals(this.pid, other.pid);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHashCode(this.pid);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.pid != null) ? String.valueOf(this.pid) : \"???\";\n\t}\n\n\t/**\n\t * Write the PID to the specified file.\n\t * @param file the PID file\n\t * @throws IllegalStateException if no PID is available.\n\t * @throws IOException if the file cannot be written\n\t */\n\tpublic void write(File file) throws IOException {\n\t\tAssert.state(this.pid != null, \"No PID available\");\n\t\tcreateParentDirectory(file);\n\t\tif (file.exists()) {\n\t\t\tassertCanOverwrite(file);\n\t\t}\n\t\ttry (FileWriter writer = new FileWriter(file)) {\n\t\t\twriter.append(String.valueOf(this.pid));\n\t\t}\n\t}\n\n\tprivate void createParentDirectory(File file) {\n\t\tFile parent = file.getParentFile();\n\t\tif (parent != null) {\n\t\t\tparent.mkdirs();\n\t\t}\n\t}\n\n\tprivate void assertCanOverwrite(File file) throws IOException {\n\t\tif (!file.canWrite() || !canWritePosixFile(file)) {\n\t\t\tthrow new FileNotFoundException(file + \" (permission denied)\");\n\t\t}\n\t}\n\n\tprivate boolean canWritePosixFile(File file) throws IOException {\n\t\ttry {\n\t\t\tSet<PosixFilePermission> permissions = Files.getPosixFilePermissions(file.toPath());\n\t\t\tfor (PosixFilePermission permission : WRITE_PERMISSIONS) {\n\t\t\t\tif (permissions.contains(permission)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\t// Assume that we can\n\t\t\treturn true;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/system/ApplicationTemp.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.FileSystem;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.FileAttribute;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.security.MessageDigest;\nimport java.util.EnumSet;\nimport java.util.HexFormat;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.NativeDetector;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provides access to an application specific temporary directory. Generally speaking\n * different Spring Boot applications will get different locations, however, simply\n * restarting an application will give the same location.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class ApplicationTemp {\n\n\tprivate static final FileAttribute<?>[] NO_FILE_ATTRIBUTES = {};\n\n\tprivate static final EnumSet<PosixFilePermission> DIRECTORY_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,\n\t\t\tPosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);\n\n\tprivate final @Nullable Class<?> sourceClass;\n\n\tprivate final Lock pathLock = new ReentrantLock();\n\n\tprivate volatile @Nullable Path path;\n\n\t/**\n\t * Create a new {@link ApplicationTemp} instance.\n\t */\n\tpublic ApplicationTemp() {\n\t\tthis(null);\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationTemp} instance for the specified source class.\n\t * @param sourceClass the source class or {@code null}\n\t */\n\tpublic ApplicationTemp(@Nullable Class<?> sourceClass) {\n\t\tthis.sourceClass = sourceClass;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getDir().getAbsolutePath();\n\t}\n\n\t/**\n\t * Return the directory to be used for application specific temp files.\n\t * @return the application temp directory\n\t */\n\tpublic File getDir() {\n\t\treturn getPath().toFile();\n\t}\n\n\t/**\n\t * Return a subdirectory of the application temp.\n\t * @param subDir the subdirectory name\n\t * @return a subdirectory\n\t */\n\tpublic File getDir(String subDir) {\n\t\treturn createDirectory(getPath().resolve(subDir)).toFile();\n\t}\n\n\tprivate Path getPath() {\n\t\tif (this.path == null) {\n\t\t\tthis.pathLock.lock();\n\t\t\ttry {\n\t\t\t\tif (this.path == null) {\n\t\t\t\t\tString hash = HexFormat.of().withUpperCase().formatHex(generateHash(this.sourceClass));\n\t\t\t\t\tthis.path = createDirectory(getTempDirectory().resolve(hash));\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.pathLock.unlock();\n\t\t\t}\n\t\t}\n\t\tPath path = this.path;\n\t\tAssert.state(path != null, \"'path' must not be null\");\n\t\treturn path;\n\t}\n\n\tprivate Path createDirectory(Path path) {\n\t\ttry {\n\t\t\tif (!Files.exists(path)) {\n\t\t\t\tFiles.createDirectory(path, getFileAttributes(path.getFileSystem(), DIRECTORY_PERMISSIONS));\n\t\t\t}\n\t\t\treturn path;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create application temp directory \" + path, ex);\n\t\t}\n\t}\n\n\tprivate FileAttribute<?>[] getFileAttributes(FileSystem fileSystem, EnumSet<PosixFilePermission> ownerReadWrite) {\n\t\tif (!fileSystem.supportedFileAttributeViews().contains(\"posix\")) {\n\t\t\treturn NO_FILE_ATTRIBUTES;\n\t\t}\n\t\treturn new FileAttribute<?>[] { PosixFilePermissions.asFileAttribute(ownerReadWrite) };\n\t}\n\n\tprivate Path getTempDirectory() {\n\t\tString property = System.getProperty(\"java.io.tmpdir\");\n\t\tAssert.state(StringUtils.hasLength(property), \"No 'java.io.tmpdir' property set\");\n\t\tPath tempDirectory = Paths.get(property);\n\t\tAssert.state(Files.exists(tempDirectory), () -> \"Temp directory '\" + tempDirectory + \"' does not exist\");\n\t\tAssert.state(Files.isDirectory(tempDirectory),\n\t\t\t\t() -> \"Temp location '\" + tempDirectory + \"' is not a directory\");\n\t\treturn tempDirectory;\n\t}\n\n\tprivate byte[] generateHash(@Nullable Class<?> sourceClass) {\n\t\tApplicationHome home = new ApplicationHome(sourceClass);\n\t\tMessageDigest digest;\n\t\ttry {\n\t\t\tdigest = MessageDigest.getInstance(\"SHA-1\");\n\t\t\tupdate(digest, home.getSource());\n\t\t\tupdate(digest, home.getDir());\n\t\t\tupdate(digest, System.getProperty(\"user.dir\"));\n\t\t\tif (!NativeDetector.inNativeImage()) {\n\t\t\t\tupdate(digest, System.getProperty(\"java.home\"));\n\t\t\t}\n\t\t\tupdate(digest, System.getProperty(\"java.class.path\"));\n\t\t\tupdate(digest, System.getProperty(\"sun.java.command\"));\n\t\t\tupdate(digest, System.getProperty(\"sun.boot.class.path\"));\n\t\t\treturn digest.digest();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate void update(MessageDigest digest, @Nullable Object source) {\n\t\tif (source != null) {\n\t\t\tdigest.update(getUpdateSourceBytes(source));\n\t\t}\n\t}\n\n\tprivate byte[] getUpdateSourceBytes(Object source) {\n\t\tif (source instanceof File file) {\n\t\t\treturn getUpdateSourceBytes(file.getAbsolutePath());\n\t\t}\n\t\treturn source.toString().getBytes();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/system/JavaVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.Console;\nimport java.io.Reader;\nimport java.text.NumberFormat;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.SortedSet;\nimport java.util.concurrent.Future;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Known Java versions.\n *\n * @author Oliver Gierke\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 2.0.0\n */\npublic enum JavaVersion {\n\n\t/**\n\t * Java 17.\n\t * @since 2.5.3\n\t */\n\tSEVENTEEN(\"17\", Console.class, \"charset\"),\n\n\t/**\n\t * Java 18.\n\t * @since 2.5.11\n\t */\n\tEIGHTEEN(\"18\", Duration.class, \"isPositive\"),\n\n\t/**\n\t * Java 19.\n\t * @since 2.6.12\n\t */\n\tNINETEEN(\"19\", Future.class, \"state\"),\n\n\t/**\n\t * Java 20.\n\t * @since 2.7.13\n\t */\n\tTWENTY(\"20\", Class.class, \"accessFlags\"),\n\n\t/**\n\t * Java 21.\n\t * @since 2.7.16\n\t */\n\tTWENTY_ONE(\"21\", SortedSet.class, \"getFirst\"),\n\n\t/**\n\t * Java 22.\n\t * @since 3.2.4\n\t */\n\tTWENTY_TWO(\"22\", Console.class, \"isTerminal\"),\n\n\t/**\n\t * Java 23.\n\t * @since 3.2.9\n\t */\n\tTWENTY_THREE(\"23\", NumberFormat.class, \"isStrict\"),\n\n\t/**\n\t * Java 24.\n\t * @since 3.4.3\n\t */\n\tTWENTY_FOUR(\"24\", Reader.class, \"of\", CharSequence.class),\n\n\t/**\n\t * Java 25.\n\t * @since 3.5.7\n\t */\n\tTWENTY_FIVE(\"25\", Reader.class, \"readAllLines\"),\n\n\t/**\n\t * Java 26.\n\t * @since 4.0.3\n\t */\n\tTWENTY_SIX(\"26\", String.class, \"equalsFoldCase\", String.class);\n\n\tprivate final String name;\n\n\tprivate final boolean available;\n\n\tprivate final Class<?> versionSpecificClass;\n\n\tJavaVersion(String name, Class<?> versionSpecificClass, String versionSpecificMethod, Class<?>... paramTypes) {\n\t\tthis.name = name;\n\t\tthis.versionSpecificClass = versionSpecificClass;\n\t\tthis.available = ClassUtils.hasMethod(versionSpecificClass, versionSpecificMethod, paramTypes);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Returns the {@link JavaVersion} of the current runtime.\n\t * @return the {@link JavaVersion}\n\t */\n\tpublic static JavaVersion getJavaVersion() {\n\t\tList<JavaVersion> candidates = Arrays.asList(JavaVersion.values());\n\t\tCollections.reverse(candidates);\n\t\tfor (JavaVersion candidate : candidates) {\n\t\t\tif (candidate.available) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn SEVENTEEN;\n\t}\n\n\t/**\n\t * Return if this version is equal to or newer than a given version.\n\t * @param version the version to compare\n\t * @return {@code true} if this version is equal to or newer than {@code version}\n\t */\n\tpublic boolean isEqualOrNewerThan(JavaVersion version) {\n\t\treturn compareTo(version) >= 0;\n\t}\n\n\t/**\n\t * Return if this version is older than a given version.\n\t * @param version the version to compare\n\t * @return {@code true} if this version is older than {@code version}\n\t */\n\tpublic boolean isOlderThan(JavaVersion version) {\n\t\treturn compareTo(version) < 0;\n\t}\n\n\tstatic class Hints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tfor (JavaVersion javaVersion : JavaVersion.values()) {\n\t\t\t\thints.reflection().registerType(javaVersion.versionSpecificClass);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/system/SystemProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Access to system properties.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic final class SystemProperties {\n\n\tprivate SystemProperties() {\n\t}\n\n\tpublic static @Nullable String get(String... properties) {\n\t\tfor (String property : properties) {\n\t\t\ttry {\n\t\t\t\tString override = System.getProperty(property);\n\t\t\t\toverride = (override != null) ? override : System.getenv(property);\n\t\t\t\tif (override != null) {\n\t\t\t\t\treturn override;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tSystem.err.println(\"Could not resolve '\" + property + \"' as system property: \" + ex);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General system support classes.\n */\n@NullMarked\npackage org.springframework.boot.system;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/SimpleAsyncTaskExecutorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Builder that can be used to configure and create a {@link SimpleAsyncTaskExecutor}.\n * Provides convenience methods to set common {@link SimpleAsyncTaskExecutor} settings and\n * register {@link #taskDecorator(TaskDecorator)}). For advanced configuration, consider\n * using {@link SimpleAsyncTaskExecutorCustomizer}.\n * <p>\n * In a typical auto-configured Spring Boot application this builder is available as a\n * bean and can be injected whenever a {@link SimpleAsyncTaskExecutor} is needed.\n *\n * @author Stephane Nicoll\n * @author Filip Hrisafov\n * @author Moritz Halbritter\n * @author Yanming Zhou\n * @since 3.2.0\n */\npublic class SimpleAsyncTaskExecutorBuilder {\n\n\tprivate final @Nullable Boolean virtualThreads;\n\n\tprivate final @Nullable String threadNamePrefix;\n\n\tprivate final boolean cancelRemainingTasksOnClose;\n\n\tprivate final boolean rejectTasksWhenLimitReached;\n\n\tprivate final @Nullable Integer concurrencyLimit;\n\n\tprivate final @Nullable TaskDecorator taskDecorator;\n\n\tprivate final @Nullable Set<SimpleAsyncTaskExecutorCustomizer> customizers;\n\n\tprivate final @Nullable Duration taskTerminationTimeout;\n\n\tpublic SimpleAsyncTaskExecutorBuilder() {\n\t\tthis(null, null, false, false, null, null, null, null);\n\t}\n\n\tprivate SimpleAsyncTaskExecutorBuilder(@Nullable Boolean virtualThreads, @Nullable String threadNamePrefix,\n\t\t\tboolean cancelRemainingTasksOnClose, boolean rejectTasksWhenLimitReached,\n\t\t\t@Nullable Integer concurrencyLimit, @Nullable TaskDecorator taskDecorator,\n\t\t\t@Nullable Set<SimpleAsyncTaskExecutorCustomizer> customizers, @Nullable Duration taskTerminationTimeout) {\n\t\tthis.virtualThreads = virtualThreads;\n\t\tthis.threadNamePrefix = threadNamePrefix;\n\t\tthis.cancelRemainingTasksOnClose = cancelRemainingTasksOnClose;\n\t\tthis.rejectTasksWhenLimitReached = rejectTasksWhenLimitReached;\n\t\tthis.concurrencyLimit = concurrencyLimit;\n\t\tthis.taskDecorator = taskDecorator;\n\t\tthis.customizers = customizers;\n\t\tthis.taskTerminationTimeout = taskTerminationTimeout;\n\t}\n\n\t/**\n\t * Set the prefix to use for the names of newly created threads.\n\t * @param threadNamePrefix the thread name prefix to set\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder threadNamePrefix(@Nullable String threadNamePrefix) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, this.customizers, this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set whether to use virtual threads.\n\t * @param virtualThreads whether to use virtual threads\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder virtualThreads(@Nullable Boolean virtualThreads) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, this.customizers, this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set whether to cancel remaining tasks on close. By default {@code false} not\n\t * tracking active threads at all or just interrupting any remaining threads that\n\t * still have not finished after the specified\n\t * {@link #taskTerminationTimeout(Duration) taskTerminationTimeout}. Switch this to\n\t * {@code true} for immediate interruption on close, either in combination with a\n\t * subsequent termination timeout or without any waiting at all, depending on whether\n\t * a {@code taskTerminationTimeout} has been specified as well.\n\t * @param cancelRemainingTasksOnClose whether to cancel remaining tasks on close\n\t * @return a new builder instance\n\t * @since 4.0.0\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder cancelRemainingTasksOnClose(boolean cancelRemainingTasksOnClose) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tcancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, this.customizers, this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set whether to reject tasks when the concurrency limit has been reached. By default\n\t * {@code false} to block the caller until the submission can be accepted. Switch to\n\t * {@code true} for immediate rejection instead.\n\t * @param rejectTasksWhenLimitReached whether to reject tasks when the concurrency\n\t * limit has been reached\n\t * @return a new builder instance\n\t * @since 3.5.0\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder rejectTasksWhenLimitReached(boolean rejectTasksWhenLimitReached) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, this.customizers, this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set the concurrency limit.\n\t * @param concurrencyLimit the concurrency limit\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder concurrencyLimit(@Nullable Integer concurrencyLimit) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, concurrencyLimit,\n\t\t\t\tthis.taskDecorator, this.customizers, this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set the {@link TaskDecorator} to use or {@code null} to not use any.\n\t * @param taskDecorator the task decorator to use\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder taskDecorator(@Nullable TaskDecorator taskDecorator) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\ttaskDecorator, this.customizers, this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set the task termination timeout.\n\t * @param taskTerminationTimeout the task termination timeout\n\t * @return a new builder instance\n\t * @since 3.2.1\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder taskTerminationTimeout(@Nullable Duration taskTerminationTimeout) {\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, this.customizers, taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Set the {@link SimpleAsyncTaskExecutorCustomizer customizers} that should be\n\t * applied to the {@link SimpleAsyncTaskExecutor}. Customizers are applied in the\n\t * order that they were added after builder configuration has been applied. Setting\n\t * this value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(SimpleAsyncTaskExecutorCustomizer...)\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder customizers(SimpleAsyncTaskExecutorCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn customizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Set the {@link SimpleAsyncTaskExecutorCustomizer customizers} that should be\n\t * applied to the {@link SimpleAsyncTaskExecutor}. Customizers are applied in the\n\t * order that they were added after builder configuration has been applied. Setting\n\t * this value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(Iterable)\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder customizers(\n\t\t\tIterable<? extends SimpleAsyncTaskExecutorCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, append(null, customizers), this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Add {@link SimpleAsyncTaskExecutorCustomizer customizers} that should be applied to\n\t * the {@link SimpleAsyncTaskExecutor}. Customizers are applied in the order that they\n\t * were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(SimpleAsyncTaskExecutorCustomizer...)\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder additionalCustomizers(SimpleAsyncTaskExecutorCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn additionalCustomizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Add {@link SimpleAsyncTaskExecutorCustomizer customizers} that should be applied to\n\t * the {@link SimpleAsyncTaskExecutor}. Customizers are applied in the order that they\n\t * were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(Iterable)\n\t */\n\tpublic SimpleAsyncTaskExecutorBuilder additionalCustomizers(\n\t\t\tIterable<? extends SimpleAsyncTaskExecutorCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new SimpleAsyncTaskExecutorBuilder(this.virtualThreads, this.threadNamePrefix,\n\t\t\t\tthis.cancelRemainingTasksOnClose, this.rejectTasksWhenLimitReached, this.concurrencyLimit,\n\t\t\t\tthis.taskDecorator, append(this.customizers, customizers), this.taskTerminationTimeout);\n\t}\n\n\t/**\n\t * Build a new {@link SimpleAsyncTaskExecutor} instance and configure it using this\n\t * builder.\n\t * @return a configured {@link SimpleAsyncTaskExecutor} instance.\n\t * @see #build(Class)\n\t * @see #configure(SimpleAsyncTaskExecutor)\n\t */\n\tpublic SimpleAsyncTaskExecutor build() {\n\t\treturn configure(new SimpleAsyncTaskExecutor());\n\t}\n\n\t/**\n\t * Build a new {@link SimpleAsyncTaskExecutor} instance of the specified type and\n\t * configure it using this builder.\n\t * @param <T> the type of task executor\n\t * @param taskExecutorClass the template type to create\n\t * @return a configured {@link SimpleAsyncTaskExecutor} instance.\n\t * @see #build()\n\t * @see #configure(SimpleAsyncTaskExecutor)\n\t */\n\tpublic <T extends SimpleAsyncTaskExecutor> T build(Class<T> taskExecutorClass) {\n\t\treturn configure(BeanUtils.instantiateClass(taskExecutorClass));\n\t}\n\n\t/**\n\t * Configure the provided {@link SimpleAsyncTaskExecutor} instance using this builder.\n\t * @param <T> the type of task executor\n\t * @param taskExecutor the {@link SimpleAsyncTaskExecutor} to configure\n\t * @return the task executor instance\n\t * @see #build()\n\t * @see #build(Class)\n\t */\n\tpublic <T extends SimpleAsyncTaskExecutor> T configure(T taskExecutor) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.virtualThreads).to(taskExecutor::setVirtualThreads);\n\t\tmap.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);\n\t\tmap.from(this.cancelRemainingTasksOnClose).to(taskExecutor::setCancelRemainingTasksOnClose);\n\t\tmap.from(this.rejectTasksWhenLimitReached).to(taskExecutor::setRejectTasksWhenLimitReached);\n\t\tmap.from(this.concurrencyLimit).to(taskExecutor::setConcurrencyLimit);\n\t\tmap.from(this.taskDecorator).to(taskExecutor::setTaskDecorator);\n\t\tmap.from(this.taskTerminationTimeout).as(Duration::toMillis).to(taskExecutor::setTaskTerminationTimeout);\n\t\tif (!CollectionUtils.isEmpty(this.customizers)) {\n\t\t\tthis.customizers.forEach((customizer) -> customizer.customize(taskExecutor));\n\t\t}\n\t\treturn taskExecutor;\n\t}\n\n\tprivate <T> Set<T> append(@Nullable Set<T> set, Iterable<? extends T> additions) {\n\t\tSet<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());\n\t\tadditions.forEach(result::add);\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/SimpleAsyncTaskExecutorCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\n\n/**\n * Callback interface that can be used to customize a {@link SimpleAsyncTaskExecutor}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @since 3.2.0\n * @see SimpleAsyncTaskExecutorBuilder\n */\n@FunctionalInterface\npublic interface SimpleAsyncTaskExecutorCustomizer {\n\n\t/**\n\t * Callback to customize a {@link SimpleAsyncTaskExecutor} instance.\n\t * @param taskExecutor the task executor to customize\n\t */\n\tvoid customize(SimpleAsyncTaskExecutor taskExecutor);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Builder that can be used to configure and create a {@link SimpleAsyncTaskScheduler}.\n * Provides convenience methods to set common {@link SimpleAsyncTaskScheduler} settings.\n * For advanced configuration, consider using {@link SimpleAsyncTaskSchedulerCustomizer}.\n * <p>\n * In a typical auto-configured Spring Boot application this builder is available as a\n * bean and can be injected whenever a {@link SimpleAsyncTaskScheduler} is needed.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @since 3.2.0\n */\npublic class SimpleAsyncTaskSchedulerBuilder {\n\n\tprivate final @Nullable String threadNamePrefix;\n\n\tprivate final @Nullable Integer concurrencyLimit;\n\n\tprivate final @Nullable Boolean virtualThreads;\n\n\tprivate final @Nullable Duration taskTerminationTimeout;\n\n\tprivate final @Nullable TaskDecorator taskDecorator;\n\n\tprivate final @Nullable Set<SimpleAsyncTaskSchedulerCustomizer> customizers;\n\n\tpublic SimpleAsyncTaskSchedulerBuilder() {\n\t\tthis(null, null, null, null, null, null);\n\t}\n\n\tprivate SimpleAsyncTaskSchedulerBuilder(@Nullable String threadNamePrefix, @Nullable Integer concurrencyLimit,\n\t\t\t@Nullable Boolean virtualThreads, @Nullable Duration taskTerminationTimeout,\n\t\t\t@Nullable TaskDecorator taskDecorator,\n\t\t\t@Nullable Set<SimpleAsyncTaskSchedulerCustomizer> taskSchedulerCustomizers) {\n\t\tthis.threadNamePrefix = threadNamePrefix;\n\t\tthis.concurrencyLimit = concurrencyLimit;\n\t\tthis.virtualThreads = virtualThreads;\n\t\tthis.customizers = taskSchedulerCustomizers;\n\t\tthis.taskDecorator = taskDecorator;\n\t\tthis.taskTerminationTimeout = taskTerminationTimeout;\n\t}\n\n\t/**\n\t * Set the prefix to use for the names of newly created threads.\n\t * @param threadNamePrefix the thread name prefix to set\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder threadNamePrefix(@Nullable String threadNamePrefix) {\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(threadNamePrefix, this.concurrencyLimit, this.virtualThreads,\n\t\t\t\tthis.taskTerminationTimeout, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the concurrency limit.\n\t * @param concurrencyLimit the concurrency limit\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder concurrencyLimit(@Nullable Integer concurrencyLimit) {\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(this.threadNamePrefix, concurrencyLimit, this.virtualThreads,\n\t\t\t\tthis.taskTerminationTimeout, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set whether to use virtual threads.\n\t * @param virtualThreads whether to use virtual threads\n\t * @return a new builder instance\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder virtualThreads(@Nullable Boolean virtualThreads) {\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(this.threadNamePrefix, this.concurrencyLimit, virtualThreads,\n\t\t\t\tthis.taskTerminationTimeout, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the task termination timeout.\n\t * @param taskTerminationTimeout the task termination timeout\n\t * @return a new builder instance\n\t * @since 3.2.1\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder taskTerminationTimeout(@Nullable Duration taskTerminationTimeout) {\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(this.threadNamePrefix, this.concurrencyLimit, this.virtualThreads,\n\t\t\t\ttaskTerminationTimeout, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the task decorator to be used by the {@link SimpleAsyncTaskScheduler}.\n\t * @param taskDecorator the task decorator to set\n\t * @return a new builder instance\n\t * @since 3.5.0\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder taskDecorator(@Nullable TaskDecorator taskDecorator) {\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(this.threadNamePrefix, this.concurrencyLimit, this.virtualThreads,\n\t\t\t\tthis.taskTerminationTimeout, taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the {@link SimpleAsyncTaskSchedulerCustomizer customizers} that should be\n\t * applied to the {@link SimpleAsyncTaskScheduler}. Customizers are applied in the\n\t * order that they were added after builder configuration has been applied. Setting\n\t * this value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(SimpleAsyncTaskSchedulerCustomizer...)\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder customizers(SimpleAsyncTaskSchedulerCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn customizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Set the {@link SimpleAsyncTaskSchedulerCustomizer customizers} that should be\n\t * applied to the {@link SimpleAsyncTaskScheduler}. Customizers are applied in the\n\t * order that they were added after builder configuration has been applied. Setting\n\t * this value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(Iterable)\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder customizers(\n\t\t\tIterable<? extends SimpleAsyncTaskSchedulerCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(this.threadNamePrefix, this.concurrencyLimit, this.virtualThreads,\n\t\t\t\tthis.taskTerminationTimeout, this.taskDecorator, append(null, customizers));\n\t}\n\n\t/**\n\t * Add {@link SimpleAsyncTaskSchedulerCustomizer customizers} that should be applied\n\t * to the {@link SimpleAsyncTaskScheduler}. Customizers are applied in the order that\n\t * they were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(SimpleAsyncTaskSchedulerCustomizer...)\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder additionalCustomizers(SimpleAsyncTaskSchedulerCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn additionalCustomizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Add {@link SimpleAsyncTaskSchedulerCustomizer customizers} that should be applied\n\t * to the {@link SimpleAsyncTaskScheduler}. Customizers are applied in the order that\n\t * they were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(Iterable)\n\t */\n\tpublic SimpleAsyncTaskSchedulerBuilder additionalCustomizers(\n\t\t\tIterable<? extends SimpleAsyncTaskSchedulerCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new SimpleAsyncTaskSchedulerBuilder(this.threadNamePrefix, this.concurrencyLimit, this.virtualThreads,\n\t\t\t\tthis.taskTerminationTimeout, this.taskDecorator, append(this.customizers, customizers));\n\t}\n\n\t/**\n\t * Build a new {@link SimpleAsyncTaskScheduler} instance and configure it using this\n\t * builder.\n\t * @return a configured {@link SimpleAsyncTaskScheduler} instance.\n\t * @see #configure(SimpleAsyncTaskScheduler)\n\t */\n\tpublic SimpleAsyncTaskScheduler build() {\n\t\treturn configure(new SimpleAsyncTaskScheduler());\n\t}\n\n\t/**\n\t * Configure the provided {@link SimpleAsyncTaskScheduler} instance using this\n\t * builder.\n\t * @param <T> the type of task scheduler\n\t * @param taskScheduler the {@link SimpleAsyncTaskScheduler} to configure\n\t * @return the task scheduler instance\n\t * @see #build()\n\t */\n\tpublic <T extends SimpleAsyncTaskScheduler> T configure(T taskScheduler) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix);\n\t\tmap.from(this.concurrencyLimit).to(taskScheduler::setConcurrencyLimit);\n\t\tmap.from(this.virtualThreads).to(taskScheduler::setVirtualThreads);\n\t\tmap.from(this.taskTerminationTimeout).as(Duration::toMillis).to(taskScheduler::setTaskTerminationTimeout);\n\t\tmap.from(this.taskDecorator).to(taskScheduler::setTaskDecorator);\n\t\tif (!CollectionUtils.isEmpty(this.customizers)) {\n\t\t\tthis.customizers.forEach((customizer) -> customizer.customize(taskScheduler));\n\t\t}\n\t\treturn taskScheduler;\n\t}\n\n\tprivate <T> Set<T> append(@Nullable Set<T> set, Iterable<? extends T> additions) {\n\t\tSet<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());\n\t\tadditions.forEach(result::add);\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\n\n/**\n * Callback interface that can be used to customize a {@link SimpleAsyncTaskScheduler}.\n *\n * @author Moritz Halbritter\n * @since 3.2.0\n */\n@FunctionalInterface\npublic interface SimpleAsyncTaskSchedulerCustomizer {\n\n\t/**\n\t * Callback to customize a {@link SimpleAsyncTaskScheduler} instance.\n\t * @param taskScheduler the task scheduler to customize\n\t */\n\tvoid customize(SimpleAsyncTaskScheduler taskScheduler);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/ThreadPoolTaskExecutorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Builder that can be used to configure and create a {@link ThreadPoolTaskExecutor}.\n * Provides convenience methods to set common {@link ThreadPoolTaskExecutor} settings and\n * register {@link #taskDecorator(TaskDecorator)}). For advanced configuration, consider\n * using {@link ThreadPoolTaskExecutorCustomizer}.\n * <p>\n * In a typical auto-configured Spring Boot application this builder is available as a\n * bean and can be injected whenever a {@link ThreadPoolTaskExecutor} is needed.\n *\n * @author Stephane Nicoll\n * @author Filip Hrisafov\n * @author Yanming Zhou\n * @since 3.2.0\n */\npublic class ThreadPoolTaskExecutorBuilder {\n\n\tprivate final @Nullable Integer queueCapacity;\n\n\tprivate final @Nullable Integer corePoolSize;\n\n\tprivate final @Nullable Integer maxPoolSize;\n\n\tprivate final @Nullable Boolean allowCoreThreadTimeOut;\n\n\tprivate final @Nullable Duration keepAlive;\n\n\tprivate final @Nullable Boolean acceptTasksAfterContextClose;\n\n\tprivate final @Nullable Boolean awaitTermination;\n\n\tprivate final @Nullable Duration awaitTerminationPeriod;\n\n\tprivate final @Nullable String threadNamePrefix;\n\n\tprivate final @Nullable TaskDecorator taskDecorator;\n\n\tprivate final @Nullable Set<ThreadPoolTaskExecutorCustomizer> customizers;\n\n\tpublic ThreadPoolTaskExecutorBuilder() {\n\t\tthis.queueCapacity = null;\n\t\tthis.corePoolSize = null;\n\t\tthis.maxPoolSize = null;\n\t\tthis.allowCoreThreadTimeOut = null;\n\t\tthis.keepAlive = null;\n\t\tthis.acceptTasksAfterContextClose = null;\n\t\tthis.awaitTermination = null;\n\t\tthis.awaitTerminationPeriod = null;\n\t\tthis.threadNamePrefix = null;\n\t\tthis.taskDecorator = null;\n\t\tthis.customizers = null;\n\t}\n\n\tprivate ThreadPoolTaskExecutorBuilder(@Nullable Integer queueCapacity, @Nullable Integer corePoolSize,\n\t\t\t@Nullable Integer maxPoolSize, @Nullable Boolean allowCoreThreadTimeOut, @Nullable Duration keepAlive,\n\t\t\t@Nullable Boolean acceptTasksAfterContextClose, @Nullable Boolean awaitTermination,\n\t\t\t@Nullable Duration awaitTerminationPeriod, @Nullable String threadNamePrefix,\n\t\t\t@Nullable TaskDecorator taskDecorator, @Nullable Set<ThreadPoolTaskExecutorCustomizer> customizers) {\n\t\tthis.queueCapacity = queueCapacity;\n\t\tthis.corePoolSize = corePoolSize;\n\t\tthis.maxPoolSize = maxPoolSize;\n\t\tthis.allowCoreThreadTimeOut = allowCoreThreadTimeOut;\n\t\tthis.keepAlive = keepAlive;\n\t\tthis.acceptTasksAfterContextClose = acceptTasksAfterContextClose;\n\t\tthis.awaitTermination = awaitTermination;\n\t\tthis.awaitTerminationPeriod = awaitTerminationPeriod;\n\t\tthis.threadNamePrefix = threadNamePrefix;\n\t\tthis.taskDecorator = taskDecorator;\n\t\tthis.customizers = customizers;\n\t}\n\n\t/**\n\t * Set the capacity of the queue. An unbounded capacity does not increase the pool and\n\t * therefore ignores {@link #maxPoolSize(int) maxPoolSize}.\n\t * @param queueCapacity the queue capacity to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder queueCapacity(int queueCapacity) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the core number of threads. Effectively that maximum number of threads as long\n\t * as the queue is not full.\n\t * <p>\n\t * Core threads can grow and shrink if {@link #allowCoreThreadTimeOut(boolean)} is\n\t * enabled.\n\t * @param corePoolSize the core pool size to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder corePoolSize(int corePoolSize) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the maximum allowed number of threads. When the {@link #queueCapacity(int)\n\t * queue} is full, the pool can expand up to that size to accommodate the load.\n\t * <p>\n\t * If the {@link #queueCapacity(int) queue capacity} is unbounded, this setting is\n\t * ignored.\n\t * @param maxPoolSize the max pool size to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder maxPoolSize(int maxPoolSize) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set whether core threads are allowed to time out. When enabled, this enables\n\t * dynamic growing and shrinking of the pool.\n\t * @param allowCoreThreadTimeOut if core threads are allowed to time out\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder allowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tallowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the time limit for which threads may remain idle before being terminated.\n\t * @param keepAlive the keep alive to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder keepAlive(@Nullable Duration keepAlive) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set whether to accept further tasks after the application context close phase has\n\t * begun.\n\t * @param acceptTasksAfterContextClose whether to accept further tasks after the\n\t * application context close phase has begun\n\t * @return a new builder instance\n\t * @since 3.3.0\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder acceptTasksAfterContextClose(boolean acceptTasksAfterContextClose) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set whether the executor should wait for scheduled tasks to complete on shutdown,\n\t * not interrupting running tasks and executing all tasks in the queue.\n\t * @param awaitTermination whether the executor needs to wait for the tasks to\n\t * complete on shutdown\n\t * @return a new builder instance\n\t * @see #awaitTerminationPeriod(Duration)\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder awaitTermination(boolean awaitTermination) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the maximum time the executor is supposed to block on shutdown. When set, the\n\t * executor blocks on shutdown in order to wait for remaining tasks to complete their\n\t * execution before the rest of the container continues to shut down. This is\n\t * particularly useful if your remaining tasks are likely to need access to other\n\t * resources that are also managed by the container.\n\t * @param awaitTerminationPeriod the await termination period to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder awaitTerminationPeriod(@Nullable Duration awaitTerminationPeriod) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tawaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the prefix to use for the names of newly created threads.\n\t * @param threadNamePrefix the thread name prefix to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder threadNamePrefix(@Nullable String threadNamePrefix) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the {@link TaskDecorator} to use or {@code null} to not use any.\n\t * @param taskDecorator the task decorator to use\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder taskDecorator(@Nullable TaskDecorator taskDecorator) {\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the {@link ThreadPoolTaskExecutorCustomizer ThreadPoolTaskExecutorCustomizers}\n\t * that should be applied to the {@link ThreadPoolTaskExecutor}. Customizers are\n\t * applied in the order that they were added after builder configuration has been\n\t * applied. Setting this value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(ThreadPoolTaskExecutorCustomizer...)\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder customizers(ThreadPoolTaskExecutorCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn customizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Set the {@link ThreadPoolTaskExecutorCustomizer ThreadPoolTaskExecutorCustomizers}\n\t * that should be applied to the {@link ThreadPoolTaskExecutor}. Customizers are\n\t * applied in the order that they were added after builder configuration has been\n\t * applied. Setting this value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(ThreadPoolTaskExecutorCustomizer...)\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder customizers(Iterable<? extends ThreadPoolTaskExecutorCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator, append(null, customizers));\n\t}\n\n\t/**\n\t * Add {@link ThreadPoolTaskExecutorCustomizer ThreadPoolTaskExecutorCustomizers} that\n\t * should be applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in\n\t * the order that they were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(ThreadPoolTaskExecutorCustomizer...)\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder additionalCustomizers(ThreadPoolTaskExecutorCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn additionalCustomizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Add {@link ThreadPoolTaskExecutorCustomizer ThreadPoolTaskExecutorCustomizers} that\n\t * should be applied to the {@link ThreadPoolTaskExecutor}. Customizers are applied in\n\t * the order that they were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(ThreadPoolTaskExecutorCustomizer...)\n\t */\n\tpublic ThreadPoolTaskExecutorBuilder additionalCustomizers(\n\t\t\tIterable<? extends ThreadPoolTaskExecutorCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new ThreadPoolTaskExecutorBuilder(this.queueCapacity, this.corePoolSize, this.maxPoolSize,\n\t\t\t\tthis.allowCoreThreadTimeOut, this.keepAlive, this.acceptTasksAfterContextClose, this.awaitTermination,\n\t\t\t\tthis.awaitTerminationPeriod, this.threadNamePrefix, this.taskDecorator,\n\t\t\t\tappend(this.customizers, customizers));\n\t}\n\n\t/**\n\t * Build a new {@link ThreadPoolTaskExecutor} instance and configure it using this\n\t * builder.\n\t * @return a configured {@link ThreadPoolTaskExecutor} instance.\n\t * @see #build(Class)\n\t * @see #configure(ThreadPoolTaskExecutor)\n\t */\n\tpublic ThreadPoolTaskExecutor build() {\n\t\treturn configure(new ThreadPoolTaskExecutor());\n\t}\n\n\t/**\n\t * Build a new {@link ThreadPoolTaskExecutor} instance of the specified type and\n\t * configure it using this builder.\n\t * @param <T> the type of task executor\n\t * @param taskExecutorClass the template type to create\n\t * @return a configured {@link ThreadPoolTaskExecutor} instance.\n\t * @see #build()\n\t * @see #configure(ThreadPoolTaskExecutor)\n\t */\n\tpublic <T extends ThreadPoolTaskExecutor> T build(Class<T> taskExecutorClass) {\n\t\treturn configure(BeanUtils.instantiateClass(taskExecutorClass));\n\t}\n\n\t/**\n\t * Configure the provided {@link ThreadPoolTaskExecutor} instance using this builder.\n\t * @param <T> the type of task executor\n\t * @param taskExecutor the {@link ThreadPoolTaskExecutor} to configure\n\t * @return the task executor instance\n\t * @see #build()\n\t * @see #build(Class)\n\t */\n\tpublic <T extends ThreadPoolTaskExecutor> T configure(T taskExecutor) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.queueCapacity).to(taskExecutor::setQueueCapacity);\n\t\tmap.from(this.corePoolSize).to(taskExecutor::setCorePoolSize);\n\t\tmap.from(this.maxPoolSize).to(taskExecutor::setMaxPoolSize);\n\t\tmap.from(this.keepAlive).asInt(Duration::getSeconds).to(taskExecutor::setKeepAliveSeconds);\n\t\tmap.from(this.allowCoreThreadTimeOut).to(taskExecutor::setAllowCoreThreadTimeOut);\n\t\tmap.from(this.acceptTasksAfterContextClose).to(taskExecutor::setAcceptTasksAfterContextClose);\n\t\tmap.from(this.awaitTermination).to(taskExecutor::setWaitForTasksToCompleteOnShutdown);\n\t\tmap.from(this.awaitTerminationPeriod).as(Duration::toMillis).to(taskExecutor::setAwaitTerminationMillis);\n\t\tmap.from(this.threadNamePrefix).whenHasText().to(taskExecutor::setThreadNamePrefix);\n\t\tmap.from(this.taskDecorator).to(taskExecutor::setTaskDecorator);\n\t\tif (!CollectionUtils.isEmpty(this.customizers)) {\n\t\t\tthis.customizers.forEach((customizer) -> customizer.customize(taskExecutor));\n\t\t}\n\t\treturn taskExecutor;\n\t}\n\n\tprivate <T> Set<T> append(@Nullable Set<T> set, Iterable<? extends T> additions) {\n\t\tSet<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());\n\t\tadditions.forEach(result::add);\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/ThreadPoolTaskExecutorCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\n/**\n * Callback interface that can be used to customize a {@link ThreadPoolTaskExecutor}.\n *\n * @author Stephane Nicoll\n * @since 3.2.0\n * @see ThreadPoolTaskExecutorBuilder\n */\n@FunctionalInterface\npublic interface ThreadPoolTaskExecutorCustomizer {\n\n\t/**\n\t * Callback to customize a {@link ThreadPoolTaskExecutor} instance.\n\t * @param taskExecutor the task executor to customize\n\t */\n\tvoid customize(ThreadPoolTaskExecutor taskExecutor);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/ThreadPoolTaskSchedulerBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Builder that can be used to configure and create a {@link ThreadPoolTaskScheduler}.\n * Provides convenience methods to set common {@link ThreadPoolTaskScheduler} settings.\n * For advanced configuration, consider using {@link ThreadPoolTaskSchedulerCustomizer}.\n * <p>\n * In a typical auto-configured Spring Boot application this builder is available as a\n * bean and can be injected whenever a {@link ThreadPoolTaskScheduler} is needed.\n *\n * @author Stephane Nicoll\n * @since 3.2.0\n */\npublic class ThreadPoolTaskSchedulerBuilder {\n\n\tprivate final @Nullable Integer poolSize;\n\n\tprivate final @Nullable Boolean awaitTermination;\n\n\tprivate final @Nullable Duration awaitTerminationPeriod;\n\n\tprivate final @Nullable String threadNamePrefix;\n\n\tprivate final @Nullable TaskDecorator taskDecorator;\n\n\tprivate final @Nullable Set<ThreadPoolTaskSchedulerCustomizer> customizers;\n\n\tpublic ThreadPoolTaskSchedulerBuilder() {\n\t\tthis(null, null, null, null, null, null);\n\t}\n\n\tprivate ThreadPoolTaskSchedulerBuilder(@Nullable Integer poolSize, @Nullable Boolean awaitTermination,\n\t\t\t@Nullable Duration awaitTerminationPeriod, @Nullable String threadNamePrefix,\n\t\t\t@Nullable TaskDecorator taskDecorator,\n\t\t\t@Nullable Set<ThreadPoolTaskSchedulerCustomizer> taskSchedulerCustomizers) {\n\t\tthis.poolSize = poolSize;\n\t\tthis.awaitTermination = awaitTermination;\n\t\tthis.awaitTerminationPeriod = awaitTerminationPeriod;\n\t\tthis.threadNamePrefix = threadNamePrefix;\n\t\tthis.taskDecorator = taskDecorator;\n\t\tthis.customizers = taskSchedulerCustomizers;\n\t}\n\n\t/**\n\t * Set the maximum allowed number of threads.\n\t * @param poolSize the pool size to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder poolSize(int poolSize) {\n\t\treturn new ThreadPoolTaskSchedulerBuilder(poolSize, this.awaitTermination, this.awaitTerminationPeriod,\n\t\t\t\tthis.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set whether the executor should wait for scheduled tasks to complete on shutdown,\n\t * not interrupting running tasks and executing all tasks in the queue.\n\t * @param awaitTermination whether the executor needs to wait for the tasks to\n\t * complete on shutdown\n\t * @return a new builder instance\n\t * @see #awaitTerminationPeriod(Duration)\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder awaitTermination(boolean awaitTermination) {\n\t\treturn new ThreadPoolTaskSchedulerBuilder(this.poolSize, awaitTermination, this.awaitTerminationPeriod,\n\t\t\t\tthis.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the maximum time the executor is supposed to block on shutdown. When set, the\n\t * executor blocks on shutdown in order to wait for remaining tasks to complete their\n\t * execution before the rest of the container continues to shut down. This is\n\t * particularly useful if your remaining tasks are likely to need access to other\n\t * resources that are also managed by the container.\n\t * @param awaitTerminationPeriod the await termination period to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder awaitTerminationPeriod(@Nullable Duration awaitTerminationPeriod) {\n\t\treturn new ThreadPoolTaskSchedulerBuilder(this.poolSize, this.awaitTermination, awaitTerminationPeriod,\n\t\t\t\tthis.threadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the prefix to use for the names of newly created threads.\n\t * @param threadNamePrefix the thread name prefix to set\n\t * @return a new builder instance\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder threadNamePrefix(@Nullable String threadNamePrefix) {\n\t\treturn new ThreadPoolTaskSchedulerBuilder(this.poolSize, this.awaitTermination, this.awaitTerminationPeriod,\n\t\t\t\tthreadNamePrefix, this.taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the {@link TaskDecorator} to be applied to the {@link ThreadPoolTaskScheduler}.\n\t * @param taskDecorator the task decorator to set\n\t * @return a new builder instance\n\t * @since 3.5.0\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder taskDecorator(@Nullable TaskDecorator taskDecorator) {\n\t\treturn new ThreadPoolTaskSchedulerBuilder(this.poolSize, this.awaitTermination, this.awaitTerminationPeriod,\n\t\t\t\tthis.threadNamePrefix, taskDecorator, this.customizers);\n\t}\n\n\t/**\n\t * Set the {@link ThreadPoolTaskSchedulerCustomizer\n\t * threadPoolTaskSchedulerCustomizers} that should be applied to the\n\t * {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that they\n\t * were added after builder configuration has been applied. Setting this value will\n\t * replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(ThreadPoolTaskSchedulerCustomizer...)\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder customizers(ThreadPoolTaskSchedulerCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn customizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Set the {@link ThreadPoolTaskSchedulerCustomizer\n\t * threadPoolTaskSchedulerCustomizers} that should be applied to the\n\t * {@link ThreadPoolTaskScheduler}. Customizers are applied in the order that they\n\t * were added after builder configuration has been applied. Setting this value will\n\t * replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(ThreadPoolTaskSchedulerCustomizer...)\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder customizers(\n\t\t\tIterable<? extends ThreadPoolTaskSchedulerCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new ThreadPoolTaskSchedulerBuilder(this.poolSize, this.awaitTermination, this.awaitTerminationPeriod,\n\t\t\t\tthis.threadNamePrefix, this.taskDecorator, append(null, customizers));\n\t}\n\n\t/**\n\t * Add {@link ThreadPoolTaskSchedulerCustomizer threadPoolTaskSchedulerCustomizers}\n\t * that should be applied to the {@link ThreadPoolTaskScheduler}. Customizers are\n\t * applied in the order that they were added after builder configuration has been\n\t * applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(ThreadPoolTaskSchedulerCustomizer...)\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder additionalCustomizers(ThreadPoolTaskSchedulerCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn additionalCustomizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Add {@link ThreadPoolTaskSchedulerCustomizer threadPoolTaskSchedulerCustomizers}\n\t * that should be applied to the {@link ThreadPoolTaskScheduler}. Customizers are\n\t * applied in the order that they were added after builder configuration has been\n\t * applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(ThreadPoolTaskSchedulerCustomizer...)\n\t */\n\tpublic ThreadPoolTaskSchedulerBuilder additionalCustomizers(\n\t\t\tIterable<? extends ThreadPoolTaskSchedulerCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new ThreadPoolTaskSchedulerBuilder(this.poolSize, this.awaitTermination, this.awaitTerminationPeriod,\n\t\t\t\tthis.threadNamePrefix, this.taskDecorator, append(this.customizers, customizers));\n\t}\n\n\t/**\n\t * Build a new {@link ThreadPoolTaskScheduler} instance and configure it using this\n\t * builder.\n\t * @return a configured {@link ThreadPoolTaskScheduler} instance.\n\t * @see #configure(ThreadPoolTaskScheduler)\n\t */\n\tpublic ThreadPoolTaskScheduler build() {\n\t\treturn configure(new ThreadPoolTaskScheduler());\n\t}\n\n\t/**\n\t * Configure the provided {@link ThreadPoolTaskScheduler} instance using this builder.\n\t * @param <T> the type of task scheduler\n\t * @param taskScheduler the {@link ThreadPoolTaskScheduler} to configure\n\t * @return the task scheduler instance\n\t * @see #build()\n\t */\n\tpublic <T extends ThreadPoolTaskScheduler> T configure(T taskScheduler) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.poolSize).to(taskScheduler::setPoolSize);\n\t\tmap.from(this.awaitTermination).to(taskScheduler::setWaitForTasksToCompleteOnShutdown);\n\t\tmap.from(this.awaitTerminationPeriod).asInt(Duration::getSeconds).to(taskScheduler::setAwaitTerminationSeconds);\n\t\tmap.from(this.threadNamePrefix).to(taskScheduler::setThreadNamePrefix);\n\t\tmap.from(this.taskDecorator).to(taskScheduler::setTaskDecorator);\n\t\tif (!CollectionUtils.isEmpty(this.customizers)) {\n\t\t\tthis.customizers.forEach((customizer) -> customizer.customize(taskScheduler));\n\t\t}\n\t\treturn taskScheduler;\n\t}\n\n\tprivate <T> Set<T> append(@Nullable Set<T> set, Iterable<? extends T> additions) {\n\t\tSet<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());\n\t\tadditions.forEach(result::add);\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/ThreadPoolTaskSchedulerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\n/**\n * Callback interface that can be used to customize a {@link ThreadPoolTaskScheduler}.\n *\n * @author Stephane Nicoll\n * @since 3.2.0\n */\n@FunctionalInterface\npublic interface ThreadPoolTaskSchedulerCustomizer {\n\n\t/**\n\t * Callback to customize a {@link ThreadPoolTaskScheduler} instance.\n\t * @param taskScheduler the task scheduler to customize\n\t */\n\tvoid customize(ThreadPoolTaskScheduler taskScheduler);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/task/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utilities and classes related to task execution and scheduling.\n */\n@NullMarked\npackage org.springframework.boot.task;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/thread/Threading.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thread;\n\nimport org.springframework.boot.system.JavaVersion;\nimport org.springframework.core.env.Environment;\n\n/**\n * Threading of the application.\n *\n * @author Moritz Halbritter\n * @since 3.2.0\n */\npublic enum Threading {\n\n\t/**\n\t * Platform threads. Active if virtual threads are not active.\n\t */\n\tPLATFORM {\n\n\t\t@Override\n\t\tpublic boolean isActive(Environment environment) {\n\t\t\treturn !VIRTUAL.isActive(environment);\n\t\t}\n\n\t},\n\t/**\n\t * Virtual threads. Active if {@code spring.threads.virtual.enabled} is {@code true}\n\t * and running on Java 21 or later.\n\t */\n\tVIRTUAL {\n\n\t\t@Override\n\t\tpublic boolean isActive(Environment environment) {\n\t\t\treturn environment.getProperty(\"spring.threads.virtual.enabled\", boolean.class, false)\n\t\t\t\t\t&& JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.TWENTY_ONE);\n\t\t}\n\n\t};\n\n\t/**\n\t * Determines whether the threading is active.\n\t * @param environment the environment\n\t * @return whether the threading is active\n\t */\n\tpublic abstract boolean isActive(Environment environment);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/thread/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to threads.\n */\n@NullMarked\npackage org.springframework.boot.thread;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/util/Instantiator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.util;\n\nimport java.lang.reflect.Constructor;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Simple factory used to instantiate objects by injecting available parameters.\n *\n * @param <T> the type to instantiate\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.4.0\n */\npublic class Instantiator<T> {\n\n\tprivate static final Comparator<Constructor<?>> CONSTRUCTOR_COMPARATOR = Comparator\n\t\t.<Constructor<?>>comparingInt(Constructor::getParameterCount)\n\t\t.reversed();\n\n\tprivate static final FailureHandler throwingFailureHandler = (type, implementationName, failure) -> {\n\t\tthrow new IllegalArgumentException(\"Unable to instantiate \" + implementationName + \" [\" + type.getName() + \"]\",\n\t\t\t\tfailure);\n\t};\n\n\tprivate final Class<?> type;\n\n\tprivate final Map<Class<?>, Function<Class<?>, @Nullable Object>> availableParameters;\n\n\tprivate final FailureHandler failureHandler;\n\n\t/**\n\t * Create a new {@link Instantiator} instance for the given type.\n\t * @param type the type to instantiate\n\t * @param availableParameters consumer used to register available parameters\n\t */\n\tpublic Instantiator(Class<?> type, Consumer<AvailableParameters> availableParameters) {\n\t\tthis(type, availableParameters, throwingFailureHandler);\n\t}\n\n\t/**\n\t * Create a new {@link Instantiator} instance for the given type.\n\t * @param type the type to instantiate\n\t * @param availableParameters consumer used to register available parameters\n\t * @param failureHandler a {@link FailureHandler} that will be called in case of\n\t * failure when instantiating objects\n\t * @since 2.7.0\n\t */\n\tpublic Instantiator(Class<?> type, Consumer<AvailableParameters> availableParameters,\n\t\t\tFailureHandler failureHandler) {\n\t\tthis.type = type;\n\t\tthis.availableParameters = getAvailableParameters(availableParameters);\n\t\tthis.failureHandler = failureHandler;\n\t}\n\n\tprivate Map<Class<?>, Function<Class<?>, @Nullable Object>> getAvailableParameters(\n\t\t\tConsumer<AvailableParameters> availableParameters) {\n\t\tMap<Class<?>, Function<Class<?>, @Nullable Object>> result = new LinkedHashMap<>();\n\t\tavailableParameters.accept(new AvailableParameters() {\n\n\t\t\t@Override\n\t\t\tpublic void add(Class<?> type, @Nullable Object instance) {\n\t\t\t\tresult.put(type, (factoryType) -> instance);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void add(Class<?> type, Function<Class<?>, @Nullable Object> factory) {\n\t\t\t\tresult.put(type, factory);\n\t\t\t}\n\n\t\t});\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n\t/**\n\t * Instantiate the given set of class name, injecting constructor arguments as\n\t * necessary.\n\t * @param names the class names to instantiate\n\t * @return a list of instantiated instances\n\t */\n\tpublic List<T> instantiate(Collection<String> names) {\n\t\treturn instantiate(null, names);\n\t}\n\n\t/**\n\t * Instantiate the given set of class name, injecting constructor arguments as\n\t * necessary.\n\t * @param classLoader the source classloader\n\t * @param names the class names to instantiate\n\t * @return a list of instantiated instances\n\t * @since 2.4.8\n\t */\n\tpublic List<T> instantiate(@Nullable ClassLoader classLoader, Collection<String> names) {\n\t\tAssert.notNull(names, \"'names' must not be null\");\n\t\treturn instantiate(names.stream().map((name) -> TypeSupplier.forName(classLoader, name)));\n\t}\n\n\t/**\n\t * Instantiate the given set of class name, injecting constructor arguments as\n\t * necessary.\n\t * @param name the class name to instantiate\n\t * @return an instantiated instance\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable T instantiate(String name) {\n\t\treturn instantiate(null, name);\n\t}\n\n\t/**\n\t * Instantiate the given set of class name, injecting constructor arguments as\n\t * necessary.\n\t * @param classLoader the source classloader\n\t * @param name the class name to instantiate\n\t * @return an instantiated instance\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable T instantiate(@Nullable ClassLoader classLoader, String name) {\n\t\treturn instantiate(TypeSupplier.forName(classLoader, name));\n\t}\n\n\t/**\n\t * Instantiate the given class, injecting constructor arguments as necessary.\n\t * @param type the type to instantiate\n\t * @return an instantiated instance\n\t * @since 3.4.0\n\t */\n\tpublic @Nullable T instantiateType(Class<?> type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\treturn instantiate(TypeSupplier.forType(type));\n\t}\n\n\t/**\n\t * Instantiate the given set of classes, injecting constructor arguments as necessary.\n\t * @param types the types to instantiate\n\t * @return a list of instantiated instances\n\t * @since 2.4.8\n\t */\n\tpublic List<T> instantiateTypes(Collection<Class<?>> types) {\n\t\tAssert.notNull(types, \"'types' must not be null\");\n\t\treturn instantiate(types.stream().map(TypeSupplier::forType));\n\t}\n\n\t/**\n\t * Get an injectable argument instance for the given type. This method can be used\n\t * when manually instantiating an object without reflection.\n\t * @param <A> the argument type\n\t * @param type the argument type\n\t * @return the argument to inject or {@code null}\n\t * @since 3.4.0\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <A> @Nullable A getArg(Class<A> type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tFunction<Class<?>, Object> parameter = getAvailableParameter(type);\n\t\tAssert.state(parameter != null, \"Unknown argument type \" + type.getName());\n\t\treturn (A) parameter.apply(this.type);\n\t}\n\n\tprivate List<T> instantiate(Stream<TypeSupplier> typeSuppliers) {\n\t\treturn typeSuppliers.map(this::instantiate).sorted(AnnotationAwareOrderComparator.INSTANCE).toList();\n\t}\n\n\tprivate @Nullable T instantiate(TypeSupplier typeSupplier) {\n\t\ttry {\n\t\t\tClass<?> type = typeSupplier.get();\n\t\t\tAssert.state(this.type.isAssignableFrom(type), () -> type + \" is not assignable to \" + this.type);\n\t\t\treturn instantiate(type);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthis.failureHandler.handleFailure(this.type, typeSupplier.getName(), ex);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate T instantiate(Class<?> type) throws Exception {\n\t\tConstructor<?>[] constructors = type.getDeclaredConstructors();\n\t\tArrays.sort(constructors, CONSTRUCTOR_COMPARATOR);\n\t\tfor (Constructor<?> constructor : constructors) {\n\t\t\tObject[] args = getArgs(constructor.getParameterTypes());\n\t\t\tif (args != null) {\n\t\t\t\tReflectionUtils.makeAccessible(constructor);\n\t\t\t\treturn (T) constructor.newInstance(args);\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalAccessException(\"Class [\" + type.getName() + \"] has no suitable constructor\");\n\t}\n\n\tprivate Object @Nullable [] getArgs(Class<?>[] parameterTypes) {\n\t\tObject[] args = new Object[parameterTypes.length];\n\t\tfor (int i = 0; i < parameterTypes.length; i++) {\n\t\t\tFunction<Class<?>, Object> parameter = getAvailableParameter(parameterTypes[i]);\n\t\t\tif (parameter == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\targs[i] = parameter.apply(this.type);\n\t\t}\n\t\treturn args;\n\t}\n\n\tprivate @Nullable Function<Class<?>, Object> getAvailableParameter(Class<?> parameterType) {\n\t\tfor (Map.Entry<Class<?>, Function<Class<?>, Object>> entry : this.availableParameters.entrySet()) {\n\t\t\tif (entry.getKey().isAssignableFrom(parameterType)) {\n\t\t\t\treturn entry.getValue();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Callback used to register available parameters.\n\t */\n\tpublic interface AvailableParameters {\n\n\t\t/**\n\t\t * Add a parameter with an instance value.\n\t\t * @param type the parameter type\n\t\t * @param instance the instance that should be injected\n\t\t */\n\t\tvoid add(Class<?> type, @Nullable Object instance);\n\n\t\t/**\n\t\t * Add a parameter with an instance factory.\n\t\t * @param type the parameter type\n\t\t * @param factory the factory used to create the instance that should be injected\n\t\t */\n\t\tvoid add(Class<?> type, Function<Class<?>, @Nullable Object> factory);\n\n\t}\n\n\t/**\n\t * {@link Supplier} that provides a class type.\n\t */\n\tprivate interface TypeSupplier {\n\n\t\tString getName();\n\n\t\tClass<?> get() throws ClassNotFoundException;\n\n\t\tstatic TypeSupplier forName(@Nullable ClassLoader classLoader, String name) {\n\t\t\treturn new TypeSupplier() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getName() {\n\t\t\t\t\treturn name;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Class<?> get() throws ClassNotFoundException {\n\t\t\t\t\treturn ClassUtils.forName(name, classLoader);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\tstatic TypeSupplier forType(Class<?> type) {\n\t\t\treturn new TypeSupplier() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getName() {\n\t\t\t\t\treturn type.getName();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Class<?> get() {\n\t\t\t\t\treturn type;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t/**\n\t * Strategy for handling a failure that occurs when instantiating a type.\n\t *\n\t * @since 2.7.0\n\t */\n\tpublic interface FailureHandler {\n\n\t\t/**\n\t\t * Handle the {@code failure} that occurred when instantiating the {@code type}\n\t\t * that was expected to be of the given {@code typeSupplier}.\n\t\t * @param type the type\n\t\t * @param implementationName the name of the implementation type\n\t\t * @param failure the failure that occurred\n\t\t */\n\t\tvoid handleFailure(Class<?> type, String implementationName, Throwable failure);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/util/LambdaSafe.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.util;\n\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Optional;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Utility that can be used to invoke lambdas in a safe way. Primarily designed to help\n * support generically typed callbacks where {@link ClassCastException class cast\n * exceptions} need to be dealt with due to class erasure.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic final class LambdaSafe {\n\n\tprivate static final @Nullable Method CLASS_GET_MODULE;\n\n\tprivate static final @Nullable Method MODULE_GET_NAME;\n\n\tstatic {\n\t\tCLASS_GET_MODULE = ReflectionUtils.findMethod(Class.class, \"getModule\");\n\t\tMODULE_GET_NAME = (CLASS_GET_MODULE != null)\n\t\t\t\t? ReflectionUtils.findMethod(CLASS_GET_MODULE.getReturnType(), \"getName\") : null;\n\t}\n\n\tprivate LambdaSafe() {\n\t}\n\n\t/**\n\t * Start a call to a single callback instance, dealing with common generic type\n\t * concerns and exceptions.\n\t * @param callbackType the callback type (a {@link FunctionalInterface functional\n\t * interface})\n\t * @param callbackInstance the callback instance (may be a lambda)\n\t * @param argument the primary argument passed to the callback\n\t * @param additionalArguments any additional arguments passed to the callback\n\t * @param <C> the callback type\n\t * @param <A> the primary argument type\n\t * @return a {@link Callback} instance that can be invoked.\n\t */\n\tpublic static <C, A> Callback<C, A> callback(Class<C> callbackType, C callbackInstance, A argument,\n\t\t\t@Nullable Object @Nullable ... additionalArguments) {\n\t\tAssert.notNull(callbackType, \"'callbackType' must not be null\");\n\t\tAssert.notNull(callbackInstance, \"'callbackInstance' must not be null\");\n\t\treturn new Callback<>(callbackType, callbackInstance, argument, additionalArguments);\n\t}\n\n\t/**\n\t * Start a call to callback instances, dealing with common generic type concerns and\n\t * exceptions.\n\t * @param callbackType the callback type (a {@link FunctionalInterface functional\n\t * interface})\n\t * @param callbackInstances the callback instances (elements may be lambdas)\n\t * @param argument the primary argument passed to the callbacks\n\t * @param additionalArguments any additional arguments passed to the callbacks\n\t * @param <C> the callback type\n\t * @param <A> the primary argument type\n\t * @return a {@link Callbacks} instance that can be invoked.\n\t */\n\tpublic static <C, A> Callbacks<C, A> callbacks(Class<C> callbackType, Collection<? extends C> callbackInstances,\n\t\t\tA argument, Object... additionalArguments) {\n\t\tAssert.notNull(callbackType, \"'callbackType' must not be null\");\n\t\tAssert.notNull(callbackInstances, \"'callbackInstances' must not be null\");\n\t\treturn new Callbacks<>(callbackType, callbackInstances, argument, additionalArguments);\n\t}\n\n\t/**\n\t * Abstract base class for lambda safe callbacks.\n\t *\n\t * @param <C> the callback type\n\t * @param <A> the primary argument type\n\t * @param <SELF> the self class reference\n\t */\n\tprotected abstract static class LambdaSafeCallback<C, A, SELF extends LambdaSafeCallback<C, A, SELF>> {\n\n\t\tprivate final Class<C> callbackType;\n\n\t\tprivate final A argument;\n\n\t\tprivate final @Nullable Object @Nullable [] additionalArguments;\n\n\t\tprivate Log logger;\n\n\t\tprivate Filter<C, A> filter = new GenericTypeFilter<>();\n\n\t\tLambdaSafeCallback(Class<C> callbackType, A argument, @Nullable Object @Nullable [] additionalArguments) {\n\t\t\tthis.callbackType = callbackType;\n\t\t\tthis.argument = argument;\n\t\t\tthis.additionalArguments = additionalArguments;\n\t\t\tthis.logger = LogFactory.getLog(callbackType);\n\t\t}\n\n\t\t/**\n\t\t * Use the specified logger source to report any lambda failures.\n\t\t * @param loggerSource the logger source to use\n\t\t * @return this instance\n\t\t */\n\t\tpublic SELF withLogger(Class<?> loggerSource) {\n\t\t\treturn withLogger(LogFactory.getLog(loggerSource));\n\t\t}\n\n\t\t/**\n\t\t * Use the specified logger to report any lambda failures.\n\t\t * @param logger the logger to use\n\t\t * @return this instance\n\t\t */\n\t\tpublic SELF withLogger(Log logger) {\n\t\t\tAssert.notNull(logger, \"'logger' must not be null\");\n\t\t\tthis.logger = logger;\n\t\t\treturn self();\n\t\t}\n\n\t\t/**\n\t\t * Use a specific filter to determine when a callback should apply. If no explicit\n\t\t * filter is set filter will be attempted using the generic type on the callback\n\t\t * type.\n\t\t * @param filter the filter to use\n\t\t * @return this instance\n\t\t * @since 3.4.8\n\t\t */\n\t\tpublic SELF withFilter(Filter<C, A> filter) {\n\t\t\tAssert.notNull(filter, \"'filter' must not be null\");\n\t\t\tthis.filter = filter;\n\t\t\treturn self();\n\t\t}\n\n\t\tprotected final <R> InvocationResult<R> invoke(C callbackInstance, Supplier<@Nullable R> supplier) {\n\t\t\tif (this.filter.match(this.callbackType, callbackInstance, this.argument, this.additionalArguments)) {\n\t\t\t\ttry {\n\t\t\t\t\treturn InvocationResult.of(supplier.get());\n\t\t\t\t}\n\t\t\t\tcatch (ClassCastException ex) {\n\t\t\t\t\tif (!isLambdaGenericProblem(ex)) {\n\t\t\t\t\t\tthrow ex;\n\t\t\t\t\t}\n\t\t\t\t\tlogNonMatchingType(callbackInstance, ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn InvocationResult.noResult();\n\t\t}\n\n\t\tprivate boolean isLambdaGenericProblem(ClassCastException ex) {\n\t\t\treturn (ex.getMessage() == null || startsWithArgumentClassName(ex.getMessage()));\n\t\t}\n\n\t\tprivate boolean startsWithArgumentClassName(String message) {\n\t\t\tPredicate<@Nullable Object> startsWith = (argument) -> startsWithArgumentClassName(message, argument);\n\t\t\treturn startsWith.test(this.argument) || additionalArgumentsStartsWith(startsWith);\n\t\t}\n\n\t\tprivate boolean additionalArgumentsStartsWith(Predicate<@Nullable Object> startsWith) {\n\t\t\tif (this.additionalArguments == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn Stream.of(this.additionalArguments).anyMatch(startsWith);\n\t\t}\n\n\t\tprivate boolean startsWithArgumentClassName(String message, @Nullable Object argument) {\n\t\t\tif (argument == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tClass<?> argumentType = argument.getClass();\n\t\t\t// On Java 8, the message starts with the class name: \"java.lang.String cannot\n\t\t\t// be cast...\"\n\t\t\tif (message.startsWith(argumentType.getName())) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// On Java 11, the message starts with \"class ...\" a.k.a. Class.toString()\n\t\t\tif (message.startsWith(argumentType.toString())) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// On Java 9, the message used to contain the module name:\n\t\t\t// \"java.base/java.lang.String cannot be cast...\"\n\t\t\tint moduleSeparatorIndex = message.indexOf('/');\n\t\t\tif (moduleSeparatorIndex != -1 && message.startsWith(argumentType.getName(), moduleSeparatorIndex + 1)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (CLASS_GET_MODULE != null && MODULE_GET_NAME != null) {\n\t\t\t\tObject module = ReflectionUtils.invokeMethod(CLASS_GET_MODULE, argumentType);\n\t\t\t\tObject moduleName = ReflectionUtils.invokeMethod(MODULE_GET_NAME, module);\n\t\t\t\treturn message.startsWith(moduleName + \"/\" + argumentType.getName());\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate void logNonMatchingType(C callback, ClassCastException ex) {\n\t\t\tif (this.logger.isDebugEnabled()) {\n\t\t\t\tClass<?> expectedType = ResolvableType.forClass(this.callbackType).resolveGeneric();\n\t\t\t\tString expectedTypeName = (expectedType != null) ? ClassUtils.getShortName(expectedType) + \" type\"\n\t\t\t\t\t\t: \"type\";\n\t\t\t\tString message = \"Non-matching \" + expectedTypeName + \" for callback \"\n\t\t\t\t\t\t+ ClassUtils.getShortName(this.callbackType) + \": \" + callback;\n\t\t\t\tthis.logger.debug(message, ex);\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate SELF self() {\n\t\t\treturn (SELF) this;\n\t\t}\n\n\t}\n\n\t/**\n\t * Represents a single callback that can be invoked in a lambda safe way.\n\t *\n\t * @param <C> the callback type\n\t * @param <A> the primary argument type\n\t */\n\tpublic static final class Callback<C, A> extends LambdaSafeCallback<C, A, Callback<C, A>> {\n\n\t\tprivate final C callbackInstance;\n\n\t\tprivate Callback(Class<C> callbackType, C callbackInstance, A argument,\n\t\t\t\t@Nullable Object @Nullable [] additionalArguments) {\n\t\t\tsuper(callbackType, argument, additionalArguments);\n\t\t\tthis.callbackInstance = callbackInstance;\n\t\t}\n\n\t\t/**\n\t\t * Invoke the callback instance where the callback method returns void.\n\t\t * @param invoker the invoker used to invoke the callback\n\t\t */\n\t\tpublic void invoke(Consumer<C> invoker) {\n\t\t\tSupplier<@Nullable Void> supplier = () -> {\n\t\t\t\tinvoker.accept(this.callbackInstance);\n\t\t\t\treturn null;\n\t\t\t};\n\t\t\tinvoke(this.callbackInstance, supplier);\n\t\t}\n\n\t\t/**\n\t\t * Invoke the callback instance where the callback method returns a result.\n\t\t * @param invoker the invoker used to invoke the callback\n\t\t * @param <R> the result type\n\t\t * @return the result of the invocation (may be {@link InvocationResult#noResult}\n\t\t * if the callback was not invoked)\n\t\t */\n\t\tpublic <R> InvocationResult<R> invokeAnd(Function<C, @Nullable R> invoker) {\n\t\t\tSupplier<@Nullable R> supplier = () -> invoker.apply(this.callbackInstance);\n\t\t\treturn invoke(this.callbackInstance, supplier);\n\t\t}\n\n\t}\n\n\t/**\n\t * Represents a collection of callbacks that can be invoked in a lambda safe way.\n\t *\n\t * @param <C> the callback type\n\t * @param <A> the primary argument type\n\t */\n\tpublic static final class Callbacks<C, A> extends LambdaSafeCallback<C, A, Callbacks<C, A>> {\n\n\t\tprivate final Collection<? extends C> callbackInstances;\n\n\t\tprivate Callbacks(Class<C> callbackType, Collection<? extends C> callbackInstances, A argument,\n\t\t\t\tObject[] additionalArguments) {\n\t\t\tsuper(callbackType, argument, additionalArguments);\n\t\t\tthis.callbackInstances = callbackInstances;\n\t\t}\n\n\t\t/**\n\t\t * Invoke the callback instances where the callback method returns void.\n\t\t * @param invoker the invoker used to invoke the callback\n\t\t */\n\t\tpublic void invoke(Consumer<C> invoker) {\n\t\t\tthis.callbackInstances.forEach((callbackInstance) -> {\n\t\t\t\tSupplier<@Nullable Void> supplier = () -> {\n\t\t\t\t\tinvoker.accept(callbackInstance);\n\t\t\t\t\treturn null;\n\t\t\t\t};\n\t\t\t\tinvoke(callbackInstance, supplier);\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * Invoke the callback instances where the callback method returns a result.\n\t\t * @param invoker the invoker used to invoke the callback\n\t\t * @param <R> the result type\n\t\t * @return the results of the invocation (may be an empty stream if no callbacks\n\t\t * could be called)\n\t\t */\n\t\tpublic <R> Stream<R> invokeAnd(Function<C, @Nullable R> invoker) {\n\t\t\tFunction<C, InvocationResult<R>> mapper = (callbackInstance) -> {\n\t\t\t\tSupplier<@Nullable R> supplier = () -> invoker.apply(callbackInstance);\n\t\t\t\treturn invoke(callbackInstance, supplier);\n\t\t\t};\n\t\t\treturn this.callbackInstances.stream()\n\t\t\t\t.map(mapper)\n\t\t\t\t.filter(InvocationResult::hasResult)\n\t\t\t\t.map(InvocationResult::get);\n\t\t}\n\n\t}\n\n\t/**\n\t * A filter that can be used to restrict when a callback is used.\n\t *\n\t * @param <C> the callback type\n\t * @param <A> the primary argument type\n\t * @since 3.4.8\n\t */\n\t@FunctionalInterface\n\tpublic interface Filter<C, A> {\n\n\t\t/**\n\t\t * Determine if the given callback matches and should be invoked.\n\t\t * @param callbackType the callback type (the functional interface)\n\t\t * @param callbackInstance the callback instance (the implementation)\n\t\t * @param argument the primary argument\n\t\t * @param additionalArguments any additional arguments\n\t\t * @return if the callback matches and should be invoked\n\t\t */\n\t\tboolean match(Class<C> callbackType, C callbackInstance, A argument,\n\t\t\t\t@Nullable Object @Nullable [] additionalArguments);\n\n\t\t/**\n\t\t * Return a {@link Filter} that allows all callbacks to be invoked.\n\t\t * @param <C> the callback type\n\t\t * @param <A> the primary argument type\n\t\t * @return an \"allow all\" filter\n\t\t */\n\t\tstatic <C, A> Filter<C, A> allowAll() {\n\t\t\treturn (callbackType, callbackInstance, argument, additionalArguments) -> true;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Filter} that matches when the callback has a single generic and primary\n\t * argument is an instance of it.\n\t */\n\tprivate static final class GenericTypeFilter<C, A> implements Filter<C, A> {\n\n\t\t@Override\n\t\tpublic boolean match(Class<C> callbackType, C callbackInstance, A argument,\n\t\t\t\t@Nullable Object @Nullable [] additionalArguments) {\n\t\t\tResolvableType type = ResolvableType.forClass(callbackType, callbackInstance.getClass());\n\t\t\tif (type.getGenerics().length != 1) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tClass<?> generic = type.resolveGeneric();\n\t\t\tif (generic != null) {\n\t\t\t\treturn generic.isInstance(argument);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n\t/**\n\t * The result of a callback which may be a value, {@code null} or absent entirely if\n\t * the callback wasn't suitable. Similar in design to {@link Optional} but allows for\n\t * {@code null} as a valid value.\n\t *\n\t * @param <R> the result type\n\t */\n\tpublic static final class InvocationResult<R> {\n\n\t\tprivate static final InvocationResult<?> NONE = new InvocationResult<>(null);\n\n\t\tprivate final @Nullable R value;\n\n\t\tprivate InvocationResult(@Nullable R value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t/**\n\t\t * Return true if a result in present.\n\t\t * @return if a result is present\n\t\t */\n\t\tpublic boolean hasResult() {\n\t\t\treturn this != NONE;\n\t\t}\n\n\t\t/**\n\t\t * Return the result of the invocation or {@code null} if the callback wasn't\n\t\t * suitable.\n\t\t * @return the result of the invocation or {@code null}\n\t\t */\n\t\tpublic @Nullable R get() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t/**\n\t\t * Return the result of the invocation or the given fallback if the callback\n\t\t * wasn't suitable.\n\t\t * @param fallback the fallback to use when there is no result\n\t\t * @return the result of the invocation or the fallback\n\t\t */\n\t\tpublic @Nullable R get(@Nullable R fallback) {\n\t\t\treturn (this != NONE) ? this.value : fallback;\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link InvocationResult} instance with the specified value.\n\t\t * @param value the value (may be {@code null})\n\t\t * @param <R> the result type\n\t\t * @return an {@link InvocationResult}\n\t\t */\n\t\tpublic static <R> InvocationResult<R> of(@Nullable R value) {\n\t\t\treturn new InvocationResult<>(value);\n\t\t}\n\n\t\t/**\n\t\t * Return an {@link InvocationResult} instance representing no result.\n\t\t * @param <R> the result type\n\t\t * @return an {@link InvocationResult}\n\t\t */\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic static <R> InvocationResult<R> noResult() {\n\t\t\treturn (InvocationResult<R>) NONE;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Contains miscellaneous utility classes.\n */\n@NullMarked\npackage org.springframework.boot.util;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/validation/MessageInterpolatorFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport jakarta.validation.MessageInterpolator;\nimport jakarta.validation.Validation;\nimport jakarta.validation.ValidationException;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.context.MessageSource;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ObjectFactory} that can be used to create a {@link MessageInterpolator}.\n * Attempts to pick the most appropriate {@link MessageInterpolator} based on the\n * classpath.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic class MessageInterpolatorFactory implements ObjectFactory<MessageInterpolator> {\n\n\tprivate static final Set<String> FALLBACKS;\n\n\tstatic {\n\t\tSet<String> fallbacks = new LinkedHashSet<>();\n\t\tfallbacks.add(\"org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator\");\n\t\tFALLBACKS = Collections.unmodifiableSet(fallbacks);\n\t}\n\n\tprivate final @Nullable MessageSource messageSource;\n\n\tpublic MessageInterpolatorFactory() {\n\t\tthis(null);\n\t}\n\n\t/**\n\t * Creates a new {@link MessageInterpolatorFactory} that will produce a\n\t * {@link MessageInterpolator} that uses the given {@code messageSource} to resolve\n\t * any message parameters before final interpolation.\n\t * @param messageSource message source to be used by the interpolator\n\t * @since 2.6.0\n\t */\n\tpublic MessageInterpolatorFactory(@Nullable MessageSource messageSource) {\n\t\tthis.messageSource = messageSource;\n\t}\n\n\t@Override\n\tpublic MessageInterpolator getObject() throws BeansException {\n\t\tMessageInterpolator messageInterpolator = getMessageInterpolator();\n\t\tif (this.messageSource != null) {\n\t\t\treturn new MessageSourceMessageInterpolator(this.messageSource, messageInterpolator);\n\t\t}\n\t\treturn messageInterpolator;\n\t}\n\n\tprivate MessageInterpolator getMessageInterpolator() {\n\t\ttry {\n\t\t\treturn Validation.byDefaultProvider().configure().getDefaultMessageInterpolator();\n\t\t}\n\t\tcatch (ValidationException ex) {\n\t\t\tMessageInterpolator fallback = getFallback();\n\t\t\tif (fallback != null) {\n\t\t\t\treturn fallback;\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate @Nullable MessageInterpolator getFallback() {\n\t\tfor (String fallback : FALLBACKS) {\n\t\t\ttry {\n\t\t\t\treturn getFallback(fallback);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Swallow and continue\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate MessageInterpolator getFallback(String fallback) {\n\t\tClass<?> interpolatorClass = ClassUtils.resolveClassName(fallback, null);\n\t\tObject interpolator = BeanUtils.instantiateClass(interpolatorClass);\n\t\treturn (MessageInterpolator) interpolator;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/validation/MessageSourceMessageInterpolator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation;\n\nimport java.util.LinkedHashSet;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport jakarta.validation.MessageInterpolator;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.MessageSource;\nimport org.springframework.context.i18n.LocaleContextHolder;\n\n/**\n * Resolves any message parameters through {@link MessageSource} and then interpolates a\n * message using the underlying {@link MessageInterpolator}.\n *\n * @author Dmytro Nosan\n * @author Scott Frederick\n */\nclass MessageSourceMessageInterpolator implements MessageInterpolator {\n\n\tprivate static final String DEFAULT_MESSAGE = MessageSourceMessageInterpolator.class.getName();\n\n\tprivate static final char PREFIX = '{';\n\n\tprivate static final char SUFFIX = '}';\n\n\tprivate static final char ESCAPE = '\\\\';\n\n\tprivate final MessageSource messageSource;\n\n\tprivate final MessageInterpolator messageInterpolator;\n\n\tMessageSourceMessageInterpolator(MessageSource messageSource, MessageInterpolator messageInterpolator) {\n\t\tthis.messageSource = messageSource;\n\t\tthis.messageInterpolator = messageInterpolator;\n\t}\n\n\t@Override\n\tpublic String interpolate(String messageTemplate, Context context) {\n\t\treturn interpolate(messageTemplate, context, LocaleContextHolder.getLocale());\n\t}\n\n\t@Override\n\tpublic String interpolate(String messageTemplate, Context context, Locale locale) {\n\t\tString message = replaceParameters(messageTemplate, locale);\n\t\treturn this.messageInterpolator.interpolate(message, context, locale);\n\t}\n\n\t/**\n\t * Recursively replaces all message parameters.\n\t * <p>\n\t * The message parameter prefix <code>&#123;</code> and suffix <code>&#125;</code> can\n\t * be escaped using {@code \\}, e.g. <code>\\&#123;escaped\\&#125;</code>.\n\t * @param message the message containing the parameters to be replaced\n\t * @param locale the locale to use when resolving replacements\n\t * @return the message with parameters replaced\n\t */\n\tprivate String replaceParameters(String message, Locale locale) {\n\t\treturn replaceParameters(message, locale, new LinkedHashSet<>(4));\n\t}\n\n\tprivate String replaceParameters(String message, Locale locale, Set<String> visitedParameters) {\n\t\tStringBuilder buf = new StringBuilder(message);\n\t\tint parentheses = 0;\n\t\tint startIndex = -1;\n\t\tint endIndex = -1;\n\t\tfor (int i = 0; i < buf.length(); i++) {\n\t\t\tif (buf.charAt(i) == ESCAPE) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t\telse if (buf.charAt(i) == PREFIX) {\n\t\t\t\tif (startIndex == -1) {\n\t\t\t\t\tstartIndex = i;\n\t\t\t\t}\n\t\t\t\tparentheses++;\n\t\t\t}\n\t\t\telse if (buf.charAt(i) == SUFFIX) {\n\t\t\t\tif (parentheses > 0) {\n\t\t\t\t\tparentheses--;\n\t\t\t\t}\n\t\t\t\tendIndex = i;\n\t\t\t}\n\t\t\tif (parentheses == 0 && startIndex < endIndex) {\n\t\t\t\tString parameter = buf.substring(startIndex + 1, endIndex);\n\t\t\t\tif (!visitedParameters.add(parameter)) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Circular reference '{\" + String.join(\" -> \", visitedParameters)\n\t\t\t\t\t\t\t+ \" -> \" + parameter + \"}'\");\n\t\t\t\t}\n\t\t\t\tString value = replaceParameter(parameter, locale, visitedParameters);\n\t\t\t\tif (value != null) {\n\t\t\t\t\tbuf.replace(startIndex, endIndex + 1, value);\n\t\t\t\t\ti = startIndex + value.length() - 1;\n\t\t\t\t}\n\t\t\t\tvisitedParameters.remove(parameter);\n\t\t\t\tstartIndex = -1;\n\t\t\t\tendIndex = -1;\n\t\t\t}\n\t\t}\n\t\treturn buf.toString();\n\t}\n\n\tprivate @Nullable String replaceParameter(String parameter, Locale locale, Set<String> visitedParameters) {\n\t\tparameter = replaceParameters(parameter, locale, visitedParameters);\n\t\tString value = this.messageSource.getMessage(parameter, null, DEFAULT_MESSAGE, locale);\n\t\tif (value == null || value.equals(DEFAULT_MESSAGE)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn replaceParameters(value, locale, visitedParameters);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/validation/beanvalidation/FilteredMethodValidationPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.beanvalidation;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.stream.Stream;\n\nimport org.springframework.aop.ClassFilter;\nimport org.springframework.aop.MethodMatcher;\nimport org.springframework.aop.support.ComposablePointcut;\nimport org.springframework.aop.support.DefaultPointcutAdvisor;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\n\n/**\n * Custom {@link MethodValidationPostProcessor} that applies\n * {@link MethodValidationExcludeFilter exclusion filters}.\n *\n * @author Andy Wilkinson\n * @since 2.4.0\n */\npublic class FilteredMethodValidationPostProcessor extends MethodValidationPostProcessor {\n\n\tprivate final Collection<MethodValidationExcludeFilter> excludeFilters;\n\n\t/**\n\t * Creates a new {@code FilteredMethodValidationPostProcessor} that will apply the\n\t * given {@code excludeFilters} when identifying beans that are eligible for method\n\t * validation post-processing.\n\t * @param excludeFilters filters to apply\n\t */\n\tpublic FilteredMethodValidationPostProcessor(Stream<? extends MethodValidationExcludeFilter> excludeFilters) {\n\t\tthis.excludeFilters = excludeFilters.map(MethodValidationExcludeFilter.class::cast).toList();\n\t}\n\n\t/**\n\t * Creates a new {@code FilteredMethodValidationPostProcessor} that will apply the\n\t * given {@code excludeFilters} when identifying beans that are eligible for method\n\t * validation post-processing.\n\t * @param excludeFilters filters to apply\n\t */\n\tpublic FilteredMethodValidationPostProcessor(Collection<? extends MethodValidationExcludeFilter> excludeFilters) {\n\t\tthis.excludeFilters = new ArrayList<>(excludeFilters);\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tsuper.afterPropertiesSet();\n\t\tDefaultPointcutAdvisor advisor = (DefaultPointcutAdvisor) this.advisor;\n\t\tAssert.state(advisor != null, \"'advisor' must not be null\");\n\t\tClassFilter classFilter = advisor.getPointcut().getClassFilter();\n\t\tMethodMatcher methodMatcher = advisor.getPointcut().getMethodMatcher();\n\t\tadvisor.setPointcut(new ComposablePointcut(classFilter, methodMatcher).intersection(this::isIncluded));\n\t}\n\n\tprivate boolean isIncluded(Class<?> candidate) {\n\t\tfor (MethodValidationExcludeFilter exclusionFilter : this.excludeFilters) {\n\t\t\tif (exclusionFilter.isExcluded(candidate)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/validation/beanvalidation/MethodValidationExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.beanvalidation;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\n\n/**\n * A filter for excluding types from method validation.\n *\n * @author Andy Wilkinson\n * @since 2.4.0\n * @see FilteredMethodValidationPostProcessor\n */\npublic interface MethodValidationExcludeFilter {\n\n\t/**\n\t * Evaluate whether to exclude the given {@code type} from method validation.\n\t * @param type the type to evaluate\n\t * @return {@code true} to exclude the type from method validation, otherwise\n\t * {@code false}.\n\t */\n\tboolean isExcluded(Class<?> type);\n\n\t/**\n\t * Factory method to create a {@link MethodValidationExcludeFilter} that excludes\n\t * classes by annotation found using an {@link SearchStrategy#INHERITED_ANNOTATIONS\n\t * inherited annotations search strategy}.\n\t * @param annotationType the annotation to check\n\t * @return a {@link MethodValidationExcludeFilter} instance\n\t */\n\tstatic MethodValidationExcludeFilter byAnnotation(Class<? extends Annotation> annotationType) {\n\t\treturn byAnnotation(annotationType, SearchStrategy.INHERITED_ANNOTATIONS);\n\t}\n\n\t/**\n\t * Factory method to create a {@link MethodValidationExcludeFilter} that excludes\n\t * classes by annotation found using the given search strategy.\n\t * @param annotationType the annotation to check\n\t * @param searchStrategy the annotation search strategy\n\t * @return a {@link MethodValidationExcludeFilter} instance\n\t */\n\tstatic MethodValidationExcludeFilter byAnnotation(Class<? extends Annotation> annotationType,\n\t\t\tSearchStrategy searchStrategy) {\n\t\treturn (type) -> MergedAnnotations.from(type, searchStrategy).isPresent(annotationType);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/validation/beanvalidation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utilities and classes related to bean validation.\n */\n@NullMarked\npackage org.springframework.boot.validation.beanvalidation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/validation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utilities and classes related to validation.\n */\n@NullMarked\npackage org.springframework.boot.validation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/AnnotationConfigReactiveWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link ConfigurableReactiveWebApplicationContext} that accepts annotated classes as\n * input - in particular {@link Configuration @Configuration}-annotated classes, but also\n * plain {@link Component @Component} classes and JSR-330 compliant classes using\n * {@code javax.inject} annotations. Allows for registering classes one by one (specifying\n * class names as config location) as well as for classpath scanning (specifying base\n * packages as config location).\n * <p>\n * Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}\n * definitions will override ones defined in earlier loaded files. This can be leveraged\n * to deliberately override certain bean definitions through an extra Configuration class.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 2.0.0\n * @see AnnotationConfigApplicationContext\n */\npublic class AnnotationConfigReactiveWebApplicationContext extends AnnotationConfigApplicationContext\n\t\timplements ConfigurableReactiveWebApplicationContext {\n\n\t/**\n\t * Create a new AnnotationConfigReactiveWebApplicationContext that needs to be\n\t * populated through {@link #register} calls and then manually {@linkplain #refresh\n\t * refreshed}.\n\t */\n\tpublic AnnotationConfigReactiveWebApplicationContext() {\n\t}\n\n\t/**\n\t * Create a new AnnotationConfigApplicationContext with the given\n\t * DefaultListableBeanFactory.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t * @since 2.2.0\n\t */\n\tpublic AnnotationConfigReactiveWebApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t}\n\n\t/**\n\t * Create a new AnnotationConfigApplicationContext, deriving bean definitions from the\n\t * given annotated classes and automatically refreshing the context.\n\t * @param annotatedClasses one or more annotated classes, e.g.\n\t * {@link Configuration @Configuration} classes\n\t * @since 2.2.0\n\t */\n\tpublic AnnotationConfigReactiveWebApplicationContext(Class<?>... annotatedClasses) {\n\t\tsuper(annotatedClasses);\n\t}\n\n\t/**\n\t * Create a new AnnotationConfigApplicationContext, scanning for bean definitions in\n\t * the given packages and automatically refreshing the context.\n\t * @param basePackages the packages to check for annotated classes\n\t * @since 2.2.0\n\t */\n\tpublic AnnotationConfigReactiveWebApplicationContext(String... basePackages) {\n\t\tsuper(basePackages);\n\t}\n\n\t@Override\n\tprotected ConfigurableEnvironment createEnvironment() {\n\t\treturn new StandardReactiveWebEnvironment();\n\t}\n\n\t@Override\n\tprotected Resource getResourceByPath(String path) {\n\t\t// We must be careful not to expose classpath resources\n\t\treturn new FilteredReactiveWebContextResource(path);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/ConfigurableReactiveWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Interface to provide configuration for a reactive web application.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic interface ConfigurableReactiveWebApplicationContext\n\t\textends ConfigurableApplicationContext, ReactiveWebApplicationContext {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/ConfigurableReactiveWebEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * Specialization of {@link ConfigurableEnvironment} for reactive application contexts.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see ConfigurableReactiveWebApplicationContext#getEnvironment()\n */\npublic interface ConfigurableReactiveWebEnvironment extends ConfigurableEnvironment {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/FilteredReactiveWebContextResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.springframework.core.io.AbstractResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.StringUtils;\n\n/**\n * Resource implementation that replaces the\n * {@link org.springframework.web.context.support.ServletContextResource} in a reactive\n * web application.\n * <p>\n * {@link #exists()} always returns {@code false} in order to avoid exposing the whole\n * classpath in a non-servlet environment.\n *\n * @author Brian Clozel\n */\nclass FilteredReactiveWebContextResource extends AbstractResource {\n\n\tprivate final String path;\n\n\tFilteredReactiveWebContextResource(String path) {\n\t\tthis.path = path;\n\t}\n\n\t@Override\n\tpublic boolean exists() {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic Resource createRelative(String relativePath) throws IOException {\n\t\tString pathToUse = StringUtils.applyRelativePath(this.path, relativePath);\n\t\treturn new FilteredReactiveWebContextResource(pathToUse);\n\t}\n\n\t@Override\n\tpublic String getDescription() {\n\t\treturn \"ReactiveWebContext resource [\" + this.path + \"]\";\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream() throws IOException {\n\t\tthrow new FileNotFoundException(getDescription() + \" cannot be opened because it does not exist\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/FilteredReactiveWebContextResourceFilePathResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.io.ApplicationResourceLoader.FilePathResolver;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link FilePathResolver} for {@link FilteredReactiveWebContextResource}.\n *\n * @author Dmytro Nosan\n */\nclass FilteredReactiveWebContextResourceFilePathResolver implements ApplicationResourceLoader.FilePathResolver {\n\n\t@Override\n\tpublic @Nullable String resolveFilePath(String location, Resource resource) {\n\t\treturn (resource instanceof FilteredReactiveWebContextResource) ? location : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/GenericReactiveWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.Resource;\n\n/**\n * Subclass of {@link GenericApplicationContext}, suitable for reactive web environments.\n *\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @since 2.0.0\n */\npublic class GenericReactiveWebApplicationContext extends GenericApplicationContext\n\t\timplements ConfigurableReactiveWebApplicationContext {\n\n\t/**\n\t * Create a new {@link GenericReactiveWebApplicationContext}.\n\t * @see #registerBeanDefinition\n\t * @see #refresh\n\t */\n\tpublic GenericReactiveWebApplicationContext() {\n\t}\n\n\t/**\n\t * Create a new {@link GenericReactiveWebApplicationContext} with the given\n\t * DefaultListableBeanFactory.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t * @see #registerBeanDefinition\n\t * @see #refresh\n\t */\n\tpublic GenericReactiveWebApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t}\n\n\t@Override\n\tprotected ConfigurableEnvironment createEnvironment() {\n\t\treturn new StandardReactiveWebEnvironment();\n\t}\n\n\t@Override\n\tprotected Resource getResourceByPath(String path) {\n\t\t// We must be careful not to expose classpath resources\n\t\treturn new FilteredReactiveWebContextResource(path);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/ReactiveWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Interface to provide configuration for a reactive web application.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic interface ReactiveWebApplicationContext extends ApplicationContext {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/StandardReactiveWebEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * {@link Environment} implementation to be used by {@code Reactive}-based web\n * applications. All web-related (reactive-based) {@code ApplicationContext} classes\n * initialize an instance by default.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class StandardReactiveWebEnvironment extends StandardEnvironment implements ConfigurableReactiveWebEnvironment {\n\n\tpublic StandardReactiveWebEnvironment() {\n\t\tsuper();\n\t}\n\n\tprotected StandardReactiveWebEnvironment(MutablePropertySources propertySources) {\n\t\tsuper(propertySources);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive based web integrations with Spring's\n * {@link org.springframework.context.ApplicationContext ApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.web.context.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/servlet/AnnotationConfigServletWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.servlet;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinitionCustomizer;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.AnnotationScopeMetadataResolver;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ScopeMetadataResolver;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\n\n/**\n * {@link GenericWebApplicationContext} that accepts annotated classes as input - in\n * particular {@link Configuration @Configuration}-annotated classes, but also plain\n * {@link Component @Component} classes and JSR-330 compliant classes using\n * {@code javax.inject} annotations. Allows for registering classes one by one (specifying\n * class names as config location) as well as for classpath scanning (specifying base\n * packages as config location).\n * <p>\n * Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}\n * definitions will override ones defined in earlier loaded files. This can be leveraged\n * to deliberately override certain bean definitions through an extra Configuration class.\n *\n * @author Stephane Nicoll\n * @since 2.2.0\n * @see #register(Class...)\n * @see #scan(String...)\n */\npublic class AnnotationConfigServletWebApplicationContext extends GenericWebApplicationContext\n\t\timplements AnnotationConfigRegistry {\n\n\tprivate final AnnotatedBeanDefinitionReader reader;\n\n\tprivate final ClassPathBeanDefinitionScanner scanner;\n\n\tprivate final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();\n\n\tprivate String @Nullable [] basePackages;\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebApplicationContext} that needs to be\n\t * populated through {@link #register} calls and then manually {@linkplain #refresh\n\t * refreshed}.\n\t */\n\tpublic AnnotationConfigServletWebApplicationContext() {\n\t\tthis.reader = new AnnotatedBeanDefinitionReader(this);\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(this);\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebApplicationContext} with the given\n\t * {@code DefaultListableBeanFactory}. The context needs to be populated through\n\t * {@link #register} calls and then manually {@linkplain #refresh refreshed}.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t */\n\tpublic AnnotationConfigServletWebApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t\tthis.reader = new AnnotatedBeanDefinitionReader(this);\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(this);\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebApplicationContext}, deriving bean\n\t * definitions from the given annotated classes and automatically refreshing the\n\t * context.\n\t * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}\n\t * classes\n\t */\n\tpublic AnnotationConfigServletWebApplicationContext(Class<?>... annotatedClasses) {\n\t\tthis();\n\t\tregister(annotatedClasses);\n\t\trefresh();\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebApplicationContext}, scanning for\n\t * bean definitions in the given packages and automatically refreshing the context.\n\t * @param basePackages the packages to check for annotated classes\n\t */\n\tpublic AnnotationConfigServletWebApplicationContext(String... basePackages) {\n\t\tthis();\n\t\tscan(basePackages);\n\t\trefresh();\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <p>\n\t * Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader} and\n\t * {@link ClassPathBeanDefinitionScanner} members.\n\t */\n\t@Override\n\tpublic void setEnvironment(ConfigurableEnvironment environment) {\n\t\tsuper.setEnvironment(environment);\n\t\tthis.reader.setEnvironment(environment);\n\t\tthis.scanner.setEnvironment(environment);\n\t}\n\n\t/**\n\t * Provide a custom {@link BeanNameGenerator} for use with\n\t * {@link AnnotatedBeanDefinitionReader} and/or\n\t * {@link ClassPathBeanDefinitionScanner}, if any.\n\t * <p>\n\t * Default is\n\t * {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.\n\t * <p>\n\t * Any call to this method must occur prior to calls to {@link #register(Class...)}\n\t * and/or {@link #scan(String...)}.\n\t * @param beanNameGenerator the bean name generator\n\t * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator\n\t * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator\n\t */\n\tpublic void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {\n\t\tthis.reader.setBeanNameGenerator(beanNameGenerator);\n\t\tthis.scanner.setBeanNameGenerator(beanNameGenerator);\n\t\tgetBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);\n\t}\n\n\t/**\n\t * Set the {@link ScopeMetadataResolver} to use for detected bean classes.\n\t * <p>\n\t * The default is an {@link AnnotationScopeMetadataResolver}.\n\t * <p>\n\t * Any call to this method must occur prior to calls to {@link #register(Class...)}\n\t * and/or {@link #scan(String...)}.\n\t * @param scopeMetadataResolver the scope metadata resolver\n\t */\n\tpublic void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {\n\t\tthis.reader.setScopeMetadataResolver(scopeMetadataResolver);\n\t\tthis.scanner.setScopeMetadataResolver(scopeMetadataResolver);\n\t}\n\n\t/**\n\t * Register one or more annotated classes to be processed. Note that\n\t * {@link #refresh()} must be called in order for the context to fully process the new\n\t * class.\n\t * <p>\n\t * Calls to {@code #register} are idempotent; adding the same annotated class more\n\t * than once has no additional effect.\n\t * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}\n\t * classes\n\t * @see #scan(String...)\n\t * @see #refresh()\n\t */\n\t@Override\n\tpublic final void register(Class<?>... annotatedClasses) {\n\t\tAssert.notEmpty(annotatedClasses, \"'annotatedClasses' must not be empty\");\n\t\tthis.annotatedClasses.addAll(Arrays.asList(annotatedClasses));\n\t}\n\n\t/**\n\t * Perform a scan within the specified base packages. Note that {@link #refresh()}\n\t * must be called in order for the context to fully process the new class.\n\t * @param basePackages the packages to check for annotated classes\n\t * @see #register(Class...)\n\t * @see #refresh()\n\t */\n\t@Override\n\tpublic final void scan(String... basePackages) {\n\t\tAssert.notEmpty(basePackages, \"'basePackages' must not be empty\");\n\t\tthis.basePackages = basePackages;\n\t}\n\n\t@Override\n\tprotected void prepareRefresh() {\n\t\tthis.scanner.clearCache();\n\t\tsuper.prepareRefresh();\n\t}\n\n\t@Override\n\tprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\tsuper.postProcessBeanFactory(beanFactory);\n\t\tif (!ObjectUtils.isEmpty(this.basePackages)) {\n\t\t\tthis.scanner.scan(this.basePackages);\n\t\t}\n\t\tif (!this.annotatedClasses.isEmpty()) {\n\t\t\tthis.reader.register(ClassUtils.toClassArray(this.annotatedClasses));\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T> void registerBean(@Nullable String beanName, Class<T> beanClass, @Nullable Supplier<T> supplier,\n\t\t\tBeanDefinitionCustomizer... customizers) {\n\t\tthis.reader.registerBean(beanClass, beanName, supplier, customizers);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/servlet/ApplicationServletEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.servlet;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.core.env.ConfigurablePropertyResolver;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\n/**\n * {@link StandardServletEnvironment} for typical use in a typical\n * {@link SpringApplication}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ApplicationServletEnvironment extends StandardServletEnvironment {\n\n\t@Override\n\tprotected @Nullable String doGetActiveProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected @Nullable String doGetDefaultProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {\n\t\treturn ConfigurationPropertySources.createPropertyResolver(propertySources);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/servlet/ServletContextResourceFilePathResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.servlet;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.io.ApplicationResourceLoader.FilePathResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.context.support.ServletContextResource;\n\n/**\n * {@link FilePathResolver} for {@link ServletContextResource}.\n *\n * @author Phillip Webb\n */\nclass ServletContextResourceFilePathResolver implements ApplicationResourceLoader.FilePathResolver {\n\n\tprivate static final String RESOURCE_CLASS_NAME = \"org.springframework.web.context.support.ServletContextResource\";\n\n\tprivate final @Nullable Class<?> resourceClass;\n\n\tServletContextResourceFilePathResolver() {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tthis.resourceClass = ClassUtils.isPresent(RESOURCE_CLASS_NAME, classLoader)\n\t\t\t\t? ClassUtils.resolveClassName(RESOURCE_CLASS_NAME, classLoader) : null;\n\t}\n\n\t@Override\n\tpublic @Nullable String resolveFilePath(String location, Resource resource) {\n\t\treturn (this.resourceClass != null && this.resourceClass.isInstance(resource)) ? location : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/servlet/WebApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.servlet;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.boot.web.servlet.ServletContextInitializerBeans;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.ServletContextScope;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\n\n/**\n * Common initialization logic for Servlet web applications.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class WebApplicationContextInitializer {\n\n\tprivate static final Log logger = LogFactory.getLog(WebApplicationContextInitializer.class);\n\n\tprivate final ConfigurableWebApplicationContext context;\n\n\tpublic WebApplicationContextInitializer(ConfigurableWebApplicationContext context) {\n\t\tthis.context = context;\n\t}\n\n\tpublic void initialize(ServletContext servletContext) throws ServletException {\n\t\tprepareWebApplicationContext(servletContext);\n\t\tregisterApplicationScope(servletContext, this.context.getBeanFactory());\n\t\tWebApplicationContextUtils.registerEnvironmentBeans(this.context.getBeanFactory(), servletContext);\n\t\tfor (ServletContextInitializer initializerBean : new ServletContextInitializerBeans(\n\t\t\t\tthis.context.getBeanFactory())) {\n\t\t\tinitializerBean.onStartup(servletContext);\n\t\t}\n\t}\n\n\tprivate void prepareWebApplicationContext(ServletContext servletContext) {\n\t\tObject rootContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);\n\t\tif (rootContext != null) {\n\t\t\tif (rootContext == this) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Cannot initialize context because there is already a root application context present - \"\n\t\t\t\t\t\t\t\t+ \"check whether you have multiple ServletContextInitializers!\");\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"Published root WebApplicationContext as ServletContext attribute with name [\"\n\t\t\t\t\t\t+ WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + \"]\");\n\t\t\t}\n\t\t\tthis.context.setServletContext(servletContext);\n\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\tlong elapsedTime = System.currentTimeMillis() - this.context.getStartupDate();\n\t\t\t\tlogger.info(\"Root WebApplicationContext: initialization completed in \" + elapsedTime + \" ms\");\n\t\t\t}\n\t\t}\n\t\tcatch (RuntimeException | Error ex) {\n\t\t\tlogger.error(\"Context initialization failed\", ex);\n\t\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate void registerApplicationScope(ServletContext servletContext, ConfigurableListableBeanFactory beanFactory) {\n\t\tServletContextScope appScope = new ServletContextScope(servletContext);\n\t\tbeanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);\n\t\t// Register as ServletContext attribute, for ContextCleanupListener to detect it.\n\t\tservletContext.setAttribute(ServletContextScope.class.getName(), appScope);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/context/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Servlet based web integrations with Spring's\n * {@link org.springframework.web.context.WebApplicationContext WebApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.web.context.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/Error.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.MessageSourceResolvable;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.validation.ObjectError;\n\n/**\n * A wrapper class for {@link MessageSourceResolvable} errors that is safe for JSON\n * serialization.\n *\n * @author Yongjun Hong\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic final class Error implements MessageSourceResolvable {\n\n\tprivate final MessageSourceResolvable cause;\n\n\t/**\n\t * Create a new {@code Error} instance with the specified cause.\n\t * @param cause the error cause (must not be {@code null})\n\t */\n\tprivate Error(MessageSourceResolvable cause) {\n\t\tAssert.notNull(cause, \"'cause' must not be null\");\n\t\tthis.cause = cause;\n\t}\n\n\t@Override\n\tpublic String @Nullable [] getCodes() {\n\t\treturn this.cause.getCodes();\n\t}\n\n\t@Override\n\tpublic Object @Nullable [] getArguments() {\n\t\treturn this.cause.getArguments();\n\t}\n\n\t@Override\n\tpublic @Nullable String getDefaultMessage() {\n\t\treturn this.cause.getDefaultMessage();\n\t}\n\n\t/**\n\t * Return the original cause of the error.\n\t * @return the error cause\n\t */\n\t@JsonIgnore\n\tpublic MessageSourceResolvable getCause() {\n\t\treturn this.cause;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn Objects.equals(this.cause, ((Error) obj).cause);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.cause);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.cause.toString();\n\t}\n\n\t/**\n\t * Wrap the given errors, if necessary, such that they are suitable for serialization\n\t * to JSON. {@link MessageSourceResolvable} implementations that are known to be\n\t * suitable are not wrapped.\n\t * @param errors the errors to wrap\n\t * @return a new Error list\n\t * @since 3.5.4\n\t */\n\tpublic static List<MessageSourceResolvable> wrapIfNecessary(List<? extends MessageSourceResolvable> errors) {\n\t\tif (CollectionUtils.isEmpty(errors)) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<MessageSourceResolvable> result = new ArrayList<>(errors.size());\n\t\tfor (MessageSourceResolvable error : errors) {\n\t\t\tresult.add(requiresWrapping(error) ? new Error(error) : error);\n\t\t}\n\t\treturn List.copyOf(result);\n\t}\n\n\tprivate static boolean requiresWrapping(MessageSourceResolvable error) {\n\t\treturn !(error instanceof ObjectError);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/ErrorAttributeOptions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Options controlling the contents of {@code ErrorAttributes}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic final class ErrorAttributeOptions {\n\n\tprivate final Set<Include> includes;\n\n\tprivate ErrorAttributeOptions(Set<Include> includes) {\n\t\tthis.includes = includes;\n\t}\n\n\t/**\n\t * Get the option for including the specified attribute in the error response.\n\t * @param include error attribute to get\n\t * @return {@code true} if the {@code Include} attribute is included in the error\n\t * response, {@code false} otherwise\n\t */\n\tpublic boolean isIncluded(Include include) {\n\t\treturn this.includes.contains(include);\n\t}\n\n\t/**\n\t * Get all options for including attributes in the error response.\n\t * @return the options\n\t */\n\tpublic Set<Include> getIncludes() {\n\t\treturn this.includes;\n\t}\n\n\t/**\n\t * Return an {@code ErrorAttributeOptions} that includes the specified attribute\n\t * {@link Include} options.\n\t * @param includes error attributes to include\n\t * @return an {@code ErrorAttributeOptions}\n\t */\n\tpublic ErrorAttributeOptions including(Include... includes) {\n\t\tEnumSet<Include> updated = copyIncludes();\n\t\tupdated.addAll(Arrays.asList(includes));\n\t\treturn new ErrorAttributeOptions(Collections.unmodifiableSet(updated));\n\t}\n\n\t/**\n\t * Return an {@code ErrorAttributeOptions} that excludes the specified attribute\n\t * {@link Include} options.\n\t * @param excludes error attributes to exclude\n\t * @return an {@code ErrorAttributeOptions}\n\t */\n\tpublic ErrorAttributeOptions excluding(Include... excludes) {\n\t\tEnumSet<Include> updated = copyIncludes();\n\t\tArrays.stream(excludes).forEach(updated::remove);\n\t\treturn new ErrorAttributeOptions(Collections.unmodifiableSet(updated));\n\t}\n\n\t/**\n\t * Remove elements from the given map if they are not included in this set of options.\n\t * @param map the map to update\n\t * @since 3.2.7\n\t */\n\tpublic void retainIncluded(Map<String, @Nullable Object> map) {\n\t\tfor (Include candidate : Include.values()) {\n\t\t\tif (!this.includes.contains(candidate)) {\n\t\t\t\tmap.remove(candidate.key);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate EnumSet<Include> copyIncludes() {\n\t\treturn (this.includes.isEmpty()) ? EnumSet.noneOf(Include.class) : EnumSet.copyOf(this.includes);\n\t}\n\n\t/**\n\t * Create an {@code ErrorAttributeOptions} with defaults.\n\t * @return an {@code ErrorAttributeOptions}\n\t */\n\tpublic static ErrorAttributeOptions defaults() {\n\t\treturn of(Include.PATH, Include.STATUS, Include.ERROR);\n\t}\n\n\t/**\n\t * Create an {@code ErrorAttributeOptions} that includes the specified attribute\n\t * {@link Include} options.\n\t * @param includes error attributes to include\n\t * @return an {@code ErrorAttributeOptions}\n\t */\n\tpublic static ErrorAttributeOptions of(Include... includes) {\n\t\treturn of(Arrays.asList(includes));\n\t}\n\n\t/**\n\t * Create an {@code ErrorAttributeOptions} that includes the specified attribute\n\t * {@link Include} options.\n\t * @param includes error attributes to include\n\t * @return an {@code ErrorAttributeOptions}\n\t */\n\tpublic static ErrorAttributeOptions of(Collection<Include> includes) {\n\t\treturn new ErrorAttributeOptions(\n\t\t\t\t(includes.isEmpty()) ? Collections.emptySet() : Collections.unmodifiableSet(EnumSet.copyOf(includes)));\n\t}\n\n\t/**\n\t * Error attributes that can be included in an error response.\n\t */\n\tpublic enum Include {\n\n\t\t/**\n\t\t * Include the exception class name attribute.\n\t\t */\n\t\tEXCEPTION(\"exception\"),\n\n\t\t/**\n\t\t * Include the stack trace attribute.\n\t\t */\n\t\tSTACK_TRACE(\"trace\"),\n\n\t\t/**\n\t\t * Include the message attribute.\n\t\t */\n\t\tMESSAGE(\"message\"),\n\n\t\t/**\n\t\t * Include the binding errors attribute.\n\t\t */\n\t\tBINDING_ERRORS(\"errors\"),\n\n\t\t/**\n\t\t * Include the HTTP status code.\n\t\t * @since 3.2.7\n\t\t */\n\t\tSTATUS(\"status\"),\n\n\t\t/**\n\t\t * Include the HTTP status code.\n\t\t * @since 3.2.7\n\t\t */\n\t\tERROR(\"error\"),\n\n\t\t/**\n\t\t * Include the request path.\n\t\t * @since 3.3.0\n\t\t */\n\t\tPATH(\"path\");\n\n\t\tprivate final String key;\n\n\t\tInclude(String key) {\n\t\t\tthis.key = key;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/ErrorPage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Simple server-independent abstraction for error pages. Roughly equivalent to the\n * {@literal &lt;error-page&gt;} element traditionally found in web.xml.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\npublic class ErrorPage {\n\n\tprivate final @Nullable HttpStatus status;\n\n\tprivate final @Nullable Class<? extends Throwable> exception;\n\n\tprivate final String path;\n\n\tpublic ErrorPage(String path) {\n\t\tthis.status = null;\n\t\tthis.exception = null;\n\t\tthis.path = path;\n\t}\n\n\tpublic ErrorPage(HttpStatus status, String path) {\n\t\tthis.status = status;\n\t\tthis.exception = null;\n\t\tthis.path = path;\n\t}\n\n\tpublic ErrorPage(Class<? extends Throwable> exception, String path) {\n\t\tthis.status = null;\n\t\tthis.exception = exception;\n\t\tthis.path = path;\n\t}\n\n\t/**\n\t * The path to render (usually implemented as a forward), starting with \"/\". A custom\n\t * controller or servlet path can be used, or if the server supports it, a template\n\t * path (e.g. \"/error.jsp\").\n\t * @return the path that will be rendered for this error\n\t */\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\t/**\n\t * Returns the exception type (or {@code null} for a page that matches by status).\n\t * @return the exception type or {@code null}\n\t */\n\tpublic @Nullable Class<? extends Throwable> getException() {\n\t\treturn this.exception;\n\t}\n\n\t/**\n\t * The HTTP status value that this error page matches (or {@code null} for a page that\n\t * matches by exception).\n\t * @return the status or {@code null}\n\t */\n\tpublic @Nullable HttpStatus getStatus() {\n\t\treturn this.status;\n\t}\n\n\t/**\n\t * The HTTP status value that this error page matches.\n\t * @return the status value (or 0 for a page that matches any status)\n\t */\n\tpublic int getStatusCode() {\n\t\treturn (this.status != null) ? this.status.value() : 0;\n\t}\n\n\t/**\n\t * The exception type name.\n\t * @return the exception type name (or {@code null} if there is none)\n\t */\n\tpublic @Nullable String getExceptionName() {\n\t\treturn (this.exception != null) ? this.exception.getName() : null;\n\t}\n\n\t/**\n\t * Return if this error page is a global one (matches all unmatched status and\n\t * exception types).\n\t * @return if this is a global error page\n\t */\n\tpublic boolean isGlobal() {\n\t\treturn (this.status == null && this.exception == null);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof ErrorPage other) {\n\t\t\treturn ObjectUtils.nullSafeEquals(getExceptionName(), other.getExceptionName())\n\t\t\t\t\t&& ObjectUtils.nullSafeEquals(this.path, other.path) && this.status == other.status;\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(getExceptionName());\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.path);\n\t\tresult = prime * result + getStatusCode();\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/ErrorPageRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\n/**\n * Interface to be implemented by types that register {@link ErrorPage ErrorPages}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ErrorPageRegistrar {\n\n\t/**\n\t * Register pages as required with the given registry.\n\t * @param registry the error page registry\n\t */\n\tvoid registerErrorPages(ErrorPageRegistry registry);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/ErrorPageRegistrarBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link BeanPostProcessor} that applies all {@link ErrorPageRegistrar}s from the bean\n * factory to {@link ErrorPageRegistry} beans.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class ErrorPageRegistrarBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ListableBeanFactory beanFactory;\n\n\tprivate @Nullable List<ErrorPageRegistrar> registrars;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) {\n\t\tAssert.isInstanceOf(ListableBeanFactory.class, beanFactory, \"'beanFactory' must be a ListableBeanFactory\");\n\t\tthis.beanFactory = (ListableBeanFactory) beanFactory;\n\t}\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof ErrorPageRegistry errorPageRegistry) {\n\t\t\tpostProcessBeforeInitialization(errorPageRegistry);\n\t\t}\n\t\treturn bean;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\treturn bean;\n\t}\n\n\tprivate void postProcessBeforeInitialization(ErrorPageRegistry registry) {\n\t\tfor (ErrorPageRegistrar registrar : getRegistrars()) {\n\t\t\tregistrar.registerErrorPages(registry);\n\t\t}\n\t}\n\n\tprivate Collection<ErrorPageRegistrar> getRegistrars() {\n\t\tif (this.registrars == null) {\n\t\t\t// Look up does not include the parent context\n\t\t\tthis.registrars = new ArrayList<>(\n\t\t\t\t\tthis.beanFactory.getBeansOfType(ErrorPageRegistrar.class, false, false).values());\n\t\t\tthis.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);\n\t\t\tthis.registrars = Collections.unmodifiableList(this.registrars);\n\t\t}\n\t\treturn this.registrars;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/ErrorPageRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\n/**\n * Interface for a registry that holds {@link ErrorPage ErrorPages}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ErrorPageRegistry {\n\n\t/**\n\t * Adds error pages that will be used when handling exceptions.\n\t * @param errorPages the error pages\n\t */\n\tvoid addErrorPages(ErrorPage... errorPages);\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/error/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Web error handling infrastructure.\n */\n@NullMarked\npackage org.springframework.boot.web.error;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterRegistration;\nimport jakarta.servlet.FilterRegistration.Dynamic;\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\n/**\n * Abstract base {@link ServletContextInitializer} to register {@link Filter}s in a\n * Servlet 3.0+ container.\n *\n * @param <T> the type of {@link Filter} to register\n * @author Phillip Webb\n * @author Brian Clozel\n * @since 1.5.22\n */\npublic abstract class AbstractFilterRegistrationBean<T extends Filter> extends DynamicRegistrationBean<Dynamic> {\n\n\tprivate static final String[] DEFAULT_URL_MAPPINGS = { \"/*\" };\n\n\tprivate Set<ServletRegistrationBean<?>> servletRegistrationBeans = new LinkedHashSet<>();\n\n\tprivate Set<String> servletNames = new LinkedHashSet<>();\n\n\tprivate Set<String> urlPatterns = new LinkedHashSet<>();\n\n\tprivate @Nullable EnumSet<DispatcherType> dispatcherTypes;\n\n\tprivate boolean matchAfter;\n\n\t/**\n\t * Create a new instance to be registered with the specified\n\t * {@link ServletRegistrationBean}s.\n\t * @param servletRegistrationBeans associate {@link ServletRegistrationBean}s\n\t */\n\tAbstractFilterRegistrationBean(ServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\tAssert.notNull(servletRegistrationBeans, \"'servletRegistrationBeans' must not be null\");\n\t\tCollections.addAll(this.servletRegistrationBeans, servletRegistrationBeans);\n\t}\n\n\t/**\n\t * Set {@link ServletRegistrationBean}s that the filter will be registered against.\n\t * @param servletRegistrationBeans the Servlet registration beans\n\t */\n\tpublic void setServletRegistrationBeans(Collection<? extends ServletRegistrationBean<?>> servletRegistrationBeans) {\n\t\tAssert.notNull(servletRegistrationBeans, \"'servletRegistrationBeans' must not be null\");\n\t\tthis.servletRegistrationBeans = new LinkedHashSet<>(servletRegistrationBeans);\n\t}\n\n\t/**\n\t * Return a mutable collection of the {@link ServletRegistrationBean} that the filter\n\t * will be registered against. {@link ServletRegistrationBean}s.\n\t * @return the Servlet registration beans\n\t * @see #setServletNames\n\t * @see #setUrlPatterns\n\t */\n\tpublic Collection<ServletRegistrationBean<?>> getServletRegistrationBeans() {\n\t\treturn this.servletRegistrationBeans;\n\t}\n\n\t/**\n\t * Add {@link ServletRegistrationBean}s for the filter.\n\t * @param servletRegistrationBeans the servlet registration beans to add\n\t * @see #setServletRegistrationBeans\n\t */\n\tpublic void addServletRegistrationBeans(ServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\tAssert.notNull(servletRegistrationBeans, \"'servletRegistrationBeans' must not be null\");\n\t\tCollections.addAll(this.servletRegistrationBeans, servletRegistrationBeans);\n\t}\n\n\t/**\n\t * Set servlet names that the filter will be registered against. This will replace any\n\t * previously specified servlet names.\n\t * @param servletNames the servlet names\n\t * @see #setServletRegistrationBeans\n\t * @see #setUrlPatterns\n\t */\n\tpublic void setServletNames(Collection<String> servletNames) {\n\t\tAssert.notNull(servletNames, \"'servletNames' must not be null\");\n\t\tthis.servletNames = new LinkedHashSet<>(servletNames);\n\t}\n\n\t/**\n\t * Return a mutable collection of servlet names that the filter will be registered\n\t * against.\n\t * @return the servlet names\n\t */\n\tpublic Collection<String> getServletNames() {\n\t\treturn this.servletNames;\n\t}\n\n\t/**\n\t * Add servlet names for the filter.\n\t * @param servletNames the servlet names to add\n\t */\n\tpublic void addServletNames(String... servletNames) {\n\t\tAssert.notNull(servletNames, \"'servletNames' must not be null\");\n\t\tthis.servletNames.addAll(Arrays.asList(servletNames));\n\t}\n\n\t/**\n\t * Set the URL patterns that the filter will be registered against. This will replace\n\t * any previously specified URL patterns.\n\t * @param urlPatterns the URL patterns\n\t * @see #setServletRegistrationBeans\n\t * @see #setServletNames\n\t */\n\tpublic void setUrlPatterns(Collection<String> urlPatterns) {\n\t\tAssert.notNull(urlPatterns, \"'urlPatterns' must not be null\");\n\t\tthis.urlPatterns = new LinkedHashSet<>(urlPatterns);\n\t}\n\n\t/**\n\t * Return a mutable collection of URL patterns, as defined in the Servlet\n\t * specification, that the filter will be registered against.\n\t * @return the URL patterns\n\t */\n\tpublic Collection<String> getUrlPatterns() {\n\t\treturn this.urlPatterns;\n\t}\n\n\t/**\n\t * Add URL patterns, as defined in the Servlet specification, that the filter will be\n\t * registered against.\n\t * @param urlPatterns the URL patterns\n\t */\n\tpublic void addUrlPatterns(String... urlPatterns) {\n\t\tAssert.notNull(urlPatterns, \"'urlPatterns' must not be null\");\n\t\tCollections.addAll(this.urlPatterns, urlPatterns);\n\t}\n\n\t/**\n\t * Determines the {@link DispatcherType dispatcher types} for which the filter should\n\t * be registered. Applies defaults based on the type of filter being registered if\n\t * none have been configured. Modifications to the returned {@link EnumSet} will have\n\t * no effect on the registration.\n\t * @return the dispatcher types, never {@code null}\n\t * @since 3.2.0\n\t */\n\tpublic EnumSet<DispatcherType> determineDispatcherTypes() {\n\t\tif (CollectionUtils.isEmpty(this.dispatcherTypes)) {\n\t\t\tT filter = getFilter();\n\t\t\tAssert.state(filter != null, \"'filter' must not be null\");\n\t\t\tif (ClassUtils.isPresent(\"org.springframework.web.filter.OncePerRequestFilter\",\n\t\t\t\t\tfilter.getClass().getClassLoader()) && filter instanceof OncePerRequestFilter) {\n\t\t\t\treturn EnumSet.allOf(DispatcherType.class);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn EnumSet.of(DispatcherType.REQUEST);\n\t\t\t}\n\t\t}\n\t\treturn EnumSet.copyOf(this.dispatcherTypes);\n\t}\n\n\t/**\n\t * Convenience method to {@link #setDispatcherTypes(EnumSet) set dispatcher types}\n\t * using the specified elements.\n\t * @param first the first dispatcher type\n\t * @param rest additional dispatcher types\n\t */\n\tpublic void setDispatcherTypes(DispatcherType first, DispatcherType... rest) {\n\t\tthis.dispatcherTypes = EnumSet.of(first, rest);\n\t}\n\n\t/**\n\t * Sets the dispatcher types that should be used with the registration.\n\t * @param dispatcherTypes the dispatcher types\n\t */\n\tpublic void setDispatcherTypes(@Nullable EnumSet<DispatcherType> dispatcherTypes) {\n\t\tthis.dispatcherTypes = dispatcherTypes;\n\t}\n\n\t/**\n\t * Set if the filter mappings should be matched after any declared filter mappings of\n\t * the ServletContext. Defaults to {@code false} indicating the filters are supposed\n\t * to be matched before any declared filter mappings of the ServletContext.\n\t * @param matchAfter if filter mappings are matched after\n\t */\n\tpublic void setMatchAfter(boolean matchAfter) {\n\t\tthis.matchAfter = matchAfter;\n\t}\n\n\t/**\n\t * Return if filter mappings should be matched after any declared Filter mappings of\n\t * the ServletContext.\n\t * @return if filter mappings are matched after\n\t */\n\tpublic boolean isMatchAfter() {\n\t\treturn this.matchAfter;\n\t}\n\n\t@Override\n\tprotected String getDescription() {\n\t\tFilter filter = getFilter();\n\t\tAssert.notNull(filter, \"'filter' must not be null\");\n\t\treturn \"filter \" + getOrDeduceName(filter);\n\t}\n\n\t@Override\n\tprotected Dynamic addRegistration(String description, ServletContext servletContext) {\n\t\tFilter filter = getFilter();\n\t\treturn servletContext.addFilter(getOrDeduceName(filter), filter);\n\t}\n\n\t/**\n\t * Configure registration settings. Subclasses can override this method to perform\n\t * additional configuration if required.\n\t * @param registration the registration\n\t */\n\t@Override\n\tprotected void configure(FilterRegistration.Dynamic registration) {\n\t\tsuper.configure(registration);\n\t\tEnumSet<DispatcherType> dispatcherTypes = determineDispatcherTypes();\n\t\tSet<String> servletNames = new LinkedHashSet<>();\n\t\tfor (ServletRegistrationBean<?> servletRegistrationBean : this.servletRegistrationBeans) {\n\t\t\tservletNames.add(servletRegistrationBean.getServletName());\n\t\t}\n\t\tservletNames.addAll(this.servletNames);\n\t\tif (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {\n\t\t\tregistration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, DEFAULT_URL_MAPPINGS);\n\t\t}\n\t\telse {\n\t\t\tif (!servletNames.isEmpty()) {\n\t\t\t\tregistration.addMappingForServletNames(dispatcherTypes, this.matchAfter,\n\t\t\t\t\t\tStringUtils.toStringArray(servletNames));\n\t\t\t}\n\t\t\tif (!this.urlPatterns.isEmpty()) {\n\t\t\t\tregistration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,\n\t\t\t\t\t\tStringUtils.toStringArray(this.urlPatterns));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Return the {@link Filter} to be registered.\n\t * @return the filter\n\t */\n\tpublic abstract @Nullable T getFilter();\n\n\t/**\n\t * Returns the filter name that will be registered.\n\t * @return the filter name\n\t * @since 3.2.0\n\t */\n\tpublic String getFilterName() {\n\t\treturn getOrDeduceName(getFilter());\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder builder = new StringBuilder(getOrDeduceName(this));\n\t\tif (this.servletNames.isEmpty() && this.urlPatterns.isEmpty()) {\n\t\t\tbuilder.append(\" urls=\").append(Arrays.toString(DEFAULT_URL_MAPPINGS));\n\t\t}\n\t\telse {\n\t\t\tif (!this.servletNames.isEmpty()) {\n\t\t\t\tbuilder.append(\" servlets=\").append(this.servletNames);\n\t\t\t}\n\t\t\tif (!this.urlPatterns.isEmpty()) {\n\t\t\t\tbuilder.append(\" urls=\").append(this.urlPatterns);\n\t\t\t}\n\t\t}\n\t\tbuilder.append(\" order=\").append(getOrder());\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/DelegatingFilterProxyRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.filter.DelegatingFilterProxy;\n\n/**\n * A {@link ServletContextInitializer} to register {@link DelegatingFilterProxy}s in a\n * Servlet 3.0+ container. Similar to the {@link ServletContext#addFilter(String, Filter)\n * registration} features provided by {@link ServletContext} but with a Spring Bean\n * friendly design.\n * <p>\n * The bean name of the actual delegate {@link Filter} should be specified using the\n * {@code targetBeanName} constructor argument. Unlike the {@link FilterRegistrationBean},\n * referenced filters are not instantiated early. In fact, if the delegate filter bean is\n * marked {@code @Lazy} it won't be instantiated at all until the filter is called.\n * <p>\n * Registrations can be associated with {@link #setUrlPatterns URL patterns} and/or\n * servlets (either by {@link #setServletNames name} or through a\n * {@link #setServletRegistrationBeans ServletRegistrationBean}s). When no URL pattern or\n * servlets are specified the filter will be associated to '/*'. The targetBeanName will\n * be used as the filter name if not otherwise specified.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see ServletContextInitializer\n * @see ServletContext#addFilter(String, Filter)\n * @see FilterRegistrationBean\n * @see DelegatingFilterProxy\n */\npublic class DelegatingFilterProxyRegistrationBean extends AbstractFilterRegistrationBean<DelegatingFilterProxy>\n\t\timplements ApplicationContextAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext applicationContext;\n\n\tprivate final String targetBeanName;\n\n\t/**\n\t * Create a new {@link DelegatingFilterProxyRegistrationBean} instance to be\n\t * registered with the specified {@link ServletRegistrationBean}s.\n\t * @param targetBeanName name of the target filter bean to look up in the Spring\n\t * application context (must not be {@code null}).\n\t * @param servletRegistrationBeans associate {@link ServletRegistrationBean}s\n\t */\n\tpublic DelegatingFilterProxyRegistrationBean(String targetBeanName,\n\t\t\tServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\tsuper(servletRegistrationBeans);\n\t\tAssert.hasLength(targetBeanName, \"'targetBeanName' must not be empty\");\n\t\tthis.targetBeanName = targetBeanName;\n\t\tsetName(targetBeanName);\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\tprotected String getTargetBeanName() {\n\t\treturn this.targetBeanName;\n\t}\n\n\t@Override\n\tpublic DelegatingFilterProxy getFilter() {\n\t\treturn new DelegatingFilterProxy(this.targetBeanName, getWebApplicationContext()) {\n\n\t\t\t@Override\n\t\t\tprotected void initFilterBean() throws ServletException {\n\t\t\t\t// Don't initialize filter bean on init()\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate WebApplicationContext getWebApplicationContext() {\n\t\tAssert.state(this.applicationContext != null, \"ApplicationContext has not been injected\");\n\t\tAssert.state(this.applicationContext instanceof WebApplicationContext,\n\t\t\t\t\"Injected ApplicationContext is not a WebApplicationContext\");\n\t\treturn (WebApplicationContext) this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/DispatcherType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\n/**\n * Enumeration of filter dispatcher types, identical to\n * {@link jakarta.servlet.DispatcherType} and used in configuration as the servlet API may\n * not be present.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic enum DispatcherType {\n\n\t/**\n\t * Apply the filter on \"RequestDispatcher.forward()\" calls.\n\t */\n\tFORWARD,\n\n\t/**\n\t * Apply the filter on \"RequestDispatcher.include()\" calls.\n\t */\n\tINCLUDE,\n\n\t/**\n\t * Apply the filter on ordinary client calls.\n\t */\n\tREQUEST,\n\n\t/**\n\t * Apply the filter under calls dispatched from an AsyncContext.\n\t */\n\tASYNC,\n\n\t/**\n\t * Apply the filter when an error is handled.\n\t */\n\tERROR\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/DynamicRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport jakarta.servlet.Registration;\nimport jakarta.servlet.ServletContext;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanNameAware;\nimport org.springframework.core.Conventions;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for Servlet 3.0+ {@link jakarta.servlet.Registration.Dynamic dynamic} based\n * registration beans.\n *\n * @param <D> the dynamic registration result\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 2.0.0\n */\npublic abstract class DynamicRegistrationBean<D extends Registration.Dynamic> extends RegistrationBean\n\t\timplements BeanNameAware {\n\n\tprivate static final Log logger = LogFactory.getLog(RegistrationBean.class);\n\n\tprivate @Nullable String name;\n\n\tprivate boolean asyncSupported = true;\n\n\tprivate Map<String, String> initParameters = new LinkedHashMap<>();\n\n\tprivate @Nullable String beanName;\n\n\tprivate boolean ignoreRegistrationFailure;\n\n\t/**\n\t * Set the name of this registration. If not specified the bean name will be used.\n\t * @param name the name of the registration\n\t */\n\tpublic void setName(String name) {\n\t\tAssert.hasLength(name, \"'name' must not be empty\");\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * Sets if asynchronous operations are supported for this registration. If not\n\t * specified defaults to {@code true}.\n\t * @param asyncSupported if async is supported\n\t */\n\tpublic void setAsyncSupported(boolean asyncSupported) {\n\t\tthis.asyncSupported = asyncSupported;\n\t}\n\n\t/**\n\t * Returns if asynchronous operations are supported for this registration.\n\t * @return if async is supported\n\t */\n\tpublic boolean isAsyncSupported() {\n\t\treturn this.asyncSupported;\n\t}\n\n\t/**\n\t * Set init-parameters for this registration. Calling this method will replace any\n\t * existing init-parameters.\n\t * @param initParameters the init parameters\n\t * @see #getInitParameters\n\t * @see #addInitParameter\n\t */\n\tpublic void setInitParameters(Map<String, String> initParameters) {\n\t\tAssert.notNull(initParameters, \"'initParameters' must not be null\");\n\t\tthis.initParameters = new LinkedHashMap<>(initParameters);\n\t}\n\n\t/**\n\t * Returns a mutable Map of the registration init-parameters.\n\t * @return the init parameters\n\t */\n\tpublic Map<String, String> getInitParameters() {\n\t\treturn this.initParameters;\n\t}\n\n\t/**\n\t * Add a single init-parameter, replacing any existing parameter with the same name.\n\t * @param name the init-parameter name\n\t * @param value the init-parameter value\n\t */\n\tpublic void addInitParameter(String name, String value) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.initParameters.put(name, value);\n\t}\n\n\t@Override\n\tprotected final void register(String description, ServletContext servletContext) {\n\t\tD registration = addRegistration(description, servletContext);\n\t\tif (registration == null) {\n\t\t\tif (this.ignoreRegistrationFailure) {\n\t\t\t\tlogger.info(StringUtils.capitalize(description) + \" was not registered (possibly already registered?)\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Failed to register '%s' on the servlet context. Possibly already registered?\"\n\t\t\t\t\t\t.formatted(description));\n\t\t}\n\t\tconfigure(registration);\n\t}\n\n\t/**\n\t * Sets whether registration failures should be ignored. If set to true, a failure\n\t * will be logged. If set to false, an {@link IllegalStateException} will be thrown.\n\t * @param ignoreRegistrationFailure whether to ignore registration failures\n\t * @since 3.1.0\n\t */\n\tpublic void setIgnoreRegistrationFailure(boolean ignoreRegistrationFailure) {\n\t\tthis.ignoreRegistrationFailure = ignoreRegistrationFailure;\n\t}\n\n\t@Override\n\tpublic void setBeanName(String name) {\n\t\tthis.beanName = name;\n\t}\n\n\tprotected abstract @Nullable D addRegistration(String description, ServletContext servletContext);\n\n\tprotected void configure(D registration) {\n\t\tregistration.setAsyncSupported(this.asyncSupported);\n\t\tif (!this.initParameters.isEmpty()) {\n\t\t\tregistration.setInitParameters(this.initParameters);\n\t\t}\n\t}\n\n\t/**\n\t * Deduces the name for this registration. Will return user specified name or fallback\n\t * to the bean name. If the bean name is not available, convention based naming is\n\t * used.\n\t * @param value the object used for convention based names\n\t * @return the deduced name\n\t */\n\tprotected final String getOrDeduceName(@Nullable Object value) {\n\t\tif (this.name != null) {\n\t\t\treturn this.name;\n\t\t}\n\t\tif (this.beanName != null) {\n\t\t\treturn this.beanName;\n\t\t}\n\t\tif (value == null) {\n\t\t\treturn \"null\";\n\t\t}\n\t\treturn Conventions.getVariableName(value);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/FilterRegistration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.annotation.WebInitParam;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Registers a {@link Filter} in a Servlet 3.0+ container. Can be used as an\n * annotation-based alternative to {@link FilterRegistrationBean}.\n *\n * @author Moritz Halbritter\n * @author Daeho Kwon\n * @since 3.5.0\n * @see FilterRegistrationBean\n */\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Order\npublic @interface FilterRegistration {\n\n\t/**\n\t * Whether this registration is enabled.\n\t * @return whether this registration is enabled\n\t */\n\tboolean enabled() default true;\n\n\t/**\n\t * Order of the registration bean.\n\t * @return the order of the registration bean\n\t */\n\t@AliasFor(annotation = Order.class, attribute = \"value\")\n\tint order() default Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Name of this registration. If not specified the bean name will be used.\n\t * @return the name\n\t */\n\tString name() default \"\";\n\n\t/**\n\t * Whether asynchronous operations are supported for this registration.\n\t * @return whether asynchronous operations are supported\n\t */\n\tboolean asyncSupported() default true;\n\n\t/**\n\t * Dispatcher types that should be used with the registration.\n\t * @return the dispatcher types\n\t */\n\tDispatcherType[] dispatcherTypes() default {};\n\n\t/**\n\t * Whether registration failures should be ignored. If set to true, a failure will be\n\t * logged. If set to false, an {@link IllegalStateException} will be thrown.\n\t * @return whether registration failures should be ignored\n\t */\n\tboolean ignoreRegistrationFailure() default false;\n\n\t/**\n\t * Init parameters to be used with the filter.\n\t * @return the init parameters\n\t */\n\tWebInitParam[] initParameters() default {};\n\n\t/**\n\t * Whether the filter mappings should be matched after any declared Filter mappings of\n\t * the ServletContext.\n\t * @return whether the filter mappings should be matched after any declared Filter\n\t * mappings of the ServletContext\n\t */\n\tboolean matchAfter() default false;\n\n\t/**\n\t * Servlet names that the filter will be registered against.\n\t * @return the servlet names\n\t */\n\tString[] servletNames() default {};\n\n\t/**\n\t * Servlet classes that the filter will be registered against.\n\t * @return the servlet classes\n\t */\n\tClass<?>[] servletClasses() default {};\n\n\t/**\n\t * URL patterns, as defined in the Servlet specification, that the filter will be\n\t * registered against.\n\t * @return the url patterns\n\t */\n\tString[] urlPatterns() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/FilterRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A {@link ServletContextInitializer} to register {@link Filter}s in a Servlet 3.0+\n * container. Similar to the {@link ServletContext#addFilter(String, Filter) registration}\n * features provided by {@link ServletContext} but with a Spring Bean friendly design.\n * <p>\n * The {@link #setFilter(Filter) Filter} must be specified before calling\n * {@link #onStartup(ServletContext)}. Registrations can be associated with\n * {@link #setUrlPatterns URL patterns} and/or servlets (either by {@link #setServletNames\n * name} or through a {@link #setServletRegistrationBeans ServletRegistrationBean}s). When\n * no URL pattern or servlets are specified the filter will be associated to '/*'. The\n * filter name will be deduced if not specified.\n *\n * @param <T> the type of {@link Filter} to register\n * @author Phillip Webb\n * @since 1.4.0\n * @see ServletContextInitializer\n * @see ServletContext#addFilter(String, Filter)\n * @see DelegatingFilterProxyRegistrationBean\n * @see FilterRegistration\n */\npublic class FilterRegistrationBean<T extends Filter> extends AbstractFilterRegistrationBean<T> {\n\n\tprivate @Nullable T filter;\n\n\t/**\n\t * Create a new {@link FilterRegistrationBean} instance.\n\t */\n\tpublic FilterRegistrationBean() {\n\t}\n\n\t/**\n\t * Create a new {@link FilterRegistrationBean} instance to be registered with the\n\t * specified {@link ServletRegistrationBean}s.\n\t * @param filter the filter to register\n\t * @param servletRegistrationBeans associate {@link ServletRegistrationBean}s\n\t */\n\tpublic FilterRegistrationBean(T filter, ServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\tsuper(servletRegistrationBeans);\n\t\tAssert.notNull(filter, \"'filter' must not be null\");\n\t\tthis.filter = filter;\n\t}\n\n\t@Override\n\tpublic @Nullable T getFilter() {\n\t\treturn this.filter;\n\t}\n\n\t/**\n\t * Set the filter to be registered.\n\t * @param filter the filter\n\t */\n\tpublic void setFilter(T filter) {\n\t\tAssert.notNull(filter, \"'filter' must not be null\");\n\t\tthis.filter = filter;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/RegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for Servlet 3.0+ based registration beans.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see ServletRegistrationBean\n * @see FilterRegistrationBean\n * @see DelegatingFilterProxyRegistrationBean\n * @see ServletListenerRegistrationBean\n */\npublic abstract class RegistrationBean implements ServletContextInitializer, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(RegistrationBean.class);\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate boolean enabled = true;\n\n\t@Override\n\tpublic final void onStartup(ServletContext servletContext) throws ServletException {\n\t\tString description = getDescription();\n\t\tif (!isEnabled()) {\n\t\t\tlogger.info(StringUtils.capitalize(description) + \" was not registered (disabled)\");\n\t\t\treturn;\n\t\t}\n\t\tregister(description, servletContext);\n\t}\n\n\t/**\n\t * Return a description of the registration. For example \"Servlet resourceServlet\"\n\t * @return a description of the registration\n\t */\n\tprotected abstract String getDescription();\n\n\t/**\n\t * Register this bean with the servlet context.\n\t * @param description a description of the item being registered\n\t * @param servletContext the servlet context\n\t */\n\tprotected abstract void register(String description, ServletContext servletContext);\n\n\t/**\n\t * Flag to indicate that the registration is enabled.\n\t * @param enabled the enabled to set\n\t */\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * Return if the registration is enabled.\n\t * @return if enabled (default {@code true})\n\t */\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\t/**\n\t * Set the order of the registration bean.\n\t * @param order the order\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t/**\n\t * Get the order of the registration bean.\n\t * @return the order\n\t */\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.ServletContainerInitializer;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\n\nimport org.springframework.web.SpringServletContainerInitializer;\nimport org.springframework.web.WebApplicationInitializer;\n\n/**\n * Interface used to configure a Servlet 3.0+ {@link ServletContext context}\n * programmatically. Unlike {@link WebApplicationInitializer}, classes that implement this\n * interface (and do not implement {@link WebApplicationInitializer}) will <b>not</b> be\n * detected by {@link SpringServletContainerInitializer} and hence will not be\n * automatically bootstrapped by the Servlet container.\n * <p>\n * This interface is designed to act in a similar way to\n * {@link ServletContainerInitializer}, but have a lifecycle that's managed by Spring and\n * not the Servlet container.\n * <p>\n * For configuration examples see {@link WebApplicationInitializer}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see WebApplicationInitializer\n */\n@FunctionalInterface\npublic interface ServletContextInitializer {\n\n\t/**\n\t * Configure the given {@link ServletContext} with any servlets, filters, listeners\n\t * context-params and attributes necessary for initialization.\n\t * @param servletContext the {@code ServletContext} to initialize\n\t * @throws ServletException if any call against the given {@code ServletContext}\n\t * throws a {@code ServletException}\n\t */\n\tvoid onStartup(ServletContext servletContext) throws ServletException;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletContextInitializerBeans.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.AbstractCollection;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.EventListener;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.annotation.WebInitParam;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.Assert;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * A collection {@link ServletContextInitializer}s obtained from a\n * {@link ListableBeanFactory}. Includes all {@link ServletContextInitializer} beans and\n * also adapts {@link Servlet}, {@link Filter} and certain {@link EventListener} beans.\n * <p>\n * Items are sorted so that adapted beans are top ({@link Servlet}, {@link Filter} then\n * {@link EventListener}) and direct {@link ServletContextInitializer} beans are at the\n * end. Further sorting is applied within these groups using the\n * {@link AnnotationAwareOrderComparator}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Brian Clozel\n * @author Moritz Halbritter\n * @author Daeho Kwon\n * @author Dmytro Danilenkov\n * @since 1.4.0\n */\npublic class ServletContextInitializerBeans extends AbstractCollection<ServletContextInitializer> {\n\n\tprivate static final String DISPATCHER_SERVLET_NAME = \"dispatcherServlet\";\n\n\tprivate static final Log logger = LogFactory.getLog(ServletContextInitializerBeans.class);\n\n\t/**\n\t * Seen bean instances or bean names.\n\t */\n\tprivate final Seen seen = new Seen();\n\n\tprivate final MultiValueMap<Class<?>, ServletContextInitializer> initializers;\n\n\tprivate final List<Class<? extends ServletContextInitializer>> initializerTypes;\n\n\tprivate final List<ServletContextInitializer> sortedList;\n\n\t@SafeVarargs\n\t@SuppressWarnings(\"varargs\")\n\tpublic ServletContextInitializerBeans(ListableBeanFactory beanFactory,\n\t\t\tClass<? extends ServletContextInitializer>... initializerTypes) {\n\t\tthis.initializers = new LinkedMultiValueMap<>();\n\t\tthis.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)\n\t\t\t\t: Collections.singletonList(ServletContextInitializer.class);\n\t\taddServletContextInitializerBeans(beanFactory);\n\t\taddAdaptableBeans(beanFactory);\n\t\tthis.sortedList = this.initializers.values()\n\t\t\t.stream()\n\t\t\t.flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))\n\t\t\t.toList();\n\t\tlogMappings(this.initializers);\n\t}\n\n\tprivate void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {\n\t\tfor (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {\n\t\t\tfor (Entry<String, ? extends ServletContextInitializer> initializerBean : getOrderedBeansOfType(beanFactory,\n\t\t\t\t\tinitializerType)) {\n\t\t\t\taddServletContextInitializerBean(initializerBean.getKey(), initializerBean.getValue(), beanFactory);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,\n\t\t\tListableBeanFactory beanFactory) {\n\t\tif (initializer instanceof ServletRegistrationBean<?> servletRegistrationBean) {\n\t\t\tServlet source = servletRegistrationBean.getServlet();\n\t\t\taddServletContextInitializerBean(Servlet.class, beanName, servletRegistrationBean, beanFactory, source);\n\t\t}\n\t\telse if (initializer instanceof FilterRegistrationBean<?> filterRegistrationBean) {\n\t\t\tFilter source = filterRegistrationBean.getFilter();\n\t\t\taddServletContextInitializerBean(Filter.class, beanName, filterRegistrationBean, beanFactory, source);\n\t\t}\n\t\telse if (initializer instanceof DelegatingFilterProxyRegistrationBean registrationBean) {\n\t\t\tString source = registrationBean.getTargetBeanName();\n\t\t\taddServletContextInitializerBean(Filter.class, beanName, registrationBean, beanFactory, source);\n\t\t}\n\t\telse if (initializer instanceof ServletListenerRegistrationBean<?> registrationBean) {\n\t\t\tEventListener source = registrationBean.getListener();\n\t\t\taddServletContextInitializerBean(EventListener.class, beanName, registrationBean, beanFactory, source);\n\t\t}\n\t\telse {\n\t\t\taddServletContextInitializerBean(ServletContextInitializer.class, beanName, initializer, beanFactory,\n\t\t\t\t\tinitializer);\n\t\t}\n\t}\n\n\tprivate void addServletContextInitializerBean(Class<?> type, String beanName, ServletContextInitializer initializer,\n\t\t\tListableBeanFactory beanFactory, @Nullable Object source) {\n\t\tthis.initializers.add(type, initializer);\n\t\tif (source != null) {\n\t\t\t// Mark the underlying source as seen in case it wraps an existing bean\n\t\t\tthis.seen.add(type, source);\n\t\t}\n\t\tif (logger.isTraceEnabled()) {\n\t\t\tString resourceDescription = getResourceDescription(beanName, beanFactory);\n\t\t\tint order = getOrder(initializer);\n\t\t\tlogger.trace(\"Added existing \" + type.getSimpleName() + \" initializer bean '\" + beanName + \"'; order=\"\n\t\t\t\t\t+ order + \", resource=\" + resourceDescription);\n\t\t}\n\t}\n\n\tprivate @Nullable String getResourceDescription(String beanName, ListableBeanFactory beanFactory) {\n\t\tif (beanFactory instanceof BeanDefinitionRegistry registry) {\n\t\t\treturn registry.getBeanDefinition(beanName).getResourceDescription();\n\t\t}\n\t\treturn \"unknown\";\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected void addAdaptableBeans(ListableBeanFactory beanFactory) {\n\t\tMultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);\n\t\taddAsRegistrationBean(beanFactory, Servlet.class,\n\t\t\t\tnew ServletRegistrationBeanAdapter(multipartConfig, beanFactory));\n\t\taddAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter(beanFactory));\n\t\tfor (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) {\n\t\t\taddAsRegistrationBean(beanFactory, EventListener.class, (Class<EventListener>) listenerType,\n\t\t\t\t\tnew ServletListenerRegistrationBeanAdapter());\n\t\t}\n\t}\n\n\tprivate @Nullable MultipartConfigElement getMultipartConfig(ListableBeanFactory beanFactory) {\n\t\tList<Entry<String, MultipartConfigElement>> beans = getOrderedBeansOfType(beanFactory,\n\t\t\t\tMultipartConfigElement.class);\n\t\treturn beans.isEmpty() ? null : beans.get(0).getValue();\n\t}\n\n\tprotected <T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,\n\t\t\tRegistrationBeanAdapter<T> adapter) {\n\t\taddAsRegistrationBean(beanFactory, type, type, adapter);\n\t}\n\n\tprivate <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, Class<T> type,\n\t\t\tClass<B> beanType, RegistrationBeanAdapter<T> adapter) {\n\t\tList<Map.Entry<String, B>> entries = getOrderedBeansOfType(beanFactory, beanType, this.seen);\n\t\tfor (Entry<String, B> entry : entries) {\n\t\t\tString beanName = entry.getKey();\n\t\t\tB bean = entry.getValue();\n\t\t\tif (this.seen.add(type, bean)) {\n\t\t\t\t// One that we haven't already seen\n\t\t\t\tRegistrationBean registration = adapter.createRegistrationBean(beanName, bean, entries.size());\n\t\t\t\tInteger order = findOrder(bean);\n\t\t\t\tif (order != null) {\n\t\t\t\t\tregistration.setOrder(order);\n\t\t\t\t}\n\t\t\t\tthis.initializers.add(type, registration);\n\t\t\t\tif (logger.isTraceEnabled()) {\n\t\t\t\t\tlogger.trace(\"Created \" + type.getSimpleName() + \" initializer for bean '\" + beanName + \"'; order=\"\n\t\t\t\t\t\t\t+ order + \", resource=\" + getResourceDescription(beanName, beanFactory));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate int getOrder(Object value) {\n\t\tInteger order = findOrder(value);\n\t\treturn (order != null) ? order : Ordered.LOWEST_PRECEDENCE;\n\t}\n\n\tprivate @Nullable Integer findOrder(Object value) {\n\t\treturn new AnnotationAwareOrderComparator() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Integer findOrder(Object obj) {\n\t\t\t\treturn super.findOrder(obj);\n\t\t\t}\n\n\t\t}.findOrder(value);\n\t}\n\n\tprivate <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type) {\n\t\treturn getOrderedBeansOfType(beanFactory, type, Seen.empty());\n\t}\n\n\tprivate <T> List<Entry<String, T>> getOrderedBeansOfType(ListableBeanFactory beanFactory, Class<T> type,\n\t\t\tSeen seen) {\n\t\tString[] names = beanFactory.getBeanNamesForType(type, true, false);\n\t\tMap<String, T> map = new LinkedHashMap<>();\n\t\tfor (String name : names) {\n\t\t\tif (!seen.contains(type, name) && !ScopedProxyUtils.isScopedTarget(name)) {\n\t\t\t\tT bean = beanFactory.getBean(name, type);\n\t\t\t\tif (!seen.contains(type, bean)) {\n\t\t\t\t\tmap.put(name, bean);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tList<Entry<String, T>> beans = new ArrayList<>(map.entrySet());\n\t\tbeans.sort((o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), o2.getValue()));\n\t\treturn beans;\n\t}\n\n\tprivate void logMappings(MultiValueMap<Class<?>, ServletContextInitializer> initializers) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogMappings(\"filters\", initializers, Filter.class, FilterRegistrationBean.class);\n\t\t\tlogMappings(\"servlets\", initializers, Servlet.class, ServletRegistrationBean.class);\n\t\t}\n\t}\n\n\tprivate void logMappings(String name, MultiValueMap<Class<?>, ServletContextInitializer> initializers,\n\t\t\tClass<?> type, Class<? extends RegistrationBean> registrationType) {\n\t\tList<ServletContextInitializer> registrations = new ArrayList<>();\n\t\tregistrations.addAll(initializers.getOrDefault(registrationType, Collections.emptyList()));\n\t\tregistrations.addAll(initializers.getOrDefault(type, Collections.emptyList()));\n\t\tString info = registrations.stream().map(Object::toString).collect(Collectors.joining(\", \"));\n\t\tlogger.debug(\"Mapping \" + name + \": \" + info);\n\t}\n\n\t@Override\n\tpublic Iterator<ServletContextInitializer> iterator() {\n\t\treturn this.sortedList.iterator();\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\treturn this.sortedList.size();\n\t}\n\n\t/**\n\t * Adapter to convert a given Bean type into a {@link RegistrationBean} (and hence a\n\t * {@link ServletContextInitializer}).\n\t *\n\t * @param <T> the type of the Bean to adapt\n\t */\n\t@FunctionalInterface\n\tprotected interface RegistrationBeanAdapter<T> {\n\n\t\tRegistrationBean createRegistrationBean(String beanName, T source, int totalNumberOfSourceBeans);\n\n\t}\n\n\t/**\n\t * {@link RegistrationBeanAdapter} for {@link Servlet} beans.\n\t */\n\tprivate static class ServletRegistrationBeanAdapter implements RegistrationBeanAdapter<Servlet> {\n\n\t\tprivate final @Nullable MultipartConfigElement multipartConfig;\n\n\t\tprivate final ListableBeanFactory beanFactory;\n\n\t\tServletRegistrationBeanAdapter(@Nullable MultipartConfigElement multipartConfig,\n\t\t\t\tListableBeanFactory beanFactory) {\n\t\t\tthis.multipartConfig = multipartConfig;\n\t\t\tthis.beanFactory = beanFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic RegistrationBean createRegistrationBean(String beanName, Servlet source, int totalNumberOfSourceBeans) {\n\t\t\tString url = (totalNumberOfSourceBeans != 1) ? \"/\" + beanName + \"/\" : \"/\";\n\t\t\tif (beanName.equals(DISPATCHER_SERVLET_NAME)) {\n\t\t\t\turl = \"/\"; // always map the main dispatcherServlet to \"/\"\n\t\t\t}\n\t\t\tServletRegistrationBean<Servlet> bean = new ServletRegistrationBean<>(source, url);\n\t\t\tbean.setName(beanName);\n\t\t\tbean.setMultipartConfig(this.multipartConfig);\n\t\t\tServletRegistration registrationAnnotation = this.beanFactory.findAnnotationOnBean(beanName,\n\t\t\t\t\tServletRegistration.class);\n\t\t\tif (registrationAnnotation != null) {\n\t\t\t\tOrder orderAnnotation = this.beanFactory.findAnnotationOnBean(beanName, Order.class);\n\t\t\t\tAssert.notNull(orderAnnotation, \"'orderAnnotation' must not be null\");\n\t\t\t\tconfigureFromAnnotation(bean, registrationAnnotation, orderAnnotation);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate void configureFromAnnotation(ServletRegistrationBean<Servlet> bean, ServletRegistration registration,\n\t\t\t\tOrder order) {\n\t\t\tbean.setEnabled(registration.enabled());\n\t\t\tbean.setOrder(order.value());\n\t\t\tif (StringUtils.hasText(registration.name())) {\n\t\t\t\tbean.setName(registration.name());\n\t\t\t}\n\t\t\tbean.setAsyncSupported(registration.asyncSupported());\n\t\t\tbean.setIgnoreRegistrationFailure(registration.ignoreRegistrationFailure());\n\t\t\tbean.setLoadOnStartup(registration.loadOnStartup());\n\t\t\tbean.setUrlMappings(Arrays.asList(registration.urlMappings()));\n\t\t\tfor (WebInitParam param : registration.initParameters()) {\n\t\t\t\tbean.addInitParameter(param.name(), param.value());\n\t\t\t}\n\t\t\tbean.setMultipartConfig(new MultipartConfigElement(registration.multipartConfig()));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link RegistrationBeanAdapter} implementation for {@link Filter} beans.\n\t * <p>\n\t * <b>NOTE:</b> A similar implementation is used in\n\t * {@code SpringBootMockMvcBuilderCustomizer} for registering\n\t * {@code @FilterRegistration} beans with {@code @MockMvc}. If you modify this class,\n\t * please also update {@code SpringBootMockMvcBuilderCustomizer} if needed.\n\t * </p>\n\t */\n\tprivate static class FilterRegistrationBeanAdapter implements RegistrationBeanAdapter<Filter> {\n\n\t\tprivate final ListableBeanFactory beanFactory;\n\n\t\tFilterRegistrationBeanAdapter(ListableBeanFactory beanFactory) {\n\t\t\tthis.beanFactory = beanFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic RegistrationBean createRegistrationBean(String beanName, Filter source, int totalNumberOfSourceBeans) {\n\t\t\tFilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(source);\n\t\t\tbean.setName(beanName);\n\t\t\tFilterRegistration registrationAnnotation = this.beanFactory.findAnnotationOnBean(beanName,\n\t\t\t\t\tFilterRegistration.class);\n\t\t\tif (registrationAnnotation != null) {\n\t\t\t\tOrder orderAnnotation = this.beanFactory.findAnnotationOnBean(beanName, Order.class);\n\t\t\t\tAssert.notNull(orderAnnotation, \"'orderAnnotation' must not be null\");\n\t\t\t\tconfigureFromAnnotation(bean, registrationAnnotation, orderAnnotation);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate void configureFromAnnotation(FilterRegistrationBean<Filter> bean, FilterRegistration registration,\n\t\t\t\tOrder order) {\n\t\t\tbean.setEnabled(registration.enabled());\n\t\t\tbean.setOrder(order.value());\n\t\t\tif (StringUtils.hasText(registration.name())) {\n\t\t\t\tbean.setName(registration.name());\n\t\t\t}\n\t\t\tbean.setAsyncSupported(registration.asyncSupported());\n\t\t\tif (registration.dispatcherTypes().length > 0) {\n\t\t\t\tbean.setDispatcherTypes(EnumSet.copyOf(Arrays.asList(registration.dispatcherTypes())));\n\t\t\t}\n\t\t\tbean.setIgnoreRegistrationFailure(registration.ignoreRegistrationFailure());\n\t\t\tbean.setMatchAfter(registration.matchAfter());\n\t\t\tbean.setServletNames(Arrays.asList(registration.servletNames()));\n\t\t\tbean.setUrlPatterns(Arrays.asList(registration.urlPatterns()));\n\t\t\tfor (WebInitParam param : registration.initParameters()) {\n\t\t\t\tbean.addInitParameter(param.name(), param.value());\n\t\t\t}\n\t\t\tthis.beanFactory.getBeanProvider(ServletRegistrationBean.class).forEach((servletRegistrationBean) -> {\n\t\t\t\tfor (Class<?> servletClass : registration.servletClasses()) {\n\t\t\t\t\tif (servletClass.isInstance(servletRegistrationBean.getServlet())) {\n\t\t\t\t\t\tbean.addServletRegistrationBeans(servletRegistrationBean);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link RegistrationBeanAdapter} for certain {@link EventListener} beans.\n\t */\n\tprivate static final class ServletListenerRegistrationBeanAdapter\n\t\t\timplements RegistrationBeanAdapter<EventListener> {\n\n\t\t@Override\n\t\tpublic RegistrationBean createRegistrationBean(String beanName, EventListener source,\n\t\t\t\tint totalNumberOfSourceBeans) {\n\t\t\treturn new ServletListenerRegistrationBean<>(source);\n\t\t}\n\n\t}\n\n\t/**\n\t * Tracks seen initializers.\n\t */\n\tprivate static final class Seen {\n\n\t\tprivate final Map<Class<?>, Set<Object>> seen = new HashMap<>();\n\n\t\tboolean add(Class<?> type, Object object) {\n\t\t\tif (contains(type, object)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.seen.computeIfAbsent(type, (ignore) -> new HashSet<>()).add(object);\n\t\t}\n\n\t\tboolean contains(Class<?> type, Object object) {\n\t\t\tif (this.seen.isEmpty()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// If it has been directly seen, or the implemented ServletContextInitializer\n\t\t\t// has been seen already\n\t\t\tif (type != ServletContextInitializer.class\n\t\t\t\t\t&& this.seen.getOrDefault(type, Collections.emptySet()).contains(object)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn this.seen.getOrDefault(ServletContextInitializer.class, Collections.emptySet()).contains(object);\n\t\t}\n\n\t\tstatic Seen empty() {\n\t\t\treturn new Seen();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletListenerRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Collections;\nimport java.util.EventListener;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextAttributeListener;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.servlet.ServletRequestAttributeListener;\nimport jakarta.servlet.ServletRequestListener;\nimport jakarta.servlet.http.HttpSessionAttributeListener;\nimport jakarta.servlet.http.HttpSessionIdListener;\nimport jakarta.servlet.http.HttpSessionListener;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * A {@link ServletContextInitializer} to register {@link EventListener}s in a Servlet\n * 3.0+ container. Similar to the {@link ServletContext#addListener(EventListener)\n * registration} features provided by {@link ServletContext} but with a Spring Bean\n * friendly design.\n *\n * This bean can be used to register the following types of listener:\n * <ul>\n * <li>{@link ServletContextAttributeListener}</li>\n * <li>{@link ServletRequestListener}</li>\n * <li>{@link ServletRequestAttributeListener}</li>\n * <li>{@link HttpSessionAttributeListener}</li>\n * <li>{@link HttpSessionIdListener}</li>\n * <li>{@link HttpSessionListener}</li>\n * <li>{@link ServletContextListener}</li>\n * </ul>\n *\n * @param <T> the type of listener\n * @author Dave Syer\n * @author Phillip Webb\n * @since 1.4.0\n */\npublic class ServletListenerRegistrationBean<T extends EventListener> extends RegistrationBean {\n\n\tprivate static final Set<Class<?>> SUPPORTED_TYPES;\n\n\tstatic {\n\t\tSet<Class<?>> types = new HashSet<>();\n\t\ttypes.add(ServletContextAttributeListener.class);\n\t\ttypes.add(ServletRequestListener.class);\n\t\ttypes.add(ServletRequestAttributeListener.class);\n\t\ttypes.add(HttpSessionAttributeListener.class);\n\t\ttypes.add(HttpSessionIdListener.class);\n\t\ttypes.add(HttpSessionListener.class);\n\t\ttypes.add(ServletContextListener.class);\n\t\tSUPPORTED_TYPES = Collections.unmodifiableSet(types);\n\t}\n\n\tprivate @Nullable T listener;\n\n\t/**\n\t * Create a new {@link ServletListenerRegistrationBean} instance.\n\t */\n\tpublic ServletListenerRegistrationBean() {\n\t}\n\n\t/**\n\t * Create a new {@link ServletListenerRegistrationBean} instance.\n\t * @param listener the listener to register\n\t */\n\tpublic ServletListenerRegistrationBean(T listener) {\n\t\tAssert.notNull(listener, \"'listener' must not be null\");\n\t\tAssert.isTrue(isSupportedType(listener), \"'listener' is not of a supported type\");\n\t\tthis.listener = listener;\n\t}\n\n\t/**\n\t * Set the listener that will be registered.\n\t * @param listener the listener to register\n\t */\n\tpublic void setListener(T listener) {\n\t\tAssert.notNull(listener, \"'listener' must not be null\");\n\t\tAssert.isTrue(isSupportedType(listener), \"'listener' is not of a supported type\");\n\t\tthis.listener = listener;\n\t}\n\n\t/**\n\t * Return the listener to be registered.\n\t * @return the listener to be registered\n\t */\n\tpublic @Nullable T getListener() {\n\t\treturn this.listener;\n\t}\n\n\t@Override\n\tprotected String getDescription() {\n\t\tAssert.notNull(this.listener, \"'listener' must not be null\");\n\t\treturn \"listener \" + this.listener;\n\t}\n\n\t@Override\n\tprotected void register(String description, ServletContext servletContext) {\n\t\ttry {\n\t\t\tservletContext.addListener(this.listener);\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to add listener '\" + this.listener + \"' to servlet context\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Returns {@code true} if the specified listener is one of the supported types.\n\t * @param listener the listener to test\n\t * @return if the listener is of a supported type\n\t */\n\tpublic static boolean isSupportedType(EventListener listener) {\n\t\tfor (Class<?> type : SUPPORTED_TYPES) {\n\t\t\tif (ClassUtils.isAssignableValue(type, listener)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return the supported types for this registration.\n\t * @return the supported types\n\t */\n\tpublic static Set<Class<?>> getSupportedTypes() {\n\t\treturn SUPPORTED_TYPES;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletRegistration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.annotation.MultipartConfig;\nimport jakarta.servlet.annotation.WebInitParam;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Registers a {@link Servlet} in a Servlet 3.0+ container. Can be used as an\n * annotation-based alternative to {@link ServletRegistrationBean}.\n *\n * @author Moritz Halbritter\n * @author Dmytro Danilenkov\n * @since 3.5.0\n * @see ServletRegistrationBean\n */\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Order\npublic @interface ServletRegistration {\n\n\t/**\n\t * Whether this registration is enabled.\n\t * @return whether this registration is enabled\n\t */\n\tboolean enabled() default true;\n\n\t/**\n\t * Order of the registration bean.\n\t * @return the order of the registration bean\n\t */\n\t@AliasFor(annotation = Order.class, attribute = \"value\")\n\tint order() default Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Name of this registration. If not specified the bean name will be used.\n\t * @return the name\n\t */\n\tString name() default \"\";\n\n\t/**\n\t * Whether asynchronous operations are supported for this registration.\n\t * @return whether asynchronous operations are supported\n\t */\n\tboolean asyncSupported() default true;\n\n\t/**\n\t * Whether registration failures should be ignored. If set to true, a failure will be\n\t * logged. If set to false, an {@link IllegalStateException} will be thrown.\n\t * @return whether registration failures should be ignored\n\t */\n\tboolean ignoreRegistrationFailure() default false;\n\n\t/**\n\t * URL mappings for the servlet. If not specified the mapping will default to '/'.\n\t * @return the url mappings\n\t */\n\tString[] urlMappings() default {};\n\n\t/**\n\t * The {@code loadOnStartup} priority. See\n\t * {@link jakarta.servlet.ServletRegistration.Dynamic#setLoadOnStartup} for details.\n\t * @return the {@code loadOnStartup} priority\n\t */\n\tint loadOnStartup() default -1;\n\n\t/**\n\t * Init parameters to be used with the servlet.\n\t * @return the init parameters\n\t */\n\tWebInitParam[] initParameters() default {};\n\n\t/**\n\t * The multipart configuration.\n\t * @return the multipart configuration\n\t */\n\tMultipartConfig multipartConfig() default @MultipartConfig;\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/ServletRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletRegistration;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link ServletContextInitializer} to register {@link Servlet}s in a Servlet 3.0+\n * container. Similar to the {@link ServletContext#addServlet(String, Servlet)\n * registration} features provided by {@link ServletContext} but with a Spring Bean\n * friendly design.\n * <p>\n * The {@link #setServlet(Servlet) servlet} must be specified before calling\n * {@link #onStartup}. URL mapping can be configured used {@link #setUrlMappings} or\n * omitted when mapping to '/*' (unless\n * {@link #ServletRegistrationBean(Servlet, boolean, String...) alwaysMapUrl} is set to\n * {@code false}). The servlet name will be deduced if not specified.\n *\n * @param <T> the type of the {@link Servlet} to register\n * @author Phillip Webb\n * @since 1.4.0\n * @see ServletContextInitializer\n * @see ServletContext#addServlet(String, Servlet)\n * @see org.springframework.boot.web.servlet.ServletRegistration\n */\npublic class ServletRegistrationBean<T extends Servlet> extends DynamicRegistrationBean<ServletRegistration.Dynamic> {\n\n\tprivate static final String[] DEFAULT_MAPPINGS = { \"/*\" };\n\n\tprivate @Nullable T servlet;\n\n\tprivate Set<String> urlMappings = new LinkedHashSet<>();\n\n\tprivate boolean alwaysMapUrl = true;\n\n\tprivate int loadOnStartup = -1;\n\n\tprivate @Nullable MultipartConfigElement multipartConfig;\n\n\t/**\n\t * Create a new {@link ServletRegistrationBean} instance.\n\t */\n\tpublic ServletRegistrationBean() {\n\t}\n\n\t/**\n\t * Create a new {@link ServletRegistrationBean} instance with the specified\n\t * {@link Servlet} and URL mappings.\n\t * @param servlet the servlet being mapped\n\t * @param urlMappings the URLs being mapped\n\t */\n\tpublic ServletRegistrationBean(T servlet, String... urlMappings) {\n\t\tthis(servlet, true, urlMappings);\n\t}\n\n\t/**\n\t * Create a new {@link ServletRegistrationBean} instance with the specified\n\t * {@link Servlet} and URL mappings.\n\t * @param servlet the servlet being mapped\n\t * @param alwaysMapUrl if omitted URL mappings should be replaced with '/*'\n\t * @param urlMappings the URLs being mapped\n\t */\n\tpublic ServletRegistrationBean(T servlet, boolean alwaysMapUrl, String... urlMappings) {\n\t\tAssert.notNull(servlet, \"'servlet' must not be null\");\n\t\tAssert.notNull(urlMappings, \"'urlMappings' must not be null\");\n\t\tthis.servlet = servlet;\n\t\tthis.alwaysMapUrl = alwaysMapUrl;\n\t\tthis.urlMappings.addAll(Arrays.asList(urlMappings));\n\t}\n\n\t/**\n\t * Sets the servlet to be registered.\n\t * @param servlet the servlet\n\t */\n\tpublic void setServlet(T servlet) {\n\t\tAssert.notNull(servlet, \"'servlet' must not be null\");\n\t\tthis.servlet = servlet;\n\t}\n\n\t/**\n\t * Return the servlet being registered.\n\t * @return the servlet\n\t */\n\tpublic @Nullable T getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\t/**\n\t * Set the URL mappings for the servlet. If not specified the mapping will default to\n\t * '/'. This will replace any previously specified mappings.\n\t * @param urlMappings the mappings to set\n\t * @see #addUrlMappings(String...)\n\t */\n\tpublic void setUrlMappings(Collection<String> urlMappings) {\n\t\tAssert.notNull(urlMappings, \"'urlMappings' must not be null\");\n\t\tthis.urlMappings = new LinkedHashSet<>(urlMappings);\n\t}\n\n\t/**\n\t * Return a mutable collection of the URL mappings, as defined in the Servlet\n\t * specification, for the servlet.\n\t * @return the urlMappings\n\t */\n\tpublic Collection<String> getUrlMappings() {\n\t\treturn this.urlMappings;\n\t}\n\n\t/**\n\t * Add URL mappings, as defined in the Servlet specification, for the servlet.\n\t * @param urlMappings the mappings to add\n\t * @see #setUrlMappings(Collection)\n\t */\n\tpublic void addUrlMappings(String... urlMappings) {\n\t\tAssert.notNull(urlMappings, \"'urlMappings' must not be null\");\n\t\tthis.urlMappings.addAll(Arrays.asList(urlMappings));\n\t}\n\n\t/**\n\t * Sets the {@code loadOnStartup} priority. See\n\t * {@link ServletRegistration.Dynamic#setLoadOnStartup} for details.\n\t * @param loadOnStartup if load on startup is enabled\n\t */\n\tpublic void setLoadOnStartup(int loadOnStartup) {\n\t\tthis.loadOnStartup = loadOnStartup;\n\t}\n\n\t/**\n\t * Set the {@link MultipartConfigElement multi-part configuration}.\n\t * @param multipartConfig the multipart configuration to set or {@code null}\n\t */\n\tpublic void setMultipartConfig(@Nullable MultipartConfigElement multipartConfig) {\n\t\tthis.multipartConfig = multipartConfig;\n\t}\n\n\t/**\n\t * Returns the {@link MultipartConfigElement multi-part configuration} to be applied\n\t * or {@code null}.\n\t * @return the multipart config\n\t */\n\tpublic @Nullable MultipartConfigElement getMultipartConfig() {\n\t\treturn this.multipartConfig;\n\t}\n\n\t@Override\n\tprotected String getDescription() {\n\t\tAssert.state(this.servlet != null, \"Unable to return description for null servlet\");\n\t\treturn \"servlet \" + getServletName();\n\t}\n\n\t@Override\n\tprotected ServletRegistration.Dynamic addRegistration(String description, ServletContext servletContext) {\n\t\tString name = getServletName();\n\t\treturn servletContext.addServlet(name, this.servlet);\n\t}\n\n\t/**\n\t * Configure registration settings. Subclasses can override this method to perform\n\t * additional configuration if required.\n\t * @param registration the registration\n\t */\n\t@Override\n\tprotected void configure(ServletRegistration.Dynamic registration) {\n\t\tsuper.configure(registration);\n\t\tString[] urlMapping = StringUtils.toStringArray(this.urlMappings);\n\t\tif (urlMapping.length == 0 && this.alwaysMapUrl) {\n\t\t\turlMapping = DEFAULT_MAPPINGS;\n\t\t}\n\t\tif (!ObjectUtils.isEmpty(urlMapping)) {\n\t\t\tregistration.addMapping(urlMapping);\n\t\t}\n\t\tregistration.setLoadOnStartup(this.loadOnStartup);\n\t\tif (this.multipartConfig != null) {\n\t\t\tregistration.setMultipartConfig(this.multipartConfig);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the servlet name that will be registered.\n\t * @return the servlet name\n\t */\n\tpublic String getServletName() {\n\t\treturn getOrDeduceName(this.servlet);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getServletName() + \" urls=\" + getUrlMappings();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes and utilities designed to work with the {@code jakarta.servlet} specification.\n */\n@NullMarked\npackage org.springframework.boot.web.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/support/ErrorPageFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletOutputStream;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpServletResponseWrapper;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.error.ErrorPageRegistrar;\nimport org.springframework.boot.web.error.ErrorPageRegistry;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\n/**\n * A Servlet {@link Filter} that provides an {@link ErrorPageRegistry} for non-embedded\n * applications (i.e. deployed WAR files). It registers error pages and handles\n * application errors by filtering requests and forwarding to the error pages instead of\n * letting the server handle them. Error pages are a feature of the servlet spec but there\n * is no Java API for registering them in the spec. This filter works around that by\n * accepting error page registrations from Spring Boot's {@link ErrorPageRegistrar} (any\n * beans of that type in the context will be applied to this server).\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class ErrorPageFilter implements Filter, ErrorPageRegistry, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(ErrorPageFilter.class);\n\n\t// From RequestDispatcher but not referenced to remain compatible with Servlet 2.5\n\n\tprivate static final String ERROR_EXCEPTION = \"jakarta.servlet.error.exception\";\n\n\tprivate static final String ERROR_EXCEPTION_TYPE = \"jakarta.servlet.error.exception_type\";\n\n\tprivate static final String ERROR_MESSAGE = \"jakarta.servlet.error.message\";\n\n\t/**\n\t * The name of the servlet attribute containing request URI.\n\t */\n\tpublic static final String ERROR_REQUEST_URI = \"jakarta.servlet.error.request_uri\";\n\n\tprivate static final String ERROR_STATUS_CODE = \"jakarta.servlet.error.status_code\";\n\n\tprivate static final Set<Class<?>> CLIENT_ABORT_EXCEPTIONS;\n\tstatic {\n\t\tSet<Class<?>> clientAbortExceptions = new HashSet<>();\n\t\taddClassIfPresent(clientAbortExceptions, \"org.apache.catalina.connector.ClientAbortException\");\n\t\tCLIENT_ABORT_EXCEPTIONS = Collections.unmodifiableSet(clientAbortExceptions);\n\t}\n\n\tprivate @Nullable String global;\n\n\tprivate final Map<Integer, String> statuses = new HashMap<>();\n\n\tprivate final Map<@Nullable Class<?>, String> exceptions = new HashMap<>();\n\n\tprivate final OncePerRequestFilter delegate = new OncePerRequestFilter() {\n\n\t\t@Override\n\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)\n\t\t\t\tthrows ServletException, IOException {\n\t\t\tErrorPageFilter.this.doFilter(request, response, chain);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean shouldNotFilterAsyncDispatch() {\n\t\t\treturn false;\n\t\t}\n\n\t};\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t\tthis.delegate.init(filterConfig);\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tthis.delegate.doFilter(request, response, chain);\n\t}\n\n\tprivate void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tErrorWrapperResponse wrapped = new ErrorWrapperResponse(response);\n\t\ttry {\n\t\t\tchain.doFilter(request, wrapped);\n\t\t\tif (wrapped.hasErrorToSend()) {\n\t\t\t\thandleErrorStatus(request, response, wrapped.getStatus(), wrapped.getMessage());\n\t\t\t\tresponse.flushBuffer();\n\t\t\t}\n\t\t\telse if (!request.isAsyncStarted() && !response.isCommitted()) {\n\t\t\t\tresponse.flushBuffer();\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tThrowable exceptionToHandle = ex;\n\t\t\tif (ex instanceof ServletException servletException) {\n\t\t\t\tThrowable rootCause = servletException.getRootCause();\n\t\t\t\tif (rootCause != null) {\n\t\t\t\t\texceptionToHandle = rootCause;\n\t\t\t\t}\n\t\t\t}\n\t\t\thandleException(request, response, wrapped, exceptionToHandle);\n\t\t\tresponse.flushBuffer();\n\t\t}\n\t}\n\n\tprivate void handleErrorStatus(HttpServletRequest request, HttpServletResponse response, int status,\n\t\t\t@Nullable String message) throws ServletException, IOException {\n\t\tif (response.isCommitted()) {\n\t\t\thandleCommittedResponse(request, null);\n\t\t\treturn;\n\t\t}\n\t\tString errorPath = getErrorPath(this.statuses, status);\n\t\tif (errorPath == null) {\n\t\t\tresponse.sendError(status, message);\n\t\t\treturn;\n\t\t}\n\t\tresponse.setStatus(status);\n\t\tsetErrorAttributes(request, status, message);\n\t\trequest.getRequestDispatcher(errorPath).forward(request, response);\n\t}\n\n\tprivate void handleException(HttpServletRequest request, HttpServletResponse response, ErrorWrapperResponse wrapped,\n\t\t\tThrowable ex) throws IOException, ServletException {\n\t\tClass<?> type = ex.getClass();\n\t\tString errorPath = getErrorPath(type);\n\t\tif (errorPath == null) {\n\t\t\trethrow(ex);\n\t\t\treturn;\n\t\t}\n\t\tif (response.isCommitted()) {\n\t\t\thandleCommittedResponse(request, ex);\n\t\t\treturn;\n\t\t}\n\t\tforwardToErrorPage(errorPath, request, wrapped, ex);\n\t}\n\n\tprivate void forwardToErrorPage(String path, HttpServletRequest request, HttpServletResponse response, Throwable ex)\n\t\t\tthrows ServletException, IOException {\n\t\tif (logger.isErrorEnabled()) {\n\t\t\tString message = \"Forwarding to error page from request \" + getDescription(request) + \" due to exception [\"\n\t\t\t\t\t+ ex.getMessage() + \"]\";\n\t\t\tlogger.error(message, ex);\n\t\t}\n\t\tsetErrorAttributes(request, 500, ex.getMessage());\n\t\trequest.setAttribute(ERROR_EXCEPTION, ex);\n\t\trequest.setAttribute(ERROR_EXCEPTION_TYPE, ex.getClass());\n\t\tresponse.reset();\n\t\tresponse.setStatus(500);\n\t\trequest.getRequestDispatcher(path).forward(request, response);\n\t\trequest.removeAttribute(ERROR_EXCEPTION);\n\t\trequest.removeAttribute(ERROR_EXCEPTION_TYPE);\n\t}\n\n\t/**\n\t * Return the description for the given request. By default this method will return a\n\t * description based on the request {@code servletPath} and {@code pathInfo}.\n\t * @param request the source request\n\t * @return the description\n\t */\n\tprotected String getDescription(HttpServletRequest request) {\n\t\tString pathInfo = (request.getPathInfo() != null) ? request.getPathInfo() : \"\";\n\t\treturn \"[\" + request.getServletPath() + pathInfo + \"]\";\n\t}\n\n\tprivate void handleCommittedResponse(HttpServletRequest request, @Nullable Throwable ex) {\n\t\tif (isClientAbortException(ex)) {\n\t\t\treturn;\n\t\t}\n\t\tString message = \"Cannot forward to error page for request \" + getDescription(request)\n\t\t\t\t+ \" as the response has already been\"\n\t\t\t\t+ \" committed. As a result, the response may have the wrong status\"\n\t\t\t\t+ \" code. If your application is running on WebSphere Application\"\n\t\t\t\t+ \" Server you may be able to resolve this problem by setting\"\n\t\t\t\t+ \" com.ibm.ws.webcontainer.invokeFlushAfterService to false\";\n\t\tif (ex == null) {\n\t\t\tlogger.error(message);\n\t\t}\n\t\telse {\n\t\t\t// User might see the error page without all the data here but throwing the\n\t\t\t// exception isn't going to help anyone (we'll log it to be on the safe side)\n\t\t\tlogger.error(message, ex);\n\t\t}\n\t}\n\n\tprivate boolean isClientAbortException(@Nullable Throwable ex) {\n\t\tif (ex == null) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (Class<?> candidate : CLIENT_ABORT_EXCEPTIONS) {\n\t\t\tif (candidate.isInstance(ex)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn isClientAbortException(ex.getCause());\n\t}\n\n\tprivate @Nullable String getErrorPath(Map<Integer, String> map, Integer status) {\n\t\tif (map.containsKey(status)) {\n\t\t\treturn map.get(status);\n\t\t}\n\t\treturn this.global;\n\t}\n\n\tprivate @Nullable String getErrorPath(Class<?> type) {\n\t\twhile (type != Object.class) {\n\t\t\tString path = this.exceptions.get(type);\n\t\t\tif (path != null) {\n\t\t\t\treturn path;\n\t\t\t}\n\t\t\ttype = type.getSuperclass();\n\t\t}\n\t\treturn this.global;\n\t}\n\n\tprivate void setErrorAttributes(HttpServletRequest request, int status, @Nullable String message) {\n\t\trequest.setAttribute(ERROR_STATUS_CODE, status);\n\t\trequest.setAttribute(ERROR_MESSAGE, message);\n\t\trequest.setAttribute(ERROR_REQUEST_URI, request.getRequestURI());\n\t}\n\n\tprivate void rethrow(Throwable ex) throws IOException, ServletException {\n\t\tif (ex instanceof RuntimeException runtimeException) {\n\t\t\tthrow runtimeException;\n\t\t}\n\t\tif (ex instanceof Error error) {\n\t\t\tthrow error;\n\t\t}\n\t\tif (ex instanceof IOException ioException) {\n\t\t\tthrow ioException;\n\t\t}\n\t\tif (ex instanceof ServletException servletException) {\n\t\t\tthrow servletException;\n\t\t}\n\t\tthrow new IllegalStateException(ex);\n\t}\n\n\t@Override\n\tpublic void addErrorPages(ErrorPage... errorPages) {\n\t\tfor (ErrorPage errorPage : errorPages) {\n\t\t\tif (errorPage.isGlobal()) {\n\t\t\t\tthis.global = errorPage.getPath();\n\t\t\t}\n\t\t\telse if (errorPage.getStatus() != null) {\n\t\t\t\tthis.statuses.put(errorPage.getStatus().value(), errorPage.getPath());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.exceptions.put(errorPage.getException(), errorPage.getPath());\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE + 1;\n\t}\n\n\tprivate static void addClassIfPresent(Collection<Class<?>> collection, String className) {\n\t\ttry {\n\t\t\tcollection.add(ClassUtils.forName(className, null));\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate static class ErrorWrapperResponse extends HttpServletResponseWrapper {\n\n\t\tprivate int status;\n\n\t\tprivate @Nullable String message;\n\n\t\tprivate boolean hasErrorToSend;\n\n\t\tErrorWrapperResponse(HttpServletResponse response) {\n\t\t\tsuper(response);\n\t\t}\n\n\t\t@Override\n\t\tpublic void sendError(int status) {\n\t\t\tsendError(status, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic void sendError(int status, @Nullable String message) {\n\t\t\tthis.status = status;\n\t\t\tthis.message = message;\n\t\t\tthis.hasErrorToSend = true;\n\t\t\t// Do not call super because the container may prevent us from handling the\n\t\t\t// error ourselves\n\t\t}\n\n\t\t@Override\n\t\tpublic int getStatus() {\n\t\t\tif (this.hasErrorToSend) {\n\t\t\t\treturn this.status;\n\t\t\t}\n\t\t\t// If there was no error we need to trust the wrapped response\n\t\t\treturn super.getStatus();\n\t\t}\n\n\t\t@Override\n\t\tpublic void flushBuffer() throws IOException {\n\t\t\tsendErrorIfNecessary();\n\t\t\tsuper.flushBuffer();\n\t\t}\n\n\t\tprivate void sendErrorIfNecessary() throws IOException {\n\t\t\tif (this.hasErrorToSend && !isCommitted()) {\n\t\t\t\t((HttpServletResponse) getResponse()).sendError(this.status, this.message);\n\t\t\t}\n\t\t}\n\n\t\t@Nullable String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\tboolean hasErrorToSend() {\n\t\t\treturn this.hasErrorToSend;\n\t\t}\n\n\t\t@Override\n\t\tpublic PrintWriter getWriter() throws IOException {\n\t\t\tsendErrorIfNecessary();\n\t\t\treturn super.getWriter();\n\t\t}\n\n\t\t@Override\n\t\tpublic ServletOutputStream getOutputStream() throws IOException {\n\t\t\tsendErrorIfNecessary();\n\t\t\treturn super.getOutputStream();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/support/ErrorPageFilterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport jakarta.servlet.DispatcherType;\n\nimport org.springframework.boot.web.error.ErrorPageRegistrarBeanPostProcessor;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for {@link ErrorPageFilter}.\n *\n * @author Andy Wilkinson\n * @author Jay Choi\n */\n@Configuration(proxyBeanMethods = false)\nclass ErrorPageFilterConfiguration {\n\n\t@Bean\n\tErrorPageFilter errorPageFilter() {\n\t\treturn new ErrorPageFilter();\n\t}\n\n\t@Bean\n\tFilterRegistrationBean<ErrorPageFilter> errorPageFilterRegistration(ErrorPageFilter filter) {\n\t\tFilterRegistrationBean<ErrorPageFilter> registration = new FilterRegistrationBean<>(filter);\n\t\tregistration.setOrder(filter.getOrder());\n\t\tregistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);\n\t\treturn registration;\n\t}\n\n\t@Bean\n\tstatic ErrorPageRegistrarBeanPostProcessor errorPageRegistrarBeanPostProcessor() {\n\t\treturn new ErrorPageRegistrarBeanPostProcessor();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/support/ServletContextApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport jakarta.servlet.ServletContext;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.core.Ordered;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * {@link ApplicationContextInitializer} for setting the servlet context.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class ServletContextApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableWebApplicationContext>, Ordered {\n\n\tprivate int order = Ordered.HIGHEST_PRECEDENCE;\n\n\tprivate final ServletContext servletContext;\n\n\tprivate final boolean addApplicationContextAttribute;\n\n\t/**\n\t * Create a new {@link ServletContextApplicationContextInitializer} instance.\n\t * @param servletContext the servlet that should be ultimately set.\n\t */\n\tpublic ServletContextApplicationContextInitializer(ServletContext servletContext) {\n\t\tthis(servletContext, false);\n\t}\n\n\t/**\n\t * Create a new {@link ServletContextApplicationContextInitializer} instance.\n\t * @param servletContext the servlet that should be ultimately set.\n\t * @param addApplicationContextAttribute if the {@link ApplicationContext} should be\n\t * stored as an attribute in the {@link ServletContext}\n\t * @since 1.3.4\n\t */\n\tpublic ServletContextApplicationContextInitializer(ServletContext servletContext,\n\t\t\tboolean addApplicationContextAttribute) {\n\t\tthis.servletContext = servletContext;\n\t\tthis.addApplicationContextAttribute = addApplicationContextAttribute;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t@Override\n\tpublic void initialize(ConfigurableWebApplicationContext applicationContext) {\n\t\tapplicationContext.setServletContext(this.servletContext);\n\t\tif (this.addApplicationContextAttribute) {\n\t\t\tthis.servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,\n\t\t\t\t\tapplicationContext);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/support/SpringBootServletInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.SQLException;\nimport java.util.Collections;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletException;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.builder.ParentContextApplicationContextInitializer;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.logging.LoggingApplicationListener;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.context.servlet.ApplicationServletEnvironment;\nimport org.springframework.boot.web.context.servlet.WebApplicationContextInitializer;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.WebApplicationInitializer;\nimport org.springframework.web.context.ConfigurableWebEnvironment;\nimport org.springframework.web.context.ContextLoaderListener;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * An opinionated {@link WebApplicationInitializer} to run a {@link SpringApplication}\n * from a traditional WAR deployment. Binds {@link Servlet}, {@link Filter} and\n * {@link ServletContextInitializer} beans from the application context to the server.\n * <p>\n * To configure the application either override the\n * {@link #configure(SpringApplicationBuilder)} method (calling\n * {@link SpringApplicationBuilder#sources(Class...)}) or make the initializer itself a\n * {@code @Configuration}. If you are using {@link SpringBootServletInitializer} in\n * combination with other {@link WebApplicationInitializer WebApplicationInitializers} you\n * might also want to add an {@code @Ordered} annotation to configure a specific startup\n * order.\n * <p>\n * Note that a WebApplicationInitializer is only needed if you are building a war file and\n * deploying it. If you prefer to run an embedded web server then you won't need this at\n * all.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @since 2.0.0\n * @see #configure(SpringApplicationBuilder)\n */\npublic abstract class SpringBootServletInitializer implements WebApplicationInitializer {\n\n\tprivate static final boolean REACTOR_PRESENT = ClassUtils.isPresent(\"reactor.core.scheduler.Schedulers\",\n\t\t\tSpringBootServletInitializer.class.getClassLoader());\n\n\tprotected @Nullable Log logger; // Don't initialize early\n\n\tprivate boolean registerErrorPageFilter = true;\n\n\t/**\n\t * Set if the {@link ErrorPageFilter} should be registered. Set to {@code false} if\n\t * error page mappings should be handled through the server and not Spring Boot.\n\t * @param registerErrorPageFilter if the {@link ErrorPageFilter} should be registered.\n\t */\n\tprotected final void setRegisterErrorPageFilter(boolean registerErrorPageFilter) {\n\t\tthis.registerErrorPageFilter = registerErrorPageFilter;\n\t}\n\n\t@Override\n\tpublic void onStartup(ServletContext servletContext) throws ServletException {\n\t\tservletContext.setAttribute(LoggingApplicationListener.REGISTER_SHUTDOWN_HOOK_PROPERTY, false);\n\t\t// Logger initialization is deferred in case an ordered\n\t\t// LogServletContextInitializer is being used\n\t\tthis.logger = LogFactory.getLog(getClass());\n\t\tWebApplicationContext rootApplicationContext = createRootApplicationContext(servletContext);\n\t\tif (rootApplicationContext != null) {\n\t\t\tservletContext.addListener(new SpringBootContextLoaderListener(rootApplicationContext, servletContext));\n\t\t}\n\t\telse {\n\t\t\tthis.logger.debug(\"No ContextLoaderListener registered, as createRootApplicationContext() did not \"\n\t\t\t\t\t+ \"return an application context\");\n\t\t}\n\t}\n\n\t/**\n\t * Deregisters the JDBC drivers that were registered by the application represented by\n\t * the given {@code servletContext}. The default implementation\n\t * {@link DriverManager#deregisterDriver(Driver) deregisters} every {@link Driver}\n\t * that was loaded by the {@link ServletContext#getClassLoader web application's class\n\t * loader}.\n\t * @param servletContext the web application's servlet context\n\t * @since 2.3.0\n\t */\n\tprotected void deregisterJdbcDrivers(ServletContext servletContext) {\n\t\tfor (Driver driver : Collections.list(DriverManager.getDrivers())) {\n\t\t\tif (driver.getClass().getClassLoader() == servletContext.getClassLoader()) {\n\t\t\t\ttry {\n\t\t\t\t\tDriverManager.deregisterDriver(driver);\n\t\t\t\t}\n\t\t\t\tcatch (SQLException ex) {\n\t\t\t\t\t// Continue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Shuts down the reactor {@link Schedulers} that were initialized by\n\t * {@code Schedulers.boundedElastic()} (or similar). The default implementation\n\t * {@link Schedulers#shutdownNow()} schedulers if they were initialized on this web\n\t * application's class loader.\n\t * @param servletContext the web application's servlet context\n\t * @since 3.4.0\n\t */\n\tprotected void shutDownSharedReactorSchedulers(ServletContext servletContext) {\n\t\tif (Schedulers.class.getClassLoader() == servletContext.getClassLoader()) {\n\t\t\tSchedulers.shutdownNow();\n\t\t}\n\t}\n\n\tprotected @Nullable WebApplicationContext createRootApplicationContext(ServletContext servletContext) {\n\t\tSpringApplicationBuilder builder = createSpringApplicationBuilder();\n\t\tbuilder.main(getClass());\n\t\tApplicationContext parent = getExistingRootWebApplicationContext(servletContext);\n\t\tif (parent != null) {\n\t\t\tgetLogger().info(\"Root context already created (using as parent).\");\n\t\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);\n\t\t\tbuilder.initializers(new ParentContextApplicationContextInitializer(parent));\n\t\t}\n\t\tbuilder.initializers(new ServletContextApplicationContextInitializer(servletContext));\n\t\tbuilder.contextFactory(new WarDeploymentApplicationContextFactory(servletContext));\n\t\tbuilder = configure(builder);\n\t\tbuilder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));\n\t\tSpringApplication application = builder.build();\n\t\tif (application.getAllSources().isEmpty()\n\t\t\t\t&& MergedAnnotations.from(getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {\n\t\t\tapplication.addPrimarySources(Collections.singleton(getClass()));\n\t\t}\n\t\tAssert.state(!application.getAllSources().isEmpty(),\n\t\t\t\t\"No SpringApplication sources have been defined. Either override the \"\n\t\t\t\t\t\t+ \"configure method or add an @Configuration annotation\");\n\t\t// Ensure error pages are registered\n\t\tif (this.registerErrorPageFilter) {\n\t\t\tapplication.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));\n\t\t}\n\t\tapplication.setRegisterShutdownHook(false);\n\t\treturn run(application);\n\t}\n\n\tprivate Log getLogger() {\n\t\tAssert.state(this.logger != null, \"Logger not set\");\n\t\treturn this.logger;\n\t}\n\n\t/**\n\t * Returns the {@code SpringApplicationBuilder} that is used to configure and create\n\t * the {@link SpringApplication}. The default implementation returns a new\n\t * {@code SpringApplicationBuilder} in its default state.\n\t * @return the {@code SpringApplicationBuilder}.\n\t */\n\tprotected SpringApplicationBuilder createSpringApplicationBuilder() {\n\t\treturn new SpringApplicationBuilder();\n\t}\n\n\t/**\n\t * Called to run a fully configured {@link SpringApplication}.\n\t * @param application the application to run\n\t * @return the {@link WebApplicationContext}\n\t */\n\tprotected @Nullable WebApplicationContext run(SpringApplication application) {\n\t\treturn (WebApplicationContext) application.run();\n\t}\n\n\tprivate @Nullable ApplicationContext getExistingRootWebApplicationContext(ServletContext servletContext) {\n\t\tObject context = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);\n\t\tif (context instanceof ApplicationContext applicationContext) {\n\t\t\treturn applicationContext;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Configure the application. Normally all you would need to do is to add sources\n\t * (e.g. config classes) because other settings have sensible defaults. You might\n\t * choose (for instance) to add default command line arguments, or set an active\n\t * Spring profile.\n\t * @param builder a builder for the application context\n\t * @return the application builder\n\t * @see SpringApplicationBuilder\n\t */\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\treturn builder;\n\t}\n\n\t/**\n\t * {@link ApplicationListener} to trigger\n\t * {@link ConfigurableWebEnvironment#initPropertySources(ServletContext, jakarta.servlet.ServletConfig)}.\n\t */\n\tprivate static final class WebEnvironmentPropertySourceInitializer\n\t\t\timplements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {\n\n\t\tprivate final ServletContext servletContext;\n\n\t\tprivate WebEnvironmentPropertySourceInitializer(ServletContext servletContext) {\n\t\t\tthis.servletContext = servletContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\t\tConfigurableEnvironment environment = event.getEnvironment();\n\t\t\tif (environment instanceof ConfigurableWebEnvironment configurableWebEnvironment) {\n\t\t\t\tconfigurableWebEnvironment.initPropertySources(this.servletContext, null);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ContextLoaderListener} for the initialized context.\n\t */\n\tprivate class SpringBootContextLoaderListener extends ContextLoaderListener {\n\n\t\tprivate final ServletContext servletContext;\n\n\t\tSpringBootContextLoaderListener(WebApplicationContext applicationContext, ServletContext servletContext) {\n\t\t\tsuper(applicationContext);\n\t\t\tthis.servletContext = servletContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void contextInitialized(ServletContextEvent event) {\n\t\t\t// no-op because the application context is already initialized\n\t\t}\n\n\t\t@Override\n\t\tpublic void contextDestroyed(ServletContextEvent event) {\n\t\t\ttry {\n\t\t\t\tsuper.contextDestroyed(event);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\t// Use original context so that the classloader can be accessed\n\t\t\t\tderegisterJdbcDrivers(this.servletContext);\n\t\t\t\t// Shut down shared reactor schedulers tied to this classloader\n\t\t\t\tif (REACTOR_PRESENT) {\n\t\t\t\t\tshutDownSharedReactorSchedulers(this.servletContext);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static final class WarDeploymentApplicationContextFactory implements ApplicationContextFactory {\n\n\t\tprivate final ServletContext servletContext;\n\n\t\tprivate WarDeploymentApplicationContextFactory(ServletContext servletContext) {\n\t\t\tthis.servletContext = servletContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Class<? extends ConfigurableEnvironment> getEnvironmentType(\n\t\t\t\t@Nullable WebApplicationType webApplicationType) {\n\t\t\treturn (webApplicationType != WebApplicationType.SERVLET) ? null : ApplicationServletEnvironment.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {\n\t\t\treturn new ApplicationServletEnvironment();\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) {\n\t\t\treturn new AnnotationConfigServletWebApplicationContext() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void onRefresh() {\n\t\t\t\t\tsuper.onRefresh();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tnew WebApplicationContextInitializer(this)\n\t\t\t\t\t\t\t.initialize(WarDeploymentApplicationContextFactory.this.servletContext);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ServletException ex) {\n\t\t\t\t\t\tthrow new ApplicationContextException(\"Cannot initialize servlet context\", ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/java/org/springframework/boot/web/servlet/support/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for Servlet-based web servers.\n */\n@NullMarked\npackage org.springframework.boot.web.servlet.support;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/main/javaTemplates/org/springframework/boot/SpringBootVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\n/**\n * Exposes the Spring Boot version.\n *\n * @author Drummond Dawson\n * @author Hendrig Sellik\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 1.3.0\n */\npublic final class SpringBootVersion {\n\n\tprivate SpringBootVersion() {\n\t}\n\n\t/**\n\t * Return the full version string of the present Spring Boot codebase.\n\t * @return the version of Spring Boot\n\t */\n\tpublic static String getVersion() {\n\t\treturn \"${springBootVersion}\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/javaTemplates/org/springframework/boot/ssl/SpringBootProviderVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\n/**\n * Exposes the Spring Boot version for SSL Provider use.\n *\n * @author Phillip Webb\n */\nfinal class SpringBootProviderVersion {\n\n\tprivate SpringBootProviderVersion() {\n\t}\n\n\t/**\n\t * Return the full version string of the present Spring Boot codebase.\n\t * @return the version of Spring Boot\n\t */\n\tstatic String get() {\n\t\treturn \"${springBootVersion}\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/kotlin/org/springframework/boot/SpringApplicationExtensions.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot\n\nimport org.springframework.context.ConfigurableApplicationContext\nimport org.springframework.util.Assert\nimport org.springframework.util.ClassUtils\nimport org.springframework.util.ReflectionUtils\nimport kotlin.reflect.KClass\n\n/**\n * Top-level function acting as a Kotlin shortcut allowing to write\n * `runApplication<MyApplication>(arg1, arg2)` instead of\n * `SpringApplication.run(MyApplication::class.java, arg1, arg2)`.\n *\n * @author Sebastien Deleuze\n * @since 2.0.0\n */\ninline fun <reified T : Any> runApplication(vararg args: String): ConfigurableApplicationContext =\n\t\tSpringApplication.run(T::class.java, *args)\n\n/**\n * Top-level function acting as a Kotlin shortcut allowing to write\n * `runApplication<MyApplication>(arg1, arg2) { // SpringApplication customization ... }`\n * instead of instantiating `SpringApplication` class, customize it and then invoking\n * `run(arg1, arg2)`.\n *\n * @author Sebastien Deleuze\n * @since 2.0.0\n */\ninline fun <reified T : Any> runApplication(\n\t\t\t\tvararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext =\n\t\tSpringApplication(T::class.java).apply(init).run(*args)\n\n/**\n * Top-level function acting as a Kotlin shortcut allowing to write\n * `fromApplication<MyApplication>().with(...)`. This method assumes that\n * the `main` function is declared in the same file as `T`.\n *\n * @author Phillip Webb\n * @since 3.1.1\n */\ninline fun <reified T : Any> fromApplication(): SpringApplication.Augmented {\n\tval type = T::class\n\tval ktClassName = \"${type.qualifiedName}Kt\"\n\ttry {\n\t\tval ktClass = ClassUtils.resolveClassName(ktClassName, type.java.classLoader)\n\t\tval mainMethod = ReflectionUtils.findMethod(ktClass, \"main\", Array<String>::class.java)\n\t\tAssert.notNull(mainMethod, \"Unable to find main method\")\n\t\treturn SpringApplication.from { ReflectionUtils.invokeMethod(mainMethod!!, null, it) }\n\t} catch (ex: Exception) {\n\t\tthrow IllegalStateException(\"Unable to use 'fromApplication' with ${type.qualifiedName}\")\n\t}\n}\n\n/**\n * Extension function that allows [SpringApplication.Augmented.with] to work with Kotlin classes.\n *\n * @author Phillip Webb\n * @author Sebastien Deleuze\n * @since 3.1.1\n */\nfun SpringApplication.Augmented.with(vararg types: KClass<*>): SpringApplication.Augmented {\n\treturn this.with(*types.map(KClass<*>::java).toTypedArray())!!\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"logging\",\n      \"type\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"debug\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Enable debug logs.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"logging.charset.console\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"description\": \"Charset to use for console output.\"\n    },\n    {\n      \"name\": \"logging.charset.file\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"description\": \"Charset to use for file output.\"\n    },\n    {\n      \"name\": \"logging.config\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Location of the logging configuration file. For instance, `classpath:logback.xml` for Logback.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.console.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable console-based logging.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.exception-conversion-word\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Conversion word used when logging exceptions.\",\n      \"defaultValue\": \"%wEx\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.file\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Log file name (for instance, `myapp.log`). Names can be an exact location or relative to the current directory.\",\n      \"deprecation\": {\n        \"replacement\": \"logging.file.name\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"logging.file.clean-history-on-start\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"logging.logback.rollingpolicy.clean-history-on-start\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"logging.file.max-history\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"logging.logback.rollingpolicy.max-history\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"logging.file.max-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"logging.logback.rollingpolicy.max-file-size\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"logging.file.name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Log file name (for instance, `myapp.log`). Names can be an exact location or relative to the current directory.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.file.path\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Location of the log file. For instance, `/var/log`.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.file.total-size-cap\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"logging.logback.rollingpolicy.total-size-cap\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"logging.group\",\n      \"type\": \"java.util.Map<java.lang.String,java.util.List<java.lang.String>>\",\n      \"description\": \"Log groups to quickly change multiple loggers at the same time. For instance, `logging.group.db=org.hibernate,org.springframework.jdbc`.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.include-application-group\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to include the application group in the logs.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"logging.include-application-name\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to include the application name in the logs.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"logging.level\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"description\": \"Log levels severity mapping. For instance, `logging.level.org.springframework=DEBUG`.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.log4j2.config.override\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"description\": \"Overriding configuration files used to create a composite configuration. Can be prefixed with 'optional:' to only load the override if it exists.\"\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.cron\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Cron expression used when the strategy is 'cron'.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"0 0 0 * * ?\"\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.file-name-pattern\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Pattern for rolled-over log file names.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz\"\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.max-file-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"description\": \"Maximum log file size.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"10MB\"\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.max-history\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of archive log files to keep.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": 7\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.strategy\",\n      \"type\": \"org.springframework.boot.logging.log4j2.RollingPolicyStrategy\",\n      \"description\": \"Rolling policy strategy.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"size\"\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.time-interval\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Time based triggering interval when the strategy is 'time' or 'size-and-time'.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": 1\n    },\n    {\n      \"name\": \"logging.log4j2.rollingpolicy.time-modulate\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to align the next rollover time to occur at the top of the interval when the strategy is time based.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"logging.logback.rollingpolicy.clean-history-on-start\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to clean the archive log files on startup.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"logging.logback.rollingpolicy.file-name-pattern\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Pattern for rolled-over log file names.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz\"\n    },\n    {\n      \"name\": \"logging.logback.rollingpolicy.max-file-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"description\": \"Maximum log file size.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"10MB\"\n    },\n    {\n      \"name\": \"logging.logback.rollingpolicy.max-history\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of archive log files to keep.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": 7\n    },\n    {\n      \"name\": \"logging.logback.rollingpolicy.total-size-cap\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"description\": \"Total size of log backups to be kept.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"0B\"\n    },\n    {\n      \"name\": \"logging.path\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Location of the log file. For instance, `/var/log`.\",\n      \"deprecation\": {\n        \"replacement\": \"logging.file.path\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"logging.pattern.console\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Appender pattern for output to the console. Its default value varies according to the logging system.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.pattern.correlation\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Appender pattern for log correlation. Its default value varies according to the logging system.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.pattern.dateformat\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Appender pattern for log date format.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"yyyy-MM-dd'T'HH:mm:ss.SSSXXX\"\n    },\n    {\n      \"name\": \"logging.pattern.file\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Appender pattern for output to a file. Its default value varies according to the logging system.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\"\n    },\n    {\n      \"name\": \"logging.pattern.level\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Appender pattern for log level.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": \"%5p\"\n    },\n    {\n      \"name\": \"logging.pattern.rolling-file-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"logging.logback.rollingpolicy.file-name-pattern\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"logging.register-shutdown-hook\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Register a shutdown hook for the logging system when it is initialized. Disabled automatically when deployed as a war file.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"logging.structured.ecs.service.environment\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured ECS service environment.\"\n    },\n    {\n      \"name\": \"logging.structured.ecs.service.name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured ECS service name (defaults to 'spring.application.name').\"\n    },\n    {\n      \"name\": \"logging.structured.ecs.service.node-name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured ECS service node name.\"\n    },\n    {\n      \"name\": \"logging.structured.ecs.service.version\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured ECS service version (defaults to 'spring.application.version').\"\n    },\n    {\n      \"name\": \"logging.structured.format.console\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured logging format for output to the console. Must be either a format id or a fully qualified class name.\"\n    },\n    {\n      \"name\": \"logging.structured.format.file\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured logging format for output to a file. Must be either a format id or a fully qualified class name.\"\n    },\n    {\n      \"name\": \"logging.structured.gelf.host\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured GELF host (defaults to 'spring.application.name').\"\n    },\n    {\n      \"name\": \"logging.structured.gelf.service.version\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Structured GELF service version (defaults to 'spring.application.version').\"\n    },\n    {\n      \"name\": \"logging.structured.json.add\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"description\": \"Additional members that should be added to structured logging JSON\"\n    },\n    {\n      \"name\": \"logging.structured.json.context.include\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether context data should be included in the JSON.\"\n    },\n    {\n      \"name\": \"logging.structured.json.context.prefix\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"The prefix to use when inserting context data.\"\n    },\n    {\n      \"name\": \"logging.structured.json.customizer\",\n      \"type\": \"java.util.Set<java.lang.Class<? extends org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer<?>>>\",\n      \"description\": \"Fully qualified class names of StructuredLoggingJsonMembersCustomizer implementations\"\n    },\n    {\n      \"name\": \"logging.structured.json.exclude\",\n      \"type\": \"java.util.Set<java.lang.String>\",\n      \"description\": \"Member paths that should be excluded from structured logging JSON\"\n    },\n    {\n      \"name\": \"logging.structured.json.include\",\n      \"type\": \"java.util.Set<java.lang.String>\",\n      \"description\": \"Member paths that should be included in structured logging JSON\"\n    },\n    {\n      \"name\": \"logging.structured.json.rename\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"description\": \"Mapping between member paths and an alternative name that should be used in structured logging JSON\"\n    },\n    {\n      \"name\": \"logging.structured.json.stacktrace.include-common-frames\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether common frames should be included.\"\n    },\n    {\n      \"name\": \"logging.structured.json.stacktrace.include-hashes\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether stack trace hashes should be included.\"\n    },\n    {\n      \"name\": \"logging.structured.json.stacktrace.max-length\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum length to print.\"\n    },\n    {\n      \"name\": \"logging.structured.json.stacktrace.max-throwable-depth\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum throwable depth to print.\"\n    },\n    {\n      \"name\": \"logging.structured.json.stacktrace.printer\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Name of the printer to use. Can be 'standard', 'logging-system', or the fully-qualified class name of a StackTracePrinter. When not specified 'logging-system' or 'standard' will be used depending if other properties are set.\"\n    },\n    {\n      \"name\": \"logging.structured.json.stacktrace.root\",\n      \"type\": \"org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace.Root\",\n      \"description\": \"Root ordering (root first or root last).\"\n    },\n    {\n      \"name\": \"logging.threshold.console\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Log level threshold for console output.\",\n      \"defaultValue\": \"TRACE\"\n    },\n    {\n      \"name\": \"logging.threshold.file\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Log level threshold for file output.\",\n      \"defaultValue\": \"TRACE\"\n    },\n    {\n      \"name\": \"spring.application.group\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Application group. Typically used with logging to help identify the application.\"\n    },\n    {\n      \"name\": \"spring.application.index\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Application index.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Application context ids are now unique by default.\",\n        \"since\": \"2.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.application.name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.context.ContextIdApplicationContextInitializer\",\n      \"description\": \"Application name. Typically used with logging to help identify the application.\"\n    },\n    {\n      \"name\": \"spring.application.version\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Application version (defaults to 'Implementation-Version' from the manifest).\"\n    },\n    {\n      \"name\": \"spring.banner.charset\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"description\": \"Banner file encoding.\",\n      \"defaultValue\": \"UTF-8\"\n    },\n    {\n      \"name\": \"spring.banner.image.bitdepth\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.image.height\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.image.invert\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.image.location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.image.margin\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.image.pixelmode\",\n      \"type\": \"org.springframework.boot.ImageBanner$PixelMode\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.image.width\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Support for image banners has been removed.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.banner.location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Banner text resource location.\",\n      \"defaultValue\": \"classpath:banner.txt\"\n    },\n    {\n      \"name\": \"spring.beaninfo.ignore\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether to skip search of BeanInfo classes.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.config.activate.on-cloud-platform\",\n      \"type\": \"org.springframework.boot.cloud.CloudPlatform\",\n      \"description\": \"Required cloud platform for the document to be included.\",\n      \"sourceType\": \"org.springframework.boot.context.config.ConfigDataProperties\"\n    },\n    {\n      \"name\": \"spring.config.activate.on-profile\",\n      \"type\": \"java.lang.String[]\",\n      \"description\": \"Profile expressions that should match for the document to be included.\",\n      \"sourceType\": \"org.springframework.boot.context.config.ConfigDataProperties\"\n    },\n    {\n      \"name\": \"spring.config.additional-location\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.context.config.ConfigDataEnvironment\",\n      \"description\": \"Config file locations used in addition to the defaults.\"\n    },\n    {\n      \"name\": \"spring.config.import\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"description\": \"Import additional config data.\",\n      \"sourceType\": \"org.springframework.boot.context.config.ConfigDataProperties\"\n    },\n    {\n      \"name\": \"spring.config.location\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.context.config.ConfigDataEnvironment\",\n      \"description\": \"Config file locations that replace the defaults.\"\n    },\n    {\n      \"name\": \"spring.config.name\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.context.config.StandardConfigDataLocationResolver\",\n      \"description\": \"Config file name.\",\n      \"defaultValue\": \"application\"\n    },\n    {\n      \"name\": \"spring.jpa.defer-datasource-initialization\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to defer DataSource initialization until after any EntityManagerFactory beans have been created and initialized.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.main.allow-bean-definition-overriding\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether bean definition overriding, by registering a definition with the same name as an existing definition, is allowed.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.main.allow-circular-references\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether to allow circular references between beans and automatically try to resolve them.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.main.banner-mode\",\n      \"type\": \"org.springframework.boot.Banner$Mode\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Mode used to display the banner when the application runs. Defaults to 'off' if structured logging is enabled or to 'console' otherwise\"\n    },\n    {\n      \"name\": \"spring.main.cloud-platform\",\n      \"type\": \"org.springframework.boot.cloud.CloudPlatform\",\n      \"description\": \"Override the Cloud Platform auto-detection.\"\n    },\n    {\n      \"name\": \"spring.main.keep-alive\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether to keep the application alive even if there are no more non-daemon threads.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.main.lazy-initialization\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether initialization should be performed lazily.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.main.log-startup-info\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether to log information about the application when it starts.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.main.register-shutdown-hook\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Whether the application should have a shutdown hook registered.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.main.show-banner\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Display the banner when the application runs.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.main.banner-mode\",\n        \"since\": \"1.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.main.sources\",\n      \"type\": \"java.util.Set<java.lang.String>\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Sources (class names, package names, or XML resource locations) to include in the ApplicationContext.\"\n    },\n    {\n      \"name\": \"spring.main.web-application-type\",\n      \"type\": \"org.springframework.boot.WebApplicationType\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Flag to explicitly request a specific type of web application. If not set, auto-detected based on the classpath.\"\n    },\n    {\n      \"name\": \"spring.main.web-environment\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.SpringApplication\",\n      \"description\": \"Run the application in a web environment (auto-detected by default).\",\n      \"deprecation\": {\n        \"replacement\": \"spring.main.web-application-type\",\n        \"since\": \"2.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mandatory-file-encoding\",\n      \"sourceType\": \"org.springframework.boot.context.FileEncodingApplicationListener\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"description\": \"Expected character encoding the application must use.\"\n    },\n    {\n      \"name\": \"spring.output.ansi.enabled\",\n      \"type\": \"org.springframework.boot.ansi.AnsiOutput$Enabled\",\n      \"description\": \"Configures the ANSI output.\",\n      \"defaultValue\": \"detect\"\n    },\n    {\n      \"name\": \"spring.pid.fail-on-write-error\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Fails if ApplicationPidFileWriter is used but it cannot write the PID file.\",\n      \"sourceType\": \"org.springframework.boot.context.ApplicationPidFileWriter\"\n    },\n    {\n      \"name\": \"spring.pid.file\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Location of the PID file to write (if ApplicationPidFileWriter is used).\",\n      \"sourceType\": \"org.springframework.boot.context.ApplicationPidFileWriter\"\n    },\n    {\n      \"name\": \"spring.profiles.active\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"sourceType\": \"org.springframework.boot.context.config.Profiles\",\n      \"description\": \"Comma-separated list of active profiles. Can be overridden by a command line switch.\"\n    },\n    {\n      \"name\": \"spring.profiles.default\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"org.springframework.boot.context.config.Profiles\",\n      \"description\": \"Name of the profile to enable if no profile is active.\",\n      \"defaultValue\": \"default\"\n    },\n    {\n      \"name\": \"spring.profiles.group\",\n      \"type\": \"java.util.Map<java.lang.String,java.util.List<java.lang.String>>\",\n      \"sourceType\": \"org.springframework.boot.context.config.Profiles\",\n      \"description\": \"Profile groups to define a logical name for a related group of profiles.\"\n    },\n    {\n      \"name\": \"spring.profiles.include\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"sourceType\": \"org.springframework.boot.context.config.Profiles\",\n      \"description\": \"Unconditionally activate the specified comma-separated list of profiles (or list of profiles if using YAML).\"\n    },\n    {\n      \"name\": \"spring.profiles.validate\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.context.config.Profiles\",\n      \"description\": \"Whether profiles should be validated to ensure sensible names are used.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.reactor.debug-agent.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"sourceType\": \"org.springframework.boot.reactor.ReactorEnvironmentPostProcessor\",\n      \"description\": \"Whether the Reactor Debug Agent should be enabled when reactor-tools is present.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"trace\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Enable trace logs.\",\n      \"sourceType\": \"org.springframework.boot.context.logging.LoggingApplicationListener\",\n      \"defaultValue\": false\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"logging.group.values\",\n      \"providers\": [\n        {\n          \"name\": \"logger-name\",\n          \"parameters\": {\n            \"group\": false\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"logging.level.keys\",\n      \"values\": [\n        {\n          \"value\": \"root\",\n          \"description\": \"Root logger used to assign the default logging level.\"\n        },\n        {\n          \"value\": \"sql\",\n          \"description\": \"SQL logging group including Hibernate SQL logger.\"\n        },\n        {\n          \"value\": \"web\",\n          \"description\": \"Web logging group including codecs.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"logger-name\"\n        }\n      ]\n    },\n    {\n      \"name\": \"logging.level.values\",\n      \"values\": [\n        {\n          \"value\": \"trace\"\n        },\n        {\n          \"value\": \"debug\"\n        },\n        {\n          \"value\": \"info\"\n        },\n        {\n          \"value\": \"warn\"\n        },\n        {\n          \"value\": \"error\"\n        },\n        {\n          \"value\": \"fatal\"\n        },\n        {\n          \"value\": \"off\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"logging.structured.format.console\",\n      \"values\": [\n        {\n          \"value\": \"ecs\"\n        },\n        {\n          \"value\": \"gelf\"\n        },\n        {\n          \"value\": \"logstash\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.lang.Class\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"logging.structured.format.file\",\n      \"values\": [\n        {\n          \"value\": \"ecs\"\n        },\n        {\n          \"value\": \"gelf\"\n        },\n        {\n          \"value\": \"logstash\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.lang.Class\"\n          }\n        }\n      ]\n    },\n \t{\n      \"name\": \"logging.structured.json.stacktrace.printer\",\n      \"values\": [\n        {\n          \"value\": \"standard\"\n        },\n        {\n          \"value\": \"logging-system\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.lang.Class<org.springframework.boot.logging.StackTracePrinter>\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.config.import\",\n      \"values\": [\n        {\n          \"value\": \"file:\"\n        },\n        {\n          \"value\": \"classpath:\"\n        },\n        {\n          \"value\": \"configtree:\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.profiles.active\",\n      \"providers\": [\n        {\n          \"name\": \"spring-profile-name\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.profiles.include\",\n      \"providers\": [\n        {\n          \"name\": \"spring-profile-name\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/META-INF/services/ch.qos.logback.classic.spi.Configurator",
    "content": "org.springframework.boot.logging.logback.RootLogLevelConfigurator"
  },
  {
    "path": "core/spring-boot/src/main/resources/META-INF/services/org.apache.logging.log4j.util.PropertySource",
    "content": "org.springframework.boot.logging.log4j2.SpringBootPropertySource"
  },
  {
    "path": "core/spring-boot/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.ApplicationProperties$ApplicationPropertiesRuntimeHints,\\\norg.springframework.boot.SpringApplicationBannerPrinter$SpringApplicationBannerPrinterRuntimeHints,\\\norg.springframework.boot.WebApplicationType$WebApplicationTypeRuntimeHints,\\\norg.springframework.boot.context.config.ConfigDataLocationRuntimeHints,\\\norg.springframework.boot.context.config.ConfigDataPropertiesRuntimeHints,\\\norg.springframework.boot.env.PropertySourceRuntimeHints,\\\norg.springframework.boot.logging.java.JavaLoggingSystemRuntimeHints,\\\norg.springframework.boot.logging.log4j2.Log4J2RuntimeHints,\\\norg.springframework.boot.logging.logback.LogbackRuntimeHints,\\\norg.springframework.boot.logging.structured.ElasticCommonSchemaProperties$ElasticCommonSchemaPropertiesRuntimeHints,\\\norg.springframework.boot.logging.structured.GraylogExtendedLogFormatProperties$GraylogExtendedLogFormatPropertiesRuntimeHints,\\\norg.springframework.boot.logging.structured.StructuredLoggingJsonProperties$StructuredLoggingJsonPropertiesRuntimeHints,\\\norg.springframework.boot.system.JavaVersion$Hints\n\norg.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\\\norg.springframework.boot.context.properties.ConfigurationPropertiesBeanFactoryInitializationAotProcessor,\\\norg.springframework.boot.logging.structured.StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor,\\\norg.springframework.boot.support.EnvironmentPostProcessorApplicationListener$EnvironmentBeanFactoryInitializationAotProcessor\n\norg.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\\\norg.springframework.boot.context.properties.ConfigurationPropertiesBeanRegistrationAotProcessor\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/META-INF/spring.factories",
    "content": "# Logging Systems\norg.springframework.boot.logging.LoggingSystemFactory=\\\norg.springframework.boot.logging.java.JavaLoggingSystem$Factory,\\\norg.springframework.boot.logging.log4j2.Log4J2LoggingSystem$Factory,\\\norg.springframework.boot.logging.logback.LogbackLoggingSystem$Factory\n\n# PropertySource Loaders\norg.springframework.boot.env.PropertySourceLoader=\\\norg.springframework.boot.env.PropertiesPropertySourceLoader,\\\norg.springframework.boot.env.YamlPropertySourceLoader\n\n# ConfigData Location Resolvers\norg.springframework.boot.context.config.ConfigDataLocationResolver=\\\norg.springframework.boot.context.config.ConfigTreeConfigDataLocationResolver,\\\norg.springframework.boot.context.config.StandardConfigDataLocationResolver,\\\norg.springframework.boot.context.config.SystemEnvironmentConfigDataLocationResolver\n\n# ConfigData Loaders\norg.springframework.boot.context.config.ConfigDataLoader=\\\norg.springframework.boot.context.config.ConfigTreeConfigDataLoader,\\\norg.springframework.boot.context.config.StandardConfigDataLoader,\\\norg.springframework.boot.context.config.SystemEnvironmentConfigDataLoader\n\n# Run Listeners\norg.springframework.boot.SpringApplicationRunListener=\\\norg.springframework.boot.context.event.EventPublishingRunListener\n\n# Error Reporters\norg.springframework.boot.SpringBootExceptionReporter=\\\norg.springframework.boot.diagnostics.FailureAnalyzers\n\n# Application Context Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\\\norg.springframework.boot.context.ContextIdApplicationContextInitializer,\\\norg.springframework.boot.io.ProtocolResolverApplicationContextInitializer\n\n# Application Listeners\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.ClearCachesApplicationListener,\\\norg.springframework.boot.builder.ParentContextCloserApplicationListener,\\\norg.springframework.boot.context.FileEncodingApplicationListener,\\\norg.springframework.boot.context.logging.LoggingApplicationListener,\\\norg.springframework.boot.support.AnsiOutputApplicationListener,\\\norg.springframework.boot.support.EnvironmentPostProcessorApplicationListener\n\n# Environment Post Processors\norg.springframework.boot.EnvironmentPostProcessor=\\\norg.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\\\norg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\\\norg.springframework.boot.support.RandomValuePropertySourceEnvironmentPostProcessor,\\\norg.springframework.boot.support.SpringApplicationJsonEnvironmentPostProcessor,\\\norg.springframework.boot.support.SystemEnvironmentPropertySourceEnvironmentPostProcessor\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.context.config.ConfigDataNotFoundFailureAnalyzer,\\\norg.springframework.boot.context.properties.IncompatibleConfigurationFailureAnalyzer,\\\norg.springframework.boot.context.properties.NotConstructorBoundInjectionFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.AotInitializerNotFoundFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.BeanDefinitionOverrideFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.MissingParameterNamesFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.MutuallyExclusiveConfigurationPropertiesFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.PatternParseFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\\\norg.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer\n\n# Failure Analysis Reporters\norg.springframework.boot.diagnostics.FailureAnalysisReporter=\\\norg.springframework.boot.diagnostics.LoggingFailureAnalysisReporter\n\n# Resource Locator Protocol Resolvers\norg.springframework.core.io.ProtocolResolver=\\\norg.springframework.boot.io.Base64ProtocolResolver\n\n# Resource File Path Resolvers\norg.springframework.boot.io.ApplicationResourceLoader$FilePathResolver=\\\norg.springframework.boot.io.ClassPathResourceFilePathResolver,\\\norg.springframework.boot.web.context.reactive.FilteredReactiveWebContextResourceFilePathResolver,\\\norg.springframework.boot.web.context.servlet.ServletContextResourceFilePathResolver\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/log4j2.springboot",
    "content": "See SpringBootConfigurationFactory\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging-file.properties",
    "content": "handlers =java.util.logging.FileHandler,java.util.logging.ConsoleHandler\n.level = INFO\n\n# File Logging\njava.util.logging.FileHandler.pattern = ${LOG_FILE}\njava.util.logging.FileHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter\njava.util.logging.FileHandler.level = ALL\njava.util.logging.FileHandler.limit = 10485760\njava.util.logging.FileHandler.count = 10\n\njava.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter\njava.util.logging.ConsoleHandler.level = ALL\n\norg.hibernate.validator.internal.util.Version.level = WARNING\norg.apache.coyote.http11.Http11NioProtocol.level = WARNING\norg.apache.tomcat.util.net.NioSelectorPool.level = WARNING\norg.apache.catalina.startup.DigesterFactory.level = SEVERE\norg.apache.catalina.util.LifecycleBase.level = SEVERE\norg.eclipse.jetty.util.component.AbstractLifeCycle.level = SEVERE\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging.properties",
    "content": "handlers =java.util.logging.ConsoleHandler\n.level = INFO\n\njava.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter\njava.util.logging.ConsoleHandler.level = ALL\n\norg.hibernate.validator.internal.util.Version.level = WARNING\norg.apache.coyote.http11.Http11NioProtocol.level = WARNING\norg.apache.tomcat.util.net.NioSelectorPool.level = WARNING\norg.apache.catalina.startup.DigesterFactory.level = SEVERE\norg.apache.catalina.util.LifecycleBase.level = SEVERE\norg.eclipse.jetty.util.component.AbstractLifeCycle.level = SEVERE\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"WARN\">\n\t<Properties>\n\t\t<Property name=\"LOG_EXCEPTION_CONVERSION_WORD\">%xwEx</Property>\n\t\t<Property name=\"LOG_LEVEL_PATTERN\">%5p</Property>\n\t\t<Property name=\"LOG_DATEFORMAT_PATTERN\">yyyy-MM-dd'T'HH:mm:ss.SSSXXX</Property>\n\t\t<Property name=\"CONSOLE_LOG_PATTERN\">%clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{--- %esb{${sys:APPLICATION_NAME:-}}%esb{${sys:APPLICATION_GROUP:-}}[%15.15t] ${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>\n\t\t<Property name=\"FILE_LOG_PATTERN\">%d{${sys:LOG_DATEFORMAT_PATTERN}} ${sys:LOG_LEVEL_PATTERN} %pid --- %esb{${sys:APPLICATION_NAME:-}}%esb{${sys:APPLICATION_GROUP:-}}[%t] ${sys:LOG_CORRELATION_PATTERN:-}%-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>\n\t\t<Property name=\"LOG4J2_ROLLINGPOLICY_FILE_NAME_PATTERN\" value=\"${sys:LOG_FILE}.%d{yyyy-MM-dd}.%i.gz\"/>\n\t</Properties>\n\t<Appenders>\n\t\t<Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n\t\t\t<Select>\n\t\t\t\t<SystemPropertyArbiter propertyName=\"CONSOLE_LOG_STRUCTURED_FORMAT\">\n\t\t\t\t\t<StructuredLogLayout format=\"${sys:CONSOLE_LOG_STRUCTURED_FORMAT}\" charset=\"${sys:CONSOLE_LOG_CHARSET}\"/>\n\t\t\t\t</SystemPropertyArbiter>\n\t\t\t\t<DefaultArbiter>\n\t\t\t\t\t<PatternLayout pattern=\"${sys:CONSOLE_LOG_PATTERN}\" charset=\"${sys:CONSOLE_LOG_CHARSET}\"/>\n\t\t\t\t</DefaultArbiter>\n\t\t\t</Select>\n\t\t\t<Filters>\n\t\t\t\t<ThresholdFilter level=\"${sys:CONSOLE_LOG_THRESHOLD:-TRACE}\"/>\n\t\t\t</Filters>\n\t\t</Console>\n\t\t<RollingFile name=\"File\" fileName=\"${sys:LOG_FILE}\" filePattern=\"${sys:LOG4J2_ROLLINGPOLICY_FILE_NAME_PATTERN}\">\n\t\t\t<Select>\n\t\t\t\t<SystemPropertyArbiter propertyName=\"FILE_LOG_STRUCTURED_FORMAT\">\n\t\t\t\t\t<StructuredLogLayout format=\"${sys:FILE_LOG_STRUCTURED_FORMAT}\" charset=\"${sys:FILE_LOG_CHARSET}\"/>\n\t\t\t\t</SystemPropertyArbiter>\n\t\t\t\t<DefaultArbiter>\n\t\t\t\t\t<PatternLayout pattern=\"${sys:FILE_LOG_PATTERN}\" charset=\"${sys:FILE_LOG_CHARSET}\"/>\n\t\t\t\t</DefaultArbiter>\n\t\t\t</Select>\n\t\t\t<Filters>\n\t\t\t\t<ThresholdFilter level=\"${sys:FILE_LOG_THRESHOLD:-TRACE}\"/>\n\t\t\t</Filters>\n\t\t\t<Policies>\n\t\t\t\t<SpringBootTriggeringPolicy\n\t\t\t\t\tstrategy=\"${sys:LOG4J2_ROLLINGPOLICY_STRATEGY:-size}\"\n\t\t\t\t\tmaxFileSize=\"${sys:LOG4J2_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}\"\n\t\t\t\t\ttimeInterval=\"${sys:LOG4J2_ROLLINGPOLICY_TIME_INTERVAL:-1}\"\n\t\t\t\t\ttimeModulate=\"${sys:LOG4J2_ROLLINGPOLICY_TIME_MODULATE:-false}\"\n\t\t\t\t\tcronExpression=\"${sys:LOG4J2_ROLLINGPOLICY_CRON}\"/>\n\t\t\t</Policies>\n\t\t\t<DefaultRolloverStrategy max=\"${sys:LOG4J2_ROLLINGPOLICY_MAX_HISTORY:-7}\"/>\n\t\t</RollingFile>\n\t</Appenders>\n\t<Loggers>\n\t\t<Logger name=\"org.apache.catalina.startup.DigesterFactory\" level=\"ERROR\"/>\n\t\t<Logger name=\"org.apache.catalina.util.LifecycleBase\" level=\"ERROR\"/>\n\t\t<Logger name=\"org.apache.coyote.http11.Http11NioProtocol\" level=\"WARN\"/>\n\t\t<Logger name=\"org.apache.sshd.common.util.SecurityUtils\" level=\"WARN\"/>\n\t\t<Logger name=\"org.apache.tomcat.util.net.NioSelectorPool\" level=\"WARN\"/>\n\t\t<Logger name=\"org.eclipse.jetty.util.component.AbstractLifeCycle\" level=\"ERROR\"/>\n\t\t<Logger name=\"org.hibernate.validator.internal.util.Version\" level=\"WARN\"/>\n\t\t<Logger name=\"org.springframework.boot.actuate.endpoint.jmx\" level=\"WARN\"/>\n\t\t<Root level=\"INFO\">\n\t\t\t<AppenderRef ref=\"Console\"/>\n\t\t\t<AppenderRef ref=\"File\"/>\n\t\t</Root>\n\t</Loggers>\n</Configuration>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"WARN\">\n\t<Properties>\n\t\t<Property name=\"LOG_EXCEPTION_CONVERSION_WORD\">%xwEx</Property>\n\t\t<Property name=\"LOG_LEVEL_PATTERN\">%5p</Property>\n\t\t<Property name=\"LOG_DATEFORMAT_PATTERN\">yyyy-MM-dd'T'HH:mm:ss.SSSXXX</Property>\n\t\t<Property name=\"CONSOLE_LOG_PATTERN\">%clr{%d{${sys:LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${sys:LOG_LEVEL_PATTERN}} %clr{%pid}{magenta} %clr{--- %esb{${sys:APPLICATION_NAME:-}}%esb{${sys:APPLICATION_GROUP:-}}[%15.15t] ${sys:LOG_CORRELATION_PATTERN:-}}{faint}%clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>\n\t</Properties>\n\t<Appenders>\n\t\t<Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n\t\t\t<Select>\n\t\t\t\t<SystemPropertyArbiter propertyName=\"CONSOLE_LOG_STRUCTURED_FORMAT\">\n\t\t\t\t\t<StructuredLogLayout format=\"${sys:CONSOLE_LOG_STRUCTURED_FORMAT}\" charset=\"${sys:CONSOLE_LOG_CHARSET}\"/>\n\t\t\t\t</SystemPropertyArbiter>\n\t\t\t\t<DefaultArbiter>\n\t\t\t\t\t<PatternLayout pattern=\"${sys:CONSOLE_LOG_PATTERN}\" charset=\"${sys:CONSOLE_LOG_CHARSET}\"/>\n\t\t\t\t</DefaultArbiter>\n\t\t\t</Select>\n\t\t\t<Filters>\n\t\t\t\t<ThresholdFilter level=\"${sys:CONSOLE_LOG_THRESHOLD:-TRACE}\"/>\n\t\t\t</Filters>\n\t\t</Console>\n\t</Appenders>\n\t<Loggers>\n\t\t<Logger name=\"org.apache.catalina.startup.DigesterFactory\" level=\"ERROR\"/>\n\t\t<Logger name=\"org.apache.catalina.util.LifecycleBase\" level=\"ERROR\"/>\n\t\t<Logger name=\"org.apache.coyote.http11.Http11NioProtocol\" level=\"WARN\"/>\n\t\t<Logger name=\"org.apache.sshd.common.util.SecurityUtils\" level=\"WARN\"/>\n\t\t<Logger name=\"org.apache.tomcat.util.net.NioSelectorPool\" level=\"WARN\"/>\n\t\t<Logger name=\"org.eclipse.jetty.util.component.AbstractLifeCycle\" level=\"ERROR\"/>\n\t\t<Logger name=\"org.hibernate.validator.internal.util.Version\" level=\"WARN\"/>\n\t\t<Logger name=\"org.springframework.boot.actuate.endpoint.jmx\" level=\"WARN\"/>\n\t\t<Root level=\"INFO\">\n\t\t\t<AppenderRef ref=\"Console\"/>\n\t\t</Root>\n\t</Loggers>\n</Configuration>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/base.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\nBase logback configuration provided for compatibility with Spring Boot 1.1\n-->\n\n<included>\n\t<include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\t<property name=\"LOG_FILE\" value=\"${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}\"/>\n\t<include resource=\"org/springframework/boot/logging/logback/console-appender.xml\"/>\n\t<include resource=\"org/springframework/boot/logging/logback/file-appender.xml\"/>\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t<appender-ref ref=\"FILE\"/>\n\t</root>\n</included>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/console-appender.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\nConsole appender logback configuration provided for import, equivalent to the programmatic\ninitialization performed by Boot\n-->\n\n<included>\n\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>${CONSOLE_LOG_THRESHOLD}</level>\n\t\t</filter>\n\t\t<encoder>\n\t\t\t<pattern>${CONSOLE_LOG_PATTERN}</pattern>\n\t\t\t<charset>${CONSOLE_LOG_CHARSET}</charset>\n\t\t</encoder>\n\t</appender>\n</included>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\nDefault logback configuration provided for import\n-->\n\n<included>\n\t<conversionRule conversionWord=\"clr\" class=\"org.springframework.boot.logging.logback.ColorConverter\"/>\n\t<conversionRule conversionWord=\"correlationId\" class=\"org.springframework.boot.logging.logback.CorrelationIdConverter\"/>\n\t<conversionRule conversionWord=\"esb\" class=\"org.springframework.boot.logging.logback.EnclosedInSquareBracketsConverter\" />\n\t<conversionRule conversionWord=\"wex\" class=\"org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter\" />\n\t<conversionRule conversionWord=\"wEx\" class=\"org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter\" />\n\n\t<property name=\"CONSOLE_LOG_PATTERN\" value=\"${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}){} %clr(${PID:-}){magenta} %clr(--- %esb(){APPLICATION_NAME}%esb{APPLICATION_GROUP}[%15.15t] ${LOG_CORRELATION_PATTERN:-}){faint}%clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\"/>\n\t<property name=\"CONSOLE_LOG_CHARSET\" value=\"${CONSOLE_LOG_CHARSET:-${file.encoding:-UTF-8}}\"/>\n\t<property name=\"CONSOLE_LOG_THRESHOLD\" value=\"${CONSOLE_LOG_THRESHOLD:-TRACE}\"/>\n\t<property name=\"CONSOLE_LOG_STRUCTURED_FORMAT\" value=\"${CONSOLE_LOG_STRUCTURED_FORMAT:-}\"/>\n\t<property name=\"FILE_LOG_PATTERN\" value=\"${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd'T'HH:mm:ss.SSSXXX}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:-} --- %esb(){APPLICATION_NAME}%esb{APPLICATION_GROUP}[%t] ${LOG_CORRELATION_PATTERN:-}%-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}\"/>\n\t<property name=\"FILE_LOG_CHARSET\" value=\"${FILE_LOG_CHARSET:-${file.encoding:-UTF-8}}\"/>\n\t<property name=\"FILE_LOG_THRESHOLD\" value=\"${FILE_LOG_THRESHOLD:-TRACE}\"/>\n\t<property name=\"FILE_LOG_STRUCTURED_FORMAT\" value=\"${FILE_LOG_STRUCTURED_FORMAT:-}\"/>\n\n\t<logger name=\"org.apache.catalina.startup.DigesterFactory\" level=\"ERROR\"/>\n\t<logger name=\"org.apache.catalina.util.LifecycleBase\" level=\"ERROR\"/>\n\t<logger name=\"org.apache.coyote.http11.Http11NioProtocol\" level=\"WARN\"/>\n\t<logger name=\"org.apache.sshd.common.util.SecurityUtils\" level=\"WARN\"/>\n\t<logger name=\"org.apache.tomcat.util.net.NioSelectorPool\" level=\"WARN\"/>\n\t<logger name=\"org.eclipse.jetty.util.component.AbstractLifeCycle\" level=\"ERROR\"/>\n\t<logger name=\"org.hibernate.validator.internal.util.Version\" level=\"WARN\"/>\n\t<logger name=\"org.springframework.boot.actuate.endpoint.jmx\" level=\"WARN\"/>\n</included>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/file-appender.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\nFile appender logback configuration provided for import, equivalent to the programmatic\ninitialization performed by Boot\n-->\n\n<included>\n\t<appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>${FILE_LOG_THRESHOLD}</level>\n\t\t</filter>\n\t\t<encoder>\n\t\t\t<pattern>${FILE_LOG_PATTERN}</pattern>\n\t\t\t<charset>${FILE_LOG_CHARSET}</charset>\n\t\t</encoder>\n\t\t<file>${LOG_FILE}</file>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\">\n\t\t\t<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>\n\t\t\t<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>\n\t\t\t<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>\n\t\t\t<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>\n\t\t\t<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}</maxHistory>\n\t\t</rollingPolicy>\n\t</appender>\n</included>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-console-appender.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\nConsole appender with structured logging logback configuration provided for import,\nequivalent to the programmatic initialization performed by Boot\n-->\n\n<included>\n\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>${CONSOLE_LOG_THRESHOLD}</level>\n\t\t</filter>\n\t\t<encoder class=\"org.springframework.boot.logging.logback.StructuredLogEncoder\">\n\t\t\t<format>${CONSOLE_LOG_STRUCTURED_FORMAT}</format>\n\t\t\t<charset>${CONSOLE_LOG_CHARSET}</charset>\n\t\t</encoder>\n\t</appender>\n</included>\n"
  },
  {
    "path": "core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-file-appender.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\nFile appender with structured logging logback configuration provided for import,\nequivalent to the programmatic initialization performed by Boot\n-->\n\n<included>\n\t<appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n\t\t\t<level>${FILE_LOG_THRESHOLD}</level>\n\t\t</filter>\n\t\t<encoder class=\"org.springframework.boot.logging.logback.StructuredLogEncoder\">\n\t\t\t<format>${FILE_LOG_STRUCTURED_FORMAT}</format>\n\t\t\t<charset>${FILE_LOG_CHARSET}</charset>\n\t\t</encoder>\n\t\t<file>${LOG_FILE}</file>\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy\">\n\t\t\t<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>\n\t\t\t<cleanHistoryOnStart>${LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START:-false}</cleanHistoryOnStart>\n\t\t\t<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>\n\t\t\t<totalSizeCap>${LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP:-0}</totalSizeCap>\n\t\t\t<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-7}</maxHistory>\n\t\t</rollingPolicy>\n\t</appender>\n</included>\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ApplicationEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * Tests for {@link ApplicationEnvironment}.\n *\n * @author Phillip Webb\n */\nclass ApplicationEnvironmentTests extends AbstractApplicationEnvironmentTests {\n\n\t@Override\n\tprotected StandardEnvironment createEnvironment() {\n\t\treturn new ApplicationEnvironment();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ApplicationInfoPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.system.ApplicationPid;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ApplicationInfoPropertySource}.\n *\n * @author Moritz Halbritter\n */\nclass ApplicationInfoPropertySourceTests {\n\n\t@Test\n\tvoid shouldAddVersion() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources().addLast(new ApplicationInfoPropertySource(\"1.2.3\"));\n\t\tassertThat(environment.getProperty(\"spring.application.version\")).isEqualTo(\"1.2.3\");\n\t}\n\n\t@Test\n\tvoid shouldNotAddVersionIfVersionIsNotAvailable() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources().addLast(new ApplicationInfoPropertySource((String) null));\n\t\tassertThat(environment.containsProperty(\"spring.application.version\")).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldAddPid() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources().addLast(new ApplicationInfoPropertySource(\"1.2.3\"));\n\t\tassertThat(environment.getProperty(\"spring.application.pid\", Long.class))\n\t\t\t.isEqualTo(new ApplicationPid().toLong());\n\t}\n\n\t@Test\n\tvoid shouldMoveToEnd() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources().addFirst(new MapPropertySource(\"first\", Collections.emptyMap()));\n\t\tenvironment.getPropertySources().addAfter(\"first\", new MapPropertySource(\"second\", Collections.emptyMap()));\n\t\tenvironment.getPropertySources().addFirst(new ApplicationInfoPropertySource(\"1.2.3\"));\n\t\tList<String> propertySources = environment.getPropertySources().stream().map(PropertySource::getName).toList();\n\t\tassertThat(propertySources).containsExactly(\"applicationInfo\", \"first\", \"second\", \"mockProperties\");\n\t\tApplicationInfoPropertySource.moveToEnd(environment);\n\t\tList<String> propertySourcesAfterMove = environment.getPropertySources()\n\t\t\t.stream()\n\t\t\t.map(PropertySource::getName)\n\t\t\t.toList();\n\t\tassertThat(propertySourcesAfterMove).containsExactly(\"first\", \"second\", \"mockProperties\", \"applicationInfo\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ApplicationPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.ApplicationProperties.ApplicationPropertiesRuntimeHints;\nimport org.springframework.boot.Banner.Mode;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ApplicationProperties}.\n *\n * @author Moritz Halbritter\n */\nclass ApplicationPropertiesTests {\n\n\t@Test\n\tvoid bannerModeShouldBeConsoleIfStructuredLoggingIsNotEnabled() {\n\t\tApplicationProperties properties = new ApplicationProperties();\n\t\tassertThat(properties.getBannerMode(new MockEnvironment())).isEqualTo(Mode.CONSOLE);\n\t}\n\n\t@Test\n\tvoid bannerModeShouldBeOffIfStructuredLoggingIsEnabled() {\n\t\tApplicationProperties properties = new ApplicationProperties();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.format.console\", \"ecs\");\n\t\tassertThat(properties.getBannerMode(environment)).isEqualTo(Mode.OFF);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ApplicationPropertiesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ApplicationProperties.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ApplicationProperties.class, \"setBannerMode\"))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ApplicationProperties.class, \"getSources\"))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ApplicationProperties.class, \"setSources\"))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ApplicationProperties.class, \"getBannerMode\"))\n\t\t\t.rejects(hints);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/BannerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.PrintStream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.Banner.Mode;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\n/**\n * Tests for {@link Banner} and its usage by {@link SpringApplication}.\n *\n * @author Phillip Webb\n * @author Michael Stummvoll\n * @author Michael Simons\n */\n@ExtendWith({ MockitoExtension.class, OutputCaptureExtension.class })\nclass BannerTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Captor\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ArgumentCaptor<Class<?>> sourceClassCaptor;\n\n\t@Test\n\tvoid testDefaultBanner(CapturedOutput output) {\n\t\tSpringApplication application = createSpringApplication();\n\t\tthis.context = application.run();\n\t\tassertThat(output).contains(\":: Spring Boot ::\");\n\t}\n\n\t@Test\n\tvoid testDefaultBannerInLog(CapturedOutput output) {\n\t\tSpringApplication application = createSpringApplication();\n\t\tthis.context = application.run();\n\t\tassertThat(output).contains(\":: Spring Boot ::\");\n\t}\n\n\t@Test\n\tvoid testCustomBanner(CapturedOutput output) {\n\t\tSpringApplication application = createSpringApplication();\n\t\tapplication.setBanner(new DummyBanner());\n\t\tthis.context = application.run();\n\t\tassertThat(output).contains(\"My Banner\");\n\t}\n\n\t@Test\n\tvoid testBannerInContext() {\n\t\tSpringApplication application = createSpringApplication();\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.containsBean(\"springBootBanner\")).isTrue();\n\t}\n\n\t@Test\n\tvoid testCustomBannerInContext() {\n\t\tSpringApplication application = createSpringApplication();\n\t\tBanner banner = mock(Banner.class);\n\t\tapplication.setBanner(banner);\n\t\tthis.context = application.run();\n\t\tBanner printedBanner = (Banner) this.context.getBean(\"springBootBanner\");\n\t\tassertThat(printedBanner).hasFieldOrPropertyWithValue(\"banner\", banner);\n\t\tthen(banner).should()\n\t\t\t.printBanner(any(Environment.class), this.sourceClassCaptor.capture(), any(PrintStream.class));\n\t\treset(banner);\n\t\tprintedBanner.printBanner(this.context.getEnvironment(), null, System.out);\n\t\tthen(banner).should()\n\t\t\t.printBanner(any(Environment.class), eq(this.sourceClassCaptor.getValue()), any(PrintStream.class));\n\t}\n\n\t@Test\n\tvoid testDisableBannerInContext() {\n\t\tSpringApplication application = createSpringApplication();\n\t\tapplication.setBannerMode(Mode.OFF);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.containsBean(\"springBootBanner\")).isFalse();\n\t}\n\n\tprivate SpringApplication createSpringApplication() {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\treturn application;\n\t}\n\n\tstatic class DummyBanner implements Banner {\n\n\t\t@Override\n\t\tpublic void printBanner(Environment environment, @Nullable Class<?> sourceClass, PrintStream out) {\n\t\t\tout.println(\"My Banner\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/BeanDefinitionLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport sampleconfig.MyComponentInPackageWithoutDot;\n\nimport org.springframework.boot.sampleconfig.MyComponent;\nimport org.springframework.boot.sampleconfig.MyNamedComponent;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BeanDefinitionLoader}.\n *\n * @author Phillip Webb\n * @author Vladislav Kisel\n */\nclass BeanDefinitionLoaderTests {\n\n\tprivate StaticApplicationContext registry;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.registry = new StaticApplicationContext();\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tthis.registry.close();\n\t}\n\n\t@Test\n\tvoid loadClass() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, MyComponent.class);\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myComponent\")).isTrue();\n\t}\n\n\t@Test\n\tvoid anonymousClassNotLoaded() {\n\t\tMyComponent myComponent = new MyComponent() {\n\n\t\t};\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, myComponent.getClass());\n\t\tassertThat(load(loader)).isZero();\n\t}\n\n\t@Test\n\tvoid loadJsr330Class() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, MyNamedComponent.class);\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myNamedComponent\")).isTrue();\n\t}\n\n\t@Test\n\t@WithSampleBeansXmlResource\n\tvoid loadXmlResource() {\n\t\tClassPathResource resource = new ClassPathResource(\"org/springframework/boot/sample-beans.xml\");\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, resource);\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myXmlComponent\")).isTrue();\n\n\t}\n\n\t@Test\n\t@WithResource(name = \"org/springframework/boot/sample-beans.groovy\", content = \"\"\"\n\t\t\timport org.springframework.boot.sampleconfig.MyComponent;\n\n\t\t\tbeans {\n\t\t\t\tmyGroovyComponent(MyComponent) {}\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid loadGroovyResource() {\n\t\tClassPathResource resource = new ClassPathResource(\"org/springframework/boot/sample-beans.groovy\");\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, resource);\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myGroovyComponent\")).isTrue();\n\n\t}\n\n\t@Test\n\t@WithResource(name = \"org/springframework/boot/sample-namespace.groovy\", content = \"\"\"\n\t\t\timport org.springframework.boot.sampleconfig.MyComponent;\n\n\t\t\tbeans {\n\t\t\t\txmlns([ctx:'http://www.springframework.org/schema/context'])\n\t\t\t\tctx.'component-scan'('base-package':'nonexistent')\n\t\t\t\tmyGroovyComponent(MyComponent) {}\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid loadGroovyResourceWithNamespace() {\n\t\tClassPathResource resource = new ClassPathResource(\"org/springframework/boot/sample-namespace.groovy\");\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, resource);\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myGroovyComponent\")).isTrue();\n\n\t}\n\n\t@Test\n\tvoid loadPackage() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, MyComponent.class.getPackage());\n\t\tassertThat(load(loader)).isEqualTo(2);\n\t\tassertThat(this.registry.containsBean(\"myComponent\")).isTrue();\n\t\tassertThat(this.registry.containsBean(\"myNamedComponent\")).isTrue();\n\t}\n\n\t@Test\n\tvoid loadClassName() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, MyComponent.class.getName());\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myComponent\")).isTrue();\n\t}\n\n\t@Test\n\t@WithSampleBeansXmlResource\n\tvoid loadXmlName() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry,\n\t\t\t\t\"classpath:org/springframework/boot/sample-beans.xml\");\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myXmlComponent\")).isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"org/springframework/boot/sample-beans.groovy\", content = \"\"\"\n\t\t\timport org.springframework.boot.sampleconfig.MyComponent;\n\n\t\t\tbeans {\n\t\t\t\tmyGroovyComponent(MyComponent) {}\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid loadGroovyName() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry,\n\t\t\t\t\"classpath:org/springframework/boot/sample-beans.groovy\");\n\t\tassertThat(load(loader)).isOne();\n\t\tassertThat(this.registry.containsBean(\"myGroovyComponent\")).isTrue();\n\t}\n\n\t@Test\n\tvoid loadPackageName() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, MyComponent.class.getPackage().getName());\n\t\tassertThat(load(loader)).isEqualTo(2);\n\t\tassertThat(this.registry.containsBean(\"myComponent\")).isTrue();\n\t\tassertThat(this.registry.containsBean(\"myNamedComponent\")).isTrue();\n\t}\n\n\t@Test\n\tvoid loadPackageNameWithoutDot() {\n\t\t// See gh-6126\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry,\n\t\t\t\tMyComponentInPackageWithoutDot.class.getPackage().getName());\n\t\tint loaded = load(loader);\n\t\tassertThat(loaded).isOne();\n\t\tassertThat(this.registry.containsBean(\"myComponentInPackageWithoutDot\")).isTrue();\n\t}\n\n\t@Test\n\tvoid loadPackageAndClassDoesNotDoubleAdd() {\n\t\tBeanDefinitionLoader loader = new BeanDefinitionLoader(this.registry, MyComponent.class.getPackage(),\n\t\t\t\tMyComponent.class);\n\t\tassertThat(load(loader)).isEqualTo(2);\n\t\tassertThat(this.registry.containsBean(\"myComponent\")).isTrue();\n\t\tassertThat(this.registry.containsBean(\"myNamedComponent\")).isTrue();\n\t}\n\n\tprivate int load(BeanDefinitionLoader loader) {\n\t\tint beans = this.registry.getBeanDefinitionCount();\n\t\tloader.load();\n\t\treturn this.registry.getBeanDefinitionCount() - beans;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/DefaultApplicationArgumentsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DefaultApplicationArguments}.\n *\n * @author Phillip Webb\n */\nclass DefaultApplicationArgumentsTests {\n\n\tprivate static final String[] ARGS = new String[] { \"--foo=bar\", \"--foo=baz\", \"--debug\", \"spring\", \"boot\" };\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid argumentsMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DefaultApplicationArguments((String[]) null))\n\t\t\t.withMessageContaining(\"'args' must not be null\");\n\t}\n\n\t@Test\n\tvoid getArgs() {\n\t\tApplicationArguments arguments = new DefaultApplicationArguments(ARGS);\n\t\tassertThat(arguments.getSourceArgs()).isEqualTo(ARGS);\n\t}\n\n\t@Test\n\tvoid optionNames() {\n\t\tApplicationArguments arguments = new DefaultApplicationArguments(ARGS);\n\t\tSet<String> expected = new HashSet<>(Arrays.asList(\"foo\", \"debug\"));\n\t\tassertThat(arguments.getOptionNames()).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid containsOption() {\n\t\tApplicationArguments arguments = new DefaultApplicationArguments(ARGS);\n\t\tassertThat(arguments.containsOption(\"foo\")).isTrue();\n\t\tassertThat(arguments.containsOption(\"debug\")).isTrue();\n\t\tassertThat(arguments.containsOption(\"spring\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getOptionValues() {\n\t\tApplicationArguments arguments = new DefaultApplicationArguments(ARGS);\n\t\tassertThat(arguments.getOptionValues(\"foo\")).isEqualTo(Arrays.asList(\"bar\", \"baz\"));\n\t\tassertThat(arguments.getOptionValues(\"debug\")).isEmpty();\n\t\tassertThat(arguments.getOptionValues(\"spring\")).isNull();\n\t}\n\n\t@Test\n\tvoid getNonOptionArgs() {\n\t\tApplicationArguments arguments = new DefaultApplicationArguments(ARGS);\n\t\tassertThat(arguments.getNonOptionArgs()).containsExactly(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getNoNonOptionArgs() {\n\t\tApplicationArguments arguments = new DefaultApplicationArguments(\"--debug\");\n\t\tassertThat(arguments.getNonOptionArgs()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/EnvironmentConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.core.env.AbstractEnvironment;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EnvironmentConverter}.\n *\n * @author Ethan Rubinson\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass EnvironmentConverterTests {\n\n\tprivate final EnvironmentConverter environmentConverter = new EnvironmentConverter(getClass().getClassLoader());\n\n\t@Test\n\tvoid convertedEnvironmentHasSameActiveProfiles() {\n\t\tAbstractEnvironment originalEnvironment = new MockEnvironment();\n\t\toriginalEnvironment.setActiveProfiles(\"activeProfile1\", \"activeProfile2\");\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(originalEnvironment, StandardEnvironment.class);\n\t\tassertThat(convertedEnvironment.getActiveProfiles()).containsExactly(\"activeProfile1\", \"activeProfile2\");\n\t}\n\n\t@Test\n\tvoid convertedEnvironmentHasSameConversionService() {\n\t\tAbstractEnvironment originalEnvironment = new MockEnvironment();\n\t\tConfigurableConversionService conversionService = mock(ConfigurableConversionService.class);\n\t\toriginalEnvironment.setConversionService(conversionService);\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(originalEnvironment, StandardEnvironment.class);\n\t\tassertThat(convertedEnvironment.getConversionService()).isEqualTo(conversionService);\n\t}\n\n\t@Test\n\tvoid envClassSameShouldReturnEnvironmentUnconverted() {\n\t\tStandardEnvironment standardEnvironment = new StandardEnvironment();\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(standardEnvironment, StandardEnvironment.class);\n\t\tassertThat(convertedEnvironment).isSameAs(standardEnvironment);\n\t}\n\n\t@Test\n\tvoid standardServletEnvironmentIsConverted() {\n\t\tStandardServletEnvironment standardServletEnvironment = new StandardServletEnvironment();\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(standardServletEnvironment, StandardEnvironment.class);\n\t\tassertThat(convertedEnvironment).isNotSameAs(standardServletEnvironment);\n\t}\n\n\t@Test\n\tvoid servletPropertySourcesAreNotCopiedOverIfNotWebEnvironment() {\n\t\tStandardServletEnvironment standardServletEnvironment = new StandardServletEnvironment();\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(standardServletEnvironment, StandardEnvironment.class);\n\t\tassertThat(convertedEnvironment).isNotSameAs(standardServletEnvironment);\n\t\tSet<String> names = new HashSet<>();\n\t\tfor (PropertySource<?> propertySource : convertedEnvironment.getPropertySources()) {\n\t\t\tnames.add(propertySource.getName());\n\t\t}\n\t\tassertThat(names).doesNotContain(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,\n\t\t\t\tStandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,\n\t\t\t\tStandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME);\n\t}\n\n\t@Test\n\tvoid envClassSameShouldReturnEnvironmentUnconvertedEvenForWeb() {\n\t\tStandardServletEnvironment standardServletEnvironment = new StandardServletEnvironment();\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(standardServletEnvironment, StandardServletEnvironment.class);\n\t\tassertThat(convertedEnvironment).isSameAs(standardServletEnvironment);\n\t}\n\n\t@Test\n\tvoid servletPropertySourcesArePresentWhenTypeToConvertIsWeb() {\n\t\tStandardEnvironment standardEnvironment = new StandardEnvironment();\n\t\tConfigurableEnvironment convertedEnvironment = this.environmentConverter\n\t\t\t.convertEnvironmentIfNecessary(standardEnvironment, StandardServletEnvironment.class);\n\t\tassertThat(convertedEnvironment).isNotSameAs(standardEnvironment);\n\t\tSet<String> names = new HashSet<>();\n\t\tfor (PropertySource<?> propertySource : convertedEnvironment.getPropertySources()) {\n\t\t\tnames.add(propertySource.getName());\n\t\t}\n\t\tassertThat(names).contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,\n\t\t\t\tStandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ExitCodeGeneratorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.Ordered;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link ExitCodeGenerators}.\n *\n * @author Phillip Webb\n */\nclass ExitCodeGeneratorsTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addAllWhenGeneratorsIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> {\n\t\t\tList<ExitCodeGenerator> generators = null;\n\t\t\tnew ExitCodeGenerators().addAll(generators);\n\t\t}).withMessageContaining(\"'generators' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addWhenGeneratorIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ExitCodeGenerators().add(null))\n\t\t\t.withMessageContaining(\"'generator' must not be null\");\n\t}\n\n\t@Test\n\tvoid getExitCodeWhenNoGeneratorsShouldReturnZero() {\n\t\tassertThat(new ExitCodeGenerators().getExitCode()).isZero();\n\t}\n\n\t@Test\n\tvoid getExitCodeWhenGeneratorThrowsShouldReturnOne() {\n\t\tExitCodeGenerator generator = mock(ExitCodeGenerator.class);\n\t\tgiven(generator.getExitCode()).willThrow(new IllegalStateException());\n\t\tExitCodeGenerators generators = new ExitCodeGenerators();\n\t\tgenerators.add(generator);\n\t\tassertThat(generators.getExitCode()).isOne();\n\t}\n\n\t@Test\n\tvoid getExitCodeWithUnorderedGeneratorsReturnsFirstNonZeroExitCode() {\n\t\tExitCodeGenerators generators = new ExitCodeGenerators();\n\t\tgenerators.add(mockGenerator(0));\n\t\tgenerators.add(mockGenerator(3));\n\t\tgenerators.add(mockGenerator(2));\n\t\tassertThat(generators.getExitCode()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid getExitCodeWhenUsingExitCodeExceptionMapperShouldCallMapper() {\n\t\tExitCodeGenerators generators = new ExitCodeGenerators();\n\t\tException e = new IOException();\n\t\tgenerators.add(e, mockMapper(IllegalStateException.class, 1));\n\t\tgenerators.add(e, mockMapper(IOException.class, 2));\n\t\tgenerators.add(e, mockMapper(UnsupportedOperationException.class, 3));\n\t\tassertThat(generators.getExitCode()).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid getExitCodeWithOrderedGeneratorsReturnsFirstNonZeroExitCode() {\n\t\tExitCodeGenerators generators = new ExitCodeGenerators();\n\t\tgenerators.add(orderedMockGenerator(0, 1));\n\t\tgenerators.add(orderedMockGenerator(1, 3));\n\t\tgenerators.add(orderedMockGenerator(2, 2));\n\t\tgenerators.add(mockGenerator(3));\n\t\tassertThat(generators.getExitCode()).isEqualTo(2);\n\t}\n\n\tprivate ExitCodeGenerator mockGenerator(int exitCode) {\n\t\tExitCodeGenerator generator = mock(ExitCodeGenerator.class);\n\t\tgiven(generator.getExitCode()).willReturn(exitCode);\n\t\treturn generator;\n\t}\n\n\tprivate ExitCodeGenerator orderedMockGenerator(int exitCode, int order) {\n\t\tExitCodeGenerator generator = mock(ExitCodeGenerator.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(generator.getExitCode()).willReturn(exitCode);\n\t\tgiven(((Ordered) generator).getOrder()).willReturn(order);\n\t\treturn generator;\n\t}\n\n\tprivate ExitCodeExceptionMapper mockMapper(Class<?> exceptionType, int exitCode) {\n\t\treturn (exception) -> {\n\t\t\tif (exceptionType.isInstance(exception)) {\n\t\t\t\treturn exitCode;\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/LazyInitializationBeanFactoryPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LazyInitializationBeanFactoryPostProcessor}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nclass LazyInitializationBeanFactoryPostProcessorTests {\n\n\t@Test\n\tvoid whenLazyInitializationIsEnabledThenNormalBeansAreNotInitializedUntilRequired() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());\n\t\t\tcontext.register(BeanState.class, ExampleBean.class);\n\t\t\tcontext.refresh();\n\t\t\tBeanState beanState = context.getBean(BeanState.class);\n\t\t\tassertThat(beanState.initializedBeans).isEmpty();\n\t\t\tcontext.getBean(ExampleBean.class);\n\t\t\tassertThat(beanState.initializedBeans).containsExactly(ExampleBean.class);\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenLazyInitializationIsEnabledThenSmartInitializingSingletonsAreInitializedDuringRefresh() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());\n\t\t\tcontext.register(BeanState.class, ExampleSmartInitializingSingleton.class);\n\t\t\tcontext.refresh();\n\t\t\tBeanState beanState = context.getBean(BeanState.class);\n\t\t\tassertThat(beanState.initializedBeans).containsExactly(ExampleSmartInitializingSingleton.class);\n\t\t\tassertThat(context.getBean(ExampleSmartInitializingSingleton.class).callbackInvoked).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenLazyInitializationIsEnabledThenInfrastructureRoleBeansAreInitializedDuringRefresh() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());\n\t\t\tcontext.register(BeanState.class);\n\t\t\tcontext.registerBean(ExampleBean.class,\n\t\t\t\t\t(definition) -> definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE));\n\t\t\tcontext.refresh();\n\t\t\tBeanState beanState = context.getBean(BeanState.class);\n\t\t\tassertThat(beanState.initializedBeans).containsExactly(ExampleBean.class);\n\t\t}\n\t}\n\n\tstatic class ExampleBean {\n\n\t\tExampleBean(BeanState beanState) {\n\t\t\tbeanState.initializedBeans.add(getClass());\n\t\t}\n\n\t}\n\n\tstatic class ExampleSmartInitializingSingleton implements SmartInitializingSingleton {\n\n\t\tprivate boolean callbackInvoked;\n\n\t\tExampleSmartInitializingSingleton(BeanState beanState) {\n\t\t\tbeanState.initializedBeans.add(getClass());\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterSingletonsInstantiated() {\n\t\t\tthis.callbackInvoked = true;\n\t\t}\n\n\t}\n\n\tstatic class BeanState {\n\n\t\tprivate final List<Class<?>> initializedBeans = new ArrayList<>();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/LazyInitializationExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LazyInitializationExcludeFilter}.\n *\n * @author Phillip Webb\n */\nclass LazyInitializationExcludeFilterTests {\n\n\t@Test\n\tvoid forBeanTypesMatchesTypes() {\n\t\tLazyInitializationExcludeFilter filter = LazyInitializationExcludeFilter.forBeanTypes(CharSequence.class,\n\t\t\t\tNumber.class);\n\t\tString beanName = \"test\";\n\t\tBeanDefinition beanDefinition = mock(BeanDefinition.class);\n\t\tassertThat(filter.isExcluded(beanName, beanDefinition, CharSequence.class)).isTrue();\n\t\tassertThat(filter.isExcluded(beanName, beanDefinition, String.class)).isTrue();\n\t\tassertThat(filter.isExcluded(beanName, beanDefinition, StringBuilder.class)).isTrue();\n\t\tassertThat(filter.isExcluded(beanName, beanDefinition, Number.class)).isTrue();\n\t\tassertThat(filter.isExcluded(beanName, beanDefinition, Long.class)).isTrue();\n\t\tassertThat(filter.isExcluded(beanName, beanDefinition, Boolean.class)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/MockApplicationEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.mock.env.MockEnvironment;\n\n/**\n * {@link MockEnvironment} with the same property overrides as\n * {@link ApplicationEnvironment}.\n *\n * @author Phillip Webb\n */\npublic class MockApplicationEnvironment extends MockEnvironment {\n\n\t@Override\n\tprotected @Nullable String doGetActiveProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected @Nullable String doGetDefaultProfilesProperty() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/OverrideSourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringApplication} {@link SpringApplication#setSources(java.util.Set)\n * source overrides}.\n *\n * @author Dave Syer\n */\nclass OverrideSourcesTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid beanInjectedToMainConfiguration() {\n\t\tthis.context = SpringApplication.run(new Class<?>[] { MainConfiguration.class },\n\t\t\t\tnew String[] { \"--spring.main.web-application-type=none\" });\n\t\tassertThat(this.context.getBean(Service.class).bean.name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid primaryBeanInjectedProvingSourcesNotOverridden() {\n\t\tthis.context = SpringApplication.run(new Class<?>[] { MainConfiguration.class, TestConfiguration.class },\n\t\t\t\tnew String[] { \"--spring.main.web-application-type=none\",\n\t\t\t\t\t\t\"--spring.main.allow-bean-definition-overriding=true\",\n\t\t\t\t\t\t\"--spring.main.sources=org.springframework.boot.OverrideSourcesTests.MainConfiguration\" });\n\t\tassertThat(this.context.getBean(Service.class).bean.name).isEqualTo(\"bar\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tTestBean another() {\n\t\t\treturn new TestBean(\"bar\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MainConfiguration {\n\n\t\t@Bean\n\t\tTestBean first() {\n\t\t\treturn new TestBean(\"foo\");\n\t\t}\n\n\t\t@Bean\n\t\tService Service() {\n\t\t\treturn new Service();\n\t\t}\n\n\t}\n\n\tstatic class Service {\n\n\t\t@Autowired\n\t\tprivate TestBean bean;\n\n\t}\n\n\tstatic class TestBean {\n\n\t\tprivate final String name;\n\n\t\tTestBean(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.PrintStream;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\nimport org.springframework.core.env.AbstractPropertyResolver;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ResourceBanner}.\n *\n * @author Phillip Webb\n * @author Vedran Pavic\n * @author Toshiaki Maki\n * @author Krzysztof Krason\n */\nclass ResourceBannerTests {\n\n\t@AfterEach\n\tvoid reset() {\n\t\tAnsiOutput.setEnabled(Enabled.DETECT);\n\t}\n\n\t@Test\n\tvoid renderVersions() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a} ${spring-boot.version} ${application.version}\".getBytes());\n\t\tString banner = printBanner(resource, \"10.2\", \"2.0\", null);\n\t\tassertThat(banner).startsWith(\"banner 1 10.2 2.0\");\n\t}\n\n\t@Test\n\tvoid renderWithoutVersions() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a} ${spring-boot.version} ${application.version}\".getBytes());\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"banner 1  \");\n\t}\n\n\t@Test\n\tvoid renderWithoutVersionsWithDefaultValues() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a} ${spring-boot.version:X.Y.Z} ${application.version:A.B.C}\".getBytes());\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"banner 1 X.Y.Z A.B.C\");\n\t}\n\n\t@Test\n\tvoid renderFormattedVersions() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a}${spring-boot.formatted-version}${application.formatted-version}\".getBytes());\n\t\tString banner = printBanner(resource, \"10.2\", \"2.0\", null);\n\t\tassertThat(banner).startsWith(\"banner 1 (v10.2) (v2.0)\");\n\t}\n\n\t@Test\n\tvoid renderWithoutFormattedVersions() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a} ${spring-boot.formatted-version} ${application.formatted-version}\".getBytes());\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"banner 1  \");\n\t}\n\n\t@Test\n\tvoid renderWithoutFormattedVersionsWithDefaultValues() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a} ${spring-boot.formatted-version:(vX.Y.Z)} ${application.formatted-version:(vA.B.C)}\"\n\t\t\t\t\t.getBytes());\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"banner 1 (vX.Y.Z) (vA.B.C)\");\n\t}\n\n\t@Test\n\tvoid renderWithColors() {\n\t\tResource resource = new ByteArrayResource(\"${Ansi.RED}This is red.${Ansi.NORMAL}\".getBytes());\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"\\u001B[31mThis is red.\\u001B[0m\");\n\t}\n\n\t@Test\n\tvoid renderWithColorsButDisabled() {\n\t\tResource resource = new ByteArrayResource(\"${Ansi.RED}This is red.${Ansi.NORMAL}\".getBytes());\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER);\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"This is red.\");\n\t}\n\n\t@Test\n\tvoid renderWith256Colors() {\n\t\tResource resource = new ByteArrayResource(\"${AnsiColor.208}This is orange.${Ansi.NORMAL}\".getBytes());\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"\\033[38;5;208mThis is orange.\\u001B[0m\");\n\t}\n\n\t@Test\n\tvoid renderWith256ColorsButDisabled() {\n\t\tResource resource = new ByteArrayResource(\"${AnsiColor.208}This is orange.${Ansi.NORMAL}\".getBytes());\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.NEVER);\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"This is orange.\");\n\t}\n\n\t@Test\n\tvoid renderWithTitle() {\n\t\tResource resource = new ByteArrayResource(\"banner ${application.title} ${a}\".getBytes());\n\t\tString banner = printBanner(resource, null, null, \"title\");\n\t\tassertThat(banner).startsWith(\"banner title 1\");\n\t}\n\n\t@Test\n\tvoid renderWithoutTitle() {\n\t\tResource resource = new ByteArrayResource(\"banner ${application.title} ${a}\".getBytes());\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"banner  1\");\n\t}\n\n\t@Test\n\tvoid renderWithoutTitleWithDefaultValue() {\n\t\tResource resource = new ByteArrayResource(\"banner ${application.title:Default Title} ${a}\".getBytes());\n\t\tString banner = printBanner(resource, null, null, null);\n\t\tassertThat(banner).startsWith(\"banner Default Title 1\");\n\t}\n\n\t@Test\n\tvoid renderWithDefaultValues() {\n\t\tResource resource = new ByteArrayResource(\n\t\t\t\t\"banner ${a:default-a} ${b:default-b} ${spring-boot.version:default-boot-version} ${application.version:default-application-version}\"\n\t\t\t\t\t.getBytes());\n\t\tString banner = printBanner(resource, \"10.2\", \"1.0\", null);\n\t\tassertThat(banner).startsWith(\"banner 1 default-b 10.2 1.0\");\n\t}\n\n\t@Test\n\tvoid renderWithMutation() {\n\t\tResource resource = new ByteArrayResource(\"banner ${foo}\".getBytes());\n\t\tString banner = printBanner(new MutatingResourceBanner(resource, \"1\", null), \"2\");\n\t\tassertThat(banner).startsWith(\"banner bar\");\n\t}\n\n\tprivate String printBanner(Resource resource, @Nullable String bootVersion, @Nullable String applicationVersion,\n\t\t\t@Nullable String applicationTitle) {\n\t\treturn printBanner(new MockResourceBanner(resource, bootVersion, applicationTitle), applicationVersion);\n\t}\n\n\tprivate String printBanner(ResourceBanner banner, @Nullable String applicationVersion) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tif (applicationVersion != null) {\n\t\t\tenvironment.setProperty(\"spring.application.version\", applicationVersion);\n\t\t}\n\t\tMap<String, Object> source = Collections.singletonMap(\"a\", \"1\");\n\t\tenvironment.getPropertySources().addLast(new MapPropertySource(\"map\", source));\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tbanner.printBanner(environment, getClass(), new PrintStream(out));\n\t\treturn out.toString();\n\t}\n\n\tstatic class MockResourceBanner extends ResourceBanner {\n\n\t\tprivate final @Nullable String bootVersion;\n\n\t\tprivate final @Nullable String applicationTitle;\n\n\t\tMockResourceBanner(Resource resource, @Nullable String bootVersion, @Nullable String applicationTitle) {\n\t\t\tsuper(resource);\n\t\t\tthis.bootVersion = bootVersion;\n\t\t\tthis.applicationTitle = applicationTitle;\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable String getBootVersion() {\n\t\t\treturn this.bootVersion;\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable String getApplicationTitle(@Nullable Class<?> sourceClass) {\n\t\t\treturn this.applicationTitle;\n\t\t}\n\n\t}\n\n\tstatic class MutatingResourceBanner extends MockResourceBanner {\n\n\t\tMutatingResourceBanner(Resource resource, String bootVersion, @Nullable String applicationTitle) {\n\t\t\tsuper(resource, bootVersion, applicationTitle);\n\t\t}\n\n\t\t@Override\n\t\tprotected List<PropertyResolver> getPropertyResolvers(Environment environment, @Nullable Class<?> sourceClass) {\n\t\t\tList<PropertyResolver> resolvers = super.getPropertyResolvers(environment, sourceClass);\n\t\t\tPropertyResolver resolver = new AbstractPropertyResolver() {\n\n\t\t\t\t@Override\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tpublic <T> @Nullable T getProperty(String key, Class<T> targetType) {\n\t\t\t\t\treturn String.class.equals(targetType) ? (T) getPropertyAsRawString(key) : null;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected @Nullable String getPropertyAsRawString(String key) {\n\t\t\t\t\treturn (\"foo\".equals(key)) ? \"bar\" : null;\n\t\t\t\t}\n\n\t\t\t};\n\t\t\tresolvers.add(resolver);\n\t\t\treturn resolvers;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SimpleMainTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SpringApplication} main method.\n *\n * @author Dave Syer\n */\n@Configuration(proxyBeanMethods = false)\n@ExtendWith(OutputCaptureExtension.class)\nclass SimpleMainTests {\n\n\tprivate static final String SPRING_STARTUP = \"Started SpringApplication in\";\n\n\t@Test\n\tvoid emptyApplicationContext() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> SpringApplication.main(getArgs()));\n\t}\n\n\t@Test\n\tvoid basePackageScan(CapturedOutput output) throws Exception {\n\t\tSpringApplication.main(getArgs(ClassUtils.getPackageName(getClass()) + \".sampleconfig\"));\n\t\tassertThat(output).contains(SPRING_STARTUP);\n\t}\n\n\t@Test\n\tvoid configClassContext(CapturedOutput output) throws Exception {\n\t\tSpringApplication.main(getArgs(getClass().getName()));\n\t\tassertThat(output).contains(SPRING_STARTUP);\n\t}\n\n\t@Test\n\t@WithSampleBeansXmlResource\n\tvoid xmlContext(CapturedOutput output) throws Exception {\n\t\tSpringApplication.main(getArgs(\"org/springframework/boot/sample-beans.xml\"));\n\t\tassertThat(output).contains(SPRING_STARTUP);\n\t}\n\n\t@Test\n\t@WithSampleBeansXmlResource\n\tvoid mixedContext(CapturedOutput output) throws Exception {\n\t\tSpringApplication.main(getArgs(getClass().getName(), \"org/springframework/boot/sample-beans.xml\"));\n\t\tassertThat(output).contains(SPRING_STARTUP);\n\t}\n\n\tprivate String[] getArgs(String... args) {\n\t\tList<String> list = new ArrayList<>(Arrays.asList(\"--spring.main.web-application-type=none\",\n\t\t\t\t\"--spring.main.show-banner=OFF\", \"--spring.main.register-shutdownHook=false\"));\n\t\tif (args.length > 0) {\n\t\t\tlist.add(\"--spring.main.sources=\" + StringUtils.arrayToCommaDelimitedString(args));\n\t\t}\n\t\treturn StringUtils.toStringArray(list);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.nio.file.Path;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.AbstractAotProcessor.Settings;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SpringApplicationAotProcessor}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass SpringApplicationAotProcessorTests {\n\n\tprivate static final ApplicationInvoker invoker = new ApplicationInvoker();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tinvoker.clean();\n\t}\n\n\t@Test\n\tvoid processApplicationInvokesMainMethod(@TempDir Path directory) {\n\t\tString[] arguments = new String[] { \"1\", \"2\" };\n\t\tSpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(PublicMainMethod.class,\n\t\t\t\tsettings(directory), arguments);\n\t\tprocessor.process();\n\t\tassertThat(ApplicationInvoker.argsHolder).isEqualTo(arguments);\n\t\tassertThat(ApplicationInvoker.postRunInvoked).isFalse();\n\t}\n\n\t@Test\n\tvoid processApplicationWithMainMethodThatDoesNotRun(@TempDir Path directory) {\n\t\tSpringApplicationAotProcessor processor = new SpringApplicationAotProcessor(BrokenApplication.class,\n\t\t\t\tsettings(directory), new String[0]);\n\t\tassertThatIllegalStateException().isThrownBy(processor::process)\n\t\t\t.withMessageContaining(\"Does it run a SpringApplication?\");\n\t\tassertThat(directory).isEmptyDirectory();\n\t}\n\n\t@Test\n\tvoid invokeMainParsesArgumentsAndInvokesMainMethod(@TempDir Path directory) throws Exception {\n\t\tString[] mainArguments = new String[] { PublicMainMethod.class.getName(),\n\t\t\t\tdirectory.resolve(\"source\").toString(), directory.resolve(\"resource\").toString(),\n\t\t\t\tdirectory.resolve(\"class\").toString(), \"com.example\", \"example\", \"1\", \"2\" };\n\t\tSpringApplicationAotProcessor.main(mainArguments);\n\t\tassertThat(ApplicationInvoker.argsHolder).containsExactly(\"1\", \"2\");\n\t\tassertThat(ApplicationInvoker.postRunInvoked).isFalse();\n\t}\n\n\t@Test\n\tvoid invokeMainParsesArgumentsAndInvokesPackagePrivateMainMethod(@TempDir Path directory) throws Exception {\n\t\tString[] mainArguments = new String[] { PackagePrivateMainMethod.class.getName(),\n\t\t\t\tdirectory.resolve(\"source\").toString(), directory.resolve(\"resource\").toString(),\n\t\t\t\tdirectory.resolve(\"class\").toString(), \"com.example\", \"example\", \"1\", \"2\" };\n\t\tSpringApplicationAotProcessor.main(mainArguments);\n\t\tassertThat(ApplicationInvoker.argsHolder).containsExactly(\"1\", \"2\");\n\t\tassertThat(ApplicationInvoker.postRunInvoked).isFalse();\n\t}\n\n\t@Test\n\tvoid invokeMainParsesArgumentsAndInvokesParameterLessMainMethod(@TempDir Path directory) throws Exception {\n\t\tString[] mainArguments = new String[] { PublicParameterlessMainMethod.class.getName(),\n\t\t\t\tdirectory.resolve(\"source\").toString(), directory.resolve(\"resource\").toString(),\n\t\t\t\tdirectory.resolve(\"class\").toString(), \"com.example\", \"example\", \"1\", \"2\" };\n\t\tSpringApplicationAotProcessor.main(mainArguments);\n\t\tassertThat(ApplicationInvoker.argsHolder).isNull();\n\t\tassertThat(ApplicationInvoker.postRunInvoked).isFalse();\n\t}\n\n\t@Test\n\tvoid invokeMainParsesArgumentsAndInvokesPackagePrivateRunMethod(@TempDir Path directory) throws Exception {\n\t\tString[] mainArguments = new String[] { PackagePrivateParameterlessMainMethod.class.getName(),\n\t\t\t\tdirectory.resolve(\"source\").toString(), directory.resolve(\"resource\").toString(),\n\t\t\t\tdirectory.resolve(\"class\").toString(), \"com.example\", \"example\", \"1\", \"2\" };\n\t\tSpringApplicationAotProcessor.main(mainArguments);\n\t\tassertThat(ApplicationInvoker.argsHolder).isNull();\n\t\tassertThat(ApplicationInvoker.postRunInvoked).isFalse();\n\t}\n\n\t@Test\n\tvoid invokeMainParsesArgumentsAndInvokesRunMethodWithoutGroupId(@TempDir Path directory) throws Exception {\n\t\tString[] mainArguments = new String[] { PublicMainMethod.class.getName(),\n\t\t\t\tdirectory.resolve(\"source\").toString(), directory.resolve(\"resource\").toString(),\n\t\t\t\tdirectory.resolve(\"class\").toString(), \"\", \"example\", \"1\", \"2\" };\n\t\tSpringApplicationAotProcessor.main(mainArguments);\n\t\tassertThat(ApplicationInvoker.argsHolder).containsExactly(\"1\", \"2\");\n\t\tassertThat(ApplicationInvoker.postRunInvoked).isFalse();\n\t}\n\n\t@Test\n\tvoid invokeMainWithMissingArguments() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> SpringApplicationAotProcessor.main(new String[] { \"Test\" }))\n\t\t\t.withMessageContaining(\"Usage:\");\n\t}\n\n\tprivate Settings settings(Path directory) {\n\t\treturn Settings.builder()\n\t\t\t.sourceOutput(directory.resolve(\"source\"))\n\t\t\t.resourceOutput(directory.resolve(\"resource\"))\n\t\t\t.classOutput(directory.resolve(\"class\"))\n\t\t\t.groupId(\"com.example\")\n\t\t\t.artifactId(\"example\")\n\t\t\t.build();\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class PublicMainMethod {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tinvoker.invoke(args, () -> SpringApplication.run(PublicMainMethod.class, args));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class PackagePrivateMainMethod {\n\n\t\tstatic void main(String[] args) {\n\t\t\tinvoker.invoke(args, () -> SpringApplication.run(PackagePrivateMainMethod.class, args));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class PublicParameterlessMainMethod {\n\n\t\tpublic static void main() {\n\t\t\tinvoker.invoke(null, () -> SpringApplication.run(PublicParameterlessMainMethod.class));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class PackagePrivateParameterlessMainMethod {\n\n\t\tstatic void main() {\n\t\t\tinvoker.invoke(null, () -> SpringApplication.run(PackagePrivateParameterlessMainMethod.class));\n\t\t}\n\n\t}\n\n\tpublic static class BrokenApplication {\n\n\t\tpublic static void main(String[] args) {\n\t\t\t// Does not run an application\n\t\t}\n\n\t}\n\n\tprivate static final class ApplicationInvoker {\n\n\t\tpublic static String @Nullable [] argsHolder;\n\n\t\tpublic static boolean postRunInvoked;\n\n\t\tvoid invoke(String @Nullable [] args, Runnable applicationRun) {\n\t\t\targsHolder = args;\n\t\t\tapplicationRun.run();\n\t\t\tpostRunInvoked = true;\n\t\t}\n\n\t\tvoid clean() {\n\t\t\targsHolder = null;\n\t\t\tpostRunInvoked = false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationBannerPrinterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.apache.commons.logging.Log;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringApplicationBannerPrinter}.\n *\n * @author Moritz Halbritter\n */\nclass SpringApplicationBannerPrinterTests {\n\n\t@Test\n\tvoid shouldRegisterRuntimeHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew SpringApplicationBannerPrinter.SpringApplicationBannerPrinterRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"banner.txt\")).accepts(runtimeHints);\n\t}\n\n\t@Test\n\t@WithResource(name = \"banner.txt\", content = \"\\uD83D\\uDE0D Spring Boot! \\uD83D\\uDE0D\")\n\tvoid shouldUseUtf8() {\n\t\tResourceLoader resourceLoader = new GenericApplicationContext();\n\t\tResource resource = resourceLoader.getResource(\"classpath:banner.txt\");\n\t\tSpringApplicationBannerPrinter printer = new SpringApplicationBannerPrinter(resourceLoader,\n\t\t\t\tnew ResourceBanner(resource));\n\t\tLog log = mock(Log.class);\n\t\tprinter.print(new MockEnvironment(), SpringApplicationBannerPrinterTests.class, log);\n\t\tArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);\n\t\tthen(log).should().info(captor.capture());\n\t\tassertThat(captor.getValue()).isEqualToIgnoringNewLines(\"\\uD83D\\uDE0D Spring Boot! \\uD83D\\uDE0D\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationNoWebTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.StaticApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringApplication} when spring web is not on the classpath.\n *\n * @author Stephane Nicoll\n */\n@ClassPathExclusions(\"spring-web*.jar\")\nclass SpringApplicationNoWebTests {\n\n\t@Test\n\tvoid detectWebApplicationTypeToNone() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tassertThat(application.getWebApplicationType()).isEqualTo(WebApplicationType.NONE);\n\t}\n\n\t@Test\n\tvoid specificApplicationContextClass() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication\n\t\t\t.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class));\n\t\tConfigurableApplicationContext context = application.run();\n\t\tassertThat(context).isInstanceOf(StaticApplicationContext.class);\n\t\tcontext.close();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookInstance.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.assertj.core.api.AbstractBooleanAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.assertj.core.api.Assertions;\nimport org.assertj.core.api.ObjectAssert;\n\nimport org.springframework.boot.SpringApplicationShutdownHookInstance.Assert;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Test access to the static {@link SpringApplicationShutdownHook} instance in\n * {@link SpringApplication}.\n *\n * @author Phillip Webb\n */\npublic final class SpringApplicationShutdownHookInstance implements AssertProvider<Assert> {\n\n\tprivate final SpringApplicationShutdownHook shutdownHook;\n\n\tprivate SpringApplicationShutdownHookInstance(SpringApplicationShutdownHook shutdownHook) {\n\t\tthis.shutdownHook = shutdownHook;\n\t}\n\n\tSpringApplicationShutdownHook getShutdownHook() {\n\t\treturn this.shutdownHook;\n\t}\n\n\t@Override\n\tpublic Assert assertThat() {\n\t\treturn new Assert(this.shutdownHook);\n\t}\n\n\tpublic static void reset() {\n\t\tget().getShutdownHook().reset();\n\t}\n\n\tpublic static SpringApplicationShutdownHookInstance get() {\n\t\treturn new SpringApplicationShutdownHookInstance(SpringApplication.shutdownHook);\n\t}\n\n\t/**\n\t * Assertions that can be performed on the {@link SpringApplicationShutdownHook}.\n\t */\n\tpublic static class Assert extends ObjectAssert<SpringApplicationShutdownHook> {\n\n\t\tAssert(SpringApplicationShutdownHook actual) {\n\t\t\tsuper(actual);\n\t\t}\n\n\t\tpublic Assert registeredApplicationContext(ConfigurableApplicationContext context) {\n\t\t\tassertThatIsApplicationContextRegistered(context).isTrue();\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Assert didNotRegisterApplicationContext(ConfigurableApplicationContext context) {\n\t\t\tassertThatIsApplicationContextRegistered(context).isFalse();\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate AbstractBooleanAssert<?> assertThatIsApplicationContextRegistered(\n\t\t\t\tConfigurableApplicationContext context) {\n\t\t\treturn Assertions.assertThat(this.actual.isApplicationContextRegistered(context))\n\t\t\t\t.as(\"ApplicationContext registered with shutdown hook\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationShutdownHookTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.Thread.State;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringApplicationShutdownHook}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n */\nclass SpringApplicationShutdownHookTests {\n\n\t@Test\n\tvoid shutdownHookIsNotAddedUntilContextIsRegistered() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tshutdownHook.enableShutdownHookAddition();\n\t\tassertThat(shutdownHook.isRuntimeShutdownHookAdded()).isFalse();\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tassertThat(shutdownHook.isRuntimeShutdownHookAdded()).isTrue();\n\t}\n\n\t@Test\n\tvoid shutdownHookIsNotAddedUntilHandlerIsRegistered() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tshutdownHook.enableShutdownHookAddition();\n\t\tassertThat(shutdownHook.isRuntimeShutdownHookAdded()).isFalse();\n\t\tshutdownHook.getHandlers().add(() -> {\n\t\t});\n\t\tassertThat(shutdownHook.isRuntimeShutdownHookAdded()).isTrue();\n\t}\n\n\t@Test\n\tvoid shutdownHookIsNotAddedUntilAdditionIsEnabled() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tshutdownHook.getHandlers().add(() -> {\n\t\t});\n\t\tassertThat(shutdownHook.isRuntimeShutdownHookAdded()).isFalse();\n\t\tshutdownHook.enableShutdownHookAddition();\n\t\tshutdownHook.getHandlers().add(() -> {\n\t\t});\n\t\tassertThat(shutdownHook.isRuntimeShutdownHookAdded()).isTrue();\n\t}\n\n\t@Test\n\tvoid runClosesContextsBeforeRunningHandlerActions() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tList<Object> finished = new CopyOnWriteArrayList<>();\n\t\tConfigurableApplicationContext context = new TestApplicationContext(finished);\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tcontext.refresh();\n\t\tRunnable handlerAction = new TestHandlerAction(finished);\n\t\tshutdownHook.getHandlers().add(handlerAction);\n\t\tshutdownHook.run();\n\t\tassertThat(finished).containsExactly(context, handlerAction);\n\t}\n\n\t@Test\n\tvoid runWhenContextIsBeingClosedInAnotherThreadWaitsUntilContextIsInactive() throws InterruptedException {\n\t\t// This situation occurs in the Spring Tools IDE. It triggers a context close via\n\t\t// JMX and then stops the JVM. The two actions happen almost simultaneously\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tList<Object> finished = new CopyOnWriteArrayList<>();\n\t\tCountDownLatch closing = new CountDownLatch(1);\n\t\tCountDownLatch proceedWithClose = new CountDownLatch(1);\n\t\tConfigurableApplicationContext context = new TestApplicationContext(finished, closing, proceedWithClose);\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tcontext.refresh();\n\t\tRunnable handlerAction = new TestHandlerAction(finished);\n\t\tshutdownHook.getHandlers().add(handlerAction);\n\t\tThread contextThread = new Thread(context::close);\n\t\tcontextThread.start();\n\t\t// Wait for context thread to begin closing the context\n\t\tclosing.await();\n\t\tThread shutdownThread = new Thread(shutdownHook);\n\t\tshutdownThread.start();\n\t\t// Shutdown thread should start waiting for context to become inactive\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(shutdownThread::getState, State.TIMED_WAITING::equals);\n\t\t// Allow context thread to proceed, unblocking shutdown thread\n\t\tproceedWithClose.countDown();\n\t\tcontextThread.join();\n\t\tshutdownThread.join();\n\t\t// Context should have been closed before handler action was run\n\t\tassertThat(finished).containsExactly(context, handlerAction);\n\t}\n\n\t@Test\n\tvoid runDueToExitDuringRefreshWhenContextHasBeenClosedDoesNotDeadlock() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tcontext.registerBean(CloseContextAndExit.class, context, shutdownHook);\n\t\tcontext.refresh();\n\t}\n\n\t@Test\n\tvoid runWhenContextIsClosedDirectlyRunsHandlerActions() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tList<Object> finished = new CopyOnWriteArrayList<>();\n\t\tConfigurableApplicationContext context = new TestApplicationContext(finished);\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tcontext.refresh();\n\t\tcontext.close();\n\t\tRunnable handlerAction1 = new TestHandlerAction(finished);\n\t\tRunnable handlerAction2 = new TestHandlerAction(finished);\n\t\tshutdownHook.getHandlers().add(handlerAction1);\n\t\tshutdownHook.getHandlers().add(handlerAction2);\n\t\tshutdownHook.run();\n\t\tassertThat(finished).contains(handlerAction1, handlerAction2);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addHandlerActionWhenNullThrowsException() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> shutdownHook.getHandlers().add(null))\n\t\t\t.withMessage(\"'action' must not be null\");\n\t}\n\n\t@Test\n\tvoid addHandlerActionWhenShuttingDownThrowsException() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tshutdownHook.run();\n\t\tRunnable handlerAction = new TestHandlerAction(new ArrayList<>());\n\t\tassertThatIllegalStateException().isThrownBy(() -> shutdownHook.getHandlers().add(handlerAction))\n\t\t\t.withMessage(\"Shutdown in progress\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid removeHandlerActionWhenNullThrowsException() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> shutdownHook.getHandlers().remove(null))\n\t\t\t.withMessage(\"'action' must not be null\");\n\t}\n\n\t@Test\n\tvoid removeHandlerActionWhenShuttingDownThrowsException() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tRunnable handlerAction = new TestHandlerAction(new ArrayList<>());\n\t\tshutdownHook.getHandlers().add(handlerAction);\n\t\tshutdownHook.run();\n\t\tassertThatIllegalStateException().isThrownBy(() -> shutdownHook.getHandlers().remove(handlerAction))\n\t\t\t.withMessage(\"Shutdown in progress\");\n\t}\n\n\t@Test\n\tvoid failsWhenDeregisterActiveContext() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tcontext.refresh();\n\t\tassertThatIllegalStateException().isThrownBy(() -> shutdownHook.deregisterFailedApplicationContext(context));\n\t\tassertThat(shutdownHook.isApplicationContextRegistered(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid deregistersFailedContext() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tshutdownHook.registerApplicationContext(context);\n\t\tcontext.registerBean(FailingBean.class);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(context::refresh);\n\t\tassertThat(shutdownHook.isApplicationContextRegistered(context)).isTrue();\n\t\tshutdownHook.deregisterFailedApplicationContext(context);\n\t\tassertThat(shutdownHook.isApplicationContextRegistered(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid handlersRunInDeterministicOrderFromLastRegisteredToFirst() {\n\t\tTestSpringApplicationShutdownHook shutdownHook = new TestSpringApplicationShutdownHook();\n\t\tRunnable r1 = mock(Runnable.class);\n\t\tRunnable r2 = mock(Runnable.class);\n\t\tRunnable r3 = mock(Runnable.class);\n\t\tshutdownHook.getHandlers().add(r2);\n\t\tshutdownHook.getHandlers().add(r1);\n\t\tshutdownHook.getHandlers().add(r3);\n\t\tshutdownHook.run();\n\t\tInOrder ordered = inOrder(r1, r2, r3);\n\t\tordered.verify(r3).run();\n\t\tordered.verify(r1).run();\n\t\tordered.verify(r2).run();\n\t\tordered.verifyNoMoreInteractions();\n\t}\n\n\tstatic class TestSpringApplicationShutdownHook extends SpringApplicationShutdownHook {\n\n\t\tprivate boolean runtimeShutdownHookAdded;\n\n\t\t@Override\n\t\tprotected void addRuntimeShutdownHook() {\n\t\t\tthis.runtimeShutdownHookAdded = true;\n\t\t}\n\n\t\tboolean isRuntimeShutdownHookAdded() {\n\t\t\treturn this.runtimeShutdownHookAdded;\n\t\t}\n\n\t}\n\n\tstatic class TestApplicationContext extends AbstractApplicationContext {\n\n\t\tprivate final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\t\tprivate final List<Object> finished;\n\n\t\tprivate final @Nullable CountDownLatch closing;\n\n\t\tprivate final @Nullable CountDownLatch proceedWithClose;\n\n\t\tTestApplicationContext(List<Object> finished) {\n\t\t\tthis(finished, null, null);\n\t\t}\n\n\t\tTestApplicationContext(List<Object> finished, @Nullable CountDownLatch closing,\n\t\t\t\t@Nullable CountDownLatch proceedWithClose) {\n\t\t\tthis.finished = finished;\n\t\t\tthis.closing = closing;\n\t\t\tthis.proceedWithClose = proceedWithClose;\n\t\t}\n\n\t\t@Override\n\t\tprotected void refreshBeanFactory() {\n\t\t}\n\n\t\t@Override\n\t\tprotected void closeBeanFactory() {\n\t\t}\n\n\t\t@Override\n\t\tprotected void onClose() {\n\t\t\tif (this.closing != null) {\n\t\t\t\tthis.closing.countDown();\n\t\t\t}\n\t\t\tif (this.proceedWithClose != null) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.proceedWithClose.await(1, TimeUnit.MINUTES);\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.finished.add(this);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurableListableBeanFactory getBeanFactory() {\n\t\t\treturn this.beanFactory;\n\t\t}\n\n\t}\n\n\tstatic class TestHandlerAction implements Runnable {\n\n\t\tprivate final List<Object> finished;\n\n\t\tTestHandlerAction(List<Object> finished) {\n\t\t\tthis.finished = finished;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tthis.finished.add(this);\n\t\t}\n\n\t}\n\n\tstatic class CloseContextAndExit implements InitializingBean {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tprivate final Runnable shutdownHook;\n\n\t\tCloseContextAndExit(ConfigurableApplicationContext context, SpringApplicationShutdownHook shutdownHook) {\n\t\t\tthis.context = context;\n\t\t\tthis.shutdownHook = shutdownHook;\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterPropertiesSet() throws Exception {\n\t\t\tthis.context.close();\n\t\t\t// Simulate System.exit by running the hook on a separate thread and waiting\n\t\t\t// for it to complete\n\t\t\tThread thread = new Thread(this.shutdownHook);\n\t\t\tthread.start();\n\t\t\tthread.join(15000);\n\t\t\tassertThat(thread.isAlive()).isFalse();\n\t\t}\n\n\t}\n\n\tstatic class FailingBean implements InitializingBean {\n\n\t\t@Override\n\t\tpublic void afterPropertiesSet() throws Exception {\n\t\t\tthrow new IllegalArgumentException(\"test failure\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\nimport jakarta.annotation.PostConstruct;\nimport org.assertj.core.api.Condition;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatcher;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.InOrder;\nimport org.mockito.Mockito;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.beans.factory.BeanDefinitionStoreException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionOverrideException;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultBeanNameGenerator;\nimport org.springframework.boot.Banner.Mode;\nimport org.springframework.boot.SpringApplication.NativeImageRequirementsException;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.AvailabilityState;\nimport org.springframework.boot.availability.LivenessState;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.builder.ParentContextApplicationContextInitializer;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.event.ApplicationContextInitializedEvent;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.context.event.SpringApplicationEvent;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.env.DefaultPropertiesPropertySource;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.context.event.ApplicationEventMulticaster;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.event.SimpleApplicationEventMulticaster;\nimport org.springframework.context.event.SmartApplicationListener;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.CommandLinePropertySource;\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.Profiles;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.metrics.ApplicationStartup;\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.ConfigurableWebEnvironment;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.mockingDetails;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link SpringApplication}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Christian Dupuis\n * @author Stephane Nicoll\n * @author Jeremy Rickard\n * @author Craig Burke\n * @author Madhura Bhave\n * @author Brian Clozel\n * @author Artsiom Yudovin\n * @author Marten Deinum\n * @author Nguyen Bao Sach\n * @author Chris Bono\n * @author Sebastien Deleuze\n * @author Moritz Halbritter\n * @author Tadaya Tsuyukubo\n * @author Yanming Zhou\n * @author Sijun Yang\n * @author Giheon Do\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SpringApplicationTests {\n\n\tprivate String headlessProperty;\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\tprivate Environment getEnvironment() {\n\t\tif (this.context != null) {\n\t\t\treturn this.context.getEnvironment();\n\t\t}\n\t\tthrow new IllegalStateException(\"Could not obtain Environment\");\n\t}\n\n\t@BeforeEach\n\tvoid storeAndClearHeadlessProperty() {\n\t\tthis.headlessProperty = System.getProperty(\"java.awt.headless\");\n\t\tSystem.clearProperty(\"java.awt.headless\");\n\t}\n\n\t@AfterEach\n\tvoid reinstateHeadlessProperty() {\n\t\tif (this.headlessProperty == null) {\n\t\t\tSystem.clearProperty(\"java.awt.headless\");\n\t\t}\n\t\telse {\n\t\t\tSystem.setProperty(\"java.awt.headless\", this.headlessProperty);\n\t\t}\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tSystem.clearProperty(\"spring.main.banner-mode\");\n\t\tSpringApplicationShutdownHookInstance.reset();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\")\n\t// Test null check\n\tvoid sourcesMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new SpringApplication((Class<?>[]) null).run())\n\t\t\t.withMessageContaining(\"'primarySources' must not be null\");\n\t}\n\n\t@Test\n\tvoid sourcesMustNotBeEmpty() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new SpringApplication().run())\n\t\t\t.withMessageContaining(\"No sources defined\");\n\t}\n\n\t@Test\n\tvoid sourcesMustBeAccessible() {\n\t\tassertThatExceptionOfType(BeanDefinitionStoreException.class)\n\t\t\t.isThrownBy(() -> new SpringApplication(InaccessibleConfiguration.class).run())\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(IllegalArgumentException.class)\n\t\t\t.withMessageContaining(\"No visible constructors\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"banner.txt\", content = \"Running a Test!\")\n\tvoid customBanner(CapturedOutput output) {\n\t\tSpringApplication application = spy(new SpringApplication(ExampleConfig.class));\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(output).startsWith(\"Running a Test!\");\n\n\t}\n\n\t@Test\n\t@WithResource(name = \"banner.txt\", content = \"\"\"\n\t\t\tRunning a Test!\n\n\t\t\t${test.property}\"\"\")\n\tvoid customBannerWithProperties(CapturedOutput output) {\n\t\tSpringApplication application = spy(new SpringApplication(ExampleConfig.class));\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--test.property=123456\");\n\t\tassertThat(output).containsPattern(\"Running a Test!\\\\s+123456\");\n\t}\n\n\t@Test\n\tvoid logsActiveProfilesWithoutProfileAndSingleDefault(CapturedOutput output) {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(output).contains(\"No active profile set, falling back to 1 default profile: \\\"default\\\"\");\n\t}\n\n\t@Test\n\tvoid logsActiveProfilesWithoutProfileAndMultipleDefaults(CapturedOutput output) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"p0\", \"default\");\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run();\n\t\tassertThat(output).contains(\"No active profile set, falling back to 2 default profiles: \\\"p0\\\", \\\"default\\\"\");\n\t}\n\n\t@Test\n\tvoid logsActiveProfilesWithSingleProfile(CapturedOutput output) {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.profiles.active=myprofiles\");\n\t\tassertThat(output).contains(\"The following 1 profile is active: \\\"myprofiles\\\"\");\n\t}\n\n\t@Test\n\tvoid logsActiveProfilesWithMultipleProfiles(CapturedOutput output) {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setAdditionalProfiles(\"p1\", \"p2\");\n\t\tapplication.run();\n\t\tassertThat(output).contains(\"The following 2 profiles are active: \\\"p1\\\", \\\"p2\\\"\");\n\t}\n\n\t@Test\n\tvoid enableBannerInLogViaProperty(CapturedOutput output) {\n\t\tSpringApplication application = spy(new SpringApplication(ExampleConfig.class));\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.main.banner-mode=log\");\n\t\tassertThatBannerModeIs(application, Banner.Mode.LOG);\n\t\tassertThat(output).contains(\"o.s.b.SpringApplication\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"bindtoapplication.properties\", content = \"spring.main.banner-mode=off\")\n\tvoid triggersConfigFileApplicationListenerBeforeBinding() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.config.name=bindtoapplication\");\n\t\tassertThatBannerModeIs(application, Mode.OFF);\n\t}\n\n\t@Test\n\tvoid bindsSystemPropertyToSpringApplication() {\n\t\tSystem.setProperty(\"spring.main.banner-mode\", \"off\");\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThatBannerModeIs(application, Mode.OFF);\n\t}\n\n\t@Test\n\tvoid bindsYamlStyleBannerModeToSpringApplication() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setDefaultProperties(Collections.singletonMap(\"spring.main.banner-mode\", false));\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThatBannerModeIs(application, Mode.OFF);\n\t}\n\n\t@Test\n\tvoid bindsBooleanAsStringBannerModeToSpringApplication() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.main.banner-mode=false\");\n\t\tassertThatBannerModeIs(application, Mode.OFF);\n\t}\n\n\t@Test\n\tvoid customId() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.application.name=foo\");\n\t\tassertThat(this.context.getId()).startsWith(\"foo\");\n\t}\n\n\t@Test\n\tvoid specificApplicationContextFactory() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication\n\t\t\t.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class));\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isInstanceOf(StaticApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid specificApplicationContextInitializer() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tfinal AtomicReference<ApplicationContext> reference = new AtomicReference<>();\n\t\tapplication.setInitializers(Collections\n\t\t\t.singletonList((ApplicationContextInitializer<ConfigurableApplicationContext>) reference::set));\n\t\tthis.context = application.run(\"--foo=bar\");\n\t\tassertThat(this.context).isSameAs(reference.get());\n\t\t// Custom initializers do not switch off the defaults\n\t\tassertThat(getEnvironment().getProperty(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid applicationRunningEventListener() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tAtomicReference<ApplicationReadyEvent> reference = addListener(application, ApplicationReadyEvent.class);\n\t\tthis.context = application.run(\"--foo=bar\");\n\t\tApplicationReadyEvent event = reference.get();\n\t\tassertThat(event).isNotNull();\n\t\tassertThat(application).isSameAs(event.getSpringApplication());\n\t}\n\n\t@Test\n\tvoid contextRefreshedEventListener() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tAtomicReference<ContextRefreshedEvent> reference = addListener(application, ContextRefreshedEvent.class);\n\t\tthis.context = application.run(\"--foo=bar\");\n\t\tContextRefreshedEvent event = reference.get();\n\t\tassertThat(event).isNotNull();\n\t\tassertThat(this.context).isSameAs(event.getApplicationContext());\n\t\t// Custom initializers do not switch off the defaults\n\t\tassertThat(getEnvironment().getProperty(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid eventsArePublishedInExpectedOrder() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tthis.context = application.run();\n\t\tInOrder inOrder = Mockito.inOrder(listener);\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationStartingEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationEnvironmentPreparedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationContextInitializedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationPreparedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ContextRefreshedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationStartedEvent.class));\n\t\tthen(listener).should(inOrder)\n\t\t\t.onApplicationEvent(argThat(isAvailabilityChangeEventWithState(LivenessState.CORRECT)));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tthen(listener).should(inOrder)\n\t\t\t.onApplicationEvent(argThat(isAvailabilityChangeEventWithState(ReadinessState.ACCEPTING_TRAFFIC)));\n\t\tinOrder.verifyNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid applicationStartedEventHasStartedTime() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tAtomicReference<ApplicationStartedEvent> reference = addListener(application, ApplicationStartedEvent.class);\n\t\tthis.context = application.run();\n\t\tassertThat(reference.get()).isNotNull().extracting(ApplicationStartedEvent::getTimeTaken).isNotNull();\n\t}\n\n\t@Test\n\tvoid applicationReadyEventHasReadyTime() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tAtomicReference<ApplicationReadyEvent> reference = addListener(application, ApplicationReadyEvent.class);\n\t\tthis.context = application.run();\n\t\tassertThat(reference.get()).isNotNull().extracting(ApplicationReadyEvent::getTimeTaken).isNotNull();\n\t}\n\n\t@Test\n\tvoid defaultApplicationContext() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isInstanceOf(AnnotationConfigApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid customEnvironment() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run();\n\t\tthen(application.getLoader()).should().setEnvironment(environment);\n\t}\n\n\t@Test\n\tvoid customResourceLoader() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tResourceLoader resourceLoader = new DefaultResourceLoader();\n\t\tapplication.setResourceLoader(resourceLoader);\n\t\tthis.context = application.run();\n\t\tthen(application.getLoader()).should().setResourceLoader(resourceLoader);\n\t}\n\n\t@Test\n\tvoid customResourceLoaderFromConstructor() {\n\t\tResourceLoader resourceLoader = new DefaultResourceLoader();\n\t\tTestSpringApplication application = new TestSpringApplication(resourceLoader, ExampleConfig.class);\n\t\tthis.context = application.run();\n\t\tthen(application.getLoader()).should().setResourceLoader(resourceLoader);\n\t}\n\n\t@Test\n\tvoid customBeanNameGenerator() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tBeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();\n\t\tapplication.setBeanNameGenerator(beanNameGenerator);\n\t\tthis.context = application.run();\n\t\tthen(application.getLoader()).should().setBeanNameGenerator(beanNameGenerator);\n\t\tObject actualGenerator = this.context.getBean(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);\n\t\tassertThat(actualGenerator).isSameAs(beanNameGenerator);\n\t}\n\n\t@Test\n\tvoid commandLinePropertySource() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run(\"--foo=bar\");\n\t\tassertThat(environment).has(matchingPropertySource(CommandLinePropertySource.class, \"commandLineArgs\"));\n\t}\n\n\t@Test\n\tvoid commandLinePropertySourceEnhancesEnvironment() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"commandLineArgs\", Collections.singletonMap(\"foo\", \"original\")));\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run(\"--foo=bar\", \"--bar=foo\");\n\t\tassertThat(environment).has(matchingPropertySource(CompositePropertySource.class, \"commandLineArgs\"));\n\t\tassertThat(environment.getProperty(\"bar\")).isEqualTo(\"foo\");\n\t\t// New command line properties take precedence\n\t\tassertThat(environment.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t\tCompositePropertySource composite = (CompositePropertySource) environment.getPropertySources()\n\t\t\t.get(\"commandLineArgs\");\n\t\tassertThat(composite).isNotNull();\n\t\tassertThat(composite.getPropertySources()).hasSize(2);\n\t\tassertThat(composite.getPropertySources()).first()\n\t\t\t.matches((source) -> source.getName().equals(\"springApplicationCommandLineArgs\"),\n\t\t\t\t\t\"is named springApplicationCommandLineArgs\");\n\t\tassertThat(composite.getPropertySources()).element(1)\n\t\t\t.matches((source) -> source.getName().equals(\"commandLineArgs\"), \"is named commandLineArgs\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"foo=bucket\")\n\tvoid propertiesFileEnhancesEnvironment() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run();\n\t\tassertThat(environment.getProperty(\"foo\")).isEqualTo(\"bucket\");\n\t}\n\n\t@Test\n\tvoid addProfiles() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setAdditionalProfiles(\"foo\");\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run();\n\t\tassertThat(environment.acceptsProfiles(Profiles.of(\"foo\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid additionalProfilesOrderedBeforeActiveProfiles() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setAdditionalProfiles(\"foo\");\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run(\"--spring.profiles.active=bar,spam\");\n\t\tassertThat(environment.getActiveProfiles()).containsExactly(\"foo\", \"bar\", \"spam\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"my.property=fromapplicationproperties\")\n\t@WithResource(name = \"application-other.properties\", content = \"my.property=fromotherpropertiesfile\")\n\tvoid addProfilesOrderWithProperties() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setAdditionalProfiles(\"other\");\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run();\n\t\t// Active profile should win over default\n\t\tassertThat(environment.getProperty(\"my.property\")).isEqualTo(\"fromotherpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"foo=bucket\")\n\tvoid emptyCommandLinePropertySourceNotAdded() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run();\n\t\tassertThat(environment.getProperty(\"foo\")).isEqualTo(\"bucket\");\n\t}\n\n\t@Test\n\tvoid disableCommandLinePropertySource() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setAddCommandLineProperties(false);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tapplication.setEnvironment(environment);\n\t\tthis.context = application.run(\"--foo=bar\");\n\t\tassertThat(environment).doesNotHave(matchingPropertySource(PropertySource.class, \"commandLineArgs\"));\n\t}\n\n\t@Test\n\tvoid contextUsesApplicationConversionService() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getBeanFactory().getConversionService())\n\t\t\t.isInstanceOf(ApplicationConversionService.class);\n\t\tassertThat(this.context.getEnvironment().getConversionService())\n\t\t\t.isInstanceOf(ApplicationConversionService.class);\n\t}\n\n\t@Test\n\tvoid contextWhenHasAddConversionServiceFalseUsesRegularConversionService() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setAddConversionService(false);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getBeanFactory().getConversionService()).isNull();\n\t\tassertThat(this.context.getEnvironment().getConversionService())\n\t\t\t.isNotInstanceOf(ApplicationConversionService.class);\n\t}\n\n\t@Test\n\tvoid runCommandLineRunnersAndApplicationRunners() {\n\t\tSpringApplication application = new SpringApplication(CommandLineRunConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"arg\");\n\t\tassertThat(this.context).has(runTestRunnerBean(\"runnerA\"));\n\t\tassertThat(this.context).has(runTestRunnerBean(\"runnerB\"));\n\t\tassertThat(this.context).has(runTestRunnerBean(\"runnerC\"));\n\t}\n\n\t@Test\n\tvoid runCommandLineRunnersAndApplicationRunnersWithParentContext() {\n\t\tSpringApplication application = new SpringApplication(CommandLineRunConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addInitializers(new ParentContextApplicationContextInitializer(\n\t\t\t\tnew AnnotationConfigApplicationContext(CommandLineRunParentConfig.class)));\n\t\tthis.context = application.run(\"arg\");\n\t\tassertThat(this.context).has(runTestRunnerBean(\"runnerA\"));\n\t\tassertThat(this.context).has(runTestRunnerBean(\"runnerB\"));\n\t\tassertThat(this.context).has(runTestRunnerBean(\"runnerC\"));\n\t\tassertThat(this.context).doesNotHave(runTestRunnerBean(\"runnerP\"));\n\t}\n\n\t@Test\n\tvoid runCommandLineRunnersAndApplicationRunnersUsingOrderOnBeanDefinitions() {\n\t\tSpringApplication application = new SpringApplication(BeanDefinitionOrderRunnerConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"arg\");\n\t\tBeanDefinitionOrderRunnerConfig config = this.context.getBean(BeanDefinitionOrderRunnerConfig.class);\n\t\tassertThat(config.runners).containsExactly(\"runnerA\", \"runnerB\", \"runnerC\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid runnersAreCalledAfterStartedIsLoggedAndBeforeApplicationReadyEventIsPublished(CapturedOutput output)\n\t\t\tthrows Exception {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tApplicationRunner applicationRunner = mock(ApplicationRunner.class);\n\t\tCommandLineRunner commandLineRunner = mock(CommandLineRunner.class);\n\t\tapplication.addInitializers((context) -> {\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tbeanFactory.registerSingleton(\"commandLineRunner\", (CommandLineRunner) (args) -> {\n\t\t\t\tassertThat(output).contains(\"Started\");\n\t\t\t\tcommandLineRunner.run(args);\n\t\t\t});\n\t\t\tbeanFactory.registerSingleton(\"applicationRunner\", (ApplicationRunner) (args) -> {\n\t\t\t\tassertThat(output).contains(\"Started\");\n\t\t\t\tapplicationRunner.run(args);\n\t\t\t});\n\t\t});\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tApplicationListener<ApplicationReadyEvent> eventListener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(eventListener);\n\t\tthis.context = application.run();\n\t\tInOrder applicationRunnerOrder = Mockito.inOrder(eventListener, applicationRunner);\n\t\tapplicationRunnerOrder.verify(applicationRunner).run(any(ApplicationArguments.class));\n\t\tapplicationRunnerOrder.verify(eventListener).onApplicationEvent(any(ApplicationReadyEvent.class));\n\t\tInOrder commandLineRunnerOrder = Mockito.inOrder(eventListener, commandLineRunner);\n\t\tcommandLineRunnerOrder.verify(commandLineRunner).run();\n\t\tcommandLineRunnerOrder.verify(eventListener).onApplicationEvent(any(ApplicationReadyEvent.class));\n\t}\n\n\t@Test\n\tvoid applicationRunnerFailureCausesApplicationFailedEventToBePublished() throws Exception {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tApplicationRunner runner = mock(ApplicationRunner.class);\n\t\tException failure = new Exception();\n\t\twillThrow(failure).given(runner).run(isA(ApplicationArguments.class));\n\t\tapplication.addInitializers((context) -> context.getBeanFactory().registerSingleton(\"runner\", runner));\n\t\tassertThatIllegalStateException().isThrownBy(application::run).withCause(failure);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationStartedEvent.class));\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t}\n\n\t@Test\n\tvoid commandLineRunnerFailureCausesApplicationFailedEventToBePublished() throws Exception {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tCommandLineRunner runner = mock(CommandLineRunner.class);\n\t\tException failure = new Exception();\n\t\twillThrow(failure).given(runner).run();\n\t\tapplication.addInitializers((context) -> context.getBeanFactory().registerSingleton(\"runner\", runner));\n\t\tassertThatIllegalStateException().isThrownBy(application::run).withCause(failure);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationStartedEvent.class));\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t}\n\n\t@Test\n\tvoid failureInReadyEventListenerDoesNotCausePublicationOfFailedEvent() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tRuntimeException failure = new RuntimeException();\n\t\twillThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run).isEqualTo(failure);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t}\n\n\t@Test\n\tvoid failureInReadyEventListenerCloseApplicationContext(CapturedOutput output) {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tExitCodeListener exitCodeListener = new ExitCodeListener();\n\t\tapplication.addListeners(exitCodeListener);\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tExitStatusException failure = new ExitStatusException();\n\t\twillThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tassertThat(exitCodeListener.getExitCode()).isEqualTo(11);\n\t\tassertThat(output).contains(\"Application run failed\");\n\t}\n\n\t@Test\n\tvoid failureOnTheJvmLogsApplicationRunFailed(CapturedOutput output) {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tExitCodeListener exitCodeListener = new ExitCodeListener();\n\t\tapplication.addListeners(exitCodeListener);\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tExitStatusException failure = new ExitStatusException();\n\t\twillThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tassertThat(exitCodeListener.getExitCode()).isEqualTo(11);\n\t\t// Leading space only happens when logging\n\t\tassertThat(output).contains(\" Application run failed\").contains(\"ExitStatusException\");\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@EnabledForJreRange(max = JRE.JAVA_24)\n\tvoid nativeImageShouldCheckForJava25() {\n\t\tSystem.setProperty(\"org.graalvm.nativeimage.imagecode\", \"true\");\n\t\ttry {\n\t\t\tSpringApplication application = new SpringApplication();\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tassertThatExceptionOfType(NativeImageRequirementsException.class).isThrownBy(application::run)\n\t\t\t\t.withMessage(\"Native Image requirements not met. \"\n\t\t\t\t\t\t+ \"Native Image must support at least Java 25 but Java %d was detected\"\n\t\t\t\t\t\t\t.formatted(Runtime.version().feature()));\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"org.graalvm.nativeimage.imagecode\");\n\t\t}\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@EnabledForJreRange(max = JRE.JAVA_24)\n\tvoid missingAotInitializerTakesPrecedenceOverNativeImageRequirementsCheck() {\n\t\tSystem.setProperty(\"spring.aot.enabled\", \"true\");\n\t\tSystem.setProperty(\"org.graalvm.nativeimage.imagecode\", \"true\");\n\t\ttry {\n\t\t\tSpringApplication application = new SpringApplication();\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tassertThatExceptionOfType(AotInitializerNotFoundException.class).isThrownBy(application::run)\n\t\t\t\t.withMessageStartingWith(\"Startup with AOT mode enabled failed\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"org.graalvm.nativeimage.imagecode\");\n\t\t\tSystem.clearProperty(\"spring.aot.enabled\");\n\t\t}\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@EnabledForJreRange(min = JRE.JAVA_25)\n\tvoid failureInANativeImageWritesFailureToSystemOut(CapturedOutput output) {\n\t\tSystem.setProperty(\"org.graalvm.nativeimage.imagecode\", \"true\");\n\t\ttry {\n\t\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tExitCodeListener exitCodeListener = new ExitCodeListener();\n\t\t\tapplication.addListeners(exitCodeListener);\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);\n\t\t\tapplication.addListeners(listener);\n\t\t\tExitStatusException failure = new ExitStatusException();\n\t\t\twillThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);\n\t\t\tthen(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\t\tthen(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\t\tassertThat(exitCodeListener.getExitCode()).isEqualTo(11);\n\t\t\t// Leading space only happens when logging\n\t\t\tassertThat(output).doesNotContain(\" Application run failed\")\n\t\t\t\t.contains(\"Application run failed\")\n\t\t\t\t.contains(\"ExitStatusException\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"org.graalvm.nativeimage.imagecode\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadSources() {\n\t\tClass<?>[] sources = { ExampleConfig.class, TestCommandLineRunner.class };\n\t\tTestSpringApplication application = new TestSpringApplication(sources);\n\t\tapplication.getSources().add(\"a\");\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setUseMockLoader(true);\n\t\tthis.context = application.run();\n\t\tSet<Object> allSources = application.getAllSources();\n\t\tassertThat(allSources).contains(ExampleConfig.class, TestCommandLineRunner.class, \"a\");\n\t}\n\n\t@Test\n\t@WithSampleBeansXmlResource\n\t@WithResource(name = \"application.properties\", content = \"sample.app.test.prop=*\")\n\tvoid wildcardSources() {\n\t\tTestSpringApplication application = new TestSpringApplication();\n\t\tapplication.getSources().add(\"classpath*:org/springframework/boot/sample-${sample.app.test.prop}.xml\");\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.config.location=classpath:/\");\n\t}\n\n\t@Test\n\tvoid run() {\n\t\tthis.context = SpringApplication.run(ExampleConfig.class);\n\t\tassertThat(this.context).isNotNull();\n\t}\n\n\t@Test\n\tvoid runComponents() {\n\t\tthis.context = SpringApplication.run(new Class<?>[] { ExampleConfig.class, Object.class }, new String[0]);\n\t\tassertThat(this.context).isNotNull();\n\t}\n\n\t@Test\n\tvoid exit() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isNotNull();\n\t\tassertThat(SpringApplication.exit(this.context)).isZero();\n\t}\n\n\t@Test\n\tvoid exitWithExplicitCode() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tExitCodeListener listener = new ExitCodeListener();\n\t\tapplication.addListeners(listener);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isNotNull();\n\t\tassertThat(SpringApplication.exit(this.context, (ExitCodeGenerator) () -> 2)).isEqualTo(2);\n\t\tassertThat(listener.getExitCode()).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid exitWithExplicitCodeFromException() {\n\t\tfinal SpringBootExceptionHandler handler = mock(SpringBootExceptionHandler.class);\n\t\tSpringApplication application = new SpringApplication(ExitCodeCommandLineRunConfig.class) {\n\n\t\t\t@Override\n\t\t\tSpringBootExceptionHandler getSpringBootExceptionHandler() {\n\t\t\t\treturn handler;\n\t\t\t}\n\n\t\t};\n\t\tExitCodeListener listener = new ExitCodeListener();\n\t\tapplication.addListeners(listener);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tassertThatIllegalStateException().isThrownBy(application::run);\n\t\tthen(handler).should().registerExitCode(11);\n\t\tassertThat(listener.getExitCode()).isEqualTo(11);\n\t}\n\n\t@Test\n\tvoid exitWithExplicitCodeFromMappedException() {\n\t\tfinal SpringBootExceptionHandler handler = mock(SpringBootExceptionHandler.class);\n\t\tSpringApplication application = new SpringApplication(MappedExitCodeCommandLineRunConfig.class) {\n\n\t\t\t@Override\n\t\t\tSpringBootExceptionHandler getSpringBootExceptionHandler() {\n\t\t\t\treturn handler;\n\t\t\t}\n\n\t\t};\n\t\tExitCodeListener listener = new ExitCodeListener();\n\t\tapplication.addListeners(listener);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tassertThatIllegalStateException().isThrownBy(application::run);\n\t\tthen(handler).should().registerExitCode(11);\n\t\tassertThat(listener.getExitCode()).isEqualTo(11);\n\t}\n\n\t@Test\n\tvoid exceptionFromRefreshIsHandledGracefully(CapturedOutput output) {\n\t\tfinal SpringBootExceptionHandler handler = mock(SpringBootExceptionHandler.class);\n\t\tSpringApplication application = new SpringApplication(RefreshFailureConfig.class) {\n\n\t\t\t@Override\n\t\t\tSpringBootExceptionHandler getSpringBootExceptionHandler() {\n\t\t\t\treturn handler;\n\t\t\t}\n\n\t\t};\n\t\tExitCodeListener listener = new ExitCodeListener();\n\t\tapplication.addListeners(listener);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);\n\t\tthen(handler).should()\n\t\t\t.registerLoggedException(\n\t\t\t\t\tassertArg((exception) -> assertThat(exception).hasCauseInstanceOf(RefreshFailureException.class)));\n\t\tassertThat(output).doesNotContain(\"NullPointerException\");\n\t}\n\n\t@Test\n\tvoid defaultCommandLineArgs() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tProperties properties = StringUtils.splitArrayElementsIntoProperties(new String[] { \"baz=\", \"bar=spam\" }, \"=\");\n\t\tassertThat(properties).isNotNull();\n\t\tapplication.setDefaultProperties(properties);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--bar=foo\", \"bucket\", \"crap\");\n\t\tassertThat(this.context).isInstanceOf(AnnotationConfigApplicationContext.class);\n\t\tassertThat(getEnvironment().getProperty(\"bar\")).isEqualTo(\"foo\");\n\t\tassertThat(getEnvironment().getProperty(\"baz\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid defaultPropertiesShouldBeMerged() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(DefaultPropertiesPropertySource.NAME,\n\t\t\t\t\tCollections.singletonMap(\"bar\", \"foo\")));\n\t\tSpringApplication application = new SpringApplicationBuilder(ExampleConfig.class).environment(environment)\n\t\t\t.properties(\"baz=bing\")\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build();\n\t\tthis.context = application.run();\n\t\tassertThat(getEnvironment().getProperty(\"bar\")).isEqualTo(\"foo\");\n\t\tassertThat(getEnvironment().getProperty(\"baz\")).isEqualTo(\"bing\");\n\t}\n\n\t@Test\n\tvoid commandLineArgsApplyToSpringApplication() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.main.banner-mode=OFF\");\n\t\tassertThat(application.getBannerMode()).isEqualTo(Banner.Mode.OFF);\n\t}\n\n\t@Test\n\tvoid registerShutdownHook() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).registeredApplicationContext(this.context);\n\t}\n\n\t@Test\n\tvoid registerShutdownHookOff() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setRegisterShutdownHook(false);\n\t\tthis.context = application.run();\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(this.context);\n\t}\n\n\t@Test\n\tvoid registerListener() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class, ListenerConfig.class);\n\t\tapplication.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tSet<ApplicationEvent> events = new LinkedHashSet<>();\n\t\tapplication.addListeners((ApplicationListener<ApplicationEvent>) events::add);\n\t\tthis.context = application.run();\n\t\tassertThat(events).hasAtLeastOneElementOfType(ApplicationPreparedEvent.class);\n\t\tassertThat(events).hasAtLeastOneElementOfType(ContextRefreshedEvent.class);\n\t\tverifyRegisteredListenerSuccessEvents(this.context);\n\t}\n\n\t@Test\n\tvoid registerListenerWithCustomMulticaster() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class, ListenerConfig.class,\n\t\t\t\tMulticaster.class);\n\t\tapplication.setApplicationContextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tSet<ApplicationEvent> events = new LinkedHashSet<>();\n\t\tapplication.addListeners((ApplicationListener<ApplicationEvent>) events::add);\n\t\tthis.context = application.run();\n\t\tassertThat(events).hasAtLeastOneElementOfType(ApplicationPreparedEvent.class);\n\t\tassertThat(events).hasAtLeastOneElementOfType(ContextRefreshedEvent.class);\n\t\tverifyRegisteredListenerSuccessEvents(this.context);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void verifyRegisteredListenerSuccessEvents(ConfigurableApplicationContext context) {\n\t\tApplicationListener<ApplicationEvent> listener = context.getBean(\"testApplicationListener\",\n\t\t\t\tApplicationListener.class);\n\t\tInOrder inOrder = Mockito.inOrder(listener);\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ContextRefreshedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationStartedEvent.class));\n\t\tthen(listener).should(inOrder)\n\t\t\t.onApplicationEvent(argThat(isAvailabilityChangeEventWithState(LivenessState.CORRECT)));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationReadyEvent.class));\n\t\tthen(listener).should(inOrder)\n\t\t\t.onApplicationEvent(argThat(isAvailabilityChangeEventWithState(ReadinessState.ACCEPTING_TRAFFIC)));\n\t\tinOrder.verifyNoMoreInteractions();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid applicationListenerFromApplicationIsCalledWhenContextFailsRefreshBeforeListenerRegistration() {\n\t\tApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tSpringApplication application = new SpringApplication(BrokenBeanFactoryPostProcessing.class);\n\t\tapplication.addListeners(listener);\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(application::run);\n\t\tverifyRegisteredListenerFailedFromApplicationEvents(listener);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid applicationListenerFromApplicationIsCalledWhenContextFailsRefreshAfterListenerRegistration() {\n\t\tApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tSpringApplication application = new SpringApplication(BrokenPostConstructConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addListeners(listener);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(application::run);\n\t\tverifyRegisteredListenerFailedFromApplicationEvents(listener);\n\t}\n\n\tprivate void verifyRegisteredListenerFailedFromApplicationEvents(ApplicationListener<ApplicationEvent> listener) {\n\t\tInOrder inOrder = Mockito.inOrder(listener);\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationStartingEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationEnvironmentPreparedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationContextInitializedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationPreparedEvent.class));\n\t\tthen(listener).should(inOrder).onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tinOrder.verifyNoMoreInteractions();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid applicationListenerFromContextIsCalledWhenContextFailsRefreshBeforeListenerRegistration() {\n\t\tfinal ApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tSpringApplication application = new SpringApplication(BrokenBeanFactoryPostProcessing.class);\n\t\tapplication.addInitializers((applicationContext) -> applicationContext.addApplicationListener(listener));\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(application::run);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tthen(listener).shouldHaveNoMoreInteractions();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid applicationListenerFromContextIsCalledWhenContextFailsRefreshAfterListenerRegistration() {\n\t\tApplicationListener<ApplicationEvent> listener = mock(ApplicationListener.class);\n\t\tSpringApplication application = new SpringApplication(BrokenPostConstructConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addInitializers((applicationContext) -> applicationContext.addApplicationListener(listener));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(application::run);\n\t\tthen(listener).should().onApplicationEvent(isA(ApplicationFailedEvent.class));\n\t\tthen(listener).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid headless() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(System.getProperty(\"java.awt.headless\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid headlessFalse() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setHeadless(false);\n\t\tthis.context = application.run();\n\t\tassertThat(System.getProperty(\"java.awt.headless\")).isEqualTo(\"false\");\n\t}\n\n\t@Test\n\tvoid headlessSystemPropertyTakesPrecedence() {\n\t\tSystem.setProperty(\"java.awt.headless\", \"false\");\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(System.getProperty(\"java.awt.headless\")).isEqualTo(\"false\");\n\t}\n\n\t@Test\n\tvoid getApplicationArgumentsBean() {\n\t\tTestSpringApplication application = new TestSpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--debug\", \"spring\", \"boot\");\n\t\tApplicationArguments args = this.context.getBean(ApplicationArguments.class);\n\t\tassertThat(args.getNonOptionArgs()).containsExactly(\"spring\", \"boot\");\n\t\tassertThat(args.containsOption(\"debug\")).isTrue();\n\t}\n\n\t@Test\n\tvoid nonWebApplicationConfiguredViaAPropertyHasTheCorrectTypeOfContextAndEnvironment() {\n\t\tConfigurableApplicationContext context = new SpringApplication(ExampleConfig.class)\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tassertThat(context).isNotInstanceOfAny(WebApplicationContext.class, ReactiveWebApplicationContext.class);\n\t\tassertThat(context.getEnvironment()).isNotInstanceOfAny(ConfigurableWebEnvironment.class);\n\t}\n\n\t@Test\n\tvoid failureResultsInSingleStackTrace(CapturedOutput output) throws Exception {\n\t\tThreadGroup group = new ThreadGroup(\"main\");\n\t\tThread thread = new Thread(group, \"main\") {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tSpringApplication application = new SpringApplication(FailingConfig.class);\n\t\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\t\tapplication.run();\n\t\t\t}\n\n\t\t};\n\t\tthread.start();\n\t\tthread.join(6000);\n\t\tassertThat(output).containsOnlyOnce(\"Caused by: java.lang.RuntimeException: ExpectedError\");\n\t}\n\n\t@Test\n\tvoid beanDefinitionOverridingIsDisabledByDefault() {\n\t\tassertThatExceptionOfType(BeanDefinitionOverrideException.class)\n\t\t\t.isThrownBy(() -> new SpringApplication(ExampleConfig.class, OverrideConfig.class).run());\n\t}\n\n\t@Test\n\tvoid beanDefinitionOverridingCanBeEnabled() {\n\t\tassertThat(new SpringApplication(ExampleConfig.class, OverrideConfig.class)\n\t\t\t.run(\"--spring.main.allow-bean-definition-overriding=true\", \"--spring.main.web-application-type=none\")\n\t\t\t.getBean(\"someBean\")).isEqualTo(\"override\");\n\t}\n\n\t@Test\n\tvoid circularReferencesAreDisabledByDefault() {\n\t\tassertThatExceptionOfType(UnsatisfiedDependencyException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new SpringApplication(ExampleProducerConfiguration.class, ExampleConsumerConfiguration.class)\n\t\t\t\t\t\t.run(\"--spring.main.web-application-type=none\"))\n\t\t\t.withRootCauseInstanceOf(BeanCurrentlyInCreationException.class);\n\t}\n\n\t@Test\n\tvoid circularReferencesCanBeEnabled() {\n\t\tassertThatNoException().isThrownBy(\n\t\t\t\t() -> new SpringApplication(ExampleProducerConfiguration.class, ExampleConsumerConfiguration.class)\n\t\t\t\t\t.run(\"--spring.main.web-application-type=none\", \"--spring.main.allow-circular-references=true\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-config/application.yml\", content = \"hello: world\")\n\tvoid relaxedBindingShouldWorkBeforeEnvironmentIsPrepared() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.config.additionalLocation=classpath:custom-config/\");\n\t\tassertThat(this.context.getEnvironment().getProperty(\"hello\")).isEqualTo(\"world\");\n\t}\n\n\t@Test\n\tvoid lazyInitializationIsDisabledByDefault() {\n\t\tassertThat(new SpringApplication(LazyInitializationConfig.class).run(\"--spring.main.web-application-type=none\")\n\t\t\t.getBean(AtomicInteger.class)).hasValue(1);\n\t}\n\n\t@Test\n\tvoid lazyInitializationCanBeEnabled() {\n\t\tassertThat(new SpringApplication(LazyInitializationConfig.class)\n\t\t\t.run(\"--spring.main.web-application-type=none\", \"--spring.main.lazy-initialization=true\")\n\t\t\t.getBean(AtomicInteger.class)).hasValue(0);\n\t}\n\n\t@Test\n\tvoid lazyInitializationIgnoresBeansThatAreExplicitlyNotLazy() {\n\t\tassertThat(new SpringApplication(NotLazyInitializationConfig.class)\n\t\t\t.run(\"--spring.main.web-application-type=none\", \"--spring.main.lazy-initialization=true\")\n\t\t\t.getBean(AtomicInteger.class)).hasValue(1);\n\t}\n\n\t@Test\n\tvoid lazyInitializationIgnoresLazyInitializationExcludeFilteredBeans() {\n\t\tassertThat(new SpringApplication(LazyInitializationExcludeFilterConfig.class)\n\t\t\t.run(\"--spring.main.web-application-type=none\", \"--spring.main.lazy-initialization=true\")\n\t\t\t.getBean(AtomicInteger.class)).hasValue(1);\n\t}\n\n\t@Test\n\tvoid customApplicationStartupPublishStartupSteps() {\n\t\tApplicationStartup applicationStartup = mock(ApplicationStartup.class);\n\t\tStartupStep startupStep = mock(StartupStep.class);\n\t\tgiven(applicationStartup.start(anyString())).willReturn(startupStep);\n\t\tgiven(startupStep.tag(anyString(), anyString())).willReturn(startupStep);\n\t\tgiven(startupStep.tag(anyString(), ArgumentMatchers.<Supplier<String>>any())).willReturn(startupStep);\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setApplicationStartup(applicationStartup);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getBean(ApplicationStartup.class)).isEqualTo(applicationStartup);\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.starting\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.environment-prepared\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.context-prepared\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.context-loaded\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.started\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.ready\");\n\t\tlong startCount = mockingDetails(applicationStartup).getInvocations()\n\t\t\t.stream()\n\t\t\t.filter((invocation) -> invocation.getMethod().toString().contains(\"start(\"))\n\t\t\t.count();\n\t\tlong endCount = mockingDetails(startupStep).getInvocations()\n\t\t\t.stream()\n\t\t\t.filter((invocation) -> invocation.getMethod().toString().contains(\"end(\"))\n\t\t\t.count();\n\t\tassertThat(startCount).isEqualTo(endCount);\n\t}\n\n\t@Test\n\tvoid customApplicationStartupPublishStartupStepsWithFailure() {\n\t\tApplicationStartup applicationStartup = mock(ApplicationStartup.class);\n\t\tStartupStep startupStep = mock(StartupStep.class);\n\t\tgiven(applicationStartup.start(anyString())).willReturn(startupStep);\n\t\tgiven(startupStep.tag(anyString(), anyString())).willReturn(startupStep);\n\t\tgiven(startupStep.tag(anyString(), ArgumentMatchers.<Supplier<String>>any())).willReturn(startupStep);\n\t\tSpringApplication application = new SpringApplication(BrokenPostConstructConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setApplicationStartup(applicationStartup);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(application::run);\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.starting\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.environment-prepared\");\n\t\tthen(applicationStartup).should().start(\"spring.boot.application.failed\");\n\t\tlong startCount = mockingDetails(applicationStartup).getInvocations()\n\t\t\t.stream()\n\t\t\t.filter((invocation) -> invocation.getMethod().toString().contains(\"start(\"))\n\t\t\t.count();\n\t\tlong endCount = mockingDetails(startupStep).getInvocations()\n\t\t\t.stream()\n\t\t\t.filter((invocation) -> invocation.getMethod().toString().contains(\"end(\"))\n\t\t\t.count();\n\t\tassertThat(startCount).isEqualTo(endCount);\n\t}\n\n\t@Test\n\tvoid addBootstrapRegistryInitializer() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addBootstrapRegistryInitializer(\n\t\t\t\t(bootstrapContext) -> bootstrapContext.register(String.class, InstanceSupplier.of(\"boot\")));\n\t\tTestApplicationListener listener = new TestApplicationListener();\n\t\tapplication.addListeners(listener);\n\t\tapplication.run();\n\t\tApplicationStartingEvent startingEvent = listener.getEvent(ApplicationStartingEvent.class);\n\t\tassertThat(startingEvent.getBootstrapContext().get(String.class)).isEqualTo(\"boot\");\n\t\tApplicationEnvironmentPreparedEvent environmentPreparedEvent = listener\n\t\t\t.getEvent(ApplicationEnvironmentPreparedEvent.class);\n\t\tassertThat(environmentPreparedEvent.getBootstrapContext().get(String.class)).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid addBootstrapRegistryInitializerCanRegisterBeans() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addBootstrapRegistryInitializer((bootstrapContext) -> {\n\t\t\tbootstrapContext.register(String.class, InstanceSupplier.of(\"boot\"));\n\t\t\tbootstrapContext.addCloseListener((event) -> {\n\t\t\t\tString string = event.getBootstrapContext().get(String.class);\n\t\t\t\tassertThat(string).isNotNull();\n\t\t\t\tevent.getApplicationContext().getBeanFactory().registerSingleton(\"test\", string);\n\t\t\t});\n\t\t});\n\t\tConfigurableApplicationContext applicationContext = application.run();\n\t\tassertThat(applicationContext.getBean(\"test\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid settingEnvironmentPrefixViaPropertiesThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new SpringApplication().run(\"--spring.main.environment-prefix=my\"));\n\t}\n\n\t@Test\n\tvoid bindsEnvironmentPrefixToSpringApplication() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setEnvironmentPrefix(\"my\");\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(application.getEnvironmentPrefix()).isEqualTo(\"my\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"spring-application-config-property-source.properties\",\n\t\t\tcontent = \"test.name=spring-application-config-property-source\")\n\tvoid movesConfigClassPropertySourcesToEnd() {\n\t\tSpringApplication application = new SpringApplication(PropertySourceConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setDefaultProperties(Collections.singletonMap(\"test.name\", \"test\"));\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().getProperty(\"test.name\"))\n\t\t\t.isEqualTo(\"spring-application-config-property-source\");\n\t}\n\n\t@Test\n\tvoid deregistersShutdownHookForFailedApplicationContext() {\n\t\tSpringApplication application = new SpringApplication(BrokenPostConstructConfig.class);\n\t\tList<ApplicationEvent> events = new ArrayList<>();\n\t\tapplication.addListeners(events::add);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(application::run);\n\t\tassertThat(events).hasAtLeastOneElementOfType(ApplicationFailedEvent.class);\n\t\tApplicationFailedEvent failure = events.stream()\n\t\t\t.filter((event) -> event instanceof ApplicationFailedEvent)\n\t\t\t.map(ApplicationFailedEvent.class::cast)\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tConfigurableApplicationContext context = failure.getApplicationContext();\n\t\tassertThat(context).isNotNull();\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(context);\n\t}\n\n\t@Test\n\tvoid withRunnableHookRunsWithHook() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tSpringApplicationRunListener runListener = mock(SpringApplicationRunListener.class);\n\t\tSpringApplicationHook hook = (springApplication) -> runListener;\n\t\tSpringApplication.withHook(hook, () -> this.context = application.run());\n\t\tassertThat(this.context).isNotNull();\n\t\tthen(runListener).should().starting(any());\n\t\tthen(runListener).should().contextPrepared(this.context);\n\t\tthen(runListener).should().ready(eq(this.context), any());\n\t\tassertThat(this.context.isRunning()).isTrue();\n\t}\n\n\t@Test\n\tvoid withCallableHookRunsWithHook() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tSpringApplicationRunListener runListener = mock(SpringApplicationRunListener.class);\n\t\tSpringApplicationHook hook = (springApplication) -> runListener;\n\t\tthis.context = SpringApplication.withHook(hook, () -> application.run());\n\t\tthen(runListener).should().starting(any());\n\t\tthen(runListener).should().contextPrepared(this.context);\n\t\tthen(runListener).should().ready(eq(this.context), any());\n\t\tassertThat(this.context.isRunning()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid withHookWhenHookThrowsAbandonedRunExceptionAbandonsRun() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tApplicationListener listener = mock(ApplicationListener.class);\n\t\tapplication.addListeners(listener);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tSpringApplicationRunListener runListener = spy(new SpringApplicationRunListener() {\n\n\t\t\t@Override\n\t\t\tpublic void contextLoaded(ConfigurableApplicationContext context) {\n\t\t\t\tthrow new SpringApplication.AbandonedRunException(context);\n\t\t\t}\n\n\t\t});\n\t\tSpringApplicationHook hook = (springApplication) -> runListener;\n\t\tassertThatExceptionOfType(SpringApplication.AbandonedRunException.class)\n\t\t\t.isThrownBy(() -> SpringApplication.withHook(hook, () -> application.run()))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tConfigurableApplicationContext context = ex.getApplicationContext();\n\t\t\t\tassertThat(context).isNotNull();\n\t\t\t\tassertThat(context.isRunning()).isFalse();\n\t\t\t});\n\t\tthen(runListener).should().starting(any());\n\t\tthen(runListener).should().contextPrepared(any());\n\t\tthen(runListener).should(never()).ready(any(), any());\n\t\tthen(runListener).should(never()).failed(any(), any());\n\t\tthen(listener).should().onApplicationEvent(any(ApplicationStartingEvent.class));\n\t\tthen(listener).should().onApplicationEvent(any(ApplicationEnvironmentPreparedEvent.class));\n\t\tthen(listener).should().onApplicationEvent(any(ApplicationPreparedEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(any(ApplicationReadyEvent.class));\n\t\tthen(listener).should(never()).onApplicationEvent(any(ApplicationFailedEvent.class));\n\t}\n\n\t@Test\n\t// gh-32555\n\tvoid shouldUseAotInitializer() {\n\t\tSpringApplication application = new SpringApplication(ExampleAotProcessedMainClass.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setMainApplicationClass(ExampleAotProcessedMainClass.class);\n\t\tSystem.setProperty(AotDetector.AOT_ENABLED, \"true\");\n\t\ttry {\n\t\t\tApplicationContext context = application.run();\n\t\t\tassertThat(context.getBean(\"test\")).isEqualTo(\"test\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(AotDetector.AOT_ENABLED);\n\t\t}\n\t}\n\n\t@Test\n\tvoid shouldReportFriendlyErrorIfAotInitializerNotFound() {\n\t\tSpringApplication application = new SpringApplication(TestSpringApplication.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setMainApplicationClass(TestSpringApplication.class);\n\t\tSystem.setProperty(AotDetector.AOT_ENABLED, \"true\");\n\t\ttry {\n\t\t\tassertThatExceptionOfType(AotInitializerNotFoundException.class).isThrownBy(application::run)\n\t\t\t\t.withMessageMatching(\"^.+AOT initializer .+ could not be found$\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(AotDetector.AOT_ENABLED);\n\t\t}\n\t}\n\n\t@Test\n\tvoid fromRunsWithAdditionalSources() {\n\t\tassertThat(ExampleAdditionalConfig.local.get()).isNull();\n\t\tthis.context = SpringApplication.from(ExampleFromMainMethod::main)\n\t\t\t.with(ExampleAdditionalConfig.class)\n\t\t\t.run()\n\t\t\t.getApplicationContext();\n\t\tassertThat(ExampleAdditionalConfig.local.get()).isNotNull();\n\t\tExampleAdditionalConfig.local.remove();\n\t}\n\n\t@Test\n\tvoid fromReturnsApplicationContext() {\n\t\tthis.context = SpringApplication.from(ExampleFromMainMethod::main)\n\t\t\t.with(ExampleAdditionalConfig.class)\n\t\t\t.run()\n\t\t\t.getApplicationContext();\n\t\tassertThat(this.context).isNotNull();\n\t}\n\n\t@Test\n\tvoid fromWithMultipleApplicationsOnlyAppliesAdditionalSourcesOnce() {\n\t\tthis.context = SpringApplication.from(MultipleApplicationsMainMethod::main)\n\t\t\t.with(SingleUseAdditionalConfig.class)\n\t\t\t.run()\n\t\t\t.getApplicationContext();\n\t\tassertThatNoException().isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(SingleUseAdditionalConfig.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid fromAppliesProfiles() {\n\t\tthis.context = SpringApplication.from(ExampleFromMainMethod::main)\n\t\t\t.with(ProfileConfig.class)\n\t\t\t.withAdditionalProfiles(\"custom\")\n\t\t\t.run()\n\t\t\t.getApplicationContext();\n\t\tassertThat(this.context).isNotNull();\n\t\tassertThat(this.context.getBeanProvider(Example.class).getIfAvailable()).isNotNull();\n\t}\n\n\t@Test\n\tvoid shouldStartDaemonThreadIfKeepAliveIsEnabled() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--spring.main.keep-alive=true\");\n\t\tSet<Thread> threads = getCurrentThreads();\n\t\tassertThat(threads).filteredOn((thread) -> thread.getName().equals(\"keep-alive\"))\n\t\t\t.singleElement()\n\t\t\t.satisfies((thread) -> assertThat(thread.isDaemon()).isFalse());\n\t}\n\n\t@Test\n\tvoid shouldStopKeepAliveThreadIfContextIsClosed() {\n\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setKeepAlive(true);\n\t\tthis.context = application.run();\n\t\tassertThat(getCurrentThreads()).filteredOn((thread) -> thread.getName().equals(\"keep-alive\")).isNotEmpty();\n\t\tthis.context.close();\n\t\tAwaitility.await()\n\t\t\t.atMost(Duration.ofSeconds(30))\n\t\t\t.untilAsserted(\n\t\t\t\t\t() -> assertThat(getCurrentThreads()).filteredOn((thread) -> thread.getName().equals(\"keep-alive\"))\n\t\t\t\t\t\t.isEmpty());\n\t}\n\n\tprivate <S extends AvailabilityState> ArgumentMatcher<ApplicationEvent> isAvailabilityChangeEventWithState(\n\t\t\tS state) {\n\t\treturn (argument) -> (argument instanceof AvailabilityChangeEvent<?> availabilityChangeEvent)\n\t\t\t\t&& availabilityChangeEvent.getState().equals(state);\n\t}\n\n\tprivate <E extends ApplicationEvent> AtomicReference<E> addListener(SpringApplication application,\n\t\t\tClass<E> eventType) {\n\t\tAtomicReference<E> reference = new AtomicReference<>();\n\t\tapplication.addListeners(new TestEventListener<>(eventType, reference));\n\t\treturn reference;\n\t}\n\n\tprivate Condition<ConfigurableEnvironment> matchingPropertySource(final Class<?> propertySourceClass,\n\t\t\tfinal String name) {\n\n\t\treturn new Condition<>(\"has property source\") {\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(ConfigurableEnvironment value) {\n\t\t\t\tfor (PropertySource<?> source : value.getPropertySources()) {\n\t\t\t\t\tif (propertySourceClass.isInstance(source) && (name == null || name.equals(source.getName()))) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate Condition<ConfigurableApplicationContext> runTestRunnerBean(String name) {\n\t\treturn new Condition<>(\"run testrunner bean\") {\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(ConfigurableApplicationContext value) {\n\t\t\t\treturn value.getBean(name, AbstractTestRunner.class).hasRun();\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate Set<Thread> getCurrentThreads() {\n\t\treturn Thread.getAllStackTraces().keySet();\n\t}\n\n\tprivate void assertThatBannerModeIs(SpringApplication application, Mode mode) {\n\t\tObject properties = ReflectionTestUtils.getField(application, \"properties\");\n\t\tassertThat(properties).hasFieldOrPropertyWithValue(\"bannerMode\", mode);\n\t}\n\n\tstatic class TestEventListener<E extends ApplicationEvent> implements SmartApplicationListener {\n\n\t\tprivate final Class<E> eventType;\n\n\t\tprivate final AtomicReference<E> reference;\n\n\t\tTestEventListener(Class<E> eventType, AtomicReference<E> reference) {\n\t\t\tthis.eventType = eventType;\n\t\t\tthis.reference = reference;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {\n\t\t\treturn this.eventType.isAssignableFrom(eventType);\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tthis.reference.set((E) event);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class InaccessibleConfiguration {\n\n\t\tprivate InaccessibleConfiguration() {\n\t\t}\n\n\t\t@Bean\n\t\tString testMessage() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\tstatic class SpyApplicationContext extends AnnotationConfigApplicationContext {\n\n\t\tConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext());\n\n\t\t@Override\n\t\tpublic void registerShutdownHook() {\n\t\t\tthis.applicationContext.registerShutdownHook();\n\t\t}\n\n\t\tConfigurableApplicationContext getApplicationContext() {\n\t\t\treturn this.applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t\tthis.applicationContext.close();\n\t\t\tsuper.close();\n\t\t}\n\n\t}\n\n\tstatic class TestSpringApplication extends SpringApplication {\n\n\t\tprivate @Nullable BeanDefinitionLoader loader;\n\n\t\tprivate boolean useMockLoader;\n\n\t\tTestSpringApplication(Class<?>... primarySources) {\n\t\t\tsuper(primarySources);\n\t\t}\n\n\t\tTestSpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {\n\t\t\tsuper(resourceLoader, primarySources);\n\t\t}\n\n\t\tvoid setUseMockLoader(boolean useMockLoader) {\n\t\t\tthis.useMockLoader = useMockLoader;\n\t\t}\n\n\t\t@Override\n\t\tprotected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {\n\t\t\tif (this.useMockLoader) {\n\t\t\t\tthis.loader = mock(BeanDefinitionLoader.class);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.loader = spy(super.createBeanDefinitionLoader(registry, sources));\n\t\t\t}\n\t\t\treturn this.loader;\n\t\t}\n\n\t\t@Nullable BeanDefinitionLoader getLoader() {\n\t\t\treturn this.loader;\n\t\t}\n\n\t\tBanner.Mode getBannerMode() {\n\t\t\treturn this.properties.getBannerMode(new MockEnvironment());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleConfig {\n\n\t\t@Bean\n\t\tString someBean() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OverrideConfig {\n\n\t\t@Bean\n\t\tString someBean() {\n\t\t\treturn \"override\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BrokenPostConstructConfig {\n\n\t\t@Bean\n\t\tThing thing() {\n\t\t\treturn new Thing();\n\t\t}\n\n\t\tstatic class Thing {\n\n\t\t\t@PostConstruct\n\t\t\tvoid boom() {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BrokenBeanFactoryPostProcessing {\n\n\t\t@Bean\n\t\tstatic BeanFactoryPostProcessor brokenBeanFactoryPostProcessor() {\n\t\t\treturn (beanFactory) -> {\n\t\t\t\tthrow new ApplicationContextException(\"broken\");\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ListenerConfig {\n\n\t\t@Bean\n\t\tApplicationListener<?> testApplicationListener() {\n\t\t\treturn mock(ApplicationListener.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Multicaster {\n\n\t\t@Bean(name = AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)\n\t\tApplicationEventMulticaster applicationEventMulticaster() {\n\t\t\treturn spy(new SimpleApplicationEventMulticaster());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FailingConfig {\n\n\t\t@Bean\n\t\tObject fail() {\n\t\t\tthrow new RuntimeException(\"ExpectedError\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CommandLineRunConfig {\n\n\t\t@Bean\n\t\tTestCommandLineRunner runnerC() {\n\t\t\treturn new TestCommandLineRunner(\"runnerC\", Ordered.LOWEST_PRECEDENCE, \"runnerB\", \"runnerA\");\n\t\t}\n\n\t\t@Bean\n\t\tTestApplicationRunner runnerB() {\n\t\t\treturn new TestApplicationRunner(\"runnerB\", Ordered.LOWEST_PRECEDENCE - 1, \"runnerA\");\n\t\t}\n\n\t\t@Bean\n\t\tTestCommandLineRunner runnerA() {\n\t\t\treturn new TestCommandLineRunner(\"runnerA\", Ordered.HIGHEST_PRECEDENCE);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CommandLineRunParentConfig {\n\n\t\t@Bean\n\t\tTestCommandLineRunner runnerP() {\n\t\t\treturn new TestCommandLineRunner(\"runnerP\", Ordered.LOWEST_PRECEDENCE);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BeanDefinitionOrderRunnerConfig {\n\n\t\tprivate final List<String> runners = new ArrayList<>();\n\n\t\t@Bean\n\t\t@Order\n\t\tCommandLineRunner runnerC() {\n\t\t\treturn (args) -> this.runners.add(\"runnerC\");\n\t\t}\n\n\t\t@Bean\n\t\t@Order(Ordered.LOWEST_PRECEDENCE - 1)\n\t\tApplicationRunner runnerB() {\n\t\t\treturn (args) -> this.runners.add(\"runnerB\");\n\t\t}\n\n\t\t@Bean\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tCommandLineRunner runnerA() {\n\t\t\treturn (args) -> this.runners.add(\"runnerA\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExitCodeCommandLineRunConfig {\n\n\t\t@Bean\n\t\tCommandLineRunner runner() {\n\t\t\treturn (args) -> {\n\t\t\t\tthrow new IllegalStateException(new ExitStatusException());\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MappedExitCodeCommandLineRunConfig {\n\n\t\t@Bean\n\t\tCommandLineRunner runner() {\n\t\t\treturn (args) -> {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tExitCodeExceptionMapper exceptionMapper() {\n\t\t\treturn (exception) -> {\n\t\t\t\tif (exception instanceof IllegalStateException) {\n\t\t\t\t\treturn 11;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RefreshFailureConfig {\n\n\t\t@PostConstruct\n\t\tvoid fail() {\n\t\t\tthrow new RefreshFailureException();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LazyInitializationConfig {\n\n\t\t@Bean\n\t\tAtomicInteger counter() {\n\t\t\treturn new AtomicInteger();\n\t\t}\n\n\t\t@Bean\n\t\tLazyBean lazyBean(AtomicInteger counter) {\n\t\t\treturn new LazyBean(counter);\n\t\t}\n\n\t\tstatic class LazyBean {\n\n\t\t\tLazyBean(AtomicInteger counter) {\n\t\t\t\tcounter.incrementAndGet();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotLazyInitializationConfig {\n\n\t\t@Bean\n\t\tAtomicInteger counter() {\n\t\t\treturn new AtomicInteger();\n\t\t}\n\n\t\t@Bean\n\t\t@Lazy(false)\n\t\tNotLazyBean NotLazyBean(AtomicInteger counter) {\n\t\t\treturn new NotLazyBean(counter);\n\t\t}\n\n\t\tstatic class NotLazyBean {\n\n\t\t\tNotLazyBean(AtomicInteger counter) {\n\t\t\t\tcounter.getAndIncrement();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LazyInitializationExcludeFilterConfig {\n\n\t\t@Bean\n\t\tAtomicInteger counter() {\n\t\t\treturn new AtomicInteger();\n\t\t}\n\n\t\t@Bean\n\t\tNotLazyBean notLazyBean(AtomicInteger counter) {\n\t\t\treturn new NotLazyBean(counter);\n\t\t}\n\n\t\t@Bean\n\t\tstatic LazyInitializationExcludeFilter lazyInitializationExcludeFilter() {\n\t\t\treturn LazyInitializationExcludeFilter.forBeanTypes(NotLazyBean.class);\n\t\t}\n\n\t}\n\n\tstatic class NotLazyBean {\n\n\t\tNotLazyBean(AtomicInteger counter) {\n\t\t\tcounter.getAndIncrement();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@org.springframework.context.annotation.PropertySource(\"classpath:spring-application-config-property-source.properties\")\n\tstatic class PropertySourceConfig {\n\n\t}\n\n\tstatic class ExitStatusException extends RuntimeException implements ExitCodeGenerator {\n\n\t\t@Override\n\t\tpublic int getExitCode() {\n\t\t\treturn 11;\n\t\t}\n\n\t}\n\n\tstatic class RefreshFailureException extends RuntimeException {\n\n\t}\n\n\tabstract static class AbstractTestRunner implements ApplicationContextAware, Ordered {\n\n\t\tprivate final String[] expectedBefore;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ApplicationContext applicationContext;\n\n\t\tprivate final int order;\n\n\t\tprivate boolean run;\n\n\t\tAbstractTestRunner(int order, String... expectedBefore) {\n\t\t\tthis.expectedBefore = expectedBefore;\n\t\t\tthis.order = order;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setApplicationContext(ApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn this.order;\n\t\t}\n\n\t\tvoid markAsRan() {\n\t\t\tthis.run = true;\n\t\t\tfor (String name : this.expectedBefore) {\n\t\t\t\tAbstractTestRunner bean = this.applicationContext.getBean(name, AbstractTestRunner.class);\n\t\t\t\tassertThat(bean.hasRun()).isTrue();\n\t\t\t}\n\t\t}\n\n\t\tboolean hasRun() {\n\t\t\treturn this.run;\n\t\t}\n\n\t}\n\n\tstatic class TestCommandLineRunner extends AbstractTestRunner implements CommandLineRunner {\n\n\t\tprivate final String name;\n\n\t\tTestCommandLineRunner(String name, int order, String... expectedBefore) {\n\t\t\tsuper(order, expectedBefore);\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run(String... args) {\n\t\t\tSystem.out.println(\">>> \" + this.name);\n\t\t\tmarkAsRan();\n\t\t}\n\n\t}\n\n\tstatic class TestApplicationRunner extends AbstractTestRunner implements ApplicationRunner {\n\n\t\tprivate final String name;\n\n\t\tTestApplicationRunner(String name, int order, String... expectedBefore) {\n\t\t\tsuper(order, expectedBefore);\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run(ApplicationArguments args) {\n\t\t\tSystem.out.println(\">>> \" + this.name);\n\t\t\tmarkAsRan();\n\t\t}\n\n\t}\n\n\tstatic class ExitCodeListener implements ApplicationListener<ExitCodeEvent> {\n\n\t\tprivate @Nullable Integer exitCode;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ExitCodeEvent event) {\n\t\t\tthis.exitCode = event.getExitCode();\n\t\t}\n\n\t\t@Nullable Integer getExitCode() {\n\t\t\treturn this.exitCode;\n\t\t}\n\n\t}\n\n\tstatic class MockResourceLoader implements ResourceLoader {\n\n\t\tprivate final Map<String, Resource> resources = new HashMap<>();\n\n\t\tvoid addResource(String source, String path) {\n\t\t\tthis.resources.put(source, new ClassPathResource(path, getClass()));\n\t\t}\n\n\t\t@Override\n\t\tpublic Resource getResource(String path) {\n\t\t\tResource resource = this.resources.get(path);\n\t\t\treturn (resource != null) ? resource : new ClassPathResource(\"doesnotexist\");\n\t\t}\n\n\t\t@Override\n\t\tpublic ClassLoader getClassLoader() {\n\t\t\treturn getClass().getClassLoader();\n\t\t}\n\n\t}\n\n\tstatic class TestApplicationListener implements ApplicationListener<ApplicationEvent> {\n\n\t\tprivate final MultiValueMap<Class<?>, ApplicationEvent> events = new LinkedMultiValueMap<>();\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tthis.events.add(event.getClass(), event);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\t<E extends ApplicationEvent> E getEvent(Class<E> type) {\n\t\t\tList<ApplicationEvent> events = this.events.get(type);\n\t\t\tassertThat(events).isNotNull();\n\t\t\treturn (E) events.get(0);\n\t\t}\n\n\t}\n\n\tstatic class Example {\n\n\t}\n\n\t@FunctionalInterface\n\tinterface ExampleConfigurer {\n\n\t\tvoid configure(Example example);\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleProducerConfiguration {\n\n\t\t@Bean\n\t\tExample example(ObjectProvider<ExampleConfigurer> configurers) {\n\t\t\tExample example = new Example();\n\t\t\tconfigurers.orderedStream().forEach((configurer) -> configurer.configure(example));\n\t\t\treturn example;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleConsumerConfiguration {\n\n\t\t@Autowired\n\t\tExample example;\n\n\t\t@Bean\n\t\tExampleConfigurer configurer() {\n\t\t\treturn (example) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class ExampleAotProcessedMainClass {\n\n\t}\n\n\tstatic class ExampleAotProcessedMainClass__ApplicationContextInitializer\n\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tapplicationContext.getBeanFactory().registerSingleton(\"test\", \"test\");\n\t\t}\n\n\t}\n\n\tstatic class ExampleFromMainMethod {\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tapplication.run(args);\n\t\t}\n\n\t}\n\n\tstatic class MultipleApplicationsMainMethod {\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication application = new SpringApplication(ExampleConfig.class);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tapplication.addListeners(new ApplicationListener<ApplicationEnvironmentPreparedEvent>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\t\t\t\tSpringApplicationBuilder builder = new SpringApplicationBuilder(\n\t\t\t\t\t\t\tInnerApplicationConfiguration.class);\n\t\t\t\t\tbuilder.web(WebApplicationType.NONE);\n\t\t\t\t\tbuilder.run().close();\n\t\t\t\t}\n\n\t\t\t});\n\t\t\tapplication.run(args);\n\t\t}\n\n\t\tstatic class InnerApplicationConfiguration {\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class ExampleAdditionalConfig {\n\n\t\tstatic ThreadLocal<ExampleAdditionalConfig> local = new ThreadLocal<>();\n\n\t\tExampleAdditionalConfig() {\n\t\t\tlocal.set(this);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class SingleUseAdditionalConfig {\n\n\t\tprivate static AtomicBoolean used = new AtomicBoolean(false);\n\n\t\tSingleUseAdditionalConfig() {\n\t\t\tif (!used.compareAndSet(false, true)) {\n\t\t\t\tthrow new IllegalStateException(\"Single-use configuration has already been used\");\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class ProfileConfig {\n\n\t\t@Bean\n\t\t@Profile(\"custom\")\n\t\tExample example() {\n\t\t\treturn new Example();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringBootConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootConfiguration @SpringBootConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass SpringBootConfigurationTests {\n\n\t@Test\n\tvoid proxyBeanMethodsIsEnabledByDefault() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(DefaultSpringBootConfiguration.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", true);\n\t}\n\n\t@Test\n\tvoid proxyBeanMethodsCanBeDisabled() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(NoBeanMethodProxyingSpringBootConfiguration.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", false);\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class DefaultSpringBootConfiguration {\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tstatic class NoBeanMethodProxyingSpringBootConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringBootExceptionHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.lang.reflect.InvocationTargetException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringBootExceptionHandler}.\n *\n * @author Henri Tremblay\n * @author Andy Wilkinson\n */\nclass SpringBootExceptionHandlerTests {\n\n\tprivate final UncaughtExceptionHandler parent = mock(UncaughtExceptionHandler.class);\n\n\tprivate final SpringBootExceptionHandler handler = new SpringBootExceptionHandler(this.parent);\n\n\t@Test\n\tvoid uncaughtExceptionDoesNotForwardLoggedErrorToParent() {\n\t\tThread thread = Thread.currentThread();\n\t\tException ex = new Exception();\n\t\tthis.handler.registerLoggedException(ex);\n\t\tthis.handler.uncaughtException(thread, ex);\n\t\tthen(this.parent).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid uncaughtExceptionForwardsLogConfigurationErrorToParent() {\n\t\tThread thread = Thread.currentThread();\n\t\tException ex = new Exception(\"[stuff] Logback configuration error detected [stuff]\");\n\t\tthis.handler.registerLoggedException(ex);\n\t\tthis.handler.uncaughtException(thread, ex);\n\t\tthen(this.parent).should().uncaughtException(thread, ex);\n\t}\n\n\t@Test\n\tvoid uncaughtExceptionForwardsWrappedLogConfigurationErrorToParent() {\n\t\tThread thread = Thread.currentThread();\n\t\tException ex = new InvocationTargetException(\n\t\t\t\tnew Exception(\"[stuff] Logback configuration error detected [stuff]\", new Exception()));\n\t\tthis.handler.registerLoggedException(ex);\n\t\tthis.handler.uncaughtException(thread, ex);\n\t\tthen(this.parent).should().uncaughtException(thread, ex);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/SpringBootVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootVersion}.\n *\n * @author Andy Wilkinson\n */\nclass SpringBootVersionTests {\n\n\t@Test\n\tvoid getVersionShouldReturnVersionMatchingGradleProperties() throws IOException {\n\t\tString expectedVersion = PropertiesLoaderUtils.loadProperties(new FileSystemResource(findGradleProperties()))\n\t\t\t.getProperty(\"version\");\n\t\tassertThat(SpringBootVersion.getVersion()).isEqualTo(expectedVersion);\n\t}\n\n\tprivate File findGradleProperties() {\n\t\tFile current = new File(\".\").getAbsoluteFile();\n\t\twhile (current != null) {\n\t\t\tFile gradleProperties = new File(current, \"gradle.properties\");\n\t\t\tSystem.out.println(gradleProperties);\n\t\t\tif (gradleProperties.isFile()) {\n\t\t\t\treturn gradleProperties;\n\t\t\t}\n\t\t\tcurrent = current.getParentFile();\n\t\t}\n\t\tthrow new IllegalStateException(\"Could not find gradle.properties\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/StartupInfoLoggerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication.Startup;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StartupInfoLogger}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nclass StartupInfoLoggerTests {\n\n\tprivate final Log log = mock(Log.class);\n\n\tprivate MockEnvironment environment;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"spring.application.version\", \"1.2.3\");\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"42\");\n\t}\n\n\t@Test\n\tvoid startingFormat() {\n\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\tnew StartupInfoLogger(getClass(), this.environment).logStarting(this.log);\n\t\tthen(this.log).should()\n\t\t\t.info(assertArg(\n\t\t\t\t\t(message) -> assertThat(message.toString()).contains(\"Starting \" + getClass().getSimpleName()\n\t\t\t\t\t\t\t+ \" v1.2.3 using Java \" + System.getProperty(\"java.version\") + \" with PID 42 (started by \"\n\t\t\t\t\t\t\t+ System.getProperty(\"user.name\") + \" in \" + System.getProperty(\"user.dir\") + \")\")));\n\t}\n\n\t@Test\n\tvoid startingFormatWhenVersionIsNotAvailable() {\n\t\tthis.environment.setProperty(\"spring.application.version\", \"\");\n\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\tnew StartupInfoLogger(getClass(), this.environment).logStarting(this.log);\n\t\tthen(this.log).should()\n\t\t\t.info(assertArg(\n\t\t\t\t\t(message) -> assertThat(message.toString()).contains(\"Starting \" + getClass().getSimpleName()\n\t\t\t\t\t\t\t+ \" using Java \" + System.getProperty(\"java.version\") + \" with PID 42 (started by \"\n\t\t\t\t\t\t\t+ System.getProperty(\"user.name\") + \" in \" + System.getProperty(\"user.dir\") + \")\")));\n\t}\n\n\t@Test\n\tvoid startingFormatWhenPidIsNotAvailable() {\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"\");\n\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\tnew StartupInfoLogger(getClass(), this.environment).logStarting(this.log);\n\t\tthen(this.log).should()\n\t\t\t.info(assertArg(\n\t\t\t\t\t(message) -> assertThat(message.toString()).contains(\"Starting \" + getClass().getSimpleName()\n\t\t\t\t\t\t\t+ \" v1.2.3 using Java \" + System.getProperty(\"java.version\") + \" (started by \"\n\t\t\t\t\t\t\t+ System.getProperty(\"user.name\") + \" in \" + System.getProperty(\"user.dir\") + \")\")));\n\t}\n\n\t@Test\n\tvoid startingFormatInAotMode() {\n\t\tSystem.setProperty(\"spring.aot.enabled\", \"true\");\n\t\ttry {\n\t\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\t\tnew StartupInfoLogger(getClass(), this.environment).logStarting(this.log);\n\t\t\tthen(this.log).should()\n\t\t\t\t.info(assertArg((message) -> assertThat(message.toString())\n\t\t\t\t\t.contains(\"Starting AOT-processed \" + getClass().getSimpleName() + \" v1.2.3 using Java \"\n\t\t\t\t\t\t\t+ System.getProperty(\"java.version\") + \" with PID 42 (started by \"\n\t\t\t\t\t\t\t+ System.getProperty(\"user.name\") + \" in \" + System.getProperty(\"user.dir\") + \")\")));\n\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"spring.aot.enabled\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid startedFormat() {\n\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\tnew StartupInfoLogger(getClass(), this.environment).logStarted(this.log, new TestStartup(1345L, \"Started\"));\n\t\tthen(this.log).should()\n\t\t\t.info(assertArg((message) -> assertThat(message.toString()).matches(\"Started \" + getClass().getSimpleName()\n\t\t\t\t\t+ \" in \\\\d+\\\\.\\\\d{1,3} seconds \\\\(process running for 1.345\\\\)\")));\n\t}\n\n\t@Test\n\tvoid startedWithoutUptimeFormat() {\n\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\tnew StartupInfoLogger(getClass(), this.environment).logStarted(this.log, new TestStartup(null, \"Started\"));\n\t\tthen(this.log).should()\n\t\t\t.info(assertArg((message) -> assertThat(message.toString())\n\t\t\t\t.matches(\"Started \" + getClass().getSimpleName() + \" in \\\\d+\\\\.\\\\d{1,3} seconds\")));\n\t}\n\n\t@Test\n\tvoid restoredFormat() {\n\t\tgiven(this.log.isInfoEnabled()).willReturn(true);\n\t\tnew StartupInfoLogger(getClass(), this.environment).logStarted(this.log, new TestStartup(null, \"Restored\"));\n\t\tthen(this.log).should()\n\t\t\t.info(assertArg((message) -> assertThat(message.toString())\n\t\t\t\t.matches(\"Restored \" + getClass().getSimpleName() + \" in \\\\d+\\\\.\\\\d{1,3} seconds\")));\n\t}\n\n\tstatic class TestStartup extends Startup {\n\n\t\tprivate final long startTime = System.currentTimeMillis();\n\n\t\tprivate final @Nullable Long uptime;\n\n\t\tprivate final String action;\n\n\t\tTestStartup(@Nullable Long uptime, String action) {\n\t\t\tthis.uptime = uptime;\n\t\t\tthis.action = action;\n\t\t\tstarted();\n\t\t}\n\n\t\t@Override\n\t\tprotected long startTime() {\n\t\t\treturn this.startTime;\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable Long processUptime() {\n\t\t\treturn this.uptime;\n\t\t}\n\n\t\t@Override\n\t\tprotected String action() {\n\t\t\treturn this.action;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/TestApplicationEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\n/**\n * Public version {@link ApplicationEnvironment} for tests to use.\n *\n * @author Phillip Webb\n */\npublic class TestApplicationEnvironment extends ApplicationEnvironment {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/WithSampleBeansXmlResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\n/**\n * Makes an {@code org/springframework/boot/sample-beans.xml} resource available from the\n * thread context classloader.\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\n@WithResource(name = \"org/springframework/boot/sample-beans.xml\",\n\t\tcontent = \"\"\"\n\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\t\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\txmlns:context=\"http://www.springframework.org/schema/context\"\n\t\t\t\t\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\n\t\t\t\t\t\t\t\thttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\t\t\t\t\t<bean id=\"myXmlComponent\" class=\"org.springframework.boot.sampleconfig.MyComponent\"/>\n\t\t\t\t</beans>\n\t\t\t\t\"\"\")\n@interface WithSampleBeansXmlResource {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.admin;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Map;\n\nimport javax.management.InstanceNotFoundException;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringApplicationAdminMXBeanRegistrar}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass SpringApplicationAdminMXBeanRegistrarTests {\n\n\tprivate static final String OBJECT_NAME = \"org.springframework.boot:type=Test,name=SpringApplication\";\n\n\tprivate MBeanServer mBeanServer;\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.mBeanServer = ManagementFactory.getPlatformMBeanServer();\n\t}\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid validateReadyFlag() {\n\t\tfinal ObjectName objectName = createObjectName(OBJECT_NAME);\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addListeners((ContextRefreshedEvent event) -> {\n\t\t\ttry {\n\t\t\t\tassertThat(isApplicationReady(objectName)).isFalse();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(\"Could not contact spring application admin bean\", ex);\n\t\t\t}\n\t\t});\n\t\tthis.context = application.run();\n\t\tassertThat(isApplicationReady(objectName)).isTrue();\n\t}\n\n\t@Test\n\tvoid eventsFromOtherContextsAreIgnored() throws MalformedObjectNameException {\n\t\tSpringApplicationAdminMXBeanRegistrar registrar = new SpringApplicationAdminMXBeanRegistrar(OBJECT_NAME);\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tregistrar.setApplicationContext(context);\n\t\tregistrar.onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0],\n\t\t\t\tmock(ConfigurableApplicationContext.class), null));\n\t\tassertThat(isApplicationReady(registrar)).isFalse();\n\t\tregistrar\n\t\t\t.onApplicationReadyEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context, null));\n\t\tassertThat(isApplicationReady(registrar)).isTrue();\n\t}\n\n\tprivate boolean isApplicationReady(SpringApplicationAdminMXBeanRegistrar registrar) {\n\t\tObject field = ReflectionTestUtils.getField(registrar, \"ready\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (Boolean) field;\n\t}\n\n\t@Test\n\tvoid environmentIsExposed() {\n\t\tfinal ObjectName objectName = createObjectName(OBJECT_NAME);\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run(\"--foo.bar=blam\");\n\t\tassertThat(isApplicationReady(objectName)).isTrue();\n\t\tassertThat(isApplicationEmbeddedWebApplication(objectName)).isFalse();\n\t\tassertThat(getProperty(objectName, \"foo.bar\")).isEqualTo(\"blam\");\n\t\tassertThat(getProperty(objectName, \"does.not.exist.test\")).isNull();\n\t}\n\n\t@Test\n\tvoid whenEnvironmentContainsServerPortsPropertySourceEmbeddedWebApplicationIsDetected() {\n\t\tfinal ObjectName objectName = createObjectName(OBJECT_NAME);\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addInitializers((context) -> context.getEnvironment()\n\t\t\t.getPropertySources()\n\t\t\t.addLast(new MapPropertySource(\"server.ports\", Map.of(\"local.server.port\", \"8910\"))));\n\t\tthis.context = application.run(\"--foo.bar=blam\");\n\t\tassertThat(isApplicationReady(objectName)).isTrue();\n\t\tassertThat(isApplicationEmbeddedWebApplication(objectName)).isTrue();\n\t}\n\n\t@Test\n\tvoid shutdownApp() {\n\t\tfinal ObjectName objectName = createObjectName(OBJECT_NAME);\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.isRunning()).isTrue();\n\t\tinvokeShutdown(objectName);\n\t\tassertThat(this.context.isRunning()).isFalse();\n\t\t// JMX cleanup\n\t\tassertThatExceptionOfType(InstanceNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.mBeanServer.getObjectInstance(objectName));\n\t}\n\n\tprivate Boolean isApplicationReady(ObjectName objectName) {\n\t\treturn getAttribute(objectName, Boolean.class, \"Ready\");\n\t}\n\n\tprivate Boolean isApplicationEmbeddedWebApplication(ObjectName objectName) {\n\t\treturn getAttribute(objectName, Boolean.class, \"EmbeddedWebApplication\");\n\t}\n\n\tprivate String getProperty(ObjectName objectName, String key) {\n\t\ttry {\n\t\t\treturn (String) this.mBeanServer.invoke(objectName, \"getProperty\", new Object[] { key },\n\t\t\t\t\tnew String[] { String.class.getName() });\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate <T> T getAttribute(ObjectName objectName, Class<T> type, String attribute) {\n\t\ttry {\n\t\t\tObject value = this.mBeanServer.getAttribute(objectName, attribute);\n\t\t\tassertThat(value == null || type.isInstance(value)).isTrue();\n\t\t\treturn type.cast(value);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate void invokeShutdown(ObjectName objectName) {\n\t\ttry {\n\t\t\tthis.mBeanServer.invoke(objectName, \"shutdown\", null, null);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate ObjectName createObjectName(String jmxName) {\n\t\ttry {\n\t\t\treturn new ObjectName(jmxName);\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid jmx name \" + jmxName, ex);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tSpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar() throws MalformedObjectNameException {\n\t\t\treturn new SpringApplicationAdminMXBeanRegistrar(OBJECT_NAME);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ansi/Ansi8BitColorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Ansi8BitColor}.\n *\n * @author Toshiaki Maki\n * @author Phillip Webb\n */\nclass Ansi8BitColorTests {\n\n\t@Test\n\tvoid toStringWhenForegroundAddsCorrectPrefix() {\n\t\tassertThat(Ansi8BitColor.foreground(208)).hasToString(\"38;5;208\");\n\t}\n\n\t@Test\n\tvoid toStringWhenBackgroundAddsCorrectPrefix() {\n\t\tassertThat(Ansi8BitColor.background(208)).hasToString(\"48;5;208\");\n\t}\n\n\t@Test\n\tvoid foregroundWhenOutsideBoundsThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Ansi8BitColor.foreground(-1))\n\t\t\t.withMessage(\"'code' must be between 0 and 255\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Ansi8BitColor.foreground(256))\n\t\t\t.withMessage(\"'code' must be between 0 and 255\");\n\t}\n\n\t@Test\n\tvoid backgroundWhenOutsideBoundsThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Ansi8BitColor.background(-1))\n\t\t\t.withMessage(\"'code' must be between 0 and 255\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Ansi8BitColor.background(256))\n\t\t\t.withMessage(\"'code' must be between 0 and 255\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tAnsi8BitColor one = Ansi8BitColor.foreground(123);\n\t\tAnsi8BitColor two = Ansi8BitColor.foreground(123);\n\t\tAnsi8BitColor three = Ansi8BitColor.background(123);\n\t\tassertThat(one).hasSameHashCodeAs(two);\n\t\tassertThat(one).isEqualTo(one).isEqualTo(two).isNotEqualTo(three).isNotNull().isNotEqualTo(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ansi/AnsiOutputEnabledValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\n\n/**\n * Public access to {@link AnsiOutput#getEnabled()} for other tests to use.\n *\n * @author Phillip Webb\n */\npublic final class AnsiOutputEnabledValue {\n\n\tprivate AnsiOutputEnabledValue() {\n\t}\n\n\tpublic static Enabled get() {\n\t\treturn AnsiOutput.getEnabled();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ansi/AnsiOutputTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AnsiOutput}.\n *\n * @author Phillip Webb\n */\nclass AnsiOutputTests {\n\n\t@BeforeAll\n\tstatic void enable() {\n\t\tAnsiOutput.setEnabled(Enabled.ALWAYS);\n\t}\n\n\t@AfterAll\n\tstatic void reset() {\n\t\tAnsiOutput.setEnabled(Enabled.DETECT);\n\t}\n\n\t@Test\n\tvoid encoding() {\n\t\tString encoded = AnsiOutput.toString(\"A\", AnsiColor.RED, AnsiStyle.BOLD, \"B\", AnsiStyle.NORMAL, \"D\",\n\t\t\t\tAnsiColor.GREEN, \"E\", AnsiStyle.FAINT, \"F\");\n\t\tassertThat(encoded).isEqualTo(\"A\u001b[31;1mB\u001b[0mD\u001b[32mE\u001b[2mF\u001b[0;39m\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ansi/AnsiPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ansi;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AnsiPropertySource}.\n *\n * @author Phillip Webb\n * @author Toshiaki Maki\n */\nclass AnsiPropertySourceTests {\n\n\tprivate final AnsiPropertySource source = new AnsiPropertySource(\"ansi\", false);\n\n\t@AfterEach\n\tvoid reset() {\n\t\tAnsiOutput.setEnabled(Enabled.DETECT);\n\t}\n\n\t@Test\n\tvoid getAnsiStyle() {\n\t\tassertThat(this.source.getProperty(\"AnsiStyle.BOLD\")).isEqualTo(AnsiStyle.BOLD);\n\t}\n\n\t@Test\n\tvoid getAnsiColor() {\n\t\tassertThat(this.source.getProperty(\"AnsiColor.RED\")).isEqualTo(AnsiColor.RED);\n\t\tassertThat(this.source.getProperty(\"AnsiColor.100\")).isEqualTo(Ansi8BitColor.foreground(100));\n\t}\n\n\t@Test\n\tvoid getAnsiBackground() {\n\t\tassertThat(this.source.getProperty(\"AnsiBackground.GREEN\")).isEqualTo(AnsiBackground.GREEN);\n\t\tassertThat(this.source.getProperty(\"AnsiBackground.100\")).isEqualTo(Ansi8BitColor.background(100));\n\t}\n\n\t@Test\n\tvoid getAnsi() {\n\t\tassertThat(this.source.getProperty(\"Ansi.BOLD\")).isEqualTo(AnsiStyle.BOLD);\n\t\tassertThat(this.source.getProperty(\"Ansi.RED\")).isEqualTo(AnsiColor.RED);\n\t\tassertThat(this.source.getProperty(\"Ansi.BG_RED\")).isEqualTo(AnsiBackground.RED);\n\t}\n\n\t@Test\n\tvoid getMissing() {\n\t\tassertThat(this.source.getProperty(\"AnsiStyle.NOPE\")).isNull();\n\t}\n\n\t@Test\n\tvoid encodeEnabled() {\n\t\tAnsiOutput.setEnabled(Enabled.ALWAYS);\n\t\tAnsiPropertySource source = new AnsiPropertySource(\"ansi\", true);\n\t\tassertThat(source.getProperty(\"Ansi.RED\")).isEqualTo(\"\\033[31m\");\n\t\tassertThat(source.getProperty(\"AnsiColor.100\")).isEqualTo(\"\\033[38;5;100m\");\n\t\tassertThat(source.getProperty(\"AnsiBackground.100\")).isEqualTo(\"\\033[48;5;100m\");\n\t}\n\n\t@Test\n\tvoid encodeDisabled() {\n\t\tAnsiOutput.setEnabled(Enabled.NEVER);\n\t\tAnsiPropertySource source = new AnsiPropertySource(\"ansi\", true);\n\t\tassertThat(source.getProperty(\"Ansi.RED\")).isEqualTo(\"\");\n\t\tassertThat(source.getProperty(\"AnsiColor.100\")).isEqualTo(\"\");\n\t\tassertThat(source.getProperty(\"AnsiBackground.100\")).isEqualTo(\"\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/availability/ApplicationAvailabilityBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ApplicationAvailabilityBean}\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass ApplicationAvailabilityBeanTests {\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\tprivate ApplicationAvailabilityBean availability;\n\n\tprivate MockLog log;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.context = new AnnotationConfigApplicationContext(TestConfiguration.class);\n\t\tthis.availability = this.context.getBean(ApplicationAvailabilityBean.class);\n\t\tthis.log = this.context.getBean(MockLog.class);\n\t}\n\n\t@Test\n\tvoid getLivenessStateWhenNoEventHasBeenPublishedReturnsDefaultState() {\n\t\tassertThat(this.availability.getLivenessState()).isEqualTo(LivenessState.BROKEN);\n\t}\n\n\t@Test\n\tvoid getLivenessStateWhenEventHasBeenPublishedReturnsPublishedState() {\n\t\tAvailabilityChangeEvent.publish(this.context, LivenessState.CORRECT);\n\t\tassertThat(this.availability.getLivenessState()).isEqualTo(LivenessState.CORRECT);\n\t}\n\n\t@Test\n\tvoid getReadinessStateWhenNoEventHasBeenPublishedReturnsDefaultState() {\n\t\tassertThat(this.availability.getReadinessState()).isEqualTo(ReadinessState.REFUSING_TRAFFIC);\n\t}\n\n\t@Test\n\tvoid getReadinessStateWhenEventHasBeenPublishedReturnsPublishedState() {\n\t\tAvailabilityChangeEvent.publish(this.context, ReadinessState.ACCEPTING_TRAFFIC);\n\t\tassertThat(this.availability.getReadinessState()).isEqualTo(ReadinessState.ACCEPTING_TRAFFIC);\n\t}\n\n\t@Test\n\tvoid getStateWhenNoEventHasBeenPublishedReturnsDefaultState() {\n\t\tassertThat(this.availability.getState(TestState.class)).isNull();\n\t\tassertThat(this.availability.getState(TestState.class, TestState.ONE)).isEqualTo(TestState.ONE);\n\t}\n\n\t@Test\n\tvoid getStateWhenEventHasBeenPublishedReturnsPublishedState() {\n\t\tAvailabilityChangeEvent.publish(this.context, TestState.TWO);\n\t\tassertThat(this.availability.getState(TestState.class)).isEqualTo(TestState.TWO);\n\t\tassertThat(this.availability.getState(TestState.class, TestState.ONE)).isEqualTo(TestState.TWO);\n\t}\n\n\t@Test\n\tvoid getLastChangeEventWhenNoEventHasBeenPublishedReturnsDefaultState() {\n\t\tassertThat(this.availability.getLastChangeEvent(TestState.class)).isNull();\n\t}\n\n\t@Test\n\tvoid getLastChangeEventWhenEventHasBeenPublishedReturnsPublishedState() {\n\t\tAvailabilityChangeEvent.publish(this.context, TestState.TWO);\n\t\tassertThat(this.availability.getLastChangeEvent(TestState.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid stateChangesAreLogged() {\n\t\tAvailabilityChangeEvent.publish(this.context, LivenessState.CORRECT);\n\t\tassertThat(this.log.getLogged()).contains(\"Application availability state LivenessState changed to CORRECT\");\n\t\tAvailabilityChangeEvent.publish(this.context, LivenessState.BROKEN);\n\t\tassertThat(this.log.getLogged())\n\t\t\t.contains(\"Application availability state LivenessState changed from CORRECT to BROKEN\");\n\t}\n\n\t@Test\n\tvoid stateChangesAreLoggedWithExceptionSource() {\n\t\tAvailabilityChangeEvent.publish(this.context, new IOException(\"connection error\"), LivenessState.BROKEN);\n\t\tassertThat(this.log.getLogged()).contains(\"Application availability state LivenessState changed to BROKEN: \"\n\t\t\t\t+ \"java.io.IOException: connection error\");\n\t}\n\n\t@Test\n\tvoid stateChangesAreLoggedWithOtherSource() {\n\t\tAvailabilityChangeEvent.publish(this.context, new CustomEventSource(), LivenessState.BROKEN);\n\t\tassertThat(this.log.getLogged()).contains(\n\t\t\t\t\"Application availability state LivenessState changed to BROKEN: \" + CustomEventSource.class.getName());\n\t}\n\n\tenum TestState implements AvailabilityState {\n\n\t\tONE {\n\t\t\t@Override\n\t\t\tpublic String test() {\n\t\t\t\treturn \"spring\";\n\t\t\t}\n\t\t},\n\n\t\tTWO {\n\t\t\t@Override\n\t\t\tpublic String test() {\n\t\t\t\treturn \"boot\";\n\t\t\t}\n\t\t};\n\n\t\tabstract String test();\n\n\t}\n\n\tstatic class CustomEventSource {\n\n\t}\n\n\t@Configuration\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tMockLog mockLog() {\n\t\t\tList<String> logged = new ArrayList<>();\n\t\t\tMockLog log = mock(MockLog.class);\n\t\t\tgiven(log.isDebugEnabled()).willReturn(true);\n\t\t\tgiven(log.getLogged()).willReturn(logged);\n\t\t\twillAnswer((invocation) -> logged.add(\"\" + invocation.getArguments()[0])).given(log).debug(any());\n\t\t\treturn log;\n\t\t}\n\n\t\t@Bean\n\t\tApplicationAvailabilityBean applicationAvailabilityBean(MockLog log) {\n\t\t\treturn new ApplicationAvailabilityBean(log);\n\t\t}\n\n\t}\n\n\tinterface MockLog extends Log {\n\n\t\tList<String> getLogged();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/availability/AvailabilityChangeEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.availability;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.EventListener;\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AvailabilityChangeEvent}.\n *\n * @author Phillip Webb\n */\nclass AvailabilityChangeEventTests {\n\n\tprivate final Object source = new Object();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenStateIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new AvailabilityChangeEvent<>(this.source, null))\n\t\t\t.withMessage(\"Payload must not be null\");\n\t}\n\n\t@Test\n\tvoid getStateReturnsState() {\n\t\tLivenessState state = LivenessState.CORRECT;\n\t\tAvailabilityChangeEvent<LivenessState> event = new AvailabilityChangeEvent<>(this.source, state);\n\t\tassertThat(event.getState()).isEqualTo(state);\n\t}\n\n\t@Test\n\tvoid getResolvableType() {\n\t\tLivenessState state = LivenessState.CORRECT;\n\t\tAvailabilityChangeEvent<LivenessState> event = new AvailabilityChangeEvent<>(this.source, state);\n\t\tResolvableType type = event.getResolvableType();\n\t\tassertThat(type.resolve()).isEqualTo(AvailabilityChangeEvent.class);\n\t\tassertThat(type.resolveGeneric()).isEqualTo(LivenessState.class);\n\t}\n\n\t@Test\n\tvoid getResolvableTypeWhenSubclassedEnum() {\n\t\tSubClassedEnum state = SubClassedEnum.TWO;\n\t\tAvailabilityChangeEvent<SubClassedEnum> event = new AvailabilityChangeEvent<>(this.source, state);\n\t\tResolvableType type = event.getResolvableType();\n\t\tassertThat(type.resolve()).isEqualTo(AvailabilityChangeEvent.class);\n\t\tassertThat(type.resolveGeneric()).isEqualTo(SubClassedEnum.class);\n\t}\n\n\t@Test\n\tvoid publishPublishesEvent() {\n\t\tApplicationContext context = mock(ApplicationContext.class);\n\t\tAvailabilityState state = LivenessState.CORRECT;\n\t\tAvailabilityChangeEvent.publish(context, state);\n\t\tthen(context).should()\n\t\t\t.publishEvent(assertArg((event) -> assertThat(event).isInstanceOfSatisfying(AvailabilityChangeEvent.class,\n\t\t\t\t\t(castedEvent) -> {\n\t\t\t\t\t\tassertThat(castedEvent.getSource()).isEqualTo(context);\n\t\t\t\t\t\tassertThat(castedEvent.getState()).isEqualTo(state);\n\t\t\t\t\t})));\n\t}\n\n\t@Test\n\tvoid publishEvenToContextConsidersGenericType() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);\n\t\tAvailabilityChangeEvent.publish(context, LivenessState.CORRECT);\n\t\tAvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);\n\t}\n\n\tenum SubClassedEnum implements AvailabilityState {\n\n\t\tONE {\n\n\t\t\t@Override\n\t\t\tString getDescription() {\n\t\t\t\treturn \"I have been overridden\";\n\t\t\t}\n\n\t\t},\n\n\t\tTWO {\n\n\t\t\t@Override\n\t\t\tString getDescription() {\n\t\t\t\treturn \"I have also been overridden\";\n\t\t\t}\n\n\t\t};\n\n\t\tabstract String getDescription();\n\n\t}\n\n\t@Configuration\n\tstatic class Config {\n\n\t\t@EventListener\n\t\tvoid onLivenessAvailabilityChange(AvailabilityChangeEvent<LivenessState> event) {\n\t\t\tassertThat(event.getState()).isInstanceOf(LivenessState.class).isEqualTo(LivenessState.CORRECT);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/bootstrap/DefaultBootstrapContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.bootstrap;\n\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Supplier;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.Scope;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.StaticApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultBootstrapContext}.\n *\n * @author Phillip Webb\n */\nclass DefaultBootstrapContextTests {\n\n\tprivate final DefaultBootstrapContext context = new DefaultBootstrapContext();\n\n\tprivate final AtomicInteger counter = new AtomicInteger();\n\n\tprivate final StaticApplicationContext applicationContext = new StaticApplicationContext();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerWhenTypeIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.context.register(null, InstanceSupplier.of(1)))\n\t\t\t.withMessage(\"'type' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerWhenRegistrationIsNullThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.context.register(Integer.class, null))\n\t\t\t.withMessage(\"'instanceSupplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid registerWhenNotAlreadyRegisteredRegistersInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tassertThat(this.context.get(Integer.class)).isZero();\n\t\tassertThat(this.context.get(Integer.class)).isZero();\n\t}\n\n\t@Test\n\tvoid registerWhenAlreadyRegisteredRegistersReplacedInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tthis.context.register(Integer.class, InstanceSupplier.of(100));\n\t\tassertThat(this.context.get(Integer.class)).isEqualTo(100);\n\t\tassertThat(this.context.get(Integer.class)).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid registerWhenSingletonAlreadyCreatedThrowsException() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tthis.context.get(Integer.class);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.context.register(Integer.class, InstanceSupplier.of(100)))\n\t\t\t.withMessage(\"java.lang.Integer has already been created\");\n\t}\n\n\t@Test\n\tvoid registerWhenPrototypeAlreadyCreatedReplacesInstance() {\n\t\tthis.context.register(Integer.class,\n\t\t\t\tInstanceSupplier.from(this.counter::getAndIncrement).withScope(Scope.PROTOTYPE));\n\t\tthis.context.get(Integer.class);\n\t\tthis.context.register(Integer.class, InstanceSupplier.of(100));\n\t\tassertThat(this.context.get(Integer.class)).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid registerWhenAlreadyCreatedThrowsException() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tthis.context.get(Integer.class);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.context.register(Integer.class, InstanceSupplier.of(100)))\n\t\t\t.withMessage(\"java.lang.Integer has already been created\");\n\t}\n\n\t@Test\n\tvoid registerWithDependencyRegistersInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.of(100));\n\t\tthis.context.register(String.class, this::integerAsString);\n\t\tassertThat(this.context.get(String.class)).isEqualTo(\"100\");\n\t}\n\n\tprivate String integerAsString(BootstrapContext context) {\n\t\treturn String.valueOf(context.get(Integer.class));\n\t}\n\n\t@Test\n\tvoid registerIfAbsentWhenAbsentRegisters() {\n\t\tthis.context.registerIfAbsent(Long.class, InstanceSupplier.of(100L));\n\t\tassertThat(this.context.get(Long.class)).isEqualTo(100L);\n\t}\n\n\t@Test\n\tvoid registerIfAbsentWhenPresentDoesNotRegister() {\n\t\tthis.context.registerIfAbsent(Long.class, InstanceSupplier.of(1L));\n\t\tthis.context.registerIfAbsent(Long.class, InstanceSupplier.of(100L));\n\t\tassertThat(this.context.get(Long.class)).isOne();\n\t}\n\n\t@Test\n\tvoid isRegisteredWhenNotRegisteredReturnsFalse() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tassertThat(this.context.isRegistered(Long.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid isRegisteredWhenRegisteredReturnsTrue() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tassertThat(this.context.isRegistered(Number.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid getRegisteredInstanceSupplierWhenNotRegisteredReturnsNull() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tassertThat(this.context.getRegisteredInstanceSupplier(Long.class)).isNull();\n\t}\n\n\t@Test\n\tvoid getRegisteredInstanceSupplierWhenRegisteredReturnsRegistration() {\n\t\tInstanceSupplier<Number> instanceSupplier = InstanceSupplier.of(1);\n\t\tthis.context.register(Number.class, instanceSupplier);\n\t\tassertThat(this.context.getRegisteredInstanceSupplier(Number.class)).isSameAs(instanceSupplier);\n\t}\n\n\t@Test\n\tvoid getWhenNoRegistrationThrowsIllegalStateException() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.context.get(Long.class))\n\t\t\t.withMessageContaining(\"has not been registered\");\n\t}\n\n\t@Test\n\tvoid getWhenRegisteredAsNullReturnsNull() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(null));\n\t\tassertThat(this.context.get(Number.class)).isNull();\n\t}\n\n\t@Test\n\tvoid getWhenSingletonCreatesOnlyOneInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tassertThat(this.context.get(Integer.class)).isZero();\n\t\tassertThat(this.context.get(Integer.class)).isZero();\n\t}\n\n\t@Test\n\tvoid getWhenPrototypeCreatesOnlyNewInstances() {\n\t\tthis.context.register(Integer.class,\n\t\t\t\tInstanceSupplier.from(this.counter::getAndIncrement).withScope(Scope.PROTOTYPE));\n\t\tassertThat(this.context.get(Integer.class)).isZero();\n\t\tassertThat(this.context.get(Integer.class)).isOne();\n\t}\n\n\t@Test\n\tvoid testName() {\n\n\t}\n\n\t@Test\n\tvoid getOrElseWhenNoRegistrationReturnsOther() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tassertThat(this.context.getOrElse(Long.class, -1L)).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid getOrElseWhenRegisteredAsNullReturnsNull() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(null));\n\t\tassertThat(this.context.getOrElse(Number.class, -1)).isNull();\n\t}\n\n\t@Test\n\tvoid getOrElseCreatesReturnsOnlyOneInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tassertThat(this.context.getOrElse(Integer.class, -1)).isZero();\n\t\tassertThat(this.context.getOrElse(Integer.class, -1)).isZero();\n\t}\n\n\t@Test\n\tvoid getOrElseSupplyWhenNoRegistrationReturnsSupplied() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tSupplier<@Nullable Long> supplier = () -> -1L;\n\t\tassertThat(this.context.getOrElseSupply(Long.class, supplier)).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid getOrElseSupplyWhenRegisteredAsNullReturnsNull() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(null));\n\t\tSupplier<@Nullable Number> supplier = () -> -1L;\n\t\tassertThat(this.context.getOrElseSupply(Number.class, supplier)).isNull();\n\t}\n\n\t@Test\n\tvoid getOrElseSupplyCreatesOnlyOneInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tSupplier<@Nullable Integer> supplier = () -> -1;\n\t\tassertThat(this.context.getOrElseSupply(Integer.class, supplier)).isZero();\n\t\tassertThat(this.context.getOrElseSupply(Integer.class, supplier)).isZero();\n\t}\n\n\t@Test\n\tvoid getOrElseThrowWhenNoRegistrationThrowsSuppliedException() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(1));\n\t\tassertThatIOException().isThrownBy(() -> this.context.getOrElseThrow(Long.class, IOException::new));\n\t}\n\n\t@Test\n\tvoid getOrElseThrowWhenRegisteredAsNullReturnsNull() {\n\t\tthis.context.register(Number.class, InstanceSupplier.of(null));\n\t\tassertThat(this.context.getOrElseThrow(Number.class, RuntimeException::new)).isNull();\n\t}\n\n\t@Test\n\tvoid getOrElseThrowCreatesOnlyOneInstance() {\n\t\tthis.context.register(Integer.class, InstanceSupplier.from(this.counter::getAndIncrement));\n\t\tassertThat(this.context.getOrElseThrow(Integer.class, RuntimeException::new)).isZero();\n\t\tassertThat(this.context.getOrElseThrow(Integer.class, RuntimeException::new)).isZero();\n\t}\n\n\t@Test\n\tvoid closeMulticastsEventToListeners() {\n\t\tTestCloseListener listener = new TestCloseListener();\n\t\tthis.context.addCloseListener(listener);\n\t\tassertThat(listener).wasNotCalled();\n\t\tthis.context.close(this.applicationContext);\n\t\tassertThat(listener).wasCalledOnlyOnce()\n\t\t\t.hasBootstrapContextSameAs(this.context)\n\t\t\t.hasApplicationContextSameAs(this.applicationContext);\n\t}\n\n\t@Test\n\tvoid addCloseListenerIgnoresMultipleCallsWithSameListener() {\n\t\tTestCloseListener listener = new TestCloseListener();\n\t\tthis.context.addCloseListener(listener);\n\t\tthis.context.addCloseListener(listener);\n\t\tthis.context.close(this.applicationContext);\n\t\tassertThat(listener).wasCalledOnlyOnce();\n\t}\n\n\t@Test\n\tvoid instanceSupplierGetScopeWhenNotConfiguredReturnsSingleton() {\n\t\tInstanceSupplier<String> supplier = InstanceSupplier.of(\"test\");\n\t\tassertThat(supplier.getScope()).isEqualTo(Scope.SINGLETON);\n\t\tassertThat(supplier.get(mock(BootstrapContext.class))).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid instanceSupplierWithScopeChangesScope() {\n\t\tInstanceSupplier<String> supplier = InstanceSupplier.of(\"test\").withScope(Scope.PROTOTYPE);\n\t\tassertThat(supplier.getScope()).isEqualTo(Scope.PROTOTYPE);\n\t\tassertThat(supplier.get(mock(BootstrapContext.class))).isEqualTo(\"test\");\n\t}\n\n\tprivate static final class TestCloseListener\n\t\t\timplements ApplicationListener<BootstrapContextClosedEvent>, AssertProvider<CloseListenerAssert> {\n\n\t\tprivate int called;\n\n\t\tprivate @Nullable BootstrapContext bootstrapContext;\n\n\t\tprivate @Nullable ConfigurableApplicationContext applicationContext;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(BootstrapContextClosedEvent event) {\n\t\t\tthis.called++;\n\t\t\tthis.bootstrapContext = event.getBootstrapContext();\n\t\t\tthis.applicationContext = event.getApplicationContext();\n\t\t}\n\n\t\t@Override\n\t\tpublic CloseListenerAssert assertThat() {\n\t\t\treturn new CloseListenerAssert(this);\n\t\t}\n\n\t}\n\n\tprivate static class CloseListenerAssert extends AbstractAssert<CloseListenerAssert, TestCloseListener> {\n\n\t\tCloseListenerAssert(TestCloseListener actual) {\n\t\t\tsuper(actual, CloseListenerAssert.class);\n\t\t}\n\n\t\tCloseListenerAssert wasCalledOnlyOnce() {\n\t\t\tassertThat(this.actual.called).as(\"action calls\").isOne();\n\t\t\treturn this;\n\t\t}\n\n\t\tCloseListenerAssert wasNotCalled() {\n\t\t\tassertThat(this.actual.called).as(\"action calls\").isZero();\n\t\t\treturn this;\n\t\t}\n\n\t\tCloseListenerAssert hasBootstrapContextSameAs(BootstrapContext bootstrapContext) {\n\t\t\tassertThat(this.actual.bootstrapContext).isSameAs(bootstrapContext);\n\t\t\treturn this;\n\t\t}\n\n\t\tCloseListenerAssert hasApplicationContextSameAs(ApplicationContext applicationContext) {\n\t\t\tassertThat(this.actual.applicationContext).isSameAs(applicationContext);\n\t\t\treturn this;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.builder;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Collections;\nimport java.util.Properties;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplicationShutdownHookInstance;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Profiles;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link SpringApplicationBuilder}.\n *\n * @author Dave Syer\n */\nclass SpringApplicationBuilderTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tclose(this.context);\n\t\tSpringApplicationShutdownHookInstance.reset();\n\t}\n\n\tprivate void close(@Nullable ApplicationContext context) {\n\t\tif (context != null) {\n\t\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\t\tconfigurableContext.close();\n\t\t\t}\n\t\t\tclose(context.getParent());\n\t\t}\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tb=file\n\t\t\tc=file\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-foo.properties\", content = \"b=profile-specific-file\")\n\tvoid profileAndProperties() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))\n\t\t\t.profiles(\"foo\")\n\t\t\t.properties(\"a=default\");\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isInstanceOf(StaticApplicationContext.class);\n\t\tassertThat(this.context.getEnvironment().getProperty(\"a\")).isEqualTo(\"default\");\n\t\tassertThat(this.context.getEnvironment().getProperty(\"b\")).isEqualTo(\"profile-specific-file\");\n\t\tassertThat(this.context.getEnvironment().getProperty(\"c\")).isEqualTo(\"file\");\n\t\tassertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of(\"foo\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid propertiesAsMap() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))\n\t\t\t.properties(Collections.singletonMap(\"bar\", \"foo\"));\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().getProperty(\"bar\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid propertiesAsProperties() {\n\t\tProperties properties = StringUtils.splitArrayElementsIntoProperties(new String[] { \"bar=foo\" }, \"=\");\n\t\tassertThat(properties).isNotNull();\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))\n\t\t\t.properties(properties);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().getProperty(\"bar\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid propertiesWithRepeatSeparator() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class))\n\t\t\t.properties(\"one=c:\\\\logging.file.name\", \"two=a:b\", \"three:c:\\\\logging.file.name\", \"four:a:b\");\n\t\tthis.context = application.run();\n\t\tConfigurableEnvironment environment = this.context.getEnvironment();\n\t\tassertThat(environment.getProperty(\"one\")).isEqualTo(\"c:\\\\logging.file.name\");\n\t\tassertThat(environment.getProperty(\"two\")).isEqualTo(\"a:b\");\n\t\tassertThat(environment.getProperty(\"three\")).isEqualTo(\"c:\\\\logging.file.name\");\n\t\tassertThat(environment.getProperty(\"four\")).isEqualTo(\"a:b\");\n\t}\n\n\t@Test\n\tvoid specificApplicationContextFactory() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder().sources(ExampleConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(StaticApplicationContext.class));\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isInstanceOf(StaticApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid parentContextCreationThatIsRunDirectly() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tapplication.parent(ExampleConfig.class);\n\t\tthis.context = application.run(\"foo.bar=baz\");\n\t\tthen(((SpyApplicationContext) this.context).getApplicationContext()).should()\n\t\t\t.setParent(any(ApplicationContext.class));\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(this.context);\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.getBean(ApplicationArguments.class).getNonOptionArgs()).contains(\"foo.bar=baz\");\n\t\tassertThat(this.context.getBean(ApplicationArguments.class).getNonOptionArgs()).contains(\"foo.bar=baz\");\n\t}\n\n\t@Test\n\tvoid parentContextCreationThatIsBuiltThenRun() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tapplication.parent(ExampleConfig.class);\n\t\tthis.context = application.build(\"a=alpha\").run(\"b=bravo\");\n\t\tthen(((SpyApplicationContext) this.context).getApplicationContext()).should()\n\t\t\t.setParent(any(ApplicationContext.class));\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(this.context);\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.getBean(ApplicationArguments.class).getNonOptionArgs()).contains(\"a=alpha\");\n\t\tassertThat(this.context.getBean(ApplicationArguments.class).getNonOptionArgs()).contains(\"b=bravo\");\n\t}\n\n\t@Test\n\tvoid parentContextCreationWithChildShutdown() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class))\n\t\t\t.registerShutdownHook(true);\n\t\tapplication.parent(ExampleConfig.class);\n\t\tthis.context = application.run();\n\t\tthen(((SpyApplicationContext) this.context).getApplicationContext()).should()\n\t\t\t.setParent(any(ApplicationContext.class));\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).registeredApplicationContext(this.context);\n\t}\n\n\t@Test\n\tvoid contextWithClassLoader() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());\n\t\tapplication.resourceLoader(new DefaultResourceLoader(classLoader));\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getClassLoader()).isEqualTo(classLoader);\n\t}\n\n\t@Test\n\tvoid parentContextWithClassLoader() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ChildConfig.class)\n\t\t\t.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tClassLoader classLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());\n\t\tapplication.resourceLoader(new DefaultResourceLoader(classLoader));\n\t\tapplication.parent(ExampleConfig.class);\n\t\tthis.context = application.run();\n\t\tResourceLoader resourceLoader = ((SpyApplicationContext) this.context).getResourceLoader();\n\t\tassertThat(resourceLoader).isNotNull();\n\t\tassertThat(resourceLoader.getClassLoader()).isEqualTo(classLoader);\n\t}\n\n\t@Test\n\tvoid parentFirstCreation() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.child(ChildConfig.class);\n\t\tapplication.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tthis.context = application.run();\n\t\tthen(((SpyApplicationContext) this.context).getApplicationContext()).should()\n\t\t\t.setParent(any(ApplicationContext.class));\n\t\tassertThat(SpringApplicationShutdownHookInstance.get()).didNotRegisterApplicationContext(this.context);\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-node.properties\", content = \"bar=spam\")\n\tvoid parentFirstCreationWithProfileAndDefaultArgs() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class).profiles(\"node\")\n\t\t\t.properties(\"transport=redis\")\n\t\t\t.child(ChildConfig.class)\n\t\t\t.web(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of(\"node\"))).isTrue();\n\t\tassertThat(this.context.getEnvironment().getProperty(\"transport\")).isEqualTo(\"redis\");\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.getEnvironment().acceptsProfiles(Profiles.of(\"node\"))).isTrue();\n\t\tassertThat(parent.getEnvironment().getProperty(\"transport\")).isEqualTo(\"redis\");\n\t\t// only defined in node profile\n\t\tassertThat(this.context.getEnvironment().getProperty(\"bar\")).isEqualTo(\"spam\");\n\t}\n\n\t@Test\n\tvoid parentFirstWithDifferentProfile() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class).profiles(\"node\")\n\t\t\t.properties(\"transport=redis\")\n\t\t\t.child(ChildConfig.class)\n\t\t\t.profiles(\"admin\")\n\t\t\t.web(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of(\"node\", \"admin\"))).isTrue();\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.getEnvironment().acceptsProfiles(Profiles.of(\"admin\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid parentWithDifferentProfile() {\n\t\tSpringApplicationBuilder shared = new SpringApplicationBuilder(ExampleConfig.class).profiles(\"node\")\n\t\t\t.properties(\"transport=redis\");\n\t\tSpringApplicationBuilder application = shared.child(ChildConfig.class)\n\t\t\t.profiles(\"admin\")\n\t\t\t.web(WebApplicationType.NONE);\n\t\tshared.profiles(\"parent\");\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of(\"node\", \"admin\"))).isTrue();\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.getEnvironment().acceptsProfiles(Profiles.of(\"node\", \"parent\"))).isTrue();\n\t\tassertThat(parent.getEnvironment().acceptsProfiles(Profiles.of(\"admin\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid parentFirstWithDifferentProfileAndExplicitEnvironment() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.environment(new StandardEnvironment())\n\t\t\t.profiles(\"node\")\n\t\t\t.properties(\"transport=redis\")\n\t\t\t.child(ChildConfig.class)\n\t\t\t.profiles(\"admin\")\n\t\t\t.web(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment().acceptsProfiles(Profiles.of(\"node\", \"admin\"))).isTrue();\n\t\t// Now they share an Environment explicitly so there's no way to keep the profiles\n\t\t// separate\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.getEnvironment().acceptsProfiles(Profiles.of(\"admin\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid parentContextIdentical() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class);\n\t\tapplication.parent(ExampleConfig.class);\n\t\tapplication.contextFactory(ApplicationContextFactory.ofContextClass(SpyApplicationContext.class));\n\t\tthis.context = application.run();\n\t\tthen(((SpyApplicationContext) this.context).getApplicationContext()).should()\n\t\t\t.setParent(any(ApplicationContext.class));\n\t}\n\n\t@Test\n\tvoid initializersCreatedOnce() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.web(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(application.application().getInitializers()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid initializersCreatedOnceForChild() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.child(ChildConfig.class)\n\t\t\t.web(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(application.application().getInitializers()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid initializersIncludeDefaults() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.initializers((ConfigurableApplicationContext applicationContext) -> {\n\t\t\t});\n\t\tthis.context = application.run();\n\t\tassertThat(application.application().getInitializers()).hasSize(4);\n\t}\n\n\t@Test\n\tvoid sourcesWithBoundSources() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder().web(WebApplicationType.NONE)\n\t\t\t.sources(ExampleConfig.class)\n\t\t\t.properties(\"spring.main.sources=\" + ChildConfig.class.getName());\n\t\tthis.context = application.run();\n\t\tthis.context.getBean(ExampleConfig.class);\n\t\tthis.context.getBean(ChildConfig.class);\n\t}\n\n\t@Test\n\tvoid addBootstrapRegistryInitializer() {\n\t\tSpringApplicationBuilder application = new SpringApplicationBuilder(ExampleConfig.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.addBootstrapRegistryInitializer((context) -> context.addCloseListener(\n\t\t\t\t\t(event) -> event.getApplicationContext().getBeanFactory().registerSingleton(\"test\", \"spring\")));\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getBean(\"test\")).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid setEnvironmentPrefix() {\n\t\tSpringApplicationBuilder builder = new SpringApplicationBuilder(ExampleConfig.class).environmentPrefix(\"test\");\n\t\tassertThat(builder.application().getEnvironmentPrefix()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid customApplicationWithResourceLoader() {\n\t\tResourceLoader resourceLoader = mock(ResourceLoader.class);\n\t\tgiven(resourceLoader.getClassLoader()).willReturn(getClass().getClassLoader());\n\t\tSpringApplicationBuilder applicationBuilder = new SpringApplicationBuilder(resourceLoader,\n\t\t\t\tExampleConfig.class) {\n\t\t\t@Override\n\t\t\tprotected SpringApplication createSpringApplication(@Nullable ResourceLoader resourceLoader,\n\t\t\t\t\tClass<?>... sources) {\n\t\t\t\treturn new CustomSpringApplication(resourceLoader, sources);\n\t\t\t}\n\t\t};\n\t\tSpringApplication application = applicationBuilder.build();\n\t\tassertThat(application).asInstanceOf(InstanceOfAssertFactories.type(CustomSpringApplication.class))\n\t\t\t.satisfies((customApp) -> assertThat(customApp.resourceLoader).isEqualTo(resourceLoader));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ChildConfig {\n\n\t}\n\n\tstatic class CustomSpringApplication extends SpringApplication {\n\n\t\tprivate final @Nullable ResourceLoader resourceLoader;\n\n\t\tCustomSpringApplication(@Nullable ResourceLoader resourceLoader, Class<?>... primarySources) {\n\t\t\tsuper(resourceLoader, primarySources);\n\t\t\tthis.resourceLoader = resourceLoader;\n\t\t}\n\n\t}\n\n\tstatic class SpyApplicationContext extends AnnotationConfigApplicationContext {\n\n\t\tprivate final ConfigurableApplicationContext applicationContext = spy(new AnnotationConfigApplicationContext());\n\n\t\tprivate @Nullable ResourceLoader resourceLoader;\n\n\t\t@Override\n\t\tpublic void setParent(@Nullable ApplicationContext parent) {\n\t\t\tthis.applicationContext.setParent(parent);\n\t\t}\n\n\t\tConfigurableApplicationContext getApplicationContext() {\n\t\t\treturn this.applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\t\tsuper.setResourceLoader(resourceLoader);\n\t\t\tthis.resourceLoader = resourceLoader;\n\t\t}\n\n\t\t@Nullable ResourceLoader getResourceLoader() {\n\t\t\treturn this.resourceLoader;\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t\tsuper.close();\n\t\t\tthis.applicationContext.close();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ApplicationContext getParent() {\n\t\t\treturn this.applicationContext.getParent();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/cloud/CloudFoundryVcapEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloud;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryVcapEnvironmentPostProcessor}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nclass CloudFoundryVcapEnvironmentPostProcessorTests {\n\n\tprivate final CloudFoundryVcapEnvironmentPostProcessor initializer = new CloudFoundryVcapEnvironmentPostProcessor(\n\t\t\tSupplier::get);\n\n\tprivate final ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();\n\n\tprivate final SpringApplication application = new SpringApplication();\n\n\t@Test\n\tvoid testApplicationProperties() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,\n\t\t\t\t\"VCAP_APPLICATION={\\\"application_users\\\":[],\\\"instance_id\\\":\\\"bb7935245adf3e650dfb7c58a06e9ece\\\",\"\n\t\t\t\t\t\t+ \"\\\"instance_index\\\":0,\\\"version\\\":\\\"3464e092-1c13-462e-a47c-807c30318a50\\\",\"\n\t\t\t\t\t\t+ \"\\\"name\\\":\\\"foo\\\",\\\"uris\\\":[\\\"foo.cfapps.io\\\"],\"\n\t\t\t\t\t\t+ \"\\\"started_at\\\":\\\"2013-05-29 02:37:59 +0000\\\",\\\"started_at_timestamp\\\":1369795079,\"\n\t\t\t\t\t\t+ \"\\\"host\\\":\\\"0.0.0.0\\\",\\\"port\\\":61034,\"\n\t\t\t\t\t\t+ \"\\\"limits\\\":{\\\"mem\\\":128,\\\"disk\\\":1024,\\\"fds\\\":16384},\"\n\t\t\t\t\t\t+ \"\\\"version\\\":\\\"3464e092-1c13-462e-a47c-807c30318a50\\\",\"\n\t\t\t\t\t\t+ \"\\\"name\\\":\\\"dsyerenv\\\",\\\"uris\\\":[\\\"dsyerenv.cfapps.io\\\"],\"\n\t\t\t\t\t\t+ \"\\\"users\\\":[],\\\"start\\\":\\\"2013-05-29 02:37:59 +0000\\\",\\\"state_timestamp\\\":1369795079}\");\n\t\tthis.initializer.postProcessEnvironment(this.context.getEnvironment(), this.application);\n\t\tassertThat(getProperty(\"vcap.application.instance_id\")).isEqualTo(\"bb7935245adf3e650dfb7c58a06e9ece\");\n\t}\n\n\t@Test\n\tvoid testApplicationUris() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,\n\t\t\t\t\"VCAP_APPLICATION={\\\"instance_id\\\":\\\"bb7935245adf3e650dfb7c58a06e9ece\\\",\\\"instance_index\\\":0,\\\"uris\\\":[\\\"foo.cfapps.io\\\"]}\");\n\t\tthis.initializer.postProcessEnvironment(this.context.getEnvironment(), this.application);\n\t\tassertThat(getProperty(\"vcap.application.uris[0]\")).isEqualTo(\"foo.cfapps.io\");\n\t}\n\n\t@Test\n\tvoid testUnparseableApplicationProperties() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, \"VCAP_APPLICATION:\");\n\t\tthis.initializer.postProcessEnvironment(this.context.getEnvironment(), this.application);\n\t\tassertThat(getProperty(\"vcap\")).isNull();\n\t}\n\n\t@Test\n\tvoid testNullApplicationProperties() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,\n\t\t\t\t\"VCAP_APPLICATION={\\\"application_users\\\":null,\"\n\t\t\t\t\t\t+ \"\\\"instance_id\\\":\\\"bb7935245adf3e650dfb7c58a06e9ece\\\",\"\n\t\t\t\t\t\t+ \"\\\"instance_index\\\":0,\\\"version\\\":\\\"3464e092-1c13-462e-a47c-807c30318a50\\\",\"\n\t\t\t\t\t\t+ \"\\\"name\\\":\\\"foo\\\",\\\"uris\\\":[\\\"foo.cfapps.io\\\"],\"\n\t\t\t\t\t\t+ \"\\\"started_at\\\":\\\"2013-05-29 02:37:59 +0000\\\",\\\"started_at_timestamp\\\":1369795079,\"\n\t\t\t\t\t\t+ \"\\\"host\\\":\\\"0.0.0.0\\\",\\\"port\\\":61034,\"\n\t\t\t\t\t\t+ \"\\\"limits\\\":{\\\"mem\\\":128,\\\"disk\\\":1024,\\\"fds\\\":16384},\"\n\t\t\t\t\t\t+ \"\\\"version\\\":\\\"3464e092-1c13-462e-a47c-807c30318a50\\\",\"\n\t\t\t\t\t\t+ \"\\\"name\\\":\\\"dsyerenv\\\",\\\"uris\\\":[\\\"dsyerenv.cfapps.io\\\"],\"\n\t\t\t\t\t\t+ \"\\\"users\\\":[],\\\"start\\\":\\\"2013-05-29 02:37:59 +0000\\\",\\\"state_timestamp\\\":1369795079}\");\n\t\tthis.initializer.postProcessEnvironment(this.context.getEnvironment(), this.application);\n\t\tassertThat(getProperty(\"vcap\")).isNull();\n\t}\n\n\t@Test\n\tvoid testServiceProperties() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,\n\t\t\t\t\"VCAP_SERVICES={\\\"rds-mysql-n/a\\\":[{\\\"name\\\":\\\"mysql\\\",\\\"label\\\":\\\"rds-mysql-n/a\\\",\"\n\t\t\t\t\t\t+ \"\\\"plan\\\":\\\"10mb\\\",\\\"credentials\\\":{\\\"name\\\":\\\"d04fb13d27d964c62b267bbba1cffb9da\\\",\"\n\t\t\t\t\t\t+ \"\\\"hostname\\\":\\\"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\\\",\"\n\t\t\t\t\t\t+ \"\\\"ssl\\\":true,\\\"location\\\":null,\"\n\t\t\t\t\t\t+ \"\\\"host\\\":\\\"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\\\",\"\n\t\t\t\t\t\t+ \"\\\"port\\\":3306,\\\"user\\\":\\\"urpRuqTf8Cpe6\\\",\\\"username\\\":\"\n\t\t\t\t\t\t+ \"\\\"urpRuqTf8Cpe6\\\",\\\"password\\\":\\\"pxLsGVpsC9A5S\\\"}}]}\");\n\t\tthis.initializer.postProcessEnvironment(this.context.getEnvironment(), this.application);\n\t\tassertThat(getProperty(\"vcap.services.mysql.name\")).isEqualTo(\"mysql\");\n\t\tassertThat(getProperty(\"vcap.services.mysql.credentials.port\")).isEqualTo(\"3306\");\n\t\tassertThat(getProperty(\"vcap.services.mysql.credentials.ssl\")).isEqualTo(\"true\");\n\t\tassertThat(getProperty(\"vcap.services.mysql.credentials.location\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid testServicePropertiesWithoutNA() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,\n\t\t\t\t\"VCAP_SERVICES={\\\"rds-mysql\\\":[{\\\"name\\\":\\\"mysql\\\",\\\"label\\\":\\\"rds-mysql\\\",\\\"plan\\\":\\\"10mb\\\",\"\n\t\t\t\t\t\t+ \"\\\"credentials\\\":{\\\"name\\\":\\\"d04fb13d27d964c62b267bbba1cffb9da\\\",\"\n\t\t\t\t\t\t+ \"\\\"hostname\\\":\\\"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\\\",\"\n\t\t\t\t\t\t+ \"\\\"host\\\":\\\"mysql-service-public.clqg2e2w3ecf.us-east-1.rds.amazonaws.com\\\",\"\n\t\t\t\t\t\t+ \"\\\"port\\\":3306,\\\"user\\\":\\\"urpRuqTf8Cpe6\\\",\\\"username\\\":\\\"urpRuqTf8Cpe6\\\",\"\n\t\t\t\t\t\t+ \"\\\"password\\\":\\\"pxLsGVpsC9A5S\\\"}}]}\");\n\t\tthis.initializer.postProcessEnvironment(this.context.getEnvironment(), this.application);\n\t\tassertThat(getProperty(\"vcap.services.mysql.name\")).isEqualTo(\"mysql\");\n\t\tassertThat(getProperty(\"vcap.services.mysql.credentials.port\")).isEqualTo(\"3306\");\n\t}\n\n\t@Test\n\tvoid orderShouldBeBeforeConfigDataEnvironmentPostProcessorWithGap() {\n\t\tassertThat(this.initializer.getOrder()).isLessThan(ConfigDataEnvironmentPostProcessor.ORDER);\n\t\tassertThat(this.initializer.getOrder()).isLessThan(ConfigDataEnvironmentPostProcessor.ORDER - 1);\n\t}\n\n\tprivate @Nullable String getProperty(String key) {\n\t\treturn this.context.getEnvironment().getProperty(key);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/cloud/CloudPlatformTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloud;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudPlatform}.\n *\n * @author Phillip Webb\n * @author Nguyen Sach\n */\nclass CloudPlatformTests {\n\n\t@Test\n\tvoid getActiveWhenEnvironmentIsNullShouldReturnNull() {\n\t\tCloudPlatform platform = CloudPlatform.getActive(null);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenNotInCloudShouldReturnNull() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasVcapApplicationShouldReturnCloudFoundry() {\n\t\tEnvironment environment = new MockEnvironment().withProperty(\"VCAP_APPLICATION\", \"---\");\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.CLOUD_FOUNDRY);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasVcapServicesShouldReturnCloudFoundry() {\n\t\tEnvironment environment = new MockEnvironment().withProperty(\"VCAP_SERVICES\", \"---\");\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.CLOUD_FOUNDRY);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasDynoShouldReturnHeroku() {\n\t\tEnvironment environment = new MockEnvironment().withProperty(\"DYNO\", \"---\");\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.HEROKU);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasHcLandscapeShouldReturnSap() {\n\t\tEnvironment environment = new MockEnvironment().withProperty(\"HC_LANDSCAPE\", \"---\");\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.SAP);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasNomadAllocIdShouldReturnNomad() {\n\t\tEnvironment environment = new MockEnvironment().withProperty(\"NOMAD_ALLOC_ID\", \"---\");\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.NOMAD);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasKubernetesServiceHostAndPortShouldReturnKubernetes() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"KUBERNETES_SERVICE_HOST\", \"---\");\n\t\tenvVars.put(\"KUBERNETES_SERVICE_PORT\", \"8080\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.KUBERNETES);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasKubernetesServiceHostAndNoKubernetesServicePortShouldNotReturnKubernetes() {\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(\n\t\t\t\tCollections.singletonMap(\"KUBERNETES_SERVICE_HOST\", \"---\"));\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasKubernetesServicePortAndNoKubernetesServiceHostShouldNotReturnKubernetes() {\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(\n\t\t\t\tCollections.singletonMap(\"KUBERNETES_SERVICE_PORT\", \"8080\"));\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasServiceHostAndServicePortShouldReturnKubernetes() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"EXAMPLE_SERVICE_HOST\", \"---\");\n\t\tenvVars.put(\"EXAMPLE_SERVICE_PORT\", \"8080\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.KUBERNETES);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasServiceHostAndNoServicePortShouldNotReturnKubernetes() {\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(\n\t\t\t\tCollections.singletonMap(\"EXAMPLE_SERVICE_HOST\", \"---\"));\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasAllAzureEnvVariablesShouldReturnAzureAppService() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"WEBSITE_SITE_NAME\", \"---\");\n\t\tenvVars.put(\"WEBSITE_INSTANCE_ID\", \"1234\");\n\t\tenvVars.put(\"WEBSITE_RESOURCE_GROUP\", \"test\");\n\t\tenvVars.put(\"WEBSITE_SKU\", \"1234\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull();\n\t\tassertThat(platform).isEqualTo(CloudPlatform.AZURE_APP_SERVICE);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasMissingWebsiteSiteNameShouldNotReturnAzureAppService() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"WEBSITE_INSTANCE_ID\", \"1234\");\n\t\tenvVars.put(\"WEBSITE_RESOURCE_GROUP\", \"test\");\n\t\tenvVars.put(\"WEBSITE_SKU\", \"1234\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasMissingWebsiteInstanceIdShouldNotReturnAzureAppService() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"WEBSITE_SITE_NAME\", \"---\");\n\t\tenvVars.put(\"WEBSITE_RESOURCE_GROUP\", \"test\");\n\t\tenvVars.put(\"WEBSITE_SKU\", \"1234\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasMissingWebsiteResourceGroupShouldNotReturnAzureAppService() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"WEBSITE_SITE_NAME\", \"---\");\n\t\tenvVars.put(\"WEBSITE_INSTANCE_ID\", \"1234\");\n\t\tenvVars.put(\"WEBSITE_SKU\", \"1234\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasMissingWebsiteSkuShouldNotReturnAzureAppService() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"WEBSITE_SITE_NAME\", \"---\");\n\t\tenvVars.put(\"WEBSITE_INSTANCE_ID\", \"1234\");\n\t\tenvVars.put(\"WEBSITE_RESOURCE_GROUP\", \"test\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"AWS_ECS_FARGATE\", \"AWS_ECS_EC2\" })\n\tvoid getActiveWhenHasAwsExecutionEnvEcsShouldReturnAwsEcs(String awsExecutionEnv) {\n\t\tMap<String, Object> envVars = Map.of(\"AWS_EXECUTION_ENV\", awsExecutionEnv);\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNotNull().isEqualTo(CloudPlatform.AWS_ECS);\n\t\tassertThat(platform.isActive(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasAwsExecutionEnvLambdaShouldNotReturnAwsEcs() {\n\t\tMap<String, Object> envVars = Map.of(\"AWS_EXECUTION_ENV\", \"AWS_Lambda_java8\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isNull();\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasEnforcedCloudPlatform() {\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(\n\t\t\t\tCollections.singletonMap(\"spring.main.cloud-platform\", \"kubernetes\"));\n\t\tCloudPlatform platform = CloudPlatform.getActive(environment);\n\t\tassertThat(platform).isEqualTo(CloudPlatform.KUBERNETES);\n\t}\n\n\t@Test\n\tvoid isEnforcedWhenEnvironmentPropertyMatchesReturnsTrue() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.main.cloud-platform\", \"kubernetes\");\n\t\tassertThat(CloudPlatform.KUBERNETES.isEnforced(environment)).isTrue();\n\t}\n\n\t@Test\n\tvoid isEnforcedWhenEnvironmentPropertyDoesNotMatchReturnsFalse() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.main.cloud-platform\", \"heroku\");\n\t\tassertThat(CloudPlatform.KUBERNETES.isEnforced(environment)).isFalse();\n\t}\n\n\t@Test\n\tvoid isEnforcedWhenEnvironmentPropertyIsMissingReturnsFalse() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tassertThat(CloudPlatform.KUBERNETES.isEnforced(environment)).isFalse();\n\t}\n\n\t@Test\n\tvoid isEnforcedWhenBinderPropertyMatchesReturnsTrue() {\n\t\tBinder binder = new Binder(new MockConfigurationPropertySource(\"spring.main.cloud-platform\", \"kubernetes\"));\n\t\tassertThat(CloudPlatform.KUBERNETES.isEnforced(binder)).isTrue();\n\t}\n\n\t@Test\n\tvoid isEnforcedWhenBinderPropertyDoesNotMatchReturnsFalse() {\n\t\tBinder binder = new Binder(new MockConfigurationPropertySource(\"spring.main.cloud-platform\", \"heroku\"));\n\t\tassertThat(CloudPlatform.KUBERNETES.isEnforced(binder)).isFalse();\n\t}\n\n\t@Test\n\tvoid isEnforcedWhenBinderPropertyIsMissingReturnsFalse() {\n\t\tBinder binder = new Binder(new MockConfigurationPropertySource());\n\t\tassertThat(CloudPlatform.KUBERNETES.isEnforced(binder)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNoCloudPlatformIsEnforcedAndHasKubernetesServiceHostAndKubernetesServicePort() {\n\t\tMap<String, Object> envVars = new HashMap<>();\n\t\tenvVars.put(\"EXAMPLE_SERVICE_HOST\", \"---\");\n\t\tenvVars.put(\"EXAMPLE_SERVICE_PORT\", \"8080\");\n\t\tEnvironment environment = getEnvironmentWithEnvVariables(envVars);\n\t\t((MockEnvironment) environment).setProperty(\"spring.main.cloud-platform\", \"none\");\n\t\tassertThat(Stream.of(CloudPlatform.values()).filter((platform) -> platform.isActive(environment)))\n\t\t\t.containsExactly(CloudPlatform.NONE);\n\t}\n\n\t@Test\n\tvoid nonePlatformShouldDisableCloudPlatformFeatures() {\n\t\tassertThat(CloudPlatform.NONE.isUsingForwardHeaders()).isFalse();\n\t}\n\n\tprivate Environment getEnvironmentWithEnvVariables(Map<String, Object> environmentVariables) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tPropertySource<?> propertySource = new SystemEnvironmentPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, environmentVariables);\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\treturn environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/ApplicationPidFileWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.context.event.SpringApplicationEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ApplicationPidFileWriter}.\n *\n * @author Jakub Kubrynski\n * @author Dave Syer\n * @author Phillip Webb\n * @author Tomasz Przybyla\n */\nclass ApplicationPidFileWriterTests {\n\n\tprivate static final ApplicationPreparedEvent EVENT = new ApplicationPreparedEvent(new SpringApplication(),\n\t\t\tnew String[] {}, mock(ConfigurableApplicationContext.class));\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid resetListener() {\n\t\tSystem.clearProperty(\"PIDFILE\");\n\t\tSystem.clearProperty(\"PID_FAIL_ON_WRITE_ERROR\");\n\t\tApplicationPidFileWriter.reset();\n\t}\n\n\t@Test\n\tvoid createPidFile() {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);\n\t\tlistener.onApplicationEvent(EVENT);\n\t\tassertThat(contentOf(file)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid overridePidFile() {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tSystem.setProperty(\"PIDFILE\", new File(this.tempDir, \"override\").getAbsolutePath());\n\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);\n\t\tlistener.onApplicationEvent(EVENT);\n\t\tassertThat(contentOf(new File(System.getProperty(\"PIDFILE\")))).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid overridePidFileWithSpring() {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tSpringApplicationEvent event = createPreparedEvent(\"spring.pid.file\", file.getAbsolutePath());\n\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter();\n\t\tlistener.onApplicationEvent(event);\n\t\tassertThat(contentOf(file)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid tryEnvironmentPreparedEvent() throws Exception {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tfile.createNewFile();\n\t\tSpringApplicationEvent event = createEnvironmentPreparedEvent(\"spring.pid.file\", file.getAbsolutePath());\n\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter();\n\t\tlistener.onApplicationEvent(event);\n\t\tassertThat(contentOf(file)).isEmpty();\n\t\tlistener.setTriggerEventType(ApplicationEnvironmentPreparedEvent.class);\n\t\tlistener.onApplicationEvent(event);\n\t\tassertThat(contentOf(file)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid tryReadyEvent() throws Exception {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tfile.createNewFile();\n\t\tSpringApplicationEvent event = createReadyEvent(\"spring.pid.file\", file.getAbsolutePath());\n\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter();\n\t\tlistener.onApplicationEvent(event);\n\t\tassertThat(contentOf(file)).isEmpty();\n\t\tlistener.setTriggerEventType(ApplicationReadyEvent.class);\n\t\tlistener.onApplicationEvent(event);\n\t\tassertThat(contentOf(file)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid withNoEnvironment() {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);\n\t\tlistener.setTriggerEventType(ApplicationStartingEvent.class);\n\t\tlistener.onApplicationEvent(\n\t\t\t\tnew ApplicationStartingEvent(new DefaultBootstrapContext(), new SpringApplication(), new String[] {}));\n\t\tassertThat(contentOf(file)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid continueWhenPidFileIsReadOnly() throws Exception {\n\t\twithReadOnlyPidFile((file) -> {\n\t\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);\n\t\t\tlistener.onApplicationEvent(EVENT);\n\t\t\tassertThat(contentOf(file)).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid throwWhenPidFileIsReadOnly() throws Exception {\n\t\twithReadOnlyPidFile((file) -> {\n\t\t\tSystem.setProperty(\"PID_FAIL_ON_WRITE_ERROR\", \"true\");\n\t\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> listener.onApplicationEvent(EVENT))\n\t\t\t\t.withMessageContaining(\"Cannot create pid file\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid throwWhenPidFileIsReadOnlyWithSpring() throws Exception {\n\t\twithReadOnlyPidFile((file) -> {\n\t\t\tSpringApplicationEvent event = createPreparedEvent(\"spring.pid.fail-on-write-error\", \"true\");\n\t\t\tApplicationPidFileWriter listener = new ApplicationPidFileWriter(file);\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> listener.onApplicationEvent(event))\n\t\t\t\t.withMessageContaining(\"Cannot create pid file\");\n\t\t});\n\t}\n\n\tprivate void withReadOnlyPidFile(Consumer<File> consumer) throws IOException {\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tfile.createNewFile();\n\t\tfile.setReadOnly();\n\t\ttry {\n\t\t\tconsumer.accept(file);\n\t\t}\n\t\tfinally {\n\t\t\tfile.setWritable(true);\n\t\t}\n\t}\n\n\tprivate SpringApplicationEvent createEnvironmentPreparedEvent(String propName, String propValue) {\n\t\tConfigurableEnvironment environment = createEnvironment(propName, propValue);\n\t\treturn new ApplicationEnvironmentPreparedEvent(new DefaultBootstrapContext(), new SpringApplication(),\n\t\t\t\tnew String[] {}, environment);\n\t}\n\n\tprivate SpringApplicationEvent createPreparedEvent(String propName, String propValue) {\n\t\tConfigurableEnvironment environment = createEnvironment(propName, propValue);\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tgiven(context.getEnvironment()).willReturn(environment);\n\t\treturn new ApplicationPreparedEvent(new SpringApplication(), new String[] {}, context);\n\t}\n\n\tprivate SpringApplicationEvent createReadyEvent(String propName, String propValue) {\n\t\tConfigurableEnvironment environment = createEnvironment(propName, propValue);\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tgiven(context.getEnvironment()).willReturn(environment);\n\t\treturn new ApplicationReadyEvent(new SpringApplication(), new String[] {}, context, null);\n\t}\n\n\tprivate ConfigurableEnvironment createEnvironment(String propName, String propValue) {\n\t\tMockPropertySource propertySource = mockPropertySource(propName, propValue);\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources().addLast(propertySource);\n\t\treturn environment;\n\t}\n\n\tprivate MockPropertySource mockPropertySource(String name, String value) {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(name, value);\n\t\treturn propertySource;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/ConfigurationWarningsApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer.ComponentScanPackageCheck;\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageConfiguration;\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageWithBasePackageClassesConfiguration;\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageWithBasePackagesConfiguration;\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageWithMetaAnnotationConfiguration;\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageWithValueConfiguration;\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageWithoutScanConfiguration;\nimport org.springframework.boot.context.configwarnings.orgspring.InOrgSpringPackageConfiguration;\nimport org.springframework.boot.context.configwarnings.real.InRealButScanningProblemPackages;\nimport org.springframework.boot.context.configwarnings.real.InRealPackageConfiguration;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationWarningsApplicationContextInitializer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ConfigurationWarningsApplicationContextInitializerTests {\n\n\tprivate static final String DEFAULT_SCAN_WARNING = \"Your ApplicationContext is unlikely to \"\n\t\t\t+ \"start due to a @ComponentScan of the default package.\";\n\n\tprivate static final String ORGSPRING_SCAN_WARNING = \"Your ApplicationContext is unlikely to \"\n\t\t\t+ \"start due to a @ComponentScan of 'org.springframework'.\";\n\n\t@Test\n\tvoid logWarningInDefaultPackage(CapturedOutput output) {\n\t\tload(InDefaultPackageConfiguration.class);\n\t\tassertThat(output).contains(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid logWarningInDefaultPackageAndMetaAnnotation(CapturedOutput output) {\n\t\tload(InDefaultPackageWithMetaAnnotationConfiguration.class);\n\t\tassertThat(output).contains(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid noLogIfInRealPackage(CapturedOutput output) {\n\t\tload(InRealPackageConfiguration.class);\n\t\tassertThat(output).doesNotContain(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid noLogWithoutComponentScanAnnotation(CapturedOutput output) {\n\t\tload(InDefaultPackageWithoutScanConfiguration.class);\n\t\tassertThat(output).doesNotContain(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid noLogIfHasValue(CapturedOutput output) {\n\t\tload(InDefaultPackageWithValueConfiguration.class);\n\t\tassertThat(output).doesNotContain(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid noLogIfHasBasePackages(CapturedOutput output) {\n\t\tload(InDefaultPackageWithBasePackagesConfiguration.class);\n\t\tassertThat(output).doesNotContain(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid noLogIfHasBasePackageClasses(CapturedOutput output) {\n\t\tload(InDefaultPackageWithBasePackageClassesConfiguration.class);\n\t\tassertThat(output).doesNotContain(DEFAULT_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid logWarningInOrgSpringPackage(CapturedOutput output) {\n\t\tload(InOrgSpringPackageConfiguration.class);\n\t\tassertThat(output).contains(ORGSPRING_SCAN_WARNING);\n\t}\n\n\t@Test\n\tvoid logWarningIfScanningProblemPackages(CapturedOutput output) {\n\t\tload(InRealButScanningProblemPackages.class);\n\t\tassertThat(output).contains(\"Your ApplicationContext is unlikely to start due to a \"\n\t\t\t\t+ \"@ComponentScan of the default package, 'org.springframework'.\");\n\n\t}\n\n\tprivate void load(Class<?> configClass) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tnew TestConfigurationWarningsApplicationContextInitializer().initialize(context);\n\t\t\tcontext.register(configClass);\n\t\t\tcontext.refresh();\n\t\t}\n\t}\n\n\t/**\n\t * Testable version of {@link ConfigurationWarningsApplicationContextInitializer}.\n\t */\n\tstatic class TestConfigurationWarningsApplicationContextInitializer\n\t\t\textends ConfigurationWarningsApplicationContextInitializer {\n\n\t\t@Override\n\t\tprotected Check[] getChecks() {\n\t\t\treturn new Check[] { new TestComponentScanPackageCheck() };\n\t\t}\n\n\t}\n\n\t/**\n\t * Testable ComponentScanPackageCheck that doesn't need to use the default or\n\t * {@code org.springframework} package.\n\t */\n\tstatic class TestComponentScanPackageCheck extends ComponentScanPackageCheck {\n\n\t\t@Override\n\t\tprotected Set<String> getComponentScanningPackages(BeanDefinitionRegistry registry) {\n\t\t\tSet<String> scannedPackages = super.getComponentScanningPackages(registry);\n\t\t\tSet<String> result = new LinkedHashSet<>();\n\t\t\tfor (String scannedPackage : scannedPackages) {\n\t\t\t\tif (scannedPackage.endsWith(\"dflt\")) {\n\t\t\t\t\tresult.add(\"\");\n\t\t\t\t}\n\t\t\t\telse if (scannedPackage.endsWith(\"orgspring\")) {\n\t\t\t\t\tresult.add(\"org.springframework\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tresult.add(scannedPackage);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ContextIdApplicationContextInitializer}.\n *\n * @author Dave Syer\n */\nclass ContextIdApplicationContextInitializerTests {\n\n\tprivate final ContextIdApplicationContextInitializer initializer = new ContextIdApplicationContextInitializer();\n\n\tprivate final List<ConfigurableApplicationContext> contexts = new ArrayList<>();\n\n\t@AfterEach\n\tvoid closeContexts() {\n\t\tCollections.reverse(this.contexts);\n\t\tthis.contexts.forEach(ConfigurableApplicationContext::close);\n\t}\n\n\t@Test\n\tvoid singleContextWithDefaultName() {\n\t\tConfigurableApplicationContext context = createContext(null);\n\t\tassertThat(context.getId()).isEqualTo(\"application\");\n\t}\n\n\t@Test\n\tvoid singleContextWithCustomName() {\n\t\tConfigurableApplicationContext context = createContext(null, \"spring.application.name=test\");\n\t\tassertThat(context.getId()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid linearHierarchy() {\n\t\tConfigurableApplicationContext grandparent = createContext(null);\n\t\tConfigurableApplicationContext parent = createContext(grandparent);\n\t\tConfigurableApplicationContext child = createContext(parent);\n\t\tassertThat(child.getId()).isEqualTo(\"application-1-1\");\n\t}\n\n\t@Test\n\tvoid complexHierarchy() {\n\t\tConfigurableApplicationContext grandparent = createContext(null);\n\t\tConfigurableApplicationContext parent1 = createContext(grandparent);\n\t\tConfigurableApplicationContext parent2 = createContext(grandparent);\n\t\tConfigurableApplicationContext child1_1 = createContext(parent1);\n\t\tassertThat(child1_1.getId()).isEqualTo(\"application-1-1\");\n\t\tConfigurableApplicationContext child1_2 = createContext(parent1);\n\t\tassertThat(child1_2.getId()).isEqualTo(\"application-1-2\");\n\t\tConfigurableApplicationContext child2_1 = createContext(parent2);\n\t\tassertThat(child2_1.getId()).isEqualTo(\"application-2-1\");\n\t}\n\n\t@Test\n\tvoid contextWithParentWithNoContextIdFallsBackToDefaultId() {\n\t\tConfigurableApplicationContext parent = new AnnotationConfigApplicationContext();\n\t\tthis.contexts.add(parent);\n\t\tparent.refresh();\n\t\tassertThat(createContext(parent).getId()).isEqualTo(\"application\");\n\t}\n\n\tprivate ConfigurableApplicationContext createContext(@Nullable ConfigurableApplicationContext parent,\n\t\t\tString... properties) {\n\t\tConfigurableApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, properties);\n\t\tif (parent != null) {\n\t\t\tcontext.setParent(parent);\n\t\t}\n\t\tthis.initializer.initialize(context);\n\t\tcontext.refresh();\n\t\tthis.contexts.add(context);\n\t\treturn context;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/FileEncodingApplicationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link FileEncodingApplicationListener}.\n *\n * @author Dave Syer\n */\nclass FileEncodingApplicationListenerTests {\n\n\tprivate final FileEncodingApplicationListener initializer = new FileEncodingApplicationListener();\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\tprivate final ApplicationEnvironmentPreparedEvent event = new ApplicationEnvironmentPreparedEvent(\n\t\t\tnew DefaultBootstrapContext(), new SpringApplication(), new String[0], this.environment);\n\n\t@Test\n\tvoid testIllegalState() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"spring.mandatory_file_encoding=FOO\");\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.initializer.onApplicationEvent(this.event));\n\t}\n\n\t@Test\n\tvoid testSunnyDayNothingMandated() {\n\t\tthis.initializer.onApplicationEvent(this.event);\n\t}\n\n\t@Test\n\tvoid testSunnyDayMandated() {\n\t\tassertThat(System.getProperty(\"file.encoding\")).isNotNull();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"spring.mandatory_file_encoding:\" + System.getProperty(\"file.encoding\"));\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tthis.initializer.onApplicationEvent(this.event);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.context.filtersample.ExampleComponent;\nimport org.springframework.boot.context.filtersample.ExampleFilteredComponent;\nimport org.springframework.boot.context.filtersample.SampleTypeExcludeFilter;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link TypeExcludeFilter}.\n *\n * @author Phillip Webb\n */\nclass TypeExcludeFilterTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadsTypeExcludeFilters() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.getBeanFactory().registerSingleton(\"filter1\", new WithoutMatchOverrideFilter());\n\t\tthis.context.getBeanFactory().registerSingleton(\"filter2\", new SampleTypeExcludeFilter());\n\t\tthis.context.register(Config.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(ExampleComponent.class)).isNotNull();\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(ExampleFilteredComponent.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ComponentScan(basePackageClasses = SampleTypeExcludeFilter.class,\n\t\t\texcludeFilters = @Filter(type = FilterType.CUSTOM, classes = SampleTypeExcludeFilter.class))\n\tstatic class Config {\n\n\t}\n\n\tstatic class WithoutMatchOverrideFilter extends TypeExcludeFilter {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/annotation/ConfigurationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Configurations}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationsTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenClassesIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TestConfigurations((Collection<Class<?>>) null))\n\t\t\t.withMessageContaining(\"'classes' must not be null\");\n\t}\n\n\t@Test\n\tvoid createShouldSortClasses() {\n\t\tTestConfigurations configurations = new TestConfigurations(Sorter.instance, OutputStream.class,\n\t\t\t\tInputStream.class);\n\t\tassertThat(configurations.getClasses()).containsExactly(InputStream.class, OutputStream.class);\n\t}\n\n\t@Test\n\tvoid getClassesShouldMergeByClassAndSort() {\n\t\tConfigurations c1 = new TestSortedConfigurations(OutputStream.class, InputStream.class);\n\t\tConfigurations c2 = new TestConfigurations(Short.class);\n\t\tConfigurations c3 = new TestSortedConfigurations(String.class, Integer.class);\n\t\tConfigurations c4 = new TestConfigurations(Long.class, Byte.class);\n\t\tClass<?>[] classes = Configurations.getClasses(c1, c2, c3, c4);\n\t\tassertThat(classes).containsExactly(Short.class, Long.class, Byte.class, InputStream.class, Integer.class,\n\t\t\t\tOutputStream.class, String.class);\n\t}\n\n\t@Test\n\tvoid getBeanNameWhenNoFunctionReturnsNull() {\n\t\tConfigurations configurations = new TestConfigurations(Short.class);\n\t\tassertThat(configurations.getBeanName(Short.class)).isNull();\n\t}\n\n\t@Test\n\tvoid getBeanNameWhenFunctionReturnsBeanName() {\n\t\tConfigurations configurations = new TestConfigurations(Sorter.instance, List.of(Short.class), Class::getName);\n\t\tassertThat(configurations.getBeanName(Short.class)).isEqualTo(Short.class.getName());\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic class TestConfigurations extends Configurations {\n\n\t\tTestConfigurations(Class<?>... classes) {\n\t\t\tthis(Arrays.asList(classes));\n\t\t}\n\n\t\tTestConfigurations(UnaryOperator<Collection<Class<?>>> sorter, Class<?>... classes) {\n\t\t\tthis(sorter, Arrays.asList(classes), null);\n\t\t}\n\n\t\tTestConfigurations(UnaryOperator<Collection<Class<?>>> sorter, Collection<Class<?>> classes,\n\t\t\t\t@Nullable Function<Class<?>, String> beanNameGenerator) {\n\t\t\tsuper(sorter, classes, beanNameGenerator);\n\t\t}\n\n\t\tTestConfigurations(Collection<Class<?>> classes) {\n\t\t\tsuper(classes);\n\t\t}\n\n\t\t@Override\n\t\tprotected Configurations merge(Set<Class<?>> mergedClasses) {\n\t\t\treturn new TestConfigurations(mergedClasses);\n\t\t}\n\n\t}\n\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class TestSortedConfigurations extends Configurations {\n\n\t\tprotected TestSortedConfigurations(Class<?>... classes) {\n\t\t\tthis(Arrays.asList(classes));\n\t\t}\n\n\t\tprotected TestSortedConfigurations(Collection<Class<?>> classes) {\n\t\t\tsuper(Sorter.instance, classes, null);\n\t\t}\n\n\t\t@Override\n\t\tprotected Configurations merge(Set<Class<?>> mergedClasses) {\n\t\t\treturn new TestSortedConfigurations(mergedClasses);\n\t\t}\n\n\t}\n\n\tstatic class Sorter implements UnaryOperator<Collection<Class<?>>> {\n\n\t\tstatic final Sorter instance = new Sorter();\n\n\t\t@Override\n\t\tpublic Collection<Class<?>> apply(Collection<Class<?>> classes) {\n\t\t\tArrayList<Class<?>> sorted = new ArrayList<>(classes);\n\t\t\tsorted.sort(Comparator.comparing(ClassUtils::getShortName));\n\t\t\treturn sorted;\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/annotation/ImportCandidatesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImportCandidates}.\n *\n * @author Moritz Halbritter\n */\nclass ImportCandidatesTests {\n\n\tprivate static final String IMPORTS_FILE = \"META-INF/spring/org.springframework.boot.context.annotation.ImportCandidatesTests$TestAnnotation.imports\";\n\n\t@Test\n\t@WithResource(name = IMPORTS_FILE, content = \"\"\"\n\t\t\t# A comment spanning a complete line\n\t\t\tclass1\n\n\t\t\tclass2 # with comment at the end\n\t\t\t   # Comment with some whitespace in front\n\t\t\tclass3\n\n\t\t\t\"\"\")\n\tvoid loadReadsFromClasspathFile() {\n\t\tImportCandidates candidates = ImportCandidates.load(TestAnnotation.class,\n\t\t\t\tThread.currentThread().getContextClassLoader());\n\t\tassertThat(candidates).containsExactly(\"class1\", \"class2\", \"class3\");\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\tpublic @interface TestAnnotation {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/annotation/UserConfigurationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.annotation;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UserConfigurations}.\n *\n * @author Phillip Webb\n */\nclass UserConfigurationsTests {\n\n\t@Test\n\tvoid ofShouldCreateUnorderedConfigurations() {\n\t\tUserConfigurations configurations = UserConfigurations.of(OutputStream.class, InputStream.class);\n\t\tassertThat(Configurations.getClasses(configurations)).containsExactly(OutputStream.class, InputStream.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataActivationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataActivationContext}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataActivationContextTests {\n\n\t@Test\n\tvoid getCloudPlatformWhenCloudPropertyNotPresentDeducesCloudPlatform() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tBinder binder = Binder.get(environment);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(environment, binder);\n\t\tassertThat(context.getCloudPlatform()).isNull();\n\t}\n\n\t@Test\n\tvoid getCloudPlatformWhenCloudPropertyInEnvironmentDeducesCloudPlatform() {\n\t\tMockEnvironment environment = createKubernetesEnvironment();\n\t\tBinder binder = Binder.get(environment);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(environment, binder);\n\t\tassertThat(context.getCloudPlatform()).isEqualTo(CloudPlatform.KUBERNETES);\n\t}\n\n\t@Test\n\tvoid getCloudPlatformWhenCloudPropertyHasBeenContributedDuringInitialLoadDeducesCloudPlatform() {\n\t\tEnvironment environment = createKubernetesEnvironment();\n\t\tBinder binder = new Binder(\n\t\t\t\tnew MapConfigurationPropertySource(Collections.singletonMap(\"spring.main.cloud-platform\", \"HEROKU\")));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(environment, binder);\n\t\tassertThat(context.getCloudPlatform()).isEqualTo(CloudPlatform.HEROKU);\n\t}\n\n\t@Test\n\tvoid getProfilesWhenWithoutProfilesReturnsNull() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tBinder binder = Binder.get(environment);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(environment, binder);\n\t\tassertThat(context.getProfiles()).isNull();\n\t}\n\n\t@Test\n\tvoid getProfilesWhenWithProfilesReturnsProfiles() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(environment, binder);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tcontext = context.withProfiles(profiles);\n\t\tassertThat(context.getProfiles()).isEqualTo(profiles);\n\t}\n\n\tprivate MockEnvironment createKubernetesEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"KUBERNETES_SERVICE_HOST\", \"host\");\n\t\tmap.put(\"KUBERNETES_SERVICE_PORT\", \"port\");\n\t\tPropertySource<?> propertySource = new MapPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, map);\n\t\tenvironment.getPropertySources().addLast(propertySource);\n\t\treturn environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorPlaceholdersResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.core.convert.support.GenericConversionService;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ConfigDataEnvironmentContributorPlaceholdersResolver}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\nclass ConfigDataEnvironmentContributorPlaceholdersResolverTests {\n\n\tprivate final ConversionService conversionService = DefaultConversionService.getSharedInstance();\n\n\t@Test\n\tvoid resolvePlaceholdersWhenNotStringReturnsResolved() {\n\t\tConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tCollections.emptyList(), null, null, false, this.conversionService);\n\t\tassertThat(resolver.resolvePlaceholders(123)).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid resolvePlaceholdersWhenNotFoundReturnsOriginal() {\n\t\tConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tCollections.emptyList(), null, null, false, this.conversionService);\n\t\tassertThat(resolver.resolvePlaceholders(\"${test}\")).isEqualTo(\"${test}\");\n\t}\n\n\t@Test\n\tvoid resolvePlaceholdersWhenFoundReturnsFirstMatch() {\n\t\tList<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s1\", \"nope\", \"t1\"), true,\n\t\t\t\tthis.conversionService));\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s2\", \"test\", \"t2\"), true,\n\t\t\t\tthis.conversionService));\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s3\", \"test\", \"t3\"), true,\n\t\t\t\tthis.conversionService));\n\t\tConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tcontributors, null, null, true, this.conversionService);\n\t\tassertThat(resolver.resolvePlaceholders(\"${test}\")).isEqualTo(\"t2\");\n\t}\n\n\t@Test\n\tvoid shouldUseConversionService() {\n\t\tGenericConversionService conversionService = new GenericConversionService();\n\t\tconversionService.addConverter(CustomValue.class, String.class, (input) -> \"custom-value\");\n\t\tList<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(\n\t\t\t\tnew TestPropertySource(\"s1\", Map.of(\"test\", new CustomValue())), true, conversionService));\n\t\tConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tcontributors, null, null, true, conversionService);\n\t\tassertThat(resolver.resolvePlaceholders(\"${test}\")).isEqualTo(\"custom-value\");\n\t}\n\n\t@Test\n\tvoid resolvePlaceholdersWhenFoundInInactiveThrowsException() {\n\t\tList<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s1\", \"nope\", \"t1\"), true,\n\t\t\t\tthis.conversionService));\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s2\", \"test\", \"t2\"), true,\n\t\t\t\tthis.conversionService));\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s3\", \"test\", \"t3\"), false,\n\t\t\t\tthis.conversionService));\n\t\tConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tcontributors, null, null, true, this.conversionService);\n\t\tassertThatExceptionOfType(InactiveConfigDataAccessException.class)\n\t\t\t.isThrownBy(() -> resolver.resolvePlaceholders(\"${test}\"))\n\t\t\t.satisfies(propertyNameAndOriginOf(\"test\", \"s3\"));\n\t}\n\n\t@Test\n\tvoid resolvePlaceholderWhenFoundInInactiveAndIgnoringReturnsResolved() {\n\t\tList<ConfigDataEnvironmentContributor> contributors = new ArrayList<>();\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s1\", \"nope\", \"t1\"), true,\n\t\t\t\tthis.conversionService));\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s2\", \"test\", \"t2\"), true,\n\t\t\t\tthis.conversionService));\n\t\tcontributors.add(new TestConfigDataEnvironmentContributor(new TestPropertySource(\"s3\", \"test\", \"t3\"), false,\n\t\t\t\tthis.conversionService));\n\t\tConfigDataEnvironmentContributorPlaceholdersResolver resolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(\n\t\t\t\tcontributors, null, null, false, this.conversionService);\n\t\tassertThat(resolver.resolvePlaceholders(\"${test}\")).isEqualTo(\"t2\");\n\t}\n\n\tprivate Consumer<InactiveConfigDataAccessException> propertyNameAndOriginOf(String propertyName, String origin) {\n\t\treturn (ex) -> {\n\t\t\tassertThat(ex.getPropertyName()).isEqualTo(propertyName);\n\t\t\tPropertySourceOrigin actualOrigin = (PropertySourceOrigin) (ex.getOrigin());\n\t\t\tassertThat(actualOrigin).isNotNull();\n\t\t\tassertThat(actualOrigin.getPropertySource().getName()).isEqualTo(origin);\n\t\t};\n\t}\n\n\tstatic class TestPropertySource extends MapPropertySource implements OriginLookup<String> {\n\n\t\tTestPropertySource(String name, String key, String value) {\n\t\t\tthis(name, Collections.singletonMap(key, value));\n\t\t}\n\n\t\tTestPropertySource(String name, Map<String, Object> source) {\n\t\t\tsuper(name, source);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getOrigin(String key) {\n\t\t\tif (getSource().containsKey(key)) {\n\t\t\t\treturn new PropertySourceOrigin(this, key);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class TestConfigDataEnvironmentContributor extends ConfigDataEnvironmentContributor {\n\n\t\tprivate final boolean active;\n\n\t\tprotected TestConfigDataEnvironmentContributor(PropertySource<?> propertySource, boolean active,\n\t\t\t\tConversionService conversionService) {\n\t\t\tsuper(Kind.ROOT, null, null, false, propertySource, null, null, null, null, conversionService);\n\t\t\tthis.active = active;\n\t\t}\n\n\t\t@Override\n\t\tboolean isActive(@Nullable ConfigDataActivationContext activationContext) {\n\t\t\treturn this.active;\n\t\t}\n\n\t}\n\n\tprivate static final class CustomValue {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.config.ConfigData.Option;\nimport org.springframework.boot.context.config.ConfigData.PropertySourceOptions;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.ImportPhase;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataEnvironmentContributor}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Nan Chiu\n */\nclass ConfigDataEnvironmentContributorTests {\n\n\tprivate static final ConfigDataLocation TEST_LOCATION = ConfigDataLocation.of(\"test\");\n\n\tprivate static final List<ConfigDataLocation> TEST_LOCATIONS = List.of(TEST_LOCATION);\n\n\tprivate final ConfigDataActivationContext activationContext = new ConfigDataActivationContext(\n\t\t\tCloudPlatform.KUBERNETES, null);\n\n\tprivate final ConversionService conversionService = DefaultConversionService.getSharedInstance();\n\n\t@Test\n\tvoid getKindReturnsKind() {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImports(TEST_LOCATIONS,\n\t\t\t\tthis.conversionService);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.INITIAL_IMPORT);\n\t}\n\n\t@Test\n\tvoid isActiveWhenPropertiesIsNullReturnsTrue() {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImports(TEST_LOCATIONS,\n\t\t\t\tthis.conversionService);\n\t\tassertThat(contributor.isActive(null)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenPropertiesIsActiveReturnsTrue() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.activate.on-cloud-platform\", \"kubernetes\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.isActive(this.activationContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenPropertiesIsNotActiveReturnsFalse() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.activate.on-cloud-platform\", \"heroku\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.isActive(this.activationContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid getLocationReturnsLocation() {\n\t\tConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigDataResource resource = mock(ConfigDataResource.class);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,\n\t\t\t\tresource, false, configData, 0, this.conversionService, ConfigDataEnvironmentUpdateListener.NONE);\n\t\tassertThat(contributor.getResource()).isSameAs(resource);\n\t}\n\n\t@Test\n\tvoid getPropertySourceReturnsPropertySource() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,\n\t\t\t\tthis.conversionService);\n\t\tassertThat(contributor.getPropertySource()).isSameAs(propertySource);\n\t}\n\n\t@Test\n\tvoid getConfigurationPropertySourceReturnsAdaptedPropertySource() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring\", \"boot\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null,\n\t\t\t\tfalse, configData, 0, this.conversionService, ConfigDataEnvironmentUpdateListener.NONE);\n\t\tConfigurationPropertySource source = contributor.getConfigurationPropertySource();\n\t\tassertThat(source).isNotNull();\n\t\tConfigurationProperty spring = source.getConfigurationProperty(ConfigurationPropertyName.of(\"spring\"));\n\t\tassertThat(spring).isNotNull();\n\t\tassertThat(spring.getValue()).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid getImportsWhenPropertiesIsNullReturnsEmptyList() {\n\t\tConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.getImports()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getImportsReturnsImports() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"spring,boot\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.getImports()).containsExactly(ConfigDataLocation.of(\"spring\"),\n\t\t\t\tConfigDataLocation.of(\"boot\"));\n\t}\n\n\t@Test\n\tvoid getImportsIgnoresEmptyElements() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"spring,,boot,\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.getImports()).containsExactly(ConfigDataLocation.of(\"spring\"),\n\t\t\t\tConfigDataLocation.of(\"boot\"));\n\t}\n\n\t@Test\n\tvoid hasUnprocessedImportsWhenNoImportsReturnsFalse() {\n\t\tConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.hasUnprocessedImports(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isFalse();\n\t}\n\n\t@Test\n\tvoid hasUnprocessedImportsWhenHasNoChildrenForPhaseReturnsTrue() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"springboot\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.hasUnprocessedImports(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isTrue();\n\t}\n\n\t@Test\n\tvoid hasUnprocessedImportsWhenHasChildrenForPhaseReturnsFalse() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"springboot\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tConfigData childConfigData = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigDataEnvironmentContributor childContributor = createBoundContributor(null, childConfigData, 0);\n\t\tConfigDataEnvironmentContributor withChildren = contributor.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(childContributor));\n\t\tassertThat(withChildren.hasUnprocessedImports(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isFalse();\n\t\tassertThat(withChildren.hasUnprocessedImports(ImportPhase.AFTER_PROFILE_ACTIVATION)).isTrue();\n\t}\n\n\t@Test\n\tvoid getChildrenWhenHasNoChildrenReturnsEmptyList() {\n\t\tConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t\tassertThat(contributor.getChildren(ImportPhase.AFTER_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test\n\tvoid getChildrenWhenHasChildrenReturnsChildren() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"springboot\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(null, configData, 0);\n\t\tConfigData childConfigData = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigDataEnvironmentContributor childContributor = createBoundContributor(null, childConfigData, 0);\n\t\tConfigDataEnvironmentContributor withChildren = contributor.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(childContributor));\n\t\tassertThat(withChildren.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).containsExactly(childContributor);\n\t\tassertThat(withChildren.getChildren(ImportPhase.AFTER_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test\n\tvoid streamReturnsStream() {\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(\"a\");\n\t\tStream<String> stream = contributor.stream().map(this::getLocationName);\n\t\tassertThat(stream).containsExactly(\"a\");\n\t}\n\n\t@Test\n\tvoid iteratorWhenSingleContributorReturnsSingletonIterator() {\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(\"a\");\n\t\tassertThat(asLocationsList(contributor.iterator())).containsExactly(\"a\");\n\t}\n\n\t@Test\n\tvoid iteratorWhenTypicalStructureReturnsCorrectlyOrderedIterator() {\n\t\tConfigDataEnvironmentContributor fileApplication = createBoundContributor(\"file:application.properties\");\n\t\tConfigDataEnvironmentContributor fileProfile = createBoundContributor(\"file:application-profile.properties\");\n\t\tConfigDataEnvironmentContributor fileImports = createBoundContributor(\"file:./\");\n\t\tfileImports = fileImports.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(fileApplication));\n\t\tfileImports = fileImports.withChildren(ImportPhase.AFTER_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(fileProfile));\n\t\tConfigDataEnvironmentContributor classpathApplication = createBoundContributor(\n\t\t\t\t\"classpath:application.properties\");\n\t\tConfigDataEnvironmentContributor classpathProfile = createBoundContributor(\n\t\t\t\t\"classpath:application-profile.properties\");\n\t\tConfigDataEnvironmentContributor classpathImports = createBoundContributor(\"classpath:/\");\n\t\tclasspathImports = classpathImports.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(classpathApplication));\n\t\tclasspathImports = classpathImports.withChildren(ImportPhase.AFTER_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(classpathProfile));\n\t\tConfigDataEnvironmentContributor root = createBoundContributor(\"root\");\n\t\troot = root.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION, Arrays.asList(fileImports, classpathImports));\n\t\tassertThat(asLocationsList(root.iterator())).containsExactly(\"file:application-profile.properties\",\n\t\t\t\t\"file:application.properties\", \"file:./\", \"classpath:application-profile.properties\",\n\t\t\t\t\"classpath:application.properties\", \"classpath:/\", \"root\");\n\t}\n\n\t@Test\n\tvoid withChildrenReturnsNewInstanceWithChildren() {\n\t\tConfigDataEnvironmentContributor root = createBoundContributor(\"root\");\n\t\tConfigDataEnvironmentContributor child = createBoundContributor(\"child\");\n\t\tConfigDataEnvironmentContributor withChildren = root.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION,\n\t\t\t\tCollections.singletonList(child));\n\t\tassertThat(root.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t\tassertThat(withChildren.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).containsExactly(child);\n\t}\n\n\t@Test\n\tvoid withChildrenAfterProfileActivationMovesProfileSpecificChildren() {\n\t\tConfigDataEnvironmentContributor root = createBoundContributor(\"root\");\n\t\tConfigDataEnvironmentContributor child1 = createBoundContributor(\"child1\");\n\t\tConfigDataEnvironmentContributor grandchild = createBoundContributor(new TestResource(\"grandchild\"),\n\t\t\t\tnew ConfigData(Collections.singleton(new MockPropertySource()),\n\t\t\t\t\t\tPropertySourceOptions.always(Option.PROFILE_SPECIFIC)),\n\t\t\t\t0);\n\t\tchild1 = child1.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.singletonList(grandchild));\n\t\troot = root.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.singletonList(child1));\n\t\tConfigDataEnvironmentContributor child2 = createBoundContributor(\"child2\");\n\t\troot = root.withChildren(ImportPhase.AFTER_PROFILE_ACTIVATION, Collections.singletonList(child2));\n\t\tassertThat(asLocationsList(root.iterator())).containsExactly(\"grandchild\", \"child2\", \"child1\", \"root\");\n\t}\n\n\t@Test\n\tvoid withReplacementReplacesChild() {\n\t\tConfigDataEnvironmentContributor root = createBoundContributor(\"root\");\n\t\tConfigDataEnvironmentContributor child = createBoundContributor(\"child\");\n\t\tConfigDataEnvironmentContributor grandchild = createBoundContributor(\"grandchild\");\n\t\tchild = child.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.singletonList(grandchild));\n\t\troot = root.withChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION, Collections.singletonList(child));\n\t\tConfigDataEnvironmentContributor updated = createBoundContributor(\"updated\");\n\t\tConfigDataEnvironmentContributor withReplacement = root.withReplacement(grandchild, updated);\n\t\tassertThat(asLocationsList(root.iterator())).containsExactly(\"grandchild\", \"child\", \"root\");\n\t\tassertThat(asLocationsList(withReplacement.iterator())).containsExactly(\"updated\", \"child\", \"root\");\n\t}\n\n\t@Test\n\tvoid ofCreatesRootContributor() {\n\t\tConfigDataEnvironmentContributor one = createBoundContributor(\"one\");\n\t\tConfigDataEnvironmentContributor two = createBoundContributor(\"two\");\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.of(Arrays.asList(one, two),\n\t\t\t\tthis.conversionService);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.ROOT);\n\t\tassertThat(contributor.getResource()).isNull();\n\t\tassertThat(contributor.getImports()).isEmpty();\n\t\tassertThat(contributor.isActive(this.activationContext)).isTrue();\n\t\tassertThat(contributor.getPropertySource()).isNull();\n\t\tassertThat(contributor.getConfigurationPropertySource()).isNull();\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).containsExactly(one, two);\n\t}\n\n\t@Test\n\tvoid ofInitialImportsCreatedInitialImportContributor() {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofInitialImports(TEST_LOCATIONS,\n\t\t\t\tthis.conversionService);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.INITIAL_IMPORT);\n\t\tassertThat(contributor.getResource()).isNull();\n\t\tassertThat(contributor.getImports()).isEqualTo(TEST_LOCATIONS);\n\t\tassertThat(contributor.isActive(this.activationContext)).isTrue();\n\t\tassertThat(contributor.getPropertySource()).isNull();\n\t\tassertThat(contributor.getConfigurationPropertySource()).isNull();\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test\n\tvoid ofExistingCreatesExistingContributor() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"test\");\n\t\tpropertySource.setProperty(\"spring.config.activate.on-cloud-platform\", \"cloudfoundry\");\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,\n\t\t\t\tthis.conversionService);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.EXISTING);\n\t\tassertThat(contributor.getResource()).isNull();\n\t\tassertThat(contributor.getImports()).isEmpty(); // Properties must not be bound\n\t\tassertThat(contributor.isActive(this.activationContext)).isTrue();\n\t\tassertThat(contributor.getPropertySource()).isEqualTo(propertySource);\n\t\tassertThat(contributor.getConfigurationPropertySource()).isNotNull();\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test\n\tvoid ofUnboundImportCreatesImportedContributor() {\n\t\tTestResource resource = new TestResource(\"test\");\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"test\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,\n\t\t\t\tresource, false, configData, 0, this.conversionService, ConfigDataEnvironmentUpdateListener.NONE);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.UNBOUND_IMPORT);\n\t\tassertThat(contributor.getResource()).isSameAs(resource);\n\t\tassertThat(contributor.getImports()).isEmpty();\n\t\tassertThat(contributor.isActive(this.activationContext)).isFalse();\n\t\tassertThat(contributor.getPropertySource()).isEqualTo(propertySource);\n\t\tassertThat(contributor.getConfigurationPropertySource()).isNotNull();\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindCreatesImportedContributor() {\n\t\tTestResource resource = new TestResource(\"test\");\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"test\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource));\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(resource, configData, 0);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.BOUND_IMPORT);\n\t\tassertThat(contributor.getResource()).isSameAs(resource);\n\t\tassertThat(contributor.getImports()).containsExactly(TEST_LOCATION);\n\t\tassertThat(contributor.isActive(this.activationContext)).isTrue();\n\t\tassertThat(contributor.getPropertySource()).isEqualTo(propertySource);\n\t\tassertThat(contributor.getConfigurationPropertySource()).isNotNull();\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenConfigDataHasIgnoreImportsOptionsCreatesImportedContributorWithoutImports() {\n\t\tTestResource resource = new TestResource(\"test\");\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.config.import\", \"test\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(propertySource), ConfigData.Option.IGNORE_IMPORTS);\n\t\tConfigDataEnvironmentContributor contributor = createBoundContributor(resource, configData, 0);\n\t\tassertThat(contributor.getKind()).isEqualTo(Kind.BOUND_IMPORT);\n\t\tassertThat(contributor.getResource()).isSameAs(resource);\n\t\tassertThat(contributor.getImports()).isEmpty();\n\t\tassertThat(contributor.isActive(this.activationContext)).isTrue();\n\t\tassertThat(contributor.getPropertySource()).isEqualTo(propertySource);\n\t\tassertThat(contributor.getConfigurationPropertySource()).isNotNull();\n\t\tassertThat(contributor.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION)).isEmpty();\n\t}\n\n\t@Test // gh-25029\n\tvoid withBoundPropertiesWhenIgnoringImportsAndNothingBound() {\n\t\tTestResource resource = new TestResource(\"a\");\n\t\tConfigData configData = new ConfigData(Collections.singleton(new MockPropertySource()), Option.IGNORE_IMPORTS);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,\n\t\t\t\tresource, false, configData, 0, this.conversionService, ConfigDataEnvironmentUpdateListener.NONE);\n\t\tConfigDataEnvironmentContributor bound = contributor.withBoundProperties(Collections.singleton(contributor),\n\t\t\t\tnull);\n\t\tassertThat(bound).isNotNull();\n\t}\n\n\tprivate ConfigDataEnvironmentContributor createBoundContributor(String location) {\n\t\treturn createBoundContributor(new TestResource(location),\n\t\t\t\tnew ConfigData(Collections.singleton(new MockPropertySource())), 0);\n\t}\n\n\tprivate ConfigDataEnvironmentContributor createBoundContributor(@Nullable ConfigDataResource resource,\n\t\t\tConfigData configData, int propertySourceIndex) {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(TEST_LOCATION,\n\t\t\t\tresource, false, configData, propertySourceIndex, this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\treturn contributor.withBoundProperties(Collections.singleton(contributor), null);\n\t}\n\n\tprivate List<String> asLocationsList(Iterator<ConfigDataEnvironmentContributor> iterator) {\n\t\tList<String> list = new ArrayList<>();\n\t\titerator.forEachRemaining((contributor) -> list.add(getLocationName(contributor)));\n\t\treturn list;\n\t}\n\n\tprivate String getLocationName(ConfigDataEnvironmentContributor contributor) {\n\t\tConfigDataResource resource = contributor.getResource();\n\t\tassertThat(resource).isNotNull();\n\t\treturn resource.toString();\n\t}\n\n\tstatic class TestResource extends ConfigDataResource {\n\n\t\tprivate final String location;\n\n\t\tTestResource(String location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.location;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentContributorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributors.BinderOption;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataEnvironmentContributors}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass ConfigDataEnvironmentContributorsTests {\n\n\tprivate static final ConfigDataLocation LOCATION_1 = ConfigDataLocation.of(\"location1\");\n\n\tprivate static final ConfigDataLocation LOCATION_2 = ConfigDataLocation.of(\"location2\");\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\tprivate final ConversionService conversionService = DefaultConversionService.getSharedInstance();\n\n\tprivate ConfigDataImporter importer;\n\n\tprivate ConfigDataActivationContext activationContext;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tBinder binder = Binder.get(environment);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tbinder, new DefaultResourceLoader(getClass().getClassLoader()),\n\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation(getClass().getClassLoader()));\n\t\tConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,\n\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation());\n\t\tthis.importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL, resolvers, loaders);\n\t\tthis.activationContext = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, null);\n\t}\n\n\t@Test\n\tvoid createCreatesWithInitialContributors() {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tIterator<ConfigDataEnvironmentContributor> iterator = contributors.iterator();\n\t\tassertThat(iterator.next()).isSameAs(contributor);\n\t\tassertThat(iterator.next().getKind()).isEqualTo(Kind.ROOT);\n\t}\n\n\t@Test\n\tvoid withProcessedImportsWhenHasNoUnprocessedImportsReturnsSameInstance() {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofExisting(new MockPropertySource(), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tConfigDataEnvironmentContributors withProcessedImports = contributors.withProcessedImports(this.importer,\n\t\t\t\tthis.activationContext);\n\t\tassertThat(withProcessedImports).isSameAs(contributors);\n\t}\n\n\t@Test\n\tvoid withProcessedImportsResolvesAndLoads() {\n\t\tthis.importer = mock(ConfigDataImporter.class);\n\t\tList<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tMap<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();\n\t\timported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource(\"a\"), false),\n\t\t\t\tnew ConfigData(List.of(propertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))\n\t\t\t.willReturn(imported);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tConfigDataEnvironmentContributors withProcessedImports = contributors.withProcessedImports(this.importer,\n\t\t\t\tthis.activationContext);\n\t\tIterator<ConfigDataEnvironmentContributor> iterator = withProcessedImports.iterator();\n\t\tassertThat(iterator.next().getPropertySource()).isSameAs(propertySource);\n\t\tassertThat(iterator.next().getKind()).isEqualTo(Kind.INITIAL_IMPORT);\n\t\tassertThat(iterator.next().getKind()).isEqualTo(Kind.ROOT);\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid withProcessedImportsResolvesAndLoadsChainedImports() {\n\t\tthis.importer = mock(ConfigDataImporter.class);\n\t\tList<ConfigDataLocation> initialLocations = Collections.singletonList(LOCATION_1);\n\t\tMockPropertySource initialPropertySource = new MockPropertySource();\n\t\tinitialPropertySource.setProperty(\"spring.config.import\", \"location2\");\n\t\tMap<ConfigDataResolutionResult, ConfigData> initialImported = new LinkedHashMap<>();\n\t\tinitialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource(\"a\"), false),\n\t\t\t\tnew ConfigData(List.of(initialPropertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations)))\n\t\t\t.willReturn(initialImported);\n\t\tList<ConfigDataLocation> secondLocations = Collections.singletonList(LOCATION_2);\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tMap<ConfigDataResolutionResult, ConfigData> secondImported = new LinkedHashMap<>();\n\t\tsecondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource(\"b\"), false),\n\t\t\t\tnew ConfigData(List.of(secondPropertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations)))\n\t\t\t.willReturn(secondImported);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tConfigDataEnvironmentContributors withProcessedImports = contributors.withProcessedImports(this.importer,\n\t\t\t\tthis.activationContext);\n\t\tIterator<ConfigDataEnvironmentContributor> iterator = withProcessedImports.iterator();\n\t\tassertThat(iterator.next().getPropertySource()).isSameAs(secondPropertySource);\n\t\tassertThat(iterator.next().getPropertySource()).isSameAs(initialPropertySource);\n\t\tassertThat(iterator.next().getKind()).isEqualTo(Kind.INITIAL_IMPORT);\n\t\tassertThat(iterator.next().getKind()).isEqualTo(Kind.ROOT);\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid withProcessedImportsProvidesLocationResolverContextWithAccessToBinder() {\n\t\tMockPropertySource existingPropertySource = new MockPropertySource();\n\t\texistingPropertySource.setProperty(\"test\", \"springboot\");\n\t\tConfigDataEnvironmentContributor existingContributor = ConfigDataEnvironmentContributor\n\t\t\t.ofExisting(existingPropertySource, this.conversionService);\n\t\tthis.importer = mock(ConfigDataImporter.class);\n\t\tList<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tMap<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();\n\t\timported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource(\"a'\"), false),\n\t\t\t\tnew ConfigData(List.of(propertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))\n\t\t\t.willReturn(imported);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(existingContributor, contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tcontributors.withProcessedImports(this.importer, this.activationContext);\n\t\tthen(this.importer).should()\n\t\t\t.resolveAndLoad(any(),\n\t\t\t\t\tassertArg((context) -> assertThat(context.getBinder().bind(\"test\", String.class).get())\n\t\t\t\t\t\t.isEqualTo(\"springboot\")),\n\t\t\t\t\tany(), any());\n\t}\n\n\t@Test\n\tvoid withProcessedImportsProvidesLocationResolverContextWithAccessToParent() {\n\t\tthis.importer = mock(ConfigDataImporter.class);\n\t\tList<ConfigDataLocation> initialLocations = Collections.singletonList(LOCATION_1);\n\t\tMockPropertySource initialPropertySource = new MockPropertySource();\n\t\tinitialPropertySource.setProperty(\"spring.config.import\", \"location2\");\n\t\tMap<ConfigDataResolutionResult, ConfigData> initialImported = new LinkedHashMap<>();\n\t\tinitialImported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource(\"a\"), false),\n\t\t\t\tnew ConfigData(List.of(initialPropertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(initialLocations)))\n\t\t\t.willReturn(initialImported);\n\t\tList<ConfigDataLocation> secondLocations = Collections.singletonList(LOCATION_2);\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tMap<ConfigDataResolutionResult, ConfigData> secondImported = new LinkedHashMap<>();\n\t\tsecondImported.put(new ConfigDataResolutionResult(LOCATION_2, new TestConfigDataResource(\"b\"), false),\n\t\t\t\tnew ConfigData(List.of(secondPropertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(secondLocations)))\n\t\t\t.willReturn(secondImported);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tArgumentCaptor<ConfigDataLocationResolverContext> locationResolverContext = ArgumentCaptor\n\t\t\t.forClass(ConfigDataLocationResolverContext.class);\n\t\tcontributors.withProcessedImports(this.importer, this.activationContext);\n\t\tthen(this.importer).should()\n\t\t\t.resolveAndLoad(any(), locationResolverContext.capture(), any(), eq(secondLocations));\n\t\tConfigDataLocationResolverContext context = locationResolverContext.getValue();\n\t\tassertThat(context.getParent()).hasToString(\"a\");\n\t}\n\n\t@Test\n\tvoid withProcessedImportsProvidesLocationResolverContextWithAccessToBootstrapRegistry() {\n\t\tMockPropertySource existingPropertySource = new MockPropertySource();\n\t\texistingPropertySource.setProperty(\"test\", \"springboot\");\n\t\tConfigDataEnvironmentContributor existingContributor = ConfigDataEnvironmentContributor\n\t\t\t.ofExisting(existingPropertySource, this.conversionService);\n\t\tthis.importer = mock(ConfigDataImporter.class);\n\t\tList<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tMap<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();\n\t\timported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource(\"a'\"), false),\n\t\t\t\tnew ConfigData(List.of(propertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))\n\t\t\t.willReturn(imported);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(existingContributor, contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tcontributors.withProcessedImports(this.importer, this.activationContext);\n\t\tthen(this.importer).should()\n\t\t\t.resolveAndLoad(any(),\n\t\t\t\t\tassertArg((context) -> assertThat(context.getBootstrapContext()).isSameAs(this.bootstrapContext)),\n\t\t\t\t\tany(), any());\n\t}\n\n\t@Test\n\tvoid withProcessedImportsProvidesLoaderContextWithAccessToBootstrapRegistry() {\n\t\tMockPropertySource existingPropertySource = new MockPropertySource();\n\t\texistingPropertySource.setProperty(\"test\", \"springboot\");\n\t\tConfigDataEnvironmentContributor existingContributor = ConfigDataEnvironmentContributor\n\t\t\t.ofExisting(existingPropertySource, this.conversionService);\n\t\tthis.importer = mock(ConfigDataImporter.class);\n\t\tList<ConfigDataLocation> locations = Collections.singletonList(LOCATION_1);\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tMap<ConfigDataResolutionResult, ConfigData> imported = new LinkedHashMap<>();\n\t\timported.put(new ConfigDataResolutionResult(LOCATION_1, new TestConfigDataResource(\"a'\"), false),\n\t\t\t\tnew ConfigData(List.of(propertySource)));\n\t\tgiven(this.importer.resolveAndLoad(eq(this.activationContext), any(), any(), eq(locations)))\n\t\t\t.willReturn(imported);\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofInitialImports(List.of(LOCATION_1), this.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(existingContributor, contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tcontributors.withProcessedImports(this.importer, this.activationContext);\n\t\tthen(this.importer).should()\n\t\t\t.resolveAndLoad(any(), any(),\n\t\t\t\t\tassertArg((context) -> assertThat(context.getBootstrapContext()).isSameAs(this.bootstrapContext)),\n\t\t\t\t\tany());\n\t}\n\n\t@Test\n\tvoid getBinderProvidesBinder() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"test\", \"springboot\");\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,\n\t\t\t\tthis.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext);\n\t\tassertThat(binder.bind(\"test\", String.class).get()).isEqualTo(\"springboot\");\n\t}\n\n\t@Test\n\tvoid getBinderWhenHasMultipleSourcesPicksFirst() {\n\t\tMockPropertySource firstPropertySource = new MockPropertySource();\n\t\tfirstPropertySource.setProperty(\"test\", \"one\");\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tsecondPropertySource.setProperty(\"test\", \"two\");\n\t\tConfigData configData = new ConfigData(Arrays.asList(firstPropertySource, secondPropertySource));\n\t\tConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);\n\t\tConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext);\n\t\tassertThat(binder.bind(\"test\", String.class).get()).isEqualTo(\"one\");\n\t}\n\n\t@Test\n\tvoid getBinderWhenHasInactiveIgnoresInactive() {\n\t\tMockPropertySource firstPropertySource = new MockPropertySource();\n\t\tfirstPropertySource.setProperty(\"test\", \"one\");\n\t\tfirstPropertySource.setProperty(\"spring.config.activate.on-profile\", \"production\");\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tsecondPropertySource.setProperty(\"test\", \"two\");\n\t\tConfigData configData = new ConfigData(Arrays.asList(firstPropertySource, secondPropertySource));\n\t\tConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);\n\t\tConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext);\n\t\tassertThat(binder.bind(\"test\", String.class).get()).isEqualTo(\"two\");\n\t}\n\n\t@Test\n\tvoid getBinderWhenHasPlaceholderResolvesPlaceholder() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"test\", \"${other}\");\n\t\tpropertySource.setProperty(\"other\", \"springboot\");\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,\n\t\t\t\tthis.conversionService);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, List.of(contributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext);\n\t\tassertThat(binder.bind(\"test\", String.class).get()).isEqualTo(\"springboot\");\n\t}\n\n\t@Test\n\tvoid getBinderWhenHasPlaceholderAndInactiveResolvesPlaceholderOnlyFromActive() {\n\t\tMockPropertySource firstPropertySource = new MockPropertySource();\n\t\tfirstPropertySource.setProperty(\"other\", \"one\");\n\t\tfirstPropertySource.setProperty(\"spring.config.activate.on-profile\", \"production\");\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tsecondPropertySource.setProperty(\"other\", \"two\");\n\t\tsecondPropertySource.setProperty(\"test\", \"${other}\");\n\t\tConfigData configData = new ConfigData(Arrays.asList(firstPropertySource, secondPropertySource));\n\t\tConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);\n\t\tConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext);\n\t\tassertThat(binder.bind(\"test\", String.class).get()).isEqualTo(\"two\");\n\t}\n\n\t@Test\n\tvoid getBinderWhenFailOnBindToInactiveSourceWithFirstInactiveThrowsException() {\n\t\tMockPropertySource firstPropertySource = new MockPropertySource();\n\t\tfirstPropertySource.setProperty(\"test\", \"one\");\n\t\tfirstPropertySource.setProperty(\"spring.config.activate.on-profile\", \"production\");\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tsecondPropertySource.setProperty(\"test\", \"two\");\n\t\tConfigData configData = new ConfigData(Arrays.asList(firstPropertySource, secondPropertySource));\n\t\tConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);\n\t\tConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> binder.bind(\"test\", String.class))\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(InactiveConfigDataAccessException.class));\n\t}\n\n\t@Test\n\tvoid getBinderWhenFailOnBindToInactiveSourceWithLastInactiveThrowsException() {\n\t\tMockPropertySource firstPropertySource = new MockPropertySource();\n\t\tfirstPropertySource.setProperty(\"test\", \"one\");\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tsecondPropertySource.setProperty(\"spring.config.activate.on-profile\", \"production\");\n\t\tsecondPropertySource.setProperty(\"test\", \"two\");\n\t\tConfigData configData = new ConfigData(Arrays.asList(firstPropertySource, secondPropertySource));\n\t\tConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);\n\t\tConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> binder.bind(\"test\", String.class))\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(InactiveConfigDataAccessException.class));\n\t}\n\n\t@Test\n\tvoid getBinderWhenFailOnBindToInactiveSourceWithResolveToInactiveThrowsException() {\n\t\tMockPropertySource firstPropertySource = new MockPropertySource();\n\t\tfirstPropertySource.setProperty(\"other\", \"one\");\n\t\tfirstPropertySource.setProperty(\"spring.config.activate.on-profile\", \"production\");\n\t\tMockPropertySource secondPropertySource = new MockPropertySource();\n\t\tsecondPropertySource.setProperty(\"test\", \"${other}\");\n\t\tsecondPropertySource.setProperty(\"other\", \"one\");\n\t\tConfigData configData = new ConfigData(Arrays.asList(firstPropertySource, secondPropertySource));\n\t\tConfigDataEnvironmentContributor firstContributor = createBoundImportContributor(configData, 0);\n\t\tConfigDataEnvironmentContributor secondContributor = createBoundImportContributor(configData, 1);\n\t\tConfigDataEnvironmentContributors contributors = new ConfigDataEnvironmentContributors(this.logFactory,\n\t\t\t\tthis.bootstrapContext, Arrays.asList(firstContributor, secondContributor), this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\tBinder binder = contributors.getBinder(this.activationContext, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> binder.bind(\"test\", String.class))\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(InactiveConfigDataAccessException.class));\n\t}\n\n\tprivate ConfigDataEnvironmentContributor createBoundImportContributor(ConfigData configData,\n\t\t\tint propertySourceIndex) {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofUnboundImport(null, null,\n\t\t\t\tfalse, configData, propertySourceIndex, this.conversionService,\n\t\t\t\tConfigDataEnvironmentUpdateListener.NONE);\n\t\treturn contributor.withBoundProperties(Collections.singleton(contributor), null);\n\t}\n\n\tprivate static class TestConfigDataResource extends ConfigDataResource {\n\n\t\tprivate final String value;\n\n\t\tTestConfigDataResource(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.context.config.TestConfigDataBootstrap.LoaderHelper;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ConfigDataEnvironmentPostProcessor} when used with a\n * {@link BootstrapRegistry}.\n *\n * @author Phillip Webb\n */\nclass ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests {\n\n\tprivate SpringApplication application;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.application = new SpringApplication(Config.class);\n\t\tthis.application.setWebApplicationType(WebApplicationType.NONE);\n\t}\n\n\t@Test\n\t@WithResource(name = \"imported.properties\", content = \"\"\"\n\t\t\tspring.config.import=testbootstrap:test\n\t\t\tspring.profiles.active=test\n\t\t\tmyprop=igotbound\n\t\t\t#---\n\t\t\tspring.config.activate.on-profile=test\n\t\t\tmyprofileprop=igotprofilebound\n\n\t\t\t\"\"\")\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.context.config.ConfigDataLoader=\\\n\t\t\torg.springframework.boot.context.config.TestConfigDataBootstrap.Loader\n\t\t\torg.springframework.boot.context.config.ConfigDataLocationResolver=\\\n\t\t\torg.springframework.boot.context.config.TestConfigDataBootstrap.LocationResolver\n\t\t\t\"\"\")\n\tvoid bootstrapsApplicationContext() {\n\t\ttry (ConfigurableApplicationContext context = this.application\n\t\t\t.run(\"--spring.config.import=classpath:imported.properties\")) {\n\t\t\tLoaderHelper bean = context.getBean(TestConfigDataBootstrap.LoaderHelper.class);\n\t\t\tassertThat(bean).isNotNull();\n\t\t\tassertThat(bean.getBound()).isEqualTo(\"igotbound\");\n\t\t\tassertThat(bean.getProfileBound()).isEqualTo(\"igotprofilebound\");\n\t\t\tassertThat(bean.getLocation().getResolverHelper().getLocation())\n\t\t\t\t.isEqualTo(ConfigDataLocation.of(\"testbootstrap:test\"));\n\t\t}\n\t}\n\n\t@Configuration\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.config.ConfigData.Option;\nimport org.springframework.boot.context.config.ConfigData.Options;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests.Config;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ConfigDataEnvironmentPostProcessor} config data imports\n * that are combined with profile-specific files.\n *\n * @author Phillip Webb\n */\n@WithResource(name = \"application.properties\", content = \"\"\"\n\t\tspring.config.import=icwps:\n\t\tprop=fromfile\n\t\t\"\"\")\n@WithResource(name = \"application-prod.properties\", content = \"prop=fromprofilefile\")\n@WithResource(name = \"META-INF/spring.factories\",\n\t\tcontent = \"\"\"\n\t\t\t\torg.springframework.boot.context.config.ConfigDataLoader=\\\n\t\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.Loader\n\t\t\t\torg.springframework.boot.context.config.ConfigDataLocationResolver=\\\n\t\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests.LocationResolver\n\t\t\t\t\"\"\")\nclass ConfigDataEnvironmentPostProcessorImportCombinedWithProfileSpecificIntegrationTests {\n\n\tprivate SpringApplication application;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tpublic File temp;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.application = new SpringApplication(Config.class);\n\t\tthis.application.setWebApplicationType(WebApplicationType.NONE);\n\t}\n\n\t@Test\n\tvoid testWithoutProfile() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString value = context.getEnvironment().getProperty(\"prop\");\n\t\tassertThat(value).isEqualTo(\"fromicwps1\");\n\t}\n\n\t@Test\n\tvoid testWithProfile() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.active=prod\");\n\t\tString value = context.getEnvironment().getProperty(\"prop\");\n\t\tassertThat(value).isEqualTo(\"fromicwps2\");\n\t}\n\n\tstatic class LocationResolver implements ConfigDataLocationResolver<Resource> {\n\n\t\t@Override\n\t\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\treturn location.hasPrefix(\"icwps:\");\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Resource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Resource> resolveProfileSpecific(ConfigDataLocationResolverContext context,\n\t\t\t\tConfigDataLocation location, Profiles profiles) {\n\t\t\treturn Collections.singletonList(new Resource(profiles));\n\t\t}\n\n\t}\n\n\tstatic class Loader implements ConfigDataLoader<Resource> {\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, Resource resource) throws IOException {\n\t\t\tList<PropertySource<?>> propertySources = new ArrayList<>();\n\t\t\tMap<PropertySource<?>, Options> propertySourceOptions = new HashMap<>();\n\t\t\tpropertySources.add(new MapPropertySource(\"icwps1\", Collections.singletonMap(\"prop\", \"fromicwps1\")));\n\t\t\tif (resource.profiles.isAccepted(\"prod\")) {\n\t\t\t\tMapPropertySource profileSpecificPropertySource = new MapPropertySource(\"icwps2\",\n\t\t\t\t\t\tCollections.singletonMap(\"prop\", \"fromicwps2\"));\n\t\t\t\tpropertySources.add(profileSpecificPropertySource);\n\t\t\t\tpropertySourceOptions.put(profileSpecificPropertySource, Options.of(Option.PROFILE_SPECIFIC));\n\t\t\t}\n\t\t\treturn new ConfigData(propertySources, propertySourceOptions::get);\n\t\t}\n\n\t}\n\n\tprivate static class Resource extends ConfigDataResource {\n\n\t\tprivate final Profiles profiles;\n\n\t\tResource(Profiles profiles) {\n\t\t\tthis.profiles = profiles;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"icwps:\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.UUID;\n\nimport org.assertj.core.api.Condition;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.TestApplicationEnvironment;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.classpath.resources.WithResourceDirectory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.Profiles;\nimport org.springframework.core.env.SimpleCommandLinePropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Integration tests for {@link ConfigDataEnvironmentPostProcessor}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Nan Chiu\n */\nclass ConfigDataEnvironmentPostProcessorIntegrationTests {\n\n\tprivate SpringApplication application;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tpublic File temp;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.application = new SpringApplication(Config.class);\n\t\tthis.application.setWebApplicationType(WebApplicationType.NONE);\n\t}\n\n\t@AfterEach\n\tvoid clearProperties() {\n\t\tSystem.clearProperty(\"the.property\");\n\t}\n\n\t@Test\n\tvoid runWhenUsingCustomResourceLoader() {\n\t\tthis.application.setResourceLoader(new ResourceLoader() {\n\n\t\t\t@Override\n\t\t\tpublic Resource getResource(String location) {\n\t\t\t\tif (location.equals(\"classpath:/custom.properties\")) {\n\t\t\t\t\treturn new ByteArrayResource(\"the.property: fromcustom\".getBytes(), location);\n\t\t\t\t}\n\t\t\t\treturn new ClassPathResource(\"doesnotexist\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic ClassLoader getClassLoader() {\n\t\t\t\treturn getClass().getClassLoader();\n\t\t\t}\n\n\t\t});\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.config.name=custom\");\n\t\tString property = context.getEnvironment().getProperty(\"the.property\");\n\t\tassertThat(property).isEqualTo(\"fromcustom\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"foo=bucket\")\n\tvoid runLoadsApplicationPropertiesOnClasspath() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"foo\");\n\t\tassertThat(property).isEqualTo(\"bucket\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"yamlkey: yamlvalue\")\n\tvoid runLoadsApplicationYamlOnClasspath() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"yamlkey\");\n\t\tassertThat(property).isEqualTo(\"yamlvalue\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"testproperties.properties\", content = \"the.property=frompropertiesfile\")\n\tvoid runLoadsFileWithCustomName() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.config.name=testproperties\");\n\t\tString property = context.getEnvironment().getProperty(\"the.property\");\n\t\tassertThat(property).isEqualTo(\"frompropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tduplicate=properties\n\t\t\tonly-properties = properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\tduplicate: yaml\n\t\t\tonly-yaml: yaml\n\t\t\t\"\"\")\n\tvoid runWhenPropertiesAndYamlShouldPreferProperties() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"duplicate\")).isEqualTo(\"properties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"only-properties\")).isEqualTo(\"properties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"only-yaml\")).isEqualTo(\"yaml\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"moreproperties.properties\", content = \"\"\"\n\t\t\tthe.property=more\n\t\t\tonly.more=more\n\t\t\t\"\"\")\n\t@WithResource(name = \"testproperties.properties\", content = \"\"\"\n\t\t\tthe.property=test\n\t\t\tonly.test=test\n\t\t\t\"\"\")\n\tvoid runWhenMultipleCustomNamesLoadsEachName() {\n\t\tConfigurableApplicationContext context = this.application\n\t\t\t.run(\"--spring.config.name=moreproperties,testproperties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"the.property\")).isEqualTo(\"test\");\n\t\tassertThat(context.getEnvironment().getProperty(\"only.more\")).isEqualTo(\"more\");\n\t\tassertThat(context.getEnvironment().getProperty(\"only.test\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-default.properties\", content = \"my.property=fromdefaultpropertiesfile\")\n\tvoid runWhenNoActiveProfilesLoadsDefaultProfileFile() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromdefaultpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\tother: notempty\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: default\n\t\t\tmy:\n\t\t\t  property: fromdefaultprofile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: other\n\t\t\tmy:\n\t\t\t  property: fromotherprofile\n\t\t\t\"\"\")\n\tvoid runWhenActiveProfilesDoesNotLoadDefault() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.active=other\");\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromotherprofile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-thedefault.properties\", content = \"the.property=fromdefaultpropertiesfile\")\n\tvoid runWhenHasCustomDefaultProfileLoadsDefaultProfileFile() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.default=thedefault\");\n\t\tString property = context.getEnvironment().getProperty(\"the.property\");\n\t\tassertThat(property).isEqualTo(\"fromdefaultpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tfoo=bucket\n\t\t\tmy.property=fromapplicationproperties\n\t\t\t\"\"\")\n\t@WithResource(name = \"testproperties.properties\", content = \"\"\"\n\t\t\tmy.property=frompropertiesfile\n\t\t\tthe.property=frompropertiesfile\n\t\t\t\"\"\")\n\tvoid runWhenHasCustomSpringConfigLocationLoadsAllFromSpecifiedLocation() {\n\t\tConfigurableApplicationContext context = this.application\n\t\t\t.run(\"--spring.config.location=classpath:application.properties,classpath:testproperties.properties\");\n\t\tString property1 = context.getEnvironment().getProperty(\"the.property\");\n\t\tString property2 = context.getEnvironment().getProperty(\"my.property\");\n\t\tString property3 = context.getEnvironment().getProperty(\"foo\");\n\t\tassertThat(property1).isEqualTo(\"frompropertiesfile\");\n\t\tassertThat(property2).isEqualTo(\"frompropertiesfile\");\n\t\tassertThat(property3).isEqualTo(\"bucket\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tfoo=bucket\n\t\t\tmy.property=fromapplicationproperties\n\t\t\t\"\"\")\n\t@WithResource(name = \"testproperties.properties\", content = \"\"\"\n\t\t\tmy.property=frompropertiesfile\n\t\t\tthe.property=frompropertiesfile\n\t\t\t\"\"\")\n\tvoid runWhenOneCustomOptionalLocationDoesNotExistLoadsOthers() {\n\t\tConfigurableApplicationContext context = this.application.run(\n\t\t\t\t\"--spring.config.location=classpath:application.properties,classpath:testproperties.properties,optional:classpath:nonexistent.properties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"frompropertiesfile\");\n\t\tassertThat(context.getEnvironment().getProperty(\"foo\")).isEqualTo(\"bucket\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: prod\n\t\t\tspring.config.import: file:./non-existent.yml\n\t\t\t\"\"\")\n\tvoid runWhenProfileSpecificMandatoryLocationDoesNotExistShouldNotFail() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromyamlfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: prod\n\t\t\tspring.config.import: file:./non-existent.yml\n\t\t\t\"\"\")\n\tvoid runWhenProfileSpecificMandatoryLocationDoesNotExistShouldFailWhenProfileActive() {\n\t\tthis.application.setAdditionalProfiles(\"prod\");\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(() -> this.application.run())\n\t\t\t.withMessageContaining(\"non-existent.yml\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"enableprofile.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=myprofile\n\t\t\tmy.property=frompropertiesfile\n\t\t\tthe.property=frompropertiesfile\n\t\t\tone.more=${my.property}\n\t\t\t\"\"\")\n\t@WithResource(name = \"enableother.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=other\n\t\t\tmy.property=fromenableotherpropertiesfile\n\t\t\tone.more=${my.property}\n\t\t\t\"\"\")\n\t@WithResource(name = \"enableprofile-other.properties\", content = \"other.property=fromotherpropertiesfile\")\n\t@WithResource(name = \"enableprofile-myprofile.properties\", content = \"\"\"\n\t\t\tmy.property=fromprofilepropertiesfile\n\t\t\tthe.property=fromprofilepropertiesfile\n\t\t\t\"\"\")\n\tvoid runWhenHasActiveProfilesFromMultipleLocationsActivatesProfileFromOneLocation() {\n\t\tConfigurableApplicationContext context = this.application\n\t\t\t.run(\"--spring.config.location=classpath:enableprofile.properties,classpath:enableother.properties\");\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.getActiveProfiles()).containsExactly(\"other\");\n\t\tString property = environment.getProperty(\"other.property\");\n\t\tassertThat(property).isEqualTo(\"fromotherpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"enableprofile.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=myprofile\n\t\t\tmy.property=frompropertiesfile\n\t\t\t\"\"\")\n\t@WithResource(name = \"enabletwoprofiles.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=myprofile,another\n\t\t\tmy.property=fromtwopropertiesfile\n\t\t\t\"\"\")\n\t@WithResource(name = \"enableprofile-myprofile.properties\", content = \"\"\"\n\t\t\tmy.property=frommyprofilepropertiesfile\n\t\t\t\"\"\")\n\t@WithResource(name = \"enableprofile-another.properties\", content = \"\"\"\n\t\t\tmy.property=fromanotherprofilepropertiesfile\n\t\t\t\"\"\")\n\tvoid runWhenHasActiveProfilesFromMultipleAdditionalLocationsWithOneSwitchedOffLoadsExpectedProperties() {\n\t\tConfigurableApplicationContext context = this.application.run(\n\t\t\t\t\"--spring.config.additional-location=classpath:enabletwoprofiles.properties,classpath:enableprofile.properties\");\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.getActiveProfiles()).containsExactly(\"myprofile\");\n\t\tString property = environment.getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"frommyprofilepropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"testproperties-1.properties\", content = \"\"\"\n\t\t\tmy.property=fromtestproperties-1.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"testproperties-1-myprofile.properties\", content = \"\"\"\n\t\t\tmy.property=fromtestproperties-1-myprofile.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"testproperties-2.properties\", content = \"\"\"\n\t\t\tmy.property=fromtestproperties-2.properties\n\t\t\t\"\"\")\n\tvoid runWhenHasImportPropertyWithProfileSpecificFileTakesPrecedence() {\n\t\tConfigurableApplicationContext context = this.application.run(\n\t\t\t\t\"--spring.config.import=classpath:testproperties-1.properties,classpath:testproperties-2.properties\",\n\t\t\t\t\"--spring.profiles.active=myprofile\");\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tString property = environment.getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromtestproperties-1-myprofile.properties\");\n\t}\n\n\t@Test\n\tvoid runWhenHasLocalFileLoadsWithLocalFileTakingPrecedenceOverClasspath() throws Exception {\n\t\tFile localFile = new File(new File(\".\"), \"application.properties\");\n\t\tassertThat(localFile).doesNotExist();\n\t\ttry {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(\"my.property\", \"fromlocalfile\");\n\t\t\ttry (OutputStream outputStream = new FileOutputStream(localFile)) {\n\t\t\t\tproperties.store(outputStream, \"\");\n\t\t\t}\n\t\t\tConfigurableApplicationContext context = this.application.run();\n\t\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\t\tassertThat(property).isEqualTo(\"fromlocalfile\");\n\t\t}\n\t\tfinally {\n\t\t\tlocalFile.delete();\n\t\t}\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.property=frompropertiesfile\n\t\t\tthe.property=frompropertiesfile\n\t\t\t\"\"\")\n\tvoid runWhenHasCommandLinePropertiesLoadsWithCommandLineTakingPrecedence() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new SimpleCommandLinePropertySource(\"--the.property=fromcommandline\"));\n\t\tthis.application.setEnvironment(environment);\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"the.property\")).isEqualTo(\"fromcommandline\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"frompropertiesfile\");\n\t}\n\n\t@Test\n\tvoid runWhenHasSystemPropertyLoadsWithSystemPropertyTakingPrecedence() {\n\t\tSystem.setProperty(\"the.property\", \"fromsystem\");\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.config.name=testproperties\");\n\t\tString property = context.getEnvironment().getProperty(\"the.property\");\n\t\tassertThat(property).isEqualTo(\"fromsystem\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"my.property=fromapplicationproperties\")\n\tvoid runWhenHasDefaultPropertiesIncludesDefaultPropertiesLast() {\n\t\tthis.application.setDefaultProperties(Map.of(\"my.property\", \"fromdefaults\", \"my.fallback\", \"fromdefaults\"));\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.fallback\")).isEqualTo(\"fromdefaults\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromapplicationproperties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"testproperties.properties\", content = \"the.property=frompropertiesfile\")\n\tvoid runWhenHasDefaultPropertiesWithConfigNameLoadsExpectedProperties() {\n\t\tthis.application.setDefaultProperties(Collections.singletonMap(\"spring.config.name\", \"testproperties\"));\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"the.property\");\n\t\tassertThat(property).isEqualTo(\"frompropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=myprofile\")\n\tvoid runWhenHasActiveProfilesFromDefaultPropertiesAndFileLoadsWithActiveProfilesFromFileTakingPrecedence() {\n\t\tthis.application.setDefaultProperties(Collections.singletonMap(\"spring.profiles.active\", \"dev\"));\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"myprofile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-other.properties\", content = \"my.property=fromotherpropertiesfile\")\n\tvoid runWhenProgrammaticallySetProfilesLoadsWithSetProfilesTakePrecedenceOverDefaultProfile() {\n\t\tthis.application.setAdditionalProfiles(\"other\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromotherpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-dev.properties\", content = \"my.property=fromdevpropertiesfile\")\n\t@WithResource(name = \"application-other.properties\", content = \"my.property=fromotherpropertiesfile\")\n\tvoid runWhenTwoProfilesSetProgrammaticallyLoadsWithPreservedProfileOrder() {\n\t\tthis.application.setAdditionalProfiles(\"other\", \"dev\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromdevpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=myprofile\")\n\t@WithResource(name = \"application-myprofile.properties\", content = \"the.property=fromprofilepropertiesfile\")\n\t@WithResource(name = \"application-other.properties\", content = \"other.property=fromotherpropertiesfile\")\n\tvoid runWhenProfilesPresentBeforeConfigFileProcessingAugmentsProfileActivatedByConfigFile() {\n\t\tthis.application.setAdditionalProfiles(\"other\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"other\", \"myprofile\");\n\t\tString property = context.getEnvironment().getProperty(\"other.property\");\n\t\tassertThat(property).isEqualTo(\"fromotherpropertiesfile\");\n\t\tproperty = context.getEnvironment().getProperty(\"the.property\");\n\t\tassertThat(property).isEqualTo(\"fromprofilepropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=myprofile\n\t\t\tone.more=${my.property}\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-myprofile.properties\", content = \"my.property=fromprofilepropertiesfile\")\n\tvoid runWhenProfilePropertiesUsedInPlaceholdersLoadsWithResolvedPlaceholders() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"one.more\")).isEqualTo(\"fromprofilepropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-dev.properties\", content = \"my.property=fromdevpropertiesfile\")\n\t@WithResource(name = \"application-other.properties\", content = \"my.property=fromotherpropertiesfile\")\n\tvoid runWhenDuplicateProfileSetProgrammaticallyAndViaPropertyLoadsWithProfiles() {\n\t\tthis.application.setAdditionalProfiles(\"dev\");\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.active=dev,other\");\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).contains(\"dev\", \"other\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromotherpropertiesfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-dev.properties\", content = \"my.property=fromdevpropertiesfile\")\n\t@WithResource(name = \"application-other.properties\", content = \"my.property=fromotherpropertiesfile\")\n\tvoid runWhenProfilesActivatedViaBracketNotationSetsProfiles() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.active[0]=dev\",\n\t\t\t\t\"--spring.profiles.active[1]=other\");\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).contains(\"dev\", \"other\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromotherpropertiesfile\");\n\t}\n\n\t@Test // gh-45387\n\tvoid runWhenProfileActivatedViaSystemEnvironmentVariableWithPrefix() {\n\t\tthis.application.setEnvironmentPrefix(\"example.prefix\");\n\t\tthis.application.setEnvironment(new TestApplicationEnvironment() {\n\n\t\t\t@Override\n\t\t\tpublic Map<String, Object> getSystemEnvironment() {\n\t\t\t\treturn Map.of(\"EXAMPLE_PREFIX_SPRING_PROFILES_ACTIVE\", \"other,dev\");\n\t\t\t}\n\n\t\t});\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).contains(\"dev\", \"other\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t  other: notempty\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: dev\n\t\t\tmy:\n\t\t\t  property: fromdevprofile\n\t\t\t\"\"\")\n\tvoid loadWhenProfileInMultiDocumentFilesLoadsExpectedProperties() {\n\t\tthis.application.setAdditionalProfiles(\"dev\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromdevprofile\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.other\")).isEqualTo(\"notempty\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t  other: notempty\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: dev\n\t\t\tmy:\n\t\t\t  property: fromdevprofile\n\t\t\tdev:\n\t\t\t  property: devproperty\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: other\n\t\t\tmy:\n\t\t\t  property: fromotherprofile\n\t\t\t\"\"\")\n\tvoid runWhenMultipleActiveProfilesWithMultiDocumentFilesLoadsInOrderOfDocument() {\n\t\tthis.application.setAdditionalProfiles(\"other\", \"dev\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(property).isEqualTo(\"fromotherprofile\");\n\t\tproperty = context.getEnvironment().getProperty(\"my.other\");\n\t\tassertThat(property).isEqualTo(\"notempty\");\n\t\tproperty = context.getEnvironment().getProperty(\"dev.property\");\n\t\tassertThat(property).isEqualTo(\"devproperty\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: dev & other\n\t\t\tmy:\n\t\t\t  property: devandother\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: (dev | other) & another\n\t\t\tmy:\n\t\t\t  property: devorotherandanother\n\t\t\t\"\"\")\n\tvoid runWhenHasAndProfileExpressionLoadsExpectedProperties() {\n\t\tthis.application.setAdditionalProfiles(\"dev\", \"other\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"devandother\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: dev & other\n\t\t\tmy:\n\t\t\t  property: devandother\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: (dev | other) & another\n\t\t\tmy:\n\t\t\t  property: devorotherandanother\n\t\t\t\"\"\")\n\tvoid runWhenHasComplexProfileExpressionsLoadsExpectedProperties() {\n\t\tthis.application.setAdditionalProfiles(\"dev\", \"another\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"devorotherandanother\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yaml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: dev & other\n\t\t\tmy:\n\t\t\t  property: devandother\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: (dev | other) & another\n\t\t\tmy:\n\t\t\t  property: devorotherandanother\n\t\t\t\"\"\")\n\tvoid runWhenProfileExpressionsDoNotMatchLoadsExpectedProperties() {\n\t\tthis.application.setAdditionalProfiles(\"dev\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromyamlfile\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t  other: notempty\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: other\n\t\t\tmy:\n\t\t\t  property: fromotherprofile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: \"!other\"\n\t\t\tmy:\n\t\t\t  property: fromnototherprofile\n\t\t\t  notother: foo\n\n\t\t\t\"\"\")\n\tvoid runWhenHasNegatedProfilesLoadsExpectedProperties() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromnototherprofile\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.notother\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t  other: notempty\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: other\n\t\t\tmy:\n\t\t\t  property: fromotherprofile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: \"!other\"\n\t\t\tmy:\n\t\t\t  property: fromnototherprofile\n\t\t\t  notother: foo\n\n\t\t\t\"\"\")\n\tvoid runWhenHasNegatedProfilesWithProfileActiveLoadsExpectedProperties() {\n\t\tthis.application.setAdditionalProfiles(\"other\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromotherprofile\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.notother\")).isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tspring:\n\t\t\t  profiles:\n\t\t\t    active: dev\n\t\t\tmy:\n\t\t\t  property: fromyamlfile\n\t\t\t---\n\t\t\tspring.config.activate.on-profile: dev\n\t\t\tmy:\n\t\t\t  property: fromdevprofile\n\t\t\t\"\"\")\n\tvoid runWhenHasActiveProfileConfigurationInMultiDocumentFileLoadsInExpectedOrder() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"dev\");\n\t\tString property = context.getEnvironment().getProperty(\"my.property\");\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).contains(\"dev\");\n\t\tassertThat(property).isEqualTo(\"fromdevprofile\");\n\t\tassertThat(context.getEnvironment().getPropertySources()).extracting(\"name\")\n\t\t\t.contains(\n\t\t\t\t\t\"Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' (document #0)\",\n\t\t\t\t\t\"Config resource 'class path resource [application.yml]' via location 'optional:classpath:/' (document #1)\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tspring:\n\t\t\t  profiles:\n\t\t\t    active: dev,healthcheck\n\t\t\t\"\"\")\n\tvoid runWhenHasYamlWithCommaSeparatedMultipleProfilesLoadsExpectedProperties() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"dev\", \"healthcheck\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tspring:\n\t\t\t  profiles:\n\t\t\t    active:\n\t\t\t      - dev\n\t\t\t      - healthcheck\n\t\t\t\"\"\")\n\tvoid runWhenHasYamlWithListProfilesLoadsExpectedProperties() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"dev\", \"healthcheck\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\t---\n\t\t\tspring:\n\t\t\t  profiles:\n\t\t\t    active: dev  ,    healthcheck\n\t\t\t\"\"\")\n\tvoid loadWhenHasWhitespaceTrims() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"dev\", \"healthcheck\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasConfigLocationAsFile() throws IOException {\n\t\tFile properties = new File(this.temp, \"specificlocation.properties\");\n\t\tFiles.write(properties.toPath(),\n\t\t\t\tList.of(\"my.property=fromspecificlocation\", \"the.property=fromspecificlocation\"));\n\t\tString location = properties.toURI().toURL().toString();\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.config.location=\" + location);\n\t\tassertThat(context.getEnvironment())\n\t\t\t.has(matchingPropertySource(\"Config resource 'file [\" + properties + \"]' via location '\" + location + \"'\"));\n\t}\n\n\t@Test\n\tvoid loadWhenHasRelativeConfigLocationUsesFileLocation() throws IOException {\n\t\tFile buildOutput = new BuildOutput(getClass()).getRootLocation();\n\t\tFile resources = new File(buildOutput, \"resources-\" + UUID.randomUUID());\n\t\ttry {\n\t\t\tresources.mkdirs();\n\t\t\tFile properties = new File(resources, \"specificlocation.properties\").getAbsoluteFile();\n\t\t\tFiles.write(properties.toPath(),\n\t\t\t\t\tList.of(\"my.property=fromspecificlocation\", \"the.property=fromspecificlocation\"));\n\t\t\tPath relative = new File(\"\").getAbsoluteFile().toPath().relativize(properties.toPath());\n\t\t\tConfigurableApplicationContext context = this.application.run(\"--spring.config.location=\" + relative);\n\t\t\tassertThat(context.getEnvironment()).has(matchingPropertySource(\n\t\t\t\t\t\"Config resource 'file [\" + relative + \"]' via location '\" + relative + \"'\"));\n\t\t}\n\t\tfinally {\n\t\t\tFileSystemUtils.deleteRecursively(resources);\n\t\t}\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-customdefault.properties\", content = \"customdefault=true\")\n\t@WithResource(name = \"application-dev.properties\", content = \"my.property=fromdevpropertiesfile\")\n\tvoid loadWhenCustomDefaultProfileAndActiveFromPreviousSourceDoesNotActivateDefault() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.default=customdefault\",\n\t\t\t\t\"--spring.profiles.active=dev\");\n\t\tassertThat(context.getEnvironment().getProperty(\"my.property\")).isEqualTo(\"fromdevpropertiesfile\");\n\t\tassertThat(context.getEnvironment().containsProperty(\"customdefault\")).isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=customdefault\n\t\t\tcustomprofile=true\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-customdefault.properties\", content = \"customprofile-customdefault=true\")\n\tvoid runWhenCustomDefaultProfileSameAsActiveFromFileActivatesProfile() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.default=customdefault\");\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.containsProperty(\"customprofile\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"customprofile-customdefault\")).isTrue();\n\t\tassertThat(environment.acceptsProfiles(Profiles.of(\"customdefault\"))).isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=${activeProfile:propertiesfile}\")\n\tvoid runWhenActiveProfilesCanBeConfiguredUsingPlaceholdersResolvedAgainstTheEnvironmentLoadsExpectedProperties() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--activeProfile=testPropertySource\");\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"testPropertySource\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tfoo=bucket\n\t\t\tvalue=1234\n\t\t\t\"\"\")\n\t@WithResource(name = \"override.properties\", content = \"foo=bar\")\n\tvoid runWhenHasAdditionalLocationLoadsWithAdditionalTakingPrecedenceOverDefaultLocation() {\n\t\tConfigurableApplicationContext context = this.application\n\t\t\t.run(\"--spring.config.additional-location=classpath:override.properties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(context.getEnvironment().getProperty(\"value\")).isEqualTo(\"1234\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tfoo=bucket\n\t\t\tvalue=1234\n\t\t\t\"\"\")\n\t@WithResource(name = \"override.properties\", content = \"foo=bar\")\n\t@WithResource(name = \"some.properties\", content = \"foo=spam\")\n\tvoid runWhenMultipleAdditionalLocationsLoadsWithLastWinning() {\n\t\tConfigurableApplicationContext context = this.application\n\t\t\t.run(\"--spring.config.additional-location=classpath:override.properties,classpath:some.properties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"foo\")).isEqualTo(\"spam\");\n\t\tassertThat(context.getEnvironment().getProperty(\"value\")).isEqualTo(\"1234\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"value=1234\")\n\t@WithResource(name = \"override.properties\", content = \"foo=bar\")\n\t@WithResource(name = \"some.properties\", content = \"foo=spam\")\n\tvoid runWhenAdditionalLocationAndLocationLoadsWithAdditionalTakingPrecedenceOverConfigured() {\n\t\tConfigurableApplicationContext context = this.application.run(\n\t\t\t\t\"--spring.config.location=classpath:some.properties\",\n\t\t\t\t\"--spring.config.additional-location=classpath:override.properties\");\n\t\tassertThat(context.getEnvironment().getProperty(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(context.getEnvironment().getProperty(\"value\")).isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.custom\", content = \"\")\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.env.PropertySourceLoader=\\\n\t\t\torg.springframework.boot.context.config.TestPropertySourceLoader1,\\\n\t\t\torg.springframework.boot.context.config.TestPropertySourceLoader2\n\t\t\t\"\"\")\n\tvoid runWhenPropertiesFromCustomPropertySourceLoaderShouldLoadFromCustomSource() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"customloader1\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"gh17001.properties\", content = \"gh17001loaded=true\")\n\tvoid runWhenCustomDefaultPropertySourceLoadsWithoutReplacingCustomSource() {\n\t\t// gh-17011\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"mapkey\", \"mapvalue\");\n\t\tMapPropertySource propertySource = new MapPropertySource(\"defaultProperties\", source) {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\t\tif (\"spring.config.name\".equals(name)) {\n\t\t\t\t\treturn \"gh17001\";\n\t\t\t\t}\n\t\t\t\treturn super.getProperty(name);\n\t\t\t}\n\n\t\t};\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tthis.application.setEnvironment(environment);\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"mapkey\")).isEqualTo(\"mapvalue\");\n\t\tassertThat(context.getEnvironment().getProperty(\"gh17001loaded\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasUnknownFileExtensionFailsFast() {\n\t\tString location = \"classpath:application.unknown\";\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.application.run(\"--spring.config.location=\" + location))\n\t\t\t.withMessageContaining(\"Unable to load config data\")\n\t\t\t.withMessageContaining(location)\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).hasMessageContaining(\"File extension is not known\")\n\t\t\t\t.hasMessageContaining(\"it must end in '/'\"));\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasOptionalMissingDirectoryContinuesToLoad() {\n\t\tString location = \"optional:classpath:application.unknown/\";\n\t\tthis.application.run(\"--spring.config.location=\" + location);\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasNonOptionalMissingFileDirectoryThrowsResourceNotFoundException() {\n\t\tFile location = new File(this.temp, \"application.unknown\");\n\t\tassertThatExceptionOfType(ConfigDataLocationNotFoundException.class).isThrownBy(() -> this.application\n\t\t\t.run(\"--spring.config.location=\" + StringUtils.cleanPath(location.getAbsolutePath()) + \"/\"));\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasNonOptionalMissingClasspathDirectoryThrowsLocationNotFoundException() {\n\t\tString location = \"classpath:application.unknown/\";\n\t\tassertThatExceptionOfType(ConfigDataLocationNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.application.run(\"--spring.config.location=\" + location));\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasNonOptionalEmptyFileDirectoryDoesNotThrowException() {\n\t\tFile location = new File(this.temp, \"application.empty\");\n\t\tlocation.mkdirs();\n\t\tassertThatNoException().isThrownBy(() -> this.application\n\t\t\t.run(\"--spring.config.location=\" + StringUtils.cleanPath(location.getAbsolutePath()) + \"/\"));\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasMandatoryDirectoryThatDoesntExistThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataLocationNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.application.run(\"--spring.config.location=\" + StringUtils.cleanPath(\"invalid/\")));\n\t}\n\n\t@Test\n\tvoid runWhenConfigLocationHasNonOptionalEmptyFileDoesNotThrowException() throws IOException {\n\t\tFile location = new File(this.temp, \"application.properties\");\n\t\tFileCopyUtils.copy(new byte[0], location);\n\t\tassertThatNoException().isThrownBy(() -> this.application\n\t\t\t.run(\"--spring.config.location=\" + StringUtils.cleanPath(location.getAbsolutePath())));\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.context.config.ConfigDataLocationResolver=\\\n\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$LocationResolver\n\n\t\t\torg.springframework.boot.context.config.ConfigDataLoader=\\\n\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$Loader\n\t\t\t\"\"\")\n\tvoid runWhenResolvedIsOptionalDoesNotThrowException() {\n\t\tApplicationContext context = this.application.run(\"--spring.config.location=test:optionalresult\");\n\t\tassertThat(context.getEnvironment().containsProperty(\"spring\")).isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles=a\")\n\tvoid runWhenUsingInvalidPropertyThrowsException() {\n\t\tassertThatExceptionOfType(InvalidConfigDataPropertyException.class).isThrownBy(() -> this.application.run());\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.import=imported\n\t\t\tspring.config.import=classpath:${my.import}.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=iwasimported\")\n\tvoid runWhenImportUsesPlaceholder() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.value\")).isEqualTo(\"iwasimported\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.import=imported\n\t\t\t#---\n\t\t\tspring.config.import=classpath:${my.import}.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=iwasimported\")\n\tvoid runWhenImportFromEarlierDocumentUsesPlaceholder() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.value\")).isEqualTo(\"iwasimported\");\n\t}\n\n\t@Test // gh-26858\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.config.import=classpath:imported.properties\n\t\t\tmy.value=application.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=imported.properties\")\n\t@WithResource(name = \"application-dev.properties\", content = \"my.value=application-dev.properties\")\n\tvoid runWhenImportWithProfileVariantOrdersPropertySourcesCorrectly() {\n\t\tthis.application.setAdditionalProfiles(\"dev\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.value\")).isEqualTo(\"application-dev.properties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.config.import=classpath:imported.properties\n\t\t\tmy.value=application.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=imported.properties\")\n\t@WithResource(name = \"imported-dev.properties\", content = \"my.value=imported-dev.properties\")\n\t@WithResource(name = \"application-dev.properties\", content = \"\"\"\n\t\t\tspring.config.import=imported-dev.properties\n\t\t\tmy.value=application-dev.properties\"\"\")\n\tvoid runWhenImportWithProfileVariantAndDirectProfileImportOrdersPropertySourcesCorrectly() {\n\t\tthis.application.setAdditionalProfiles(\"dev\");\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.value\")).isEqualTo(\"imported-dev.properties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.import=application-import-with-placeholder-imported\n\t\t\t#---\n\t\t\tspring.config.import=classpath:org/springframework/boot/context/config/${my.import}.properties\n\t\t\t#---\n\t\t\tmy.import=badbadbad\n\t\t\tspring.config.activate.on-profile=missing\n\t\t\t\"\"\")\n\tvoid runWhenHasPropertyInProfileDocumentThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run())\n\t\t\t.withCauseInstanceOf(InactiveConfigDataAccessException.class);\n\t}\n\n\t@Test // gh-29386\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.value=application\n\t\t\t#---\n\t\t\tmy.import=imported\n\t\t\tspring.config.activate.on-profile=missing\n\t\t\t#---\n\t\t\tspring.config.import=${my.import}.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=imported\")\n\tvoid runWhenHasPropertyInEarlierProfileDocumentThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run())\n\t\t\t.withCauseInstanceOf(InactiveConfigDataAccessException.class);\n\t}\n\n\t@Test // gh-29386\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.import=imported\n\t\t\t#---\n\t\t\tmy.value=should-be-ignored\n\t\t\tspring.config.activate.on-profile=missing\n\t\t\t#---\n\t\t\tspring.config.import=classpath:${my.import}.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=imported\")\n\tvoid runWhenHasPropertyInEarlierDocumentLoads() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getProperty(\"my.value\")).isEqualTo(\"imported\");\n\t}\n\n\t@Test\n\tvoid runWhenHasNonOptionalImportThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(\n\t\t\t\t() -> this.application.run(\"--spring.config.location=classpath:missing-appplication.properties\"));\n\t}\n\n\t@Test\n\tvoid runWhenHasNonOptionalImportAndIgnoreNotFoundPropertyDoesNotThrowException() {\n\t\tthis.application.run(\"--spring.config.on-not-found=ignore\",\n\t\t\t\t\"--spring.config.location=classpath:missing-appplication.properties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=p1\n\t\t\tspring.profiles.include=p2\n\t\t\t#---\n\t\t\tspring.profiles.include=p3,p4\n\t\t\t#---\n\t\t\tspring.profiles.include=p5\n\t\t\t\"\"\")\n\tvoid runWhenHasIncludedProfilesActivatesProfiles() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactlyInAnyOrder(\"p1\", \"p2\", \"p3\", \"p4\",\n\t\t\t\t\"p5\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=p1\n\t\t\tspring.profiles.include=p2\n\t\t\t#---\n\t\t\tmyprofile=p4\n\t\t\tspring.profiles.include=p3,${myprofile}\n\t\t\t#---\n\t\t\tmyotherprofile=p5\n\t\t\tspring.profiles.include=${myotherprofile}\n\t\t\t\"\"\")\n\tvoid runWhenHasIncludedProfilesWithPlaceholderActivatesProfiles() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactlyInAnyOrder(\"p1\", \"p2\", \"p3\", \"p4\",\n\t\t\t\t\"p5\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=p1\n\t\t\tspring.profiles.include=p2\n\t\t\t#---\n\t\t\tspring.config.activate.on-profile=p2\n\t\t\tspring.profiles.include=p3\n\t\t\t\"\"\")\n\tvoid runWhenHasIncludedProfilesWithProfileSpecificDocumentThrowsException() {\n\t\tassertThatExceptionOfType(InactiveConfigDataAccessException.class).isThrownBy(() -> this.application.run());\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-test.yaml\", content = \"\"\"\n\t\t\tspring:\n\t\t\t  profiles:\n\t\t\t    include:\n\t\t\t      - p\n\t\t\t\"\"\")\n\tvoid runWhenHasIncludedProfilesWithListSyntaxWithProfileSpecificDocumentThrowsException() {\n\t\tassertThatExceptionOfType(InvalidConfigDataPropertyException.class)\n\t\t\t.isThrownBy(() -> this.application.run(\"--spring.profiles.active=test\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tmy.import=imported\n\t\t\tspring.config.import=classpath:${my.import}.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"imported.properties\", content = \"my.value=imported\")\n\tvoid runWhenImportingIncludesParentOrigin() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tBinder binder = Binder.get(context.getEnvironment());\n\t\tList<ConfigurationProperty> properties = new ArrayList<>();\n\t\tBindHandler bindHandler = new BindHandler() {\n\n\t\t\t@Override\n\t\t\tpublic Object onSuccess(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t\t\tObject result) {\n\t\t\t\tproperties.add(context.getConfigurationProperty());\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t};\n\t\tbinder.bind(\"my.value\", Bindable.of(String.class), bindHandler);\n\t\tassertThat(properties).hasSize(1);\n\t\tOrigin origin = properties.get(0).getOrigin();\n\t\tassertThat(origin).isNotNull();\n\t\tassertThat(origin.toString()).contains(\"imported.properties\");\n\t\tOrigin parent = origin.getParent();\n\t\tassertThat(parent).isNotNull();\n\t\tassertThat(parent.toString()).contains(\"application.properties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"config/first/application.properties\", content = \"first.property=apple\")\n\t@WithResource(name = \"config/second/application.properties\", content = \"second.property=ball\")\n\t@WithResource(name = \"config/third/nested/application.properties\", content = \"third.property=three\")\n\tvoid runWhenHasWildcardLocationLoadsFromAllMatchingLocations() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.config.location=classpath:config/*/\");\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.getProperty(\"first.property\")).isEqualTo(\"apple\");\n\t\tassertThat(environment.getProperty(\"second.property\")).isEqualTo(\"ball\");\n\t\tassertThat(environment.getProperty(\"third.property\")).isNull();\n\t}\n\n\t@Test\n\tvoid runWhenOptionalWildcardFileDoesNotExistDoesNotThrowException() {\n\t\tassertThatNoException().isThrownBy(() -> this.application\n\t\t\t.run(\"--spring.config.location=optional:classpath:nonexistent/*/testproperties.properties\"));\n\t}\n\n\t@Test\n\tvoid runWhenMandatoryWildcardFileDoesNotExistThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataLocationNotFoundException.class).isThrownBy(() -> this.application\n\t\t\t.run(\"--spring.config.location=classpath:nonexistent/*/testproperties.properties\"));\n\t}\n\n\t@Test\n\t@WithResourceDirectory(\"config/empty\")\n\tvoid runWhenMandatoryWildcardDirectoryHasEmptyDirectoryDoesNotThrowException() {\n\t\tassertThatNoException().isThrownBy(() -> this.application.run(\"--spring.config.location=classpath:config/*/\"));\n\t}\n\n\t@Test\n\t@WithResourceDirectory(\"config/empty\")\n\tvoid runWhenOptionalWildcardDirectoryHasNoSubdirectoriesDoesNotThrow() {\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> this.application.run(\"--spring.config.location=optional:classpath:config/*/\"));\n\t}\n\n\t@Test\n\t@WithResourceDirectory(\"config\")\n\tvoid runWhenMandatoryWildcardDirectoryHasNoSubdirectoriesThrows() {\n\t\tassertThatExceptionOfType(ConfigDataLocationNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.application.run(\"--spring.config.location=classpath:config/*/\"))\n\t\t\t.withMessage(\"Config data location 'classpath:config/*/' contains no subdirectories\");\n\t}\n\n\t@Test\n\tvoid runWhenOptionalWildcardDirectoryDoesNotExistDoesNotThrowException() {\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> this.application.run(\"--spring.config.location=optional:file:invalid/*/\"));\n\t}\n\n\t@Test // gh-24990\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=test,other\")\n\t@WithResource(name = \"application-test.properties\", content = \"\"\"\n\t\t\ttest1=test1\n\t\t\t#---\n\t\t\tspring.config.activate.on-profile=other\n\t\t\ttest2=test2\n\t\t\t\"\"\")\n\tvoid runWhenHasProfileSpecificFileWithActiveOnProfileProperty() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.getProperty(\"test1\")).isEqualTo(\"test1\");\n\t\tassertThat(environment.getProperty(\"test2\")).isEqualTo(\"test2\");\n\t}\n\n\t@Test // gh-26960\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=p1,p2\n\t\t\tapplication=true\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-p1.properties\", content = \"\"\"\n\t\t\tapplication-p1=true\n\t\t\tspring.config.import=import.properties\n\t\t\t\"\"\")\n\t@WithResource(name = \"import.properties\", content = \"import=true\")\n\t@WithResource(name = \"import-p1.properties\", content = \"import-p1=true\")\n\t@WithResource(name = \"import-p2.properties\", content = \"import-p2=true\")\n\tvoid runWhenHasProfileSpecificImportWithImportImportsSecondProfileSpecificFile() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.containsProperty(\"application\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"application-p1\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"application-p2\")).isFalse();\n\t\tassertThat(environment.containsProperty(\"import\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"import-p1\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"import-p2\")).isTrue();\n\t}\n\n\t@Test // gh-26960\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=p1,p2\")\n\t@WithResource(name = \"application-p1.properties\", content = \"spring.config.import:test:boot\")\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.context.config.ConfigDataLocationResolver=\\\n\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$LocationResolver\n\n\t\t\torg.springframework.boot.context.config.ConfigDataLoader=\\\n\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentPostProcessorIntegrationTests$Loader\n\t\t\t\"\"\")\n\tvoid runWhenHasProfileSpecificImportWithCustomImportResolvesProfileSpecific() {\n\t\tConfigurableApplicationContext context = this.application.run();\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.containsProperty(\"test:boot\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"test:boot:ps\")).isTrue();\n\t}\n\n\t@Test // gh-26593\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\troot=true\n\t\t\tv1=root\n\t\t\tv2=root\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-p1.properties\", content = \"\"\"\n\t\t\troot-p1=true\n\t\t\tv1=root-p1\n\t\t\tv2=root-p1\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-p2.properties\", content = \"\"\"\n\t\t\troot-p2=true\n\t\t\tv1=root-p2\n\t\t\tv2=root-p2\n\t\t\t\"\"\")\n\t@WithResource(name = \"config/application.properties\", content = \"\"\"\n\t\t\tconfig=true\n\t\t\tv1=config\n\t\t\tv2=config\n\t\t\t\"\"\")\n\t@WithResource(name = \"config/application-p1.properties\", content = \"\"\"\n\t\t\tconfig-p1=true\n\t\t\tv1=config-p1\n\t\t\t#v2 intentionally missing\n\t\t\t\"\"\")\n\t@WithResource(name = \"config/application-p2.properties\", content = \"\"\"\n\t\t\tconfig-p2=true\n\t\t\tv1=config-p2\n\t\t\t#v2 intentionally missing\n\t\t\t\"\"\")\n\tvoid runWhenHasFilesInRootAndConfigWithProfiles() {\n\t\tConfigurableApplicationContext context = this.application.run(\"--spring.profiles.active=p1,p2\");\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tassertThat(environment.containsProperty(\"root\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"root-p1\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"root-p2\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"config\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"config-p1\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"config-p2\")).isTrue();\n\t\tassertThat(environment.getProperty(\"v1\")).isEqualTo(\"config-p2\");\n\t\tassertThat(environment.getProperty(\"v2\")).isEqualTo(\"root-p2\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=fa!l\n\t\t\t\"\"\")\n\tvoid invalidProfileActivePropertyThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run())\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"must contain a letter\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.include=fa!l\n\t\t\t\"\"\")\n\tvoid invalidProfileIncludePropertyThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.application.run())\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"must contain a letter\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=p!1\n\t\t\tspring.profiles.include=p!2\n\t\t\tspring.profiles.validate=false\n\t\t\t\"\"\")\n\tvoid unvalidatedProfileProperties() {\n\t\tassertThatNoException().isThrownBy(() -> this.application.run());\n\t}\n\n\tprivate Condition<ConfigurableEnvironment> matchingPropertySource(final String sourceName) {\n\t\treturn new Condition<>(\"environment containing property source \" + sourceName) {\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(ConfigurableEnvironment value) {\n\t\t\t\treturn value.getPropertySources().contains(sourceName);\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\tstatic class LocationResolver implements ConfigDataLocationResolver<TestConfigDataResource> {\n\n\t\t@Override\n\t\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\treturn location.hasPrefix(\"test:\");\n\n\t\t}\n\n\t\t@Override\n\t\tpublic List<TestConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\t\tConfigDataLocation location)\n\t\t\t\tthrows ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException {\n\t\t\treturn Collections.singletonList(new TestConfigDataResource(location, false));\n\t\t}\n\n\t\t@Override\n\t\tpublic List<TestConfigDataResource> resolveProfileSpecific(ConfigDataLocationResolverContext context,\n\t\t\t\tConfigDataLocation location, org.springframework.boot.context.config.Profiles profiles)\n\t\t\t\tthrows ConfigDataLocationNotFoundException {\n\t\t\treturn Collections.singletonList(new TestConfigDataResource(location, true));\n\t\t}\n\n\t}\n\n\tstatic class Loader implements ConfigDataLoader<TestConfigDataResource> {\n\n\t\t@Override\n\t\tpublic @Nullable ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource resource)\n\t\t\t\tthrows IOException, ConfigDataResourceNotFoundException {\n\t\t\tif (resource.isOptional()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\t\tif (!resource.isProfileSpecific()) {\n\t\t\t\tmap.put(\"spring\", \"boot\");\n\t\t\t}\n\t\t\tString suffix = (!resource.isProfileSpecific()) ? \"\" : \":ps\";\n\t\t\tmap.put(resource + suffix, \"true\");\n\t\t\tMapPropertySource propertySource = new MapPropertySource(\"loaded\" + suffix, map);\n\t\t\treturn new ConfigData(Collections.singleton(propertySource));\n\t\t}\n\n\t}\n\n\tstatic class TestConfigDataResource extends ConfigDataResource {\n\n\t\tprivate final ConfigDataLocation location;\n\n\t\tprivate final boolean profileSpecific;\n\n\t\tTestConfigDataResource(ConfigDataLocation location, boolean profileSpecific) {\n\t\t\tsuper(location.toString().contains(\"optionalresult\"));\n\t\t\tthis.location = location;\n\t\t\tthis.profileSpecific = profileSpecific;\n\t\t}\n\n\t\tboolean isProfileSpecific() {\n\t\t\treturn this.profileSpecific;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tTestConfigDataResource other = (TestConfigDataResource) obj;\n\t\t\treturn ObjectUtils.nullSafeEquals(this.location, other.location)\n\t\t\t\t\t&& this.profileSpecific == other.profileSpecific;\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.location.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.TestApplicationEnvironment;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.config.ConfigData.Options;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ConfigDataEnvironmentPostProcessor}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Nguyen Bao Sach\n */\nclass ConfigDataEnvironmentPostProcessorTests {\n\n\tprivate final TestApplicationEnvironment environment = new TestApplicationEnvironment();\n\n\tprivate final SpringApplication application = new SpringApplication();\n\n\tprivate @Nullable ConfigDataEnvironment configDataEnvironment;\n\n\tprivate @Nullable ConfigDataEnvironmentPostProcessor postProcessor;\n\n\t@Test\n\tvoid postProcessEnvironmentWhenNoLoaderCreatesDefaultLoaderInstance() {\n\t\tsetupMocksAndSpies();\n\t\tassertThat(this.configDataEnvironment).isNotNull();\n\t\tassertThat(this.postProcessor).isNotNull();\n\t\twillReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any());\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tthen(this.postProcessor).should()\n\t\t\t.getConfigDataEnvironment(any(),\n\t\t\t\t\tassertArg((resourceLoader) -> assertThat(resourceLoader).isInstanceOf(DefaultResourceLoader.class)),\n\t\t\t\t\tany());\n\t\tthen(this.configDataEnvironment).should().processAndApply();\n\t}\n\n\t@Test\n\tvoid postProcessEnvironmentWhenCustomLoaderUsesSpecifiedLoaderInstance() {\n\t\tsetupMocksAndSpies();\n\t\tassertThat(this.configDataEnvironment).isNotNull();\n\t\tassertThat(this.postProcessor).isNotNull();\n\t\tResourceLoader resourceLoader = mock(ResourceLoader.class);\n\t\tthis.application.setResourceLoader(resourceLoader);\n\t\twillReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any());\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tthen(this.postProcessor).should()\n\t\t\t.getConfigDataEnvironment(any(),\n\t\t\t\t\tassertArg((resourceLoaderB) -> assertThat(resourceLoaderB).isSameAs(resourceLoader)), any());\n\t\tthen(this.configDataEnvironment).should().processAndApply();\n\t}\n\n\t@Test\n\tvoid postProcessEnvironmentWhenHasAdditionalProfilesOnSpringApplicationUsesAdditionalProfiles() {\n\t\tsetupMocksAndSpies();\n\t\tassertThat(this.configDataEnvironment).isNotNull();\n\t\tassertThat(this.postProcessor).isNotNull();\n\t\tthis.application.setAdditionalProfiles(\"dev\");\n\t\twillReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any());\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tthen(this.postProcessor).should()\n\t\t\t.getConfigDataEnvironment(any(), any(),\n\t\t\t\t\tassertArg((additionalProperties) -> assertThat(additionalProperties).containsExactly(\"dev\")));\n\t\tthen(this.configDataEnvironment).should().processAndApply();\n\t}\n\n\t@Test\n\tvoid postProcessEnvironmentWhenNoActiveProfiles() {\n\t\tsetupMocksAndSpies();\n\t\tassertThat(this.configDataEnvironment).isNotNull();\n\t\tassertThat(this.postProcessor).isNotNull();\n\t\twillReturn(this.configDataEnvironment).given(this.postProcessor).getConfigDataEnvironment(any(), any(), any());\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tthen(this.postProcessor).should().getConfigDataEnvironment(any(), any(ResourceLoader.class), any());\n\t\tthen(this.configDataEnvironment).should().processAndApply();\n\t\tassertThat(this.environment.getActiveProfiles()).isEmpty();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"property=value\")\n\t@WithResource(name = \"application-dev.properties\", content = \"property=dev-value\")\n\tvoid applyToAppliesPostProcessing() {\n\t\tint before = this.environment.getPropertySources().size();\n\t\tTestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();\n\t\tConfigDataEnvironmentPostProcessor.applyTo(this.environment, null, null, Collections.singleton(\"dev\"),\n\t\t\t\tlistener);\n\t\tassertThat(this.environment.getPropertySources()).hasSizeGreaterThan(before);\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"dev\");\n\t\tassertThat(listener.getAddedPropertySources()).isNotEmpty();\n\t\tProfiles profiles = listener.getProfiles();\n\t\tassertThat(profiles).isNotNull();\n\t\tassertThat(profiles.getActive()).containsExactly(\"dev\");\n\t\tassertThat(listener.getAddedPropertySources().stream().anyMatch((added) -> hasDevProfile(added.getResource())))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=dev\n\t\t\tproperty=value\n\t\t\t#---\n\t\t\tspring.config.activate.on-profile=dev\n\t\t\tproperty=dev-value1\n\t\t\t\"\"\")\n\t@WithResource(name = \"application-dev.properties\", content = \"property=dev-value2\")\n\tvoid applyToCanOverrideConfigDataOptions() {\n\t\tConfigDataEnvironmentUpdateListener listener = new ConfigDataEnvironmentUpdateListener() {\n\n\t\t\t@Override\n\t\t\tpublic Options onConfigDataOptions(ConfigData configData, PropertySource<?> propertySource,\n\t\t\t\t\tOptions options) {\n\t\t\t\treturn options.with(ConfigData.Option.IGNORE_PROFILES);\n\t\t\t}\n\n\t\t};\n\t\tConfigDataEnvironmentPostProcessor.applyTo(this.environment, null, null, Collections.emptyList(), listener);\n\t\tassertThat(this.environment.getProperty(\"property\")).isEqualTo(\"value\");\n\t\tassertThat(this.environment.getActiveProfiles()).isEmpty();\n\t}\n\n\tprivate void setupMocksAndSpies() {\n\t\tthis.configDataEnvironment = mock(ConfigDataEnvironment.class);\n\t\tthis.postProcessor = spy(new ConfigDataEnvironmentPostProcessor(Supplier::get, new DefaultBootstrapContext()));\n\t}\n\n\tprivate boolean hasDevProfile(@Nullable ConfigDataResource resource) {\n\t\treturn (resource instanceof StandardConfigDataResource standardResource)\n\t\t\t\t&& \"dev\".equals(standardResource.getProfile());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestInfo;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.MockApplicationEnvironment;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.ImportPhase;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;\nimport org.springframework.boot.context.config.TestConfigDataEnvironmentUpdateListener.AddedPropertySource;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataEnvironment}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataEnvironmentTests {\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\tprivate final MockApplicationEnvironment environment = new MockApplicationEnvironment();\n\n\tprivate final ResourceLoader resourceLoader = new DefaultResourceLoader();\n\n\tprivate final Collection<String> additionalProfiles = Collections.emptyList();\n\n\tprivate final ConversionService conversionService = DefaultConversionService.getSharedInstance();\n\n\t@Test\n\tvoid createExposesEnvironmentBinderToConfigDataLocationResolvers() {\n\t\tthis.environment.setProperty(\"spring\", \"boot\");\n\t\tTestConfigDataEnvironment configDataEnvironment = new TestConfigDataEnvironment(this.logFactory,\n\t\t\t\tthis.bootstrapContext, this.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tBinder binder = configDataEnvironment.getConfigDataLocationResolversBinder();\n\t\tassertThat(binder).isNotNull();\n\t\tassertThat(binder.bind(\"spring\", String.class).get()).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid createCreatesContributorsBasedOnExistingSources() {\n\t\tMockPropertySource propertySource1 = new MockPropertySource(\"p1\");\n\t\tMockPropertySource propertySource2 = new MockPropertySource(\"p2\");\n\t\tMockPropertySource propertySource3 = new MockPropertySource(\"p3\");\n\t\tthis.environment.getPropertySources().addLast(propertySource1);\n\t\tthis.environment.getPropertySources().addLast(propertySource2);\n\t\tthis.environment.getPropertySources().addLast(propertySource3);\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tList<ConfigDataEnvironmentContributor> children = configDataEnvironment.getContributors()\n\t\t\t.getRoot()\n\t\t\t.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION);\n\t\tObject[] wrapped = children.stream()\n\t\t\t.filter((child) -> child.getKind() == Kind.EXISTING)\n\t\t\t.map(ConfigDataEnvironmentContributor::getPropertySource)\n\t\t\t.toArray();\n\t\tassertThat(wrapped[1]).isEqualTo(propertySource1);\n\t\tassertThat(wrapped[2]).isEqualTo(propertySource2);\n\t\tassertThat(wrapped[3]).isEqualTo(propertySource3);\n\t}\n\n\t@Test\n\tvoid createWhenHasDefaultPropertySourceMovesItToLastContributor() {\n\t\tMockPropertySource defaultPropertySource = new MockPropertySource(\"defaultProperties\");\n\t\tMockPropertySource propertySource1 = new MockPropertySource(\"p2\");\n\t\tMockPropertySource propertySource2 = new MockPropertySource(\"p3\");\n\t\tthis.environment.getPropertySources().addLast(defaultPropertySource);\n\t\tthis.environment.getPropertySources().addLast(propertySource1);\n\t\tthis.environment.getPropertySources().addLast(propertySource2);\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tList<ConfigDataEnvironmentContributor> children = configDataEnvironment.getContributors()\n\t\t\t.getRoot()\n\t\t\t.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION);\n\t\tObject[] wrapped = children.stream()\n\t\t\t.filter((child) -> child.getKind() == Kind.EXISTING)\n\t\t\t.map(ConfigDataEnvironmentContributor::getPropertySource)\n\t\t\t.toArray();\n\t\tassertThat(wrapped[1]).isEqualTo(propertySource1);\n\t\tassertThat(wrapped[2]).isEqualTo(propertySource2);\n\t\tassertThat(wrapped[3]).isEqualTo(defaultPropertySource);\n\t}\n\n\t@Test\n\tvoid createCreatesInitialImportContributorsInCorrectOrder() {\n\t\tthis.environment.setProperty(\"spring.config.location\", \"l1,l2\");\n\t\tthis.environment.setProperty(\"spring.config.additional-location\", \"a1,a2\");\n\t\tthis.environment.setProperty(\"spring.config.import\", \"i1,i2\");\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tList<ConfigDataEnvironmentContributor> children = configDataEnvironment.getContributors()\n\t\t\t.getRoot()\n\t\t\t.getChildren(ImportPhase.BEFORE_PROFILE_ACTIVATION);\n\t\tObject[] imports = children.stream()\n\t\t\t.filter((child) -> child.getKind() == Kind.INITIAL_IMPORT)\n\t\t\t.map(ConfigDataEnvironmentContributor::getImports)\n\t\t\t.map(Object::toString)\n\t\t\t.toArray();\n\t\tassertThat(imports).containsExactly(\"[i1, i2]\", \"[a2]\", \"[a1]\", \"[l2]\", \"[l1]\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring=boot\")\n\tvoid processAndApplyAddsImportedSourceToEnvironment() {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring=boot\n\t\t\t#---\n\t\t\tspring.config.activate.on-profile=missing\n\t\t\tother=value\n\t\t\tNo newline at end of file\n\t\t\t\"\"\")\n\tvoid processAndApplyOnlyAddsActiveContributors() {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(this.environment.getProperty(\"other\")).isNull();\n\t}\n\n\t@Test\n\tvoid processAndApplyMovesDefaultPropertySourceToLast(TestInfo info) {\n\t\tMockPropertySource defaultPropertySource = new MockPropertySource(\"defaultProperties\");\n\t\tthis.environment.getPropertySources().addFirst(defaultPropertySource);\n\t\tthis.environment.setProperty(\"spring.config.location\", getConfigLocation(info));\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tList<PropertySource<?>> sources = this.environment.getPropertySources().stream().toList();\n\t\tassertThat(sources.get(sources.size() - 1)).isSameAs(defaultPropertySource);\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.default=one,two,three\")\n\tvoid processAndApplySetsDefaultProfiles(TestInfo info) {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getDefaultProfiles()).containsExactly(\"one\", \"two\", \"three\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=one,two,three\")\n\tvoid processAndApplySetsActiveProfiles() {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"one\", \"two\", \"three\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\"\"\n\t\t\tspring.profiles.active=one,two,three\n\t\t\tspring.profiles.group.one=four,five\n\t\t\t\"\"\")\n\tvoid processAndApplySetsActiveProfilesAndProfileGroups() {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"one\", \"four\", \"five\", \"two\", \"three\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=test\")\n\tvoid processAndApplyDoesNotSetProfilesFromIgnoreProfilesContributors(TestInfo info) {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null) {\n\n\t\t\t@Override\n\t\t\tprotected ConfigDataEnvironmentContributors createContributors(\n\t\t\t\t\tList<ConfigDataEnvironmentContributor> contributors) {\n\t\t\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\t\t\tsource.put(\"spring.profiles.active\", \"ignore1\");\n\t\t\t\tsource.put(\"spring.profiles.include\", \"ignore2\");\n\t\t\t\tConfigData data = new ConfigData(Collections.singleton(new MapPropertySource(\"test\", source)),\n\t\t\t\t\t\tConfigData.Option.IGNORE_PROFILES);\n\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of(\"test\"),\n\t\t\t\t\t\tmock(ConfigDataResource.class), false, data, 0,\n\t\t\t\t\t\tConfigDataEnvironmentTests.this.conversionService, ConfigDataEnvironmentUpdateListener.NONE));\n\t\t\t\treturn super.createContributors(contributors);\n\t\t\t}\n\n\t\t};\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"include\", \"include[0]\" })\n\tvoid processAndApplyWhenHasProfileIncludeInProfileSpecificDocumentThrowsException(String property, TestInfo info) {\n\t\tthis.environment.setProperty(\"spring.config.location\", getConfigLocation(info));\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null) {\n\n\t\t\t@Override\n\t\t\tprotected ConfigDataEnvironmentContributors createContributors(\n\t\t\t\t\tList<ConfigDataEnvironmentContributor> contributors) {\n\t\t\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\t\t\tsource.put(\"spring.config.activate.on-profile\", \"activate\");\n\t\t\t\tsource.put(\"spring.profiles.\" + property, \"include\");\n\t\t\t\tConfigData data = new ConfigData(Collections.singleton(new MapPropertySource(\"test\", source)));\n\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of(\"test\"),\n\t\t\t\t\t\tmock(ConfigDataResource.class), false, data, 0,\n\t\t\t\t\t\tConfigDataEnvironmentTests.this.conversionService, ConfigDataEnvironmentUpdateListener.NONE));\n\t\t\t\treturn super.createContributors(contributors);\n\t\t\t}\n\n\t\t};\n\t\tassertThatExceptionOfType(InactiveConfigDataAccessException.class)\n\t\t\t.isThrownBy(configDataEnvironment::processAndApply);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"spring.profiles.include\", \"spring.profiles.include[0]\" })\n\tvoid processAndApplyIncludesProfilesFromSpringProfilesInclude(String property, TestInfo info) {\n\t\tthis.environment.setProperty(\"spring.config.location\", getConfigLocation(info));\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null) {\n\n\t\t\t@Override\n\t\t\tprotected ConfigDataEnvironmentContributors createContributors(\n\t\t\t\t\tList<ConfigDataEnvironmentContributor> contributors) {\n\t\t\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\t\t\tsource.put(property, \"included\");\n\t\t\t\tConfigData data = new ConfigData(Collections.singleton(new MapPropertySource(\"test\", source)));\n\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of(\"test\"),\n\t\t\t\t\t\tmock(ConfigDataResource.class), false, data, 0,\n\t\t\t\t\t\tConfigDataEnvironmentTests.this.conversionService, ConfigDataEnvironmentUpdateListener.NONE));\n\t\t\t\treturn super.createContributors(contributors);\n\t\t\t}\n\n\t\t};\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"included\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring=boot\")\n\tvoid processAndApplyDoesNotSetProfilesFromIgnoreProfilesContributorsWhenNoProfilesActive(TestInfo info) {\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null) {\n\n\t\t\t@Override\n\t\t\tprotected ConfigDataEnvironmentContributors createContributors(\n\t\t\t\t\tList<ConfigDataEnvironmentContributor> contributors) {\n\t\t\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\t\t\tsource.put(\"spring.profiles.active\", \"ignore1\");\n\t\t\t\tsource.put(\"spring.profiles.include\", \"ignore2\");\n\t\t\t\tConfigData data = new ConfigData(Collections.singleton(new MapPropertySource(\"test\", source)),\n\t\t\t\t\t\tConfigData.Option.IGNORE_PROFILES);\n\t\t\t\tcontributors.add(ConfigDataEnvironmentContributor.ofUnboundImport(ConfigDataLocation.of(\"test\"),\n\t\t\t\t\t\tmock(ConfigDataResource.class), false, data, 0,\n\t\t\t\t\t\tConfigDataEnvironmentTests.this.conversionService, ConfigDataEnvironmentUpdateListener.NONE));\n\t\t\t\treturn super.createContributors(contributors);\n\t\t\t}\n\n\t\t};\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getActiveProfiles()).isEmpty();\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid processAndApplyWhenHasInvalidPropertyThrowsException() {\n\t\tthis.environment.setProperty(\"spring.profiles\", \"a\");\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, null);\n\t\tassertThatExceptionOfType(InvalidConfigDataPropertyException.class)\n\t\t\t.isThrownBy(configDataEnvironment::processAndApply);\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom/config.properties\", content = \"spring=boot\")\n\tvoid processAndApplyWhenHasListenerCallsOnPropertySourceAdded(TestInfo info) {\n\t\tthis.environment.setProperty(\"spring.config.location\", \"classpath:custom/config.properties\");\n\t\tTestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, listener);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(listener.getAddedPropertySources()).hasSize(1);\n\t\tAddedPropertySource addedPropertySource = listener.getAddedPropertySources().get(0);\n\t\tassertThat(addedPropertySource.getPropertySource().getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(addedPropertySource.getLocation()).hasToString(\"classpath:custom/config.properties\");\n\t\tConfigDataResource resource = addedPropertySource.getResource();\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.toString()).contains(\"class path resource\").contains(\"custom/config.properties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.profiles.active=one,two,three\")\n\tvoid processAndApplyWhenHasListenerCallsOnSetProfiles(TestInfo info) {\n\t\tTestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, this.additionalProfiles, listener);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tProfiles profiles = listener.getProfiles();\n\t\tassertThat(profiles).isNotNull();\n\t\tassertThat(profiles.getActive()).containsExactly(\"one\", \"two\", \"three\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\t@WithResource(name = \"separate-class-loader-spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.context.config.ConfigDataLoader=\\\n\t\t\torg.springframework.boot.context.config.ConfigDataEnvironmentTests$SeparateClassLoaderConfigDataLoader\n\t\t\t\"\"\")\n\tvoid configDataLoadersAreLoadedUsingClassLoaderFromResourceLoader() {\n\t\tResourceLoader resourceLoader = mock(ResourceLoader.class);\n\t\tClassLoader classLoader = new ClassLoader(Thread.currentThread().getContextClassLoader()) {\n\n\t\t\t@Override\n\t\t\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t\t\tif (SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION.equals(name)) {\n\t\t\t\t\treturn super.getResources(\"separate-class-loader-spring.factories\");\n\t\t\t\t}\n\t\t\t\treturn super.getResources(name);\n\t\t\t}\n\n\t\t};\n\t\tgiven(resourceLoader.getClassLoader()).willReturn(classLoader);\n\t\tTestConfigDataEnvironment configDataEnvironment = new TestConfigDataEnvironment(this.logFactory,\n\t\t\t\tthis.bootstrapContext, this.environment, resourceLoader, this.additionalProfiles, null);\n\t\tassertThat(configDataEnvironment).extracting(\"loaders.loaders\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.extracting((item) -> (Class) item.getClass())\n\t\t\t.containsOnly(SeparateClassLoaderConfigDataLoader.class);\n\t}\n\n\t@Test // gh-49724\n\t@WithResource(name = \"application-local.properties\", content = \"test.property=classpath-local\")\n\tvoid processAndApplyWhenExternalFileConfigOverridesProfileSpecificClasspathConfig(@TempDir Path tempDir)\n\t\t\tthrows IOException {\n\t\tFiles.writeString(tempDir.resolve(\"application.properties\"), \"test.property=file-default\\n\");\n\t\tthis.environment.setProperty(\"spring.config.location\",\n\t\t\t\t\"optional:classpath:/,optional:file:\" + tempDir.toAbsolutePath() + \"/\");\n\t\tConfigDataEnvironment configDataEnvironment = new ConfigDataEnvironment(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.environment, this.resourceLoader, List.of(\"local\"), null);\n\t\tconfigDataEnvironment.processAndApply();\n\t\tassertThat(this.environment.getProperty(\"test.property\")).isEqualTo(\"file-default\");\n\t}\n\n\tprivate String getConfigLocation(TestInfo info) {\n\t\treturn \"optional:classpath:\" + info.getTestClass().get().getName().replace('.', '/') + \"-\"\n\t\t\t\t+ info.getTestMethod().get().getName() + \".properties\";\n\t}\n\n\tstatic class TestConfigDataEnvironment extends ConfigDataEnvironment {\n\n\t\tprivate @Nullable Binder configDataLocationResolversBinder;\n\n\t\tTestConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,\n\t\t\t\tConfigurableEnvironment environment, ResourceLoader resourceLoader,\n\t\t\t\tCollection<String> additionalProfiles,\n\t\t\t\t@Nullable ConfigDataEnvironmentUpdateListener environmentUpdateListener) {\n\t\t\tsuper(logFactory, bootstrapContext, environment, resourceLoader, additionalProfiles,\n\t\t\t\t\tenvironmentUpdateListener);\n\t\t}\n\n\t\t@Override\n\t\tprotected ConfigDataLocationResolvers createConfigDataLocationResolvers(DeferredLogFactory logFactory,\n\t\t\t\tConfigurableBootstrapContext bootstrapContext, Binder binder, ResourceLoader resourceLoader) {\n\t\t\tthis.configDataLocationResolversBinder = binder;\n\t\t\treturn super.createConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader);\n\t\t}\n\n\t\t@Nullable Binder getConfigDataLocationResolversBinder() {\n\t\t\treturn this.configDataLocationResolversBinder;\n\t\t}\n\n\t}\n\n\tstatic class SeparateClassLoaderConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {\n\n\t\t@Override\n\t\tpublic @Nullable ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource)\n\t\t\t\tthrows IOException, ConfigDataResourceNotFoundException {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataImporterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link ConfigDataImporter}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass ConfigDataImporterTests {\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigDataLocationResolvers resolvers;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigDataLoaders loaders;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Binder binder;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigDataLocationResolverContext locationResolverContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigDataLoaderContext loaderContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigDataActivationContext activationContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Profiles profiles;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tgiven(this.activationContext.getProfiles()).willReturn(this.profiles);\n\t}\n\n\t@Test\n\tvoid loadImportsResolvesAndLoadsLocations() throws Exception {\n\t\tConfigDataLocation location1 = ConfigDataLocation.of(\"test1\");\n\t\tConfigDataLocation location2 = ConfigDataLocation.of(\"test2\");\n\t\tTestResource resource1 = new TestResource(\"r1\");\n\t\tTestResource resource2 = new TestResource(\"r2\");\n\t\tConfigData configData1 = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigData configData2 = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tgiven(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles))\n\t\t\t.willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1, false)));\n\t\tgiven(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles))\n\t\t\t.willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2, false)));\n\t\tgiven(this.loaders.load(this.loaderContext, resource1)).willReturn(configData1);\n\t\tgiven(this.loaders.load(this.loaderContext, resource2)).willReturn(configData2);\n\t\tConfigDataImporter importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL,\n\t\t\t\tthis.resolvers, this.loaders);\n\t\tCollection<ConfigData> loaded = importer\n\t\t\t.resolveAndLoad(this.activationContext, this.locationResolverContext, this.loaderContext,\n\t\t\t\t\tArrays.asList(location1, location2))\n\t\t\t.values();\n\t\tassertThat(loaded).containsExactly(configData2, configData1);\n\t}\n\n\t@Test\n\tvoid loadImportsWhenAlreadyImportedLocationSkipsLoad() throws Exception {\n\t\tConfigDataLocation location1 = ConfigDataLocation.of(\"test1\");\n\t\tConfigDataLocation location2 = ConfigDataLocation.of(\"test2\");\n\t\tConfigDataLocation location3 = ConfigDataLocation.of(\"test3\");\n\t\tList<ConfigDataLocation> locations1and2 = Arrays.asList(location1, location2);\n\t\tList<ConfigDataLocation> locations2and3 = Arrays.asList(location2, location3);\n\t\tTestResource resource1 = new TestResource(\"r1\");\n\t\tTestResource resource2 = new TestResource(\"r2\");\n\t\tTestResource resource3 = new TestResource(\"r3\");\n\t\tConfigData configData1 = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigData configData2 = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tConfigData configData3 = new ConfigData(Collections.singleton(new MockPropertySource()));\n\t\tgiven(this.resolvers.resolve(this.locationResolverContext, location1, this.profiles))\n\t\t\t.willReturn(Collections.singletonList(new ConfigDataResolutionResult(location1, resource1, false)));\n\t\tgiven(this.resolvers.resolve(this.locationResolverContext, location2, this.profiles))\n\t\t\t.willReturn(Collections.singletonList(new ConfigDataResolutionResult(location2, resource2, false)));\n\t\tgiven(this.resolvers.resolve(this.locationResolverContext, location3, this.profiles))\n\t\t\t.willReturn(Collections.singletonList(new ConfigDataResolutionResult(location3, resource3, false)));\n\t\tgiven(this.loaders.load(this.loaderContext, resource1)).willReturn(configData1);\n\t\tgiven(this.loaders.load(this.loaderContext, resource2)).willReturn(configData2);\n\t\tgiven(this.loaders.load(this.loaderContext, resource3)).willReturn(configData3);\n\t\tConfigDataImporter importer = new ConfigDataImporter(this.logFactory, ConfigDataNotFoundAction.FAIL,\n\t\t\t\tthis.resolvers, this.loaders);\n\t\tCollection<ConfigData> loaded1and2 = importer\n\t\t\t.resolveAndLoad(this.activationContext, this.locationResolverContext, this.loaderContext, locations1and2)\n\t\t\t.values();\n\t\tCollection<ConfigData> loaded2and3 = importer\n\t\t\t.resolveAndLoad(this.activationContext, this.locationResolverContext, this.loaderContext, locations2and3)\n\t\t\t.values();\n\t\tassertThat(loaded1and2).containsExactly(configData2, configData1);\n\t\tassertThat(loaded2and3).containsExactly(configData3);\n\t}\n\n\tstatic class TestResource extends ConfigDataResource {\n\n\t\tprivate final String name;\n\n\t\tTestResource(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataLoader}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataLoaderTests {\n\n\tprivate final TestConfigDataLoader loader = new TestConfigDataLoader();\n\n\tprivate final ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class);\n\n\t@Test\n\tvoid isLoadableAlwaysReturnsTrue() {\n\t\tassertThat(this.loader.isLoadable(this.context, new TestConfigDataResource())).isTrue();\n\t}\n\n\tstatic class TestConfigDataLoader implements ConfigDataLoader<TestConfigDataResource> {\n\n\t\t@Override\n\t\tpublic @Nullable ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource resource)\n\t\t\t\tthrows IOException {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class TestConfigDataResource extends ConfigDataResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLoadersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.test.io.support.MockSpringFactoriesLoader;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataLoaders}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataLoadersTests {\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\tprivate final ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class);\n\n\t@Test\n\tvoid createWhenLoaderHasDeferredLogFactoryParameterInjectsDeferredLogFactory() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, DeferredLogFactoryConfigDataLoader.class);\n\t\tConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,\n\t\t\t\tspringFactoriesLoader);\n\t\tassertThat(loaders).extracting(\"loaders\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.satisfies(this::containsValidDeferredLogFactoryConfigDataLoader);\n\t}\n\n\tprivate void containsValidDeferredLogFactoryConfigDataLoader(List<?> list) {\n\t\tassertThat(list).hasSize(1);\n\t\tDeferredLogFactoryConfigDataLoader loader = (DeferredLogFactoryConfigDataLoader) list.get(0);\n\t\tassertThat(loader.getLogFactory()).isSameAs(this.logFactory);\n\t}\n\n\t@Test\n\tvoid createWhenLoaderHasLogParameterThrowsException() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, LogConfigDataLoader.class);\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ConfigDataLoaders(this.logFactory, this.bootstrapContext, springFactoriesLoader))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(IllegalArgumentException.class)\n\t\t\t.withMessageContaining(\"use DeferredLogFactory\");\n\t}\n\n\t@Test\n\tvoid createWhenLoaderHasBootstrapParametersInjectsBootstrapContext() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, BootstrappingConfigDataLoader.class);\n\t\tnew ConfigDataLoaders(this.logFactory, this.bootstrapContext, springFactoriesLoader);\n\t\tassertThat(this.bootstrapContext.get(String.class)).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid loadWhenSingleLoaderSupportsLocationReturnsLoadedConfigData() throws Exception {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, TestConfigDataLoader.class);\n\t\tConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,\n\t\t\t\tspringFactoriesLoader);\n\t\tTestConfigDataResource location = new TestConfigDataResource(\"test\");\n\t\tConfigData loaded = loaders.load(this.context, location);\n\t\tassertThat(loaded).isNotNull();\n\t\tassertThat(getLoader(loaded)).isInstanceOf(TestConfigDataLoader.class);\n\t}\n\n\t@Test\n\tvoid loadWhenMultipleLoadersSupportLocationThrowsException() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, AnotherConfigDataLoader.class, TestConfigDataLoader.class);\n\t\tConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,\n\t\t\t\tspringFactoriesLoader);\n\t\tTestConfigDataResource location = new TestConfigDataResource(\"test\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> loaders.load(this.context, location))\n\t\t\t.withMessageContaining(\"Multiple loaders found for resource 'test'\");\n\t}\n\n\t@Test\n\tvoid loadWhenNoLoaderSupportsLocationThrowsException() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, NonLoadableConfigDataLoader.class);\n\t\tConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,\n\t\t\t\tspringFactoriesLoader);\n\t\tTestConfigDataResource location = new TestConfigDataResource(\"test\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> loaders.load(this.context, location))\n\t\t\t.withMessage(\"No loader found for resource 'test'\");\n\t}\n\n\t@Test\n\tvoid loadWhenGenericTypeDoesNotMatchSkipsLoader() throws Exception {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLoader.class, OtherConfigDataLoader.class, SpecificConfigDataLoader.class);\n\t\tConfigDataLoaders loaders = new ConfigDataLoaders(this.logFactory, this.bootstrapContext,\n\t\t\t\tspringFactoriesLoader);\n\t\tTestConfigDataResource location = new TestConfigDataResource(\"test\");\n\t\tConfigData loaded = loaders.load(this.context, location);\n\t\tassertThat(loaded).isNotNull();\n\t\tassertThat(getLoader(loaded)).isInstanceOf(SpecificConfigDataLoader.class);\n\t}\n\n\tprivate ConfigDataLoader<?> getLoader(ConfigData loaded) {\n\t\tConfigDataLoader<?> result = (ConfigDataLoader<?>) loaded.getPropertySources().get(0).getProperty(\"loader\");\n\t\tassertThat(result).isNotNull();\n\t\treturn result;\n\t}\n\n\tprivate static ConfigData createConfigData(ConfigDataLoader<?> loader, ConfigDataResource resource) {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"loader\", loader);\n\t\tpropertySource.setProperty(\"resource\", resource);\n\t\tList<PropertySource<?>> propertySources = Arrays.asList(propertySource);\n\t\treturn new ConfigData(propertySources);\n\t}\n\n\tstatic class TestConfigDataResource extends ConfigDataResource {\n\n\t\tprivate final String value;\n\n\t\tTestConfigDataResource(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\tstatic class OtherConfigDataResource extends ConfigDataResource {\n\n\t}\n\n\tstatic class DeferredLogFactoryConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {\n\n\t\tprivate final DeferredLogFactory logFactory;\n\n\t\tDeferredLogFactoryConfigDataLoader(DeferredLogFactory logFactory) {\n\t\t\tassertThat(logFactory).isNotNull();\n\t\t\tthis.logFactory = logFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {\n\t\t\tthrow new AssertionError(\"Unexpected call\");\n\t\t}\n\n\t\tDeferredLogFactory getLogFactory() {\n\t\t\treturn this.logFactory;\n\t\t}\n\n\t}\n\n\tstatic class LogConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {\n\n\t\tfinal Log logger;\n\n\t\tLogConfigDataLoader(Log logger) {\n\t\t\tthis.logger = logger;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {\n\t\t\tthrow new AssertionError(\"Unexpected call\");\n\t\t}\n\n\t}\n\n\tstatic class BootstrappingConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {\n\n\t\tBootstrappingConfigDataLoader(ConfigurableBootstrapContext configurableBootstrapContext,\n\t\t\t\tBootstrapRegistry bootstrapRegistry, BootstrapContext bootstrapContext) {\n\t\t\tassertThat(configurableBootstrapContext).isNotNull();\n\t\t\tassertThat(bootstrapRegistry).isNotNull();\n\t\t\tassertThat(bootstrapContext).isNotNull();\n\t\t\tassertThat(configurableBootstrapContext).isEqualTo(bootstrapRegistry).isEqualTo(bootstrapContext);\n\t\t\tbootstrapRegistry.register(String.class, InstanceSupplier.of(\"boot\"));\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {\n\t\t\tthrow new AssertionError(\"Unexpected call\");\n\t\t}\n\n\t}\n\n\tstatic class TestConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {\n\t\t\treturn createConfigData(this, resource);\n\t\t}\n\n\t}\n\n\tstatic class AnotherConfigDataLoader implements ConfigDataLoader<ConfigDataResource> {\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, ConfigDataResource resource) throws IOException {\n\t\t\treturn createConfigData(this, resource);\n\t\t}\n\n\t}\n\n\tstatic class NonLoadableConfigDataLoader extends TestConfigDataLoader {\n\n\t\t@Override\n\t\tpublic boolean isLoadable(ConfigDataLoaderContext context, ConfigDataResource resource) {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\tstatic class SpecificConfigDataLoader implements ConfigDataLoader<TestConfigDataResource> {\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, TestConfigDataResource location) throws IOException {\n\t\t\treturn createConfigData(this, location);\n\t\t}\n\n\t}\n\n\tstatic class OtherConfigDataLoader implements ConfigDataLoader<OtherConfigDataResource> {\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, OtherConfigDataResource location) throws IOException {\n\t\t\treturn createConfigData(this, location);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationBindHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataLocationBindHandler}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ConfigDataLocationBindHandlerTests {\n\n\tprivate static final Bindable<ConfigDataLocation[]> ARRAY = Bindable.of(ConfigDataLocation[].class);\n\n\tprivate static final Bindable<ValueObject> VALUE_OBJECT = Bindable.of(ValueObject.class);\n\n\tprivate final ConfigDataLocationBindHandler handler = new ConfigDataLocationBindHandler();\n\n\t@Test\n\tvoid bindToArrayFromCommaStringPropertySetsOrigin() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"locations\", \"a,b,c\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataLocation[] bound = binder.bind(\"locations\", ARRAY, this.handler).get();\n\t\tString expectedLocation = \"\\\"locations\\\" from property source \\\"source\\\"\";\n\t\tassertThat(bound[0]).hasToString(\"a\");\n\t\tassertThat(bound[0].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[1]).hasToString(\"b\");\n\t\tassertThat(bound[1].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[2]).hasToString(\"c\");\n\t\tassertThat(bound[2].getOrigin()).hasToString(expectedLocation);\n\t}\n\n\t@Test\n\tvoid bindToArrayFromCommaStringPropertyDoesNotFailOnEmptyElements() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"locations\", \",a,,b,c,\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataLocation[] bound = binder.bind(\"locations\", ARRAY, this.handler).get();\n\t\tString expectedLocation = \"\\\"locations\\\" from property source \\\"source\\\"\";\n\t\tassertThat(bound[0]).hasToString(\"\");\n\t\tassertThat(bound[0].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[1]).hasToString(\"a\");\n\t\tassertThat(bound[1].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[2]).hasToString(\"\");\n\t\tassertThat(bound[2].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[3]).hasToString(\"b\");\n\t\tassertThat(bound[3].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[4]).hasToString(\"c\");\n\t\tassertThat(bound[4].getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound[5]).hasToString(\"\");\n\t\tassertThat(bound[5].getOrigin()).hasToString(expectedLocation);\n\t}\n\n\t@Test\n\tvoid bindToArrayFromIndexedPropertiesSetsOrigin() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"locations[0]\", \"a\");\n\t\tsource.put(\"locations[1]\", \"b\");\n\t\tsource.put(\"locations[2]\", \"c\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataLocation[] bound = binder.bind(\"locations\", ARRAY, this.handler).get();\n\t\tassertThat(bound[0]).hasToString(\"a\");\n\t\tassertThat(bound[0].getOrigin()).hasToString(\"\\\"locations[0]\\\" from property source \\\"source\\\"\");\n\t\tassertThat(bound[1]).hasToString(\"b\");\n\t\tassertThat(bound[1].getOrigin()).hasToString(\"\\\"locations[1]\\\" from property source \\\"source\\\"\");\n\t\tassertThat(bound[2]).hasToString(\"c\");\n\t\tassertThat(bound[2].getOrigin()).hasToString(\"\\\"locations[2]\\\" from property source \\\"source\\\"\");\n\t}\n\n\t@Test\n\tvoid bindToValueObjectFromCommaStringPropertySetsOrigin() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"test.locations\", \"a,b,c\");\n\t\tBinder binder = new Binder(source);\n\t\tValueObject bound = binder.bind(\"test\", VALUE_OBJECT, this.handler).get();\n\t\tString expectedLocation = \"\\\"test.locations\\\" from property source \\\"source\\\"\";\n\t\tassertThat(bound.getLocation(0)).hasToString(\"a\");\n\t\tassertThat(bound.getLocation(0).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(1)).hasToString(\"b\");\n\t\tassertThat(bound.getLocation(1).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(2)).hasToString(\"c\");\n\t\tassertThat(bound.getLocation(2).getOrigin()).hasToString(expectedLocation);\n\t}\n\n\t@Test\n\tvoid bindToValueObjectFromCommaStringPropertyDoesNotFailOnEmptyElements() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"test.locations\", \",a,b,,c,\");\n\t\tBinder binder = new Binder(source);\n\t\tValueObject bound = binder.bind(\"test\", VALUE_OBJECT, this.handler).get();\n\t\tString expectedLocation = \"\\\"test.locations\\\" from property source \\\"source\\\"\";\n\t\tassertThat(bound.getLocation(0)).hasToString(\"\");\n\t\tassertThat(bound.getLocation(0).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(1)).hasToString(\"a\");\n\t\tassertThat(bound.getLocation(1).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(2)).hasToString(\"b\");\n\t\tassertThat(bound.getLocation(2).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(3)).hasToString(\"\");\n\t\tassertThat(bound.getLocation(3).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(4)).hasToString(\"c\");\n\t\tassertThat(bound.getLocation(4).getOrigin()).hasToString(expectedLocation);\n\t\tassertThat(bound.getLocation(5)).hasToString(\"\");\n\t\tassertThat(bound.getLocation(5).getOrigin()).hasToString(expectedLocation);\n\t}\n\n\t@Test\n\tvoid bindToValueObjectFromIndexedPropertiesSetsOrigin() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"test.locations[0]\", \"a\");\n\t\tsource.put(\"test.locations[1]\", \"b\");\n\t\tsource.put(\"test.locations[2]\", \"c\");\n\t\tBinder binder = new Binder(source);\n\t\tValueObject bound = binder.bind(\"test\", VALUE_OBJECT, this.handler).get();\n\t\tassertThat(bound.getLocation(0)).hasToString(\"a\");\n\t\tassertThat(bound.getLocation(0).getOrigin())\n\t\t\t.hasToString(\"\\\"test.locations[0]\\\" from property source \\\"source\\\"\");\n\t\tassertThat(bound.getLocation(1)).hasToString(\"b\");\n\t\tassertThat(bound.getLocation(1).getOrigin())\n\t\t\t.hasToString(\"\\\"test.locations[1]\\\" from property source \\\"source\\\"\");\n\t\tassertThat(bound.getLocation(2)).hasToString(\"c\");\n\t\tassertThat(bound.getLocation(2).getOrigin())\n\t\t\t.hasToString(\"\\\"test.locations[2]\\\" from property source \\\"source\\\"\");\n\t}\n\n\tstatic class ValueObject {\n\n\t\tprivate final List<ConfigDataLocation> locations;\n\n\t\tValueObject(List<ConfigDataLocation> locations) {\n\t\t\tthis.locations = locations;\n\t\t}\n\n\t\tConfigDataLocation getLocation(int index) {\n\t\t\treturn this.locations.get(index);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationNotFoundExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.Origin;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataLocationNotFoundException}.\n *\n * @author Phillip Webb\n */\nclass ConfigDataLocationNotFoundExceptionTests {\n\n\tprivate final Origin origin = mock(Origin.class);\n\n\tprivate final ConfigDataLocation location = ConfigDataLocation.of(\"optional:test\").withOrigin(this.origin);\n\n\tprivate final ConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(\n\t\t\tthis.location);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenLocationIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigDataLocationNotFoundException(null))\n\t\t\t.withMessage(\"'location' must not be null\");\n\t}\n\n\t@Test\n\tvoid getLocationReturnsLocation() {\n\t\tassertThat(this.exception.getLocation()).isSameAs(this.location);\n\t}\n\n\t@Test\n\tvoid getOriginReturnsLocationOrigin() {\n\t\tassertThat(this.exception.getOrigin()).isSameAs(this.origin);\n\t}\n\n\t@Test\n\tvoid getReferenceDescriptionReturnsLocationString() {\n\t\tassertThat(this.exception.getReferenceDescription()).isEqualTo(\"location 'optional:test'\");\n\t}\n\n\t@Test\n\tvoid getMessageReturnsMessage() {\n\t\tassertThat(this.exception).hasMessage(\"Config data location 'optional:test' cannot be found\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataLocationResolver}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataLocationResolverTests {\n\n\tprivate final ConfigDataLocationResolver<?> resolver = new TestConfigDataLocationResolver();\n\n\tprivate final ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class);\n\n\t@Test\n\tvoid resolveProfileSpecificReturnsEmptyList() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"location\");\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tProfiles profiles = new Profiles(environment, Binder.get(environment), null);\n\t\tassertThat(this.resolver.resolveProfileSpecific(this.context, location, profiles)).isEmpty();\n\t}\n\n\tstatic class TestConfigDataLocationResolver implements ConfigDataLocationResolver<ConfigDataResource> {\n\n\t\t@Override\n\t\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<ConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\t\tConfigDataLocation location) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationResolversTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.test.io.support.MockSpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ConfigDataLocationResolvers}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass ConfigDataLocationResolversTests {\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Binder binder;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigDataLocationResolverContext context;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Profiles profiles;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File tempDir;\n\n\t@Test\n\tvoid createWhenInjectingDeferredLogFactoryCreatesResolver() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, TestLogResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tassertThat(resolvers.getResolvers()).hasSize(1);\n\t\tassertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(TestLogResolver.class);\n\t\tTestLogResolver resolver = (TestLogResolver) resolvers.getResolvers().get(0);\n\t\tassertThat(resolver.getDeferredLogFactory()).isSameAs(this.logFactory);\n\t}\n\n\t@Test\n\tvoid createWhenInjectingBinderCreatesResolver() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, TestBoundResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tassertThat(resolvers.getResolvers()).hasSize(1);\n\t\tassertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(TestBoundResolver.class);\n\t\tassertThat(((TestBoundResolver) resolvers.getResolvers().get(0)).getBinder()).isSameAs(this.binder);\n\t}\n\n\t@Test\n\tvoid createWhenNotInjectingBinderCreatesResolver() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, TestResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tassertThat(resolvers.getResolvers()).hasSize(1);\n\t\tassertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(TestResolver.class);\n\t}\n\n\t@Test\n\tvoid createWhenResolverHasBootstrapParametersInjectsBootstrapContext() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, TestBootstrappingResolver.class);\n\t\tnew ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext, this.binder,\n\t\t\t\tnew DefaultResourceLoader(), springFactoriesLoader);\n\t\tassertThat(this.bootstrapContext.get(String.class)).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid createOrdersResolvers() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, TestResolver.class, LowestTestResolver.class,\n\t\t\t\tHighestTestResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tassertThat(resolvers.getResolvers().get(0)).isExactlyInstanceOf(HighestTestResolver.class);\n\t\tassertThat(resolvers.getResolvers().get(1)).isExactlyInstanceOf(TestResolver.class);\n\t\tassertThat(resolvers.getResolvers().get(2)).isExactlyInstanceOf(LowestTestResolver.class);\n\t}\n\n\t@Test\n\tvoid resolveResolvesUsingFirstSupportedResolver() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, LowestTestResolver.class,\n\t\t\t\tHighestTestResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"LowestTestResolver:test\");\n\t\tList<ConfigDataResolutionResult> resolved = resolvers.resolve(this.context, location, null);\n\t\tassertThat(resolved).hasSize(1);\n\t\tTestConfigDataResource resource = (TestConfigDataResource) resolved.get(0).getResource();\n\t\tassertThat(resource.getResolver()).isInstanceOf(LowestTestResolver.class);\n\t\tassertThat(resource.getLocation()).isEqualTo(location);\n\t\tassertThat(resource.isProfileSpecific()).isFalse();\n\t}\n\n\t@Test\n\tvoid resolveWhenProfileMergesResolvedLocations() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, LowestTestResolver.class,\n\t\t\t\tHighestTestResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"LowestTestResolver:test\");\n\t\tList<ConfigDataResolutionResult> resolved = resolvers.resolve(this.context, location, this.profiles);\n\t\tassertThat(resolved).hasSize(2);\n\t\tTestConfigDataResource resource = (TestConfigDataResource) resolved.get(0).getResource();\n\t\tassertThat(resource.getResolver()).isInstanceOf(LowestTestResolver.class);\n\t\tassertThat(resource.getLocation()).isEqualTo(location);\n\t\tassertThat(resource.isProfileSpecific()).isFalse();\n\t\tTestConfigDataResource profileResource = (TestConfigDataResource) resolved.get(1).getResource();\n\t\tassertThat(profileResource.getResolver()).isInstanceOf(LowestTestResolver.class);\n\t\tassertThat(profileResource.getLocation()).isEqualTo(location);\n\t\tassertThat(profileResource.isProfileSpecific()).isTrue();\n\t}\n\n\t@Test\n\tvoid resolveWhenNoResolverThrowsException() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, LowestTestResolver.class,\n\t\t\t\tHighestTestResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"Missing:test\");\n\t\tassertThatExceptionOfType(UnsupportedConfigDataLocationException.class)\n\t\t\t.isThrownBy(() -> resolvers.resolve(this.context, location, null))\n\t\t\t.satisfies((ex) -> assertThat(ex.getLocation()).isEqualTo(location));\n\t}\n\n\t@Test\n\tvoid resolveWhenOptional() {\n\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\tspringFactoriesLoader.add(ConfigDataLocationResolver.class, OptionalResourceTestResolver.class);\n\t\tConfigDataLocationResolvers resolvers = new ConfigDataLocationResolvers(this.logFactory, this.bootstrapContext,\n\t\t\t\tthis.binder, new DefaultResourceLoader(), springFactoriesLoader);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"OptionalResourceTestResolver:test\");\n\t\tList<ConfigDataResolutionResult> resolved = resolvers.resolve(this.context, location, null);\n\t\tassertThat(resolved.get(0).getResource().isOptional()).isTrue();\n\t}\n\n\tstatic class TestResolver implements ConfigDataLocationResolver<TestConfigDataResource> {\n\n\t\tprivate final boolean optionalResource;\n\n\t\tTestResolver() {\n\t\t\tthis(false);\n\t\t}\n\n\t\tprivate TestResolver(boolean optionalResource) {\n\t\t\tthis.optionalResource = optionalResource;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\tString name = getClass().getName();\n\t\t\tname = name.substring(name.lastIndexOf(\"$\") + 1);\n\t\t\treturn location.hasPrefix(name + \":\");\n\t\t}\n\n\t\t@Override\n\t\tpublic List<TestConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\t\tConfigDataLocation location) {\n\t\t\treturn Collections.singletonList(new TestConfigDataResource(this.optionalResource, this, location, false));\n\t\t}\n\n\t\t@Override\n\t\tpublic List<TestConfigDataResource> resolveProfileSpecific(ConfigDataLocationResolverContext context,\n\t\t\t\tConfigDataLocation location, Profiles profiles) {\n\t\t\treturn Collections.singletonList(new TestConfigDataResource(this.optionalResource, this, location, true));\n\t\t}\n\n\t}\n\n\tstatic class TestLogResolver extends TestResolver {\n\n\t\tprivate final DeferredLogFactory deferredLogFactory;\n\n\t\tTestLogResolver(DeferredLogFactory deferredLogFactory) {\n\t\t\tthis.deferredLogFactory = deferredLogFactory;\n\t\t}\n\n\t\tDeferredLogFactory getDeferredLogFactory() {\n\t\t\treturn this.deferredLogFactory;\n\t\t}\n\n\t}\n\n\tstatic class TestBoundResolver extends TestResolver {\n\n\t\tprivate final Binder binder;\n\n\t\tTestBoundResolver(Binder binder) {\n\t\t\tthis.binder = binder;\n\t\t}\n\n\t\tBinder getBinder() {\n\t\t\treturn this.binder;\n\t\t}\n\n\t}\n\n\tstatic class TestBootstrappingResolver extends TestResolver {\n\n\t\tTestBootstrappingResolver(ConfigurableBootstrapContext configurableBootstrapContext,\n\t\t\t\tBootstrapRegistry bootstrapRegistry, BootstrapContext bootstrapContext) {\n\t\t\tassertThat(configurableBootstrapContext).isNotNull();\n\t\t\tassertThat(bootstrapRegistry).isNotNull();\n\t\t\tassertThat(bootstrapContext).isNotNull();\n\t\t\tassertThat(configurableBootstrapContext).isEqualTo(bootstrapRegistry).isEqualTo(bootstrapContext);\n\t\t\tbootstrapRegistry.register(String.class, InstanceSupplier.of(\"boot\"));\n\t\t}\n\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic class HighestTestResolver extends TestResolver {\n\n\t}\n\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class LowestTestResolver extends TestResolver {\n\n\t}\n\n\tstatic class OptionalResourceTestResolver extends TestResolver {\n\n\t\tOptionalResourceTestResolver() {\n\t\t\tsuper(true);\n\t\t}\n\n\t}\n\n\tstatic class TestConfigDataResource extends ConfigDataResource {\n\n\t\tprivate final TestResolver resolver;\n\n\t\tprivate final ConfigDataLocation location;\n\n\t\tprivate final boolean profileSpecific;\n\n\t\tTestConfigDataResource(boolean optional, TestResolver resolver, ConfigDataLocation location,\n\t\t\t\tboolean profileSpecific) {\n\t\t\tsuper(optional);\n\t\t\tthis.resolver = resolver;\n\t\t\tthis.location = location;\n\t\t\tthis.profileSpecific = profileSpecific;\n\t\t}\n\n\t\tTestResolver getResolver() {\n\t\t\treturn this.resolver;\n\t\t}\n\n\t\tConfigDataLocation getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\tboolean isProfileSpecific() {\n\t\t\treturn this.profileSpecific;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.ResourcePatternHint;\nimport org.springframework.aot.hint.ResourcePatternHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.test.io.support.MockSpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataLocationRuntimeHints}.\n *\n * @author Stephane Nicoll\n */\nclass ConfigDataLocationRuntimeHintsTests {\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"\")\n\t@WithResource(name = \"config/application.properties\", content = \"\")\n\tvoid registerWithDefaultSettings() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew TestConfigDataLocationRuntimeHints().registerHints(hints, Thread.currentThread().getContextClassLoader());\n\t\tassertThat(hints.resources().resourcePatternHints()).singleElement()\n\t\t\t.satisfies(includes(\"application*.properties\", \"application*.xml\", \"application*.yaml\", \"application*.yml\",\n\t\t\t\t\t\"config/application*.properties\", \"config/application*.xml\", \"config/application*.yaml\",\n\t\t\t\t\t\"config/application*.yml\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.properties\")\n\t@WithResource(name = \"config/test.properties\")\n\tvoid registerWithCustomName() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew TestConfigDataLocationRuntimeHints() {\n\t\t\t@Override\n\t\t\tprotected List<String> getFileNames(@Nullable ClassLoader classLoader) {\n\t\t\t\treturn List.of(\"test\");\n\t\t\t}\n\n\t\t}.registerHints(hints, Thread.currentThread().getContextClassLoader());\n\t\tassertThat(hints.resources().resourcePatternHints()).singleElement()\n\t\t\t.satisfies(includes(\"test*.properties\", \"test*.xml\", \"test*.yaml\", \"test*.yml\", \"config/test*.properties\",\n\t\t\t\t\t\"config/test*.xml\", \"config/test*.yaml\", \"config/test*.yml\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\")\n\t@WithResource(name = \"config/application.properties\")\n\tvoid registerWithCustomLocation() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew TestConfigDataLocationRuntimeHints() {\n\t\t\t@Override\n\t\t\tprotected List<String> getLocations(@Nullable ClassLoader classLoader) {\n\t\t\t\treturn List.of(\"config/\");\n\t\t\t}\n\t\t}.registerHints(hints, Thread.currentThread().getContextClassLoader());\n\t\tassertThat(hints.resources().resourcePatternHints()).singleElement()\n\t\t\t.satisfies(includes(\"config/application*.properties\", \"config/application*.xml\", \"config/application*.yaml\",\n\t\t\t\t\t\"config/application*.yml\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.conf\")\n\t@WithResource(name = \"config/application.conf\")\n\tvoid registerWithCustomExtension() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ConfigDataLocationRuntimeHints() {\n\t\t\t@Override\n\t\t\tprotected List<String> getExtensions(@Nullable ClassLoader classLoader) {\n\t\t\t\treturn List.of(\".conf\");\n\t\t\t}\n\t\t}.registerHints(hints, Thread.currentThread().getContextClassLoader());\n\t\tassertThat(hints.resources().resourcePatternHints()).singleElement()\n\t\t\t.satisfies(includes(\"application*.conf\", \"config/application*.conf\"));\n\t}\n\n\t@Test\n\tvoid registerWithUnknownLocationDoesNotAddHint() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ConfigDataLocationRuntimeHints() {\n\t\t\t@Override\n\t\t\tprotected List<String> getLocations(@Nullable ClassLoader classLoader) {\n\t\t\t\treturn List.of(UUID.randomUUID().toString());\n\t\t\t}\n\t\t}.registerHints(hints, Thread.currentThread().getContextClassLoader());\n\t\tassertThat(hints.resources().resourcePatternHints()).isEmpty();\n\t}\n\n\tprivate Consumer<ResourcePatternHints> includes(String... patterns) {\n\t\treturn (hint) -> assertThat(hint.getIncludes().stream().map(ResourcePatternHint::getPattern))\n\t\t\t.contains(patterns);\n\t}\n\n\tstatic class TestConfigDataLocationRuntimeHints extends ConfigDataLocationRuntimeHints {\n\n\t\tprivate final MockSpringFactoriesLoader springFactoriesLoader;\n\n\t\tTestConfigDataLocationRuntimeHints(MockSpringFactoriesLoader springFactoriesLoader) {\n\t\t\tthis.springFactoriesLoader = springFactoriesLoader;\n\t\t}\n\n\t\tTestConfigDataLocationRuntimeHints() {\n\t\t\tthis(springFactoriesLoader());\n\t\t}\n\n\t\tprivate static MockSpringFactoriesLoader springFactoriesLoader() {\n\t\t\tMockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader();\n\t\t\tspringFactoriesLoader.add(PropertySourceLoader.class, PropertiesPropertySourceLoader.class,\n\t\t\t\t\tYamlPropertySourceLoader.class);\n\t\t\treturn springFactoriesLoader;\n\t\t}\n\n\t\t@Override\n\t\tprotected SpringFactoriesLoader getSpringFactoriesLoader(@Nullable ClassLoader classLoader) {\n\t\t\treturn this.springFactoriesLoader;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataLocationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.Origin;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigDataLocation}.\n *\n * @author Phillip Webb\n */\nclass ConfigDataLocationTests {\n\n\t@Test\n\tvoid isOptionalWhenNotPrefixedWithOptionalReturnsFalse() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tassertThat(location.isOptional()).isFalse();\n\t}\n\n\t@Test\n\tvoid isOptionalWhenPrefixedWithOptionalReturnsTrue() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:test\");\n\t\tassertThat(location.isOptional()).isTrue();\n\t}\n\n\t@Test\n\tvoid getValueWhenNotPrefixedWithOptionalReturnsValue() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tassertThat(location.getValue()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getValueWhenPrefixedWithOptionalReturnsValueWithoutPrefix() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:test\");\n\t\tassertThat(location.getValue()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid hasPrefixWhenPrefixedReturnsTrue() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:test:path\");\n\t\tassertThat(location.hasPrefix(\"test:\")).isTrue();\n\t}\n\n\t@Test\n\tvoid hasPrefixWhenNotPrefixedReturnsFalse() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:file:path\");\n\t\tassertThat(location.hasPrefix(\"test:\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getNonPrefixedValueWhenPrefixedReturnsNonPrefixed() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:test:path\");\n\t\tassertThat(location.getNonPrefixedValue(\"test:\")).isEqualTo(\"path\");\n\t}\n\n\t@Test\n\tvoid getNonPrefixedValueWhenNotPrefixedReturnsOriginalValue() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:file:path\");\n\t\tassertThat(location.getNonPrefixedValue(\"test:\")).isEqualTo(\"file:path\");\n\t}\n\n\t@Test\n\tvoid getOriginWhenNoOriginReturnsNull() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tassertThat(location.getOrigin()).isNull();\n\t}\n\n\t@Test\n\tvoid getOriginWhenWithOriginReturnsOrigin() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\").withOrigin(origin);\n\t\tassertThat(location.getOrigin()).isSameAs(origin);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tConfigDataLocation l1 = ConfigDataLocation.of(\"a\");\n\t\tConfigDataLocation l2 = ConfigDataLocation.of(\"a\");\n\t\tConfigDataLocation l3 = ConfigDataLocation.of(\"optional:a\");\n\t\tConfigDataLocation l4 = ConfigDataLocation.of(\"b\");\n\t\tassertThat(l1).hasSameHashCodeAs(l2).hasSameHashCodeAs(l3);\n\t\tassertThat(l1).isEqualTo(l2).isEqualTo(l3).isNotEqualTo(l4);\n\t}\n\n\t@Test\n\tvoid toStringReturnsOriginalString() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:test\");\n\t\tassertThat(location).hasToString(\"optional:test\");\n\t}\n\n\t@Test\n\tvoid withOriginSetsOrigin() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\").withOrigin(origin);\n\t\tassertThat(location.getOrigin()).isSameAs(origin);\n\t}\n\n\t@Test\n\tvoid ofWhenNullValueReturnsEmptyLocation() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(null);\n\t\tassertThat(location.getValue().isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid ofWhenEmptyValueReturnsEmptyLocation() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"\");\n\t\tassertThat(location.getValue().isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid ofWhenEmptyOptionalValueReturnsEmptyLocation() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:\");\n\t\tassertThat(location.getValue().isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid ofReturnsLocation() {\n\t\tassertThat(ConfigDataLocation.of(\"test\")).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid splitWhenNoSemiColonReturnsSingleElement() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tConfigDataLocation[] split = location.split();\n\t\tassertThat(split).containsExactly(ConfigDataLocation.of(\"test\"));\n\t}\n\n\t@Test\n\tvoid splitWhenSemiColonReturnsElements() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"one;two;three\");\n\t\tConfigDataLocation[] split = location.split();\n\t\tassertThat(split).containsExactly(ConfigDataLocation.of(\"one\"), ConfigDataLocation.of(\"two\"),\n\t\t\t\tConfigDataLocation.of(\"three\"));\n\t}\n\n\t@Test\n\tvoid splitOnCharReturnsElements() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"one::two::three\");\n\t\tConfigDataLocation[] split = location.split(\"::\");\n\t\tassertThat(split).containsExactly(ConfigDataLocation.of(\"one\"), ConfigDataLocation.of(\"two\"),\n\t\t\t\tConfigDataLocation.of(\"three\"));\n\t}\n\n\t@Test\n\tvoid splitWhenHasOriginReturnsElementsWithOriginSet() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"a;b\").withOrigin(origin);\n\t\tConfigDataLocation[] split = location.split();\n\t\tassertThat(split[0].getOrigin()).isEqualTo(origin);\n\t\tassertThat(split[1].getOrigin()).isEqualTo(origin);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataNotFoundFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.origin.Origin;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataNotFoundFailureAnalyzer}.\n *\n * @author Michal Mlak\n * @author Phillip Webb\n */\nclass ConfigDataNotFoundFailureAnalyzerTests {\n\n\tprivate final ConfigDataNotFoundFailureAnalyzer analyzer = new ConfigDataNotFoundFailureAnalyzer();\n\n\t@Test\n\tvoid analyzeWhenConfigDataLocationNotFoundException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location);\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription()).isEqualTo(\"Config data location 'test' does not exist\");\n\t\tassertThat(result.getAction())\n\t\t\t.isEqualTo(\"Check that the value 'test' is correct, or prefix it with 'optional:'\");\n\t}\n\n\t@Test\n\tvoid analyzeWhenOptionalConfigDataLocationNotFoundException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:test\");\n\t\tConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location);\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription()).isEqualTo(\"Config data location 'optional:test' does not exist\");\n\t\tassertThat(result.getAction()).isEqualTo(\"Check that the value 'optional:test' is correct\");\n\t}\n\n\t@Test\n\tvoid analyzeWhenConfigDataLocationWithOriginNotFoundException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\").withOrigin(new TestOrigin(\"origin\"));\n\t\tConfigDataLocationNotFoundException exception = new ConfigDataLocationNotFoundException(location);\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription()).isEqualTo(\"Config data location 'test' does not exist\");\n\t\tassertThat(result.getAction())\n\t\t\t.isEqualTo(\"Check that the value 'test' at origin is correct, or prefix it with 'optional:'\");\n\t}\n\n\t@Test\n\tvoid analyzeWhenConfigDataResourceNotFoundException() {\n\t\tConfigDataResource resource = new TestConfigDataResource(\"myresource\");\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(resource);\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription()).isEqualTo(\"Config data resource 'myresource' does not exist\");\n\t\tassertThat(result.getAction()).isEqualTo(\"Check that the value is correct\");\n\t}\n\n\t@Test\n\tvoid analyzeWhenConfigDataResourceWithLocationNotFoundException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tConfigDataResource resource = new TestConfigDataResource(\"myresource\");\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(resource)\n\t\t\t.withLocation(location);\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription())\n\t\t\t.isEqualTo(\"Config data resource 'myresource' via location 'test' does not exist\");\n\t\tassertThat(result.getAction())\n\t\t\t.isEqualTo(\"Check that the value 'test' is correct, or prefix it with 'optional:'\");\n\t}\n\n\tstatic class TestOrigin implements Origin {\n\n\t\tprivate final String string;\n\n\t\tTestOrigin(String string) {\n\t\t\tthis.string = string;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t}\n\n\tstatic class TestConfigDataResource extends ConfigDataResource {\n\n\t\tprivate final String string;\n\n\t\tTestConfigDataResource(String string) {\n\t\t\tthis.string = string;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataPropertiesRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.context.config.ConfigDataProperties.Activate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataPropertiesRuntimeHints}.\n *\n * @author Moritz Halbritter\n */\nclass ConfigDataPropertiesRuntimeHintsTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ConfigDataPropertiesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConfigDataProperties.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConfigDataLocation.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Activate.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ConfigDataLocation.class, \"of\"))\n\t\t\t.accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.config.ConfigDataProperties.Activate;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataProperties}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Yanming Zhou\n */\nclass ConfigDataPropertiesTests {\n\n\tprivate static final @Nullable CloudPlatform NULL_CLOUD_PLATFORM = null;\n\n\tprivate static final @Nullable Profiles NULL_PROFILES = null;\n\n\tprivate static final List<ConfigDataLocation> NO_IMPORTS = Collections.emptyList();\n\n\t@Test\n\tvoid getImportsReturnsImports() {\n\t\tConfigDataLocation l1 = ConfigDataLocation.of(\"one\");\n\t\tConfigDataLocation l2 = ConfigDataLocation.of(\"two\");\n\t\tConfigDataLocation l3 = ConfigDataLocation.of(\"three\");\n\t\tList<ConfigDataLocation> imports = Arrays.asList(l1, l2, l3);\n\t\tConfigDataProperties properties = new ConfigDataProperties(imports, null);\n\t\tassertThat(properties.getImports()).containsExactly(l1, l2, l3);\n\t}\n\n\t@Test\n\tvoid getImportsWhenImportsAreNullReturnsEmptyList() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(null, null);\n\t\tassertThat(properties.getImports()).isEmpty();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNullCloudPlatformAgainstNullCloudPlatform() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS, new Activate(null, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNullCloudPlatformAgainstSpecificCloudPlatform() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS, new Activate(null, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenSpecificCloudPlatformAgainstNullCloudPlatform() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(CloudPlatform.KUBERNETES, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveWhenSpecificCloudPlatformAgainstMatchingSpecificCloudPlatform() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(CloudPlatform.KUBERNETES, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenSpecificCloudPlatformAgainstDifferentSpecificCloudPlatform() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(CloudPlatform.KUBERNETES, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.HEROKU, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNoneCloudPlatformAgainstNullCloudPlatform() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS, new Activate(CloudPlatform.NONE, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNullProfilesAgainstNullProfiles() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS, new Activate(null, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM, NULL_PROFILES);\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNullProfilesAgainstSpecificProfiles() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS, new Activate(null, null));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenSpecificProfilesAgainstNullProfiles() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(null, new String[] { \"a\" }));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM, null);\n\t\tassertThat(properties.isActive(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveWhenSpecificProfilesAgainstMatchingSpecificProfiles() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(null, new String[] { \"a\" }));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenSpecificProfilesAgainstMissingSpecificProfiles() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(null, new String[] { \"x\" }));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties.isActive(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveWhenProfileExpressionAgainstSpecificProfiles() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS,\n\t\t\t\tnew Activate(null, new String[] { \"a | b\" }));\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenActivateIsNull() {\n\t\tConfigDataProperties properties = new ConfigDataProperties(NO_IMPORTS, null);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveAgainstBoundData() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"spring.config.activate.on-cloud-platform\", \"kubernetes\");\n\t\tsource.put(\"spring.config.activate.on-profile\", \"a | b\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveAgainstBoundDataWhenProfilesDontMatch() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"spring.config.activate.on-cloud-platform\", \"kubernetes\");\n\t\tsource.put(\"spring.config.activate.on-profile\", \"x | z\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.isActive(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveAgainstBoundDataWhenCloudPlatformDoesntMatch() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"spring.config.activate.on-cloud-platform\", \"cloud-foundry\");\n\t\tsource.put(\"spring.config.activate.on-profile\", \"a | b\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(CloudPlatform.KUBERNETES,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.isActive(context)).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveAgainstBoundDataWhenProfilesMatchCommaSeparatedList() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"spring.config.activate.on-profile\", \"a&b,nonexistent\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tConfigDataActivationContext context = new ConfigDataActivationContext(NULL_CLOUD_PLATFORM,\n\t\t\t\tcreateTestProfiles());\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.isActive(context)).isTrue();\n\t}\n\n\t@Test\n\tvoid getImportOriginWhenCommaListReturnsOrigin() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"spring.config.import\", \"one,two,three\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.getImports().get(1).getOrigin())\n\t\t\t.hasToString(\"\\\"spring.config.import\\\" from property source \\\"source\\\"\");\n\t}\n\n\t@Test\n\tvoid getImportOriginWhenBracketListReturnsOrigin() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"spring.config.import[0]\", \"one\");\n\t\tsource.put(\"spring.config.import[1]\", \"two\");\n\t\tsource.put(\"spring.config.import[2]\", \"three\");\n\t\tBinder binder = new Binder(source);\n\t\tConfigDataProperties properties = ConfigDataProperties.get(binder);\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.getImports().get(1).getOrigin())\n\t\t\t.hasToString(\"\\\"spring.config.import[1]\\\" from property source \\\"source\\\"\");\n\t}\n\n\tprivate Profiles createTestProfiles() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\treturn new Profiles(environment, binder, null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataResourceNotFoundExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.io.FileSystemResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigDataResourceNotFoundException}.\n *\n * @author Phillip Webb\n */\nclass ConfigDataResourceNotFoundExceptionTests {\n\n\tprivate final ConfigDataResource resource = new TestConfigDataResource();\n\n\tprivate final ConfigDataLocation location = ConfigDataLocation.of(\"optional:test\");\n\n\tprivate final Throwable cause = new RuntimeException();\n\n\tprivate File exists;\n\n\tprivate File missing;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@BeforeEach\n\tvoid setup() throws IOException {\n\t\tthis.exists = new File(this.temp, \"exists\");\n\t\tthis.missing = new File(this.temp, \"missing\");\n\t\ttry (OutputStream out = new FileOutputStream(this.exists)) {\n\t\t\tout.write(\"test\".getBytes());\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResourceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigDataResourceNotFoundException(null))\n\t\t\t.withMessage(\"'resource' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithResourceCreatesInstance() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource);\n\t\tassertThat(exception.getResource()).isSameAs(this.resource);\n\t}\n\n\t@Test\n\tvoid createWithResourceAndCauseCreatesInstance() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource,\n\t\t\t\tthis.cause);\n\t\tassertThat(exception.getResource()).isSameAs(this.resource);\n\t\tassertThat(exception.getCause()).isSameAs(this.cause);\n\t}\n\n\t@Test\n\tvoid getResourceReturnsResource() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource);\n\t\tassertThat(exception.getResource()).isSameAs(this.resource);\n\t}\n\n\t@Test\n\tvoid getLocationWhenHasNoLocationReturnsNull() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource);\n\t\tassertThat(exception.getLocation()).isNull();\n\t}\n\n\t@Test\n\tvoid getLocationWhenHasLocationReturnsLocation() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource)\n\t\t\t.withLocation(this.location);\n\t\tassertThat(exception.getLocation()).isSameAs(this.location);\n\t}\n\n\t@Test\n\tvoid getReferenceDescriptionWhenHasNoLocationReturnsDescription() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource);\n\t\tassertThat(exception.getReferenceDescription()).isEqualTo(\"resource 'mytestresource'\");\n\t}\n\n\t@Test\n\tvoid getReferenceDescriptionWhenHasLocationReturnsDescription() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource)\n\t\t\t.withLocation(this.location);\n\t\tassertThat(exception.getReferenceDescription())\n\t\t\t.isEqualTo(\"resource 'mytestresource' via location 'optional:test'\");\n\t}\n\n\t@Test\n\tvoid withLocationReturnsNewInstanceWithLocation() {\n\t\tConfigDataResourceNotFoundException exception = new ConfigDataResourceNotFoundException(this.resource)\n\t\t\t.withLocation(this.location);\n\t\tassertThat(exception.getLocation()).isSameAs(this.location);\n\t}\n\n\t@Test\n\tvoid throwIfDoesNotExistWhenPathExistsDoesNothing() {\n\t\tConfigDataResourceNotFoundException.throwIfDoesNotExist(this.resource, this.exists.toPath());\n\t}\n\n\t@Test\n\tvoid throwIfDoesNotExistWhenPathDoesNotExistThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class).isThrownBy(\n\t\t\t\t() -> ConfigDataResourceNotFoundException.throwIfDoesNotExist(this.resource, this.missing.toPath()));\n\t}\n\n\t@Test\n\tvoid throwIfDoesNotExistWhenFileExistsDoesNothing() {\n\t\tConfigDataResourceNotFoundException.throwIfDoesNotExist(this.resource, this.exists);\n\n\t}\n\n\t@Test\n\tvoid throwIfDoesNotExistWhenFileDoesNotExistThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class)\n\t\t\t.isThrownBy(() -> ConfigDataResourceNotFoundException.throwIfDoesNotExist(this.resource, this.missing));\n\t}\n\n\t@Test\n\tvoid throwIfDoesNotExistWhenResourceExistsDoesNothing() {\n\t\tConfigDataResourceNotFoundException.throwIfDoesNotExist(this.resource, new FileSystemResource(this.exists));\n\t}\n\n\t@Test\n\tvoid throwIfDoesNotExistWhenResourceDoesNotExistThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class)\n\t\t\t.isThrownBy(() -> ConfigDataResourceNotFoundException.throwIfDoesNotExist(this.resource,\n\t\t\t\t\tnew FileSystemResource(this.missing)));\n\t}\n\n\tstatic class TestConfigDataResource extends ConfigDataResource {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"mytestresource\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.config.ConfigData.Option;\nimport org.springframework.boot.context.config.ConfigData.Options;\nimport org.springframework.boot.context.config.ConfigData.PropertySourceOptions;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigData}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigDataTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertySourcesIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigData(null))\n\t\t\t.withMessage(\"'propertySources' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenOptionsIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigData(Collections.emptyList(), (Option[]) null))\n\t\t\t.withMessage(\"'options' must not be null\");\n\t}\n\n\t@Test\n\tvoid getPropertySourcesReturnsCopyOfSources() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.emptyMap());\n\t\tList<MapPropertySource> sources = new ArrayList<>(Collections.singleton(source));\n\t\tConfigData configData = new ConfigData(sources);\n\t\tsources.clear();\n\t\tassertThat(configData.getPropertySources()).containsExactly(source);\n\t}\n\n\t@Test\n\tvoid getOptionsWhenOptionsSetAtConstructionAlwaysReturnsSameOptions() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.emptyMap());\n\t\tConfigData configData = new ConfigData(Collections.singleton(source), Option.IGNORE_IMPORTS);\n\t\tassertThat(configData.getOptions(source).asSet()).containsExactly(Option.IGNORE_IMPORTS);\n\t}\n\n\t@Test\n\tvoid getOptionsReturnsOptionsFromPropertySourceOptions() {\n\t\tMapPropertySource source1 = new MapPropertySource(\"test\", Collections.emptyMap());\n\t\tMapPropertySource source2 = new MapPropertySource(\"test\", Collections.emptyMap());\n\t\tOptions options1 = Options.of(Option.IGNORE_IMPORTS);\n\t\tOptions options2 = Options.of(Option.IGNORE_PROFILES);\n\t\tPropertySourceOptions propertySourceOptions = (source) -> (source != source1) ? options2 : options1;\n\t\tConfigData configData = new ConfigData(Arrays.asList(source1, source2), propertySourceOptions);\n\t\tassertThat(configData.getOptions(source1)).isEqualTo(options1);\n\t\tassertThat(configData.getOptions(source2)).isEqualTo(options2);\n\t}\n\n\t@Test\n\tvoid getOptionsWhenPropertySourceOptionsReturnsNullReturnsNone() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.emptyMap());\n\t\tPropertySourceOptions propertySourceOptions = (propertySource) -> null;\n\t\tConfigData configData = new ConfigData(Collections.singleton(source), propertySourceOptions);\n\t\tassertThat(configData.getOptions(source)).isEqualTo(Options.NONE);\n\t}\n\n\t@Test\n\tvoid optionsOfCreatesOptions() {\n\t\tOptions options = Options.of(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t\tassertThat(options.asSet()).containsExactly(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t}\n\n\t@Test\n\tvoid optionsOfUsesCopyOfOptions() {\n\t\tOption[] array = { Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES };\n\t\tOptions options = Options.of(array);\n\t\tarray[0] = Option.PROFILE_SPECIFIC;\n\t\tassertThat(options.asSet()).containsExactly(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t}\n\n\t@Test\n\tvoid optionsNoneReturnsEmptyOptions() {\n\t\tassertThat(Options.NONE.asSet()).isEmpty();\n\t}\n\n\t@Test\n\tvoid optionsWithoutReturnsNewOptions() {\n\t\tOptions options = Options.of(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t\tOptions without = options.without(Option.IGNORE_PROFILES);\n\t\tassertThat(options.asSet()).containsExactly(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t\tassertThat(without.asSet()).containsExactly(Option.IGNORE_IMPORTS);\n\t}\n\n\t@Test\n\tvoid optionsWithReturnsNewOptions() {\n\t\tOptions options = Options.of(Option.IGNORE_IMPORTS);\n\t\tOptions with = options.with(Option.IGNORE_PROFILES);\n\t\tassertThat(options.asSet()).containsExactly(Option.IGNORE_IMPORTS);\n\t\tassertThat(with.asSet()).containsExactly(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t}\n\n\t@Test\n\tvoid propertySourceOptionsAlwaysReturnsSameOptionsEachTime() {\n\t\tPropertySourceOptions options = PropertySourceOptions.always(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t\tOptions propertySourceOptions = options.get(mock(PropertySource.class));\n\t\tassertThat(propertySourceOptions).isNotNull();\n\t\tassertThat(propertySourceOptions.asSet()).containsExactly(Option.IGNORE_IMPORTS, Option.IGNORE_PROFILES);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigTreeConfigDataLoader}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ConfigTreeConfigDataLoaderTests {\n\n\tprivate final ConfigTreeConfigDataLoader loader = new ConfigTreeConfigDataLoader();\n\n\tprivate final ConfigDataLoaderContext loaderContext = mock(ConfigDataLoaderContext.class);\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath directory;\n\n\t@Test\n\tvoid loadReturnsConfigDataWithPropertySource() throws IOException {\n\t\tFile file = this.directory.resolve(\"hello\").toFile();\n\t\tfile.getParentFile().mkdirs();\n\t\tFileCopyUtils.copy(\"world\\n\".getBytes(StandardCharsets.UTF_8), file);\n\t\tConfigTreeConfigDataResource location = new ConfigTreeConfigDataResource(this.directory.toString());\n\t\tConfigData configData = this.loader.load(this.loaderContext, location);\n\t\tassertThat(configData.getPropertySources()).hasSize(1);\n\t\tPropertySource<?> source = configData.getPropertySources().get(0);\n\t\tassertThat(source.getName()).isEqualTo(\"Config tree '\" + this.directory.toString() + \"'\");\n\t\tassertThat(source.getProperty(\"hello\")).hasToString(\"world\");\n\t}\n\n\t@Test\n\tvoid loadWhenPathDoesNotExistThrowsException() {\n\t\tFile missing = this.directory.resolve(\"missing\").toFile();\n\t\tConfigTreeConfigDataResource location = new ConfigTreeConfigDataResource(missing.toString());\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.loader.load(this.loaderContext, location));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataLocationResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigTreeConfigDataLocationResolver}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ConfigTreeConfigDataLocationResolverTests {\n\n\tprivate final ConfigTreeConfigDataLocationResolver resolver = new ConfigTreeConfigDataLocationResolver(\n\t\t\tnew DefaultResourceLoader());\n\n\tprivate final ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class);\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid isResolvableWhenPrefixMatchesReturnsTrue() {\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"configtree:/etc/config\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isResolvableWhenPrefixDoesNotMatchReturnsFalse() {\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"http://etc/config\"))).isFalse();\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"/etc/config\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid resolveReturnsConfigVolumeMountLocation() {\n\t\tList<ConfigTreeConfigDataResource> locations = this.resolver.resolve(this.context,\n\t\t\t\tConfigDataLocation.of(\"configtree:/etc/config/\"));\n\t\tassertThat(locations).hasSize(1);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.containsExactly(\"config tree [\" + new File(\"/etc/config\").getAbsolutePath() + \"]\");\n\t}\n\n\t@Test\n\tvoid resolveWildcardPattern() throws Exception {\n\t\tFile directoryA = new File(this.temp, \"a\");\n\t\tFile directoryB = new File(this.temp, \"b\");\n\t\tdirectoryA.mkdirs();\n\t\tdirectoryB.mkdirs();\n\t\tFileCopyUtils.copy(\"test\".getBytes(), new File(directoryA, \"spring\"));\n\t\tFileCopyUtils.copy(\"test\".getBytes(), new File(directoryB, \"boot\"));\n\t\tList<ConfigTreeConfigDataResource> locations = this.resolver.resolve(this.context,\n\t\t\t\tConfigDataLocation.of(\"configtree:\" + this.temp.getAbsolutePath() + \"/*/\"));\n\t\tassertThat(locations).hasSize(2);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.containsExactly(\"config tree [\" + directoryA.getAbsolutePath() + \"]\",\n\t\t\t\t\t\"config tree [\" + directoryB.getAbsolutePath() + \"]\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigTreeConfigDataResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigTreeConfigDataResource}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ConfigTreeConfigDataResourceTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid constructorWhenPathStringIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreeConfigDataResource((String) null))\n\t\t\t.withMessage(\"'path' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid constructorWhenPathIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreeConfigDataResource((Path) null))\n\t\t\t.withMessage(\"'path' must not be null\");\n\t}\n\n\t@Test\n\tvoid equalsWhenPathIsTheSameReturnsTrue() {\n\t\tConfigTreeConfigDataResource location = new ConfigTreeConfigDataResource(\"/etc/config\");\n\t\tConfigTreeConfigDataResource other = new ConfigTreeConfigDataResource(\"/etc/config\");\n\t\tassertThat(location).isEqualTo(other);\n\t}\n\n\t@Test\n\tvoid equalsWhenPathIsDifferentReturnsFalse() {\n\t\tConfigTreeConfigDataResource location = new ConfigTreeConfigDataResource(\"/etc/config\");\n\t\tConfigTreeConfigDataResource other = new ConfigTreeConfigDataResource(\"other-location\");\n\t\tassertThat(location).isNotEqualTo(other);\n\t}\n\n\t@Test\n\tvoid toStringReturnsDescriptiveString() {\n\t\tConfigTreeConfigDataResource location = new ConfigTreeConfigDataResource(\"/etc/config\");\n\t\tassertThat(location).hasToString(\"config tree [\" + new File(\"/etc/config\").getAbsolutePath() + \"]\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/FileHintTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FileHint}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass FileHintTests {\n\n\t@Test\n\tvoid shouldParseImplicitExtension() {\n\t\tString value = \"foo[.bar]\";\n\t\tFileHint hint = FileHint.from(value);\n\t\tassertThat(hint.isPresent()).isTrue();\n\t\tassertThat(hint.getExtension()).isEqualTo(\".bar\");\n\t\tassertThat(FileHint.removeFrom(value)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid shouldParseExplicitExtension() {\n\t\tString value = \"foo[extension=.bar]\";\n\t\tFileHint hint = FileHint.from(value);\n\t\tassertThat(hint.isPresent()).isTrue();\n\t\tassertThat(hint.getExtension()).isEqualTo(\".bar\");\n\t\tassertThat(FileHint.removeFrom(value)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid shouldParseNestedBrackets() {\n\t\tString value = \"foo[encoding=[utf-8]]\";\n\t\tFileHint hint = FileHint.from(value);\n\t\tassertThat(hint.isPresent()).isTrue();\n\t\tassertThat(hint.getEncoding()).isEqualTo(\"[utf-8]\");\n\t\tassertThat(FileHint.removeFrom(value)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid shouldParseEncoding() {\n\t\tString value = \"foo[encoding=utf-8]\";\n\t\tFileHint hint = FileHint.from(value);\n\t\tassertThat(hint.isPresent()).isTrue();\n\t\tassertThat(hint.getEncoding()).isEqualTo(\"utf-8\");\n\t\tassertThat(FileHint.removeFrom(value)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid shouldParseAll() {\n\t\tString value = \"foo[extension=.bar][encoding=utf-8]\";\n\t\tFileHint hint = FileHint.from(value);\n\t\tassertThat(hint.isPresent()).isTrue();\n\t\tassertThat(hint.getExtension()).isEqualTo(\".bar\");\n\t\tassertThat(hint.getEncoding()).isEqualTo(\"utf-8\");\n\t\tassertThat(FileHint.removeFrom(value)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid isPresentWhenHasNoHint() {\n\t\tassertThat(FileHint.from(\"foo\").isPresent()).isFalse();\n\t\tassertThat(FileHint.from(\"foo[bar]\").isPresent()).isFalse();\n\t\tassertThat(FileHint.from(\"foo[.b[ar]\").isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getExtensionOrElseWhenHasHint() {\n\t\tassertThat(FileHint.from(\"foo[.bar]\").getExtensionOrElse(\".txt\")).isEqualTo(\".bar\");\n\t}\n\n\t@Test\n\tvoid getExtensionOrElseWhenHasNoHint() {\n\t\tassertThat(FileHint.from(\"foo\").getExtensionOrElse(\".txt\")).isEqualTo(\".txt\");\n\t}\n\n\t@Test\n\tvoid removeFromWhenHasNoHint() {\n\t\tassertThat(FileHint.removeFrom(\"foo\")).isEqualTo(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/InactiveConfigDataAccessExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link InactiveConfigDataAccessException}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass InactiveConfigDataAccessExceptionTests {\n\n\tprivate final MockPropertySource propertySource = new MockPropertySource();\n\n\tprivate final ConfigDataResource resource = new TestConfigDataResource();\n\n\tprivate final String propertyName = \"spring\";\n\n\tprivate final Origin origin = new PropertySourceOrigin(this.propertySource, this.propertyName);\n\n\t@Test\n\tvoid createHasCorrectMessage() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource,\n\t\t\t\tthis.resource, this.propertyName, this.origin);\n\t\tassertThat(exception).hasMessage(\"Inactive property source 'mockProperties' imported from location 'test' \"\n\t\t\t\t+ \"cannot contain property 'spring' [origin: \\\"spring\\\" from property source \\\"mockProperties\\\"]\");\n\t}\n\n\t@Test\n\tvoid createWhenNoLocationHasCorrectMessage() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource, null,\n\t\t\t\tthis.propertyName, this.origin);\n\t\tassertThat(exception).hasMessage(\"Inactive property source 'mockProperties' \"\n\t\t\t\t+ \"cannot contain property 'spring' [origin: \\\"spring\\\" from property source \\\"mockProperties\\\"]\");\n\t}\n\n\t@Test\n\tvoid createWhenNoOriginHasCorrectMessage() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource,\n\t\t\t\tthis.resource, this.propertyName, null);\n\t\tassertThat(exception).hasMessage(\"Inactive property source 'mockProperties' imported from location 'test' \"\n\t\t\t\t+ \"cannot contain property 'spring'\");\n\t}\n\n\t@Test\n\tvoid getPropertySourceReturnsPropertySource() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource,\n\t\t\t\tthis.resource, this.propertyName, this.origin);\n\t\tassertThat(exception.getPropertySource()).isSameAs(this.propertySource);\n\t}\n\n\t@Test\n\tvoid getLocationReturnsLocation() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource,\n\t\t\t\tthis.resource, this.propertyName, this.origin);\n\t\tassertThat(exception.getLocation()).isSameAs(this.resource);\n\t}\n\n\t@Test\n\tvoid getPropertyNameReturnsPropertyName() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource,\n\t\t\t\tthis.resource, this.propertyName, this.origin);\n\t\tassertThat(exception.getPropertyName()).isSameAs(this.propertyName);\n\t}\n\n\t@Test\n\tvoid getOriginReturnsOrigin() {\n\t\tInactiveConfigDataAccessException exception = new InactiveConfigDataAccessException(this.propertySource,\n\t\t\t\tthis.resource, this.propertyName, this.origin);\n\t\tassertThat(exception.getOrigin()).isSameAs(this.origin);\n\t}\n\n\t@Test\n\tvoid throwIfPropertyFoundWhenSourceIsNullDoesNothing() {\n\t\tConfigDataEnvironmentContributor contributor = mock(ConfigDataEnvironmentContributor.class);\n\t\tgiven(contributor.getConfigurationPropertySource()).willReturn(null);\n\t\tInactiveConfigDataAccessException.throwIfPropertyFound(contributor, ConfigurationPropertyName.of(\"spring\"));\n\t}\n\n\t@Test\n\tvoid throwIfPropertyFoundWhenPropertyNotFoundDoesNothing() {\n\t\tConfigDataEnvironmentContributor contributor = mock(ConfigDataEnvironmentContributor.class);\n\t\tConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(this.propertySource);\n\t\tgiven(contributor.getConfigurationPropertySource()).willReturn(configurationPropertySource);\n\t\tInactiveConfigDataAccessException.throwIfPropertyFound(contributor, ConfigurationPropertyName.of(\"spring\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid throwIfPropertyFoundWhenPropertyFoundThrowsException() {\n\t\tthis.propertySource.setProperty(\"spring\", \"test\");\n\t\tConfigDataEnvironmentContributor contributor = mock(ConfigDataEnvironmentContributor.class);\n\t\tConfigurationPropertySource configurationPropertySource = ConfigurationPropertySource.from(this.propertySource);\n\t\tgiven(contributor.getConfigurationPropertySource()).willReturn(configurationPropertySource);\n\t\tgiven(contributor.getPropertySource()).willReturn((PropertySource) this.propertySource);\n\t\tgiven(contributor.getResource()).willReturn(this.resource);\n\t\tassertThatExceptionOfType(InactiveConfigDataAccessException.class)\n\t\t\t.isThrownBy(() -> InactiveConfigDataAccessException.throwIfPropertyFound(contributor,\n\t\t\t\t\tConfigurationPropertyName.of(\"spring\")))\n\t\t\t.withMessage(\"Inactive property source 'mockProperties' imported from location 'test' \"\n\t\t\t\t\t+ \"cannot contain property 'spring' [origin: \\\"spring\\\" from property source \\\"mockProperties\\\"]\");\n\t}\n\n\tprivate static final class TestConfigDataResource extends ConfigDataResource {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/InvalidConfigDataPropertyExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.config.ConfigDataEnvironmentContributor.Kind;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.origin.MockOrigin;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link InvalidConfigDataPropertyException}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass InvalidConfigDataPropertyExceptionTests {\n\n\tprivate final ConfigDataResource resource = new TestConfigDataResource();\n\n\tprivate final ConfigurationPropertyName replacement = ConfigurationPropertyName.of(\"replacement\");\n\n\tprivate final ConfigurationPropertyName invalid = ConfigurationPropertyName.of(\"invalid\");\n\n\tprivate final ConfigurationProperty property = new ConfigurationProperty(this.invalid, \"bad\",\n\t\t\tMockOrigin.of(\"origin\"));\n\n\tprivate final ConversionService conversionService = DefaultConversionService.getSharedInstance();\n\n\t@Test\n\tvoid createHasCorrectMessage() {\n\t\tassertThat(new InvalidConfigDataPropertyException(this.property, false, this.replacement, this.resource))\n\t\t\t.hasMessage(\n\t\t\t\t\t\"Property 'invalid' imported from location 'test' is invalid and should be replaced with 'replacement' [origin: origin]\");\n\t}\n\n\t@Test\n\tvoid createWhenNoLocationHasCorrectMessage() {\n\t\tassertThat(new InvalidConfigDataPropertyException(this.property, false, this.replacement, null))\n\t\t\t.hasMessage(\"Property 'invalid' is invalid and should be replaced with 'replacement' [origin: origin]\");\n\t}\n\n\t@Test\n\tvoid createWhenNoReplacementHasCorrectMessage() {\n\t\tassertThat(new InvalidConfigDataPropertyException(this.property, false, null, this.resource))\n\t\t\t.hasMessage(\"Property 'invalid' imported from location 'test' is invalid [origin: origin]\");\n\t}\n\n\t@Test\n\tvoid createWhenNoOriginHasCorrectMessage() {\n\t\tConfigurationProperty property = new ConfigurationProperty(this.invalid, \"bad\", null);\n\t\tassertThat(new InvalidConfigDataPropertyException(property, false, this.replacement, this.resource)).hasMessage(\n\t\t\t\t\"Property 'invalid' imported from location 'test' is invalid and should be replaced with 'replacement'\");\n\t}\n\n\t@Test\n\tvoid createWhenProfileSpecificHasCorrectMessage() {\n\t\tConfigurationProperty property = new ConfigurationProperty(this.invalid, \"bad\", null);\n\t\tassertThat(new InvalidConfigDataPropertyException(property, true, null, this.resource))\n\t\t\t.hasMessage(\"Property 'invalid' imported from location 'test' is invalid in a profile specific resource\");\n\t}\n\n\t@Test\n\tvoid getPropertyReturnsProperty() {\n\t\tInvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, false,\n\t\t\t\tthis.replacement, this.resource);\n\t\tassertThat(exception.getProperty()).isEqualTo(this.property);\n\t}\n\n\t@Test\n\tvoid getLocationReturnsLocation() {\n\t\tInvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, false,\n\t\t\t\tthis.replacement, this.resource);\n\t\tassertThat(exception.getLocation()).isEqualTo(this.resource);\n\t}\n\n\t@Test\n\tvoid getReplacementReturnsReplacement() {\n\t\tInvalidConfigDataPropertyException exception = new InvalidConfigDataPropertyException(this.property, false,\n\t\t\t\tthis.replacement, this.resource);\n\t\tassertThat(exception.getReplacement()).isEqualTo(this.replacement);\n\t}\n\n\t@Test\n\tvoid throwOrWarnWhenHasInvalidPropertyThrowsException() {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(\"spring.profiles\", \"a\");\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor.ofExisting(propertySource,\n\t\t\t\tthis.conversionService);\n\t\tassertThatExceptionOfType(InvalidConfigDataPropertyException.class)\n\t\t\t.isThrownBy(() -> InvalidConfigDataPropertyException.throwIfPropertyFound(contributor))\n\t\t\t.withMessageStartingWith(\"Property 'spring.profiles' is invalid and should be replaced with \"\n\t\t\t\t\t+ \"'spring.config.activate.on-profile'\");\n\t}\n\n\t@Test\n\tvoid throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException() {\n\t\tthrowOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException(\"spring.profiles.include\");\n\t\tthrowOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException(\"spring.profiles.active\");\n\t\tthrowOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException(\"spring.profiles.default\");\n\t}\n\n\t@Test\n\tvoid throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyOnIgnoringProfilesContributorDoesNotThrowException() {\n\t\tConfigDataEnvironmentContributor contributor = createInvalidProfileSpecificPropertyContributor(\n\t\t\t\t\"spring.profiles.active\", ConfigData.Option.IGNORE_PROFILES);\n\t\tassertThatNoException().isThrownBy(() -> InvalidConfigDataPropertyException.throwIfPropertyFound(contributor));\n\t}\n\n\tprivate void throwOrWarnWhenWhenHasInvalidProfileSpecificPropertyThrowsException(String name) {\n\t\tConfigDataEnvironmentContributor contributor = createInvalidProfileSpecificPropertyContributor(name);\n\t\tassertThatExceptionOfType(InvalidConfigDataPropertyException.class)\n\t\t\t.isThrownBy(() -> InvalidConfigDataPropertyException.throwIfPropertyFound(contributor))\n\t\t\t.withMessageStartingWith(\"Property '\" + name + \"' is invalid in a profile specific resource\");\n\t}\n\n\tprivate ConfigDataEnvironmentContributor createInvalidProfileSpecificPropertyContributor(String name,\n\t\t\tConfigData.Option... configDataOptions) {\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.setProperty(name, \"a\");\n\t\treturn new ConfigDataEnvironmentContributor(Kind.BOUND_IMPORT, null, null, true, propertySource,\n\t\t\t\tConfigurationPropertySource.from(propertySource), null, ConfigData.Options.of(configDataOptions), null,\n\t\t\t\tthis.conversionService);\n\t}\n\n\t@Test\n\tvoid throwOrWarnWhenHasNoInvalidPropertyDoesNothing() {\n\t\tConfigDataEnvironmentContributor contributor = ConfigDataEnvironmentContributor\n\t\t\t.ofExisting(new MockPropertySource(), this.conversionService);\n\t\tInvalidConfigDataPropertyException.throwIfPropertyFound(contributor);\n\t}\n\n\tprivate static final class TestConfigDataResource extends ConfigDataResource {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/LocationResourceLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.context.config.LocationResourceLoader.ResourceType;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link LocationResourceLoader}.\n *\n * @author Phillip Webb\n */\nclass LocationResourceLoaderTests {\n\n\tprivate final LocationResourceLoader loader = new LocationResourceLoader(new DefaultResourceLoader());\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid isPatternWhenHasAsteriskReturnsTrue() {\n\t\tassertThat(this.loader.isPattern(\"spring/*/boot\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isPatternWhenNoAsteriskReturnsFalse() {\n\t\tassertThat(this.loader.isPattern(\"spring/boot\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getResourceWhenPatternThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.loader.getResource(\"spring/boot/*\"))\n\t\t\t.withMessage(\"Location 'spring/boot/*' must not be a pattern\");\n\t}\n\n\t@Test\n\tvoid getResourceReturnsResource() throws Exception {\n\t\tFile file = new File(this.temp, \"file\");\n\t\tFileCopyUtils.copy(\"test\".getBytes(), file);\n\t\tResource resource = this.loader.getResource(file.toURI().toString());\n\t\tassertThat(resource.getInputStream()).hasContent(\"test\");\n\t}\n\n\t@Test\n\tvoid getResourceWhenNotUrlReturnsResource() throws Exception {\n\t\tFile file = new File(this.temp, \"file\");\n\t\tFileCopyUtils.copy(\"test\".getBytes(), file);\n\t\tResource resource = this.loader.getResource(file.getAbsolutePath());\n\t\tassertThat(resource.getInputStream()).hasContent(\"test\");\n\t}\n\n\t@Test\n\tvoid getResourceWhenNonCleanPathReturnsResource() throws Exception {\n\t\tFile file = new File(this.temp, \"file\");\n\t\tFileCopyUtils.copy(\"test\".getBytes(), file);\n\t\tResource resource = this.loader.getResource(this.temp.getAbsolutePath() + \"/spring/../file\");\n\t\tassertThat(resource.getInputStream()).hasContent(\"test\");\n\t}\n\n\t@Test\n\tvoid getResourcesWhenNotPatternThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.loader.getResources(\"spring/boot\", ResourceType.FILE))\n\t\t\t.withMessage(\"Location 'spring/boot' must be a pattern\");\n\t}\n\n\t@Test\n\tvoid getResourcesWhenLocationStartsWithClasspathWildcardThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.loader.getResources(\"classpath*:spring/boot/*/\", ResourceType.FILE))\n\t\t\t.withMessage(\"Location 'classpath*:spring/boot/*/' cannot use classpath wildcards\");\n\t}\n\n\t@Test\n\tvoid getResourcesWhenLocationContainsMultipleWildcardsThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.loader.getResources(\"spring/*/boot/*/\", ResourceType.FILE))\n\t\t\t.withMessage(\"Location 'spring/*/boot/*/' cannot contain multiple wildcards\");\n\t}\n\n\t@Test\n\tvoid getResourcesWhenPatternDoesNotEndWithAsteriskSlashThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.loader.getResources(\"spring/boot/*\", ResourceType.FILE))\n\t\t\t.withMessage(\"Location 'spring/boot/*' must end with '*/'\");\n\t}\n\n\t@Test\n\tvoid getFileResourceReturnsResources() throws Exception {\n\t\tcreateTree();\n\t\tResource[] resources = this.loader.getResources(this.temp.getAbsolutePath() + \"/*/file\", ResourceType.FILE);\n\t\tassertThat(resources).hasSize(2);\n\t\tassertThat(resources[0].getInputStream()).hasContent(\"a\");\n\t\tassertThat(resources[1].getInputStream()).hasContent(\"b\");\n\t}\n\n\t@Test\n\tvoid getDirectoryResourceReturnsResources() throws Exception {\n\t\tcreateTree();\n\t\tResource[] resources = this.loader.getResources(this.temp.getAbsolutePath() + \"/*/\", ResourceType.DIRECTORY);\n\t\tassertThat(resources).hasSize(2);\n\t\tassertThat(resources[0].getFilename()).isEqualTo(\"a\");\n\t\tassertThat(resources[1].getFilename()).isEqualTo(\"b\");\n\t}\n\n\t@Test\n\tvoid getResourcesWhenHasHiddenDirectoriesFiltersResults() throws IOException {\n\t\tcreateTree();\n\t\tFile hiddenDirectory = new File(this.temp, \"..a\");\n\t\thiddenDirectory.mkdirs();\n\t\tFileCopyUtils.copy(\"h\".getBytes(), new File(hiddenDirectory, \"file\"));\n\t\tResource[] resources = this.loader.getResources(this.temp.getAbsolutePath() + \"/*/file\", ResourceType.FILE);\n\t\tassertThat(resources).hasSize(2);\n\t\tassertThat(resources[0].getInputStream()).hasContent(\"a\");\n\t\tassertThat(resources[1].getInputStream()).hasContent(\"b\");\n\t}\n\n\tprivate void createTree() throws IOException {\n\t\tFile directoryA = new File(this.temp, \"a\");\n\t\tFile directoryB = new File(this.temp, \"b\");\n\t\tdirectoryA.mkdirs();\n\t\tdirectoryB.mkdirs();\n\t\tFileCopyUtils.copy(\"a\".getBytes(), new File(directoryA, \"file\"));\n\t\tFileCopyUtils.copy(\"b\".getBytes(), new File(directoryB, \"file\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ProfilesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link Profiles}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Sijun Yang\n */\nclass ProfilesTests {\n\n\t@Test\n\tvoid getActiveWhenNoEnvironmentProfilesAndNoPropertyReturnsEmptyArray() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getActiveWhenNoEnvironmentProfilesAndBinderProperty() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tBinder binder = new Binder(\n\t\t\t\tnew MapConfigurationPropertySource(Collections.singletonMap(\"spring.profiles.active\", \"a,b,c\")));\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenNoEnvironmentProfilesAndEnvironmentProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenEnvironmentProfilesAndBinderProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tBinder binder = new Binder(\n\t\t\t\tnew MapConfigurationPropertySource(Collections.singletonMap(\"spring.profiles.active\", \"d,e,f\")));\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\", \"d\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenEnvironmentProfilesAndBinderPropertyShouldReturnEnvironmentProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tList<ConfigurationPropertySource> sources = new ArrayList<>();\n\t\tConfigurationPropertySources.get(environment).forEach(sources::add);\n\t\tsources.add(new MapConfigurationPropertySource(Collections.singletonMap(\"spring.profiles.active\", \"d,e,f\")));\n\t\tBinder binder = new Binder(sources);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenEnvironmentProfilesAndEnvironmentProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"d,e,f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\", \"d\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenNoEnvironmentProfilesAndEnvironmentPropertyInBindNotation() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active[0]\", \"a\");\n\t\tenvironment.setProperty(\"spring.profiles.active[1]\", \"b\");\n\t\tenvironment.setProperty(\"spring.profiles.active[2]\", \"c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenEnvironmentProfilesInBindNotationAndEnvironmentPropertyReturnsEnvironmentProfiles() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tenvironment.setProperty(\"spring.profiles.active[0]\", \"d\");\n\t\tenvironment.setProperty(\"spring.profiles.active[1]\", \"e\");\n\t\tenvironment.setProperty(\"spring.profiles.active[2]\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\", \"d\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasDuplicatesReturnsUniqueElements() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,a,b,c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getActiveWithProfileGroups() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"d,e\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"d\", \"e\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getActiveWhenHasAdditionalIncludesAdditional() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"d,e,f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, Arrays.asList(\"a\", \"b\", \"c\"));\n\t\tassertThat(profiles.getActive()).containsExactly(\"a\", \"b\", \"c\", \"d\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenNoEnvironmentProfilesAndNoPropertyReturnsEmptyArray() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"default\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenNoEnvironmentProfilesAndBinderProperty() {\n\t\tEnvironment environment = new MockEnvironment();\n\t\tBinder binder = new Binder(\n\t\t\t\tnew MapConfigurationPropertySource(Collections.singletonMap(\"spring.profiles.default\", \"a,b,c\")));\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenDefaultEnvironmentProfileAndBinderProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.default\", \"default\");\n\t\tList<ConfigurationPropertySource> sources = new ArrayList<>();\n\t\tConfigurationPropertySources.get(environment).forEach(sources::add);\n\t\tsources.add(new MapConfigurationPropertySource(Collections.singletonMap(\"spring.profiles.default\", \"a,b,c\")));\n\t\tBinder binder = new Binder(sources);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"default\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenNoEnvironmentProfilesAndEnvironmentProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.default\", \"a,b,c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenEnvironmentProfilesAndBinderProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"a\", \"b\", \"c\");\n\t\tBinder binder = new Binder(\n\t\t\t\tnew MapConfigurationPropertySource(Collections.singletonMap(\"spring.profiles.default\", \"d,e,f\")));\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenEnvironmentProfilesAndEnvironmentProperty() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"a\", \"b\", \"c\");\n\t\tenvironment.setProperty(\"spring.profiles.default\", \"d,e,f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenNoEnvironmentProfilesAndEnvironmentPropertyInBindNotation() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.default[0]\", \"a\");\n\t\tenvironment.setProperty(\"spring.profiles.default[1]\", \"b\");\n\t\tenvironment.setProperty(\"spring.profiles.default[2]\", \"c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenHasDuplicatesReturnsUniqueElements() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.default\", \"a,b,a,b,c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWithProfileGroups() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.default\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"d,e\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"d\", \"e\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getDefaultWhenEnvironmentProfilesInBindNotationAndEnvironmentPropertyReturnsBoth() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"a\", \"b\", \"c\");\n\t\tenvironment.setProperty(\"spring.profiles.default[0]\", \"d\");\n\t\tenvironment.setProperty(\"spring.profiles.default[1]\", \"e\");\n\t\tenvironment.setProperty(\"spring.profiles.default[2]\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getDefault()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid iteratorIteratesAllActiveProfiles() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles1 = new Profiles(environment, binder, null);\n\t\tProfiles profiles = profiles1;\n\t\tassertThat(profiles).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid iteratorIteratesAllDefaultProfilesWhenNoActive() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles1 = new Profiles(environment, binder, null);\n\t\tProfiles profiles = profiles1;\n\t\tassertThat(profiles).containsExactly(\"d\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid isActiveWhenActiveContainsProfileReturnsTrue() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles1 = new Profiles(environment, binder, null);\n\t\tProfiles profiles = profiles1;\n\t\tassertThat(profiles.isAccepted(\"a\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenActiveDoesNotContainProfileReturnsFalse() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setActiveProfiles(\"a\", \"b\", \"c\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles1 = new Profiles(environment, binder, null);\n\t\tProfiles profiles = profiles1;\n\t\tassertThat(profiles.isAccepted(\"x\")).isFalse();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNoActiveAndDefaultContainsProfileReturnsTrue() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles1 = new Profiles(environment, binder, null);\n\t\tProfiles profiles = profiles1;\n\t\tassertThat(profiles.isAccepted(\"d\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isActiveWhenNoActiveAndDefaultDoesNotContainProfileReturnsFalse() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles1 = new Profiles(environment, binder, null);\n\t\tProfiles profiles = profiles1;\n\t\tassertThat(profiles.isAccepted(\"x\")).isFalse();\n\t}\n\n\t@Test\n\tvoid iteratorWithProfileGroups() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"e,f\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"x,y\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles).containsExactly(\"a\", \"e\", \"x\", \"y\", \"f\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid iteratorWithProfileGroupsAndNoActive() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"e,f\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"x,y\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles).containsExactly(\"default\");\n\t}\n\n\t@Test\n\tvoid iteratorWithProfileGroupsForDefault() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.group.default\", \"e,f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles).containsExactly(\"default\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid getAcceptedWithProfileGroups() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"e,f\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"x,y\");\n\t\tenvironment.setDefaultProfiles(\"g\", \"h\", \"i\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getAccepted()).containsExactly(\"a\", \"e\", \"x\", \"y\", \"f\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getAcceptedWhenNoActiveAndDefaultWithGroups() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"x,y\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getAccepted()).containsExactly(\"d\", \"e\", \"x\", \"y\", \"f\");\n\t}\n\n\t@Test\n\tvoid isAcceptedWithGroupsReturnsTrue() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"e,f\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"x,y\");\n\t\tenvironment.setDefaultProfiles(\"g\", \"h\", \"i\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.isAccepted(\"a\")).isTrue();\n\t\tassertThat(profiles.isAccepted(\"e\")).isTrue();\n\t\tassertThat(profiles.isAccepted(\"g\")).isFalse();\n\t}\n\n\t@Test\n\tvoid isAcceptedWhenNoActiveAndDefaultWithGroupsContainsProfileReturnsTrue() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setDefaultProfiles(\"d\", \"e\", \"f\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"x,y\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.isAccepted(\"d\")).isTrue();\n\t\tassertThat(profiles.isAccepted(\"x\")).isTrue();\n\t}\n\n\t@Test\n\tvoid simpleRecursiveReferenceInProfileGroupIgnoresDuplicates() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"a,e,f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getAccepted()).containsExactly(\"a\", \"e\", \"f\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid multipleRecursiveReferenceInProfileGroupIgnoresDuplicates() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"a,b,f\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getAccepted()).containsExactly(\"a\", \"b\", \"f\", \"c\");\n\t}\n\n\t@Test\n\tvoid complexRecursiveReferenceInProfileGroupIgnoresDuplicates() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"a,b,c\");\n\t\tenvironment.setProperty(\"spring.profiles.group.a\", \"e,f,g\");\n\t\tenvironment.setProperty(\"spring.profiles.group.e\", \"a,x,y,g\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getAccepted()).containsExactly(\"a\", \"e\", \"x\", \"y\", \"g\", \"f\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid validNamesArePermitted() {\n\t\tassertValidName(\"spring.profiles.active\", \"ok\");\n\t\tassertValidName(\"spring.profiles.default\", \"ok\");\n\t\tassertValidName(\"spring.profiles.group.a\", \"ok\");\n\t}\n\n\t@Test\n\tvoid invalidNamesAreNotPermitted() {\n\t\tassertInvalidName(\"spring.profiles.active\", \"fa!l\");\n\t\tassertInvalidName(\"spring.profiles.default\", \"fa!l\");\n\t\tassertInvalidName(\"spring.profiles.group.a\", \"fa!l\");\n\t}\n\n\t@Test\n\tvoid invalidNamesWhenValidationDisabledArePermitted() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.validate\", \"false\");\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"fa!l\");\n\t\tBinder binder = Binder.get(environment);\n\t\tProfiles profiles = new Profiles(environment, binder, null);\n\t\tassertThat(profiles.getAccepted()).containsExactly(\"fa!l\");\n\t}\n\n\t@Test\n\tvoid invalidNameInEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.profiles.active\", \"fa!l\");\n\t\tBinder binder = new Binder();\n\t\tassertThatIllegalStateException().isThrownBy(() -> new Profiles(environment, binder, null))\n\t\t\t.withMessage(\"Invalid profile property value found in Environment under 'spring.profiles.active'\");\n\t}\n\n\t@Test\n\tvoid invalidNameInActive() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tBinder binder = new Binder();\n\t\tassertThatIllegalStateException().isThrownBy(() -> new Profiles(environment, binder, Set.of(\"fa!l\")))\n\t\t\t.withMessage(\"Invalid profile property value found in additional profiles\");\n\t}\n\n\tprivate void assertValidName(String name, String value) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(name, value);\n\t\tBinder binder = Binder.get(environment);\n\t\tassertThatNoException().isThrownBy(() -> new Profiles(environment, binder, null));\n\t}\n\n\tprivate void assertInvalidName(String name, String value) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(name, value);\n\t\tBinder binder = Binder.get(environment);\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> new Profiles(environment, binder, null));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/ProfilesValidatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link ProfilesValidator}.\n *\n * @author Phillip Webb\n * @author Sijun Yang\n */\nclass ProfilesValidatorTests {\n\n\tprivate static final Bindable<String> STRING = Bindable.of(String.class);\n\n\tprivate static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);\n\n\tprivate static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable.mapOf(String.class, String.class);\n\n\t@Test\n\tvoid validateWhenValid() {\n\t\tassertValid(\"test\");\n\t\tassertValid(\"dev-test\");\n\t\tassertValid(\"dev-test_123\");\n\t\tassertValid(\"dev-테스트_123\");\n\t\tassertValid(\"d-e_v-t-.e_@@s+t\");\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidThrowsException() {\n\t\tassertInvalid(\"-dev\");\n\t\tassertInvalid(\"_dev\");\n\t\tassertInvalid(\"+dev\");\n\t\tassertInvalid(\".dev\");\n\t\tassertInvalid(\"dev_\");\n\t\tassertInvalid(\"dev*test\");\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidBoundStringThrowsException() {\n\t\tassertInvalid(Map.of(\"profile\", \"dev*test\"), STRING);\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidBoundCollectionThrowsException() {\n\t\tassertInvalid(Map.of(\"profile\", \"dev*test\"), STRING_LIST);\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidBoundCollectionFromIndexedThrowsException() {\n\t\tassertInvalid(Map.of(\"profile[0]\", \"ok,\", \"profile[1]\", \"dev*test\"), STRING_LIST);\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidBoundMapFromIndexedThrowsException() {\n\t\tassertInvalid(Map.of(\"profile.foo\", \"dev*test\"), STRING_STRING_MAP);\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidThrowsUsefulExceptionMessage() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(Map.of(\"profile\", \"b*d\")))\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Profile 'b*d' must contain a letter, digit or allowed char ('-', '_', '.', '+', '@')\");\n\t}\n\n\t@Test\n\tvoid validateWhenInvalidStartCharacterThrowsUsefulExceptionMessage() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(Map.of(\"profile\", \"_bad\")))\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"Profile '_bad' must start and end with a letter or digit\");\n\t}\n\n\t@Test\n\tvoid validateWithWrappedExceptionMessageWhenValid() {\n\t\tassertThatNoException().isThrownBy(() -> ProfilesValidator.get(new Binder()).validate(\"ok\", () -> \"context\"));\n\t}\n\n\t@Test\n\tvoid validateWithWrappedExceptionMessageWhenInvalidThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> ProfilesValidator.get(new Binder()).validate(\"b*d\", () -> \"context\"))\n\t\t\t.withMessage(\"context\")\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"must contain a letter\");\n\t}\n\n\tprivate void assertValid(String value) {\n\t\tassertThatNoException().isThrownBy(() -> bind(Map.of(\"profile\", value)));\n\t}\n\n\tprivate void assertInvalid(String value) {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(Map.of(\"profile\", value)));\n\t}\n\n\tprivate <T> void assertInvalid(Map<String, String> map, Bindable<T> target) {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(map, target));\n\t}\n\n\tprivate void bind(Map<?, ?> map) {\n\t\tbind(map, STRING);\n\t}\n\n\tprivate <T> void bind(Map<?, ?> map, Bindable<T> target) {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tBinder binder = new Binder(source);\n\t\tProfilesValidator validator = ProfilesValidator.get(binder);\n\t\tbinder.bind(\"profile\", target, validator);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StandardConfigDataLoader}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass StandardConfigDataLoaderTests {\n\n\tprivate final StandardConfigDataLoader loader = new StandardConfigDataLoader();\n\n\tprivate final ConfigDataLoaderContext loaderContext = mock(ConfigDataLoaderContext.class);\n\n\t@Test\n\t@WithResource(name = \"application.yml\", content = \"\"\"\n\t\t\tfoo: bar\n\t\t\t---\n\t\t\thello: world\n\t\t\t\"\"\")\n\tvoid loadWhenLocationResultsInMultiplePropertySourcesAddsAllToConfigData() throws IOException {\n\t\tClassPathResource resource = new ClassPathResource(\"application.yml\");\n\t\tStandardConfigDataReference reference = new StandardConfigDataReference(\n\t\t\t\tConfigDataLocation.of(\"classpath:application.yml\"), null, \"classpath:application\", null, \"yml\",\n\t\t\t\tnew YamlPropertySourceLoader(), null);\n\t\tStandardConfigDataResource location = new StandardConfigDataResource(reference, resource);\n\t\tConfigData configData = this.loader.load(this.loaderContext, location);\n\t\tassertThat(configData.getPropertySources()).hasSize(2);\n\t\tPropertySource<?> source1 = configData.getPropertySources().get(0);\n\t\tPropertySource<?> source2 = configData.getPropertySources().get(1);\n\t\tassertThat(source1.getName()).isEqualTo(\"Config resource 'class path resource [application.yml]' \"\n\t\t\t\t+ \"via location 'classpath:application.yml' (document #0)\");\n\t\tassertThat(source1.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(source2.getName()).isEqualTo(\"Config resource 'class path resource [application.yml]' \"\n\t\t\t\t+ \"via location 'classpath:application.yml' (document #1)\");\n\t\tassertThat(source2.getProperty(\"hello\")).isEqualTo(\"world\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"empty.properties\")\n\tvoid loadWhenPropertySourceIsEmptyAddsNothingToConfigData() throws IOException {\n\t\tClassPathResource resource = new ClassPathResource(\"empty.properties\");\n\t\tStandardConfigDataReference reference = new StandardConfigDataReference(\n\t\t\t\tConfigDataLocation.of(\"empty.properties\"), null, \"empty\", null, \"properties\",\n\t\t\t\tnew PropertiesPropertySourceLoader(), null);\n\t\tStandardConfigDataResource location = new StandardConfigDataResource(reference, resource);\n\t\tConfigData configData = this.loader.load(this.loaderContext, location);\n\t\tassertThat(configData.getPropertySources()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataLocationResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.logging.DeferredLogs;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcesRoot;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StandardConfigDataLocationResolver}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Sijun Yang\n */\nclass StandardConfigDataLocationResolverTests {\n\n\tprivate StandardConfigDataLocationResolver resolver;\n\n\tprivate final ConfigDataLocationResolverContext context = mock(ConfigDataLocationResolverContext.class);\n\n\tprivate MockEnvironment environment;\n\n\tprivate Binder environmentBinder;\n\n\tprivate final ResourceLoader resourceLoader = new DefaultResourceLoader();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environmentBinder = Binder.get(this.environment);\n\t\tthis.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,\n\t\t\t\tthis.resourceLoader);\n\t}\n\n\t@Test\n\tvoid isResolvableAlwaysReturnsTrue() {\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"test\"))).isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"configdata/application.properties\")\n\tvoid resolveWhenLocationIsDirectoryResolvesAllMatchingFilesInDirectory() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"classpath:/configdata/\");\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.containsExactly(\"class path resource [configdata/application.properties]\");\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationIsFileResolvesFile() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"file:configdata/application.properties\");\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.containsExactly(filePath(\"configdata\", \"application.properties\"));\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationIsFileAndNoMatchingLoaderThrowsException() {\n\t\tConfigDataLocation location = ConfigDataLocation\n\t\t\t.of(\"file:src/test/resources/configdata/properties/application.unknown\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))\n\t\t\t.withMessageStartingWith(\"Unable to load config data from\")\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).hasMessageStartingWith(\"File extension is not known\"));\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationHasUnknownPrefixAndNoMatchingLoaderThrowsException() {\n\t\tConfigDataLocation location = ConfigDataLocation\n\t\t\t.of(\"typo:src/test/resources/configdata/properties/application.unknown\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))\n\t\t\t.withMessageStartingWith(\"Unable to load config data from\")\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).hasMessageStartingWith(\n\t\t\t\t\t\"Incorrect ConfigDataLocationResolver chosen or file extension is not known to any PropertySourceLoader\"));\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationWildcardIsSpecifiedForClasspathLocationThrowsException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"classpath*:application.properties\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))\n\t\t\t.withMessageContaining(\"Location 'classpath*:application.properties' cannot use classpath wildcards\");\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationWildcardIsNotBeforeLastSlashThrowsException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"file:src/test/resources/*/config/\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))\n\t\t\t.withMessageStartingWith(\"Location '\")\n\t\t\t.withMessageEndingWith(\"' must end with '*/'\");\n\t}\n\n\t@Test\n\tvoid createWhenConfigNameHasWildcardThrowsException() {\n\t\tthis.environment.setProperty(\"spring.config.name\", \"*/application\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,\n\t\t\t\t\tthis.resourceLoader))\n\t\t\t.withMessageStartingWith(\"Config name '\")\n\t\t\t.withMessageEndingWith(\"' cannot contain '*'\");\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationHasMultipleWildcardsThrowsException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"file:src/test/resources/config/**/\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))\n\t\t\t.withMessageStartingWith(\"Location '\")\n\t\t\t.withMessageEndingWith(\"' cannot contain multiple wildcards\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"config/0-empty/testproperties.properties\")\n\t@WithResource(name = \"config/1-first/testproperties.properties\", content = \"first.property=apple\")\n\t@WithResource(name = \"config/2-second/testproperties.properties\", content = \"second.property=ball\")\n\t@WithResource(name = \"config/nested/3-third/testproperties.properties\", content = \"third.property=shouldnotbefound\")\n\tvoid resolveWhenLocationIsWildcardDirectoriesRestrictsToOneLevelDeep(@ResourcesRoot Path resourcesRoot) {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"file:\" + resourcesRoot + \"/config/*/\");\n\t\tthis.environment.setProperty(\"spring.config.name\", \"testproperties\");\n\t\tthis.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,\n\t\t\t\tthis.resourceLoader);\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(3);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.contains(filePath(resourcesRoot.resolve(\"config/1-first/testproperties.properties\")))\n\t\t\t.contains(filePath(resourcesRoot.resolve(\"config/2-second/testproperties.properties\")))\n\t\t\t.doesNotContain(filePath(resourcesRoot.resolve(\"config/nested/3-third/testproperties.properties\")));\n\t}\n\n\t@Test\n\t@WithResource(name = \"config/0-empty/testproperties.properties\")\n\t@WithResource(name = \"config/1-first/testproperties.properties\", content = \"first.property=apple\")\n\t@WithResource(name = \"config/2-second/testproperties.properties\", content = \"second.property=ball\")\n\t@WithResource(name = \"config/nested/3-third/testproperties.properties\", content = \"third.property=shouldnotbefound\")\n\tvoid resolveWhenLocationIsWildcardDirectoriesSortsAlphabeticallyBasedOnFixedPath(\n\t\t\t@ResourcesRoot Path resourcesRoot) {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"file:\" + resourcesRoot + \"/config/*/\");\n\t\tthis.environment.setProperty(\"spring.config.name\", \"testproperties\");\n\t\tthis.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,\n\t\t\t\tthis.resourceLoader);\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.containsExactly(filePath(resourcesRoot.resolve(\"config/0-empty/testproperties.properties\")),\n\t\t\t\t\tfilePath(resourcesRoot.resolve(\"config/1-first/testproperties.properties\")),\n\t\t\t\t\tfilePath(resourcesRoot.resolve(\"config/2-second/testproperties.properties\")));\n\t}\n\n\t@Test\n\t@WithResource(name = \"config/0-empty/testproperties.properties\")\n\t@WithResource(name = \"config/1-first/testproperties.properties\", content = \"first.property=apple\")\n\t@WithResource(name = \"config/2-second/testproperties.properties\", content = \"second.property=ball\")\n\t@WithResource(name = \"config/nested/3-third/testproperties.properties\", content = \"third.property=shouldnotbefound\")\n\tvoid resolveWhenLocationIsWildcardFilesLoadsAllFilesThatMatch(@ResourcesRoot Path resourcesRoot) {\n\t\tConfigDataLocation location = ConfigDataLocation\n\t\t\t.of(\"file:\" + resourcesRoot + \"/config/*/testproperties.properties\");\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(3);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.contains(filePath(resourcesRoot.resolve(\"config/1-first/testproperties.properties\")))\n\t\t\t.contains(filePath(resourcesRoot.resolve(\"config/2-second/testproperties.properties\")))\n\t\t\t.doesNotContain(filePath(resourcesRoot.resolve(\"config/nested/3-third/testproperties.properties\")));\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationIsRelativeAndFileResolves() {\n\t\tthis.environment.setProperty(\"spring.config.name\", \"other\");\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"other.properties\");\n\t\tthis.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,\n\t\t\t\tthis.resourceLoader);\n\t\tStandardConfigDataReference parentReference = new StandardConfigDataReference(\n\t\t\t\tConfigDataLocation.of(\"classpath:configdata/properties/application.properties\"), null,\n\t\t\t\t\"classpath:configdata/properties/application\", null, \"properties\", new PropertiesPropertySourceLoader(),\n\t\t\t\tnull);\n\t\tClassPathResource parentResource = new ClassPathResource(\"configdata/properties/application.properties\");\n\t\tStandardConfigDataResource parent = new StandardConfigDataResource(parentReference, parentResource);\n\t\tgiven(this.context.getParent()).willReturn(parent);\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.contains(\"class path resource [configdata/properties/other.properties]\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"config/specific.properties\")\n\t@WithResource(name = \"config/nested/3-third/testproperties.properties\")\n\tvoid resolveWhenLocationIsRelativeAndDirectoryResolves() {\n\t\tthis.environment.setProperty(\"spring.config.name\", \"testproperties\");\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"nested/3-third/\");\n\t\tthis.resolver = new StandardConfigDataLocationResolver(new DeferredLogs(), this.environmentBinder,\n\t\t\t\tthis.resourceLoader);\n\t\tStandardConfigDataReference parentReference = new StandardConfigDataReference(\n\t\t\t\tConfigDataLocation.of(\"optional:classpath:configdata/\"), null, \"classpath:config/specific\", null,\n\t\t\t\t\"properties\", new PropertiesPropertySourceLoader(), null);\n\t\tClassPathResource parentResource = new ClassPathResource(\"config/specific.properties\");\n\t\tStandardConfigDataResource parent = new StandardConfigDataResource(parentReference, parentResource);\n\t\tgiven(this.context.getParent()).willReturn(parent);\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.contains(\"class path resource [config/nested/3-third/testproperties.properties]\");\n\t}\n\n\t@Test\n\tvoid resolveWhenLocationIsRelativeAndNoMatchingLoaderThrowsException() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"application.other\");\n\t\tStandardConfigDataReference parentReference = new StandardConfigDataReference(\n\t\t\t\tConfigDataLocation.of(\"classpath:configdata/properties/application.properties\"), null,\n\t\t\t\t\"configdata/properties/application\", null, \"properties\", new PropertiesPropertySourceLoader(), null);\n\t\tClassPathResource parentResource = new ClassPathResource(\"configdata/properties/application.properties\");\n\t\tStandardConfigDataResource parent = new StandardConfigDataResource(parentReference, parentResource);\n\t\tgiven(this.context.getParent()).willReturn(parent);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(this.context, location))\n\t\t\t.withMessageStartingWith(\"Unable to load config data from 'application.other'\")\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).hasMessageStartingWith(\"File extension is not known\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-props-no-extension\", content = \"withnoextension=test\")\n\tvoid resolveWhenLocationUsesOptionalExtensionSyntaxResolves() throws Exception {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"classpath:/application-props-no-extension[.properties]\");\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tStandardConfigDataResource resolved = locations.get(0);\n\t\tassertThat(resolved.getResource().getFilename()).endsWith(\"application-props-no-extension\");\n\t\tConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved);\n\t\tPropertySource<?> propertySource = loaded.getPropertySources().get(0);\n\t\tassertThat(propertySource.getProperty(\"withnoextension\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-props-no-extension\", content = \"withnoextension=test\")\n\tvoid resolveWhenLocationUsesOptionalExplicitExtensionSyntaxResolves() throws Exception {\n\t\tConfigDataLocation location = ConfigDataLocation\n\t\t\t.of(\"classpath:/application-props-no-extension[extension=.properties]\");\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tStandardConfigDataResource resolved = locations.get(0);\n\t\tassertThat(resolved.getResource().getFilename()).endsWith(\"application-props-no-extension\");\n\t\tConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved);\n\t\tPropertySource<?> propertySource = loaded.getPropertySources().get(0);\n\t\tassertThat(propertySource.getProperty(\"withnoextension\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"utf-8.properties\", content = \"smiley=😃\")\n\tvoid resolveWhenLocationUsesEncodingSyntaxResolves() throws IOException {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"classpath:utf-8.properties[encoding=utf-8]\");\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolve(this.context, location);\n\t\tassertThat(locations).hasSize(1);\n\t\tStandardConfigDataResource resolved = locations.get(0);\n\t\tassertThat(resolved.getReference().getEncoding()).isEqualTo(StandardCharsets.UTF_8);\n\t\tConfigData loaded = new StandardConfigDataLoader().load(mock(ConfigDataLoaderContext.class), resolved);\n\t\tPropertySource<?> propertySource = loaded.getPropertySources().get(0);\n\t\tassertThat(propertySource.getProperty(\"smiley\")).isEqualTo(\"😃\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-dev.properties\")\n\tvoid resolveProfileSpecificReturnsProfileSpecificFiles() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"classpath:/\");\n\t\tthis.environment.setActiveProfiles(\"dev\");\n\t\tProfiles profiles = new Profiles(this.environment, this.environmentBinder, Collections.emptyList());\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolveProfileSpecific(this.context, location,\n\t\t\t\tprofiles);\n\t\tassertThat(locations).hasSize(1);\n\t\tassertThat(locations).extracting(Object::toString)\n\t\t\t.containsExactly(\"class path resource [application-dev.properties]\");\n\t}\n\n\t@Test\n\tvoid resolveProfileSpecificWhenLocationIsFileReturnsEmptyList() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"classpath:/configdata/properties/application.properties\");\n\t\tProfiles profiles = mock(Profiles.class);\n\t\tgiven(profiles.iterator()).willReturn(Collections.emptyIterator());\n\t\tgiven(profiles.getActive()).willReturn(Collections.singletonList(\"dev\"));\n\t\tList<StandardConfigDataResource> locations = this.resolver.resolveProfileSpecific(this.context, location,\n\t\t\t\tprofiles);\n\t\tassertThat(locations).isEmpty();\n\t}\n\n\t@Test\n\tvoid resolveWhenOptionalAndLoaderIsUnknownShouldNotFail() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:some-unknown-loader:dummy.properties\");\n\t\tassertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));\n\t}\n\n\t@Test\n\tvoid resolveWhenOptionalAndLoaderIsUnknownAndExtensionIsUnknownShouldNotFail() {\n\t\tConfigDataLocation location = ConfigDataLocation\n\t\t\t.of(\"optional:some-unknown-loader:dummy.some-unknown-extension\");\n\t\tassertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));\n\t}\n\n\t@Test\n\tvoid resolveWhenOptionalAndExtensionIsUnknownShouldNotFail() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:file:dummy.some-unknown-extension\");\n\t\tassertThatNoException().isThrownBy(() -> this.resolver.resolve(this.context, location));\n\t}\n\n\tprivate String filePath(String... components) {\n\t\treturn \"file [\" + String.join(File.separator, components) + \"]\";\n\t}\n\n\tprivate String filePath(Path path) {\n\t\treturn \"file [%s]\".formatted(path);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/StandardConfigDataResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.FileUrlResource;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StandardConfigDataResource}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass StandardConfigDataResourceTests {\n\n\tStandardConfigDataReference reference = mock(StandardConfigDataReference.class);\n\n\tprivate final Resource resource = mock(Resource.class);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenReferenceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new StandardConfigDataResource(null, this.resource))\n\t\t\t.withMessage(\"'reference' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResourceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new StandardConfigDataResource(this.reference, null))\n\t\t\t.withMessage(\"'resource' must not be null\");\n\t}\n\n\t@Test\n\tvoid equalsWhenResourceIsTheSameReturnsTrue() {\n\t\tResource resource = new ClassPathResource(\"config/\");\n\t\tStandardConfigDataResource location = new StandardConfigDataResource(this.reference, resource);\n\t\tStandardConfigDataResource other = new StandardConfigDataResource(this.reference, resource);\n\t\tassertThat(location).isEqualTo(other);\n\t}\n\n\t@Test\n\tvoid equalsWhenResourceIsDifferentReturnsFalse() {\n\t\tResource resource1 = new ClassPathResource(\"config/\");\n\t\tResource resource2 = new ClassPathResource(\"configdata/\");\n\t\tStandardConfigDataResource location = new StandardConfigDataResource(this.reference, resource1);\n\t\tStandardConfigDataResource other = new StandardConfigDataResource(this.reference, resource2);\n\t\tassertThat(location).isNotEqualTo(other);\n\t}\n\n\t@Test // gh-34212\n\t@WithResource(name = \"test.resource\", content = \"test\")\n\tvoid equalsAndHashCodeWhenSameUnderlyingResource(@ResourcePath(\"test.resource\") Path path) throws IOException {\n\t\tPath directory = path.getParent();\n\t\tassertThat(directory).isNotNull();\n\t\tURLClassLoader classLoader = new URLClassLoader(new URL[] { directory.toUri().toURL() },\n\t\t\t\tgetClass().getClassLoader());\n\t\tClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\ttry {\n\t\t\tClassPathResource classResource = new ClassPathResource(\"test.resource\", classLoader);\n\t\t\tFileUrlResource fileResource = new FileUrlResource(classResource.getURL());\n\t\t\tConfigDataResource classDataResource = new StandardConfigDataResource(this.reference, classResource);\n\t\t\tConfigDataResource fileDataResource = new StandardConfigDataResource(this.reference, fileResource);\n\t\t\tassertThat(classDataResource).isEqualTo(fileDataResource);\n\t\t\tassertThat(classDataResource).hasSameHashCodeAs(fileDataResource);\n\t\t}\n\t\tfinally {\n\t\t\tThread.currentThread().setContextClassLoader(contextClassLoader);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/SystemEnvironmentConfigDataLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SystemEnvironmentConfigDataLoader}.\n *\n * @author Moritz Halbritter\n */\nclass SystemEnvironmentConfigDataLoaderTests {\n\n\tprivate ConfigDataLoaderContext context;\n\n\tprivate Map<String, String> environment;\n\n\tprivate SystemEnvironmentConfigDataLoader loader;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.context = mock(ConfigDataLoaderContext.class);\n\t\tthis.environment = new HashMap<>();\n\t\tthis.loader = new SystemEnvironmentConfigDataLoader();\n\t}\n\n\t@Test\n\tvoid loadLoadsConfigData() throws IOException {\n\t\tthis.environment.put(\"VAR1\", \"key1=value1\");\n\t\tConfigData data = this.loader.load(this.context, createResource(\"VAR1\"));\n\t\tassertThat(data.getPropertySources()).hasSize(1);\n\t\tPropertySource<?> propertySource = data.getPropertySources().get(0);\n\t\tassertThat(propertySource.getProperty(\"key1\")).isEqualTo(\"value1\");\n\t}\n\n\t@Test\n\tvoid loadWhenNoContentThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataResourceNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.loader.load(this.context, createResource(\"VAR1\")))\n\t\t\t.withMessage(\"Config data resource 'system environment variable [VAR1] content \"\n\t\t\t\t\t+ \"loaded using PropertiesPropertySourceLoader' cannot be found\");\n\t}\n\n\tprivate SystemEnvironmentConfigDataResource createResource(String variableName) {\n\t\treturn new SystemEnvironmentConfigDataResource(variableName, new PropertiesPropertySourceLoader(),\n\t\t\t\tthis.environment::get, null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/SystemEnvironmentConfigDataLocationResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SystemEnvironmentConfigDataLocationResolver}.\n *\n * @author Moritz Halbritter\n */\nclass SystemEnvironmentConfigDataLocationResolverTests {\n\n\tprivate SystemEnvironmentConfigDataLocationResolver resolver;\n\n\tprivate Map<String, String> environment;\n\n\tprivate ConfigDataLocationResolverContext context;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.context = mock(ConfigDataLocationResolverContext.class);\n\t\tthis.environment = new HashMap<>();\n\t\tthis.resolver = new SystemEnvironmentConfigDataLocationResolver(\n\t\t\t\tList.of(new PropertiesPropertySourceLoader(), new YamlPropertySourceLoader()), this.environment::get);\n\t}\n\n\t@Test\n\tvoid isResolvable() {\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"env:VAR1\"))).isTrue();\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"dummy:VAR1\"))).isFalse();\n\t\tassertThat(this.resolver.isResolvable(this.context, ConfigDataLocation.of(\"VAR1\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid resolveResolves() {\n\t\tthis.environment.put(\"VAR1\", \"VALUE1\");\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"env:VAR1\");\n\t\tList<SystemEnvironmentConfigDataResource> resolved = this.resolver.resolve(this.context, location);\n\t\tassertThat(resolved).hasSize(1);\n\t\tSystemEnvironmentConfigDataResource resource = resolved.get(0);\n\t\tassertThat(resource.getVariableName()).isEqualTo(\"VAR1\");\n\t\tassertThat(resource.getLoader()).isInstanceOf(PropertiesPropertySourceLoader.class);\n\t}\n\n\t@Test\n\tvoid resolveWhenHasNoVariableThrowsException() {\n\t\tassertThatExceptionOfType(ConfigDataLocationNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.resolver.resolve(this.context, ConfigDataLocation.of(\"env:VAR1\")))\n\t\t\t.withMessage(\"Environment variable 'VAR1' is not set\");\n\t}\n\n\t@Test\n\tvoid resolveWhenOptionalAndHasVariableResolves() {\n\t\tthis.environment.put(\"VAR1\", \"VALUE1\");\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:env:VAR1\");\n\t\tList<SystemEnvironmentConfigDataResource> resolved = this.resolver.resolve(this.context, location);\n\t\tassertThat(resolved).hasSize(1);\n\t\tSystemEnvironmentConfigDataResource resource = resolved.get(0);\n\t\tassertThat(resource.getVariableName()).isEqualTo(\"VAR1\");\n\t\tassertThat(resource.getLoader()).isInstanceOf(PropertiesPropertySourceLoader.class);\n\t}\n\n\t@Test\n\tvoid resolveWhenOptionalAndHasNoVariableResolvesEmpty() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"optional:env:VAR1\");\n\t\tList<SystemEnvironmentConfigDataResource> resolved = this.resolver.resolve(this.context, location);\n\t\tassertThat(resolved).isEmpty();\n\t}\n\n\t@Test\n\tvoid resolveWhenHasPropertiesExtensionHintResolves() {\n\t\tthis.environment.put(\"VAR1\", \"VALUE1\");\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"env:VAR1[.properties]\");\n\t\tList<SystemEnvironmentConfigDataResource> resolved = this.resolver.resolve(this.context, location);\n\t\tassertThat(resolved).hasSize(1);\n\t\tSystemEnvironmentConfigDataResource resource = resolved.get(0);\n\t\tassertThat(resource.getVariableName()).isEqualTo(\"VAR1\");\n\t\tassertThat(resource.getLoader()).isInstanceOf(PropertiesPropertySourceLoader.class);\n\t}\n\n\t@Test\n\tvoid resolveWhenHasYamlExtensionHintResolves() {\n\t\tthis.environment.put(\"VAR1\", \"VALUE1\");\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"env:VAR1[.yaml]\");\n\t\tList<SystemEnvironmentConfigDataResource> resolved = this.resolver.resolve(this.context, location);\n\t\tassertThat(resolved).hasSize(1);\n\t\tSystemEnvironmentConfigDataResource resource = resolved.get(0);\n\t\tassertThat(resource.getVariableName()).isEqualTo(\"VAR1\");\n\t\tassertThat(resource.getLoader()).isInstanceOf(YamlPropertySourceLoader.class);\n\t}\n\n\t@Test\n\tvoid resolveWhenHasUnknownExtensionHintThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.resolver.resolve(this.context, ConfigDataLocation.of(\"env:VAR1[.dummy]\")))\n\t\t\t.withMessage(\"File extension 'dummy' is not known to any PropertySourceLoader\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/SystemEnvironmentConfigDataResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SystemEnvironmentConfigDataResource}.\n *\n * @author Moritz Halbritter\n */\nclass SystemEnvironmentConfigDataResourceTests {\n\n\tprivate Map<String, String> environment = new HashMap<>();\n\n\tprivate final YamlPropertySourceLoader yamlLoader = new YamlPropertySourceLoader();\n\n\tprivate final PropertiesPropertySourceLoader propertiesLoader = new PropertiesPropertySourceLoader();\n\n\t@Test\n\tvoid loadLoadsPropertySources() throws IOException {\n\t\tthis.environment.put(\"VAR1\", \"key1=value1\");\n\t\tList<PropertySource<?>> loaded = createResource(\"VAR1\").load();\n\t\tassertThat(loaded).hasSize(1);\n\t\tassertThat(loaded.get(0).getProperty(\"key1\")).isEqualTo(\"value1\");\n\t}\n\n\t@Test\n\tvoid loadWhenNoContentReturnsNull() throws IOException {\n\t\tList<PropertySource<?>> loaded = createResource(\"VAR1\").load();\n\t\tassertThat(loaded).isNull();\n\t}\n\n\t@Test\n\tvoid equalsAndHashcode() {\n\t\tSystemEnvironmentConfigDataResource var1 = createResource(\"VAR1\");\n\t\tSystemEnvironmentConfigDataResource var2 = createResource(\"VAR2\");\n\t\tSystemEnvironmentConfigDataResource var3 = createResource(\"VAR1\", this.yamlLoader);\n\t\tSystemEnvironmentConfigDataResource var4 = createResource(\"VAR1\");\n\t\tassertThat(var1).isNotEqualTo(var2);\n\t\tassertThat(var1).isNotEqualTo(var3);\n\t\tassertThat(var1).isEqualTo(var4);\n\t\tassertThat(var1).hasSameHashCodeAs(var4);\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tSystemEnvironmentConfigDataResource resource = createResource(\"VAR1\");\n\t\tassertThat(resource)\n\t\t\t.hasToString(\"system environment variable [VAR1] content loaded using PropertiesPropertySourceLoader\");\n\t}\n\n\tprivate SystemEnvironmentConfigDataResource createResource(String variableName) {\n\t\treturn createResource(variableName, this.propertiesLoader);\n\t}\n\n\tprivate SystemEnvironmentConfigDataResource createResource(String variableName,\n\t\t\tPropertySourceLoader propertySourceLoader) {\n\t\treturn new SystemEnvironmentConfigDataResource(variableName, propertySourceLoader, this.environment::get, null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataBootstrap.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.BootstrapContextClosedEvent;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.env.MapPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test classes used with\n * {@link ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests} to show how\n * a bootstrap registry can be used. This example will create helper instances during\n * result and load. It also shows how the helper can ultimately be registered as a bean.\n *\n * @author Phillip Webb\n */\nclass TestConfigDataBootstrap {\n\n\tstatic class LocationResolver implements ConfigDataLocationResolver<Resource> {\n\n\t\t@Override\n\t\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\tcontext.getBootstrapContext().get(Binder.class); // gh-24559\n\t\t\treturn location.hasPrefix(\"testbootstrap:\");\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Resource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\t\tcontext.getBootstrapContext()\n\t\t\t\t.registerIfAbsent(ResolverHelper.class, InstanceSupplier.from(() -> new ResolverHelper(location)));\n\t\t\tResolverHelper helper = context.getBootstrapContext().get(ResolverHelper.class);\n\t\t\tassertThat(helper).isNotNull();\n\t\t\treturn Collections.singletonList(new Resource(helper));\n\t\t}\n\n\t}\n\n\tstatic class Loader implements ConfigDataLoader<Resource> {\n\n\t\t@Override\n\t\tpublic ConfigData load(ConfigDataLoaderContext context, Resource location) throws IOException {\n\t\t\tcontext.getBootstrapContext()\n\t\t\t\t.registerIfAbsent(LoaderHelper.class,\n\t\t\t\t\t\t(bootstrapContext) -> new LoaderHelper(location, () -> bootstrapContext.get(Binder.class)));\n\t\t\tLoaderHelper helper = context.getBootstrapContext().get(LoaderHelper.class);\n\t\t\tassertThat(helper).isNotNull();\n\t\t\tcontext.getBootstrapContext().addCloseListener(helper);\n\t\t\treturn new ConfigData(\n\t\t\t\t\tCollections.singleton(new MapPropertySource(\"loaded\", Collections.singletonMap(\"test\", \"test\"))));\n\t\t}\n\n\t}\n\n\tstatic class Resource extends ConfigDataResource {\n\n\t\tprivate final ResolverHelper resolverHelper;\n\n\t\tResource(ResolverHelper resolverHelper) {\n\t\t\tthis.resolverHelper = resolverHelper;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t\tResolverHelper getResolverHelper() {\n\t\t\treturn this.resolverHelper;\n\t\t}\n\n\t}\n\n\tstatic class ResolverHelper {\n\n\t\tprivate final ConfigDataLocation location;\n\n\t\tResolverHelper(ConfigDataLocation location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tConfigDataLocation getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t}\n\n\tstatic class LoaderHelper implements ApplicationListener<BootstrapContextClosedEvent> {\n\n\t\tprivate final Resource location;\n\n\t\tprivate final Supplier<Binder> binder;\n\n\t\tLoaderHelper(Resource location, Supplier<Binder> binder) {\n\t\t\tthis.location = location;\n\t\t\tthis.binder = binder;\n\t\t}\n\n\t\tResource getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\t@Nullable String getBound() {\n\t\t\treturn this.binder.get().bind(\"myprop\", String.class).orElse(null);\n\t\t}\n\n\t\t@Nullable String getProfileBound() {\n\t\t\treturn this.binder.get().bind(\"myprofileprop\", String.class).orElse(null);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(BootstrapContextClosedEvent event) {\n\t\t\tevent.getApplicationContext().getBeanFactory().registerSingleton(\"loaderHelper\", this);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataEnvironmentUpdateListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertySource;\n\nclass TestConfigDataEnvironmentUpdateListener implements ConfigDataEnvironmentUpdateListener {\n\n\tprivate final List<AddedPropertySource> addedPropertySources = new ArrayList<>();\n\n\tprivate @Nullable Profiles profiles;\n\n\t@Override\n\tpublic void onPropertySourceAdded(PropertySource<?> propertySource, @Nullable ConfigDataLocation location,\n\t\t\t@Nullable ConfigDataResource resource) {\n\t\tthis.addedPropertySources.add(new AddedPropertySource(propertySource, location, resource));\n\t}\n\n\t@Override\n\tpublic void onSetProfiles(Profiles profiles) {\n\t\tthis.profiles = profiles;\n\t}\n\n\tList<AddedPropertySource> getAddedPropertySources() {\n\t\treturn Collections.unmodifiableList(this.addedPropertySources);\n\t}\n\n\t@Nullable Profiles getProfiles() {\n\t\treturn this.profiles;\n\t}\n\n\tstatic class AddedPropertySource {\n\n\t\tprivate final PropertySource<?> propertySource;\n\n\t\tprivate final @Nullable ConfigDataLocation location;\n\n\t\tprivate final @Nullable ConfigDataResource resource;\n\n\t\tAddedPropertySource(PropertySource<?> propertySource, @Nullable ConfigDataLocation location,\n\t\t\t\t@Nullable ConfigDataResource resource) {\n\t\t\tthis.propertySource = propertySource;\n\t\t\tthis.location = location;\n\t\t\tthis.resource = resource;\n\t\t}\n\n\t\tPropertySource<?> getPropertySource() {\n\t\t\treturn this.propertySource;\n\t\t}\n\n\t\t@Nullable ConfigDataLocation getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\t@Nullable ConfigDataResource getResource() {\n\t\t\treturn this.resource;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/TestPropertySourceLoader1.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link PropertySourceLoader} for tests.\n *\n * @author Madhura Bhave\n */\nclass TestPropertySourceLoader1 implements PropertySourceLoader {\n\n\t@Override\n\tpublic String[] getFileExtensions() {\n\t\treturn new String[] { \"custom\" };\n\t}\n\n\t@Override\n\tpublic List<PropertySource<?>> load(String name, Resource resource) throws IOException {\n\t\tMap<String, Object> map = Collections.singletonMap(\"customloader1\", \"true\");\n\t\treturn Collections.singletonList(new MapPropertySource(name, map));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/TestPropertySourceLoader2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link PropertySourceLoader} for tests.\n *\n * @author Madhura Bhave\n */\nclass TestPropertySourceLoader2 implements PropertySourceLoader {\n\n\t@Override\n\tpublic String[] getFileExtensions() {\n\t\treturn new String[] { \"custom\" };\n\t}\n\n\t@Override\n\tpublic List<PropertySource<?>> load(String name, Resource resource) throws IOException {\n\t\tMap<String, Object> map = Collections.singletonMap(\"customloader2\", \"true\");\n\t\treturn Collections.singletonList(new MapPropertySource(name, map));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/config/UnsupportedConfigDataLocationExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UnsupportedConfigDataLocationException}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass UnsupportedConfigDataLocationExceptionTests {\n\n\t@Test\n\tvoid createSetsMessage() {\n\t\tUnsupportedConfigDataLocationException exception = new UnsupportedConfigDataLocationException(\n\t\t\t\tConfigDataLocation.of(\"test\"));\n\t\tassertThat(exception).hasMessage(\"Unsupported config data location 'test'\");\n\t}\n\n\t@Test\n\tvoid getLocationReturnsLocation() {\n\t\tConfigDataLocation location = ConfigDataLocation.of(\"test\");\n\t\tUnsupportedConfigDataLocationException exception = new UnsupportedConfigDataLocationException(location);\n\t\tassertThat(exception.getLocation()).isEqualTo(location);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/annotation/MetaComponentScan.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.ComponentScan;\n\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\n@ComponentScan\npublic @interface MetaComponentScan {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/annotation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.configwarnings.annotation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/InDefaultPackageConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan\npublic class InDefaultPackageConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/InDefaultPackageWithBasePackageClassesConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.springframework.boot.context.configwarnings.real.nested.ExampleBean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan(basePackageClasses = ExampleBean.class)\npublic class InDefaultPackageWithBasePackageClassesConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/InDefaultPackageWithBasePackagesConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan(basePackages = \"org.springframework.boot.context.configwarnings.nested\")\npublic class InDefaultPackageWithBasePackagesConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/InDefaultPackageWithMetaAnnotationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.springframework.boot.context.configwarnings.annotation.MetaComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@MetaComponentScan\npublic class InDefaultPackageWithMetaAnnotationConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/InDefaultPackageWithValueConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan(\"org.springframework.boot.context.configwarnings.nested\")\npublic class InDefaultPackageWithValueConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/InDefaultPackageWithoutScanConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class InDefaultPackageWithoutScanConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/dflt/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.configwarnings.dflt;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/orgspring/InOrgSpringPackageConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.orgspring;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan\npublic class InOrgSpringPackageConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/orgspring/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.configwarnings.orgspring;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/real/InRealButScanningProblemPackages.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.real;\n\nimport org.springframework.boot.context.configwarnings.dflt.InDefaultPackageConfiguration;\nimport org.springframework.boot.context.configwarnings.orgspring.InOrgSpringPackageConfiguration;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan(basePackageClasses = { InDefaultPackageConfiguration.class, InOrgSpringPackageConfiguration.class })\npublic class InRealButScanningProblemPackages {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/real/InRealPackageConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.real;\n\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@ComponentScan\npublic class InRealPackageConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/real/nested/ExampleBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.configwarnings.real.nested;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ExampleBean {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/real/nested/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.configwarnings.real.nested;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/configwarnings/real/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.configwarnings.real;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/event/EventPublishingRunListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.event;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EventPublishingRunListener}\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass EventPublishingRunListenerTests {\n\n\tprivate static final String[] NO_ARGS = new String[0];\n\n\t@Test\n\tvoid shouldPublishLifecycleEvents() {\n\t\tDefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\t\tStaticApplicationContext context = new StaticApplicationContext();\n\t\tTestApplicationListener applicationListener = new TestApplicationListener();\n\t\tSpringApplication application = mock(SpringApplication.class);\n\t\tgiven(application.getListeners()).willReturn(Collections.singleton(applicationListener));\n\t\tEventPublishingRunListener publishingListener = new EventPublishingRunListener(application, NO_ARGS);\n\t\tapplicationListener.assertReceivedNoEvents();\n\t\tpublishingListener.starting(bootstrapContext);\n\t\tapplicationListener.assertReceivedEvent(ApplicationStartingEvent.class);\n\t\tpublishingListener.environmentPrepared(bootstrapContext, new MockEnvironment());\n\t\tapplicationListener.assertReceivedEvent(ApplicationEnvironmentPreparedEvent.class);\n\t\tpublishingListener.contextPrepared(context);\n\t\tapplicationListener.assertReceivedEvent(ApplicationContextInitializedEvent.class);\n\t\tpublishingListener.contextLoaded(context);\n\t\tapplicationListener.assertReceivedEvent(ApplicationPreparedEvent.class);\n\t\tcontext.refresh();\n\t\tpublishingListener.started(context, null);\n\t\tapplicationListener.assertReceivedEvent(ApplicationStartedEvent.class, AvailabilityChangeEvent.class);\n\t\tpublishingListener.ready(context, null);\n\t\tapplicationListener.assertReceivedEvent(ApplicationReadyEvent.class, AvailabilityChangeEvent.class);\n\t}\n\n\t@Test\n\tvoid initialEventListenerCanAddAdditionalListenersToApplication() {\n\t\tSpringApplication application = new SpringApplication();\n\t\tDefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tTestApplicationListener lateAddedApplicationListener = new TestApplicationListener();\n\t\tApplicationListener<ApplicationStartingEvent> listener = (event) -> event.getSpringApplication()\n\t\t\t.addListeners(lateAddedApplicationListener);\n\t\tapplication.addListeners(listener);\n\t\tEventPublishingRunListener runListener = new EventPublishingRunListener(application, NO_ARGS);\n\t\trunListener.starting(bootstrapContext);\n\t\trunListener.environmentPrepared(bootstrapContext, environment);\n\t\tlateAddedApplicationListener.assertReceivedEvent(ApplicationEnvironmentPreparedEvent.class);\n\t}\n\n\tstatic class TestApplicationListener implements ApplicationListener<ApplicationEvent> {\n\n\t\tprivate final Deque<ApplicationEvent> events = new ArrayDeque<>();\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tthis.events.add(event);\n\t\t}\n\n\t\tvoid assertReceivedNoEvents() {\n\t\t\tassertThat(this.events).isEmpty();\n\t\t}\n\n\t\tvoid assertReceivedEvent(Class<?>... eventClasses) {\n\t\t\tList<ApplicationEvent> receivedEvents = new ArrayList<>();\n\t\t\twhile (!this.events.isEmpty()) {\n\t\t\t\treceivedEvents.add(this.events.pollFirst());\n\t\t\t}\n\t\t\tassertThat(receivedEvents).extracting(\"class\").contains((Object[]) eventClasses);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.filtersample;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ExampleComponent {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleFilteredComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.filtersample;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ExampleFilteredComponent {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/filtersample/SampleTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.filtersample;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\n\npublic class SampleTypeExcludeFilter extends TypeExcludeFilter {\n\n\t@Override\n\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\treturn metadataReader.getClassMetadata().getClassName().equals(ExampleFilteredComponent.class.getName());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/filtersample/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.filtersample;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.logging;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemFactory;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.stereotype.Component;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link LoggingApplicationListener}.\n *\n * @author Stephane Nicoll\n */\n@WithResource(name = \"META-INF/spring.factories\",\n\t\tcontent = \"\"\"\n\t\t\t\torg.springframework.boot.logging.LoggingSystemFactory=org.springframework.boot.context.logging.LoggingApplicationListenerIntegrationTests$MockLoggingSystemFactory\n\t\t\t\t\"\"\")\n@ExtendWith(OutputCaptureExtension.class)\nclass LoggingApplicationListenerIntegrationTests {\n\n\t@Test\n\tvoid loggingSystemRegisteredInTheContext() {\n\t\ttry (ConfigurableApplicationContext context = new SpringApplicationBuilder(SampleService.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.run()) {\n\t\t\tSampleService service = context.getBean(SampleService.class);\n\t\t\tassertThat(service.loggingSystem).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid logFileRegisteredInTheContextWhenApplicable(@TempDir File tempDir) {\n\t\tString logFile = new File(tempDir, \"test.log\").getAbsolutePath();\n\t\ttry (ConfigurableApplicationContext context = new SpringApplicationBuilder(SampleService.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.properties(\"logging.file.name=\" + logFile)\n\t\t\t.run()) {\n\t\t\tSampleService service = context.getBean(SampleService.class);\n\t\t\tassertThat(service.logFile).isNotNull();\n\t\t\tassertThat(service.logFile).hasToString(logFile);\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid loggingPerformedDuringChildApplicationStartIsNotLost(CapturedOutput output) {\n\t\tnew SpringApplicationBuilder(Config.class).web(WebApplicationType.NONE)\n\t\t\t.child(Config.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.listeners(new ApplicationListener<ApplicationStartingEvent>() {\n\n\t\t\t\tprivate final Logger logger = LoggerFactory.getLogger(getClass());\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onApplicationEvent(ApplicationStartingEvent event) {\n\t\t\t\t\tthis.logger.info(\"Child application starting\");\n\t\t\t\t}\n\n\t\t\t})\n\t\t\t.run();\n\t\tassertThat(output).contains(\"Child application starting\");\n\t}\n\n\t@Component\n\tstatic class SampleService {\n\n\t\tprivate final LoggingSystem loggingSystem;\n\n\t\tprivate final @Nullable LogFile logFile;\n\n\t\tSampleService(LoggingSystem loggingSystem, ObjectProvider<LogFile> logFile) {\n\t\t\tthis.loggingSystem = loggingSystem;\n\t\t\tthis.logFile = logFile.getIfAvailable();\n\t\t}\n\n\t}\n\n\tstatic class Config {\n\n\t}\n\n\tstatic class MockLoggingSystemFactory implements LoggingSystemFactory {\n\n\t\t@Override\n\t\tpublic LoggingSystem getLoggingSystem(ClassLoader classLoader) {\n\t\t\treturn new MockLoggingSystem();\n\t\t}\n\n\t}\n\n\tstatic class MockLoggingSystem extends LoggingSystem {\n\n\t\t@Override\n\t\tpublic void beforeInitialize() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/logging/LoggingApplicationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.logging;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Handler;\nimport java.util.logging.LogManager;\nimport java.util.logging.Logger;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.LoggerContext;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.bridge.SLF4JBridgeHandler;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.logging.AbstractLoggingSystem;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggerGroup;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.logging.java.JavaLoggingSystem;\nimport org.springframework.boot.system.ApplicationPid;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.SimpleApplicationEventMulticaster;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link LoggingApplicationListener} with Logback.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Ben Hale\n * @author Fahim Farook\n * @author Eddú Meléndez\n * @author Jonatan Ivanov\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathExclusions(\"log4j*.jar\")\nclass LoggingApplicationListenerTests {\n\n\tprivate static final String[] NO_ARGS = {};\n\n\tprivate final LoggingApplicationListener listener = new LoggingApplicationListener();\n\n\tprivate final LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();\n\n\tprivate final ch.qos.logback.classic.Logger logger = this.loggerContext.getLogger(getClass());\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\tprivate final SpringApplication springApplication = new SpringApplication(TestConfiguration.class);\n\n\tprivate final GenericApplicationContext context = new GenericApplicationContext();\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tpublic Path tempDir;\n\n\tprivate File logFile;\n\n\tprivate Set<Object> systemPropertyNames;\n\n\tprivate CapturedOutput output;\n\n\t@BeforeEach\n\tvoid init(CapturedOutput output) throws IOException {\n\t\tthis.systemPropertyNames = new HashSet<>(System.getProperties().keySet());\n\t\tthis.output = output;\n\t\tthis.logFile = new File(this.tempDir.toFile(), \"foo.log\");\n\t\tLogManager.getLogManager().readConfiguration(JavaLoggingSystem.class.getResourceAsStream(\"logging.properties\"));\n\t\tmulticastEvent(new ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS));\n\t\tnew File(this.tempDir.toFile(), \"spring.log\").delete();\n\t\tConfigurableEnvironment environment = this.context.getEnvironment();\n\t\tConfigurationPropertySources.attach(environment);\n\t}\n\n\t@AfterEach\n\tvoid clear() {\n\t\tLoggingSystem loggingSystem = LoggingSystem.get(getClass().getClassLoader());\n\t\tloggingSystem.setLogLevel(\"ROOT\", LogLevel.INFO);\n\t\tloggingSystem.cleanUp();\n\t\tif (loggingSystem.getShutdownHandler() != null) {\n\t\t\tloggingSystem.getShutdownHandler().run();\n\t\t}\n\t\tSystem.clearProperty(LoggingSystem.class.getName());\n\t\tSystem.clearProperty(LoggingSystem.SYSTEM_PROPERTY);\n\t\tSystem.getProperties().keySet().retainAll(this.systemPropertyNames);\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid baseConfigLocation() {\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\", new RuntimeException(\"Expected\"));\n\t\tassertThat(this.output).contains(\"Hello world\");\n\t\tassertThat(this.output).doesNotContain(\"???\");\n\t\tassertThat(this.output).contains(\"[junit-\");\n\t\tassertThat(new File(this.tempDir + \"/spring.log\")).doesNotExist();\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid overrideConfigLocation() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.config=classpath:nondefault.xml\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(this.output).contains(\"Hello world\").doesNotContain(\"???\").startsWith(\"null \").endsWith(\"BOOTBOOT\");\n\t}\n\n\t@Test\n\tvoid throwableFromInitializeResultsInGracefulFailure(CapturedOutput output) {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, BrokenInitializationLoggingSystem.class.getName());\n\t\tmulticastEvent(this.listener,\n\t\t\t\tnew ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS));\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), getClassLoader()));\n\t\tassertThat(output).contains(\"Deliberately broken\");\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid trailingWhitespaceInLoggingConfigShouldBeTrimmed() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.config=classpath:nondefault.xml \");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(this.output).contains(\"Hello world\").doesNotContain(\"???\").startsWith(\"null \").endsWith(\"BOOTBOOT\");\n\t}\n\n\t@Test\n\tvoid overrideConfigDoesNotExist() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.config=doesnotexist.xml\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), getClassLoader()));\n\t\tassertThat(this.output)\n\t\t\t.contains(\"Logging system failed to initialize using configuration from 'doesnotexist.xml'\")\n\t\t\t.doesNotContain(\"JoranException\");\n\t}\n\n\t@Test\n\tvoid azureDefaultLoggingConfigDoesNotCauseAFailure() {\n\t\taddPropertiesToEnvironment(this.context,\n\t\t\t\t\"logging.config=-Djava.util.logging.config.file=\\\"d:\\\\home\\\\site\\\\wwwroot\\\\bin\\\\apache-tomcat-7.0.52\\\\conf\\\\logging.properties\\\"\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(this.output).contains(\"Hello world\").doesNotContain(\"???\");\n\t\tassertThat(new File(this.tempDir.toFile(), \"/spring.log\")).doesNotExist();\n\t}\n\n\t@Test\n\tvoid tomcatNopLoggingConfigDoesNotCauseAFailure() {\n\t\taddPropertiesToEnvironment(this.context, \"LOGGING_CONFIG=-Dnop\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(this.output).contains(\"Hello world\").doesNotContain(\"???\");\n\t\tassertThat(new File(this.tempDir.toFile(), \"/spring.log\")).doesNotExist();\n\t}\n\n\t@Test\n\tvoid overrideConfigBroken() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.config=classpath:logback-broken.xml\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\t\tassertThat(this.output).contains(\n\t\t\t\t\t\"Logging system failed to initialize using configuration from 'classpath:logback-broken.xml'\");\n\t\t\tassertThat(this.output).contains(\"ConsolAppender\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid addLogFileProperty() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.config=classpath:nondefault.xml\",\n\t\t\t\t\"logging.file.name=\" + this.logFile);\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tLog logger = LogFactory.getLog(LoggingApplicationListenerTests.class);\n\t\tString existingOutput = this.output.toString();\n\t\tlogger.info(\"Hello world\");\n\t\tString output = this.output.toString().substring(existingOutput.length()).trim();\n\t\tassertThat(output).startsWith(this.logFile.getAbsolutePath());\n\t}\n\n\t@Test\n\tvoid addLogFilePropertyWithDefault() {\n\t\tassertThat(this.logFile).doesNotExist();\n\t\taddPropertiesToEnvironment(this.context, \"logging.file.name=\" + this.logFile);\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tLog logger = LogFactory.getLog(LoggingApplicationListenerTests.class);\n\t\tlogger.info(\"Hello world\");\n\t\tassertThat(this.logFile).isFile();\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid addLogPathProperty() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.config=classpath:nondefault.xml\",\n\t\t\t\t\"logging.file.path=\" + this.tempDir);\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tLog logger = LogFactory.getLog(LoggingApplicationListenerTests.class);\n\t\tString existingOutput = this.output.toString();\n\t\tlogger.info(\"Hello world\");\n\t\tString output = this.output.toString().substring(existingOutput.length()).trim();\n\t\tassertThat(output).startsWith(new File(this.tempDir.toFile(), \"spring.log\").getAbsolutePath());\n\t}\n\n\t@Test\n\tvoid parseDebugArg() {\n\t\taddPropertiesToEnvironment(this.context, \"debug\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t\tassertThat(this.output).doesNotContain(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid parseDebugArgExpandGroups() {\n\t\taddPropertiesToEnvironment(this.context, \"debug\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.loggerContext.getLogger(\"org.springframework.boot.actuate.endpoint.web\").debug(\"testdebugwebgroup\");\n\t\tthis.loggerContext.getLogger(\"org.hibernate.SQL\").debug(\"testdebugsqlgroup\");\n\t\tassertThat(this.output).contains(\"testdebugwebgroup\");\n\t\tassertThat(this.output).contains(\"testdebugsqlgroup\");\n\t\tLoggerGroups loggerGroups = (LoggerGroups) ReflectionTestUtils.getField(this.listener, \"loggerGroups\");\n\t\tassertThat(loggerGroups).isNotNull();\n\t\tLoggerGroup loggerGroup = loggerGroups.get(\"web\");\n\t\tassertThat(loggerGroup).isNotNull();\n\t\tassertThat(loggerGroup.getConfiguredLevel()).isEqualTo(LogLevel.DEBUG);\n\t}\n\n\t@Test\n\tvoid parseTraceArg() {\n\t\taddPropertiesToEnvironment(this.context, \"trace\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t\tassertThat(this.output).contains(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid disableDebugArg() {\n\t\tdisableDebugTraceArg(\"debug=false\");\n\t}\n\n\t@Test\n\tvoid disableTraceArg() {\n\t\tdisableDebugTraceArg(\"trace=false\");\n\t}\n\n\tprivate void disableDebugTraceArg(String... environment) {\n\t\taddPropertiesToEnvironment(this.context, environment);\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).doesNotContain(\"testatdebug\");\n\t\tassertThat(this.output).doesNotContain(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid parseLevels() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.org.springframework.boot=TRACE\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t\tassertThat(this.output).contains(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid parseLevelsCaseInsensitive() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.org.springframework.boot=TrAcE\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t\tassertThat(this.output).contains(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid parseLevelsTrimsWhitespace() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.org.springframework.boot= trace \");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t\tassertThat(this.output).contains(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid parseLevelsWithPlaceholder() {\n\t\taddPropertiesToEnvironment(this.context, \"foo=TRACE\", \"logging.level.org.springframework.boot=${foo}\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.trace(\"testattrace\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t\tassertThat(this.output).contains(\"testattrace\");\n\t}\n\n\t@Test\n\tvoid parseLevelsFails() {\n\t\tthis.logger.setLevel(Level.INFO);\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.org.springframework.boot=GARBAGE\");\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.listener.initialize(this.context.getEnvironment(), getClassLoader()));\n\t}\n\n\t@Test\n\tvoid parseLevelsNone() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.org.springframework.boot=OFF\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.error(\"testaterror\");\n\t\tassertThat(this.output).doesNotContain(\"testatdebug\").doesNotContain(\"testaterror\");\n\t}\n\n\t@Test\n\tvoid parseLevelsMapsFalseToOff() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.org.springframework.boot=false\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tthis.logger.error(\"testaterror\");\n\t\tassertThat(this.output).doesNotContain(\"testatdebug\").doesNotContain(\"testaterror\");\n\t}\n\n\t@Test\n\tvoid parseArgsDisabled() {\n\t\tthis.listener.setParseArgs(false);\n\t\taddPropertiesToEnvironment(this.context, \"debug\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tassertThat(this.output).doesNotContain(\"testatdebug\");\n\t}\n\n\t@Test\n\tvoid parseArgsDoesntReplace() {\n\t\tthis.listener.setSpringBootLogging(LogLevel.ERROR);\n\t\tthis.listener.setParseArgs(false);\n\t\tmulticastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication,\n\t\t\t\tnew String[] { \"--debug\" }));\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tassertThat(this.output).doesNotContain(\"testatdebug\");\n\t}\n\n\t@Test\n\tvoid bridgeHandlerLifecycle() {\n\t\tassertThat(bridgeHandlerInstalled()).isTrue();\n\t\tmulticastEvent(new ContextClosedEvent(this.context));\n\t\tassertThat(bridgeHandlerInstalled()).isFalse();\n\t}\n\n\t@Test\n\tvoid defaultExceptionConversionWord() {\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\", new RuntimeException(\"Wrapper\", new RuntimeException(\"Expected\")));\n\t\tassertThat(this.output).contains(\"Hello world\");\n\t\tassertThat(this.output).doesNotContain(\"Wrapped by: java.lang.RuntimeException: Wrapper\");\n\t}\n\n\t@Test\n\tvoid overrideExceptionConversionWord() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.exceptionConversionWord=%rEx\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.info(\"Hello world\", new RuntimeException(\"Wrapper\", new RuntimeException(\"Expected\")));\n\t\tassertThat(this.output).contains(\"Hello world\");\n\t\tassertThat(this.output).contains(\"Wrapped by: java.lang.RuntimeException: Wrapper\");\n\t}\n\n\t@Test\n\tvoid shutdownHookIsRegisteredByDefault() throws Exception {\n\t\tTestLoggingApplicationListener listener = new TestLoggingApplicationListener();\n\t\tObject registered = ReflectionTestUtils.getField(listener, TestLoggingApplicationListener.class,\n\t\t\t\t\"shutdownHookRegistered\");\n\t\tassertThat(registered).isNotNull();\n\t\t((AtomicBoolean) registered).set(false);\n\t\tSystem.setProperty(LoggingSystem.class.getName(), TestShutdownHandlerLoggingSystem.class.getName());\n\t\tmulticastEvent(listener, new ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS));\n\t\tlistener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertThat(listener.shutdownHook).isNotNull();\n\t\tlistener.shutdownHook.run();\n\t\tCountDownLatch shutdownLatch = TestShutdownHandlerLoggingSystem.shutdownLatch;\n\t\tassertThat(shutdownLatch).isNotNull();\n\t\tassertThat(shutdownLatch.await(30, TimeUnit.SECONDS)).isTrue();\n\t}\n\n\t@Test\n\tvoid shutdownHookRegistrationCanBeDisabled() {\n\t\tTestLoggingApplicationListener listener = new TestLoggingApplicationListener();\n\t\tObject registered = ReflectionTestUtils.getField(listener, TestLoggingApplicationListener.class,\n\t\t\t\t\"shutdownHookRegistered\");\n\t\tassertThat(registered).isNotNull();\n\t\t((AtomicBoolean) registered).set(false);\n\t\tSystem.setProperty(LoggingSystem.class.getName(), TestShutdownHandlerLoggingSystem.class.getName());\n\t\taddPropertiesToEnvironment(this.context, \"logging.register_shutdown_hook=false\");\n\t\tmulticastEvent(listener, new ApplicationStartingEvent(this.bootstrapContext, new SpringApplication(), NO_ARGS));\n\t\tlistener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertThat(listener.shutdownHook).isNull();\n\t}\n\n\t@Test\n\tvoid closingContextCleansUpLoggingSystem() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName());\n\t\tmulticastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[0]));\n\t\tTestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(this.listener,\n\t\t\t\t\"loggingSystem\");\n\t\tassertThat(loggingSystem).isNotNull();\n\t\tassertThat(loggingSystem.cleanedUp).isFalse();\n\t\tmulticastEvent(new ContextClosedEvent(this.context));\n\t\tassertThat(loggingSystem.cleanedUp).isTrue();\n\t}\n\n\t@Test\n\tvoid closingChildContextDoesNotCleanUpLoggingSystem() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName());\n\t\tmulticastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[0]));\n\t\tTestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(this.listener,\n\t\t\t\t\"loggingSystem\");\n\t\tassertThat(loggingSystem).isNotNull();\n\t\tassertThat(loggingSystem.cleanedUp).isFalse();\n\t\tGenericApplicationContext childContext = new GenericApplicationContext();\n\t\tchildContext.setParent(this.context);\n\t\tmulticastEvent(new ContextClosedEvent(childContext));\n\t\tassertThat(loggingSystem.cleanedUp).isFalse();\n\t\tmulticastEvent(new ContextClosedEvent(this.context));\n\t\tassertThat(loggingSystem.cleanedUp).isTrue();\n\t\tchildContext.close();\n\t}\n\n\t@Test\n\tvoid systemPropertiesAreSetForLoggingConfiguration() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.exception-conversion-word=conversion\",\n\t\t\t\t\"logging.file.name=\" + this.logFile, \"logging.file.path=path\", \"logging.pattern.console=console\",\n\t\t\t\t\"logging.pattern.file=file\", \"logging.pattern.level=level\", \"logging.pattern.correlation=correlation\",\n\t\t\t\t\"logging.pattern.rolling-file-name=my.log.%d{yyyyMMdd}.%i.gz\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)).isEqualTo(\"console\");\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.FILE_PATTERN)).isEqualTo(\"file\");\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD)).isEqualTo(\"conversion\");\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.LOG_FILE)).isEqualTo(this.logFile.getAbsolutePath());\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.LEVEL_PATTERN)).isEqualTo(\"level\");\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.LOG_PATH)).isEqualTo(\"path\");\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.PID)).isNotNull();\n\t}\n\n\t@Test\n\tvoid environmentPropertiesIgnoreUnresolvablePlaceholders() {\n\t\t// gh-7719\n\t\taddPropertiesToEnvironment(this.context, \"logging.pattern.console=console ${doesnotexist}\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)).isEqualTo(\"console ${doesnotexist}\");\n\t}\n\n\t@Test\n\tvoid environmentPropertiesResolvePlaceholders() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.pattern.console=console ${pid}\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN))\n\t\t\t.isEqualTo(this.context.getEnvironment().getProperty(\"logging.pattern.console\"));\n\t}\n\n\t@Test\n\tvoid logFilePropertiesCanReferenceSystemProperties() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.file.name=\" + this.tempDir + \"${PID}.log\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.LOG_FILE))\n\t\t\t.isEqualTo(this.tempDir + new ApplicationPid().toString() + \".log\");\n\t}\n\n\t@Test\n\tvoid applicationFailedEventCleansUpLoggingSystem() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName());\n\t\tmulticastEvent(new ApplicationStartingEvent(this.bootstrapContext, this.springApplication, new String[0]));\n\t\tTestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(this.listener,\n\t\t\t\t\"loggingSystem\");\n\t\tassertThat(loggingSystem).isNotNull();\n\t\tassertThat(loggingSystem.cleanedUp).isFalse();\n\t\tmulticastEvent(new ApplicationFailedEvent(this.springApplication, new String[0],\n\t\t\t\tnew GenericApplicationContext(), new Exception()));\n\t\tassertThat(loggingSystem.cleanedUp).isTrue();\n\t}\n\n\t@Test\n\tvoid cleanupOccursAfterWebServerShutdown() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName());\n\t\tthis.springApplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableApplicationContext context = this.springApplication.run();\n\t\tApplicationListener<?> listener = this.springApplication.getListeners()\n\t\t\t.stream()\n\t\t\t.filter(LoggingApplicationListener.class::isInstance)\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tTestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils.getField(listener,\n\t\t\t\t\"loggingSystem\");\n\t\tassertThat(loggingSystem).isNotNull();\n\t\tassertThat(loggingSystem.cleanedUp).isFalse();\n\t\tWebServerStyleLifecycle lifecycle = context.getBean(WebServerStyleLifecycle.class);\n\t\tAtomicBoolean called = new AtomicBoolean();\n\t\tAtomicBoolean cleanupOnStop = new AtomicBoolean();\n\t\tlifecycle.onStop = () -> {\n\t\t\tcalled.set(true);\n\t\t\tcleanupOnStop.set(loggingSystem.cleanedUp);\n\t\t};\n\t\tcontext.close();\n\t\tassertThat(called).isTrue();\n\t\tassertThat(cleanupOnStop).isFalse();\n\t\tassertThat(loggingSystem.cleanedUp).isTrue();\n\t}\n\n\t@Test\n\tvoid lowPriorityPropertySourceShouldNotOverrideRootLoggerConfig() {\n\t\tMutablePropertySources propertySources = this.context.getEnvironment().getPropertySources();\n\t\tpropertySources\n\t\t\t.addFirst(new MapPropertySource(\"test1\", Collections.singletonMap(\"logging.level.ROOT\", \"DEBUG\")));\n\t\tpropertySources.addLast(new MapPropertySource(\"test2\", Collections.singletonMap(\"logging.level.root\", \"WARN\")));\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tthis.logger.debug(\"testatdebug\");\n\t\tassertThat(this.output).contains(\"testatdebug\");\n\t}\n\n\t@Test\n\tvoid loggingGroupsDefaultsAreApplied() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.level.web=TRACE\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertTraceEnabled(\"org.springframework.core\", false);\n\t\tassertTraceEnabled(\"org.springframework.core.codec\", true);\n\t\tassertTraceEnabled(\"org.springframework.http\", true);\n\t\tassertTraceEnabled(\"org.springframework.web\", true);\n\t\tassertTraceEnabled(\"org.springframework.boot.actuate.endpoint.web\", true);\n\t\tassertTraceEnabled(\"org.springframework.boot.web.servlet.ServletContextInitializerBeans\", true);\n\t}\n\n\t@Test\n\tvoid loggingGroupsCanBeDefined() {\n\t\taddPropertiesToEnvironment(this.context, \"logging.group.foo=com.foo.bar,com.foo.baz\",\n\t\t\t\t\"logging.level.foo=TRACE\");\n\t\tthis.listener.initialize(this.context.getEnvironment(), getClassLoader());\n\t\tassertTraceEnabled(\"com.foo\", false);\n\t\tassertTraceEnabled(\"com.foo.bar\", true);\n\t\tassertTraceEnabled(\"com.foo.baz\", true);\n\t}\n\n\tprivate ClassLoader getClassLoader() {\n\t\tClassLoader classLoader = this.context.getClassLoader();\n\t\tassertThat(classLoader).isNotNull();\n\t\treturn classLoader;\n\t}\n\n\tprivate String getSystemProperty(LoggingSystemProperty property) {\n\t\treturn System.getProperty(property.getEnvironmentVariableName());\n\t}\n\n\tprivate void assertTraceEnabled(String name, boolean expected) {\n\t\tassertThat(this.loggerContext.getLogger(name).isTraceEnabled()).isEqualTo(expected);\n\t}\n\n\tprivate void multicastEvent(ApplicationEvent event) {\n\t\tmulticastEvent(this.listener, event);\n\t}\n\n\tprivate void multicastEvent(ApplicationListener<?> listener, ApplicationEvent event) {\n\t\tSimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();\n\t\tmulticaster.addApplicationListener(listener);\n\t\tmulticaster.multicastEvent(event);\n\t}\n\n\tprivate boolean bridgeHandlerInstalled() {\n\t\tLogger rootLogger = LogManager.getLogManager().getLogger(\"\");\n\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\tfor (Handler handler : handlers) {\n\t\t\tif (handler instanceof SLF4JBridgeHandler) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate void addPropertiesToEnvironment(ConfigurableApplicationContext context, String... pairs) {\n\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tfor (String pair : pairs) {\n\t\t\tString[] split = pair.split(\"=\", 2);\n\t\t\tproperties.put(split[0], (split.length == 2) ? split[1] : \"\");\n\t\t}\n\t\tMapPropertySource propertySource = new MapPropertySource(\"logging-config\", properties);\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t}\n\n\tstatic class TestShutdownHandlerLoggingSystem extends AbstractLoggingSystem {\n\n\t\tprivate static @Nullable CountDownLatch shutdownLatch;\n\n\t\tTestShutdownHandlerLoggingSystem(ClassLoader classLoader) {\n\t\t\tsuper(classLoader);\n\t\t\tTestShutdownHandlerLoggingSystem.shutdownLatch = new CountDownLatch(1);\n\t\t}\n\n\t\t@Override\n\t\tprotected String[] getStandardConfigLocations() {\n\t\t\treturn new String[] { \"foo.bar\" };\n\t\t}\n\n\t\t@Override\n\t\tprotected void loadDefaults(LoggingInitializationContext initializationContext, @Nullable LogFile logFile) {\n\t\t}\n\n\t\t@Override\n\t\tprotected void loadConfiguration(LoggingInitializationContext initializationContext, String location,\n\t\t\t\t@Nullable LogFile logFile) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\t}\n\n\t\t@Override\n\t\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic Runnable getShutdownHandler() {\n\t\t\treturn () -> {\n\t\t\t\tCountDownLatch shutdownLatch = TestShutdownHandlerLoggingSystem.shutdownLatch;\n\t\t\t\tassertThat(shutdownLatch).isNotNull();\n\t\t\t\tshutdownLatch.countDown();\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class TestLoggingApplicationListener extends LoggingApplicationListener {\n\n\t\tprivate @Nullable Runnable shutdownHook;\n\n\t\t@Override\n\t\tvoid registerShutdownHook(Runnable shutdownHook) {\n\t\t\tthis.shutdownHook = shutdownHook;\n\t\t}\n\n\t}\n\n\tstatic final class TestCleanupLoggingSystem extends LoggingSystem {\n\n\t\tprivate boolean cleanedUp;\n\n\t\tTestCleanupLoggingSystem(ClassLoader classLoader) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void beforeInitialize() {\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\t}\n\n\t\t@Override\n\t\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic void cleanUp() {\n\t\t\tthis.cleanedUp = true;\n\t\t}\n\n\t}\n\n\tstatic final class BrokenInitializationLoggingSystem extends LoggingSystem {\n\n\t\tBrokenInitializationLoggingSystem(ClassLoader classLoader) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void beforeInitialize() {\n\t\t}\n\n\t\t@Override\n\t\tpublic void initialize(LoggingInitializationContext initializationContext, @Nullable String configLocation,\n\t\t\t\t@Nullable LogFile logFile) {\n\t\t\tthrow new Error(\"Deliberately broken\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\t}\n\n\t\t@Override\n\t\tpublic List<LoggerConfiguration> getLoggerConfigurations() {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable LoggerConfiguration getLoggerConfiguration(String loggerName) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration\n\t@Import(WebServerStyleLifecycle.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\tstatic class WebServerStyleLifecycle implements SmartLifecycle {\n\n\t\tprivate volatile boolean running;\n\n\t\t@Nullable Runnable onStop;\n\n\t\t@Override\n\t\tpublic void start() {\n\t\t\tthis.running = true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void stop() {\n\t\t\tthis.running = false;\n\t\t\tif (this.onStop != null) {\n\t\t\t\tthis.onStop.run();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isRunning() {\n\t\t\treturn this.running;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getPhase() {\n\t\t\treturn Integer.MAX_VALUE - 1;\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"nondefault.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t\t\t\t<encoder>\n\t\t\t\t\t\t<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>\n\t\t\t\t\t</encoder>\n\t\t\t\t</appender>\n\t\t\t\t<root level=\"INFO\">\n\t\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithNonDefaultXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/metrics/buffering/BufferingApplicationStartupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.metrics.buffering;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Queue;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.metrics.buffering.StartupTimeline.TimelineEvent;\nimport org.springframework.core.metrics.StartupStep;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link BufferingApplicationStartup}.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass BufferingApplicationStartupTests {\n\n\t@Test\n\tvoid shouldNotRecordEventsWhenOverCapacity() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(2);\n\t\tapplicationStartup.start(\"first\").end();\n\t\tapplicationStartup.start(\"second\").end();\n\t\tapplicationStartup.start(\"third\").end();\n\t\tassertThat(applicationStartup.getBufferedTimeline().getEvents()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid shouldNotRecordEventsWhenFiltered() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(5);\n\t\tapplicationStartup.addFilter((step) -> step.getName().startsWith(\"spring\"));\n\t\tapplicationStartup.start(\"spring.first\").end();\n\t\tStartupStep filtered = applicationStartup.start(\"filtered.second\");\n\t\tapplicationStartup.start(\"spring.third\").end();\n\t\tfiltered.end();\n\t\tList<TimelineEvent> events = applicationStartup.getBufferedTimeline().getEvents();\n\t\tassertThat(events).hasSize(2);\n\t\tStartupTimeline.TimelineEvent firstEvent = events.get(0);\n\t\tassertThat(firstEvent.getStartupStep().getId()).isZero();\n\t\tassertThat(firstEvent.getStartupStep().getParentId()).isNull();\n\t\tStartupTimeline.TimelineEvent secondEvent = events.get(1);\n\t\tassertThat(secondEvent.getStartupStep().getId()).isEqualTo(2);\n\t\tassertThat(secondEvent.getStartupStep().getParentId()).isOne();\n\t}\n\n\t@Test\n\tvoid bufferShouldNotBeEmptyWhenGettingSnapshot() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(2);\n\t\tapplicationStartup.start(\"first\").end();\n\t\tapplicationStartup.start(\"second\").end();\n\t\tassertThat(applicationStartup.getBufferedTimeline().getEvents()).hasSize(2);\n\t\tassertThat(applicationStartup.getBufferedTimeline().getEvents()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid bufferShouldBeEmptyWhenDraining() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(2);\n\t\tapplicationStartup.start(\"first\").end();\n\t\tapplicationStartup.start(\"second\").end();\n\t\tassertThat(applicationStartup.drainBufferedTimeline().getEvents()).hasSize(2);\n\t\tassertThat(applicationStartup.getBufferedTimeline().getEvents()).isEmpty();\n\t}\n\n\t@Test\n\tvoid startRecordingShouldFailIfEventsWereRecorded() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(2);\n\t\tapplicationStartup.start(\"first\").end();\n\t\tassertThatIllegalStateException().isThrownBy(applicationStartup::startRecording)\n\t\t\t.withMessage(\"Cannot restart recording once steps have been buffered\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid taggingShouldFailWhenEventAlreadyRecorded() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(2);\n\t\tStartupStep step = applicationStartup.start(\"first\");\n\t\tstep.end();\n\t\tassertThatIllegalStateException().isThrownBy(() -> step.tag(\"name\", \"value\"))\n\t\t\t.withMessage(\"StartupStep has already ended.\");\n\t}\n\n\t@Test\n\tvoid taggingShouldFailWhenRemovingEntry() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(2);\n\t\tStartupStep step = applicationStartup.start(\"first\");\n\t\tstep.tag(\"name\", \"value\");\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> step.getTags().iterator().remove());\n\t}\n\n\t@Test // gh-25792\n\tvoid outOfOrderWithMultipleEndCallsShouldNotFail() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(200);\n\t\tStartupStep one = applicationStartup.start(\"one\");\n\t\tStartupStep two = applicationStartup.start(\"two\");\n\t\tStartupStep three = applicationStartup.start(\"three\");\n\t\ttwo.end();\n\t\ttwo.end();\n\t\ttwo.end();\n\t\tStartupStep four = applicationStartup.start(\"four\");\n\t\tfour.end();\n\t\tthree.end();\n\t\tone.end();\n\t}\n\n\t@Test // gh-25792\n\tvoid multiThreadedAccessShouldWork() throws InterruptedException {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(5000);\n\t\tQueue<Exception> errors = new ConcurrentLinkedQueue<>();\n\t\tList<Thread> threads = new ArrayList<>();\n\t\tfor (int thread = 0; thread < 20; thread++) {\n\t\t\tString prefix = \"thread-\" + thread + \"-\";\n\t\t\tthreads.add(new Thread(() -> {\n\t\t\t\ttry {\n\t\t\t\t\tfor (int i = 0; i < 100; i++) {\n\t\t\t\t\t\tStartupStep step = applicationStartup.start(prefix + i);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tThread.sleep(1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\t\t\t// Ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstep.end();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\terrors.add(ex);\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\tthreads.forEach(Thread::start);\n\t\tfor (Thread thread : threads) {\n\t\t\tthread.join();\n\t\t}\n\t\tassertThat(errors).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.stream.Stream;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.assertj.core.error.BasicErrorMessageFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBeanFactoryInitializationAotProcessor.ConfigurationPropertiesReflectionHintsContribution;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigurationPropertiesBeanFactoryInitializationAotProcessor}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Sebastien Deleuze\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests {\n\n\tprivate final ConfigurationPropertiesBeanFactoryInitializationAotProcessor processor = new ConfigurationPropertiesBeanFactoryInitializationAotProcessor();\n\n\t@Test\n\tvoid configurationPropertiesBeanFactoryInitializationAotProcessorIsRegistered() {\n\t\tassertThat(AotServices.factories().load(BeanFactoryInitializationAotProcessor.class))\n\t\t\t.anyMatch(ConfigurationPropertiesBeanFactoryInitializationAotProcessor.class::isInstance);\n\t}\n\n\t@Test\n\tvoid processNoMatchesReturnsNullContribution() {\n\t\tassertThat(process(String.class)).isNull();\n\t}\n\n\t@Test\n\tvoid manuallyRegisteredSingletonBindsAsJavaBean() {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tbeanFactory.registerSingleton(\"test\", new SampleProperties());\n\t\tConfigurationPropertiesReflectionHintsContribution contribution = process(beanFactory);\n\t\tassertThat(contribution).isNotNull();\n\t\tassertThat(singleBindable(contribution)).hasBindMethod(BindMethod.JAVA_BEAN).hasType(SampleProperties.class);\n\t\tassertThat(typeHints(contribution).map(TypeHint::getType))\n\t\t\t.containsExactly(TypeReference.of(SampleProperties.class));\n\t}\n\n\t@Test\n\tvoid javaBeanConfigurationPropertiesBindAsJavaBean() {\n\t\tConfigurationPropertiesReflectionHintsContribution contribution = process(EnableJavaBeanProperties.class);\n\t\tassertThat(contribution).isNotNull();\n\t\tassertThat(singleBindable(contribution)).hasBindMethod(BindMethod.JAVA_BEAN).hasType(JavaBeanProperties.class);\n\t\tassertThat(typeHints(contribution).map(TypeHint::getType))\n\t\t\t.containsExactly(TypeReference.of(JavaBeanProperties.class));\n\t}\n\n\t@Test\n\tvoid constructorBindingConfigurationPropertiesBindAsValueObject() {\n\t\tConfigurationPropertiesReflectionHintsContribution contribution = process(\n\t\t\t\tEnableConstructorBindingProperties.class);\n\t\tassertThat(contribution).isNotNull();\n\t\tassertThat(singleBindable(contribution)).hasBindMethod(BindMethod.VALUE_OBJECT)\n\t\t\t.hasType(ConstructorBindingProperties.class);\n\t\tassertThat(typeHints(contribution).map(TypeHint::getType))\n\t\t\t.containsExactly(TypeReference.of(ConstructorBindingProperties.class));\n\t}\n\n\t@Test\n\tvoid possibleConstructorBindingPropertiesDefinedThroughBeanMethodBindAsJavaBean() {\n\t\tConfigurationPropertiesReflectionHintsContribution contribution = process(\n\t\t\t\tPossibleConstructorBindingPropertiesBeanMethodConfiguration.class);\n\t\tassertThat(contribution).isNotNull();\n\t\tassertThat(singleBindable(contribution)).hasBindMethod(BindMethod.JAVA_BEAN)\n\t\t\t.hasType(PossibleConstructorBindingProperties.class);\n\t\tassertThat(typeHints(contribution).map(TypeHint::getType))\n\t\t\t.containsExactly(TypeReference.of(PossibleConstructorBindingProperties.class));\n\t}\n\n\t@Test\n\tvoid possibleConstructorBindingPropertiesDefinedThroughEnabledAnnotationBindAsValueObject() {\n\t\tConfigurationPropertiesReflectionHintsContribution contribution = process(\n\t\t\t\tEnablePossibleConstructorBindingProperties.class);\n\t\tassertThat(contribution).isNotNull();\n\t\tassertThat(singleBindable(contribution)).hasBindMethod(BindMethod.VALUE_OBJECT)\n\t\t\t.hasType(PossibleConstructorBindingProperties.class);\n\t\tassertThat(typeHints(contribution).map(TypeHint::getType))\n\t\t\t.containsExactly(TypeReference.of(PossibleConstructorBindingProperties.class));\n\t}\n\n\tprivate Stream<TypeHint> typeHints(ConfigurationPropertiesReflectionHintsContribution contribution) {\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tcontribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));\n\t\treturn generationContext.getRuntimeHints().reflection().typeHints();\n\t}\n\n\tprivate @Nullable ConfigurationPropertiesReflectionHintsContribution process(Class<?> config) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config)) {\n\t\t\treturn process(context.getBeanFactory());\n\t\t}\n\t}\n\n\tprivate @Nullable ConfigurationPropertiesReflectionHintsContribution process(\n\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\treturn this.processor.processAheadOfTime(beanFactory);\n\t}\n\n\tprivate BindableAssertProvider singleBindable(ConfigurationPropertiesReflectionHintsContribution contribution) {\n\t\tassertThat(contribution.getBindables()).hasSize(1);\n\t\treturn new BindableAssertProvider(contribution.getBindables().iterator().next());\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class SampleProperties {\n\n\t}\n\n\t@EnableConfigurationProperties(JavaBeanProperties.class)\n\tstatic class EnableJavaBeanProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"java-bean\")\n\tstatic class JavaBeanProperties {\n\n\t\tprivate @Nullable String value;\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorBindingProperties.class)\n\tstatic class EnableConstructorBindingProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"constructor-binding\")\n\tstatic class ConstructorBindingProperties {\n\n\t\tprivate final String value;\n\n\t\tConstructorBindingProperties(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tString getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PossibleConstructorBindingPropertiesBeanMethodConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"bean-method\")\n\t\tPossibleConstructorBindingProperties possibleConstructorBindingProperties() {\n\t\t\treturn new PossibleConstructorBindingProperties(\"alpha\");\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(PossibleConstructorBindingProperties.class)\n\tstatic class EnablePossibleConstructorBindingProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"possible-constructor-binding\")\n\tstatic class PossibleConstructorBindingProperties {\n\n\t\tprivate @Nullable String value;\n\n\t\tPossibleConstructorBindingProperties(String arg) {\n\n\t\t}\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class BindableAssertProvider implements AssertProvider<BindableAssert> {\n\n\t\tprivate final Bindable<?> bindable;\n\n\t\tBindableAssertProvider(Bindable<?> bindable) {\n\t\t\tthis.bindable = bindable;\n\t\t}\n\n\t\t@Override\n\t\tpublic BindableAssert assertThat() {\n\t\t\treturn new BindableAssert(this.bindable);\n\t\t}\n\n\t}\n\n\tstatic class BindableAssert extends AbstractAssert<BindableAssert, Bindable<?>> {\n\n\t\tBindableAssert(Bindable<?> bindable) {\n\t\t\tsuper(bindable, BindableAssert.class);\n\t\t}\n\n\t\tBindableAssert hasBindMethod(BindMethod bindMethod) {\n\t\t\tif (this.actual.getBindMethod() != bindMethod) {\n\t\t\t\tthrowAssertionError(\n\t\t\t\t\t\tnew BasicErrorMessageFactory(\"Expected %s to have bind method %s but bind method was %s\",\n\t\t\t\t\t\t\t\tthis.actual, bindMethod, this.actual.getBindMethod()));\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tBindableAssert hasType(Class<?> type) {\n\t\t\tif (!type.equals(this.actual.getType().resolve())) {\n\t\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\"Expected %s to have type %s but type was %s\",\n\t\t\t\t\t\tthis.actual, type, this.actual.getType().resolve()));\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.scope.ScopedProxyFactoryBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.context.annotation.ScopedProxyMode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ConfigurationPropertiesBeanRegistrar}.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nclass ConfigurationPropertiesBeanRegistrarTests {\n\n\tprivate final BeanDefinitionRegistry registry = new DefaultListableBeanFactory();\n\n\tprivate final ConfigurationPropertiesBeanRegistrar registrar = new ConfigurationPropertiesBeanRegistrar(\n\t\t\tthis.registry);\n\n\t@Test\n\tvoid registerWhenNotAlreadyRegisteredAddBeanDefinition() {\n\t\tString beanName = \"beancp-\" + BeanConfigurationProperties.class.getName();\n\t\tthis.registrar.register(BeanConfigurationProperties.class);\n\t\tBeanDefinition definition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(definition).isNotNull();\n\t\tassertThat(definition.getBeanClassName()).isEqualTo(BeanConfigurationProperties.class.getName());\n\t}\n\n\t@Test\n\tvoid registerWhenAlreadyContainsNameDoesNotReplace() {\n\t\tString beanName = \"beancp-\" + BeanConfigurationProperties.class.getName();\n\t\tthis.registry.registerBeanDefinition(beanName, new RootBeanDefinition());\n\t\tthis.registrar.register(BeanConfigurationProperties.class);\n\t\tBeanDefinition definition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(definition).isNotNull();\n\t\tassertThat(definition.getBeanClassName()).isNull();\n\t}\n\n\t@Test\n\tvoid registerWhenNoAnnotationThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.registrar.register(NoAnnotationConfigurationProperties.class))\n\t\t\t.withMessageContaining(\"No ConfigurationProperties annotation found\");\n\t}\n\n\t@Test\n\tvoid registerWhenValueObjectRegistersValueObjectBeanDefinition() {\n\t\tString beanName = \"valuecp-\" + ValueObjectConfigurationProperties.class.getName();\n\t\tthis.registrar.register(ValueObjectConfigurationProperties.class);\n\t\tBeanDefinition definition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(definition).satisfies(hasBindMethodAttribute(BindMethod.VALUE_OBJECT));\n\t}\n\n\t@Test\n\tvoid registerWhenNotValueObjectRegistersRootBeanDefinitionWithJavaBeanBindMethod() {\n\t\tString beanName = MultiConstructorBeanConfigurationProperties.class.getName();\n\t\tthis.registrar.register(MultiConstructorBeanConfigurationProperties.class);\n\t\tBeanDefinition definition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(definition).satisfies(hasBindMethodAttribute(BindMethod.JAVA_BEAN));\n\t}\n\n\t@Test\n\tvoid registerWhenNoScopeUsesSingleton() {\n\t\tString beanName = \"beancp-\" + BeanConfigurationProperties.class.getName();\n\t\tthis.registrar.register(BeanConfigurationProperties.class);\n\t\tBeanDefinition definition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(definition).isNotNull();\n\t\tassertThat(definition.getScope()).isEqualTo(BeanDefinition.SCOPE_SINGLETON);\n\t}\n\n\t@Test\n\tvoid registerScopedBeanDefinition() {\n\t\tString beanName = \"beancp-\" + ScopedBeanConfigurationProperties.class.getName();\n\t\tthis.registrar.register(ScopedBeanConfigurationProperties.class);\n\t\tBeanDefinition beanDefinition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(beanDefinition).isNotNull();\n\t\tassertThat(beanDefinition.getBeanClassName()).isEqualTo(ScopedBeanConfigurationProperties.class.getName());\n\t\tassertThat(beanDefinition.getScope()).isEqualTo(BeanDefinition.SCOPE_PROTOTYPE);\n\t}\n\n\t@Test\n\tvoid registerScopedBeanDefinitionWithProxyMode() {\n\t\tString beanName = \"beancp-\" + ProxyScopedBeanConfigurationProperties.class.getName();\n\t\tthis.registrar.register(ProxyScopedBeanConfigurationProperties.class);\n\t\tBeanDefinition proxiedBeanDefinition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(proxiedBeanDefinition).isNotNull();\n\t\tassertThat(proxiedBeanDefinition.getBeanClassName()).isEqualTo(ScopedProxyFactoryBean.class.getName());\n\t\tString targetBeanName = (String) proxiedBeanDefinition.getPropertyValues().get(\"targetBeanName\");\n\t\tassertThat(targetBeanName).isNotNull();\n\t\tBeanDefinition beanDefinition = this.registry.getBeanDefinition(targetBeanName);\n\t\tassertThat(beanDefinition).isNotNull();\n\t\tassertThat(beanDefinition.getBeanClassName()).isEqualTo(ProxyScopedBeanConfigurationProperties.class.getName());\n\t\tassertThat(beanDefinition.getScope()).isEqualTo(BeanDefinition.SCOPE_PROTOTYPE);\n\t}\n\n\t@Test\n\tvoid registerBeanDefinitionWithCommonDefinitionAnnotations() {\n\t\tString beanName = \"beancp-\" + PrimaryConfigurationProperties.class.getName();\n\t\tthis.registrar.register(PrimaryConfigurationProperties.class);\n\t\tBeanDefinition beanDefinition = this.registry.getBeanDefinition(beanName);\n\t\tassertThat(beanDefinition).isNotNull();\n\t\tassertThat(beanDefinition.isPrimary()).isEqualTo(true);\n\t}\n\n\tprivate Consumer<BeanDefinition> hasBindMethodAttribute(BindMethod bindMethod) {\n\t\treturn (definition) -> {\n\t\t\tassertThat(definition.hasAttribute(BindMethod.class.getName())).isTrue();\n\t\t\tassertThat(definition.getAttribute(BindMethod.class.getName())).isEqualTo(bindMethod);\n\t\t};\n\t}\n\n\t@ConfigurationProperties(\"beancp\")\n\tstatic class BeanConfigurationProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"beancp\")\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\tstatic class ScopedBeanConfigurationProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"beancp\")\n\t@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)\n\tstatic class ProxyScopedBeanConfigurationProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"beancp\")\n\t@Primary\n\tstatic class PrimaryConfigurationProperties {\n\n\t}\n\n\tstatic class NoAnnotationConfigurationProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"valuecp\")\n\tstatic class ValueObjectConfigurationProperties {\n\n\t\tValueObjectConfigurationProperties(String name) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class MultiConstructorBeanConfigurationProperties {\n\n\t\tMultiConstructorBeanConfigurationProperties() {\n\t\t}\n\n\t\tMultiConstructorBeanConfigurationProperties(String name) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanRegistrationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Arrays;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BFirstProperties;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BSecondProperties;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesBeanRegistrationAotProcessor}.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationPropertiesBeanRegistrationAotProcessorTests {\n\n\tprivate final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\tprivate final ConfigurationPropertiesBeanRegistrationAotProcessor processor = new ConfigurationPropertiesBeanRegistrationAotProcessor();\n\n\t@Test\n\tvoid configurationPropertiesBeanRegistrationAotProcessorIsRegistered() {\n\t\tassertThat(AotServices.factories().load(BeanRegistrationAotProcessor.class))\n\t\t\t.anyMatch(ConfigurationPropertiesBeanRegistrationAotProcessor.class::isInstance);\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWithNoConfigurationPropertiesBean() {\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);\n\t\tthis.beanFactory.registerBeanDefinition(\"test\", beanDefinition);\n\t\tBeanRegistrationAotContribution contribution = this.processor\n\t\t\t.processAheadOfTime(RegisteredBean.of(this.beanFactory, \"test\"));\n\t\tassertThat(contribution).isNull();\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWithJavaBeanConfigurationPropertiesBean() {\n\t\tBeanRegistrationAotContribution contribution = process(JavaBeanSampleBean.class);\n\t\tassertThat(contribution).isNull();\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWithValueObjectConfigurationPropertiesBean() {\n\t\tBeanRegistrationAotContribution contribution = process(ValueObjectSampleBean.class);\n\t\tassertThat(contribution).isNotNull();\n\t}\n\n\tprivate @Nullable BeanRegistrationAotContribution process(Class<?> type) {\n\t\tConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(this.beanFactory);\n\t\tbeanRegistrar.register(type);\n\t\tRegisteredBean registeredBean = RegisteredBean.of(this.beanFactory,\n\t\t\t\tthis.beanFactory.getBeanDefinitionNames()[0]);\n\t\treturn this.processor.processAheadOfTime(registeredBean);\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid aotContributedInitializerBindsValueObject() {\n\t\tcompile(createContext(ValueObjectSampleBeanConfiguration.class), (freshContext) -> {\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(freshContext, \"test.name=Hello\");\n\t\t\tfreshContext.refresh();\n\t\t\tValueObjectSampleBean bean = freshContext.getBean(ValueObjectSampleBean.class);\n\t\t\tassertThat(bean.name).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid aotContributedInitializerBindsValueObjectWithSpecificConstructor() {\n\t\tcompile(createContext(ValueObjectSampleBeanWithSpecificConstructorConfiguration.class), (freshContext) -> {\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(freshContext, \"test.name=Hello\",\n\t\t\t\t\t\"test.counter=30\");\n\t\t\tfreshContext.refresh();\n\t\t\tValueObjectWithSpecificConstructorSampleBean bean = freshContext\n\t\t\t\t.getBean(ValueObjectWithSpecificConstructorSampleBean.class);\n\t\t\tassertThat(bean.name).isEqualTo(\"Hello\");\n\t\t\tassertThat(bean.counter).isEqualTo(30);\n\t\t});\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid aotContributedInitializerBindsJavaBean() {\n\t\tcompile(createContext(), (freshContext) -> {\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(freshContext, \"test.name=Hello\");\n\t\t\tfreshContext.refresh();\n\t\t\tJavaBeanSampleBean bean = freshContext.getBean(JavaBeanSampleBean.class);\n\t\t\tassertThat(bean.getName()).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid aotContributedInitializerBindsScannedValueObject() {\n\t\tcompile(createContext(ScanTestConfiguration.class), (freshContext) -> {\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(freshContext, \"b.first.name=Hello\");\n\t\t\tfreshContext.refresh();\n\t\t\tBFirstProperties bean = freshContext.getBean(BFirstProperties.class);\n\t\t\tassertThat(bean.getName()).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid aotContributedInitializerBindsScannedJavaBean() {\n\t\tcompile(createContext(ScanTestConfiguration.class), (freshContext) -> {\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(freshContext, \"b.second.number=42\");\n\t\t\tfreshContext.refresh();\n\t\t\tBSecondProperties bean = freshContext.getBean(BSecondProperties.class);\n\t\t\tassertThat(bean.getNumber()).isEqualTo(42);\n\t\t});\n\t}\n\n\tprivate GenericApplicationContext createContext(Class<?>... types) {\n\t\tGenericApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.registerBean(JavaBeanSampleBeanConfiguration.class);\n\t\tArrays.stream(types).forEach((type) -> context.registerBean(type));\n\t\treturn context;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void compile(GenericApplicationContext context, Consumer<GenericApplicationContext> freshContext) {\n\t\tTestGenerationContext generationContext = new TestGenerationContext(TestTarget.class);\n\t\tClassName className = new ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\tgenerationContext.writeGeneratedContent();\n\t\tTestCompiler.forSystem()\n\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t.with(generationContext)\n\t\t\t.compile((compiled) -> {\n\t\t\t\tGenericApplicationContext freshApplicationContext = new GenericApplicationContext();\n\t\t\t\tApplicationContextInitializer<GenericApplicationContext> initializer = compiled\n\t\t\t\t\t.getInstance(ApplicationContextInitializer.class, className.toString());\n\t\t\t\tinitializer.initialize(freshApplicationContext);\n\t\t\t\tfreshContext.accept(freshApplicationContext);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(JavaBeanSampleBean.class)\n\tstatic class JavaBeanSampleBeanConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tpublic static class JavaBeanSampleBean {\n\n\t\tprivate @Nullable String name;\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ValueObjectSampleBean.class)\n\tstatic class ValueObjectSampleBeanConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tpublic static class ValueObjectSampleBean {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final String name;\n\n\t\tValueObjectSampleBean(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ValueObjectWithSpecificConstructorSampleBean.class)\n\tstatic class ValueObjectSampleBeanWithSpecificConstructorConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tpublic static class ValueObjectWithSpecificConstructorSampleBean {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final String name;\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final Integer counter;\n\n\t\tValueObjectWithSpecificConstructorSampleBean(String name, Integer counter) {\n\t\t\tthis.name = name;\n\t\t\tthis.counter = counter;\n\t\t}\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate ValueObjectWithSpecificConstructorSampleBean(String name) {\n\t\t\tthis(name, 42);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConfigurationPropertiesScan(basePackageClasses = BScanConfiguration.class)\n\tstatic class ScanTestConfiguration {\n\n\t}\n\n\tstatic class TestTarget {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.lang.reflect.Constructor;\nimport java.util.Map;\n\nimport net.bytebuddy.ByteBuddy;\nimport net.bytebuddy.ClassFileVersion;\nimport net.bytebuddy.description.annotation.AnnotationDescription;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.function.ThrowingConsumer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.bind.BindConstructorProvider;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.stereotype.Component;\nimport org.springframework.validation.annotation.Validated;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ConfigurationPropertiesBean}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigurationPropertiesBeanTests {\n\n\t@Test\n\tvoid getAllReturnsAll() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tNonAnnotatedComponent.class, AnnotatedComponent.class, AnnotatedBeanConfiguration.class,\n\t\t\t\tValueObjectConfiguration.class)) {\n\t\t\tMap<String, ConfigurationPropertiesBean> all = ConfigurationPropertiesBean.getAll(context);\n\t\t\tassertThat(all).containsOnlyKeys(\"annotatedComponent\", \"annotatedBean\", ValueObject.class.getName());\n\t\t\tConfigurationPropertiesBean component = all.get(\"annotatedComponent\");\n\t\t\tassertThat(component).isNotNull();\n\t\t\tassertThat(component.getName()).isEqualTo(\"annotatedComponent\");\n\t\t\tassertThat(component.getInstance()).isInstanceOf(AnnotatedComponent.class);\n\t\t\tassertThat(component.getAnnotation()).isNotNull();\n\t\t\tassertThat(component.getType()).isEqualTo(AnnotatedComponent.class);\n\t\t\tassertThat(component.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t\tConfigurationPropertiesBean bean = all.get(\"annotatedBean\");\n\t\t\tassertThat(bean).isNotNull();\n\t\t\tassertThat(bean.getName()).isEqualTo(\"annotatedBean\");\n\t\t\tassertThat(bean.getInstance()).isInstanceOf(AnnotatedBean.class);\n\t\t\tassertThat(bean.getType()).isEqualTo(AnnotatedBean.class);\n\t\t\tassertThat(bean.getAnnotation()).isNotNull();\n\t\t\tassertThat(bean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t\tConfigurationPropertiesBean valueObject = all.get(ValueObject.class.getName());\n\t\t\tassertThat(valueObject).isNotNull();\n\t\t\tassertThat(valueObject.getName()).isEqualTo(ValueObject.class.getName());\n\t\t\tassertThat(valueObject.getInstance()).isInstanceOf(ValueObject.class);\n\t\t\tassertThat(valueObject.getType()).isEqualTo(ValueObject.class);\n\t\t\tassertThat(valueObject.getAnnotation()).isNotNull();\n\t\t\tassertThat(valueObject.asBindTarget().getBindMethod()).isEqualTo(BindMethod.VALUE_OBJECT);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getAllDoesNotFindABeanDeclaredInAStaticBeanMethodOnAConfigurationAndConfigurationPropertiesAnnotatedClass() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tStaticBeanMethodConfiguration.class)) {\n\t\t\tMap<String, ConfigurationPropertiesBean> all = ConfigurationPropertiesBean.getAll(context);\n\t\t\tassertThat(all).containsOnlyKeys(\"configurationPropertiesBeanTests.StaticBeanMethodConfiguration\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getAllWhenHasBadBeanDoesNotFail() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tNonAnnotatedComponent.class, AnnotatedComponent.class, AnnotatedBeanConfiguration.class,\n\t\t\t\tValueObjectConfiguration.class, BadBeanConfiguration.class)) {\n\t\t\tMap<String, ConfigurationPropertiesBean> all = ConfigurationPropertiesBean.getAll(context);\n\t\t\tassertThat(all).isNotEmpty();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getWhenNotAnnotatedReturnsNull() throws Throwable {\n\t\tget(NonAnnotatedComponent.class, \"nonAnnotatedComponent\",\n\t\t\t\t(propertiesBean) -> assertThat(propertiesBean).isNull());\n\t}\n\n\t@Test\n\tvoid getWhenBeanIsAnnotatedReturnsBean() throws Throwable {\n\t\tget(AnnotatedComponent.class, \"annotatedComponent\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getName()).isEqualTo(\"annotatedComponent\");\n\t\t\tassertThat(propertiesBean.getInstance()).isInstanceOf(AnnotatedComponent.class);\n\t\t\tassertThat(propertiesBean.getType()).isEqualTo(AnnotatedComponent.class);\n\t\t\tassertThat(propertiesBean.getAnnotation().prefix()).isEqualTo(\"prefix\");\n\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenFactoryMethodIsAnnotatedReturnsBean() throws Throwable {\n\t\tget(NonAnnotatedBeanConfiguration.class, \"nonAnnotatedBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getName()).isEqualTo(\"nonAnnotatedBean\");\n\t\t\tassertThat(propertiesBean.getInstance()).isInstanceOf(NonAnnotatedBean.class);\n\t\t\tassertThat(propertiesBean.getType()).isEqualTo(NonAnnotatedBean.class);\n\t\t\tassertThat(propertiesBean.getAnnotation().prefix()).isEqualTo(\"prefix\");\n\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenImportedFactoryMethodIsAnnotatedAndMetadataCachingIsDisabledReturnsBean() throws Throwable {\n\t\tgetWithoutBeanMetadataCaching(NonAnnotatedBeanImportConfiguration.class, \"nonAnnotatedBean\",\n\t\t\t\t(propertiesBean) -> {\n\t\t\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\t\t\tassertThat(propertiesBean.getName()).isEqualTo(\"nonAnnotatedBean\");\n\t\t\t\t\tassertThat(propertiesBean.getInstance()).isInstanceOf(NonAnnotatedBean.class);\n\t\t\t\t\tassertThat(propertiesBean.getType()).isEqualTo(NonAnnotatedBean.class);\n\t\t\t\t\tassertThat(propertiesBean.getAnnotation().prefix()).isEqualTo(\"prefix\");\n\t\t\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenImportedFactoryMethodIsAnnotatedReturnsBean() throws Throwable {\n\t\tget(NonAnnotatedBeanImportConfiguration.class, \"nonAnnotatedBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getName()).isEqualTo(\"nonAnnotatedBean\");\n\t\t\tassertThat(propertiesBean.getInstance()).isInstanceOf(NonAnnotatedBean.class);\n\t\t\tassertThat(propertiesBean.getType()).isEqualTo(NonAnnotatedBean.class);\n\t\t\tassertThat(propertiesBean.getAnnotation().prefix()).isEqualTo(\"prefix\");\n\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasFactoryMethodBindsUsingMethodReturnType() throws Throwable {\n\t\tget(NonAnnotatedGenericBeanConfiguration.class, \"nonAnnotatedGenericBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getType()).isEqualTo(NonAnnotatedGenericBean.class);\n\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t\tResolvableType type = propertiesBean.asBindTarget().getType();\n\t\t\tassertThat(type.resolve()).isEqualTo(NonAnnotatedGenericBean.class);\n\t\t\tassertThat(type.resolveGeneric(0)).isEqualTo(String.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasFactoryMethodWithoutAnnotationBindsUsingMethodType() throws Throwable {\n\t\tget(AnnotatedGenericBeanConfiguration.class, \"annotatedGenericBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getType()).isEqualTo(AnnotatedGenericBean.class);\n\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t\tResolvableType type = propertiesBean.asBindTarget().getType();\n\t\t\tassertThat(type.resolve()).isEqualTo(AnnotatedGenericBean.class);\n\t\t\tassertThat(type.resolveGeneric(0)).isEqualTo(String.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasNoFactoryMethodBindsUsingObjectType() throws Throwable {\n\t\tget(AnnotatedGenericComponent.class, \"annotatedGenericComponent\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getType()).isEqualTo(AnnotatedGenericComponent.class);\n\t\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.JAVA_BEAN);\n\t\t\tResolvableType type = propertiesBean.asBindTarget().getType();\n\t\t\tassertThat(type.resolve()).isEqualTo(AnnotatedGenericComponent.class);\n\t\t\tassertThat(type.getGeneric(0).resolve()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasFactoryMethodAndBeanAnnotationFavorsFactoryMethod() throws Throwable {\n\t\tget(AnnotatedBeanConfiguration.class, \"annotatedBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tassertThat(propertiesBean.getAnnotation().prefix()).isEqualTo(\"factory\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasValidatedBeanBindsWithBeanAnnotation() throws Throwable {\n\t\tget(ValidatedBeanConfiguration.class, \"validatedBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tValidated validated = propertiesBean.asBindTarget().getAnnotation(Validated.class);\n\t\t\tassertThat(validated).isNotNull();\n\t\t\tassertThat(validated.value()).containsExactly(BeanGroup.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasValidatedFactoryMethodBindsWithFactoryMethodAnnotation() throws Throwable {\n\t\tget(ValidatedMethodConfiguration.class, \"annotatedBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tValidated validated = propertiesBean.asBindTarget().getAnnotation(Validated.class);\n\t\t\tassertThat(validated).isNotNull();\n\t\t\tassertThat(validated.value()).containsExactly(FactoryMethodGroup.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWhenHasValidatedBeanAndFactoryMethodBindsWithFactoryMethodAnnotation() throws Throwable {\n\t\tget(ValidatedMethodAndBeanConfiguration.class, \"validatedBean\", (propertiesBean) -> {\n\t\t\tassertThat(propertiesBean).isNotNull();\n\t\t\tValidated validated = propertiesBean.asBindTarget().getAnnotation(Validated.class);\n\t\t\tassertThat(validated).isNotNull();\n\t\t\tassertThat(validated.value()).containsExactly(FactoryMethodGroup.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid forValueObjectWithConstructorBindingAnnotatedClassReturnsBean() {\n\t\tConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean\n\t\t\t.forValueObject(ConstructorBindingOnConstructor.class, \"valueObjectBean\");\n\t\tassertThat(propertiesBean.getName()).isEqualTo(\"valueObjectBean\");\n\t\tassertThat(propertiesBean.getInstance()).isNull();\n\t\tassertThat(propertiesBean.getType()).isEqualTo(ConstructorBindingOnConstructor.class);\n\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.VALUE_OBJECT);\n\t\tassertThat(propertiesBean.getAnnotation()).isNotNull();\n\t\tBindable<?> target = propertiesBean.asBindTarget();\n\t\tassertThat(target.getType()).isEqualTo(ResolvableType.forClass(ConstructorBindingOnConstructor.class));\n\t\tassertThat(target.getValue()).isNull();\n\t\tassertThat(BindConstructorProvider.DEFAULT.getBindConstructor(ConstructorBindingOnConstructor.class, false))\n\t\t\t.isNotNull();\n\t}\n\n\t@Test\n\tvoid forValueObjectWithRecordReturnsBean() {\n\t\tClass<?> implicitConstructorBinding = new ByteBuddy(ClassFileVersion.JAVA_V16).makeRecord()\n\t\t\t.name(\"org.springframework.boot.context.properties.ImplicitConstructorBinding\")\n\t\t\t.annotateType(AnnotationDescription.Builder.ofType(ConfigurationProperties.class)\n\t\t\t\t.define(\"prefix\", \"implicit\")\n\t\t\t\t.build())\n\t\t\t.defineRecordComponent(\"someString\", String.class)\n\t\t\t.defineRecordComponent(\"someInteger\", Integer.class)\n\t\t\t.make()\n\t\t\t.load(getClass().getClassLoader())\n\t\t\t.getLoaded();\n\t\tConfigurationPropertiesBean propertiesBean = ConfigurationPropertiesBean\n\t\t\t.forValueObject(implicitConstructorBinding, \"implicitBindingRecord\");\n\t\tassertThat(propertiesBean.getName()).isEqualTo(\"implicitBindingRecord\");\n\t\tassertThat(propertiesBean.getInstance()).isNull();\n\t\tassertThat(propertiesBean.getType()).isEqualTo(implicitConstructorBinding);\n\t\tassertThat(propertiesBean.asBindTarget().getBindMethod()).isEqualTo(BindMethod.VALUE_OBJECT);\n\t\tassertThat(propertiesBean.getAnnotation()).isNotNull();\n\t\tBindable<?> target = propertiesBean.asBindTarget();\n\t\tassertThat(target.getType()).isEqualTo(ResolvableType.forClass(implicitConstructorBinding));\n\t\tassertThat(target.getValue()).isNull();\n\t\tConstructor<?> bindConstructor = BindConstructorProvider.DEFAULT.getBindConstructor(implicitConstructorBinding,\n\t\t\t\tfalse);\n\t\tassertThat(bindConstructor).isNotNull();\n\t\tassertThat(bindConstructor.getParameterTypes()).containsExactly(String.class, Integer.class);\n\t}\n\n\t@Test\n\tvoid forValueObjectWhenJavaBeanBindTypeThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> ConfigurationPropertiesBean.forValueObject(AnnotatedBean.class, \"annotatedBean\"))\n\t\t\t.withMessage(\"Bean 'annotatedBean' is not a @ConfigurationProperties value object\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> ConfigurationPropertiesBean.forValueObject(NonAnnotatedBean.class, \"nonAnnotatedBean\"))\n\t\t\t.withMessage(\"Bean 'nonAnnotatedBean' is not a @ConfigurationProperties value object\");\n\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWhenNoConstructorBindingReturnsJavaBean() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(NoConstructorBinding.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWhenConstructorBindingOnConstructorReturnsValueObject() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(ConstructorBindingOnConstructor.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.VALUE_OBJECT);\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWhenNoConstructorBindingAnnotationOnSingleParameterizedConstructorReturnsValueObject() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(ConstructorBindingNoAnnotation.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.VALUE_OBJECT);\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWhenConstructorBindingOnMultipleConstructorsThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> ConfigurationPropertiesBean.deduceBindMethod(ConstructorBindingOnMultipleConstructors.class))\n\t\t\t.withMessage(ConstructorBindingOnMultipleConstructors.class.getName()\n\t\t\t\t\t+ \" has more than one @ConstructorBinding constructor\");\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWithMultipleConstructorsReturnJavaBean() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean\n\t\t\t.deduceBindMethod(NoConstructorBindingOnMultipleConstructors.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWithNoArgConstructorReturnsJavaBean() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(JavaBeanWithNoArgConstructor.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid deduceBindMethodWithSingleArgAutowiredConstructorReturnsJavaBean() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(JavaBeanWithAutowiredConstructor.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid constructorBindingAndAutowiredConstructorsShouldThrowException() {\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> ConfigurationPropertiesBean.deduceBindMethod(ConstructorBindingAndAutowiredConstructors.class));\n\t}\n\n\t@Test\n\tvoid innerClassWithSyntheticFieldShouldReturnJavaBean() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(Inner.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid innerClassWithParameterizedConstructorShouldReturnJavaBean() {\n\t\tBindMethod bindType = ConfigurationPropertiesBean.deduceBindMethod(ParameterizedConstructorInner.class);\n\t\tassertThat(bindType).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\tprivate void get(Class<?> configuration, String beanName,\n\t\t\tThrowingConsumer<@Nullable ConfigurationPropertiesBean> consumer) throws Throwable {\n\t\tget(configuration, beanName, true, consumer);\n\t}\n\n\tprivate void getWithoutBeanMetadataCaching(Class<?> configuration, String beanName,\n\t\t\tThrowingConsumer<@Nullable ConfigurationPropertiesBean> consumer) throws Throwable {\n\t\tget(configuration, beanName, false, consumer);\n\t}\n\n\tprivate void get(Class<?> configuration, String beanName, boolean cacheBeanMetadata,\n\t\t\tThrowingConsumer<@Nullable ConfigurationPropertiesBean> consumer) throws Throwable {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.getBeanFactory().setCacheBeanMetadata(cacheBeanMetadata);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tObject bean = context.getBean(beanName);\n\t\t\tconsumer.accept(ConfigurationPropertiesBean.get(context, bean, beanName));\n\t\t}\n\t}\n\n\t@Component(\"nonAnnotatedComponent\")\n\tstatic class NonAnnotatedComponent {\n\n\t}\n\n\t@Component(\"annotatedComponent\")\n\t@ConfigurationProperties(\"prefix\")\n\tstatic class AnnotatedComponent {\n\n\t}\n\n\t@ConfigurationProperties(\"prefix\")\n\tstatic class AnnotatedBean {\n\n\t}\n\n\tstatic class NonAnnotatedBean {\n\n\t}\n\n\tstatic class NonAnnotatedGenericBean<T> {\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class AnnotatedGenericBean<T> {\n\n\t}\n\n\t@Component(\"annotatedGenericComponent\")\n\t@ConfigurationProperties\n\tstatic class AnnotatedGenericComponent<T> {\n\n\t}\n\n\t@Validated(BeanGroup.class)\n\t@ConfigurationProperties\n\tstatic class ValidatedBean {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonAnnotatedBeanConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"prefix\")\n\t\tNonAnnotatedBean nonAnnotatedBean() {\n\t\t\treturn new NonAnnotatedBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonAnnotatedGenericBeanConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties\n\t\tNonAnnotatedGenericBean<String> nonAnnotatedGenericBean() {\n\t\t\treturn new NonAnnotatedGenericBean<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotatedGenericBeanConfiguration {\n\n\t\t@Bean\n\t\tAnnotatedGenericBean<String> annotatedGenericBean() {\n\t\t\treturn new AnnotatedGenericBean<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotatedBeanConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"factory\")\n\t\tAnnotatedBean annotatedBean() {\n\t\t\treturn new AnnotatedBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ValidatedBeanConfiguration {\n\n\t\t@Bean\n\t\tValidatedBean validatedBean() {\n\t\t\treturn new ValidatedBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ValidatedMethodConfiguration {\n\n\t\t@Bean\n\t\t@Validated(FactoryMethodGroup.class)\n\t\tAnnotatedBean annotatedBean() {\n\t\t\treturn new AnnotatedBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ValidatedMethodAndBeanConfiguration {\n\n\t\t@Bean\n\t\t@Validated(FactoryMethodGroup.class)\n\t\tValidatedBean validatedBean() {\n\t\t\treturn new ValidatedBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ValueObject.class)\n\tstatic class ValueObjectConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BadBeanConfiguration {\n\n\t\t@Bean\n\t\t@Lazy\n\t\tBadBean badBean() {\n\t\t\treturn new BadBean();\n\t\t}\n\n\t}\n\n\tstatic class BadBean {\n\n\t\tBadBean() {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class ValueObject {\n\n\t\tValueObject(String name) {\n\t\t}\n\n\t}\n\n\tstatic class BeanGroup {\n\n\t}\n\n\tstatic class FactoryMethodGroup {\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class NoConstructorBinding {\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class ConstructorBindingNoAnnotation {\n\n\t\tConstructorBindingNoAnnotation(String name) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class ConstructorBindingOnConstructor {\n\n\t\tConstructorBindingOnConstructor(String name) {\n\t\t\tthis(name, -1);\n\t\t}\n\n\t\t@ConstructorBinding\n\t\tConstructorBindingOnConstructor(String name, int age) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class ConstructorBindingOnMultipleConstructors {\n\n\t\t@ConstructorBinding\n\t\tConstructorBindingOnMultipleConstructors(String name) {\n\t\t\tthis(name, -1);\n\t\t}\n\n\t\t@ConstructorBinding\n\t\tConstructorBindingOnMultipleConstructors(String name, int age) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class NoConstructorBindingOnMultipleConstructors {\n\n\t\tNoConstructorBindingOnMultipleConstructors(String name) {\n\t\t\tthis(name, -1);\n\t\t}\n\n\t\tNoConstructorBindingOnMultipleConstructors(String name, int age) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class JavaBeanWithAutowiredConstructor {\n\n\t\t@Autowired\n\t\tJavaBeanWithAutowiredConstructor(String name) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class JavaBeanWithNoArgConstructor {\n\n\t\tJavaBeanWithNoArgConstructor() {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class ConstructorBindingAndAutowiredConstructors {\n\n\t\t@Autowired\n\t\tConstructorBindingAndAutowiredConstructors(String name) {\n\t\t}\n\n\t\t@ConstructorBinding\n\t\tConstructorBindingAndAutowiredConstructors(Integer age) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(NonAnnotatedBeanConfigurationImportSelector.class)\n\tstatic class NonAnnotatedBeanImportConfiguration {\n\n\t}\n\n\tstatic class NonAnnotatedBeanConfigurationImportSelector implements ImportSelector {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\treturn new String[] { NonAnnotatedBeanConfiguration.class.getName() };\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tclass Inner {\n\n\t}\n\n\t@ConfigurationProperties\n\tclass ParameterizedConstructorInner {\n\n\t\tParameterizedConstructorInner(Integer age) {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConfigurationProperties\n\tstatic class StaticBeanMethodConfiguration {\n\n\t\t@Bean\n\t\tstatic String stringBean() {\n\t\t\treturn \"example\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.stereotype.Component;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesBindException}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertiesBindExceptionTests {\n\n\t@Test\n\tvoid createFromBeanHasDetails() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(Example.class);\n\t\tConfigurationPropertiesBean bean = ConfigurationPropertiesBean.get(applicationContext,\n\t\t\t\tapplicationContext.getBean(Example.class), \"example\");\n\t\tassertThat(bean).isNotNull();\n\t\tConfigurationPropertiesBindException exception = new ConfigurationPropertiesBindException(bean,\n\t\t\t\tnew IllegalStateException());\n\t\tassertThat(exception.getMessage()).isEqualTo(\"Error creating bean with name 'example': \"\n\t\t\t\t+ \"Could not bind properties to 'ConfigurationPropertiesBindExceptionTests.Example' : \"\n\t\t\t\t+ \"prefix=, ignoreInvalidFields=false, ignoreUnknownFields=true\");\n\t\tassertThat(exception.getBeanType()).isEqualTo(Example.class);\n\t\tassertThat(exception.getBeanName()).isEqualTo(\"example\");\n\t\tassertThat(exception.getAnnotation()).isInstanceOf(ConfigurationProperties.class);\n\t\tassertThat(exception.getCause()).isInstanceOf(IllegalStateException.class);\n\t}\n\n\t@Component(\"example\")\n\t@ConfigurationProperties\n\tstatic class Example {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindHandlerAdvisorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesBindHandlerAdvisor}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertiesBindHandlerAdvisorTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid loadWithoutConfigurationPropertiesBindHandlerAdvisor() {\n\t\tload(WithoutConfigurationPropertiesBindHandlerAdvisor.class, \"foo.bar.default.content-type=text/plain\",\n\t\t\t\t\"foo.bar.bindings.input.destination=d1\", \"foo.bar.bindings.input.content-type=text/xml\",\n\t\t\t\t\"foo.bar.bindings.output.destination=d2\");\n\t\tBindingServiceProperties properties = this.context.getBean(BindingServiceProperties.class);\n\t\tBindingProperties input = properties.getBindings().get(\"input\");\n\t\tassertThat(input).isNotNull();\n\t\tassertThat(input.getDestination()).isEqualTo(\"d1\");\n\t\tassertThat(input.getContentType()).isEqualTo(\"text/xml\");\n\t\tBindingProperties output = properties.getBindings().get(\"output\");\n\t\tassertThat(output).isNotNull();\n\t\tassertThat(output.getDestination()).isEqualTo(\"d2\");\n\t\tassertThat(output.getContentType()).isEqualTo(\"application/json\");\n\t}\n\n\t@Test\n\tvoid loadWithConfigurationPropertiesBindHandlerAdvisor() {\n\t\tload(WithConfigurationPropertiesBindHandlerAdvisor.class, \"foo.bar.default.content-type=text/plain\",\n\t\t\t\t\"foo.bar.bindings.input.destination=d1\", \"foo.bar.bindings.input.content-type=text/xml\",\n\t\t\t\t\"foo.bar.bindings.output.destination=d2\");\n\t\tBindingServiceProperties properties = this.context.getBean(BindingServiceProperties.class);\n\t\tBindingProperties input = properties.getBindings().get(\"input\");\n\t\tassertThat(input).isNotNull();\n\t\tassertThat(input.getDestination()).isEqualTo(\"d1\");\n\t\tassertThat(input.getContentType()).isEqualTo(\"text/xml\");\n\t\tBindingProperties output = properties.getBindings().get(\"output\");\n\t\tassertThat(output).isNotNull();\n\t\tassertThat(output.getDestination()).isEqualTo(\"d2\");\n\t\tassertThat(output.getContentType()).isEqualTo(\"text/plain\");\n\t}\n\n\tprivate AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {\n\t\treturn load(new Class<?>[] { configuration }, inlinedProperties);\n\t}\n\n\tprivate AnnotationConfigApplicationContext load(Class<?>[] configuration, String... inlinedProperties) {\n\t\tthis.context.register(configuration);\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, inlinedProperties);\n\t\tthis.context.refresh();\n\t\treturn this.context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(BindingServiceProperties.class)\n\tstatic class WithoutConfigurationPropertiesBindHandlerAdvisor {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(BindingServiceProperties.class)\n\t@Import(DefaultValuesConfigurationPropertiesBindHandlerAdvisor.class)\n\tstatic class WithConfigurationPropertiesBindHandlerAdvisor {\n\n\t}\n\n\tstatic class DefaultValuesConfigurationPropertiesBindHandlerAdvisor\n\t\t\timplements ConfigurationPropertiesBindHandlerAdvisor {\n\n\t\t@Override\n\t\tpublic BindHandler apply(BindHandler bindHandler) {\n\t\t\treturn new DefaultValuesBindHandler(bindHandler);\n\t\t}\n\n\t}\n\n\tstatic class DefaultValuesBindHandler extends AbstractBindHandler {\n\n\t\tprivate final Map<ConfigurationPropertyName, ConfigurationPropertyName> mappings;\n\n\t\tDefaultValuesBindHandler(BindHandler bindHandler) {\n\t\t\tsuper(bindHandler);\n\t\t\tthis.mappings = new LinkedHashMap<>();\n\t\t\tthis.mappings.put(ConfigurationPropertyName.of(\"foo.bar.bindings\"),\n\t\t\t\t\tConfigurationPropertyName.of(\"foo.bar.default\"));\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target,\n\t\t\t\tBindContext context) {\n\t\t\tConfigurationPropertyName defaultName = getDefaultName(name);\n\t\t\tif (defaultName != null) {\n\t\t\t\tBindResult<T> result = context.getBinder().bind(defaultName, target);\n\t\t\t\tif (result.isBound()) {\n\t\t\t\t\treturn target.withExistingValue(result.get());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.onStart(name, target, context);\n\t\t}\n\n\t\tprivate @Nullable ConfigurationPropertyName getDefaultName(ConfigurationPropertyName name) {\n\t\t\tfor (Map.Entry<ConfigurationPropertyName, ConfigurationPropertyName> mapping : this.mappings.entrySet()) {\n\t\t\t\tConfigurationPropertyName from = mapping.getKey();\n\t\t\t\tConfigurationPropertyName to = mapping.getValue();\n\t\t\t\tif (name.getNumberOfElements() == from.getNumberOfElements() + 1 && from.isParentOf(name)) {\n\t\t\t\t\treturn to;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"foo.bar\")\n\tstatic class BindingServiceProperties {\n\n\t\tprivate final Map<String, BindingProperties> bindings = new TreeMap<>();\n\n\t\tMap<String, BindingProperties> getBindings() {\n\t\t\treturn this.bindings;\n\t\t}\n\n\t}\n\n\tstatic class BindingProperties {\n\n\t\tprivate @Nullable String destination;\n\n\t\tprivate String contentType = \"application/json\";\n\n\t\t@Nullable String getDestination() {\n\t\t\treturn this.destination;\n\t\t}\n\n\t\tvoid setDestination(@Nullable String destination) {\n\t\t\tthis.destination = destination;\n\t\t}\n\n\t\tString getContentType() {\n\t\t\treturn this.contentType;\n\t\t}\n\n\t\tvoid setContentType(String contentType) {\n\t\t\tthis.contentType = contentType;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesCharSequenceToObjectConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.convert.ConversionServiceArguments;\nimport org.springframework.boot.convert.ConversionServiceTest;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.format.support.DefaultFormattingConversionService;\nimport org.springframework.format.support.FormattingConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesCharSequenceToObjectConverter}\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesCharSequenceToObjectConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenCanConvertViaToString(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(new StringBuilder(\"1\"), Integer.class)).isOne();\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenCanConvertDirectlySkipsStringConversion(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(new String(\"1\"), Long.class)).isOne();\n\t\tif (!ConversionServiceArguments.isApplicationConversionService(conversionService)) {\n\t\t\tassertThat(conversionService.convert(new StringBuilder(\"1\"), Long.class)).isEqualTo(2);\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenTargetIsList() {\n\t\tConversionService conversionService = new ApplicationConversionService();\n\t\tStringBuilder source = new StringBuilder(\"1,2,3\");\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(StringBuilder.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));\n\t\tList<String> converted = (List<String>) conversionService.convert(source, sourceType, targetType);\n\t\tassertThat(converted).containsExactly(\"1\", \"2\", \"3\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenTargetIsListAndNotUsingApplicationConversionService() {\n\t\tFormattingConversionService conversionService = new DefaultFormattingConversionService();\n\t\tconversionService.addConverter(new ConfigurationPropertiesCharSequenceToObjectConverter(conversionService));\n\t\tStringBuilder source = new StringBuilder(\"1,2,3\");\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(StringBuilder.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));\n\t\tList<String> converted = (List<String>) conversionService.convert(source, sourceType, targetType);\n\t\tassertThat(converted).containsExactly(\"1\", \"2\", \"3\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with((conversionService) -> {\n\t\t\tconversionService.addConverter(new StringToIntegerConverter());\n\t\t\tconversionService.addConverter(new StringToLongConverter());\n\t\t\tconversionService.addConverter(new CharSequenceToLongConverter());\n\t\t\tconversionService.addConverter(new ConfigurationPropertiesCharSequenceToObjectConverter(conversionService));\n\t\t});\n\t}\n\n\tstatic class StringToIntegerConverter implements Converter<String, Integer> {\n\n\t\t@Override\n\t\tpublic Integer convert(String source) {\n\t\t\treturn Integer.valueOf(source);\n\t\t}\n\n\t}\n\n\tstatic class StringToLongConverter implements Converter<String, Long> {\n\n\t\t@Override\n\t\tpublic Long convert(String source) {\n\t\t\treturn Long.valueOf(source);\n\t\t}\n\n\t}\n\n\tstatic class CharSequenceToLongConverter implements Converter<CharSequence, Long> {\n\n\t\t@Override\n\t\tpublic Long convert(CharSequence source) {\n\t\t\treturn Long.parseLong(source.toString()) + 1;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.io.IOException;\nimport java.util.Locale;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.boot.context.properties.scan.combined.c.CombinedConfiguration;\nimport org.springframework.boot.context.properties.scan.combined.d.OtherCombinedConfiguration;\nimport org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesScanRegistrar}.\n *\n * @author Madhura Bhave\n */\nclass ConfigurationPropertiesScanRegistrarTests {\n\n\tprivate final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\tprivate final ConfigurationPropertiesScanRegistrar registrar = new ConfigurationPropertiesScanRegistrar(\n\t\t\tnew MockEnvironment(), null);\n\n\t@Test\n\tvoid registerBeanDefinitionsShouldScanForConfigurationProperties() throws IOException {\n\t\tthis.registrar.registerBeanDefinitions(getAnnotationMetadata(ConfigurationPropertiesScanConfiguration.class),\n\t\t\t\tthis.beanFactory);\n\t\tBeanDefinition bingDefinition = this.beanFactory.getBeanDefinition(\n\t\t\t\t\"bing-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$BingProperties\");\n\t\tBeanDefinition fooDefinition = this.beanFactory.getBeanDefinition(\n\t\t\t\t\"foo-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$FooProperties\");\n\t\tBeanDefinition barDefinition = this.beanFactory.getBeanDefinition(\n\t\t\t\t\"bar-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$BarProperties\");\n\t\tassertThat(bingDefinition).satisfies(hasBindMethod(BindMethod.JAVA_BEAN));\n\t\tassertThat(fooDefinition).satisfies(hasBindMethod(BindMethod.JAVA_BEAN));\n\t\tassertThat(barDefinition).satisfies(hasBindMethod(BindMethod.VALUE_OBJECT));\n\t}\n\n\t@Test\n\tvoid scanWhenBeanDefinitionExistsShouldSkip() throws IOException {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tbeanFactory.setAllowBeanDefinitionOverriding(false);\n\t\tthis.registrar.registerBeanDefinitions(\n\t\t\t\tgetAnnotationMetadata(ConfigurationPropertiesScanConfiguration.TestConfiguration.class), beanFactory);\n\t\tassertThat(beanFactory.containsBeanDefinition(\n\t\t\t\t\"foo-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$FooProperties\"))\n\t\t\t.isTrue();\n\t\tassertThat(beanFactory.getBeanDefinitionNames())\n\t\t\t.filteredOn((name) -> name.toLowerCase(Locale.ENGLISH).contains(\"fooproperties\"))\n\t\t\t.hasSize(1);\n\t}\n\n\t@Test\n\tvoid scanWhenBasePackagesAndBasePackageClassesProvidedShouldUseThat() throws IOException {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tbeanFactory.setAllowBeanDefinitionOverriding(false);\n\t\tthis.registrar.registerBeanDefinitions(\n\t\t\t\tgetAnnotationMetadata(ConfigurationPropertiesScanConfiguration.DifferentPackageConfiguration.class),\n\t\t\t\tbeanFactory);\n\t\tassertThat(beanFactory.containsBeanDefinition(\n\t\t\t\t\"foo-org.springframework.boot.context.properties.scan.valid.ConfigurationPropertiesScanConfiguration$FooProperties\"))\n\t\t\t.isFalse();\n\t\tBeanDefinition aDefinition = beanFactory.getBeanDefinition(\n\t\t\t\t\"a-org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration$AProperties\");\n\t\tBeanDefinition bFirstDefinition = beanFactory.getBeanDefinition(\n\t\t\t\t\"b.first-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BFirstProperties\");\n\t\tBeanDefinition bSecondDefinition = beanFactory.getBeanDefinition(\n\t\t\t\t\"b.second-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BSecondProperties\");\n\t\tassertThat(aDefinition).satisfies(hasBindMethod(BindMethod.JAVA_BEAN));\n\t\t// Constructor injection\n\t\tassertThat(bFirstDefinition).satisfies(hasBindMethod(BindMethod.VALUE_OBJECT));\n\t\t// Post-processing injection\n\t\tassertThat(bSecondDefinition).satisfies(hasBindMethod(BindMethod.JAVA_BEAN));\n\t}\n\n\t@Test\n\tvoid scanWhenComponentAnnotationPresentShouldSkipType() throws IOException {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tbeanFactory.setAllowBeanDefinitionOverriding(false);\n\t\tthis.registrar.registerBeanDefinitions(getAnnotationMetadata(CombinedScanConfiguration.class), beanFactory);\n\t\tassertThat(beanFactory.getBeanDefinitionCount()).isZero();\n\t}\n\n\t@Test\n\tvoid scanWhenOtherComponentAnnotationPresentShouldSkipType() throws IOException {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tbeanFactory.setAllowBeanDefinitionOverriding(false);\n\t\tthis.registrar.registerBeanDefinitions(getAnnotationMetadata(OtherCombinedScanConfiguration.class),\n\t\t\t\tbeanFactory);\n\t\tassertThat(beanFactory.getBeanDefinitionCount()).isZero();\n\t}\n\n\tprivate Consumer<BeanDefinition> hasBindMethod(BindMethod bindMethod) {\n\t\treturn (definition) -> {\n\t\t\tassertThat(definition.hasAttribute(BindMethod.class.getName())).isTrue();\n\t\t\tassertThat(definition.getAttribute(BindMethod.class.getName())).isEqualTo(bindMethod);\n\t\t};\n\t}\n\n\tprivate AnnotationMetadata getAnnotationMetadata(Class<?> source) throws IOException {\n\t\treturn new SimpleMetadataReaderFactory().getMetadataReader(source.getName()).getAnnotationMetadata();\n\t}\n\n\t@ConfigurationPropertiesScan(basePackageClasses = CombinedConfiguration.class)\n\tstatic class CombinedScanConfiguration {\n\n\t}\n\n\t@ConfigurationPropertiesScan(basePackageClasses = OtherCombinedConfiguration.class)\n\tstatic class OtherCombinedScanConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesScanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.io.IOException;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BFirstProperties;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BProperties;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration.BSecondProperties;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.filter.AssignableTypeFilter;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willCallRealMethod;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link ConfigurationPropertiesScan @ConfigurationPropertiesScan}.\n *\n * @author Madhura Bhave\n * @author Johnny Lim\n * @author Stephane Nicoll\n */\nclass ConfigurationPropertiesScanTests {\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t}\n\n\t@AfterEach\n\tvoid teardown() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid scanImportBeanRegistrarShouldBeEnvironmentAwareWithRequiredProfile() {\n\t\tthis.context.getEnvironment().addActiveProfile(\"test\");\n\t\tload(TestConfiguration.class);\n\t\tassertThat(this.context.containsBean(\n\t\t\t\t\"profile-org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration$MyProfileProperties\"))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid scanImportBeanRegistrarShouldBeEnvironmentAwareWithoutRequiredProfile() {\n\t\tload(TestConfiguration.class);\n\t\tassertThat(this.context.containsBean(\n\t\t\t\t\"profile-org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration$MyProfileProperties\"))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid scanImportBeanRegistrarShouldBeResourceLoaderAwareWithRequiredResource() {\n\t\tDefaultResourceLoader resourceLoader = mock(DefaultResourceLoader.class);\n\t\tthis.context.setResourceLoader(resourceLoader);\n\t\twillCallRealMethod().given(resourceLoader).getClassLoader();\n\t\tgiven(resourceLoader.getResource(\"test\")).willReturn(new ByteArrayResource(\"test\".getBytes()));\n\t\tload(TestConfiguration.class);\n\t\tassertThat(this.context.containsBean(\n\t\t\t\t\"resource-org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration$MyResourceProperties\"))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid scanImportBeanRegistrarShouldBeResourceLoaderAwareWithoutRequiredResource() {\n\t\tload(TestConfiguration.class);\n\t\tassertThat(this.context.containsBean(\n\t\t\t\t\"resource-org.springframework.boot.context.properties.scan.valid.a.AScanConfiguration$MyResourceProperties\"))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid scanImportBeanRegistrarShouldUsePackageName() {\n\t\tload(TestAnotherPackageConfiguration.class);\n\t\tassertThat(this.context.getBeanNamesForType(BProperties.class)).containsOnly(\n\t\t\t\t\"b.first-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BFirstProperties\",\n\t\t\t\t\"b.second-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BSecondProperties\");\n\t}\n\n\t@Test\n\tvoid scanImportBeanRegistrarShouldApplyTypeExcludeFilter() {\n\t\tthis.context.getBeanFactory().registerSingleton(\"filter\", new ConfigurationPropertiesTestTypeExcludeFilter());\n\t\tthis.context.register(TestAnotherPackageConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBeanNamesForType(BProperties.class)).containsOnly(\n\t\t\t\t\"b.first-org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration$BFirstProperties\");\n\t}\n\n\t@Test\n\tvoid scanShouldBindConfigurationProperties() {\n\t\tload(TestAnotherPackageConfiguration.class, \"b.first.name=constructor\", \"b.second.number=42\");\n\t\tassertThat(this.context.getBean(BFirstProperties.class).getName()).isEqualTo(\"constructor\");\n\t\tassertThat(this.context.getBean(BSecondProperties.class).getNumber()).isEqualTo(42);\n\t}\n\n\tprivate void load(Class<?> configuration, String... inlinedProperties) {\n\t\tthis.context.register(configuration);\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, inlinedProperties);\n\t\tthis.context.refresh();\n\t}\n\n\t@ConfigurationPropertiesScan(basePackageClasses = AScanConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@ConfigurationPropertiesScan(basePackages = \"org.springframework.boot.context.properties.scan.valid.b\")\n\tstatic class TestAnotherPackageConfiguration {\n\n\t}\n\n\tstatic class ConfigurationPropertiesTestTypeExcludeFilter extends TypeExcludeFilter {\n\n\t\t@Override\n\t\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\t\tthrows IOException {\n\t\t\tAssignableTypeFilter typeFilter = new AssignableTypeFilter(BFirstProperties.class);\n\t\t\treturn !typeFilter.match(metadataReader, metadataReaderFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object o) {\n\t\t\treturn (this == o);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Objects.hash(42);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTestBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.bean.override.convention.TestBean;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for overriding {@link ConfigurationProperties @ConfigurationProperties} with\n * {@link TestBean @TestBean}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@TestPropertySource(properties = \"immutable.property=test-property-source\")\nclass ConfigurationPropertiesTestBeanTests {\n\n\t@TestBean\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ImmutableProperties properties;\n\n\t@Autowired\n\tprivate SomeConfiguration someConfiguration;\n\n\t@Test\n\tvoid propertiesCanBeOverriddenUsingTestBean() {\n\t\tassertThat(this.properties.property).isEqualTo(\"test-bean\");\n\t\tassertThat(this.someConfiguration.properties.property).isEqualTo(\"test-bean\");\n\t}\n\n\tstatic ImmutableProperties properties() {\n\t\treturn new ImmutableProperties(\"test-bean\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ImmutableProperties.class)\n\tstatic class SomeConfiguration {\n\n\t\tprivate final ImmutableProperties properties;\n\n\t\tSomeConfiguration(ImmutableProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"immutable\")\n\tstatic class ImmutableProperties {\n\n\t\tprivate final String property;\n\n\t\tImmutableProperties(String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t\tString getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.beans.PropertyEditorSupport;\nimport java.io.File;\nimport java.text.ParseException;\nimport java.time.Duration;\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport jakarta.annotation.PostConstruct;\nimport jakarta.validation.Valid;\nimport jakarta.validation.constraints.NotEmpty;\nimport jakarta.validation.constraints.NotNull;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesTests.JavaBeanNestedConstructorBindingProperties.Nested;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\nimport org.springframework.boot.context.properties.bind.validation.BindValidationException;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.convert.DataSizeUnit;\nimport org.springframework.boot.convert.DurationFormat;\nimport org.springframework.boot.convert.DurationStyle;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.boot.convert.PeriodFormat;\nimport org.springframework.boot.convert.PeriodStyle;\nimport org.springframework.boot.convert.PeriodUnit;\nimport org.springframework.boot.env.RandomValuePropertySource;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.format.Formatter;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.stereotype.Component;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.ValidationUtils;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.annotation.Validated;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigurationProperties @ConfigurationProperties}-annotated beans.\n * Covers {@link EnableConfigurationProperties @EnableConfigurationProperties},\n * {@link ConfigurationPropertiesBindingPostProcessor} and\n * {@link ConfigurationPropertiesBinder}.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Vladislav Kisel\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ConfigurationPropertiesTests {\n\n\tprivate AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tthis.context.close();\n\t\tSystem.clearProperty(\"name\");\n\t\tSystem.clearProperty(\"nested.name\");\n\t\tSystem.clearProperty(\"nested_name\");\n\t}\n\n\t@Test\n\tvoid loadShouldBind() {\n\t\tload(BasicConfiguration.class, \"name=foo\");\n\t\tassertThat(this.context.getBeanNamesForType(BasicProperties.class)).hasSize(1);\n\t\tassertThat(this.context.containsBean(BasicProperties.class.getName())).isTrue();\n\t\tassertThat(this.context.getBean(BasicProperties.class).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadShouldBindNested() {\n\t\tload(NestedConfiguration.class, \"name=foo\", \"nested.name=bar\");\n\t\tassertThat(this.context.getBeanNamesForType(NestedProperties.class)).hasSize(1);\n\t\tassertThat(this.context.getBean(NestedProperties.class).name).isEqualTo(\"foo\");\n\t\tassertThat(this.context.getBean(NestedProperties.class).nested.name).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWhenUsingSystemPropertiesShouldBind() {\n\t\tSystem.setProperty(\"name\", \"foo\");\n\t\tload(BasicConfiguration.class);\n\t\tassertThat(this.context.getBeanNamesForType(BasicProperties.class)).hasSize(1);\n\t\tassertThat(this.context.getBean(BasicProperties.class).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenUsingSystemPropertiesShouldBindNested() {\n\t\tSystem.setProperty(\"name\", \"foo\");\n\t\tSystem.setProperty(\"nested.name\", \"bar\");\n\t\tload(NestedConfiguration.class);\n\t\tassertThat(this.context.getBeanNamesForType(NestedProperties.class)).hasSize(1);\n\t\tassertThat(this.context.getBean(NestedProperties.class).name).isEqualTo(\"foo\");\n\t\tassertThat(this.context.getBean(NestedProperties.class).nested.name).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasIgnoreUnknownFieldsFalseAndNoUnknownFieldsShouldBind() {\n\t\tremoveSystemProperties();\n\t\tload(IgnoreUnknownFieldsFalseConfiguration.class, \"name=foo\");\n\t\tIgnoreUnknownFieldsFalseProperties bean = this.context.getBean(IgnoreUnknownFieldsFalseProperties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasIgnoreUnknownFieldsFalseAndUnknownFieldsShouldFail() {\n\t\tremoveSystemProperties();\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class)\n\t\t\t.isThrownBy(() -> load(IgnoreUnknownFieldsFalseConfiguration.class, \"name=foo\", \"bar=baz\"))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid givenIgnoreUnknownFieldsFalseAndIgnoreInvalidFieldsTrueWhenThereAreUnknownFieldsThenBindingShouldFail() {\n\t\tremoveSystemProperties();\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class).isThrownBy(\n\t\t\t\t() -> load(IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueConfiguration.class, \"name=foo\", \"bar=baz\"))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenHasIgnoreInvalidFieldsTrueAndInvalidFieldsShouldBind() {\n\t\tload(IgnoreInvalidFieldsFalseProperties.class, \"com.example.bar=spam\");\n\t\tIgnoreInvalidFieldsFalseProperties bean = this.context.getBean(IgnoreInvalidFieldsFalseProperties.class);\n\t\tassertThat(bean.getBar()).isZero();\n\t}\n\n\t@Test\n\tvoid loadWhenHasPrefixShouldBind() {\n\t\tload(PrefixConfiguration.class, \"spring.foo.name=foo\");\n\t\tPrefixProperties bean = this.context.getBean(PrefixProperties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenPropertiesHaveAnnotationOnBaseClassShouldBind() {\n\t\tload(AnnotationOnBaseClassConfiguration.class, \"name=foo\");\n\t\tAnnotationOnBaseClassProperties bean = this.context.getBean(AnnotationOnBaseClassProperties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingArrayShouldBind() {\n\t\tload(BasicConfiguration.class, \"name=foo\", \"array=1,2,3\");\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.array).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingArrayFromYamlArrayShouldBind() {\n\t\tload(BasicConfiguration.class, \"name=foo\", \"list[0]=1\", \"list[1]=2\", \"list[2]=3\");\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.list).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingOver256ElementsShouldBind() {\n\t\tList<String> pairs = new ArrayList<>();\n\t\tpairs.add(\"name:foo\");\n\t\tfor (int i = 0; i < 1000; i++) {\n\t\t\tpairs.add(\"list[\" + i + \"]:\" + i);\n\t\t}\n\t\tload(BasicConfiguration.class, StringUtils.toStringArray(pairs));\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.list).hasSize(1000);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingWithoutAndAnnotationShouldFail() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> load(WithoutAndAnnotationConfiguration.class, \"name:foo\"))\n\t\t\t.withMessageContaining(\"No ConfigurationProperties annotation found\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingWithoutAnnotationValueShouldBind() {\n\t\tload(WithoutAnnotationValueConfiguration.class, \"name=foo\");\n\t\tWithoutAnnotationValueProperties bean = this.context.getBean(WithoutAnnotationValueProperties.class);\n\t\tassertThat(bean.name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"testProperties.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\t\t\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\t\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t\t\t\t\t\t<bean\n\t\t\t\t\t\t\tid=\"org.springframework.boot.context.properties.ConfigurationPropertiesTests$BasicProperties\"\n\t\t\t\t\t\t\tclass=\"org.springframework.boot.context.properties.ConfigurationPropertiesTests$BasicProperties\">\n\t\t\t\t\t\t\t<property name=\"name\" value=\"bar\"/>\n\t\t\t\t\t\t</bean>\n\n\t\t\t\t\t</beans>\n\t\t\t\t\t\"\"\")\n\tvoid loadWhenBindingWithDefaultsInXmlShouldBind() {\n\t\tremoveSystemProperties();\n\t\tload(new Class<?>[] { DefaultsInXmlConfiguration.class });\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.name).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingWithDefaultsInJavaConfigurationShouldBind() {\n\t\tload(DefaultsInJavaConfiguration.class);\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.name).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingTwoBeansShouldBind() {\n\t\tload(new Class<?>[] { WithoutAnnotationValueConfiguration.class, BasicConfiguration.class });\n\t\tassertThat(this.context.getBean(BasicProperties.class)).isNotNull();\n\t\tassertThat(this.context.getBean(WithoutAnnotationValueProperties.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid loadWhenBindingWithParentContextShouldBind() {\n\t\tAnnotationConfigApplicationContext parent = load(BasicConfiguration.class, \"name=parent\");\n\t\tassertThat(parent.getEnvironment().getProperty(\"name\")).isEqualTo(\"parent\");\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.setParent(parent);\n\t\tremoveSystemProperties();\n\t\tload(new Class<?>[] { BasicConfiguration.class, BasicPropertiesConsumer.class }, \"name=child\");\n\t\tassertThat(this.context.getEnvironment().getProperty(\"name\")).isEqualTo(\"child\");\n\t\tassertThat(this.context.getBean(BasicProperties.class)).isNotNull();\n\t\tassertThat(parent.getBean(BasicProperties.class)).isNotNull();\n\t\tassertThat(this.context.getBean(BasicPropertiesConsumer.class).getName()).isEqualTo(\"child\");\n\t\tparent.close();\n\t}\n\n\t@Test\n\tvoid loadWhenBindingOnlyParentContextShouldBind() {\n\t\tAnnotationConfigApplicationContext parent = load(BasicConfiguration.class, \"name=foo\");\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.setParent(parent);\n\t\tload(BasicPropertiesConsumer.class);\n\t\tassertThat(this.context.getBeanNamesForType(BasicProperties.class)).isEmpty();\n\t\tassertThat(parent.getBeanNamesForType(BasicProperties.class)).hasSize(1);\n\t\tassertThat(this.context.getBean(BasicPropertiesConsumer.class).getName()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenPrefixedPropertiesDeclaredAsBeanShouldBind() {\n\t\tload(PrefixPropertiesDeclaredAsBeanConfiguration.class, \"spring.foo.name=foo\");\n\t\tPrefixProperties bean = this.context.getBean(PrefixProperties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenPrefixedPropertiesDeclaredAsAnnotationValueShouldBind() {\n\t\tload(PrefixPropertiesDeclaredAsAnnotationValueConfiguration.class, \"spring.foo.name=foo\");\n\t\tPrefixProperties bean = this.context.getBean(\"spring.foo-\" + PrefixProperties.class.getName(),\n\t\t\t\tPrefixProperties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenMultiplePrefixedPropertiesDeclaredAsAnnotationValueShouldBind() {\n\t\tload(MultiplePrefixPropertiesDeclaredAsAnnotationValueConfiguration.class, \"spring.foo.name=foo\",\n\t\t\t\t\"spring.bar.name=bar\");\n\t\tPrefixProperties bean1 = this.context.getBean(PrefixProperties.class);\n\t\tAnotherPrefixProperties bean2 = this.context.getBean(AnotherPrefixProperties.class);\n\t\tassertThat(((BasicProperties) bean1).name).isEqualTo(\"foo\");\n\t\tassertThat(((BasicProperties) bean2).name).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToMapKeyWithPeriodShouldBind() {\n\t\tload(MapProperties.class, \"mymap.key1.key2:value12\", \"mymap.key3:value3\");\n\t\tMapProperties bean = this.context.getBean(MapProperties.class);\n\t\tassertThat(bean.mymap).containsOnly(entry(\"key3\", \"value3\"), entry(\"key1.key2\", \"value12\"));\n\t}\n\n\t@Test\n\tvoid loadWhenPrefixedPropertiesAreReplacedOnBeanMethodShouldBind() {\n\t\tload(PrefixedPropertiesReplacedOnBeanMethodConfiguration.class, \"external.name=bar\", \"spam.name=foo\");\n\t\tPrefixProperties bean = this.context.getBean(PrefixProperties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadShouldBindToJavaTimeDuration() {\n\t\tload(BasicConfiguration.class, \"duration=PT1M\");\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tDuration duration = bean.getDuration();\n\t\tassertThat(duration).isNotNull();\n\t\tassertThat(duration.getSeconds()).isEqualTo(60);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToValidatedImplementationOfInterfaceShouldBind() {\n\t\tload(ValidatedImplementationConfiguration.class, \"test.foo=bar\");\n\t\tValidatedImplementationProperties bean = this.context.getBean(ValidatedImplementationProperties.class);\n\t\tassertThat(bean.getFoo()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWithPropertyPlaceholderValueShouldBind() {\n\t\tload(WithPropertyPlaceholderValueConfiguration.class, \"default.value=foo\");\n\t\tWithPropertyPlaceholderValueProperties bean = this.context\n\t\t\t.getBean(WithPropertyPlaceholderValueProperties.class);\n\t\tassertThat(bean.getValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWithPropertyPlaceholderShouldNotAlterPropertySourceOrder() {\n\t\tload(WithPropertyPlaceholderWithLocalPropertiesValueConfiguration.class, \"com.example.bar=a\");\n\t\tSimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);\n\t\tassertThat(bean.getBar()).isEqualTo(\"a\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasPostConstructShouldTriggerPostConstructWithBoundBean() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"bar\", \"foo\");\n\t\tthis.context.setEnvironment(environment);\n\t\tthis.context.register(WithPostConstructConfiguration.class);\n\t\tthis.context.refresh();\n\t\tWithPostConstructConfiguration bean = this.context.getBean(WithPostConstructConfiguration.class);\n\t\tassertThat(bean.initialized).isTrue();\n\t}\n\n\t@Test\n\tvoid loadShouldNotInitializeFactoryBeans() {\n\t\tWithFactoryBeanConfiguration.factoryBeanInitialized = false;\n\t\tthis.context = new AnnotationConfigApplicationContext() {\n\n\t\t\t@Override\n\t\t\tprotected void onRefresh() {\n\t\t\t\tassertThat(WithFactoryBeanConfiguration.factoryBeanInitialized).as(\"Initialized too early\").isFalse();\n\t\t\t\tsuper.onRefresh();\n\t\t\t}\n\n\t\t};\n\t\tthis.context.register(WithFactoryBeanConfiguration.class);\n\t\tBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(FactoryBeanTester.class)\n\t\t\t.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)\n\t\t\t.getBeanDefinition();\n\t\tthis.context.registerBeanDefinition(\"test\", beanDefinition);\n\t\tthis.context.refresh();\n\t\tassertThat(WithFactoryBeanConfiguration.factoryBeanInitialized).as(\"Not Initialized\").isTrue();\n\t}\n\n\t@Test\n\tvoid loadWhenUsingRelaxedFormsShouldBindToEnum() {\n\t\tbindToEnum(\"test.theValue=FOO\");\n\t\tbindToEnum(\"test.theValue=foo\");\n\t\tbindToEnum(\"test.the-value=FoO\");\n\t\tbindToEnum(\"test.THE_VALUE=FoO\");\n\t}\n\n\tprivate void bindToEnum(String... inlinedProperties) {\n\t\tload(WithEnumProperties.class, inlinedProperties);\n\t\tWithEnumProperties bean = this.context.getBean(WithEnumProperties.class);\n\t\tassertThat(bean.getTheValue()).isEqualTo(FooEnum.FOO);\n\t\tresetContext();\n\t}\n\n\t@Test\n\tvoid loadWhenUsingRelaxedFormsShouldBindToEnumSet() {\n\t\tbindToEnumSet(\"test.the-values=foo,bar\", FooEnum.FOO, FooEnum.BAR);\n\t\tbindToEnumSet(\"test.the-values=foo\", FooEnum.FOO);\n\t}\n\n\tprivate void bindToEnumSet(String inlinedProperty, FooEnum... expected) {\n\t\tload(WithEnumProperties.class, inlinedProperty);\n\t\tWithEnumProperties bean = this.context.getBean(WithEnumProperties.class);\n\t\tassertThat(bean.getTheValues()).contains(expected);\n\t\tresetContext();\n\t}\n\n\t@Test\n\tvoid loadShouldBindToCharArray() {\n\t\tload(WithCharArrayProperties.class, \"test.chars=word\");\n\t\tWithCharArrayProperties bean = this.context.getBean(WithCharArrayProperties.class);\n\t\tassertThat(bean.getChars()).isEqualTo(\"word\".toCharArray());\n\t}\n\n\t@Test\n\tvoid loadWhenUsingRelaxedFormsAndOverrideShouldBind() {\n\t\tload(WithRelaxedNamesProperties.class, \"test.FOO_BAR=test1\", \"test.FOO_BAR=test2\", \"test.BAR-B-A-Z=testa\",\n\t\t\t\t\"test.BAR-B-A-Z=testb\");\n\t\tWithRelaxedNamesProperties bean = this.context.getBean(WithRelaxedNamesProperties.class);\n\t\tassertThat(bean.getFooBar()).isEqualTo(\"test2\");\n\t\tassertThat(bean.getBarBAZ()).isEqualTo(\"testb\");\n\t}\n\n\t@Test\n\tvoid loadShouldBindToMap() {\n\t\tload(WithMapProperties.class, \"test.map.foo=bar\");\n\t\tWithMapProperties bean = this.context.getBean(WithMapProperties.class);\n\t\tassertThat(bean.getMap()).containsOnly(entry(\"foo\", \"bar\"));\n\t}\n\n\t@Test\n\tvoid loadShouldBindToMapWithNumericKey() {\n\t\tload(MapWithNumericKeyProperties.class, \"sample.properties.1.name=One\");\n\t\tMapWithNumericKeyProperties bean = this.context.getBean(MapWithNumericKeyProperties.class);\n\t\tBasicProperties one = bean.getProperties().get(\"1\");\n\t\tassertThat(one).isNotNull();\n\t\tassertThat(one.name).isEqualTo(\"One\");\n\t}\n\n\t@Test\n\tvoid loadWhenUsingSystemPropertiesShouldBindToMap() {\n\t\tthis.context.getEnvironment()\n\t\t\t.getPropertySources()\n\t\t\t.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tCollections.singletonMap(\"TEST_MAP_FOO_BAR\", \"baz\")));\n\t\tload(WithComplexMapProperties.class);\n\t\tWithComplexMapProperties bean = this.context.getBean(WithComplexMapProperties.class);\n\t\tMap<String, Map<String, String>> map = bean.getMap();\n\t\tassertThat(map).isNotNull();\n\t\tassertThat(map).containsOnlyKeys(\"foo\");\n\t\tassertThat(map.get(\"foo\")).containsOnly(entry(\"bar\", \"baz\"));\n\t}\n\n\t@Test\n\tvoid loadWhenDotsInSystemEnvironmentPropertiesShouldBind() {\n\t\tthis.context.getEnvironment()\n\t\t\t.getPropertySources()\n\t\t\t.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tCollections.singletonMap(\"com.example.bar\", \"baz\")));\n\t\tload(SimplePrefixedProperties.class);\n\t\tSimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);\n\t\tassertThat(bean.getBar()).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid loadWhenEnvironmentPrefixSetShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tsources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tnew SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\t\tCollections.singletonMap(\"MY_SPRING_FOO_NAME\", \"Jane\")));\n\t\tSpringApplication application = new SpringApplication(PrefixConfiguration.class);\n\t\tapplication.setApplicationContextFactory((webApplicationType) -> ConfigurationPropertiesTests.this.context);\n\t\tapplication.setEnvironmentPrefix(\"my\");\n\t\tapplication.setEnvironment(this.context.getEnvironment());\n\t\tapplication.run();\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.name).isEqualTo(\"Jane\");\n\t}\n\n\t@Test\n\tvoid loadWhenOverridingPropertiesShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tsources.addFirst(\n\t\t\t\tnew SystemEnvironmentPropertySource(\"system\", Collections.singletonMap(\"SPRING_FOO_NAME\", \"Jane\")));\n\t\tsources.addLast(new MapPropertySource(\"test\", Collections.singletonMap(\"spring.foo.name\", \"John\")));\n\t\tload(PrefixConfiguration.class);\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.name).isEqualTo(\"Jane\");\n\t}\n\n\t@Test\n\tvoid loadWhenJsr303ConstraintDoesNotMatchShouldFail() {\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class)\n\t\t\t.isThrownBy(() -> load(ValidatedJsr303Configuration.class, \"description=\"))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadValidatedOnBeanMethodAndJsr303ConstraintDoesNotMatchShouldFail() {\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class)\n\t\t\t.isThrownBy(() -> load(ValidatedOnBeanJsr303Configuration.class, \"description=\"))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotAnnotatedWithValidShouldNotFail() {\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> load(ValidatedNestedJsr303Properties.class, \"properties.description=\"));\n\t}\n\n\t@Test\n\tvoid loadWhenJsr303ConstraintDoesNotMatchOnNestedThatIsNotDirectlyAnnotatedButIsValidShouldFail() {\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class)\n\t\t\t.isThrownBy(() -> load(ValidatedValidNestedJsr303Properties.class))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenJsr303ConstraintMatchesShouldBind() {\n\t\tload(ValidatedJsr303Configuration.class, \"description=foo\");\n\t\tValidatedJsr303Properties bean = this.context.getBean(ValidatedJsr303Properties.class);\n\t\tassertThat(bean.getDescription()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenJsr303ConstraintDoesNotMatchAndNotValidatedAnnotationShouldBind() {\n\t\tload(NonValidatedJsr303Configuration.class, \"name=foo\");\n\t\tNonValidatedJsr303Properties bean = this.context.getBean(NonValidatedJsr303Properties.class);\n\t\tassertThat(((BasicProperties) bean).name).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasMultiplePropertySourcesPlaceholderConfigurerShouldLogWarning(CapturedOutput output) {\n\t\tload(MultiplePropertySourcesPlaceholderConfigurerConfiguration.class);\n\t\tassertThat(output).contains(\"Multiple PropertySourcesPlaceholderConfigurer beans registered\");\n\t}\n\n\t@Test\n\tvoid loadWhenOverridingPropertiesWithPlaceholderResolutionInEnvironmentShouldBindWithOverride() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tsources\n\t\t\t.addFirst(new SystemEnvironmentPropertySource(\"system\", Collections.singletonMap(\"COM_EXAMPLE_BAR\", \"10\")));\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"com.example.bar\", 5);\n\t\tsource.put(\"com.example.foo\", \"${com.example.bar}\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(SimplePrefixedProperties.class);\n\t\tSimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);\n\t\tassertThat(bean.getFoo()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid loadWhenHasUnboundElementsFromSystemEnvironmentShouldNotThrowException() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tsources.addFirst(new MapPropertySource(\"test\", Collections.singletonMap(\"com.example.foo\", 5)));\n\t\tsources.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tCollections.singletonMap(\"COM_EXAMPLE_OTHER\", \"10\")));\n\t\tload(SimplePrefixedProperties.class);\n\t\tSimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);\n\t\tassertThat(bean.getFoo()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadShouldSupportRebindableConfigurationPropertiesRegisteredAsBean() {\n\t\ttestRebindableConfigurationProperties(PrototypePropertiesBeanConfiguration.class);\n\t}\n\n\t@Test\n\tvoid loadShouldSupportRebindableConfigurationPropertiesRegisteredUsingRegistrar() {\n\t\ttestRebindableConfigurationProperties(PrototypePropertiesRegistrarConfiguration.class);\n\t}\n\n\tvoid testRebindableConfigurationProperties(Class<?> configurationClass) {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"example.one\", \"foo\");\n\t\tsources.addFirst(new MapPropertySource(\"test-source\", source));\n\t\tthis.context.register(configurationClass);\n\t\tthis.context.refresh();\n\t\tPrototypeBean first = this.context.getBean(PrototypeBean.class);\n\t\tassertThat(first.getOne()).isEqualTo(\"foo\");\n\t\tsource.put(\"example.one\", \"bar\");\n\t\tsources.addFirst(new MapPropertySource(\"extra\", Collections.singletonMap(\"example.two\", \"baz\")));\n\t\tPrototypeBean second = this.context.getBean(PrototypeBean.class);\n\t\tassertThat(second.getOne()).isEqualTo(\"bar\");\n\t\tassertThat(second.getTwo()).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationPropertiesRegisteredAsBean() {\n\t\ttestPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationProperties(\n\t\t\t\tPrototypePropertiesBeanConfiguration.class);\n\t}\n\n\t@Test\n\tvoid loadWhenHasPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationPropertiesRegisteredUsingRegistrar() {\n\t\ttestPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationProperties(\n\t\t\t\tPrototypePropertiesRegistrarConfiguration.class);\n\t}\n\n\tvoid testPropertySourcesPlaceholderConfigurerShouldSupportRebindableConfigurationProperties(\n\t\t\tClass<?> configurationClass) {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"example.one\", \"foo\");\n\t\tsources.addFirst(new MapPropertySource(\"test-source\", source));\n\t\tthis.context.register(configurationClass);\n\t\tthis.context.register(PropertySourcesPlaceholderConfigurer.class);\n\t\tthis.context.refresh();\n\t\tPrototypeBean first = this.context.getBean(PrototypeBean.class);\n\t\tassertThat(first.getOne()).isEqualTo(\"foo\");\n\t\tsource.put(\"example.one\", \"bar\");\n\t\tsources.addFirst(new MapPropertySource(\"extra\", Collections.singletonMap(\"example.two\", \"baz\")));\n\t\tPrototypeBean second = this.context.getBean(PrototypeBean.class);\n\t\tassertThat(second.getOne()).isEqualTo(\"bar\");\n\t\tassertThat(second.getTwo()).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid customProtocolResolverIsInvoked() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, \"test.resource=application.properties\");\n\t\tProtocolResolver protocolResolver = mock(ProtocolResolver.class);\n\t\tgiven(protocolResolver.resolve(anyString(), any(ResourceLoader.class))).willReturn(null);\n\t\tthis.context.addProtocolResolver(protocolResolver);\n\t\tthis.context.register(PropertiesWithResource.class);\n\t\tthis.context.refresh();\n\t\tthen(protocolResolver).should().resolve(eq(\"application.properties\"), any(ResourceLoader.class));\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\")\n\tvoid customProtocolResolver() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context,\n\t\t\t\t\"test.resource=test:/application.properties\");\n\t\tthis.context.addProtocolResolver(new TestProtocolResolver());\n\t\tthis.context.register(PropertiesWithResource.class);\n\t\tthis.context.refresh();\n\t\tResource resource = this.context.getBean(PropertiesWithResource.class).getResource();\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource).isInstanceOf(ClassPathResource.class);\n\t\tassertThat(resource.exists()).isTrue();\n\t\tassertThat(((ClassPathResource) resource).getPath()).isEqualTo(\"application.properties\");\n\t}\n\n\t@Test\n\tvoid loadShouldUseConverterBean() {\n\t\tprepareConverterContext(PersonConverterConfiguration.class, PersonProperties.class);\n\t\tPerson person = this.context.getBean(PersonProperties.class).getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t}\n\n\t@Test\n\tvoid loadShouldUseStringConverterBeanWhenValueIsCharSequence() {\n\t\tthis.context.register(PersonConverterConfiguration.class, PersonProperties.class);\n\t\tPropertySource<?> testProperties = new MapPropertySource(\"test\", Map.of(\"test.person\", new CharSequence() {\n\n\t\t\tprivate final String value = \"John Smith\";\n\n\t\t\t@Override\n\t\t\tpublic int length() {\n\t\t\t\treturn this.value.length();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic char charAt(int index) {\n\t\t\t\treturn this.value.charAt(index);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic CharSequence subSequence(int start, int end) {\n\t\t\t\treturn this.value.subSequence(start, end);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\treturn this.value;\n\t\t\t}\n\n\t\t}));\n\t\tthis.context.getEnvironment().getPropertySources().addLast(testProperties);\n\t\tthis.context.refresh();\n\t\tPerson person = this.context.getBean(PersonProperties.class).getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t}\n\n\t@Test\n\tvoid loadWhenBeanFactoryConversionServiceAndConverterBeanCanUseBeanFactoryConverter() {\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new AlienConverter());\n\t\tthis.context.getBeanFactory().setConversionService(conversionService);\n\t\tload(new Class<?>[] { PersonConverterConfiguration.class, PersonAndAlienProperties.class },\n\t\t\t\t\"test.person=John Smith\", \"test.alien=Alf Tanner\");\n\t\tPersonAndAlienProperties properties = this.context.getBean(PersonAndAlienProperties.class);\n\t\tPerson person = properties.getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t\tAlien alien = properties.getAlien();\n\t\tassertThat(alien).isNotNull();\n\t\tassertThat(alien.name).isEqualTo(\"rennaT flA\");\n\t}\n\n\t@Test\n\tvoid loadWhenBeanFactoryConversionServiceAndConverterBeanCanUseConverterBean() {\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new PersonConverter());\n\t\tthis.context.getBeanFactory().setConversionService(conversionService);\n\t\tload(new Class<?>[] { AlienConverterConfiguration.class, PersonAndAlienProperties.class },\n\t\t\t\t\"test.person=John Smith\", \"test.alien=Alf Tanner\");\n\t\tPersonAndAlienProperties properties = this.context.getBean(PersonAndAlienProperties.class);\n\t\tPerson person = properties.getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t\tAlien alien = properties.getAlien();\n\t\tassertThat(alien).isNotNull();\n\t\tassertThat(alien.name).isEqualTo(\"rennaT flA\");\n\t}\n\n\t@Test // gh-38734\n\tvoid loadWhenBeanFactoryConversionServiceAndConverterBeanCanUseConverterBeanWithCollections() {\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new PersonConverter());\n\t\tthis.context.getBeanFactory().setConversionService(conversionService);\n\t\tload(new Class<?>[] { AlienConverterConfiguration.class, PersonAndAliensProperties.class },\n\t\t\t\t\"test.person=John Smith\", \"test.aliens=Alf Tanner,Gilbert\");\n\t\tPersonAndAliensProperties properties = this.context.getBean(PersonAndAliensProperties.class);\n\t\tPerson person = properties.getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t\tList<Alien> aliens = properties.getAliens();\n\t\tassertThat(aliens).isNotNull();\n\t\tassertThat(aliens.get(0).name).isEqualTo(\"rennaT flA\");\n\t\tassertThat(aliens.get(1).name).isEqualTo(\"trebliG\");\n\t}\n\n\t@Test\n\tvoid loadWhenConfigurationConverterIsNotQualifiedShouldNotConvert() {\n\t\tassertThatExceptionOfType(BeanCreationException.class)\n\t\t\t.isThrownBy(() -> prepareConverterContext(NonQualifiedConverterConfiguration.class, PersonProperties.class))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadShouldUseGenericConverterBean() {\n\t\tprepareConverterContext(GenericConverterConfiguration.class, PersonProperties.class);\n\t\tPerson person = this.context.getBean(PersonProperties.class).getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t}\n\n\t@Test\n\tvoid loadShouldUseFormatterBean() {\n\t\tprepareConverterContext(FormatterConfiguration.class, PersonProperties.class);\n\t\tPerson person = this.context.getBean(PersonProperties.class).getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t}\n\n\t@Test\n\tvoid loadWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() {\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(\n\t\t\t\t() -> prepareConverterContext(NonQualifiedGenericConverterConfiguration.class, PersonProperties.class))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid loadShouldBindToBeanWithGenerics() {\n\t\tload(GenericConfiguration.class, \"foo.bar=hello\");\n\t\tAGenericClass foo = this.context.getBean(AGenericClass.class);\n\t\tassertThat(foo.getBar()).isNotNull();\n\t}\n\n\tprivate void prepareConverterContext(Class<?>... config) {\n\t\tload(config, \"test.person=John Smith\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasConfigurationPropertiesValidatorShouldApplyValidator() {\n\t\tassertThatException().isThrownBy(() -> load(WithCustomValidatorConfiguration.class)).satisfies((ex) -> {\n\t\t\tassertThat(ex).hasCauseInstanceOf(BindException.class);\n\t\t\tassertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid loadWhenHasUnsupportedConfigurationPropertiesValidatorShouldBind() {\n\t\tload(WithUnsupportedCustomValidatorConfiguration.class, \"test.foo=bar\");\n\t\tWithSetterThatThrowsValidationExceptionProperties bean = this.context\n\t\t\t.getBean(WithSetterThatThrowsValidationExceptionProperties.class);\n\t\tassertThat(bean.getFoo()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid loadWhenConfigurationPropertiesIsAlsoValidatorShouldApplyValidator() {\n\t\tassertThatException().isThrownBy(() -> load(ValidatorProperties.class)).satisfies((ex) -> {\n\t\t\tassertThat(ex).hasCauseInstanceOf(BindException.class);\n\t\t\tassertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid loadWhenConstructorBoundConfigurationPropertiesIsAlsoValidatorShouldApplyValidator() {\n\t\tassertThatException().isThrownBy(() -> load(ValidatorConstructorBoundPropertiesConfiguration.class))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex).hasCauseInstanceOf(BindException.class);\n\t\t\t\tassertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid loadWhenConfigurationPropertiesWithValidDefaultValuesShouldNotFail() {\n\t\tAnnotationConfigApplicationContext context = load(ValidatorPropertiesWithDefaultValues.class);\n\t\tValidatorPropertiesWithDefaultValues bean = context.getBean(ValidatorPropertiesWithDefaultValues.class);\n\t\tassertThat(bean.getBar()).isEqualTo(\"a\");\n\t}\n\n\t@Test\n\tvoid loadWhenSetterThrowsValidationExceptionShouldFail() {\n\t\tassertThatExceptionOfType(BeanCreationException.class)\n\t\t\t.isThrownBy(() -> load(WithSetterThatThrowsValidationExceptionProperties.class, \"test.foo=spam\"))\n\t\t\t.withCauseInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenFailsShouldIncludeAnnotationDetails() {\n\t\tremoveSystemProperties();\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class)\n\t\t\t.isThrownBy(() -> load(IgnoreUnknownFieldsFalseConfiguration.class, \"name=foo\", \"bar=baz\"))\n\t\t\t.withMessageContaining(\"Could not bind properties to \"\n\t\t\t\t\t+ \"'ConfigurationPropertiesTests.IgnoreUnknownFieldsFalseProperties' : \"\n\t\t\t\t\t+ \"prefix=, ignoreInvalidFields=false, ignoreUnknownFields=false\");\n\t}\n\n\t@Test\n\tvoid loadWhenHasCustomPropertyEditorShouldBind() {\n\t\tthis.context.getBeanFactory().registerCustomEditor(Person.class, PersonPropertyEditor.class);\n\t\tload(PersonProperties.class, \"test.person=boot,spring\");\n\t\tPersonProperties bean = this.context.getBean(PersonProperties.class);\n\t\tPerson person = bean.getPerson();\n\t\tassertThat(person).isNotNull();\n\t\tassertThat(person.firstName).isEqualTo(\"spring\");\n\t\tassertThat(person.lastName).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToListOfGenericClassShouldBind() {\n\t\t// gh-12166\n\t\tload(ListOfGenericClassProperties.class, \"test.list=java.lang.RuntimeException\");\n\t\tListOfGenericClassProperties bean = this.context.getBean(ListOfGenericClassProperties.class);\n\t\tassertThat(bean.getList()).containsExactly(RuntimeException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingCurrentDirectoryToFileShouldBind() {\n\t\tload(FileProperties.class, \"test.file=.\");\n\t\tFileProperties bean = this.context.getBean(FileProperties.class);\n\t\tassertThat(bean.getFile()).isEqualTo(new File(\".\"));\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToDataSizeShouldBind() {\n\t\tload(DataSizeProperties.class, \"test.size=10GB\", \"test.another-size=5\");\n\t\tDataSizeProperties bean = this.context.getBean(DataSizeProperties.class);\n\t\tassertThat(bean.getSize()).isEqualTo(DataSize.ofGigabytes(10));\n\t\tassertThat(bean.getAnotherSize()).isEqualTo(DataSize.ofKilobytes(5));\n\t}\n\n\t@Test\n\tvoid loadWhenTopLevelConverterNotFoundExceptionShouldNotFail() {\n\t\tload(PersonProperties.class, \"test=boot\");\n\t}\n\n\t@Test\n\tvoid loadWhenConfigurationPropertiesContainsMapWithPositiveAndNegativeIntegerKeys() {\n\t\t// gh-14136\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.map.x.[-1].a\", \"baz\");\n\t\tsource.put(\"test.map.x.1.a\", \"bar\");\n\t\tsource.put(\"test.map.x.1.b\", 1);\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(WithIntegerMapProperties.class);\n\t\tWithIntegerMapProperties bean = this.context.getBean(WithIntegerMapProperties.class);\n\t\tMap<String, Map<Integer, Foo>> map = bean.getMap();\n\t\tassertThat(map).isNotNull();\n\t\tMap<Integer, Foo> x = map.get(\"x\");\n\t\tassertThat(x).isNotNull();\n\t\tFoo minus1 = x.get(-1);\n\t\tassertThat(minus1).isNotNull();\n\t\tassertThat(minus1.getA()).isEqualTo(\"baz\");\n\t\tassertThat(minus1.getB()).isZero();\n\t\tFoo one = x.get(1);\n\t\tassertThat(one).isNotNull();\n\t\tassertThat(one.getA()).isEqualTo(\"bar\");\n\t\tassertThat(one.getB()).isOne();\n\t}\n\n\t@Test\n\tvoid loadWhenConfigurationPropertiesInjectsAnotherBeanShouldNotFail() {\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class)\n\t\t\t.isThrownBy(() -> load(OtherInjectPropertiesConfiguration.class))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(BindException.class)\n\t\t\t.withMessageContaining(OtherInjectedProperties.class.getName())\n\t\t\t.withMessageContaining(\"Failed to bind properties under 'test'\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.foo\", \"baz\");\n\t\tsource.put(\"test.bar\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(ConstructorParameterConfiguration.class);\n\t\tConstructorParameterProperties bean = this.context.getBean(ConstructorParameterProperties.class);\n\t\tassertThat(bean.getFoo()).isEqualTo(\"baz\");\n\t\tassertThat(bean.getBar()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithCustomDataUnitShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.duration\", \"12\");\n\t\tsource.put(\"test.size\", \"13\");\n\t\tsource.put(\"test.period\", \"14\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(ConstructorParameterWithUnitConfiguration.class);\n\t\tConstructorParameterWithUnitProperties bean = this.context\n\t\t\t.getBean(ConstructorParameterWithUnitProperties.class);\n\t\tassertThat(bean.getDuration()).isEqualTo(Duration.ofDays(12));\n\t\tassertThat(bean.getSize()).isEqualTo(DataSize.ofMegabytes(13));\n\t\tassertThat(bean.getPeriod()).isEqualTo(Period.ofYears(14));\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithDefaultValuesShouldBind() {\n\t\tload(ConstructorParameterConfiguration.class);\n\t\tConstructorParameterProperties bean = this.context.getBean(ConstructorParameterProperties.class);\n\t\tassertThat(bean.getFoo()).isEqualTo(\"hello\");\n\t\tassertThat(bean.getBar()).isZero();\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithEmptyDefaultValueShouldBind() {\n\t\tload(ConstructorParameterEmptyDefaultValueConfiguration.class);\n\t\tConstructorParameterEmptyDefaultValueProperties bean = this.context\n\t\t\t.getBean(ConstructorParameterEmptyDefaultValueProperties.class);\n\t\tassertThat(bean.getSet()).isEmpty();\n\t\tassertThat(bean.getMap()).isEmpty();\n\t\tassertThat(bean.getArray()).isEmpty();\n\t\tassertThat(bean.getOptional()).isEmpty();\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithDefaultDataUnitShouldBind() {\n\t\tload(ConstructorParameterWithUnitConfiguration.class);\n\t\tConstructorParameterWithUnitProperties bean = this.context\n\t\t\t.getBean(ConstructorParameterWithUnitProperties.class);\n\t\tassertThat(bean.getDuration()).isEqualTo(Duration.ofDays(2));\n\t\tassertThat(bean.getSize()).isEqualTo(DataSize.ofMegabytes(3));\n\t\tassertThat(bean.getPeriod()).isEqualTo(Period.ofYears(4));\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithCustomDataFormatShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.duration\", \"12d\");\n\t\tsource.put(\"test.period\", \"13y\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(ConstructorParameterWithFormatConfiguration.class);\n\t\tConstructorParameterWithFormatProperties bean = this.context\n\t\t\t.getBean(ConstructorParameterWithFormatProperties.class);\n\t\tassertThat(bean.getDuration()).isEqualTo(Duration.ofDays(12));\n\t\tassertThat(bean.getPeriod()).isEqualTo(Period.ofYears(13));\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithNotMatchingCustomDurationFormatShouldFail() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.duration\", \"P12D\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tassertThatException().isThrownBy(() -> load(ConstructorParameterWithFormatConfiguration.class))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithNotMatchingCustomPeriodFormatShouldFail() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.period\", \"P12D\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tassertThatException().isThrownBy(() -> load(ConstructorParameterWithFormatConfiguration.class))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(BindException.class);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithDefaultDataFormatShouldBind() {\n\t\tload(ConstructorParameterWithFormatConfiguration.class);\n\t\tConstructorParameterWithFormatProperties bean = this.context\n\t\t\t.getBean(ConstructorParameterWithFormatProperties.class);\n\t\tassertThat(bean.getDuration()).isEqualTo(Duration.ofDays(2));\n\t\tassertThat(bean.getPeriod()).isEqualTo(Period.ofYears(3));\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersShouldValidate() {\n\t\tassertThatException().isThrownBy(() -> load(ConstructorParameterValidationConfiguration.class))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex).hasCauseInstanceOf(BindException.class);\n\t\t\t\tassertThat(ex.getCause()).hasCauseExactlyInstanceOf(BindValidationException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid loadWhenBindingOnBeanWithoutBeanDefinitionShouldBind() {\n\t\tload(BasicConfiguration.class, \"name=test\");\n\t\tBasicProperties bean = this.context.getBean(BasicProperties.class);\n\t\tassertThat(bean.name).isEqualTo(\"test\");\n\t\tbean.name = \"override\";\n\t\tthis.context.getBean(ConfigurationPropertiesBindingPostProcessor.class)\n\t\t\t.postProcessBeforeInitialization(bean, \"does-not-exist\");\n\t\tassertThat(bean.name).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToNestedConstructorPropertiesShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.name\", \"spring\");\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(NestedConstructorPropertiesConfiguration.class);\n\t\tNestedConstructorProperties bean = this.context.getBean(NestedConstructorProperties.class);\n\t\tassertThat(bean.getName()).isEqualTo(\"spring\");\n\t\tassertThat(bean.getNested().getAge()).isEqualTo(5);\n\t}\n\n\t@Test // gh-18485\n\tvoid loadWhenBindingToMultiConstructorConfigurationProperties() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested[0].name\", \"spring\");\n\t\tsource.put(\"test.nested[0].age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(MultiConstructorConfigurationPropertiesConfiguration.class);\n\t\tMultiConstructorConfigurationListProperties bean = this.context\n\t\t\t.getBean(MultiConstructorConfigurationListProperties.class);\n\t\tMultiConstructorConfigurationProperties nested = bean.getNested().get(0);\n\t\tassertThat(nested.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nested.getAge()).isEqualTo(5);\n\t}\n\n\t@Test // gh-18485\n\tvoid loadWhenBindingToMultiConstructorConfigurationPropertiesUsingShortcutSyntax() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested[0]\", \"spring\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(MultiConstructorConfigurationPropertiesConfiguration.class);\n\t\tMultiConstructorConfigurationListProperties bean = this.context\n\t\t\t.getBean(MultiConstructorConfigurationListProperties.class);\n\t\tMultiConstructorConfigurationProperties nested = bean.getNested().get(0);\n\t\tassertThat(nested.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nested.getAge()).isZero();\n\t}\n\n\t@Test // gh-18481\n\tvoid loadWhenBindingToNestedConstructorPropertiesWithDeducedNestedShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.name\", \"spring\");\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(DeducedNestedConstructorPropertiesConfiguration.class);\n\t\tDeducedNestedConstructorProperties bean = this.context.getBean(DeducedNestedConstructorProperties.class);\n\t\tassertThat(bean.getName()).isEqualTo(\"spring\");\n\t\tassertThat(bean.getNested().getAge()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToNestedPropertiesWithSyntheticConstructorShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(SyntheticConstructorPropertiesConfiguration.class);\n\t\tSyntheticNestedConstructorProperties bean = this.context.getBean(SyntheticNestedConstructorProperties.class);\n\t\tassertThat(bean.getNested().getAge()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToJavaBeanWithNestedConstructorBindingShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(JavaBeanNestedConstructorBindingPropertiesConfiguration.class);\n\t\tJavaBeanNestedConstructorBindingProperties bean = this.context\n\t\t\t.getBean(JavaBeanNestedConstructorBindingProperties.class);\n\t\tNested nested = bean.getNested();\n\t\tassertThat(nested).isNotNull();\n\t\tassertThat(nested.getAge()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToNestedWithMultipleConstructorsShouldBind() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(NestedMultipleConstructorsConfiguration.class);\n\t\tNestedMultipleConstructorProperties bean = this.context.getBean(NestedMultipleConstructorProperties.class);\n\t\tassertThat(bean.getNested().getAge()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToJavaBeanWithoutExplicitConstructorBindingOnNestedShouldUseSetterBasedBinding() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(JavaBeanNonDefaultConstructorPropertiesConfiguration.class);\n\t\tJavaBeanNonDefaultConstructorProperties bean = this.context\n\t\t\t.getBean(JavaBeanNonDefaultConstructorProperties.class);\n\t\tJavaBeanNonDefaultConstructorProperties.Nested nested = bean.getNested();\n\t\tassertThat(nested).isNotNull();\n\t\tassertThat(nested.getAge()).isEqualTo(10);\n\t}\n\n\t@Test // gh-18652\n\tvoid loadWhenBeanFactoryContainsSingletonForConstructorBindingTypeShouldNotFail() {\n\t\tConfigurableListableBeanFactory beanFactory = this.context.getBeanFactory();\n\t\t((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(\"test\",\n\t\t\t\tnew RootBeanDefinition(ConstructorParameterProperties.class));\n\t\tbeanFactory.registerSingleton(\"test\", new ConstructorParameterProperties(\"bar\", 5));\n\t\tload(TestConfiguration.class);\n\t}\n\n\t@Test\n\tvoid loadWhenConstructorBindingWithOuterClassDeducedConstructorBound() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested.outer.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(ConstructorBindingWithOuterClassConstructorBoundConfiguration.class);\n\t\tConstructorBindingWithOuterClassConstructorBoundProperties bean = this.context\n\t\t\t.getBean(ConstructorBindingWithOuterClassConstructorBoundProperties.class);\n\t\tOuter outer = bean.getNested().getOuter();\n\t\tassertThat(outer).isNotNull();\n\t\tassertThat(outer.getAge()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid loadWhenConstructorBindingWithOuterClassAndNestedAutowiredShouldThrowException() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test.nested.age\", \"5\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tassertThatExceptionOfType(ConfigurationPropertiesBindException.class).isThrownBy(\n\t\t\t\t() -> load(ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowiredConfiguration.class));\n\t}\n\n\t@Test\n\tvoid loadWhenConfigurationPropertiesPrefixMatchesPropertyInEnvironment() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"test\", \"bar\");\n\t\tsource.put(\"test.a\", \"baz\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(WithPublicStringConstructorPropertiesConfiguration.class);\n\t\tWithPublicStringConstructorProperties bean = this.context.getBean(WithPublicStringConstructorProperties.class);\n\t\tassertThat(bean.getA()).isEqualTo(\"baz\");\n\t}\n\n\t@Test // gh-26201\n\tvoid loadWhenBoundToRandomPropertyPlaceholder() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tsources.addFirst(new RandomValuePropertySource());\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"com.example.bar\", \"${random.int[100,200]}\");\n\t\tsources.addLast(new MapPropertySource(\"test\", source));\n\t\tload(SimplePrefixedProperties.class);\n\t\tSimplePrefixedProperties bean = this.context.getBean(SimplePrefixedProperties.class);\n\t\tassertThat(bean.getBar()).isNotNull().containsOnlyDigits();\n\t}\n\n\t@Test\n\tvoid boundPropertiesShouldBeRecorded() {\n\t\tload(NestedConfiguration.class, \"name=foo\", \"nested.name=bar\");\n\t\tBoundConfigurationProperties bound = BoundConfigurationProperties.get(this.context);\n\t\tassertThat(bound).isNotNull();\n\t\tSet<ConfigurationPropertyName> keys = bound.getAll().keySet();\n\t\tassertThat(keys.stream().map(ConfigurationPropertyName::toString)).contains(\"name\", \"nested.name\");\n\t}\n\n\t@Test // gh-28592\n\tvoid loadWhenBindingWithCustomConverterAndObjectToObjectMethod() {\n\t\tthis.context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());\n\t\tload(WithCustomConverterAndObjectToObjectMethodConfiguration.class, \"test.item=foo\");\n\t\tWithCustomConverterAndObjectToObjectMethodProperties bean = this.context\n\t\t\t.getBean(WithCustomConverterAndObjectToObjectMethodProperties.class);\n\t\tWithPublicObjectToObjectMethod item = bean.getItem();\n\t\tassertThat(item).isNotNull();\n\t\tassertThat(item.getValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test // gh-33710\n\tvoid loadWhenConstructorUsedInBeanMethodAndNotAsConstructorBinding() {\n\t\tload(ConstructorUsedInBeanMethodConfiguration.class, \"test.two=bound-2\");\n\t\tConstructorUsedDirectly bean = this.context.getBean(ConstructorUsedDirectly.class);\n\t\tassertThat(bean.getOne()).isEqualTo(\"bean-method-1\");\n\t\tassertThat(bean.getTwo()).isEqualTo(\"bound-2\");\n\t}\n\n\t@Test // gh-33409\n\tvoid loadWhenConstructorUsedInNestedPropertyAndNotAsConstructorBinding() {\n\t\tload(ConstructorUsedInNestedPropertyConfiguration.class, \"test.nested.two=bound-2\");\n\t\tConstructorUsedInNestedProperty bean = this.context.getBean(ConstructorUsedInNestedProperty.class);\n\t\tassertThat(bean.getNested().getOne()).isEqualTo(\"nested-1\");\n\t\tassertThat(bean.getNested().getTwo()).isEqualTo(\"bound-2\");\n\t}\n\n\t@Test // gh-34407\n\tvoid loadWhenNestedRecordWithExistingInstance() {\n\t\tload(NestedRecordInstancePropertiesConfiguration.class, \"test.nested.name=spring\");\n\t\tNestedRecordInstanceProperties bean = this.context.getBean(NestedRecordInstanceProperties.class);\n\t\tassertThat(bean.getNested().name()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid loadWhenPotentiallyConstructorBoundPropertiesAreImportedUsesJavaBeanBinding() {\n\t\tload(PotentiallyConstructorBoundPropertiesImporter.class, \"test.prop=alpha\");\n\t\tPotentiallyConstructorBoundProperties properties = this.context\n\t\t\t.getBean(PotentiallyConstructorBoundProperties.class);\n\t\tassertThat(properties.getProp()).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingClasspathPatternToResourceArrayShouldBindMultipleValues() {\n\t\tload(ResourceArrayPropertiesConfiguration.class,\n\t\t\t\t\"test.resources=classpath*:org/springframework/boot/context/properties/*.class\");\n\t\tResourceArrayProperties properties = this.context.getBean(ResourceArrayProperties.class);\n\t\tassertThat(properties.getResources()).hasSizeGreaterThan(1);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingClasspathPatternToResourceCollectionShouldBindMultipleValues() {\n\t\tload(ResourceCollectionPropertiesConfiguration.class,\n\t\t\t\t\"test.resources=classpath*:org/springframework/boot/context/properties/*.class\");\n\t\tResourceCollectionProperties properties = this.context.getBean(ResourceCollectionProperties.class);\n\t\tassertThat(properties.getResources()).hasSizeGreaterThan(1);\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToConstructorParametersWithConversionToCustomListImplementation() {\n\t\tload(ConstructorBoundCustomListPropertiesConfiguration.class, \"test.values=a,b\");\n\t\tassertThat(this.context.getBean(ConstructorBoundCustomListProperties.class).getValues()).containsExactly(\"a\",\n\t\t\t\t\"b\");\n\t}\n\n\t@Test\n\tvoid loadWhenBindingToJavaBeanWithConversionToCustomListImplementation() {\n\t\tload(SetterBoundCustomListPropertiesConfiguration.class, \"test.values=a,b\");\n\t\tassertThat(this.context.getBean(SetterBoundCustomListProperties.class).getValues()).containsExactly(\"a\", \"b\");\n\t}\n\n\tprivate AnnotationConfigApplicationContext load(Class<?> configuration, String... inlinedProperties) {\n\t\treturn load(new Class<?>[] { configuration }, inlinedProperties);\n\t}\n\n\tprivate AnnotationConfigApplicationContext load(Class<?>[] configuration, String... inlinedProperties) {\n\t\tthis.context.register(configuration);\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, inlinedProperties);\n\t\tthis.context.refresh();\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Strict tests need a known set of properties so we remove system items which may be\n\t * environment specific.\n\t */\n\tprivate void removeSystemProperties() {\n\t\tMutablePropertySources sources = this.context.getEnvironment().getPropertySources();\n\t\tsources.remove(\"systemProperties\");\n\t\tsources.remove(\"systemEnvironment\");\n\t}\n\n\tprivate void resetContext() {\n\t\tthis.context.close();\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(BasicProperties.class)\n\tstatic class BasicConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(NestedProperties.class)\n\tstatic class NestedConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(IgnoreUnknownFieldsFalseProperties.class)\n\tstatic class IgnoreUnknownFieldsFalseConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueProperties.class)\n\tstatic class IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(PrefixProperties.class)\n\tstatic class PrefixConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ValidatedJsr303Properties.class)\n\tstatic class ValidatedJsr303Configuration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class ValidatedOnBeanJsr303Configuration {\n\n\t\t@Bean\n\t\t@Validated\n\t\tNonValidatedJsr303Properties properties() {\n\t\t\treturn new NonValidatedJsr303Properties();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(NonValidatedJsr303Properties.class)\n\tstatic class NonValidatedJsr303Configuration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(AnnotationOnBaseClassProperties.class)\n\tstatic class AnnotationOnBaseClassConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WithoutAndAnnotationConfiguration.class)\n\tstatic class WithoutAndAnnotationConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WithoutAnnotationValueProperties.class)\n\tstatic class WithoutAnnotationValueConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\t@ImportResource(\"testProperties.xml\")\n\tstatic class DefaultsInXmlConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DefaultsInJavaConfiguration {\n\n\t\t@Bean\n\t\tBasicProperties basicProperties() {\n\t\t\tBasicProperties test = new BasicProperties();\n\t\t\ttest.setName(\"bar\");\n\t\t\treturn test;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class PrefixPropertiesDeclaredAsBeanConfiguration {\n\n\t\t@Bean\n\t\tPrefixProperties prefixProperties() {\n\t\t\treturn new PrefixProperties();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(PrefixProperties.class)\n\tstatic class PrefixPropertiesDeclaredAsAnnotationValueConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties({ PrefixProperties.class, AnotherPrefixProperties.class })\n\tstatic class MultiplePrefixPropertiesDeclaredAsAnnotationValueConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class PrefixedPropertiesReplacedOnBeanMethodConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spam\")\n\t\tPrefixProperties prefixProperties() {\n\t\t\treturn new PrefixProperties();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class ValidatedImplementationConfiguration {\n\n\t\t@Bean\n\t\tValidatedImplementationProperties testProperties() {\n\t\t\treturn new ValidatedImplementationProperties();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties\n\tstatic class WithPostConstructConfiguration {\n\n\t\tprivate @Nullable String bar;\n\n\t\tprivate boolean initialized;\n\n\t\tvoid setBar(@Nullable String bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\t@Nullable String getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\t@PostConstruct\n\t\tvoid init() {\n\t\t\tassertThat(this.bar).isNotNull();\n\t\t\tthis.initialized = true;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WithPropertyPlaceholderValueProperties.class)\n\tstatic class WithPropertyPlaceholderValueConfiguration {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer configurer() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(SimplePrefixedProperties.class)\n\tstatic class WithPropertyPlaceholderWithLocalPropertiesValueConfiguration {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer configurer() {\n\t\t\tPropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer();\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(\"com.example.bar\", \"b\");\n\t\t\tplaceholderConfigurer.setProperties(properties);\n\t\t\treturn placeholderConfigurer;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class WithFactoryBeanConfiguration {\n\n\t\tstatic boolean factoryBeanInitialized;\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class MultiplePropertySourcesPlaceholderConfigurerConfiguration {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer configurer1() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer configurer2() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class PrototypePropertiesBeanConfiguration {\n\n\t\t@Bean\n\t\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t\t@ConfigurationProperties(\"example\")\n\t\tPrototypeBean prototypeBean() {\n\t\t\treturn new PrototypeBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(PrototypeBeanProperties.class)\n\tstatic class PrototypePropertiesRegistrarConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"example\")\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\tstatic class PrototypeBeanProperties extends PrototypeBean {\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class PropertiesWithResource {\n\n\t\tprivate @Nullable Resource resource;\n\n\t\t@Nullable Resource getResource() {\n\t\t\treturn this.resource;\n\t\t}\n\n\t\tvoid setResource(@Nullable Resource resource) {\n\t\t\tthis.resource = resource;\n\t\t}\n\n\t}\n\n\tstatic class TestProtocolResolver implements ProtocolResolver {\n\n\t\tstatic final String PREFIX = \"test:/\";\n\n\t\t@Override\n\t\tpublic @Nullable Resource resolve(String location, ResourceLoader resourceLoader) {\n\t\t\tif (location.startsWith(PREFIX)) {\n\t\t\t\tString path = location.substring(PREFIX.length());\n\t\t\t\treturn new ClassPathResource(path);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PersonConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<String, Person> personConverter() {\n\t\t\treturn new PersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AlienConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<String, Alien> alienConverter() {\n\t\t\treturn new AlienConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonQualifiedConverterConfiguration {\n\n\t\t@Bean\n\t\tConverter<String, Person> personConverter() {\n\t\t\treturn new PersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic GenericConverter genericPersonConverter() {\n\t\t\treturn new GenericPersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FormatterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Formatter<Person> personFormatter() {\n\t\t\treturn new PersonFormatter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonQualifiedGenericConverterConfiguration {\n\n\t\t@Bean\n\t\tGenericConverter genericPersonConverter() {\n\t\t\treturn new GenericPersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class GenericConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tAGenericClass<String> aBeanToBind() {\n\t\t\treturn new AGenericClass<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WithCustomValidatorProperties.class)\n\tstatic class WithCustomValidatorConfiguration {\n\n\t\t@Bean(name = EnableConfigurationProperties.VALIDATOR_BEAN_NAME)\n\t\tCustomPropertiesValidator validator() {\n\t\t\treturn new CustomPropertiesValidator();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WithSetterThatThrowsValidationExceptionProperties.class)\n\tstatic class WithUnsupportedCustomValidatorConfiguration {\n\n\t\t@Bean(name = EnableConfigurationProperties.VALIDATOR_BEAN_NAME)\n\t\tCustomPropertiesValidator validator() {\n\t\t\treturn new CustomPropertiesValidator();\n\t\t}\n\n\t}\n\n\tstatic class AGenericClass<T> {\n\n\t\tprivate @Nullable T bar;\n\n\t\t@Nullable T getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tvoid setBar(@Nullable T bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t}\n\n\tstatic class PrototypeBean {\n\n\t\tprivate @Nullable String one;\n\n\t\tprivate @Nullable String two;\n\n\t\t@Nullable String getOne() {\n\t\t\treturn this.one;\n\t\t}\n\n\t\tvoid setOne(@Nullable String one) {\n\t\t\tthis.one = one;\n\t\t}\n\n\t\t@Nullable String getTwo() {\n\t\t\treturn this.two;\n\t\t}\n\n\t\tvoid setTwo(@Nullable String two) {\n\t\t\tthis.two = two;\n\t\t}\n\n\t}\n\n\t// Must be a raw type\n\t@SuppressWarnings(\"rawtypes\")\n\tstatic class FactoryBeanTester implements FactoryBean, InitializingBean {\n\n\t\t@Override\n\t\tpublic Object getObject() {\n\t\t\treturn Object.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Class<?> getObjectType() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isSingleton() {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterPropertiesSet() {\n\t\t\tWithFactoryBeanConfiguration.factoryBeanInitialized = true;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tpublic static class BasicProperties {\n\n\t\tprivate @Nullable String name;\n\n\t\tprivate int @Nullable [] array;\n\n\t\tprivate @Nullable List<Integer> list = new ArrayList<>();\n\n\t\tprivate @Nullable Duration duration;\n\n\t\t// No getter - you should be able to bind to a write-only bean\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\t// Must be public for XML\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tvoid setArray(int... values) {\n\t\t\tthis.array = values;\n\t\t}\n\n\t\tint @Nullable [] getArray() {\n\t\t\treturn this.array;\n\t\t}\n\n\t\t@Nullable List<Integer> getList() {\n\t\t\treturn this.list;\n\t\t}\n\n\t\tvoid setList(@Nullable List<Integer> list) {\n\t\t\tthis.list = list;\n\t\t}\n\n\t\t@Nullable Duration getDuration() {\n\t\t\treturn this.duration;\n\t\t}\n\n\t\tvoid setDuration(@Nullable Duration duration) {\n\t\t\tthis.duration = duration;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class NestedProperties {\n\n\t\tprivate @Nullable String name;\n\n\t\tprivate final Nested nested = new Nested();\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\tprivate @Nullable String name;\n\n\t\t\tvoid setName(@Nullable String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(ignoreUnknownFields = false)\n\tstatic class IgnoreUnknownFieldsFalseProperties extends BasicProperties {\n\n\t}\n\n\t@ConfigurationProperties(ignoreUnknownFields = false, ignoreInvalidFields = true)\n\tstatic class IgnoreUnknownFieldsFalseIgnoreInvalidFieldsTrueProperties extends BasicProperties {\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(prefix = \"com.example\", ignoreInvalidFields = true)\n\tstatic class IgnoreInvalidFieldsFalseProperties {\n\n\t\tprivate long bar;\n\n\t\tvoid setBar(long bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tlong getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"spring.foo\")\n\tstatic class PrefixProperties extends BasicProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"spring.bar\")\n\tstatic class AnotherPrefixProperties extends BasicProperties {\n\n\t}\n\n\tstatic class Jsr303Properties extends BasicProperties {\n\n\t\t@NotEmpty\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String description;\n\n\t\tString getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tvoid setDescription(String description) {\n\t\t\tthis.description = description;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties\n\t@Validated\n\tstatic class ValidatedJsr303Properties extends Jsr303Properties {\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class NonValidatedJsr303Properties extends Jsr303Properties {\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties\n\t@Validated\n\tstatic class ValidatedNestedJsr303Properties {\n\n\t\tprivate final Jsr303Properties properties = new Jsr303Properties();\n\n\t\tJsr303Properties getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties\n\t@Validated\n\tstatic class ValidatedValidNestedJsr303Properties {\n\n\t\t@Valid\n\t\tprivate final Jsr303Properties properties = new Jsr303Properties();\n\n\t\tJsr303Properties getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t}\n\n\tstatic class AnnotationOnBaseClassProperties extends BasicProperties {\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class WithoutAnnotationValueProperties {\n\n\t\tprivate @Nullable String name;\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t// No getter - you should be able to bind to a write-only bean\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties\n\tstatic class MapProperties {\n\n\t\tprivate @Nullable Map<String, String> mymap;\n\n\t\tvoid setMymap(@Nullable Map<String, String> mymap) {\n\t\t\tthis.mymap = mymap;\n\t\t}\n\n\t\t@Nullable Map<String, String> getMymap() {\n\t\t\treturn this.mymap;\n\t\t}\n\n\t}\n\n\t@Component\n\tstatic class BasicPropertiesConsumer {\n\n\t\t@Autowired\n\t\tprivate BasicProperties properties;\n\n\t\t@PostConstruct\n\t\tvoid init() {\n\t\t\tassertThat(this.properties).isNotNull();\n\t\t}\n\n\t\t@Nullable String getName() {\n\t\t\treturn this.properties.name;\n\t\t}\n\n\t}\n\n\tinterface InterfaceForValidatedImplementation {\n\n\t\tString getFoo();\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\t@Validated\n\tstatic class ValidatedImplementationProperties implements InterfaceForValidatedImplementation {\n\n\t\t@NotNull\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String foo;\n\n\t\t@Override\n\t\tpublic String getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\t@Validated\n\tstatic class WithPropertyPlaceholderValueProperties {\n\n\t\t@Value(\"${default.value}\")\n\t\tprivate @Nullable String value;\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithEnumProperties {\n\n\t\tprivate @Nullable FooEnum theValue;\n\n\t\tprivate @Nullable List<FooEnum> theValues;\n\n\t\tvoid setTheValue(@Nullable FooEnum value) {\n\t\t\tthis.theValue = value;\n\t\t}\n\n\t\t@Nullable FooEnum getTheValue() {\n\t\t\treturn this.theValue;\n\t\t}\n\n\t\t@Nullable List<FooEnum> getTheValues() {\n\t\t\treturn this.theValues;\n\t\t}\n\n\t\tvoid setTheValues(@Nullable List<FooEnum> theValues) {\n\t\t\tthis.theValues = theValues;\n\t\t}\n\n\t}\n\n\tenum FooEnum {\n\n\t\tFOO, BAZ, BAR\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(prefix = \"test\", ignoreUnknownFields = false)\n\tstatic class WithCharArrayProperties {\n\n\t\tprivate char @Nullable [] chars;\n\n\t\tchar @Nullable [] getChars() {\n\t\t\treturn this.chars;\n\t\t}\n\n\t\tvoid setChars(char @Nullable [] chars) {\n\t\t\tthis.chars = chars;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithRelaxedNamesProperties {\n\n\t\tprivate @Nullable String fooBar;\n\n\t\tprivate @Nullable String barBAZ;\n\n\t\t@Nullable String getFooBar() {\n\t\t\treturn this.fooBar;\n\t\t}\n\n\t\tvoid setFooBar(@Nullable String fooBar) {\n\t\t\tthis.fooBar = fooBar;\n\t\t}\n\n\t\t@Nullable String getBarBAZ() {\n\t\t\treturn this.barBAZ;\n\t\t}\n\n\t\tvoid setBarBAZ(@Nullable String barBAZ) {\n\t\t\tthis.barBAZ = barBAZ;\n\t\t}\n\n\t}\n\n\t@Validated\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithMapProperties {\n\n\t\tprivate @Nullable Map<String, String> map;\n\n\t\t@Nullable Map<String, String> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tvoid setMap(@Nullable Map<String, String> map) {\n\t\t\tthis.map = map;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithComplexMapProperties {\n\n\t\tprivate @Nullable Map<String, Map<String, String>> map;\n\n\t\t@Nullable Map<String, Map<String, String>> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tvoid setMap(@Nullable Map<String, Map<String, String>> map) {\n\t\t\tthis.map = map;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithIntegerMapProperties {\n\n\t\tprivate @Nullable Map<String, Map<Integer, Foo>> map;\n\n\t\t@Nullable Map<String, Map<Integer, Foo>> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tvoid setMap(@Nullable Map<String, Map<Integer, Foo>> map) {\n\t\t\tthis.map = map;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(prefix = \"com.example\", ignoreUnknownFields = false)\n\tstatic class SimplePrefixedProperties {\n\n\t\tprivate int foo;\n\n\t\tprivate @Nullable String bar;\n\n\t\t@Nullable String getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tvoid setBar(@Nullable String bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tint getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(int foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class PersonProperties {\n\n\t\tprivate @Nullable Person person;\n\n\t\t@Nullable Person getPerson() {\n\t\t\treturn this.person;\n\t\t}\n\n\t\tvoid setPerson(@Nullable Person person) {\n\t\t\tthis.person = person;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class PersonAndAlienProperties {\n\n\t\tprivate @Nullable Person person;\n\n\t\tprivate @Nullable Alien alien;\n\n\t\t@Nullable Person getPerson() {\n\t\t\treturn this.person;\n\t\t}\n\n\t\tvoid setPerson(@Nullable Person person) {\n\t\t\tthis.person = person;\n\t\t}\n\n\t\t@Nullable Alien getAlien() {\n\t\t\treturn this.alien;\n\t\t}\n\n\t\tvoid setAlien(@Nullable Alien alien) {\n\t\t\tthis.alien = alien;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class PersonAndAliensProperties {\n\n\t\tprivate @Nullable Person person;\n\n\t\tprivate @Nullable List<Alien> aliens;\n\n\t\t@Nullable Person getPerson() {\n\t\t\treturn this.person;\n\t\t}\n\n\t\tvoid setPerson(@Nullable Person person) {\n\t\t\tthis.person = person;\n\t\t}\n\n\t\t@Nullable List<Alien> getAliens() {\n\t\t\treturn this.aliens;\n\t\t}\n\n\t\tvoid setAliens(@Nullable List<Alien> aliens) {\n\t\t\tthis.aliens = aliens;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"sample\")\n\tstatic class MapWithNumericKeyProperties {\n\n\t\tprivate final Map<String, BasicProperties> properties = new LinkedHashMap<>();\n\n\t\tMap<String, BasicProperties> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties\n\tstatic class ValidatorProperties implements Validator {\n\n\t\tprivate @Nullable String foo;\n\n\t\t@Override\n\t\tpublic boolean supports(Class<?> type) {\n\t\t\treturn type == ValidatorProperties.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic void validate(Object target, Errors errors) {\n\t\t\tValidationUtils.rejectIfEmpty(errors, \"foo\", \"TEST1\");\n\t\t}\n\n\t\t@Nullable String getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(@Nullable String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ValidatorConstructorBoundProperties.class)\n\tstatic class ValidatorConstructorBoundPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties\n\tstatic class ValidatorConstructorBoundProperties implements Validator {\n\n\t\tprivate final String foo;\n\n\t\tValidatorConstructorBoundProperties(String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supports(Class<?> type) {\n\t\t\treturn type == ValidatorConstructorBoundProperties.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic void validate(Object target, Errors errors) {\n\t\t\tValidationUtils.rejectIfEmpty(errors, \"foo\", \"TEST1\");\n\t\t}\n\n\t\tString getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithSetterThatThrowsValidationExceptionProperties {\n\n\t\tprivate @Nullable String foo;\n\n\t\t@Nullable String getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(String foo) {\n\t\t\tthis.foo = foo;\n\t\t\tif (!foo.equals(\"bar\")) {\n\t\t\t\tthrow new IllegalArgumentException(\"Wrong value for foo\");\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"custom\")\n\tstatic class WithCustomValidatorProperties {\n\n\t\tprivate @Nullable String foo;\n\n\t\t@Nullable String getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(@Nullable String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class ListOfGenericClassProperties {\n\n\t\tprivate @Nullable List<Class<? extends Throwable>> list;\n\n\t\t@Nullable List<Class<? extends Throwable>> getList() {\n\t\t\treturn this.list;\n\t\t}\n\n\t\tvoid setList(@Nullable List<Class<? extends Throwable>> list) {\n\t\t\tthis.list = list;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class FileProperties {\n\n\t\tprivate @Nullable File file;\n\n\t\t@Nullable File getFile() {\n\t\t\treturn this.file;\n\t\t}\n\n\t\tvoid setFile(@Nullable File file) {\n\t\t\tthis.file = file;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties\n\t@ConfigurationProperties(\"test\")\n\tstatic class DataSizeProperties {\n\n\t\tprivate @Nullable DataSize size;\n\n\t\t@DataSizeUnit(DataUnit.KILOBYTES)\n\t\tprivate @Nullable DataSize anotherSize;\n\n\t\t@Nullable DataSize getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t\tvoid setSize(@Nullable DataSize size) {\n\t\t\tthis.size = size;\n\t\t}\n\n\t\t@Nullable DataSize getAnotherSize() {\n\t\t\treturn this.anotherSize;\n\t\t}\n\n\t\tvoid setAnotherSize(@Nullable DataSize anotherSize) {\n\t\t\tthis.anotherSize = anotherSize;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class OtherInjectedProperties {\n\n\t\tfinal @Nullable DataSizeProperties dataSizeProperties;\n\n\t\tOtherInjectedProperties(ObjectProvider<DataSizeProperties> dataSizeProperties) {\n\t\t\tthis.dataSizeProperties = dataSizeProperties.getIfUnique();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(OtherInjectedProperties.class)\n\tstatic class OtherInjectPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\t@Validated\n\tstatic class ConstructorParameterProperties {\n\n\t\t@NotEmpty\n\t\tprivate final String foo;\n\n\t\tprivate final int bar;\n\n\t\tConstructorParameterProperties(@DefaultValue(\"hello\") String foo, int bar) {\n\t\t\tthis.foo = foo;\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tString getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tint getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorParameterEmptyDefaultValueProperties {\n\n\t\tprivate final Set<String> set;\n\n\t\tprivate final Map<String, String> map;\n\n\t\tprivate final int[] array;\n\n\t\tprivate final Optional<String> optional;\n\n\t\tConstructorParameterEmptyDefaultValueProperties(@DefaultValue Set<String> set,\n\t\t\t\t@DefaultValue Map<String, String> map, @DefaultValue int[] array,\n\t\t\t\t@DefaultValue Optional<String> optional) {\n\t\t\tthis.set = set;\n\t\t\tthis.map = map;\n\t\t\tthis.array = array;\n\t\t\tthis.optional = optional;\n\t\t}\n\n\t\tSet<String> getSet() {\n\t\t\treturn this.set;\n\t\t}\n\n\t\tMap<String, String> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tint[] getArray() {\n\t\t\treturn this.array;\n\t\t}\n\n\t\tOptional<String> getOptional() {\n\t\t\treturn this.optional;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorParameterWithUnitProperties {\n\n\t\tprivate final Duration duration;\n\n\t\tprivate final DataSize size;\n\n\t\tprivate final Period period;\n\n\t\t@ConstructorBinding\n\t\tConstructorParameterWithUnitProperties(@DefaultValue(\"2\") @DurationUnit(ChronoUnit.DAYS) Duration duration,\n\t\t\t\t@DefaultValue(\"3\") @DataSizeUnit(DataUnit.MEGABYTES) DataSize size,\n\t\t\t\t@DefaultValue(\"4\") @PeriodUnit(ChronoUnit.YEARS) Period period) {\n\t\t\tthis.size = size;\n\t\t\tthis.duration = duration;\n\t\t\tthis.period = period;\n\t\t}\n\n\t\tDuration getDuration() {\n\t\t\treturn this.duration;\n\t\t}\n\n\t\tDataSize getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t\tPeriod getPeriod() {\n\t\t\treturn this.period;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorParameterWithFormatProperties {\n\n\t\tprivate final Duration duration;\n\n\t\tprivate final Period period;\n\n\t\tConstructorParameterWithFormatProperties(\n\t\t\t\t@DefaultValue(\"2d\") @DurationFormat(DurationStyle.SIMPLE) Duration duration,\n\t\t\t\t@DefaultValue(\"3y\") @PeriodFormat(PeriodStyle.SIMPLE) Period period) {\n\t\t\tthis.duration = duration;\n\t\t\tthis.period = period;\n\t\t}\n\n\t\tDuration getDuration() {\n\t\t\treturn this.duration;\n\t\t}\n\n\t\tPeriod getPeriod() {\n\t\t\treturn this.period;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\t@Validated\n\tstatic class ConstructorParameterValidatedProperties {\n\n\t\t@NotEmpty\n\t\tprivate final String foo;\n\n\t\tConstructorParameterValidatedProperties(String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t\tString getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorParameterProperties.class)\n\tstatic class ConstructorParameterConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorParameterEmptyDefaultValueProperties.class)\n\tstatic class ConstructorParameterEmptyDefaultValueConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorParameterWithUnitProperties.class)\n\tstatic class ConstructorParameterWithUnitConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorParameterWithFormatProperties.class)\n\tstatic class ConstructorParameterWithFormatConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorParameterValidatedProperties.class)\n\tstatic class ConstructorParameterValidationConfiguration {\n\n\t}\n\n\tstatic class CustomPropertiesValidator implements Validator {\n\n\t\t@Override\n\t\tpublic boolean supports(Class<?> type) {\n\t\t\treturn type == WithCustomValidatorProperties.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic void validate(Object target, Errors errors) {\n\t\t\tValidationUtils.rejectIfEmpty(errors, \"foo\", \"TEST1\");\n\t\t}\n\n\t}\n\n\tstatic class PersonConverter implements Converter<String, Person> {\n\n\t\t@Override\n\t\tpublic Person convert(String source) {\n\t\t\tString[] content = StringUtils.split(source, \" \");\n\t\t\tassertThat(content).isNotNull();\n\t\t\treturn new Person(content[0], content[1]);\n\t\t}\n\n\t}\n\n\tstatic class AlienConverter implements Converter<String, Alien> {\n\n\t\t@Override\n\t\tpublic Alien convert(String source) {\n\t\t\treturn new Alien(new StringBuilder(source).reverse().toString());\n\t\t}\n\n\t}\n\n\tstatic class GenericPersonConverter implements GenericConverter {\n\n\t\t@Override\n\t\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\t\treturn Collections.singleton(new ConvertiblePair(String.class, Person.class));\n\t\t}\n\n\t\t@Override\n\t\tpublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tString[] content = StringUtils.split((String) source, \" \");\n\t\t\tassertThat(content).isNotNull();\n\t\t\treturn new Person(content[0], content[1]);\n\t\t}\n\n\t}\n\n\tstatic class PersonFormatter implements Formatter<Person> {\n\n\t\t@Override\n\t\tpublic String print(Person person, Locale locale) {\n\t\t\treturn person.getFirstName() + \" \" + person.getLastName();\n\t\t}\n\n\t\t@Override\n\t\tpublic Person parse(String text, Locale locale) throws ParseException {\n\t\t\tString[] content = text.split(\" \");\n\t\t\treturn new Person(content[0], content[1]);\n\t\t}\n\n\t}\n\n\tstatic class PersonPropertyEditor extends PropertyEditorSupport {\n\n\t\t@Override\n\t\tpublic void setAsText(String text) {\n\t\t\tString[] content = text.split(\",\");\n\t\t\tsetValue(new Person(content[1], content[0]));\n\t\t}\n\n\t}\n\n\tstatic class Person {\n\n\t\tprivate final String firstName;\n\n\t\tprivate final String lastName;\n\n\t\tPerson(String firstName, String lastName) {\n\t\t\tthis.firstName = firstName;\n\t\t\tthis.lastName = lastName;\n\t\t}\n\n\t\tString getFirstName() {\n\t\t\treturn this.firstName;\n\t\t}\n\n\t\tString getLastName() {\n\t\t\treturn this.lastName;\n\t\t}\n\n\t}\n\n\tstatic class Alien {\n\n\t\tprivate final String name;\n\n\t\tAlien(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic class Foo {\n\n\t\tprivate @Nullable String a;\n\n\t\tprivate int b;\n\n\t\t@Nullable String getA() {\n\t\t\treturn this.a;\n\t\t}\n\n\t\tvoid setA(@Nullable String a) {\n\t\t\tthis.a = a;\n\t\t}\n\n\t\tint getB() {\n\t\t\treturn this.b;\n\t\t}\n\n\t\tvoid setB(int b) {\n\t\t\tthis.b = b;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(NestedConstructorProperties.class)\n\tstatic class NestedConstructorPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class NestedConstructorProperties {\n\n\t\tprivate final String name;\n\n\t\tprivate final Nested nested;\n\n\t\tNestedConstructorProperties(String name, Nested nested) {\n\t\t\tthis.name = name;\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\tprivate final int age;\n\n\t\t\t@ConstructorBinding\n\t\t\tNested(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class NestedMultipleConstructorProperties {\n\n\t\tprivate final String name;\n\n\t\tprivate final Nested nested;\n\n\t\tNestedMultipleConstructorProperties(String name, Nested nested) {\n\t\t\tthis.name = name;\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\tprivate int age;\n\n\t\t\tNested(String property) {\n\n\t\t\t}\n\n\t\t\t@ConstructorBinding\n\t\t\tNested(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(NestedMultipleConstructorProperties.class)\n\tstatic class NestedMultipleConstructorsConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorBindingWithOuterClassConstructorBoundProperties {\n\n\t\tprivate final Nested nested;\n\n\t\tConstructorBindingWithOuterClassConstructorBoundProperties(Nested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\tprivate @Nullable Outer outer;\n\n\t\t\t@Nullable Outer getOuter() {\n\t\t\t\treturn this.outer;\n\t\t\t}\n\n\t\t\tvoid setOuter(@Nullable Outer nested) {\n\t\t\t\tthis.outer = nested;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowired {\n\n\t\tprivate final Nested nested;\n\n\t\tConstructorBindingWithOuterClassConstructorBoundAndNestedAutowired(Nested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\tprivate final int age;\n\n\t\t\t@Autowired\n\t\t\tNested(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class Outer {\n\n\t\tprivate final int age;\n\n\t\tOuter(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\n\t\tint getAge() {\n\t\t\treturn this.age;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorBindingWithOuterClassConstructorBoundProperties.class)\n\tstatic class ConstructorBindingWithOuterClassConstructorBoundConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowired.class)\n\tstatic class ConstructorBindingWithOuterClassConstructorBoundAndNestedAutowiredConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class MultiConstructorConfigurationListProperties {\n\n\t\tprivate final List<MultiConstructorConfigurationProperties> nested = new ArrayList<>();\n\n\t\tList<MultiConstructorConfigurationProperties> getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(MultiConstructorConfigurationListProperties.class)\n\tstatic class MultiConstructorConfigurationPropertiesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(JavaBeanNestedConstructorBindingProperties.class)\n\tstatic class JavaBeanNestedConstructorBindingPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class JavaBeanNestedConstructorBindingProperties {\n\n\t\tprivate @Nullable Nested nested;\n\n\t\t@Nullable Nested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(@Nullable Nested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tstatic final class Nested {\n\n\t\t\tprivate final int age;\n\n\t\t\t@ConstructorBinding\n\t\t\tprivate Nested(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(JavaBeanNonDefaultConstructorProperties.class)\n\tstatic class JavaBeanNonDefaultConstructorPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class JavaBeanNonDefaultConstructorProperties {\n\n\t\tprivate @Nullable Nested nested;\n\n\t\t@Nullable Nested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(@Nullable Nested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tstatic final class Nested {\n\n\t\t\tprivate int age;\n\n\t\t\tprivate Nested() {\n\n\t\t\t}\n\n\t\t\tprivate Nested(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t\tvoid setAge(int age) {\n\t\t\t\tthis.age = age + 5;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(SyntheticNestedConstructorProperties.class)\n\tstatic class SyntheticConstructorPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class SyntheticNestedConstructorProperties {\n\n\t\tprivate final Nested nested;\n\n\t\tSyntheticNestedConstructorProperties(Nested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic final class Nested {\n\n\t\t\tprivate int age;\n\n\t\t\tprivate Nested() {\n\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t\tvoid setAge(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tstatic class AnotherNested {\n\n\t\t\t\tprivate final Nested nested;\n\n\t\t\t\tAnotherNested(String name) {\n\t\t\t\t\tthis.nested = new Nested();\n\t\t\t\t}\n\n\t\t\t\tNested getNested() {\n\t\t\t\t\treturn this.nested;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(DeducedNestedConstructorProperties.class)\n\tstatic class DeducedNestedConstructorPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class DeducedNestedConstructorProperties {\n\n\t\tprivate final String name;\n\n\t\tprivate final Nested nested;\n\n\t\tDeducedNestedConstructorProperties(String name, Nested nested) {\n\t\t\tthis.name = name;\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\tprivate final int age;\n\n\t\t\tNested(int age) {\n\t\t\t\tthis.age = age;\n\t\t\t}\n\n\t\t\tint getAge() {\n\t\t\t\treturn this.age;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\t@EnableConfigurationProperties(WithPublicStringConstructorProperties.class)\n\tstatic class WithPublicStringConstructorPropertiesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WithCustomConverterAndObjectToObjectMethodProperties.class)\n\tstatic class WithCustomConverterAndObjectToObjectMethodConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic WithObjectToObjectMethodConverter withObjectToObjectMethodConverter() {\n\t\t\treturn new WithObjectToObjectMethodConverter();\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class WithCustomConverterAndObjectToObjectMethodProperties {\n\n\t\tprivate @Nullable WithPublicObjectToObjectMethod item;\n\n\t\t@Nullable WithPublicObjectToObjectMethod getItem() {\n\t\t\treturn this.item;\n\t\t}\n\n\t\tvoid setItem(@Nullable WithPublicObjectToObjectMethod item) {\n\t\t\tthis.item = item;\n\t\t}\n\n\t}\n\n\tstatic class WithObjectToObjectMethodConverter implements Converter<String, WithPublicObjectToObjectMethod> {\n\n\t\t@Override\n\t\tpublic WithPublicObjectToObjectMethod convert(String source) {\n\t\t\treturn new WithPublicObjectToObjectMethod(source);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class ConstructorUsedInBeanMethodConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"test\")\n\t\tConstructorUsedDirectly constructorUsedInBeanMethod() {\n\t\t\treturn new ConstructorUsedDirectly(\"bean-method-1\", \"bean-method-2\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ConstructorUsedInNestedProperty.class)\n\tstatic class ConstructorUsedInNestedPropertyConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorUsedInNestedProperty {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate ConstructorUsedDirectly nested = new ConstructorUsedDirectly(\"nested-1\", \"nested-2\");\n\n\t\tConstructorUsedDirectly getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(ConstructorUsedDirectly nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t}\n\n\tstatic class ConstructorUsedDirectly {\n\n\t\tprivate String one;\n\n\t\tprivate String two;\n\n\t\tConstructorUsedDirectly(String one, String two) {\n\t\t\tthis.one = one;\n\t\t\tthis.two = two;\n\t\t}\n\n\t\tString getOne() {\n\t\t\treturn this.one;\n\t\t}\n\n\t\tvoid setOne(String one) {\n\t\t\tthis.one = one;\n\t\t}\n\n\t\tString getTwo() {\n\t\t\treturn this.two;\n\t\t}\n\n\t\tvoid setTwo(String two) {\n\t\t\tthis.two = two;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(NestedRecordInstanceProperties.class)\n\tstatic class NestedRecordInstancePropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class NestedRecordInstanceProperties {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate NestedRecord nested = new NestedRecord(\"unnamed\");\n\n\t\tNestedRecord getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(NestedRecord nestedRecord) {\n\t\t\tthis.nested = nestedRecord;\n\t\t}\n\n\t}\n\n\trecord NestedRecord(String name) {\n\t}\n\n\t@EnableConfigurationProperties\n\t@Import(PotentiallyConstructorBoundProperties.class)\n\tstatic class PotentiallyConstructorBoundPropertiesImporter {\n\n\t\t@Bean\n\t\tString notAProperty() {\n\t\t\treturn \"notAProperty\";\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class PotentiallyConstructorBoundProperties {\n\n\t\tprivate @Nullable String prop;\n\n\t\tPotentiallyConstructorBoundProperties(String notAProperty) {\n\n\t\t}\n\n\t\t@Nullable String getProp() {\n\t\t\treturn this.prop;\n\t\t}\n\n\t\tvoid setProp(@Nullable String prop) {\n\t\t\tthis.prop = prop;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ResourceArrayProperties.class)\n\tstatic class ResourceArrayPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ResourceArrayProperties {\n\n\t\tprivate Resource @Nullable [] resources;\n\n\t\tResource @Nullable [] getResources() {\n\t\t\treturn this.resources;\n\t\t}\n\n\t\tvoid setResources(Resource @Nullable [] resources) {\n\t\t\tthis.resources = resources;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ResourceCollectionProperties.class)\n\tstatic class ResourceCollectionPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ResourceCollectionProperties {\n\n\t\tprivate @Nullable Collection<Resource> resources;\n\n\t\t@Nullable Collection<Resource> getResources() {\n\t\t\treturn this.resources;\n\t\t}\n\n\t\tvoid setResources(@Nullable Collection<Resource> resources) {\n\t\t\tthis.resources = resources;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ConstructorBoundCustomListProperties.class)\n\tstatic class ConstructorBoundCustomListPropertiesConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<ArrayList<?>, CustomList<?>> arrayListToCustomList() {\n\t\t\treturn new Converter<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic CustomList<?> convert(ArrayList<?> source) {\n\t\t\t\t\treturn new CustomList<>(source);\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorBoundCustomListProperties {\n\n\t\tprivate final CustomList<String> values;\n\n\t\tConstructorBoundCustomListProperties(CustomList<String> values) {\n\t\t\tthis.values = values;\n\t\t}\n\n\t\tCustomList<String> getValues() {\n\t\t\treturn this.values;\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(SetterBoundCustomListProperties.class)\n\tstatic class SetterBoundCustomListPropertiesConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<ArrayList<?>, CustomList<?>> arrayListToCustomList() {\n\t\t\treturn new Converter<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic CustomList<?> convert(ArrayList<?> source) {\n\t\t\t\t\treturn new CustomList<>(source);\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class SetterBoundCustomListProperties {\n\n\t\tprivate @Nullable CustomList<String> values;\n\n\t\t@Nullable CustomList<String> getValues() {\n\t\t\treturn this.values;\n\t\t}\n\n\t\tvoid setValues(@Nullable CustomList<String> values) {\n\t\t\tthis.values = values;\n\t\t}\n\n\t}\n\n\tstatic final class CustomList<E> extends ArrayList<E> {\n\n\t\tCustomList(List<E> delegate) {\n\t\t\tsuper(delegate);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ConversionServiceDeducerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.format.Printer;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.function.ThrowingSupplier;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConversionServiceDeducer}.\n *\n * @author Phillip Webb\n */\nclass ConversionServiceDeducerTests {\n\n\t@Test\n\tvoid getConversionServicesWhenHasConversionServiceBeanContainsOnlyBean() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tCustomConverterServiceConfiguration.class);\n\t\tConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext);\n\t\tTestApplicationConversionService expected = applicationContext.getBean(TestApplicationConversionService.class);\n\t\tassertThat(deducer.getConversionServices()).containsExactly(expected);\n\t}\n\n\t@Test\n\tvoid getConversionServiceWhenHasNoConversionServiceBeanAndNoQualifiedBeansAndNoBeanFactoryConversionServiceReturnsEmptyList() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(EmptyConfiguration.class);\n\t\tConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext);\n\t\tassertThat(deducer.getConversionServices()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getConversionServiceWhenHasNoConversionServiceBeanAndNoQualifiedBeansAndBeanFactoryConversionServiceContainsOnlyBeanFactoryInstance() {\n\t\tConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tEmptyConfiguration.class);\n\t\tConversionService conversionService = new ApplicationConversionService();\n\t\tapplicationContext.getBeanFactory().setConversionService(conversionService);\n\t\tConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext);\n\t\tList<ConversionService> conversionServices = deducer.getConversionServices();\n\t\tassertThat(conversionServices).isNotNull();\n\t\tassertThat(conversionServices).containsOnly(conversionService);\n\t\tassertThat(conversionServices.get(0)).isSameAs(conversionService);\n\t}\n\n\t@Test\n\tvoid getConversionServiceWhenHasQualifiedConverterBeansContainsCustomizedFormattingService() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tCustomConverterConfiguration.class);\n\t\tConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext);\n\t\tList<ConversionService> conversionServices = deducer.getConversionServices();\n\t\tassertThat(conversionServices).hasSize(2);\n\t\tassertThat(conversionServices.get(0)).isExactlyInstanceOf(FormattingConversionService.class);\n\t\tassertThat(conversionServices.get(0).canConvert(InputStream.class, OutputStream.class)).isTrue();\n\t\tassertThat(conversionServices.get(0).canConvert(CharSequence.class, InputStream.class)).isTrue();\n\t\tassertThat(conversionServices.get(1)).isSameAs(ApplicationConversionService.getSharedInstance());\n\t}\n\n\t@Test\n\tvoid getConversionServiceWhenHasQualifiedConverterLambdaBeansContainsCustomizedFormattingService() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tCustomLambdaConverterConfiguration.class);\n\t\tConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext);\n\t\tList<ConversionService> conversionServices = deducer.getConversionServices();\n\t\tassertThat(conversionServices).hasSize(2);\n\t\tassertThat(conversionServices.get(0)).isExactlyInstanceOf(FormattingConversionService.class);\n\t\tassertThat(conversionServices.get(0).canConvert(InputStream.class, OutputStream.class)).isTrue();\n\t\tassertThat(conversionServices.get(0).canConvert(CharSequence.class, InputStream.class)).isTrue();\n\t\tassertThat(conversionServices.get(1)).isSameAs(ApplicationConversionService.getSharedInstance());\n\t}\n\n\t@Test\n\tvoid getConversionServiceWhenHasPrinterBean() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(PrinterConfiguration.class);\n\t\tConversionServiceDeducer deducer = new ConversionServiceDeducer(applicationContext);\n\t\tList<ConversionService> conversionServices = deducer.getConversionServices();\n\t\tInputStream inputStream = new ByteArrayInputStream(\"test\".getBytes(StandardCharsets.UTF_8));\n\t\tassertThat(conversionServices).isNotNull();\n\t\tassertThat(conversionServices.get(0).convert(inputStream, String.class)).isEqualTo(\"test\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConverterServiceConfiguration {\n\n\t\t@Bean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME)\n\t\tTestApplicationConversionService conversionService() {\n\t\t\treturn new TestApplicationConversionService();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic TestConverter testConverter() {\n\t\t\treturn new TestConverter();\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic StringConverter stringConverter() {\n\t\t\treturn new StringConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomLambdaConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<InputStream, OutputStream> testConverter() {\n\t\t\treturn (source) -> new TestConverter().convert(source);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<String, InputStream> stringConverter() {\n\t\t\treturn (source) -> new StringConverter().convert(source);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrinterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Printer<InputStream> inputStreamPrinter() {\n\t\t\treturn (source, locale) -> ThrowingSupplier\n\t\t\t\t.of(() -> StreamUtils.copyToString(source, StandardCharsets.UTF_8))\n\t\t\t\t.get();\n\t\t}\n\n\t}\n\n\tprivate static final class TestApplicationConversionService extends ApplicationConversionService {\n\n\t}\n\n\tprivate static final class TestConverter implements Converter<InputStream, OutputStream> {\n\n\t\t@Override\n\t\tpublic OutputStream convert(InputStream source) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n\tprivate static final class StringConverter implements Converter<String, InputStream> {\n\n\t\t@Override\n\t\tpublic InputStream convert(String source) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.context.properties.bind.BindMethod;\nimport org.springframework.core.type.AnnotationMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link EnableConfigurationPropertiesRegistrar}.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n */\nclass EnableConfigurationPropertiesRegistrarTests {\n\n\tprivate DefaultListableBeanFactory beanFactory;\n\n\tprivate EnableConfigurationPropertiesRegistrar registrar;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.beanFactory = spy(new DefaultListableBeanFactory());\n\t\tthis.registrar = new EnableConfigurationPropertiesRegistrar();\n\t}\n\n\t@Test\n\tvoid typeWithDefaultConstructorShouldRegisterRootBeanDefinition() {\n\t\tregister(TestConfiguration.class);\n\t\tBeanDefinition definition = this.beanFactory\n\t\t\t.getBeanDefinition(\"foo-\" + getClass().getName() + \"$FooProperties\");\n\t\tassertThat(definition).satisfies(hasBindMethod(BindMethod.JAVA_BEAN));\n\t}\n\n\t@Test\n\tvoid constructorBoundPropertiesShouldRegisterConfigurationPropertiesBeanDefinition() {\n\t\tregister(TestConfiguration.class);\n\t\tBeanDefinition definition = this.beanFactory\n\t\t\t.getBeanDefinition(\"bar-\" + getClass().getName() + \"$BarProperties\");\n\t\tassertThat(definition).satisfies(hasBindMethod(BindMethod.VALUE_OBJECT));\n\t}\n\n\t@Test\n\tvoid typeWithMultipleConstructorsShouldRegisterGenericBeanDefinition() {\n\t\tregister(TestConfiguration.class);\n\t\tBeanDefinition definition = this.beanFactory\n\t\t\t.getBeanDefinition(\"bing-\" + getClass().getName() + \"$BingProperties\");\n\t\tassertThat(definition).satisfies(hasBindMethod(BindMethod.JAVA_BEAN));\n\t}\n\n\t@Test\n\tvoid typeWithNoAnnotationShouldFail() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> register(InvalidConfiguration.class))\n\t\t\t.withMessageContaining(\"No ConfigurationProperties annotation found\")\n\t\t\t.withMessageContaining(EnableConfigurationPropertiesRegistrar.class.getName());\n\t}\n\n\t@Test\n\tvoid registrationWithDuplicatedTypeShouldRegisterSingleBeanDefinition() {\n\t\tregister(DuplicateConfiguration.class);\n\t\tString name = \"foo-\" + getClass().getName() + \"$FooProperties\";\n\t\tthen(this.beanFactory).should().registerBeanDefinition(eq(name), any());\n\t}\n\n\t@Test\n\tvoid registrationWithNoTypeShouldNotRegisterAnything() {\n\t\tregister(EmptyConfiguration.class);\n\t\tString[] names = this.beanFactory.getBeanNamesForType(Object.class);\n\t\tfor (String name : names) {\n\t\t\tassertThat(name).doesNotContain(\"-\");\n\t\t}\n\t}\n\n\tprivate Consumer<BeanDefinition> hasBindMethod(BindMethod bindMethod) {\n\t\treturn (definition) -> {\n\t\t\tassertThat(definition.hasAttribute(BindMethod.class.getName())).isTrue();\n\t\t\tassertThat(definition.getAttribute(BindMethod.class.getName())).isEqualTo(bindMethod);\n\t\t};\n\t}\n\n\tprivate void register(Class<?> configuration) {\n\t\tAnnotationMetadata metadata = AnnotationMetadata.introspect(configuration);\n\t\tthis.registrar.registerBeanDefinitions(metadata, this.beanFactory);\n\t}\n\n\t@EnableConfigurationProperties({ FooProperties.class, BarProperties.class, BingProperties.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(EnableConfigurationPropertiesRegistrarTests.class)\n\tstatic class InvalidConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties({ FooProperties.class, FooProperties.class })\n\tstatic class DuplicateConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"foo\")\n\tstatic class FooProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"bar\")\n\tstatic class BarProperties {\n\n\t\tBarProperties(String foo) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"bing\")\n\tstatic class BingProperties {\n\n\t\tBingProperties() {\n\t\t}\n\n\t\tBingProperties(String foo) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/IncompatibleConfigurationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IncompatibleConfigurationFailureAnalyzer}\n *\n * @author Brian Clozel\n */\nclass IncompatibleConfigurationFailureAnalyzerTests {\n\n\t@Test\n\tvoid incompatibleConfigurationListsKeys() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(\"spring.first.key\", \"spring.second.key\");\n\t\tassertThat(failureAnalysis).isNotNull();\n\t\tassertThat(failureAnalysis.getDescription()).contains(\n\t\t\t\t\"The following configuration properties have incompatible values: [spring.first.key, spring.second.key]\");\n\t\tassertThat(failureAnalysis.getAction())\n\t\t\t.contains(\"Review the docs for spring.first.key, spring.second.key and change the configured values.\");\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(String... keys) {\n\t\tIncompatibleConfigurationException failure = new IncompatibleConfigurationException(keys);\n\t\treturn new IncompatibleConfigurationFailureAnalyzer().analyze(failure);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/MultiConstructorConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Class used to test multi-constructor binding. Must be public and have public\n * constructors.\n *\n * @author Phillip Webb\n */\npublic class MultiConstructorConfigurationProperties {\n\n\tprivate @Nullable String name;\n\n\tprivate int age;\n\n\tpublic MultiConstructorConfigurationProperties() {\n\t}\n\n\tpublic MultiConstructorConfigurationProperties(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn this.age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/NotConstructorBoundInjectionFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.FatalBeanException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NotConstructorBoundInjectionFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n */\nclass NotConstructorBoundInjectionFailureAnalyzerTests {\n\n\tprivate final NotConstructorBoundInjectionFailureAnalyzer analyzer = new NotConstructorBoundInjectionFailureAnalyzer();\n\n\t@Test\n\tvoid failureAnalysisForConfigurationPropertiesThatShouldHaveBeenConstructorBound() {\n\t\tFailureAnalysis analysis = analyzeFailure(\n\t\t\t\tcreateFailure(ShouldHaveUsedConstructorBindingPropertiesConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).isEqualTo(ConstructorBoundProperties.class.getSimpleName()\n\t\t\t\t+ \" is annotated with @\" + ConstructorBinding.class.getSimpleName()\n\t\t\t\t+ \" but it is defined as a regular bean which caused dependency injection to fail.\");\n\t\tassertThat(analysis.getAction())\n\t\t\t.isEqualTo(\"Update your configuration so that \" + ConstructorBoundProperties.class.getSimpleName()\n\t\t\t\t\t+ \" is defined via @\" + ConfigurationPropertiesScan.class.getSimpleName() + \" or @\"\n\t\t\t\t\t+ EnableConfigurationProperties.class.getSimpleName() + \".\");\n\t}\n\n\t@Test\n\tvoid failureAnalysisForNonConstructorBoundProperties() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(JavaBeanBoundPropertiesConfiguration.class));\n\t\tassertThat(analysis).isNull();\n\t}\n\n\tprivate @Nullable FatalBeanException createFailure(Class<?> config) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.register(config);\n\t\t\tcontext.refresh();\n\t\t\treturn null;\n\t\t}\n\t\tcatch (FatalBeanException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate @Nullable FailureAnalysis analyzeFailure(@Nullable Exception failure) {\n\t\tassertThat(failure).isNotNull();\n\t\tFailureAnalysis analysis = this.analyzer.analyze(failure);\n\t\tif (analysis != null) {\n\t\t\tnew LoggingFailureAnalysisReporter().report(analysis);\n\t\t}\n\t\treturn analysis;\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class ConstructorBoundProperties {\n\n\t\tprivate final String name;\n\n\t\tConstructorBoundProperties(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ConstructorBoundProperties.class)\n\tstatic class ShouldHaveUsedConstructorBindingPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class JavaBeanBoundProperties {\n\n\t\tprivate @Nullable String name;\n\n\t\t@Autowired\n\t\tJavaBeanBoundProperties(String dependency) {\n\n\t\t}\n\n\t\t@Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(JavaBeanBoundProperties.class)\n\tstatic class JavaBeanBoundPropertiesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertyMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.PropertyMapper.Source.Always;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link PropertyMapper}.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Chris Bono\n */\nclass PropertyMapperTests {\n\n\tprivate final PropertyMapper map = PropertyMapper.get();\n\n\t@Test\n\tvoid fromNullValue() {\n\t\tExampleDest dest = new ExampleDest();\n\t\tthis.map.from((String) null).to(dest::setName);\n\t\tassertThat(dest.getName()).isNull();\n\t}\n\n\t@Test\n\tvoid fromValue() {\n\t\tExampleDest dest = new ExampleDest();\n\t\tthis.map.from(\"Hello World\").to(dest::setName);\n\t\tassertThat(dest.getName()).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid fromValueAsIntShouldAdaptValue() {\n\t\tInteger result = this.map.from(\"123\").asInt(Long::valueOf).toInstance(Integer::valueOf);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromWhenSupplierIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.map.from((Supplier<?>) null))\n\t\t\t.withMessageContaining(\"'supplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid orFromWhenSuppliedWithNull() {\n\t\tassertThat(this.map.from(\"value\").orFrom(() -> \"fallback\").toInstance(Function.identity())).isEqualTo(\"value\");\n\t}\n\n\t@Test\n\tvoid orFromWhenSuppliedWithNonNull() {\n\t\tassertThat(this.map.from((String) null).orFrom(() -> \"fallback\").toInstance(Function.identity()))\n\t\t\t.isEqualTo(\"fallback\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid toWhenConsumerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.map.from(() -> \"\").to(null))\n\t\t\t.withMessageContaining(\"'consumer' must not be null\");\n\t}\n\n\t@Test\n\tvoid toShouldMapFromSupplier() {\n\t\tExampleSource source = new ExampleSource(\"test\");\n\t\tExampleDest dest = new ExampleDest();\n\t\tthis.map.from(source::getName).to(dest::setName);\n\t\tassertThat(dest.getName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid asIntShouldAdaptSupplier() {\n\t\tInteger result = this.map.from(() -> \"123\").asInt(Long::valueOf).toInstance(Integer::valueOf);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid asWhenAdapterIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.map.from(() -> \"\").as(null))\n\t\t\t.withMessageContaining(\"'adapter' must not be null\");\n\t}\n\n\t@Test\n\tvoid asShouldAdaptSupplier() {\n\t\tExampleDest dest = new ExampleDest();\n\t\tthis.map.from(() -> 123).as(String::valueOf).to(dest::setName);\n\t\tassertThat(dest.getName()).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid whenTrueWhenValueIsTrueShouldMap() {\n\t\tBoolean result = this.map.from(true).whenTrue().toInstance(Boolean::valueOf);\n\t\tassertThat(result).isTrue();\n\t}\n\n\t@Test\n\tvoid whenTrueWhenValueIsFalseShouldNotMap() {\n\t\tthis.map.from(false).whenTrue().toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenFalseWhenValueIsFalseShouldMap() {\n\t\tBoolean result = this.map.from(false).whenFalse().toInstance(Boolean::valueOf);\n\t\tassertThat(result).isFalse();\n\t}\n\n\t@Test\n\tvoid whenFalseWhenValueIsTrueShouldNotMap() {\n\t\tthis.map.from(true).whenFalse().toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenHasTextWhenValueIsNullShouldNotMap() {\n\t\tthis.map.from(() -> null).whenHasText().toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenHasTextWhenValueIsEmptyShouldNotMap() {\n\t\tthis.map.from(\"\").whenHasText().toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenHasTextWhenValueHasTextShouldMap() {\n\t\tInteger result = this.map.from(123).whenHasText().toInstance(Integer::valueOf);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid whenEqualToWhenValueIsEqualShouldMatch() {\n\t\tString result = this.map.from(\"123\").whenEqualTo(\"123\").toInstance(String::new);\n\t\tassertThat(result).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid whenEqualToWhenValueIsNotEqualShouldNotMatch() {\n\t\tthis.map.from(\"123\").whenEqualTo(\"321\").toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenInstanceOfWhenValueIsTargetTypeShouldMatch() {\n\t\tLong result = this.map.from(123L).whenInstanceOf(Long.class).toInstance((value) -> value + 1);\n\t\tassertThat(result).isEqualTo(124L);\n\t}\n\n\t@Test\n\tvoid whenInstanceOfWhenValueIsNotTargetTypeShouldNotMatch() {\n\t\tSupplier<Number> supplier = () -> 123L;\n\t\tthis.map.from(supplier).whenInstanceOf(Double.class).toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenWhenValueMatchesShouldMap() {\n\t\tString result = this.map.from(\"123\").when(\"123\"::equals).toInstance(String::new);\n\t\tassertThat(result).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid whenWhenValueDoesNotMatchShouldNotMap() {\n\t\tthis.map.from(\"123\").when(\"321\"::equals).toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenWhenCombinedWithAsUsesSourceValue() {\n\t\tCount<String> source = new Count<>(() -> \"123\");\n\t\tLong result = this.map.from(source)\n\t\t\t.when(\"123\"::equals)\n\t\t\t.as(Integer::valueOf)\n\t\t\t.when((v) -> v == 123)\n\t\t\t.as(Integer::longValue)\n\t\t\t.toInstance(Long::valueOf);\n\t\tassertThat(result).isEqualTo(123);\n\t\tassertThat(source.getCount()).isOne();\n\t}\n\n\t@Test\n\tvoid whenWhenValueNotMatchesShouldSupportChainedCalls() {\n\t\tthis.map.from(\"123\").when(\"456\"::equals).when(\"123\"::equals).toCall(this::failure);\n\t}\n\n\t@Test\n\tvoid whenWhenValueMatchesShouldSupportChainedCalls() {\n\t\tString result = this.map.from(\"123\").when((s) -> s.contains(\"2\")).when(\"123\"::equals).toInstance(String::new);\n\t\tassertThat(result).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid toImmutableReturnsNewInstance() {\n\t\tImmutable instance = this.map.from(\"Spring\").toInstance(Immutable::of);\n\t\tinstance = this.map.from(\"123\").as(Integer::valueOf).to(instance, Immutable::withAge);\n\t\tassertThat(instance).hasToString(\"Spring 123\");\n\t}\n\n\t@Test\n\tvoid toImmutableWhenFilteredReturnsOriginalInstance() {\n\t\tImmutable instance = this.map.from(\"Spring\").toInstance(Immutable::of);\n\t\tinstance = this.map.from(\"123\").when(\"345\"::equals).as(Integer::valueOf).to(instance, Immutable::withAge);\n\t\tassertThat(instance).hasToString(\"Spring null\");\n\t}\n\n\t@Test\n\tvoid toConsumerWhenNull() {\n\t\tExampleDest dest = new ExampleDest();\n\t\tthis.map.from((String) null).to(dest::setName);\n\t\tassertThat(dest.getName()).isNull();\n\t\tassertThat(dest.setNameCalled).isFalse();\n\t}\n\n\t@Test\n\tvoid toImmutableWhenNull() {\n\t\tImmutable instance = this.map.from(\"Spring\").toInstance(Immutable::of);\n\t\tinstance = this.map.from((Integer) null).to(instance, Immutable::withAge);\n\t\tassertThat(instance).hasToString(\"Spring null\");\n\t\tassertThat(instance.withAgeCalled).isFalse();\n\t}\n\n\t@Test\n\tvoid toInstanceWhenNull() {\n\t\tassertThatExceptionOfType(NoSuchElementException.class)\n\t\t\t.isThrownBy(() -> this.map.from((String) null).toInstance(String::valueOf));\n\t}\n\n\t@Test\n\tvoid toCallWhenNull() {\n\t\tAtomicBoolean called = new AtomicBoolean();\n\t\tRunnable call = () -> called.set(true);\n\t\tthis.map.from((String) null).toCall(call);\n\t\tassertThat(called).isFalse();\n\t}\n\n\tprivate void failure() {\n\t\tfail();\n\t}\n\n\t/**\n\t * Tests for {@link Always}.\n\t */\n\t@Nested\n\tclass AlwaysTests {\n\n\t\tprivate final PropertyMapper map = PropertyMapperTests.this.map;\n\n\t\t@Test\n\t\tvoid asWhenNull() {\n\t\t\tString value = this.map.from((String) null).always().as(String::valueOf).toInstance((string) -> {\n\t\t\t\tassertThat(string).isNotNull();\n\t\t\t\treturn string;\n\t\t\t});\n\t\t\tassertThat(value).isEqualTo(\"null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid toConsumerWhenNull() {\n\t\t\tExampleDest dest = new ExampleDest();\n\t\t\tthis.map.from((String) null).always().to(dest::setName);\n\t\t\tassertThat(dest.getName()).isNull();\n\t\t\tassertThat(dest.setNameCalled).isTrue();\n\t\t}\n\n\t\t@Test\n\t\tvoid toImmutableWhenNull() {\n\t\t\tImmutable instance = this.map.from(\"Spring\").toInstance(Immutable::of);\n\t\t\tinstance = this.map.from((Integer) null).always().to(instance, Immutable::withAge);\n\t\t\tassertThat(instance).hasToString(\"Spring null\");\n\t\t\tassertThat(instance.withAgeCalled).isTrue();\n\t\t}\n\n\t\t@Test\n\t\tvoid toInstanceWhenNull() {\n\t\t\tString value = this.map.from((String) null).always().toInstance(String::valueOf);\n\t\t\tassertThat(value).isEqualTo(\"null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid toCallWhenNull() {\n\t\t\tAtomicBoolean called = new AtomicBoolean();\n\t\t\tRunnable call = () -> called.set(true);\n\t\t\tthis.map.from((String) null).always().toCall(call);\n\t\t\tassertThat(called).isTrue();\n\t\t}\n\n\t}\n\n\tstatic class Count<T> implements Supplier<T> {\n\n\t\tprivate final Supplier<T> source;\n\n\t\tprivate int count;\n\n\t\tCount(Supplier<T> source) {\n\t\t\tthis.source = source;\n\t\t}\n\n\t\t@Override\n\t\tpublic T get() {\n\t\t\tthis.count++;\n\t\t\treturn this.source.get();\n\t\t}\n\n\t\tint getCount() {\n\t\t\treturn this.count;\n\t\t}\n\n\t}\n\n\tstatic class ExampleSource {\n\n\t\tprivate final String name;\n\n\t\tExampleSource(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic class ExampleDest {\n\n\t\tprivate @Nullable String name;\n\n\t\tboolean setNameCalled;\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t\tthis.setNameCalled = true;\n\t\t}\n\n\t\t@Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic class Immutable {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable Integer age;\n\n\t\tfinal boolean withAgeCalled;\n\n\t\tImmutable(String name, @Nullable Integer age) {\n\t\t\tthis(name, age, false);\n\t\t}\n\n\t\tprivate Immutable(String name, @Nullable Integer age, boolean withAgeCalled) {\n\t\t\tthis.name = name;\n\t\t\tthis.age = age;\n\t\t\tthis.withAgeCalled = withAgeCalled;\n\t\t}\n\n\t\tImmutable withAge(@Nullable Integer age) {\n\t\t\treturn new Immutable(this.name, age, true);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"%s %s\".formatted(this.name, this.age);\n\t\t}\n\n\t\tstatic Immutable of(String name) {\n\t\t\treturn new Immutable(name, null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/PropertySourcesDeducerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySources;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PropertySourcesDeducer}.\n *\n * @author Phillip Webb\n */\nclass PropertySourcesDeducerTests {\n\n\t@Test\n\tvoid getPropertySourcesWhenHasSinglePropertySourcesPlaceholderConfigurerReturnsBean() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tPropertySourcesPlaceholderConfigurerConfiguration.class);\n\t\tPropertySourcesDeducer deducer = new PropertySourcesDeducer(applicationContext);\n\t\tPropertySources propertySources = deducer.getPropertySources();\n\t\tassertThat(propertySources.get(\"test\")).isInstanceOf(TestPropertySource.class);\n\t}\n\n\t@Test\n\tvoid getPropertySourcesWhenHasNoPropertySourcesPlaceholderConfigurerReturnsEnvironmentSources() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(EmptyConfiguration.class);\n\t\tConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();\n\t\tenvironment.getPropertySources().addFirst(new TestPropertySource());\n\t\tPropertySourcesDeducer deducer = new PropertySourcesDeducer(applicationContext);\n\t\tPropertySources propertySources = deducer.getPropertySources();\n\t\tassertThat(propertySources.get(\"test\")).isInstanceOf(TestPropertySource.class);\n\t}\n\n\t@Test\n\tvoid getPropertySourcesWhenHasMultiplePropertySourcesPlaceholderConfigurerReturnsEnvironmentSources() {\n\t\tApplicationContext applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tMultiplePropertySourcesPlaceholderConfigurerConfiguration.class);\n\t\tConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();\n\t\tenvironment.getPropertySources().addFirst(new TestPropertySource());\n\t\tPropertySourcesDeducer deducer = new PropertySourcesDeducer(applicationContext);\n\t\tPropertySources propertySources = deducer.getPropertySources();\n\t\tassertThat(propertySources.get(\"test\")).isInstanceOf(TestPropertySource.class);\n\t}\n\n\t@Test\n\tvoid getPropertySourcesWhenUnavailableThrowsException() {\n\t\tApplicationContext applicationContext = mock(ApplicationContext.class);\n\t\tEnvironment environment = mock(Environment.class);\n\t\tgiven(applicationContext.getEnvironment()).willReturn(environment);\n\t\tPropertySourcesDeducer deducer = new PropertySourcesDeducer(applicationContext);\n\t\tassertThatIllegalStateException().isThrownBy(deducer::getPropertySources)\n\t\t\t.withMessage(\"Unable to obtain PropertySources from PropertySourcesPlaceholderConfigurer or Environment\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PropertySourcesPlaceholderConfigurerConfiguration {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\t\tPropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();\n\t\t\tMutablePropertySources propertySources = new MutablePropertySources();\n\t\t\tpropertySources.addFirst(new TestPropertySource());\n\t\t\tconfigurer.setPropertySources(propertySources);\n\t\t\treturn configurer;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultiplePropertySourcesPlaceholderConfigurerConfiguration {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer1() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer2() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n\tprivate static class TestPropertySource extends MapPropertySource {\n\n\t\tTestPropertySource() {\n\t\t\tsuper(\"test\", Collections.emptyMap());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/ValidatorPropertiesWithDefaultValues.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.ValidationUtils;\nimport org.springframework.validation.Validator;\n\n/**\n * Used for testing validation of properties that have default field values.\n *\n * @author Madhura Bhave\n */\n@EnableConfigurationProperties\n@ConfigurationProperties\nclass ValidatorPropertiesWithDefaultValues implements Validator {\n\n\tprivate String bar = \"a\";\n\n\t@Override\n\tpublic boolean supports(Class<?> type) {\n\t\treturn type == ValidatorPropertiesWithDefaultValues.class;\n\t}\n\n\t@Override\n\tpublic void validate(Object target, Errors errors) {\n\t\tValidationUtils.rejectIfEmpty(errors, \"bar\", \"foo.empty\");\n\t}\n\n\tpublic String getBar() {\n\t\treturn this.bar;\n\t}\n\n\tpublic void setBar(String bar) {\n\t\tthis.bar = bar;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/WithPublicObjectToObjectMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport java.util.Optional;\n\n/**\n * Data object with a public method picked up by the {@code ObjectToObjectConverter}. Used\n * in {@link ConfigurationPropertiesTests}.\n *\n * @author Phillip Webb\n */\npublic class WithPublicObjectToObjectMethod {\n\n\tprivate final String value;\n\n\tWithPublicObjectToObjectMethod(String value) {\n\t\tthis.value = value;\n\t}\n\n\tString getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic static Optional<WithPublicObjectToObjectMethod> from(String value) {\n\t\treturn Optional.of(new WithPublicObjectToObjectMethod(value));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/WithPublicStringConstructorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@link ConfigurationProperties @ConfigurationProperties} with an additional\n * single-arg public constructor. Used in {@link ConfigurationPropertiesTests}.\n *\n * @author Madhura Bhave\n */\n@ConfigurationProperties(\"test\")\npublic class WithPublicStringConstructorProperties {\n\n\tprivate @Nullable String a;\n\n\tpublic WithPublicStringConstructorProperties() {\n\t}\n\n\tpublic WithPublicStringConstructorProperties(String a) {\n\t\tthis.a = a;\n\t}\n\n\tpublic @Nullable String getA() {\n\t\treturn this.a;\n\t}\n\n\tpublic void setA(@Nullable String a) {\n\t\tthis.a = a;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ArrayBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ArrayBinder}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ArrayBinderTests {\n\n\tprivate static final Bindable<List<Integer>> INTEGER_LIST = Bindable.listOf(Integer.class);\n\n\tprivate static final Bindable<Integer[]> INTEGER_ARRAY = Bindable.of(Integer[].class);\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate final Binder binder = new Binder(this.sources);\n\n\t@Test\n\tvoid bindToArrayShouldReturnArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tInteger[] result = this.binder.bind(\"foo\", INTEGER_ARRAY).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToCollectionShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo[0]\", \"1\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tthis.binder.bind(\"foo\", INTEGER_LIST, handler);\n\t\tInOrder inOrder = inOrder(handler);\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo[0]\")), eq(Bindable.of(Integer.class)), any(), eq(1));\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(INTEGER_LIST), any(), isA(List.class));\n\t}\n\n\t@Test\n\tvoid bindToArrayShouldReturnPrimitiveArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tint[] result = this.binder.bind(\"foo\", Bindable.of(int[].class)).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenNestedShouldReturnPopulatedArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0][0]\", \"1\");\n\t\tsource.put(\"foo[0][1]\", \"2\");\n\t\tsource.put(\"foo[1][0]\", \"3\");\n\t\tsource.put(\"foo[1][1]\", \"4\");\n\t\tthis.sources.add(source);\n\t\tResolvableType type = ResolvableType.forArrayComponent(INTEGER_ARRAY.getType());\n\t\tBindable<Integer[][]> target = Bindable.of(type);\n\t\tInteger[][] result = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(result).hasDimensions(2, 2);\n\t\tassertThat(result[0]).containsExactly(1, 2);\n\t\tassertThat(result[1]).containsExactly(3, 4);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenNestedListShouldReturnPopulatedArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0][0]\", \"1\");\n\t\tsource.put(\"foo[0][1]\", \"2\");\n\t\tsource.put(\"foo[1][0]\", \"3\");\n\t\tsource.put(\"foo[1][1]\", \"4\");\n\t\tthis.sources.add(source);\n\t\tResolvableType type = ResolvableType.forArrayComponent(INTEGER_LIST.getType());\n\t\tBindable<List<Integer>[]> target = Bindable.of(type);\n\t\tList<Integer>[] result = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(result).hasSize(2);\n\t\tassertThat(result[0]).containsExactly(1, 2);\n\t\tassertThat(result[1]).containsExactly(3, 4);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenNotInOrderShouldReturnPopulatedArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tInteger[] result = this.binder.bind(\"foo\", INTEGER_ARRAY).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenNonSequentialShouldThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"2\");\n\t\tsource.put(\"foo[1]\", \"1\");\n\t\tsource.put(\"foo[3]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind(\"foo\", INTEGER_ARRAY))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tThrowable cause = ex.getCause();\n\t\t\t\tassertThat(cause).isNotNull();\n\t\t\t\tSet<ConfigurationProperty> unbound = ((UnboundConfigurationPropertiesException) cause)\n\t\t\t\t\t.getUnboundProperties();\n\t\t\t\tassertThat(unbound).hasSize(1);\n\t\t\t\tConfigurationProperty property = unbound.iterator().next();\n\t\t\t\tassertThat(property.getName()).hasToString(\"foo[3]\");\n\t\t\t\tassertThat(property.getValue()).isEqualTo(\"3\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenNonIterableShouldReturnPopulatedArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source.nonIterable());\n\t\tInteger[] result = this.binder.bind(\"foo\", INTEGER_ARRAY).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenMultipleSourceShouldOnlyUseFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"bar\", \"baz\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo[0]\", \"1\");\n\t\tsource2.put(\"foo[1]\", \"2\");\n\t\tthis.sources.add(source2);\n\t\tMockConfigurationPropertySource source3 = new MockConfigurationPropertySource();\n\t\tsource3.put(\"foo[0]\", \"7\");\n\t\tsource3.put(\"foo[1]\", \"8\");\n\t\tsource3.put(\"foo[2]\", \"9\");\n\t\tthis.sources.add(source3);\n\t\tInteger[] result = this.binder.bind(\"foo\", INTEGER_ARRAY).get();\n\t\tassertThat(result).containsExactly(1, 2);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenHasExistingCollectionShouldReplaceAllContents() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo[0]\", \"1\"));\n\t\tInteger[] existing = new Integer[2];\n\t\texisting[0] = 1000;\n\t\texisting[1] = 1001;\n\t\tInteger[] result = this.binder.bind(\"foo\", INTEGER_ARRAY.withExistingValue(existing)).get();\n\t\tassertThat(result).containsExactly(1);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenNoValueShouldReturnUnbound() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"faf.bar\", \"1\"));\n\t\tBindResult<Integer[]> result = this.binder.bind(\"foo\", INTEGER_ARRAY);\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToArrayShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo[0]\", \"1\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tBindable<Integer[]> target = INTEGER_ARRAY;\n\t\tthis.binder.bind(\"foo\", target, handler);\n\t\tInOrder inOrder = inOrder(handler);\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo[0]\")), eq(Bindable.of(Integer.class)), any(), eq(1));\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), isA(Integer[].class));\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenCommaListShouldReturnPopulatedArray() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"1,2,3\"));\n\t\tint[] result = this.binder.bind(\"foo\", Bindable.of(int[].class)).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenCommaListAndIndexedShouldOnlyUseFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"foo\", \"1,2\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo[0]\", \"2\");\n\t\tsource2.put(\"foo[1]\", \"3\");\n\t\tint[] result = this.binder.bind(\"foo\", Bindable.of(int[].class)).get();\n\t\tassertThat(result).containsExactly(1, 2);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenIndexedAndCommaListShouldOnlyUseFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"foo[0]\", \"1\");\n\t\tsource1.put(\"foo[1]\", \"2\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo\", \"2,3\");\n\t\tint[] result = this.binder.bind(\"foo\", Bindable.of(int[].class)).get();\n\t\tassertThat(result).containsExactly(1, 2);\n\t}\n\n\t@Test\n\tvoid bindToArrayShouldBindCharArray() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"word\"));\n\t\tchar[] result = this.binder.bind(\"foo\", Bindable.of(char[].class)).get();\n\t\tassertThat(result).containsExactly(\"word\".toCharArray());\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenEmptyStringShouldReturnEmptyArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"\");\n\t\tthis.sources.add(source);\n\t\tString[] result = this.binder.bind(\"foo\", Bindable.of(String[].class)).get();\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenHasSpacesShouldTrim() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"1,  2,3\");\n\t\tthis.sources.add(source);\n\t\tString[] result = this.binder.bind(\"foo\", Bindable.of(String[].class)).get();\n\t\tassertThat(result).containsExactly(\"1\", \"2\", \"3\");\n\t}\n\n\t@Test\n\tvoid bindToArrayShouldUsePropertyEditor() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"java.lang.RuntimeException\");\n\t\tsource.put(\"foo[1]\", \"java.lang.IllegalStateException\");\n\t\tthis.sources.add(source);\n\t\tassertThat(this.binder.bind(\"foo\", Bindable.of(Class[].class)).get()).containsExactly(RuntimeException.class,\n\t\t\t\tIllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid bindToArrayWhenStringShouldUsePropertyEditor() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"java.lang.RuntimeException,java.lang.IllegalStateException\");\n\t\tthis.sources.add(source);\n\t\tassertThat(this.binder.bind(\"foo\", Bindable.of(Class[].class)).get()).containsExactly(RuntimeException.class,\n\t\t\t\tIllegalStateException.class);\n\t}\n\n\tprivate BindHandler mockBindHandler() {\n\t\tBindHandler handler = mock(BindHandler.class);\n\t\tgiven(handler.onStart(any(), any(), any())).willAnswer(InvocationArgument.index(1));\n\t\tgiven(handler.onCreate(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));\n\t\tgiven(handler.onSuccess(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));\n\t\treturn handler;\n\t}\n\n\tprivate static final class InvocationArgument<T> implements Answer<T> {\n\n\t\tprivate final int index;\n\n\t\tprivate InvocationArgument(int index) {\n\t\t\tthis.index = index;\n\t\t}\n\n\t\t@Override\n\t\tpublic T answer(InvocationOnMock invocation) throws Throwable {\n\t\t\treturn invocation.getArgument(this.index);\n\t\t}\n\n\t\tprivate static <T> InvocationArgument<T> index(int index) {\n\t\t\treturn new InvocationArgument<>(index);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BackCompatibilityBinderIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests to ensure that the {@link Binder} offers at least some support for\n * Boot 1.5 style binding.\n *\n * @author Phillip Webb\n */\nclass BackCompatibilityBinderIntegrationTests {\n\n\t@Test\n\tvoid bindWhenBindingCamelCaseToEnvironmentWithExtractUnderscore() {\n\t\t// gh-10873\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tSystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tCollections.singletonMap(\"FOO_ZK_NODES\", \"foo\"));\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tExampleCamelCaseBean result = Binder.get(environment)\n\t\t\t.bind(\"foo\", Bindable.of(ExampleCamelCaseBean.class))\n\t\t\t.get();\n\t\tassertThat(result.getZkNodes()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingSystemEnvironmentToOverride() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tSystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(\"override\",\n\t\t\t\tCollections.singletonMap(\"foo.password\", \"test\"));\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tPasswordProperties result = Binder.get(environment).bind(\"foo\", Bindable.of(PasswordProperties.class)).get();\n\t\tassertThat(result.getPassword()).isEqualTo(\"test\");\n\t}\n\n\tstatic class ExampleCamelCaseBean {\n\n\t\tprivate @Nullable String zkNodes;\n\n\t\t@Nullable String getZkNodes() {\n\t\t\treturn this.zkNodes;\n\t\t}\n\n\t\tvoid setZkNodes(@Nullable String zkNodes) {\n\t\t\tthis.zkNodes = zkNodes;\n\t\t}\n\n\t}\n\n\tstatic class PasswordProperties {\n\n\t\tprivate @Nullable String password;\n\n\t\t@Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tvoid setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.beans.PropertyEditorSupport;\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.beans.PropertyEditorRegistry;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.support.GenericConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link BindConverter}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(MockitoExtension.class)\nclass BindConverterTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Consumer<PropertyEditorRegistry> propertyEditorInitializer;\n\n\t@Test\n\tvoid createWhenPropertyEditorInitializerIsNullShouldCreate() {\n\t\tBindConverter.get(null, null);\n\t}\n\n\t@Test\n\tvoid createWhenPropertyEditorInitializerIsNotNullShouldUseToInitialize() {\n\t\tBindConverter.get(null, this.propertyEditorInitializer);\n\t\tthen(this.propertyEditorInitializer).should().accept(any(PropertyEditorRegistry.class));\n\t}\n\n\t@Test\n\tvoid canConvertWhenHasDefaultEditorShouldReturnTrue() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(null);\n\t\tassertThat(bindConverter.canConvert(\"java.lang.RuntimeException\", ResolvableType.forClass(Class.class)))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid canConvertWhenHasCustomEditorShouldReturnTrue() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tassertThat(bindConverter.canConvert(\"test\", ResolvableType.forClass(SampleType.class))).isTrue();\n\t}\n\n\t@Test\n\tvoid canConvertWhenHasEditorByConventionShouldReturnTrue() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(null);\n\t\tassertThat(bindConverter.canConvert(\"test\", ResolvableType.forClass(ConventionType.class))).isTrue();\n\t}\n\n\t@Test\n\tvoid canConvertWhenHasEditorForCollectionElementShouldReturnTrue() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tassertThat(bindConverter.canConvert(\"test\", ResolvableType.forClassWithGenerics(List.class, SampleType.class)))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid canConvertWhenHasEditorForArrayElementShouldReturnTrue() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tassertThat(bindConverter.canConvert(\"test\", ResolvableType.forClass(SampleType[].class))).isTrue();\n\t}\n\n\t@Test\n\tvoid canConvertWhenConversionServiceCanConvertShouldReturnTrue() {\n\t\tBindConverter bindConverter = getBindConverter(new SampleTypeConverter());\n\t\tassertThat(bindConverter.canConvert(\"test\", ResolvableType.forClass(SampleType.class))).isTrue();\n\t}\n\n\t@Test\n\tvoid canConvertWhenNotPropertyEditorAndConversionServiceCannotConvertShouldReturnFalse() {\n\t\tBindConverter bindConverter = BindConverter.get(null, null);\n\t\tassertThat(bindConverter.canConvert(\"test\", ResolvableType.forClass(SampleType.class))).isFalse();\n\t}\n\n\t@Test\n\tvoid convertWhenHasDefaultEditorShouldConvert() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(null);\n\t\tClass<?> converted = bindConverter.convert(\"java.lang.RuntimeException\", ResolvableType.forClass(Class.class));\n\t\tassertThat(converted).isEqualTo(RuntimeException.class);\n\t}\n\n\t@Test\n\tvoid convertWhenHasCustomEditorShouldConvert() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tSampleType converted = bindConverter.convert(\"test\", ResolvableType.forClass(SampleType.class));\n\t\tassertThat(converted).isNotNull();\n\t\tassertThat(converted.getText()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid convertWhenHasEditorByConventionShouldConvert() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(null);\n\t\tConventionType converted = bindConverter.convert(\"test\", ResolvableType.forClass(ConventionType.class));\n\t\tassertThat(converted).isNotNull();\n\t\tassertThat(converted.getText()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid convertWhenHasEditorForCollectionElementShouldConvert() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tList<SampleType> converted = bindConverter.convert(\"test\",\n\t\t\t\tResolvableType.forClassWithGenerics(List.class, SampleType.class));\n\t\tassertThat(converted).hasSize(1);\n\t\tassertThat(converted.get(0).getText()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid convertWhenHasEditorForArrayElementShouldConvert() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tSampleType[] converted = bindConverter.convert(\"test\", ResolvableType.forClass(SampleType[].class));\n\t\tassertThat(converted).isNotNull();\n\t\tassertThat(converted).isNotEmpty();\n\t\tassertThat(converted[0].getText()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid convertWhenConversionServiceCanConvertShouldConvert() {\n\t\tBindConverter bindConverter = getBindConverter(new SampleTypeConverter());\n\t\tSampleType converted = bindConverter.convert(\"test\", ResolvableType.forClass(SampleType.class));\n\t\tassertThat(converted).isNotNull();\n\t\tassertThat(converted.getText()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid convertWhenNotPropertyEditorAndConversionServiceCannotConvertShouldThrowException() {\n\t\tBindConverter bindConverter = BindConverter.get(null, null);\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> bindConverter.convert(\"test\", ResolvableType.forClass(SampleType.class)));\n\t}\n\n\t@Test\n\tvoid convertWhenConvertingToFileShouldExcludeFileEditor() {\n\t\t// For back compatibility we want true file conversion and not an accidental\n\t\t// classpath resource reference. See gh-12163\n\t\tBindConverter bindConverter = BindConverter.get(Collections.singletonList(new GenericConversionService()),\n\t\t\t\tnull);\n\t\tFile result = bindConverter.convert(\".\", ResolvableType.forClass(File.class));\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getPath()).isEqualTo(\".\");\n\t}\n\n\t@Test\n\tvoid fallsBackToApplicationConversionService() {\n\t\tBindConverter bindConverter = BindConverter.get(Collections.singletonList(new GenericConversionService()),\n\t\t\t\tnull);\n\t\tDuration result = bindConverter.convert(\"10s\", ResolvableType.forClass(Duration.class));\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getSeconds()).isEqualTo(10);\n\t}\n\n\t@Test // gh-27028\n\tvoid convertWhenConversionFailsThrowsConversionFailedExceptionRatherThanConverterNotFoundException() {\n\t\tBindConverter bindConverter = BindConverter.get(Collections.singletonList(new GenericConversionService()),\n\t\t\t\tnull);\n\t\tassertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t.isThrownBy(() -> bindConverter.convert(\"com.example.Missing\", ResolvableType.forClass(Class.class)))\n\t\t\t.withRootCauseInstanceOf(ClassNotFoundException.class);\n\t}\n\n\t@Test\n\tvoid convertWhenUsingTypeConverterConversionServiceFromMultipleThreads() {\n\t\tBindConverter bindConverter = getPropertyEditorOnlyBindConverter(this::registerSampleTypeEditor);\n\t\tResolvableType type = ResolvableType.forClass(SampleType.class);\n\t\tList<Thread> threads = new ArrayList<>();\n\t\tList<SampleType> results = Collections.synchronizedList(new ArrayList<>());\n\t\tfor (int i = 0; i < 40; i++) {\n\t\t\tthreads.add(new Thread(() -> {\n\t\t\t\tfor (int j = 0; j < 20; j++) {\n\t\t\t\t\tresults.add(bindConverter.convert(\"test\", type));\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\tthreads.forEach(Thread::start);\n\t\tfor (Thread thread : threads) {\n\t\t\ttry {\n\t\t\t\tthread.join();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tassertThat(results).isNotEmpty().doesNotContainNull();\n\t}\n\n\tprivate BindConverter getPropertyEditorOnlyBindConverter(\n\t\t\t@Nullable Consumer<PropertyEditorRegistry> propertyEditorInitializer) {\n\t\treturn BindConverter.get(Collections.singletonList(new ThrowingConversionService()), propertyEditorInitializer);\n\t}\n\n\tprivate BindConverter getBindConverter(Converter<?, ?> converter) {\n\t\tGenericConversionService conversionService = new GenericConversionService();\n\t\tconversionService.addConverter(converter);\n\t\treturn BindConverter.get(Collections.singletonList(conversionService), null);\n\t}\n\n\tprivate void registerSampleTypeEditor(PropertyEditorRegistry registry) {\n\t\tregistry.registerCustomEditor(SampleType.class, new SampleTypePropertyEditor());\n\t}\n\n\tstatic class SampleType {\n\n\t\tprivate @Nullable String text;\n\n\t\t@Nullable String getText() {\n\t\t\treturn this.text;\n\t\t}\n\n\t}\n\n\tstatic class SampleTypePropertyEditor extends PropertyEditorSupport {\n\n\t\t@Override\n\t\tpublic void setAsText(String text) {\n\t\t\tsetValue(null);\n\t\t\tif (text != null) {\n\t\t\t\tSampleType value = new SampleType();\n\t\t\t\tvalue.text = text;\n\t\t\t\tsetValue(value);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class SampleTypeConverter implements Converter<String, SampleType> {\n\n\t\t@Override\n\t\tpublic SampleType convert(String source) {\n\t\t\tSampleType result = new SampleType();\n\t\t\tresult.text = source;\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tstatic class ConventionType {\n\n\t\tprivate @Nullable String text;\n\n\t\t@Nullable String getText() {\n\t\t\treturn this.text;\n\t\t}\n\n\t}\n\n\tstatic class ConventionTypeEditor extends PropertyEditorSupport {\n\n\t\t@Override\n\t\tpublic void setAsText(String text) {\n\t\t\tConventionType value = new ConventionType();\n\t\t\tvalue.text = text;\n\t\t\tsetValue(value);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ConversionService} that always throws an {@link AssertionError}.\n\t */\n\tstatic class ThrowingConversionService implements ConversionService {\n\n\t\t@Override\n\t\tpublic boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {\n\t\t\tthrow new AssertionError(\"Should not call conversion service\");\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tthrow new AssertionError(\"Should not call conversion service\");\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> T convert(@Nullable Object source, Class<T> targetType) {\n\t\t\tthrow new AssertionError(\"Should not call conversion service\");\n\t\t}\n\n\t\t@Override\n\t\tpublic Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tthrow new AssertionError(\"Should not call conversion service\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindResultTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.io.IOException;\nimport java.util.NoSuchElementException;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link BindResult}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass BindResultTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Consumer<String> consumer;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Function<String, String> mapper;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Supplier<String> supplier;\n\n\t@Test\n\tvoid getWhenHasValueShouldReturnValue() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThat(result.get()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getWhenHasNoValueShouldThrowException() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tassertThatExceptionOfType(NoSuchElementException.class).isThrownBy(result::get)\n\t\t\t.withMessageContaining(\"No value bound\");\n\t}\n\n\t@Test\n\tvoid isBoundWhenHasValueShouldReturnTrue() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThat(result.isBound()).isTrue();\n\t}\n\n\t@Test\n\tvoid isBoundWhenHasNoValueShouldFalse() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ifBoundWhenConsumerIsNullShouldThrowException() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> result.ifBound(null))\n\t\t\t.withMessageContaining(\"'consumer' must not be null\");\n\t}\n\n\t@Test\n\tvoid ifBoundWhenHasValueShouldCallConsumer() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tresult.ifBound(this.consumer);\n\t\tthen(this.consumer).should().accept(\"foo\");\n\t}\n\n\t@Test\n\tvoid ifBoundWhenHasNoValueShouldNotCallConsumer() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tresult.ifBound(this.consumer);\n\t\tthen(this.consumer).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid mapWhenMapperIsNullShouldThrowException() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> result.map(null))\n\t\t\t.withMessageContaining(\"'mapper' must not be null\");\n\t}\n\n\t@Test\n\tvoid mapWhenHasValueShouldCallMapper() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tgiven(this.mapper.apply(\"foo\")).willReturn(\"bar\");\n\t\tassertThat(result.map(this.mapper).get()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid mapWhenHasNoValueShouldNotCallMapper() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tresult.map(this.mapper);\n\t\tthen(this.mapper).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid orElseWhenHasValueShouldReturnValue() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThat(result.orElse(\"bar\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid orElseWhenHasValueNoShouldReturnOther() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tassertThat(result.orElse(\"bar\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid orElseGetWhenHasValueShouldReturnValue() {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThat(result.orElseGet(this.supplier)).isEqualTo(\"foo\");\n\t\tthen(this.supplier).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid orElseGetWhenHasValueNoShouldReturnOther() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tgiven(this.supplier.get()).willReturn(\"bar\");\n\t\tassertThat(result.orElseGet(this.supplier)).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid orElseThrowWhenHasValueShouldReturnValue() throws Exception {\n\t\tBindResult<String> result = BindResult.of(\"foo\");\n\t\tassertThat(result.orElseThrow(IOException::new)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid orElseThrowWhenHasNoValueShouldThrowException() {\n\t\tBindResult<String> result = BindResult.of(null);\n\t\tassertThatIOException().isThrownBy(() -> result.orElseThrow(IOException::new));\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tBindResult<?> result1 = BindResult.of(\"foo\");\n\t\tBindResult<?> result2 = BindResult.of(\"foo\");\n\t\tBindResult<?> result3 = BindResult.of(\"bar\");\n\t\tBindResult<?> result4 = BindResult.of(null);\n\t\tassertThat(result1).hasSameHashCodeAs(result2);\n\t\tassertThat(result1).isEqualTo(result1).isEqualTo(result2).isNotEqualTo(result3).isNotEqualTo(result4);\n\t}\n\n\t@Test\n\tvoid ofWhenHasValueShouldReturnBoundResultOfValue() {\n\t\tBindResult<Object> result = BindResult.of(\"foo\");\n\t\tassertThat(result.isBound()).isTrue();\n\t\tassertThat(result.get()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid ofWhenValueIsNullShouldReturnUnbound() {\n\t\tBindResult<Object> result = BindResult.of(null);\n\t\tassertThat(result.isBound()).isFalse();\n\t\tassertThat(result).isSameAs(BindResult.of(null));\n\t}\n\n\tstatic class ExampleBean {\n\n\t\tprivate final String value;\n\n\t\tExampleBean() {\n\t\t\tthis.value = \"new\";\n\t\t}\n\n\t\tExampleBean(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tString getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Constructor;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.apache.tomcat.jdbc.pool.PoolProperties;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.ExecutableHint;\nimport org.springframework.aot.hint.FieldHint;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.context.properties.BoundConfigurationProperties;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBean;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrarTests.BaseProperties.InheritedNested;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrarTests.ComplexNestedProperties.ListenerRetry;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrarTests.ComplexNestedProperties.Retry;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrarTests.ComplexNestedProperties.Simple;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.core.StandardReflectionParameterNameDiscoverer;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link BindableRuntimeHintsRegistrar}.\n *\n * @author Tumit Watcharapol\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass BindableRuntimeHintsRegistrarTests {\n\n\t@Test\n\tvoid registerHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tClass<?>[] types = { BoundConfigurationProperties.class, ConfigurationPropertiesBean.class };\n\t\tBindableRuntimeHintsRegistrar registrar = new BindableRuntimeHintsRegistrar(types);\n\t\tregistrar.registerHints(runtimeHints);\n\t\tfor (Class<?> type : types) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection().onType(type)).accepts(runtimeHints);\n\t\t}\n\t}\n\n\t@Test\n\tvoid registerHintsWithIterable() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tList<Class<?>> types = Arrays.asList(BoundConfigurationProperties.class, ConfigurationPropertiesBean.class);\n\t\tBindableRuntimeHintsRegistrar registrar = BindableRuntimeHintsRegistrar.forTypes(types);\n\t\tregistrar.registerHints(runtimeHints);\n\t\tfor (Class<?> type : types) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection().onType(type)).accepts(runtimeHints);\n\t\t}\n\t}\n\n\t@Test\n\tvoid registerHintsWhenNoClasses() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tBindableRuntimeHintsRegistrar registrar = new BindableRuntimeHintsRegistrar(new Class<?>[0]);\n\t\tregistrar.registerHints(runtimeHints);\n\t\tassertThat(runtimeHints.reflection().typeHints()).isEmpty();\n\t}\n\n\t@Test\n\tvoid registerHintsViaForType() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tClass<?>[] types = { BoundConfigurationProperties.class, ConfigurationPropertiesBean.class };\n\t\tBindableRuntimeHintsRegistrar registrar = BindableRuntimeHintsRegistrar.forTypes(types);\n\t\tregistrar.registerHints(runtimeHints);\n\t\tfor (Class<?> type : types) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection().onType(type)).accepts(runtimeHints);\n\t\t}\n\t}\n\n\t@Test\n\tvoid registerHintsWhenJavaBean() {\n\t\tRuntimeHints runtimeHints = registerHints(JavaBean.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement().satisfies(javaBeanBinding(JavaBean.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenJavaBeanWithSeveralConstructors() throws NoSuchMethodException {\n\t\tRuntimeHints runtimeHints = registerHints(WithSeveralConstructors.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement()\n\t\t\t.satisfies(javaBeanBinding(WithSeveralConstructors.class)\n\t\t\t\t.constructor(WithSeveralConstructors.class.getDeclaredConstructor()));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenJavaBeanWithMapOfPojo() {\n\t\tRuntimeHints runtimeHints = registerHints(WithMap.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2)\n\t\t\t.anySatisfy(javaBeanBinding(WithMap.class).methods(\"getAddresses\"))\n\t\t\t.anySatisfy(javaBeanBinding(Address.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenJavaBeanWithListOfPojo() {\n\t\tRuntimeHints runtimeHints = registerHints(WithList.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2)\n\t\t\t.anySatisfy(javaBeanBinding(WithList.class).methods(\"getAllAddresses\"))\n\t\t\t.anySatisfy(javaBeanBinding(Address.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenJavaBeanWitArrayOfPojo() {\n\t\tRuntimeHints runtimeHints = registerHints(WithArray.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2)\n\t\t\t.anySatisfy(javaBeanBinding(WithArray.class).methods(\"getAllAddresses\"))\n\t\t\t.anySatisfy(javaBeanBinding(Address.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenJavaBeanWithListOfJavaType() {\n\t\tRuntimeHints runtimeHints = registerHints(WithSimpleList.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement()\n\t\t\t.satisfies(javaBeanBinding(WithSimpleList.class).methods(\"getNames\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenValueObject() {\n\t\tRuntimeHints runtimeHints = registerHints(Immutable.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement()\n\t\t\t.satisfies(valueObjectBinding(Immutable.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenValueObjectWithSpecificConstructor() throws NoSuchMethodException {\n\t\tRuntimeHints runtimeHints = registerHints(ImmutableWithSeveralConstructors.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement()\n\t\t\t.satisfies(valueObjectBinding(ImmutableWithSeveralConstructors.class,\n\t\t\t\t\tImmutableWithSeveralConstructors.class.getDeclaredConstructor(String.class)));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenValueObjectWithSeveralLayersOfPojo() {\n\t\tRuntimeHints runtimeHints = registerHints(ImmutableWithList.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(3)\n\t\t\t.anySatisfy(valueObjectBinding(ImmutableWithList.class))\n\t\t\t.anySatisfy(valueObjectBinding(Person.class))\n\t\t\t.anySatisfy(valueObjectBinding(Address.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasNestedTypeNotUsedIsIgnored() {\n\t\tRuntimeHints runtimeHints = registerHints(WithNested.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement().satisfies(javaBeanBinding(WithNested.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenWhenHasNestedExternalType() {\n\t\tRuntimeHints runtimeHints = registerHints(WithExternalNested.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(3)\n\t\t\t.anySatisfy(javaBeanBinding(WithExternalNested.class)\n\t\t\t\t.methods(\"getName\", \"setName\", \"getSampleType\", \"setSampleType\")\n\t\t\t\t.fields(\"name\", \"sampleType\"))\n\t\t\t.anySatisfy(javaBeanBinding(SampleType.class).methods(\"getNested\").fields(\"nested\"))\n\t\t\t.anySatisfy(javaBeanBinding(SampleType.Nested.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasRecursiveType() {\n\t\tRuntimeHints runtimeHints = registerHints(WithRecursive.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2)\n\t\t\t.anySatisfy(\n\t\t\t\t\tjavaBeanBinding(WithRecursive.class).methods(\"getRecursive\", \"setRecursive\").fields(\"recursive\"))\n\t\t\t.anySatisfy(javaBeanBinding(Recursive.class).methods(\"getRecursive\", \"setRecursive\").fields(\"recursive\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenValueObjectWithRecursiveType() {\n\t\tRuntimeHints runtimeHints = registerHints(ImmutableWithRecursive.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2)\n\t\t\t.anySatisfy(valueObjectBinding(ImmutableWithRecursive.class))\n\t\t\t.anySatisfy(valueObjectBinding(ImmutableRecursive.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasWellKnownTypes() {\n\t\tRuntimeHints runtimeHints = registerHints(WithWellKnownTypes.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement()\n\t\t\t.satisfies(javaBeanBinding(WithWellKnownTypes.class)\n\t\t\t\t.methods(\"getApplicationContext\", \"setApplicationContext\", \"getEnvironment\", \"setEnvironment\")\n\t\t\t\t.fields(\"applicationContext\", \"environment\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasCrossReference() {\n\t\tRuntimeHints runtimeHints = registerHints(WithCrossReference.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(3)\n\t\t\t.anySatisfy(javaBeanBinding(WithCrossReference.class).methods(\"getCrossReferenceA\", \"setCrossReferenceA\")\n\t\t\t\t.fields(\"crossReferenceA\"))\n\t\t\t.anySatisfy(javaBeanBinding(CrossReferenceA.class).methods(\"getCrossReferenceB\", \"setCrossReferenceB\")\n\t\t\t\t.fields(\"crossReferenceB\"))\n\t\t\t.anySatisfy(javaBeanBinding(CrossReferenceB.class).methods(\"getCrossReferenceA\", \"setCrossReferenceA\")\n\t\t\t\t.fields(\"crossReferenceA\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasUnresolvedGeneric() {\n\t\tRuntimeHints runtimeHints = registerHints(WithGeneric.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2)\n\t\t\t.anySatisfy(javaBeanBinding(WithGeneric.class).methods(\"getGeneric\").fields(\"generic\"))\n\t\t\t.anySatisfy(javaBeanBinding(GenericObject.class));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasNestedGenerics() {\n\t\tRuntimeHints runtimeHints = registerHints(NestedGenerics.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(2);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(NestedGenerics.class)).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(NestedGenerics.Nested.class)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasMultipleNestedClasses() {\n\t\tRuntimeHints runtimeHints = registerHints(TripleNested.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(3);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(TripleNested.class)).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(TripleNested.DoubleNested.class)).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(TripleNested.DoubleNested.Nested.class))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasPackagePrivateGettersAndSetters() {\n\t\tRuntimeHints runtimeHints = registerHints(PackagePrivateGettersAndSetters.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).singleElement()\n\t\t\t.satisfies(javaBeanBinding(PackagePrivateGettersAndSetters.class)\n\t\t\t\t.methods(\"getAlpha\", \"setAlpha\", \"getBravo\", \"setBravo\")\n\t\t\t\t.fields(\"alpha\", \"bravo\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasInheritedNestedProperties() {\n\t\tRuntimeHints runtimeHints = registerHints(ExtendingProperties.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(3);\n\t\tassertThat(runtimeHints.reflection().getTypeHint(BaseProperties.class)).satisfies((entry) -> {\n\t\t\tassertThat(entry.getMemberCategories()).isEmpty();\n\t\t\tassertThat(entry.methods()).extracting(ExecutableHint::getName)\n\t\t\t\t.containsExactlyInAnyOrder(\"getInheritedNested\", \"setInheritedNested\");\n\t\t});\n\t\tassertThat(runtimeHints.reflection().getTypeHint(ExtendingProperties.class))\n\t\t\t.satisfies(javaBeanBinding(ExtendingProperties.class).methods(\"getBravo\", \"setBravo\").fields(\"bravo\"));\n\t\tassertThat(runtimeHints.reflection().getTypeHint(InheritedNested.class))\n\t\t\t.satisfies(javaBeanBinding(InheritedNested.class).methods(\"getAlpha\", \"setAlpha\").fields(\"alpha\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWhenHasComplexNestedProperties() {\n\t\tRuntimeHints runtimeHints = registerHints(ComplexNestedProperties.class);\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(4);\n\t\tassertThat(runtimeHints.reflection().getTypeHint(Retry.class)).satisfies((entry) -> {\n\t\t\tassertThat(entry.getMemberCategories()).isEmpty();\n\t\t\tassertThat(entry.methods()).extracting(ExecutableHint::getName)\n\t\t\t\t.containsExactlyInAnyOrder(\"getCount\", \"setCount\");\n\t\t});\n\t\tassertThat(runtimeHints.reflection().getTypeHint(ListenerRetry.class))\n\t\t\t.satisfies(javaBeanBinding(ListenerRetry.class).methods(\"isStateless\", \"setStateless\").fields(\"stateless\"));\n\t\tassertThat(runtimeHints.reflection().getTypeHint(Simple.class))\n\t\t\t.satisfies(javaBeanBinding(Simple.class).methods(\"getRetry\").fields(\"retry\"));\n\t\tassertThat(runtimeHints.reflection().getTypeHint(ComplexNestedProperties.class))\n\t\t\t.satisfies(javaBeanBinding(ComplexNestedProperties.class).methods(\"getSimple\").fields(\"simple\"));\n\t}\n\n\t@Test\n\tvoid registerHintsDoesNotThrowWhenParameterInformationForConstructorBindingIsNotAvailable()\n\t\t\tthrows NoSuchMethodException, SecurityException {\n\t\tConstructor<?> constructor = PoolProperties.InterceptorProperty.class.getConstructor(String.class,\n\t\t\t\tString.class);\n\t\t@Nullable String[] parameterNames = new StandardReflectionParameterNameDiscoverer().getParameterNames(constructor);\n\t\tassertThat(parameterNames).isNull();\n\t\tassertThatNoException().isThrownBy(() -> registerHints(PoolProperties.class));\n\t}\n\n\tprivate JavaBeanBinding javaBeanBinding(Class<?> type) {\n\t\treturn new JavaBeanBinding(type);\n\t}\n\n\tprivate Consumer<TypeHint> valueObjectBinding(Class<?> type) {\n\t\treturn valueObjectBinding(type, type.getDeclaredConstructors()[0]);\n\t}\n\n\tprivate Consumer<TypeHint> valueObjectBinding(Class<?> type, Constructor<?> constructor) {\n\t\treturn (entry) -> {\n\t\t\tassertThat(entry.getType()).isEqualTo(TypeReference.of(type));\n\t\t\tassertThat(entry.constructors()).singleElement().satisfies(match(constructor));\n\t\t\tassertThat(entry.getMemberCategories()).isEmpty();\n\t\t\tassertThat(entry.methods()).isEmpty();\n\t\t};\n\t}\n\n\tprivate static Consumer<ExecutableHint> match(Constructor<?> constructor) {\n\t\treturn (executableHint) -> {\n\t\t\tassertThat(executableHint.getName()).isEqualTo(\"<init>\");\n\t\t\tassertThat(Arrays.stream(constructor.getParameterTypes()).map(TypeReference::of).toList())\n\t\t\t\t.isEqualTo(executableHint.getParameterTypes());\n\t\t};\n\t}\n\n\tprivate RuntimeHints registerHints(Class<?>... types) {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tBindableRuntimeHintsRegistrar.forTypes(types).registerHints(hints);\n\t\treturn hints;\n\t}\n\n\tpublic static class JavaBean {\n\n\t}\n\n\tpublic static class WithSeveralConstructors {\n\n\t\tWithSeveralConstructors() {\n\t\t}\n\n\t\tWithSeveralConstructors(String ignored) {\n\t\t}\n\n\t}\n\n\tpublic static class WithMap {\n\n\t\tpublic Map<String, Address> getAddresses() {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\n\t}\n\n\tpublic static class WithList {\n\n\t\tpublic List<Address> getAllAddresses() {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t}\n\n\tpublic static class WithSimpleList {\n\n\t\tpublic List<String> getNames() {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t}\n\n\tpublic static class WithArray {\n\n\t\tpublic Address[] getAllAddresses() {\n\t\t\treturn new Address[0];\n\t\t}\n\n\t}\n\n\tpublic static class Immutable {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final String name;\n\n\t\tImmutable(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\tpublic static class ImmutableWithSeveralConstructors {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final String name;\n\n\t\t@ConstructorBinding\n\t\tImmutableWithSeveralConstructors(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tImmutableWithSeveralConstructors() {\n\t\t\tthis(\"test\");\n\t\t}\n\n\t}\n\n\tpublic static class ImmutableWithList {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final List<Person> family;\n\n\t\tImmutableWithList(List<Person> family) {\n\t\t\tthis.family = family;\n\t\t}\n\n\t}\n\n\tpublic static class WithNested {\n\n\t\tstatic class OneLevelDown {\n\n\t\t}\n\n\t}\n\n\tpublic static class WithExternalNested {\n\n\t\tprivate @Nullable String name;\n\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable SampleType sampleType;\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic @Nullable SampleType getSampleType() {\n\t\t\treturn this.sampleType;\n\t\t}\n\n\t\tpublic void setSampleType(@Nullable SampleType sampleType) {\n\t\t\tthis.sampleType = sampleType;\n\t\t}\n\n\t}\n\n\tpublic static class WithRecursive {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable Recursive recursive;\n\n\t\tpublic @Nullable Recursive getRecursive() {\n\t\t\treturn this.recursive;\n\t\t}\n\n\t\tpublic void setRecursive(@Nullable Recursive recursive) {\n\t\t\tthis.recursive = recursive;\n\t\t}\n\n\t}\n\n\tpublic static class ImmutableWithRecursive {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate final @Nullable ImmutableRecursive recursive;\n\n\t\tImmutableWithRecursive(@Nullable ImmutableRecursive recursive) {\n\t\t\tthis.recursive = recursive;\n\t\t}\n\n\t}\n\n\tpublic static class WithWellKnownTypes implements ApplicationContextAware, EnvironmentAware {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ApplicationContext applicationContext;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate Environment environment;\n\n\t\tpublic ApplicationContext getApplicationContext() {\n\t\t\treturn this.applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setApplicationContext(ApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\tpublic Environment getEnvironment() {\n\t\t\treturn this.environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setEnvironment(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t}\n\n\tpublic static class SampleType {\n\n\t\tprivate final Nested nested = new Nested();\n\n\t\tpublic Nested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t}\n\n\t}\n\n\tpublic static class PackagePrivateGettersAndSetters {\n\n\t\tprivate @Nullable String alpha;\n\n\t\tprivate @Nullable Map<String, String> bravo;\n\n\t\t@Nullable String getAlpha() {\n\t\t\treturn this.alpha;\n\t\t}\n\n\t\tvoid setAlpha(@Nullable String alpha) {\n\t\t\tthis.alpha = alpha;\n\t\t}\n\n\t\t@Nullable Map<String, String> getBravo() {\n\t\t\treturn this.bravo;\n\t\t}\n\n\t\tvoid setBravo(@Nullable Map<String, String> bravo) {\n\t\t\tthis.bravo = bravo;\n\t\t}\n\n\t}\n\n\tpublic static class Address {\n\n\t}\n\n\tpublic static class Person {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final String firstName;\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final String lastName;\n\n\t\t@NestedConfigurationProperty\n\t\tprivate final Address address;\n\n\t\tPerson(String firstName, String lastName, Address address) {\n\t\t\tthis.firstName = firstName;\n\t\t\tthis.lastName = lastName;\n\t\t\tthis.address = address;\n\t\t}\n\n\t}\n\n\tpublic static class Recursive {\n\n\t\tprivate @Nullable Recursive recursive;\n\n\t\tpublic @Nullable Recursive getRecursive() {\n\t\t\treturn this.recursive;\n\t\t}\n\n\t\tpublic void setRecursive(@Nullable Recursive recursive) {\n\t\t\tthis.recursive = recursive;\n\t\t}\n\n\t}\n\n\tpublic static class ImmutableRecursive {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final @Nullable ImmutableRecursive recursive;\n\n\t\tImmutableRecursive(@Nullable ImmutableRecursive recursive) {\n\t\t\tthis.recursive = recursive;\n\t\t}\n\n\t}\n\n\tpublic static class WithCrossReference {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable CrossReferenceA crossReferenceA;\n\n\t\tpublic void setCrossReferenceA(@Nullable CrossReferenceA crossReferenceA) {\n\t\t\tthis.crossReferenceA = crossReferenceA;\n\t\t}\n\n\t\tpublic @Nullable CrossReferenceA getCrossReferenceA() {\n\t\t\treturn this.crossReferenceA;\n\t\t}\n\n\t}\n\n\tpublic static class CrossReferenceA {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable CrossReferenceB crossReferenceB;\n\n\t\tpublic void setCrossReferenceB(@Nullable CrossReferenceB crossReferenceB) {\n\t\t\tthis.crossReferenceB = crossReferenceB;\n\t\t}\n\n\t\tpublic @Nullable CrossReferenceB getCrossReferenceB() {\n\t\t\treturn this.crossReferenceB;\n\t\t}\n\n\t}\n\n\tpublic static class CrossReferenceB {\n\n\t\tprivate @Nullable CrossReferenceA crossReferenceA;\n\n\t\tpublic void setCrossReferenceA(@Nullable CrossReferenceA crossReferenceA) {\n\t\t\tthis.crossReferenceA = crossReferenceA;\n\t\t}\n\n\t\tpublic @Nullable CrossReferenceA getCrossReferenceA() {\n\t\t\treturn this.crossReferenceA;\n\t\t}\n\n\t}\n\n\tpublic static class WithGeneric {\n\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable GenericObject<?> generic;\n\n\t\tpublic @Nullable GenericObject<?> getGeneric() {\n\t\t\treturn this.generic;\n\t\t}\n\n\t}\n\n\tpublic static final class GenericObject<T> {\n\n\t\tprivate final T value;\n\n\t\tGenericObject(T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic T getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\tpublic static class NestedGenerics {\n\n\t\tprivate final Map<String, List<Nested>> nested = new HashMap<>();\n\n\t\tpublic Map<String, List<Nested>> getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tpublic static class Nested {\n\n\t\t\tprivate @Nullable String field;\n\n\t\t\tpublic @Nullable String getField() {\n\t\t\t\treturn this.field;\n\t\t\t}\n\n\t\t\tpublic void setField(@Nullable String field) {\n\t\t\t\tthis.field = field;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class TripleNested {\n\n\t\tprivate final DoubleNested doubleNested = new DoubleNested();\n\n\t\tpublic DoubleNested getDoubleNested() {\n\t\t\treturn this.doubleNested;\n\t\t}\n\n\t\tpublic static class DoubleNested {\n\n\t\t\tprivate final Nested nested = new Nested();\n\n\t\t\tpublic Nested getNested() {\n\t\t\t\treturn this.nested;\n\t\t\t}\n\n\t\t\tpublic static class Nested {\n\n\t\t\t\tprivate @Nullable String field;\n\n\t\t\t\tpublic @Nullable String getField() {\n\t\t\t\t\treturn this.field;\n\t\t\t\t}\n\n\t\t\t\tpublic void setField(@Nullable String field) {\n\t\t\t\t\tthis.field = field;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic abstract static class BaseProperties {\n\n\t\tprivate @Nullable InheritedNested inheritedNested;\n\n\t\tpublic @Nullable InheritedNested getInheritedNested() {\n\t\t\treturn this.inheritedNested;\n\t\t}\n\n\t\tpublic void setInheritedNested(@Nullable InheritedNested inheritedNested) {\n\t\t\tthis.inheritedNested = inheritedNested;\n\t\t}\n\n\t\tpublic static class InheritedNested {\n\n\t\t\tprivate @Nullable String alpha;\n\n\t\t\tpublic @Nullable String getAlpha() {\n\t\t\t\treturn this.alpha;\n\t\t\t}\n\n\t\t\tpublic void setAlpha(@Nullable String alpha) {\n\t\t\t\tthis.alpha = alpha;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class ExtendingProperties extends BaseProperties {\n\n\t\tprivate @Nullable String bravo;\n\n\t\tpublic @Nullable String getBravo() {\n\t\t\treturn this.bravo;\n\t\t}\n\n\t\tpublic void setBravo(@Nullable String bravo) {\n\t\t\tthis.bravo = bravo;\n\t\t}\n\n\t}\n\n\tpublic static class ComplexNestedProperties {\n\n\t\tprivate final Simple simple = new Simple();\n\n\t\tpublic Simple getSimple() {\n\t\t\treturn this.simple;\n\t\t}\n\n\t\tpublic static class Simple {\n\n\t\t\tprivate final ListenerRetry retry = new ListenerRetry();\n\n\t\t\tpublic ListenerRetry getRetry() {\n\t\t\t\treturn this.retry;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic abstract static class Retry {\n\n\t\t\tprivate int count = 5;\n\n\t\t\tpublic int getCount() {\n\t\t\t\treturn this.count;\n\t\t\t}\n\n\t\t\tpublic void setCount(int count) {\n\t\t\t\tthis.count = count;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class ListenerRetry extends Retry {\n\n\t\t\tprivate boolean stateless;\n\n\t\t\tpublic boolean isStateless() {\n\t\t\t\treturn this.stateless;\n\t\t\t}\n\n\t\t\tpublic void setStateless(boolean stateless) {\n\t\t\t\tthis.stateless = stateless;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tprivate static final class JavaBeanBinding implements Consumer<TypeHint> {\n\n\t\tprivate final Class<?> type;\n\n\t\tprivate Constructor<?> constructor;\n\n\t\tprivate List<String> expectedMethods = Collections.emptyList();\n\n\t\tprivate List<String> expectedFields = Collections.emptyList();\n\n\t\tprivate JavaBeanBinding(Class<?> type) {\n\t\t\tthis.type = type;\n\t\t\tthis.constructor = this.type.getDeclaredConstructors()[0];\n\t\t}\n\n\t\t@Override\n\t\tpublic void accept(TypeHint entry) {\n\t\t\tassertThat(entry.getType()).isEqualTo(TypeReference.of(this.type));\n\t\t\tassertThat(entry.constructors()).singleElement().satisfies(match(this.constructor));\n\t\t\tassertThat(entry.getMemberCategories()).isEmpty();\n\t\t\tassertThat(entry.methods()).as(\"Methods requiring reflection\")\n\t\t\t\t.extracting(ExecutableHint::getName)\n\t\t\t\t.containsExactlyInAnyOrderElementsOf(this.expectedMethods);\n\t\t\tassertThat(entry.fields()).as(\"Fields requiring reflection\")\n\t\t\t\t.extracting(FieldHint::getName)\n\t\t\t\t.containsExactlyInAnyOrderElementsOf(this.expectedFields);\n\t\t}\n\n\t\tprivate JavaBeanBinding constructor(Constructor<?> constructor) {\n\t\t\tthis.constructor = constructor;\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate JavaBeanBinding methods(String... methods) {\n\t\t\tthis.expectedMethods = List.of(methods);\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate JavaBeanBinding fields(String... fields) {\n\t\t\tthis.expectedFields = List.of(fields);\n\t\t\treturn this;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable.BindRestriction;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.AnnotationUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Bindable}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass BindableTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofClassWhenTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Bindable.of((Class<?>) null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofTypeWhenTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Bindable.of((ResolvableType) null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofClassShouldSetType() {\n\t\tassertThat(Bindable.of(String.class).getType()).isEqualTo(ResolvableType.forClass(String.class));\n\t}\n\n\t@Test\n\tvoid ofTypeShouldSetType() {\n\t\tResolvableType type = ResolvableType.forClass(String.class);\n\t\tassertThat(Bindable.of(type).getType()).isEqualTo(type);\n\t}\n\n\t@Test\n\tvoid ofInstanceShouldSetTypeAndExistingValue() {\n\t\tString instance = \"foo\";\n\t\tResolvableType type = ResolvableType.forClass(String.class);\n\t\tassertThat(Bindable.ofInstance(instance).getType()).isEqualTo(type);\n\t\tSupplier<String> value = Bindable.ofInstance(instance).getValue();\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value.get()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid ofClassWithExistingValueShouldSetTypeAndExistingValue() {\n\t\tSupplier<String> value = Bindable.of(String.class).withExistingValue(\"foo\").getValue();\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value.get()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid ofTypeWithExistingValueShouldSetTypeAndExistingValue() {\n\t\tSupplier<Object> value = Bindable.of(ResolvableType.forClass(String.class)).withExistingValue(\"foo\").getValue();\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value.get()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid ofTypeWhenExistingValueIsNotInstanceOfTypeShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> Bindable.of(ResolvableType.forClass(String.class)).withExistingValue(123))\n\t\t\t.withMessageContaining(\"'existingValue' must be an instance of \" + String.class.getName());\n\t}\n\n\t@Test\n\tvoid ofTypeWhenPrimitiveWithExistingValueWrapperShouldNotThrowException() {\n\t\tBindable<Integer> bindable = Bindable.<Integer>of(ResolvableType.forClass(int.class)).withExistingValue(123);\n\t\tassertThat(bindable.getType().resolve()).isEqualTo(int.class);\n\t\tSupplier<Integer> value = bindable.getValue();\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid getBoxedTypeWhenNotBoxedShouldReturnType() {\n\t\tBindable<String> bindable = Bindable.of(String.class);\n\t\tassertThat(bindable.getBoxedType()).isEqualTo(ResolvableType.forClass(String.class));\n\t}\n\n\t@Test\n\tvoid getBoxedTypeWhenPrimitiveShouldReturnBoxedType() {\n\t\tBindable<Integer> bindable = Bindable.of(int.class);\n\t\tassertThat(bindable.getType()).isEqualTo(ResolvableType.forClass(int.class));\n\t\tassertThat(bindable.getBoxedType()).isEqualTo(ResolvableType.forClass(Integer.class));\n\t}\n\n\t@Test\n\tvoid getBoxedTypeWhenPrimitiveArrayShouldReturnBoxedType() {\n\t\tBindable<int[]> bindable = Bindable.of(int[].class);\n\t\tassertThat(bindable.getType().getComponentType()).isEqualTo(ResolvableType.forClass(int.class));\n\t\tassertThat(bindable.getBoxedType().isArray()).isTrue();\n\t\tassertThat(bindable.getBoxedType().getComponentType()).isEqualTo(ResolvableType.forClass(Integer.class));\n\t}\n\n\t@Test\n\tvoid getAnnotationsShouldReturnEmptyArray() {\n\t\tassertThat(Bindable.of(String.class).getAnnotations()).isEmpty();\n\t}\n\n\t@Test\n\tvoid withAnnotationsShouldSetAnnotations() {\n\t\tAnnotation annotation = mock(Annotation.class);\n\t\tassertThat(Bindable.of(String.class).withAnnotations(annotation).getAnnotations()).containsExactly(annotation);\n\t}\n\n\t@Test\n\tvoid getAnnotationWhenMatchShouldReturnAnnotation() {\n\t\tTest annotation = AnnotationUtils.synthesizeAnnotation(Test.class);\n\t\tassertThat(Bindable.of(String.class).withAnnotations(annotation).getAnnotation(Test.class))\n\t\t\t.isSameAs(annotation);\n\t}\n\n\t@Test\n\tvoid getAnnotationWhenNoMatchShouldReturnNull() {\n\t\tTest annotation = AnnotationUtils.synthesizeAnnotation(Test.class);\n\t\tassertThat(Bindable.of(String.class).withAnnotations(annotation).getAnnotation(Bean.class)).isNull();\n\t}\n\n\t@Test\n\tvoid toStringShouldShowDetails() {\n\t\tAnnotation annotation = AnnotationUtils.synthesizeAnnotation(TestAnnotation.class);\n\t\tBindable<String> bindable = Bindable.of(String.class).withExistingValue(\"foo\").withAnnotations(annotation);\n\t\tassertThat(bindable.toString())\n\t\t\t.contains(\"type = java.lang.String, value = 'provided', annotations = array<Annotation>[\"\n\t\t\t\t\t+ \"@org.springframework.boot.context.properties.bind.BindableTests.TestAnnotation()]\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tAnnotation annotation = AnnotationUtils.synthesizeAnnotation(TestAnnotation.class);\n\t\tBindable<String> bindable1 = Bindable.of(String.class).withExistingValue(\"foo\").withAnnotations(annotation);\n\t\tBindable<String> bindable2 = Bindable.of(String.class).withExistingValue(\"foo\").withAnnotations(annotation);\n\t\tBindable<String> bindable3 = Bindable.of(String.class).withExistingValue(\"fof\").withAnnotations(annotation);\n\t\tassertThat(bindable1).hasSameHashCodeAs(bindable2);\n\t\tassertThat(bindable1).isEqualTo(bindable1).isEqualTo(bindable2);\n\t\tassertThat(bindable1).isEqualTo(bindable3);\n\t}\n\n\t@Test // gh-18218\n\tvoid withExistingValueDoesNotForgetAnnotations() {\n\t\tAnnotation annotation = AnnotationUtils.synthesizeAnnotation(TestAnnotation.class);\n\t\tBindable<?> bindable = Bindable.of(String.class).withAnnotations(annotation).withExistingValue(\"\");\n\t\tassertThat(bindable.getAnnotations()).containsExactly(annotation);\n\t}\n\n\t@Test // gh-18218\n\tvoid withSuppliedValueDoesNotForgetAnnotations() {\n\t\tAnnotation annotation = AnnotationUtils.synthesizeAnnotation(TestAnnotation.class);\n\t\tBindable<?> bindable = Bindable.of(String.class).withAnnotations(annotation).withSuppliedValue(() -> \"\");\n\t\tassertThat(bindable.getAnnotations()).containsExactly(annotation);\n\t}\n\n\t@Test\n\tvoid hasBindRestrictionWhenDefaultReturnsFalse() {\n\t\tBindable<String> bindable = Bindable.of(String.class);\n\t\tfor (BindRestriction bindRestriction : BindRestriction.values()) {\n\t\t\tassertThat(bindable.hasBindRestriction(bindRestriction)).isFalse();\n\t\t}\n\t}\n\n\t@Test\n\tvoid withBindRestrictionAddsBindRestriction() {\n\t\tBindable<String> bindable = Bindable.of(String.class);\n\t\tBindable<String> restricted = bindable.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY);\n\t\tassertThat(bindable.hasBindRestriction(BindRestriction.NO_DIRECT_PROPERTY)).isFalse();\n\t\tassertThat(restricted.hasBindRestriction(BindRestriction.NO_DIRECT_PROPERTY)).isTrue();\n\t}\n\n\t@Test\n\tvoid whenTypeCouldUseJavaBeanOrValueObjectJavaBeanBindingCanBeSpecified() {\n\t\tBindMethod bindMethod = Bindable.of(JavaBeanOrValueObject.class)\n\t\t\t.withBindMethod(BindMethod.JAVA_BEAN)\n\t\t\t.getBindMethod();\n\t\tassertThat(bindMethod).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid whenTypeCouldUseJavaBeanOrValueObjectExistingValueForcesJavaBeanBinding() {\n\t\tBindMethod bindMethod = Bindable.of(JavaBeanOrValueObject.class)\n\t\t\t.withExistingValue(new JavaBeanOrValueObject(\"value\"))\n\t\t\t.getBindMethod();\n\t\tassertThat(bindMethod).isEqualTo(BindMethod.JAVA_BEAN);\n\t}\n\n\t@Test\n\tvoid whenBindingIsValueObjectExistingValueThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> Bindable.of(JavaBeanOrValueObject.class)\n\t\t\t.withBindMethod(BindMethod.VALUE_OBJECT)\n\t\t\t.withExistingValue(new JavaBeanOrValueObject(\"value\")));\n\t}\n\n\t@Test\n\tvoid whenBindableHasExistingValueValueObjectBindMethodThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> Bindable.of(JavaBeanOrValueObject.class)\n\t\t\t.withExistingValue(new JavaBeanOrValueObject(\"value\"))\n\t\t\t.withBindMethod(BindMethod.VALUE_OBJECT));\n\t}\n\n\t@Test\n\tvoid whenBindableHasSuppliedValueValueObjectBindMethodThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> Bindable.of(JavaBeanOrValueObject.class)\n\t\t\t.withSuppliedValue(() -> new JavaBeanOrValueObject(\"value\"))\n\t\t\t.withBindMethod(BindMethod.VALUE_OBJECT));\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface TestAnnotation {\n\n\t}\n\n\tstatic class JavaBeanOrValueObject {\n\n\t\tprivate String property;\n\n\t\tJavaBeanOrValueObject(String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t\tString getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t\tvoid setProperty(String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.beans.PropertyEditorSupport;\nimport java.time.LocalDate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.validation.Validation;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport org.springframework.boot.context.properties.bind.Bindable.BindRestriction;\nimport org.springframework.boot.context.properties.bind.validation.ValidationBindHandler;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.format.annotation.DateTimeFormat;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.validation.beanvalidation.SpringValidatorAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Binder}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass BinderTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate Binder binder = new Binder(this.sources);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSourcesIsNullArrayShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Binder((ConfigurationPropertySource[]) null))\n\t\t\t.withMessageContaining(\"'sources' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSourcesIsNullIterableShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Binder((Iterable<ConfigurationPropertySource>) null))\n\t\t\t.withMessageContaining(\"'sources' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenArraySourcesContainsNullElementShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Binder(new ConfigurationPropertySource[] { null }))\n\t\t\t.withMessageContaining(\"'sources' must not contain null elements\");\n\t}\n\n\t@Test\n\tvoid createWhenIterableSourcesContainsNullElementShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Binder(Collections.singletonList(null)))\n\t\t\t.withMessageContaining(\"'sources' must not contain null elements\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid bindWhenNameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.binder.bind((ConfigurationPropertyName) null, Bindable.of(String.class),\n\t\t\t\t\tBindHandler.DEFAULT))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid bindWhenTargetIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.binder.bind(ConfigurationPropertyName.of(\"foo\"), null, BindHandler.DEFAULT))\n\t\t\t.withMessageContaining(\"'target' must not be null\");\n\t}\n\n\t@Test\n\tvoid bindToValueWhenPropertyIsMissingShouldReturnUnbound() {\n\t\tthis.sources.add(new MockConfigurationPropertySource());\n\t\tBindResult<String> result = this.binder.bind(\"foo\", Bindable.of(String.class));\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToValueShouldReturnPropertyValue() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", 123));\n\t\tBindResult<Integer> result = this.binder.bind(\"foo\", Bindable.of(Integer.class));\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid bindToValueShouldReturnPropertyValueFromSecondSource() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", 123));\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"bar\", 234));\n\t\tBindResult<Integer> result = this.binder.bind(\"bar\", Bindable.of(Integer.class));\n\t\tassertThat(result.get()).isEqualTo(234);\n\t}\n\n\t@Test\n\tvoid bindToValueShouldReturnConvertedPropertyValue() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"123\"));\n\t\tBindResult<Integer> result = this.binder.bind(\"foo\", Bindable.of(Integer.class));\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid bindToValueWhenMultipleCandidatesShouldReturnFirst() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", 123));\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", 234));\n\t\tBindResult<Integer> result = this.binder.bind(\"foo\", Bindable.of(Integer.class));\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid bindToValueWithPlaceholdersShouldResolve() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, \"bar=23\");\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"1${bar}\"));\n\t\tthis.binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment));\n\t\tBindResult<Integer> result = this.binder.bind(\"foo\", Bindable.of(Integer.class));\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid bindToValueWithMissingPlaceholderShouldResolveToValueWithPlaceholder() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"${bar}\"));\n\t\tthis.binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment));\n\t\tBindResult<String> result = this.binder.bind(\"foo\", Bindable.of(String.class));\n\t\tassertThat(result.get()).isEqualTo(\"${bar}\");\n\t}\n\n\t@Test\n\tvoid bindToValueWithCustomPropertyEditorShouldReturnConvertedValue() {\n\t\tthis.binder = new Binder(this.sources, null, null,\n\t\t\t\t(registry) -> registry.registerCustomEditor(JavaBean.class, new JavaBeanPropertyEditor()));\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"123\"));\n\t\tBindResult<JavaBean> result = this.binder.bind(\"foo\", Bindable.of(JavaBean.class));\n\t\tassertThat(result.get().getValue()).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid bindToValueShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"1\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tBindable<Integer> target = Bindable.of(Integer.class);\n\t\tthis.binder.bind(\"foo\", target, handler);\n\t\tInOrder ordered = inOrder(handler);\n\t\tordered.verify(handler).onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), eq(1));\n\t}\n\n\t@Test\n\tvoid bindOrCreateWhenNotBoundShouldTriggerOnCreate() {\n\t\tBindHandler handler = mock(BindHandler.class);\n\t\tBindable<JavaBean> target = Bindable.of(JavaBean.class);\n\t\tthis.binder.bindOrCreate(\"foo\", target, handler);\n\t\tInOrder ordered = inOrder(handler);\n\t\tordered.verify(handler).onCreate(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), any());\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanShouldReturnPopulatedBean() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.value\", \"bar\"));\n\t\tJavaBean result = this.binder.bind(\"foo\", Bindable.of(JavaBean.class)).get();\n\t\tassertThat(result.getValue()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanWhenNonIterableShouldReturnPopulatedBean() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource(\"foo.value\", \"bar\");\n\t\tthis.sources.add(source.nonIterable());\n\t\tJavaBean result = this.binder.bind(\"foo\", Bindable.of(JavaBean.class)).get();\n\t\tassertThat(result.getValue()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanWhenHasPropertyWithSameNameShouldStillBind() {\n\t\t// gh-10945\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"boom\");\n\t\tsource.put(\"foo.value\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tJavaBean result = this.binder.bind(\"foo\", Bindable.of(JavaBean.class)).get();\n\t\tassertThat(result.getValue()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.value\", \"bar\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tBindable<JavaBean> target = Bindable.of(JavaBean.class);\n\t\tthis.binder.bind(\"foo\", target, handler);\n\t\tInOrder inOrder = inOrder(handler);\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo.value\")), eq(Bindable.of(String.class)), any(), eq(\"bar\"));\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), isA(JavaBean.class));\n\t}\n\n\t@Test\n\tvoid bindWhenHasCustomDefaultHandlerShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.value\", \"bar\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tBinder binder = new Binder(this.sources, null, null, null, handler);\n\t\tBindable<JavaBean> target = Bindable.of(JavaBean.class);\n\t\tbinder.bind(\"foo\", target);\n\t\tInOrder inOrder = inOrder(handler);\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo.value\")), eq(Bindable.of(String.class)), any(), eq(\"bar\"));\n\t\tinOrder.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), isA(JavaBean.class));\n\t}\n\n\t@Test\n\tvoid bindWhenHasMalformedDateShouldThrowException() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"2014-04-01T01:30:00.000-05:00\"));\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(LocalDate.class)))\n\t\t\t.withCauseInstanceOf(ConversionFailedException.class);\n\t}\n\n\t@Test\n\tvoid bindWhenHasAnnotationsShouldChangeConvertedValue() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"2014-04-01T01:30:00.000-05:00\"));\n\t\tDateTimeFormat annotation = AnnotationUtils.synthesizeAnnotation(\n\t\t\t\tCollections.singletonMap(\"iso\", DateTimeFormat.ISO.DATE_TIME), DateTimeFormat.class, null);\n\t\tLocalDate result = this.binder.bind(\"foo\", Bindable.of(LocalDate.class).withAnnotations(annotation)).get();\n\t\tassertThat(result).hasToString(\"2014-04-01\");\n\t}\n\n\t@Test\n\tvoid bindToValidatedBeanWithResourceAndNonEnumerablePropertySource() {\n\t\tConfigurationPropertySources.from(new PropertySource<String>(\"test\") {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}).forEach(this.sources::add);\n\t\tValidator validator = new SpringValidatorAdapter(\n\t\t\t\tValidation.byDefaultProvider().configure().buildValidatorFactory().getValidator());\n\t\tthis.binder.bind(\"foo\", Bindable.of(ResourceBean.class), new ValidationBindHandler(validator));\n\t}\n\n\t@Test\n\tvoid bindToBeanWithCycle() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source.nonIterable());\n\t\tBindable<CycleBean1> target = Bindable.of(CycleBean1.class);\n\t\tthis.binder.bind(\"foo\", target);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid bindToBeanWithUnresolvableGenerics() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"hello\");\n\t\tthis.sources.add(source);\n\t\tBindable<GenericBean> target = Bindable.of(GenericBean.class);\n\t\tthis.binder.bind(\"foo\", target);\n\t}\n\n\t@Test\n\tvoid bindWithEmptyPrefixShouldIgnorePropertiesWithEmptyName() {\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"value\", \"hello\");\n\t\tsource.put(\"\", \"bar\");\n\t\tIterable<@Nullable ConfigurationPropertySource> propertySources = ConfigurationPropertySources\n\t\t\t.from(new MapPropertySource(\"test\", source));\n\t\tpropertySources.forEach(this.sources::add);\n\t\tBindable<JavaBean> target = Bindable.of(JavaBean.class);\n\t\tJavaBean result = this.binder.bind(\"\", target).get();\n\t\tassertThat(result.getValue()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid bindOrCreateWhenBindSuccessfulShouldReturnBoundValue() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.value\", \"bar\"));\n\t\tJavaBean result = this.binder.bindOrCreate(\"foo\", Bindable.of(JavaBean.class));\n\t\tassertThat(result.getValue()).isEqualTo(\"bar\");\n\t\tassertThat(result.getItems()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindOrCreateWhenUnboundShouldReturnCreatedValue() {\n\t\tJavaBean value = this.binder.bindOrCreate(\"foo\", Bindable.of(JavaBean.class));\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value).isInstanceOf(JavaBean.class);\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanWhenHandlerOnStartReturnsNullShouldReturnUnbound() { // gh-18129\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.value\", \"bar\"));\n\t\tBindResult<JavaBean> result = this.binder.bind(\"foo\", Bindable.of(JavaBean.class), new BindHandler() {\n\n\t\t\t@Override\n\t\t\tpublic <T> @Nullable Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target,\n\t\t\t\t\tBindContext context) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t});\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanWithPublicConstructor() {\n\t\tBindable<JavaBeanWithPublicConstructor> bindable = Bindable.of(JavaBeanWithPublicConstructor.class);\n\t\tJavaBeanWithPublicConstructor result = bindToJavaBeanWithPublicConstructor(bindable);\n\t\tassertThat(result.getValue()).isEqualTo(\"constructor\");\n\t}\n\n\t@Test\n\tvoid bindToJavaBeanWithPublicConstructorWhenHasBindRestriction() {\n\t\tBindable<JavaBeanWithPublicConstructor> bindable = Bindable.of(JavaBeanWithPublicConstructor.class)\n\t\t\t.withBindRestrictions(BindRestriction.NO_DIRECT_PROPERTY);\n\t\tJavaBeanWithPublicConstructor result = bindToJavaBeanWithPublicConstructor(bindable);\n\t\tassertThat(result.getValue()).isEqualTo(\"setter\");\n\t}\n\n\tprivate JavaBeanWithPublicConstructor bindToJavaBeanWithPublicConstructor(\n\t\t\tBindable<JavaBeanWithPublicConstructor> bindable) {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"constructor\");\n\t\tsource.put(\"foo.value\", \"setter\");\n\t\tthis.sources.add(source);\n\t\treturn this.binder.bindOrCreate(\"foo\", bindable);\n\t}\n\n\tprivate BindHandler mockBindHandler() {\n\t\tBindHandler handler = mock(BindHandler.class);\n\t\tgiven(handler.onStart(any(), any(), any())).willAnswer(InvocationArgument.index(1));\n\t\tgiven(handler.onCreate(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));\n\t\tgiven(handler.onSuccess(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));\n\t\treturn handler;\n\t}\n\n\tstatic class JavaBean {\n\n\t\tprivate @Nullable String value;\n\n\t\tprivate final List<String> items = Collections.emptyList();\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tList<String> getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t}\n\n\tstatic class NestedJavaBean {\n\n\t\tprivate DefaultValuesBean valuesBean = new DefaultValuesBean();\n\n\t\tDefaultValuesBean getValuesBean() {\n\t\t\treturn this.valuesBean;\n\t\t}\n\n\t\tvoid setValuesBean(DefaultValuesBean valuesBean) {\n\t\t\tthis.valuesBean = valuesBean;\n\t\t}\n\n\t}\n\n\tstatic class DefaultValuesBean {\n\n\t\tprivate String value = \"hello\";\n\n\t\tprivate final List<String> items = Collections.emptyList();\n\n\t\tString getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tList<String> getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t}\n\n\tpublic enum ExampleEnum {\n\n\t\tFOO_BAR, BAR_BAZ, BAZ_BOO\n\n\t}\n\n\t@Validated\n\tstatic class ResourceBean {\n\n\t\tprivate @Nullable Resource resource;\n\n\t\t@Nullable Resource getResource() {\n\t\t\treturn this.resource;\n\t\t}\n\n\t\tvoid setResource(@Nullable Resource resource) {\n\t\t\tthis.resource = resource;\n\t\t}\n\n\t}\n\n\tstatic class CycleBean1 {\n\n\t\tprivate @Nullable CycleBean2 two;\n\n\t\t@Nullable CycleBean2 getTwo() {\n\t\t\treturn this.two;\n\t\t}\n\n\t\tvoid setTwo(@Nullable CycleBean2 two) {\n\t\t\tthis.two = two;\n\t\t}\n\n\t}\n\n\tstatic class CycleBean2 {\n\n\t\tprivate @Nullable CycleBean1 one;\n\n\t\t@Nullable CycleBean1 getOne() {\n\t\t\treturn this.one;\n\t\t}\n\n\t\tvoid setOne(@Nullable CycleBean1 one) {\n\t\t\tthis.one = one;\n\t\t}\n\n\t}\n\n\tstatic class GenericBean<T> {\n\n\t\tprivate @Nullable T bar;\n\n\t\t@Nullable T getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tvoid setBar(@Nullable T bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t}\n\n\tstatic class JavaBeanPropertyEditor extends PropertyEditorSupport {\n\n\t\t@Override\n\t\tpublic void setAsText(String text) {\n\t\t\tJavaBean value = new JavaBean();\n\t\t\tvalue.setValue(text);\n\t\t\tsetValue(value);\n\t\t}\n\n\t}\n\n\tprivate static final class InvocationArgument<T> implements Answer<T> {\n\n\t\tprivate final int index;\n\n\t\tprivate InvocationArgument(int index) {\n\t\t\tthis.index = index;\n\t\t}\n\n\t\t@Override\n\t\tpublic T answer(InvocationOnMock invocation) throws Throwable {\n\t\t\treturn invocation.getArgument(this.index);\n\t\t}\n\n\t\tprivate static <T> InvocationArgument<T> index(int index) {\n\t\t\treturn new InvocationArgument<>(index);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BoundPropertiesTrackingBindHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link BoundPropertiesTrackingBindHandler}.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass BoundPropertiesTrackingBindHandlerTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate BoundPropertiesTrackingBindHandler handler;\n\n\tprivate Binder binder;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Consumer<ConfigurationProperty> consumer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.binder = new Binder(this.sources);\n\t\tthis.handler = new BoundPropertiesTrackingBindHandler(this.consumer);\n\t}\n\n\t@Test\n\tvoid handlerShouldCallRecordBindingIfConfigurationPropertyIsNotNull() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.age\", 4));\n\t\tthis.binder.bind(\"foo\", Bindable.of(ExampleBean.class), this.handler);\n\t\tthen(this.consumer).should().accept(any(ConfigurationProperty.class));\n\t\tthen(this.consumer).should(never()).accept(null);\n\t}\n\n\tstatic class ExampleBean {\n\n\t\tprivate int age;\n\n\t\tint getAge() {\n\t\t\treturn this.age;\n\t\t}\n\n\t\tvoid setAge(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/CollectionBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BinderTests.ExampleEnum;\nimport org.springframework.boot.context.properties.bind.BinderTests.JavaBean;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link CollectionBinder}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass CollectionBinderTests {\n\n\tprivate static final Bindable<List<Integer>> INTEGER_LIST = Bindable.listOf(Integer.class);\n\n\tprivate static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);\n\n\tprivate static final Bindable<Set<String>> STRING_SET = Bindable.setOf(String.class);\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate Binder binder = new Binder(this.sources);\n\n\t@Test\n\tvoid bindToCollectionShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToSetShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"a\");\n\t\tsource.put(\"foo[1]\", \"b\");\n\t\tsource.put(\"foo[2]\", \"c\");\n\t\tthis.sources.add(source);\n\t\tSet<String> result = this.binder.bind(\"foo\", STRING_SET).get();\n\t\tassertThat(result).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenNestedShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0][0]\", \"1\");\n\t\tsource.put(\"foo[0][1]\", \"2\");\n\t\tsource.put(\"foo[1][0]\", \"3\");\n\t\tsource.put(\"foo[1][1]\", \"4\");\n\t\tthis.sources.add(source);\n\t\tBindable<List<List<Integer>>> target = Bindable\n\t\t\t.of(ResolvableType.forClassWithGenerics(List.class, INTEGER_LIST.getType()));\n\t\tList<List<Integer>> result = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(result).hasSize(2);\n\t\tassertThat(result.get(0)).containsExactly(1, 2);\n\t\tassertThat(result.get(1)).containsExactly(3, 4);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenNotInOrderShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenNonSequentialShouldThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"2\");\n\t\tsource.put(\"foo[1]\", \"1\");\n\t\tsource.put(\"foo[3]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind(\"foo\", INTEGER_LIST))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tThrowable cause = ex.getCause();\n\t\t\t\tassertThat(cause).isNotNull();\n\t\t\t\tSet<ConfigurationProperty> unbound = ((UnboundConfigurationPropertiesException) cause)\n\t\t\t\t\t.getUnboundProperties();\n\t\t\t\tassertThat(unbound).singleElement().satisfies((property) -> {\n\t\t\t\t\tassertThat(property.getName()).hasToString(\"foo[3]\");\n\t\t\t\t\tassertThat(property.getValue()).isEqualTo(\"3\");\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenNonKnownIndexedChildNotBoundThrowsException() {\n\t\t// gh-45994\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0].first\", \"Spring\");\n\t\tsource.put(\"foo[0].last\", \"Boot\");\n\t\tsource.put(\"foo[1].missing\", \"bad\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.listOf(Name.class)))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tThrowable cause = ex.getCause();\n\t\t\t\tassertThat(cause).isNotNull();\n\t\t\t\tSet<ConfigurationProperty> unbound = ((UnboundConfigurationPropertiesException) cause)\n\t\t\t\t\t.getUnboundProperties();\n\t\t\t\tassertThat(unbound).singleElement().satisfies((property) -> {\n\t\t\t\t\tassertThat(property.getName()).hasToString(\"foo[1].missing\");\n\t\t\t\t\tassertThat(property.getValue()).isEqualTo(\"bad\");\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid bindToNestedCollectionWhenNonKnownIndexed() {\n\t\t// gh-46039\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0].items[0]\", \"a\");\n\t\tsource.put(\"foo[0].items[1]\", \"b\");\n\t\tsource.put(\"foo[0].string\", \"test\");\n\t\tthis.sources.add(source);\n\t\tList<ExampleCollectionBean> list = this.binder.bind(\"foo\", Bindable.listOf(ExampleCollectionBean.class)).get();\n\t\tassertThat(list).singleElement().satisfies((bean) -> {\n\t\t\tassertThat(bean.getItems()).containsExactly(\"a\", \"b\", \"d\");\n\t\t\tassertThat(bean.getString()).isEqualTo(\"test\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid bindToNonScalarCollectionWhenNonSequentialShouldThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0].value\", \"1\");\n\t\tsource.put(\"foo[1].value\", \"2\");\n\t\tsource.put(\"foo[4].value\", \"4\");\n\t\tthis.sources.add(source);\n\t\tBindable<List<JavaBean>> target = Bindable.listOf(JavaBean.class);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind(\"foo\", target))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tThrowable cause = ex.getCause();\n\t\t\t\tassertThat(cause).isNotNull();\n\t\t\t\tSet<ConfigurationProperty> unbound = ((UnboundConfigurationPropertiesException) cause)\n\t\t\t\t\t.getUnboundProperties();\n\t\t\t\tassertThat(unbound).singleElement().satisfies((property) -> {\n\t\t\t\t\tassertThat(property.getName()).hasToString(\"foo[4].value\");\n\t\t\t\t\tassertThat(property.getValue()).isEqualTo(\"4\");\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenNonIterableShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[2]\", \"3\");\n\t\tthis.sources.add(source.nonIterable());\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenMultipleSourceShouldOnlyUseFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"bar\", \"baz\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo[0]\", \"1\");\n\t\tsource2.put(\"foo[1]\", \"2\");\n\t\tthis.sources.add(source2);\n\t\tMockConfigurationPropertySource source3 = new MockConfigurationPropertySource();\n\t\tsource3.put(\"foo[0]\", \"7\");\n\t\tsource3.put(\"foo[1]\", \"8\");\n\t\tsource3.put(\"foo[2]\", \"9\");\n\t\tthis.sources.add(source3);\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenHasExistingCollectionShouldReplaceAllContents() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo[0]\", \"1\"));\n\t\tList<Integer> existing = new LinkedList<>();\n\t\texisting.add(1000);\n\t\texisting.add(1001);\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST.withExistingValue(existing)).get();\n\t\tassertThat(result).isExactlyInstanceOf(LinkedList.class);\n\t\tassertThat(result).containsExactly(1);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenHasExistingCollectionButNoValueShouldReturnUnbound() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"faf[0]\", \"1\"));\n\t\tList<Integer> existing = new LinkedList<>();\n\t\texisting.add(1000);\n\t\tBindResult<List<Integer>> result = this.binder.bind(\"foo\", INTEGER_LIST.withExistingValue(existing));\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToCollectionShouldRespectCollectionType() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo[0]\", \"1\"));\n\t\tResolvableType type = ResolvableType.forClassWithGenerics(LinkedList.class, Integer.class);\n\t\tObject defaultList = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tObject customList = this.binder.bind(\"foo\", Bindable.of(type)).get();\n\t\tassertThat(customList).isExactlyInstanceOf(LinkedList.class).isNotInstanceOf(defaultList.getClass());\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenNoValueShouldReturnUnbound() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"faf.bar\", \"1\"));\n\t\tBindResult<List<Integer>> result = this.binder.bind(\"foo\", INTEGER_LIST);\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenCommaListShouldReturnPopulatedCollection() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"1,2,3\"));\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenCommaListWithPlaceholdersShouldReturnPopulatedCollection() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, \"bar=1,2,3\");\n\t\tthis.binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment));\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"${bar}\"));\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2, 3);\n\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenCommaListAndIndexedShouldOnlyUseFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"foo\", \"1,2\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo[0]\", \"2\");\n\t\tsource2.put(\"foo[1]\", \"3\");\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenIndexedAndCommaListShouldOnlyUseFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"foo[0]\", \"1\");\n\t\tsource1.put(\"foo[1]\", \"2\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo\", \"2,3\");\n\t\tList<Integer> result = this.binder.bind(\"foo\", INTEGER_LIST).get();\n\t\tassertThat(result).containsExactly(1, 2);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenItemContainsCommasShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"1,2\");\n\t\tsource.put(\"foo[1]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tList<String> result = this.binder.bind(\"foo\", STRING_LIST).get();\n\t\tassertThat(result).containsExactly(\"1,2\", \"3\");\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenEmptyStringShouldReturnEmptyCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"\");\n\t\tthis.sources.add(source);\n\t\tList<String> result = this.binder.bind(\"foo\", STRING_LIST).get();\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindToNonScalarCollectionShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0].value\", \"a\");\n\t\tsource.put(\"foo[1].value\", \"b\");\n\t\tsource.put(\"foo[2].value\", \"c\");\n\t\tthis.sources.add(source);\n\t\tBindable<List<JavaBean>> target = Bindable.listOf(JavaBean.class);\n\t\tList<JavaBean> result = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(result).hasSize(3);\n\t\tList<String> values = result.stream().map(JavaBean::getValue).toList();\n\t\tassertThat(values).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToImmutableCollectionShouldReturnPopulatedCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.values\", \"a,b,c\");\n\t\tthis.sources.add(source);\n\t\tSet<String> result = this.binder.bind(\"foo.values\", STRING_SET.withExistingValue(Collections.emptySet())).get();\n\t\tassertThat(result).hasSize(3);\n\t}\n\n\t@Test\n\tvoid bindToCollectionShouldAlsoCallSetterIfPresent() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items\", \"a,b,c\");\n\t\tthis.sources.add(source);\n\t\tExampleCollectionBean result = this.binder.bind(\"foo\", ExampleCollectionBean.class).get();\n\t\tassertThat(result.getItems()).hasSize(4);\n\t\tassertThat(result.getItems()).containsExactly(\"a\", \"b\", \"c\", \"d\");\n\t}\n\n\t@Test\n\tvoid bindToCollectionWithNoDefaultConstructor() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items\", \"a,b,c,c\");\n\t\tthis.sources.add(source);\n\t\tExampleCustomNoDefaultConstructorBean result = this.binder\n\t\t\t.bind(\"foo\", ExampleCustomNoDefaultConstructorBean.class)\n\t\t\t.get();\n\t\tassertThat(result.getItems()).hasSize(4);\n\t\tassertThat(result.getItems()).containsExactly(\"a\", \"b\", \"c\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToCollectionWithDefaultConstructor() {\n\t\t// gh-12322\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items\", \"a,b,c,c\");\n\t\tthis.sources.add(source);\n\t\tExampleCustomWithDefaultConstructorBean result = this.binder\n\t\t\t.bind(\"foo\", ExampleCustomWithDefaultConstructorBean.class)\n\t\t\t.get();\n\t\tassertThat(result.getItems()).hasSize(4);\n\t\tassertThat(result.getItems()).containsExactly(\"a\", \"b\", \"c\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToListShouldAllowDuplicateValues() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items\", \"a,b,c,c\");\n\t\tthis.sources.add(source);\n\t\tExampleCollectionBean result = this.binder.bind(\"foo\", ExampleCollectionBean.class).get();\n\t\tassertThat(result.getItems()).hasSize(5);\n\t\tassertThat(result.getItems()).containsExactly(\"a\", \"b\", \"c\", \"c\", \"d\");\n\t}\n\n\t@Test\n\tvoid bindToSetShouldNotAllowDuplicateValues() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items-set\", \"a,b,c,c\");\n\t\tthis.sources.add(source);\n\t\tExampleCollectionBean result = this.binder.bind(\"foo\", ExampleCollectionBean.class).get();\n\t\tassertThat(result.getItemsSet()).hasSize(3);\n\t\tassertThat(result.getItemsSet()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToBeanWithNestedCollectionShouldPopulateCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"one\");\n\t\tsource.put(\"foo.foos[0].value\", \"two\");\n\t\tsource.put(\"foo.foos[1].value\", \"three\");\n\t\tthis.sources.add(source);\n\t\tBindable<BeanWithNestedCollection> target = Bindable.of(BeanWithNestedCollection.class);\n\t\tBeanWithNestedCollection foo = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(foo.getValue()).isEqualTo(\"one\");\n\t\tList<BeanWithNestedCollection> foos = foo.getFoos();\n\t\tassertThat(foos).isNotNull();\n\t\tassertThat(foos.get(0).getValue()).isEqualTo(\"two\");\n\t\tassertThat(foos.get(1).getValue()).isEqualTo(\"three\");\n\t}\n\n\t@Test\n\tvoid bindToNestedCollectionWhenEmptyStringShouldReturnEmptyCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"one\");\n\t\tsource.put(\"foo.foos\", \"\");\n\t\tthis.sources.add(source);\n\t\tBindable<BeanWithNestedCollection> target = Bindable.of(BeanWithNestedCollection.class);\n\t\tBeanWithNestedCollection foo = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(foo.getValue()).isEqualTo(\"one\");\n\t\tassertThat(foo.getFoos()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindToCollectionShouldUsePropertyEditor() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"java.lang.RuntimeException\");\n\t\tsource.put(\"foo[1]\", \"java.lang.IllegalStateException\");\n\t\tthis.sources.add(source);\n\t\tassertThat(this.binder.bind(\"foo\", Bindable.listOf(Class.class)).get()).containsExactly(RuntimeException.class,\n\t\t\t\tIllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid bindToCollectionWhenStringShouldUsePropertyEditor() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"java.lang.RuntimeException,java.lang.IllegalStateException\");\n\t\tthis.sources.add(source);\n\t\tassertThat(this.binder.bind(\"foo\", Bindable.listOf(Class.class)).get()).containsExactly(RuntimeException.class,\n\t\t\t\tIllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid bindToBeanWithNestedCollectionAndNonIterableSourceShouldNotFail() {\n\t\t// gh-10702\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source.nonIterable());\n\t\tBindable<BeanWithNestedCollection> target = Bindable.of(BeanWithNestedCollection.class);\n\t\tthis.binder.bind(\"foo\", target);\n\t}\n\n\t@Test\n\tvoid bindToBeanWithClonedArray() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar[0]\", \"hello\");\n\t\tthis.sources.add(source);\n\t\tBindable<ClonedArrayBean> target = Bindable.of(ClonedArrayBean.class);\n\t\tClonedArrayBean bean = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(bean.getBar()).containsExactly(\"hello\");\n\t}\n\n\t@Test\n\tvoid bindToBeanWithExceptionInGetterForExistingValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.values\", \"a,b,c\");\n\t\tthis.sources.add(source);\n\t\tBeanWithGetterException result = this.binder.bind(\"foo\", Bindable.of(BeanWithGetterException.class)).get();\n\t\tassertThat(result.getValues()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToBeanWithEnumSetCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.values[0]\", \"foo-bar,bar-baz\");\n\t\tthis.sources.add(source);\n\t\tBeanWithEnumSetCollection result = this.binder.bind(\"foo\", Bindable.of(BeanWithEnumSetCollection.class)).get();\n\t\tList<EnumSet<ExampleEnum>> values = result.getValues();\n\t\tassertThat(values).isNotNull();\n\t\tassertThat(values.get(0)).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToWellFormedSystemEnvironmentVariableProperty() {\n\t\t// gh-46184\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"FOO_THENAMES_0_FIRST\", \"spring\");\n\t\tmap.put(\"FOO_THENAMES_0_LAST\", \"boot\");\n\t\tmap.put(\"FOO_THENAMES_1_FIRST\", \"binding\");\n\t\tmap.put(\"FOO_THENAMES_1_LAST\", \"test\");\n\t\tSystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, map);\n\t\tthis.sources.add(ConfigurationPropertySource.from(propertySource));\n\t\tBeanWithCamelCaseNameList result = this.binder.bind(\"foo\", BeanWithCamelCaseNameList.class).get();\n\t\tassertThat(result.theNames()).containsExactly(new Name(\"spring\", \"boot\"), new Name(\"binding\", \"test\"));\n\t}\n\n\t@Test\n\tvoid bindToLegacySystemEnvironmentVariableProperty() {\n\t\t// gh-46184\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"FOO_THE_NAMES_0_FIRST\", \"spring\");\n\t\tmap.put(\"FOO_THE_NAMES_0_LAST\", \"boot\");\n\t\tmap.put(\"FOO_THE_NAMES_1_FIRST\", \"binding\");\n\t\tmap.put(\"FOO_THE_NAMES_1_LAST\", \"test\");\n\t\tSystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, map);\n\t\tthis.sources.add(ConfigurationPropertySource.from(propertySource));\n\t\tBeanWithCamelCaseNameList result = this.binder.bind(\"foo\", BeanWithCamelCaseNameList.class).get();\n\t\tassertThat(result.theNames()).containsExactly(new Name(\"spring\", \"boot\"), new Name(\"binding\", \"test\"));\n\t}\n\n\tstatic class ExampleCollectionBean {\n\n\t\tprivate final List<String> items = new ArrayList<>();\n\n\t\tprivate Set<String> itemsSet = new LinkedHashSet<>();\n\n\t\tprivate @Nullable String string;\n\n\t\tList<String> getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t\tvoid setItems(List<String> items) {\n\t\t\tthis.items.add(\"d\");\n\t\t}\n\n\t\tSet<String> getItemsSet() {\n\t\t\treturn this.itemsSet;\n\t\t}\n\n\t\tvoid setItemsSet(Set<String> itemsSet) {\n\t\t\tthis.itemsSet = itemsSet;\n\t\t}\n\n\t\t@Nullable String getString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t\tvoid setString(@Nullable String string) {\n\t\t\tthis.string = string;\n\t\t}\n\n\t}\n\n\tstatic class ExampleCustomNoDefaultConstructorBean {\n\n\t\tprivate MyCustomNoDefaultConstructorList items = new MyCustomNoDefaultConstructorList(\n\t\t\t\tCollections.singletonList(\"foo\"));\n\n\t\tMyCustomNoDefaultConstructorList getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t\tvoid setItems(MyCustomNoDefaultConstructorList items) {\n\t\t\tthis.items = items;\n\t\t}\n\n\t}\n\n\tstatic class MyCustomNoDefaultConstructorList extends ArrayList<String> {\n\n\t\tMyCustomNoDefaultConstructorList(List<String> items) {\n\t\t\taddAll(items);\n\t\t}\n\n\t}\n\n\tstatic class ExampleCustomWithDefaultConstructorBean {\n\n\t\tprivate final MyCustomWithDefaultConstructorList items = new MyCustomWithDefaultConstructorList();\n\n\t\tMyCustomWithDefaultConstructorList getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t\tvoid setItems(MyCustomWithDefaultConstructorList items) {\n\t\t\tthis.items.clear();\n\t\t\tthis.items.addAll(items);\n\t\t}\n\n\t}\n\n\tstatic class MyCustomWithDefaultConstructorList extends ArrayList<String> {\n\n\t}\n\n\tstatic class BeanWithNestedCollection {\n\n\t\tprivate @Nullable String value;\n\n\t\tprivate @Nullable List<BeanWithNestedCollection> foos;\n\n\t\t@Nullable List<BeanWithNestedCollection> getFoos() {\n\t\t\treturn this.foos;\n\t\t}\n\n\t\tvoid setFoos(@Nullable List<BeanWithNestedCollection> foos) {\n\t\t\tthis.foos = foos;\n\t\t}\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class ClonedArrayBean {\n\n\t\tprivate String @Nullable [] bar;\n\n\t\tString @Nullable [] getBar() {\n\t\t\treturn (this.bar != null) ? this.bar.clone() : null;\n\t\t}\n\n\t\tvoid setBar(String @Nullable [] bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t}\n\n\tstatic class BeanWithGetterException {\n\n\t\tprivate @Nullable List<String> values;\n\n\t\tvoid setValues(@Nullable List<String> values) {\n\t\t\tthis.values = values;\n\t\t}\n\n\t\t@Nullable List<String> getValues() {\n\t\t\treturn Collections.unmodifiableList(this.values);\n\t\t}\n\n\t}\n\n\tstatic class BeanWithEnumSetCollection {\n\n\t\tprivate @Nullable List<EnumSet<ExampleEnum>> values;\n\n\t\tvoid setValues(@Nullable List<EnumSet<ExampleEnum>> values) {\n\t\t\tthis.values = values;\n\t\t}\n\n\t\t@Nullable List<EnumSet<ExampleEnum>> getValues() {\n\t\t\treturn this.values;\n\t\t}\n\n\t}\n\n\trecord BeanWithCamelCaseNameList(List<Name> theNames) {\n\n\t}\n\n\trecord Name(String first, String last) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/DataObjectPropertyNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataObjectPropertyName}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass DataObjectPropertyNameTests {\n\n\t@Test\n\tvoid toDashedCaseConvertsValue() {\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"Foo\")).isEqualTo(\"foo\");\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"foo\")).isEqualTo(\"foo\");\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"fooBar\")).isEqualTo(\"foo-bar\");\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"foo_bar\")).isEqualTo(\"foo-bar\");\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"_foo_bar\")).isEqualTo(\"-foo-bar\");\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"foo_Bar\")).isEqualTo(\"foo-bar\");\n\t}\n\n\t@Test\n\tvoid toDashedFormWhenContainsIndexedAddsNoDashToIndex() {\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"test[fooBar]\")).isEqualTo(\"test[fooBar]\");\n\t\tassertThat(DataObjectPropertyName.toDashedForm(\"testAgain[fooBar]\")).isEqualTo(\"test-again[fooBar]\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/DefaultBindConstructorProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Constructor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link DefaultBindConstructorProvider}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Yanming Zhou\n */\nclass DefaultBindConstructorProviderTests {\n\n\tprivate final DefaultBindConstructorProvider provider = new DefaultBindConstructorProvider();\n\n\t@Test\n\tvoid getBindConstructorWhenHasOnlyDefaultConstructorReturnsNull() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(OnlyDefaultConstructor.class, false);\n\t\tassertThat(constructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasMultipleAmbiguousConstructorsReturnsNull() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(MultipleAmbiguousConstructors.class, false);\n\t\tassertThat(constructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasTwoConstructorsWithOneConstructorBindingReturnsConstructor() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(TwoConstructorsWithOneConstructorBinding.class,\n\t\t\t\tfalse);\n\t\tassertThat(constructor).isNotNull();\n\t\tassertThat(constructor.getParameterCount()).isOne();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasOneConstructorWithAutowiredReturnsNull() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(OneConstructorWithAutowired.class, false);\n\t\tassertThat(constructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasTwoConstructorsWithOneAutowiredReturnsNull() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(TwoConstructorsWithOneAutowired.class, false);\n\t\tassertThat(constructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasTwoConstructorsWithOneAutowiredAndOneConstructorBindingThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.provider\n\t\t\t\t.getBindConstructor(TwoConstructorsWithOneAutowiredAndOneConstructorBinding.class, false))\n\t\t\t.withMessageContaining(\"declares @ConstructorBinding and @Autowired\");\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasOneConstructorWithConstructorBindingReturnsConstructor() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(OneConstructorWithConstructorBinding.class,\n\t\t\t\tfalse);\n\t\tassertThat(constructor).isNotNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasTwoConstructorsWithBothConstructorBindingThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.provider.getBindConstructor(TwoConstructorsWithBothConstructorBinding.class, false))\n\t\t\t.withMessageContaining(\"has more than one @ConstructorBinding\");\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenIsTypeWithPrivateConstructorReturnsNull() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(TypeWithPrivateConstructor.class, false);\n\t\tassertThat(constructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenIsMemberTypeWithPrivateConstructorReturnsNull() {\n\t\tConstructor<?> constructor = this.provider.getBindConstructor(MemberTypeWithPrivateConstructor.Member.class,\n\t\t\t\tfalse);\n\t\tassertThat(constructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorFromProxiedClassWithOneAutowiredConstructorReturnsNull() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tProxiedWithOneConstructorWithAutowired.class)) {\n\t\t\tProxiedWithOneConstructorWithAutowired bean = context.getBean(ProxiedWithOneConstructorWithAutowired.class);\n\t\t\tConstructor<?> bindConstructor = this.provider.getBindConstructor(bean.getClass(), false);\n\t\t\tassertThat(bindConstructor).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasExistingValueAndOneConstructorWithoutAnnotationsReturnsNull() {\n\t\tOneConstructorWithoutAnnotations existingValue = new OneConstructorWithoutAnnotations(\"name\", 123);\n\t\tBindable<?> bindable = Bindable.of(OneConstructorWithoutAnnotations.class).withExistingValue(existingValue);\n\t\tConstructor<?> bindConstructor = this.provider.getBindConstructor(bindable, false);\n\t\tassertThat(bindConstructor).isNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasExistingValueAndOneConstructorWithConstructorBindingReturnsConstructor() {\n\t\tOneConstructorWithConstructorBinding existingValue = new OneConstructorWithConstructorBinding(\"name\", 123);\n\t\tBindable<?> bindable = Bindable.of(OneConstructorWithConstructorBinding.class).withExistingValue(existingValue);\n\t\tConstructor<?> bindConstructor = this.provider.getBindConstructor(bindable, false);\n\t\tassertThat(bindConstructor).isNotNull();\n\t}\n\n\t@Test\n\tvoid getBindConstructorWhenHasExistingValueAndValueIsRecordReturnsConstructor() {\n\t\tOneConstructorOnRecord existingValue = new OneConstructorOnRecord(\"name\", 123);\n\t\tBindable<?> bindable = Bindable.of(OneConstructorOnRecord.class).withExistingValue(existingValue);\n\t\tConstructor<?> bindConstructor = this.provider.getBindConstructor(bindable, false);\n\t\tassertThat(bindConstructor).isNotNull();\n\t}\n\n\tstatic class OnlyDefaultConstructor {\n\n\t}\n\n\tstatic class MultipleAmbiguousConstructors {\n\n\t\tMultipleAmbiguousConstructors() {\n\t\t}\n\n\t\tMultipleAmbiguousConstructors(String name) {\n\t\t}\n\n\t}\n\n\tstatic class TwoConstructorsWithOneConstructorBinding {\n\n\t\t@ConstructorBinding\n\t\tTwoConstructorsWithOneConstructorBinding(String name) {\n\t\t\tthis(name, 100);\n\t\t}\n\n\t\tTwoConstructorsWithOneConstructorBinding(String name, int age) {\n\t\t}\n\n\t}\n\n\tstatic class OneConstructorWithAutowired {\n\n\t\t@Autowired\n\t\tOneConstructorWithAutowired(String name, int age) {\n\t\t}\n\n\t}\n\n\tstatic class TwoConstructorsWithOneAutowired {\n\n\t\t@Autowired\n\t\tTwoConstructorsWithOneAutowired(String name) {\n\t\t\tthis(name, 100);\n\t\t}\n\n\t\tTwoConstructorsWithOneAutowired(String name, int age) {\n\t\t}\n\n\t}\n\n\tstatic class TwoConstructorsWithOneAutowiredAndOneConstructorBinding {\n\n\t\t@Autowired\n\t\tTwoConstructorsWithOneAutowiredAndOneConstructorBinding(String name) {\n\t\t\tthis(name, 100);\n\t\t}\n\n\t\t@ConstructorBinding\n\t\tTwoConstructorsWithOneAutowiredAndOneConstructorBinding(String name, int age) {\n\t\t}\n\n\t}\n\n\tstatic class OneConstructorWithConstructorBinding {\n\n\t\t@ConstructorBinding\n\t\tOneConstructorWithConstructorBinding(String name, int age) {\n\t\t}\n\n\t}\n\n\tstatic class OneConstructorWithoutAnnotations {\n\n\t\tOneConstructorWithoutAnnotations(String name, int age) {\n\t\t}\n\n\t}\n\n\trecord OneConstructorOnRecord(String name, int age) {\n\n\t}\n\n\tstatic class TwoConstructorsWithBothConstructorBinding {\n\n\t\t@ConstructorBinding\n\t\tTwoConstructorsWithBothConstructorBinding(String name) {\n\t\t\tthis(name, 100);\n\t\t}\n\n\t\t@ConstructorBinding\n\t\tTwoConstructorsWithBothConstructorBinding(String name, int age) {\n\t\t}\n\n\t}\n\n\tstatic final class TypeWithPrivateConstructor {\n\n\t\tprivate TypeWithPrivateConstructor(Environment environment) {\n\t\t}\n\n\t}\n\n\tstatic class MemberTypeWithPrivateConstructor {\n\n\t\tstatic final class Member {\n\n\t\t\tprivate Member(String name) {\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class ProxiedWithOneConstructorWithAutowired {\n\n\t\t@Autowired\n\t\tProxiedWithOneConstructorWithAutowired(Environment environment) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.time.LocalDate;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.JavaBeanBinder.Bean;\nimport org.springframework.boot.context.properties.bind.JavaBeanBinder.BeanProperty;\nimport org.springframework.boot.context.properties.bind.handler.IgnoreErrorsBindHandler;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.convert.Delimiter;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.format.annotation.DateTimeFormat;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link JavaBeanBinder}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @author Lasse Wulff\n */\nclass JavaBeanBinderTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate final Binder binder = new Binder(this.sources);\n\n\t@Test\n\tvoid bindToClassShouldCreateBoundBean() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tsource.put(\"foo.long-value\", \"34\");\n\t\tsource.put(\"foo.string-value\", \"foo\");\n\t\tsource.put(\"foo.enum-value\", \"foo-bar\");\n\t\tthis.sources.add(source);\n\t\tExampleValueBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleValueBean.class)).get();\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);\n\t}\n\n\t@Test\n\tvoid bindRenamedPropertyToClassBean() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"renamed.public\", \"alpha\");\n\t\tthis.sources.add(source);\n\t\tExampleRenamedPropertyBean bean = this.binder.bind(\"renamed\", Bindable.of(ExampleRenamedPropertyBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getExampleProperty()).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoPrefixShouldCreateBoundBean() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"int-value\", \"12\");\n\t\tsource.put(\"long-value\", \"34\");\n\t\tsource.put(\"string-value\", \"foo\");\n\t\tsource.put(\"enum-value\", \"foo-bar\");\n\t\tthis.sources.add(source);\n\t\tExampleValueBean bean = this.binder.bind(ConfigurationPropertyName.of(\"\"), Bindable.of(ExampleValueBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);\n\t}\n\n\t@Test\n\tvoid bindToInstanceShouldBindToInstance() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tsource.put(\"foo.long-value\", \"34\");\n\t\tsource.put(\"foo.string-value\", \"foo\");\n\t\tsource.put(\"foo.enum-value\", \"foo-bar\");\n\t\tthis.sources.add(source);\n\t\tExampleValueBean bean = new ExampleValueBean();\n\t\tExampleValueBean boundBean = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(ExampleValueBean.class).withExistingValue(bean))\n\t\t\t.get();\n\t\tassertThat(boundBean).isSameAs(bean);\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);\n\t}\n\n\t@Test\n\tvoid bindToInstanceWithNoPropertiesShouldReturnUnbound() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source);\n\t\tExampleDefaultsBean bean = new ExampleDefaultsBean();\n\t\tBindResult<ExampleDefaultsBean> boundBean = this.binder.bind(\"foo\",\n\t\t\t\tBindable.of(ExampleDefaultsBean.class).withExistingValue(bean));\n\t\tassertThat(boundBean.isBound()).isFalse();\n\t\tassertThat(bean.getFoo()).isEqualTo(123);\n\t\tassertThat(bean.getBar()).isEqualTo(456);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldLeaveDefaults() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"999\");\n\t\tthis.sources.add(source);\n\t\tExampleDefaultsBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleDefaultsBean.class)).get();\n\t\tassertThat(bean.getFoo()).isEqualTo(123);\n\t\tassertThat(bean.getBar()).isEqualTo(999);\n\t}\n\n\t@Test\n\tvoid bindToExistingInstanceShouldLeaveDefaults() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"999\");\n\t\tthis.sources.add(source);\n\t\tExampleDefaultsBean bean = new ExampleDefaultsBean();\n\t\tbean.setFoo(888);\n\t\tExampleDefaultsBean boundBean = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(ExampleDefaultsBean.class).withExistingValue(bean))\n\t\t\t.get();\n\t\tassertThat(boundBean).isSameAs(bean);\n\t\tassertThat(bean.getFoo()).isEqualTo(888);\n\t\tassertThat(bean.getBar()).isEqualTo(999);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindToMap() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.map.foo-bar\", \"1\");\n\t\tsource.put(\"foo.map.bar-baz\", \"2\");\n\t\tthis.sources.add(source);\n\t\tExampleMapBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleMapBean.class)).get();\n\t\tassertThat(bean.getMap()).containsExactly(entry(ExampleEnum.FOO_BAR, 1), entry(ExampleEnum.BAR_BAZ, 2));\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindToList() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.list[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.list[1]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleListBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleListBean.class)).get();\n\t\tassertThat(bean.getList()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToListIfUnboundElementsPresentShouldThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.list[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.list[2]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleListBean.class)))\n\t\t\t.withCauseInstanceOf(UnboundConfigurationPropertiesException.class);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindToSet() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.set[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.set[1]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleSetBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleSetBean.class)).get();\n\t\tassertThat(bean.getSet()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindToCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.collection[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.collection[1]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleCollectionBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleCollectionBean.class)).get();\n\t\tassertThat(bean.getCollection()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindToCollectionWithDelimiter() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.collection\", \"foo-bar|bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleCollectionBeanWithDelimiter bean = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(ExampleCollectionBeanWithDelimiter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getCollection()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoSetterShouldBindToMap() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.map.foo-bar\", \"1\");\n\t\tsource.put(\"foo.map.bar-baz\", \"2\");\n\t\tthis.sources.add(source);\n\t\tExampleMapBeanWithoutSetter bean = this.binder.bind(\"foo\", Bindable.of(ExampleMapBeanWithoutSetter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getMap()).containsExactly(entry(ExampleEnum.FOO_BAR, 1), entry(ExampleEnum.BAR_BAZ, 2));\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoSetterShouldBindToList() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.list[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.list[1]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleListBeanWithoutSetter bean = this.binder.bind(\"foo\", Bindable.of(ExampleListBeanWithoutSetter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getList()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoSetterShouldBindToSet() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.set[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.set[1]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleSetBeanWithoutSetter bean = this.binder.bind(\"foo\", Bindable.of(ExampleSetBeanWithoutSetter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getSet()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoSetterShouldBindToCollection() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.collection[0]\", \"foo-bar\");\n\t\tsource.put(\"foo.collection[1]\", \"bar-baz\");\n\t\tthis.sources.add(source);\n\t\tExampleCollectionBeanWithoutSetter bean = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(ExampleCollectionBeanWithoutSetter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getCollection()).containsExactly(ExampleEnum.FOO_BAR, ExampleEnum.BAR_BAZ);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindNested() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleNestedBean.class)).get();\n\t\tExampleValueBean valueBean = bean.getValueBean();\n\t\tassertThat(valueBean).isNotNull();\n\t\tassertThat(valueBean.getIntValue()).isEqualTo(123);\n\t\tassertThat(valueBean.getStringValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid bindToClassWhenIterableShouldBindNestedBasedOnInstance() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBeanWithoutSetterOrType bean = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(ExampleNestedBeanWithoutSetterOrType.class))\n\t\t\t.get();\n\t\tExampleValueBean valueBean = (ExampleValueBean) bean.getValueBean();\n\t\tassertThat(valueBean.getIntValue()).isEqualTo(123);\n\t\tassertThat(valueBean.getStringValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid bindToClassWhenNotIterableShouldNotBindNestedBasedOnInstance() {\n\t\t// If we can't tell that binding will happen, we don't want to randomly invoke\n\t\t// getters on the class and cause side effects\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.string-value\", \"foo\");\n\t\tthis.sources.add(source.nonIterable());\n\t\tBindResult<ExampleNestedBeanWithoutSetterOrType> bean = this.binder.bind(\"foo\",\n\t\t\t\tBindable.of(ExampleNestedBeanWithoutSetterOrType.class));\n\t\tassertThat(bean.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoSetterShouldBindNested() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBeanWithoutSetter bean = this.binder.bind(\"foo\", Bindable.of(ExampleNestedBeanWithoutSetter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getValueBean().getIntValue()).isEqualTo(123);\n\t\tassertThat(bean.getValueBean().getStringValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoSetterAndImmutableShouldThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.nested.foo\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleImmutableNestedBeanWithoutSetter.class)));\n\t}\n\n\t@Test\n\tvoid bindToInstanceWhenNoNestedShouldLeaveNestedAsNull() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"faf.value-bean.int-value\", \"123\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBean bean = new ExampleNestedBean();\n\t\tBindResult<ExampleNestedBean> boundBean = this.binder.bind(\"foo\",\n\t\t\t\tBindable.of(ExampleNestedBean.class).withExistingValue(bean));\n\t\tassertThat(boundBean.isBound()).isFalse();\n\t\tassertThat(bean.getValueBean()).isNull();\n\t}\n\n\t@Test\n\tvoid bindToClassWithOverriddenPropertyShouldSetSubclassProperty() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.sub-int-value\", \"456\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedSubclassBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleNestedSubclassBean.class)).get();\n\t\tassertThat(bean.getValueBean()).isNotNull();\n\t\tassertThat(bean.getValueBean().getIntValue()).isEqualTo(123);\n\t\tassertThat(bean.getValueBean().getSubIntValue()).isEqualTo(456);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenPropertiesMissingShouldReturnUnbound() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"faf.int-value\", \"12\");\n\t\tthis.sources.add(source);\n\t\tBindResult<ExampleValueBean> bean = this.binder.bind(\"foo\", Bindable.of(ExampleValueBean.class));\n\t\tassertThat(bean.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenNoDefaultConstructorShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tBindResult<ExampleWithNonDefaultConstructor> bean = this.binder.bind(\"foo\",\n\t\t\t\tBindable.of(ExampleWithNonDefaultConstructor.class));\n\t\tassertThat(bean.isBound()).isTrue();\n\t\tExampleWithNonDefaultConstructor boundBean = bean.get();\n\t\tassertThat(boundBean.getValue()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindToInstanceWhenNoDefaultConstructorShouldBind() {\n\t\tBinder binder = new Binder(this.sources, null, (ConversionService) null, null, null,\n\t\t\t\t(bindable, isNestedConstructorBinding) -> null);\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tExampleWithNonDefaultConstructor bean = new ExampleWithNonDefaultConstructor(\"faf\");\n\t\tExampleWithNonDefaultConstructor boundBean = binder\n\t\t\t.bind(\"foo\", Bindable.of(ExampleWithNonDefaultConstructor.class).withExistingValue(bean))\n\t\t\t.get();\n\t\tassertThat(boundBean).isSameAs(bean);\n\t\tassertThat(bean.getValue()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindHierarchy() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"123\");\n\t\tsource.put(\"foo.long-value\", \"456\");\n\t\tthis.sources.add(source);\n\t\tExampleSubclassBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleSubclassBean.class)).get();\n\t\tassertThat(bean.getIntValue()).isEqualTo(123);\n\t\tassertThat(bean.getLongValue()).isEqualTo(456);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenPropertyCannotBeConvertedShouldThrowException() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.int-value\", \"foo\"));\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleValueBean.class)));\n\t}\n\n\t@Test\n\tvoid bindToClassWhenPropertyCannotBeConvertedAndIgnoreErrorsShouldNotSetValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tsource.put(\"foo.long-value\", \"bang\");\n\t\tsource.put(\"foo.string-value\", \"foo\");\n\t\tsource.put(\"foo.enum-value\", \"foo-bar\");\n\t\tthis.sources.add(source);\n\t\tIgnoreErrorsBindHandler handler = new IgnoreErrorsBindHandler();\n\t\tExampleValueBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleValueBean.class), handler).get();\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getLongValue()).isZero();\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenMismatchedGetSetShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"123\");\n\t\tthis.sources.add(source);\n\t\tExampleMismatchBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleMismatchBean.class)).get();\n\t\tassertThat(bean.getValue()).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid bindToClassShouldNotInvokeExtraMethods() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource(\"foo.value\", \"123\");\n\t\tthis.sources.add(source.nonIterable());\n\t\tExampleWithThrowingGetters bean = this.binder.bind(\"foo\", Bindable.of(ExampleWithThrowingGetters.class)).get();\n\t\tassertThat(bean.getValue()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid bindToClassWithSelfReferenceShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"123\");\n\t\tthis.sources.add(source);\n\t\tExampleWithSelfReference bean = this.binder.bind(\"foo\", Bindable.of(ExampleWithSelfReference.class)).get();\n\t\tassertThat(bean.getValue()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid bindToInstanceWithExistingValueShouldReturnUnbound() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source);\n\t\tExampleNestedBean existingValue = new ExampleNestedBean();\n\t\tExampleValueBean valueBean = new ExampleValueBean();\n\t\texistingValue.setValueBean(valueBean);\n\t\tBindResult<ExampleNestedBean> result = this.binder.bind(\"foo\",\n\t\t\t\tBindable.of(ExampleNestedBean.class).withExistingValue(existingValue));\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindWithAnnotations() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.date\", \"2014-04-01\");\n\t\tthis.sources.add(source);\n\t\tConverterAnnotatedExampleBean bean = this.binder.bind(\"foo\", Bindable.of(ConverterAnnotatedExampleBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getDate()).hasToString(\"2014-04-01\");\n\t}\n\n\t@Test\n\tvoid bindWhenValueIsConvertedWithPropertyEditorShouldBind() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"java.lang.RuntimeException\");\n\t\tthis.sources.add(source);\n\t\tExampleWithPropertyEditorType bean = this.binder.bind(\"foo\", Bindable.of(ExampleWithPropertyEditorType.class))\n\t\t\t.get();\n\t\tassertThat(bean.getValue()).isEqualTo(RuntimeException.class);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldIgnoreInvalidAccessors() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.name\", \"something\");\n\t\tthis.sources.add(source);\n\t\tExampleWithInvalidAccessors bean = this.binder.bind(\"foo\", Bindable.of(ExampleWithInvalidAccessors.class))\n\t\t\t.get();\n\t\tassertThat(bean.getName()).isEqualTo(\"something\");\n\t}\n\n\t@Test\n\tvoid bindToClassShouldIgnoreStaticAccessors() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.name\", \"invalid\");\n\t\tsource.put(\"foo.counter\", \"42\");\n\t\tthis.sources.add(source);\n\t\tExampleWithStaticAccessors bean = this.binder.bind(\"foo\", Bindable.of(ExampleWithStaticAccessors.class)).get();\n\t\tassertThat(ExampleWithStaticAccessors.name).isNull();\n\t\tassertThat(bean.getCounter()).isEqualTo(42);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldCacheWithGenerics() {\n\t\t// gh-16821\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.integers[a].value\", \"1\");\n\t\tsource.put(\"foo.booleans[b].value\", \"true\");\n\t\tthis.sources.add(source);\n\t\tExampleWithGenericMap bean = this.binder.bind(\"foo\", Bindable.of(ExampleWithGenericMap.class)).get();\n\t\tGenericValue<Integer> a = bean.getIntegers().get(\"a\");\n\t\tassertThat(a).isNotNull();\n\t\tassertThat(a.getValue()).isOne();\n\t\tGenericValue<Boolean> b = bean.getBooleans().get(\"b\");\n\t\tassertThat(b).isNotNull();\n\t\tassertThat(b.getValue()).isTrue();\n\t}\n\n\t@Test\n\tvoid bindToClassWithOverloadedSetterShouldUseSetterThatMatchesField() {\n\t\t// gh-16206\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.property\", \"some string\");\n\t\tthis.sources.add(source);\n\t\tPropertyWithOverloadedSetter bean = this.binder.bind(\"foo\", Bindable.of(PropertyWithOverloadedSetter.class))\n\t\t\t.get();\n\t\tassertThat(bean.getProperty()).isEqualTo(\"some string\");\n\t}\n\n\t@Test\n\tvoid beanPropertiesPreferMatchingType() {\n\t\t// gh-16206\n\t\tResolvableType type = ResolvableType.forClass(PropertyWithOverloadedSetter.class);\n\t\tClass<?> resolvedType = type.resolve();\n\t\tassertThat(resolvedType).isNotNull();\n\t\tBean<PropertyWithOverloadedSetter> bean = new Bean<>(type, resolvedType) {\n\n\t\t\t@Override\n\t\t\tprotected void addProperties(Method[] declaredMethods, Field[] declaredFields) {\n\t\t\t\t// We override here because we need a specific order of the declared\n\t\t\t\t// methods and the JVM doesn't give us one\n\t\t\t\tint intSetter = -1;\n\t\t\t\tint stringSetter = -1;\n\t\t\t\tfor (int i = 0; i < declaredMethods.length; i++) {\n\t\t\t\t\tMethod method = declaredMethods[i];\n\t\t\t\t\tif (method.getName().equals(\"setProperty\")) {\n\t\t\t\t\t\tif (method.getParameters()[0].getType().equals(int.class)) {\n\t\t\t\t\t\t\tintSetter = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tstringSetter = i;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (intSetter > stringSetter) {\n\t\t\t\t\tMethod method = declaredMethods[intSetter];\n\t\t\t\t\tdeclaredMethods[intSetter] = declaredMethods[stringSetter];\n\t\t\t\t\tdeclaredMethods[stringSetter] = method;\n\t\t\t\t}\n\t\t\t\tsuper.addProperties(declaredMethods, declaredFields);\n\t\t\t}\n\n\t\t};\n\t\tBeanProperty property = bean.getProperties().get(\"property\");\n\t\tassertThat(property).isNotNull();\n\t\tPropertyWithOverloadedSetter target = new PropertyWithOverloadedSetter();\n\t\tproperty.setValue(() -> target, \"some string\");\n\t}\n\n\t@Test\n\tvoid bindOrCreateWithNestedShouldReturnCreatedValue() {\n\t\tNestedJavaBean result = this.binder.bindOrCreate(\"foo\", Bindable.of(NestedJavaBean.class));\n\t\tassertThat(result.getNested().getBar()).isEqualTo(456);\n\t}\n\n\t@Test\n\tvoid bindWhenHasPackagePrivateSetterShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.property\", \"test\");\n\t\tthis.sources.add(source);\n\t\tPackagePrivateSetterBean bean = this.binder.bind(\"foo\", Bindable.of(PackagePrivateSetterBean.class)).get();\n\t\tassertThat(bean.getProperty()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid bindUsesConsistentPropertyOrder() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.gamma\", \"0\");\n\t\tsource.put(\"foo.alpha\", \"0\");\n\t\tsource.put(\"foo.beta\", \"0\");\n\t\tthis.sources.add(source);\n\t\tPropertyOrderBean bean = this.binder.bind(\"foo\", Bindable.of(PropertyOrderBean.class)).get();\n\t\tassertThat(bean.getAlpha()).isZero();\n\t\tassertThat(bean.getBeta()).isOne();\n\t\tassertThat(bean.getGamma()).isEqualTo(2);\n\t}\n\n\t@Test // gh-23007\n\tvoid bindWhenBeanWithGetSetIsMethodsFoundUsesGetterThatMatchesSetter() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.names\", \"spring,boot\");\n\t\tthis.sources.add(source);\n\t\tJavaBeanWithGetSetIs bean = this.binder.bind(\"test\", Bindable.of(JavaBeanWithGetSetIs.class)).get();\n\t\tassertThat(bean.getNames()).containsExactly(\"spring\", \"boot\");\n\t}\n\n\t@Test // gh-23007\n\tvoid bindWhenBeanWithGetIsMethodsFoundDoesNotUseIsGetter() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.names\", \"spring,boot\");\n\t\tthis.sources.add(source);\n\t\tJavaBeanWithGetIs bean = this.binder.bind(\"test\", Bindable.of(JavaBeanWithGetIs.class)).get();\n\t\tassertThat(bean.getNames()).containsExactly(\"spring\", \"boot\");\n\t}\n\n\t@Test // gh-33105\n\tvoid bindWhenHasBridgeMethods() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.value\", \"spring-boot\");\n\t\tthis.sources.add(source);\n\t\tApplicationConversionService conversionService = new ApplicationConversionService();\n\t\tconversionService.addConverter(String.class, BridgeType.class, BridgeType::new);\n\t\tBinder binder = new Binder(this.sources, null, conversionService);\n\t\tBridgeMethods bean = binder.bind(\"test\", Bindable.of(BridgeMethods.class)).get();\n\t\tassertThat(bean.getValue()).hasToString(\"spring-boot\");\n\t}\n\n\tstatic class ExampleValueBean {\n\n\t\tprivate int intValue;\n\n\t\tprivate long longValue;\n\n\t\tprivate @Nullable String stringValue;\n\n\t\tprivate @Nullable ExampleEnum enumValue;\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tvoid setIntValue(int intValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t\tlong getLongValue() {\n\t\t\treturn this.longValue;\n\t\t}\n\n\t\tvoid setLongValue(long longValue) {\n\t\t\tthis.longValue = longValue;\n\t\t}\n\n\t\t@Nullable String getStringValue() {\n\t\t\treturn this.stringValue;\n\t\t}\n\n\t\tvoid setStringValue(@Nullable String stringValue) {\n\t\t\tthis.stringValue = stringValue;\n\t\t}\n\n\t\t@Nullable ExampleEnum getEnumValue() {\n\t\t\treturn this.enumValue;\n\t\t}\n\n\t\tvoid setEnumValue(@Nullable ExampleEnum enumValue) {\n\t\t\tthis.enumValue = enumValue;\n\t\t}\n\n\t}\n\n\tstatic class ExampleRenamedPropertyBean {\n\n\t\t@Name(\"public\")\n\t\tprivate @Nullable String exampleProperty;\n\n\t\t@Nullable String getExampleProperty() {\n\t\t\treturn this.exampleProperty;\n\t\t}\n\n\t\tvoid setExampleProperty(@Nullable String exampleProperty) {\n\t\t\tthis.exampleProperty = exampleProperty;\n\t\t}\n\n\t}\n\n\tstatic class ExampleDefaultsBean {\n\n\t\tprivate int foo = 123;\n\n\t\tprivate int bar = 456;\n\n\t\tint getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(int foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t\tint getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tvoid setBar(int bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t}\n\n\tstatic class ExampleMapBean {\n\n\t\tprivate @Nullable Map<ExampleEnum, Integer> map;\n\n\t\t@Nullable Map<ExampleEnum, Integer> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tvoid setMap(@Nullable Map<ExampleEnum, Integer> map) {\n\t\t\tthis.map = map;\n\t\t}\n\n\t}\n\n\tstatic class ExampleListBean {\n\n\t\tprivate @Nullable List<ExampleEnum> list;\n\n\t\t@Nullable List<ExampleEnum> getList() {\n\t\t\treturn this.list;\n\t\t}\n\n\t\tvoid setList(@Nullable List<ExampleEnum> list) {\n\t\t\tthis.list = list;\n\t\t}\n\n\t}\n\n\tstatic class ExampleSetBean {\n\n\t\tprivate @Nullable Set<ExampleEnum> set;\n\n\t\t@Nullable Set<ExampleEnum> getSet() {\n\t\t\treturn this.set;\n\t\t}\n\n\t\tvoid setSet(@Nullable Set<ExampleEnum> set) {\n\t\t\tthis.set = set;\n\t\t}\n\n\t}\n\n\tstatic class ExampleCollectionBean {\n\n\t\tprivate @Nullable Collection<ExampleEnum> collection;\n\n\t\t@Nullable Collection<ExampleEnum> getCollection() {\n\t\t\treturn this.collection;\n\t\t}\n\n\t\tvoid setCollection(@Nullable Collection<ExampleEnum> collection) {\n\t\t\tthis.collection = collection;\n\t\t}\n\n\t}\n\n\tstatic class ExampleMapBeanWithoutSetter {\n\n\t\tprivate final Map<ExampleEnum, Integer> map = new LinkedHashMap<>();\n\n\t\tMap<ExampleEnum, Integer> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t}\n\n\tstatic class ExampleListBeanWithoutSetter {\n\n\t\tprivate final List<ExampleEnum> list = new ArrayList<>();\n\n\t\tList<ExampleEnum> getList() {\n\t\t\treturn this.list;\n\t\t}\n\n\t}\n\n\tstatic class ExampleSetBeanWithoutSetter {\n\n\t\tprivate final Set<ExampleEnum> set = new LinkedHashSet<>();\n\n\t\tSet<ExampleEnum> getSet() {\n\t\t\treturn this.set;\n\t\t}\n\n\t}\n\n\tstatic class ExampleCollectionBeanWithoutSetter {\n\n\t\tprivate final Collection<ExampleEnum> collection = new ArrayList<>();\n\n\t\tCollection<ExampleEnum> getCollection() {\n\t\t\treturn this.collection;\n\t\t}\n\n\t}\n\n\tstatic class ExampleCollectionBeanWithDelimiter {\n\n\t\t@Delimiter(\"|\")\n\t\tprivate @Nullable Collection<ExampleEnum> collection;\n\n\t\t@Nullable Collection<ExampleEnum> getCollection() {\n\t\t\treturn this.collection;\n\t\t}\n\n\t\tvoid setCollection(@Nullable Collection<ExampleEnum> collection) {\n\t\t\tthis.collection = collection;\n\t\t}\n\n\t}\n\n\tstatic class ExampleNestedBean {\n\n\t\tprivate @Nullable ExampleValueBean valueBean;\n\n\t\t@Nullable ExampleValueBean getValueBean() {\n\t\t\treturn this.valueBean;\n\t\t}\n\n\t\tvoid setValueBean(@Nullable ExampleValueBean valueBean) {\n\t\t\tthis.valueBean = valueBean;\n\t\t}\n\n\t}\n\n\tstatic class ExampleNestedBeanWithoutSetter {\n\n\t\tprivate final ExampleValueBean valueBean = new ExampleValueBean();\n\n\t\tExampleValueBean getValueBean() {\n\t\t\treturn this.valueBean;\n\t\t}\n\n\t}\n\n\tstatic class ExampleNestedBeanWithoutSetterOrType {\n\n\t\tprivate final ExampleValueBean valueBean = new ExampleValueBean();\n\n\t\tObject getValueBean() {\n\t\t\treturn this.valueBean;\n\t\t}\n\n\t}\n\n\tstatic class ExampleImmutableNestedBeanWithoutSetter {\n\n\t\tprivate final NestedImmutable nested = new NestedImmutable();\n\n\t\tNestedImmutable getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tstatic class NestedImmutable {\n\n\t\t\tString getFoo() {\n\t\t\t\treturn \"foo\";\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class ExampleNestedSubclassBean extends ExampleNestedBean {\n\n\t\tprivate @Nullable ExampleValueSubclassBean valueBean;\n\n\t\t@Override\n\t\t@Nullable ExampleValueSubclassBean getValueBean() {\n\t\t\treturn this.valueBean;\n\t\t}\n\n\t\tvoid setValueBean(@Nullable ExampleValueSubclassBean valueBean) {\n\t\t\tthis.valueBean = valueBean;\n\t\t}\n\n\t\tstatic class ExampleValueSubclassBean extends ExampleValueBean {\n\n\t\t\tprivate int subIntValue;\n\n\t\t\tint getSubIntValue() {\n\t\t\t\treturn this.subIntValue;\n\t\t\t}\n\n\t\t\tvoid setSubIntValue(int intValue) {\n\t\t\t\tthis.subIntValue = intValue;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithNonDefaultConstructor {\n\n\t\tprivate @Nullable String value;\n\n\t\tExampleWithNonDefaultConstructor(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class ExampleSuperClassBean {\n\n\t\tprivate int intValue;\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tvoid setIntValue(int intValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t}\n\n\tstatic class ExampleSubclassBean extends ExampleSuperClassBean {\n\n\t\tprivate long longValue;\n\n\t\tlong getLongValue() {\n\t\t\treturn this.longValue;\n\t\t}\n\n\t\tvoid setLongValue(long longValue) {\n\t\t\tthis.longValue = longValue;\n\t\t}\n\n\t}\n\n\tstatic class ExampleMismatchBean {\n\n\t\tprivate int value;\n\n\t\tString getValue() {\n\t\t\treturn String.valueOf(this.value);\n\t\t}\n\n\t\tvoid setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithThrowingGetters {\n\n\t\tprivate int value;\n\n\t\tint getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tList<String> getNames() {\n\t\t\tthrow new RuntimeException();\n\t\t}\n\n\t\tExampleValueBean getNested() {\n\t\t\tthrow new RuntimeException();\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithSelfReference {\n\n\t\tprivate int value;\n\n\t\tprivate @Nullable ExampleWithSelfReference self;\n\n\t\tint getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Nullable ExampleWithSelfReference getSelf() {\n\t\t\treturn this.self;\n\t\t}\n\n\t\tvoid setSelf(@Nullable ExampleWithSelfReference self) {\n\t\t\tthis.self = self;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithInvalidAccessors {\n\n\t\tprivate @Nullable String name;\n\n\t\t@Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString get() {\n\t\t\tthrow new IllegalArgumentException(\"should not be invoked\");\n\t\t}\n\n\t\tboolean is() {\n\t\t\tthrow new IllegalArgumentException(\"should not be invoked\");\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithStaticAccessors {\n\n\t\tprivate static @Nullable String name;\n\n\t\tprivate int counter;\n\n\t\tstatic @Nullable String getName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tstatic void setName(@Nullable String name) {\n\t\t\tExampleWithStaticAccessors.name = name;\n\t\t}\n\n\t\tint getCounter() {\n\t\t\treturn this.counter;\n\t\t}\n\n\t\tvoid setCounter(int counter) {\n\t\t\tthis.counter = counter;\n\t\t}\n\n\t}\n\n\tpublic enum ExampleEnum {\n\n\t\tFOO_BAR,\n\n\t\tBAR_BAZ\n\n\t}\n\n\tstatic class ConverterAnnotatedExampleBean {\n\n\t\t@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)\n\t\tprivate @Nullable LocalDate date;\n\n\t\t@Nullable LocalDate getDate() {\n\t\t\treturn this.date;\n\t\t}\n\n\t\tvoid setDate(@Nullable LocalDate date) {\n\t\t\tthis.date = date;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithPropertyEditorType {\n\n\t\tprivate @Nullable Class<? extends Throwable> value;\n\n\t\t@Nullable Class<? extends Throwable> getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable Class<? extends Throwable> value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithGenericMap {\n\n\t\tprivate final Map<String, GenericValue<Integer>> integers = new LinkedHashMap<>();\n\n\t\tprivate final Map<String, GenericValue<Boolean>> booleans = new LinkedHashMap<>();\n\n\t\tMap<String, GenericValue<Integer>> getIntegers() {\n\t\t\treturn this.integers;\n\t\t}\n\n\t\tMap<String, GenericValue<Boolean>> getBooleans() {\n\t\t\treturn this.booleans;\n\t\t}\n\n\t}\n\n\tstatic class GenericValue<T> {\n\n\t\tprivate @Nullable T value;\n\n\t\t@Nullable T getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class PropertyWithOverloadedSetter {\n\n\t\tprivate @Nullable String property;\n\n\t\tvoid setProperty(int property) {\n\t\t\tthis.property = String.valueOf(property);\n\t\t}\n\n\t\tvoid setProperty(@Nullable String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t\t@Nullable String getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t}\n\n\tstatic class NestedJavaBean {\n\n\t\tprivate ExampleDefaultsBean nested = new ExampleDefaultsBean();\n\n\t\tExampleDefaultsBean getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(ExampleDefaultsBean nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t}\n\n\tstatic class PackagePrivateSetterBean {\n\n\t\tprivate @Nullable String property;\n\n\t\t@Nullable String getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t\tvoid setProperty(@Nullable String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t}\n\n\tstatic class JavaBeanWithGetSetIs {\n\n\t\tprivate List<String> names = new ArrayList<>();\n\n\t\tList<String> getNames() {\n\t\t\treturn this.names;\n\t\t}\n\n\t\tvoid setNames(List<String> names) {\n\t\t\tthis.names = names;\n\t\t}\n\n\t\tboolean isNames() {\n\t\t\treturn !this.names.isEmpty();\n\t\t}\n\n\t}\n\n\tstatic class JavaBeanWithGetIs {\n\n\t\tprivate final List<String> names = new ArrayList<>();\n\n\t\tboolean isNames() {\n\t\t\treturn !this.names.isEmpty();\n\t\t}\n\n\t\tList<String> getNames() {\n\t\t\treturn this.names;\n\t\t}\n\n\t}\n\n\tstatic class PropertyOrderBean {\n\n\t\tstatic AtomicInteger atomic = new AtomicInteger();\n\n\t\tprivate int alpha;\n\n\t\tprivate int beta;\n\n\t\tprivate int gamma;\n\n\t\tint getAlpha() {\n\t\t\treturn this.alpha;\n\t\t}\n\n\t\tvoid setAlpha(int alpha) {\n\t\t\tthis.alpha = alpha + atomic.getAndIncrement();\n\t\t}\n\n\t\tint getBeta() {\n\t\t\treturn this.beta;\n\t\t}\n\n\t\tvoid setBeta(int beta) {\n\t\t\tthis.beta = beta + atomic.getAndIncrement();\n\t\t}\n\n\t\tint getGamma() {\n\t\t\treturn this.gamma;\n\t\t}\n\n\t\tvoid setGamma(int gamma) {\n\t\t\tthis.gamma = gamma + atomic.getAndIncrement();\n\t\t}\n\n\t}\n\n\tstatic class BridgeMethodsBase<T extends BridgeBaseType> {\n\n\t\tprivate @Nullable T value;\n\n\t\t@Nullable T getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class BridgeMethods extends BridgeMethodsBase<BridgeType> {\n\n\t\t@Override\n\t\t@Nullable BridgeType getValue() {\n\t\t\treturn super.getValue();\n\t\t}\n\n\t}\n\n\tstatic class BridgeBaseType {\n\n\t}\n\n\tstatic class BridgeType extends BridgeBaseType {\n\n\t\tprivate final String value;\n\n\t\tBridgeType(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/JavaBeanWithPublicConstructor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Java bean with an additional public single-arg constructor.\n *\n * @author Phillip Webb\n */\npublic class JavaBeanWithPublicConstructor {\n\n\tprivate @Nullable String value;\n\n\tpublic JavaBeanWithPublicConstructor() {\n\t}\n\n\tpublic JavaBeanWithPublicConstructor(String value) {\n\t\tsetValue(value);\n\t}\n\n\tpublic @Nullable String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(@Nullable String value) {\n\t\tthis.value = value;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/MapBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.net.InetAddress;\nimport java.util.AbstractMap;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport org.springframework.boot.context.properties.bind.BinderTests.ExampleEnum;\nimport org.springframework.boot.context.properties.bind.BinderTests.JavaBean;\nimport org.springframework.boot.context.properties.bind.MapBinderTests.CustomMapWithoutDefaultCtor.CustomMap;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MapBinder}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass MapBinderTests {\n\n\tprivate static final Bindable<Map<String, String>> STRING_STRING_MAP = Bindable.mapOf(String.class, String.class);\n\n\tprivate static final Bindable<Map<String, Integer>> STRING_INTEGER_MAP = Bindable.mapOf(String.class,\n\t\t\tInteger.class);\n\n\tprivate static final Bindable<Map<Integer, Integer>> INTEGER_INTEGER_MAP = Bindable.mapOf(Integer.class,\n\t\t\tInteger.class);\n\n\tprivate static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable.mapOf(String.class, Object.class);\n\n\tprivate static final Bindable<Map<String, String[]>> STRING_ARRAY_MAP = Bindable.mapOf(String.class,\n\t\t\tString[].class);\n\n\tprivate static final Bindable<EnumMap<ExampleEnum, String>> EXAMPLE_ENUM_STRING_ENUM_MAP = Bindable\n\t\t.of(ResolvableType.forClassWithGenerics(EnumMap.class, ExampleEnum.class, String.class));\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate final Binder binder = new Binder(this.sources);\n\n\t@Test\n\tvoid bindToMapShouldReturnPopulatedMap() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"1\");\n\t\tsource.put(\"foo.[baz]\", \"2\");\n\t\tsource.put(\"foo[BiNg]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tMap<String, String> result = this.binder.bind(\"foo\", STRING_STRING_MAP).get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsEntry(\"bar\", \"1\");\n\t\tassertThat(result).containsEntry(\"baz\", \"2\");\n\t\tassertThat(result).containsEntry(\"BiNg\", \"3\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid bindToMapWithEmptyPrefix() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"1\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Object> result = this.binder.bind(\"\", STRING_OBJECT_MAP).get();\n\t\tassertThat((Map<String, Object>) result.get(\"foo\")).containsEntry(\"bar\", \"1\");\n\t}\n\n\t@Test\n\tvoid bindToMapShouldConvertMapValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"1\");\n\t\tsource.put(\"foo.[baz]\", \"2\");\n\t\tsource.put(\"foo[BiNg]\", \"3\");\n\t\tsource.put(\"faf.bar\", \"x\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Integer> result = this.binder.bind(\"foo\", STRING_INTEGER_MAP).get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsEntry(\"bar\", 1);\n\t\tassertThat(result).containsEntry(\"baz\", 2);\n\t\tassertThat(result).containsEntry(\"BiNg\", 3);\n\t}\n\n\t@Test\n\tvoid bindToMapShouldBindToMapValue() {\n\t\tResolvableType type = ResolvableType.forClassWithGenerics(Map.class, ResolvableType.forClass(String.class),\n\t\t\t\tSTRING_INTEGER_MAP.getType());\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar.baz\", \"1\");\n\t\tsource.put(\"foo.bar.bin\", \"2\");\n\t\tsource.put(\"foo.far.baz\", \"3\");\n\t\tsource.put(\"foo.far.bin\", \"4\");\n\t\tsource.put(\"faf.far.bin\", \"x\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Map<String, Integer>> result = this.binder\n\t\t\t.bind(\"foo\", Bindable.<Map<String, Map<String, Integer>>>of(type))\n\t\t\t.get();\n\t\tassertThat(result).hasSize(2);\n\t\tassertThat(result.get(\"bar\")).containsEntry(\"baz\", 1).containsEntry(\"bin\", 2);\n\t\tassertThat(result.get(\"far\")).containsEntry(\"baz\", 3).containsEntry(\"bin\", 4);\n\t}\n\n\t@Test\n\tvoid bindToMapShouldBindNestedMapValue() {\n\t\tResolvableType nestedType = ResolvableType.forClassWithGenerics(Map.class,\n\t\t\t\tResolvableType.forClass(String.class), STRING_INTEGER_MAP.getType());\n\t\tResolvableType type = ResolvableType.forClassWithGenerics(Map.class, ResolvableType.forClass(String.class),\n\t\t\t\tnestedType);\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.nested.bar.baz\", \"1\");\n\t\tsource.put(\"foo.nested.bar.bin\", \"2\");\n\t\tsource.put(\"foo.nested.far.baz\", \"3\");\n\t\tsource.put(\"foo.nested.far.bin\", \"4\");\n\t\tsource.put(\"faf.nested.far.bin\", \"x\");\n\t\tthis.sources.add(source);\n\t\tBindable<Map<String, Map<String, Map<String, Integer>>>> target = Bindable.of(type);\n\t\tMap<String, Map<String, Map<String, Integer>>> result = this.binder.bind(\"foo\", target).get();\n\t\tMap<String, Map<String, Integer>> nested = result.get(\"nested\");\n\t\tassertThat(nested).hasSize(2);\n\t\tassertThat(nested.get(\"bar\")).containsEntry(\"baz\", 1).containsEntry(\"bin\", 2);\n\t\tassertThat(nested.get(\"far\")).containsEntry(\"baz\", 3).containsEntry(\"bin\", 4);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid bindToMapWhenMapValueIsObjectShouldBindNestedMapValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.nested.bar.baz\", \"1\");\n\t\tsource.put(\"foo.nested.bar.bin\", \"2\");\n\t\tsource.put(\"foo.nested.far.baz\", \"3\");\n\t\tsource.put(\"foo.nested.far.bin\", \"4\");\n\t\tsource.put(\"faf.nested.far.bin\", \"x\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Object> result = this.binder.bind(\"foo\", Bindable.mapOf(String.class, Object.class)).get();\n\t\tMap<String, Object> nested = (Map<String, Object>) result.get(\"nested\");\n\t\tassertThat(nested).hasSize(2);\n\t\tMap<String, Object> bar = (Map<String, Object>) nested.get(\"bar\");\n\t\tassertThat(bar).containsEntry(\"baz\", \"1\").containsEntry(\"bin\", \"2\");\n\t\tMap<String, Object> far = (Map<String, Object>) nested.get(\"far\");\n\t\tassertThat(far).containsEntry(\"baz\", \"3\").containsEntry(\"bin\", \"4\");\n\t}\n\n\t@Test\n\tvoid bindToMapWhenMapValueIsObjectAndNoRootShouldBindNestedMapValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"commit.id\", \"abcdefg\");\n\t\tsource.put(\"branch\", \"master\");\n\t\tsource.put(\"foo\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Object> result = this.binder.bind(\"\", Bindable.mapOf(String.class, Object.class)).get();\n\t\tassertThat(result).containsEntry(\"commit\", Collections.singletonMap(\"id\", \"abcdefg\"));\n\t\tassertThat(result).containsEntry(\"branch\", \"master\");\n\t\tassertThat(result).containsEntry(\"foo\", \"bar\");\n\t}\n\n\t@Test\n\tvoid bindToMapWhenEmptyRootNameShouldBindMap() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"bar.baz\", \"1\");\n\t\tsource.put(\"bar.bin\", \"2\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Integer> result = this.binder.bind(\"\", STRING_INTEGER_MAP).get();\n\t\tassertThat(result).hasSize(2);\n\t\tassertThat(result).containsEntry(\"bar.baz\", 1).containsEntry(\"bar.bin\", 2);\n\t}\n\n\t@Test\n\tvoid bindToMapWhenMultipleCandidateShouldBindFirst() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"foo.bar\", \"1\");\n\t\tsource1.put(\"foo.baz\", \"2\");\n\t\tthis.sources.add(source1);\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"foo.baz\", \"3\");\n\t\tsource2.put(\"foo.bin\", \"4\");\n\t\tthis.sources.add(source2);\n\t\tMap<String, Integer> result = this.binder.bind(\"foo\", STRING_INTEGER_MAP).get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsEntry(\"bar\", 1);\n\t\tassertThat(result).containsEntry(\"baz\", 2);\n\t\tassertThat(result).containsEntry(\"bin\", 4);\n\t}\n\n\t@Test\n\tvoid bindToMapWhenMultipleInSameSourceCandidateShouldBindFirst() {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tmap.put(\"foo.bar\", \"1\");\n\t\tmap.put(\"foo.b-az\", \"2\");\n\t\tmap.put(\"foo.ba-z\", \"3\");\n\t\tmap.put(\"foo.bin\", \"4\");\n\t\tMapConfigurationPropertySource propertySource = new MapConfigurationPropertySource(map);\n\t\tthis.sources.add(propertySource);\n\t\tMap<String, Integer> result = this.binder.bind(\"foo\", STRING_INTEGER_MAP).get();\n\t\tassertThat(result).hasSize(4);\n\t\tassertThat(result).containsEntry(\"bar\", 1);\n\t\tassertThat(result).containsEntry(\"b-az\", 2);\n\t\tassertThat(result).containsEntry(\"ba-z\", 3);\n\t\tassertThat(result).containsEntry(\"bin\", 4);\n\t}\n\n\t@Test\n\tvoid bindToMapWhenHasExistingMapShouldReplaceOnlyNewContents() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.bar\", \"1\"));\n\t\tMap<String, Integer> existing = new HashMap<>();\n\t\texisting.put(\"bar\", 1000);\n\t\texisting.put(\"baz\", 1001);\n\t\tBindable<Map<String, Integer>> target = STRING_INTEGER_MAP.withExistingValue(existing);\n\t\tMap<String, Integer> result = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(result).isExactlyInstanceOf(HashMap.class);\n\t\tassertThat(result).hasSize(2);\n\t\tassertThat(result).containsEntry(\"bar\", 1);\n\t\tassertThat(result).containsEntry(\"baz\", 1001);\n\t}\n\n\t@Test\n\tvoid bindToMapShouldRespectMapType() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.bar\", \"1\"));\n\t\tResolvableType type = ResolvableType.forClassWithGenerics(HashMap.class, String.class, Integer.class);\n\t\tObject defaultMap = this.binder.bind(\"foo\", STRING_INTEGER_MAP).get();\n\t\tObject customMap = this.binder.bind(\"foo\", Bindable.of(type)).get();\n\t\tassertThat(customMap).isExactlyInstanceOf(HashMap.class).isNotInstanceOf(defaultMap.getClass());\n\t}\n\n\t@Test\n\tvoid bindToMapWhenNoValueShouldReturnUnbound() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"faf.bar\", \"1\"));\n\t\tBindResult<Map<String, Integer>> result = this.binder.bind(\"foo\", STRING_INTEGER_MAP);\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToMapShouldConvertKey() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo[0]\", \"1\");\n\t\tsource.put(\"foo[1]\", \"2\");\n\t\tsource.put(\"foo[9]\", \"3\");\n\t\tthis.sources.add(source);\n\t\tMap<Integer, Integer> result = this.binder.bind(\"foo\", INTEGER_INTEGER_MAP).get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsEntry(0, 1);\n\t\tassertThat(result).containsEntry(1, 2);\n\t\tassertThat(result).containsEntry(9, 3);\n\t}\n\n\t@Test\n\tvoid bindToMapShouldBeGreedyForStrings() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.aaa.bbb.ccc\", \"b\");\n\t\tsource.put(\"foo.bbb.ccc.ddd\", \"a\");\n\t\tsource.put(\"foo.ccc.ddd.eee\", \"r\");\n\t\tthis.sources.add(source);\n\t\tMap<String, String> result = this.binder.bind(\"foo\", STRING_STRING_MAP).get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsEntry(\"aaa.bbb.ccc\", \"b\");\n\t\tassertThat(result).containsEntry(\"bbb.ccc.ddd\", \"a\");\n\t\tassertThat(result).containsEntry(\"ccc.ddd.eee\", \"r\");\n\t}\n\n\t@Test\n\tvoid bindToMapShouldBeGreedyForScalars() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.aaa.bbb.ccc\", \"foo-bar\");\n\t\tsource.put(\"foo.bbb.ccc.ddd\", \"BAR_BAZ\");\n\t\tsource.put(\"foo.ccc.ddd.eee\", \"bazboo\");\n\t\tthis.sources.add(source);\n\t\tMap<String, ExampleEnum> result = this.binder.bind(\"foo\", Bindable.mapOf(String.class, ExampleEnum.class))\n\t\t\t.get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsEntry(\"aaa.bbb.ccc\", ExampleEnum.FOO_BAR);\n\t\tassertThat(result).containsEntry(\"bbb.ccc.ddd\", ExampleEnum.BAR_BAZ);\n\t\tassertThat(result).containsEntry(\"ccc.ddd.eee\", ExampleEnum.BAZ_BOO);\n\t}\n\n\t@Test\n\tvoid bindToMapWithPlaceholdersShouldBeGreedyForScalars() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, \"foo=boo\");\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource(\"foo.aaa.bbb.ccc\", \"baz-${foo}\");\n\t\tthis.sources.add(source);\n\t\tBinder binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment));\n\t\tMap<String, ExampleEnum> result = binder.bind(\"foo\", Bindable.mapOf(String.class, ExampleEnum.class)).get();\n\t\tassertThat(result).containsEntry(\"aaa.bbb.ccc\", ExampleEnum.BAZ_BOO);\n\t}\n\n\t@Test\n\tvoid bindToMapWithNoPropertiesShouldReturnUnbound() {\n\t\tBindResult<Map<String, ExampleEnum>> result = this.binder.bind(\"foo\",\n\t\t\t\tBindable.mapOf(String.class, ExampleEnum.class));\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToMapShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.bar\", \"1\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tBindable<Map<String, Integer>> target = STRING_INTEGER_MAP;\n\t\tthis.binder.bind(\"foo\", target, handler);\n\t\tInOrder ordered = inOrder(handler);\n\t\tordered.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo.bar\")), eq(Bindable.of(Integer.class)), any(), eq(1));\n\t\tordered.verify(handler).onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), isA(Map.class));\n\t}\n\n\t@Test\n\tvoid bindToMapStringArrayShouldTriggerOnSuccess() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.bar\", \"a,b,c\", \"line1\"));\n\t\tBindHandler handler = mockBindHandler();\n\t\tBindable<Map<String, String[]>> target = STRING_ARRAY_MAP;\n\t\tthis.binder.bind(\"foo\", target, handler);\n\t\tInOrder ordered = inOrder(handler);\n\t\tordered.verify(handler)\n\t\t\t.onSuccess(eq(ConfigurationPropertyName.of(\"foo.bar\")), eq(Bindable.of(String[].class)), any(),\n\t\t\t\t\tassertArg((array) -> assertThat((String[]) array).containsExactly(\"a\", \"b\", \"c\")));\n\t\tordered.verify(handler).onSuccess(eq(ConfigurationPropertyName.of(\"foo\")), eq(target), any(), isA(Map.class));\n\t}\n\n\t@Test\n\tvoid bindToMapNonScalarCollectionShouldPopulateMap() {\n\t\tBindable<List<JavaBean>> valueType = Bindable.listOf(JavaBean.class);\n\t\tBindable<Map<String, List<JavaBean>>> target = getMapBindable(String.class, valueType.getType());\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar[0].value\", \"a\");\n\t\tsource.put(\"foo.bar[1].value\", \"b\");\n\t\tsource.put(\"foo.bar[2].value\", \"c\");\n\t\tthis.sources.add(source);\n\t\tMap<String, List<JavaBean>> map = this.binder.bind(\"foo\", target).get();\n\t\tList<JavaBean> bar = map.get(\"bar\");\n\t\tassertThat(bar).isNotNull();\n\t\tList<String> values = bar.stream().map(JavaBean::getValue).toList();\n\t\tassertThat(values).containsExactly(\"a\", \"b\", \"c\");\n\n\t}\n\n\t@Test\n\tvoid bindToPropertiesShouldBeEquivalentToMapOfStringString() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.bar.baz\", \"1\", \"line1\"));\n\t\tBindable<Properties> target = Bindable.of(Properties.class);\n\t\tProperties properties = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(properties.getProperty(\"bar.baz\")).isEqualTo(\"1\");\n\t}\n\n\t@Test\n\tvoid bindToMapShouldNotTreatClassWithStringConstructorAsScalar() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.bar.pattern\", \"1\", \"line1\"));\n\t\tBindable<Map<String, Foo>> target = Bindable.mapOf(String.class, Foo.class);\n\t\tMap<String, Foo> map = this.binder.bind(\"foo\", target).get();\n\t\tFoo bar = map.get(\"bar\");\n\t\tassertThat(bar).isNotNull();\n\t\tassertThat(bar.getPattern()).isEqualTo(\"1\");\n\t}\n\n\t@Test\n\tvoid bindToMapStringArrayWithDotKeysShouldPreserveDot() {\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo.bar.baz[0]\", \"a\");\n\t\tmockSource.put(\"foo.bar.baz[1]\", \"b\");\n\t\tmockSource.put(\"foo.bar.baz[2]\", \"c\");\n\t\tthis.sources.add(mockSource);\n\t\tMap<String, String[]> map = this.binder.bind(\"foo\", STRING_ARRAY_MAP).get();\n\t\tassertThat(map.get(\"bar.baz\")).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToMapStringArrayWithDotKeysAndCommaSeparatedShouldPreserveDot() {\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo.bar.baz\", \"a,b,c\");\n\t\tthis.sources.add(mockSource);\n\t\tMap<String, String[]> map = this.binder.bind(\"foo\", STRING_ARRAY_MAP).get();\n\t\tassertThat(map.get(\"bar.baz\")).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToMapStringCollectionWithDotKeysShouldPreserveDot() {\n\t\tBindable<List<String>> valueType = Bindable.listOf(String.class);\n\t\tBindable<Map<String, List<String>>> target = getMapBindable(String.class, valueType.getType());\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo.bar.baz[0]\", \"a\");\n\t\tmockSource.put(\"foo.bar.baz[1]\", \"b\");\n\t\tmockSource.put(\"foo.bar.baz[2]\", \"c\");\n\t\tthis.sources.add(mockSource);\n\t\tMap<String, List<String>> map = this.binder.bind(\"foo\", target).get();\n\t\tList<String> values = map.get(\"bar.baz\");\n\t\tassertThat(values).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToMapNonScalarCollectionWithDotKeysShouldBind() {\n\t\tBindable<List<JavaBean>> valueType = Bindable.listOf(JavaBean.class);\n\t\tBindable<Map<String, List<JavaBean>>> target = getMapBindable(String.class, valueType.getType());\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo.bar.baz[0].value\", \"a\");\n\t\tmockSource.put(\"foo.bar.baz[1].value\", \"b\");\n\t\tmockSource.put(\"foo.bar.baz[2].value\", \"c\");\n\t\tthis.sources.add(mockSource);\n\t\tMap<String, List<JavaBean>> map = this.binder.bind(\"foo\", target).get();\n\t\tList<JavaBean> barBaz = map.get(\"bar.baz\");\n\t\tassertThat(barBaz).isNotNull();\n\t\tList<String> values = barBaz.stream().map(JavaBean::getValue).toList();\n\t\tassertThat(values).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid bindToListOfMaps() {\n\t\tBindable<List<Integer>> listBindable = Bindable.listOf(Integer.class);\n\t\tBindable<Map<String, List<Integer>>> mapBindable = getMapBindable(String.class, listBindable.getType());\n\t\tBindable<List<Map<String, List<Integer>>>> target = getListBindable(mapBindable.getType());\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo[0].a\", \"1,2,3\");\n\t\tmockSource.put(\"foo[1].b\", \"4,5,6\");\n\t\tthis.sources.add(mockSource);\n\t\tList<Map<String, List<Integer>>> list = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(list.get(0).get(\"a\")).containsExactly(1, 2, 3);\n\t\tassertThat(list.get(1).get(\"b\")).containsExactly(4, 5, 6);\n\t}\n\n\t@Test\n\tvoid bindToMapWithNumberKeyAndCommaSeparated() {\n\t\tBindable<List<String>> listBindable = Bindable.listOf(String.class);\n\t\tBindable<Map<Integer, List<String>>> target = getMapBindable(Integer.class, listBindable.getType());\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo[0]\", \"a,b,c\");\n\t\tmockSource.put(\"foo[1]\", \"e,f,g\");\n\t\tthis.sources.add(mockSource);\n\t\tMap<Integer, List<String>> map = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(map.get(0)).containsExactly(\"a\", \"b\", \"c\");\n\t\tassertThat(map.get(1)).containsExactly(\"e\", \"f\", \"g\");\n\t}\n\n\t@Test\n\tvoid bindToMapWithNumberKeyAndIndexed() {\n\t\tBindable<List<Integer>> listBindable = Bindable.listOf(Integer.class);\n\t\tBindable<Map<Integer, List<Integer>>> target = getMapBindable(Integer.class, listBindable.getType());\n\t\tMockConfigurationPropertySource mockSource = new MockConfigurationPropertySource();\n\t\tmockSource.put(\"foo[0][0]\", \"8\");\n\t\tmockSource.put(\"foo[0][1]\", \"9\");\n\t\tthis.sources.add(mockSource);\n\t\tMap<Integer, List<Integer>> map = this.binder.bind(\"foo\", target).get();\n\t\tassertThat(map.get(0)).containsExactly(8, 9);\n\t}\n\n\t@Test\n\tvoid bindingWithSquareBracketMap() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.[x [B] y]\", \"[ball]\");\n\t\tthis.sources.add(source);\n\t\tMap<String, String> map = this.binder.bind(\"foo\", STRING_STRING_MAP).get();\n\t\tassertThat(map).containsEntry(\"x [B] y\", \"[ball]\");\n\t}\n\n\t@Test\n\tvoid nestedMapsShouldNotBindToNull() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value\", \"one\");\n\t\tsource.put(\"foo.foos.foo1.value\", \"two\");\n\t\tsource.put(\"foo.foos.foo2.value\", \"three\");\n\t\tthis.sources.add(source);\n\t\tBindResult<NestableFoo> foo = this.binder.bind(\"foo\", NestableFoo.class);\n\t\tassertThat(foo.get().getValue()).isNotNull();\n\t\tNestableFoo foo1 = foo.get().getFoos().get(\"foo1\");\n\t\tassertThat(foo1).isNotNull();\n\t\tassertThat(foo1.getValue()).isEqualTo(\"two\");\n\t\tNestableFoo foo2 = foo.get().getFoos().get(\"foo2\");\n\t\tassertThat(foo2).isNotNull();\n\t\tassertThat(foo2.getValue()).isEqualTo(\"three\");\n\t}\n\n\t@Test\n\tvoid bindToMapWithCustomConverter() {\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new MapConverter());\n\t\tBinder binder = new Binder(this.sources, null, conversionService, null);\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"a,b\");\n\t\tthis.sources.add(source);\n\t\tMap<String, String> map = binder.bind(\"foo\", STRING_STRING_MAP).get();\n\t\tassertThat(map).containsKey(\"a\");\n\t\tassertThat(map).containsKey(\"b\");\n\t}\n\n\t@Test\n\tvoid bindToMapWithCustomConverterAndChildElements() {\n\t\t// gh-11892\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new MapConverter());\n\t\tBinder binder = new Binder(this.sources, null, conversionService, null);\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"boom\");\n\t\tsource.put(\"foo.a\", \"a\");\n\t\tsource.put(\"foo.b\", \"b\");\n\t\tthis.sources.add(source);\n\t\tMap<String, String> map = binder.bind(\"foo\", STRING_STRING_MAP).get();\n\t\tassertThat(map).containsEntry(\"a\", \"a\");\n\t\tassertThat(map).containsEntry(\"b\", \"b\");\n\t}\n\n\t@Test\n\tvoid bindToMapWithNoConverterForValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"a,b\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind(\"foo\", STRING_STRING_MAP));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid bindToMapWithPropertyEditorForKey() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.[java.lang.RuntimeException]\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tMap<Class, String> map = this.binder.bind(\"foo\", Bindable.mapOf(Class.class, String.class)).get();\n\t\tassertThat(map).containsExactly(entry(RuntimeException.class, \"bar\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid bindToMapWithPropertyEditorForValue() {\n\t\t// gh-12166\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"java.lang.RuntimeException\");\n\t\tthis.sources.add(source);\n\t\tMap<String, Class> map = this.binder.bind(\"foo\", Bindable.mapOf(String.class, Class.class)).get();\n\t\tassertThat(map).containsExactly(entry(\"bar\", RuntimeException.class));\n\t}\n\n\t@Test\n\tvoid bindToMapWithNoDefaultConstructor() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items.a\", \"b\");\n\t\tthis.sources.add(source);\n\t\tExampleCustomNoDefaultConstructorBean result = this.binder\n\t\t\t.bind(\"foo\", ExampleCustomNoDefaultConstructorBean.class)\n\t\t\t.get();\n\t\tassertThat(result.getItems()).containsOnly(entry(\"foo\", \"bar\"), entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid bindToMapWithDefaultConstructor() {\n\t\t// gh-12322\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.items.a\", \"b\");\n\t\tthis.sources.add(source);\n\t\tExampleCustomWithDefaultConstructorBean result = this.binder\n\t\t\t.bind(\"foo\", ExampleCustomWithDefaultConstructorBean.class)\n\t\t\t.get();\n\t\tassertThat(result.getItems()).containsExactly(entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid bindToImmutableMapShouldReturnPopulatedMap() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.values.c\", \"d\");\n\t\tsource.put(\"foo.values.e\", \"f\");\n\t\tthis.sources.add(source);\n\t\tMap<String, String> result = this.binder\n\t\t\t.bind(\"foo.values\", STRING_STRING_MAP.withExistingValue(Collections.singletonMap(\"a\", \"b\")))\n\t\t\t.get();\n\t\tassertThat(result).hasSize(3);\n\t\tassertThat(result).containsExactly(entry(\"a\", \"b\"), entry(\"c\", \"d\"), entry(\"e\", \"f\"));\n\t}\n\n\t@Test\n\tvoid bindToBeanWithExceptionInGetterForExistingValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.values.a\", \"b\");\n\t\tthis.sources.add(source);\n\t\tBeanWithGetterException result = this.binder.bind(\"foo\", Bindable.of(BeanWithGetterException.class)).get();\n\t\tassertThat(result.getValues()).containsExactly(entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid bindToMapWithWildcardShouldConvertToTheRightType() {\n\t\t// gh-18767\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.addresses.localhost[0]\", \"127.0.0.1\");\n\t\tsource.put(\"foo.addresses.localhost[1]\", \"127.0.0.2\");\n\t\tthis.sources.add(source);\n\t\tMapWithWildcardProperties result = this.binder.bind(\"foo\", Bindable.of(MapWithWildcardProperties.class)).get();\n\t\tMap<String, ? extends List<? extends InetAddress>> addresses = result.getAddresses();\n\t\tassertThat(addresses).isNotNull();\n\t\tList<? extends InetAddress> localhost = addresses.get(\"localhost\");\n\t\tassertThat(localhost).isNotNull();\n\t\tassertThat(localhost.stream().map(InetAddress::getHostAddress)).containsExactly(\"127.0.0.1\", \"127.0.0.2\");\n\t}\n\n\t@Test\n\tvoid bindToMapWithPlaceholdersShouldResolve() {\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new MapConverter());\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tBinder binder = new Binder(this.sources, new PropertySourcesPlaceholdersResolver(environment),\n\t\t\t\tconversionService, null, null);\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, \"bar=bc\");\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"a${bar},${bar}d\"));\n\t\tMap<String, String> map = binder.bind(\"foo\", STRING_STRING_MAP).get();\n\t\tassertThat(map).containsKey(\"abc\");\n\t\tassertThat(map).containsKey(\"bcd\");\n\t}\n\n\t@Test\n\tvoid bindToCustomMapWithoutCtorAndConverterShouldResolve() {\n\t\tDefaultConversionService conversionService = new DefaultConversionService();\n\t\tconversionService.addConverter(new CustomMapConverter());\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.custom-map\", \"value\");\n\t\tthis.sources.add(source);\n\t\tBinder binder = new Binder(this.sources, null, conversionService, null);\n\t\tCustomMapWithoutDefaultCtor result = binder.bind(\"foo\", Bindable.of(CustomMapWithoutDefaultCtor.class)).get();\n\t\tassertThat(result.getCustomMap().getSource()).isEqualTo(\"value\");\n\t}\n\n\t@Test\n\tvoid bindToEnumMapShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"props.foo-bar\", \"value\");\n\t\tthis.sources.add(source);\n\t\tBinder binder = new Binder(this.sources, null, null, null);\n\t\tEnumMap<ExampleEnum, String> result = binder.bind(\"props\", EXAMPLE_ENUM_STRING_ENUM_MAP).get();\n\t\tassertThat(result).hasSize(1).containsEntry(ExampleEnum.FOO_BAR, \"value\");\n\t}\n\n\tprivate <K, V> Bindable<Map<K, V>> getMapBindable(Class<K> keyGeneric, ResolvableType valueType) {\n\t\tResolvableType keyType = ResolvableType.forClass(keyGeneric);\n\t\treturn Bindable.of(ResolvableType.forClassWithGenerics(Map.class, keyType, valueType));\n\t}\n\n\tprivate <T> Bindable<List<T>> getListBindable(ResolvableType type) {\n\t\treturn Bindable.of(ResolvableType.forClassWithGenerics(List.class, type));\n\t}\n\n\tprivate BindHandler mockBindHandler() {\n\t\tBindHandler handler = mock(BindHandler.class);\n\t\tgiven(handler.onStart(any(), any(), any())).willAnswer(InvocationArgument.index(1));\n\t\tgiven(handler.onCreate(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));\n\t\tgiven(handler.onSuccess(any(), any(), any(), any())).willAnswer(InvocationArgument.index(3));\n\t\treturn handler;\n\t}\n\n\tstatic class Foo {\n\n\t\tprivate @Nullable String pattern;\n\n\t\tFoo() {\n\t\t}\n\n\t\tFoo(@Nullable String pattern) {\n\t\t\tthis.pattern = pattern;\n\t\t}\n\n\t\t@Nullable String getPattern() {\n\t\t\treturn this.pattern;\n\t\t}\n\n\t\tvoid setPattern(@Nullable String pattern) {\n\t\t\tthis.pattern = pattern;\n\t\t}\n\n\t}\n\n\tstatic class NestableFoo {\n\n\t\tprivate final Map<String, NestableFoo> foos = new LinkedHashMap<>();\n\n\t\tprivate @Nullable String value;\n\n\t\tMap<String, NestableFoo> getFoos() {\n\t\t\treturn this.foos;\n\t\t}\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\tstatic class MapConverter implements Converter<String, Map<String, String>> {\n\n\t\t@Override\n\t\tpublic Map<String, String> convert(String s) {\n\t\t\treturn StringUtils.commaDelimitedListToSet(s).stream().collect(Collectors.toMap((k) -> k, (k) -> \"\"));\n\t\t}\n\n\t}\n\n\tstatic class ExampleCustomNoDefaultConstructorBean {\n\n\t\tprivate MyCustomNoDefaultConstructorMap items = new MyCustomNoDefaultConstructorMap(\n\t\t\t\tCollections.singletonMap(\"foo\", \"bar\"));\n\n\t\tMyCustomNoDefaultConstructorMap getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t\tvoid setItems(MyCustomNoDefaultConstructorMap items) {\n\t\t\tthis.items = items;\n\t\t}\n\n\t}\n\n\tstatic class MyCustomNoDefaultConstructorMap extends HashMap<String, String> {\n\n\t\tMyCustomNoDefaultConstructorMap(Map<String, String> items) {\n\t\t\tputAll(items);\n\t\t}\n\n\t}\n\n\tstatic class ExampleCustomWithDefaultConstructorBean {\n\n\t\tprivate final MyCustomWithDefaultConstructorMap items = new MyCustomWithDefaultConstructorMap();\n\n\t\tMyCustomWithDefaultConstructorMap getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t\tvoid setItems(MyCustomWithDefaultConstructorMap items) {\n\t\t\tthis.items.clear();\n\t\t\tthis.items.putAll(items);\n\t\t}\n\n\t}\n\n\tstatic class MyCustomWithDefaultConstructorMap extends HashMap<String, String> {\n\n\t}\n\n\tstatic class BeanWithGetterException {\n\n\t\tprivate @Nullable Map<String, String> values;\n\n\t\tvoid setValues(@Nullable Map<String, String> values) {\n\t\t\tthis.values = values;\n\t\t}\n\n\t\t@Nullable Map<String, String> getValues() {\n\t\t\treturn Collections.unmodifiableMap(this.values);\n\t\t}\n\n\t}\n\n\tstatic class MapWithWildcardProperties {\n\n\t\tprivate @Nullable Map<String, ? extends List<? extends InetAddress>> addresses;\n\n\t\t@Nullable Map<String, ? extends List<? extends InetAddress>> getAddresses() {\n\t\t\treturn this.addresses;\n\t\t}\n\n\t\tvoid setAddresses(@Nullable Map<String, ? extends List<? extends InetAddress>> addresses) {\n\t\t\tthis.addresses = addresses;\n\t\t}\n\n\t}\n\n\tstatic class CustomMapWithoutDefaultCtor {\n\n\t\tprivate final CustomMap customMap;\n\n\t\tCustomMapWithoutDefaultCtor(CustomMap customMap) {\n\t\t\tthis.customMap = customMap;\n\t\t}\n\n\t\tCustomMap getCustomMap() {\n\t\t\treturn this.customMap;\n\t\t}\n\n\t\tstatic final class CustomMap extends AbstractMap<String, Object> {\n\n\t\t\tprivate final String source;\n\n\t\t\tCustomMap(String source) {\n\t\t\t\tthis.source = source;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Set<Entry<String, Object>> entrySet() {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\n\t\t\tString getSource() {\n\t\t\t\treturn this.source;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tprivate static final class CustomMapConverter implements Converter<String, CustomMap> {\n\n\t\t@Override\n\t\tpublic CustomMap convert(String source) {\n\t\t\treturn new CustomMap(source);\n\t\t}\n\n\t}\n\n\tprivate static final class InvocationArgument<T> implements Answer<T> {\n\n\t\tprivate final int index;\n\n\t\tprivate InvocationArgument(int index) {\n\t\t\tthis.index = index;\n\t\t}\n\n\t\t@Override\n\t\tpublic T answer(InvocationOnMock invocation) throws Throwable {\n\t\t\treturn invocation.getArgument(this.index);\n\t\t}\n\n\t\tprivate static <T> InvocationArgument<T> index(int index) {\n\t\t\treturn new InvocationArgument<>(index);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/PropertySourcesPlaceholdersResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.util.PropertyPlaceholderHelper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link PropertySourcesPlaceholdersResolver}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass PropertySourcesPlaceholdersResolverTests {\n\n\tprivate @Nullable PropertySourcesPlaceholdersResolver resolver;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid placeholderResolverIfEnvironmentNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PropertySourcesPlaceholdersResolver((Environment) null))\n\t\t\t.withMessageContaining(\"'environment' must not be null\");\n\t}\n\n\t@Test\n\tvoid resolveIfPlaceholderPresentResolvesProperty() {\n\t\tMutablePropertySources sources = getPropertySources();\n\t\tthis.resolver = new PropertySourcesPlaceholdersResolver(sources);\n\t\tObject resolved = this.resolver.resolvePlaceholders(\"${FOO}\");\n\t\tassertThat(resolved).isEqualTo(\"hello world\");\n\t}\n\n\t@Test\n\tvoid resolveIfPlaceholderAbsentUsesDefault() {\n\t\tthis.resolver = new PropertySourcesPlaceholdersResolver((PropertySources) null);\n\t\tObject resolved = this.resolver.resolvePlaceholders(\"${FOO:bar}\");\n\t\tassertThat(resolved).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid resolveIfPlaceholderAbsentAndNoDefaultUsesPlaceholder() {\n\t\tthis.resolver = new PropertySourcesPlaceholdersResolver((PropertySources) null);\n\t\tObject resolved = this.resolver.resolvePlaceholders(\"${FOO}\");\n\t\tassertThat(resolved).isEqualTo(\"${FOO}\");\n\t}\n\n\t@Test\n\tvoid resolveIfHelperPresentShouldUseIt() {\n\t\tMutablePropertySources sources = getPropertySources();\n\t\tTestPropertyPlaceholderHelper helper = new TestPropertyPlaceholderHelper(\"$<\", \">\");\n\t\tthis.resolver = new PropertySourcesPlaceholdersResolver(sources, helper);\n\t\tObject resolved = this.resolver.resolvePlaceholders(\"$<FOO>\");\n\t\tassertThat(resolved).isEqualTo(\"hello world\");\n\t}\n\n\tprivate MutablePropertySources getPropertySources() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"FOO\", \"hello world\");\n\t\tsources.addFirst(new MapPropertySource(\"test\", source));\n\t\treturn sources;\n\t}\n\n\tstatic class TestPropertyPlaceholderHelper extends PropertyPlaceholderHelper {\n\n\t\tTestPropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix) {\n\t\t\tsuper(placeholderPrefix, placeholderSuffix);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/ValueObjectBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind;\n\nimport java.lang.reflect.Constructor;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.time.LocalDate;\nimport java.util.ArrayList;\nimport java.util.EnumMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport com.jayway.jsonpath.JsonPath;\nimport com.jayway.jsonpath.internal.CharacterIndex;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.format.annotation.DateTimeFormat;\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ValueObjectBinder}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Pavel Anisimov\n * @author Yanming Zhou\n * @author Ondřej Světlík\n */\nclass ValueObjectBinderTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate final Binder binder = new Binder(this.sources);\n\n\t@Test\n\tvoid bindToClassShouldCreateBoundBean() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tsource.put(\"foo.long-value\", \"34\");\n\t\tsource.put(\"foo.boolean-value\", \"true\");\n\t\tsource.put(\"foo.string-value\", \"foo\");\n\t\tsource.put(\"foo.enum-value\", \"foo-bar\");\n\t\tthis.sources.add(source);\n\t\tExampleValueBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleValueBean.class)).get();\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.isBooleanValue()).isTrue();\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasNoPrefixShouldCreateBoundBean() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"int-value\", \"12\");\n\t\tsource.put(\"long-value\", \"34\");\n\t\tsource.put(\"boolean-value\", \"true\");\n\t\tsource.put(\"string-value\", \"foo\");\n\t\tsource.put(\"enum-value\", \"foo-bar\");\n\t\tthis.sources.add(source);\n\t\tExampleValueBean bean = this.binder.bind(ConfigurationPropertyName.of(\"\"), Bindable.of(ExampleValueBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.isBooleanValue()).isTrue();\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getEnumValue()).isEqualTo(ExampleEnum.FOO_BAR);\n\t}\n\n\t@Test\n\tvoid bindToAbstractClassWithShouldNotBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.name\", \"test\");\n\t\tthis.sources.add(source);\n\t\tboolean bound = this.binder.bind(\"foo\", Bindable.of(ExampleAbstractBean.class)).isBound();\n\t\tassertThat(bound).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWithMultipleConstructorsShouldNotBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tthis.sources.add(source);\n\t\tboolean bound = this.binder.bind(\"foo\", Bindable.of(MultipleConstructorsBean.class)).isBound();\n\t\tassertThat(bound).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWithMultipleConstructorsAndFilterShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tthis.sources.add(source);\n\t\tConstructor<?>[] constructors = MultipleConstructorsBean.class.getDeclaredConstructors();\n\t\tConstructor<?> constructor = (constructors[0].getParameterCount() == 1) ? constructors[0] : constructors[1];\n\t\tBinder binder = new Binder(this.sources, null, (ConversionService) null, null, null,\n\t\t\t\t(bindable, isNestedConstructorBinding) -> constructor);\n\t\tMultipleConstructorsBean bound = binder.bind(\"foo\", Bindable.of(MultipleConstructorsBean.class)).get();\n\t\tassertThat(bound.getIntValue()).isEqualTo(12);\n\t}\n\n\t@Test\n\tvoid bindToClassWithOnlyDefaultConstructorShouldNotBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tthis.sources.add(source);\n\t\tboolean bound = this.binder.bind(\"foo\", Bindable.of(DefaultConstructorBean.class)).isBound();\n\t\tassertThat(bound).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWithMultipleConstructorsWhenOnlyOneIsNotPrivateShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.int-value\", \"12\");\n\t\tthis.sources.add(source);\n\t\tMultipleConstructorsOnlyOneNotPrivateBean bean = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(MultipleConstructorsOnlyOneNotPrivateBean.class))\n\t\t\t.get();\n\t\tbean = bean.withString(\"test\");\n\t\tassertThat(bean.getIntValue()).isEqualTo(12);\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindNested() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.long-value\", \"34\");\n\t\tsource.put(\"foo.value-bean.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleNestedBean.class)).get();\n\t\tassertThat(bean.getValueBean().getIntValue()).isEqualTo(123);\n\t\tassertThat(bean.getValueBean().getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.getValueBean().isBooleanValue()).isFalse();\n\t\tassertThat(bean.getValueBean().getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getValueBean().getEnumValue()).isNull();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenNoValuesShouldNotBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source);\n\t\tassertThat(this.binder.bind(\"foo\", Bindable.of(ExampleNestedBean.class)).isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenParentOfEmptyStringAndSubValuesShouldFail() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean\", \"\");\n\t\tsource.put(\"foo.value-bean.int-value\", \"123\");\n\t\tsource.put(\"foo.value-bean.long-value\", \"34\");\n\t\tsource.put(\"foo.value-bean.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleNestedBean.class)).get();\n\t\tassertThat(bean.getValueBean().getIntValue()).isEqualTo(123);\n\t\tassertThat(bean.getValueBean().getLongValue()).isEqualTo(34);\n\t\tassertThat(bean.getValueBean().isBooleanValue()).isFalse();\n\t\tassertThat(bean.getValueBean().getStringValue()).isEqualTo(\"foo\");\n\t\tassertThat(bean.getValueBean().getEnumValue()).isNull();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenParentOfEmptyStringAndNoSubValuesShouldFail() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean\", \"\");\n\t\tthis.sources.add(source);\n\t\tExampleNestedBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleNestedBean.class)).get();\n\t\tassertThat(bean.getValueBean().getIntValue()).isEqualTo(0);\n\t\tassertThat(bean.getValueBean().getLongValue()).isEqualTo(0);\n\t\tassertThat(bean.getValueBean().isBooleanValue()).isFalse();\n\t\tassertThat(bean.getValueBean().getStringValue()).isNull();\n\t\tassertThat(bean.getValueBean().getEnumValue()).isNull();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenParentOfNullAndNoSubValuesShouldNotBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value-bean\", null);\n\t\tthis.sources.add(source);\n\t\tBindResult<ExampleNestedBean> bindResult = this.binder.bind(\"foo\", Bindable.of(ExampleNestedBean.class));\n\t\tassertThat(bindResult.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToEmptyRecordWhenParentOfEmptyString() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo\", \"\");\n\t\tthis.sources.add(source);\n\t\tEmptyRecord emptyRecord = this.binder.bind(\"foo\", Bindable.of(EmptyRecord.class)).get();\n\t\tassertThat(emptyRecord).isNotNull();\n\t}\n\n\t@Test\n\tvoid bindToClassWithNoValueForPrimitiveShouldUseDefault() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tExampleValueBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleValueBean.class)).get();\n\t\tassertThat(bean.getIntValue()).isZero();\n\t\tassertThat(bean.getLongValue()).isZero();\n\t\tassertThat(bean.isBooleanValue()).isFalse();\n\t\tassertThat(bean.getStringValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid bindToClassWithNoValueAndDefaultValueShouldNotBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.string-value\", \"foo\");\n\t\tthis.sources.add(source);\n\t\tassertThat(this.binder.bind(\"foo\", Bindable.of(ExampleDefaultValueBean.class)).isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindToClassWhenNoParameterBoundShouldReturnNull() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source.nonIterable());\n\t\tBindResult<ExampleFailingConstructorBean> result = this.binder.bind(\"foo\",\n\t\t\t\tBindable.of(ExampleFailingConstructorBean.class));\n\t\tassertThat(result.isBound()).isFalse();\n\t}\n\n\t@Test\n\tvoid bindWithAnnotations() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.date\", \"2014-04-01\");\n\t\tthis.sources.add(source);\n\t\tConverterAnnotatedExampleBean bean = this.binder.bind(\"foo\", Bindable.of(ConverterAnnotatedExampleBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getDate()).hasToString(\"2014-04-01\");\n\t}\n\n\t@Test\n\tvoid bindWithAnnotationsAndDefaultValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"hello\");\n\t\tthis.sources.add(source);\n\t\tConverterAnnotatedExampleBean bean = this.binder.bind(\"foo\", Bindable.of(ConverterAnnotatedExampleBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getDate()).hasToString(\"2019-05-10\");\n\t}\n\n\t@Test\n\tvoid bindToClassWhenHasPackagePrivateConstructorShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.property\", \"test\");\n\t\tthis.sources.add(source);\n\t\tExamplePackagePrivateConstructorBean bound = this.binder\n\t\t\t.bind(\"foo\", Bindable.of(ExamplePackagePrivateConstructorBean.class))\n\t\t\t.get();\n\t\tassertThat(bound.getProperty()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid createShouldReturnCreatedValue() {\n\t\tExampleValueBean value = this.binder.bindOrCreate(\"foo\", Bindable.of(ExampleValueBean.class));\n\t\tassertThat(value.getIntValue()).isZero();\n\t\tassertThat(value.getLongValue()).isZero();\n\t\tassertThat(value.isBooleanValue()).isFalse();\n\t\tassertThat(value.getStringValue()).isNull();\n\t\tassertThat(value.getEnumValue()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithNestedShouldReturnCreatedValue() {\n\t\tExampleNestedBean value = this.binder.bindOrCreate(\"foo\", Bindable.of(ExampleNestedBean.class));\n\t\tassertThat(value.getValueBean()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithDefaultValuesShouldReturnCreatedWithDefaultValues() {\n\t\tExampleDefaultValueBean value = this.binder.bindOrCreate(\"foo\", Bindable.of(ExampleDefaultValueBean.class));\n\t\tassertThat(value.getIntValue()).isEqualTo(5);\n\t\tassertThat(value.getStringsList()).containsOnly(\"a\", \"b\", \"c\");\n\t\tassertThat(value.getCustomList()).containsOnly(\"x,y,z\");\n\t}\n\n\t@Test\n\tvoid createWithDefaultValuesAndAnnotationsShouldReturnCreatedWithDefaultValues() {\n\t\tConverterAnnotatedExampleBean bean = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(ConverterAnnotatedExampleBean.class));\n\t\tassertThat(bean.getDate()).hasToString(\"2019-05-10\");\n\t}\n\n\t@Test\n\tvoid bindWhenAllPropertiesBoundShouldClearConfigurationProperty() { // gh-18704\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"hello\");\n\t\tthis.sources.add(source);\n\t\tBindable<ValidatingConstructorBean> target = Bindable.of(ValidatingConstructorBean.class);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bind(\"foo\", target))\n\t\t\t.satisfies(this::noConfigurationProperty);\n\t}\n\n\t@Test\n\tvoid bindToClassShouldBindWithGenerics() {\n\t\t// gh-19156\n\t\tResolvableType type = ResolvableType.forClassWithGenerics(Map.class, String.class, String.class);\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.value.bar\", \"baz\");\n\t\tthis.sources.add(source);\n\t\tGenericValue<Map<String, String>> bean = this.binder\n\t\t\t.bind(\"foo\", Bindable\n\t\t\t\t.<GenericValue<Map<String, String>>>of(ResolvableType.forClassWithGenerics(GenericValue.class, type)))\n\t\t\t.get();\n\t\tassertThat(bean.getValue()).containsEntry(\"bar\", \"baz\");\n\t}\n\n\t@Test\n\tvoid bindWhenParametersWithDefaultValueShouldReturnNonNullValues() {\n\t\tNestedConstructorBeanWithDefaultValue bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(NestedConstructorBeanWithDefaultValue.class));\n\t\tassertThat(bound.getNestedImmutable().getFoo()).isEqualTo(\"hello\");\n\t\tassertThat(bound.getNestedJavaBean()).isNotNull();\n\t}\n\n\t@Test\n\tvoid bindWhenJavaLangParameterWithEmptyDefaultValueShouldThrowException() {\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bindOrCreate(\"foo\",\n\t\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForJavaLangTypes.class)))\n\t\t\t.withStackTraceContaining(\"Parameter of type java.lang.String must have a non-empty default value.\");\n\t}\n\n\t@Test\n\tvoid bindWhenCollectionParameterWithEmptyDefaultValueShouldReturnEmptyInstance() {\n\t\tNestedConstructorBeanWithEmptyDefaultValueForCollectionTypes bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForCollectionTypes.class));\n\t\tassertThat(bound.getListValue()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenMapParametersWithEmptyDefaultValueShouldReturnEmptyInstance() {\n\t\tNestedConstructorBeanWithEmptyDefaultValueForMapTypes bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForMapTypes.class));\n\t\tassertThat(bound.getMapValue()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenEnumMapParametersWithEmptyDefaultValueShouldReturnEmptyInstance() {\n\t\tNestedConstructorBeanWithEmptyDefaultValueForEnumMapTypes bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForEnumMapTypes.class));\n\t\tassertThat(bound.getMapValue()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenArrayParameterWithEmptyDefaultValueShouldReturnEmptyInstance() {\n\t\tNestedConstructorBeanWithEmptyDefaultValueForArrayTypes bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForArrayTypes.class));\n\t\tassertThat(bound.getArrayValue()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenOptionalParameterWithEmptyDefaultValueShouldReturnEmptyInstance() {\n\t\tNestedConstructorBeanWithEmptyDefaultValueForOptionalTypes bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForOptionalTypes.class));\n\t\tassertThat(bound.getOptionalValue()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenOptionalParameterWithNoValueForPrimitiveShouldReturnEmptyInstance() {\n\t\tRecordPropertiesWithOptional bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(RecordPropertiesWithOptional.class));\n\t\tassertThat(bound.property1()).isEmpty();\n\t}\n\n\t@Test\n\tvoid bindWhenOptionalParameterInNestedWithNoValueForPrimitiveShouldReturnEmptyInstance() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.nested.property2\", \"str\");\n\t\tthis.sources.add(source);\n\t\tRecordPropertiesWithOptionalInNestedRecord bound = this.binder.bindOrCreate(\"foo\",\n\t\t\t\tBindable.of(RecordPropertiesWithOptionalInNestedRecord.class));\n\t\tassertThat(bound.nested()).isNotNull();\n\t\tassertThat(bound.nested().property1()).isEmpty();\n\t\tassertThat(bound.nested().property2()).isEqualTo(\"str\");\n\t}\n\n\t@Test\n\tvoid bindWhenEnumParameterWithEmptyDefaultValueShouldThrowException() {\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bindOrCreate(\"foo\",\n\t\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForEnumTypes.class)))\n\t\t\t.withStackTraceContaining(\n\t\t\t\t\t\"Parameter of type org.springframework.boot.context.properties.bind.ValueObjectBinderTests$NestedConstructorBeanWithEmptyDefaultValueForEnumTypes$Foo must have a non-empty default value.\");\n\t}\n\n\t@Test\n\tvoid bindWhenPrimitiveParameterWithEmptyDefaultValueShouldThrowException() {\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bindOrCreate(\"foo\",\n\t\t\t\t\tBindable.of(NestedConstructorBeanWithEmptyDefaultValueForPrimitiveTypes.class)))\n\t\t\t.withStackTraceContaining(\"Parameter of type int must have a non-empty default value.\");\n\t}\n\n\t@Test\n\tvoid bindWhenBindingToPathTypeWithValue() { // gh-21263\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.name\", \"test\");\n\t\tsource.put(\"test.path\", \"specific_value\");\n\t\tthis.sources.add(source);\n\t\tBindable<PathBean> target = Bindable.of(PathBean.class);\n\t\tPathBean bound = this.binder.bind(\"test\", target).get();\n\t\tassertThat(bound.getName()).isEqualTo(\"test\");\n\t\tassertThat(bound.getPath()).isEqualTo(Paths.get(\"specific_value\"));\n\t}\n\n\t@Test\n\tvoid bindWhenBindingToPathTypeWithDefaultValue() { // gh-21263\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.name\", \"test\");\n\t\tthis.sources.add(source);\n\t\tBindable<PathBean> target = Bindable.of(PathBean.class);\n\t\tPathBean bound = this.binder.bindOrCreate(\"test\", target);\n\t\tassertThat(bound.getName()).isEqualTo(\"test\");\n\t\tassertThat(bound.getPath()).isEqualTo(Paths.get(\"default_value\"));\n\t}\n\n\t@Test\n\tvoid bindToAnnotationNamedConstructorParameter() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.import\", \"test\");\n\t\tthis.sources.add(source);\n\t\tBindable<NamedConstructorParameter> target = Bindable.of(NamedConstructorParameter.class);\n\t\tNamedConstructorParameter bound = this.binder.bindOrCreate(\"test\", target);\n\t\tassertThat(bound.getImportName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid bindToAnnotationNamedRecordComponent() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.import\", \"test\");\n\t\tthis.sources.add(source);\n\t\tBindable<NamedRecordComponent> target = Bindable.of(NamedRecordComponent.class);\n\t\tNamedRecordComponent bound = this.binder.bindOrCreate(\"test\", target);\n\t\tassertThat(bound.importName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid bindToRecordWithDefaultValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.property1\", \"value-from-config-1\");\n\t\tthis.sources.add(source);\n\t\tBindable<RecordProperties> target = Bindable.of(RecordProperties.class);\n\t\tRecordProperties bound = this.binder.bindOrCreate(\"test\", target);\n\t\tassertThat(bound.property1()).isEqualTo(\"value-from-config-1\");\n\t\tassertThat(bound.property2()).isEqualTo(\"default-value-2\");\n\t}\n\n\t@Test // gh-38201\n\tvoid bindWhenNonExtractableParameterNamesOnPropertyAndNonIterablePropertySource() throws Exception {\n\t\tverifyJsonPathParametersCannotBeResolved();\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.value\", \"test\");\n\t\tthis.sources.add(source.nonIterable());\n\t\tBindable<NonExtractableParameterName> target = Bindable.of(NonExtractableParameterName.class);\n\t\tNonExtractableParameterName bound = this.binder.bindOrCreate(\"test\", target);\n\t\tassertThat(bound.getValue()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid createWhenNonExtractableParameterNamesOnPropertyAndNonIterablePropertySource() throws Exception {\n\t\tassertThat(new DefaultParameterNameDiscoverer()\n\t\t\t.getParameterNames(CharacterIndex.class.getDeclaredConstructor(CharSequence.class))).isNull();\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tthis.sources.add(source.nonIterable());\n\t\tBindable<CharacterIndex> target = Bindable.of(CharacterIndex.class).withBindMethod(BindMethod.VALUE_OBJECT);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> this.binder.bindOrCreate(\"test\", target))\n\t\t\t.withStackTraceContaining(\"Ensure that the compiler uses the '-parameters' flag\");\n\t}\n\n\tprivate void verifyJsonPathParametersCannotBeResolved() throws NoSuchFieldException {\n\t\tClass<?> jsonPathClass = NonExtractableParameterName.class.getDeclaredField(\"jsonPath\").getType();\n\t\tConstructor<?>[] constructors = jsonPathClass.getDeclaredConstructors();\n\t\tassertThat(constructors).hasSize(1);\n\t\tconstructors[0].setAccessible(true);\n\t\tassertThat(new DefaultParameterNameDiscoverer().getParameterNames(constructors[0])).isNull();\n\t}\n\n\tprivate void noConfigurationProperty(BindException ex) {\n\t\tassertThat(ex.getProperty()).isNull();\n\t}\n\n\tstatic class ExampleValueBean {\n\n\t\tprivate final int intValue;\n\n\t\tprivate final long longValue;\n\n\t\tprivate final boolean booleanValue;\n\n\t\tprivate final String stringValue;\n\n\t\tprivate final ExampleEnum enumValue;\n\n\t\tExampleValueBean(int intValue, long longValue, boolean booleanValue, String stringValue,\n\t\t\t\tExampleEnum enumValue) {\n\t\t\tthis.intValue = intValue;\n\t\t\tthis.longValue = longValue;\n\t\t\tthis.booleanValue = booleanValue;\n\t\t\tthis.stringValue = stringValue;\n\t\t\tthis.enumValue = enumValue;\n\t\t}\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tlong getLongValue() {\n\t\t\treturn this.longValue;\n\t\t}\n\n\t\tboolean isBooleanValue() {\n\t\t\treturn this.booleanValue;\n\t\t}\n\n\t\tString getStringValue() {\n\t\t\treturn this.stringValue;\n\t\t}\n\n\t\tExampleEnum getEnumValue() {\n\t\t\treturn this.enumValue;\n\t\t}\n\n\t}\n\n\tpublic enum ExampleEnum {\n\n\t\tFOO_BAR,\n\n\t\tBAR_BAZ\n\n\t}\n\n\tstatic class MultipleConstructorsBean {\n\n\t\tprivate final int intValue;\n\n\t\tMultipleConstructorsBean(int intValue) {\n\t\t\tthis(intValue, 23L, \"hello\");\n\t\t}\n\n\t\tMultipleConstructorsBean(int intValue, long longValue, String stringValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t}\n\n\tstatic class MultipleConstructorsOnlyOneNotPrivateBean {\n\n\t\tprivate final int intValue;\n\n\t\tprivate final String stringValue;\n\n\t\tMultipleConstructorsOnlyOneNotPrivateBean(int intValue) {\n\t\t\tthis(intValue, 23L, \"hello\");\n\t\t}\n\n\t\tprivate MultipleConstructorsOnlyOneNotPrivateBean(int intValue, long longValue, String stringValue) {\n\t\t\tthis.intValue = intValue;\n\t\t\tthis.stringValue = stringValue;\n\t\t}\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tString getStringValue() {\n\t\t\treturn this.stringValue;\n\t\t}\n\n\t\tMultipleConstructorsOnlyOneNotPrivateBean withString(String stringValue) {\n\t\t\treturn new MultipleConstructorsOnlyOneNotPrivateBean(this.intValue, 0, stringValue);\n\t\t}\n\n\t}\n\n\tabstract static class ExampleAbstractBean {\n\n\t\tprivate final String name;\n\n\t\tExampleAbstractBean(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic class DefaultConstructorBean {\n\n\t\tDefaultConstructorBean() {\n\t\t}\n\n\t}\n\n\tstatic class ExampleNestedBean {\n\n\t\tprivate final ExampleValueBean valueBean;\n\n\t\tExampleNestedBean(ExampleValueBean valueBean) {\n\t\t\tthis.valueBean = valueBean;\n\t\t}\n\n\t\tExampleValueBean getValueBean() {\n\t\t\treturn this.valueBean;\n\t\t}\n\n\t}\n\n\tstatic class ExampleDefaultValueBean {\n\n\t\tprivate final int intValue;\n\n\t\tprivate final List<String> stringsList;\n\n\t\tprivate final List<String> customList;\n\n\t\tExampleDefaultValueBean(@DefaultValue(\"5\") int intValue,\n\t\t\t\t@DefaultValue({ \"a\", \"b\", \"c\" }) List<String> stringsList,\n\t\t\t\t@DefaultValue(\"x,y,z\") List<String> customList) {\n\t\t\tthis.intValue = intValue;\n\t\t\tthis.stringsList = stringsList;\n\t\t\tthis.customList = customList;\n\t\t}\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tList<String> getStringsList() {\n\t\t\treturn this.stringsList;\n\t\t}\n\n\t\tList<String> getCustomList() {\n\t\t\treturn this.customList;\n\t\t}\n\n\t}\n\n\tstatic class ExampleFailingConstructorBean {\n\n\t\tprivate final String name;\n\n\t\tprivate final Object value;\n\n\t\tExampleFailingConstructorBean(String name, String value) {\n\t\t\tAssert.notNull(name, \"'name' must be not null.\");\n\t\t\tAssert.notNull(value, \"'value' must be not null.\");\n\t\t\tthis.name = name;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tObject getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\tstatic class ConverterAnnotatedExampleBean {\n\n\t\tprivate final LocalDate date;\n\n\t\tprivate final String bar;\n\n\t\tConverterAnnotatedExampleBean(\n\t\t\t\t@DefaultValue(\"2019-05-10\") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date, String bar) {\n\t\t\tthis.date = date;\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tLocalDate getDate() {\n\t\t\treturn this.date;\n\t\t}\n\n\t\tString getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t}\n\n\tstatic class ExamplePackagePrivateConstructorBean {\n\n\t\tprivate final String property;\n\n\t\tExamplePackagePrivateConstructorBean(String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t\tString getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t}\n\n\tstatic class ValidatingConstructorBean {\n\n\t\tprivate final String foo;\n\n\t\tprivate final String bar;\n\n\t\tValidatingConstructorBean(String foo, String bar) {\n\t\t\tAssert.notNull(foo, \"'foo' must not be null\");\n\t\t\tthis.foo = foo;\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tString getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tString getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t}\n\n\tstatic class GenericValue<T> {\n\n\t\tprivate final T value;\n\n\t\tGenericValue(T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tT getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithDefaultValue {\n\n\t\tprivate final NestedImmutable nestedImmutable;\n\n\t\tprivate final NestedJavaBean nestedJavaBean;\n\n\t\tNestedConstructorBeanWithDefaultValue(@DefaultValue NestedImmutable nestedImmutable,\n\t\t\t\t@DefaultValue NestedJavaBean nestedJavaBean) {\n\t\t\tthis.nestedImmutable = nestedImmutable;\n\t\t\tthis.nestedJavaBean = nestedJavaBean;\n\t\t}\n\n\t\tNestedImmutable getNestedImmutable() {\n\t\t\treturn this.nestedImmutable;\n\t\t}\n\n\t\tNestedJavaBean getNestedJavaBean() {\n\t\t\treturn this.nestedJavaBean;\n\t\t}\n\n\t}\n\n\tstatic class NestedImmutable {\n\n\t\tprivate final String foo;\n\n\t\tprivate final String bar;\n\n\t\tNestedImmutable(@DefaultValue(\"hello\") String foo, String bar) {\n\t\t\tthis.foo = foo;\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tString getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tString getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t}\n\n\tstatic class NestedJavaBean {\n\n\t\tprivate @Nullable String value;\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForJavaLangTypes {\n\n\t\tprivate final String stringValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForJavaLangTypes(@DefaultValue String stringValue) {\n\t\t\tthis.stringValue = stringValue;\n\t\t}\n\n\t\tString getStringValue() {\n\t\t\treturn this.stringValue;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForCollectionTypes {\n\n\t\tprivate final List<String> listValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForCollectionTypes(@DefaultValue List<String> listValue) {\n\t\t\tthis.listValue = listValue;\n\t\t}\n\n\t\tList<String> getListValue() {\n\t\t\treturn this.listValue;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForMapTypes {\n\n\t\tprivate final Map<String, String> mapValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForMapTypes(@DefaultValue Map<String, String> mapValue) {\n\t\t\tthis.mapValue = mapValue;\n\t\t}\n\n\t\tMap<String, String> getMapValue() {\n\t\t\treturn this.mapValue;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForEnumMapTypes {\n\n\t\tprivate final EnumMap<ExampleEnum, String> mapValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForEnumMapTypes(@DefaultValue EnumMap<ExampleEnum, String> mapValue) {\n\t\t\tthis.mapValue = mapValue;\n\t\t}\n\n\t\tEnumMap<ExampleEnum, String> getMapValue() {\n\t\t\treturn this.mapValue;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForArrayTypes {\n\n\t\tprivate final String[] arrayValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForArrayTypes(@DefaultValue String[] arrayValue) {\n\t\t\tthis.arrayValue = arrayValue;\n\t\t}\n\n\t\tString[] getArrayValue() {\n\t\t\treturn this.arrayValue;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForOptionalTypes {\n\n\t\tprivate final Optional<String> optionalValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForOptionalTypes(@DefaultValue Optional<String> optionalValue) {\n\t\t\tthis.optionalValue = optionalValue;\n\t\t}\n\n\t\tOptional<String> getOptionalValue() {\n\t\t\treturn this.optionalValue;\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForEnumTypes {\n\n\t\tprivate final Foo foo;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForEnumTypes(@DefaultValue Foo foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t\tFoo getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tenum Foo {\n\n\t\t\tBAR, BAZ\n\n\t\t}\n\n\t}\n\n\tstatic class NestedConstructorBeanWithEmptyDefaultValueForPrimitiveTypes {\n\n\t\tprivate final int intValue;\n\n\t\tNestedConstructorBeanWithEmptyDefaultValueForPrimitiveTypes(@DefaultValue int intValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t\tint getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t}\n\n\tstatic class PathBean {\n\n\t\tprivate final String name;\n\n\t\tprivate final Path path;\n\n\t\tPathBean(String name, @DefaultValue(\"default_value\") Path path) {\n\t\t\tthis.name = name;\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tPath getPath() {\n\t\t\treturn this.path;\n\t\t}\n\n\t}\n\n\tstatic class NamedConstructorParameter {\n\n\t\tprivate final String importName;\n\n\t\tNamedConstructorParameter(@Name(\"import\") String importName) {\n\t\t\tthis.importName = importName;\n\t\t}\n\n\t\tString getImportName() {\n\t\t\treturn this.importName;\n\t\t}\n\n\t}\n\n\trecord NamedRecordComponent(@Name(\"import\") String importName) {\n\t}\n\n\trecord RecordProperties(@DefaultValue(\"default-value-1\") String property1,\n\t\t\t@DefaultValue(\"default-value-2\") String property2) {\n\t}\n\n\trecord RecordPropertiesWithOptional(Optional<String> property1) {\n\t}\n\n\trecord RecordPropertiesWithOptionalInNestedRecord(NestedRecord nested) {\n\t\trecord NestedRecord(Optional<String> property1, String property2) {\n\t\t}\n\t}\n\n\tstatic class NonExtractableParameterName {\n\n\t\tprivate @Nullable String value;\n\n\t\tprivate @Nullable JsonPath jsonPath;\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Nullable JsonPath getJsonPath() {\n\t\t\treturn this.jsonPath;\n\t\t}\n\n\t\tvoid setJsonPath(@Nullable JsonPath jsonPath) {\n\t\t\tthis.jsonPath = jsonPath;\n\t\t}\n\n\t}\n\n\trecord EmptyRecord() {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/IgnoreErrorsBindHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link IgnoreErrorsBindHandler}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass IgnoreErrorsBindHandlerTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate Binder binder;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t}\n\n\t@Test\n\tvoid bindWhenNotIgnoringErrorsShouldFail() {\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"example\", Bindable.of(Example.class)));\n\t}\n\n\t@Test\n\tvoid bindWhenIgnoringErrorsShouldBind() {\n\t\tExample bound = this.binder.bind(\"example\", Bindable.of(Example.class), new IgnoreErrorsBindHandler()).get();\n\t\tassertThat(bound.getFoo()).isZero();\n\t}\n\n\tstatic class Example {\n\n\t\tprivate int foo;\n\n\t\tint getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(int foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/IgnoreTopLevelConverterNotFoundBindHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.core.convert.ConverterNotFoundException;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link IgnoreTopLevelConverterNotFoundBindHandler}.\n *\n * @author Madhura Bhave\n */\nclass IgnoreTopLevelConverterNotFoundBindHandlerTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate Binder binder;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t}\n\n\t@Test\n\tvoid bindWhenHandlerNotPresentShouldFail() {\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"example\", Bindable.of(Example.class)))\n\t\t\t.withCauseInstanceOf(ConverterNotFoundException.class);\n\t}\n\n\t@Test\n\tvoid bindWhenTopLevelContextAndExceptionIgnorableShouldNotFail() {\n\t\tthis.binder.bind(\"example\", Bindable.of(Example.class), new IgnoreTopLevelConverterNotFoundBindHandler());\n\t}\n\n\t@Test\n\tvoid bindWhenExceptionNotIgnorableShouldFail() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"1\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"example\", Bindable.of(Example.class),\n\t\t\t\t\tnew IgnoreTopLevelConverterNotFoundBindHandler()))\n\t\t\t.withCauseInstanceOf(IllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid bindWhenExceptionInNestedContextShouldFail() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.map\", \"hello\");\n\t\tthis.sources.add(source);\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"example\", Bindable.of(Example.class),\n\t\t\t\t\tnew IgnoreTopLevelConverterNotFoundBindHandler()))\n\t\t\t.withCauseInstanceOf(ConverterNotFoundException.class);\n\t}\n\n\tstatic class Example {\n\n\t\tprivate int foo;\n\n\t\tprivate @Nullable Map<String, String> map;\n\n\t\tint getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(int foo) {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t\t@Nullable Map<String, String> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tvoid setMap(@Nullable Map<String, String> map) {\n\t\t\tthis.map = map;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/handler/NoUnboundElementsBindHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.handler;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.BindHandler;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link NoUnboundElementsBindHandler}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass NoUnboundElementsBindHandlerTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate @Nullable Binder binder;\n\n\t@Test\n\tvoid bindWhenNotUsingNoUnboundElementsHandlerShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"bar\");\n\t\tsource.put(\"example.baz\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t\tExample bound = this.binder.bind(ConfigurationPropertyName.of(\"example\"), Bindable.of(Example.class)).get();\n\t\tassertThat(bound.getFoo()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerShouldBind() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t\tExample bound = this.binder.bind(\"example\", Bindable.of(Example.class), new NoUnboundElementsBindHandler())\n\t\t\t.get();\n\t\tassertThat(bound.getFoo()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"bar\");\n\t\tsource.put(\"example.baz\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.binder).isNotNull();\n\t\t\tthis.binder.bind(\"example\", Bindable.of(Example.class), new NoUnboundElementsBindHandler());\n\t\t}).satisfies((ex) -> {\n\t\t\tThrowable cause = ex.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\tassertThat(cause.getMessage()).contains(\"The elements [example.baz] were left unbound\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerShouldBindIfPrefixDifferent() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"bar\");\n\t\tsource.put(\"other.baz\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t\tExample bound = this.binder.bind(\"example\", Bindable.of(Example.class), new NoUnboundElementsBindHandler())\n\t\t\t.get();\n\t\tassertThat(bound.getFoo()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerShouldBindIfUnboundSystemProperties() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo\", \"bar\");\n\t\tsource.put(\"example.other\", \"baz\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t\tNoUnboundElementsBindHandler handler = new NoUnboundElementsBindHandler(BindHandler.DEFAULT,\n\t\t\t\t((configurationPropertySource) -> false));\n\t\tExample bound = this.binder.bind(\"example\", Bindable.of(Example.class), handler).get();\n\t\tassertThat(bound.getFoo()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerShouldBindIfUnboundCollectionProperties() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"example.foo[0]\", \"bar\");\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"example.foo[0]\", \"bar\");\n\t\tsource2.put(\"example.foo[1]\", \"baz\");\n\t\tthis.sources.add(source1);\n\t\tthis.sources.add(source2);\n\t\tthis.binder = new Binder(this.sources);\n\t\tNoUnboundElementsBindHandler handler = new NoUnboundElementsBindHandler();\n\t\tExampleWithList bound = this.binder.bind(\"example\", Bindable.of(ExampleWithList.class), handler).get();\n\t\tassertThat(bound.getFoo()).containsExactly(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerAndUnboundListElementsShouldThrowException() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"example.foo[0]\", \"bar\");\n\t\tthis.sources.add(source);\n\t\tthis.binder = new Binder(this.sources);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.binder).isNotNull();\n\t\t\tthis.binder.bind(\"example\", Bindable.of(Example.class), new NoUnboundElementsBindHandler());\n\t\t}).satisfies((ex) -> {\n\t\t\tThrowable cause = ex.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\tassertThat(cause.getMessage()).contains(\"The elements [example.foo[0]] were left unbound\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerShouldBindIfUnboundNestedCollectionProperties() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"example.nested[0].string-value\", \"bar\");\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"example.nested[0].string-value\", \"bar\");\n\t\tsource2.put(\"example.nested[0].int-value\", \"2\");\n\t\tsource2.put(\"example.nested[1].string-value\", \"baz\");\n\t\tsource2.put(\"example.nested[1].other-nested.baz\", \"baz\");\n\t\tthis.sources.add(source1);\n\t\tthis.sources.add(source2);\n\t\tthis.binder = new Binder(this.sources);\n\t\tNoUnboundElementsBindHandler handler = new NoUnboundElementsBindHandler();\n\t\tExampleWithNestedList bound = this.binder.bind(\"example\", Bindable.of(ExampleWithNestedList.class), handler)\n\t\t\t.get();\n\t\tList<Nested> nested = bound.getNested();\n\t\tassertThat(nested).isNotNull();\n\t\tassertThat(nested.get(0).getStringValue()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid bindWhenUsingNoUnboundElementsHandlerAndUnboundCollectionElementsWithInvalidPropertyShouldThrowException() {\n\t\tMockConfigurationPropertySource source1 = new MockConfigurationPropertySource();\n\t\tsource1.put(\"example.nested[0].string-value\", \"bar\");\n\t\tMockConfigurationPropertySource source2 = new MockConfigurationPropertySource();\n\t\tsource2.put(\"example.nested[0].string-value\", \"bar\");\n\t\tsource2.put(\"example.nested[1].int-value\", \"1\");\n\t\tsource2.put(\"example.nested[1].invalid\", \"baz\");\n\t\tthis.sources.add(source1);\n\t\tthis.sources.add(source2);\n\t\tthis.binder = new Binder(this.sources);\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.binder).isNotNull();\n\t\t\tthis.binder.bind(\"example\", Bindable.of(ExampleWithNestedList.class), new NoUnboundElementsBindHandler());\n\t\t}).satisfies((ex) -> {\n\t\t\tThrowable cause = ex.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\tassertThat(cause.getMessage()).contains(\"The elements [example.nested[1].invalid] were left unbound\");\n\t\t});\n\t}\n\n\tstatic class Example {\n\n\t\tprivate @Nullable String foo;\n\n\t\t@Nullable String getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(@Nullable String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithList {\n\n\t\tprivate @Nullable List<String> foo;\n\n\t\t@Nullable List<String> getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(@Nullable List<String> foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithNestedList {\n\n\t\tprivate @Nullable List<Nested> nested;\n\n\t\t@Nullable List<Nested> getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(@Nullable List<Nested> nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t}\n\n\tstatic class Nested {\n\n\t\tprivate @Nullable String stringValue;\n\n\t\tprivate @Nullable Integer intValue;\n\n\t\tprivate @Nullable OtherNested otherNested;\n\n\t\t@Nullable String getStringValue() {\n\t\t\treturn this.stringValue;\n\t\t}\n\n\t\tvoid setStringValue(@Nullable String value) {\n\t\t\tthis.stringValue = value;\n\t\t}\n\n\t\t@Nullable Integer getIntValue() {\n\t\t\treturn this.intValue;\n\t\t}\n\n\t\tvoid setIntValue(@Nullable Integer intValue) {\n\t\t\tthis.intValue = intValue;\n\t\t}\n\n\t\t@Nullable OtherNested getOtherNested() {\n\t\t\treturn this.otherNested;\n\t\t}\n\n\t\tvoid setOtherNested(@Nullable OtherNested otherNested) {\n\t\t\tthis.otherNested = otherNested;\n\t\t}\n\n\t}\n\n\tstatic class OtherNested {\n\n\t\tprivate @Nullable String baz;\n\n\t\t@Nullable String getBaz() {\n\t\t\treturn this.baz;\n\t\t}\n\n\t\tvoid setBaz(@Nullable String baz) {\n\t\t\tthis.baz = baz;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/test/PackagePrivateBeanBindingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.test;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Binder} using package private Java beans.\n *\n * @author Madhura Bhave\n */\nclass PackagePrivateBeanBindingTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate Binder binder;\n\n\tprivate ConfigurationPropertyName name;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.binder = new Binder(this.sources);\n\t\tthis.name = ConfigurationPropertyName.of(\"foo\");\n\t}\n\n\t@Test\n\tvoid bindToPackagePrivateClassShouldBindToInstance() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"999\");\n\t\tthis.sources.add(source);\n\t\tExamplePackagePrivateBean bean = this.binder.bind(this.name, Bindable.of(ExamplePackagePrivateBean.class))\n\t\t\t.get();\n\t\tassertThat(bean.getBar()).isEqualTo(999);\n\t}\n\n\tstatic class ExamplePackagePrivateBean {\n\n\t\tprivate int bar;\n\n\t\tint getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tvoid setBar(int bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/test/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.properties.bind.test;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/BindValidationExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BindValidationException}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass BindValidationExceptionTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenValidationErrorsIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new BindValidationException(null))\n\t\t\t.withMessageContaining(\"'validationErrors' must not be null\");\n\t}\n\n\t@Test\n\tvoid getValidationErrorsShouldReturnValidationErrors() {\n\t\tValidationErrors errors = mock(ValidationErrors.class);\n\t\tBindValidationException exception = new BindValidationException(errors);\n\t\tassertThat(exception.getValidationErrors()).isEqualTo(errors);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/OriginTrackedFieldErrorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.MockOrigin;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.validation.FieldError;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OriginTrackedFieldError}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass OriginTrackedFieldErrorTests {\n\n\tprivate static final FieldError FIELD_ERROR = new FieldError(\"foo\", \"bar\", \"faf\");\n\n\tprivate static final Origin ORIGIN = MockOrigin.of(\"afile\");\n\n\t@Test\n\tvoid ofWhenFieldErrorIsNullShouldReturnNull() {\n\t\tassertThat(OriginTrackedFieldError.of(null, ORIGIN)).isNull();\n\t}\n\n\t@Test\n\tvoid ofWhenOriginIsNullShouldReturnFieldErrorWithoutOrigin() {\n\t\tassertThat(OriginTrackedFieldError.of(FIELD_ERROR, null)).isSameAs(FIELD_ERROR);\n\t}\n\n\t@Test\n\tvoid ofShouldReturnOriginCapableFieldError() {\n\t\tFieldError fieldError = OriginTrackedFieldError.of(FIELD_ERROR, ORIGIN);\n\t\tassertThat(fieldError.getObjectName()).isEqualTo(\"foo\");\n\t\tassertThat(fieldError.getField()).isEqualTo(\"bar\");\n\t\tassertThat(Origin.from(fieldError)).isEqualTo(ORIGIN);\n\t}\n\n\t@Test\n\tvoid toStringShouldAddOrigin() {\n\t\tassertThat(OriginTrackedFieldError.of(FIELD_ERROR, ORIGIN))\n\t\t\t.hasToString(\"Field error in object 'foo' on field 'bar': rejected value [null]\"\n\t\t\t\t\t+ \"; codes []; arguments []; default message [faf]; origin afile\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport jakarta.validation.Valid;\nimport jakarta.validation.constraints.Min;\nimport jakarta.validation.constraints.NotNull;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.AbstractBindHandler;\nimport org.springframework.boot.context.properties.bind.BindContext;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.validation.ValidationUtils;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ValidationBindHandler}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ValidationBindHandlerTests {\n\n\tprivate final List<ConfigurationPropertySource> sources = new ArrayList<>();\n\n\tprivate ValidationBindHandler handler;\n\n\tprivate Binder binder;\n\n\tprivate LocalValidatorFactoryBean validator;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.binder = new Binder(this.sources);\n\t\tthis.validator = new LocalValidatorFactoryBean();\n\t\tthis.validator.afterPropertiesSet();\n\t\tthis.handler = new ValidationBindHandler(this.validator);\n\t}\n\n\t@Test\n\tvoid bindShouldBindWithoutHandler() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.age\", 4));\n\t\tExampleValidatedBean bean = this.binder.bind(\"foo\", Bindable.of(ExampleValidatedBean.class)).get();\n\t\tassertThat(bean.getAge()).isEqualTo(4);\n\t}\n\n\t@Test\n\tvoid bindShouldFailWithHandler() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.age\", 4));\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleValidatedBean.class), this.handler))\n\t\t\t.withCauseInstanceOf(BindValidationException.class);\n\t}\n\n\t@Test\n\tvoid bindShouldValidateNestedProperties() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.nested.age\", 4));\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleValidatedWithNestedBean.class), this.handler))\n\t\t\t.withCauseInstanceOf(BindValidationException.class);\n\t}\n\n\t@Test\n\tvoid bindShouldFailWithAccessToOrigin() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.age\", 4, \"file\"));\n\t\tBindValidationException cause = bindAndExpectValidationError(() -> this.binder\n\t\t\t.bind(ConfigurationPropertyName.of(\"foo\"), Bindable.of(ExampleValidatedBean.class), this.handler));\n\t\tObjectError objectError = cause.getValidationErrors().getAllErrors().get(0);\n\t\tassertThat(Origin.from(objectError)).hasToString(\"file\");\n\t}\n\n\t@Test\n\tvoid bindShouldFailWithAccessToBoundProperties() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.nested.name\", \"baz\");\n\t\tsource.put(\"foo.nested.age\", \"4\");\n\t\tsource.put(\"faf.bar\", \"baz\");\n\t\tthis.sources.add(source);\n\t\tBindValidationException cause = bindAndExpectValidationError(() -> this.binder.bind(\n\t\t\t\tConfigurationPropertyName.of(\"foo\"), Bindable.of(ExampleValidatedWithNestedBean.class), this.handler));\n\t\tSet<ConfigurationProperty> boundProperties = cause.getValidationErrors().getBoundProperties();\n\t\tassertThat(boundProperties).extracting((p) -> p.getName().toString())\n\t\t\t.contains(\"foo.nested.age\", \"foo.nested.name\");\n\t}\n\n\t@Test\n\tvoid bindShouldFailWithAccessToNameAndValue() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.nested.age\", \"4\"));\n\t\tBindValidationException cause = bindAndExpectValidationError(() -> this.binder.bind(\n\t\t\t\tConfigurationPropertyName.of(\"foo\"), Bindable.of(ExampleValidatedWithNestedBean.class), this.handler));\n\t\tassertThat(cause.getValidationErrors().getName()).hasToString(\"foo.nested\");\n\t\tassertThat(cause.getMessage()).contains(\"nested.age\");\n\t\tassertThat(cause.getMessage()).contains(\"rejected value [4]\");\n\t}\n\n\t@Test\n\tvoid bindShouldFailIfExistingValueIsInvalid() {\n\t\tExampleValidatedBean existingValue = new ExampleValidatedBean();\n\t\tBindValidationException cause = bindAndExpectValidationError(\n\t\t\t\t() -> this.binder.bind(ConfigurationPropertyName.of(\"foo\"),\n\t\t\t\t\t\tBindable.of(ExampleValidatedBean.class).withExistingValue(existingValue), this.handler));\n\t\tFieldError fieldError = (FieldError) cause.getValidationErrors().getAllErrors().get(0);\n\t\tassertThat(fieldError.getField()).isEqualTo(\"age\");\n\t}\n\n\t@Test\n\tvoid bindShouldValidateWithoutAnnotation() {\n\t\tExampleNonValidatedBean existingValue = new ExampleNonValidatedBean();\n\t\tbindAndExpectValidationError(() -> this.binder.bind(ConfigurationPropertyName.of(\"foo\"),\n\t\t\t\tBindable.of(ExampleNonValidatedBean.class).withExistingValue(existingValue), this.handler));\n\t}\n\n\t@Test\n\tvoid bindShouldNotValidateDepthGreaterThanZero() {\n\t\t// gh-12227\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"baz\");\n\t\tthis.sources.add(source);\n\t\tExampleValidatedBeanWithGetterException existingValue = new ExampleValidatedBeanWithGetterException();\n\t\tthis.binder.bind(ConfigurationPropertyName.of(\"foo\"),\n\t\t\t\tBindable.of(ExampleValidatedBeanWithGetterException.class).withExistingValue(existingValue),\n\t\t\t\tthis.handler);\n\t}\n\n\t@Test\n\tvoid bindShouldNotValidateIfOtherHandlersInChainThrowError() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"hello\"));\n\t\tExampleValidatedBean bean = new ExampleValidatedBean();\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleValidatedBean.class).withExistingValue(bean),\n\t\t\t\t\tthis.handler))\n\t\t\t.withCauseInstanceOf(ConverterNotFoundException.class);\n\t}\n\n\t@Test\n\tvoid bindShouldValidateIfOtherHandlersInChainIgnoreError() {\n\t\tTestHandler testHandler = new TestHandler(null);\n\t\tthis.handler = new ValidationBindHandler(testHandler, this.validator);\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"hello\"));\n\t\tExampleValidatedBean bean = new ExampleValidatedBean();\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleValidatedBean.class).withExistingValue(bean),\n\t\t\t\t\tthis.handler))\n\t\t\t.withCauseInstanceOf(BindValidationException.class);\n\t}\n\n\t@Test\n\tvoid bindShouldValidateIfOtherHandlersInChainReplaceErrorWithResult() {\n\t\tTestHandler testHandler = new TestHandler(new ExampleValidatedBeanSubclass());\n\t\tthis.handler = new ValidationBindHandler(testHandler, this.validator);\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo\", \"hello\"));\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.age\", \"bad\"));\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.years\", \"99\"));\n\t\tExampleValidatedBean bean = new ExampleValidatedBean();\n\t\tassertThatExceptionOfType(BindException.class)\n\t\t\t.isThrownBy(() -> this.binder.bind(\"foo\", Bindable.of(ExampleValidatedBean.class).withExistingValue(bean),\n\t\t\t\t\tthis.handler))\n\t\t\t.withCauseInstanceOf(BindValidationException.class)\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).hasMessageContaining(\"years\"));\n\t}\n\n\t@Test\n\tvoid validationErrorsForCamelCaseFieldsShouldContainRejectedValue() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.inner.person-age\", 2));\n\t\tBindValidationException cause = bindAndExpectValidationError(() -> this.binder\n\t\t\t.bind(ConfigurationPropertyName.of(\"foo\"), Bindable.of(ExampleCamelCase.class), this.handler));\n\t\tassertThat(cause.getMessage()).contains(\"rejected value [2]\");\n\t}\n\n\t@Test\n\tvoid validationShouldBeSkippedIfPreviousValidationErrorPresent() {\n\t\tthis.sources.add(new MockConfigurationPropertySource(\"foo.inner.person-age\", 2));\n\t\tBindValidationException cause = bindAndExpectValidationError(() -> this.binder\n\t\t\t.bind(ConfigurationPropertyName.of(\"foo\"), Bindable.of(ExampleCamelCase.class), this.handler));\n\t\tFieldError fieldError = (FieldError) cause.getValidationErrors().getAllErrors().get(0);\n\t\tassertThat(fieldError.getField()).isEqualTo(\"personAge\");\n\t}\n\n\t@Test\n\tvoid validateMapValues() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"test.items.[itemOne].number\", \"one\");\n\t\tsource.put(\"test.items.[ITEM2].number\", \"two\");\n\t\tthis.sources.add(source);\n\t\tValidator validator = getMapValidator();\n\t\tthis.handler = new ValidationBindHandler(validator);\n\t\tthis.binder.bind(ConfigurationPropertyName.of(\"test\"), Bindable.of(ExampleWithMap.class), this.handler);\n\t}\n\n\t@Test\n\tvoid validateMapValuesWithNonUniformSource() {\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"test.items.itemOne.number\", \"one\");\n\t\tmap.put(\"test.items.ITEM2.number\", \"two\");\n\t\tthis.sources.add(ConfigurationPropertySources.from(new MapPropertySource(\"test\", map)).iterator().next());\n\t\tValidator validator = getMapValidator();\n\t\tthis.handler = new ValidationBindHandler(validator);\n\t\tthis.binder.bind(ConfigurationPropertyName.of(\"test\"), Bindable.of(ExampleWithMap.class), this.handler);\n\t}\n\n\tprivate Validator getMapValidator() {\n\t\treturn new Validator() {\n\n\t\t\t@Override\n\t\t\tpublic boolean supports(Class<?> type) {\n\t\t\t\treturn ExampleWithMap.class == type;\n\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void validate(Object target, Errors errors) {\n\t\t\t\tExampleWithMap value = (ExampleWithMap) target;\n\t\t\t\tvalue.getItems().forEach((k, v) -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\terrors.pushNestedPath(\"items[\" + k + \"]\");\n\t\t\t\t\t\tValidationUtils.rejectIfEmptyOrWhitespace(errors, \"number\", \"NUMBER_ERR\");\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\terrors.popNestedPath();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate BindValidationException bindAndExpectValidationError(Runnable action) {\n\t\ttry {\n\t\t\taction.run();\n\t\t}\n\t\tcatch (BindException ex) {\n\t\t\tThrowable cause = ex.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\treturn (BindValidationException) cause;\n\t\t}\n\t\tthrow new IllegalStateException(\"Did not throw\");\n\t}\n\n\tstatic class ExampleNonValidatedBean {\n\n\t\t@Min(5)\n\t\tprivate int age;\n\n\t\tint getAge() {\n\t\t\treturn this.age;\n\t\t}\n\n\t\tvoid setAge(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\n\t}\n\n\t@Validated\n\tstatic class ExampleValidatedBean {\n\n\t\t@Min(5)\n\t\tprivate int age;\n\n\t\tint getAge() {\n\t\t\treturn this.age;\n\t\t}\n\n\t\tvoid setAge(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\n\t}\n\n\tpublic static class ExampleValidatedBeanSubclass extends ExampleValidatedBean {\n\n\t\t@Min(100)\n\t\tprivate int years;\n\n\t\tExampleValidatedBeanSubclass() {\n\t\t\tsetAge(20);\n\t\t}\n\n\t\tpublic int getYears() {\n\t\t\treturn this.years;\n\t\t}\n\n\t\tpublic void setYears(int years) {\n\t\t\tthis.years = years;\n\t\t}\n\n\t}\n\n\t@Validated\n\tstatic class ExampleValidatedWithNestedBean {\n\n\t\t@Valid\n\t\tprivate ExampleNested nested = new ExampleNested();\n\n\t\tExampleNested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(ExampleNested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t}\n\n\tstatic class ExampleNested {\n\n\t\tprivate @Nullable String name;\n\n\t\t@Min(5)\n\t\tprivate int age;\n\n\t\t@NotNull\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String address;\n\n\t\t@Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tvoid setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tint getAge() {\n\t\t\treturn this.age;\n\t\t}\n\n\t\tvoid setAge(int age) {\n\t\t\tthis.age = age;\n\t\t}\n\n\t\tString getAddress() {\n\t\t\treturn this.address;\n\t\t}\n\n\t\tvoid setAddress(String address) {\n\t\t\tthis.address = address;\n\t\t}\n\n\t}\n\n\t@Validated\n\tstatic class ExampleCamelCase {\n\n\t\t@Valid\n\t\tprivate final InnerProperties inner = new InnerProperties();\n\n\t\tInnerProperties getInner() {\n\t\t\treturn this.inner;\n\t\t}\n\n\t\tstatic class InnerProperties {\n\n\t\t\t@Min(5)\n\t\t\tprivate int personAge;\n\n\t\t\tint getPersonAge() {\n\t\t\t\treturn this.personAge;\n\t\t\t}\n\n\t\t\tvoid setPersonAge(int personAge) {\n\t\t\t\tthis.personAge = personAge;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Validated\n\tstatic class ExampleValidatedBeanWithGetterException {\n\n\t\tint getAge() {\n\t\t\tthrow new RuntimeException();\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithMap {\n\n\t\tprivate final Map<String, ExampleMapValue> items = new LinkedHashMap<>();\n\n\t\tMap<String, ExampleMapValue> getItems() {\n\t\t\treturn this.items;\n\t\t}\n\n\t}\n\n\tstatic class ExampleMapValue {\n\n\t\tprivate @Nullable String number;\n\n\t\t@Nullable String getNumber() {\n\t\t\treturn this.number;\n\t\t}\n\n\t\tvoid setNumber(@Nullable String number) {\n\t\t\tthis.number = number;\n\t\t}\n\n\t}\n\n\tstatic class TestHandler extends AbstractBindHandler {\n\n\t\tprivate final @Nullable Object result;\n\n\t\tTestHandler(@Nullable Object result) {\n\t\t\tthis.result = result;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,\n\t\t\t\tException error) throws Exception {\n\t\t\treturn this.result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationErrorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind.validation;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.origin.MockOrigin;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ValidationErrors}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ValidationErrorsTests {\n\n\tprivate static final ConfigurationPropertyName NAME = ConfigurationPropertyName.of(\"foo\");\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenNameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ValidationErrors(null, Collections.emptySet(), Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenBoundPropertiesIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ValidationErrors(NAME, null, Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'boundProperties' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenErrorsIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ValidationErrors(NAME, Collections.emptySet(), null))\n\t\t\t.withMessageContaining(\"'errors' must not be null\");\n\t}\n\n\t@Test\n\tvoid getNameShouldReturnName() {\n\t\tConfigurationPropertyName name = NAME;\n\t\tValidationErrors errors = new ValidationErrors(name, Collections.emptySet(), Collections.emptyList());\n\t\tassertThat((Object) errors.getName()).isEqualTo(name);\n\t}\n\n\t@Test\n\tvoid getBoundPropertiesShouldReturnBoundProperties() {\n\t\tSet<ConfigurationProperty> boundProperties = new LinkedHashSet<>();\n\t\tboundProperties.add(new ConfigurationProperty(NAME, \"foo\", null));\n\t\tValidationErrors errors = new ValidationErrors(NAME, boundProperties, Collections.emptyList());\n\t\tassertThat(errors.getBoundProperties()).isEqualTo(boundProperties);\n\t}\n\n\t@Test\n\tvoid getErrorsShouldReturnErrors() {\n\t\tList<ObjectError> allErrors = new ArrayList<>();\n\t\tallErrors.add(new ObjectError(\"foo\", \"bar\"));\n\t\tValidationErrors errors = new ValidationErrors(NAME, Collections.emptySet(), allErrors);\n\t\tassertThat(errors.getAllErrors()).isEqualTo(allErrors);\n\t}\n\n\t@Test\n\tvoid iteratorShouldIterateErrors() {\n\t\tList<ObjectError> allErrors = new ArrayList<>();\n\t\tallErrors.add(new ObjectError(\"foo\", \"bar\"));\n\t\tValidationErrors errors = new ValidationErrors(NAME, Collections.emptySet(), allErrors);\n\t\tassertThat(errors.iterator()).toIterable().containsExactlyElementsOf(allErrors);\n\t}\n\n\t@Test\n\tvoid getErrorsShouldAdaptFieldErrorsToBeOriginProviders() {\n\t\tSet<ConfigurationProperty> boundProperties = new LinkedHashSet<>();\n\t\tConfigurationPropertyName name1 = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tOrigin origin1 = MockOrigin.of(\"line1\");\n\t\tboundProperties.add(new ConfigurationProperty(name1, \"boot\", origin1));\n\t\tConfigurationPropertyName name2 = ConfigurationPropertyName.of(\"foo.baz.bar\");\n\t\tOrigin origin2 = MockOrigin.of(\"line2\");\n\t\tboundProperties.add(new ConfigurationProperty(name2, \"boot\", origin2));\n\t\tList<ObjectError> allErrors = new ArrayList<>();\n\t\tallErrors.add(new FieldError(\"objectname\", \"bar\", \"message\"));\n\t\tValidationErrors errors = new ValidationErrors(ConfigurationPropertyName.of(\"foo.baz\"), boundProperties,\n\t\t\t\tallErrors);\n\t\tassertThat(Origin.from(errors.getAllErrors().get(0))).isEqualTo(origin2);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/combined/c/CombinedConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.scan.combined.c;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author Madhura Bhave\n */\npublic class CombinedConfiguration {\n\n\t@Component\n\t@ConfigurationProperties(\"b\")\n\tstatic class MyProperties {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/combined/c/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.properties.scan.combined.c;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/combined/d/OtherCombinedConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.scan.combined.d;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @author Madhura Bhave\n */\npublic class OtherCombinedConfiguration {\n\n\t@RestController\n\t@ConfigurationProperties(\"c\")\n\tstatic class MyControllerProperties {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/combined/d/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.properties.scan.combined.d;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/ConfigurationPropertiesScanConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.scan.valid;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.scan.valid.b.BScanConfiguration;\n\n/**\n * Used for testing {@link ConfigurationProperties @ConfigurationProperties} scanning.\n *\n * @author Madhura Bhave\n */\n@ConfigurationPropertiesScan\npublic class ConfigurationPropertiesScanConfiguration {\n\n\t@ConfigurationPropertiesScan\n\t@EnableConfigurationProperties({ ConfigurationPropertiesScanConfiguration.FooProperties.class })\n\tpublic static class TestConfiguration {\n\n\t}\n\n\t@ConfigurationPropertiesScan(basePackages = \"org.springframework.boot.context.properties.scan.valid.a\",\n\t\t\tbasePackageClasses = BScanConfiguration.class)\n\tpublic static class DifferentPackageConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"foo\")\n\tstatic class FooProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"bar\")\n\tstatic class BarProperties {\n\n\t\tBarProperties(String foo) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"bing\")\n\tstatic class BingProperties {\n\n\t\tBingProperties() {\n\t\t}\n\n\t\tBingProperties(String foo) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/a/AScanConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.scan.valid.a;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * @author Madhura Bhave\n */\npublic class AScanConfiguration {\n\n\t@ConfigurationProperties(\"a\")\n\tstatic class AProperties {\n\n\t}\n\n\t@Profile(\"test\")\n\t@ConfigurationProperties(\"profile\")\n\tstatic class MyProfileProperties {\n\n\t}\n\n\t@Conditional(TestResourceCondition.class)\n\t@ConfigurationProperties(\"resource\")\n\tstatic class MyResourceProperties {\n\n\t}\n\n\tstatic class TestResourceCondition implements Condition {\n\n\t\t@Override\n\t\tpublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\treturn context.getResourceLoader().getResource(\"test\").exists();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/a/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.properties.scan.valid.a;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/b/BScanConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.scan.valid.b;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * @author Madhura Bhave\n * @author Stephane Nicoll\n */\npublic class BScanConfiguration {\n\n\tpublic interface BProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"b.first\")\n\tpublic static class BFirstProperties implements BProperties {\n\n\t\tprivate final String name;\n\n\t\tpublic BFirstProperties(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"b.second\")\n\tpublic static class BSecondProperties implements BProperties {\n\n\t\tprivate int number;\n\n\t\tpublic int getNumber() {\n\t\t\treturn this.number;\n\t\t}\n\n\t\tpublic void setNumber(int number) {\n\t\t\tthis.number = number;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/b/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.properties.scan.valid.b;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/scan/valid/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.context.properties.scan.valid;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AbstractPropertyMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.List;\n\n/**\n * Abstract base class for {@link PropertyMapper} tests.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Eddú Meléndez\n */\npublic abstract class AbstractPropertyMapperTests {\n\n\tprotected abstract PropertyMapper getMapper();\n\n\tprotected final List<String> mapConfigurationPropertyName(String configurationPropertyName) {\n\t\treturn getMapper().map(ConfigurationPropertyName.of(configurationPropertyName));\n\t}\n\n\tprotected final String mapPropertySourceName(String propertySourceName) {\n\t\treturn getMapper().map(propertySourceName).toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AliasedConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AliasedConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AliasedConfigurationPropertySourceTests {\n\n\t@Test\n\tvoid getConfigurationPropertyShouldConsiderAliases() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"bing\");\n\t\tsource.put(\"foo.baz\", \"biff\");\n\t\tConfigurationPropertySource aliased = source.nonIterable()\n\t\t\t.withAliases(new ConfigurationPropertyNameAliases(\"foo.bar\", \"foo.bar1\"));\n\t\tassertThat(getValue(aliased, \"foo.bar\")).isEqualTo(\"bing\");\n\t\tassertThat(getValue(aliased, \"foo.bar1\")).isEqualTo(\"bing\");\n\t}\n\n\t@Test\n\tvoid getConfigurationPropertyWhenNotAliasesShouldReturnValue() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"bing\");\n\t\tsource.put(\"foo.baz\", \"biff\");\n\t\tConfigurationPropertySource aliased = source.nonIterable()\n\t\t\t.withAliases(new ConfigurationPropertyNameAliases(\"foo.bar\", \"foo.bar1\"));\n\t\tassertThat(getValue(aliased, \"foo.baz\")).isEqualTo(\"biff\");\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsUnknownShouldReturnUnknown() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().unknown(name);\n\t\tConfigurationPropertySource aliased = source\n\t\t\t.withAliases(new ConfigurationPropertyNameAliases(\"foo.bar\", \"foo.bar1\"));\n\t\tassertThat(aliased.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsPresentShouldReturnPresent() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().present(name)\n\t\t\t.unknown(ConfigurationPropertyName.of(\"bar\"));\n\t\tConfigurationPropertySource aliased = source\n\t\t\t.withAliases(new ConfigurationPropertyNameAliases(\"foo.bar\", \"foo.bar1\"));\n\t\tassertThat(aliased.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.PRESENT);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenAllAreAbsentShouldReturnAbsent() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().absent(name)\n\t\t\t.absent(ConfigurationPropertyName.of(\"bar\"));\n\t\tConfigurationPropertySource aliased = source.withAliases(new ConfigurationPropertyNameAliases(\"foo\", \"bar\"));\n\t\tassertThat(aliased.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenAnyIsPresentShouldReturnPresent() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().absent(name)\n\t\t\t.present(ConfigurationPropertyName.of(\"bar\"));\n\t\tConfigurationPropertySource aliased = source.withAliases(new ConfigurationPropertyNameAliases(\"foo\", \"bar\"));\n\t\tassertThat(aliased.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.PRESENT);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenPresentInAliasShouldReturnPresent() {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(\n\t\t\t\tCollections.singletonMap(\"foo.bar\", \"foobar\"));\n\t\tConfigurationPropertySource aliased = source\n\t\t\t.withAliases(new ConfigurationPropertyNameAliases(\"foo.bar\", \"baz.foo\"));\n\t\tassertThat(aliased.containsDescendantOf(ConfigurationPropertyName.of(\"baz\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t}\n\n\tprivate @Nullable Object getValue(ConfigurationPropertySource source, String name) {\n\t\tConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name));\n\t\treturn (property != null) ? property.getValue() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/AliasedIterableConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AliasedConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AliasedIterableConfigurationPropertySourceTests extends AliasedConfigurationPropertySourceTests {\n\n\t@Test\n\tvoid streamShouldIncludeAliases() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"bing\");\n\t\tsource.put(\"foo.baz\", \"biff\");\n\t\tIterableConfigurationPropertySource aliased = source\n\t\t\t.withAliases(new ConfigurationPropertyNameAliases(\"foo.bar\", \"foo.bar1\"));\n\t\tassertThat(aliased.stream()).containsExactly(ConfigurationPropertyName.of(\"foo.bar\"),\n\t\t\t\tConfigurationPropertyName.of(\"foo.bar1\"), ConfigurationPropertyName.of(\"foo.baz\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/CachingConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link CachingConfigurationPropertySource}.\n *\n * @author Phillip Webb\n */\nclass CachingConfigurationPropertySourceTests {\n\n\t@Test\n\tvoid findWhenNullSourceReturnsNull() {\n\t\tConfigurationPropertySource source = null;\n\t\tassertThat(CachingConfigurationPropertySource.find(source)).isNull();\n\t}\n\n\t@Test\n\tvoid findWhenNotCachingConfigurationPropertySourceReturnsNull() {\n\t\tConfigurationPropertySource source = mock(ConfigurationPropertySource.class);\n\t\tassertThat(CachingConfigurationPropertySource.find(source)).isNull();\n\t}\n\n\t@Test\n\tvoid findWhenCachingConfigurationPropertySourceReturnsCaching() {\n\t\tConfigurationPropertySource source = mock(ConfigurationPropertySource.class,\n\t\t\t\twithSettings().extraInterfaces(CachingConfigurationPropertySource.class));\n\t\tConfigurationPropertyCaching caching = mock(ConfigurationPropertyCaching.class);\n\t\tgiven(((CachingConfigurationPropertySource) source).getCaching()).willReturn(caching);\n\t\tassertThat(CachingConfigurationPropertySource.find(source)).isEqualTo(caching);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyCachingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ConfigurationPropertyCaching}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertyCachingTests {\n\n\tprivate StandardEnvironment environment;\n\n\tprivate MapPropertySource propertySource;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new StandardEnvironment();\n\t\tthis.propertySource = new MapPropertySource(\"test\", Collections.singletonMap(\"spring\", \"boot\"));\n\t\tthis.environment.getPropertySources().addLast(this.propertySource);\n\t}\n\n\t@Test\n\tvoid getFromEnvironmentReturnsCaching() {\n\t\tConfigurationPropertyCaching caching = ConfigurationPropertyCaching.get(this.environment);\n\t\tassertThat(caching).isInstanceOf(ConfigurationPropertySourcesCaching.class);\n\t}\n\n\t@Test\n\tvoid getFromEnvironmentForUnderlyingSourceReturnsCaching() {\n\t\tConfigurationPropertyCaching caching = ConfigurationPropertyCaching.get(this.environment, this.propertySource);\n\t\tassertThat(caching).isInstanceOf(SoftReferenceConfigurationPropertyCache.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getFromSourcesWhenSourcesIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ConfigurationPropertyCaching.get((Iterable<ConfigurationPropertySource>) null))\n\t\t\t.withMessage(\"'sources' must not be null\");\n\t}\n\n\t@Test\n\tvoid getFromSourcesReturnsCachingComposite() {\n\t\tList<ConfigurationPropertySource> sources = new ArrayList<>();\n\t\tsources.add(SpringConfigurationPropertySource.from(this.propertySource));\n\t\tConfigurationPropertyCaching caching = ConfigurationPropertyCaching.get(sources);\n\t\tassertThat(caching).isInstanceOf(ConfigurationPropertySourcesCaching.class);\n\t}\n\n\t@Test\n\tvoid getFromSourcesForUnderlyingSourceReturnsCaching() {\n\t\tList<ConfigurationPropertySource> sources = new ArrayList<>();\n\t\tsources.add(SpringConfigurationPropertySource.from(this.propertySource));\n\t\tConfigurationPropertyCaching caching = ConfigurationPropertyCaching.get(sources, this.propertySource);\n\t\tassertThat(caching).isInstanceOf(SoftReferenceConfigurationPropertyCache.class);\n\t}\n\n\t@Test\n\tvoid getFromSourcesForUnderlyingSourceWhenCantFindThrowsException() {\n\t\tList<ConfigurationPropertySource> sources = new ArrayList<>();\n\t\tsources.add(SpringConfigurationPropertySource.from(this.propertySource));\n\t\tMapPropertySource anotherPropertySource = new MapPropertySource(\"test2\", Collections.emptyMap());\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> ConfigurationPropertyCaching.get(sources, anotherPropertySource))\n\t\t\t.withMessage(\"Unable to find cache from configuration property sources\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameAliasesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigurationPropertyNameAliases}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigurationPropertyNameAliasesTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithStringWhenNullNameShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigurationPropertyNameAliases((String) null))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithStringShouldAddMapping() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases(\"foo\", \"bar\", \"baz\");\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"bar\"), ConfigurationPropertyName.of(\"baz\"));\n\t}\n\n\t@Test\n\tvoid createWithNameShouldAddMapping() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases(\n\t\t\t\tConfigurationPropertyName.of(\"foo\"), ConfigurationPropertyName.of(\"bar\"),\n\t\t\t\tConfigurationPropertyName.of(\"baz\"));\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"bar\"), ConfigurationPropertyName.of(\"baz\"));\n\t}\n\n\t@Test\n\tvoid addAliasesFromStringShouldAddMapping() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(\"foo\", \"bar\", \"baz\");\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"bar\"), ConfigurationPropertyName.of(\"baz\"));\n\t}\n\n\t@Test\n\tvoid addAliasesFromNameShouldAddMapping() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(ConfigurationPropertyName.of(\"foo\"), ConfigurationPropertyName.of(\"bar\"),\n\t\t\t\tConfigurationPropertyName.of(\"baz\"));\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"bar\"), ConfigurationPropertyName.of(\"baz\"));\n\t}\n\n\t@Test\n\tvoid addWhenHasExistingShouldAddAdditionalMappings() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(\"foo\", \"bar\");\n\t\taliases.addAliases(\"foo\", \"baz\");\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"bar\"), ConfigurationPropertyName.of(\"baz\"));\n\t}\n\n\t@Test\n\tvoid getAliasesWhenNotMappedShouldReturnEmptyList() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\"))).isEmpty();\n\t}\n\n\t@Test\n\tvoid getAliasesWhenMappedShouldReturnMapping() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(\"foo\", \"bar\");\n\t\tassertThat(aliases.getAliases(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"bar\"));\n\t}\n\n\t@Test\n\tvoid getNameForAliasWhenHasMappingShouldReturnName() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(\"foo\", \"bar\");\n\t\taliases.addAliases(\"foo\", \"baz\");\n\t\tassertThat((Object) aliases.getNameForAlias(ConfigurationPropertyName.of(\"bar\")))\n\t\t\t.isEqualTo(ConfigurationPropertyName.of(\"foo\"));\n\t\tassertThat((Object) aliases.getNameForAlias(ConfigurationPropertyName.of(\"baz\")))\n\t\t\t.isEqualTo(ConfigurationPropertyName.of(\"foo\"));\n\t}\n\n\t@Test\n\tvoid getNameForAliasWhenNotMappedShouldReturnNull() {\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(\"foo\", \"bar\");\n\t\tassertThat((Object) aliases.getNameForAlias(ConfigurationPropertyName.of(\"baz\"))).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigurationPropertyName}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Eddú Meléndez\n */\nclass ConfigurationPropertyNameTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofNameShouldNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ConfigurationPropertyName.of(null))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofNameShouldNotStartWithDash() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"-foo\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameShouldNotStartWithDot() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\".foo\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameShouldNotEndWithDot() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"foo.\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameShouldNotContainUppercase() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"fOo\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameShouldNotContainInvalidChars() {\n\t\tString invalid = \"_@$%*+=':;\";\n\t\tfor (char c : invalid.toCharArray()) {\n\t\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"foo\" + c))\n\t\t\t\t.satisfies((ex) -> assertThat(ex.getMessage()).contains(\"is not valid\"));\n\t\t}\n\t}\n\n\t@Test\n\tvoid ofNameWhenSimple() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"name\");\n\t\tassertThat(name).hasToString(\"name\");\n\t\tassertThat(name.getNumberOfElements()).isOne();\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"name\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t}\n\n\t@Test\n\tvoid ofNameWhenStartsWithNumber() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"1foo\");\n\t\tassertThat(name).hasToString(\"1foo\");\n\t\tassertThat(name.getNumberOfElements()).isOne();\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"1foo\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t}\n\n\t@Test\n\tvoid ofNameWhenRunOnAssociative() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo[bar]\");\n\t\tassertThat(name).hasToString(\"foo[bar]\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"bar\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isTrue();\n\t}\n\n\t@Test\n\tvoid ofNameWhenDotOnAssociative() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tassertThat(name).hasToString(\"foo.bar\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"bar\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isFalse();\n\t}\n\n\t@Test\n\tvoid ofNameWhenDotAndAssociative() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.[bar]\");\n\t\tassertThat(name).hasToString(\"foo[bar]\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"bar\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isTrue();\n\t}\n\n\t@Test\n\tvoid ofNameWhenDoubleRunOnAndAssociative() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo[bar]baz\");\n\t\tassertThat(name).hasToString(\"foo[bar].baz\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"bar\");\n\t\tassertThat(name.getElement(2, Form.ORIGINAL)).isEqualTo(\"baz\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isTrue();\n\t\tassertThat(name.isIndexed(2)).isFalse();\n\t}\n\n\t@Test\n\tvoid ofNameWhenDoubleDotAndAssociative() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.[bar].baz\");\n\t\tassertThat(name).hasToString(\"foo[bar].baz\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"bar\");\n\t\tassertThat(name.getElement(2, Form.ORIGINAL)).isEqualTo(\"baz\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isTrue();\n\t\tassertThat(name.isIndexed(2)).isFalse();\n\t}\n\n\t@Test\n\tvoid ofNameWhenMissingCloseBracket() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"[bar\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameWhenMissingOpenBracket() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"bar]\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameWhenMultipleMismatchedBrackets() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"[a[[[b]ar]\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameWhenNestedBrackets() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo[a[c][[b]ar]]\");\n\t\tassertThat(name).hasToString(\"foo[a[c][[b]ar]]\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"a[c][[b]ar]\");\n\t}\n\n\t@Test\n\tvoid ofNameWithWhitespaceInName() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"foo. bar\"))\n\t\t\t.withMessageContaining(\"is not valid\");\n\t}\n\n\t@Test\n\tvoid ofNameWithWhitespaceInAssociativeElement() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo[b a r]\");\n\t\tassertThat(name).hasToString(\"foo[b a r]\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"b a r\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isTrue();\n\t}\n\n\t@Test\n\tvoid ofNameWithUppercaseInAssociativeElement() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo[BAR]\");\n\t\tassertThat(name).hasToString(\"foo[BAR]\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"BAR\");\n\t\tassertThat(name.isIndexed(0)).isFalse();\n\t\tassertThat(name.isIndexed(1)).isTrue();\n\t}\n\n\t@Test\n\tvoid ofWhenNameIsEmptyShouldReturnEmptyName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"\");\n\t\tassertThat(name.toString()).isEmpty();\n\t\tassertThat(name.append(\"foo\")).hasToString(\"foo\");\n\t}\n\n\t@Test\n\tvoid ofIfValidWhenNameIsValidReturnsName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.ofIfValid(\"spring.bo-ot\");\n\t\tassertThat(name).hasToString(\"spring.bo-ot\");\n\t}\n\n\t@Test\n\tvoid ofIfValidWhenNameIsNotValidReturnsNull() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.ofIfValid(\"spring.bo!oot\");\n\t\tassertThat(name).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid adaptWhenNameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ConfigurationPropertyName.adapt(null, '.'))\n\t\t\t.withMessageContaining(\"Name must not be null\");\n\t}\n\n\t@Test\n\tvoid adaptWhenElementValueProcessorIsNullShouldAdapt() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"foo\", '.', null);\n\t\tassertThat(name).hasToString(\"foo\");\n\t}\n\n\t@Test\n\tvoid adaptShouldCreateName() {\n\t\tConfigurationPropertyName expected = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"foo.bar.baz\", '.');\n\t\tassertThat(name).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid adaptShouldStripInvalidChars() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"f@@.b%r\", '.');\n\t\tassertThat(name.getElement(0, Form.UNIFORM)).isEqualTo(\"f\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"f\");\n\t\tassertThat(name.getElement(1, Form.UNIFORM)).isEqualTo(\"br\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"br\");\n\t\tassertThat(name).hasToString(\"f.br\");\n\t}\n\n\t@Test\n\tvoid adaptShouldSupportUnderscore() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"f-_o.b_r\", '.');\n\t\tassertThat(name.getElement(0, Form.UNIFORM)).isEqualTo(\"fo\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"f-_o\");\n\t\tassertThat(name.getElement(1, Form.UNIFORM)).isEqualTo(\"br\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"b_r\");\n\t\tassertThat(name).hasToString(\"f-o.br\");\n\t}\n\n\t@Test\n\tvoid adaptShouldSupportMixedCase() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"fOo.bAr\", '.');\n\t\tassertThat(name.getElement(0, Form.UNIFORM)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"fOo\");\n\t\tassertThat(name.getElement(1, Form.UNIFORM)).isEqualTo(\"bar\");\n\t\tassertThat(name.getElement(1, Form.ORIGINAL)).isEqualTo(\"bAr\");\n\t\tassertThat(name).hasToString(\"foo.bar\");\n\t}\n\n\t@Test\n\tvoid adaptShouldUseElementValueProcessor() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"FOO_THE-BAR\", '_',\n\t\t\t\t(c) -> c.toString().replace(\"-\", \"\"));\n\t\tassertThat(name).hasToString(\"foo.thebar\");\n\t}\n\n\t@Test\n\tvoid adaptShouldSupportIndexedElements() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"foo\", '.');\n\t\tassertThat(name).hasToString(\"foo\");\n\t\tassertThat(name.getNumberOfElements()).isOne();\n\t\tname = ConfigurationPropertyName.adapt(\"[foo]\", '.');\n\t\tassertThat(name).hasToString(\"[foo]\");\n\t\tassertThat(name.getNumberOfElements()).isOne();\n\t\tname = ConfigurationPropertyName.adapt(\"foo.bar\", '.');\n\t\tassertThat(name).hasToString(\"foo.bar\");\n\t\tassertThat(name.getNumberOfElements()).isEqualTo(2);\n\t\tname = ConfigurationPropertyName.adapt(\"foo[foo.bar]\", '.');\n\t\tassertThat(name).hasToString(\"foo[foo.bar]\");\n\t\tassertThat(name.getNumberOfElements()).isEqualTo(2);\n\t\tname = ConfigurationPropertyName.adapt(\"foo.[bar].baz\", '.');\n\t\tassertThat(name).hasToString(\"foo[bar].baz\");\n\t\tassertThat(name.getNumberOfElements()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid adaptUnderscoreShouldReturnEmpty() {\n\t\tassertThat(ConfigurationPropertyName.adapt(\"_\", '_').isEmpty()).isTrue();\n\t\tassertThat(ConfigurationPropertyName.adapt(\"_\", '.').isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid isEmptyWhenEmptyShouldReturnTrue() {\n\t\tassertThat(ConfigurationPropertyName.of(\"\").isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid isEmptyWhenNotEmptyShouldReturnFalse() {\n\t\tassertThat(ConfigurationPropertyName.of(\"x\").isEmpty()).isFalse();\n\t}\n\n\t@Test\n\tvoid isLastElementIndexedWhenIndexedShouldReturnTrue() {\n\t\tassertThat(ConfigurationPropertyName.of(\"foo[0]\").isLastElementIndexed()).isTrue();\n\t}\n\n\t@Test\n\tvoid isLastElementIndexedWhenNotIndexedShouldReturnFalse() {\n\t\tassertThat(ConfigurationPropertyName.of(\"foo.bar\").isLastElementIndexed()).isFalse();\n\t\tassertThat(ConfigurationPropertyName.of(\"foo[0].bar\").isLastElementIndexed()).isFalse();\n\t}\n\n\t@Test\n\tvoid getLastElementShouldGetLastElement() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"foo.bAr\", '.');\n\t\tassertThat(name.getLastElement(Form.ORIGINAL)).isEqualTo(\"bAr\");\n\t\tassertThat(name.getLastElement(Form.UNIFORM)).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid getLastElementWhenEmptyShouldReturnEmptyString() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.EMPTY;\n\t\tassertThat(name.getLastElement(Form.ORIGINAL)).isEmpty();\n\t\tassertThat(name.getLastElement(Form.UNIFORM)).isEmpty();\n\t}\n\n\t@Test\n\tvoid getElementShouldNotIncludeAngleBrackets() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"[foo]\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"foo\");\n\t\tassertThat(name.getElement(0, Form.UNIFORM)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getElementInUniformFormShouldNotIncludeDashes() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"f-o-o\");\n\t\tassertThat(name.getElement(0, Form.ORIGINAL)).isEqualTo(\"f-o-o\");\n\t\tassertThat(name.getElement(0, Form.UNIFORM)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getElementInOriginalFormShouldReturnElement() {\n\t\tassertThat(getElements(\"foo.bar\", Form.ORIGINAL)).containsExactly(\"foo\", \"bar\");\n\t\tassertThat(getElements(\"foo[0]\", Form.ORIGINAL)).containsExactly(\"foo\", \"0\");\n\t\tassertThat(getElements(\"foo.[0]\", Form.ORIGINAL)).containsExactly(\"foo\", \"0\");\n\t\tassertThat(getElements(\"foo[baz]\", Form.ORIGINAL)).containsExactly(\"foo\", \"baz\");\n\t\tassertThat(getElements(\"foo.baz\", Form.ORIGINAL)).containsExactly(\"foo\", \"baz\");\n\t\tassertThat(getElements(\"foo[baz].bar\", Form.ORIGINAL)).containsExactly(\"foo\", \"baz\", \"bar\");\n\t\tassertThat(getElements(\"foo.baz.bar\", Form.ORIGINAL)).containsExactly(\"foo\", \"baz\", \"bar\");\n\t\tassertThat(getElements(\"foo.baz-bar\", Form.ORIGINAL)).containsExactly(\"foo\", \"baz-bar\");\n\t}\n\n\t@Test\n\tvoid getElementInUniformFormShouldReturnElement() {\n\t\tassertThat(getElements(\"foo.bar\", Form.UNIFORM)).containsExactly(\"foo\", \"bar\");\n\t\tassertThat(getElements(\"foo[0]\", Form.UNIFORM)).containsExactly(\"foo\", \"0\");\n\t\tassertThat(getElements(\"foo.[0]\", Form.UNIFORM)).containsExactly(\"foo\", \"0\");\n\t\tassertThat(getElements(\"foo[baz]\", Form.UNIFORM)).containsExactly(\"foo\", \"baz\");\n\t\tassertThat(getElements(\"foo.baz\", Form.UNIFORM)).containsExactly(\"foo\", \"baz\");\n\t\tassertThat(getElements(\"foo[baz].bar\", Form.UNIFORM)).containsExactly(\"foo\", \"baz\", \"bar\");\n\t\tassertThat(getElements(\"foo.baz.bar\", Form.UNIFORM)).containsExactly(\"foo\", \"baz\", \"bar\");\n\t\tassertThat(getElements(\"foo.baz-bar\", Form.UNIFORM)).containsExactly(\"foo\", \"bazbar\");\n\t}\n\n\tprivate List<CharSequence> getElements(String name, Form form) {\n\t\tConfigurationPropertyName propertyName = ConfigurationPropertyName.of(name);\n\t\tList<CharSequence> result = new ArrayList<>(propertyName.getNumberOfElements());\n\t\tfor (int i = 0; i < propertyName.getNumberOfElements(); i++) {\n\t\t\tresult.add(propertyName.getElement(i, form));\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Test\n\tvoid getNumberOfElementsShouldReturnNumberOfElement() {\n\t\tassertThat(ConfigurationPropertyName.of(\"\").getNumberOfElements()).isZero();\n\t\tassertThat(ConfigurationPropertyName.of(\"x\").getNumberOfElements()).isOne();\n\t\tassertThat(ConfigurationPropertyName.of(\"x.y\").getNumberOfElements()).isEqualTo(2);\n\t\tassertThat(ConfigurationPropertyName.of(\"x[0].y\").getNumberOfElements()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid appendWhenNotIndexedShouldAppendWithDot() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tassertThat(name.append(\"bar\")).hasToString(\"foo.bar\");\n\t}\n\n\t@Test\n\tvoid appendWhenIndexedShouldAppendWithBrackets() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\").append(\"[bar]\");\n\t\tassertThat(name.isLastElementIndexed()).isTrue();\n\t\tassertThat(name).hasToString(\"foo[bar]\");\n\t}\n\n\t@Test\n\tvoid appendWhenElementNameIsNotValidShouldThrowException() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyNameException.class)\n\t\t\t.isThrownBy(() -> ConfigurationPropertyName.of(\"foo\").append(\"-bar\"))\n\t\t\t.withMessageContaining(\"Configuration property name '-bar' is not valid\");\n\t}\n\n\t@Test\n\tvoid appendWhenElementNameMultiDotShouldAppend() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\").append(\"bar.baz\");\n\t\tassertThat(name).hasToString(\"foo.bar.baz\");\n\t\tassertThat(name.getNumberOfElements()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid appendWhenElementNameIsNullShouldReturnName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tassertThat((Object) name.append((String) null)).isSameAs(name);\n\t}\n\n\t@Test\n\tvoid appendConfigurationPropertyNameShouldReturnAppendedName() {\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.of(\"spring.boot\");\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.of(\"tests.code\");\n\t\tassertThat(n1.append(n2)).hasToString(\"spring.boot.tests.code\");\n\t}\n\n\t@Test\n\tvoid appendConfigurationPropertyNameWhenNullShouldReturnName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tassertThat((Object) name.append((ConfigurationPropertyName) null)).isSameAs(name);\n\t}\n\n\t@Test\n\tvoid getParentShouldReturnParent() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"this.is.a.multipart.name\");\n\t\tConfigurationPropertyName p1 = name.getParent();\n\t\tConfigurationPropertyName p2 = p1.getParent();\n\t\tConfigurationPropertyName p3 = p2.getParent();\n\t\tConfigurationPropertyName p4 = p3.getParent();\n\t\tConfigurationPropertyName p5 = p4.getParent();\n\t\tassertThat(p1).hasToString(\"this.is.a.multipart\");\n\t\tassertThat(p2).hasToString(\"this.is.a\");\n\t\tassertThat(p3).hasToString(\"this.is\");\n\t\tassertThat(p4).hasToString(\"this\");\n\t\tassertThat(p5).isEqualTo(ConfigurationPropertyName.EMPTY);\n\t}\n\n\t@Test\n\tvoid getParentWhenEmptyShouldReturnEmpty() {\n\t\tassertThat(ConfigurationPropertyName.EMPTY.getParent()).isEqualTo(ConfigurationPropertyName.EMPTY);\n\t}\n\n\t@Test\n\tvoid chopWhenLessThenSizeShouldReturnChopped() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.chop(1)).hasToString(\"foo\");\n\t\tassertThat(name.chop(2)).hasToString(\"foo.bar\");\n\t}\n\n\t@Test\n\tvoid chopWhenGreaterThanSizeShouldReturnExisting() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.chop(4)).isEqualTo(name);\n\t}\n\n\t@Test\n\tvoid chopWhenEqualToSizeShouldReturnExisting() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.chop(3)).isEqualTo(name);\n\t}\n\n\t@Test\n\tvoid subNameWhenOffsetLessThanSizeShouldReturnSubName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.subName(1)).hasToString(\"bar.baz\");\n\t\tassertThat(name.subName(2)).hasToString(\"baz\");\n\t}\n\n\t@Test\n\tvoid subNameOfAdaptedNameWhenOffsetLessThanSizeShouldReturnSubName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"MY_LOGGING_LEVEL_ONE\", '_');\n\t\tassertThat(name.subName(1)).hasToString(\"logging.level.one\");\n\t\tassertThat(name.subName(2)).hasToString(\"level.one\");\n\t}\n\n\t@Test\n\tvoid subNameOfAdaptedNameWithValueProcessorWhenOffsetLessThanSizeShouldReturnSubName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"MY_LOGGING_LEVEL_ONE\", '_',\n\t\t\t\t(value) -> value.toString().toLowerCase(Locale.ENGLISH));\n\t\tassertThat(name.subName(1)).hasToString(\"logging.level.one\");\n\t\tassertThat(name.subName(2)).hasToString(\"level.one\");\n\t}\n\n\t@Test\n\tvoid subNameWhenOffsetZeroShouldReturnName() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.subName(0)).isSameAs(name);\n\t}\n\n\t@Test\n\tvoid subNameWhenOffsetEqualToSizeShouldReturnEmpty() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.subName(3)).isSameAs(ConfigurationPropertyName.EMPTY);\n\t}\n\n\t@Test\n\tvoid subNameWhenOffsetMoreThanSizeShouldReturnEmpty() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> name.subName(4));\n\t}\n\n\t@Test\n\tvoid subNameWhenOffsetNegativeShouldThrowException() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> name.subName(-1));\n\t}\n\n\t@Test\n\tvoid isParentOfWhenSameShouldReturnFalse() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tassertThat(name.isParentOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isParentOfWhenParentShouldReturnTrue() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertyName child = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tassertThat(name.isParentOf(child)).isTrue();\n\t\tassertThat(child.isParentOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isParentOfWhenGrandparentShouldReturnFalse() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertyName grandchild = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.isParentOf(grandchild)).isFalse();\n\t\tassertThat(grandchild.isParentOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isParentOfWhenRootReturnTrue() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"\");\n\t\tConfigurationPropertyName child = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertyName grandchild = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tassertThat(name.isParentOf(child)).isTrue();\n\t\tassertThat(name.isParentOf(grandchild)).isFalse();\n\t\tassertThat(child.isAncestorOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isAncestorOfWhenSameShouldReturnFalse() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tassertThat(name.isAncestorOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isAncestorOfWhenParentShouldReturnTrue() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertyName child = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tassertThat(name.isAncestorOf(child)).isTrue();\n\t\tassertThat(child.isAncestorOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isAncestorOfWhenGrandparentShouldReturnTrue() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertyName grandchild = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.isAncestorOf(grandchild)).isTrue();\n\t\tassertThat(grandchild.isAncestorOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid isAncestorOfWhenRootShouldReturnTrue() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"\");\n\t\tConfigurationPropertyName grandchild = ConfigurationPropertyName.of(\"foo.bar.baz\");\n\t\tassertThat(name.isAncestorOf(grandchild)).isTrue();\n\t\tassertThat(grandchild.isAncestorOf(name)).isFalse();\n\t}\n\n\t@Test\n\tvoid compareShouldSortNames() {\n\t\tList<ConfigurationPropertyName> names = new ArrayList<>();\n\t\tnames.add(ConfigurationPropertyName.of(\"foo[10]\"));\n\t\tnames.add(ConfigurationPropertyName.of(\"foo.bard\"));\n\t\tnames.add(ConfigurationPropertyName.of(\"foo[2]\"));\n\t\tnames.add(ConfigurationPropertyName.of(\"foo.bar\"));\n\t\tnames.add(ConfigurationPropertyName.of(\"foo.baz\"));\n\t\tnames.add(ConfigurationPropertyName.of(\"foo\"));\n\t\tCollections.sort(names);\n\t\tassertThat(names.stream().map(ConfigurationPropertyName::toString).toList()).containsExactly(\"foo\", \"foo[2]\",\n\t\t\t\t\"foo[10]\", \"foo.bar\", \"foo.bard\", \"foo.baz\");\n\t}\n\n\t@Test\n\tvoid compareDifferentLengthsShouldSortNames() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"spring.web.resources.chain.strategy.content\");\n\t\tConfigurationPropertyName other = ConfigurationPropertyName\n\t\t\t.of(\"spring.web.resources.chain.strategy.content.enabled\");\n\t\tassertThat(name).isLessThan(other);\n\t}\n\n\t@Test\n\tvoid toStringShouldBeLowerCaseDashed() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"fOO.b_-a-r\", '.');\n\t\tassertThat(name).hasToString(\"foo.b-a-r\");\n\t}\n\n\t@Test\n\tvoid toStringFromOfShouldBeLowerCaseDashed() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo.bar-baz\");\n\t\tassertThat(name).hasToString(\"foo.bar-baz\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tConfigurationPropertyName n01 = ConfigurationPropertyName.of(\"foo[bar]\");\n\t\tConfigurationPropertyName n02 = ConfigurationPropertyName.of(\"foo[bar]\");\n\t\tConfigurationPropertyName n03 = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tConfigurationPropertyName n04 = ConfigurationPropertyName.of(\"f-o-o.b-a-r\");\n\t\tConfigurationPropertyName n05 = ConfigurationPropertyName.of(\"foo[BAR]\");\n\t\tConfigurationPropertyName n06 = ConfigurationPropertyName.of(\"oof[bar]\");\n\t\tConfigurationPropertyName n07 = ConfigurationPropertyName.of(\"foo.bar\");\n\t\tConfigurationPropertyName n08 = ConfigurationPropertyName.EMPTY;\n\t\tConfigurationPropertyName n09 = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertyName n10 = ConfigurationPropertyName.of(\"fo\");\n\t\tConfigurationPropertyName n11 = ConfigurationPropertyName.adapt(\"foo.BaR\", '.');\n\t\tConfigurationPropertyName n12 = ConfigurationPropertyName.of(\"f-o-o[b-a-r]\");\n\t\tConfigurationPropertyName n13 = ConfigurationPropertyName.of(\"f-o-o[b-a-r--]\");\n\t\tConfigurationPropertyName n14 = ConfigurationPropertyName.of(\"[1]\");\n\t\tConfigurationPropertyName n15 = ConfigurationPropertyName.of(\"[-1]\");\n\t\tassertThat((Object) n01).isEqualTo(n01);\n\t\tassertThat(n01).hasSameHashCodeAs(n01);\n\t\tassertThat((Object) n01).isEqualTo(n02);\n\t\tassertThat(n01).hasSameHashCodeAs(n02);\n\t\tassertThat((Object) n01).isEqualTo(n03);\n\t\tassertThat(n01).hasSameHashCodeAs(n03);\n\t\tassertThat((Object) n01).isEqualTo(n04);\n\t\tassertThat(n01).hasSameHashCodeAs(n04);\n\t\tassertThat((Object) n11).isEqualTo(n03);\n\t\tassertThat(n11).hasSameHashCodeAs(n03);\n\t\tassertThat((Object) n03).isEqualTo(n11);\n\t\tassertThat(n03).hasSameHashCodeAs(n11);\n\t\tassertThat((Object) n01).isNotEqualTo(n05);\n\t\tassertThat((Object) n01).isNotEqualTo(n06);\n\t\tassertThat((Object) n07).isNotEqualTo(n08);\n\t\tassertThat((Object) n09).isNotEqualTo(n10);\n\t\tassertThat((Object) n10).isNotEqualTo(n09);\n\t\tassertThat((Object) n12).isNotEqualTo(n13);\n\t\tassertThat((Object) n14).isNotEqualTo(n15);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCodeAfterOperations() {\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.of(\"nested\");\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.EMPTY.append(\"nested\");\n\t\tConfigurationPropertyName n3 = ConfigurationPropertyName.of(\"nested.value\").getParent();\n\t\tassertThat(n1).hasSameHashCodeAs(n2).hasSameHashCodeAs(n3);\n\t\tassertThat(n1).isEqualTo(n2).isEqualTo(n3);\n\t}\n\n\t@Test\n\tvoid equalsWhenStartsWith() {\n\t\t// gh-14665\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.of(\"my.sources[0].xame\");\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.of(\"my.sources[0].xamespace\");\n\t\tassertThat(n1).isNotEqualTo(n2);\n\t}\n\n\t@Test\n\tvoid equalsWhenStartsWithOfAdaptedName() {\n\t\t// gh-15152\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.adapt(\"example.mymap.ALPHA\", '.');\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.adapt(\"example.mymap.ALPHA_BRAVO\", '.');\n\t\tassertThat(n1).isNotEqualTo(n2);\n\t}\n\n\t@Test\n\tvoid equalsWhenStartsWithOfAdaptedNameOfIllegalChars() {\n\t\t// gh-15152\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.adapt(\"example.mymap.ALPH!\", '.');\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.adapt(\"example.mymap.ALPHA!BRAVO\", '.');\n\t\tassertThat(n1).isNotEqualTo(n2);\n\t}\n\n\t@Test\n\tvoid equalsWhenNameStartsTheSameUsingDashedCompare() {\n\t\t// gh-16855\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.of(\"management.metrics.web.server.auto-time-request\");\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.of(\"management.metrics.web.server.auto-time-requests\");\n\t\tassertThat(n1).isNotEqualTo(n2);\n\t\tassertThat(n2).isNotEqualTo(n1);\n\t}\n\n\t@Test // gh-30317\n\tvoid equalsWhenAdaptedNameMatchesDueToRemovalOfTrailingNonUniformCharacters() {\n\t\tConfigurationPropertyName name1 = ConfigurationPropertyName.of(\"example.demo\");\n\t\tConfigurationPropertyName name2 = ConfigurationPropertyName.adapt(\"example.demo$$\", '.');\n\t\tassertThat(name1).isEqualTo(name2);\n\t\tassertThat(name2).isEqualTo(name1);\n\t}\n\n\t@Test // gh-34804\n\tvoid equalsSymmetricWhenNameMatchesDueToIgnoredTrailingDashes() {\n\t\tConfigurationPropertyName n1 = ConfigurationPropertyName.of(\"example.demo\");\n\t\tConfigurationPropertyName n2 = ConfigurationPropertyName.of(\"example.demo--\");\n\t\tassertThat(n2).isEqualTo(n1);\n\t\tassertThat(n1).isEqualTo(n2);\n\t}\n\n\t@Test\n\tvoid isValidWhenValidShouldReturnTrue() {\n\t\tassertThat(ConfigurationPropertyName.isValid(\"\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo.bar\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo[0]\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo[0].baz\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo.b1\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo.b-a-r\")).isTrue();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo[FooBar].baz\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isValidWhenNotValidShouldReturnFalse() {\n\t\tassertThat(ConfigurationPropertyName.isValid(null)).isFalse();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"-foo\")).isFalse();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"FooBar\")).isFalse();\n\t\tassertThat(ConfigurationPropertyName.isValid(\"foo!bar\")).isFalse();\n\t}\n\n\t@Test\n\tvoid hashCodeIsStored() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"hash.code\");\n\t\tint hashCode = name.hashCode();\n\t\t// hasFieldOrPropertyWithValue would look up for hashCode()\n\t\tassertThat(ReflectionTestUtils.getField(name, \"hashCode\")).isEqualTo(hashCode);\n\t}\n\n\t@Test\n\tvoid hasIndexedElementWhenHasIndexedElementReturnsTrue() {\n\t\tassertThat(ConfigurationPropertyName.of(\"foo[bar]\").hasIndexedElement()).isTrue();\n\t}\n\n\t@Test\n\tvoid hasIndexedElementWhenHasNoIndexedElementReturnsFalse() {\n\t\tassertThat(ConfigurationPropertyName.of(\"foo.bar\").hasIndexedElement()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigurationPropertySource}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertySourceTests {\n\n\t@Test\n\tvoid fromCreatesConfigurationPropertySourcesPropertySource() {\n\t\tMockPropertySource source = new MockPropertySource();\n\t\tsource.setProperty(\"spring\", \"boot\");\n\t\tConfigurationPropertySource adapted = ConfigurationPropertySource.from(source);\n\t\tassertThat(adapted).isNotNull();\n\t\tConfigurationProperty spring = adapted.getConfigurationProperty(ConfigurationPropertyName.of(\"spring\"));\n\t\tassertThat(spring).isNotNull();\n\t\tassertThat(spring.getValue()).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsAlreadyConfigurationPropertySourcesPropertySourceReturnsNull() {\n\t\tConfigurationPropertySourcesPropertySource source = mock(ConfigurationPropertySourcesPropertySource.class);\n\t\tassertThat(ConfigurationPropertySource.from(source)).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesCachingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link ConfigurationPropertySourcesCaching}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertySourcesCachingTests {\n\n\tprivate List<ConfigurationPropertySource> sources;\n\n\tprivate ConfigurationPropertySourcesCaching caching;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.sources = new ArrayList<>();\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tthis.sources.add(mockSource(i % 2 == 0));\n\t\t}\n\t\tthis.caching = new ConfigurationPropertySourcesCaching(this.sources);\n\t}\n\n\tprivate ConfigurationPropertySource mockSource(boolean cachingSource) {\n\t\tif (!cachingSource) {\n\t\t\treturn mock(ConfigurationPropertySource.class);\n\t\t}\n\t\tConfigurationPropertySource source = mock(ConfigurationPropertySource.class,\n\t\t\t\twithSettings().extraInterfaces(CachingConfigurationPropertySource.class));\n\t\tConfigurationPropertyCaching caching = mock(ConfigurationPropertyCaching.class);\n\t\tgiven(((CachingConfigurationPropertySource) source).getCaching()).willReturn(caching);\n\t\treturn source;\n\t}\n\n\t@Test\n\tvoid enableDelegatesToCachingConfigurationPropertySources() {\n\t\tthis.caching.enable();\n\t\tthen(getCaching(0)).should().enable();\n\t\tthen(getCaching(2)).should().enable();\n\t}\n\n\t@Test\n\tvoid enableWhenSourcesIsNullDoesNothing() {\n\t\tnew ConfigurationPropertySourcesCaching(null).enable();\n\t}\n\n\t@Test\n\tvoid disableDelegatesToCachingConfigurationPropertySources() {\n\t\tthis.caching.disable();\n\t\tthen(getCaching(0)).should().disable();\n\t\tthen(getCaching(2)).should().disable();\n\t}\n\n\t@Test\n\tvoid disableWhenSourcesIsNullDoesNothing() {\n\t\tnew ConfigurationPropertySourcesCaching(null).disable();\n\t}\n\n\t@Test\n\tvoid setTimeToLiveDelegatesToCachingConfigurationPropertySources() {\n\t\tDuration ttl = Duration.ofDays(1);\n\t\tthis.caching.setTimeToLive(ttl);\n\t\tthen(getCaching(0)).should().setTimeToLive(ttl);\n\t\tthen(getCaching(2)).should().setTimeToLive(ttl);\n\t}\n\n\t@Test\n\tvoid setTimeToLiveWhenSourcesIsNullDoesNothing() {\n\t\tnew ConfigurationPropertySourcesCaching(null).setTimeToLive(Duration.ofSeconds(1));\n\t}\n\n\t@Test\n\tvoid clearDelegatesToCachingConfigurationPropertySources() {\n\t\tthis.caching.clear();\n\t\tthen(getCaching(0)).should().clear();\n\t\tthen(getCaching(2)).should().clear();\n\t}\n\n\t@Test\n\tvoid clearWhenSourcesIsNullDoesNothing() {\n\t\tnew ConfigurationPropertySourcesCaching(null).enable();\n\t}\n\n\tprivate @Nullable ConfigurationPropertyCaching getCaching(int index) {\n\t\treturn CachingConfigurationPropertySource.find(this.sources.get(index));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertyResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.env.ConfigurablePropertyResolver;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ConfigurationPropertySourcesPropertyResolver}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertySourcesPropertyResolverTests {\n\n\t@Test\n\tvoid standardPropertyResolverResolvesMultipleTimes() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, true);\n\t\tenvironment.getProperty(\"missing\");\n\t\tassertThat(propertySource.getCount(\"missing\")).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid configurationPropertySourcesPropertyResolverResolvesSingleTime() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, true);\n\t\tenvironment.getProperty(\"missing\");\n\t\tassertThat(propertySource.getCount(\"missing\")).isOne();\n\t}\n\n\t@Test\n\tvoid containsPropertyWhenValidConfigurationPropertyName() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, true);\n\t\tassertThat(environment.containsProperty(\"spring\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"sprong\")).isFalse();\n\t\tassertThat(propertySource.getCount(\"spring\")).isOne();\n\t\tassertThat(propertySource.getCount(\"sprong\")).isOne();\n\t}\n\n\t@Test\n\tvoid containsPropertyWhenNotValidConfigurationPropertyName() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, true);\n\t\tassertThat(environment.containsProperty(\"spr!ng\")).isTrue();\n\t\tassertThat(environment.containsProperty(\"spr*ng\")).isFalse();\n\t\tassertThat(propertySource.getCount(\"spr!ng\")).isOne();\n\t\tassertThat(propertySource.getCount(\"spr*ng\")).isOne();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenValidConfigurationPropertyName() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, true);\n\t\tassertThat(environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(environment.getProperty(\"sprong\")).isNull();\n\t\tassertThat(propertySource.getCount(\"spring\")).isOne();\n\t\tassertThat(propertySource.getCount(\"sprong\")).isOne();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNotValidConfigurationPropertyName() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, true);\n\t\tassertThat(environment.getProperty(\"spr!ng\")).isEqualTo(\"boot\");\n\t\tassertThat(environment.getProperty(\"spr*ng\")).isNull();\n\t\tassertThat(propertySource.getCount(\"spr!ng\")).isOne();\n\t\tassertThat(propertySource.getCount(\"spr*ng\")).isOne();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNotAttached() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tCountingMockPropertySource propertySource = createMockPropertySource(environment, false);\n\t\tassertThat(environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(environment.getProperty(\"sprong\")).isNull();\n\t\tassertThat(propertySource.getCount(\"spring\")).isOne();\n\t\tassertThat(propertySource.getCount(\"sprong\")).isOne();\n\t}\n\n\t@Test // gh-26732\n\tvoid getPropertyAsTypeWhenHasPlaceholder() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.withProperty(\"v1\", \"1\");\n\t\tpropertySource.withProperty(\"v2\", \"${v1}\");\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tassertThat(environment.getProperty(\"v2\")).isEqualTo(\"1\");\n\t\tassertThat(environment.getProperty(\"v2\", Integer.class)).isOne();\n\t}\n\n\t@Test\n\tvoid throwsInvalidConfigurationPropertyValueExceptionWhenGetPropertyAsTypeFailsToConvert() {\n\t\tResolverEnvironment environment = new ResolverEnvironment();\n\t\tMockPropertySource propertySource = new MockPropertySource();\n\t\tpropertySource.withProperty(\"v1\", \"one\");\n\t\tpropertySource.withProperty(\"v2\", \"${v1}\");\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tassertThat(environment.getProperty(\"v2\")).isEqualTo(\"one\");\n\t\tassertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t.isThrownBy(() -> environment.getProperty(\"v2\", Integer.class))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getValue()).isEqualTo(\"one\");\n\t\t\t\tassertThat(ex.getSourceType()).isEqualTo(TypeDescriptor.valueOf(String.class));\n\t\t\t\tassertThat(ex.getTargetType()).isEqualTo(TypeDescriptor.valueOf(Integer.class));\n\t\t\t})\n\t\t\t.havingCause()\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tInvalidConfigurationPropertyValueException invalidValueEx = (InvalidConfigurationPropertyValueException) ex;\n\t\t\t\tassertThat(invalidValueEx.getName()).isEqualTo(\"v2\");\n\t\t\t\tassertThat(invalidValueEx.getValue()).isEqualTo(\"one\");\n\t\t\t\tassertThat(ex).cause().isInstanceOf(NumberFormatException.class);\n\t\t\t});\n\t}\n\n\tprivate CountingMockPropertySource createMockPropertySource(StandardEnvironment environment, boolean attach) {\n\t\tCountingMockPropertySource propertySource = new CountingMockPropertySource();\n\t\tpropertySource.withProperty(\"spring\", \"boot\");\n\t\tpropertySource.withProperty(\"spr!ng\", \"boot\");\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tif (attach) {\n\t\t\tConfigurationPropertySources.attach(environment);\n\t\t}\n\t\treturn propertySource;\n\t}\n\n\tstatic class ResolverEnvironment extends StandardEnvironment {\n\n\t\t@Override\n\t\tprotected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {\n\t\t\treturn new ConfigurationPropertySourcesPropertyResolver(propertySources);\n\t\t}\n\n\t}\n\n\tstatic class CountingMockPropertySource extends MockPropertySource {\n\n\t\tprivate final Map<String, AtomicInteger> counts = new HashMap<>();\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\tincrementCount(name);\n\t\t\treturn super.getProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean containsProperty(String name) {\n\t\t\tincrementCount(name);\n\t\t\treturn super.containsProperty(name);\n\t\t}\n\n\t\tprivate void incrementCount(String name) {\n\t\t\tthis.counts.computeIfAbsent(name, (k) -> new AtomicInteger()).incrementAndGet();\n\t\t}\n\n\t\tint getCount(String name) {\n\t\t\tAtomicInteger count = this.counts.get(name);\n\t\t\treturn (count != null) ? count.get() : 0;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertySourcesPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigurationPropertySourcesPropertySourceTests {\n\n\tprivate final List<ConfigurationPropertySource> configurationSources = new ArrayList<>();\n\n\tprivate final ConfigurationPropertySourcesPropertySource propertySource = new ConfigurationPropertySourcesPropertySource(\n\t\t\t\"test\", this.configurationSources);\n\n\t@Test\n\tvoid getPropertyShouldReturnValue() {\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"baz\"));\n\t\tassertThat(this.propertySource.getProperty(\"foo.bar\")).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNameIsNotValidShouldReturnNull() {\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"baz\"));\n\t\tassertThat(this.propertySource.getProperty(\"FOO.B-A-R\")).isNull();\n\t\tassertThat(this.propertySource.getProperty(\"FOO.B A R\")).isNull();\n\t\tassertThat(this.propertySource.getProperty(\".foo.bar\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenMultipleShouldReturnFirst() {\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"baz\"));\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"bill\"));\n\t\tassertThat(this.propertySource.getProperty(\"foo.bar\")).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNoneShouldReturnFirst() {\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"baz\"));\n\t\tassertThat(this.propertySource.getProperty(\"foo.foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyOriginShouldReturnOrigin() {\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"baz\", \"line1\"));\n\t\tassertThat(this.propertySource.getOrigin(\"foo.bar\")).hasToString(\"line1\");\n\t}\n\n\t@Test\n\tvoid getPropertyOriginWhenMissingShouldReturnNull() {\n\t\tthis.configurationSources.add(new MockConfigurationPropertySource(\"foo.bar\", \"baz\", \"line1\"));\n\t\tassertThat(this.propertySource.getOrigin(\"foo.foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid getNameShouldReturnName() {\n\t\tassertThat(this.propertySource.getName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getSourceShouldReturnSource() {\n\t\tassertThat(this.propertySource.getSource()).isSameAs(this.configurationSources);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertySourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertySources}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertySourcesTests {\n\n\t@Test\n\tvoid attachShouldAddAdapterAtBeginning() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tsources.addLast(new SystemEnvironmentPropertySource(\"system\", Collections.singletonMap(\"SERVER_PORT\", \"1234\")));\n\t\tsources.addLast(new MapPropertySource(\"config\", Collections.singletonMap(\"server.port\", \"4568\")));\n\t\tint size = sources.size();\n\t\tConfigurationPropertySources.attach(environment);\n\t\tassertThat(sources).hasSize(size + 1);\n\t\tPropertyResolver resolver = new PropertySourcesPropertyResolver(sources);\n\t\tassertThat(resolver.getProperty(\"server.port\")).isEqualTo(\"1234\");\n\t}\n\n\t@Test\n\tvoid attachShouldReattachInMergedSetup() {\n\t\tConfigurableEnvironment parent = new StandardEnvironment();\n\t\tConfigurationPropertySources.attach(parent);\n\t\tConfigurableEnvironment child = new StandardEnvironment();\n\t\tchild.merge(parent);\n\t\tchild.getPropertySources()\n\t\t\t.addLast(new MapPropertySource(\"config\", Collections.singletonMap(\"my.example_property\", \"1234\")));\n\t\tConfigurationPropertySources.attach(child);\n\t\tassertThat(child.getProperty(\"my.example-property\")).isEqualTo(\"1234\");\n\t}\n\n\t@Test\n\tvoid attachWhenAlreadyAttachedWithSameSourcesShouldReturnExistingInstance() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tsources.addLast(new SystemEnvironmentPropertySource(\"system\", Collections.singletonMap(\"SERVER_PORT\", \"1234\")));\n\t\tsources.addLast(new MapPropertySource(\"config\", Collections.singletonMap(\"server.port\", \"4568\")));\n\t\tConfigurationPropertySources.attach(environment);\n\t\tIterable<ConfigurationPropertySource> first = ConfigurationPropertySources.get(environment);\n\t\tConfigurationPropertySources.attach(environment);\n\t\tIterable<ConfigurationPropertySource> second = ConfigurationPropertySources.get(environment);\n\t\tassertThat(first).isSameAs(second);\n\t}\n\n\t@Test\n\tvoid getWhenNotAttachedShouldReturnAdapted() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tassertThat(ConfigurationPropertySources.get(environment)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid getWhenAttachedShouldReturnAttached() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tsources.addFirst(new MapPropertySource(\"test\", Collections.singletonMap(\"a\", \"b\")));\n\t\tint expectedSize = sources.size();\n\t\tConfigurationPropertySources.attach(environment);\n\t\tassertThat(ConfigurationPropertySources.get(environment)).hasSize(expectedSize);\n\t}\n\n\t@Test\n\tvoid environmentPropertyExpansionShouldWorkWhenAttached() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"fooBar\", \"Spring ${barBaz} ${bar-baz}\");\n\t\tsource.put(\"barBaz\", \"Boot\");\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tConfigurationPropertySources.attach(environment);\n\t\tassertThat(environment.getProperty(\"foo-bar\")).isEqualTo(\"Spring Boot Boot\");\n\t}\n\n\t@Test\n\tvoid fromPropertySourceShouldReturnSpringConfigurationPropertySource() {\n\t\tPropertySource<?> source = new MapPropertySource(\"foo\", Collections.singletonMap(\"foo\", \"bar\"));\n\t\tConfigurationPropertySource configurationPropertySource = ConfigurationPropertySources.from(source)\n\t\t\t.iterator()\n\t\t\t.next();\n\t\tassertThat(configurationPropertySource).isInstanceOf(SpringConfigurationPropertySource.class);\n\t}\n\n\t@Test\n\tvoid fromPropertySourceShouldFlattenPropertySources() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources().addFirst(new MapPropertySource(\"foo\", Collections.singletonMap(\"foo\", \"bar\")));\n\t\tenvironment.getPropertySources().addFirst(new MapPropertySource(\"far\", Collections.singletonMap(\"far\", \"far\")));\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addFirst(new PropertySource<Environment>(\"env\", environment) {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getProperty(String key) {\n\t\t\t\treturn this.source.getProperty(key);\n\t\t\t}\n\n\t\t});\n\t\tsources.addLast(new MapPropertySource(\"baz\", Collections.singletonMap(\"baz\", \"barf\")));\n\t\tIterable<ConfigurationPropertySource> configurationSources = ConfigurationPropertySources.from(sources);\n\t\tassertThat(configurationSources.iterator()).toIterable().hasSize(5);\n\t}\n\n\t@Test // gh-20625\n\tvoid environmentPropertyAccessWhenImmutableShouldBePerformant() {\n\t\tlong baseline = testPropertySourcePerformance(false);\n\t\tlong immutable = testPropertySourcePerformance(true);\n\t\tassertThat(immutable).isLessThan(baseline / 2);\n\t}\n\n\t@Test // gh-20625\n\tvoid environmentPropertyAccessWhenMutableWithCacheShouldBePerformant() {\n\t\tStandardEnvironment environment = createPerformanceTestEnvironment(false);\n\t\tlong uncached = testPropertySourcePerformance(environment);\n\t\tConfigurationPropertyCaching.get(environment).enable();\n\t\tlong cached = testPropertySourcePerformance(environment);\n\t\tassertThat(cached).isLessThan(uncached / 2);\n\t}\n\n\t@Test // gh-20625\n\t@Disabled(\"for manual testing\")\n\tvoid environmentPropertyAccessWhenMutableShouldBeTolerable() {\n\t\tassertThat(testPropertySourcePerformance(false)).isLessThan(5000);\n\t}\n\n\t@Test // gh-21416\n\tvoid descendantOfPropertyAccessWhenMutableWithCacheShouldBePerformant() {\n\t\tFunction<StandardEnvironment, Long> descendantOfPerformance = (environment) -> {\n\t\t\tIterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);\n\t\t\tConfigurationPropertyName missing = ConfigurationPropertyName.of(\"missing\");\n\t\t\tlong start = System.nanoTime();\n\t\t\tfor (int i = 0; i < 1000; i++) {\n\t\t\t\tfor (ConfigurationPropertySource source : sources) {\n\t\t\t\t\tassertThat(source.containsDescendantOf(missing)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);\n\t\t};\n\t\tStandardEnvironment environment = createPerformanceTestEnvironment(false);\n\t\tlong baseline = descendantOfPerformance.apply(environment);\n\t\tConfigurationPropertyCaching.get(environment).enable();\n\t\tlong cached = descendantOfPerformance.apply(environment);\n\t\tassertThat(cached).isLessThan(baseline / 2);\n\t}\n\n\tprivate long testPropertySourcePerformance(boolean immutable) {\n\t\tStandardEnvironment environment = createPerformanceTestEnvironment(immutable);\n\t\treturn testPropertySourcePerformance(environment);\n\t}\n\n\tprivate StandardEnvironment createPerformanceTestEnvironment(boolean immutable) {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tfor (int i = 0; i < 100; i++) {\n\t\t\tpropertySources.addLast(new TestPropertySource(i, immutable));\n\t\t}\n\t\tConfigurationPropertySources.attach(environment);\n\t\treturn environment;\n\t}\n\n\tprivate long testPropertySourcePerformance(StandardEnvironment environment) {\n\t\tlong start = System.nanoTime();\n\t\tfor (int i = 0; i < 1000; i++) {\n\t\t\tenvironment.getProperty(\"missing\" + i);\n\t\t}\n\t\tlong total = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);\n\t\tassertThat(environment.getProperty(\"test-10-property-80\")).isEqualTo(\"test-10-property-80-value\");\n\t\treturn total;\n\t}\n\n\tstatic class TestPropertySource extends MapPropertySource implements PropertySourceInfo {\n\n\t\tprivate final boolean immutable;\n\n\t\tTestPropertySource(int index, boolean immutable) {\n\t\t\tsuper(\"test-\" + index, createProperties(index));\n\t\t\tthis.immutable = immutable;\n\t\t}\n\n\t\tprivate static Map<String, Object> createProperties(int index) {\n\t\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\t\tfor (int i = 0; i < 1000; i++) {\n\t\t\t\tString name = \"test-\" + index + \"-property-\" + i;\n\t\t\t\tString value = name + \"-value\";\n\t\t\t\tmap.put(name, value);\n\t\t\t}\n\t\t\treturn map;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isImmutable() {\n\t\t\treturn this.immutable;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyStateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConfigurationPropertyState}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertyStateTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid searchWhenIterableIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ConfigurationPropertyState.search(null, (e) -> true))\n\t\t\t.withMessageContaining(\"'source' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid searchWhenPredicateIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ConfigurationPropertyState.search(Collections.emptyList(), null))\n\t\t\t.withMessageContaining(\"'predicate' must not be null\");\n\t}\n\n\t@Test\n\tvoid searchWhenContainsItemShouldReturnPresent() {\n\t\tList<String> source = Arrays.asList(\"a\", \"b\", \"c\");\n\t\tConfigurationPropertyState result = ConfigurationPropertyState.search(source, \"b\"::equals);\n\t\tassertThat(result).isEqualTo(ConfigurationPropertyState.PRESENT);\n\t}\n\n\t@Test\n\tvoid searchWhenContainsNoItemShouldReturnAbsent() {\n\t\tList<String> source = Arrays.asList(\"a\", \"x\", \"c\");\n\t\tConfigurationPropertyState result = ConfigurationPropertyState.search(source, \"b\"::equals);\n\t\tassertThat(result).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/ConfigurationPropertyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Objects;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigurationProperty}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass ConfigurationPropertyTests {\n\n\tprivate static final ConfigurationPropertyName NAME = ConfigurationPropertyName.of(\"foo\");\n\n\tprivate final ConfigurationPropertySource source = Objects\n\t\t.requireNonNull(ConfigurationPropertySource.from(mock(PropertySource.class)));\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenNameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigurationProperty(null, \"bar\", null))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenValueIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigurationProperty(NAME, null, null))\n\t\t\t.withMessageContaining(\"'value' must not be null\");\n\t}\n\n\t@Test\n\tvoid getNameShouldReturnName() {\n\t\tConfigurationProperty property = ConfigurationProperty.of(this.source, NAME, \"foo\", null);\n\t\tassertThat((Object) property.getName()).isEqualTo(NAME);\n\t}\n\n\t@Test\n\tvoid getValueShouldReturnValue() {\n\t\tConfigurationProperty property = ConfigurationProperty.of(this.source, NAME, \"foo\", null);\n\t\tassertThat(property.getValue()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getPropertyOriginShouldReturnValuePropertyOrigin() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tOriginProvider property = ConfigurationProperty.of(this.source, NAME, \"foo\", origin);\n\t\tassertThat(property.getOrigin()).isEqualTo(origin);\n\t}\n\n\t@Test\n\tvoid getPropertySourceShouldReturnPropertySource() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tConfigurationProperty property = ConfigurationProperty.of(this.source, NAME, \"foo\", origin);\n\t\tassertThat(property.getSource()).isEqualTo(this.source);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tConfigurationProperty property1 = new ConfigurationProperty(ConfigurationPropertyName.of(\"foo\"), \"bar\", null);\n\t\tConfigurationProperty property2 = new ConfigurationProperty(ConfigurationPropertyName.of(\"foo\"), \"bar\", null);\n\t\tConfigurationProperty property3 = new ConfigurationProperty(ConfigurationPropertyName.of(\"foo\"), \"baz\", null);\n\t\tConfigurationProperty property4 = new ConfigurationProperty(ConfigurationPropertyName.of(\"baz\"), \"bar\", null);\n\t\tassertThat(property1).hasSameHashCodeAs(property2);\n\t\tassertThat(property1).isEqualTo(property2).isNotEqualTo(property3).isNotEqualTo(property4);\n\t}\n\n\t@Test\n\tvoid toStringShouldReturnValue() {\n\t\tConfigurationProperty property = ConfigurationProperty.of(this.source, NAME, \"foo\", null);\n\t\tassertThat(property.toString()).contains(\"name\").contains(\"value\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/DefaultPropertyMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DefaultPropertyMapper}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass DefaultPropertyMapperTests extends AbstractPropertyMapperTests {\n\n\t@Override\n\tprotected PropertyMapper getMapper() {\n\t\treturn DefaultPropertyMapper.INSTANCE;\n\t}\n\n\t@Test\n\tvoid mapFromStringShouldReturnBestGuess() {\n\t\tassertThat(mapPropertySourceName(\"server\")).isEqualTo(\"server\");\n\t\tassertThat(mapPropertySourceName(\"server.port\")).isEqualTo(\"server.port\");\n\t\tassertThat(mapPropertySourceName(\"host[0]\")).isEqualTo(\"host[0]\");\n\t\tassertThat(mapPropertySourceName(\"host[0][1]\")).isEqualTo(\"host[0][1]\");\n\t\tassertThat(mapPropertySourceName(\"host[0].name\")).isEqualTo(\"host[0].name\");\n\t\tassertThat(mapPropertySourceName(\"host.f00.name\")).isEqualTo(\"host.f00.name\");\n\t\tassertThat(mapPropertySourceName(\"my.host-name\")).isEqualTo(\"my.host-name\");\n\t\tassertThat(mapPropertySourceName(\"my.hostName\")).isEqualTo(\"my.hostname\");\n\t\tassertThat(mapPropertySourceName(\"my.HOST_NAME\")).isEqualTo(\"my.hostname\");\n\t\tassertThat(mapPropertySourceName(\"s[!@#$%^&*()=+]e-rVeR\")).isEqualTo(\"s[!@#$%^&*()=+].e-rver\");\n\t\tassertThat(mapPropertySourceName(\"host[FOO].name\")).isEqualTo(\"host[FOO].name\");\n\t}\n\n\t@Test\n\tvoid mapFromConfigurationShouldReturnBestGuess() {\n\t\tassertThat(mapConfigurationPropertyName(\"server\")).containsExactly(\"server\");\n\t\tassertThat(mapConfigurationPropertyName(\"server.port\")).containsExactly(\"server.port\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[0]\")).containsExactly(\"host[0]\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[0][1]\")).containsExactly(\"host[0][1]\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[0].name\")).containsExactly(\"host[0].name\");\n\t\tassertThat(mapConfigurationPropertyName(\"host.f00.name\")).containsExactly(\"host.f00.name\");\n\t\tassertThat(mapConfigurationPropertyName(\"my.host-name\")).containsExactly(\"my.host-name\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[FOO].name\")).containsExactly(\"host[FOO].name\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredConfigurationPropertiesSourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Objects;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Test for {@link FilteredIterableConfigurationPropertiesSource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass FilteredConfigurationPropertiesSourceTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new FilteredConfigurationPropertiesSource(null, Objects::nonNull))\n\t\t\t.withMessageContaining(\"'source' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenFilterIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new FilteredConfigurationPropertiesSource(new MockConfigurationPropertySource(), null))\n\t\t\t.withMessageContaining(\"'filter' must not be null\");\n\t}\n\n\t@Test\n\tvoid getValueShouldFilterNames() {\n\t\tConfigurationPropertySource source = createTestSource();\n\t\tConfigurationPropertySource filtered = source.filter(this::noBrackets);\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"a\");\n\t\tConfigurationProperty configurationProperty = source.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"1\");\n\t\tConfigurationProperty configurationProperty2 = filtered.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty2).isNotNull();\n\t\tassertThat(configurationProperty2.getValue()).isEqualTo(\"1\");\n\t\tConfigurationPropertyName bracketName = ConfigurationPropertyName.of(\"a[1]\");\n\t\tConfigurationProperty configurationProperty3 = source.getConfigurationProperty(bracketName);\n\t\tassertThat(configurationProperty3).isNotNull();\n\t\tassertThat(configurationProperty3.getValue()).isEqualTo(\"2\");\n\t\tassertThat(filtered.getConfigurationProperty(bracketName)).isNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsEmptyShouldReturnEmpty() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().unknown(name);\n\t\tConfigurationPropertySource filtered = source.filter((n) -> true);\n\t\tassertThat(filtered.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsFalseShouldReturnFalse() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().absent(name);\n\t\tConfigurationPropertySource filtered = source.filter((n) -> true);\n\t\tassertThat(filtered.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsTrueShouldReturnEmpty() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().present(name);\n\t\tConfigurationPropertySource filtered = source.filter((n) -> true);\n\t\tassertThat(filtered.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.UNKNOWN);\n\t}\n\n\tprotected final ConfigurationPropertySource createTestSource() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"a\", \"1\");\n\t\tsource.put(\"a[1]\", \"2\");\n\t\tsource.put(\"b\", \"3\");\n\t\tsource.put(\"b[1]\", \"4\");\n\t\tsource.put(\"c\", \"5\");\n\t\treturn convertSource(source);\n\t}\n\n\tprotected ConfigurationPropertySource convertSource(MockConfigurationPropertySource source) {\n\t\treturn source.nonIterable();\n\t}\n\n\tprivate boolean noBrackets(ConfigurationPropertyName name) {\n\t\treturn !name.toString().contains(\"[\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/FilteredIterableConfigurationPropertiesSourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.assertj.core.extractor.Extractors;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.OriginTrackedMapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link FilteredIterableConfigurationPropertiesSource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass FilteredIterableConfigurationPropertiesSourceTests extends FilteredConfigurationPropertiesSourceTests {\n\n\t@Test\n\tvoid iteratorFiltersNames() {\n\t\tMockConfigurationPropertySource source = (MockConfigurationPropertySource) createTestSource();\n\t\tIterableConfigurationPropertySource filtered = source.filter(this::noBrackets);\n\t\tassertThat(filtered.iterator()).toIterable()\n\t\t\t.extracting(ConfigurationPropertyName::toString)\n\t\t\t.containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid containsDescendantOfUsesContents() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"foo.bar.baz\", \"1\");\n\t\tsource.put(\"foo.bar[0]\", \"1\");\n\t\tsource.put(\"faf.bar[0]\", \"1\");\n\t\tIterableConfigurationPropertySource filtered = source.filter(this::noBrackets);\n\t\tassertThat(filtered.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(filtered.containsDescendantOf(ConfigurationPropertyName.of(\"faf\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Test\n\tvoid iteratorWhenSpringPropertySourceFiltersNames() {\n\t\tIterableConfigurationPropertySource testSource = (IterableConfigurationPropertySource) createTestSource();\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tfor (ConfigurationPropertyName name : testSource) {\n\t\t\tConfigurationProperty configurationProperty = testSource.getConfigurationProperty(name);\n\t\t\tassertThat(configurationProperty).isNotNull();\n\t\t\tmap.put(name.toString(), configurationProperty.getValue());\n\t\t}\n\t\tPropertySource<?> propertySource = new OriginTrackedMapPropertySource(\"test\", map, true);\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource.from(propertySource);\n\t\tIterableConfigurationPropertySource filtered = (IterableConfigurationPropertySource) source\n\t\t\t.filter(this::noBrackets);\n\t\tassertThat(Extractors.byName(\"filteredNames\").apply(filtered)).isNotNull();\n\t\tassertThat(filtered.iterator()).toIterable()\n\t\t\t.extracting(ConfigurationPropertyName::toString)\n\t\t\t.containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid iteratorWhenSpringPropertySourceAndAnotherFilterFiltersNames() {\n\t\tIterableConfigurationPropertySource testSource = (IterableConfigurationPropertySource) createTestSource();\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tfor (ConfigurationPropertyName name : testSource) {\n\t\t\tConfigurationProperty configurationProperty = testSource.getConfigurationProperty(name);\n\t\t\tassertThat(configurationProperty).isNotNull();\n\t\t\tmap.put(name.toString(), configurationProperty.getValue());\n\t\t}\n\t\tPropertySource<?> propertySource = new OriginTrackedMapPropertySource(\"test\", map, true);\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource.from(propertySource);\n\t\tIterableConfigurationPropertySource filtered = (IterableConfigurationPropertySource) source\n\t\t\t.filter(this::noBrackets);\n\t\tIterableConfigurationPropertySource secondFiltered = filtered.filter((name) -> !name.toString().contains(\"c\"));\n\t\tassertThat(Extractors.byName(\"filteredNames\").apply(filtered)).isNotNull();\n\t\tassertThat(secondFiltered.iterator()).toIterable()\n\t\t\t.extracting(ConfigurationPropertyName::toString)\n\t\t\t.containsExactly(\"a\", \"b\");\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSpringPropertySourceUsesContents() {\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"foo.bar.baz\", \"1\");\n\t\tmap.put(\"foo.bar[0]\", \"1\");\n\t\tmap.put(\"faf.bar[0]\", \"1\");\n\t\tPropertySource<?> propertySource = new OriginTrackedMapPropertySource(\"test\", map, true);\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource.from(propertySource);\n\t\tIterableConfigurationPropertySource filtered = (IterableConfigurationPropertySource) source\n\t\t\t.filter(this::noBrackets);\n\t\tassertThat(Extractors.byName(\"filteredNames\").apply(filtered)).isNotNull();\n\t\tassertThat(filtered.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(filtered.containsDescendantOf(ConfigurationPropertyName.of(\"faf\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Override\n\tprotected ConfigurationPropertySource convertSource(MockConfigurationPropertySource source) {\n\t\treturn source;\n\t}\n\n\tprivate boolean noBrackets(ConfigurationPropertyName name) {\n\t\treturn !name.toString().contains(\"[\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/KnownAncestorsConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass KnownAncestorsConfigurationPropertySource implements ConfigurationPropertySource {\n\n\tprivate final Map<ConfigurationPropertyName, ConfigurationPropertyState> ancestors = new HashMap<>();\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyState containsDescendantOf(ConfigurationPropertyName name) {\n\t\tConfigurationPropertyState state = this.ancestors.get(name);\n\t\tassertThat(state).isNotNull();\n\t\treturn state;\n\t}\n\n\tKnownAncestorsConfigurationPropertySource absent(ConfigurationPropertyName name) {\n\t\treturn ancestor(name, ConfigurationPropertyState.ABSENT);\n\t}\n\n\tKnownAncestorsConfigurationPropertySource present(ConfigurationPropertyName name) {\n\t\treturn ancestor(name, ConfigurationPropertyState.PRESENT);\n\t}\n\n\tKnownAncestorsConfigurationPropertySource unknown(ConfigurationPropertyName name) {\n\t\treturn ancestor(name, ConfigurationPropertyState.UNKNOWN);\n\t}\n\n\tprivate KnownAncestorsConfigurationPropertySource ancestor(ConfigurationPropertyName name,\n\t\t\tConfigurationPropertyState state) {\n\t\tthis.ancestors.put(name, state);\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MapConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link MapConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass MapConfigurationPropertySourceTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenMapIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new MapConfigurationPropertySource(null))\n\t\t\t.withMessageContaining(\"'map' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenMapHasEntriesShouldAdaptMap() {\n\t\tMap<Object, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"foo.BAR\", \"spring\");\n\t\tmap.put(ConfigurationPropertyName.of(\"foo.baz\"), \"boot\");\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tassertThat(getValue(source, \"foo.bar\")).isEqualTo(\"spring\");\n\t\tassertThat(getValue(source, \"foo.baz\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid putAllWhenMapIsNullShouldThrowException() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> source.putAll(null))\n\t\t\t.withMessageContaining(\"'map' must not be null\");\n\t}\n\n\t@Test\n\tvoid putAllShouldPutEntries() {\n\t\tMap<Object, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"foo.BAR\", \"spring\");\n\t\tmap.put(\"foo.baz\", \"boot\");\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.putAll(map);\n\t\tassertThat(getValue(source, \"foo.bar\")).isEqualTo(\"spring\");\n\t\tassertThat(getValue(source, \"foo.baz\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid putShouldPutEntry() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"baz\");\n\t\tassertThat(getValue(source, \"foo.bar\")).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid getConfigurationPropertyShouldGetFromMemory() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"foo.bar\", \"baz\");\n\t\tassertThat(getValue(source, \"foo.bar\")).isEqualTo(\"baz\");\n\t\tsource.put(\"foo.bar\", \"big\");\n\t\tassertThat(getValue(source, \"foo.bar\")).isEqualTo(\"big\");\n\t}\n\n\t@Test\n\tvoid iteratorShouldGetFromMemory() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"foo.BAR\", \"spring\");\n\t\tsource.put(\"foo.baz\", \"boot\");\n\t\tassertThat(source.iterator()).toIterable()\n\t\t\t.containsExactly(ConfigurationPropertyName.of(\"foo.bar\"), ConfigurationPropertyName.of(\"foo.baz\"));\n\t}\n\n\t@Test\n\tvoid streamShouldGetFromMemory() {\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\t\tsource.put(\"foo.BAR\", \"spring\");\n\t\tsource.put(\"foo.baz\", \"boot\");\n\t\tassertThat(source.stream()).containsExactly(ConfigurationPropertyName.of(\"foo.bar\"),\n\t\t\t\tConfigurationPropertyName.of(\"foo.baz\"));\n\n\t}\n\n\tprivate @Nullable Object getValue(ConfigurationPropertySource source, String name) {\n\t\tConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name));\n\t\treturn (property != null) ? property.getValue() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MockConfigurationPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.MockOrigin;\nimport org.springframework.boot.origin.OriginTrackedValue;\n\n/**\n * Mock {@link ConfigurationPropertySource} implementation used for testing.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\npublic class MockConfigurationPropertySource implements IterableConfigurationPropertySource {\n\n\tprivate final Map<ConfigurationPropertyName, OriginTrackedValue> map = new LinkedHashMap<>();\n\n\tpublic MockConfigurationPropertySource() {\n\t}\n\n\tpublic MockConfigurationPropertySource(String configurationPropertyName, Object value) {\n\t\tthis(configurationPropertyName, value, null);\n\t}\n\n\tpublic MockConfigurationPropertySource(String configurationPropertyName, Object value, @Nullable String origin) {\n\t\tput(ConfigurationPropertyName.of(configurationPropertyName),\n\t\t\t\tOriginTrackedValue.of(value, MockOrigin.of(origin)));\n\t}\n\n\tpublic MockConfigurationPropertySource(Map<String, String> configs) {\n\t\tconfigs.forEach(this::put);\n\t}\n\n\tpublic void put(String name, @Nullable String value) {\n\t\tput(ConfigurationPropertyName.of(name), value);\n\t}\n\n\tpublic void put(ConfigurationPropertyName name, @Nullable String value) {\n\t\tput(name, OriginTrackedValue.of(value));\n\t}\n\n\tprivate void put(ConfigurationPropertyName name, @Nullable OriginTrackedValue value) {\n\t\tthis.map.put(name, value);\n\t}\n\n\tpublic ConfigurationPropertySource nonIterable() {\n\t\treturn new NonIterable();\n\t}\n\n\t@Override\n\tpublic Iterator<ConfigurationPropertyName> iterator() {\n\t\treturn this.map.keySet().iterator();\n\t}\n\n\t@Override\n\tpublic Stream<ConfigurationPropertyName> stream() {\n\t\treturn this.map.keySet().stream();\n\t}\n\n\t@Override\n\tpublic Object getUnderlyingSource() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\tOriginTrackedValue result = this.map.get(name);\n\t\tif (result == null) {\n\t\t\tresult = findValue(name);\n\t\t}\n\t\treturn ConfigurationProperty.of(name, result);\n\t}\n\n\tprivate @Nullable OriginTrackedValue findValue(ConfigurationPropertyName name) {\n\t\treturn this.map.get(name);\n\t}\n\n\tprivate final class NonIterable implements ConfigurationPropertySource {\n\n\t\t@Override\n\t\tpublic Object getUnderlyingSource() {\n\t\t\treturn MockConfigurationPropertySource.this.map;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConfigurationProperty getConfigurationProperty(ConfigurationPropertyName name) {\n\t\t\treturn MockConfigurationPropertySource.this.getConfigurationProperty(name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/MutuallyExclusiveConfigurationPropertiesExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link MutuallyExclusiveConfigurationPropertiesException}.\n *\n * @author Phillip Webb\n */\nclass MutuallyExclusiveConfigurationPropertiesExceptionTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenConfiguredNamesIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new MutuallyExclusiveConfigurationPropertiesException(null, Arrays.asList(\"a\", \"b\")))\n\t\t\t.withMessage(\"'configuredNames' must contain 2 or more names\");\n\t}\n\n\t@Test\n\tvoid createWhenConfiguredNamesContainsOneElementThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new MutuallyExclusiveConfigurationPropertiesException(Collections.singleton(\"a\"),\n\t\t\t\t\tArrays.asList(\"a\", \"b\")))\n\t\t\t.withMessage(\"'configuredNames' must contain 2 or more names\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenMutuallyExclusiveNamesIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new MutuallyExclusiveConfigurationPropertiesException(Arrays.asList(\"a\", \"b\"), null))\n\t\t\t.withMessage(\"'mutuallyExclusiveNames' must contain 2 or more names\");\n\t}\n\n\t@Test\n\tvoid createWhenMutuallyExclusiveNamesContainsOneElementThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new MutuallyExclusiveConfigurationPropertiesException(Arrays.asList(\"a\", \"b\"),\n\t\t\t\t\tCollections.singleton(\"a\")))\n\t\t\t.withMessage(\"'mutuallyExclusiveNames' must contain 2 or more names\");\n\t}\n\n\t@Test\n\tvoid createBuildsSensibleMessage() {\n\t\tList<String> names = Arrays.asList(\"a\", \"b\");\n\t\tassertThat(new MutuallyExclusiveConfigurationPropertiesException(names, names))\n\t\t\t.hasMessage(\"The configuration properties 'a, b' are mutually exclusive \"\n\t\t\t\t\t+ \"and 'a, b' have been configured together\");\n\t}\n\n\t@Test\n\tvoid getConfiguredNamesReturnsConfiguredNames() {\n\t\tList<String> configuredNames = Arrays.asList(\"a\", \"b\");\n\t\tList<String> mutuallyExclusiveNames = Arrays.asList(\"a\", \"b\", \"c\");\n\t\tMutuallyExclusiveConfigurationPropertiesException exception = new MutuallyExclusiveConfigurationPropertiesException(\n\t\t\t\tconfiguredNames, mutuallyExclusiveNames);\n\t\tassertThat(exception.getConfiguredNames()).hasSameElementsAs(configuredNames);\n\t}\n\n\t@Test\n\tvoid getMutuallyExclusiveNamesReturnsMutuallyExclusiveNames() {\n\t\tList<String> configuredNames = Arrays.asList(\"a\", \"b\");\n\t\tList<String> mutuallyExclusiveNames = Arrays.asList(\"a\", \"b\", \"c\");\n\t\tMutuallyExclusiveConfigurationPropertiesException exception = new MutuallyExclusiveConfigurationPropertiesException(\n\t\t\t\tconfiguredNames, mutuallyExclusiveNames);\n\t\tassertThat(exception.getMutuallyExclusiveNames()).hasSameElementsAs(mutuallyExclusiveNames);\n\t}\n\n\t@Test\n\tvoid throwIfMultipleNonNullValuesInWhenEntriesHasAllNullsDoesNotThrowException() {\n\t\tassertThatNoException().isThrownBy(\n\t\t\t\t() -> MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\t\tentries.put(\"a\", null);\n\t\t\t\t\tentries.put(\"b\", null);\n\t\t\t\t\tentries.put(\"c\", null);\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid throwIfMultipleNonNullValuesInWhenEntriesHasSingleNonNullDoesNotThrowException() {\n\t\tassertThatNoException().isThrownBy(\n\t\t\t\t() -> MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\t\tentries.put(\"a\", null);\n\t\t\t\t\tentries.put(\"b\", \"B\");\n\t\t\t\t\tentries.put(\"c\", null);\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid throwIfMultipleNonNullValuesInWhenEntriesHasTwoNonNullsThrowsException() {\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class).isThrownBy(\n\t\t\t\t() -> MutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\t\tentries.put(\"a\", \"a\");\n\t\t\t\t\tentries.put(\"b\", \"B\");\n\t\t\t\t\tentries.put(\"c\", null);\n\t\t\t\t}))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getConfiguredNames()).containsExactly(\"a\", \"b\");\n\t\t\t\tassertThat(ex.getMutuallyExclusiveNames()).containsExactly(\"a\", \"b\", \"c\");\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PrefixedConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PrefixedConfigurationPropertySource}.\n *\n * @author Madhura Bhave\n */\nclass PrefixedConfigurationPropertySourceTests {\n\n\t@Test\n\tvoid getConfigurationPropertyShouldConsiderPrefix() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"my.foo.bar\", \"bing\");\n\t\tsource.put(\"my.foo.baz\", \"biff\");\n\t\tConfigurationPropertySource prefixed = source.nonIterable().withPrefix(\"my\");\n\t\tassertThat(getName(prefixed, \"foo.bar\")).hasToString(\"foo.bar\");\n\t\tassertThat(getValue(prefixed, \"foo.bar\")).isEqualTo(\"bing\");\n\t\tassertThat(getName(prefixed, \"foo.baz\")).hasToString(\"foo.baz\");\n\t\tassertThat(getValue(prefixed, \"foo.baz\")).isEqualTo(\"biff\");\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsUnknownShouldReturnUnknown() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().unknown(name);\n\t\tConfigurationPropertySource prefixed = source.withPrefix(\"my\");\n\t\tassertThat(prefixed.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsPresentShouldReturnPresent() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().present(name)\n\t\t\t.unknown(ConfigurationPropertyName.of(\"bar\"));\n\t\tConfigurationPropertySource prefixed = source.withPrefix(\"my\");\n\t\tassertThat(prefixed.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSourceReturnsAbsentShouldReturnAbsent() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.foo\");\n\t\tConfigurationPropertySource source = new KnownAncestorsConfigurationPropertySource().absent(name)\n\t\t\t.absent(ConfigurationPropertyName.of(\"bar\"));\n\t\tConfigurationPropertySource prefixed = source.withPrefix(\"my\");\n\t\tassertThat(prefixed.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Test\n\tvoid withPrefixWhenPrefixIsNullReturnsOriginalSource() {\n\t\tConfigurationPropertySource source = new MockConfigurationPropertySource().nonIterable();\n\t\tConfigurationPropertySource prefixed = source.withPrefix(null);\n\t\tassertThat(prefixed).isSameAs(source);\n\t}\n\n\t@Test\n\tvoid withPrefixWhenPrefixIsEmptyReturnsOriginalSource() {\n\t\tConfigurationPropertySource source = new MockConfigurationPropertySource().nonIterable();\n\t\tConfigurationPropertySource prefixed = source.withPrefix(\"\");\n\t\tassertThat(prefixed).isSameAs(source);\n\t}\n\n\tprivate @Nullable ConfigurationPropertyName getName(ConfigurationPropertySource source, String name) {\n\t\tConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name));\n\t\treturn (property != null) ? property.getName() : null;\n\t}\n\n\tprivate @Nullable Object getValue(ConfigurationPropertySource source, String name) {\n\t\tConfigurationProperty property = source.getConfigurationProperty(ConfigurationPropertyName.of(name));\n\t\treturn (property != null) ? property.getValue() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/PrefixedIterableConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PrefixedIterableConfigurationPropertySource}.\n *\n * @author Madhura Bhave\n */\nclass PrefixedIterableConfigurationPropertySourceTests {\n\n\t@Test\n\tvoid streamShouldConsiderPrefix() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"my.foo.bar\", \"bing\");\n\t\tsource.put(\"my.foo.baz\", \"biff\");\n\t\tsource.put(\"hello.bing\", \"blah\");\n\t\tIterableConfigurationPropertySource prefixed = source.withPrefix(\"my\");\n\t\tassertThat(prefixed.stream()).containsExactly(ConfigurationPropertyName.of(\"foo.bar\"),\n\t\t\t\tConfigurationPropertyName.of(\"foo.baz\"), ConfigurationPropertyName.of(\"hello.bing\"));\n\t}\n\n\t@Test\n\tvoid emptyPrefixShouldReturnOriginalStream() {\n\t\tMockConfigurationPropertySource source = new MockConfigurationPropertySource();\n\t\tsource.put(\"my.foo.bar\", \"bing\");\n\t\tsource.put(\"my.foo.baz\", \"biff\");\n\t\tsource.put(\"hello.bing\", \"blah\");\n\t\tIterableConfigurationPropertySource prefixed = source.withPrefix(\"\");\n\t\tassertThat(prefixed.stream()).containsExactly(ConfigurationPropertyName.of(\"my.foo.bar\"),\n\t\t\t\tConfigurationPropertyName.of(\"my.foo.baz\"), ConfigurationPropertyName.of(\"hello.bing\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SoftReferenceConfigurationPropertyCacheTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneOffset;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyCaching.CacheOverride;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SoftReferenceConfigurationPropertyCache}.\n *\n * @author Phillip Webb\n */\nclass SoftReferenceConfigurationPropertyCacheTests {\n\n\tprivate static final Clock FIXED_CLOCK = Clock.fixed(Instant.parse(\"2020-01-02T09:00:00Z\"), ZoneOffset.UTC);\n\n\tprivate Clock clock = FIXED_CLOCK;\n\n\tprivate final AtomicInteger createCount = new AtomicInteger();\n\n\tprivate TestSoftReferenceConfigurationPropertyCache cache = new TestSoftReferenceConfigurationPropertyCache(false);\n\n\t@Test\n\tvoid getReturnsValueWithCorrectCounts() {\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 1);\n\t\tget(this.cache).assertCounts(0, 2);\n\t}\n\n\t@Test\n\tvoid getWhenNeverExpireReturnsValueWithCorrectCounts() {\n\t\tthis.cache = new TestSoftReferenceConfigurationPropertyCache(true);\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 0);\n\t}\n\n\t@Test\n\tvoid enableEnablesCachingWithUnlimitedTimeToLive() {\n\t\tthis.cache.enable();\n\t\tget(this.cache).assertCounts(0, 0);\n\t\ttick(Duration.ofDays(300));\n\t\tget(this.cache).assertCounts(0, 0);\n\t}\n\n\t@Test\n\tvoid setTimeToLiveEnablesCachingWithTimeToLive() {\n\t\tthis.cache.setTimeToLive(Duration.ofDays(1));\n\t\tget(this.cache).assertCounts(0, 0);\n\t\ttick(Duration.ofHours(2));\n\t\tget(this.cache).assertCounts(0, 0);\n\t\ttick(Duration.ofDays(2));\n\t\tget(this.cache).assertCounts(0, 1);\n\t}\n\n\t@Test\n\tvoid setTimeToLiveWhenZeroDisablesCaching() {\n\t\tthis.cache.setTimeToLive(Duration.ZERO);\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 1);\n\t\tget(this.cache).assertCounts(0, 2);\n\t}\n\n\t@Test\n\tvoid setTimeToLiveWhenNullDisablesCaching() {\n\t\tthis.cache.setTimeToLive(null);\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 1);\n\t\tget(this.cache).assertCounts(0, 2);\n\t}\n\n\t@Test\n\tvoid clearExpiresCache() {\n\t\tthis.cache.enable();\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tthis.cache.clear();\n\t\tget(this.cache).assertCounts(0, 1);\n\t}\n\n\t@Test\n\tvoid overrideWhenNeverExpiresReturnsNoOpOverride() {\n\t\tTestSoftReferenceConfigurationPropertyCache cache = new TestSoftReferenceConfigurationPropertyCache(true);\n\t\tassertThat(cache.override()).isSameAs(SoftReferenceConfigurationPropertyCache.NO_OP_OVERRIDE);\n\t}\n\n\t@Test\n\tvoid overrideEnablesCaching() {\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 1);\n\t\ttry (CacheOverride override = this.cache.override()) {\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t}\n\t\tget(this.cache).assertCounts(0, 3);\n\t}\n\n\t@Test\n\tvoid overrideWhenHasExistingTimeToLiveEnablesCaching() {\n\t\tthis.cache.setTimeToLive(Duration.ofHours(1));\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 0);\n\t\ttick(Duration.ofHours(2));\n\t\tget(this.cache).assertCounts(0, 1);\n\t\ttry (CacheOverride override = this.cache.override()) {\n\t\t\tget(this.cache).assertCounts(0, 1);\n\t\t\ttick(Duration.ofHours(2));\n\t\t\tget(this.cache).assertCounts(0, 1);\n\t\t}\n\t\tget(this.cache).assertCounts(0, 2);\n\t\tget(this.cache).assertCounts(0, 2);\n\t\ttick(Duration.ofHours(2));\n\t\tget(this.cache).assertCounts(0, 3);\n\t}\n\n\t@Test\n\tvoid overrideWhenDisabledDoesNotReturnStaleData() {\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 1);\n\t\tthis.cache.disable();\n\t\ttry (CacheOverride override = this.cache.override()) {\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t}\n\t\tget(this.cache).assertCounts(0, 3);\n\t}\n\n\t@Test\n\tvoid overrideCanBeClosedTwiceWithoutIssue() {\n\t\tget(this.cache).assertCounts(0, 0);\n\t\tget(this.cache).assertCounts(0, 1);\n\t\tthis.cache.disable();\n\t\ttry (CacheOverride override = this.cache.override()) {\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t\tget(this.cache).assertCounts(0, 2);\n\t\t\toverride.close();\n\t\t\tget(this.cache).assertCounts(0, 3);\n\t\t}\n\t\tget(this.cache).assertCounts(0, 4);\n\n\t}\n\n\tprivate Value get(SoftReferenceConfigurationPropertyCache<Value> cache) {\n\t\treturn cache.get(this::createValue, this::updateValue);\n\t}\n\n\tprivate Value createValue() {\n\t\treturn new Value(this.createCount.getAndIncrement(), -1);\n\t}\n\n\tprivate Value updateValue(Value value) {\n\t\treturn new Value(value.createCount, value.refreshCount + 1);\n\t}\n\n\tprivate void tick(Duration duration) {\n\t\tthis.clock = Clock.offset(this.clock, duration);\n\t}\n\n\t/**\n\t * Testable {@link SoftReferenceConfigurationPropertyCache} that actually uses real\n\t * references.\n\t */\n\tclass TestSoftReferenceConfigurationPropertyCache extends SoftReferenceConfigurationPropertyCache<Value> {\n\n\t\tprivate @Nullable Value value;\n\n\t\tTestSoftReferenceConfigurationPropertyCache(boolean neverExpire) {\n\t\t\tsuper(neverExpire);\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable Value getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Override\n\t\tprotected void setValue(Value value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tprotected Instant now() {\n\t\t\treturn SoftReferenceConfigurationPropertyCacheTests.this.clock.instant();\n\t\t}\n\n\t}\n\n\t/**\n\t * Value used for testing.\n\t */\n\tstatic class Value {\n\n\t\tprivate final int createCount;\n\n\t\tprivate final int refreshCount;\n\n\t\tValue(int createCount, int refreshCount) {\n\t\t\tthis.createCount = createCount;\n\t\t\tthis.refreshCount = refreshCount;\n\t\t}\n\n\t\tvoid assertCounts(int expectedCreateCount, int expectedRefreshCount) {\n\t\t\tassertThat(this.createCount).as(\"created\").isEqualTo(expectedCreateCount);\n\t\t\tassertThat(this.refreshCount).as(\"refreshed\").isEqualTo(expectedRefreshCount);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.RandomValuePropertySource;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass SpringConfigurationPropertySourceTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertySourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new SpringConfigurationPropertySource(null, false, mock(PropertyMapper.class)))\n\t\t\t.withMessageContaining(\"'propertySource' must not be null\");\n\t}\n\n\t@Test\n\tvoid getValueShouldUseDirectMapping() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key1\", \"value1\");\n\t\tsource.put(\"key2\", \"value2\");\n\t\tsource.put(\"key3\", \"value3\");\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tmapper.addFromConfigurationProperty(name, \"key2\");\n\t\tSpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false,\n\t\t\t\tmapper);\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"value2\");\n\t}\n\n\t@Test\n\tvoid getValueOriginAndPropertySource() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key\", \"value\");\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tmapper.addFromConfigurationProperty(name, \"key\");\n\t\tSpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false,\n\t\t\t\tmapper);\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getOrigin()).hasToString(\"\\\"key\\\" from property source \\\"test\\\"\");\n\t\tassertThat(configurationProperty.getSource()).isEqualTo(adapter);\n\t}\n\n\t@Test\n\tvoid getValueWhenOriginCapableShouldIncludeSourceOrigin() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key\", \"value\");\n\t\tPropertySource<?> propertySource = new OriginCapablePropertySource<>(new MapPropertySource(\"test\", source));\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tmapper.addFromConfigurationProperty(name, \"key\");\n\t\tSpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false,\n\t\t\t\tmapper);\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getOrigin()).hasToString(\"TestOrigin key\");\n\t}\n\n\t@Test\n\tvoid containsDescendantOfShouldReturnEmpty() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"foo.bar\", \"value\");\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tSpringConfigurationPropertySource adapter = new SpringConfigurationPropertySource(propertySource, false,\n\t\t\t\tDefaultPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.UNKNOWN);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromWhenPropertySourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> SpringConfigurationPropertySource.from(null))\n\t\t\t.withMessageContaining(\"'source' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromWhenNonEnumerableShouldReturnNonIterable() {\n\t\tPropertySource<?> propertySource = new PropertySource<>(\"test\", new Object()) {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t};\n\t\tassertThat(SpringConfigurationPropertySource.from(propertySource))\n\t\t\t.isNotInstanceOf(IterableConfigurationPropertySource.class);\n\n\t}\n\n\t@Test\n\tvoid fromWhenEnumerableButRestrictedShouldReturnNonIterable() {\n\t\tMap<String, Object> source = new LinkedHashMap<>() {\n\n\t\t\t@Override\n\t\t\tpublic int size() {\n\t\t\t\tthrow new UnsupportedOperationException(\"Same as security restricted\");\n\t\t\t}\n\n\t\t};\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tassertThat(SpringConfigurationPropertySource.from(propertySource))\n\t\t\t.isNotInstanceOf(IterableConfigurationPropertySource.class);\n\t}\n\n\t@Test\n\tvoid getWhenEnumerableShouldBeIterable() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"fooBar\", \"Spring ${barBaz} ${bar-baz}\");\n\t\tsource.put(\"barBaz\", \"Boot\");\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tassertThat(SpringConfigurationPropertySource.from(propertySource))\n\t\t\t.isInstanceOf(IterableConfigurationPropertySource.class);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenRandomSourceAndRandomPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomValuePropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"random\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenRandomSourceAndRandomPrefixedPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomValuePropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"random.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNotNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenRandomSourceWithDifferentNameAndRandomPrefixedPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomValuePropertySource(\"different\"));\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"random.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNotNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenRandomSourceAndNonRandomPropertyReturnsAbsent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomValuePropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"abandon.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenWrappedRandomSourceAndRandomPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomWrapperPropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"cachedrandom\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenWrappedRandomSourceAndRandomPrefixedPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomWrapperPropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"cachedrandom.something.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenWrappedRandomSourceWithMatchingNameAndRandomPrefixedPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomWrapperPropertySource(\"cachedrandom\"));\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"cachedrandom.something.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNotNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenWrappedRandomSourceAndRandomDashPrefixedPropertyReturnsPresent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomWrapperPropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"cached-random.something.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNull();\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenWrappedRandomSourceAndNonRandomPropertyReturnsAbsent() {\n\t\tSpringConfigurationPropertySource source = SpringConfigurationPropertySource\n\t\t\t.from(new RandomWrapperPropertySource());\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"abandon.something.int\");\n\t\tassertThat(source.containsDescendantOf(name)).isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(source.getConfigurationProperty(name)).isNull();\n\t}\n\n\tstatic class RandomWrapperPropertySource extends PropertySource<RandomValuePropertySource> {\n\n\t\tprivate final String prefix;\n\n\t\tRandomWrapperPropertySource() {\n\t\t\tthis(\"cachedRandom\");\n\t\t}\n\n\t\tRandomWrapperPropertySource(String name) {\n\t\t\tsuper(name, new RandomValuePropertySource());\n\t\t\tthis.prefix = name + \".\";\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\tname = name.toLowerCase(Locale.ROOT);\n\t\t\tif (!name.startsWith(this.prefix)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn getSource().getProperty(\"random.\" + name.substring(this.prefix.length()));\n\t\t}\n\n\t}\n\n\t/**\n\t * Test {@link PropertySource} that's also an {@link OriginLookup}.\n\t *\n\t * @param <T> The source type\n\t */\n\tstatic class OriginCapablePropertySource<T> extends PropertySource<T> implements OriginLookup<String> {\n\n\t\tprivate final PropertySource<T> propertySource;\n\n\t\tOriginCapablePropertySource(PropertySource<T> propertySource) {\n\t\t\tsuper(propertySource.getName(), propertySource.getSource());\n\t\t\tthis.propertySource = propertySource;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\treturn this.propertySource.getProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String name) {\n\t\t\treturn new Origin() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String toString() {\n\t\t\t\t\treturn \"TestOrigin \" + name;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringConfigurationPropertySourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\nimport java.util.Iterator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.RandomValuePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link SpringConfigurationPropertySources}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass SpringConfigurationPropertySourcesTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertySourcesIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new SpringConfigurationPropertySources(null))\n\t\t\t.withMessageContaining(\"'sources' must not be null\");\n\t}\n\n\t@Test\n\tvoid shouldAdaptPropertySource() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addFirst(new MapPropertySource(\"test\", Collections.singletonMap(\"a\", \"b\")));\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"a\");\n\t\tConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"b\");\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldAdaptSystemEnvironmentPropertySource() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tCollections.singletonMap(\"SERVER_PORT\", \"1234\")));\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"server.port\");\n\t\tConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"1234\");\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldExtendedAdaptSystemEnvironmentPropertySource() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addLast(new SystemEnvironmentPropertySource(\n\t\t\t\t\"test-\" + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tCollections.singletonMap(\"SERVER_PORT\", \"1234\")));\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"server.port\");\n\t\tConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"1234\");\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldNotAdaptSystemEnvironmentPropertyOverrideSource() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources\n\t\t\t.addLast(new SystemEnvironmentPropertySource(\"override\", Collections.singletonMap(\"server.port\", \"1234\")));\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"server.port\");\n\t\tConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"1234\");\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldAdaptSystemEnvironmentPropertySourceWithUnderscoreValue() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tCollections.singletonMap(\"_\", \"1234\")));\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"bar\");\n\t\tassertThat(iterator.next().getConfigurationProperty(name)).isNull();\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldAdaptMultiplePropertySources() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addLast(new SystemEnvironmentPropertySource(\"system\", Collections.singletonMap(\"SERVER_PORT\", \"1234\")));\n\t\tsources.addLast(new MapPropertySource(\"test1\", Collections.singletonMap(\"server.po-rt\", \"4567\")));\n\t\tsources.addLast(new MapPropertySource(\"test2\", Collections.singletonMap(\"a\", \"b\")));\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"server.port\");\n\t\tConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"1234\");\n\t\tconfigurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"4567\");\n\t\tconfigurationProperty = iterator.next().getConfigurationProperty(ConfigurationPropertyName.of(\"a\"));\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"b\");\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldFlattenEnvironment() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources().addFirst(new MapPropertySource(\"foo\", Collections.singletonMap(\"foo\", \"bar\")));\n\t\tenvironment.getPropertySources().addFirst(new MapPropertySource(\"far\", Collections.singletonMap(\"far\", \"far\")));\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addFirst(new PropertySource<Environment>(\"env\", environment) {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getProperty(String key) {\n\t\t\t\treturn this.source.getProperty(key);\n\t\t\t}\n\n\t\t});\n\t\tsources.addLast(new MapPropertySource(\"baz\", Collections.singletonMap(\"baz\", \"barf\")));\n\t\tSpringConfigurationPropertySources configurationSources = new SpringConfigurationPropertySources(sources);\n\t\tassertThat(configurationSources.iterator()).toIterable().hasSize(5);\n\t}\n\n\t@Test\n\tvoid shouldTrackChanges() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tSpringConfigurationPropertySources configurationSources = new SpringConfigurationPropertySources(sources);\n\t\tassertThat(configurationSources.iterator()).toIterable().isEmpty();\n\t\tMapPropertySource source1 = new MapPropertySource(\"test1\", Collections.singletonMap(\"a\", \"b\"));\n\t\tsources.addLast(source1);\n\t\tassertThat(configurationSources.iterator()).toIterable().hasSize(1);\n\t\tMapPropertySource source2 = new MapPropertySource(\"test2\", Collections.singletonMap(\"b\", \"c\"));\n\t\tsources.addLast(source2);\n\t\tassertThat(configurationSources.iterator()).toIterable().hasSize(2);\n\t}\n\n\t@Test\n\tvoid shouldTrackWhenSourceHasIdenticalName() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tSpringConfigurationPropertySources configurationSources = new SpringConfigurationPropertySources(sources);\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"a\");\n\t\tMapPropertySource source1 = new MapPropertySource(\"test\", Collections.singletonMap(\"a\", \"s1\"));\n\t\tsources.addLast(source1);\n\t\tConfigurationProperty configurationProperty = configurationSources.iterator()\n\t\t\t.next()\n\t\t\t.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"s1\");\n\t\tMapPropertySource source2 = new MapPropertySource(\"test\", Collections.singletonMap(\"a\", \"s2\"));\n\t\tsources.remove(\"test\");\n\t\tsources.addLast(source2);\n\t\tconfigurationProperty = configurationSources.iterator().next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"s2\");\n\t}\n\n\t@Test // gh-21659\n\tvoid shouldAdaptRandomPropertySource() {\n\t\tMutablePropertySources sources = new MutablePropertySources();\n\t\tsources.addFirst(new RandomValuePropertySource());\n\t\tIterator<ConfigurationPropertySource> iterator = new SpringConfigurationPropertySources(sources).iterator();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"random.int\");\n\t\tConfigurationProperty configurationProperty = iterator.next().getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isNotNull();\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.ConcurrentModificationException;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.OriginTrackedMapPropertySource;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringIterableConfigurationPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Fahim Farook\n */\nclass SpringIterableConfigurationPropertySourceTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertySourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new SpringIterableConfigurationPropertySource(null, false, mock(PropertyMapper.class)))\n\t\t\t.withMessageContaining(\"'propertySource' must not be null\");\n\t}\n\n\t@Test\n\tvoid iteratorShouldAdaptNames() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key1\", \"value1\");\n\t\tsource.put(\"key2\", \"value2\");\n\t\tsource.put(\"key3\", \"value3\");\n\t\tsource.put(\"key4\", \"value4\");\n\t\tEnumerablePropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tTestPropertyMapper mapper1 = new TestPropertyMapper();\n\t\tmapper1.addFromPropertySource(\"key1\", \"my.key1\");\n\t\tmapper1.addFromPropertySource(\"key2\", \"my.key2a\");\n\t\tmapper1.addFromPropertySource(\"key4\", \"my.key4\");\n\t\tTestPropertyMapper mapper2 = new TestPropertyMapper();\n\t\tmapper2.addFromPropertySource(\"key2\", \"my.key2b\");\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, false, mapper1, mapper2);\n\t\tassertThat(adapter.iterator()).toIterable()\n\t\t\t.extracting(Object::toString)\n\t\t\t.containsExactly(\"my.key1\", \"my.key2a\", \"my.key4\");\n\t}\n\n\t@Test\n\tvoid getValueShouldUseDirectMapping() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key1\", \"value1\");\n\t\tsource.put(\"key2\", \"value2\");\n\t\tsource.put(\"key3\", \"value3\");\n\t\tEnumerablePropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tmapper.addFromConfigurationProperty(name, \"key2\");\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, false, mapper);\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"value2\");\n\t}\n\n\t@Test\n\tvoid getValueShouldUseEnumerableMapping() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key1\", \"value1\");\n\t\tsource.put(\"key2\", \"value2\");\n\t\tsource.put(\"key3\", \"value3\");\n\t\tEnumerablePropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tmapper.addFromPropertySource(\"key1\", \"my.missing\");\n\t\tmapper.addFromPropertySource(\"key2\", \"my.k-e-y\");\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, false, mapper);\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getValue()).isEqualTo(\"value2\");\n\t}\n\n\t@Test\n\tvoid getValueOrigin() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key\", \"value\");\n\t\tEnumerablePropertySource<?> propertySource = new MapPropertySource(\"test\", source);\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tmapper.addFromConfigurationProperty(name, \"key\");\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, false, mapper);\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getOrigin()).hasToString(\"\\\"key\\\" from property source \\\"test\\\"\");\n\t}\n\n\t@Test\n\tvoid getValueWhenOriginCapableShouldIncludeSourceOrigin() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"key\", \"value\");\n\t\tEnumerablePropertySource<?> propertySource = new OriginCapablePropertySource<>(\n\t\t\t\tnew MapPropertySource(\"test\", source));\n\t\tTestPropertyMapper mapper = new TestPropertyMapper();\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.key\");\n\t\tmapper.addFromConfigurationProperty(name, \"key\");\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, false, mapper);\n\t\tConfigurationProperty configurationProperty = adapter.getConfigurationProperty(name);\n\t\tassertThat(configurationProperty).isNotNull();\n\t\tassertThat(configurationProperty.getOrigin()).hasToString(\"TestOrigin key\");\n\t}\n\n\t@Test\n\tvoid containsDescendantOfShouldCheckSourceNames() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"foo.bar\", \"value\");\n\t\tsource.put(\"faf\", \"value\");\n\t\tEnumerablePropertySource<?> propertySource = new OriginCapablePropertySource<>(\n\t\t\t\tnew MapPropertySource(\"test\", source));\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, false, DefaultPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"foo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"faf\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"fof\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Test\n\tvoid containsDescendantOfWhenSystemEnvironmentPropertySourceShouldSupportLegacyProperty() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"FOO_BAR_BAZ_BONG\", \"bing\");\n\t\tsource.put(\"FOO_ALPHABRAVO_GAMMA\", \"delta\");\n\t\tsource.put(\"loo_bar_baz_bong\", \"bing\");\n\t\tsource.put(\"loo_alphabravo_gamma\", \"delta\");\n\t\tSystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, source);\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, true, SystemEnvironmentPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"foo.bar-baz\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"foo.alpha-bravo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"foo.blah\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"loo.bar-baz\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"loo.alpha-bravo\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tassertThat(adapter.containsDescendantOf(ConfigurationPropertyName.of(\"loo.blah\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.ABSENT);\n\t}\n\n\t@Test\n\tvoid getConfigurationPropertyWhenSystemEnvironmentPropertySourceShouldSupportLegacyProperty() {\n\t\tMap<String, Object> source = new LinkedHashMap<>();\n\t\tsource.put(\"TEST_VALUE_UPPER\", \"upper\");\n\t\tsource.put(\"test_value_lower\", \"lower\");\n\t\tSystemEnvironmentPropertySource propertySource = new SystemEnvironmentPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, source);\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(\n\t\t\t\tpropertySource, true, SystemEnvironmentPropertyMapper.INSTANCE, DefaultPropertyMapper.INSTANCE);\n\t\tConfigurationProperty valueUpper = adapter\n\t\t\t.getConfigurationProperty(ConfigurationPropertyName.of(\"test.value-upper\"));\n\t\tassertThat(valueUpper).isNotNull();\n\t\tassertThat(valueUpper.getValue()).isEqualTo(\"upper\");\n\t\tConfigurationProperty valueLower = adapter\n\t\t\t.getConfigurationProperty(ConfigurationPropertyName.of(\"test.value-lower\"));\n\t\tassertThat(valueLower).isNotNull();\n\t\tassertThat(valueLower.getValue()).isEqualTo(\"lower\");\n\t}\n\n\t@Test\n\tvoid simpleMapPropertySourceKeyDataChangeInvalidatesCache() {\n\t\t// gh-13344\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"key1\", \"value1\");\n\t\tmap.put(\"key2\", \"value2\");\n\t\tEnumerablePropertySource<?> source = new MapPropertySource(\"test\", map);\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(source, false,\n\t\t\t\tDefaultPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.stream()).hasSize(2);\n\t\tmap.put(\"key3\", \"value3\");\n\t\tassertThat(adapter.stream()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid concurrentModificationExceptionInvalidatesCache() {\n\t\t// gh-17013\n\t\tConcurrentModificationThrowingMap<String, Object> map = new ConcurrentModificationThrowingMap<>();\n\t\tmap.put(\"key1\", \"value1\");\n\t\tmap.put(\"key2\", \"value2\");\n\t\tEnumerablePropertySource<?> source = new MapPropertySource(\"test\", map);\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(source, false,\n\t\t\t\tDefaultPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.stream()).hasSize(2);\n\t\tmap.setThrowException(true);\n\t\tmap.put(\"key3\", \"value3\");\n\t\tassertThat(adapter.stream()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid originTrackedMapPropertySourceKeyAdditionInvalidatesCache() {\n\t\t// gh-13344\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"key1\", \"value1\");\n\t\tmap.put(\"key2\", \"value2\");\n\t\tEnumerablePropertySource<?> source = new OriginTrackedMapPropertySource(\"test\", map);\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(source, false,\n\t\t\t\tDefaultPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.stream()).hasSize(2);\n\t\tmap.put(\"key3\", \"value3\");\n\t\tassertThat(adapter.stream()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid readOnlyOriginTrackedMapPropertySourceKeyAdditionDoesNotInvalidateCache() {\n\t\t// gh-16717\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"key1\", \"value1\");\n\t\tmap.put(\"key2\", \"value2\");\n\t\tEnumerablePropertySource<?> source = new OriginTrackedMapPropertySource(\"test\", map, true);\n\t\tSpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(source, false,\n\t\t\t\tDefaultPropertyMapper.INSTANCE);\n\t\tassertThat(adapter.stream()).hasSize(2);\n\t\tmap.put(\"key3\", \"value3\");\n\t\tassertThat(adapter.stream()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid orderOfUnderlyingSourceIsPreserved() {\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"test.map.alpha\", \"value1\");\n\t\tmap.put(\"test.map.bravo\", \"value2\");\n\t\tmap.put(\"test.map.charlie\", \"value3\");\n\t\tmap.put(\"test.map.delta\", \"value4\");\n\t\tEnumerablePropertySource<?> source = new OriginTrackedMapPropertySource(\"test\", map, true);\n\t\tSpringIterableConfigurationPropertySource propertySource = new SpringIterableConfigurationPropertySource(source,\n\t\t\t\tfalse, DefaultPropertyMapper.INSTANCE);\n\t\tassertThat(propertySource.stream().map(ConfigurationPropertyName::toString)).containsExactly(\"test.map.alpha\",\n\t\t\t\t\"test.map.bravo\", \"test.map.charlie\", \"test.map.delta\");\n\t}\n\n\t@Test\n\tvoid cacheRefreshRecalculatesDescendants() {\n\t\t// gh-45639\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"one.two.three\", \"test\");\n\t\tEnumerablePropertySource<?> source = new OriginTrackedMapPropertySource(\"test\", map, false);\n\t\tSpringIterableConfigurationPropertySource propertySource = new SpringIterableConfigurationPropertySource(source,\n\t\t\t\tfalse, DefaultPropertyMapper.INSTANCE);\n\t\tassertThat(propertySource.containsDescendantOf(ConfigurationPropertyName.of(\"one.two\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t\tmap.put(\"new\", \"value\");\n\t\tassertThat(propertySource.containsDescendantOf(ConfigurationPropertyName.of(\"one.two\")))\n\t\t\t.isEqualTo(ConfigurationPropertyState.PRESENT);\n\t}\n\n\t/**\n\t * Test {@link PropertySource} that's also an {@link OriginLookup}.\n\t *\n\t * @param <T> the source type\n\t */\n\tstatic class OriginCapablePropertySource<T> extends EnumerablePropertySource<T> implements OriginLookup<String> {\n\n\t\tprivate final EnumerablePropertySource<T> propertySource;\n\n\t\tOriginCapablePropertySource(EnumerablePropertySource<T> propertySource) {\n\t\t\tsuper(propertySource.getName(), propertySource.getSource());\n\t\t\tthis.propertySource = propertySource;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\treturn this.propertySource.getProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getPropertyNames() {\n\t\t\treturn this.propertySource.getPropertyNames();\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String name) {\n\t\t\treturn new Origin() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String toString() {\n\t\t\t\t\treturn \"TestOrigin \" + name;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class ConcurrentModificationThrowingMap<K, V> extends LinkedHashMap<K, V> {\n\n\t\tprivate boolean throwException;\n\n\t\tvoid setThrowException(boolean throwException) {\n\t\t\tthis.throwException = throwException;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<K> keySet() {\n\t\t\treturn new KeySet(super.keySet());\n\t\t}\n\n\t\tprivate class KeySet extends LinkedHashSet<K> {\n\n\t\t\tKeySet(Set<K> keySet) {\n\t\t\t\tsuper(keySet);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Iterator<K> iterator() {\n\t\t\t\tif (ConcurrentModificationThrowingMap.this.throwException) {\n\t\t\t\t\tConcurrentModificationThrowingMap.this.throwException = false;\n\t\t\t\t\tthrow new ConcurrentModificationException();\n\t\t\t\t}\n\t\t\t\treturn super.iterator();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SystemEnvironmentPropertyMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.function.BiPredicate;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SystemEnvironmentPropertyMapper}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass SystemEnvironmentPropertyMapperTests extends AbstractPropertyMapperTests {\n\n\t@Override\n\tprotected PropertyMapper getMapper() {\n\t\treturn SystemEnvironmentPropertyMapper.INSTANCE;\n\t}\n\n\t@Test\n\tvoid mapFromStringShouldReturnBestGuess() {\n\t\tassertThat(mapPropertySourceName(\"SERVER\")).isEqualTo(\"server\");\n\t\tassertThat(mapPropertySourceName(\"SERVER_PORT\")).isEqualTo(\"server.port\");\n\t\tassertThat(mapPropertySourceName(\"HOST_0\")).isEqualTo(\"host[0]\");\n\t\tassertThat(mapPropertySourceName(\"HOST_0_1\")).isEqualTo(\"host[0][1]\");\n\t\tassertThat(mapPropertySourceName(\"HOST_0_NAME\")).isEqualTo(\"host[0].name\");\n\t\tassertThat(mapPropertySourceName(\"HOST_F00_NAME\")).isEqualTo(\"host.f00.name\");\n\t\tassertThat(mapPropertySourceName(\"S-ERVER\")).isEqualTo(\"s-erver\");\n\t}\n\n\t@Test\n\tvoid mapFromConfigurationShouldReturnBestGuess() {\n\t\tassertThat(mapConfigurationPropertyName(\"server\")).containsExactly(\"SERVER\", \"server\");\n\t\tassertThat(mapConfigurationPropertyName(\"server.port\")).containsExactly(\"SERVER_PORT\", \"server_port\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[0]\")).containsExactly(\"HOST_0\", \"host_0\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[0][1]\")).containsExactly(\"HOST_0_1\", \"host_0_1\");\n\t\tassertThat(mapConfigurationPropertyName(\"host[0].name\")).containsExactly(\"HOST_0_NAME\", \"host_0_name\");\n\t\tassertThat(mapConfigurationPropertyName(\"host.f00.name\")).containsExactly(\"HOST_F00_NAME\", \"host_f00_name\");\n\t\tassertThat(mapConfigurationPropertyName(\"foo.the-bar\")).containsExactly(\"FOO_THEBAR\", \"FOO_THE_BAR\",\n\t\t\t\t\"foo_thebar\", \"foo_the_bar\");\n\t}\n\n\t@Test\n\tvoid underscoreShouldMapToEmptyString() {\n\t\tConfigurationPropertyName mapped = getMapper().map(\"_\");\n\t\tassertThat(mapped.isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid underscoreWithWhitespaceShouldMapToEmptyString() {\n\t\tConfigurationPropertyName mapped = getMapper().map(\" _\");\n\t\tassertThat(mapped.isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid isAncestorOfConsidersLegacyNames() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.of(\"my.spring-boot\");\n\t\tBiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> check = getMapper().getAncestorOfCheck();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.adapt(\"MY_SPRING_BOOT_PROPERTY\", '_'))).isTrue();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.adapt(\"MY_SPRINGBOOT_PROPERTY\", '_'))).isTrue();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.adapt(\"MY_BOOT_PROPERTY\", '_'))).isFalse();\n\t}\n\n\t@Test\n\tvoid isAncestorOfWhenNonCanonicalSource() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"my.springBoot\", '.');\n\t\tBiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> check = getMapper().getAncestorOfCheck();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.of(\"my.spring-boot.property\"))).isTrue();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.of(\"my.springboot.property\"))).isTrue();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.of(\"my.boot.property\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isAncestorOfWhenNonCanonicalAndDashedSource() {\n\t\tConfigurationPropertyName name = ConfigurationPropertyName.adapt(\"my.springBoot.input-value\", '.');\n\t\tBiPredicate<ConfigurationPropertyName, ConfigurationPropertyName> check = getMapper().getAncestorOfCheck();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.of(\"my.spring-boot.input-value.property\"))).isTrue();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.of(\"my.springboot.inputvalue.property\"))).isTrue();\n\t\tassertThat(check.test(name, ConfigurationPropertyName.of(\"my.boot.property\"))).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/TestPropertyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * Test {@link PropertyMapper} implementation.\n */\nclass TestPropertyMapper implements PropertyMapper {\n\n\tprivate final MultiValueMap<ConfigurationPropertyName, String> fromConfig = new LinkedMultiValueMap<>();\n\n\tprivate final Map<String, ConfigurationPropertyName> fromSource = new LinkedHashMap<>();\n\n\tvoid addFromPropertySource(String from, String to) {\n\t\tthis.fromSource.put(from, ConfigurationPropertyName.of(to));\n\t}\n\n\tvoid addFromConfigurationProperty(ConfigurationPropertyName from, String... to) {\n\t\tfor (String propertySourceName : to) {\n\t\t\tthis.fromConfig.add(from, propertySourceName);\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<String> map(ConfigurationPropertyName configurationPropertyName) {\n\t\treturn this.fromConfig.getOrDefault(configurationPropertyName, Collections.emptyList());\n\t}\n\n\t@Override\n\tpublic ConfigurationPropertyName map(String propertySourceName) {\n\t\treturn this.fromSource.getOrDefault(propertySourceName, ConfigurationPropertyName.EMPTY);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/context/properties/source/UnboundElementsSourceFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.source;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link UnboundElementsSourceFilter}.\n *\n * @author Madhura Bhave\n */\nclass UnboundElementsSourceFilterTests {\n\n\tprivate UnboundElementsSourceFilter filter;\n\n\tprivate ConfigurationPropertySource source;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.filter = new UnboundElementsSourceFilter();\n\t\tthis.source = mock(ConfigurationPropertySource.class);\n\t}\n\n\t@Test\n\tvoid filterWhenSourceIsSystemPropertiesPropertySourceShouldReturnFalse() {\n\t\tMockPropertySource propertySource = new MockPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);\n\t\tgiven(this.source.getUnderlyingSource()).willReturn(propertySource);\n\t\tassertThat(this.filter.apply(this.source)).isFalse();\n\t}\n\n\t@Test\n\tvoid filterWhenSourceIsSystemEnvironmentPropertySourceShouldReturnFalse() {\n\t\tMockPropertySource propertySource = new MockPropertySource(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);\n\t\tgiven(this.source.getUnderlyingSource()).willReturn(propertySource);\n\t\tassertThat(this.filter.apply(this.source)).isFalse();\n\t}\n\n\t@Test\n\tvoid filterWhenSourceIsNotSystemShouldReturnTrue() {\n\t\tMockPropertySource propertySource = new MockPropertySource(\"test\");\n\t\tgiven(this.source.getUnderlyingSource()).willReturn(propertySource);\n\t\tassertThat(this.filter.apply(this.source)).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/ApplicationConversionServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.text.ParseException;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.assertj.core.api.ThrowableAssert.ThrowingCallable;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.convert.ApplicationConversionService.ConverterBeanAdapter;\nimport org.springframework.boot.convert.ApplicationConversionService.ParserBeanAdapter;\nimport org.springframework.boot.convert.ApplicationConversionService.PrinterBeanAdapter;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.ConditionalConverter;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.ConverterFactory;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.format.AnnotationFormatterFactory;\nimport org.springframework.format.Formatter;\nimport org.springframework.format.FormatterRegistry;\nimport org.springframework.format.Parser;\nimport org.springframework.format.Printer;\nimport org.springframework.format.support.FormattingConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link ApplicationConversionService}.\n *\n * @author Phillip Webb\n * @author Shixiong Guo\n */\nclass ApplicationConversionServiceTests {\n\n\tprivate final FormatterRegistry registry = mock(FormatterRegistry.class,\n\t\t\twithSettings().extraInterfaces(ConversionService.class));\n\n\t@Test\n\tvoid addBeansWhenHasGenericConverterBeanAddConverter() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tExampleGenericConverter.class)) {\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should().addConverter(context.getBean(ExampleGenericConverter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\tvoid addBeansWhenHasConverterBeanAddConverter() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExampleConverter.class)) {\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should().addConverter(context.getBean(ExampleConverter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\tvoid addBeansWhenHasFormatterBeanAddsOnlyFormatter() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExampleFormatter.class)) {\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should().addFormatter(context.getBean(ExampleFormatter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\tvoid addBeansWhenHasPrinterBeanAddPrinter() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExamplePrinter.class)) {\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should().addPrinter(context.getBean(ExamplePrinter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\tvoid addBeansWhenHasParserBeanAddParser() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExampleParser.class)) {\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should().addParser(context.getBean(ExampleParser.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid addBeansWhenHasConverterBeanMethodAddConverter() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tConverterBeanMethodConfiguration.class)) {\n\t\t\tConverter<String, Integer> converter = (Converter<String, Integer>) context.getBean(\"converter\");\n\t\t\twillThrow(IllegalArgumentException.class).given(this.registry).addConverter(converter);\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should().addConverter(any(ConverterBeanAdapter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid addBeansWhenHasPrinterBeanMethodAddPrinter() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tPrinterBeanMethodConfiguration.class)) {\n\t\t\tPrinter<Integer> printer = (Printer<Integer>) context.getBean(\"printer\");\n\t\t\twillThrow(IllegalArgumentException.class).given(this.registry).addPrinter(printer);\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should(never()).addPrinter(printer);\n\t\t\tthen(this.registry).should().addConverter(any(PrinterBeanAdapter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid addBeansWhenHasParserBeanMethodAddParser() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tParserBeanMethodConfiguration.class)) {\n\t\t\tParser<Integer> parser = (Parser<Integer>) context.getBean(\"parser\");\n\t\t\twillThrow(IllegalArgumentException.class).given(this.registry).addParser(parser);\n\t\t\tApplicationConversionService.addBeans(this.registry, context);\n\t\t\tthen(this.registry).should(never()).addParser(parser);\n\t\t\tthen(this.registry).should().addConverter(any(ParserBeanAdapter.class));\n\t\t\tthen(this.registry).shouldHaveNoMoreInteractions();\n\t\t}\n\t}\n\n\t@Test\n\tvoid isConvertViaObjectSourceTypeWhenObjectSourceReturnsTrue() {\n\t\t// Uses ObjectToCollectionConverter\n\t\tApplicationConversionService conversionService = new ApplicationConversionService();\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(Long.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.valueOf(List.class);\n\t\tassertThat(conversionService.canConvert(sourceType, targetType)).isTrue();\n\t\tassertThat(conversionService.isConvertViaObjectSourceType(sourceType, targetType)).isTrue();\n\t}\n\n\t@Test\n\tvoid isConvertViaObjectSourceTypeWhenNotObjectSourceReturnsFalse() {\n\t\t// Uses StringToCollectionConverter\n\t\tApplicationConversionService conversionService = new ApplicationConversionService();\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.valueOf(List.class);\n\t\tassertThat(conversionService.canConvert(sourceType, targetType)).isTrue();\n\t\tassertThat(conversionService.isConvertViaObjectSourceType(sourceType, targetType)).isFalse();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid sharedInstanceCannotBeModified() {\n\t\tApplicationConversionService instance = (ApplicationConversionService) ApplicationConversionService\n\t\t\t.getSharedInstance();\n\t\tPrinter<?> printer = mock(Printer.class);\n\t\tParser<?> parser = mock(Parser.class);\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addPrinter(printer));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addParser(parser));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addFormatter(mock(Formatter.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldType(getClass(), mock(Formatter.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addConverter(mock(Converter.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addFormatterForFieldType(getClass(), printer, parser));\n\t\tassertUnmodifiableExceptionThrown(\n\t\t\t\t() -> instance.addFormatterForFieldAnnotation(mock(AnnotationFormatterFactory.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addConverter(getClass(), getClass(), mock(Converter.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addConverter(mock(GenericConverter.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.addConverterFactory(mock(ConverterFactory.class)));\n\t\tassertUnmodifiableExceptionThrown(() -> instance.removeConvertible(getClass(), getClass()));\n\t}\n\n\t@Test\n\tvoid addPrinterBeanWithTypeConvertsUsingTypeInformation() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tPrinter<?> printer = (object, locale) -> object.toString().toUpperCase(locale);\n\t\tApplicationConversionService.addBean(conversionService, printer,\n\t\t\t\tResolvableType.forClassWithGenerics(Printer.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(new ExampleRecord(\"test\"), String.class)).isEqualTo(\"TEST\");\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(new OtherRecord(\"test\"), String.class));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> conversionService.addPrinter(printer))\n\t\t\t.withMessageContaining(\"Unable to extract\");\n\t}\n\n\t@Test\n\tvoid addParserBeanWithTypeConvertsUsingTypeInformation() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tParser<?> parser = (text, locale) -> new ExampleRecord(text.toString());\n\t\tApplicationConversionService.addBean(conversionService, parser,\n\t\t\t\tResolvableType.forClassWithGenerics(Parser.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(\"test\", ExampleRecord.class)).isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(\"test\", OtherRecord.class));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> conversionService.addParser(parser))\n\t\t\t.withMessageContaining(\"Unable to extract\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid addFormatterBeanWithTypeConvertsUsingTypeInformation() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tFormatter<?> formatter = new Formatter() {\n\n\t\t\t@Override\n\t\t\tpublic String print(Object object, Locale locale) {\n\t\t\t\treturn object.toString().toUpperCase(locale);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Object parse(String text, Locale locale) throws ParseException {\n\t\t\t\treturn new ExampleRecord(text.toString());\n\t\t\t}\n\n\t\t};\n\t\tApplicationConversionService.addBean(conversionService, formatter,\n\t\t\t\tResolvableType.forClassWithGenerics(Formatter.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(new ExampleRecord(\"test\"), String.class)).isEqualTo(\"TEST\");\n\t\tassertThat(conversionService.convert(\"test\", ExampleRecord.class)).isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(new OtherRecord(\"test\"), String.class));\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(\"test\", OtherRecord.class));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> conversionService.addFormatter(formatter))\n\t\t\t.withMessageContaining(\"Unable to extract\");\n\t}\n\n\t@Test\n\tvoid addConverterBeanWithTypeConvertsUsingTypeInformation() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tConverter<?, ?> converter = (source) -> new ExampleRecord(source.toString());\n\t\tApplicationConversionService.addBean(conversionService, converter,\n\t\t\t\tResolvableType.forClassWithGenerics(Converter.class, CharSequence.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(\"test\", ExampleRecord.class)).isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThat(conversionService.convert(new StringBuilder(\"test\"), ExampleRecord.class))\n\t\t\t.isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(\"test\", OtherRecord.class));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> conversionService.addConverter(converter))\n\t\t\t.withMessageContaining(\"Unable to determine\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid addConverterBeanWithTypeWhenConditionalChecksCondition() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tConditionalConverterConverter<?, ?> converter = new ConditionalConverterConverter() {\n\n\t\t\t@Override\n\t\t\tpublic Object convert(Object source) {\n\t\t\t\treturn new ExampleRecord(source.toString());\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\t\treturn sourceType.getType() != StringBuilder.class;\n\t\t\t}\n\n\t\t};\n\t\tApplicationConversionService.addBean(conversionService, converter,\n\t\t\t\tResolvableType.forClassWithGenerics(Converter.class, CharSequence.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(\"test\", ExampleRecord.class)).isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(new StringBuilder(\"test\"), ExampleRecord.class));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> conversionService.addConverter(converter))\n\t\t\t.withMessageContaining(\"Unable to determine\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid addConverterBeanWithTypeWhenNullSourceCanConvertToOptionEmpty() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tConverter<?, ?> converter = (source) -> new ExampleRecord(source.toString());\n\t\tApplicationConversionService.addBean(conversionService, converter,\n\t\t\t\tResolvableType.forClassWithGenerics(Converter.class, CharSequence.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(null, ExampleRecord.class)).isNull();\n\t\tassertThat(conversionService.convert(null, Optional.class)).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid addConverterFactoryBeanWithTypeConvertsUsingTypeInformation() {\n\t\tFormattingConversionService conversionService = new FormattingConversionService();\n\t\tConverter<?, ?> converter = (source) -> new ExampleRecord(source.toString());\n\t\tConverterFactory converterFactory = (targetType) -> converter;\n\t\tApplicationConversionService.addBean(conversionService, converterFactory,\n\t\t\t\tResolvableType.forClassWithGenerics(ConverterFactory.class, CharSequence.class, ExampleRecord.class));\n\t\tassertThat(conversionService.convert(\"test\", ExampleRecord.class)).isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThat(conversionService.convert(new StringBuilder(\"test\"), ExampleRecord.class))\n\t\t\t.isEqualTo(new ExampleRecord(\"test\"));\n\t\tassertThatExceptionOfType(ConverterNotFoundException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(\"test\", OtherRecord.class));\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> conversionService.addConverterFactory(converterFactory))\n\t\t\t.withMessageContaining(\"Unable to determine\");\n\t}\n\n\tprivate void assertUnmodifiableExceptionThrown(ThrowingCallable throwingCallable) {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(throwingCallable)\n\t\t\t.withMessage(\"This ApplicationConversionService cannot be modified\");\n\t}\n\n\tstatic class ExampleGenericConverter implements GenericConverter {\n\n\t\t@Override\n\t\tpublic @Nullable Set<ConvertiblePair> getConvertibleTypes() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class ExampleConverter implements Converter<String, @Nullable Integer> {\n\n\t\t@Override\n\t\tpublic @Nullable Integer convert(String source) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class ExampleFormatter implements Formatter<Integer> {\n\n\t\t@Override\n\t\tpublic String print(Integer object, Locale locale) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Integer parse(String text, Locale locale) throws ParseException {\n\t\t\treturn 1;\n\t\t}\n\n\t}\n\n\tstatic class ExampleParser implements Parser<Integer> {\n\n\t\t@Override\n\t\tpublic Integer parse(String text, Locale locale) throws ParseException {\n\t\t\treturn 1;\n\t\t}\n\n\t}\n\n\tstatic class ExamplePrinter implements Printer<Integer> {\n\n\t\t@Override\n\t\tpublic String print(Integer object, Locale locale) {\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class ConverterBeanMethodConfiguration {\n\n\t\t@Bean\n\t\tConverter<String, Integer> converter() {\n\t\t\treturn Integer::valueOf;\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class PrinterBeanMethodConfiguration {\n\n\t\t@Bean\n\t\tPrinter<Integer> printer() {\n\t\t\treturn (object, locale) -> object.toString();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class ParserBeanMethodConfiguration {\n\n\t\t@Bean\n\t\tParser<Integer> parser() {\n\t\t\treturn (text, locale) -> Integer.valueOf(text);\n\t\t}\n\n\t}\n\n\trecord ExampleRecord(String value) {\n\n\t\t@Override\n\t\tpublic final String toString() {\n\t\t\treturn value();\n\t\t}\n\n\t}\n\n\trecord OtherRecord(String value) {\n\n\t}\n\n\tinterface ConditionalConverterConverter<S, T> extends Converter<S, T>, ConditionalConverter {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/ArrayToDelimitedStringConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.reflect.Field;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArrayToDelimitedStringConverter}.\n *\n * @author Phillip Webb\n */\nclass ArrayToDelimitedStringConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertListToStringShouldConvert(ConversionService conversionService) {\n\t\tString[] list = { \"a\", \"b\", \"c\" };\n\t\tString converted = conversionService.convert(list, String.class);\n\t\tassertThat(converted).isEqualTo(\"a,b,c\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenHasDelimiterNoneShouldConvert(ConversionService conversionService) {\n\t\tData data = new Data();\n\t\tdata.none = new String[] { \"1\", \"2\", \"3\" };\n\t\tField field = ReflectionUtils.findField(Data.class, \"none\");\n\t\tassertThat(field).isNotNull();\n\t\tString converted = (String) conversionService.convert(data.none, TypeDescriptor.nested(field, 0),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"123\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenHasDelimiterDashShouldConvert(ConversionService conversionService) {\n\t\tData data = new Data();\n\t\tdata.dash = new String[] { \"1\", \"2\", \"3\" };\n\t\tField field = ReflectionUtils.findField(Data.class, \"dash\");\n\t\tassertThat(field).isNotNull();\n\t\tString converted = (String) conversionService.convert(data.dash, TypeDescriptor.nested(field, 0),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1-2-3\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertShouldConvertNull(ConversionService conversionService) {\n\t\tString[] list = null;\n\t\tString converted = conversionService.convert(list, String.class);\n\t\tassertThat(converted).isNull();\n\t}\n\n\t@Test\n\tvoid convertShouldConvertElements() {\n\t\tData data = new Data();\n\t\tdata.type = new int[] { 1, 2, 3 };\n\t\tField field = ReflectionUtils.findField(Data.class, \"type\");\n\t\tassertThat(field).isNotNull();\n\t\tString converted = (String) new ApplicationConversionService().convert(data.type,\n\t\t\t\tTypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1.2.3\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverter(new ArrayToDelimitedStringConverter(service)));\n\t}\n\n\tstatic class Data {\n\n\t\t@Delimiter(Delimiter.NONE)\n\t\tString @Nullable [] none;\n\n\t\t@Delimiter(\"-\")\n\t\tString @Nullable [] dash;\n\n\t\t@Delimiter(\".\")\n\t\tint @Nullable [] type;\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/CharArrayFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CharArrayFormatter}.\n *\n * @author Phillip Webb\n */\nclass CharArrayFormatterTests {\n\n\t@ConversionServiceTest\n\tvoid convertFromCharArrayToStringShouldConvert(ConversionService conversionService) {\n\t\tchar[] source = { 'b', 'o', 'o', 't' };\n\t\tString converted = conversionService.convert(source, String.class);\n\t\tassertThat(converted).isEqualTo(\"boot\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToCharArrayShouldConvert(ConversionService conversionService) {\n\t\tString source = \"boot\";\n\t\tchar[] converted = conversionService.convert(source, char[].class);\n\t\tassertThat(converted).containsExactly('b', 'o', 'o', 't');\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new CharArrayFormatter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/CharSequenceToObjectConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.format.support.DefaultFormattingConversionService;\nimport org.springframework.format.support.FormattingConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CharSequenceToObjectConverter}\n *\n * @author Phillip Webb\n */\nclass CharSequenceToObjectConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenCanConvertViaToString(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(new StringBuilder(\"1\"), Integer.class)).isOne();\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenCanConvertDirectlySkipsStringConversion(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(new String(\"1\"), Long.class)).isOne();\n\t\tif (!ConversionServiceArguments.isApplicationConversionService(conversionService)) {\n\t\t\tassertThat(conversionService.convert(new StringBuilder(\"1\"), Long.class)).isEqualTo(2);\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenTargetIsList() {\n\t\tConversionService conversionService = new ApplicationConversionService();\n\t\tStringBuilder source = new StringBuilder(\"1,2,3\");\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(StringBuilder.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));\n\t\tList<String> converted = (List<String>) conversionService.convert(source, sourceType, targetType);\n\t\tassertThat(converted).containsExactly(\"1\", \"2\", \"3\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenTargetIsListAndNotUsingApplicationConversionService() {\n\t\tFormattingConversionService conversionService = new DefaultFormattingConversionService();\n\t\tconversionService.addConverter(new CharSequenceToObjectConverter(conversionService));\n\t\tStringBuilder source = new StringBuilder(\"1,2,3\");\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(StringBuilder.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class));\n\t\tList<String> converted = (List<String>) conversionService.convert(source, sourceType, targetType);\n\t\tassertThat(converted).containsExactly(\"1\", \"2\", \"3\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with((conversionService) -> {\n\t\t\tconversionService.addConverter(new StringToIntegerConverter());\n\t\t\tconversionService.addConverter(new StringToLongConverter());\n\t\t\tconversionService.addConverter(new CharSequenceToLongConverter());\n\t\t\tconversionService.addConverter(new CharSequenceToObjectConverter(conversionService));\n\t\t});\n\t}\n\n\tstatic class StringToIntegerConverter implements Converter<String, Integer> {\n\n\t\t@Override\n\t\tpublic Integer convert(String source) {\n\t\t\treturn Integer.valueOf(source);\n\t\t}\n\n\t}\n\n\tstatic class StringToLongConverter implements Converter<String, Long> {\n\n\t\t@Override\n\t\tpublic Long convert(String source) {\n\t\t\treturn Long.valueOf(source);\n\t\t}\n\n\t}\n\n\tstatic class CharSequenceToLongConverter implements Converter<CharSequence, Long> {\n\n\t\t@Override\n\t\tpublic Long convert(CharSequence source) {\n\t\t\treturn Long.parseLong(source.toString()) + 1;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/CollectionToDelimitedStringConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.reflect.Field;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CollectionToDelimitedStringConverter}.\n *\n * @author Phillip Webb\n */\nclass CollectionToDelimitedStringConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertListToStringShouldConvert(ConversionService conversionService) {\n\t\tList<String> list = Arrays.asList(\"a\", \"b\", \"c\");\n\t\tString converted = conversionService.convert(list, String.class);\n\t\tassertThat(converted).isEqualTo(\"a,b,c\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenHasDelimiterNoneShouldConvert(ConversionService conversionService) {\n\t\tData data = new Data();\n\t\tdata.none = Arrays.asList(\"1\", \"2\", \"3\");\n\t\tField field = ReflectionUtils.findField(Data.class, \"none\");\n\t\tassertThat(field).isNotNull();\n\t\tString converted = (String) conversionService.convert(data.none, TypeDescriptor.nested(field, 0),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"123\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenHasDelimiterDashShouldConvert(ConversionService conversionService) {\n\t\tData data = new Data();\n\t\tdata.dash = Arrays.asList(\"1\", \"2\", \"3\");\n\t\tField field = ReflectionUtils.findField(Data.class, \"dash\");\n\t\tassertThat(field).isNotNull();\n\t\tString converted = (String) conversionService.convert(data.dash, TypeDescriptor.nested(field, 0),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1-2-3\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertShouldConvertNull(ConversionService conversionService) {\n\t\tList<String> list = null;\n\t\tString converted = conversionService.convert(list, String.class);\n\t\tassertThat(converted).isNull();\n\t}\n\n\t@Test\n\tvoid convertShouldConvertElements() {\n\t\tData data = new Data();\n\t\tdata.type = Arrays.asList(1, 2, 3);\n\t\tField field = ReflectionUtils.findField(Data.class, \"type\");\n\t\tassertThat(field).isNotNull();\n\t\tString converted = (String) new ApplicationConversionService().convert(data.type,\n\t\t\t\tTypeDescriptor.nested(field, 0), TypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1.2.3\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverter(new CollectionToDelimitedStringConverter(service)));\n\t}\n\n\tstatic class Data {\n\n\t\t@Delimiter(Delimiter.NONE)\n\t\t@Nullable List<String> none;\n\n\t\t@Delimiter(\"-\")\n\t\t@Nullable List<String> dash;\n\n\t\t@Delimiter(\".\")\n\t\t@Nullable List<Integer> type;\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/ConversionServiceArguments.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.format.Formatter;\nimport org.springframework.format.support.FormattingConversionService;\n\n/**\n * Factory for creating a {@link Stream stream} of {@link Arguments} for use in a\n * {@link ParameterizedTest parameterized test}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic final class ConversionServiceArguments {\n\n\tprivate ConversionServiceArguments() {\n\t}\n\n\tpublic static Stream<? extends Arguments> with(Formatter<?> formatter) {\n\t\treturn with((conversionService) -> conversionService.addFormatter(formatter));\n\t}\n\n\tpublic static Stream<? extends Arguments> with(GenericConverter converter) {\n\t\treturn with((conversionService) -> conversionService.addConverter(converter));\n\t}\n\n\tpublic static Stream<? extends Arguments> with(Consumer<FormattingConversionService> initializer) {\n\t\tFormattingConversionService withoutDefaults = new FormattingConversionService();\n\t\tinitializer.accept(withoutDefaults);\n\t\treturn Stream.of(\n\t\t\t\tArguments.of(new NamedConversionService(withoutDefaults, \"Without defaults conversion service\")),\n\t\t\t\tArguments.of(new NamedConversionService(new ApplicationConversionService(),\n\t\t\t\t\t\t\"Application conversion service\")));\n\t}\n\n\tpublic static boolean isApplicationConversionService(ConversionService conversionService) {\n\t\tif (conversionService instanceof NamedConversionService namedConversionService) {\n\t\t\treturn isApplicationConversionService(namedConversionService.delegate);\n\t\t}\n\t\treturn conversionService instanceof ApplicationConversionService;\n\t}\n\n\tstatic class NamedConversionService implements ConversionService {\n\n\t\tprivate final ConversionService delegate;\n\n\t\tprivate final String name;\n\n\t\tNamedConversionService(ConversionService delegate, String name) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {\n\t\t\treturn this.delegate.canConvert(sourceType, targetType);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\treturn this.delegate.canConvert(sourceType, targetType);\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> @Nullable T convert(@Nullable Object source, Class<T> targetType) {\n\t\t\treturn this.delegate.convert(source, targetType);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType,\n\t\t\t\tTypeDescriptor targetType) {\n\t\t\treturn this.delegate.convert(source, sourceType, targetType);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/ConversionServiceTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.core.convert.ConversionService;\n\n/**\n * Specialized {@link ParameterizedTest parameterized test} for\n * {@link ConversionService}-related testing. Test classes with methods annotated with\n * {@link ParameterizedTest @ParameterizedTest} must have a {@code static}\n * {@code conversionServices} method that is suitable for use as a {@link MethodSource\n * method source}.\n *\n * @author Andy Wilkinson\n */\n@ParameterizedTest\n@MethodSource(\"conversionServices\")\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ConversionServiceTest {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToArrayConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.reflect.Field;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DelimitedStringToArrayConverter}.\n *\n * @author Phillip Webb\n */\nclass DelimitedStringToArrayConverterTests {\n\n\t@ConversionServiceTest\n\tvoid canConvertFromStringToArrayShouldReturnTrue(ConversionService conversionService) {\n\t\tassertThat(conversionService.canConvert(String.class, String[].class)).isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid matchesWhenTargetIsNotAnnotatedShouldReturnTrue(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tField field = ReflectionUtils.findField(Values.class, \"noAnnotation\");\n\t\tassertThat(field).isNotNull();\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(field, 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(new DelimitedStringToArrayConverter(conversionService).matches(sourceType, targetType)).isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid matchesWhenHasAnnotationAndNonConvertibleElementTypeShouldReturnFalse(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tField field = ReflectionUtils.findField(Values.class, \"nonConvertibleElementType\");\n\t\tassertThat(field).isNotNull();\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(field, 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(new DelimitedStringToArrayConverter(conversionService).matches(sourceType, targetType)).isFalse();\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenHasDelimiterOfNoneShouldReturnWholeString(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tField field = ReflectionUtils.findField(Values.class, \"delimiterNone\");\n\t\tassertThat(field).isNotNull();\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(field, 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tString[] converted = (String[]) conversionService.convert(\"a,b,c\", sourceType, targetType);\n\t\tassertThat(converted).containsExactly(\"a,b,c\");\n\t}\n\n\t@Test\n\tvoid matchesWhenHasAnnotationAndConvertibleElementTypeShouldReturnTrue() {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tField field = ReflectionUtils.findField(Values.class, \"convertibleElementType\");\n\t\tassertThat(field).isNotNull();\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(field, 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(\n\t\t\t\tnew DelimitedStringToArrayConverter(new ApplicationConversionService()).matches(sourceType, targetType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid convertWhenHasConvertibleElementTypeShouldReturnConvertedType() {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tField field = ReflectionUtils.findField(Values.class, \"convertibleElementType\");\n\t\tassertThat(field).isNotNull();\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(field, 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tInteger[] converted = (Integer[]) new ApplicationConversionService().convert(\" 1 |  2| 3  \", sourceType,\n\t\t\t\ttargetType);\n\t\tassertThat(converted).containsExactly(1, 2, 3);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverter(new DelimitedStringToArrayConverter(service)));\n\t}\n\n\tstatic class Values {\n\n\t\t@Nullable List<String> noAnnotation;\n\n\t\t@Delimiter(\"|\")\n\t\tInteger @Nullable [] convertibleElementType;\n\n\t\t@Delimiter(\"|\")\n\t\tNonConvertible @Nullable [] nonConvertibleElementType;\n\n\t\t@Delimiter(Delimiter.NONE)\n\t\tString @Nullable [] delimiterNone;\n\n\t}\n\n\tstatic class NonConvertible {\n\n\t}\n\n\tstatic class MyCustomList<E> extends LinkedList<E> {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/DelimitedStringToCollectionConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.lang.reflect.Field;\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DelimitedStringToCollectionConverter}.\n *\n * @author Phillip Webb\n */\nclass DelimitedStringToCollectionConverterTests {\n\n\t@ConversionServiceTest\n\tvoid canConvertFromStringToCollectionShouldReturnTrue(ConversionService conversionService) {\n\t\tassertThat(conversionService.canConvert(String.class, Collection.class)).isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid matchesWhenTargetIsNotAnnotatedShouldReturnTrue(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"noAnnotation\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(new DelimitedStringToCollectionConverter(conversionService).matches(sourceType, targetType))\n\t\t\t.isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid matchesWhenHasAnnotationAndNoElementTypeShouldReturnTrue(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"noElementType\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(new DelimitedStringToCollectionConverter(conversionService).matches(sourceType, targetType))\n\t\t\t.isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid matchesWhenHasAnnotationAndNonConvertibleElementTypeShouldReturnFalse(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"nonConvertibleElementType\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(new DelimitedStringToCollectionConverter(conversionService).matches(sourceType, targetType))\n\t\t\t.isFalse();\n\t}\n\n\t@ConversionServiceTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenHasNoElementTypeShouldReturnTrimmedString(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"noElementType\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tCollection<String> converted = (Collection<String>) conversionService.convert(\" a |  b| c  \", sourceType,\n\t\t\t\ttargetType);\n\t\tassertThat(converted).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@ConversionServiceTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenHasDelimiterOfNoneShouldReturnWholeString(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"delimiterNone\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tList<String> converted = (List<String>) conversionService.convert(\"a,b,c\", sourceType, targetType);\n\t\tassertThat(converted).containsExactly(\"a,b,c\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@ConversionServiceTest\n\tvoid convertWhenHasCollectionObjectTypeShouldUseCollectionObjectType(ConversionService conversionService) {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"specificType\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tMyCustomList<String> converted = (MyCustomList<String>) conversionService.convert(\"a*b\", sourceType,\n\t\t\t\ttargetType);\n\t\tassertThat(converted).containsExactly(\"a\", \"b\");\n\t}\n\n\t@Test\n\tvoid matchesWhenHasAnnotationAndConvertibleElementTypeShouldReturnTrue() {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"convertibleElementType\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tassertThat(new DelimitedStringToCollectionConverter(new ApplicationConversionService()).matches(sourceType,\n\t\t\t\ttargetType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid convertWhenHasConvertibleElementTypeShouldReturnConvertedType() {\n\t\tTypeDescriptor sourceType = TypeDescriptor.valueOf(String.class);\n\t\tTypeDescriptor targetType = TypeDescriptor.nested(getField(\"convertibleElementType\"), 0);\n\t\tassertThat(targetType).isNotNull();\n\t\tList<Integer> converted = (List<Integer>) new ApplicationConversionService().convert(\" 1 |  2| 3  \", sourceType,\n\t\t\t\ttargetType);\n\t\tassertThat(converted).containsExactly(1, 2, 3);\n\t}\n\n\tprivate Field getField(String fieldName) {\n\t\tField field = ReflectionUtils.findField(Values.class, fieldName);\n\t\tassertThat(field).isNotNull();\n\t\treturn field;\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverter(new DelimitedStringToCollectionConverter(service)));\n\t}\n\n\tstatic class Values {\n\n\t\t@Nullable List<String> noAnnotation;\n\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\t@Delimiter(\"|\")\n\t\t@Nullable List noElementType;\n\n\t\t@Delimiter(\"|\")\n\t\t@Nullable List<Integer> convertibleElementType;\n\n\t\t@Delimiter(\"|\")\n\t\t@Nullable List<NonConvertible> nonConvertibleElementType;\n\n\t\t@Delimiter(Delimiter.NONE)\n\t\t@Nullable List<String> delimiterNone;\n\n\t\t@Delimiter(\"*\")\n\t\t@Nullable MyCustomList<String> specificType;\n\n\t}\n\n\tstatic class NonConvertible {\n\n\t}\n\n\tstatic class MyCustomList<E> extends LinkedList<E> {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/DurationStyleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DurationStyle}.\n *\n * @author Phillip Webb\n * @author Valentine Wu\n */\nclass DurationStyleTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid detectAndParseWhenValueIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.detectAndParse(null))\n\t\t\t.withMessageContaining(\"'value' must not be null\");\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenIso8601ShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"pt20.345s\")).isEqualTo(Duration.parse(\"pt20.345s\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"PT20.345S\")).isEqualTo(Duration.parse(\"PT20.345S\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"PT15M\")).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"+PT15M\")).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"PT10H\")).isEqualTo(Duration.parse(\"PT10H\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"P2D\")).isEqualTo(Duration.parse(\"P2D\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"P2DT3H4M\")).isEqualTo(Duration.parse(\"P2DT3H4M\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"-PT6H3M\")).isEqualTo(Duration.parse(\"-PT6H3M\"));\n\t\tassertThat(DurationStyle.detectAndParse(\"-PT-6H+3M\")).isEqualTo(Duration.parse(\"-PT-6H+3M\"));\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleNanosShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10ns\")).hasNanos(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"10NS\")).hasNanos(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10ns\")).hasNanos(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10ns\")).hasNanos(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleMicrosShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10us\")).hasNanos(10000);\n\t\tassertThat(DurationStyle.detectAndParse(\"10US\")).hasNanos(10000);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10us\")).hasNanos(10000);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10us\")).hasNanos(-10000);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleMillisShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10ms\")).hasMillis(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"10MS\")).hasMillis(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10ms\")).hasMillis(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10ms\")).hasMillis(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleSecondsShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10s\")).hasSeconds(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"10S\")).hasSeconds(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10s\")).hasSeconds(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10s\")).hasSeconds(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleMinutesShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10m\")).hasMinutes(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"10M\")).hasMinutes(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10m\")).hasMinutes(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10m\")).hasMinutes(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleHoursShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10h\")).hasHours(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"10H\")).hasHours(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10h\")).hasHours(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10h\")).hasHours(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleDaysShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10d\")).hasDays(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"10D\")).hasDays(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10d\")).hasDays(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10d\")).hasDays(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleWithoutSuffixShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10\")).hasMillis(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10\")).hasMillis(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10\")).hasMillis(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleWithoutSuffixButWithChronoUnitShouldReturnDuration() {\n\t\tassertThat(DurationStyle.detectAndParse(\"10\", ChronoUnit.SECONDS)).hasSeconds(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"+10\", ChronoUnit.SECONDS)).hasSeconds(10);\n\t\tassertThat(DurationStyle.detectAndParse(\"-10\", ChronoUnit.SECONDS)).hasSeconds(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenBadFormatShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.detectAndParse(\"10foo\"))\n\t\t\t.withMessageContaining(\"'10foo' is not a valid duration\");\n\t}\n\n\t@Test\n\tvoid detectWhenSimpleShouldReturnSimple() {\n\t\tassertThat(DurationStyle.detect(\"10\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"+10\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"-10\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10ns\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10ms\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10s\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10m\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10h\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10d\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"-10ms\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"-10ms\")).isEqualTo(DurationStyle.SIMPLE);\n\t\tassertThat(DurationStyle.detect(\"10D\")).isEqualTo(DurationStyle.SIMPLE);\n\t}\n\n\t@Test\n\tvoid detectWhenIso8601ShouldReturnIso8601() {\n\t\tassertThat(DurationStyle.detect(\"pt20.345s\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"PT20.345S\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"PT15M\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"+PT15M\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"PT10H\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"P2D\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"P2DT3H4M\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"-PT6H3M\")).isEqualTo(DurationStyle.ISO8601);\n\t\tassertThat(DurationStyle.detect(\"-PT-6H+3M\")).isEqualTo(DurationStyle.ISO8601);\n\t}\n\n\t@Test\n\tvoid detectWhenUnknownShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.detect(\"bad\"))\n\t\t\t.withMessageContaining(\"'bad' is not a valid duration\");\n\t}\n\n\t@Test\n\tvoid parseIso8601ShouldParse() {\n\t\tassertThat(DurationStyle.ISO8601.parse(\"pt20.345s\")).isEqualTo(Duration.parse(\"pt20.345s\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"PT20.345S\")).isEqualTo(Duration.parse(\"PT20.345S\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"PT15M\")).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"+PT15M\")).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"PT10H\")).isEqualTo(Duration.parse(\"PT10H\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"P2D\")).isEqualTo(Duration.parse(\"P2D\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"P2DT3H4M\")).isEqualTo(Duration.parse(\"P2DT3H4M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"-PT6H3M\")).isEqualTo(Duration.parse(\"-PT6H3M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"-PT-6H+3M\")).isEqualTo(Duration.parse(\"-PT-6H+3M\"));\n\t}\n\n\t@Test\n\tvoid parseIso8601WithUnitShouldIgnoreUnit() {\n\t\tassertThat(DurationStyle.ISO8601.parse(\"pt20.345s\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"pt20.345s\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"PT20.345S\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"PT20.345S\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"PT15M\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"+PT15M\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"PT10H\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"PT10H\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"P2D\")).isEqualTo(Duration.parse(\"P2D\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"P2DT3H4M\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"P2DT3H4M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"-PT6H3M\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"-PT6H3M\"));\n\t\tassertThat(DurationStyle.ISO8601.parse(\"-PT-6H+3M\", ChronoUnit.SECONDS)).isEqualTo(Duration.parse(\"-PT-6H+3M\"));\n\t}\n\n\t@Test\n\tvoid parseIso8601WhenSimpleShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.ISO8601.parse(\"10d\"))\n\t\t\t.withMessageContaining(\"'10d' is not a valid ISO-8601 duration\");\n\t}\n\n\t@Test\n\tvoid parseSimpleShouldParse() {\n\t\tassertThat(DurationStyle.SIMPLE.parse(\"10m\")).hasMinutes(10);\n\t}\n\n\t@Test\n\tvoid parseSimpleWithUnitShouldUseUnitAsFallback() {\n\t\tassertThat(DurationStyle.SIMPLE.parse(\"10m\", ChronoUnit.SECONDS)).hasMinutes(10);\n\t\tassertThat(DurationStyle.SIMPLE.parse(\"10\", ChronoUnit.MINUTES)).hasMinutes(10);\n\t}\n\n\t@Test\n\tvoid parseSimpleWhenUnknownUnitShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.SIMPLE.parse(\"10mb\")).satisfies((ex) -> {\n\t\t\tThrowable cause = ex.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\tassertThat(cause.getMessage()).isEqualTo(\"Unknown unit 'mb'\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid parseSimpleWhenIso8601ShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DurationStyle.SIMPLE.parse(\"PT10H\"))\n\t\t\t.withMessageContaining(\"'PT10H' is not a valid simple duration\");\n\t}\n\n\t@Test\n\tvoid printIso8601ShouldPrint() {\n\t\tDuration duration = Duration.parse(\"-PT-6H+3M\");\n\t\tassertThat(DurationStyle.ISO8601.print(duration)).isEqualTo(\"PT5H57M\");\n\t}\n\n\t@Test\n\tvoid printIso8601ShouldIgnoreUnit() {\n\t\tDuration duration = Duration.parse(\"-PT-6H+3M\");\n\t\tassertThat(DurationStyle.ISO8601.print(duration, ChronoUnit.DAYS)).isEqualTo(\"PT5H57M\");\n\t}\n\n\t@Test\n\tvoid printSimpleWithoutUnitShouldPrintInMs() {\n\t\tDuration duration = Duration.ofSeconds(1);\n\t\tassertThat(DurationStyle.SIMPLE.print(duration)).isEqualTo(\"1000ms\");\n\t}\n\n\t@Test\n\tvoid printSimpleWithSecondsUnitShouldPrintInUnit() {\n\t\tDuration duration = Duration.ofMillis(1000);\n\t\tassertThat(DurationStyle.SIMPLE.print(duration, ChronoUnit.SECONDS)).isEqualTo(\"1s\");\n\t}\n\n\t@Test\n\tvoid printSimpleWithMicrosUnitShouldPrintInUnit() {\n\t\tDuration duration = Duration.ofNanos(2000);\n\t\tassertThat(DurationStyle.SIMPLE.print(duration, ChronoUnit.MICROS)).isEqualTo(\"2us\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/DurationToNumberConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DurationToNumberConverter}.\n *\n * @author Phillip Webb\n */\nclass DurationToNumberConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWithoutStyleShouldReturnMs(ConversionService conversionService) {\n\t\tLong converted = conversionService.convert(Duration.ofSeconds(1), Long.class);\n\t\tassertThat(converted).isEqualTo(1000);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatShouldUseIgnoreFormat(ConversionService conversionService) {\n\t\tInteger converted = (Integer) conversionService.convert(Duration.ofSeconds(1),\n\t\t\t\tMockDurationTypeDescriptor.get(null, DurationStyle.ISO8601), TypeDescriptor.valueOf(Integer.class));\n\t\tassertThat(converted).isEqualTo(1000);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatAndUnitShouldUseFormatAndUnit(ConversionService conversionService) {\n\t\tByte converted = (Byte) conversionService.convert(Duration.ofSeconds(1),\n\t\t\t\tMockDurationTypeDescriptor.get(ChronoUnit.SECONDS, null), TypeDescriptor.valueOf(Byte.class));\n\t\tassertThat(converted).isEqualTo((byte) 1);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new DurationToNumberConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/DurationToStringConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DurationToStringConverter}.\n *\n * @author Phillip Webb\n */\nclass DurationToStringConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWithoutStyleShouldReturnIso8601(ConversionService conversionService) {\n\t\tString converted = conversionService.convert(Duration.ofSeconds(1), String.class);\n\t\tassertThat(converted).isEqualTo(\"PT1S\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatShouldUseFormatAndMs(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Duration.ofSeconds(1),\n\t\t\t\tMockDurationTypeDescriptor.get(null, DurationStyle.SIMPLE), TypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1000ms\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatAndUnitShouldUseFormatAndUnit(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Duration.ofSeconds(1),\n\t\t\t\tMockDurationTypeDescriptor.get(ChronoUnit.SECONDS, DurationStyle.SIMPLE),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1s\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new DurationToStringConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/InetAddressFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.junit.jupiter.api.Assumptions.assumingThat;\n\n/**\n * Tests for {@link InetAddressFormatter}.\n *\n * @author Phillip Webb\n */\nclass InetAddressFormatterTests {\n\n\t@ConversionServiceTest\n\tvoid convertFromInetAddressToStringShouldConvert(ConversionService conversionService) {\n\t\tassumingThat(isResolvable(\"example.com\"), () -> {\n\t\t\tInetAddress address = InetAddress.getByName(\"example.com\");\n\t\t\tString converted = conversionService.convert(address, String.class);\n\t\t\tassertThat(converted).isEqualTo(address.getHostAddress());\n\t\t});\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToInetAddressShouldConvert(ConversionService conversionService) {\n\t\tassumingThat(isResolvable(\"example.com\"), () -> {\n\t\t\tInetAddress converted = conversionService.convert(\"example.com\", InetAddress.class);\n\t\t\tassertThat(converted).isNotNull();\n\t\t\tassertThat(converted.toString()).startsWith(\"example.com\");\n\t\t});\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToInetAddressWhenHostDoesNotExistShouldThrowException(ConversionService conversionService) {\n\t\tString missingDomain = \"ireallydontexist.example.com\";\n\t\tassumingThat(!isResolvable(\"ireallydontexist.example.com\"),\n\t\t\t\t() -> assertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t\t\t.isThrownBy(() -> conversionService.convert(missingDomain, InetAddress.class)));\n\t}\n\n\tprivate boolean isResolvable(String host) {\n\t\ttry {\n\t\t\tInetAddress.getByName(host);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (UnknownHostException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new InetAddressFormatter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/InputStreamSourceToByteArrayConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link InputStreamSourceToByteArrayConverter}.\n *\n * @author Phillip Webb\n */\nclass InputStreamSourceToByteArrayConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertConvertsSource(ConversionService conversionService) {\n\t\tInputStreamSource source = () -> new ByteArrayInputStream(new byte[] { 0, 1, 2 });\n\t\tassertThat(conversionService.convert(source, byte[].class)).containsExactly(0, 1, 2);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenFailsWithIOExceptionThrowsException(ConversionService conversionService) throws Exception {\n\t\tInputStreamSource source = mock(InputStreamSource.class);\n\t\tgiven(source.getInputStream()).willThrow(IOException.class);\n\t\tassertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(source, byte[].class))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(IllegalStateException.class)\n\t\t\t.withMessageContaining(\"Unable to read from input stream source\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenFailsWithIOExceptionFromOriginProviderThrowsException(ConversionService conversionService)\n\t\t\tthrows Exception {\n\t\tOrigin origin = new TestOrigin(\"mylocation\");\n\t\tInputStreamSource source = mock(InputStreamSource.class, withSettings().extraInterfaces(OriginProvider.class));\n\t\tgiven(source.getInputStream()).willThrow(IOException.class);\n\t\tgiven(((OriginProvider) source).getOrigin()).willReturn(origin);\n\t\tassertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(source, byte[].class))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(IllegalStateException.class)\n\t\t\t.withMessageContaining(\"Unable to read from mylocation\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenFailsWithIOExceptionFromResourceThrowsException(ConversionService conversionService)\n\t\t\tthrows Exception {\n\t\tResource source = mock(Resource.class);\n\t\tgiven(source.getInputStream()).willThrow(IOException.class);\n\t\tgiven(source.getDescription()).willReturn(\"myresource\");\n\t\tassertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t.isThrownBy(() -> conversionService.convert(source, byte[].class))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(IllegalStateException.class)\n\t\t\t.withMessageContaining(\"Unable to read from myresource\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverter(new InputStreamSourceToByteArrayConverter()));\n\t}\n\n\tprivate static class TestOrigin implements Origin {\n\n\t\tprivate final String string;\n\n\t\tTestOrigin(String string) {\n\t\t\tthis.string = string;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/IsoOffsetFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.OffsetDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IsoOffsetFormatter}.\n *\n * @author Phillip Webb\n */\nclass IsoOffsetFormatterTests {\n\n\t@ConversionServiceTest\n\tvoid convertShouldConvertStringToIsoDate(ConversionService conversionService) {\n\t\tOffsetDateTime now = OffsetDateTime.now();\n\t\tOffsetDateTime converted = conversionService.convert(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(now),\n\t\t\t\tOffsetDateTime.class);\n\t\tassertThat(converted).isEqualTo(now);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertShouldConvertIsoDateToString(ConversionService conversionService) {\n\t\tOffsetDateTime now = OffsetDateTime.now();\n\t\tString converted = conversionService.convert(now, String.class);\n\t\tassertThat(converted).isNotNull().startsWith(now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new IsoOffsetFormatter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/LenientBooleanToEnumConverterFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LenientBooleanToEnumConverterFactory}.\n *\n * @author Madhura Bhave\n */\nclass LenientBooleanToEnumConverterFactoryTests {\n\n\t@ConversionServiceTest\n\tvoid convertFromBooleanToEnumWhenShouldConvertValue(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(true, TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.ON);\n\t\tassertThat(conversionService.convert(false, TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.OFF);\n\t\tassertThat(conversionService.convert(true, TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.TRUE);\n\t\tassertThat(conversionService.convert(false, TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.FALSE);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverterFactory(new LenientBooleanToEnumConverterFactory()));\n\t}\n\n\tenum TestOnOffEnum {\n\n\t\tON, OFF\n\n\t}\n\n\tenum TestTrueFalseEnum {\n\n\t\tONE, TWO, TRUE, FALSE, ON, OFF\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/LenientStringToEnumConverterFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Locale;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LenientStringToEnumConverterFactory}.\n *\n * @author Phillip Webb\n */\nclass LenientStringToEnumConverterFactoryTests {\n\n\t@ConversionServiceTest\n\tvoid canConvertFromStringToEnumShouldReturnTrue(ConversionService conversionService) {\n\t\tassertThat(conversionService.canConvert(String.class, TestEnum.class)).isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid canConvertFromStringToEnumSubclassShouldReturnTrue(ConversionService conversionService) {\n\t\tassertThat(conversionService.canConvert(String.class, TestSubclassEnum.ONE.getClass())).isTrue();\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToEnumWhenExactMatchShouldConvertValue(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(\"\", TestEnum.class)).isNull();\n\t\tassertThat(conversionService.convert(\"ONE\", TestEnum.class)).isEqualTo(TestEnum.ONE);\n\t\tassertThat(conversionService.convert(\"TWO\", TestEnum.class)).isEqualTo(TestEnum.TWO);\n\t\tassertThat(conversionService.convert(\"THREE_AND_FOUR\", TestEnum.class)).isEqualTo(TestEnum.THREE_AND_FOUR);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToEnumWhenFuzzyMatchShouldConvertValue(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(\"\", TestEnum.class)).isNull();\n\t\tassertThat(conversionService.convert(\"one\", TestEnum.class)).isEqualTo(TestEnum.ONE);\n\t\tassertThat(conversionService.convert(\"tWo\", TestEnum.class)).isEqualTo(TestEnum.TWO);\n\t\tassertThat(conversionService.convert(\"three_and_four\", TestEnum.class)).isEqualTo(TestEnum.THREE_AND_FOUR);\n\t\tassertThat(conversionService.convert(\"threeandfour\", TestEnum.class)).isEqualTo(TestEnum.THREE_AND_FOUR);\n\t\tassertThat(conversionService.convert(\"three-and-four\", TestEnum.class)).isEqualTo(TestEnum.THREE_AND_FOUR);\n\t\tassertThat(conversionService.convert(\"threeAndFour\", TestEnum.class)).isEqualTo(TestEnum.THREE_AND_FOUR);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToEnumWhenUsingNonEnglishLocaleShouldConvertValue(ConversionService conversionService) {\n\t\tLocale defaultLocale = Locale.getDefault();\n\t\ttry {\n\t\t\tLocale.setDefault(new Locale(\"tr\"));\n\t\t\tLocaleSensitiveEnum result = conversionService.convert(\"accept-case-insensitive-properties\",\n\t\t\t\t\tLocaleSensitiveEnum.class);\n\t\t\tassertThat(result).isEqualTo(LocaleSensitiveEnum.ACCEPT_CASE_INSENSITIVE_PROPERTIES);\n\t\t}\n\t\tfinally {\n\t\t\tLocale.setDefault(defaultLocale);\n\t\t}\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertFromStringToEnumWhenYamlBooleanShouldConvertValue(ConversionService conversionService) {\n\t\tassertThat(conversionService.convert(\"one\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.ONE);\n\t\tassertThat(conversionService.convert(\"two\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.TWO);\n\t\tassertThat(conversionService.convert(\"true\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.ON);\n\t\tassertThat(conversionService.convert(\"false\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.OFF);\n\t\tassertThat(conversionService.convert(\"TRUE\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.ON);\n\t\tassertThat(conversionService.convert(\"FALSE\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.OFF);\n\t\tassertThat(conversionService.convert(\"fA_lsE\", TestOnOffEnum.class)).isEqualTo(TestOnOffEnum.OFF);\n\t\tassertThat(conversionService.convert(\"one\", TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.ONE);\n\t\tassertThat(conversionService.convert(\"two\", TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.TWO);\n\t\tassertThat(conversionService.convert(\"true\", TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.TRUE);\n\t\tassertThat(conversionService.convert(\"false\", TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.FALSE);\n\t\tassertThat(conversionService.convert(\"TRUE\", TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.TRUE);\n\t\tassertThat(conversionService.convert(\"FALSE\", TestTrueFalseEnum.class)).isEqualTo(TestTrueFalseEnum.FALSE);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((service) -> service.addConverterFactory(new LenientStringToEnumConverterFactory()));\n\t}\n\n\tenum TestEnum {\n\n\t\tONE, TWO, THREE_AND_FOUR\n\n\t}\n\n\tenum TestOnOffEnum {\n\n\t\tONE, TWO, ON, OFF\n\n\t}\n\n\tenum TestTrueFalseEnum {\n\n\t\tONE, TWO, TRUE, FALSE, ON, OFF\n\n\t}\n\n\tenum LocaleSensitiveEnum {\n\n\t\tACCEPT_CASE_INSENSITIVE_PROPERTIES\n\n\t}\n\n\tenum TestSubclassEnum {\n\n\t\tONE {\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\treturn \"foo\";\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/MockDataSizeTypeDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Create a mock {@link TypeDescriptor} with optional {@link DataSizeUnit @DataSizeUnit}\n * annotation.\n *\n * @author Stephane Nicoll\n */\npublic final class MockDataSizeTypeDescriptor {\n\n\tprivate MockDataSizeTypeDescriptor() {\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static TypeDescriptor get(@Nullable DataUnit unit) {\n\t\tTypeDescriptor descriptor = mock(TypeDescriptor.class);\n\t\tif (unit != null) {\n\t\t\tDataSizeUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation(Collections.singletonMap(\"value\", unit),\n\t\t\t\t\tDataSizeUnit.class, null);\n\t\t\tgiven(descriptor.getAnnotation(DataSizeUnit.class)).willReturn(unitAnnotation);\n\t\t}\n\t\tgiven(descriptor.getType()).willReturn((Class) DataSize.class);\n\t\tgiven(descriptor.getObjectType()).willReturn((Class) DataSize.class);\n\t\treturn descriptor;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/MockDurationTypeDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Create a mock {@link TypeDescriptor} with optional {@link DurationUnit @DurationUnit}\n * and {@link DurationFormat @DurationFormat} annotations.\n *\n * @author Phillip Webb\n */\npublic final class MockDurationTypeDescriptor {\n\n\tprivate MockDurationTypeDescriptor() {\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static TypeDescriptor get(@Nullable ChronoUnit unit, @Nullable DurationStyle style) {\n\t\tTypeDescriptor descriptor = mock(TypeDescriptor.class);\n\t\tif (unit != null) {\n\t\t\tDurationUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation(Collections.singletonMap(\"value\", unit),\n\t\t\t\t\tDurationUnit.class, null);\n\t\t\tgiven(descriptor.getAnnotation(DurationUnit.class)).willReturn(unitAnnotation);\n\t\t}\n\t\tif (style != null) {\n\t\t\tDurationFormat formatAnnotation = AnnotationUtils\n\t\t\t\t.synthesizeAnnotation(Collections.singletonMap(\"value\", style), DurationFormat.class, null);\n\t\t\tgiven(descriptor.getAnnotation(DurationFormat.class)).willReturn(formatAnnotation);\n\t\t}\n\t\tgiven(descriptor.getType()).willReturn((Class) Duration.class);\n\t\tgiven(descriptor.getObjectType()).willReturn((Class) Duration.class);\n\t\treturn descriptor;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/MockPeriodTypeDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Create a mock {@link TypeDescriptor} with optional {@link PeriodUnit @PeriodUnit} and\n * {@link PeriodFormat @PeriodFormat} annotations.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n */\npublic final class MockPeriodTypeDescriptor {\n\n\tprivate MockPeriodTypeDescriptor() {\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic static TypeDescriptor get(@Nullable ChronoUnit unit, @Nullable PeriodStyle style) {\n\t\tTypeDescriptor descriptor = mock(TypeDescriptor.class);\n\t\tif (unit != null) {\n\t\t\tPeriodUnit unitAnnotation = AnnotationUtils.synthesizeAnnotation(Collections.singletonMap(\"value\", unit),\n\t\t\t\t\tPeriodUnit.class, null);\n\t\t\tgiven(descriptor.getAnnotation(PeriodUnit.class)).willReturn(unitAnnotation);\n\t\t}\n\t\tif (style != null) {\n\t\t\tPeriodFormat formatAnnotation = AnnotationUtils\n\t\t\t\t.synthesizeAnnotation(Collections.singletonMap(\"value\", style), PeriodFormat.class, null);\n\t\t\tgiven(descriptor.getAnnotation(PeriodFormat.class)).willReturn(formatAnnotation);\n\t\t}\n\t\tgiven(descriptor.getType()).willReturn((Class) Period.class);\n\t\tgiven(descriptor.getObjectType()).willReturn((Class) Period.class);\n\t\treturn descriptor;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDataSizeConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.Collections;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NumberToDataSizeConverter}.\n *\n * @author Stephane Nicoll\n */\nclass NumberToDataSizeConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, 10)).isEqualTo(DataSize.ofBytes(10));\n\t\tassertThat(convert(conversionService, +10)).isEqualTo(DataSize.ofBytes(10));\n\t\tassertThat(convert(conversionService, -10)).isEqualTo(DataSize.ofBytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, 10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10));\n\t\tassertThat(convert(conversionService, +10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10));\n\t\tassertThat(convert(conversionService, -10, DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(-10));\n\t}\n\n\tprivate @Nullable DataSize convert(ConversionService conversionService, Integer source) {\n\t\treturn conversionService.convert(source, DataSize.class);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate @Nullable DataSize convert(ConversionService conversionService, Integer source,\n\t\t\t@Nullable DataUnit defaultUnit) {\n\t\tTypeDescriptor targetType = mock(TypeDescriptor.class);\n\t\tif (defaultUnit != null) {\n\t\t\tDataSizeUnit unitAnnotation = AnnotationUtils\n\t\t\t\t.synthesizeAnnotation(Collections.singletonMap(\"value\", defaultUnit), DataSizeUnit.class, null);\n\t\t\tgiven(targetType.getAnnotation(DataSizeUnit.class)).willReturn(unitAnnotation);\n\t\t}\n\t\tgiven(targetType.getType()).willReturn((Class) DataSize.class);\n\t\treturn (DataSize) conversionService.convert(source, TypeDescriptor.forObject(source), targetType);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new NumberToDataSizeConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToDurationConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NumberToDurationConverter}.\n *\n * @author Phillip Webb\n */\nclass NumberToDurationConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, 10)).hasMillis(10);\n\t\tassertThat(convert(conversionService, +10)).hasMillis(10);\n\t\tassertThat(convert(conversionService, -10)).hasMillis(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, 10, ChronoUnit.SECONDS)).hasSeconds(10);\n\t\tassertThat(convert(conversionService, +10, ChronoUnit.SECONDS)).hasSeconds(10);\n\t\tassertThat(convert(conversionService, -10, ChronoUnit.SECONDS)).hasSeconds(-10);\n\t}\n\n\tprivate @Nullable Duration convert(ConversionService conversionService, Integer source) {\n\t\treturn conversionService.convert(source, Duration.class);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate @Nullable Duration convert(ConversionService conversionService, Integer source,\n\t\t\t@Nullable ChronoUnit defaultUnit) {\n\t\tTypeDescriptor targetType = mock(TypeDescriptor.class);\n\t\tif (defaultUnit != null) {\n\t\t\tDurationUnit unitAnnotation = AnnotationUtils\n\t\t\t\t.synthesizeAnnotation(Collections.singletonMap(\"value\", defaultUnit), DurationUnit.class, null);\n\t\t\tgiven(targetType.getAnnotation(DurationUnit.class)).willReturn(unitAnnotation);\n\t\t}\n\t\tgiven(targetType.getType()).willReturn((Class) Duration.class);\n\t\treturn (Duration) conversionService.convert(source, TypeDescriptor.forObject(source), targetType);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new NumberToDurationConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/NumberToPeriodConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Collections;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NumberToPeriodConverter}.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n */\nclass NumberToPeriodConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, 10)).hasDays(10);\n\t\tassertThat(convert(conversionService, +10)).hasDays(10);\n\t\tassertThat(convert(conversionService, -10)).hasDays(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, 10, ChronoUnit.DAYS)).hasDays(10);\n\t\tassertThat(convert(conversionService, -10, ChronoUnit.DAYS)).hasDays(-10);\n\t\tassertThat(convert(conversionService, 10, ChronoUnit.WEEKS)).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(convert(conversionService, -10, ChronoUnit.WEEKS)).isEqualTo(Period.ofWeeks(-10));\n\t\tassertThat(convert(conversionService, 10, ChronoUnit.MONTHS)).hasMonths(10);\n\t\tassertThat(convert(conversionService, -10, ChronoUnit.MONTHS)).hasMonths(-10);\n\t\tassertThat(convert(conversionService, 10, ChronoUnit.YEARS)).hasYears(10);\n\t\tassertThat(convert(conversionService, -10, ChronoUnit.YEARS)).hasYears(-10);\n\t}\n\n\tprivate @Nullable Period convert(ConversionService conversionService, Integer source) {\n\t\treturn conversionService.convert(source, Period.class);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate @Nullable Period convert(ConversionService conversionService, Integer source,\n\t\t\t@Nullable ChronoUnit defaultUnit) {\n\t\tTypeDescriptor targetType = mock(TypeDescriptor.class);\n\t\tif (defaultUnit != null) {\n\t\t\tPeriodUnit unitAnnotation = AnnotationUtils\n\t\t\t\t.synthesizeAnnotation(Collections.singletonMap(\"value\", defaultUnit), PeriodUnit.class, null);\n\t\t\tgiven(targetType.getAnnotation(PeriodUnit.class)).willReturn(unitAnnotation);\n\t\t}\n\t\tgiven(targetType.getType()).willReturn((Class) Period.class);\n\t\treturn (Period) conversionService.convert(source, TypeDescriptor.forObject(source), targetType);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new NumberToPeriodConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/PeriodStyleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link PeriodStyle}.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n * @author Valentine Wu\n */\nclass PeriodStyleTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid detectAndParseWhenValueIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.detectAndParse(null))\n\t\t\t.withMessageContaining(\"'value' must not be null\");\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenIso8601ShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"p15m\")).isEqualTo(Period.parse(\"p15m\"));\n\t\tassertThat(PeriodStyle.detectAndParse(\"P15M\")).isEqualTo(Period.parse(\"P15M\"));\n\t\tassertThat(PeriodStyle.detectAndParse(\"-P15M\")).isEqualTo(Period.parse(\"P-15M\"));\n\t\tassertThat(PeriodStyle.detectAndParse(\"+P15M\")).isEqualTo(Period.parse(\"P15M\"));\n\t\tassertThat(PeriodStyle.detectAndParse(\"P2D\")).isEqualTo(Period.parse(\"P2D\"));\n\t\tassertThat(PeriodStyle.detectAndParse(\"-P20Y\")).isEqualTo(Period.parse(\"P-20Y\"));\n\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleDaysShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"10d\")).hasDays(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"10D\")).hasDays(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"+10d\")).hasDays(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"-10D\")).hasDays(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleWeeksShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"10w\")).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(PeriodStyle.detectAndParse(\"10W\")).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(PeriodStyle.detectAndParse(\"+10w\")).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(PeriodStyle.detectAndParse(\"-10W\")).isEqualTo(Period.ofWeeks(-10));\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleMonthsShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"10m\")).hasMonths(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"10M\")).hasMonths(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"+10m\")).hasMonths(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"-10M\")).hasMonths(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleYearsShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"10y\")).hasYears(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"10Y\")).hasYears(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"+10y\")).hasYears(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"-10Y\")).hasYears(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleWithoutSuffixShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"10\")).hasDays(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"+10\")).hasDays(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"-10\")).hasDays(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenSimpleWithoutSuffixButWithChronoUnitShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"10\", ChronoUnit.MONTHS)).hasMonths(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"+10\", ChronoUnit.MONTHS)).hasMonths(10);\n\t\tassertThat(PeriodStyle.detectAndParse(\"-10\", ChronoUnit.MONTHS)).hasMonths(-10);\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenComplexShouldReturnPeriod() {\n\t\tassertThat(PeriodStyle.detectAndParse(\"1y2m\")).isEqualTo(Period.of(1, 2, 0));\n\t\tassertThat(PeriodStyle.detectAndParse(\"1y2m3d\")).isEqualTo(Period.of(1, 2, 3));\n\t\tassertThat(PeriodStyle.detectAndParse(\"2m3d\")).isEqualTo(Period.of(0, 2, 3));\n\t\tassertThat(PeriodStyle.detectAndParse(\"1y3d\")).isEqualTo(Period.of(1, 0, 3));\n\t\tassertThat(PeriodStyle.detectAndParse(\"-1y3d\")).isEqualTo(Period.of(-1, 0, 3));\n\t\tassertThat(PeriodStyle.detectAndParse(\"-1y-3d\")).isEqualTo(Period.of(-1, 0, -3));\n\t}\n\n\t@Test\n\tvoid detectAndParseWhenBadFormatShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.detectAndParse(\"10foo\"))\n\t\t\t.withMessageContaining(\"'10foo' is not a valid period\");\n\t}\n\n\t@Test\n\tvoid detectWhenSimpleShouldReturnSimple() {\n\t\tassertThat(PeriodStyle.detect(\"10\")).isEqualTo(PeriodStyle.SIMPLE);\n\t\tassertThat(PeriodStyle.detect(\"+10\")).isEqualTo(PeriodStyle.SIMPLE);\n\t\tassertThat(PeriodStyle.detect(\"-10\")).isEqualTo(PeriodStyle.SIMPLE);\n\t\tassertThat(PeriodStyle.detect(\"10m\")).isEqualTo(PeriodStyle.SIMPLE);\n\t\tassertThat(PeriodStyle.detect(\"10y\")).isEqualTo(PeriodStyle.SIMPLE);\n\t\tassertThat(PeriodStyle.detect(\"10d\")).isEqualTo(PeriodStyle.SIMPLE);\n\t\tassertThat(PeriodStyle.detect(\"10D\")).isEqualTo(PeriodStyle.SIMPLE);\n\t}\n\n\t@Test\n\tvoid detectWhenIso8601ShouldReturnIso8601() {\n\t\tassertThat(PeriodStyle.detect(\"p20\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"P20\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"-P15M\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"+P15M\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"P10Y\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"P2D\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"-P6\")).isEqualTo(PeriodStyle.ISO8601);\n\t\tassertThat(PeriodStyle.detect(\"-P-6M\")).isEqualTo(PeriodStyle.ISO8601);\n\t}\n\n\t@Test\n\tvoid detectWhenUnknownShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.detect(\"bad\"))\n\t\t\t.withMessageContaining(\"'bad' is not a valid period\");\n\t}\n\n\t@Test\n\tvoid parseIso8601ShouldParse() {\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"p20d\")).isEqualTo(Period.parse(\"p20d\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P20D\")).isEqualTo(Period.parse(\"P20D\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P15M\")).isEqualTo(Period.parse(\"P15M\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"+P15M\")).isEqualTo(Period.parse(\"P15M\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P10Y\")).isEqualTo(Period.parse(\"P10Y\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P2D\")).isEqualTo(Period.parse(\"P2D\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"-P6D\")).isEqualTo(Period.parse(\"-P6D\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"-P-6Y+3M\")).isEqualTo(Period.parse(\"-P-6Y+3M\"));\n\t}\n\n\t@Test\n\tvoid parseIso8601WithUnitShouldIgnoreUnit() {\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"p20d\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"p20d\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P20D\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"P20D\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P15M\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"P15M\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"+P15M\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"P15M\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P10Y\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"P10Y\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"P2D\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"P2D\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"-P6D\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"-P6D\"));\n\t\tassertThat(PeriodStyle.ISO8601.parse(\"-P-6Y+3M\", ChronoUnit.SECONDS)).isEqualTo(Period.parse(\"-P-6Y+3M\"));\n\t}\n\n\t@Test\n\tvoid parseIso8601WhenSimpleShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.ISO8601.parse(\"10d\"))\n\t\t\t.withMessageContaining(\"'10d' is not a valid ISO-8601 period\");\n\t}\n\n\t@Test\n\tvoid parseSimpleShouldParse() {\n\t\tassertThat(PeriodStyle.SIMPLE.parse(\"10m\")).hasMonths(10);\n\t}\n\n\t@Test\n\tvoid parseSimpleWithUnitShouldUseUnitAsFallback() {\n\t\tassertThat(PeriodStyle.SIMPLE.parse(\"10m\", ChronoUnit.DAYS)).hasMonths(10);\n\t\tassertThat(PeriodStyle.SIMPLE.parse(\"10\", ChronoUnit.MONTHS)).hasMonths(10);\n\t}\n\n\t@Test\n\tvoid parseSimpleWhenUnknownUnitShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.SIMPLE.parse(\"10x\")).satisfies((ex) -> {\n\t\t\tThrowable cause = ex.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\tassertThat(cause.getMessage()).isEqualTo(\"Does not match simple period pattern\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid parseSimpleWhenIso8601ShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PeriodStyle.SIMPLE.parse(\"PT10H\"))\n\t\t\t.withMessageContaining(\"'PT10H' is not a valid simple period\");\n\t}\n\n\t@Test\n\tvoid printIso8601ShouldPrint() {\n\t\tPeriod period = Period.parse(\"-P-6M+3D\");\n\t\tassertThat(PeriodStyle.ISO8601.print(period)).isEqualTo(\"P6M-3D\");\n\t}\n\n\t@Test\n\tvoid printIso8601ShouldIgnoreUnit() {\n\t\tPeriod period = Period.parse(\"-P3Y\");\n\t\tassertThat(PeriodStyle.ISO8601.print(period, ChronoUnit.DAYS)).isEqualTo(\"P-3Y\");\n\t}\n\n\t@Test\n\tvoid printSimpleWhenZeroWithoutUnitShouldPrintInDays() {\n\t\tPeriod period = Period.ofMonths(0);\n\t\tassertThat(PeriodStyle.SIMPLE.print(period)).isEqualTo(\"0d\");\n\t}\n\n\t@Test\n\tvoid printSimpleWhenZeroWithUnitShouldPrintInUnit() {\n\t\tPeriod period = Period.ofYears(0);\n\t\tassertThat(PeriodStyle.SIMPLE.print(period, ChronoUnit.YEARS)).isEqualTo(\"0y\");\n\t}\n\n\t@Test\n\tvoid printSimpleWhenNonZeroShouldIgnoreUnit() {\n\t\tPeriod period = Period.of(1, 2, 3);\n\t\tassertThat(PeriodStyle.SIMPLE.print(period, ChronoUnit.YEARS)).isEqualTo(\"1y2m3d\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/PeriodToStringConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PeriodToStringConverter}.\n *\n * @author Eddú Melendez\n * @author Edson Chávez\n */\nclass PeriodToStringConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWithoutStyleShouldReturnIso8601(ConversionService conversionService) {\n\t\tString converted = conversionService.convert(Period.ofDays(1), String.class);\n\t\tassertThat(converted).isEqualTo(Period.ofDays(1).toString());\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatWhenZeroShouldUseFormatAndDays(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Period.ofMonths(0),\n\t\t\t\tMockPeriodTypeDescriptor.get(null, PeriodStyle.SIMPLE), TypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"0d\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatShouldUseFormat(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Period.of(1, 2, 3),\n\t\t\t\tMockPeriodTypeDescriptor.get(null, PeriodStyle.SIMPLE), TypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1y2m3d\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatAndUnitWhenZeroShouldUseFormatAndUnit(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Period.ofYears(0),\n\t\t\t\tMockPeriodTypeDescriptor.get(ChronoUnit.YEARS, PeriodStyle.SIMPLE),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"0y\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithFormatAndUnitWhenNonZeroShouldUseFormatAndIgnoreUnit(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Period.of(1, 0, 3),\n\t\t\t\tMockPeriodTypeDescriptor.get(ChronoUnit.YEARS, PeriodStyle.SIMPLE),\n\t\t\t\tTypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"1y3d\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWithWeekUnitShouldConvertToStringInDays(ConversionService conversionService) {\n\t\tString converted = (String) conversionService.convert(Period.ofWeeks(53),\n\t\t\t\tMockPeriodTypeDescriptor.get(null, PeriodStyle.SIMPLE), TypeDescriptor.valueOf(String.class));\n\t\tassertThat(converted).isEqualTo(\"371d\");\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new PeriodToStringConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDataSizeConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link StringToDataSizeConverter}.\n *\n * @author Stephane Nicoll\n */\nclass StringToDataSizeConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleBytesShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10B\")).isEqualTo(DataSize.ofBytes(10));\n\t\tassertThat(convert(conversionService, \"+10B\")).isEqualTo(DataSize.ofBytes(10));\n\t\tassertThat(convert(conversionService, \"-10B\")).isEqualTo(DataSize.ofBytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleKilobytesShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10KB\")).isEqualTo(DataSize.ofKilobytes(10));\n\t\tassertThat(convert(conversionService, \"+10KB\")).isEqualTo(DataSize.ofKilobytes(10));\n\t\tassertThat(convert(conversionService, \"-10KB\")).isEqualTo(DataSize.ofKilobytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleMegabytesShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10MB\")).isEqualTo(DataSize.ofMegabytes(10));\n\t\tassertThat(convert(conversionService, \"+10MB\")).isEqualTo(DataSize.ofMegabytes(10));\n\t\tassertThat(convert(conversionService, \"-10MB\")).isEqualTo(DataSize.ofMegabytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleGigabytesShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10GB\")).isEqualTo(DataSize.ofGigabytes(10));\n\t\tassertThat(convert(conversionService, \"+10GB\")).isEqualTo(DataSize.ofGigabytes(10));\n\t\tassertThat(convert(conversionService, \"-10GB\")).isEqualTo(DataSize.ofGigabytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleTerabytesShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10TB\")).isEqualTo(DataSize.ofTerabytes(10));\n\t\tassertThat(convert(conversionService, \"+10TB\")).isEqualTo(DataSize.ofTerabytes(10));\n\t\tassertThat(convert(conversionService, \"-10TB\")).isEqualTo(DataSize.ofTerabytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10\")).isEqualTo(DataSize.ofBytes(10));\n\t\tassertThat(convert(conversionService, \"+10\")).isEqualTo(DataSize.ofBytes(10));\n\t\tassertThat(convert(conversionService, \"-10\")).isEqualTo(DataSize.ofBytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDataSize(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10\", DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10));\n\t\tassertThat(convert(conversionService, \"+10\", DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(10));\n\t\tassertThat(convert(conversionService, \"-10\", DataUnit.KILOBYTES)).isEqualTo(DataSize.ofKilobytes(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenBadFormatShouldThrowException(ConversionService conversionService) {\n\t\tassertThatExceptionOfType(ConversionFailedException.class).isThrownBy(() -> convert(conversionService, \"10WB\"))\n\t\t\t.havingCause()\n\t\t\t.isInstanceOf(IllegalArgumentException.class)\n\t\t\t.withMessageContaining(\"'10WB' is not a valid data size\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenEmptyShouldReturnNull(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"\")).isNull();\n\t}\n\n\tprivate @Nullable DataSize convert(ConversionService conversionService, String source) {\n\t\treturn conversionService.convert(source, DataSize.class);\n\t}\n\n\tprivate @Nullable DataSize convert(ConversionService conversionService, String source, @Nullable DataUnit unit) {\n\t\treturn (DataSize) conversionService.convert(source, TypeDescriptor.forObject(source),\n\t\t\t\tMockDataSizeTypeDescriptor.get(unit));\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new StringToDataSizeConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/StringToDurationConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link StringToDurationConverter}.\n *\n * @author Phillip Webb\n */\nclass StringToDurationConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenIso8601ShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"pt20.345s\")).isEqualTo(Duration.parse(\"pt20.345s\"));\n\t\tassertThat(convert(conversionService, \"PT20.345S\")).isEqualTo(Duration.parse(\"PT20.345S\"));\n\t\tassertThat(convert(conversionService, \"PT15M\")).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(convert(conversionService, \"+PT15M\")).isEqualTo(Duration.parse(\"PT15M\"));\n\t\tassertThat(convert(conversionService, \"PT10H\")).isEqualTo(Duration.parse(\"PT10H\"));\n\t\tassertThat(convert(conversionService, \"P2D\")).isEqualTo(Duration.parse(\"P2D\"));\n\t\tassertThat(convert(conversionService, \"P2DT3H4M\")).isEqualTo(Duration.parse(\"P2DT3H4M\"));\n\t\tassertThat(convert(conversionService, \"-PT6H3M\")).isEqualTo(Duration.parse(\"-PT6H3M\"));\n\t\tassertThat(convert(conversionService, \"-PT-6H+3M\")).isEqualTo(Duration.parse(\"-PT-6H+3M\"));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleNanosShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10ns\")).hasNanos(10);\n\t\tassertThat(convert(conversionService, \"10NS\")).hasNanos(10);\n\t\tassertThat(convert(conversionService, \"+10ns\")).hasNanos(10);\n\t\tassertThat(convert(conversionService, \"-10ns\")).hasNanos(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleMicrosShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10us\")).hasNanos(10000);\n\t\tassertThat(convert(conversionService, \"10US\")).hasNanos(10000);\n\t\tassertThat(convert(conversionService, \"+10us\")).hasNanos(10000);\n\t\tassertThat(convert(conversionService, \"-10us\")).hasNanos(-10000);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleMillisShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10ms\")).hasMillis(10);\n\t\tassertThat(convert(conversionService, \"10MS\")).hasMillis(10);\n\t\tassertThat(convert(conversionService, \"+10ms\")).hasMillis(10);\n\t\tassertThat(convert(conversionService, \"-10ms\")).hasMillis(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleSecondsShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10s\")).hasSeconds(10);\n\t\tassertThat(convert(conversionService, \"10S\")).hasSeconds(10);\n\t\tassertThat(convert(conversionService, \"+10s\")).hasSeconds(10);\n\t\tassertThat(convert(conversionService, \"-10s\")).hasSeconds(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleMinutesShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10m\")).hasMinutes(10);\n\t\tassertThat(convert(conversionService, \"10M\")).hasMinutes(10);\n\t\tassertThat(convert(conversionService, \"+10m\")).hasMinutes(10);\n\t\tassertThat(convert(conversionService, \"-10m\")).hasMinutes(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleHoursShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10h\")).hasHours(10);\n\t\tassertThat(convert(conversionService, \"10H\")).hasHours(10);\n\t\tassertThat(convert(conversionService, \"+10h\")).hasHours(10);\n\t\tassertThat(convert(conversionService, \"-10h\")).hasHours(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleDaysShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10d\")).hasDays(10);\n\t\tassertThat(convert(conversionService, \"10D\")).hasDays(10);\n\t\tassertThat(convert(conversionService, \"+10d\")).hasDays(10);\n\t\tassertThat(convert(conversionService, \"-10d\")).hasDays(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10\")).hasMillis(10);\n\t\tassertThat(convert(conversionService, \"+10\")).hasMillis(10);\n\t\tassertThat(convert(conversionService, \"-10\")).hasMillis(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnDuration(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10\", ChronoUnit.SECONDS, null)).hasSeconds(10);\n\t\tassertThat(convert(conversionService, \"+10\", ChronoUnit.SECONDS, null)).hasSeconds(10);\n\t\tassertThat(convert(conversionService, \"-10\", ChronoUnit.SECONDS, null)).hasSeconds(-10);\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenBadFormatShouldThrowException(ConversionService conversionService) {\n\t\tassertThatExceptionOfType(ConversionFailedException.class).isThrownBy(() -> convert(conversionService, \"10foo\"))\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\"'10foo' is not a valid duration\");\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenStyleMismatchShouldThrowException(ConversionService conversionService) {\n\t\tassertThatExceptionOfType(ConversionFailedException.class)\n\t\t\t.isThrownBy(() -> convert(conversionService, \"10s\", null, DurationStyle.ISO8601));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenEmptyShouldReturnNull(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"\")).isNull();\n\t}\n\n\tprivate @Nullable Duration convert(ConversionService conversionService, String source) {\n\t\treturn conversionService.convert(source, Duration.class);\n\t}\n\n\tprivate @Nullable Duration convert(ConversionService conversionService, String source, @Nullable ChronoUnit unit,\n\t\t\t@Nullable DurationStyle style) {\n\t\treturn (Duration) conversionService.convert(source, TypeDescriptor.forObject(source),\n\t\t\t\tMockDurationTypeDescriptor.get(unit, style));\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new StringToDurationConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/StringToFileConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StringToFileConverter}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass StringToFileConverterTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleFileReturnsFile(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, this.temp.getAbsolutePath() + \"/test\"))\n\t\t\t.isEqualTo(new File(this.temp, \"test\").getAbsoluteFile());\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenFilePrefixedReturnsFile(ConversionService conversionService) {\n\t\tFile file = convert(conversionService, \"file:\" + this.temp.getAbsolutePath() + \"/test\");\n\t\tassertThat(file).isNotNull();\n\t\tassertThat(file.getAbsoluteFile()).isEqualTo(new File(this.temp, \"test\").getAbsoluteFile());\n\t}\n\n\t@ConversionServiceTest\n\t@WithResource(name = \"com/example/test-file.txt\", content = \"test content\")\n\tvoid convertWhenClasspathPrefixedReturnsFile(ConversionService conversionService) throws IOException {\n\t\tString resource = new ClassPathResource(\"com/example/test-file.txt\").getURL().getFile();\n\t\tFile file = convert(conversionService, \"classpath:com/example/test-file.txt\");\n\t\tassertThat(file).isNotNull();\n\t\tassertThat(file.getAbsoluteFile()).isEqualTo(new File(resource).getAbsoluteFile());\n\t}\n\n\tprivate @Nullable File convert(ConversionService conversionService, String source) {\n\t\treturn conversionService.convert(source, File.class);\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments\n\t\t\t.with((conversionService) -> conversionService.addConverter(new StringToFileConverter()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/convert/StringToPeriodConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.convert;\n\nimport java.time.Period;\nimport java.time.temporal.ChronoUnit;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.provider.Arguments;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.TypeDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StringToPeriodConverter}.\n *\n * @author Eddú Meléndez\n * @author Edson Chávez\n */\nclass StringToPeriodConverterTests {\n\n\t@ConversionServiceTest\n\tvoid convertWhenIso8601ShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"p2y\")).isEqualTo(Period.parse(\"p2y\"));\n\t\tassertThat(convert(conversionService, \"P2Y\")).isEqualTo(Period.parse(\"P2Y\"));\n\t\tassertThat(convert(conversionService, \"P3M\")).isEqualTo(Period.parse(\"P3M\"));\n\t\tassertThat(convert(conversionService, \"P4W\")).isEqualTo(Period.parse(\"P4W\"));\n\t\tassertThat(convert(conversionService, \"P5D\")).isEqualTo(Period.parse(\"P5D\"));\n\t\tassertThat(convert(conversionService, \"P1Y2M3D\")).isEqualTo(Period.parse(\"P1Y2M3D\"));\n\t\tassertThat(convert(conversionService, \"P1Y2M3W4D\")).isEqualTo(Period.parse(\"P1Y2M3W4D\"));\n\t\tassertThat(convert(conversionService, \"P-1Y2M\")).isEqualTo(Period.parse(\"P-1Y2M\"));\n\t\tassertThat(convert(conversionService, \"-P1Y2M\")).isEqualTo(Period.parse(\"-P1Y2M\"));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleDaysShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10d\")).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"10D\")).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"+10d\")).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"-10D\")).isEqualTo(Period.ofDays(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWeeksShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10w\")).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(convert(conversionService, \"10W\")).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(convert(conversionService, \"+10w\")).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(convert(conversionService, \"-10W\")).isEqualTo(Period.ofWeeks(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleMonthsShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10m\")).isEqualTo(Period.ofMonths(10));\n\t\tassertThat(convert(conversionService, \"10M\")).isEqualTo(Period.ofMonths(10));\n\t\tassertThat(convert(conversionService, \"+10m\")).isEqualTo(Period.ofMonths(10));\n\t\tassertThat(convert(conversionService, \"-10M\")).isEqualTo(Period.ofMonths(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleYearsShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10y\")).isEqualTo(Period.ofYears(10));\n\t\tassertThat(convert(conversionService, \"10Y\")).isEqualTo(Period.ofYears(10));\n\t\tassertThat(convert(conversionService, \"+10y\")).isEqualTo(Period.ofYears(10));\n\t\tassertThat(convert(conversionService, \"-10Y\")).isEqualTo(Period.ofYears(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10\")).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"+10\")).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"-10\")).isEqualTo(Period.ofDays(-10));\n\t}\n\n\t@ConversionServiceTest\n\tvoid convertWhenSimpleWithoutSuffixButWithAnnotationShouldReturnPeriod(ConversionService conversionService) {\n\t\tassertThat(convert(conversionService, \"10\", ChronoUnit.DAYS, null)).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"+10\", ChronoUnit.DAYS, null)).isEqualTo(Period.ofDays(10));\n\t\tassertThat(convert(conversionService, \"-10\", ChronoUnit.DAYS, null)).isEqualTo(Period.ofDays(-10));\n\t\tassertThat(convert(conversionService, \"10\", ChronoUnit.WEEKS, null)).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(convert(conversionService, \"+10\", ChronoUnit.WEEKS, null)).isEqualTo(Period.ofWeeks(10));\n\t\tassertThat(convert(conversionService, \"-10\", ChronoUnit.WEEKS, null)).isEqualTo(Period.ofWeeks(-10));\n\t\tassertThat(convert(conversionService, \"10\", ChronoUnit.MONTHS, null)).isEqualTo(Period.ofMonths(10));\n\t\tassertThat(convert(conversionService, \"+10\", ChronoUnit.MONTHS, null)).isEqualTo(Period.ofMonths(10));\n\t\tassertThat(convert(conversionService, \"-10\", ChronoUnit.MONTHS, null)).isEqualTo(Period.ofMonths(-10));\n\t\tassertThat(convert(conversionService, \"10\", ChronoUnit.YEARS, null)).isEqualTo(Period.ofYears(10));\n\t\tassertThat(convert(conversionService, \"+10\", ChronoUnit.YEARS, null)).isEqualTo(Period.ofYears(10));\n\t\tassertThat(convert(conversionService, \"-10\", ChronoUnit.YEARS, null)).isEqualTo(Period.ofYears(-10));\n\t}\n\n\tprivate @Nullable Period convert(ConversionService conversionService, String source) {\n\t\treturn conversionService.convert(source, Period.class);\n\t}\n\n\tprivate @Nullable Period convert(ConversionService conversionService, String source, @Nullable ChronoUnit unit,\n\t\t\t@Nullable PeriodStyle style) {\n\t\treturn (Period) conversionService.convert(source, TypeDescriptor.forObject(source),\n\t\t\t\tMockPeriodTypeDescriptor.get(unit, style));\n\t}\n\n\tstatic Stream<? extends Arguments> conversionServices() {\n\t\treturn ConversionServiceArguments.with(new StringToPeriodConverter());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/AbstractFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractFailureAnalyzer}.\n *\n * @author Kim Jung Bin\n * @author Stephane Nicoll\n */\nclass AbstractFailureAnalyzerTests {\n\n\tprivate final TestFailureAnalyzer failureAnalyzer = new TestFailureAnalyzer();\n\n\t@Test\n\tvoid findCauseWithNullException() {\n\t\tassertThat(this.failureAnalyzer.findCause(null, Throwable.class)).isNull();\n\t}\n\n\t@Test\n\tvoid findCauseWithDirectExactMatch() {\n\t\tTestException ex = new TestException();\n\t\tassertThat(this.failureAnalyzer.findCause(ex, TestException.class)).isEqualTo(ex);\n\t}\n\n\t@Test\n\tvoid findCauseWithDirectSubClass() {\n\t\tSpecificTestException ex = new SpecificTestException();\n\t\tassertThat(this.failureAnalyzer.findCause(ex, TestException.class)).isEqualTo(ex);\n\t}\n\n\t@Test\n\tvoid findCauseWitNestedAndExactMatch() {\n\t\tTestException ex = new TestException();\n\t\tassertThat(this.failureAnalyzer.findCause(new IllegalArgumentException(new IllegalStateException(ex)),\n\t\t\t\tTestException.class))\n\t\t\t.isEqualTo(ex);\n\t}\n\n\t@Test\n\tvoid findCauseWitNestedAndSubClass() {\n\t\tSpecificTestException ex = new SpecificTestException();\n\t\tassertThat(this.failureAnalyzer.findCause(new IOException(new IllegalStateException(ex)), TestException.class))\n\t\t\t.isEqualTo(ex);\n\t}\n\n\t@Test\n\tvoid findCauseWithUnrelatedException() {\n\t\tIOException ex = new IOException();\n\t\tassertThat(this.failureAnalyzer.findCause(ex, TestException.class)).isNull();\n\t}\n\n\t@Test\n\tvoid findCauseWithMoreSpecificException() {\n\t\tTestException ex = new TestException();\n\t\tassertThat(this.failureAnalyzer.findCause(ex, SpecificTestException.class)).isNull();\n\t}\n\n\tstatic class TestFailureAnalyzer extends AbstractFailureAnalyzer<Throwable> {\n\n\t\t@Override\n\t\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, Throwable cause) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class TestException extends Exception {\n\n\t}\n\n\tstatic class SpecificTestException extends TestException {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport jakarta.annotation.PostConstruct;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.util.pattern.PathPatternParser;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Integration tests for {@link FailureAnalyzers}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass FailureAnalyzersIntegrationTests {\n\n\t@Test\n\tvoid analysisIsPerformed(CapturedOutput output) {\n\t\tassertThatException()\n\t\t\t.isThrownBy(() -> new SpringApplicationBuilder(TestConfiguration.class).web(WebApplicationType.NONE).run());\n\t\tassertThat(output).contains(\"APPLICATION FAILED TO START\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@PostConstruct\n\t\tvoid fail() {\n\t\t\tnew PathPatternParser().parse(\"{ }\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.test.io.support.MockSpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link FailureAnalyzers}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass FailureAnalyzersTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate static FailureAnalyzer failureAnalyzer;\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\tprivate final List<FailureAnalysis> reports = new ArrayList<>();\n\n\t@BeforeEach\n\tvoid configureMock() {\n\t\tfailureAnalyzer = mock(FailureAnalyzer.class);\n\t}\n\n\t@Test\n\tvoid analyzersAreLoadedAndCalled() {\n\t\tRuntimeException failure = new RuntimeException();\n\t\tanalyzeAndReport(failure, BasicFailureAnalyzer.class, BasicFailureAnalyzer.class);\n\t\tthen(failureAnalyzer).should(times(2)).analyze(failure);\n\t}\n\n\t@Test\n\tvoid analyzerIsConstructedWithBeanFactory() {\n\t\tRuntimeException failure = new RuntimeException();\n\t\tanalyzeAndReport(failure, BasicFailureAnalyzer.class, BeanFactoryConstructorFailureAnalyzer.class);\n\t\tthen(failureAnalyzer).should(times(2)).analyze(failure);\n\t}\n\n\t@Test\n\tvoid analyzerIsConstructedWithEnvironment() {\n\t\tRuntimeException failure = new RuntimeException();\n\t\tanalyzeAndReport(failure, BasicFailureAnalyzer.class, EnvironmentConstructorFailureAnalyzer.class);\n\t\tthen(failureAnalyzer).should(times(2)).analyze(failure);\n\t}\n\n\t@Test\n\tvoid analyzerThatFailsDuringInitializationDoesNotPreventOtherAnalyzersFromBeingCalled() {\n\t\tRuntimeException failure = new RuntimeException();\n\t\tanalyzeAndReport(failure, BrokenInitializationFailureAnalyzer.class, BasicFailureAnalyzer.class);\n\t\tthen(failureAnalyzer).should().analyze(failure);\n\t}\n\n\t@Test\n\tvoid analyzerThatFailsDuringAnalysisDoesNotPreventOtherAnalyzersFromBeingCalled() {\n\t\tRuntimeException failure = new RuntimeException();\n\t\tanalyzeAndReport(failure, BrokenAnalysisFailureAnalyzer.class, BasicFailureAnalyzer.class);\n\t\tthen(failureAnalyzer).should().analyze(failure);\n\t}\n\n\t@Test\n\tvoid failureAnalyzedExceptionAreReported() {\n\t\tFailureAnalyzedException failure = new FailureAnalyzedException(\"Bad\", \"Fix it!\");\n\t\tanalyzeAndReport(failure);\n\t\tassertThat(this.reports).hasSize(1);\n\t\tFailureAnalysis report = this.reports.get(0);\n\t\tassertThat(report.getDescription()).isEqualTo(\"Bad\");\n\t\tassertThat(report.getAction()).isEqualTo(\"Fix it!\");\n\t\tassertThat(report.getCause()).isSameAs(failure);\n\t}\n\n\t@Test\n\tvoid wrappedFailureAnalyzedExceptionAreReported() {\n\t\tFailureAnalyzedException failure = new FailureAnalyzedException(\"Bad\", \"Fix it!\");\n\t\tanalyzeAndReport(new IllegalStateException(\"the state of this!\", failure));\n\t\tassertThat(this.reports).hasSize(1);\n\t\tFailureAnalysis report = this.reports.get(0);\n\t\tassertThat(report.getDescription()).isEqualTo(\"Bad\");\n\t\tassertThat(report.getAction()).isEqualTo(\"Fix it!\");\n\t\tassertThat(report.getCause()).isSameAs(failure);\n\t}\n\n\t@Test\n\tvoid whenOtherAnalyzerIsAvailableFailureAnalyzedExceptionAreNotReported() {\n\t\tFailureAnalyzedException failure = new FailureAnalyzedException(\"Bad\", \"Fix it!\");\n\t\tanalyzeAndReport(new IllegalStateException(\"the state of this!\", failure), IllegalStateFailureAnalyzer.class);\n\t\tassertThat(this.reports).hasSize(1);\n\t\tFailureAnalysis report = this.reports.get(0);\n\t\tassertThat(report.getDescription()).isEqualTo(\"analyzed state\");\n\t}\n\n\t@SafeVarargs\n\tprivate void analyzeAndReport(Throwable failure, Class<? extends FailureAnalyzer>... failureAnalyzerClasses) {\n\t\tanalyzeAndReport(failure, this.context, failureAnalyzerClasses);\n\t}\n\n\t@SafeVarargs\n\tprivate void analyzeAndReport(Throwable failure, AnnotationConfigApplicationContext context,\n\t\t\tClass<? extends FailureAnalyzer>... failureAnalyzerClasses) {\n\t\tMockSpringFactoriesLoader loader = new MockSpringFactoriesLoader();\n\t\tfor (Class<? extends FailureAnalyzer> failureAnalyzerClass : failureAnalyzerClasses) {\n\t\t\tloader.add(FailureAnalyzer.class, failureAnalyzerClass);\n\t\t}\n\t\tloader.addInstance(FailureAnalysisReporter.class, this.reports::add);\n\t\tnew FailureAnalyzers(context, loader).reportException(failure);\n\t}\n\n\tstatic class BasicFailureAnalyzer implements FailureAnalyzer {\n\n\t\t@Override\n\t\tpublic @Nullable FailureAnalysis analyze(Throwable failure) {\n\t\t\treturn failureAnalyzer.analyze(failure);\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"NullAway\") // Intentional NullPointerException\n\tstatic class BrokenInitializationFailureAnalyzer implements FailureAnalyzer {\n\n\t\tstatic {\n\t\t\tObject foo = null;\n\t\t\tfoo.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic FailureAnalysis analyze(Throwable failure) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class BrokenAnalysisFailureAnalyzer implements FailureAnalyzer {\n\n\t\t@Override\n\t\tpublic FailureAnalysis analyze(Throwable failure) {\n\t\t\tthrow new NoClassDefFoundError();\n\t\t}\n\n\t}\n\n\tstatic class BeanFactoryConstructorFailureAnalyzer extends BasicFailureAnalyzer {\n\n\t\tBeanFactoryConstructorFailureAnalyzer(BeanFactory beanFactory) {\n\t\t\tassertThat(beanFactory).isNotNull();\n\t\t}\n\n\t}\n\n\tstatic class EnvironmentConstructorFailureAnalyzer extends BasicFailureAnalyzer {\n\n\t\tEnvironmentConstructorFailureAnalyzer(Environment environment) {\n\t\t\tassertThat(environment).isNotNull();\n\t\t}\n\n\t}\n\n\tstatic class IllegalStateFailureAnalyzer implements FailureAnalyzer {\n\n\t\t@Override\n\t\tpublic @Nullable FailureAnalysis analyze(Throwable failure) {\n\t\t\tif (failure instanceof IllegalStateException) {\n\t\t\t\treturn new FailureAnalysis(\"analyzed state\", null, failure);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/AotInitializerNotFoundFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.AotInitializerNotFoundException;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AotInitializerNotFoundFailureAnalyzer}.\n *\n * @author Moritz Halbritter\n */\nclass AotInitializerNotFoundFailureAnalyzerTests {\n\n\t@Test\n\tvoid shouldAnalyze() {\n\t\tFailureAnalysis analysis = analyze();\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).isEqualTo(\n\t\t\t\t\"Startup with AOT mode enabled failed: AOT initializer class org.springframework.boot.diagnostics.analyzer.AotInitializerNotFoundFailureAnalyzerTests__ApplicationContextInitializer could not be found\");\n\t\tassertThat(analysis.getAction()).isEqualTo(\n\t\t\t\t\"\"\"\n\t\t\t\t\t\tConsider the following:\n\t\t\t\t\t\t\\tDid you build the application with enabled AOT processing?\n\t\t\t\t\t\t\\tIs the main class org.springframework.boot.diagnostics.analyzer.AotInitializerNotFoundFailureAnalyzerTests correct?\n\t\t\t\t\t\t\\tIf you want to run the application in regular mode, remove the system property 'spring.aot.enabled'\"\"\");\n\t}\n\n\tprivate @Nullable FailureAnalysis analyze() {\n\t\treturn new AotInitializerNotFoundFailureAnalyzer()\n\t\t\t.analyze(new AotInitializerNotFoundException(AotInitializerNotFoundFailureAnalyzerTests.class,\n\t\t\t\t\tAotInitializerNotFoundFailureAnalyzerTests.class + \"__ApplicationContextInitializer\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanCurrentlyInCreationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzerTests.CycleWithAutowiredFields.BeanThreeConfiguration;\nimport org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzerTests.CycleWithAutowiredFields.BeanTwoConfiguration;\nimport org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzerTests.CyclicBeanMethodsConfiguration.InnerConfiguration;\nimport org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzerTests.CyclicBeanMethodsConfiguration.InnerConfiguration.InnerInnerConfiguration;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link BeanCurrentlyInCreationFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass BeanCurrentlyInCreationFailureAnalyzerTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\tprivate final BeanCurrentlyInCreationFailureAnalyzer analyzer = new BeanCurrentlyInCreationFailureAnalyzer(\n\t\t\tthis.context.getBeanFactory());\n\n\t@Test\n\tvoid cyclicBeanMethods() throws IOException {\n\t\tFailureAnalysis analysis = performAnalysis(CyclicBeanMethodsConfiguration.class);\n\t\tList<String> lines = readDescriptionLines(analysis);\n\t\tassertThat(lines).hasSize(9);\n\t\tassertThat(lines.get(0))\n\t\t\t.isEqualTo(\"The dependencies of some of the beans in the application context form a cycle:\");\n\t\tassertThat(lines.get(1)).isEmpty();\n\t\tassertThat(lines.get(2)).isEqualTo(\"┌─────┐\");\n\t\tassertThat(lines.get(3)).startsWith(\"|  one defined in \" + InnerInnerConfiguration.class.getName());\n\t\tassertThat(lines.get(4)).isEqualTo(\"↑     ↓\");\n\t\tassertThat(lines.get(5)).startsWith(\"|  two defined in \" + InnerConfiguration.class.getName());\n\t\tassertThat(lines.get(6)).isEqualTo(\"↑     ↓\");\n\t\tassertThat(lines.get(7)).startsWith(\"|  three defined in \" + CyclicBeanMethodsConfiguration.class.getName());\n\t\tassertThat(lines.get(8)).isEqualTo(\"└─────┘\");\n\t\tassertThat(analysis.getAction()).isNotNull();\n\t}\n\n\t@Test\n\tvoid cycleWithAutowiredFields() throws IOException {\n\t\tFailureAnalysis analysis = performAnalysis(CycleWithAutowiredFields.class);\n\t\tassertThat(analysis.getDescription())\n\t\t\t.startsWith(\"The dependencies of some of the beans in the application context form a cycle:\");\n\t\tList<String> lines = readDescriptionLines(analysis);\n\t\tassertThat(lines).hasSize(9);\n\t\tassertThat(lines.get(0))\n\t\t\t.isEqualTo(\"The dependencies of some of the beans in the application context form a cycle:\");\n\t\tassertThat(lines.get(1)).isEmpty();\n\t\tassertThat(lines.get(2)).isEqualTo(\"┌─────┐\");\n\t\tassertThat(lines.get(3)).startsWith(\"|  three defined in \" + BeanThreeConfiguration.class.getName());\n\t\tassertThat(lines.get(4)).isEqualTo(\"↑     ↓\");\n\t\tassertThat(lines.get(5)).startsWith(\"|  one defined in \" + CycleWithAutowiredFields.class.getName());\n\t\tassertThat(lines.get(6)).isEqualTo(\"↑     ↓\");\n\t\tassertThat(lines.get(7))\n\t\t\t.startsWith(\"|  \" + BeanTwoConfiguration.class.getName() + \" (field private \" + BeanThree.class.getName());\n\t\tassertThat(lines.get(8)).isEqualTo(\"└─────┘\");\n\t\tassertThat(analysis.getAction()).isNotNull();\n\t}\n\n\t@Test\n\tvoid cycleReferencedViaOtherBeans() throws IOException {\n\t\tFailureAnalysis analysis = performAnalysis(CycleReferencedViaOtherBeansConfiguration.class);\n\t\tList<String> lines = readDescriptionLines(analysis);\n\t\tassertThat(lines).hasSize(12);\n\t\tassertThat(lines.get(0))\n\t\t\t.isEqualTo(\"The dependencies of some of the beans in the application context form a cycle:\");\n\t\tassertThat(lines.get(1)).isEmpty();\n\t\tassertThat(lines.get(2)).contains(\"refererOne (field \" + RefererTwo.class.getName());\n\t\tassertThat(lines.get(3)).isEqualTo(\"      ↓\");\n\t\tassertThat(lines.get(4)).contains(\"refererTwo (field \" + BeanOne.class.getName());\n\t\tassertThat(lines.get(5)).isEqualTo(\"┌─────┐\");\n\t\tassertThat(lines.get(6))\n\t\t\t.startsWith(\"|  one defined in \" + CycleReferencedViaOtherBeansConfiguration.class.getName());\n\t\tassertThat(lines.get(7)).isEqualTo(\"↑     ↓\");\n\t\tassertThat(lines.get(8))\n\t\t\t.startsWith(\"|  two defined in \" + CycleReferencedViaOtherBeansConfiguration.class.getName());\n\t\tassertThat(lines.get(9)).isEqualTo(\"↑     ↓\");\n\t\tassertThat(lines.get(10))\n\t\t\t.startsWith(\"|  three defined in \" + CycleReferencedViaOtherBeansConfiguration.class.getName());\n\t\tassertThat(lines.get(11)).isEqualTo(\"└─────┘\");\n\t\tassertThat(analysis.getAction()).isNotNull();\n\t}\n\n\t@Test\n\tvoid testSelfReferenceCycle() throws IOException {\n\t\tFailureAnalysis analysis = performAnalysis(SelfReferenceBeanConfiguration.class);\n\t\tList<String> lines = readDescriptionLines(analysis);\n\t\tassertThat(lines).hasSize(5);\n\t\tassertThat(lines.get(0))\n\t\t\t.isEqualTo(\"The dependencies of some of the beans in the application context form a cycle:\");\n\t\tassertThat(lines.get(1)).isEmpty();\n\t\tassertThat(lines.get(2)).isEqualTo(\"┌──->──┐\");\n\t\tassertThat(lines.get(3)).startsWith(\"|  bean defined in \" + SelfReferenceBeanConfiguration.class.getName());\n\t\tassertThat(lines.get(4)).isEqualTo(\"└──<-──┘\");\n\t\tassertThat(analysis.getAction()).isNotNull();\n\t}\n\n\t@Test\n\tvoid cycleWithAnUnknownStartIsNotAnalyzed() {\n\t\tassertThat(this.analyzer.analyze(new BeanCurrentlyInCreationException(\"test\"))).isNull();\n\t}\n\n\t@Test\n\tvoid cycleWithCircularReferencesAllowed() {\n\t\tFailureAnalysis analysis = performAnalysis(CyclicBeanMethodsConfiguration.class, true);\n\t\tassertThat(analysis.getAction()).contains(\"Despite circular references being allowed\");\n\t}\n\n\t@Test\n\tvoid cycleWithCircularReferencesProhibited() {\n\t\tFailureAnalysis analysis = performAnalysis(CyclicBeanMethodsConfiguration.class, false);\n\t\tassertThat(analysis.getAction()).contains(\"As a last resort\");\n\t}\n\n\tprivate List<String> readDescriptionLines(FailureAnalysis analysis) throws IOException {\n\t\ttry (BufferedReader reader = new BufferedReader(new StringReader(analysis.getDescription()))) {\n\t\t\treturn reader.lines().toList();\n\t\t}\n\t}\n\n\tprivate FailureAnalysis performAnalysis(Class<?> configuration) {\n\t\treturn performAnalysis(configuration, true);\n\t}\n\n\tprivate FailureAnalysis performAnalysis(Class<?> configuration, boolean allowCircularReferences) {\n\t\tFailureAnalysis analysis = this.analyzer.analyze(createFailure(configuration, allowCircularReferences));\n\t\tassertThat(analysis).isNotNull();\n\t\treturn analysis;\n\t}\n\n\tprivate Exception createFailure(Class<?> configuration, boolean allowCircularReferences) {\n\t\ttry {\n\t\t\tthis.context.register(configuration);\n\t\t\tAbstractAutowireCapableBeanFactory beanFactory = (AbstractAutowireCapableBeanFactory) this.context\n\t\t\t\t.getBeanFactory();\n\t\t\tbeanFactory.setAllowCircularReferences(allowCircularReferences);\n\t\t\tthis.context.refresh();\n\t\t\tfail(\"Expected failure did not occur\");\n\t\t\tthrow new AssertionError(\"This should not be reached\");\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\tstatic class CyclicBeanMethodsConfiguration {\n\n\t\t@Bean\n\t\tBeanThree three(BeanOne one) {\n\t\t\treturn new BeanThree();\n\t\t}\n\n\t\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\t\tstatic class InnerConfiguration {\n\n\t\t\t@Bean\n\t\t\tBeanTwo two(BeanThree three) {\n\t\t\t\treturn new BeanTwo();\n\t\t\t}\n\n\t\t\t@Configuration(proxyBeanMethods = false)\n\t\t\tstatic class InnerInnerConfiguration {\n\n\t\t\t\t@Bean\n\t\t\t\tBeanOne one(BeanTwo two) {\n\t\t\t\t\treturn new BeanOne();\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CycleReferencedViaOtherBeansConfiguration {\n\n\t\t@Bean\n\t\tBeanOne one(BeanTwo two) {\n\t\t\treturn new BeanOne();\n\t\t}\n\n\t\t@Bean\n\t\tBeanTwo two(BeanThree three) {\n\t\t\treturn new BeanTwo();\n\t\t}\n\n\t\t@Bean\n\t\tBeanThree three(BeanOne beanOne) {\n\t\t\treturn new BeanThree();\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class InnerConfiguration {\n\n\t\t\t@Bean\n\t\t\tRefererTwo refererTwo() {\n\t\t\t\treturn new RefererTwo();\n\t\t\t}\n\n\t\t\t@Configuration(proxyBeanMethods = false)\n\t\t\tstatic class InnerInnerConfiguration {\n\n\t\t\t\t@Bean\n\t\t\t\tRefererOne refererOne() {\n\t\t\t\t\treturn new RefererOne();\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\tstatic class CycleWithAutowiredFields {\n\n\t\t@Bean\n\t\tBeanOne one(BeanTwo two) {\n\t\t\treturn new BeanOne();\n\t\t}\n\n\t\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\t\tstatic class BeanTwoConfiguration {\n\n\t\t\t@SuppressWarnings(\"unused\")\n\t\t\t@Autowired\n\t\t\tprivate BeanThree three;\n\n\t\t\t@Bean\n\t\t\tBeanTwo two() {\n\t\t\t\treturn new BeanTwo();\n\t\t\t}\n\n\t\t}\n\n\t\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\t\tstatic class BeanThreeConfiguration {\n\n\t\t\t@Bean\n\t\t\tBeanThree three(BeanOne one) {\n\t\t\t\treturn new BeanThree();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SelfReferenceBeanConfiguration {\n\n\t\t@Bean\n\t\tSelfReferenceBean bean(SelfReferenceBean bean) {\n\t\t\treturn new SelfReferenceBean();\n\t\t}\n\n\t}\n\n\tstatic class RefererOne {\n\n\t\t@Autowired\n\t\tRefererTwo refererTwo;\n\n\t}\n\n\tstatic class RefererTwo {\n\n\t\t@Autowired\n\t\tBeanOne beanOne;\n\n\t}\n\n\tstatic class BeanOne {\n\n\t}\n\n\tstatic class BeanTwo {\n\n\t}\n\n\tstatic class BeanThree {\n\n\t}\n\n\tstatic class SelfReferenceBean {\n\n\t\t@Autowired\n\t\tSelfReferenceBean bean;\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanDefinitionOverrideFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.BeanDefinitionOverrideException;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BeanDefinitionOverrideFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n */\nclass BeanDefinitionOverrideFailureAnalyzerTests {\n\n\t@Test\n\tvoid analyzeBeanDefinitionOverrideException() {\n\t\tFailureAnalysis analysis = performAnalysis(BeanOverrideConfiguration.class);\n\t\tassertThat(analysis).isNotNull();\n\t\tString description = analysis.getDescription();\n\t\tassertThat(description).contains(\"The bean 'testBean', defined in \" + SecondConfiguration.class.getName()\n\t\t\t\t+ \", could not be registered.\");\n\t\tassertThat(description).contains(FirstConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid analyzeBeanDefinitionOverrideExceptionWithDefinitionsWithNoResourceDescription() {\n\t\tFailureAnalysis analysis = performAnalysis((context) -> {\n\t\t\tcontext.registerBean(\"testBean\", String.class, (Supplier<String>) String::new);\n\t\t\tcontext.registerBean(\"testBean\", String.class, (Supplier<String>) String::new);\n\t\t});\n\t\tassertThat(analysis).isNotNull();\n\t\tString description = analysis.getDescription();\n\t\tassertThat(description)\n\t\t\t.isEqualTo(\"The bean 'testBean' could not be registered. A bean with that name has already\"\n\t\t\t\t\t+ \" been defined and overriding is disabled.\");\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(Class<?> configuration) {\n\t\tBeanDefinitionOverrideException failure = createFailure(configuration);\n\t\tassertThat(failure).isNotNull();\n\t\treturn new BeanDefinitionOverrideFailureAnalyzer().analyze(failure);\n\t}\n\n\tprivate @Nullable BeanDefinitionOverrideException createFailure(Class<?> configuration) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tcontext.setAllowBeanDefinitionOverriding(false);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\treturn null;\n\t\t}\n\t\tcatch (BeanDefinitionOverrideException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(\n\t\t\tApplicationContextInitializer<AnnotationConfigApplicationContext> initializer) {\n\t\tBeanDefinitionOverrideException failure = createFailure(initializer);\n\t\tassertThat(failure).isNotNull();\n\t\treturn new BeanDefinitionOverrideFailureAnalyzer().analyze(failure);\n\t}\n\n\tprivate @Nullable BeanDefinitionOverrideException createFailure(\n\t\t\tApplicationContextInitializer<AnnotationConfigApplicationContext> initializer) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tcontext.setAllowBeanDefinitionOverriding(false);\n\t\t\tinitializer.initialize(context);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\treturn null;\n\t\t}\n\t\tcatch (BeanDefinitionOverrideException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ FirstConfiguration.class, SecondConfiguration.class })\n\tstatic class BeanOverrideConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FirstConfiguration {\n\n\t\t@Bean\n\t\tString testBean() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecondConfiguration {\n\n\t\t@Bean\n\t\tString testBean() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BeanNotOfRequiredTypeFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.scheduling.annotation.EnableAsync;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link BeanNotOfRequiredTypeFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass BeanNotOfRequiredTypeFailureAnalyzerTests {\n\n\tprivate final FailureAnalyzer analyzer = new BeanNotOfRequiredTypeFailureAnalyzer();\n\n\t@Test\n\tvoid jdkProxyCausesInjectionFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(JdkProxyConfiguration.class);\n\t\tassertThat(analysis.getDescription()).startsWith(\"The bean 'asyncBean'\");\n\t\tassertThat(analysis.getDescription())\n\t\t\t.containsPattern(\"The bean is of type '\" + AsyncBean.class.getPackage().getName() + \".\\\\$Proxy.*'\");\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(String.format(\"and implements:%n\\t\") + SomeInterface.class.getName());\n\t\tassertThat(analysis.getDescription()).contains(\"Expected a bean of type '\" + AsyncBean.class.getName() + \"'\");\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(String.format(\"which implements:%n\\t\") + SomeInterface.class.getName());\n\t}\n\n\tprivate FailureAnalysis performAnalysis(Class<?> configuration) {\n\t\tFailureAnalysis analysis = this.analyzer.analyze(createFailure(configuration));\n\t\tassertThat(analysis).isNotNull();\n\t\treturn analysis;\n\t}\n\n\tprivate Exception createFailure(Class<?> configuration) {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(configuration)) {\n\t\t\tfail(\"Expected failure did not occur\");\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAsync\n\t@Import(UserConfiguration.class)\n\tstatic class JdkProxyConfiguration {\n\n\t\t@Bean\n\t\tAsyncBean asyncBean() {\n\t\t\treturn new AsyncBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserConfiguration {\n\n\t\t@Bean\n\t\tAsyncBeanUser user(AsyncBean bean) {\n\t\t\treturn new AsyncBeanUser(bean);\n\t\t}\n\n\t}\n\n\tstatic class AsyncBean implements SomeInterface {\n\n\t\t@Async\n\t\tvoid foo() {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void bar() {\n\n\t\t}\n\n\t}\n\n\tinterface SomeInterface {\n\n\t\tvoid bar();\n\n\t}\n\n\tstatic class AsyncBeanUser {\n\n\t\tAsyncBeanUser(AsyncBean asyncBean) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport jakarta.validation.constraints.Min;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.validation.annotation.Validated;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BindFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass BindFailureAnalyzerTests {\n\n\t@Test\n\tvoid analysisForUnboundElementsIsNull() {\n\t\tFailureAnalysis analysis = performAnalysis(UnboundElementsFailureConfiguration.class,\n\t\t\t\t\"test.foo.listValue[0]=hello\", \"test.foo.listValue[2]=world\");\n\t\tassertThat(analysis).isNull();\n\t}\n\n\t@Test\n\tvoid analysisForValidationExceptionIsNull() {\n\t\tFailureAnalysis analysis = performAnalysis(FieldValidationFailureConfiguration.class, \"test.foo.value=1\");\n\t\tassertThat(analysis).isNull();\n\t}\n\n\t@Test\n\tvoid bindExceptionDueToOtherFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(GenericFailureConfiguration.class, \"test.foo.value=alpha\");\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(failure(\"test.foo.value\", \"alpha\",\n\t\t\t\t\"\\\"test.foo.value\\\" from property source \\\"test\\\"\", \"failed to convert java.lang.String to int\"));\n\t}\n\n\t@Test\n\tvoid bindExceptionForUnknownValueInEnumListsValidValuesInAction() {\n\t\tFailureAnalysis analysis = performAnalysis(EnumFailureConfiguration.class, \"test.foo.fruit=apple,strawberry\");\n\t\tassertThat(analysis).isNotNull();\n\t\tfor (Fruit fruit : Fruit.values()) {\n\t\t\tassertThat(analysis.getAction()).contains(fruit.name());\n\t\t}\n\t}\n\n\t@Test\n\tvoid bindExceptionWithNestedFailureShouldDisplayNestedMessage() {\n\t\tFailureAnalysis analysis = performAnalysis(NestedFailureConfiguration.class, \"test.foo.value=hello\");\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(failure(\"test.foo.value\", \"hello\",\n\t\t\t\t\"\\\"test.foo.value\\\" from property source \\\"test\\\"\", \"java.lang.RuntimeException: This is a failure\"));\n\t}\n\n\t@Test // gh-27028\n\tvoid bindExceptionDueToClassNotFoundConversionFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(GenericFailureConfiguration.class,\n\t\t\t\t\"test.foo.type=com.example.Missing\");\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(failure(\"test.foo.type\", \"com.example.Missing\",\n\t\t\t\t\"\\\"test.foo.type\\\" from property source \\\"test\\\"\",\n\t\t\t\t\"failed to convert java.lang.String to java.lang.Class<?> (caused by java.lang.ClassNotFoundException: com.example.Missing\"));\n\t}\n\n\t@Test\n\tvoid bindExceptionDueToMapConversionFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(LoggingLevelFailureConfiguration.class, \"logging.level=debug\");\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(failure(\"logging.level\", \"debug\",\n\t\t\t\t\"\\\"logging.level\\\" from property source \\\"test\\\"\",\n\t\t\t\t\"org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting \"\n\t\t\t\t\t\t+ \"from type [java.lang.String] to type [java.util.Map<java.lang.String, \"\n\t\t\t\t\t\t+ \"org.springframework.boot.logging.LogLevel>]\"));\n\t}\n\n\t@Test\n\tvoid bindExceptionWithSuppressedMissingParametersException() {\n\t\tBeanCreationException failure = createFailure(GenericFailureConfiguration.class, \"test.foo.value=alpha\");\n\t\tassertThat(failure).isNotNull();\n\t\tfailure.addSuppressed(new IllegalStateException(\n\t\t\t\t\"Missing parameter names. Ensure that the compiler uses the '-parameters' flag\"));\n\t\tFailureAnalysis analysis = new BindFailureAnalyzer().analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(failure(\"test.foo.value\", \"alpha\", \"\\\"test.foo.value\\\" from property source \\\"test\\\"\",\n\t\t\t\t\t\"failed to convert java.lang.String to int\"))\n\t\t\t.contains(MissingParameterNamesFailureAnalyzer.POSSIBILITY);\n\t\tassertThat(analysis.getAction()).contains(MissingParameterNamesFailureAnalyzer.ACTION);\n\t}\n\n\tprivate static String failure(String property, String value, String origin, String reason) {\n\t\treturn String.format(\"Property: %s%n    Value: \\\"%s\\\"%n    Origin: %s%n    Reason: %s\", property, value, origin,\n\t\t\t\treason);\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(Class<?> configuration, String... environment) {\n\t\tBeanCreationException failure = createFailure(configuration, environment);\n\t\tassertThat(failure).isNotNull();\n\t\treturn new BindFailureAnalyzer().analyze(failure);\n\t}\n\n\tprivate @Nullable BeanCreationException createFailure(Class<?> configuration, String... environment) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\taddEnvironment(context, environment);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\treturn null;\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate void addEnvironment(AnnotationConfigApplicationContext context, String[] environment) {\n\t\tMutablePropertySources sources = context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tfor (String pair : environment) {\n\t\t\tint index = pair.indexOf('=');\n\t\t\tString key = (index > 0) ? pair.substring(0, index) : pair;\n\t\t\tString value = (index > 0) ? pair.substring(index + 1) : \"\";\n\t\t\tmap.put(key.trim(), value.trim());\n\t\t}\n\t\tsources.addFirst(new MapPropertySource(\"test\", map));\n\t}\n\n\t@EnableConfigurationProperties(BindValidationFailureAnalyzerTests.FieldValidationFailureProperties.class)\n\tstatic class FieldValidationFailureConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(UnboundElementsFailureProperties.class)\n\tstatic class UnboundElementsFailureConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(GenericFailureProperties.class)\n\tstatic class GenericFailureConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(EnumFailureProperties.class)\n\tstatic class EnumFailureConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(NestedFailureProperties.class)\n\tstatic class NestedFailureConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(LoggingProperties.class)\n\tstatic class LoggingLevelFailureConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\t@Validated\n\tstatic class FieldValidationFailureProperties {\n\n\t\t@Min(value = 5, message = \"at least five\")\n\t\tprivate int value;\n\n\t\tint getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\tstatic class UnboundElementsFailureProperties {\n\n\t\tprivate @Nullable List<String> listValue;\n\n\t\t@Nullable List<String> getListValue() {\n\t\t\treturn this.listValue;\n\t\t}\n\n\t\tvoid setListValue(@Nullable List<String> listValue) {\n\t\t\tthis.listValue = listValue;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\tstatic class GenericFailureProperties {\n\n\t\tprivate int value;\n\n\t\tprivate @Nullable Class<?> type;\n\n\t\tint getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Nullable Class<?> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tvoid setType(@Nullable Class<?> type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\tstatic class EnumFailureProperties {\n\n\t\tprivate @Nullable Set<Fruit> fruit;\n\n\t\t@Nullable Set<Fruit> getFruit() {\n\t\t\treturn this.fruit;\n\t\t}\n\n\t\tvoid setFruit(@Nullable Set<Fruit> fruit) {\n\t\t\tthis.fruit = fruit;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\tstatic class NestedFailureProperties {\n\n\t\tprivate @Nullable String value;\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthrow new RuntimeException(\"This is a failure\");\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"logging\")\n\tstatic class LoggingProperties {\n\n\t\tprivate Map<String, LogLevel> level = new HashMap<>();\n\n\t\tMap<String, LogLevel> getLevel() {\n\t\t\treturn this.level;\n\t\t}\n\n\t\tvoid setLevel(Map<String, LogLevel> level) {\n\t\t\tthis.level = level;\n\t\t}\n\n\t}\n\n\tenum Fruit {\n\n\t\tAPPLE, BANANA, ORANGE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/BindValidationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport jakarta.validation.Valid;\nimport jakarta.validation.constraints.Min;\nimport jakarta.validation.constraints.NotNull;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.validation.BindException;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.annotation.Validated;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BindValidationFailureAnalyzer}.\n *\n * @author Madhura Bhave\n */\nclass BindValidationFailureAnalyzerTests {\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tLocaleContextHolder.setLocale(Locale.US);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tLocaleContextHolder.resetLocaleContext();\n\t}\n\n\t@Test\n\tvoid bindExceptionWithFieldErrorsDueToValidationFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(FieldValidationFailureConfiguration.class);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(failure(\"test.foo.foo\", \"null\", \"must not be null\"))\n\t\t\t.contains(failure(\"test.foo.value\", \"0\", \"at least five\"))\n\t\t\t.contains(failure(\"test.foo.nested.bar\", \"null\", \"must not be null\"))\n\t\t\t.contains(\n\t\t\t\t\t\"Binding to target org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzerTests$FieldValidationFailureProperties failed:\");\n\t}\n\n\t@Test\n\tvoid bindExceptionWithOriginDueToValidationFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(FieldValidationFailureConfiguration.class, \"test.foo.value=4\");\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\"Origin: \\\"test.foo.value\\\" from property source \\\"test\\\"\");\n\t}\n\n\t@Test\n\tvoid bindExceptionWithObjectErrorsDueToValidationFailure() {\n\t\tFailureAnalysis analysis = performAnalysis(ObjectValidationFailureConfiguration.class);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\"Reason: This object could not be bound.\");\n\t}\n\n\t@Test\n\tvoid otherBindExceptionShouldReturnAnalysis() {\n\t\tBindException cause = new BindException(new FieldValidationFailureProperties(),\n\t\t\t\t\"fieldValidationFailureProperties\");\n\t\tcause.addError(new FieldError(\"test\", \"value\", \"must not be null\"));\n\t\tBeanCreationException rootFailure = new BeanCreationException(\"bean creation failure\", cause);\n\t\tFailureAnalysis analysis = new BindValidationFailureAnalyzer().analyze(rootFailure, rootFailure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(failure(\"test.value\", \"null\", \"must not be null\"));\n\t}\n\n\tprivate static String failure(String property, String value, String reason) {\n\t\treturn String.format(\"Property: %s%n    Value: \\\"%s\\\"%n    Reason: %s\", property, value, reason);\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(Class<?> configuration, String... environment) {\n\t\tBeanCreationException failure = createFailure(configuration, environment);\n\t\tassertThat(failure).isNotNull();\n\t\treturn new BindValidationFailureAnalyzer().analyze(failure);\n\t}\n\n\tprivate @Nullable BeanCreationException createFailure(Class<?> configuration, String... environment) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\taddEnvironment(context, environment);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\treturn null;\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate void addEnvironment(AnnotationConfigApplicationContext context, String[] environment) {\n\t\tMutablePropertySources sources = context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tfor (String pair : environment) {\n\t\t\tint index = pair.indexOf('=');\n\t\t\tString key = (index > 0) ? pair.substring(0, index) : pair;\n\t\t\tString value = (index > 0) ? pair.substring(index + 1) : \"\";\n\t\t\tmap.put(key.trim(), value.trim());\n\t\t}\n\t\tsources.addFirst(new MapPropertySource(\"test\", map));\n\t}\n\n\t@EnableConfigurationProperties(FieldValidationFailureProperties.class)\n\tstatic class FieldValidationFailureConfiguration {\n\n\t}\n\n\t@EnableConfigurationProperties(ObjectErrorFailureProperties.class)\n\tstatic class ObjectValidationFailureConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\t@Validated\n\tstatic class FieldValidationFailureProperties {\n\n\t\t@NotNull\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String foo;\n\n\t\t@Min(value = 5, message = \"at least five\")\n\t\tprivate int value;\n\n\t\t@Valid\n\t\tprivate FieldValidationFailureProperties.Nested nested = new FieldValidationFailureProperties.Nested();\n\n\t\tString getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tvoid setFoo(String foo) {\n\t\t\tthis.foo = foo;\n\t\t}\n\n\t\tint getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tFieldValidationFailureProperties.Nested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tvoid setNested(FieldValidationFailureProperties.Nested nested) {\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tstatic class Nested {\n\n\t\t\t@NotNull\n\t\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\t\tprivate String bar;\n\n\t\t\tString getBar() {\n\t\t\t\treturn this.bar;\n\t\t\t}\n\n\t\t\tvoid setBar(String bar) {\n\t\t\t\tthis.bar = bar;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"foo.bar\")\n\t@Validated\n\tstatic class ObjectErrorFailureProperties implements Validator {\n\n\t\t@Override\n\t\tpublic void validate(Object target, Errors errors) {\n\t\t\terrors.reject(\"my.objectError\", \"This object could not be bound.\");\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supports(Class<?> type) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyNameFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InvalidConfigurationPropertyNameFailureAnalyzer}.\n *\n * @author Madhura Bhave\n */\nclass InvalidConfigurationPropertyNameFailureAnalyzerTests {\n\n\tprivate final InvalidConfigurationPropertyNameFailureAnalyzer analyzer = new InvalidConfigurationPropertyNameFailureAnalyzer();\n\n\t@Test\n\tvoid analysisWhenRootCauseIsBeanCreationFailureShouldContainBeanName() {\n\t\tBeanCreationException failure = createFailure(InvalidPrefixConfiguration.class);\n\t\tassertThat(failure).isNotNull();\n\t\tFailureAnalysis analysis = this.analyzer.analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(String.format(\"%n    Invalid characters: %s%n    Bean: %s%n    Reason: %s\", \"'F', 'P'\",\n\t\t\t\t\t\"invalidPrefixProperties\", \"Canonical names should be kebab-case ('-' separated), \"\n\t\t\t\t\t\t\t+ \"lowercase alpha-numeric characters and must start with a letter\"));\n\t}\n\n\tprivate @Nullable BeanCreationException createFailure(Class<?> configuration) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\treturn null;\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(InvalidPrefixProperties.class)\n\tstatic class InvalidPrefixConfiguration {\n\n\t\t@Bean(name = \"invalidPrefixProperties\")\n\t\tInvalidPrefixProperties invalidPrefixProperties() {\n\t\t\treturn new InvalidPrefixProperties();\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"FooPrefix\")\n\tstatic class InvalidPrefixProperties {\n\n\t\tprivate @Nullable String value;\n\n\t\t@Nullable String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tvoid setValue(@Nullable String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/InvalidConfigurationPropertyValueFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.ObjectUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InvalidConfigurationPropertyValueFailureAnalyzer}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass InvalidConfigurationPropertyValueFailureAnalyzerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\tvoid analysisWithNullEnvironment() {\n\t\tInvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException(\n\t\t\t\t\"test.property\", \"invalid\", \"This is not valid.\");\n\t\tFailureAnalysis analysis = new InvalidConfigurationPropertyValueFailureAnalyzer(null).analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(\"Invalid value 'invalid' for configuration property 'test.property'.\");\n\t}\n\n\t@Test\n\tvoid analysisWithKnownProperty() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.singletonMap(\"test.property\", \"invalid\"));\n\t\tthis.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source));\n\t\tInvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException(\n\t\t\t\t\"test.property\", \"invalid\", \"This is not valid.\");\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertCommonParts(failure, analysis);\n\t\tassertThat(analysis.getAction()).contains(\"Review the value of the property with the provided reason.\");\n\t\tassertThat(analysis.getDescription()).contains(\"Validation failed for the following reason\")\n\t\t\t.contains(\"This is not valid.\")\n\t\t\t.doesNotContain(\"Additionally, this property is also set\");\n\t}\n\n\t@Test\n\tvoid analysisWithKnownPropertyFromSystemEnvironment() {\n\t\tMapPropertySource source = new SystemEnvironmentPropertySource(\"systemEnvironment\",\n\t\t\t\tCollections.singletonMap(\"COM_EXAMPLE_TESTPROPERTY\", \"invalid\"));\n\t\tthis.environment.getPropertySources().addFirst(source);\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tassertThat(this.environment.getProperty(\"com.example.test-property\")).isEqualTo(\"invalid\");\n\t\tInvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException(\n\t\t\t\t\"com.example.test-property\", \"invalid\", \"This is not valid.\");\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\"com.example.test-property\")\n\t\t\t.contains(\"invalid\")\n\t\t\t.contains(\"property source \\\"systemEnvironment\\\"\");\n\t\tassertThat(analysis.getCause()).isSameAs(failure);\n\t\tassertThat(analysis.getAction()).contains(\"Review the value of the property with the provided reason.\");\n\t\tassertThat(analysis.getDescription()).contains(\"Validation failed for the following reason\")\n\t\t\t.contains(\"This is not valid.\")\n\t\t\t.doesNotContain(\"Additionally, this property is also set\");\n\t}\n\n\t@Test\n\tvoid analysisWithKnownPropertyAndNoReason() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.singletonMap(\"test.property\", \"invalid\"));\n\t\tthis.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source));\n\t\tInvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException(\n\t\t\t\t\"test.property\", \"invalid\", null);\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getAction()).contains(\"Review the value of the property.\");\n\t\tassertThat(analysis.getDescription()).contains(\"No reason was provided.\")\n\t\t\t.doesNotContain(\"Additionally, this property is also set\");\n\t}\n\n\t@Test\n\tvoid analysisWithKnownPropertyAndOtherCandidates() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.singletonMap(\"test.property\", \"invalid\"));\n\t\tMapPropertySource additional = new MapPropertySource(\"additional\",\n\t\t\t\tCollections.singletonMap(\"test.property\", \"valid\"));\n\t\tMapPropertySource another = new MapPropertySource(\"another\", Collections.singletonMap(\"test.property\", \"test\"));\n\t\tthis.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source));\n\t\tthis.environment.getPropertySources().addLast(additional);\n\t\tthis.environment.getPropertySources().addLast(OriginCapablePropertySource.get(another));\n\t\tthis.environment.getPropertySources().addLast(OriginCapablePropertySource.get(\"another-again\", another));\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tInvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException(\n\t\t\t\t\"test.property\", \"invalid\", \"This is not valid.\");\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertCommonParts(failure, analysis);\n\t\tassertThat(analysis.getAction()).contains(\"Review the value of the property with the provided reason.\");\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(\"Additionally, this property is also set in the following property sources:\")\n\t\t\t.contains(\"In 'additional' with the value 'valid'\")\n\t\t\t.contains(\"In 'another' with the value 'test' (originating from 'TestOrigin test.property')\")\n\t\t\t.doesNotContain(\"another-again\");\n\t}\n\n\t@Test\n\tvoid analysisWithUnknownKey() {\n\t\tInvalidConfigurationPropertyValueException failure = new InvalidConfigurationPropertyValueException(\n\t\t\t\t\"test.key.not.defined\", \"invalid\", \"This is not valid.\");\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(\"Invalid value 'invalid' for configuration property 'test.key.not.defined'.\");\n\t}\n\n\tprivate void assertCommonParts(InvalidConfigurationPropertyValueException failure, FailureAnalysis analysis) {\n\t\tassertThat(analysis.getDescription()).contains(\"test.property\")\n\t\t\t.contains(\"invalid\")\n\t\t\t.contains(\"TestOrigin test.property\");\n\t\tassertThat(analysis.getCause()).isSameAs(failure);\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(InvalidConfigurationPropertyValueException failure) {\n\t\tInvalidConfigurationPropertyValueFailureAnalyzer analyzer = new InvalidConfigurationPropertyValueFailureAnalyzer(\n\t\t\t\tthis.environment);\n\t\treturn analyzer.analyze(failure);\n\t}\n\n\tstatic class OriginCapablePropertySource<T> extends EnumerablePropertySource<T> implements OriginLookup<String> {\n\n\t\tprivate final EnumerablePropertySource<T> propertySource;\n\n\t\tOriginCapablePropertySource(EnumerablePropertySource<T> propertySource) {\n\t\t\tthis(propertySource.getName(), propertySource);\n\t\t}\n\n\t\tOriginCapablePropertySource(String name, EnumerablePropertySource<T> propertySource) {\n\t\t\tsuper(name, propertySource.getSource());\n\t\t\tthis.propertySource = propertySource;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\treturn this.propertySource.getProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getPropertyNames() {\n\t\t\treturn this.propertySource.getPropertyNames();\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String name) {\n\t\t\treturn new TestOrigin(name, this.propertySource.getName());\n\t\t}\n\n\t\tstatic <T> OriginCapablePropertySource<T> get(EnumerablePropertySource<T> propertySource) {\n\t\t\treturn new OriginCapablePropertySource<>(propertySource);\n\t\t}\n\n\t\tstatic <T> OriginCapablePropertySource<T> get(String name, EnumerablePropertySource<T> propertySource) {\n\t\t\treturn new OriginCapablePropertySource<>(name, propertySource);\n\t\t}\n\n\t\tstatic final class TestOrigin implements Origin {\n\n\t\t\tprivate final String name;\n\n\t\t\tprivate final String sourceName;\n\n\t\t\tprivate TestOrigin(String name, String sourceName) {\n\t\t\t\tthis.name = name;\n\t\t\t\tthis.sourceName = sourceName;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean equals(Object obj) {\n\t\t\t\tif (this == obj) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tTestOrigin other = (TestOrigin) obj;\n\t\t\t\treturn ObjectUtils.nullSafeEquals(this.name, other.name)\n\t\t\t\t\t\t&& ObjectUtils.nullSafeEquals(this.sourceName, other.sourceName);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic int hashCode() {\n\t\t\t\treturn ObjectUtils.nullSafeHashCode(this.name);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\treturn \"TestOrigin \" + this.name;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/JakartaApiValidationExceptionFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.validation.annotation.Validated;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Tests for {@link ValidationExceptionFailureAnalyzer}\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"hibernate-validator-*.jar\")\nclass JakartaApiValidationExceptionFailureAnalyzerTests {\n\n\t@Test\n\tvoid validatedPropertiesTest() {\n\t\tassertThatException().isThrownBy(() -> new AnnotationConfigApplicationContext(TestConfiguration.class).close())\n\t\t\t.satisfies((ex) -> assertThat(new ValidationExceptionFailureAnalyzer().analyze(ex)).isNotNull());\n\t}\n\n\t@Test\n\tvoid nonValidatedPropertiesTest() {\n\t\tnew AnnotationConfigApplicationContext(NonValidatedTestConfiguration.class).close();\n\t}\n\n\t@EnableConfigurationProperties(TestProperties.class)\n\tstatic class TestConfiguration {\n\n\t\tTestConfiguration(TestProperties testProperties) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\t@Validated\n\tstatic class TestProperties {\n\n\t}\n\n\t@EnableConfigurationProperties(NonValidatedTestProperties.class)\n\tstatic class NonValidatedTestConfiguration {\n\n\t\tNonValidatedTestConfiguration(NonValidatedTestProperties testProperties) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class NonValidatedTestProperties {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MissingParameterNamesFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.web.context.request.NativeWebRequest;\nimport org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MissingParameterNamesFailureAnalyzer}.\n *\n * @author Phillip Webb\n */\nclass MissingParameterNamesFailureAnalyzerTests {\n\n\t@Test\n\tvoid analyzeWhenMissingParametersExceptionReturnsFailure() throws Exception {\n\t\tMissingParameterNamesFailureAnalyzer analyzer = new MissingParameterNamesFailureAnalyzer();\n\t\tFailureAnalysis analysis = analyzer.analyze(getSpringFrameworkMissingParameterException());\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.isEqualTo(String.format(\"Name for argument of type [java.lang.String] not specified, and parameter name \"\n\t\t\t\t\t+ \"information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n\"));\n\t\tassertThat(analysis.getAction()).isEqualTo(MissingParameterNamesFailureAnalyzer.ACTION);\n\t}\n\n\t@Test\n\tvoid analyzeForMissingParametersWhenMissingParametersExceptionReturnsFailure() throws Exception {\n\t\tFailureAnalysis analysis = MissingParameterNamesFailureAnalyzer\n\t\t\t.analyzeForMissingParameters(getSpringFrameworkMissingParameterException());\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.isEqualTo(String.format(\"Name for argument of type [java.lang.String] not specified, and parameter name \"\n\t\t\t\t\t+ \"information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n\"));\n\t\tassertThat(analysis.getAction()).isEqualTo(MissingParameterNamesFailureAnalyzer.ACTION);\n\t}\n\n\t@Test\n\tvoid analyzeForMissingParametersWhenInCauseReturnsFailure() throws Exception {\n\t\tRuntimeException exception = new RuntimeException(\"Badness\", getSpringFrameworkMissingParameterException());\n\t\tFailureAnalysis analysis = MissingParameterNamesFailureAnalyzer.analyzeForMissingParameters(exception);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.isEqualTo(String.format(\"Name for argument of type [java.lang.String] not specified, and parameter name \"\n\t\t\t\t\t+ \"information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n%n\"\n\t\t\t\t\t+ \"    Resulting Failure: java.lang.RuntimeException: Badness\"));\n\t\tassertThat(analysis.getAction()).isEqualTo(MissingParameterNamesFailureAnalyzer.ACTION);\n\t}\n\n\t@Test\n\tvoid analyzeForMissingParametersWhenInSuppressedReturnsFailure() throws Exception {\n\t\tRuntimeException exception = new RuntimeException(\"Badness\");\n\t\texception.addSuppressed(getSpringFrameworkMissingParameterException());\n\t\tFailureAnalysis analysis = MissingParameterNamesFailureAnalyzer.analyzeForMissingParameters(exception);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.isEqualTo(String.format(\"Name for argument of type [java.lang.String] not specified, and parameter name \"\n\t\t\t\t\t+ \"information not available via reflection. Ensure that the compiler uses the '-parameters' flag.:%n%n\"\n\t\t\t\t\t+ \"    Resulting Failure: java.lang.RuntimeException: Badness\"));\n\t\tassertThat(analysis.getAction()).isEqualTo(MissingParameterNamesFailureAnalyzer.ACTION);\n\t}\n\n\t@Test\n\tvoid analyzeForMissingParametersWhenNotPresentReturnsNull() {\n\t\tRuntimeException exception = new RuntimeException(\"Badness\");\n\t\tFailureAnalysis analysis = MissingParameterNamesFailureAnalyzer.analyzeForMissingParameters(exception);\n\t\tassertThat(analysis).isNull();\n\t}\n\n\tprivate RuntimeException getSpringFrameworkMissingParameterException() throws Exception {\n\t\tMockResolver resolver = new MockResolver();\n\t\tMethod method = getClass().getDeclaredMethod(\"example\", String.class);\n\t\tMethodParameter parameter = new MethodParameter(method, 0);\n\t\tparameter.initParameterNameDiscovery(null);\n\t\ttry {\n\t\t\tresolver.resolveArgument(parameter, null, mock(NativeWebRequest.class), null);\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\treturn ex;\n\t\t}\n\t\tthrow new AssertionError(\"Did not throw\");\n\t}\n\n\tvoid example(String name) {\n\t}\n\n\tstatic class MockResolver extends AbstractNamedValueMethodArgumentResolver {\n\n\t\t@Override\n\t\tpublic boolean supportsParameter(MethodParameter parameter) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tprotected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {\n\t\t\treturn new NamedValueInfo(\"\", false, null);\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable Object resolveName(String name, MethodParameter parameter, NativeWebRequest request)\n\t\t\t\tthrows Exception {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MutuallyExclusiveConfigurationPropertiesFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass MutuallyExclusiveConfigurationPropertiesFailureAnalyzerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\tvoid analyzeWhenEnvironmentIsNullShouldReturnNull() {\n\t\tMutuallyExclusiveConfigurationPropertiesException failure = new MutuallyExclusiveConfigurationPropertiesException(\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")),\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")));\n\t\tFailureAnalysis failureAnalysis = new MutuallyExclusiveConfigurationPropertiesFailureAnalyzer(null)\n\t\t\t.analyze(failure);\n\t\tassertThat(failureAnalysis).isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenNotAllPropertiesAreInTheEnvironmentShouldReturnNull() {\n\t\tMapPropertySource source = new MapPropertySource(\"test\", Collections.singletonMap(\"com.example.a\", \"alpha\"));\n\t\tthis.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source));\n\t\tMutuallyExclusiveConfigurationPropertiesException failure = new MutuallyExclusiveConfigurationPropertiesException(\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")),\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")));\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenAllConfiguredPropertiesAreInTheEnvironmentShouldReturnAnalysis() {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"com.example.a\", \"alpha\");\n\t\tproperties.put(\"com.example.b\", \"bravo\");\n\t\tMapPropertySource source = new MapPropertySource(\"test\", properties);\n\t\tthis.environment.getPropertySources().addFirst(OriginCapablePropertySource.get(source));\n\t\tMutuallyExclusiveConfigurationPropertiesException failure = new MutuallyExclusiveConfigurationPropertiesException(\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")),\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")));\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getAction()).isEqualTo(\n\t\t\t\t\"Update your configuration so that only one of the mutually exclusive properties is configured.\");\n\t\tassertThat(analysis.getDescription()).contains(String.format(\n\t\t\t\t\"The following configuration properties are mutually exclusive:%n%n\\tcom.example.a%n\\tcom.example.b%n\"))\n\t\t\t.contains(\n\t\t\t\t\tString.format(\"However, more than one of those properties has been configured at the same time:%n%n\"\n\t\t\t\t\t\t\t+ \"\\tcom.example.a (originating from 'TestOrigin test')%n\"\n\t\t\t\t\t\t\t+ \"\\tcom.example.b (originating from 'TestOrigin test')%n\"));\n\t}\n\n\t@Test\n\tvoid analyzeWhenPropertyIsInMultiplePropertySourcesShouldListEachSourceInAnalysis() {\n\t\tMap<String, Object> properties = new LinkedHashMap<>();\n\t\tproperties.put(\"com.example.a\", \"alpha\");\n\t\tproperties.put(\"com.example.b\", \"bravo\");\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(OriginCapablePropertySource.get(new MapPropertySource(\"test-one\", properties)));\n\t\tthis.environment.getPropertySources()\n\t\t\t.addLast(OriginCapablePropertySource.get(new MapPropertySource(\"test-two\", properties)));\n\t\tMutuallyExclusiveConfigurationPropertiesException failure = new MutuallyExclusiveConfigurationPropertiesException(\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")),\n\t\t\t\tnew HashSet<>(Arrays.asList(\"com.example.a\", \"com.example.b\")));\n\t\tFailureAnalysis analysis = performAnalysis(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getAction()).isEqualTo(\n\t\t\t\t\"Update your configuration so that only one of the mutually exclusive properties is configured.\");\n\t\tassertThat(analysis.getDescription()).contains(String.format(\n\t\t\t\t\"The following configuration properties are mutually exclusive:%n%n\\tcom.example.a%n\\tcom.example.b%n\"))\n\t\t\t.contains(\n\t\t\t\t\tString.format(\"However, more than one of those properties has been configured at the same time:%n%n\"\n\t\t\t\t\t\t\t+ \"\\tcom.example.a (originating from 'TestOrigin test-one')%n\"\n\t\t\t\t\t\t\t+ \"\\tcom.example.a (originating from 'TestOrigin test-two')%n\"\n\t\t\t\t\t\t\t+ \"\\tcom.example.b (originating from 'TestOrigin test-one')%n\"\n\t\t\t\t\t\t\t+ \"\\tcom.example.b (originating from 'TestOrigin test-two')%n\"));\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(MutuallyExclusiveConfigurationPropertiesException failure) {\n\t\tMutuallyExclusiveConfigurationPropertiesFailureAnalyzer analyzer = new MutuallyExclusiveConfigurationPropertiesFailureAnalyzer(\n\t\t\t\tthis.environment);\n\t\treturn analyzer.analyze(failure);\n\t}\n\n\tstatic class OriginCapablePropertySource<T> extends EnumerablePropertySource<T> implements OriginLookup<String> {\n\n\t\tprivate final EnumerablePropertySource<T> propertySource;\n\n\t\tOriginCapablePropertySource(EnumerablePropertySource<T> propertySource) {\n\t\t\tsuper(propertySource.getName(), propertySource.getSource());\n\t\t\tthis.propertySource = propertySource;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\treturn this.propertySource.getProperty(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getPropertyNames() {\n\t\t\treturn this.propertySource.getPropertyNames();\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String name) {\n\t\t\treturn new Origin() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String toString() {\n\t\t\t\t\treturn \"TestOrigin \" + getName();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\tstatic <T> OriginCapablePropertySource<T> get(EnumerablePropertySource<T> propertySource) {\n\t\t\treturn new OriginCapablePropertySource<>(propertySource);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer.ClassDescriptor;\nimport org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer.NoSuchMethodDescriptor;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.data.r2dbc.mapping.R2dbcMappingContext;\nimport org.springframework.util.MimeType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoSuchMethodFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\n@ClassPathOverrides({ \"org.springframework:spring-core:5.3.12\",\n\t\t\"org.springframework.data:spring-data-relational:1.1.7.RELEASE\",\n\t\t\"org.springframework.data:spring-data-r2dbc:3.4.7\" })\nclass NoSuchMethodFailureAnalyzerTests {\n\n\t@Test\n\tvoid parseHotspotErrorMessage() {\n\t\tNoSuchMethodDescriptor descriptor = new NoSuchMethodFailureAnalyzer().getNoSuchMethodDescriptor(\n\t\t\t\t\"'boolean org.springframework.util.MimeType.isMoreSpecific(org.springframework.util.MimeType)'\");\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getErrorMessage())\n\t\t\t.isEqualTo(\"'boolean org.springframework.util.MimeType.isMoreSpecific(org.springframework.util.MimeType)'\");\n\t\tassertThat(descriptor.getClassName()).isEqualTo(\"org.springframework.util.MimeType\");\n\t\tassertThat(descriptor.getCandidateLocations()).hasSizeGreaterThan(1);\n\t\tList<ClassDescriptor> typeHierarchy = descriptor.getTypeHierarchy();\n\t\tassertThat(typeHierarchy).hasSize(1);\n\t\tassertThat(typeHierarchy.get(0).getLocation()).asString().contains(\"spring-core-5.3.12.jar\");\n\t}\n\n\t@Test\n\tvoid parseOpenJ9ErrorMessage() {\n\t\tNoSuchMethodDescriptor descriptor = new NoSuchMethodFailureAnalyzer().getNoSuchMethodDescriptor(\n\t\t\t\t\"org/springframework/util/MimeType.isMoreSpecific(Lorg/springframework/util/MimeType;)Z \"\n\t\t\t\t\t\t+ \"(loaded from ...) \"\n\t\t\t\t\t\t+ \"called from class org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzerTests \"\n\t\t\t\t\t\t+ \"(loaded from ... \"\n\t\t\t\t\t\t+ \"by org.springframework.boot.testsupport.classpath.ModifiedClassPathClassLoader@e0ce6310).\");\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getErrorMessage())\n\t\t\t.isEqualTo(\"org/springframework/util/MimeType.isMoreSpecific(Lorg/springframework/util/MimeType;)Z\");\n\t\tassertThat(descriptor.getClassName()).isEqualTo(\"org.springframework.util.MimeType\");\n\t\tassertThat(descriptor.getCandidateLocations()).hasSizeGreaterThan(1);\n\t\tList<ClassDescriptor> typeHierarchy = descriptor.getTypeHierarchy();\n\t\tassertThat(typeHierarchy).hasSize(1);\n\t\tassertThat(typeHierarchy.get(0).getLocation()).asString().contains(\"spring-core-5.3.12.jar\");\n\t}\n\n\t@Test\n\tvoid whenAMethodOnAClassIsMissingThenNoSuchMethodErrorIsAnalyzed() {\n\t\tThrowable failure = createFailureForMissingMethod();\n\t\tFailureAnalysis analysis = new NoSuchMethodFailureAnalyzer().analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(NoSuchMethodFailureAnalyzerTests.class.getName() + \".createFailureForMissingMethod(\")\n\t\t\t.contains(\"isMoreSpecific(\")\n\t\t\t.contains(\"calling method's class, \" + NoSuchMethodFailureAnalyzerTests.class.getName() + \",\")\n\t\t\t.contains(\"called method's class, org.springframework.util.MimeType,\");\n\t\tassertThat(analysis.getAction()).contains(NoSuchMethodFailureAnalyzerTests.class.getName())\n\t\t\t.contains(\"org.springframework.util.MimeType\");\n\t}\n\n\t@Test\n\tvoid whenAnInheritedMethodIsMissingThenNoSuchMethodErrorIsAnalyzed() {\n\t\tThrowable failure = createFailureForMissingInheritedMethod();\n\t\tFailureAnalysis analysis = new NoSuchMethodFailureAnalyzer().analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(R2dbcMappingContext.class.getName() + \".<init>(\")\n\t\t\t.contains(R2dbcMappingContext.class.getName() + \".setForceQuote(\")\n\t\t\t.contains(\"calling method's class, org.springframework.data.r2dbc.mapping.R2dbcMappingContext,\")\n\t\t\t.contains(\"called method's class, org.springframework.data.r2dbc.mapping.R2dbcMappingContext,\")\n\t\t\t.contains(\"    org.springframework.data.r2dbc.mapping.R2dbcMappingContext\")\n\t\t\t.contains(\"    org.springframework.data.relational.core.mapping.RelationalMappingContext\")\n\t\t\t.contains(\"    org.springframework.data.mapping.context.AbstractMappingContext\");\n\t\tassertThat(analysis.getAction()).contains(\"org.springframework.data.r2dbc.mapping.R2dbcMappingContext\");\n\t}\n\n\t@SuppressWarnings(\"NullAway\") // Deliberately trigger exception\n\tprivate Throwable createFailureForMissingMethod() {\n\t\ttry {\n\t\t\tMimeType mimeType = new MimeType(\"application\", \"json\");\n\t\t\tmimeType.isMoreSpecific(null);\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate Throwable createFailureForMissingInheritedMethod() {\n\t\ttry {\n\t\t\tnew R2dbcMappingContext();\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoUniqueBeanDefinitionFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.NoUniqueBeanDefinitionException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.analyzer.nounique.TestBean;\nimport org.springframework.boot.diagnostics.analyzer.nounique.TestBeanConsumer;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoUniqueBeanDefinitionFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@WithResource(name = \"producer.xml\",\n\t\tcontent = \"\"\"\n\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\t\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t\t\t\t\t<bean class=\"org.springframework.boot.diagnostics.analyzer.nounique.TestBean\" name=\"xmlTestBean\"/>\n\n\t\t\t\t</beans>\n\t\t\t\t\"\"\")\nclass NoUniqueBeanDefinitionFailureAnalyzerTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\tprivate final NoUniqueBeanDefinitionFailureAnalyzer analyzer = new NoUniqueBeanDefinitionFailureAnalyzer(\n\t\t\tthis.context.getBeanFactory());\n\n\t@Test\n\tvoid failureAnalysisForFieldConsumer() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(FieldConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).startsWith(\n\t\t\t\t\"Field testBean in \" + FieldConsumer.class.getName() + \" required a single bean, but 6 were found:\");\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForMethodConsumer() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(MethodConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).startsWith(\"Parameter 0 of method consumer in \"\n\t\t\t\t+ MethodConsumer.class.getName() + \" required a single bean, but 6 were found:\");\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForConstructorConsumer() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(ConstructorConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).startsWith(\"Parameter 0 of constructor in \"\n\t\t\t\t+ ConstructorConsumer.class.getName() + \" required a single bean, but 6 were found:\");\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForObjectProviderMethodConsumer() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(ObjectProviderMethodConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).startsWith(\"Method consumer in \"\n\t\t\t\t+ ObjectProviderMethodConsumer.class.getName() + \" required a single bean, but 6 were found:\");\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\t@WithResource(name = \"consumer.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\t\t\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\t\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t\t\t\t\t\t<bean class=\"org.springframework.boot.diagnostics.analyzer.nounique.TestBeanConsumer\"/>\n\n\t\t\t\t\t</beans>\n\t\t\t\t\t\"\"\")\n\tvoid failureAnalysisForXmlConsumer() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(XmlConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).startsWith(\"Parameter 0 of constructor in \"\n\t\t\t\t+ TestBeanConsumer.class.getName() + \" required a single bean, but 6 were found:\");\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForObjectProviderConstructorConsumer() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(ObjectProviderConstructorConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).startsWith(\"Constructor in \"\n\t\t\t\t+ ObjectProviderConstructorConsumer.class.getName() + \" required a single bean, but 6 were found:\");\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\tvoid failureAnalysisIncludesPossiblyMissingParameterNames() {\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(createFailure(MethodConsumer.class));\n\t\tassertThat(failureAnalysis.getDescription()).contains(MissingParameterNamesFailureAnalyzer.POSSIBILITY);\n\t\tassertThat(failureAnalysis.getAction()).contains(MissingParameterNamesFailureAnalyzer.ACTION);\n\t\tassertFoundBeans(failureAnalysis);\n\t}\n\n\t@Test\n\tvoid failureAnalysisWithoutInjectionPoints() {\n\t\tthis.context.registerBean(\"beanOne\", TestBean.class);\n\t\tthis.context.register(DuplicateBeansProducer.class);\n\t\tthis.context.refresh();\n\t\tFailureAnalysis failureAnalysis = analyzeFailure(new NoUniqueBeanDefinitionException(TestBean.class, 3,\n\t\t\t\t\"no TestBeanProvider specified and expected single matching TestBean but found 3: beanOne,beanTwo,xmlBean\"));\n\t\tassertThat(failureAnalysis.getDescription())\n\t\t\t.startsWith(\"A component required a single bean, but 3 were found:\");\n\t\tassertThat(failureAnalysis.getDescription()).contains(\"beanOne: defined in unknown location\");\n\t\tassertThat(failureAnalysis.getDescription())\n\t\t\t.contains(\"beanTwo: defined by method 'beanTwo' in \" + DuplicateBeansProducer.class.getName());\n\t\tassertThat(failureAnalysis.getDescription()).contains(\"xmlBean: a programmatically registered singleton\");\n\t}\n\n\tprivate BeanCreationException createFailure(Class<?> consumer) {\n\t\tthis.context.registerBean(\"beanOne\", TestBean.class);\n\t\tthis.context.register(DuplicateBeansProducer.class, consumer);\n\t\tthis.context.setParent(new AnnotationConfigApplicationContext(ParentProducer.class));\n\t\ttry {\n\t\t\tthis.context.refresh();\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate FailureAnalysis analyzeFailure(Exception failure) {\n\t\tFailureAnalysis analyze = this.analyzer.analyze(failure);\n\t\tassertThat(analyze).isNotNull();\n\t\treturn analyze;\n\t}\n\n\tprivate void assertFoundBeans(FailureAnalysis analysis) {\n\t\tassertThat(analysis.getDescription()).contains(\"beanOne: defined in unknown location\");\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(\"beanTwo: defined by method 'beanTwo' in \" + DuplicateBeansProducer.class.getName());\n\t\tassertThat(analysis.getDescription())\n\t\t\t.contains(\"beanThree: defined by method 'beanThree' in \" + ParentProducer.class.getName());\n\t\tassertThat(analysis.getDescription()).contains(\"barTestBean\");\n\t\tassertThat(analysis.getDescription()).contains(\"fooTestBean\");\n\t\tassertThat(analysis.getDescription()).contains(\"xmlTestBean\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ComponentScan(basePackageClasses = TestBean.class)\n\t@ImportResource(\"classpath:producer.xml\")\n\tstatic class DuplicateBeansProducer {\n\n\t\t@Bean\n\t\tTestBean beanTwo() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParentProducer {\n\n\t\t@Bean\n\t\tTestBean beanThree() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FieldConsumer {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\t@Autowired\n\t\tprivate TestBean testBean;\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObjectProviderConstructorConsumer {\n\n\t\tObjectProviderConstructorConsumer(ObjectProvider<TestBean> objectProvider) {\n\t\t\tobjectProvider.getIfAvailable();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConstructorConsumer {\n\n\t\tConstructorConsumer(TestBean testBean) {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MethodConsumer {\n\n\t\t@Bean\n\t\tString consumer(TestBean testBean) {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObjectProviderMethodConsumer {\n\n\t\t@Bean\n\t\tString consumer(ObjectProvider<TestBean> testBeanProvider) {\n\t\t\ttestBeanProvider.getIfAvailable();\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportResource(\"classpath:consumer.xml\")\n\tstatic class XmlConsumer {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/PatternParseFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.web.util.pattern.PathPatternParser;\nimport org.springframework.web.util.pattern.PatternParseException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PatternParseFailureAnalyzer}\n *\n * @author Brian Clozel\n */\nclass PatternParseFailureAnalyzerTests {\n\n\tprivate final PathPatternParser parser = new PathPatternParser();\n\n\t@Test\n\tvoid patternParseFailureQuotesPattern() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(\"/spring/**/framework\");\n\t\tassertThat(failureAnalysis.getDescription())\n\t\t\t.contains(\"Invalid mapping pattern detected:\\n\" + \"/spring/**/framework\\n\" + \"        ^\");\n\t\tassertThat(failureAnalysis.getAction())\n\t\t\t.contains(\"Fix this pattern in your application or switch to the legacy parser\"\n\t\t\t\t\t+ \" implementation with 'spring.mvc.pathmatch.matching-strategy=ant_path_matcher'.\");\n\t}\n\n\tprivate FailureAnalysis performAnalysis(String pattern) {\n\t\tPatternParseException failure = createFailure(pattern);\n\t\tFailureAnalysis analyze = new PatternParseFailureAnalyzer().analyze(failure);\n\t\tassertThat(analyze).isNotNull();\n\t\treturn analyze;\n\t}\n\n\tPatternParseException createFailure(String pattern) {\n\t\ttry {\n\t\t\tthis.parser.parse(pattern);\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (PatternParseException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/UnboundConfigurationPropertyFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UnboundConfigurationPropertyFailureAnalyzer}.\n *\n * @author Madhura Bhave\n */\nclass UnboundConfigurationPropertyFailureAnalyzerTests {\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tLocaleContextHolder.setLocale(Locale.US);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tLocaleContextHolder.resetLocaleContext();\n\t}\n\n\t@Test\n\tvoid bindExceptionDueToUnboundElements() {\n\t\tFailureAnalysis analysis = performAnalysis(UnboundElementsFailureConfiguration.class,\n\t\t\t\t\"test.foo.listValue[0]=hello\", \"test.foo.listValue[2]=world\");\n\t\tassertThat(analysis.getDescription()).contains(\n\t\t\t\tfailure(\"test.foo.listvalue[2]\", \"world\", \"\\\"test.foo.listValue[2]\\\" from property source \\\"test\\\"\",\n\t\t\t\t\t\t\"The elements [test.foo.listvalue[2]] were left unbound.\"));\n\t}\n\n\tprivate static String failure(String property, String value, String origin, String reason) {\n\t\treturn String.format(\"Property: %s%n    Value: \\\"%s\\\"%n    Origin: %s%n    Reason: %s\", property, value, origin,\n\t\t\t\treason);\n\t}\n\n\tprivate FailureAnalysis performAnalysis(Class<?> configuration, String... environment) {\n\t\tBeanCreationException failure = createFailure(configuration, environment);\n\t\tFailureAnalysis analyze = new UnboundConfigurationPropertyFailureAnalyzer().analyze(failure);\n\t\tassertThat(analyze).isNotNull();\n\t\treturn analyze;\n\t}\n\n\tprivate BeanCreationException createFailure(Class<?> configuration, String... environment) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\taddEnvironment(context, environment);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate void addEnvironment(AnnotationConfigApplicationContext context, String[] environment) {\n\t\tMutablePropertySources sources = context.getEnvironment().getPropertySources();\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tfor (String pair : environment) {\n\t\t\tint index = pair.indexOf('=');\n\t\t\tString key = (index > 0) ? pair.substring(0, index) : pair;\n\t\t\tString value = (index > 0) ? pair.substring(index + 1) : \"\";\n\t\t\tmap.put(key.trim(), value.trim());\n\t\t}\n\t\tsources.addFirst(new MapPropertySource(\"test\", map));\n\t}\n\n\t@EnableConfigurationProperties(UnboundElementsFailureProperties.class)\n\tstatic class UnboundElementsFailureConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test.foo\")\n\tstatic class UnboundElementsFailureProperties {\n\n\t\tprivate @Nullable List<String> listValue;\n\n\t\t@Nullable List<String> getListValue() {\n\t\t\treturn this.listValue;\n\t\t}\n\n\t\tvoid setListValue(@Nullable List<String> listValue) {\n\t\t\tthis.listValue = listValue;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/nounique/BarTestBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer.nounique;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class BarTestBean extends TestBean {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/nounique/FooTestBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer.nounique;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class FooTestBean extends TestBean {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/nounique/TestBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer.nounique;\n\npublic class TestBean {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/nounique/TestBeanConsumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.diagnostics.analyzer.nounique;\n\npublic class TestBeanConsumer {\n\n\tTestBeanConsumer(TestBean testBean) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/nounique/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.diagnostics.analyzer.nounique;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/ConfigTreePropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.env.ConfigTreePropertySource.Option;\nimport org.springframework.boot.env.ConfigTreePropertySource.Value;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ConfigTreePropertySource}.\n *\n * @author Phillip Webb\n */\nclass ConfigTreePropertySourceTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath directory;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource(null, this.directory))\n\t\t\t.withMessageContaining(\"name must contain\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSourceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource(\"test\", null))\n\t\t\t.withMessage(\"Property source must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenSourceDoesNotExistThrowsException() {\n\t\tPath missing = this.directory.resolve(\"missing\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource(\"test\", missing))\n\t\t\t.withMessage(\"'sourceDirectory' [\" + missing + \"] must exist\");\n\t}\n\n\t@Test\n\tvoid createWhenSourceIsFileThrowsException() throws Exception {\n\t\tPath file = this.directory.resolve(\"file\");\n\t\tFileCopyUtils.copy(\"test\".getBytes(StandardCharsets.UTF_8), file.toFile());\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConfigTreePropertySource(\"test\", file))\n\t\t\t.withMessage(\"'sourceDirectory' [\" + file + \"] must be a directory\");\n\t}\n\n\t@Test\n\tvoid getPropertyNamesFromFlatReturnsPropertyNames() throws Exception {\n\t\tConfigTreePropertySource propertySource = getFlatPropertySource();\n\t\tassertThat(propertySource.getPropertyNames()).containsExactly(\"a\", \"b\", \"c\", \"one\");\n\t}\n\n\t@Test\n\tvoid getPropertyNamesFromNestedReturnsPropertyNames() throws Exception {\n\t\tConfigTreePropertySource propertySource = getNestedPropertySource();\n\t\tassertThat(propertySource.getPropertyNames()).containsExactly(\"c\", \"fa.a\", \"fa.b\", \"fb.a\", \"fb.fa.a\");\n\t}\n\n\t@Test\n\tvoid getPropertyNamesFromNestedWithSymlinkInPathReturnsPropertyNames() throws Exception {\n\t\taddNested();\n\t\tPath symlinkTempDir = Files.createSymbolicLink(this.directory.resolveSibling(\"symlinkTempDir\"), this.directory);\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", symlinkTempDir);\n\t\tFiles.delete(symlinkTempDir);\n\t\tassertThat(propertySource.getPropertyNames()).containsExactly(\"c\", \"fa.a\", \"fa.b\", \"fb.a\", \"fb.fa.a\");\n\t}\n\n\t@Test\n\tvoid getPropertyNamesFromFlatWithSymlinksIgnoresHiddenFiles() throws Exception {\n\t\tConfigTreePropertySource propertySource = getSymlinkedFlatPropertySource();\n\t\tassertThat(propertySource.getPropertyNames()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getPropertyNamesFromNestedWithSymlinksIgnoresHiddenFiles() throws Exception {\n\t\tConfigTreePropertySource propertySource = getSymlinkedNestedPropertySource();\n\t\tassertThat(propertySource.getPropertyNames()).containsExactly(\"aa\", \"ab\", \"baa\", \"c\");\n\t}\n\n\t@Test\n\tvoid getPropertyNamesWhenLowercaseReturnsPropertyNames() throws Exception {\n\t\taddProperty(\"SpRiNg\", \"boot\");\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", this.directory,\n\t\t\t\tOption.USE_LOWERCASE_NAMES);\n\t\tassertThat(propertySource.getPropertyNames()).containsExactly(\"spring\");\n\t}\n\n\t@Test\n\tvoid getPropertyFromFlatReturnsFileContent() throws Exception {\n\t\tConfigTreePropertySource propertySource = getFlatPropertySource();\n\t\tassertThat(propertySource.getProperty(\"b\")).hasToString(\"B\");\n\t}\n\n\t@Test\n\tvoid getPropertyFromFlatWhenMissingReturnsNull() throws Exception {\n\t\tConfigTreePropertySource propertySource = getFlatPropertySource();\n\t\tassertThat(propertySource.getProperty(\"missing\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyFromFlatWhenFileDeletedThrowsException() throws Exception {\n\t\tConfigTreePropertySource propertySource = getFlatPropertySource();\n\t\tPath b = this.directory.resolve(\"b\");\n\t\tFiles.delete(b);\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tValue property = propertySource.getProperty(\"b\");\n\t\t\tassertThat(property).isNotNull();\n\t\t\tproperty.toString();\n\t\t}).withMessage(\"The property file '\" + b + \"' no longer exists\");\n\t}\n\n\t@Test\n\tvoid getOriginFromFlatReturnsOrigin() throws Exception {\n\t\tConfigTreePropertySource propertySource = getFlatPropertySource();\n\t\tTextResourceOrigin origin = (TextResourceOrigin) propertySource.getOrigin(\"b\");\n\t\tassertThat(origin).isNotNull();\n\t\tResource resource = origin.getResource();\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.getFile()).isEqualTo(this.directory.resolve(\"b\").toFile());\n\t\tLocation location = origin.getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.getLine()).isZero();\n\t\tassertThat(location.getColumn()).isZero();\n\t}\n\n\t@Test\n\tvoid getOriginFromFlatWhenMissingReturnsNull() throws Exception {\n\t\tConfigTreePropertySource propertySource = getFlatPropertySource();\n\t\tassertThat(propertySource.getOrigin(\"missing\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyViaEnvironmentSupportsConversion() throws Exception {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tConversionService conversionService = ApplicationConversionService.getSharedInstance();\n\t\tenvironment.setConversionService((ConfigurableConversionService) conversionService);\n\t\tenvironment.getPropertySources().addFirst(getFlatPropertySource());\n\t\tassertThat(environment.getProperty(\"a\")).isEqualTo(\"A\");\n\t\tassertThat(environment.getProperty(\"b\")).isEqualTo(\"B\");\n\t\tInputStreamSource c = environment.getProperty(\"c\", InputStreamSource.class);\n\t\tassertThat(c).isNotNull();\n\t\tassertThat(c.getInputStream()).hasContent(\"C\");\n\t\tassertThat(environment.getProperty(\"c\", byte[].class)).contains('C');\n\t\tassertThat(environment.getProperty(\"one\", Integer.class)).isOne();\n\t}\n\n\t@Test\n\tvoid getPropertyFromNestedReturnsFileContent() throws Exception {\n\t\tConfigTreePropertySource propertySource = getNestedPropertySource();\n\t\tassertThat(propertySource.getProperty(\"fb.fa.a\")).hasToString(\"BAA\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNotAlwaysReadIgnoresUpdates() throws Exception {\n\t\tConfigTreePropertySource propertySource = getNestedPropertySource();\n\t\tValue v1 = propertySource.getProperty(\"fa.b\");\n\t\tValue v2 = propertySource.getProperty(\"fa.b\");\n\t\tassertThat(v1).isNotNull();\n\t\tassertThat(v1).isSameAs(v2);\n\t\tassertThat(v1).hasToString(\"AB\");\n\t\tassertThat(FileCopyUtils.copyToByteArray(v1.getInputStream())).containsExactly('A', 'B');\n\t\taddProperty(\"fa/b\", \"XX\");\n\t\tassertThat(v1).hasToString(\"AB\");\n\t\tassertThat(FileCopyUtils.copyToByteArray(v1.getInputStream())).containsExactly('A', 'B');\n\t}\n\n\t@Test\n\tvoid getPropertyWhenAlwaysReadReflectsUpdates() throws Exception {\n\t\taddNested();\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", this.directory,\n\t\t\t\tOption.ALWAYS_READ);\n\t\tValue v1 = propertySource.getProperty(\"fa.b\");\n\t\tValue v2 = propertySource.getProperty(\"fa.b\");\n\t\tassertThat(v1).isNotNull();\n\t\tassertThat(v1).isNotSameAs(v2);\n\t\tassertThat(v1).hasToString(\"AB\");\n\t\tassertThat(FileCopyUtils.copyToByteArray(v1.getInputStream())).containsExactly('A', 'B');\n\t\taddProperty(\"fa/b\", \"XX\");\n\t\tassertThat(v1).hasToString(\"XX\");\n\t\tassertThat(FileCopyUtils.copyToByteArray(v1.getInputStream())).containsExactly('X', 'X');\n\t\tassertThat(propertySource.getProperty(\"fa.b\")).hasToString(\"XX\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenLowercaseReturnsValue() throws Exception {\n\t\taddProperty(\"SpRiNg\", \"boot\");\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", this.directory,\n\t\t\t\tOption.USE_LOWERCASE_NAMES);\n\t\tassertThat(propertySource.getProperty(\"spring\")).hasToString(\"boot\");\n\t}\n\n\t@Test\n\tvoid getPropertyAsStringWhenMultiLinePropertyReturnsNonTrimmed() throws Exception {\n\t\taddProperty(\"a\", \"a\\nb\\n\");\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", this.directory,\n\t\t\t\tOption.AUTO_TRIM_TRAILING_NEW_LINE);\n\t\tassertThat(propertySource.getProperty(\"a\")).hasToString(\"a\\nb\\n\");\n\t}\n\n\t@Test\n\tvoid getPropertyAsStringWhenPropertyEndsWithNewLineReturnsTrimmed() throws Exception {\n\t\taddProperty(\"a\", \"a\\n\");\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", this.directory,\n\t\t\t\tOption.AUTO_TRIM_TRAILING_NEW_LINE);\n\t\tassertThat(propertySource.getProperty(\"a\")).hasToString(\"a\");\n\t}\n\n\t@Test\n\tvoid getPropertyAsStringWhenPropertyEndsWithWindowsNewLineReturnsTrimmed() throws Exception {\n\t\taddProperty(\"a\", \"a\\r\\n\");\n\t\tConfigTreePropertySource propertySource = new ConfigTreePropertySource(\"test\", this.directory,\n\t\t\t\tOption.AUTO_TRIM_TRAILING_NEW_LINE);\n\t\tassertThat(propertySource.getProperty(\"a\")).hasToString(\"a\");\n\t}\n\n\tprivate ConfigTreePropertySource getFlatPropertySource() throws IOException {\n\t\taddProperty(\"a\", \"A\");\n\t\taddProperty(\"b\", \"B\");\n\t\taddProperty(\"c\", \"C\");\n\t\taddProperty(\"one\", \"1\");\n\t\treturn new ConfigTreePropertySource(\"test\", this.directory);\n\t}\n\n\tprivate ConfigTreePropertySource getSymlinkedFlatPropertySource() throws IOException {\n\t\taddProperty(\"..hidden-a\", \"A\");\n\t\taddProperty(\"..hidden-b\", \"B\");\n\t\taddProperty(\"..hidden-c\", \"C\");\n\t\tcreateSymbolicLink(\"a\", \"..hidden-a\");\n\t\tcreateSymbolicLink(\"b\", \"..hidden-b\");\n\t\tcreateSymbolicLink(\"c\", \"..hidden-c\");\n\t\treturn new ConfigTreePropertySource(\"test\", this.directory);\n\t}\n\n\tprivate ConfigTreePropertySource getNestedPropertySource() throws IOException {\n\t\taddNested();\n\t\treturn new ConfigTreePropertySource(\"test\", this.directory);\n\t}\n\n\tprivate void addNested() throws IOException {\n\t\taddProperty(\"fa/a\", \"AA\");\n\t\taddProperty(\"fa/b\", \"AB\");\n\t\taddProperty(\"fb/a\", \"BA\");\n\t\taddProperty(\"fb/fa/a\", \"BAA\");\n\t\taddProperty(\"c\", \"C\");\n\t}\n\n\tprivate ConfigTreePropertySource getSymlinkedNestedPropertySource() throws IOException {\n\t\taddProperty(\"..hidden-a/a\", \"AA\");\n\t\taddProperty(\"..hidden-a/b\", \"AB\");\n\t\taddProperty(\"..hidden-b/fa/a\", \"BAA\");\n\t\taddProperty(\"c\", \"C\");\n\t\tcreateSymbolicLink(\"aa\", \"..hidden-a/a\");\n\t\tcreateSymbolicLink(\"ab\", \"..hidden-a/b\");\n\t\tcreateSymbolicLink(\"baa\", \"..hidden-b/fa/a\");\n\t\treturn new ConfigTreePropertySource(\"test\", this.directory);\n\t}\n\n\tprivate void addProperty(String path, String value) throws IOException {\n\t\tFile file = this.directory.resolve(path).toFile();\n\t\tfile.getParentFile().mkdirs();\n\t\tFileCopyUtils.copy(value.getBytes(StandardCharsets.UTF_8), file);\n\t}\n\n\tprivate void createSymbolicLink(String link, String target) throws IOException {\n\t\tFiles.createSymbolicLink(this.directory.resolve(link).toAbsolutePath(),\n\t\t\t\tthis.directory.resolve(target).toAbsolutePath());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/DefaultPropertiesPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.Collections;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link DefaultPropertiesPropertySource}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass DefaultPropertiesPropertySourceTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Consumer<DefaultPropertiesPropertySource> action;\n\n\t@Test\n\tvoid nameIsDefaultProperties() {\n\t\tassertThat(DefaultPropertiesPropertySource.NAME).isEqualTo(\"defaultProperties\");\n\t}\n\n\t@Test\n\tvoid createCreatesSource() {\n\t\tDefaultPropertiesPropertySource propertySource = new DefaultPropertiesPropertySource(\n\t\t\t\tCollections.singletonMap(\"spring\", \"boot\"));\n\t\tassertThat(propertySource.getName()).isEqualTo(\"defaultProperties\");\n\t\tassertThat(propertySource.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid hasMatchingNameWhenNameMatchesReturnsTrue() {\n\t\tMockPropertySource propertySource = new MockPropertySource(\"defaultProperties\");\n\t\tassertThat(DefaultPropertiesPropertySource.hasMatchingName(propertySource)).isTrue();\n\t}\n\n\t@Test\n\tvoid hasMatchingNameWhenNameDoesNotMatchReturnsFalse() {\n\t\tMockPropertySource propertySource = new MockPropertySource(\"normalProperties\");\n\t\tassertThat(DefaultPropertiesPropertySource.hasMatchingName(propertySource)).isFalse();\n\t}\n\n\t@Test\n\tvoid hasMatchingNameWhenPropertySourceIsNullReturnsFalse() {\n\t\tassertThat(DefaultPropertiesPropertySource.hasMatchingName(null)).isFalse();\n\t}\n\n\t@Test\n\tvoid ifNotEmptyWhenNullDoesNotCallAction() {\n\t\tDefaultPropertiesPropertySource.ifNotEmpty(null, this.action);\n\t\tthen(this.action).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid ifNotEmptyWhenEmptyDoesNotCallAction() {\n\t\tDefaultPropertiesPropertySource.ifNotEmpty(Collections.emptyMap(), this.action);\n\t\tthen(this.action).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid ifNotEmptyHasValueCallsAction() {\n\t\tDefaultPropertiesPropertySource.ifNotEmpty(Collections.singletonMap(\"spring\", \"boot\"), this.action);\n\t\tthen(this.action).should()\n\t\t\t.accept(assertArg((properties) -> assertThat(properties.getProperty(\"spring\")).isEqualTo(\"boot\")));\n\t}\n\n\t@Test\n\tvoid moveToEndWhenNotPresentDoesNothing() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tDefaultPropertiesPropertySource.moveToEnd(environment);\n\t}\n\n\t@Test\n\tvoid addOrMergeWhenExistingNotFoundShouldAdd() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tDefaultPropertiesPropertySource.addOrMerge(Collections.singletonMap(\"spring\", \"boot\"), propertySources);\n\t\tassertThat(propertySources.contains(DefaultPropertiesPropertySource.NAME)).isTrue();\n\t\tassertThat(getDefaultPropertySource(propertySources).getProperty(\"spring\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid addOrMergeWhenExistingFoundShouldMerge() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tpropertySources.addLast(new DefaultPropertiesPropertySource(Collections.singletonMap(\"spring\", \"boot\")));\n\t\tDefaultPropertiesPropertySource.addOrMerge(Collections.singletonMap(\"hello\", \"world\"), propertySources);\n\t\tassertThat(propertySources.contains(DefaultPropertiesPropertySource.NAME)).isTrue();\n\t\tassertThat(getDefaultPropertySource(propertySources).getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(getDefaultPropertySource(propertySources).getProperty(\"hello\")).isEqualTo(\"world\");\n\t}\n\n\t@Test\n\tvoid addOrMergeWhenExistingNotMapPropertySourceShouldNotMerge() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tCompositePropertySource composite = new CompositePropertySource(DefaultPropertiesPropertySource.NAME);\n\t\tcomposite.addPropertySource(new DefaultPropertiesPropertySource(Collections.singletonMap(\"spring\", \"boot\")));\n\t\tpropertySources.addFirst(composite);\n\t\tDefaultPropertiesPropertySource.addOrMerge(Collections.singletonMap(\"hello\", \"world\"), propertySources);\n\t\tassertThat(propertySources.contains(DefaultPropertiesPropertySource.NAME)).isTrue();\n\t\tassertThat(getDefaultPropertySource(propertySources).getProperty(\"spring\")).isNull();\n\t\tassertThat(getDefaultPropertySource(propertySources).getProperty(\"hello\")).isEqualTo(\"world\");\n\t}\n\n\t@Test\n\tvoid moveToEndWhenPresentMovesToEnd() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tpropertySources.addLast(new DefaultPropertiesPropertySource(Collections.singletonMap(\"spring\", \"boot\")));\n\t\tpropertySources.addLast(new MockPropertySource(\"test\"));\n\t\tDefaultPropertiesPropertySource.moveToEnd(environment);\n\t\tString[] names = propertySources.stream().map(PropertySource::getName).toArray(String[]::new);\n\t\tassertThat(names).containsExactly(MockPropertySource.MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, \"test\",\n\t\t\t\tDefaultPropertiesPropertySource.NAME);\n\t}\n\n\tprivate PropertySource<?> getDefaultPropertySource(MutablePropertySources propertySources) {\n\t\tPropertySource<?> propertySource = propertySources.get(DefaultPropertiesPropertySource.NAME);\n\t\tassertThat(propertySource).isNotNull();\n\t\treturn propertySource;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/EnvironmentPostProcessorsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.boot.support.EnvironmentPostProcessorsFactory;\nimport org.springframework.core.OverridingClassLoader;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EnvironmentPostProcessorsFactory}.\n *\n * @author Phillip Webb\n */\nclass EnvironmentPostProcessorsFactoryTests {\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\t@Test\n\tvoid fromSpringFactoriesReturnsFactory() {\n\t\tEnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory.fromSpringFactories(null);\n\t\tList<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory,\n\t\t\t\tthis.bootstrapContext);\n\t\tassertThat(processors).hasSizeGreaterThan(1);\n\t}\n\n\t@Test\n\tvoid ofClassesReturnsFactory() {\n\t\tEnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory\n\t\t\t.of(TestEnvironmentPostProcessor.class);\n\t\tList<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory,\n\t\t\t\tthis.bootstrapContext);\n\t\tassertThat(processors).hasSize(1);\n\t\tassertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid ofClassNamesReturnsFactory() {\n\t\tEnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory\n\t\t\t.of(TestEnvironmentPostProcessor.class.getName());\n\t\tList<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory,\n\t\t\t\tthis.bootstrapContext);\n\t\tassertThat(processors).hasSize(1);\n\t\tassertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid ofClassNamesWithClassLoaderReturnsFactory() {\n\t\tOverridingClassLoader classLoader = new OverridingClassLoader(getClass().getClassLoader()) {\n\n\t\t\t@Override\n\t\t\tprotected boolean isEligibleForOverriding(String className) {\n\t\t\t\treturn super.isEligibleForOverriding(className)\n\t\t\t\t\t\t&& className.equals(TestEnvironmentPostProcessor.class.getName());\n\t\t\t}\n\n\t\t};\n\t\tEnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory.of(classLoader,\n\t\t\t\tTestEnvironmentPostProcessor.class.getName());\n\t\tList<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory,\n\t\t\t\tthis.bootstrapContext);\n\t\tassertThat(processors).hasSize(1);\n\t\tassertThat(processors.get(0).getClass().getClassLoader()).isSameAs(classLoader);\n\t}\n\n\tstatic class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\tTestEnvironmentPostProcessor(DeferredLogFactory logFactory) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/NoSnakeYamlPropertySourceLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.core.io.ByteArrayResource;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link YamlPropertySourceLoader} when snakeyaml is not available.\n *\n * @author Madhura Bhave\n */\n@ClassPathExclusions(\"snakeyaml-*.jar\")\nclass NoSnakeYamlPropertySourceLoaderTests {\n\n\tprivate final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();\n\n\t@Test\n\tvoid load() {\n\t\tByteArrayResource resource = new ByteArrayResource(\"foo:\\n  bar: spam\".getBytes());\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.loader.load(\"resource\", resource))\n\t\t\t.withMessageContaining(\"Attempted to load resource but snakeyaml was not found on the classpath\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedMapPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedValue;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OriginTrackedMapPropertySource}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass OriginTrackedMapPropertySourceTests {\n\n\tprivate final Map<String, Object> map = new LinkedHashMap<>();\n\n\tprivate final OriginTrackedMapPropertySource source = new OriginTrackedMapPropertySource(\"test\", this.map);\n\n\tprivate final Origin origin = mock(Origin.class);\n\n\t@Test\n\tvoid getPropertyWhenMissingShouldReturnNull() {\n\t\tassertThat(this.source.getProperty(\"test\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNonTrackedShouldReturnValue() {\n\t\tthis.map.put(\"test\", \"foo\");\n\t\tassertThat(this.source.getProperty(\"test\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenTrackedShouldReturnValue() {\n\t\tthis.map.put(\"test\", OriginTrackedValue.of(\"foo\", this.origin));\n\t\tassertThat(this.source.getProperty(\"test\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getPropertyOriginWhenMissingShouldReturnNull() {\n\t\tassertThat(this.source.getOrigin(\"test\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyOriginWhenNonTrackedShouldReturnNull() {\n\t\tthis.map.put(\"test\", \"foo\");\n\t\tassertThat(this.source.getOrigin(\"test\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyOriginWhenTrackedShouldReturnOrigin() {\n\t\tthis.map.put(\"test\", OriginTrackedValue.of(\"foo\", this.origin));\n\t\tassertThat(this.source.getOrigin(\"test\")).isEqualTo(this.origin);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedPropertiesLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.env.OriginTrackedPropertiesLoader.Document;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link OriginTrackedPropertiesLoader}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass OriginTrackedPropertiesLoaderTests {\n\n\tprivate ClassPathResource resource;\n\n\tprivate List<Document> documents;\n\n\t@BeforeEach\n\tvoid setUp() throws Exception {\n\t\tString path = \"test-properties.properties\";\n\t\tthis.resource = new ClassPathResource(path, getClass());\n\t\tthis.documents = new OriginTrackedPropertiesLoader(this.resource).load(null);\n\t}\n\n\t@Test\n\tvoid compareToJavaProperties() throws Exception {\n\t\tProperties java = PropertiesLoaderUtils.loadProperties(this.resource);\n\t\tProperties ours = new Properties();\n\t\tnew OriginTrackedPropertiesLoader(this.resource).load(null, false)\n\t\t\t.get(0)\n\t\t\t.asMap()\n\t\t\t.forEach((k, v) -> ours.put(k, v.getValue()));\n\t\tassertThat(ours).isEqualTo(java);\n\t}\n\n\t@Test\n\tvoid getSimpleProperty() {\n\t\tOriginTrackedValue value = getFromFirst(\"test\");\n\t\tassertThat(getValue(value)).isEqualTo(\"properties\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"11:6\");\n\t}\n\n\t@Test\n\tvoid getSimplePropertyWithColonSeparator() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-colon-separator\");\n\t\tassertThat(getValue(value)).isEqualTo(\"my-property\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"15:23\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithSeparatorSurroundedBySpaces() {\n\t\tOriginTrackedValue value = getFromFirst(\"blah\");\n\t\tassertThat(getValue(value)).isEqualTo(\"hello world\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"2:12\");\n\t}\n\n\t@Test\n\tvoid getUnicodeProperty() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-unicode\");\n\t\tassertThat(getValue(value)).isEqualTo(\"properties&test\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"12:14\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"malformed-unicode.properties\", content = \"test-malformed-unicode=properties\\\\u(026test\")\n\tvoid getMalformedUnicodeProperty() {\n\t\t// gh-12716\n\t\tClassPathResource resource = new ClassPathResource(\"malformed-unicode.properties\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> new OriginTrackedPropertiesLoader(resource).load(null))\n\t\t\t.withMessageContaining(\"Malformed \\\\uxxxx encoding\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"utf-8.properties\", content = \"smiley=😃\")\n\tvoid shouldRespectEncoding() throws IOException {\n\t\tClassPathResource resource = new ClassPathResource(\"utf-8.properties\");\n\t\tList<Document> documents = new OriginTrackedPropertiesLoader(resource).load(StandardCharsets.UTF_8);\n\t\tOriginTrackedValue value = documents.get(0).asMap().get(\"smiley\");\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value.getValue()).isEqualTo(\"😃\");\n\t}\n\n\t@Test\n\tvoid getEscapedProperty() {\n\t\tOriginTrackedValue value = getFromFirst(\"test=property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"helloworld\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"14:15\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithTab() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-tab-property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo\\tbar\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"16:19\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithBang() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-bang-property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo!\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"34:20\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithValueComment() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-property-value-comment\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo !bar #foo\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"36:29\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithMultilineImmediateBang() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-multiline-immediate-bang\");\n\t\tassertThat(getValue(value)).isEqualTo(\"!foo\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"39:1\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithCarriageReturn() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-return-property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo\\rbar\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"17:22\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithNewLine() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-newline-property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo\\nbar\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"18:23\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithFormFeed() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-form-feed-property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo\\fbar\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"19:25\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithWhiteSpace() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-whitespace-property\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo   bar\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"20:32\");\n\t}\n\n\t@Test\n\tvoid getCommentedOutPropertyShouldBeNull() {\n\t\tassertThat(getFromFirst(\"commented-property\")).isNull();\n\t\tassertThat(getFromFirst(\"#commented-property\")).isNull();\n\t\tassertThat(getFromFirst(\"commented-two\")).isNull();\n\t\tassertThat(getFromFirst(\"!commented-two\")).isNull();\n\t}\n\n\t@Test\n\tvoid getMultiline() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-multiline\");\n\t\tassertThat(getValue(value)).isEqualTo(\"ab\\\\c\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"21:17\");\n\t}\n\n\t@Test\n\tvoid getImmediateMultiline() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-multiline-immediate\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"32:1\");\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithPoundPrefixAndWithoutWhitespaceLoadsMultiDoc() throws IOException {\n\t\tString content = \"a=a\\n#---\\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(2);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithExclamationPrefixAndWithoutWhitespaceLoadsMultiDoc() throws IOException {\n\t\tString content = \"a=a\\n!---\\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(2);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithPoundPrefixAndLeadingWhitespaceLoadsSingleDoc() throws IOException {\n\t\tString content = \"a=a\\n \\t#---\\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(1);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithExclamationPrefixAndLeadingWhitespaceLoadsSingleDoc() throws IOException {\n\t\tString content = \"a=a\\n \\t!---\\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(1);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithPoundPrefixAndTrailingWhitespaceLoadsMultiDoc() throws IOException {\n\t\tString content = \"a=a\\n#--- \\t \\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(2);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithExclamationPrefixAndTrailingWhitespaceLoadsMultiDoc() throws IOException {\n\t\tString content = \"a=a\\n!--- \\t \\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(2);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithPoundPrefixAndTrailingCharsLoadsSingleDoc() throws IOException {\n\t\tString content = \"a=a\\n#--- \\tcomment\\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(1);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentWithExclamationPrefixAndTrailingCharsLoadsSingleDoc() throws IOException {\n\t\tString content = \"a=a\\n!--- \\tcomment\\nb=b\";\n\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes())).load(null);\n\t\tassertThat(loaded).hasSize(1);\n\t}\n\n\t@Test\n\tvoid loadWhenMultiDocumentSeparatorPrefixDifferentFromCommentPrefixLoadsMultiDoc() throws IOException {\n\t\tString[] contents = new String[] { \"a=a\\n# comment\\n!---\\nb=b\", \"a=a\\n! comment\\n#---\\nb=b\" };\n\t\tfor (String content : contents) {\n\t\t\tList<Document> loaded = new OriginTrackedPropertiesLoader(new ByteArrayResource(content.getBytes()))\n\t\t\t\t.load(null);\n\t\t\tassertThat(loaded).hasSize(2);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getPropertyWithWhitespaceAfterKey() {\n\t\tOriginTrackedValue value = getFromFirst(\"bar\");\n\t\tassertThat(getValue(value)).isEqualTo(\"foo=baz\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"3:7\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithSpaceSeparator() {\n\t\tOriginTrackedValue value = getFromFirst(\"hello\");\n\t\tassertThat(getValue(value)).isEqualTo(\"world\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"4:9\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithBackslashEscaped() {\n\t\tOriginTrackedValue value = getFromFirst(\"proper\\\\ty\");\n\t\tassertThat(getValue(value)).isEqualTo(\"test\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"5:11\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithEmptyValue() {\n\t\tOriginTrackedValue value = getFromFirst(\"foo\");\n\t\tassertThat(getValue(value)).isEqualTo(\"\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"7:0\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithBackslashEscapedInValue() {\n\t\tOriginTrackedValue value = getFromFirst(\"bat\");\n\t\tassertThat(getValue(value)).isEqualTo(\"a\\\\\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"7:7\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithSeparatorInValue() {\n\t\tOriginTrackedValue value = getFromFirst(\"bling\");\n\t\tassertThat(getValue(value)).isEqualTo(\"a=b\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"8:9\");\n\t}\n\n\t@Test\n\tvoid getListProperty() {\n\t\tOriginTrackedValue apple = getFromFirst(\"foods[0]\");\n\t\tassertThat(getValue(apple)).isEqualTo(\"Apple\");\n\t\tassertThat(getLocation(apple)).isEqualTo(\"24:9\");\n\t\tOriginTrackedValue orange = getFromFirst(\"foods[1]\");\n\t\tassertThat(getValue(orange)).isEqualTo(\"Orange\");\n\t\tassertThat(getLocation(orange)).isEqualTo(\"25:1\");\n\t\tOriginTrackedValue strawberry = getFromFirst(\"foods[2]\");\n\t\tassertThat(getValue(strawberry)).isEqualTo(\"Strawberry\");\n\t\tassertThat(getLocation(strawberry)).isEqualTo(\"26:1\");\n\t\tOriginTrackedValue mango = getFromFirst(\"foods[3]\");\n\t\tassertThat(getValue(mango)).isEqualTo(\"Mango\");\n\t\tassertThat(getLocation(mango)).isEqualTo(\"27:1\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithISO88591Character() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-iso8859-1-chars\");\n\t\tassertThat(getValue(value)).isEqualTo(\"æ×ÈÅÞßáñÀÿ\");\n\t}\n\n\t@Test\n\tvoid getPropertyWithTrailingSpace() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-with-trailing-space\");\n\t\tassertThat(getValue(value)).isEqualTo(\"trailing \");\n\t}\n\n\t@Test\n\tvoid getPropertyWithEscapedTrailingSpace() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-with-escaped-trailing-space\");\n\t\tassertThat(getValue(value)).isEqualTo(\"trailing \");\n\t}\n\n\t@Test\n\t@WithResource(name = \"existing-non-multi-document.properties\", content = \"\"\"\n\t\t\t#---\n\t\t\t# Test\n\t\t\t#---\n\n\t\t\tspring=boot\n\n\t\t\t#---\n\t\t\t# Test\n\n\t\t\tboot=bar\n\n\n\t\t\t# Test\n\t\t\t#---\n\n\t\t\tbar=ok\n\n\t\t\t!---\n\t\t\t! Test\n\t\t\t!---\n\n\t\t\tok=well\n\n\t\t\t!---\n\t\t\t! Test\n\n\t\t\twell=hello\n\n\t\t\t! Test\n\t\t\t!---\n\n\t\t\thello=world\n\n\t\t\t\"\"\")\n\tvoid existingCommentsAreNotTreatedAsMultiDoc() throws Exception {\n\t\tthis.resource = new ClassPathResource(\"existing-non-multi-document.properties\");\n\t\tthis.documents = new OriginTrackedPropertiesLoader(this.resource).load(null);\n\t\tassertThat(this.documents).hasSize(1);\n\t}\n\n\t@Test\n\tvoid getPropertyAfterPoundCharacter() {\n\t\tOriginTrackedValue value = getFromFirst(\"test-line-after-empty-pound\");\n\t\tassertThat(getValue(value)).isEqualTo(\"abc\");\n\t}\n\n\tprivate @Nullable OriginTrackedValue getFromFirst(String key) {\n\t\treturn this.documents.get(0).asMap().get(key);\n\t}\n\n\tprivate @Nullable Object getValue(@Nullable OriginTrackedValue value) {\n\t\treturn (value != null) ? value.getValue() : null;\n\t}\n\n\tprivate @Nullable String getLocation(@Nullable OriginTrackedValue value) {\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\tOrigin origin = value.getOrigin();\n\t\tassertThat(origin).isNotNull();\n\t\tLocation location = ((TextResourceOrigin) origin).getLocation();\n\t\tassertThat(location).isNotNull();\n\t\treturn location.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/OriginTrackedYamlLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.yaml.snakeyaml.composer.ComposerException;\n\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link OriginTrackedYamlLoader}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass OriginTrackedYamlLoaderTests {\n\n\tprivate OriginTrackedYamlLoader loader;\n\n\tprivate @Nullable List<Map<String, Object>> result;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tResource resource = new ClassPathResource(\"test-yaml.yml\");\n\t\tthis.loader = new OriginTrackedYamlLoader(resource);\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid processSimpleKey() {\n\t\tOriginTrackedValue value = getValue(\"name\");\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value).hasToString(\"Martin D'vloper\");\n\t\tassertThat(getLocation(value)).isEqualTo(\"3:7\");\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid processMap() {\n\t\tOriginTrackedValue perl = getValue(\"languages.perl\");\n\t\tOriginTrackedValue python = getValue(\"languages.python\");\n\t\tOriginTrackedValue pascal = getValue(\"languages.pascal\");\n\t\tassertThat(perl).isNotNull();\n\t\tassertThat(perl).hasToString(\"Elite\");\n\t\tassertThat(getLocation(perl)).isEqualTo(\"13:11\");\n\t\tassertThat(python).isNotNull();\n\t\tassertThat(python).hasToString(\"Elite\");\n\t\tassertThat(getLocation(python)).isEqualTo(\"14:13\");\n\t\tassertThat(pascal).isNotNull();\n\t\tassertThat(pascal).hasToString(\"Lame\");\n\t\tassertThat(getLocation(pascal)).isEqualTo(\"15:13\");\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid processCollection() {\n\t\tOriginTrackedValue apple = getValue(\"foods[0]\");\n\t\tOriginTrackedValue orange = getValue(\"foods[1]\");\n\t\tOriginTrackedValue strawberry = getValue(\"foods[2]\");\n\t\tOriginTrackedValue mango = getValue(\"foods[3]\");\n\t\tassertThat(apple).isNotNull();\n\t\tassertThat(apple).hasToString(\"Apple\");\n\t\tassertThat(getLocation(apple)).isEqualTo(\"8:7\");\n\t\tassertThat(orange).isNotNull();\n\t\tassertThat(orange).hasToString(\"Orange\");\n\t\tassertThat(getLocation(orange)).isEqualTo(\"9:7\");\n\t\tassertThat(strawberry).isNotNull();\n\t\tassertThat(strawberry).hasToString(\"Strawberry\");\n\t\tassertThat(getLocation(strawberry)).isEqualTo(\"10:7\");\n\t\tassertThat(mango).isNotNull();\n\t\tassertThat(mango).hasToString(\"Mango\");\n\t\tassertThat(getLocation(mango)).isEqualTo(\"11:7\");\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid processMultiline() {\n\t\tOriginTrackedValue education = getValue(\"education\");\n\t\tassertThat(education).isNotNull();\n\t\tassertThat(education).hasToString(\"4 GCSEs\\n3 A-Levels\\nBSc in the Internet of Things\\n\");\n\t\tassertThat(getLocation(education)).isEqualTo(\"16:12\");\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid processListOfMaps() {\n\t\tOriginTrackedValue name = getValue(\"example.foo[0].name\");\n\t\tOriginTrackedValue url = getValue(\"example.foo[0].url\");\n\t\tOriginTrackedValue bar1 = getValue(\"example.foo[0].bar[0].bar1\");\n\t\tOriginTrackedValue bar2 = getValue(\"example.foo[0].bar[1].bar2\");\n\t\tassertThat(name).isNotNull();\n\t\tassertThat(name).hasToString(\"springboot\");\n\t\tassertThat(getLocation(name)).isEqualTo(\"22:15\");\n\t\tassertThat(url).isNotNull();\n\t\tassertThat(url).hasToString(\"https://springboot.example.com/\");\n\t\tassertThat(getLocation(url)).isEqualTo(\"23:14\");\n\t\tassertThat(bar1).isNotNull();\n\t\tassertThat(bar1).hasToString(\"baz\");\n\t\tassertThat(getLocation(bar1)).isEqualTo(\"25:19\");\n\t\tassertThat(bar2).isNotNull();\n\t\tassertThat(bar2).hasToString(\"bling\");\n\t\tassertThat(getLocation(bar2)).isEqualTo(\"26:19\");\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid processEmptyAndNullValues() {\n\t\tOriginTrackedValue empty = getValue(\"empty\");\n\t\tOriginTrackedValue nullValue = getValue(\"null-value\");\n\t\tOriginTrackedValue emptyList = getValue(\"emptylist\");\n\t\tassertThat(empty).isNotNull();\n\t\tassertThat(empty.getValue()).isEqualTo(\"\");\n\t\tassertThat(getLocation(empty)).isEqualTo(\"27:8\");\n\t\tassertThat(nullValue).isNotNull();\n\t\tassertThat(nullValue.getValue()).isEqualTo(\"\");\n\t\tassertThat(getLocation(nullValue)).isEqualTo(\"28:13\");\n\t\tassertThat(emptyList).isNotNull();\n\t\tassertThat(emptyList.getValue()).isEqualTo(\"\");\n\t\tassertThat(getLocation(emptyList)).isEqualTo(\"29:12\");\n\t}\n\n\t@Test\n\t@WithTestYamlResource\n\tvoid emptyMapsOrObjectsAreNotDropped() {\n\t\tassertThat(getFirstResult()).contains(entry(\"emptymap\", \"\"));\n\t}\n\n\t@Test\n\tvoid unsupportedType() {\n\t\tString yaml = \"value: !!java.net.URL [!!java.lang.String [!!java.lang.StringBuilder [\\\"http://localhost:9000/\\\"]]]\";\n\t\tResource resource = new ByteArrayResource(yaml.getBytes(StandardCharsets.UTF_8));\n\t\tthis.loader = new OriginTrackedYamlLoader(resource);\n\t\tassertThatExceptionOfType(ComposerException.class).isThrownBy(this.loader::load);\n\t}\n\n\t@Test\n\t@WithResource(name = \"test-empty-yaml.yml\", content = \"\"\"\n\t\t\t---\n\t\t\t---\n\n\t\t\t---\n\t\t\t---\n\t\t\t\"\"\")\n\tvoid emptyDocuments() {\n\t\tthis.loader = new OriginTrackedYamlLoader(new ClassPathResource(\"test-empty-yaml.yml\"));\n\t\tList<Map<String, Object>> loaded = this.loader.load();\n\t\tassertThat(loaded).isEmpty();\n\t}\n\n\t@Test\n\tvoid loadWhenLargeNumberOfNodesLoadsYaml() {\n\t\tStringBuilder yaml = new StringBuilder();\n\t\tint size = 500;\n\t\tyaml.append(\"defs:\\n\");\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\tyaml.append(\" - def\" + i + \": &def\" + i + \"\\n\");\n\t\t\tyaml.append(\"    - value: \" + i + \"\\n\");\n\t\t}\n\t\tyaml.append(\"refs:\\n\");\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\tyaml.append(\"  ref\" + i + \":\\n\");\n\t\t\tyaml.append(\"   - value: *def\" + i + \"\\n\");\n\t\t}\n\t\tResource resource = new ByteArrayResource(yaml.toString().getBytes(StandardCharsets.UTF_8));\n\t\tthis.loader = new OriginTrackedYamlLoader(resource);\n\t\tMap<String, Object> loaded = this.loader.load().get(0);\n\t\tassertThat(loaded).hasSize(size * 2);\n\t}\n\n\t@Test\n\t@WithResource(name = \"recursive.yml\", content = \"\"\"\n\t\t\t&def1\n\t\t\t*def1: a\n\t\t\ttest:\n\t\t\t  a:\n\t\t\t    spring: 'a'\n\t\t\t  b:\n\t\t\t    boot: 'b'\n\t\t\t\"\"\")\n\tvoid loadWhenRecursiveLoadsYaml() {\n\t\tResource resource = new ClassPathResource(\"recursive.yml\");\n\t\tthis.loader = new OriginTrackedYamlLoader(resource);\n\t\tMap<String, Object> loaded = this.loader.load().get(0);\n\t\tassertThat(loaded.get(\"test.a.spring\")).hasToString(\"a\");\n\t\tassertThat(loaded.get(\"test.b.boot\")).hasToString(\"b\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"anchors.yml\", content = \"\"\"\n\t\t\tsome:\n\t\t\t  path: &anchor\n\t\t\t    config:\n\t\t\t      key: value\n\t\t\t  anotherpath:\n\t\t\t    <<: *anchor\n\t\t\t\"\"\")\n\tvoid loadWhenUsingAnchors() {\n\t\tResource resource = new ClassPathResource(\"anchors.yml\");\n\t\tthis.loader = new OriginTrackedYamlLoader(resource);\n\t\tMap<String, Object> loaded = this.loader.load().get(0);\n\t\tassertThat(loaded.get(\"some.path.config.key\")).hasToString(\"value\");\n\t\tassertThat(loaded.get(\"some.anotherpath.config.key\")).hasToString(\"value\");\n\t}\n\n\t@Test\n\tvoid canLoadFilesBiggerThan3Mb() {\n\t\tStringBuilder yaml = new StringBuilder();\n\t\twhile (yaml.length() < 4_194_304) {\n\t\t\tyaml.append(\"- some list entry\\n\");\n\t\t}\n\t\tResource resource = new ByteArrayResource(yaml.toString().getBytes(StandardCharsets.UTF_8));\n\t\tthis.loader = new OriginTrackedYamlLoader(resource);\n\t\tMap<String, Object> loaded = this.loader.load().get(0);\n\t\tassertThat(loaded).isNotEmpty();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T getValue(String name) {\n\t\treturn (T) getFirstResult().get(name);\n\t}\n\n\tprivate Map<String, Object> getFirstResult() {\n\t\tif (this.result == null) {\n\t\t\tthis.result = this.loader.load();\n\t\t}\n\t\tMap<String, Object> map = this.result.get(0);\n\t\treturn map;\n\t}\n\n\tprivate String getLocation(OriginTrackedValue value) {\n\t\tTextResourceOrigin origin = (TextResourceOrigin) value.getOrigin();\n\t\tassertThat(origin).isNotNull();\n\t\tLocation location = origin.getLocation();\n\t\tassertThat(location).isNotNull();\n\t\treturn location.toString();\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Target(ElementType.METHOD)\n\t@WithResource(name = \"test-yaml.yml\", content = \"\"\"\n\t\t\t# https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html\n\n\t\t\tname: Martin D'vloper\n\t\t\tjob: Developer\n\t\t\tskill: Elite\n\t\t\temployed: True\n\t\t\tfoods:\n\t\t\t    - Apple\n\t\t\t    - Orange\n\t\t\t    - Strawberry\n\t\t\t    - Mango\n\t\t\tlanguages:\n\t\t\t    perl: Elite\n\t\t\t    python: Elite\n\t\t\t    pascal: Lame\n\t\t\teducation: |\n\t\t\t    4 GCSEs\n\t\t\t    3 A-Levels\n\t\t\t    BSc in the Internet of Things\n\t\t\texample:\n\t\t\t    foo:\n\t\t\t      - name: springboot\n\t\t\t        url: https://springboot.example.com/\n\t\t\t        bar:\n\t\t\t          - bar1: baz\n\t\t\t          - bar2: bling\n\t\t\tempty: \"\"\n\t\t\tnull-value: null\n\t\t\temptylist: []\n\t\t\temptymap: {}\n\t\t\t---\n\n\t\t\tspring:\n\t\t\t  profiles: development\n\t\t\tname: Test Name\n\n\t\t\t---\n\t\t\t\"\"\")\n\tprivate @interface WithTestYamlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/PropertiesPropertySourceLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesPropertySourceLoader}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass PropertiesPropertySourceLoaderTests {\n\n\tprivate final PropertiesPropertySourceLoader loader = new PropertiesPropertySourceLoader();\n\n\t@Test\n\tvoid getFileExtensions() {\n\t\tassertThat(this.loader.getFileExtensions()).isEqualTo(new String[] { \"properties\", \"xml\" });\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.properties\", content = \"test=properties\")\n\tvoid loadProperties() throws Exception {\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"test.properties\", new ClassPathResource(\"test.properties\"));\n\t\tPropertySource<?> source = loaded.get(0);\n\t\tassertThat(source.getProperty(\"test\")).isEqualTo(\"properties\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.properties\", content = \"\"\"\n\t\t\t#---\n\t\t\t#test\n\t\t\tblah=hello world\n\t\t\tbar=baz\n\t\t\thello=world\n\t\t\t#---\n\t\t\tfoo=bar\n\t\t\tbling=biz\n\t\t\t#comment1\n\t\t\t#comment2\n\t\t\t\"\"\")\n\tvoid loadMultiDocumentPropertiesWithSeparatorAtTheBeginningOfFile() throws Exception {\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"test.properties\", new ClassPathResource(\"test.properties\"));\n\t\tassertThat(loaded).hasSize(2);\n\t\tPropertySource<?> source1 = loaded.get(0);\n\t\tPropertySource<?> source2 = loaded.get(1);\n\t\tassertThat(source1.getProperty(\"blah\")).isEqualTo(\"hello world\");\n\t\tassertThat(source2.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.properties\", content = \"\"\"\n\t\t\t#test\n\t\t\tblah=hello world\n\t\t\tbar=baz\n\t\t\thello=world\n\t\t\t#---\n\t\t\tfoo=bar\n\t\t\tbling=biz\n\t\t\t#comment1\n\t\t\t#comment2\n\t\t\t#---\n\t\t\t\"\"\")\n\tvoid loadMultiDocumentProperties() throws Exception {\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"test.properties\", new ClassPathResource(\"test.properties\"));\n\t\tassertThat(loaded).hasSize(2);\n\t\tPropertySource<?> source1 = loaded.get(0);\n\t\tPropertySource<?> source2 = loaded.get(1);\n\t\tassertThat(source1.getProperty(\"blah\")).isEqualTo(\"hello world\");\n\t\tassertThat(source2.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.properties\", content = \"\"\"\n\n\t\t\t#---\n\t\t\t#test\n\t\t\tblah=hello world\n\t\t\tbar=baz\n\t\t\thello=world\n\t\t\t#---\n\t\t\t#---\n\t\t\tfoo=bar\n\t\t\tbling=biz\n\t\t\t#comment1\n\t\t\t#comment2\n\t\t\t\"\"\")\n\tvoid loadMultiDocumentPropertiesWithEmptyDocument() throws Exception {\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"test.properties\", new ClassPathResource(\"test.properties\"));\n\t\tassertThat(loaded).hasSize(2);\n\t\tPropertySource<?> source1 = loaded.get(0);\n\t\tPropertySource<?> source2 = loaded.get(1);\n\t\tassertThat(source1.getProperty(\"blah\")).isEqualTo(\"hello world\");\n\t\tassertThat(source2.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n\t\t\t<properties>\n\t\t\t\t<entry key=\"test\">xml</entry>\n\t\t\t</properties>\n\t\t\t\"\"\")\n\tvoid loadXml() throws Exception {\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"test.xml\", new ClassPathResource(\"test.xml\"));\n\t\tPropertySource<?> source = loaded.get(0);\n\t\tassertThat(source.getProperty(\"test\")).isEqualTo(\"xml\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test.properties\", content = \"\"\"\n\t\t\tone=1\n\t\t\tnone\n\t\t\tzero=\n\t\t\ttwo=2\n\t\t\t\"\"\")\n\tvoid loadWithEmptyValues() throws Exception {\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"test.properties\", new ClassPathResource(\"test.properties\"));\n\t\tPropertySource<?> source = loaded.get(0);\n\t\tassertThat(source.getProperty(\"one\")).isEqualTo(\"1\");\n\t\tassertThat(source.getProperty(\"none\")).isEqualTo(\"\");\n\t\tassertThat(source.getProperty(\"zero\")).isEqualTo(\"\");\n\t\tassertThat(source.getProperty(\"two\")).isEqualTo(\"2\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/RandomValuePropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.Collections;\nimport java.util.Random;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link RandomValuePropertySource}.\n *\n * @author Dave Syer\n * @author Matt Benson\n * @author Moritz Halbritter\n */\nclass RandomValuePropertySourceTests {\n\n\tprivate final RandomValuePropertySource source = new RandomValuePropertySource();\n\n\t@Test\n\tvoid getPropertyWhenNotRandomReturnsNull() {\n\t\tassertThat(this.source.getProperty(\"foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenStringReturnsValue() {\n\t\tassertThat(this.source.getProperty(\"random.string\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenIntReturnsValue() {\n\t\tInteger value = (Integer) this.source.getProperty(\"random.int\");\n\t\tassertThat(value).isNotNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenUuidReturnsValue() {\n\t\tString value = (String) this.source.getProperty(\"random.uuid\");\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(UUID.fromString(value)).isNotNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenIntRangeReturnsValue() {\n\t\tInteger value = (Integer) this.source.getProperty(\"random.int[4,10]\");\n\t\tassertThat(value).isNotNull();\n\t\tassertThat(value).isGreaterThanOrEqualTo(4);\n\t\tassertThat(value).isLessThan(10);\n\t}\n\n\t@Test\n\tvoid intRangeWhenLowerBoundEqualsUpperBoundShouldFailWithIllegalArgumentException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.source.getProperty(\"random.int[4,4]\"))\n\t\t\t.withMessage(\"Lower bound must be less than upper bound.\");\n\t}\n\n\t@Test\n\tvoid intRangeWhenLowerBoundNegative() {\n\t\tInteger value = (Integer) this.source.getProperty(\"random.int[-4,4]\");\n\t\tassertThat(value).isGreaterThanOrEqualTo(-4);\n\t\tassertThat(value).isLessThan(4);\n\t}\n\n\t@Test\n\tvoid getPropertyWhenIntMaxReturnsValue() {\n\t\tInteger value = (Integer) this.source.getProperty(\"random.int(10)\");\n\t\tassertThat(value).isNotNull().isLessThan(10);\n\t}\n\n\t@Test\n\tvoid intMaxZero() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.source.getProperty(\"random.int(0)\"))\n\t\t\t.withMessage(\"Bound must be positive.\");\n\t}\n\n\t@Test\n\tvoid intNegativeBound() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.source.getProperty(\"random.int(-5)\"))\n\t\t\t.withMessage(\"Bound must be positive.\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenLongReturnsValue() {\n\t\tLong value = (Long) this.source.getProperty(\"random.long\");\n\t\tassertThat(value).isNotNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenLongRangeReturnsValue() {\n\t\tLong value = (Long) this.source.getProperty(\"random.long[4,10]\");\n\t\tassertThat(value).isNotNull().isBetween(4L, 10L);\n\t}\n\n\t@Test\n\tvoid longRangeWhenLowerBoundEqualsUpperBoundShouldFailWithIllegalArgumentException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.source.getProperty(\"random.long[4,4]\"))\n\t\t\t.withMessage(\"Lower bound must be less than upper bound.\");\n\t}\n\n\t@Test\n\tvoid longRangeWhenLowerBoundNegative() {\n\t\tLong value = (Long) this.source.getProperty(\"random.long[-4,4]\");\n\t\tassertThat(value).isGreaterThanOrEqualTo(-4);\n\t\tassertThat(value).isLessThan(4);\n\t}\n\n\t@Test\n\tvoid getPropertyWhenLongMaxReturnsValue() {\n\t\tLong value = (Long) this.source.getProperty(\"random.long(10)\");\n\t\tassertThat(value).isNotNull().isLessThan(10L);\n\t}\n\n\t@Test\n\tvoid longMaxZero() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.source.getProperty(\"random.long(0)\"))\n\t\t\t.withMessage(\"Bound must be positive.\");\n\t}\n\n\t@Test\n\tvoid longNegativeBound() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.source.getProperty(\"random.long(-5)\"))\n\t\t\t.withMessage(\"Bound must be positive.\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenLongOverflowReturnsValue() {\n\t\tRandomValuePropertySource source = spy(this.source);\n\t\tgiven(source.getSource()).willReturn(new Random() {\n\n\t\t\t@Override\n\t\t\tpublic long nextLong() {\n\t\t\t\t// constant that used to become -8, now becomes 8\n\t\t\t\treturn Long.MIN_VALUE;\n\t\t\t}\n\n\t\t});\n\t\tLong value = (Long) source.getProperty(\"random.long(10)\");\n\t\tassertThat(value).isNotNull().isGreaterThanOrEqualTo(0L).isLessThan(10L);\n\t\tvalue = (Long) source.getProperty(\"random.long[4,10]\");\n\t\tassertThat(value).isNotNull().isGreaterThanOrEqualTo(4L).isLessThan(10L);\n\t}\n\n\t@Test\n\tvoid addToEnvironmentAddsSource() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tRandomValuePropertySource.addToEnvironment(environment);\n\t\tassertThat(environment.getProperty(\"random.string\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid addToEnvironmentWhenAlreadyAddedAddsSource() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tRandomValuePropertySource.addToEnvironment(environment);\n\t\tRandomValuePropertySource.addToEnvironment(environment);\n\t\tassertThat(environment.getProperty(\"random.string\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid addToEnvironmentAddsAfterSystemEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tCollections.emptyMap()));\n\t\tRandomValuePropertySource.addToEnvironment(environment);\n\t\tassertThat(environment.getPropertySources().stream().map(PropertySource::getName)).containsExactly(\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\tRandomValuePropertySource.RANDOM_PROPERTY_SOURCE_NAME, \"mockProperties\");\n\t}\n\n\t@Test\n\tvoid randomStringIs32CharsLong() {\n\t\tassertThat(this.source.getProperty(\"random.string\")).asString().hasSize(32);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/env/YamlPropertySourceLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.env;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link YamlPropertySourceLoader}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass YamlPropertySourceLoaderTests {\n\n\tprivate final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();\n\n\t@Test\n\tvoid load() throws Exception {\n\t\tByteArrayResource resource = new ByteArrayResource(\"foo:\\n  bar: spam\".getBytes());\n\t\tPropertySource<?> source = this.loader.load(\"resource\", resource).get(0);\n\t\tassertThat(source).isNotNull();\n\t\tassertThat(source.getProperty(\"foo.bar\")).isEqualTo(\"spam\");\n\t}\n\n\t@Test\n\tvoid orderedItems() throws Exception {\n\t\tStringBuilder yaml = new StringBuilder();\n\t\tList<String> expected = new ArrayList<>();\n\t\tfor (char c = 'a'; c <= 'z'; c++) {\n\t\t\tyaml.append(c).append(\": value\").append(c).append(\"\\n\");\n\t\t\texpected.add(String.valueOf(c));\n\t\t}\n\t\tByteArrayResource resource = new ByteArrayResource(yaml.toString().getBytes());\n\t\tEnumerablePropertySource<?> source = (EnumerablePropertySource<?>) this.loader.load(\"resource\", resource)\n\t\t\t.get(0);\n\t\tassertThat(source).isNotNull();\n\t\tassertThat(source.getPropertyNames()).isEqualTo(StringUtils.toStringArray(expected));\n\t}\n\n\t@Test\n\tvoid mergeItems() throws Exception {\n\t\tStringBuilder yaml = new StringBuilder();\n\t\tyaml.append(\"foo:\\n  bar: spam\\n\");\n\t\tyaml.append(\"---\\n\");\n\t\tyaml.append(\"foo:\\n  baz: wham\\n\");\n\t\tByteArrayResource resource = new ByteArrayResource(yaml.toString().getBytes());\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"resource\", resource);\n\t\tassertThat(loaded).hasSize(2);\n\t\tassertThat(loaded.get(0).getProperty(\"foo.bar\")).isEqualTo(\"spam\");\n\t\tassertThat(loaded.get(1).getProperty(\"foo.baz\")).isEqualTo(\"wham\");\n\t}\n\n\t@Test\n\tvoid timestampLikeItemsDoNotBecomeDates() throws Exception {\n\t\tByteArrayResource resource = new ByteArrayResource(\"foo: 2015-01-28\".getBytes());\n\t\tPropertySource<?> source = this.loader.load(\"resource\", resource).get(0);\n\t\tassertThat(source).isNotNull();\n\t\tassertThat(source.getProperty(\"foo\")).isEqualTo(\"2015-01-28\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test-yaml.yml\", content = \"\"\"\n\t\t\ta: b\n\t\t\t---\n\t\t\tc: d\n\t\t\te: f\n\t\t\t\"\"\")\n\tvoid loadOriginAware() throws Exception {\n\t\tResource resource = new ClassPathResource(\"test-yaml.yml\");\n\t\tList<PropertySource<?>> loaded = this.loader.load(\"resource\", resource);\n\t\tfor (PropertySource<?> source : loaded) {\n\t\t\tEnumerablePropertySource<?> enumerableSource = (EnumerablePropertySource<?>) source;\n\t\t\tfor (String name : enumerableSource.getPropertyNames()) {\n\t\t\t\tSystem.out.println(name + \" = \" + enumerableSource.getProperty(name));\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/BuildPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BuildProperties}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass BuildPropertiesTests {\n\n\t@Test\n\tvoid basicInfo() {\n\t\tInstant instant = Instant.now();\n\t\tBuildProperties properties = new BuildProperties(\n\t\t\t\tcreateProperties(\"com.example\", \"demo\", \"0.0.1\", DateTimeFormatter.ISO_INSTANT.format(instant)));\n\t\tassertThat(properties.getGroup()).isEqualTo(\"com.example\");\n\t\tassertThat(properties.getArtifact()).isEqualTo(\"demo\");\n\t\tassertThat(properties.getVersion()).isEqualTo(\"0.0.1\");\n\t\tassertThat(properties.getTime()).isEqualTo(instant.truncatedTo(ChronoUnit.MILLIS));\n\t\tassertThat(properties.get(\"time\")).isEqualTo(String.valueOf(instant.toEpochMilli()));\n\t}\n\n\t@Test\n\tvoid noInfo() {\n\t\tBuildProperties properties = new BuildProperties(new Properties());\n\t\tassertThat(properties.getGroup()).isNull();\n\t\tassertThat(properties.getArtifact()).isNull();\n\t\tassertThat(properties.getVersion()).isNull();\n\t\tassertThat(properties.getTime()).isNull();\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew BuildProperties.BuildPropertiesRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"META-INF/build-info.properties\"))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n\tprivate static Properties createProperties(String group, String artifact, String version, String buildTime) {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"group\", group);\n\t\tproperties.put(\"artifact\", artifact);\n\t\tproperties.put(\"version\", version);\n\t\tproperties.put(\"time\", buildTime);\n\t\treturn properties;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/GitPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GitProperties}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass GitPropertiesTests {\n\n\t@Test\n\tvoid basicInfo() {\n\t\tGitProperties properties = new GitProperties(\n\t\t\t\tcreateProperties(\"master\", \"abcdefghijklmno\", \"abcdefg\", \"1457527123\"));\n\t\tassertThat(properties.getBranch()).isEqualTo(\"master\");\n\t\tassertThat(properties.getCommitId()).isEqualTo(\"abcdefghijklmno\");\n\t\tassertThat(properties.getShortCommitId()).isEqualTo(\"abcdefg\");\n\t}\n\n\t@Test\n\tvoid noInfo() {\n\t\tGitProperties properties = new GitProperties(new Properties());\n\t\tassertThat(properties.getBranch()).isNull();\n\t\tassertThat(properties.getCommitId()).isNull();\n\t\tassertThat(properties.getShortCommitId()).isNull();\n\t\tassertThat(properties.getCommitTime()).isNull();\n\t}\n\n\t@Test\n\tvoid coerceEpochSecond() {\n\t\tGitProperties properties = new GitProperties(createProperties(\"master\", \"abcdefg\", null, \"1457527123\"));\n\t\tassertThat(properties.getCommitTime()).isNotNull();\n\t\tassertThat(properties.get(\"commit.time\")).isEqualTo(\"1457527123000\");\n\t\tassertThat(properties.getCommitTime().toEpochMilli()).isEqualTo(1457527123000L);\n\t}\n\n\t@Test\n\tvoid coerceLegacyDateString() {\n\t\tGitProperties properties = new GitProperties(\n\t\t\t\tcreateProperties(\"master\", \"abcdefg\", null, \"2016-03-04T14:36:33+0100\"));\n\t\tassertThat(properties.getCommitTime()).isNotNull();\n\t\tassertThat(properties.get(\"commit.time\")).isEqualTo(\"1457098593000\");\n\t\tassertThat(properties.getCommitTime().toEpochMilli()).isEqualTo(1457098593000L);\n\t}\n\n\t@Test\n\tvoid coerceDateString() {\n\t\tGitProperties properties = new GitProperties(\n\t\t\t\tcreateProperties(\"master\", \"abcdefg\", null, \"2016-03-04T14:36:33+01:00\"));\n\t\tassertThat(properties.getCommitTime()).isNotNull();\n\t\tassertThat(properties.get(\"commit.time\")).isEqualTo(\"1457098593000\");\n\t\tassertThat(properties.getCommitTime().toEpochMilli()).isEqualTo(1457098593000L);\n\t}\n\n\t@Test\n\tvoid coerceUnsupportedFormat() {\n\t\tGitProperties properties = new GitProperties(\n\t\t\t\tcreateProperties(\"master\", \"abcdefg\", null, \"2016-03-04 15:22:24\"));\n\t\tassertThat(properties.getCommitTime()).isNull();\n\t\tassertThat(properties.get(\"commit.time\")).isEqualTo(\"2016-03-04 15:22:24\");\n\t}\n\n\t@Test\n\tvoid shortCommitUsedIfPresent() {\n\t\tGitProperties properties = new GitProperties(\n\t\t\t\tcreateProperties(\"master\", \"abcdefghijklmno\", \"abcdefgh\", \"1457527123\"));\n\t\tassertThat(properties.getCommitId()).isEqualTo(\"abcdefghijklmno\");\n\t\tassertThat(properties.getShortCommitId()).isEqualTo(\"abcdefgh\");\n\t}\n\n\t@Test\n\tvoid shortenCommitIdShorterThan7() {\n\t\tGitProperties properties = new GitProperties(createProperties(\"master\", \"abc\", null, \"1457527123\"));\n\t\tassertThat(properties.getCommitId()).isEqualTo(\"abc\");\n\t\tassertThat(properties.getShortCommitId()).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid shortenCommitIdLongerThan7() {\n\t\tGitProperties properties = new GitProperties(createProperties(\"master\", \"abcdefghijklmno\", null, \"1457527123\"));\n\t\tassertThat(properties.getCommitId()).isEqualTo(\"abcdefghijklmno\");\n\t\tassertThat(properties.getShortCommitId()).isEqualTo(\"abcdefg\");\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew GitProperties.GitPropertiesRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"git.properties\")).accepts(runtimeHints);\n\t}\n\n\tprivate static Properties createProperties(String branch, String commitId, @Nullable String commitIdAbbrev,\n\t\t\tString commitTime) {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"branch\", branch);\n\t\tproperties.put(\"commit.id\", commitId);\n\t\tif (commitIdAbbrev != null) {\n\t\t\tproperties.put(\"commit.id.abbrev\", commitIdAbbrev);\n\t\t}\n\t\tproperties.put(\"commit.time\", commitTime);\n\t\treturn properties;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/InfoPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link InfoProperties}.\n *\n * @author Stephane Nicoll\n */\nclass InfoPropertiesTests {\n\n\t@Test\n\tvoid inputIsImmutable() {\n\t\tProperties p = new Properties();\n\t\tp.put(\"foo\", \"bar\");\n\t\tInfoProperties infoProperties = new InfoProperties(p);\n\t\tassertThat(infoProperties.get(\"foo\")).isEqualTo(\"bar\");\n\t\tp.remove(\"foo\");\n\t\tassertThat(infoProperties.get(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid iterator() {\n\t\tProperties p = new Properties();\n\t\tp.put(\"one\", \"first\");\n\t\tp.put(\"two\", \"second\");\n\t\tInfoProperties infoProperties = new InfoProperties(p);\n\t\tProperties copy = new Properties();\n\t\tfor (InfoProperties.Entry entry : infoProperties) {\n\t\t\tcopy.put(entry.getKey(), entry.getValue());\n\t\t}\n\t\tassertThat(p).isEqualTo(copy);\n\t}\n\n\t@Test\n\tvoid removeNotSupported() {\n\t\tProperties p = new Properties();\n\t\tp.put(\"foo\", \"bar\");\n\t\tInfoProperties infoProperties = new InfoProperties(p);\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(infoProperties.iterator()::remove);\n\t}\n\n\t@Test\n\tvoid toPropertySources() {\n\t\tProperties p = new Properties();\n\t\tp.put(\"one\", \"first\");\n\t\tp.put(\"two\", \"second\");\n\t\tInfoProperties infoProperties = new MyInfoProperties(p);\n\t\tPropertySource<?> source = infoProperties.toPropertySource();\n\t\tassertThat(source.getProperty(\"one\")).isEqualTo(\"first\");\n\t\tassertThat(source.getProperty(\"two\")).isEqualTo(\"second\");\n\t\tassertThat(source.getName()).isEqualTo(\"MyInfoProperties\");\n\t}\n\n\tstatic class MyInfoProperties extends InfoProperties {\n\n\t\tMyInfoProperties(Properties entries) {\n\t\t\tsuper(entries);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/JavaInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JavaInfo}.\n *\n * @author Jonatan Ivanov\n * @author Stephane Nicoll\n */\nclass JavaInfoTests {\n\n\t@Test\n\tvoid javaInfoIsAvailable() {\n\t\tJavaInfo javaInfo = new JavaInfo();\n\t\tassertThat(javaInfo.getVersion()).isEqualTo(System.getProperty(\"java.version\"));\n\t\tassertThat(javaInfo.getVendor()).satisfies((vendorInfo) -> {\n\t\t\tassertThat(vendorInfo.getName()).isEqualTo(System.getProperty(\"java.vendor\"));\n\t\t\tassertThat(vendorInfo.getVersion()).isEqualTo(System.getProperty(\"java.vendor.version\"));\n\t\t});\n\t\tassertThat(javaInfo.getRuntime()).satisfies((jreInfo) -> {\n\t\t\tassertThat(jreInfo.getName()).isEqualTo(System.getProperty(\"java.runtime.name\"));\n\t\t\tassertThat(jreInfo.getVersion()).isEqualTo(System.getProperty(\"java.runtime.version\"));\n\t\t});\n\t\tassertThat(javaInfo.getJvm()).satisfies((jvmInfo) -> {\n\t\t\tassertThat(jvmInfo.getName()).isEqualTo(System.getProperty(\"java.vm.name\"));\n\t\t\tassertThat(jvmInfo.getVendor()).isEqualTo(System.getProperty(\"java.vm.vendor\"));\n\t\t\tassertThat(jvmInfo.getVersion()).isEqualTo(System.getProperty(\"java.vm.version\"));\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/OsInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OsInfo}.\n *\n * @author Jonatan Ivanov\n */\nclass OsInfoTests {\n\n\t@Test\n\tvoid osInfoIsAvailable() {\n\t\tOsInfo osInfo = new OsInfo();\n\t\tassertThat(osInfo.getName()).isEqualTo(System.getProperty(\"os.name\"));\n\t\tassertThat(osInfo.getVersion()).isEqualTo(System.getProperty(\"os.version\"));\n\t\tassertThat(osInfo.getArch()).isEqualTo(System.getProperty(\"os.arch\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/ProcessInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.info.ProcessInfo.MemoryInfo;\nimport org.springframework.boot.info.ProcessInfo.MemoryInfo.MemoryUsageInfo;\nimport org.springframework.boot.info.ProcessInfo.VirtualThreadsInfo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ProcessInfo}.\n *\n * @author Jonatan Ivanov\n * @author Andrey Litvitski\n */\nclass ProcessInfoTests {\n\n\t@Test\n\tvoid processInfoIsAvailable() {\n\t\tProcessInfo processInfo = new ProcessInfo();\n\t\tassertThat(processInfo.getCpus()).isEqualTo(Runtime.getRuntime().availableProcessors());\n\t\tassertThat(processInfo.getOwner()).isEqualTo(ProcessHandle.current().info().user().orElse(null));\n\t\tassertThat(processInfo.getPid()).isEqualTo(ProcessHandle.current().pid());\n\t\tassertThat(processInfo.getParentPid())\n\t\t\t.isEqualTo(ProcessHandle.current().parent().map(ProcessHandle::pid).orElse(null));\n\t\tif (ProcessHandle.current().info().startInstant().isPresent()) {\n\t\t\tassertThat(processInfo.getUptime()).isPositive();\n\t\t\tassertThat(processInfo.getStartTime()).isInThePast();\n\t\t\tassertThat(processInfo.getCurrentTime()).isAfter(processInfo.getStartTime());\n\t\t}\n\t\telse {\n\t\t\tassertThat(processInfo.getUptime()).isNull();\n\t\t\tassertThat(processInfo.getStartTime()).isNull();\n\t\t\tassertThat(processInfo.getCurrentTime()).isNotNull();\n\t\t}\n\t\tassertThat(processInfo.getTimezone()).isNotNull();\n\t\tassertThat(processInfo.getLocale()).isNotNull();\n\t\tassertThat(processInfo.getWorkingDirectory()).isNotBlank();\n\t}\n\n\t@Test\n\tvoid memoryInfoIsAvailable() {\n\t\tProcessInfo processInfo = new ProcessInfo();\n\t\tMemoryUsageInfo heapUsageInfo = processInfo.getMemory().getHeap();\n\t\tassertThat(heapUsageInfo.getInit()).isPositive().isLessThanOrEqualTo(heapUsageInfo.getMax());\n\t\tassertThat(heapUsageInfo.getUsed()).isPositive().isLessThanOrEqualTo(heapUsageInfo.getCommitted());\n\t\tassertThat(heapUsageInfo.getCommitted()).isPositive().isLessThanOrEqualTo(heapUsageInfo.getMax());\n\t\tassertThat(heapUsageInfo.getMax()).isPositive();\n\t\tMemoryUsageInfo nonHeapUsageInfo = processInfo.getMemory().getNonHeap();\n\t\tassertThat(nonHeapUsageInfo.getInit()).isPositive();\n\t\tassertThat(nonHeapUsageInfo.getUsed()).isPositive().isLessThanOrEqualTo(nonHeapUsageInfo.getCommitted());\n\t\tassertThat(nonHeapUsageInfo.getCommitted()).isPositive();\n\t\tassertThat(nonHeapUsageInfo.getMax()).isEqualTo(-1);\n\t\tList<MemoryInfo.GarbageCollectorInfo> garbageCollectors = processInfo.getMemory().getGarbageCollectors();\n\t\tassertThat(garbageCollectors).isNotEmpty();\n\t\tassertThat(garbageCollectors).allSatisfy((garbageCollector) -> {\n\t\t\tassertThat(garbageCollector.getName()).isNotEmpty();\n\t\t\tassertThat(garbageCollector.getCollectionCount()).isNotNegative();\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_24)\n\tvoid virtualThreadsInfoIfAvailable() {\n\t\tProcessInfo processInfo = new ProcessInfo();\n\t\tVirtualThreadsInfo virtualThreadsInfo = processInfo.getVirtualThreads();\n\t\tassertThat(virtualThreadsInfo).isNotNull();\n\t\tassertThat(virtualThreadsInfo.getMounted()).isGreaterThanOrEqualTo(0);\n\t\tassertThat(virtualThreadsInfo.getQueued()).isGreaterThanOrEqualTo(0);\n\t\tassertThat(virtualThreadsInfo.getParallelism()).isGreaterThan(0);\n\t\tassertThat(virtualThreadsInfo.getPoolSize()).isGreaterThanOrEqualTo(0);\n\t}\n\n\t@Test\n\t@EnabledForJreRange(max = JRE.JAVA_23)\n\tvoid virtualThreadsInfoIfNotAvailable() {\n\t\tProcessInfo processInfo = new ProcessInfo();\n\t\tassertThat(processInfo.getVirtualThreads()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/info/SslInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.info;\n\nimport java.time.Clock;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.info.SslInfo.BundleInfo;\nimport org.springframework.boot.info.SslInfo.CertificateChainInfo;\nimport org.springframework.boot.info.SslInfo.CertificateInfo;\nimport org.springframework.boot.info.SslInfo.CertificateValidityInfo.Status;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslInfo}.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass SslInfoTests {\n\n\tprivate static final Clock CLOCK = Clock.fixed(Instant.parse(\"2025-06-18T13:00:00Z\"), ZoneId.of(\"UTC\"));\n\n\t@Test\n\t@WithPackageResources(\"test.p12\")\n\tvoid validCertificatesShouldProvideSslInfo() {\n\t\tSslInfo sslInfo = createSslInfo(\"classpath:test.p12\");\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tBundleInfo bundle = sslInfo.getBundles().get(0);\n\t\tassertThat(bundle.getName()).isEqualTo(\"test-0\");\n\t\tassertThat(bundle.getCertificateChains()).hasSize(4);\n\t\tassertThat(bundle.getCertificateChains().get(0).getAlias()).isEqualTo(\"spring-boot\");\n\t\tassertThat(bundle.getCertificateChains().get(0).getCertificates()).hasSize(1);\n\t\tassertThat(bundle.getCertificateChains().get(1).getAlias()).isEqualTo(\"test-alias\");\n\t\tassertThat(bundle.getCertificateChains().get(1).getCertificates()).hasSize(1);\n\t\tassertThat(bundle.getCertificateChains().get(2).getAlias()).isEqualTo(\"spring-boot-cert\");\n\t\tassertThat(bundle.getCertificateChains().get(2).getCertificates()).hasSize(1);\n\t\tassertThat(bundle.getCertificateChains().get(3).getAlias()).isEqualTo(\"test-alias-cert\");\n\t\tassertThat(bundle.getCertificateChains().get(3).getCertificates()).hasSize(1);\n\t\tCertificateInfo cert1 = bundle.getCertificateChains().get(0).getCertificates().get(0);\n\t\tassertThat(cert1.getSubject()).isEqualTo(\"CN=localhost,OU=Spring,O=VMware,L=Palo Alto,ST=California,C=US\");\n\t\tassertThat(cert1.getIssuer()).isEqualTo(cert1.getSubject());\n\t\tassertThat(cert1.getSerialNumber()).isNotEmpty();\n\t\tassertThat(cert1.getVersion()).isEqualTo(\"V3\");\n\t\tassertThat(cert1.getSignatureAlgorithmName()).isEqualTo(\"SHA256withRSA\");\n\t\tassertThat(cert1.getValidityStarts()).isBefore(CLOCK.instant());\n\t\tassertThat(cert1.getValidityEnds()).isAfter(CLOCK.instant());\n\t\tassertThat(cert1.getValidity()).isNotNull();\n\t\tassertThat(cert1.getValidity().getStatus()).isSameAs(Status.VALID);\n\t\tassertThat(cert1.getValidity().getMessage()).isNull();\n\t\tCertificateInfo cert2 = bundle.getCertificateChains().get(1).getCertificates().get(0);\n\t\tassertThat(cert2.getSubject()).isEqualTo(\"CN=localhost,OU=Spring,O=VMware,L=Palo Alto,ST=California,C=US\");\n\t\tassertThat(cert2.getIssuer()).isEqualTo(cert2.getSubject());\n\t\tassertThat(cert2.getSerialNumber()).isNotEmpty();\n\t\tassertThat(cert2.getVersion()).isEqualTo(\"V3\");\n\t\tassertThat(cert2.getSignatureAlgorithmName()).isEqualTo(\"SHA256withRSA\");\n\t\tassertThat(cert2.getValidityStarts()).isBefore(CLOCK.instant());\n\t\tassertThat(cert2.getValidityEnds()).isAfter(CLOCK.instant());\n\t\tassertThat(cert2.getValidity()).isNotNull();\n\t\tassertThat(cert2.getValidity().getStatus()).isSameAs(Status.VALID);\n\t\tassertThat(cert2.getValidity().getMessage()).isNull();\n\t\tassertThat(bundle.getTrustStoreCertificateChains()).isEmpty();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-not-yet-valid.p12\")\n\tvoid notYetValidCertificateShouldProvideSslInfo() {\n\t\tSslInfo sslInfo = createSslInfo(\"classpath:test-not-yet-valid.p12\");\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tBundleInfo bundle = sslInfo.getBundles().get(0);\n\t\tassertThat(bundle.getName()).isEqualTo(\"test-0\");\n\t\tassertThat(bundle.getCertificateChains()).hasSize(1);\n\t\tCertificateChainInfo certificateChain = bundle.getCertificateChains().get(0);\n\t\tassertThat(certificateChain.getAlias()).isEqualTo(\"spring-boot\");\n\t\tList<CertificateInfo> certs = certificateChain.getCertificates();\n\t\tassertThat(certs).hasSize(1);\n\t\tCertificateInfo cert = certs.get(0);\n\t\tassertThat(cert.getSubject()).isEqualTo(\"CN=localhost,OU=Spring,O=VMware,L=Palo Alto,ST=California,C=US\");\n\t\tassertThat(cert.getIssuer()).isEqualTo(cert.getSubject());\n\t\tassertThat(cert.getSerialNumber()).isNotEmpty();\n\t\tassertThat(cert.getVersion()).isEqualTo(\"V3\");\n\t\tassertThat(cert.getSignatureAlgorithmName()).isEqualTo(\"SHA256withRSA\");\n\t\tassertThat(cert.getValidityStarts()).isAfter(CLOCK.instant());\n\t\tassertThat(cert.getValidityEnds()).isAfter(CLOCK.instant());\n\t\tassertThat(cert.getValidity()).isNotNull();\n\t\tassertThat(cert.getValidity().getStatus()).isSameAs(Status.NOT_YET_VALID);\n\t\tassertThat(cert.getValidity().getMessage()).startsWith(\"Not valid before\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-expired.p12\")\n\tvoid expiredCertificateShouldProvideSslInfo() {\n\t\tSslInfo sslInfo = createSslInfo(\"classpath:test-expired.p12\");\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tBundleInfo bundle = sslInfo.getBundles().get(0);\n\t\tassertThat(bundle.getName()).isEqualTo(\"test-0\");\n\t\tassertThat(bundle.getCertificateChains()).hasSize(1);\n\t\tCertificateChainInfo certificateChain = bundle.getCertificateChains().get(0);\n\t\tassertThat(certificateChain.getAlias()).isEqualTo(\"spring-boot\");\n\t\tList<CertificateInfo> certs = certificateChain.getCertificates();\n\t\tassertThat(certs).hasSize(1);\n\t\tCertificateInfo cert = certs.get(0);\n\t\tassertThat(cert.getSubject()).isEqualTo(\"CN=localhost,OU=Spring,O=VMware,L=Palo Alto,ST=California,C=US\");\n\t\tassertThat(cert.getIssuer()).isEqualTo(cert.getSubject());\n\t\tassertThat(cert.getSerialNumber()).isNotEmpty();\n\t\tassertThat(cert.getVersion()).isEqualTo(\"V3\");\n\t\tassertThat(cert.getSignatureAlgorithmName()).isEqualTo(\"SHA256withRSA\");\n\t\tassertThat(cert.getValidityStarts()).isBefore(CLOCK.instant());\n\t\tassertThat(cert.getValidityEnds()).isBefore(CLOCK.instant());\n\t\tassertThat(cert.getValidity()).isNotNull();\n\t\tassertThat(cert.getValidity().getStatus()).isSameAs(Status.EXPIRED);\n\t\tassertThat(cert.getValidity().getMessage()).startsWith(\"Not valid after\");\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test.p12\", \"test-not-yet-valid.p12\", \"test-expired.p12\", \"will-expire-soon.p12\" })\n\tvoid multipleBundlesShouldProvideSslInfo() {\n\t\tSslInfo sslInfo = createSslInfo(\"classpath:test.p12\", \"classpath:test-not-yet-valid.p12\",\n\t\t\t\t\"classpath:test-expired.p12\", \"classpath:will-expire-soon.p12\");\n\t\tassertThat(sslInfo.getBundles()).hasSize(4);\n\t\tassertThat(sslInfo.getBundles()).allSatisfy((bundle) -> assertThat(bundle.getName()).startsWith(\"test-\"));\n\t\tList<CertificateInfo> certs = sslInfo.getBundles()\n\t\t\t.stream()\n\t\t\t.flatMap((bundle) -> bundle.getCertificateChains().stream())\n\t\t\t.flatMap((certificateChain) -> certificateChain.getCertificates().stream())\n\t\t\t.toList();\n\t\tassertThat(certs).hasSize(7);\n\t\tassertThat(certs).allSatisfy((cert) -> {\n\t\t\tassertThat(cert.getSubject()).isEqualTo(\"CN=localhost,OU=Spring,O=VMware,L=Palo Alto,ST=California,C=US\");\n\t\t\tassertThat(cert.getIssuer()).isEqualTo(cert.getSubject());\n\t\t\tassertThat(cert.getSerialNumber()).isNotEmpty();\n\t\t\tassertThat(cert.getVersion()).isEqualTo(\"V3\");\n\t\t\tassertThat(cert.getSignatureAlgorithmName()).isNotEmpty();\n\t\t\tassertThat(cert.getValidity()).isNotNull();\n\t\t});\n\t\tassertThat(certs).anySatisfy((cert) -> {\n\t\t\tassertThat(cert.getValidityStarts()).isBefore(CLOCK.instant());\n\t\t\tassertThat(cert.getValidityEnds()).isAfter(CLOCK.instant());\n\t\t\tassertThat(cert.getValidity()).isNotNull();\n\t\t\tassertThat(cert.getValidity().getStatus()).isSameAs(Status.VALID);\n\t\t\tassertThat(cert.getValidity().getMessage()).isNull();\n\t\t});\n\t\tassertThat(certs).satisfiesOnlyOnce((cert) -> {\n\t\t\tassertThat(cert.getValidityStarts()).isAfter(CLOCK.instant());\n\t\t\tassertThat(cert.getValidityEnds()).isAfter(CLOCK.instant());\n\t\t\tassertThat(cert.getValidity()).isNotNull();\n\t\t\tassertThat(cert.getValidity().getStatus()).isSameAs(Status.NOT_YET_VALID);\n\t\t\tassertThat(cert.getValidity().getMessage()).startsWith(\"Not valid before\");\n\t\t});\n\t\tassertThat(certs).satisfiesOnlyOnce((cert) -> {\n\t\t\tassertThat(cert.getValidityStarts()).isBefore(CLOCK.instant());\n\t\t\tassertThat(cert.getValidityEnds()).isBefore(CLOCK.instant());\n\t\t\tassertThat(cert.getValidity()).isNotNull();\n\t\t\tassertThat(cert.getValidity().getStatus()).isSameAs(Status.EXPIRED);\n\t\t\tassertThat(cert.getValidity().getMessage()).startsWith(\"Not valid after\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid nullKeyStore() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tsslBundleRegistry.registerBundle(\"test\", SslBundle.of(SslStoreBundle.NONE, SslBundleKey.NONE));\n\t\tSslInfo sslInfo = new SslInfo(sslBundleRegistry, CLOCK);\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tassertThat(sslInfo.getBundles().get(0).getCertificateChains()).isEmpty();\n\t\tassertThat(sslInfo.getBundles().get(0).getTrustStoreCertificateChains()).isEmpty();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.p12\")\n\tvoid trustStoreCertificatesShouldProvideSslInfo() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tJksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(\"classpath:test.p12\")\n\t\t\t.withPassword(\"secret\");\n\t\tSslStoreBundle sslStoreBundle = new JksSslStoreBundle(null, trustStoreDetails);\n\t\tsslBundleRegistry.registerBundle(\"test-trust\", SslBundle.of(sslStoreBundle));\n\t\tSslInfo sslInfo = new SslInfo(sslBundleRegistry, CLOCK);\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tBundleInfo bundle = sslInfo.getBundles().get(0);\n\t\tassertThat(bundle.getName()).isEqualTo(\"test-trust\");\n\t\tassertThat(bundle.getCertificateChains()).isEmpty();\n\t\tassertThat(bundle.getTrustStoreCertificateChains()).hasSize(4);\n\t\tassertThat(bundle.getTrustStoreCertificateChains().get(0).getAlias()).isEqualTo(\"spring-boot\");\n\t\tassertThat(bundle.getTrustStoreCertificateChains().get(1).getAlias()).isEqualTo(\"test-alias\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.p12\")\n\tvoid bothKeyStoreAndTrustStoreCertificatesShouldProvideSslInfo() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tJksSslStoreDetails storeDetails = JksSslStoreDetails.forLocation(\"classpath:test.p12\").withPassword(\"secret\");\n\t\tSslStoreBundle sslStoreBundle = new JksSslStoreBundle(storeDetails, storeDetails);\n\t\tsslBundleRegistry.registerBundle(\"test-both\", SslBundle.of(sslStoreBundle));\n\t\tSslInfo sslInfo = new SslInfo(sslBundleRegistry, CLOCK);\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tBundleInfo bundle = sslInfo.getBundles().get(0);\n\t\tassertThat(bundle.getName()).isEqualTo(\"test-both\");\n\t\tassertThat(bundle.getCertificateChains()).hasSize(4);\n\t\tassertThat(bundle.getTrustStoreCertificateChains()).hasSize(4);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"keystore.jks\", \"truststore.jks\" })\n\tvoid separateKeyStoreAndTrustStoreShouldProvideSslInfo() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(\"classpath:keystore.jks\")\n\t\t\t.withPassword(\"secret\");\n\t\tJksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(\"classpath:truststore.jks\")\n\t\t\t.withPassword(\"secret\");\n\t\tSslStoreBundle sslStoreBundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tsslBundleRegistry.registerBundle(\"test-separate\", SslBundle.of(sslStoreBundle));\n\t\tSslInfo sslInfo = new SslInfo(sslBundleRegistry, CLOCK);\n\t\tassertThat(sslInfo.getBundles()).hasSize(1);\n\t\tBundleInfo bundle = sslInfo.getBundles().get(0);\n\t\tassertThat(bundle.getName()).isEqualTo(\"test-separate\");\n\t\t// Keystore has 2 PrivateKeyEntry entries\n\t\tassertThat(bundle.getCertificateChains()).hasSize(2);\n\t\tassertThat(bundle.getCertificateChains()).allSatisfy((chain) -> {\n\t\t\tassertThat(chain.getCertificates()).hasSize(1);\n\t\t\tassertThat(chain.getCertificates().get(0).getSubject()).startsWith(\"CN=localhost\");\n\t\t});\n\t\t// Truststore has 3 trustedCertEntry entries\n\t\tassertThat(bundle.getTrustStoreCertificateChains()).hasSize(3);\n\t\tassertThat(bundle.getTrustStoreCertificateChains()).allSatisfy((chain) -> {\n\t\t\tassertThat(chain.getCertificates()).hasSize(1);\n\t\t\tassertThat(chain.getCertificates().get(0).getSubject()).startsWith(\"CN=localhost\");\n\t\t});\n\t}\n\n\tprivate SslInfo createSslInfo(String... locations) {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tfor (int i = 0; i < locations.length; i++) {\n\t\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(locations[i]).withPassword(\"secret\");\n\t\t\tSslStoreBundle sslStoreBundle = new JksSslStoreBundle(keyStoreDetails, null);\n\t\t\tsslBundleRegistry.registerBundle(\"test-%d\".formatted(i), SslBundle.of(sslStoreBundle));\n\t\t}\n\t\treturn new SslInfo(sslBundleRegistry, CLOCK);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/io/ApplicationResourceLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.Base64;\nimport java.util.Enumeration;\nimport java.util.function.UnaryOperator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ApplicationResourceLoader}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass ApplicationResourceLoaderTests {\n\n\tprivate static final String SPRING_FACTORIES = \"META-INF/spring.factories\";\n\n\tprivate static final String TEST_PROTOCOL_RESOLVERS_FACTORIES = \"META-INF/spring-test-protocol-resolvers.factories\";\n\n\tprivate static final String TEST_BASE_64_VALUE = Base64.getEncoder().encodeToString(\"test\".getBytes());\n\n\t@Test\n\tvoid getIncludesProtocolResolvers() throws IOException {\n\t\tResourceLoader loader = ApplicationResourceLoader.get();\n\t\tResource resource = loader.getResource(\"base64:\" + TEST_BASE_64_VALUE);\n\t\tassertThat(contentAsString(resource)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid shouldLoadAbsolutePath() throws IOException {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(\"/root/file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/root\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadAbsolutePathWithWorkingDirectory() throws IOException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"/root/file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/root\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadRelativeFilename() throws IOException {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(\"file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasNoParent().hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadRelativeFilenameWithWorkingDirectory() throws IOException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/working-directory\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadRelativePathWithWorkingDirectory() throws IOException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"a/file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/working-directory/a\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"a-file\")\n\tvoid shouldLoadClasspathLocations() {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(\"classpath:a-file\");\n\t\tassertThat(resource.exists()).isTrue();\n\t}\n\n\t@Test\n\tvoid shouldLoadNonExistentClasspathLocations() {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(\"classpath:doesnt-exist\");\n\t\tassertThat(resource.exists()).isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"a-file\", content = \"some content\")\n\tvoid shouldLoadClasspathLocationsWithWorkingDirectory() {\n\t\tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"classpath:a-file\");\n\t\tassertThat(resource.exists()).isTrue();\n\t}\n\n\t@Test\n\tvoid shouldLoadNonExistentClasspathLocationsWithWorkingDirectory() {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"classpath:doesnt-exist\");\n\t\tassertThat(resource.exists()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldLoadRelativeFileUris() throws IOException {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(\"file:file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasNoParent().hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadAbsoluteFileUris() throws IOException {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(\"file:/file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadRelativeFileUrisWithWorkingDirectory() throws IOException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"file:file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/working-directory\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\tvoid shouldLoadAbsoluteFileUrisWithWorkingDirectory() throws IOException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tResource resource = ApplicationResourceLoader\n\t\t\t.get(classLoader, SpringFactoriesLoader.forDefaultResourceLocation(classLoader),\n\t\t\t\t\tPath.of(\"/working-directory\"))\n\t\t\t.getResource(\"file:/file.txt\");\n\t\tassertThat(resource.isFile()).isTrue();\n\t\tassertThat(resource.getFile()).hasParent(\"/\").hasName(\"file.txt\");\n\t}\n\n\t@Test\n\t@WithResource(name = TEST_PROTOCOL_RESOLVERS_FACTORIES,\n\t\t\tcontent = \"org.springframework.core.io.ProtocolResolver=org.springframework.boot.io.ReverseStringProtocolResolver\")\n\tvoid getWithClassPathIncludesProtocolResolvers() throws IOException {\n\t\tClassLoader classLoader = new TestClassLoader(this::useTestProtocolResolversFactories);\n\t\tResourceLoader loader = ApplicationResourceLoader.get(classLoader);\n\t\tResource resource = loader.getResource(\"reverse:test\");\n\t\tassertThat(contentAsString(resource)).isEqualTo(\"tset\");\n\t}\n\n\t@Test\n\tvoid getWithClassPathWhenClassPathIsNullIncludesProtocolResolvers() throws IOException {\n\t\tResourceLoader loader = ApplicationResourceLoader.get((ClassLoader) null);\n\t\tResource resource = loader.getResource(\"base64:\" + TEST_BASE_64_VALUE);\n\t\tassertThat(contentAsString(resource)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithResource(name = TEST_PROTOCOL_RESOLVERS_FACTORIES,\n\t\t\tcontent = \"org.springframework.core.io.ProtocolResolver=org.springframework.boot.io.ReverseStringProtocolResolver\")\n\tvoid getWithClassPathAndSpringFactoriesLoaderIncludesProtocolResolvers() throws IOException {\n\t\tSpringFactoriesLoader springFactoriesLoader = SpringFactoriesLoader\n\t\t\t.forResourceLocation(TEST_PROTOCOL_RESOLVERS_FACTORIES, Thread.currentThread().getContextClassLoader());\n\t\tResourceLoader loader = ApplicationResourceLoader.get((ClassLoader) null, springFactoriesLoader);\n\t\tResource resource = loader.getResource(\"reverse:test\");\n\t\tassertThat(contentAsString(resource)).isEqualTo(\"tset\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWithClassPathAndSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ApplicationResourceLoader.get((ClassLoader) null, null))\n\t\t\t.withMessage(\"'springFactoriesLoader' must not be null\");\n\t}\n\n\t@Test\n\tvoid getWithResourceLoaderIncludesProtocolResolvers() throws IOException {\n\t\tResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader());\n\t\tResource resource = loader.getResource(\"base64:\" + TEST_BASE_64_VALUE);\n\t\tassertThat(contentAsString(resource)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getWithResourceLoaderDelegatesLoading() throws IOException {\n\t\tDefaultResourceLoader delegate = new TestResourceLoader();\n\t\tResourceLoader loader = ApplicationResourceLoader.get(delegate);\n\t\tassertThat(contentAsString(loader.getResource(\"spring\"))).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWithResourceLoaderWhenResourceLoaderIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ApplicationResourceLoader.get((ResourceLoader) null))\n\t\t\t.withMessage(\"'resourceLoader' must not be null\");\n\t}\n\n\t@Test\n\tvoid getWithResourceLoaderAndSpringFactoriesLoaderIncludesProtocolResolvers() throws IOException {\n\t\tDefaultResourceLoader delegate = new TestResourceLoader();\n\t\tResourceLoader loader = ApplicationResourceLoader.get(delegate);\n\t\tResource resource = loader.getResource(\"base64:\" + TEST_BASE_64_VALUE);\n\t\tassertThat(contentAsString(resource)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWithResourceLoaderAndSpringFactoriesLoaderWhenResourceLoaderIsNullThrowsException() {\n\t\tSpringFactoriesLoader springFactoriesLoader = SpringFactoriesLoader\n\t\t\t.forResourceLocation(TEST_PROTOCOL_RESOLVERS_FACTORIES);\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ApplicationResourceLoader.get((ResourceLoader) null, springFactoriesLoader))\n\t\t\t.withMessage(\"'resourceLoader' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWithResourceLoaderAndSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ApplicationResourceLoader.get(new TestResourceLoader(), null))\n\t\t\t.withMessage(\"'springFactoriesLoader' must not be null\");\n\t}\n\n\t@Test\n\tvoid getResourceWhenPathIsRelative() throws IOException {\n\t\tResourceLoader loader = ApplicationResourceLoader.get();\n\t\tString name = \"relative/path/file.txt\";\n\t\tResource resource = loader.getResource(name);\n\t\tFile resourceFile = resource.getFile();\n\t\tassertThat(resourceFile).isRelative();\n\t\tassertThat(resourceFile).isEqualTo(new File(name));\n\t}\n\n\t@Test\n\t@WithResource(name = TEST_PROTOCOL_RESOLVERS_FACTORIES,\n\t\t\tcontent = \"org.springframework.core.io.ProtocolResolver=org.springframework.boot.io.ReverseStringProtocolResolver\")\n\tvoid getResourceWhenPathIsAbsolute(@ResourcePath(TEST_PROTOCOL_RESOLVERS_FACTORIES) File file) throws IOException {\n\t\tResourceLoader loader = ApplicationResourceLoader.get();\n\t\tResource resource = loader.getResource(file.getAbsolutePath());\n\t\tassertThat(resource.getFile()).hasSameBinaryContentAs(file);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getResourceWhenPathIsNull() {\n\t\tResourceLoader loader = ApplicationResourceLoader.get();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> loader.getResource(null))\n\t\t\t.withMessage(\"Location must not be null\");\n\t}\n\n\t@Test\n\tvoid getResourceWithPreferFileResolutionWhenFullPathWithClassPathResource() throws Exception {\n\t\tFile file = new File(\"src/main/resources/a-file\");\n\t\tResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(), true);\n\t\tResource resource = loader.getResource(file.getAbsolutePath());\n\t\tassertThat(resource).isInstanceOf(FileSystemResource.class);\n\t\tassertThat(resource.getFile().getAbsoluteFile()).isEqualTo(file.getAbsoluteFile());\n\t\tResourceLoader regularLoader = ApplicationResourceLoader.get(new DefaultResourceLoader(), false);\n\t\tassertThat(regularLoader.getResource(file.getAbsolutePath())).isInstanceOf(ClassPathResource.class);\n\t}\n\n\t@Test\n\tvoid getResourceWithPreferFileResolutionWhenRelativePathWithClassPathResource() throws Exception {\n\t\tResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(), true);\n\t\tResource resource = loader.getResource(\"src/main/resources/a-file\");\n\t\tassertThat(resource).isInstanceOf(FileSystemResource.class);\n\t\tassertThat(resource.getFile().getAbsoluteFile())\n\t\t\t.isEqualTo(new File(\"src/main/resources/a-file\").getAbsoluteFile());\n\t\tResourceLoader regularLoader = ApplicationResourceLoader.get(new DefaultResourceLoader(), false);\n\t\tassertThat(regularLoader.getResource(\"src/main/resources/a-file\")).isInstanceOf(ClassPathResource.class);\n\t}\n\n\t@Test\n\tvoid getResourceWithPreferFileResolutionWhenExplicitClassPathPrefix() {\n\t\tResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(), true);\n\t\tResource resource = loader.getResource(\"classpath:a-file\");\n\t\tassertThat(resource).isInstanceOf(ClassPathResource.class);\n\t}\n\n\t@Test\n\tvoid getClassLoaderReturnsDelegateClassLoader() {\n\t\tClassLoader classLoader = new TestClassLoader(this::useTestProtocolResolversFactories);\n\t\tResourceLoader loader = ApplicationResourceLoader.get(new DefaultResourceLoader(classLoader));\n\t\tassertThat(loader.getClassLoader()).isSameAs(classLoader);\n\t}\n\n\tprivate String contentAsString(Resource resource) throws IOException {\n\t\treturn resource.getContentAsString(StandardCharsets.UTF_8);\n\t}\n\n\tprivate String useTestProtocolResolversFactories(String name) {\n\t\treturn (!SPRING_FACTORIES.equals(name)) ? name : TEST_PROTOCOL_RESOLVERS_FACTORIES;\n\t}\n\n\tstatic class TestClassLoader extends ClassLoader {\n\n\t\tprivate final UnaryOperator<String> mapper;\n\n\t\tTestClassLoader(UnaryOperator<String> mapper) {\n\t\t\tsuper(Thread.currentThread().getContextClassLoader());\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic URL getResource(String name) {\n\t\t\treturn super.getResource(this.mapper.apply(name));\n\t\t}\n\n\t\t@Override\n\t\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t\treturn super.getResources(this.mapper.apply(name));\n\t\t}\n\n\t}\n\n\tstatic class TestResourceLoader extends DefaultResourceLoader {\n\n\t\t@Override\n\t\tpublic Resource getResource(String location) {\n\t\t\treturn (!\"spring\".equals(location)) ? super.getResource(location)\n\t\t\t\t\t: new ByteArrayResource(\"boot\".getBytes(StandardCharsets.UTF_8));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/io/Base64ProtocolResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Base64ProtocolResolver}.\n *\n * @author Scott Frederick\n */\nclass Base64ProtocolResolverTests {\n\n\t@Test\n\tvoid base64LocationResolves() throws IOException {\n\t\tString location = Base64.getEncoder().encodeToString(\"test value\".getBytes());\n\t\tResource resource = new Base64ProtocolResolver().resolve(\"base64:\" + location, new DefaultResourceLoader());\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"test value\");\n\t}\n\n\t@Test\n\tvoid base64LocationWithInvalidBase64ThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new Base64ProtocolResolver().resolve(\"base64:not valid base64\", new DefaultResourceLoader()))\n\t\t\t.withMessageContaining(\"Illegal base64\");\n\t}\n\n\t@Test\n\tvoid locationWithoutPrefixDoesNotResolve() {\n\t\tResource resource = new Base64ProtocolResolver().resolve(\"file:notbase64.txt\", new DefaultResourceLoader());\n\t\tassertThat(resource).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for resolving configuration properties using\n * {@code ProtocolResolver ProtocolResolvers}.\n *\n * @author Scott Frederick\n */\nclass ProtocolResolverApplicationContextInitializerIntegrationTests {\n\n\t@Test\n\tvoid base64ResourceResolves() throws IOException {\n\t\tSpringApplication application = new SpringApplication(TestConfiguration.class);\n\t\tapplication.setDefaultProperties(Map.of(\"test.resource\", \"base64:dGVzdC12YWx1ZQ==\"));\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tConfigurableApplicationContext context = application.run();\n\t\tTestProperties propertiesBean = context.getBean(TestProperties.class);\n\t\tResource resource = propertiesBean.getResource();\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.exists()).isTrue();\n\t\tassertThat(resource.getContentAsString(Charset.defaultCharset())).isEqualTo(\"test-value\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(TestProperties.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class TestProperties {\n\n\t\t@Nullable Resource resource;\n\n\t\t@Nullable Resource getResource() {\n\t\t\treturn this.resource;\n\t\t}\n\n\t\tvoid setResource(@Nullable Resource resource) {\n\t\t\tthis.resource = resource;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/io/ProtocolResolverApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ProtocolResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ProtocolResolverApplicationContextInitializer}.\n *\n * @author Scott Frederick\n */\nclass ProtocolResolverApplicationContextInitializerTests {\n\n\t@Test\n\tvoid initializeAddsProtocolResolversToApplicationContext() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tProtocolResolverApplicationContextInitializer initializer = new ProtocolResolverApplicationContextInitializer();\n\t\t\tinitializer.initialize(context);\n\t\t\tassertThat(context).isInstanceOf(DefaultResourceLoader.class);\n\t\t\tCollection<ProtocolResolver> protocolResolvers = ((DefaultResourceLoader) context).getProtocolResolvers();\n\t\t\tassertThat(protocolResolvers).hasExactlyElementsOfTypes(Base64ProtocolResolver.class);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/io/ReverseStringProtocolResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.io;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * Test {@link ProtocolResolver} that reverses a String.\n *\n * @author Phillip Webb\n */\nclass ReverseStringProtocolResolver implements ProtocolResolver {\n\n\tprivate static final String PREFIX = \"reverse:\";\n\n\t@Override\n\tpublic @Nullable Resource resolve(String location, ResourceLoader resourceLoader) {\n\t\tif (!location.startsWith(PREFIX)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ByteArrayResource(reverse(location.substring(PREFIX.length())));\n\t}\n\n\tprivate byte[] reverse(String substring) {\n\t\treturn new StringBuilder(substring).reverse().toString().getBytes(StandardCharsets.UTF_8);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/AbstractJsonParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.ResourceContent;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Base for {@link JsonParser} tests.\n *\n * @author Dave Syer\n * @author Jean de Klerk\n * @author Stephane Nicoll\n */\nabstract class AbstractJsonParserTests {\n\n\tprivate final JsonParser parser = getParser();\n\n\tprotected abstract JsonParser getParser();\n\n\t@Test\n\tvoid simpleMap() {\n\t\tMap<String, Object> map = this.parser.parseMap(\"{\\\"foo\\\":\\\"bar\\\",\\\"spam\\\":1}\");\n\t\tassertThat(map).hasSize(2);\n\t\tassertThat(map).containsEntry(\"foo\", \"bar\");\n\t\tObject spam = map.get(\"spam\");\n\t\tassertThat(spam).isNotNull();\n\t\tassertThat(((Number) spam).longValue()).isOne();\n\t}\n\n\t@Test\n\tvoid doubleValue() {\n\t\tMap<String, Object> map = this.parser.parseMap(\"{\\\"foo\\\":\\\"bar\\\",\\\"spam\\\":1.23}\");\n\t\tassertThat(map).hasSize(2);\n\t\tassertThat(map).containsEntry(\"foo\", \"bar\");\n\t\tassertThat(map).containsEntry(\"spam\", 1.23d);\n\t}\n\n\t@Test\n\tvoid stringContainingNumber() {\n\t\tMap<String, Object> map = this.parser.parseMap(\"{\\\"foo\\\":\\\"123\\\"}\");\n\t\tassertThat(map).hasSize(1);\n\t\tassertThat(map).containsEntry(\"foo\", \"123\");\n\t}\n\n\t@Test\n\tvoid stringContainingComma() {\n\t\tMap<String, Object> map = this.parser.parseMap(\"{\\\"foo\\\":\\\"bar1,bar2\\\"}\");\n\t\tassertThat(map).hasSize(1);\n\t\tassertThat(map).containsEntry(\"foo\", \"bar1,bar2\");\n\t}\n\n\t@Test\n\tvoid emptyMap() {\n\t\tMap<String, Object> map = this.parser.parseMap(\"{}\");\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid simpleList() {\n\t\tList<Object> list = this.parser.parseList(\"[\\\"foo\\\",\\\"bar\\\",1]\");\n\t\tassertThat(list).hasSize(3);\n\t\tassertThat(list.get(1)).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid emptyList() {\n\t\tList<Object> list = this.parser.parseList(\"[]\");\n\t\tassertThat(list).isEmpty();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid listOfMaps() {\n\t\tList<Object> list = this.parser.parseList(\"[{\\\"foo\\\":\\\"bar\\\",\\\"spam\\\":1},{\\\"foo\\\":\\\"baz\\\",\\\"spam\\\":2}]\");\n\t\tassertThat(list).hasSize(2);\n\t\tassertThat(((Map<String, Object>) list.get(1))).hasSize(2);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid mapOfLists() {\n\t\tMap<String, Object> map = this.parser\n\t\t\t.parseMap(\"{\\\"foo\\\":[{\\\"foo\\\":\\\"bar\\\",\\\"spam\\\":1},{\\\"foo\\\":\\\"baz\\\",\\\"spam\\\":2}]}\");\n\t\tassertThat(map).hasSize(1);\n\t\tassertThat(((List<Object>) map.get(\"foo\"))).hasSize(2);\n\t\tassertThat(map.get(\"foo\")).asInstanceOf(InstanceOfAssertFactories.LIST).allMatch(Map.class::isInstance);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid nestedLeadingAndTrailingWhitespace() {\n\t\tMap<String, Object> map = this.parser\n\t\t\t.parseMap(\" {\\\"foo\\\": [ { \\\"foo\\\" : \\\"bar\\\" , \\\"spam\\\" : 1 } , { \\\"foo\\\" : \\\"baz\\\" , \\\"spam\\\" : 2 } ] } \");\n\t\tassertThat(map).hasSize(1);\n\t\tassertThat(((List<Object>) map.get(\"foo\"))).hasSize(2);\n\t\tassertThat(map.get(\"foo\")).asInstanceOf(InstanceOfAssertFactories.LIST).allMatch(Map.class::isInstance);\n\t}\n\n\t@Test\n\tvoid mapWithNullThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseMap(null));\n\t}\n\n\t@Test\n\tvoid listWithNullThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseList(null));\n\t}\n\n\t@Test\n\tvoid mapWithEmptyStringThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseMap(\"\"));\n\t}\n\n\t@Test\n\tvoid listWithEmptyStringThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseList(\"\"));\n\t}\n\n\t@Test\n\tvoid mapWithListThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseMap(\"[]\"));\n\t}\n\n\t@Test\n\tvoid listWithMapThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseList(\"{}\"));\n\t}\n\n\t@Test\n\tvoid listWithLeadingWhitespace() {\n\t\tList<Object> list = this.parser.parseList(\"\\n\\t[\\\"foo\\\"]\");\n\t\tassertThat(list).hasSize(1);\n\t\tassertThat(list.get(0)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid mapWithLeadingWhitespace() {\n\t\tMap<String, Object> map = this.parser.parseMap(\"\\n\\t{\\\"foo\\\":\\\"bar\\\"}\");\n\t\tassertThat(map).hasSize(1);\n\t\tassertThat(map).containsEntry(\"foo\", \"bar\");\n\t}\n\n\t@Test\n\tvoid mapWithLeadingWhitespaceListThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseMap(\"\\n\\t[]\"));\n\t}\n\n\t@Test\n\tvoid listWithLeadingWhitespaceMapThrowsARuntimeException() {\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> this.parser.parseList(\"\\n\\t{}\"));\n\t}\n\n\t@Test\n\tvoid escapeDoubleQuote() {\n\t\tString input = \"{\\\"foo\\\": \\\"\\\\\\\"bar\\\\\\\"\\\"}\";\n\t\tMap<String, Object> map = this.parser.parseMap(input);\n\t\tassertThat(map).containsEntry(\"foo\", \"\\\"bar\\\"\");\n\t}\n\n\t@Test\n\tvoid listWithMalformedMap() {\n\t\tassertThatExceptionOfType(JsonParseException.class)\n\t\t\t.isThrownBy(() -> this.parser.parseList(\"[tru,erqett,{\\\"foo\\\":fatrue,true,true,true,tr''ue}]\"));\n\t}\n\n\t@Test\n\tvoid mapWithKeyAndNoValue() {\n\t\tassertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseMap(\"{\\\"foo\\\"}\"));\n\t}\n\n\t@Test // gh-31868\n\t@WithPackageResources(\"repeated-open-array.txt\")\n\tvoid listWithRepeatedOpenArray(@ResourceContent(\"repeated-open-array.txt\") String input) {\n\t\tassertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input))\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"too deeply nested\");\n\t}\n\n\t@Test // gh-31869\n\t@WithPackageResources(\"large-malformed-json.txt\")\n\tvoid largeMalformed(@ResourceContent(\"large-malformed-json.txt\") String input) {\n\t\tassertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input));\n\t}\n\n\t@Test // gh-32029\n\t@WithPackageResources(\"deeply-nested-map-json.txt\")\n\tvoid deeplyNestedMap(@ResourceContent(\"deeply-nested-map-json.txt\") String input) {\n\t\tassertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/BasicJsonParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\n/**\n * Tests for {@link BasicJsonParser}.\n *\n * @author Dave Syer\n */\nclass BasicJsonParserTests extends AbstractJsonParserTests {\n\n\t@Override\n\tprotected JsonParser getParser() {\n\t\treturn new BasicJsonParser();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/GsonJsonParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\n/**\n * Tests for {@link GsonJsonParser}.\n *\n * @author Dave Syer\n */\nclass GsonJsonParserTests extends AbstractJsonParserTests {\n\n\t@Override\n\tprotected JsonParser getParser() {\n\t\treturn new GsonJsonParser();\n\t}\n\n\t@Override\n\tvoid listWithRepeatedOpenArray(String input) {\n\t\t// Gson does not protect against deeply nested JSON\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/JacksonJsonParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.type.TypeReference;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link JacksonJsonParser}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass JacksonJsonParserTests extends AbstractJsonParserTests {\n\n\t@Override\n\tprotected JsonParser getParser() {\n\t\treturn new JacksonJsonParser();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid instanceWithSpecificObjectMapper() {\n\t\tJsonMapper jsonMapper = spy(new JsonMapper());\n\t\tnew JacksonJsonParser(jsonMapper).parseMap(\"{}\");\n\t\tthen(jsonMapper).should().readValue(eq(\"{}\"), any(TypeReference.class));\n\t}\n\n\t@Override\n\t@Disabled(\"Jackson's array handling is no longer stack bound so protection has been removed.\")\n\t// https://github.com/FasterXML/jackson-databind/commit/8238ab41d0350fb915797c89d46777b4496b74fd\n\tvoid listWithRepeatedOpenArray(String input) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/JsonValueWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.json.JsonValueWriter.Series;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link JsonValueWriter} .\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass JsonValueWriterTests {\n\n\t@Test\n\tvoid writeNameAndValueWhenNameIsNull() {\n\t\tassertThat(doWrite((writer) -> writer.write(null, \"test\"))).isEqualTo(quoted(\"test\"));\n\t}\n\n\t@Test\n\tvoid writeNameAndValueWhenNameIsNotNull() {\n\t\tassertThat(doWrite((writer) -> {\n\t\t\twriter.start(Series.OBJECT);\n\t\t\twriter.write(\"name\", \"value\");\n\t\t\twriter.end(Series.OBJECT);\n\t\t})).isEqualTo(\"\"\"\n\t\t\t\t{\"name\":\"value\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenNull() {\n\t\tassertThat(write(null)).isEqualTo(\"null\");\n\t}\n\n\t@Test\n\tvoid writeWhenWritableJson() {\n\n\t\tJsonWriter<String> writer = (instance, out) -> out.append(\"\"\"\n\t\t\t\t{\"test\":\"%s\"}\"\"\".formatted(instance));\n\t\tassertThat(write(writer.write(\"hello\"))).isEqualTo(\"\"\"\n\t\t\t\t{\"test\":\"hello\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenStringArray() {\n\t\tassertThat(write(new String[] { \"a\", \"b\", \"c\" })).isEqualTo(\"\"\"\n\t\t\t\t[\"a\",\"b\",\"c\"]\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenNumberArray() {\n\t\tassertThat(write(new int[] { 1, 2, 3 })).isEqualTo(\"[1,2,3]\");\n\t\tassertThat(write(new double[] { 1.0, 2.0, 3.0 })).isEqualTo(\"[1.0,2.0,3.0]\");\n\t}\n\n\t@Test\n\tvoid writeWhenBooleanArray() {\n\t\tassertThat(write(new boolean[] { true, false, true })).isEqualTo(\"[true,false,true]\");\n\t}\n\n\t@Test\n\tvoid writeWhenArrayWithNullElements() {\n\t\tassertThat(write(new Object[] { null, null })).isEqualTo(\"[null,null]\");\n\t}\n\n\t@Test\n\tvoid writeWhenArrayWithMixedElementTypes() {\n\t\tassertThat(write(new Object[] { \"a\", \"b\", \"c\", 1, 2, true, null })).isEqualTo(\"\"\"\n\t\t\t\t[\"a\",\"b\",\"c\",1,2,true,null]\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenCollection() {\n\t\tassertThat(write(List.of(\"a\", \"b\", \"c\"))).isEqualTo(\"\"\"\n\t\t\t\t[\"a\",\"b\",\"c\"]\"\"\");\n\t\tassertThat(write(new LinkedHashSet<>(List.of(\"a\", \"b\", \"c\")))).isEqualTo(\"\"\"\n\t\t\t\t[\"a\",\"b\",\"c\"]\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenMap() {\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", \"A\");\n\t\tmap.put(\"b\", \"B\");\n\t\tassertThat(write(map)).isEqualTo(\"\"\"\n\t\t\t\t{\"a\":\"A\",\"b\":\"B\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenMapWithNumericalKeys() {\n\t\tMap<Integer, String> map = new LinkedHashMap<>();\n\t\tmap.put(1, \"A\");\n\t\tmap.put(2, \"B\");\n\t\tassertThat(write(map)).isEqualTo(\"\"\"\n\t\t\t\t{\"1\":\"A\",\"2\":\"B\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenMapWithMixedValueTypes() {\n\t\tMap<Object, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", 1);\n\t\tmap.put(\"b\", 2.0);\n\t\tmap.put(\"c\", true);\n\t\tmap.put(\"d\", \"d\");\n\t\tmap.put(\"e\", null);\n\t\tassertThat(write(map)).isEqualTo(\"\"\"\n\t\t\t\t{\"a\":1,\"b\":2.0,\"c\":true,\"d\":\"d\",\"e\":null}\"\"\");\n\t}\n\n\t@Test\n\tvoid writeWhenNumber() {\n\t\tassertThat(write((byte) 123)).isEqualTo(\"123\");\n\t\tassertThat(write(123)).isEqualTo(\"123\");\n\t\tassertThat(write(123L)).isEqualTo(\"123\");\n\t\tassertThat(write(2.0)).isEqualTo(\"2.0\");\n\t\tassertThat(write(2.0f)).isEqualTo(\"2.0\");\n\t\tassertThat(write(Byte.valueOf((byte) 123))).isEqualTo(\"123\");\n\t\tassertThat(write(Integer.valueOf(123))).isEqualTo(\"123\");\n\t\tassertThat(write(Long.valueOf(123L))).isEqualTo(\"123\");\n\t\tassertThat(write(Double.valueOf(2.0))).isEqualTo(\"2.0\");\n\t\tassertThat(write(Float.valueOf(2.0f))).isEqualTo(\"2.0\");\n\t}\n\n\t@Test\n\tvoid writeWhenBoolean() {\n\t\tassertThat(write(true)).isEqualTo(\"true\");\n\t\tassertThat(write(Boolean.TRUE)).isEqualTo(\"true\");\n\t\tassertThat(write(false)).isEqualTo(\"false\");\n\t\tassertThat(write(Boolean.FALSE)).isEqualTo(\"false\");\n\t}\n\n\t@Test\n\tvoid writeWhenString() {\n\t\tassertThat(write(\"test\")).isEqualTo(quoted(\"test\"));\n\t}\n\n\t@Test\n\tvoid writeWhenStringRequiringEscape() {\n\t\tassertThat(write(\"\\\"\")).isEqualTo(quoted(\"\\\\\\\"\"));\n\t\tassertThat(write(\"\\\\\")).isEqualTo(quoted(\"\\\\\\\\\"));\n\t\tassertThat(write(\"\\b\")).isEqualTo(quoted(\"\\\\b\"));\n\t\tassertThat(write(\"\\f\")).isEqualTo(quoted(\"\\\\f\"));\n\t\tassertThat(write(\"\\n\")).isEqualTo(quoted(\"\\\\n\"));\n\t\tassertThat(write(\"\\r\")).isEqualTo(quoted(\"\\\\r\"));\n\t\tassertThat(write(\"\\t\")).isEqualTo(quoted(\"\\\\t\"));\n\t\tassertThat(write(\"\\u0000\\u001F\")).isEqualTo(quoted(\"\\\\u0000\\\\u001F\"));\n\t}\n\n\t@Test\n\tvoid shouldNotEscapeForwardSlash() {\n\t\tassertThat(write(\"/\")).isEqualTo(quoted(\"/\"));\n\t}\n\n\t@Test\n\tvoid writeObject() {\n\t\tMap<String, String> map = Map.of(\"a\", \"A\");\n\t\tString actual = doWrite((valueWriter) -> valueWriter.writeObject(map::forEach));\n\t\tassertThat(actual).isEqualTo(\"\"\"\n\t\t\t\t{\"a\":\"A\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid writePairs() {\n\t\tString actual = doWrite((valueWriter) -> {\n\t\t\tvalueWriter.start(Series.OBJECT);\n\t\t\tvalueWriter.writePairs(Map.of(\"a\", \"A\")::forEach);\n\t\t\tvalueWriter.writePairs(Map.of(\"b\", \"B\")::forEach);\n\t\t\tvalueWriter.end(Series.OBJECT);\n\t\t});\n\t\tassertThat(actual).isEqualTo(\"\"\"\n\t\t\t\t{\"a\":\"A\",\"b\":\"B\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid writePairsWhenDuplicateThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> doWrite((valueWriter) -> {\n\t\t\tvalueWriter.start(Series.OBJECT);\n\t\t\tvalueWriter.writePairs(Map.of(\"a\", \"A\")::forEach);\n\t\t\tvalueWriter.writePairs(Map.of(\"a\", \"B\")::forEach);\n\t\t\tvalueWriter.end(Series.OBJECT);\n\t\t})).withMessage(\"The name 'a' has already been written\");\n\t}\n\n\t@Test\n\tvoid writeArray() {\n\t\tList<String> list = List.of(\"a\", \"b\", \"c\");\n\t\tString actual = doWrite((valueWriter) -> valueWriter.writeArray(list::forEach));\n\t\tassertThat(actual).isEqualTo(\"\"\"\n\t\t\t\t[\"a\",\"b\",\"c\"]\"\"\");\n\t}\n\n\t@Test\n\tvoid writeElements() {\n\t\tString actual = doWrite((valueWriter) -> {\n\t\t\tvalueWriter.start(Series.ARRAY);\n\t\t\tvalueWriter.writeElements(List.of(\"a\", \"b\")::forEach);\n\t\t\tvalueWriter.writeElements(List.of(\"c\", \"d\")::forEach);\n\t\t\tvalueWriter.end(Series.ARRAY);\n\t\t});\n\t\tassertThat(actual).isEqualTo(\"\"\"\n\t\t\t\t[\"a\",\"b\",\"c\",\"d\"]\"\"\");\n\t}\n\n\t@Test\n\tvoid startAndEndWithNull() {\n\t\tString actual = doWrite((valueWriter) -> {\n\t\t\tvalueWriter.start(null);\n\t\t\tvalueWriter.write(\"test\");\n\t\t\tvalueWriter.end(null);\n\t\t});\n\t\tassertThat(actual).isEqualTo(quoted(\"test\"));\n\t}\n\n\t@Test\n\tvoid endWhenNotStartedThrowsException() {\n\t\tdoWrite((valueWriter) -> assertThatExceptionOfType(NoSuchElementException.class)\n\t\t\t.isThrownBy(() -> valueWriter.end(Series.ARRAY)));\n\t}\n\n\t@Test // gh-44502\n\tvoid writeJavaNioPathWhenSingleElementShouldBeSerializedAsString() {\n\t\tassertThat(doWrite((valueWriter) -> valueWriter.write(Path.of(\"a\")))).isEqualTo(quoted(\"a\"));\n\t}\n\n\t@Test // gh-44502\n\t@EnabledOnOs(OS.WINDOWS)\n\tvoid writeJavaNioPathShouldBeSerializedAsStringOnWindows() {\n\t\tassertThat(doWrite((valueWriter) -> valueWriter.write(Path.of(\"a/b/c\")))).isEqualTo(quoted(\"a\\\\\\\\b\\\\\\\\c\"));\n\t}\n\n\t@Test // gh-44502\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid writeJavaNioPathShouldBeSerializedAsString() {\n\t\tassertThat(doWrite((valueWriter) -> valueWriter.write(Path.of(\"a/b/c\")))).isEqualTo(quoted(\"a/b/c\"));\n\t}\n\n\t@Test\n\tvoid illegalStateExceptionShouldBeThrownWhenCollectionExceededNestingDepth() {\n\t\tJsonValueWriter writer = new JsonValueWriter(new StringBuilder(), 128);\n\t\tList<Object> list = new ArrayList<>();\n\t\tlist.add(list);\n\t\tassertThatIllegalStateException().isThrownBy(() -> writer.write(list))\n\t\t\t.withMessageStartingWith(\n\t\t\t\t\t\"JSON nesting depth (129) exceeds maximum depth of 128 (current path: [0][0][0][0][0][0][0][0][0][0][0][0]\");\n\t}\n\n\t@Test\n\tvoid illegalStateExceptionShouldBeThrownWhenMapExceededNestingDepth() {\n\t\tJsonValueWriter writer = new JsonValueWriter(new StringBuilder(), 128);\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"foo\", Map.of(\"bar\", map));\n\t\tassertThatIllegalStateException().isThrownBy(() -> writer.write(map))\n\t\t\t.withMessageStartingWith(\n\t\t\t\t\t\"JSON nesting depth (129) exceeds maximum depth of 128 (current path: foo.bar.foo.bar.foo.bar.foo\");\n\t}\n\n\t@Test\n\tvoid illegalStateExceptionShouldBeThrownWhenIterableExceededNestingDepth() {\n\t\tJsonValueWriter writer = new JsonValueWriter(new StringBuilder(), 128);\n\t\tList<Object> list = new ArrayList<>();\n\t\tlist.add(list);\n\t\tassertThatIllegalStateException().isThrownBy(() -> writer.write((Iterable<Object>) list::iterator))\n\t\t\t.withMessageStartingWith(\n\t\t\t\t\t\"JSON nesting depth (129) exceeds maximum depth of 128 (current path: [0][0][0][0][0][0][0][0][0][0][0][0]\");\n\t}\n\n\t@Test\n\tvoid shouldAllowStartingObjectWhenCurrentDepthIsMaxDepth() {\n\t\tStringBuilder out = new StringBuilder();\n\t\tJsonValueWriter writer = new JsonValueWriter(out, 2);\n\t\twriter.start(Series.OBJECT);\n\t\twriter.start(Series.OBJECT);\n\t\twriter.start(Series.OBJECT);\n\t\twriter.end(Series.OBJECT);\n\t\twriter.end(Series.OBJECT);\n\t\twriter.end(Series.OBJECT);\n\t\tassertThat(out).hasToString(\"{{{}}}\");\n\t}\n\n\t@Test\n\tvoid shouldAllowStartingArrayWhenCurrentDepthIsMaxDepth() {\n\t\tStringBuilder out = new StringBuilder();\n\t\tJsonValueWriter writer = new JsonValueWriter(out, 2);\n\t\twriter.start(Series.ARRAY);\n\t\twriter.start(Series.ARRAY);\n\t\twriter.start(Series.ARRAY);\n\t\twriter.end(Series.ARRAY);\n\t\twriter.end(Series.ARRAY);\n\t\twriter.end(Series.ARRAY);\n\t\tassertThat(out).hasToString(\"[[[]]]\");\n\t}\n\n\tprivate <V> String write(@Nullable V value) {\n\t\treturn doWrite((valueWriter) -> valueWriter.write(value));\n\t}\n\n\tprivate String doWrite(Consumer<JsonValueWriter> action) {\n\t\tStringBuilder out = new StringBuilder();\n\t\taction.accept(new JsonValueWriter(out));\n\t\treturn out.toString();\n\t}\n\n\tprivate String quoted(String string) {\n\t\treturn \"\\\"\" + string + \"\\\"\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/JsonWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.json.JsonWriter.Extractor;\nimport org.springframework.boot.json.JsonWriter.Member;\nimport org.springframework.boot.json.JsonWriter.MemberPath;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.json.JsonWriter.NameProcessor;\nimport org.springframework.boot.json.JsonWriter.PairExtractor;\nimport org.springframework.boot.json.JsonWriter.ValueProcessor;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link JsonWriter}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass JsonWriterTests {\n\n\tprivate static final Person PERSON = new Person(\"Spring\", \"Boot\", 10);\n\n\t@Test\n\tvoid writeToStringWritesToString() {\n\t\tassertThat(ofFormatString(\"%s\").writeToString(123)).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid writeReturnsWritableJson() {\n\t\tassertThat(ofFormatString(\"%s\").write(123)).isInstanceOf(WritableJson.class);\n\t}\n\n\t@Test\n\tvoid withSuffixAddsSuffixToWrittenString() {\n\t\tassertThat(ofFormatString(\"%s\").withSuffix(\"000\").writeToString(123)).isEqualTo(\"123000\");\n\t}\n\n\t@Test\n\tvoid withSuffixWhenSuffixIsNullReturnsExistingWriter() {\n\t\tJsonWriter<?> writer = ofFormatString(\"%s\");\n\t\tassertThat(writer.withSuffix(null)).isSameAs(writer);\n\t}\n\n\t@Test\n\tvoid withSuffixWhenSuffixIsEmptyReturnsExistingWriter() {\n\t\tJsonWriter<?> writer = ofFormatString(\"%s\");\n\t\tassertThat(writer.withSuffix(\"\")).isSameAs(writer);\n\t}\n\n\t@Test\n\tvoid withNewLineAtEndAddsNewLineToWrittenString() {\n\t\tassertThat(ofFormatString(\"%s\").withNewLineAtEnd().writeToString(123)).isEqualTo(\"123\\n\");\n\t}\n\n\t@Test\n\tvoid ofAddingNamedSelf() {\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.add(\"test\"));\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(\"\"\"\n\t\t\t\t{\"test\":\"Spring Boot (10)\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid ofAddingUnnamedSelf() {\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.add());\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(quoted(\"Spring Boot (10)\"));\n\t}\n\n\t@Test\n\tvoid ofAddValue() {\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.add(\"Spring\", \"Boot\"));\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(\"\"\"\n\t\t\t\t{\"Spring\":\"Boot\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid ofAddSupplier() {\n\t\tSupplier<@Nullable String> supplier = () -> \"Boot\";\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.add(\"Spring\", supplier));\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(\"\"\"\n\t\t\t\t{\"Spring\":\"Boot\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid ofAddExtractor() {\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\tmembers.add(\"firstName\", Person::firstName);\n\t\t\tmembers.add(\"lastName\", Person::lastName);\n\t\t\tmembers.add(\"age\", Person::age);\n\t\t});\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(\"\"\"\n\t\t\t\t{\"firstName\":\"Spring\",\"lastName\":\"Boot\",\"age\":10}\"\"\");\n\t}\n\n\t@Test\n\tvoid ofFromValue() {\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.from(\"Boot\"));\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(quoted(\"Boot\"));\n\t}\n\n\t@Test\n\tvoid ofFromSupplier() {\n\t\tSupplier<@Nullable String> supplier = () -> \"Boot\";\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.from(supplier));\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(quoted(\"Boot\"));\n\t}\n\n\t@Test\n\tvoid ofFromExtractor() {\n\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.from(Person::lastName));\n\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(quoted(\"Boot\"));\n\t}\n\n\t@Test\n\tvoid ofAddMapEntries() {\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", \"A\");\n\t\tmap.put(\"b\", 123);\n\t\tmap.put(\"c\", true);\n\t\tJsonWriter<List<Map<String, Object>>> writer = JsonWriter\n\t\t\t.of((members) -> members.addMapEntries((list) -> list.get(0)));\n\t\tassertThat(writer.writeToString(List.of(map))).isEqualTo(\"\"\"\n\t\t\t\t{\"a\":\"A\",\"b\":123,\"c\":true}\"\"\");\n\t}\n\n\t@Test\n\tvoid ofWhenNoMembersAddedThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {\n\t\t})).withMessage(\"No members have been added\");\n\t}\n\n\t@Test\n\tvoid ofWhenOneContributesPairByNameAndOneHasNoNameThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {\n\t\t\tmembers.add(\"Spring\", \"Boot\");\n\t\t\tmembers.from(\"alone\");\n\t\t}))\n\t\t\t.withMessage(\"Member at index 1 does not contribute a named pair, \"\n\t\t\t\t\t+ \"ensure that all members have a name or call an appropriate 'using' method\");\n\t}\n\n\t@Test\n\tvoid ofWhenOneContributesPairByUsingPairsAndOneHasNoNameThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {\n\t\t\tmembers.from(Map.of(\"Spring\", \"Boot\")).usingPairs(Map::forEach);\n\t\t\tmembers.from(\"alone\");\n\t\t}))\n\t\t\t.withMessage(\"Member at index 1 does not contribute a named pair, \"\n\t\t\t\t\t+ \"ensure that all members have a name or call an appropriate 'using' method\");\n\t}\n\n\t@Test\n\tvoid ofWhenOneContributesPairByUsingMembersAndOneHasNoNameThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((members) -> {\n\t\t\tmembers.from(PERSON).usingMembers((personMembers) -> {\n\t\t\t\tpersonMembers.add(\"first\", Person::firstName);\n\t\t\t\tpersonMembers.add(\"last\", Person::firstName);\n\t\t\t});\n\t\t\tmembers.from(\"alone\");\n\t\t}))\n\t\t\t.withMessage(\"Member at index 1 does not contribute a named pair, \"\n\t\t\t\t\t+ \"ensure that all members have a name or call an appropriate 'using' method\");\n\t}\n\n\tprivate static String quoted(String value) {\n\t\treturn \"\\\"\" + value + \"\\\"\";\n\t}\n\n\tprivate static <T> JsonWriter<T> ofFormatString(String json) {\n\t\treturn (instance, out) -> out.append(json.formatted(instance));\n\t}\n\n\t/**\n\t * Tests for {@link JsonWriter#standard()}.\n\t */\n\t@Nested\n\tclass StandardWriterTests {\n\n\t\t@Test\n\t\tvoid whenPrimitive() {\n\t\t\tassertThat(write(null)).isEqualTo(\"null\");\n\t\t\tassertThat(write(123)).isEqualTo(\"123\");\n\t\t\tassertThat(write(true)).isEqualTo(\"true\");\n\t\t\tassertThat(write(\"test\")).isEqualTo(quoted(\"test\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenMap() {\n\t\t\tassertThat(write(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"spring\":\"boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenArray() {\n\t\t\tassertThat(write(new int[] { 1, 2, 3 })).isEqualTo(\"[1,2,3]\");\n\t\t}\n\n\t\tprivate <T> String write(@Nullable T instance) {\n\t\t\treturn JsonWriter.standard().writeToString(instance);\n\t\t}\n\n\t}\n\n\t/**\n\t * Tests for {@link Members} and {@link Member}.\n\t */\n\t@Nested\n\tclass MembersTest {\n\n\t\t@Test\n\t\tvoid whenNotNull() {\n\t\t\tJsonWriter<String> writer = JsonWriter.of((members) -> members.add().whenNotNull());\n\t\t\tassertThat(writer.writeToString(\"test\")).isEqualTo(quoted(\"test\"));\n\t\t\tassertThat(writer.writeToString(null)).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNotNullExtracted() {\n\t\t\tPerson personWithNull = new Person(\"Spring\", null, 10);\n\t\t\tFunction<@Nullable Person, @Nullable Object> lastName = (person) -> (person != null) ? person.lastName()\n\t\t\t\t\t: null;\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> members.add().whenNotNull(lastName));\n\t\t\tassertThat(writer.writeToString(PERSON)).isEqualTo(quoted(\"Spring Boot (10)\"));\n\t\t\tassertThat(writer.writeToString(personWithNull)).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasLength() {\n\t\t\tJsonWriter<String> writer = JsonWriter.of((members) -> members.add().whenHasLength());\n\t\t\tassertThat(writer.writeToString(\"test\")).isEqualTo(quoted(\"test\"));\n\t\t\tassertThat(writer.writeToString(\"\")).isEmpty();\n\t\t\tassertThat(writer.writeToString(null)).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasLengthOnNonString() {\n\t\t\tJsonWriter<StringBuilder> writer = JsonWriter.of((members) -> members.add().whenHasLength());\n\t\t\tassertThat(writer.writeToString(new StringBuilder(\"test\"))).isEqualTo(quoted(\"test\"));\n\t\t\tassertThat(writer.writeToString(new StringBuilder())).isEmpty();\n\t\t\tassertThat(writer.writeToString(null)).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNotEmpty() {\n\t\t\tJsonWriter<Object> writer = JsonWriter.of((members) -> members.add().whenNotEmpty());\n\t\t\tassertThat(writer.writeToString(List.of(\"a\"))).isEqualTo(\"\"\"\n\t\t\t\t\t[\"a\"]\"\"\");\n\t\t\tassertThat(writer.writeToString(Collections.emptyList())).isEmpty();\n\t\t\tassertThat(writer.writeToString(new Object[] {})).isEmpty();\n\t\t\tassertThat(writer.writeToString(new int[] {})).isEmpty();\n\t\t\tassertThat(writer.writeToString(null)).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNot() {\n\t\t\tPredicate<@Nullable List<String>> isEmpty = List::isEmpty;\n\t\t\tJsonWriter<List<String>> writer = JsonWriter.of((members) -> members.add().whenNot(isEmpty));\n\t\t\tassertThat(writer.writeToString(List.of(\"a\"))).isEqualTo(\"\"\"\n\t\t\t\t\t[\"a\"]\"\"\");\n\t\t\tassertThat(writer.writeToString(Collections.emptyList())).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid when() {\n\t\t\tPredicate<@Nullable List<String>> isEmpty = List::isEmpty;\n\t\t\tJsonWriter<List<String>> writer = JsonWriter.of((members) -> members.add().when(isEmpty));\n\t\t\tassertThat(writer.writeToString(List.of(\"a\"))).isEmpty();\n\t\t\tassertThat(writer.writeToString(Collections.emptyList())).isEqualTo(\"[]\");\n\t\t}\n\n\t\t@Test\n\t\tvoid chainedPredicates() {\n\t\t\tSet<String> banned = Set.of(\"Spring\", \"Boot\");\n\t\t\tPredicate<@Nullable String> stringLengthPredicate = (string) -> string != null && string.length() <= 2;\n\t\t\tPredicate<@Nullable String> bannedPredicate = (string) -> string != null && banned.contains(string);\n\t\t\tJsonWriter<String> writer = JsonWriter\n\t\t\t\t.of((members) -> members.add().whenHasLength().whenNot(bannedPredicate).whenNot(stringLengthPredicate));\n\t\t\tassertThat(writer.writeToString(\"\")).isEmpty();\n\t\t\tassertThat(writer.writeToString(\"a\")).isEmpty();\n\t\t\tassertThat(writer.writeToString(\"Boot\")).isEmpty();\n\t\t\tassertThat(writer.writeToString(\"JSON\")).isEqualTo(quoted(\"JSON\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid as() {\n\t\t\tJsonWriter<String> writer = JsonWriter.of((members) -> members.add().as(Integer::valueOf));\n\t\t\tassertThat(writer.writeToString(\"123\")).isEqualTo(\"123\");\n\t\t}\n\n\t\t@Test\n\t\tvoid asWhenValueIsNullDoesNotCallAdapter() {\n\t\t\tJsonWriter<String> writer = JsonWriter.of((members) -> members.add().as((value) -> {\n\t\t\t\tthrow new RuntimeException(\"bad\");\n\t\t\t}));\n\t\t\twriter.writeToString(null);\n\t\t}\n\n\t\t@Test\n\t\tvoid chainedAs() {\n\t\t\tExtractor<Integer, Boolean> booleanExtractor = (integer) -> integer != 0;\n\t\t\tJsonWriter<String> writer = JsonWriter\n\t\t\t\t.of((members) -> members.add().as(Integer::valueOf).as(booleanExtractor));\n\t\t\tassertThat(writer.writeToString(\"0\")).isEqualTo(\"false\");\n\t\t\tassertThat(writer.writeToString(\"1\")).isEqualTo(\"true\");\n\t\t}\n\n\t\t@Test\n\t\tvoid chainedAsAndPredicates() {\n\t\t\tExtractor<Integer, Boolean> booleanExtractor = (integer) -> integer != 0;\n\t\t\tPredicate<@Nullable String> isEmpty = (string) -> !StringUtils.hasLength(string);\n\t\t\tJsonWriter<String> writer = JsonWriter.of((members) -> members.add()\n\t\t\t\t.whenNot(isEmpty)\n\t\t\t\t.as(Integer::valueOf)\n\t\t\t\t.when((integer) -> integer < 2)\n\t\t\t\t.as(booleanExtractor));\n\t\t\tassertThat(writer.writeToString(\"\")).isEmpty();\n\t\t\tassertThat(writer.writeToString(\"0\")).isEqualTo(\"false\");\n\t\t\tassertThat(writer.writeToString(\"1\")).isEqualTo(\"true\");\n\t\t\tassertThat(writer.writeToString(\"2\")).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid usingExtractedPairsWithExtractor() {\n\t\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\t\tmap.put(\"a\", \"A\");\n\t\t\tmap.put(\"b\", \"B\");\n\t\t\tPairExtractor<Map.Entry<String, Object>> extractor = PairExtractor.of(Map.Entry::getKey,\n\t\t\t\t\tMap.Entry::getValue);\n\t\t\tJsonWriter<Map<String, Object>> writer = JsonWriter\n\t\t\t\t.of((members) -> members.add().as(Map::entrySet).usingExtractedPairs(Set::forEach, extractor));\n\t\t\tassertThat(writer.writeToString(map)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"a\":\"A\",\"b\":\"B\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingExtractedPairs() {\n\t\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\t\tmap.put(\"a\", \"A\");\n\t\t\tmap.put(\"b\", \"B\");\n\t\t\tFunction<Map.Entry<String, Object>, String> nameExtractor = Map.Entry::getKey;\n\t\t\tFunction<Map.Entry<String, Object>, Object> valueExtractor = Map.Entry::getValue;\n\t\t\tJsonWriter<Map<String, Object>> writer = JsonWriter.of((members) -> members.add()\n\t\t\t\t.as(Map::entrySet)\n\t\t\t\t.usingExtractedPairs(Set::forEach, nameExtractor, valueExtractor));\n\t\t\tassertThat(writer.writeToString(map)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"a\":\"A\",\"b\":\"B\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingPairs() {\n\t\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\t\tmap.put(\"a\", \"A\");\n\t\t\tmap.put(\"b\", \"B\");\n\t\t\tJsonWriter<Map<String, Object>> writer = JsonWriter.of((members) -> members.add().usingPairs(Map::forEach));\n\t\t\tassertThat(writer.writeToString(map)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"a\":\"A\",\"b\":\"B\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingPairsWhenAlreadyDeclaredThrowsException() {\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> JsonWriter.of((\n\t\t\t\t\tmembers) -> members.from(Collections.emptyMap()).usingPairs(Map::forEach).usingPairs(Map::forEach)))\n\t\t\t\t.withMessage(\"Pairs cannot be declared multiple times\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingPairsWhenUsingMembersThrowsException() {\n\t\t\tassertThatIllegalStateException()\n\t\t\t\t.isThrownBy(() -> JsonWriter.of((members) -> members.from(Collections.emptyMap())\n\t\t\t\t\t.usingMembers((mapMembers) -> mapMembers.add(\"test\"))\n\t\t\t\t\t.usingPairs(Map::forEach)))\n\t\t\t\t.withMessage(\"Pairs cannot be declared when using members\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingMembers() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"personOne\", Couple::person1).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"fn\", Person::firstName);\n\t\t\t\t\tpersonMembers.add(\"ln\", Person::lastName);\n\t\t\t\t});\n\t\t\t\tmembers.add(\"personTwo\", Couple::person2).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"details\", Person::toString);\n\t\t\t\t\tpersonMembers.add(\"eldest\", true);\n\t\t\t\t});\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"personOne\":{\"fn\":\"Spring\",\"ln\":\"Boot\"},\"\"\" + \"\"\"\n\t\t\t\t\t\"personTwo\":{\"details\":\"Spring Framework (20)\",\"eldest\":true}}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingMembersWithoutName() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"version\", 1);\n\t\t\t\tmembers.from(Couple::person1)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"one\", Person::toString));\n\t\t\t\tmembers.from(Couple::person2)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"two\", Person::toString));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"version\":1,\"one\":\"Spring Boot (10)\",\"two\":\"Spring Framework (20)\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingMembersWithoutNameInMember() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> members.add(\"only\", Couple::person2)\n\t\t\t\t.usingMembers((personMembers) -> personMembers.from(Person::toString)));\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"only\":\"Spring Framework (20)\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingMembersWithoutNameAtAll() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> members.from(Couple::person2)\n\t\t\t\t.usingMembers((personMembers) -> personMembers.from(Person::toString)));\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(quoted(\"Spring Framework (20)\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid usingMembersWhenAlreadyDeclaredThrowsException() {\n\t\t\tassertThatIllegalStateException()\n\t\t\t\t.isThrownBy(() -> JsonWriter.of((members) -> members.from(Collections.emptyMap())\n\t\t\t\t\t.usingMembers((mapMembers) -> mapMembers.add(\"test\"))\n\t\t\t\t\t.usingMembers((mapMembers) -> mapMembers.add(\"test\"))))\n\t\t\t\t.withMessage(\"Members cannot be declared multiple times\");\n\t\t}\n\n\t\t@Test\n\t\tvoid usingMembersWhenUsingPairsThrowsException() {\n\t\t\tassertThatIllegalStateException()\n\t\t\t\t.isThrownBy(() -> JsonWriter.of((members) -> members.from(Collections.emptyMap())\n\t\t\t\t\t.usingPairs(Map::forEach)\n\t\t\t\t\t.usingMembers((mapMembers) -> mapMembers.add(\"test\"))))\n\t\t\t\t.withMessage(\"Members cannot be declared when using pairs\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Tests for {@link MemberPath}.\n\t */\n\t@Nested\n\tclass MemberPathTests {\n\n\t\t@Test\n\t\tvoid createWhenIndexAndNamedThrowException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> new MemberPath(null, \"boot\", 0))\n\t\t\t\t.withMessage(\"'name' and 'index' cannot be mixed\");\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> new MemberPath(null, null, -1))\n\t\t\t\t.withMessage(\"'name' and 'index' cannot be mixed\");\n\t\t}\n\n\t\t@Test\n\t\tvoid toStringReturnsUsefulString() {\n\t\t\tassertThat(MemberPath.ROOT).hasToString(\"\");\n\t\t\tMemberPath spring = new MemberPath(MemberPath.ROOT, \"spring\", MemberPath.UNINDEXED);\n\t\t\tMemberPath springDotBoot = new MemberPath(spring, \"boot\", MemberPath.UNINDEXED);\n\t\t\tMemberPath springZero = new MemberPath(spring, null, 0);\n\t\t\tMemberPath springZeroDotBoot = new MemberPath(springZero, \"boot\", MemberPath.UNINDEXED);\n\t\t\tassertThat(spring).hasToString(\"spring\");\n\t\t\tassertThat(springDotBoot).hasToString(\"spring.boot\");\n\t\t\tassertThat(springZero).hasToString(\"spring[0]\");\n\t\t\tassertThat(springZeroDotBoot).hasToString(\"spring[0].boot\");\n\t\t}\n\n\t\t@Test\n\t\tvoid childWithNameCreatesChild() {\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring\").child(\"boot\")).hasToString(\"spring.boot\");\n\t\t}\n\n\t\t@Test\n\t\tvoid childWithNameWhenNameSpecialChars() {\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring.io\").child(\"boot\")).hasToString(\"spring\\\\.io.boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring[io]\").child(\"boot\")).hasToString(\"spring\\\\[io\\\\].boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring.[io]\").child(\"boot\")).hasToString(\"spring\\\\.\\\\[io\\\\].boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring\\\\io\").child(\"boot\")).hasToString(\"spring\\\\\\\\io.boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring.\\\\io\").child(\"boot\")).hasToString(\"spring\\\\.\\\\\\\\io.boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring[\\\\io]\").child(\"boot\")).hasToString(\"spring\\\\[\\\\\\\\io\\\\].boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"123\").child(\"boot\")).hasToString(\"123.boot\");\n\t\t\tassertThat(MemberPath.ROOT.child(\"1.2.3\").child(\"boot\")).hasToString(\"1\\\\.2\\\\.3.boot\");\n\t\t}\n\n\t\t@Test\n\t\tvoid childWithIndexCreatesChild() {\n\t\t\tassertThat(MemberPath.ROOT.child(\"spring\").child(0)).hasToString(\"spring[0]\");\n\t\t}\n\n\t\t@Test\n\t\tvoid ofParsesPaths() {\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring\").child(0));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring.io\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring[io]\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring.[io]\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring\\\\io\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring.\\\\io\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"spring[\\\\io]\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"123\").child(\"boot\"));\n\t\t\tassertOfFromToString(MemberPath.ROOT.child(\"1.2.3\").child(\"boot\"));\n\t\t}\n\n\t\tprivate void assertOfFromToString(MemberPath path) {\n\t\t\tassertThat(MemberPath.of(path.toString())).isEqualTo(path);\n\t\t}\n\n\t}\n\n\t/**\n\t * Tests for {@link Members#applyingPathFilter(java.util.function.Predicate)}.\n\t */\n\t@Nested\n\tclass PathFilterTests {\n\n\t\t@Test\n\t\tvoid filteringMember() {\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"first\", Person::firstName);\n\t\t\t\tmembers.add(\"last\", Person::lastName);\n\t\t\t\tmembers.applyingPathFilter((path) -> {\n\t\t\t\t\tString name = path.name();\n\t\t\t\t\tassertThat(name).isNotNull();\n\t\t\t\t\treturn name.equals(\"first\");\n\t\t\t\t});\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(new Person(\"spring\", \"boot\", 10))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"last\":\"boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid filteringInMap() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingPathFilter((path) -> {\n\t\t\t\t\tString name = path.name();\n\t\t\t\t\tassertThat(name).isNotNull();\n\t\t\t\t\treturn name.equals(\"spring\");\n\t\t\t\t});\n\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\", \"test\", \"test\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"test\":\"test\"}\"\"\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Tests for {@link NameProcessor}.\n\t */\n\t@Nested\n\tclass NameProcessorTests {\n\n\t\t@Test\n\t\tvoid processNameWhenSimpleValue() {\n\t\t\tJsonWriter<String> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(\"test\")).isEqualTo(\"\\\"test\\\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenMember() {\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"first\", Person::firstName);\n\t\t\t\tmembers.add(\"last\", Person::lastName);\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(new Person(\"spring\", \"boot\", 10))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"FIRST\":\"spring\",\"LAST\":\"boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenInMap() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"SPRING\":\"boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenInNestedMap() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"test\", Map.of(\"spring\", \"boot\")))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"TEST\":{\"SPRING\":\"boot\"}}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenInPairs() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add().usingPairs(Map::forEach);\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"SPRING\":\"boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenHasNestedMembers() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.from(Couple::person1)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"one\", Person::toString));\n\t\t\t\tmembers.from(Couple::person2)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"two\", Person::toString));\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"ONE\":\"Spring Boot (10)\",\"TWO\":\"Spring Framework (20)\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenHasNestedMembersWithAdditionalValueProcessor() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.from(Couple::person1)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"one\", Person::toString));\n\t\t\t\tmembers.from(Couple::person2).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"two\", Person::toString);\n\t\t\t\t\tpersonMembers.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\t\t\t});\n\t\t\t\tmembers.applyingNameProcessor(NameProcessor.of((name) -> name + \"!\"));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"one!\":\"Spring Boot (10)\",\"TWO!\":\"Spring Framework (20)\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenDeeplyNestedUsesCompoundPaths() {\n\t\t\tList<String> paths = new ArrayList<>();\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"one\", Couple::person1).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"first\", Person::firstName);\n\t\t\t\t\tpersonMembers.add(\"last\", Person::lastName);\n\t\t\t\t});\n\t\t\t\tmembers.add(\"two\", Couple::person2).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"first\", Person::firstName);\n\t\t\t\t\tpersonMembers.add(\"last\", Person::lastName);\n\t\t\t\t});\n\t\t\t\tmembers.applyingNameProcessor((path, existingName) -> {\n\t\t\t\t\tpaths.add(path.toString());\n\t\t\t\t\treturn existingName;\n\t\t\t\t});\n\t\t\t});\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\twriter.writeToString(couple);\n\t\t\tassertThat(paths).containsExactly(\"one\", \"one.first\", \"one.last\", \"two\", \"two.first\", \"two.last\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenReturnsNullThrowsException() {\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"first\", Person::firstName);\n\t\t\t\tmembers.add(\"last\", Person::lastName);\n\t\t\t\tmembers\n\t\t\t\t\t.applyingNameProcessor((path, existingName) -> !\"first\".equals(existingName) ? existingName : null);\n\t\t\t});\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> writer.writeToString(new Person(\"spring\", \"boot\", 10)))\n\t\t\t\t.withMessageContaining(\"NameProcessor\")\n\t\t\t\t.withMessageContaining(\"returned an empty result\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processNameWhenReturnsEmptyStringThrowsException() {\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"first\", Person::firstName);\n\t\t\t\tmembers.add(\"last\", Person::lastName);\n\t\t\t\tmembers\n\t\t\t\t\t.applyingNameProcessor((path, existingName) -> !\"first\".equals(existingName) ? existingName : \"\");\n\t\t\t});\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> writer.writeToString(new Person(\"spring\", \"boot\", 10)))\n\t\t\t\t.withMessageContaining(\"NameProcessor\")\n\t\t\t\t.withMessageContaining(\"returned an empty result\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Tests for {@link ValueProcessor}.\n\t */\n\t@Nested\n\tclass ValueProcessorTests {\n\n\t\t@Test\n\t\tvoid of() {\n\t\t\tValueProcessor<String> processor = ValueProcessor.of(stringToUppercase());\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT, \"test\")).isEqualTo(\"TEST\");\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid ofWhenNull() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> ValueProcessor.of(null))\n\t\t\t\t.withMessage(\"'action' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasPathWithStringWhenPathMatches() {\n\t\t\tValueProcessor<String> processor = ValueProcessor.of(stringToUppercase()).whenHasPath(\"foo\");\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT.child(\"foo\"), \"test\")).isEqualTo(\"TEST\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasPathWithStringWhenPathDoesNotMatch() {\n\t\t\tValueProcessor<String> processor = ValueProcessor.<String>of(stringToUppercase()).whenHasPath(\"foo\");\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT.child(\"bar\"), \"test\")).isEqualTo(\"test\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasPathWithPredicateWhenPathMatches() {\n\t\t\tValueProcessor<String> processor = ValueProcessor.<String>of(stringToUppercase())\n\t\t\t\t.whenHasPath((path) -> path.toString().startsWith(\"f\"));\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT.child(\"foo\"), \"test\")).isEqualTo(\"TEST\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasPathWithPredicateWhenPathDoesNotMatch() {\n\t\t\tValueProcessor<String> processor = ValueProcessor.<String>of(stringToUppercase())\n\t\t\t\t.whenHasPath((path) -> path.toString().startsWith(\"f\"));\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT.child(\"bar\"), \"test\")).isEqualTo(\"test\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenInstanceOfWhenInstanceMatches() {\n\t\t\tValueProcessor<Object> processor = ValueProcessor.of(objectToUppercase()).whenInstanceOf(String.class);\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT, \"test\")).hasToString(\"TEST\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenInstanceOfWhenInstanceDoesNotMatch() {\n\t\t\tValueProcessor<Object> processor = ValueProcessor.of(objectToUppercase()).whenInstanceOf(String.class);\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT, new StringBuilder(\"test\"))).hasToString(\"test\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenWhenPredicateMatches() {\n\t\t\tPredicate<@Nullable String> equals = \"test\"::equals;\n\t\t\tValueProcessor<String> processor = ValueProcessor.of(stringToUppercase()).when(equals);\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT, \"test\")).isEqualTo(\"TEST\");\n\t\t}\n\n\t\t@Test\n\t\tvoid whenWhenPredicateDoesNotMatch() {\n\t\t\tPredicate<@Nullable String> equals = \"test\"::equals;\n\t\t\tValueProcessor<String> processor = ValueProcessor.of(stringToUppercase()).when(equals);\n\t\t\tassertThat(processor.processValue(MemberPath.ROOT, \"other\")).isEqualTo(\"other\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenSimpleValue() {\n\t\t\tJsonWriter<String> writer = simpleWriterWithUppercaseProcessor();\n\t\t\tassertThat(writer.writeToString(\"test\")).isEqualTo(\"\\\"TEST\\\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenMemberValue() {\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"first\", Person::firstName);\n\t\t\t\tmembers.add(\"last\", Person::lastName);\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(new Person(\"spring\", \"boot\", 10))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"first\":\"Spring\",\"last\":\"Boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenInMap() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"spring\":\"Boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenInNestedMap() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"test\", Map.of(\"spring\", \"boot\")))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"test\":{\"spring\":\"Boot\"}}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenInPairs() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add().usingPairs(Map::forEach);\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"spring\":\"Boot\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenCalledWithMultipleTypesIgnoresLambdaErrors() {\n\t\t\tJsonWriter<Object> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(\"spring\")).isEqualTo(\"\\\"Spring\\\"\");\n\t\t\tassertThat(writer.writeToString(123)).isEqualTo(\"123\");\n\t\t\tassertThat(writer.writeToString(true)).isEqualTo(\"true\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenLimitedToPath() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()).whenHasPath(\"spring\"));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"spring\":\"Boot\"}\"\"\");\n\t\t\tassertThat(writer.writeToString(Map.of(\"boot\", \"spring\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"boot\":\"spring\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhen() {\n\t\t\tJsonWriter<Map<?, ?>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tPredicate<@Nullable String> startsWithB = (candidate) -> candidate != null && candidate.startsWith(\"b\");\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(stringCapitalize()).when(startsWithB));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(Map.of(\"spring\", \"boot\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"spring\":\"Boot\"}\"\"\");\n\t\t\tassertThat(writer.writeToString(Map.of(\"boot\", \"spring\"))).isEqualTo(\"\"\"\n\t\t\t\t\t{\"boot\":\"spring\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenHasNestedMembers() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.from(Couple::person1)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"one\", Person::toString));\n\t\t\t\tmembers.from(Couple::person2)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"two\", Person::toString));\n\t\t\t\tUnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null)\n\t\t\t\t\t\t? string.toUpperCase(Locale.ROOT) : null;\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"one\":\"SPRING BOOT (10)\",\"two\":\"SPRING FRAMEWORK (20)\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenHasNestedMembersWithAdditionalValueProcessor() {\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.from(Couple::person1)\n\t\t\t\t\t.usingMembers((personMembers) -> personMembers.add(\"one\", Person::toString));\n\t\t\t\tmembers.from(Couple::person2).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"two\", Person::toString);\n\t\t\t\t\tUnaryOperator<@Nullable String> operator = (item) -> item + \"!\";\n\t\t\t\t\tpersonMembers.applyingValueProcessor(ValueProcessor.of(String.class, operator));\n\t\t\t\t});\n\t\t\t\tUnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null)\n\t\t\t\t\t\t? string.toUpperCase(Locale.ROOT) : null;\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));\n\t\t\t});\n\t\t\tassertThat(writer.writeToString(couple)).isEqualTo(\"\"\"\n\t\t\t\t\t{\"one\":\"SPRING BOOT (10)\",\"two\":\"SPRING FRAMEWORK (20)!\"}\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenDeeplyNestedUsesCompoundPaths() {\n\t\t\tList<String> paths = new ArrayList<>();\n\t\t\tJsonWriter<Couple> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"one\", Couple::person1).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"first\", Person::firstName);\n\t\t\t\t\tpersonMembers.add(\"last\", Person::lastName);\n\t\t\t\t});\n\t\t\t\tmembers.add(\"two\", Couple::person2).usingMembers((personMembers) -> {\n\t\t\t\t\tpersonMembers.add(\"first\", Person::firstName);\n\t\t\t\t\tpersonMembers.add(\"last\", Person::lastName);\n\t\t\t\t});\n\t\t\t\tmembers.applyingValueProcessor((path, value) -> {\n\t\t\t\t\tpaths.add(path.toString());\n\t\t\t\t\treturn value;\n\t\t\t\t});\n\t\t\t});\n\t\t\tCouple couple = new Couple(PERSON, new Person(\"Spring\", \"Framework\", 20));\n\t\t\twriter.writeToString(couple);\n\t\t\tassertThat(paths).containsExactly(\"one\", \"one.first\", \"one.last\", \"two\", \"two.first\", \"two.last\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueWhenUsingListUsesIndexedPaths() {\n\t\t\tList<String> paths = new ArrayList<>();\n\t\t\tJsonWriter<List<String>> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tmembers.applyingValueProcessor((path, value) -> {\n\t\t\t\t\tpaths.add(path.toString());\n\t\t\t\t\treturn value;\n\t\t\t\t});\n\t\t\t});\n\t\t\twriter.writeToString(List.of(\"a\", \"b\", \"c\"));\n\t\t\tassertThat(paths).containsExactly(\"\", \"[0]\", \"[1]\", \"[2]\");\n\t\t}\n\n\t\t@Test\n\t\tvoid processValueUsesUnprocessedNameInPath() {\n\t\t\tList<String> paths = new ArrayList<>();\n\t\t\tJsonWriter<Person> writer = JsonWriter.of((members) -> {\n\t\t\t\tmembers.add(\"first\", Person::firstName);\n\t\t\t\tmembers.add(\"last\", Person::lastName);\n\t\t\t\tmembers.applyingValueProcessor((path, value) -> {\n\t\t\t\t\tpaths.add(path.toString());\n\t\t\t\t\treturn value;\n\t\t\t\t});\n\t\t\t\tmembers.applyingNameProcessor((path, existingName) -> \"the-\" + existingName);\n\t\t\t});\n\t\t\twriter.writeToString(PERSON);\n\t\t\tassertThat(paths).containsExactly(\"first\", \"last\");\n\t\t}\n\n\t\tprivate static UnaryOperator<@Nullable String> stringToUppercase() {\n\t\t\treturn (string) -> (string != null) ? string.toUpperCase(Locale.ROOT) : null;\n\t\t}\n\n\t\tprivate static UnaryOperator<@Nullable Object> objectToUppercase() {\n\t\t\treturn (string) -> (string != null) ? string.toString().toUpperCase(Locale.ROOT) : null;\n\t\t}\n\n\t\tprivate static UnaryOperator<@Nullable String> stringCapitalize() {\n\t\t\treturn (string) -> (string != null) ? StringUtils.capitalize(string) : null;\n\t\t}\n\n\t\tprivate JsonWriter<String> simpleWriterWithUppercaseProcessor() {\n\t\t\treturn JsonWriter.of((members) -> {\n\t\t\t\tmembers.add();\n\t\t\t\tUnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null)\n\t\t\t\t\t\t? string.toUpperCase(Locale.ROOT) : null;\n\t\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));\n\t\t\t});\n\t\t}\n\n\t}\n\n\trecord Person(String firstName, @Nullable String lastName, int age) {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"%s %s (%s)\".formatted(this.firstName, this.lastName, this.age);\n\t\t}\n\n\t}\n\n\trecord Couple(Person person1, Person person2) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/json/WritableJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.io.FileSystemResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link WritableJson}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass WritableJsonTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid toJsonStringReturnsString() {\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThat(writable.toJsonString()).isEqualTo(\"{}\");\n\t}\n\n\t@Test\n\tvoid toJsonStringWhenIOExceptionIsThrownThrowsUncheckedIOException() {\n\t\tWritableJson writable = (out) -> {\n\t\t\tthrow new IOException(\"bad\");\n\t\t};\n\t\tassertThatExceptionOfType(UncheckedIOException.class).isThrownBy(() -> writable.toJsonString())\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"bad\");\n\t}\n\n\t@Test\n\tvoid toByteArrayReturnsByteArray() {\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThat(writable.toByteArray()).isEqualTo(\"{}\".getBytes());\n\t}\n\n\t@Test\n\tvoid toResourceWritesJson() throws Exception {\n\t\tFile file = new File(this.temp, \"out.json\");\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\twritable.toResource(new FileSystemResource(file));\n\t\tassertThat(file).content().isEqualTo(\"{}\");\n\t}\n\n\t@Test\n\tvoid toResourceWithCharsetWritesJson() throws Exception {\n\t\tFile file = new File(this.temp, \"out.json\");\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\twritable.toResource(new FileSystemResource(file), StandardCharsets.ISO_8859_1);\n\t\tassertThat(file).content(StandardCharsets.ISO_8859_1).isEqualTo(\"{}\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid toResourceWithCharsetWhenOutIsNullThrowsException() {\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> writable.toResource(null, StandardCharsets.UTF_8))\n\t\t\t.withMessage(\"'out' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid toResourceWithCharsetWhenCharsetIsNullThrowsException() {\n\t\tFile file = new File(this.temp, \"out.json\");\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> writable.toResource(new FileSystemResource(file), null))\n\t\t\t.withMessage(\"'charset' must not be null\");\n\t}\n\n\t@Test\n\tvoid toOutputStreamWritesJson() throws Exception {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\twritable.toOutputStream(outputStream);\n\t\tassertThat(outputStream.toString(StandardCharsets.UTF_8)).isEqualTo(\"{}\");\n\t}\n\n\t@Test\n\tvoid toOutputStreamWithCharsetWritesJson() throws Exception {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\twritable.toOutputStream(outputStream, StandardCharsets.ISO_8859_1);\n\t\tassertThat(outputStream.toString(StandardCharsets.ISO_8859_1)).isEqualTo(\"{}\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid toOutputStreamWithCharsetWhenOutIsNullThrowsException() {\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> writable.toOutputStream(null, StandardCharsets.UTF_8))\n\t\t\t.withMessage(\"'out' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid toOutputStreamWithCharsetWhenCharsetIsNullThrowsException() {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> writable.toOutputStream(outputStream, null))\n\t\t\t.withMessage(\"'charset' must not be null\");\n\t}\n\n\t@Test\n\tvoid toWriterWritesJson() throws Exception {\n\t\tStringWriter writer = new StringWriter();\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\twritable.toWriter(writer);\n\t\tassertThat(writer).hasToString(\"{}\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid toWriterWhenWriterIsNullThrowsException() {\n\t\tWritableJson writable = (out) -> out.append(\"{}\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> writable.toWriter(null))\n\t\t\t.withMessage(\"'out' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofReturnsInstanceWithSensibleToString() {\n\t\tWritableJson writable = WritableJson.of((out) -> out.append(\"{}\"));\n\t\tassertThat(writable).hasToString(\"{}\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/AbstractLoggingSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Arrays;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.slf4j.MDC;\n\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Base for {@link LoggingSystem} tests.\n *\n * @author Ilya Lukyanovich\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic abstract class AbstractLoggingSystemTests {\n\n\tprivate static final String JAVA_IO_TMPDIR = \"java.io.tmpdir\";\n\n\tprivate String originalTempDirectory;\n\n\t@BeforeEach\n\tvoid configureTempDir(@TempDir Path temp) throws IOException {\n\t\tthis.originalTempDirectory = System.getProperty(JAVA_IO_TMPDIR);\n\t\tFiles.delete(Files.createTempFile(\"prevent\", \"pollution\"));\n\t\tFile.createTempFile(\"prevent\", \"pollution\").delete();\n\t\tSystem.setProperty(JAVA_IO_TMPDIR, temp.toAbsolutePath().toString());\n\t\tMDC.clear();\n\t}\n\n\t@AfterEach\n\tvoid reinstateTempDir() {\n\t\tSystem.setProperty(JAVA_IO_TMPDIR, this.originalTempDirectory);\n\t}\n\n\t@AfterEach\n\tvoid clear() {\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t\tMDC.clear();\n\t}\n\n\tprotected final String[] getSpringConfigLocations(AbstractLoggingSystem system) {\n\t\treturn system.getSpringConfigLocations();\n\t}\n\n\tprotected final LogFile getLogFile(@Nullable String file, @Nullable String path) {\n\t\treturn getLogFile(file, path, true);\n\t}\n\n\tprotected final LogFile getLogFile(@Nullable String file, @Nullable String path, boolean applyToSystemProperties) {\n\t\tLogFile logFile = new LogFile(file, path);\n\t\tif (applyToSystemProperties) {\n\t\t\tlogFile.applyToSystemProperties();\n\t\t}\n\t\treturn logFile;\n\t}\n\n\tprotected final String tmpDir() {\n\t\tString path = StringUtils.cleanPath(System.getProperty(JAVA_IO_TMPDIR));\n\t\tif (path.endsWith(\"/\")) {\n\t\t\tpath = path.substring(0, path.length() - 1);\n\t\t}\n\t\treturn path;\n\t}\n\n\tprotected final @Nullable String getLineWithText(File file, CharSequence outputSearch) {\n\t\treturn getLineWithText(contentOf(file), outputSearch);\n\t}\n\n\tprotected final @Nullable String getLineWithText(CharSequence output, CharSequence outputSearch) {\n\t\treturn Arrays.stream(output.toString().split(\"\\\\r?\\\\n\"))\n\t\t\t.filter((line) -> line.contains(outputSearch))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/CorrelationIdFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link CorrelationIdFormatter}.\n *\n * @author Phillip Webb\n */\nclass CorrelationIdFormatterTests {\n\n\t@Test\n\tvoid formatWithDefaultSpecWhenHasBothParts() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"traceId\", \"01234567890123456789012345678901\");\n\t\tcontext.put(\"spanId\", \"0123456789012345\");\n\t\tString formatted = CorrelationIdFormatter.DEFAULT.format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid formatWithDefaultSpecWhenHasNoParts() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tString formatted = CorrelationIdFormatter.DEFAULT.format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[                                                 ] \");\n\t}\n\n\t@Test\n\tvoid formatWithDefaultSpecWhenHasOnlyFirstPart() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"traceId\", \"01234567890123456789012345678901\");\n\t\tString formatted = CorrelationIdFormatter.DEFAULT.format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[01234567890123456789012345678901-                ] \");\n\t}\n\n\t@Test\n\tvoid formatWithDefaultSpecWhenHasOnlySecondPart() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"spanId\", \"0123456789012345\");\n\t\tString formatted = CorrelationIdFormatter.DEFAULT.format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[                                -0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid formatWhenPartsAreShort() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"traceId\", \"0123456789012345678901234567\");\n\t\tcontext.put(\"spanId\", \"012345678901\");\n\t\tString formatted = CorrelationIdFormatter.DEFAULT.format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[0123456789012345678901234567    -012345678901    ] \");\n\t}\n\n\t@Test\n\tvoid formatWhenPartsAreLong() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"traceId\", \"01234567890123456789012345678901FFFF\");\n\t\tcontext.put(\"spanId\", \"0123456789012345FFFF\");\n\t\tString formatted = CorrelationIdFormatter.DEFAULT.format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[01234567890123456789012345678901FFFF-0123456789012345FFFF] \");\n\t}\n\n\t@Test\n\tvoid formatWithCustomSpec() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"a\", \"01234567890123456789012345678901\");\n\t\tcontext.put(\"b\", \"0123456789012345\");\n\t\tString formatted = CorrelationIdFormatter.of(\"a(32),b(16)\").format(context::get);\n\t\tassertThat(formatted).isEqualTo(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid formatToWithDefaultSpec() {\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"traceId\", \"01234567890123456789012345678901\");\n\t\tcontext.put(\"spanId\", \"0123456789012345\");\n\t\tStringBuilder formatted = new StringBuilder();\n\t\tCorrelationIdFormatter.DEFAULT.formatTo(context::get, formatted);\n\t\tassertThat(formatted).hasToString(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid ofWhenSpecIsMalformed() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> CorrelationIdFormatter.of(\"good(12),bad\"))\n\t\t\t.withMessage(\"Unable to parse correlation formatter spec 'good(12),bad'\")\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"Invalid specification part 'bad'\");\n\t}\n\n\t@Test\n\tvoid ofWhenSpecIsEmpty() {\n\t\tassertThat(CorrelationIdFormatter.of(\"\")).isSameAs(CorrelationIdFormatter.DEFAULT);\n\t}\n\n\t@Test\n\tvoid toStringReturnsSpec() {\n\t\tassertThat(CorrelationIdFormatter.DEFAULT).hasToString(\"traceId(32),spanId(16)\");\n\t\tassertThat(CorrelationIdFormatter.of(\"a(32),b(16)\")).hasToString(\"a(32),b(16)\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DeferredLogFactory}.\n *\n * @author Phillip Webb\n */\nclass DeferredLogFactoryTests {\n\n\tprivate final DeferredLogFactory factory = (supplier) -> this.log = supplier.get();\n\n\tprivate @Nullable Log log;\n\n\t@Test\n\tvoid getLogFromClassCreatesLogSupplier() {\n\t\tthis.factory.getLog(DeferredLogFactoryTests.class);\n\t\tassertThat(this.log).isNotNull();\n\t}\n\n\t@Test\n\tvoid getLogFromDestinationCreatesLogSupplier() {\n\t\tLog log = mock(Log.class);\n\t\tthis.factory.getLog(log);\n\t\tassertThat(this.log).isSameAs(log);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.apache.commons.logging.Log;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.DeferredLog.Lines;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DeferredLog}.\n *\n * @author Phillip Webb\n */\nclass DeferredLogTests {\n\n\tprivate final DeferredLog deferredLog = new DeferredLog();\n\n\tprivate final Object message = \"Message\";\n\n\tprivate final Throwable throwable = new IllegalStateException();\n\n\tprivate final Log log = mock(Log.class);\n\n\t@Test\n\tvoid isTraceEnabled() {\n\t\tassertThat(this.deferredLog.isTraceEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid isDebugEnabled() {\n\t\tassertThat(this.deferredLog.isDebugEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid isInfoEnabled() {\n\t\tassertThat(this.deferredLog.isInfoEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid isWarnEnabled() {\n\t\tassertThat(this.deferredLog.isWarnEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid isErrorEnabled() {\n\t\tassertThat(this.deferredLog.isErrorEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid isFatalEnabled() {\n\t\tassertThat(this.deferredLog.isFatalEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid trace() {\n\t\tthis.deferredLog.trace(this.message);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().trace(this.message, null);\n\t}\n\n\t@Test\n\tvoid traceWithThrowable() {\n\t\tthis.deferredLog.trace(this.message, this.throwable);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().trace(this.message, this.throwable);\n\t}\n\n\t@Test\n\tvoid debug() {\n\t\tthis.deferredLog.debug(this.message);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().debug(this.message, null);\n\t}\n\n\t@Test\n\tvoid debugWithThrowable() {\n\t\tthis.deferredLog.debug(this.message, this.throwable);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().debug(this.message, this.throwable);\n\t}\n\n\t@Test\n\tvoid info() {\n\t\tthis.deferredLog.info(this.message);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().info(this.message, null);\n\t}\n\n\t@Test\n\tvoid infoWithThrowable() {\n\t\tthis.deferredLog.info(this.message, this.throwable);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().info(this.message, this.throwable);\n\t}\n\n\t@Test\n\tvoid warn() {\n\t\tthis.deferredLog.warn(this.message);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().warn(this.message, null);\n\t}\n\n\t@Test\n\tvoid warnWithThrowable() {\n\t\tthis.deferredLog.warn(this.message, this.throwable);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().warn(this.message, this.throwable);\n\t}\n\n\t@Test\n\tvoid error() {\n\t\tthis.deferredLog.error(this.message);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().error(this.message, null);\n\t}\n\n\t@Test\n\tvoid errorWithThrowable() {\n\t\tthis.deferredLog.error(this.message, this.throwable);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().error(this.message, this.throwable);\n\t}\n\n\t@Test\n\tvoid fatal() {\n\t\tthis.deferredLog.fatal(this.message);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().fatal(this.message, null);\n\t}\n\n\t@Test\n\tvoid fatalWithThrowable() {\n\t\tthis.deferredLog.fatal(this.message, this.throwable);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthen(this.log).should().fatal(this.message, this.throwable);\n\t}\n\n\t@Test\n\tvoid clearsOnReplayTo() {\n\t\tthis.deferredLog.info(\"1\");\n\t\tthis.deferredLog.fatal(\"2\");\n\t\tLog log2 = mock(Log.class);\n\t\tthis.deferredLog.replayTo(this.log);\n\t\tthis.deferredLog.replayTo(log2);\n\t\tthen(this.log).should().info(\"1\", null);\n\t\tthen(this.log).should().fatal(\"2\", null);\n\t\tthen(this.log).shouldHaveNoMoreInteractions();\n\t\tthen(log2).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid switchTo() {\n\t\tLines lines = (Lines) ReflectionTestUtils.getField(this.deferredLog, \"lines\");\n\t\tassertThat(lines).isEmpty();\n\t\tthis.deferredLog.error(this.message, this.throwable);\n\t\tassertThat(lines).hasSize(1);\n\t\tthis.deferredLog.switchTo(this.log);\n\t\tassertThat(lines).isEmpty();\n\t\tthis.deferredLog.info(\"Message2\");\n\t\tassertThat(lines).isEmpty();\n\t\tthen(this.log).should().error(this.message, this.throwable);\n\t\tthen(this.log).should().info(\"Message2\", null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/DeferredLogsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.apache.commons.logging.Log;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DeferredLogs}.\n *\n * @author Phillip Webb\n */\nclass DeferredLogsTests {\n\n\t@Test\n\tvoid switchOverAllSwitchesLoggersWithOrderedOutput() {\n\t\tLog log1 = mock(Log.class);\n\t\tLog log2 = mock(Log.class);\n\t\tDeferredLogs loggers = new DeferredLogs();\n\t\tLog dlog1 = loggers.getLog(log1);\n\t\tLog dlog2 = loggers.getLog(log2);\n\t\tdlog1.info(\"a\");\n\t\tdlog2.info(\"b\");\n\t\tdlog1.info(\"c\");\n\t\tdlog2.info(\"d\");\n\t\tthen(log1).shouldHaveNoInteractions();\n\t\tthen(log2).shouldHaveNoInteractions();\n\t\tloggers.switchOverAll();\n\t\tInOrder ordered = inOrder(log1, log2);\n\t\tthen(log1).should(ordered).info(\"a\", null);\n\t\tthen(log2).should(ordered).info(\"b\", null);\n\t\tthen(log1).should(ordered).info(\"c\", null);\n\t\tthen(log2).should(ordered).info(\"d\", null);\n\t\tthen(log1).shouldHaveNoMoreInteractions();\n\t\tthen(log2).shouldHaveNoMoreInteractions();\n\t\tdlog1.info(\"e\");\n\t\tdlog2.info(\"f\");\n\t\tthen(log1).should(ordered).info(\"e\", null);\n\t\tthen(log2).should(ordered).info(\"f\", null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/DelegatingLoggingSystemFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DelegatingLoggingSystemFactory}.\n *\n * @author Phillip Webb\n */\nclass DelegatingLoggingSystemFactoryTests {\n\n\tprivate final ClassLoader classLoader = getClass().getClassLoader();\n\n\t@Test\n\tvoid getLoggingSystemWhenDelegatesFunctionIsNullReturnsNull() {\n\t\tDelegatingLoggingSystemFactory factory = new DelegatingLoggingSystemFactory(null);\n\t\tassertThat(factory.getLoggingSystem(this.classLoader)).isNull();\n\t}\n\n\t@Test\n\tvoid getLoggingSystemWhenDelegatesFunctionReturnsNullReturnsNull() {\n\t\tDelegatingLoggingSystemFactory factory = new DelegatingLoggingSystemFactory((cl) -> null);\n\t\tassertThat(factory.getLoggingSystem(this.classLoader)).isNull();\n\t}\n\n\t@Test\n\tvoid getLoggingSystemReturnsFirstNonNullLoggingSystem() {\n\t\tList<LoggingSystemFactory> delegates = new ArrayList<>();\n\t\tdelegates.add(mock(LoggingSystemFactory.class));\n\t\tdelegates.add(mock(LoggingSystemFactory.class));\n\t\tdelegates.add(mock(LoggingSystemFactory.class));\n\t\tLoggingSystem result = mock(LoggingSystem.class);\n\t\tgiven(delegates.get(1).getLoggingSystem(this.classLoader)).willReturn(result);\n\t\tDelegatingLoggingSystemFactory factory = new DelegatingLoggingSystemFactory((cl) -> delegates);\n\t\tassertThat(factory.getLoggingSystem(this.classLoader)).isSameAs(result);\n\t\tthen(delegates.get(0)).should().getLoggingSystem(this.classLoader);\n\t\tthen(delegates.get(1)).should().getLoggingSystem(this.classLoader);\n\t\tthen(delegates.get(2)).shouldHaveNoInteractions();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LogFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySourcesPropertyResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LogFile}.\n *\n * @author Phillip Webb\n */\nclass LogFileTests {\n\n\t@Test\n\tvoid noProperties() {\n\t\tPropertyResolver resolver = getPropertyResolver(Collections.emptyMap());\n\t\tLogFile logFile = LogFile.get(resolver);\n\t\tassertThat(logFile).isNull();\n\t}\n\n\t@Test\n\tvoid loggingFile() {\n\t\tPropertyResolver resolver = getPropertyResolver(Collections.singletonMap(\"logging.file.name\", \"log.file\"));\n\t\ttestLoggingFile(resolver);\n\t}\n\n\tprivate void testLoggingFile(PropertyResolver resolver) {\n\t\tLogFile logFile = LogFile.get(resolver);\n\t\tassertThat(logFile).isNotNull();\n\t\tProperties properties = new Properties();\n\t\tlogFile.applyTo(properties);\n\t\tassertThat(logFile).hasToString(\"log.file\");\n\t\tassertThat(properties.getProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"log.file\");\n\t\tassertThat(properties.getProperty(LoggingSystemProperty.LOG_PATH.getEnvironmentVariableName())).isNull();\n\t}\n\n\t@Test\n\tvoid loggingPath() {\n\t\tPropertyResolver resolver = getPropertyResolver(Collections.singletonMap(\"logging.file.path\", \"logpath\"));\n\t\ttestLoggingPath(resolver);\n\t}\n\n\tprivate void testLoggingPath(PropertyResolver resolver) {\n\t\tLogFile logFile = LogFile.get(resolver);\n\t\tassertThat(logFile).isNotNull();\n\t\tProperties properties = new Properties();\n\t\tlogFile.applyTo(properties);\n\t\tassertThat(logFile).hasToString(\"logpath\" + File.separatorChar + \"spring.log\");\n\t\tassertThat(properties.getProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"logpath\" + File.separatorChar + \"spring.log\");\n\t\tassertThat(properties.getProperty(LoggingSystemProperty.LOG_PATH.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"logpath\");\n\t}\n\n\t@Test\n\tvoid loggingFileAndPath() {\n\t\tMap<String, Object> properties = new LinkedHashMap<>();\n\t\tproperties.put(\"logging.file.name\", \"log.file\");\n\t\tproperties.put(\"logging.file.path\", \"logpath\");\n\t\tPropertyResolver resolver = getPropertyResolver(properties);\n\t\ttestLoggingFileAndPath(resolver);\n\t}\n\n\tprivate void testLoggingFileAndPath(PropertyResolver resolver) {\n\t\tLogFile logFile = LogFile.get(resolver);\n\t\tassertThat(logFile).isNotNull();\n\t\tProperties properties = new Properties();\n\t\tlogFile.applyTo(properties);\n\t\tassertThat(logFile).hasToString(\"log.file\");\n\t\tassertThat(properties.getProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"log.file\");\n\t\tassertThat(properties.getProperty(LoggingSystemProperty.LOG_PATH.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"logpath\");\n\t}\n\n\tprivate PropertyResolver getPropertyResolver(Map<String, Object> properties) {\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"properties\", properties);\n\t\tMutablePropertySources propertySources = new MutablePropertySources();\n\t\tpropertySources.addFirst(propertySource);\n\t\treturn new PropertySourcesPropertyResolver(propertySources);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LogLevelTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.apache.commons.logging.Log;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LogLevel}.\n *\n * @author Phillip Webb\n */\nclass LogLevelTests {\n\n\tprivate Log logger = mock(Log.class);\n\n\tprivate Exception exception = new Exception();\n\n\t@Test\n\tvoid logWhenTraceLogsAtTrace() {\n\t\tLogLevel.TRACE.log(this.logger, \"test\");\n\t\tLogLevel.TRACE.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).should().trace(\"test\", null);\n\t\tthen(this.logger).should().trace(\"test\", this.exception);\n\t}\n\n\t@Test\n\tvoid logWhenDebugLogsAtDebug() {\n\t\tLogLevel.DEBUG.log(this.logger, \"test\");\n\t\tLogLevel.DEBUG.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).should().debug(\"test\", null);\n\t\tthen(this.logger).should().debug(\"test\", this.exception);\n\t}\n\n\t@Test\n\tvoid logWhenInfoLogsAtInfo() {\n\t\tLogLevel.INFO.log(this.logger, \"test\");\n\t\tLogLevel.INFO.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).should().info(\"test\", null);\n\t\tthen(this.logger).should().info(\"test\", this.exception);\n\t}\n\n\t@Test\n\tvoid logWhenWarnLogsAtWarn() {\n\t\tLogLevel.WARN.log(this.logger, \"test\");\n\t\tLogLevel.WARN.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).should().warn(\"test\", null);\n\t\tthen(this.logger).should().warn(\"test\", this.exception);\n\t}\n\n\t@Test\n\tvoid logWhenErrorLogsAtError() {\n\t\tLogLevel.ERROR.log(this.logger, \"test\");\n\t\tLogLevel.ERROR.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).should().error(\"test\", null);\n\t\tthen(this.logger).should().error(\"test\", this.exception);\n\t}\n\n\t@Test\n\tvoid logWhenFatalLogsAtFatal() {\n\t\tLogLevel.FATAL.log(this.logger, \"test\");\n\t\tLogLevel.FATAL.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).should().fatal(\"test\", null);\n\t\tthen(this.logger).should().fatal(\"test\", this.exception);\n\t}\n\n\t@Test\n\tvoid logWhenOffDoesNotLog() {\n\t\tLogLevel.OFF.log(this.logger, \"test\");\n\t\tLogLevel.OFF.log(this.logger, \"test\", this.exception);\n\t\tthen(this.logger).shouldHaveNoInteractions();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LogbackAndLog4J2ExcludedLoggingSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.java.JavaLoggingSystem;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LoggingSystem} when Logback is not on the classpath.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions({ \"log4j-*.jar\", \"logback-*.jar\" })\nclass LogbackAndLog4J2ExcludedLoggingSystemTests {\n\n\t@Test\n\tvoid whenLogbackAndLog4J2AreNotPresentJULIsTheLoggingSystem() {\n\t\tassertThat(LoggingSystem.get(getClass().getClassLoader())).isInstanceOf(JavaLoggingSystem.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerConfigurationComparatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LoggerConfigurationComparator}.\n *\n * @author Ben Hale\n */\nclass LoggerConfigurationComparatorTests {\n\n\tprivate final LoggerConfigurationComparator comparator = new LoggerConfigurationComparator(\"ROOT\");\n\n\t@Test\n\tvoid rootLoggerFirst() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"ROOT\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"alpha\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isLessThan(0);\n\t}\n\n\t@Test\n\tvoid rootLoggerSecond() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"alpha\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"ROOT\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isGreaterThan(0);\n\t}\n\n\t@Test\n\tvoid rootLoggerFirstEmpty() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"ROOT\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isLessThan(0);\n\t}\n\n\t@Test\n\tvoid rootLoggerSecondEmpty() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"ROOT\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isGreaterThan(0);\n\t}\n\n\t@Test\n\tvoid lexicalFirst() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"alpha\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"bravo\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isLessThan(0);\n\t}\n\n\t@Test\n\tvoid lexicalSecond() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"bravo\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"alpha\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isGreaterThan(0);\n\t}\n\n\t@Test\n\tvoid lexicalEqual() {\n\t\tLoggerConfiguration first = new LoggerConfiguration(\"alpha\", null, LogLevel.OFF);\n\t\tLoggerConfiguration second = new LoggerConfiguration(\"alpha\", null, LogLevel.OFF);\n\t\tassertThat(this.comparator.compare(first, second)).isZero();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.LoggerConfiguration.ConfigurationScope;\nimport org.springframework.boot.logging.LoggerConfiguration.LevelConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link LoggerConfiguration}.\n *\n * @author Phillip Webb\n */\nclass LoggerConfigurationTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithLogLevelWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new LoggerConfiguration(null, null, LogLevel.DEBUG))\n\t\t\t.withMessage(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithLogLevelWhenEffectiveLevelIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new LoggerConfiguration(\"test\", null, (LogLevel) null))\n\t\t\t.withMessage(\"'effectiveLevel' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithLevelConfigurationWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new LoggerConfiguration(null, null, LevelConfiguration.of(LogLevel.DEBUG)))\n\t\t\t.withMessage(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithLevelConfigurationWhenInheritedLevelConfigurationIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new LoggerConfiguration(\"test\", null, (LevelConfiguration) null))\n\t\t\t.withMessage(\"'inheritedLevelConfiguration' must not be null\");\n\t}\n\n\t@Test\n\tvoid getNameReturnsName() {\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", null,\n\t\t\t\tLevelConfiguration.of(LogLevel.DEBUG));\n\t\tassertThat(configuration.getName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getConfiguredLevelWhenConfiguredReturnsLevel() {\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", LevelConfiguration.of(LogLevel.DEBUG),\n\t\t\t\tLevelConfiguration.of(LogLevel.DEBUG));\n\t\tassertThat(configuration.getConfiguredLevel()).isEqualTo(LogLevel.DEBUG);\n\t}\n\n\t@Test\n\tvoid getConfiguredLevelWhenNotConfiguredReturnsNull() {\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", null,\n\t\t\t\tLevelConfiguration.of(LogLevel.DEBUG));\n\t\tassertThat(configuration.getConfiguredLevel()).isNull();\n\t}\n\n\t@Test\n\tvoid getEffectiveLevelReturnsEffectiveLevel() {\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", null,\n\t\t\t\tLevelConfiguration.of(LogLevel.DEBUG));\n\t\tassertThat(configuration.getEffectiveLevel()).isEqualTo(LogLevel.DEBUG);\n\t}\n\n\t@Test\n\tvoid getLevelConfigurationWithDirectScopeWhenConfiguredReturnsConfiguration() {\n\t\tLevelConfiguration assigned = LevelConfiguration.of(LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", assigned,\n\t\t\t\tLevelConfiguration.of(LogLevel.DEBUG));\n\t\tassertThat(configuration.getLevelConfiguration(ConfigurationScope.DIRECT)).isEqualTo(assigned);\n\t}\n\n\t@Test\n\tvoid getLevelConfigurationWithDirectScopeWhenNotConfiguredReturnsNull() {\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", null,\n\t\t\t\tLevelConfiguration.of(LogLevel.DEBUG));\n\t\tassertThat(configuration.getLevelConfiguration(ConfigurationScope.DIRECT)).isNull();\n\t}\n\n\t@Test\n\tvoid getLevelConfigurationWithInheritedScopeReturnsConfiguration() {\n\t\tLevelConfiguration effective = LevelConfiguration.of(LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = new LoggerConfiguration(\"test\", null, effective);\n\t\tassertThat(configuration.getLevelConfiguration(ConfigurationScope.INHERITED)).isEqualTo(effective);\n\t}\n\n\t/**\n\t * Tests for {@link LevelConfiguration}.\n\t */\n\t@Nested\n\tclass LevelConfigurationTests {\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid ofWhenLogLevelIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> LevelConfiguration.of(null))\n\t\t\t\t.withMessage(\"'logLevel' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid ofCreatesConfiguration() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.of(LogLevel.DEBUG);\n\t\t\tassertThat(configuration.getLevel()).isEqualTo(LogLevel.DEBUG);\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tvoid ofCustomWhenNameIsNullThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> LevelConfiguration.ofCustom(null))\n\t\t\t\t.withMessage(\"'name' must not be empty\");\n\t\t}\n\n\t\t@Test\n\t\tvoid ofCustomWhenNameIsEmptyThrowsException() {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> LevelConfiguration.ofCustom(\"\"))\n\t\t\t\t.withMessage(\"'name' must not be empty\");\n\t\t}\n\n\t\t@Test\n\t\tvoid ofCustomCreatesConfiguration() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.ofCustom(\"FINE\");\n\t\t\tassertThat(configuration).isNotNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid getNameWhenFromLogLevelReturnsName() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.of(LogLevel.DEBUG);\n\t\t\tassertThat(configuration.getName()).isEqualTo(\"DEBUG\");\n\t\t}\n\n\t\t@Test\n\t\tvoid getNameWhenCustomReturnsName() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.ofCustom(\"FINE\");\n\t\t\tassertThat(configuration.getName()).isEqualTo(\"FINE\");\n\t\t}\n\n\t\t@Test\n\t\tvoid getLevelWhenCustomThrowsException() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.ofCustom(\"FINE\");\n\t\t\tassertThatIllegalStateException().isThrownBy(configuration::getLevel)\n\t\t\t\t.withMessage(\"Unable to provide LogLevel for 'FINE'\");\n\t\t}\n\n\t\t@Test\n\t\tvoid getLevelReturnsLevel() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.of(LogLevel.DEBUG);\n\t\t\tassertThat(configuration.getLevel()).isEqualTo(LogLevel.DEBUG);\n\t\t}\n\n\t\t@Test\n\t\tvoid isCustomWhenNotCustomReturnsFalse() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.of(LogLevel.DEBUG);\n\t\t\tassertThat(configuration.isCustom()).isFalse();\n\t\t}\n\n\t\t@Test\n\t\tvoid isCustomWhenCustomReturnsTrue() {\n\t\t\tLevelConfiguration configuration = LevelConfiguration.ofCustom(\"DEBUG\");\n\t\t\tassertThat(configuration.isCustom()).isTrue();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LoggerGroupsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LoggerGroups}\n *\n * @author HaiTao Zhang\n * @author Madhura Bhave\n */\nclass LoggerGroupsTests {\n\n\t@Test\n\tvoid putAllShouldAddLoggerGroups() {\n\t\tMap<String, List<String>> groups = Collections.singletonMap(\"test\",\n\t\t\t\tArrays.asList(\"test.member\", \"test.member2\"));\n\t\tLoggerGroups loggerGroups = new LoggerGroups();\n\t\tloggerGroups.putAll(groups);\n\t\tLoggerGroup group = loggerGroups.get(\"test\");\n\t\tassertThat(group).isNotNull();\n\t\tassertThat(group.getMembers()).containsExactly(\"test.member\", \"test.member2\");\n\t}\n\n\t@Test\n\tvoid iteratorShouldReturnLoggerGroups() {\n\t\tLoggerGroups groups = createLoggerGroups();\n\t\tassertThat(groups).hasSize(3);\n\t\tassertThat(groups).extracting(\"name\").containsExactlyInAnyOrder(\"test0\", \"test1\", \"test2\");\n\t}\n\n\tprivate LoggerGroups createLoggerGroups() {\n\t\tMap<String, List<String>> groups = new LinkedHashMap<>();\n\t\tgroups.put(\"test0\", Arrays.asList(\"test0.member\", \"test0.member2\"));\n\t\tgroups.put(\"test1\", Arrays.asList(\"test1.member\", \"test1.member2\"));\n\t\tgroups.put(\"test2\", Arrays.asList(\"test2.member\", \"test2.member2\"));\n\t\treturn new LoggerGroups(groups);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.Console;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link LoggingSystemProperties}.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass LoggingSystemPropertiesTests {\n\n\tprivate Set<Object> systemPropertyNames;\n\n\t@BeforeEach\n\tvoid captureSystemPropertyNames() {\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t\tSystem.getProperties().remove(\"LOGGED_APPLICATION_NAME\");\n\t\tthis.systemPropertyNames = new HashSet<>(System.getProperties().keySet());\n\t}\n\n\t@AfterEach\n\tvoid restoreSystemProperties() {\n\t\tSystem.getProperties().keySet().retainAll(this.systemPropertyNames);\n\t}\n\n\t@Test\n\tvoid pidIsSet() {\n\t\tnew LoggingSystemProperties(new MockEnvironment()).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.PID)).isNotNull();\n\t}\n\n\t@Test\n\tvoid consoleLogPatternIsSet() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.pattern.console\", \"console pattern\"))\n\t\t\t.apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)).isEqualTo(\"console pattern\");\n\t}\n\n\t@Test\n\tvoid consoleCharsetWhenNoPropertyUsesCharsetDefault() {\n\t\tLoggingSystemProperties loggingSystemProperties = spy(new LoggingSystemProperties(new MockEnvironment()));\n\t\tgiven(loggingSystemProperties.getConsole()).willReturn(null);\n\t\tloggingSystemProperties.apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET)).isEqualTo(Charset.defaultCharset().name());\n\t}\n\n\t@Test\n\tvoid consoleCharsetWhenNoPropertyUsesSystemConsoleCharsetWhenAvailable() {\n\t\tLoggingSystemProperties loggingSystemProperties = spy(new LoggingSystemProperties(new MockEnvironment()));\n\t\tConsole console = mock(Console.class);\n\t\tgiven(console.charset()).willReturn(StandardCharsets.UTF_16BE);\n\t\tgiven(loggingSystemProperties.getConsole()).willReturn(console);\n\t\tloggingSystemProperties.apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET))\n\t\t\t.isEqualTo(StandardCharsets.UTF_16BE.name());\n\t}\n\n\t@Test\n\tvoid consoleCharsetIsSet() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.charset.console\", \"UTF-16\"))\n\t\t\t.apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_CHARSET)).isEqualTo(\"UTF-16\");\n\t}\n\n\t@Test\n\tvoid fileLogPatternIsSet() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.pattern.file\", \"file pattern\"))\n\t\t\t.apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.FILE_PATTERN)).isEqualTo(\"file pattern\");\n\t}\n\n\t@Test\n\tvoid fileCharsetWhenNoPropertyUsesUtf8() {\n\t\tnew LoggingSystemProperties(new MockEnvironment()).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.FILE_CHARSET)).isEqualTo(\"UTF-8\");\n\t}\n\n\t@Test\n\tvoid fileCharsetIsSet() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.charset.file\", \"UTF-16\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.FILE_CHARSET)).isEqualTo(\"UTF-16\");\n\t}\n\n\t@Test\n\tvoid consoleLogPatternCanReferencePid() {\n\t\tnew LoggingSystemProperties(environment(\"logging.pattern.console\", \"${PID:unknown}\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.CONSOLE_PATTERN)).matches(\"[0-9]+\");\n\t}\n\n\t@Test\n\tvoid fileLogPatternCanReferencePid() {\n\t\tnew LoggingSystemProperties(environment(\"logging.pattern.file\", \"${PID:unknown}\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.FILE_PATTERN)).matches(\"[0-9]+\");\n\t}\n\n\tprivate String getSystemProperty(LoggingSystemProperty property) {\n\t\treturn System.getProperty(property.getEnvironmentVariableName());\n\t}\n\n\t@Test\n\tvoid correlationPatternIsSet() {\n\t\tnew LoggingSystemProperties(\n\t\t\t\tnew MockEnvironment().withProperty(\"logging.pattern.correlation\", \"correlation pattern\"))\n\t\t\t.apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CORRELATION_PATTERN.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"correlation pattern\");\n\t}\n\n\t@Test\n\tvoid defaultValueResolverIsUsed() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tMap<String, String> defaultValues = Map\n\t\t\t.of(LoggingSystemProperty.CORRELATION_PATTERN.getApplicationPropertyName(), \"default correlation pattern\");\n\t\tnew LoggingSystemProperties(environment, defaultValues::get, null).apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CORRELATION_PATTERN.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"default correlation pattern\");\n\t}\n\n\t@Test\n\tvoid loggedApplicationNameWhenHasApplicationName() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"spring.application.name\", \"test\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_NAME)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid loggedApplicationNameWhenHasNoApplicationName() {\n\t\tnew LoggingSystemProperties(new MockEnvironment()).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_NAME)).isNull();\n\t}\n\n\t@Test\n\tvoid loggedApplicationNameWhenApplicationNameLoggingDisabled() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"spring.application.name\", \"test\")\n\t\t\t.withProperty(\"logging.include-application-name\", \"false\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_NAME)).isNull();\n\t}\n\n\t@Test\n\tvoid legacyLoggedApplicationNameWhenHasApplicationName() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"spring.application.name\", \"test\")).apply(null);\n\t\tassertThat(System.getProperty(\"LOGGED_APPLICATION_NAME\")).isEqualTo(\"[test] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupWhenHasApplicationGroup() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"spring.application.group\", \"test\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_GROUP)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid applicationGroupWhenHasNoApplicationGroup() {\n\t\tnew LoggingSystemProperties(new MockEnvironment()).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_GROUP)).isNull();\n\t}\n\n\t@Test\n\tvoid applicationGroupWhenApplicationGroupLoggingDisabled() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"spring.application.group\", \"test\")\n\t\t\t.withProperty(\"logging.include-application-group\", \"false\")).apply(null);\n\t\tassertThat(getSystemProperty(LoggingSystemProperty.APPLICATION_GROUP)).isNull();\n\t}\n\n\t@Test\n\tvoid shouldSupportFalseConsoleThreshold() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.threshold.console\", \"false\"))\n\t\t\t.apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CONSOLE_THRESHOLD.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"OFF\");\n\t}\n\n\t@Test\n\tvoid shouldSupportFalseFileThreshold() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.threshold.file\", \"false\")).apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.FILE_THRESHOLD.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"OFF\");\n\t}\n\n\t@Test\n\tvoid shouldSetFileStructuredLogging() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.structured.format.file\", \"ecs\"))\n\t\t\t.apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.FILE_STRUCTURED_FORMAT.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"ecs\");\n\t}\n\n\t@Test\n\tvoid shouldSetConsoleStructuredLogging() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.structured.format.console\", \"ecs\"))\n\t\t\t.apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CONSOLE_STRUCTURED_FORMAT.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"ecs\");\n\t}\n\n\t@Test\n\tvoid shouldSetConsoleLevelThresholdToOffWhenConsoleLoggingDisabled() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.console.enabled\", \"false\")).apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CONSOLE_THRESHOLD.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"OFF\");\n\t}\n\n\t@Test\n\tvoid shouldNotChangeConsoleLevelThresholdWhenConsoleLoggingEnabled() {\n\t\tnew LoggingSystemProperties(new MockEnvironment().withProperty(\"logging.console.enabled\", \"true\")\n\t\t\t.withProperty(\"logging.threshold.console\", \"TRACE\")).apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CONSOLE_THRESHOLD.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(\"TRACE\");\n\t}\n\n\tprivate Environment environment(String key, Object value) {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources().addLast(new MapPropertySource(\"test\", Collections.singletonMap(key, value)));\n\t\treturn environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/LoggingSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.LoggingSystem.NoOpLoggingSystem;\nimport org.springframework.boot.logging.java.JavaLoggingSystem;\nimport org.springframework.boot.logging.log4j2.Log4J2LoggingSystem;\nimport org.springframework.boot.logging.logback.LogbackLoggingSystem;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link LoggingSystem}.\n *\n * @author Andy Wilkinson\n */\nclass LoggingSystemTests {\n\n\t@AfterEach\n\tvoid clearSystemProperty() {\n\t\tSystem.clearProperty(LoggingSystem.SYSTEM_PROPERTY);\n\t}\n\n\t@Test\n\tvoid logbackIsTheDefaultLoggingSystem() {\n\t\tassertThat(LoggingSystem.get(getClass().getClassLoader())).isInstanceOf(LogbackLoggingSystem.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"logback-*.jar\")\n\tvoid log4j2IsUsedInTheAbsenceOfLogback() {\n\t\tassertThat(LoggingSystem.get(getClass().getClassLoader())).isInstanceOf(Log4J2LoggingSystem.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"logback-*.jar\", \"log4j-*.jar\" })\n\tvoid julIsUsedInTheAbsenceOfLogbackAndLog4j2() {\n\t\tassertThat(LoggingSystem.get(getClass().getClassLoader())).isInstanceOf(JavaLoggingSystem.class);\n\t}\n\n\t@Test\n\tvoid loggingSystemCanBeDisabled() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, LoggingSystem.NONE);\n\t\tLoggingSystem loggingSystem = LoggingSystem.get(getClass().getClassLoader());\n\t\tassertThat(loggingSystem).isInstanceOf(NoOpLoggingSystem.class);\n\t}\n\n\t@Test\n\tvoid log4j2CanBeForcedUsingSystemProperty() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, Log4J2LoggingSystem.class.getName());\n\t\tassertThat(LoggingSystem.get(getClass().getClassLoader())).isInstanceOf(Log4J2LoggingSystem.class);\n\t}\n\n\t@Test\n\tvoid julCanBeForcedUsingSystemProperty() {\n\t\tSystem.setProperty(LoggingSystem.SYSTEM_PROPERTY, JavaLoggingSystem.class.getName());\n\t\tassertThat(LoggingSystem.get(getClass().getClassLoader())).isInstanceOf(JavaLoggingSystem.class);\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationIsUnsupported() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> new StubLoggingSystem().getLoggerConfiguration(\"test-logger-name\"));\n\t}\n\n\t@Test\n\tvoid listLoggerConfigurationsIsUnsupported() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> new StubLoggingSystem().getLoggerConfigurations());\n\t}\n\n\tprivate static final class StubLoggingSystem extends LoggingSystem {\n\n\t\t@Override\n\t\tpublic void beforeInitialize() {\n\t\t\t// Stub implementation\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogLevel(@Nullable String loggerName, @Nullable LogLevel level) {\n\t\t\t// Stub implementation\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/StandardStackTracePrinterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.util.Objects;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link StandardStackTracePrinter}.\n *\n * @author Phillip Webb\n */\nclass StandardStackTracePrinterTests {\n\n\t@Test\n\tvoid rootLastPrintsStackTrace() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast();\n\t\tassertThatCleanedStackTraceMatches(printer, exception, standardStackTrace());\n\t}\n\n\t@Test\n\tvoid rootLastPrintsStackTraceThatMatchesJvm() {\n\t\tThrowable exception = TestException.create();\n\t\tWriter printedJvmStackTrace = new StringWriter();\n\t\texception.printStackTrace(new PrintWriter(printedJvmStackTrace));\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast();\n\t\tassertThatCleanedStackTraceMatches(printer, exception,\n\t\t\t\tTestException.withoutLineNumbers(printedJvmStackTrace.toString()));\n\t}\n\n\t@Test\n\tvoid rootFirstPrintsStackTrace() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst();\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\tWrapped by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\tWrapped by: java.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\t... 1 more\n\t\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withCommonFramesWhenRootLastPrintsAllFrames() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast().withCommonFrames();\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tCaused by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tCaused by: java.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withCommonFramesWhenRootFirstPrintsAllFrames() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst().withCommonFrames();\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tWrapped by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tWrapped by: java.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withoutSuppressedHidesSuppressed() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast().withoutSuppressed();\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tCaused by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: java.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withMaximumLengthWhenNegativeThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> StandardStackTracePrinter.rootFirst().withMaximumLength(0))\n\t\t\t.withMessage(\"'maximumLength' must be positive\");\n\t}\n\n\t@Test\n\tvoid withMaximumLengthTruncatesOutput() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst().withMaximumLength(14);\n\t\tassertThat(printer.printStackTraceToString(exception)).isEqualTo(\"java.lang.R...\");\n\t}\n\n\t@Test\n\tvoid withMaximumThrowableDepthWhenNegativeThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> StandardStackTracePrinter.rootFirst().withMaximumThrowableDepth(0))\n\t\t\t.withMessage(\"'maximumThrowableDepth' must be positive\");\n\t}\n\n\t@Test\n\tvoid withMaximumThrowableDepthFiltersElements() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst().withMaximumThrowableDepth(1);\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\tWrapped by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\t... 1 filtered\n\t\t\t\t\t... 1 more\n\t\t\t\tWrapped by: java.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\t... 3 filtered\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\t... 1 more\n\t\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withMaximumThrowableDepthAndCommonFramesFiltersElements() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst()\n\t\t\t.withCommonFrames()\n\t\t\t.withMaximumThrowableDepth(2);\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tWrapped by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 filtered\n\t\t\t\tWrapped by: java.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\t... 2 filtered\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withFilterWhenPredicateIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> StandardStackTracePrinter.rootFirst().withFilter(null))\n\t\t\t.withMessage(\"'predicate' must not be null\");\n\t}\n\n\t@Test\n\tvoid withFilterWhenFilterMatches() {\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst()\n\t\t\t.withFilter(IllegalStateException.class::isInstance);\n\t\tassertThat(printer.printStackTraceToString(new IllegalStateException(\"test\"))).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid withFilterWhenFilterDoesNotMatch() {\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst()\n\t\t\t.withFilter(IllegalStateException.class::isInstance);\n\t\tassertThat(printer.printStackTraceToString(new RuntimeException(\"test\"))).isEmpty();\n\t}\n\n\t@Test\n\tvoid withMultipleFiltersMustAllMatch() {\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst()\n\t\t\t.withFilter(IllegalStateException.class::isInstance)\n\t\t\t.withFilter((ex) -> \"test\".equals(ex.getMessage()));\n\t\tassertThat(printer.printStackTraceToString(new IllegalStateException(\"test\"))).isNotEmpty();\n\t\tassertThat(printer.printStackTraceToString(new IllegalStateException(\"nope\"))).isEmpty();\n\t\tassertThat(printer.printStackTraceToString(new RuntimeException(\"test\"))).isEmpty();\n\t}\n\n\t@Test\n\tvoid withFrameFilter() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootFirst()\n\t\t\t.withCommonFrames()\n\t\t\t.withFrameFilter((index, element) -> element.getMethodName().startsWith(\"run\"));\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tjava.lang.RuntimeException: root\n\t\t\t\t\t... 1 filtered\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tWrapped by: java.lang.RuntimeException: cause\n\t\t\t\t\t... 2 filtered\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\tWrapped by: java.lang.RuntimeException: exception\n\t\t\t\t\t... 3 filtered\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\t... 1 filtered\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withLineSeparatorUsesLineSeparator() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast().withLineSeparator(\"!\");\n\t\tassertThatCleanedStackTraceMatches(printer, exception, standardStackTrace().replace(\"\\n\", \"!\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withFormatterWhenFormatterIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> StandardStackTracePrinter.rootLast().withFormatter(null))\n\t\t\t.withMessage(\"'formatter' must not be null\");\n\t}\n\n\t@Test\n\tvoid withFormatterFormatsThrowable() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast()\n\t\t\t.withFormatter((throwable) -> ClassUtils.getShortName(throwable.getClass()) + \": \"\n\t\t\t\t\t+ throwable.getLocalizedMessage());\n\t\tassertThatCleanedStackTraceMatches(printer, exception, \"\"\"\n\t\t\t\tRuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tSuppressed: RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withFrameFormatterWhenFormatterIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> StandardStackTracePrinter.rootLast().withFrameFormatter(null))\n\t\t\t.withMessage(\"'frameFormatter' must not be null\");\n\t}\n\n\t@Test\n\tvoid withFrameFormatterFormatsFrame() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast()\n\t\t\t.withFrameFormatter(\n\t\t\t\t\t(element) -> ClassUtils.getShortName(element.getClassName()) + \".\" + element.getMethodName());\n\t\tassertThat(printer.printStackTraceToString(exception)).isEqualToNormalizingNewlines(\"\"\"\n\t\t\t\tjava.lang.RuntimeException: exception\n\t\t\t\t\tat TestException.actualCreateException\n\t\t\t\t\tat TestException.createException\n\t\t\t\t\tat TestException.createTestException\n\t\t\t\t\tat TestException.CreatorThread.run\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat TestException.createTestException\n\t\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: java.lang.RuntimeException: cause\n\t\t\t\t\tat TestException.createCause\n\t\t\t\t\tat TestException.createTestException\n\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: java.lang.RuntimeException: root\n\t\t\t\t\tat TestException.createTestException\n\t\t\t\t\t... 1 more\n\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withHashesFunctionPrintsStackTraceWithHashes() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast()\n\t\t\t.withHashes((frame) -> Objects.hash(frame.getClassName(), frame.getMethodName()));\n\t\tassertThat(printer.printStackTraceToString(exception)).isEqualToNormalizingNewlines(\"\"\"\n\t\t\t\t<#cc3eebec> java.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:69)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:65)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:55)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:83)\n\t\t\t\t\tSuppressed: <#834defc3> java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:56)\n\t\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: <#611639c5> java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:61)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:54)\n\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: <#834defc3> java.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:53)\n\t\t\t\t\t... 1 more\n\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid withHashesPrintsStackTraceWithHashes() {\n\t\tThrowable exception = TestException.create();\n\t\tStandardStackTracePrinter printer = StandardStackTracePrinter.rootLast().withHashes();\n\t\tassertThat(printer.printStackTraceToString(exception)).containsPattern(\"<#[0-9a-f]{8}>\");\n\t}\n\n\tprivate String standardStackTrace() {\n\t\treturn \"\"\"\n\t\t\t\tjava.lang.RuntimeException: exception\n\t\t\t\t\tat org.springframework.boot.logging.TestException.actualCreateException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tSuppressed: java.lang.RuntimeException: suppressed\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: java.lang.RuntimeException: cause\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createCause(TestException.java:NN)\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\tCaused by: java.lang.RuntimeException: root\n\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t... 1 more\n\t\t\t\t\t\"\"\";\n\t}\n\n\tprivate void assertThatCleanedStackTraceMatches(StandardStackTracePrinter printer, Throwable throwable,\n\t\t\tString expected) {\n\t\tString actual = printer.printStackTraceToString(throwable);\n\t\tassertThat(TestException.withoutLineNumbers(actual)).isEqualToNormalizingNewlines(expected);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/TestException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Creates a test exception without too much stacktrace.\n *\n * @author Phillip Webb\n */\npublic final class TestException {\n\n\tprivate static final Pattern LINE_NUMBER_PATTERN = Pattern.compile(\"\\\\.java\\\\:\\\\d+\\\\)\");\n\n\tprivate TestException() {\n\t}\n\n\tpublic static Exception create() {\n\t\tCreatorThread creatorThread = new CreatorThread();\n\t\tcreatorThread.start();\n\t\ttry {\n\t\t\tcreatorThread.join();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t\tException exception = creatorThread.exception;\n\t\tassertThat(exception).isNotNull();\n\t\treturn exception;\n\t}\n\n\tprivate static Exception createTestException() {\n\t\tThrowable root = new RuntimeException(\"root\");\n\t\tThrowable cause = createCause(root);\n\t\tException exception = createException(cause);\n\t\texception.addSuppressed(new RuntimeException(\"suppressed\"));\n\t\treturn exception;\n\t}\n\n\tprivate static Throwable createCause(Throwable root) {\n\t\treturn new RuntimeException(\"cause\", root);\n\t}\n\n\tprivate static Exception createException(Throwable cause) {\n\t\treturn actualCreateException(cause);\n\t}\n\n\tprivate static Exception actualCreateException(Throwable cause) {\n\t\treturn new RuntimeException(\"exception\", cause);\n\t}\n\n\tpublic static String withoutLineNumbers(String stackTrace) {\n\t\tMatcher matcher = LINE_NUMBER_PATTERN.matcher(stackTrace);\n\t\treturn matcher.replaceAll(\".java:NN)\");\n\t}\n\n\tprivate static final class CreatorThread extends Thread {\n\n\t\t@Nullable Exception exception;\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tthis.exception = createTestException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/java/JavaLoggingSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.java;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.AbstractLoggingSystemTests;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link JavaLoggingSystem}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Ben Hale\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass JavaLoggingSystemTests extends AbstractLoggingSystemTests {\n\n\tprivate static final FileFilter SPRING_LOG_FILTER = (pathname) -> pathname.getName().startsWith(\"spring.log\");\n\n\tprivate final JavaLoggingSystem loggingSystem = new JavaLoggingSystem(getClass().getClassLoader());\n\n\tprivate Logger logger;\n\n\tprivate Locale defaultLocale;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.logger = Logger.getLogger(getClass().getName());\n\t\tthis.defaultLocale = Locale.getDefault();\n\t\tLocale.setDefault(Locale.ENGLISH);\n\t}\n\n\t@AfterEach\n\tvoid resetLogger() {\n\t\tthis.logger.setLevel(Level.OFF);\n\t\tthis.loggingSystem.getShutdownHandler().run();\n\t}\n\n\t@AfterEach\n\tvoid restoreLocale() {\n\t\tLocale.setDefault(this.defaultLocale);\n\t}\n\n\t@Test\n\tvoid noFile(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\").doesNotContain(\"Hidden\");\n\t\tassertThat(new File(tmpDir() + \"/spring.log\")).doesNotExist();\n\t}\n\n\t@Test\n\tvoid withFile(CapturedOutput output) {\n\t\tFile temp = new File(tmpDir());\n\t\tFile[] logFiles = temp.listFiles(SPRING_LOG_FILTER);\n\t\tfor (File file : logFiles) {\n\t\t\tfile.delete();\n\t\t}\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, getLogFile(null, tmpDir()));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\").doesNotContain(\"Hidden\");\n\t\tassertThat(temp.listFiles(SPRING_LOG_FILTER)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid testCustomFormatter(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\").contains(\"???? INFO [\");\n\t}\n\n\t@Test\n\tvoid testSystemPropertyInitializesFormat(CapturedOutput output) {\n\t\tSystem.setProperty(LoggingSystemProperty.PID.getEnvironmentVariableName(), \"1234\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(),\n\t\t\t\t\"classpath:\" + ClassUtils.addResourcePathToPackagePath(getClass(), \"logging.properties\"), null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\").contains(\"1234 INFO [\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"logging-nondefault.properties\", content = \"\"\"\n\t\t\thandlers = java.util.logging.ConsoleHandler\n\t\t\t.level = INFO\n\t\t\t\"\"\")\n\tvoid testNonDefaultConfigLocation(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), \"classpath:logging-nondefault.properties\", null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"INFO: Hello\");\n\t}\n\n\t@Test\n\tvoid testNonexistentConfigLocation() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.loggingSystem.initialize(getInitializationContext(),\n\t\t\t\t\"classpath:logging-nonexistent.properties\", null));\n\t}\n\n\t@Test\n\tvoid getSupportedLevels() {\n\t\tassertThat(this.loggingSystem.getSupportedLogLevels()).isEqualTo(\n\t\t\t\tEnumSet.of(LogLevel.TRACE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.OFF));\n\t}\n\n\t@Test\n\tvoid setLevel(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.logger.fine(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", LogLevel.DEBUG);\n\t\tthis.logger.fine(\"Hello\");\n\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Hello\")).isOne();\n\t}\n\n\t@Test\n\tvoid setLevelToNull(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.logger.fine(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", LogLevel.DEBUG);\n\t\tthis.logger.fine(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", null);\n\t\tthis.logger.fine(\"Hello\");\n\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Hello\")).isOne();\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurations() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tList<LoggerConfiguration> configurations = this.loggingSystem.getLoggerConfigurations();\n\t\tassertThat(configurations).isNotEmpty();\n\t\tassertThat(configurations.get(0).getName()).isEqualTo(LoggingSystem.ROOT_LOGGER_NAME);\n\t}\n\n\t@Test\n\tvoid getLoggerConfiguration() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName());\n\t\tassertThat(configuration)\n\t\t\t.isEqualTo(new LoggerConfiguration(getClass().getName(), LogLevel.DEBUG, LogLevel.DEBUG));\n\t}\n\n\t@Test\n\tvoid shouldNotContainAnsiEscapeCodes(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(getInitializationContext(), null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).doesNotContain(\"\\033[\");\n\t}\n\n\tprivate LoggingInitializationContext getInitializationContext() {\n\t\treturn new LoggingInitializationContext(null);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/java/TestFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.java;\n\nimport java.util.logging.Formatter;\nimport java.util.logging.LogRecord;\n\n/**\n * Simple test {@link Formatter}.\n *\n * @author Dave Syer\n */\npublic class TestFormatter extends Formatter {\n\n\t@Override\n\tpublic String format(LogRecord record) {\n\t\treturn String.format(\"foo: %s -- %s%n\", record.getLoggerName(), record.getMessage());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/AbstractStructuredLoggingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.time.Instant;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.impl.MutableLogEvent;\nimport org.apache.logging.log4j.message.SimpleMessage;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport tools.jackson.core.type.TypeReference;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.logging.structured.MockStructuredLoggingJsonMembersCustomizerBuilder;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for structured formatting tests.\n *\n * @author Moritz Halbritter\n */\n@ExtendWith(MockitoExtension.class)\nabstract class AbstractStructuredLoggingTests {\n\n\tstatic final Instant EVENT_TIME = Instant.ofEpochMilli(1719910193000L);\n\n\tprivate static final JsonMapper JSON_MAPPER = new JsonMapper();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tStructuredLoggingJsonMembersCustomizer<?> customizer;\n\n\tMockStructuredLoggingJsonMembersCustomizerBuilder<?> customizerBuilder = new MockStructuredLoggingJsonMembersCustomizerBuilder<>(\n\t\t\t() -> this.customizer);\n\n\tprotected Map<String, Object> map(Object... values) {\n\t\tassertThat(values.length).isEven();\n\t\tMap<String, Object> result = new HashMap<>();\n\t\tfor (int i = 0; i < values.length; i += 2) {\n\t\t\tresult.put(values[i].toString(), values[i + 1]);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected static MutableLogEvent createEvent() {\n\t\treturn createEvent(null);\n\t}\n\n\tprotected static MutableLogEvent createEvent(@Nullable Throwable thrown) {\n\t\tMutableLogEvent event = new MutableLogEvent();\n\t\tevent.setTimeMillis(EVENT_TIME.toEpochMilli());\n\t\tevent.setLevel(Level.INFO);\n\t\tevent.setThreadName(\"main\");\n\t\tevent.setLoggerName(\"org.example.Test\");\n\t\tevent.setMessage(new SimpleMessage(\"message\"));\n\t\tevent.setThrown(thrown);\n\t\treturn event;\n\t}\n\n\tprotected Map<String, Object> deserialize(String json) {\n\t\treturn JSON_MAPPER.readValue(json, new TypeReference<>() {\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ColorConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.Level;\nimport org.apache.logging.log4j.core.AbstractLogEvent;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ansi.AnsiOutput;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ColorConverter}.\n *\n * @author Vladimir Tsanev\n */\nclass ColorConverterTests {\n\n\tprivate final String in = \"in\";\n\n\tprivate TestLogEvent event;\n\n\t@BeforeAll\n\tstatic void setupAnsi() {\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);\n\t}\n\n\t@AfterAll\n\tstatic void resetAnsi() {\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.DETECT);\n\t}\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.event = new TestLogEvent();\n\t}\n\n\t@Test\n\tvoid black() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"black\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[30min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid white() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"white\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[37min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid faint() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"faint\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[2min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid red() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"red\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid green() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"green\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[32min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid yellow() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"yellow\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[33min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid blue() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"blue\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[34min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid magenta() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"magenta\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[35min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid cyan() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"cyan\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[36min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightBlack() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_black\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[90min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightWhite() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_white\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[97min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightRed() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_red\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[91min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightGreen() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_green\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[92min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightYellow() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_yellow\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[93min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightBlue() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_blue\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[94min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightMagenta() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_magenta\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[95min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightCyan() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bright_cyan\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[96min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bold() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bold\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[1min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid italic() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"italic\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[3min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid underline() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"underline\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[4min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid reverse() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"reverse\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[7min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgRed() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bg_red\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[41min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgGreen() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bg_green\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[42min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgYellow() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bg_yellow\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[43min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgBlue() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bg_blue\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[44min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgBrightRed() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bg_bright_red\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[101min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid multipleStyles() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"bold, red\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[1;31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightFatal() {\n\t\tthis.event.setLevel(Level.FATAL);\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(null).format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightError() {\n\t\tthis.event.setLevel(Level.ERROR);\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(null).format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightWarn() {\n\t\tthis.event.setLevel(Level.WARN);\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(null).format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[33min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightDebug() {\n\t\tthis.event.setLevel(Level.DEBUG);\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(null).format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[32min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightTrace() {\n\t\tthis.event.setLevel(Level.TRACE);\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(null).format(this.event, output);\n\t\tassertThat(output).hasToString(\"\\033[32min\\033[0;39m\");\n\t}\n\n\tprivate ColorConverter newConverter(@Nullable String additionalOptions) {\n\t\tString[] options = (additionalOptions != null) ? new String[] { this.in, additionalOptions }\n\t\t\t\t: new String[] { this.in };\n\t\tColorConverter converter = ColorConverter.newInstance(null, options);\n\t\tassertThat(converter).isNotNull();\n\t\treturn converter;\n\t}\n\n\tstatic class TestLogEvent extends AbstractLogEvent {\n\n\t\tprivate @Nullable Level level;\n\n\t\t@Override\n\t\tpublic @Nullable Level getLevel() {\n\t\t\treturn this.level;\n\t\t}\n\n\t\tvoid setLevel(@Nullable Level level) {\n\t\t\tthis.level = level;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/CorrelationIdConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Map;\n\nimport org.apache.logging.log4j.core.AbstractLogEvent;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.impl.JdkMapAdapterStringMap;\nimport org.apache.logging.log4j.util.ReadOnlyStringMap;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CorrelationIdConverter}.\n *\n * @author Phillip Webb\n */\nclass CorrelationIdConverterTests {\n\n\tprivate CorrelationIdConverter converter = CorrelationIdConverter.newInstance(null);\n\n\tprivate final LogEvent event = new TestLogEvent();\n\n\t@Test\n\tvoid defaultPattern() {\n\t\tStringBuilder result = new StringBuilder();\n\t\tthis.converter.format(this.event, result);\n\t\tassertThat(result).hasToString(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid customPattern() {\n\t\tthis.converter = CorrelationIdConverter.newInstance(new String[] { \"traceId(0),spanId(0)\" });\n\t\tStringBuilder result = new StringBuilder();\n\t\tthis.converter.format(this.event, result);\n\t\tassertThat(result).hasToString(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\tstatic class TestLogEvent extends AbstractLogEvent {\n\n\t\t@Override\n\t\tpublic ReadOnlyStringMap getContextData() {\n\t\t\treturn new JdkMapAdapterStringMap(\n\t\t\t\t\tMap.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"), true);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ElasticCommonSchemaStructuredLogFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.logging.log4j.Marker;\nimport org.apache.logging.log4j.MarkerManager;\nimport org.apache.logging.log4j.core.impl.JdkMapAdapterStringMap;\nimport org.apache.logging.log4j.core.impl.MutableLogEvent;\nimport org.apache.logging.log4j.message.MapMessage;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.structured.TestContextPairs;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link ElasticCommonSchemaStructuredLogFormatter}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredLoggingTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate ElasticCommonSchemaStructuredLogFormatter formatter;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.name\", \"name\");\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.version\", \"1.0.0\");\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.environment\", \"test\");\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.node-name\", \"node-1\");\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"1\");\n\t\tthis.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, null,\n\t\t\t\tTestContextPairs.include(), this.customizerBuilder);\n\t}\n\n\t@Test\n\tvoid callsNestedOnCustomizerBuilder() {\n\t\tassertThat(this.customizerBuilder.isNested()).isTrue();\n\t}\n\n\t@Test\n\tvoid callsCustomizer() {\n\t\tthen(this.customizer).should().customize(any());\n\t}\n\n\t@Test\n\tvoid shouldFormat() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setContextData(new JdkMapAdapterStringMap(Map.of(\"mdc-1\", \"mdc-v-1\"), true));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tMap<String, Object> expected = new HashMap<>();\n\t\texpected.put(\"@timestamp\", \"2024-07-02T08:49:53Z\");\n\t\texpected.put(\"message\", \"message\");\n\t\texpected.put(\"mdc-1\", \"mdc-v-1\");\n\t\texpected.put(\"ecs\", Map.of(\"version\", \"8.11\"));\n\t\texpected.put(\"process\", map(\"pid\", 1, \"thread\", map(\"name\", \"main\")));\n\t\texpected.put(\"log\", map(\"level\", \"INFO\", \"logger\", \"org.example.Test\"));\n\t\texpected.put(\"service\",\n\t\t\t\tmap(\"name\", \"name\", \"version\", \"1.0.0\", \"environment\", \"test\", \"node\", map(\"name\", \"node-1\")));\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(expected);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldFormatException() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setThrown(new RuntimeException(\"Boom\"));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tMap<String, Object> error = (Map<String, Object>) deserialized.get(\"error\");\n\t\tMap<String, Object> expectedError = new HashMap<>();\n\t\texpectedError.put(\"type\", \"java.lang.RuntimeException\");\n\t\texpectedError.put(\"message\", \"Boom\");\n\t\tassertThat(error).isNotNull();\n\t\tassertThat(error).containsAllEntriesOf(expectedError);\n\t\tString stackTrace = (String) error.get(\"stack_trace\");\n\t\tassertThat(stackTrace)\n\t\t\t.startsWith(String.format(\"java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.log4j2.\"\n\t\t\t\t\t+ \"ElasticCommonSchemaStructuredLogFormatterTests.shouldFormatException\"));\n\t\tassertThat(json).contains(String\n\t\t\t.format(\"java.lang.RuntimeException: Boom%n\\\\tat org.springframework.boot.logging.log4j2.\"\n\t\t\t\t\t+ \"ElasticCommonSchemaStructuredLogFormatterTests.shouldFormatException\")\n\t\t\t.replace(\"\\n\", \"\\\\n\")\n\t\t\t.replace(\"\\r\", \"\\\\r\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldFormatExceptionUsingStackTracePrinter() {\n\t\tthis.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, new SimpleStackTracePrinter(),\n\t\t\t\tTestContextPairs.include(), this.customizerBuilder);\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setThrown(new RuntimeException(\"Boom\"));\n\t\tMap<String, Object> deserialized = deserialize(this.formatter.format(event));\n\t\tMap<String, Object> error = (Map<String, Object>) deserialized.get(\"error\");\n\t\tassertThat(error).isNotNull();\n\t\tString stackTrace = (String) error.get(\"stack_trace\");\n\t\tassertThat(stackTrace).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldFormatStructuredMessage() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setMessage(new MapMessage<>().with(\"foo\", true).with(\"bar\", 1.0));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tMap<String, Object> expectedMessage = Map.of(\"foo\", true, \"bar\", 1.0);\n\t\tassertThat(deserialized.get(\"message\")).isEqualTo(expectedMessage);\n\t}\n\n\t@Test\n\tvoid shouldFormatMarkersAsTags() {\n\t\tMutableLogEvent event = createEvent();\n\t\tMarker parent = MarkerManager.getMarker(\"parent\");\n\t\tparent.addParents(MarkerManager.getMarker(\"grandparent\"));\n\t\tMarker parent1 = MarkerManager.getMarker(\"parent1\");\n\t\tparent1.addParents(MarkerManager.getMarker(\"grandparent1\"));\n\t\tMarker grandchild = MarkerManager.getMarker(\"grandchild\");\n\t\tgrandchild.addParents(parent);\n\t\tgrandchild.addParents(parent1);\n\t\tevent.setMarker(grandchild);\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized.get(\"tags\"))\n\t\t\t.isEqualTo(List.of(\"grandchild\", \"grandparent\", \"grandparent1\", \"parent\", \"parent1\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/EnclosedInSquareBracketsConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.log4j2.ColorConverterTests.TestLogEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EnclosedInSquareBracketsConverter}.\n *\n * @author Phillip Webb\n */\nclass EnclosedInSquareBracketsConverterTests {\n\n\tprivate final TestLogEvent event = new TestLogEvent();\n\n\t@Test\n\tvoid transformWhenEmpty() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"\");\n\t}\n\n\t@Test\n\tvoid transformWhenName() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tnewConverter(\"My Application\").format(this.event, output);\n\t\tassertThat(output).hasToString(\"[My Application] \");\n\t}\n\n\tprivate EnclosedInSquareBracketsConverter newConverter(String in) {\n\t\tEnclosedInSquareBracketsConverter converter = EnclosedInSquareBracketsConverter.newInstance(null,\n\t\t\t\tnew String[] { in });\n\t\tassertThat(converter).isNotNull();\n\t\treturn converter;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ExtendedWhitespaceThrowablePatternConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.config.DefaultConfiguration;\nimport org.apache.logging.log4j.core.impl.Log4jLogEvent;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ExtendedWhitespaceThrowablePatternConverter}.\n *\n * @author Vladimir Tsanev\n * @author Phillip Webb\n */\nclass ExtendedWhitespaceThrowablePatternConverterTests {\n\n\tprivate final LogEventPatternConverter converter = ExtendedWhitespaceThrowablePatternConverter\n\t\t.newInstance(new DefaultConfiguration(), new String[] {});\n\n\t@Test\n\tvoid noStackTrace() {\n\t\tLogEvent event = Log4jLogEvent.newBuilder().build();\n\t\tStringBuilder builder = new StringBuilder();\n\t\tthis.converter.format(event, builder);\n\t\tassertThat(builder).isEmpty();\n\t}\n\n\t@Test\n\tvoid withStackTrace() {\n\t\tLogEvent event = Log4jLogEvent.newBuilder().setThrown(new Exception()).build();\n\t\tStringBuilder builder = new StringBuilder();\n\t\tthis.converter.format(event, builder);\n\t\tassertThat(builder).startsWith(System.lineSeparator()).endsWith(System.lineSeparator());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/ExtractorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.impl.MutableLogEvent;\nimport org.apache.logging.log4j.message.SimpleMessage;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Extractor}.\n *\n * @author Phillip Webb\n */\nclass ExtractorTests {\n\n\t@Test\n\tvoid messageAndStackTraceWhenNoPrinterPrintsUsingLoggingSystem() {\n\t\tExtractor extractor = new Extractor(null);\n\t\tassertThat(extractor.messageAndStackTrace(createEvent())).startsWith(\"TestMessage\\n\\n\")\n\t\t\t.contains(\"java.lang.RuntimeException: Boom!\");\n\t}\n\n\t@Test\n\tvoid messageAndStackTraceWhenPrinterPrintsUsingPrinter() {\n\t\tExtractor extractor = new Extractor(new SimpleStackTracePrinter());\n\t\tassertThat(extractor.messageAndStackTrace(createEvent()))\n\t\t\t.isEqualTo(\"TestMessage\\n\\nstacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid stackTraceWhenNoPrinterPrintsUsingLoggingSystem() {\n\t\tExtractor extractor = new Extractor(null);\n\t\tassertThat(extractor.stackTrace(createEvent())).contains(\"java.lang.RuntimeException: Boom!\");\n\t}\n\n\t@Test\n\tvoid stackTraceWhenPrinterPrintsUsingPrinter() {\n\t\tExtractor extractor = new Extractor(new SimpleStackTracePrinter());\n\t\tassertThat(extractor.stackTrace(createEvent())).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\tprivate LogEvent createEvent() {\n\t\tMutableLogEvent event = new MutableLogEvent();\n\t\tevent.setMessage(new SimpleMessage(\"TestMessage\"));\n\t\tevent.setThrown(new RuntimeException(\"Boom!\"));\n\t\treturn event;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/GraylogExtendedLogFormatStructuredLogFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Map;\n\nimport org.apache.logging.log4j.core.impl.JdkMapAdapterStringMap;\nimport org.apache.logging.log4j.core.impl.MutableLogEvent;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.structured.TestContextPairs;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link GraylogExtendedLogFormatStructuredLogFormatter}.\n *\n * @author Samuel Lissner\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass GraylogExtendedLogFormatStructuredLogFormatterTests extends AbstractStructuredLoggingTests {\n\n\tprivate GraylogExtendedLogFormatStructuredLogFormatter formatter;\n\n\tprivate MockEnvironment environment;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"logging.structured.gelf.host\", \"name\");\n\t\tthis.environment.setProperty(\"logging.structured.gelf.service.version\", \"1.0.0\");\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"1\");\n\t\tthis.formatter = new GraylogExtendedLogFormatStructuredLogFormatter(this.environment, null,\n\t\t\t\tTestContextPairs.include(), this.customizer);\n\t}\n\n\t@Test\n\tvoid callsCustomizer() {\n\t\tthen(this.customizer).should().customize(any());\n\t}\n\n\t@Test\n\tvoid shouldFormat() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setContextData(new JdkMapAdapterStringMap(Map.of(\"mdc-1\", \"mdc-v-1\"), true));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(\n\t\t\t\tmap(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\", 1719910193.0, \"level\", 6, \"_level_name\", \"INFO\",\n\t\t\t\t\t\t\"_process_pid\", 1, \"_process_thread_name\", \"main\", \"_service_version\", \"1.0.0\", \"_log_logger\",\n\t\t\t\t\t\t\"org.example.Test\", \"short_message\", \"message\", \"_mdc-1\", \"mdc-v-1\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatMillisecondsInTimestamp() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setTimeMillis(1719910193123L);\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).contains(\"\\\"timestamp\\\":1719910193.123\");\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\",\n\t\t\t\t1719910193.123, \"level\", 6, \"_level_name\", \"INFO\", \"_process_pid\", 1, \"_process_thread_name\", \"main\",\n\t\t\t\t\"_service_version\", \"1.0.0\", \"_log_logger\", \"org.example.Test\", \"short_message\", \"message\"));\n\t}\n\n\t@Test\n\tvoid shouldNotAllowInvalidFieldNames(CapturedOutput output) {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setContextData(new JdkMapAdapterStringMap(Map.of(\"/\", \"value\"), true));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\",\n\t\t\t\t1719910193.0, \"level\", 6, \"_level_name\", \"INFO\", \"_process_pid\", 1, \"_process_thread_name\", \"main\",\n\t\t\t\t\"_service_version\", \"1.0.0\", \"_log_logger\", \"org.example.Test\", \"short_message\", \"message\"));\n\t\tassertThat(output).contains(\"'/' is not a valid field name according to GELF standard\");\n\t}\n\n\t@Test\n\tvoid shouldNotAllowIllegalFieldNames(CapturedOutput output) {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setContextData(new JdkMapAdapterStringMap(Map.of(\"id\", \"1\"), true));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\",\n\t\t\t\t1719910193.0, \"level\", 6, \"_level_name\", \"INFO\", \"_process_pid\", 1, \"_process_thread_name\", \"main\",\n\t\t\t\t\"_service_version\", \"1.0.0\", \"_log_logger\", \"org.example.Test\", \"short_message\", \"message\"));\n\t\tassertThat(output).contains(\"'id' is an illegal field name according to GELF standard\");\n\t}\n\n\t@Test\n\tvoid shouldNotAddDoubleUnderscoreToCustomFields() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setContextData(new JdkMapAdapterStringMap(Map.of(\"_custom\", \"value\"), true));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(\n\t\t\t\tmap(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\", 1719910193.0, \"level\", 6, \"_level_name\", \"INFO\",\n\t\t\t\t\t\t\"_process_pid\", 1, \"_process_thread_name\", \"main\", \"_service_version\", \"1.0.0\", \"_log_logger\",\n\t\t\t\t\t\t\"org.example.Test\", \"short_message\", \"message\", \"_custom\", \"value\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatException() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setThrown(new RuntimeException(\"Boom\"));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString fullMessage = (String) deserialized.get(\"full_message\");\n\t\tString stackTrace = (String) deserialized.get(\"_error_stack_trace\");\n\t\tassertThat(fullMessage).startsWith(\n\t\t\t\t\"message\\n\\njava.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.log4j2.GraylogExtendedLogFormatStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted());\n\t\tassertThat(deserialized)\n\t\t\t.containsAllEntriesOf(map(\"_error_type\", \"java.lang.RuntimeException\", \"_error_message\", \"Boom\"));\n\t\tassertThat(stackTrace).startsWith(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.log4j2.GraylogExtendedLogFormatStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted());\n\t\tassertThat(json).contains(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\\\tat org.springframework.boot.logging.log4j2.GraylogExtendedLogFormatStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted()\n\t\t\t\t\t.replace(\"\\n\", \"\\\\n\")\n\t\t\t\t\t.replace(\"\\r\", \"\\\\r\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatExceptionUsingStackTracePrinter() {\n\t\tthis.formatter = new GraylogExtendedLogFormatStructuredLogFormatter(this.environment,\n\t\t\t\tnew SimpleStackTracePrinter(), TestContextPairs.include(), this.customizer);\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setThrown(new RuntimeException(\"Boom\"));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString fullMessage = (String) deserialized.get(\"full_message\");\n\t\tString stackTrace = (String) deserialized.get(\"_error_stack_trace\");\n\t\tassertThat(fullMessage).isEqualTo(\"message\\n\\nstacktrace:RuntimeException\");\n\t\tassertThat(deserialized)\n\t\t\t.containsAllEntriesOf(map(\"_error_type\", \"java.lang.RuntimeException\", \"_error_message\", \"Boom\"));\n\t\tassertThat(stackTrace).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.beans.PropertyChangeEvent;\nimport java.beans.PropertyChangeListener;\nimport java.io.File;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.EnumSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.logging.Handler;\nimport java.util.logging.Level;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.appender.RollingFileAppender;\nimport org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.CronTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;\nimport org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.LoggerConfig;\nimport org.apache.logging.log4j.core.config.composite.CompositeConfiguration;\nimport org.apache.logging.log4j.core.config.plugins.util.PluginRegistry;\nimport org.apache.logging.log4j.core.config.xml.XmlConfiguration;\nimport org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;\nimport org.apache.logging.log4j.jul.Log4jBridgeHandler;\nimport org.apache.logging.log4j.status.StatusListener;\nimport org.apache.logging.log4j.status.StatusLogger;\nimport org.apache.logging.log4j.util.PropertiesUtil;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestInfo;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.slf4j.MDC;\n\nimport org.springframework.boot.logging.AbstractLoggingSystemTests;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.logging.ConfigureClasspathToPreferLog4j2;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.core.env.Environment;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link Log4J2LoggingSystem}.\n *\n * @author Daniel Fullarton\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Ben Hale\n * @author Madhura Bhave\n * @author Piotr P. Karwasz\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathExclusions(\"logback-*.jar\")\n@ConfigureClasspathToPreferLog4j2\nclass Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {\n\n\tprivate TestLog4J2LoggingSystem loggingSystem;\n\n\tprivate MockEnvironment environment;\n\n\tprivate LoggingInitializationContext initializationContext;\n\n\tprivate Logger logger;\n\n\t@BeforeEach\n\tvoid setup(TestInfo testInfo) {\n\t\tclearRollingPolicySystemProperties();\n\t\tPluginRegistry.getInstance().clear();\n\t\tthis.loggingSystem = new TestLog4J2LoggingSystem(testInfo.getDisplayName());\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.initializationContext = new LoggingInitializationContext(this.environment);\n\t\tthis.logger = this.loggingSystem.getLoggerContext().getLogger(getClass().getName());\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tthis.loggingSystem.getConfiguration().stop();\n\t\tthis.loggingSystem.cleanUp();\n\t\tPluginRegistry.getInstance().clear();\n\t\tLogManager.getFactory().removeContext(this.loggingSystem.getLoggerContext());\n\t\tclearRollingPolicySystemProperties();\n\t}\n\n\tprivate void clearRollingPolicySystemProperties() {\n\t\tfor (RollingPolicySystemProperty property : RollingPolicySystemProperty.values()) {\n\t\t\tSystem.clearProperty(property.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid noFile(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tConfiguration configuration = this.loggingSystem.getConfiguration();\n\t\tassertThat(output).contains(\"Hello world\").doesNotContain(\"Hidden\");\n\t\tassertThat(new File(tmpDir() + \"/spring.log\")).doesNotExist();\n\t\tassertThat(configuration.getConfigurationSource().getFile()).isNotNull();\n\t}\n\n\t@Test\n\tvoid withFile(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tthis.loggingSystem.initialize(this.initializationContext, getRelativeClasspathLocation(\"log4j2-file.xml\"),\n\t\t\t\tgetLogFile(null, tmpDir()));\n\t\tthis.logger.info(\"Hello world\");\n\t\tConfiguration configuration = this.loggingSystem.getConfiguration();\n\t\tassertThat(output).contains(\"Hello world\").doesNotContain(\"Hidden\");\n\t\tassertThat(new File(tmpDir() + \"/spring.log\")).exists();\n\t\tassertThat(configuration.getConfigurationSource().getLocation()).contains(\"log4j2-file.xml\");\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid testNonDefaultConfigLocation(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, \"classpath:nondefault.xml\",\n\t\t\t\tgetLogFile(tmpDir() + \"/tmp.log\", null));\n\t\tthis.logger.info(\"Hello world\");\n\t\tConfiguration configuration = this.loggingSystem.getConfiguration();\n\t\tassertThat(output).contains(\"Hello world\").contains(tmpDir() + \"/tmp.log\");\n\t\tassertThat(new File(tmpDir() + \"/tmp.log\")).doesNotExist();\n\t\tassertThat(configuration.getConfigurationSource().getFile().getAbsolutePath()).contains(\"nondefault.xml\");\n\t\tassertThat(configuration.getWatchManager().getIntervalSeconds()).isEqualTo(30);\n\t}\n\n\t@Test\n\tvoid testNonexistentConfigLocation() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.loggingSystem.initialize(this.initializationContext,\n\t\t\t\t\"classpath:log4j2-nonexistent.xml\", null));\n\t}\n\n\t@Test\n\t@WithSpringXmlResource\n\tvoid testSpringBootConfigLocation() {\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tConfiguration configuration = this.loggingSystem.getConfiguration();\n\t\tassertThat(configuration.getName()).isEqualTo(\"SpringBoot\");\n\t\tassertThat(configuration.getConfigurationSource().getLocation()).endsWith(\"log4j2-test-spring.xml\");\n\t}\n\n\t@Test\n\tvoid getSupportedLevels() {\n\t\tassertThat(this.loggingSystem.getSupportedLogLevels()).isEqualTo(EnumSet.allOf(LogLevel.class));\n\t}\n\n\t@Test\n\tvoid setLevel(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", LogLevel.DEBUG);\n\t\tthis.logger.debug(\"Hello\");\n\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Hello\")).isOne();\n\t}\n\n\t@Test\n\tvoid setLevelToNull(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", LogLevel.DEBUG);\n\t\tthis.logger.debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", null);\n\t\tthis.logger.debug(\"Hello\");\n\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Hello\")).isOne();\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurations() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tList<LoggerConfiguration> configurations = this.loggingSystem.getLoggerConfigurations();\n\t\tassertThat(configurations).isNotEmpty();\n\t\tassertThat(configurations.get(0).getName()).isEqualTo(LoggingSystem.ROOT_LOGGER_NAME);\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationsShouldReturnAllLoggers() {\n\t\tthis.loggingSystem.getLoggerContext()\n\t\t\t.getLogger(\"org.springframework.boot.logging.log4j2.Log4J2LoggingSystemTests$Nested\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tList<LoggerConfiguration> configurations = this.loggingSystem.getLoggerConfigurations();\n\t\tassertThat(configurations).isNotEmpty();\n\t\tassertThat(configurations.get(0).getName()).isEqualTo(LoggingSystem.ROOT_LOGGER_NAME);\n\t\tMap<String, LogLevel> loggers = new LinkedHashMap<>();\n\t\tconfigurations.forEach((logger) -> loggers.put(logger.getName(), logger.getConfiguredLevel()));\n\t\tassertIsPresent(\"org\", loggers, null);\n\t\tassertIsPresent(\"org.springframework.boot.logging.log4j2\", loggers, null);\n\t\tassertIsPresent(\"org.springframework.boot.logging.log4j2.Log4J2LoggingSystemTests\", loggers, LogLevel.DEBUG);\n\t\tassertIsPresent(\"org.springframework.boot.logging.log4j2.Log4J2LoggingSystemTests$Nested\", loggers, null);\n\t}\n\n\t@Test // gh-35227\n\tvoid getLoggerConfigurationWhenHasCustomLevel() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tString loggerName = getClass().getName();\n\t\torg.apache.logging.log4j.Level level = org.apache.logging.log4j.Level.forName(\"CUSTOM_LEVEL\", 1000);\n\t\tloggerContext.getConfiguration().addLogger(loggerName, new LoggerConfig(loggerName, level, true));\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(loggerName);\n\t\tassertThat(configuration).isNotNull();\n\t\tassertThat(configuration.getLevelConfiguration().getName()).isEqualTo(\"CUSTOM_LEVEL\");\n\t}\n\n\tprivate void assertIsPresent(String loggerName, Map<String, LogLevel> loggers, @Nullable LogLevel logLevel) {\n\t\tassertThat(loggers).containsKey(loggerName);\n\t\tassertThat(loggers).containsEntry(loggerName, logLevel);\n\t}\n\n\t@Test\n\tvoid getLoggerConfiguration() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName());\n\t\tassertThat(configuration)\n\t\t\t.isEqualTo(new LoggerConfiguration(getClass().getName(), LogLevel.DEBUG, LogLevel.DEBUG));\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationShouldReturnLoggerWithNullConfiguredLevel() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(\"org\");\n\t\tassertThat(configuration).isEqualTo(new LoggerConfiguration(\"org\", null, LogLevel.INFO));\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationForNonExistentLoggerShouldReturnNull() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(\"doesnotexist\");\n\t\tassertThat(configuration).isNull();\n\t}\n\n\t@Test\n\tvoid setLevelOfUnconfiguredLoggerDoesNotAffectRootConfiguration(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tLogManager.getRootLogger().debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"foo.bar.baz\", LogLevel.DEBUG);\n\t\tLogManager.getRootLogger().debug(\"Hello\");\n\t\tassertThat(output.toString()).doesNotContain(\"Hello\");\n\t}\n\n\t@Test\n\tvoid loggingThatUsesJulIsCaptured(CapturedOutput output) {\n\t\tString name = getClass().getName();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(name, LogLevel.TRACE);\n\t\tjava.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(name);\n\t\tjulLogger.setLevel(java.util.logging.Level.INFO);\n\t\tjulLogger.severe(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\");\n\t}\n\n\t@Test\n\tvoid exceptionsIncludeClassPackaging(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, getRelativeClasspathLocation(\"log4j2-file.xml\"),\n\t\t\t\tgetLogFile(null, tmpDir()));\n\t\tthis.logger.warn(\"Expected exception\", new RuntimeException(\"Expected\"));\n\t\tString fileContents = contentOf(new File(tmpDir() + \"/spring.log\"));\n\t\tassertThat(fileContents).contains(\"[junit-\");\n\t\tassertThat(output).contains(\"[junit-\");\n\t}\n\n\t@Test\n\tvoid beforeInitializeFilterDisablesErrorLogging() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThat(this.logger.isErrorEnabled()).isFalse();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, getLogFile(null, tmpDir()));\n\t}\n\n\t@Test\n\tvoid customExceptionConversionWord(CapturedOutput output) {\n\t\tSystem.setProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD.getEnvironmentVariableName(), \"%ex\");\n\t\ttry {\n\t\t\tthis.loggingSystem.beforeInitialize();\n\t\t\tthis.logger.info(\"Hidden\");\n\t\t\tthis.loggingSystem.initialize(this.initializationContext, getRelativeClasspathLocation(\"log4j2-file.xml\"),\n\t\t\t\t\tgetLogFile(null, tmpDir()));\n\t\t\tthis.logger.warn(\"Expected exception\", new RuntimeException(\"Expected\", new RuntimeException(\"Cause\")));\n\t\t\tString fileContents = contentOf(new File(tmpDir() + \"/spring.log\"));\n\t\t\tassertThat(fileContents).contains(\"java.lang.RuntimeException: Expected\").doesNotContain(\"Wrapped by:\");\n\t\t\tassertThat(output).contains(\"java.lang.RuntimeException: Expected\").doesNotContain(\"Wrapped by:\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid initializationIsOnlyPerformedOnceUntilCleanedUp() {\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tPropertyChangeListener listener = mock(PropertyChangeListener.class);\n\t\tloggerContext.addPropertyChangeListener(listener);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthen(listener).should(times(2)).propertyChange(any(PropertyChangeEvent.class));\n\t\tthis.loggingSystem.cleanUp();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthen(listener).should(times(4)).propertyChange(any(PropertyChangeEvent.class));\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationWithResetLevelReturnsNull() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(\"com.example\", LogLevel.WARN);\n\t\tthis.loggingSystem.setLogLevel(\"com.example.test\", LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(\"com.example.test\");\n\t\tassertThat(configuration)\n\t\t\t.isEqualTo(new LoggerConfiguration(\"com.example.test\", LogLevel.DEBUG, LogLevel.DEBUG));\n\t\tthis.loggingSystem.setLogLevel(\"com.example.test\", null);\n\t\tLoggerConfiguration updatedConfiguration = this.loggingSystem.getLoggerConfiguration(\"com.example.test\");\n\t\tassertThat(updatedConfiguration).isNull();\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationWithResetLevelWhenAlreadyConfiguredReturnsParentConfiguredLevel() {\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tloggerContext.getConfiguration()\n\t\t\t.addLogger(\"com.example.test\",\n\t\t\t\t\tnew LoggerConfig(\"com.example.test\", org.apache.logging.log4j.Level.INFO, false));\n\t\tthis.loggingSystem.setLogLevel(\"com.example\", LogLevel.WARN);\n\t\tthis.loggingSystem.setLogLevel(\"com.example.test\", LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(\"com.example.test\");\n\t\tassertThat(configuration)\n\t\t\t.isEqualTo(new LoggerConfiguration(\"com.example.test\", LogLevel.DEBUG, LogLevel.DEBUG));\n\t\tthis.loggingSystem.setLogLevel(\"com.example.test\", null);\n\t\tLoggerConfiguration updatedConfiguration = this.loggingSystem.getLoggerConfiguration(\"com.example.test\");\n\t\tassertThat(updatedConfiguration)\n\t\t\t.isEqualTo(new LoggerConfiguration(\"com.example.test\", LogLevel.WARN, LogLevel.WARN));\n\t}\n\n\t@Test\n\tvoid log4jLevelsArePropagatedToJul() {\n\t\t// In this test we need to use the global logging system, since JUL is a global\n\t\t// singleton.\n\t\tLoggingSystem loggingSystem = LoggingSystem.get(getClass().getClassLoader());\n\t\tloggingSystem.beforeInitialize();\n\t\tjava.util.logging.Logger rootLogger = java.util.logging.Logger.getLogger(\"\");\n\t\t// check if Log4jBridgeHandler is used\n\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\tassertThat(handlers).hasSize(1);\n\t\tassertThat(handlers[0]).isInstanceOf(Log4jBridgeHandler.class);\n\n\t\tloggingSystem.initialize(this.initializationContext, null, null);\n\t\tjava.util.logging.Logger logger = java.util.logging.Logger.getLogger(Log4J2LoggingSystemTests.class.getName());\n\t\tlogger.info(\"Log to trigger level propagation\");\n\t\tassertThat(logger.getLevel()).isNull();\n\t\tloggingSystem.setLogLevel(Log4J2LoggingSystemTests.class.getName(), LogLevel.DEBUG);\n\t\tassertThat(logger.getLevel()).isEqualTo(Level.FINE);\n\t}\n\n\t@Test\n\tvoid shutdownHookIsDisabled() {\n\t\tassertThat(\n\t\t\t\tPropertiesUtil.getProperties().getBooleanProperty(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, true))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid loadOptionalOverrideConfigurationWhenDoesNotExist() {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"optional:classpath:override.xml\");\n\t\tthis.loggingSystem.initialize(this.initializationContext, \"classpath:nondefault.xml\", null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(XmlConfiguration.class);\n\t}\n\n\t@Test\n\tvoid loadOptionalOverrideConfigurationWhenDoesNotExistUponReinitialization() {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"optional:classpath:override.xml\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(XmlConfiguration.class);\n\t\tthis.loggingSystem.cleanUp();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(XmlConfiguration.class);\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\t@WithOverrideXmlResource\n\tvoid loadOptionalOverrideConfiguration() {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"optional:classpath:override.xml\");\n\t\tthis.loggingSystem.initialize(this.initializationContext, \"classpath:nondefault.xml\", null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);\n\t}\n\n\t@Test\n\t@WithOverrideXmlResource\n\tvoid loadOptionalOverrideConfigurationUponReinitialization() {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"optional:classpath:override.xml\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);\n\t\tthis.loggingSystem.cleanUp();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\t@WithOverrideXmlResource\n\tvoid compositeConfigurationWithCustomBaseConfiguration() {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"classpath:override.xml\");\n\t\tthis.loggingSystem.initialize(this.initializationContext, \"classpath:nondefault.xml\", null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);\n\t}\n\n\t@Test\n\t@WithOverrideXmlResource\n\tvoid compositeConfigurationWithStandardConfigLocationConfiguration() {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"classpath:override.xml\");\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tassertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);\n\t}\n\n\t@Test\n\tvoid initializeAttachesEnvironmentToLoggerContext() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tEnvironment environment = Log4J2LoggingSystem.getEnvironment(loggerContext);\n\t\tassertThat(environment).isSameAs(this.environment);\n\t}\n\n\t@Test\n\tvoid initializeRegisterStatusListenerAndAttachToLoggerContext() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tStatusListener statusListener = (StatusListener) loggerContext\n\t\t\t.getObject(Log4J2LoggingSystem.STATUS_LISTENER_KEY);\n\t\tassertThat(statusListener).isNotNull();\n\t\tassertThat(StatusLogger.getLogger().getListeners()).contains(statusListener);\n\t}\n\n\t@Test\n\tvoid statusListenerIsUpdatedUponReinitialization() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\t// listener should be registered\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tStatusListener statusListener = (StatusListener) loggerContext\n\t\t\t.getObject(Log4J2LoggingSystem.STATUS_LISTENER_KEY);\n\t\tassertThat(statusListener).isNotNull();\n\t\tassertThat(StatusLogger.getLogger().getListeners()).contains(statusListener);\n\n\t\tthis.loggingSystem.cleanUp();\n\t\t// listener should be removed from context and StatusLogger\n\t\tassertThat(StatusLogger.getLogger().getListeners()).doesNotContain(statusListener);\n\t\tassertThat(loggerContext.getObject(Log4J2LoggingSystem.STATUS_LISTENER_KEY)).isNull();\n\n\t\t// a new listener should be registered\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tStatusListener statusListener1 = (StatusListener) loggerContext\n\t\t\t.getObject(Log4J2LoggingSystem.STATUS_LISTENER_KEY);\n\t\tassertThat(statusListener1).isNotNull();\n\t\tassertThat(StatusLogger.getLogger().getListeners()).contains(statusListener1);\n\t}\n\n\t@Test\n\tvoid initializeAddsSpringEnvironmentPropertySource() {\n\t\tthis.environment.setProperty(\"spring\", \"boot\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tPropertiesUtil properties = PropertiesUtil.getProperties();\n\t\tassertThat(properties.getStringProperty(\"spring\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid environmentIsUpdatedUponReinitialization() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring\", \"boot: one\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(new LoggingInitializationContext(environment), null, null);\n\t\tassertThat(PropertiesUtil.getProperties().getStringProperty(\"spring\")).isEqualTo(\"boot: one\");\n\t\tthis.loggingSystem.cleanUp();\n\t\tthis.environment.setProperty(\"spring\", \"boot: two\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tassertThat(PropertiesUtil.getProperties().getStringProperty(\"spring\")).isEqualTo(\"boot: two\");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToFileWhenExpectCorrelationIdTrueAndMdcContent() {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\"))\n\t\t\t.contains(\" [01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndMdcContent(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenExpectCorrelationIdFalseAndMdcContent(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"false\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"0123456789012345\");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndNoMdcContent(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [                                                 ] \");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenHasCorrelationPattern(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.correlation\", \"%correlationId{spanId(0),traceId(0)}\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [0123456789012345-01234567890123456789012345678901] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToConsoleWhenHasApplicationName(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[myapp] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToConsoleWhenHasApplicationNameWithParenthesis(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp (dev)\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[myapp (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToConsoleWhenDisabled(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tthis.environment.setProperty(\"logging.include-application-name\", \"false\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"${sys:LOGGED_APPLICATION_NAME}\")\n\t\t\t.doesNotContain(\"${sys:APPLICATION_NAME}\")\n\t\t\t.doesNotContain(\"myapp\");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToFileWhenHasApplicationName() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[myapp] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToFileWhenHasApplicationNameWithParenthesis() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp (dev)\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[myapp (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToFileWhenDisabled() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tthis.environment.setProperty(\"logging.include-application-name\", \"false\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).doesNotContain(\"${sys:LOGGED_APPLICATION_NAME}\")\n\t\t\t.doesNotContain(\"${sys:APPLICATION_NAME}\")\n\t\t\t.doesNotContain(\"myapp\");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToConsoleWhenHasApplicationGroup(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[mygroup] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToConsoleWhenHasApplicationGroupWithParenthesis(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup (dev)\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[mygroup (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToConsoleWhenDisabled(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tthis.environment.setProperty(\"logging.include-application-group\", \"false\");\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"${sys:APPLICATION_GROUP}\")\n\t\t\t.doesNotContain(\"mygroup\");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToFileWhenHasApplicationGroup() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[mygroup] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToFileWhenHasApplicationGroupWithParenthesis() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup (dev)\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[mygroup (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToFileWhenDisabled() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tthis.environment.setProperty(\"logging.include-application-group\", \"false\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.disableSelfInitialization();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).doesNotContain(\"${sys:APPLICATION_GROUP}\")\n\t\t\t.doesNotContain(\"mygroup\");\n\t}\n\n\t@Test\n\tvoid shouldNotContainAnsiEscapeCodes(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).doesNotContain(\"\\033[\");\n\t}\n\n\tprivate String getRelativeClasspathLocation(String fileName) {\n\t\tString defaultPath = ClassUtils.getPackageName(getClass());\n\t\tdefaultPath = defaultPath.replace('.', '/');\n\t\tdefaultPath = defaultPath + \"/\" + fileName;\n\t\tdefaultPath = \"classpath:\" + defaultPath;\n\t\treturn defaultPath;\n\t}\n\n\t@Test\n\tvoid rollingPolicySystemPropertiesAreApplied() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-file-size\", \"50MB\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-history\", \"30\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.file-name-pattern\",\n\t\t\t\t\"${LOG_FILE}.%d{yyyy-MM-dd}.%i.log\");\n\t\tFile file = new File(tmpDir(), \"log4j2-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.getSystemProperties(this.environment).apply(logFile);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, logFile);\n\t\tString maxFileSize = System.getProperty(\"LOG4J2_ROLLINGPOLICY_MAX_FILE_SIZE\");\n\t\tString maxHistory = System.getProperty(\"LOG4J2_ROLLINGPOLICY_MAX_HISTORY\");\n\t\tString fileNamePattern = System.getProperty(\"LOG4J2_ROLLINGPOLICY_FILE_NAME_PATTERN\");\n\t\tassertThat(maxFileSize).isEqualTo(String.valueOf(50 * 1024 * 1024));\n\t\tassertThat(maxHistory).isEqualTo(\"30\");\n\t\tassertThat(fileNamePattern).isEqualTo(\"${LOG_FILE}.%d{yyyy-MM-dd}.%i.log\");\n\t}\n\n\t@Test\n\tvoid rollingPolicyAppliesDefaults() {\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tSizeBasedTriggeringPolicy sizePolicy = findPolicy(policy, SizeBasedTriggeringPolicy.class);\n\t\tassertThat(sizePolicy).isNotNull();\n\t\tassertThat(sizePolicy.getMaxFileSize()).isEqualTo(DataSize.ofMegabytes(10).toBytes());\n\t}\n\n\t@Test\n\tvoid rollingPolicySizeStrategyIsApplied() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"size\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-file-size\", \"50MB\");\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tSizeBasedTriggeringPolicy sizePolicy = findPolicy(policy, SizeBasedTriggeringPolicy.class);\n\t\tassertThat(sizePolicy).isNotNull();\n\t\tassertThat(sizePolicy.getMaxFileSize()).isEqualTo(DataSize.ofMegabytes(50).toBytes());\n\t}\n\n\t@Test\n\tvoid rollingPolicyTimeStrategyAppliesDefaults() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"time\");\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tTimeBasedTriggeringPolicy timePolicy = findPolicy(policy, TimeBasedTriggeringPolicy.class);\n\t\tassertThat(timePolicy).isNotNull();\n\t\tassertThat(timePolicy.getInterval()).isEqualTo(1);\n\t\tassertThat(timePolicy).hasFieldOrPropertyWithValue(\"modulate\", false);\n\t}\n\n\t@Test\n\tvoid rollingPolicyTimeStrategyIsApplied() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"time\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.time-interval\", \"2\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.time-modulate\", \"true\");\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tTimeBasedTriggeringPolicy timePolicy = findPolicy(policy, TimeBasedTriggeringPolicy.class);\n\t\tassertThat(timePolicy).isNotNull();\n\t\tassertThat(timePolicy.getInterval()).isEqualTo(2);\n\t\tassertThat(timePolicy).hasFieldOrPropertyWithValue(\"modulate\", true);\n\t}\n\n\t@Test\n\tvoid rollingPolicySizeAndTimeStrategyIsApplied() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"size-and-time\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-file-size\", \"5MB\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.time-interval\", \"3\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.time-modulate\", \"true\");\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tassertThat(findPolicy(policy, TimeBasedTriggeringPolicy.class)).satisfies((timePolicy) -> {\n\t\t\tassertThat(timePolicy.getInterval()).isEqualTo(3);\n\t\t\tassertThat(timePolicy).hasFieldOrPropertyWithValue(\"modulate\", true);\n\t\t});\n\t\tassertThat(findPolicy(policy, SizeBasedTriggeringPolicy.class)).satisfies(\n\t\t\t\t(sizePolicy) -> assertThat(sizePolicy.getMaxFileSize()).isEqualTo(DataSize.ofMegabytes(5).toBytes()));\n\t}\n\n\t@Test\n\tvoid rollingPolicyCronStrategyAppliesDefault() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"cron\");\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tCronTriggeringPolicy cronPolicy = findPolicy(policy, CronTriggeringPolicy.class);\n\t\tassertThat(cronPolicy).isNotNull();\n\t\tassertThat(cronPolicy.getCronExpression().getCronExpression()).isEqualTo(\"0 0 0 * * ?\");\n\t}\n\n\t@Test\n\tvoid rollingPolicyCronStrategyIsApplied() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"cron\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.cron\", \"0 0 1 * * ?\");\n\t\tTriggeringPolicy policy = getTriggeringPolicy();\n\t\tCronTriggeringPolicy cronPolicy = findPolicy(policy, CronTriggeringPolicy.class);\n\t\tassertThat(cronPolicy).isNotNull();\n\t\tassertThat(cronPolicy.getCronExpression().getCronExpression()).isEqualTo(\"0 0 1 * * ?\");\n\t}\n\n\tprivate TriggeringPolicy getTriggeringPolicy() {\n\t\tFile file = new File(tmpDir(), \"target-file.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tthis.loggingSystem.getSystemProperties(this.environment).apply(logFile);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(this.initializationContext,\n\t\t\t\t\"classpath:org/springframework/boot/logging/log4j2/log4j2-file.xml\", logFile);\n\t\tLoggerContext loggerContext = this.loggingSystem.getLoggerContext();\n\t\tConfiguration configuration = loggerContext.getConfiguration();\n\t\tRollingFileAppender appender = (RollingFileAppender) configuration.getAppenders().get(\"File\");\n\t\tassertThat(appender).isNotNull();\n\t\treturn appender.getManager().getTriggeringPolicy();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T extends TriggeringPolicy> @Nullable T findPolicy(TriggeringPolicy policy, Class<T> type) {\n\t\tif (type.isInstance(policy)) {\n\t\t\treturn (T) policy;\n\t\t}\n\t\tif (policy instanceof CompositeTriggeringPolicy composite) {\n\t\t\tfor (TriggeringPolicy child : composite.getTriggeringPolicies()) {\n\t\t\t\tT found = findPolicy(child, type);\n\t\t\t\tif (found != null) {\n\t\t\t\t\treturn found;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"override.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<Configuration status=\"WARN\" monitorInterval=\"30\">\n\t\t\t\t<Appenders>\n\t\t\t\t\t<Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n\t\t\t\t\t\t<PatternLayout pattern=\"${LOG_PATTERN}\"/>\n\t\t\t\t\t</Console>\n\t\t\t\t</Appenders>\n\t\t\t</Configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithOverrideXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"log4j2-test-spring.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<Configuration xmlns=\"https://logging.apache.org/xml/ns\"\n\t\t\t\t\t               xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\t               xsi:schemaLocation=\"https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-config-2.xsd\"\n\t\t\t\t\t               name=\"SpringBoot\">\n\t\t\t\t\t\t<Appenders>\n\t\t\t\t\t\t\t<Console name=\"CONSOLE\"/>\n\t\t\t\t\t\t</Appenders>\n\t\t\t\t\t\t<Loggers>\n\t\t\t\t\t\t\t<Root level=\"INFO\">\n\t\t\t\t\t\t\t\t<AppenderRef ref=\"CONSOLE\"/>\n\t\t\t\t\t\t\t</Root>\n\t\t\t\t\t\t</Loggers>\n\t\t\t\t\t</Configuration>\n\t\t\t\t\t\"\"\")\n\tprivate @interface WithSpringXmlResource {\n\n\t}\n\n\t/**\n\t * Used for testing that loggers in nested classes are returned by\n\t * {@link Log4J2LoggingSystem#getLoggerConfigurations()} .\n\t */\n\tstatic class Nested {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate static final Log logger = LogFactory.getLog(Nested.class);\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"nondefault.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<Configuration status=\"WARN\" monitorInterval=\"30\">\n\t\t\t\t\t\t<Properties>\n\t\t\t\t\t\t\t<Property name=\"PID\">????</Property>\n\t\t\t\t\t\t\t<Property name=\"LOG_PATTERN\">${sys:LOG_FILE} %d{yyyy-MM-dd HH:mm:ss.SSS}] service%X{context} - ${sys:PID} %5p [%t] --- %c{1}: %m%n</Property>\n\t\t\t\t\t\t</Properties>\n\t\t\t\t\t\t<Appenders>\n\t\t\t\t\t\t\t<Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n\t\t\t\t\t\t\t\t<PatternLayout pattern=\"${LOG_PATTERN}\"/>\n\t\t\t\t\t\t\t</Console>\n\t\t\t\t\t\t</Appenders>\n\t\t\t\t\t\t<Loggers>\n\t\t\t\t\t\t\t<Root level=\"info\">\n\t\t\t\t\t\t\t\t<AppenderRef ref=\"Console\"/>\n\t\t\t\t\t\t\t</Root>\n\t\t\t\t\t\t</Loggers>\n\t\t\t\t\t</Configuration>\n\t\t\t\t\t\"\"\")\n\tprivate @interface WithNonDefaultXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2RuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Arrays;\n\nimport org.apache.logging.log4j.core.impl.Log4jContextFactory;\nimport org.apache.logging.log4j.jul.Log4jBridgeHandler;\nimport org.apache.logging.log4j.jul.LogManager;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.ResourceHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Log4J2RuntimeHints}.\n *\n * @author Piotr P. Karwasz\n * @author Stephane Nicoll\n */\nclass Log4J2RuntimeHintsTests {\n\n\tprivate static final ReflectionHintsPredicates reflectionHints = RuntimeHintsPredicates.reflection();\n\n\tprivate static final ResourceHintsPredicates resourceHints = RuntimeHintsPredicates.resource();\n\n\t@Test\n\tvoid registersHintsForTypesCheckedByLog4J2LoggingSystem() {\n\t\tRuntimeHints runtimeHints = registerHints();\n\t\tassertThat(reflectionHints.onType(Log4jContextFactory.class)).accepts(runtimeHints);\n\t\tassertThat(reflectionHints.onType(Log4jBridgeHandler.class)).accepts(runtimeHints);\n\t\tassertThat(reflectionHints.onType(LogManager.class)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid registersHintsForLog4j2DefaultConfigurationFiles() {\n\t\tRuntimeHints runtimeHints = registerHints();\n\t\tassertThat(resourceHints.forResource(\"org/springframework/boot/logging/log4j2/log4j2.xml\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(resourceHints.forResource(\"org/springframework/boot/logging/log4j2/log4j2-file.xml\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(resourceHints.forResource(\"log4j2.springboot\")).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid doesNotRegisterHintsWhenLog4jCoreIsNotAvailable() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew Log4J2RuntimeHints().registerHints(runtimeHints, new HidePackagesClassLoader(\"org.apache.logging.log4j\"));\n\t\tassertThat(runtimeHints.reflection().typeHints()).isEmpty();\n\t}\n\n\tprivate RuntimeHints registerHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew Log4J2RuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\treturn hints;\n\t}\n\n\tstatic final class HidePackagesClassLoader extends URLClassLoader {\n\n\t\tprivate final String[] hiddenPackages;\n\n\t\tHidePackagesClassLoader(String... hiddenPackages) {\n\t\t\tsuper(new URL[0], HidePackagesClassLoader.class.getClassLoader());\n\t\t\tthis.hiddenPackages = hiddenPackages;\n\t\t}\n\n\t\t@Override\n\t\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\t\tif (Arrays.stream(this.hiddenPackages).anyMatch(name::startsWith)) {\n\t\t\t\tthrow new ClassNotFoundException();\n\t\t\t}\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2FileXmlTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.io.File;\n\nimport org.apache.logging.log4j.core.layout.PatternLayout;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.logging.LoggingSystemProperty;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@code log4j2-file.xml}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass Log4j2FileXmlTests extends Log4j2XmlTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Override\n\t@AfterEach\n\tvoid stopConfiguration() {\n\t\tsuper.stopConfiguration();\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenLogExceptionConversionWordIsNotConfiguredThenFileAppenderUsesDefault() {\n\t\tassertThat(fileAppenderPattern()).contains(\"%xwEx\");\n\t}\n\n\t@Test\n\tvoid whenLogExceptionConversionWordIsSetThenFileAppenderUsesIt() {\n\t\twithSystemProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD.getEnvironmentVariableName(), \"custom\",\n\t\t\t\t() -> assertThat(fileAppenderPattern()).contains(\"custom\"));\n\t}\n\n\t@Test\n\tvoid whenLogLevelPatternIsNotConfiguredThenFileAppenderUsesDefault() {\n\t\tassertThat(fileAppenderPattern()).contains(\"%5p\");\n\t}\n\n\t@Test\n\tvoid whenLogLevelPatternIsSetThenFileAppenderUsesIt() {\n\t\twithSystemProperty(LoggingSystemProperty.LEVEL_PATTERN.getEnvironmentVariableName(), \"custom\",\n\t\t\t\t() -> assertThat(fileAppenderPattern()).contains(\"custom\"));\n\t}\n\n\t@Test\n\tvoid whenLogLDateformatPatternIsNotConfiguredThenFileAppenderUsesDefault() {\n\t\tassertThat(fileAppenderPattern()).contains(\"yyyy-MM-dd'T'HH:mm:ss.SSSXXX\");\n\t}\n\n\t@Test\n\tvoid whenLogDateformatPatternIsSetThenFileAppenderUsesIt() {\n\t\twithSystemProperty(LoggingSystemProperty.DATEFORMAT_PATTERN.getEnvironmentVariableName(), \"dd-MM-yyyy\",\n\t\t\t\t() -> assertThat(fileAppenderPattern()).contains(\"dd-MM-yyyy\"));\n\t}\n\n\t@Override\n\tprotected String getConfigFileName() {\n\t\treturn \"log4j2-file.xml\";\n\t}\n\n\t@Override\n\tprotected void prepareConfiguration() {\n\t\tSystem.setProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName(),\n\t\t\t\tnew File(this.temp, \"test.log\").getAbsolutePath());\n\t\tsuper.prepareConfiguration();\n\t}\n\n\tprivate String fileAppenderPattern() {\n\t\tprepareConfiguration();\n\t\tassertThat(this.configuration).isNotNull();\n\t\treturn ((PatternLayout) this.configuration.getAppender(\"File\").getLayout()).getConversionPattern();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2LoggingSystemPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Log4j2LoggingSystemProperties}.\n *\n * @author hojooo\n */\nclass Log4j2LoggingSystemPropertiesTests {\n\n\tprivate Set<Object> systemPropertyNames;\n\n\tprivate MockEnvironment environment;\n\n\t@BeforeEach\n\tvoid captureSystemPropertyNames() {\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t\tthis.systemPropertyNames = new HashSet<>(System.getProperties().keySet());\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment\n\t\t\t.setConversionService((ConfigurableConversionService) ApplicationConversionService.getSharedInstance());\n\t}\n\n\t@AfterEach\n\tvoid restoreSystemProperties() {\n\t\tSystem.getProperties().keySet().retainAll(this.systemPropertyNames);\n\t}\n\n\t@Test\n\tvoid appliesLog4j2RollingPolicyProperties() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-file-size\", \"50MB\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-history\", \"30\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.file-name-pattern\", \"test.%d{yyyy-MM-dd}.%i.log\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.strategy\", \"time\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.time-interval\", \"2\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.time-modulate\", \"true\");\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.cron\", \"0 0 1 * * ?\");\n\n\t\tnew Log4j2LoggingSystemProperties(this.environment).apply(null);\n\n\t\tassertThat(System.getProperties())\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_MAX_FILE_SIZE\", String.valueOf(DataSize.ofMegabytes(50).toBytes()))\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_MAX_HISTORY\", \"30\")\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_FILE_NAME_PATTERN\", \"test.%d{yyyy-MM-dd}.%i.log\")\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_STRATEGY\", \"time\")\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_TIME_INTERVAL\", \"2\")\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_TIME_MODULATE\", \"true\")\n\t\t\t.containsEntry(\"LOG4J2_ROLLINGPOLICY_CRON\", \"0 0 1 * * ?\");\n\t}\n\n\t@Test\n\tvoid appliesLog4j2RollingPolicyPropertiesWithDefaults() {\n\t\tnew Log4j2LoggingSystemProperties(this.environment).apply(null);\n\t\tassertThat(System.getProperties().keySet())\n\t\t\t.noneMatch((key) -> ((String) key).startsWith(\"LOG4J2_ROLLINGPOLICY\"));\n\t}\n\n\t@Test\n\tvoid appliesWithLogFile() {\n\t\tthis.environment.setProperty(\"logging.log4j2.rollingpolicy.max-file-size\", \"25MB\");\n\t\tLogFile logFile = LogFile.get(this.environment);\n\t\tnew Log4j2LoggingSystemProperties(this.environment).apply(logFile);\n\t\tassertThat(System.getProperties()).containsEntry(\"LOG4J2_ROLLINGPOLICY_MAX_FILE_SIZE\",\n\t\t\t\tString.valueOf(DataSize.ofMegabytes(25).toBytes()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4j2XmlTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.apache.logging.log4j.core.config.ConfigurationFactory;\nimport org.apache.logging.log4j.core.config.ConfigurationSource;\nimport org.apache.logging.log4j.core.layout.PatternLayout;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.LoggingSystemProperty;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@code log4j2.xml}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass Log4j2XmlTests {\n\n\tprotected @Nullable Configuration configuration;\n\n\t@AfterEach\n\tvoid stopConfiguration() {\n\t\tif (this.configuration != null) {\n\t\t\tthis.configuration.stop();\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenLogExceptionConversionWordIsNotConfiguredThenConsoleUsesDefault() {\n\t\tassertThat(consolePattern()).contains(\"%xwEx\");\n\t}\n\n\t@Test\n\tvoid whenLogExceptionConversionWordIsSetThenConsoleUsesIt() {\n\t\twithSystemProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD.getEnvironmentVariableName(), \"custom\",\n\t\t\t\t() -> assertThat(consolePattern()).contains(\"custom\"));\n\t}\n\n\t@Test\n\tvoid whenLogLevelPatternIsNotConfiguredThenConsoleUsesDefault() {\n\t\tassertThat(consolePattern()).contains(\"%5p\");\n\t}\n\n\t@Test\n\tvoid whenLogLevelPatternIsSetThenConsoleUsesIt() {\n\t\twithSystemProperty(LoggingSystemProperty.LEVEL_PATTERN.getEnvironmentVariableName(), \"custom\",\n\t\t\t\t() -> assertThat(consolePattern()).contains(\"custom\"));\n\t}\n\n\t@Test\n\tvoid whenLogLDateformatPatternIsNotConfiguredThenConsoleUsesDefault() {\n\t\tassertThat(consolePattern()).contains(\"yyyy-MM-dd'T'HH:mm:ss.SSSXXX\");\n\t}\n\n\t@Test\n\tvoid whenLogDateformatPatternIsSetThenConsoleUsesIt() {\n\t\twithSystemProperty(LoggingSystemProperty.DATEFORMAT_PATTERN.getEnvironmentVariableName(), \"dd-MM-yyyy\",\n\t\t\t\t() -> assertThat(consolePattern()).contains(\"dd-MM-yyyy\"));\n\t}\n\n\tprotected void withSystemProperty(String name, String value, Runnable action) {\n\t\tString previous = System.setProperty(name, value);\n\t\taction.run();\n\t\tif (previous == null) {\n\t\t\tSystem.clearProperty(name);\n\t\t}\n\t\telse {\n\t\t\tSystem.setProperty(name, previous);\n\t\t}\n\t}\n\n\tprivate String consolePattern() {\n\t\tprepareConfiguration();\n\t\tassertThat(this.configuration).isNotNull();\n\t\treturn ((PatternLayout) this.configuration.getAppender(\"Console\").getLayout()).getConversionPattern();\n\t}\n\n\tprotected void prepareConfiguration() {\n\t\tthis.configuration = initializeConfiguration();\n\t\tthis.configuration.start();\n\t}\n\n\tprotected Configuration initializeConfiguration() {\n\t\tLoggerContext context = new LoggerContext(\"test\");\n\t\tConfiguration configuration = ConfigurationFactory.getInstance()\n\t\t\t.getConfiguration(context, configurationSource());\n\t\tconfiguration.initialize();\n\t\treturn configuration;\n\t}\n\n\tprivate ConfigurationSource configurationSource() {\n\t\ttry (InputStream in = getClass().getResourceAsStream(getConfigFileName())) {\n\t\t\treturn new ConfigurationSource(in);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprotected String getConfigFileName() {\n\t\treturn \"log4j2.xml\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/LogstashStructuredLogFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.time.OffsetDateTime;\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.logging.log4j.MarkerManager.Log4jMarker;\nimport org.apache.logging.log4j.core.impl.JdkMapAdapterStringMap;\nimport org.apache.logging.log4j.core.impl.MutableLogEvent;\nimport org.apache.logging.log4j.message.MapMessage;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.structured.TestContextPairs;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link LogstashStructuredLogFormatter}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass LogstashStructuredLogFormatterTests extends AbstractStructuredLoggingTests {\n\n\tprivate LogstashStructuredLogFormatter formatter;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.formatter = new LogstashStructuredLogFormatter(null, TestContextPairs.include(), this.customizer);\n\t}\n\n\t@Test\n\tvoid callsCustomizer() {\n\t\tthen(this.customizer).should().customize(any());\n\t}\n\n\t@Test\n\tvoid shouldFormat() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setContextData(new JdkMapAdapterStringMap(Map.of(\"mdc-1\", \"mdc-v-1\"), true));\n\t\tLog4jMarker marker1 = new Log4jMarker(\"marker-1\");\n\t\tmarker1.addParents(new Log4jMarker(\"marker-2\"));\n\t\tevent.setMarker(marker1);\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString timestamp = DateTimeFormatter.ISO_OFFSET_DATE_TIME\n\t\t\t.format(OffsetDateTime.ofInstant(EVENT_TIME, ZoneId.systemDefault()));\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"@timestamp\", timestamp, \"@version\", \"1\",\n\t\t\t\t\"message\", \"message\", \"logger_name\", \"org.example.Test\", \"thread_name\", \"main\", \"level\", \"INFO\",\n\t\t\t\t\"level_value\", 400, \"mdc-1\", \"mdc-v-1\", \"tags\", List.of(\"marker-1\", \"marker-2\")));\n\t}\n\n\t@Test\n\tvoid shouldFormatException() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setThrown(new RuntimeException(\"Boom\"));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString stackTrace = (String) deserialized.get(\"stack_trace\");\n\t\tassertThat(stackTrace).startsWith(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.log4j2.LogstashStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted());\n\t\tassertThat(json).contains(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\\\tat org.springframework.boot.logging.log4j2.LogstashStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted()\n\t\t\t\t\t.replace(\"\\n\", \"\\\\n\")\n\t\t\t\t\t.replace(\"\\r\", \"\\\\r\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatExceptionWithStackTracePrinter() {\n\t\tthis.formatter = new LogstashStructuredLogFormatter(new SimpleStackTracePrinter(), TestContextPairs.include(),\n\t\t\t\tthis.customizer);\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setThrown(new RuntimeException(\"Boom\"));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString stackTrace = (String) deserialized.get(\"stack_trace\");\n\t\tassertThat(stackTrace).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldFormatStructuredMessage() {\n\t\tMutableLogEvent event = createEvent();\n\t\tevent.setMessage(new MapMessage<>().with(\"foo\", true).with(\"bar\", 1.0));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tMap<String, Object> expectedMessage = Map.of(\"foo\", true, \"bar\", 1.0);\n\t\tString timestamp = DateTimeFormatter.ISO_OFFSET_DATE_TIME\n\t\t\t.format(OffsetDateTime.ofInstant(EVENT_TIME, ZoneId.systemDefault()));\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(\n\t\t\t\tmap(\"@timestamp\", timestamp, \"@version\", \"1\", \"message\", expectedMessage, \"logger_name\",\n\t\t\t\t\t\t\"org.example.Test\", \"thread_name\", \"main\", \"level\", \"INFO\", \"level_value\", 400));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SimpleStackTracePrinter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Simple {@link StackTracePrinter} used for testing.\n *\n * @author Phillip Webb\n */\nclass SimpleStackTracePrinter implements StackTracePrinter {\n\n\t@Override\n\tpublic void printStackTrace(Throwable throwable, Appendable out) throws IOException {\n\t\tout.append(\"stacktrace:\" + ClassUtils.getShortName(throwable.getClass()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringBootPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.lang.reflect.Method;\nimport java.util.stream.Stream;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.core.util.Constants;\nimport org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootPropertySource}.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions({ \"jakarta.servlet-api-*.jar\", \"tomcat-embed-core-*.jar\" })\nclass SpringBootPropertySourceTests {\n\n\t@Test\n\tvoid propertySourceHasDisabledShutdownHook() {\n\t\t// Log4j2 disables the hook automatically in a web app so we check that it doesn't\n\t\t// think it's in one\n\t\tassertThat(Constants.IS_WEB_APP).isFalse();\n\t\tassertThat(((ShutdownCallbackRegistry) LogManager.getFactory()).addShutdownCallback(() -> {\n\t\t})).isNull();\n\t}\n\n\t@Test\n\tvoid allDefaultMethodsAreImplemented() {\n\t\tassertThat(Stream.of(SpringBootPropertySource.class.getMethods()).filter(Method::isDefault)).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringEnvironmentLookupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.apache.logging.log4j.core.lookup.Interpolator;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SpringEnvironmentLookup}.\n *\n * @author Phillip Webb\n */\nclass SpringEnvironmentLookupTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate LoggerContext loggerContext;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.loggerContext = (LoggerContext) LogManager.getContext(false);\n\t\tthis.loggerContext.putObject(Log4J2LoggingSystem.ENVIRONMENT_KEY, this.environment);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tthis.loggerContext.removeObject(Log4J2LoggingSystem.ENVIRONMENT_KEY);\n\t}\n\n\t@Test\n\tvoid lookupWhenFoundInEnvironmentReturnsValue() {\n\t\tthis.environment.setProperty(\"test\", \"test\");\n\t\tInterpolator lookup = createLookup(this.loggerContext);\n\t\tassertThat(lookup.lookup(\"spring:test\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid lookupWhenNotFoundInEnvironmentReturnsNull() {\n\t\tInterpolator lookup = createLookup(this.loggerContext);\n\t\tassertThat(lookup.lookup(\"spring:test\")).isNull();\n\t}\n\n\t@Test\n\tvoid lookupWhenNoSpringEnvironmentThrowsException() {\n\t\tthis.loggerContext.removeObject(Log4J2LoggingSystem.ENVIRONMENT_KEY);\n\t\tInterpolator lookup = createLookup(this.loggerContext);\n\t\tassertThatIllegalStateException().isThrownBy(() -> lookup.lookup(\"spring:test\"))\n\t\t\t.withMessage(\"Unable to obtain Spring Environment from LoggerContext. \"\n\t\t\t\t\t+ \"This can happen if your log4j2 configuration filename does not end with '-spring' \"\n\t\t\t\t\t+ \"(for example using 'log4j2.xml' instead of 'log4j2-spring.xml')\");\n\t}\n\n\tprivate Interpolator createLookup(LoggerContext context) {\n\t\tInterpolator lookup = new Interpolator();\n\t\tlookup.setConfiguration(context.getConfiguration());\n\t\tlookup.setLoggerContext(context);\n\t\treturn lookup;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringEnvironmentPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Properties;\n\nimport org.apache.logging.log4j.util.PropertiesPropertySource;\nimport org.apache.logging.log4j.util.SystemPropertiesPropertySource;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringEnvironmentPropertySource}.\n *\n * @author Phillip Webb\n */\nclass SpringEnvironmentPropertySourceTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate SpringEnvironmentPropertySource propertySource;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"spring\", \"boot\");\n\t\tthis.propertySource = new SpringEnvironmentPropertySource();\n\t\tthis.propertySource.setEnvironment(this.environment);\n\t}\n\n\t@Test\n\tvoid getPriorityIsOrderedCorrectly() {\n\t\tint priority = this.propertySource.getPriority();\n\t\tassertThat(priority).isEqualTo(-100);\n\t\tassertThat(priority).isLessThan(new SystemPropertiesPropertySource().getPriority());\n\t\tassertThat(priority).isLessThan(new PropertiesPropertySource(new Properties()).getPriority());\n\t}\n\n\t@Test\n\tvoid getPropertyWhenInEnvironmentReturnsValue() {\n\t\tassertThat(this.propertySource.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid getPropertyWhenEnvironmentIsNullReturnsNull() {\n\t\tthis.propertySource.setEnvironment(null);\n\t\tassertThat(this.propertySource.getProperty(\"spring\")).isNull();\n\t}\n\n\t@Test\n\tvoid getPropertyWhenNotInEnvironmentReturnsNull() {\n\t\tassertThat(this.propertySource.getProperty(\"nope\")).isNull();\n\t}\n\n\t@Test\n\tvoid containsPropertyWhenInEnvironmentReturnsTrue() {\n\t\tassertThat(this.propertySource.containsProperty(\"spring\")).isTrue();\n\t}\n\n\t@Test\n\tvoid containsPropertyWhenEnvironmentIsNullReturnsFalse() {\n\t\tthis.propertySource.setEnvironment(null);\n\t\tassertThat(this.propertySource.containsProperty(\"spring\")).isFalse();\n\t}\n\n\t@Test\n\tvoid containsPropertyWhenNotInEnvironmentReturnsFalse() {\n\t\tassertThat(this.propertySource.containsProperty(\"nope\")).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/SpringProfileArbiterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Set;\n\nimport org.apache.logging.log4j.Logger;\nimport org.apache.logging.log4j.util.PropertiesUtil;\nimport org.apache.logging.log4j.util.PropertySource;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestInfo;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.logging.ConfigureClasspathToPreferLog4j2;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringProfileArbiter}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathExclusions(\"logback-*.jar\")\n@ConfigureClasspathToPreferLog4j2\nclass SpringProfileArbiterTests {\n\n\tprivate CapturedOutput output;\n\n\tprivate TestLog4J2LoggingSystem loggingSystem;\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final LoggingInitializationContext initializationContext = new LoggingInitializationContext(\n\t\t\tthis.environment);\n\n\tprivate Logger logger;\n\n\t@BeforeEach\n\tvoid setup(CapturedOutput output, TestInfo testInfo) {\n\t\tthis.output = output;\n\t\tthis.loggingSystem = new TestLog4J2LoggingSystem(testInfo.getDisplayName());\n\t\tthis.logger = this.loggingSystem.getLoggerContext().getLogger(getClass().getName());\n\t\tcleanUpPropertySources();\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tthis.loggingSystem.cleanUp();\n\t\tcleanUpPropertySources();\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void cleanUpPropertySources() { // https://issues.apache.org/jira/browse/LOG4J2-3618\n\t\tPropertiesUtil properties = PropertiesUtil.getProperties();\n\t\tObject environment = ReflectionTestUtils.getField(properties, \"environment\");\n\t\tassertThat(environment).isNotNull();\n\t\tSet<PropertySource> sources = (Set<PropertySource>) ReflectionTestUtils.getField(environment, \"sources\");\n\t\tassertThat(sources).isNotNull();\n\t\tsources.removeIf((candidate) -> candidate instanceof SpringEnvironmentPropertySource\n\t\t\t\t|| candidate instanceof SpringBootPropertySource);\n\t}\n\n\t@Test\n\t@WithProductionProfileXmlResource\n\tvoid profileActive() {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"production-profile.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithMultiProfileNamesXmlResource\n\tvoid multipleNamesFirstProfileActive() {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"multi-profile-names.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithMultiProfileNamesXmlResource\n\tvoid multipleNamesSecondProfileActive() {\n\t\tthis.environment.setActiveProfiles(\"test\");\n\t\tinitialize(\"multi-profile-names.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProductionProfileXmlResource\n\tvoid profileNotActive() {\n\t\tinitialize(\"production-profile.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).doesNotContain(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProfileExpressionXmlResource\n\tvoid profileExpressionMatchFirst() {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"profile-expression.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProfileExpressionXmlResource\n\tvoid profileExpressionMatchSecond() {\n\t\tthis.environment.setActiveProfiles(\"test\");\n\t\tinitialize(\"profile-expression.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProfileExpressionXmlResource\n\tvoid profileExpressionNoMatch() {\n\t\tthis.environment.setActiveProfiles(\"development\");\n\t\tinitialize(\"profile-expression.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).doesNotContain(\"Hello\");\n\t}\n\n\tprivate void initialize(String config) {\n\t\tthis.environment.setProperty(\"logging.log4j2.config.override\", \"classpath:\" + config);\n\t\tthis.loggingSystem.initialize(this.initializationContext, null, null);\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"multi-profile-names.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<Configuration>\n\t\t\t    <Loggers>\n\t\t\t\t    <SpringProfile name=\"production, test\">\n\t\t\t\t\t\t<Logger name=\"org.springframework.boot.logging.log4j2\" level=\"TRACE\" />\n\t\t\t\t\t</SpringProfile>\n\t\t\t\t</Loggers>\n\t\t\t</Configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithMultiProfileNamesXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"profile-expression.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<Configuration>\n\t\t\t    <Loggers>\n\t\t\t\t    <SpringProfile name=\"production | test\">\n\t\t\t\t\t\t<Logger name=\"org.springframework.boot.logging.log4j2\" level=\"TRACE\" />\n\t\t\t\t\t</SpringProfile>\n\t\t\t\t</Loggers>\n\t\t\t</Configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithProfileExpressionXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"production-profile.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<Configuration>\n\t\t\t    <Loggers>\n\t\t\t\t    <SpringProfile name=\"production\">\n\t\t\t\t\t\t<Logger name=\"org.springframework.boot.logging.log4j2\" level=\"TRACE\" />\n\t\t\t\t\t</SpringProfile>\n\t\t\t\t</Loggers>\n\t\t\t</Configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithProductionProfileXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/StructuredLogLayoutTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport java.util.Map;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.LoggerContext;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.log4j2.StructuredLogLayout.Builder;\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.core.env.Environment;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link StructuredLogLayout}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass StructuredLogLayoutTests extends AbstractStructuredLoggingTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate LoggerContext loggerContext;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"logging.structured.json.stacktrace.printer\",\n\t\t\t\tSimpleStackTracePrinter.class.getName());\n\t\tthis.loggerContext = (LoggerContext) LogManager.getContext(false);\n\t\tthis.loggerContext.putObject(Log4J2LoggingSystem.ENVIRONMENT_KEY, this.environment);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tthis.loggerContext.removeObject(Log4J2LoggingSystem.ENVIRONMENT_KEY);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldSupportEcsCommonFormat() {\n\t\tStructuredLogLayout layout = newBuilder().setFormat(\"ecs\").build();\n\t\tString json = layout.toSerializable(createEvent(new RuntimeException(\"Boom!\")));\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsEntry(\"ecs\", Map.of(\"version\", \"8.11\"));\n\t\tMap<String, Object> error = (Map<String, Object>) deserialized.get(\"error\");\n\t\tassertThat(error).isNotNull();\n\t\tassertThat(error.get(\"stack_trace\")).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldOutputNestedAdditionalEcsJson() {\n\t\tthis.environment.setProperty(\"logging.structured.json.add.extra.value\", \"test\");\n\t\tStructuredLogLayout layout = newBuilder().setFormat(\"ecs\").build();\n\t\tString json = layout.toSerializable(createEvent(new RuntimeException(\"Boom!\")));\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsKey(\"extra\");\n\t\tassertThat((Map<String, Object>) deserialized.get(\"extra\")).containsEntry(\"value\", \"test\");\n\t\tSystem.out.println(deserialized);\n\t}\n\n\t@Test\n\tvoid shouldSupportLogstashCommonFormat() {\n\t\tStructuredLogLayout layout = newBuilder().setFormat(\"logstash\").build();\n\t\tString json = layout.toSerializable(createEvent(new RuntimeException(\"Boom!\")));\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsKey(\"@version\");\n\t\tassertThat(deserialized.get(\"stack_trace\")).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldSupportGelfCommonFormat() {\n\t\tStructuredLogLayout layout = newBuilder().setFormat(\"gelf\").build();\n\t\tString json = layout.toSerializable(createEvent(new RuntimeException(\"Boom!\")));\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsKey(\"version\");\n\t\tassertThat(deserialized.get(\"_error_stack_trace\")).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldSupportCustomFormat() {\n\t\tStructuredLogLayout layout = newBuilder().setFormat(CustomLog4j2StructuredLoggingFormatter.class.getName())\n\t\t\t.build();\n\t\tString format = layout.toSerializable(createEvent());\n\t\tassertThat(format).isEqualTo(\"custom-format\");\n\t}\n\n\t@Test\n\tvoid shouldInjectCustomFormatConstructorParameters() {\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"42\");\n\t\tStructuredLogLayout layout = newBuilder()\n\t\t\t.setFormat(CustomLog4j2StructuredLoggingFormatterWithInjection.class.getName())\n\t\t\t.build();\n\t\tString format = layout.toSerializable(createEvent());\n\t\tassertThat(format).isEqualTo(\"custom-format-with-injection pid=42\");\n\t}\n\n\t@Test\n\tvoid shouldCheckTypeArgument() {\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> newBuilder().setFormat(CustomLog4j2StructuredLoggingFormatterWrongType.class.getName()).build())\n\t\t\t.withMessageContaining(\"must be org.apache.logging.log4j.core.LogEvent but was java.lang.String\");\n\t}\n\n\t@Test\n\tvoid shouldCheckTypeArgumentWithRawType() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> newBuilder().setFormat(CustomLog4j2StructuredLoggingFormatterRawType.class.getName()).build())\n\t\t\t.withMessageContaining(\"must be org.apache.logging.log4j.core.LogEvent but was null\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfNoCommonOrCustomFormatIsSet() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> newBuilder().setFormat(\"does-not-exist\").build())\n\t\t\t.withMessageContaining(\"Unknown format 'does-not-exist'. \"\n\t\t\t\t\t+ \"Values can be a valid fully-qualified class name or one of the common formats: [ecs, gelf, logstash]\");\n\t}\n\n\tprivate Builder newBuilder() {\n\t\tBuilder builder = StructuredLogLayout.newBuilder();\n\t\tReflectionTestUtils.setField(builder, \"loggerContext\", this.loggerContext);\n\t\treturn builder;\n\t}\n\n\tstatic final class CustomLog4j2StructuredLoggingFormatter implements StructuredLogFormatter<LogEvent> {\n\n\t\t@Override\n\t\tpublic String format(LogEvent event) {\n\t\t\treturn \"custom-format\";\n\t\t}\n\n\t}\n\n\tstatic final class CustomLog4j2StructuredLoggingFormatterWithInjection implements StructuredLogFormatter<LogEvent> {\n\n\t\tprivate final Environment environment;\n\n\t\tCustomLog4j2StructuredLoggingFormatterWithInjection(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic String format(LogEvent event) {\n\t\t\treturn \"custom-format-with-injection pid=\" + this.environment.getProperty(\"spring.application.pid\");\n\t\t}\n\n\t}\n\n\tstatic final class CustomLog4j2StructuredLoggingFormatterWrongType implements StructuredLogFormatter<String> {\n\n\t\t@Override\n\t\tpublic String format(String event) {\n\t\t\treturn event;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tstatic final class CustomLog4j2StructuredLoggingFormatterRawType implements StructuredLogFormatter {\n\n\t\t@Override\n\t\tpublic String format(Object event) {\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/TestLog4J2LoggingSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.config.Configuration;\nimport org.jspecify.annotations.Nullable;\n\nclass TestLog4J2LoggingSystem extends Log4J2LoggingSystem {\n\n\tprivate boolean disableSelfInitialization;\n\n\tTestLog4J2LoggingSystem(String contextName) {\n\t\t// Tests add resources to the thread context classloader\n\t\tsuper(Thread.currentThread().getContextClassLoader());\n\t\tgetLoggerContext().setName(contextName);\n\t\tgetLoggerContext().start();\n\t}\n\n\tConfiguration getConfiguration() {\n\t\treturn getLoggerContext().getConfiguration();\n\t}\n\n\t@Override\n\tprotected @Nullable String getSelfInitializationConfig() {\n\t\treturn this.disableSelfInitialization ? null : super.getSelfInitializationConfig();\n\t}\n\n\tvoid disableSelfInitialization() {\n\t\tthis.disableSelfInitialization = true;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/WhitespaceThrowablePatternConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.log4j2;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.apache.logging.log4j.core.config.DefaultConfiguration;\nimport org.apache.logging.log4j.core.impl.Log4jLogEvent;\nimport org.apache.logging.log4j.core.pattern.LogEventPatternConverter;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WhitespaceThrowablePatternConverter}.\n *\n * @author Vladimir Tsanev\n */\nclass WhitespaceThrowablePatternConverterTests {\n\n\tprivate final LogEventPatternConverter converter = WhitespaceThrowablePatternConverter\n\t\t.newInstance(new DefaultConfiguration(), new String[] {});\n\n\t@Test\n\tvoid noStackTrace() {\n\t\tLogEvent event = Log4jLogEvent.newBuilder().build();\n\t\tStringBuilder builder = new StringBuilder();\n\t\tthis.converter.format(event, builder);\n\t\tassertThat(builder).isEmpty();\n\t}\n\n\t@Test\n\tvoid withStackTrace() {\n\t\tLogEvent event = Log4jLogEvent.newBuilder().setThrown(new Exception()).build();\n\t\tStringBuilder builder = new StringBuilder();\n\t\tthis.converter.format(event, builder);\n\t\tassertThat(builder.toString()).startsWith(System.lineSeparator()).endsWith(System.lineSeparator());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/AbstractStructuredLoggingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.slf4j.Marker;\nimport org.slf4j.event.KeyValuePair;\nimport org.slf4j.helpers.BasicMarkerFactory;\nimport tools.jackson.core.type.TypeReference;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.logging.structured.MockStructuredLoggingJsonMembersCustomizerBuilder;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for structured formatting tests.\n *\n * @author Moritz Halbritter\n */\n@ExtendWith(MockitoExtension.class)\nabstract class AbstractStructuredLoggingTests {\n\n\tstatic final Instant EVENT_TIME = Instant.ofEpochSecond(1719910193L);\n\n\tprivate static final JsonMapper JSON_MAPPER = new JsonMapper();\n\n\tprivate ThrowableProxyConverter throwableProxyConverter;\n\n\tprivate BasicMarkerFactory markerFactory;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tStructuredLoggingJsonMembersCustomizer<?> customizer;\n\n\tMockStructuredLoggingJsonMembersCustomizerBuilder<?> customizerBuilder = new MockStructuredLoggingJsonMembersCustomizerBuilder<>(\n\t\t\t() -> this.customizer);\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.markerFactory = new BasicMarkerFactory();\n\t\tthis.throwableProxyConverter = new ThrowableProxyConverter();\n\t\tthis.throwableProxyConverter.start();\n\t}\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tthis.throwableProxyConverter.stop();\n\t}\n\n\tprotected Marker getMarker(String name) {\n\t\treturn this.markerFactory.getDetachedMarker(name);\n\t}\n\n\tprotected ThrowableProxyConverter getThrowableProxyConverter() {\n\t\treturn this.throwableProxyConverter;\n\t}\n\n\tprotected Map<String, Object> map(Object... values) {\n\t\tassertThat(values.length).isEven();\n\t\tMap<String, Object> result = new HashMap<>();\n\t\tfor (int i = 0; i < values.length; i += 2) {\n\t\t\tresult.put(values[i].toString(), values[i + 1]);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected List<KeyValuePair> keyValuePairs(Object... values) {\n\t\tassertThat(values.length).isEven();\n\t\tList<KeyValuePair> result = new ArrayList<>();\n\t\tfor (int i = 0; i < values.length; i += 2) {\n\t\t\tresult.add(new KeyValuePair(values[i].toString(), values[i + 1]));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprotected static LoggingEvent createEvent() {\n\t\treturn createEvent(null);\n\t}\n\n\tprotected static LoggingEvent createEvent(@Nullable Throwable thrown) {\n\t\tLoggingEvent event = new LoggingEvent();\n\t\tevent.setInstant(EVENT_TIME);\n\t\tevent.setLevel(Level.INFO);\n\t\tevent.setThreadName(\"main\");\n\t\tevent.setLoggerName(\"org.example.Test\");\n\t\tevent.setMessage(\"message\");\n\t\tif (thrown != null) {\n\t\t\tevent.setThrowableProxy(new ThrowableProxy(thrown));\n\t\t}\n\t\treturn event;\n\t}\n\n\tprotected Map<String, Object> deserialize(String json) {\n\t\treturn JSON_MAPPER.readValue(json, new TypeReference<>() {\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ColorConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ansi.AnsiOutput;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ColorConverter}.\n *\n * @author Phillip Webb\n */\nclass ColorConverterTests {\n\n\tprivate final ColorConverter converter = new ColorConverter();\n\n\tprivate final LoggingEvent event = new LoggingEvent();\n\n\tprivate final String in = \"in\";\n\n\t@BeforeAll\n\tstatic void setupAnsi() {\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.ALWAYS);\n\t}\n\n\t@AfterAll\n\tstatic void resetAnsi() {\n\t\tAnsiOutput.setEnabled(AnsiOutput.Enabled.DETECT);\n\t}\n\n\t@Test\n\tvoid black() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"black\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[30min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid white() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"white\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[37min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid faint() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"faint\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[2min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid red() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"red\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid green() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"green\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[32min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid yellow() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"yellow\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[33min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid blue() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"blue\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[34min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid magenta() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"magenta\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[35min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid cyan() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"cyan\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[36min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightBlack() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_black\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[90min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightWhite() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_white\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[97min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightRed() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_red\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[91min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightGreen() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_green\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[92min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightYellow() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_yellow\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[93min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightBlue() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_blue\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[94min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightMagenta() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_magenta\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[95min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid brightCyan() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bright_cyan\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[96min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bold() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bold\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[1min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid italic() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"italic\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[3min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid underline() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"underline\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[4min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid reverse() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"reverse\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[7min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgRed() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bg_red\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[41min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgGreen() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bg_green\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[42min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgYellow() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bg_yellow\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[43min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgBlue() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bg_blue\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[44min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid bgBrightRed() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bg_bright_red\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[101min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid multipleStylesCommaSeparated() {\n\t\tthis.converter.setOptionList(Collections.singletonList(\"bold, red\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[1;31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid multipleStyles() {\n\t\tthis.converter.setOptionList(Arrays.asList(\"bold\", \"red\"));\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[1;31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightError() {\n\t\tthis.event.setLevel(Level.ERROR);\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[31min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightWarn() {\n\t\tthis.event.setLevel(Level.WARN);\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[33min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightDebug() {\n\t\tthis.event.setLevel(Level.DEBUG);\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[32min\\033[0;39m\");\n\t}\n\n\t@Test\n\tvoid highlightTrace() {\n\t\tthis.event.setLevel(Level.TRACE);\n\t\tString out = this.converter.transform(this.event, this.in);\n\t\tassertThat(out).isEqualTo(\"\\033[32min\\033[0;39m\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/CorrelationIdConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CorrelationIdConverter}.\n *\n * @author Phillip Webb\n */\nclass CorrelationIdConverterTests {\n\n\tprivate final CorrelationIdConverter converter;\n\n\tprivate final LoggingEvent event = new LoggingEvent();\n\n\tCorrelationIdConverterTests() {\n\t\tthis.converter = new CorrelationIdConverter();\n\t\tthis.converter.setContext(new LoggerContext());\n\t}\n\n\t@Test\n\tvoid defaultPattern() {\n\t\taddMdcProperties(this.event);\n\t\tthis.converter.start();\n\t\tString converted = this.converter.convert(this.event);\n\t\tthis.converter.stop();\n\t\tassertThat(converted).isEqualTo(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid customPattern() {\n\t\tthis.converter.setOptionList(List.of(\"traceId(0)\", \"spanId(0)\"));\n\t\taddMdcProperties(this.event);\n\t\tthis.converter.start();\n\t\tString converted = this.converter.convert(this.event);\n\t\tthis.converter.stop();\n\t\tassertThat(converted).isEqualTo(\"[01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\tprivate void addMdcProperties(LoggingEvent event) {\n\t\tevent.setMDCPropertyMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/DefaultLogbackConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.Console;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link DefaultLogbackConfiguration}\n *\n * @author Phillip Webb\n */\nclass DefaultLogbackConfigurationTests {\n\n\tprivate final LoggerContext loggerContext = new LoggerContext();\n\n\tprivate final LogbackConfigurator logbackConfigurator = new LogbackConfigurator(this.loggerContext);\n\n\t@Test\n\tvoid defaultLogbackXmlContainsConsoleLogPattern() throws Exception {\n\t\tassertThatDefaultXmlContains(\"CONSOLE_LOG_PATTERN\", DefaultLogbackConfiguration.CONSOLE_LOG_PATTERN);\n\t}\n\n\t@Test\n\tvoid defaultLogbackXmlContainsFileLogPattern() throws Exception {\n\t\tassertThatDefaultXmlContains(\"FILE_LOG_PATTERN\", DefaultLogbackConfiguration.FILE_LOG_PATTERN);\n\t}\n\n\t@Test\n\tvoid consoleLogCharsetShouldUseConsoleCharsetIfConsoleAvailable() {\n\t\tDefaultLogbackConfiguration logbackConfiguration = spy(new DefaultLogbackConfiguration(null));\n\t\tConsole console = mock(Console.class);\n\t\tgiven(console.charset()).willReturn(StandardCharsets.UTF_16);\n\t\tgiven(logbackConfiguration.getConsole()).willReturn(console);\n\t\tlogbackConfiguration.apply(this.logbackConfigurator);\n\t\tassertThat(this.loggerContext.getProperty(\"CONSOLE_LOG_CHARSET\")).isEqualTo(StandardCharsets.UTF_16.name());\n\t}\n\n\t@Test\n\tvoid consoleLogCharsetShouldDefaultToUtf8WhenConsoleIsNull() {\n\t\tDefaultLogbackConfiguration logbackConfiguration = spy(new DefaultLogbackConfiguration(null));\n\t\tgiven(logbackConfiguration.getConsole()).willReturn(null);\n\t\tlogbackConfiguration.apply(this.logbackConfigurator);\n\t\tassertThat(this.loggerContext.getProperty(\"CONSOLE_LOG_CHARSET\")).isEqualTo(StandardCharsets.UTF_8.name());\n\t}\n\n\t@Test\n\tvoid consoleLogCharsetShouldUseSystemPropertyIfSet() {\n\t\twithSystemProperty(\"CONSOLE_LOG_CHARSET\", StandardCharsets.US_ASCII.name(), () -> {\n\t\t\tnew DefaultLogbackConfiguration(null).apply(this.logbackConfigurator);\n\t\t\tassertThat(this.loggerContext.getProperty(\"CONSOLE_LOG_CHARSET\"))\n\t\t\t\t.isEqualTo(StandardCharsets.US_ASCII.name());\n\t\t});\n\t}\n\n\t@Test\n\tvoid fileLogCharsetShouldUseSystemPropertyIfSet() {\n\t\twithSystemProperty(\"FILE_LOG_CHARSET\", StandardCharsets.ISO_8859_1.name(), () -> {\n\t\t\tnew DefaultLogbackConfiguration(null).apply(this.logbackConfigurator);\n\t\t\tassertThat(this.loggerContext.getProperty(\"FILE_LOG_CHARSET\"))\n\t\t\t\t.isEqualTo(StandardCharsets.ISO_8859_1.name());\n\t\t});\n\t}\n\n\t@Test\n\tvoid fileLogCharsetShouldDefaultToUtf8() {\n\t\tnew DefaultLogbackConfiguration(null).apply(this.logbackConfigurator);\n\t\tassertThat(this.loggerContext.getProperty(\"FILE_LOG_CHARSET\")).isEqualTo(StandardCharsets.UTF_8.name());\n\t}\n\n\tprivate void assertThatDefaultXmlContains(String name, String value) throws Exception {\n\t\tString expected = \"<property name=\\\"%s\\\" value=\\\"%s\\\"/>\".formatted(name, value);\n\t\tassertThat(defaultXmlContent()).contains(expected);\n\t}\n\n\tprivate String defaultXmlContent() throws IOException {\n\t\treturn StreamUtils.copyToString(getClass().getResourceAsStream(\"defaults.xml\"), StandardCharsets.UTF_8);\n\t}\n\n\tprivate static void withSystemProperty(String name, String value, Runnable action) {\n\t\tString previous = System.getProperty(name);\n\t\ttry {\n\t\t\tSystem.setProperty(name, value);\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tif (previous != null) {\n\t\t\t\tSystem.setProperty(name, previous);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.clearProperty(name);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ElasticCommonSchemaStructuredLogFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Marker;\nimport org.slf4j.MarkerFactory;\n\nimport org.springframework.boot.logging.structured.TestContextPairs;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link ElasticCommonSchemaStructuredLogFormatter}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass ElasticCommonSchemaStructuredLogFormatterTests extends AbstractStructuredLoggingTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate ElasticCommonSchemaStructuredLogFormatter formatter;\n\n\t@Override\n\t@BeforeEach\n\tvoid setUp() {\n\t\tsuper.setUp();\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.name\", \"name\");\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.version\", \"1.0.0\");\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.environment\", \"test\");\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.node-name\", \"node-1\");\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"1\");\n\t\tthis.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, null,\n\t\t\t\tTestContextPairs.include(), getThrowableProxyConverter(), this.customizerBuilder);\n\t}\n\n\t@Test\n\tvoid callsNestedOnCustomizerBuilder() {\n\t\tassertThat(this.customizerBuilder.isNested()).isTrue();\n\t}\n\n\t@Test\n\tvoid callsCustomizer() {\n\t\tthen(this.customizer).should().customize(any());\n\t}\n\n\t@Test\n\tvoid shouldFormat() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"mdc-1\", \"mdc-v-1\"));\n\t\tevent.setKeyValuePairs(keyValuePairs(\"kv-1\", \"kv-v-1\"));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tMap<String, Object> expected = new HashMap<>();\n\t\texpected.put(\"@timestamp\", \"2024-07-02T08:49:53Z\");\n\t\texpected.put(\"message\", \"message\");\n\t\texpected.put(\"mdc-1\", \"mdc-v-1\");\n\t\texpected.put(\"kv-1\", \"kv-v-1\");\n\t\texpected.put(\"ecs\", Map.of(\"version\", \"8.11\"));\n\t\texpected.put(\"process\", map(\"pid\", 1, \"thread\", map(\"name\", \"main\")));\n\t\texpected.put(\"log\", map(\"level\", \"INFO\", \"logger\", \"org.example.Test\"));\n\t\texpected.put(\"service\",\n\t\t\t\tmap(\"name\", \"name\", \"version\", \"1.0.0\", \"environment\", \"test\", \"node\", map(\"name\", \"node-1\")));\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(expected);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldFormatException() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom\")));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tMap<String, Object> error = (Map<String, Object>) deserialized.get(\"error\");\n\t\tMap<String, Object> expectedError = new HashMap<>();\n\t\texpectedError.put(\"type\", \"java.lang.RuntimeException\");\n\t\texpectedError.put(\"message\", \"Boom\");\n\t\tassertThat(error).isNotNull();\n\t\tassertThat(error).containsAllEntriesOf(expectedError);\n\t\tString stackTrace = (String) error.get(\"stack_trace\");\n\t\tassertThat(stackTrace)\n\t\t\t.startsWith(String.format(\"java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.logback.\"\n\t\t\t\t\t+ \"ElasticCommonSchemaStructuredLogFormatterTests.shouldFormatException\"));\n\t\tassertThat(json).contains(String\n\t\t\t.format(\"java.lang.RuntimeException: Boom%n\\\\tat org.springframework.boot.logging.logback.\"\n\t\t\t\t\t+ \"ElasticCommonSchemaStructuredLogFormatterTests.shouldFormatException\")\n\t\t\t.replace(\"\\n\", \"\\\\n\")\n\t\t\t.replace(\"\\r\", \"\\\\r\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldFormatExceptionUsingStackTracePrinter() {\n\t\tthis.formatter = new ElasticCommonSchemaStructuredLogFormatter(this.environment, new SimpleStackTracePrinter(),\n\t\t\t\tTestContextPairs.include(), getThrowableProxyConverter(), this.customizerBuilder);\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom\")));\n\t\tMap<String, Object> deserialized = deserialize(this.formatter.format(event));\n\t\tMap<String, Object> error = (Map<String, Object>) deserialized.get(\"error\");\n\t\tassertThat(error).isNotNull();\n\t\tString stackTrace = (String) error.get(\"stack_trace\");\n\t\tassertThat(stackTrace).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldFormatMarkersAsTags() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tMarker parent = MarkerFactory.getDetachedMarker(\"parent\");\n\t\tparent.add(MarkerFactory.getDetachedMarker(\"child\"));\n\t\tMarker parent1 = MarkerFactory.getDetachedMarker(\"parent1\");\n\t\tparent1.add(MarkerFactory.getDetachedMarker(\"child1\"));\n\t\tMarker grandparent = MarkerFactory.getMarker(\"grandparent\");\n\t\tgrandparent.add(parent);\n\t\tgrandparent.add(parent1);\n\t\tevent.addMarker(grandparent);\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized.get(\"tags\")).isEqualTo(List.of(\"child\", \"child1\", \"grandparent\", \"parent\", \"parent1\"));\n\t}\n\n\t@Test\n\tvoid shouldNestMdcAndKeyValuePairs() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"a1.b1.c1\", \"A1B1C1\", \"a1.b1.c2\", \"A1B1C2\"));\n\t\tevent.setKeyValuePairs(keyValuePairs(\"a2.b1.c1\", \"A2B1C1\", \"a2.b1.c2\", \"A2B1C2\"));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized.get(\"a1\")).isEqualTo(Map.of(\"b1\", Map.of(\"c1\", \"A1B1C1\", \"c2\", \"A1B1C2\")));\n\t\tassertThat(deserialized.get(\"a2\")).isEqualTo(Map.of(\"b1\", Map.of(\"c1\", \"A2B1C1\", \"c2\", \"A2B1C2\")));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/EnclosedInSquareBracketsConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.LoggerContextVO;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EnclosedInSquareBracketsConverter}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass EnclosedInSquareBracketsConverterTests {\n\n\tprivate final EnclosedInSquareBracketsConverter converter;\n\n\tprivate final LoggingEvent event = new LoggingEvent();\n\n\tEnclosedInSquareBracketsConverterTests() {\n\t\tthis.converter = new EnclosedInSquareBracketsConverter();\n\t\tthis.converter.setContext(new LoggerContext());\n\t\tthis.event.setLoggerContextRemoteView(\n\t\t\t\tnew LoggerContextVO(\"test\", Collections.emptyMap(), System.currentTimeMillis()));\n\t}\n\n\t@Test\n\tvoid transformWhenNull() {\n\t\tassertThat(this.converter.transform(this.event, null)).isEqualTo(\"\");\n\t}\n\n\t@Test\n\tvoid transformWhenEmpty() {\n\t\tassertThat(this.converter.transform(this.event, \"\")).isEqualTo(\"\");\n\t}\n\n\t@Test\n\tvoid transformWhenName() {\n\t\tassertThat(this.converter.transform(this.event, \"My Application\")).isEqualTo(\"[My Application] \");\n\t}\n\n\t@Test\n\tvoid transformWhenEmptyFromFirstOption() {\n\t\twithLoggedApplicationName(\"spring\", null, () -> {\n\t\t\tthis.converter.setOptionList(List.of(\"spring\"));\n\t\t\tthis.converter.start();\n\t\t\tString converted = this.converter.convert(this.event);\n\t\t\tassertThat(converted).isEqualTo(\"\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid transformWhenNameFromFirstOption() {\n\t\twithLoggedApplicationName(\"spring\", \"boot\", () -> {\n\t\t\tthis.converter.setOptionList(List.of(\"spring\"));\n\t\t\tthis.converter.start();\n\t\t\tString converted = this.converter.convert(this.event);\n\t\t\tassertThat(converted).isEqualTo(\"[boot] \");\n\t\t});\n\t}\n\n\tprivate void withLoggedApplicationName(String name, @Nullable String value, Runnable action) {\n\t\tif (value == null) {\n\t\t\tSystem.clearProperty(name);\n\t\t}\n\t\telse {\n\t\t\tSystem.setProperty(name, value);\n\t\t}\n\t\ttry {\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(name);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ExtendedWhitespaceThrowableProxyConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ExtendedWhitespaceThrowableProxyConverter}.\n *\n * @author Phillip Webb\n * @author Chanwit Kaewkasi\n */\nclass ExtendedWhitespaceThrowableProxyConverterTests {\n\n\tprivate final ExtendedWhitespaceThrowableProxyConverter converter = new ExtendedWhitespaceThrowableProxyConverter();\n\n\tprivate final LoggingEvent event = new LoggingEvent();\n\n\t@Test\n\tvoid noStackTrace() {\n\t\tString s = this.converter.convert(this.event);\n\t\tassertThat(s).isEmpty();\n\t}\n\n\t@Test\n\tvoid withStackTrace() {\n\t\tthis.event.setThrowableProxy(new ThrowableProxy(new RuntimeException()));\n\t\tString s = this.converter.convert(this.event);\n\t\tassertThat(s).startsWith(System.lineSeparator()).endsWith(System.lineSeparator());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/ExtractorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Extractor}.\n *\n * @author Phillip Webb\n */\nclass ExtractorTests {\n\n\t@Test\n\tvoid messageAndStackTraceWhenNoPrinterPrintsUsingLoggingSystem() {\n\t\tExtractor extractor = new Extractor(null, createConverter());\n\t\tassertThat(extractor.messageAndStackTrace(createEvent())).startsWith(\"TestMessage\\n\\n\")\n\t\t\t.contains(\"java.lang.RuntimeException: Boom!\");\n\t}\n\n\t@Test\n\tvoid messageAndStackTraceWhenNoPrinterPrintsUsingPrinter() {\n\t\tExtractor extractor = new Extractor(new SimpleStackTracePrinter(), createConverter());\n\t\tassertThat(extractor.messageAndStackTrace(createEvent()))\n\t\t\t.isEqualTo(\"TestMessage\\n\\nstacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid stackTraceWhenNoPrinterPrintsUsingFallback() {\n\t\tExtractor extractor = new Extractor(null, createConverter());\n\t\tassertThat(extractor.stackTrace(createEvent())).contains(\"java.lang.RuntimeException: Boom!\");\n\t}\n\n\t@Test\n\tvoid stackTraceWhenNoPrinterPrintsUsingPrinter() {\n\t\tExtractor extractor = new Extractor(new SimpleStackTracePrinter(), createConverter());\n\t\tassertThat(extractor.stackTrace(createEvent())).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\tprivate ThrowableProxyConverter createConverter() {\n\t\tThrowableProxyConverter converter = new ThrowableProxyConverter();\n\t\tconverter.start();\n\t\treturn converter;\n\t}\n\n\tprivate ILoggingEvent createEvent() {\n\t\tLoggingEvent event = new LoggingEvent();\n\t\tevent.setMessage(\"TestMessage\");\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom!\")));\n\t\treturn event;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/GraylogExtendedLogFormatStructuredLogFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.structured.TestContextPairs;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link GraylogExtendedLogFormatStructuredLogFormatter}.\n *\n * @author Samuel Lissner\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass GraylogExtendedLogFormatStructuredLogFormatterTests extends AbstractStructuredLoggingTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate GraylogExtendedLogFormatStructuredLogFormatter formatter;\n\n\t@Override\n\t@BeforeEach\n\tvoid setUp() {\n\t\tsuper.setUp();\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"logging.structured.gelf.host\", \"name\");\n\t\tthis.environment.setProperty(\"logging.structured.gelf.service.version\", \"1.0.0\");\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"1\");\n\t\tthis.formatter = new GraylogExtendedLogFormatStructuredLogFormatter(this.environment, null,\n\t\t\t\tTestContextPairs.include(), getThrowableProxyConverter(), this.customizer);\n\t}\n\n\t@Test\n\tvoid callsCustomizer() {\n\t\tthen(this.customizer).should().customize(any());\n\t}\n\n\t@Test\n\tvoid shouldFormat() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"mdc-1\", \"mdc-v-1\"));\n\t\tevent.setKeyValuePairs(keyValuePairs(\"kv-1\", \"kv-v-1\"));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(\n\t\t\t\tmap(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\", 1719910193.0, \"level\", 6, \"_level_name\", \"INFO\",\n\t\t\t\t\t\t\"_process_pid\", 1, \"_process_thread_name\", \"main\", \"_service_version\", \"1.0.0\", \"_log_logger\",\n\t\t\t\t\t\t\"org.example.Test\", \"short_message\", \"message\", \"_mdc-1\", \"mdc-v-1\", \"_kv-1\", \"kv-v-1\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatMillisecondsInTimestamp() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setTimeStamp(1719910193123L);\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).contains(\"\\\"timestamp\\\":1719910193.123\");\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\",\n\t\t\t\t1719910193.123, \"level\", 6, \"_level_name\", \"INFO\", \"_process_pid\", 1, \"_process_thread_name\", \"main\",\n\t\t\t\t\"_service_version\", \"1.0.0\", \"_log_logger\", \"org.example.Test\", \"short_message\", \"message\"));\n\t}\n\n\t@Test\n\tvoid shouldNotAllowInvalidFieldNames(CapturedOutput output) {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"/\", \"value\"));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\",\n\t\t\t\t1719910193.0, \"level\", 6, \"_level_name\", \"INFO\", \"_process_pid\", 1, \"_process_thread_name\", \"main\",\n\t\t\t\t\"_service_version\", \"1.0.0\", \"_log_logger\", \"org.example.Test\", \"short_message\", \"message\"));\n\t\tassertThat(output).contains(\"'/' is not a valid field name according to GELF standard\");\n\t}\n\n\t@Test\n\tvoid shouldNotAllowIllegalFieldNames(CapturedOutput output) {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"id\", \"1\"));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\",\n\t\t\t\t1719910193.0, \"level\", 6, \"_level_name\", \"INFO\", \"_process_pid\", 1, \"_process_thread_name\", \"main\",\n\t\t\t\t\"_service_version\", \"1.0.0\", \"_log_logger\", \"org.example.Test\", \"short_message\", \"message\"));\n\t\tassertThat(output).contains(\"'id' is an illegal field name according to GELF standard\");\n\t}\n\n\t@Test\n\tvoid shouldNotAddDoubleUnderscoreToCustomFields() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"_custom\", \"value\"));\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(\n\t\t\t\tmap(\"version\", \"1.1\", \"host\", \"name\", \"timestamp\", 1719910193.0, \"level\", 6, \"_level_name\", \"INFO\",\n\t\t\t\t\t\t\"_process_pid\", 1, \"_process_thread_name\", \"main\", \"_service_version\", \"1.0.0\", \"_log_logger\",\n\t\t\t\t\t\t\"org.example.Test\", \"short_message\", \"message\", \"_custom\", \"value\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatException() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom\")));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString fullMessage = (String) deserialized.get(\"full_message\");\n\t\tString stackTrace = (String) deserialized.get(\"_error_stack_trace\");\n\t\tassertThat(fullMessage).startsWith(\n\t\t\t\t\"message\\n\\njava.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.logback.GraylogExtendedLogFormatStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted());\n\t\tassertThat(deserialized)\n\t\t\t.containsAllEntriesOf(map(\"_error_type\", \"java.lang.RuntimeException\", \"_error_message\", \"Boom\"));\n\t\tassertThat(stackTrace).startsWith(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.logback.GraylogExtendedLogFormatStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted());\n\t\tassertThat(json).contains(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\\\tat org.springframework.boot.logging.logback.GraylogExtendedLogFormatStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted()\n\t\t\t\t\t.replace(\"\\n\", \"\\\\n\")\n\t\t\t\t\t.replace(\"\\r\", \"\\\\r\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatExceptionUsingStackTracePrinter() {\n\t\tthis.formatter = new GraylogExtendedLogFormatStructuredLogFormatter(this.environment,\n\t\t\t\tnew SimpleStackTracePrinter(), TestContextPairs.include(), getThrowableProxyConverter(),\n\t\t\t\tthis.customizer);\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom\")));\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString fullMessage = (String) deserialized.get(\"full_message\");\n\t\tString stackTrace = (String) deserialized.get(\"_error_stack_trace\");\n\t\tassertThat(fullMessage).isEqualTo(\"message\\n\\nstacktrace:RuntimeException\");\n\t\tassertThat(deserialized)\n\t\t\t.containsAllEntriesOf(map(\"_error_type\", \"java.lang.RuntimeException\", \"_error_message\", \"Boom\"));\n\t\tassertThat(stackTrace).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationAotContributionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.encoder.PatternLayoutEncoder;\nimport ch.qos.logback.classic.model.RootLoggerModel;\nimport ch.qos.logback.core.CoreConstants;\nimport ch.qos.logback.core.FileAppender;\nimport ch.qos.logback.core.Layout;\nimport ch.qos.logback.core.joran.spi.DefaultClass;\nimport ch.qos.logback.core.model.ComponentModel;\nimport ch.qos.logback.core.model.ImplicitModel;\nimport ch.qos.logback.core.model.ImportModel;\nimport ch.qos.logback.core.model.Model;\nimport ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;\nimport ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicy;\nimport ch.qos.logback.core.util.FileSize;\nimport org.assertj.core.api.Condition;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.aot.generate.GeneratedFiles.Kind;\nimport org.springframework.aot.generate.InMemoryGeneratedFiles;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.logback.SpringBootJoranConfigurator.LogbackConfigurationAotContribution;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.core.io.InputStreamSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LogbackConfigurationAotContribution}.\n *\n * @author Andy Wilkinson\n */\nclass LogbackConfigurationAotContributionTests {\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid prepare() {\n\t\tLoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();\n\t\tcontext.reset();\n\t}\n\n\t@Test\n\tvoid contributionOfBasicModel() {\n\t\tTestGenerationContext generationContext = applyContribution(new Model());\n\t\tInMemoryGeneratedFiles generatedFiles = generationContext.getGeneratedFiles();\n\t\tassertThat(generatedFiles).has(resource(\"META-INF/spring/logback-model\"));\n\t\tassertThat(generatedFiles).has(resource(\"META-INF/spring/logback-pattern-rules\"));\n\t\tReflectionHints reflectionHints = generationContext.getRuntimeHints().reflection();\n\t\tassertThat(reflectionHints.typeHints().map(TypeHint::getType)).containsExactlyInAnyOrderElementsOf(\n\t\t\t\tTypeReference.listOf(Model.class, ArrayList.class, Boolean.class, Integer.class));\n\t\tassertThat(reflectionHints.typeHints().map(TypeHint::hasJavaSerialization).distinct()).singleElement()\n\t\t\t.isEqualTo(true);\n\t\tInputStreamSource generatedFile = generatedFiles.getGeneratedFile(Kind.RESOURCE,\n\t\t\t\t\"META-INF/spring/logback-pattern-rules\");\n\t\tassertThat(generatedFile).isNotNull();\n\t\tProperties patternRules = load(generatedFile);\n\t\tassertThat(patternRules).isEmpty();\n\t}\n\n\t@Test\n\tvoid contributionOfBasicModelThatMatchesExistingModel() {\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tModel model = new Model();\n\t\tapplyContribution(model, generationContext);\n\t\tapplyContribution(model, generationContext);\n\t\tInMemoryGeneratedFiles generatedFiles = generationContext.getGeneratedFiles();\n\t\tassertThat(generatedFiles).has(resource(\"META-INF/spring/logback-model\"));\n\t\tassertThat(generatedFiles).has(resource(\"META-INF/spring/logback-pattern-rules\"));\n\t\tReflectionHints reflectionHints = generationContext.getRuntimeHints().reflection();\n\t\tassertThat(reflectionHints.typeHints().map(TypeHint::getType)).containsExactlyInAnyOrderElementsOf(\n\t\t\t\tTypeReference.listOf(Model.class, ArrayList.class, Boolean.class, Integer.class));\n\t\tassertThat(reflectionHints.typeHints().map(TypeHint::hasJavaSerialization).distinct()).singleElement()\n\t\t\t.isEqualTo(true);\n\t\tInputStreamSource generatedFile = generatedFiles.getGeneratedFile(Kind.RESOURCE,\n\t\t\t\t\"META-INF/spring/logback-pattern-rules\");\n\t\tassertThat(generatedFile).isNotNull();\n\t\tProperties patternRules = load(generatedFile);\n\t\tassertThat(patternRules).isEmpty();\n\t}\n\n\t@Test\n\tvoid contributionOfBasicModelThatDiffersFromExistingModelThrows() {\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tapplyContribution(new Model(), generationContext);\n\t\tModel model = new Model();\n\t\tmodel.addSubModel(new RootLoggerModel());\n\t\tassertThatIllegalStateException().isThrownBy(() -> applyContribution(model, generationContext))\n\t\t\t.withMessage(\"Logging configuration differs from the configuration that has already been written. \"\n\t\t\t\t\t+ \"Update your logging configuration so that it is the same for each context\");\n\t}\n\n\t@Test\n\tvoid patternRulesAreStoredAndRegisteredForReflection() {\n\t\tLoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();\n\t\tcontext.putObject(CoreConstants.PATTERN_RULE_REGISTRY,\n\t\t\t\tMap.of(\"a\", \"com.example.Alpha\", \"b\", \"com.example.Bravo\"));\n\t\tTestGenerationContext generationContext = applyContribution(new Model());\n\t\tassertThat(invokePublicConstructorsOf(\"com.example.Alpha\")).accepts(generationContext.getRuntimeHints());\n\t\tassertThat(invokePublicConstructorsOf(\"com.example.Bravo\")).accepts(generationContext.getRuntimeHints());\n\t\tInputStreamSource generatedFile = generationContext.getGeneratedFiles()\n\t\t\t.getGeneratedFile(Kind.RESOURCE, \"META-INF/spring/logback-pattern-rules\");\n\t\tassertThat(generatedFile).isNotNull();\n\t\tProperties patternRules = load(generatedFile);\n\t\tassertThat(patternRules).hasSize(2);\n\t\tassertThat(patternRules).containsEntry(\"a\", \"com.example.Alpha\");\n\t\tassertThat(patternRules).containsEntry(\"b\", \"com.example.Bravo\");\n\t}\n\n\t@Test\n\tvoid componentModelClassAndSetterParametersAreRegisteredForReflection() {\n\t\tComponentModel component = new ComponentModel();\n\t\tcomponent.setClassName(SizeAndTimeBasedRollingPolicy.class.getName());\n\t\tModel model = new Model();\n\t\tmodel.getSubModels().add(component);\n\t\tTestGenerationContext generationContext = applyContribution(model);\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(SizeAndTimeBasedRollingPolicy.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(FileAppender.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(FileSize.class)).accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(\n\t\t\t\tTimeBasedFileNamingAndTriggeringPolicy.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(SizeAndTimeBasedRollingPolicy.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(FileSize.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(FileAppender.class));\n\t}\n\n\t@Test\n\tvoid implicitModelClassAndSetterParametersAreRegisteredForReflection() {\n\t\tImplicitModel implicit = new ImplicitModel();\n\t\timplicit.setTag(\"encoder\");\n\t\tModel model = new Model();\n\t\tmodel.getSubModels().add(implicit);\n\t\tTestGenerationContext generationContext = applyContribution(model);\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(PatternLayoutEncoder.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Layout.class)).accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Charset.class)).accepts(runtimeHints);\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(PatternLayoutEncoder.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Layout.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Charset.class));\n\t}\n\n\t@Test\n\tvoid componentModelReferencingImportedClassNameIsRegisteredForReflection() {\n\t\tImportModel importModel = new ImportModel();\n\t\timportModel.setClassName(SizeAndTimeBasedRollingPolicy.class.getName());\n\t\tComponentModel component = new ComponentModel();\n\t\tcomponent.setClassName(SizeAndTimeBasedRollingPolicy.class.getSimpleName());\n\t\tModel model = new Model();\n\t\tmodel.getSubModels().addAll(List.of(importModel, component));\n\t\tTestGenerationContext generationContext = applyContribution(model);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(SizeAndTimeBasedRollingPolicy.class))\n\t\t\t.accepts(generationContext.getRuntimeHints());\n\t\tassertThat(generationContext.getRuntimeHints())\n\t\t\t.satisfies(hasValidTypeName(SizeAndTimeBasedRollingPolicy.class));\n\t}\n\n\t@Test\n\tvoid typeFromParentsSetterIsRegisteredForReflection() {\n\t\tImplicitModel implementation = new ImplicitModel();\n\t\timplementation.setTag(\"implementation\");\n\t\tComponentModel component = new ComponentModel();\n\t\tcomponent.setClassName(Outer.class.getName());\n\t\tcomponent.getSubModels().add(implementation);\n\t\tTestGenerationContext generationContext = applyContribution(component);\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Outer.class)).accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Outer.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Implementation.class));\n\t}\n\n\t@Test\n\tvoid typeFromParentsDefaultClassAnnotatedSetterIsRegisteredForReflection() {\n\t\tImplicitModel contract = new ImplicitModel();\n\t\tcontract.setTag(\"contract\");\n\t\tComponentModel component = new ComponentModel();\n\t\tcomponent.setClassName(OuterWithDefaultClass.class.getName());\n\t\tcomponent.getSubModels().add(contract);\n\t\tTestGenerationContext generationContext = applyContribution(component);\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(OuterWithDefaultClass.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(BaseImplementation.Details.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(OuterWithDefaultClass.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Implementation.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(BaseImplementation.Details.class));\n\t}\n\n\t@Test\n\tvoid componentTypesOfArraysAreRegisteredForReflection() {\n\t\tComponentModel component = new ComponentModel();\n\t\tcomponent.setClassName(ArrayParameters.class.getName());\n\t\tTestGenerationContext generationContext = applyContribution(component);\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(InetSocketAddress.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(InetSocketAddress.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(ArrayParameters.class));\n\t}\n\n\t@Test\n\tvoid placeholdersInComponentClassAttributeAreReplaced() {\n\t\tComponentModel component = new ComponentModel();\n\t\tcomponent.setClassName(\"${VARIABLE_CLASS_NAME}\");\n\t\tTestGenerationContext generationContext = applyContribution(component,\n\t\t\t\t(context) -> context.putProperty(\"VARIABLE_CLASS_NAME\", Outer.class.getName()));\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Outer.class)).accepts(runtimeHints);\n\t\tassertThat(invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Implementation.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Outer.class));\n\t\tassertThat(runtimeHints).satisfies(hasValidTypeName(Implementation.class));\n\t}\n\n\tprivate Predicate<RuntimeHints> invokePublicConstructorsOf(String name) {\n\t\treturn RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference.of(name))\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t}\n\n\tprivate Predicate<RuntimeHints> invokePublicConstructorsAndInspectAndInvokePublicMethodsOf(Class<?> type) {\n\t\treturn RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference.of(type))\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS, MemberCategory.INVOKE_PUBLIC_METHODS);\n\t}\n\n\tprivate Consumer<RuntimeHints> hasValidTypeName(Class<?> type) {\n\t\treturn (runtimeHints) -> assertThat(runtimeHints.reflection().getTypeHint(type)).extracting(TypeHint::getType)\n\t\t\t.extracting(TypeReference::getName)\n\t\t\t.isEqualTo(type.getName());\n\t}\n\n\tprivate Properties load(InputStreamSource source) {\n\t\ttry (InputStream inputStream = source.getInputStream()) {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.load(inputStream);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate Condition<InMemoryGeneratedFiles> resource(String name) {\n\t\treturn new Condition<>((files) -> files.getGeneratedFile(Kind.RESOURCE, name) != null,\n\t\t\t\t\"has a resource named '%s'\", name);\n\t}\n\n\tprivate TestGenerationContext applyContribution(Model model) {\n\t\treturn this.applyContribution(model, (context) -> {\n\t\t});\n\t}\n\n\tprivate TestGenerationContext applyContribution(Model model, Consumer<LoggerContext> contextCustomizer) {\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tapplyContribution(model, contextCustomizer, generationContext);\n\t\treturn generationContext;\n\t}\n\n\tprivate void applyContribution(Model model, TestGenerationContext generationContext) {\n\t\tapplyContribution(model, (context) -> {\n\t\t}, generationContext);\n\t}\n\n\tprivate void applyContribution(Model model, Consumer<LoggerContext> contextCustomizer,\n\t\t\tTestGenerationContext generationContext) {\n\t\tLoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();\n\t\tcontextCustomizer.accept(context);\n\t\tSpringBootJoranConfigurator configurator = new SpringBootJoranConfigurator(\n\t\t\t\tnew LoggingInitializationContext(null));\n\t\tconfigurator.setContext(context);\n\t\twithSystemProperty(AbstractAotProcessor.AOT_PROCESSING, \"true\", () -> configurator.processModel(model));\n\t\tLogbackConfigurationAotContribution contribution = (LogbackConfigurationAotContribution) context\n\t\t\t.getObject(BeanFactoryInitializationAotContribution.class.getName());\n\t\tcontribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));\n\t}\n\n\tprivate void withSystemProperty(String name, String value, Runnable action) {\n\t\tSystem.setProperty(name, value);\n\t\ttry {\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(name);\n\t\t}\n\t}\n\n\tpublic static class Outer {\n\n\t\tpublic void setImplementation(Implementation implementation) {\n\t\t}\n\n\t}\n\n\tpublic static class OuterWithDefaultClass {\n\n\t\t@DefaultClass(Implementation.class)\n\t\tpublic void setContract(Contract contract) {\n\t\t}\n\n\t}\n\n\tpublic static class BaseImplementation implements Contract {\n\n\t\tpublic void setDetails(Details details) {\n\t\t}\n\n\t\tpublic static final class Details {\n\n\t\t}\n\n\t}\n\n\tpublic static class Implementation extends BaseImplementation {\n\n\t}\n\n\tpublic interface Contract {\n\n\t}\n\n\tpublic static class ArrayParameters {\n\n\t\tpublic void addDestinations(InetSocketAddress... addresses) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.File;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.encoder.PatternLayoutEncoder;\nimport ch.qos.logback.classic.joran.JoranConfigurator;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.core.Appender;\nimport ch.qos.logback.core.ConsoleAppender;\nimport ch.qos.logback.core.FileAppender;\nimport ch.qos.logback.core.encoder.Encoder;\nimport ch.qos.logback.core.joran.spi.JoranException;\nimport ch.qos.logback.core.rolling.RollingFileAppender;\nimport ch.qos.logback.core.rolling.RollingPolicy;\nimport ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.ResourcesRoot;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for default Logback configuration provided by {@code base.xml}.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n */\nclass LogbackConfigurationTests {\n\n\t@Test\n\t@WithResource(name = \"custom-console-log-pattern.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<property name=\"CONSOLE_LOG_PATTERN\" value=\"foo\" />\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\" />\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid consolePatternCanBeOverridden(@ResourcesRoot File resourcesRoot) throws JoranException {\n\t\tJoranConfigurator configurator = new JoranConfigurator();\n\t\tLoggerContext context = new LoggerContext();\n\t\tconfigurator.setContext(context);\n\t\tconfigurator.doConfigure(new File(resourcesRoot, \"custom-console-log-pattern.xml\"));\n\t\tAppender<ILoggingEvent> appender = context.getLogger(\"ROOT\").getAppender(\"CONSOLE\");\n\t\tassertThat(appender).isInstanceOf(ConsoleAppender.class);\n\t\tEncoder<?> encoder = ((ConsoleAppender<?>) appender).getEncoder();\n\t\tassertThat(encoder).isInstanceOf(PatternLayoutEncoder.class);\n\t\tassertThat(((PatternLayoutEncoder) encoder).getPattern()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-file-log-pattern.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<property name=\"FILE_LOG_PATTERN\" value=\"bar\" />\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\" />\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid filePatternCanBeOverridden(@ResourcesRoot File resourcesRoot) throws JoranException {\n\t\tJoranConfigurator configurator = new JoranConfigurator();\n\t\tLoggerContext context = new LoggerContext();\n\t\tconfigurator.setContext(context);\n\t\tconfigurator.doConfigure(new File(resourcesRoot, \"custom-file-log-pattern.xml\"));\n\t\tAppender<ILoggingEvent> appender = context.getLogger(\"ROOT\").getAppender(\"FILE\");\n\t\tassertThat(appender).isInstanceOf(FileAppender.class);\n\t\tEncoder<?> encoder = ((FileAppender<?>) appender).getEncoder();\n\t\tassertThat(encoder).isInstanceOf(PatternLayoutEncoder.class);\n\t\tassertThat(((PatternLayoutEncoder) encoder).getPattern()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-file-log-pattern.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<property name=\"FILE_LOG_PATTERN\" value=\"bar\" />\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\" />\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid defaultRollingFileNamePattern(@ResourcesRoot File resourcesRoot) throws JoranException {\n\t\tJoranConfigurator configurator = new JoranConfigurator();\n\t\tLoggerContext context = new LoggerContext();\n\t\tconfigurator.setContext(context);\n\t\tconfigurator.doConfigure(new File(resourcesRoot, \"custom-file-log-pattern.xml\"));\n\t\tAppender<ILoggingEvent> appender = context.getLogger(\"ROOT\").getAppender(\"FILE\");\n\t\tassertThat(appender).isInstanceOf(RollingFileAppender.class);\n\t\tRollingPolicy rollingPolicy = ((RollingFileAppender<?>) appender).getRollingPolicy();\n\t\tString fileNamePattern = ((SizeAndTimeBasedRollingPolicy<?>) rollingPolicy).getFileNamePattern();\n\t\tassertThat(fileNamePattern).endsWith(\"spring.log.%d{yyyy-MM-dd}.%i.gz\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-file-log-pattern-with-fileNamePattern.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<property name=\"LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN\" value=\"my.log.%d{yyyyMMdd}.%i.gz\"/>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\" />\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid customRollingFileNamePattern(@ResourcesRoot File resourcesRoot) throws JoranException {\n\t\tJoranConfigurator configurator = new JoranConfigurator();\n\t\tLoggerContext context = new LoggerContext();\n\t\tconfigurator.setContext(context);\n\t\tconfigurator.doConfigure(new File(resourcesRoot, \"custom-file-log-pattern-with-fileNamePattern.xml\"));\n\t\tAppender<ILoggingEvent> appender = context.getLogger(\"ROOT\").getAppender(\"FILE\");\n\t\tassertThat(appender).isInstanceOf(RollingFileAppender.class);\n\t\tRollingPolicy rollingPolicy = ((RollingFileAppender<?>) appender).getRollingPolicy();\n\t\tString fileNamePattern = ((SizeAndTimeBasedRollingPolicy<?>) rollingPolicy).getFileNamePattern();\n\t\tassertThat(fileNamePattern).endsWith(\"my.log.%d{yyyyMMdd}.%i.gz\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemParallelInitializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for parallel initialization of {@link LogbackLoggingSystem} that are separate\n * from {@link LogbackLoggingSystemTests}. This isolation allows them to have complete\n * control over how and when the logging system is initialized.\n *\n * @author Andy Wilkinson\n */\nclass LogbackLoggingSystemParallelInitializationTests {\n\n\tprivate final LoggingSystem loggingSystem = LoggingSystem.get(getClass().getClassLoader());\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tthis.loggingSystem.cleanUp();\n\t\t((LoggerContext) LoggerFactory.getILoggerFactory()).stop();\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\tvoid noExceptionsAreThrownWhenBeforeInitializeIsCalledInParallel() {\n\t\tList<Thread> threads = new ArrayList<>();\n\t\tList<Throwable> exceptions = new CopyOnWriteArrayList<>();\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tThread thread = new Thread(this.loggingSystem::beforeInitialize);\n\t\t\tthread.setUncaughtExceptionHandler((t, ex) -> exceptions.add(ex));\n\t\t\tthreads.add(thread);\n\t\t}\n\t\tthreads.forEach(Thread::start);\n\t\tthreads.forEach(this::join);\n\t\tassertThat(exceptions).isEmpty();\n\t}\n\n\tprivate void join(Thread thread) {\n\t\ttry {\n\t\t\tthread.join();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.Console;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link LogbackLoggingSystemProperties}.\n *\n * @author Phillip Webb\n */\nclass LogbackLoggingSystemPropertiesTests {\n\n\tprivate Set<Object> systemPropertyNames;\n\n\tprivate MockEnvironment environment;\n\n\t@BeforeEach\n\tvoid captureSystemPropertyNames() {\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t\tthis.systemPropertyNames = new HashSet<>(System.getProperties().keySet());\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment\n\t\t\t.setConversionService((ConfigurableConversionService) ApplicationConversionService.getSharedInstance());\n\n\t}\n\n\t@AfterEach\n\tvoid restoreSystemProperties() {\n\t\tSystem.getProperties().keySet().retainAll(this.systemPropertyNames);\n\t}\n\n\t@Test\n\tvoid applySetsStandardSystemProperties() {\n\t\tthis.environment.setProperty(\"logging.pattern.console\", \"boot\");\n\t\tnew LogbackLoggingSystemProperties(this.environment).apply();\n\t\tassertThat(System.getProperties())\n\t\t\t.containsEntry(LoggingSystemProperty.CONSOLE_PATTERN.getEnvironmentVariableName(), \"boot\");\n\t}\n\n\t@Test\n\tvoid applySetsLogbackSystemProperties() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.file-name-pattern\", \"fnp\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.clean-history-on-start\", \"chos\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-file-size\", \"1KB\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.total-size-cap\", \"2KB\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-history\", \"mh\");\n\t\tnew LogbackLoggingSystemProperties(this.environment).apply();\n\t\tassertThat(System.getProperties())\n\t\t\t.containsEntry(RollingPolicySystemProperty.FILE_NAME_PATTERN.getEnvironmentVariableName(), \"fnp\")\n\t\t\t.containsEntry(RollingPolicySystemProperty.CLEAN_HISTORY_ON_START.getEnvironmentVariableName(), \"chos\")\n\t\t\t.containsEntry(RollingPolicySystemProperty.MAX_FILE_SIZE.getEnvironmentVariableName(), \"1024\")\n\t\t\t.containsEntry(RollingPolicySystemProperty.TOTAL_SIZE_CAP.getEnvironmentVariableName(), \"2048\")\n\t\t\t.containsEntry(RollingPolicySystemProperty.MAX_HISTORY.getEnvironmentVariableName(), \"mh\");\n\t}\n\n\t@Test\n\tvoid consoleCharsetWhenNoPropertyUsesDefault() {\n\t\tLogbackLoggingSystemProperties logbackLoggingSystemProperties = spy(\n\t\t\t\tnew LogbackLoggingSystemProperties(new MockEnvironment(), null, null));\n\t\tgiven(logbackLoggingSystemProperties.getConsole()).willReturn(null);\n\n\t\tlogbackLoggingSystemProperties.apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CONSOLE_CHARSET.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(Charset.defaultCharset().name());\n\t}\n\n\t@Test\n\tvoid consoleCharsetWhenNoPropertyUsesSystemConsoleCharsetWhenAvailable() {\n\t\tLogbackLoggingSystemProperties logbackLoggingSystemProperties = spy(\n\t\t\t\tnew LogbackLoggingSystemProperties(new MockEnvironment(), null, null));\n\n\t\tConsole console = mock(Console.class);\n\t\tgiven(console.charset()).willReturn(StandardCharsets.UTF_16BE);\n\t\tgiven(logbackLoggingSystemProperties.getConsole()).willReturn(console);\n\n\t\tlogbackLoggingSystemProperties.apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.CONSOLE_CHARSET.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(StandardCharsets.UTF_16BE.name());\n\t}\n\n\t@Test\n\tvoid fileCharsetWhenNoPropertyUsesUtf8() {\n\t\tnew LoggingSystemProperties(new MockEnvironment()).apply(null);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.FILE_CHARSET.getEnvironmentVariableName()))\n\t\t\t.isEqualTo(StandardCharsets.UTF_8.name());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackLoggingSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.Console;\nimport java.io.File;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.logging.Handler;\nimport java.util.logging.LogManager;\nimport java.util.stream.Stream;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.LoggerContextListener;\nimport ch.qos.logback.core.AppenderBase;\nimport ch.qos.logback.core.ConsoleAppender;\nimport ch.qos.logback.core.encoder.LayoutWrappingEncoder;\nimport ch.qos.logback.core.joran.spi.JoranException;\nimport ch.qos.logback.core.rolling.RollingFileAppender;\nimport ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy;\nimport ch.qos.logback.core.status.ErrorStatus;\nimport ch.qos.logback.core.status.InfoStatus;\nimport ch.qos.logback.core.status.OnConsoleStatusListener;\nimport ch.qos.logback.core.status.StatusManager;\nimport ch.qos.logback.core.status.WarnStatus;\nimport ch.qos.logback.core.util.DynamicClassLoadingException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.slf4j.ILoggerFactory;\nimport org.slf4j.LoggerFactory;\nimport org.slf4j.MDC;\nimport org.slf4j.bridge.SLF4JBridgeHandler;\n\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.logging.AbstractLoggingSystemTests;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperties;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link LogbackLoggingSystem}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Ben Hale\n * @author Madhura Bhave\n * @author Vedran Pavic\n * @author Robert Thornton\n * @author Eddú Meléndez\n * @author Scott Frederick\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathExclusions({ \"log4j-core-*.jar\", \"log4j-api-*.jar\" })\nclass LogbackLoggingSystemTests extends AbstractLoggingSystemTests {\n\n\tprivate final LogbackLoggingSystem loggingSystem = new LogbackLoggingSystem(getClass().getClassLoader());\n\n\tprivate Logger logger;\n\n\tprivate MockEnvironment environment;\n\n\tprivate LoggingInitializationContext initializationContext;\n\n\tprivate Set<Object> systemPropertyNames;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t\tthis.systemPropertyNames = new HashSet<>(System.getProperties().keySet());\n\t\tthis.loggingSystem.cleanUp();\n\t\tthis.logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger(getClass());\n\t\tthis.environment = new MockEnvironment();\n\t\tConversionService conversionService = ApplicationConversionService.getSharedInstance();\n\t\tthis.environment.setConversionService((ConfigurableConversionService) conversionService);\n\t\tthis.initializationContext = new LoggingInitializationContext(this.environment);\n\t\tthis.loggingSystem.setStatusPrinterStream(System.out);\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tSystem.getProperties().keySet().retainAll(this.systemPropertyNames);\n\t\tthis.loggingSystem.cleanUp();\n\t\t((LoggerContext) LoggerFactory.getILoggerFactory()).stop();\n\t}\n\n\t@Test\n\t@WithIncludeDefaultsXmlResource\n\tvoid logbackDefaultsConfigurationDoesNotTriggerDeprecation(CapturedOutput output) {\n\t\tinitialize(this.initializationContext, \"classpath:include-defaults.xml\", null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).isEqualTo(\"[INFO] - Hello world\");\n\t\tassertThat(output.toString()).doesNotContain(\"WARN\").doesNotContain(\"deprecated\");\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid logbackBaseConfigurationDoesNotTriggerDeprecation(CapturedOutput output) {\n\t\tinitialize(this.initializationContext, \"classpath:include-base.xml\", null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\" INFO \").endsWith(\": Hello world\");\n\t\tassertThat(output.toString()).doesNotContain(\"WARN\").doesNotContain(\"deprecated\");\n\t}\n\n\t@Test\n\t@ClassPathOverrides({ \"org.jboss.logging:jboss-logging:3.5.0.Final\", \"org.apache.logging.log4j:log4j-core:2.19.0\" })\n\tvoid jbossLoggingRoutesThroughLog4j2ByDefault() {\n\t\tSystem.getProperties().remove(\"org.jboss.logging.provider\");\n\t\torg.jboss.logging.Logger jbossLogger = org.jboss.logging.Logger.getLogger(getClass());\n\t\tassertThat(jbossLogger.getClass().getName()).isEqualTo(\"org.jboss.logging.Log4j2Logger\");\n\t}\n\n\t@Test\n\t@ClassPathOverrides(\"org.jboss.logging:jboss-logging:3.5.0.Final\")\n\tvoid jbossLoggingRoutesThroughSlf4jWhenLoggingSystemIsInitialized() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tassertThat(org.jboss.logging.Logger.getLogger(getClass()).getClass().getName())\n\t\t\t.isEqualTo(\"org.jboss.logging.Slf4jLocationAwareLogger\");\n\t}\n\n\t@Test\n\tvoid noFile(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\").doesNotContain(\"Hidden\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(new File(tmpDir() + \"/spring.log\")).doesNotExist();\n\t}\n\n\t@Test\n\tvoid withFile(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tinitialize(this.initializationContext, null, getLogFile(null, tmpDir()));\n\t\tthis.logger.info(\"Hello world\");\n\t\tFile file = new File(tmpDir() + \"/spring.log\");\n\t\tassertThat(output).doesNotContain(\"LOGBACK:\");\n\t\tassertThat(output).contains(\"Hello world\").doesNotContain(\"Hidden\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(file).exists();\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(ReflectionTestUtils.getField(getRollingPolicy(), \"maxFileSize\")).hasToString(\"10 MB\");\n\t\tassertThat(getRollingPolicy().getMaxHistory()).isEqualTo(7);\n\t}\n\n\t@Test\n\tvoid defaultConfigConfiguresAConsoleAppender() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tassertThat(getConsoleAppender()).isNotNull();\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid testNonDefaultConfigLocation(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, \"classpath:nondefault.xml\", getLogFile(tmpDir() + \"/tmp.log\", null));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).doesNotContain(\"DEBUG\")\n\t\t\t.contains(\"Hello world\")\n\t\t\t.contains(tmpDir() + \"/tmp.log\")\n\t\t\t.endsWith(\"BOOTBOOT\");\n\t\tassertThat(new File(tmpDir() + \"/tmp.log\")).doesNotExist();\n\t}\n\n\t@Test\n\tvoid testLogbackSpecificSystemProperty(CapturedOutput output) {\n\t\tSystem.setProperty(\"logback.configurationFile\", \"/foo/my-file.xml\");\n\t\ttry {\n\t\t\tthis.loggingSystem.beforeInitialize();\n\t\t\tinitialize(this.initializationContext, null, null);\n\t\t\tassertThat(output)\n\t\t\t\t.contains(\"Ignoring 'logback.configurationFile' system property. Please use 'logging.config' instead.\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"logback.configurationFile\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid testNonexistentConfigLocation() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> initialize(this.initializationContext, \"classpath:logback-nonexistent.xml\", null));\n\t}\n\n\t@Test\n\tvoid getSupportedLevels() {\n\t\tassertThat(this.loggingSystem.getSupportedLogLevels()).isEqualTo(\n\t\t\t\tEnumSet.of(LogLevel.TRACE, LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR, LogLevel.OFF));\n\t}\n\n\t@Test\n\tvoid setLevel(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", LogLevel.DEBUG);\n\t\tthis.logger.debug(\"Hello\");\n\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Hello\")).isOne();\n\t}\n\n\t@Test\n\tvoid setLevelToNull(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", LogLevel.DEBUG);\n\t\tthis.logger.debug(\"Hello\");\n\t\tthis.loggingSystem.setLogLevel(\"org.springframework.boot\", null);\n\t\tthis.logger.debug(\"Hello\");\n\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Hello\")).isOne();\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurations() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tList<LoggerConfiguration> configurations = this.loggingSystem.getLoggerConfigurations();\n\t\tassertThat(configurations).isNotEmpty();\n\t\tassertThat(configurations.get(0).getName()).isEqualTo(LoggingSystem.ROOT_LOGGER_NAME);\n\t}\n\n\t@Test\n\tvoid getLoggerConfiguration() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(getClass().getName());\n\t\tassertThat(configuration)\n\t\t\t.isEqualTo(new LoggerConfiguration(getClass().getName(), LogLevel.DEBUG, LogLevel.DEBUG));\n\t}\n\n\t@Test\n\tvoid getLoggerConfigurationForLoggerThatDoesNotExistShouldReturnNull() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(\"doesnotexist\");\n\t\tassertThat(configuration).isNull();\n\t}\n\n\t@Test\n\tvoid systemLevelTraceShouldReturnNativeLevelTraceNotAll() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.TRACE);\n\t\tLogger logger = (Logger) LoggerFactory.getILoggerFactory().getLogger(getClass().getName());\n\t\tassertThat(logger.getLevel()).isEqualTo(Level.TRACE);\n\t}\n\n\t@Test\n\tvoid loggingThatUsesJulIsCaptured(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tjava.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(getClass().getName());\n\t\tjulLogger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\");\n\t}\n\n\t@Test\n\tvoid loggingLevelIsPropagatedToJul(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.setLogLevel(getClass().getName(), LogLevel.DEBUG);\n\t\tjava.util.logging.Logger julLogger = java.util.logging.Logger.getLogger(getClass().getName());\n\t\tjulLogger.fine(\"Hello debug world\");\n\t\tassertThat(output).contains(\"Hello debug world\");\n\t}\n\n\t@Test\n\tvoid bridgeHandlerLifecycle() {\n\t\tassertThat(bridgeHandlerInstalled()).isFalse();\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThat(bridgeHandlerInstalled()).isTrue();\n\t\tthis.loggingSystem.cleanUp();\n\t\tassertThat(bridgeHandlerInstalled()).isFalse();\n\t}\n\n\t@Test\n\tvoid standardConfigLocations() {\n\t\tString[] locations = this.loggingSystem.getStandardConfigLocations();\n\t\tassertThat(locations).containsExactly(\"logback-test.groovy\", \"logback-test.xml\", \"logback.groovy\",\n\t\t\t\t\"logback.xml\");\n\t}\n\n\t@Test\n\tvoid springConfigLocations() {\n\t\tString[] locations = getSpringConfigLocations(this.loggingSystem);\n\t\tassertThat(locations).containsExactly(\"logback-test-spring.groovy\", \"logback-test-spring.xml\",\n\t\t\t\t\"logback-spring.groovy\", \"logback-spring.xml\");\n\t}\n\n\tprivate boolean bridgeHandlerInstalled() {\n\t\tjava.util.logging.Logger rootLogger = LogManager.getLogManager().getLogger(\"\");\n\t\tHandler[] handlers = rootLogger.getHandlers();\n\t\tfor (Handler handler : handlers) {\n\t\t\tif (handler instanceof SLF4JBridgeHandler) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Test\n\tvoid testConsolePatternProperty(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.console\", \"%logger %msg\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tinitialize(loggingInitializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"INFO\");\n\t}\n\n\t@Test\n\tvoid testLevelPatternProperty(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.level\", \"X%clr(%p)X\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tinitialize(loggingInitializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"XINFOX\");\n\t}\n\n\t@Test\n\tvoid testFilePatternProperty(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.file\", \"%logger %msg\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).doesNotContain(\"INFO\");\n\t}\n\n\t@Test\n\tvoid testCleanHistoryOnStartProperty() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.clean-history-on-start\", \"true\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(getRollingPolicy().isCleanHistoryOnStart()).isTrue();\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid testCleanHistoryOnStartPropertyWithXmlConfiguration() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.clean-history-on-start\", \"true\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, \"classpath:include-base.xml\", logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(getRollingPolicy().isCleanHistoryOnStart()).isTrue();\n\t}\n\n\t@Test\n\tvoid testMaxFileSizePropertyWithLogbackFileSize() {\n\t\ttestMaxFileSizeProperty(\"100 MB\", \"100 MB\");\n\t}\n\n\t@Test\n\tvoid testMaxFileSizePropertyWithDataSize() {\n\t\ttestMaxFileSizeProperty(\"15MB\", \"15 MB\");\n\t}\n\n\t@Test\n\tvoid testMaxFileSizePropertyWithBytesValue() {\n\t\ttestMaxFileSizeProperty(String.valueOf(10 * 1024 * 1024), \"10 MB\");\n\t}\n\n\tprivate void testMaxFileSizeProperty(String sizeValue, String expectedFileSize) {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-file-size\", sizeValue);\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(ReflectionTestUtils.getField(getRollingPolicy(), \"maxFileSize\")).hasToString(expectedFileSize);\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid testMaxFileSizePropertyWithXmlConfiguration() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-file-size\", \"100MB\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, \"classpath:include-base.xml\", logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(ReflectionTestUtils.getField(getRollingPolicy(), \"maxFileSize\")).hasToString(\"100 MB\");\n\t}\n\n\t@Test\n\tvoid testMaxHistoryProperty() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-history\", \"30\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(getRollingPolicy().getMaxHistory()).isEqualTo(30);\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid testMaxHistoryPropertyWithXmlConfiguration() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-history\", \"30\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, \"classpath:include-base.xml\", logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(getRollingPolicy().getMaxHistory()).isEqualTo(30);\n\t}\n\n\t@Test\n\tvoid testTotalSizeCapPropertyWithLogbackFileSize() {\n\t\ttestTotalSizeCapProperty(\"101 MB\", \"101 MB\");\n\t}\n\n\t@Test\n\tvoid testTotalSizeCapPropertyWithDataSize() {\n\t\ttestTotalSizeCapProperty(\"10MB\", \"10 MB\");\n\t}\n\n\t@Test\n\tvoid testTotalSizeCapPropertyWithBytesValue() {\n\t\ttestTotalSizeCapProperty(String.valueOf(10 * 1024 * 1024), \"10 MB\");\n\t}\n\n\tprivate void testTotalSizeCapProperty(String sizeValue, String expectedFileSize) {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.total-size-cap\", sizeValue);\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(ReflectionTestUtils.getField(getRollingPolicy(), \"totalSizeCap\")).hasToString(expectedFileSize);\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid testTotalSizeCapPropertyWithXmlConfiguration() {\n\t\tString expectedSize = \"101 MB\";\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.total-size-cap\", expectedSize);\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, \"classpath:include-base.xml\", logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(ReflectionTestUtils.getField(getRollingPolicy(), \"totalSizeCap\")).hasToString(expectedSize);\n\t}\n\n\t@Test\n\tvoid exceptionsIncludeClassPackaging(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, getLogFile(null, tmpDir()));\n\t\tthis.logger.warn(\"Expected exception\", new RuntimeException(\"Expected\"));\n\t\tString fileContents = contentOf(new File(tmpDir() + \"/spring.log\"));\n\t\tassertThat(fileContents).contains(\"[junit-\");\n\t\tassertThat(output).contains(\"[junit-\");\n\t}\n\n\t@Test\n\tvoid customExceptionConversionWord(CapturedOutput output) {\n\t\tSystem.setProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD.getEnvironmentVariableName(), \"%ex\");\n\t\ttry {\n\t\t\tthis.loggingSystem.beforeInitialize();\n\t\t\tthis.logger.info(\"Hidden\");\n\t\t\tinitialize(this.initializationContext, null, getLogFile(null, tmpDir()));\n\t\t\tthis.logger.warn(\"Expected exception\", new RuntimeException(\"Expected\", new RuntimeException(\"Cause\")));\n\t\t\tString fileContents = contentOf(new File(tmpDir() + \"/spring.log\"));\n\t\t\tassertThat(fileContents).contains(\"java.lang.RuntimeException: Expected\").doesNotContain(\"Wrapped by:\");\n\t\t\tassertThat(output).contains(\"java.lang.RuntimeException: Expected\").doesNotContain(\"Wrapped by:\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(LoggingSystemProperty.EXCEPTION_CONVERSION_WORD.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid initializeShouldSetSystemProperty() {\n\t\t// gh-5491\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.logger.info(\"Hidden\");\n\t\tLogFile logFile = getLogFile(tmpDir() + \"/example.log\", null, false);\n\t\tinitialize(this.initializationContext, \"classpath:nondefault.xml\", logFile);\n\t\tassertThat(System.getProperty(LoggingSystemProperty.LOG_FILE.getEnvironmentVariableName()))\n\t\t\t.endsWith(\"example.log\");\n\t}\n\n\t@Test\n\tvoid initializeShouldApplyLogbackSystemPropertiesToTheContext() {\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.file-name-pattern\", \"file-name-pattern\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.clean-history-on-start\", \"true\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-file-size\", \"10MB\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.total-size-cap\", \"100MB\");\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.max-history\", \"20\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tLoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();\n\t\tMap<String, String> properties = loggerContext.getCopyOfPropertyMap();\n\t\tSet<String> expectedProperties = new HashSet<>();\n\t\tStream.of(RollingPolicySystemProperty.values())\n\t\t\t.map(RollingPolicySystemProperty::getEnvironmentVariableName)\n\t\t\t.forEach(expectedProperties::add);\n\t\tStream.of(LoggingSystemProperty.values())\n\t\t\t.map(LoggingSystemProperty::getEnvironmentVariableName)\n\t\t\t.forEach(expectedProperties::add);\n\t\texpectedProperties.removeAll(List.of(\"LOG_FILE\", \"LOG_PATH\"));\n\t\texpectedProperties.add(\"org.jboss.logging.provider\");\n\t\texpectedProperties.add(\"LOG_CORRELATION_PATTERN\");\n\t\texpectedProperties.add(\"CONSOLE_LOG_STRUCTURED_FORMAT\");\n\t\texpectedProperties.add(\"FILE_LOG_STRUCTURED_FORMAT\");\n\t\tassertThat(properties).containsOnlyKeys(expectedProperties);\n\t\tassertThat(properties).containsEntry(\"CONSOLE_LOG_CHARSET\", getConsoleCharset());\n\t}\n\n\t@Test\n\tvoid initializationIsOnlyPerformedOnceUntilCleanedUp() {\n\t\tLoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();\n\t\tLoggerContextListener listener = mock(LoggerContextListener.class);\n\t\tloggerContext.addListener(listener);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthen(listener).should().onReset(loggerContext);\n\t\tthis.loggingSystem.cleanUp();\n\t\tloggerContext.addListener(listener);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthen(listener).should(times(2)).onReset(loggerContext);\n\t}\n\n\t@Test\n\tvoid testDateformatPatternDefault(CapturedOutput output) {\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tinitialize(loggingInitializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.containsPattern(\"\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}:\\\\d{2}\\\\.\\\\d{3}([-+]\\\\d{2}:\\\\d{2}|Z)\");\n\t}\n\n\t@Test\n\tvoid testDateformatPatternProperty(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.dateformat\", \"dd-MM-yyyy\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tinitialize(loggingInitializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).containsPattern(\"\\\\d{2}-\\\\d{2}-\\\\d{4}\\\\s\");\n\t}\n\n\t@Test // gh-24835\n\tvoid testDateformatPatternPropertyDirect(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.dateformat\", \"yyyy\");\n\t\tnew LoggingSystemProperties(this.environment).apply();\n\t\tthis.environment.setProperty(\"logging.pattern.dateformat\", \"dd-MM-yyyy\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tinitialize(loggingInitializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).containsPattern(\"\\\\d{2}-\\\\d{2}-\\\\d{4}\\\\s\");\n\t}\n\n\t@Test\n\tvoid noDebugOutputIsProducedByDefault(CapturedOutput output) {\n\t\tSystem.clearProperty(\"logback.debug\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tassertThat(output).doesNotContain(\"LevelChangePropagator\").doesNotContain(\"SizeAndTimeBasedFNATP\");\n\t}\n\n\t@Test\n\tvoid logbackDebugPropertyIsHonored(CapturedOutput output) {\n\t\tSystem.setProperty(\"logback.debug\", \"true\");\n\t\ttry {\n\t\t\tthis.loggingSystem.beforeInitialize();\n\t\t\tLoggerContext loggerContext = this.logger.getLoggerContext();\n\t\t\tStatusManager statusManager = loggerContext.getStatusManager();\n\t\t\tstatusManager.add(new InfoStatus(\"INFO STATUS MESSAGE\", getClass()));\n\t\t\tstatusManager.add(new WarnStatus(\"WARN STATUS MESSAGE\", getClass()));\n\t\t\tstatusManager.add(new ErrorStatus(\"ERROR STATUS MESSAGE\", getClass()));\n\t\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\t\tinitialize(this.initializationContext, null, logFile);\n\t\t\tassertThat(output).contains(\"LevelChangePropagator\")\n\t\t\t\t.contains(\"SizeAndTimeBasedFileNamingAndTriggeringPolicy\")\n\t\t\t\t.contains(\"DebugLogbackConfigurator\")\n\t\t\t\t.contains(\"INFO STATUS MESSAGE\")\n\t\t\t\t.contains(\"WARN STATUS MESSAGE\")\n\t\t\t\t.contains(\"ERROR STATUS MESSAGE\");\n\t\t\tassertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {\n\t\t\t\tassertThat(listener).isInstanceOf(SystemStatusListener.class);\n\t\t\t\tassertThat(listener).hasFieldOrPropertyWithValue(\"debug\", true);\n\t\t\t});\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"logback.debug\");\n\t\t}\n\t}\n\n\t@Test\n\t@WithResource(name = \"logback-include-status-listener.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<statusListener class=\"ch.qos.logback.core.status.OnConsoleStatusListener\"/>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\t\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t\t\t\t<encoder>\n\t\t\t\t\t\t<pattern>[%p] - %m%n</pattern>\n\t\t\t\t\t</encoder>\n\t\t\t\t</appender>\n\t\t\t\t<root level=\"INFO\">\n\t\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid logbackSystemStatusListenerShouldBeRegisteredWhenCustomLogbackXmlHasStatusListener(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, \"classpath:logback-include-status-listener.xml\", null);\n\t\tLoggerContext loggerContext = this.logger.getLoggerContext();\n\t\tassertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).hasSize(2)\n\t\t\t.allSatisfy((listener) -> assertThat(listener).isInstanceOf(OnConsoleStatusListener.class))\n\t\t\t.anySatisfy((listener) -> assertThat(listener).isInstanceOf(SystemStatusListener.class));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Hello world\");\n\t}\n\n\t@Test\n\tvoid logbackSystemStatusListenerShouldBeRegistered(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, getLogFile(tmpDir() + \"/tmp.log\", null));\n\t\tLoggerContext loggerContext = this.logger.getLoggerContext();\n\t\tassertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {\n\t\t\tassertThat(listener).isInstanceOf(SystemStatusListener.class);\n\t\t\tassertThat(listener).hasFieldOrPropertyWithValue(\"debug\", false);\n\t\t});\n\t\tAlwaysFailAppender appender = new AlwaysFailAppender();\n\t\tappender.setContext(loggerContext);\n\t\tappender.start();\n\t\tthis.logger.addAppender(appender);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Always Fail Appender\").contains(\"Hello world\");\n\t}\n\n\t@Test\n\tvoid logbackSystemStatusListenerShouldBeRegisteredOnlyOnce() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, getLogFile(tmpDir() + \"/tmp.log\", null));\n\t\tLoggerContext loggerContext = this.logger.getLoggerContext();\n\t\tSystemStatusListener.addTo(loggerContext);\n\t\tSystemStatusListener.addTo(loggerContext, true);\n\t\tassertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).satisfiesOnlyOnce((listener) -> {\n\t\t\tassertThat(listener).isInstanceOf(SystemStatusListener.class);\n\t\t\tassertThat(listener).hasFieldOrPropertyWithValue(\"debug\", false);\n\t\t});\n\t}\n\n\t@Test\n\tvoid logbackSystemStatusListenerShouldBeRegisteredAndFilterStatusByLevelIfDebugDisabled(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tLoggerContext loggerContext = this.logger.getLoggerContext();\n\t\tStatusManager statusManager = loggerContext.getStatusManager();\n\t\tstatusManager.add(new InfoStatus(\"INFO STATUS MESSAGE\", getClass()));\n\t\tstatusManager.add(new WarnStatus(\"WARN STATUS MESSAGE\", getClass()));\n\t\tstatusManager.add(new ErrorStatus(\"ERROR STATUS MESSAGE\", getClass()));\n\t\tinitialize(this.initializationContext, null, getLogFile(tmpDir() + \"/tmp.log\", null));\n\t\tassertThat(statusManager.getCopyOfStatusListenerList()).allSatisfy((listener) -> {\n\t\t\tassertThat(listener).isInstanceOf(SystemStatusListener.class);\n\t\t\tassertThat(listener).hasFieldOrPropertyWithValue(\"debug\", false);\n\t\t});\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).doesNotContain(\"INFO STATUS MESSAGE\");\n\t\tassertThat(output).contains(\"WARN STATUS MESSAGE\");\n\t\tassertThat(output).contains(\"ERROR STATUS MESSAGE\");\n\t\tassertThat(output).contains(\"Hello world\");\n\t}\n\n\t@Test\n\t@WithIncludeDefaultsXmlResource\n\tvoid logbackSystemStatusListenerShouldBeRegisteredWhenUsingCustomLogbackXml(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, \"classpath:include-defaults.xml\", null);\n\t\tLoggerContext loggerContext = this.logger.getLoggerContext();\n\t\tassertThat(loggerContext.getStatusManager().getCopyOfStatusListenerList()).allSatisfy((listener) -> {\n\t\t\tassertThat(listener).isInstanceOf(SystemStatusListener.class);\n\t\t\tassertThat(listener).hasFieldOrPropertyWithValue(\"debug\", false);\n\t\t});\n\t\tAlwaysFailAppender appender = new AlwaysFailAppender();\n\t\tappender.setContext(loggerContext);\n\t\tappender.start();\n\t\tthis.logger.addAppender(appender);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"Always Fail Appender\").contains(\"Hello world\");\n\t}\n\n\t@Test\n\tvoid testRollingFileNamePatternProperty() {\n\t\tString rollingFile = \"my.log.%d{yyyyMMdd}.%i.gz\";\n\t\tthis.environment.setProperty(\"logging.logback.rollingpolicy.file-name-pattern\", rollingFile);\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"my.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"INFO\");\n\t\tassertThat(getRollingPolicy().getFileNamePattern()).isEqualTo(rollingFile);\n\t}\n\n\t@Test\n\tvoid customCharset() {\n\t\tthis.environment.setProperty(\"logging.charset.console\", \"UTF-16\");\n\t\tLoggingInitializationContext loggingInitializationContext = new LoggingInitializationContext(this.environment);\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(loggingInitializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tLayoutWrappingEncoder<?> encoder = (LayoutWrappingEncoder<?>) getConsoleAppender().getEncoder();\n\t\tassertThat(encoder.getCharset()).isEqualTo(StandardCharsets.UTF_16);\n\t}\n\n\t@Test\n\tvoid whenContextHasNoAotContributionThenProcessAheadOfTimeReturnsNull() {\n\t\tBeanFactoryInitializationAotContribution contribution = this.loggingSystem\n\t\t\t.processAheadOfTime(mock(ConfigurableListableBeanFactory.class));\n\t\tassertThat(contribution).isNull();\n\t}\n\n\t@Test\n\tvoid whenContextHasAotContributionThenProcessAheadOfTimeClearsAndReturnsIt() {\n\t\tLoggerContext context = ((LoggerContext) LoggerFactory.getILoggerFactory());\n\t\tcontext.putObject(BeanFactoryInitializationAotContribution.class.getName(),\n\t\t\t\tmock(BeanFactoryInitializationAotContribution.class));\n\t\tBeanFactoryInitializationAotContribution contribution = this.loggingSystem\n\t\t\t.processAheadOfTime(mock(ConfigurableListableBeanFactory.class));\n\t\tassertThat(context.getObject(BeanFactoryInitializationAotContribution.class.getName())).isNull();\n\t\tassertThat(contribution).isNotNull();\n\t}\n\n\t@Test // gh-33610\n\t@WithResource(name = \"springprofile-in-root.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t\t\t\t<encoder>\n\t\t\t\t\t\t<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>\n\t\t\t\t\t</encoder>\n\t\t\t\t</appender>\n\t\t\t\t<root level=\"INFO\">\n\t\t\t\t\t<springProfile name=\"profile\">\n\t\t\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t\t\t</springProfile>\n\t\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid springProfileIfNestedWithinSecondPhaseElementSanityChecker(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, \"classpath:springprofile-in-root.xml\", null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).contains(\"<springProfile> elements cannot be nested within an\");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToFileWhenExpectCorrelationIdTrueAndMdcContent() {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\"))\n\t\t\t.contains(\" [01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndMdcContent(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenExpectCorrelationIdFalseAndMdcContent(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"false\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"0123456789012345\");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenExpectCorrelationIdTrueAndNoMdcContent(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [                                                 ] \");\n\t}\n\n\t@Test\n\tvoid correlationLoggingToConsoleWhenHasCorrelationPattern(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.pattern.correlation\", \"%correlationId{spanId(0),traceId(0)}\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [0123456789012345-01234567890123456789012345678901] \");\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid correlationLoggingToConsoleWhenUsingXmlConfiguration(CapturedOutput output) {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tinitialize(this.initializationContext, \"classpath:include-base.xml\", null);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\"))\n\t\t\t.contains(\" [01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\t@WithIncludeBaseXmlResource\n\tvoid correlationLoggingToFileWhenUsingFileConfiguration() {\n\t\tthis.environment.setProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, \"true\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, \"classpath:include-base.xml\", logFile);\n\t\tMDC.setContextMap(Map.of(\"traceId\", \"01234567890123456789012345678901\", \"spanId\", \"0123456789012345\"));\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\"))\n\t\t\t.contains(\" [01234567890123456789012345678901-0123456789012345] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToConsoleWhenHasApplicationName(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[myapp] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToConsoleWhenHasApplicationNameWithParenthesis(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp (dev)\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[myapp (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToConsoleWhenDisabled(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tthis.environment.setProperty(\"logging.include-application-name\", \"false\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"myapp\").doesNotContain(\"null\");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToFileWhenHasApplicationName() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[myapp] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToFileWhenHasApplicationNameWithParenthesis() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp (dev)\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[myapp (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationNameLoggingToFileWhenDisabled() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"myapp\");\n\t\tthis.environment.setProperty(\"logging.include-application-name\", \"false\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).doesNotContain(\"myapp\").doesNotContain(\"null\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"broken.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsolAppender\">\n\t\t\t\t\t<encoder>\n\t\t\t\t\t\t<pattern>${LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>\n\t\t\t\t\t</encoder>\n\t\t\t\t</appender>\n\t\t\t\t<root level=\"INFO\">\n\t\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid whenConfigurationErrorIsDetectedUnderlyingCausesAreIncludedAsSuppressedExceptions() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> initialize(this.initializationContext, \"classpath:broken.xml\",\n\t\t\t\t\tgetLogFile(tmpDir() + \"/tmp.log\", null)))\n\t\t\t.satisfies((ex) -> assertThat(ex.getSuppressed())\n\t\t\t\t.hasAtLeastOneElementOfType(DynamicClassLoadingException.class));\n\t}\n\n\t@Test\n\t@WithResource(name = \"invalid-format.txt\", content = \"Not XML\")\n\tvoid whenConfigLocationIsNotXmlThenIllegalArgumentExceptionShouldBeThrown() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> initialize(this.initializationContext, \"classpath:invalid-format.txt\",\n\t\t\t\t\tgetLogFile(tmpDir() + \"/tmp.log\", null)))\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).isInstanceOf(JoranException.class)\n\t\t\t\t.hasMessageStartingWith(\"Problem parsing XML document. See previously reported errors\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"without-extension\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t\t\t<encoder>\n\t\t\t\t\t<pattern>%msg</pattern>\n\t\t\t\t</encoder>\n\t\t\t</appender>\n\t\t\t<root level=\"INFO\">\n\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tvoid whenConfigLocationIsXmlFileWithoutExtensionShouldWork(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, \"classpath:without-extension\", getLogFile(tmpDir() + \"/tmp.log\", null));\n\t\tthis.logger.info(\"No extension and works!\");\n\t\tassertThat(output.toString()).contains(\"No extension and works!\");\n\t}\n\n\t@Test\n\tvoid whenConfigLocationIsXmlAndHasQueryParametersThenIllegalArgumentExceptionShouldNotBeThrown() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> initialize(this.initializationContext, \"file:///logback-nonexistent.xml?raw=true\",\n\t\t\t\t\tgetLogFile(tmpDir() + \"/tmp.log\", null)))\n\t\t\t.satisfies((ex) -> assertThat(ex.getCause()).isNotInstanceOf(IllegalArgumentException.class));\n\t}\n\n\t@Test\n\tvoid shouldRespectConsoleThreshold(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"logging.threshold.console\", \"warn\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Some info message\");\n\t\tthis.logger.warn(\"Some warn message\");\n\t\tassertThat(output).doesNotContain(\"Some info message\").contains(\"Some warn message\");\n\t}\n\n\t@Test\n\tvoid shouldRespectFileThreshold() {\n\t\tthis.environment.setProperty(\"logging.threshold.file\", \"warn\");\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, getLogFile(null, tmpDir()));\n\t\tthis.logger.info(\"Some info message\");\n\t\tthis.logger.warn(\"Some warn message\");\n\t\tPath file = Path.of(tmpDir(), \"spring.log\");\n\t\tassertThat(file).content(StandardCharsets.UTF_8)\n\t\t\t.doesNotContain(\"Some info message\")\n\t\t\t.contains(\"Some warn message\");\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid applyingSystemPropertiesDoesNotCauseUnwantedStatusWarnings(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"test\", Map.of(\"logging.pattern.console\", \"[CONSOLE]%m\")));\n\t\tthis.loggingSystem.initialize(this.initializationContext, \"classpath:nondefault.xml\", null);\n\t\tassertThat(output).doesNotContain(\"WARN\");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToConsoleWhenHasApplicationGroup(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[mygroup] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToConsoleWhenHasApplicationGroupWithParenthesis(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup (dev)\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).contains(\"[mygroup (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToConsoleWhenDisabled(CapturedOutput output) {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tthis.environment.setProperty(\"logging.include-application-group\", \"false\");\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(output, \"Hello world\")).doesNotContain(\"mygroup\").doesNotContain(\"null\");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToFileWhenHasApplicationGroup() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[mygroup] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToFileWhenHasApplicationGroupWithParenthesis() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"mygroup (dev)\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).contains(\"[mygroup (dev)] \");\n\t}\n\n\t@Test\n\tvoid applicationGroupLoggingToFileWhenDisabled() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"myGroup\");\n\t\tthis.environment.setProperty(\"logging.include-application-group\", \"false\");\n\t\tFile file = new File(tmpDir(), \"logback-test.log\");\n\t\tLogFile logFile = getLogFile(file.getPath(), null);\n\t\tinitialize(this.initializationContext, null, logFile);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(getLineWithText(file, \"Hello world\")).doesNotContain(\"myGroup\").doesNotContain(\"null\");\n\t}\n\n\t@Test\n\tvoid shouldNotContainAnsiEscapeCodes(CapturedOutput output) {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tthis.logger.info(\"Hello world\");\n\t\tassertThat(output).doesNotContain(\"\\033[\");\n\t}\n\n\t@Test\n\tvoid getEnvironment() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tinitialize(this.initializationContext, null, null);\n\t\tassertThat(this.logger.getLoggerContext().getObject(Environment.class.getName())).isSameAs(this.environment);\n\t}\n\n\t@Test\n\t@WithNonDefaultXmlResource\n\tvoid getEnvironmentWhenUsingFile() {\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tLogFile logFile = getLogFile(tmpDir() + \"/example.log\", null, false);\n\t\tinitialize(this.initializationContext, \"classpath:nondefault.xml\", logFile);\n\t\tassertThat(this.logger.getLoggerContext().getObject(Environment.class.getName())).isSameAs(this.environment);\n\t}\n\n\tprivate void initialize(LoggingInitializationContext context, @Nullable String configLocation,\n\t\t\t@Nullable LogFile logFile) {\n\t\tConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();\n\t\tassertThat(environment).isNotNull();\n\t\tthis.loggingSystem.getSystemProperties(environment).apply(logFile);\n\t\tthis.loggingSystem.beforeInitialize();\n\t\tthis.loggingSystem.initialize(context, configLocation, logFile);\n\t}\n\n\tprivate static String getConsoleCharset() {\n\t\tConsole console = System.console();\n\t\treturn (console != null) ? console.charset().name() : Charset.defaultCharset().name();\n\t}\n\n\tprivate static Logger getRootLogger() {\n\t\tILoggerFactory factory = LoggerFactory.getILoggerFactory();\n\t\tLoggerContext context = (LoggerContext) factory;\n\t\treturn context.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);\n\t}\n\n\tprivate static ConsoleAppender<?> getConsoleAppender() {\n\t\treturn (ConsoleAppender<?>) getRootLogger().getAppender(\"CONSOLE\");\n\t}\n\n\tprivate static RollingFileAppender<?> getFileAppender() {\n\t\treturn (RollingFileAppender<?>) getRootLogger().getAppender(\"FILE\");\n\t}\n\n\tprivate static SizeAndTimeBasedRollingPolicy<?> getRollingPolicy() {\n\t\treturn (SizeAndTimeBasedRollingPolicy<?>) getFileAppender().getRollingPolicy();\n\t}\n\n\tprivate static final class AlwaysFailAppender extends AppenderBase<ILoggingEvent> {\n\n\t\t@Override\n\t\tprotected void append(ILoggingEvent eventObject) {\n\t\t\tthrow new RuntimeException(\"Always Fail Appender\");\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"include-base.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithIncludeBaseXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"nondefault.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t\t\t\t<encoder>\n\t\t\t\t\t\t<pattern>%property{LOG_FILE} [%t] ${PID:-????} %c{1}: %m%n BOOTBOOT</pattern>\n\t\t\t\t\t</encoder>\n\t\t\t\t</appender>\n\t\t\t\t<root level=\"INFO\">\n\t\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithNonDefaultXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"include-defaults.xml\", content = \"\"\"\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\t\t\t\t<appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t\t\t\t<encoder>\n\t\t\t\t\t\t<pattern>[%p] - %m%n</pattern>\n\t\t\t\t\t</encoder>\n\t\t\t\t</appender>\n\t\t\t\t<root level=\"INFO\">\n\t\t\t\t\t<appender-ref ref=\"CONSOLE\"/>\n\t\t\t\t</root>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithIncludeDefaultsXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogbackRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.pattern.SyslogStartConverter;\nimport ch.qos.logback.core.pattern.Converter;\nimport ch.qos.logback.core.rolling.helper.DateTokenConverter;\nimport ch.qos.logback.core.rolling.helper.IntegerTokenConverter;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.bridge.SLF4JBridgeHandler;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LogbackRuntimeHints}.\n *\n * @author Andy Wilkinson\n */\nclass LogbackRuntimeHintsTests {\n\n\t@Test\n\tvoid registersHintsForTypesCheckedByLogbackLoggingSystem() {\n\t\tReflectionHints reflection = registerHints();\n\t\tassertThat(reflection.getTypeHint(LoggerContext.class)).isNotNull();\n\t\tassertThat(reflection.getTypeHint(SLF4JBridgeHandler.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid registersHintsForBuiltInLogbackConverters() {\n\t\tReflectionHints reflection = registerHints();\n\t\tassertThat(logbackConverters()).allSatisfy(registeredForPublicConstructorInvocation(reflection));\n\t}\n\n\t@Test\n\tvoid registersHintsForSpringBootConverters() throws IOException {\n\t\tReflectionHints reflection = registerHints();\n\t\tassertThat(converterClasses()).allSatisfy(registeredForPublicConstructorInvocation(reflection));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Stream<Class<Converter<?>>> converterClasses() throws IOException {\n\t\tPathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();\n\t\treturn Stream.of(resolver.getResources(\"classpath:org/springframework/boot/logging/logback/*.class\"))\n\t\t\t.filter(Resource::isFile)\n\t\t\t.map(this::loadClass)\n\t\t\t.filter(Converter.class::isAssignableFrom)\n\t\t\t.map((type) -> (Class<Converter<?>>) type);\n\t}\n\n\tprivate Class<?> loadClass(Resource resource) {\n\t\ttry {\n\t\t\tString filename = resource.getFilename();\n\t\t\tassertThat(filename).isNotNull();\n\t\t\treturn getClass().getClassLoader()\n\t\t\t\t.loadClass(\"org.springframework.boot.logging.logback.\" + filename.replace(\".class\", \"\"));\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Test\n\tvoid doesNotRegisterHintsWhenLoggerContextIsNotAvailable() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew LogbackRuntimeHints().registerHints(hints, ClassLoader.getPlatformClassLoader());\n\t\tassertThat(hints.reflection().typeHints()).isEmpty();\n\t}\n\n\tprivate ReflectionHints registerHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew LogbackRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\treturn hints.reflection();\n\t}\n\n\tprivate Consumer<Class<?>> registeredForPublicConstructorInvocation(ReflectionHints reflection) {\n\t\treturn (converter) -> {\n\t\t\tTypeHint typeHint = reflection.getTypeHint(converter);\n\t\t\tassertThat(typeHint).isNotNull();\n\t\t\tassertThat(typeHint.getMemberCategories()).containsExactly(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t};\n\t}\n\n\tprivate List<Class<?>> logbackConverters() {\n\t\treturn List.of(DateTokenConverter.class, IntegerTokenConverter.class, SyslogStartConverter.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/LogstashStructuredLogFormatterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.time.OffsetDateTime;\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Marker;\n\nimport org.springframework.boot.logging.structured.TestContextPairs;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link LogstashStructuredLogFormatter}.\n *\n * @author Moritz Halbritter\n */\nclass LogstashStructuredLogFormatterTests extends AbstractStructuredLoggingTests {\n\n\tprivate LogstashStructuredLogFormatter formatter;\n\n\t@Override\n\t@BeforeEach\n\tvoid setUp() {\n\t\tsuper.setUp();\n\t\tthis.formatter = new LogstashStructuredLogFormatter(null, TestContextPairs.include(),\n\t\t\t\tgetThrowableProxyConverter(), this.customizer);\n\t}\n\n\t@Test\n\tvoid callsCustomizer() {\n\t\tthen(this.customizer).should().customize(any());\n\t}\n\n\t@Test\n\tvoid shouldFormat() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Map.of(\"mdc-1\", \"mdc-v-1\"));\n\t\tevent.setKeyValuePairs(keyValuePairs(\"kv-1\", \"kv-v-1\"));\n\t\tMarker marker1 = getMarker(\"marker-1\");\n\t\tmarker1.add(getMarker(\"marker-2\"));\n\t\tevent.addMarker(marker1);\n\t\tString json = this.formatter.format(event);\n\t\tassertThat(json).endsWith(\"\\n\");\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString timestamp = DateTimeFormatter.ISO_OFFSET_DATE_TIME\n\t\t\t.format(OffsetDateTime.ofInstant(EVENT_TIME, ZoneId.systemDefault()));\n\t\tassertThat(deserialized).containsExactlyInAnyOrderEntriesOf(map(\"@timestamp\", timestamp, \"@version\", \"1\",\n\t\t\t\t\"message\", \"message\", \"logger_name\", \"org.example.Test\", \"thread_name\", \"main\", \"level\", \"INFO\",\n\t\t\t\t\"level_value\", 20000, \"mdc-1\", \"mdc-v-1\", \"kv-1\", \"kv-v-1\", \"tags\", List.of(\"marker-1\", \"marker-2\")));\n\t}\n\n\t@Test\n\tvoid shouldFormatException() {\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom\")));\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString stackTrace = (String) deserialized.get(\"stack_trace\");\n\t\tassertThat(stackTrace).startsWith(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\tat org.springframework.boot.logging.logback.LogstashStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted());\n\t\tassertThat(json).contains(\n\t\t\t\t\"java.lang.RuntimeException: Boom%n\\\\tat org.springframework.boot.logging.logback.LogstashStructuredLogFormatterTests.shouldFormatException\"\n\t\t\t\t\t.formatted()\n\t\t\t\t\t.replace(\"\\n\", \"\\\\n\")\n\t\t\t\t\t.replace(\"\\r\", \"\\\\r\"));\n\t}\n\n\t@Test\n\tvoid shouldFormatExceptionWithStackTracePrinter() {\n\t\tthis.formatter = new LogstashStructuredLogFormatter(new SimpleStackTracePrinter(), TestContextPairs.include(),\n\t\t\t\tgetThrowableProxyConverter(), this.customizer);\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setThrowableProxy(new ThrowableProxy(new RuntimeException(\"Boom\")));\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = this.formatter.format(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tString stackTrace = (String) deserialized.get(\"stack_trace\");\n\t\tassertThat(stackTrace).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/RootLogLevelConfiguratorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.spi.Configurator.ExecutionStatus;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RootLogLevelConfigurator}.\n *\n * @author Andy Wilkinson\n */\nclass RootLogLevelConfiguratorTests {\n\n\t@Test\n\tvoid shouldSetRootLogLevelToInfo() {\n\t\tLoggerContext context = new LoggerContext();\n\t\tassertThat(context.getLogger(Logger.ROOT_LOGGER_NAME).getLevel()).isEqualTo(Level.DEBUG);\n\t\tassertThat(new RootLogLevelConfigurator().configure(context)).isEqualTo(ExecutionStatus.INVOKE_NEXT_IF_ANY);\n\t\tassertThat(context.getLogger(Logger.ROOT_LOGGER_NAME).getLevel()).isEqualTo(Level.INFO);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/SimpleStackTracePrinter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Simple {@link StackTracePrinter} used for testing.\n *\n * @author Phillip Webb\n */\nclass SimpleStackTracePrinter implements StackTracePrinter {\n\n\t@Override\n\tpublic void printStackTrace(Throwable throwable, Appendable out) throws IOException {\n\t\tout.append(\"stacktrace:\" + ClassUtils.getShortName(throwable.getClass()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringBootJoranConfiguratorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport ch.qos.logback.classic.BasicConfigurator;\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.classic.joran.JoranConfigurator;\nimport ch.qos.logback.core.joran.spi.JoranException;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.logging.LoggingInitializationContext;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootJoranConfigurator}.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SpringBootJoranConfiguratorTests {\n\n\tprivate MockEnvironment environment;\n\n\tprivate LoggingInitializationContext initializationContext;\n\n\tprivate JoranConfigurator configurator;\n\n\tprivate LoggerContext context;\n\n\tprivate Logger logger;\n\n\tprivate CapturedOutput output;\n\n\t@BeforeEach\n\tvoid setup(CapturedOutput output) {\n\t\tthis.output = output;\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.initializationContext = new LoggingInitializationContext(this.environment);\n\t\tthis.configurator = new SpringBootJoranConfigurator(this.initializationContext);\n\t\tthis.context = (LoggerContext) LoggerFactory.getILoggerFactory();\n\t\tthis.logger = this.context.getLogger(getClass());\n\t}\n\n\t@AfterEach\n\tvoid reset() {\n\t\tthis.context.stop();\n\t\tnew BasicConfigurator().configure((LoggerContext) LoggerFactory.getILoggerFactory());\n\t\tthis.context.start();\n\t}\n\n\t@Test\n\t@WithProductionProfileXmlResource\n\tvoid profileActive() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"production-profile.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"profile-in-include.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<include file=\"${resourceRoot}/include-with-profile.xml\"/>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\t@WithResource(name = \"include-with-profile.xml\", content = \"\"\"\n\t\t\t<included>\n\t\t\t\t<springProfile name=\"production\">\n\t\t\t\t\t<logger name=\"org.springframework.boot.logging.logback\" level=\"TRACE\"/>\n\t\t\t\t</springProfile>\n\t\t\t</included>\n\t\t\t\"\"\")\n\tvoid profileInIncludeActive() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"profile-in-include.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithMultiProfileNamesXmlResource\n\tvoid multipleNamesFirstProfileActive() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"multi-profile-names.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithMultiProfileNamesXmlResource\n\tvoid multipleNamesSecondProfileActive() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"test\");\n\t\tinitialize(\"multi-profile-names.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProductionProfileXmlResource\n\tvoid profileNotActive() throws Exception {\n\t\tinitialize(\"production-profile.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).doesNotContain(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProfileExpressionXmlResource\n\tvoid profileExpressionMatchFirst() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"production\");\n\t\tinitialize(\"profile-expression.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProfileExpressionXmlResource\n\tvoid profileExpressionMatchSecond() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"test\");\n\t\tinitialize(\"profile-expression.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).contains(\"Hello\");\n\t}\n\n\t@Test\n\t@WithProfileExpressionXmlResource\n\tvoid profileExpressionNoMatch() throws Exception {\n\t\tthis.environment.setActiveProfiles(\"development\");\n\t\tinitialize(\"profile-expression.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tassertThat(this.output).doesNotContain(\"Hello\");\n\t}\n\n\t@Test\n\t@WithNestedXmlResource\n\tvoid profileNestedActiveActive() throws Exception {\n\t\tdoTestNestedProfile(true, \"outer\", \"inner\");\n\t}\n\n\t@Test\n\t@WithNestedXmlResource\n\tvoid profileNestedActiveNotActive() throws Exception {\n\t\tdoTestNestedProfile(false, \"outer\");\n\t}\n\n\t@Test\n\t@WithNestedXmlResource\n\tvoid profileNestedNotActiveActive() throws Exception {\n\t\tdoTestNestedProfile(false, \"inner\");\n\t}\n\n\t@Test\n\t@WithNestedXmlResource\n\tvoid profileNestedNotActiveNotActive() throws Exception {\n\t\tdoTestNestedProfile(false);\n\t}\n\n\t@Test\n\t@WithPropertyXmlResource\n\tvoid springProperty() throws Exception {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"my.example-property=test\");\n\t\tinitialize(\"property.xml\");\n\t\tassertThat(this.context.getProperty(\"MINE\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPropertyXmlResource\n\tvoid relaxedSpringProperty() throws Exception {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"my.EXAMPLE_PROPERTY=test\");\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tinitialize(\"property.xml\");\n\t\tassertThat(this.context.getProperty(\"MINE\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPropertyXmlResource\n\tvoid springPropertyNoValue() throws Exception {\n\t\tinitialize(\"property.xml\");\n\t\tassertThat(this.context.getProperty(\"SIMPLE\")).isNull();\n\t}\n\n\t@Test\n\t@WithPropertyXmlResource\n\tvoid relaxedSpringPropertyNoValue() throws Exception {\n\t\tinitialize(\"property.xml\");\n\t\tassertThat(this.context.getProperty(\"MINE\")).isNull();\n\t}\n\n\t@Test\n\t@WithPropertyDefaultValueXmlResource\n\tvoid springPropertyWithDefaultValue() throws Exception {\n\t\tinitialize(\"property-default-value.xml\");\n\t\tassertThat(this.context.getProperty(\"SIMPLE\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\t@WithPropertyDefaultValueXmlResource\n\tvoid relaxedSpringPropertyWithDefaultValue() throws Exception {\n\t\tinitialize(\"property-default-value.xml\");\n\t\tassertThat(this.context.getProperty(\"MINE\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\t@WithPropertyInIfXmlResource\n\tvoid springPropertyInIfWhenTrue() throws Exception {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"my.example-property=true\");\n\t\tinitialize(\"property-in-if.xml\");\n\t\tassertThat(this.context.getProperty(\"MYCHECK\")).isEqualTo(\"i-was-included\");\n\t}\n\n\t@Test\n\t@WithPropertyInIfXmlResource\n\tvoid springPropertyInIfWhenFalse() throws Exception {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"my.example-property=false\");\n\t\tinitialize(\"property-in-if.xml\");\n\t\tassertThat(this.context.getProperty(\"MYCHECK\")).isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"property-in-include.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<include file=\"${resourceRoot}/include-with-property.xml\"/>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\t@WithResource(name = \"include-with-property.xml\", content = \"\"\"\n\t\t\t<included>\n\t\t\t\t<springProperty scope=\"context\" name=\"MINE\" source=\"my.example-property\" defaultValue=\"default-test\"/>\n\t\t\t</included>\n\t\t\t\"\"\")\n\t@ClassPathExclusions\n\tvoid springPropertyInInclude() throws Exception {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"my.example-property=test\");\n\t\tinitialize(\"property-in-include.xml\");\n\t\tassertThat(this.context.getProperty(\"MINE\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPropertyXmlResource\n\tvoid addsAotContributionToContextDuringAotProcessing() throws Exception {\n\t\twithSystemProperty(AbstractAotProcessor.AOT_PROCESSING, \"true\", () -> {\n\t\t\tinitialize(\"property.xml\");\n\t\t\tObject contribution = this.context.getObject(BeanFactoryInitializationAotContribution.class.getName());\n\t\t\tassertThat(contribution).isNotNull();\n\t\t});\n\t}\n\n\tprivate void withSystemProperty(String name, String value, Action action) throws Exception {\n\t\tSystem.setProperty(name, value);\n\t\ttry {\n\t\t\taction.perform();\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(name);\n\t\t}\n\t}\n\n\tprivate void doTestNestedProfile(boolean expected, String... profiles) throws JoranException {\n\t\tthis.environment.setActiveProfiles(profiles);\n\t\tinitialize(\"nested.xml\");\n\t\tthis.logger.trace(\"Hello\");\n\t\tif (expected) {\n\t\t\tassertThat(this.output).contains(\"Hello\");\n\t\t}\n\t\telse {\n\t\t\tassertThat(this.output).doesNotContain(\"Hello\");\n\t\t}\n\n\t}\n\n\tprivate void initialize(String config) throws JoranException {\n\t\tthis.configurator.setContext(this.context);\n\t\tClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tthis.configurator.doConfigure(contextClassLoader.getResource(config));\n\t}\n\n\tprivate interface Action {\n\n\t\tvoid perform() throws Exception;\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"property-default-value.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProperty scope=\"context\" name=\"SIMPLE\" source=\"testpropertyfoobar\" defaultValue=\"foo\"/>\n\t\t\t\t<springProperty scope=\"context\" name=\"MINE\" source=\"my.example-property\" defaultValue=\"bar\"/>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithPropertyDefaultValueXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"property-in-if.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProperty scope=\"context\" name=\"MINE\" source=\"my.example-property\"/>\n\t\t\t\t<if condition='property(\"MINE\").contains(\"true\")'>\n\t\t\t\t\t<then>\n\t\t\t\t\t\t<variable scope=\"context\" name=\"MYCHECK\" value=\"i-was-included\"/>\n\t\t\t\t\t</then>\n\t\t\t\t</if>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithPropertyInIfXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"property.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProperty scope=\"context\" name=\"SIMPLE\" source=\"testpropertyfoobar\"/>\n\t\t\t\t<springProperty scope=\"context\" name=\"MINE\" source=\"my.example-property\"/>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithPropertyXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"profile-expression.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProfile name=\"production | test\">\n\t\t\t\t\t<logger name=\"org.springframework.boot.logging.logback\" level=\"TRACE\"/>\n\t\t\t\t</springProfile>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithProfileExpressionXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"production-profile.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProfile name=\"production\">\n\t\t\t\t\t<logger name=\"org.springframework.boot.logging.logback\" level=\"TRACE\"/>\n\t\t\t\t</springProfile>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithProductionProfileXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"nested.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProfile name=\"outer\">\n\t\t\t\t\t<springProfile name=\"inner\">\n\t\t\t\t\t\t<logger name=\"org.springframework.boot.logging.logback\" level=\"TRACE\"/>\n\t\t\t\t\t</springProfile>\n\t\t\t\t</springProfile>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithNestedXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"multi-profile-names.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<configuration>\n\t\t\t\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t\t\t\t<springProfile name=\"production, test\">\n\t\t\t\t\t<logger name=\"org.springframework.boot.logging.logback\" level=\"TRACE\"/>\n\t\t\t\t</springProfile>\n\t\t\t</configuration>\n\t\t\t\"\"\")\n\tprivate @interface WithMultiProfileNamesXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/SpringProfileModelHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport ch.qos.logback.core.Context;\nimport ch.qos.logback.core.ContextBase;\nimport ch.qos.logback.core.model.processor.ModelHandlerException;\nimport ch.qos.logback.core.model.processor.ModelInterpretationContext;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentMatchers;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.Profiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringProfileModelHandler}.\n *\n * @author Andy Wilkinson\n */\nclass SpringProfileModelHandlerTests {\n\n\tprivate final Environment environment = mock(Environment.class);\n\n\tprivate final Context context = new ContextBase();\n\n\tprivate final SpringProfileModelHandler action = new SpringProfileModelHandler(this.context, this.environment);\n\n\tprivate final ModelInterpretationContext interpretationContext = new ModelInterpretationContext(this.context);\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.action.setContext(this.context);\n\t}\n\n\t@Test\n\tvoid environmentIsQueriedWithProfileFromModelName() throws ModelHandlerException {\n\t\tSpringProfileModel model = new SpringProfileModel();\n\t\tmodel.setName(\"dev\");\n\t\tthis.action.handle(this.interpretationContext, model);\n\t\tthen(this.environment).should().acceptsProfiles(ArgumentMatchers.<Profiles>assertArg(((profiles) -> {\n\t\t\tList<String> profileNames = new ArrayList<>();\n\t\t\tprofiles.matches((profile) -> {\n\t\t\t\tprofileNames.add(profile);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tassertThat(profileNames).containsExactly(\"dev\");\n\t\t})));\n\t}\n\n\t@Test\n\tvoid environmentIsQueriedWithMultipleProfilesFromCommaSeparatedModelName() throws ModelHandlerException {\n\t\tSpringProfileModel model = new SpringProfileModel();\n\t\tmodel.setName(\"dev,qa\");\n\t\tthis.action.handle(this.interpretationContext, model);\n\t\tthen(this.environment).should().acceptsProfiles(ArgumentMatchers.<Profiles>assertArg(((profiles) -> {\n\t\t\tList<String> profileNames = new ArrayList<>();\n\t\t\tprofiles.matches((profile) -> {\n\t\t\t\tprofileNames.add(profile);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tassertThat(profileNames).containsExactly(\"dev\", \"qa\");\n\t\t})));\n\t}\n\n\t@Test\n\tvoid environmentIsQueriedWithResolvedValueWhenModelNameUsesAPlaceholder() throws ModelHandlerException {\n\t\tSpringProfileModel model = new SpringProfileModel();\n\t\tmodel.setName(\"${profile}\");\n\t\tthis.context.putProperty(\"profile\", \"dev\");\n\t\tthis.action.handle(this.interpretationContext, model);\n\t\tthen(this.environment).should().acceptsProfiles(ArgumentMatchers.<Profiles>assertArg(((profiles) -> {\n\t\t\tList<String> profileNames = new ArrayList<>();\n\t\t\tprofiles.matches((profile) -> {\n\t\t\t\tprofileNames.add(profile);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tassertThat(profileNames).containsExactly(\"dev\");\n\t\t})));\n\t}\n\n\t@Test\n\tvoid environmentIsQueriedWithResolvedValuesFromCommaSeparatedNameNameAttributeWithPlaceholders()\n\t\t\tthrows ModelHandlerException {\n\t\tSpringProfileModel model = new SpringProfileModel();\n\t\tmodel.setName(\"${profile1},${profile2}\");\n\t\tthis.context.putProperty(\"profile1\", \"dev\");\n\t\tthis.context.putProperty(\"profile2\", \"qa\");\n\t\tthis.action.handle(this.interpretationContext, model);\n\t\tthen(this.environment).should().acceptsProfiles(ArgumentMatchers.<Profiles>assertArg(((profiles) -> {\n\t\t\tList<String> profileNames = new ArrayList<>();\n\t\t\tprofiles.matches((profile) -> {\n\t\t\t\tprofileNames.add(profile);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tassertThat(profileNames).containsExactly(\"dev\", \"qa\");\n\t\t})));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/StructuredLogEncoderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.core.Context;\nimport ch.qos.logback.core.ContextBase;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.core.env.Environment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link StructuredLogEncoder}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass StructuredLogEncoderTests extends AbstractStructuredLoggingTests {\n\n\tprivate StructuredLogEncoder encoder;\n\n\tprivate Context loggerContext;\n\n\tprivate MockEnvironment environment;\n\n\t@Override\n\t@BeforeEach\n\tvoid setUp() {\n\t\tsuper.setUp();\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.environment.setProperty(\"logging.structured.json.stacktrace.printer\",\n\t\t\t\tSimpleStackTracePrinter.class.getName());\n\t\tthis.loggerContext = new ContextBase();\n\t\tthis.loggerContext.putObject(Environment.class.getName(), this.environment);\n\t\tthis.encoder = new StructuredLogEncoder();\n\t\tthis.encoder.setContext(this.loggerContext);\n\t}\n\n\t@Override\n\t@AfterEach\n\tvoid tearDown() {\n\t\tsuper.tearDown();\n\t\tthis.encoder.stop();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldSupportEcsCommonFormat() {\n\t\tthis.encoder.setFormat(\"ecs\");\n\t\tthis.encoder.start();\n\t\tLoggingEvent event = createEvent(new RuntimeException(\"Boom!\"));\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = encode(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsEntry(\"ecs\", Map.of(\"version\", \"8.11\"));\n\t\tMap<String, Object> error = (Map<String, Object>) deserialized.get(\"error\");\n\t\tassertThat(error).isNotNull();\n\t\tassertThat(error.get(\"stack_trace\")).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldOutputNestedAdditionalEcsJson() {\n\t\tthis.environment.setProperty(\"logging.structured.json.add.extra.value\", \"test\");\n\t\tthis.encoder.setFormat(\"ecs\");\n\t\tthis.encoder.start();\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = encode(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsKey(\"extra\");\n\t\tassertThat((Map<String, Object>) deserialized.get(\"extra\")).containsEntry(\"value\", \"test\");\n\t\tSystem.out.println(deserialized);\n\t}\n\n\t@Test\n\tvoid shouldSupportLogstashCommonFormat() {\n\t\tthis.encoder.setFormat(\"logstash\");\n\t\tthis.encoder.start();\n\t\tLoggingEvent event = createEvent(new RuntimeException(\"Boom!\"));\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = encode(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsKey(\"@version\");\n\t\tassertThat(deserialized.get(\"stack_trace\")).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldSupportGelfCommonFormat() {\n\t\tthis.encoder.setFormat(\"gelf\");\n\t\tthis.encoder.start();\n\t\tLoggingEvent event = createEvent(new RuntimeException(\"Boom!\"));\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString json = encode(event);\n\t\tMap<String, Object> deserialized = deserialize(json);\n\t\tassertThat(deserialized).containsKey(\"version\");\n\t\tassertThat(deserialized.get(\"_error_stack_trace\")).isEqualTo(\"stacktrace:RuntimeException\");\n\t}\n\n\t@Test\n\tvoid shouldSupportCustomFormat() {\n\t\tthis.encoder.setFormat(CustomLogbackStructuredLoggingFormatter.class.getName());\n\t\tthis.encoder.start();\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString format = encode(event);\n\t\tassertThat(format).isEqualTo(\"custom-format\");\n\t}\n\n\t@Test\n\tvoid shouldInjectCustomFormatConstructorParameters() {\n\t\tthis.environment.setProperty(\"spring.application.pid\", \"42\");\n\t\tthis.encoder.setFormat(CustomLogbackStructuredLoggingFormatterWithInjection.class.getName());\n\t\tthis.encoder.start();\n\t\tLoggingEvent event = createEvent();\n\t\tevent.setMDCPropertyMap(Collections.emptyMap());\n\t\tString format = encode(event);\n\t\tassertThat(format).isEqualTo(\"custom-format-with-injection pid=42 hasThrowableProxyConverter=true\");\n\t}\n\n\t@Test\n\tvoid shouldCheckTypeArgument() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tthis.encoder.setFormat(CustomLogbackStructuredLoggingFormatterWrongType.class.getName());\n\t\t\tthis.encoder.start();\n\t\t}).withMessageContaining(\"must be ch.qos.logback.classic.spi.ILoggingEvent but was java.lang.String\");\n\t}\n\n\t@Test\n\tvoid shouldCheckTypeArgumentWithRawType() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tthis.encoder.setFormat(CustomLogbackStructuredLoggingFormatterRawType.class.getName());\n\t\t\tthis.encoder.start();\n\t\t}).withMessageContaining(\"must be ch.qos.logback.classic.spi.ILoggingEvent but was null\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfNoCommonOrCustomFormatIsSet() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> {\n\t\t\tthis.encoder.setFormat(\"does-not-exist\");\n\t\t\tthis.encoder.start();\n\t\t})\n\t\t\t.withMessageContaining(\"Unknown format 'does-not-exist'. Values can be a valid fully-qualified \"\n\t\t\t\t\t+ \"class name or one of the common formats: [ecs, gelf, logstash]\");\n\t}\n\n\tprivate String encode(LoggingEvent event) {\n\t\treturn new String(this.encoder.encode(event), StandardCharsets.UTF_8);\n\t}\n\n\tstatic final class CustomLogbackStructuredLoggingFormatter implements StructuredLogFormatter<ILoggingEvent> {\n\n\t\t@Override\n\t\tpublic String format(ILoggingEvent event) {\n\t\t\treturn \"custom-format\";\n\t\t}\n\n\t}\n\n\tstatic final class CustomLogbackStructuredLoggingFormatterWithInjection\n\t\t\timplements StructuredLogFormatter<ILoggingEvent> {\n\n\t\tprivate final Environment environment;\n\n\t\tprivate final ThrowableProxyConverter throwableProxyConverter;\n\n\t\tCustomLogbackStructuredLoggingFormatterWithInjection(Environment environment,\n\t\t\t\tThrowableProxyConverter throwableProxyConverter) {\n\t\t\tthis.environment = environment;\n\t\t\tthis.throwableProxyConverter = throwableProxyConverter;\n\t\t}\n\n\t\t@Override\n\t\tpublic String format(ILoggingEvent event) {\n\t\t\tboolean hasThrowableProxyConverter = this.throwableProxyConverter != null;\n\t\t\treturn \"custom-format-with-injection pid=\" + this.environment.getProperty(\"spring.application.pid\")\n\t\t\t\t\t+ \" hasThrowableProxyConverter=\" + hasThrowableProxyConverter;\n\t\t}\n\n\t}\n\n\tstatic final class CustomLogbackStructuredLoggingFormatterWrongType implements StructuredLogFormatter<String> {\n\n\t\t@Override\n\t\tpublic String format(String event) {\n\t\t\treturn event;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tstatic final class CustomLogbackStructuredLoggingFormatterRawType implements StructuredLogFormatter {\n\n\t\t@Override\n\t\tpublic String format(Object event) {\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/SystemStatusListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport java.util.function.Supplier;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport ch.qos.logback.core.BasicStatusManager;\nimport ch.qos.logback.core.status.ErrorStatus;\nimport ch.qos.logback.core.status.InfoStatus;\nimport ch.qos.logback.core.status.Status;\nimport ch.qos.logback.core.status.StatusListener;\nimport ch.qos.logback.core.status.StatusManager;\nimport ch.qos.logback.core.status.WarnStatus;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SystemStatusListener}.\n *\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SystemStatusListenerTests {\n\n\tprivate static final String TEST_MESSAGE = \"testtesttest\";\n\n\tprivate final StatusManager statusManager = new BasicStatusManager();\n\n\tprivate final LoggerContext loggerContext = new LoggerContext();\n\n\tSystemStatusListenerTests() {\n\t\tthis.loggerContext.setStatusManager(this.statusManager);\n\t}\n\n\t@Test\n\tvoid addStatusWithInfoLevelWhenNoDebugDoesNotPrint(CapturedOutput output) {\n\t\taddStatus(false, () -> new InfoStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).doesNotContain(TEST_MESSAGE);\n\t\tassertThat(output.getErr()).doesNotContain(TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid addStatusWithWarningLevelWhenNoDebugPrintsToSystemErr(CapturedOutput output) {\n\t\taddStatus(false, () -> new WarnStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).doesNotContain(TEST_MESSAGE);\n\t\tassertThat(output.getErr()).contains(TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid addStatusWithErrorLevelWhenNoDebugPrintsToSystemErr(CapturedOutput output) {\n\t\taddStatus(false, () -> new ErrorStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).doesNotContain(TEST_MESSAGE);\n\t\tassertThat(output.getErr()).contains(TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid addStatusWithInfoLevelWhenDebugPrintsToSystemOut(CapturedOutput output) {\n\t\taddStatus(true, () -> new InfoStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).contains(TEST_MESSAGE);\n\t\tassertThat(output.getErr()).doesNotContain(TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid addStatusWithWarningLevelWhenDebugPrintsToSystemOut(CapturedOutput output) {\n\t\taddStatus(true, () -> new WarnStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).contains(TEST_MESSAGE);\n\t\tassertThat(output.getErr()).doesNotContain(TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid addStatusWithErrorLevelWhenDebugPrintsToSystemOut(CapturedOutput output) {\n\t\taddStatus(true, () -> new ErrorStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).contains(TEST_MESSAGE);\n\t\tassertThat(output.getErr()).doesNotContain(TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid shouldRetrospectivePrintStatusOnStartAndDebugIsDisabled(CapturedOutput output) {\n\t\tthis.statusManager.add(new ErrorStatus(TEST_MESSAGE, null));\n\t\tthis.statusManager.add(new WarnStatus(TEST_MESSAGE, null));\n\t\tthis.statusManager.add(new InfoStatus(TEST_MESSAGE, null));\n\t\taddStatus(false, () -> new InfoStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getErr()).contains(\"WARN \" + TEST_MESSAGE);\n\t\tassertThat(output.getErr()).contains(\"ERROR \" + TEST_MESSAGE);\n\t\tassertThat(output.getErr()).doesNotContain(\"INFO\");\n\t\tassertThat(output.getOut()).isEmpty();\n\t}\n\n\t@Test\n\tvoid shouldRetrospectivePrintStatusOnStartAndDebugIsEnabled(CapturedOutput output) {\n\t\tthis.statusManager.add(new ErrorStatus(TEST_MESSAGE, null));\n\t\tthis.statusManager.add(new WarnStatus(TEST_MESSAGE, null));\n\t\tthis.statusManager.add(new InfoStatus(TEST_MESSAGE, null));\n\t\taddStatus(true, () -> new InfoStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getErr()).isEmpty();\n\t\tassertThat(output.getOut()).contains(\"WARN \" + TEST_MESSAGE);\n\t\tassertThat(output.getOut()).contains(\"ERROR \" + TEST_MESSAGE);\n\t\tassertThat(output.getOut()).contains(\"INFO \" + TEST_MESSAGE);\n\t}\n\n\t@Test\n\tvoid shouldNotRetrospectivePrintWhenStatusIsOutdated(CapturedOutput output) {\n\t\tErrorStatus outdatedStatus = new ErrorStatus(TEST_MESSAGE, null);\n\t\tReflectionTestUtils.setField(outdatedStatus, \"timestamp\", System.currentTimeMillis() - 300);\n\t\tthis.statusManager.add(outdatedStatus);\n\t\taddStatus(false, () -> new InfoStatus(TEST_MESSAGE, null));\n\t\tassertThat(output.getOut()).isEmpty();\n\t\tassertThat(output.getErr()).isEmpty();\n\t}\n\n\tprivate void addStatus(boolean debug, Supplier<Status> statusFactory) {\n\t\tSystemStatusListener.addTo(this.loggerContext, debug);\n\t\tStatusListener listener = this.statusManager.getCopyOfStatusListenerList().get(0);\n\t\tassertThat(listener).extracting(\"context\").isSameAs(this.loggerContext);\n\t\tlistener.addStatusEvent(statusFactory.get());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/logback/WhitespaceThrowableProxyConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.logback;\n\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.classic.spi.ThrowableProxy;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WhitespaceThrowableProxyConverter}.\n *\n * @author Phillip Webb\n * @author Chanwit Kaewkasi\n */\nclass WhitespaceThrowableProxyConverterTests {\n\n\tprivate final WhitespaceThrowableProxyConverter converter = new WhitespaceThrowableProxyConverter();\n\n\tprivate final LoggingEvent event = new LoggingEvent();\n\n\t@Test\n\tvoid noStackTrace() {\n\t\tString s = this.converter.convert(this.event);\n\t\tassertThat(s).isEmpty();\n\t}\n\n\t@Test\n\tvoid withStackTrace() {\n\t\tthis.event.setThrowableProxy(new ThrowableProxy(new RuntimeException()));\n\t\tString s = this.converter.convert(this.event);\n\t\tassertThat(s).startsWith(System.lineSeparator()).endsWith(System.lineSeparator());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/CommonStructuredLogFormatTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CommonStructuredLogFormat}.\n *\n * @author Phillip Webb\n */\nclass CommonStructuredLogFormatTests {\n\n\t@Test\n\tvoid forIdReturnsCommonStructuredLogFormat() {\n\t\tassertThat(CommonStructuredLogFormat.forId(\"ecs\")).isEqualTo(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA);\n\t\tassertThat(CommonStructuredLogFormat.forId(\"logstash\")).isEqualTo(CommonStructuredLogFormat.LOGSTASH);\n\t}\n\n\t@Test\n\tvoid forIdWhenIdIsInDifferentCaseReturnsCommonStructuredLogFormat() {\n\t\tassertThat(CommonStructuredLogFormat.forId(\"ECS\")).isEqualTo(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA);\n\t\tassertThat(CommonStructuredLogFormat.forId(\"logSTAsh\")).isEqualTo(CommonStructuredLogFormat.LOGSTASH);\n\t}\n\n\t@Test\n\tvoid forIdWhenNotKnownReturnsNull() {\n\t\tassertThat(CommonStructuredLogFormat.forId(\"madeup\")).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/ContextPairsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ContextPairs}.\n *\n * @author Phillip Webb\n */\nclass ContextPairsTests {\n\n\t@Test\n\tvoid flatWhenIncludeFalseDoesNothing() {\n\t\tContextPairs contextPairs = new ContextPairs(false, null);\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(contextPairs.flat(\".\", (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).isEmpty();\n\t}\n\n\t@Test\n\tvoid flatIncludesName() {\n\t\tContextPairs contextPairs = new ContextPairs(true, null);\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(contextPairs.flat(\".\", (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).containsExactlyEntriesOf(map);\n\t}\n\n\t@Test\n\tvoid flatWhenPrefixAppliesPrefix() {\n\t\tContextPairs contextPairs = new ContextPairs(true, \"the\");\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(contextPairs.flat(\"_\", (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).containsOnly(entry(\"the_spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid flatWhenPrefixEndingWithDelimiterAppliesPrefix() {\n\t\tContextPairs contextPairs = new ContextPairs(true, \"the_\");\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(contextPairs.flat(\"_\", (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).containsOnly(entry(\"the_spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid flatWhenPrefixAndNameStartingWithDelimiterAppliesPrefix() {\n\t\tContextPairs contextPairs = new ContextPairs(true, \"the\");\n\t\tMap<String, String> map = Map.of(\"_spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(contextPairs.flat(\"_\", (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).containsOnly(entry(\"the_spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid flatWhenJoinerJoins() {\n\t\tContextPairs contextPairs = new ContextPairs(true, \"the\");\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(\n\t\t\t\tcontextPairs.flat((prefix, name) -> prefix + name, (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).containsOnly(entry(\"thespring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid flatWhenJoinerReturnsNullFilters() {\n\t\tContextPairs contextPairs = new ContextPairs(true, \"the\");\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(\n\t\t\t\tcontextPairs.flat((prefix, name) -> null, (pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).isEmpty();\n\t}\n\n\t@Test\n\tvoid nestedWhenIncludeFalseDoesNothing() {\n\t\tContextPairs contextPairs = new ContextPairs(false, null);\n\t\tMap<String, String> map = Map.of(\"spring\", \"boot\");\n\t\tMap<String, Object> actual = apply(contextPairs.nested((pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tassertThat(actual).isEmpty();\n\t}\n\n\t@Test\n\tvoid nestedExpandsNames() {\n\t\tContextPairs contextPairs = new ContextPairs(true, null);\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"a1.b1.c1\", \"A1B1C1\");\n\t\tmap.put(\"a1.b2.c1\", \"A1B2C1\");\n\t\tmap.put(\"a1.b1.c2\", \"A1B1C2\");\n\t\tMap<String, Object> actual = apply(contextPairs.nested((pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\tMap<String, Object> a1 = new LinkedHashMap<>();\n\t\tMap<String, Object> b1 = new LinkedHashMap<>();\n\t\tMap<String, Object> b2 = new LinkedHashMap<>();\n\t\texpected.put(\"a1\", a1);\n\t\ta1.put(\"b1\", b1);\n\t\ta1.put(\"b2\", b2);\n\t\tb1.put(\"c1\", \"A1B1C1\");\n\t\tb1.put(\"c2\", \"A1B1C2\");\n\t\tb2.put(\"c1\", \"A1B2C1\");\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid nestedWhenNameEndsWithDelimiterDropsTrailingDelimiter() {\n\t\tContextPairs contextPairs = new ContextPairs(true, null);\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"a1.b1.\", \"A1B1\");\n\t\tMap<String, Object> actual = apply(contextPairs.nested((pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\tMap<String, Object> a1 = new LinkedHashMap<>();\n\t\texpected.put(\"a1\", a1);\n\t\ta1.put(\"b1\", \"A1B1\");\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid nestedWhenDuplicateInParentThrowsException() {\n\t\tContextPairs contextPairs = new ContextPairs(true, null);\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"a1.b1.c1\", \"A1B1C1\");\n\t\tmap.put(\"a1.b1\", \"A1B1\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> apply(contextPairs.nested((pairs) -> pairs.addMapEntries((item) -> map))))\n\t\t\t.withMessage(\"Duplicate nested pairs added under 'a1.b1'\");\n\t}\n\n\t@Test\n\tvoid nestedWhenDuplicateInLeafThrowsException() {\n\t\tContextPairs contextPairs = new ContextPairs(true, null);\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"a1.b1\", \"A1B1\");\n\t\tmap.put(\"a1.b1.c1\", \"A1B1C1\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> apply(contextPairs.nested((pairs) -> pairs.addMapEntries((item) -> map))))\n\t\t\t.withMessage(\"Duplicate nested pairs added under 'a1.b1'\");\n\t}\n\n\t@Test\n\tvoid nestedWhenPrefixAppliesPrefix() {\n\t\tContextPairs contextPairs = new ContextPairs(true, \"a1\");\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"b1.c1\", \"A1B1C1\");\n\t\tmap.put(\"b2.c1\", \"A1B2C1\");\n\t\tmap.put(\"b1.c2\", \"A1B1C2\");\n\t\tMap<String, Object> actual = apply(contextPairs.nested((pairs) -> pairs.addMapEntries((item) -> map)));\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\tMap<String, Object> a1 = new LinkedHashMap<>();\n\t\tMap<String, Object> b1 = new LinkedHashMap<>();\n\t\tMap<String, Object> b2 = new LinkedHashMap<>();\n\t\texpected.put(\"a1\", a1);\n\t\ta1.put(\"b1\", b1);\n\t\ta1.put(\"b2\", b2);\n\t\tb1.put(\"c1\", \"A1B1C1\");\n\t\tb1.put(\"c2\", \"A1B1C2\");\n\t\tb2.put(\"c1\", \"A1B2C1\");\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\tMap<String, Object> apply(BiConsumer<?, BiConsumer<String, Object>> action) {\n\t\tMap<String, Object> result = new LinkedHashMap<>();\n\t\taction.accept(null, result::put);\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/ElasticCommonSchemaPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.logging.structured.ElasticCommonSchemaProperties.ElasticCommonSchemaPropertiesRuntimeHints;\nimport org.springframework.boot.logging.structured.ElasticCommonSchemaProperties.Service;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ElasticCommonSchemaProperties}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass ElasticCommonSchemaPropertiesTests {\n\n\t@Test\n\tvoid getBindsFromEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.ecs.service.name\", \"spring\");\n\t\tenvironment.setProperty(\"logging.structured.ecs.service.version\", \"1.2.3\");\n\t\tenvironment.setProperty(\"logging.structured.ecs.service.environment\", \"prod\");\n\t\tenvironment.setProperty(\"logging.structured.ecs.service.node-name\", \"boot\");\n\t\tElasticCommonSchemaProperties properties = ElasticCommonSchemaProperties.get(environment);\n\t\tassertThat(properties)\n\t\t\t.isEqualTo(new ElasticCommonSchemaProperties(new Service(\"spring\", \"1.2.3\", \"prod\", \"boot\")));\n\t}\n\n\t@Test\n\tvoid getWhenNoServiceNameUsesApplicationName() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.application.name\", \"spring\");\n\t\tElasticCommonSchemaProperties properties = ElasticCommonSchemaProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new ElasticCommonSchemaProperties(new Service(\"spring\", null, null, null)));\n\t}\n\n\t@Test\n\tvoid getWhenNoServiceVersionUsesApplicationVersion() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.application.version\", \"1.2.3\");\n\t\tElasticCommonSchemaProperties properties = ElasticCommonSchemaProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new ElasticCommonSchemaProperties(new Service(null, \"1.2.3\", null, null)));\n\t}\n\n\t@Test\n\tvoid getWhenNoPropertiesToBind() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tElasticCommonSchemaProperties properties = ElasticCommonSchemaProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new ElasticCommonSchemaProperties(new Service(null, null, null, null)));\n\t}\n\n\t@Test\n\tvoid addToJsonMembersCreatesValidJson() {\n\t\tElasticCommonSchemaProperties properties = new ElasticCommonSchemaProperties(\n\t\t\t\tnew Service(\"spring\", \"1.2.3\", \"prod\", \"boot\"));\n\t\tJsonWriter<ElasticCommonSchemaProperties> writer = JsonWriter.of(properties::jsonMembers);\n\t\tassertThat(writer.writeToString(properties)).isEqualToNormalizingNewlines(\"\"\"\n\t\t\t\t{\n\t\t\t\t  \"service\": {\n\t\t\t\t    \"name\": \"spring\",\n\t\t\t\t    \"version\": \"1.2.3\",\n\t\t\t\t    \"environment\": \"prod\",\n\t\t\t\t    \"node\": {\n\t\t\t\t      \"name\": \"boot\"\n\t\t\t\t    }\n\t\t\t\t  }\n\t\t\t\t}\"\"\".replaceAll(\"\\\\s+\", \"\"));\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHints() throws Exception {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ElasticCommonSchemaPropertiesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ElasticCommonSchemaProperties.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onConstructorInvocation(ElasticCommonSchemaProperties.class.getConstructor(Service.class))).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Service.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onConstructorInvocation(\n\t\t\t\t\tService.class.getConstructor(String.class, String.class, String.class, String.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid elasticCommonSchemaPropertiesRuntimeHintsIsRegistered() {\n\t\tassertThat(AotServices.factories().load(RuntimeHintsRegistrar.class))\n\t\t\t.anyMatch(ElasticCommonSchemaPropertiesRuntimeHints.class::isInstance);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/GraylogExtendedLogFormatPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.logging.structured.GraylogExtendedLogFormatProperties.GraylogExtendedLogFormatPropertiesRuntimeHints;\nimport org.springframework.boot.logging.structured.GraylogExtendedLogFormatProperties.Service;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraylogExtendedLogFormatProperties}.\n *\n * @author Samuel Lissner\n * @author Phillip Webb\n */\nclass GraylogExtendedLogFormatPropertiesTests {\n\n\t@Test\n\tvoid getBindsFromEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.gelf.host\", \"spring\");\n\t\tenvironment.setProperty(\"logging.structured.gelf.service.version\", \"1.2.3\");\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(\"spring\", new Service(\"1.2.3\")));\n\t}\n\n\t@Test\n\tvoid getBindsFromEnvironmentWhenHostIsPresentAndServiceIsMissing() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.gelf.host\", \"spring\");\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(\"spring\", new Service(null)));\n\t}\n\n\t@Test\n\tvoid getBindsFromEnvironmentWhenHostIsPresentAndServiceIsMissingUsesApplicationVersion() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.gelf.host\", \"spring\");\n\t\tenvironment.setProperty(\"spring.application.version\", \"1.2.3\");\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(\"spring\", new Service(\"1.2.3\")));\n\t}\n\n\t@Test\n\tvoid getBindsFromEnvironmentWhenVersionIsPresentAndHostIsMissingUsesApplicationName() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.application.name\", \"spring\");\n\t\tenvironment.setProperty(\"logging.structured.gelf.service.version\", \"1.2.3\");\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(\"spring\", new Service(\"1.2.3\")));\n\t}\n\n\t@Test\n\tvoid getWhenNoServiceNameUsesApplicationName() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.application.name\", \"spring\");\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(\"spring\", new Service(null)));\n\t}\n\n\t@Test\n\tvoid getWhenNoServiceVersionUsesApplicationVersion() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.application.version\", \"1.2.3\");\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(null, new Service(\"1.2.3\")));\n\t}\n\n\t@Test\n\tvoid getWhenNoPropertiesToBind() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tGraylogExtendedLogFormatProperties properties = GraylogExtendedLogFormatProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new GraylogExtendedLogFormatProperties(null, new Service(null)));\n\t}\n\n\t@Test\n\tvoid addToJsonMembersCreatesValidJson() {\n\t\tGraylogExtendedLogFormatProperties properties = new GraylogExtendedLogFormatProperties(\"spring\",\n\t\t\t\tnew Service(\"1.2.3\"));\n\t\tJsonWriter<GraylogExtendedLogFormatProperties> writer = JsonWriter.of(properties::jsonMembers);\n\t\tassertThat(writer.writeToString(properties)).isEqualTo(\"{\\\"host\\\":\\\"spring\\\",\\\"_service_version\\\":\\\"1.2.3\\\"}\");\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHints() throws Exception {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew GraylogExtendedLogFormatPropertiesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(GraylogExtendedLogFormatProperties.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onConstructorInvocation(\n\t\t\t\t\tGraylogExtendedLogFormatProperties.class.getConstructor(String.class, Service.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Service.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onConstructorInvocation(GraylogExtendedLogFormatProperties.Service.class.getConstructor(String.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid graylogExtendedLogFormatPropertiesRuntimeHintsIsRegistered() {\n\t\tassertThat(AotServices.factories().load(RuntimeHintsRegistrar.class))\n\t\t\t.anyMatch(GraylogExtendedLogFormatPropertiesRuntimeHints.class::isInstance);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/MockStructuredLoggingJsonMembersCustomizerBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer.Builder;\n\n/**\n * Mock {@link StructuredLoggingJsonMembersCustomizer.Builder}.\n *\n * @param <T> the type being written\n * @author Phillip Webb\n */\npublic class MockStructuredLoggingJsonMembersCustomizerBuilder<T>\n\t\timplements StructuredLoggingJsonMembersCustomizer.Builder<T> {\n\n\tprivate final Supplier<StructuredLoggingJsonMembersCustomizer<T>> customizerSupplier;\n\n\tpublic MockStructuredLoggingJsonMembersCustomizerBuilder(\n\t\t\tSupplier<StructuredLoggingJsonMembersCustomizer<T>> customizerSupplier) {\n\t\tthis.customizerSupplier = customizerSupplier;\n\t}\n\n\tprivate boolean nested;\n\n\t@Override\n\tpublic Builder<T> nested(boolean nested) {\n\t\tthis.nested = nested;\n\t\treturn this;\n\t}\n\n\tpublic boolean isNested() {\n\t\treturn this.nested;\n\t}\n\n\t@Override\n\tpublic StructuredLoggingJsonMembersCustomizer<T> build() {\n\t\treturn this.customizerSupplier.get();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLogFormatterFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.json.JsonWriter.ValueProcessor;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.StandardStackTracePrinter;\nimport org.springframework.boot.logging.structured.StructuredLogFormatterFactory.CommonFormatters;\nimport org.springframework.boot.util.Instantiator.AvailableParameters;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StructuredLogFormatterFactory}.\n *\n * @author Phillip Webb\n */\nclass StructuredLogFormatterFactoryTests {\n\n\tprivate final StructuredLogFormatterFactory<LogEvent> factory;\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tStructuredLogFormatterFactoryTests() {\n\t\tthis.environment.setProperty(\"logging.structured.ecs.service.version\", \"1.2.3\");\n\t\tthis.factory = new StructuredLogFormatterFactory<>(LogEvent.class, this.environment,\n\t\t\t\tthis::addAvailableParameters, this::addCommonFormatters);\n\t}\n\n\tprivate void addAvailableParameters(AvailableParameters availableParameters) {\n\t\tavailableParameters.add(StringBuilder.class, new StringBuilder(\"Hello\"));\n\t}\n\n\tprivate void addCommonFormatters(CommonFormatters<LogEvent> commonFormatters) {\n\t\tcommonFormatters.add(CommonStructuredLogFormat.ELASTIC_COMMON_SCHEMA, (instantiator) -> {\n\t\t\tEnvironment environment = instantiator.getArg(Environment.class);\n\t\t\tassertThat(environment).isNotNull();\n\t\t\tStackTracePrinter stackTracePrinter = instantiator.getArg(StackTracePrinter.class);\n\t\t\tStringBuilder stringBuilder = instantiator.getArg(StringBuilder.class);\n\t\t\tassertThat(stringBuilder).isNotNull();\n\t\t\treturn new TestEcsFormatter(environment, stackTracePrinter, stringBuilder);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getUsingCommonFormat() {\n\t\tassertThat(this.factory.get(\"ecs\")).isInstanceOf(TestEcsFormatter.class);\n\t}\n\n\t@Test\n\tvoid getUsingClassName() {\n\t\tassertThat(this.factory.get(ExtendedTestEcsFormatter.class.getName()))\n\t\t\t.isInstanceOf(ExtendedTestEcsFormatter.class);\n\t}\n\n\t@Test\n\tvoid getUsingClassNameWhenNoSuchClass() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> assertThat(this.factory.get(\"com.example.WeMadeItUp\")).isNull())\n\t\t\t.withMessage(\"Unknown format 'com.example.WeMadeItUp'. \"\n\t\t\t\t\t+ \"Values can be a valid fully-qualified class name or one of the common formats: [ecs]\");\n\t}\n\n\t@Test\n\tvoid getUsingClassNameWhenHasGenericMismatch() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.factory.get(DifferentFormatter.class.getName()))\n\t\t\t.withMessage(\"Type argument of org.springframework.boot.logging.structured.\"\n\t\t\t\t\t+ \"StructuredLogFormatterFactoryTests$DifferentFormatter \"\n\t\t\t\t\t+ \"must be org.springframework.boot.logging.structured.\"\n\t\t\t\t\t+ \"StructuredLogFormatterFactoryTests$LogEvent \"\n\t\t\t\t\t+ \"but was org.springframework.boot.logging.structured.\"\n\t\t\t\t\t+ \"StructuredLogFormatterFactoryTests$DifferentLogEvent\");\n\t}\n\n\t@Test\n\tvoid getUsingClassNameInjectsEnvironment() {\n\t\tTestEcsFormatter formatter = (TestEcsFormatter) this.factory.get(TestEcsFormatter.class.getName());\n\t\tassertThat(formatter.getEnvironment()).isSameAs(this.environment);\n\t}\n\n\t@Test\n\tvoid getUsingClassNameInjectsStackTracePrinter() {\n\t\tthis.environment.setProperty(\"logging.structured.json.stacktrace.printer\", \"standard\");\n\t\tStructuredLogFormatterFactory<LogEvent> factory = new StructuredLogFormatterFactory<>(LogEvent.class,\n\t\t\t\tthis.environment, this::addAvailableParameters, this::addCommonFormatters);\n\t\tTestEcsFormatter formatter = (TestEcsFormatter) factory.get(TestEcsFormatter.class.getName());\n\t\tassertThat(formatter.getStackTracePrinter()).isInstanceOf(StandardStackTracePrinter.class);\n\t}\n\n\t@Test\n\tvoid getUsingClassNameInjectsCustomParameter() {\n\t\tTestEcsFormatter formatter = (TestEcsFormatter) this.factory.get(TestEcsFormatter.class.getName());\n\t\tassertThat(formatter.getCustom()).hasToString(\"Hello\");\n\t}\n\n\t@Test\n\tvoid getInjectStringMembersCustomizer() {\n\t\tthis.environment.setProperty(\"logging.structured.json.rename.spring\", \"test\");\n\t\tSpringFactoriesLoader factoriesLoader = mock(SpringFactoriesLoader.class);\n\t\tgiven(factoriesLoader.load(any(), any(ArgumentResolver.class)))\n\t\t\t.willReturn(List.of(new StringMembersStructuredLoggingJsonMembersCustomizer()));\n\t\tStructuredLogFormatterFactory<LogEvent> factory = new StructuredLogFormatterFactory<>(factoriesLoader,\n\t\t\t\tLogEvent.class, this.environment, this::addAvailableParameters, this::addCommonFormatters);\n\t\tCustomizedFormatter formatter = (CustomizedFormatter) factory.get(CustomizedFormatter.class.getName());\n\t\tassertThat(formatter.format(new LogEvent())).contains(\"\\\"test\\\":\\\"BOOT\\\"\");\n\t}\n\n\t@Test\n\tvoid getInjectObjectMembersCustomizer() {\n\t\tthis.environment.setProperty(\"logging.structured.json.rename.spring\", \"test\");\n\t\tSpringFactoriesLoader factoriesLoader = mock(SpringFactoriesLoader.class);\n\t\tgiven(factoriesLoader.load(any(), any(ArgumentResolver.class)))\n\t\t\t.willReturn(List.of(new ObjectMembersStructuredLoggingJsonMembersCustomizer()));\n\t\tStructuredLogFormatterFactory<LogEvent> factory = new StructuredLogFormatterFactory<>(factoriesLoader,\n\t\t\t\tLogEvent.class, this.environment, this::addAvailableParameters, this::addCommonFormatters);\n\t\tCustomizedFormatter formatter = (CustomizedFormatter) factory.get(CustomizedFormatter.class.getName());\n\t\tassertThat(formatter.format(new LogEvent())).contains(\"\\\"test\\\":\\\"BOOT\\\"\");\n\t}\n\n\tstatic class StringMembersStructuredLoggingJsonMembersCustomizer\n\t\t\timplements StructuredLoggingJsonMembersCustomizer<String> {\n\n\t\t@Override\n\t\tpublic void customize(Members<String> members) {\n\t\t\tUnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) ? string.toUpperCase(Locale.ROOT)\n\t\t\t\t\t: null;\n\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));\n\t\t}\n\n\t}\n\n\tstatic class ObjectMembersStructuredLoggingJsonMembersCustomizer\n\t\t\timplements StructuredLoggingJsonMembersCustomizer<Object> {\n\n\t\t@Override\n\t\tpublic void customize(Members<Object> members) {\n\t\t\tUnaryOperator<@Nullable String> toUpperCase = (string) -> (string != null) ? string.toUpperCase(Locale.ROOT)\n\t\t\t\t\t: null;\n\t\t\tmembers.applyingValueProcessor(ValueProcessor.of(String.class, toUpperCase));\n\t\t}\n\n\t}\n\n\tstatic class LogEvent {\n\n\t}\n\n\tstatic class DifferentLogEvent {\n\n\t}\n\n\tstatic class TestEcsFormatter implements StructuredLogFormatter<LogEvent> {\n\n\t\tprivate final Environment environment;\n\n\t\tprivate final @Nullable StackTracePrinter stackTracePrinter;\n\n\t\tprivate final StringBuilder custom;\n\n\t\tTestEcsFormatter(Environment environment, @Nullable StackTracePrinter stackTracePrinter, StringBuilder custom) {\n\t\t\tthis.environment = environment;\n\t\t\tthis.stackTracePrinter = stackTracePrinter;\n\t\t\tthis.custom = custom;\n\t\t}\n\n\t\t@Override\n\t\tpublic String format(LogEvent event) {\n\t\t\treturn \"formatted \" + this.environment.getProperty(\"logging.structured.ecs.service.version\");\n\t\t}\n\n\t\tEnvironment getEnvironment() {\n\t\t\treturn this.environment;\n\t\t}\n\n\t\t@Nullable StackTracePrinter getStackTracePrinter() {\n\t\t\treturn this.stackTracePrinter;\n\t\t}\n\n\t\tStringBuilder getCustom() {\n\t\t\treturn this.custom;\n\t\t}\n\n\t}\n\n\tstatic class ExtendedTestEcsFormatter extends TestEcsFormatter {\n\n\t\tExtendedTestEcsFormatter(Environment environment, StackTracePrinter stackTracePrinter, StringBuilder custom) {\n\t\t\tsuper(environment, stackTracePrinter, custom);\n\t\t}\n\n\t}\n\n\tstatic class DifferentFormatter implements StructuredLogFormatter<DifferentLogEvent> {\n\n\t\t@Override\n\t\tpublic String format(DifferentLogEvent event) {\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n\n\tstatic class CustomizedFormatter extends JsonWriterStructuredLogFormatter<LogEvent> {\n\n\t\tCustomizedFormatter(StructuredLoggingJsonMembersCustomizer<?> customizer) {\n\t\t\tsuper((members) -> members.add(\"spring\", \"boot\"), customizer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor}.\n *\n * @author Dmytro Nosan\n */\nclass StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorTests {\n\n\t@Test\n\tvoid structuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessorIsRegistered() {\n\t\tassertThat(AotServices.factories().load(BeanFactoryInitializationAotProcessor.class))\n\t\t\t.anyMatch(StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor.class::isInstance);\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHintsWhenCustomizerIsPresent() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.json.customizer\", TestCustomizer.class.getName());\n\n\t\tBeanFactoryInitializationAotContribution contribution = getContribution(environment);\n\t\tassertThat(contribution).isNotNull();\n\n\t\tRuntimeHints hints = getRuntimeHints(contribution);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TestCustomizer.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,\n\t\t\t\t\tMemberCategory.INVOKE_PUBLIC_CONSTRUCTORS))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHintsWhenCustomStackTracePrinterIsPresent() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.printer\", TestStackTracePrinter.class.getName());\n\n\t\tBeanFactoryInitializationAotContribution contribution = getContribution(environment);\n\t\tassertThat(contribution).isNotNull();\n\n\t\tRuntimeHints hints = getRuntimeHints(contribution);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TestStackTracePrinter.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,\n\t\t\t\t\tMemberCategory.INVOKE_PUBLIC_CONSTRUCTORS))\n\t\t\t.accepts(hints);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"logging-system\", \"standard\" })\n\tvoid shouldNotRegisterRuntimeHintsWhenStackTracePrinterIsNotCustomImplementation(String printer) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.printer\", printer);\n\n\t\tBeanFactoryInitializationAotContribution contribution = getContribution(environment);\n\t\tassertThat(contribution).isNull();\n\t}\n\n\t@Test\n\tvoid shouldNotRegisterRuntimeHintsWhenPropertiesAreNotSet() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tBeanFactoryInitializationAotContribution contribution = getContribution(environment);\n\t\tassertThat(contribution).isNull();\n\t}\n\n\t@Test\n\tvoid shouldNotRegisterRuntimeHintsWhenCustomizerAndPrinterAreNotSet() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"logging.structured.json.exclude\", \"something\");\n\t\tBeanFactoryInitializationAotContribution contribution = getContribution(environment);\n\t\tassertThat(contribution).isNull();\n\t}\n\n\tprivate @Nullable BeanFactoryInitializationAotContribution getContribution(ConfigurableEnvironment environment) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.setEnvironment(environment);\n\t\t\tcontext.refresh();\n\t\t\treturn new StructuredLoggingJsonPropertiesBeanFactoryInitializationAotProcessor()\n\t\t\t\t.processAheadOfTime(context.getBeanFactory());\n\t\t}\n\t}\n\n\tprivate RuntimeHints getRuntimeHints(BeanFactoryInitializationAotContribution contribution) {\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tcontribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));\n\t\treturn generationContext.getRuntimeHints();\n\t}\n\n\tstatic class TestCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {\n\n\t\t@Override\n\t\tpublic void customize(Members<String> members) {\n\t\t}\n\n\t}\n\n\tstatic class TestStackTracePrinter implements StackTracePrinter {\n\n\t\t@Override\n\t\tpublic void printStackTrace(Throwable throwable, Appendable out) throws IOException {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesJsonMembersCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.json.JsonWriter.NameProcessor;\nimport org.springframework.boot.util.Instantiator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link StructuredLoggingJsonPropertiesJsonMembersCustomizer}.\n *\n * @author Phillip Webb\n * @author Yanming Zhou\n */\n@ExtendWith(MockitoExtension.class)\nclass StructuredLoggingJsonPropertiesJsonMembersCustomizerTests {\n\n\t@Mock\n\t@SuppressWarnings({ \"rawtypes\", \"NullAway.Init\" })\n\tprivate Instantiator instantiator;\n\n\t@Test\n\tvoid customizeWhenHasExcludeFiltersMember() {\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),\n\t\t\t\tSet.of(\"a\"), Collections.emptyMap(), Collections.emptyMap(), null, null, null);\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).doesNotContain(\"a\").contains(\"b\");\n\t}\n\n\t@Test\n\tvoid customizeWhenHasIncludeFiltersOtherMembers() {\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Set.of(\"a\"),\n\t\t\t\tCollections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null, null);\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"a\")\n\t\t\t.doesNotContain(\"b\")\n\t\t\t.doesNotContain(\"c\")\n\t\t\t.doesNotContain(\"d\");\n\t}\n\n\t@Test\n\tvoid customizeWhenHasIncludeAndExcludeFiltersMembers() {\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Set.of(\"a\", \"b\"), Set.of(\"b\"),\n\t\t\t\tCollections.emptyMap(), Collections.emptyMap(), null, null, null);\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"a\")\n\t\t\t.doesNotContain(\"b\")\n\t\t\t.doesNotContain(\"c\")\n\t\t\t.doesNotContain(\"d\");\n\t}\n\n\t@Test\n\tvoid customizeWhenHasRenameRenamesMember() {\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),\n\t\t\t\tCollections.emptySet(), Map.of(\"a\", \"z\"), Collections.emptyMap(), null, null, null);\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"\\\"z\\\":\\\"a\\\"\");\n\t}\n\n\t@Test\n\tvoid customizeWhenHasAddAddsMember() {\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),\n\t\t\t\tCollections.emptySet(), Collections.emptyMap(), Map.of(\"z\", \"z\"), null, null, null);\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"\\\"z\\\":\\\"z\\\"\");\n\t}\n\n\t@Test\n\tvoid customizeWhenHasNestedAddAddsMember() {\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),\n\t\t\t\tCollections.emptySet(), Collections.emptyMap(), Map.of(\"y.z\", \"yz\"), null, null, null);\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, true);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"\\\"y\\\":{\\\"z\\\":\\\"yz\\\"}\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeWhenHasCustomizerCustomizesMember() {\n\t\tStructuredLoggingJsonMembersCustomizer<?> uppercaseCustomizer = (members) -> members\n\t\t\t.applyingNameProcessor(NameProcessor.of(String::toUpperCase));\n\t\tgiven(this.instantiator.instantiateType(TestCustomizer.class)).willReturn(uppercaseCustomizer);\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),\n\t\t\t\tCollections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null,\n\t\t\t\tSet.of(TestCustomizer.class));\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"\\\"A\\\":\\\"a\\\"\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeWhenHasCustomizersCustomizesMember() {\n\t\tgiven(this.instantiator.instantiateType(FooCustomizer.class)).willReturn(new FooCustomizer());\n\t\tgiven(this.instantiator.instantiateType(BarCustomizer.class)).willReturn(new BarCustomizer());\n\t\tStructuredLoggingJsonProperties properties = new StructuredLoggingJsonProperties(Collections.emptySet(),\n\t\t\t\tCollections.emptySet(), Collections.emptyMap(), Collections.emptyMap(), null, null,\n\t\t\t\tSet.of(FooCustomizer.class, BarCustomizer.class));\n\t\tStructuredLoggingJsonPropertiesJsonMembersCustomizer customizer = new StructuredLoggingJsonPropertiesJsonMembersCustomizer(\n\t\t\t\tthis.instantiator, properties, false);\n\t\tassertThat(writeSampleJson(customizer)).contains(\"\\\"foo\\\":\\\"foo\\\"\").contains(\"\\\"bar\\\":\\\"bar\\\"\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate String writeSampleJson(StructuredLoggingJsonMembersCustomizer customizer) {\n\t\treturn JsonWriter.of((members) -> {\n\t\t\tmembers.add(\"a\", \"a\");\n\t\t\tmembers.add(\"b\", \"b\");\n\t\t\tmembers.add(\"c\", \"c\");\n\t\t\tcustomizer.customize(members);\n\t\t}).writeToString(new Object());\n\t}\n\n\tstatic class TestCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {\n\n\t\t@Override\n\t\tpublic void customize(Members<String> members) {\n\t\t}\n\n\t}\n\n\tstatic class FooCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {\n\n\t\t@Override\n\t\tpublic void customize(Members<String> members) {\n\t\t\tmembers.add(\"foo\", \"foo\");\n\t\t}\n\n\t}\n\n\tstatic class BarCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {\n\n\t\t@Override\n\t\tpublic void customize(Members<String> members) {\n\t\t\tmembers.add(\"bar\", \"bar\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/StructuredLoggingJsonPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.logging.StackTracePrinter;\nimport org.springframework.boot.logging.StandardStackTracePrinter;\nimport org.springframework.boot.logging.TestException;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.Context;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StackTrace.Root;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonProperties.StructuredLoggingJsonPropertiesRuntimeHints;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StructuredLoggingJsonProperties}.\n *\n * @author Phillip Webb\n */\nclass StructuredLoggingJsonPropertiesTests {\n\n\t@Test\n\tvoid getWhenHasNoStackTracePropertiesBindsFromEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tsetupJsonProperties(environment);\n\t\tStructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);\n\t\tassertThat(properties).isEqualTo(new StructuredLoggingJsonProperties(Set.of(\"a\", \"b\"), Set.of(\"c\", \"d\"),\n\t\t\t\tMap.of(\"e\", \"f\"), Map.of(\"g\", \"h\"), null, null, Set.of(TestCustomizer.class)));\n\t}\n\n\t@Test\n\tvoid getWhenHasStackTracePropertiesBindsFromEnvironment() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tsetupJsonProperties(environment);\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.printer\", \"standard\");\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.root\", \"first\");\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.max-length\", \"1024\");\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.max-throwable-depth\", \"5\");\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.include-common-frames\", \"true\");\n\t\tenvironment.setProperty(\"logging.structured.json.stacktrace.include-hashes\", \"true\");\n\t\tStructuredLoggingJsonProperties properties = StructuredLoggingJsonProperties.get(environment);\n\t\tassertThat(properties).isNotNull();\n\t\tassertThat(properties.stackTrace())\n\t\t\t.isEqualTo(new StructuredLoggingJsonProperties.StackTrace(\"standard\", Root.FIRST, 1024, 5, true, true));\n\t}\n\n\tprivate void setupJsonProperties(MockEnvironment environment) {\n\t\tenvironment.setProperty(\"logging.structured.json.include\", \"a,b\");\n\t\tenvironment.setProperty(\"logging.structured.json.exclude\", \"c,d\");\n\t\tenvironment.setProperty(\"logging.structured.json.rename.e\", \"f\");\n\t\tenvironment.setProperty(\"logging.structured.json.add.g\", \"h\");\n\t\tenvironment.setProperty(\"logging.structured.json.customizer\", TestCustomizer.class.getName());\n\t}\n\n\t@Test\n\tvoid getWhenNoBoundPropertiesReturnsNull() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tStructuredLoggingJsonProperties.get(environment);\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHints() throws Exception {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew StructuredLoggingJsonPropertiesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(StructuredLoggingJsonProperties.class)).accepts(hints);\n\t\tassertThat(\n\t\t\t\tRuntimeHintsPredicates.reflection()\n\t\t\t\t\t.onConstructorInvocation(StructuredLoggingJsonProperties.class.getDeclaredConstructor(Set.class,\n\t\t\t\t\t\t\tSet.class, Map.class, Map.class, StackTrace.class, Context.class, Set.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onConstructorInvocation(StackTrace.class.getDeclaredConstructor(String.class, Root.class, Integer.class,\n\t\t\t\t\tInteger.class, Boolean.class, Boolean.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onConstructorInvocation(Context.class.getDeclaredConstructor(boolean.class, String.class))).accepts(hints);\n\t}\n\n\t@Test\n\tvoid structuredLoggingJsonPropertiesRuntimeHintsIsRegistered() {\n\t\tassertThat(AotServices.factories().load(RuntimeHintsRegistrar.class))\n\t\t\t.anyMatch(StructuredLoggingJsonPropertiesRuntimeHints.class::isInstance);\n\t}\n\n\t@Nested\n\tclass StackTraceTests {\n\n\t\t@Test\n\t\tvoid createPrinterWhenEmptyReturnsNull() {\n\t\t\tStackTrace properties = new StackTrace(null, null, null, null, null, null);\n\t\t\tassertThat(properties.createPrinter()).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenNoPrinterAndNotEmptyReturnsStandard() {\n\t\t\tStackTrace properties = new StackTrace(null, Root.LAST, null, null, null, null);\n\t\t\tassertThat(properties.createPrinter()).isInstanceOf(StandardStackTracePrinter.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenLoggingSystemReturnsNull() {\n\t\t\tStackTrace properties = new StackTrace(\"logging-system\", null, null, null, null, null);\n\t\t\tassertThat(properties.createPrinter()).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenLoggingSystemRelaxedReturnsNull() {\n\t\t\tStackTrace properties = new StackTrace(\"LoggingSystem\", null, null, null, null, null);\n\t\t\tassertThat(properties.createPrinter()).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenStandardReturnsStandardPrinter() {\n\t\t\tStackTrace properties = new StackTrace(\"standard\", null, null, null, null, null);\n\t\t\tassertThat(properties.createPrinter()).isInstanceOf(StandardStackTracePrinter.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenStandardRelaxedReturnsStandardPrinter() {\n\t\t\tStackTrace properties = new StackTrace(\"STANDARD\", null, null, null, null, null);\n\t\t\tassertThat(properties.createPrinter()).isInstanceOf(StandardStackTracePrinter.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenStandardAppliesCustomizations() {\n\t\t\tException exception = TestException.create();\n\t\t\tStackTrace properties = new StackTrace(null, Root.FIRST, 300, 2, true, false);\n\t\t\tStandardStackTracePrinter printer = (StandardStackTracePrinter) properties.createPrinter();\n\t\t\tassertThat(printer).isNotNull();\n\t\t\tprinter = printer.withLineSeparator(\"\\n\");\n\t\t\tString actual = TestException.withoutLineNumbers(printer.printStackTraceToString(exception));\n\t\t\tassertThat(actual).isEqualToNormalizingNewlines(\"\"\"\n\t\t\t\t\tjava.lang.RuntimeException: root\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException.createTestException(TestException.java:NN)\n\t\t\t\t\t\tat org.springframework.boot.logging.TestException$CreatorThread.run(TestException.java:NN)\n\t\t\t\t\tWrapped by: java.lang.RuntimeException: cause\n\t\t\t\t\t\tat org.springframework.boot.log...\"\"\");\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenStandardWithHashesPrintsHash() {\n\t\t\tException exception = TestException.create();\n\t\t\tStackTrace properties = new StackTrace(null, null, null, null, null, true);\n\t\t\tStackTracePrinter printer = properties.createPrinter();\n\t\t\tassertThat(printer).isNotNull();\n\t\t\tString actual = printer.printStackTraceToString(exception);\n\t\t\tassertThat(actual).containsPattern(\"<#[0-9a-z]{8}>\");\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenClassNameCreatesPrinter() {\n\t\t\tException exception = TestException.create();\n\t\t\tStackTrace properties = new StackTrace(TestStackTracePrinter.class.getName(), null, null, null, true, null);\n\t\t\tStackTracePrinter printer = properties.createPrinter();\n\t\t\tassertThat(printer).isNotNull();\n\t\t\tassertThat(printer.printStackTraceToString(exception)).isEqualTo(\"java.lang.RuntimeException: exception\");\n\t\t}\n\n\t\t@Test\n\t\tvoid createPrinterWhenClassNameInjectsConfiguredPrinter() {\n\t\t\tException exception = TestException.create();\n\t\t\tStackTrace properties = new StackTrace(TestStackTracePrinterCustomized.class.getName(), Root.FIRST, 300, 2,\n\t\t\t\t\ttrue, null);\n\t\t\tStackTracePrinter printer = properties.createPrinter();\n\t\t\tassertThat(printer).isNotNull();\n\t\t\tString actual = TestException.withoutLineNumbers(printer.printStackTraceToString(exception));\n\t\t\tassertThat(actual).isEqualTo(\"RuntimeExceptionroot!\tat org.springfr...\");\n\t\t}\n\n\t\t@Test\n\t\tvoid hasCustomPrinterShouldReturnFalseWhenPrinterIsEmpty() {\n\t\t\tStackTrace stackTrace = new StackTrace(\"\", null, null, null, null, null);\n\t\t\tassertThat(stackTrace.hasCustomPrinter()).isFalse();\n\t\t}\n\n\t\t@Test\n\t\tvoid hasCustomPrinterShouldReturnFalseWhenPrinterHasLoggingSystem() {\n\t\t\tStackTrace stackTrace = new StackTrace(\"loggingsystem\", null, null, null, null, null);\n\t\t\tassertThat(stackTrace.hasCustomPrinter()).isFalse();\n\t\t}\n\n\t\t@Test\n\t\tvoid hasCustomPrinterShouldReturnFalseWhenPrinterHasStandard() {\n\t\t\tStackTrace stackTrace = new StackTrace(\"standard\", null, null, null, null, null);\n\t\t\tassertThat(stackTrace.hasCustomPrinter()).isFalse();\n\t\t}\n\n\t\t@Test\n\t\tvoid hasCustomPrinterShouldReturnTrueWhenPrinterHasCustom() {\n\t\t\tStackTrace stackTrace = new StackTrace(\"custom-printer\", null, null, null, null, null);\n\t\t\tassertThat(stackTrace.hasCustomPrinter()).isTrue();\n\t\t}\n\n\t}\n\n\tstatic class TestCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {\n\n\t\t@Override\n\t\tpublic void customize(Members<String> members) {\n\t\t}\n\n\t}\n\n\tstatic class TestStackTracePrinter implements StackTracePrinter {\n\n\t\t@Override\n\t\tpublic void printStackTrace(Throwable throwable, Appendable out) throws IOException {\n\t\t\tout.append(throwable.toString());\n\t\t}\n\n\t}\n\n\tstatic class TestStackTracePrinterCustomized implements StackTracePrinter {\n\n\t\tprivate final StandardStackTracePrinter printer;\n\n\t\tTestStackTracePrinterCustomized(StandardStackTracePrinter printer) {\n\t\t\tthis.printer = printer.withMaximumLength(40)\n\t\t\t\t.withLineSeparator(\"!\")\n\t\t\t\t.withFormatter((throwable) -> ClassUtils.getShortName(throwable.getClass()) + throwable.getMessage());\n\t\t}\n\n\t\t@Override\n\t\tpublic void printStackTrace(Throwable throwable, Appendable out) throws IOException {\n\t\t\tthis.printer.printStackTrace(throwable, out);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/logging/structured/TestContextPairs.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.logging.structured;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Test access to {@link ContextPairs}.\n *\n * @author Phillip Webb\n */\npublic final class TestContextPairs {\n\n\tprivate TestContextPairs() {\n\t}\n\n\tpublic static ContextPairs include() {\n\t\treturn of(true, null);\n\t}\n\n\tpublic static ContextPairs of(boolean include, @Nullable String prefix) {\n\t\treturn new ContextPairs(include, prefix);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/JarUriTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JarUri}.\n *\n * @author Phillip Webb\n */\nclass JarUriTests {\n\n\t@Test\n\tvoid describeBootInfClassesUri() {\n\t\tJarUri uri = JarUri.from(\"jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar\"\n\t\t\t\t+ \"!/BOOT-INF/classes!/application.properties\");\n\t\tassertThat(uri).isNotNull();\n\t\tassertThat(uri.getDescription()).isEqualTo(\"project-0.0.1-SNAPSHOT.jar\");\n\t}\n\n\t@Test\n\tvoid describeBootInfLibUri() {\n\t\tJarUri uri = JarUri.from(\"jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar\"\n\t\t\t\t+ \"!/BOOT-INF/lib/nested.jar!/application.properties\");\n\t\tassertThat(uri).isNotNull();\n\t\tassertThat(uri.getDescription()).isEqualTo(\"project-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/nested.jar\");\n\t}\n\n\t@Test\n\tvoid describeRegularJar() {\n\t\tJarUri uri = JarUri\n\t\t\t.from(\"jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar!/application.properties\");\n\t\tassertThat(uri).isNotNull();\n\t\tassertThat(uri.getDescription()).isEqualTo(\"project-0.0.1-SNAPSHOT.jar\");\n\t}\n\n\t@Test\n\tvoid getDescriptionMergedWithExisting() {\n\t\tJarUri uri = JarUri.from(\"jar:file:/project-0.0.1-SNAPSHOT.jar!/application.properties\");\n\t\tassertThat(uri).isNotNull();\n\t\tassertThat(uri.getDescription(\"classpath: [application.properties]\"))\n\t\t\t.isEqualTo(\"classpath: [application.properties] from project-0.0.1-SNAPSHOT.jar\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/MockOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\n\n/**\n * Mock {@link Origin} implementation used for testing.\n *\n * @author Phillip Webb\n */\npublic final class MockOrigin implements Origin {\n\n\tprivate final String value;\n\n\tprivate final @Nullable Origin parent;\n\n\tprivate MockOrigin(String value, @Nullable Origin parent) {\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\tthis.value = value;\n\t\tthis.parent = parent;\n\t}\n\n\t@Override\n\tpublic @Nullable Origin getParent() {\n\t\treturn this.parent;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.value.equals(((MockOrigin) obj).value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tpublic static @Nullable Origin of(@Nullable String value) {\n\t\treturn of(value, null);\n\t}\n\n\t@Contract(\"!null, _ -> !null\")\n\tpublic static @Nullable Origin of(@Nullable String value, @Nullable Origin parent) {\n\t\treturn (value != null) ? new MockOrigin(value, parent) : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/OriginLookupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OriginLookup}.\n *\n * @author Phillip Webb\n */\nclass OriginLookupTests {\n\n\t@Test\n\tvoid getOriginWhenSourceIsNullShouldReturnNull() {\n\t\tassertThat(OriginLookup.getOrigin(null, \"foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid getOriginWhenSourceIsNotLookupShouldReturnLookupOrigin() {\n\t\tObject source = new Object();\n\t\tassertThat(OriginLookup.getOrigin(source, \"foo\")).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getOriginWhenSourceIsLookupShouldReturnLookupOrigin() {\n\t\tOriginLookup<String> source = mock(OriginLookup.class);\n\t\tOrigin origin = MockOrigin.of(\"bar\");\n\t\tgiven(source.getOrigin(\"foo\")).willReturn(origin);\n\t\tassertThat(OriginLookup.getOrigin(source, \"foo\")).isEqualTo(origin);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getOriginWhenSourceLookupThrowsAndErrorShouldReturnNull() {\n\t\tOriginLookup<String> source = mock(OriginLookup.class);\n\t\twillThrow(RuntimeException.class).given(source).getOrigin(\"foo\");\n\t\tassertThat(OriginLookup.getOrigin(source, \"foo\")).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Origin}.\n *\n * @author Phillip Webb\n */\nclass OriginTests {\n\n\t@Test\n\tvoid getParentWhenDefaultIsNull() {\n\t\tOrigin origin = new Origin() {\n\t\t};\n\t\tassertThat(origin.getParent()).isNull();\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsNullReturnsNull() {\n\t\tassertThat(Origin.from(null)).isNull();\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsRegularObjectReturnsNull() {\n\t\tObject source = new Object();\n\t\tassertThat(Origin.from(source)).isNull();\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsOriginReturnsSource() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tassertThat(Origin.from(origin)).isEqualTo(origin);\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsOriginProviderReturnsProvidedOrigin() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tOriginProvider originProvider = mock(OriginProvider.class);\n\t\tgiven(originProvider.getOrigin()).willReturn(origin);\n\t\tassertThat(Origin.from(origin)).isEqualTo(origin);\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsThrowableUsesCause() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tException exception = new RuntimeException(new TestException(origin, null));\n\t\tassertThat(Origin.from(exception)).isEqualTo(origin);\n\t}\n\n\t@Test\n\tvoid fromWhenSourceIsThrowableAndOriginProviderThatReturnsNullUsesCause() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tException exception = new TestException(null, new TestException(origin, null));\n\t\tassertThat(Origin.from(exception)).isEqualTo(origin);\n\t}\n\n\t@Test\n\tvoid parentsFromWhenSourceIsNullReturnsEmptyList() {\n\t\tassertThat(Origin.parentsFrom(null)).isEmpty();\n\t}\n\n\t@Test\n\tvoid parentsFromReturnsParents() {\n\t\tOrigin o1 = MockOrigin.of(\"1\");\n\t\tOrigin o2 = MockOrigin.of(\"2\", o1);\n\t\tOrigin o3 = MockOrigin.of(\"3\", o2);\n\t\tList<Origin> parents = Origin.parentsFrom(o3);\n\t\tassertThat(parents).containsExactly(o2, o1);\n\t}\n\n\tstatic class TestException extends RuntimeException implements OriginProvider {\n\n\t\tprivate final @Nullable Origin origin;\n\n\t\tTestException(@Nullable Origin origin, @Nullable Throwable cause) {\n\t\t\tsuper(cause);\n\t\t\tthis.origin = origin;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getOrigin() {\n\t\t\treturn this.origin;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTrackedResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.io.IOException;\nimport java.nio.channels.ReadableByteChannel;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.OriginTrackedResource.OriginTrackedWritableResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.WritableResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OriginTrackedResource}.\n *\n * @author Phillip Webb\n */\nclass OriginTrackedResourceTests {\n\n\tprivate Origin origin;\n\n\tprivate WritableResource resource;\n\n\tprivate OriginTrackedWritableResource tracked;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.origin = MockOrigin.of(\"test\");\n\t\tthis.resource = mock(WritableResource.class);\n\t\tthis.tracked = OriginTrackedResource.of(this.resource, this.origin);\n\t}\n\n\t@Test\n\tvoid getInputStreamDelegatesToResource() throws IOException {\n\t\tthis.tracked.getInputStream();\n\t\tthen(this.resource).should().getInputStream();\n\t}\n\n\t@Test\n\tvoid existsDelegatesToResource() {\n\t\tthis.tracked.exists();\n\t\tthen(this.resource).should().exists();\n\t}\n\n\t@Test\n\tvoid isReadableDelegatesToResource() {\n\t\tthis.tracked.isReadable();\n\t\tthen(this.resource).should().isReadable();\n\t}\n\n\t@Test\n\tvoid isOpenDelegatesToResource() {\n\t\tthis.tracked.isOpen();\n\t\tthen(this.resource).should().isOpen();\n\t}\n\n\t@Test\n\tvoid isFileDelegatesToResource() {\n\t\tthis.tracked.isFile();\n\t\tthen(this.resource).should().isFile();\n\t}\n\n\t@Test\n\tvoid getURLDelegatesToResource() throws IOException {\n\t\tthis.tracked.getURL();\n\t\tthen(this.resource).should().getURL();\n\t}\n\n\t@Test\n\tvoid getURIDelegatesToResource() throws IOException {\n\t\tthis.tracked.getURI();\n\t\tthen(this.resource).should().getURI();\n\t}\n\n\t@Test\n\tvoid getFileDelegatesToResource() throws IOException {\n\t\tthis.tracked.getFile();\n\t\tthen(this.resource).should().getFile();\n\t}\n\n\t@Test\n\tvoid readableChannelDelegatesToResource() throws IOException {\n\t\ttry (ReadableByteChannel ignore = this.tracked.readableChannel()) {\n\t\t\tthen(this.resource).should().readableChannel();\n\t\t}\n\t}\n\n\t@Test\n\tvoid contentLengthDelegatesToResource() throws IOException {\n\t\tthis.tracked.contentLength();\n\t\tthen(this.resource).should().contentLength();\n\t}\n\n\t@Test\n\tvoid lastModifiedDelegatesToResource() throws IOException {\n\t\tthis.tracked.lastModified();\n\t\tthen(this.resource).should().lastModified();\n\t}\n\n\t@Test\n\tvoid createRelativeDelegatesToResource() throws IOException {\n\t\tthis.tracked.createRelative(\"path\");\n\t\tthen(this.resource).should().createRelative(\"path\");\n\t}\n\n\t@Test\n\tvoid getFilenameDelegatesToResource() {\n\t\tthis.tracked.getFilename();\n\t\tthen(this.resource).should().getFilename();\n\t}\n\n\t@Test\n\tvoid getDescriptionDelegatesToResource() {\n\t\tthis.tracked.getDescription();\n\t\tthen(this.resource).should().getDescription();\n\t}\n\n\t@Test\n\tvoid getOutputStreamDelegatesToResource() throws IOException {\n\t\tthis.tracked.getOutputStream();\n\t\tthen(this.resource).should().getOutputStream();\n\t}\n\n\t@Test\n\tvoid toStringDelegatesToResource() {\n\t\tResource resource = new ClassPathResource(\"test\");\n\t\tResource tracked = OriginTrackedResource.of(resource, this.origin);\n\t\tassertThat(tracked).hasToString(resource.toString());\n\t}\n\n\t@Test\n\tvoid getOriginReturnsOrigin() {\n\t\tassertThat(this.tracked.getOrigin()).isEqualTo(this.origin);\n\t}\n\n\t@Test\n\tvoid getResourceReturnsResource() {\n\t\tassertThat(this.tracked.getResource()).isEqualTo(this.resource);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tOrigin o1 = MockOrigin.of(\"o1\");\n\t\tOrigin o2 = MockOrigin.of(\"o2\");\n\t\tResource r1 = mock(Resource.class);\n\t\tResource r2 = mock(Resource.class);\n\t\tOriginTrackedResource r1o1a = OriginTrackedResource.of(r1, o1);\n\t\tOriginTrackedResource r1o1b = OriginTrackedResource.of(r1, o1);\n\t\tOriginTrackedResource r1o2 = OriginTrackedResource.of(r1, o2);\n\t\tOriginTrackedResource r2o1 = OriginTrackedResource.of(r2, o1);\n\t\tOriginTrackedResource r2o2 = OriginTrackedResource.of(r2, o2);\n\t\tassertThat(r1o1a).isEqualTo(r1o1a).isEqualTo(r1o1a).isNotEqualTo(r1o2).isNotEqualTo(r2o1).isNotEqualTo(r2o2);\n\t\tassertThat(r1o1a).hasSameHashCodeAs(r1o1b);\n\t}\n\n\t@Test\n\tvoid ofReturnsOriginTrackedResource() {\n\t\tResource resource = mock(Resource.class);\n\t\tResource tracked = OriginTrackedResource.of(resource, this.origin);\n\t\tassertThat(tracked).isExactlyInstanceOf(OriginTrackedResource.class);\n\t}\n\n\t@Test\n\tvoid ofWhenWritableReturnsOriginTrackedWritableResource() {\n\t\tResource resource = mock(WritableResource.class);\n\t\tResource tracked = OriginTrackedResource.of(resource, this.origin);\n\t\tassertThat(tracked).isInstanceOf(WritableResource.class)\n\t\t\t.isExactlyInstanceOf(OriginTrackedWritableResource.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/OriginTrackedValueTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OriginTrackedValue}.\n *\n * @author Phillip Webb\n */\nclass OriginTrackedValueTests {\n\n\t@Test\n\tvoid getValueShouldReturnValue() {\n\t\tObject value = new Object();\n\t\tassertThat(OriginTrackedValue.of(value).getValue()).isEqualTo(value);\n\t}\n\n\t@Test\n\tvoid getOriginShouldReturnOrigin() {\n\t\tObject value = new Object();\n\t\tOrigin origin = mock(Origin.class);\n\t\tassertThat(OriginTrackedValue.of(value, origin).getOrigin()).isEqualTo(origin);\n\t}\n\n\t@Test\n\tvoid toStringShouldReturnValueToString() {\n\t\tObject value = new Object();\n\t\tassertThat(OriginTrackedValue.of(value)).hasToString(value.toString());\n\t}\n\n\t@Test\n\tvoid hashCodeAndEqualsShouldIgnoreOrigin() {\n\t\tObject value1 = new Object();\n\t\tOriginTrackedValue tracked1 = OriginTrackedValue.of(value1);\n\t\tOriginTrackedValue tracked2 = OriginTrackedValue.of(value1, mock(Origin.class));\n\t\tOriginTrackedValue tracked3 = OriginTrackedValue.of(new Object());\n\t\tassertThat(tracked1).hasSameHashCodeAs(tracked2);\n\t\tassertThat(tracked1).isEqualTo(tracked1).isEqualTo(tracked2).isNotEqualTo(tracked3);\n\t}\n\n\t@Test\n\tvoid ofWhenValueIsNullShouldReturnNull() {\n\t\tassertThat(OriginTrackedValue.of(null)).isNull();\n\t\tassertThat(OriginTrackedValue.of(null, mock(Origin.class))).isNull();\n\t}\n\n\t@Test\n\tvoid ofWhenValueIsCharSequenceShouldReturnCharSequence() {\n\t\tString value = \"foo\";\n\t\tOriginTrackedValue tracked = OriginTrackedValue.of(value);\n\t\tassertThat(tracked).isInstanceOf(CharSequence.class);\n\t\tCharSequence charSequence = (CharSequence) tracked;\n\t\tassertThat(charSequence).hasSameSizeAs(value);\n\t\tassertThat(charSequence.charAt(0)).isEqualTo(value.charAt(0));\n\t\tassertThat(charSequence.subSequence(0, 1)).isEqualTo(value.subSequence(0, 1));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/PropertySourceOriginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.util.HashMap;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link PropertySourceOrigin}.\n *\n * @author Phillip Webb\n */\nclass PropertySourceOriginTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertySourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new PropertySourceOrigin(null, \"name\"))\n\t\t\t.withMessageContaining(\"'propertySource' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertyNameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PropertySourceOrigin(mock(PropertySource.class), null))\n\t\t\t.withMessageContaining(\"'propertyName' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenPropertyNameIsEmptyShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new PropertySourceOrigin(mock(PropertySource.class), \"\"))\n\t\t\t.withMessageContaining(\"'propertyName' must not be empty\");\n\t}\n\n\t@Test\n\tvoid getPropertySourceShouldReturnPropertySource() {\n\t\tMapPropertySource propertySource = new MapPropertySource(\"test\", new HashMap<>());\n\t\tPropertySourceOrigin origin = new PropertySourceOrigin(propertySource, \"foo\");\n\t\tassertThat(origin.getPropertySource()).isEqualTo(propertySource);\n\t}\n\n\t@Test\n\tvoid getPropertyNameShouldReturnPropertyName() {\n\t\tMapPropertySource propertySource = new MapPropertySource(\"test\", new HashMap<>());\n\t\tPropertySourceOrigin origin = new PropertySourceOrigin(propertySource, \"foo\");\n\t\tassertThat(origin.getPropertyName()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid toStringShouldShowDetails() {\n\t\tMapPropertySource propertySource = new MapPropertySource(\"test\", new HashMap<>());\n\t\tPropertySourceOrigin origin = new PropertySourceOrigin(propertySource, \"foo\");\n\t\tassertThat(origin).hasToString(\"\\\"foo\\\" from property source \\\"test\\\"\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getWhenPropertySourceSupportsOriginLookupShouldReturnOrigin() {\n\t\tOrigin origin = mock(Origin.class);\n\t\tPropertySource<?> propertySource = mock(PropertySource.class,\n\t\t\t\twithSettings().extraInterfaces(OriginLookup.class));\n\t\tOriginLookup<String> originCapablePropertySource = (OriginLookup<String>) propertySource;\n\t\tgiven(originCapablePropertySource.getOrigin(\"foo\")).willReturn(origin);\n\t\tOrigin actual = PropertySourceOrigin.get(propertySource, \"foo\");\n\t\tassertThat(actual).hasToString(origin.toString());\n\t\tassertThat(((PropertySourceOrigin) actual).getOrigin()).isSameAs(origin);\n\t}\n\n\t@Test\n\tvoid getWhenPropertySourceSupportsOriginLookupButNoOriginShouldWrap() {\n\t\tPropertySource<?> propertySource = mock(PropertySource.class,\n\t\t\t\twithSettings().extraInterfaces(OriginLookup.class));\n\t\tassertThat(PropertySourceOrigin.get(propertySource, \"foo\")).isInstanceOf(PropertySourceOrigin.class);\n\t}\n\n\t@Test\n\tvoid getWhenPropertySourceIsNotOriginAwareShouldWrap() {\n\t\tMapPropertySource propertySource = new MapPropertySource(\"test\", new HashMap<>());\n\t\tPropertySourceOrigin origin = new PropertySourceOrigin(propertySource, \"foo\");\n\t\tassertThat(origin.getPropertySource()).isEqualTo(propertySource);\n\t\tassertThat(origin.getPropertyName()).isEqualTo(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/SystemEnvironmentOriginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link SystemEnvironmentOrigin}.\n *\n * @author Madhura Bhave\n */\nclass SystemEnvironmentOriginTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertyIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new SystemEnvironmentOrigin(null))\n\t\t\t.withMessage(\"'property' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenPropertyNameIsEmptyShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new SystemEnvironmentOrigin(\"\"))\n\t\t\t.withMessage(\"'property' must not be empty\");\n\t}\n\n\t@Test\n\tvoid getPropertyShouldReturnProperty() {\n\t\tSystemEnvironmentOrigin origin = new SystemEnvironmentOrigin(\"FOO_BAR\");\n\t\tassertThat(origin.getProperty()).isEqualTo(\"FOO_BAR\");\n\t}\n\n\t@Test\n\tvoid toStringShouldReturnStringWithDetails() {\n\t\tSystemEnvironmentOrigin origin = new SystemEnvironmentOrigin(\"FOO_BAR\");\n\t\tassertThat(origin).hasToString(\"System Environment Property \\\"FOO_BAR\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/origin/TextResourceOriginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.origin;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TextResourceOrigin}.\n *\n * @author Phillip Webb\n */\nclass TextResourceOriginTests {\n\n\t@Test\n\tvoid createWithNullResourceSetsNullResource() {\n\t\tTextResourceOrigin origin = new TextResourceOrigin(null, null);\n\t\tassertThat(origin.getResource()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithNullLocationSetsNullLocation() {\n\t\tTextResourceOrigin origin = new TextResourceOrigin(null, null);\n\t\tassertThat(origin.getLocation()).isNull();\n\t}\n\n\t@Test\n\tvoid getResourceReturnResource() {\n\t\tClassPathResource resource = new ClassPathResource(\"foo.txt\");\n\t\tTextResourceOrigin origin = new TextResourceOrigin(resource, null);\n\t\tassertThat(origin.getResource()).isEqualTo(resource);\n\t}\n\n\t@Test\n\tvoid getLocationReturnsLocation() {\n\t\tLocation location = new Location(1, 2);\n\t\tTextResourceOrigin origin = new TextResourceOrigin(null, location);\n\t\tassertThat(origin.getLocation()).isEqualTo(location);\n\t}\n\n\t@Test\n\tvoid getParentWhenResourceIsNotOriginTrackedReturnsNull() {\n\t\tClassPathResource resource = new ClassPathResource(\"foo.txt\");\n\t\tTextResourceOrigin origin = new TextResourceOrigin(resource, null);\n\t\tassertThat(origin.getParent()).isNull();\n\t}\n\n\t@Test\n\tvoid getParentWhenResourceIsOriginTrackedReturnsResourceOrigin() {\n\t\tOrigin resourceOrigin = MockOrigin.of(\"test\");\n\t\tResource resource = OriginTrackedResource.of(new ClassPathResource(\"foo.txt\"), resourceOrigin);\n\t\tTextResourceOrigin origin = new TextResourceOrigin(resource, null);\n\t\tassertThat(origin.getParent()).isSameAs(resourceOrigin);\n\t}\n\n\t@Test\n\tvoid getLocationLineReturnsLine() {\n\t\tLocation location = new Location(1, 2);\n\t\tassertThat(location.getLine()).isOne();\n\t}\n\n\t@Test\n\tvoid getLocationColumnReturnsColumn() {\n\t\tLocation location = new Location(1, 2);\n\t\tassertThat(location.getColumn()).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid locationToStringReturnsNiceString() {\n\t\tLocation location = new Location(1, 2);\n\t\tassertThat(location).hasToString(\"2:3\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsNiceString() {\n\t\tClassPathResource resource = new ClassPathResource(\"foo.txt\");\n\t\tLocation location = new Location(1, 2);\n\t\tTextResourceOrigin origin = new TextResourceOrigin(resource, location);\n\t\tassertThat(origin).hasToString(\"class path resource [foo.txt] - 2:3\");\n\t}\n\n\t@Test\n\tvoid toStringWhenResourceIsNullReturnsNiceString() {\n\t\tLocation location = new Location(1, 2);\n\t\tTextResourceOrigin origin = new TextResourceOrigin(null, location);\n\t\tassertThat(origin).hasToString(\"unknown resource [?] - 2:3\");\n\t}\n\n\t@Test\n\tvoid toStringWhenLocationIsNullReturnsNiceString() {\n\t\tClassPathResource resource = new ClassPathResource(\"foo.txt\");\n\t\tTextResourceOrigin origin = new TextResourceOrigin(resource, null);\n\t\tassertThat(origin).hasToString(\"class path resource [foo.txt]\");\n\t}\n\n\t@Test\n\tvoid toStringWhenResourceIsClasspathResourceReturnsToStringWithJar() {\n\t\tClassPathResource resource = new ClassPathResource(\"foo.txt\") {\n\n\t\t\t@Override\n\t\t\tpublic URI getURI() throws IOException {\n\t\t\t\ttry {\n\t\t\t\t\treturn new URI(\"jar:file:/home/user/project/target/project-0.0.1-SNAPSHOT.jar\"\n\t\t\t\t\t\t\t+ \"!/BOOT-INF/classes!/foo.txt\");\n\t\t\t\t}\n\t\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t};\n\t\tLocation location = new Location(1, 2);\n\t\tTextResourceOrigin origin = new TextResourceOrigin(resource, location);\n\t\tassertThat(origin).hasToString(\"class path resource [foo.txt] from project-0.0.1-SNAPSHOT.jar - 2:3\");\n\t}\n\n\t@Test\n\tvoid locationEqualsAndHashCodeUsesLineAndColumn() {\n\t\tLocation location1 = new Location(1, 2);\n\t\tLocation location2 = new Location(1, 2);\n\t\tLocation location3 = new Location(2, 2);\n\t\tassertThat(location1).hasSameHashCodeAs(location1);\n\t\tassertThat(location1).hasSameHashCodeAs(location2);\n\t\tassertThat(location1.hashCode()).isNotEqualTo(location3.hashCode());\n\t\tassertThat(location1).isEqualTo(location1);\n\t\tassertThat(location1).isEqualTo(location2);\n\t\tassertThat(location1).isNotEqualTo(location3);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCodeUsesResourceAndLocation() {\n\t\tTextResourceOrigin origin1 = new TextResourceOrigin(new ClassPathResource(\"foo.txt\"), new Location(1, 2));\n\t\tTextResourceOrigin origin2 = new TextResourceOrigin(new ClassPathResource(\"foo.txt\"), new Location(1, 2));\n\t\tTextResourceOrigin origin3 = new TextResourceOrigin(new ClassPathResource(\"foo.txt\"), new Location(2, 2));\n\t\tTextResourceOrigin origin4 = new TextResourceOrigin(new ClassPathResource(\"foo2.txt\"), new Location(1, 2));\n\t\tassertThat(origin1).hasSameHashCodeAs(origin1);\n\t\tassertThat(origin1).hasSameHashCodeAs(origin2);\n\t\tassertThat(origin1.hashCode()).isNotEqualTo(origin3.hashCode());\n\t\tassertThat(origin1.hashCode()).isNotEqualTo(origin4.hashCode());\n\t\tassertThat(origin1).isEqualTo(origin1);\n\t\tassertThat(origin1).isEqualTo(origin2);\n\t\tassertThat(origin1).isNotEqualTo(origin3);\n\t\tassertThat(origin1).isNotEqualTo(origin4);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/retry/RetryPolicySettingsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.retry;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.retry.RetryPolicy;\nimport org.springframework.util.backoff.BackOff;\nimport org.springframework.util.backoff.ExponentialBackOff;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RetryPolicySettings}.\n *\n * @author Stephane Nicoll\n */\nclass RetryPolicySettingsTests {\n\n\t@Test\n\tvoid exceptionIncludesCanBeReplaced() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.getExceptionIncludes().add(IllegalStateException.class);\n\t\tsettings.setExceptionIncludes(List.of(IllegalArgumentException.class));\n\t\tassertThat(settings.getExceptionIncludes()).containsExactly(IllegalArgumentException.class);\n\t}\n\n\t@Test\n\tvoid exceptionIncludesListIsCopied() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tList<Class<? extends Throwable>> includes = new ArrayList<>();\n\t\tincludes.add(IllegalStateException.class);\n\t\tsettings.setExceptionIncludes(includes);\n\t\tincludes.add(IllegalArgumentException.class);\n\t\tassertThat(settings.getExceptionIncludes()).containsExactly(IllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithExceptionIncludes() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.getExceptionIncludes().add(IllegalStateException.class);\n\t\tRetryPolicy retryPolicy = settings.createRetryPolicy();\n\t\tassertThat(retryPolicy.shouldRetry(new IllegalStateException(\"test\"))).isTrue();\n\t\tassertThat(retryPolicy.shouldRetry(new IllegalArgumentException(\"test\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid exceptionExcludesCanBeReplaced() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.getExceptionExcludes().add(IllegalStateException.class);\n\t\tsettings.setExceptionExcludes(List.of(IllegalArgumentException.class));\n\t\tassertThat(settings.getExceptionExcludes()).containsExactly(IllegalArgumentException.class);\n\t}\n\n\t@Test\n\tvoid exceptionExcludesListIsCopied() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tList<Class<? extends Throwable>> excludes = new ArrayList<>();\n\t\texcludes.add(IllegalStateException.class);\n\t\tsettings.setExceptionExcludes(excludes);\n\t\texcludes.add(IllegalArgumentException.class);\n\t\tassertThat(settings.getExceptionExcludes()).containsExactly(IllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithExceptionExcludes() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.getExceptionExcludes().add(IllegalStateException.class);\n\t\tRetryPolicy retryPolicy = settings.createRetryPolicy();\n\t\tassertThat(retryPolicy.shouldRetry(new IllegalStateException(\"test\"))).isFalse();\n\t\tassertThat(retryPolicy.shouldRetry(new IllegalArgumentException(\"test\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid getDefaultExceptionPredicate() {\n\t\tassertThat(new RetryPolicySettings().getExceptionPredicate()).isNull();\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithExceptionPredicate() {\n\t\tIllegalArgumentException exception = new IllegalArgumentException(\"test\");\n\t\tPredicate<Throwable> exceptionPredicate = mock();\n\t\tgiven(exceptionPredicate.test(exception)).willReturn(true);\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.setExceptionPredicate(exceptionPredicate);\n\t\tRetryPolicy retryPolicy = settings.createRetryPolicy();\n\t\tassertThat(retryPolicy.shouldRetry(exception)).isTrue();\n\t\tthen(exceptionPredicate).should().test(exception);\n\t\tthen(exceptionPredicate).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithDefaultsMatchesBackOffDefaults() {\n\t\tRetryPolicy defaultRetryPolicy = RetryPolicy.builder().build();\n\t\tRetryPolicy retryPolicy = new RetryPolicySettings().createRetryPolicy();\n\t\tassertThat(retryPolicy.getBackOff()).isInstanceOf(ExponentialBackOff.class);\n\t\tExponentialBackOff defaultBackOff = (ExponentialBackOff) defaultRetryPolicy.getBackOff();\n\t\tExponentialBackOff backOff = (ExponentialBackOff) retryPolicy.getBackOff();\n\t\tassertThat(backOff.getMaxAttempts()).isEqualTo(defaultBackOff.getMaxAttempts());\n\t\tassertThat(backOff.getInitialInterval()).isEqualTo(defaultBackOff.getInitialInterval());\n\t\tassertThat(backOff.getJitter()).isEqualTo(defaultBackOff.getJitter());\n\t\tassertThat(backOff.getMultiplier()).isEqualTo(defaultBackOff.getMultiplier());\n\t\tassertThat(backOff.getMaxInterval()).isEqualTo(defaultBackOff.getMaxInterval());\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithCustomAttributes() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.setMaxRetries(10L);\n\t\tsettings.setDelay(Duration.ofSeconds(2));\n\t\tsettings.setJitter(Duration.ofMillis(500));\n\t\tsettings.setMultiplier(2.0);\n\t\tsettings.setMaxDelay(Duration.ofSeconds(20));\n\t\tRetryPolicy retryPolicy = settings.createRetryPolicy();\n\t\tassertThat(retryPolicy.getBackOff()).isInstanceOfSatisfying(ExponentialBackOff.class, (backOff) -> {\n\t\t\tassertThat(backOff.getMaxAttempts()).isEqualTo(10);\n\t\t\tassertThat(backOff.getInitialInterval()).isEqualTo(2000);\n\t\t\tassertThat(backOff.getJitter()).isEqualTo(500);\n\t\t\tassertThat(backOff.getMultiplier()).isEqualTo(2.0);\n\t\t\tassertThat(backOff.getMaxInterval()).isEqualTo(20_000);\n\t\t});\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithFactoryCanOverrideAttribute() {\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.setDelay(Duration.ofSeconds(2));\n\t\tsettings.setMultiplier(2.0);\n\t\tsettings.setFactory((builder) -> builder.multiplier(3.0).build());\n\t\tRetryPolicy retryPolicy = settings.createRetryPolicy();\n\t\tassertThat(retryPolicy.getBackOff()).isInstanceOfSatisfying(ExponentialBackOff.class, (backOff) -> {\n\t\t\tassertThat(backOff.getInitialInterval()).isEqualTo(2000L);\n\t\t\tassertThat(backOff.getMultiplier()).isEqualTo(3.0);\n\t\t});\n\t}\n\n\t@Test\n\tvoid createRetryPolicyWithFactoryCanIgnoreBuilder() {\n\t\tBackOff backOff = mock(BackOff.class);\n\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\tsettings.setFactory((builder) -> RetryPolicy.builder().backOff(backOff).build());\n\t\tRetryPolicy retryPolicy = settings.createRetryPolicy();\n\t\tassertThat(retryPolicy.getBackOff()).isEqualTo(backOff);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/sampleconfig/MyComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sampleconfig;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyComponent {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/sampleconfig/MyNamedComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sampleconfig;\n\nimport jakarta.inject.Named;\n\n@Named\npublic class MyNamedComponent {\n\n\tMyNamedComponent() {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/sampleconfig/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sample config for tests\n */\n@NullMarked\npackage org.springframework.boot.sampleconfig;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/AliasKeyManagerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.util.Arrays;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.X509ExtendedKeyManager;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AliasKeyManagerFactory}.\n *\n * @author Phillip Webb\n */\nclass AliasKeyManagerFactoryTests {\n\n\t@Test\n\tvoid chooseEngineServerAliasReturnsAlias() throws Exception {\n\t\tKeyManagerFactory delegate = mock(KeyManagerFactory.class);\n\t\tgiven(delegate.getKeyManagers()).willReturn(new KeyManager[] { mock(X509ExtendedKeyManager.class) });\n\t\tAliasKeyManagerFactory factory = new AliasKeyManagerFactory(delegate, \"test-alias\",\n\t\t\t\tKeyManagerFactory.getDefaultAlgorithm());\n\t\tfactory.init(null, null);\n\t\tKeyManager[] keyManagers = factory.getKeyManagers();\n\t\tX509ExtendedKeyManager x509KeyManager = (X509ExtendedKeyManager) Arrays.stream(keyManagers)\n\t\t\t.filter(X509ExtendedKeyManager.class::isInstance)\n\t\t\t.findAny()\n\t\t\t.get();\n\t\tString chosenAlias = x509KeyManager.chooseEngineServerAlias(null, null, null);\n\t\tassertThat(chosenAlias).isEqualTo(\"test-alias\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslBundleRegistryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.awaitility.Awaitility;\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultSslBundleRegistry}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass DefaultSslBundleRegistryTests {\n\n\tprivate final SslBundle bundle1 = mock(SslBundle.class);\n\n\tprivate final SslBundle bundle2 = mock(SslBundle.class);\n\n\tprivate DefaultSslBundleRegistry registry;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.registry = new DefaultSslBundleRegistry();\n\t}\n\n\t@Test\n\tvoid createWithNameAndBundleRegistersBundle() {\n\t\tDefaultSslBundleRegistry registry = new DefaultSslBundleRegistry(\"test\", this.bundle1);\n\t\tassertThat(registry.getBundle(\"test\")).isSameAs(this.bundle1);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerBundleWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerBundle(null, this.bundle1))\n\t\t\t.withMessage(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerBundleWhenBundleIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerBundle(\"test\", null))\n\t\t\t.withMessage(\"'bundle' must not be null\");\n\t}\n\n\t@Test\n\tvoid registerBundleWhenNameIsTakenThrowsException() {\n\t\tthis.registry.registerBundle(\"test\", this.bundle1);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.registry.registerBundle(\"test\", this.bundle2))\n\t\t\t.withMessage(\"Cannot replace existing SSL bundle 'test'\");\n\t}\n\n\t@Test\n\tvoid registerBundleRegistersBundle() {\n\t\tthis.registry.registerBundle(\"test\", this.bundle1);\n\t\tassertThat(this.registry.getBundle(\"test\")).isSameAs(this.bundle1);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getBundleWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.registry.getBundle(null))\n\t\t\t.withMessage(\"'name' must not be null\");\n\t}\n\n\t@Test\n\tvoid getBundleWhenNoSuchBundleThrowsException() {\n\t\tthis.registry.registerBundle(\"test\", this.bundle1);\n\t\tassertThatExceptionOfType(NoSuchSslBundleException.class).isThrownBy(() -> this.registry.getBundle(\"missing\"))\n\t\t\t.satisfies((ex) -> assertThat(ex.getBundleName()).isEqualTo(\"missing\"));\n\t}\n\n\t@Test\n\tvoid getBundleReturnsBundle() {\n\t\tthis.registry.registerBundle(\"test1\", this.bundle1);\n\t\tthis.registry.registerBundle(\"test2\", this.bundle2);\n\t\tassertThat(this.registry.getBundle(\"test1\")).isSameAs(this.bundle1);\n\t\tassertThat(this.registry.getBundle(\"test2\")).isSameAs(this.bundle2);\n\t}\n\n\t@Test\n\tvoid getBundleNamesReturnsNames() {\n\t\tthis.registry.registerBundle(\"test1\", this.bundle1);\n\t\tthis.registry.registerBundle(\"test2\", this.bundle2);\n\t\tassertThat(this.registry.getBundleNames()).containsExactly(\"test1\", \"test2\");\n\t}\n\n\t@Test\n\tvoid updateBundleShouldNotifyUpdateHandlers() {\n\t\tAtomicReference<SslBundle> updatedBundle = new AtomicReference<>();\n\t\tthis.registry.registerBundle(\"test1\", this.bundle1);\n\t\tthis.registry.addBundleUpdateHandler(\"test1\", updatedBundle::set);\n\t\tthis.registry.updateBundle(\"test1\", this.bundle2);\n\t\tAwaitility.await().untilAtomic(updatedBundle, Matchers.equalTo(this.bundle2));\n\t}\n\n\t@Test\n\tvoid shouldFailIfUpdatingNonRegisteredBundle() {\n\t\tassertThatExceptionOfType(NoSuchSslBundleException.class)\n\t\t\t.isThrownBy(() -> this.registry.updateBundle(\"dummy\", this.bundle1))\n\t\t\t.withMessageContaining(\"'dummy'\");\n\t}\n\n\t@Test\n\tvoid shouldLogIfUpdatingBundleWithoutListeners(CapturedOutput output) {\n\t\tthis.registry.registerBundle(\"test1\", this.bundle1);\n\t\tthis.registry.getBundle(\"test1\");\n\t\tthis.registry.updateBundle(\"test1\", this.bundle2);\n\t\tassertThat(output).contains(\n\t\t\t\t\"SSL bundle 'test1' has been updated but may be in use by a technology that doesn't support SSL reloading\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/DefaultSslManagerBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultSslManagerBundle}.\n *\n * @author Phillip Webb\n */\nclass DefaultSslManagerBundleTests {\n\n\tprivate final KeyManagerFactory keyManagerFactory = mock(KeyManagerFactory.class);\n\n\tprivate final TrustManagerFactory trustManagerFactory = mock(TrustManagerFactory.class);\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenStoreBundleIsNull() throws Exception {\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(null, SslBundleKey.NONE);\n\t\tKeyManagerFactory result = bundle.getKeyManagerFactory();\n\t\tassertThat(result).isNotNull();\n\t\tthen(this.keyManagerFactory).should().init(null, null);\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenKeyIsNull() throws Exception {\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(SslStoreBundle.NONE, null);\n\t\tKeyManagerFactory result = bundle.getKeyManagerFactory();\n\t\tassertThat(result).isSameAs(this.keyManagerFactory);\n\t\tthen(this.keyManagerFactory).should().init(null, null);\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasKeyAliasReturnsWrapped() {\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(null, SslBundleKey.of(\"secret\", \"alias\"));\n\t\tKeyManagerFactory result = bundle.getKeyManagerFactory();\n\t\tassertThat(result).isInstanceOf(AliasKeyManagerFactory.class);\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasKeyPassword() throws Exception {\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(null, SslBundleKey.of(\"secret\"));\n\t\tKeyManagerFactory result = bundle.getKeyManagerFactory();\n\t\tassertThat(result).isSameAs(this.keyManagerFactory);\n\t\tthen(this.keyManagerFactory).should().init(null, \"secret\".toCharArray());\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasKeyStorePassword() throws Exception {\n\t\tSslStoreBundle storeBundle = SslStoreBundle.of(null, \"secret\", null);\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(storeBundle, null);\n\t\tKeyManagerFactory result = bundle.getKeyManagerFactory();\n\t\tassertThat(result).isSameAs(this.keyManagerFactory);\n\t\tthen(this.keyManagerFactory).should().init(null, \"secret\".toCharArray());\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasAliasNotInStoreThrowsException() throws Exception {\n\t\tKeyStore keyStore = mock(KeyStore.class);\n\t\tgiven(keyStore.containsAlias(\"alias\")).willReturn(false);\n\t\tSslStoreBundle storeBundle = SslStoreBundle.of(keyStore, null, null);\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(storeBundle,\n\t\t\t\tSslBundleKey.of(\"secret\", \"alias\"));\n\t\tassertThatIllegalStateException().isThrownBy(bundle::getKeyManagerFactory)\n\t\t\t.withMessage(\"Keystore does not contain alias 'alias'\");\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasAliasNotDeterminedInStoreThrowsException() throws Exception {\n\t\tKeyStore keyStore = mock(KeyStore.class);\n\t\tgiven(keyStore.containsAlias(\"alias\")).willThrow(KeyStoreException.class);\n\t\tSslStoreBundle storeBundle = SslStoreBundle.of(keyStore, null, null);\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(storeBundle,\n\t\t\t\tSslBundleKey.of(\"secret\", \"alias\"));\n\t\tassertThatIllegalStateException().isThrownBy(bundle::getKeyManagerFactory)\n\t\t\t.withMessage(\"Could not determine if keystore contains alias 'alias'\");\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasStore() throws Exception {\n\t\tKeyStore keyStore = mock(KeyStore.class);\n\t\tSslStoreBundle storeBundle = SslStoreBundle.of(keyStore, null, null);\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(storeBundle, null);\n\t\tKeyManagerFactory result = bundle.getKeyManagerFactory();\n\t\tassertThat(result).isSameAs(this.keyManagerFactory);\n\t\tthen(this.keyManagerFactory).should().init(keyStore, null);\n\t}\n\n\t@Test\n\tvoid getTrustManagerFactoryWhenStoreBundleIsNull() throws Exception {\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(null, null);\n\t\tTrustManagerFactory result = bundle.getTrustManagerFactory();\n\t\tassertThat(result).isSameAs(this.trustManagerFactory);\n\t\tthen(this.trustManagerFactory).should().init((KeyStore) null);\n\t}\n\n\t@Test\n\tvoid getTrustManagerFactoryWhenHasStore() throws Exception {\n\t\tKeyStore trustStore = mock(KeyStore.class);\n\t\tSslStoreBundle storeBundle = SslStoreBundle.of(null, null, trustStore);\n\t\tDefaultSslManagerBundle bundle = new TestDefaultSslManagerBundle(storeBundle, null);\n\t\tTrustManagerFactory result = bundle.getTrustManagerFactory();\n\t\tassertThat(result).isSameAs(this.trustManagerFactory);\n\t\tthen(this.trustManagerFactory).should().init(trustStore);\n\t}\n\n\t/**\n\t * Test version of {@link DefaultSslManagerBundle}.\n\t */\n\tclass TestDefaultSslManagerBundle extends DefaultSslManagerBundle {\n\n\t\tTestDefaultSslManagerBundle(@Nullable SslStoreBundle storeBundle, @Nullable SslBundleKey key) {\n\t\t\tsuper(storeBundle, key);\n\t\t}\n\n\t\t@Override\n\t\tprotected KeyManagerFactory getKeyManagerFactoryInstance(String algorithm) throws NoSuchAlgorithmException {\n\t\t\treturn DefaultSslManagerBundleTests.this.keyManagerFactory;\n\t\t}\n\n\t\t@Override\n\t\tprotected TrustManagerFactory getTrustManagerFactoryInstance(String algorithm) throws NoSuchAlgorithmException {\n\t\t\treturn DefaultSslManagerBundleTests.this.trustManagerFactory;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/FixedTrustManagerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link FixedTrustManagerFactory}.\n *\n * @author Moritz Halbritter\n */\nclass FixedTrustManagerFactoryTests {\n\n\t@Test\n\tvoid shouldReturnTrustManagers() throws Exception {\n\t\tTrustManager trustManager1 = mock(TrustManager.class);\n\t\tTrustManager trustManager2 = mock(TrustManager.class);\n\t\tFixedTrustManagerFactory factory = FixedTrustManagerFactory.of(getDefaultTrustManagerFactory(), trustManager1,\n\t\t\t\ttrustManager2);\n\t\tassertThat(factory.getTrustManagers()).containsExactly(trustManager1, trustManager2);\n\t}\n\n\tprivate static TrustManagerFactory getDefaultTrustManagerFactory() throws NoSuchAlgorithmException {\n\t\treturn TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/NoSuchSslBundleExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoSuchSslBundleException}.\n *\n * @author Phillip Webb\n */\nclass NoSuchSslBundleExceptionTests {\n\n\t@Test\n\tvoid createCreatesException() {\n\t\tThrowable cause = new RuntimeException();\n\t\tNoSuchSslBundleException exception = new NoSuchSslBundleException(\"name\", \"badness\", cause);\n\t\tassertThat(exception).hasMessage(\"badness\").hasCause(cause);\n\t\tassertThat(exception.getBundleName()).isEqualTo(\"name\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/SslBundleKeyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SslBundleKey}.\n *\n * @author Phillip Webb\n */\nclass SslBundleKeyTests {\n\n\t@Test\n\tvoid noneHasNoValues() {\n\t\tSslBundleKey keyReference = SslBundleKey.NONE;\n\t\tassertThat(keyReference.getPassword()).isNull();\n\t\tassertThat(keyReference.getAlias()).isNull();\n\t}\n\n\t@Test\n\tvoid ofCreatesWithPasswordSslKeyReference() {\n\t\tSslBundleKey keyReference = SslBundleKey.of(\"password\");\n\t\tassertThat(keyReference.getPassword()).isEqualTo(\"password\");\n\t\tassertThat(keyReference.getAlias()).isNull();\n\t}\n\n\t@Test\n\tvoid ofCreatesWithPasswordAndAliasSslKeyReference() {\n\t\tSslBundleKey keyReference = SslBundleKey.of(\"password\", \"alias\");\n\t\tassertThat(keyReference.getPassword()).isEqualTo(\"password\");\n\t\tassertThat(keyReference.getAlias()).isEqualTo(\"alias\");\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasAliasNotInStoreThrowsException() throws Exception {\n\t\tKeyStore keyStore = mock(KeyStore.class);\n\t\tgiven(keyStore.containsAlias(\"alias\")).willReturn(false);\n\t\tSslBundleKey key = SslBundleKey.of(\"secret\", \"alias\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> key.assertContainsAlias(keyStore))\n\t\t\t.withMessage(\"Keystore does not contain alias 'alias'\");\n\t}\n\n\t@Test\n\tvoid getKeyManagerFactoryWhenHasAliasNotDeterminedInStoreThrowsException() throws Exception {\n\t\tKeyStore keyStore = mock(KeyStore.class);\n\t\tgiven(keyStore.containsAlias(\"alias\")).willThrow(KeyStoreException.class);\n\t\tSslBundleKey key = SslBundleKey.of(\"secret\", \"alias\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> key.assertContainsAlias(keyStore))\n\t\t\t.withMessage(\"Could not determine if keystore contains alias 'alias'\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/SslBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SslBundle}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass SslBundleTests {\n\n\t@Test\n\tvoid createSslContextDelegatesToManagers() {\n\t\tSslManagerBundle managers = mock(SslManagerBundle.class);\n\t\tSslBundle bundle = SslBundle.of(null, null, null, \"testprotocol\", managers);\n\t\tbundle.createSslContext();\n\t\tthen(managers).should().createSslContext(\"testprotocol\");\n\t}\n\n\t@Test\n\tvoid ofCreatesSslBundle() {\n\t\tSslStoreBundle stores = mock(SslStoreBundle.class);\n\t\tSslBundleKey key = mock(SslBundleKey.class);\n\t\tSslOptions options = mock(SslOptions.class);\n\t\tString protocol = \"test\";\n\t\tSslManagerBundle managers = mock(SslManagerBundle.class);\n\t\tSslBundle bundle = SslBundle.of(stores, key, options, protocol, managers);\n\t\tassertThat(bundle.getStores()).isSameAs(stores);\n\t\tassertThat(bundle.getKey()).isSameAs(key);\n\t\tassertThat(bundle.getOptions()).isSameAs(options);\n\t\tassertThat(bundle.getProtocol()).isSameAs(protocol);\n\t\tassertThat(bundle.getManagers()).isSameAs(managers);\n\t}\n\n\t@Test\n\tvoid shouldCreateSystemDefaultBundle() {\n\t\tSslBundle sslBundle = SslBundle.systemDefault();\n\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\tassertThat(sslContext).isNotNull();\n\t\tTrustManager[] trustManagers = sslBundle.getManagers().getTrustManagers();\n\t\tassertThat(trustManagers).isNotEmpty();\n\t\tTrustManager trustManager = trustManagers[0];\n\t\tassertThat(trustManager).isInstanceOf(X509TrustManager.class);\n\t\tX509TrustManager x509TrustManager = (X509TrustManager) trustManager;\n\t\tassertThat(x509TrustManager.getAcceptedIssuers()).isNotEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/SslManagerBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SslManagerBundle}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass SslManagerBundleTests {\n\n\tprivate final KeyManagerFactory keyManagerFactory = mock(KeyManagerFactory.class);\n\n\tprivate final TrustManagerFactory trustManagerFactory = mock(TrustManagerFactory.class);\n\n\t@Test\n\tvoid getKeyManagersDelegatesToFactory() {\n\t\tSslManagerBundle bundle = SslManagerBundle.of(this.keyManagerFactory, this.trustManagerFactory);\n\t\tbundle.getKeyManagers();\n\t\tthen(this.keyManagerFactory).should().getKeyManagers();\n\t}\n\n\t@Test\n\tvoid getTrustManagersDelegatesToFactory() {\n\t\tSslManagerBundle bundle = SslManagerBundle.of(this.keyManagerFactory, this.trustManagerFactory);\n\t\tbundle.getTrustManagers();\n\t\tthen(this.trustManagerFactory).should().getTrustManagers();\n\t}\n\n\t@Test\n\tvoid createSslContextCreatesInitializedSslContext() {\n\t\tSslManagerBundle bundle = SslManagerBundle.of(this.keyManagerFactory, this.trustManagerFactory);\n\t\tSSLContext sslContext = bundle.createSslContext(\"TLS\");\n\t\tassertThat(sslContext).isNotNull();\n\t\tassertThat(sslContext.getProtocol()).isEqualTo(\"TLS\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenKeyManagerFactoryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> SslManagerBundle.of(null, this.trustManagerFactory))\n\t\t\t.withMessage(\"'keyManagerFactory' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenTrustManagerFactoryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> SslManagerBundle.of(this.keyManagerFactory, null))\n\t\t\t.withMessage(\"'trustManagerFactory' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofCreatesSslManagerBundle() {\n\t\tSslManagerBundle bundle = SslManagerBundle.of(this.keyManagerFactory, this.trustManagerFactory);\n\t\tassertThat(bundle.getKeyManagerFactory()).isSameAs(this.keyManagerFactory);\n\t\tassertThat(bundle.getTrustManagerFactory()).isSameAs(this.trustManagerFactory);\n\t}\n\n\t@Test\n\tvoid fromCreatesDefaultSslManagerBundle() {\n\t\tSslManagerBundle bundle = SslManagerBundle.from(SslStoreBundle.NONE, SslBundleKey.NONE);\n\t\tassertThat(bundle).isInstanceOf(DefaultSslManagerBundle.class);\n\t}\n\n\t@Test\n\tvoid shouldReturnTrustManagerFactory() {\n\t\tSslManagerBundle bundle = SslManagerBundle.from(this.trustManagerFactory);\n\t\tassertThat(bundle.getKeyManagerFactory()).isNotNull();\n\t\tassertThat(bundle.getTrustManagerFactory()).isSameAs(this.trustManagerFactory);\n\t}\n\n\t@Test\n\tvoid shouldReturnTrustManagers() {\n\t\tTrustManager trustManager1 = mock(TrustManager.class);\n\t\tTrustManager trustManager2 = mock(TrustManager.class);\n\t\tSslManagerBundle bundle = SslManagerBundle.from(trustManager1, trustManager2);\n\t\tassertThat(bundle.getKeyManagerFactory()).isNotNull();\n\t\tassertThat(bundle.getTrustManagerFactory().getTrustManagers()).containsExactly(trustManager1, trustManager2);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/SslOptionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslOptions}.\n *\n * @author Phillip Webb\n */\nclass SslOptionsTests {\n\n\t@Test\n\tvoid noneReturnsNull() {\n\t\tSslOptions options = SslOptions.NONE;\n\t\tassertThat(options.getCiphers()).isNull();\n\t\tassertThat(options.getEnabledProtocols()).isNull();\n\t}\n\n\t@Test\n\tvoid ofWithArrayCreatesSslOptions() {\n\t\tString[] ciphers = { \"a\", \"b\", \"c\" };\n\t\tString[] enabledProtocols = { \"d\", \"e\", \"f\" };\n\t\tSslOptions options = SslOptions.of(ciphers, enabledProtocols);\n\t\tassertThat(options.getCiphers()).containsExactly(ciphers);\n\t\tassertThat(options.getEnabledProtocols()).containsExactly(enabledProtocols);\n\t}\n\n\t@Test\n\tvoid ofWithNullArraysCreatesSslOptions() {\n\t\tString[] ciphers = null;\n\t\tString[] enabledProtocols = null;\n\t\tSslOptions options = SslOptions.of(ciphers, enabledProtocols);\n\t\tassertThat(options.getCiphers()).isNull();\n\t\tassertThat(options.getEnabledProtocols()).isNull();\n\t}\n\n\t@Test\n\tvoid ofWithSetCreatesSslOptions() {\n\t\tSet<String> ciphers = Set.of(\"a\", \"b\", \"c\");\n\t\tSet<String> enabledProtocols = Set.of(\"d\", \"e\", \"f\");\n\t\tSslOptions options = SslOptions.of(ciphers, enabledProtocols);\n\t\tassertThat(options.getCiphers()).contains(\"a\", \"b\", \"c\");\n\t\tassertThat(options.getEnabledProtocols()).contains(\"d\", \"e\", \"f\");\n\t}\n\n\t@Test\n\tvoid ofWithNullSetCreatesSslOptions() {\n\t\tSet<String> ciphers = null;\n\t\tSet<String> enabledProtocols = null;\n\t\tSslOptions options = SslOptions.of(ciphers, enabledProtocols);\n\t\tassertThat(options.getCiphers()).isNull();\n\t\tassertThat(options.getEnabledProtocols()).isNull();\n\t}\n\n\t@Test\n\tvoid isSpecifiedWhenHasCiphers() {\n\t\tSslOptions options = SslOptions.of(Set.of(\"a\", \"b\", \"c\"), null);\n\t\tassertThat(options.isSpecified()).isTrue();\n\t}\n\n\t@Test\n\tvoid isSpecifiedWhenHasEnabledProtocols() {\n\t\tSslOptions options = SslOptions.of(null, Set.of(\"d\", \"e\", \"f\"));\n\t\tassertThat(options.isSpecified()).isTrue();\n\t}\n\n\t@Test\n\tvoid isSpecifiedWhenHasNoCiphersOrEnabledProtocols() {\n\t\tSslOptions options = SslOptions.NONE;\n\t\tassertThat(options.isSpecified()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/SslStoreBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl;\n\nimport java.security.KeyStore;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SslStoreBundle}\n *\n * @author Phillip Webb\n */\nclass SslStoreBundleTests {\n\n\t@Test\n\tvoid noneReturnsEmptySslStoreBundle() {\n\t\tSslStoreBundle bundle = SslStoreBundle.NONE;\n\t\tassertThat(bundle.getKeyStore()).isNull();\n\t\tassertThat(bundle.getKeyStorePassword()).isNull();\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\tvoid ofCreatesStoreBundle() {\n\t\tKeyStore keyStore = mock(KeyStore.class);\n\t\tString keyStorePassword = \"secret\";\n\t\tKeyStore trustStore = mock(KeyStore.class);\n\t\tSslStoreBundle bundle = SslStoreBundle.of(keyStore, keyStorePassword, trustStore);\n\t\tassertThat(bundle.getKeyStore()).isSameAs(keyStore);\n\t\tassertThat(bundle.getKeyStorePassword()).isEqualTo(keyStorePassword);\n\t\tassertThat(bundle.getTrustStore()).isSameAs(trustStore);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/jks/JksSslStoreBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.jks;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.security.KeyStore;\nimport java.util.Base64;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11Security;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link JksSslStoreBundle}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@MockPkcs11Security\nclass JksSslStoreBundleTests {\n\n\t@Test\n\tvoid whenNullStores() {\n\t\tJksSslStoreDetails keyStoreDetails = null;\n\t\tJksSslStoreDetails trustStoreDetails = null;\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).isNull();\n\t\tassertThat(bundle.getKeyStorePassword()).isNull();\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\tvoid whenStoresHaveNoValues() {\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(null);\n\t\tJksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(null);\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).isNull();\n\t\tassertThat(bundle.getKeyStorePassword()).isNull();\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\tvoid whenTypePKCS11AndLocationGetKeyStoreThrowsException() {\n\t\tJksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(\"PKCS11\", null, \"test.jks\", null);\n\t\tJksSslStoreBundle jksSslStoreBundle = new JksSslStoreBundle(keyStoreDetails, null);\n\t\tassertThatIllegalStateException().isThrownBy(jksSslStoreBundle::getKeyStore)\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Unable to create key store: Location is 'test.jks', but must be empty or null for PKCS11 hardware key stores\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasKeyStoreLocation() {\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(\"classpath:test.jks\")\n\t\t\t.withPassword(\"secret\");\n\t\tJksSslStoreDetails trustStoreDetails = null;\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"test-alias\", \"password\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid getTrustStoreWithLocations() {\n\t\tJksSslStoreDetails keyStoreDetails = null;\n\t\tJksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(\"classpath:test.jks\")\n\t\t\t.withPassword(\"secret\");\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"test-alias\", \"password\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasKeyStoreType() {\n\t\tJksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(\"jks\", null, \"classpath:test.jks\", \"secret\");\n\t\tJksSslStoreDetails trustStoreDetails = null;\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"jks\", \"test-alias\", \"password\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasTrustStoreType() {\n\t\tJksSslStoreDetails keyStoreDetails = null;\n\t\tJksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(\"jks\", null, \"classpath:test.jks\", \"secret\");\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"jks\", \"test-alias\", \"password\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasKeyStoreProvider() {\n\t\tJksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(null, \"com.example.KeyStoreProvider\",\n\t\t\t\t\"classpath:test.jks\", \"secret\");\n\t\tJksSslStoreBundle jksSslStoreBundle = new JksSslStoreBundle(keyStoreDetails, null);\n\t\tassertThatIllegalStateException().isThrownBy(jksSslStoreBundle::getKeyStore)\n\t\t\t.withMessageContaining(\"com.example.KeyStoreProvider\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasTrustStoreProvider() {\n\t\tJksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(null, \"com.example.KeyStoreProvider\",\n\t\t\t\t\"classpath:test.jks\", \"secret\");\n\t\tJksSslStoreBundle jksSslStoreBundle = new JksSslStoreBundle(null, trustStoreDetails);\n\t\tassertThatIllegalStateException().isThrownBy(jksSslStoreBundle::getTrustStore)\n\t\t\t.withMessageContaining(\"com.example.KeyStoreProvider\");\n\t}\n\n\t@Test\n\tvoid storeCreationIsLazy() {\n\t\tJksSslStoreDetails details = new JksSslStoreDetails(null, null, \"does-not-exist\", null);\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(details, details);\n\t\tassertThatIllegalStateException().isThrownBy(bundle::getKeyStore);\n\t\tassertThatIllegalStateException().isThrownBy(bundle::getTrustStore);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test.p12\", \"test.jks\" })\n\tvoid whenLocationsAreBase64Encoded() throws IOException {\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(encodeFileContent(\"classpath:test.p12\"))\n\t\t\t.withPassword(\"secret\");\n\t\tJksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(encodeFileContent(\"classpath:test.jks\"))\n\t\t\t.withPassword(\"secret\");\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"test-alias\", \"secret\"));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"test-alias\", \"password\"));\n\t}\n\n\t@Test\n\tvoid invalidBase64EncodedLocationThrowsException() {\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(\"base64:not base 64\");\n\t\tJksSslStoreBundle jksSslStoreBundle = new JksSslStoreBundle(keyStoreDetails, null);\n\t\tassertThatIllegalStateException().isThrownBy(jksSslStoreBundle::getKeyStore)\n\t\t\t.withMessageContaining(\"key store\")\n\t\t\t.withMessageContaining(\"base64:not base 64\")\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(IllegalArgumentException.class)\n\t\t\t.withMessageContaining(\"Illegal base64\");\n\t}\n\n\t@Test\n\tvoid invalidLocationThrowsException() {\n\t\tJksSslStoreDetails trustStoreDetails = JksSslStoreDetails.forLocation(\"does-not-exist.p12\");\n\t\tJksSslStoreBundle jksSslStoreBundle = new JksSslStoreBundle(null, trustStoreDetails);\n\t\tassertThatIllegalStateException().isThrownBy(jksSslStoreBundle::getTrustStore)\n\t\t\t.withMessageContaining(\"trust store\")\n\t\t\t.withMessageContaining(\"does-not-exist.p12\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid usesResourceLoader() {\n\t\tJksSslStoreDetails keyStoreDetails = null;\n\t\tJksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(\"jks\", null, \"classpath:test.jks\", \"secret\");\n\t\tResourceLoader resourceLoader = spy(new DefaultResourceLoader());\n\t\tJksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails, resourceLoader);\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"jks\", \"test-alias\", \"password\"));\n\t\tthen(resourceLoader).should(atLeastOnce()).getResource(\"classpath:test.jks\");\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyAlias, String keyPassword) {\n\t\treturn storeContainingCertAndKey(KeyStore.getDefaultType(), keyAlias, keyPassword);\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyStoreType, String keyAlias, String keyPassword) {\n\t\treturn ThrowingConsumer.of((keyStore) -> {\n\t\t\tassertThat(keyStore).isNotNull();\n\t\t\tassertThat(keyStore.getType()).isEqualTo(keyStoreType);\n\t\t\tassertThat(keyStore.containsAlias(keyAlias)).isTrue();\n\t\t\tassertThat(keyStore.getCertificate(keyAlias)).isNotNull();\n\t\t\tassertThat(keyStore.getKey(keyAlias, keyPassword.toCharArray())).isNotNull();\n\t\t});\n\t}\n\n\tprivate String encodeFileContent(String location) throws IOException {\n\t\tResource resource = ApplicationResourceLoader.get().getResource(location);\n\t\tbyte[] bytes = Files.readAllBytes(resource.getFile().toPath());\n\t\treturn \"base64:\" + Base64.getEncoder().encodeToString(bytes);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/LoadedPemSslStoreTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.UncheckedIOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link LoadedPemSslStore}.\n *\n * @author Phillip Webb\n */\nclass LoadedPemSslStoreTests {\n\n\t@Test\n\t@WithPackageResources(\"test-key.pem\")\n\tvoid certificatesAreLoadedLazily() {\n\t\tPemSslStoreDetails details = PemSslStoreDetails.forCertificate(\"classpath:missing-test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tLoadedPemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get());\n\t\tassertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::certificates);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid privateKeyIsLoadedLazily() {\n\t\tPemSslStoreDetails details = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:missing-test-key.pem\");\n\t\tLoadedPemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get());\n\t\tassertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::privateKey);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-key.pem\")\n\tvoid withAliasIsLazy() {\n\t\tPemSslStoreDetails details = PemSslStoreDetails.forCertificate(\"classpath:missing-test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tPemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get()).withAlias(\"alias\");\n\t\tassertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::certificates);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-key.pem\")\n\tvoid withPasswordIsLazy() {\n\t\tPemSslStoreDetails details = PemSslStoreDetails.forCertificate(\"classpath:missing-test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tPemSslStore store = new LoadedPemSslStore(details, ApplicationResourceLoader.get()).withPassword(\"password\");\n\t\tassertThatExceptionOfType(UncheckedIOException.class).isThrownBy(store::certificates);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid usesResourceLoader() {\n\t\tPemSslStoreDetails details = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\");\n\t\tResourceLoader resourceLoader = spy(new DefaultResourceLoader());\n\t\tLoadedPemSslStore store = new LoadedPemSslStore(details, resourceLoader);\n\t\tstore.certificates();\n\t\tthen(resourceLoader).should(atLeastOnce()).getResource(\"classpath:test-cert.pem\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemCertificateParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PemCertificateParser}.\n *\n * @author Scott Frederick\n */\nclass PemCertificateParserTests {\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid parseCertificate() throws Exception {\n\t\tList<X509Certificate> certificates = PemCertificateParser.parse(read(\"test-cert.pem\"));\n\t\tassertThat(certificates).isNotNull();\n\t\tassertThat(certificates).hasSize(1);\n\t\tassertThat(certificates.get(0).getType()).isEqualTo(\"X.509\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert-chain.pem\")\n\tvoid parseCertificateChain() throws Exception {\n\t\tList<X509Certificate> certificates = PemCertificateParser.parse(read(\"test-cert-chain.pem\"));\n\t\tassertThat(certificates).isNotNull();\n\t\tassertThat(certificates).hasSize(2);\n\t\tassertThat(certificates.get(0).getType()).isEqualTo(\"X.509\");\n\t\tassertThat(certificates.get(1).getType()).isEqualTo(\"X.509\");\n\t}\n\n\tprivate String read(String path) throws IOException {\n\t\treturn new ClassPathResource(path).getContentAsString(StandardCharsets.UTF_8);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link PemContent}.\n *\n * @author Phillip Webb\n */\nclass PemContentTests {\n\n\t@Test\n\tvoid getCertificateWhenNoCertificatesThrowsException() {\n\t\tPemContent content = PemContent.of(\"\");\n\t\tassertThatIllegalStateException().isThrownBy(content::getCertificates)\n\t\t\t.withMessage(\"Missing certificates or unrecognized format\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert-chain.pem\")\n\tvoid getCertificateReturnsCertificates() throws Exception {\n\t\tPemContent content = PemContent.load(contentFromClasspath(\"/test-cert-chain.pem\"),\n\t\t\t\tApplicationResourceLoader.get());\n\t\tassertThat(content).isNotNull();\n\t\tList<X509Certificate> certificates = content.getCertificates();\n\t\tassertThat(certificates).isNotNull();\n\t\tassertThat(certificates).hasSize(2);\n\t\tassertThat(certificates.get(0).getType()).isEqualTo(\"X.509\");\n\t\tassertThat(certificates.get(1).getType()).isEqualTo(\"X.509\");\n\t}\n\n\t@Test\n\tvoid getPrivateKeyWhenNoKeyThrowsException() {\n\t\tPemContent content = PemContent.of(\"\");\n\t\tassertThatIllegalStateException().isThrownBy(content::getPrivateKey)\n\t\t\t.withMessage(\"Missing private key or unrecognized format\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"dsa.key\")\n\tvoid getPrivateKeyReturnsPrivateKey() throws Exception {\n\t\tPemContent content = PemContent.load(contentFromClasspath(\"dsa.key\"), ApplicationResourceLoader.get());\n\t\tassertThat(content).isNotNull();\n\t\tPrivateKey privateKey = content.getPrivateKey();\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(\"DSA\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tPemContent c1 = PemContent.of(\"aaa\");\n\t\tPemContent c2 = PemContent.of(\"aaa\");\n\t\tPemContent c3 = PemContent.of(\"bbb\");\n\t\tassertThat(c1).isEqualTo(c1).isEqualTo(c2).isNotEqualTo(c3);\n\t\tassertThat(c1).hasSameHashCodeAs(c2);\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tPemContent content = PemContent.of(\"test\");\n\t\tassertThat(content).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid loadWithStringWhenContentIsNullReturnsNull() throws Exception {\n\t\tassertThat(PemContent.load((String) null, ApplicationResourceLoader.get())).isNull();\n\t}\n\n\t@Test\n\tvoid loadWithStringWhenContentIsPemContentReturnsContent() throws Exception {\n\t\tString content = \"\"\"\n\t\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t\tMIICpDCCAYwCCQCDOqHKPjAhCTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls\n\t\t\t\tb2NhbGhvc3QwHhcNMTQwOTEwMjE0MzA1WhcNMTQxMDEwMjE0MzA1WjAUMRIwEAYD\n\t\t\t\tVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR\n\t\t\t\t0KfxUw7MF/8RB5/YXOM7yLnoHYb/M/6dyoulMbtEdKKhQhU28o5FiDkHcEG9PJQL\n\t\t\t\tgqrRgAjl3VmCC9omtfZJQ2EpfkTttkJjnKOOroXhYE51/CYSckapBYCVh8GkjUEJ\n\t\t\t\tuEfnp07cTfYZFqViIgIWPZyjkzl3w4girS7kCuzNdDntVJVx5F/EsFwMA8n3C0Qa\n\t\t\t\tzHQoM5s00Fer6aTwd6AW0JD5QkADavpfzZ554e4HrVGwHlM28WKQQkFzzGu44FFX\n\t\t\t\tyVuEF3HeyVPug8GRHAc8UU7ijVgJB5TmbvRGYowIErD5i4VvGLuOv9mgR3aVyN0S\n\t\t\t\tdJ1N7aJnXpeSQjAgf03jAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAE4yvwhbPldg\n\t\t\t\tBpl7sBw/m2B3bfiNeSqa4tII1PQ7ysgWVb9HbFNKkriScwDWlqo6ljZfJ+SDFCoj\n\t\t\t\tbQz4fOFdMAOzRnpTrG2NAKMoJLY0/g/p7XO00PiC8T3h3BOJ5SHuW3gUyfGXmAYs\n\t\t\t\tDnJxJOrwPzj57xvNXjNSbDOJ3DRfCbB0CWBexOeGDiUokoEq3Gnz04Q4ZfHyAcpZ\n\t\t\t\t3deMw8Od5p9WAoCh3oClpFyOSzXYKZd+3ppMMtfc4wnbfocnfSFxj0UCpOEJw4Ez\n\t\t\t\t+lGuHKdhNOVW9CmqPD1y76o6c8PQKuF7KZEoY2jvy3GeIfddBvqXgZ4PbWvFz1jO\n\t\t\t\t32C9XWHwRA4=\n\t\t\t\t-----END CERTIFICATE-----\"\"\";\n\t\tassertThat(PemContent.load(content, ApplicationResourceLoader.get())).hasToString(content);\n\t}\n\n\t@Test\n\tvoid loadWithStringWhenContentIsPemContentReturnsTrimmedContent() throws Exception {\n\t\tString content = \"\"\"\n\t\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t\t\tMIICpDCCAYwCCQCDOqHKPjAhCTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls\n\t\t\t\t\tb2NhbGhvc3QwHhcNMTQwOTEwMjE0MzA1WhcNMTQxMDEwMjE0MzA1WjAUMRIwEAYD\n\t\t\t\tVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR\n\t\t\t\t\t0KfxUw7MF/8RB5/YXOM7yLnoHYb/M/6dyoulMbtEdKKhQhU28o5FiDkHcEG9PJQL\n\t\t\t\tgqrRgAjl3VmCC9omtfZJQ2EpfkTttkJjnKOOroXhYE51/CYSckapBYCVh8GkjUEJ\n\t\t\t\t\tuEfnp07cTfYZFqViIgIWPZyjkzl3w4girS7kCuzNdDntVJVx5F/EsFwMA8n3C0Qa\n\t\t\t\tzHQoM5s00Fer6aTwd6AW0JD5QkADavpfzZ554e4HrVGwHlM28WKQQkFzzGu44FFX\n\t\t\t\t\tyVuEF3HeyVPug8GRHAc8UU7ijVgJB5TmbvRGYowIErD5i4VvGLuOv9mgR3aVyN0S\n\t\t\t\t\tdJ1N7aJnXpeSQjAgf03jAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAE4yvwhbPldg\n\t\t\t\t\tBpl7sBw/m2B3bfiNeSqa4tII1PQ7ysgWVb9HbFNKkriScwDWlqo6ljZfJ+SDFCoj\n\t\t\t\tbQz4fOFdMAOzRnpTrG2NAKMoJLY0/g/p7XO00PiC8T3h3BOJ5SHuW3gUyfGXmAYs\n\t\t\t\t\tDnJxJOrwPzj57xvNXjNSbDOJ3DRfCbB0CWBexOeGDiUokoEq3Gnz04Q4ZfHyAcpZ\n\t\t\t\t3deMw8Od5p9WAoCh3oClpFyOSzXYKZd+3ppMMtfc4wnbfocnfSFxj0UCpOEJw4Ez\n\t\t\t\t+lGuHKdhNOVW9CmqPD1y76o6c8PQKuF7KZEoY2jvy3GeIfddBvqXgZ4PbWvFz1jO\n\t\t\t\t\t32C9XWHwRA4=\n\t\t\t\t\t-----END CERTIFICATE-----  \"\"\";\n\t\tString trimmedContent = \"\"\"\n\t\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t\tMIICpDCCAYwCCQCDOqHKPjAhCTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls\n\t\t\t\tb2NhbGhvc3QwHhcNMTQwOTEwMjE0MzA1WhcNMTQxMDEwMjE0MzA1WjAUMRIwEAYD\n\t\t\t\tVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR\n\t\t\t\t0KfxUw7MF/8RB5/YXOM7yLnoHYb/M/6dyoulMbtEdKKhQhU28o5FiDkHcEG9PJQL\n\t\t\t\tgqrRgAjl3VmCC9omtfZJQ2EpfkTttkJjnKOOroXhYE51/CYSckapBYCVh8GkjUEJ\n\t\t\t\tuEfnp07cTfYZFqViIgIWPZyjkzl3w4girS7kCuzNdDntVJVx5F/EsFwMA8n3C0Qa\n\t\t\t\tzHQoM5s00Fer6aTwd6AW0JD5QkADavpfzZ554e4HrVGwHlM28WKQQkFzzGu44FFX\n\t\t\t\tyVuEF3HeyVPug8GRHAc8UU7ijVgJB5TmbvRGYowIErD5i4VvGLuOv9mgR3aVyN0S\n\t\t\t\tdJ1N7aJnXpeSQjAgf03jAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAE4yvwhbPldg\n\t\t\t\tBpl7sBw/m2B3bfiNeSqa4tII1PQ7ysgWVb9HbFNKkriScwDWlqo6ljZfJ+SDFCoj\n\t\t\t\tbQz4fOFdMAOzRnpTrG2NAKMoJLY0/g/p7XO00PiC8T3h3BOJ5SHuW3gUyfGXmAYs\n\t\t\t\tDnJxJOrwPzj57xvNXjNSbDOJ3DRfCbB0CWBexOeGDiUokoEq3Gnz04Q4ZfHyAcpZ\n\t\t\t\t3deMw8Od5p9WAoCh3oClpFyOSzXYKZd+3ppMMtfc4wnbfocnfSFxj0UCpOEJw4Ez\n\t\t\t\t+lGuHKdhNOVW9CmqPD1y76o6c8PQKuF7KZEoY2jvy3GeIfddBvqXgZ4PbWvFz1jO\n\t\t\t\t32C9XWHwRA4=\n\t\t\t\t-----END CERTIFICATE-----\"\"\";\n\t\tassertThat(PemContent.load(content, ApplicationResourceLoader.get())).hasToString(trimmedContent);\n\t}\n\n\t@Test\n\tvoid isPresentInTextWithUntrimmedContent() {\n\t\tString content = \"\"\"\n\t\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t\t\tMIICpDCCAYwCCQCDOqHKPjAhCTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls\n\t\t\t\t\tb2NhbGhvc3QwHhcNMTQwOTEwMjE0MzA1WhcNMTQxMDEwMjE0MzA1WjAUMRIwEAYD\n\t\t\t\tVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDR\n\t\t\t\t\t0KfxUw7MF/8RB5/YXOM7yLnoHYb/M/6dyoulMbtEdKKhQhU28o5FiDkHcEG9PJQL\n\t\t\t\tgqrRgAjl3VmCC9omtfZJQ2EpfkTttkJjnKOOroXhYE51/CYSckapBYCVh8GkjUEJ\n\t\t\t\t\tuEfnp07cTfYZFqViIgIWPZyjkzl3w4girS7kCuzNdDntVJVx5F/EsFwMA8n3C0Qa\n\t\t\t\tzHQoM5s00Fer6aTwd6AW0JD5QkADavpfzZ554e4HrVGwHlM28WKQQkFzzGu44FFX\n\t\t\t\t\tyVuEF3HeyVPug8GRHAc8UU7ijVgJB5TmbvRGYowIErD5i4VvGLuOv9mgR3aVyN0S\n\t\t\t\t\tdJ1N7aJnXpeSQjAgf03jAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAE4yvwhbPldg\n\t\t\t\t\tBpl7sBw/m2B3bfiNeSqa4tII1PQ7ysgWVb9HbFNKkriScwDWlqo6ljZfJ+SDFCoj\n\t\t\t\tbQz4fOFdMAOzRnpTrG2NAKMoJLY0/g/p7XO00PiC8T3h3BOJ5SHuW3gUyfGXmAYs\n\t\t\t\t\tDnJxJOrwPzj57xvNXjNSbDOJ3DRfCbB0CWBexOeGDiUokoEq3Gnz04Q4ZfHyAcpZ\n\t\t\t\t3deMw8Od5p9WAoCh3oClpFyOSzXYKZd+3ppMMtfc4wnbfocnfSFxj0UCpOEJw4Ez\n\t\t\t\t+lGuHKdhNOVW9CmqPD1y76o6c8PQKuF7KZEoY2jvy3GeIfddBvqXgZ4PbWvFz1jO\n\t\t\t\t\t32C9XWHwRA4=\n\t\t\t\t\t-----END CERTIFICATE-----  \"\"\";\n\t\tassertThat(PemContent.isPresentInText(content)).isTrue();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid loadWithStringWhenClasspathLocationReturnsContent() throws IOException {\n\t\tPemContent content = PemContent.load(\"classpath:test-cert.pem\", ApplicationResourceLoader.get());\n\t\tassertThat(content).isNotNull();\n\t\tString actual = content.toString();\n\t\tString expected = contentFromClasspath(\"test-cert.pem\");\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid loadWithStringWhenFileLocationReturnsContent(@ResourcePath(\"test-cert.pem\") String testCert)\n\t\t\tthrows IOException {\n\t\tPemContent content = PemContent.load(testCert, ApplicationResourceLoader.get());\n\t\tassertThat(content).isNotNull();\n\t\tString actual = content.toString();\n\t\tString expected = contentFromClasspath(\"test-cert.pem\");\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid loadWithPathReturnsContent(@ResourcePath(\"test-cert.pem\") Path testCert) throws IOException {\n\t\tString actual = PemContent.load(testCert).toString();\n\t\tString expected = contentFromClasspath(\"test-cert.pem\");\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test-cert.pem\")\n\tvoid loadWithResourceLoaderUsesResourceLoader() throws IOException {\n\t\tResourceLoader resourceLoader = spy(new DefaultResourceLoader());\n\t\tPemContent.load(\"classpath:test-cert.pem\", resourceLoader);\n\t\tthen(resourceLoader).should(atLeastOnce()).getResource(\"classpath:test-cert.pem\");\n\t}\n\n\t@Test\n\tvoid ofWhenNullReturnsNull() {\n\t\tassertThat(PemContent.of(null)).isNull();\n\t}\n\n\t@Test\n\tvoid ofReturnsContent() {\n\t\tassertThat(PemContent.of(\"test\")).hasToString(\"test\");\n\t}\n\n\tprivate static String contentFromClasspath(String path) throws IOException {\n\t\treturn new ClassPathResource(path).getContentAsString(StandardCharsets.UTF_8).indent(0).stripTrailing();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemPrivateKeyParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.PrivateKey;\nimport java.security.interfaces.ECPrivateKey;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.CsvSource;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link PemPrivateKeyParser}.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass PemPrivateKeyParserTests {\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@CsvSource({\n\t\t\t\"dsa.key,\t\tDSA\",\n\t\t\t\"rsa.key,\t\tRSA\",\n\t\t\t\"rsa-pss.key,\tRSASSA-PSS\"\n\t})\n\t// @formatter:on\n\tvoid shouldParseTraditionalPkcs8(String file, String algorithm) throws IOException {\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"pkcs8/\" + file));\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(algorithm);\n\t}\n\n\t@Test\n\tvoid shouldParseTraditionalPkcs1() throws IOException {\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"pkcs1/rsa.key\"));\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(\"RSA\");\n\t}\n\n\t@Test\n\tvoid shouldNotParseUnsupportedTraditionalPkcs1() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read(\"pkcs1/dsa.key\")))\n\t\t\t.withMessageContaining(\"Missing private key or unrecognized format\");\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@CsvSource({\n\t\t\t\"brainpoolP256r1.key,\tbrainpoolP256r1,\t1.3.36.3.3.2.8.1.1.7\",\n\t\t\t\"brainpoolP320r1.key,\tbrainpoolP320r1,\t1.3.36.3.3.2.8.1.1.9\",\n\t\t\t\"brainpoolP384r1.key,\tbrainpoolP384r1,\t1.3.36.3.3.2.8.1.1.11\",\n\t\t\t\"brainpoolP512r1.key,\tbrainpoolP512r1,\t1.3.36.3.3.2.8.1.1.13\",\n\t\t\t\"prime256v1.key,\t\tsecp256r1,\t\t\t1.2.840.10045.3.1.7\",\n\t\t\t\"secp224r1.key,\t\t\tsecp224r1,\t\t\t1.3.132.0.33\",\n\t\t\t\"secp256k1.key,\t\t\tsecp256k1,\t\t\t1.3.132.0.10\",\n\t\t\t\"secp256r1.key,\t\t\tsecp256r1,\t\t\t1.2.840.10045.3.1.7\",\n\t\t\t\"secp384r1.key,\t\t\tsecp384r1,\t\t\t1.3.132.0.34\",\n\t\t\t\"secp521r1.key,\t\t\tsecp521r1,\t\t\t1.3.132.0.35\"\n\t})\n\t// @formatter:on\n\tvoid shouldParseEcPkcs8(String file, String curveName, String oid) throws IOException {\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"pkcs8/\" + file));\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(\"EC\");\n\t\tassertThat(privateKey).isInstanceOf(ECPrivateKey.class);\n\t\tECPrivateKey ecPrivateKey = (ECPrivateKey) privateKey;\n\t\tassertThat(ecPrivateKey.getParams().toString()).contains(curveName).contains(oid);\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@ValueSource(strings = {\n\t\t\t\"brainpoolP256t1.key\",\n\t\t\t\"brainpoolP320t1.key\",\n\t\t\t\"brainpoolP384t1.key\",\n\t\t\t\"brainpoolP512t1.key\"\n\t})\n\t\t// @formatter:on\n\tvoid shouldNotParseUnsupportedEcPkcs8(String file) {\n\t\tassertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read(\"pkcs8/\" + file)))\n\t\t\t.withMessageContaining(\"Missing private key or unrecognized format\");\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@ValueSource(strings = {\n\t\t\t\"ed448.key\",\n\t\t\t\"ed25519.key\"\n\t})\n\t\t// @formatter:on\n\tvoid shouldParseEdDsaPkcs8(String file) throws IOException {\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"pkcs8/\" + file));\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(\"EdDSA\");\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@ValueSource(strings = {\n\t\t\t\"x448.key\",\n\t\t\t\"x25519.key\"\n\t})\n\t\t// @formatter:on\n\tvoid shouldParseXdhPkcs8(String file) throws IOException {\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"pkcs8/\" + file));\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(\"XDH\");\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@CsvSource({\n\t\t\t\"brainpoolP256r1.key,\tbrainpoolP256r1,\t1.3.36.3.3.2.8.1.1.7\",\n\t\t\t\"brainpoolP320r1.key,\tbrainpoolP320r1,\t1.3.36.3.3.2.8.1.1.9\",\n\t\t\t\"brainpoolP384r1.key,\tbrainpoolP384r1,\t1.3.36.3.3.2.8.1.1.11\",\n\t\t\t\"brainpoolP512r1.key,\tbrainpoolP512r1,\t1.3.36.3.3.2.8.1.1.13\",\n\t\t\t\"prime256v1.key,\t\tsecp256r1,\t\t\t1.2.840.10045.3.1.7\",\n\t\t\t\"secp224r1.key,\t\t\tsecp224r1,\t\t\t1.3.132.0.33\",\n\t\t\t\"secp256k1.key,\t\t\tsecp256k1,\t\t\t1.3.132.0.10\",\n\t\t\t\"secp256r1.key,\t\t\tsecp256r1,\t\t\t1.2.840.10045.3.1.7\",\n\t\t\t\"secp384r1.key,\t\t\tsecp384r1,\t\t\t1.3.132.0.34\",\n\t\t\t\"secp521r1.key,\t\t\tsecp521r1,\t\t\t1.3.132.0.35\"\n\t})\n\t\t// @formatter:on\n\tvoid shouldParseEcSec1(String file, String curveName, String oid) throws IOException {\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"sec1/\" + file));\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(\"EC\");\n\t\tassertThat(privateKey).isInstanceOf(ECPrivateKey.class);\n\t\tECPrivateKey ecPrivateKey = (ECPrivateKey) privateKey;\n\t\tassertThat(ecPrivateKey.getParams().toString()).contains(curveName).contains(oid);\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@ValueSource(strings = {\n\t\t\t\"brainpoolP256t1.key\",\n\t\t\t\"brainpoolP320t1.key\",\n\t\t\t\"brainpoolP384t1.key\",\n\t\t\t\"brainpoolP512t1.key\"\n\t})\n\t\t// @formatter:on\n\tvoid shouldNotParseUnsupportedEcSec1(String file) {\n\t\tassertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read(\"sec1/\" + file)))\n\t\t\t.withMessageContaining(\"Missing private key or unrecognized format\");\n\t}\n\n\t@Test\n\tvoid parseWithNonKeyTextWillThrowException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> PemPrivateKeyParser.parse(read(\"file.txt\")));\n\t}\n\n\t@ParameterizedTest\n\t// @formatter:off\n\t@CsvSource({\n\t\t\t\"dsa-aes-128-cbc.key,\t\t\t\tDSA\",\n\t\t\t\"rsa-aes-256-cbc.key,\t\t\t\tRSA\",\n\t\t\t\"prime256v1-aes-256-cbc.key,\t\tEC\",\n\t\t\t\"ed25519-aes-256-cbc.key,\t\t\tEdDSA\",\n\t\t\t\"x448-aes-256-cbc.key,\t\t\t\tXDH\"\n\t})\n\t\t// @formatter:on\n\tvoid shouldParseEncryptedPkcs8(String file, String algorithm) throws IOException {\n\t\t// Created with:\n\t\t// openssl pkcs8 -topk8 -in <input file> -out <output file> -v2 <algorithm>\n\t\t// -passout pass:test\n\t\t// where <algorithm> is aes128 or aes256\n\t\tPrivateKey privateKey = PemPrivateKeyParser.parse(read(\"pkcs8/\" + file), \"test\");\n\t\tassertThat(privateKey).isNotNull();\n\t\tassertThat(privateKey.getFormat()).isEqualTo(\"PKCS#8\");\n\t\tassertThat(privateKey.getAlgorithm()).isEqualTo(algorithm);\n\t}\n\n\t@Test\n\tvoid shouldNotParseEncryptedPkcs8NotUsingAes() {\n\t\t// Created with:\n\t\t// openssl pkcs8 -topk8 -in rsa.key -out rsa-des-ede3-cbc.key -v2 des3 -passout\n\t\t// pass:test\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> PemPrivateKeyParser.parse(read(\"pkcs8/rsa-des-ede3-cbc.key\"), \"test\"))\n\t\t\t.isInstanceOf(IllegalStateException.class)\n\t\t\t.withMessageContaining(\"Error decrypting private key\");\n\t}\n\n\t@Test\n\tvoid shouldNotParseEncryptedPkcs8NotUsingPbkdf2() {\n\t\t// Created with:\n\t\t// openssl pkcs8 -topk8 -in rsa.key -out rsa-des-ede3-cbc.key -scrypt -passout\n\t\t// pass:test\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> PemPrivateKeyParser.parse(read(\"pkcs8/rsa-scrypt.key\"), \"test\"))\n\t\t\t.withMessageContaining(\"Error decrypting private key\");\n\t}\n\n\t@Test\n\tvoid shouldNotParseEncryptedSec1() {\n\t\t// created with:\n\t\t// openssl ecparam -genkey -name prime256v1 | openssl ec -aes-128-cbc -out\n\t\t// prime256v1-aes-128-cbc.key\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> PemPrivateKeyParser.parse(read(\"sec1/prime256v1-aes-128-cbc.key\"), \"test\"))\n\t\t\t.withMessageContaining(\"Missing private key or unrecognized format\");\n\t}\n\n\t@Test\n\tvoid shouldNotParseEncryptedPkcs1() {\n\t\t// created with:\n\t\t// openssl genrsa -aes-256-cbc -out rsa-aes-256-cbc.key\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> PemPrivateKeyParser.parse(read(\"pkcs1/rsa-aes-256-cbc.key\"), \"test\"))\n\t\t\t.withMessageContaining(\"Missing private key or unrecognized format\");\n\t}\n\n\tprivate String read(String path) throws IOException {\n\t\treturn new ClassPathResource(\"org/springframework/boot/ssl/pem/\" + path)\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.security.KeyStore;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link PemSslStoreBundle}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass PemSslStoreBundleTests {\n\n\tprivate static final String CERTIFICATE = \"\"\"\n\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\tMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\n\t\t\tBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\n\t\t\tMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\n\t\t\taG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\n\t\t\tBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\n\t\t\tMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\n\t\t\taG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n\t\t\t+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\n\t\t\tsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\n\t\t\tnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n\t\t\t11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\n\t\t\tfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\n\t\t\tUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\n\t\t\tA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\n\t\t\thkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\n\t\t\thHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\n\t\t\tgJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\n\t\t\tdG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\n\t\t\tfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\n\t\t\tILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n\t\t\t-----END CERTIFICATE-----\n\t\t\t\"\"\".strip();\n\n\tprivate static final String PRIVATE_KEY = \"\"\"\n\t\t\t-----BEGIN PRIVATE KEY-----\n\t\t\tMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD8B1saBN8Y0ZjX\n\t\t\tQ/pvnv2hZa+cBBkFHVkgw+tdzgdcO5Kjv2rnRKd3Oh8Qwdxj3BC9GpicF4GOgkDG\n\t\t\tLrMrYbmV/xGUnNh3YpUwbv+U/pm3VnuSZCk4aYgNEWHrnEHyrge87+MqYqGuMIke\n\t\t\tA5z7GV44PeThfKQs2BLLL/ME+Pb/jN6IVlIHxdBT5TBQkqNGFU7swdZoQ5Viqv44\n\t\t\tUNdVqU5pP3UF/perbOm2CHCbeLiLRvmuvGuBbrbko2XUwBNH+UjmEQaRh/epoy8B\n\t\t\tD31vGY87ym/YOEdpIrqD8bwg7NWP/Fdsryqi8p+U8fcfw4xZjotA0Sv04BC7zXHg\n\t\t\tm1AyZoVzAgMBAAECggEAfEqiZqANaF+BqXQIb4Dw42ZTJzWsIyYYnPySOGZRoe5t\n\t\t\tQJ03uwtULYv34xtANe1DQgd6SMyc46ugBzzjtprQ3ET5Jhn99U6kdcjf+dpf85dO\n\t\t\thOEppP0CkDNI39nleinSfh6uIOqYgt/D143/nqQhn8oCdSOzkbwT9KnWh1bC9T7I\n\t\t\tvFjGfElvt1/xl88qYgrWgYLgXaencNGgiv/4/M0FNhiHEGsVC7SCu6kapC/WIQpE\n\t\t\t5IdV+HR+tiLoGZhXlhqorY7QC4xKC4wwafVSiFxqDOQAuK+SMD4TCEv0Aop+c+SE\n\t\t\tYBigVTmgVeJkjK7IkTEhKkAEFmRF5/5w+bZD9FhTNQKBgQD+4fNG1ChSU8RdizZT\n\t\t\t5dPlDyAxpETSCEXFFVGtPPh2j93HDWn7XugNyjn5FylTH507QlabC+5wZqltdIjK\n\t\t\tGRB5MIinQ9/nR2fuwGc9s+0BiSEwNOUB1MWm7wWL/JUIiKq6sTi6sJIfsYg79zco\n\t\t\tqxl5WE94aoINx9Utq1cdWhwJTQKBgQD9IjPksd4Jprz8zMrGLzR8k1gqHyhv24qY\n\t\t\tEJ7jiHKKAP6xllTUYwh1IBSL6w2j5lfZPpIkb4Jlk2KUoX6fN81pWkBC/fTBUSIB\n\t\t\tEHM9bL51+yKEYUbGIy/gANuRbHXsWg3sjUsFTNPN4hGTFk3w2xChCyl/f5us8Lo8\n\t\t\tZ633SNdpvwKBgQCGyDU9XzNzVZihXtx7wS0sE7OSjKtX5cf/UCbA1V0OVUWR3SYO\n\t\t\tJ0HPCQFfF0BjFHSwwYPKuaR9C8zMdLNhK5/qdh/NU7czNi9fsZ7moh7SkRFbzJzN\n\t\t\tOxbKD9t/CzJEMQEXeF/nWTfsSpUgILqqZtAxuuFLbAcaAnJYlCKdAumQgQKBgQCK\n\t\t\tmqjJh68pn7gJwGUjoYNe1xtGbSsqHI9F9ovZ0MPO1v6e5M7sQJHH+Fnnxzv/y8e8\n\t\t\td6tz8e73iX1IHymDKv35uuZHCGF1XOR+qrA/KQUc+vcKf21OXsP/JtkTRs1HLoRD\n\t\t\tS5aRf2DWcfvniyYARSNU2xTM8GWgi2ueWbMDHUp+ZwKBgA/swC+K+Jg5DEWm6Sau\n\t\t\te6y+eC6S+SoXEKkI3wf7m9aKoZo0y+jh8Gas6gratlc181pSM8O3vZG0n19b493I\n\t\t\tapCFomMLE56zEzvyzfpsNhFhk5MBMCn0LPyzX6MiynRlGyWIj0c99fbHI3pOMufP\n\t\t\tWgmVLTZ8uDcSW1MbdUCwFSk5\n\t\t\t-----END PRIVATE KEY-----\n\t\t\t\"\"\".strip();\n\n\tprivate static final char[] EMPTY_KEY_PASSWORD = new char[] {};\n\n\t@Test\n\tvoid createWithDetailsWhenNullStores() {\n\t\tPemSslStoreDetails keyStoreDetails = null;\n\t\tPemSslStoreDetails trustStoreDetails = null;\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).isNull();\n\t\tassertThat(bundle.getKeyStorePassword()).isNull();\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithDetailsWhenStoresHaveNoValues() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(null);\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(null);\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).isNull();\n\t\tassertThat(bundle.getKeyStorePassword()).isNull();\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid createWithDetailsWhenHasKeyStoreDetailsCertAndKey() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tPemSslStoreDetails trustStoreDetails = null;\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"pkcs8/key-rsa-encrypted.pem\" })\n\tvoid createWithDetailsWhenHasKeyStoreDetailsCertAndEncryptedKey() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:pkcs8/key-rsa-encrypted.pem\")\n\t\t\t.withPrivateKeyPassword(\"test\");\n\t\tPemSslStoreDetails trustStoreDetails = null;\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).isNull();\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetailsWithoutKey() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\");\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCert(\"ssl\"));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetails() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\");\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t}\n\n\t@Test\n\tvoid createWithDetailsWhenHasEmbeddedKeyStoreDetailsAndTrustStoreDetails() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(CERTIFICATE).withPrivateKey(PRIVATE_KEY);\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(CERTIFICATE)\n\t\t\t.withPrivateKey(PRIVATE_KEY);\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid createWithDetailsWhenHasStoreType() {\n\t\tPemSslStoreDetails keyStoreDetails = new PemSslStoreDetails(\"PKCS12\", \"classpath:test-cert.pem\",\n\t\t\t\t\"classpath:test-key.pem\");\n\t\tPemSslStoreDetails trustStoreDetails = new PemSslStoreDetails(\"PKCS12\", \"classpath:test-cert.pem\",\n\t\t\t\t\"classpath:test-key.pem\");\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"PKCS12\", \"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"PKCS12\", \"ssl\"));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid createWithDetailsWhenHasKeyStoreDetailsAndTrustStoreDetailsAndKeyPassword() {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\")\n\t\t\t.withAlias(\"ksa\")\n\t\t\t.withPassword(\"kss\");\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(\"classpath:test-cert.pem\")\n\t\t\t.withPrivateKey(\"classpath:test-key.pem\")\n\t\t\t.withAlias(\"tsa\")\n\t\t\t.withPassword(\"tss\");\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ksa\", \"kss\".toCharArray()));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"tsa\", \"tss\".toCharArray()));\n\t}\n\n\t@Test\n\tvoid createWithPemSslStoreCreatesInstance() {\n\t\tList<X509Certificate> certificates = PemContent.of(CERTIFICATE).getCertificates();\n\t\tPrivateKey privateKey = PemContent.of(PRIVATE_KEY).getPrivateKey();\n\t\tPemSslStore pemSslStore = PemSslStore.of(certificates, privateKey);\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(pemSslStore, pemSslStore);\n\t\tassertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t\tassertThat(bundle.getTrustStore()).satisfies(storeContainingCertAndKey(\"ssl\"));\n\t}\n\n\t@Test\n\tvoid storeCreationIsLazy() {\n\t\tPemSslStore pemSslStore = mock(PemSslStore.class);\n\t\tPemSslStoreBundle bundle = new PemSslStoreBundle(pemSslStore, pemSslStore);\n\t\tgiven(pemSslStore.certificates()).willReturn(PemContent.of(CERTIFICATE).getCertificates());\n\t\tthen(pemSslStore).shouldHaveNoInteractions();\n\t\tbundle.getKeyStore();\n\t\tthen(pemSslStore).should().certificates();\n\t\tbundle.getTrustStore();\n\t\tthen(pemSslStore).should(times(2)).certificates();\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCert(String keyAlias) {\n\t\treturn storeContainingCert(KeyStore.getDefaultType(), keyAlias);\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCert(String keyStoreType, String keyAlias) {\n\t\treturn ThrowingConsumer.of((keyStore) -> {\n\t\t\tassertThat(keyStore).isNotNull();\n\t\t\tassertThat(keyStore.getType()).isEqualTo(keyStoreType);\n\t\t\tassertThat(keyStore.containsAlias(keyAlias)).isTrue();\n\t\t\tassertThat(keyStore.getCertificate(keyAlias)).isNotNull();\n\t\t\tassertThat(keyStore.getKey(keyAlias, EMPTY_KEY_PASSWORD)).isNull();\n\t\t});\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyAlias) {\n\t\treturn storeContainingCertAndKey(KeyStore.getDefaultType(), keyAlias);\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyStoreType, String keyAlias) {\n\t\treturn storeContainingCertAndKey(keyStoreType, keyAlias, EMPTY_KEY_PASSWORD);\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyAlias, char[] keyPassword) {\n\t\treturn storeContainingCertAndKey(KeyStore.getDefaultType(), keyAlias, keyPassword);\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyStoreType, String keyAlias, char[] keyPassword) {\n\t\treturn ThrowingConsumer.of((keyStore) -> {\n\t\t\tassertThat(keyStore).isNotNull();\n\t\t\tassertThat(keyStore.getType()).isEqualTo(keyStoreType);\n\t\t\tassertThat(keyStore.containsAlias(keyAlias)).isTrue();\n\t\t\tassertThat(keyStore.getCertificate(keyAlias)).isNotNull();\n\t\t\tassertThat(keyStore.getKey(keyAlias, keyPassword)).isNotNull();\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/ssl/pem/PemSslStoreTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ssl.pem;\n\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PemSslStore}.\n *\n * @author Phillip Webb\n */\nclass PemSslStoreTests {\n\n\t@Test\n\tvoid withAliasReturnsStoreWithNewAlias() {\n\t\tList<X509Certificate> certificates = List.of(mock(X509Certificate.class));\n\t\tPrivateKey privateKey = mock(PrivateKey.class);\n\t\tPemSslStore store = PemSslStore.of(\"type\", \"alias\", \"secret\", certificates, privateKey);\n\t\tassertThat(store.withAlias(\"newalias\").alias()).isEqualTo(\"newalias\");\n\t}\n\n\t@Test\n\tvoid withPasswordReturnsStoreWithNewPassword() {\n\t\tList<X509Certificate> certificates = List.of(mock(X509Certificate.class));\n\t\tPrivateKey privateKey = mock(PrivateKey.class);\n\t\tPemSslStore store = PemSslStore.of(\"type\", \"alias\", \"secret\", certificates, privateKey);\n\t\tassertThat(store.withPassword(\"newsecret\").password()).isEqualTo(\"newsecret\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenNullCertificatesThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PemSslStore.of(null, null, null, null, null))\n\t\t\t.withMessage(\"'certificates' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenEmptyCertificatesThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> PemSslStore.of(null, null, null, Collections.emptyList(), null))\n\t\t\t.withMessage(\"'certificates' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofReturnsPemSslStore() {\n\t\tList<X509Certificate> certificates = List.of(mock(X509Certificate.class));\n\t\tPrivateKey privateKey = mock(PrivateKey.class);\n\t\tPemSslStore store = PemSslStore.of(\"type\", \"alias\", \"password\", certificates, privateKey);\n\t\tassertThat(store.type()).isEqualTo(\"type\");\n\t\tassertThat(store.alias()).isEqualTo(\"alias\");\n\t\tassertThat(store.password()).isEqualTo(\"password\");\n\t\tassertThat(store.certificates()).isEqualTo(certificates);\n\t\tassertThat(store.privateKey()).isEqualTo(privateKey);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/support/AnsiOutputApplicationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\nimport org.springframework.boot.ansi.AnsiOutputEnabledValue;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AnsiOutputApplicationListener}.\n *\n * @author Phillip Webb\n */\nclass AnsiOutputApplicationListenerTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@BeforeEach\n\tvoid resetAnsi() {\n\t\tAnsiOutput.setEnabled(Enabled.DETECT);\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tresetAnsi();\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid enabled() {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tMap<String, Object> props = new HashMap<>();\n\t\tprops.put(\"spring.output.ansi.enabled\", \"ALWAYS\");\n\t\tapplication.setDefaultProperties(props);\n\t\tthis.context = application.run();\n\t\tassertThat(AnsiOutputEnabledValue.get()).isEqualTo(Enabled.ALWAYS);\n\t}\n\n\t@Test\n\tvoid disabled() {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tMap<String, Object> props = new HashMap<>();\n\t\tprops.put(\"spring.output.ansi.enabled\", \"never\");\n\t\tapplication.setDefaultProperties(props);\n\t\tthis.context = application.run();\n\t\tassertThat(AnsiOutputEnabledValue.get()).isEqualTo(Enabled.NEVER);\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.output.ansi.enabled=never\")\n\tvoid disabledViaApplicationProperties() {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = application.run();\n\t\tassertThat(AnsiOutputEnabledValue.get()).isEqualTo(Enabled.NEVER);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/support/EnvironmentPostProcessorApplicationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.boot.logging.DeferredLogs;\nimport org.springframework.boot.support.EnvironmentPostProcessorApplicationListener.EnvironmentBeanFactoryInitializationAotProcessor;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.test.tools.Compiled;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link EnvironmentPostProcessorApplicationListener}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass EnvironmentPostProcessorApplicationListenerTests {\n\n\t@Nested\n\tclass ListenerTests {\n\n\t\tprivate final DeferredLogs deferredLogs = spy(new DeferredLogs());\n\n\t\tprivate final DefaultBootstrapContext bootstrapContext = spy(new DefaultBootstrapContext());\n\n\t\tprivate final EnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener();\n\n\t\t@BeforeEach\n\t\tvoid setup() {\n\t\t\tReflectionTestUtils.setField(this.listener, \"deferredLogs\", this.deferredLogs);\n\t\t\tReflectionTestUtils.setField(this.listener, \"postProcessorsFactory\",\n\t\t\t\t\t(Function<ClassLoader, EnvironmentPostProcessorsFactory>) (\n\t\t\t\t\t\t\tclassLoader) -> EnvironmentPostProcessorsFactory.of(TestEnvironmentPostProcessor.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid createUsesSpringFactories() {\n\t\t\tEnvironmentPostProcessorApplicationListener listener = new EnvironmentPostProcessorApplicationListener();\n\t\t\tassertThat(listener.getEnvironmentPostProcessors(null, this.bootstrapContext)).hasSizeGreaterThan(1);\n\t\t}\n\n\t\t@Test\n\t\tvoid createWhenHasFactoryUsesFactory() {\n\t\t\tEnvironmentPostProcessorApplicationListener listener = EnvironmentPostProcessorApplicationListener\n\t\t\t\t.with(EnvironmentPostProcessorsFactory.of(TestEnvironmentPostProcessor.class));\n\t\t\tList<EnvironmentPostProcessor> postProcessors = listener.getEnvironmentPostProcessors(null,\n\t\t\t\t\tthis.bootstrapContext);\n\t\t\tassertThat(postProcessors).hasSize(1);\n\t\t\tassertThat(postProcessors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid supportsEventTypeWhenApplicationEnvironmentPreparedEventReturnsTrue() {\n\t\t\tassertThat(this.listener.supportsEventType(ApplicationEnvironmentPreparedEvent.class)).isTrue();\n\t\t}\n\n\t\t@Test\n\t\tvoid supportsEventTypeWhenApplicationPreparedEventReturnsTrue() {\n\t\t\tassertThat(this.listener.supportsEventType(ApplicationPreparedEvent.class)).isTrue();\n\t\t}\n\n\t\t@Test\n\t\tvoid supportsEventTypeWhenApplicationFailedEventReturnsTrue() {\n\t\t\tassertThat(this.listener.supportsEventType(ApplicationFailedEvent.class)).isTrue();\n\t\t}\n\n\t\t@Test\n\t\tvoid supportsEventTypeWhenOtherEventReturnsFalse() {\n\t\t\tassertThat(this.listener.supportsEventType(ApplicationStartingEvent.class)).isFalse();\n\t\t}\n\n\t\t@Test\n\t\tvoid onApplicationEventWhenApplicationEnvironmentPreparedEventCallsPostProcessors() {\n\t\t\tSpringApplication application = mock(SpringApplication.class);\n\t\t\tMockEnvironment environment = new MockEnvironment();\n\t\t\tApplicationEnvironmentPreparedEvent event = new ApplicationEnvironmentPreparedEvent(this.bootstrapContext,\n\t\t\t\t\tapplication, new String[0], environment);\n\t\t\tthis.listener.onApplicationEvent(event);\n\t\t\tassertThat(environment.getProperty(\"processed\")).isEqualTo(\"true\");\n\t\t}\n\n\t\t@Test\n\t\tvoid onApplicationEventWhenApplicationPreparedEventSwitchesLogs() {\n\t\t\tSpringApplication application = mock(SpringApplication.class);\n\t\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\t\tApplicationPreparedEvent event = new ApplicationPreparedEvent(application, new String[0], context);\n\t\t\tthis.listener.onApplicationEvent(event);\n\t\t\tthen(this.deferredLogs).should().switchOverAll();\n\t\t}\n\n\t\t@Test\n\t\tvoid onApplicationEventWhenApplicationFailedEventSwitchesLogs() {\n\t\t\tSpringApplication application = mock(SpringApplication.class);\n\t\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\t\tApplicationFailedEvent event = new ApplicationFailedEvent(application, new String[0], context,\n\t\t\t\t\tnew RuntimeException());\n\t\t\tthis.listener.onApplicationEvent(event);\n\t\t\tthen(this.deferredLogs).should().switchOverAll();\n\t\t}\n\n\t\tstatic class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\t\tTestEnvironmentPostProcessor(DeferredLogFactory logFactory, BootstrapRegistry bootstrapRegistry) {\n\t\t\t\tassertThat(logFactory).isNotNull();\n\t\t\t\tassertThat(bootstrapRegistry).isNotNull();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t\t\t((MockEnvironment) environment).setProperty(\"processed\", \"true\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass AotTests {\n\n\t\tprivate static final ClassName TEST_APP = ClassName.get(\"com.example\", \"TestApp\");\n\n\t\t@Test\n\t\tvoid aotContributionIsNotNecessaryWithDefaultConfiguration() {\n\t\t\tassertThat(getContribution(new StandardEnvironment())).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid aotContributionIsNotNecessaryWithDefaultProfileActive() {\n\t\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\t\tenvironment.setDefaultProfiles(\"fallback\");\n\t\t\tenvironment.setActiveProfiles(\"fallback\");\n\t\t\tassertThat(getContribution(environment)).isNull();\n\t\t}\n\n\t\t@Test\n\t\tvoid aotContributionRegistersActiveProfiles() {\n\t\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\t\tenvironment.setActiveProfiles(\"one\", \"two\");\n\t\t\tcompile(createContext(environment), (compiled) -> {\n\t\t\t\tEnvironmentPostProcessor environmentPostProcessor = compiled.getInstance(EnvironmentPostProcessor.class,\n\t\t\t\t\t\tClassName.get(\"com.example\", \"TestApp__EnvironmentPostProcessor\").toString());\n\t\t\t\tStandardEnvironment freshEnvironment = new StandardEnvironment();\n\t\t\t\tenvironmentPostProcessor.postProcessEnvironment(freshEnvironment, new SpringApplication());\n\t\t\t\tassertThat(freshEnvironment.getActiveProfiles()).containsExactly(\"one\", \"two\");\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid aotContributionRegistersReflectionHints() {\n\t\t\tGenericApplicationContext applicationContext = new GenericApplicationContext();\n\t\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\t\tenvironment.setActiveProfiles(\"one\", \"two\");\n\t\t\tapplicationContext.getBeanFactory().registerSingleton(\"environment\", environment);\n\t\t\tBeanFactoryInitializationAotContribution aotContribution = new EnvironmentBeanFactoryInitializationAotProcessor()\n\t\t\t\t.processAheadOfTime(applicationContext.getBeanFactory());\n\t\t\tassertThat(aotContribution).isNotNull();\n\t\t\tGenerationContext generationContext = new TestGenerationContext();\n\t\t\taotContribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(TypeReference.of(TestGenerationContext.TEST_TARGET + \"__\"\n\t\t\t\t\t\t+ EnvironmentPostProcessorApplicationListener.AOT_FEATURE_NAME))\n\t\t\t\t.withMemberCategory(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS))\n\t\t\t\t.accepts(generationContext.getRuntimeHints());\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldUseAotEnvironmentPostProcessor() {\n\t\t\tSpringApplication application = new SpringApplication(ExampleAotProcessedApp.class);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tapplication.setMainApplicationClass(ExampleAotProcessedApp.class);\n\t\t\tSystem.setProperty(AotDetector.AOT_ENABLED, \"true\");\n\t\t\ttry {\n\t\t\t\tApplicationContext context = application.run();\n\t\t\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"one\", \"three\");\n\t\t\t\tassertThat(context.getBean(\"test\")).isEqualTo(\"test\");\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tSystem.clearProperty(AotDetector.AOT_ENABLED);\n\t\t\t}\n\t\t}\n\n\t\t@Test\n\t\tvoid aotEnvironmentPostProcessorShouldBeAppliedFirst(@TempDir Path tempDir) {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(EnvironmentPostProcessor.class.getName(), TestEnvironmentPostProcessor.class.getName());\n\t\t\tClassLoader classLoader = createClassLoaderWithAdditionalSpringFactories(tempDir, properties);\n\t\t\tDefaultResourceLoader resourceLoader = new DefaultResourceLoader(classLoader);\n\n\t\t\tSpringApplication application = new SpringApplication(ExampleAotProcessedApp.class);\n\t\t\tapplication.setResourceLoader(resourceLoader);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tapplication.setMainApplicationClass(ExampleAotProcessedApp.class);\n\t\t\tSystem.setProperty(AotDetector.AOT_ENABLED, \"true\");\n\t\t\ttry {\n\t\t\t\tApplicationContext context = application.run();\n\t\t\t\t// See TestEnvironmentPostProcessor\n\t\t\t\tassertThat(context.getEnvironment().getProperty(\"test.activeProfiles\")).isEqualTo(\"one,three\");\n\t\t\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"one\", \"three\");\n\t\t\t\tassertThat(context.getBean(\"test\")).isEqualTo(\"test\");\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tSystem.clearProperty(AotDetector.AOT_ENABLED);\n\t\t\t}\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldBeLenientIfAotEnvironmentPostProcessorDoesNotExist() {\n\t\t\tSpringApplication application = new SpringApplication(ExampleAotProcessedNoProfileApp.class);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t\tapplication.setMainApplicationClass(ExampleAotProcessedNoProfileApp.class);\n\t\t\tSystem.setProperty(AotDetector.AOT_ENABLED, \"true\");\n\t\t\ttry {\n\t\t\t\tApplicationContext context = application.run();\n\t\t\t\tassertThat(context.getEnvironment().getActiveProfiles()).isEmpty();\n\t\t\t\tassertThat(context.getBean(\"test\")).isEqualTo(\"test\");\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tSystem.clearProperty(AotDetector.AOT_ENABLED);\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable BeanFactoryInitializationAotContribution getContribution(\n\t\t\t\tConfigurableEnvironment environment) {\n\t\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\t\tbeanFactory.registerSingleton(ConfigurableApplicationContext.ENVIRONMENT_BEAN_NAME, environment);\n\t\t\treturn new EnvironmentBeanFactoryInitializationAotProcessor().processAheadOfTime(beanFactory);\n\t\t}\n\n\t\tprivate GenericApplicationContext createContext(ConfigurableEnvironment environment) {\n\t\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\t\tcontext.setEnvironment(environment);\n\t\t\treturn context;\n\t\t}\n\n\t\tprivate void compile(GenericApplicationContext context, Consumer<Compiled> compiled) {\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext(TEST_APP);\n\t\t\tnew ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\t\tgenerationContext.writeGeneratedContent();\n\t\t\tTestCompiler.forSystem()\n\t\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t\t.with(generationContext)\n\t\t\t\t.compile(compiled);\n\t\t}\n\n\t\tprivate ClassLoader createClassLoaderWithAdditionalSpringFactories(Path tempDir, Properties properties) {\n\t\t\treturn new ClassLoader() {\n\t\t\t\t@Override\n\t\t\t\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t\t\t\tEnumeration<URL> resources = super.getResources(name);\n\t\t\t\t\tif (SpringFactoriesLoader.FACTORIES_RESOURCE_LOCATION.equals(name)) {\n\t\t\t\t\t\tPath springFactories = tempDir.resolve(\"spring.factories\");\n\t\t\t\t\t\ttry (BufferedWriter writer = Files.newBufferedWriter(springFactories)) {\n\t\t\t\t\t\t\tproperties.store(writer, \"\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tList<URL> allResources = new ArrayList<>();\n\t\t\t\t\t\tallResources.add(springFactories.toUri().toURL());\n\t\t\t\t\t\tallResources.addAll(Collections.list(resources));\n\t\t\t\t\t\treturn Collections.enumeration(allResources);\n\t\t\t\t\t}\n\t\t\t\t\treturn resources;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tstatic class TestEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\t\t\t@Override\n\t\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t\t\tMockPropertySource propertySource = new MockPropertySource().withProperty(\"test.activeProfiles\",\n\t\t\t\t\t\tStringUtils.arrayToCommaDelimitedString(environment.getActiveProfiles()));\n\t\t\t\tenvironment.getPropertySources().addLast(propertySource);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic int getOrder() {\n\t\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class ExampleAotProcessedApp {\n\n\t\t}\n\n\t\tstatic class ExampleAotProcessedApp__ApplicationContextInitializer\n\t\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t\t@Override\n\t\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\t\tapplicationContext.getBeanFactory().registerSingleton(\"test\", \"test\");\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class ExampleAotProcessedApp__EnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\t\t@Override\n\t\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t\t\tenvironment.addActiveProfile(\"one\");\n\t\t\t\tenvironment.addActiveProfile(\"three\");\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class ExampleAotProcessedNoProfileApp {\n\n\t\t}\n\n\t\tstatic class ExampleAotProcessedNoProfileApp__ApplicationContextInitializer\n\t\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t\t@Override\n\t\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\t\tapplicationContext.getBeanFactory().registerSingleton(\"test\", \"test\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/support/RandomValuePropertySourceEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RandomValuePropertySourceEnvironmentPostProcessor}.\n *\n * @author Phillip Webb\n */\nclass RandomValuePropertySourceEnvironmentPostProcessorTests {\n\n\tprivate final RandomValuePropertySourceEnvironmentPostProcessor postProcessor = new RandomValuePropertySourceEnvironmentPostProcessor(\n\t\t\tSupplier::get);\n\n\t@Test\n\tvoid getOrderIsBeforeConfigData() {\n\t\tassertThat(this.postProcessor.getOrder()).isLessThan(ConfigDataEnvironmentPostProcessor.ORDER);\n\t}\n\n\t@Test\n\tvoid postProcessEnvironmentAddsPropertySource() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tthis.postProcessor.postProcessEnvironment(environment, mock(SpringApplication.class));\n\t\tassertThat(environment.getProperty(\"random.string\")).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/support/ReflectionEnvironmentPostProcessorsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.core.OverridingClassLoader;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ReflectionEnvironmentPostProcessorsFactory}.\n *\n * @author Phillip Webb\n */\nclass ReflectionEnvironmentPostProcessorsFactoryTests {\n\n\tprivate final DeferredLogFactory logFactory = Supplier::get;\n\n\tprivate final DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\n\t@Test\n\tvoid createWithClassesCreatesFactory() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(\n\t\t\t\tTestEnvironmentPostProcessor.class);\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid createWithClassNamesArrayCreatesFactory() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tTestEnvironmentPostProcessor.class.getName());\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid createWithClassNamesListCreatesFactory() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tArrays.asList(TestEnvironmentPostProcessor.class.getName()));\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid createWithClassNamesAndClassLoaderListCreatesFactory() {\n\t\tOverridingClassLoader classLoader = new OverridingClassLoader(getClass().getClassLoader()) {\n\n\t\t\t@Override\n\t\t\tprotected boolean isEligibleForOverriding(String className) {\n\t\t\t\treturn super.isEligibleForOverriding(className)\n\t\t\t\t\t\t&& className.equals(TestEnvironmentPostProcessor.class.getName());\n\t\t\t}\n\n\t\t};\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(classLoader,\n\t\t\t\tArrays.asList(TestEnvironmentPostProcessor.class.getName()));\n\t\tassertThatFactory(factory).createsSinglePostProcessorWithClassLoader(classLoader);\n\t}\n\n\t@Test\n\tvoid getEnvironmentPostProcessorsWhenHasDefaultConstructorCreatesPostProcessors() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tTestEnvironmentPostProcessor.class.getName());\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid getEnvironmentPostProcessorsWhenHasLogFactoryConstructorCreatesPostProcessors() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tTestLogFactoryEnvironmentPostProcessor.class.getName());\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestLogFactoryEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid getEnvironmentPostProcessorsWhenHasLogConstructorCreatesPostProcessors() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tTestLogEnvironmentPostProcessor.class.getName());\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestLogEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid getEnvironmentPostProcessorsWhenHasBootstrapRegistryConstructorCreatesPostProcessors() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tTestBootstrapRegistryEnvironmentPostProcessor.class.getName());\n\t\tassertThatFactory(factory).createsSinglePostProcessor(TestBootstrapRegistryEnvironmentPostProcessor.class);\n\t}\n\n\t@Test\n\tvoid getEnvironmentPostProcessorsWhenHasNoSuitableConstructorThrowsException() {\n\t\tReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(null,\n\t\t\t\tBadEnvironmentPostProcessor.class.getName());\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.getEnvironmentPostProcessors(this.logFactory, this.bootstrapContext))\n\t\t\t.withMessageContaining(\"Unable to instantiate\");\n\t}\n\n\tprivate EnvironmentPostProcessorsFactoryAssert assertThatFactory(EnvironmentPostProcessorsFactory factory) {\n\t\treturn new EnvironmentPostProcessorsFactoryAssert(factory);\n\t}\n\n\tclass EnvironmentPostProcessorsFactoryAssert {\n\n\t\tprivate final EnvironmentPostProcessorsFactory factory;\n\n\t\tEnvironmentPostProcessorsFactoryAssert(EnvironmentPostProcessorsFactory factory) {\n\t\t\tthis.factory = factory;\n\t\t}\n\n\t\tvoid createsSinglePostProcessor(Class<?> expectedType) {\n\t\t\tEnvironmentPostProcessor processor = getSingleProcessor();\n\t\t\tassertThat(processor).isInstanceOf(expectedType);\n\t\t}\n\n\t\tvoid createsSinglePostProcessorWithClassLoader(OverridingClassLoader classLoader) {\n\t\t\tEnvironmentPostProcessor processor = getSingleProcessor();\n\t\t\tassertThat(processor.getClass().getClassLoader()).isSameAs(classLoader);\n\t\t}\n\n\t\tprivate EnvironmentPostProcessor getSingleProcessor() {\n\t\t\tList<EnvironmentPostProcessor> processors = this.factory.getEnvironmentPostProcessors(\n\t\t\t\t\tReflectionEnvironmentPostProcessorsFactoryTests.this.logFactory,\n\t\t\t\t\tReflectionEnvironmentPostProcessorsFactoryTests.this.bootstrapContext);\n\t\t\tassertThat(processors).hasSize(1);\n\t\t\treturn processors.get(0);\n\t\t}\n\n\t}\n\n\tstatic class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t}\n\n\t}\n\n\tstatic class TestLogFactoryEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\tTestLogFactoryEnvironmentPostProcessor(DeferredLogFactory logFactory) {\n\t\t\tassertThat(logFactory).isNotNull();\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t}\n\n\t}\n\n\tstatic class TestLogEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\tTestLogEnvironmentPostProcessor(Log log) {\n\t\t\tassertThat(log).isNotNull();\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t}\n\n\t}\n\n\tstatic class TestBootstrapRegistryEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\tTestBootstrapRegistryEnvironmentPostProcessor(BootstrapRegistry bootstrapRegistry) {\n\t\t\tassertThat(bootstrapRegistry).isNotNull();\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t}\n\n\t}\n\n\tstatic class BadEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t\tBadEnvironmentPostProcessor(InputStream inputStream) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/support/SpringApplicationJsonEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.json.JsonParseException;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link SpringApplicationJsonEnvironmentPostProcessor}.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Artsiom Yudovin\n */\nclass SpringApplicationJsonEnvironmentPostProcessorTests {\n\n\tprivate final SpringApplicationJsonEnvironmentPostProcessor processor = new SpringApplicationJsonEnvironmentPostProcessor();\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\t@Test\n\tvoid error() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"spring.application.json=foo:bar\");\n\t\tassertThatExceptionOfType(JsonParseException.class)\n\t\t\t.isThrownBy(() -> this.processor.postProcessEnvironment(this.environment, getApplication()))\n\t\t\t.withMessageContaining(\"Cannot parse JSON\");\n\t}\n\n\t@Test\n\tvoid missing() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid empty() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, \"spring.application.json={}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid periodSeparated() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"spring.application.json={\\\"foo\\\":\\\"bar\\\"}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid envVar() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":\\\"bar\\\"}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid nested() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":{\\\"bar\\\":\\\"spam\\\",\\\"rab\\\":\\\"maps\\\"}}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo.bar:}\")).isEqualTo(\"spam\");\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo.rab:}\")).isEqualTo(\"maps\");\n\t}\n\n\t@Test\n\tvoid prefixed() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo.bar\\\":\\\"spam\\\"}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo.bar:}\")).isEqualTo(\"spam\");\n\t}\n\n\t@Test\n\tvoid list() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo[1]:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":[\\\"bar\\\",\\\"spam\\\"]}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo[1]:}\")).isEqualTo(\"spam\");\n\t}\n\n\t@Test\n\tvoid listOfObject() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo[0].bar:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":[{\\\"bar\\\":\\\"spam\\\"}]}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo[0].bar:}\")).isEqualTo(\"spam\");\n\t}\n\n\t@Test\n\tvoid propertySourceShouldTrackOrigin() {\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEmpty();\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"spring.application.json={\\\"foo\\\":\\\"bar\\\"}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tPropertySource<?> propertySource = this.environment.getPropertySources().get(\"spring.application.json\");\n\t\tassertThat(propertySource).isNotNull();\n\t\tPropertySourceOrigin origin = (PropertySourceOrigin) PropertySourceOrigin.get(propertySource, \"foo\");\n\t\tassertThat(origin.getPropertySource().getName()).isEqualTo(\"Inlined Test Properties\");\n\t\tassertThat(origin.getPropertyName()).isEqualTo(\"spring.application.json\");\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo:}\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid propertySourceShouldBeOrderedBeforeJndiPropertySource() {\n\t\ttestServletPropertySource(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME);\n\t}\n\n\t@Test\n\tvoid propertySourceShouldBeOrderedBeforeServletContextPropertySource() {\n\t\ttestServletPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME);\n\t}\n\n\t@Test\n\tvoid propertySourceShouldBeOrderedBeforeServletConfigPropertySource() {\n\t\ttestServletPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME);\n\t}\n\n\t@Test\n\tvoid propertySourceOrderingWhenMultipleServletSpecificPropertySources() {\n\t\tMapPropertySource jndi = getPropertySource(StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME, \"jndi\");\n\t\tthis.environment.getPropertySources().addFirst(jndi);\n\t\tMapPropertySource servlet = getPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\"servlet\");\n\t\tthis.environment.getPropertySources().addFirst(servlet);\n\t\tMapPropertySource custom = getPropertySource(\"custom\", \"custom\");\n\t\tthis.environment.getPropertySources().addFirst(custom);\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":\\\"bar\\\"}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tPropertySource<?> json = this.environment.getPropertySources().get(\"spring.application.json\");\n\t\tassertThat(this.environment.getProperty(\"foo\")).isEqualTo(\"custom\");\n\t\tassertThat(this.environment.getPropertySources()).containsSequence(custom, json, servlet, jndi);\n\t}\n\n\t@Test\n\tvoid nullValuesShouldBeAddedToPropertySource() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":null}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.containsProperty(\"foo\")).isTrue();\n\t}\n\n\t@Test\n\tvoid emptyValuesForCollectionShouldNotBeIgnored() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":[]}\");\n\t\tMockPropertySource source = new MockPropertySource();\n\t\tsource.setProperty(\"foo\", \"bar\");\n\t\tthis.environment.getPropertySources().addLast(source);\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo}\")).isEqualTo(\"bar\");\n\t\tthis.environment.getPropertySources().addLast(source);\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.resolvePlaceholders(\"${foo}\")).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid emptyMapValuesShouldNotBeIgnored() {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":{}}\");\n\t\tMockPropertySource source = new MockPropertySource();\n\t\tsource.setProperty(\"foo.baz\", \"bar\");\n\t\tthis.environment.getPropertySources().addLast(source);\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.getProperty(\"foo\", Map.class)).isEmpty();\n\t}\n\n\tprivate SpringApplication getApplication() {\n\t\treturn new SpringApplication();\n\t}\n\n\tprivate void testServletPropertySource(String servletPropertySourceName) {\n\t\tthis.environment.getPropertySources().addFirst(getPropertySource(servletPropertySourceName, \"servlet\"));\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,\n\t\t\t\t\"SPRING_APPLICATION_JSON={\\\"foo\\\":\\\"bar\\\"}\");\n\t\tthis.processor.postProcessEnvironment(this.environment, getApplication());\n\t\tassertThat(this.environment.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\tprivate MapPropertySource getPropertySource(String name, String value) {\n\t\treturn new MapPropertySource(name, Collections.singletonMap(\"foo\", value));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/support/SystemEnvironmentPropertySourceEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.support;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.origin.SystemEnvironmentOrigin;\nimport org.springframework.boot.support.SystemEnvironmentPropertySourceEnvironmentPostProcessor.OriginAwareSystemEnvironmentPropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SystemEnvironmentPropertySourceEnvironmentPostProcessor}.\n *\n * @author Madhura Bhave\n */\nclass SystemEnvironmentPropertySourceEnvironmentPostProcessorTests {\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\tprivate final SpringApplication application = new SpringApplication();\n\n\t@Test\n\tvoid postProcessShouldReplaceSystemEnvironmentPropertySource() {\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor postProcessor = new SystemEnvironmentPropertySourceEnvironmentPostProcessor();\n\t\tpostProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tPropertySource<?> replaced = this.environment.getPropertySources().get(\"systemEnvironment\");\n\t\tassertThat(replaced).isInstanceOf(OriginAwareSystemEnvironmentPropertySource.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid replacedPropertySourceShouldBeOriginAware() {\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor postProcessor = new SystemEnvironmentPropertySourceEnvironmentPostProcessor();\n\t\tPropertySource<?> original = this.environment.getPropertySources().get(\"systemEnvironment\");\n\t\tassertThat(original).isNotNull();\n\t\tpostProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tOriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment\n\t\t\t.getPropertySources()\n\t\t\t.get(\"systemEnvironment\");\n\t\tassertThat(replaced).isNotNull();\n\t\tMap<String, Object> originalMap = (Map<String, Object>) original.getSource();\n\t\tMap<String, Object> replacedMap = replaced.getSource();\n\t\toriginalMap.forEach((key, value) -> {\n\t\t\tObject actual = replacedMap.get(key);\n\t\t\tassertThat(actual).isEqualTo(value);\n\t\t\tassertThat(replaced.getOrigin(key)).isInstanceOf(SystemEnvironmentOrigin.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid replacedPropertySourceWhenPropertyAbsentShouldReturnNullOrigin() {\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor postProcessor = new SystemEnvironmentPropertySourceEnvironmentPostProcessor();\n\t\tpostProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tOriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment\n\t\t\t.getPropertySources()\n\t\t\t.get(\"systemEnvironment\");\n\t\tassertThat(replaced).isNotNull();\n\t\tassertThat(replaced.getOrigin(\"NON_EXISTENT\")).isNull();\n\t}\n\n\t@Test\n\tvoid replacedPropertySourceShouldResolveProperty() {\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor postProcessor = new SystemEnvironmentPropertySourceEnvironmentPostProcessor();\n\t\tMap<String, Object> source = Collections.singletonMap(\"FOO_BAR_BAZ\", \"hello\");\n\t\tthis.environment.getPropertySources()\n\t\t\t.replace(\"systemEnvironment\", new SystemEnvironmentPropertySource(\"systemEnvironment\", source));\n\t\tpostProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tOriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment\n\t\t\t.getPropertySources()\n\t\t\t.get(\"systemEnvironment\");\n\t\tassertThat(replaced).isNotNull();\n\t\tSystemEnvironmentOrigin origin = (SystemEnvironmentOrigin) replaced.getOrigin(\"foo.bar.baz\");\n\t\tassertThat(origin).isNotNull();\n\t\tassertThat(origin.getProperty()).isEqualTo(\"FOO_BAR_BAZ\");\n\t\tassertThat(replaced.getProperty(\"foo.bar.baz\")).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid propertySourceShouldBePrefixed() {\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor postProcessor = new SystemEnvironmentPropertySourceEnvironmentPostProcessor();\n\t\tSpringApplication application = new SpringApplication();\n\t\tapplication.setEnvironmentPrefix(\"my\");\n\t\tpostProcessor.postProcessEnvironment(this.environment, application);\n\t\tOriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) this.environment\n\t\t\t.getPropertySources()\n\t\t\t.get(\"systemEnvironment\");\n\t\tassertThat(replaced).isNotNull();\n\t\tassertThat(replaced.getPrefix()).isEqualTo(\"my\");\n\t}\n\n\t@Test\n\tvoid postProcessWithParentEnvironmentShouldApplyPrefix() {\n\t\tSpringApplication application = new SpringApplication();\n\t\tapplication.setEnvironmentPrefix(\"my\");\n\t\tnew SystemEnvironmentPropertySourceEnvironmentPostProcessor().postProcessEnvironment(this.environment,\n\t\t\t\tapplication);\n\t\tStandardEnvironment child = new StandardEnvironment();\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor.postProcessEnvironment(child, this.environment);\n\t\tOriginAwareSystemEnvironmentPropertySource replaced = (OriginAwareSystemEnvironmentPropertySource) child\n\t\t\t.getPropertySources()\n\t\t\t.get(\"systemEnvironment\");\n\t\tassertThat(replaced).isNotNull();\n\t\tassertThat(replaced.getPrefix()).isEqualTo(\"my\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport net.bytebuddy.ByteBuddy;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ApplicationHome}.\n *\n * @author Andy Wilkinson\n */\nclass ApplicationHomeTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid whenSourceClassIsProvidedThenApplicationHomeReflectsItsLocation() throws Exception {\n\t\tFile app = new File(this.tempDir, \"app\");\n\t\tApplicationHome applicationHome = createApplicationHome(app);\n\t\tassertThat(applicationHome.getDir()).isEqualTo(app);\n\t}\n\n\t@Test\n\tvoid whenSourceClassIsProvidedWithSpaceInItsPathThenApplicationHomeReflectsItsLocation() throws Exception {\n\t\tFile app = new File(this.tempDir, \"app location\");\n\t\tApplicationHome applicationHome = createApplicationHome(app);\n\t\tassertThat(applicationHome.getDir()).isEqualTo(app);\n\t}\n\n\tprivate ApplicationHome createApplicationHome(File location) throws Exception {\n\t\tFile examplePackage = new File(location, \"com/example\");\n\t\texamplePackage.mkdirs();\n\t\tFileCopyUtils.copy(\n\t\t\t\tnew ByteArrayInputStream(\n\t\t\t\t\t\tnew ByteBuddy().subclass(Object.class).name(\"com.example.Source\").make().getBytes()),\n\t\t\t\tnew FileOutputStream(new File(examplePackage, \"Source.class\")));\n\t\ttry (URLClassLoader classLoader = new URLClassLoader(new URL[] { location.toURI().toURL() })) {\n\t\t\tClass<?> sourceClass = classLoader.loadClass(\"com.example.Source\");\n\t\t\t// Separate thread to bypass stack-based unit test detection in\n\t\t\t// ApplicationHome\n\t\t\tExecutorService executor = Executors.newSingleThreadExecutor();\n\t\t\ttry {\n\t\t\t\treturn executor.submit(() -> new ApplicationHome(sourceClass)).get();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\texecutor.shutdown();\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Tests for {@link ApplicationPid}.\n *\n * @author Phillip Webb\n */\nclass ApplicationPidTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid toStringWithPid() {\n\t\tassertThat(new ApplicationPid(123L)).hasToString(\"123\");\n\t}\n\n\t@Test\n\tvoid toStringWithoutPid() {\n\t\tassertThat(new ApplicationPid(null)).hasToString(\"???\");\n\t}\n\n\t@Test\n\tvoid throwIllegalStateWritingMissingPid() {\n\t\tApplicationPid pid = new ApplicationPid(null);\n\t\tassertThatIllegalStateException().isThrownBy(() -> pid.write(new File(this.tempDir, \"pid\")))\n\t\t\t.withMessageContaining(\"No PID available\");\n\t}\n\n\t@Test\n\tvoid writePid() throws Exception {\n\t\tApplicationPid pid = new ApplicationPid(123L);\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tpid.write(file);\n\t\tassertThat(contentOf(file)).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid writeNewPid() throws Exception {\n\t\t// gh-10784\n\t\tApplicationPid pid = new ApplicationPid(123L);\n\t\tFile file = new File(this.tempDir, \"pid\");\n\t\tfile.delete();\n\t\tpid.write(file);\n\t\tassertThat(contentOf(file)).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid toLong() {\n\t\tApplicationPid pid = new ApplicationPid(123L);\n\t\tassertThat(pid.toLong()).isEqualTo(123L);\n\t}\n\n\t@Test\n\tvoid toLongWhenNotAvailable() {\n\t\tApplicationPid pid = new ApplicationPid(null);\n\t\tassertThat(pid.toLong()).isNull();\n\t}\n\n\t@Test\n\tvoid isAvailableWhenAvailable() {\n\t\tApplicationPid pid = new ApplicationPid(123L);\n\t\tassertThat(pid.isAvailable()).isTrue();\n\t}\n\n\t@Test\n\tvoid isAvailableWhenNotAvailable() {\n\t\tApplicationPid pid = new ApplicationPid(null);\n\t\tassertThat(pid.isAvailable()).isFalse();\n\t}\n\n\t@Test\n\tvoid getPidFromJvm() {\n\t\tassertThat(new ApplicationPid().toString()).isNotEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationTempTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.FileSystem;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.PosixFileAttributeView;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ApplicationTemp}.\n *\n * @author Phillip Webb\n */\nclass ApplicationTempTests {\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid cleanup() {\n\t\tFileSystemUtils.deleteRecursively(new ApplicationTemp().getDir());\n\t}\n\n\t@Test\n\tvoid generatesConsistentTemp() {\n\t\tApplicationTemp t1 = new ApplicationTemp();\n\t\tApplicationTemp t2 = new ApplicationTemp();\n\t\tassertThat(t1.getDir()).isNotNull();\n\t\tassertThat(t1.getDir()).isEqualTo(t2.getDir());\n\t}\n\n\t@Test\n\tvoid differentBasedOnUserDir() {\n\t\tString userDir = System.getProperty(\"user.dir\");\n\t\ttry {\n\t\t\tFile t1 = new ApplicationTemp().getDir();\n\t\t\tSystem.setProperty(\"user.dir\", \"abc\");\n\t\t\tFile t2 = new ApplicationTemp().getDir();\n\t\t\tassertThat(t1).isNotEqualTo(t2);\n\t\t}\n\t\tfinally {\n\t\t\tSystem.setProperty(\"user.dir\", userDir);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getSubDir() {\n\t\tApplicationTemp temp = new ApplicationTemp();\n\t\tassertThat(temp.getDir(\"abc\")).isEqualTo(new File(temp.getDir(), \"abc\"));\n\t}\n\n\t@Test\n\tvoid posixPermissions() throws IOException {\n\t\tApplicationTemp temp = new ApplicationTemp();\n\t\tPath path = temp.getDir().toPath();\n\t\tFileSystem fileSystem = path.getFileSystem();\n\t\tif (fileSystem.supportedFileAttributeViews().contains(\"posix\")) {\n\t\t\tassertDirectoryPermissions(path);\n\t\t\tassertDirectoryPermissions(temp.getDir(\"sub\").toPath());\n\t\t}\n\t}\n\n\tprivate void assertDirectoryPermissions(Path path) throws IOException {\n\t\tSet<PosixFilePermission> permissions = Files.getFileAttributeView(path, PosixFileAttributeView.class)\n\t\t\t.readAttributes()\n\t\t\t.permissions();\n\t\tassertThat(permissions).containsExactlyInAnyOrder(PosixFilePermission.OWNER_READ,\n\t\t\t\tPosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/system/JavaVersionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledOnJre;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JavaVersion}.\n *\n * @author Stephane Nicoll\n */\nclass JavaVersionTests {\n\n\t@Test\n\tvoid getJavaVersionShouldBeAvailable() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isNotNull();\n\t}\n\n\t@Test\n\tvoid compareToWhenComparingSmallerToGreaterShouldBeLessThanZero() {\n\t\tassertThat(JavaVersion.SEVENTEEN).isLessThan(JavaVersion.EIGHTEEN);\n\t}\n\n\t@Test\n\tvoid compareToWhenComparingGreaterToSmallerShouldBeGreaterThanZero() {\n\t\tassertThat(JavaVersion.EIGHTEEN).isGreaterThan(JavaVersion.SEVENTEEN);\n\t}\n\n\t@Test\n\tvoid compareToWhenComparingSameShouldBeZero() {\n\t\tassertThat(JavaVersion.SEVENTEEN).isEqualByComparingTo(JavaVersion.SEVENTEEN);\n\t}\n\n\t@Test\n\tvoid isEqualOrNewerThanWhenComparingSameShouldBeTrue() {\n\t\tassertThat(JavaVersion.SEVENTEEN.isEqualOrNewerThan(JavaVersion.SEVENTEEN)).isTrue();\n\t}\n\n\t@Test\n\tvoid isEqualOrNewerThanWhenSmallerToGreaterShouldBeFalse() {\n\t\tassertThat(JavaVersion.SEVENTEEN.isEqualOrNewerThan(JavaVersion.EIGHTEEN)).isFalse();\n\t}\n\n\t@Test\n\tvoid isEqualOrNewerThanWhenGreaterToSmallerShouldBeTrue() {\n\t\tassertThat(JavaVersion.EIGHTEEN.isEqualOrNewerThan(JavaVersion.SEVENTEEN)).isTrue();\n\t}\n\n\t@Test\n\tvoid isOlderThanThanWhenComparingSameShouldBeFalse() {\n\t\tassertThat(JavaVersion.SEVENTEEN.isOlderThan(JavaVersion.SEVENTEEN)).isFalse();\n\t}\n\n\t@Test\n\tvoid isOlderThanWhenSmallerToGreaterShouldBeTrue() {\n\t\tassertThat(JavaVersion.SEVENTEEN.isOlderThan(JavaVersion.EIGHTEEN)).isTrue();\n\t}\n\n\t@Test\n\tvoid isOlderThanWhenGreaterToSmallerShouldBeFalse() {\n\t\tassertThat(JavaVersion.EIGHTEEN.isOlderThan(JavaVersion.SEVENTEEN)).isFalse();\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_17)\n\tvoid currentJavaVersionSeventeen() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.SEVENTEEN);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_18)\n\tvoid currentJavaVersionEighteen() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.EIGHTEEN);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_19)\n\tvoid currentJavaVersionNineteen() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.NINETEEN);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_20)\n\tvoid currentJavaVersionTwenty() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_21)\n\tvoid currentJavaVersionTwentyOne() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY_ONE);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_22)\n\tvoid currentJavaVersionTwentyTwo() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY_TWO);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_23)\n\tvoid currentJavaVersionTwentyThree() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY_THREE);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_24)\n\tvoid currentJavaVersionTwentyFour() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY_FOUR);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_25)\n\tvoid currentJavaVersionTwentyFive() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY_FIVE);\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_26)\n\tvoid currentJavaVersionTwentySix() {\n\t\tassertThat(JavaVersion.getJavaVersion()).isEqualTo(JavaVersion.TWENTY_SIX);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/system/MockApplicationPid.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.system;\n\n/**\n * Factory to create mock {@link ApplicationPid} instances for testing.\n *\n * @author Phillip Webb\n */\npublic final class MockApplicationPid {\n\n\tprivate MockApplicationPid() {\n\t}\n\n\tpublic static ApplicationPid of(long value) {\n\t\treturn new ApplicationPid(value);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskExecutorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.testsupport.assertj.SimpleAsyncTaskExecutorAssert;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.TaskDecorator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link SimpleAsyncTaskExecutorBuilder}.\n *\n * @author Stephane Nicoll\n * @author Filip Hrisafov\n * @author Moritz Halbritter\n * @author Yanming Zhou\n */\nclass SimpleAsyncTaskExecutorBuilderTests {\n\n\tprivate final SimpleAsyncTaskExecutorBuilder builder = new SimpleAsyncTaskExecutorBuilder();\n\n\t@Test\n\tvoid threadNamePrefixShouldApply() {\n\t\tSimpleAsyncTaskExecutor executor = this.builder.threadNamePrefix(\"test-\").build();\n\t\tassertThat(executor.getThreadNamePrefix()).isEqualTo(\"test-\");\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid virtualThreadsShouldApply() {\n\t\tSimpleAsyncTaskExecutor executor = this.builder.virtualThreads(true).build();\n\t\tSimpleAsyncTaskExecutorAssert.assertThat(executor).usesVirtualThreads();\n\t}\n\n\t@Test\n\tvoid cancelRemainingTasksOnCloseShouldApply() {\n\t\tSimpleAsyncTaskExecutor executor = this.builder.cancelRemainingTasksOnClose(true).build();\n\t\tassertThat(executor).extracting(\"cancelRemainingTasksOnClose\").isEqualTo(true);\n\t}\n\n\t@Test\n\tvoid rejectTasksWhenLimitReachedShouldApply() {\n\t\tSimpleAsyncTaskExecutor executor = this.builder.rejectTasksWhenLimitReached(true).build();\n\t\tassertThat(executor).extracting(\"rejectTasksWhenLimitReached\").isEqualTo(true);\n\t}\n\n\t@Test\n\tvoid concurrencyLimitShouldApply() {\n\t\tSimpleAsyncTaskExecutor executor = this.builder.concurrencyLimit(1).build();\n\t\tassertThat(executor.getConcurrencyLimit()).isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid taskDecoratorShouldApply() {\n\t\tTaskDecorator taskDecorator = mock(TaskDecorator.class);\n\t\tSimpleAsyncTaskExecutor executor = this.builder.taskDecorator(taskDecorator).build();\n\t\tassertThat(executor).extracting(\"taskDecorator\").isSameAs(taskDecorator);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((SimpleAsyncTaskExecutorCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((Set<SimpleAsyncTaskExecutorCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid customizersShouldApply() {\n\t\tSimpleAsyncTaskExecutorCustomizer customizer = mock(SimpleAsyncTaskExecutorCustomizer.class);\n\t\tSimpleAsyncTaskExecutor executor = this.builder.customizers(customizer).build();\n\t\tthen(customizer).should().customize(executor);\n\t}\n\n\t@Test\n\tvoid customizersShouldBeAppliedLast() {\n\t\tTaskDecorator taskDecorator = mock(TaskDecorator.class);\n\t\tSimpleAsyncTaskExecutor executor = spy(new SimpleAsyncTaskExecutor());\n\t\tthis.builder.threadNamePrefix(\"test-\")\n\t\t\t.virtualThreads(true)\n\t\t\t.concurrencyLimit(1)\n\t\t\t.taskDecorator(taskDecorator)\n\t\t\t.additionalCustomizers((taskExecutor) -> {\n\t\t\t\tthen(taskExecutor).should().setConcurrencyLimit(1);\n\t\t\t\tthen(taskExecutor).should().setVirtualThreads(true);\n\t\t\t\tthen(taskExecutor).should().setThreadNamePrefix(\"test-\");\n\t\t\t\tthen(taskExecutor).should().setTaskDecorator(taskDecorator);\n\t\t\t});\n\t\tthis.builder.configure(executor);\n\t}\n\n\t@Test\n\tvoid customizersShouldReplaceExisting() {\n\t\tSimpleAsyncTaskExecutorCustomizer customizer1 = mock(SimpleAsyncTaskExecutorCustomizer.class);\n\t\tSimpleAsyncTaskExecutorCustomizer customizer2 = mock(SimpleAsyncTaskExecutorCustomizer.class);\n\t\tSimpleAsyncTaskExecutor executor = this.builder.customizers(customizer1)\n\t\t\t.customizers(Collections.singleton(customizer2))\n\t\t\t.build();\n\t\tthen(customizer1).shouldHaveNoInteractions();\n\t\tthen(customizer2).should().customize(executor);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((SimpleAsyncTaskExecutorCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((Set<SimpleAsyncTaskExecutorCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalCustomizersShouldAddToExisting() {\n\t\tSimpleAsyncTaskExecutorCustomizer customizer1 = mock(SimpleAsyncTaskExecutorCustomizer.class);\n\t\tSimpleAsyncTaskExecutorCustomizer customizer2 = mock(SimpleAsyncTaskExecutorCustomizer.class);\n\t\tSimpleAsyncTaskExecutor executor = this.builder.customizers(customizer1)\n\t\t\t.additionalCustomizers(customizer2)\n\t\t\t.build();\n\t\tthen(customizer1).should().customize(executor);\n\t\tthen(customizer2).should().customize(executor);\n\t}\n\n\t@Test\n\tvoid taskTerminationTimeoutShouldApply() {\n\t\tSimpleAsyncTaskExecutor executor = this.builder.taskTerminationTimeout(Duration.ofSeconds(1)).build();\n\t\tassertThat(executor).extracting(\"taskTerminationTimeout\").isEqualTo(1000L);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/task/SimpleAsyncTaskSchedulerBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link SimpleAsyncTaskSchedulerBuilder}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass SimpleAsyncTaskSchedulerBuilderTests {\n\n\tprivate final SimpleAsyncTaskSchedulerBuilder builder = new SimpleAsyncTaskSchedulerBuilder();\n\n\t@Test\n\tvoid threadNamePrefixShouldApply() {\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.threadNamePrefix(\"test-\").build();\n\t\tassertThat(scheduler.getThreadNamePrefix()).isEqualTo(\"test-\");\n\t}\n\n\t@Test\n\tvoid concurrencyLimitShouldApply() {\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.concurrencyLimit(1).build();\n\t\tassertThat(scheduler.getConcurrencyLimit()).isEqualTo(1);\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid virtualThreadsShouldApply() {\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.virtualThreads(true).build();\n\t\tassertThat(scheduler).extracting(\"virtualThreadDelegate\").isNotNull();\n\t}\n\n\t@Test\n\tvoid taskTerminationTimeoutShouldApply() {\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.taskTerminationTimeout(Duration.ofSeconds(1)).build();\n\t\tassertThat(scheduler).extracting(\"taskTerminationTimeout\").isEqualTo(1000L);\n\t}\n\n\t@Test\n\tvoid taskDecoratorShouldApply() {\n\t\tTaskDecorator taskDecorator = mock(TaskDecorator.class);\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.taskDecorator(taskDecorator).build();\n\t\tassertThat(scheduler).extracting(\"taskDecorator\").isSameAs(taskDecorator);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((SimpleAsyncTaskSchedulerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((Set<SimpleAsyncTaskSchedulerCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid customizersShouldApply() {\n\t\tSimpleAsyncTaskSchedulerCustomizer customizer = mock(SimpleAsyncTaskSchedulerCustomizer.class);\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.customizers(customizer).build();\n\t\tthen(customizer).should().customize(scheduler);\n\t}\n\n\t@Test\n\tvoid customizersShouldBeAppliedLast() {\n\t\tSimpleAsyncTaskScheduler scheduler = spy(new SimpleAsyncTaskScheduler());\n\t\tthis.builder.concurrencyLimit(1).threadNamePrefix(\"test-\").additionalCustomizers((taskScheduler) -> {\n\t\t\tthen(taskScheduler).should().setConcurrencyLimit(1);\n\t\t\tthen(taskScheduler).should().setThreadNamePrefix(\"test-\");\n\t\t});\n\t\tthis.builder.configure(scheduler);\n\t}\n\n\t@Test\n\tvoid customizersShouldReplaceExisting() {\n\t\tSimpleAsyncTaskSchedulerCustomizer customizer1 = mock(SimpleAsyncTaskSchedulerCustomizer.class);\n\t\tSimpleAsyncTaskSchedulerCustomizer customizer2 = mock(SimpleAsyncTaskSchedulerCustomizer.class);\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.customizers(customizer1)\n\t\t\t.customizers(Collections.singleton(customizer2))\n\t\t\t.build();\n\t\tthen(customizer1).shouldHaveNoInteractions();\n\t\tthen(customizer2).should().customize(scheduler);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((SimpleAsyncTaskSchedulerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((Set<SimpleAsyncTaskSchedulerCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalCustomizersShouldAddToExisting() {\n\t\tSimpleAsyncTaskSchedulerCustomizer customizer1 = mock(SimpleAsyncTaskSchedulerCustomizer.class);\n\t\tSimpleAsyncTaskSchedulerCustomizer customizer2 = mock(SimpleAsyncTaskSchedulerCustomizer.class);\n\t\tSimpleAsyncTaskScheduler scheduler = this.builder.customizers(customizer1)\n\t\t\t.additionalCustomizers(customizer2)\n\t\t\t.build();\n\t\tthen(customizer1).should().customize(scheduler);\n\t\tthen(customizer2).should().customize(scheduler);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskExecutorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ThreadPoolTaskExecutorBuilder}.\n *\n * @author Stephane Nicoll\n * @author Filip Hrisafov\n * @author Yanming Zhou\n */\nclass ThreadPoolTaskExecutorBuilderTests {\n\n\tprivate final ThreadPoolTaskExecutorBuilder builder = new ThreadPoolTaskExecutorBuilder();\n\n\t@Test\n\tvoid poolSettingsShouldApply() {\n\t\tThreadPoolTaskExecutor executor = this.builder.queueCapacity(10)\n\t\t\t.corePoolSize(4)\n\t\t\t.maxPoolSize(8)\n\t\t\t.allowCoreThreadTimeOut(true)\n\t\t\t.keepAlive(Duration.ofMinutes(1))\n\t\t\t.build();\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"queueCapacity\", 10);\n\t\tassertThat(executor.getCorePoolSize()).isEqualTo(4);\n\t\tassertThat(executor.getMaxPoolSize()).isEqualTo(8);\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"allowCoreThreadTimeOut\", true);\n\t\tassertThat(executor.getKeepAliveSeconds()).isEqualTo(60);\n\t}\n\n\t@Test\n\tvoid acceptTasksAfterContextCloseShouldApply() {\n\t\tThreadPoolTaskExecutor executor = this.builder.acceptTasksAfterContextClose(true).build();\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"acceptTasksAfterContextClose\", true);\n\t}\n\n\t@Test\n\tvoid awaitTerminationShouldApply() {\n\t\tThreadPoolTaskExecutor executor = this.builder.awaitTermination(true).build();\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"waitForTasksToCompleteOnShutdown\", true);\n\t}\n\n\t@Test\n\tvoid awaitTerminationPeriodShouldApplyWithMillisecondPrecision() {\n\t\tDuration period = Duration.ofMillis(50);\n\t\tThreadPoolTaskExecutor executor = this.builder.awaitTerminationPeriod(period).build();\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"awaitTerminationMillis\", period.toMillis());\n\t}\n\n\t@Test\n\tvoid threadNamePrefixShouldApply() {\n\t\tThreadPoolTaskExecutor executor = this.builder.threadNamePrefix(\"test-\").build();\n\t\tassertThat(executor.getThreadNamePrefix()).isEqualTo(\"test-\");\n\t}\n\n\t@Test\n\tvoid taskDecoratorShouldApply() {\n\t\tTaskDecorator taskDecorator = mock(TaskDecorator.class);\n\t\tThreadPoolTaskExecutor executor = this.builder.taskDecorator(taskDecorator).build();\n\t\tassertThat(executor).extracting(\"taskDecorator\").isSameAs(taskDecorator);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((ThreadPoolTaskExecutorCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((Set<ThreadPoolTaskExecutorCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid customizersShouldApply() {\n\t\tThreadPoolTaskExecutorCustomizer customizer = mock(ThreadPoolTaskExecutorCustomizer.class);\n\t\tThreadPoolTaskExecutor executor = this.builder.customizers(customizer).build();\n\t\tthen(customizer).should().customize(executor);\n\t}\n\n\t@Test\n\tvoid customizersShouldBeAppliedLast() {\n\t\tTaskDecorator taskDecorator = mock(TaskDecorator.class);\n\t\tThreadPoolTaskExecutor executor = spy(new ThreadPoolTaskExecutor());\n\t\tthis.builder.queueCapacity(10)\n\t\t\t.corePoolSize(4)\n\t\t\t.maxPoolSize(8)\n\t\t\t.allowCoreThreadTimeOut(true)\n\t\t\t.keepAlive(Duration.ofMinutes(1))\n\t\t\t.awaitTermination(true)\n\t\t\t.awaitTerminationPeriod(Duration.ofSeconds(30))\n\t\t\t.threadNamePrefix(\"test-\")\n\t\t\t.taskDecorator(taskDecorator)\n\t\t\t.additionalCustomizers((taskExecutor) -> {\n\t\t\t\tthen(taskExecutor).should().setQueueCapacity(10);\n\t\t\t\tthen(taskExecutor).should().setCorePoolSize(4);\n\t\t\t\tthen(taskExecutor).should().setMaxPoolSize(8);\n\t\t\t\tthen(taskExecutor).should().setAllowCoreThreadTimeOut(true);\n\t\t\t\tthen(taskExecutor).should().setKeepAliveSeconds(60);\n\t\t\t\tthen(taskExecutor).should().setWaitForTasksToCompleteOnShutdown(true);\n\t\t\t\tthen(taskExecutor).should().setAwaitTerminationSeconds(30);\n\t\t\t\tthen(taskExecutor).should().setThreadNamePrefix(\"test-\");\n\t\t\t\tthen(taskExecutor).should().setTaskDecorator(taskDecorator);\n\t\t\t});\n\t\tthis.builder.configure(executor);\n\t}\n\n\t@Test\n\tvoid customizersShouldReplaceExisting() {\n\t\tThreadPoolTaskExecutorCustomizer customizer1 = mock(ThreadPoolTaskExecutorCustomizer.class);\n\t\tThreadPoolTaskExecutorCustomizer customizer2 = mock(ThreadPoolTaskExecutorCustomizer.class);\n\t\tThreadPoolTaskExecutor executor = this.builder.customizers(customizer1)\n\t\t\t.customizers(Collections.singleton(customizer2))\n\t\t\t.build();\n\t\tthen(customizer1).shouldHaveNoInteractions();\n\t\tthen(customizer2).should().customize(executor);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((ThreadPoolTaskExecutorCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((Set<ThreadPoolTaskExecutorCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalCustomizersShouldAddToExisting() {\n\t\tThreadPoolTaskExecutorCustomizer customizer1 = mock(ThreadPoolTaskExecutorCustomizer.class);\n\t\tThreadPoolTaskExecutorCustomizer customizer2 = mock(ThreadPoolTaskExecutorCustomizer.class);\n\t\tThreadPoolTaskExecutor executor = this.builder.customizers(customizer1)\n\t\t\t.additionalCustomizers(customizer2)\n\t\t\t.build();\n\t\tthen(customizer1).should().customize(executor);\n\t\tthen(customizer2).should().customize(executor);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/task/ThreadPoolTaskSchedulerBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.task;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ThreadPoolTaskSchedulerBuilder}.\n *\n * @author Stephane Nicoll\n */\nclass ThreadPoolTaskSchedulerBuilderTests {\n\n\tprivate final ThreadPoolTaskSchedulerBuilder builder = new ThreadPoolTaskSchedulerBuilder();\n\n\t@Test\n\tvoid poolSettingsShouldApply() {\n\t\tThreadPoolTaskScheduler scheduler = this.builder.poolSize(4).build();\n\t\tassertThat(scheduler.getPoolSize()).isEqualTo(4);\n\t}\n\n\t@Test\n\tvoid awaitTerminationShouldApply() {\n\t\tThreadPoolTaskScheduler executor = this.builder.awaitTermination(true).build();\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"waitForTasksToCompleteOnShutdown\", true);\n\t}\n\n\t@Test\n\tvoid awaitTerminationPeriodShouldApply() {\n\t\tDuration period = Duration.ofMinutes(1);\n\t\tThreadPoolTaskScheduler executor = this.builder.awaitTerminationPeriod(period).build();\n\t\tassertThat(executor).hasFieldOrPropertyWithValue(\"awaitTerminationMillis\", period.toMillis());\n\t}\n\n\t@Test\n\tvoid threadNamePrefixShouldApply() {\n\t\tThreadPoolTaskScheduler scheduler = this.builder.threadNamePrefix(\"test-\").build();\n\t\tassertThat(scheduler.getThreadNamePrefix()).isEqualTo(\"test-\");\n\t}\n\n\t@Test\n\tvoid taskDecoratorShouldApply() {\n\t\tTaskDecorator taskDecorator = mock(TaskDecorator.class);\n\t\tThreadPoolTaskScheduler scheduler = this.builder.taskDecorator(taskDecorator).build();\n\t\tassertThat(scheduler).extracting(\"taskDecorator\").isSameAs(taskDecorator);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((ThreadPoolTaskSchedulerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((Set<ThreadPoolTaskSchedulerCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid customizersShouldApply() {\n\t\tThreadPoolTaskSchedulerCustomizer customizer = mock(ThreadPoolTaskSchedulerCustomizer.class);\n\t\tThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer).build();\n\t\tthen(customizer).should().customize(scheduler);\n\t}\n\n\t@Test\n\tvoid customizersShouldBeAppliedLast() {\n\t\tThreadPoolTaskScheduler scheduler = spy(new ThreadPoolTaskScheduler());\n\t\tthis.builder.poolSize(4).threadNamePrefix(\"test-\").additionalCustomizers((taskScheduler) -> {\n\t\t\tthen(taskScheduler).should().setPoolSize(4);\n\t\t\tthen(taskScheduler).should().setThreadNamePrefix(\"test-\");\n\t\t});\n\t\tthis.builder.configure(scheduler);\n\t}\n\n\t@Test\n\tvoid customizersShouldReplaceExisting() {\n\t\tThreadPoolTaskSchedulerCustomizer customizer1 = mock(ThreadPoolTaskSchedulerCustomizer.class);\n\t\tThreadPoolTaskSchedulerCustomizer customizer2 = mock(ThreadPoolTaskSchedulerCustomizer.class);\n\t\tThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer1)\n\t\t\t.customizers(Collections.singleton(customizer2))\n\t\t\t.build();\n\t\tthen(customizer1).shouldHaveNoInteractions();\n\t\tthen(customizer2).should().customize(scheduler);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((ThreadPoolTaskSchedulerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((Set<ThreadPoolTaskSchedulerCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalCustomizersShouldAddToExisting() {\n\t\tThreadPoolTaskSchedulerCustomizer customizer1 = mock(ThreadPoolTaskSchedulerCustomizer.class);\n\t\tThreadPoolTaskSchedulerCustomizer customizer2 = mock(ThreadPoolTaskSchedulerCustomizer.class);\n\t\tThreadPoolTaskScheduler scheduler = this.builder.customizers(customizer1)\n\t\t\t.additionalCustomizers(customizer2)\n\t\t\t.build();\n\t\tthen(customizer1).should().customize(scheduler);\n\t\tthen(customizer2).should().customize(scheduler);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/util/InstantiatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.util;\n\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.util.Instantiator.FailureHandler;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.OverridingClassLoader;\nimport org.springframework.core.annotation.Order;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Instantiator}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass InstantiatorTests {\n\n\tprivate final ParamA paramA = new ParamA();\n\n\tprivate final ParamB paramB = new ParamB();\n\n\tprivate @Nullable ParamC paramC;\n\n\t@Test\n\tvoid instantiateWhenOnlyDefaultConstructorCreatesInstance() {\n\t\tWithDefaultConstructor instance = createInstance(WithDefaultConstructor.class);\n\t\tassertThat(instance).isInstanceOf(WithDefaultConstructor.class);\n\t}\n\n\t@Test\n\tvoid instantiateWhenMultipleConstructorPicksMostArguments() {\n\t\tWithMultipleConstructors instance = createInstance(WithMultipleConstructors.class);\n\t\tassertThat(instance).isInstanceOf(WithMultipleConstructors.class);\n\t}\n\n\t@Test\n\tvoid instantiateWhenAdditionalConstructorPicksMostSuitable() {\n\t\tWithAdditionalConstructor instance = createInstance(WithAdditionalConstructor.class);\n\t\tassertThat(instance).isInstanceOf(WithAdditionalConstructor.class);\n\t}\n\n\t@Test\n\tvoid instantiateOrdersInstances() {\n\t\tList<Object> instances = createInstantiator(Object.class).instantiate(\n\t\t\t\tArrays.asList(WithMultipleConstructors.class.getName(), WithAdditionalConstructor.class.getName()));\n\t\tassertThat(instances).hasSize(2);\n\t\tassertThat(instances.get(0)).isInstanceOf(WithAdditionalConstructor.class);\n\t\tassertThat(instances.get(1)).isInstanceOf(WithMultipleConstructors.class);\n\t}\n\n\t@Test\n\tvoid instantiateWithFactory() {\n\t\tassertThat(this.paramC).isNull();\n\t\tWithFactory instance = createInstance(WithFactory.class);\n\t\tassertThat(instance.getParamC()).isEqualTo(this.paramC);\n\t}\n\n\t@Test\n\tvoid instantiateTypesCreatesInstance() {\n\t\tWithDefaultConstructor instance = createInstantiator(WithDefaultConstructor.class)\n\t\t\t.instantiateTypes(Collections.singleton(WithDefaultConstructor.class))\n\t\t\t.get(0);\n\t\tassertThat(instance).isInstanceOf(WithDefaultConstructor.class);\n\t}\n\n\t@Test\n\tvoid instantiateWithClassLoaderCreatesInstance() {\n\t\tOverridingClassLoader classLoader = new OverridingClassLoader(getClass().getClassLoader()) {\n\n\t\t\t@Override\n\t\t\tprotected boolean isEligibleForOverriding(String className) {\n\t\t\t\treturn super.isEligibleForOverriding(className)\n\t\t\t\t\t\t&& className.equals(WithDefaultConstructorSubclass.class.getName());\n\t\t\t}\n\n\t\t};\n\t\tWithDefaultConstructor instance = createInstantiator(WithDefaultConstructor.class)\n\t\t\t.instantiate(classLoader, Collections.singleton(WithDefaultConstructorSubclass.class.getName()))\n\t\t\t.get(0);\n\t\tassertThat(instance.getClass().getClassLoader()).isSameAs(classLoader);\n\t}\n\n\t@Test\n\tvoid createWhenWrongTypeThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> createInstantiator(WithDefaultConstructor.class)\n\t\t\t\t.instantiate(Collections.singleton(WithAdditionalConstructor.class.getName())))\n\t\t\t.withMessageContaining(\"Unable to instantiate\");\n\t}\n\n\t@Test\n\tvoid createWithFailureHandlerInvokesFailureHandler() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new Instantiator<>(WithDefaultConstructor.class, (availableParameters) -> {\n\t\t\t}, new CustomFailureHandler())\n\t\t\t\t.instantiate(Collections.singleton(WithAdditionalConstructor.class.getName())))\n\t\t\t.withMessageContaining(\"custom failure handler message\");\n\t}\n\n\t@Test\n\tvoid instantiateWithSingleNameCreatesInstance() {\n\t\tWithDefaultConstructor instance = createInstantiator(WithDefaultConstructor.class)\n\t\t\t.instantiate(WithDefaultConstructor.class.getName());\n\t\tassertThat(instance).isInstanceOf(WithDefaultConstructor.class);\n\t}\n\n\t@Test\n\tvoid getArgReturnsArg() {\n\t\tInstantiator<?> instantiator = createInstantiator(WithMultipleConstructors.class);\n\t\tassertThat(instantiator.getArg(ParamA.class)).isSameAs(this.paramA);\n\t\tassertThat(instantiator.getArg(ParamB.class)).isSameAs(this.paramB);\n\t\tassertThat(instantiator.getArg(ParamC.class)).isInstanceOf(ParamC.class);\n\t}\n\n\t@Test\n\tvoid getArgWhenUnknownThrowsException() {\n\t\tInstantiator<?> instantiator = createInstantiator(WithMultipleConstructors.class);\n\t\tassertThatIllegalStateException().isThrownBy(() -> instantiator.getArg(InputStream.class))\n\t\t\t.withMessageStartingWith(\"Unknown argument type\");\n\t}\n\n\tprivate <T> T createInstance(Class<T> type) {\n\t\tT instance = createInstantiator(type).instantiate(type.getName());\n\t\tassertThat(instance).isNotNull();\n\t\treturn instance;\n\t}\n\n\tprivate <T> Instantiator<T> createInstantiator(Class<T> type) {\n\t\treturn new Instantiator<>(type, (availableParameters) -> {\n\t\t\tavailableParameters.add(ParamA.class, this.paramA);\n\t\t\tavailableParameters.add(ParamB.class, this.paramB);\n\t\t\tavailableParameters.add(ParamC.class, ParamC::new);\n\t\t});\n\t}\n\n\tstatic class WithDefaultConstructorSubclass extends WithDefaultConstructor {\n\n\t}\n\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class WithMultipleConstructors {\n\n\t\tWithMultipleConstructors() {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t\tWithMultipleConstructors(ParamA paramA) {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t\tWithMultipleConstructors(ParamA paramA, ParamB paramB) {\n\t\t}\n\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic class WithAdditionalConstructor {\n\n\t\tWithAdditionalConstructor(ParamA paramA, ParamB paramB) {\n\t\t}\n\n\t\tWithAdditionalConstructor(ParamA paramA, ParamB paramB, String extra) {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t}\n\n\tstatic class WithFactory {\n\n\t\tprivate final ParamC paramC;\n\n\t\tWithFactory(ParamC paramC) {\n\t\t\tthis.paramC = paramC;\n\t\t}\n\n\t\tParamC getParamC() {\n\t\t\treturn this.paramC;\n\t\t}\n\n\t}\n\n\tclass ParamA {\n\n\t}\n\n\tclass ParamB {\n\n\t}\n\n\tclass ParamC {\n\n\t\tParamC(Class<?> type) {\n\t\t\tInstantiatorTests.this.paramC = this;\n\t\t}\n\n\t}\n\n\tclass CustomFailureHandler implements FailureHandler {\n\n\t\t@Override\n\t\tpublic void handleFailure(Class<?> type, String implementationName, Throwable failure) {\n\t\t\tthrow new IllegalStateException(\"custom failure handler message\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/util/LambdaSafeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.util;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.util.LambdaSafe.Filter;\nimport org.springframework.boot.util.LambdaSafe.InvocationResult;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.contains;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LambdaSafe}.\n *\n * @author Phillip Webb\n */\nclass LambdaSafeTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid callbackWhenCallbackTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LambdaSafe.callback(null, new Object(), null))\n\t\t\t.withMessageContaining(\"'callbackType' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid callbackWhenCallbackInstanceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LambdaSafe.callback(Object.class, null, null))\n\t\t\t.withMessageContaining(\"'callbackInstance' must not be null\");\n\t}\n\n\t@Test\n\tvoid callbackInvokeWhenNoGenericShouldInvokeCallback() {\n\t\tNonGenericCallback callbackInstance = mock(NonGenericCallback.class);\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(NonGenericCallback.class, callbackInstance, argument).invoke((c) -> c.handle(argument));\n\t\tthen(callbackInstance).should().handle(argument);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackInvokeWhenHasGenericShouldInvokeCallback() {\n\t\tStringCallback callbackInstance = mock(StringCallback.class);\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(GenericCallback.class, callbackInstance, argument).invoke((c) -> c.handle(argument));\n\t\tthen(callbackInstance).should().handle(argument);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackInvokeWhenHasResolvableGenericMatchShouldInvokeCallback() {\n\t\tStringBuilderCallback callbackInstance = mock(StringBuilderCallback.class);\n\t\tStringBuilder argument = new StringBuilder(\"foo\");\n\t\tLambdaSafe.callback(GenericCallback.class, callbackInstance, argument).invoke((c) -> c.handle(argument));\n\t\tthen(callbackInstance).should().handle(argument);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackInvokeWhenHasResolvableGenericNonMatchShouldNotInvokeCallback() {\n\t\tGenericCallback<?> callbackInstance = mock(StringBuilderCallback.class);\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(GenericCallback.class, callbackInstance, argument).invoke((c) -> c.handle(argument));\n\t\tthen(callbackInstance).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackInvokeWhenLambdaMismatchShouldSwallowException() {\n\t\tGenericCallback<StringBuilder> callbackInstance = (s) -> fail(\"Should not get here\");\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(GenericCallback.class, callbackInstance, argument).invoke((c) -> c.handle(argument));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackInvokeWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() {\n\t\tGenericMultiArgCallback<StringBuilder> callbackInstance = (n, s, b) -> fail(\"Should not get here\");\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(GenericMultiArgCallback.class, callbackInstance, argument)\n\t\t\t.invoke((c) -> c.handle(1, argument, false));\n\t}\n\n\t@Test\n\tvoid callbackInvokeAndWhenNoGenericShouldReturnResult() {\n\t\tNonGenericFactory callbackInstance = mock(NonGenericFactory.class);\n\t\tString argument = \"foo\";\n\t\tgiven(callbackInstance.handle(\"foo\")).willReturn(123);\n\t\tFunction<NonGenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(NonGenericFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result.hasResult()).isTrue();\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbackInvokeAndWhenHasGenericShouldReturnResult() {\n\t\tStringFactory callbackInstance = mock(StringFactory.class);\n\t\tString argument = \"foo\";\n\t\tgiven(callbackInstance.handle(\"foo\")).willReturn(123);\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result.hasResult()).isTrue();\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbackInvokeAndWhenReturnNullShouldReturnResult() {\n\t\tStringFactory callbackInstance = mock(StringFactory.class);\n\t\tString argument = \"foo\";\n\t\tgiven(callbackInstance.handle(\"foo\")).willReturn(null);\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result.hasResult()).isTrue();\n\t\tassertThat(result.get()).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbackInvokeAndWhenHasResolvableGenericMatchShouldReturnResult() {\n\t\tStringBuilderFactory callbackInstance = mock(StringBuilderFactory.class);\n\t\tStringBuilder argument = new StringBuilder(\"foo\");\n\t\tgiven(callbackInstance.handle(any(StringBuilder.class))).willReturn(123);\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tthen(callbackInstance).should().handle(argument);\n\t\tassertThat(result.hasResult()).isTrue();\n\t\tassertThat(result.get()).isEqualTo(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbackInvokeAndWhenHasResolvableGenericNonMatchShouldReturnNoResult() {\n\t\tGenericFactory<?> callbackInstance = mock(StringBuilderFactory.class);\n\t\tString argument = \"foo\";\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result.hasResult()).isFalse();\n\t\tthen(callbackInstance).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbackInvokeAndWhenLambdaMismatchShouldSwallowException() {\n\t\tGenericFactory<StringBuilder> callbackInstance = (s) -> {\n\t\t\tfail(\"Should not get here\");\n\t\t\treturn 123;\n\t\t};\n\t\tString argument = \"foo\";\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(GenericFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result.hasResult()).isFalse();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbackInvokeAndWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() {\n\t\tGenericMultiArgFactory<StringBuilder> callbackInstance = (n, s, b) -> {\n\t\t\tfail(\"Should not get here\");\n\t\t\treturn 123;\n\t\t};\n\t\tString argument = \"foo\";\n\t\tFunction<GenericMultiArgFactory, @Nullable Integer> handle = (c) -> c.handle(1, argument, false);\n\t\tInvocationResult<Integer> result = LambdaSafe.callback(GenericMultiArgFactory.class, callbackInstance, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result.hasResult()).isFalse();\n\t}\n\n\t@Test\n\tvoid callbacksInvokeWhenNoGenericShouldInvokeCallbacks() {\n\t\tNonGenericCallback callbackInstance = mock(NonGenericCallback.class);\n\t\tString argument = \"foo\";\n\t\tConsumer<NonGenericCallback> handle = (c) -> c.handle(argument);\n\t\tLambdaSafe.callbacks(NonGenericCallback.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invoke(handle);\n\t\tthen(callbackInstance).should().handle(argument);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeWhenHasGenericShouldInvokeCallback() {\n\t\tStringCallback callbackInstance = mock(StringCallback.class);\n\t\tString argument = \"foo\";\n\t\tConsumer<GenericCallback> handle = (c) -> c.handle(argument);\n\t\tLambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle);\n\t\tthen(callbackInstance).should().handle(argument);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeWhenHasResolvableGenericMatchShouldInvokeCallback() {\n\t\tStringBuilderCallback callbackInstance = mock(StringBuilderCallback.class);\n\t\tStringBuilder argument = new StringBuilder(\"foo\");\n\t\tConsumer<GenericCallback> handle = (c) -> c.handle(argument);\n\t\tLambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle);\n\t\tthen(callbackInstance).should().handle(argument);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeWhenHasResolvableGenericNonMatchShouldNotInvokeCallback() {\n\t\tGenericCallback<?> callbackInstance = mock(StringBuilderCallback.class);\n\t\tString argument = \"foo\";\n\t\tConsumer<GenericCallback> handle = (c) -> c.handle(null);\n\t\tLambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle);\n\t\tthen(callbackInstance).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeWhenLambdaMismatchShouldSwallowException() {\n\t\tGenericCallback<StringBuilder> callbackInstance = (s) -> fail(\"Should not get here\");\n\t\tString argument = \"foo\";\n\t\tConsumer<GenericCallback> handle = (c) -> c.handle(argument);\n\t\tLambdaSafe.callbacks(GenericCallback.class, Collections.singleton(callbackInstance), argument).invoke(handle);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() {\n\t\tGenericMultiArgCallback<StringBuilder> callbackInstance = (n, s, b) -> fail(\"Should not get here\");\n\t\tString argument = \"foo\";\n\t\tConsumer<GenericMultiArgCallback> handle = (c) -> c.handle(1, argument, false);\n\t\tLambdaSafe.callbacks(GenericMultiArgCallback.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invoke(handle);\n\t}\n\n\t@Test\n\tvoid callbacksInvokeAndWhenNoGenericShouldReturnResult() {\n\t\tNonGenericFactory callbackInstance = mock(NonGenericFactory.class);\n\t\tString argument = \"foo\";\n\t\tgiven(callbackInstance.handle(\"foo\")).willReturn(123);\n\t\tFunction<NonGenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(NonGenericFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).containsExactly(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeAndWhenHasGenericShouldReturnResult() {\n\t\tStringFactory callbackInstance = mock(StringFactory.class);\n\t\tString argument = \"foo\";\n\t\tgiven(callbackInstance.handle(\"foo\")).willReturn(123);\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).containsExactly(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeAndWhenReturnNullShouldReturnResult() {\n\t\tStringFactory callbackInstance = mock(StringFactory.class);\n\t\tString argument = \"foo\";\n\t\tgiven(callbackInstance.handle(\"foo\")).willReturn(null);\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).containsExactly((Integer) null);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeAndWhenHasResolvableGenericMatchShouldReturnResult() {\n\t\tStringBuilderFactory callbackInstance = mock(StringBuilderFactory.class);\n\t\tStringBuilder argument = new StringBuilder(\"foo\");\n\t\tgiven(callbackInstance.handle(any(StringBuilder.class))).willReturn(123);\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).containsExactly(123);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeAndWhenHasResolvableGenericNonMatchShouldReturnNoResult() {\n\t\tGenericFactory<?> callbackInstance = mock(StringBuilderFactory.class);\n\t\tString argument = \"foo\";\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeAndWhenLambdaMismatchShouldSwallowException() {\n\t\tGenericFactory<StringBuilder> callbackInstance = (s) -> {\n\t\t\tfail(\"Should not get here\");\n\t\t\treturn 123;\n\t\t};\n\t\tString argument = \"foo\";\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> (c).handle(argument);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(GenericFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeAndWhenLambdaMismatchOnDifferentArgumentShouldSwallowException() {\n\t\tGenericMultiArgFactory<StringBuilder> callbackInstance = (n, s, b) -> {\n\t\t\tfail(\"Should not get here\");\n\t\t\treturn 123;\n\t\t};\n\t\tString argument = \"foo\";\n\t\tFunction<GenericMultiArgFactory, @Nullable Integer> handle = (c) -> c.handle(1, argument, false);\n\t\tStream<Integer> result = LambdaSafe\n\t\t\t.callbacks(GenericMultiArgFactory.class, Collections.singleton(callbackInstance), argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid callbacksInvokeWhenMultipleShouldInvokeSuitable() {\n\t\tList<GenericFactory<?>> callbackInstances = new ArrayList<>();\n\t\tGenericFactory<String> callback1 = (s) -> 1;\n\t\tGenericFactory<CharSequence> callback2 = (s) -> 2;\n\t\tGenericFactory<StringBuilder> callback3 = (s) -> 3;\n\t\tStringFactory callback4 = mock(StringFactory.class);\n\t\tgiven(callback4.handle(any(String.class))).willReturn(4);\n\t\tStringBuilderFactory callback5 = mock(StringBuilderFactory.class);\n\t\tgiven(callback5.handle(any(StringBuilder.class))).willReturn(5);\n\t\tcallbackInstances.add(callback1);\n\t\tcallbackInstances.add(callback2);\n\t\tcallbackInstances.add(callback3);\n\t\tcallbackInstances.add(callback4);\n\t\tcallbackInstances.add(callback5);\n\t\tString argument = \"foo\";\n\t\tFunction<GenericFactory, @Nullable Integer> handle = (c) -> c.handle(argument);\n\t\tStream<Integer> result = LambdaSafe.callbacks(GenericFactory.class, callbackInstances, argument)\n\t\t\t.invokeAnd(handle);\n\t\tassertThat(result).containsExactly(1, 2, 4);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackWithFilterShouldUseFilter() {\n\t\tGenericCallback<?> callbackInstance = mock(StringBuilderCallback.class);\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(GenericCallback.class, callbackInstance, argument)\n\t\t\t.withFilter(Filter.allowAll())\n\t\t\t.invoke((c) -> c.handle(null));\n\t\tthen(callbackInstance).should().handle(null);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid callbackWithLoggerShouldUseLogger() {\n\t\tLog logger = mock(Log.class);\n\t\tgiven(logger.isDebugEnabled()).willReturn(true);\n\t\tGenericCallback<StringBuilder> callbackInstance = (s) -> fail(\"Should not get here\");\n\t\tString argument = \"foo\";\n\t\tLambdaSafe.callback(GenericCallback.class, callbackInstance, argument)\n\t\t\t.withLogger(logger)\n\t\t\t.invoke((c) -> c.handle(argument));\n\t\tthen(logger).should()\n\t\t\t.debug(contains(\"Non-matching CharSequence type for callback LambdaSafeTests.GenericCallback\"),\n\t\t\t\t\tany(Throwable.class));\n\t}\n\n\tinterface NonGenericCallback {\n\n\t\tvoid handle(String argument);\n\n\t}\n\n\tinterface GenericCallback<T extends CharSequence> {\n\n\t\tvoid handle(@Nullable T argument);\n\n\t}\n\n\tinterface StringCallback extends GenericCallback<String> {\n\n\t}\n\n\tinterface StringBuilderCallback extends GenericCallback<StringBuilder> {\n\n\t}\n\n\tinterface GenericMultiArgCallback<T extends CharSequence> {\n\n\t\tvoid handle(Integer number, T argument, Boolean bool);\n\n\t}\n\n\tinterface NonGenericFactory {\n\n\t\tInteger handle(String argument);\n\n\t}\n\n\tinterface GenericFactory<T extends CharSequence> {\n\n\t\tInteger handle(T argument);\n\n\t}\n\n\tinterface StringFactory extends GenericFactory<String> {\n\n\t}\n\n\tinterface StringBuilderFactory extends GenericFactory<StringBuilder> {\n\n\t}\n\n\tinterface GenericMultiArgFactory<T extends CharSequence> {\n\n\t\tInteger handle(Integer number, T argument, Boolean bool);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/util/WithDefaultConstructor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.util;\n\n/**\n * Simple public class with a default constructor.\n *\n * @author Phillip Webb\n */\npublic class WithDefaultConstructor {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation;\n\nimport jakarta.validation.MessageInterpolator;\nimport org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.MessageSource;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MessageInterpolatorFactory}.\n *\n * @author Phillip Webb\n */\nclass MessageInterpolatorFactoryTests {\n\n\t@Test\n\tvoid getObjectShouldReturnResourceBundleMessageInterpolator() {\n\t\tMessageInterpolator interpolator = new MessageInterpolatorFactory().getObject();\n\t\tassertThat(interpolator).isInstanceOf(ResourceBundleMessageInterpolator.class);\n\t}\n\n\t@Test\n\tvoid getObjectShouldReturnMessageSourceMessageInterpolatorDelegateWithResourceBundleMessageInterpolator() {\n\t\tMessageSource messageSource = mock(MessageSource.class);\n\t\tMessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(messageSource);\n\t\tMessageInterpolator interpolator = interpolatorFactory.getObject();\n\t\tassertThat(interpolator).isInstanceOf(MessageSourceMessageInterpolator.class);\n\t\tassertThat(interpolator).hasFieldOrPropertyWithValue(\"messageSource\", messageSource);\n\t\tassertThat(ReflectionTestUtils.getField(interpolator, \"messageInterpolator\"))\n\t\t\t.isInstanceOf(ResourceBundleMessageInterpolator.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/validation/MessageInterpolatorFactoryWithoutElIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation;\n\nimport jakarta.validation.MessageInterpolator;\nimport jakarta.validation.Validation;\nimport jakarta.validation.ValidationException;\nimport org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.MessageSource;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link MessageInterpolatorFactory} without EL.\n *\n * @author Phillip Webb\n */\n@ClassPathExclusions(\"tomcat-embed-el-*.jar\")\nclass MessageInterpolatorFactoryWithoutElIntegrationTests {\n\n\t@Test\n\tvoid defaultMessageInterpolatorShouldFail() {\n\t\t// Sanity test\n\t\tassertThatExceptionOfType(ValidationException.class)\n\t\t\t.isThrownBy(Validation.byDefaultProvider().configure()::getDefaultMessageInterpolator)\n\t\t\t.withMessageContaining(\"jakarta.el.ExpressionFactory\");\n\t}\n\n\t@Test\n\tvoid getObjectShouldUseFallback() {\n\t\tMessageInterpolator interpolator = new MessageInterpolatorFactory().getObject();\n\t\tassertThat(interpolator).isInstanceOf(ParameterMessageInterpolator.class);\n\t}\n\n\t@Test\n\tvoid getObjectShouldUseMessageSourceMessageInterpolatorDelegateWithFallback() {\n\t\tMessageSource messageSource = mock(MessageSource.class);\n\t\tMessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(messageSource);\n\t\tMessageInterpolator interpolator = interpolatorFactory.getObject();\n\t\tassertThat(interpolator).isInstanceOf(MessageSourceMessageInterpolator.class);\n\t\tassertThat(interpolator).hasFieldOrPropertyWithValue(\"messageSource\", messageSource);\n\t\tassertThat(ReflectionTestUtils.getField(interpolator, \"messageInterpolator\"))\n\t\t\t.isInstanceOf(ParameterMessageInterpolator.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/validation/MessageSourceMessageInterpolatorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport jakarta.validation.ConstraintViolation;\nimport jakarta.validation.Validator;\nimport jakarta.validation.constraints.NotNull;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.context.support.StaticMessageSource;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Integration tests for {@link MessageSourceMessageInterpolator}.\n *\n * @author Dmytro Nosan\n */\nclass MessageSourceMessageInterpolatorIntegrationTests {\n\n\t@NotNull\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String defaultMessage;\n\n\t@NotNull(message = \"{null}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String nullable;\n\n\t@NotNull(message = \"{blank}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String blank;\n\n\t@NotNull(message = \"{unknown}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String unknown;\n\n\t@NotNull(message = \"{recursion}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String recursion;\n\n\t@NotNull(message = \"\\\\{null}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String escapePrefix;\n\n\t@NotNull(message = \"{null\\\\}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String escapeSuffix;\n\n\t@NotNull(message = \"\\\\{null\\\\}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String escapePrefixSuffix;\n\n\t@NotNull(message = \"\\\\\\\\{null}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String escapeEscape;\n\n\t@Test\n\tvoid defaultMessage() {\n\t\tassertThat(validate(\"defaultMessage\")).containsExactly(\"must not be null\");\n\t}\n\n\t@Test\n\tvoid nullable() {\n\t\tassertThat(validate(\"nullable\")).containsExactly(\"must not be null\");\n\t}\n\n\t@Test\n\tvoid blank() {\n\t\tassertThat(validate(\"blank\")).containsExactly(\"must not be null or must not be blank\");\n\t}\n\n\t@Test\n\tvoid recursion() {\n\t\tassertThatException().isThrownBy(() -> validate(\"recursion\"))\n\t\t\t.withStackTraceContaining(\"Circular reference '{recursion -> middle -> recursion}'\");\n\t}\n\n\t@Test\n\tvoid unknown() {\n\t\tassertThat(validate(\"unknown\")).containsExactly(\"{unknown}\");\n\t}\n\n\t@Test\n\tvoid escapePrefix() {\n\t\tassertThat(validate(\"escapePrefix\")).containsExactly(\"\\\\{null}\");\n\t}\n\n\t@Test\n\tvoid escapeSuffix() {\n\t\tassertThat(validate(\"escapeSuffix\")).containsExactly(\"{null\\\\}\");\n\t}\n\n\t@Test\n\tvoid escapePrefixSuffix() {\n\t\tassertThat(validate(\"escapePrefixSuffix\")).containsExactly(\"{null}\");\n\t}\n\n\t@Test\n\tvoid escapeEscape() {\n\t\tassertThat(validate(\"escapeEscape\")).containsExactly(\"\\\\must not be null\");\n\t}\n\n\tprivate List<String> validate(String property) {\n\t\treturn withEnglishLocale(() -> {\n\t\t\tValidator validator = buildValidator();\n\t\t\tList<String> messages = new ArrayList<>();\n\t\t\tSet<ConstraintViolation<Object>> constraints = validator.validateProperty(this, property);\n\t\t\tfor (ConstraintViolation<Object> constraint : constraints) {\n\t\t\t\tmessages.add(constraint.getMessage());\n\t\t\t}\n\t\t\treturn messages;\n\t\t});\n\t}\n\n\tprivate static Validator buildValidator() {\n\t\tLocale locale = LocaleContextHolder.getLocale();\n\t\tStaticMessageSource messageSource = new StaticMessageSource();\n\t\tmessageSource.addMessage(\"blank\", locale, \"{null} or {jakarta.validation.constraints.NotBlank.message}\");\n\t\tmessageSource.addMessage(\"null\", locale, \"{jakarta.validation.constraints.NotNull.message}\");\n\t\tmessageSource.addMessage(\"recursion\", locale, \"{middle}\");\n\t\tmessageSource.addMessage(\"middle\", locale, \"{recursion}\");\n\t\tMessageInterpolatorFactory messageInterpolatorFactory = new MessageInterpolatorFactory(messageSource);\n\t\ttry (LocalValidatorFactoryBean validatorFactory = new LocalValidatorFactoryBean()) {\n\t\t\tvalidatorFactory.setMessageInterpolator(messageInterpolatorFactory.getObject());\n\t\t\tvalidatorFactory.afterPropertiesSet();\n\t\t\treturn validatorFactory.getValidator();\n\t\t}\n\t}\n\n\tprivate static <T> T withEnglishLocale(Supplier<T> supplier) {\n\t\tLocale defaultLocale = Locale.getDefault();\n\t\ttry {\n\t\t\tLocale.setDefault(Locale.ENGLISH);\n\t\t\treturn supplier.get();\n\t\t}\n\t\tfinally {\n\t\t\tLocale.setDefault(defaultLocale);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/validation/MessageSourceMessageInterpolatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation;\n\nimport java.util.Locale;\n\nimport jakarta.validation.MessageInterpolator;\nimport jakarta.validation.MessageInterpolator.Context;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.support.StaticMessageSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MessageSourceMessageInterpolator}.\n *\n * @author Dmytro Nosan\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass MessageSourceMessageInterpolatorTests {\n\n\tprivate final Context context = mock(Context.class);\n\n\tprivate final StaticMessageSource messageSource = new StaticMessageSource();\n\n\tprivate final MessageSourceMessageInterpolator interpolator = new MessageSourceMessageInterpolator(\n\t\t\tthis.messageSource, new IdentityMessageInterpolator());\n\n\t@Test\n\tvoid interpolateShouldReplaceParameters() {\n\t\tthis.messageSource.addMessage(\"foo\", Locale.getDefault(), \"fooValue\");\n\t\tthis.messageSource.addMessage(\"bar\", Locale.getDefault(), \"\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}{bar}\", this.context)).isEqualTo(\"fooValue\");\n\t}\n\n\t@Test\n\tvoid interpolateWhenParametersAreUnknownShouldLeaveThemUnchanged() {\n\t\tthis.messageSource.addMessage(\"top\", Locale.getDefault(), \"{child}+{child}\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}{top}{bar}\", this.context))\n\t\t\t.isEqualTo(\"{foo}{child}+{child}{bar}\");\n\t}\n\n\t@Test\n\tvoid interpolateWhenParametersAreUnknownUsingCodeAsDefaultShouldLeaveThemUnchanged() {\n\t\tthis.messageSource.setUseCodeAsDefaultMessage(true);\n\t\tthis.messageSource.addMessage(\"top\", Locale.getDefault(), \"{child}+{child}\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}{top}{bar}\", this.context))\n\t\t\t.isEqualTo(\"{foo}{child}+{child}{bar}\");\n\t}\n\n\t@Test\n\tvoid interpolateShouldReplaceParameterThatReferencesAMessageThatMatchesItsCode() {\n\t\tthis.messageSource.addMessage(\"foo\", Locale.getDefault(), \"foo\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}\", this.context)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid interpolateUsingCodeAsDefaultShouldReplaceParameterThatReferencesAMessageThatMatchesItsCode() {\n\t\tthis.messageSource.setUseCodeAsDefaultMessage(true);\n\t\tthis.messageSource.addMessage(\"foo\", Locale.getDefault(), \"foo\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}\", this.context)).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid interpolateWhenParametersAreNestedShouldFullyReplaceAllParameters() {\n\t\tthis.messageSource.addMessage(\"top\", Locale.getDefault(), \"{child}+{child}\");\n\t\tthis.messageSource.addMessage(\"child\", Locale.getDefault(), \"{{differentiator}.grandchild}\");\n\t\tthis.messageSource.addMessage(\"differentiator\", Locale.getDefault(), \"first\");\n\t\tthis.messageSource.addMessage(\"first.grandchild\", Locale.getDefault(), \"actualValue\");\n\t\tassertThat(this.interpolator.interpolate(\"{top}\", this.context)).isEqualTo(\"actualValue+actualValue\");\n\t}\n\n\t@Test\n\tvoid interpolateWhenParameterBracesAreUnbalancedShouldLeaveThemUnchanged() {\n\t\tthis.messageSource.addMessage(\"top\", Locale.getDefault(), \"topValue\");\n\t\tassertThat(this.interpolator.interpolate(\"\\\\{top}\", this.context)).isEqualTo(\"\\\\{top}\");\n\t\tassertThat(this.interpolator.interpolate(\"{top\\\\}\", this.context)).isEqualTo(\"{top\\\\}\");\n\t\tassertThat(this.interpolator.interpolate(\"{{top}\", this.context)).isEqualTo(\"{{top}\");\n\t\tassertThat(this.interpolator.interpolate(\"{top}}\", this.context)).isEqualTo(\"topValue}\");\n\t}\n\n\t@Test\n\tvoid interpolateWhenBracesAreEscapedShouldIgnore() {\n\t\tthis.messageSource.addMessage(\"foo\", Locale.getDefault(), \"fooValue\");\n\t\tthis.messageSource.addMessage(\"bar\", Locale.getDefault(), \"\\\\{foo}\");\n\t\tthis.messageSource.addMessage(\"bazz\\\\}\", Locale.getDefault(), \"bazzValue\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}\", this.context)).isEqualTo(\"fooValue\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}\\\\a\", this.context)).isEqualTo(\"fooValue\\\\a\");\n\t\tassertThat(this.interpolator.interpolate(\"\\\\\\\\{foo}\", this.context)).isEqualTo(\"\\\\\\\\fooValue\");\n\t\tassertThat(this.interpolator.interpolate(\"\\\\\\\\\\\\{foo}\", this.context)).isEqualTo(\"\\\\\\\\\\\\{foo}\");\n\t\tassertThat(this.interpolator.interpolate(\"\\\\{foo}\", this.context)).isEqualTo(\"\\\\{foo}\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo\\\\}\", this.context)).isEqualTo(\"{foo\\\\}\");\n\t\tassertThat(this.interpolator.interpolate(\"\\\\{foo\\\\}\", this.context)).isEqualTo(\"\\\\{foo\\\\}\");\n\t\tassertThat(this.interpolator.interpolate(\"{foo}\\\\\", this.context)).isEqualTo(\"fooValue\\\\\");\n\t\tassertThat(this.interpolator.interpolate(\"{bar}\", this.context)).isEqualTo(\"\\\\{foo}\");\n\t\tassertThat(this.interpolator.interpolate(\"{bazz\\\\}}\", this.context)).isEqualTo(\"bazzValue\");\n\t}\n\n\t@Test\n\tvoid interpolateWhenParametersContainACycleShouldThrow() {\n\t\tthis.messageSource.addMessage(\"a\", Locale.getDefault(), \"{b}\");\n\t\tthis.messageSource.addMessage(\"b\", Locale.getDefault(), \"{c}\");\n\t\tthis.messageSource.addMessage(\"c\", Locale.getDefault(), \"{a}\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.interpolator.interpolate(\"{a}\", this.context))\n\t\t\t.withMessage(\"Circular reference '{a -> b -> c -> a}'\");\n\t}\n\n\tprivate static final class IdentityMessageInterpolator implements MessageInterpolator {\n\n\t\t@Override\n\t\tpublic String interpolate(String messageTemplate, Context context) {\n\t\t\treturn messageTemplate;\n\t\t}\n\n\t\t@Override\n\t\tpublic String interpolate(String messageTemplate, Context context, Locale locale) {\n\t\t\treturn messageTemplate;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/validation/beanvalidation/MethodValidationExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.beanvalidation;\n\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MethodValidationExcludeFilter}.\n *\n * @author Andy Wilkinson\n */\nclass MethodValidationExcludeFilterTests {\n\n\t@Test\n\tvoid byAnnotationWhenClassIsAnnotatedExcludes() {\n\t\tMethodValidationExcludeFilter filter = MethodValidationExcludeFilter.byAnnotation(Indicator.class);\n\t\tassertThat(filter.isExcluded(Annotated.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid byAnnotationWhenClassIsNotAnnotatedIncludes() {\n\t\tMethodValidationExcludeFilter filter = MethodValidationExcludeFilter.byAnnotation(Indicator.class);\n\t\tassertThat(filter.isExcluded(Plain.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid byAnnotationWhenSuperclassIsAnnotatedWithInheritedAnnotationExcludes() {\n\t\tMethodValidationExcludeFilter filter = MethodValidationExcludeFilter.byAnnotation(Indicator.class);\n\t\tassertThat(filter.isExcluded(AnnotatedSuperClass.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid byAnnotationWithDirectSearchStrategyWhenSuperclassIsAnnotatedWithInheritedAnnotationIncludes() {\n\t\tMethodValidationExcludeFilter filter = MethodValidationExcludeFilter.byAnnotation(Indicator.class,\n\t\t\t\tSearchStrategy.DIRECT);\n\t\tassertThat(filter.isExcluded(AnnotatedSuperClass.class)).isFalse();\n\t}\n\n\tstatic class Plain {\n\n\t}\n\n\t@Indicator\n\tstatic class Annotated {\n\n\t}\n\n\t@Inherited\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface Indicator {\n\n\t}\n\n\tstatic class AnnotatedSuperClass extends Annotated {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/context/reactive/FilteredReactiveWebContextResourceFilePathResolverIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link FilteredReactiveWebContextResourceFilePathResolver}.\n *\n * @author Dmytro Nosan\n */\nclass FilteredReactiveWebContextResourceFilePathResolverIntegrationTests {\n\n\t@Test\n\tvoid getResourceWhenFilteredReactiveWebContextResourceWithPreferFileResolution() throws Exception {\n\t\tResourceLoader resourceLoader = ApplicationResourceLoader\n\t\t\t.get(new AnnotationConfigReactiveWebApplicationContext(), true);\n\t\tResource resource = resourceLoader.getResource(\"src/main/resources/a-file\");\n\t\tassertThat(resource).isInstanceOf(FileSystemResource.class);\n\t\tassertThat(resource.getFile().getAbsoluteFile())\n\t\t\t.isEqualTo(new File(\"src/main/resources/a-file\").getAbsoluteFile());\n\t}\n\n\t@Test\n\tvoid getResourceWhenFilteredReactiveWebContextResource() {\n\t\tResourceLoader resourceLoader = ApplicationResourceLoader\n\t\t\t.get(new AnnotationConfigReactiveWebApplicationContext(), false);\n\t\tResource resource = resourceLoader.getResource(\"src/main/resources/a-file\");\n\t\tassertThat(resource).isInstanceOf(ClassUtils.resolveClassName(\n\t\t\t\t\"org.springframework.boot.web.context.reactive.FilteredReactiveWebContextResource\", null));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/context/reactive/GenericReactiveWebApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.reactive;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GenericReactiveWebApplicationContext}\n *\n * @author Brian Clozel\n */\nclass GenericReactiveWebApplicationContextTests {\n\n\t@Test\n\tvoid getResourceByPath() throws Exception {\n\t\tGenericReactiveWebApplicationContext context = new GenericReactiveWebApplicationContext();\n\t\tResource rootResource = context.getResourceByPath(\"/\");\n\t\tassertThat(rootResource.exists()).isFalse();\n\t\tassertThat(rootResource.createRelative(\"application.properties\").exists()).isFalse();\n\t\tcontext.close();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/context/servlet/ServletContextResourceFilePathResolverIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.context.servlet;\n\nimport java.io.File;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.context.support.ServletContextResource;\nimport org.springframework.web.context.support.ServletContextResourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ServletContextResourceFilePathResolver}.\n *\n * @author Phillip Webb\n */\nclass ServletContextResourceFilePathResolverIntegrationTests {\n\n\t@Test\n\tvoid getResourceWithPreferFileResolutionWhenPathWithServletContextResource() throws Exception {\n\t\tServletContext servletContext = new MockServletContext();\n\t\tServletContextResourceLoader servletContextResourceLoader = new ServletContextResourceLoader(servletContext);\n\t\tResourceLoader loader = ApplicationResourceLoader.get(servletContextResourceLoader, true);\n\t\tResource resource = loader.getResource(\"src/main/resources/a-file\");\n\t\tassertThat(resource).isInstanceOf(FileSystemResource.class);\n\t\tassertThat(resource.getFile().getAbsoluteFile())\n\t\t\t.isEqualTo(new File(\"src/main/resources/a-file\").getAbsoluteFile());\n\t\tResourceLoader regularLoader = ApplicationResourceLoader.get(servletContextResourceLoader, false);\n\t\tassertThat(regularLoader.getResource(\"src/main/resources/a-file\")).isInstanceOf(ServletContextResource.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/error/ErrorAttributesOptionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\nimport java.util.EnumSet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ErrorAttributeOptions}.\n *\n * @author Wanderlei Souza\n * @author Stephane Nicoll\n */\nclass ErrorAttributesOptionsTests {\n\n\t@Test\n\tvoid includingFromEmptyAttributesReturnAddedEntry() {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.of(EnumSet.noneOf(Include.class));\n\t\tassertThat(options.including(Include.EXCEPTION).getIncludes()).containsOnly(Include.EXCEPTION);\n\t}\n\n\t@Test\n\tvoid includingFromMatchingAttributesDoesNotModifyOptions() {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.of(EnumSet.of(Include.EXCEPTION, Include.STACK_TRACE));\n\t\tassertThat(options.including(Include.EXCEPTION).getIncludes()).containsOnly(Include.EXCEPTION,\n\t\t\t\tInclude.STACK_TRACE);\n\t}\n\n\t@Test\n\tvoid excludingFromEmptyAttributesReturnEmptyList() {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.of(EnumSet.noneOf(Include.class));\n\t\tassertThat(options.excluding(Include.EXCEPTION).getIncludes()).isEmpty();\n\t}\n\n\t@Test\n\tvoid excludingFromMatchingAttributesRemoveMatch() {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.of(EnumSet.of(Include.EXCEPTION, Include.STACK_TRACE));\n\t\tassertThat(options.excluding(Include.EXCEPTION).getIncludes()).containsOnly(Include.STACK_TRACE);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/error/ErrorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.error;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.context.MessageSourceResolvable;\nimport org.springframework.context.support.DefaultMessageSourceResolvable;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Error}.\n *\n * @author Andy Wilkinson\n */\nclass ErrorTests {\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid wrapIfNecessaryDoesNotWrapFieldErrorOrObjectError() {\n\t\tList<MessageSourceResolvable> wrapped = Error.wrapIfNecessary(List.of(new ObjectError(\"name\", \"message\"),\n\t\t\t\tnew FieldError(\"name\", \"field\", \"message\"), new CustomMessageSourceResolvable(\"code\")));\n\t\tassertThat(wrapped).extracting((error) -> (Class) error.getClass())\n\t\t\t.containsExactly(ObjectError.class, FieldError.class, Error.class);\n\t}\n\n\t@Test\n\tvoid errorCauseDoesNotAppearInJson() {\n\t\tString json = new JsonMapper()\n\t\t\t.writeValueAsString(Error.wrapIfNecessary(List.of(new CustomMessageSourceResolvable(\"code\"))));\n\t\tassertThat(json).doesNotContain(\"some detail\");\n\t}\n\n\tpublic static class CustomMessageSourceResolvable extends DefaultMessageSourceResolvable {\n\n\t\tCustomMessageSourceResolvable(String code) {\n\t\t\tsuper(code);\n\t\t}\n\n\t\tpublic String getDetail() {\n\t\t\treturn \"some detail\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/AbstractFilterRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterRegistration;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatCode;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Abstract base for {@link AbstractFilterRegistrationBean} tests.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@ExtendWith(MockitoExtension.class)\nabstract class AbstractFilterRegistrationBeanTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tServletContext servletContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFilterRegistration.Dynamic registration;\n\n\t@Test\n\tvoid startupWithDefaults() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addFilter(eq(\"mockFilter\"), getExpectedFilter());\n\t\tthen(this.registration).should().setAsyncSupported(true);\n\t\tthen(this.registration).should().addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, \"/*\");\n\t}\n\n\t@Test\n\tvoid startupWithSpecifiedValues() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.setName(\"test\");\n\t\tbean.setAsyncSupported(false);\n\t\tbean.setInitParameters(Collections.singletonMap(\"a\", \"b\"));\n\t\tbean.addInitParameter(\"c\", \"d\");\n\t\tbean.setUrlPatterns(new LinkedHashSet<>(Arrays.asList(\"/a\", \"/b\")));\n\t\tbean.addUrlPatterns(\"/c\");\n\t\tbean.setServletNames(new LinkedHashSet<>(Arrays.asList(\"s1\", \"s2\")));\n\t\tbean.addServletNames(\"s3\");\n\t\tbean.setServletRegistrationBeans(Collections.singleton(mockServletRegistration(\"s4\")));\n\t\tbean.addServletRegistrationBeans(mockServletRegistration(\"s5\"));\n\t\tbean.setMatchAfter(true);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addFilter(eq(\"test\"), getExpectedFilter());\n\t\tthen(this.registration).should().setAsyncSupported(false);\n\t\tMap<String, String> expectedInitParameters = new HashMap<>();\n\t\texpectedInitParameters.put(\"a\", \"b\");\n\t\texpectedInitParameters.put(\"c\", \"d\");\n\t\tthen(this.registration).should().setInitParameters(expectedInitParameters);\n\t\tthen(this.registration).should()\n\t\t\t.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, \"/a\", \"/b\", \"/c\");\n\t\tthen(this.registration).should()\n\t\t\t.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, \"s4\", \"s5\", \"s1\", \"s2\", \"s3\");\n\t}\n\n\t@Test\n\tvoid specificName() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.setName(\"specificName\");\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addFilter(eq(\"specificName\"), getExpectedFilter());\n\t}\n\n\t@Test\n\tvoid deducedName() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addFilter(eq(\"mockFilter\"), getExpectedFilter());\n\t}\n\n\t@Test\n\tvoid disable() throws Exception {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.setEnabled(false);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should(never()).addFilter(eq(\"mockFilter\"), getExpectedFilter());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setServletRegistrationBeanMustNotBeNull() {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.setServletRegistrationBeans(null))\n\t\t\t.withMessageContaining(\"servletRegistrationBeans' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addServletRegistrationBeanMustNotBeNull() {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> bean.addServletRegistrationBeans((ServletRegistrationBean[]) null))\n\t\t\t.withMessageContaining(\"'servletRegistrationBeans' must not be null\");\n\t}\n\n\t@Test\n\tvoid setServletRegistrationBeanReplacesValue() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean(mockServletRegistration(\"a\"));\n\t\tbean.setServletRegistrationBeans(new LinkedHashSet<>(Collections.singletonList(mockServletRegistration(\"b\"))));\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should().addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), false, \"b\");\n\t}\n\n\t@Test\n\tvoid modifyInitParameters() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.addInitParameter(\"a\", \"b\");\n\t\tbean.getInitParameters().put(\"a\", \"c\");\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should().setInitParameters(Collections.singletonMap(\"a\", \"c\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setUrlPatternMustNotBeNull() {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.setUrlPatterns(null))\n\t\t\t.withMessageContaining(\"'urlPatterns' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addUrlPatternMustNotBeNull() {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.addUrlPatterns((String[]) null))\n\t\t\t.withMessageContaining(\"'urlPatterns' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setServletNameMustNotBeNull() {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.setServletNames(null))\n\t\t\t.withMessageContaining(\"'servletNames' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addServletNameMustNotBeNull() {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.addServletNames((String[]) null))\n\t\t\t.withMessageContaining(\"'servletNames' must not be null\");\n\t}\n\n\t@Test\n\tvoid withSpecificDispatcherTypes() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.setDispatcherTypes(DispatcherType.INCLUDE, DispatcherType.FORWARD);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should()\n\t\t\t.addMappingForUrlPatterns(EnumSet.of(DispatcherType.INCLUDE, DispatcherType.FORWARD), false, \"/*\");\n\t}\n\n\t@Test\n\tvoid withSpecificDispatcherTypesEnumSet() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tEnumSet<DispatcherType> types = EnumSet.of(DispatcherType.INCLUDE, DispatcherType.FORWARD);\n\t\tbean.setDispatcherTypes(types);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should().addMappingForUrlPatterns(types, false, \"/*\");\n\t}\n\n\t@Test\n\tvoid failsWithDoubleRegistration() {\n\t\tassertThatIllegalStateException().isThrownBy(this::doubleRegistration)\n\t\t\t.withMessage(\"Failed to register 'filter double-registration' on the \"\n\t\t\t\t\t+ \"servlet context. Possibly already registered?\");\n\t}\n\n\tprivate void doubleRegistration() throws ServletException {\n\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\tbean.setName(\"double-registration\");\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(null);\n\t\tbean.onStartup(this.servletContext);\n\t}\n\n\t@Test\n\tvoid doesntFailIfDoubleRegistrationIsIgnored() {\n\t\tassertThatCode(() -> {\n\t\t\tAbstractFilterRegistrationBean<?> bean = createFilterRegistrationBean();\n\t\t\tbean.setName(\"double-registration\");\n\t\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(null);\n\t\t\tbean.setIgnoreRegistrationFailure(true);\n\t\t\tbean.onStartup(this.servletContext);\n\t\t}).doesNotThrowAnyException();\n\t}\n\n\t@Test\n\tvoid shouldDetermineDispatcherTypesIfNotSet() {\n\t\tAbstractFilterRegistrationBean<SimpleFilter> simpleFilter = new AbstractFilterRegistrationBean<>() {\n\t\t\t@Override\n\t\t\tpublic SimpleFilter getFilter() {\n\t\t\t\treturn new SimpleFilter();\n\t\t\t}\n\t\t};\n\t\tassertThat(simpleFilter.determineDispatcherTypes()).containsExactly(DispatcherType.REQUEST);\n\t}\n\n\t@Test\n\tvoid shouldDetermineDispatcherTypesForOncePerRequestFilters() {\n\t\tAbstractFilterRegistrationBean<SimpleOncePerRequestFilter> simpleFilter = new AbstractFilterRegistrationBean<>() {\n\t\t\t@Override\n\t\t\tpublic SimpleOncePerRequestFilter getFilter() {\n\t\t\t\treturn new SimpleOncePerRequestFilter();\n\t\t\t}\n\t\t};\n\t\tassertThat(simpleFilter.determineDispatcherTypes())\n\t\t\t.containsExactlyInAnyOrderElementsOf(EnumSet.allOf(DispatcherType.class));\n\t}\n\n\t@Test\n\tvoid shouldDetermineDispatcherTypesForSetDispatcherTypes() {\n\t\tAbstractFilterRegistrationBean<SimpleFilter> simpleFilter = new AbstractFilterRegistrationBean<>() {\n\t\t\t@Override\n\t\t\tpublic SimpleFilter getFilter() {\n\t\t\t\treturn new SimpleFilter();\n\t\t\t}\n\t\t};\n\t\tsimpleFilter.setDispatcherTypes(DispatcherType.INCLUDE, DispatcherType.FORWARD);\n\t\tassertThat(simpleFilter.determineDispatcherTypes()).containsExactlyInAnyOrder(DispatcherType.INCLUDE,\n\t\t\t\tDispatcherType.FORWARD);\n\t}\n\n\tprotected abstract Filter getExpectedFilter();\n\n\tprotected abstract AbstractFilterRegistrationBean<?> createFilterRegistrationBean(\n\t\t\tServletRegistrationBean<?>... servletRegistrationBeans);\n\n\tprotected final ServletRegistrationBean<?> mockServletRegistration(String name) {\n\t\tServletRegistrationBean<?> bean = new ServletRegistrationBean<>();\n\t\tbean.setName(name);\n\t\treturn bean;\n\t}\n\n\tprivate static final class SimpleFilter implements Filter {\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\n\t\t}\n\n\t}\n\n\tprivate static final class SimpleOncePerRequestFilter extends OncePerRequestFilter {\n\n\t\t@Override\n\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\tFilterChain filterChain) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DelegatingFilterProxyRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.mock.web.MockFilterChain;\nimport org.springframework.mock.web.MockFilterConfig;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\nimport org.springframework.web.filter.DelegatingFilterProxy;\nimport org.springframework.web.filter.GenericFilterBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.isA;\n\n/**\n * Tests for {@link DelegatingFilterProxyRegistrationBean}.\n *\n * @author Phillip Webb\n */\nclass DelegatingFilterProxyRegistrationBeanTests extends AbstractFilterRegistrationBeanTests {\n\n\tprivate static final ThreadLocal<Boolean> mockFilterInitialized = new ThreadLocal<>();\n\n\tprivate final GenericWebApplicationContext applicationContext = new GenericWebApplicationContext(\n\t\t\tnew MockServletContext());\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid targetBeanNameMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DelegatingFilterProxyRegistrationBean(null))\n\t\t\t.withMessageContaining(\"'targetBeanName' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid targetBeanNameMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DelegatingFilterProxyRegistrationBean(\"\"))\n\t\t\t.withMessageContaining(\"'targetBeanName' must not be empty\");\n\t}\n\n\t@Test\n\tvoid nameDefaultsToTargetBeanName() {\n\t\tassertThat(new DelegatingFilterProxyRegistrationBean(\"myFilter\").getOrDeduceName(null)).isEqualTo(\"myFilter\");\n\t}\n\n\t@Test\n\tvoid getFilterUsesDelegatingFilterProxy() {\n\t\tDelegatingFilterProxyRegistrationBean registrationBean = createFilterRegistrationBean();\n\t\tFilter filter = registrationBean.getFilter();\n\t\tassertThat(filter).isInstanceOf(DelegatingFilterProxy.class);\n\t\tassertThat(filter).extracting(\"webApplicationContext\").isEqualTo(this.applicationContext);\n\t\tassertThat(filter).extracting(\"targetBeanName\").isEqualTo(\"mockFilter\");\n\t}\n\n\t@Test\n\tvoid initShouldNotCauseEarlyInitialization() throws Exception {\n\t\tthis.applicationContext.registerBeanDefinition(\"mockFilter\", new RootBeanDefinition(MockFilter.class));\n\t\tDelegatingFilterProxyRegistrationBean registrationBean = createFilterRegistrationBean();\n\t\tFilter filter = registrationBean.getFilter();\n\t\tfilter.init(new MockFilterConfig());\n\t\tmockFilterInitialized.remove();\n\t\tfilter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain());\n\t\tassertThat(mockFilterInitialized.get()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createServletRegistrationBeanMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new DelegatingFilterProxyRegistrationBean(\"mockFilter\", (ServletRegistrationBean<?>[]) null))\n\t\t\t.withMessageContaining(\"'servletRegistrationBeans' must not be null\");\n\t}\n\n\t@Override\n\tprotected DelegatingFilterProxyRegistrationBean createFilterRegistrationBean(\n\t\t\tServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\tDelegatingFilterProxyRegistrationBean bean = new DelegatingFilterProxyRegistrationBean(\"mockFilter\",\n\t\t\t\tservletRegistrationBeans);\n\t\tbean.setApplicationContext(this.applicationContext);\n\t\treturn bean;\n\t}\n\n\t@Override\n\tprotected Filter getExpectedFilter() {\n\t\treturn isA(DelegatingFilterProxy.class);\n\t}\n\n\tstatic class MockFilter extends GenericFilterBean {\n\n\t\tMockFilter() {\n\t\t\tmockFilterInitialized.set(true);\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/DynamicRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.Registration.Dynamic;\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DynamicRegistrationBean}.\n *\n * @author Moritz Halbritter\n */\nclass DynamicRegistrationBeanTests {\n\n\t@Test\n\tvoid shouldUseNameIfSet() {\n\t\tDynamicRegistrationBean<?> bean = createBean();\n\t\tbean.setName(\"givenName\");\n\t\tassertThat(bean.getOrDeduceName(\"dummy\")).isEqualTo(\"givenName\");\n\t}\n\n\t@Test\n\tvoid shouldUseBeanNameIfNameIsNotSet() {\n\t\tDynamicRegistrationBean<?> bean = createBean();\n\t\tbean.setBeanName(\"beanName\");\n\t\tassertThat(bean.getOrDeduceName(\"dummy\")).isEqualTo(\"beanName\");\n\t}\n\n\t@Test\n\tvoid shouldUseConventionBasedNameIfNoNameOrBeanNameIsSet() {\n\t\tDynamicRegistrationBean<?> bean = createBean();\n\t\tassertThat(bean.getOrDeduceName(\"dummy\")).isEqualTo(\"string\");\n\t}\n\n\tprivate static DynamicRegistrationBean<?> createBean() {\n\t\treturn new DynamicRegistrationBean<>() {\n\t\t\t@Override\n\t\t\tprotected @Nullable Dynamic addRegistration(String description, ServletContext servletContext) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected String getDescription() {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.io.IOException;\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.servlet.mock.MockFilter;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link FilterRegistrationBean}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass FilterRegistrationBeanTests extends AbstractFilterRegistrationBeanTests {\n\n\tprivate final MockFilter filter = new MockFilter();\n\n\tprivate final OncePerRequestFilter oncePerRequestFilter = new OncePerRequestFilter() {\n\n\t\t@Override\n\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\tFilterChain filterChain) throws ServletException, IOException {\n\t\t\tfilterChain.doFilter(request, response);\n\t\t}\n\n\t};\n\n\t@Test\n\tvoid setFilter() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tFilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();\n\t\tbean.setFilter(this.filter);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addFilter(\"mockFilter\", this.filter);\n\t}\n\n\t@Test\n\tvoid setFilterMustNotBeNull() {\n\t\tFilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.onStartup(this.servletContext))\n\t\t\t.withMessageContaining(\"'filter' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid constructFilterMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new FilterRegistrationBean<>(null))\n\t\t\t.withMessageContaining(\"'filter' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createServletRegistrationBeanMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new FilterRegistrationBean<>(this.filter, (ServletRegistrationBean[]) null))\n\t\t\t.withMessageContaining(\"'servletRegistrationBeans' must not be null\");\n\t}\n\n\t@Test\n\tvoid startupWithOncePerRequestDefaults() throws Exception {\n\t\tgiven(this.servletContext.addFilter(anyString(), any(Filter.class))).willReturn(this.registration);\n\t\tFilterRegistrationBean<?> bean = new FilterRegistrationBean<>(this.oncePerRequestFilter);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addFilter(eq(\"oncePerRequestFilter\"), eq(this.oncePerRequestFilter));\n\t\tthen(this.registration).should().setAsyncSupported(true);\n\t\tthen(this.registration).should().addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, \"/*\");\n\t}\n\n\t@Override\n\tprotected AbstractFilterRegistrationBean<MockFilter> createFilterRegistrationBean(\n\t\t\tServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\treturn new FilterRegistrationBean<>(this.filter, servletRegistrationBeans);\n\t}\n\n\t@Override\n\tprotected Filter getExpectedFilter() {\n\t\treturn eq(this.filter);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/FilterRegistrationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Collections;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterRegistration.Dynamic;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.context.servlet.WebApplicationContextInitializer;\nimport org.springframework.boot.web.servlet.mock.MockFilter;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Integration tests for {@link Filter} registration.\n *\n * @author Andy Wilkinson\n */\nclass FilterRegistrationIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid normalFiltersAreRegistered() {\n\t\tload(FilterConfiguration.class);\n\t\tassertThat(this.context).isNotNull();\n\t\tthen(this.context.getServletContext()).should()\n\t\t\t.addFilter(\"myFilter\", this.context.getBean(\"myFilter\", MockFilter.class));\n\t}\n\n\t@Test\n\tvoid scopedTargetFiltersAreNotRegistered() {\n\t\tload(ScopedTargetFilterConfiguration.class);\n\t\tassertThat(this.context).isNotNull();\n\t\tthen(this.context.getServletContext()).should(times(0)).addFilter(any(String.class), any(Filter.class));\n\t}\n\n\tprivate void load(Class<?> configuration) {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(Collections.emptyEnumeration());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.setServletContext(servletContext);\n\t\tthis.context.register(configuration);\n\t\tthis.context.refresh();\n\t\ttry {\n\t\t\tnew WebApplicationContextInitializer(this.context).initialize(servletContext);\n\t\t}\n\t\tcatch (ServletException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ScopedTargetFilterConfiguration {\n\n\t\t@Bean(name = \"scopedTarget.myFilter\")\n\t\tFilter myFilter() {\n\t\t\treturn new MockFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterConfiguration {\n\n\t\t@Bean\n\t\tFilter myFilter() {\n\t\t\treturn new MockFilter();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/NoSpringWebFilterRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport jakarta.servlet.Filter;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.web.servlet.mock.MockFilter;\n\nimport static org.mockito.ArgumentMatchers.eq;\n\n/**\n * Tests for {@link FilterRegistrationBean} when {@code spring-web} is not on the\n * classpath.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"spring-web-*.jar\")\nclass NoSpringWebFilterRegistrationBeanTests extends AbstractFilterRegistrationBeanTests {\n\n\tprivate final MockFilter filter = new MockFilter();\n\n\t@Override\n\tprotected AbstractFilterRegistrationBean<MockFilter> createFilterRegistrationBean(\n\t\t\tServletRegistrationBean<?>... servletRegistrationBeans) {\n\t\treturn new FilterRegistrationBean<>(this.filter, servletRegistrationBeans);\n\t}\n\n\t@Override\n\tprotected Filter getExpectedFilter() {\n\t\treturn eq(this.filter);\n\t}\n\n\t@Override\n\tvoid shouldDetermineDispatcherTypesForOncePerRequestFilters() {\n\t\t// Disabled because OncePerRequestFilter isn't on the classpath\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletContextInitializerBeansTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Collection;\nimport java.util.EnumSet;\nimport java.util.Map;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.annotation.MultipartConfig;\nimport jakarta.servlet.annotation.WebInitParam;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpSessionIdListener;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServletContextInitializerBeans}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Daeho Kwon\n * @author Dmytro Danilenkov\n */\nclass ServletContextInitializerBeansTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@Test\n\tvoid servletThatImplementsServletContextInitializerIsOnlyRegisteredOnce() {\n\t\tload(ServletConfiguration.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory());\n\t\tassertThat(initializerBeans).hasSize(1);\n\t\tassertThat(initializerBeans.iterator()).toIterable().hasOnlyElementsOfType(TestServlet.class);\n\t}\n\n\t@Test\n\tvoid filterThatImplementsServletContextInitializerIsOnlyRegisteredOnce() {\n\t\tload(FilterConfiguration.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory());\n\t\tassertThat(initializerBeans).hasSize(1);\n\t\tassertThat(initializerBeans.iterator()).toIterable().hasOnlyElementsOfType(TestFilter.class);\n\t}\n\n\t@Test\n\tvoid looksForInitializerBeansOfSpecifiedType() {\n\t\tload(TestConfiguration.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThat(initializerBeans).hasSize(1);\n\t\tassertThat(initializerBeans.iterator()).toIterable().hasOnlyElementsOfType(TestServletContextInitializer.class);\n\t}\n\n\t@Test\n\tvoid whenAnHttpSessionIdListenerBeanIsDefinedThenARegistrationBeanIsCreatedForIt() {\n\t\tload(HttpSessionIdListenerConfiguration.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory());\n\t\tassertThat(initializerBeans).hasSize(1);\n\t\tassertThat(initializerBeans).first()\n\t\t\t.isInstanceOf(ServletListenerRegistrationBean.class)\n\t\t\t.extracting((initializer) -> ((ServletListenerRegistrationBean<?>) initializer).getListener())\n\t\t\t.isInstanceOf(HttpSessionIdListener.class);\n\t}\n\n\t@Test\n\tvoid classesThatImplementMultipleInterfacesAreRegisteredForAllOfThem() {\n\t\tload(MultipleInterfacesConfiguration.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory());\n\t\tassertThat(initializerBeans).hasSize(3);\n\t\tassertThat(initializerBeans).element(0)\n\t\t\t.isInstanceOf(ServletRegistrationBean.class)\n\t\t\t.extracting((initializer) -> ((ServletRegistrationBean<?>) initializer).getServlet())\n\t\t\t.isInstanceOf(TestServletAndFilterAndListener.class);\n\t\tassertThat(initializerBeans).element(1)\n\t\t\t.isInstanceOf(FilterRegistrationBean.class)\n\t\t\t.extracting((initializer) -> ((FilterRegistrationBean<?>) initializer).getFilter())\n\t\t\t.isInstanceOf(TestServletAndFilterAndListener.class);\n\t\tassertThat(initializerBeans).element(2)\n\t\t\t.isInstanceOf(ServletListenerRegistrationBean.class)\n\t\t\t.extracting((initializer) -> ((ServletListenerRegistrationBean<?>) initializer).getListener())\n\t\t\t.isInstanceOf(TestServletAndFilterAndListener.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldApplyServletRegistrationAnnotation() {\n\t\tload(ServletConfigurationWithAnnotation.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class, (servletRegistrationBean) -> {\n\t\t\tassertThat(servletRegistrationBean.isEnabled()).isFalse();\n\t\t\tassertThat(servletRegistrationBean.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);\n\t\t\tassertThat(servletRegistrationBean.getServletName()).isEqualTo(\"test\");\n\t\t\tassertThat(servletRegistrationBean.isAsyncSupported()).isFalse();\n\t\t\tassertThat(servletRegistrationBean.getUrlMappings()).containsExactly(\"/test/*\");\n\t\t\tassertThat(servletRegistrationBean.getInitParameters())\n\t\t\t\t.containsExactlyInAnyOrderEntriesOf(Map.of(\"env\", \"test\", \"debug\", \"true\"));\n\t\t\tassertThat(servletRegistrationBean.getMultipartConfig()).isNotNull();\n\t\t\tassertThat(servletRegistrationBean.getMultipartConfig().getLocation()).isEqualTo(\"/tmp\");\n\t\t\tassertThat(servletRegistrationBean.getMultipartConfig().getMaxFileSize()).isEqualTo(1024);\n\t\t\tassertThat(servletRegistrationBean.getMultipartConfig().getMaxRequestSize()).isEqualTo(4096);\n\t\t\tassertThat(servletRegistrationBean.getMultipartConfig().getFileSizeThreshold()).isEqualTo(128);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldApplyFilterRegistrationAnnotation() {\n\t\tload(FilterConfigurationWithAnnotation.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, FilterRegistrationBean.class, (filterRegistrationBean) -> {\n\t\t\tassertThat(filterRegistrationBean.isEnabled()).isFalse();\n\t\t\tassertThat(filterRegistrationBean.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);\n\t\t\tassertThat(filterRegistrationBean.getFilterName()).isEqualTo(\"test\");\n\t\t\tassertThat(filterRegistrationBean.isAsyncSupported()).isFalse();\n\t\t\tassertThat(filterRegistrationBean.isMatchAfter()).isTrue();\n\t\t\tassertThat(filterRegistrationBean.getServletNames()).containsExactly(\"test\");\n\t\t\tassertThat(filterRegistrationBean.determineDispatcherTypes()).containsExactly(DispatcherType.ERROR);\n\t\t\tassertThat(filterRegistrationBean.getUrlPatterns()).containsExactly(\"/test/*\");\n\t\t\tassertThat(filterRegistrationBean.getInitParameters())\n\t\t\t\t.containsExactlyInAnyOrderEntriesOf(Map.of(\"env\", \"test\", \"debug\", \"true\"));\n\t\t\tCollection<ServletRegistrationBean<?>> servletRegistrationBeans = filterRegistrationBean\n\t\t\t\t.getServletRegistrationBeans();\n\t\t\tassertThat(servletRegistrationBeans).hasSize(1);\n\t\t\tassertThat(servletRegistrationBeans.iterator().next().getServletName())\n\t\t\t\t.isEqualTo(\"testServletRegistrationBean\");\n\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldApplyFilterRegistrationAnnotationWithDefaultDispatcherTypes() {\n\t\tload(FilterConfigurationWithAnnotationAndDefaultDispatcherTypes.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, FilterRegistrationBean.class,\n\t\t\t\t(filterRegistrationBean) -> assertThat(filterRegistrationBean.determineDispatcherTypes())\n\t\t\t\t\t.containsExactlyElementsOf(EnumSet.allOf(DispatcherType.class)));\n\t}\n\n\t@Test\n\tvoid shouldApplyOrderFromBean() {\n\t\tload(OrderedServletConfiguration.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class,\n\t\t\t\t(servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder())\n\t\t\t\t\t.isEqualTo(OrderedTestServlet.ORDER));\n\t}\n\n\t@Test\n\tvoid shouldApplyOrderFromOrderAnnotationOnBeanMethod() {\n\t\tload(ServletConfigurationWithAnnotationAndOrderAnnotation.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class,\n\t\t\t\t(servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder())\n\t\t\t\t\t.isEqualTo(ServletConfigurationWithAnnotationAndOrderAnnotation.ORDER));\n\t}\n\n\t@Test\n\tvoid orderedInterfaceShouldTakePrecedenceOverOrderAnnotation() {\n\t\tload(OrderedServletConfigurationWithAnnotationAndOrder.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class,\n\t\t\t\t(servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder())\n\t\t\t\t\t.isEqualTo(OrderedTestServlet.ORDER));\n\t}\n\n\t@Test\n\tvoid shouldApplyOrderFromOrderAttribute() {\n\t\tload(ServletConfigurationWithAnnotationAndOrder.class);\n\t\tServletContextInitializerBeans initializerBeans = new ServletContextInitializerBeans(\n\t\t\t\tgetContext().getBeanFactory(), TestServletContextInitializer.class);\n\t\tassertThatSingleRegistration(initializerBeans, ServletRegistrationBean.class,\n\t\t\t\t(servletRegistrationBean) -> assertThat(servletRegistrationBean.getOrder())\n\t\t\t\t\t.isEqualTo(ServletConfigurationWithAnnotationAndOrder.ORDER));\n\t}\n\n\tprivate void load(Class<?>... configuration) {\n\t\tthis.context = new AnnotationConfigApplicationContext(configuration);\n\t}\n\n\tprivate <T extends RegistrationBean> void assertThatSingleRegistration(\n\t\t\tServletContextInitializerBeans initializerBeans, Class<T> clazz, ThrowingConsumer<T> code) {\n\t\tassertThat(initializerBeans).hasSize(1);\n\t\tServletContextInitializer initializer = initializerBeans.iterator().next();\n\t\tassertThat(initializer).isInstanceOf(clazz);\n\t\tcode.accept(clazz.cast(initializer));\n\t}\n\n\tprivate ConfigurableApplicationContext getContext() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn this.context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletConfiguration {\n\n\t\t@Bean\n\t\tTestServlet testServlet() {\n\t\t\treturn new TestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OrderedServletConfiguration {\n\n\t\t@Bean\n\t\tOrderedTestServlet testServlet() {\n\t\t\treturn new OrderedTestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletConfigurationWithAnnotation {\n\n\t\t@Bean\n\t\t@ServletRegistration(enabled = false, name = \"test\", asyncSupported = false, urlMappings = \"/test/*\",\n\t\t\t\tloadOnStartup = 1,\n\t\t\t\tinitParameters = { @WebInitParam(name = \"env\", value = \"test\"),\n\t\t\t\t\t\t@WebInitParam(name = \"debug\", value = \"true\") },\n\t\t\t\tmultipartConfig = @MultipartConfig(location = \"/tmp\", maxFileSize = 1024, maxRequestSize = 4096,\n\t\t\t\t\t\tfileSizeThreshold = 128))\n\t\tTestServlet testServlet() {\n\t\t\treturn new TestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletConfigurationWithAnnotationAndOrderAnnotation {\n\n\t\tstatic final int ORDER = 7;\n\n\t\t@Bean\n\t\t@ServletRegistration(name = \"test\")\n\t\t@Order(ORDER)\n\t\tTestServlet testServlet() {\n\t\t\treturn new TestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletConfigurationWithAnnotationAndOrder {\n\n\t\tstatic final int ORDER = 9;\n\n\t\t@Bean\n\t\t@ServletRegistration(name = \"test\", order = ORDER)\n\t\tTestServlet testServlet() {\n\t\t\treturn new TestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OrderedServletConfigurationWithAnnotationAndOrder {\n\n\t\tstatic final int ORDER = 5;\n\n\t\t@Bean\n\t\t@ServletRegistration\n\t\t@Order(ORDER)\n\t\tOrderedTestServlet testServlet() {\n\t\t\treturn new OrderedTestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterConfiguration {\n\n\t\t@Bean\n\t\tTestFilter testFilter() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterConfigurationWithAnnotation {\n\n\t\t@Bean\n\t\t@FilterRegistration(\n\t\t\t\tenabled = false, name = \"test\", asyncSupported = false, dispatcherTypes = DispatcherType.ERROR,\n\t\t\t\tmatchAfter = true, servletNames = \"test\", urlPatterns = \"/test/*\", initParameters = {\n\t\t\t\t\t\t@WebInitParam(name = \"env\", value = \"test\"), @WebInitParam(name = \"debug\", value = \"true\") },\n\t\t\t\tservletClasses = { TestServlet.class })\n\t\tTestFilter testFilter() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<TestServlet> testServletRegistrationBean() {\n\t\t\treturn new ServletRegistrationBean<>(new TestServlet());\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<NonMatchingServlet> nonMatchingServletRegistrationBean() {\n\t\t\treturn new ServletRegistrationBean<>(new NonMatchingServlet());\n\t\t}\n\n\t\tstatic class NonMatchingServlet extends HttpServlet implements ServletContextInitializer {\n\n\t\t\t@Override\n\t\t\tpublic void onStartup(ServletContext servletContext) {\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterConfigurationWithAnnotationAndDefaultDispatcherTypes {\n\n\t\t@Bean\n\t\t@FilterRegistration(name = \"test\")\n\t\tTestOncePerRequestFilter testFilter() {\n\t\t\treturn new TestOncePerRequestFilter();\n\t\t}\n\n\t\tstatic class TestOncePerRequestFilter extends OncePerRequestFilter {\n\n\t\t\t@Override\n\t\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\t\tFilterChain filterChain) {\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleInterfacesConfiguration {\n\n\t\t@Bean\n\t\tTestServletAndFilterAndListener testServletAndFilterAndListener() {\n\t\t\treturn new TestServletAndFilterAndListener();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestServletContextInitializer testServletContextInitializer() {\n\t\t\treturn new TestServletContextInitializer();\n\t\t}\n\n\t\t@Bean\n\t\tOtherTestServletContextInitializer otherTestServletContextInitializer() {\n\t\t\treturn new OtherTestServletContextInitializer();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpSessionIdListenerConfiguration {\n\n\t\t@Bean\n\t\tHttpSessionIdListener httpSessionIdListener() {\n\t\t\treturn (event, oldId) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class TestServlet extends HttpServlet implements ServletContextInitializer {\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) {\n\n\t\t}\n\n\t}\n\n\tstatic class OrderedTestServlet extends HttpServlet implements ServletContextInitializer, Ordered {\n\n\t\tstatic final int ORDER = 3;\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn ORDER;\n\t\t}\n\n\t}\n\n\tstatic class TestFilter implements Filter, ServletContextInitializer {\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void init(FilterConfig filterConfig) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\n\t\t}\n\n\t}\n\n\tstatic class TestServletContextInitializer implements ServletContextInitializer {\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) {\n\n\t\t}\n\n\t}\n\n\tstatic class OtherTestServletContextInitializer implements ServletContextInitializer {\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletListenerRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.EventListener;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextListener;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ServletListenerRegistrationBean}.\n *\n * @author Dave Syer\n */\n@ExtendWith(MockitoExtension.class)\nclass ServletListenerRegistrationBeanTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletContextListener listener;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletContext servletContext;\n\n\t@Test\n\tvoid startupWithDefaults() throws Exception {\n\t\tServletListenerRegistrationBean<ServletContextListener> bean = new ServletListenerRegistrationBean<>(\n\t\t\t\tthis.listener);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addListener(this.listener);\n\t}\n\n\t@Test\n\tvoid disable() throws Exception {\n\t\tServletListenerRegistrationBean<ServletContextListener> bean = new ServletListenerRegistrationBean<>(\n\t\t\t\tthis.listener);\n\t\tbean.setEnabled(false);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should(never()).addListener(any(ServletContextListener.class));\n\t}\n\n\t@Test\n\tvoid cannotRegisterUnsupportedType() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ServletListenerRegistrationBean<>(new EventListener() {\n\n\t\t\t}))\n\t\t\t.withMessageContaining(\"'listener' is not of a supported type\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/ServletRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\n\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.web.servlet.mock.MockServlet;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ServletRegistrationBean}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass ServletRegistrationBeanTests {\n\n\tprivate final MockServlet servlet = new MockServlet();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletContext servletContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletRegistration.Dynamic registration;\n\n\t@Test\n\tvoid startupWithDefaults() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addServlet(\"mockServlet\", this.servlet);\n\t\tthen(this.registration).should().setAsyncSupported(true);\n\t\tthen(this.registration).should().addMapping(\"/*\");\n\t}\n\n\t@Test\n\tvoid failsWithDoubleRegistration() {\n\t\tassertThatIllegalStateException().isThrownBy(this::doubleRegistration)\n\t\t\t.withMessage(\"Failed to register 'servlet double-registration' on \"\n\t\t\t\t\t+ \"the servlet context. Possibly already registered?\");\n\t}\n\n\tprivate void doubleRegistration() throws ServletException {\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet);\n\t\tbean.setName(\"double-registration\");\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(null);\n\t\tbean.onStartup(this.servletContext);\n\t}\n\n\t@Test\n\tvoid startupWithSpecifiedValues() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>();\n\t\tbean.setName(\"test\");\n\t\tbean.setServlet(this.servlet);\n\t\tbean.setAsyncSupported(false);\n\t\tbean.setInitParameters(Collections.singletonMap(\"a\", \"b\"));\n\t\tbean.addInitParameter(\"c\", \"d\");\n\t\tbean.setUrlMappings(new LinkedHashSet<>(Arrays.asList(\"/a\", \"/b\")));\n\t\tbean.addUrlMappings(\"/c\");\n\t\tbean.setLoadOnStartup(10);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addServlet(\"test\", this.servlet);\n\t\tthen(this.registration).should().setAsyncSupported(false);\n\t\tMap<String, String> expectedInitParameters = new HashMap<>();\n\t\texpectedInitParameters.put(\"a\", \"b\");\n\t\texpectedInitParameters.put(\"c\", \"d\");\n\t\tthen(this.registration).should().setInitParameters(expectedInitParameters);\n\t\tthen(this.registration).should().addMapping(\"/a\", \"/b\", \"/c\");\n\t\tthen(this.registration).should().setLoadOnStartup(10);\n\t}\n\n\t@Test\n\tvoid specificName() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>();\n\t\tbean.setName(\"specificName\");\n\t\tbean.setServlet(this.servlet);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addServlet(\"specificName\", this.servlet);\n\t}\n\n\t@Test\n\tvoid deducedName() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>();\n\t\tbean.setServlet(this.servlet);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should().addServlet(\"mockServlet\", this.servlet);\n\t}\n\n\t@Test\n\tvoid disable() throws Exception {\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>();\n\t\tbean.setServlet(this.servlet);\n\t\tbean.setEnabled(false);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should(never()).addServlet(\"mockServlet\", this.servlet);\n\t}\n\n\t@Test\n\tvoid setServletMustNotBeNull() {\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>();\n\t\tassertThatIllegalStateException().isThrownBy(() -> bean.onStartup(this.servletContext))\n\t\t\t.withMessageContaining(\"Unable to return description for null servlet\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createServletMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ServletRegistrationBean<MockServlet>(null))\n\t\t\t.withMessageContaining(\"'servlet' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setMappingMustNotBeNull() {\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.setUrlMappings(null))\n\t\t\t.withMessageContaining(\"'urlMappings' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createMappingMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ServletRegistrationBean<>(this.servlet, (String[]) null))\n\t\t\t.withMessageContaining(\"'urlMappings' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addMappingMustNotBeNull() {\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> bean.addUrlMappings((String[]) null))\n\t\t\t.withMessageContaining(\"'urlMappings' must not be null\");\n\t}\n\n\t@Test\n\tvoid setMappingReplacesValue() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet, \"/a\", \"/b\");\n\t\tbean.setUrlMappings(new LinkedHashSet<>(Arrays.asList(\"/c\", \"/d\")));\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should().addMapping(\"/c\", \"/d\");\n\t}\n\n\t@Test\n\tvoid modifyInitParameters() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet, \"/a\", \"/b\");\n\t\tbean.addInitParameter(\"a\", \"b\");\n\t\tbean.getInitParameters().put(\"a\", \"c\");\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should().setInitParameters(Collections.singletonMap(\"a\", \"c\"));\n\t}\n\n\t@Test\n\tvoid withoutDefaultMappings() throws Exception {\n\t\tgiven(this.servletContext.addServlet(anyString(), any(Servlet.class))).willReturn(this.registration);\n\t\tServletRegistrationBean<MockServlet> bean = new ServletRegistrationBean<>(this.servlet, false);\n\t\tbean.onStartup(this.servletContext);\n\t\tthen(this.registration).should(never()).addMapping(any(String[].class));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/TestServletAndFilterAndListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletRequestListener;\nimport jakarta.servlet.ServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nclass TestServletAndFilterAndListener implements Servlet, Filter, ServletRequestListener {\n\n\t@Override\n\tpublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)\n\t\t\tthrows IOException, ServletException {\n\n\t}\n\n\t@Override\n\tpublic void init(ServletConfig servletConfig) throws ServletException {\n\n\t}\n\n\t@Override\n\tpublic @Nullable ServletConfig getServletConfig() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void service(ServletRequest servletRequest, ServletResponse servletResponse)\n\t\t\tthrows ServletException, IOException {\n\n\t}\n\n\t@Override\n\tpublic @Nullable String getServletInfo() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/ErrorPageFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport jakarta.servlet.RequestDispatcher;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpServletResponseWrapper;\nimport org.apache.catalina.connector.ClientAbortException;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.web.MockFilterChain;\nimport org.springframework.mock.web.MockFilterConfig;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockRequestDispatcher;\nimport org.springframework.web.bind.MissingServletRequestParameterException;\nimport org.springframework.web.context.request.async.DeferredResult;\nimport org.springframework.web.context.request.async.StandardServletAsyncWebRequest;\nimport org.springframework.web.context.request.async.WebAsyncManager;\nimport org.springframework.web.context.request.async.WebAsyncUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ErrorPageFilter}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ErrorPageFilterTests {\n\n\tprivate final ErrorPageFilter filter = new ErrorPageFilter();\n\n\tprivate final DispatchRecordingMockHttpServletRequest request = new DispatchRecordingMockHttpServletRequest();\n\n\tprivate final MockHttpServletResponse response = new MockHttpServletResponse();\n\n\tprivate MockFilterChain chain = new TestFilterChain((request, response, chain) -> {\n\t});\n\n\t@Test\n\tvoid notAnError() throws Exception {\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat(getChainResponse().getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isNull();\n\t}\n\n\t@Test\n\tvoid notAnErrorButNotOK() throws Exception {\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tresponse.setStatus(201);\n\t\t\tchain.call();\n\t\t\tresponse.flushBuffer();\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(getChainResponse().getStatus()).isEqualTo(201);\n\t\tassertThat(((HttpServletResponse) getChainResponse().getResponse()).getStatus()).isEqualTo(201);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid unauthorizedWithErrorPath() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> response.sendError(401, \"UNAUTHORIZED\"));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tHttpServletResponseWrapper wrapper = getChainResponse();\n\t\tassertThat(wrapper.getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(wrapper.getStatus()).isEqualTo(401);\n\t\t// The real response has to be 401 as well...\n\t\tassertThat(this.response.getStatus()).isEqualTo(401);\n\t\tassertThat(this.response.getForwardedUrl()).isEqualTo(\"/error\");\n\t}\n\n\t@Test\n\tvoid responseCommitted() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.response.setCommitted(true);\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, \"BAD\"));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(400);\n\t\tassertThat(this.response.getForwardedUrl()).isNull();\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid responseCommittedWhenFromClientAbortException(CapturedOutput output) throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.response.setCommitted(true);\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new ClientAbortException();\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(output).doesNotContain(\"Cannot forward\");\n\t}\n\n\t@Test\n\tvoid responseUncommittedWithoutErrorPage() throws Exception {\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, \"BAD\"));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(400);\n\t\tassertThat(this.response.getForwardedUrl()).isNull();\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid oncePerRequest() throws Exception {\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tresponse.sendError(400, \"BAD\");\n\t\t\tassertThat(request.getAttribute(\"FILTER.FILTERED\")).isNotNull();\n\t\t});\n\t\tthis.filter.init(new MockFilterConfig(\"FILTER\"));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t}\n\n\t@Test\n\tvoid globalError() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, \"BAD\"));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(400);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(400);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo(\"BAD\");\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo(\"/test/path\");\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isEqualTo(\"/error\");\n\t}\n\n\t@Test\n\tvoid statusError() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, \"/400\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> response.sendError(400, \"BAD\"));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(400);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(400);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo(\"BAD\");\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo(\"/test/path\");\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isEqualTo(\"/400\");\n\t}\n\n\t@Test\n\tvoid statusErrorWithCommittedResponse() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, \"/400\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tresponse.sendError(400, \"BAD\");\n\t\t\tresponse.flushBuffer();\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(400);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isNull();\n\t}\n\n\t@Test\n\tvoid exceptionError() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(RuntimeException.class, \"/500\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new RuntimeException(\"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo(\"BAD\");\n\t\tMap<String, Object> requestAttributes = getAttributesForDispatch(\"/500\");\n\t\tassertThat(requestAttributes).containsEntry(RequestDispatcher.ERROR_EXCEPTION_TYPE, RuntimeException.class);\n\t\tassertThat(requestAttributes.get(RequestDispatcher.ERROR_EXCEPTION)).isInstanceOf(RuntimeException.class);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo(\"/test/path\");\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isEqualTo(\"/500\");\n\t}\n\n\t@Test\n\tvoid exceptionErrorWithCommittedResponse() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(RuntimeException.class, \"/500\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tresponse.flushBuffer();\n\t\t\tthrow new RuntimeException(\"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.response.getForwardedUrl()).isNull();\n\t}\n\n\t@Test\n\tvoid statusCode() throws Exception {\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> assertThat(response.getStatus()).isEqualTo(200));\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid subClassExceptionError() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(RuntimeException.class, \"/500\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new IllegalStateException(\"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo(\"BAD\");\n\t\tMap<String, Object> requestAttributes = getAttributesForDispatch(\"/500\");\n\t\tassertThat(requestAttributes).containsEntry(RequestDispatcher.ERROR_EXCEPTION_TYPE,\n\t\t\t\tIllegalStateException.class);\n\t\tassertThat(requestAttributes.get(RequestDispatcher.ERROR_EXCEPTION)).isInstanceOf(IllegalStateException.class);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo(\"/test/path\");\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid responseIsNotCommittedWhenRequestIsAsync() throws Exception {\n\t\tthis.request.setAsyncStarted(true);\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isFalse();\n\t}\n\n\t@Test\n\tvoid responseIsCommittedWhenRequestIsAsyncAndExceptionIsThrown() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.request.setAsyncStarted(true);\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new RuntimeException(\"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid responseIsCommittedWhenRequestIsAsyncAndStatusIs400Plus() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.request.setAsyncStarted(true);\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tresponse.sendError(400, \"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid responseIsNotCommittedDuringAsyncDispatch() throws Exception {\n\t\tsetUpAsyncDispatch();\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isFalse();\n\t}\n\n\t@Test\n\tvoid responseIsCommittedWhenExceptionIsThrownDuringAsyncDispatch() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tsetUpAsyncDispatch();\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new RuntimeException(\"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid responseIsCommittedWhenStatusIs400PlusDuringAsyncDispatch() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tsetUpAsyncDispatch();\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tresponse.sendError(400, \"BAD\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.chain.getRequest()).isEqualTo(this.request);\n\t\tassertThat((getChainResponse()).getResponse()).isEqualTo(this.response);\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t}\n\n\t@Test\n\tvoid responseIsNotFlushedIfStatusIsLessThan400AndItHasAlreadyBeenCommitted() throws Exception {\n\t\tHttpServletResponse committedResponse = mock(HttpServletResponse.class);\n\t\tgiven(committedResponse.isCommitted()).willReturn(true);\n\t\tgiven(committedResponse.getStatus()).willReturn(200);\n\t\tthis.filter.doFilter(this.request, committedResponse, this.chain);\n\t\tthen(committedResponse).should(never()).flushBuffer();\n\t}\n\n\t@Test\n\tvoid errorMessageForRequestWithoutPathInfo(CapturedOutput output) throws IOException, ServletException {\n\t\tthis.request.setServletPath(\"/test\");\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new RuntimeException();\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(output).contains(\"request [/test]\");\n\t}\n\n\t@Test\n\tvoid errorMessageForRequestWithPathInfo(CapturedOutput output) throws IOException, ServletException {\n\t\tthis.request.setServletPath(\"/test\");\n\t\tthis.request.setPathInfo(\"/alpha\");\n\t\tthis.filter.addErrorPages(new ErrorPage(\"/error\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new RuntimeException();\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(output).contains(\"request [/test/alpha]\");\n\t}\n\n\t@Test\n\tvoid servletExceptionIsUnwrapped() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(RuntimeException.class, \"/500\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new ServletException(\"Wrapper\", new RuntimeException(\"BAD\"));\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE)).isEqualTo(\"BAD\");\n\t\tMap<String, Object> requestAttributes = getAttributesForDispatch(\"/500\");\n\t\tassertThat(requestAttributes).containsEntry(RequestDispatcher.ERROR_EXCEPTION_TYPE, RuntimeException.class);\n\t\tassertThat(requestAttributes.get(RequestDispatcher.ERROR_EXCEPTION)).isInstanceOf(RuntimeException.class);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo(\"/test/path\");\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isEqualTo(\"/500\");\n\t}\n\n\t@Test\n\tvoid servletExceptionWithNoCause() throws Exception {\n\t\tthis.filter.addErrorPages(new ErrorPage(MissingServletRequestParameterException.class, \"/500\"));\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tchain.call();\n\t\t\tthrow new MissingServletRequestParameterException(\"test\", \"string\");\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat((getChainResponse()).getStatus()).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE)).isEqualTo(500);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_MESSAGE))\n\t\t\t.isEqualTo(\"Required request parameter 'test' for method parameter type string is not present\");\n\t\tMap<String, Object> requestAttributes = getAttributesForDispatch(\"/500\");\n\t\tassertThat(requestAttributes).containsEntry(RequestDispatcher.ERROR_EXCEPTION_TYPE,\n\t\t\t\tMissingServletRequestParameterException.class);\n\t\tassertThat(requestAttributes.get(RequestDispatcher.ERROR_EXCEPTION))\n\t\t\t.isInstanceOf(MissingServletRequestParameterException.class);\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)).isNull();\n\t\tassertThat(this.request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI)).isEqualTo(\"/test/path\");\n\t\tassertThat(this.response.isCommitted()).isTrue();\n\t\tassertThat(this.response.getForwardedUrl()).isEqualTo(\"/500\");\n\t}\n\n\t@Test\n\tvoid whenErrorIsSentAndWriterIsFlushedErrorIsSentToTheClient() throws Exception {\n\t\tthis.chain = new TestFilterChain((request, response, chain) -> {\n\t\t\tresponse.sendError(400);\n\t\t\tresponse.getWriter().flush();\n\t\t});\n\t\tthis.filter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.response.getStatus()).isEqualTo(400);\n\t}\n\n\tprivate void setUpAsyncDispatch() throws Exception {\n\t\tthis.request.setAsyncSupported(true);\n\t\tthis.request.setAsyncStarted(true);\n\t\tDeferredResult<String> result = new DeferredResult<>();\n\t\tWebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(this.request);\n\t\tasyncManager.setAsyncWebRequest(new StandardServletAsyncWebRequest(this.request, this.response));\n\t\tasyncManager.startDeferredResultProcessing(result);\n\t}\n\n\tprivate Map<String, Object> getAttributesForDispatch(String path) {\n\t\treturn this.request.getDispatcher(path).getRequestAttributes();\n\t}\n\n\tprivate HttpServletResponseWrapper getChainResponse() {\n\t\tHttpServletResponseWrapper response = (HttpServletResponseWrapper) this.chain.getResponse();\n\t\tassertThat(response).isNotNull();\n\t\treturn response;\n\t}\n\n\tstatic class TestFilterChain extends MockFilterChain {\n\n\t\tprivate final FilterHandler handler;\n\n\t\tTestFilterChain(FilterHandler handler) {\n\t\t\tthis.handler = handler;\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {\n\t\t\tAtomicBoolean called = new AtomicBoolean();\n\t\t\tChain chain = () -> {\n\t\t\t\tif (called.compareAndSet(false, true)) {\n\t\t\t\t\tsuper.doFilter(request, response);\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis.handler.handle((HttpServletRequest) request, (HttpServletResponse) response, chain);\n\t\t\tchain.call();\n\t\t}\n\n\t}\n\n\t@FunctionalInterface\n\tinterface FilterHandler {\n\n\t\tvoid handle(HttpServletRequest request, HttpServletResponse response, Chain chain)\n\t\t\t\tthrows IOException, ServletException;\n\n\t}\n\n\t@FunctionalInterface\n\tinterface Chain {\n\n\t\tvoid call() throws IOException, ServletException;\n\n\t}\n\n\tprivate static final class DispatchRecordingMockHttpServletRequest extends MockHttpServletRequest {\n\n\t\tprivate final Map<String, AttributeCapturingRequestDispatcher> dispatchers = new HashMap<>();\n\n\t\tprivate DispatchRecordingMockHttpServletRequest() {\n\t\t\tsuper(\"GET\", \"/test/path\");\n\t\t}\n\n\t\t@Override\n\t\tpublic RequestDispatcher getRequestDispatcher(String path) {\n\t\t\tAttributeCapturingRequestDispatcher dispatcher = new AttributeCapturingRequestDispatcher(path);\n\t\t\tthis.dispatchers.put(path, dispatcher);\n\t\t\treturn dispatcher;\n\t\t}\n\n\t\tprivate AttributeCapturingRequestDispatcher getDispatcher(String path) {\n\t\t\tAttributeCapturingRequestDispatcher dispatcher = this.dispatchers.get(path);\n\t\t\tassertThat(dispatcher).isNotNull();\n\t\t\treturn dispatcher;\n\t\t}\n\n\t\tprivate static final class AttributeCapturingRequestDispatcher extends MockRequestDispatcher {\n\n\t\t\tprivate final Map<String, Object> requestAttributes = new HashMap<>();\n\n\t\t\tprivate AttributeCapturingRequestDispatcher(String resource) {\n\t\t\t\tsuper(resource);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void forward(ServletRequest request, ServletResponse response) {\n\t\t\t\tcaptureAttributes(request);\n\t\t\t\tsuper.forward(request, response);\n\t\t\t}\n\n\t\t\tprivate void captureAttributes(ServletRequest request) {\n\t\t\t\tEnumeration<String> names = request.getAttributeNames();\n\t\t\t\twhile (names.hasMoreElements()) {\n\t\t\t\t\tString name = names.nextElement();\n\t\t\t\t\tthis.requestAttributes.put(name, request.getAttribute(name));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate Map<String, Object> getRequestAttributes() {\n\t\t\t\treturn this.requestAttributes;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/ServletContextApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ServletContextApplicationContextInitializer}.\n *\n * @author Andy Wilkinson\n */\nclass ServletContextApplicationContextInitializerTests {\n\n\tprivate final ServletContext servletContext = mock(ServletContext.class);\n\n\tprivate final ConfigurableWebApplicationContext applicationContext = mock(ConfigurableWebApplicationContext.class);\n\n\t@Test\n\tvoid servletContextIsSetOnTheApplicationContext() {\n\t\tnew ServletContextApplicationContextInitializer(this.servletContext).initialize(this.applicationContext);\n\t\tthen(this.applicationContext).should().setServletContext(this.servletContext);\n\t}\n\n\t@Test\n\tvoid applicationContextIsNotStoredInServletContextByDefault() {\n\t\tnew ServletContextApplicationContextInitializer(this.servletContext).initialize(this.applicationContext);\n\t\tthen(this.servletContext).should(never())\n\t\t\t.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.applicationContext);\n\t}\n\n\t@Test\n\tvoid applicationContextCanBeStoredInServletContext() {\n\t\tnew ServletContextApplicationContextInitializer(this.servletContext, true).initialize(this.applicationContext);\n\t\tthen(this.servletContext).should()\n\t\t\t.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/org/springframework/boot/web/servlet/support/SpringBootServletInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Map;\nimport java.util.Vector;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterRegistration.Dynamic;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.servlet.ServletException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.logging.LoggingApplicationListener;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.boot.web.error.ErrorPageRegistrarBeanPostProcessor;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringBootServletInitializer}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Jay Choi\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SpringBootServletInitializerTests {\n\n\tprivate final ServletContext servletContext = new MockServletContext();\n\n\tprivate @Nullable SpringApplication application;\n\n\t@AfterEach\n\tvoid verifyLoggingOutput(CapturedOutput output) {\n\t\tassertThat(output).doesNotContain(StandardServletEnvironment.class.getSimpleName());\n\t}\n\n\t@Test\n\tvoid failsWithoutConfigure() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MockSpringBootServletInitializer().createRootApplicationContext(this.servletContext))\n\t\t\t.withMessageContaining(\"No SpringApplication sources have been defined\");\n\t}\n\n\t@Test\n\tvoid withConfigurationAnnotation() {\n\t\tnew WithConfigurationAnnotation().createRootApplicationContext(this.servletContext);\n\t\tassertThat(this.application).isNotNull();\n\t\tassertThat(this.application.getAllSources()).containsOnly(WithConfigurationAnnotation.class,\n\t\t\t\tErrorPageFilterConfiguration.class);\n\t}\n\n\t@Test\n\tvoid withConfiguredSource() {\n\t\tnew WithConfiguredSource().createRootApplicationContext(this.servletContext);\n\t\tassertThat(this.application).isNotNull();\n\t\tassertThat(this.application.getAllSources()).containsOnly(Config.class, ErrorPageFilterConfiguration.class);\n\t}\n\n\t@Test\n\tvoid applicationBuilderCanBeCustomized() {\n\t\tCustomSpringBootServletInitializer servletInitializer = new CustomSpringBootServletInitializer();\n\t\tservletInitializer.createRootApplicationContext(this.servletContext);\n\t\tassertThat(servletInitializer.applicationBuilder.built).isTrue();\n\t}\n\n\t@Test\n\tvoid mainClassHasSensibleDefault() {\n\t\tnew WithConfigurationAnnotation().createRootApplicationContext(this.servletContext);\n\t\tassertThat(this.application).hasFieldOrPropertyWithValue(\"mainApplicationClass\",\n\t\t\t\tWithConfigurationAnnotation.class);\n\t}\n\n\t@Test\n\tvoid shutdownHooksAreNotRegistered() throws ServletException {\n\t\tnew WithConfigurationAnnotation().onStartup(this.servletContext);\n\t\tassertThat(this.servletContext.getAttribute(LoggingApplicationListener.REGISTER_SHUTDOWN_HOOK_PROPERTY))\n\t\t\t.isEqualTo(false);\n\t\tassertThat(this.application).isNotNull();\n\t\tObject properties = ReflectionTestUtils.getField(this.application, \"properties\");\n\t\tassertThat(properties).hasFieldOrPropertyWithValue(\"registerShutdownHook\", false);\n\t}\n\n\t@Test\n\tvoid errorPageFilterRegistrationCanBeDisabled() {\n\t\ttry (AbstractApplicationContext context = (AbstractApplicationContext) new WithErrorPageFilterNotRegistered()\n\t\t\t.createRootApplicationContext(this.servletContext)) {\n\t\t\tassertThat(context).isNotNull();\n\t\t\tassertThat(context.getBeansOfType(ErrorPageFilter.class)).isEmpty();\n\t\t\tassertThat(context.getBeansOfType(ErrorPageRegistrarBeanPostProcessor.class)).isEmpty();\n\t\t}\n\t}\n\n\t@Test\n\tvoid errorPageRegistrarBeanPostProcessorIsRegistered() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(Collections.emptyEnumeration());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\ttry (AbstractApplicationContext context = (AbstractApplicationContext) new DefaultSpringBootServletInitializer()\n\t\t\t.createRootApplicationContext(servletContext)) {\n\t\t\tassertThat(context).isNotNull();\n\t\t\tassertThat(context.getBeansOfType(ErrorPageRegistrarBeanPostProcessor.class)).hasSize(1);\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid errorPageFilterIsRegisteredWithNearHighestPrecedence() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(Collections.emptyEnumeration());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\ttry (AbstractApplicationContext context = (AbstractApplicationContext) new DefaultSpringBootServletInitializer()\n\t\t\t.createRootApplicationContext(servletContext)) {\n\t\t\tassertThat(context).isNotNull();\n\t\t\tMap<String, FilterRegistrationBean> registrations = context.getBeansOfType(FilterRegistrationBean.class);\n\t\t\tassertThat(registrations).hasSize(1);\n\t\t\tFilterRegistrationBean errorPageFilterRegistration = registrations.get(\"errorPageFilterRegistration\");\n\t\t\tassertThat(errorPageFilterRegistration).isNotNull();\n\t\t\tassertThat(errorPageFilterRegistration.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE + 1);\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid errorPageFilterIsRegisteredForRequestAndAsyncDispatch() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(Collections.emptyEnumeration());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\ttry (AbstractApplicationContext context = (AbstractApplicationContext) new DefaultSpringBootServletInitializer()\n\t\t\t.createRootApplicationContext(servletContext)) {\n\t\t\tassertThat(context).isNotNull();\n\t\t\tMap<String, FilterRegistrationBean> registrations = context.getBeansOfType(FilterRegistrationBean.class);\n\t\t\tassertThat(registrations).hasSize(1);\n\t\t\tFilterRegistrationBean errorPageFilterRegistration = registrations.get(\"errorPageFilterRegistration\");\n\t\t\tassertThat(errorPageFilterRegistration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\t\tEnumSet.of(DispatcherType.ASYNC, DispatcherType.REQUEST));\n\t\t}\n\t}\n\n\t@Test\n\tvoid executableWarThatUsesServletInitializerDoesNotHaveErrorPageFilterConfigured() {\n\t\ttry (ConfigurableApplicationContext context = new SpringApplication(DefaultSpringBootServletInitializer.class)\n\t\t\t.run()) {\n\t\t\tassertThat(context.getBeansOfType(ErrorPageFilter.class)).isEmpty();\n\t\t}\n\t}\n\n\t@Test\n\tvoid environmentIsConfiguredWithStandardServletEnvironment() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames())\n\t\t\t.willReturn(Collections.enumeration(Collections.singletonList(\"servlet.init.test\")));\n\t\tgiven(servletContext.getInitParameter(\"servlet.init.test\")).willReturn(\"from-servlet-context\");\n\t\tgiven(servletContext.getAttributeNames())\n\t\t\t.willReturn(Collections.enumeration(Collections.singletonList(\"servlet.attribute.test\")));\n\t\tgiven(servletContext.getAttribute(\"servlet.attribute.test\")).willReturn(\"also-from-servlet-context\");\n\t\ttry (ConfigurableApplicationContext context = (ConfigurableApplicationContext) new RegularSpringBootServletInitializer()\n\t\t\t.createRootApplicationContext(servletContext)) {\n\t\t\tassertThat(context).isNotNull();\n\t\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\t\tassertThat(environment).isInstanceOf(StandardServletEnvironment.class);\n\t\t\tassertThat(environment.getClass().getName()).endsWith(\"ApplicationServletEnvironment\");\n\t\t\tassertThat(environment.getPropertySources()).map(PropertySource::getName)\n\t\t\t\t.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\t\tStandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME);\n\t\t\tassertThat(environment.getProperty(\"servlet.init.test\")).isEqualTo(\"from-servlet-context\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid servletContextPropertySourceIsAvailablePriorToRefresh() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames())\n\t\t\t.willReturn(Collections.enumeration(Collections.singletonList(\"spring.profiles.active\")));\n\t\tgiven(servletContext.getInitParameter(\"spring.profiles.active\")).willReturn(\"from-servlet-context\");\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\ttry (ConfigurableApplicationContext context = (ConfigurableApplicationContext) new PropertySourceVerifyingSpringBootServletInitializer()\n\t\t\t.createRootApplicationContext(servletContext)) {\n\t\t\tassertThat(context).isNotNull();\n\t\t\tassertThat(context.getEnvironment().getActiveProfiles()).containsExactly(\"from-servlet-context\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenServletContextIsDestroyedThenJdbcDriversAreDeregistered() throws ServletException {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(new Vector<String>().elements());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(new Vector<String>().elements());\n\t\tAtomicBoolean driversDeregistered = new AtomicBoolean();\n\t\tnew SpringBootServletInitializer() {\n\n\t\t\t@Override\n\t\t\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\t\t\treturn builder.sources(Config.class);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected void deregisterJdbcDrivers(ServletContext servletContext) {\n\t\t\t\tdriversDeregistered.set(true);\n\t\t\t}\n\n\t\t}.onStartup(servletContext);\n\t\tArgumentCaptor<ServletContextListener> captor = ArgumentCaptor.forClass(ServletContextListener.class);\n\t\tthen(servletContext).should().addListener(captor.capture());\n\t\tcaptor.getValue().contextDestroyed(new ServletContextEvent(servletContext));\n\t\tassertThat(driversDeregistered).isTrue();\n\t}\n\n\t@Test\n\tvoid whenServletContextIsDestroyedThenReactorSchedulersAreShutDown() throws ServletException {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.addFilter(any(), any(Filter.class))).willReturn(mock(Dynamic.class));\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(new Vector<String>().elements());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(new Vector<String>().elements());\n\t\tAtomicBoolean schedulersShutDown = new AtomicBoolean();\n\t\tnew SpringBootServletInitializer() {\n\n\t\t\t@Override\n\t\t\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\t\t\treturn builder.sources(Config.class);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected void shutDownSharedReactorSchedulers(ServletContext servletContext) {\n\t\t\t\tschedulersShutDown.set(true);\n\t\t\t}\n\n\t\t}.onStartup(servletContext);\n\t\tArgumentCaptor<ServletContextListener> captor = ArgumentCaptor.forClass(ServletContextListener.class);\n\t\tthen(servletContext).should().addListener(captor.capture());\n\t\tcaptor.getValue().contextDestroyed(new ServletContextEvent(servletContext));\n\t\tassertThat(schedulersShutDown).isTrue();\n\t}\n\n\tstatic class PropertySourceVerifyingSpringBootServletInitializer extends SpringBootServletInitializer {\n\n\t\t@Override\n\t\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\t\treturn builder.sources(TestApp.class).listeners(new PropertySourceVerifyingApplicationListener());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestApp {\n\n\t}\n\n\tprivate class MockSpringBootServletInitializer extends SpringBootServletInitializer {\n\n\t\t@Override\n\t\tprotected @Nullable WebApplicationContext run(SpringApplication application) {\n\t\t\tSpringBootServletInitializerTests.this.application = application;\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate final class CustomSpringBootServletInitializer extends MockSpringBootServletInitializer {\n\n\t\tprivate final CustomSpringApplicationBuilder applicationBuilder = new CustomSpringApplicationBuilder();\n\n\t\t@Override\n\t\tprotected SpringApplicationBuilder createSpringApplicationBuilder() {\n\t\t\treturn this.applicationBuilder;\n\t\t}\n\n\t\t@Override\n\t\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\t\treturn application.sources(Config.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic class WithConfigurationAnnotation extends MockSpringBootServletInitializer {\n\n\t}\n\n\tpublic class WithConfiguredSource extends MockSpringBootServletInitializer {\n\n\t\t@Override\n\t\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\t\treturn application.sources(Config.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DefaultSpringBootServletInitializer extends SpringBootServletInitializer {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WithErrorPageFilterNotRegistered extends SpringBootServletInitializer {\n\n\t\tWithErrorPageFilterNotRegistered() {\n\t\t\tsetRegisterErrorPageFilter(false);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\tstatic class CustomSpringApplicationBuilder extends SpringApplicationBuilder {\n\n\t\tprivate boolean built;\n\n\t\t@Override\n\t\tpublic SpringApplication build() {\n\t\t\tthis.built = true;\n\t\t\treturn super.build();\n\t\t}\n\n\t}\n\n\tstatic class RegularSpringBootServletInitializer extends SpringBootServletInitializer {\n\n\t\t@Override\n\t\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\t\treturn builder.sources(TestApp.class);\n\t\t}\n\n\t}\n\n\tprivate static final class PropertySourceVerifyingApplicationListener\n\t\t\timplements ApplicationListener<ApplicationEnvironmentPreparedEvent> {\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\t\tPropertySource<?> propertySource = event.getEnvironment()\n\t\t\t\t.getPropertySources()\n\t\t\t\t.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME);\n\t\t\tassertThat(propertySource).isNotNull();\n\t\t\tassertThat(propertySource.getProperty(\"spring.profiles.active\")).isEqualTo(\"from-servlet-context\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/sampleconfig/MyComponentInPackageWithoutDot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sampleconfig;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyComponentInPackageWithoutDot {\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/java/sampleconfig/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage sampleconfig;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/SpringApplicationExtensionsTests.kt",
    "content": "/*\n * Copyright 2002-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.Assertions.assertThatIllegalStateException\nimport org.junit.jupiter.api.Test\n\nimport org.springframework.beans.factory.getBean\nimport org.springframework.boot.kotlinsample.TestKotlinApplication\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.core.env.StandardEnvironment\n\n/**\n * Tests for `SpringApplicationExtensions`.\n *\n * @author Sebastien Deleuze\n */\nclass SpringApplicationExtensionsTests {\n\n\t@Test\n\tfun `Kotlin runApplication() top level function`() {\n\t\tval context = runApplication<ExampleConfig>()\n\t\tassertThat(context).isNotNull()\n\t}\n\n\t@Test\n\tfun `Kotlin runApplication() top level function with a custom environment`() {\n\t\tval environment = StandardEnvironment()\n\t\tval context = runApplication<ExampleConfig> {\n\t\t\tsetEnvironment(environment)\n\t\t}\n\t\tassertThat(context).isNotNull()\n\t\tassertThat(environment).isEqualTo(context.environment)\n\t}\n\n\t@Test\n\tfun `Kotlin runApplication(arg1, arg2) top level function`() {\n\t\tval context = runApplication<ExampleConfig>(\"--debug\", \"spring\", \"boot\")\n\t\tval args = context.getBean<ApplicationArguments>()\n\t\tassertThat(args.nonOptionArgs.toTypedArray()).containsExactly(\"spring\", \"boot\")\n\t\tassertThat(args.containsOption(\"debug\")).isTrue()\n\t}\n\n\t@Test\n\tfun `Kotlin runApplication(arg1, arg2) top level function with a custom environment`() {\n\t\tval environment = StandardEnvironment()\n\t\tval context = runApplication<ExampleConfig>(\"--debug\", \"spring\", \"boot\") {\n\t\t\tsetEnvironment(environment)\n\t\t}\n\t\tval args = context.getBean<ApplicationArguments>()\n\t\tassertThat(args.nonOptionArgs.toTypedArray()).containsExactly(\"spring\", \"boot\")\n\t\tassertThat(args.containsOption(\"debug\")).isTrue()\n\t\tassertThat(environment).isEqualTo(context.environment)\n\t}\n\n\t@Test\n\tfun `Kotlin fromApplication() top level function`() {\n\t\tval context = fromApplication<TestKotlinApplication>().with(ExampleConfig::class).run().applicationContext\n\t\tassertThat(context.getBean<ExampleBean>()).isNotNull()\n\t}\n\n\t@Test\n\tfun `Kotlin fromApplication() top level function with multiple sources`() {\n\t\tval context = fromApplication<TestKotlinApplication>()\n\t\t\t\t.with(ExampleConfig::class, AnotherExampleConfig::class).run().applicationContext\n\t\tassertThat(context.getBean<ExampleBean>()).isNotNull()\n\t\tassertThat(context.getBean<AnotherExampleBean>()).isNotNull()\n\t}\n\n\t@Test\n\tfun `Kotlin fromApplication() top level function when no main`() {\n\t\tassertThatIllegalStateException().isThrownBy { fromApplication<ExampleConfig>().run() }\n\t\t\t.withMessage(\"Unable to use 'fromApplication' with \" +\n\t\t\t\t\t\"org.springframework.boot.SpringApplicationExtensionsTests.ExampleConfig\")\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tinternal open class ExampleConfig {\n\n\t\t@Bean\n\t\topen fun exampleBean(): ExampleBean {\n\t\t\treturn ExampleBean()\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tinternal open class AnotherExampleConfig {\n\n\t\t@Bean\n\t\topen fun anotherExampleBean(): AnotherExampleBean {\n\t\t\treturn AnotherExampleBean()\n\t\t}\n\n\t}\n\n\tclass ExampleBean {\n\n\t}\n\n\tclass AnotherExampleBean {\n\n\t}\n\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/context/properties/KotlinConfigurationPropertiesBeanRegistrarTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory\nimport org.springframework.boot.context.properties.bind.BindMethod\n\n/**\n * Tests for `ConfigurationPropertiesBeanRegistrar`.\n *\n * @author Stephane Nicoll\n */\n@Suppress(\"unused\")\nclass KotlinConfigurationPropertiesBeanRegistrarTests {\n\n\tprivate val beanFactory = DefaultListableBeanFactory()\n\n\tprivate val registrar = ConfigurationPropertiesBeanRegistrar(beanFactory)\n\n\t@Test\n\tfun `type with primary constructor and no autowired should register value object configuration properties`() {\n\t\tthis.registrar.register(BarProperties::class.java)\n\t\tval beanDefinition = this.beanFactory.getBeanDefinition(\n\t\t\t\t\"bar-org.springframework.boot.context.properties.KotlinConfigurationPropertiesBeanRegistrarTests\\$BarProperties\")\n\t\tassertThat(beanDefinition.hasAttribute(BindMethod::class.java.name)).isTrue()\n\t\tassertThat(beanDefinition.getAttribute(BindMethod::class.java.name)).isEqualTo(BindMethod.VALUE_OBJECT)\n\t}\n\n\t@Test\n\tfun `type with no primary constructor should register java bean configuration properties`() {\n\t\tthis.registrar.register(BingProperties::class.java)\n\t\tval beanDefinition = this.beanFactory.getBeanDefinition(\n\t\t\t\t\"bing-org.springframework.boot.context.properties.KotlinConfigurationPropertiesBeanRegistrarTests\\$BingProperties\")\n\t\tassertThat(beanDefinition.hasAttribute(BindMethod::class.java.name)).isTrue()\n\t\tassertThat(beanDefinition.getAttribute(BindMethod::class.java.name)).isEqualTo(BindMethod.JAVA_BEAN)\n\t}\n\n\t@ConfigurationProperties(\"foo\")\n\tclass FooProperties\n\n\t@ConfigurationProperties(\"bar\")\n\tclass BarProperties(val name: String?, val counter: Int = 42)\n\n\t@ConfigurationProperties(\"bing\")\n\tclass BingProperties {\n\n\t\tconstructor()\n\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String)\n\n\t}\n\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/context/properties/KotlinConfigurationPropertiesTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties\n\nimport org.junit.jupiter.api.AfterEach\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry\nimport org.springframework.beans.factory.support.RootBeanDefinition\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.context.annotation.Import\nimport org.springframework.test.context.support.TestPropertySourceUtils\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.springframework.boot.context.properties.bind.Name\n\n/**\n * Tests for {@link ConfigurationProperties @ConfigurationProperties}-annotated beans.\n *\n * @author Madhura Bhave\n * @author Lasse Wulff\n */\nclass KotlinConfigurationPropertiesTests {\n\n\tprivate var context = AnnotationConfigApplicationContext()\n\n\t@AfterEach\n\tfun cleanUp() {\n\t\tthis.context.close()\n\t}\n\n\t@Test //gh-18652\n\tfun `type with constructor binding and existing singleton should not fail`() {\n\t\tval beanFactory = this.context.beanFactory\n\t\t(beanFactory as BeanDefinitionRegistry).registerBeanDefinition(\"foo\",\n\t\t\t\tRootBeanDefinition(BingProperties::class.java))\n\t\tbeanFactory.registerSingleton(\"foo\", BingProperties(\"\"))\n\t\tthis.context.register(EnableConfigProperties::class.java)\n\t\tthis.context.refresh()\n\t}\n\n\t@Test\n\tfun `type with constructor bound lateinit property can be bound`() {\n\t\tthis.context.register(EnableLateInitProperties::class.java)\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, \"lateinit.inner.value=alpha\")\n\t\tthis.context.refresh()\n\t\tassertThat(this.context.getBean(LateInitProperties::class.java).inner.value).isEqualTo(\"alpha\")\n\t}\n\n\t@Test\n\tfun `renamed property can be bound`() {\n\t\tthis.context.register(EnableRenamedProperties::class.java)\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, \"renamed.var=beta\")\n\t\tthis.context.refresh()\n\t\tassertThat(this.context.getBean(RenamedProperties::class.java).bar).isEqualTo(\"beta\")\n\t}\n\n\t@Test\n\tfun `type with constructor bound lateinit property with default can be bound`() {\n\t\tthis.context.register(EnableLateInitPropertiesWithDefault::class.java)\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, \"lateinit-with-default.inner.bravo=two\")\n\t\tthis.context.refresh()\n\t\tval properties = this.context.getBean(LateInitPropertiesWithDefault::class.java)\n\t\tassertThat(properties.inner.alpha).isEqualTo(\"apple\")\n\t\tassertThat(properties.inner.bravo).isEqualTo(\"two\")\n\t}\n\n\t@Test\n\tfun `mutable data class properties can be imported`() {\n\t\tthis.context.register(MutableDataClassPropertiesImporter::class.java)\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, \"mutable.prop=alpha\")\n\t\tthis.context.refresh()\n\t\tassertThat(this.context.getBean(MutableDataClassProperties::class.java).prop).isEqualTo(\"alpha\")\n\t}\n\n\t@ConfigurationProperties(\"foo\")\n\tclass BingProperties(@Suppress(\"UNUSED_PARAMETER\") bar: String)\n\n\t@EnableConfigurationProperties\n\tclass EnableConfigProperties\n\n\t@ConfigurationProperties(\"lateinit\")\n\tclass LateInitProperties {\n\n\t\tlateinit var inner: Inner\n\n\t}\n\n\tdata class Inner(val value: String)\n\n\t@EnableConfigurationProperties(LateInitPropertiesWithDefault::class)\n\tclass EnableLateInitPropertiesWithDefault\n\n\t@ConfigurationProperties(\"lateinit-with-default\")\n\tclass LateInitPropertiesWithDefault {\n\n\t\tlateinit var inner: InnerWithDefault\n\n\t}\n\n\tdata class InnerWithDefault(val alpha: String = \"apple\", val bravo: String = \"banana\")\n\n\t@EnableConfigurationProperties(LateInitProperties::class)\n\tclass EnableLateInitProperties\n\n\t@EnableConfigurationProperties\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(MutableDataClassProperties::class)\n\tclass MutableDataClassPropertiesImporter\n\n\t@ConfigurationProperties(\"mutable\")\n\tdata class MutableDataClassProperties(\n\t\tvar prop: String = \"\"\n\t)\n\n\t@EnableConfigurationProperties(RenamedProperties::class)\n\tclass EnableRenamedProperties\n\n\t@ConfigurationProperties(\"renamed\")\n\tclass RenamedProperties{\n\t\t@Name(\"var\")\n\t\tvar bar: String = \"\"\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/context/properties/bind/KotlinBindableRuntimeHintsRegistrarTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.aot.hint.MemberCategory\nimport org.springframework.aot.hint.RuntimeHints\n\n\n/**\n * Tests for {@link BindableRuntimeHintsRegistrar}.\n *\n * @author Andy Wilkinson\n */\nclass KotlinBindableRuntimeHintsRegistrarTests {\n\n\t@Test\n\tfun `registerHints for data class with default value should allow declared constructors to be invoked`() {\n\t\tval runtimeHints = RuntimeHints()\n\t\tval register = BindableRuntimeHintsRegistrar.forTypes(PropertyWithDefaultValue::class.java)\n\t\tregister.registerHints(runtimeHints)\n\t\tassertThat(runtimeHints.reflection().typeHints()).hasSize(1)\n\t\tassertThat(runtimeHints.reflection().typeHints()).allSatisfy { hint ->\n\t\t\tassertThat(hint.memberCategories).containsExactly(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)\n\t\t}\n\t}\n\n\tdata class PropertyWithDefaultValue(var a: String = \"alpha\")\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/context/properties/bind/KotlinConstructorParametersBinderTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName\nimport org.springframework.boot.context.properties.source.MockConfigurationPropertySource\nimport org.springframework.core.ResolvableType\n\n/**\n * Tests for `ConstructorParametersBinder`.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass KotlinConstructorParametersBinderTests {\n\n\t@Test\n\tfun `Bind to class should create bound bean`() {\n\t\tval source = MockConfigurationPropertySource(mapOf(\"foo.int-value\" to \"12\",\n\t\t\t\t\"foo.int-value\" to \"12\",\n\t\t\t\t\"foo.long-value\" to \"34\",\n\t\t\t\t\"foo.boolean-value\" to \"true\",\n\t\t\t\t\"foo.string-value\" to \"foo\",\n\t\t\t\t\"foo.enum-value\" to \"foo-bar\"))\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleValueBean::class.java)).get()\n\t\tassertThat(bean.intValue).isEqualTo(12)\n\t\tassertThat(bean.longValue).isEqualTo(34)\n\t\tassertThat(bean.booleanValue).isTrue()\n\t\tassertThat(bean.stringValue).isEqualTo(\"foo\")\n\t\tassertThat(bean.enumValue).isEqualTo(ExampleEnum.FOO_BAR)\n\t}\n\n\t@Test\n\tfun `Bind to class when has no prefix should create bound bean`() {\n\t\tval source = MockConfigurationPropertySource(mapOf(\"int-value\" to \"12\",\n\t\t\t\t\"long-value\" to \"34\",\n\t\t\t\t\"boolean-value\" to \"true\",\n\t\t\t\t\"string-value\" to \"foo\",\n\t\t\t\t\"enum-value\" to \"foo-bar\"))\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(ConfigurationPropertyName.of(\"\"),\n\t\t\t\tBindable.of(ExampleValueBean::class.java)).get()\n\t\tassertThat(bean.intValue).isEqualTo(12)\n\t\tassertThat(bean.longValue).isEqualTo(34)\n\t\tassertThat(bean.booleanValue).isTrue()\n\t\tassertThat(bean.stringValue).isEqualTo(\"foo\")\n\t\tassertThat(bean.enumValue).isEqualTo(ExampleEnum.FOO_BAR)\n\t}\n\n\t@Test\n\tfun `Bind to data class should create bound bean`() {\n\t\tval source = MockConfigurationPropertySource(mapOf(\"foo.int-value\" to \"12\",\n\t\t\t\t\"foo.long-value\" to \"34\",\n\t\t\t\t\"foo.boolean-value\" to \"true\",\n\t\t\t\t\"foo.string-value\" to \"foo\",\n\t\t\t\t\"foo.enum-value\" to \"foo-bar\"))\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleDataClassBean::class.java)).get()\n\t\tval expectedBean = ExampleDataClassBean(intValue = 12,\n\t\t\t\tlongValue = 34,\n\t\t\t\tbooleanValue = true,\n\t\t\t\tstringValue = \"foo\",\n\t\t\t\tenumValue = ExampleEnum.FOO_BAR)\n\t\tassertThat(bean).isEqualTo(expectedBean)\n\t}\n\n\t@Test\n\tfun `Bind to class with multiple constructors and primary constructor should bind`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.int-value\", \"12\")\n\t\tval binder = Binder(source)\n\t\tval bindable = binder.bind(\"foo\", Bindable.of(\n\t\t\t\tMultipleConstructorsWithPrimaryConstructorBean::class.java))\n\t\tassertThat(bindable.isBound).isTrue()\n\t\tassertThat(bindable.get().intValue).isEqualTo(12)\n\t}\n\n\t@Test\n\tfun `Bind to class with multiple constructors should not bind`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.int-value\", \"12\")\n\t\tval binder = Binder(source)\n\t\tval bindable = binder.bind(\"foo\", Bindable.of(\n\t\t\t\tMultipleConstructorsBean::class.java))\n\t\tassertThat(bindable.isBound).isFalse()\n\t}\n\n\t@Test\n\tfun `Bind to class with only default constructor should not bind`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.int-value\", \"12\")\n\t\tval binder = Binder(source)\n\t\tval bindable = binder.bind(\"foo\", Bindable.of(\n\t\t\t\tDefaultConstructorBean::class.java))\n\t\tassertThat(bindable.isBound).isFalse()\n\t}\n\n\t@Test\n\tfun `Bind to class should bind nested`() {\n\t\tval source = MockConfigurationPropertySource(mapOf(\"foo.value-bean.int-value\" to \"123\",\n\t\t\t\t\"foo.value-bean.long-value\" to \"34\",\n\t\t\t\t\"foo.value-bean.boolean-value\" to \"true\",\n\t\t\t\t\"foo.value-bean.string-value\" to \"foo\"))\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleNestedBean::class.java)).get()\n\t\tassertThat(bean.valueBean.intValue).isEqualTo(123)\n\t\tassertThat(bean.valueBean.longValue).isEqualTo(34)\n\t\tassertThat(bean.valueBean.booleanValue).isTrue()\n\t\tassertThat(bean.valueBean.stringValue).isEqualTo(\"foo\")\n\t\tassertThat(bean.valueBean.enumValue).isNull()\n\t}\n\n\t@Test\n\tfun `Bind to class with no value for optional should use null`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"foo\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(\n\t\t\t\tExampleValueBean::class.java)).get()\n\t\tassertThat(bean.intValue).isNull()\n\t\tassertThat(bean.longValue).isNull()\n\t\tassertThat(bean.booleanValue).isNull()\n\t\tassertThat(bean.stringValue).isEqualTo(\"foo\")\n\t\tassertThat(bean.enumValue).isNull()\n\t}\n\n\t@Test\n\tfun `Bind to class with no value for primitive should use default value`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"foo\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(\n\t\t\t\tExamplePrimitiveDefaultBean::class.java)).get()\n\t\tassertThat(bean.intValue).isEqualTo(0)\n\t\tassertThat(bean.longValue).isEqualTo(0)\n\t\tassertThat(bean.booleanValue).isFalse()\n\t\tassertThat(bean.stringValue).isEqualTo(\"foo\")\n\t\tassertThat(bean.enumValue).isNull()\n\t}\n\n\t@Test\n\tfun `Bind to class with no value and default value should return unbound`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"foo\")\n\t\tval binder = Binder(source)\n\t\tassertThat(binder.bind(\"foo\", Bindable.of(\n\t\t\t\tExampleDefaultValueBean::class.java)).isBound).isFalse()\n\t}\n\n\t@Test\n\tfun `Bind or create to class with no value and default value should return default value`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"foo\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bindOrCreate(\"foo\", Bindable.of(\n\t\t\t\tExampleDefaultValueBean::class.java))\n\t\tassertThat(bean.intValue).isEqualTo(5)\n\t\tassertThat(bean.stringsList).containsOnly(\"a\", \"b\", \"c\")\n\t\tassertThat(bean.customList).containsOnly(\"x,y,z\")\n\t}\n\n\t@Test\n\tfun `Bind to data class with no value should use default value`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.enum-value\", \"foo-bar\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleDataClassBean::class.java)).get()\n\t\tval expectedBean = ExampleDataClassBean(intValue = 5,\n\t\t\t\tlongValue = 42,\n\t\t\t\tbooleanValue = false,\n\t\t\t\tstringValue = \"my data\",\n\t\t\t\tenumValue = ExampleEnum.FOO_BAR)\n\t\tassertThat(bean).isEqualTo(expectedBean)\n\t}\n\n\t@Test\n\tfun `Bind to data class with generics`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.value.bar\", \"baz\")\n\t\tval binder = Binder(source)\n\t\tval type = ResolvableType.forClassWithGenerics(Map::class.java, String::class.java,\n\t\t\t\tString::class.java)\n\t\tval bean = binder.bind(\"foo\", Bindable\n\t\t\t\t.of<GenericValue<Map<String, String>>>(ResolvableType.forClassWithGenerics(GenericValue::class.java, type)))\n\t\t\t\t.get()\n\t\tassertThat(bean.value[\"bar\"]).isEqualTo(\"baz\")\n\t}\n\n\t@Test\n\tfun `Bind to named data class constructor parameter`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"test\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleNamedParameterDataClass::class.java)).get()\n\t\tassertThat(bean.stringDataValue).isEqualTo(\"test\")\n\t}\n\n\t@Test\n\tfun `Bind to named class constructor parameter`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"test\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleNamedParameterClass::class.java)).get()\n\t\tassertThat(bean.stringDataValue).isEqualTo(\"test\")\n\t}\n\n\t@Test\n\tfun `Bind to singleton object`() {\n\t\tval source = MockConfigurationPropertySource(\"foo.string-value\", \"test\")\n\t\tval binder = Binder(source)\n\t\tval bean = binder.bind(\"foo\", Bindable.of(ExampleSingletonBean::class.java)).get()\n\t\tassertThat(bean.stringValue).isEqualTo(\"test\")\n\t}\n\n\tclass ExampleValueBean(val intValue: Int?, val longValue: Long?,\n\t\t\t\t\t\t   val booleanValue: Boolean?, val stringValue: String?,\n\t\t\t\t\t\t   val enumValue: ExampleEnum?)\n\n\tclass ExamplePrimitiveDefaultBean(val intValue: Int = 0, val longValue: Long = 0,\n\t\t\t\t\t\t\t\t\t  val booleanValue: Boolean = false, val stringValue: String?,\n\t\t\t\t\t\t\t\t\t  val enumValue: ExampleEnum?)\n\n\n\tenum class ExampleEnum {\n\n\t\tFOO_BAR,\n\n\t\tBAR_BAZ\n\t}\n\n\t@Suppress(\"unused\", \"UNUSED_PARAMETER\")\n\tclass MultipleConstructorsWithPrimaryConstructorBean(val intValue: Int) {\n\t\tconstructor(intValue: Int, longValue: Long) : this(intValue)\n\t}\n\n\t@Suppress(\"unused\", \"UNUSED_PARAMETER\")\n\tclass MultipleConstructorsBean {\n\t\tconstructor(intValue: Int)\n\n\t\tconstructor(intValue: Int, longValue: Long) : this(intValue)\n\t}\n\n\tclass DefaultConstructorBean\n\n\tclass ExampleNestedBean(val valueBean: ExampleValueBean)\n\n\tclass ExampleDefaultValueBean(val intValue: Int = 5,\n\t\t\t\t\t\t\t\t  val stringsList: List<String> = listOf(\"a\", \"b\", \"c\"),\n\t\t\t\t\t\t\t\t  val customList: List<String> = listOf(\"x,y,z\"))\n\n\tdata class ExampleDataClassBean(val intValue: Int = 5, val longValue: Long = 42,\n\t\t\t\t\t\t\t\t\tval booleanValue: Boolean = false,\n\t\t\t\t\t\t\t\t\tval stringValue: String = \"my data\",\n\t\t\t\t\t\t\t\t\tval enumValue: ExampleEnum = ExampleEnum.BAR_BAZ)\n\n\tdata class ExampleNamedParameterDataClass(@Name(\"stringValue\") val stringDataValue: String)\n\n\tclass ExampleNamedParameterClass(@Name(\"stringValue\") val stringDataValue: String)\n\n\tdata class GenericValue<T>(\n\t\tval value: T\n\t)\n\n\tobject ExampleSingletonBean {\n\t\tvar stringValue: String? = null\n\t}\n\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/context/properties/bind/KotlinDefaultBindConstructorProviderTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.bind\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.Assertions.assertThatIllegalStateException\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\n\n/**\n * Tests for `DefaultBindConstructorProvider`.\n *\n * @author Madhura Bhave\n */\n@Suppress(\"unused\")\nclass KotlinDefaultBindConstructorProviderTests {\n\n\tprivate val constructorProvider = DefaultBindConstructorProvider()\n\n\t@Test\n\tfun `type with default constructor should register java bean`() {\n\t\tval bindConstructor = this.constructorProvider.getBindConstructor(FooProperties::class.java, false)\n\t\tassertThat(bindConstructor).isNull()\n\t}\n\n\t@Test\n\tfun `type with no primary constructor should register java bean`() {\n\t\tval bindConstructor = this.constructorProvider.getBindConstructor(MultipleAmbiguousConstructors::class.java, false)\n\t\tassertThat(bindConstructor).isNull()\n\t}\n\n\t@Test\n\tfun `type with primary and secondary annotated constructor should use secondary constructor for binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(ConstructorBindingOnSecondaryWithPrimaryConstructor::class.java, false)\n\t\tassertThat(bindConstructor).isNotNull()\n\t}\n\n\t@Test\n\tfun `type with primary constructor with autowired should not use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(AutowiredPrimaryProperties::class.java, false)\n\t\tassertThat(bindConstructor).isNull()\n\t}\n\n\t@Test\n\tfun `type with primary and secondary constructor with autowired should not use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(PrimaryWithAutowiredSecondaryProperties::class.java, false)\n\t\tassertThat(bindConstructor).isNull()\n\t}\n\n\t@Test\n\tfun `type with no param primary constructor and params secondary constructor should not use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(NoParamPrimaryWithParamsSecondaryProperties::class.java, false)\n\t\tassertThat(bindConstructor).isNull()\n\t}\n\n\t@Test\n\tfun `type with params primary constructor and no param secondary constructor should use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider.\n\t\t\t\tgetBindConstructor(ParamsPrimaryWithNoParamSecondaryProperties::class.java, false)\n\t\tassertThat(bindConstructor).isNotNull()\n\t}\n\n\t@Test\n\tfun `type with autowired secondary constructor should not use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(AutowiredSecondaryProperties::class.java, false)\n\t\tassertThat(bindConstructor).isNull()\n\t}\n\n\t@Test\n\tfun `type with autowired primary and constructor binding on secondary constructor should throw exception`() {\n\t\tassertThatIllegalStateException().isThrownBy {\n\t\t\tthis.constructorProvider\n\t\t\t\t\t.getBindConstructor(ConstructorBindingOnSecondaryAndAutowiredPrimaryProperties::class.java, false)\n\t\t}\n\t}\n\n\t@Test\n\tfun `type with autowired secondary and constructor binding on primary constructor should throw exception`() {\n\t\tassertThatIllegalStateException().isThrownBy {\n\t\t\tthis.constructorProvider\n\t\t\t\t\t.getBindConstructor(ConstructorBindingOnPrimaryAndAutowiredSecondaryProperties::class.java, false)\n\t\t}\n\t}\n\n\t@Test\n\tfun `type with primary constructor and no annotation should use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(ConstructorBindingPrimaryConstructorNoAnnotation::class.java, false)\n\t\tassertThat(bindConstructor).isNotNull()\n\t}\n\n\t@Test\n\tfun `type with secondary constructor and no annotation should use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(ConstructorBindingSecondaryConstructorNoAnnotation::class.java, false)\n\t\tassertThat(bindConstructor).isNotNull()\n\t}\n\n\t@Test\n\tfun `type with multiple constructors`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(ConstructorBindingMultipleConstructors::class.java, false)\n\t\tassertThat(bindConstructor).isNotNull()\n\t}\n\n\t@Test\n\tfun `type with multiple annotated constructors should throw exception`() {\n\t\tassertThatIllegalStateException().isThrownBy {\n\t\t\tthis.constructorProvider\n\t\t\t\t\t.getBindConstructor(ConstructorBindingMultipleAnnotatedConstructors::class.java, false)\n\t\t}\n\t}\n\n\t@Test\n\tfun `type with secondary and primary annotated constructors should throw exception`() {\n\t\tassertThatIllegalStateException().isThrownBy {\n\t\t\tthis.constructorProvider\n\t\t\t\t\t.getBindConstructor(ConstructorBindingSecondaryAndPrimaryAnnotatedConstructors::class.java, false)\n\t\t}\n\t}\n\n\t@Test\n\tfun `data class with default values should use constructor binding`() {\n\t\tval bindConstructor = this.constructorProvider\n\t\t\t\t.getBindConstructor(ConstructorBindingDataClassWithDefaultValues::class.java, false)\n\t\tassertThat(bindConstructor).isNotNull()\n\t}\n\n\tclass FooProperties\n\n\tclass PrimaryWithAutowiredSecondaryProperties(val name: String?, val counter: Int = 42) {\n\n\t\t@Autowired\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String) : this(foo, 21)\n\t}\n\n\tclass NoParamPrimaryWithParamsSecondaryProperties() {\n\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") name: String) : this()\n\n\t\tvar name: String? = null\n\t}\n\n\tclass ParamsPrimaryWithNoParamSecondaryProperties(var name: String?) {\n\n\t\tconstructor() : this(null)\n\t}\n\n\tclass AutowiredSecondaryProperties {\n\n\t\t@Autowired\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String)\n\t}\n\n\tclass AutowiredPrimaryProperties @Autowired constructor(val name: String?, val counter: Int = 42)\n\n\tclass ConstructorBindingOnSecondaryAndAutowiredPrimaryProperties @Autowired constructor(\n\t\t\tval name: String?, val counter: Int = 42) {\n\n\t\t@ConstructorBinding\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String) : this(foo, 21)\n\t}\n\n\tclass ConstructorBindingOnPrimaryAndAutowiredSecondaryProperties @ConstructorBinding constructor(\n\t\t\tval name: String?, val counter: Int = 42) {\n\n\t\t@Autowired\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String) : this(foo, 21)\n\t}\n\n\tclass ConstructorBindingOnSecondaryWithPrimaryConstructor(val name: String?, val counter: Int = 42) {\n\n\t\t@ConstructorBinding\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String) : this(foo, 21)\n\t}\n\n\tclass ConstructorBindingOnPrimaryWithSecondaryConstructor @ConstructorBinding constructor(\n\t\t\tval name: String?, val counter: Int = 42) {\n\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String) : this(foo, 21)\n\t}\n\n\tclass ConstructorBindingPrimaryConstructorNoAnnotation(val name: String?, val counter: Int = 42)\n\n\tclass ConstructorBindingSecondaryConstructorNoAnnotation {\n\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String)\n\n\t}\n\n\tclass MultipleAmbiguousConstructors {\n\n\t\tconstructor()\n\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String)\n\n\t}\n\n\tclass ConstructorBindingMultipleConstructors {\n\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") bar: Int)\n\n\t\t@ConstructorBinding\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String)\n\n\t}\n\n\tclass ConstructorBindingMultipleAnnotatedConstructors {\n\n\t\t@ConstructorBinding\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") bar: Int)\n\n\t\t@ConstructorBinding\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String)\n\n\t}\n\n\tclass ConstructorBindingSecondaryAndPrimaryAnnotatedConstructors @ConstructorBinding constructor(\n\t\t\tval name: String?, val counter: Int = 42) {\n\n\t\t@ConstructorBinding\n\t\tconstructor(@Suppress(\"UNUSED_PARAMETER\") foo: String) : this(foo, 21)\n\n\t}\n\n\tdata class ConstructorBindingDataClassWithDefaultValues(val name: String = \"Joan\", val counter: Int = 42)\n\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/test/kotlin/org/springframework/boot/kotlinsample/TestKotlinApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kotlinsample\n\nimport org.springframework.boot.runApplication\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nopen class TestKotlinApplication\n\nfun main(args: Array<String>) {\n\trunApplication<TestKotlinApplication>(*args)\n}\n\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/log4j2-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"warn\" name=\"test\">\n\t<Properties>\n\t\t<Property name=\"LOG_EXCEPTION_CONVERSION_WORD\">%xwEx</Property>\n\t\t<Property name=\"LOG_LEVEL_PATTERN\">%5p</Property>\n\t</Properties>\n\t<Appenders>\n\t\t<Console name=\"STDOUT\" target=\"SYSTEM_OUT\" follow=\"true\">\n\t\t\t<PatternLayout pattern=\"%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}\"/>\n\t\t</Console>\n\t</Appenders>\n\t<Loggers>\n\t\t<Root level=\"info\">\n\t\t\t<AppenderRef ref=\"STDOUT\"/>\n\t\t</Root>\n\t</Loggers>\n</Configuration>\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/env/test-properties.properties",
    "content": "   # foo\nblah   =   hello world\nbar   foo=baz\nhello   world\nproper\\\\ty=test\nfoo\nbat = a\\\\\nbling = a=b\n\n#commented-property=test\ntest=properties\ntest-unicode=properties\\u0026test\n  # comment ending \\\ntest\\=property=helloworld\ntest-colon-separator: my-property\ntest-tab-property=foo\\tbar\ntest-return-property=foo\\rbar\ntest-newline-property=foo\\nbar\ntest-form-feed-property=foo\\fbar\ntest-whitespace-property   =   foo   bar\ntest-multiline= a\\\n  b\\\\\\\n  c\nfoods[]=Apple,\\\nOrange,\\\nStrawberry,\\\nMango\nlanguages[perl]=Elite\nlanguages[python]=Elite\nlanguage[pascal]=Lame\ntest-multiline-immediate=\\\nfoo\n!commented-two=bang\\\ntest-bang-property=foo!\nanother=bar\ntest-property-value-comment=foo \\\n!bar #foo\ntest-multiline-immediate-bang=\\\n!foo\n\n#test ISO 8859-1\ntest-iso8859-1-chars=\n\ntest-with-trailing-space= trailing \ntest-with-escaped-trailing-space= trailing\\ \n\n#\ntest-line-after-empty-pound=abc"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/json/deeply-nested-map-json.txt",
    "content": "[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��{\":{\":{\":{\":{\":{\":[{\":{\"\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\":{\"��"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/json/large-malformed-json.txt",
    "content": "[[{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{/t:{{:{t:{[:{{:{4:{{t:{{:{[:{{:{t:{:{t:{{:{t:{:{t{t:{{{:{t?{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{/t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt:{:{[{ty/t:{{:{t:{[:{{:{4:{{t:{{:{[:{{:{t:{:{t:{{:{t:{:{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{/t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t:{:{:{:{{:{t:{t{s:{t:{tt:{{:{[\",[[{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{/t:{{:{t:{[:{{:{4:{{t:{{:{[:{{:{t:{:{t:{{:{t:{:{t{t:{{{:{t?{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{/t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt:{:{[{ty/t:{{:{t:{[:{{:{4:{{t:{{:{[:{{:{t:{:{t:{{:{t:{:{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t{t{t:{{{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{:{:{t:{{t:{{:{t:{:{t:{{:{t:{:{t:{{:{t:{[:{{:{t:{{t:{{:{[:{{:{tt:[{tt{:{t:{{t:{{:{t:{:{t:{{:{t:{:{:{:{{:{t:{t{s:{t:{tt:{{:{[\","
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/json/repeated-open-array.txt",
    "content": "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/ca.crt",
    "content": "-----BEGIN TRUSTED CERTIFICATE-----\nMIIDIDCCAgsCFH3lh1RXOEy2ESqUPyzb+9zxMYUnMA0GCSqGSIb3DQEBCwUAME8x\nCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAkNBMCAXDTIzMTAwNTA3MjU1M1oY\nDzIxMjMwOTExMDcyNTUzWjBPMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs\ndCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQswCQYDVQQDDAJD\nQTCCAR4wDQYJKoZIhvcNAQEBBQADggELADCCAQYCgf4NNpc+6B3qvwKcRYgoXmJ4\n3wyWktBK7BdShz/YnW1OlFZ+R845ZiDw0KdzElZWkYqn+BYJus6lPIS5dfLcrGSf\na1e8IK02RpBiY/WJvupetnSk8gKA7emF94NlV4gXr4ICJAhXvXUFyBLpdEUE/lcg\nlgCbVJzs5jWUnffEF9mrClzzo0+iXw34zwmyYyBTFmlOEr+QUEdAb6Lr/klpTVit\nas2Ddg1QT4EaSIdTEpkVRZp2dyYVdqSxpaBq21xg0viDHsYQrP96IfacmUB7kFFn\nHsnptDHFvJj2WSQDX+PRS7tLl4mmfizZg80eGfLD22ShNspRSGnbJc0OzegPiwID\nAQABMA0GCSqGSIb3DQEBCwUAA4H/AAnC+FQqdeJaG5I7R+pNjgKplL2UsxW983kA\nCVVkv/Dt0+4rbPC67o9/8Tr+g4eo/wUntMNo2ghF3oBItGr7pJE16zPiLwIvha9c\n8BDhCEZWyhz3vkamZUi19lOnkm3zTmmDE/nX4WYH6CL4UWjxvniZYwW8AdVSnFXY\nncriuvfliLa3dw1SJ7FtxdcBn4yfzrZWcY+psYNHpftLGYRmQF/VCDSB9EAIEggr\nyBcP749u2y8s44WvKAnnwfLcALIrylY25zN0pao/l2X8HI6qHUeA/QbbEBpDoQvR\ndu/rgaHCVvFFxATefhBJ0CUA1Nn5nrGwyRTKnZWtR080qwUp\n-----END TRUSTED CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/ca.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEqQIBADANBgkqhkiG9w0BAQEFAASCBJMwggSPAgEAAoH+DTaXPugd6r8CnEWI\nKF5ieN8MlpLQSuwXUoc/2J1tTpRWfkfOOWYg8NCncxJWVpGKp/gWCbrOpTyEuXXy\n3Kxkn2tXvCCtNkaQYmP1ib7qXrZ0pPICgO3phfeDZVeIF6+CAiQIV711BcgS6XRF\nBP5XIJYAm1Sc7OY1lJ33xBfZqwpc86NPol8N+M8JsmMgUxZpThK/kFBHQG+i6/5J\naU1YrWrNg3YNUE+BGkiHUxKZFUWadncmFXaksaWgattcYNL4gx7GEKz/eiH2nJlA\ne5BRZx7J6bQxxbyY9lkkA1/j0Uu7S5eJpn4s2YPNHhnyw9tkoTbKUUhp2yXNDs3o\nD4sCAwEAAQKB/goGHht1EC0kFyDihvbJE79Kx0v7uNT94nuTa1Yzp9bzJeLLKqHU\n3qySPlZH1QP7icr/pAhhlZ85GB9yYXoTtopSbs6jo4QHaEWcO4vyL+8GT9tKVafl\n1UDyktXw36fIV8Kz/zhA3GQ0clR1Bl9RbFumMHOmbx4xTvieFnbG+TQ2THfFccGS\njCO6+dab6daXs8sBt0rGMh72utIISVsFJc7v3B8BpaNOI4iBMciRSyZeE4Vw/lRg\ne3iErAVUmUjBrUK/wBy/l9cbbpkp+rvhQpmTIPtKd5f29AQNL7p6V+2+yRb2woRk\n0i1HwOHGOhiCTxXZB9/nZykaT/T2+J9BAn8+DEWCRcfifyNEyuE54G6BvLvgGTgs\n+kXWS7p0+wO9CFBDZARu/MXFEfcWt4ZTIj8HtMiKhxNbC1LiGtQnJoLV6AM75E5Q\ntoh/xyYOnHbhnbhsSNcpJk5iIdqQE6hWh+rYXFr1aJFMRZaWRkcUG8iIxWQQjRvw\nqxLm9GQtEhF7An82hAlPCDs+6kT1otBEN8vGaW8qkxWYJf6kSd/I0/TEKRYpIwBa\nIst2BN5GrJTitKhzQIq2ZyT2byHxS0VIvInZJ6sFC+V6fHYpzWbS3zkBy2zswfAZ\nUYrdjLVv16qZYsdjUnhkyUaBbBXnrTPlPzxXvgTeqJeJ5tbR6wgeqPUxAn8lcQxE\nt00N/UBQE8jjPu4QNc59RVqjsYaQ8POcAZjY6fpdIC6Ytsm0yMl8mNRiuCimws28\n4hOo/eVO8XeSBGgxIidJbdRgWjV2PbtWV85ZCO6v0Sic+TOVfe5AwMv1I2FwnBJ7\nQlVjXB6podDkbnuNJOfkIPJ6QRFP8qu8ksmfAn8mttuZeYIBawLv4eC/IVSgIc3l\nUTC7rPfKGgBHMWaYS4lGS2n7mMwektR7IiJVYPBjcIlRgaw5KbDUF50rS2Elissj\nuVANDQgpJYoI5KcqRBmlhRCKGmNgdIWA2Ip5hTGNskp3YIymamif71t0SNUEhpgU\nu2tqbjlON/e7NkdxAn8VdVYq+4sAWRdU4VJqqyf8dyBx68sysvY6HYlKS2bpfu3C\nJ3gbPximDZhzMvKx2/CAzMbAT3anyr/DiUImk+QdWSmht+1SLH7A14MDjzQ0D5xt\nGgPqWn7PtcJojFMjc/o5/fKgFf4CYkJhv2KycX9UeldBxpqNpNigzFWBLdtu\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/dsa.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIDXQIBADCCAzYGByqGSM44BAEwggMpAoIBgQC1d6MOqEDLxjfjz1v7Vg44bBBX\nVOoNdWhvJPl9NL2Js57UmYGrTqFit2VCLxbS5FVLyOZ25S0myQRsEtKyi4V9+ELI\n0q3oQplm+l3tZqKjtO69ZlbzYSl9IG1254/FCwBnBTuN7Vl6A2vryIhY7cL4E053\nYy0xqfP7swPgMYNBqjc9c53hNHKiseQJ8Q2wFKZqm13xgqnBqmWbm7yNmzKJbjMW\nZt3/WpJdjqfRnjSljFOkYPPBkGRUIKHcZ9fw4odVov2vblGzXwR+sFeE3lcF50WN\nuppjszMXlqR4y937CUSFbCabatRHEcPTq/FxioERCrCdx3AKOfwAquahtvWb9V7A\n47FlibDDeybh5jCH0j9HSjhjSiDZdadSgGKFynPNlVAlOETZKGqkeqAZZ+dsPkVO\nn8tx+VXZJF00YSe1HLKJUWXaT1tEGF6vw/dXhhQVir4j63fN2tZdhTOW1ao/J/iT\nVYEQQjYeMKKuZQveBKRBlpAjhmjOztbE8VL4O/cCHQCxPXlCpORbfOMEEGU0hbEE\nHsxFHMXHCnURCJxVAoIBgQCBqsk+z57UndC1Ut6u19wILXs7UBgLo0ivId2QHtm5\nkY77P9/lNOyCIQkBnULbJ36lHm6yxLZ8imyC5Lc7wlFJpJ6PpiTJ3nPi3fzhbftB\n2KCJVSwB3XfkjvyyS8bfwwqyrmce9el+AIFJuWPrFSkjNthq7U5vU5a+uNT9XZrs\nEaDbjkjVJXRX1oDS3IfWXWpb9i/LOE9HU+NfDKfydasWASvwNX1F5BKXD0AH9adj\n9Q7b0p4DVTh+UPWLBk9/e6gsA5HaRI1urAMNxs5Xnmd8UYF1I+AmjQ9Mi63Pa0YW\nQjpdH2hoOQGLemQ/72woFVzLaHWBcTuSwjREilaAA5M8CWq4rpuA79MrcHgzSp2C\nW1gtZa2/3SymcJ7Py2PHbncod8gR9dxHWVO07ccOXUG0iL9m4MzQ27uVvTh8Nrma\nM+JET778E2FaAkAIT34eNMC6Yk2IDrxU9L66FFx3+3n0cOeWaJxIWrIQ6uWk+uIH\nVzPsZAQU/V0/QBABlHuSj1cEHgIcYTbB5VrbIgust0jVvQCnlF4b1V0qz2iDJt6o\nsA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/file.txt",
    "content": "Text file to test parsing failures with invalid input\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs1/dsa.key",
    "content": "-----BEGIN DSA PRIVATE KEY-----\nMIIBuwIBAAKBgQCDX+Ux7y7dkfCnQgRIXzAlFrG8uPxwFdC8J4FJNrAurnjL//PV\n8LEHBDVbyPjHaoNbH8Pfc2pJnOzndWZVf0nqBd4Q/Tz9w/pJ9g6E8HOh+rzU3eK5\nmF0rezcMbJsot2Vdx6XrTztDKi2GY0etKNV399DYtepIYA6v5ovuYAOjLwIVAPyb\n9zR+UjyCkBwESDm9dpzKsGp1AoGAS2vtTiO7/MT8cJwo4mxYtiJnV5R2mk1JJOTe\n4AFPgmnce/YbBzU2JwL9J9HGewDkmxudW0zoxZVeNw4dRua6oB5STV8XciW8vSo6\nmdDBJFoBW9/DUscRP4j2aRfkXGlYuiEF6ZT8g6pPHZG7pLviihMAWNRVLmBt38wa\n8FA9aZECgYADbfwh7OhSE1J0WRaEk/4Usos5Oi6fhUyqr2u34Ereug9Gt4tkhePa\nb3y31i2PQfsatpR+4VpBC6zpPgHQYpuqlqDRWJCd+Cxo9751nOiA3xYVxNoiwIn/\nWxoUkC8Jv8kYFAJRceXkF/auVh77MUoruAmoT2lGE6zP6ngP2q6jFwIVAJMF5kZ+\nAUZbUBUpZaPuZ15RL8GF\n-----END DSA PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs1/rsa-aes-256-cbc.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,2036BA8802B364C6BE415A48E1AC9966\n\n0euP/daGIbl798XGc2Tc6u6NmnCl8C6hE0a2grO+wbvFEa13IT4hNVNTzqahfLb8\nSTF9LXdvPbz9HybyWnG8KNm5sqsSY1omsHQI38khhwuhpHuWfjb62TqWobwrAmAU\nqh2+kjc7upzW48axJLRQ69vfE4zKczZ4Sqv8qImPz9SiXPeaXinHf/wKfgXZZOvr\n6A8nCykLglVrFbrZWydqKrTM9w/LTXsn0gNpDmrfZERDgWnabKnjYidHkXdgAoFy\nulsBjKvj2hJFtnJHTkCPXj6XAj18cwUWsN7inFJR5wqjIWXuLqfv/fNbK9lPzjAk\nvMTEVWwynekvXFsSvnHAyEJfmRCNF6DOE+5VwjEROCFq8xceK4fz4T3BHC7XSgis\n2ofBZwjCAJ0pP6SdRpbbZ0wlXH09wqDDTZ2vWD6bEG7hO9VuP/aO76MIWydLa78z\nbDb2R6MnYKmYEInPzwfU4H66Z3/cz8orfYLlnF55DRd4rO+fJm6Y/XY14ac3x0S+\nP67s5e0WbdImagUsOxGNBjgOr84lwmtk/LoVd5nKho8JyQw3V7tiyrsKsM1lAXdS\nTaJXKRnN6LbgC8d+Tgfjc/qMUdVqLlN8zATIa6E4sc861DDiJsneXuFm43pHc/ja\n0sxSifBKgLGenj8xY5ANEfrYnXKrzaQemUnMzd+zan6OS02I+e8WTQevESt1j0D8\n7mgLJ9W2SfNNfiEd5OKar21lLNOc3POaFn7M73zL/gyhTROipPR3fpV+08k27UKl\nnzGhFtRwQieXl34QjM0JrHokKKfv8FsAJsbrGnz2/wcm6jJGmrj5VVsogMKc90v4\nZTM44NAKymM0UTuIp/rKb/UUVYDpl9VWDegWh2+XKX8io31ENrDMcvQTJ/mzNCuZ\nSINrAeMbVD6W5L0i7THEt32YsDmbFsBaEJBlNXlUNBa/NCK0pjwAn5AYOFUvEqBC\noZUEleUMU6Q3TKI287o37euw3No6jo5VdPULlrwHsZAjmq9EUvRCgMoIEPdxv5XG\na4PljE7DQLlk6G9d+gjRzClLFfkadSTbtH9o2011RtWUKP4dcRuSOcBm64xVIO6J\nrhe38sE3yzHvLUM/mvLsEM8B0AHl85nrEstlbBzftXMo2CAJ2Gs9c61PYfft+xiT\npRdHx4HB1P+kfHa96ayvAytOexHih2iVKVG5CchOr5tbWmkhXVE5cZAKzvczDYFd\nYvniHNiqt6LO8EbJOzz+Yxessmd0zBXj/rjxTMdGwaRjiFI0BIguYpvmGoMS8+bp\nspRj2DMtqjNZz68BEEfgKQwDHPCTblYSR+3Uw4sja608sflqQ8rTmOwbfta3SNS8\nKq/zzWfYzarQ8hAk5n/H1Jm6AQdvcptyMjuF8FAiMnvt8xDCBRMD3xY2BHb/tcs9\ndBWBxhb76CKIrV3pzm9gGhhZ32Ndq9KmmE+bWCYyvrLxvPJxODfM7X5XamPmG5SH\nwEKSbp0wPF0b6vyxt5M72OYnU8UnxYWu6PlbVvczfWEu9fIw/oIN/kDT/QUojTyt\nwBgzVSTSNFaDtVXJw10IWQgsgWdNY5XueHKH060P5g+14woxU8i3TboNd+tC3hRl\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs1/rsa.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEA1zZsVLbl+bOl2QlFZ5R5hbJrR5u+G3Ddd/f25JWwno9tfRik\n+39KrIHJKwxq/TH1d0WjfOuvFBz5Ucnh86NOSnffz7kxLgP8QcjQkwuVTjDj4lTp\nsJpi/U1npAZ6Eu1/KeC3R2u8qqvYG3U3G6cQYw5Y+0wHf5EYlIvKfx5oVEEf67pz\n7q2TffqoOV7PQHyHt+/BKFJI1ehj8W/2uQJJ9UTmGvixAYLZ6gHLmtEUj1cBZUb1\n5X/lVbbsiL8B2prbuPoJWYcppH8L2cqSq4JP43Y2VR3CtrQH9MBbLxBfPVnzuD1j\nX1J++xMMN7NCRpBNI/xoJNxvxO+3RgNbkhz4f8WhJbuCwaoNJStytq2fcqOfT3t7\nlW10Gj67joMJZtIsW7JPquFGW6RNq7YqMCJ9ML8Vv9B9UJcUEeE+a+IX6epJBQK6\n1KC6TIe4SB+xl1Vu1xosuAyvni2H7QDjbiZvE8WX2apKk7fv81Epi+9J5Dn4zMpk\nZ5GG1/itA+rZSCWCs8c3lbGq0olZMsXNNhbNZOqiih3yeaMw/B/3v/XMn98rliMl\nC8VOX92eKKBJTX/CjMuSU48mxNE8lQJaDcfld9JE6ndmiZWe7BpXEF8wYtL/NObI\nxZXfcLDsEHopPpU9gaRDZmtL2aUweliF3WIIUmoo/C3kR7ZOSJ5fC66a+yECAwEA\nAQKCAgAhLFxqen7cjJqF5+3w12wb9bKfqRwWssEQmwJNnd1Js6YW4FOeCLMEAEV4\nA0QCn07NAcj/mny0RvsPZmUT3xpUVEIFjPBNvYOGyGOOJvzuvo6B9sDG3iVgEixl\nljH+9OjjFaZqteqxDCgVo23JL2lRO4bvxXpqaX02eI3QJmnCgv9eoLD6G3teseJ4\nZWrg79EjwystAfIENvwg3TdUsUuhKOunQKpYJ0lbzscJqCzZI3otmFCS/bHmEnpH\nYdnxTmmMC86hJDqBBqxW9+i/0yhpUXFykVHQQ9PuIDBuAsILfPAaeCv3J4o3PWpm\ns5UFt3yMjX2oIOqBmsnPWvkkfp63Gr2rGfAMftXSA0l9VcyMPZx78jihZx43f8bK\nMVu4Rd/V1Yxc0n7fr/TTOl5m3Fb4rdOuPOoLEDUQeO4SplStxbjIAEwa1oFFSD8x\nxtsBhSP63+dwflkeuV7OgRP8Fsuu2MDnn5AHeHaM81J4smLjpZ9j6BdhWMVmimvH\nL0Y/MiScC9ngTXpop5ph1VzOXVM1R05jnt53P3UNNTubkndOnuBoa71Zbcjz1HkZ\nAPWbETt/1CgJ7aCN9CV7FYNA8/z9t4R/VObquwHE3qfzIOAzSb+rehoBr3nrtzAZ\nA4uUOcvgnHzbm9FG0ysdqhri830KxnYfzeQ+bXeZDGU8PZcuIQKCAQEA/BS0oeP0\n5HAPSFVtNrSMNHTUvprHyfxp959Q8gAHD8MmQctoEUcABARUeDNNZbP/pNF2lCWB\nrJfDLod8VZsViBj3coF0w4VinuC1hphEiu+He7UhOdS/PlpEr6Ci0gTsIIhqboVa\nvKdvaEYaEHVp1//P8yC+M9CtF/fSCNlRElqgWzwkcFxMB4ErTWnIU0+ni+GtcKMs\n4DrpAuSf4LXUBxoP6MBuTbRMcurEFE7Vwbslup/AZphXCF++2E5viOvXn3/uBPkh\nL/wVTAgjb9Vdd/zTQKYp8Ol769OosrQcfb6Aa6OBuGhpkUVVSdNiSqZrclVfSWOR\n5WoHHjiDiZ9a/QKCAQEA2o763dX7lKVTSXTAB7jTBMONrOX7g1gY8Dt2RvCzZY6R\nzLQ/mQOcU8r1PdJc3WEdHP6YYzWy+7buMp/vsMsu17UnVW3ac22vISOLwStbZ0XJ\nDvm7rPQvaBG7/EDJvSGv654MCPGyM/JEgispK1I4yTAKltBFQ2NebUtg8NBPqK0q\nKrRUiMB1H2QhoRIW47yFTTm3snosu1nnQ/qGDgWWUW2iGZtftN40HzXQPy2bMv2x\n/ATRjsWVJcdqytqlg0wYM+4Ekkz633cnR59qZ76o3DoNEJUoM5fBwTKNfxExKRSc\nWkqkXWoWGqkvXaW7jPec+8HQ/o15aLzCvhP3OIKz9QKCAQEA+n4I0SaY37eLODHL\niST4fdfq4E0mY0z0cCBca14jpkIh7heWnjSTi2pSFe/E5V9slfefga+ToFJengn8\nP4UQbGGC4sJJqVEOoxpgyBLfacCEPSXMko8aS3ef8XYK1fAWRG3KdXEGrZkkV9Xx\naJGEUCPgHJVY7Fxc5QhaKnjo2vg7iO3Gt/C/jGWLBi4r5r2snI/xrZA4s8lWao2N\nYdrNixEW5g7yjTyxCzDHD/cW6qBx6XV913ViZuvd1Ux8AO97IQAbIc3+cJRrBVbB\nAAxiCS2vLvrvino5ripx5MKd3UZEjrG34eu/m5/uFKJ9dfjRpJe5TFApVnN6B0nZ\nTBSScQKCAQAieroC8zYcTjSkewGsdjD8KGmaZDHYl7Zfd9ICAQkcNXC07Z624gXw\nhi1IUn6KAj8YiuW5iQgyg7pyTB8BMhyytQZ+iLUUzrH5NWVf1Ro3YaAFd8puz5sG\n/P0+H250IvNg5W8anh6x6T97lZmKFw+UVbrl7fdvWSbVcTXa59IZVzA2ynonlM0l\nZaOUiIkJ5nzVIQzk4DdcWyOL6uLpJWKAeB5Bkex4WTG51sCCpww78B/7FTuGHY+Z\nBSvI0tOXshKDZsJb3j8Zr++HchPUSBTVoWbcPdu4v/E2LGZ8LFcoFvNPn0Ts48aW\n8CfjyziaVZnzcbEp52HG7zh9yiKPTLddAoIBAEpS/V+z3Vu1iMdQ9uoBIdcQbcLX\nGYBoyyLEgmBBAYfNHJ9YTt4HwvDr57vgAqnadXmQh9+IRdpF7rSizr3OBqnBJE0J\nnbGLKvJArMw4IcF29JOkpuR3GiuigfYgQ0JgYw7fZwc24eesKwopDWutUexo0Tlc\nef2CmgR/+rymyEknpX8xT5ExYaNz8odguNjRqSohM63p2UXkdi5CLYpu0q28iY59\n0s+3LAwsLPeZirR8TZ0NgirMMAIrILsCYmP78OGV6stOEUj1oUPIu6Txa/Z20saA\nb6z079eXrl1voiiRyJ0h7tHL9VEQA62dICHY9BY1I7H9ZL+Fi1Af5jfXGSs=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP256r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGIAgEAMBQGByqGSM49AgEGCSskAwMCCAEBBwRtMGsCAQEEIBfCkWEWyc2tHIvS\nAo6hhcj09dnh8NOmtZeqGmcXHnIqoUQDQgAElux3elmSzb/WqEZXb1vdXx/tcIpC\nYq2vewG8H1SikMoACeFVRcjuy31gJ4Q8M7UQmrR4+WXSptV/UQ6Gkt3XuQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP256t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGIAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCARtMGsCAQEEIILhgc3joEZDWMDm\n9TYgrENN7gbqtMpMw1e2MTLwlJhCoUQDQgAEiDN20JP8O9zSK46tP6MkXJPNAfyN\nIQ0hOgcQ//Fw5V0yiSU+BPGeDoIDsW8LnElS1hIZWq0JVQNZge5ei2bshQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP320r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGiAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCQSBhjCBgwIBAQQoNifTnb4a5dOR\nyr8QFVM7Zkw/f/AMm5T5PQ6iVTCzrnw/kZ8glwl+JKFUA1IABHSnWUC/tKXpNHGE\nP89QVKEgvetwCQWFoOENAgXORniLiaLdAdsR80ouTsZiFgHG9su0l5ESEnFWQr5x\nUMj/vPwwhSYm+YP5ucx5NezuBM4d\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP320t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGiAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCgSBhjCBgwIBAQQotGnirBX69ezE\n7a9yIBQcqeCMm7hc5YAG8D4396ytBa/2/O/lonDlOqFUA1IABDQHDepa3l/S8Gt9\nWrNCNpCPZNBXvmkGPnVXZchZI5BtUySwYxHX1tpatGs3jY7drVYm+NyxZE81pecY\nTvXR8bu7e3BIp2SwZmXEDxdYp1fw\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP384r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG6AgEAMBQGByqGSM49AgEGCSskAwMCCAEBCwSBnjCBmwIBAQQwK6y6NydLMTNm\nLhDNPyTDKEemTWTUuMGfBQxEz+lQKAqz/So4uA+fQzor/t8to+uioWQDYgAEaK8X\n3KCyRDMpbACw2xG4UUe9OxyuGWFaGKPxhKJDyW5Z56gT5P1Q2y4CblL/X9VcDIMX\ndcQqRNBkPQfy1+fJXwKO0ClfD6MIE3bv6PTZ55J6H2H1dpg38a2soRchz0FN\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP384t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG6AgEAMBQGByqGSM49AgEGCSskAwMCCAEBDASBnjCBmwIBAQQwBGUaEvTtnxm8\nfOWj2c2cX4991rvGmfGviuWWQRblSii/v9FG4nQ4Q2IrgBy+hgK9oWQDYgAEQL0d\nQoOTArIx70V/XxipoxxBeKT7zmIe7id5pQiw4O4nA2S2BFxQF9eW9ipnm6DaN6ja\nX/+2k+cC4qIfqzeLcLUFXxz0qdec8lNNtr9QmwoQlv11beeHmQu9C1GwHmvG\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP512r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHsAgEAMBQGByqGSM49AgEGCSskAwMCCAEBDQSB0DCBzQIBAQRAmEQNFMGIDLoj\nKtdg8V71WdSs7FiBkE6Bft25+yY8ohugk/u8aKeIKNVtSirMgQhGFJy/BIBkvM6V\n1JfnrglkjqGBhQOBggAEYbjTnA0x42NdM7jVv7jAoZq0iOYopbwejlOEsx8/MqRa\nYt4Ef83holIsgOHWSeW+kw1oMDmieoCrhnkM/3KgGzV+BxCeieAWGxABsj9YhAmb\nATorRJ4q/pMxRq8gIUv05/dGuUttl1gdbKKnGQjxDBM4v5H+/4z00nzzj4Gbfx8=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/brainpoolP512t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHsAgEAMBQGByqGSM49AgEGCSskAwMCCAEBDgSB0DCBzQIBAQRATamyZ088BsIP\nScslwa0I1xfC0/6udycncr+i/QIFOXNr4OQiVb4KC/CS/2FPotVMFSHZfCS2bgi6\nYvg3Mta5SKGBhQOBggAEm/uIqsytMZypsqCuL0jwZh8xCRVEkUd02YPXcOBhMzS9\nbhAao4CLAuXhWzplr5qk/7ttvczl7qFDOvBzNAIieZHwbFrouZ6Pew8pQXRcMDB+\nFnXwNgpljTNmz/f1ePjVKU1ZgbQ+xVf8Qt8OI9S0Pla8siTgbVweGMLtq0A8Wuo=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/dsa-aes-128-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIDzTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIJ2oQD0S0aMcCAggA\nMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBCNXluHkzV+EEdxlhmcIAWBBIID\ncAWJ20CCQlOCxxCddujc5gPPotUyKTbXA7xI3J9DdjrqBaHrNY/Yii4Zxk9lpzPL\n3x3M3O4C8nJjk4OEA0fiyBYOV1d+KZfa7UZojIe/e+7BuTH9WAvgVzORYYEFX6x7\nDTTmYH6VSej/RBdNTV1KeWA4+20Zn+vqCwcBG6R78cQDP3xGOmT6jOAQR/0kkqEv\nGN22UGpuMlHb7SDiYeDRqQPdRMkpu1RZS37MWEZ//yuwqEyaowK0JgTVGKyibf3E\nqXYV7TqEumdfrpZxPXkmJwswUSoFwE1wM0XU5WMg+lnNiroaVQjzqLEEqENpJ03c\nY27l0m83GRVvISvwLGOKY0Sbcb2d6NnqBjbVjbJopjBrww3iiTUqGiQZTFjiJ3CD\nVNKdG3HPWEdjZG5xoF9BLF3ZVz/jrfLkK2RcZBs0U6SyENd3H1gOk3yv4Uw2VjXi\nh/PA27oFJ2I5DN9bcHhbKVMFykc9JZbisDO0TNx6gbVxZUdNEER0nsP4/sZCwXp+\nK7rGvrUk17vBesp0K/tTfdBM2xVkV6oCMKPeQpsdekwCSAdNamSpxZn5LqUaX+Gw\nbMf1FxTlIL0ujLiN6/U3VWxLuJuoJauFyM5wYlpqgBOQIszVREQqMOs/Zp1WT5uS\nVUA7tdcIpSE7aA3q2rg1BkaiLMSEBMY/XWAI6SCj7iQyRD6GDse/ayJrQ4rUPvD4\niRLQN9B1BYwAplGX3Cmi++Yos7tOq8D2HfTDsI0bHAi+oSDTRUAsiezx5QRLgrp1\npO2dyBlJ5HOlK4SA8h5CMlk2fVgCLGCZ61VcqF1DHu5NKuCnCR73QrwuZAPlo19L\nJt1YAgcXBfFoSbjAvE+AXcxu2uw+t2kj6cjGRSRpBNSHCn3bJ2zu0qrPL3lOMhtt\nDYp0QNWJkW/6/fpmXXAYQQv6bFY0Bia8Ima9LATcCwpYcRox1pL2rvU1EWLDVy6N\nPdFdlzLM7UcrY9Vy40gEj1qz9epAXqzfPkmbyP3i41BjKlZfmmzpJEI6hIJMtT6T\nxWU1Kgg+mAED6STAJ6nem2bIEzMfsNM00VrHXoLU4IWPCe8NMYOaVox1xBWs1mer\nlu9dgGBAy4/gn6v55XzjQ4R16wyiiJn3ZQGrUD0AE6N2E/tfWiphVG1tYDjjWCLv\nbXG/U6P6DjClkBocb4DgKBc=\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/dsa.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIDXQIBADCCAzYGByqGSM44BAEwggMpAoIBgQC1d6MOqEDLxjfjz1v7Vg44bBBX\nVOoNdWhvJPl9NL2Js57UmYGrTqFit2VCLxbS5FVLyOZ25S0myQRsEtKyi4V9+ELI\n0q3oQplm+l3tZqKjtO69ZlbzYSl9IG1254/FCwBnBTuN7Vl6A2vryIhY7cL4E053\nYy0xqfP7swPgMYNBqjc9c53hNHKiseQJ8Q2wFKZqm13xgqnBqmWbm7yNmzKJbjMW\nZt3/WpJdjqfRnjSljFOkYPPBkGRUIKHcZ9fw4odVov2vblGzXwR+sFeE3lcF50WN\nuppjszMXlqR4y937CUSFbCabatRHEcPTq/FxioERCrCdx3AKOfwAquahtvWb9V7A\n47FlibDDeybh5jCH0j9HSjhjSiDZdadSgGKFynPNlVAlOETZKGqkeqAZZ+dsPkVO\nn8tx+VXZJF00YSe1HLKJUWXaT1tEGF6vw/dXhhQVir4j63fN2tZdhTOW1ao/J/iT\nVYEQQjYeMKKuZQveBKRBlpAjhmjOztbE8VL4O/cCHQCxPXlCpORbfOMEEGU0hbEE\nHsxFHMXHCnURCJxVAoIBgQCBqsk+z57UndC1Ut6u19wILXs7UBgLo0ivId2QHtm5\nkY77P9/lNOyCIQkBnULbJ36lHm6yxLZ8imyC5Lc7wlFJpJ6PpiTJ3nPi3fzhbftB\n2KCJVSwB3XfkjvyyS8bfwwqyrmce9el+AIFJuWPrFSkjNthq7U5vU5a+uNT9XZrs\nEaDbjkjVJXRX1oDS3IfWXWpb9i/LOE9HU+NfDKfydasWASvwNX1F5BKXD0AH9adj\n9Q7b0p4DVTh+UPWLBk9/e6gsA5HaRI1urAMNxs5Xnmd8UYF1I+AmjQ9Mi63Pa0YW\nQjpdH2hoOQGLemQ/72woFVzLaHWBcTuSwjREilaAA5M8CWq4rpuA79MrcHgzSp2C\nW1gtZa2/3SymcJ7Py2PHbncod8gR9dxHWVO07ccOXUG0iL9m4MzQ27uVvTh8Nrma\nM+JET778E2FaAkAIT34eNMC6Yk2IDrxU9L66FFx3+3n0cOeWaJxIWrIQ6uWk+uIH\nVzPsZAQU/V0/QBABlHuSj1cEHgIcYTbB5VrbIgust0jVvQCnlF4b1V0qz2iDJt6o\nsA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/ed25519-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAi1t9NlcmE8TwICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJacGnDl5HIWWbv604Vp0CUEQDEx\njZKBJnhmLTPMJbE1TgVe+9N8ZG1CVpSFz0xo9xCk15G4E9jgxXw/a8Sqy7NiDqRb\nFLJrSStMU+ygP7wXIFo=\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/ed25519.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIJ55hBE+FwS4M3k/c45ZJKPHtsklKrb6qJlER0cMJ2rn\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/ed448.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMEcCAQAwBQYDK2VxBDsEOSSF8O0uKk5pRrjUNV+QgonwO+WeDRb/i1U7vM+TLzh7\njAV58E6oglA53konKxGv+GC38dCb72gSeQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/key-rsa-encrypted.pem",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIX1pl8K5MBZoCAggA\nMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDAZbI9gwQvuQp1MWqsGkJeBIIJ\nUIsFUQY5CFVcTqF2wNDdyA/5X4YvQ1wKPwYdSIHhGAe4UjljSqUBG5StfZmdA4aT\nDdrzdApbZxP8BUlIjrjfR1tsbgnvevEkWUTftA2jzOmKBmYQ44WmQV2JGz6rWcH1\nZUc0ArKq1Jz2OU+JnE3Olrbf4QupcYCQ+qgB5Afkp78hMUWiGPXaW12Ankjk0qVU\n6zKiLP7cpignOlDTth+pYe/ltFQr1cLSgTsas/9X565usS333s8P7RQQsPRa5+De\nhsgZIGeJTX6RGG0ipxZjd97jle54T6UPnYQWmHHZuX0LNqThTeUHZxPaMLJ7jnFY\nNtqNvlXydkWRqdVmP2L2uk4mECrQrKqcqLIdlEL+sB00t+hjNtyCh6dIaQ5rbYDS\n1k7fNDx1m2k1u3ydtUUeN6/7OJ7X1Is8k3WDTxHguFDz1mmeCw0lgH9tWZ4peG0/\nhIP2p02icaoSx24K7b6yHShJ/+B6lp17tYe/FgVBzO75tB7ljH5bZjYcZ9iIGy9h\nT9Jq53M/lAnsAADLt1fiYRTWq9G5w/wzl0vqNTVpnpE7nXTs7d6Di812k8uyf2G+\nRU8Bsv50SJEZzW4liXhGxJXaI2TKKa8o27vPm/hK6cL2uoS6d22+/dUL1yP0ZXl7\nLOgqnNS3e6wT5xfdbXXclGUER8jP1QRPTm3evI13BRWHswLTeHWmdivZFrCHHw6o\n7f3LARYLkefwO/FsC9IJzpdgN3B4V/K0BIcVYwXYgrqUIei91b+3EHgqvB3cXLdG\nr91IBTvV15V9Hz8FUmTo+0uRdP7nrQ9+4451p6RP8FUuaAV03/a47YWemkZtqmzd\nzuWB/Eo1fzmxrbHyXZoN9D04ubOB9S/6jUy9N2IwQykeKy+go/FHltQr8l0JhkKs\nipbaRc719n2Fj/hBkaIzLl/nxK2KWR2kCAiVXo8WHJOzzRlgEMUCbgoNbvf7X+ek\n7O2VXOR2ZrqDSXs0WsZsq2LeAXlN2rIS3TKVru1T+0YKe/z/qZFvdygkTGB0qX7n\nG+v03iRVSGingsl3UiW/S0wLDxdxnBgERggD+YSwQ/pFQTPn4AOe7xStW/2/d95W\nS6rA23ijN+U3O1yN1jCJjMZUFK4DDwKbIUyqcF+m8jvYLrvYxNuVh3pwwDbGARGF\nq3rzm4K0UUeCZa3sBlV9EkVhIxdibO9fPFP/9o+pGHacZ9/B0QtCXLfb3RnRX3AW\nuM5L3gMd14TeIaeTMyHz4H9epUNwph022TKV98au8diLNGtB8eNZuu4wAYTfwYfi\nkUcS+Yp/EqwO8/evdCvWSe5xJ1QuLcl+Fr6XGEs+QmcGNDSq9VaqNu5QndZSBR26\nZv5vGpukqwxGXdHmETvLavam4io4Q/2XUQgZLdCTKxs4Sf3BiAyrW0DWEFQ0vLXt\nFFNQ6AXuVe7jvaGDox86RZ3bHDwWJePBAkQtOza/lFkvLd2h9bcjppeHxznr36Ha\nAnVfIJ57sjBlQA0bpUmTGDkcC1FmRnM5ADQdCENu6ZCkgkVwpFeYfJX/Vk3wMH41\nDQwSF7gP75DDLBnwyb8WooMWEkULBzBEa6N6koZejmgEaULv0aWN0BhE8G1XxVq+\n+hOwgNMVm0d9UrceOUsyj4G7UpJbMO0jtLSt3PWE9xfCqDm7vVPf9sA3/Qa6YtXX\nEkNCfItqqbYBWsNKzNpZXDpiS26DFhpww9JrwEL2KBRp247ANxZxG7dhk5H12+Zv\n2c49np0/zAHAhREzuebnPZiWbEMPOM0y9WxIhbCN+u1E16nxZWDeNagDsOCkiNrR\nc02C3U+MZd6S5oYT2h9kc5qq9NyCkJQTFO4012sBYn9LZ0aFUXIPPCilrr2dRMJG\nCUMGrtMfbauEQ7iZYSCdg1PDNmtrv3sirJWZueMNQhEppdtYiV5gfCPVl0sa3fvP\n4yLiPiMMrTjspyXq66jTR116Sm0ZdffDZHGDFUSFowEJZ5JbigUsQDvRwcGjoZ//\nIKT3PPQ55tukuD2WmI2FT4j9SYr3YSBWcraY0povPanxwAIewZZW9BxrOgEDthkY\n7VPeShzcJ4z8O60ioJTtR7gZYhcy9NoTHM8sbXhHS8QloWa22cwXACtPtuh7ErQZ\njPHIhb+KLFa7P7O6ceTYwZlqUnA+HFI9VHarrutxqRaUWa37JAEhd1bplmxBXDZo\n/8S4pNVlxT9xQmuYpN5JvWCeUadV5SwHCGVHcIDVsDVAWF6zLYwb6zWF1i3uRYTP\nFNwZx4DiskQhQu34QAnvvajZ1wZf3xJ6LS+exOoAZ8Z/qyxWmDwffSvf6Nx/Tw1r\nwLFmKTcMGxBUzGMJ4txp0tiJIHYE8IQMYWNOBeB/GjRWxTEBl5doFpXpDdFz+mfP\nk/wRUTkbuRg1KxXV2GPGB94m9elePD+Rf+m0Hl9rWPGsPR2JE6lr6k/kUYAWXuSh\no/3w85skoGcAe51EVvtrtqbPTTcd/ndigKI7U4shQnZCm8nUISYlIukor2vNlIuw\n1MC94zP2sfWBreka5VAC3IsP67lkdJx6DLvv80GJ50O7u1oKjQCroEKGC22puTb9\nNZn0h8BepBrgY6eWA9eZyrJ+v0HfMKN0O4lBBhtcedHTGZmBhKffjS0KTqvztFyo\nvnx86mIoiskANpfTn1QWSHxVJm5fNlRNK3DdCDzsQ8OcweIGc/omcg1MYp3Qav17\nE6HoYWVrYUhVbzrOPiW3SorE5c0Xk1tTZQXH212mt3RhMTPmrqc6+PVIwFfU/lzi\nSABjj1Jws9QLbb74J8O5eP4+ZxAvkZtKaLTBibJhYOGtGIrsWzfmcsEzCH+YUPYz\n3vMT6E6wB/KazfI3TWc2g0eHklu7mx1HDlR1V6BOfJ3tOMOqqOOpvAp8A3J+TULB\nZlQIOlMYH+fnQfRg2FcVHGCik32h7HdjeoZha/Qsogrg5j4LL0NkJf3k5E8I/c4L\no7yY0rPMKt6qmmZe4msO9wFGomWCms5LBV9K3H4bEtNdPs5rdP8wO8C9NaGRuUgZ\n3pPm1AYRdxJNW3TGR+D7nTuDrRIKrxMkWyKOkwQteWAqI4OAiMezhpv8X0+pq5K8\n8rPROuQkq/znG8wktQ0V6P+JjL1oBayhrpadgYY/tc1+S8U/zeeCPnFtUXLLdk/K\nstzs8gsvZCWWn6M5mlSrsyLaB1sgbxbuOlaH4FlUAYZC\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/prime256v1-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjZ2eXtLFXLdgICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEIlOTfeoLwq9Bs9TFtw7VSMEgZAU\nRO9W+K3vvzRG4sACrcFaB7PMhv3+HUOcPFf09QHa7aSJMWsb8EXGFBK4xlFhkK0/\nN0C8sRtH2N1JdYj9hiwS7I8WyybaR2W0ZALNR57iLz3WsOGQ7nVECFprElboqnSW\nBtjkKTD9pz3xX/6cMkDV/2WqbS6Y/dzWJTH8yTTqjzTjbs4vguEK1Io6dlIRVqA=\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/prime256v1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguc9upTMQn8b+loAx\n6c8q20dHYBf3V9374I3kJIDmC1ShRANCAARnLuOxL7n7Gq12zd9vq2neAv6PYc1h\nW6M2gJKSbfFYGhte382jOJ2TgwaTQL/J5IPSfuJKkmAPBIl8CdJKWlwA\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/rsa-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIX1pl8K5MBZoCAggA\nMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDAZbI9gwQvuQp1MWqsGkJeBIIJ\nUIsFUQY5CFVcTqF2wNDdyA/5X4YvQ1wKPwYdSIHhGAe4UjljSqUBG5StfZmdA4aT\nDdrzdApbZxP8BUlIjrjfR1tsbgnvevEkWUTftA2jzOmKBmYQ44WmQV2JGz6rWcH1\nZUc0ArKq1Jz2OU+JnE3Olrbf4QupcYCQ+qgB5Afkp78hMUWiGPXaW12Ankjk0qVU\n6zKiLP7cpignOlDTth+pYe/ltFQr1cLSgTsas/9X565usS333s8P7RQQsPRa5+De\nhsgZIGeJTX6RGG0ipxZjd97jle54T6UPnYQWmHHZuX0LNqThTeUHZxPaMLJ7jnFY\nNtqNvlXydkWRqdVmP2L2uk4mECrQrKqcqLIdlEL+sB00t+hjNtyCh6dIaQ5rbYDS\n1k7fNDx1m2k1u3ydtUUeN6/7OJ7X1Is8k3WDTxHguFDz1mmeCw0lgH9tWZ4peG0/\nhIP2p02icaoSx24K7b6yHShJ/+B6lp17tYe/FgVBzO75tB7ljH5bZjYcZ9iIGy9h\nT9Jq53M/lAnsAADLt1fiYRTWq9G5w/wzl0vqNTVpnpE7nXTs7d6Di812k8uyf2G+\nRU8Bsv50SJEZzW4liXhGxJXaI2TKKa8o27vPm/hK6cL2uoS6d22+/dUL1yP0ZXl7\nLOgqnNS3e6wT5xfdbXXclGUER8jP1QRPTm3evI13BRWHswLTeHWmdivZFrCHHw6o\n7f3LARYLkefwO/FsC9IJzpdgN3B4V/K0BIcVYwXYgrqUIei91b+3EHgqvB3cXLdG\nr91IBTvV15V9Hz8FUmTo+0uRdP7nrQ9+4451p6RP8FUuaAV03/a47YWemkZtqmzd\nzuWB/Eo1fzmxrbHyXZoN9D04ubOB9S/6jUy9N2IwQykeKy+go/FHltQr8l0JhkKs\nipbaRc719n2Fj/hBkaIzLl/nxK2KWR2kCAiVXo8WHJOzzRlgEMUCbgoNbvf7X+ek\n7O2VXOR2ZrqDSXs0WsZsq2LeAXlN2rIS3TKVru1T+0YKe/z/qZFvdygkTGB0qX7n\nG+v03iRVSGingsl3UiW/S0wLDxdxnBgERggD+YSwQ/pFQTPn4AOe7xStW/2/d95W\nS6rA23ijN+U3O1yN1jCJjMZUFK4DDwKbIUyqcF+m8jvYLrvYxNuVh3pwwDbGARGF\nq3rzm4K0UUeCZa3sBlV9EkVhIxdibO9fPFP/9o+pGHacZ9/B0QtCXLfb3RnRX3AW\nuM5L3gMd14TeIaeTMyHz4H9epUNwph022TKV98au8diLNGtB8eNZuu4wAYTfwYfi\nkUcS+Yp/EqwO8/evdCvWSe5xJ1QuLcl+Fr6XGEs+QmcGNDSq9VaqNu5QndZSBR26\nZv5vGpukqwxGXdHmETvLavam4io4Q/2XUQgZLdCTKxs4Sf3BiAyrW0DWEFQ0vLXt\nFFNQ6AXuVe7jvaGDox86RZ3bHDwWJePBAkQtOza/lFkvLd2h9bcjppeHxznr36Ha\nAnVfIJ57sjBlQA0bpUmTGDkcC1FmRnM5ADQdCENu6ZCkgkVwpFeYfJX/Vk3wMH41\nDQwSF7gP75DDLBnwyb8WooMWEkULBzBEa6N6koZejmgEaULv0aWN0BhE8G1XxVq+\n+hOwgNMVm0d9UrceOUsyj4G7UpJbMO0jtLSt3PWE9xfCqDm7vVPf9sA3/Qa6YtXX\nEkNCfItqqbYBWsNKzNpZXDpiS26DFhpww9JrwEL2KBRp247ANxZxG7dhk5H12+Zv\n2c49np0/zAHAhREzuebnPZiWbEMPOM0y9WxIhbCN+u1E16nxZWDeNagDsOCkiNrR\nc02C3U+MZd6S5oYT2h9kc5qq9NyCkJQTFO4012sBYn9LZ0aFUXIPPCilrr2dRMJG\nCUMGrtMfbauEQ7iZYSCdg1PDNmtrv3sirJWZueMNQhEppdtYiV5gfCPVl0sa3fvP\n4yLiPiMMrTjspyXq66jTR116Sm0ZdffDZHGDFUSFowEJZ5JbigUsQDvRwcGjoZ//\nIKT3PPQ55tukuD2WmI2FT4j9SYr3YSBWcraY0povPanxwAIewZZW9BxrOgEDthkY\n7VPeShzcJ4z8O60ioJTtR7gZYhcy9NoTHM8sbXhHS8QloWa22cwXACtPtuh7ErQZ\njPHIhb+KLFa7P7O6ceTYwZlqUnA+HFI9VHarrutxqRaUWa37JAEhd1bplmxBXDZo\n/8S4pNVlxT9xQmuYpN5JvWCeUadV5SwHCGVHcIDVsDVAWF6zLYwb6zWF1i3uRYTP\nFNwZx4DiskQhQu34QAnvvajZ1wZf3xJ6LS+exOoAZ8Z/qyxWmDwffSvf6Nx/Tw1r\nwLFmKTcMGxBUzGMJ4txp0tiJIHYE8IQMYWNOBeB/GjRWxTEBl5doFpXpDdFz+mfP\nk/wRUTkbuRg1KxXV2GPGB94m9elePD+Rf+m0Hl9rWPGsPR2JE6lr6k/kUYAWXuSh\no/3w85skoGcAe51EVvtrtqbPTTcd/ndigKI7U4shQnZCm8nUISYlIukor2vNlIuw\n1MC94zP2sfWBreka5VAC3IsP67lkdJx6DLvv80GJ50O7u1oKjQCroEKGC22puTb9\nNZn0h8BepBrgY6eWA9eZyrJ+v0HfMKN0O4lBBhtcedHTGZmBhKffjS0KTqvztFyo\nvnx86mIoiskANpfTn1QWSHxVJm5fNlRNK3DdCDzsQ8OcweIGc/omcg1MYp3Qav17\nE6HoYWVrYUhVbzrOPiW3SorE5c0Xk1tTZQXH212mt3RhMTPmrqc6+PVIwFfU/lzi\nSABjj1Jws9QLbb74J8O5eP4+ZxAvkZtKaLTBibJhYOGtGIrsWzfmcsEzCH+YUPYz\n3vMT6E6wB/KazfI3TWc2g0eHklu7mx1HDlR1V6BOfJ3tOMOqqOOpvAp8A3J+TULB\nZlQIOlMYH+fnQfRg2FcVHGCik32h7HdjeoZha/Qsogrg5j4LL0NkJf3k5E8I/c4L\no7yY0rPMKt6qmmZe4msO9wFGomWCms5LBV9K3H4bEtNdPs5rdP8wO8C9NaGRuUgZ\n3pPm1AYRdxJNW3TGR+D7nTuDrRIKrxMkWyKOkwQteWAqI4OAiMezhpv8X0+pq5K8\n8rPROuQkq/znG8wktQ0V6P+JjL1oBayhrpadgYY/tc1+S8U/zeeCPnFtUXLLdk/K\nstzs8gsvZCWWn6M5mlSrsyLaB1sgbxbuOlaH4FlUAYZC\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/rsa-des-ede3-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJnDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQInDrn6GvZlw8CAggA\nMAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECNwtOc3eKItmBIIJSNZzJs9X5vLX\n1PNFSOjg2bDJFXWJ4X8vtnA8g0JsK0+kGmRxg+FlWXTqAGJbm0imoE4YSQ0NXkfj\n6eFtgebm2zdRRfbABJX/drZMSIDYl5Le7B/zqIeI9cO16GDEbyDam+MXD+mRt3Bk\nJ4JyJPCin22nAtKb+D0zHs2F/9Iwi+3IYL1awvHspfOQVwARoj9Jc0K98qtGSa9M\nKikC+0LGr4zw0fOSMzrhijg5mqi8wTsYn/9u5+TkQ8cwg6cBKCGCjNOi7ml6uyC5\nLE4dYAcSkFbbRRNOuM/RYiKxFpGAFrfxUVfHI3dLjDe6DUAN18ZmLitij2WI5TcU\nazfFRYMnkmI12Tu6JeKrFrhQOt4gUq1W2h5KwvKvZAikRvc1pE+X8h08S/kAwsUb\nPuxgAN54myeHIGoaxG/C1ImaRoSPquKVoayJoIwDQ2kKJJ5EdXFJ56SyA1kYk4y4\nOhv+kvk47ZAwFZnNz+Lt+22uFOnrMZobv/jKsTRfJsz0QhwmTIaB9C5QehkAeZJD\n6M/JVjRWoLALcNu/S7imzbzNBS4r1ctYLv2dkakzBhR4o5Yfn4sg48p1x5EBTTre\n6X3/qWH9z1vtpJsjC7vA4ACkLaz0Vb9Tb9No+Sjjp2xi6arJphMwjuZ0LPf0EuVd\nwzbkRHXzpYMACuaypNaTQrNCgpR19eV98SThrf8QkyyKD0qwtzwoTmGX45FnGFWy\nH8HL+lZzfpA9zzRCjqLGeTkgQJLIMP0orD9kkVYCHtUorUQPr8MIu/o45PKCZtNd\n++kaTm8x+wjXYNK+cyOnyda5rj3XsMYqPnMtdg42cHu4oODEV1JH2fl8sXpuGB4A\n7qsSBORrZJiPEdayT9Gsve0A6Vi7gGK+9a5WRxqS2Hlbgr6lgqUr8zX1YYi6Ace3\nd2GhEqNvyAX+6Cp9FYH7JauKtrMf40LxCNTpTmhhrhwS61nd+ka/5e8v6G05eSTA\nESbBKo+QiE2Ek1xfrfKlsc8IcBXxmPF5QQ7Gb9eGI69myPRNTv/XN4mnvA8bZF8k\nKqLp3lO6Y5jGKHToooViTDX0WRApJF94oaefuUbDJpW9foaOfZpBz4yhLnY7syTd\nn8LNRYbMHbFbbe5eoGhb6goHD1R24/SeKumDpzyj1HewcoYGP00toDFxijY/AA96\n+4HlKJX7JJEDvORgVEZ+tOGo1xplagrndpKnX+WsFzvuPJ3RNFifbkp7iRP1W6HJ\nGq+oZ0ewj3z4MKi0s58BgTwQENRmLEdp0G1nyYY1nuRmaq+t1IlvR0bMYhTARqcY\nGAdHdwJN6MXQWFyqTQ8L9N0OuCpENposKBvdUcrSFAIALafX+vJrB0aS0ZVM5w37\nyiskAa1KMqo20XTiH9z3awnKAVZqjY0oE2BTehdK/NWgaLH82AsxFIMFmN7GCyY9\nQOIlzceqRlltJ7PsTmvDN+pRaO6KdcbtO/7hsvUgZWOs6x21JRQHUShDNB765dlE\nusuEl3T72TBlTdxQ1tj4fA0RUCAF1T6B/9aW/rBsPTQIBLyJEr/78m7lBKmgQ+2i\nREjuQC8NYkzLLa+fOiIO9LTjPqdSpzMCqMIbjiR1eYMJHFoP+8E2gAqKZBDOaNoI\nV5tfZk+/Uz5AIYQocd1aUEQCgyf2WJLp2B5boO2lS1qXBb4YML/D2L7Udz4JU3Qk\nfkSlDC4zx01XdmmbGedBCGG3npf/pCerrHcaPJUWOjMk+M1tR3Mpmmm+/yJm4Xyu\nbPcvV4pEqlfBsIjLCt6xyF18vuF458yB7djtZJ3wkx9lLbpLAh/z7ywoCF7B35nQ\n+kUjFBsboV+1J+9sK4bULrtYOhjxAU1P7Mpq4BbWbRWBWK9/Kz8maeCrLEW/tpnk\nEureG7aZtwQz6vHyeDDQTpFVdeSFO4qFy7Pouf/VVzX/eph/6y3ZDsjYfxFiUD6z\nTV9aPs8WDDcWhd+voSQlBlBB4ttspQgZhefCScu6hhW5PNVFyNm/TSHleOEBXiEf\n0Ab4FeFkQ+c1GwhtvsmGLBP/2VzkkDSunO2QDbpNYGzR2Lsn56JQjeKwiTHblzRy\nAwSJ4DU/V7S2K4wu9QmP2SefrBJTlbLd8VFbwAGAHDeM5Xi/TnleaQvUPGz56F5l\nmoaYsXbDQGlyA+PYs+CCa9rSfvppX4EwDIftDqxAzEAIbQJir4VEiPpE/CrJtUc0\nJMI6ug1Cpp1p2U38y+POyv42Awk8M3KOPUvXxQkfU7leSClLh2zCAkC1CeUGLrZU\nG/Fuob5ZjjJ6I6/+3jF91Y6bDvh9e71jys6eTnYNfXs23f7uwqv7G0VqhY3AjXKs\n9YS81sdBNbZIObMeXA9w2kG+RLWB5C4hpkqgoRJHDyE06Vzy7zzWLBS6AY6/f2lX\nlNVUETpf7j3PU2bGry865V5eGS43lTUnsMUDVQL1OuiWLg30JUH2AP8cqQqgN+O/\nmK44RfZIrGz7o3currsobXBMNaqFqVlCRtdqEVsiRprWiGlHtLEnAh/UNVp3h4ca\ns9nGo0wA9bpHqAYzyJoDKRgjj4V7vk6rDNdJeRow9v4byVOpEXBY2WX+oRWYruyR\n+ArU/zAeK/6oUb4yegc25SGTZxEHlZvZs9U8Ft3SmzGDtuiS8tgMgfLe23fN8mUv\npRwRqkRmPYRZpH23MTWVBGSAos9nlP5MxA7IgclRywpINOJpNsbPbihhcjd5oBhK\nZK6eqdpYUdSWHpUdSUi3DhirYXWQA3bGjhJ/IuvGpqdXm2P9rpUArEjwuG7De7QS\nt65n15oECLzVg/3vZviKSC0RkW5p+pQEbVifxu3Azs8SrUlXsilcHMTnTVGK2wG2\nFi4ReqftHwy1JIAsMEeAQAvuR86TFaHKasw2p+/IenHo/cTAyqEJjgGeTJWjUtCK\ndUavMKA5ZYIP1E5/F0/QBNVToghoDgMVV870p7QWjgLVtPVCDPx3I7JKh9GBmNR5\n0dd3JMpO9Gkk8cBGwurrr/Ak8ynRLv0MRdB/8HDp66XiHR6tBl8ZoZ4ZsnME56Bc\nF2+OmOuxVThpOxPlECU8XtI37ZlSxbG0X/s5eBy2mmrVDzGQDYXC3VuEp3lrk8QV\nk1KU6zxzFLXnKEhZraP78TIKhvV7tiggyTBmx1emLigMqmd7AnVseY1LRlFQgUB1\nwloOOrNW1gpIoUUMVuRjFA==\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/rsa-pss.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEApfv1BYcLTl09aBmW\nOnwUEKxByqBZeCXLp6Ck6/plp3GgC9gtFMfSk7mImkIt8BAFWK27A0/vOFDf7SDX\ntFYtlL6ZukxSgaltyEjMVMX/oqB3vMsqzDX96So4UauDlQexWORT0LcUp3IcjA8L\nJrrZS6j278y3ah/Xkex56IRpfFbdqPj/p4rJMw0WFtqvINV6C2xGxeoC1/LcHM/H\nWQLpeRD5PgnIwUw/dqMYtV7nfUDU5wCJLe6I0ogdgmCGrAeogldFilakPs47yU03\n/b6qWFHaj7OwGZRV51R/GChS1HdVN42nsXHiIz26KPIf8BS6O/iAZlUaS8xhw5XB\nje0uIQIDAQABAoIBAAh8WZn3Pfo7JRUJ3dbOmh4CGHj5+qj8Ua2XtmbEDediFTsV\nybQ6xQa9YQD16jBQOV2/wARa1VGNPO18FNsI3tqwZd6S4VL0rQKkyiF5X+jaCFUU\nE/ONvRXrDScLvDXlx0jSn4BXo8wttszoRfssaUiHclxvHF9mEljI/LCI+HWdTAys\n+3l/Yn1ewwA2iFFU+ZcwgvZHXjLjRLfImTfr7oQLeolpP9sxfwb2RdQ24ifgIh9N\nYv9KzFfFJNl+2o3q6XBKqvjXYWmTam/hwXhGnFNb3LgrOwkSUIVpUJl52F/fu+BD\nAdJu0ELPUNIu2Ll0fBp3Efj80vcSZqtDSJ3Bl/sCgYEA6DZQm1L1Y2tPMcX+JLtV\nBKC19YRTJLI+CQsU5YnD4DN6O3a8PITfRf+SHWI9slGGs4QU0rv6NLMj4c0Vxsbk\n74LQArprdw768+hLH8z3r/fAZ0QrTJZSKMuGvs4To4dHvNSdc2lYDtadDysPxkKZ\n23aL3ApmCqZpHvIUndOGKV8CgYEAtvzWJd6faGWUEbQI2qI4/H2w/t4oxIgVDOeu\nqCjIfw3jj9QUQrzC/ckHEJrb9ILYuzxfe92qPf9qmqHyE3aKMCN4MFIz+PdfwM7F\nP3/QSriS+PdCnS0ysmHrUdJRXOsl6SYDVnCfyhU6HtL4GFO5expMesogpw2xXkYk\ngYOaWH8CgYAP0SNMcSoly3lpeoMFHX19AzVhs9G1/i4bj5WszOV6sAbzZfMMbECJ\nFA9v0PFC5Cq4r5Z7hDJWxJz9FGsXTxTo+5APn4MSaQLO+lOjpuJ4KfgBELOiU9rk\nzHgxJvhPezd3tUPESLimyheIoPZCGuc/+6MrKcopj4w5f2PIHFBXIQKBgQCN7qTn\n8LpyTj/AT4WCl8tdxNxRg93ZOrghL18gnamOKyaz+8rPTPxtvsyVC5jKGeejqxtg\nxzlyJzf3wt8yS4K5/fkOeeRIGxARTBBgxXG5U1rkc10e7tzg0eSlrV1glh/srIhw\nNqEqLLbNC9RVgjNfEbH6l+clzBAkUIGmV36TXwKBgQCI9r8ZYR7xGYYDTpMSbGdL\nXpWuNWwgZQsvBAH+pXaE3A/36tXdggA5nZH3SA+yIoJHGiXHeM8K9LOMAbAzHhsJ\nia/yFcH7lat92/28mrxoAkHHk5oUdIcP6pcPny3cE874sh/UPG7BNKrS+h2ll21e\nOFsE0r+qLh68/S0HZM1/eA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/rsa-scrypt.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJpTBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIXPgQcyUbFcgCAkAA\nAgEIAgEBMB0GCWCGSAFlAwQBKgQQAEM4E1Gom8Gno5BsBlIbbgSCCVBXC6unomo8\nRViDXg/JbarYH5GAj7PJfOHMtYVGWSuysLnoANxqBLsmxvfnzkoI6hBVkU+FJwyG\n4CZodJn/q7OxuK2VYtE2LV/2QgfBfhDpBSvcfoyfFy6QfBZaIP1rfp4cDucuHxn0\n5sab/On/lw2qALw5gS63uEJQ6GoTvTgkMiRVKLi/ozqg44mn7N/Rvbx58IUexcrm\nZsFCzJBNPp8Z4fKCTi1CE+Z7BemhAzL6JvE2IHBjaGsZyr6rKOYv7u1QC2KTUyEm\nFLNthxOAqCTaWGYP9cstE38fL0zE24crfOJaRd+7oZu0LwwF2R8kewSKNze7+WbZ\nhbDWu4qWTdHszDeLnEJTCX/xQr5uj/c6Xp89FR8ovsTY/nnt9cEhX+x2tzjxIuR1\npTGrJvgwL/3PS+4d/O5w7SBpSUSjU8/gPLSU+pZq87+1JRZQpiBUouwpwE96/PjO\nD4iQM7BcDLYaY+f4pP/K9N3fIBr5hDH+QeArfZ5/Fy96yXijlJIm18Z6xs+aoLbe\niL3coTVUc3sF7beKDE7Y5qlVBw/pTazmcwnUxP509j/W/+WLXFf6WjucH94ZchrG\n5cgi8LGtP+jnrfyoIK7lLBsT66tK3cUxjhpiiHebEQ2RpHpvutoiC933oCZ3FLQf\n3TzuuhWiY3ufIZ67xXZ+i13Gwt/f1OEk0hIecGbLheHKFykA2t36c+/3WZb3niPW\nwdwAzhPaX+nvrk5vsHVgdFJNrXyYwEg/ygO/F/0yXbjYUX7tKyWbb4ikhJdxjgZv\nieDC+9RIAMpcC7Ac7G4c2vNgiJlLs81apP0LGQ3n+eibCz2VJWzsWohbMXBTcDfc\na8yJMRaiOSIQlEwes5k3vs993qL9nKSGHHGe2e7PMHuVinzEgkaDHlDfIuFn1KnA\n/aQGbgU8jwK8VpOkjNZllaE2bPZibgQAcgctq/yGRbxfJcmX2HBKUoca1Z0ntLDb\nL4Y/hZb7b577NlWsepxfZRlVqj0KXIzTc2XrMz2U+4D5fj4+KUkk1z75gE3o8wGa\ndkfRSA+LFRCyExtoMSSSxIvlaHRVsL84kkcClh0IjRViGo2708HObkPrBxk8lMaU\nx7lLB0IU1ENjcqrF4rfLwh2K/b9AcOv2zcZ/zgDYEeRXEHhw48+/PzdQ8GRsSanF\nGNjZC9tJ6uCP/uVOcoUoHycD21WjSjZ9naGI0nXWbIUYb6uaQtwPKmNqQElwaXaJ\ny/ncQkxYDrOEoUI8fZFnX1PXHEtP9LmB/MH11RguZn6ha0onFvSMqb9ZWPWZH9FL\nL7tf2jMSHOXjwCKKGugjcj+RYg21P68PUpkCeKnDTpWe62Nx0CHGuylM9UvOS9AG\nO9N7XW/nzPtgoAoWnZafiE4bFea1w65OszHDFuK+k5zrF79dxb8ajJ8XCbhh+Ywc\nDAhNM2jMsK0Tx2rQylFzdl+KcTMiczeTSBxV/g78uoJ2H6/pks4AHkTZ5ZSe1mkM\nqt8DIVhTyV0jUwSj12Fss0yAps51k9UjrQ0iQaeJ6VCCaePRHQ1YyBJT/UyDLlBD\nOPgsUnC5CeN4sFfORAAhUq3jNZ8TmQ8d4RJIaqTrI3ItMz9kiBluq6uDQMJ8a0gl\nJDv2aocsar1dri7TefouEkPUwbkfw+ahlerKiQcQHmaG4V/KWyu30N0axJKXLMHY\nticksi9RzJGthbkHTCru/Rs+va5b7Tdxla8r9krRamkjxG7RtDet2czWNLJTCC0q\nVZAy4iMT9NeJTgvWkOhYzWPczkNiCDGSPJkyHezK6lYRbnkBR5KITiRsIjXHsH99\nLH/77bewFdyl2mNwy/0+6p+rLGnvPX1ZhxYYoKKKTmNsddVZh2xLSczvKi7Pd/9Q\nkALBSxMPdt7klPXh5BGte9WA/4DEsiyvmUwNsySCtgcMj9xiSJM3COhcs1uhmGch\nuv0Znl7VSE/1Y0yKQhW91QlA6JIGAh319t1VJYcbSiOt3FoCelu4ya/JmGLNtfKF\nAlMJrj1dqxO0pGwpfKHfLeC7G430TPd6ukjFwy+jrPn+LGw0Wzw5BS2fc6E2JaAd\ntfLM+AUlS7I/+O371e6V1g9+55KaGWsN1K99j7W9Md64BsqvGXeJwQtG+JLkPIiv\n+ETwbPe4yrcJgslZ0CDocwfLIMfv7sU8PxFXdzYz96NDSYU5HN9l6XACfBkYc5DQ\ntYqdcqDXIRAOpMhviZXkNW6HnaYugHIOIfIVDo1ZoZSNnQKAHt7jvjjQ/Kb+JvMB\nKfCtyJvDl19S3XhslRViEc0LrvE3xZIP91QM1SyhnqagVY142QWyB6vd/yiMjndO\nTk0bH7wWdk6DiQTBKO3QV2SWPkTy5+O4uHKPO2S2ebIEzi5btsgTkwsBtzS+bo4f\n54t1RvBqg9uHUHKg/PGBX+l/TNQnk8RBVXF3U/Tct2d2W14+YT/UbvxopFNizXHn\nG+kZvv3iOAACfYlGgqarZ5i/O5eiMtOBxE2iCwFq6h7LBH3R28L1pZ0U/pMBWG/n\nvadGNZQ5DGd82n15ieRqXeRNlFt9+jPW3T/eHDUEIqsCEkorGLzlyNWJrtn/0WyH\nyLeiKBSfyBrS/IbDCQ80kVYaFF3+m77kjpFxSN4ugyruPEXL+ofZQyzt/k9cprlr\nnPun523IiG+4bMWHQn8boYEWua28R9Cyn5q9C2HZskFAvEiglyEQTfrU6/lrhhei\nyZU88IL7vwc+8ajToqnNngPedRDkXlOVP/YLuoSry7oEV9Vb5PETypLEvdIwaOcZ\niTp1EKt+ZD+ryJn+D4vrhNDAGYhEDEPiQY9nHC6/w1/O/oAmbhwiqChSxTXecw2m\nKWZflrm53t0S1NsEvmzWKo5QgJlLbeMO/o9HE4xy1gLINXQQYDUBV4IVjYxsIRYd\n3TERnB5bmL3Efsa+rKXmYy2zNg+RVl5iK56K3mSlCo4dD0yAYT/tD7lX8brCCahz\nO35C+rkwdCIRr6CgCTRStqxJjndC+uyn7/SxfNMc57Mdb87UjO2DHiLAr4OUoq0+\nuOmNwygqpe7kzCD1q2AdueMCII5aaqVpVtJ//r+0iswlRaciWj/VMfTqTQDweSvw\nw2gQo//1NRalhDYYWzr0PfggIIcEhQfXfPCk2kG/6mCBfXKRvBm9+WrQkKS6zdJ4\noDEneepILtLCVoJewFPvdkpnL1xcdjveuw==\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/rsa.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCb/Jbg0D7zw7IF\nDBzn/KZ0kjPf+vkOaZOxNG/PosID2/+OKHK9oXgnZcVbEtvJgR4KKjc4nrSMFtFa\nBbwsvJWxUEqGjLQ5WahSe04R2yZ4LViGbFuBOHAWq9qtxRyDdkghrQvNy8cOr53K\nO8/UAOJCgkYr7x562QLEQ+FUvpGqID2xWI5TUxVezmHdU/sZF8bRyH7TtEZ5zMqZ\nLt2hjD8CrzFt9aMv2eBldX8c2YTi1/3YPKi8mos21jsyRFa8gPeyi/TnKfA5mows\nDWxCN2dvOw3ynKapFQV1QZief7KRxw3FGnUOdUfw/FqfpddZK7TJ3/AoaM6oNHy5\naAqcVMqPqb4ZC0eO1R6+xIA4SoZBD+ZTJC2khoVQRRwfRyKQJpp9eWJ9+SOGCkCY\nr+yZbcvGAuz7Y8SPp3kUWZwflofRCeE3p77U+icKkppkkmEJIb1iMm6qYoTjc5M/\nwTpI5qeQmGaftzz4dlWafTAbHT2jbwvSMgYFQQvW4RyV8Iu95PYl6aUg12mXwv6a\npYf0QuOPGCMP4UzfLfFTYDniS+34aaWkl77Lzmw98BRHa2Xjmn+iGQcHYjKvh7FM\nbRBiFxcSEWjkh+mgDypV+8mqS6FOPC7WeCNvt1XGIRoKnlF4OarZjdI5KP9wKtV5\nhhx6GQpeuZSWyTBLKbVIsuUiGG2VxwIDAQABAoICAD24HM7JNw9mkCqVF17nRcl8\nC9CE0kTUm16TO+ZxJMk4JA7QjE3h9NPJ3ePiO1qonwUwnPbnPNLtOFqhSEp/N8+X\n0FUamTjT89jm9wXzq24DqzJM74vak+c0imsVQen2RCYm/TOpfJKgBBP/xITC8MOW\nHkPF8k5zTTfxD9hjKumgpihkvLPVfPAtQuW7E/BiywU4io4jl3sb/9HKjGEeR9Q9\nE5bJiY8mazZZ3jjBDGZhRgxoO++cSpcg/v0tsxAVC2z3GajZnDZ+oxXPHdW5bFDD\nkgo712mxap5xnPyh1DsAAr/JbyWQXC3K++SNTv72Xys9Ux36EkLVub/2nbQrjJXb\nVc6eoJRpoeXwvfeqnJOaRUWqluSxqhxI7ngLtVxTAAM79H0GBdAEaB5DvU20zdu8\n7k3ggJ9Xoyu19KiCsC6L+Odix+vTyv+QmIQBGHB4Ts/4YrKMLF49HWpo2qjV9Zef\nbCKjjzz8VrFk5FyFWJQk8o0P9NLn6+epD7n/ndjeUWy04pLc9i3ya7wmojZZbWKE\nUpwcruX/el7A8t7cQjMKHO8/tzFVPsI7o2osqvfY/sZRBWuDe3iHgY40ROwvUvjr\n6k6qwIHPmJqgywmMbv0KD+nnjGqIYThxuvh1n9gp/JlI/QWOs26Mvwk+QFMbA+6g\nXfihMLpzLXWY+Z/7uT0ZAoIBAQDIFiDO/Z2VRS+vNlYOAAEYP0amVTH6Isza3bZe\nO3nvC47Gj4/vcxJQdrMHEtI2/geLXDv9jexox8YvcxQ6KeJVPSNRFVHGIEWLUK29\npEzPZDUl3xYFl/WTHLn6gxV7uqxO+Xz5TTCaMRCssbz69QZPryfdIZZ1+WXtKX6s\npaRhwwizln9c7vHoN4lPO51Dk1iP6JqcJZdRzPXHSjYSBnuapWBy62+rkHQBbOFn\nyv7WzhnbOEYM8GlvteDNH4xG0gcT4G81dOtGw4frtfpphU8k0Vy3LypjlVQr1Smd\ndZdbC9TT8kC2hyB3saCp9vQUc1U48CHHW7BGBYTSyaRosndrAoIBAQDHk6IQuF1A\nOM/FNwD2nao8I2bOJEYyPgaPFv/lUytC5fmCUuU/FKBdyW+0wtIQDxp/zG2Mq9L0\nle0E/L4WI1Zz4jt0tef7qDLm4tadK9foU4vFuFpfwnvgP8uAgzxgK45CTQU09X3N\nPRfw4Jp6BK1giEqLhuxXrQvhTocswnIgB2s4LUv6g2LEGpyfXCLBoiyBNTYpxHYq\n3E4VtOycxniwUWnR+PQOt9GwIDpjKHzZMHfEOOrOyac85N1s1JDxC1s5XftPII79\njNxTDeN7O/BP1eEQN1U5Qbw36cjrNzgxNzK3L8NqZP0YlSHpm1s816Am0+TM0oF6\nmKV0VCYYcd4VAoIBAEWPa9iKUz6RzwIa4c/8MGU9mlI5TCap8o4khkI8ayev3PMq\n9d9JIhTXL2ZGJM75gaXxaum7bXT//uaAG4gdB5KarqyBvOwkTAkjA0Pq2sk/DTsd\nU4qeScHbOszcxZs+SqkqE0iYjU0Nwb5IDGsyw/7v5ev6wVRCYC0TP/bFn2BdbakB\nqUWlzHPu2s2w6/uSPjfJpfajGvhVSRz/r8yUdGRPGjjZoPkEP1A/ih2LdQ04mcSc\ny72z1vP/RygIz7vPSKagYAk1nJX9ZEOOAICu19T09Ea7HwF/6MNUWCNlvjjo5BTL\nI7RRRfhWyIROVozFi9s/oH6uYZn2UTb24zGC2gECggEBALiIfECDh82a+hm7Cwv8\nqmwiu6r9hV5tVXk25fNv3D9mDzd+WHPkKYeuergjr0GkBXeHWP/J3CvE+Lw0yboE\ngKpz00/N5qsdUbuEoLYA1Qj/PuzZ0c5bMFkgA5VXQxsVCtupBZh7KQ/9XkaeFped\n/YWVX3/1iFBlM+fmyTwMqqOM2Im/8FG47Diw9oKvGX/66LWrsuIZwr1MqHKPsHwh\nU3SMQpEgZOG6+4qjsfj/dbkIhKUNj6cWc6jtYQOA5GfMfVPk3zrBuxUcCphM7jqD\nKGdZNlndH9LqQhNc+ibrDu0Kwbz5z/FvYUo6knnC6TCvm2hrYlI0jf4CaHHQYM0X\ndCUCggEACvTEoQ7gZMeaqr+j8fhsisLoRRCtslqoU27jqWTriISlnlvjNHqYOWb/\nJXinuvpiYZG5jih6KXxa26H+Q5Pb4amVNPq/d6qBu5yv9qpD3mCJaHNHPByLScZ9\nG+pBW+y5JXHCdFJjo6G4ipLLpPglAPte/TmEnoShGsxtgOmupYSliNteAz0ykvSv\nAt+UfdzdSY2uHC7JLnJjB7SeOz8YeXyE8KCBOAokxCjs0CdBeZDK46sti9umMuIr\ncDVIk/azvt5ex5sXP944Ds7tUs/qS1bdm5DsG4XYBkSKRhNqlkdxLumMPnGcwsZC\nJSRSgO3qryi1B/PjFld2fmtKpkffCw==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/secp224r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMHgCAQAwEAYHKoZIzj0CAQYFK4EEACEEYTBfAgEBBByDAgBh6UOQqYJSPoiNWrK0\nrA0rTMLw8JdCEveBoTwDOgAEABwjlgBV9PPpMfo8fo6yWRdT+sb1cUdEhobd+V/D\n/i58cWpDqd4CApevJWtkGbwhU4J9mN0aYrk=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/secp256k1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgAjoYh3zy6gJciB7F/pHi\nfU+IfPBeEhgQBFT3zNvox5ihRANCAATTIv3AIcnOXMvnURBseRspHsowmPAxPgsx\nLH5+aU2mW06f2PsIe9F8gG/Nf2UOOuO+aqwEStIkfSBR+Fwpl2UR\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/secp256r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSFp08cP6os9Fxmky\no5VFi6woYEqvbhVNYTp9NvwzBCChRANCAAQo6UQaiHkZr7lxrKDZyL9Qinr4Vy0Q\nW3K2EPFYbVIupvzW0RH8vBy+0/yoaNyUsw/IsmBO+A60mhBB4rTjmq6R\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/secp384r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCqdZTmuPvhbOVI/Vkk\nyjowWmBb1+81m+ay2QF15TZns1iX4HQlaOZ1GzaqhJRS0R2hZANiAASYw9dep7R9\nIoC8Dzt6T0NYOOJE/TPdOXOH+M6uJvKAtmXGalFeLQX6HKlUDNPnBDTKp9p6Nu/o\n2k/p2C9m0DaX70sNuyfOmh738Bw2Hlz3If+903Jj+hKSR4kWDkKYb/s=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/secp521r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAdO/4HyMRu7/QcjYn\nf8vynFJRVOKHVVmRFrAzZwkdusoqf9gkicCxcxhOpOGLezzTH4XBynbcmmMn4PNS\nZriTYO6hgYkDgYYABAAp8YOO/QeQoVEdzsOwZt1ta0/b5r0ESM/QNkBVgrRdCsJ+\ny3p/xis4wFlhv7lsrtuDoeuMimnvl+fAfptCzMKHugGBvSE0SjLgydEmUjh/y/a4\nO3cGqwUXnnxiLKJ98NFaooGYY+AwH4h77oCbQR1lf8jhe1qsJkR9mXpYuGnkaJ7l\nqg==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/x25519.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VuBCIEINAdGSXck38nDXMgbRKqKiBPVuxDirhOs9VDE+NaokZz\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/x448-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIGrMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjrmjUn6y1PFwICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJuU2Lvx741TqKFa9X8bRGkEUPYI\nSNtLGe+fIcgz7rF8YaTnA0oeMsRp4RxBw/fsaEGrHUTM1ddjuyRzdKKNnghZIs0w\nzy/O8QNXDzrss5bnxZyHZA2XEvftHTH1Mw9jCtwA\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/pkcs8/x448.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMEYCAQAwBQYDK2VvBDoEOFRfvQhj134qZjH0wDbmPc90BADiqrpGZSae/sd8GG84\nau0ISBY6I7BJJZdiLLED+0abd0hLYAyl\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP256r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGIAgEAMBQGByqGSM49AgEGCSskAwMCCAEBBwRtMGsCAQEEIBfCkWEWyc2tHIvS\nAo6hhcj09dnh8NOmtZeqGmcXHnIqoUQDQgAElux3elmSzb/WqEZXb1vdXx/tcIpC\nYq2vewG8H1SikMoACeFVRcjuy31gJ4Q8M7UQmrR4+WXSptV/UQ6Gkt3XuQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP256t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHgCAQEEIILhgc3joEZDWMDm9TYgrENN7gbqtMpMw1e2MTLwlJhCoAsGCSskAwMC\nCAEBCKFEA0IABIgzdtCT/Dvc0iuOrT+jJFyTzQH8jSENIToHEP/xcOVdMoklPgTx\nng6CA7FvC5xJUtYSGVqtCVUDWYHuXotm7IU=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP320r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGiAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCQSBhjCBgwIBAQQoNifTnb4a5dOR\nyr8QFVM7Zkw/f/AMm5T5PQ6iVTCzrnw/kZ8glwl+JKFUA1IABHSnWUC/tKXpNHGE\nP89QVKEgvetwCQWFoOENAgXORniLiaLdAdsR80ouTsZiFgHG9su0l5ESEnFWQr5x\nUMj/vPwwhSYm+YP5ucx5NezuBM4d\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP320t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGQAgEBBCi0aeKsFfr17MTtr3IgFByp4IybuFzlgAbwPjf3rK0Fr/b87+WicOU6\noAsGCSskAwMCCAEBCqFUA1IABDQHDepa3l/S8Gt9WrNCNpCPZNBXvmkGPnVXZchZ\nI5BtUySwYxHX1tpatGs3jY7drVYm+NyxZE81pecYTvXR8bu7e3BIp2SwZmXEDxdY\np1fw\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP384r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG6AgEAMBQGByqGSM49AgEGCSskAwMCCAEBCwSBnjCBmwIBAQQwK6y6NydLMTNm\nLhDNPyTDKEemTWTUuMGfBQxEz+lQKAqz/So4uA+fQzor/t8to+uioWQDYgAEaK8X\n3KCyRDMpbACw2xG4UUe9OxyuGWFaGKPxhKJDyW5Z56gT5P1Q2y4CblL/X9VcDIMX\ndcQqRNBkPQfy1+fJXwKO0ClfD6MIE3bv6PTZ55J6H2H1dpg38a2soRchz0FN\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP384t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGoAgEBBDAEZRoS9O2fGbx85aPZzZxfj33Wu8aZ8a+K5ZZBFuVKKL+/0UbidDhD\nYiuAHL6GAr2gCwYJKyQDAwIIAQEMoWQDYgAEQL0dQoOTArIx70V/XxipoxxBeKT7\nzmIe7id5pQiw4O4nA2S2BFxQF9eW9ipnm6DaN6jaX/+2k+cC4qIfqzeLcLUFXxz0\nqdec8lNNtr9QmwoQlv11beeHmQu9C1GwHmvG\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP512r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHsAgEAMBQGByqGSM49AgEGCSskAwMCCAEBDQSB0DCBzQIBAQRAmEQNFMGIDLoj\nKtdg8V71WdSs7FiBkE6Bft25+yY8ohugk/u8aKeIKNVtSirMgQhGFJy/BIBkvM6V\n1JfnrglkjqGBhQOBggAEYbjTnA0x42NdM7jVv7jAoZq0iOYopbwejlOEsx8/MqRa\nYt4Ef83holIsgOHWSeW+kw1oMDmieoCrhnkM/3KgGzV+BxCeieAWGxABsj9YhAmb\nATorRJ4q/pMxRq8gIUv05/dGuUttl1gdbKKnGQjxDBM4v5H+/4z00nzzj4Gbfx8=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/brainpoolP512t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIHaAgEBBEBNqbJnTzwGwg9JyyXBrQjXF8LT/q53Jydyv6L9AgU5c2vg5CJVvgoL\n8JL/YU+i1UwVIdl8JLZuCLpi+Dcy1rlIoAsGCSskAwMCCAEBDqGBhQOBggAEm/uI\nqsytMZypsqCuL0jwZh8xCRVEkUd02YPXcOBhMzS9bhAao4CLAuXhWzplr5qk/7tt\nvczl7qFDOvBzNAIieZHwbFrouZ6Pew8pQXRcMDB+FnXwNgpljTNmz/f1ePjVKU1Z\ngbQ+xVf8Qt8OI9S0Pla8siTgbVweGMLtq0A8Wuo=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/prime256v1-aes-128-cbc.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-128-CBC,3F26BBC4C7A6F3B5B3A5C03C7CC59B33\n\nrp4qC+n+qIG+WKJp4BHQHk5z0oraaaLZvoVK5glESGx5IcR3mCsN7tdg2aZ7yEk+\nHnT4nQuM3R5pv248cmK0xDUje8N7FLe8lixVnEyQx3JdZfGdauowt9yaxL3AJypX\nidWxNrxz1xff5RSMI6+PFv2SQpG0l794EpOjZxOUABM=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/prime256v1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguc9upTMQn8b+loAx\n6c8q20dHYBf3V9374I3kJIDmC1ShRANCAARnLuOxL7n7Gq12zd9vq2neAv6PYc1h\nW6M2gJKSbfFYGhte382jOJ2TgwaTQL/J5IPSfuJKkmAPBIl8CdJKWlwA\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/secp224r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMHgCAQAwEAYHKoZIzj0CAQYFK4EEACEEYTBfAgEBBByDAgBh6UOQqYJSPoiNWrK0\nrA0rTMLw8JdCEveBoTwDOgAEABwjlgBV9PPpMfo8fo6yWRdT+sb1cUdEhobd+V/D\n/i58cWpDqd4CApevJWtkGbwhU4J9mN0aYrk=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/secp256k1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgAjoYh3zy6gJciB7F/pHi\nfU+IfPBeEhgQBFT3zNvox5ihRANCAATTIv3AIcnOXMvnURBseRspHsowmPAxPgsx\nLH5+aU2mW06f2PsIe9F8gG/Nf2UOOuO+aqwEStIkfSBR+Fwpl2UR\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/secp256r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSFp08cP6os9Fxmky\no5VFi6woYEqvbhVNYTp9NvwzBCChRANCAAQo6UQaiHkZr7lxrKDZyL9Qinr4Vy0Q\nW3K2EPFYbVIupvzW0RH8vBy+0/yoaNyUsw/IsmBO+A60mhBB4rTjmq6R\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/secp384r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCqdZTmuPvhbOVI/Vkk\nyjowWmBb1+81m+ay2QF15TZns1iX4HQlaOZ1GzaqhJRS0R2hZANiAASYw9dep7R9\nIoC8Dzt6T0NYOOJE/TPdOXOH+M6uJvKAtmXGalFeLQX6HKlUDNPnBDTKp9p6Nu/o\n2k/p2C9m0DaX70sNuyfOmh738Bw2Hlz3If+903Jj+hKSR4kWDkKYb/s=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/sec1/secp521r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAdO/4HyMRu7/QcjYn\nf8vynFJRVOKHVVmRFrAzZwkdusoqf9gkicCxcxhOpOGLezzTH4XBynbcmmMn4PNS\nZriTYO6hgYkDgYYABAAp8YOO/QeQoVEdzsOwZt1ta0/b5r0ESM/QNkBVgrRdCsJ+\ny3p/xis4wFlhv7lsrtuDoeuMimnvl+fAfptCzMKHugGBvSE0SjLgydEmUjh/y/a4\nO3cGqwUXnnxiLKJ98NFaooGYY+AwH4h77oCbQR1lf8jhe1qsJkR9mXpYuGnkaJ7l\nqg==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/test-cert-chain.pem",
    "content": "-----BEGIN TRUSTED CERTIFICATE-----\nMIIClzCCAgACCQCPbjkRoMVEQDANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x\nDTALBgNVBAoMBFRlc3QxDTALBgNVBAsMBFRlc3QxFDASBgNVBAMMC2V4YW1wbGUu\nY29tMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTIwMDMyNzIx\nNTgwNFoXDTIxMDMyNzIxNTgwNFowgY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD\nYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARUZXN0\nMQ0wCwYDVQQLDARUZXN0MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3\nDQEJARYQdGVzdEBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\ngYEA1YzixWEoyzrd20C2R1gjyPCoPfFLlG6UYTyT0tueNy6yjv6qbJ8lcZg7616O\n3I9LuOHhZh9U+fCDCgPfiDdyJfDEW/P+dsOMFyMUXPrJPze2yPpOnvV8iJ5DM93u\nfEVhCCyzLdYu0P2P3hU2W+T3/Im9DA7FOPA2vF1SrIJ2qtUCAwEAATANBgkqhkiG\n9w0BAQUFAAOBgQBdShkwUv78vkn1jAdtfbB+7mpV9tufVdo29j7pmotTCz3ny5fc\nzLEfeu6JPugAR71JYbc2CqGrMneSk1zT91EH6ohIz8OR5VNvzB7N7q65Ci7OFMPl\nly6k3rHpMCBtHoyNFhNVfPLxGJ9VlWFKLgIAbCmL4OIQm1l6Fr1MSM38Zw==\n-----END TRUSTED CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAfgCAQEwDQYJKoZIhvcNAQEFBQAwgY8xCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQK\nDARUZXN0MQ0wCwYDVQQLDARUZXN0MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0G\nCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0yMDAzMjcyMjAxNDZaFw0y\nMTAzMjcyMjAxNDZaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p\nYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwEVGVzdDENMAsGA1UE\nCwwEVGVzdDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRl\nc3RAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM7kd2cj\nF49wm1+OQ7Q5GE96cXueWNPr/Nwei71tf6G4BmE0B+suXHEvnLpHTj9pdX/ZzBIK\n8jIZ/x8RnSduK/Ky+zm1QMYUWZtWCAgCW8WzgB69Cn/hQG8KSX3S9bqODuQAvP54\nGQJD7+4kVuNBGjFb4DaD4nvMmPtALSZf8ZCZAgMBAAEwDQYJKoZIhvcNAQEFBQAD\ngYEAOn6X8+0VVlDjF+TvTgI0KIasA6nDm+KXe7LVtfvqWqQZH4qyd2uiwcDM3Aux\na/OsPdOw0j+NqFDBd3mSMhSVgfvXdK6j9WaxY1VGXyaidLARgvn63wfzgr857sQW\nc8eSxbwEQxwlMvVxW6Os4VhCfUQr8VrBrvPa2zs+6IlK+Ug=\n-----END CERTIFICATE-----"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/test-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot/src/test/resources/org/springframework/boot/ssl/pem/test-key.pem",
    "content": "Bag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nKey Attributes: <No Attributes>\n-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD8B1saBN8Y0ZjX\nQ/pvnv2hZa+cBBkFHVkgw+tdzgdcO5Kjv2rnRKd3Oh8Qwdxj3BC9GpicF4GOgkDG\nLrMrYbmV/xGUnNh3YpUwbv+U/pm3VnuSZCk4aYgNEWHrnEHyrge87+MqYqGuMIke\nA5z7GV44PeThfKQs2BLLL/ME+Pb/jN6IVlIHxdBT5TBQkqNGFU7swdZoQ5Viqv44\nUNdVqU5pP3UF/perbOm2CHCbeLiLRvmuvGuBbrbko2XUwBNH+UjmEQaRh/epoy8B\nD31vGY87ym/YOEdpIrqD8bwg7NWP/Fdsryqi8p+U8fcfw4xZjotA0Sv04BC7zXHg\nm1AyZoVzAgMBAAECggEAfEqiZqANaF+BqXQIb4Dw42ZTJzWsIyYYnPySOGZRoe5t\nQJ03uwtULYv34xtANe1DQgd6SMyc46ugBzzjtprQ3ET5Jhn99U6kdcjf+dpf85dO\nhOEppP0CkDNI39nleinSfh6uIOqYgt/D143/nqQhn8oCdSOzkbwT9KnWh1bC9T7I\nvFjGfElvt1/xl88qYgrWgYLgXaencNGgiv/4/M0FNhiHEGsVC7SCu6kapC/WIQpE\n5IdV+HR+tiLoGZhXlhqorY7QC4xKC4wwafVSiFxqDOQAuK+SMD4TCEv0Aop+c+SE\nYBigVTmgVeJkjK7IkTEhKkAEFmRF5/5w+bZD9FhTNQKBgQD+4fNG1ChSU8RdizZT\n5dPlDyAxpETSCEXFFVGtPPh2j93HDWn7XugNyjn5FylTH507QlabC+5wZqltdIjK\nGRB5MIinQ9/nR2fuwGc9s+0BiSEwNOUB1MWm7wWL/JUIiKq6sTi6sJIfsYg79zco\nqxl5WE94aoINx9Utq1cdWhwJTQKBgQD9IjPksd4Jprz8zMrGLzR8k1gqHyhv24qY\nEJ7jiHKKAP6xllTUYwh1IBSL6w2j5lfZPpIkb4Jlk2KUoX6fN81pWkBC/fTBUSIB\nEHM9bL51+yKEYUbGIy/gANuRbHXsWg3sjUsFTNPN4hGTFk3w2xChCyl/f5us8Lo8\nZ633SNdpvwKBgQCGyDU9XzNzVZihXtx7wS0sE7OSjKtX5cf/UCbA1V0OVUWR3SYO\nJ0HPCQFfF0BjFHSwwYPKuaR9C8zMdLNhK5/qdh/NU7czNi9fsZ7moh7SkRFbzJzN\nOxbKD9t/CzJEMQEXeF/nWTfsSpUgILqqZtAxuuFLbAcaAnJYlCKdAumQgQKBgQCK\nmqjJh68pn7gJwGUjoYNe1xtGbSsqHI9F9ovZ0MPO1v6e5M7sQJHH+Fnnxzv/y8e8\nd6tz8e73iX1IHymDKv35uuZHCGF1XOR+qrA/KQUc+vcKf21OXsP/JtkTRs1HLoRD\nS5aRf2DWcfvniyYARSNU2xTM8GWgi2ueWbMDHUp+ZwKBgA/swC+K+Jg5DEWm6Sau\ne6y+eC6S+SoXEKkI3wf7m9aKoZo0y+jh8Gas6gratlc181pSM8O3vZG0n19b493I\napCFomMLE56zEzvyzfpsNhFhk5MBMCn0LPyzX6MiynRlGyWIj0c99fbHI3pOMufP\nWgmVLTZ8uDcSW1MbdUCwFSk5\n-----END PRIVATE KEY-----\nBag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nsubject=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\nissuer=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\n-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot/src/testFixtures/java/org/springframework/boot/AbstractApplicationEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.core.env.AbstractEnvironment;\nimport org.springframework.core.env.ConfigurablePropertyResolver;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for {@link SpringApplication} {@link Environment} tests.\n *\n * @author Phillip Webb\n */\npublic abstract class AbstractApplicationEnvironmentTests {\n\n\t@Test\n\tvoid getActiveProfilesDoesNotResolveProperty() {\n\t\tStandardEnvironment environment = createEnvironment();\n\t\tnew MockPropertySource().withProperty(\"\", \"\");\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new MockPropertySource().withProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, \"test\"));\n\t\tassertThat(environment.getActiveProfiles()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDefaultProfilesDoesNotResolveProperty() {\n\t\tStandardEnvironment environment = createEnvironment();\n\t\tnew MockPropertySource().withProperty(\"\", \"\");\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(\n\t\t\t\t\tnew MockPropertySource().withProperty(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, \"test\"));\n\t\tassertThat(environment.getDefaultProfiles()).containsExactly(\"default\");\n\t}\n\n\t@Test\n\tvoid propertyResolverIsOptimizedForConfigurationProperties() {\n\t\tStandardEnvironment environment = createEnvironment();\n\t\tConfigurablePropertyResolver expected = ConfigurationPropertySources\n\t\t\t.createPropertyResolver(new MutablePropertySources());\n\t\tassertThat(environment).extracting(\"propertyResolver\").hasSameClassAs(expected);\n\t}\n\n\tprotected abstract StandardEnvironment createEnvironment();\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/mock/MockFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.mock;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\n\n/**\n * Simple mock Filter that does nothing.\n *\n * @author Phillip Webb\n */\npublic class MockFilter implements Filter {\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/mock/MockServlet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.mock;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\n\n/**\n * Simple mock Servlet that does nothing.\n *\n * @author Phillip Webb\n */\npublic class MockServlet extends GenericServlet {\n\n\t@Override\n\tpublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/mock/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Additional mocks used for servlet testing.\n */\npackage org.springframework.boot.web.servlet.mock;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot AutoConfigure\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\n\toptional(\"com.github.ben-manes.caffeine:caffeine\")\n\toptional(\"org.aspectj:aspectjweaver\")\n\toptional(\"io.micrometer:context-propagation\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"javax.money:money-api\")\n\toptional(\"org.springframework:spring-web\")\n\toptional(\"org.springframework.data:spring-data-commons\")\n\n\ttestFixturesCompileOnly(project(\":core:spring-boot-test\"))\n\ttestFixturesCompileOnly(project(\":test-support:spring-boot-test-support\"))\n\ttestFixturesCompileOnly(\"javax.cache:cache-api\")\n\ttestFixturesImplementation(testFixtures(project(\":core:spring-boot\")))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot\")))\n\ttestImplementation(\"ch.qos.logback:logback-classic\")\n\ttestImplementation(\"io.projectreactor:reactor-core\")\n\ttestImplementation(\"org.springframework:spring-context-support\")\n\ttestImplementation(\"org.springframework.security:spring-security-config\")\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestRuntimeOnly(\"com.github.ben-manes.caffeine:caffeine\")\n\ttestRuntimeOnly(\"org.springframework:spring-webflux\")\n}\n\ntest {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AbstractDependsOnBeanFactoryPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.StringUtils;\n\n/**\n * Abstract base class for a {@link BeanFactoryPostProcessor} that can be used to\n * dynamically declare that all beans of a specific type should depend on specific other\n * beans identified by name or type.\n *\n * @author Marcel Overdijk\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Dmytro Nosan\n * @since 1.3.0\n * @see BeanDefinition#setDependsOn(String[])\n */\npublic abstract class AbstractDependsOnBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {\n\n\tprivate final Class<?> beanClass;\n\n\tprivate final @Nullable Class<? extends FactoryBean<?>> factoryBeanClass;\n\n\tprivate final Function<ListableBeanFactory, Set<String>> dependsOn;\n\n\t/**\n\t * Create an instance with target bean, factory bean classes, and dependency names.\n\t * @param beanClass target bean class\n\t * @param factoryBeanClass target factory bean class\n\t * @param dependsOn dependency names\n\t */\n\tprotected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,\n\t\t\t@Nullable Class<? extends FactoryBean<?>> factoryBeanClass, String... dependsOn) {\n\t\tthis.beanClass = beanClass;\n\t\tthis.factoryBeanClass = factoryBeanClass;\n\t\tthis.dependsOn = (beanFactory) -> new HashSet<>(Arrays.asList(dependsOn));\n\t}\n\n\t/**\n\t * Create an instance with target bean, factory bean classes, and dependency types.\n\t * @param beanClass target bean class\n\t * @param factoryBeanClass target factory bean class\n\t * @param dependencyTypes dependency types\n\t * @since 2.1.7\n\t */\n\tprotected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,\n\t\t\t@Nullable Class<? extends FactoryBean<?>> factoryBeanClass, Class<?>... dependencyTypes) {\n\t\tthis.beanClass = beanClass;\n\t\tthis.factoryBeanClass = factoryBeanClass;\n\t\tthis.dependsOn = (beanFactory) -> Arrays.stream(dependencyTypes)\n\t\t\t.flatMap((dependencyType) -> getBeanNames(beanFactory, dependencyType).stream())\n\t\t\t.collect(Collectors.toSet());\n\t}\n\n\t/**\n\t * Create an instance with target bean class and dependency names.\n\t * @param beanClass target bean class\n\t * @param dependsOn dependency names\n\t * @since 2.0.4\n\t */\n\tprotected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass, String... dependsOn) {\n\t\tthis(beanClass, null, dependsOn);\n\t}\n\n\t/**\n\t * Create an instance with target bean class and dependency types.\n\t * @param beanClass target bean class\n\t * @param dependencyTypes dependency types\n\t * @since 2.1.7\n\t */\n\tprotected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass, Class<?>... dependencyTypes) {\n\t\tthis(beanClass, null, dependencyTypes);\n\t}\n\n\t@Override\n\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\tfor (String beanName : getBeanNames(beanFactory)) {\n\t\t\tBeanDefinition definition = getBeanDefinition(beanName, beanFactory);\n\t\t\tString[] dependencies = definition.getDependsOn();\n\t\t\tfor (String dependencyName : this.dependsOn.apply(beanFactory)) {\n\t\t\t\tdependencies = StringUtils.addStringToArray(dependencies, dependencyName);\n\t\t\t}\n\t\t\tdefinition.setDependsOn(dependencies);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\tprivate Set<String> getBeanNames(ListableBeanFactory beanFactory) {\n\t\tSet<String> names = getBeanNames(beanFactory, this.beanClass);\n\t\tif (this.factoryBeanClass != null) {\n\t\t\tnames.addAll(getBeanNames(beanFactory, this.factoryBeanClass));\n\t\t}\n\t\treturn names;\n\t}\n\n\tprivate static Set<String> getBeanNames(ListableBeanFactory beanFactory, Class<?> beanClass) {\n\t\tString[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, beanClass, true, false);\n\t\treturn Arrays.stream(names).map(BeanFactoryUtils::transformedBeanName).collect(Collectors.toSet());\n\t}\n\n\tprivate static BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {\n\t\ttry {\n\t\t\treturn beanFactory.getBeanDefinition(beanName);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\tBeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();\n\t\t\tif (parentBeanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {\n\t\t\t\treturn getBeanDefinition(beanName, listableBeanFactory);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.context.annotation.AnnotationBeanNameGenerator;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Indicates that a class provides configuration that can be automatically applied by\n * Spring Boot. Auto-configuration classes are regular\n * {@link Configuration @Configuration} with the exception that\n * {@link Configuration#proxyBeanMethods() proxyBeanMethods} is always {@code false}. They\n * are located using {@link ImportCandidates}.\n * <p>\n * Generally, auto-configuration classes are top-level classes that are marked as\n * {@link Conditional @Conditional} (most often using\n * {@link ConditionalOnClass @ConditionalOnClass} and\n * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).\n *\n * @author Moritz Halbritter\n * @see EnableAutoConfiguration\n * @see AutoConfigureBefore\n * @see AutoConfigureAfter\n * @see Conditional\n * @see ConditionalOnClass\n * @see ConditionalOnMissingBean\n * @since 2.7.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Configuration(proxyBeanMethods = false)\n@AutoConfigureBefore\n@AutoConfigureAfter\npublic @interface AutoConfiguration {\n\n\t/**\n\t * Explicitly specify the name of the Spring bean definition associated with the\n\t * {@code @AutoConfiguration} class. If left unspecified (the common case), a bean\n\t * name will be automatically generated.\n\t * <p>\n\t * The custom name applies only if the {@code @AutoConfiguration} class is picked up\n\t * through component scanning or supplied directly to an\n\t * {@link AnnotationConfigApplicationContext}. If the {@code @AutoConfiguration} class\n\t * is registered as a traditional XML bean definition, the name/id of the bean element\n\t * will take precedence.\n\t * @return the explicit component name, if any (or empty String otherwise)\n\t * @see AnnotationBeanNameGenerator\n\t */\n\t@AliasFor(annotation = Configuration.class)\n\tString value() default \"\";\n\n\t/**\n\t * The auto-configuration classes that should have not yet been applied.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #beforeName} attribute.\n\t * @return the classes\n\t */\n\t@AliasFor(annotation = AutoConfigureBefore.class, attribute = \"value\")\n\tClass<?>[] before() default {};\n\n\t/**\n\t * The names of the auto-configuration classes that should have not yet been applied.\n\t * In the unusual case that an auto-configuration class is not a top-level class, its\n\t * name should use {@code $} to separate it from its containing class, for example\n\t * {@code com.example.Outer$NestedAutoConfiguration}.\n\t * @return the class names\n\t */\n\t@AliasFor(annotation = AutoConfigureBefore.class, attribute = \"name\")\n\tString[] beforeName() default {};\n\n\t/**\n\t * The auto-configuration classes that should have already been applied.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #afterName} attribute.\n\t * @return the classes\n\t */\n\t@AliasFor(annotation = AutoConfigureAfter.class, attribute = \"value\")\n\tClass<?>[] after() default {};\n\n\t/**\n\t * The names of the auto-configuration classes that should have already been applied.\n\t * In the unusual case that an auto-configuration class is not a top-level class, its\n\t * class name should use {@code $} to separate it from its containing class, for\n\t * example {@code com.example.Outer$NestedAutoConfiguration}.\n\t * @return the class names\n\t */\n\t@AliasFor(annotation = AutoConfigureAfter.class, attribute = \"name\")\n\tString[] afterName() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.filter.TypeFilter;\n\n/**\n * A {@link TypeFilter} implementation that matches registered auto-configuration classes.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 1.5.0\n */\npublic class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader beanClassLoader;\n\n\tprivate volatile @Nullable List<String> autoConfigurations;\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader beanClassLoader) {\n\t\tthis.beanClassLoader = beanClassLoader;\n\t}\n\n\t@Override\n\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\treturn isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);\n\t}\n\n\tprivate boolean isConfiguration(MetadataReader metadataReader) {\n\t\treturn metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());\n\t}\n\n\tprivate boolean isAutoConfiguration(MetadataReader metadataReader) {\n\t\tboolean annotatedWithAutoConfiguration = metadataReader.getAnnotationMetadata()\n\t\t\t.isAnnotated(AutoConfiguration.class.getName());\n\t\treturn annotatedWithAutoConfiguration\n\t\t\t\t|| getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());\n\t}\n\n\tprotected List<String> getAutoConfigurations() {\n\t\tList<String> autoConfigurations = this.autoConfigurations;\n\t\tif (autoConfigurations == null) {\n\t\t\tImportCandidates importCandidates = ImportCandidates.load(AutoConfiguration.class, this.beanClassLoader);\n\t\t\tautoConfigurations = importCandidates.getCandidates();\n\t\t\tthis.autoConfigurations = autoConfigurations;\n\t\t}\n\t\treturn autoConfigurations;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.EventObject;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Event fired when auto-configuration classes are imported.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic class AutoConfigurationImportEvent extends EventObject {\n\n\tprivate final List<String> candidateConfigurations;\n\n\tprivate final Set<String> exclusions;\n\n\tpublic AutoConfigurationImportEvent(Object source, List<String> candidateConfigurations, Set<String> exclusions) {\n\t\tsuper(source);\n\t\tthis.candidateConfigurations = Collections.unmodifiableList(candidateConfigurations);\n\t\tthis.exclusions = Collections.unmodifiableSet(exclusions);\n\t}\n\n\t/**\n\t * Return the auto-configuration candidate configurations that are going to be\n\t * imported.\n\t * @return the auto-configuration candidates\n\t */\n\tpublic List<String> getCandidateConfigurations() {\n\t\treturn this.candidateConfigurations;\n\t}\n\n\t/**\n\t * Return the exclusions that were applied.\n\t * @return the exclusions applied\n\t */\n\tpublic Set<String> getExclusions() {\n\t\treturn this.exclusions;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.ResourceLoaderAware;\n\n/**\n * Filter that can be registered in {@code spring.factories} to limit the\n * auto-configuration classes considered. This interface is designed to allow fast removal\n * of auto-configuration classes before their bytecode is even read.\n * <p>\n * An {@link AutoConfigurationImportFilter} may implement any of the following\n * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective\n * methods will be called prior to {@link #match}:\n * <ul>\n * <li>{@link EnvironmentAware}</li>\n * <li>{@link BeanFactoryAware}</li>\n * <li>{@link BeanClassLoaderAware}</li>\n * <li>{@link ResourceLoaderAware}</li>\n * </ul>\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\n@FunctionalInterface\npublic interface AutoConfigurationImportFilter {\n\n\t/**\n\t * Apply the filter to the given auto-configuration class candidates.\n\t * @param autoConfigurationClasses the auto-configuration classes being considered.\n\t * This array may contain {@code null} elements. Implementations should not change the\n\t * values in this array.\n\t * @param autoConfigurationMetadata access to the meta-data generated by the\n\t * auto-configure annotation processor\n\t * @return a boolean array indicating which of the auto-configuration classes should\n\t * be imported. The returned array must be the same size as the incoming\n\t * {@code autoConfigurationClasses} parameter. Entries containing {@code false} will\n\t * not be imported.\n\t */\n\tboolean[] match(@Nullable String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata);\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.EventListener;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.ResourceLoaderAware;\n\n/**\n * Listener that can be registered with {@code spring.factories} to receive details of\n * imported auto-configurations.\n * <p>\n * An {@link AutoConfigurationImportListener} may implement any of the following\n * {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective\n * methods will be called prior to\n * {@link #onAutoConfigurationImportEvent(AutoConfigurationImportEvent)}:\n * <ul>\n * <li>{@link EnvironmentAware}</li>\n * <li>{@link BeanFactoryAware}</li>\n * <li>{@link BeanClassLoaderAware}</li>\n * <li>{@link ResourceLoaderAware}</li>\n * </ul>\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\n@FunctionalInterface\npublic interface AutoConfigurationImportListener extends EventListener {\n\n\t/**\n\t * Handle an auto-configuration import event.\n\t * @param event the event to respond to\n\t */\n\tvoid onAutoConfigurationImportEvent(AutoConfigurationImportEvent event);\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.Aware;\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DeferredImportSelector;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link DeferredImportSelector} to handle {@link EnableAutoConfiguration\n * auto-configuration}. This class can also be subclassed if a custom variant of\n * {@link EnableAutoConfiguration @EnableAutoConfiguration} is needed.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @since 1.3.0\n * @see EnableAutoConfiguration\n */\npublic class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,\n\t\tResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {\n\n\tstatic final int ORDER = Ordered.LOWEST_PRECEDENCE - 1;\n\n\tprivate static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();\n\n\tprivate static final String[] NO_IMPORTS = {};\n\n\tprivate static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);\n\n\tprivate static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = \"spring.autoconfigure.exclude\";\n\n\tprivate final Class<?> autoConfigurationAnnotation;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigurableListableBeanFactory beanFactory;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Environment environment;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader beanClassLoader;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ResourceLoader resourceLoader;\n\n\tprivate volatile @Nullable ConfigurationClassFilter configurationClassFilter;\n\n\tprivate volatile @Nullable AutoConfigurationReplacements autoConfigurationReplacements;\n\n\tpublic AutoConfigurationImportSelector() {\n\t\tthis(null);\n\t}\n\n\tAutoConfigurationImportSelector(@Nullable Class<?> autoConfigurationAnnotation) {\n\t\tthis.autoConfigurationAnnotation = (autoConfigurationAnnotation != null) ? autoConfigurationAnnotation\n\t\t\t\t: AutoConfiguration.class;\n\t}\n\n\t@Override\n\tpublic String[] selectImports(AnnotationMetadata annotationMetadata) {\n\t\tif (!isEnabled(annotationMetadata)) {\n\t\t\treturn NO_IMPORTS;\n\t\t}\n\t\tAutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);\n\t\treturn StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());\n\t}\n\n\t@Override\n\tpublic Predicate<String> getExclusionFilter() {\n\t\treturn this::shouldExclude;\n\t}\n\n\tprivate boolean shouldExclude(String configurationClassName) {\n\t\treturn getConfigurationClassFilter().filter(Collections.singletonList(configurationClassName)).isEmpty();\n\t}\n\n\t/**\n\t * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}\n\t * of the importing {@link Configuration @Configuration} class.\n\t * @param annotationMetadata the annotation metadata of the configuration class\n\t * @return the auto-configurations that should be imported\n\t */\n\tprotected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {\n\t\tif (!isEnabled(annotationMetadata)) {\n\t\t\treturn EMPTY_ENTRY;\n\t\t}\n\t\tAnnotationAttributes attributes = getAttributes(annotationMetadata);\n\t\tList<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);\n\t\tconfigurations = removeDuplicates(configurations);\n\t\tSet<String> exclusions = getExclusions(annotationMetadata, attributes);\n\t\tcheckExcludedClasses(configurations, exclusions);\n\t\tconfigurations.removeAll(exclusions);\n\t\tconfigurations = getConfigurationClassFilter().filter(configurations);\n\t\tfireAutoConfigurationImportEvents(configurations, exclusions);\n\t\treturn new AutoConfigurationEntry(configurations, exclusions);\n\t}\n\n\t@Override\n\tpublic Class<? extends Group> getImportGroup() {\n\t\treturn AutoConfigurationGroup.class;\n\t}\n\n\tprotected boolean isEnabled(AnnotationMetadata metadata) {\n\t\tif (getClass() == AutoConfigurationImportSelector.class) {\n\t\t\treturn getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return the appropriate {@link AnnotationAttributes} from the\n\t * {@link AnnotationMetadata}. By default this method will return attributes for\n\t * {@link #getAnnotationClass()}.\n\t * @param metadata the annotation metadata\n\t * @return annotation attributes\n\t */\n\tprotected @Nullable AnnotationAttributes getAttributes(AnnotationMetadata metadata) {\n\t\tString name = getAnnotationClass().getName();\n\t\tAnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));\n\t\tAssert.state(attributes != null, () -> \"No auto-configuration attributes found. Is \" + metadata.getClassName()\n\t\t\t\t+ \" annotated with \" + ClassUtils.getShortName(name) + \"?\");\n\t\treturn attributes;\n\t}\n\n\t/**\n\t * Return the source annotation class used by the selector.\n\t * @return the annotation class\n\t */\n\tprotected Class<?> getAnnotationClass() {\n\t\treturn EnableAutoConfiguration.class;\n\t}\n\n\t/**\n\t * Return the auto-configuration class names that should be considered. By default,\n\t * this method will load candidates using {@link ImportCandidates}.\n\t * @param metadata the source metadata\n\t * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation\n\t * attributes}\n\t * @return a list of candidate configurations\n\t */\n\tprotected List<String> getCandidateConfigurations(AnnotationMetadata metadata,\n\t\t\t@Nullable AnnotationAttributes attributes) {\n\t\tImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,\n\t\t\t\tgetBeanClassLoader());\n\t\tList<String> configurations = importCandidates.getCandidates();\n\t\tAssert.state(!CollectionUtils.isEmpty(configurations),\n\t\t\t\t\"No auto configuration classes found in \" + \"META-INF/spring/\"\n\t\t\t\t\t\t+ this.autoConfigurationAnnotation.getName() + \".imports. If you \"\n\t\t\t\t\t\t+ \"are using a custom packaging, make sure that file is correct.\");\n\t\treturn configurations;\n\t}\n\n\tprivate void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {\n\t\tList<String> invalidExcludes = new ArrayList<>(exclusions.size());\n\t\tClassLoader classLoader = (this.beanClassLoader != null) ? this.beanClassLoader : getClass().getClassLoader();\n\t\tfor (String exclusion : exclusions) {\n\t\t\tif (ClassUtils.isPresent(exclusion, classLoader) && !configurations.contains(exclusion)) {\n\t\t\t\tinvalidExcludes.add(exclusion);\n\t\t\t}\n\t\t}\n\t\tif (!invalidExcludes.isEmpty()) {\n\t\t\thandleInvalidExcludes(invalidExcludes);\n\t\t}\n\t}\n\n\t/**\n\t * Handle any invalid excludes that have been specified.\n\t * @param invalidExcludes the list of invalid excludes (will always have at least one\n\t * element)\n\t */\n\tprotected void handleInvalidExcludes(List<String> invalidExcludes) {\n\t\tStringBuilder message = new StringBuilder();\n\t\tfor (String exclude : invalidExcludes) {\n\t\t\tmessage.append(\"\\t- \").append(exclude).append(String.format(\"%n\"));\n\t\t}\n\t\tthrow new IllegalStateException(String.format(\n\t\t\t\t\"The following classes could not be excluded because they are not auto-configuration classes:%n%s\",\n\t\t\t\tmessage));\n\t}\n\n\t/**\n\t * Return any exclusions that limit the candidate configurations.\n\t * @param metadata the source metadata\n\t * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation\n\t * attributes}\n\t * @return exclusions or an empty set\n\t */\n\tprotected Set<String> getExclusions(AnnotationMetadata metadata, @Nullable AnnotationAttributes attributes) {\n\t\tSet<String> excluded = new LinkedHashSet<>();\n\t\tif (attributes != null) {\n\t\t\texcluded.addAll(asList(attributes, \"exclude\"));\n\t\t\texcluded.addAll(asList(attributes, \"excludeName\"));\n\t\t}\n\t\texcluded.addAll(getExcludeAutoConfigurationsProperty());\n\t\treturn getAutoConfigurationReplacements().replaceAll(excluded);\n\t}\n\n\t/**\n\t * Returns the auto-configurations excluded by the\n\t * {@code spring.autoconfigure.exclude} property.\n\t * @return excluded auto-configurations\n\t * @since 2.3.2\n\t */\n\tprotected List<String> getExcludeAutoConfigurationsProperty() {\n\t\tEnvironment environment = getEnvironment();\n\t\tif (environment == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tif (environment instanceof ConfigurableEnvironment) {\n\t\t\tBinder binder = Binder.get(environment);\n\t\t\treturn binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class)\n\t\t\t\t.map(Arrays::asList)\n\t\t\t\t.orElse(Collections.emptyList());\n\t\t}\n\t\tString[] excludes = environment.getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);\n\t\treturn (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();\n\t}\n\n\tprotected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {\n\t\treturn SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);\n\t}\n\n\tprivate ConfigurationClassFilter getConfigurationClassFilter() {\n\t\tConfigurationClassFilter configurationClassFilter = this.configurationClassFilter;\n\t\tif (configurationClassFilter == null) {\n\t\t\tList<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();\n\t\t\tfor (AutoConfigurationImportFilter filter : filters) {\n\t\t\t\tinvokeAwareMethods(filter);\n\t\t\t}\n\t\t\tconfigurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);\n\t\t\tthis.configurationClassFilter = configurationClassFilter;\n\t\t}\n\t\treturn configurationClassFilter;\n\t}\n\n\tprivate AutoConfigurationReplacements getAutoConfigurationReplacements() {\n\t\tAutoConfigurationReplacements autoConfigurationReplacements = this.autoConfigurationReplacements;\n\t\tif (autoConfigurationReplacements == null) {\n\t\t\tautoConfigurationReplacements = AutoConfigurationReplacements.load(this.autoConfigurationAnnotation,\n\t\t\t\t\tthis.beanClassLoader);\n\t\t\tthis.autoConfigurationReplacements = autoConfigurationReplacements;\n\t\t}\n\t\treturn autoConfigurationReplacements;\n\t}\n\n\tprotected final <T> List<T> removeDuplicates(List<T> list) {\n\t\treturn new ArrayList<>(new LinkedHashSet<>(list));\n\t}\n\n\tprotected final List<String> asList(AnnotationAttributes attributes, String name) {\n\t\tString[] value = attributes.getStringArray(name);\n\t\treturn Arrays.asList(value);\n\t}\n\n\tprivate void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {\n\t\tList<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();\n\t\tif (!listeners.isEmpty()) {\n\t\t\tAutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);\n\t\t\tfor (AutoConfigurationImportListener listener : listeners) {\n\t\t\t\tinvokeAwareMethods(listener);\n\t\t\t\tlistener.onAutoConfigurationImportEvent(event);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {\n\t\treturn SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);\n\t}\n\n\tprivate void invokeAwareMethods(Object instance) {\n\t\tif (instance instanceof Aware) {\n\t\t\tif (instance instanceof BeanClassLoaderAware beanClassLoaderAwareInstance) {\n\t\t\t\tbeanClassLoaderAwareInstance.setBeanClassLoader(this.beanClassLoader);\n\t\t\t}\n\t\t\tif (instance instanceof BeanFactoryAware beanFactoryAwareInstance) {\n\t\t\t\tbeanFactoryAwareInstance.setBeanFactory(this.beanFactory);\n\t\t\t}\n\t\t\tif (instance instanceof EnvironmentAware environmentAwareInstance) {\n\t\t\t\tenvironmentAwareInstance.setEnvironment(this.environment);\n\t\t\t}\n\t\t\tif (instance instanceof ResourceLoaderAware resourceLoaderAwareInstance) {\n\t\t\t\tresourceLoaderAwareInstance.setResourceLoader(this.resourceLoader);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tAssert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);\n\t\tthis.beanFactory = (ConfigurableListableBeanFactory) beanFactory;\n\t}\n\n\tprotected final ConfigurableListableBeanFactory getBeanFactory() {\n\t\treturn this.beanFactory;\n\t}\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.beanClassLoader = classLoader;\n\t}\n\n\tprotected ClassLoader getBeanClassLoader() {\n\t\treturn this.beanClassLoader;\n\t}\n\n\t@Override\n\tpublic void setEnvironment(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\tprotected final Environment getEnvironment() {\n\t\treturn this.environment;\n\t}\n\n\t@Override\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\tprotected final ResourceLoader getResourceLoader() {\n\t\treturn this.resourceLoader;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\tprivate static class ConfigurationClassFilter {\n\n\t\tprivate final AutoConfigurationMetadata autoConfigurationMetadata;\n\n\t\tprivate final List<AutoConfigurationImportFilter> filters;\n\n\t\tConfigurationClassFilter(ClassLoader classLoader, List<AutoConfigurationImportFilter> filters) {\n\t\t\tthis.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(classLoader);\n\t\t\tthis.filters = filters;\n\t\t}\n\n\t\tList<String> filter(List<String> configurations) {\n\t\t\tlong startTime = System.nanoTime();\n\t\t\t@Nullable String[] candidates = StringUtils.toStringArray(configurations);\n\t\t\tboolean skipped = false;\n\t\t\tfor (AutoConfigurationImportFilter filter : this.filters) {\n\t\t\t\tboolean[] match = filter.match(candidates, this.autoConfigurationMetadata);\n\t\t\t\tfor (int i = 0; i < match.length; i++) {\n\t\t\t\t\tif (!match[i]) {\n\t\t\t\t\t\tcandidates[i] = null;\n\t\t\t\t\t\tskipped = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!skipped) {\n\t\t\t\treturn configurations;\n\t\t\t}\n\t\t\tList<String> result = new ArrayList<>(candidates.length);\n\t\t\tfor (String candidate : candidates) {\n\t\t\t\tif (candidate != null) {\n\t\t\t\t\tresult.add(candidate);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (logger.isTraceEnabled()) {\n\t\t\t\tint numberFiltered = configurations.size() - result.size();\n\t\t\t\tlogger.trace(\"Filtered \" + numberFiltered + \" auto configuration class in \"\n\t\t\t\t\t\t+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + \" ms\");\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tprivate static final class AutoConfigurationGroup\n\t\t\timplements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {\n\n\t\tprivate final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();\n\n\t\tprivate final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ClassLoader beanClassLoader;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate BeanFactory beanFactory;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ResourceLoader resourceLoader;\n\n\t\tprivate @Nullable AutoConfigurationMetadata autoConfigurationMetadata;\n\n\t\tprivate @Nullable AutoConfigurationReplacements autoConfigurationReplacements;\n\n\t\t@Override\n\t\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\t\tthis.beanClassLoader = classLoader;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setBeanFactory(BeanFactory beanFactory) {\n\t\t\tthis.beanFactory = beanFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\t\tthis.resourceLoader = resourceLoader;\n\t\t}\n\n\t\t@Override\n\t\tpublic void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {\n\t\t\tAssert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,\n\t\t\t\t\t() -> String.format(\"Only %s implementations are supported, got %s\",\n\t\t\t\t\t\t\tAutoConfigurationImportSelector.class.getSimpleName(),\n\t\t\t\t\t\t\tdeferredImportSelector.getClass().getName()));\n\t\t\tAutoConfigurationImportSelector autoConfigurationImportSelector = (AutoConfigurationImportSelector) deferredImportSelector;\n\t\t\tAutoConfigurationReplacements autoConfigurationReplacements = autoConfigurationImportSelector\n\t\t\t\t.getAutoConfigurationReplacements();\n\t\t\tAssert.state(\n\t\t\t\t\tthis.autoConfigurationReplacements == null\n\t\t\t\t\t\t\t|| this.autoConfigurationReplacements.equals(autoConfigurationReplacements),\n\t\t\t\t\t\"Auto-configuration replacements must be the same for each call to process\");\n\t\t\tthis.autoConfigurationReplacements = autoConfigurationReplacements;\n\t\t\tAutoConfigurationEntry autoConfigurationEntry = autoConfigurationImportSelector\n\t\t\t\t.getAutoConfigurationEntry(annotationMetadata);\n\t\t\tthis.autoConfigurationEntries.add(autoConfigurationEntry);\n\t\t\tfor (String importClassName : autoConfigurationEntry.getConfigurations()) {\n\t\t\t\tthis.entries.putIfAbsent(importClassName, annotationMetadata);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterable<Entry> selectImports() {\n\t\t\tif (this.autoConfigurationEntries.isEmpty()) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\tSet<String> allExclusions = this.autoConfigurationEntries.stream()\n\t\t\t\t.map(AutoConfigurationEntry::getExclusions)\n\t\t\t\t.flatMap(Collection::stream)\n\t\t\t\t.collect(Collectors.toSet());\n\t\t\tSet<String> processedConfigurations = this.autoConfigurationEntries.stream()\n\t\t\t\t.map(AutoConfigurationEntry::getConfigurations)\n\t\t\t\t.flatMap(Collection::stream)\n\t\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t\t\tprocessedConfigurations.removeAll(allExclusions);\n\t\t\treturn sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()\n\t\t\t\t.map(this::getEntry)\n\t\t\t\t.toList();\n\t\t}\n\n\t\tprivate Entry getEntry(String importClassName) {\n\t\t\tAnnotationMetadata metadata = this.entries.get(importClassName);\n\t\t\tAssert.state(metadata != null, \"'metadata' must not be null\");\n\t\t\treturn new Entry(metadata, importClassName);\n\t\t}\n\n\t\tprivate AutoConfigurationMetadata getAutoConfigurationMetadata() {\n\t\t\tif (this.autoConfigurationMetadata == null) {\n\t\t\t\tthis.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);\n\t\t\t}\n\t\t\treturn this.autoConfigurationMetadata;\n\t\t}\n\n\t\tprivate List<String> sortAutoConfigurations(Set<String> configurations,\n\t\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t\tAssert.state(this.autoConfigurationReplacements != null,\n\t\t\t\t\t\"'autoConfigurationReplacements' must not be null\");\n\t\t\treturn new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata,\n\t\t\t\t\tthis.autoConfigurationReplacements::replace)\n\t\t\t\t.getInPriorityOrder(configurations);\n\t\t}\n\n\t\tprivate MetadataReaderFactory getMetadataReaderFactory() {\n\t\t\ttry {\n\t\t\t\treturn this.beanFactory.getBean(SharedMetadataReaderFactoryContextInitializer.BEAN_NAME,\n\t\t\t\t\t\tMetadataReaderFactory.class);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn new CachingMetadataReaderFactory(this.resourceLoader);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprotected static class AutoConfigurationEntry {\n\n\t\tprivate final List<String> configurations;\n\n\t\tprivate final Set<String> exclusions;\n\n\t\tprivate AutoConfigurationEntry() {\n\t\t\tthis.configurations = Collections.emptyList();\n\t\t\tthis.exclusions = Collections.emptySet();\n\t\t}\n\n\t\t/**\n\t\t * Create an entry with the configurations that were contributed and their\n\t\t * exclusions.\n\t\t * @param configurations the configurations that should be imported\n\t\t * @param exclusions the exclusions that were applied to the original list\n\t\t */\n\t\tAutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {\n\t\t\tthis.configurations = new ArrayList<>(configurations);\n\t\t\tthis.exclusions = new HashSet<>(exclusions);\n\t\t}\n\n\t\tpublic List<String> getConfigurations() {\n\t\t\treturn this.configurations;\n\t\t}\n\n\t\tpublic Set<String> getExclusions() {\n\t\t\treturn this.exclusions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Provides access to meta-data written by the auto-configure annotation processor.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic interface AutoConfigurationMetadata {\n\n\t/**\n\t * Return {@code true} if the specified class name was processed by the annotation\n\t * processor.\n\t * @param className the source class\n\t * @return if the class was processed\n\t */\n\tboolean wasProcessed(String className);\n\n\t/**\n\t * Get an {@link Integer} value from the meta-data.\n\t * @param className the source class\n\t * @param key the meta-data key\n\t * @return the meta-data value or {@code null}\n\t */\n\t@Nullable Integer getInteger(String className, String key);\n\n\t/**\n\t * Get an {@link Integer} value from the meta-data.\n\t * @param className the source class\n\t * @param key the meta-data key\n\t * @param defaultValue the default value\n\t * @return the meta-data value or {@code defaultValue}\n\t */\n\t@Contract(\"_, _, !null -> !null\")\n\t@Nullable Integer getInteger(String className, String key, @Nullable Integer defaultValue);\n\n\t/**\n\t * Get a {@link Set} value from the meta-data.\n\t * @param className the source class\n\t * @param key the meta-data key\n\t * @return the meta-data value or {@code null}\n\t */\n\t@Nullable Set<String> getSet(String className, String key);\n\n\t/**\n\t * Get a {@link Set} value from the meta-data.\n\t * @param className the source class\n\t * @param key the meta-data key\n\t * @param defaultValue the default value\n\t * @return the meta-data value or {@code defaultValue}\n\t */\n\t@Contract(\"_, _, !null -> !null\")\n\t@Nullable Set<String> getSet(String className, String key, @Nullable Set<String> defaultValue);\n\n\t/**\n\t * Get an {@link String} value from the meta-data.\n\t * @param className the source class\n\t * @param key the meta-data key\n\t * @return the meta-data value or {@code null}\n\t */\n\t@Nullable String get(String className, String key);\n\n\t/**\n\t * Get an {@link String} value from the meta-data.\n\t * @param className the source class\n\t * @param key the meta-data key\n\t * @param defaultValue the default value\n\t * @return the meta-data value or {@code defaultValue}\n\t */\n\t@Contract(\"_, _, !null -> !null\")\n\t@Nullable String get(String className, String key, @Nullable String defaultValue);\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationMetadataLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Enumeration;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.UrlResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Internal utility used to load {@link AutoConfigurationMetadata}.\n *\n * @author Phillip Webb\n */\nfinal class AutoConfigurationMetadataLoader {\n\n\tprivate static final String PATH = \"META-INF/spring-autoconfigure-metadata.properties\";\n\n\tprivate AutoConfigurationMetadataLoader() {\n\t}\n\n\tstatic AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {\n\t\treturn loadMetadata(classLoader, PATH);\n\t}\n\n\tstatic AutoConfigurationMetadata loadMetadata(@Nullable ClassLoader classLoader, String path) {\n\t\ttry {\n\t\t\tEnumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)\n\t\t\t\t\t: ClassLoader.getSystemResources(path);\n\t\t\tProperties properties = new Properties();\n\t\t\twhile (urls.hasMoreElements()) {\n\t\t\t\tproperties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));\n\t\t\t}\n\t\t\treturn loadMetadata(properties);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Unable to load @ConditionalOnClass location [\" + path + \"]\", ex);\n\t\t}\n\t}\n\n\tstatic AutoConfigurationMetadata loadMetadata(Properties properties) {\n\t\treturn new PropertiesAutoConfigurationMetadata(properties);\n\t}\n\n\t/**\n\t * {@link AutoConfigurationMetadata} implementation backed by a properties file.\n\t */\n\tprivate static class PropertiesAutoConfigurationMetadata implements AutoConfigurationMetadata {\n\n\t\tprivate final Properties properties;\n\n\t\tPropertiesAutoConfigurationMetadata(Properties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean wasProcessed(String className) {\n\t\t\treturn this.properties.containsKey(className);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Integer getInteger(String className, String key) {\n\t\t\treturn getInteger(className, key, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Integer getInteger(String className, String key, @Nullable Integer defaultValue) {\n\t\t\tString value = get(className, key);\n\t\t\treturn (value != null) ? Integer.valueOf(value) : defaultValue;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Set<String> getSet(String className, String key) {\n\t\t\treturn getSet(className, key, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Set<String> getSet(String className, String key, @Nullable Set<String> defaultValue) {\n\t\t\tString value = get(className, key);\n\t\t\treturn (value != null) ? StringUtils.commaDelimitedListToSet(value) : defaultValue;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(String className, String key) {\n\t\t\treturn get(className, key, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(String className, String key, @Nullable String defaultValue) {\n\t\t\tString value = this.properties.getProperty(className + \".\" + key);\n\t\t\treturn (value != null) ? value : defaultValue;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\n\n/**\n * Registers packages with {@link AutoConfigurationPackages}. When no {@link #basePackages\n * base packages} or {@link #basePackageClasses base package classes} are specified, the\n * package of the annotated class is registered.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see AutoConfigurationPackages\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Import(AutoConfigurationPackages.Registrar.class)\npublic @interface AutoConfigurationPackage {\n\n\t/**\n\t * Base packages that should be registered with {@link AutoConfigurationPackages}.\n\t * <p>\n\t * Use {@link #basePackageClasses} for a type-safe alternative to String-based package\n\t * names.\n\t * @return the back package names\n\t * @since 2.3.0\n\t */\n\tString[] basePackages() default {};\n\n\t/**\n\t * Type-safe alternative to {@link #basePackages} for specifying the packages to be\n\t * registered with {@link AutoConfigurationPackages}.\n\t * <p>\n\t * Consider creating a special no-op marker class or interface in each package that\n\t * serves no purpose other than being referenced by this attribute.\n\t * @return the base package classes\n\t * @since 2.3.0\n\t */\n\tClass<?>[] basePackageClasses() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConstructorArgumentValues;\nimport org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.context.annotation.DeterminableImports;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Class for storing auto-configuration packages for reference later (e.g. by JPA entity\n * scanner).\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Oliver Gierke\n * @since 1.0.0\n */\npublic abstract class AutoConfigurationPackages {\n\n\tprivate static final Log logger = LogFactory.getLog(AutoConfigurationPackages.class);\n\n\tprivate static final String BEAN = AutoConfigurationPackages.class.getName();\n\n\t/**\n\t * Determine if the auto-configuration base packages for the given bean factory are\n\t * available.\n\t * @param beanFactory the source bean factory\n\t * @return true if there are auto-config packages available\n\t */\n\tpublic static boolean has(BeanFactory beanFactory) {\n\t\treturn beanFactory.containsBean(BEAN) && !get(beanFactory).isEmpty();\n\t}\n\n\t/**\n\t * Return the auto-configuration base packages for the given bean factory.\n\t * @param beanFactory the source bean factory\n\t * @return a list of auto-configuration packages\n\t * @throws IllegalStateException if auto-configuration is not enabled\n\t */\n\tpublic static List<String> get(BeanFactory beanFactory) {\n\t\ttry {\n\t\t\treturn beanFactory.getBean(BEAN, BasePackages.class).get();\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to retrieve @EnableAutoConfiguration base packages\");\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically registers the auto-configuration package names. Subsequent\n\t * invocations will add the given package names to those that have already been\n\t * registered. You can use this method to manually define the base packages that will\n\t * be used for a given {@link BeanDefinitionRegistry}. Generally it's recommended that\n\t * you don't call this method directly, but instead rely on the default convention\n\t * where the package name is set from your {@code @EnableAutoConfiguration}\n\t * configuration class or classes.\n\t * @param registry the bean definition registry\n\t * @param packageNames the package names to set\n\t */\n\tpublic static void register(BeanDefinitionRegistry registry, String... packageNames) {\n\t\tif (registry.containsBeanDefinition(BEAN)) {\n\t\t\taddBasePackages(registry.getBeanDefinition(BEAN), packageNames);\n\t\t}\n\t\telse {\n\t\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(BasePackages.class);\n\t\t\tbeanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\t\t\taddBasePackages(beanDefinition, packageNames);\n\t\t\tregistry.registerBeanDefinition(BEAN, beanDefinition);\n\t\t}\n\t}\n\n\tprivate static void addBasePackages(BeanDefinition beanDefinition, String[] additionalBasePackages) {\n\t\tConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();\n\t\tif (constructorArgumentValues.hasIndexedArgumentValue(0)) {\n\t\t\tValueHolder indexedArgumentValue = constructorArgumentValues.getIndexedArgumentValue(0, String[].class);\n\t\t\tAssert.state(indexedArgumentValue != null, \"'indexedArgumentValue' must not be null\");\n\t\t\tString[] existingPackages = (String[]) indexedArgumentValue.getValue();\n\t\t\tStream<String> existingPackagesStream = (existingPackages != null) ? Stream.of(existingPackages)\n\t\t\t\t\t: Stream.empty();\n\t\t\tconstructorArgumentValues.addIndexedArgumentValue(0,\n\t\t\t\t\tStream.concat(existingPackagesStream, Stream.of(additionalBasePackages))\n\t\t\t\t\t\t.distinct()\n\t\t\t\t\t\t.toArray(String[]::new));\n\t\t}\n\t\telse {\n\t\t\tconstructorArgumentValues.addIndexedArgumentValue(0, additionalBasePackages);\n\t\t}\n\t}\n\n\t/**\n\t * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing\n\t * configuration.\n\t */\n\tstatic class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {\n\t\t\tregister(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<Object> determineImports(AnnotationMetadata metadata) {\n\t\t\treturn Collections.singleton(new PackageImports(metadata));\n\t\t}\n\n\t}\n\n\t/**\n\t * Wrapper for a package import.\n\t */\n\tprivate static final class PackageImports {\n\n\t\tprivate final List<String> packageNames;\n\n\t\tPackageImports(AnnotationMetadata metadata) {\n\t\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t\t.fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));\n\t\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\t\tList<String> packageNames = new ArrayList<>(Arrays.asList(attributes.getStringArray(\"basePackages\")));\n\t\t\tfor (Class<?> basePackageClass : attributes.getClassArray(\"basePackageClasses\")) {\n\t\t\t\tpackageNames.add(basePackageClass.getPackage().getName());\n\t\t\t}\n\t\t\tif (packageNames.isEmpty()) {\n\t\t\t\tpackageNames.add(ClassUtils.getPackageName(metadata.getClassName()));\n\t\t\t}\n\t\t\tthis.packageNames = Collections.unmodifiableList(packageNames);\n\t\t}\n\n\t\tList<String> getPackageNames() {\n\t\t\treturn this.packageNames;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.packageNames.equals(((PackageImports) obj).packageNames);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.packageNames.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Package Imports \" + this.packageNames;\n\t\t}\n\n\t}\n\n\t/**\n\t * Holder for the base package (name may be null to indicate no scanning).\n\t */\n\tstatic final class BasePackages {\n\n\t\tprivate final List<String> packages;\n\n\t\tprivate boolean loggedBasePackageInfo;\n\n\t\tBasePackages(String... names) {\n\t\t\tList<String> packages = new ArrayList<>();\n\t\t\tfor (String name : names) {\n\t\t\t\tif (StringUtils.hasText(name)) {\n\t\t\t\t\tpackages.add(name);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.packages = packages;\n\t\t}\n\n\t\tList<String> get() {\n\t\t\tif (!this.loggedBasePackageInfo) {\n\t\t\t\tif (this.packages.isEmpty()) {\n\t\t\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\t\t\tlogger.warn(\"@EnableAutoConfiguration was declared on a class \"\n\t\t\t\t\t\t\t\t+ \"in the default package. Automatic @Repository and \"\n\t\t\t\t\t\t\t\t+ \"@Entity scanning is not enabled.\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\tString packageNames = StringUtils.collectionToCommaDelimitedString(this.packages);\n\t\t\t\t\t\tlogger.debug(\"@EnableAutoConfiguration was declared on a class in the package '\" + packageNames\n\t\t\t\t\t\t\t\t+ \"'. Automatic @Repository and @Entity scanning is enabled.\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.loggedBasePackageInfo = true;\n\t\t\t}\n\t\t\treturn this.packages;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationReplacements.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.core.io.UrlResource;\nimport org.springframework.util.Assert;\n\n/**\n * Contains auto-configuration replacements used to handle deprecated or moved\n * auto-configurations which may still be referenced by\n * {@link AutoConfigureBefore @AutoConfigureBefore},\n * {@link AutoConfigureAfter @AutoConfigureAfter} or exclusions.\n *\n * @author Phillip Webb\n */\nfinal class AutoConfigurationReplacements {\n\n\tprivate static final String LOCATION = \"META-INF/spring/%s.replacements\";\n\n\tprivate final Map<String, String> replacements;\n\n\tprivate AutoConfigurationReplacements(Map<String, String> replacements) {\n\t\tthis.replacements = Map.copyOf(replacements);\n\t}\n\n\tSet<String> replaceAll(Set<String> classNames) {\n\t\tSet<String> replaced = new LinkedHashSet<>(classNames.size());\n\t\tfor (String className : classNames) {\n\t\t\treplaced.add(replace(className));\n\t\t}\n\t\treturn replaced;\n\t}\n\n\tString replace(String className) {\n\t\treturn this.replacements.getOrDefault(className, className);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.replacements.equals(((AutoConfigurationReplacements) obj).replacements);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.replacements.hashCode();\n\t}\n\n\t/**\n\t * Loads the relocations from the classpath. Relocations are stored in files named\n\t * {@code META-INF/spring/full-qualified-annotation-name.replacements} on the\n\t * classpath. The file is loaded using {@link Properties#load(java.io.InputStream)}\n\t * with each entry containing an auto-configuration class name as the key and the\n\t * replacement class name as the value.\n\t * @param annotation annotation to load\n\t * @param classLoader class loader to use for loading\n\t * @return list of names of annotated classes\n\t */\n\tstatic AutoConfigurationReplacements load(Class<?> annotation, @Nullable ClassLoader classLoader) {\n\t\tAssert.notNull(annotation, \"'annotation' must not be null\");\n\t\tClassLoader classLoaderToUse = decideClassloader(classLoader);\n\t\tString location = String.format(LOCATION, annotation.getName());\n\t\tEnumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);\n\t\tMap<String, String> replacements = new HashMap<>();\n\t\twhile (urls.hasMoreElements()) {\n\t\t\tURL url = urls.nextElement();\n\t\t\treplacements.putAll(readReplacements(url));\n\t\t}\n\t\treturn new AutoConfigurationReplacements(replacements);\n\t}\n\n\tprivate static ClassLoader decideClassloader(@Nullable ClassLoader classLoader) {\n\t\tif (classLoader == null) {\n\t\t\treturn ImportCandidates.class.getClassLoader();\n\t\t}\n\t\treturn classLoader;\n\t}\n\n\tprivate static Enumeration<URL> findUrlsInClasspath(ClassLoader classLoader, String location) {\n\t\ttry {\n\t\t\treturn classLoader.getResources(location);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to load configurations from location [\" + location + \"]\", ex);\n\t\t}\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate static Map<String, String> readReplacements(URL url) {\n\t\ttry (BufferedReader reader = new BufferedReader(\n\t\t\t\tnew InputStreamReader(new UrlResource(url).getInputStream(), StandardCharsets.UTF_8))) {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.load(reader);\n\t\t\treturn (Map) properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Unable to load replacements from location [\" + url + \"]\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationSorter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.util.Assert;\n\n/**\n * Sort {@link EnableAutoConfiguration auto-configuration} classes into priority order by\n * reading {@link AutoConfigureOrder @AutoConfigureOrder},\n * {@link AutoConfigureBefore @AutoConfigureBefore} and\n * {@link AutoConfigureAfter @AutoConfigureAfter} annotations (without loading classes).\n *\n * @author Phillip Webb\n */\nclass AutoConfigurationSorter {\n\n\tprivate final MetadataReaderFactory metadataReaderFactory;\n\n\tprivate final @Nullable AutoConfigurationMetadata autoConfigurationMetadata;\n\n\tprivate final @Nullable UnaryOperator<String> replacementMapper;\n\n\tAutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,\n\t\t\t@Nullable AutoConfigurationMetadata autoConfigurationMetadata,\n\t\t\t@Nullable UnaryOperator<String> replacementMapper) {\n\t\tAssert.notNull(metadataReaderFactory, \"'metadataReaderFactory' must not be null\");\n\t\tthis.metadataReaderFactory = metadataReaderFactory;\n\t\tthis.autoConfigurationMetadata = autoConfigurationMetadata;\n\t\tthis.replacementMapper = replacementMapper;\n\t}\n\n\tList<String> getInPriorityOrder(Collection<String> classNames) {\n\t\t// Initially sort alphabetically\n\t\tList<String> alphabeticallyOrderedClassNames = new ArrayList<>(classNames);\n\t\tCollections.sort(alphabeticallyOrderedClassNames);\n\t\t// Then sort by order\n\t\tAutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,\n\t\t\t\tthis.autoConfigurationMetadata, alphabeticallyOrderedClassNames);\n\t\tList<String> orderedClassNames = new ArrayList<>(classNames);\n\t\tCollections.sort(orderedClassNames);\n\t\torderedClassNames.sort((o1, o2) -> {\n\t\t\tint i1 = classes.get(o1).getOrder();\n\t\t\tint i2 = classes.get(o2).getOrder();\n\t\t\treturn Integer.compare(i1, i2);\n\t\t});\n\t\t// Then respect @AutoConfigureBefore @AutoConfigureAfter\n\t\torderedClassNames = sortByAnnotation(classes, orderedClassNames);\n\t\treturn orderedClassNames;\n\t}\n\n\tprivate List<String> sortByAnnotation(AutoConfigurationClasses classes, List<String> classNames) {\n\t\tList<String> toSort = new ArrayList<>(classNames);\n\t\ttoSort.addAll(classes.getAllNames());\n\t\tSet<String> sorted = new LinkedHashSet<>();\n\t\tSet<String> processing = new LinkedHashSet<>();\n\t\twhile (!toSort.isEmpty()) {\n\t\t\tdoSortByAfterAnnotation(classes, toSort, sorted, processing, null);\n\t\t}\n\t\tsorted.retainAll(classNames);\n\t\treturn new ArrayList<>(sorted);\n\t}\n\n\tprivate void doSortByAfterAnnotation(AutoConfigurationClasses classes, List<String> toSort, Set<String> sorted,\n\t\t\tSet<String> processing, @Nullable String current) {\n\t\tif (current == null) {\n\t\t\tcurrent = toSort.remove(0);\n\t\t}\n\t\tprocessing.add(current);\n\t\tSet<String> afters = new TreeSet<>(Comparator.comparing(toSort::indexOf));\n\t\tafters.addAll(classes.getClassesRequestedAfter(current));\n\t\tfor (String after : afters) {\n\t\t\tcheckForCycles(processing, current, after);\n\t\t\tif (!sorted.contains(after) && toSort.contains(after)) {\n\t\t\t\tdoSortByAfterAnnotation(classes, toSort, sorted, processing, after);\n\t\t\t}\n\t\t}\n\t\tprocessing.remove(current);\n\t\tsorted.add(current);\n\t}\n\n\tprivate void checkForCycles(Set<String> processing, String current, String after) {\n\t\tAssert.state(!processing.contains(after),\n\t\t\t\t() -> \"AutoConfigure cycle detected between \" + current + \" and \" + after);\n\t}\n\n\tprivate class AutoConfigurationClasses {\n\n\t\tprivate final Map<String, AutoConfigurationClass> classes = new LinkedHashMap<>();\n\n\t\tAutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,\n\t\t\t\t@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames) {\n\t\t\taddToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);\n\t\t}\n\n\t\tSet<String> getAllNames() {\n\t\t\treturn this.classes.keySet();\n\t\t}\n\n\t\tprivate void addToClasses(MetadataReaderFactory metadataReaderFactory,\n\t\t\t\t@Nullable AutoConfigurationMetadata autoConfigurationMetadata, Collection<String> classNames,\n\t\t\t\tboolean required) {\n\t\t\tfor (String className : classNames) {\n\t\t\t\tif (!this.classes.containsKey(className)) {\n\t\t\t\t\tAutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(className,\n\t\t\t\t\t\t\tmetadataReaderFactory, autoConfigurationMetadata);\n\t\t\t\t\tboolean available = autoConfigurationClass.isAvailable();\n\t\t\t\t\tif (required || available) {\n\t\t\t\t\t\tthis.classes.put(className, autoConfigurationClass);\n\t\t\t\t\t}\n\t\t\t\t\tif (available) {\n\t\t\t\t\t\taddToClasses(metadataReaderFactory, autoConfigurationMetadata,\n\t\t\t\t\t\t\t\tautoConfigurationClass.getBefore(), false);\n\t\t\t\t\t\taddToClasses(metadataReaderFactory, autoConfigurationMetadata,\n\t\t\t\t\t\t\t\tautoConfigurationClass.getAfter(), false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tAutoConfigurationClass get(String className) {\n\t\t\tAutoConfigurationClass autoConfigurationClass = this.classes.get(className);\n\t\t\tAssert.state(autoConfigurationClass != null, \"'autoConfigurationClass' must not be null\");\n\t\t\treturn autoConfigurationClass;\n\t\t}\n\n\t\tSet<String> getClassesRequestedAfter(String className) {\n\t\t\tSet<String> classesRequestedAfter = new LinkedHashSet<>(get(className).getAfter());\n\t\t\tthis.classes.forEach((name, autoConfigurationClass) -> {\n\t\t\t\tif (autoConfigurationClass.getBefore().contains(className)) {\n\t\t\t\t\tclassesRequestedAfter.add(name);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn classesRequestedAfter;\n\t\t}\n\n\t}\n\n\tprivate class AutoConfigurationClass {\n\n\t\tprivate final String className;\n\n\t\tprivate final MetadataReaderFactory metadataReaderFactory;\n\n\t\tprivate final @Nullable AutoConfigurationMetadata autoConfigurationMetadata;\n\n\t\tprivate volatile @Nullable AnnotationMetadata annotationMetadata;\n\n\t\tprivate volatile @Nullable Set<String> before;\n\n\t\tprivate volatile @Nullable Set<String> after;\n\n\t\tAutoConfigurationClass(String className, MetadataReaderFactory metadataReaderFactory,\n\t\t\t\t@Nullable AutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t\tthis.className = className;\n\t\t\tthis.metadataReaderFactory = metadataReaderFactory;\n\t\t\tthis.autoConfigurationMetadata = autoConfigurationMetadata;\n\t\t}\n\n\t\tboolean isAvailable() {\n\t\t\ttry {\n\t\t\t\tif (!wasProcessed()) {\n\t\t\t\t\tgetAnnotationMetadata();\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tSet<String> getBefore() {\n\t\t\tSet<String> before = this.before;\n\t\t\tif (before == null) {\n\t\t\t\tbefore = getClassNames(\"AutoConfigureBefore\", AutoConfigureBefore.class);\n\t\t\t\tthis.before = before;\n\t\t\t}\n\t\t\treturn before;\n\t\t}\n\n\t\tSet<String> getAfter() {\n\t\t\tSet<String> after = this.after;\n\t\t\tif (after == null) {\n\t\t\t\tafter = getClassNames(\"AutoConfigureAfter\", AutoConfigureAfter.class);\n\t\t\t\tthis.after = after;\n\t\t\t}\n\t\t\treturn after;\n\t\t}\n\n\t\tprivate Set<String> getClassNames(String metadataKey, Class<? extends Annotation> annotation) {\n\t\t\tSet<String> annotationValue = wasProcessed() ? getSet(metadataKey) : getAnnotationValue(annotation);\n\t\t\treturn applyReplacements(annotationValue);\n\t\t}\n\n\t\tprivate Set<String> getSet(String metadataKey) {\n\t\t\tAssert.state(this.autoConfigurationMetadata != null, \"'autoConfigurationMetadata' must not be null\");\n\t\t\treturn this.autoConfigurationMetadata.getSet(this.className, metadataKey, Collections.emptySet());\n\t\t}\n\n\t\tprivate Set<String> applyReplacements(Set<String> values) {\n\t\t\tif (AutoConfigurationSorter.this.replacementMapper == null) {\n\t\t\t\treturn values;\n\t\t\t}\n\t\t\tSet<String> replaced = new LinkedHashSet<>(values);\n\t\t\tfor (String value : values) {\n\t\t\t\treplaced.add(AutoConfigurationSorter.this.replacementMapper.apply(value));\n\t\t\t}\n\t\t\treturn replaced;\n\t\t}\n\n\t\tprivate int getOrder() {\n\t\t\tif (wasProcessed()) {\n\t\t\t\tAssert.state(this.autoConfigurationMetadata != null, \"'autoConfigurationMetadata' must not be null\");\n\t\t\t\treturn this.autoConfigurationMetadata.getInteger(this.className, \"AutoConfigureOrder\",\n\t\t\t\t\t\tAutoConfigureOrder.DEFAULT_ORDER);\n\t\t\t}\n\t\t\tMap<String, @Nullable Object> attributes = getAnnotationMetadata()\n\t\t\t\t.getAnnotationAttributes(AutoConfigureOrder.class.getName());\n\t\t\tif (attributes != null) {\n\t\t\t\tInteger value = (Integer) attributes.get(\"value\");\n\t\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\treturn AutoConfigureOrder.DEFAULT_ORDER;\n\t\t}\n\n\t\tprivate boolean wasProcessed() {\n\t\t\treturn (this.autoConfigurationMetadata != null\n\t\t\t\t\t&& this.autoConfigurationMetadata.wasProcessed(this.className));\n\t\t}\n\n\t\tprivate Set<String> getAnnotationValue(Class<?> annotation) {\n\t\t\tMap<String, @Nullable Object> attributes = getAnnotationMetadata()\n\t\t\t\t.getAnnotationAttributes(annotation.getName(), true);\n\t\t\tif (attributes == null) {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\t\t\tSet<String> result = new LinkedHashSet<>();\n\t\t\tString[] value = (String[]) attributes.get(\"value\");\n\t\t\tString[] name = (String[]) attributes.get(\"name\");\n\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\tCollections.addAll(result, value);\n\t\t\tCollections.addAll(result, name);\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate AnnotationMetadata getAnnotationMetadata() {\n\t\t\tAnnotationMetadata annotationMetadata = this.annotationMetadata;\n\t\t\tif (annotationMetadata == null) {\n\t\t\t\ttry {\n\t\t\t\t\tMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(this.className);\n\t\t\t\t\tannotationMetadata = metadataReader.getAnnotationMetadata();\n\t\t\t\t\tthis.annotationMetadata = annotationMetadata;\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new IllegalStateException(\"Unable to read meta-data for class \" + this.className, ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn annotationMetadata;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.UnaryOperator;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.context.annotation.Configurations;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link Configurations} representing auto-configuration {@code @Configuration} classes.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class AutoConfigurations extends Configurations implements Ordered {\n\n\tprivate static final SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\tprivate static final int ORDER = AutoConfigurationImportSelector.ORDER;\n\n\tstatic final AutoConfigurationReplacements replacements = AutoConfigurationReplacements\n\t\t.load(AutoConfiguration.class, null);\n\n\tprivate final UnaryOperator<String> replacementMapper;\n\n\tprotected AutoConfigurations(Collection<Class<?>> classes) {\n\t\tthis(replacements::replace, classes);\n\t}\n\n\tAutoConfigurations(UnaryOperator<String> replacementMapper, Collection<Class<?>> classes) {\n\t\tsuper(sorter(replacementMapper), classes, Class::getName);\n\t\tthis.replacementMapper = replacementMapper;\n\t}\n\n\tprivate static UnaryOperator<Collection<Class<?>>> sorter(UnaryOperator<String> replacementMapper) {\n\t\tAutoConfigurationSorter sorter = new AutoConfigurationSorter(metadataReaderFactory, null, replacementMapper);\n\t\treturn (classes) -> {\n\t\t\tList<String> names = classes.stream().map(Class::getName).map(replacementMapper).toList();\n\t\t\tList<String> sorted = sorter.getInPriorityOrder(names);\n\t\t\treturn sorted.stream()\n\t\t\t\t.map((className) -> ClassUtils.resolveClassName(className, null))\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t};\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tprotected AutoConfigurations merge(Set<Class<?>> mergedClasses) {\n\t\treturn new AutoConfigurations(this.replacementMapper, mergedClasses);\n\t}\n\n\tpublic static AutoConfigurations of(Class<?>... classes) {\n\t\treturn new AutoConfigurations(Arrays.asList(classes));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigureAfter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\n/**\n * Hint for that an {@link EnableAutoConfiguration auto-configuration} should be applied\n * after other specified auto-configuration classes.\n * <p>\n * As with standard {@link Configuration @Configuration} classes, the order in which\n * auto-configuration classes are applied only affects the order in which their beans are\n * defined. The order in which those beans are subsequently created is unaffected and is\n * determined by each bean's dependencies and any {@link DependsOn @DependsOn}\n * relationships.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE })\n@Documented\npublic @interface AutoConfigureAfter {\n\n\t/**\n\t * The auto-configuration classes that should have already been applied.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #name} attribute.\n\t * @return the classes\n\t */\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The names of the auto-configuration classes that should have already been applied.\n\t * In the unusual case that an auto-configuration class is not a top-level class, its\n\t * class name should use {@code $} to separate it from its containing class, for\n\t * example {@code com.example.Outer$NestedAutoConfiguration}.\n\t * @return the class names\n\t * @since 1.2.2\n\t */\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigureBefore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\n\n/**\n * Hint that an {@link EnableAutoConfiguration auto-configuration} should be applied\n * before other specified auto-configuration classes.\n * <p>\n * As with standard {@link Configuration @Configuration} classes, the order in which\n * auto-configuration classes are applied only affects the order in which their beans are\n * defined. The order in which those beans are subsequently created is unaffected and is\n * determined by each bean's dependencies and any {@link DependsOn @DependsOn}\n * relationships.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE })\n@Documented\npublic @interface AutoConfigureBefore {\n\n\t/**\n\t * The auto-configuration classes that should have not yet been applied.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #name} attribute.\n\t * @return the classes\n\t */\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The names of the auto-configuration classes that should have not yet been applied.\n\t * In the unusual case that an auto-configuration class is not a top-level class, its\n\t * class name should use {@code $} to separate it from its containing class, for\n\t * example {@code com.example.Outer$NestedAutoConfiguration}.\n\t * @return the class names\n\t * @since 1.2.2\n\t */\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigureOrder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Auto-configuration specific variant of Spring Framework's {@link Order @Order}\n * annotation. Allows auto-configuration classes to be ordered among themselves without\n * affecting the order of configuration classes passed to\n * {@link AnnotationConfigApplicationContext#register(Class...)}.\n * <p>\n * As with standard {@link Configuration @Configuration} classes, the order in which\n * auto-configuration classes are applied only affects the order in which their beans are\n * defined. The order in which those beans are subsequently created is unaffected and is\n * determined by each bean's dependencies and any {@link DependsOn @DependsOn}\n * relationships.\n *\n * @author Andy Wilkinson\n * @since 1.3.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })\n@Documented\npublic @interface AutoConfigureOrder {\n\n\t/**\n\t * The default order value.\n\t */\n\tint DEFAULT_ORDER = 0;\n\n\t/**\n\t * The order value. Default is {@code 0}.\n\t * @see Ordered#getOrder()\n\t * @return the order value\n\t */\n\tint value() default DEFAULT_ORDER;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Enable auto-configuration of the Spring Application Context, attempting to guess and\n * configure beans that you are likely to need. Auto-configuration classes are usually\n * applied based on your classpath and what beans you have defined.\n * <p>\n * When using {@link SpringBootApplication @SpringBootApplication}, the auto-configuration\n * of the context is automatically enabled and adding this annotation has therefore no\n * additional effect.\n * <p>\n * Auto-configuration tries to be as intelligent as possible and will back-away as you\n * define more of your own configuration. You can always manually {@link #exclude()} any\n * configuration that you never want to apply (use {@link #excludeName()} if you don't\n * have access to them). You can also exclude them through the\n * {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied\n * after user-defined beans have been registered.\n * <p>\n * The package of the class that is annotated with {@code @EnableAutoConfiguration},\n * usually through {@code @SpringBootApplication}, has specific significance and is often\n * used as a 'default'. For example, it will be used when scanning for {@code @Entity}\n * classes. It is generally recommended that you place {@code @EnableAutoConfiguration}\n * (if you're not using {@code @SpringBootApplication}) in a root package so that all\n * sub-packages and classes can be searched.\n * <p>\n * Auto-configuration classes are regular Spring {@link Configuration @Configuration}\n * beans. They are located using {@link ImportCandidates}. Generally auto-configuration\n * beans are {@link Conditional @Conditional} beans (most often using\n * {@link ConditionalOnClass @ConditionalOnClass} and\n * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 1.0.0\n * @see ConditionalOnBean\n * @see ConditionalOnMissingBean\n * @see ConditionalOnClass\n * @see AutoConfigureAfter\n * @see SpringBootApplication\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigurationPackage\n@Import(AutoConfigurationImportSelector.class)\npublic @interface EnableAutoConfiguration {\n\n\t/**\n\t * Environment property that can be used to override when auto-configuration is\n\t * enabled.\n\t */\n\tString ENABLED_OVERRIDE_PROPERTY = \"spring.boot.enableautoconfiguration\";\n\n\t/**\n\t * Exclude specific auto-configuration classes such that they will never be applied.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #excludeName()} attribute.\n\t * @return the classes to exclude\n\t */\n\tClass<?>[] exclude() default {};\n\n\t/**\n\t * Exclude specific auto-configuration class names such that they will never be\n\t * applied.\n\t * @return the class names to exclude\n\t * @since 1.3.0\n\t */\n\tString[] excludeName() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Import and apply the specified auto-configuration classes. Applies the same ordering\n * rules as {@code @EnableAutoConfiguration} but restricts the auto-configuration classes\n * to the specified set, rather than consulting {@link ImportCandidates}.\n * <p>\n * Can also be used to {@link #exclude()} specific auto-configuration classes such that\n * they will never be applied.\n * <p>\n * Generally, {@code @EnableAutoConfiguration} should be used in preference to this\n * annotation, however, {@code @ImportAutoConfiguration} can be useful in some situations\n * and especially when writing tests.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.3.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Import(ImportAutoConfigurationImportSelector.class)\npublic @interface ImportAutoConfiguration {\n\n\t/**\n\t * The auto-configuration classes that should be imported. This is an alias for\n\t * {@link #classes()}.\n\t * @return the classes to import\n\t */\n\t@AliasFor(\"classes\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The auto-configuration classes that should be imported. When empty, the classes are\n\t * specified using a file in {@code META-INF/spring} where the file name is the\n\t * fully-qualified name of the annotated class, suffixed with {@code .imports}. An\n\t * entry in the file may be prefixed with {@code optional:} to indicate that the\n\t * imported class should be ignored if it is not on the classpath.\n\t * @return the classes to import\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] classes() default {};\n\n\t/**\n\t * Exclude specific auto-configuration classes such that they will never be applied.\n\t * @return the classes to exclude\n\t */\n\tClass<?>[] exclude() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.annotation.DeterminableImports;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Variant of {@link AutoConfigurationImportSelector} for\n * {@link ImportAutoConfiguration @ImportAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Scott Frederick\n */\nclass ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector implements DeterminableImports {\n\n\tprivate static final String OPTIONAL_PREFIX = \"optional:\";\n\n\tprivate static final Set<String> ANNOTATION_NAMES;\n\n\tstatic {\n\t\tSet<String> names = new LinkedHashSet<>();\n\t\tnames.add(ImportAutoConfiguration.class.getName());\n\t\tnames.add(\"org.springframework.boot.autoconfigure.test.ImportAutoConfiguration\");\n\t\tANNOTATION_NAMES = Collections.unmodifiableSet(names);\n\t}\n\n\t@Override\n\tpublic Set<Object> determineImports(AnnotationMetadata metadata) {\n\t\tList<String> candidateConfigurations = getCandidateConfigurations(metadata, null);\n\t\tSet<String> result = new LinkedHashSet<>(candidateConfigurations);\n\t\tresult.removeAll(getExclusions(metadata, null));\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n\t@Override\n\tprotected @Nullable AnnotationAttributes getAttributes(AnnotationMetadata metadata) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected List<String> getCandidateConfigurations(AnnotationMetadata metadata,\n\t\t\t@Nullable AnnotationAttributes attributes) {\n\t\tList<String> candidates = new ArrayList<>();\n\t\tMap<Class<?>, List<Annotation>> annotations = getAnnotations(metadata);\n\t\tannotations.forEach(\n\t\t\t\t(source, sourceAnnotations) -> collectCandidateConfigurations(source, sourceAnnotations, candidates));\n\t\treturn candidates;\n\t}\n\n\tprivate void collectCandidateConfigurations(Class<?> source, List<Annotation> annotations,\n\t\t\tList<String> candidates) {\n\t\tfor (Annotation annotation : annotations) {\n\t\t\tcandidates.addAll(getConfigurationsForAnnotation(source, annotation));\n\t\t}\n\t}\n\n\tprivate Collection<String> getConfigurationsForAnnotation(Class<?> source, Annotation annotation) {\n\t\tString[] classes = (String[]) AnnotationUtils.getAnnotationAttributes(annotation, true).get(\"classes\");\n\t\tif (classes != null && classes.length > 0) {\n\t\t\treturn Arrays.asList(classes);\n\t\t}\n\t\treturn loadFactoryNames(source).stream().map(this::mapFactoryName).filter(Objects::nonNull).toList();\n\t}\n\n\tprivate @Nullable String mapFactoryName(String name) {\n\t\tif (!name.startsWith(OPTIONAL_PREFIX)) {\n\t\t\treturn name;\n\t\t}\n\t\tname = name.substring(OPTIONAL_PREFIX.length());\n\t\treturn (!present(name)) ? null : name;\n\t}\n\n\tprivate boolean present(String className) {\n\t\tString resourcePath = ClassUtils.convertClassNameToResourcePath(className) + \".class\";\n\t\treturn new ClassPathResource(resourcePath).exists();\n\t}\n\n\tprotected Collection<String> loadFactoryNames(Class<?> source) {\n\t\treturn ImportCandidates.load(source, getBeanClassLoader()).getCandidates();\n\t}\n\n\t@Override\n\tprotected Set<String> getExclusions(AnnotationMetadata metadata, @Nullable AnnotationAttributes attributes) {\n\t\tSet<String> exclusions = new LinkedHashSet<>();\n\t\tClass<?> source = ClassUtils.resolveClassName(metadata.getClassName(), getBeanClassLoader());\n\t\tfor (String annotationName : ANNOTATION_NAMES) {\n\t\t\tAnnotationAttributes merged = AnnotatedElementUtils.getMergedAnnotationAttributes(source, annotationName);\n\t\t\tClass<?>[] exclude = (merged != null) ? merged.getClassArray(\"exclude\") : null;\n\t\t\tif (exclude != null) {\n\t\t\t\tfor (Class<?> excludeClass : exclude) {\n\t\t\t\t\texclusions.add(excludeClass.getName());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (List<Annotation> annotations : getAnnotations(metadata).values()) {\n\t\t\tfor (Annotation annotation : annotations) {\n\t\t\t\tString[] exclude = (String[]) AnnotationUtils.getAnnotationAttributes(annotation, true).get(\"exclude\");\n\t\t\t\tif (!ObjectUtils.isEmpty(exclude)) {\n\t\t\t\t\texclusions.addAll(Arrays.asList(exclude));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\texclusions.addAll(getExcludeAutoConfigurationsProperty());\n\t\treturn exclusions;\n\t}\n\n\tprotected final Map<Class<?>, List<Annotation>> getAnnotations(AnnotationMetadata metadata) {\n\t\tMultiValueMap<Class<?>, Annotation> annotations = new LinkedMultiValueMap<>();\n\t\tClass<?> source = ClassUtils.resolveClassName(metadata.getClassName(), getBeanClassLoader());\n\t\tcollectAnnotations(source, annotations, new HashSet<>());\n\t\treturn Collections.unmodifiableMap(annotations);\n\t}\n\n\tprivate void collectAnnotations(@Nullable Class<?> source, MultiValueMap<Class<?>, Annotation> annotations,\n\t\t\tHashSet<Class<?>> seen) {\n\t\tif (source != null && seen.add(source)) {\n\t\t\tfor (Annotation annotation : source.getDeclaredAnnotations()) {\n\t\t\t\tif (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {\n\t\t\t\t\tif (ANNOTATION_NAMES.contains(annotation.annotationType().getName())) {\n\t\t\t\t\t\tannotations.add(source, annotation);\n\t\t\t\t\t}\n\t\t\t\t\tcollectAnnotations(annotation.annotationType(), annotations, seen);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcollectAnnotations(source.getSuperclass(), annotations, seen);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn super.getOrder() - 1;\n\t}\n\n\t@Override\n\tprotected void handleInvalidExcludes(List<String> invalidExcludes) {\n\t\t// Ignore for test\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.RuntimeBeanReference;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.ConfigurationClassPostProcessor;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\n\n/**\n * {@link ApplicationContextInitializer} to create a shared\n * {@link CachingMetadataReaderFactory} between the\n * {@link ConfigurationClassPostProcessor} and Spring Boot.\n *\n * @author Phillip Webb\n * @author Dave Syer\n */\nclass SharedMetadataReaderFactoryContextInitializer implements\n\t\tApplicationContextInitializer<ConfigurableApplicationContext>, Ordered, BeanRegistrationExcludeFilter {\n\n\tpublic static final String BEAN_NAME = \"org.springframework.boot.autoconfigure.\"\n\t\t\t+ \"internalCachingMetadataReaderFactory\";\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn;\n\t\t}\n\t\tBeanFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(applicationContext);\n\t\tapplicationContext.addBeanFactoryPostProcessor(postProcessor);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {\n\t\treturn BEAN_NAME.equals(registeredBean.getBeanName());\n\t}\n\n\t/**\n\t * {@link BeanDefinitionRegistryPostProcessor} to register the\n\t * {@link CachingMetadataReaderFactory} and configure the\n\t * {@link ConfigurationClassPostProcessor}.\n\t */\n\tstatic class CachingMetadataReaderFactoryPostProcessor\n\t\t\timplements BeanDefinitionRegistryPostProcessor, PriorityOrdered {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tCachingMetadataReaderFactoryPostProcessor(ConfigurableApplicationContext context) {\n\t\t\tthis.context = context;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\t// Must happen before the ConfigurationClassPostProcessor is created\n\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n\t\t\tregister(registry);\n\t\t\tconfigureConfigurationClassPostProcessor(registry);\n\t\t}\n\n\t\tprivate void register(BeanDefinitionRegistry registry) {\n\t\t\tif (!registry.containsBeanDefinition(BEAN_NAME)) {\n\t\t\t\tBeanDefinition definition = BeanDefinitionBuilder\n\t\t\t\t\t.rootBeanDefinition(SharedMetadataReaderFactoryBean.class, SharedMetadataReaderFactoryBean::new)\n\t\t\t\t\t.getBeanDefinition();\n\t\t\t\tregistry.registerBeanDefinition(BEAN_NAME, definition);\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureConfigurationClassPostProcessor(BeanDefinitionRegistry registry) {\n\t\t\ttry {\n\t\t\t\tconfigureConfigurationClassPostProcessor(\n\t\t\t\t\t\tregistry.getBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureConfigurationClassPostProcessor(BeanDefinition definition) {\n\t\t\tif (definition instanceof AbstractBeanDefinition abstractBeanDefinition) {\n\t\t\t\tconfigureConfigurationClassPostProcessor(abstractBeanDefinition);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconfigureConfigurationClassPostProcessor(definition.getPropertyValues());\n\t\t}\n\n\t\tprivate void configureConfigurationClassPostProcessor(AbstractBeanDefinition definition) {\n\t\t\tSupplier<?> instanceSupplier = definition.getInstanceSupplier();\n\t\t\tif (instanceSupplier != null) {\n\t\t\t\tdefinition.setInstanceSupplier(\n\t\t\t\t\t\tnew ConfigurationClassPostProcessorCustomizingSupplier(this.context, instanceSupplier));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconfigureConfigurationClassPostProcessor(definition.getPropertyValues());\n\t\t}\n\n\t\tprivate void configureConfigurationClassPostProcessor(MutablePropertyValues propertyValues) {\n\t\t\tpropertyValues.add(\"metadataReaderFactory\", new RuntimeBeanReference(BEAN_NAME));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Supplier} used to customize the {@link ConfigurationClassPostProcessor} when\n\t * it's first created.\n\t */\n\tstatic class ConfigurationClassPostProcessorCustomizingSupplier implements Supplier<Object> {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tprivate final Supplier<?> instanceSupplier;\n\n\t\tConfigurationClassPostProcessorCustomizingSupplier(ConfigurableApplicationContext context,\n\t\t\t\tSupplier<?> instanceSupplier) {\n\t\t\tthis.context = context;\n\t\t\tthis.instanceSupplier = instanceSupplier;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object get() {\n\t\t\tObject instance = this.instanceSupplier.get();\n\t\t\tif (instance instanceof ConfigurationClassPostProcessor postProcessor) {\n\t\t\t\tconfigureConfigurationClassPostProcessor(postProcessor);\n\t\t\t}\n\t\t\treturn instance;\n\t\t}\n\n\t\tprivate void configureConfigurationClassPostProcessor(ConfigurationClassPostProcessor instance) {\n\t\t\tinstance.setMetadataReaderFactory(this.context.getBean(BEAN_NAME, MetadataReaderFactory.class));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link FactoryBean} to create the shared {@link MetadataReaderFactory}.\n\t */\n\tstatic class SharedMetadataReaderFactoryBean implements FactoryBean<CachingMetadataReaderFactory>,\n\t\t\tResourceLoaderAware, ApplicationListener<ContextRefreshedEvent> {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate CachingMetadataReaderFactory metadataReaderFactory;\n\n\t\t@Override\n\t\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\t\tthis.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);\n\t\t}\n\n\t\t@Override\n\t\tpublic CachingMetadataReaderFactory getObject() throws Exception {\n\t\t\treturn this.metadataReaderFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn CachingMetadataReaderFactory.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isSingleton() {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextRefreshedEvent event) {\n\t\t\tthis.metadataReaderFactory.clearCache();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.context.annotation.AnnotationBeanNameGenerator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Indicates a {@link Configuration configuration} class that declares one or more\n * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration\n * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience\n * annotation that is equivalent to declaring {@code @SpringBootConfiguration},\n * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 1.2.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@SpringBootConfiguration\n@EnableAutoConfiguration\n@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),\n\t\t@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })\npublic @interface SpringBootApplication {\n\n\t/**\n\t * Exclude specific auto-configuration classes such that they will never be applied.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #excludeName} attribute.\n\t * @return the classes to exclude\n\t */\n\t@AliasFor(annotation = EnableAutoConfiguration.class)\n\tClass<?>[] exclude() default {};\n\n\t/**\n\t * Exclude specific auto-configuration class names such that they will never be\n\t * applied.\n\t * @return the class names to exclude\n\t * @since 1.3.0\n\t */\n\t@AliasFor(annotation = EnableAutoConfiguration.class)\n\tString[] excludeName() default {};\n\n\t/**\n\t * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}\n\t * for a type-safe alternative to String-based package names.\n\t * <p>\n\t * <strong>Note:</strong> this setting is an alias for\n\t * {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}\n\t * scanning or Spring Data repository scanning. For those you should add\n\t * {@code @EntityScan} and {@code @Enable...Repositories} annotations.\n\t * @return base packages to scan\n\t * @since 1.3.0\n\t */\n\t@AliasFor(annotation = ComponentScan.class, attribute = \"basePackages\")\n\tString[] scanBasePackages() default {};\n\n\t/**\n\t * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to\n\t * scan for annotated components. The package of each class specified will be scanned.\n\t * <p>\n\t * Consider creating a special no-op marker class or interface in each package that\n\t * serves no purpose other than being referenced by this attribute.\n\t * <p>\n\t * <strong>Note:</strong> this setting is an alias for\n\t * {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}\n\t * scanning or Spring Data repository scanning. For those you should add\n\t * {@code @EntityScan} and {@code @Enable...Repositories} annotations.\n\t * @return base packages to scan\n\t * @since 1.3.0\n\t */\n\t@AliasFor(annotation = ComponentScan.class, attribute = \"basePackageClasses\")\n\tClass<?>[] scanBasePackageClasses() default {};\n\n\t/**\n\t * The {@link BeanNameGenerator} class to be used for naming detected components\n\t * within the Spring container.\n\t * <p>\n\t * The default value of the {@link BeanNameGenerator} interface itself indicates that\n\t * the scanner used to process this {@code @SpringBootApplication} annotation should\n\t * use its inherited bean name generator, e.g. the default\n\t * {@link AnnotationBeanNameGenerator} or any custom instance supplied to the\n\t * application context at bootstrap time.\n\t * @return {@link BeanNameGenerator} to use\n\t * @see SpringApplication#setBeanNameGenerator(BeanNameGenerator)\n\t * @since 2.3.0\n\t */\n\t@AliasFor(annotation = ComponentScan.class, attribute = \"nameGenerator\")\n\tClass<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;\n\n\t/**\n\t * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce\n\t * bean lifecycle behavior, e.g. to return shared singleton bean instances even in\n\t * case of direct {@code @Bean} method calls in user code. This feature requires\n\t * method interception, implemented through a runtime-generated CGLIB subclass which\n\t * comes with limitations such as the configuration class and its methods not being\n\t * allowed to declare {@code final}.\n\t * <p>\n\t * The default is {@code true}, allowing for 'inter-bean references' within the\n\t * configuration class as well as for external calls to this configuration's\n\t * {@code @Bean} methods, e.g. from another configuration class. If this is not needed\n\t * since each of this particular configuration's {@code @Bean} methods is\n\t * self-contained and designed as a plain factory method for container use, switch\n\t * this flag to {@code false} in order to avoid CGLIB subclass processing.\n\t * <p>\n\t * Turning off bean method interception effectively processes {@code @Bean} methods\n\t * individually like when declared on non-{@code @Configuration} classes, a.k.a.\n\t * \"@Bean Lite Mode\" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally\n\t * equivalent to removing the {@code @Configuration} stereotype.\n\t * @since 2.2\n\t * @return whether to proxy {@code @Bean} methods\n\t */\n\t@AliasFor(annotation = Configuration.class)\n\tboolean proxyBeanMethods() default true;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.admin;\n\nimport javax.management.MalformedObjectNameException;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.admin.SpringApplicationAdminMXBean;\nimport org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.jmx.export.MBeanExporter;\n\n/**\n * Register a JMX component that allows to administer the current application. Intended\n * for internal use only.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 1.3.0\n * @see SpringApplicationAdminMXBean\n */\n@AutoConfiguration(after = JmxAutoConfiguration.class)\n@ConditionalOnBooleanProperty(\"spring.application.admin.enabled\")\npublic final class SpringApplicationAdminJmxAutoConfiguration {\n\n\t/**\n\t * The property to use to customize the {@code ObjectName} of the application admin\n\t * mbean.\n\t */\n\tprivate static final String JMX_NAME_PROPERTY = \"spring.application.admin.jmx-name\";\n\n\t/**\n\t * The default {@code ObjectName} of the application admin mbean.\n\t */\n\tprivate static final String DEFAULT_JMX_NAME = \"org.springframework.boot:type=Admin,name=SpringApplication\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar(ObjectProvider<MBeanExporter> mbeanExporters,\n\t\t\tEnvironment environment) throws MalformedObjectNameException {\n\t\tString jmxName = environment.getProperty(JMX_NAME_PROPERTY, DEFAULT_JMX_NAME);\n\t\tif (mbeanExporters != null) { // Make sure to not register that MBean twice\n\t\t\tfor (MBeanExporter mbeanExporter : mbeanExporters) {\n\t\t\t\tmbeanExporter.addExcludedBean(jmxName);\n\t\t\t}\n\t\t}\n\t\treturn new SpringApplicationAdminMXBeanRegistrar(jmxName);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/admin/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for admin-related features.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.admin;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/aop/AopAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.aop;\n\nimport org.aspectj.weaver.Advice;\n\nimport org.springframework.aop.config.AopConfigUtils;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration\n * Auto-configuration} for Spring's AOP support. Equivalent to enabling\n * {@link EnableAspectJAutoProxy @EnableAspectJAutoProxy} in your configuration.\n * <p>\n * The configuration will not be activated if {@literal spring.aop.auto=false}. The\n * {@literal proxyTargetClass} attribute will be {@literal true}, by default, but can be\n * overridden by specifying {@literal spring.aop.proxy-target-class=false}.\n *\n * @author Dave Syer\n * @author Josh Long\n * @since 1.0.0\n * @see EnableAspectJAutoProxy\n */\n@AutoConfiguration\n@ConditionalOnBooleanProperty(name = \"spring.aop.auto\", matchIfMissing = true)\npublic final class AopAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Advice.class)\n\tstatic class AspectJAutoProxyingConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableAspectJAutoProxy(proxyTargetClass = false)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.aop.proxy-target-class\", havingValue = false)\n\t\tstatic class JdkDynamicAutoProxyConfiguration {\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableAspectJAutoProxy(proxyTargetClass = true)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.aop.proxy-target-class\", matchIfMissing = true)\n\t\tstatic class CglibAutoProxyConfiguration {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingClass(\"org.aspectj.weaver.Advice\")\n\t@ConditionalOnBooleanProperty(name = \"spring.aop.proxy-target-class\", matchIfMissing = true)\n\tstatic class ClassProxyingConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanFactoryPostProcessor forceAutoProxyCreatorToUseClassProxying() {\n\t\t\treturn (beanFactory) -> {\n\t\t\t\tif (beanFactory instanceof BeanDefinitionRegistry registry) {\n\t\t\t\t\tAopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);\n\t\t\t\t\tAopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/aop/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring AOP.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.aop;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/availability/ApplicationAvailabilityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.availability;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.ApplicationAvailabilityBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration} for\n * {@link ApplicationAvailabilityBean}.\n *\n * @author Brian Clozel\n * @author Taeik Lim\n * @since 2.3.0\n */\n@AutoConfiguration\npublic final class ApplicationAvailabilityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ApplicationAvailability.class)\n\tApplicationAvailabilityBean applicationAvailability() {\n\t\treturn new ApplicationAvailabilityBean();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/availability/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for application availability features.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.availability;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.cache;\n\n/**\n * Supported cache types (defined in order of precedence).\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @since 4.0.0\n */\npublic enum CacheType {\n\n\t/**\n\t * Generic caching using 'Cache' beans from the context.\n\t */\n\tGENERIC,\n\n\t/**\n\t * JCache (JSR-107) backed caching.\n\t */\n\tJCACHE,\n\n\t/**\n\t * Hazelcast backed caching.\n\t */\n\tHAZELCAST,\n\n\t/**\n\t * Couchbase backed caching.\n\t */\n\tCOUCHBASE,\n\n\t/**\n\t * Infinispan backed caching.\n\t */\n\tINFINISPAN,\n\n\t/**\n\t * Redis backed caching.\n\t */\n\tREDIS,\n\n\t/**\n\t * Cache2k backed caching.\n\t */\n\tCACHE2K,\n\n\t/**\n\t * Caffeine backed caching.\n\t */\n\tCAFFEINE,\n\n\t/**\n\t * Simple in-memory caching.\n\t */\n\tSIMPLE,\n\n\t/**\n\t * No caching.\n\t */\n\tNONE\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration base classes for Caching support.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.cache;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/AbstractNestedCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.ConfigurationCondition;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * Abstract base class for nested conditions.\n *\n * @author Phillip Webb\n * @since 1.5.22\n */\npublic abstract class AbstractNestedCondition extends SpringBootCondition implements ConfigurationCondition {\n\n\tprivate final ConfigurationPhase configurationPhase;\n\n\tAbstractNestedCondition(ConfigurationPhase configurationPhase) {\n\t\tAssert.notNull(configurationPhase, \"'configurationPhase' must not be null\");\n\t\tthis.configurationPhase = configurationPhase;\n\t}\n\n\t@Override\n\tpublic ConfigurationPhase getConfigurationPhase() {\n\t\treturn this.configurationPhase;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tString className = getClass().getName();\n\t\tMemberConditions memberConditions = new MemberConditions(context, this.configurationPhase, className);\n\t\tMemberMatchOutcomes memberOutcomes = new MemberMatchOutcomes(memberConditions);\n\t\treturn getFinalMatchOutcome(memberOutcomes);\n\t}\n\n\tprotected abstract ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes);\n\n\tprotected static class MemberMatchOutcomes {\n\n\t\tprivate final List<ConditionOutcome> all;\n\n\t\tprivate final List<ConditionOutcome> matches;\n\n\t\tprivate final List<ConditionOutcome> nonMatches;\n\n\t\tpublic MemberMatchOutcomes(MemberConditions memberConditions) {\n\t\t\tthis.all = Collections.unmodifiableList(memberConditions.getMatchOutcomes());\n\t\t\tList<ConditionOutcome> matches = new ArrayList<>();\n\t\t\tList<ConditionOutcome> nonMatches = new ArrayList<>();\n\t\t\tfor (ConditionOutcome outcome : this.all) {\n\t\t\t\t(outcome.isMatch() ? matches : nonMatches).add(outcome);\n\t\t\t}\n\t\t\tthis.matches = Collections.unmodifiableList(matches);\n\t\t\tthis.nonMatches = Collections.unmodifiableList(nonMatches);\n\t\t}\n\n\t\tpublic List<ConditionOutcome> getAll() {\n\t\t\treturn this.all;\n\t\t}\n\n\t\tpublic List<ConditionOutcome> getMatches() {\n\t\t\treturn this.matches;\n\t\t}\n\n\t\tpublic List<ConditionOutcome> getNonMatches() {\n\t\t\treturn this.nonMatches;\n\t\t}\n\n\t}\n\n\tprivate static class MemberConditions {\n\n\t\tprivate final ConditionContext context;\n\n\t\tprivate final MetadataReaderFactory readerFactory;\n\n\t\tprivate final Map<AnnotationMetadata, List<Condition>> memberConditions;\n\n\t\tMemberConditions(ConditionContext context, ConfigurationPhase phase, String className) {\n\t\t\tthis.context = context;\n\t\t\tthis.readerFactory = new SimpleMetadataReaderFactory(context.getResourceLoader());\n\t\t\tString[] members = getMetadata(className).getMemberClassNames();\n\t\t\tthis.memberConditions = getMemberConditions(members, phase, className);\n\t\t}\n\n\t\tprivate Map<AnnotationMetadata, List<Condition>> getMemberConditions(String[] members, ConfigurationPhase phase,\n\t\t\t\tString className) {\n\t\t\tMultiValueMap<AnnotationMetadata, Condition> memberConditions = new LinkedMultiValueMap<>();\n\t\t\tfor (String member : members) {\n\t\t\t\tAnnotationMetadata metadata = getMetadata(member);\n\t\t\t\tfor (String[] conditionClasses : getConditionClasses(metadata)) {\n\t\t\t\t\tfor (String conditionClass : conditionClasses) {\n\t\t\t\t\t\tCondition condition = getCondition(conditionClass);\n\t\t\t\t\t\tvalidateMemberCondition(condition, phase, className);\n\t\t\t\t\t\tmemberConditions.add(metadata, condition);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn Collections.unmodifiableMap(memberConditions);\n\t\t}\n\n\t\tprivate void validateMemberCondition(Condition condition, ConfigurationPhase nestedPhase,\n\t\t\t\tString nestedClassName) {\n\t\t\tif (nestedPhase == ConfigurationPhase.PARSE_CONFIGURATION\n\t\t\t\t\t&& condition instanceof ConfigurationCondition configurationCondition) {\n\t\t\t\tConfigurationPhase memberPhase = configurationCondition.getConfigurationPhase();\n\t\t\t\tif (memberPhase == ConfigurationPhase.REGISTER_BEAN) {\n\t\t\t\t\tthrow new IllegalStateException(\"Nested condition \" + nestedClassName + \" uses a configuration \"\n\t\t\t\t\t\t\t+ \"phase that is inappropriate for \" + condition.getClass());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate AnnotationMetadata getMetadata(String className) {\n\t\t\ttry {\n\t\t\t\treturn this.readerFactory.getMetadataReader(className).getAnnotationMetadata();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {\n\t\t\tMultiValueMap<String, @Nullable Object> attributes = metadata\n\t\t\t\t.getAllAnnotationAttributes(Conditional.class.getName(), true);\n\t\t\tObject values = (attributes != null) ? attributes.get(\"value\") : null;\n\t\t\treturn (List<String[]>) ((values != null) ? values : Collections.emptyList());\n\t\t}\n\n\t\tprivate Condition getCondition(String conditionClassName) {\n\t\t\tClass<?> conditionClass = ClassUtils.resolveClassName(conditionClassName, this.context.getClassLoader());\n\t\t\treturn (Condition) BeanUtils.instantiateClass(conditionClass);\n\t\t}\n\n\t\tList<ConditionOutcome> getMatchOutcomes() {\n\t\t\tList<ConditionOutcome> outcomes = new ArrayList<>();\n\t\t\tthis.memberConditions.forEach((metadata, conditions) -> outcomes\n\t\t\t\t.add(new MemberOutcomes(this.context, metadata, conditions).getUltimateOutcome()));\n\t\t\treturn Collections.unmodifiableList(outcomes);\n\t\t}\n\n\t}\n\n\tprivate static class MemberOutcomes {\n\n\t\tprivate final ConditionContext context;\n\n\t\tprivate final AnnotationMetadata metadata;\n\n\t\tprivate final List<ConditionOutcome> outcomes;\n\n\t\tMemberOutcomes(ConditionContext context, AnnotationMetadata metadata, List<Condition> conditions) {\n\t\t\tthis.context = context;\n\t\t\tthis.metadata = metadata;\n\t\t\tthis.outcomes = new ArrayList<>(conditions.size());\n\t\t\tfor (Condition condition : conditions) {\n\t\t\t\tthis.outcomes.add(getConditionOutcome(metadata, condition));\n\t\t\t}\n\t\t}\n\n\t\tprivate ConditionOutcome getConditionOutcome(AnnotationMetadata metadata, Condition condition) {\n\t\t\tif (condition instanceof SpringBootCondition springBootCondition) {\n\t\t\t\treturn springBootCondition.getMatchOutcome(this.context, metadata);\n\t\t\t}\n\t\t\treturn new ConditionOutcome(condition.matches(this.context, metadata), ConditionMessage.empty());\n\t\t}\n\n\t\tConditionOutcome getUltimateOutcome() {\n\t\t\tConditionMessage.Builder message = ConditionMessage\n\t\t\t\t.forCondition(\"NestedCondition on \" + ClassUtils.getShortName(this.metadata.getClassName()));\n\t\t\tif (this.outcomes.size() == 1) {\n\t\t\t\tConditionOutcome outcome = this.outcomes.get(0);\n\t\t\t\treturn new ConditionOutcome(outcome.isMatch(), message.because(outcome.getMessage()));\n\t\t\t}\n\t\t\tList<ConditionOutcome> match = new ArrayList<>();\n\t\t\tList<ConditionOutcome> nonMatch = new ArrayList<>();\n\t\t\tfor (ConditionOutcome outcome : this.outcomes) {\n\t\t\t\t(outcome.isMatch() ? match : nonMatch).add(outcome);\n\t\t\t}\n\t\t\tif (nonMatch.isEmpty()) {\n\t\t\t\treturn ConditionOutcome.match(message.found(\"matching nested conditions\").items(match));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.found(\"non-matching nested conditions\").items(nonMatch));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/AllNestedConditions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.context.annotation.Condition;\n\n/**\n * {@link Condition} that will match when all nested class conditions match. Can be used\n * to create composite conditions, for example:\n *\n * <pre class=\"code\">\n * static class OnJndiAndProperty extends AllNestedConditions {\n *\n *    OnJndiAndProperty() {\n *        super(ConfigurationPhase.PARSE_CONFIGURATION);\n *    }\n *\n *    &#064;ConditionalOnJndi()\n *    static class OnJndi {\n *    }\n *\n *    &#064;ConditionalOnProperty(\"something\")\n *    static class OnProperty {\n *    }\n *\n * }\n * </pre>\n * <p>\n * The\n * {@link org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase\n * ConfigurationPhase} should be specified according to the conditions that are defined.\n * In the example above, all conditions are static and can be evaluated early so\n * {@code PARSE_CONFIGURATION} is a right fit.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic abstract class AllNestedConditions extends AbstractNestedCondition {\n\n\tpublic AllNestedConditions(ConfigurationPhase configurationPhase) {\n\t\tsuper(configurationPhase);\n\t}\n\n\t@Override\n\tprotected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {\n\t\tboolean match = hasSameSize(memberOutcomes.getMatches(), memberOutcomes.getAll());\n\t\tList<ConditionMessage> messages = new ArrayList<>();\n\t\tmessages.add(ConditionMessage.forCondition(\"AllNestedConditions\")\n\t\t\t.because(memberOutcomes.getMatches().size() + \" matched \" + memberOutcomes.getNonMatches().size()\n\t\t\t\t\t+ \" did not\"));\n\t\tfor (ConditionOutcome outcome : memberOutcomes.getAll()) {\n\t\t\tmessages.add(outcome.getConditionMessage());\n\t\t}\n\t\treturn new ConditionOutcome(match, ConditionMessage.of(messages));\n\t}\n\n\tprivate boolean hasSameSize(List<?> list1, List<?> list2) {\n\t\treturn list1.size() == list2.size();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/AnyNestedCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link Condition} that will match when any nested class condition matches. Can be used\n * to create composite conditions, for example:\n *\n * <pre class=\"code\">\n * static class OnJndiOrProperty extends AnyNestedCondition {\n *\n *    OnJndiOrProperty() {\n *        super(ConfigurationPhase.PARSE_CONFIGURATION);\n *    }\n *\n *    &#064;ConditionalOnJndi()\n *    static class OnJndi {\n *    }\n *\n *    &#064;ConditionalOnProperty(\"something\")\n *    static class OnProperty {\n *    }\n *\n * }\n * </pre>\n * <p>\n * The\n * {@link org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase\n * ConfigurationPhase} should be specified according to the conditions that are defined.\n * In the example above, all conditions are static and can be evaluated early so\n * {@code PARSE_CONFIGURATION} is a right fit.\n *\n * @author Phillip Webb\n * @since 1.2.0\n */\n@Order(Ordered.LOWEST_PRECEDENCE - 20)\npublic abstract class AnyNestedCondition extends AbstractNestedCondition {\n\n\tpublic AnyNestedCondition(ConfigurationPhase configurationPhase) {\n\t\tsuper(configurationPhase);\n\t}\n\n\t@Override\n\tprotected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {\n\t\tboolean match = !memberOutcomes.getMatches().isEmpty();\n\t\tList<ConditionMessage> messages = new ArrayList<>();\n\t\tmessages.add(ConditionMessage.forCondition(\"AnyNestedCondition\")\n\t\t\t.because(memberOutcomes.getMatches().size() + \" matched \" + memberOutcomes.getNonMatches().size()\n\t\t\t\t\t+ \" did not\"));\n\t\tfor (ConditionOutcome outcome : memberOutcomes.getAll()) {\n\t\t\tmessages.add(outcome.getConditionMessage());\n\t\t}\n\t\treturn new ConditionOutcome(match, ConditionMessage.of(messages));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Records condition evaluation details for reporting and logging.\n *\n * @author Greg Turnquist\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 1.0.0\n */\npublic final class ConditionEvaluationReport {\n\n\tprivate static final String BEAN_NAME = \"autoConfigurationReport\";\n\n\tprivate static final AncestorsMatchedCondition ANCESTOR_CONDITION = new AncestorsMatchedCondition();\n\n\tprivate final SortedMap<String, ConditionAndOutcomes> outcomes = new TreeMap<>();\n\n\tprivate boolean addedAncestorOutcomes;\n\n\tprivate @Nullable ConditionEvaluationReport parent;\n\n\tprivate final List<String> exclusions = new ArrayList<>();\n\n\tprivate final Set<String> unconditionalClasses = new HashSet<>();\n\n\t/**\n\t * Private constructor.\n\t * @see #get(ConfigurableListableBeanFactory)\n\t */\n\tprivate ConditionEvaluationReport() {\n\t}\n\n\t/**\n\t * Record the occurrence of condition evaluation.\n\t * @param source the source of the condition (class or method name)\n\t * @param condition the condition evaluated\n\t * @param outcome the condition outcome\n\t */\n\tpublic void recordConditionEvaluation(String source, Condition condition, ConditionOutcome outcome) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tAssert.notNull(condition, \"'condition' must not be null\");\n\t\tAssert.notNull(outcome, \"'outcome' must not be null\");\n\t\tthis.unconditionalClasses.remove(source);\n\t\tthis.outcomes.computeIfAbsent(source, (key) -> new ConditionAndOutcomes()).add(condition, outcome);\n\t\tthis.addedAncestorOutcomes = false;\n\t}\n\n\t/**\n\t * Records the names of the classes that have been excluded from condition evaluation.\n\t * @param exclusions the names of the excluded classes\n\t */\n\tpublic void recordExclusions(Collection<String> exclusions) {\n\t\tAssert.notNull(exclusions, \"'exclusions' must not be null\");\n\t\tthis.exclusions.addAll(exclusions);\n\t}\n\n\t/**\n\t * Records the names of the classes that are candidates for condition evaluation.\n\t * @param evaluationCandidates the names of the classes whose conditions will be\n\t * evaluated\n\t */\n\tpublic void recordEvaluationCandidates(List<String> evaluationCandidates) {\n\t\tAssert.notNull(evaluationCandidates, \"'evaluationCandidates' must not be null\");\n\t\tthis.unconditionalClasses.addAll(evaluationCandidates);\n\t}\n\n\t/**\n\t * Returns condition outcomes from this report, grouped by the source.\n\t * @return the condition outcomes\n\t */\n\tpublic Map<String, ConditionAndOutcomes> getConditionAndOutcomesBySource() {\n\t\tif (!this.addedAncestorOutcomes) {\n\t\t\tthis.outcomes.forEach((source, sourceOutcomes) -> {\n\t\t\t\tif (!sourceOutcomes.isFullMatch()) {\n\t\t\t\t\taddNoMatchOutcomeToAncestors(source);\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.addedAncestorOutcomes = true;\n\t\t}\n\t\treturn Collections.unmodifiableMap(this.outcomes);\n\t}\n\n\tprivate void addNoMatchOutcomeToAncestors(String source) {\n\t\tString prefix = source + \"$\";\n\t\tthis.outcomes.forEach((candidateSource, sourceOutcomes) -> {\n\t\t\tif (candidateSource.startsWith(prefix)) {\n\t\t\t\tConditionOutcome outcome = ConditionOutcome\n\t\t\t\t\t.noMatch(ConditionMessage.forCondition(\"Ancestor \" + source).because(\"did not match\"));\n\t\t\t\tsourceOutcomes.add(ANCESTOR_CONDITION, outcome);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Returns the names of the classes that have been excluded from condition evaluation.\n\t * @return the names of the excluded classes\n\t */\n\tpublic List<String> getExclusions() {\n\t\treturn Collections.unmodifiableList(this.exclusions);\n\t}\n\n\t/**\n\t * Returns the names of the classes that were evaluated but were not conditional.\n\t * @return the names of the unconditional classes\n\t */\n\tpublic Set<String> getUnconditionalClasses() {\n\t\tSet<String> filtered = new HashSet<>(this.unconditionalClasses);\n\t\tthis.exclusions.forEach(filtered::remove);\n\t\treturn Collections.unmodifiableSet(filtered);\n\t}\n\n\t/**\n\t * The parent report (from a parent BeanFactory if there is one).\n\t * @return the parent report (or null if there isn't one)\n\t */\n\tpublic @Nullable ConditionEvaluationReport getParent() {\n\t\treturn this.parent;\n\t}\n\n\t/**\n\t * Attempt to find the {@link ConditionEvaluationReport} for the specified bean\n\t * factory.\n\t * @param beanFactory the bean factory (may be {@code null})\n\t * @return the {@link ConditionEvaluationReport} or {@code null}\n\t */\n\tpublic static @Nullable ConditionEvaluationReport find(BeanFactory beanFactory) {\n\t\tif (beanFactory instanceof ConfigurableListableBeanFactory) {\n\t\t\treturn ConditionEvaluationReport.get((ConfigurableListableBeanFactory) beanFactory);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Obtain a {@link ConditionEvaluationReport} for the specified bean factory.\n\t * @param beanFactory the bean factory\n\t * @return an existing or new {@link ConditionEvaluationReport}\n\t */\n\tpublic static ConditionEvaluationReport get(ConfigurableListableBeanFactory beanFactory) {\n\t\tsynchronized (beanFactory) {\n\t\t\tConditionEvaluationReport report;\n\t\t\tif (beanFactory.containsSingleton(BEAN_NAME)) {\n\t\t\t\treport = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treport = new ConditionEvaluationReport();\n\t\t\t\tbeanFactory.registerSingleton(BEAN_NAME, report);\n\t\t\t}\n\t\t\tlocateParent(beanFactory.getParentBeanFactory(), report);\n\t\t\treturn report;\n\t\t}\n\t}\n\n\tprivate static void locateParent(@Nullable BeanFactory beanFactory, ConditionEvaluationReport report) {\n\t\tif (beanFactory != null && report.parent == null && beanFactory.containsBean(BEAN_NAME)) {\n\t\t\treport.parent = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);\n\t\t}\n\t}\n\n\tpublic ConditionEvaluationReport getDelta(ConditionEvaluationReport previousReport) {\n\t\tConditionEvaluationReport delta = new ConditionEvaluationReport();\n\t\tthis.outcomes.forEach((source, sourceOutcomes) -> {\n\t\t\tConditionAndOutcomes previous = previousReport.outcomes.get(source);\n\t\t\tif (previous == null || previous.isFullMatch() != sourceOutcomes.isFullMatch()) {\n\t\t\t\tsourceOutcomes.forEach((conditionAndOutcome) -> delta.recordConditionEvaluation(source,\n\t\t\t\t\t\tconditionAndOutcome.getCondition(), conditionAndOutcome.getOutcome()));\n\t\t\t}\n\t\t});\n\t\tList<String> newExclusions = new ArrayList<>(this.exclusions);\n\t\tnewExclusions.removeAll(previousReport.getExclusions());\n\t\tdelta.recordExclusions(newExclusions);\n\t\tList<String> newUnconditionalClasses = new ArrayList<>(this.unconditionalClasses);\n\t\tnewUnconditionalClasses.removeAll(previousReport.unconditionalClasses);\n\t\tdelta.unconditionalClasses.addAll(newUnconditionalClasses);\n\t\treturn delta;\n\t}\n\n\t/**\n\t * Provides access to a number of {@link ConditionAndOutcome} items.\n\t */\n\tpublic static class ConditionAndOutcomes implements Iterable<ConditionAndOutcome> {\n\n\t\tprivate final Set<ConditionAndOutcome> outcomes = new LinkedHashSet<>();\n\n\t\tpublic void add(Condition condition, ConditionOutcome outcome) {\n\t\t\tthis.outcomes.add(new ConditionAndOutcome(condition, outcome));\n\t\t}\n\n\t\t/**\n\t\t * Return {@code true} if all outcomes match.\n\t\t * @return {@code true} if a full match\n\t\t */\n\t\tpublic boolean isFullMatch() {\n\t\t\tfor (ConditionAndOutcome conditionAndOutcomes : this) {\n\t\t\t\tif (!conditionAndOutcomes.getOutcome().isMatch()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\t/**\n\t\t * Return a {@link Stream} of the {@link ConditionAndOutcome} items.\n\t\t * @return a stream of the {@link ConditionAndOutcome} items.\n\t\t * @since 3.5.0\n\t\t */\n\t\tpublic Stream<ConditionAndOutcome> stream() {\n\t\t\treturn StreamSupport.stream(spliterator(), false);\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<ConditionAndOutcome> iterator() {\n\t\t\treturn Collections.unmodifiableSet(this.outcomes).iterator();\n\t\t}\n\n\t}\n\n\t/**\n\t * Provides access to a single {@link Condition} and {@link ConditionOutcome}.\n\t */\n\tpublic static class ConditionAndOutcome {\n\n\t\tprivate final Condition condition;\n\n\t\tprivate final ConditionOutcome outcome;\n\n\t\tpublic ConditionAndOutcome(Condition condition, ConditionOutcome outcome) {\n\t\t\tthis.condition = condition;\n\t\t\tthis.outcome = outcome;\n\t\t}\n\n\t\tpublic Condition getCondition() {\n\t\t\treturn this.condition;\n\t\t}\n\n\t\tpublic ConditionOutcome getOutcome() {\n\t\t\treturn this.outcome;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tConditionAndOutcome other = (ConditionAndOutcome) obj;\n\t\t\treturn (ObjectUtils.nullSafeEquals(this.condition.getClass(), other.condition.getClass())\n\t\t\t\t\t&& ObjectUtils.nullSafeEquals(this.outcome, other.outcome));\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.condition.getClass().hashCode() * 31 + this.outcome.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.condition.getClass() + \" \" + this.outcome;\n\t\t}\n\n\t}\n\n\tprivate static final class AncestorsMatchedCondition implements Condition {\n\n\t\t@Override\n\t\tpublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportAutoConfigurationImportListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportEvent;\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportListener;\n\n/**\n * {@link AutoConfigurationImportListener} to record results with the\n * {@link ConditionEvaluationReport}.\n *\n * @author Phillip Webb\n */\nclass ConditionEvaluationReportAutoConfigurationImportListener\n\t\timplements AutoConfigurationImportListener, BeanFactoryAware {\n\n\tprivate @Nullable ConfigurableListableBeanFactory beanFactory;\n\n\t@Override\n\tpublic void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {\n\t\tif (this.beanFactory != null) {\n\t\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);\n\t\t\treport.recordEvaluationCandidates(event.getCandidateConfigurations());\n\t\t\treport.recordExclusions(event.getExclusions());\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory)\n\t\t\t\t? listableBeanFactory : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionMessage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A message associated with a {@link ConditionOutcome}. Provides a fluent builder style\n * API to encourage consistency across all condition messages.\n *\n * @author Phillip Webb\n * @since 1.4.1\n */\npublic final class ConditionMessage {\n\n\tprivate final @Nullable String message;\n\n\tprivate ConditionMessage() {\n\t\tthis(null);\n\t}\n\n\tprivate ConditionMessage(@Nullable String message) {\n\t\tthis.message = message;\n\t}\n\n\tprivate ConditionMessage(ConditionMessage prior, String message) {\n\t\tthis.message = prior.isEmpty() ? message : prior + \"; \" + message;\n\t}\n\n\t/**\n\t * Return {@code true} if the message is empty.\n\t * @return if the message is empty\n\t */\n\tpublic boolean isEmpty() {\n\t\treturn !StringUtils.hasLength(this.message);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof ConditionMessage other) {\n\t\t\treturn ObjectUtils.nullSafeEquals(other.message, this.message);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn ObjectUtils.nullSafeHashCode(this.message);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.message != null) ? this.message : \"\";\n\t}\n\n\t/**\n\t * Return a new {@link ConditionMessage} based on the instance and an appended\n\t * message.\n\t * @param message the message to append\n\t * @return a new {@link ConditionMessage} instance\n\t */\n\tpublic ConditionMessage append(@Nullable String message) {\n\t\tif (!StringUtils.hasLength(message)) {\n\t\t\treturn this;\n\t\t}\n\t\tif (!StringUtils.hasLength(this.message)) {\n\t\t\treturn new ConditionMessage(message);\n\t\t}\n\n\t\treturn new ConditionMessage(this.message + \" \" + message);\n\t}\n\n\t/**\n\t * Return a new builder to construct a new {@link ConditionMessage} based on the\n\t * instance and a new condition outcome.\n\t * @param condition the condition\n\t * @param details details of the condition\n\t * @return a {@link Builder} builder\n\t * @see #andCondition(String, Object...)\n\t * @see #forCondition(Class, Object...)\n\t */\n\tpublic Builder andCondition(Class<? extends Annotation> condition, Object... details) {\n\t\tAssert.notNull(condition, \"'condition' must not be null\");\n\t\treturn andCondition(\"@\" + ClassUtils.getShortName(condition), details);\n\t}\n\n\t/**\n\t * Return a new builder to construct a new {@link ConditionMessage} based on the\n\t * instance and a new condition outcome.\n\t * @param condition the condition\n\t * @param details details of the condition\n\t * @return a {@link Builder} builder\n\t * @see #andCondition(Class, Object...)\n\t * @see #forCondition(String, Object...)\n\t */\n\tpublic Builder andCondition(String condition, Object... details) {\n\t\tAssert.notNull(condition, \"'condition' must not be null\");\n\t\tString detail = StringUtils.arrayToDelimitedString(details, \" \");\n\t\tif (StringUtils.hasLength(detail)) {\n\t\t\treturn new Builder(condition + \" \" + detail);\n\t\t}\n\t\treturn new Builder(condition);\n\t}\n\n\t/**\n\t * Factory method to return a new empty {@link ConditionMessage}.\n\t * @return a new empty {@link ConditionMessage}\n\t */\n\tpublic static ConditionMessage empty() {\n\t\treturn new ConditionMessage();\n\t}\n\n\t/**\n\t * Factory method to create a new {@link ConditionMessage} with a specific message.\n\t * @param message the source message (may be a format string if {@code args} are\n\t * specified)\n\t * @param args format arguments for the message\n\t * @return a new {@link ConditionMessage} instance\n\t */\n\tpublic static ConditionMessage of(String message, Object... args) {\n\t\tif (ObjectUtils.isEmpty(args)) {\n\t\t\treturn new ConditionMessage(message);\n\t\t}\n\t\treturn new ConditionMessage(String.format(message, args));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link ConditionMessage} comprised of the specified\n\t * messages.\n\t * @param messages the source messages (may be {@code null})\n\t * @return a new {@link ConditionMessage} instance\n\t */\n\tpublic static ConditionMessage of(@Nullable Collection<? extends ConditionMessage> messages) {\n\t\tConditionMessage result = new ConditionMessage();\n\t\tif (messages != null) {\n\t\t\tfor (ConditionMessage message : messages) {\n\t\t\t\tresult = new ConditionMessage(result, message.toString());\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Factory method for a builder to construct a new {@link ConditionMessage} for a\n\t * condition.\n\t * @param condition the condition\n\t * @param details details of the condition\n\t * @return a {@link Builder} builder\n\t * @see #forCondition(String, Object...)\n\t * @see #andCondition(String, Object...)\n\t */\n\tpublic static Builder forCondition(Class<? extends Annotation> condition, Object... details) {\n\t\treturn new ConditionMessage().andCondition(condition, details);\n\t}\n\n\t/**\n\t * Factory method for a builder to construct a new {@link ConditionMessage} for a\n\t * condition.\n\t * @param condition the condition\n\t * @param details details of the condition\n\t * @return a {@link Builder} builder\n\t * @see #forCondition(Class, Object...)\n\t * @see #andCondition(String, Object...)\n\t */\n\tpublic static Builder forCondition(String condition, Object... details) {\n\t\treturn new ConditionMessage().andCondition(condition, details);\n\t}\n\n\t/**\n\t * Builder used to create a {@link ConditionMessage} for a condition.\n\t */\n\tpublic final class Builder {\n\n\t\tprivate final String condition;\n\n\t\tprivate Builder(String condition) {\n\t\t\tthis.condition = condition;\n\t\t}\n\n\t\t/**\n\t\t * Indicate that an exact result was found. For example\n\t\t * {@code foundExactly(\"foo\")} results in the message \"found foo\".\n\t\t * @param result the result that was found\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage foundExactly(Object result) {\n\t\t\treturn found(\"\").items(result);\n\t\t}\n\n\t\t/**\n\t\t * Indicate that one or more results were found. For example\n\t\t * {@code found(\"bean\").items(\"x\")} results in the message \"found bean x\".\n\t\t * @param article the article found\n\t\t * @return an {@link ItemsBuilder}\n\t\t */\n\t\tpublic ItemsBuilder found(String article) {\n\t\t\treturn found(article, article);\n\t\t}\n\n\t\t/**\n\t\t * Indicate that one or more results were found. For example\n\t\t * {@code found(\"bean\", \"beans\").items(\"x\", \"y\")} results in the message \"found\n\t\t * beans x, y\".\n\t\t * @param singular the article found in singular form\n\t\t * @param plural the article found in plural form\n\t\t * @return an {@link ItemsBuilder}\n\t\t */\n\t\tpublic ItemsBuilder found(String singular, String plural) {\n\t\t\treturn new ItemsBuilder(this, \"found\", singular, plural);\n\t\t}\n\n\t\t/**\n\t\t * Indicate that one or more results were not found. For example\n\t\t * {@code didNotFind(\"bean\").items(\"x\")} results in the message \"did not find bean\n\t\t * x\".\n\t\t * @param article the article found\n\t\t * @return an {@link ItemsBuilder}\n\t\t */\n\t\tpublic ItemsBuilder didNotFind(String article) {\n\t\t\treturn didNotFind(article, article);\n\t\t}\n\n\t\t/**\n\t\t * Indicate that one or more results were found. For example\n\t\t * {@code didNotFind(\"bean\", \"beans\").items(\"x\", \"y\")} results in the message \"did\n\t\t * not find beans x, y\".\n\t\t * @param singular the article found in singular form\n\t\t * @param plural the article found in plural form\n\t\t * @return an {@link ItemsBuilder}\n\t\t */\n\t\tpublic ItemsBuilder didNotFind(String singular, String plural) {\n\t\t\treturn new ItemsBuilder(this, \"did not find\", singular, plural);\n\t\t}\n\n\t\t/**\n\t\t * Indicates a single result. For example {@code resultedIn(\"yes\")} results in the\n\t\t * message \"resulted in yes\".\n\t\t * @param result the result\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage resultedIn(Object result) {\n\t\t\treturn because(\"resulted in \" + result);\n\t\t}\n\n\t\t/**\n\t\t * Indicates something is available. For example {@code available(\"money\")}\n\t\t * results in the message \"money is available\".\n\t\t * @param item the item that is available\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage available(String item) {\n\t\t\treturn because(item + \" is available\");\n\t\t}\n\n\t\t/**\n\t\t * Indicates something is not available. For example {@code notAvailable(\"time\")}\n\t\t * results in the message \"time is not available\".\n\t\t * @param item the item that is not available\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage notAvailable(String item) {\n\t\t\treturn because(item + \" is not available\");\n\t\t}\n\n\t\t/**\n\t\t * Indicates the reason. For example {@code because(\"running Linux\")} results in\n\t\t * the message \"running Linux\".\n\t\t * @param reason the reason for the message\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage because(@Nullable String reason) {\n\t\t\tif (StringUtils.hasLength(reason)) {\n\t\t\t\treturn new ConditionMessage(ConditionMessage.this,\n\t\t\t\t\t\tStringUtils.hasLength(this.condition) ? this.condition + \" \" + reason : reason);\n\t\t\t}\n\t\t\treturn new ConditionMessage(ConditionMessage.this, this.condition);\n\t\t}\n\n\t}\n\n\t/**\n\t * Builder used to create an {@link ItemsBuilder} for a condition.\n\t */\n\tpublic final class ItemsBuilder {\n\n\t\tprivate final Builder condition;\n\n\t\tprivate final String reason;\n\n\t\tprivate final String singular;\n\n\t\tprivate final String plural;\n\n\t\tprivate ItemsBuilder(Builder condition, String reason, String singular, String plural) {\n\t\t\tthis.condition = condition;\n\t\t\tthis.reason = reason;\n\t\t\tthis.singular = singular;\n\t\t\tthis.plural = plural;\n\t\t}\n\n\t\t/**\n\t\t * Used when no items are available. For example\n\t\t * {@code didNotFind(\"any beans\").atAll()} results in the message \"did not find\n\t\t * any beans\".\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage atAll() {\n\t\t\treturn items(Collections.emptyList());\n\t\t}\n\n\t\t/**\n\t\t * Indicate the items. For example\n\t\t * {@code didNotFind(\"bean\", \"beans\").items(\"x\", \"y\")} results in the message \"did\n\t\t * not find beans x, y\".\n\t\t * @param items the items (may be {@code null})\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage items(Object @Nullable ... items) {\n\t\t\treturn items(Style.NORMAL, items);\n\t\t}\n\n\t\t/**\n\t\t * Indicate the items. For example\n\t\t * {@code didNotFind(\"bean\", \"beans\").items(\"x\", \"y\")} results in the message \"did\n\t\t * not find beans x, y\".\n\t\t * @param style the render style\n\t\t * @param items the items (may be {@code null})\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage items(Style style, Object @Nullable ... items) {\n\t\t\treturn items(style, (items != null) ? Arrays.asList(items) : null);\n\t\t}\n\n\t\t/**\n\t\t * Indicate the items. For example\n\t\t * {@code didNotFind(\"bean\", \"beans\").items(Collections.singleton(\"x\")} results in\n\t\t * the message \"did not find bean x\".\n\t\t * @param items the source of the items (may be {@code null})\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage items(@Nullable Collection<?> items) {\n\t\t\treturn items(Style.NORMAL, items);\n\t\t}\n\n\t\t/**\n\t\t * Indicate the items with a {@link Style}. For example\n\t\t * {@code didNotFind(\"bean\", \"beans\").items(Style.QUOTE, Collections.singleton(\"x\")}\n\t\t * results in the message \"did not find bean 'x'\".\n\t\t * @param style the render style\n\t\t * @param items the source of the items (may be {@code null})\n\t\t * @return a built {@link ConditionMessage}\n\t\t */\n\t\tpublic ConditionMessage items(Style style, @Nullable Collection<?> items) {\n\t\t\tAssert.notNull(style, \"'style' must not be null\");\n\t\t\tStringBuilder message = new StringBuilder(this.reason);\n\t\t\titems = style.applyTo(items);\n\t\t\tif ((this.condition == null || items == null || items.size() <= 1)\n\t\t\t\t\t&& StringUtils.hasLength(this.singular)) {\n\t\t\t\tmessage.append(\" \").append(this.singular);\n\t\t\t}\n\t\t\telse if (StringUtils.hasLength(this.plural)) {\n\t\t\t\tmessage.append(\" \").append(this.plural);\n\t\t\t}\n\t\t\tif (!CollectionUtils.isEmpty(items)) {\n\t\t\t\tmessage.append(\" \").append(StringUtils.collectionToDelimitedString(items, \", \"));\n\t\t\t}\n\t\t\treturn this.condition.because(message.toString());\n\t\t}\n\n\t}\n\n\t/**\n\t * Render styles.\n\t */\n\tpublic enum Style {\n\n\t\t/**\n\t\t * Render with normal styling.\n\t\t */\n\t\tNORMAL {\n\n\t\t\t@Override\n\t\t\tprotected @Nullable Object applyToItem(@Nullable Object item) {\n\t\t\t\treturn item;\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Render with the item surrounded by quotes.\n\t\t */\n\t\tQUOTE {\n\n\t\t\t@Override\n\t\t\tprotected @Nullable String applyToItem(@Nullable Object item) {\n\t\t\t\treturn (item != null) ? \"'\" + item + \"'\" : null;\n\t\t\t}\n\n\t\t};\n\n\t\tpublic @Nullable Collection<?> applyTo(@Nullable Collection<?> items) {\n\t\t\tif (items == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tList<Object> result = new ArrayList<>(items.size());\n\t\t\tfor (Object item : items) {\n\t\t\t\tObject applied = applyToItem(item);\n\t\t\t\tif (applied != null) {\n\t\t\t\t\tresult.add(applied);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tprotected abstract @Nullable Object applyToItem(@Nullable Object item);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionOutcome.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Outcome for a condition match, including log message.\n *\n * @author Phillip Webb\n * @since 1.0.0\n * @see ConditionMessage\n */\npublic class ConditionOutcome {\n\n\tprivate final boolean match;\n\n\tprivate final ConditionMessage message;\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance. For more consistent messages\n\t * consider using {@link #ConditionOutcome(boolean, ConditionMessage)}.\n\t * @param match if the condition is a match\n\t * @param message the condition message\n\t */\n\tpublic ConditionOutcome(boolean match, String message) {\n\t\tthis(match, ConditionMessage.of(message));\n\t}\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance.\n\t * @param match if the condition is a match\n\t * @param message the condition message\n\t */\n\tpublic ConditionOutcome(boolean match, ConditionMessage message) {\n\t\tAssert.notNull(message, \"'message' must not be null\");\n\t\tthis.match = match;\n\t\tthis.message = message;\n\t}\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance for a 'match'.\n\t * @return the {@link ConditionOutcome}\n\t */\n\tpublic static ConditionOutcome match() {\n\t\treturn match(ConditionMessage.empty());\n\t}\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance for 'match'. For more consistent\n\t * messages consider using {@link #match(ConditionMessage)}.\n\t * @param message the message\n\t * @return the {@link ConditionOutcome}\n\t */\n\tpublic static ConditionOutcome match(String message) {\n\t\treturn new ConditionOutcome(true, message);\n\t}\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance for 'match'.\n\t * @param message the message\n\t * @return the {@link ConditionOutcome}\n\t */\n\tpublic static ConditionOutcome match(ConditionMessage message) {\n\t\treturn new ConditionOutcome(true, message);\n\t}\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance for 'no match'. For more consistent\n\t * messages consider using {@link #noMatch(ConditionMessage)}.\n\t * @param message the message\n\t * @return the {@link ConditionOutcome}\n\t */\n\tpublic static ConditionOutcome noMatch(String message) {\n\t\treturn new ConditionOutcome(false, message);\n\t}\n\n\t/**\n\t * Create a new {@link ConditionOutcome} instance for 'no match'.\n\t * @param message the message\n\t * @return the {@link ConditionOutcome}\n\t */\n\tpublic static ConditionOutcome noMatch(ConditionMessage message) {\n\t\treturn new ConditionOutcome(false, message);\n\t}\n\n\t/**\n\t * Return {@code true} if the outcome was a match.\n\t * @return {@code true} if the outcome matches\n\t */\n\tpublic boolean isMatch() {\n\t\treturn this.match;\n\t}\n\n\t/**\n\t * Return an outcome message or {@code null}.\n\t * @return the message or {@code null}\n\t */\n\tpublic @Nullable String getMessage() {\n\t\treturn this.message.isEmpty() ? null : this.message.toString();\n\t}\n\n\t/**\n\t * Return an outcome message.\n\t * @return the message\n\t */\n\tpublic ConditionMessage getConditionMessage() {\n\t\treturn this.message;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (getClass() == obj.getClass()) {\n\t\t\tConditionOutcome other = (ConditionOutcome) obj;\n\t\t\treturn (this.match == other.match && ObjectUtils.nullSafeEquals(this.message, other.message));\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Boolean.hashCode(this.match) * 31 + ObjectUtils.nullSafeHashCode(this.message);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.message != null) ? this.message.toString() : \"\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when beans meeting all the specified\n * requirements are already contained in the {@link BeanFactory}. All the requirements\n * must be met for the condition to match, but they do not have to be met by the same\n * bean.\n * <p>\n * When placed on a {@link Bean @Bean} method and none of {@link #value}, {@link #type},\n * {@link #name}, or {@link #annotation} has been specified, the bean type to match\n * defaults to the return type of the {@code @Bean} method:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * public class MyAutoConfiguration {\n *\n *     &#064;ConditionalOnBean\n *     &#064;Bean\n *     public MyService myService() {\n *         ...\n *     }\n *\n * }</pre>\n * <p>\n * In the sample above the condition will match if a bean of type {@code MyService} is\n * already contained in the {@link BeanFactory}.\n * <p>\n * The condition can only match the bean definitions that have been processed by the\n * application context so far and, as such, it is strongly recommended to use this\n * condition on auto-configuration classes only. If a candidate bean may be created by\n * another auto-configuration, make sure that the one using this condition runs after.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnBeanCondition.class)\npublic @interface ConditionalOnBean {\n\n\t/**\n\t * The class types of beans that should be checked. The condition matches when beans\n\t * of all classes specified are contained in the {@link BeanFactory}. Beans that are\n\t * not autowire candidates or that are not default candidates are ignored.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #type} attribute.\n\t * @return the class types of beans to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The class type names of beans that should be checked. The condition matches when\n\t * beans of all classes specified are contained in the {@link BeanFactory}. Beans that\n\t * are not autowire candidates or that are not default candidates are ignored.\n\t * @return the class type names of beans to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tString[] type() default {};\n\n\t/**\n\t * The annotation type decorating a bean that should be checked. The condition matches\n\t * when all the annotations specified are defined on beans in the {@link BeanFactory}.\n\t * Beans that are not autowire candidates or that are not default candidates are\n\t * ignored.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation.\n\t * @return the class-level annotation types to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tClass<? extends Annotation>[] annotation() default {};\n\n\t/**\n\t * The names of beans to check. The condition matches when all the bean names\n\t * specified are contained in the {@link BeanFactory}.\n\t * @return the names of beans to check\n\t */\n\tString[] name() default {};\n\n\t/**\n\t * Strategy to decide if the application context hierarchy (parent contexts) should be\n\t * considered.\n\t * @return the search strategy\n\t */\n\tSearchStrategy search() default SearchStrategy.ALL;\n\n\t/**\n\t * Additional classes that may contain the specified bean types within their generic\n\t * parameters. For example, an annotation declaring {@code value=Name.class} and\n\t * {@code parameterizedContainer=NameRegistration.class} would detect both\n\t * {@code Name} and {@code NameRegistration<Name>}.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation.\n\t * @return the container types\n\t * @since 2.1.0\n\t */\n\tClass<?>[] parameterizedContainer() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBooleanProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * Container annotation that aggregates several\n * {@link ConditionalOnBooleanProperty @ConditionalOnBooleanProperty} annotations.\n *\n * @author Phillip Webb\n * @since 3.5.0\n * @see ConditionalOnBooleanProperty\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnPropertyCondition.class)\npublic @interface ConditionalOnBooleanProperties {\n\n\t/**\n\t * Return the contained\n\t * {@link ConditionalOnBooleanProperty @ConditionalOnBooleanProperty} annotations.\n\t * @return the contained annotations\n\t */\n\tConditionalOnBooleanProperty[] value();\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBooleanProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Repeatable;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link Conditional @Conditional} that checks if the specified properties have a\n * specific boolean value. By default the properties must be present in the\n * {@link Environment} and equal to {@code true}. The {@link #havingValue()} and\n * {@link #matchIfMissing()} attributes allow further customizations.\n * <p>\n * If the property is not contained in the {@link Environment} at all, the\n * {@link #matchIfMissing()} attribute is consulted. By default missing attributes do not\n * match.\n *\n * @author Phillip Webb\n * @since 3.5.0\n * @see ConditionalOnProperty\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnPropertyCondition.class)\n@Repeatable(ConditionalOnBooleanProperties.class)\npublic @interface ConditionalOnBooleanProperty {\n\n\t/**\n\t * Alias for {@link #name()}.\n\t * @return the names\n\t */\n\tString[] value() default {};\n\n\t/**\n\t * A prefix that should be applied to each property. The prefix automatically ends\n\t * with a dot if not specified. A valid prefix is defined by one or more words\n\t * separated with dots (e.g. {@code \"acme.system.feature\"}).\n\t * @return the prefix\n\t */\n\tString prefix() default \"\";\n\n\t/**\n\t * The name of the properties to test. If a prefix has been defined, it is applied to\n\t * compute the full key of each property. For instance if the prefix is\n\t * {@code app.config} and one value is {@code my-value}, the full key would be\n\t * {@code app.config.my-value}\n\t * <p>\n\t * Use the dashed notation to specify each property, that is all lower case with a \"-\"\n\t * to separate words (e.g. {@code my-long-property}).\n\t * <p>\n\t * If multiple names are specified, all of the properties have to pass the test for\n\t * the condition to match.\n\t * @return the names\n\t */\n\tString[] name() default {};\n\n\t/**\n\t * The expected value for the properties. If not specified, the property must be equal\n\t * to {@code true}.\n\t * @return the expected value\n\t */\n\tboolean havingValue() default true;\n\n\t/**\n\t * Specify if the condition should match if the property is not set. Defaults to\n\t * {@code false}.\n\t * @return if the condition should match if the property is missing\n\t */\n\tboolean matchIfMissing() default false;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCheckpointRestore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when coordinated restore at\n * checkpoint is to be used.\n *\n * @author Andy Wilkinson\n * @since 3.2.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ConditionalOnClass(name = \"org.crac.Resource\")\npublic @interface ConditionalOnCheckpointRestore {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when the specified classes are on\n * the classpath.\n * <p>\n * A {@code Class} {@link #value() value} can be safely specified on\n * {@code @Configuration} classes as the annotation metadata is parsed by using ASM before\n * the class is loaded. If a class reference cannot be used then a {@link #name() name}\n * {@code String} attribute can be used.\n * <p>\n * <b>Note:</b> Extra care must be taken when using {@code @ConditionalOnClass} on\n * {@code @Bean} methods where typically the return type is the target of the condition.\n * Before the condition on the method applies, the JVM will have loaded the class and\n * potentially processed method references which will fail if the class is not present. To\n * handle this scenario, a separate {@code @Configuration} class should be used to isolate\n * the condition. For example: <pre class=\"code\">\n * &#064;AutoConfiguration\n * public class MyAutoConfiguration {\n *\n * \t&#64;Configuration(proxyBeanMethods = false)\n * \t&#64;ConditionalOnClass(SomeService.class)\n * \tpublic static class SomeServiceConfiguration {\n *\n * \t\t&#64;Bean\n * \t\t&#64;ConditionalOnMissingBean\n * \t\tpublic SomeService someService() {\n * \t\t\treturn new SomeService();\n * \t\t}\n *\n * \t}\n *\n * }</pre>\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnClassCondition.class)\npublic @interface ConditionalOnClass {\n\n\t/**\n\t * The classes that must be present.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #name} attribute.\n\t * @return the classes that must be present\n\t */\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The classes names that must be present.\n\t * @return the class names that must be present.\n\t */\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatform.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when the specified cloud platform is\n * active.\n *\n * @author Madhura Bhave\n * @since 1.5.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnCloudPlatformCondition.class)\npublic @interface ConditionalOnCloudPlatform {\n\n\t/**\n\t * The {@link CloudPlatform cloud platform} that must be active.\n\t * @return the expected cloud platform\n\t */\n\tCloudPlatform value();\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnExpression.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * Configuration annotation for a conditional element that depends on the value of a SpEL\n * expression.\n * <p>\n * Referencing a bean in the expression will cause that bean to be initialized very early\n * in context refresh processing. As a result, the bean won't be eligible for\n * post-processing (such as configuration properties binding) and its state may be\n * incomplete.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnExpressionCondition.class)\npublic @interface ConditionalOnExpression {\n\n\t/**\n\t * The SpEL expression to evaluate. Expression should return {@code true} if the\n\t * condition passes or {@code false} if it fails.\n\t * @return the SpEL expression\n\t */\n\tString value() default \"true\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJava.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.system.JavaVersion;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches based on the JVM version the application\n * is running on.\n *\n * @author Oliver Gierke\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.1.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnJavaCondition.class)\npublic @interface ConditionalOnJava {\n\n\t/**\n\t * Configures whether the value configured in {@link #value()} shall be considered the\n\t * upper exclusive or lower inclusive boundary. Defaults to\n\t * {@link Range#EQUAL_OR_NEWER}.\n\t * @return the range\n\t */\n\tRange range() default Range.EQUAL_OR_NEWER;\n\n\t/**\n\t * The {@link JavaVersion} to check for. Use {@link #range()} to specify whether the\n\t * configured value is an upper-exclusive or lower-inclusive boundary.\n\t * @return the java version\n\t */\n\tJavaVersion value();\n\n\t/**\n\t * Range options.\n\t */\n\tenum Range {\n\n\t\t/**\n\t\t * Equal to, or newer than the specified {@link JavaVersion}.\n\t\t */\n\t\tEQUAL_OR_NEWER,\n\n\t\t/**\n\t\t * Older than the specified {@link JavaVersion}.\n\t\t */\n\t\tOLDER_THAN\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndi.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport javax.naming.InitialContext;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches based on the availability of a JNDI\n * {@link InitialContext} and the ability to lookup specific locations.\n *\n * @author Phillip Webb\n * @since 1.2.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnJndiCondition.class)\npublic @interface ConditionalOnJndi {\n\n\t/**\n\t * JNDI Locations, one of which must exist. If no locations are specific the condition\n\t * matches solely based on the presence of an {@link InitialContext}.\n\t * @return the JNDI locations\n\t */\n\tString[] value() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when no beans meeting the specified\n * requirements are already contained in the {@link BeanFactory}. None of the requirements\n * must be met for the condition to match and the requirements do not have to be met by\n * the same bean.\n * <p>\n * When placed on a {@link Bean @Bean} method and none of {@link #value}, {@link #type},\n * {@link #name}, or {@link #annotation} has been specified, the bean type to match\n * defaults to the return type of the {@code @Bean} method:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * public class MyAutoConfiguration {\n *\n *     &#064;ConditionalOnMissingBean\n *     &#064;Bean\n *     public MyService myService() {\n *         ...\n *     }\n *\n * }</pre>\n * <p>\n * In the sample above the condition will match if no bean of type {@code MyService} is\n * already contained in the {@link BeanFactory}.\n * <p>\n * The condition can only match the bean definitions that have been processed by the\n * application context so far and, as such, it is strongly recommended to use this\n * condition on auto-configuration classes only. If a candidate bean may be created by\n * another auto-configuration, make sure that the one using this condition runs after.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnBeanCondition.class)\npublic @interface ConditionalOnMissingBean {\n\n\t/**\n\t * The class types of beans that should be checked. The condition matches when no bean\n\t * of each class specified is contained in the {@link BeanFactory}. Beans that are not\n\t * autowire candidates or that are not default candidates are ignored.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #type} attribute.\n\t * @return the class types of beans to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The class type names of beans that should be checked. The condition matches when no\n\t * bean of each class specified is contained in the {@link BeanFactory}. Beans that\n\t * are not autowire candidates or that are not default candidates are ignored.\n\t * @return the class type names of beans to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tString[] type() default {};\n\n\t/**\n\t * The class types of beans that should be ignored when identifying matching beans.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #ignoredType} attribute.\n\t * @return the class types of beans to ignore\n\t * @since 1.2.5\n\t */\n\tClass<?>[] ignored() default {};\n\n\t/**\n\t * The class type names of beans that should be ignored when identifying matching\n\t * beans.\n\t * @return the class type names of beans to ignore\n\t * @since 1.2.5\n\t */\n\tString[] ignoredType() default {};\n\n\t/**\n\t * The annotation type decorating a bean that should be checked. The condition matches\n\t * when each annotation specified is missing from all beans in the\n\t * {@link BeanFactory}. Beans that are not autowire candidates or that are not default\n\t * candidates are ignored.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation.\n\t * @return the class-level annotation types to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tClass<? extends Annotation>[] annotation() default {};\n\n\t/**\n\t * The names of beans to check. The condition matches when each bean name specified is\n\t * missing in the {@link BeanFactory}.\n\t * @return the names of beans to check\n\t */\n\tString[] name() default {};\n\n\t/**\n\t * Strategy to decide if the application context hierarchy (parent contexts) should be\n\t * considered.\n\t * @return the search strategy\n\t */\n\tSearchStrategy search() default SearchStrategy.ALL;\n\n\t/**\n\t * Additional classes that may contain the specified bean types within their generic\n\t * parameters. For example, an annotation declaring {@code value=Name.class} and\n\t * {@code parameterizedContainer=NameRegistration.class} would detect both\n\t * {@code Name} and {@code NameRegistration<Name>}.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation.\n\t * @return the container types\n\t * @since 2.1.0\n\t */\n\tClass<?>[] parameterizedContainer() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when the specified classes are not\n * on the classpath.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnClassCondition.class)\npublic @interface ConditionalOnMissingClass {\n\n\t/**\n\t * The names of the classes that must not be present.\n\t * @return the names of the classes that must not be present\n\t */\n\tString[] value() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingFilterBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.servlet.Filter;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * {@link Conditional @Conditional} that only matches when no {@link Filter} beans of the\n * specified type are contained in the {@link BeanFactory}. This condition will detect\n * both directly registered {@link Filter} beans as well as those registered through a\n * {@link FilterRegistrationBean}.\n * <p>\n * When placed on a {@code @Bean} method, the bean class defaults to the return type of\n * the factory method or the type of the {@link Filter} if the bean is a\n * {@link FilterRegistrationBean}:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * public class MyAutoConfiguration {\n *\n *     &#064;ConditionalOnMissingFilterBean\n *     &#064;Bean\n *     public MyFilter myFilter() {\n *         ...\n *     }\n *\n * }</pre>\n * <p>\n * In the sample above the condition will match if no bean of type {@code MyFilter} or\n * {@code FilterRegistrationBean<MyFilter>} is already contained in the\n * {@link BeanFactory}.\n *\n * @author Phillip Webb\n * @since 2.1.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ConditionalOnMissingBean(parameterizedContainer = FilterRegistrationBean.class)\npublic @interface ConditionalOnMissingFilterBean {\n\n\t/**\n\t * The filter bean type that must not be present.\n\t * @return the bean type\n\t */\n\t@AliasFor(annotation = ConditionalOnMissingBean.class)\n\tClass<? extends Filter>[] value() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWarDeployment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when the application is not a\n * traditional WAR deployment. For applications with embedded servers, this condition will\n * return true.\n *\n * @author Guirong Hu\n * @since 2.7.10\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnWarDeploymentCondition.class)\npublic @interface ConditionalOnNotWarDeployment {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when the application context is a\n * not a web application context.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnWebApplicationCondition.class)\npublic @interface ConditionalOnNotWebApplication {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * Container annotation that aggregates several\n * {@link ConditionalOnProperty @ConditionalOnProperty} annotations.\n *\n * @author Phillip Webb\n * @since 3.5.0\n * @see ConditionalOnProperty\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnPropertyCondition.class)\npublic @interface ConditionalOnProperties {\n\n\t/**\n\t * Return the contained {@link ConditionalOnProperty @ConditionalOnProperty}\n\t * annotations.\n\t * @return the contained annotations\n\t */\n\tConditionalOnProperty[] value();\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Repeatable;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link Conditional @Conditional} that checks if the specified properties have a\n * specific value. By default the properties must be present in the {@link Environment}\n * and <strong>not</strong> equal to {@code false}. The {@link #havingValue()} and\n * {@link #matchIfMissing()} attributes allow further customizations.\n * <p>\n * The {@link #havingValue} attribute can be used to specify the value that the property\n * should have. The table below shows when a condition matches according to the property\n * value and the {@link #havingValue()} attribute:\n *\n * <table border=\"1\">\n * <caption>Having values</caption>\n * <tr>\n * <th>Property Value</th>\n * <th>{@code havingValue=\"\"}</th>\n * <th>{@code havingValue=\"true\"}</th>\n * <th>{@code havingValue=\"false\"}</th>\n * <th>{@code havingValue=\"foo\"}</th>\n * </tr>\n * <tr>\n * <td>{@code \"true\"}</td>\n * <td>yes</td>\n * <td>yes</td>\n * <td>no</td>\n * <td>no</td>\n * </tr>\n * <tr>\n * <td>{@code \"false\"}</td>\n * <td>no</td>\n * <td>no</td>\n * <td>yes</td>\n * <td>no</td>\n * </tr>\n * <tr>\n * <td>{@code \"foo\"}</td>\n * <td>yes</td>\n * <td>no</td>\n * <td>no</td>\n * <td>yes</td>\n * </tr>\n * </table>\n * <p>\n * If the property is not contained in the {@link Environment} at all, the\n * {@link #matchIfMissing()} attribute is consulted. By default missing attributes do not\n * match.\n * <p>\n * This condition cannot be reliably used for matching collection properties. For example,\n * in the following configuration, the condition matches if {@code spring.example.values}\n * is present in the {@link Environment} but does not match if\n * {@code spring.example.values[0]} is present.\n *\n * <pre class=\"code\">\n * &#064;ConditionalOnProperty(prefix = \"spring\", name = \"example.values\")\n * class ExampleAutoConfiguration {\n * }\n * </pre>\n *\n * It is better to use a custom condition for such cases.\n *\n * @author Maciej Walkowiak\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 1.1.0\n * @see ConditionalOnBooleanProperty\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnPropertyCondition.class)\n@Repeatable(ConditionalOnProperties.class)\npublic @interface ConditionalOnProperty {\n\n\t/**\n\t * Alias for {@link #name()}.\n\t * @return the names\n\t */\n\tString[] value() default {};\n\n\t/**\n\t * A prefix that should be applied to each property. The prefix automatically ends\n\t * with a dot if not specified. A valid prefix is defined by one or more words\n\t * separated with dots (e.g. {@code \"acme.system.feature\"}).\n\t * @return the prefix\n\t */\n\tString prefix() default \"\";\n\n\t/**\n\t * The name of the properties to test. If a prefix has been defined, it is applied to\n\t * compute the full key of each property. For instance if the prefix is\n\t * {@code app.config} and one value is {@code my-value}, the full key would be\n\t * {@code app.config.my-value}\n\t * <p>\n\t * Use the dashed notation to specify each property, that is all lower case with a \"-\"\n\t * to separate words (e.g. {@code my-long-property}).\n\t * <p>\n\t * If multiple names are specified, all of the properties have to pass the test for\n\t * the condition to match.\n\t * @return the names\n\t */\n\tString[] name() default {};\n\n\t/**\n\t * The string representation of the expected value for the properties. If not\n\t * specified, the property must <strong>not</strong> be equal to {@code false}.\n\t * @return the expected value\n\t */\n\tString havingValue() default \"\";\n\n\t/**\n\t * Specify if the condition should match if the property is not set. Defaults to\n\t * {@code false}.\n\t * @return if the condition should match if the property is missing\n\t */\n\tboolean matchIfMissing() default false;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when the specified resources are on\n * the classpath.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnResourceCondition.class)\npublic @interface ConditionalOnResource {\n\n\t/**\n\t * The resources that must be present.\n\t * @return the resource paths that must be present.\n\t */\n\tString[] resources() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when a bean of the specified class\n * is already contained in the {@link BeanFactory} and a single candidate can be\n * determined.\n * <p>\n * The condition will also match if multiple matching bean instances are already contained\n * in the {@link BeanFactory} but a primary candidate has been defined; essentially, the\n * condition match if auto-wiring a bean with the defined type will succeed.\n * <p>\n * The condition can only match the bean definitions that have been processed by the\n * application context so far and, as such, it is strongly recommended to use this\n * condition on auto-configuration classes only. If a candidate bean may be created by\n * another auto-configuration, make sure that the one using this condition runs after.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnBeanCondition.class)\npublic @interface ConditionalOnSingleCandidate {\n\n\t/**\n\t * The class type of bean that should be checked. The condition matches if a bean of\n\t * the class specified is contained in the {@link BeanFactory} and a primary candidate\n\t * exists in case of multiple instances. Beans that are not autowire candidates, that\n\t * are not default candidates, or that are fallback candidates are ignored.\n\t * <p>\n\t * Since this annotation is parsed by loading class bytecode, it is safe to specify\n\t * classes here that may ultimately not be on the classpath, but only if this\n\t * annotation is directly on the affected component and <b>not</b> if this annotation\n\t * is used as a composed, meta-annotation. In order to use this annotation as a\n\t * meta-annotation, only use the {@link #type} attribute.\n\t * <p>\n\t * This attribute may <strong>not</strong> be used in conjunction with\n\t * {@link #type()}, but it may be used instead of {@link #type()}.\n\t * @return the class type of the bean to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tClass<?> value() default Object.class;\n\n\t/**\n\t * The class type name of bean that should be checked. The condition matches if a bean\n\t * of the class specified is contained in the {@link BeanFactory} and a primary\n\t * candidate exists in case of multiple instances. Beans that are not autowire\n\t * candidates, that are not default candidates, or that are fallback candidates are\n\t * ignored.\n\t * <p>\n\t * This attribute may <strong>not</strong> be used in conjunction with\n\t * {@link #value()}, but it may be used instead of {@link #value()}.\n\t * @return the class type name of the bean to check\n\t * @see Bean#autowireCandidate()\n\t * @see BeanDefinition#isAutowireCandidate\n\t * @see Bean#defaultCandidate()\n\t * @see AbstractBeanDefinition#isDefaultCandidate\n\t */\n\tString type() default \"\";\n\n\t/**\n\t * Strategy to decide if the application context hierarchy (parent contexts) should be\n\t * considered.\n\t * @return the search strategy\n\t */\n\tSearchStrategy search() default SearchStrategy.ALL;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnThreading.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when the specified threading is active.\n *\n * @author Moritz Halbritter\n * @since 3.2.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnThreadingCondition.class)\npublic @interface ConditionalOnThreading {\n\n\t/**\n\t * The {@link Threading threading} that must be active.\n\t * @return the expected threading\n\t */\n\tThreading value();\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWarDeployment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when the application is a traditional WAR\n * deployment. For applications with embedded servers, this condition will return false.\n *\n * @author Madhura Bhave\n * @since 2.3.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnWarDeploymentCondition.class)\npublic @interface ConditionalOnWarDeployment {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when the application is a web\n * application. By default, any web application will match but it can be narrowed using\n * the {@link #type()} attribute.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @since 1.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnWebApplicationCondition.class)\npublic @interface ConditionalOnWebApplication {\n\n\t/**\n\t * The required type of the web application.\n\t * @return the required web application type\n\t */\n\tType type() default Type.ANY;\n\n\t/**\n\t * Available application types.\n\t */\n\tenum Type {\n\n\t\t/**\n\t\t * Any web application will match.\n\t\t */\n\t\tANY,\n\n\t\t/**\n\t\t * Only servlet-based web application will match.\n\t\t */\n\t\tSERVLET,\n\n\t\t/**\n\t\t * Only reactive-based web application will match.\n\t\t */\n\t\tREACTIVE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;\nimport org.springframework.boot.autoconfigure.AutoConfigurationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Abstract base class for a {@link SpringBootCondition} that also implements\n * {@link AutoConfigurationImportFilter}.\n *\n * @author Phillip Webb\n */\nabstract class FilteringSpringBootCondition extends SpringBootCondition\n\t\timplements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanFactory beanFactory;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader beanClassLoader;\n\n\t@Override\n\tpublic boolean[] match(@Nullable String[] autoConfigurationClasses,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);\n\t\t@Nullable ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);\n\t\tboolean[] match = new boolean[outcomes.length];\n\t\tfor (int i = 0; i < outcomes.length; i++) {\n\t\t\tConditionOutcome outcome = outcomes[i];\n\t\t\tmatch[i] = (outcome == null || outcome.isMatch());\n\t\t\tif (!match[i] && outcome != null) {\n\t\t\t\tString autoConfigurationClass = autoConfigurationClasses[i];\n\t\t\t\tAssert.state(autoConfigurationClass != null, \"'autoConfigurationClass' must not be null\");\n\t\t\t\tlogOutcome(autoConfigurationClass, outcome);\n\t\t\t\tif (report != null) {\n\t\t\t\t\treport.recordConditionEvaluation(autoConfigurationClass, this, outcome);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn match;\n\t}\n\n\tprotected abstract @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata);\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\tprotected final BeanFactory getBeanFactory() {\n\t\treturn this.beanFactory;\n\t}\n\n\tprotected final ClassLoader getBeanClassLoader() {\n\t\treturn this.beanClassLoader;\n\t}\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.beanClassLoader = classLoader;\n\t}\n\n\tprotected final List<String> filter(@Nullable Collection<String> classNames, ClassNameFilter classNameFilter,\n\t\t\t@Nullable ClassLoader classLoader) {\n\t\tif (CollectionUtils.isEmpty(classNames)) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<String> matches = new ArrayList<>(classNames.size());\n\t\tfor (String candidate : classNames) {\n\t\t\tif (classNameFilter.matches(candidate, classLoader)) {\n\t\t\t\tmatches.add(candidate);\n\t\t\t}\n\t\t}\n\t\treturn matches;\n\t}\n\n\t/**\n\t * Slightly faster variant of {@link ClassUtils#forName(String, ClassLoader)} that\n\t * doesn't deal with primitives, arrays or inner types.\n\t * @param className the class name to resolve\n\t * @param classLoader the class loader to use\n\t * @return a resolved class\n\t * @throws ClassNotFoundException if the class cannot be found\n\t */\n\tprotected static Class<?> resolve(String className, @Nullable ClassLoader classLoader)\n\t\t\tthrows ClassNotFoundException {\n\t\tif (classLoader != null) {\n\t\t\treturn Class.forName(className, false, classLoader);\n\t\t}\n\t\treturn Class.forName(className);\n\t}\n\n\tprotected enum ClassNameFilter {\n\n\t\tPRESENT {\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(String className, @Nullable ClassLoader classLoader) {\n\t\t\t\treturn isPresent(className, classLoader);\n\t\t\t}\n\n\t\t},\n\n\t\tMISSING {\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(String className, @Nullable ClassLoader classLoader) {\n\t\t\t\treturn !isPresent(className, classLoader);\n\t\t\t}\n\n\t\t};\n\n\t\tabstract boolean matches(String className, @Nullable ClassLoader classLoader);\n\n\t\tprivate static boolean isPresent(String className, @Nullable ClassLoader classLoader) {\n\t\t\tif (classLoader == null) {\n\t\t\t\tclassLoader = ClassUtils.getDefaultClassLoader();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tresolve(className, classLoader);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/NoneNestedConditions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.context.annotation.Condition;\n\n/**\n * {@link Condition} that will match when none of the nested class conditions match. Can\n * be used to create composite conditions, for example:\n *\n * <pre class=\"code\">\n * static class OnNeitherJndiNorProperty extends NoneNestedConditions {\n *\n *    OnNeitherJndiNorProperty() {\n *        super(ConfigurationPhase.PARSE_CONFIGURATION);\n *    }\n *\n *    &#064;ConditionalOnJndi()\n *    static class OnJndi {\n *    }\n *\n *    &#064;ConditionalOnProperty(\"something\")\n *    static class OnProperty {\n *    }\n *\n * }\n * </pre>\n * <p>\n * The\n * {@link org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase\n * ConfigurationPhase} should be specified according to the conditions that are defined.\n * In the example above, all conditions are static and can be evaluated early so\n * {@code PARSE_CONFIGURATION} is a right fit.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic abstract class NoneNestedConditions extends AbstractNestedCondition {\n\n\tpublic NoneNestedConditions(ConfigurationPhase configurationPhase) {\n\t\tsuper(configurationPhase);\n\t}\n\n\t@Override\n\tprotected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {\n\t\tboolean match = memberOutcomes.getMatches().isEmpty();\n\t\tList<ConditionMessage> messages = new ArrayList<>();\n\t\tmessages.add(ConditionMessage.forCondition(\"NoneNestedConditions\")\n\t\t\t.because(memberOutcomes.getMatches().size() + \" matched \" + memberOutcomes.getNonMatches().size()\n\t\t\t\t\t+ \" did not\"));\n\t\tfor (ConditionOutcome outcome : memberOutcomes.getAll()) {\n\t\t\tmessages.add(outcome.getConditionMessage());\n\t\t}\n\t\treturn new ConditionOutcome(match, ConditionMessage.of(messages));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.function.BiPredicate;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.HierarchicalBeanFactory;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.SingletonBeanRegistry;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurationMetadata;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.ConfigurationCondition;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotation.Adapt;\nimport org.springframework.core.annotation.MergedAnnotationCollectors;\nimport org.springframework.core.annotation.MergedAnnotationPredicates;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Condition} that checks for the presence or absence of specific beans.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Jakub Kubrynski\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Uladzislau Seuruk\n * @see ConditionalOnBean\n * @see ConditionalOnMissingBean\n * @see ConditionalOnSingleCandidate\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass OnBeanCondition extends FilteringSpringBootCondition implements ConfigurationCondition {\n\n\t@Override\n\tpublic ConfigurationPhase getConfigurationPhase() {\n\t\treturn ConfigurationPhase.REGISTER_BEAN;\n\t}\n\n\t@Override\n\tprotected final @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];\n\t\tfor (int i = 0; i < outcomes.length; i++) {\n\t\t\tString autoConfigurationClass = autoConfigurationClasses[i];\n\t\t\tif (autoConfigurationClass != null) {\n\t\t\t\tSet<String> onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, \"ConditionalOnBean\");\n\t\t\t\toutcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);\n\t\t\t\tif (outcomes[i] == null) {\n\t\t\t\t\tSet<String> onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,\n\t\t\t\t\t\t\t\"ConditionalOnSingleCandidate\");\n\t\t\t\t\toutcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn outcomes;\n\t}\n\n\tprivate @Nullable ConditionOutcome getOutcome(@Nullable Set<String> requiredBeanTypes,\n\t\t\tClass<? extends Annotation> annotation) {\n\t\tList<String> missing = filter(requiredBeanTypes, ClassNameFilter.MISSING, getBeanClassLoader());\n\t\tif (!missing.isEmpty()) {\n\t\t\tConditionMessage message = ConditionMessage.forCondition(annotation)\n\t\t\t\t.didNotFind(\"required type\", \"required types\")\n\t\t\t\t.items(Style.QUOTE, missing);\n\t\t\treturn ConditionOutcome.noMatch(message);\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionOutcome matchOutcome = ConditionOutcome.match();\n\t\tMergedAnnotations annotations = metadata.getAnnotations();\n\t\tif (annotations.isPresent(ConditionalOnBean.class)) {\n\t\t\tSpec<ConditionalOnBean> spec = new Spec<>(context, metadata, annotations, ConditionalOnBean.class);\n\t\t\tmatchOutcome = evaluateConditionalOnBean(spec, matchOutcome.getConditionMessage());\n\t\t\tif (!matchOutcome.isMatch()) {\n\t\t\t\treturn matchOutcome;\n\t\t\t}\n\t\t}\n\t\tif (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {\n\t\t\tSpec<ConditionalOnSingleCandidate> spec = new SingleCandidateSpec(context, metadata,\n\t\t\t\t\tmetadata.getAnnotations());\n\t\t\tmatchOutcome = evaluateConditionalOnSingleCandidate(spec, matchOutcome.getConditionMessage());\n\t\t\tif (!matchOutcome.isMatch()) {\n\t\t\t\treturn matchOutcome;\n\t\t\t}\n\t\t}\n\t\tif (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {\n\t\t\tSpec<ConditionalOnMissingBean> spec = new Spec<>(context, metadata, annotations,\n\t\t\t\t\tConditionalOnMissingBean.class);\n\t\t\tmatchOutcome = evaluateConditionalOnMissingBean(spec, matchOutcome.getConditionMessage());\n\t\t\tif (!matchOutcome.isMatch()) {\n\t\t\t\treturn matchOutcome;\n\t\t\t}\n\t\t}\n\t\treturn matchOutcome;\n\t}\n\n\tprivate ConditionOutcome evaluateConditionalOnBean(Spec<ConditionalOnBean> spec, ConditionMessage matchMessage) {\n\t\tMatchResult matchResult = getMatchingBeans(spec);\n\t\tif (!matchResult.isAllMatched()) {\n\t\t\tString reason = createOnBeanNoMatchReason(matchResult);\n\t\t\treturn ConditionOutcome.noMatch(spec.message().because(reason));\n\t\t}\n\t\treturn ConditionOutcome.match(spec.message(matchMessage)\n\t\t\t.found(\"bean\", \"beans\")\n\t\t\t.items(Style.QUOTE, matchResult.getNamesOfAllMatches()));\n\t}\n\n\tprivate ConditionOutcome evaluateConditionalOnSingleCandidate(Spec<ConditionalOnSingleCandidate> spec,\n\t\t\tConditionMessage matchMessage) {\n\t\tMatchResult matchResult = getMatchingBeans(spec);\n\t\tif (!matchResult.isAllMatched()) {\n\t\t\treturn ConditionOutcome.noMatch(spec.message().didNotFind(\"any beans\").atAll());\n\t\t}\n\t\tSet<String> allBeans = matchResult.getNamesOfAllMatches();\n\t\tif (allBeans.size() == 1) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.match(spec.message(matchMessage).found(\"a single bean\").items(Style.QUOTE, allBeans));\n\t\t}\n\t\tConfigurableListableBeanFactory beanFactory = spec.context.getBeanFactory();\n\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\tMap<String, @Nullable BeanDefinition> beanDefinitions = getBeanDefinitions(beanFactory, allBeans,\n\t\t\t\tspec.getStrategy() == SearchStrategy.ALL);\n\t\tList<String> primaryBeans = getPrimaryBeans(beanDefinitions);\n\t\tif (primaryBeans.size() == 1) {\n\t\t\treturn ConditionOutcome.match(spec.message(matchMessage)\n\t\t\t\t.found(\"a single primary bean '\" + primaryBeans.get(0) + \"' from beans\")\n\t\t\t\t.items(Style.QUOTE, allBeans));\n\t\t}\n\t\tif (primaryBeans.size() > 1) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.noMatch(spec.message().found(\"multiple primary beans\").items(Style.QUOTE, primaryBeans));\n\t\t}\n\t\tList<String> nonFallbackBeans = getNonFallbackBeans(beanDefinitions);\n\t\tif (nonFallbackBeans.size() == 1) {\n\t\t\treturn ConditionOutcome.match(spec.message(matchMessage)\n\t\t\t\t.found(\"a single non-fallback bean '\" + nonFallbackBeans.get(0) + \"' from beans\")\n\t\t\t\t.items(Style.QUOTE, allBeans));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(spec.message().found(\"multiple beans\").items(Style.QUOTE, allBeans));\n\t}\n\n\tprivate ConditionOutcome evaluateConditionalOnMissingBean(Spec<ConditionalOnMissingBean> spec,\n\t\t\tConditionMessage matchMessage) {\n\t\tMatchResult matchResult = getMatchingBeans(spec);\n\t\tif (matchResult.isAnyMatched()) {\n\t\t\tString reason = createOnMissingBeanNoMatchReason(matchResult);\n\t\t\treturn ConditionOutcome.noMatch(spec.message().because(reason));\n\t\t}\n\t\treturn ConditionOutcome.match(spec.message(matchMessage).didNotFind(\"any beans\").atAll());\n\t}\n\n\tprotected final MatchResult getMatchingBeans(Spec<?> spec) {\n\t\tConfigurableListableBeanFactory beanFactory = getSearchBeanFactory(spec);\n\t\tClassLoader classLoader = spec.getContext().getClassLoader();\n\t\tboolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;\n\t\tSet<BeanType> parameterizedContainers = spec.getParameterizedContainers();\n\t\tMatchResult result = new MatchResult();\n\t\tSet<String> beansIgnoredByType = getNamesOfBeansIgnoredByType(beanFactory, considerHierarchy,\n\t\t\t\tspec.getIgnoredTypes(), parameterizedContainers);\n\t\tfor (BeanType type : spec.getTypes()) {\n\t\t\tMap<String, @Nullable BeanDefinition> typeMatchedDefinitions = getBeanDefinitionsForType(beanFactory,\n\t\t\t\t\tconsiderHierarchy, type, parameterizedContainers);\n\t\t\tSet<String> typeMatchedNames = matchedNamesFrom(typeMatchedDefinitions,\n\t\t\t\t\t(name, definition) -> !ScopedProxyUtils.isScopedTarget(name)\n\t\t\t\t\t\t\t&& isCandidate(beanFactory, name, definition, beansIgnoredByType));\n\t\t\tif (typeMatchedNames.isEmpty()) {\n\t\t\t\tresult.recordUnmatchedType(type);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.recordMatchedType(type, typeMatchedNames);\n\t\t\t}\n\t\t}\n\t\tfor (String annotation : spec.getAnnotations()) {\n\t\t\tMap<String, @Nullable BeanDefinition> annotationMatchedDefinitions = getBeanDefinitionsForAnnotation(\n\t\t\t\t\tclassLoader, beanFactory, annotation, considerHierarchy);\n\t\t\tSet<String> annotationMatchedNames = matchedNamesFrom(annotationMatchedDefinitions,\n\t\t\t\t\t(name, definition) -> isCandidate(beanFactory, name, definition, beansIgnoredByType));\n\t\t\tif (annotationMatchedNames.isEmpty()) {\n\t\t\t\tresult.recordUnmatchedAnnotation(annotation);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.recordMatchedAnnotation(annotation, annotationMatchedNames);\n\n\t\t\t}\n\t\t}\n\t\tfor (String beanName : spec.getNames()) {\n\t\t\tif (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName, considerHierarchy)) {\n\t\t\t\tresult.recordMatchedName(beanName);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.recordUnmatchedName(beanName);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate ConfigurableListableBeanFactory getSearchBeanFactory(Spec<?> spec) {\n\t\tConfigurableListableBeanFactory beanFactory = spec.getContext().getBeanFactory();\n\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null'\");\n\t\tif (spec.getStrategy() == SearchStrategy.ANCESTORS) {\n\t\t\tBeanFactory parent = beanFactory.getParentBeanFactory();\n\t\t\tAssert.state(parent instanceof ConfigurableListableBeanFactory,\n\t\t\t\t\t\"Unable to use SearchStrategy.ANCESTORS without ConfigurableListableBeanFactory\");\n\t\t\tbeanFactory = (ConfigurableListableBeanFactory) parent;\n\t\t}\n\t\treturn beanFactory;\n\t}\n\n\tprivate Set<String> matchedNamesFrom(Map<String, @Nullable BeanDefinition> namedDefinitions,\n\t\t\tBiPredicate<String, BeanDefinition> filter) {\n\t\tSet<String> matchedNames = new LinkedHashSet<>(namedDefinitions.size());\n\t\tfor (Entry<String, BeanDefinition> namedDefinition : namedDefinitions.entrySet()) {\n\t\t\tif (filter.test(namedDefinition.getKey(), namedDefinition.getValue())) {\n\t\t\t\tmatchedNames.add(namedDefinition.getKey());\n\t\t\t}\n\t\t}\n\t\treturn matchedNames;\n\t}\n\n\tprivate boolean isCandidate(ConfigurableListableBeanFactory beanFactory, String name,\n\t\t\t@Nullable BeanDefinition definition, Set<String> ignoredBeans) {\n\t\tif (ignoredBeans.contains(name)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (definition == null || (definition.isAutowireCandidate() && isDefaultCandidate(definition))) {\n\t\t\treturn true;\n\t\t}\n\t\tif (ScopedProxyUtils.isScopedTarget(name)) {\n\t\t\ttry {\n\t\t\t\tBeanDefinition originalDefinition = beanFactory\n\t\t\t\t\t.getBeanDefinition(ScopedProxyUtils.getOriginalBeanName(name));\n\t\t\t\tif (originalDefinition.isAutowireCandidate() && isDefaultCandidate(originalDefinition)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isDefaultCandidate(BeanDefinition definition) {\n\t\tif (definition instanceof AbstractBeanDefinition abstractBeanDefinition) {\n\t\t\treturn abstractBeanDefinition.isDefaultCandidate();\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate Set<String> getNamesOfBeansIgnoredByType(ListableBeanFactory beanFactory, boolean considerHierarchy,\n\t\t\tSet<BeanType> ignoredTypes, Set<BeanType> parameterizedContainers) {\n\t\tSet<String> result = null;\n\t\tfor (BeanType ignoredType : ignoredTypes) {\n\t\t\tCollection<String> ignoredNames = getBeanDefinitionsForType(beanFactory, considerHierarchy, ignoredType,\n\t\t\t\t\tparameterizedContainers)\n\t\t\t\t.keySet();\n\t\t\tresult = addAll(result, ignoredNames);\n\t\t}\n\t\treturn (result != null) ? result : Collections.emptySet();\n\t}\n\n\tprivate Map<String, @Nullable BeanDefinition> getBeanDefinitionsForType(ListableBeanFactory beanFactory,\n\t\t\tboolean considerHierarchy, BeanType type, Set<BeanType> parameterizedContainers) {\n\t\tMap<String, @Nullable BeanDefinition> result = collectBeanDefinitionsForType(beanFactory, considerHierarchy,\n\t\t\t\ttype, parameterizedContainers, null);\n\t\treturn (result != null) ? result : Collections.<String, @Nullable BeanDefinition>emptyMap();\n\t}\n\n\tprivate @Nullable Map<String, @Nullable BeanDefinition> collectBeanDefinitionsForType(\n\t\t\tListableBeanFactory beanFactory, boolean considerHierarchy, BeanType type,\n\t\t\tSet<BeanType> parameterizedContainers, @Nullable Map<String, @Nullable BeanDefinition> result) {\n\t\tif (ResolvableType.NONE.equals(type.resolvableType())) {\n\t\t\treturn result;\n\t\t}\n\t\tresult = putAll(result, beanFactory.getBeanNamesForType(type.resolvableType(), true, false), beanFactory);\n\t\tfor (BeanType parameterizedContainer : parameterizedContainers) {\n\t\t\tClass<?> resolved = parameterizedContainer.resolvableType().resolve();\n\t\t\tAssert.state(resolved != null, \"'resolved' must not be null\");\n\t\t\tResolvableType generic = ResolvableType.forClassWithGenerics(resolved, type.resolvableType());\n\t\t\tresult = putAll(result, beanFactory.getBeanNamesForType(generic, true, false), beanFactory);\n\t\t}\n\t\tif (considerHierarchy && beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory) {\n\t\t\tBeanFactory parent = hierarchicalBeanFactory.getParentBeanFactory();\n\t\t\tif (parent instanceof ListableBeanFactory listableBeanFactory) {\n\t\t\t\tresult = collectBeanDefinitionsForType(listableBeanFactory, considerHierarchy, type,\n\t\t\t\t\t\tparameterizedContainers, result);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate Map<String, @Nullable BeanDefinition> getBeanDefinitionsForAnnotation(@Nullable ClassLoader classLoader,\n\t\t\tConfigurableListableBeanFactory beanFactory, String type, boolean considerHierarchy) throws LinkageError {\n\t\tMap<String, @Nullable BeanDefinition> result = null;\n\t\ttry {\n\t\t\tresult = collectBeanDefinitionsForAnnotation(beanFactory, resolveAnnotationType(classLoader, type),\n\t\t\t\t\tconsiderHierarchy, result);\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\t// Continue\n\t\t}\n\t\treturn (result != null) ? result : Collections.<String, @Nullable BeanDefinition>emptyMap();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Class<? extends Annotation> resolveAnnotationType(@Nullable ClassLoader classLoader, String type)\n\t\t\tthrows ClassNotFoundException {\n\t\treturn (Class<? extends Annotation>) resolve(type, classLoader);\n\t}\n\n\tprivate @Nullable Map<String, @Nullable BeanDefinition> collectBeanDefinitionsForAnnotation(\n\t\t\tListableBeanFactory beanFactory, Class<? extends Annotation> annotationType, boolean considerHierarchy,\n\t\t\t@Nullable Map<String, @Nullable BeanDefinition> result) {\n\t\tresult = putAll(result, getBeanNamesForAnnotation(beanFactory, annotationType), beanFactory);\n\t\tif (considerHierarchy) {\n\t\t\tBeanFactory parent = ((HierarchicalBeanFactory) beanFactory).getParentBeanFactory();\n\t\t\tif (parent instanceof ListableBeanFactory listableBeanFactory) {\n\t\t\t\tresult = collectBeanDefinitionsForAnnotation(listableBeanFactory, annotationType, considerHierarchy,\n\t\t\t\t\t\tresult);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate String[] getBeanNamesForAnnotation(ListableBeanFactory beanFactory,\n\t\t\tClass<? extends Annotation> annotationType) {\n\t\tSet<String> foundBeanNames = new LinkedHashSet<>();\n\t\tfor (String beanName : beanFactory.getBeanDefinitionNames()) {\n\t\t\tif (beanFactory instanceof ConfigurableListableBeanFactory configurableListableBeanFactory) {\n\t\t\t\tBeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition(beanName);\n\t\t\t\tif (beanDefinition != null && beanDefinition.isAbstract()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (beanFactory.findAnnotationOnBean(beanName, annotationType, false) != null) {\n\t\t\t\tfoundBeanNames.add(beanName);\n\t\t\t}\n\t\t}\n\t\tif (beanFactory instanceof SingletonBeanRegistry singletonBeanRegistry) {\n\t\t\tfor (String beanName : singletonBeanRegistry.getSingletonNames()) {\n\t\t\t\tif (beanFactory.findAnnotationOnBean(beanName, annotationType) != null) {\n\t\t\t\t\tfoundBeanNames.add(beanName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn foundBeanNames.toArray(String[]::new);\n\t}\n\n\tprivate boolean containsBean(ConfigurableListableBeanFactory beanFactory, String beanName,\n\t\t\tboolean considerHierarchy) {\n\t\tif (considerHierarchy) {\n\t\t\treturn beanFactory.containsBean(beanName);\n\t\t}\n\t\treturn beanFactory.containsLocalBean(beanName);\n\t}\n\n\tprivate String createOnBeanNoMatchReason(MatchResult matchResult) {\n\t\tStringBuilder reason = new StringBuilder();\n\t\tappendMessageForNoMatches(reason, matchResult.getUnmatchedAnnotations(), \"annotated with\");\n\t\tappendMessageForNoMatches(reason, matchResult.getUnmatchedTypes(), \"of type\");\n\t\tappendMessageForNoMatches(reason, matchResult.getUnmatchedNames(), \"named\");\n\t\treturn reason.toString();\n\t}\n\n\tprivate void appendMessageForNoMatches(StringBuilder reason, Collection<String> unmatched, String description) {\n\t\tif (!unmatched.isEmpty()) {\n\t\t\tif (!reason.isEmpty()) {\n\t\t\t\treason.append(\" and \");\n\t\t\t}\n\t\t\treason.append(\"did not find any beans \");\n\t\t\treason.append(description);\n\t\t\treason.append(\" \");\n\t\t\treason.append(StringUtils.collectionToDelimitedString(unmatched, \", \"));\n\t\t}\n\t}\n\n\tprivate String createOnMissingBeanNoMatchReason(MatchResult matchResult) {\n\t\tStringBuilder reason = new StringBuilder();\n\t\tappendMessageForMatches(reason, matchResult.getMatchedAnnotations(), \"annotated with\");\n\t\tappendMessageForMatches(reason, matchResult.getMatchedTypes(), \"of type\");\n\t\tif (!matchResult.getMatchedNames().isEmpty()) {\n\t\t\tif (!reason.isEmpty()) {\n\t\t\t\treason.append(\" and \");\n\t\t\t}\n\t\t\treason.append(\"found beans named \");\n\t\t\treason.append(StringUtils.collectionToDelimitedString(matchResult.getMatchedNames(), \", \"));\n\t\t}\n\t\treturn reason.toString();\n\t}\n\n\tprivate void appendMessageForMatches(StringBuilder reason, Map<String, Collection<String>> matches,\n\t\t\tString description) {\n\t\tif (!matches.isEmpty()) {\n\t\t\tmatches.forEach((key, value) -> {\n\t\t\t\tif (!reason.isEmpty()) {\n\t\t\t\t\treason.append(\" and \");\n\t\t\t\t}\n\t\t\t\treason.append(\"found beans \");\n\t\t\t\treason.append(description);\n\t\t\t\treason.append(\" '\");\n\t\t\t\treason.append(key);\n\t\t\t\treason.append(\"' \");\n\t\t\t\treason.append(StringUtils.collectionToDelimitedString(value, \", \"));\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate Map<String, @Nullable BeanDefinition> getBeanDefinitions(ConfigurableListableBeanFactory beanFactory,\n\t\t\tSet<String> beanNames, boolean considerHierarchy) {\n\t\tMap<String, @Nullable BeanDefinition> definitions = new HashMap<>(beanNames.size());\n\t\tfor (String beanName : beanNames) {\n\t\t\tBeanDefinition beanDefinition = findBeanDefinition(beanFactory, beanName, considerHierarchy);\n\t\t\tdefinitions.put(beanName, beanDefinition);\n\t\t}\n\t\treturn definitions;\n\t}\n\n\tprivate List<String> getPrimaryBeans(Map<String, @Nullable BeanDefinition> beanDefinitions) {\n\t\treturn getMatchingBeans(beanDefinitions, this::isPrimary);\n\t}\n\n\tprivate boolean isPrimary(@Nullable BeanDefinition beanDefinition) {\n\t\treturn (beanDefinition != null) && beanDefinition.isPrimary();\n\t}\n\n\tprivate List<String> getNonFallbackBeans(Map<String, @Nullable BeanDefinition> beanDefinitions) {\n\t\treturn getMatchingBeans(beanDefinitions, this::isNotFallback);\n\t}\n\n\tprivate boolean isNotFallback(@Nullable BeanDefinition beanDefinition) {\n\t\treturn (beanDefinition == null) || !beanDefinition.isFallback();\n\t}\n\n\tprivate List<String> getMatchingBeans(Map<String, @Nullable BeanDefinition> beanDefinitions,\n\t\t\tPredicate<@Nullable BeanDefinition> test) {\n\t\tList<String> matches = new ArrayList<>();\n\t\tfor (Entry<String, @Nullable BeanDefinition> namedBeanDefinition : beanDefinitions.entrySet()) {\n\t\t\tif (test.test(namedBeanDefinition.getValue())) {\n\t\t\t\tmatches.add(namedBeanDefinition.getKey());\n\t\t\t}\n\t\t}\n\t\treturn matches;\n\t}\n\n\tprivate @Nullable BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName,\n\t\t\tboolean considerHierarchy) {\n\t\tif (beanFactory.containsBeanDefinition(beanName)) {\n\t\t\treturn beanFactory.getBeanDefinition(beanName);\n\t\t}\n\t\tif (considerHierarchy\n\t\t\t\t&& beanFactory.getParentBeanFactory() instanceof ConfigurableListableBeanFactory listableBeanFactory) {\n\t\t\treturn findBeanDefinition(listableBeanFactory, beanName, considerHierarchy);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static @Nullable Set<String> addAll(@Nullable Set<String> result, @Nullable Collection<String> additional) {\n\t\tif (CollectionUtils.isEmpty(additional)) {\n\t\t\treturn result;\n\t\t}\n\t\tresult = (result != null) ? result : new LinkedHashSet<>();\n\t\tresult.addAll(additional);\n\t\treturn result;\n\t}\n\n\tprivate static @Nullable Map<String, @Nullable BeanDefinition> putAll(\n\t\t\t@Nullable Map<String, @Nullable BeanDefinition> result, String[] beanNames,\n\t\t\tListableBeanFactory beanFactory) {\n\t\tif (ObjectUtils.isEmpty(beanNames)) {\n\t\t\treturn result;\n\t\t}\n\t\tif (result == null) {\n\t\t\tresult = new LinkedHashMap<>();\n\t\t}\n\t\tfor (String beanName : beanNames) {\n\t\t\tif (beanFactory instanceof ConfigurableListableBeanFactory clbf) {\n\t\t\t\tresult.put(beanName, getBeanDefinition(beanName, clbf));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.put(beanName, null);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static @Nullable BeanDefinition getBeanDefinition(String beanName,\n\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\ttry {\n\t\t\treturn beanFactory.getBeanDefinition(beanName);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\tif (BeanFactoryUtils.isFactoryDereference(beanName)) {\n\t\t\t\treturn getBeanDefinition(BeanFactoryUtils.transformedBeanName(beanName), beanFactory);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * A search specification extracted from the underlying annotation.\n\t */\n\tprivate static class Spec<A extends Annotation> {\n\n\t\tprivate final ConditionContext context;\n\n\t\tprivate final Class<? extends Annotation> annotationType;\n\n\t\tprivate final Set<String> names;\n\n\t\tprivate final Set<BeanType> types;\n\n\t\tprivate final Set<String> annotations;\n\n\t\tprivate final Set<BeanType> ignoredTypes;\n\n\t\tprivate final Set<BeanType> parameterizedContainers;\n\n\t\tprivate final @Nullable SearchStrategy strategy;\n\n\t\tSpec(ConditionContext context, AnnotatedTypeMetadata metadata, MergedAnnotations annotations,\n\t\t\t\tClass<A> annotationType) {\n\t\t\tMultiValueMap<String, @Nullable Object> attributes = annotations.stream(annotationType)\n\t\t\t\t.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))\n\t\t\t\t.collect(MergedAnnotationCollectors.toMultiValueMap(Adapt.CLASS_TO_STRING));\n\t\t\tMergedAnnotation<A> annotation = annotations.get(annotationType);\n\t\t\tthis.context = context;\n\t\t\tthis.annotationType = annotationType;\n\t\t\tthis.names = extract(attributes, \"name\");\n\t\t\tthis.annotations = extract(attributes, \"annotation\");\n\t\t\tthis.ignoredTypes = resolveWhenPossible(extract(attributes, \"ignored\", \"ignoredType\"));\n\t\t\tthis.parameterizedContainers = resolveWhenPossible(extract(attributes, \"parameterizedContainer\"));\n\t\t\tthis.strategy = annotation.getValue(\"search\", SearchStrategy.class).orElse(null);\n\t\t\tSet<BeanType> types = resolveWhenPossible(extractTypes(attributes));\n\t\t\tBeanTypeDeductionException deductionException = null;\n\t\t\tif (types.isEmpty() && this.names.isEmpty() && this.annotations.isEmpty()) {\n\t\t\t\ttry {\n\t\t\t\t\ttypes = deducedBeanType(context, metadata);\n\t\t\t\t}\n\t\t\t\tcatch (BeanTypeDeductionException ex) {\n\t\t\t\t\tdeductionException = ex;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.types = types;\n\t\t\tvalidate(deductionException);\n\t\t}\n\n\t\tprotected Set<String> extractTypes(@Nullable MultiValueMap<String, @Nullable Object> attributes) {\n\t\t\treturn extract(attributes, \"value\", \"type\");\n\t\t}\n\n\t\tprivate Set<String> extract(@Nullable MultiValueMap<String, @Nullable Object> attributes,\n\t\t\t\tString... attributeNames) {\n\t\t\tif (CollectionUtils.isEmpty(attributes)) {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\t\t\tSet<String> result = new LinkedHashSet<>();\n\t\t\tfor (String attributeName : attributeNames) {\n\t\t\t\tList<@Nullable Object> values = attributes.getOrDefault(attributeName, Collections.emptyList());\n\t\t\t\tfor (Object value : values) {\n\t\t\t\t\tif (value instanceof String[] stringArray) {\n\t\t\t\t\t\tmerge(result, stringArray);\n\t\t\t\t\t}\n\t\t\t\t\telse if (value instanceof String string) {\n\t\t\t\t\t\tmerge(result, string);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result.isEmpty() ? Collections.emptySet() : result;\n\t\t}\n\n\t\tprivate void merge(Set<String> result, String... additional) {\n\t\t\tCollections.addAll(result, additional);\n\t\t}\n\n\t\tprivate Set<BeanType> resolveWhenPossible(Set<String> classNames) {\n\t\t\tif (classNames.isEmpty()) {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\t\t\tSet<BeanType> resolved = new LinkedHashSet<>(classNames.size());\n\t\t\tfor (String className : classNames) {\n\t\t\t\ttry {\n\t\t\t\t\tClass<?> type = resolve(className, this.context.getClassLoader());\n\t\t\t\t\tresolved.add(new BeanType(className, ResolvableType.forRawClass(type)));\n\t\t\t\t}\n\t\t\t\tcatch (ClassNotFoundException | NoClassDefFoundError ex) {\n\t\t\t\t\tresolved.add(new BeanType(className, ResolvableType.NONE));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resolved;\n\t\t}\n\n\t\tprotected void validate(@Nullable BeanTypeDeductionException ex) {\n\t\t\tif (!hasAtLeastOneElement(getTypes(), getNames(), getAnnotations())) {\n\t\t\t\tString message = getAnnotationName() + \" did not specify a bean using type, name or annotation\";\n\t\t\t\tif (ex == null) {\n\t\t\t\t\tthrow new IllegalStateException(message);\n\t\t\t\t}\n\t\t\t\tthrow new IllegalStateException(message + \" and the attempt to deduce the bean's type failed\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean hasAtLeastOneElement(Set<?>... sets) {\n\t\t\tfor (Set<?> set : sets) {\n\t\t\t\tif (!set.isEmpty()) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprotected final String getAnnotationName() {\n\t\t\treturn \"@\" + ClassUtils.getShortName(this.annotationType);\n\t\t}\n\n\t\tprivate Set<BeanType> deducedBeanType(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tif (metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName())) {\n\t\t\t\treturn deducedBeanTypeForBeanMethod(context, (MethodMetadata) metadata);\n\t\t\t}\n\t\t\treturn Collections.emptySet();\n\t\t}\n\n\t\tprivate Set<BeanType> deducedBeanTypeForBeanMethod(ConditionContext context, MethodMetadata metadata) {\n\t\t\ttry {\n\t\t\t\treturn Set.of(getReturnType(context, metadata));\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new BeanTypeDeductionException(metadata.getDeclaringClassName(), metadata.getMethodName(), ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate BeanType getReturnType(ConditionContext context, MethodMetadata metadata)\n\t\t\t\tthrows ClassNotFoundException, LinkageError {\n\t\t\t// Safe to load at this point since we are in the REGISTER_BEAN phase\n\t\t\tClassLoader classLoader = context.getClassLoader();\n\t\t\tResolvableType returnType = getMethodReturnType(metadata, classLoader);\n\t\t\tif (isParameterizedContainer(returnType.resolve())) {\n\t\t\t\treturnType = returnType.getGeneric();\n\t\t\t}\n\t\t\treturn new BeanType(returnType.toString(), returnType);\n\t\t}\n\n\t\tprivate boolean isParameterizedContainer(@Nullable Class<?> type) {\n\t\t\treturn (type != null) && this.parameterizedContainers.stream()\n\t\t\t\t.map((beanType) -> beanType.resolvableType().resolve(type))\n\t\t\t\t.anyMatch((container) -> container != null && container.isAssignableFrom(type));\n\t\t}\n\n\t\tprivate ResolvableType getMethodReturnType(MethodMetadata metadata, @Nullable ClassLoader classLoader)\n\t\t\t\tthrows ClassNotFoundException, LinkageError {\n\t\t\tClass<?> declaringClass = resolve(metadata.getDeclaringClassName(), classLoader);\n\t\t\tMethod beanMethod = findBeanMethod(declaringClass, metadata.getMethodName());\n\t\t\treturn ResolvableType.forMethodReturnType(beanMethod);\n\t\t}\n\n\t\tprivate Method findBeanMethod(Class<?> declaringClass, String methodName) {\n\t\t\tMethod method = ReflectionUtils.findMethod(declaringClass, methodName);\n\t\t\tif (isBeanMethod(method)) {\n\t\t\t\treturn method;\n\t\t\t}\n\t\t\tMethod[] candidates = ReflectionUtils.getAllDeclaredMethods(declaringClass);\n\t\t\tfor (Method candidate : candidates) {\n\t\t\t\tif (candidate.getName().equals(methodName) && isBeanMethod(candidate)) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unable to find bean method \" + methodName);\n\t\t}\n\n\t\t@Contract(\"null -> false\")\n\t\tprivate boolean isBeanMethod(@Nullable Method method) {\n\t\t\treturn method != null && MergedAnnotations.from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.isPresent(Bean.class);\n\t\t}\n\n\t\tprivate SearchStrategy getStrategy() {\n\t\t\treturn (this.strategy != null) ? this.strategy : SearchStrategy.ALL;\n\t\t}\n\n\t\tSet<BeanType> getTypes() {\n\t\t\treturn this.types;\n\t\t}\n\n\t\tprivate ConditionContext getContext() {\n\t\t\treturn this.context;\n\t\t}\n\n\t\tprivate Set<String> getNames() {\n\t\t\treturn this.names;\n\t\t}\n\n\t\tprivate Set<String> getAnnotations() {\n\t\t\treturn this.annotations;\n\t\t}\n\n\t\tprivate Set<BeanType> getIgnoredTypes() {\n\t\t\treturn this.ignoredTypes;\n\t\t}\n\n\t\tprivate Set<BeanType> getParameterizedContainers() {\n\t\t\treturn this.parameterizedContainers;\n\t\t}\n\n\t\tprivate Builder message() {\n\t\t\treturn ConditionMessage.forCondition(this.annotationType, this);\n\t\t}\n\n\t\tprivate Builder message(ConditionMessage message) {\n\t\t\treturn message.andCondition(this.annotationType, this);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tboolean hasNames = !this.names.isEmpty();\n\t\t\tboolean hasTypes = !this.types.isEmpty();\n\t\t\tboolean hasIgnoredTypes = !this.ignoredTypes.isEmpty();\n\t\t\tStringBuilder string = new StringBuilder();\n\t\t\tstring.append(\"(\");\n\t\t\tif (hasNames) {\n\t\t\t\tstring.append(\"names: \");\n\t\t\t\tstring.append(StringUtils.collectionToCommaDelimitedString(this.names));\n\t\t\t\tstring.append(hasTypes ? \" \" : \"; \");\n\t\t\t}\n\t\t\tif (hasTypes) {\n\t\t\t\tstring.append(\"types: \");\n\t\t\t\tstring.append(StringUtils.collectionToCommaDelimitedString(this.types));\n\t\t\t\tstring.append(hasIgnoredTypes ? \" \" : \"; \");\n\t\t\t}\n\t\t\tif (hasIgnoredTypes) {\n\t\t\t\tstring.append(\"ignored: \");\n\t\t\t\tstring.append(StringUtils.collectionToCommaDelimitedString(this.ignoredTypes));\n\t\t\t\tstring.append(\"; \");\n\t\t\t}\n\t\t\tif (this.strategy != null) {\n\t\t\t\tstring.append(\"SearchStrategy: \");\n\t\t\t\tstring.append(this.strategy.toString().toLowerCase(Locale.ENGLISH));\n\t\t\t}\n\t\t\tstring.append(\")\");\n\t\t\treturn string.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * Specialized {@link Spec specification} for\n\t * {@link ConditionalOnSingleCandidate @ConditionalOnSingleCandidate}.\n\t */\n\tprivate static class SingleCandidateSpec extends Spec<ConditionalOnSingleCandidate> {\n\n\t\tprivate static final Collection<String> FILTERED_TYPES = Arrays.asList(\"\", Object.class.getName());\n\n\t\tSingleCandidateSpec(ConditionContext context, AnnotatedTypeMetadata metadata, MergedAnnotations annotations) {\n\t\t\tsuper(context, metadata, annotations, ConditionalOnSingleCandidate.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected Set<String> extractTypes(@Nullable MultiValueMap<String, @Nullable Object> attributes) {\n\t\t\tSet<String> types = super.extractTypes(attributes);\n\t\t\ttypes.removeAll(FILTERED_TYPES);\n\t\t\treturn types;\n\t\t}\n\n\t\t@Override\n\t\tprotected void validate(@Nullable BeanTypeDeductionException ex) {\n\t\t\tAssert.isTrue(getTypes().size() == 1,\n\t\t\t\t\t() -> getAnnotationName() + \" annotations must specify only one type (got \"\n\t\t\t\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(getTypes()) + \")\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Results collected during the condition evaluation.\n\t */\n\tprivate static final class MatchResult {\n\n\t\tprivate final Map<String, Collection<String>> matchedAnnotations = new HashMap<>();\n\n\t\tprivate final List<String> matchedNames = new ArrayList<>();\n\n\t\tprivate final Map<String, Collection<String>> matchedTypes = new HashMap<>();\n\n\t\tprivate final List<String> unmatchedAnnotations = new ArrayList<>();\n\n\t\tprivate final List<String> unmatchedNames = new ArrayList<>();\n\n\t\tprivate final List<String> unmatchedTypes = new ArrayList<>();\n\n\t\tprivate final Set<String> namesOfAllMatches = new HashSet<>();\n\n\t\tprivate void recordMatchedName(String name) {\n\t\t\tthis.matchedNames.add(name);\n\t\t\tthis.namesOfAllMatches.add(name);\n\t\t}\n\n\t\tprivate void recordUnmatchedName(String name) {\n\t\t\tthis.unmatchedNames.add(name);\n\t\t}\n\n\t\tprivate void recordMatchedAnnotation(String annotation, Collection<String> matchingNames) {\n\t\t\tthis.matchedAnnotations.put(annotation, matchingNames);\n\t\t\tthis.namesOfAllMatches.addAll(matchingNames);\n\t\t}\n\n\t\tprivate void recordUnmatchedAnnotation(String annotation) {\n\t\t\tthis.unmatchedAnnotations.add(annotation);\n\t\t}\n\n\t\tprivate void recordMatchedType(BeanType type, Collection<String> matchingNames) {\n\t\t\tthis.matchedTypes.put(type.name.toString(), matchingNames);\n\t\t\tthis.namesOfAllMatches.addAll(matchingNames);\n\t\t}\n\n\t\tprivate void recordUnmatchedType(BeanType type) {\n\t\t\tthis.unmatchedTypes.add(type.toString());\n\t\t}\n\n\t\tboolean isAllMatched() {\n\t\t\treturn this.unmatchedAnnotations.isEmpty() && this.unmatchedNames.isEmpty()\n\t\t\t\t\t&& this.unmatchedTypes.isEmpty();\n\t\t}\n\n\t\tboolean isAnyMatched() {\n\t\t\treturn (!this.matchedAnnotations.isEmpty()) || (!this.matchedNames.isEmpty())\n\t\t\t\t\t|| (!this.matchedTypes.isEmpty());\n\t\t}\n\n\t\tMap<String, Collection<String>> getMatchedAnnotations() {\n\t\t\treturn this.matchedAnnotations;\n\t\t}\n\n\t\tList<String> getMatchedNames() {\n\t\t\treturn this.matchedNames;\n\t\t}\n\n\t\tMap<String, Collection<String>> getMatchedTypes() {\n\t\t\treturn this.matchedTypes;\n\t\t}\n\n\t\tList<String> getUnmatchedAnnotations() {\n\t\t\treturn this.unmatchedAnnotations;\n\t\t}\n\n\t\tList<String> getUnmatchedNames() {\n\t\t\treturn this.unmatchedNames;\n\t\t}\n\n\t\tList<String> getUnmatchedTypes() {\n\t\t\treturn this.unmatchedTypes;\n\t\t}\n\n\t\tSet<String> getNamesOfAllMatches() {\n\t\t\treturn this.namesOfAllMatches;\n\t\t}\n\n\t}\n\n\t/**\n\t * Exception thrown when the bean type cannot be deduced.\n\t */\n\tstatic final class BeanTypeDeductionException extends RuntimeException {\n\n\t\tprivate BeanTypeDeductionException(String className, String beanMethodName, Throwable cause) {\n\t\t\tsuper(\"Failed to deduce bean type for \" + className + \".\" + beanMethodName, cause);\n\t\t}\n\n\t}\n\n\trecord BeanType(String name, ResolvableType resolvableType) {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn ResolvableType.NONE.equals(this.resolvableType) ? this.name : this.resolvableType.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnClassCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;\nimport org.springframework.boot.autoconfigure.AutoConfigurationMetadata;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Condition} and {@link AutoConfigurationImportFilter} that checks for the\n * presence or absence of specific classes.\n *\n * @author Phillip Webb\n * @see ConditionalOnClass\n * @see ConditionalOnMissingClass\n */\n@Order(Ordered.HIGHEST_PRECEDENCE)\nclass OnClassCondition extends FilteringSpringBootCondition {\n\n\t@Override\n\tprotected final @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t// Split the work and perform half in a background thread if more than one\n\t\t// processor is available. Using a single additional thread seems to offer the\n\t\t// best performance. More threads make things worse.\n\t\tif (autoConfigurationClasses.length > 1 && Runtime.getRuntime().availableProcessors() > 1) {\n\t\t\treturn resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata);\n\t\t}\n\t\telse {\n\t\t\tOutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0,\n\t\t\t\t\tautoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());\n\t\t\treturn outcomesResolver.resolveOutcomes();\n\t\t}\n\t}\n\n\tprivate @Nullable ConditionOutcome[] resolveOutcomesThreaded(@Nullable String[] autoConfigurationClasses,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\tint split = autoConfigurationClasses.length / 2;\n\t\tOutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,\n\t\t\t\tautoConfigurationMetadata);\n\t\tOutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,\n\t\t\t\tautoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());\n\t\t@Nullable ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();\n\t\t@Nullable ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();\n\t\t@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];\n\t\tSystem.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);\n\t\tSystem.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);\n\t\treturn outcomes;\n\t}\n\n\tprivate OutcomesResolver createOutcomesResolver(@Nullable String[] autoConfigurationClasses, int start, int end,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\tOutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, start, end,\n\t\t\t\tautoConfigurationMetadata, getBeanClassLoader());\n\t\treturn new ThreadedOutcomesResolver(outcomesResolver);\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tClassLoader classLoader = context.getClassLoader();\n\t\tConditionMessage matchMessage = ConditionMessage.empty();\n\t\tList<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);\n\t\tif (onClasses != null) {\n\t\t\tList<String> missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);\n\t\t\tif (!missing.isEmpty()) {\n\t\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)\n\t\t\t\t\t.didNotFind(\"required class\", \"required classes\")\n\t\t\t\t\t.items(Style.QUOTE, missing));\n\t\t\t}\n\t\t\tmatchMessage = matchMessage.andCondition(ConditionalOnClass.class)\n\t\t\t\t.found(\"required class\", \"required classes\")\n\t\t\t\t.items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));\n\t\t}\n\t\tList<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);\n\t\tif (onMissingClasses != null) {\n\t\t\tList<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);\n\t\t\tif (!present.isEmpty()) {\n\t\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnMissingClass.class)\n\t\t\t\t\t.found(\"unwanted class\", \"unwanted classes\")\n\t\t\t\t\t.items(Style.QUOTE, present));\n\t\t\t}\n\t\t\tmatchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)\n\t\t\t\t.didNotFind(\"unwanted class\", \"unwanted classes\")\n\t\t\t\t.items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));\n\t\t}\n\t\treturn ConditionOutcome.match(matchMessage);\n\t}\n\n\tprivate @Nullable List<String> getCandidates(AnnotatedTypeMetadata metadata, Class<?> annotationType) {\n\t\tMultiValueMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAllAnnotationAttributes(annotationType.getName(), true);\n\t\tif (attributes == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<String> candidates = new ArrayList<>();\n\t\taddAll(candidates, attributes.get(\"value\"));\n\t\taddAll(candidates, attributes.get(\"name\"));\n\t\treturn candidates;\n\t}\n\n\tprivate void addAll(List<String> list, @Nullable List<@Nullable Object> itemsToAdd) {\n\t\tif (itemsToAdd != null) {\n\t\t\tfor (Object item : itemsToAdd) {\n\t\t\t\tif (item != null) {\n\t\t\t\t\tCollections.addAll(list, (String[]) item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate interface OutcomesResolver {\n\n\t\t@Nullable ConditionOutcome[] resolveOutcomes();\n\n\t}\n\n\tprivate static final class ThreadedOutcomesResolver implements OutcomesResolver {\n\n\t\tprivate final Thread thread;\n\n\t\tprivate volatile @Nullable ConditionOutcome @Nullable [] outcomes;\n\n\t\tprivate volatile @Nullable Throwable failure;\n\n\t\tprivate ThreadedOutcomesResolver(OutcomesResolver outcomesResolver) {\n\t\t\tthis.thread = new Thread(() -> {\n\t\t\t\ttry {\n\t\t\t\t\tthis.outcomes = outcomesResolver.resolveOutcomes();\n\t\t\t\t}\n\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t\tthis.failure = ex;\n\t\t\t\t}\n\t\t\t});\n\t\t\tthis.thread.start();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConditionOutcome[] resolveOutcomes() {\n\t\t\ttry {\n\t\t\t\tthis.thread.join();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t\tThrowable failure = this.failure;\n\t\t\tif (failure != null) {\n\t\t\t\tReflectionUtils.rethrowRuntimeException(failure);\n\t\t\t}\n\t\t\t@Nullable ConditionOutcome[] outcomes = this.outcomes;\n\t\t\treturn (outcomes != null) ? outcomes : new ConditionOutcome[0];\n\t\t}\n\n\t}\n\n\tprivate static final class StandardOutcomesResolver implements OutcomesResolver {\n\n\t\tprivate final @Nullable String[] autoConfigurationClasses;\n\n\t\tprivate final int start;\n\n\t\tprivate final int end;\n\n\t\tprivate final AutoConfigurationMetadata autoConfigurationMetadata;\n\n\t\tprivate final ClassLoader beanClassLoader;\n\n\t\tprivate StandardOutcomesResolver(@Nullable String[] autoConfigurationClasses, int start, int end,\n\t\t\t\tAutoConfigurationMetadata autoConfigurationMetadata, ClassLoader beanClassLoader) {\n\t\t\tthis.autoConfigurationClasses = autoConfigurationClasses;\n\t\t\tthis.start = start;\n\t\t\tthis.end = end;\n\t\t\tthis.autoConfigurationMetadata = autoConfigurationMetadata;\n\t\t\tthis.beanClassLoader = beanClassLoader;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConditionOutcome[] resolveOutcomes() {\n\t\t\treturn getOutcomes(this.autoConfigurationClasses, this.start, this.end, this.autoConfigurationMetadata);\n\t\t}\n\n\t\tprivate @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses, int start,\n\t\t\t\tint end, AutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t\t@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[end - start];\n\t\t\tfor (int i = start; i < end; i++) {\n\t\t\t\tString autoConfigurationClass = autoConfigurationClasses[i];\n\t\t\t\tif (autoConfigurationClass != null) {\n\t\t\t\t\tString candidates = autoConfigurationMetadata.get(autoConfigurationClass, \"ConditionalOnClass\");\n\t\t\t\t\tif (candidates != null) {\n\t\t\t\t\t\toutcomes[i - start] = getOutcome(candidates);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn outcomes;\n\t\t}\n\n\t\tprivate @Nullable ConditionOutcome getOutcome(String candidates) {\n\t\t\ttry {\n\t\t\t\tif (!candidates.contains(\",\")) {\n\t\t\t\t\treturn getOutcome(candidates, this.beanClassLoader);\n\t\t\t\t}\n\t\t\t\tfor (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {\n\t\t\t\t\tConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);\n\t\t\t\t\tif (outcome != null) {\n\t\t\t\t\t\treturn outcome;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// We'll get another chance later\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable ConditionOutcome getOutcome(String className, ClassLoader classLoader) {\n\t\t\tif (ClassNameFilter.MISSING.matches(className, classLoader)) {\n\t\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)\n\t\t\t\t\t.didNotFind(\"required class\")\n\t\t\t\t\t.items(Style.QUOTE, className));\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnCloudPlatformCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Condition} that checks for a required {@link CloudPlatform}.\n *\n * @author Madhura Bhave\n * @see ConditionalOnCloudPlatform\n */\nclass OnCloudPlatformCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnCloudPlatform.class.getName());\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tCloudPlatform cloudPlatform = (CloudPlatform) attributes.get(\"value\");\n\t\tAssert.state(cloudPlatform != null, \"'cloudPlatform' must not be null\");\n\t\treturn getMatchOutcome(context.getEnvironment(), cloudPlatform);\n\t}\n\n\tprivate ConditionOutcome getMatchOutcome(Environment environment, CloudPlatform cloudPlatform) {\n\t\tString name = cloudPlatform.name();\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnCloudPlatform.class);\n\t\tif (cloudPlatform.isActive(environment)) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(name));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.didNotFind(name).atAll());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnExpressionCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanExpressionContext;\nimport org.springframework.beans.factory.config.BeanExpressionResolver;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.expression.StandardBeanExpressionResolver;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * A Condition that evaluates a SpEL expression.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @see ConditionalOnExpression\n */\n@Order(Ordered.LOWEST_PRECEDENCE - 20)\nclass OnExpressionCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnExpression.class.getName());\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tString expression = (String) attributes.get(\"value\");\n\t\tAssert.state(expression != null, \"'expression' must not be null\");\n\t\texpression = wrapIfNecessary(expression);\n\t\tConditionMessage.Builder messageBuilder = ConditionMessage.forCondition(ConditionalOnExpression.class,\n\t\t\t\t\"(\" + expression + \")\");\n\t\texpression = context.getEnvironment().resolvePlaceholders(expression);\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tif (beanFactory != null) {\n\t\t\tboolean result = evaluateExpression(beanFactory, expression);\n\t\t\treturn new ConditionOutcome(result, messageBuilder.resultedIn(result));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(messageBuilder.because(\"no BeanFactory available.\"));\n\t}\n\n\tprivate boolean evaluateExpression(ConfigurableListableBeanFactory beanFactory, String expression) {\n\t\tBeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();\n\t\tif (resolver == null) {\n\t\t\tresolver = new StandardBeanExpressionResolver();\n\t\t}\n\t\tBeanExpressionContext expressionContext = new BeanExpressionContext(beanFactory, null);\n\t\tObject result = resolver.evaluate(expression, expressionContext);\n\t\treturn (result != null && (boolean) result);\n\t}\n\n\t/**\n\t * Allow user to provide bare expression with no '#{}' wrapper.\n\t * @param expression source expression\n\t * @return wrapped expression\n\t */\n\tprivate String wrapIfNecessary(String expression) {\n\t\tif (!expression.startsWith(\"#{\")) {\n\t\t\treturn \"#{\" + expression + \"}\";\n\t\t}\n\t\treturn expression;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnJavaCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnJava.Range;\nimport org.springframework.boot.system.JavaVersion;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Condition} that checks for a required version of Java.\n *\n * @author Oliver Gierke\n * @author Phillip Webb\n * @see ConditionalOnJava\n */\n@Order(Ordered.HIGHEST_PRECEDENCE + 20)\nclass OnJavaCondition extends SpringBootCondition {\n\n\tprivate static final JavaVersion JVM_VERSION = JavaVersion.getJavaVersion();\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata.getAnnotationAttributes(ConditionalOnJava.class.getName());\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tRange range = (Range) attributes.get(\"range\");\n\t\tAssert.state(range != null, \"'range' must not be null\");\n\t\tJavaVersion version = (JavaVersion) attributes.get(\"value\");\n\t\tAssert.state(version != null, \"'version' must not be null\");\n\t\treturn getMatchOutcome(range, JVM_VERSION, version);\n\t}\n\n\tprotected ConditionOutcome getMatchOutcome(Range range, JavaVersion runningVersion, JavaVersion version) {\n\t\tboolean match = isWithin(runningVersion, range, version);\n\t\tString expected = String.format((range != Range.EQUAL_OR_NEWER) ? \"(older than %s)\" : \"(%s or newer)\", version);\n\t\tConditionMessage message = ConditionMessage.forCondition(ConditionalOnJava.class, expected)\n\t\t\t.foundExactly(runningVersion);\n\t\treturn new ConditionOutcome(match, message);\n\t}\n\n\t/**\n\t * Determines if the {@code runningVersion} is within the specified range of versions.\n\t * @param runningVersion the current version.\n\t * @param range the range\n\t * @param version the bounds of the range\n\t * @return if this version is within the specified range\n\t */\n\tprivate boolean isWithin(JavaVersion runningVersion, Range range, JavaVersion version) {\n\t\tif (range == Range.EQUAL_OR_NEWER) {\n\t\t\treturn runningVersion.isEqualOrNewerThan(version);\n\t\t}\n\t\tif (range == Range.OLDER_THAN) {\n\t\t\treturn runningVersion.isOlderThan(version);\n\t\t}\n\t\tthrow new IllegalStateException(\"Unknown range \" + range);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnJndiCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport javax.naming.NamingException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.jndi.JndiLocatorDelegate;\nimport org.springframework.jndi.JndiLocatorSupport;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Condition} that checks for JNDI locations.\n *\n * @author Phillip Webb\n * @see ConditionalOnJndi\n */\n@Order(Ordered.LOWEST_PRECEDENCE - 20)\nclass OnJndiCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t.fromMap(metadata.getAnnotationAttributes(ConditionalOnJndi.class.getName()));\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tString[] locations = attributes.getStringArray(\"value\");\n\t\ttry {\n\t\t\treturn getMatchOutcome(locations);\n\t\t}\n\t\tcatch (NoClassDefFoundError ex) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.noMatch(ConditionMessage.forCondition(ConditionalOnJndi.class).because(\"JNDI class not found\"));\n\t\t}\n\t}\n\n\tprivate ConditionOutcome getMatchOutcome(String[] locations) {\n\t\tif (!isJndiAvailable()) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.noMatch(ConditionMessage.forCondition(ConditionalOnJndi.class).notAvailable(\"JNDI environment\"));\n\t\t}\n\t\tif (locations.length == 0) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.match(ConditionMessage.forCondition(ConditionalOnJndi.class).available(\"JNDI environment\"));\n\t\t}\n\t\tJndiLocator locator = getJndiLocator(locations);\n\t\tString location = locator.lookupFirstLocation();\n\t\tString details = \"(\" + StringUtils.arrayToCommaDelimitedString(locations) + \")\";\n\t\tif (location != null) {\n\t\t\treturn ConditionOutcome.match(ConditionMessage.forCondition(ConditionalOnJndi.class, details)\n\t\t\t\t.foundExactly(\"\\\"\" + location + \"\\\"\"));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnJndi.class, details)\n\t\t\t.didNotFind(\"any matching JNDI location\")\n\t\t\t.atAll());\n\t}\n\n\tprotected boolean isJndiAvailable() {\n\t\treturn JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable();\n\t}\n\n\tprotected JndiLocator getJndiLocator(String[] locations) {\n\t\treturn new JndiLocator(locations);\n\t}\n\n\tprotected static class JndiLocator extends JndiLocatorSupport {\n\n\t\tprivate final String[] locations;\n\n\t\tpublic JndiLocator(String[] locations) {\n\t\t\tthis.locations = locations;\n\t\t}\n\n\t\tpublic @Nullable String lookupFirstLocation() {\n\t\t\tfor (String location : this.locations) {\n\t\t\t\ttry {\n\t\t\t\t\tlookup(location);\n\t\t\t\t\treturn location;\n\t\t\t\t}\n\t\t\t\tcatch (NamingException ex) {\n\t\t\t\t\t// Swallow and continue\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotationPredicates;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Condition} that checks if properties are defined in the environment.\n *\n * @author Maciej Walkowiak\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @see ConditionalOnProperty\n * @see ConditionalOnBooleanProperty\n */\n@Order(Ordered.HIGHEST_PRECEDENCE + 40)\nclass OnPropertyCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMergedAnnotations mergedAnnotations = metadata.getAnnotations();\n\t\tList<MergedAnnotation<Annotation>> annotations = stream(mergedAnnotations).toList();\n\t\tList<ConditionMessage> noMatch = new ArrayList<>();\n\t\tList<ConditionMessage> match = new ArrayList<>();\n\t\tfor (MergedAnnotation<Annotation> annotation : annotations) {\n\t\t\tConditionOutcome outcome = determineOutcome(annotation, context.getEnvironment());\n\t\t\t(outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());\n\t\t}\n\t\tif (!noMatch.isEmpty()) {\n\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.of(noMatch));\n\t\t}\n\t\treturn ConditionOutcome.match(ConditionMessage.of(match));\n\t}\n\n\tprivate Stream<MergedAnnotation<Annotation>> stream(MergedAnnotations mergedAnnotations) {\n\t\treturn Stream.concat(stream(mergedAnnotations, ConditionalOnProperty.class, ConditionalOnProperties.class),\n\t\t\t\tstream(mergedAnnotations, ConditionalOnBooleanProperty.class, ConditionalOnBooleanProperties.class));\n\t}\n\n\tprivate Stream<MergedAnnotation<Annotation>> stream(MergedAnnotations mergedAnnotations,\n\t\t\tClass<? extends Annotation> type, Class<? extends Annotation> containerType) {\n\t\treturn Stream.concat(stream(mergedAnnotations, type), streamRepeated(mergedAnnotations, type, containerType));\n\t}\n\n\tprivate Stream<MergedAnnotation<Annotation>> streamRepeated(MergedAnnotations mergedAnnotations,\n\t\t\tClass<? extends Annotation> type, Class<? extends Annotation> containerType) {\n\t\treturn stream(mergedAnnotations, containerType).flatMap((container) -> streamRepeated(container, type));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Stream<MergedAnnotation<Annotation>> streamRepeated(MergedAnnotation<Annotation> container,\n\t\t\tClass<? extends Annotation> type) {\n\t\tMergedAnnotation<? extends Annotation>[] repeated = container.getAnnotationArray(MergedAnnotation.VALUE, type);\n\t\treturn Arrays.stream((MergedAnnotation<Annotation>[]) repeated);\n\t}\n\n\tprivate Stream<MergedAnnotation<Annotation>> stream(MergedAnnotations annotations,\n\t\t\tClass<? extends Annotation> type) {\n\t\treturn annotations.stream(type.getName())\n\t\t\t.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes));\n\t}\n\n\tprivate ConditionOutcome determineOutcome(MergedAnnotation<Annotation> annotation, PropertyResolver resolver) {\n\t\tClass<Annotation> annotationType = annotation.getType();\n\t\tSpec spec = new Spec(annotationType, annotation.asAnnotationAttributes());\n\t\tList<String> missingProperties = new ArrayList<>();\n\t\tList<String> nonMatchingProperties = new ArrayList<>();\n\t\tspec.collectProperties(resolver, missingProperties, nonMatchingProperties);\n\t\tif (!missingProperties.isEmpty()) {\n\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(annotationType, spec)\n\t\t\t\t.didNotFind(\"property\", \"properties\")\n\t\t\t\t.items(Style.QUOTE, missingProperties));\n\t\t}\n\t\tif (!nonMatchingProperties.isEmpty()) {\n\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(annotationType, spec)\n\t\t\t\t.found(\"different value in property\", \"different value in properties\")\n\t\t\t\t.items(Style.QUOTE, nonMatchingProperties));\n\t\t}\n\t\treturn ConditionOutcome.match(ConditionMessage.forCondition(annotationType, spec).because(\"matched\"));\n\t}\n\n\tprivate static class Spec {\n\n\t\tprivate final Class<? extends Annotation> annotationType;\n\n\t\tprivate final String prefix;\n\n\t\tprivate final String[] names;\n\n\t\tprivate final String havingValue;\n\n\t\tprivate final boolean matchIfMissing;\n\n\t\tSpec(Class<? extends Annotation> annotationType, AnnotationAttributes annotationAttributes) {\n\t\t\tthis.annotationType = annotationType;\n\t\t\tthis.prefix = (!annotationAttributes.containsKey(\"prefix\")) ? \"\" : getPrefix(annotationAttributes);\n\t\t\tthis.names = getNames(annotationAttributes);\n\t\t\tthis.havingValue = getHavingValue(annotationAttributes);\n\t\t\tthis.matchIfMissing = annotationAttributes.getBoolean(\"matchIfMissing\");\n\t\t}\n\n\t\tprivate static String getHavingValue(AnnotationAttributes annotationAttributes) {\n\t\t\tObject havingValue = annotationAttributes.get(\"havingValue\");\n\t\t\tAssert.state(havingValue != null, \"'havingValue' must not be null\");\n\t\t\treturn havingValue.toString();\n\t\t}\n\n\t\tprivate String getPrefix(AnnotationAttributes annotationAttributes) {\n\t\t\tString prefix = annotationAttributes.getString(\"prefix\").trim();\n\t\t\tif (StringUtils.hasText(prefix) && !prefix.endsWith(\".\")) {\n\t\t\t\tprefix = prefix + \".\";\n\t\t\t}\n\t\t\treturn prefix;\n\t\t}\n\n\t\tprivate String[] getNames(AnnotationAttributes annotationAttributes) {\n\t\t\tString[] value = (String[]) annotationAttributes.get(\"value\");\n\t\t\tString[] name = (String[]) annotationAttributes.get(\"name\");\n\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\tAssert.state(value.length > 0 || name.length > 0,\n\t\t\t\t\t() -> \"The name or value attribute of @%s must be specified\"\n\t\t\t\t\t\t.formatted(ClassUtils.getShortName(this.annotationType)));\n\t\t\tAssert.state(value.length == 0 || name.length == 0,\n\t\t\t\t\t() -> \"The name and value attributes of @%s are exclusive\"\n\t\t\t\t\t\t.formatted(ClassUtils.getShortName(this.annotationType)));\n\t\t\treturn (value.length > 0) ? value : name;\n\t\t}\n\n\t\tprivate void collectProperties(PropertyResolver resolver, List<String> missing, List<String> nonMatching) {\n\t\t\tfor (String name : this.names) {\n\t\t\t\tString key = this.prefix + name;\n\t\t\t\tif (resolver.containsProperty(key)) {\n\t\t\t\t\tif (!isMatch(resolver.getProperty(key), this.havingValue)) {\n\t\t\t\t\t\tnonMatching.add(name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!this.matchIfMissing) {\n\t\t\t\t\t\tmissing.add(name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isMatch(@Nullable String value, String requiredValue) {\n\t\t\tif (StringUtils.hasLength(requiredValue)) {\n\t\t\t\treturn requiredValue.equalsIgnoreCase(value);\n\t\t\t}\n\t\t\treturn !\"false\".equalsIgnoreCase(value);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tresult.append(\"(\");\n\t\t\tresult.append(this.prefix);\n\t\t\tif (this.names.length == 1) {\n\t\t\t\tresult.append(this.names[0]);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.append(\"[\");\n\t\t\t\tresult.append(StringUtils.arrayToCommaDelimitedString(this.names));\n\t\t\t\tresult.append(\"]\");\n\t\t\t}\n\t\t\tif (StringUtils.hasLength(this.havingValue)) {\n\t\t\t\tresult.append(\"=\").append(this.havingValue);\n\t\t\t}\n\t\t\tresult.append(\")\");\n\t\t\treturn result.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnPropertyListCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link Condition} that checks if a property whose value is a list is defined in the\n * environment.\n *\n * @author Eneias Silva\n * @author Stephane Nicoll\n * @since 2.0.5\n */\npublic abstract class OnPropertyListCondition extends SpringBootCondition {\n\n\tprivate static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);\n\n\tprivate final String propertyName;\n\n\tprivate final Supplier<ConditionMessage.Builder> messageBuilder;\n\n\t/**\n\t * Create a new instance with the property to check and the message builder to use.\n\t * @param propertyName the name of the property\n\t * @param messageBuilder a message builder supplier that should provide a fresh\n\t * instance on each call\n\t */\n\tprotected OnPropertyListCondition(String propertyName, Supplier<ConditionMessage.Builder> messageBuilder) {\n\t\tthis.propertyName = propertyName;\n\t\tthis.messageBuilder = messageBuilder;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tBindResult<?> property = Binder.get(context.getEnvironment()).bind(this.propertyName, STRING_LIST);\n\t\tConditionMessage.Builder messageBuilder = this.messageBuilder.get();\n\t\tif (property.isBound()) {\n\t\t\treturn ConditionOutcome.match(messageBuilder.found(\"property\").items(this.propertyName));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(messageBuilder.didNotFind(\"property\").items(this.propertyName));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnResourceCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * {@link Condition} that checks for specific resources.\n *\n * @author Dave Syer\n * @see ConditionalOnResource\n */\n@Order(Ordered.HIGHEST_PRECEDENCE + 20)\nclass OnResourceCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMultiValueMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAllAnnotationAttributes(ConditionalOnResource.class.getName(), true);\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tResourceLoader loader = context.getResourceLoader();\n\t\tList<String> locations = new ArrayList<>();\n\t\tList<@Nullable Object> resources = attributes.get(\"resources\");\n\t\tAssert.state(resources != null, \"'resources' must not be null\");\n\t\tcollectValues(locations, resources);\n\t\tAssert.state(!locations.isEmpty(),\n\t\t\t\t\"@ConditionalOnResource annotations must specify at least one resource location\");\n\t\tList<String> missing = new ArrayList<>();\n\t\tfor (String location : locations) {\n\t\t\tString resource = context.getEnvironment().resolvePlaceholders(location);\n\t\t\tif (!loader.getResource(resource).exists()) {\n\t\t\t\tmissing.add(location);\n\t\t\t}\n\t\t}\n\t\tif (!missing.isEmpty()) {\n\t\t\treturn ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnResource.class)\n\t\t\t\t.didNotFind(\"resource\", \"resources\")\n\t\t\t\t.items(Style.QUOTE, missing));\n\t\t}\n\t\treturn ConditionOutcome.match(ConditionMessage.forCondition(ConditionalOnResource.class)\n\t\t\t.found(\"location\", \"locations\")\n\t\t\t.items(locations));\n\t}\n\n\tprivate void collectValues(List<String> names, List<@Nullable Object> resources) {\n\t\tfor (Object resource : resources) {\n\t\t\tObject[] items = (Object[]) resource;\n\t\t\tif (items != null) {\n\t\t\t\tfor (Object item : items) {\n\t\t\t\t\tnames.add((String) item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnThreadingCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Condition} that checks for a required {@link Threading}.\n *\n * @author Moritz Halbritter\n * @see ConditionalOnThreading\n */\nclass OnThreadingCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnThreading.class.getName());\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tThreading threading = (Threading) attributes.get(\"value\");\n\t\tAssert.state(threading != null, \"'threading' must not be null\");\n\t\treturn getMatchOutcome(context.getEnvironment(), threading);\n\t}\n\n\tprivate ConditionOutcome getMatchOutcome(Environment environment, Threading threading) {\n\t\tString name = threading.name();\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnThreading.class);\n\t\tif (threading.isActive(environment)) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(name));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.didNotFind(name).atAll());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWarDeploymentCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport jakarta.servlet.ServletContext;\n\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * {@link Condition} that checks if the application is running as a traditional war\n * deployment.\n *\n * @author Madhura Bhave\n * @see ConditionalOnWarDeployment\n * @see ConditionalOnNotWarDeployment\n */\nclass OnWarDeploymentCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tboolean required = metadata.isAnnotated(ConditionalOnWarDeployment.class.getName());\n\t\tResourceLoader resourceLoader = context.getResourceLoader();\n\t\tif (resourceLoader instanceof WebApplicationContext applicationContext) {\n\t\t\tServletContext servletContext = applicationContext.getServletContext();\n\t\t\tif (servletContext != null) {\n\t\t\t\treturn new ConditionOutcome(required, \"Application is deployed as a WAR file.\");\n\t\t\t}\n\t\t}\n\t\treturn new ConditionOutcome(!required, ConditionMessage.forCondition(ConditionalOnWarDeployment.class)\n\t\t\t.because(\"the application is not deployed as a WAR file.\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurationMetadata;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebEnvironment;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.context.ConfigurableWebEnvironment;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * {@link Condition} that checks for the presence or absence of\n * {@link WebApplicationContext}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @see ConditionalOnWebApplication\n * @see ConditionalOnNotWebApplication\n */\n@Order(Ordered.HIGHEST_PRECEDENCE + 20)\nclass OnWebApplicationCondition extends FilteringSpringBootCondition {\n\n\tprivate static final String SERVLET_WEB_APPLICATION_CLASS = \"org.springframework.web.context.support.GenericWebApplicationContext\";\n\n\tprivate static final String REACTIVE_WEB_APPLICATION_CLASS = \"org.springframework.web.reactive.HandlerResult\";\n\n\t@Override\n\tprotected @Nullable ConditionOutcome[] getOutcomes(@Nullable String[] autoConfigurationClasses,\n\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t@Nullable ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];\n\t\tfor (int i = 0; i < outcomes.length; i++) {\n\t\t\tString autoConfigurationClass = autoConfigurationClasses[i];\n\t\t\tif (autoConfigurationClass != null) {\n\t\t\t\toutcomes[i] = getOutcome(\n\t\t\t\t\t\tautoConfigurationMetadata.get(autoConfigurationClass, \"ConditionalOnWebApplication\"));\n\t\t\t}\n\t\t}\n\t\treturn outcomes;\n\t}\n\n\tprivate @Nullable ConditionOutcome getOutcome(@Nullable String type) {\n\t\tif (type == null) {\n\t\t\treturn null;\n\t\t}\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class);\n\t\tClassNameFilter missingClassFilter = ClassNameFilter.MISSING;\n\t\tif (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) {\n\t\t\tif (missingClassFilter.matches(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"servlet web application classes\").atAll());\n\t\t\t}\n\t\t}\n\t\tif (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) {\n\t\t\tif (missingClassFilter.matches(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"reactive web application classes\").atAll());\n\t\t\t}\n\t\t}\n\t\tif (missingClassFilter.matches(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())\n\t\t\t\t&& !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"reactive or servlet web application classes\").atAll());\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tboolean required = metadata.isAnnotated(ConditionalOnWebApplication.class.getName());\n\t\tConditionOutcome outcome = isWebApplication(context, metadata, required);\n\t\tif (required && !outcome.isMatch()) {\n\t\t\treturn ConditionOutcome.noMatch(outcome.getConditionMessage());\n\t\t}\n\t\tif (!required && outcome.isMatch()) {\n\t\t\treturn ConditionOutcome.noMatch(outcome.getConditionMessage());\n\t\t}\n\t\treturn ConditionOutcome.match(outcome.getConditionMessage());\n\t}\n\n\tprivate ConditionOutcome isWebApplication(ConditionContext context, AnnotatedTypeMetadata metadata,\n\t\t\tboolean required) {\n\t\treturn switch (deduceType(metadata)) {\n\t\t\tcase SERVLET -> isServletWebApplication(context);\n\t\t\tcase REACTIVE -> isReactiveWebApplication(context);\n\t\t\tdefault -> isAnyWebApplication(context, required);\n\t\t};\n\t}\n\n\tprivate ConditionOutcome isAnyWebApplication(ConditionContext context, boolean required) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class,\n\t\t\t\trequired ? \"(required)\" : \"\");\n\t\tConditionOutcome servletOutcome = isServletWebApplication(context);\n\t\tif (servletOutcome.isMatch() && required) {\n\t\t\treturn new ConditionOutcome(servletOutcome.isMatch(), message.because(servletOutcome.getMessage()));\n\t\t}\n\t\tConditionOutcome reactiveOutcome = isReactiveWebApplication(context);\n\t\tif (reactiveOutcome.isMatch() && required) {\n\t\t\treturn new ConditionOutcome(reactiveOutcome.isMatch(), message.because(reactiveOutcome.getMessage()));\n\t\t}\n\t\treturn new ConditionOutcome(servletOutcome.isMatch() || reactiveOutcome.isMatch(),\n\t\t\t\tmessage.because(servletOutcome.getMessage()).append(\"and\").append(reactiveOutcome.getMessage()));\n\t}\n\n\tprivate ConditionOutcome isServletWebApplication(ConditionContext context) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"\");\n\t\tif (ClassNameFilter.MISSING.matches(SERVLET_WEB_APPLICATION_CLASS, context.getClassLoader())) {\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"servlet web application classes\").atAll());\n\t\t}\n\t\tif (context.getBeanFactory() != null) {\n\t\t\tString[] scopes = context.getBeanFactory().getRegisteredScopeNames();\n\t\t\tif (ObjectUtils.containsElement(scopes, \"session\")) {\n\t\t\t\treturn ConditionOutcome.match(message.foundExactly(\"'session' scope\"));\n\t\t\t}\n\t\t}\n\t\tif (context.getEnvironment() instanceof ConfigurableWebEnvironment) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"ConfigurableWebEnvironment\"));\n\t\t}\n\t\tif (context.getResourceLoader() instanceof WebApplicationContext) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"WebApplicationContext\"));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.because(\"not a servlet web application\"));\n\t}\n\n\tprivate ConditionOutcome isReactiveWebApplication(ConditionContext context) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"\");\n\t\tif (ClassNameFilter.MISSING.matches(REACTIVE_WEB_APPLICATION_CLASS, context.getClassLoader())) {\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"reactive web application classes\").atAll());\n\t\t}\n\t\tif (context.getEnvironment() instanceof ConfigurableReactiveWebEnvironment) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"ConfigurableReactiveWebEnvironment\"));\n\t\t}\n\t\tif (context.getResourceLoader() instanceof ReactiveWebApplicationContext) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"ReactiveWebApplicationContext\"));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.because(\"not a reactive web application\"));\n\t}\n\n\tprivate Type deduceType(AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnWebApplication.class.getName());\n\t\tif (attributes != null) {\n\t\t\tObject type = attributes.get(\"type\");\n\t\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\t\treturn (Type) type;\n\t\t}\n\t\treturn Type.ANY;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ResourceCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link SpringBootCondition} used to check if a resource can be found using a\n * configurable property and optional default location(s).\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 1.3.0\n */\npublic abstract class ResourceCondition extends SpringBootCondition {\n\n\tprivate final String name;\n\n\tprivate final String property;\n\n\tprivate final String[] resourceLocations;\n\n\t/**\n\t * Create a new condition.\n\t * @param name the name of the component\n\t * @param property the configuration property\n\t * @param resourceLocations default location(s) where the configuration file can be\n\t * found if the configuration key is not specified\n\t * @since 2.0.0\n\t */\n\tprotected ResourceCondition(String name, String property, String... resourceLocations) {\n\t\tthis.name = name;\n\t\tthis.property = property;\n\t\tthis.resourceLocations = resourceLocations;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tif (context.getEnvironment().containsProperty(this.property)) {\n\t\t\treturn ConditionOutcome.match(startConditionMessage().foundExactly(\"property \" + this.property));\n\t\t}\n\t\treturn getResourceOutcome(context, metadata);\n\t}\n\n\t/**\n\t * Check if one of the default resource locations actually exists.\n\t * @param context the condition context\n\t * @param metadata the annotation metadata\n\t * @return the condition outcome\n\t */\n\tprotected ConditionOutcome getResourceOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tList<String> found = new ArrayList<>();\n\t\tfor (String location : this.resourceLocations) {\n\t\t\tResource resource = context.getResourceLoader().getResource(location);\n\t\t\tif (resource != null && resource.exists()) {\n\t\t\t\tfound.add(location);\n\t\t\t}\n\t\t}\n\t\tif (found.isEmpty()) {\n\t\t\tConditionMessage message = startConditionMessage().didNotFind(\"resource\", \"resources\")\n\t\t\t\t.items(Style.QUOTE, Arrays.asList(this.resourceLocations));\n\t\t\treturn ConditionOutcome.noMatch(message);\n\t\t}\n\t\tConditionMessage message = startConditionMessage().found(\"resource\", \"resources\").items(Style.QUOTE, found);\n\t\treturn ConditionOutcome.match(message);\n\t}\n\n\tprotected final Builder startConditionMessage() {\n\t\treturn ConditionMessage.forCondition(\"ResourceCondition\", \"(\" + this.name + \")\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/SearchStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\n/**\n * Some named search strategies for beans in the bean factory hierarchy.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\npublic enum SearchStrategy {\n\n\t/**\n\t * Search only the current context.\n\t */\n\tCURRENT,\n\n\t/**\n\t * Search all ancestors, but not the current context.\n\t */\n\tANCESTORS,\n\n\t/**\n\t * Search the entire hierarchy.\n\t */\n\tALL\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/SpringBootCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.ClassMetadata;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base of all {@link Condition} implementations used with Spring Boot. Provides sensible\n * logging to help the user diagnose what classes are loaded.\n *\n * @author Phillip Webb\n * @author Greg Turnquist\n * @since 1.0.0\n */\npublic abstract class SpringBootCondition implements Condition {\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\t@Override\n\tpublic final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tString classOrMethodName = getClassOrMethodName(metadata);\n\t\ttry {\n\t\t\tConditionOutcome outcome = getMatchOutcome(context, metadata);\n\t\t\tlogOutcome(classOrMethodName, outcome);\n\t\t\trecordEvaluation(context, classOrMethodName, outcome);\n\t\t\treturn outcome.isMatch();\n\t\t}\n\t\tcatch (NoClassDefFoundError ex) {\n\t\t\tthrow new IllegalStateException(\"Could not evaluate condition on \" + classOrMethodName + \" due to \"\n\t\t\t\t\t+ ex.getMessage() + \" not found. Make sure your own configuration does not rely on \"\n\t\t\t\t\t+ \"that class. This can also happen if you are \"\n\t\t\t\t\t+ \"@ComponentScanning a springframework package (e.g. if you \"\n\t\t\t\t\t+ \"put a @ComponentScan in the default package by mistake)\", ex);\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow new IllegalStateException(\"Error processing condition on \" + getName(metadata), ex);\n\t\t}\n\t}\n\n\tprivate String getName(AnnotatedTypeMetadata metadata) {\n\t\tif (metadata instanceof AnnotationMetadata annotationMetadata) {\n\t\t\treturn annotationMetadata.getClassName();\n\t\t}\n\t\tif (metadata instanceof MethodMetadata methodMetadata) {\n\t\t\treturn methodMetadata.getDeclaringClassName() + \".\" + methodMetadata.getMethodName();\n\t\t}\n\t\treturn metadata.toString();\n\t}\n\n\tprivate static String getClassOrMethodName(AnnotatedTypeMetadata metadata) {\n\t\tif (metadata instanceof ClassMetadata classMetadata) {\n\t\t\treturn classMetadata.getClassName();\n\t\t}\n\t\tMethodMetadata methodMetadata = (MethodMetadata) metadata;\n\t\treturn methodMetadata.getDeclaringClassName() + \"#\" + methodMetadata.getMethodName();\n\t}\n\n\tprotected final void logOutcome(String classOrMethodName, ConditionOutcome outcome) {\n\t\tif (this.logger.isTraceEnabled()) {\n\t\t\tthis.logger.trace(getLogMessage(classOrMethodName, outcome));\n\t\t}\n\t}\n\n\tprivate StringBuilder getLogMessage(String classOrMethodName, ConditionOutcome outcome) {\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(\"Condition \");\n\t\tmessage.append(ClassUtils.getShortName(getClass()));\n\t\tmessage.append(\" on \");\n\t\tmessage.append(classOrMethodName);\n\t\tmessage.append(outcome.isMatch() ? \" matched\" : \" did not match\");\n\t\tif (StringUtils.hasLength(outcome.getMessage())) {\n\t\t\tmessage.append(\" due to \");\n\t\t\tmessage.append(outcome.getMessage());\n\t\t}\n\t\treturn message;\n\t}\n\n\tprivate void recordEvaluation(ConditionContext context, String classOrMethodName, ConditionOutcome outcome) {\n\t\tif (context.getBeanFactory() != null) {\n\t\t\tConditionEvaluationReport.get(context.getBeanFactory())\n\t\t\t\t.recordConditionEvaluation(classOrMethodName, this, outcome);\n\t\t}\n\t}\n\n\t/**\n\t * Determine the outcome of the match along with suitable log output.\n\t * @param context the condition context\n\t * @param metadata the annotation metadata\n\t * @return the condition outcome\n\t */\n\tpublic abstract ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata);\n\n\t/**\n\t * Return true if any of the specified conditions match.\n\t * @param context the context\n\t * @param metadata the annotation meta-data\n\t * @param conditions conditions to test\n\t * @return {@code true} if any condition matches.\n\t */\n\tprotected final boolean anyMatches(ConditionContext context, AnnotatedTypeMetadata metadata,\n\t\t\tCondition... conditions) {\n\t\tfor (Condition condition : conditions) {\n\t\t\tif (matches(context, metadata, condition)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return true if any of the specified condition matches.\n\t * @param context the context\n\t * @param metadata the annotation meta-data\n\t * @param condition condition to test\n\t * @return {@code true} if the condition matches.\n\t */\n\tprotected final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata, Condition condition) {\n\t\tif (condition instanceof SpringBootCondition springBootCondition) {\n\t\t\treturn springBootCondition.getMatchOutcome(context, metadata).isMatch();\n\t\t}\n\t\treturn condition.matches(context, metadata);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * {@code @Condition} annotations and supporting classes.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/container/ContainerImageMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.container;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.core.AttributeAccessor;\n\n/**\n * Metadata about a container image that can be added to an {@link AttributeAccessor}.\n * Primarily designed to be attached to {@link BeanDefinition BeanDefinitions} created in\n * support of Testcontainers or Docker Compose.\n *\n * @param imageName the container image name or {@code null} if the image name is not yet\n * known\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic record ContainerImageMetadata(@Nullable String imageName) {\n\n\tstatic final String NAME = ContainerImageMetadata.class.getName();\n\n\t/**\n\t * Add this container image metadata to the given attributes.\n\t * @param attributes the attributes to add the metadata to\n\t */\n\tpublic void addTo(@Nullable AttributeAccessor attributes) {\n\t\tif (attributes != null) {\n\t\t\tattributes.setAttribute(NAME, this);\n\t\t}\n\t}\n\n\t/**\n\t * Return {@code true} if {@link ContainerImageMetadata} has been added to the given\n\t * attributes.\n\t * @param attributes the attributes to check\n\t * @return if metadata is present\n\t */\n\tpublic static boolean isPresent(@Nullable AttributeAccessor attributes) {\n\t\treturn getFrom(attributes) != null;\n\t}\n\n\t/**\n\t * Return {@link ContainerImageMetadata} from the given attributes or {@code null} if\n\t * no metadata has been added.\n\t * @param attributes the attributes\n\t * @return the metadata or {@code null}\n\t */\n\tpublic static @Nullable ContainerImageMetadata getFrom(@Nullable AttributeAccessor attributes) {\n\t\treturn (attributes != null) ? (ContainerImageMetadata) attributes.getAttribute(NAME) : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/container/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes related to auto-configuration involving containers.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.container;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link ConfigurationProperties @ConfigurationProperties} beans. Automatically binds and\n * validates any bean annotated with {@code @ConfigurationProperties}.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n * @see EnableConfigurationProperties\n * @see ConfigurationProperties\n */\n@AutoConfiguration\n@EnableConfigurationProperties\npublic final class ConfigurationPropertiesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/LifecycleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.DefaultLifecycleProcessor;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} relating to the application\n * context's lifecycle.\n *\n * @author Andy Wilkinson\n * @since 2.3.0\n */\n@AutoConfiguration\n@EnableConfigurationProperties(LifecycleProperties.class)\npublic final class LifecycleAutoConfiguration {\n\n\t@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)\n\t@ConditionalOnMissingBean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME,\n\t\t\tsearch = SearchStrategy.CURRENT)\n\tDefaultLifecycleProcessor defaultLifecycleProcessor(LifecycleProperties properties) {\n\t\tDefaultLifecycleProcessor lifecycleProcessor = new DefaultLifecycleProcessor();\n\t\tlifecycleProcessor.setTimeoutPerShutdownPhase(properties.getTimeoutPerShutdownPhase().toMillis());\n\t\treturn lifecycleProcessor;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/LifecycleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for lifecycle processing.\n *\n * @author Andy Wilkinson\n * @since 2.3.0\n */\n@ConfigurationProperties(\"spring.lifecycle\")\npublic class LifecycleProperties {\n\n\t/**\n\t * Timeout for the shutdown of any phase (group of SmartLifecycle beans with the same\n\t * 'phase' value).\n\t */\n\tprivate Duration timeoutPerShutdownPhase = Duration.ofSeconds(30);\n\n\tpublic Duration getTimeoutPerShutdownPhase() {\n\t\treturn this.timeoutPerShutdownPhase;\n\t}\n\n\tpublic void setTimeoutPerShutdownPhase(Duration timeoutPerShutdownPhase) {\n\t\tthis.timeoutPerShutdownPhase = timeoutPerShutdownPhase;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.MessageSourceRuntimeHints;\nimport org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.ResourceBundleCondition;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.MessageSource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.ResourceBundleMessageSource;\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ConcurrentReferenceHashMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Marc Becker\n * @author Misagh Moayyed\n * @since 1.5.0\n */\n@AutoConfiguration\n@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)\n@Conditional(ResourceBundleCondition.class)\n@EnableConfigurationProperties(MessageSourceProperties.class)\n@ImportRuntimeHints(MessageSourceRuntimeHints.class)\npublic final class MessageSourceAutoConfiguration {\n\n\tprivate static final Resource[] NO_RESOURCES = {};\n\n\t@Bean\n\tMessageSource messageSource(MessageSourceProperties properties) {\n\t\tResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();\n\t\tif (!CollectionUtils.isEmpty(properties.getBasename())) {\n\t\t\tmessageSource.setBasenames(properties.getBasename().toArray(new String[0]));\n\t\t}\n\t\tif (properties.getEncoding() != null) {\n\t\t\tmessageSource.setDefaultEncoding(properties.getEncoding().name());\n\t\t}\n\t\tmessageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());\n\t\tDuration cacheDuration = properties.getCacheDuration();\n\t\tif (cacheDuration != null) {\n\t\t\tmessageSource.setCacheMillis(cacheDuration.toMillis());\n\t\t}\n\t\tmessageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());\n\t\tmessageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());\n\t\tmessageSource.setCommonMessages(loadCommonMessages(properties.getCommonMessages()));\n\t\treturn messageSource;\n\t}\n\n\tprivate @Nullable Properties loadCommonMessages(@Nullable List<Resource> resources) {\n\t\tif (CollectionUtils.isEmpty(resources)) {\n\t\t\treturn null;\n\t\t}\n\t\tProperties properties = CollectionFactory.createSortedProperties(false);\n\t\tfor (Resource resource : resources) {\n\t\t\ttry {\n\t\t\t\tPropertiesLoaderUtils.fillProperties(properties, resource);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(\"Failed to load common messages from '%s'\".formatted(resource), ex);\n\t\t\t}\n\t\t}\n\t\treturn properties;\n\t}\n\n\tprotected static class ResourceBundleCondition extends SpringBootCondition {\n\n\t\tprivate static final ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap<>();\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tString basename = context.getEnvironment().getProperty(\"spring.messages.basename\", \"messages\");\n\t\t\tConditionOutcome outcome = cache.get(basename);\n\t\t\tif (outcome == null) {\n\t\t\t\toutcome = getMatchOutcomeForBasename(context, basename);\n\t\t\t\tcache.put(basename, outcome);\n\t\t\t}\n\t\t\treturn outcome;\n\t\t}\n\n\t\tprivate ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"ResourceBundle\");\n\t\t\tfor (String name : StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename))) {\n\t\t\t\tfor (Resource resource : getResources(context.getClassLoader(), name)) {\n\t\t\t\t\tif (resource.exists()) {\n\t\t\t\t\t\treturn ConditionOutcome.match(message.found(\"bundle\").items(resource));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"bundle with basename \" + basename).atAll());\n\t\t}\n\n\t\tprivate Resource[] getResources(@Nullable ClassLoader classLoader, String name) {\n\t\t\tString target = name.replace('.', '/');\n\t\t\ttry {\n\t\t\t\treturn new PathMatchingResourcePatternResolver(classLoader)\n\t\t\t\t\t.getResources(\"classpath*:\" + target + \".properties\");\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn NO_RESOURCES;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class MessageSourceRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"messages.properties\").registerPattern(\"messages_*.properties\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/MessageSourceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.core.io.Resource;\n\n/**\n * Configuration properties for Message Source.\n *\n * @author Stephane Nicoll\n * @author Kedar Joshi\n * @author Misagh Moayyed\n * @since 2.0.0\n */\n@ConfigurationProperties(\"spring.messages\")\npublic class MessageSourceProperties {\n\n\t/**\n\t * List of basenames (essentially a fully-qualified classpath location), each\n\t * following the ResourceBundle convention with relaxed support for slash based\n\t * locations. If it doesn't contain a package qualifier (such as \"org.mypackage\"), it\n\t * will be resolved from the classpath root.\n\t */\n\tprivate List<String> basename = new ArrayList<>(List.of(\"messages\"));\n\n\t/**\n\t * List of locale-independent property file resources containing common messages.\n\t */\n\tprivate @Nullable List<Resource> commonMessages;\n\n\t/**\n\t * Message bundles encoding.\n\t */\n\tprivate Charset encoding = StandardCharsets.UTF_8;\n\n\t/**\n\t * Loaded resource bundle files cache duration. When not set, bundles are cached\n\t * forever. If a duration suffix is not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate @Nullable Duration cacheDuration;\n\n\t/**\n\t * Whether to fall back to the system Locale if no files for a specific Locale have\n\t * been found. if this is turned off, the only fallback will be the default file (e.g.\n\t * \"messages.properties\" for basename \"messages\").\n\t */\n\tprivate boolean fallbackToSystemLocale = true;\n\n\t/**\n\t * Whether to always apply the MessageFormat rules, parsing even messages without\n\t * arguments.\n\t */\n\tprivate boolean alwaysUseMessageFormat;\n\n\t/**\n\t * Whether to use the message code as the default message instead of throwing a\n\t * \"NoSuchMessageException\". Recommended during development only.\n\t */\n\tprivate boolean useCodeAsDefaultMessage;\n\n\tpublic List<String> getBasename() {\n\t\treturn this.basename;\n\t}\n\n\tpublic void setBasename(List<String> basename) {\n\t\tthis.basename = basename;\n\t}\n\n\tpublic Charset getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\tpublic void setEncoding(Charset encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\tpublic @Nullable Duration getCacheDuration() {\n\t\treturn this.cacheDuration;\n\t}\n\n\tpublic void setCacheDuration(@Nullable Duration cacheDuration) {\n\t\tthis.cacheDuration = cacheDuration;\n\t}\n\n\tpublic boolean isFallbackToSystemLocale() {\n\t\treturn this.fallbackToSystemLocale;\n\t}\n\n\tpublic void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {\n\t\tthis.fallbackToSystemLocale = fallbackToSystemLocale;\n\t}\n\n\tpublic boolean isAlwaysUseMessageFormat() {\n\t\treturn this.alwaysUseMessageFormat;\n\t}\n\n\tpublic void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) {\n\t\tthis.alwaysUseMessageFormat = alwaysUseMessageFormat;\n\t}\n\n\tpublic boolean isUseCodeAsDefaultMessage() {\n\t\treturn this.useCodeAsDefaultMessage;\n\t}\n\n\tpublic void setUseCodeAsDefaultMessage(boolean useCodeAsDefaultMessage) {\n\t\tthis.useCodeAsDefaultMessage = useCodeAsDefaultMessage;\n\t}\n\n\tpublic @Nullable List<Resource> getCommonMessages() {\n\t\treturn this.commonMessages;\n\t}\n\n\tpublic void setCommonMessages(@Nullable List<Resource> commonMessages) {\n\t\tthis.commonMessages = commonMessages;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/PropertyPlaceholderAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link PropertySourcesPlaceholderConfigurer}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @since 1.5.0\n */\n@AutoConfiguration\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)\npublic final class PropertyPlaceholderAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)\n\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for the Spring context.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/AbstractRepositoryConfigurationSourceSupport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.data;\n\nimport java.lang.annotation.Annotation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;\nimport org.springframework.data.repository.config.BootstrapMode;\nimport org.springframework.data.repository.config.RepositoryConfigurationDelegate;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\nimport org.springframework.data.util.Streamable;\n\n/**\n * Base {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data\n * Repositories.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Oliver Gierke\n * @since 1.0.0\n */\npublic abstract class AbstractRepositoryConfigurationSourceSupport\n\t\timplements ImportBeanDefinitionRegistrar, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ResourceLoader resourceLoader;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanFactory beanFactory;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Environment environment;\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,\n\t\t\t@Nullable BeanNameGenerator importBeanNameGenerator) {\n\t\tRepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(\n\t\t\t\tgetConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment);\n\t\tdelegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension());\n\t}\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tregisterBeanDefinitions(importingClassMetadata, registry, null);\n\t}\n\n\tprivate AnnotationRepositoryConfigurationSource getConfigurationSource(BeanDefinitionRegistry registry,\n\t\t\t@Nullable BeanNameGenerator importBeanNameGenerator) {\n\t\tAnnotationMetadata metadata = AnnotationMetadata.introspect(getConfiguration());\n\t\treturn new AutoConfiguredAnnotationRepositoryConfigurationSource(metadata, getAnnotation(), this.resourceLoader,\n\t\t\t\tthis.environment, registry, importBeanNameGenerator) {\n\t\t};\n\t}\n\n\tprotected Streamable<String> getBasePackages() {\n\t\treturn Streamable.of(AutoConfigurationPackages.get(this.beanFactory));\n\t}\n\n\t/**\n\t * The Spring Data annotation used to enable the particular repository support.\n\t * @return the annotation class\n\t */\n\tprotected abstract Class<? extends Annotation> getAnnotation();\n\n\t/**\n\t * The configuration class that will be used by Spring Boot as a template.\n\t * @return the configuration class\n\t */\n\tprotected abstract Class<?> getConfiguration();\n\n\t/**\n\t * The {@link RepositoryConfigurationExtension} for the particular repository support.\n\t * @return the repository configuration extension\n\t */\n\tprotected abstract RepositoryConfigurationExtension getRepositoryConfigurationExtension();\n\n\t/**\n\t * The {@link BootstrapMode} for the particular repository support. Defaults to\n\t * {@link BootstrapMode#DEFAULT}.\n\t * @return the bootstrap mode\n\t */\n\tprotected BootstrapMode getBootstrapMode() {\n\t\treturn BootstrapMode.DEFAULT;\n\t}\n\n\t@Override\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic void setEnvironment(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * An auto-configured {@link AnnotationRepositoryConfigurationSource}.\n\t */\n\tprivate class AutoConfiguredAnnotationRepositoryConfigurationSource\n\t\t\textends AnnotationRepositoryConfigurationSource {\n\n\t\tAutoConfiguredAnnotationRepositoryConfigurationSource(AnnotationMetadata metadata,\n\t\t\t\tClass<? extends Annotation> annotation, ResourceLoader resourceLoader, Environment environment,\n\t\t\t\tBeanDefinitionRegistry registry, @Nullable BeanNameGenerator generator) {\n\t\t\tsuper(metadata, annotation, resourceLoader, environment, registry, generator);\n\t\t}\n\n\t\t@Override\n\t\tpublic Streamable<String> getBasePackages() {\n\t\t\treturn AbstractRepositoryConfigurationSourceSupport.this.getBasePackages();\n\t\t}\n\n\t\t@Override\n\t\tpublic BootstrapMode getBootstrapMode() {\n\t\t\treturn AbstractRepositoryConfigurationSourceSupport.this.getBootstrapMode();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.data;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when a particular type of Spring\n * Data repository has been enabled.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnRepositoryTypeCondition.class)\npublic @interface ConditionalOnRepositoryType {\n\n\t/**\n\t * The name of the store that backs the repositories.\n\t * @return the store\n\t */\n\tString store();\n\n\t/**\n\t * The required repository type.\n\t * @return the required repository type\n\t */\n\tRepositoryType type();\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/OnRepositoryTypeCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.data;\n\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link SpringBootCondition} for controlling what type of Spring Data repositories are\n * auto-configured.\n *\n * @author Andy Wilkinson\n */\nclass OnRepositoryTypeCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnRepositoryType.class.getName(), true);\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tString store = (String) attributes.get(\"store\");\n\t\tAssert.state(store != null, \"'store' must not be null\");\n\t\tRepositoryType configuredType = getTypeProperty(context.getEnvironment(), store);\n\t\tRepositoryType requiredType = (RepositoryType) attributes.get(\"type\");\n\t\tAssert.state(requiredType != null, \"'requiredType' must not be null\");\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnRepositoryType.class);\n\t\tif (configuredType == requiredType || configuredType == RepositoryType.AUTO) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.match(message.because(\"configured type of '\" + configuredType.name() + \"' matched required type\"));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.because(\"configured type (\" + configuredType.name()\n\t\t\t\t+ \") did not match required type (\" + requiredType.name() + \")\"));\n\t}\n\n\tprivate RepositoryType getTypeProperty(Environment environment, String store) {\n\t\treturn RepositoryType\n\t\t\t.valueOf(environment.getProperty(String.format(\"spring.data.%s.repositories.type\", store), \"auto\")\n\t\t\t\t.toUpperCase(Locale.ENGLISH));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/RepositoryType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.data;\n\n/**\n * Type of Spring Data repositories to enable.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic enum RepositoryType {\n\n\t/**\n\t * Enables all repository types automatically based on their availability.\n\t */\n\tAUTO,\n\n\t/**\n\t * Enables imperative repositories.\n\t */\n\tIMPERATIVE,\n\n\t/**\n\t * Enables no repositories.\n\t */\n\tNONE,\n\n\t/**\n\t * Enables reactive repositories.\n\t */\n\tREACTIVE\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration base classes for Spring Data.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.data;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.diagnostics.analyzer;\n\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.InjectionPoint;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.UnsatisfiedDependencyException;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.analyzer.AbstractInjectionFailureAnalyzer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * An {@link AbstractInjectionFailureAnalyzer} that performs analysis of failures caused\n * by a {@link NoSuchBeanDefinitionException}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyzer<NoSuchBeanDefinitionException> {\n\n\tprivate final ConfigurableListableBeanFactory beanFactory;\n\n\tprivate final MetadataReaderFactory metadataReaderFactory;\n\n\tprivate final ConditionEvaluationReport report;\n\n\tNoSuchBeanDefinitionFailureAnalyzer(BeanFactory beanFactory) {\n\t\tAssert.isTrue(beanFactory instanceof ConfigurableListableBeanFactory,\n\t\t\t\t\"'beanFactory' must be a ConfigurableListableBeanFactory\");\n\t\tthis.beanFactory = (ConfigurableListableBeanFactory) beanFactory;\n\t\tthis.metadataReaderFactory = new CachingMetadataReaderFactory(this.beanFactory.getBeanClassLoader());\n\t\t// Get early as won't be accessible once context has failed to start\n\t\tthis.report = ConditionEvaluationReport.get(this.beanFactory);\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause,\n\t\t\t@Nullable String description) {\n\t\tif (cause.getNumberOfBeansFound() != 0) {\n\t\t\treturn null;\n\t\t}\n\t\tList<AutoConfigurationResult> autoConfigurationResults = getAutoConfigurationResults(cause);\n\t\tList<UserConfigurationResult> userConfigurationResults = getUserConfigurationResults(cause);\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(String.format(\"%s required %s that could not be found.%n\",\n\t\t\t\t(description != null) ? description : \"A component\", getBeanDescription(cause)));\n\t\tInjectionPoint injectionPoint = findInjectionPoint(rootFailure);\n\t\tif (injectionPoint != null) {\n\t\t\tAnnotation[] injectionAnnotations = injectionPoint.getAnnotations();\n\t\t\tif (injectionAnnotations.length > 0) {\n\t\t\t\tmessage.append(String.format(\"%nThe injection point has the following annotations:%n\"));\n\t\t\t\tfor (Annotation injectionAnnotation : injectionAnnotations) {\n\t\t\t\t\tmessage.append(String.format(\"\\t- %s%n\", injectionAnnotation));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!autoConfigurationResults.isEmpty() || !userConfigurationResults.isEmpty()) {\n\t\t\tmessage.append(String.format(\"%nThe following candidates were found but could not be injected:%n\"));\n\t\t\tfor (AutoConfigurationResult result : autoConfigurationResults) {\n\t\t\t\tmessage.append(String.format(\"\\t- %s%n\", result));\n\t\t\t}\n\t\t\tfor (UserConfigurationResult result : userConfigurationResults) {\n\t\t\t\tmessage.append(String.format(\"\\t- %s%n\", result));\n\t\t\t}\n\t\t}\n\t\tString action = String.format(\"Consider %s %s in your configuration.\",\n\t\t\t\t(!autoConfigurationResults.isEmpty() || !userConfigurationResults.isEmpty())\n\t\t\t\t\t\t? \"revisiting the entries above or defining\" : \"defining\",\n\t\t\t\tgetBeanDescription(cause));\n\t\treturn new FailureAnalysis(message.toString(), action, cause);\n\t}\n\n\tprivate String getBeanDescription(NoSuchBeanDefinitionException cause) {\n\t\tif (cause.getResolvableType() != null) {\n\t\t\tClass<?> type = extractBeanType(cause.getResolvableType());\n\t\t\treturn \"a bean of type '\" + type.getName() + \"'\";\n\t\t}\n\t\treturn \"a bean named '\" + cause.getBeanName() + \"'\";\n\t}\n\n\tprivate Class<?> extractBeanType(ResolvableType resolvableType) {\n\t\tClass<?> rawClass = resolvableType.getRawClass();\n\t\tAssert.state(rawClass != null, \"'rawClass' must not be null\");\n\t\treturn rawClass;\n\t}\n\n\tprivate List<AutoConfigurationResult> getAutoConfigurationResults(NoSuchBeanDefinitionException cause) {\n\t\tList<AutoConfigurationResult> results = new ArrayList<>();\n\t\tcollectReportedConditionOutcomes(cause, results);\n\t\tcollectExcludedAutoConfiguration(cause, results);\n\t\treturn results;\n\t}\n\n\tprivate List<UserConfigurationResult> getUserConfigurationResults(NoSuchBeanDefinitionException cause) {\n\t\tResolvableType type = cause.getResolvableType();\n\t\tif (type == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tString[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, type);\n\t\treturn Arrays.stream(beanNames)\n\t\t\t.map((beanName) -> new UserConfigurationResult(getFactoryMethodMetadata(beanName),\n\t\t\t\t\tthis.beanFactory.getBean(beanName).equals(null)))\n\t\t\t.toList();\n\t}\n\n\tprivate @Nullable MethodMetadata getFactoryMethodMetadata(String beanName) {\n\t\tBeanDefinition beanDefinition = this.beanFactory.getBeanDefinition(beanName);\n\t\tif (beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {\n\t\t\treturn annotatedBeanDefinition.getFactoryMethodMetadata();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void collectReportedConditionOutcomes(NoSuchBeanDefinitionException cause,\n\t\t\tList<AutoConfigurationResult> results) {\n\t\tthis.report.getConditionAndOutcomesBySource()\n\t\t\t.forEach((source, sourceOutcomes) -> collectReportedConditionOutcomes(cause, new Source(source),\n\t\t\t\t\tsourceOutcomes, results));\n\t}\n\n\tprivate void collectReportedConditionOutcomes(NoSuchBeanDefinitionException cause, Source source,\n\t\t\tConditionAndOutcomes sourceOutcomes, List<AutoConfigurationResult> results) {\n\t\tif (sourceOutcomes.isFullMatch()) {\n\t\t\treturn;\n\t\t}\n\t\tBeanMethods methods = new BeanMethods(source, cause);\n\t\tfor (ConditionAndOutcome conditionAndOutcome : sourceOutcomes) {\n\t\t\tif (!conditionAndOutcome.getOutcome().isMatch()) {\n\t\t\t\tfor (MethodMetadata method : methods) {\n\t\t\t\t\tresults.add(new AutoConfigurationResult(method, conditionAndOutcome.getOutcome()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void collectExcludedAutoConfiguration(NoSuchBeanDefinitionException cause,\n\t\t\tList<AutoConfigurationResult> results) {\n\t\tfor (String excludedClass : this.report.getExclusions()) {\n\t\t\tSource source = new Source(excludedClass);\n\t\t\tBeanMethods methods = new BeanMethods(source, cause);\n\t\t\tfor (MethodMetadata method : methods) {\n\t\t\t\tString message = String.format(\"auto-configuration '%s' was excluded\",\n\t\t\t\t\t\tClassUtils.getShortName(excludedClass));\n\t\t\t\tresults.add(new AutoConfigurationResult(method, new ConditionOutcome(false, message)));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate @Nullable InjectionPoint findInjectionPoint(Throwable failure) {\n\t\tUnsatisfiedDependencyException unsatisfiedDependencyException = findCause(failure,\n\t\t\t\tUnsatisfiedDependencyException.class);\n\t\tif (unsatisfiedDependencyException == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn unsatisfiedDependencyException.getInjectionPoint();\n\t}\n\n\tprivate static class Source {\n\n\t\tprivate final String className;\n\n\t\tprivate final @Nullable String methodName;\n\n\t\tSource(String source) {\n\t\t\tString[] tokens = source.split(\"#\");\n\t\t\tthis.className = (tokens.length > 1) ? tokens[0] : source;\n\t\t\tthis.methodName = (tokens.length != 2) ? null : tokens[1];\n\t\t}\n\n\t\tString getClassName() {\n\t\t\treturn this.className;\n\t\t}\n\n\t\t@Nullable String getMethodName() {\n\t\t\treturn this.methodName;\n\t\t}\n\n\t}\n\n\tprivate class BeanMethods implements Iterable<MethodMetadata> {\n\n\t\tprivate final List<MethodMetadata> methods;\n\n\t\tBeanMethods(Source source, NoSuchBeanDefinitionException cause) {\n\t\t\tthis.methods = findBeanMethods(source, cause);\n\t\t}\n\n\t\tprivate List<MethodMetadata> findBeanMethods(Source source, NoSuchBeanDefinitionException cause) {\n\t\t\ttry {\n\t\t\t\tMetadataReader classMetadata = NoSuchBeanDefinitionFailureAnalyzer.this.metadataReaderFactory\n\t\t\t\t\t.getMetadataReader(source.getClassName());\n\t\t\t\tSet<MethodMetadata> candidates = classMetadata.getAnnotationMetadata()\n\t\t\t\t\t.getAnnotatedMethods(Bean.class.getName());\n\t\t\t\tList<MethodMetadata> result = new ArrayList<>();\n\t\t\t\tfor (MethodMetadata candidate : candidates) {\n\t\t\t\t\tif (isMatch(candidate, source, cause)) {\n\t\t\t\t\t\tresult.add(candidate);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn Collections.unmodifiableList(result);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isMatch(MethodMetadata candidate, Source source, NoSuchBeanDefinitionException cause) {\n\t\t\tif (source.getMethodName() != null && !source.getMethodName().equals(candidate.getMethodName())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tString name = cause.getBeanName();\n\t\t\tResolvableType resolvableType = cause.getResolvableType();\n\t\t\treturn ((name != null && hasName(candidate, name))\n\t\t\t\t\t|| (resolvableType != null && hasType(candidate, extractBeanType(resolvableType))));\n\t\t}\n\n\t\tprivate boolean hasName(MethodMetadata methodMetadata, String name) {\n\t\t\tMap<String, @Nullable Object> attributes = methodMetadata.getAnnotationAttributes(Bean.class.getName());\n\t\t\tString[] candidates = (attributes != null) ? (String[]) attributes.get(\"name\") : null;\n\t\t\tif (candidates != null) {\n\t\t\t\tfor (String candidate : candidates) {\n\t\t\t\t\tif (candidate.equals(name)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn methodMetadata.getMethodName().equals(name);\n\t\t}\n\n\t\tprivate boolean hasType(MethodMetadata candidate, Class<?> type) {\n\t\t\tString returnTypeName = candidate.getReturnTypeName();\n\t\t\tif (type.getName().equals(returnTypeName)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tClass<?> returnType = ClassUtils.forName(returnTypeName,\n\t\t\t\t\t\tNoSuchBeanDefinitionFailureAnalyzer.this.beanFactory.getBeanClassLoader());\n\t\t\t\treturn type.isAssignableFrom(returnType);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<MethodMetadata> iterator() {\n\t\t\treturn this.methods.iterator();\n\t\t}\n\n\t}\n\n\tprivate static class AutoConfigurationResult {\n\n\t\tprivate final MethodMetadata methodMetadata;\n\n\t\tprivate final ConditionOutcome conditionOutcome;\n\n\t\tAutoConfigurationResult(MethodMetadata methodMetadata, ConditionOutcome conditionOutcome) {\n\t\t\tthis.methodMetadata = methodMetadata;\n\t\t\tthis.conditionOutcome = conditionOutcome;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"Bean method '%s' in '%s' not loaded because %s\", this.methodMetadata.getMethodName(),\n\t\t\t\t\tClassUtils.getShortName(this.methodMetadata.getDeclaringClassName()),\n\t\t\t\t\tthis.conditionOutcome.getMessage());\n\t\t}\n\n\t}\n\n\tprivate static class UserConfigurationResult {\n\n\t\tprivate final @Nullable MethodMetadata methodMetadata;\n\n\t\tprivate final boolean nullBean;\n\n\t\tUserConfigurationResult(@Nullable MethodMetadata methodMetadata, boolean nullBean) {\n\t\t\tthis.methodMetadata = methodMetadata;\n\t\t\tthis.nullBean = nullBean;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tStringBuilder sb = new StringBuilder(\"User-defined bean\");\n\t\t\tif (this.methodMetadata != null) {\n\t\t\t\tsb.append(String.format(\" method '%s' in '%s'\", this.methodMetadata.getMethodName(),\n\t\t\t\t\t\tClassUtils.getShortName(this.methodMetadata.getDeclaringClassName())));\n\t\t\t}\n\t\t\tif (this.nullBean) {\n\t\t\t\tsb.append(\" ignored as the bean value is null\");\n\t\t\t}\n\t\t\treturn sb.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Internal {@link org.springframework.boot.diagnostics.FailureAnalyzer} implementations\n * related to auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.diagnostics.analyzer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.info;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnResource;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.info.BuildProperties;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.EncodedResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for various project information.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 1.4.0\n */\n@AutoConfiguration\n@EnableConfigurationProperties(ProjectInfoProperties.class)\npublic final class ProjectInfoAutoConfiguration {\n\n\tprivate final ProjectInfoProperties properties;\n\n\tProjectInfoAutoConfiguration(ProjectInfoProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Conditional(GitResourceAvailableCondition.class)\n\t@ConditionalOnMissingBean\n\t@Bean\n\tGitProperties gitProperties() throws Exception {\n\t\treturn new GitProperties(\n\t\t\t\tloadFrom(this.properties.getGit().getLocation(), \"git\", this.properties.getGit().getEncoding()));\n\t}\n\n\t@ConditionalOnResource(resources = \"${spring.info.build.location:classpath:META-INF/build-info.properties}\")\n\t@ConditionalOnMissingBean\n\t@Bean\n\tBuildProperties buildProperties() throws Exception {\n\t\treturn new BuildProperties(\n\t\t\t\tloadFrom(this.properties.getBuild().getLocation(), \"build\", this.properties.getBuild().getEncoding()));\n\t}\n\n\tprivate Properties loadFrom(Resource location, String prefix, Charset encoding) throws IOException {\n\t\tprefix = prefix.endsWith(\".\") ? prefix : prefix + \".\";\n\t\tProperties source = loadSource(location, encoding);\n\t\tProperties target = new Properties();\n\t\tfor (String key : source.stringPropertyNames()) {\n\t\t\tif (key.startsWith(prefix)) {\n\t\t\t\ttarget.put(key.substring(prefix.length()), source.get(key));\n\t\t\t}\n\t\t}\n\t\treturn target;\n\t}\n\n\tprivate Properties loadSource(Resource location, @Nullable Charset encoding) throws IOException {\n\t\tif (encoding != null) {\n\t\t\treturn PropertiesLoaderUtils.loadProperties(new EncodedResource(location, encoding));\n\t\t}\n\t\treturn PropertiesLoaderUtils.loadProperties(location);\n\t}\n\n\tstatic class GitResourceAvailableCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tResourceLoader loader = context.getResourceLoader();\n\t\t\tEnvironment environment = context.getEnvironment();\n\t\t\tString location = environment.getProperty(\"spring.info.git.location\");\n\t\t\tif (location == null) {\n\t\t\t\tlocation = \"classpath:git.properties\";\n\t\t\t}\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"GitResource\");\n\t\t\tif (loader.getResource(location).exists()) {\n\t\t\t\treturn ConditionOutcome.match(message.found(\"git info at\").items(location));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"git info at\").items(location));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/ProjectInfoProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.info;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\n\n/**\n * Configuration properties for project information.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@ConfigurationProperties(\"spring.info\")\npublic class ProjectInfoProperties {\n\n\tprivate final Build build = new Build();\n\n\tprivate final Git git = new Git();\n\n\tpublic Build getBuild() {\n\t\treturn this.build;\n\t}\n\n\tpublic Git getGit() {\n\t\treturn this.git;\n\t}\n\n\t/**\n\t * Build specific info properties.\n\t */\n\tpublic static class Build {\n\n\t\t/**\n\t\t * Location of the generated build-info.properties file.\n\t\t */\n\t\tprivate Resource location = new ClassPathResource(\"META-INF/build-info.properties\");\n\n\t\t/**\n\t\t * File encoding.\n\t\t */\n\t\tprivate Charset encoding = StandardCharsets.UTF_8;\n\n\t\tpublic Resource getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\tpublic void setLocation(Resource location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tpublic Charset getEncoding() {\n\t\t\treturn this.encoding;\n\t\t}\n\n\t\tpublic void setEncoding(Charset encoding) {\n\t\t\tthis.encoding = encoding;\n\t\t}\n\n\t}\n\n\t/**\n\t * Git specific info properties.\n\t */\n\tpublic static class Git {\n\n\t\t/**\n\t\t * Location of the generated git.properties file.\n\t\t */\n\t\tprivate Resource location = new ClassPathResource(\"git.properties\");\n\n\t\t/**\n\t\t * File encoding.\n\t\t */\n\t\tprivate Charset encoding = StandardCharsets.UTF_8;\n\n\t\tpublic Resource getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\tpublic void setLocation(Resource location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tpublic Charset getEncoding() {\n\t\t\treturn this.encoding;\n\t\t}\n\n\t\tpublic void setEncoding(Charset encoding) {\n\t\t\tthis.encoding = encoding;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/info/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for project information.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.info;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jmx;\n\nimport javax.management.MBeanServer;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.EnableMBeanExport;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jmx.export.MBeanExporter;\nimport org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;\nimport org.springframework.jmx.export.annotation.AnnotationMBeanExporter;\nimport org.springframework.jmx.export.naming.ObjectNamingStrategy;\nimport org.springframework.jmx.support.MBeanServerFactoryBean;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to enable/disable Spring's\n * {@link EnableMBeanExport @EnableMBeanExport} mechanism based on configuration\n * properties.\n * <p>\n * To enable auto export of annotation beans set {@code spring.jmx.enabled: true}.\n *\n * @author Christian Dupuis\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author Scott Frederick\n * @since 1.0.0\n */\n@AutoConfiguration\n@EnableConfigurationProperties(JmxProperties.class)\n@ConditionalOnClass({ MBeanExporter.class })\n@ConditionalOnBooleanProperty(\"spring.jmx.enabled\")\npublic final class JmxAutoConfiguration {\n\n\tprivate final JmxProperties properties;\n\n\tJmxAutoConfiguration(JmxProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@Primary\n\t@ConditionalOnMissingBean(value = MBeanExporter.class, search = SearchStrategy.CURRENT)\n\tAnnotationMBeanExporter mbeanExporter(ObjectNamingStrategy namingStrategy, BeanFactory beanFactory) {\n\t\tAnnotationMBeanExporter exporter = new AnnotationMBeanExporter();\n\t\texporter.setRegistrationPolicy(this.properties.getRegistrationPolicy());\n\t\texporter.setNamingStrategy(namingStrategy);\n\t\tString serverBean = this.properties.getServer();\n\t\tif (StringUtils.hasLength(serverBean)) {\n\t\t\texporter.setServer(beanFactory.getBean(serverBean, MBeanServer.class));\n\t\t}\n\t\texporter.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames());\n\t\treturn exporter;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = ObjectNamingStrategy.class, search = SearchStrategy.CURRENT)\n\tParentAwareNamingStrategy objectNamingStrategy() {\n\t\tParentAwareNamingStrategy namingStrategy = new ParentAwareNamingStrategy(new AnnotationJmxAttributeSource());\n\t\tString defaultDomain = this.properties.getDefaultDomain();\n\t\tif (StringUtils.hasLength(defaultDomain)) {\n\t\t\tnamingStrategy.setDefaultDomain(defaultDomain);\n\t\t}\n\t\tnamingStrategy.setEnsureUniqueRuntimeObjectNames(this.properties.isUniqueNames());\n\t\treturn namingStrategy;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMBeanServer mbeanServer() {\n\t\tMBeanServerFactoryBean factory = new MBeanServerFactoryBean();\n\t\tfactory.setLocateExistingServerIfPossible(true);\n\t\tfactory.afterPropertiesSet();\n\t\tMBeanServer mBeanServer = factory.getObject();\n\t\tAssert.state(mBeanServer != null, \"'mBeanServer' must not be null\");\n\t\treturn mBeanServer;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jmx;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.jmx.support.RegistrationPolicy;\n\n/**\n * Configuration properties for JMX.\n *\n * @author Scott Frederick\n * @since 2.7.0\n */\n@ConfigurationProperties(\"spring.jmx\")\npublic class JmxProperties {\n\n\t/**\n\t * Expose Spring's management beans to the JMX domain.\n\t */\n\tprivate boolean enabled;\n\n\t/**\n\t * Whether unique runtime object names should be ensured.\n\t */\n\tprivate boolean uniqueNames;\n\n\t/**\n\t * MBeanServer bean name.\n\t */\n\tprivate String server = \"mbeanServer\";\n\n\t/**\n\t * JMX domain name.\n\t */\n\tprivate @Nullable String defaultDomain;\n\n\t/**\n\t * JMX Registration policy.\n\t */\n\tprivate RegistrationPolicy registrationPolicy = RegistrationPolicy.FAIL_ON_EXISTING;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic boolean isUniqueNames() {\n\t\treturn this.uniqueNames;\n\t}\n\n\tpublic void setUniqueNames(boolean uniqueNames) {\n\t\tthis.uniqueNames = uniqueNames;\n\t}\n\n\tpublic String getServer() {\n\t\treturn this.server;\n\t}\n\n\tpublic void setServer(String server) {\n\t\tthis.server = server;\n\t}\n\n\tpublic @Nullable String getDefaultDomain() {\n\t\treturn this.defaultDomain;\n\t}\n\n\tpublic void setDefaultDomain(@Nullable String defaultDomain) {\n\t\tthis.defaultDomain = defaultDomain;\n\t}\n\n\tpublic RegistrationPolicy getRegistrationPolicy() {\n\t\treturn this.registrationPolicy;\n\t}\n\n\tpublic void setRegistrationPolicy(RegistrationPolicy registrationPolicy) {\n\t\tthis.registrationPolicy = registrationPolicy;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/ParentAwareNamingStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jmx;\n\nimport java.util.Hashtable;\n\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.jmx.export.metadata.JmxAttributeSource;\nimport org.springframework.jmx.export.naming.MetadataNamingStrategy;\nimport org.springframework.jmx.support.JmxUtils;\nimport org.springframework.jmx.support.ObjectNameManager;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Extension of {@link MetadataNamingStrategy} that supports a parent\n * {@link ApplicationContext}.\n *\n * @author Dave Syer\n * @since 1.1.1\n */\npublic class ParentAwareNamingStrategy extends MetadataNamingStrategy implements ApplicationContextAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext applicationContext;\n\n\tprivate boolean ensureUniqueRuntimeObjectNames;\n\n\tpublic ParentAwareNamingStrategy(JmxAttributeSource attributeSource) {\n\t\tsuper(attributeSource);\n\t}\n\n\t/**\n\t * Set if unique runtime object names should be ensured.\n\t * @param ensureUniqueRuntimeObjectNames {@code true} if unique names should be\n\t * ensured.\n\t */\n\tpublic void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {\n\t\tthis.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Override\n\tpublic ObjectName getObjectName(Object managedBean, @Nullable String beanKey) throws MalformedObjectNameException {\n\t\tObjectName name = super.getObjectName(managedBean, beanKey);\n\t\tif (this.ensureUniqueRuntimeObjectNames) {\n\t\t\treturn JmxUtils.appendIdentityToObjectName(name, managedBean);\n\t\t}\n\t\tif (parentContextContainsSameBean(this.applicationContext, beanKey)) {\n\t\t\treturn appendToObjectName(name, \"context\", ObjectUtils.getIdentityHexString(this.applicationContext));\n\t\t}\n\t\treturn name;\n\t}\n\n\tprivate boolean parentContextContainsSameBean(ApplicationContext context, @Nullable String beanKey) {\n\t\tif (context.getParent() == null) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tApplicationContext parent = this.applicationContext.getParent();\n\t\t\tAssert.state(parent != null, \"'parent' must not be null\");\n\t\t\tAssert.state(beanKey != null, \"'beanKey' must not be null\");\n\t\t\tparent.getBean(beanKey);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (BeansException ex) {\n\t\t\treturn parentContextContainsSameBean(context.getParent(), beanKey);\n\t\t}\n\t}\n\n\tprivate ObjectName appendToObjectName(ObjectName name, String key, String value)\n\t\t\tthrows MalformedObjectNameException {\n\t\tHashtable<String, String> keyProperties = name.getKeyPropertyList();\n\t\tkeyProperties.put(key, value);\n\t\treturn ObjectNameManager.getInstance(name.getDomain(), keyProperties);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JMX.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.jmx;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLogger.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.util.Assert;\n\n/**\n * Logs the {@link ConditionEvaluationReport}.\n *\n * @author Greg Turnquist\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass ConditionEvaluationReportLogger {\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\tprivate final Supplier<ConditionEvaluationReport> reportSupplier;\n\n\tprivate final LogLevel logLevel;\n\n\tConditionEvaluationReportLogger(LogLevel logLevel, Supplier<ConditionEvaluationReport> reportSupplier) {\n\t\tAssert.isTrue(isInfoOrDebug(logLevel), \"'logLevel' must be INFO or DEBUG\");\n\t\tthis.logLevel = logLevel;\n\t\tthis.reportSupplier = reportSupplier;\n\t}\n\n\tprivate boolean isInfoOrDebug(LogLevel logLevel) {\n\t\treturn LogLevel.INFO.equals(logLevel) || LogLevel.DEBUG.equals(logLevel);\n\t}\n\n\tvoid logReport(boolean isCrashReport) {\n\t\tConditionEvaluationReport report = this.reportSupplier.get();\n\t\tif (report == null) {\n\t\t\tthis.logger.info(\"Unable to provide the condition evaluation report\");\n\t\t\treturn;\n\t\t}\n\t\tif (!report.getConditionAndOutcomesBySource().isEmpty()) {\n\t\t\tif (this.logLevel.equals(LogLevel.INFO)) {\n\t\t\t\tif (this.logger.isInfoEnabled()) {\n\t\t\t\t\tthis.logger.info(new ConditionEvaluationReportMessage(report));\n\t\t\t\t}\n\t\t\t\telse if (isCrashReport) {\n\t\t\t\t\tlogMessage(\"info\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (this.logger.isDebugEnabled()) {\n\t\t\t\t\tthis.logger.debug(new ConditionEvaluationReportMessage(report));\n\t\t\t\t}\n\t\t\t\telse if (isCrashReport) {\n\t\t\t\t\tlogMessage(\"debug\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void logMessage(String logLevel) {\n\t\tthis.logger.info(String.format(\"%n%nError starting ApplicationContext. To display the \"\n\t\t\t\t+ \"condition evaluation report re-run your application with '%s' enabled.\", logLevel));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLoggingListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.event.GenericApplicationListener;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ApplicationContextInitializer} that writes the {@link ConditionEvaluationReport}\n * to the log. Reports are logged at the {@link LogLevel#DEBUG DEBUG} level. A crash\n * report triggers an info output suggesting the user runs again with debug enabled to\n * display the report.\n * <p>\n * This initializer is not intended to be shared across multiple application context\n * instances.\n *\n * @author Greg Turnquist\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class ConditionEvaluationReportLoggingListener\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\tprivate final LogLevel logLevel;\n\n\tpublic ConditionEvaluationReportLoggingListener() {\n\t\tthis(LogLevel.DEBUG);\n\t}\n\n\tprivate ConditionEvaluationReportLoggingListener(LogLevel logLevel) {\n\t\tAssert.isTrue(isInfoOrDebug(logLevel), \"'logLevel' must be INFO or DEBUG\");\n\t\tthis.logLevel = logLevel;\n\t}\n\n\tprivate boolean isInfoOrDebug(LogLevel logLevelForReport) {\n\t\treturn LogLevel.INFO.equals(logLevelForReport) || LogLevel.DEBUG.equals(logLevelForReport);\n\t}\n\n\t/**\n\t * Static factory method that creates a\n\t * {@link ConditionEvaluationReportLoggingListener} which logs the report at the\n\t * specified log level.\n\t * @param logLevelForReport the log level to log the report at\n\t * @return a {@link ConditionEvaluationReportLoggingListener} instance.\n\t * @since 3.0.0\n\t */\n\tpublic static ConditionEvaluationReportLoggingListener forLogLevel(LogLevel logLevelForReport) {\n\t\treturn new ConditionEvaluationReportLoggingListener(logLevelForReport);\n\t}\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.addApplicationListener(new ConditionEvaluationReportListener(applicationContext));\n\t}\n\n\tprivate final class ConditionEvaluationReportListener implements GenericApplicationListener {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tprivate final ConditionEvaluationReportLogger logger;\n\n\t\tprivate ConditionEvaluationReportListener(ConfigurableApplicationContext context) {\n\t\t\tthis.context = context;\n\t\t\tSupplier<ConditionEvaluationReport> reportSupplier;\n\t\t\tif (context instanceof GenericApplicationContext) {\n\t\t\t\t// Get the report early when the context allows early access to the bean\n\t\t\t\t// factory in case the context subsequently fails to load\n\t\t\t\tConditionEvaluationReport report = getReport();\n\t\t\t\treportSupplier = () -> report;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treportSupplier = this::getReport;\n\t\t\t}\n\t\t\tthis.logger = new ConditionEvaluationReportLogger(ConditionEvaluationReportLoggingListener.this.logLevel,\n\t\t\t\t\treportSupplier);\n\t\t}\n\n\t\tprivate ConditionEvaluationReport getReport() {\n\t\t\treturn ConditionEvaluationReport.get(this.context.getBeanFactory());\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsEventType(ResolvableType resolvableType) {\n\t\t\tClass<?> type = resolvableType.getRawClass();\n\t\t\tif (type == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn ContextRefreshedEvent.class.isAssignableFrom(type)\n\t\t\t\t\t|| ApplicationFailedEvent.class.isAssignableFrom(type);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsSourceType(@Nullable Class<?> sourceType) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tif (event instanceof ContextRefreshedEvent contextRefreshedEvent) {\n\t\t\t\tif (contextRefreshedEvent.getApplicationContext() == this.context) {\n\t\t\t\t\tthis.logger.logReport(false);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (event instanceof ApplicationFailedEvent applicationFailedEvent\n\t\t\t\t\t&& applicationFailedEvent.getApplicationContext() == this.context) {\n\t\t\t\tthis.logger.logReport(true);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLoggingProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.logging.LogLevel;\n\n/**\n * {@link BeanFactoryInitializationAotProcessor} that logs the\n * {@link ConditionEvaluationReport} during ahead-of-time processing.\n *\n * @author Andy Wilkinson\n */\nclass ConditionEvaluationReportLoggingProcessor implements BeanFactoryInitializationAotProcessor {\n\n\t@Override\n\tpublic @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(\n\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\tlogConditionEvaluationReport(beanFactory);\n\t\treturn null;\n\t}\n\n\tprivate void logConditionEvaluationReport(ConfigurableListableBeanFactory beanFactory) {\n\t\tnew ConditionEvaluationReportLogger(LogLevel.DEBUG, () -> ConditionEvaluationReport.get(beanFactory))\n\t\t\t.logReport(false);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportMessage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * A condition evaluation report message that can logged or printed.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.4.0\n */\npublic class ConditionEvaluationReportMessage {\n\n\tprivate final StringBuilder message;\n\n\tpublic ConditionEvaluationReportMessage(ConditionEvaluationReport report) {\n\t\tthis(report, \"CONDITIONS EVALUATION REPORT\");\n\t}\n\n\tpublic ConditionEvaluationReportMessage(ConditionEvaluationReport report, String title) {\n\t\tthis.message = getLogMessage(report, title);\n\t}\n\n\tprivate StringBuilder getLogMessage(ConditionEvaluationReport report, String title) {\n\t\tString separator = \"=\".repeat(title.length());\n\t\tStringBuilder message = new StringBuilder();\n\t\tmessage.append(String.format(\"%n%n%n\"));\n\t\tmessage.append(String.format(\"%s%n\", separator));\n\t\tmessage.append(String.format(\"%s%n\", title));\n\t\tmessage.append(String.format(\"%s%n%n%n\", separator));\n\t\tMap<String, ConditionAndOutcomes> shortOutcomes = orderByName(report.getConditionAndOutcomesBySource());\n\t\tlogPositiveMatches(message, shortOutcomes);\n\t\tlogNegativeMatches(message, shortOutcomes);\n\t\tlogExclusions(report, message);\n\t\tlogUnconditionalClasses(report, message);\n\t\tmessage.append(String.format(\"%n%n\"));\n\t\treturn message;\n\t}\n\n\tprivate void logPositiveMatches(StringBuilder message, Map<String, ConditionAndOutcomes> shortOutcomes) {\n\t\tmessage.append(String.format(\"Positive matches:%n\"));\n\t\tmessage.append(String.format(\"-----------------%n\"));\n\t\tList<Entry<String, ConditionAndOutcomes>> matched = shortOutcomes.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((entry) -> entry.getValue().isFullMatch())\n\t\t\t.toList();\n\t\tif (matched.isEmpty()) {\n\t\t\tmessage.append(String.format(\"%n    None%n\"));\n\t\t}\n\t\telse {\n\t\t\tmatched.forEach((entry) -> addMatchLogMessage(message, entry.getKey(), entry.getValue()));\n\t\t}\n\t\tmessage.append(String.format(\"%n%n\"));\n\t}\n\n\tprivate void logNegativeMatches(StringBuilder message, Map<String, ConditionAndOutcomes> shortOutcomes) {\n\t\tmessage.append(String.format(\"Negative matches:%n\"));\n\t\tmessage.append(String.format(\"-----------------%n\"));\n\t\tList<Entry<String, ConditionAndOutcomes>> nonMatched = shortOutcomes.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((entry) -> !entry.getValue().isFullMatch())\n\t\t\t.toList();\n\t\tif (nonMatched.isEmpty()) {\n\t\t\tmessage.append(String.format(\"%n    None%n\"));\n\t\t}\n\t\telse {\n\t\t\tnonMatched.forEach((entry) -> addNonMatchLogMessage(message, entry.getKey(), entry.getValue()));\n\t\t}\n\t\tmessage.append(String.format(\"%n%n\"));\n\t}\n\n\tprivate void logExclusions(ConditionEvaluationReport report, StringBuilder message) {\n\t\tmessage.append(String.format(\"Exclusions:%n\"));\n\t\tmessage.append(String.format(\"-----------%n\"));\n\t\tif (report.getExclusions().isEmpty()) {\n\t\t\tmessage.append(String.format(\"%n    None%n\"));\n\t\t}\n\t\telse {\n\t\t\tfor (String exclusion : report.getExclusions()) {\n\t\t\t\tmessage.append(String.format(\"%n    %s%n\", exclusion));\n\t\t\t}\n\t\t}\n\t\tmessage.append(String.format(\"%n%n\"));\n\t}\n\n\tprivate void logUnconditionalClasses(ConditionEvaluationReport report, StringBuilder message) {\n\t\tmessage.append(String.format(\"Unconditional classes:%n\"));\n\t\tmessage.append(String.format(\"----------------------%n\"));\n\t\tif (report.getUnconditionalClasses().isEmpty()) {\n\t\t\tmessage.append(String.format(\"%n    None%n\"));\n\t\t}\n\t\telse {\n\t\t\tfor (String unconditionalClass : report.getUnconditionalClasses()) {\n\t\t\t\tmessage.append(String.format(\"%n    %s%n\", unconditionalClass));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Map<String, ConditionAndOutcomes> orderByName(Map<String, ConditionAndOutcomes> outcomes) {\n\t\tMultiValueMap<String, String> map = mapToFullyQualifiedNames(outcomes.keySet());\n\t\tList<String> shortNames = new ArrayList<>(map.keySet());\n\t\tCollections.sort(shortNames);\n\t\tMap<String, ConditionAndOutcomes> result = new LinkedHashMap<>();\n\t\tfor (String shortName : shortNames) {\n\t\t\tList<String> fullyQualifiedNames = map.get(shortName);\n\t\t\tAssert.state(fullyQualifiedNames != null, \"'fullyQualifiedNames' must not be null\");\n\t\t\tif (fullyQualifiedNames.size() > 1) {\n\t\t\t\tfullyQualifiedNames\n\t\t\t\t\t.forEach((fullyQualifiedName) -> result.put(fullyQualifiedName, outcomes.get(fullyQualifiedName)));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.put(shortName, outcomes.get(fullyQualifiedNames.get(0)));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate MultiValueMap<String, String> mapToFullyQualifiedNames(Set<String> keySet) {\n\t\tLinkedMultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n\t\tkeySet\n\t\t\t.forEach((fullyQualifiedName) -> map.add(ClassUtils.getShortName(fullyQualifiedName), fullyQualifiedName));\n\t\treturn map;\n\t}\n\n\tprivate void addMatchLogMessage(StringBuilder message, String source, ConditionAndOutcomes matches) {\n\t\tmessage.append(String.format(\"%n   %s matched:%n\", source));\n\t\tfor (ConditionAndOutcome match : matches) {\n\t\t\tlogConditionAndOutcome(message, \"      \", match);\n\t\t}\n\t}\n\n\tprivate void addNonMatchLogMessage(StringBuilder message, String source,\n\t\t\tConditionAndOutcomes conditionAndOutcomes) {\n\t\tmessage.append(String.format(\"%n   %s:%n\", source));\n\t\tList<ConditionAndOutcome> matches = new ArrayList<>();\n\t\tList<ConditionAndOutcome> nonMatches = new ArrayList<>();\n\t\tfor (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {\n\t\t\tif (conditionAndOutcome.getOutcome().isMatch()) {\n\t\t\t\tmatches.add(conditionAndOutcome);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnonMatches.add(conditionAndOutcome);\n\t\t\t}\n\t\t}\n\t\tmessage.append(String.format(\"      Did not match:%n\"));\n\t\tfor (ConditionAndOutcome nonMatch : nonMatches) {\n\t\t\tlogConditionAndOutcome(message, \"         \", nonMatch);\n\t\t}\n\t\tif (!matches.isEmpty()) {\n\t\t\tmessage.append(String.format(\"      Matched:%n\"));\n\t\t\tfor (ConditionAndOutcome match : matches) {\n\t\t\t\tlogConditionAndOutcome(message, \"         \", match);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void logConditionAndOutcome(StringBuilder message, String indent, ConditionAndOutcome conditionAndOutcome) {\n\t\tmessage.append(String.format(\"%s- \", indent));\n\t\tString outcomeMessage = conditionAndOutcome.getOutcome().getMessage();\n\t\tif (StringUtils.hasLength(outcomeMessage)) {\n\t\t\tmessage.append(outcomeMessage);\n\t\t}\n\t\telse {\n\t\t\tmessage.append(conditionAndOutcome.getOutcome().isMatch() ? \"matched\" : \"did not match\");\n\t\t}\n\t\tmessage.append(\" (\");\n\t\tmessage.append(ClassUtils.getShortName(conditionAndOutcome.getCondition().getClass()));\n\t\tmessage.append(String.format(\")%n\"));\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for logging.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.logging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot's auto-configuration capabilities.\n *\n * @see org.springframework.boot.autoconfigure.EnableAutoConfiguration\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/preinitialize/BackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.preinitialize;\n\n/**\n * Interface used to preinitialize in the background code that may otherwise cause a delay\n * when first called. Implementations should be registered in {@code spring.factories}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface BackgroundPreinitializer {\n\n\t/**\n\t * Perform any require preinitialization.\n\t * @throws Exception on any initialization error\n\t */\n\tvoid preinitialize() throws Exception;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/preinitialize/BackgroundPreinitializingApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.preinitialize;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.SpringApplicationEvent;\nimport org.springframework.boot.context.logging.LoggingApplicationListener;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.NativeDetector;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * {@link ApplicationListener} to trigger early initialization in a background thread of\n * time-consuming tasks.\n * <p>\n * Set the {@link #IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME} system property to\n * {@code true} to disable this mechanism.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @author Sebastien Deleuze\n * @see BackgroundPreinitializer\n */\nclass BackgroundPreinitializingApplicationListener implements ApplicationListener<SpringApplicationEvent>, Ordered {\n\n\t/**\n\t * System property that instructs Spring Boot how to run pre initialization. When the\n\t * property is set to {@code true}, no pre-initialization happens and each item is\n\t * initialized in the foreground as it needs to. When the property is {@code false}\n\t * (default), pre initialization runs in a separate thread in the background.\n\t */\n\tpublic static final String IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME = \"spring.backgroundpreinitializer.ignore\";\n\n\tprivate static final AtomicBoolean started = new AtomicBoolean();\n\n\tprivate static final CountDownLatch complete = new CountDownLatch(1);\n\n\tprivate final SpringFactoriesLoader factoriesLoader;\n\n\tprivate final boolean enabled;\n\n\tBackgroundPreinitializingApplicationListener() {\n\t\tthis(SpringFactoriesLoader.forDefaultResourceLocation());\n\t}\n\n\tBackgroundPreinitializingApplicationListener(SpringFactoriesLoader factoriesLoader) {\n\t\tthis.factoriesLoader = factoriesLoader;\n\t\tthis.enabled = !NativeDetector.inNativeImage()\n\t\t\t\t&& !Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)\n\t\t\t\t&& Runtime.getRuntime().availableProcessors() > 1;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn LoggingApplicationListener.DEFAULT_ORDER + 1;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(SpringApplicationEvent event) {\n\t\tif (!this.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tif (event instanceof ApplicationEnvironmentPreparedEvent && started.compareAndSet(false, true)) {\n\t\t\tpreinitialize();\n\t\t}\n\t\tif ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) && started.get()) {\n\t\t\ttry {\n\t\t\t\tcomplete.await();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void preinitialize() {\n\t\tRunner runner = new Runner(this.factoriesLoader.load(BackgroundPreinitializer.class));\n\t\ttry {\n\t\t\tThread thread = new Thread(runner, \"background-preinit\");\n\t\t\tthread.start();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// This will fail on Google App Engine where creating threads is\n\t\t\t// prohibited. We can safely continue but startup will be slightly slower\n\t\t\t// as the initialization will now happen on the main thread.\n\t\t\tcomplete.countDown();\n\t\t}\n\t}\n\n\t/**\n\t * Runner thread to call the {@link BackgroundPreinitializer} instances.\n\t *\n\t * @param preinitializers the preinitializers\n\t */\n\trecord Runner(List<BackgroundPreinitializer> preinitializers) implements Runnable {\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tfor (BackgroundPreinitializer preinitializer : this.preinitializers) {\n\t\t\t\ttry {\n\t\t\t\t\tpreinitializer.preinitialize();\n\t\t\t\t}\n\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t}\n\t\t\t}\n\t\t\tcomplete.countDown();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/preinitialize/CharsetsBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.preinitialize;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * {@link BackgroundPreinitializer} for commonly used charsets.\n *\n * @author Phillip Webb\n */\nfinal class CharsetsBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tStandardCharsets.UTF_8.name();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/preinitialize/ConversionServiceBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.preinitialize;\n\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.format.support.DefaultFormattingConversionService;\n\n/**\n * {@link BackgroundPreinitializer} for Spring's {@link ConversionService}.\n *\n * @author Phillip Webb\n */\nfinal class ConversionServiceBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tnew DefaultFormattingConversionService();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/preinitialize/ZoneIdBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.preinitialize;\n\nimport java.time.ZoneId;\n\n/**\n * {@link BackgroundPreinitializer} for {@link ZoneId}.\n *\n * @author Phillip Webb\n */\nfinal class ZoneIdBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tZoneId.systemDefault();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/preinitialize/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Capabilities to preinitialize code in the background to improve startup performance.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.preinitialize;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.service.connection;\n\nimport org.springframework.boot.origin.OriginProvider;\n\n/**\n * Base interface for types that provide the details required to establish a connection to\n * a remote service.\n * <p>\n * Implementation classes can also implement {@link OriginProvider} in order to provide\n * origin information.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic interface ConnectionDetails {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetailsFactories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.service.connection;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.FailureHandler;\nimport org.springframework.util.Assert;\n\n/**\n * A registry of {@link ConnectionDetailsFactory} instances.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Pedro Xavier Leite Cavadas\n * @since 3.1.0\n */\npublic class ConnectionDetailsFactories {\n\n\tprivate static final Log logger = LogFactory.getLog(ConnectionDetailsFactories.class);\n\n\tprivate final List<Registration<?, ?>> registrations = new ArrayList<>();\n\n\t/**\n\t * Create a new {@link ConnectionDetailsFactories} instance.\n\t * @param classLoader the class loader used to load factories\n\t * @since 3.5.0\n\t */\n\tpublic ConnectionDetailsFactories(@Nullable ClassLoader classLoader) {\n\t\tthis(SpringFactoriesLoader.forDefaultResourceLocation(classLoader));\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tConnectionDetailsFactories(SpringFactoriesLoader loader) {\n\t\tList<ConnectionDetailsFactory> factories = loader.load(ConnectionDetailsFactory.class,\n\t\t\t\tFailureHandler.logging(logger));\n\t\tStream<Registration<?, ?>> registrations = factories.stream().map(Registration::get);\n\t\tregistrations.filter(Objects::nonNull).forEach(this.registrations::add);\n\t}\n\n\t/**\n\t * Return a {@link Map} of {@link ConnectionDetails} interface type to\n\t * {@link ConnectionDetails} instance created from the factories associated with the\n\t * given source.\n\t * @param <S> the source type\n\t * @param source the source\n\t * @param required if a connection details result is required\n\t * @return a map of {@link ConnectionDetails} instances\n\t * @throws ConnectionDetailsFactoryNotFoundException if a result is required but no\n\t * connection details factory is registered for the source\n\t * @throws ConnectionDetailsNotFoundException if a result is required but no\n\t * connection details instance was created from a registered factory\n\t */\n\tpublic <S> Map<Class<?>, ConnectionDetails> getConnectionDetails(S source, boolean required)\n\t\t\tthrows ConnectionDetailsFactoryNotFoundException, ConnectionDetailsNotFoundException {\n\t\tList<Registration<S, ?>> registrations = getRegistrations(source, required);\n\t\tMap<Class<?>, ConnectionDetails> result = new LinkedHashMap<>();\n\t\tfor (Registration<S, ?> registration : registrations) {\n\t\t\tConnectionDetails connectionDetails = registration.factory().getConnectionDetails(source);\n\t\t\tif (connectionDetails != null) {\n\t\t\t\tClass<?> connectionDetailsType = registration.connectionDetailsType();\n\t\t\t\tConnectionDetails previous = result.put(connectionDetailsType, connectionDetails);\n\t\t\t\tAssert.state(previous == null, () -> \"Duplicate connection details supplied for %s\"\n\t\t\t\t\t.formatted(connectionDetailsType.getName()));\n\t\t\t}\n\t\t}\n\t\tif (required && result.isEmpty()) {\n\t\t\tthrow new ConnectionDetailsNotFoundException(source);\n\t\t}\n\t\treturn Map.copyOf(result);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t<S> List<Registration<S, ?>> getRegistrations(S source, boolean required) {\n\t\tClass<S> sourceType = (Class<S>) source.getClass();\n\t\tList<Registration<S, ?>> result = new ArrayList<>();\n\t\tfor (Registration<?, ?> candidate : this.registrations) {\n\t\t\tif (candidate.sourceType().isAssignableFrom(sourceType)) {\n\t\t\t\tresult.add((Registration<S, ?>) candidate);\n\t\t\t}\n\t\t}\n\t\tif (required && result.isEmpty()) {\n\t\t\tthrow new ConnectionDetailsFactoryNotFoundException(source);\n\t\t}\n\t\tresult.sort(Comparator.comparing(Registration::factory, AnnotationAwareOrderComparator.INSTANCE));\n\t\treturn List.copyOf(result);\n\t}\n\n\t/**\n\t * A {@link ConnectionDetailsFactory} registration.\n\t *\n\t * @param <S> the source type\n\t * @param <D> the connection details type\n\t * @param sourceType the source type\n\t * @param connectionDetailsType the connection details type\n\t * @param factory the factory\n\t */\n\trecord Registration<S, D extends ConnectionDetails>(Class<S> sourceType, Class<D> connectionDetailsType,\n\t\t\tConnectionDetailsFactory<S, D> factory) {\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate static <S, D extends ConnectionDetails> @Nullable Registration<S, D> get(\n\t\t\t\tConnectionDetailsFactory<S, D> factory) {\n\t\t\tResolvableType type = ResolvableType.forClass(ConnectionDetailsFactory.class, factory.getClass());\n\t\t\t@Nullable Class<?>[] generics = type.resolveGenerics();\n\t\t\tClass<S> sourceType = (Class<S>) generics[0];\n\t\t\tClass<D> connectionDetailsType = (Class<D>) generics[1];\n\t\t\treturn (sourceType != null && connectionDetailsType != null)\n\t\t\t\t\t? new Registration<>(sourceType, connectionDetailsType, factory) : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.service.connection;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A factory to create {@link ConnectionDetails} from a given {@code source}.\n * Implementations should be registered in {@code META-INF/spring.factories}.\n *\n * @param <S> the source type accepted by the factory. Implementations are expected to\n * provide a valid {@code toString}.\n * @param <D> the type of {@link ConnectionDetails} produced by the factory\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic interface ConnectionDetailsFactory<S, D extends ConnectionDetails> {\n\n\t/**\n\t * Get the {@link ConnectionDetails} from the given {@code source}. May return\n\t * {@code null} if no details can be created.\n\t * @param source the source\n\t * @return the connection details or {@code null}\n\t */\n\t@Nullable D getConnectionDetails(S source);\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetailsFactoryNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.service.connection;\n\n/**\n * {@link RuntimeException} thrown when a {@link ConnectionDetailsFactory} could not be\n * found.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class ConnectionDetailsFactoryNotFoundException extends RuntimeException {\n\n\t<S> ConnectionDetailsFactoryNotFoundException(S source) {\n\t\tthis(\"No ConnectionDetailsFactory found for source '%s'\".formatted(source));\n\t}\n\n\tpublic ConnectionDetailsFactoryNotFoundException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic ConnectionDetailsFactoryNotFoundException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetailsNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.service.connection;\n\n/**\n * {@link RuntimeException} thrown when required {@link ConnectionDetails} could not be\n * found.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class ConnectionDetailsNotFoundException extends RuntimeException {\n\n\t<S> ConnectionDetailsNotFoundException(S source) {\n\t\tthis(\"No ConnectionDetails found for source '%s'\".formatted(source));\n\t}\n\n\tpublic ConnectionDetailsNotFoundException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic ConnectionDetailsNotFoundException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/service/connection/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for service connections that affect auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.service.connection;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/BundleContentNotWatchableException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\n/**\n * Thrown when a bundle content location is not watchable.\n *\n * @author Moritz Halbritter\n */\nclass BundleContentNotWatchableException extends RuntimeException {\n\n\tprivate final BundleContentProperty property;\n\n\tBundleContentNotWatchableException(BundleContentProperty property) {\n\t\tsuper(\"The content of '%s' is not watchable. Only 'file:' resources are watchable, but '%s' has been set\"\n\t\t\t.formatted(property.name(), property.value()));\n\t\tthis.property = property;\n\t}\n\n\tprivate BundleContentNotWatchableException(String bundleName, BundleContentProperty property, Throwable cause) {\n\t\tsuper(\"The content of '%s' from bundle '%s' is not watchable'. Only 'file:' resources are watchable, but '%s' has been set\"\n\t\t\t.formatted(property.name(), bundleName, property.value()), cause);\n\t\tthis.property = property;\n\t}\n\n\tBundleContentNotWatchableException withBundleName(String bundleName) {\n\t\treturn new BundleContentNotWatchableException(bundleName, this.property, this);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/BundleContentNotWatchableFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of non-watchable bundle\n * content failures caused by {@link BundleContentNotWatchableException}.\n *\n * @author Moritz Halbritter\n */\nclass BundleContentNotWatchableFailureAnalyzer extends AbstractFailureAnalyzer<BundleContentNotWatchableException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, BundleContentNotWatchableException cause) {\n\t\treturn new FailureAnalysis(cause.getMessage(), \"Update your application to correct the invalid configuration:\\n\"\n\t\t\t\t+ \"Either use a watchable resource, or disable bundle reloading by setting reload-on-update = false on the bundle.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/BundleContentProperty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.nio.file.Path;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.pem.PemContent;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Helper utility to manage a single bundle content configuration property. May possibly\n * contain PEM content, a location or a directory search pattern.\n *\n * @param name the configuration property name (excluding any prefix)\n * @param value the configuration property value\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nrecord BundleContentProperty(String name, @Nullable String value) {\n\n\t/**\n\t * Return if the property value is PEM content.\n\t * @return if the value is PEM content\n\t */\n\tboolean isPemContent() {\n\t\treturn PemContent.isPresentInText(this.value);\n\t}\n\n\t/**\n\t * Return if there is any property value present.\n\t * @return if the value is present\n\t */\n\tboolean hasValue() {\n\t\treturn StringUtils.hasText(this.value);\n\t}\n\n\tPath toWatchPath(ResourceLoader resourceLoader) {\n\t\ttry {\n\t\t\tAssert.state(!isPemContent(), \"Value contains PEM content\");\n\t\t\tAssert.state(this.value != null, \"Value must not be null\");\n\t\t\tResource resource = resourceLoader.getResource(this.value);\n\t\t\tif (!resource.isFile()) {\n\t\t\t\tthrow new BundleContentNotWatchableException(this);\n\t\t\t}\n\t\t\treturn Path.of(resource.getFile().getAbsolutePath());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof BundleContentNotWatchableException bundleContentNotWatchableException) {\n\t\t\t\tthrow bundleContentNotWatchableException;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unable to convert value of property '%s' to a path\".formatted(this.name),\n\t\t\t\t\tex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/CertificateMatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.PublicKey;\nimport java.security.Signature;\nimport java.security.SignatureException;\nimport java.security.cert.Certificate;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Helper used to match certificates against a {@link PrivateKey}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass CertificateMatcher {\n\n\tprivate static final byte[] DATA = new byte[256];\n\tstatic {\n\t\tfor (int i = 0; i < DATA.length; i++) {\n\t\t\tDATA[i] = (byte) i;\n\t\t}\n\t}\n\n\tprivate final PrivateKey privateKey;\n\n\tprivate final Signature signature;\n\n\tprivate final byte @Nullable [] generatedSignature;\n\n\tCertificateMatcher(PrivateKey privateKey) {\n\t\tAssert.notNull(privateKey, \"'privateKey' must not be null\");\n\t\tthis.privateKey = privateKey;\n\t\tSignature signature = createSignature(privateKey);\n\t\tAssert.state(signature != null, \"Failed to create signature\");\n\t\tthis.signature = signature;\n\t\tthis.generatedSignature = sign(signature, privateKey);\n\t}\n\n\tprivate @Nullable Signature createSignature(PrivateKey privateKey) {\n\t\ttry {\n\t\t\tString algorithm = getSignatureAlgorithm(privateKey);\n\t\t\treturn (algorithm != null) ? Signature.getInstance(algorithm) : null;\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static @Nullable String getSignatureAlgorithm(PrivateKey privateKey) {\n\t\t// https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html#signature-algorithms\n\t\t// https://docs.oracle.com/en/java/javase/17/docs/specs/security/standard-names.html#keypairgenerator-algorithms\n\t\treturn switch (privateKey.getAlgorithm()) {\n\t\t\tcase \"RSA\" -> \"SHA256withRSA\";\n\t\t\tcase \"DSA\" -> \"SHA256withDSA\";\n\t\t\tcase \"EC\" -> \"SHA256withECDSA\";\n\t\t\tcase \"EdDSA\" -> \"EdDSA\";\n\t\t\tdefault -> null;\n\t\t};\n\t}\n\n\tboolean matchesAny(List<? extends Certificate> certificates) {\n\t\treturn (this.generatedSignature != null) && certificates.stream().anyMatch(this::matches);\n\t}\n\n\tboolean matches(Certificate certificate) {\n\t\treturn matches(certificate.getPublicKey());\n\t}\n\n\tprivate boolean matches(PublicKey publicKey) {\n\t\treturn (this.generatedSignature != null)\n\t\t\t\t&& Objects.equals(this.privateKey.getAlgorithm(), publicKey.getAlgorithm()) && verify(publicKey);\n\t}\n\n\tprivate boolean verify(PublicKey publicKey) {\n\t\ttry {\n\t\t\tthis.signature.initVerify(publicKey);\n\t\t\tthis.signature.update(DATA);\n\t\t\treturn this.signature.verify(this.generatedSignature);\n\t\t}\n\t\tcatch (InvalidKeyException | SignatureException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static byte @Nullable [] sign(Signature signature, PrivateKey privateKey) {\n\t\ttry {\n\t\t\tsignature.initSign(privateKey);\n\t\t\tsignature.update(DATA);\n\t\t\treturn signature.sign();\n\t\t}\n\t\tcatch (InvalidKeyException | SignatureException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/FileWatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.ClosedWatchServiceException;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardWatchEventKinds;\nimport java.nio.file.WatchEvent;\nimport java.nio.file.WatchKey;\nimport java.nio.file.WatchService;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\n\n/**\n * Watches files and directories and triggers a callback on change.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass FileWatcher implements Closeable {\n\n\tprivate static final Log logger = LogFactory.getLog(FileWatcher.class);\n\n\tprivate final Duration quietPeriod;\n\n\tprivate final Object lock = new Object();\n\n\tprivate @Nullable WatcherThread thread;\n\n\t/**\n\t * Create a new {@link FileWatcher} instance.\n\t * @param quietPeriod the duration that no file changes should occur before triggering\n\t * actions\n\t */\n\tFileWatcher(Duration quietPeriod) {\n\t\tAssert.notNull(quietPeriod, \"'quietPeriod' must not be null\");\n\t\tthis.quietPeriod = quietPeriod;\n\t}\n\n\t/**\n\t * Watch the given files or directories for changes.\n\t * @param paths the files or directories to watch\n\t * @param action the action to take when changes are detected\n\t */\n\tvoid watch(Set<Path> paths, Runnable action) {\n\t\tAssert.notNull(paths, \"'paths' must not be null\");\n\t\tAssert.notNull(action, \"'action' must not be null\");\n\t\tif (paths.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tsynchronized (this.lock) {\n\t\t\ttry {\n\t\t\t\tif (this.thread == null) {\n\t\t\t\t\tthis.thread = new WatcherThread();\n\t\t\t\t\tthis.thread.start();\n\t\t\t\t}\n\t\t\t\tthis.thread.register(new Registration(getRegistrationPaths(paths), action));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(\"Failed to register paths for watching: \" + paths, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Retrieves all {@link Path Paths} that should be registered for the specified\n\t * {@link Path}. If the path is a symlink, changes to the symlink should be monitored,\n\t * not just the file it points to. For example, for the given {@code keystore.jks}\n\t * path in the following directory structure:<pre>\n\t * +- stores\n\t * |  +─ keystore.jks\n\t * +- <em>data</em> -&gt; stores\n\t * +─ <em>keystore.jks</em> -&gt; data/keystore.jks\n\t * </pre> the resulting paths would include:\n\t * <p>\n\t * <ul>\n\t * <li>{@code keystore.jks}</li>\n\t * <li>{@code data/keystore.jks}</li>\n\t * <li>{@code data}</li>\n\t * <li>{@code stores/keystore.jks}</li>\n\t * </ul>\n\t * @param paths the source paths\n\t * @return all possible {@link Path} instances to be registered\n\t * @throws IOException if an I/O error occurs\n\t */\n\tprivate Set<Path> getRegistrationPaths(Set<Path> paths) throws IOException {\n\t\tSet<Path> result = new HashSet<>();\n\t\tfor (Path path : paths) {\n\t\t\tcollectRegistrationPaths(path, result);\n\t\t}\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n\tprivate void collectRegistrationPaths(Path path, Set<Path> result) throws IOException {\n\t\tpath = path.toAbsolutePath();\n\t\tresult.add(path);\n\t\tPath parent = path.getParent();\n\t\tif (parent != null && Files.isSymbolicLink(parent)) {\n\t\t\tresult.add(parent);\n\t\t\tcollectRegistrationPaths(resolveSiblingSymbolicLink(parent).resolve(path.getFileName()), result);\n\t\t}\n\t\telse if (Files.isSymbolicLink(path)) {\n\t\t\tcollectRegistrationPaths(resolveSiblingSymbolicLink(path), result);\n\t\t}\n\t}\n\n\tprivate Path resolveSiblingSymbolicLink(Path path) throws IOException {\n\t\treturn path.resolveSibling(Files.readSymbolicLink(path));\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tsynchronized (this.lock) {\n\t\t\tif (this.thread != null) {\n\t\t\t\tthis.thread.close();\n\t\t\t\tthis.thread.interrupt();\n\t\t\t\ttry {\n\t\t\t\t\tthis.thread.join();\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t\tthis.thread = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The watcher thread used to check for changes.\n\t */\n\tprivate class WatcherThread extends Thread implements Closeable {\n\n\t\tprivate final WatchService watchService = FileSystems.getDefault().newWatchService();\n\n\t\tprivate final Map<WatchKey, List<Registration>> registrations = new ConcurrentHashMap<>();\n\n\t\tprivate volatile boolean running = true;\n\n\t\tWatcherThread() throws IOException {\n\t\t\tsetName(\"ssl-bundle-watcher\");\n\t\t\tsetDaemon(true);\n\t\t\tsetUncaughtExceptionHandler(this::onThreadException);\n\t\t}\n\n\t\tprivate void onThreadException(Thread thread, Throwable throwable) {\n\t\t\tlogger.error(\"Uncaught exception in file watcher thread\", throwable);\n\t\t}\n\n\t\tvoid register(Registration registration) throws IOException {\n\t\t\tSet<Path> directories = new HashSet<>();\n\t\t\tfor (Path path : registration.paths()) {\n\t\t\t\tif (!Files.isRegularFile(path) && !Files.isDirectory(path)) {\n\t\t\t\t\tthrow new IOException(\"'%s' is neither a file nor a directory\".formatted(path));\n\t\t\t\t}\n\t\t\t\tPath directory = Files.isDirectory(path) ? path : path.getParent();\n\t\t\t\tdirectories.add(directory);\n\t\t\t}\n\t\t\tfor (Path directory : directories) {\n\t\t\t\tWatchKey watchKey = register(directory);\n\t\t\t\tthis.registrations.computeIfAbsent(watchKey, (key) -> new CopyOnWriteArrayList<>()).add(registration);\n\t\t\t}\n\t\t}\n\n\t\tprivate WatchKey register(Path directory) throws IOException {\n\t\t\tlogger.debug(LogMessage.format(\"Registering '%s'\", directory));\n\t\t\treturn directory.register(this.watchService, StandardWatchEventKinds.ENTRY_CREATE,\n\t\t\t\t\tStandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tlogger.debug(\"Watch thread started\");\n\t\t\tSet<Runnable> actions = new HashSet<>();\n\t\t\twhile (this.running) {\n\t\t\t\ttry {\n\t\t\t\t\tlong timeout = FileWatcher.this.quietPeriod.toMillis();\n\t\t\t\t\tWatchKey key = this.watchService.poll(timeout, TimeUnit.MILLISECONDS);\n\t\t\t\t\tif (key == null) {\n\t\t\t\t\t\tactions.forEach(this::runSafely);\n\t\t\t\t\t\tactions.clear();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\taccumulate(key, actions);\n\t\t\t\t\t\tkey.reset();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t\tcatch (ClosedWatchServiceException ex) {\n\t\t\t\t\tlogger.debug(\"File watcher has been closed\");\n\t\t\t\t\tthis.running = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlogger.debug(\"Watch thread stopped\");\n\t\t}\n\n\t\tprivate void runSafely(Runnable action) {\n\t\t\ttry {\n\t\t\t\taction.run();\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tlogger.error(\"Unexpected SSL reload error\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate void accumulate(WatchKey key, Set<Runnable> actions) {\n\t\t\tList<Registration> registrations = this.registrations.get(key);\n\t\t\tPath directory = (Path) key.watchable();\n\t\t\tfor (WatchEvent<?> event : key.pollEvents()) {\n\t\t\t\tPath file = directory.resolve((Path) event.context());\n\t\t\t\tAssert.state(registrations != null, \"'registrations' must not be null\");\n\t\t\t\tfor (Registration registration : registrations) {\n\t\t\t\t\tif (registration.manages(file)) {\n\t\t\t\t\t\tactions.add(registration.action());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tthis.running = false;\n\t\t\tthis.watchService.close();\n\t\t}\n\n\t}\n\n\t/**\n\t * An individual watch registration.\n\t *\n\t * @param paths the paths being registered\n\t * @param action the action to take\n\t */\n\tprivate record Registration(Set<Path> paths, Runnable action) {\n\n\t\tboolean manages(Path file) {\n\t\t\tPath absolutePath = file.toAbsolutePath();\n\t\t\treturn this.paths.contains(absolutePath) || isInDirectories(absolutePath);\n\t\t}\n\n\t\tprivate boolean isInDirectories(Path file) {\n\t\t\treturn this.paths.stream().filter(Files::isDirectory).anyMatch(file::startsWith);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/JksSslBundleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\n\n/**\n * {@link SslBundleProperties} for Java keystores.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.1.0\n * @see JksSslStoreBundle\n */\npublic class JksSslBundleProperties extends SslBundleProperties {\n\n\t/**\n\t * Keystore properties.\n\t */\n\tprivate final Store keystore = new Store();\n\n\t/**\n\t * Truststore properties.\n\t */\n\tprivate final Store truststore = new Store();\n\n\tpublic Store getKeystore() {\n\t\treturn this.keystore;\n\t}\n\n\tpublic Store getTruststore() {\n\t\treturn this.truststore;\n\t}\n\n\t/**\n\t * Store properties.\n\t */\n\tpublic static class Store {\n\n\t\t/**\n\t\t * Type of the store to create, e.g. JKS.\n\t\t */\n\t\tprivate @Nullable String type;\n\n\t\t/**\n\t\t * Provider for the store.\n\t\t */\n\t\tprivate @Nullable String provider;\n\n\t\t/**\n\t\t * Location of the resource containing the store content.\n\t\t */\n\t\tprivate @Nullable String location;\n\n\t\t/**\n\t\t * Password used to access the store.\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\tpublic @Nullable String getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic void setType(@Nullable String type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic @Nullable String getProvider() {\n\t\t\treturn this.provider;\n\t\t}\n\n\t\tpublic void setProvider(@Nullable String provider) {\n\t\t\tthis.provider = provider;\n\t\t}\n\n\t\tpublic @Nullable String getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\tpublic void setLocation(@Nullable String location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/PemSslBundleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\n\n/**\n * {@link SslBundleProperties} for PEM-encoded certificates and private keys.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 3.1.0\n * @see PemSslStoreBundle\n */\npublic class PemSslBundleProperties extends SslBundleProperties {\n\n\t/**\n\t * Keystore properties.\n\t */\n\tprivate final Store keystore = new Store();\n\n\t/**\n\t * Truststore properties.\n\t */\n\tprivate final Store truststore = new Store();\n\n\tpublic Store getKeystore() {\n\t\treturn this.keystore;\n\t}\n\n\tpublic Store getTruststore() {\n\t\treturn this.truststore;\n\t}\n\n\t/**\n\t * Store properties.\n\t */\n\tpublic static class Store {\n\n\t\t/**\n\t\t * Type of the store to create, e.g. JKS.\n\t\t */\n\t\tprivate @Nullable String type;\n\n\t\t/**\n\t\t * Location or content of the certificate or certificate chain in PEM format.\n\t\t */\n\t\tprivate @Nullable String certificate;\n\n\t\t/**\n\t\t * Location or content of the private key in PEM format.\n\t\t */\n\t\tprivate @Nullable String privateKey;\n\n\t\t/**\n\t\t * Password used to decrypt an encrypted private key.\n\t\t */\n\t\tprivate @Nullable String privateKeyPassword;\n\n\t\t/**\n\t\t * Whether to verify that the private key matches the public key.\n\t\t */\n\t\tprivate boolean verifyKeys;\n\n\t\tpublic @Nullable String getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic void setType(@Nullable String type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic @Nullable String getCertificate() {\n\t\t\treturn this.certificate;\n\t\t}\n\n\t\tpublic void setCertificate(@Nullable String certificate) {\n\t\t\tthis.certificate = certificate;\n\t\t}\n\n\t\tpublic @Nullable String getPrivateKey() {\n\t\t\treturn this.privateKey;\n\t\t}\n\n\t\tpublic void setPrivateKey(@Nullable String privateKey) {\n\t\t\tthis.privateKey = privateKey;\n\t\t}\n\n\t\tpublic @Nullable String getPrivateKeyPassword() {\n\t\t\treturn this.privateKeyPassword;\n\t\t}\n\n\t\tpublic void setPrivateKeyPassword(@Nullable String privateKeyPassword) {\n\t\t\tthis.privateKeyPassword = privateKeyPassword;\n\t\t}\n\n\t\tpublic boolean isVerifyKeys() {\n\t\t\treturn this.verifyKeys;\n\t\t}\n\n\t\tpublic void setVerifyKeys(boolean verifyKeys) {\n\t\t\tthis.verifyKeys = verifyKeys;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/PropertiesSslBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.ssl.SslBundleProperties.Key;\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslManagerBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.ssl.pem.PemSslStore;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link SslBundle} backed by {@link JksSslBundleProperties} or\n * {@link PemSslBundleProperties}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic final class PropertiesSslBundle implements SslBundle {\n\n\tprivate final SslStoreBundle stores;\n\n\tprivate final SslBundleKey key;\n\n\tprivate final SslOptions options;\n\n\tprivate final String protocol;\n\n\tprivate final SslManagerBundle managers;\n\n\tprivate PropertiesSslBundle(SslStoreBundle stores, SslBundleProperties properties) {\n\t\tthis.stores = stores;\n\t\tthis.key = asSslKeyReference(properties.getKey());\n\t\tthis.options = asSslOptions(properties.getOptions());\n\t\tthis.protocol = properties.getProtocol();\n\t\tthis.managers = SslManagerBundle.from(this.stores, this.key);\n\t}\n\n\tprivate static SslBundleKey asSslKeyReference(@Nullable Key key) {\n\t\treturn (key != null) ? SslBundleKey.of(key.getPassword(), key.getAlias()) : SslBundleKey.NONE;\n\t}\n\n\tprivate static SslOptions asSslOptions(SslBundleProperties.@Nullable Options options) {\n\t\treturn (options != null) ? SslOptions.of(options.getCiphers(), options.getEnabledProtocols()) : SslOptions.NONE;\n\t}\n\n\t@Override\n\tpublic SslStoreBundle getStores() {\n\t\treturn this.stores;\n\t}\n\n\t@Override\n\tpublic SslBundleKey getKey() {\n\t\treturn this.key;\n\t}\n\n\t@Override\n\tpublic SslOptions getOptions() {\n\t\treturn this.options;\n\t}\n\n\t@Override\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\t@Override\n\tpublic SslManagerBundle getManagers() {\n\t\treturn this.managers;\n\t}\n\n\t/**\n\t * Get an {@link SslBundle} for the given {@link PemSslBundleProperties}.\n\t * @param properties the source properties\n\t * @return an {@link SslBundle} instance\n\t */\n\tpublic static SslBundle get(PemSslBundleProperties properties) {\n\t\treturn get(properties, ApplicationResourceLoader.get());\n\t}\n\n\t/**\n\t * Get an {@link SslBundle} for the given {@link PemSslBundleProperties}.\n\t * @param properties the source properties\n\t * @param resourceLoader the resource loader used to load content\n\t * @return an {@link SslBundle} instance\n\t * @since 3.3.5\n\t */\n\tpublic static SslBundle get(PemSslBundleProperties properties, ResourceLoader resourceLoader) {\n\t\tPemSslStore keyStore = getPemSslStore(\"keystore\", properties.getKeystore(), resourceLoader);\n\t\tif (keyStore != null) {\n\t\t\tkeyStore = keyStore.withAlias(properties.getKey().getAlias())\n\t\t\t\t.withPassword(properties.getKey().getPassword());\n\t\t}\n\t\tPemSslStore trustStore = getPemSslStore(\"truststore\", properties.getTruststore(), resourceLoader);\n\t\tSslStoreBundle storeBundle = new PemSslStoreBundle(keyStore, trustStore);\n\t\treturn new PropertiesSslBundle(storeBundle, properties);\n\t}\n\n\tprivate static @Nullable PemSslStore getPemSslStore(String propertyName, PemSslBundleProperties.Store properties,\n\t\t\tResourceLoader resourceLoader) {\n\t\tPemSslStoreDetails details = asPemSslStoreDetails(properties);\n\t\tPemSslStore pemSslStore = PemSslStore.load(details, resourceLoader);\n\t\tif (properties.isVerifyKeys()) {\n\t\t\tAssert.state(pemSslStore != null, \"'pemSslStore' must not be null\");\n\t\t\tPrivateKey privateKey = pemSslStore.privateKey();\n\t\t\tAssert.state(privateKey != null, \"'privateKey' must not be null\");\n\t\t\tCertificateMatcher certificateMatcher = new CertificateMatcher(privateKey);\n\t\t\tList<X509Certificate> certificates = pemSslStore.certificates();\n\t\t\tAssert.state(certificates != null, \"'certificates' must not be null\");\n\t\t\tAssert.state(certificateMatcher.matchesAny(certificates),\n\t\t\t\t\t() -> \"Private key in %s matches none of the certificates in the chain\".formatted(propertyName));\n\t\t}\n\t\treturn pemSslStore;\n\t}\n\n\tprivate static PemSslStoreDetails asPemSslStoreDetails(PemSslBundleProperties.Store properties) {\n\t\treturn new PemSslStoreDetails(properties.getType(), properties.getCertificate(), properties.getPrivateKey(),\n\t\t\t\tproperties.getPrivateKeyPassword());\n\t}\n\n\t/**\n\t * Get an {@link SslBundle} for the given {@link JksSslBundleProperties}.\n\t * @param properties the source properties\n\t * @return an {@link SslBundle} instance\n\t */\n\tpublic static SslBundle get(JksSslBundleProperties properties) {\n\t\treturn get(properties, ApplicationResourceLoader.get());\n\t}\n\n\t/**\n\t * Get an {@link SslBundle} for the given {@link JksSslBundleProperties}.\n\t * @param properties the source properties\n\t * @param resourceLoader the resource loader used to load content\n\t * @return an {@link SslBundle} instance\n\t * @since 3.3.5\n\t */\n\tpublic static SslBundle get(JksSslBundleProperties properties, ResourceLoader resourceLoader) {\n\t\tSslStoreBundle storeBundle = asSslStoreBundle(properties, resourceLoader);\n\t\treturn new PropertiesSslBundle(storeBundle, properties);\n\t}\n\n\tprivate static SslStoreBundle asSslStoreBundle(JksSslBundleProperties properties, ResourceLoader resourceLoader) {\n\t\tJksSslStoreDetails keyStoreDetails = asStoreDetails(properties.getKeystore());\n\t\tJksSslStoreDetails trustStoreDetails = asStoreDetails(properties.getTruststore());\n\t\treturn new JksSslStoreBundle(keyStoreDetails, trustStoreDetails, resourceLoader);\n\t}\n\n\tprivate static JksSslStoreDetails asStoreDetails(JksSslBundleProperties.Store properties) {\n\t\treturn new JksSslStoreDetails(properties.getType(), properties.getProvider(), properties.getLocation(),\n\t\t\t\tproperties.getPassword());\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tcreator.append(\"key\", this.key);\n\t\tcreator.append(\"options\", this.options);\n\t\tcreator.append(\"protocol\", this.protocol);\n\t\tcreator.append(\"stores\", this.stores);\n\t\treturn creator.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for SSL.\n *\n * @author Scott Frederick\n * @since 3.1.0\n */\n@AutoConfiguration\n@EnableConfigurationProperties(SslProperties.class)\npublic final class SslAutoConfiguration {\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final SslProperties sslProperties;\n\n\tSslAutoConfiguration(ResourceLoader resourceLoader, SslProperties sslProperties) {\n\t\tthis.resourceLoader = ApplicationResourceLoader.get(resourceLoader, true);\n\t\tthis.sslProperties = sslProperties;\n\t}\n\n\t@Bean\n\tFileWatcher fileWatcher() {\n\t\treturn new FileWatcher(this.sslProperties.getBundle().getWatch().getFile().getQuietPeriod());\n\t}\n\n\t@Bean\n\tSslPropertiesBundleRegistrar sslPropertiesSslBundleRegistrar(FileWatcher fileWatcher) {\n\t\treturn new SslPropertiesBundleRegistrar(this.sslProperties, fileWatcher, this.resourceLoader);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean({ SslBundleRegistry.class, SslBundles.class })\n\tDefaultSslBundleRegistry sslBundleRegistry(ObjectProvider<SslBundleRegistrar> sslBundleRegistrars) {\n\t\tDefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();\n\t\tsslBundleRegistrars.orderedStream().forEach((registrar) -> registrar.registerBundles(registry));\n\t\treturn registry;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslBundleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Base class for SSL Bundle properties.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.1.0\n * @see SslBundle\n */\npublic abstract class SslBundleProperties {\n\n\t/**\n\t * Key details for the bundle.\n\t */\n\tprivate final Key key = new Key();\n\n\t/**\n\t * Options for the SSL connection.\n\t */\n\tprivate final Options options = new Options();\n\n\t/**\n\t * SSL Protocol to use.\n\t */\n\tprivate String protocol = SslBundle.DEFAULT_PROTOCOL;\n\n\t/**\n\t * Whether to reload the SSL bundle.\n\t */\n\tprivate boolean reloadOnUpdate;\n\n\tpublic Key getKey() {\n\t\treturn this.key;\n\t}\n\n\tpublic Options getOptions() {\n\t\treturn this.options;\n\t}\n\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\tpublic void setProtocol(String protocol) {\n\t\tthis.protocol = protocol;\n\t}\n\n\tpublic boolean isReloadOnUpdate() {\n\t\treturn this.reloadOnUpdate;\n\t}\n\n\tpublic void setReloadOnUpdate(boolean reloadOnUpdate) {\n\t\tthis.reloadOnUpdate = reloadOnUpdate;\n\t}\n\n\tpublic static class Options {\n\n\t\t/**\n\t\t * Supported SSL ciphers.\n\t\t */\n\t\tprivate @Nullable Set<String> ciphers;\n\n\t\t/**\n\t\t * Enabled SSL protocols.\n\t\t */\n\t\tprivate @Nullable Set<String> enabledProtocols;\n\n\t\tpublic @Nullable Set<String> getCiphers() {\n\t\t\treturn this.ciphers;\n\t\t}\n\n\t\tpublic void setCiphers(@Nullable Set<String> ciphers) {\n\t\t\tthis.ciphers = ciphers;\n\t\t}\n\n\t\tpublic @Nullable Set<String> getEnabledProtocols() {\n\t\t\treturn this.enabledProtocols;\n\t\t}\n\n\t\tpublic void setEnabledProtocols(@Nullable Set<String> enabledProtocols) {\n\t\t\tthis.enabledProtocols = enabledProtocols;\n\t\t}\n\n\t}\n\n\tpublic static class Key {\n\n\t\t/**\n\t\t * The password used to access the key in the key store.\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\t/**\n\t\t * The alias that identifies the key in the key store.\n\t\t */\n\t\tprivate @Nullable String alias;\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t\tpublic @Nullable String getAlias() {\n\t\t\treturn this.alias;\n\t\t}\n\n\t\tpublic void setAlias(@Nullable String alias) {\n\t\t\tthis.alias = alias;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslBundleRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleRegistry;\n\n/**\n * Interface to be implemented by types that register {@link SslBundle} instances with an\n * {@link SslBundleRegistry}.\n *\n * @author Scott Frederick\n * @since 3.1.0\n */\n@FunctionalInterface\npublic interface SslBundleRegistrar {\n\n\t/**\n\t * Callback method for registering {@link SslBundle}s with an\n\t * {@link SslBundleRegistry}.\n\t * @param registry the registry that accepts {@code SslBundle}s\n\t */\n\tvoid registerBundles(SslBundleRegistry registry);\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.time.Duration;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties for centralized SSL trust material configuration.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 3.1.0\n */\n@ConfigurationProperties(\"spring.ssl\")\npublic class SslProperties {\n\n\t/**\n\t * SSL bundles.\n\t */\n\tprivate final Bundles bundle = new Bundles();\n\n\tpublic Bundles getBundle() {\n\t\treturn this.bundle;\n\t}\n\n\t/**\n\t * Properties to define SSL Bundles.\n\t */\n\tpublic static class Bundles {\n\n\t\t/**\n\t\t * PEM-encoded SSL trust material.\n\t\t */\n\t\tprivate final Map<String, PemSslBundleProperties> pem = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Java keystore SSL trust material.\n\t\t */\n\t\tprivate final Map<String, JksSslBundleProperties> jks = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Trust material watching.\n\t\t */\n\t\tprivate final Watch watch = new Watch();\n\n\t\tpublic Map<String, PemSslBundleProperties> getPem() {\n\t\t\treturn this.pem;\n\t\t}\n\n\t\tpublic Map<String, JksSslBundleProperties> getJks() {\n\t\t\treturn this.jks;\n\t\t}\n\n\t\tpublic Watch getWatch() {\n\t\t\treturn this.watch;\n\t\t}\n\n\t\tpublic static class Watch {\n\n\t\t\t/**\n\t\t\t * File watching.\n\t\t\t */\n\t\t\tprivate final File file = new File();\n\n\t\t\tpublic File getFile() {\n\t\t\t\treturn this.file;\n\t\t\t}\n\n\t\t\tpublic static class File {\n\n\t\t\t\t/**\n\t\t\t\t * Quiet period, after which changes are detected.\n\t\t\t\t */\n\t\t\t\tprivate Duration quietPeriod = Duration.ofSeconds(10);\n\n\t\t\t\tpublic Duration getQuietPeriod() {\n\t\t\t\t\treturn this.quietPeriod;\n\t\t\t\t}\n\n\t\t\t\tpublic void setQuietPeriod(Duration quietPeriod) {\n\t\t\t\t\tthis.quietPeriod = quietPeriod;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/SslPropertiesBundleRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleRegistry;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * A {@link SslBundleRegistrar} that registers SSL bundles based\n * {@link SslProperties#getBundle() configuration properties}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass SslPropertiesBundleRegistrar implements SslBundleRegistrar {\n\n\tprivate final SslProperties.Bundles properties;\n\n\tprivate final FileWatcher fileWatcher;\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tSslPropertiesBundleRegistrar(SslProperties properties, FileWatcher fileWatcher, ResourceLoader resourceLoader) {\n\t\tthis.properties = properties.getBundle();\n\t\tthis.fileWatcher = fileWatcher;\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tpublic void registerBundles(SslBundleRegistry registry) {\n\t\tregisterBundles(registry, this.properties.getPem(), PropertiesSslBundle::get, this::watchedPemPaths);\n\t\tregisterBundles(registry, this.properties.getJks(), PropertiesSslBundle::get, this::watchedJksPaths);\n\t}\n\n\tprivate <P extends SslBundleProperties> void registerBundles(SslBundleRegistry registry, Map<String, P> properties,\n\t\t\tBiFunction<P, ResourceLoader, SslBundle> bundleFactory, Function<Bundle<P>, Set<Path>> watchedPaths) {\n\t\tproperties.forEach((bundleName, bundleProperties) -> {\n\t\t\tSupplier<SslBundle> bundleSupplier = () -> bundleFactory.apply(bundleProperties, this.resourceLoader);\n\t\t\ttry {\n\t\t\t\tregistry.registerBundle(bundleName, bundleSupplier.get());\n\t\t\t\tif (bundleProperties.isReloadOnUpdate()) {\n\t\t\t\t\tSupplier<Set<Path>> pathsSupplier = () -> watchedPaths\n\t\t\t\t\t\t.apply(new Bundle<>(bundleName, bundleProperties));\n\t\t\t\t\twatchForUpdates(registry, bundleName, pathsSupplier, bundleSupplier);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to register SSL bundle '%s'\".formatted(bundleName), ex);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void watchForUpdates(SslBundleRegistry registry, String bundleName, Supplier<Set<Path>> pathsSupplier,\n\t\t\tSupplier<SslBundle> bundleSupplier) {\n\t\ttry {\n\t\t\tthis.fileWatcher.watch(pathsSupplier.get(), () -> registry.updateBundle(bundleName, bundleSupplier.get()));\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to watch for reload on update\", ex);\n\t\t}\n\t}\n\n\tprivate Set<Path> watchedJksPaths(Bundle<JksSslBundleProperties> bundle) {\n\t\tList<BundleContentProperty> watched = new ArrayList<>();\n\t\twatched.add(new BundleContentProperty(\"keystore.location\", bundle.properties().getKeystore().getLocation()));\n\t\twatched\n\t\t\t.add(new BundleContentProperty(\"truststore.location\", bundle.properties().getTruststore().getLocation()));\n\t\treturn watchedPaths(bundle.name(), watched);\n\t}\n\n\tprivate Set<Path> watchedPemPaths(Bundle<PemSslBundleProperties> bundle) {\n\t\tList<BundleContentProperty> watched = new ArrayList<>();\n\t\twatched\n\t\t\t.add(new BundleContentProperty(\"keystore.private-key\", bundle.properties().getKeystore().getPrivateKey()));\n\t\twatched\n\t\t\t.add(new BundleContentProperty(\"keystore.certificate\", bundle.properties().getKeystore().getCertificate()));\n\t\twatched.add(new BundleContentProperty(\"truststore.private-key\",\n\t\t\t\tbundle.properties().getTruststore().getPrivateKey()));\n\t\twatched.add(new BundleContentProperty(\"truststore.certificate\",\n\t\t\t\tbundle.properties().getTruststore().getCertificate()));\n\t\treturn watchedPaths(bundle.name(), watched);\n\t}\n\n\tprivate Set<Path> watchedPaths(String bundleName, List<BundleContentProperty> properties) {\n\t\ttry {\n\t\t\treturn properties.stream()\n\t\t\t\t.filter(BundleContentProperty::hasValue)\n\t\t\t\t.map((content) -> content.toWatchPath(this.resourceLoader))\n\t\t\t\t.collect(Collectors.toSet());\n\t\t}\n\t\tcatch (BundleContentNotWatchableException ex) {\n\t\t\tthrow ex.withBundleName(bundleName);\n\t\t}\n\t}\n\n\tprivate record Bundle<P>(String name, P properties) {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for SSL bundles.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/DefaultTaskSchedulerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.task.SimpleAsyncTaskSchedulerBuilder;\nimport org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\nimport org.springframework.scheduling.config.TaskSchedulerRouter;\n\n/**\n * Configuration that can be imported to expose a standard {@link TaskScheduler} if the\n * user has not enabled task scheduling explicitly. A {@link SimpleAsyncTaskScheduler} is\n * exposed if the user enables virtual threads via\n * {@code spring.threads.virtual.enabled=true}, otherwise {@link ThreadPoolTaskScheduler}.\n * <p>\n * Configurations importing this one should be ordered after\n * {@link TaskSchedulingAutoConfiguration}.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(name = DefaultTaskSchedulerConfiguration.DEFAULT_TASK_SCHEDULER_BEAN_NAME)\npublic class DefaultTaskSchedulerConfiguration {\n\n\t/**\n\t * The bean name of the default task scheduler.\n\t */\n\tpublic static final String DEFAULT_TASK_SCHEDULER_BEAN_NAME = TaskSchedulerRouter.DEFAULT_TASK_SCHEDULER_BEAN_NAME;\n\n\t@Bean(name = DEFAULT_TASK_SCHEDULER_BEAN_NAME)\n\t@ConditionalOnBean(ThreadPoolTaskSchedulerBuilder.class)\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tThreadPoolTaskScheduler taskScheduler(ThreadPoolTaskSchedulerBuilder threadPoolTaskSchedulerBuilder) {\n\t\treturn threadPoolTaskSchedulerBuilder.build();\n\t}\n\n\t@Bean(name = DEFAULT_TASK_SCHEDULER_BEAN_NAME)\n\t@ConditionalOnBean(SimpleAsyncTaskSchedulerBuilder.class)\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tSimpleAsyncTaskScheduler taskSchedulerVirtualThreads(\n\t\t\tSimpleAsyncTaskSchedulerBuilder simpleAsyncTaskSchedulerBuilder) {\n\t\treturn simpleAsyncTaskSchedulerBuilder.build();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/ScheduledBeanLazyInitializationExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.springframework.aop.framework.AopInfrastructureBean;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.core.MethodIntrospector;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.scheduling.annotation.Schedules;\nimport org.springframework.util.ClassUtils;\n\n/**\n * A {@link LazyInitializationExcludeFilter} that detects bean methods annotated with\n * {@link Scheduled} or {@link Schedules}.\n *\n * @author Stephane Nicoll\n */\nclass ScheduledBeanLazyInitializationExcludeFilter implements LazyInitializationExcludeFilter {\n\n\tprivate final Set<Class<?>> nonAnnotatedClasses = ConcurrentHashMap.newKeySet(64);\n\n\tScheduledBeanLazyInitializationExcludeFilter() {\n\t\t// Ignore AOP infrastructure such as scoped proxies.\n\t\tthis.nonAnnotatedClasses.add(AopInfrastructureBean.class);\n\t\tthis.nonAnnotatedClasses.add(TaskScheduler.class);\n\t\tthis.nonAnnotatedClasses.add(ScheduledExecutorService.class);\n\t}\n\n\t@Override\n\tpublic boolean isExcluded(String beanName, BeanDefinition beanDefinition, Class<?> beanType) {\n\t\treturn hasScheduledTask(beanType);\n\t}\n\n\tprivate boolean hasScheduledTask(Class<?> type) {\n\t\tClass<?> targetType = ClassUtils.getUserClass(type);\n\t\tif (!this.nonAnnotatedClasses.contains(targetType)\n\t\t\t\t&& AnnotationUtils.isCandidateClass(targetType, Arrays.asList(Scheduled.class, Schedules.class))) {\n\t\t\tMap<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetType,\n\t\t\t\t\t(MethodIntrospector.MetadataLookup<Set<Scheduled>>) (method) -> {\n\t\t\t\t\t\tSet<Scheduled> scheduledAnnotations = AnnotatedElementUtils\n\t\t\t\t\t\t\t.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);\n\t\t\t\t\t\treturn (!scheduledAnnotations.isEmpty() ? scheduledAnnotations : null);\n\t\t\t\t\t});\n\t\t\tif (annotatedMethods.isEmpty()) {\n\t\t\t\tthis.nonAnnotatedClasses.add(targetType);\n\t\t\t}\n\t\t\treturn !annotatedMethods.isEmpty();\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link TaskExecutor}.\n *\n * @author Stephane Nicoll\n * @author Camille Vienot\n * @author Moritz Halbritter\n * @since 2.1.0\n */\n@ConditionalOnClass(ThreadPoolTaskExecutor.class)\n@AutoConfiguration\n@EnableConfigurationProperties(TaskExecutionProperties.class)\n@Import({ TaskExecutorConfigurations.TaskExecutorContextPropagationConfiguration.class,\n\t\tTaskExecutorConfigurations.ThreadPoolTaskExecutorBuilderConfiguration.class,\n\t\tTaskExecutorConfigurations.SimpleAsyncTaskExecutorBuilderConfiguration.class,\n\t\tTaskExecutorConfigurations.TaskExecutorConfiguration.class,\n\t\tTaskExecutorConfigurations.BootstrapExecutorConfiguration.class })\npublic final class TaskExecutionAutoConfiguration {\n\n\t/**\n\t * Bean name of the application {@link TaskExecutor}.\n\t */\n\tpublic static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = \"applicationTaskExecutor\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for task execution.\n *\n * @author Stephane Nicoll\n * @author Filip Hrisafov\n * @author Yanming Zhou\n * @since 2.1.0\n */\n@ConfigurationProperties(\"spring.task.execution\")\npublic class TaskExecutionProperties {\n\n\tprivate final Pool pool = new Pool();\n\n\tprivate final Simple simple = new Simple();\n\n\tprivate final Shutdown shutdown = new Shutdown();\n\n\t/**\n\t * Determine when the task executor is to be created.\n\t */\n\tprivate Mode mode = Mode.AUTO;\n\n\t/**\n\t * Whether to propagate the current context to task executions.\n\t */\n\tprivate boolean propagateContext;\n\n\t/**\n\t * Prefix to use for the names of newly created threads.\n\t */\n\tprivate String threadNamePrefix = \"task-\";\n\n\tpublic Simple getSimple() {\n\t\treturn this.simple;\n\t}\n\n\tpublic Pool getPool() {\n\t\treturn this.pool;\n\t}\n\n\tpublic Shutdown getShutdown() {\n\t\treturn this.shutdown;\n\t}\n\n\tpublic Mode getMode() {\n\t\treturn this.mode;\n\t}\n\n\tpublic void setMode(Mode mode) {\n\t\tthis.mode = mode;\n\t}\n\n\tpublic boolean getPropagateContext() {\n\t\treturn this.propagateContext;\n\t}\n\n\tpublic void setPropagateContext(boolean propagateContext) {\n\t\tthis.propagateContext = propagateContext;\n\t}\n\n\tpublic String getThreadNamePrefix() {\n\t\treturn this.threadNamePrefix;\n\t}\n\n\tpublic void setThreadNamePrefix(String threadNamePrefix) {\n\t\tthis.threadNamePrefix = threadNamePrefix;\n\t}\n\n\tpublic static class Simple {\n\n\t\t/**\n\t\t * Whether to cancel remaining tasks on close. Only recommended if threads are\n\t\t * commonly expected to be stuck.\n\t\t */\n\t\tprivate boolean cancelRemainingTasksOnClose;\n\n\t\t/**\n\t\t * Whether to reject tasks when the concurrency limit has been reached.\n\t\t */\n\t\tprivate boolean rejectTasksWhenLimitReached;\n\n\t\t/**\n\t\t * Set the maximum number of parallel accesses allowed. -1 indicates no\n\t\t * concurrency limit at all.\n\t\t */\n\t\tprivate @Nullable Integer concurrencyLimit;\n\n\t\tpublic boolean isCancelRemainingTasksOnClose() {\n\t\t\treturn this.cancelRemainingTasksOnClose;\n\t\t}\n\n\t\tpublic void setCancelRemainingTasksOnClose(boolean cancelRemainingTasksOnClose) {\n\t\t\tthis.cancelRemainingTasksOnClose = cancelRemainingTasksOnClose;\n\t\t}\n\n\t\tpublic boolean isRejectTasksWhenLimitReached() {\n\t\t\treturn this.rejectTasksWhenLimitReached;\n\t\t}\n\n\t\tpublic void setRejectTasksWhenLimitReached(boolean rejectTasksWhenLimitReached) {\n\t\t\tthis.rejectTasksWhenLimitReached = rejectTasksWhenLimitReached;\n\t\t}\n\n\t\tpublic @Nullable Integer getConcurrencyLimit() {\n\t\t\treturn this.concurrencyLimit;\n\t\t}\n\n\t\tpublic void setConcurrencyLimit(@Nullable Integer concurrencyLimit) {\n\t\t\tthis.concurrencyLimit = concurrencyLimit;\n\t\t}\n\n\t}\n\n\tpublic static class Pool {\n\n\t\t/**\n\t\t * Queue capacity. An unbounded capacity does not increase the pool and therefore\n\t\t * ignores the \"max-size\" property. Doesn't have an effect if virtual threads are\n\t\t * enabled.\n\t\t */\n\t\tprivate int queueCapacity = Integer.MAX_VALUE;\n\n\t\t/**\n\t\t * Core number of threads. Doesn't have an effect if virtual threads are enabled.\n\t\t */\n\t\tprivate int coreSize = 8;\n\n\t\t/**\n\t\t * Maximum allowed number of threads. If tasks are filling up the queue, the pool\n\t\t * can expand up to that size to accommodate the load. Ignored if the queue is\n\t\t * unbounded. Doesn't have an effect if virtual threads are enabled.\n\t\t */\n\t\tprivate int maxSize = Integer.MAX_VALUE;\n\n\t\t/**\n\t\t * Whether core threads are allowed to time out. This enables dynamic growing and\n\t\t * shrinking of the pool. Doesn't have an effect if virtual threads are enabled.\n\t\t */\n\t\tprivate boolean allowCoreThreadTimeout = true;\n\n\t\t/**\n\t\t * Time limit for which threads may remain idle before being terminated. Doesn't\n\t\t * have an effect if virtual threads are enabled.\n\t\t */\n\t\tprivate Duration keepAlive = Duration.ofSeconds(60);\n\n\t\tprivate final Shutdown shutdown = new Shutdown();\n\n\t\tpublic int getQueueCapacity() {\n\t\t\treturn this.queueCapacity;\n\t\t}\n\n\t\tpublic void setQueueCapacity(int queueCapacity) {\n\t\t\tthis.queueCapacity = queueCapacity;\n\t\t}\n\n\t\tpublic int getCoreSize() {\n\t\t\treturn this.coreSize;\n\t\t}\n\n\t\tpublic void setCoreSize(int coreSize) {\n\t\t\tthis.coreSize = coreSize;\n\t\t}\n\n\t\tpublic int getMaxSize() {\n\t\t\treturn this.maxSize;\n\t\t}\n\n\t\tpublic void setMaxSize(int maxSize) {\n\t\t\tthis.maxSize = maxSize;\n\t\t}\n\n\t\tpublic boolean isAllowCoreThreadTimeout() {\n\t\t\treturn this.allowCoreThreadTimeout;\n\t\t}\n\n\t\tpublic void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout) {\n\t\t\tthis.allowCoreThreadTimeout = allowCoreThreadTimeout;\n\t\t}\n\n\t\tpublic Duration getKeepAlive() {\n\t\t\treturn this.keepAlive;\n\t\t}\n\n\t\tpublic void setKeepAlive(Duration keepAlive) {\n\t\t\tthis.keepAlive = keepAlive;\n\t\t}\n\n\t\tpublic Shutdown getShutdown() {\n\t\t\treturn this.shutdown;\n\t\t}\n\n\t\tpublic static class Shutdown {\n\n\t\t\t/**\n\t\t\t * Whether to accept further tasks after the application context close phase\n\t\t\t * has begun.\n\t\t\t */\n\t\t\tprivate boolean acceptTasksAfterContextClose;\n\n\t\t\tpublic boolean isAcceptTasksAfterContextClose() {\n\t\t\t\treturn this.acceptTasksAfterContextClose;\n\t\t\t}\n\n\t\t\tpublic void setAcceptTasksAfterContextClose(boolean acceptTasksAfterContextClose) {\n\t\t\t\tthis.acceptTasksAfterContextClose = acceptTasksAfterContextClose;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Shutdown {\n\n\t\t/**\n\t\t * Whether the executor should wait for scheduled tasks to complete on shutdown.\n\t\t */\n\t\tprivate boolean awaitTermination;\n\n\t\t/**\n\t\t * Maximum time the executor should wait for remaining tasks to complete.\n\t\t */\n\t\tprivate @Nullable Duration awaitTerminationPeriod;\n\n\t\tpublic boolean isAwaitTermination() {\n\t\t\treturn this.awaitTermination;\n\t\t}\n\n\t\tpublic void setAwaitTermination(boolean awaitTermination) {\n\t\t\tthis.awaitTermination = awaitTermination;\n\t\t}\n\n\t\tpublic @Nullable Duration getAwaitTerminationPeriod() {\n\t\t\treturn this.awaitTerminationPeriod;\n\t\t}\n\n\t\tpublic void setAwaitTerminationPeriod(@Nullable Duration awaitTerminationPeriod) {\n\t\t\tthis.awaitTerminationPeriod = awaitTerminationPeriod;\n\t\t}\n\n\t}\n\n\t/**\n\t * Determine when the task executor is to be created.\n\t *\n\t * @since 3.5.0\n\t */\n\tpublic enum Mode {\n\n\t\t/**\n\t\t * Create the task executor if no user-defined executor is present.\n\t\t */\n\t\tAUTO,\n\n\t\t/**\n\t\t * Create the task executor even if a user-defined executor is present.\n\t\t */\n\t\tFORCE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskExecutorConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\nimport io.micrometer.context.ContextSnapshot;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;\nimport org.springframework.boot.task.SimpleAsyncTaskExecutorCustomizer;\nimport org.springframework.boot.task.ThreadPoolTaskExecutorBuilder;\nimport org.springframework.boot.task.ThreadPoolTaskExecutorCustomizer;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.core.task.support.CompositeTaskDecorator;\nimport org.springframework.core.task.support.ContextPropagatingTaskDecorator;\nimport org.springframework.scheduling.annotation.AsyncConfigurer;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\n/**\n * {@link TaskExecutor} configurations to be imported by\n * {@link TaskExecutionAutoConfiguration} in a specific order.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Yanming Zhou\n */\nclass TaskExecutorConfigurations {\n\n\tprivate static @Nullable TaskDecorator getTaskDecorator(ObjectProvider<TaskDecorator> taskDecorator) {\n\t\tList<TaskDecorator> taskDecorators = taskDecorator.orderedStream().toList();\n\t\tif (taskDecorators.size() == 1) {\n\t\t\treturn taskDecorators.get(0);\n\t\t}\n\t\treturn (!taskDecorators.isEmpty()) ? new CompositeTaskDecorator(taskDecorators) : null;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ContextSnapshot.class)\n\tstatic class TaskExecutorContextPropagationConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnProperty(name = \"spring.task.execution.propagate-context\", havingValue = \"true\")\n\t\tContextPropagatingTaskDecorator contextPropagatingTaskDecorator() {\n\t\t\treturn new ContextPropagatingTaskDecorator();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(OnExecutorCondition.class)\n\t@Import({ AsyncConfigurerWrapperConfiguration.class, AsyncConfigurerConfiguration.class })\n\tstatic class TaskExecutorConfiguration {\n\n\t\t@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)\n\t\t@ConditionalOnThreading(Threading.VIRTUAL)\n\t\tSimpleAsyncTaskExecutor applicationTaskExecutorVirtualThreads(SimpleAsyncTaskExecutorBuilder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)\n\t\t@Lazy\n\t\t@ConditionalOnThreading(Threading.PLATFORM)\n\t\tThreadPoolTaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder) {\n\t\t\treturn threadPoolTaskExecutorBuilder.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ThreadPoolTaskExecutorBuilderConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tThreadPoolTaskExecutorBuilder threadPoolTaskExecutorBuilder(TaskExecutionProperties properties,\n\t\t\t\tObjectProvider<ThreadPoolTaskExecutorCustomizer> threadPoolTaskExecutorCustomizers,\n\t\t\t\tObjectProvider<TaskDecorator> taskDecorator) {\n\t\t\tTaskExecutionProperties.Pool pool = properties.getPool();\n\t\t\tThreadPoolTaskExecutorBuilder builder = new ThreadPoolTaskExecutorBuilder();\n\t\t\tbuilder = builder.queueCapacity(pool.getQueueCapacity());\n\t\t\tbuilder = builder.corePoolSize(pool.getCoreSize());\n\t\t\tbuilder = builder.maxPoolSize(pool.getMaxSize());\n\t\t\tbuilder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());\n\t\t\tbuilder = builder.keepAlive(pool.getKeepAlive());\n\t\t\tbuilder = builder.acceptTasksAfterContextClose(pool.getShutdown().isAcceptTasksAfterContextClose());\n\t\t\tTaskExecutionProperties.Shutdown shutdown = properties.getShutdown();\n\t\t\tbuilder = builder.awaitTermination(shutdown.isAwaitTermination());\n\t\t\tbuilder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());\n\t\t\tbuilder = builder.threadNamePrefix(properties.getThreadNamePrefix());\n\t\t\tbuilder = builder.customizers(threadPoolTaskExecutorCustomizers.orderedStream()::iterator);\n\t\t\tbuilder = builder.taskDecorator(getTaskDecorator(taskDecorator));\n\t\t\treturn builder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleAsyncTaskExecutorBuilderConfiguration {\n\n\t\tprivate final TaskExecutionProperties properties;\n\n\t\tprivate final ObjectProvider<SimpleAsyncTaskExecutorCustomizer> taskExecutorCustomizers;\n\n\t\tprivate final ObjectProvider<TaskDecorator> taskDecorator;\n\n\t\tSimpleAsyncTaskExecutorBuilderConfiguration(TaskExecutionProperties properties,\n\t\t\t\tObjectProvider<SimpleAsyncTaskExecutorCustomizer> taskExecutorCustomizers,\n\t\t\t\tObjectProvider<TaskDecorator> taskDecorator) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.taskExecutorCustomizers = taskExecutorCustomizers;\n\t\t\tthis.taskDecorator = taskDecorator;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnThreading(Threading.PLATFORM)\n\t\tSimpleAsyncTaskExecutorBuilder simpleAsyncTaskExecutorBuilder() {\n\t\t\treturn builder();\n\t\t}\n\n\t\t@Bean(name = \"simpleAsyncTaskExecutorBuilder\")\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnThreading(Threading.VIRTUAL)\n\t\tSimpleAsyncTaskExecutorBuilder simpleAsyncTaskExecutorBuilderVirtualThreads() {\n\t\t\treturn builder().virtualThreads(true);\n\t\t}\n\n\t\tprivate SimpleAsyncTaskExecutorBuilder builder() {\n\t\t\tSimpleAsyncTaskExecutorBuilder builder = new SimpleAsyncTaskExecutorBuilder();\n\t\t\tbuilder = builder.threadNamePrefix(this.properties.getThreadNamePrefix());\n\t\t\tbuilder = builder.customizers(this.taskExecutorCustomizers.orderedStream()::iterator);\n\t\t\tbuilder = builder.taskDecorator(getTaskDecorator(this.taskDecorator));\n\t\t\tTaskExecutionProperties.Simple simple = this.properties.getSimple();\n\t\t\tbuilder = builder.cancelRemainingTasksOnClose(simple.isCancelRemainingTasksOnClose());\n\t\t\tbuilder = builder.rejectTasksWhenLimitReached(simple.isRejectTasksWhenLimitReached());\n\t\t\tbuilder = builder.concurrencyLimit(simple.getConcurrencyLimit());\n\t\t\tTaskExecutionProperties.Shutdown shutdown = this.properties.getShutdown();\n\t\t\tif (shutdown.isAwaitTermination()) {\n\t\t\t\tbuilder = builder.taskTerminationTimeout(shutdown.getAwaitTerminationPeriod());\n\t\t\t}\n\t\t\treturn builder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(AsyncConfigurer.class)\n\tstatic class AsyncConfigurerWrapperConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor applicationTaskExecutorAsyncConfigurerBeanPostProcessor(\n\t\t\t\tObjectProvider<BeanFactory> beanFactory) {\n\t\t\treturn new BeanPostProcessor() {\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\t\t\tif (bean instanceof AsyncConfigurer asyncConfigurer\n\t\t\t\t\t\t\t&& !(bean instanceof ApplicationTaskExecutorAsyncConfigurer)) {\n\t\t\t\t\t\treturn new ApplicationTaskExecutorAsyncConfigurer(beanFactory.getObject(), asyncConfigurer);\n\t\t\t\t\t}\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(AsyncConfigurer.class)\n\tstatic class AsyncConfigurerConfiguration {\n\n\t\t@Bean\n\t\tApplicationTaskExecutorAsyncConfigurer applicationTaskExecutorAsyncConfigurer(BeanFactory beanFactory) {\n\t\t\treturn new ApplicationTaskExecutorAsyncConfigurer(beanFactory, null);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BootstrapExecutorConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanFactoryPostProcessor bootstrapExecutorAliasPostProcessor() {\n\t\t\treturn (beanFactory) -> {\n\t\t\t\tboolean hasBootstrapExecutor = beanFactory\n\t\t\t\t\t.containsBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\t\tboolean hasApplicationTaskExecutor = beanFactory\n\t\t\t\t\t.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);\n\t\t\t\tif (!hasBootstrapExecutor && hasApplicationTaskExecutor) {\n\t\t\t\t\tbeanFactory.registerAlias(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME,\n\t\t\t\t\t\t\tConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class OnExecutorCondition extends AnyNestedCondition {\n\n\t\tOnExecutorCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnMissingBean(Executor.class)\n\t\tprivate static final class ExecutorBeanCondition {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(value = \"spring.task.execution.mode\", havingValue = \"force\")\n\t\tprivate static final class ModelCondition {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link AsyncConfigurer} implementation that delegates to the user-defined\n\t * {@link AsyncConfigurer} instance, if any. Consistently use the executor named\n\t * {@value TaskExecutionAutoConfiguration#APPLICATION_TASK_EXECUTOR_BEAN_NAME} in the\n\t * absence of a custom executor.\n\t */\n\tstatic class ApplicationTaskExecutorAsyncConfigurer implements AsyncConfigurer {\n\n\t\tprivate final BeanFactory beanFactory;\n\n\t\tprivate final @Nullable AsyncConfigurer delegate;\n\n\t\tApplicationTaskExecutorAsyncConfigurer(BeanFactory beanFactory, @Nullable AsyncConfigurer delegate) {\n\t\t\tthis.beanFactory = beanFactory;\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic Executor getAsyncExecutor() {\n\t\t\tExecutor executor = (this.delegate != null) ? this.delegate.getAsyncExecutor() : null;\n\t\t\treturn (executor != null) ? executor : getApplicationTaskExecutor();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {\n\t\t\treturn (this.delegate != null) ? this.delegate.getAsyncUncaughtExceptionHandler() : null;\n\t\t}\n\n\t\tprivate Executor getApplicationTaskExecutor() {\n\t\t\treturn this.beanFactory.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME,\n\t\t\t\t\tExecutor.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\nimport org.springframework.scheduling.config.TaskManagementConfigUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link TaskScheduler}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @since 2.1.0\n */\n@ConditionalOnClass(ThreadPoolTaskScheduler.class)\n@AutoConfiguration(after = TaskExecutionAutoConfiguration.class)\n@EnableConfigurationProperties(TaskSchedulingProperties.class)\n@Import({ TaskSchedulingConfigurations.ThreadPoolTaskSchedulerBuilderConfiguration.class,\n\t\tTaskSchedulingConfigurations.SimpleAsyncTaskSchedulerBuilderConfiguration.class,\n\t\tTaskSchedulingConfigurations.TaskSchedulerConfiguration.class })\npublic final class TaskSchedulingAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)\n\tstatic LazyInitializationExcludeFilter scheduledBeanLazyInitializationExcludeFilter() {\n\t\treturn new ScheduledBeanLazyInitializationExcludeFilter();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.util.List;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.task.SimpleAsyncTaskSchedulerBuilder;\nimport org.springframework.boot.task.SimpleAsyncTaskSchedulerCustomizer;\nimport org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder;\nimport org.springframework.boot.task.ThreadPoolTaskSchedulerCustomizer;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.core.task.support.CompositeTaskDecorator;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.config.TaskManagementConfigUtils;\n\n/**\n * {@link TaskScheduler} configurations to be imported by\n * {@link TaskSchedulingAutoConfiguration} in a specific order.\n *\n * @author Moritz Halbritter\n */\nclass TaskSchedulingConfigurations {\n\n\tprivate static @Nullable TaskDecorator getTaskDecorator(ObjectProvider<TaskDecorator> taskDecorator) {\n\t\tList<TaskDecorator> taskDecorators = taskDecorator.orderedStream().toList();\n\t\tif (taskDecorators.size() == 1) {\n\t\t\treturn taskDecorators.get(0);\n\t\t}\n\t\treturn (!taskDecorators.isEmpty()) ? new CompositeTaskDecorator(taskDecorators) : null;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)\n\t@ConditionalOnMissingBean({ TaskScheduler.class, ScheduledExecutorService.class })\n\t@Import(DefaultTaskSchedulerConfiguration.class)\n\tstatic class TaskSchedulerConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ThreadPoolTaskSchedulerBuilderConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tThreadPoolTaskSchedulerBuilder threadPoolTaskSchedulerBuilder(TaskSchedulingProperties properties,\n\t\t\t\tObjectProvider<TaskDecorator> taskDecorator,\n\t\t\t\tObjectProvider<ThreadPoolTaskSchedulerCustomizer> threadPoolTaskSchedulerCustomizers) {\n\t\t\tTaskSchedulingProperties.Shutdown shutdown = properties.getShutdown();\n\t\t\tThreadPoolTaskSchedulerBuilder builder = new ThreadPoolTaskSchedulerBuilder();\n\t\t\tbuilder = builder.poolSize(properties.getPool().getSize());\n\t\t\tbuilder = builder.awaitTermination(shutdown.isAwaitTermination());\n\t\t\tbuilder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());\n\t\t\tbuilder = builder.threadNamePrefix(properties.getThreadNamePrefix());\n\t\t\tbuilder = builder.taskDecorator(getTaskDecorator(taskDecorator));\n\t\t\tbuilder = builder.customizers(threadPoolTaskSchedulerCustomizers);\n\t\t\treturn builder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleAsyncTaskSchedulerBuilderConfiguration {\n\n\t\tprivate final TaskSchedulingProperties properties;\n\n\t\tprivate final ObjectProvider<TaskDecorator> taskDecorator;\n\n\t\tprivate final ObjectProvider<SimpleAsyncTaskSchedulerCustomizer> taskSchedulerCustomizers;\n\n\t\tSimpleAsyncTaskSchedulerBuilderConfiguration(TaskSchedulingProperties properties,\n\t\t\t\tObjectProvider<TaskDecorator> taskDecorator,\n\t\t\t\tObjectProvider<SimpleAsyncTaskSchedulerCustomizer> taskSchedulerCustomizers) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.taskDecorator = taskDecorator;\n\t\t\tthis.taskSchedulerCustomizers = taskSchedulerCustomizers;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnThreading(Threading.PLATFORM)\n\t\tSimpleAsyncTaskSchedulerBuilder simpleAsyncTaskSchedulerBuilder() {\n\t\t\treturn builder();\n\t\t}\n\n\t\t@Bean(name = \"simpleAsyncTaskSchedulerBuilder\")\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnThreading(Threading.VIRTUAL)\n\t\tSimpleAsyncTaskSchedulerBuilder simpleAsyncTaskSchedulerBuilderVirtualThreads() {\n\t\t\treturn builder().virtualThreads(true);\n\t\t}\n\n\t\tprivate SimpleAsyncTaskSchedulerBuilder builder() {\n\t\t\tSimpleAsyncTaskSchedulerBuilder builder = new SimpleAsyncTaskSchedulerBuilder();\n\t\t\tbuilder = builder.threadNamePrefix(this.properties.getThreadNamePrefix());\n\t\t\tbuilder = builder.taskDecorator(getTaskDecorator(this.taskDecorator));\n\t\t\tbuilder = builder.customizers(this.taskSchedulerCustomizers.orderedStream()::iterator);\n\t\t\tTaskSchedulingProperties.Simple simple = this.properties.getSimple();\n\t\t\tbuilder = builder.concurrencyLimit(simple.getConcurrencyLimit());\n\t\t\tTaskSchedulingProperties.Shutdown shutdown = this.properties.getShutdown();\n\t\t\tif (shutdown.isAwaitTermination()) {\n\t\t\t\tbuilder = builder.taskTerminationTimeout(shutdown.getAwaitTerminationPeriod());\n\t\t\t}\n\t\t\treturn builder;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/TaskSchedulingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for task scheduling.\n *\n * @author Stephane Nicoll\n * @since 2.1.0\n */\n@ConfigurationProperties(\"spring.task.scheduling\")\npublic class TaskSchedulingProperties {\n\n\tprivate final Pool pool = new Pool();\n\n\tprivate final Simple simple = new Simple();\n\n\tprivate final Shutdown shutdown = new Shutdown();\n\n\t/**\n\t * Prefix to use for the names of newly created threads.\n\t */\n\tprivate String threadNamePrefix = \"scheduling-\";\n\n\tpublic Pool getPool() {\n\t\treturn this.pool;\n\t}\n\n\tpublic Simple getSimple() {\n\t\treturn this.simple;\n\t}\n\n\tpublic Shutdown getShutdown() {\n\t\treturn this.shutdown;\n\t}\n\n\tpublic String getThreadNamePrefix() {\n\t\treturn this.threadNamePrefix;\n\t}\n\n\tpublic void setThreadNamePrefix(String threadNamePrefix) {\n\t\tthis.threadNamePrefix = threadNamePrefix;\n\t}\n\n\tpublic static class Pool {\n\n\t\t/**\n\t\t * Maximum allowed number of threads. Doesn't have an effect if virtual threads\n\t\t * are enabled.\n\t\t */\n\t\tprivate int size = 1;\n\n\t\tpublic int getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t\tpublic void setSize(int size) {\n\t\t\tthis.size = size;\n\t\t}\n\n\t}\n\n\tpublic static class Simple {\n\n\t\t/**\n\t\t * Set the maximum number of parallel accesses allowed. -1 indicates no\n\t\t * concurrency limit at all.\n\t\t */\n\t\tprivate @Nullable Integer concurrencyLimit;\n\n\t\tpublic @Nullable Integer getConcurrencyLimit() {\n\t\t\treturn this.concurrencyLimit;\n\t\t}\n\n\t\tpublic void setConcurrencyLimit(@Nullable Integer concurrencyLimit) {\n\t\t\tthis.concurrencyLimit = concurrencyLimit;\n\t\t}\n\n\t}\n\n\tpublic static class Shutdown {\n\n\t\t/**\n\t\t * Whether the executor should wait for scheduled tasks to complete on shutdown.\n\t\t */\n\t\tprivate boolean awaitTermination;\n\n\t\t/**\n\t\t * Maximum time the executor should wait for remaining tasks to complete.\n\t\t */\n\t\tprivate @Nullable Duration awaitTerminationPeriod;\n\n\t\tpublic boolean isAwaitTermination() {\n\t\t\treturn this.awaitTermination;\n\t\t}\n\n\t\tpublic void setAwaitTermination(boolean awaitTermination) {\n\t\t\tthis.awaitTermination = awaitTermination;\n\t\t}\n\n\t\tpublic @Nullable Duration getAwaitTerminationPeriod() {\n\t\t\treturn this.awaitTerminationPeriod;\n\t\t}\n\n\t\tpublic void setAwaitTerminationPeriod(@Nullable Duration awaitTerminationPeriod) {\n\t\t\tthis.awaitTerminationPeriod = awaitTerminationPeriod;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/task/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for task execution and scheduling.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.task;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/PathBasedTemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Abstract base class for {@link TemplateAvailabilityProvider} implementations that find\n * templates from paths.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 1.4.6\n */\npublic abstract class PathBasedTemplateAvailabilityProvider implements TemplateAvailabilityProvider {\n\n\tprivate final String className;\n\n\tprivate final Class<TemplateAvailabilityProperties> propertiesClass;\n\n\tprivate final String propertyPrefix;\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic PathBasedTemplateAvailabilityProvider(String className,\n\t\t\tClass<? extends TemplateAvailabilityProperties> propertiesClass, String propertyPrefix) {\n\t\tthis.className = className;\n\t\tthis.propertiesClass = (Class<TemplateAvailabilityProperties>) propertiesClass;\n\t\tthis.propertyPrefix = propertyPrefix;\n\t}\n\n\t@Override\n\tpublic boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\tResourceLoader resourceLoader) {\n\t\tif (ClassUtils.isPresent(this.className, classLoader)) {\n\t\t\tBinder binder = Binder.get(environment);\n\t\t\tTemplateAvailabilityProperties properties = binder.bindOrCreate(this.propertyPrefix, this.propertiesClass);\n\t\t\treturn isTemplateAvailable(view, resourceLoader, properties);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isTemplateAvailable(String view, ResourceLoader resourceLoader,\n\t\t\tTemplateAvailabilityProperties properties) {\n\t\tString location = properties.getPrefix() + view + properties.getSuffix();\n\t\tfor (String path : properties.getLoaderPath()) {\n\t\t\tif (resourceLoader.getResource(path + location).exists()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprotected abstract static class TemplateAvailabilityProperties {\n\n\t\tprivate String prefix;\n\n\t\tprivate String suffix;\n\n\t\tprotected TemplateAvailabilityProperties(String prefix, String suffix) {\n\t\t\tthis.prefix = prefix;\n\t\t\tthis.suffix = suffix;\n\t\t}\n\n\t\tprotected abstract List<String> getLoaderPath();\n\n\t\tpublic String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic void setPrefix(String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t\tpublic String getSuffix() {\n\t\t\treturn this.suffix;\n\t\t}\n\n\t\tpublic void setSuffix(String suffix) {\n\t\t\tthis.suffix = suffix;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * Indicates the availability of view templates for a particular templating engine such as\n * FreeMarker or Thymeleaf.\n *\n * @author Andy Wilkinson\n * @since 1.1.0\n */\n@FunctionalInterface\npublic interface TemplateAvailabilityProvider {\n\n\t/**\n\t * Returns {@code true} if a template is available for the given {@code view}.\n\t * @param view the view name\n\t * @param environment the environment\n\t * @param classLoader the class loader\n\t * @param resourceLoader the resource loader\n\t * @return if the template is available\n\t */\n\tboolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\tResourceLoader resourceLoader);\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateAvailabilityProviders.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.Assert;\n\n/**\n * Collection of {@link TemplateAvailabilityProvider} beans that can be used to check\n * which (if any) templating engine supports a given view. Caches responses unless the\n * {@code spring.template.provider.cache} property is set to {@code false}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 1.4.0\n */\npublic class TemplateAvailabilityProviders {\n\n\tprivate final List<TemplateAvailabilityProvider> providers;\n\n\tprivate static final int CACHE_LIMIT = 1024;\n\n\tprivate static final TemplateAvailabilityProvider NONE = new NoTemplateAvailabilityProvider();\n\n\t/**\n\t * Resolved template views, returning already cached instances without a global lock.\n\t */\n\tprivate final Map<String, TemplateAvailabilityProvider> resolved = new ConcurrentHashMap<>(CACHE_LIMIT);\n\n\t/**\n\t * Map from view name resolve template view, synchronized when accessed.\n\t */\n\tprivate final Map<String, TemplateAvailabilityProvider> cache = new LinkedHashMap<>(CACHE_LIMIT, 0.75f, true) {\n\n\t\t@Override\n\t\tprotected boolean removeEldestEntry(Map.Entry<String, TemplateAvailabilityProvider> eldest) {\n\t\t\tif (size() > CACHE_LIMIT) {\n\t\t\t\tTemplateAvailabilityProviders.this.resolved.remove(eldest.getKey());\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t};\n\n\t/**\n\t * Create a new {@link TemplateAvailabilityProviders} instance.\n\t * @param applicationContext the source application context\n\t */\n\tpublic TemplateAvailabilityProviders(ApplicationContext applicationContext) {\n\t\tthis(getClassLoader(applicationContext));\n\t}\n\n\tprivate static ClassLoader getClassLoader(ApplicationContext applicationContext) {\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tClassLoader classLoader = applicationContext.getClassLoader();\n\t\tAssert.state(classLoader != null, \"'classLoader' must not be null\");\n\t\treturn classLoader;\n\t}\n\n\t/**\n\t * Create a new {@link TemplateAvailabilityProviders} instance.\n\t * @param classLoader the source class loader\n\t */\n\tpublic TemplateAvailabilityProviders(ClassLoader classLoader) {\n\t\tAssert.notNull(classLoader, \"'classLoader' must not be null\");\n\t\tthis.providers = SpringFactoriesLoader.loadFactories(TemplateAvailabilityProvider.class, classLoader);\n\t}\n\n\t/**\n\t * Create a new {@link TemplateAvailabilityProviders} instance.\n\t * @param providers the underlying providers\n\t */\n\tprotected TemplateAvailabilityProviders(Collection<? extends TemplateAvailabilityProvider> providers) {\n\t\tAssert.notNull(providers, \"'providers' must not be null\");\n\t\tthis.providers = new ArrayList<>(providers);\n\t}\n\n\t/**\n\t * Return the underlying providers being used.\n\t * @return the providers being used\n\t */\n\tpublic List<TemplateAvailabilityProvider> getProviders() {\n\t\treturn this.providers;\n\t}\n\n\t/**\n\t * Get the provider that can be used to render the given view.\n\t * @param view the view to render\n\t * @param applicationContext the application context\n\t * @return a {@link TemplateAvailabilityProvider} or null\n\t */\n\tpublic @Nullable TemplateAvailabilityProvider getProvider(String view, ApplicationContext applicationContext) {\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tClassLoader classLoader = applicationContext.getClassLoader();\n\t\tAssert.state(classLoader != null, \"'classLoader' must not be null\");\n\t\treturn getProvider(view, applicationContext.getEnvironment(), classLoader, applicationContext);\n\t}\n\n\t/**\n\t * Get the provider that can be used to render the given view.\n\t * @param view the view to render\n\t * @param environment the environment\n\t * @param classLoader the class loader\n\t * @param resourceLoader the resource loader\n\t * @return a {@link TemplateAvailabilityProvider} or null\n\t */\n\tpublic @Nullable TemplateAvailabilityProvider getProvider(String view, Environment environment,\n\t\t\tClassLoader classLoader, ResourceLoader resourceLoader) {\n\t\tAssert.notNull(view, \"'view' must not be null\");\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tAssert.notNull(classLoader, \"'classLoader' must not be null\");\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\tBoolean useCache = environment.getProperty(\"spring.template.provider.cache\", Boolean.class, true);\n\t\tif (!useCache) {\n\t\t\treturn findProvider(view, environment, classLoader, resourceLoader);\n\t\t}\n\t\tTemplateAvailabilityProvider provider = this.resolved.get(view);\n\t\tif (provider == null) {\n\t\t\tsynchronized (this.cache) {\n\t\t\t\tprovider = findProvider(view, environment, classLoader, resourceLoader);\n\t\t\t\tprovider = (provider != null) ? provider : NONE;\n\t\t\t\tthis.resolved.put(view, provider);\n\t\t\t\tthis.cache.put(view, provider);\n\t\t\t}\n\t\t}\n\t\treturn (provider != NONE) ? provider : null;\n\t}\n\n\tprivate @Nullable TemplateAvailabilityProvider findProvider(String view, Environment environment,\n\t\t\tClassLoader classLoader, ResourceLoader resourceLoader) {\n\t\tfor (TemplateAvailabilityProvider candidate : this.providers) {\n\t\t\tif (candidate.isTemplateAvailable(view, environment, classLoader, resourceLoader)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static final class NoTemplateAvailabilityProvider implements TemplateAvailabilityProvider {\n\n\t\t@Override\n\t\tpublic boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\t\tResourceLoader resourceLoader) {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateLocation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport java.io.IOException;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.util.Assert;\n\n/**\n * Contains a location that templates can be loaded from.\n *\n * @author Phillip Webb\n * @since 1.2.1\n */\npublic class TemplateLocation {\n\n\tprivate final String path;\n\n\tpublic TemplateLocation(String path) {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tthis.path = path;\n\t}\n\n\t/**\n\t * Determine if this template location exists using the specified\n\t * {@link ResourcePatternResolver}.\n\t * @param resolver the resolver used to test if the location exists\n\t * @return {@code true} if the location exists.\n\t */\n\tpublic boolean exists(ResourcePatternResolver resolver) {\n\t\tAssert.notNull(resolver, \"'resolver' must not be null\");\n\t\tif (resolver.getResource(this.path).exists()) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\treturn anyExists(resolver);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean anyExists(ResourcePatternResolver resolver) throws IOException {\n\t\tString searchPath = this.path;\n\t\tif (searchPath.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX)) {\n\t\t\tsearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX\n\t\t\t\t\t+ searchPath.substring(ResourceLoader.CLASSPATH_URL_PREFIX.length());\n\t\t}\n\t\tif (searchPath.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {\n\t\t\tResource[] resources = resolver.getResources(searchPath);\n\t\t\tfor (Resource resource : resources) {\n\t\t\t\tif (resource.exists()) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.path;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * {@link RuntimeHintsRegistrar} for default template location.\n *\n * @author Stephane Nicoll\n */\nclass TemplateRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\thints.resources().registerPatternIfPresent(classLoader, \"templates\", (hint) -> hint.includes(\"templates/**\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Base classes for template Auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.template;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ConditionalOnEnabledResourceChain.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether the Spring resource handling chain\n * is enabled. Matches if {@link WebProperties.Resources.Chain#getEnabled()} is\n * {@code true} or if one of {@code \"org.webjars:webjars-locator-core\"},\n * {@code \"org.webjars:webjars-locator-lite\"} is on the classpath.\n * <p>\n * Note that support for {@code \"org.webjars:webjars-locator-core\"} is deprecated.\n *\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnEnabledResourceChainCondition.class)\npublic @interface ConditionalOnEnabledResourceChain {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Configuration properties for web error handling.\n *\n * @author Michael Stummvoll\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Scott Frederick\n * @since 1.3.0\n */\npublic class ErrorProperties {\n\n\t/**\n\t * Path of the error controller.\n\t */\n\t@Value(\"${error.path:/error}\")\n\tprivate String path = \"/error\";\n\n\t/**\n\t * Include the \"exception\" attribute.\n\t */\n\tprivate boolean includeException;\n\n\t/**\n\t * When to include the \"trace\" attribute.\n\t */\n\tprivate IncludeAttribute includeStacktrace = IncludeAttribute.NEVER;\n\n\t/**\n\t * When to include \"message\" attribute.\n\t */\n\tprivate IncludeAttribute includeMessage = IncludeAttribute.NEVER;\n\n\t/**\n\t * When to include \"errors\" attribute.\n\t */\n\tprivate IncludeAttribute includeBindingErrors = IncludeAttribute.NEVER;\n\n\t/**\n\t * When to include \"path\" attribute.\n\t */\n\tprivate IncludeAttribute includePath = IncludeAttribute.ALWAYS;\n\n\tprivate final Whitelabel whitelabel = new Whitelabel();\n\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\tpublic void setPath(String path) {\n\t\tthis.path = path;\n\t}\n\n\tpublic boolean isIncludeException() {\n\t\treturn this.includeException;\n\t}\n\n\tpublic void setIncludeException(boolean includeException) {\n\t\tthis.includeException = includeException;\n\t}\n\n\tpublic IncludeAttribute getIncludeStacktrace() {\n\t\treturn this.includeStacktrace;\n\t}\n\n\tpublic void setIncludeStacktrace(IncludeAttribute includeStacktrace) {\n\t\tthis.includeStacktrace = includeStacktrace;\n\t}\n\n\tpublic IncludeAttribute getIncludeMessage() {\n\t\treturn this.includeMessage;\n\t}\n\n\tpublic void setIncludeMessage(IncludeAttribute includeMessage) {\n\t\tthis.includeMessage = includeMessage;\n\t}\n\n\tpublic IncludeAttribute getIncludeBindingErrors() {\n\t\treturn this.includeBindingErrors;\n\t}\n\n\tpublic void setIncludeBindingErrors(IncludeAttribute includeBindingErrors) {\n\t\tthis.includeBindingErrors = includeBindingErrors;\n\t}\n\n\tpublic IncludeAttribute getIncludePath() {\n\t\treturn this.includePath;\n\t}\n\n\tpublic void setIncludePath(IncludeAttribute includePath) {\n\t\tthis.includePath = includePath;\n\t}\n\n\tpublic Whitelabel getWhitelabel() {\n\t\treturn this.whitelabel;\n\t}\n\n\t/**\n\t * Include error attributes options.\n\t */\n\tpublic enum IncludeAttribute {\n\n\t\t/**\n\t\t * Never add error attribute.\n\t\t */\n\t\tNEVER,\n\n\t\t/**\n\t\t * Always add error attribute.\n\t\t */\n\t\tALWAYS,\n\n\t\t/**\n\t\t * Add error attribute when the appropriate request parameter is not \"false\".\n\t\t */\n\t\tON_PARAM\n\n\t}\n\n\tpublic static class Whitelabel {\n\n\t\t/**\n\t\t * Whether to enable the default error page displayed in browsers in case of a\n\t\t * server error.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/OnEnabledResourceChainCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources.Chain;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link Condition} that checks whether the Spring resource handling chain is enabled.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Brian Clozel\n * @see ConditionalOnEnabledResourceChain\n */\nclass OnEnabledResourceChainCondition extends SpringBootCondition {\n\n\tprivate static final String WEBJAR_ASSET_LOCATOR = \"org.webjars.WebJarAssetLocator\";\n\n\tprivate static final String WEBJAR_VERSION_LOCATOR = \"org.webjars.WebJarVersionLocator\";\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();\n\t\tboolean fixed = getEnabledProperty(environment, \"strategy.fixed.\", false);\n\t\tboolean content = getEnabledProperty(environment, \"strategy.content.\", false);\n\t\tBoolean chain = getEnabledProperty(environment, \"\", null);\n\t\tBoolean match = Chain.getEnabled(fixed, content, chain);\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnEnabledResourceChain.class);\n\t\tif (match == null) {\n\t\t\tif (ClassUtils.isPresent(WEBJAR_VERSION_LOCATOR, getClass().getClassLoader())) {\n\t\t\t\treturn ConditionOutcome.match(message.found(\"class\").items(WEBJAR_VERSION_LOCATOR));\n\t\t\t}\n\t\t\tif (ClassUtils.isPresent(WEBJAR_ASSET_LOCATOR, getClass().getClassLoader())) {\n\t\t\t\treturn ConditionOutcome.match(message.found(\"class\").items(WEBJAR_ASSET_LOCATOR));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"class\").items(WEBJAR_VERSION_LOCATOR));\n\t\t}\n\t\tif (match) {\n\t\t\treturn ConditionOutcome.match(message.because(\"enabled\"));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.because(\"disabled\"));\n\t}\n\n\t@Contract(\"_, _, !null -> !null\")\n\tprivate @Nullable Boolean getEnabledProperty(ConfigurableEnvironment environment, String key,\n\t\t\t@Nullable Boolean defaultValue) {\n\t\tString name = \"spring.web.resources.chain.\" + key + \"enabled\";\n\t\tif (defaultValue == null) {\n\t\t\treturn environment.getProperty(name, Boolean.class);\n\t\t}\n\t\treturn environment.getProperty(name, Boolean.class, defaultValue);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Locale;\nimport java.util.concurrent.TimeUnit;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.http.CacheControl;\n\n/**\n * {@link ConfigurationProperties Configuration properties} for general web concerns.\n *\n * @author Andy Wilkinson\n * @since 2.4.0\n */\n@ConfigurationProperties(\"spring.web\")\npublic class WebProperties {\n\n\t/**\n\t * Locale to use. By default, this locale is overridden by the \"Accept-Language\"\n\t * header.\n\t */\n\tprivate @Nullable Locale locale;\n\n\t/**\n\t * Define how the locale should be resolved.\n\t */\n\tprivate LocaleResolver localeResolver = LocaleResolver.ACCEPT_HEADER;\n\n\tprivate final Resources resources = new Resources();\n\n\t@NestedConfigurationProperty\n\tprivate final ErrorProperties error = new ErrorProperties();\n\n\tpublic @Nullable Locale getLocale() {\n\t\treturn this.locale;\n\t}\n\n\tpublic void setLocale(@Nullable Locale locale) {\n\t\tthis.locale = locale;\n\t}\n\n\tpublic LocaleResolver getLocaleResolver() {\n\t\treturn this.localeResolver;\n\t}\n\n\tpublic void setLocaleResolver(LocaleResolver localeResolver) {\n\t\tthis.localeResolver = localeResolver;\n\t}\n\n\tpublic ErrorProperties getError() {\n\t\treturn this.error;\n\t}\n\n\tpublic Resources getResources() {\n\t\treturn this.resources;\n\t}\n\n\tpublic enum LocaleResolver {\n\n\t\t/**\n\t\t * Always use the configured locale.\n\t\t */\n\t\tFIXED,\n\n\t\t/**\n\t\t * Use the \"Accept-Language\" header or the configured locale if the header is not\n\t\t * set.\n\t\t */\n\t\tACCEPT_HEADER\n\n\t}\n\n\tpublic static class Resources {\n\n\t\tprivate static final String[] CLASSPATH_RESOURCE_LOCATIONS = { \"classpath:/META-INF/resources/\",\n\t\t\t\t\"classpath:/resources/\", \"classpath:/static/\", \"classpath:/public/\" };\n\n\t\t/**\n\t\t * Locations of static resources. Defaults to classpath:[/META-INF/resources/,\n\t\t * /resources/, /static/, /public/].\n\t\t */\n\t\tprivate String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;\n\n\t\t/**\n\t\t * Whether to enable default resource handling.\n\t\t */\n\t\tprivate boolean addMappings = true;\n\n\t\tprivate boolean customized;\n\n\t\tprivate final Chain chain = new Chain();\n\n\t\tprivate final Cache cache = new Cache();\n\n\t\tpublic String[] getStaticLocations() {\n\t\t\treturn this.staticLocations;\n\t\t}\n\n\t\tpublic void setStaticLocations(String[] staticLocations) {\n\t\t\tthis.staticLocations = appendSlashIfNecessary(staticLocations);\n\t\t\tthis.customized = true;\n\t\t}\n\n\t\tprivate String[] appendSlashIfNecessary(String[] staticLocations) {\n\t\t\tString[] normalized = new String[staticLocations.length];\n\t\t\tfor (int i = 0; i < staticLocations.length; i++) {\n\t\t\t\tString location = staticLocations[i];\n\t\t\t\tnormalized[i] = location.endsWith(\"/\") ? location : location + \"/\";\n\t\t\t}\n\t\t\treturn normalized;\n\t\t}\n\n\t\tpublic boolean isAddMappings() {\n\t\t\treturn this.addMappings;\n\t\t}\n\n\t\tpublic void setAddMappings(boolean addMappings) {\n\t\t\tthis.customized = true;\n\t\t\tthis.addMappings = addMappings;\n\t\t}\n\n\t\tpublic Chain getChain() {\n\t\t\treturn this.chain;\n\t\t}\n\n\t\tpublic Cache getCache() {\n\t\t\treturn this.cache;\n\t\t}\n\n\t\tpublic boolean hasBeenCustomized() {\n\t\t\treturn this.customized || getChain().hasBeenCustomized() || getCache().hasBeenCustomized();\n\t\t}\n\n\t\t/**\n\t\t * Configuration for the Spring Resource Handling chain.\n\t\t */\n\t\tpublic static class Chain {\n\n\t\t\tboolean customized;\n\n\t\t\t/**\n\t\t\t * Whether to enable the Spring Resource Handling chain. By default, disabled\n\t\t\t * unless at least one strategy has been enabled.\n\t\t\t */\n\t\t\tprivate @Nullable Boolean enabled;\n\n\t\t\t/**\n\t\t\t * Whether to enable caching in the Resource chain.\n\t\t\t */\n\t\t\tprivate boolean cache = true;\n\n\t\t\t/**\n\t\t\t * Whether to enable resolution of already compressed resources (gzip,\n\t\t\t * brotli). Checks for a resource name with the '.gz' or '.br' file\n\t\t\t * extensions.\n\t\t\t */\n\t\t\tprivate boolean compressed;\n\n\t\t\tprivate final Strategy strategy = new Strategy();\n\n\t\t\t/**\n\t\t\t * Return whether the resource chain is enabled. Return {@code null} if no\n\t\t\t * specific settings are present.\n\t\t\t * @return whether the resource chain is enabled or {@code null} if no\n\t\t\t * specified settings are present.\n\t\t\t */\n\t\t\tpublic @Nullable Boolean getEnabled() {\n\t\t\t\treturn getEnabled(getStrategy().getFixed().isEnabled(), getStrategy().getContent().isEnabled(),\n\t\t\t\t\t\tthis.enabled);\n\t\t\t}\n\n\t\t\tprivate boolean hasBeenCustomized() {\n\t\t\t\treturn this.customized || getStrategy().hasBeenCustomized();\n\t\t\t}\n\n\t\t\tpublic void setEnabled(Boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t\tthis.customized = true;\n\t\t\t}\n\n\t\t\tpublic boolean isCache() {\n\t\t\t\treturn this.cache;\n\t\t\t}\n\n\t\t\tpublic void setCache(boolean cache) {\n\t\t\t\tthis.cache = cache;\n\t\t\t\tthis.customized = true;\n\t\t\t}\n\n\t\t\tpublic Strategy getStrategy() {\n\t\t\t\treturn this.strategy;\n\t\t\t}\n\n\t\t\tpublic boolean isCompressed() {\n\t\t\t\treturn this.compressed;\n\t\t\t}\n\n\t\t\tpublic void setCompressed(boolean compressed) {\n\t\t\t\tthis.compressed = compressed;\n\t\t\t\tthis.customized = true;\n\t\t\t}\n\n\t\t\tstatic @Nullable Boolean getEnabled(boolean fixedEnabled, boolean contentEnabled,\n\t\t\t\t\t@Nullable Boolean chainEnabled) {\n\t\t\t\treturn (fixedEnabled || contentEnabled) ? Boolean.TRUE : chainEnabled;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Strategies for extracting and embedding a resource version in its URL path.\n\t\t\t */\n\t\t\tpublic static class Strategy {\n\n\t\t\t\tprivate final Fixed fixed = new Fixed();\n\n\t\t\t\tprivate final Content content = new Content();\n\n\t\t\t\tpublic Fixed getFixed() {\n\t\t\t\t\treturn this.fixed;\n\t\t\t\t}\n\n\t\t\t\tpublic Content getContent() {\n\t\t\t\t\treturn this.content;\n\t\t\t\t}\n\n\t\t\t\tprivate boolean hasBeenCustomized() {\n\t\t\t\t\treturn getFixed().hasBeenCustomized() || getContent().hasBeenCustomized();\n\t\t\t\t}\n\n\t\t\t\t/**\n\t\t\t\t * Version Strategy based on content hashing.\n\t\t\t\t */\n\t\t\t\tpublic static class Content {\n\n\t\t\t\t\tprivate boolean customized;\n\n\t\t\t\t\t/**\n\t\t\t\t\t * Whether to enable the content Version Strategy.\n\t\t\t\t\t */\n\t\t\t\t\tprivate boolean enabled;\n\n\t\t\t\t\t/**\n\t\t\t\t\t * List of patterns to apply to the content Version Strategy.\n\t\t\t\t\t */\n\t\t\t\t\tprivate String[] paths = new String[] { \"/**\" };\n\n\t\t\t\t\tpublic boolean isEnabled() {\n\t\t\t\t\t\treturn this.enabled;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\t\t\tthis.customized = true;\n\t\t\t\t\t\tthis.enabled = enabled;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic String[] getPaths() {\n\t\t\t\t\t\treturn this.paths;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic void setPaths(String[] paths) {\n\t\t\t\t\t\tthis.customized = true;\n\t\t\t\t\t\tthis.paths = paths;\n\t\t\t\t\t}\n\n\t\t\t\t\tprivate boolean hasBeenCustomized() {\n\t\t\t\t\t\treturn this.customized;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t/**\n\t\t\t\t * Version Strategy based on a fixed version string.\n\t\t\t\t */\n\t\t\t\tpublic static class Fixed {\n\n\t\t\t\t\tprivate boolean customized;\n\n\t\t\t\t\t/**\n\t\t\t\t\t * Whether to enable the fixed Version Strategy.\n\t\t\t\t\t */\n\t\t\t\t\tprivate boolean enabled;\n\n\t\t\t\t\t/**\n\t\t\t\t\t * List of patterns to apply to the fixed Version Strategy.\n\t\t\t\t\t */\n\t\t\t\t\tprivate String[] paths = new String[] { \"/**\" };\n\n\t\t\t\t\t/**\n\t\t\t\t\t * Version string to use for the fixed Version Strategy.\n\t\t\t\t\t */\n\t\t\t\t\tprivate @Nullable String version;\n\n\t\t\t\t\tpublic boolean isEnabled() {\n\t\t\t\t\t\treturn this.enabled;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\t\t\tthis.customized = true;\n\t\t\t\t\t\tthis.enabled = enabled;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic String[] getPaths() {\n\t\t\t\t\t\treturn this.paths;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic void setPaths(String[] paths) {\n\t\t\t\t\t\tthis.customized = true;\n\t\t\t\t\t\tthis.paths = paths;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic @Nullable String getVersion() {\n\t\t\t\t\t\treturn this.version;\n\t\t\t\t\t}\n\n\t\t\t\t\tpublic void setVersion(@Nullable String version) {\n\t\t\t\t\t\tthis.customized = true;\n\t\t\t\t\t\tthis.version = version;\n\t\t\t\t\t}\n\n\t\t\t\t\tprivate boolean hasBeenCustomized() {\n\t\t\t\t\t\treturn this.customized;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Cache configuration.\n\t\t */\n\t\tpublic static class Cache {\n\n\t\t\tprivate boolean customized;\n\n\t\t\t/**\n\t\t\t * Cache period for the resources served by the resource handler. If a\n\t\t\t * duration suffix is not specified, seconds will be used. Can be overridden\n\t\t\t * by the 'spring.web.resources.cache.cachecontrol' properties.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate @Nullable Duration period;\n\n\t\t\t/**\n\t\t\t * Cache control HTTP headers, only allows valid directive combinations.\n\t\t\t * Overrides the 'spring.web.resources.cache.period' property.\n\t\t\t */\n\t\t\tprivate final Cachecontrol cachecontrol = new Cachecontrol();\n\n\t\t\t/**\n\t\t\t * Whether we should use the \"lastModified\" metadata of the files in HTTP\n\t\t\t * caching headers.\n\t\t\t */\n\t\t\tprivate boolean useLastModified = true;\n\n\t\t\tpublic @Nullable Duration getPeriod() {\n\t\t\t\treturn this.period;\n\t\t\t}\n\n\t\t\tpublic void setPeriod(@Nullable Duration period) {\n\t\t\t\tthis.customized = true;\n\t\t\t\tthis.period = period;\n\t\t\t}\n\n\t\t\tpublic Cachecontrol getCachecontrol() {\n\t\t\t\treturn this.cachecontrol;\n\t\t\t}\n\n\t\t\tpublic boolean isUseLastModified() {\n\t\t\t\treturn this.useLastModified;\n\t\t\t}\n\n\t\t\tpublic void setUseLastModified(boolean useLastModified) {\n\t\t\t\tthis.useLastModified = useLastModified;\n\t\t\t}\n\n\t\t\tprivate boolean hasBeenCustomized() {\n\t\t\t\treturn this.customized || getCachecontrol().hasBeenCustomized();\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Cache Control HTTP header configuration.\n\t\t\t */\n\t\t\tpublic static class Cachecontrol {\n\n\t\t\t\tprivate boolean customized;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum time the response should be cached, in seconds if no duration\n\t\t\t\t * suffix is not specified.\n\t\t\t\t */\n\t\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\t\tprivate @Nullable Duration maxAge;\n\n\t\t\t\t/**\n\t\t\t\t * Indicate that the cached response can be reused only if re-validated\n\t\t\t\t * with the server.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean noCache;\n\n\t\t\t\t/**\n\t\t\t\t * Indicate to not cache the response in any case.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean noStore;\n\n\t\t\t\t/**\n\t\t\t\t * Indicate that once it has become stale, a cache must not use the\n\t\t\t\t * response without re-validating it with the server.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean mustRevalidate;\n\n\t\t\t\t/**\n\t\t\t\t * Indicate intermediaries (caches and others) that they should not\n\t\t\t\t * transform the response content.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean noTransform;\n\n\t\t\t\t/**\n\t\t\t\t * Indicate that any cache may store the response.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean cachePublic;\n\n\t\t\t\t/**\n\t\t\t\t * Indicate that the response message is intended for a single user and\n\t\t\t\t * must not be stored by a shared cache.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean cachePrivate;\n\n\t\t\t\t/**\n\t\t\t\t * Same meaning as the \"must-revalidate\" directive, except that it does\n\t\t\t\t * not apply to private caches.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Boolean proxyRevalidate;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum time the response can be served after it becomes stale, in\n\t\t\t\t * seconds if no duration suffix is not specified.\n\t\t\t\t */\n\t\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\t\tprivate @Nullable Duration staleWhileRevalidate;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum time the response may be used when errors are encountered, in\n\t\t\t\t * seconds if no duration suffix is not specified.\n\t\t\t\t */\n\t\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\t\tprivate @Nullable Duration staleIfError;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum time the response should be cached by shared caches, in seconds\n\t\t\t\t * if no duration suffix is not specified.\n\t\t\t\t */\n\t\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\t\tprivate @Nullable Duration sMaxAge;\n\n\t\t\t\tpublic @Nullable Duration getMaxAge() {\n\t\t\t\t\treturn this.maxAge;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxAge(@Nullable Duration maxAge) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.maxAge = maxAge;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getNoCache() {\n\t\t\t\t\treturn this.noCache;\n\t\t\t\t}\n\n\t\t\t\tpublic void setNoCache(@Nullable Boolean noCache) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.noCache = noCache;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getNoStore() {\n\t\t\t\t\treturn this.noStore;\n\t\t\t\t}\n\n\t\t\t\tpublic void setNoStore(@Nullable Boolean noStore) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.noStore = noStore;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getMustRevalidate() {\n\t\t\t\t\treturn this.mustRevalidate;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMustRevalidate(@Nullable Boolean mustRevalidate) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.mustRevalidate = mustRevalidate;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getNoTransform() {\n\t\t\t\t\treturn this.noTransform;\n\t\t\t\t}\n\n\t\t\t\tpublic void setNoTransform(@Nullable Boolean noTransform) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.noTransform = noTransform;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getCachePublic() {\n\t\t\t\t\treturn this.cachePublic;\n\t\t\t\t}\n\n\t\t\t\tpublic void setCachePublic(@Nullable Boolean cachePublic) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.cachePublic = cachePublic;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getCachePrivate() {\n\t\t\t\t\treturn this.cachePrivate;\n\t\t\t\t}\n\n\t\t\t\tpublic void setCachePrivate(@Nullable Boolean cachePrivate) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.cachePrivate = cachePrivate;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Boolean getProxyRevalidate() {\n\t\t\t\t\treturn this.proxyRevalidate;\n\t\t\t\t}\n\n\t\t\t\tpublic void setProxyRevalidate(@Nullable Boolean proxyRevalidate) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.proxyRevalidate = proxyRevalidate;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Duration getStaleWhileRevalidate() {\n\t\t\t\t\treturn this.staleWhileRevalidate;\n\t\t\t\t}\n\n\t\t\t\tpublic void setStaleWhileRevalidate(@Nullable Duration staleWhileRevalidate) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.staleWhileRevalidate = staleWhileRevalidate;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Duration getStaleIfError() {\n\t\t\t\t\treturn this.staleIfError;\n\t\t\t\t}\n\n\t\t\t\tpublic void setStaleIfError(@Nullable Duration staleIfError) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.staleIfError = staleIfError;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Duration getSMaxAge() {\n\t\t\t\t\treturn this.sMaxAge;\n\t\t\t\t}\n\n\t\t\t\tpublic void setSMaxAge(@Nullable Duration sMaxAge) {\n\t\t\t\t\tthis.customized = true;\n\t\t\t\t\tthis.sMaxAge = sMaxAge;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable CacheControl toHttpCacheControl() {\n\t\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\t\tCacheControl control = createCacheControl();\n\t\t\t\t\tmap.from(this::getMustRevalidate).whenTrue().toCall(control::mustRevalidate);\n\t\t\t\t\tmap.from(this::getNoTransform).whenTrue().toCall(control::noTransform);\n\t\t\t\t\tmap.from(this::getCachePublic).whenTrue().toCall(control::cachePublic);\n\t\t\t\t\tmap.from(this::getCachePrivate).whenTrue().toCall(control::cachePrivate);\n\t\t\t\t\tmap.from(this::getProxyRevalidate).whenTrue().toCall(control::proxyRevalidate);\n\t\t\t\t\tmap.from(this::getStaleWhileRevalidate)\n\t\t\t\t\t\t.to((duration) -> control.staleWhileRevalidate(duration.getSeconds(), TimeUnit.SECONDS));\n\t\t\t\t\tmap.from(this::getStaleIfError)\n\t\t\t\t\t\t.to((duration) -> control.staleIfError(duration.getSeconds(), TimeUnit.SECONDS));\n\t\t\t\t\tmap.from(this::getSMaxAge)\n\t\t\t\t\t\t.to((duration) -> control.sMaxAge(duration.getSeconds(), TimeUnit.SECONDS));\n\t\t\t\t\t// check if cacheControl remained untouched\n\t\t\t\t\tif (control.getHeaderValue() == null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\treturn control;\n\t\t\t\t}\n\n\t\t\t\tprivate CacheControl createCacheControl() {\n\t\t\t\t\tif (Boolean.TRUE.equals(this.noStore)) {\n\t\t\t\t\t\treturn CacheControl.noStore();\n\t\t\t\t\t}\n\t\t\t\t\tif (Boolean.TRUE.equals(this.noCache)) {\n\t\t\t\t\t\treturn CacheControl.noCache();\n\t\t\t\t\t}\n\t\t\t\t\tif (this.maxAge != null) {\n\t\t\t\t\t\treturn CacheControl.maxAge(this.maxAge.getSeconds(), TimeUnit.SECONDS);\n\t\t\t\t\t}\n\t\t\t\t\treturn CacheControl.empty();\n\t\t\t\t}\n\n\t\t\t\tprivate boolean hasBeenCustomized() {\n\t\t\t\t\treturn this.customized;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebResourcesRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * {@link RuntimeHintsRegistrar} for default locations of web resources.\n *\n * @author Stephane Nicoll\n * @since 3.0.0\n */\npublic class WebResourcesRuntimeHints implements RuntimeHintsRegistrar {\n\n\tprivate static final List<String> DEFAULT_LOCATIONS = List.of(\"META-INF/resources/\", \"resources/\", \"static/\",\n\t\t\t\"public/\");\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tClassLoader classLoaderToUse = (classLoader != null) ? classLoader : getClass().getClassLoader();\n\t\tString[] locations = DEFAULT_LOCATIONS.stream()\n\t\t\t.filter((candidate) -> classLoaderToUse.getResource(candidate) != null)\n\t\t\t.map((location) -> location + \"**\")\n\t\t\t.toArray(String[]::new);\n\t\tif (locations.length > 0) {\n\t\t\thints.resources().registerPattern((hint) -> hint.includes(locations));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/DateTimeFormatters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web.format;\n\nimport java.time.format.DateTimeFormatter;\nimport java.time.format.ResolverStyle;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link DateTimeFormatter Formatters} for dates, times, and date-times.\n *\n * @author Andy Wilkinson\n * @author Gaurav Pareek\n * @since 2.3.0\n */\npublic class DateTimeFormatters {\n\n\tprivate @Nullable DateTimeFormatter dateFormatter;\n\n\tprivate @Nullable String datePattern;\n\n\tprivate @Nullable DateTimeFormatter timeFormatter;\n\n\tprivate @Nullable DateTimeFormatter dateTimeFormatter;\n\n\t/**\n\t * Configures the date format using the given {@code pattern}.\n\t * @param pattern the pattern for formatting dates\n\t * @return {@code this} for chained method invocation\n\t */\n\tpublic DateTimeFormatters dateFormat(@Nullable String pattern) {\n\t\tif (isIso(pattern)) {\n\t\t\tthis.dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE;\n\t\t\tthis.datePattern = \"yyyy-MM-dd\";\n\t\t}\n\t\telse {\n\t\t\tthis.dateFormatter = formatter(pattern);\n\t\t\tthis.datePattern = pattern;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Configures the time format using the given {@code pattern}.\n\t * @param pattern the pattern for formatting times\n\t * @return {@code this} for chained method invocation\n\t */\n\tpublic DateTimeFormatters timeFormat(@Nullable String pattern) {\n\t\tthis.timeFormatter = isIso(pattern) ? DateTimeFormatter.ISO_LOCAL_TIME\n\t\t\t\t: (isIsoOffset(pattern) ? DateTimeFormatter.ISO_OFFSET_TIME : formatter(pattern));\n\t\treturn this;\n\t}\n\n\t/**\n\t * Configures the date-time format using the given {@code pattern}.\n\t * @param pattern the pattern for formatting date-times\n\t * @return {@code this} for chained method invocation\n\t */\n\tpublic DateTimeFormatters dateTimeFormat(@Nullable String pattern) {\n\t\tthis.dateTimeFormatter = isIso(pattern) ? DateTimeFormatter.ISO_LOCAL_DATE_TIME\n\t\t\t\t: (isIsoOffset(pattern) ? DateTimeFormatter.ISO_OFFSET_DATE_TIME : formatter(pattern));\n\t\treturn this;\n\t}\n\n\t@Nullable DateTimeFormatter getDateFormatter() {\n\t\treturn this.dateFormatter;\n\t}\n\n\t@Nullable String getDatePattern() {\n\t\treturn this.datePattern;\n\t}\n\n\t@Nullable DateTimeFormatter getTimeFormatter() {\n\t\treturn this.timeFormatter;\n\t}\n\n\t@Nullable DateTimeFormatter getDateTimeFormatter() {\n\t\treturn this.dateTimeFormatter;\n\t}\n\n\tboolean isCustomized() {\n\t\treturn this.dateFormatter != null || this.timeFormatter != null || this.dateTimeFormatter != null;\n\t}\n\n\tprivate static @Nullable DateTimeFormatter formatter(@Nullable String pattern) {\n\t\treturn StringUtils.hasText(pattern)\n\t\t\t\t? DateTimeFormatter.ofPattern(pattern).withResolverStyle(ResolverStyle.SMART) : null;\n\t}\n\n\tprivate static boolean isIso(@Nullable String pattern) {\n\t\treturn \"iso\".equalsIgnoreCase(pattern);\n\t}\n\n\tprivate static boolean isIsoOffset(@Nullable String pattern) {\n\t\treturn \"isooffset\".equalsIgnoreCase(pattern) || \"iso-offset\".equalsIgnoreCase(pattern);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web.format;\n\nimport java.time.format.DateTimeFormatter;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.format.datetime.DateFormatter;\nimport org.springframework.format.datetime.DateFormatterRegistrar;\nimport org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;\nimport org.springframework.format.number.NumberFormatAnnotationFormatterFactory;\nimport org.springframework.format.number.money.CurrencyUnitFormatter;\nimport org.springframework.format.number.money.Jsr354NumberFormatAnnotationFormatterFactory;\nimport org.springframework.format.number.money.MonetaryAmountFormatter;\nimport org.springframework.format.support.DefaultFormattingConversionService;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link org.springframework.format.support.FormattingConversionService} dedicated to web\n * applications for formatting and converting values to/from the web.\n *\n * @author Brian Clozel\n * @since 2.0.0\n */\npublic class WebConversionService extends DefaultFormattingConversionService {\n\n\tprivate static final boolean JSR_354_PRESENT = ClassUtils.isPresent(\"javax.money.MonetaryAmount\",\n\t\t\tWebConversionService.class.getClassLoader());\n\n\t/**\n\t * Create a new WebConversionService that configures formatters with the provided\n\t * date, time, and date-time formats, or registers the default if no custom format is\n\t * provided.\n\t * @param dateTimeFormatters the formatters to use for date, time, and date-time\n\t * formatting\n\t * @since 2.3.0\n\t */\n\tpublic WebConversionService(DateTimeFormatters dateTimeFormatters) {\n\t\tsuper(false);\n\t\tif (dateTimeFormatters.isCustomized()) {\n\t\t\taddFormatters(dateTimeFormatters);\n\t\t}\n\t\telse {\n\t\t\taddDefaultFormatters(this);\n\t\t}\n\t}\n\n\tprivate void addFormatters(DateTimeFormatters dateTimeFormatters) {\n\t\taddFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());\n\t\tif (JSR_354_PRESENT) {\n\t\t\taddFormatter(new CurrencyUnitFormatter());\n\t\t\taddFormatter(new MonetaryAmountFormatter());\n\t\t\taddFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());\n\t\t}\n\t\tregisterJsr310(dateTimeFormatters);\n\t\tregisterJavaDate(dateTimeFormatters);\n\t}\n\n\tprivate void registerJsr310(DateTimeFormatters dateTimeFormatters) {\n\t\tDateTimeFormatterRegistrar dateTime = new DateTimeFormatterRegistrar();\n\t\tconfigure(dateTimeFormatters::getDateFormatter, dateTime::setDateFormatter);\n\t\tconfigure(dateTimeFormatters::getTimeFormatter, dateTime::setTimeFormatter);\n\t\tconfigure(dateTimeFormatters::getDateTimeFormatter, dateTime::setDateTimeFormatter);\n\t\tdateTime.registerFormatters(this);\n\t}\n\n\tprivate void configure(Supplier<@Nullable DateTimeFormatter> supplier, Consumer<DateTimeFormatter> consumer) {\n\t\tDateTimeFormatter formatter = supplier.get();\n\t\tif (formatter != null) {\n\t\t\tconsumer.accept(formatter);\n\t\t}\n\t}\n\n\tprivate void registerJavaDate(DateTimeFormatters dateTimeFormatters) {\n\t\tDateFormatterRegistrar dateFormatterRegistrar = new DateFormatterRegistrar();\n\t\tString datePattern = dateTimeFormatters.getDatePattern();\n\t\tif (datePattern != null) {\n\t\t\tDateFormatter dateFormatter = new DateFormatter(datePattern);\n\t\t\tdateFormatterRegistrar.setFormatter(dateFormatter);\n\t\t}\n\t\tdateFormatterRegistrar.registerFormatters(this);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for web-specific formatting.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.web.format;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for common web concerns.\n */\n@NullMarked\npackage org.springframework.boot.autoconfigure.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.aop.auto\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Add @EnableAspectJAutoProxy.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.aop.proxy-target-class\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether subclass-based (CGLIB) proxies are to be created (true), as opposed to standard Java interface-based proxies (false).\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.application.admin.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable admin features for the application.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.application.admin.jmx-name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"JMX name of the application admin MBean.\",\n      \"defaultValue\": \"org.springframework.boot:type=Admin,name=SpringApplication\"\n    },\n    {\n      \"name\": \"spring.autoconfigure.exclude\",\n      \"type\": \"java.util.List<java.lang.Class>\",\n      \"description\": \"Auto-configuration classes to exclude.\"\n    },\n    {\n      \"name\": \"spring.git.properties\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Resource reference to a generated git info properties file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.info.git.location\",\n        \"level\": \"error\",\n        \"since\": \"1.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.info.build.location\",\n      \"defaultValue\": \"classpath:META-INF/build-info.properties\"\n    },\n    {\n      \"name\": \"spring.info.git.location\",\n      \"defaultValue\": \"classpath:git.properties\"\n    },\n    {\n      \"name\": \"spring.messages.basename\",\n      \"defaultValue\": [\n        \"messages\"\n      ]\n    },\n     {\n      \"name\": \"spring.resources.add-mappings\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.add-mappings\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.cache-private\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.cache-private\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.cache-public\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.cache-public\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.max-age\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.max-age\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.must-revalidate\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.must-revalidate\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.no-cache\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.no-cache\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.no-store\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.no-store\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.no-transform\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.no-transform\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.proxy-revalidate\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.proxy-revalidate\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.s-max-age\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.s-max-age\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.stale-if-error\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.stale-if-error\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.cachecontrol.stale-while-revalidate\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.cachecontrol.stale-while-revalidate\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.period\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.period\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.cache.use-last-modified\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.cache.use-last-modified\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.cache\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.cache\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.compressed\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.compressed\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.enabled\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.gzipped\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.compressed\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.html-application-cache\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.strategy.content.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.strategy.content.enabled\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.strategy.content.paths\",\n      \"type\": \"java.lang.String[]\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.strategy.content.paths\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.strategy.fixed.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.strategy.fixed.enabled\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.strategy.fixed.paths\",\n      \"type\": \"java.lang.String[]\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.strategy.fixed.paths\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.chain.strategy.fixed.version\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.chain.strategy.fixed.version\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.resources.static-locations\",\n      \"type\": \"java.lang.String[]\",\n      \"deprecation\": {\n        \"replacement\": \"spring.web.resources.static-locations\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.threads.virtual.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use virtual threads.\",\n      \"defaultValue\": false\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"server.servlet.jsp.class-name\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"jakarta.servlet.http.HttpServlet\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.jmx.server\",\n      \"providers\": [\n        {\n          \"name\": \"spring-bean-reference\",\n          \"parameters\": {\n            \"target\": \"javax.management.MBeanServer\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\\\norg.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingProcessor\n\norg.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\\\norg.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer\n\norg.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.autoconfigure.template.TemplateRuntimeHints\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration\norg.springframework.boot.autoconfigure.aop.AopAutoConfiguration\norg.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration\norg.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration\norg.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration\norg.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration\norg.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration\norg.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration\norg.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration\norg.springframework.boot.autoconfigure.ssl.SslAutoConfiguration\norg.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration\norg.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.template.provider.cache=false\ndefaults.spring.web.error.include-binding-errors=always\ndefaults.spring.web.error.include-message=always\ndefaults.spring.web.error.include-stacktrace=always\ndefaults.spring.web.resources.cache.period=0\ndefaults.spring.web.resources.chain.cache=false\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories",
    "content": "# ApplicationContext Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\\\norg.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener\n\n# Application Listeners\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializingApplicationListener\n\n# Auto Configuration Import Listeners\norg.springframework.boot.autoconfigure.AutoConfigurationImportListener=\\\norg.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener\n\n# Auto Configuration Import Filters\norg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\\\norg.springframework.boot.autoconfigure.condition.OnBeanCondition,\\\norg.springframework.boot.autoconfigure.condition.OnClassCondition,\\\norg.springframework.boot.autoconfigure.condition.OnWebApplicationCondition\n\n# Background Preinitializers\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer=\\\norg.springframework.boot.autoconfigure.preinitialize.CharsetsBackgroundPreinitializer,\\\norg.springframework.boot.autoconfigure.preinitialize.ConversionServiceBackgroundPreinitializer\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\\\norg.springframework.boot.autoconfigure.ssl.BundleContentNotWatchableFailureAnalyzer\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AbstractDependsOnBeanFactoryPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractDependsOnBeanFactoryPostProcessor}.\n *\n * @author Dmytro Nosan\n */\nclass AbstractDependsOnBeanFactoryPostProcessorTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(FooBarConfiguration.class);\n\n\t@Test\n\tvoid fooBeansShouldDependOnBarBeanNames() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FooDependsOnBarNamePostProcessor.class, FooBarFactoryBeanConfiguration.class)\n\t\t\t.run(this::assertThatFooDependsOnBar);\n\t}\n\n\t@Test\n\tvoid fooBeansShouldDependOnBarBeanTypes() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FooDependsOnBarTypePostProcessor.class, FooBarFactoryBeanConfiguration.class)\n\t\t\t.run(this::assertThatFooDependsOnBar);\n\t}\n\n\t@Test\n\tvoid fooBeansShouldDependOnBarBeanNamesParentContext() {\n\t\ttry (AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(\n\t\t\t\tFooBarFactoryBeanConfiguration.class)) {\n\t\t\tthis.contextRunner.withUserConfiguration(FooDependsOnBarNamePostProcessor.class)\n\t\t\t\t.withParent(parentContext)\n\t\t\t\t.run(this::assertThatFooDependsOnBar);\n\t\t}\n\t}\n\n\t@Test\n\tvoid fooBeansShouldDependOnBarBeanTypesParentContext() {\n\t\ttry (AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(\n\t\t\t\tFooBarFactoryBeanConfiguration.class)) {\n\t\t\tthis.contextRunner.withUserConfiguration(FooDependsOnBarTypePostProcessor.class)\n\t\t\t\t.withParent(parentContext)\n\t\t\t\t.run(this::assertThatFooDependsOnBar);\n\t\t}\n\t}\n\n\t@Test\n\tvoid postProcessorHasADefaultOrderOfZero() {\n\t\tassertThat(new FooDependsOnBarTypePostProcessor().getOrder()).isZero();\n\t}\n\n\tprivate void assertThatFooDependsOnBar(AssertableApplicationContext context) {\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tassertThat(getBeanDefinition(\"foo\", beanFactory).getDependsOn()).containsExactly(\"bar\", \"barFactoryBean\");\n\t\tassertThat(getBeanDefinition(\"fooFactoryBean\", beanFactory).getDependsOn()).containsExactly(\"bar\",\n\t\t\t\t\"barFactoryBean\");\n\t}\n\n\tprivate BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {\n\t\ttry {\n\t\t\treturn beanFactory.getBeanDefinition(beanName);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\tBeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();\n\t\t\tif (parentBeanFactory instanceof ConfigurableListableBeanFactory configurableListableBeanFactory) {\n\t\t\t\treturn getBeanDefinition(beanName, configurableListableBeanFactory);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tstatic class Foo {\n\n\t}\n\n\tstatic class Bar {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FooBarFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tFooFactoryBean fooFactoryBean() {\n\t\t\treturn new FooFactoryBean();\n\t\t}\n\n\t\t@Bean\n\t\tBarFactoryBean barFactoryBean() {\n\t\t\treturn new BarFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FooBarConfiguration {\n\n\t\t@Bean\n\t\tBar bar() {\n\t\t\treturn new Bar();\n\t\t}\n\n\t\t@Bean\n\t\tFoo foo() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t}\n\n\tstatic class FooDependsOnBarTypePostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {\n\n\t\tprotected FooDependsOnBarTypePostProcessor() {\n\t\t\tsuper(Foo.class, FooFactoryBean.class, Bar.class, BarFactoryBean.class);\n\t\t}\n\n\t}\n\n\tstatic class FooDependsOnBarNamePostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {\n\n\t\tprotected FooDependsOnBarNamePostProcessor() {\n\t\t\tsuper(Foo.class, FooFactoryBean.class, \"bar\", \"barFactoryBean\");\n\t\t}\n\n\t}\n\n\tstatic class FooFactoryBean implements FactoryBean<Foo> {\n\n\t\t@Override\n\t\tpublic Foo getObject() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn Foo.class;\n\t\t}\n\n\t}\n\n\tstatic class BarFactoryBean implements FactoryBean<Bar> {\n\n\t\t@Override\n\t\tpublic Bar getObject() {\n\t\t\treturn new Bar();\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn Bar.class;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.context.filtersample.ExampleConfiguration;\nimport org.springframework.boot.autoconfigure.context.filtersample.ExampleFilteredAutoConfiguration;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link AutoConfigurationExcludeFilter}.\n *\n * @author Stephane Nicoll\n */\nclass AutoConfigurationExcludeFilterTests {\n\n\tprivate static final Class<?> FILTERED = ExampleFilteredAutoConfiguration.class;\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid filterExcludeAutoConfiguration() {\n\t\tthis.context = new AnnotationConfigApplicationContext(Config.class);\n\t\tassertThat(this.context.getBeansOfType(String.class)).hasSize(1);\n\t\tassertThat(this.context.getBean(String.class)).isEqualTo(\"test\");\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(FILTERED);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ComponentScan(basePackageClasses = ExampleConfiguration.class,\n\t\t\texcludeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM,\n\t\t\t\t\tclasses = TestAutoConfigurationExcludeFilter.class))\n\tstatic class Config {\n\n\t}\n\n\tstatic class TestAutoConfigurationExcludeFilter extends AutoConfigurationExcludeFilter {\n\n\t\t@Override\n\t\tprotected List<String> getAutoConfigurations() {\n\t\t\treturn Collections.singletonList(FILTERED.getName());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigurationImportSelector}.\n *\n * @author Stephane Nicoll\n */\nclass AutoConfigurationImportSelectorIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid singleSelectorWithNoImports() {\n\t\tthis.contextRunner.withUserConfiguration(NoConfig.class)\n\t\t\t.run((context) -> assertThat(getImportedConfigBeans(context)).isEmpty());\n\t}\n\n\t@Test\n\tvoid singleSelector() {\n\t\tthis.contextRunner.withUserConfiguration(SingleConfig.class)\n\t\t\t.run((context) -> assertThat(getImportedConfigBeans(context)).containsExactly(\"ConfigC\"));\n\t}\n\n\t@Test\n\tvoid multipleSelectorsShouldMergeAndSortCorrectly() {\n\t\tthis.contextRunner.withUserConfiguration(MultiConfig.class, AnotherMultiConfig.class)\n\t\t\t.run((context) -> assertThat(getImportedConfigBeans(context)).containsExactly(\"ConfigA\", \"ConfigB\",\n\t\t\t\t\t\"ConfigC\", \"ConfigD\"));\n\t}\n\n\t@Test\n\tvoid multipleSelectorsWithRedundantImportsShouldMergeAndSortCorrectly() {\n\t\tthis.contextRunner.withUserConfiguration(SingleConfig.class, MultiConfig.class, AnotherMultiConfig.class)\n\t\t\t.run((context) -> assertThat(getImportedConfigBeans(context)).containsExactly(\"ConfigA\", \"ConfigB\",\n\t\t\t\t\t\"ConfigC\", \"ConfigD\"));\n\t}\n\n\tprivate List<String> getImportedConfigBeans(AssertableApplicationContext context) {\n\t\tString shortName = ClassUtils.getShortName(AutoConfigurationImportSelectorIntegrationTests.class);\n\t\tint beginIndex = shortName.length() + 1;\n\t\tList<String> orderedConfigBeans = new ArrayList<>();\n\t\tfor (String bean : context.getBeanDefinitionNames()) {\n\t\t\tif (bean.contains(\"$Config\")) {\n\t\t\t\tString shortBeanName = ClassUtils.getShortName(bean);\n\t\t\t\torderedConfigBeans.add(shortBeanName.substring(beginIndex));\n\t\t\t}\n\t\t}\n\t\treturn orderedConfigBeans;\n\t}\n\n\t@ImportAutoConfiguration\n\tstatic class NoConfig {\n\n\t}\n\n\t@ImportAutoConfiguration(ConfigC.class)\n\tstatic class SingleConfig {\n\n\t}\n\n\t@ImportAutoConfiguration({ ConfigD.class, ConfigB.class })\n\tstatic class MultiConfig {\n\n\t}\n\n\t@ImportAutoConfiguration({ ConfigC.class, ConfigA.class })\n\tstatic class AnotherMultiConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigA {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigureAfter(ConfigA.class)\n\t@AutoConfigureBefore(ConfigC.class)\n\tstatic class ConfigB {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigC {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigureAfter(ConfigC.class)\n\tstatic class ConfigD {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DeferredImportSelector.Group;\nimport org.springframework.context.annotation.DeferredImportSelector.Group.Entry;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link AutoConfigurationImportSelector}\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n */\n@WithResource(name = \"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports\", content = \"\"\"\n\t\tcom.example.one.FirstAutoConfiguration\n\t\tcom.example.two.SecondAutoConfiguration\n\t\tcom.example.three.ThirdAutoConfiguration\n\t\tcom.example.four.FourthAutoConfiguration\n\t\tcom.example.five.FifthAutoConfiguration\n\t\tcom.example.six.SixthAutoConfiguration\n\t\torg.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$SeventhAutoConfiguration\n\t\t\"\"\")\nclass AutoConfigurationImportSelectorTests {\n\n\tprivate final TestAutoConfigurationImportSelector importSelector = new TestAutoConfigurationImportSelector(null);\n\n\tprivate final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final List<AutoConfigurationImportFilter> filters = new ArrayList<>();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tsetupImportSelector(this.importSelector);\n\t}\n\n\t@Test\n\tvoid importsAreSelectedWhenUsingEnableAutoConfiguration() {\n\t\tString[] imports = selectImports(BasicEnableAutoConfiguration.class);\n\t\tassertThat(imports).hasSameSizeAs(getAutoConfigurationClassNames());\n\t\tassertThat(getLastEvent().getExclusions()).isEmpty();\n\t}\n\n\t@Test\n\tvoid classExclusionsAreApplied() {\n\t\tString[] imports = selectImports(EnableAutoConfigurationWithClassExclusions.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);\n\t\tassertThat(getLastEvent().getExclusions()).contains(SeventhAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid classExclusionsAreAppliedWhenUsingSpringBootApplication() {\n\t\tString[] imports = selectImports(SpringBootApplicationWithClassExclusions.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);\n\t\tassertThat(getLastEvent().getExclusions()).contains(SeventhAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid classNamesExclusionsAreApplied() {\n\t\tString[] imports = selectImports(EnableAutoConfigurationWithClassNameExclusions.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);\n\t\tassertThat(getLastEvent().getExclusions()).contains(\"com.example.one.FirstAutoConfiguration\");\n\t}\n\n\t@Test\n\tvoid classNamesExclusionsAreAppliedWhenUsingSpringBootApplication() {\n\t\tString[] imports = selectImports(SpringBootApplicationWithClassNameExclusions.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);\n\t\tassertThat(getLastEvent().getExclusions()).contains(\"com.example.three.ThirdAutoConfiguration\");\n\t}\n\n\t@Test\n\tvoid propertyExclusionsAreApplied() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\", \"com.example.three.ThirdAutoConfiguration\");\n\t\tString[] imports = selectImports(BasicEnableAutoConfiguration.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1);\n\t\tassertThat(getLastEvent().getExclusions()).contains(\"com.example.three.ThirdAutoConfiguration\");\n\t}\n\n\t@Test\n\tvoid severalPropertyExclusionsAreApplied() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\",\n\t\t\t\t\"com.example.two.SecondAutoConfiguration,com.example.four.FourthAutoConfiguration\");\n\t\ttestSeveralPropertyExclusionsAreApplied();\n\t}\n\n\t@Test\n\tvoid severalPropertyExclusionsAreAppliedWithExtraSpaces() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\",\n\t\t\t\t\"com.example.two.SecondAutoConfiguration , com.example.four.FourthAutoConfiguration  \");\n\t\ttestSeveralPropertyExclusionsAreApplied();\n\t}\n\n\t@Test\n\tvoid severalPropertyYamlExclusionsAreApplied() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude[0]\", \"com.example.two.SecondAutoConfiguration\");\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude[1]\", \"com.example.four.FourthAutoConfiguration\");\n\t\ttestSeveralPropertyExclusionsAreApplied();\n\t}\n\n\tprivate void testSeveralPropertyExclusionsAreApplied() {\n\t\tString[] imports = selectImports(BasicEnableAutoConfiguration.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 2);\n\t\tassertThat(getLastEvent().getExclusions()).contains(\"com.example.two.SecondAutoConfiguration\",\n\t\t\t\t\"com.example.four.FourthAutoConfiguration\");\n\t}\n\n\t@Test\n\tvoid combinedExclusionsAreApplied() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\", \"com.example.one.FirstAutoConfiguration\");\n\t\tString[] imports = selectImports(EnableAutoConfigurationWithClassAndClassNameExclusions.class);\n\t\tassertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 3);\n\t\tassertThat(getLastEvent().getExclusions()).contains(\"com.example.one.FirstAutoConfiguration\",\n\t\t\t\t\"com.example.five.FifthAutoConfiguration\", SeventhAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\t@WithTestAutoConfigurationImportsResource\n\t@WithTestAutoConfigurationReplacementsResource\n\tvoid removedExclusionsAreApplied() {\n\t\tTestAutoConfigurationImportSelector importSelector = new TestAutoConfigurationImportSelector(\n\t\t\t\tTestAutoConfiguration.class);\n\t\tsetupImportSelector(importSelector);\n\t\tAnnotationMetadata metadata = AnnotationMetadata.introspect(BasicEnableAutoConfiguration.class);\n\t\tassertThat(importSelector.selectImports(metadata)).contains(ReplacementAutoConfiguration.class.getName());\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\", DeprecatedAutoConfiguration.class.getName());\n\t\tassertThat(importSelector.selectImports(metadata)).doesNotContain(ReplacementAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid nonAutoConfigurationClassExclusionsShouldThrowException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> selectImports(EnableAutoConfigurationWithFaultyClassExclude.class));\n\t}\n\n\t@Test\n\tvoid nonAutoConfigurationClassNameExclusionsWhenPresentOnClassPathShouldThrowException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> selectImports(EnableAutoConfigurationWithFaultyClassNameExclude.class));\n\t}\n\n\t@Test\n\tvoid nonAutoConfigurationPropertyExclusionsWhenPresentOnClassPathShouldThrowException() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests.TestConfiguration\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> selectImports(BasicEnableAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid nameAndPropertyExclusionsWhenNotPresentOnClasspathShouldNotThrowException() {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.DoesNotExist2\");\n\t\tselectImports(EnableAutoConfigurationWithAbsentClassNameExclude.class);\n\t\tassertThat(getLastEvent().getExclusions()).containsExactlyInAnyOrder(\n\t\t\t\t\"org.springframework.boot.autoconfigure.DoesNotExist1\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.DoesNotExist2\");\n\t}\n\n\t@Test\n\tvoid filterShouldFilterImports() {\n\t\tString[] defaultImports = selectImports(BasicEnableAutoConfiguration.class);\n\t\tthis.filters.add(new TestAutoConfigurationImportFilter(defaultImports, 1));\n\t\tthis.filters.add(new TestAutoConfigurationImportFilter(defaultImports, 3, 4));\n\t\tString[] filtered = selectImports(BasicEnableAutoConfiguration.class);\n\t\tassertThat(filtered).hasSize(defaultImports.length - 3);\n\t\tassertThat(filtered).doesNotContain(defaultImports[1], defaultImports[3], defaultImports[4]);\n\t}\n\n\t@Test\n\tvoid filterShouldSupportAware() {\n\t\tTestAutoConfigurationImportFilter filter = new TestAutoConfigurationImportFilter(new String[] {});\n\t\tthis.filters.add(filter);\n\t\tselectImports(BasicEnableAutoConfiguration.class);\n\t\tassertThat(filter.getBeanFactory()).isEqualTo(this.beanFactory);\n\t}\n\n\t@Test\n\tvoid getExclusionFilterReuseFilters() {\n\t\tString[] allImports = new String[] { \"com.example.A\", \"com.example.B\", \"com.example.C\" };\n\t\tthis.filters.add(new TestAutoConfigurationImportFilter(allImports, 0));\n\t\tthis.filters.add(new TestAutoConfigurationImportFilter(allImports, 2));\n\t\tassertThat(this.importSelector.getExclusionFilter().test(\"com.example.A\")).isTrue();\n\t\tassertThat(this.importSelector.getExclusionFilter().test(\"com.example.B\")).isFalse();\n\t\tassertThat(this.importSelector.getExclusionFilter().test(\"com.example.C\")).isTrue();\n\t}\n\n\t@Test\n\t@WithTestAutoConfigurationImportsResource\n\t@WithTestAutoConfigurationReplacementsResource\n\tvoid sortingConsidersReplacements() {\n\t\tTestAutoConfigurationImportSelector importSelector = new TestAutoConfigurationImportSelector(\n\t\t\t\tTestAutoConfiguration.class);\n\t\tsetupImportSelector(importSelector);\n\t\tAnnotationMetadata metadata = AnnotationMetadata.introspect(BasicEnableAutoConfiguration.class);\n\t\tassertThat(importSelector.selectImports(metadata)).containsExactly(\n\t\t\t\tAfterDeprecatedAutoConfiguration.class.getName(), ReplacementAutoConfiguration.class.getName());\n\t\tGroup group = BeanUtils.instantiateClass(importSelector.getImportGroup());\n\t\t((BeanFactoryAware) group).setBeanFactory(this.beanFactory);\n\t\tgroup.process(metadata, importSelector);\n\t\tStream<Entry> imports = StreamSupport.stream(group.selectImports().spliterator(), false);\n\t\tassertThat(imports.map(Entry::getImportClassName)).containsExactly(ReplacementAutoConfiguration.class.getName(),\n\t\t\t\tAfterDeprecatedAutoConfiguration.class.getName());\n\t}\n\n\tprivate String[] selectImports(Class<?> source) {\n\t\treturn this.importSelector.selectImports(AnnotationMetadata.introspect(source));\n\t}\n\n\tprivate List<String> getAutoConfigurationClassNames() {\n\t\treturn ImportCandidates.load(AutoConfiguration.class, Thread.currentThread().getContextClassLoader())\n\t\t\t.getCandidates();\n\t}\n\n\tprivate void setupImportSelector(TestAutoConfigurationImportSelector importSelector) {\n\t\timportSelector.setBeanFactory(this.beanFactory);\n\t\timportSelector.setEnvironment(this.environment);\n\t\timportSelector.setResourceLoader(new DefaultResourceLoader());\n\t\timportSelector.setBeanClassLoader(Thread.currentThread().getContextClassLoader());\n\t}\n\n\tprivate AutoConfigurationImportEvent getLastEvent() {\n\t\tAutoConfigurationImportEvent result = this.importSelector.getLastEvent();\n\t\tassertThat(result).isNotNull();\n\t\treturn result;\n\t}\n\n\tprivate final class TestAutoConfigurationImportSelector extends AutoConfigurationImportSelector {\n\n\t\tprivate @Nullable AutoConfigurationImportEvent lastEvent;\n\n\t\tTestAutoConfigurationImportSelector(@Nullable Class<?> autoConfigurationAnnotation) {\n\t\t\tsuper(autoConfigurationAnnotation);\n\t\t}\n\n\t\t@Override\n\t\tprotected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {\n\t\t\treturn AutoConfigurationImportSelectorTests.this.filters;\n\t\t}\n\n\t\t@Override\n\t\tprotected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {\n\t\t\treturn Collections.singletonList((event) -> this.lastEvent = event);\n\t\t}\n\n\t\t@Nullable AutoConfigurationImportEvent getLastEvent() {\n\t\t\treturn this.lastEvent;\n\t\t}\n\n\t}\n\n\tstatic class TestAutoConfigurationImportFilter implements AutoConfigurationImportFilter, BeanFactoryAware {\n\n\t\tprivate final Set<String> nonMatching = new HashSet<>();\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate BeanFactory beanFactory;\n\n\t\tTestAutoConfigurationImportFilter(String[] configurations, int... nonMatching) {\n\t\t\tfor (int i : nonMatching) {\n\t\t\t\tthis.nonMatching.add(configurations[i]);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean[] match(@Nullable String[] autoConfigurationClasses,\n\t\t\t\tAutoConfigurationMetadata autoConfigurationMetadata) {\n\t\t\tboolean[] result = new boolean[autoConfigurationClasses.length];\n\t\t\tfor (int i = 0; i < result.length; i++) {\n\t\t\t\tresult[i] = !this.nonMatching.contains(autoConfigurationClasses[i]);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setBeanFactory(BeanFactory beanFactory) {\n\t\t\tthis.beanFactory = beanFactory;\n\t\t}\n\n\t\tBeanFactory getBeanFactory() {\n\t\t\treturn this.beanFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate final class TestConfiguration {\n\n\t}\n\n\t@EnableAutoConfiguration\n\tprivate final class BasicEnableAutoConfiguration {\n\n\t}\n\n\t@EnableAutoConfiguration(exclude = SeventhAutoConfiguration.class)\n\tprivate final class EnableAutoConfigurationWithClassExclusions {\n\n\t}\n\n\t@SpringBootApplication(exclude = SeventhAutoConfiguration.class)\n\tprivate final class SpringBootApplicationWithClassExclusions {\n\n\t}\n\n\t@EnableAutoConfiguration(excludeName = \"com.example.one.FirstAutoConfiguration\")\n\tprivate final class EnableAutoConfigurationWithClassNameExclusions {\n\n\t}\n\n\t@EnableAutoConfiguration(exclude = SeventhAutoConfiguration.class,\n\t\t\texcludeName = \"com.example.five.FifthAutoConfiguration\")\n\tprivate final class EnableAutoConfigurationWithClassAndClassNameExclusions {\n\n\t}\n\n\t@EnableAutoConfiguration(exclude = TestConfiguration.class)\n\tprivate final class EnableAutoConfigurationWithFaultyClassExclude {\n\n\t}\n\n\t@EnableAutoConfiguration(\n\t\t\texcludeName = \"org.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests.TestConfiguration\")\n\tprivate final class EnableAutoConfigurationWithFaultyClassNameExclude {\n\n\t}\n\n\t@EnableAutoConfiguration(excludeName = \"org.springframework.boot.autoconfigure.DoesNotExist1\")\n\tprivate final class EnableAutoConfigurationWithAbsentClassNameExclude {\n\n\t}\n\n\t@SpringBootApplication(excludeName = \"com.example.three.ThirdAutoConfiguration\")\n\tprivate final class SpringBootApplicationWithClassNameExclusions {\n\n\t}\n\n\tstatic class DeprecatedAutoConfiguration {\n\n\t}\n\n\tstatic class ReplacementAutoConfiguration {\n\n\t}\n\n\t@AutoConfigureAfter(DeprecatedAutoConfiguration.class)\n\tstatic class AfterDeprecatedAutoConfiguration {\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface TestAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\tpublic static final class SeventhAutoConfiguration {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(\n\t\t\tname = \"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$TestAutoConfiguration.imports\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$AfterDeprecatedAutoConfiguration\n\t\t\t\t\torg.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$ReplacementAutoConfiguration\n\t\t\t\t\t\"\"\")\n\t@interface WithTestAutoConfigurationImportsResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(\n\t\t\tname = \"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$TestAutoConfiguration.replacements\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$DeprecatedAutoConfiguration=\\\n\t\t\t\t\torg.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$ReplacementAutoConfiguration\n\t\t\t\t\t\"\"\")\n\t@interface WithTestAutoConfigurationReplacementsResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationMetadataLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link AutoConfigurationMetadataLoader}.\n *\n * @author Phillip Webb\n */\n@WithResource(name = \"metadata.properties\", content = \"\"\"\n\t\ttest=\n\t\ttest.string=abc\n\t\ttest.int=123\n\t\ttest.set=a,b,b,c\n\t\t\"\"\")\nclass AutoConfigurationMetadataLoaderTests {\n\n\t@Test\n\tvoid loadShouldLoadProperties() {\n\t\tassertThat(load()).isNotNull();\n\t}\n\n\t@Test\n\tvoid wasProcessedWhenProcessedShouldReturnTrue() {\n\t\tassertThat(load().wasProcessed(\"test\")).isTrue();\n\t}\n\n\t@Test\n\tvoid wasProcessedWhenNotProcessedShouldReturnFalse() {\n\t\tassertThat(load().wasProcessed(\"testx\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getIntegerShouldReturnValue() {\n\t\tassertThat(load().getInteger(\"test\", \"int\")).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid getIntegerWhenMissingShouldReturnNull() {\n\t\tassertThat(load().getInteger(\"test\", \"intx\")).isNull();\n\t}\n\n\t@Test\n\tvoid getIntegerWithDefaultWhenMissingShouldReturnDefault() {\n\t\tassertThat(load().getInteger(\"test\", \"intx\", 345)).isEqualTo(345);\n\t}\n\n\t@Test\n\tvoid getSetShouldReturnValue() {\n\t\tassertThat(load().getSet(\"test\", \"set\")).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid getSetWhenMissingShouldReturnNull() {\n\t\tassertThat(load().getSet(\"test\", \"setx\")).isNull();\n\t}\n\n\t@Test\n\tvoid getSetWithDefaultWhenMissingShouldReturnDefault() {\n\t\tassertThat(load().getSet(\"test\", \"setx\", Collections.singleton(\"x\"))).containsExactly(\"x\");\n\t}\n\n\t@Test\n\tvoid getShouldReturnValue() {\n\t\tassertThat(load().get(\"test\", \"string\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid getWhenMissingShouldReturnNull() {\n\t\tassertThat(load().get(\"test\", \"stringx\")).isNull();\n\t}\n\n\t@Test\n\tvoid getWithDefaultWhenMissingShouldReturnDefault() {\n\t\tassertThat(load().get(\"test\", \"stringx\", \"xyz\")).isEqualTo(\"xyz\");\n\t}\n\n\tprivate AutoConfigurationMetadata load() {\n\t\tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n\t\treturn AutoConfigurationMetadataLoader.loadMetadata(classLoader, \"metadata.properties\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationPackagesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.packagestest.one.FirstConfiguration;\nimport org.springframework.boot.autoconfigure.packagestest.two.SecondConfiguration;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link AutoConfigurationPackages}.\n *\n * @author Phillip Webb\n * @author Oliver Gierke\n */\n@SuppressWarnings(\"resource\")\nclass AutoConfigurationPackagesTests {\n\n\t@Test\n\tvoid setAndGet() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tConfigWithAutoConfigurationPackage.class);\n\t\tassertThat(AutoConfigurationPackages.get(context.getBeanFactory()))\n\t\t\t.containsExactly(getClass().getPackage().getName());\n\t}\n\n\t@Test\n\tvoid getWithoutSet() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EmptyConfig.class);\n\t\tassertThatIllegalStateException().isThrownBy(() -> AutoConfigurationPackages.get(context.getBeanFactory()))\n\t\t\t.withMessageContaining(\"Unable to retrieve @EnableAutoConfiguration base packages\");\n\t}\n\n\t@Test\n\tvoid detectsMultipleAutoConfigurationPackages() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FirstConfiguration.class,\n\t\t\t\tSecondConfiguration.class);\n\t\tList<String> packages = AutoConfigurationPackages.get(context.getBeanFactory());\n\t\tPackage package1 = FirstConfiguration.class.getPackage();\n\t\tPackage package2 = SecondConfiguration.class.getPackage();\n\t\tassertThat(packages).containsOnly(package1.getName(), package2.getName());\n\t}\n\n\t@Test\n\tvoid whenBasePackagesAreSpecifiedThenTheyAreRegistered() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tConfigWithAutoConfigurationBasePackages.class);\n\t\tList<String> packages = AutoConfigurationPackages.get(context.getBeanFactory());\n\t\tassertThat(packages).containsExactly(\"com.example.alpha\", \"com.example.bravo\");\n\t}\n\n\t@Test\n\tvoid whenBasePackageClassesAreSpecifiedThenTheirPackagesAreRegistered() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tConfigWithAutoConfigurationBasePackageClasses.class);\n\t\tList<String> packages = AutoConfigurationPackages.get(context.getBeanFactory());\n\t\tassertThat(packages).containsOnly(FirstConfiguration.class.getPackage().getName(),\n\t\t\t\tSecondConfiguration.class.getPackage().getName());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigurationPackage\n\tstatic class ConfigWithAutoConfigurationPackage {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigurationPackage(basePackages = { \"com.example.alpha\", \"com.example.bravo\" })\n\tstatic class ConfigWithAutoConfigurationBasePackages {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigurationPackage(basePackageClasses = { FirstConfiguration.class, SecondConfiguration.class })\n\tstatic class ConfigWithAutoConfigurationBasePackageClasses {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationReplacementsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigurationReplacements}.\n *\n * @author Phillip Webb\n */\n@WithResource(\n\t\tname = \"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfigurationReplacementsTests$TestAutoConfigurationReplacements.replacements\",\n\t\tcontent = \"\"\"\n\t\t\t\tcom.example.A1=com.example.A2\n\t\t\t\tcom.example.B1=com.example.B2\n\t\t\t\t\"\"\")\nclass AutoConfigurationReplacementsTests {\n\n\tprivate AutoConfigurationReplacements replacements;\n\n\t@BeforeEach\n\tvoid loadReplacements() {\n\t\tthis.replacements = AutoConfigurationReplacements.load(TestAutoConfigurationReplacements.class,\n\t\t\t\tThread.currentThread().getContextClassLoader());\n\t}\n\n\t@Test\n\tvoid replaceWhenMatchReplacesClassName() {\n\t\tassertThat(this.replacements.replace(\"com.example.A1\")).isEqualTo(\"com.example.A2\");\n\t}\n\n\t@Test\n\tvoid replaceWhenNoMatchReturnsOriginalClassName() {\n\t\tassertThat(this.replacements.replace(\"com.example.Z1\")).isEqualTo(\"com.example.Z1\");\n\t}\n\n\t@Test\n\tvoid replaceAllReplacesAllMatching() {\n\t\tSet<String> classNames = new LinkedHashSet<>(\n\t\t\t\tList.of(\"com.example.A1\", \"com.example.B1\", \"com.example.Y1\", \"com.example.Z1\"));\n\t\tassertThat(this.replacements.replaceAll(classNames)).containsExactly(\"com.example.A2\", \"com.example.B2\",\n\t\t\t\t\"com.example.Y1\", \"com.example.Z1\");\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface TestAutoConfigurationReplacements {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationSorterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AutoConfigurationSorter}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Alexandre Baron\n */\nclass AutoConfigurationSorterTests {\n\n\tprivate static final String DEFAULT = OrderUnspecified.class.getName();\n\n\tprivate static final String LOWEST = OrderLowest.class.getName();\n\n\tprivate static final String HIGHEST = OrderHighest.class.getName();\n\n\tprivate static final String A = AutoConfigureA.class.getName();\n\n\tprivate static final String A2 = AutoConfigureA2.class.getName();\n\n\tprivate static final String A3 = AutoConfigureA3.class.getName();\n\n\tprivate static final String A_WITH_REPLACED = AutoConfigureAWithReplaced.class.getName();\n\n\tprivate static final String B = AutoConfigureB.class.getName();\n\n\tprivate static final String B2 = AutoConfigureB2.class.getName();\n\n\tprivate static final String B_WITH_REPLACED = AutoConfigureBWithReplaced.class.getName();\n\n\tprivate static final String C = AutoConfigureC.class.getName();\n\n\tprivate static final String D = AutoConfigureD.class.getName();\n\n\tprivate static final String E = AutoConfigureE.class.getName();\n\n\tprivate static final String W = AutoConfigureW.class.getName();\n\n\tprivate static final String W2 = AutoConfigureW2.class.getName();\n\n\tprivate static final String X = AutoConfigureX.class.getName();\n\n\tprivate static final String Y = AutoConfigureY.class.getName();\n\n\tprivate static final String Y2 = AutoConfigureY2.class.getName();\n\n\tprivate static final String Z = AutoConfigureZ.class.getName();\n\n\tprivate static final String Z2 = AutoConfigureZ2.class.getName();\n\n\tprivate static final UnaryOperator<String> REPLACEMENT_MAPPER = (name) -> name.replace(\"Deprecated\", \"\");\n\n\tprivate AutoConfigurationSorter sorter;\n\n\tprivate AutoConfigurationMetadata autoConfigurationMetadata = mock(AutoConfigurationMetadata.class);\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.sorter = new AutoConfigurationSorter(new SkipCycleMetadataReaderFactory(), this.autoConfigurationMetadata,\n\t\t\t\tREPLACEMENT_MAPPER);\n\t}\n\n\t@Test\n\tvoid byOrderAnnotation() {\n\t\tList<String> actual = getInPriorityOrder(LOWEST, HIGHEST, DEFAULT);\n\t\tassertThat(actual).containsExactly(HIGHEST, DEFAULT, LOWEST);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfter() {\n\t\tList<String> actual = getInPriorityOrder(A, B, C);\n\t\tassertThat(actual).containsExactly(C, B, A);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfterAliasFor() {\n\t\tList<String> actual = getInPriorityOrder(A3, B2, C);\n\t\tassertThat(actual).containsExactly(C, B2, A3);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfterAliasForWithProperties() throws Exception {\n\t\tMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();\n\t\tthis.autoConfigurationMetadata = getAutoConfigurationMetadata(A3, B2, C);\n\t\tthis.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata, REPLACEMENT_MAPPER);\n\t\tList<String> actual = getInPriorityOrder(A3, B2, C);\n\t\tassertThat(actual).containsExactly(C, B2, A3);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfterWithDeprecated() {\n\t\tList<String> actual = getInPriorityOrder(A_WITH_REPLACED, B_WITH_REPLACED, C);\n\t\tassertThat(actual).containsExactly(C, B_WITH_REPLACED, A_WITH_REPLACED);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureBefore() {\n\t\tList<String> actual = getInPriorityOrder(X, Y, Z);\n\t\tassertThat(actual).containsExactly(Z, Y, X);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureBeforeAliasFor() {\n\t\tList<String> actual = getInPriorityOrder(X, Y2, Z2);\n\t\tassertThat(actual).containsExactly(Z2, Y2, X);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureBeforeAliasForWithProperties() throws Exception {\n\t\tMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();\n\t\tthis.autoConfigurationMetadata = getAutoConfigurationMetadata(X, Y2, Z2);\n\t\tthis.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata, REPLACEMENT_MAPPER);\n\t\tList<String> actual = getInPriorityOrder(X, Y2, Z2);\n\t\tassertThat(actual).containsExactly(Z2, Y2, X);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfterDoubles() {\n\t\tList<String> actual = getInPriorityOrder(A, B, C, E);\n\t\tassertThat(actual).containsExactly(C, E, B, A);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureMixedBeforeAndAfter() {\n\t\tList<String> actual = getInPriorityOrder(A, B, C, W, X);\n\t\tassertThat(actual).containsExactly(C, W, B, A, X);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureMixedBeforeAndAfterWithClassNames() {\n\t\tList<String> actual = getInPriorityOrder(A2, B, C, W2, X);\n\t\tassertThat(actual).containsExactly(C, W2, B, A2, X);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureMixedBeforeAndAfterWithDifferentInputOrder() {\n\t\tList<String> actual = getInPriorityOrder(W, X, A, B, C);\n\t\tassertThat(actual).containsExactly(C, W, B, A, X);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfterWithMissing() {\n\t\tList<String> actual = getInPriorityOrder(A, B);\n\t\tassertThat(actual).containsExactly(B, A);\n\t}\n\n\t@Test\n\tvoid byAutoConfigureAfterWithCycle() {\n\t\tthis.sorter = new AutoConfigurationSorter(new CachingMetadataReaderFactory(), this.autoConfigurationMetadata,\n\t\t\t\tREPLACEMENT_MAPPER);\n\t\tassertThatIllegalStateException().isThrownBy(() -> getInPriorityOrder(A, B, C, D))\n\t\t\t.withMessageContaining(\"AutoConfigure cycle detected\");\n\t}\n\n\t@Test\n\tvoid usesAnnotationPropertiesWhenPossible() throws Exception {\n\t\tMetadataReaderFactory readerFactory = new SkipCycleMetadataReaderFactory();\n\t\tthis.autoConfigurationMetadata = getAutoConfigurationMetadata(A2, B, C, W2, X);\n\t\tthis.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata, REPLACEMENT_MAPPER);\n\t\tList<String> actual = getInPriorityOrder(A2, B, C, W2, X);\n\t\tassertThat(actual).containsExactly(C, W2, B, A2, X);\n\t}\n\n\t@Test\n\tvoid useAnnotationWithNoDirectLink() throws Exception {\n\t\tMetadataReaderFactory readerFactory = new SkipCycleMetadataReaderFactory();\n\t\tthis.autoConfigurationMetadata = getAutoConfigurationMetadata(A, B, E);\n\t\tthis.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata, REPLACEMENT_MAPPER);\n\t\tList<String> actual = getInPriorityOrder(A, E);\n\t\tassertThat(actual).containsExactly(E, A);\n\t}\n\n\t@Test\n\tvoid useAnnotationWithNoDirectLinkAndCycle() throws Exception {\n\t\tMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();\n\t\tthis.autoConfigurationMetadata = getAutoConfigurationMetadata(A, B, D);\n\t\tthis.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata, REPLACEMENT_MAPPER);\n\t\tassertThatIllegalStateException().isThrownBy(() -> getInPriorityOrder(D, B))\n\t\t\t.withMessageContaining(\"AutoConfigure cycle detected\");\n\t}\n\n\t@Test // gh-38904\n\tvoid byBeforeAnnotationThenOrderAnnotation() {\n\t\tString oa = OrderAutoConfigureA.class.getName();\n\t\tString oa1 = OrderAutoConfigureASeedR1.class.getName();\n\t\tString oa2 = OrderAutoConfigureASeedY2.class.getName();\n\t\tString oa3 = OrderAutoConfigureASeedA3.class.getName();\n\t\tString oa4 = OrderAutoConfigureAutoConfigureASeedG4.class.getName();\n\t\tList<String> actual = getInPriorityOrder(oa4, oa3, oa2, oa1, oa);\n\t\tassertThat(actual).containsExactly(oa1, oa2, oa3, oa4, oa);\n\t}\n\n\tprivate List<String> getInPriorityOrder(String... classNames) {\n\t\treturn this.sorter.getInPriorityOrder(Arrays.asList(classNames));\n\t}\n\n\tprivate AutoConfigurationMetadata getAutoConfigurationMetadata(String... classNames) throws Exception {\n\t\tProperties properties = new Properties();\n\t\tfor (String className : classNames) {\n\t\t\tClass<?> type = ClassUtils.forName(className, null);\n\t\t\tproperties.put(type.getName(), \"\");\n\t\t\tAnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(type);\n\t\t\taddAutoConfigureOrder(properties, className, annotationMetadata);\n\t\t\taddAutoConfigureBefore(properties, className, annotationMetadata);\n\t\t\taddAutoConfigureAfter(properties, className, annotationMetadata);\n\t\t}\n\t\treturn AutoConfigurationMetadataLoader.loadMetadata(properties);\n\t}\n\n\tprivate void addAutoConfigureAfter(Properties properties, String className, AnnotationMetadata annotationMetadata) {\n\t\tMap<String, @Nullable Object> autoConfigureAfter = annotationMetadata\n\t\t\t.getAnnotationAttributes(AutoConfigureAfter.class.getName(), true);\n\t\tif (autoConfigureAfter != null) {\n\t\t\tString[] valueAttribute = (String[]) autoConfigureAfter.get(\"value\");\n\t\t\tString[] nameAttribute = (String[]) autoConfigureAfter.get(\"name\");\n\t\t\tassertThat(valueAttribute).isNotNull();\n\t\t\tassertThat(nameAttribute).isNotNull();\n\t\t\tString value = merge(valueAttribute, nameAttribute);\n\t\t\tif (!value.isEmpty()) {\n\t\t\t\tproperties.put(className + \".AutoConfigureAfter\", value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addAutoConfigureBefore(Properties properties, String className,\n\t\t\tAnnotationMetadata annotationMetadata) {\n\t\tMap<String, @Nullable Object> autoConfigureBefore = annotationMetadata\n\t\t\t.getAnnotationAttributes(AutoConfigureBefore.class.getName(), true);\n\t\tif (autoConfigureBefore != null) {\n\t\t\tString[] valueAttribute = (String[]) autoConfigureBefore.get(\"value\");\n\t\t\tString[] nameAttribute = (String[]) autoConfigureBefore.get(\"name\");\n\t\t\tassertThat(valueAttribute).isNotNull();\n\t\t\tassertThat(nameAttribute).isNotNull();\n\t\t\tString value = merge(valueAttribute, nameAttribute);\n\t\t\tif (!value.isEmpty()) {\n\t\t\t\tproperties.put(className + \".AutoConfigureBefore\", value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addAutoConfigureOrder(Properties properties, String className, AnnotationMetadata annotationMetadata) {\n\t\tMap<String, @Nullable Object> autoConfigureOrder = annotationMetadata\n\t\t\t.getAnnotationAttributes(AutoConfigureOrder.class.getName());\n\t\tif (autoConfigureOrder != null) {\n\t\t\tInteger order = (Integer) autoConfigureOrder.get(\"order\");\n\t\t\tif (order != null) {\n\t\t\t\tproperties.put(className + \".AutoConfigureOrder\", String.valueOf(order));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String merge(String[] value, String[] name) {\n\t\tSet<String> items = new LinkedHashSet<>();\n\t\tCollections.addAll(items, value);\n\t\tCollections.addAll(items, name);\n\t\treturn StringUtils.collectionToCommaDelimitedString(items);\n\t}\n\n\t@AutoConfigureOrder\n\tstatic class OrderUnspecified {\n\n\t}\n\n\t@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)\n\tstatic class OrderLowest {\n\n\t}\n\n\t@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)\n\tstatic class OrderHighest {\n\n\t}\n\n\t@AutoConfigureAfter(AutoConfigureB.class)\n\tstatic class AutoConfigureA {\n\n\t}\n\n\t@AutoConfigureAfter(name = \"org.springframework.boot.autoconfigure.AutoConfigurationSorterTests$AutoConfigureB\")\n\tstatic class AutoConfigureA2 {\n\n\t}\n\n\t@AutoConfiguration(after = AutoConfigureB2.class)\n\tpublic static final class AutoConfigureA3 {\n\n\t}\n\n\t@AutoConfigureAfter(AutoConfigureBWithReplaced.class)\n\tpublic static class AutoConfigureAWithReplaced {\n\n\t}\n\n\t@AutoConfigureAfter({ AutoConfigureC.class, AutoConfigureD.class, AutoConfigureE.class })\n\tstatic class AutoConfigureB {\n\n\t}\n\n\t@AutoConfiguration(after = { AutoConfigureC.class })\n\tpublic static final class AutoConfigureB2 {\n\n\t}\n\n\t@AutoConfigureAfter({ DeprecatedAutoConfigureC.class, AutoConfigureD.class, AutoConfigureE.class })\n\tpublic static class AutoConfigureBWithReplaced {\n\n\t}\n\n\tstatic class AutoConfigureC {\n\n\t}\n\n\t// @DeprecatedAutoConfiguration(replacement =\n\t// \"org.springframework.boot.autoconfigure.AutoConfigurationSorterTests$AutoConfigureC\")\n\tpublic static class DeprecatedAutoConfigureC {\n\n\t}\n\n\t@AutoConfigureAfter(AutoConfigureA.class)\n\tstatic class AutoConfigureD {\n\n\t}\n\n\tstatic class AutoConfigureE {\n\n\t}\n\n\t@AutoConfigureBefore(AutoConfigureB.class)\n\tstatic class AutoConfigureW {\n\n\t}\n\n\t@AutoConfigureBefore(name = \"org.springframework.boot.autoconfigure.AutoConfigurationSorterTests$AutoConfigureB\")\n\tstatic class AutoConfigureW2 {\n\n\t}\n\n\tstatic class AutoConfigureX {\n\n\t}\n\n\t@AutoConfigureBefore(AutoConfigureX.class)\n\tstatic class AutoConfigureY {\n\n\t}\n\n\t@AutoConfiguration(before = AutoConfigureX.class)\n\tpublic static final class AutoConfigureY2 {\n\n\t}\n\n\t// @DeprecatedAutoConfiguration(replacement =\n\t// \"org.springframework.boot.autoconfigure.AutoConfigurationSorterTests$AutoConfigureY\")\n\tpublic static class DeprecatedAutoConfigureY {\n\n\t}\n\n\t@AutoConfigureBefore(AutoConfigureY.class)\n\tstatic class AutoConfigureZ {\n\n\t}\n\n\t@AutoConfiguration(before = AutoConfigureY2.class)\n\tpublic static final class AutoConfigureZ2 {\n\n\t}\n\n\tstatic class OrderAutoConfigureA {\n\n\t}\n\n\t// Use seeds in auto-configuration class names to mislead the sort by names done in\n\t// AutoConfigurationSorter class.\n\t@AutoConfigureBefore(OrderAutoConfigureA.class)\n\t@AutoConfigureOrder(1)\n\tstatic class OrderAutoConfigureASeedR1 {\n\n\t}\n\n\t@AutoConfigureBefore(OrderAutoConfigureA.class)\n\t@AutoConfigureOrder(2)\n\tstatic class OrderAutoConfigureASeedY2 {\n\n\t}\n\n\t@AutoConfigureBefore(OrderAutoConfigureA.class)\n\t@AutoConfigureOrder(3)\n\tstatic class OrderAutoConfigureASeedA3 {\n\n\t}\n\n\t@AutoConfigureBefore(OrderAutoConfigureA.class)\n\t@AutoConfigureOrder(4)\n\tstatic class OrderAutoConfigureAutoConfigureASeedG4 {\n\n\t}\n\n\tstatic class SkipCycleMetadataReaderFactory extends CachingMetadataReaderFactory {\n\n\t\t@Override\n\t\tpublic MetadataReader getMetadataReader(String className) throws IOException {\n\t\t\tif (className.equals(D)) {\n\t\t\t\tthrow new IOException();\n\t\t\t}\n\t\t\treturn super.getMetadataReader(className);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.annotation.Configurations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigurations}.\n *\n * @author Phillip Webb\n */\nclass AutoConfigurationsTests {\n\n\t@Test\n\tvoid ofShouldCreateOrderedConfigurations() {\n\t\tConfigurations configurations = AutoConfigurations.of(AutoConfigureA.class, AutoConfigureB.class);\n\t\tassertThat(Configurations.getClasses(configurations)).containsExactly(AutoConfigureB.class,\n\t\t\t\tAutoConfigureA.class);\n\t}\n\n\t@Test\n\tvoid whenHasReplacementForAutoConfigureAfterShouldCreateOrderedConfigurations() {\n\t\tConfigurations configurations = new AutoConfigurations(this::replaceB,\n\t\t\t\tArrays.asList(AutoConfigureA.class, AutoConfigureB2.class));\n\t\tassertThat(Configurations.getClasses(configurations)).containsExactly(AutoConfigureB2.class,\n\t\t\t\tAutoConfigureA.class);\n\t}\n\n\t@Test\n\tvoid whenHasReplacementForClassShouldReplaceClass() {\n\t\tConfigurations configurations = new AutoConfigurations(this::replaceB,\n\t\t\t\tArrays.asList(AutoConfigureA.class, AutoConfigureB.class));\n\t\tassertThat(Configurations.getClasses(configurations)).containsExactly(AutoConfigureB2.class,\n\t\t\t\tAutoConfigureA.class);\n\t}\n\n\t@Test\n\tvoid getBeanNameShouldUseClassName() {\n\t\tConfigurations configurations = AutoConfigurations.of(AutoConfigureA.class, AutoConfigureB.class);\n\t\tassertThat(configurations.getBeanName(AutoConfigureA.class)).isEqualTo(AutoConfigureA.class.getName());\n\t}\n\n\tprivate String replaceB(String className) {\n\t\treturn (!AutoConfigureB.class.getName().equals(className)) ? className : AutoConfigureB2.class.getName();\n\t}\n\n\t@AutoConfigureAfter(AutoConfigureB.class)\n\tstatic class AutoConfigureA {\n\n\t}\n\n\tstatic class AutoConfigureB {\n\n\t}\n\n\tstatic class AutoConfigureB2 {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/EarlyInitFactoryBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.FactoryBean;\n\npublic class EarlyInitFactoryBean implements FactoryBean<String> {\n\n\tprivate @Nullable String propertyFromConfig;\n\n\tpublic void setPropertyFromConfig(String propertyFromConfig) {\n\t\tthis.propertyFromConfig = propertyFromConfig;\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic @Nullable Class<?> getObjectType() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable String getObject() throws Exception {\n\t\treturn this.propertyFromConfig;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.io.IOException;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImportAutoConfigurationImportSelector}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ImportAutoConfigurationImportSelectorTests {\n\n\tprivate final ImportAutoConfigurationImportSelector importSelector = new TestImportAutoConfigurationImportSelector();\n\n\tprivate final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.importSelector.setBeanFactory(this.beanFactory);\n\t\tthis.importSelector.setEnvironment(this.environment);\n\t\tthis.importSelector.setResourceLoader(new DefaultResourceLoader());\n\t\tthis.importSelector.setBeanClassLoader(Thread.currentThread().getContextClassLoader());\n\t}\n\n\t@Test\n\tvoid importsAreSelected() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(ImportImported.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsExactly(ImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid importsAreSelectedUsingClassesAttribute() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(ImportImportedUsingClassesAttribute.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsExactly(ImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\t@WithResource(\n\t\t\tname = \"META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFile.imports\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration\n\t\t\t\t\torg.springframework.boot.autoconfigure.missing.MissingAutoConfiguration\n\t\t\t\t\t\"\"\")\n\tvoid importsAreSelectedFromImportsFile() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(FromImportsFile.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsExactly(\n\t\t\t\t\"org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration\");\n\t}\n\n\t@Test\n\t@WithResource(\n\t\t\tname = \"META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFile.imports\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\toptional:org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration\n\t\t\t\t\toptional:org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration\n\t\t\t\t\torg.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$AnotherImportedAutoConfiguration\n\t\t\t\t\t\"\"\")\n\tvoid importsSelectedFromImportsFileIgnoreMissingOptionalClasses() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(FromImportsFile.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsExactly(\n\t\t\t\t\"org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$AnotherImportedAutoConfiguration\");\n\t}\n\n\t@Test\n\tvoid propertyExclusionsAreApplied() throws IOException {\n\t\tthis.environment.setProperty(\"spring.autoconfigure.exclude\", ImportedAutoConfiguration.class.getName());\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(MultipleImports.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsExactly(AnotherImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid multipleImportsAreFound() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(MultipleImports.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsOnly(ImportedAutoConfiguration.class.getName(),\n\t\t\t\tAnotherImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid selfAnnotatingAnnotationDoesNotCauseStackOverflow() throws IOException {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(ImportWithSelfAnnotatingAnnotation.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsOnly(AnotherImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid exclusionsAreApplied() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(MultipleImportsWithExclusion.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsOnly(ImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid exclusionsWithoutImport() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(ExclusionWithoutImport.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).containsOnly(ImportedAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid exclusionsAliasesAreApplied() throws Exception {\n\t\tAnnotationMetadata annotationMetadata = getAnnotationMetadata(ImportWithSelfAnnotatingAnnotationExclude.class);\n\t\tString[] imports = this.importSelector.selectImports(annotationMetadata);\n\t\tassertThat(imports).isEmpty();\n\t}\n\n\t@Test\n\tvoid determineImportsWhenUsingMetaWithoutClassesShouldBeEqual() throws Exception {\n\t\tSet<Object> set1 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationWithUnrelatedOne.class));\n\t\tSet<Object> set2 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationWithUnrelatedTwo.class));\n\t\tassertThat(set1).isEqualTo(set2);\n\t\tassertThat(set1).hasSameHashCodeAs(set2);\n\t}\n\n\t@Test\n\tvoid determineImportsWhenUsingNonMetaWithoutClassesShouldBeSame() throws Exception {\n\t\tSet<Object> set1 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportAutoConfigurationWithUnrelatedOne.class));\n\t\tSet<Object> set2 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportAutoConfigurationWithUnrelatedTwo.class));\n\t\tassertThat(set1).isEqualTo(set2);\n\t}\n\n\t@Test\n\tvoid determineImportsWhenUsingNonMetaWithClassesShouldBeSame() throws Exception {\n\t\tSet<Object> set1 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportAutoConfigurationWithItemsOne.class));\n\t\tSet<Object> set2 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportAutoConfigurationWithItemsTwo.class));\n\t\tassertThat(set1).isEqualTo(set2);\n\t}\n\n\t@Test\n\tvoid determineImportsWhenUsingMetaExcludeWithoutClassesShouldBeEqual() throws Exception {\n\t\tSet<Object> set1 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationExcludeWithUnrelatedOne.class));\n\t\tSet<Object> set2 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationExcludeWithUnrelatedTwo.class));\n\t\tassertThat(set1).isEqualTo(set2);\n\t\tassertThat(set1).hasSameHashCodeAs(set2);\n\t}\n\n\t@Test\n\tvoid determineImportsWhenUsingMetaDifferentExcludeWithoutClassesShouldBeDifferent() throws Exception {\n\t\tSet<Object> set1 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationExcludeWithUnrelatedOne.class));\n\t\tSet<Object> set2 = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationWithUnrelatedTwo.class));\n\t\tassertThat(set1).isNotEqualTo(set2);\n\t}\n\n\t@Test\n\tvoid determineImportsShouldNotSetPackageImport() throws Exception {\n\t\tClass<?> packageImportsClass = ClassUtils\n\t\t\t.resolveClassName(\"org.springframework.boot.autoconfigure.AutoConfigurationPackages.PackageImports\", null);\n\t\tSet<Object> selectedImports = this.importSelector\n\t\t\t.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationExcludeWithUnrelatedOne.class));\n\t\tfor (Object selectedImport : selectedImports) {\n\t\t\tassertThat(selectedImport).isNotInstanceOf(packageImportsClass);\n\t\t}\n\t}\n\n\tprivate AnnotationMetadata getAnnotationMetadata(Class<?> source) throws IOException {\n\t\treturn new SimpleMetadataReaderFactory().getMetadataReader(source.getName()).getAnnotationMetadata();\n\t}\n\n\t@ImportAutoConfiguration(ImportedAutoConfiguration.class)\n\tstatic class ImportImported {\n\n\t}\n\n\t@ImportAutoConfiguration(classes = ImportedAutoConfiguration.class)\n\tstatic class ImportImportedUsingClassesAttribute {\n\n\t}\n\n\t@ImportOne\n\t@ImportTwo\n\tstatic class MultipleImports {\n\n\t}\n\n\t@ImportOne\n\t@ImportTwo\n\t@ImportAutoConfiguration(exclude = AnotherImportedAutoConfiguration.class)\n\tstatic class MultipleImportsWithExclusion {\n\n\t}\n\n\t@ImportOne\n\t@ImportAutoConfiguration(exclude = AnotherImportedAutoConfiguration.class)\n\tstatic class ExclusionWithoutImport {\n\n\t}\n\n\t@SelfAnnotating\n\tstatic class ImportWithSelfAnnotatingAnnotation {\n\n\t}\n\n\t@SelfAnnotating(excludeAutoConfiguration = AnotherImportedAutoConfiguration.class)\n\tstatic class ImportWithSelfAnnotatingAnnotationExclude {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ImportAutoConfiguration(ImportedAutoConfiguration.class)\n\t@interface ImportOne {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ImportAutoConfiguration(AnotherImportedAutoConfiguration.class)\n\t@interface ImportTwo {\n\n\t}\n\n\t@MetaImportAutoConfiguration\n\t@UnrelatedOne\n\tstatic class ImportMetaAutoConfigurationWithUnrelatedOne {\n\n\t}\n\n\t@MetaImportAutoConfiguration\n\t@UnrelatedTwo\n\tstatic class ImportMetaAutoConfigurationWithUnrelatedTwo {\n\n\t}\n\n\t@ImportAutoConfiguration\n\t@UnrelatedOne\n\tstatic class ImportAutoConfigurationWithUnrelatedOne {\n\n\t}\n\n\t@ImportAutoConfiguration\n\t@UnrelatedTwo\n\tstatic class ImportAutoConfigurationWithUnrelatedTwo {\n\n\t}\n\n\t@ImportAutoConfiguration(classes = AnotherImportedAutoConfiguration.class)\n\t@UnrelatedOne\n\tstatic class ImportAutoConfigurationWithItemsOne {\n\n\t}\n\n\t@ImportAutoConfiguration(classes = AnotherImportedAutoConfiguration.class)\n\t@UnrelatedTwo\n\tstatic class ImportAutoConfigurationWithItemsTwo {\n\n\t}\n\n\t@MetaImportAutoConfiguration(exclude = AnotherImportedAutoConfiguration.class)\n\t@UnrelatedOne\n\tstatic class ImportMetaAutoConfigurationExcludeWithUnrelatedOne {\n\n\t}\n\n\t@MetaImportAutoConfiguration(exclude = AnotherImportedAutoConfiguration.class)\n\t@UnrelatedTwo\n\tstatic class ImportMetaAutoConfigurationExcludeWithUnrelatedTwo {\n\n\t}\n\n\t@ImportAutoConfiguration\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface MetaImportAutoConfiguration {\n\n\t\t@AliasFor(annotation = ImportAutoConfiguration.class)\n\t\tClass<?>[] exclude() default {\n\n\t\t};\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface UnrelatedOne {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface UnrelatedTwo {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ImportAutoConfiguration(AnotherImportedAutoConfiguration.class)\n\t@SelfAnnotating\n\t@interface SelfAnnotating {\n\n\t\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\t\tClass<?>[] excludeAutoConfiguration() default {\n\n\t\t};\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ImportAutoConfiguration\n\t@interface FromImportsFile {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ImportAutoConfiguration\n\t@interface FromImportsFileIgnoresMissingOptionalClasses {\n\n\t}\n\n\tstatic class TestImportAutoConfigurationImportSelector extends ImportAutoConfigurationImportSelector {\n\n\t\t@Override\n\t\tprotected Collection<String> loadFactoryNames(Class<?> source) {\n\t\t\tif (source == MetaImportAutoConfiguration.class) {\n\t\t\t\treturn Arrays.asList(AnotherImportedAutoConfiguration.class.getName(),\n\t\t\t\t\t\tImportedAutoConfiguration.class.getName());\n\t\t\t}\n\t\t\treturn super.loadFactoryNames(source);\n\t\t}\n\n\t}\n\n\t@AutoConfiguration\n\tpublic static final class ImportedAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\tpublic static final class AnotherImportedAutoConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImportAutoConfiguration @ImportAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass ImportAutoConfigurationTests {\n\n\t@Test\n\tvoid multipleAnnotationsShouldMergeCorrectly() {\n\t\tassertThat(getImportedConfigBeans(Config.class)).containsExactly(\"ConfigA\", \"ConfigB\", \"ConfigC\", \"ConfigD\");\n\t\tassertThat(getImportedConfigBeans(AnotherConfig.class)).containsExactly(\"ConfigA\", \"ConfigB\", \"ConfigC\",\n\t\t\t\t\"ConfigD\");\n\t}\n\n\t@Test\n\tvoid classesAsAnAlias() {\n\t\tassertThat(getImportedConfigBeans(AnotherConfigUsingClasses.class)).containsExactly(\"ConfigA\", \"ConfigB\",\n\t\t\t\t\"ConfigC\", \"ConfigD\");\n\t}\n\n\t@Test\n\tvoid excluding() {\n\t\tassertThat(getImportedConfigBeans(ExcludingConfig.class)).containsExactly(\"ConfigA\", \"ConfigB\", \"ConfigD\");\n\t}\n\n\t@Test\n\tvoid excludeAppliedGlobally() {\n\t\tassertThat(getImportedConfigBeans(ExcludeDConfig.class, ImportADConfig.class)).containsExactly(\"ConfigA\");\n\t}\n\n\t@Test\n\tvoid excludeWithRedundancy() {\n\t\tassertThat(getImportedConfigBeans(ExcludeADConfig.class, ExcludeDConfig.class, ImportADConfig.class)).isEmpty();\n\t}\n\n\tprivate List<String> getImportedConfigBeans(Class<?>... config) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(config);\n\t\tString shortName = ClassUtils.getShortName(ImportAutoConfigurationTests.class);\n\t\tint beginIndex = shortName.length() + 1;\n\t\tList<String> orderedConfigBeans = new ArrayList<>();\n\t\tfor (String bean : context.getBeanDefinitionNames()) {\n\t\t\tif (bean.contains(\"$Config\")) {\n\t\t\t\tString shortBeanName = ClassUtils.getShortName(bean);\n\t\t\t\torderedConfigBeans.add(shortBeanName.substring(beginIndex));\n\t\t\t}\n\t\t}\n\t\tcontext.close();\n\t\treturn orderedConfigBeans;\n\t}\n\n\t@ImportAutoConfiguration({ ConfigD.class, ConfigB.class })\n\t@MetaImportAutoConfiguration\n\tstatic class Config {\n\n\t}\n\n\t@MetaImportAutoConfiguration\n\t@ImportAutoConfiguration({ ConfigB.class, ConfigD.class })\n\tstatic class AnotherConfig {\n\n\t}\n\n\t@MetaImportAutoConfiguration\n\t@ImportAutoConfiguration(classes = { ConfigB.class, ConfigD.class })\n\tstatic class AnotherConfigUsingClasses {\n\n\t}\n\n\t@ImportAutoConfiguration(classes = { ConfigD.class, ConfigB.class }, exclude = ConfigC.class)\n\t@MetaImportAutoConfiguration\n\tstatic class ExcludingConfig {\n\n\t}\n\n\t@ImportAutoConfiguration(classes = { ConfigA.class, ConfigD.class })\n\tstatic class ImportADConfig {\n\n\t}\n\n\t@ImportAutoConfiguration(exclude = { ConfigA.class, ConfigD.class })\n\tstatic class ExcludeADConfig {\n\n\t}\n\n\t@ImportAutoConfiguration(exclude = ConfigD.class)\n\tstatic class ExcludeDConfig {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@ImportAutoConfiguration({ ConfigC.class, ConfigA.class })\n\t@interface MetaImportAutoConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigA {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigureAfter(ConfigA.class)\n\tstatic class ConfigB {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigureAfter(ConfigB.class)\n\tstatic class ConfigC {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigureAfter(ConfigC.class)\n\tstatic class ConfigD {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/SharedMetadataReaderFactoryContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.ConfigurationClassPostProcessor;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SharedMetadataReaderFactoryContextInitializer}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\nclass SharedMetadataReaderFactoryContextInitializerTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid checkOrderOfInitializer() {\n\t\tSpringApplication application = new SpringApplication(TestConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tList<ApplicationContextInitializer<?>> initializers = (List<ApplicationContextInitializer<?>>) ReflectionTestUtils\n\t\t\t.getField(application, \"initializers\");\n\t\t// Simulate what would happen if an initializer was added using spring.factories\n\t\t// and happened to be loaded first\n\t\tassertThat(initializers).isNotNull();\n\t\tinitializers.add(0, new Initializer());\n\t\tGenericApplicationContext context = (GenericApplicationContext) application.run();\n\t\tBeanDefinition definition = context.getBeanDefinition(SharedMetadataReaderFactoryContextInitializer.BEAN_NAME);\n\t\tassertThat(definition.getAttribute(\"seen\")).isEqualTo(true);\n\t}\n\n\t@Test\n\tvoid initializeWhenUsingSupplierDecorates() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tBeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getBeanFactory();\n\t\tConfigurationClassPostProcessor configurationAnnotationPostProcessor = mock(\n\t\t\t\tConfigurationClassPostProcessor.class);\n\t\tBeanDefinition beanDefinition = BeanDefinitionBuilder\n\t\t\t.rootBeanDefinition(ConfigurationClassPostProcessor.class, () -> configurationAnnotationPostProcessor)\n\t\t\t.getBeanDefinition();\n\t\tregistry.registerBeanDefinition(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME,\n\t\t\t\tbeanDefinition);\n\t\tCachingMetadataReaderFactoryPostProcessor postProcessor = new CachingMetadataReaderFactoryPostProcessor(\n\t\t\t\tcontext);\n\t\tpostProcessor.postProcessBeanDefinitionRegistry(registry);\n\t\tcontext.refresh();\n\t\tConfigurationClassPostProcessor bean = context.getBean(ConfigurationClassPostProcessor.class);\n\t\tassertThat(bean).isSameAs(configurationAnnotationPostProcessor);\n\t\tthen(configurationAnnotationPostProcessor).should()\n\t\t\t.setMetadataReaderFactory(assertArg((metadataReaderFactory) -> assertThat(metadataReaderFactory)\n\t\t\t\t.isInstanceOf(CachingMetadataReaderFactory.class)));\n\t}\n\n\tstatic class TestConfig {\n\n\t}\n\n\tstatic class Initializer implements ApplicationContextInitializer<GenericApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(GenericApplicationContext applicationContext) {\n\t\t\tapplicationContext.addBeanFactoryPostProcessor(new PostProcessor());\n\t\t}\n\n\t}\n\n\tstatic class PostProcessor implements BeanDefinitionRegistryPostProcessor {\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {\n\t\t\tfor (String name : registry.getBeanDefinitionNames()) {\n\t\t\t\tBeanDefinition definition = registry.getBeanDefinition(name);\n\t\t\t\tdefinition.setAttribute(\"seen\", true);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/SpringBootApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultBeanNameGenerator;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootApplication @SpringBootApplication}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass SpringBootApplicationTests {\n\n\t@Test\n\tvoid proxyBeanMethodsIsEnabledByDefault() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(DefaultSpringBootApplication.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", true);\n\t}\n\n\t@Test\n\tvoid proxyBeanMethodsCanBeDisabled() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(NoBeanMethodProxyingSpringBootApplication.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", false);\n\t}\n\n\t@Test\n\tvoid nameGeneratorDefaultToBeanNameGenerator() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(DefaultSpringBootApplication.class, ComponentScan.class);\n\t\tassertThat(attributes).containsEntry(\"nameGenerator\", BeanNameGenerator.class);\n\t}\n\n\t@Test\n\tvoid nameGeneratorCanBeSpecified() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(CustomNameGeneratorConfiguration.class, ComponentScan.class);\n\t\tassertThat(attributes).containsEntry(\"nameGenerator\", TestBeanNameGenerator.class);\n\t}\n\n\t@SpringBootApplication\n\tstatic class DefaultSpringBootApplication {\n\n\t}\n\n\t@SpringBootApplication(proxyBeanMethods = false)\n\tstatic class NoBeanMethodProxyingSpringBootApplication {\n\n\t}\n\n\t@SpringBootApplication(nameGenerator = TestBeanNameGenerator.class)\n\tstatic class CustomNameGeneratorConfiguration {\n\n\t}\n\n\tstatic class TestBeanNameGenerator extends DefaultBeanNameGenerator {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/TestAutoConfigurationSorter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.function.UnaryOperator;\n\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\n\n/**\n * Public version of {@link AutoConfigurationSorter} for use in tests.\n *\n * @author Phillip Webb\n */\npublic class TestAutoConfigurationSorter extends AutoConfigurationSorter {\n\n\tpublic TestAutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,\n\t\t\tUnaryOperator<String> replacementMapper) {\n\t\tsuper(metadataReaderFactory, AutoConfigurationMetadataLoader.loadMetadata(new Properties()), replacementMapper);\n\t}\n\n\t@Override\n\tpublic List<String> getInPriorityOrder(Collection<String> classNames) {\n\t\treturn super.getInPriorityOrder(classNames);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/admin/SpringApplicationAdminJmxAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.admin;\n\nimport java.lang.management.ManagementFactory;\n\nimport javax.management.InstanceNotFoundException;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectInstance;\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jmx.export.MBeanExporter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link SpringApplicationAdminJmxAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Nguyen Bao Sach\n */\nclass SpringApplicationAdminJmxAutoConfigurationTests {\n\n\tprivate static final String ENABLE_ADMIN_PROP = \"spring.application.admin.enabled=true\";\n\n\tprivate static final String DEFAULT_JMX_NAME = \"org.springframework.boot:type=Admin,name=SpringApplication\";\n\n\tprivate final MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SpringApplicationAdminJmxAutoConfiguration.class));\n\n\t@Test\n\tvoid notRegisteredWhenThereAreNoMBeanExporter() {\n\t\tthis.contextRunner.withPropertyValues(ENABLE_ADMIN_PROP).run((context) -> {\n\t\t\tObjectName objectName = createDefaultObjectName();\n\t\t\tObjectInstance objectInstance = this.server.getObjectInstance(objectName);\n\t\t\tassertThat(objectInstance).as(\"Lifecycle bean should have been registered\").isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid notRegisteredByDefaultWhenThereAreMultipleMBeanExporters() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleMBeanExportersConfiguration.class)\n\t\t\t.run((context) -> assertThatExceptionOfType(InstanceNotFoundException.class)\n\t\t\t\t.isThrownBy(() -> this.server.getObjectInstance(createDefaultObjectName())));\n\t}\n\n\t@Test\n\tvoid registeredWithPropertyWhenThereAreMultipleMBeanExporters() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleMBeanExportersConfiguration.class)\n\t\t\t.withPropertyValues(ENABLE_ADMIN_PROP)\n\t\t\t.run((context) -> {\n\t\t\t\tObjectName objectName = createDefaultObjectName();\n\t\t\t\tObjectInstance objectInstance = this.server.getObjectInstance(objectName);\n\t\t\t\tassertThat(objectInstance).as(\"Lifecycle bean should have been registered\").isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registerWithCustomJmxNameWhenThereAreMultipleMBeanExporters() {\n\t\tString customJmxName = \"org.acme:name=FooBar\";\n\t\tthis.contextRunner.withUserConfiguration(MultipleMBeanExportersConfiguration.class)\n\t\t\t.withSystemProperties(\"spring.application.admin.jmx-name=\" + customJmxName)\n\t\t\t.withPropertyValues(ENABLE_ADMIN_PROP)\n\t\t\t.run((context) -> {\n\t\t\t\ttry {\n\t\t\t\t\tthis.server.getObjectInstance(createObjectName(customJmxName));\n\t\t\t\t}\n\t\t\t\tcatch (InstanceNotFoundException ex) {\n\t\t\t\t\tfail(\"Admin MBean should have been exposed with custom name\");\n\t\t\t\t}\n\t\t\t\tassertThatExceptionOfType(InstanceNotFoundException.class)\n\t\t\t\t\t.isThrownBy(() -> this.server.getObjectInstance(createDefaultObjectName()));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid onlyRegisteredOnceWhenThereIsAChildContext() {\n\t\tSpringApplicationBuilder parentBuilder = new SpringApplicationBuilder().web(WebApplicationType.NONE)\n\t\t\t.sources(MultipleMBeanExportersConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class);\n\t\tSpringApplicationBuilder childBuilder = parentBuilder\n\t\t\t.child(MultipleMBeanExportersConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class)\n\t\t\t.web(WebApplicationType.NONE);\n\t\ttry (ConfigurableApplicationContext parent = parentBuilder.run(\"--\" + ENABLE_ADMIN_PROP);\n\t\t\t\tConfigurableApplicationContext child = childBuilder.run(\"--\" + ENABLE_ADMIN_PROP)) {\n\t\t\tBeanFactoryUtils.beanOfType(parent.getBeanFactory(), SpringApplicationAdminMXBeanRegistrar.class);\n\t\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> BeanFactoryUtils\n\t\t\t\t.beanOfType(child.getBeanFactory(), SpringApplicationAdminMXBeanRegistrar.class));\n\t\t}\n\t}\n\n\tprivate ObjectName createDefaultObjectName() {\n\t\treturn createObjectName(DEFAULT_JMX_NAME);\n\t}\n\n\tprivate ObjectName createObjectName(String jmxName) {\n\t\ttry {\n\t\t\treturn new ObjectName(jmxName);\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid jmx name \" + jmxName, ex);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleMBeanExportersConfiguration {\n\n\t\t@Bean\n\t\tMBeanExporter firstMBeanExporter() {\n\t\t\treturn new MBeanExporter();\n\t\t}\n\n\t\t@Bean\n\t\tMBeanExporter secondMBeanExporter() {\n\t\t\treturn new MBeanExporter();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/aop/AopAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.aop;\n\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Before;\nimport org.aspectj.weaver.Advice;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AopAutoConfiguration}.\n *\n * @author Eberhard Wolff\n * @author Stephane Nicoll\n */\nclass AopAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AopAutoConfiguration.class));\n\n\t@Test\n\tvoid aopDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.aop.auto:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tTestAspect aspect = context.getBean(TestAspect.class);\n\t\t\t\tassertThat(aspect.isCalled()).isFalse();\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tbean.foo();\n\t\t\t\tassertThat(aspect.isCalled()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid aopWithDefaultSettings() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run(proxyTargetClassEnabled());\n\t}\n\n\t@Test\n\tvoid aopWithEnabledProxyTargetClass() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.aop.proxy-target-class:true\")\n\t\t\t.run(proxyTargetClassEnabled());\n\t}\n\n\t@Test\n\tvoid aopWithDisabledProxyTargetClass() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.aop.proxy-target-class:false\")\n\t\t\t.run(proxyTargetClassDisabled());\n\t}\n\n\t@Test\n\tvoid customConfigurationWithProxyTargetClassDefaultDoesNotDisableProxying() {\n\t\tthis.contextRunner.withUserConfiguration(CustomTestConfiguration.class).run(proxyTargetClassEnabled());\n\n\t}\n\n\t@Test\n\tvoid whenGlobalMethodSecurityIsEnabledAndAspectJIsNotAvailableThenClassProxyingIsStillUsedByDefault() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class))\n\t\t\t.withUserConfiguration(ExampleController.class, EnableGlobalMethodSecurityConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getBean(ExampleController.class).matches(AopUtils::isCglibProxy));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> proxyTargetClassEnabled() {\n\t\treturn (context) -> {\n\t\t\tTestAspect aspect = context.getBean(TestAspect.class);\n\t\t\tassertThat(aspect.isCalled()).isFalse();\n\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\tbean.foo();\n\t\t\tassertThat(aspect.isCalled()).isTrue();\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> proxyTargetClassDisabled() {\n\t\treturn (context) -> {\n\t\t\tTestAspect aspect = context.getBean(TestAspect.class);\n\t\t\tassertThat(aspect.isCalled()).isFalse();\n\t\t\tTestInterface bean = context.getBean(TestInterface.class);\n\t\t\tbean.foo();\n\t\t\tassertThat(aspect.isCalled()).isTrue();\n\t\t\tassertThat(context).doesNotHaveBean(TestBean.class);\n\t\t};\n\t}\n\n\t@EnableAspectJAutoProxy\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestConfiguration.class)\n\tstatic class CustomTestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestAspect aspect() {\n\t\t\treturn new TestAspect();\n\t\t}\n\n\t\t@Bean\n\t\tTestInterface bean() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\tstatic class TestBean implements TestInterface {\n\n\t\t@Override\n\t\tpublic void foo() {\n\t\t}\n\n\t}\n\n\t@Aspect\n\tstatic class TestAspect {\n\n\t\tprivate boolean called;\n\n\t\tboolean isCalled() {\n\t\t\treturn this.called;\n\t\t}\n\n\t\t@Before(\"execution(* foo(..))\")\n\t\tvoid before() {\n\t\t\tthis.called = true;\n\t\t}\n\n\t}\n\n\tinterface TestInterface {\n\n\t\tvoid foo();\n\n\t}\n\n\t@EnableMethodSecurity(prePostEnabled = true)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EnableGlobalMethodSecurityConfiguration {\n\n\t}\n\n\tpublic static class ExampleController implements TestInterface {\n\n\t\t@RequestMapping(\"/test\")\n\t\t@PreAuthorize(\"true\")\n\t\tString demo() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t\t@Override\n\t\tpublic void foo() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/aop/NonAspectJAopAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.aop;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.config.AopConfigUtils;\nimport org.springframework.aop.framework.autoproxy.AutoProxyUtils;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AopAutoConfiguration} without AspectJ.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"aspectjweaver*.jar\")\nclass NonAspectJAopAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AopAutoConfiguration.class));\n\n\t@Test\n\tvoid whenAspectJIsAbsentAndProxyTargetClassIsEnabledProxyCreatorBeanIsDefined() {\n\t\tthis.contextRunner.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> {\n\t\t\t\tBeanDefinition defaultProxyConfig = context.getBeanFactory()\n\t\t\t\t\t.getBeanDefinition(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME);\n\t\t\t\tassertThat(defaultProxyConfig.getPropertyValues().get(\"proxyTargetClass\")).isEqualTo(Boolean.TRUE);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenAspectJIsAbsentAndProxyTargetClassIsDisabledNoProxyCreatorBeanIsDefined() {\n\t\tthis.contextRunner.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.withPropertyValues(\"spring.aop.proxy-target-class:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME)\n\t\t\t\t.doesNotHaveBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/availability/ApplicationAvailabilityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.availability;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ApplicationAvailabilityAutoConfiguration}\n *\n * @author Brian Clozel\n * @author Taeik Lim\n */\nclass ApplicationAvailabilityAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ApplicationAvailabilityAutoConfiguration.class));\n\n\t@Test\n\tvoid providerIsPresentWhenNotRegistered() {\n\t\tthis.contextRunner.run(((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t.hasBean(\"applicationAvailability\")));\n\t}\n\n\t@Test\n\tvoid providerIsNotConfiguredWhenCustomOneIsPresent() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customApplicationAvailability\", ApplicationAvailability.class,\n\t\t\t\t\t() -> mock(ApplicationAvailability.class))\n\t\t\t.run(((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t\t.hasBean(\"customApplicationAvailability\")));\n\t}\n\n\t@Test\n\tvoid whenLazyInitializationIsEnabledApplicationAvailabilityBeanShouldStillReceiveAvailabilityChangeEvents() {\n\t\tthis.contextRunner.withBean(LazyInitializationBeanFactoryPostProcessor.class).run((context) -> {\n\t\t\tAvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);\n\t\t\tApplicationAvailability applicationAvailability = context.getBean(ApplicationAvailability.class);\n\t\t\tassertThat(applicationAvailability.getLastChangeEvent(ReadinessState.class)).isNotNull();\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/AbstractNestedConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractNestedCondition}.\n *\n * @author Razib Shahriar\n */\nclass AbstractNestedConditionTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid validPhase() {\n\t\tthis.contextRunner.withUserConfiguration(ValidConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"myBean\"));\n\t}\n\n\t@Test\n\tvoid invalidMemberPhase() {\n\t\tthis.contextRunner.withUserConfiguration(InvalidConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tThrowable startupFailure = context.getStartupFailure();\n\t\t\tassertThat(startupFailure).isNotNull();\n\t\t\tassertThat(startupFailure.getCause()).isInstanceOf(IllegalStateException.class)\n\t\t\t\t.hasMessageContaining(\"Nested condition \" + InvalidNestedCondition.class.getName()\n\t\t\t\t\t\t+ \" uses a configuration phase that is inappropriate for class \"\n\t\t\t\t\t\t+ OnBeanCondition.class.getName());\n\t\t});\n\t}\n\n\t@Test\n\tvoid invalidNestedMemberPhase() {\n\t\tthis.contextRunner.withUserConfiguration(DoubleNestedConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tThrowable startupFailure = context.getStartupFailure();\n\t\t\tassertThat(startupFailure).isNotNull();\n\t\t\tassertThat(startupFailure.getCause()).isInstanceOf(IllegalStateException.class)\n\t\t\t\t.hasMessageContaining(\"Nested condition \" + DoubleNestedCondition.class.getName()\n\t\t\t\t\t\t+ \" uses a configuration phase that is inappropriate for class \"\n\t\t\t\t\t\t+ ValidNestedCondition.class.getName());\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(ValidNestedCondition.class)\n\tstatic class ValidConfig {\n\n\t\t@Bean\n\t\tString myBean() {\n\t\t\treturn \"myBean\";\n\t\t}\n\n\t}\n\n\tstatic class ValidNestedCondition extends AbstractNestedCondition {\n\n\t\tValidNestedCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@Override\n\t\tprotected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {\n\t\t\treturn ConditionOutcome.match();\n\t\t}\n\n\t\t@ConditionalOnMissingBean(name = \"myBean\")\n\t\tstatic class MissingMyBean {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(InvalidNestedCondition.class)\n\tstatic class InvalidConfig {\n\n\t\t@Bean\n\t\tString myBean() {\n\t\t\treturn \"myBean\";\n\t\t}\n\n\t}\n\n\tstatic class InvalidNestedCondition extends AbstractNestedCondition {\n\n\t\tInvalidNestedCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@Override\n\t\tprotected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {\n\t\t\treturn ConditionOutcome.match();\n\t\t}\n\n\t\t@ConditionalOnMissingBean(name = \"myBean\")\n\t\tstatic class MissingMyBean {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(DoubleNestedCondition.class)\n\tstatic class DoubleNestedConfig {\n\n\t}\n\n\tstatic class DoubleNestedCondition extends AbstractNestedCondition {\n\n\t\tDoubleNestedCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@Override\n\t\tprotected ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes) {\n\t\t\treturn ConditionOutcome.match();\n\t\t}\n\n\t\t@Conditional(ValidNestedCondition.class)\n\t\tstatic class NestedConditionThatIsValid {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/AllNestedConditionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AllNestedConditions}.\n */\nclass AllNestedConditionsTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid neither() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).run(match(false));\n\t}\n\n\t@Test\n\tvoid propertyA() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).withPropertyValues(\"a:a\").run(match(false));\n\t}\n\n\t@Test\n\tvoid propertyB() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).withPropertyValues(\"b:b\").run(match(false));\n\t}\n\n\t@Test\n\tvoid both() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).withPropertyValues(\"a:a\", \"b:b\").run(match(true));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> match(boolean expected) {\n\t\treturn (context) -> {\n\t\t\tif (expected) {\n\t\t\t\tassertThat(context).hasBean(\"myBean\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"myBean\");\n\t\t\t}\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(OnPropertyAAndBCondition.class)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tString myBean() {\n\t\t\treturn \"myBean\";\n\t\t}\n\n\t}\n\n\tstatic class OnPropertyAAndBCondition extends AllNestedConditions {\n\n\t\tOnPropertyAAndBCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"a\")\n\t\tstatic class HasPropertyA {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"b\")\n\t\tstatic class HasPropertyB {\n\n\t\t}\n\n\t\t@Conditional(NonSpringBootCondition.class)\n\t\tstatic class SubclassC {\n\n\t\t}\n\n\t}\n\n\tstatic class NonSpringBootCondition implements Condition {\n\n\t\t@Override\n\t\tpublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/AnyNestedConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AnyNestedCondition}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n */\nclass AnyNestedConditionTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid neither() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).run(match(false));\n\t}\n\n\t@Test\n\tvoid propertyA() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).withPropertyValues(\"a:a\").run(match(true));\n\t}\n\n\t@Test\n\tvoid propertyB() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).withPropertyValues(\"b:b\").run(match(true));\n\t}\n\n\t@Test\n\tvoid both() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).withPropertyValues(\"a:a\", \"b:b\").run(match(true));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> match(boolean expected) {\n\t\treturn (context) -> {\n\t\t\tif (expected) {\n\t\t\t\tassertThat(context).hasBean(\"myBean\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"myBean\");\n\t\t\t}\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(OnPropertyAorBCondition.class)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tString myBean() {\n\t\t\treturn \"myBean\";\n\t\t}\n\n\t}\n\n\tstatic class OnPropertyAorBCondition extends AnyNestedCondition {\n\n\t\tOnPropertyAorBCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"a\")\n\t\tstatic class HasPropertyA {\n\n\t\t}\n\n\t\t@ConditionalOnExpression(\"true\")\n\t\t@ConditionalOnProperty(\"b\")\n\t\tstatic class HasPropertyB {\n\n\t\t}\n\n\t\t@Conditional(NonSpringBootCondition.class)\n\t\tstatic class SubclassC {\n\n\t\t}\n\n\t}\n\n\tstatic class NonSpringBootCondition implements Condition {\n\n\t\t@Override\n\t\tpublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportAutoConfigurationImportListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportEvent;\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportListener;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionEvaluationReportAutoConfigurationImportListener}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass ConditionEvaluationReportAutoConfigurationImportListenerTests {\n\n\tprivate ConditionEvaluationReportAutoConfigurationImportListener listener;\n\n\tprivate final ConfigurableListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.listener = new ConditionEvaluationReportAutoConfigurationImportListener();\n\t\tthis.listener.setBeanFactory(this.beanFactory);\n\t}\n\n\t@Test\n\tvoid shouldBeInSpringFactories() {\n\t\tList<AutoConfigurationImportListener> factories = SpringFactoriesLoader\n\t\t\t.loadFactories(AutoConfigurationImportListener.class, null);\n\t\tassertThat(factories)\n\t\t\t.hasAtLeastOneElementOfType(ConditionEvaluationReportAutoConfigurationImportListener.class);\n\t}\n\n\t@Test\n\tvoid onAutoConfigurationImportEventShouldRecordCandidates() {\n\t\tList<String> candidateConfigurations = Collections.singletonList(\"Test\");\n\t\tSet<String> exclusions = Collections.emptySet();\n\t\tAutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, candidateConfigurations,\n\t\t\t\texclusions);\n\t\tthis.listener.onAutoConfigurationImportEvent(event);\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);\n\t\tassertThat(report.getUnconditionalClasses()).containsExactlyElementsOf(candidateConfigurations);\n\t}\n\n\t@Test\n\tvoid onAutoConfigurationImportEventShouldRecordExclusions() {\n\t\tList<String> candidateConfigurations = Collections.emptyList();\n\t\tSet<String> exclusions = Collections.singleton(\"Test\");\n\t\tAutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, candidateConfigurations,\n\t\t\t\texclusions);\n\t\tthis.listener.onAutoConfigurationImportEvent(event);\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);\n\t\tassertThat(report.getExclusions()).containsExactlyElementsOf(exclusions);\n\t}\n\n\t@Test\n\tvoid onAutoConfigurationImportEventShouldApplyExclusionsGlobally() {\n\t\tAutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, Arrays.asList(\"First\", \"Second\"),\n\t\t\t\tCollections.emptySet());\n\t\tthis.listener.onAutoConfigurationImportEvent(event);\n\t\tAutoConfigurationImportEvent anotherEvent = new AutoConfigurationImportEvent(this, Collections.emptyList(),\n\t\t\t\tCollections.singleton(\"First\"));\n\t\tthis.listener.onAutoConfigurationImportEvent(anotherEvent);\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);\n\t\tassertThat(report.getUnconditionalClasses()).containsExactly(\"Second\");\n\t\tassertThat(report.getExclusions()).containsExactly(\"First\");\n\t}\n\n\t@Test\n\tvoid onAutoConfigurationImportEventShouldApplyExclusionsGloballyWhenExclusionIsAlreadyApplied() {\n\t\tAutoConfigurationImportEvent excludeEvent = new AutoConfigurationImportEvent(this, Collections.emptyList(),\n\t\t\t\tCollections.singleton(\"First\"));\n\t\tthis.listener.onAutoConfigurationImportEvent(excludeEvent);\n\t\tAutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, Arrays.asList(\"First\", \"Second\"),\n\t\t\t\tCollections.emptySet());\n\t\tthis.listener.onAutoConfigurationImportEvent(event);\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);\n\t\tassertThat(report.getUnconditionalClasses()).containsExactly(\"Second\");\n\t\tassertThat(report.getExclusions()).containsExactly(\"First\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.time.Duration;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.autoconfigure.condition.config.UniqueShortNameAutoConfiguration;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ConfigurationCondition;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionEvaluationReport}.\n *\n * @author Greg Turnquist\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass ConditionEvaluationReportTests {\n\n\tprivate DefaultListableBeanFactory beanFactory;\n\n\tprivate ConditionEvaluationReport report;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Condition condition1;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Condition condition2;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Condition condition3;\n\n\tprivate @Nullable ConditionOutcome outcome1;\n\n\tprivate @Nullable ConditionOutcome outcome2;\n\n\tprivate @Nullable ConditionOutcome outcome3;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.beanFactory = new DefaultListableBeanFactory();\n\t\tthis.report = ConditionEvaluationReport.get(this.beanFactory);\n\t}\n\n\t@Test\n\tvoid get() {\n\t\tassertThat(this.report).isNotNull();\n\t\tassertThat(this.report).isSameAs(ConditionEvaluationReport.get(this.beanFactory));\n\t}\n\n\t@Test\n\tvoid parent() {\n\t\tthis.beanFactory.setParentBeanFactory(new DefaultListableBeanFactory());\n\t\tBeanFactory parentBeanFactory = this.beanFactory.getParentBeanFactory();\n\t\tassertThat(parentBeanFactory).isNotNull();\n\t\tConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory);\n\t\tassertThat(this.report).isSameAs(ConditionEvaluationReport.get(this.beanFactory));\n\t\tassertThat(this.report).isNotNull();\n\t\tassertThat(this.report.getParent()).isNotNull();\n\t\tConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory);\n\t\tassertThat(this.report).isSameAs(ConditionEvaluationReport.get(this.beanFactory));\n\t\tassertThat(this.report.getParent())\n\t\t\t.isSameAs(ConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory));\n\t}\n\n\t@Test\n\tvoid parentBottomUp() {\n\t\tthis.beanFactory = new DefaultListableBeanFactory(); // NB: overrides setup\n\t\tthis.beanFactory.setParentBeanFactory(new DefaultListableBeanFactory());\n\t\tBeanFactory parentBeanFactory = this.beanFactory.getParentBeanFactory();\n\t\tassertThat(parentBeanFactory).isNotNull();\n\t\tConditionEvaluationReport.get((ConfigurableListableBeanFactory) parentBeanFactory);\n\t\tthis.report = ConditionEvaluationReport.get(this.beanFactory);\n\t\tassertThat(this.report).isNotNull();\n\t\tassertThat(this.report).isNotSameAs(this.report.getParent());\n\t\tassertThat(this.report.getParent()).isNotNull();\n\t\tassertThat(this.report.getParent().getParent()).isNull();\n\t}\n\n\t@Test\n\tvoid recordConditionEvaluations() {\n\t\tthis.outcome1 = new ConditionOutcome(false, \"m1\");\n\t\tthis.outcome2 = new ConditionOutcome(false, \"m2\");\n\t\tthis.outcome3 = new ConditionOutcome(false, \"m3\");\n\t\tthis.report.recordConditionEvaluation(\"a\", this.condition1, this.outcome1);\n\t\tthis.report.recordConditionEvaluation(\"a\", this.condition2, this.outcome2);\n\t\tthis.report.recordConditionEvaluation(\"b\", this.condition3, this.outcome3);\n\t\tMap<String, ConditionAndOutcomes> map = this.report.getConditionAndOutcomesBySource();\n\t\tassertThat(map).hasSize(2);\n\t\tConditionAndOutcomes a = map.get(\"a\");\n\t\tassertThat(a).isNotNull();\n\t\tIterator<ConditionAndOutcome> iterator = a.iterator();\n\t\tConditionAndOutcome conditionAndOutcome = iterator.next();\n\t\tassertThat(conditionAndOutcome.getCondition()).isEqualTo(this.condition1);\n\t\tassertThat(conditionAndOutcome.getOutcome()).isEqualTo(this.outcome1);\n\t\tconditionAndOutcome = iterator.next();\n\t\tassertThat(conditionAndOutcome.getCondition()).isEqualTo(this.condition2);\n\t\tassertThat(conditionAndOutcome.getOutcome()).isEqualTo(this.outcome2);\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t\tConditionAndOutcomes b = map.get(\"b\");\n\t\tassertThat(b).isNotNull();\n\t\titerator = b.iterator();\n\t\tconditionAndOutcome = iterator.next();\n\t\tassertThat(conditionAndOutcome.getCondition()).isEqualTo(this.condition3);\n\t\tassertThat(conditionAndOutcome.getOutcome()).isEqualTo(this.outcome3);\n\t\tassertThat(iterator.hasNext()).isFalse();\n\t}\n\n\t@Test\n\tvoid fullMatch() {\n\t\tprepareMatches(true, true, true);\n\t\tConditionAndOutcomes a = this.report.getConditionAndOutcomesBySource().get(\"a\");\n\t\tassertThat(a).isNotNull();\n\t\tassertThat(a.isFullMatch()).isTrue();\n\t}\n\n\t@Test\n\tvoid notFullMatch() {\n\t\tprepareMatches(true, false, true);\n\t\tConditionAndOutcomes a = this.report.getConditionAndOutcomesBySource().get(\"a\");\n\t\tassertThat(a).isNotNull();\n\t\tassertThat(a.isFullMatch()).isFalse();\n\t}\n\n\tprivate void prepareMatches(boolean m1, boolean m2, boolean m3) {\n\t\tthis.outcome1 = new ConditionOutcome(m1, \"m1\");\n\t\tthis.outcome2 = new ConditionOutcome(m2, \"m2\");\n\t\tthis.outcome3 = new ConditionOutcome(m3, \"m3\");\n\t\tthis.report.recordConditionEvaluation(\"a\", this.condition1, this.outcome1);\n\t\tthis.report.recordConditionEvaluation(\"a\", this.condition2, this.outcome2);\n\t\tthis.report.recordConditionEvaluation(\"a\", this.condition3, this.outcome3);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid springBootConditionPopulatesReport() {\n\t\tConditionEvaluationReport report = ConditionEvaluationReport\n\t\t\t.get(new AnnotationConfigApplicationContext(Config.class).getBeanFactory());\n\t\tassertThat(report.getUnconditionalClasses()).containsExactly(UnconditionalAutoConfiguration.class.getName());\n\t\tassertThat(report.getConditionAndOutcomesBySource()).containsOnlyKeys(MatchingAutoConfiguration.class.getName(),\n\t\t\t\tNonMatchingAutoConfiguration.class.getName());\n\t\tassertThat(report.getConditionAndOutcomesBySource().get(MatchingAutoConfiguration.class.getName()))\n\t\t\t.satisfies((outcomes) -> assertThat(outcomes).extracting(ConditionAndOutcome::getOutcome)\n\t\t\t\t.extracting(ConditionOutcome::isMatch)\n\t\t\t\t.containsOnly(true));\n\t\tassertThat(report.getConditionAndOutcomesBySource().get(NonMatchingAutoConfiguration.class.getName()))\n\t\t\t.satisfies((outcomes) -> assertThat(outcomes).extracting(ConditionAndOutcome::getOutcome)\n\t\t\t\t.extracting(ConditionOutcome::isMatch)\n\t\t\t\t.containsOnly(false));\n\t}\n\n\t@Test\n\tvoid testDuplicateConditionAndOutcomes() {\n\t\tConditionAndOutcome outcome1 = new ConditionAndOutcome(this.condition1,\n\t\t\t\tnew ConditionOutcome(true, \"Message 1\"));\n\t\tConditionAndOutcome outcome2 = new ConditionAndOutcome(this.condition2,\n\t\t\t\tnew ConditionOutcome(true, \"Message 2\"));\n\t\tConditionAndOutcome outcome3 = new ConditionAndOutcome(this.condition3,\n\t\t\t\tnew ConditionOutcome(true, \"Message 2\"));\n\t\tassertThat(outcome1).isNotEqualTo(outcome2);\n\t\tassertThat(outcome2).isEqualTo(outcome3);\n\t\tConditionAndOutcomes outcomes = new ConditionAndOutcomes();\n\t\toutcomes.add(this.condition1, new ConditionOutcome(true, \"Message 1\"));\n\t\toutcomes.add(this.condition2, new ConditionOutcome(true, \"Message 2\"));\n\t\toutcomes.add(this.condition3, new ConditionOutcome(true, \"Message 2\"));\n\t\tassertThat(outcomes).hasSize(2);\n\t}\n\n\t@Test\n\tvoid negativeOuterPositiveInnerBean() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"test.present=true\").applyTo(context);\n\t\tcontext.register(NegativeOuterConfig.class);\n\t\tcontext.refresh();\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());\n\t\tMap<String, ConditionAndOutcomes> sourceOutcomes = report.getConditionAndOutcomesBySource();\n\t\tassertThat(context.containsBean(\"negativeOuterPositiveInnerBean\")).isFalse();\n\t\tString negativeConfig = NegativeOuterConfig.class.getName();\n\t\tConditionAndOutcomes negativeOutcome = sourceOutcomes.get(negativeConfig);\n\t\tassertThat(negativeOutcome).isNotNull();\n\t\tassertThat(negativeOutcome.isFullMatch()).isFalse();\n\t\tString positiveConfig = NegativeOuterConfig.PositiveInnerConfig.class.getName();\n\t\tConditionAndOutcomes positiveOutcome = sourceOutcomes.get(positiveConfig);\n\t\tassertThat(positiveOutcome).isNotNull();\n\t\tassertThat(positiveOutcome.isFullMatch()).isFalse();\n\t}\n\n\t@Test\n\tvoid reportWhenSameShortNamePresentMoreThanOnceShouldUseFullyQualifiedName() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(UniqueShortNameAutoConfiguration.class,\n\t\t\t\torg.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration.class,\n\t\t\t\torg.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration.class);\n\t\tcontext.refresh();\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());\n\t\tassertThat(report.getConditionAndOutcomesBySource()).containsKeys(\n\t\t\t\t\"org.springframework.boot.autoconfigure.condition.config.UniqueShortNameAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration\");\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid reportMessageWhenSameShortNamePresentMoreThanOnceShouldUseFullyQualifiedName() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(UniqueShortNameAutoConfiguration.class,\n\t\t\t\torg.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration.class,\n\t\t\t\torg.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration.class);\n\t\tcontext.refresh();\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());\n\t\tString reportMessage = new ConditionEvaluationReportMessage(report).toString();\n\t\tassertThat(reportMessage).contains(\"UniqueShortNameAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration\");\n\t\tassertThat(reportMessage)\n\t\t\t.doesNotContain(\"org.springframework.boot.autoconfigure.condition.config.UniqueShortNameAutoConfiguration\");\n\t\tcontext.close();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional({ ConditionEvaluationReportTests.MatchParseCondition.class,\n\t\t\tConditionEvaluationReportTests.NoMatchBeanCondition.class })\n\tstatic class NegativeOuterConfig {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@Conditional({ ConditionEvaluationReportTests.MatchParseCondition.class })\n\t\tstatic class PositiveInnerConfig {\n\n\t\t\t@Bean\n\t\t\tString negativeOuterPositiveInnerBean() {\n\t\t\t\treturn \"negativeOuterPositiveInnerBean\";\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class TestMatchCondition extends SpringBootCondition implements ConfigurationCondition {\n\n\t\tprivate final ConfigurationPhase phase;\n\n\t\tprivate final boolean match;\n\n\t\tTestMatchCondition(ConfigurationPhase phase, boolean match) {\n\t\t\tthis.phase = phase;\n\t\t\tthis.match = match;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConfigurationPhase getConfigurationPhase() {\n\t\t\treturn this.phase;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\treturn new ConditionOutcome(this.match, ClassUtils.getShortName(getClass()));\n\t\t}\n\n\t}\n\n\tstatic class MatchParseCondition extends TestMatchCondition {\n\n\t\tMatchParseCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION, true);\n\t\t}\n\n\t}\n\n\tstatic class MatchBeanCondition extends TestMatchCondition {\n\n\t\tMatchBeanCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN, true);\n\t\t}\n\n\t}\n\n\tstatic class NoMatchParseCondition extends TestMatchCondition {\n\n\t\tNoMatchParseCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION, false);\n\t\t}\n\n\t}\n\n\tstatic class NoMatchBeanCondition extends TestMatchCondition {\n\n\t\tNoMatchBeanCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN, false);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ MatchingAutoConfiguration.class, NonMatchingAutoConfiguration.class,\n\t\t\tUnconditionalAutoConfiguration.class })\n\tstatic class Config {\n\n\t}\n\n\t@AutoConfiguration\n\t@ConditionalOnProperty(name = \"com.example.property\", matchIfMissing = true)\n\tpublic static final class MatchingAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\t@ConditionalOnBean(Duration.class)\n\tpublic static final class NonMatchingAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\tpublic static final class UnconditionalAutoConfiguration {\n\n\t\t@Bean\n\t\tString example() {\n\t\t\treturn \"example\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionMessageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionMessage}.\n *\n * @author Phillip Webb\n */\nclass ConditionMessageTests {\n\n\t@Test\n\tvoid isEmptyWhenEmptyShouldReturnTrue() {\n\t\tConditionMessage message = ConditionMessage.empty();\n\t\tassertThat(message.isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid isEmptyWhenNotEmptyShouldReturnFalse() {\n\t\tConditionMessage message = ConditionMessage.of(\"Test\");\n\t\tassertThat(message.isEmpty()).isFalse();\n\t}\n\n\t@Test\n\tvoid toStringWhenEmptyShouldReturnEmptyString() {\n\t\tConditionMessage message = ConditionMessage.empty();\n\t\tassertThat(message).hasToString(\"\");\n\t}\n\n\t@Test\n\tvoid toStringWhenHasMessageShouldReturnMessage() {\n\t\tConditionMessage message = ConditionMessage.of(\"Test\");\n\t\tassertThat(message).hasToString(\"Test\");\n\t}\n\n\t@Test\n\tvoid appendWhenHasExistingMessageShouldAddSpace() {\n\t\tConditionMessage message = ConditionMessage.of(\"a\").append(\"b\");\n\t\tassertThat(message).hasToString(\"a b\");\n\t}\n\n\t@Test\n\tvoid appendWhenAppendingNullShouldDoNothing() {\n\t\tConditionMessage message = ConditionMessage.of(\"a\").append(null);\n\t\tassertThat(message).hasToString(\"a\");\n\t}\n\n\t@Test\n\tvoid appendWhenNoMessageShouldNotAddSpace() {\n\t\tConditionMessage message = ConditionMessage.empty().append(\"b\");\n\t\tassertThat(message).hasToString(\"b\");\n\t}\n\n\t@Test\n\tvoid andConditionWhenUsingClassShouldIncludeCondition() {\n\t\tConditionMessage message = ConditionMessage.empty().andCondition(Test.class).because(\"OK\");\n\t\tassertThat(message).hasToString(\"@Test OK\");\n\t}\n\n\t@Test\n\tvoid andConditionWhenUsingStringShouldIncludeCondition() {\n\t\tConditionMessage message = ConditionMessage.empty().andCondition(\"@Test\").because(\"OK\");\n\t\tassertThat(message).hasToString(\"@Test OK\");\n\t}\n\n\t@Test\n\tvoid andConditionWhenIncludingDetailsShouldIncludeCondition() {\n\t\tConditionMessage message = ConditionMessage.empty().andCondition(Test.class, \"(a=b)\").because(\"OK\");\n\t\tassertThat(message).hasToString(\"@Test (a=b) OK\");\n\t}\n\n\t@Test\n\tvoid ofCollectionShouldCombine() {\n\t\tList<ConditionMessage> messages = new ArrayList<>();\n\t\tmessages.add(ConditionMessage.of(\"a\"));\n\t\tmessages.add(ConditionMessage.of(\"b\"));\n\t\tConditionMessage message = ConditionMessage.of(messages);\n\t\tassertThat(message).hasToString(\"a; b\");\n\t}\n\n\t@Test\n\tvoid ofCollectionWhenNullShouldReturnEmpty() {\n\t\tConditionMessage message = ConditionMessage.of((List<ConditionMessage>) null);\n\t\tassertThat(message.isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tvoid forConditionShouldIncludeCondition() {\n\t\tConditionMessage message = ConditionMessage.forCondition(\"@Test\").because(\"OK\");\n\t\tassertThat(message).hasToString(\"@Test OK\");\n\t}\n\n\t@Test\n\tvoid forConditionShouldNotAddExtraSpaceWithEmptyCondition() {\n\t\tConditionMessage message = ConditionMessage.forCondition(\"\").because(\"OK\");\n\t\tassertThat(message).hasToString(\"OK\");\n\t}\n\n\t@Test\n\tvoid forConditionWhenClassShouldIncludeCondition() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class, \"(a=b)\").because(\"OK\");\n\t\tassertThat(message).hasToString(\"@Test (a=b) OK\");\n\t}\n\n\t@Test\n\tvoid foundExactlyShouldConstructMessage() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).foundExactly(\"abc\");\n\t\tassertThat(message).hasToString(\"@Test found abc\");\n\t}\n\n\t@Test\n\tvoid foundWhenSingleElementShouldUseSingular() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).found(\"bean\", \"beans\").items(\"a\");\n\t\tassertThat(message).hasToString(\"@Test found bean a\");\n\t}\n\n\t@Test\n\tvoid foundNoneAtAllShouldConstructMessage() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).found(\"no beans\").atAll();\n\t\tassertThat(message).hasToString(\"@Test found no beans\");\n\t}\n\n\t@Test\n\tvoid foundWhenMultipleElementsShouldUsePlural() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class)\n\t\t\t.found(\"bean\", \"beans\")\n\t\t\t.items(\"a\", \"b\", \"c\");\n\t\tassertThat(message).hasToString(\"@Test found beans a, b, c\");\n\t}\n\n\t@Test\n\tvoid foundWhenQuoteStyleShouldQuote() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class)\n\t\t\t.found(\"bean\", \"beans\")\n\t\t\t.items(Style.QUOTE, \"a\", \"b\", \"c\");\n\t\tassertThat(message).hasToString(\"@Test found beans 'a', 'b', 'c'\");\n\t}\n\n\t@Test\n\tvoid didNotFindWhenSingleElementShouldUseSingular() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).didNotFind(\"class\", \"classes\").items(\"a\");\n\t\tassertThat(message).hasToString(\"@Test did not find class a\");\n\t}\n\n\t@Test\n\tvoid didNotFindWhenMultipleElementsShouldUsePlural() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class)\n\t\t\t.didNotFind(\"class\", \"classes\")\n\t\t\t.items(\"a\", \"b\", \"c\");\n\t\tassertThat(message).hasToString(\"@Test did not find classes a, b, c\");\n\t}\n\n\t@Test\n\tvoid resultedInShouldConstructMessage() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).resultedIn(\"Green\");\n\t\tassertThat(message).hasToString(\"@Test resulted in Green\");\n\t}\n\n\t@Test\n\tvoid notAvailableShouldConstructMessage() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).notAvailable(\"JMX\");\n\t\tassertThat(message).hasToString(\"@Test JMX is not available\");\n\t}\n\n\t@Test\n\tvoid availableShouldConstructMessage() {\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).available(\"JMX\");\n\t\tassertThat(message).hasToString(\"@Test JMX is available\");\n\t}\n\n\t@Test\n\tvoid itemsTolerateNullInput() {\n\t\tCollection<?> items = null;\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class).didNotFind(\"item\").items(items);\n\t\tassertThat(message).hasToString(\"@Test did not find item\");\n\t}\n\n\t@Test\n\tvoid quotedItemsTolerateNullInput() {\n\t\tCollection<?> items = null;\n\t\tConditionMessage message = ConditionMessage.forCondition(Test.class)\n\t\t\t.didNotFind(\"item\")\n\t\t\t.items(Style.QUOTE, items);\n\t\tassertThat(message).hasToString(\"@Test did not find item\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnBean @ConditionalOnBean}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Uladzislau Seuruk\n */\nclass ConditionalOnBeanTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid testNameOnBeanCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testNameAndTypeOnBeanCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanNameAndTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid testNameOnBeanConditionReverseOrder() {\n\t\t// Ideally this should be true\n\t\tthis.contextRunner.withUserConfiguration(OnBeanNameConfiguration.class, FooConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid testClassOnBeanCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanClassConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testClassOnBeanClassNameCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanClassNameConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testOnBeanConditionWithXml() {\n\t\tthis.contextRunner.withUserConfiguration(XmlConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testOnBeanConditionWithCombinedXml() {\n\t\t// Ideally this should be true\n\t\tthis.contextRunner.withUserConfiguration(CombinedXmlConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid testAnnotationOnBeanCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanType() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanMissingClassConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid withPropertyPlaceholderClassName() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(PropertySourcesPlaceholderConfigurer.class,\n\t\t\t\t\tWithPropertyPlaceholderClassNameConfiguration.class, OnBeanClassConfiguration.class)\n\t\t\t.withPropertyValues(\"mybeanclass=java.lang.String\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid beanProducedByFactoryBeanIsConsideredWhenMatchingOnAnnotation() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FactoryBeanConfiguration.class, OnAnnotationWithFactoryBeanConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"bar\");\n\t\t\t\tassertThat(context).hasSingleBean(ExampleBean.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid beanProducedByFactoryBeanIsConsideredWhenMatchingOnAnnotation2() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EarlyInitializationFactoryBeanConfiguration.class,\n\t\t\t\t\tEarlyInitializationOnAnnotationFactoryBeanConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(EarlyInitializationFactoryBeanConfiguration.calledWhenNoFrozen).as(\"calledWhenNoFrozen\")\n\t\t\t\t\t.isFalse();\n\t\t\t\tassertThat(context).hasBean(\"bar\");\n\t\t\t\tassertThat(context).hasSingleBean(ExampleBean.class);\n\t\t\t});\n\t}\n\n\tprivate void hasBarBean(AssertableApplicationContext context) {\n\t\tassertThat(context).hasBean(\"bar\");\n\t\tassertThat(context.getBean(\"bar\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid onBeanConditionOutputShouldNotContainConditionalOnMissingBeanClassInMessage() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanNameConfiguration.class).run((context) -> {\n\t\t\tCollection<ConditionAndOutcomes> conditionAndOutcomes = ConditionEvaluationReport\n\t\t\t\t.get(context.getSourceApplicationContext().getBeanFactory())\n\t\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t\t.values();\n\t\t\tString message = conditionAndOutcomes.iterator().next().iterator().next().getOutcome().getMessage();\n\t\t\tassertThat(message).doesNotContain(\"@ConditionalOnMissingBean\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid conditionEvaluationConsidersChangeInTypeWhenBeanIsOverridden() {\n\t\tthis.contextRunner.withAllowBeanDefinitionOverriding(true)\n\t\t\t.withUserConfiguration(OriginalDefinitionConfiguration.class, OverridingDefinitionConfiguration.class,\n\t\t\t\t\tConsumingConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"testBean\");\n\t\t\t\tassertThat(context).hasSingleBean(Integer.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(ConsumingConfiguration.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfMissingBeanDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithoutCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"otherExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfExistingBeanMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"customExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfMissingBeanRegistrationDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithoutCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"otherExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfExistingBeanRegistrationMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"customExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnTypeIsOfExistingBeanMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"customExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnTypeIsOfExistingBeanRegistrationMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"customExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnRegistrationTypeIsOfExistingBeanMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnRegistrationTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"customExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnRegistrationTypeIsOfExistingBeanRegistrationMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnRegistrationTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"customExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid conditionalOnBeanTypeIgnoresNotAutowireCandidateBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NotAutowireCandidateConfiguration.class, OnBeanClassConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid conditionalOnBeanNameMatchesNotAutowireCandidateBean() {\n\t\tthis.contextRunner.withUserConfiguration(NotAutowireCandidateConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid conditionalOnAnnotatedBeanIgnoresNotAutowireCandidateBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AnnotatedNotAutowireCandidateConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid conditionalOnBeanTypeIgnoresNotDefaultCandidateBean() {\n\t\tthis.contextRunner.withUserConfiguration(NotDefaultCandidateConfiguration.class, OnBeanClassConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid conditionalOnBeanTypeIgnoresNotDefaultCandidateFactoryBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NotDefaultCandidateFactoryBeanConfiguration.class,\n\t\t\t\t\tOnBeanClassWithFactoryBeanConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid conditionalOnBeanNameMatchesNotDefaultCandidateBean() {\n\t\tthis.contextRunner.withUserConfiguration(NotDefaultCandidateConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid conditionalOnAnnotatedBeanIgnoresNotDefaultCandidateBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AnnotatedNotDefaultCandidateConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid genericWhenTypeArgumentMatches() {\n\t\tthis.contextRunner.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\tGenericWithStringTypeArgumentsConfiguration.class, GenericWithIntegerTypeArgumentsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"customGenericExampleBean\", \"genericStringTypeArgumentsExampleBean\")));\n\t}\n\n\t@Test\n\tvoid genericWhenTypeArgumentWithValueMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithStringConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"genericStringExampleBean\", \"genericStringWithValueExampleBean\")));\n\t}\n\n\t@Test\n\tvoid genericWithValueWhenSubclassTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"customGenericExampleBean\", \"genericStringWithValueExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerGenericWhenTypeArgumentNotMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithIntegerConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithParameterizedContainerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(GenericExampleBean.class, \"genericIntegerExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerGenericWhenTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithStringConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithParameterizedContainerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"genericStringExampleBean\", \"parameterizedContainerGenericExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerGenericWhenSubclassTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithParameterizedContainerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"customGenericExampleBean\", \"parameterizedContainerGenericExampleBean\")));\n\t}\n\n\t@Test\n\tvoid whenTypeDoesNotExistItIsStillDescribedInConditionOutcomeMessage() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanForTypeThatDoesNotExist.class).run((context) -> {\n\t\t\tMap<String, ConditionAndOutcomes> conditionAndOutcomesBySource = ConditionEvaluationReport\n\t\t\t\t.get(context.getBeanFactory())\n\t\t\t\t.getConditionAndOutcomesBySource();\n\t\t\tassertThat(conditionAndOutcomesBySource).hasEntrySatisfying(OnBeanForTypeThatDoesNotExist.class.getName(),\n\t\t\t\t\t(conditionAndOutcomes) -> {\n\t\t\t\t\t\tassertThat(conditionAndOutcomes).hasSize(1)\n\t\t\t\t\t\t\t.first()\n\t\t\t\t\t\t\t.extracting(ConditionAndOutcome::getOutcome)\n\t\t\t\t\t\t\t.satisfies((outcome) -> {\n\t\t\t\t\t\t\t\tassertThat(outcome.isMatch()).isFalse();\n\t\t\t\t\t\t\t\tassertThat(outcome.getMessage()).contains(\"com.example.DoesNotExist\");\n\t\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t});\n\t}\n\n\tprivate Consumer<ConfigurableApplicationContext> beansAndContainersNamed(Class<?> type, String... names) {\n\t\treturn (context) -> {\n\t\t\tString[] beans = context.getBeanNamesForType(type);\n\t\t\tString[] containers = context.getBeanNamesForType(TestParameterizedContainer.class);\n\t\t\tassertThat(StringUtils.concatenateStringArrays(beans, containers)).containsOnly(names);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(name = \"foo\")\n\tstatic class OnBeanNameConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(name = \"foo\", value = Date.class)\n\tstatic class OnBeanNameAndTypeConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(annotation = TestAnnotation.class)\n\tstatic class OnAnnotationConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(String.class)\n\tstatic class OnBeanClassConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ExampleFactoryBean.class)\n\tstatic class OnBeanClassWithFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(type = \"java.lang.String\")\n\tstatic class OnBeanClassNameConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(type = \"some.type.Missing\")\n\tstatic class OnBeanMissingClassConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAnnotation\n\tstatic class FooConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotAutowireCandidateConfiguration {\n\n\t\t@Bean(autowireCandidate = false)\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotDefaultCandidateConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotDefaultCandidateFactoryBeanConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tExampleFactoryBean exampleBeanFactoryBean() {\n\t\t\treturn new ExampleFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportResource(\"org/springframework/boot/autoconfigure/condition/foo.xml\")\n\tstatic class XmlConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportResource(\"org/springframework/boot/autoconfigure/condition/foo.xml\")\n\t@Import(OnBeanNameConfiguration.class)\n\tstatic class CombinedXmlConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(WithPropertyPlaceholderClassNameRegistrar.class)\n\tstatic class WithPropertyPlaceholderClassNameConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tExampleFactoryBean exampleBeanFactoryBean() {\n\t\t\treturn new ExampleFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(annotation = TestAnnotation.class)\n\tstatic class OnAnnotationWithFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EarlyInitializationFactoryBeanConfiguration {\n\n\t\tstatic boolean calledWhenNoFrozen;\n\n\t\t@Bean\n\t\t@TestAnnotation\n\t\tstatic FactoryBean<?> exampleBeanFactoryBean(ApplicationContext applicationContext) {\n\t\t\t// NOTE: must be static and return raw FactoryBean and not the subclass so\n\t\t\t// Spring can't guess type\n\t\t\tConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext)\n\t\t\t\t.getBeanFactory();\n\t\t\tcalledWhenNoFrozen = calledWhenNoFrozen || !beanFactory.isConfigurationFrozen();\n\t\t\treturn new ExampleFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(annotation = TestAnnotation.class)\n\tstatic class EarlyInitializationOnAnnotationFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\tstatic class WithPropertyPlaceholderClassNameRegistrar implements ImportBeanDefinitionRegistrar {\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,\n\t\t\t\tBeanDefinitionRegistry registry) {\n\t\t\tRootBeanDefinition bd = new RootBeanDefinition();\n\t\t\tbd.setBeanClassName(\"${mybeanclass}\");\n\t\t\tregistry.registerBeanDefinition(\"mybean\", bd);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OriginalDefinitionConfiguration {\n\n\t\t@Bean\n\t\tString testBean() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(String.class)\n\tstatic class OverridingDefinitionConfiguration {\n\n\t\t@Bean\n\t\tInteger testBean() {\n\t\t\treturn 1;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(String.class)\n\tstatic class ConsumingConfiguration {\n\n\t\tConsumingConfiguration(String testBean) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithCustomConfiguration {\n\n\t\t@Bean\n\t\tCustomExampleBean customExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithoutCustomConfiguration {\n\n\t\t@Bean\n\t\tOtherExampleBean otherExampleBean() {\n\t\t\treturn new OtherExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithoutCustomContainerConfiguration {\n\n\t\t@Bean\n\t\tTestParameterizedContainer<OtherExampleBean> otherExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithCustomContainerConfiguration {\n\n\t\t@Bean\n\t\tTestParameterizedContainer<CustomExampleBean> customExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedConditionWithValueConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(value = CustomExampleBean.class, parameterizedContainer = TestParameterizedContainer.class)\n\t\tCustomExampleBean conditionalCustomExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedConditionWithReturnTypeConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tCustomExampleBean conditionalCustomExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedConditionWithReturnRegistrationTypeConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tTestParameterizedContainer<CustomExampleBean> conditionalCustomExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotatedNotAutowireCandidateConfiguration {\n\n\t\t@Bean(autowireCandidate = false)\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"value\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotatedNotDefaultCandidateConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"value\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithCustomGenericConfiguration {\n\n\t\t@Bean\n\t\tCustomGenericExampleBean customGenericExampleBean() {\n\t\t\treturn new CustomGenericExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericWithStringConfiguration {\n\n\t\t@Bean\n\t\tGenericExampleBean<String> genericStringExampleBean() {\n\t\t\treturn new GenericExampleBean<>(\"genericStringExampleBean\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericWithStringTypeArgumentsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean\n\t\tGenericExampleBean<String> genericStringTypeArgumentsExampleBean() {\n\t\t\treturn new GenericExampleBean<>(\"genericStringTypeArgumentsExampleBean\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericWithIntegerConfiguration {\n\n\t\t@Bean\n\t\tGenericExampleBean<Integer> genericIntegerExampleBean() {\n\t\t\treturn new GenericExampleBean<>(1_000);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericWithIntegerTypeArgumentsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean\n\t\tGenericExampleBean<Integer> genericIntegerTypeArgumentsExampleBean() {\n\t\t\treturn new GenericExampleBean<>(1_000);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TypeArgumentsConditionWithValueConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(GenericExampleBean.class)\n\t\tGenericExampleBean<String> genericStringWithValueExampleBean() {\n\t\t\treturn new GenericExampleBean<>(\"genericStringWithValueExampleBean\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TypeArgumentsConditionWithParameterizedContainerConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tTestParameterizedContainer<GenericExampleBean<String>> parameterizedContainerGenericExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\tstatic class ExampleFactoryBean implements FactoryBean<ExampleBean> {\n\n\t\t@Override\n\t\tpublic ExampleBean getObject() {\n\t\t\treturn new ExampleBean(\"fromFactory\");\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn ExampleBean.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isSingleton() {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t@TestAnnotation\n\tstatic class ExampleBean {\n\n\t\tprivate final String value;\n\n\t\tExampleBean(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\tstatic class CustomExampleBean extends ExampleBean {\n\n\t\tCustomExampleBean() {\n\t\t\tsuper(\"custom subclass\");\n\t\t}\n\n\t}\n\n\tstatic class OtherExampleBean extends ExampleBean {\n\n\t\tOtherExampleBean() {\n\t\t\tsuper(\"other subclass\");\n\t\t}\n\n\t}\n\n\t@TestAnnotation\n\tstatic class GenericExampleBean<T> {\n\n\t\tprivate final T value;\n\n\t\tGenericExampleBean(T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.valueOf(this.value);\n\t\t}\n\n\t}\n\n\tstatic class CustomGenericExampleBean extends GenericExampleBean<String> {\n\n\t\tCustomGenericExampleBean() {\n\t\t\tsuper(\"custom subclass\");\n\t\t}\n\n\t}\n\n\t@Target({ ElementType.TYPE, ElementType.METHOD })\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@interface TestAnnotation {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(type = \"com.example.DoesNotExist\")\n\tstatic class OnBeanForTypeThatDoesNotExist {\n\n\t\t@Bean\n\t\tString bean() {\n\t\t\treturn \"bean\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBooleanPropertyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ConditionalOnBooleanProperty @ConditionalOnBooleanProperty}.\n *\n * @author Phillip Webb\n */\nclass ConditionalOnBooleanPropertyTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultsWhenTrue() {\n\t\tload(Defaults.class, \"test=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultsWhenFalse() {\n\t\tload(Defaults.class, \"test=false\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid defaultsWhenMissing() {\n\t\tload(Defaults.class);\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueTrueMatchIfMissingFalseWhenTrue() {\n\t\tload(HavingValueTrueMatchIfMissingFalse.class, \"test=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid havingValueTrueMatchIfMissingFalseWhenFalse() {\n\t\tload(HavingValueTrueMatchIfMissingFalse.class, \"test=false\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueTrueMatchIfMissingFalseWhenMissing() {\n\t\tload(HavingValueTrueMatchIfMissingFalse.class);\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueTrueMatchIfMissingTrueWhenTrue() {\n\t\tload(HavingValueTrueMatchIfMissingTrue.class, \"test=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid havingValueTrueMatchIfMissingTrueWhenFalse() {\n\t\tload(HavingValueTrueMatchIfMissingTrue.class, \"test=false\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueTrueMatchIfMissingTrueWhenMissing() {\n\t\tload(HavingValueTrueMatchIfMissingTrue.class);\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid havingValueFalseMatchIfMissingFalseWhenTrue() {\n\t\tload(HavingValueFalseMatchIfMissingFalse.class, \"test=true\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueFalseMatchIfMissingFalseWhenFalse() {\n\t\tload(HavingValueFalseMatchIfMissingFalse.class, \"test=false\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid havingValueFalseMatchIfMissingFalseWhenMissing() {\n\t\tload(HavingValueFalseMatchIfMissingFalse.class);\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueFalseMatchIfMissingTrueWhenTrue() {\n\t\tload(HavingValueFalseMatchIfMissingTrue.class, \"test=true\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid havingValueFalseMatchIfMissingTrueWhenFalse() {\n\t\tload(HavingValueFalseMatchIfMissingTrue.class, \"test=false\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid havingValueFalseMatchIfMissingTrueWhenMissing() {\n\t\tload(HavingValueFalseMatchIfMissingTrue.class);\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid withPrefix() {\n\t\tload(HavingValueFalseMatchIfMissingTrue.class, \"foo.test=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid nameOrValueMustBeSpecified() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> load(NoNameOrValueAttribute.class, \"some.property\"))\n\t\t\t.satisfies(causeMessageContaining(\n\t\t\t\t\t\"The name or value attribute of @ConditionalOnBooleanProperty must be specified\"));\n\t}\n\n\t@Test\n\tvoid nameAndValueMustNotBeSpecified() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> load(NameAndValueAttribute.class, \"some.property\"))\n\t\t\t.satisfies(causeMessageContaining(\n\t\t\t\t\t\"The name and value attributes of @ConditionalOnBooleanProperty are exclusive\"));\n\t}\n\n\t@Test\n\tvoid conditionReportWhenMatched() {\n\t\tload(Defaults.class, \"test=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t\tassertThat(getConditionEvaluationReport()).contains(\"@ConditionalOnBooleanProperty (test=true) matched\");\n\t}\n\n\t@Test\n\tvoid conditionReportWhenDoesNotMatch() {\n\t\tload(Defaults.class, \"test=false\");\n\t\tassertThat(containsBean()).isFalse();\n\t\tassertThat(getConditionEvaluationReport())\n\t\t\t.contains(\"@ConditionalOnBooleanProperty (test=true) found different value in property 'test'\");\n\t}\n\n\t@Test\n\tvoid repeatablePropertiesConditionReportWhenMatched() {\n\t\tload(RepeatablePropertiesRequiredConfiguration.class, \"property1=true\", \"property2=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t\tString report = getConditionEvaluationReport();\n\t\tassertThat(report).contains(\"@ConditionalOnBooleanProperty (property1=true) matched\");\n\t\tassertThat(report).contains(\"@ConditionalOnBooleanProperty (property2=true) matched\");\n\t}\n\n\t@Test\n\tvoid repeatablePropertiesConditionReportWhenDoesNotMatch() {\n\t\tload(RepeatablePropertiesRequiredConfiguration.class, \"property1=true\");\n\t\tassertThat(getConditionEvaluationReport())\n\t\t\t.contains(\"@ConditionalOnBooleanProperty (property2=true) did not find property 'property2'\");\n\t}\n\n\tprivate <T extends Exception> Consumer<T> causeMessageContaining(String message) {\n\t\treturn (ex) -> assertThat(ex.getCause()).hasMessageContaining(message);\n\t}\n\n\tprivate String getConditionEvaluationReport() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn ConditionEvaluationReport.get(this.context.getBeanFactory())\n\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t.values()\n\t\t\t.stream()\n\t\t\t.flatMap(ConditionAndOutcomes::stream)\n\t\t\t.map(Object::toString)\n\t\t\t.collect(Collectors.joining(\"\\n\"));\n\t}\n\n\tprivate void load(Class<?> config, String... environment) {\n\t\tTestPropertyValues.of(environment).applyTo(this.environment);\n\t\tthis.context = new SpringApplicationBuilder(config).environment(this.environment)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.run();\n\t}\n\n\tprivate boolean containsBean() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn this.context.containsBean(\"foo\");\n\t}\n\n\tabstract static class BeanConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(\"test\")\n\tstatic class Defaults extends BeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"test\", havingValue = true, matchIfMissing = false)\n\tstatic class HavingValueTrueMatchIfMissingFalse extends BeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"test\", havingValue = true, matchIfMissing = true)\n\tstatic class HavingValueTrueMatchIfMissingTrue extends BeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"test\", havingValue = false, matchIfMissing = false)\n\tstatic class HavingValueFalseMatchIfMissingFalse extends BeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"test\", havingValue = false, matchIfMissing = true)\n\tstatic class HavingValueFalseMatchIfMissingTrue extends BeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(prefix = \"foo\", name = \"test\")\n\tstatic class WithPrefix extends BeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty\n\tstatic class NoNameOrValueAttribute {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(value = \"x\", name = \"y\")\n\tstatic class NameAndValueAttribute {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(\"property1\")\n\t@ConditionalOnBooleanProperty(\"property2\")\n\tstatic class RepeatablePropertiesRequiredConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCheckpointRestoreTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnCheckpointRestore @ConditionalOnCheckpointRestore}.\n *\n * @author Andy Wilkinson\n */\nclass ConditionalOnCheckpointRestoreTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(BasicConfiguration.class);\n\n\t@Test\n\tvoid whenCracIsUnavailableThenConditionDoesNotMatch() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(\"someBean\"));\n\t}\n\n\t@Test\n\t@ClassPathOverrides(\"org.crac:crac:1.3.0\")\n\tvoid whenCracIsAvailableThenConditionMatches() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"someBean\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BasicConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnCheckpointRestore\n\t\tString someBean() {\n\t\t\treturn \"someBean\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClassTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnClass @ConditionalOnClass}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass ConditionalOnClassTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid testVanillaOnClassCondition() {\n\t\tthis.contextRunner.withUserConfiguration(BasicConfiguration.class, FooConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testMissingOnClassCondition() {\n\t\tthis.contextRunner.withUserConfiguration(MissingConfiguration.class, FooConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(\"bar\");\n\t\t\tassertThat(context).hasBean(\"foo\");\n\t\t\tassertThat(context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testOnClassConditionWithXml() {\n\t\tthis.contextRunner.withUserConfiguration(BasicConfiguration.class, XmlConfiguration.class)\n\t\t\t.run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid testOnClassConditionWithCombinedXml() {\n\t\tthis.contextRunner.withUserConfiguration(CombinedXmlConfiguration.class).run(this::hasBarBean);\n\t}\n\n\t@Test\n\tvoid onClassConditionOutputShouldNotContainConditionalOnMissingClassInMessage() {\n\t\tthis.contextRunner.withUserConfiguration(BasicConfiguration.class).run((context) -> {\n\t\t\tCollection<ConditionEvaluationReport.ConditionAndOutcomes> conditionAndOutcomes = ConditionEvaluationReport\n\t\t\t\t.get(context.getSourceApplicationContext().getBeanFactory())\n\t\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t\t.values();\n\t\t\tString message = conditionAndOutcomes.iterator().next().iterator().next().getOutcome().getMessage();\n\t\t\tassertThat(message).doesNotContain(\"@ConditionalOnMissingClass did not find unwanted class\");\n\t\t});\n\t}\n\n\tprivate void hasBarBean(AssertableApplicationContext context) {\n\t\tassertThat(context).hasBean(\"bar\");\n\t\tassertThat(context.getBean(\"bar\")).isEqualTo(\"bar\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ConditionalOnClassTests.class)\n\tstatic class BasicConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = \"FOO\")\n\tstatic class MissingConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FooConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportResource(\"org/springframework/boot/autoconfigure/condition/foo.xml\")\n\tstatic class XmlConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BasicConfiguration.class)\n\t@ImportResource(\"org/springframework/boot/autoconfigure/condition/foo.xml\")\n\tstatic class CombinedXmlConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnCloudPlatformTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnCloudPlatform @ConditionalOnCloudPlatform}.\n */\nclass ConditionalOnCloudPlatformTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid outcomeWhenCloudfoundryPlatformNotPresentShouldNotMatch() {\n\t\tthis.contextRunner.withUserConfiguration(CloudFoundryPlatformConfig.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenCloudfoundryPlatformPresentShouldMatch() {\n\t\tthis.contextRunner.withUserConfiguration(CloudFoundryPlatformConfig.class)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenCloudfoundryPlatformPresentAndMethodTargetShouldMatch() {\n\t\tthis.contextRunner.withUserConfiguration(CloudFoundryPlatformOnMethodConfig.class)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)\n\tstatic class CloudFoundryPlatformConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CloudFoundryPlatformOnMethodConfig {\n\n\t\t@Bean\n\t\t@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnExpressionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConditionalOnExpression @ConditionalOnExpression}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass ConditionalOnExpressionTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid expressionIsTrue() {\n\t\tthis.contextRunner.withUserConfiguration(BasicConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(\"foo\")).isEqualTo(\"foo\"));\n\t}\n\n\t@Test\n\tvoid expressionEvaluatesToTrueRegistersBean() {\n\t\tthis.contextRunner.withUserConfiguration(MissingConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid expressionEvaluatesToFalseDoesNotRegisterBean() {\n\t\tthis.contextRunner.withUserConfiguration(NullConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid expressionEvaluationWithNoBeanFactoryDoesNotMatch() {\n\t\tOnExpressionCondition condition = new OnExpressionCondition();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tConditionContext conditionContext = mock(ConditionContext.class);\n\t\tgiven(conditionContext.getEnvironment()).willReturn(environment);\n\t\tConditionOutcome outcome = condition.getMatchOutcome(conditionContext, mockMetadata(\"invalid-spel\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage()).contains(\"invalid-spel\").contains(\"no BeanFactory available\");\n\t}\n\n\tprivate AnnotatedTypeMetadata mockMetadata(String value) {\n\t\tAnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);\n\t\tgiven(metadata.getAnnotationAttributes(ConditionalOnExpression.class.getName()))\n\t\t\t.willReturn(Collections.singletonMap(\"value\", value));\n\t\treturn metadata;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnExpression(\"false\")\n\tstatic class MissingConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnExpression(\"true\")\n\tstatic class BasicConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnExpression(\"true ? null : false\")\n\tstatic class NullConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJavaTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.io.Console;\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledOnJre;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnJava.Range;\nimport org.springframework.boot.system.JavaVersion;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnJava @ConditionalOnJava}.\n *\n * @author Oliver Gierke\n * @author Phillip Webb\n */\nclass ConditionalOnJavaTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\tprivate final OnJavaCondition condition = new OnJavaCondition();\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_17)\n\tvoid doesNotMatchIfBetterVersionIsRequired() {\n\t\tthis.contextRunner.withUserConfiguration(Java18Required.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(String.class));\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_18)\n\tvoid doesNotMatchIfLowerIsRequired() {\n\t\tthis.contextRunner.withUserConfiguration(OlderThan18Required.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(String.class));\n\t}\n\n\t@Test\n\tvoid matchesIfVersionIsInRange() {\n\t\tthis.contextRunner.withUserConfiguration(Java17Required.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(String.class));\n\t}\n\n\t@Test\n\tvoid boundsTests() {\n\t\ttestBounds(Range.EQUAL_OR_NEWER, JavaVersion.EIGHTEEN, JavaVersion.SEVENTEEN, true);\n\t\ttestBounds(Range.EQUAL_OR_NEWER, JavaVersion.SEVENTEEN, JavaVersion.SEVENTEEN, true);\n\t\ttestBounds(Range.EQUAL_OR_NEWER, JavaVersion.SEVENTEEN, JavaVersion.EIGHTEEN, false);\n\t\ttestBounds(Range.OLDER_THAN, JavaVersion.EIGHTEEN, JavaVersion.SEVENTEEN, false);\n\t\ttestBounds(Range.OLDER_THAN, JavaVersion.SEVENTEEN, JavaVersion.SEVENTEEN, false);\n\t\ttestBounds(Range.OLDER_THAN, JavaVersion.SEVENTEEN, JavaVersion.EIGHTEEN, true);\n\t}\n\n\t@Test\n\tvoid equalOrNewerMessage() {\n\t\tConditionOutcome outcome = this.condition.getMatchOutcome(Range.EQUAL_OR_NEWER, JavaVersion.EIGHTEEN,\n\t\t\t\tJavaVersion.SEVENTEEN);\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"@ConditionalOnJava (17 or newer) found 18\");\n\t}\n\n\t@Test\n\tvoid olderThanMessage() {\n\t\tConditionOutcome outcome = this.condition.getMatchOutcome(Range.OLDER_THAN, JavaVersion.EIGHTEEN,\n\t\t\t\tJavaVersion.SEVENTEEN);\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"@ConditionalOnJava (older than 17) found 18\");\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_17)\n\tvoid java17IsDetected() throws Exception {\n\t\tassertThat(getJavaVersion()).isEqualTo(\"17\");\n\t}\n\n\t@Test\n\t@EnabledOnJre(JRE.JAVA_17)\n\tvoid java17IsTheFallback() throws Exception {\n\t\tassertThat(getJavaVersion(Console.class)).isEqualTo(\"17\");\n\t}\n\n\tprivate String getJavaVersion(Class<?>... hiddenClasses) throws Exception {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(hiddenClasses);\n\t\tClass<?> javaVersionClass = Class.forName(JavaVersion.class.getName(), false, classLoader);\n\t\tMethod getJavaVersionMethod = ReflectionUtils.findMethod(javaVersionClass, \"getJavaVersion\");\n\t\tassertThat(getJavaVersionMethod).isNotNull();\n\t\tObject javaVersion = ReflectionUtils.invokeMethod(getJavaVersionMethod, null);\n\t\tclassLoader.close();\n\t\tassertThat(javaVersion).isNotNull();\n\t\treturn javaVersion.toString();\n\t}\n\n\tprivate void testBounds(Range range, JavaVersion runningVersion, JavaVersion version, boolean expected) {\n\t\tConditionOutcome outcome = this.condition.getMatchOutcome(range, runningVersion, version);\n\t\tassertThat(outcome.isMatch()).as(outcome.getMessage()).isEqualTo(expected);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnJava(JavaVersion.SEVENTEEN)\n\tstatic class Java17Required {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnJava(range = Range.OLDER_THAN, value = JavaVersion.EIGHTEEN)\n\tstatic class OlderThan18Required {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnJava(JavaVersion.EIGHTEEN)\n\tstatic class Java18Required {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnJndiTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.naming.Context;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoader;\nimport org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConditionalOnJndi @ConditionalOnJndi}\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ConditionalOnJndiTests {\n\n\tprivate ClassLoader threadContextClassLoader;\n\n\tprivate @Nullable String initialContextFactory;\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\tprivate final MockableOnJndi condition = new MockableOnJndi();\n\n\t@BeforeEach\n\tvoid setupThreadContextClassLoader() {\n\t\tthis.threadContextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread().setContextClassLoader(new JndiPropertiesHidingClassLoader(getClass().getClassLoader()));\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tTestableInitialContextFactory.clearAll();\n\t\tif (this.initialContextFactory != null) {\n\t\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, this.initialContextFactory);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\t}\n\t\tThread.currentThread().setContextClassLoader(this.threadContextClassLoader);\n\t}\n\n\t@Test\n\tvoid jndiNotAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(JndiAvailableConfiguration.class, JndiConditionConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(String.class));\n\t}\n\n\t@Test\n\tvoid jndiAvailable() {\n\t\tsetupJndi();\n\t\tthis.contextRunner.withUserConfiguration(JndiAvailableConfiguration.class, JndiConditionConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(String.class));\n\t}\n\n\t@Test\n\tvoid jndiLocationNotBound() {\n\t\tsetupJndi();\n\t\tthis.contextRunner.withUserConfiguration(JndiConditionConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(String.class));\n\t}\n\n\t@Test\n\tvoid jndiLocationBound() {\n\t\tsetupJndi();\n\t\tTestableInitialContextFactory.bind(\"java:/FooManager\", new Object());\n\t\tthis.contextRunner.withUserConfiguration(JndiConditionConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(String.class));\n\t}\n\n\t@Test\n\tvoid jndiLocationNotFound() {\n\t\tConditionOutcome outcome = this.condition.getMatchOutcome(mock(ConditionContext.class),\n\t\t\t\tmockMetadata(\"java:/a\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t}\n\n\t@Test\n\tvoid jndiLocationFound() {\n\t\tthis.condition.setFoundLocation(\"java:/b\");\n\t\tConditionOutcome outcome = this.condition.getMatchOutcome(mock(ConditionContext.class),\n\t\t\t\tmockMetadata(\"java:/a\", \"java:/b\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t}\n\n\tprivate void setupJndi() {\n\t\tthis.initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, TestableInitialContextFactory.class.getName());\n\t}\n\n\tprivate AnnotatedTypeMetadata mockMetadata(String... value) {\n\t\tAnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);\n\t\tMap<String, Object> attributes = new HashMap<>();\n\t\tattributes.put(\"value\", value);\n\t\tgiven(metadata.getAnnotationAttributes(ConditionalOnJndi.class.getName())).willReturn(attributes);\n\t\treturn metadata;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnJndi\n\tstatic class JndiAvailableConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnJndi(\"java:/FooManager\")\n\tstatic class JndiConditionConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\tstatic class MockableOnJndi extends OnJndiCondition {\n\n\t\tprivate final boolean jndiAvailable = true;\n\n\t\tprivate @Nullable String foundLocation;\n\n\t\t@Override\n\t\tprotected boolean isJndiAvailable() {\n\t\t\treturn this.jndiAvailable;\n\t\t}\n\n\t\t@Override\n\t\tprotected JndiLocator getJndiLocator(String[] locations) {\n\t\t\treturn new JndiLocator(locations) {\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable String lookupFirstLocation() {\n\t\t\t\t\treturn MockableOnJndi.this.foundLocation;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tvoid setFoundLocation(String foundLocation) {\n\t\t\tthis.foundLocation = foundLocation;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.autoconfigure.condition.scan.ScanBean;\nimport org.springframework.boot.autoconfigure.condition.scan.ScannedFactoryBeanConfiguration;\nimport org.springframework.boot.autoconfigure.condition.scan.ScannedFactoryBeanWithBeanMethodArgumentsConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.context.annotation.ScopedProxyMode;\nimport org.springframework.context.support.SimpleThreadScope;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnMissingBean @ConditionalOnMissingBean}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Jakub Kubrynski\n * @author Andy Wilkinson\n * @author Uladzislau Seuruk\n */\n@SuppressWarnings(\"resource\")\nclass ConditionalOnMissingBeanTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid testNameOnMissingBeanCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"bar\");\n\t\t\t\tassertThat(context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testNameOnMissingBeanConditionReverseOrder() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanNameConfiguration.class, FooConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\t// Ideally this would be doesNotHaveBean, but the ordering is a\n\t\t\t\t// problem\n\t\t\t\tassertThat(context).hasBean(\"bar\");\n\t\t\t\tassertThat(context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testNameAndTypeOnMissingBeanCondition() {\n\t\t// Arguably this should be hasBean, but as things are implemented the conditions\n\t\t// specified in the different attributes of @ConditionalOnBean are combined with\n\t\t// logical OR (not AND) so if any of them match the condition is true.\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnBeanNameAndTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid hierarchyConsidered() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class)\n\t\t\t.run((parent) -> new ApplicationContextRunner().withParent(parent)\n\t\t\t\t.withUserConfiguration(HierarchyConsideredConfiguration.class)\n\t\t\t\t.run((context) -> assertThat(context.containsLocalBean(\"bar\")).isFalse()));\n\t}\n\n\t@Test\n\tvoid hierarchyNotConsidered() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class)\n\t\t\t.run((parent) -> new ApplicationContextRunner().withParent(parent)\n\t\t\t\t.withUserConfiguration(HierarchyNotConsideredConfiguration.class)\n\t\t\t\t.run((context) -> assertThat(context.containsLocalBean(\"bar\")).isTrue()));\n\t}\n\n\t@Test\n\tvoid impliedOnBeanMethod() {\n\t\tthis.contextRunner.withUserConfiguration(ExampleBeanConfiguration.class, ImpliedOnBeanMethodConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ExampleBean.class));\n\t}\n\n\t@Test\n\tvoid testAnnotationOnMissingBeanCondition() {\n\t\tthis.contextRunner.withUserConfiguration(FooConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"bar\");\n\t\t\t\tassertThat(context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testAnnotationOnMissingBeanConditionWithScopedProxy() {\n\t\tthis.contextRunner.withInitializer(this::registerScope)\n\t\t\t.withUserConfiguration(ScopedExampleBeanConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"bar\");\n\t\t\t\tassertThat(context.getBean(ScopedExampleBean.class)).hasToString(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testAnnotationOnMissingBeanConditionWithEagerFactoryBean() {\n\t\t// Rigorous test for SPR-11069\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FooConfiguration.class, OnAnnotationConfiguration.class,\n\t\t\t\t\tFactoryBeanXmlConfiguration.class, PropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"bar\");\n\t\t\t\tassertThat(context).hasBean(\"example\");\n\t\t\t\tassertThat(context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t\t\t});\n\t}\n\n\t@Test // gh-42484\n\tvoid testAnnotationOnMissingBeanConditionOnMethodWhenNoAnnotatedBeans() {\n\t\t// There are no beans with @TestAnnotation but there is an UnrelatedExampleBean\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(UnrelatedExampleBeanConfiguration.class, OnAnnotationMethodConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"conditional\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionOutputShouldNotContainConditionalOnBeanClassInMessage() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanNameConfiguration.class).run((context) -> {\n\t\t\tCollection<ConditionEvaluationReport.ConditionAndOutcomes> conditionAndOutcomes = ConditionEvaluationReport\n\t\t\t\t.get(context.getSourceApplicationContext().getBeanFactory())\n\t\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t\t.values();\n\t\t\tString message = conditionAndOutcomes.iterator().next().iterator().next().getOutcome().getMessage();\n\t\t\tassertThat(message).doesNotContain(\"@ConditionalOnBean\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithFactoryBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FactoryBeanConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithComponentScannedFactoryBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ComponentScannedFactoryBeanBeanMethodConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ScanBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithComponentScannedFactoryBeanWithBeanMethodArguments() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ComponentScannedFactoryBeanBeanMethodWithArgumentsConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ScanBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithFactoryBeanWithBeanMethodArguments() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FactoryBeanWithBeanMethodArgumentsConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.withPropertyValues(\"theValue=foo\")\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithConcreteFactoryBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ConcreteFactoryBeanConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithUnhelpfulFactoryBean() {\n\t\t// We could not tell that the FactoryBean would ultimately create an ExampleBean\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(UnhelpfulFactoryBeanConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getBeans(ExampleBean.class).hasSize(2));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithRegisteredFactoryBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(RegisteredFactoryBeanConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithNonspecificFactoryBeanWithClassAttribute() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NonspecificFactoryBeanClassAttributeConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithNonspecificFactoryBeanWithStringAttribute() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NonspecificFactoryBeanStringAttributeConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithFactoryBeanInXml() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FactoryBeanXmlConfiguration.class,\n\t\t\t\t\tConditionalOnMissingBeanProducedByFactoryBeanConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(ExampleBean.class)).hasToString(\"fromFactory\"));\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithIgnoredSubclass() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomExampleBeanConfiguration.class,\n\t\t\t\t\tConditionalOnIgnoredSubclassConfiguration.class, PropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(ExampleBean.class).hasSize(2);\n\t\t\t\tassertThat(context).getBeans(CustomExampleBean.class).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testOnMissingBeanConditionWithIgnoredSubclassByName() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomExampleBeanConfiguration.class,\n\t\t\t\t\tConditionalOnIgnoredSubclassByNameConfiguration.class, PropertyPlaceholderAutoConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(ExampleBean.class).hasSize(2);\n\t\t\t\tassertThat(context).getBeans(CustomExampleBean.class).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid grandparentIsConsideredWhenUsingAncestorsStrategy() {\n\t\tthis.contextRunner.withUserConfiguration(ExampleBeanConfiguration.class)\n\t\t\t.run((grandparent) -> new ApplicationContextRunner().withParent(grandparent)\n\t\t\t\t.run((parent) -> new ApplicationContextRunner().withParent(parent)\n\t\t\t\t\t.withUserConfiguration(ExampleBeanConfiguration.class, OnBeanInAncestorsConfiguration.class)\n\t\t\t\t\t.run((context) -> assertThat(context).getBeans(ExampleBean.class).hasSize(1))));\n\t}\n\n\t@Test\n\tvoid currentContextIsIgnoredWhenUsingAncestorsStrategy() {\n\t\tthis.contextRunner.run((parent) -> new ApplicationContextRunner().withParent(parent)\n\t\t\t.withUserConfiguration(ExampleBeanConfiguration.class, OnBeanInAncestorsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getBeans(ExampleBean.class).hasSize(2)));\n\t}\n\n\t@Test\n\tvoid beanProducedByFactoryBeanIsConsideredWhenMatchingOnAnnotation() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ConcreteFactoryBeanConfiguration.class,\n\t\t\t\t\tOnAnnotationWithFactoryBeanConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"bar\");\n\t\t\t\tassertThat(context).hasSingleBean(ExampleBean.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfMissingBeanMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithoutCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"otherExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfExistingBeanDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"customExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfMissingBeanRegistrationMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithoutCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(\n\t\t\t\t\tbeansAndContainersNamed(ExampleBean.class, \"otherExampleBean\", \"conditionalCustomExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenValueIsOfExistingBeanRegistrationDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"customExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnTypeIsOfExistingBeanDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"customExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnTypeIsOfExistingBeanRegistrationDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"customExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnRegistrationTypeIsOfExistingBeanDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnRegistrationTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"customExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerWhenReturnRegistrationTypeIsOfExistingBeanRegistrationDoesNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomContainerConfiguration.class,\n\t\t\t\t\tParameterizedConditionWithReturnRegistrationTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(ExampleBean.class, \"customExampleBean\")));\n\t}\n\n\t@Test\n\tvoid typeBasedMatchingIgnoresBeanThatIsNotAutowireCandidate() {\n\t\tthis.contextRunner.withUserConfiguration(NotAutowireCandidateConfiguration.class, OnBeanTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid nameBasedMatchingConsidersBeanThatIsNotAutowireCandidate() {\n\t\tthis.contextRunner.withUserConfiguration(NotAutowireCandidateConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid annotationBasedMatchingIgnoresBeanThatIsNotAutowireCandidateBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AnnotatedNotAutowireCandidateConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid typeBasedMatchingIgnoresBeanThatIsNotDefaultCandidate() {\n\t\tthis.contextRunner.withUserConfiguration(NotDefaultCandidateConfiguration.class, OnBeanTypeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid typeBasedMatchingIgnoresFactoryBeanThatIsNotDefaultCandidate() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NotDefaultCandidateFactoryBeanConfiguration.class,\n\t\t\t\t\tConditionalOnMissingFactoryBeanConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"&exampleFactoryBean\")\n\t\t\t\t.hasBean(\"&additionalExampleFactoryBean\"));\n\t}\n\n\t@Test\n\tvoid nameBasedMatchingConsidersBeanThatIsNotDefaultCandidate() {\n\t\tthis.contextRunner.withUserConfiguration(NotDefaultCandidateConfiguration.class, OnBeanNameConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid annotationBasedMatchingIgnoresBeanThatIsNotDefaultCandidateBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AnnotatedNotDefaultCandidateConfiguration.class, OnAnnotationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid genericWhenTypeArgumentNotMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithStringTypeArgumentsConfiguration.class,\n\t\t\t\t\tGenericWithIntegerTypeArgumentsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"genericStringExampleBean\", \"genericIntegerExampleBean\")));\n\t}\n\n\t@Test\n\tvoid genericWhenSubclassTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\t\tGenericWithStringTypeArgumentsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(GenericExampleBean.class, \"customGenericExampleBean\")));\n\t}\n\n\t@Test\n\tvoid genericWhenSubclassTypeArgumentNotMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\t\tGenericWithIntegerTypeArgumentsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"customGenericExampleBean\", \"genericIntegerExampleBean\")));\n\t}\n\n\t@Test\n\tvoid genericWhenTypeArgumentWithValueMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithStringTypeArgumentsConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(GenericExampleBean.class, \"genericStringExampleBean\")));\n\t}\n\n\t@Test\n\tvoid genericWithValueWhenSubclassTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithValueConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(GenericExampleBean.class, \"customGenericExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerGenericWhenTypeArgumentNotMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithIntegerTypeArgumentsConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithParameterizedContainerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(beansAndContainersNamed(GenericExampleBean.class,\n\t\t\t\t\t\"genericIntegerExampleBean\", \"parameterizedContainerGenericExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerGenericWhenTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(GenericWithStringTypeArgumentsConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithParameterizedContainerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(GenericExampleBean.class, \"genericStringExampleBean\")));\n\t}\n\n\t@Test\n\tvoid parameterizedContainerGenericWhenSubclassTypeArgumentMatches() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ParameterizedWithCustomGenericConfiguration.class,\n\t\t\t\t\tTypeArgumentsConditionWithParameterizedContainerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.satisfies(beansAndContainersNamed(GenericExampleBean.class, \"customGenericExampleBean\")));\n\t}\n\n\t@Test\n\tvoid whenTypeDoesNotExistItIsStillDescribedInConditionOutcomeMessage() {\n\t\tthis.contextRunner.withUserConfiguration(OnMissingBeanForTypeThatDoesNotExist.class).run((context) -> {\n\t\t\tMap<String, ConditionAndOutcomes> conditionAndOutcomesBySource = ConditionEvaluationReport\n\t\t\t\t.get(context.getBeanFactory())\n\t\t\t\t.getConditionAndOutcomesBySource();\n\t\t\tassertThat(conditionAndOutcomesBySource)\n\t\t\t\t.hasEntrySatisfying(OnMissingBeanForTypeThatDoesNotExist.class.getName(), (conditionAndOutcomes) -> {\n\t\t\t\t\tassertThat(conditionAndOutcomes).hasSize(1)\n\t\t\t\t\t\t.first()\n\t\t\t\t\t\t.extracting(ConditionAndOutcome::getOutcome)\n\t\t\t\t\t\t.satisfies((outcome) -> {\n\t\t\t\t\t\t\tassertThat(outcome.isMatch()).isTrue();\n\t\t\t\t\t\t\tassertThat(outcome.getMessage()).contains(\"com.example.DoesNotExist\");\n\t\t\t\t\t\t});\n\t\t\t\t});\n\t\t});\n\t}\n\n\tprivate Consumer<ConfigurableApplicationContext> beansAndContainersNamed(Class<?> type, String... names) {\n\t\treturn (context) -> {\n\t\t\tString[] beans = context.getBeanNamesForType(type);\n\t\t\tString[] containers = context.getBeanNamesForType(TestParameterizedContainer.class);\n\t\t\tassertThat(StringUtils.concatenateStringArrays(beans, containers)).containsOnly(names);\n\t\t};\n\t}\n\n\tprivate void registerScope(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.getBeanFactory().registerScope(\"test\", new TestScope());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnBeanInAncestorsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(search = SearchStrategy.ANCESTORS)\n\t\tExampleBean exampleBean2() {\n\t\t\treturn new ExampleBean(\"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(name = \"foo\")\n\tstatic class OnBeanNameConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(type = \"java.lang.String\")\n\tstatic class OnBeanTypeConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(name = \"foo\", value = Date.class)\n\t@ConditionalOnBean(name = \"foo\", value = Date.class)\n\tstatic class OnBeanNameAndTypeConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tExampleFactoryBean exampleBeanFactoryBean() {\n\t\t\treturn new ExampleFactoryBean(\"foo\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotDefaultCandidateFactoryBeanConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tExampleFactoryBean exampleFactoryBean() {\n\t\t\treturn new ExampleFactoryBean(\"foo\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ComponentScan(basePackages = \"org.springframework.boot.autoconfigure.condition.scan\", useDefaultFilters = false,\n\t\t\tincludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE,\n\t\t\t\t\tclasses = ScannedFactoryBeanConfiguration.class))\n\tstatic class ComponentScannedFactoryBeanBeanMethodConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ComponentScan(basePackages = \"org.springframework.boot.autoconfigure.condition.scan\", useDefaultFilters = false,\n\t\t\tincludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE,\n\t\t\t\t\tclasses = ScannedFactoryBeanWithBeanMethodArgumentsConfiguration.class))\n\tstatic class ComponentScannedFactoryBeanBeanMethodWithArgumentsConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FactoryBeanWithBeanMethodArgumentsConfiguration {\n\n\t\t@Bean\n\t\tFactoryBean<ExampleBean> exampleBeanFactoryBean(@Value(\"${theValue}\") String value) {\n\t\t\treturn new ExampleFactoryBean(value);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConcreteFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tExampleFactoryBean exampleBeanFactoryBean() {\n\t\t\treturn new ExampleFactoryBean(\"foo\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UnhelpfulFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tFactoryBean exampleBeanFactoryBean() {\n\t\t\treturn new ExampleFactoryBean(\"foo\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(NonspecificFactoryBeanClassAttributeRegistrar.class)\n\tstatic class NonspecificFactoryBeanClassAttributeConfiguration {\n\n\t}\n\n\tstatic class NonspecificFactoryBeanClassAttributeRegistrar implements ImportBeanDefinitionRegistrar {\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata meta, BeanDefinitionRegistry registry) {\n\t\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(NonspecificFactoryBean.class);\n\t\t\tbuilder.addConstructorArgValue(\"foo\");\n\t\t\tbuilder.getBeanDefinition().setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, ExampleBean.class);\n\t\t\tregistry.registerBeanDefinition(\"exampleBeanFactoryBean\", builder.getBeanDefinition());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(NonspecificFactoryBeanClassAttributeRegistrar.class)\n\tstatic class NonspecificFactoryBeanStringAttributeConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(FactoryBeanRegistrar.class)\n\tstatic class RegisteredFactoryBeanConfiguration {\n\n\t}\n\n\tstatic class FactoryBeanRegistrar implements ImportBeanDefinitionRegistrar {\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata meta, BeanDefinitionRegistry registry) {\n\t\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ExampleFactoryBean.class);\n\t\t\tbuilder.addConstructorArgValue(\"foo\");\n\t\t\tregistry.registerBeanDefinition(\"exampleBeanFactoryBean\", builder.getBeanDefinition());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportResource(\"org/springframework/boot/autoconfigure/condition/factorybean.xml\")\n\tstatic class FactoryBeanXmlConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConditionalOnMissingBeanProducedByFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tExampleBean createExampleBean() {\n\t\t\treturn new ExampleBean(\"direct\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConditionalOnMissingFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tExampleFactoryBean additionalExampleFactoryBean() {\n\t\t\treturn new ExampleFactoryBean(\"factory\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConditionalOnIgnoredSubclassConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ignored = CustomExampleBean.class)\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConditionalOnIgnoredSubclassByNameConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(\n\t\t\t\tignoredType = \"org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanTests$CustomExampleBean\")\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomExampleBeanConfiguration {\n\n\t\t@Bean\n\t\tCustomExampleBean customExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(annotation = TestAnnotation.class)\n\tstatic class OnAnnotationConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnAnnotationMethodConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(annotation = TestAnnotation.class)\n\t\tUnrelatedExampleBean conditional() {\n\t\t\treturn new UnrelatedExampleBean(\"conditional\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(annotation = TestAnnotation.class)\n\tstatic class OnAnnotationWithFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAnnotation\n\tstatic class FooConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotAutowireCandidateConfiguration {\n\n\t\t@Bean(autowireCandidate = false)\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NotDefaultCandidateConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(name = \"foo\")\n\tstatic class HierarchyConsideredConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(name = \"foo\", search = SearchStrategy.CURRENT)\n\tstatic class HierarchyNotConsideredConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleBeanConfiguration {\n\n\t\t@Bean\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ScopedExampleBean.class)\n\tstatic class ScopedExampleBeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UnrelatedExampleBeanConfiguration {\n\n\t\t@Bean\n\t\tUnrelatedExampleBean unrelatedExampleBean() {\n\t\t\treturn new UnrelatedExampleBean(\"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ImpliedOnBeanMethodConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tExampleBean exampleBean2() {\n\t\t\treturn new ExampleBean(\"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithCustomConfiguration {\n\n\t\t@Bean\n\t\tCustomExampleBean customExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithoutCustomConfiguration {\n\n\t\t@Bean\n\t\tOtherExampleBean otherExampleBean() {\n\t\t\treturn new OtherExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithoutCustomContainerConfiguration {\n\n\t\t@Bean\n\t\tTestParameterizedContainer<OtherExampleBean> otherExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithCustomContainerConfiguration {\n\n\t\t@Bean\n\t\tTestParameterizedContainer<CustomExampleBean> customExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedConditionWithValueConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tCustomExampleBean conditionalCustomExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedConditionWithReturnTypeConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tCustomExampleBean conditionalCustomExampleBean() {\n\t\t\treturn new CustomExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedConditionWithReturnRegistrationTypeConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tTestParameterizedContainer<CustomExampleBean> conditionalCustomExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotatedNotAutowireCandidateConfiguration {\n\n\t\t@Bean(autowireCandidate = false)\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"value\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotatedNotDefaultCandidateConfiguration {\n\n\t\t@Bean(autowireCandidate = false)\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean(\"value\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterizedWithCustomGenericConfiguration {\n\n\t\t@Bean\n\t\tCustomGenericExampleBean customGenericExampleBean() {\n\t\t\treturn new CustomGenericExampleBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericWithStringTypeArgumentsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tGenericExampleBean<String> genericStringExampleBean() {\n\t\t\treturn new GenericExampleBean<>(\"genericStringExampleBean\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericWithIntegerTypeArgumentsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tGenericExampleBean<Integer> genericIntegerExampleBean() {\n\t\t\treturn new GenericExampleBean<>(1_000);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TypeArgumentsConditionWithValueConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(GenericExampleBean.class)\n\t\tGenericExampleBean<String> genericStringWithValueExampleBean() {\n\t\t\treturn new GenericExampleBean<>(\"genericStringWithValueExampleBean\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TypeArgumentsConditionWithParameterizedContainerConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(parameterizedContainer = TestParameterizedContainer.class)\n\t\tTestParameterizedContainer<GenericExampleBean<String>> parameterizedContainerGenericExampleBean() {\n\t\t\treturn new TestParameterizedContainer<>();\n\t\t}\n\n\t}\n\n\tstatic class ExampleFactoryBean implements FactoryBean<ExampleBean> {\n\n\t\tExampleFactoryBean(String value) {\n\t\t\tAssert.state(!value.contains(\"$\"), \"value should not contain '$'\");\n\t\t}\n\n\t\t@Override\n\t\tpublic ExampleBean getObject() {\n\t\t\treturn new ExampleBean(\"fromFactory\");\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn ExampleBean.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isSingleton() {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\tstatic class NonspecificFactoryBean implements FactoryBean<Object> {\n\n\t\tNonspecificFactoryBean(String value) {\n\t\t\tAssert.state(!value.contains(\"$\"), \"value should not contain '$'\");\n\t\t}\n\n\t\t@Override\n\t\tpublic ExampleBean getObject() {\n\t\t\treturn new ExampleBean(\"fromFactory\");\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn ExampleBean.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isSingleton() {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t@TestAnnotation\n\tstatic class ExampleBean {\n\n\t\tprivate final String value;\n\n\t\tExampleBean(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t@Scope(scopeName = \"test\", proxyMode = ScopedProxyMode.TARGET_CLASS)\n\tstatic class ScopedExampleBean extends ExampleBean {\n\n\t\tScopedExampleBean() {\n\t\t\tsuper(\"test\");\n\t\t}\n\n\t}\n\n\tstatic class CustomExampleBean extends ExampleBean {\n\n\t\tCustomExampleBean() {\n\t\t\tsuper(\"custom subclass\");\n\t\t}\n\n\t}\n\n\tstatic class OtherExampleBean extends ExampleBean {\n\n\t\tOtherExampleBean() {\n\t\t\tsuper(\"other subclass\");\n\t\t}\n\n\t}\n\n\tstatic class UnrelatedExampleBean {\n\n\t\tprivate final String value;\n\n\t\tUnrelatedExampleBean(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t@TestAnnotation\n\tstatic class GenericExampleBean<T> {\n\n\t\tprivate final T value;\n\n\t\tGenericExampleBean(T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.valueOf(this.value);\n\t\t}\n\n\t}\n\n\tstatic class CustomGenericExampleBean extends GenericExampleBean<String> {\n\n\t\tCustomGenericExampleBean() {\n\t\t\tsuper(\"custom subclass\");\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@interface TestAnnotation {\n\n\t}\n\n\tstatic class TestScope extends SimpleThreadScope {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(type = \"com.example.DoesNotExist\")\n\tstatic class OnMissingBeanForTypeThatDoesNotExist {\n\n\t\t@Bean\n\t\tString bean() {\n\t\t\treturn \"bean\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanWithFilteredClasspathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.cache.caffeine.CaffeineCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests {@link ConditionalOnMissingBean @ConditionalOnMissingBean} with filtered\n * classpath.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"spring-context-support-*.jar\")\nclass ConditionalOnMissingBeanWithFilteredClasspathTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(OnBeanTypeConfiguration.class);\n\n\t@Test\n\tvoid testNameOnMissingBeanTypeWithMissingImport() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnBeanTypeConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(\n\t\t\t\ttype = \"org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanWithFilteredClasspathTests.TestCacheManager\")\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\tstatic class TestCacheManager extends CaffeineCacheManager {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingClassTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnMissingClass @ConditionalOnMissingClass}.\n *\n * @author Dave Syer\n */\nclass ConditionalOnMissingClassTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@Test\n\tvoid testVanillaOnClassCondition() {\n\t\tthis.context.register(BasicConfiguration.class, FooConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.containsBean(\"bar\")).isFalse();\n\t\tassertThat(this.context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid testMissingOnClassCondition() {\n\t\tthis.context.register(MissingConfiguration.class, FooConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.containsBean(\"bar\")).isTrue();\n\t\tassertThat(this.context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingClass(\"org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClassTests\")\n\tstatic class BasicConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingClass(\"FOO\")\n\tstatic class MissingConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FooConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingFilterBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.io.IOException;\nimport java.util.function.Consumer;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnMissingFilterBean @ConditionalOnMissingFilterBean}.\n *\n * @author Phillip Webb\n */\nclass ConditionalOnMissingFilterBeanTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid outcomeWhenValueIsOfMissingBeanReturnsMatch() {\n\t\tthis.contextRunner.withUserConfiguration(WithoutTestFilterConfig.class, OnMissingWithValueConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myOtherFilter\", \"testFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenValueIsOfExistingBeanReturnsNoMatch() {\n\t\tthis.contextRunner.withUserConfiguration(WithTestFilterConfig.class, OnMissingWithValueConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myTestFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenValueIsOfMissingBeanRegistrationReturnsMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(WithoutTestFilterRegistrationConfig.class, OnMissingWithValueConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myOtherFilter\", \"testFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenValueIsOfExistingBeanRegistrationReturnsNoMatch() {\n\t\tthis.contextRunner.withUserConfiguration(WithTestFilterRegistrationConfig.class, OnMissingWithValueConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myTestFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenReturnTypeIsOfExistingBeanReturnsNoMatch() {\n\t\tthis.contextRunner.withUserConfiguration(WithTestFilterConfig.class, OnMissingWithReturnTypeConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myTestFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenReturnTypeIsOfExistingBeanRegistrationReturnsNoMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(WithTestFilterRegistrationConfig.class, OnMissingWithReturnTypeConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myTestFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenReturnRegistrationTypeIsOfExistingBeanReturnsNoMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(WithTestFilterConfig.class, OnMissingWithReturnRegistrationTypeConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myTestFilter\")));\n\t}\n\n\t@Test\n\tvoid outcomeWhenReturnRegistrationTypeIsOfExistingBeanRegistrationReturnsNoMatch() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(WithTestFilterRegistrationConfig.class,\n\t\t\t\t\tOnMissingWithReturnRegistrationTypeConfig.class)\n\t\t\t.run((context) -> assertThat(context).satisfies(filterBeanRequirement(\"myTestFilter\")));\n\t}\n\n\tprivate Consumer<ConfigurableApplicationContext> filterBeanRequirement(String... names) {\n\t\treturn (context) -> {\n\t\t\tString[] filters = context.getBeanNamesForType(Filter.class);\n\t\t\tString[] registrations = context.getBeanNamesForType(FilterRegistrationBean.class);\n\t\t\tassertThat(StringUtils.concatenateStringArrays(filters, registrations)).containsOnly(names);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WithTestFilterConfig {\n\n\t\t@Bean\n\t\tTestFilter myTestFilter() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WithoutTestFilterConfig {\n\n\t\t@Bean\n\t\tOtherFilter myOtherFilter() {\n\t\t\treturn new OtherFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WithoutTestFilterRegistrationConfig {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<OtherFilter> myOtherFilter() {\n\t\t\treturn new FilterRegistrationBean<>(new OtherFilter());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WithTestFilterRegistrationConfig {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<TestFilter> myTestFilter() {\n\t\t\treturn new FilterRegistrationBean<>(new TestFilter());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnMissingWithValueConfig {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingFilterBean(TestFilter.class)\n\t\tTestFilter testFilter() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnMissingWithReturnTypeConfig {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingFilterBean\n\t\tTestFilter testFilter() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnMissingWithReturnRegistrationTypeConfig {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingFilterBean\n\t\tFilterRegistrationBean<TestFilter> testFilter() {\n\t\t\treturn new FilterRegistrationBean<>(new TestFilter());\n\t\t}\n\n\t}\n\n\tstatic class TestFilter implements Filter {\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\tthrows IOException, ServletException {\n\t\t}\n\n\t}\n\n\tstatic class OtherFilter implements Filter {\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\tthrows IOException, ServletException {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWarDeploymentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnNotWarDeployment @ConditionalOnNotWarDeployment}.\n *\n * @author Guirong Hu\n */\nclass ConditionalOnNotWarDeploymentTests {\n\n\t@Test\n\tvoid nonWebApplicationShouldMatch() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\t\tcontextRunner.withUserConfiguration(NotWarDeploymentConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"notForWar\"));\n\t}\n\n\t@Test\n\tvoid reactiveWebApplicationShouldMatch() {\n\t\tReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner();\n\t\tcontextRunner.withUserConfiguration(NotWarDeploymentConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"notForWar\"));\n\t}\n\n\t@Test\n\tvoid embeddedServletWebApplicationShouldMatch() {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\t\tAnnotationConfigServletWebApplicationContext::new);\n\t\tcontextRunner.withUserConfiguration(NotWarDeploymentConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"notForWar\"));\n\t}\n\n\t@Test\n\tvoid warDeployedServletWebApplicationShouldNotMatch() {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner();\n\t\tcontextRunner.withUserConfiguration(NotWarDeploymentConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"notForWar\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnNotWarDeployment\n\tstatic class NotWarDeploymentConfiguration {\n\n\t\t@Bean\n\t\tString notForWar() {\n\t\t\treturn \"notForWar\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ConditionalOnNotWebApplication @ConditionalOnNotWebApplication}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass ConditionalOnNotWebApplicationTests {\n\n\t@Test\n\tvoid testNotWebApplicationWithServletContext() {\n\t\tnew WebApplicationContextRunner().withUserConfiguration(NotWebApplicationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(String.class));\n\t}\n\n\t@Test\n\tvoid testNotWebApplicationWithReactiveContext() {\n\t\tnew ReactiveWebApplicationContextRunner().withUserConfiguration(NotWebApplicationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(String.class));\n\t}\n\n\t@Test\n\tvoid testNotWebApplication() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(NotWebApplicationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getBeans(String.class).containsExactly(entry(\"none\", \"none\")));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnNotWebApplication\n\tstatic class NotWebApplicationConfiguration {\n\n\t\t@Bean\n\t\tString none() {\n\t\t\treturn \"none\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnPropertyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ConditionalOnProperty @ConditionalOnProperty}.\n *\n * @author Maciej Walkowiak\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ConditionalOnPropertyTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid allPropertiesAreDefined() {\n\t\tload(MultiplePropertiesRequiredConfiguration.class, \"property1=value1\", \"property2=value2\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid notAllPropertiesAreDefined() {\n\t\tload(MultiplePropertiesRequiredConfiguration.class, \"property1=value1\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid propertyValueEqualsFalse() {\n\t\tload(MultiplePropertiesRequiredConfiguration.class, \"property1=false\", \"property2=value2\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid propertyValueEqualsFALSE() {\n\t\tload(MultiplePropertiesRequiredConfiguration.class, \"property1=FALSE\", \"property2=value2\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid relaxedName() {\n\t\tload(RelaxedPropertiesRequiredConfiguration.class, \"spring.theRelaxedProperty=value1\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid prefixWithoutPeriod() {\n\t\tload(RelaxedPropertiesRequiredConfigurationWithShortPrefix.class, \"spring.property=value1\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\t// Enabled by default\n\tvoid enabledIfNotConfiguredOtherwise() {\n\t\tload(EnabledIfNotConfiguredOtherwiseConfig.class);\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid enabledIfNotConfiguredOtherwiseWithConfig() {\n\t\tload(EnabledIfNotConfiguredOtherwiseConfig.class, \"simple.myProperty:false\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid enabledIfNotConfiguredOtherwiseWithConfigDifferentCase() {\n\t\tload(EnabledIfNotConfiguredOtherwiseConfig.class, \"simple.my-property:FALSE\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\t// Disabled by default\n\tvoid disableIfNotConfiguredOtherwise() {\n\t\tload(DisabledIfNotConfiguredOtherwiseConfig.class);\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid disableIfNotConfiguredOtherwiseWithConfig() {\n\t\tload(DisabledIfNotConfiguredOtherwiseConfig.class, \"simple.myProperty:true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid disableIfNotConfiguredOtherwiseWithConfigDifferentCase() {\n\t\tload(DisabledIfNotConfiguredOtherwiseConfig.class, \"simple.myproperty:TrUe\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid simpleValueIsSet() {\n\t\tload(SimpleValueConfig.class, \"simple.myProperty:bar\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid caseInsensitive() {\n\t\tload(SimpleValueConfig.class, \"simple.myProperty:BaR\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultValueIsSet() {\n\t\tload(DefaultValueConfig.class, \"simple.myProperty:bar\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultValueIsNotSet() {\n\t\tload(DefaultValueConfig.class);\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultValueIsSetDifferentValue() {\n\t\tload(DefaultValueConfig.class, \"simple.myProperty:another\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid prefix() {\n\t\tload(PrefixValueConfig.class, \"simple.myProperty:bar\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid relaxedEnabledByDefault() {\n\t\tload(PrefixValueConfig.class, \"simple.myProperty:bar\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid multiValuesAllSet() {\n\t\tload(MultiValuesConfig.class, \"simple.my-property:bar\", \"simple.my-another-property:bar\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid multiValuesOnlyOneSet() {\n\t\tload(MultiValuesConfig.class, \"simple.my-property:bar\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid usingValueAttribute() {\n\t\tload(ValueAttribute.class, \"some.property\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\tprivate boolean containsBean() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn this.context.containsBean(\"foo\");\n\t}\n\n\t@Test\n\tvoid nameOrValueMustBeSpecified() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> load(NoNameOrValueAttribute.class, \"some.property\"))\n\t\t\t.satisfies(\n\t\t\t\t\tcauseMessageContaining(\"The name or value attribute of @ConditionalOnProperty must be specified\"));\n\t}\n\n\t@Test\n\tvoid nameAndValueMustNotBeSpecified() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> load(NameAndValueAttribute.class, \"some.property\"))\n\t\t\t.satisfies(causeMessageContaining(\"The name and value attributes of @ConditionalOnProperty are exclusive\"));\n\t}\n\n\tprivate <T extends Exception> Consumer<T> causeMessageContaining(String message) {\n\t\treturn (ex) -> assertThat(ex.getCause()).hasMessageContaining(message);\n\t}\n\n\t@Test\n\tvoid metaAnnotationConditionMatchesWhenPropertyIsSet() {\n\t\tload(MetaAnnotation.class, \"my.feature.enabled=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid metaAnnotationConditionDoesNotMatchWhenPropertyIsNotSet() {\n\t\tload(MetaAnnotation.class);\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationConditionDoesNotMatchWhenOnlyDirectPropertyIsSet() {\n\t\tload(MetaAnnotationAndDirectAnnotation.class, \"my.other.feature.enabled=true\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationConditionDoesNotMatchWhenOnlyMetaPropertyIsSet() {\n\t\tload(MetaAnnotationAndDirectAnnotation.class, \"my.feature.enabled=true\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationConditionDoesNotMatchWhenNeitherPropertyIsSet() {\n\t\tload(MetaAnnotationAndDirectAnnotation.class);\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationConditionMatchesWhenBothPropertiesAreSet() {\n\t\tload(MetaAnnotationAndDirectAnnotation.class, \"my.feature.enabled=true\", \"my.other.feature.enabled=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid metaAnnotationWithAliasConditionMatchesWhenPropertyIsSet() {\n\t\tload(MetaAnnotationWithAlias.class, \"my.feature.enabled=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationWithAliasConditionDoesNotMatchWhenOnlyMetaPropertyIsSet() {\n\t\tload(MetaAnnotationAndDirectAnnotationWithAlias.class, \"my.feature.enabled=true\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationWithAliasConditionDoesNotMatchWhenOnlyDirectPropertyIsSet() {\n\t\tload(MetaAnnotationAndDirectAnnotationWithAlias.class, \"my.other.feature.enabled=true\");\n\t\tassertThat(containsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid metaAndDirectAnnotationWithAliasConditionMatchesWhenBothPropertiesAreSet() {\n\t\tload(MetaAnnotationAndDirectAnnotationWithAlias.class, \"my.feature.enabled=true\",\n\t\t\t\t\"my.other.feature.enabled=true\");\n\t\tassertThat(containsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid multiplePropertiesConditionReportWhenMatched() {\n\t\tload(MultiplePropertiesRequiredConfiguration.class, \"property1=value1\", \"property2=value2\");\n\t\tassertThat(containsBean()).isTrue();\n\t\tassertThat(getConditionEvaluationReport()).contains(\"@ConditionalOnProperty ([property1,property2]) matched\");\n\t}\n\n\t@Test\n\tvoid multiplePropertiesConditionReportWhenDoesNotMatch() {\n\t\tload(MultiplePropertiesRequiredConfiguration.class, \"property1=value1\");\n\t\tassertThat(getConditionEvaluationReport())\n\t\t\t.contains(\"@ConditionalOnProperty ([property1,property2]) did not find property 'property2'\");\n\t}\n\n\t@Test\n\tvoid repeatablePropertiesConditionReportWhenMatched() {\n\t\tload(RepeatablePropertiesRequiredConfiguration.class, \"property1=value1\", \"property2=value2\");\n\t\tassertThat(containsBean()).isTrue();\n\t\tString report = getConditionEvaluationReport();\n\t\tassertThat(report).contains(\"@ConditionalOnProperty (property1) matched\");\n\t\tassertThat(report).contains(\"@ConditionalOnProperty (property2) matched\");\n\t}\n\n\t@Test\n\tvoid repeatablePropertiesConditionReportWhenDoesNotMatch() {\n\t\tload(RepeatablePropertiesRequiredConfiguration.class, \"property1=value1\");\n\t\tassertThat(getConditionEvaluationReport())\n\t\t\t.contains(\"@ConditionalOnProperty (property2) did not find property 'property2'\");\n\t}\n\n\tprivate void load(Class<?> config, String... environment) {\n\t\tTestPropertyValues.of(environment).applyTo(this.environment);\n\t\tthis.context = new SpringApplicationBuilder(config).environment(this.environment)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.run();\n\t}\n\n\tprivate String getConditionEvaluationReport() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn ConditionEvaluationReport.get(this.context.getBeanFactory())\n\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t.values()\n\t\t\t.stream()\n\t\t\t.flatMap(ConditionAndOutcomes::stream)\n\t\t\t.map(Object::toString)\n\t\t\t.collect(Collectors.joining(\"\\n\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(name = { \"property1\", \"property2\" })\n\tstatic class MultiplePropertiesRequiredConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(\"property1\")\n\t@ConditionalOnProperty(\"property2\")\n\tstatic class RepeatablePropertiesRequiredConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(prefix = \"spring.\", name = \"the-relaxed-property\")\n\tstatic class RelaxedPropertiesRequiredConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(prefix = \"spring\", name = \"property\")\n\tstatic class RelaxedPropertiesRequiredConfigurationWithShortPrefix {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t// i.e ${simple.myProperty:true}\n\t@ConditionalOnProperty(prefix = \"simple\", name = \"my-property\", havingValue = \"true\", matchIfMissing = true)\n\tstatic class EnabledIfNotConfiguredOtherwiseConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t// i.e ${simple.myProperty:false}\n\t@ConditionalOnProperty(prefix = \"simple\", name = \"my-property\", havingValue = \"true\")\n\tstatic class DisabledIfNotConfiguredOtherwiseConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(prefix = \"simple\", name = \"my-property\", havingValue = \"bar\")\n\tstatic class SimpleValueConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(name = \"simple.myProperty\", havingValue = \"bar\", matchIfMissing = true)\n\tstatic class DefaultValueConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(prefix = \"simple\", name = \"my-property\", havingValue = \"bar\")\n\tstatic class PrefixValueConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(prefix = \"simple\", name = { \"my-property\", \"my-another-property\" }, havingValue = \"bar\")\n\tstatic class MultiValuesConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(\"some.property\")\n\tstatic class ValueAttribute {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty\n\tstatic class NoNameOrValueAttribute {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(value = \"x\", name = \"y\")\n\tstatic class NameAndValueAttribute {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMyFeature\n\tstatic class MetaAnnotation {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMyFeature\n\t@ConditionalOnProperty(prefix = \"my.other.feature\", name = \"enabled\", havingValue = \"true\")\n\tstatic class MetaAnnotationAndDirectAnnotation {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Target({ ElementType.TYPE, ElementType.METHOD })\n\t@ConditionalOnProperty(prefix = \"my.feature\", name = \"enabled\", havingValue = \"true\")\n\t@interface ConditionalOnMyFeature {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMyFeatureWithAlias(\"my.feature\")\n\tstatic class MetaAnnotationWithAlias {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMyFeatureWithAlias(\"my.feature\")\n\t@ConditionalOnProperty(prefix = \"my.other.feature\", name = \"enabled\", havingValue = \"true\")\n\tstatic class MetaAnnotationAndDirectAnnotationWithAlias {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Target({ ElementType.TYPE, ElementType.METHOD })\n\t@ConditionalOnProperty(name = \"enabled\", havingValue = \"true\")\n\t@interface ConditionalOnMyFeatureWithAlias {\n\n\t\t@AliasFor(annotation = ConditionalOnProperty.class, attribute = \"prefix\")\n\t\tString value();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnResource @ConditionalOnResource}.\n *\n * @author Dave Syer\n */\nclass ConditionalOnResourceTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@Test\n\t@WithResource(name = \"schema.sql\")\n\tvoid testResourceExists() {\n\t\tthis.context.register(BasicConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.containsBean(\"foo\")).isTrue();\n\t\tassertThat(this.context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"schema.sql\")\n\tvoid testResourceExistsWithPlaceholder() {\n\t\tTestPropertyValues.of(\"schema=schema.sql\").applyTo(this.context);\n\t\tthis.context.register(PlaceholderConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.containsBean(\"foo\")).isTrue();\n\t\tassertThat(this.context.getBean(\"foo\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid testResourceNotExists() {\n\t\tthis.context.register(MissingConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.containsBean(\"foo\")).isFalse();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnResource(resources = \"foo\")\n\tstatic class MissingConfiguration {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnResource(resources = \"schema.sql\")\n\tstatic class BasicConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnResource(resources = \"${schema}\")\n\tstatic class PlaceholderConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Fallback;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.context.annotation.ScopedProxyMode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnSingleCandidate @ConditionalOnSingleCandidate}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass ConditionalOnSingleCandidateTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid singleCandidateNoCandidate() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"consumer\"));\n\t}\n\n\t@Test\n\tvoid singleCandidateOneCandidate() {\n\t\tthis.contextRunner.withUserConfiguration(AlphaConfiguration.class, OnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"consumer\");\n\t\t\t\tassertThat(context.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateOneScopedProxyCandidate() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaScopedProxyConfiguration.class, OnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"consumer\");\n\t\t\t\tassertThat(context.getBean(\"consumer\")).hasToString(\"alpha\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateInAncestorsOneCandidateInCurrent() {\n\t\tthis.contextRunner.run((parent) -> this.contextRunner\n\t\t\t.withUserConfiguration(AlphaConfiguration.class, OnBeanSingleCandidateInAncestorsConfiguration.class)\n\t\t\t.withParent(parent)\n\t\t\t.run((child) -> assertThat(child).doesNotHaveBean(\"consumer\")));\n\t}\n\n\t@Test\n\tvoid singleCandidateInAncestorsOneCandidateInParent() {\n\t\tthis.contextRunner.withUserConfiguration(AlphaConfiguration.class)\n\t\t\t.run((parent) -> this.contextRunner\n\t\t\t\t.withUserConfiguration(OnBeanSingleCandidateInAncestorsConfiguration.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tassertThat(child).hasBean(\"consumer\");\n\t\t\t\t\tassertThat(child.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid singleCandidateInAncestorsOneCandidateInGrandparent() {\n\t\tthis.contextRunner.withUserConfiguration(AlphaConfiguration.class)\n\t\t\t.run((grandparent) -> this.contextRunner.withParent(grandparent)\n\t\t\t\t.run((parent) -> this.contextRunner\n\t\t\t\t\t.withUserConfiguration(OnBeanSingleCandidateInAncestorsConfiguration.class)\n\t\t\t\t\t.withParent(parent)\n\t\t\t\t\t.run((child) -> {\n\t\t\t\t\t\tassertThat(child).hasBean(\"consumer\");\n\t\t\t\t\t\tassertThat(child.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t\t\t})));\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidates() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaConfiguration.class, BravoConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"consumer\"));\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidatesOnePrimary() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaPrimaryConfiguration.class, BravoConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"consumer\");\n\t\t\t\tassertThat(context.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateTwoCandidatesOneNormalOneFallback() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaFallbackConfiguration.class, BravoConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"consumer\");\n\t\t\t\tassertThat(context.getBean(\"consumer\")).isEqualTo(\"bravo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidatesMultiplePrimary() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaPrimaryConfiguration.class, BravoPrimaryConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"consumer\"));\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidatesAllFallback() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaFallbackConfiguration.class, BravoFallbackConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"consumer\"));\n\t}\n\n\t@Test\n\tvoid invalidAnnotationTwoTypes() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanSingleCandidateTwoTypesConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.hasCauseInstanceOf(IllegalArgumentException.class)\n\t\t\t\t.hasMessageContaining(OnBeanSingleCandidateTwoTypesConfiguration.class.getName());\n\t\t});\n\t}\n\n\t@Test\n\tvoid invalidAnnotationNoType() {\n\t\tthis.contextRunner.withUserConfiguration(OnBeanSingleCandidateNoTypeConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.hasCauseInstanceOf(IllegalArgumentException.class)\n\t\t\t\t.hasMessageContaining(OnBeanSingleCandidateNoTypeConfiguration.class.getName());\n\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidatesInContextHierarchy() {\n\t\tthis.contextRunner.withUserConfiguration(AlphaPrimaryConfiguration.class, BravoConfiguration.class)\n\t\t\t.run((parent) -> this.contextRunner.withUserConfiguration(OnBeanSingleCandidateConfiguration.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tassertThat(child).hasBean(\"consumer\");\n\t\t\t\t\tassertThat(child.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidatesOneAutowireCandidate() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaConfiguration.class, BravoNonAutowireConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"consumer\");\n\t\t\t\tassertThat(context.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateMultipleCandidatesOneDefaultCandidate() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AlphaConfiguration.class, BravoNonDefaultConfiguration.class,\n\t\t\t\t\tOnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"consumer\");\n\t\t\t\tassertThat(context.getBean(\"consumer\")).isEqualTo(\"alpha\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid singleCandidateDoesNotMatchWhenMultipleRegisteredAsSingletonCandidates() {\n\t\tthis.contextRunner.withInitializer((context) -> {\n\t\t\tcontext.getBeanFactory().registerSingleton(\"alpha\", \"alpha\");\n\t\t\tcontext.getBeanFactory().registerSingleton(\"bravo\", \"bravo\");\n\t\t})\n\t\t\t.withUserConfiguration(OnBeanSingleCandidateConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"consumer\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(String.class)\n\tstatic class OnBeanSingleCandidateConfiguration {\n\n\t\t@Bean\n\t\tCharSequence consumer(CharSequence s) {\n\t\t\treturn s;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(value = String.class, search = SearchStrategy.ANCESTORS)\n\tstatic class OnBeanSingleCandidateInAncestorsConfiguration {\n\n\t\t@Bean\n\t\tCharSequence consumer(CharSequence s) {\n\t\t\treturn s;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(value = String.class, type = \"java.lang.Integer\")\n\tstatic class OnBeanSingleCandidateTwoTypesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate\n\tstatic class OnBeanSingleCandidateNoTypeConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AlphaConfiguration {\n\n\t\t@Bean\n\t\tString alpha() {\n\t\t\treturn \"alpha\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AlphaPrimaryConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tString alpha() {\n\t\t\treturn \"alpha\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AlphaFallbackConfiguration {\n\n\t\t@Bean\n\t\t@Fallback\n\t\tString alpha() {\n\t\t\treturn \"alpha\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AlphaScopedProxyConfiguration {\n\n\t\t@Bean\n\t\t@Scope(proxyMode = ScopedProxyMode.INTERFACES)\n\t\tString alpha() {\n\t\t\treturn \"alpha\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BravoConfiguration {\n\n\t\t@Bean\n\t\tString bravo() {\n\t\t\treturn \"bravo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BravoPrimaryConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tString bravo() {\n\t\t\treturn \"bravo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BravoFallbackConfiguration {\n\n\t\t@Bean\n\t\t@Fallback\n\t\tString bravo() {\n\t\t\treturn \"bravo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BravoNonAutowireConfiguration {\n\n\t\t@Bean(autowireCandidate = false)\n\t\tString bravo() {\n\t\t\treturn \"bravo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BravoNonDefaultConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tString bravo() {\n\t\t\treturn \"bravo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnThreadingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnThreading}.\n *\n * @author Moritz Halbritter\n */\nclass ConditionalOnThreadingTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(BasicConfiguration.class);\n\n\t@Test\n\t@EnabledForJreRange(max = JRE.JAVA_20)\n\tvoid platformThreadsOnJdkBelow21IfVirtualThreadsPropertyIsEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThreadType.class)).isEqualTo(ThreadType.PLATFORM));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(max = JRE.JAVA_20)\n\tvoid platformThreadsOnJdkBelow21IfVirtualThreadsPropertyIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=false\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThreadType.class)).isEqualTo(ThreadType.PLATFORM));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid virtualThreadsOnJdk21IfVirtualThreadsPropertyIsEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThreadType.class)).isEqualTo(ThreadType.VIRTUAL));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid platformThreadsOnJdk21IfVirtualThreadsPropertyIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=false\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThreadType.class)).isEqualTo(ThreadType.PLATFORM));\n\t}\n\n\tprivate enum ThreadType {\n\n\t\tPLATFORM, VIRTUAL\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BasicConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnThreading(Threading.VIRTUAL)\n\t\tThreadType virtual() {\n\t\t\treturn ThreadType.VIRTUAL;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnThreading(Threading.PLATFORM)\n\t\tThreadType platform() {\n\t\t\treturn ThreadType.PLATFORM;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWarDeploymentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnWarDeployment @ConditionalOnWarDeployment}.\n *\n * @author Madhura Bhave\n */\nclass ConditionalOnWarDeploymentTests {\n\n\t@Test\n\tvoid nonWebApplicationShouldNotMatch() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\t\tcontextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"forWar\"));\n\t}\n\n\t@Test\n\tvoid reactiveWebApplicationShouldNotMatch() {\n\t\tReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner();\n\t\tcontextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"forWar\"));\n\t}\n\n\t@Test\n\tvoid embeddedServletWebApplicationShouldNotMatch() {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\t\tAnnotationConfigServletWebApplicationContext::new);\n\t\tcontextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"forWar\"));\n\t}\n\n\t@Test\n\tvoid warDeployedServletWebApplicationShouldMatch() {\n\t\t// sets a mock servletContext before context refresh which is what the\n\t\t// SpringBootServletInitializer does for WAR deployments.\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner();\n\t\tcontextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"forWar\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWarDeployment\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tString forWar() {\n\t\t\treturn \"forWar\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.web.context.reactive.AnnotationConfigReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.web.MockServletContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ConditionalOnWebApplication @ConditionalOnWebApplication}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass ConditionalOnWebApplicationTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid testWebApplicationWithServletContext() {\n\t\tAnnotationConfigServletWebApplicationContext ctx = new AnnotationConfigServletWebApplicationContext();\n\t\tctx.register(AnyWebApplicationConfiguration.class, ServletWebApplicationConfiguration.class,\n\t\t\t\tReactiveWebApplicationConfiguration.class);\n\t\tctx.setServletContext(new MockServletContext());\n\t\tctx.refresh();\n\t\tthis.context = ctx;\n\t\tassertThat(this.context.getBeansOfType(String.class)).containsExactly(entry(\"any\", \"any\"),\n\t\t\t\tentry(\"servlet\", \"servlet\"));\n\t}\n\n\t@Test\n\tvoid testWebApplicationWithReactiveContext() {\n\t\tAnnotationConfigReactiveWebApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();\n\t\tcontext.register(AnyWebApplicationConfiguration.class, ServletWebApplicationConfiguration.class,\n\t\t\t\tReactiveWebApplicationConfiguration.class);\n\t\tcontext.refresh();\n\t\tthis.context = context;\n\t\tassertThat(this.context.getBeansOfType(String.class)).containsExactly(entry(\"any\", \"any\"),\n\t\t\t\tentry(\"reactive\", \"reactive\"));\n\t}\n\n\t@Test\n\tvoid testNonWebApplication() {\n\t\tAnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();\n\t\tctx.register(AnyWebApplicationConfiguration.class, ServletWebApplicationConfiguration.class,\n\t\t\t\tReactiveWebApplicationConfiguration.class);\n\t\tctx.refresh();\n\t\tthis.context = ctx;\n\t\tassertThat(this.context.getBeansOfType(String.class)).isEmpty();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication\n\tstatic class AnyWebApplicationConfiguration {\n\n\t\t@Bean\n\t\tString any() {\n\t\t\treturn \"any\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\tstatic class ServletWebApplicationConfiguration {\n\n\t\t@Bean\n\t\tString servlet() {\n\t\t\treturn \"servlet\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\tstatic class ReactiveWebApplicationConfiguration {\n\n\t\t@Bean\n\t\tString reactive() {\n\t\t\treturn \"reactive\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/NoneNestedConditionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoneNestedConditions}.\n */\nclass NoneNestedConditionsTests {\n\n\t@Test\n\tvoid neither() {\n\t\tAnnotationConfigApplicationContext context = load(Config.class);\n\t\tassertThat(context.containsBean(\"myBean\")).isTrue();\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid propertyA() {\n\t\tAnnotationConfigApplicationContext context = load(Config.class, \"a:a\");\n\t\tassertThat(context.containsBean(\"myBean\")).isFalse();\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid propertyB() {\n\t\tAnnotationConfigApplicationContext context = load(Config.class, \"b:b\");\n\t\tassertThat(context.containsBean(\"myBean\")).isFalse();\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid both() {\n\t\tAnnotationConfigApplicationContext context = load(Config.class, \"a:a\", \"b:b\");\n\t\tassertThat(context.containsBean(\"myBean\")).isFalse();\n\t\tcontext.close();\n\t}\n\n\tprivate AnnotationConfigApplicationContext load(Class<?> config, String... env) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(env).applyTo(context);\n\t\tcontext.register(config);\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(NeitherPropertyANorPropertyBCondition.class)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tString myBean() {\n\t\t\treturn \"myBean\";\n\t\t}\n\n\t}\n\n\tstatic class NeitherPropertyANorPropertyBCondition extends NoneNestedConditions {\n\n\t\tNeitherPropertyANorPropertyBCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"a\")\n\t\tstatic class HasPropertyA {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"b\")\n\t\tstatic class HasPropertyB {\n\n\t\t}\n\n\t\t@Conditional(NonSpringBootCondition.class)\n\t\tstatic class SubClassC {\n\n\t\t}\n\n\t}\n\n\tstatic class NonSpringBootCondition implements Condition {\n\n\t\t@Override\n\t\tpublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnBeanConditionTypeDeductionFailureTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.ObjectMapper;\n\nimport org.springframework.boot.autoconfigure.condition.OnBeanCondition.BeanTypeDeductionException;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.type.AnnotationMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Tests for {@link OnBeanCondition} when deduction of the bean's type fails\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"jackson-core-*.jar\")\nclass OnBeanConditionTypeDeductionFailureTests {\n\n\t@Test\n\tvoid conditionalOnMissingBeanWithDeducedTypeThatIsPartiallyMissingFromClassPath() {\n\t\tassertThatException()\n\t\t\t.isThrownBy(() -> new AnnotationConfigApplicationContext(ImportingConfiguration.class).close())\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tThrowable beanTypeDeductionException = findNestedCause(ex, BeanTypeDeductionException.class);\n\t\t\t\tassertThat(beanTypeDeductionException).isNotNull();\n\t\t\t\tassertThat(beanTypeDeductionException).hasMessage(\"Failed to deduce bean type for \"\n\t\t\t\t\t\t+ OnMissingBeanConfiguration.class.getName() + \".objectMapper\");\n\t\t\t\tassertThat(findNestedCause(beanTypeDeductionException, NoClassDefFoundError.class)).isNotNull();\n\n\t\t\t});\n\t}\n\n\tprivate @Nullable Throwable findNestedCause(Throwable ex, Class<? extends Throwable> target) {\n\t\tThrowable candidate = ex;\n\t\twhile (candidate != null) {\n\t\t\tif (target.isInstance(candidate)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t\tcandidate = candidate.getCause();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(OnMissingBeanImportSelector.class)\n\tstatic class ImportingConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OnMissingBeanConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tObjectMapper objectMapper() {\n\t\t\treturn new ObjectMapper();\n\t\t}\n\n\t}\n\n\tstatic class OnMissingBeanImportSelector implements ImportSelector {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\treturn new String[] { OnMissingBeanConfiguration.class.getName() };\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnClassConditionAutoConfigurationImportFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurationImportFilter;\nimport org.springframework.boot.autoconfigure.AutoConfigurationMetadata;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for the {@link AutoConfigurationImportFilter} part of {@link OnClassCondition}.\n *\n * @author Phillip Webb\n */\nclass OnClassConditionAutoConfigurationImportFilterTests {\n\n\tprivate final OnClassCondition filter = new OnClassCondition();\n\n\tprivate final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.filter.setBeanClassLoader(getClass().getClassLoader());\n\t\tthis.filter.setBeanFactory(this.beanFactory);\n\t}\n\n\t@Test\n\tvoid shouldBeRegistered() {\n\t\tassertThat(SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, null))\n\t\t\t.hasAtLeastOneElementOfType(OnClassCondition.class);\n\t}\n\n\t@Test\n\tvoid matchShouldMatchClasses() {\n\t\tString[] autoConfigurationClasses = new String[] { \"test.match\", \"test.nomatch\" };\n\t\tboolean[] result = this.filter.match(autoConfigurationClasses, getAutoConfigurationMetadata());\n\t\tassertThat(result).containsExactly(true, false);\n\t}\n\n\t@Test\n\tvoid matchShouldRecordOutcome() {\n\t\tString[] autoConfigurationClasses = new String[] { \"test.match\", \"test.nomatch\" };\n\t\tthis.filter.match(autoConfigurationClasses, getAutoConfigurationMetadata());\n\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.beanFactory);\n\t\tassertThat(report.getConditionAndOutcomesBySource()).hasSize(1).containsKey(\"test.nomatch\");\n\t}\n\n\tprivate AutoConfigurationMetadata getAutoConfigurationMetadata() {\n\t\tAutoConfigurationMetadata metadata = mock(AutoConfigurationMetadata.class);\n\t\tgiven(metadata.wasProcessed(\"test.match\")).willReturn(true);\n\t\tgiven(metadata.get(\"test.match\", \"ConditionalOnClass\")).willReturn(\"java.io.InputStream\");\n\t\tgiven(metadata.wasProcessed(\"test.nomatch\")).willReturn(true);\n\t\tgiven(metadata.get(\"test.nomatch\", \"ConditionalOnClass\")).willReturn(\"java.io.DoesNotExist\");\n\t\treturn metadata;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/OnPropertyListConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OnPropertyListCondition}.\n *\n * @author Stephane Nicoll\n */\nclass OnPropertyListConditionTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfig.class);\n\n\t@Test\n\tvoid propertyNotDefined() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid propertyDefinedAsCommaSeparated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.test.my-list=value1\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid propertyDefinedAsList() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.test.my-list[0]=value1\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid propertyDefinedAsCommaSeparatedRelaxed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.test.myList=value1\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid propertyDefinedAsListRelaxed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.test.myList[0]=value1\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(TestPropertyListCondition.class)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\tstatic class TestPropertyListCondition extends OnPropertyListCondition {\n\n\t\tTestPropertyListCondition() {\n\t\t\tsuper(\"spring.test.my-list\", () -> ConditionMessage.forCondition(\"test\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ResourceConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link ResourceCondition}.\n *\n * @author Stephane Nicoll\n */\nclass ResourceConditionTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\t@WithResource(name = \"logging.properties\")\n\tvoid defaultResourceAndNoExplicitKey() {\n\t\tload(DefaultLocationConfiguration.class);\n\t\tassertThat(isContainsBean()).isTrue();\n\t}\n\n\t@Test\n\tvoid unknownDefaultLocationAndNoExplicitKey() {\n\t\tload(UnknownDefaultLocationConfiguration.class);\n\t\tassertThat(isContainsBean()).isFalse();\n\t}\n\n\t@Test\n\tvoid unknownDefaultLocationAndExplicitKeyToResource() {\n\t\tload(UnknownDefaultLocationConfiguration.class, \"spring.foo.test.config=logging.properties\");\n\t\tassertThat(isContainsBean()).isTrue();\n\t}\n\n\tprivate void load(Class<?> config, String... environment) {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(environment).applyTo(applicationContext);\n\t\tapplicationContext.register(config);\n\t\tapplicationContext.refresh();\n\t\tthis.context = applicationContext;\n\t}\n\n\tprivate boolean isContainsBean() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn this.context.containsBean(\"foo\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(DefaultLocationResourceCondition.class)\n\tstatic class DefaultLocationConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(UnknownDefaultLocationResourceCondition.class)\n\tstatic class UnknownDefaultLocationConfiguration {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\tstatic class DefaultLocationResourceCondition extends ResourceCondition {\n\n\t\tDefaultLocationResourceCondition() {\n\t\t\tsuper(\"test\", \"spring.foo.test.config\", \"classpath:/logging.properties\");\n\t\t}\n\n\t}\n\n\tstatic class UnknownDefaultLocationResourceCondition extends ResourceCondition {\n\n\t\tUnknownDefaultLocationResourceCondition() {\n\t\t\tsuper(\"test\", \"spring.foo.test.config\", \"classpath:/this-file-does-not-exist.xml\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/SpringBootConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SpringBootCondition}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"resource\")\nclass SpringBootConditionTests {\n\n\t@Test\n\tvoid sensibleClassException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new AnnotationConfigApplicationContext(ErrorOnClass.class))\n\t\t\t.withMessageContaining(\"Error processing condition on \" + ErrorOnClass.class.getName());\n\t}\n\n\t@Test\n\tvoid sensibleMethodException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new AnnotationConfigApplicationContext(ErrorOnMethod.class))\n\t\t\t.withMessageContaining(\"Error processing condition on \" + ErrorOnMethod.class.getName() + \".myBean\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(AlwaysThrowsCondition.class)\n\tstatic class ErrorOnClass {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ErrorOnMethod {\n\n\t\t@Bean\n\t\t@Conditional(AlwaysThrowsCondition.class)\n\t\tString myBean() {\n\t\t\treturn \"bean\";\n\t\t}\n\n\t}\n\n\tstatic class AlwaysThrowsCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tthrow new RuntimeException(\"Oh no!\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/TestParameterizedContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition;\n\n/**\n * Simple parameterized container for testing {@link ConditionalOnBean @ConditionalOnBean}\n * and {@link ConditionalOnMissingBean @ConditionalOnMissingBean}.\n *\n * @param <T> The bean type\n * @author Phillip Webb\n */\npublic class TestParameterizedContainer<T> {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/UniqueShortNameAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.config;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\n\n/**\n * Uniquely named auto-configuration for {@link ConditionEvaluationReport} tests.\n *\n * @author Andy Wilkinson\n */\n@AutoConfiguration\n@ConditionalOnProperty(\"unique\")\npublic final class UniqueShortNameAutoConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/first/SampleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.config.first;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Sample auto-configuration for {@link ConditionEvaluationReport} tests.\n *\n * @author Madhura Bhave\n */\n@AutoConfiguration(\"autoConfigOne\")\n@ConditionalOnProperty(\"sample.first\")\npublic final class SampleAutoConfiguration {\n\n\t@Bean\n\tString one() {\n\t\treturn \"one\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/first/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.condition.config.first;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.condition.config;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/second/SampleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.config.second;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Sample auto-configuration for {@link ConditionEvaluationReport} tests.\n *\n * @author Madhura Bhave\n */\n@AutoConfiguration(\"autoConfigTwo\")\n@ConditionalOnProperty(\"sample.second\")\npublic final class SampleAutoConfiguration {\n\n\t@Bean\n\tString two() {\n\t\treturn \"two\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/second/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.condition.config.second;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/scan/ScanBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.scan;\n\npublic class ScanBean {\n\n\tprivate final String value;\n\n\tpublic ScanBean(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/scan/ScanFactoryBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.scan;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.util.Assert;\n\nclass ScanFactoryBean implements FactoryBean<ScanBean> {\n\n\tScanFactoryBean(String value) {\n\t\tAssert.state(!value.contains(\"$\"), \"value should not contain '$'\");\n\t}\n\n\t@Override\n\tpublic ScanBean getObject() {\n\t\treturn new ScanBean(\"fromFactory\");\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn ScanBean.class;\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/scan/ScannedFactoryBeanConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.scan;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for a factory bean produced by a bean method on a configuration class\n * found through component scanning.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\npublic class ScannedFactoryBeanConfiguration {\n\n\t@Bean\n\tpublic FactoryBean<ScanBean> exampleBeanFactoryBean() {\n\t\treturn new ScanFactoryBean(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/scan/ScannedFactoryBeanWithBeanMethodArgumentsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.condition.scan;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for a factory bean produced by a bean method with arguments on a\n * configuration class found through component scanning.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\npublic class ScannedFactoryBeanWithBeanMethodArgumentsConfiguration {\n\n\t@Bean\n\tpublic Foo foo() {\n\t\treturn new Foo();\n\t}\n\n\t@Bean\n\tpublic ScanFactoryBean exampleBeanFactoryBean(Foo foo) {\n\t\treturn new ScanFactoryBean(\"foo\");\n\t}\n\n\tstatic class Foo {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/scan/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.condition.scan;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/container/ContainerImageMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.container;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.AttributeAccessor;\nimport org.springframework.core.AttributeAccessorSupport;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ContainerImageMetadata}.\n *\n * @author Phillip Webb\n */\nclass ContainerImageMetadataTests {\n\n\tprivate ContainerImageMetadata metadata = new ContainerImageMetadata(\"test\");\n\n\tprivate AttributeAccessor attributes = new AttributeAccessorSupport() {\n\n\t};\n\n\t@Test\n\tvoid addToWhenAttributesIsNullDoesNothing() {\n\t\tthis.metadata.addTo(null);\n\t}\n\n\t@Test\n\tvoid addToAddsMetadata() {\n\t\tthis.metadata.addTo(this.attributes);\n\t\tassertThat(this.attributes.getAttribute(ContainerImageMetadata.NAME)).isSameAs(this.metadata);\n\t}\n\n\t@Test\n\tvoid isPresentWhenPresentReturnsTrue() {\n\t\tthis.metadata.addTo(this.attributes);\n\t\tassertThat(ContainerImageMetadata.isPresent(this.attributes)).isTrue();\n\t}\n\n\t@Test\n\tvoid isPresentWhenNotPresentReturnsFalse() {\n\t\tassertThat(ContainerImageMetadata.isPresent(this.attributes)).isFalse();\n\t}\n\n\t@Test\n\tvoid isPresentWhenNullAttributesReturnsFalse() {\n\t\tassertThat(ContainerImageMetadata.isPresent(null)).isFalse();\n\t}\n\n\t@Test\n\tvoid getFromWhenPresentReturnsMetadata() {\n\t\tthis.metadata.addTo(this.attributes);\n\t\tassertThat(ContainerImageMetadata.getFrom(this.attributes)).isSameAs(this.metadata);\n\t}\n\n\t@Test\n\tvoid getFromWhenNotPresentReturnsNull() {\n\t\tassertThat(ContainerImageMetadata.getFrom(this.attributes)).isNull();\n\t}\n\n\t@Test\n\tvoid getFromWhenNullAttributesReturnsNull() {\n\t\tassertThat(ContainerImageMetadata.getFrom(null)).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.stereotype.Component;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationPropertiesAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid processAnnotatedBean() {\n\t\tload(new Class<?>[] { AutoConfig.class, SampleBean.class }, \"foo.name:test\");\n\t\tassertThat(getBean().getName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid processAnnotatedBeanNoAutoConfig() {\n\t\tload(new Class<?>[] { SampleBean.class }, \"foo.name:test\");\n\t\tassertThat(getBean().getName()).isEqualTo(\"default\");\n\t}\n\n\tprivate void load(Class<?>[] configs, String... environment) {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(configs);\n\t\tTestPropertyValues.of(environment).applyTo(this.context);\n\t\tthis.context.refresh();\n\t}\n\n\tprivate SampleBean getBean() {\n\t\tassertThat(this.context).isNotNull();\n\t\treturn this.context.getBean(SampleBean.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(ConfigurationPropertiesAutoConfiguration.class)\n\tstatic class AutoConfig {\n\n\t}\n\n\t@Component\n\t@ConfigurationProperties(\"foo\")\n\tstatic class SampleBean {\n\n\t\tprivate String name = \"default\";\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tvoid setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/LifecycleAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.DefaultLifecycleProcessor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LifecycleAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass LifecycleAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LifecycleAutoConfiguration.class));\n\n\t@Test\n\tvoid lifecycleProcessorIsConfiguredWithDefaultTimeout() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\tObject processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\tassertThat(processor).extracting(\"timeoutPerShutdownPhase\").isEqualTo(30000L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid lifecycleProcessorIsConfiguredWithCustomTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.lifecycle.timeout-per-shutdown-phase=15s\").run((context) -> {\n\t\t\tassertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\tObject processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\tassertThat(processor).extracting(\"timeoutPerShutdownPhase\").isEqualTo(15000L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid lifecycleProcessorIsConfiguredWithCustomTimeoutInAChildContext() {\n\t\tnew ApplicationContextRunner().run((parent) -> {\n\t\t\tthis.contextRunner.withParent(parent)\n\t\t\t\t.withPropertyValues(\"spring.lifecycle.timeout-per-shutdown-phase=15s\")\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tassertThat(child).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\t\t\tObject processor = child.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\t\t\tassertThat(processor).extracting(\"timeoutPerShutdownPhase\").isEqualTo(15000L);\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUserDefinesALifecycleProcessorBeanThenTheAutoConfigurationBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(LifecycleProcessorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\tObject processor = context.getBean(AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME);\n\t\t\tassertThat(processor).extracting(\"timeoutPerShutdownPhase\").isEqualTo(5000L);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LifecycleProcessorConfiguration {\n\n\t\t@Bean(name = AbstractApplicationContext.LIFECYCLE_PROCESSOR_BEAN_NAME)\n\t\tDefaultLifecycleProcessor customLifecycleProcessor() {\n\t\t\tDefaultLifecycleProcessor processor = new DefaultLifecycleProcessor();\n\t\t\tprocessor.setTimeoutPerShutdownPhase(5000);\n\t\t\treturn processor;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/MessageSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.MessageSourceRuntimeHints;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.MessageSource;\nimport org.springframework.context.MessageSourceResolvable;\nimport org.springframework.context.NoSuchMessageException;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MessageSourceAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Kedar Joshi\n * @author Marc Becker\n * @author Misagh Moayyed\n * @author Phillip Webb\n */\nclass MessageSourceAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MessageSourceAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultMessageSource() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK))\n\t\t\t.isEqualTo(\"Foo message\"));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid propertiesBundleWithSlashIsDetected() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/messages\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MessageSource.class);\n\t\t\tassertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK)).isEqualTo(\"bar\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid propertiesBundleWithDotIsDetected() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test.messages\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MessageSource.class);\n\t\t\tassertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK)).isEqualTo(\"bar\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithTestSwedishPropertiesResource\n\tvoid testEncodingWorks() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/swedish\")\n\t\t\t.run((context) -> assertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK))\n\t\t\t\t.isEqualTo(\"Some text with some swedish öäå!\"));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testCacheDurationNoUnit() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\", \"spring.messages.cache-duration=10\")\n\t\t\t.run(assertCache(10 * 1000));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testCacheDurationWithUnit() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\", \"spring.messages.cache-duration=1m\")\n\t\t\t.run(assertCache(60 * 1000));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertCache(long expected) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(MessageSource.class);\n\t\t\tassertThat(context.getBean(MessageSource.class)).hasFieldOrPropertyWithValue(\"cacheMillis\", expected);\n\t\t};\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\t@WithTestMessages2PropertiesResource\n\tvoid testMultipleMessageSourceCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/messages,test/messages2\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK)).isEqualTo(\"bar\");\n\t\t\t\tassertThat(context.getMessage(\"foo-foo\", null, \"Foo-Foo message\", Locale.UK)).isEqualTo(\"bar-bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\t@Disabled(\"Expected to fail per gh-1075\")\n\t@WithResource(name = \"application-switch-messages.properties\", content = \"spring.messages.basename:test/messages\")\n\tvoid testMessageSourceFromPropertySourceAnnotation() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class)\n\t\t\t.run((context) -> assertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK)).isEqualTo(\"bar\"));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\t@WithResource(name = \"test/common-messages.properties\", content = \"hello=world\")\n\tvoid testCommonMessages() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\",\n\t\t\t\t\t\"spring.messages.common-messages=classpath:test/common-messages.properties\")\n\t\t\t.run((context) -> assertThat(context.getMessage(\"hello\", null, \"Hello!\", Locale.UK)).isEqualTo(\"world\"));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testCommonMessagesWhenNotFound() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\",\n\t\t\t\t\t\"spring.messages.common-messages=classpath:test/common-messages.properties\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.hasMessageContaining(\n\t\t\t\t\t\t\"Failed to load common messages from 'class path resource [test/common-messages.properties]'\"));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testFallbackDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/messages\")\n\t\t\t.run((context) -> assertThat(context.getBean(MessageSource.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"fallbackToSystemLocale\", true));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testFallbackTurnOff() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\",\n\t\t\t\t\t\"spring.messages.fallback-to-system-locale:false\")\n\t\t\t.run((context) -> assertThat(context.getBean(MessageSource.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"fallbackToSystemLocale\", false));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testFormatMessageDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/messages\")\n\t\t\t.run((context) -> assertThat(context.getBean(MessageSource.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"alwaysUseMessageFormat\", false));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testFormatMessageOn() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\",\n\t\t\t\t\t\"spring.messages.always-use-message-format:true\")\n\t\t\t.run((context) -> assertThat(context.getBean(MessageSource.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"alwaysUseMessageFormat\", true));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testUseCodeAsDefaultMessageDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/messages\")\n\t\t\t.run((context) -> assertThat(context.getBean(MessageSource.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"useCodeAsDefaultMessage\", false));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid testUseCodeAsDefaultMessageOn() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\",\n\t\t\t\t\t\"spring.messages.use-code-as-default-message=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(MessageSource.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"useCodeAsDefaultMessage\", true));\n\t}\n\n\t@Test\n\tvoid existingMessageSourceIsPreferred() {\n\t\tthis.contextRunner.withUserConfiguration(CustomMessageSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getMessage(\"foo\", null, null, null)).isEqualTo(\"foo\"));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid existingMessageSourceInParentIsIgnored() {\n\t\tthis.contextRunner.run((parent) -> this.contextRunner.withParent(parent)\n\t\t\t.withPropertyValues(\"spring.messages.basename=test/messages\")\n\t\t\t.run((context) -> assertThat(context.getMessage(\"foo\", null, \"Foo message\", Locale.UK)).isEqualTo(\"bar\")));\n\t}\n\n\t@Test\n\t@WithTestMessagesPropertiesResource\n\tvoid messageSourceWithNonStandardBeanNameIsIgnored() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.messages.basename=test/messages\")\n\t\t\t.withUserConfiguration(CustomBeanNameMessageSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getMessage(\"foo\", null, Locale.US)).isEqualTo(\"bar\"));\n\t}\n\n\t@Test\n\tvoid shouldRegisterDefaultHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew MessageSourceRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"messages.properties\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"messages_de.properties\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"messages_zh-CN.properties\")).accepts(hints);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@PropertySource(\"classpath:/switch-messages.properties\")\n\tstatic class Config {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomMessageSourceConfiguration {\n\n\t\t@Bean\n\t\tMessageSource messageSource() {\n\t\t\treturn new TestMessageSource();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBeanNameMessageSourceConfiguration {\n\n\t\t@Bean\n\t\tMessageSource codeReturningMessageSource() {\n\t\t\treturn new TestMessageSource();\n\t\t}\n\n\t}\n\n\tstatic class TestMessageSource implements MessageSource {\n\n\t\t@Override\n\t\tpublic String getMessage(String code, Object @Nullable [] args, @Nullable String defaultMessage,\n\t\t\t\t@Nullable Locale locale) {\n\t\t\treturn code;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getMessage(String code, Object @Nullable [] args, @Nullable Locale locale) {\n\t\t\treturn code;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getMessage(MessageSourceResolvable resolvable, @Nullable Locale locale) {\n\t\t\tString[] codes = resolvable.getCodes();\n\t\t\tif (codes == null) {\n\t\t\t\tthrow new NoSuchMessageException(\"codes is null\");\n\t\t\t}\n\t\t\treturn codes[0];\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"test/messages.properties\", content = \"foo=bar\")\n\t@interface WithTestMessagesPropertiesResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"test/messages2.properties\", content = \"foo-foo=bar-bar\")\n\t@interface WithTestMessages2PropertiesResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"test/swedish.properties\", content = \"foo=Some text with some swedish öäå!\")\n\t@interface WithTestSwedishPropertiesResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/PropertyPlaceholderAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context;\n\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertyPlaceholderAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass PropertyPlaceholderAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid whenTheAutoConfigurationIsNotUsedThenBeanDefinitionPlaceholdersAreNotResolved() {\n\t\tthis.contextRunner.withPropertyValues(\"fruit:banana\")\n\t\t\t.withInitializer(this::definePlaceholderBean)\n\t\t\t.run((context) -> assertThat(context.getBean(PlaceholderBean.class).fruit).isEqualTo(\"${fruit:apple}\"));\n\t}\n\n\t@Test\n\tvoid whenTheAutoConfigurationIsUsedThenBeanDefinitionPlaceholdersAreResolved() {\n\t\tthis.contextRunner.withPropertyValues(\"fruit:banana\")\n\t\t\t.withInitializer(this::definePlaceholderBean)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(PlaceholderBean.class).fruit).isEqualTo(\"banana\"));\n\t}\n\n\t@Test\n\tvoid whenTheAutoConfigurationIsNotUsedThenValuePlaceholdersAreResolved() {\n\t\tthis.contextRunner.withPropertyValues(\"fruit:banana\")\n\t\t\t.withUserConfiguration(PlaceholderConfig.class)\n\t\t\t.run((context) -> assertThat(context.getBean(PlaceholderConfig.class).fruit).isEqualTo(\"banana\"));\n\t}\n\n\t@Test\n\tvoid whenTheAutoConfigurationIsUsedThenValuePlaceholdersAreResolved() {\n\t\tthis.contextRunner.withPropertyValues(\"fruit:banana\")\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class))\n\t\t\t.withUserConfiguration(PlaceholderConfig.class)\n\t\t\t.run((context) -> assertThat(context.getBean(PlaceholderConfig.class).fruit).isEqualTo(\"banana\"));\n\t}\n\n\t@Test\n\tvoid whenThereIsAUserDefinedPropertySourcesPlaceholderConfigurerThenItIsUsedForBeanDefinitionPlaceholderResolution() {\n\t\tthis.contextRunner.withPropertyValues(\"fruit:banana\")\n\t\t\t.withInitializer(this::definePlaceholderBean)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class))\n\t\t\t.withUserConfiguration(PlaceholdersOverride.class)\n\t\t\t.run((context) -> assertThat(context.getBean(PlaceholderBean.class).fruit).isEqualTo(\"orange\"));\n\t}\n\n\t@Test\n\tvoid whenThereIsAUserDefinedPropertySourcesPlaceholderConfigurerThenItIsUsedForValuePlaceholderResolution() {\n\t\tthis.contextRunner.withPropertyValues(\"fruit:banana\")\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class))\n\t\t\t.withUserConfiguration(PlaceholderConfig.class, PlaceholdersOverride.class)\n\t\t\t.run((context) -> assertThat(context.getBean(PlaceholderConfig.class).fruit).isEqualTo(\"orange\"));\n\t}\n\n\tprivate void definePlaceholderBean(ConfigurableApplicationContext context) {\n\t\t((BeanDefinitionRegistry) context.getBeanFactory()).registerBeanDefinition(\"placeholderBean\",\n\t\t\t\tBeanDefinitionBuilder.rootBeanDefinition(PlaceholderBean.class)\n\t\t\t\t\t.addConstructorArgValue(\"${fruit:apple}\")\n\t\t\t\t\t.getBeanDefinition());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PlaceholderConfig {\n\n\t\t@Value(\"${fruit:apple}\")\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String fruit;\n\n\t}\n\n\tstatic class PlaceholderBean {\n\n\t\tprivate final String fruit;\n\n\t\tPlaceholderBean(String fruit) {\n\t\t\tthis.fruit = fruit;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PlaceholdersOverride {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer morePlaceholders() {\n\t\t\tPropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();\n\t\t\tProperties properties = StringUtils.splitArrayElementsIntoProperties(new String[] { \"fruit=orange\" }, \"=\");\n\t\t\tassertThat(properties).isNotNull();\n\t\t\tconfigurer.setProperties(properties);\n\t\t\tconfigurer.setLocalOverride(true);\n\t\t\tconfigurer.setOrder(0);\n\t\t\treturn configurer;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/filtersample/ExampleConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context.filtersample;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class ExampleConfiguration {\n\n\t@Bean\n\tpublic String example() {\n\t\treturn \"test\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/filtersample/ExampleFilteredAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.context.filtersample;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n@AutoConfiguration\npublic final class ExampleFilteredAutoConfiguration {\n\n\t@Bean\n\tString anotherExample() {\n\t\treturn \"fail\";\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/filtersample/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.context.filtersample;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryTypeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.data;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnRepositoryType @ConditionalOnRepositoryType}.\n *\n * @author Andy Wilkinson\n */\nclass ConditionalOnRepositoryTypeTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid imperativeRepositoryMatchesWithNoConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ImperativeRepository.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ImperativeRepository.class));\n\t}\n\n\t@Test\n\tvoid reactiveRepositoryMatchesWithNoConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveRepository.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveRepository.class));\n\t}\n\n\t@Test\n\tvoid imperativeRepositoryMatchesWithAutoConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ImperativeRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:auto\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ImperativeRepository.class));\n\t}\n\n\t@Test\n\tvoid reactiveRepositoryMatchesWithAutoConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:auto\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveRepository.class));\n\t}\n\n\t@Test\n\tvoid imperativeRepositoryMatchesWithImperativeConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ImperativeRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:imperative\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ImperativeRepository.class));\n\t}\n\n\t@Test\n\tvoid reactiveRepositoryMatchesWithReactiveConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:reactive\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveRepository.class));\n\t}\n\n\t@Test\n\tvoid imperativeRepositoryDoesNotMatchWithReactiveConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ImperativeRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:reactive\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ImperativeRepository.class));\n\t}\n\n\t@Test\n\tvoid reactiveRepositoryDoesNotMatchWithImperativeConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:imperative\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveRepository.class));\n\t}\n\n\t@Test\n\tvoid imperativeRepositoryDoesNotMatchWithNoneConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ImperativeRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ImperativeRepository.class));\n\t}\n\n\t@Test\n\tvoid reactiveRepositoryDoesNotMatchWithNoneConfiguredType() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveRepository.class));\n\t}\n\n\t@Test\n\tvoid failsFastWhenConfiguredTypeIsUnknown() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveRepository.class)\n\t\t\t.withPropertyValues(\"spring.data.test.repositories.type:abcde\")\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnRepositoryType(store = \"test\", type = RepositoryType.IMPERATIVE)\n\tstatic class ImperativeRepository {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnRepositoryType(store = \"test\", type = RepositoryType.REACTIVE)\n\tstatic class ReactiveRepository {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/diagnostics/analyzer/NoSuchBeanDefinitionFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.diagnostics.analyzer;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.FatalBeanException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoUniqueBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoSuchBeanDefinitionFailureAnalyzer}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass NoSuchBeanDefinitionFailureAnalyzerTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\tprivate final NoSuchBeanDefinitionFailureAnalyzer analyzer = new NoSuchBeanDefinitionFailureAnalyzer(\n\t\t\tthis.context.getBeanFactory());\n\n\t@Test\n\tvoid failureAnalysisForMultipleBeans() {\n\t\tFailureAnalysis analysis = analyzeFailure(new NoUniqueBeanDefinitionException(String.class, 2, \"Test\"));\n\t\tassertThat(analysis).isNull();\n\t}\n\n\t@Test\n\tvoid failureAnalysisForNoMatchType() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(StringHandler.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);\n\t\tassertThat(analysis.getDescription())\n\t\t\t.doesNotContain(\"No matching auto-configuration has been found for this type.\");\n\t\tassertThat(analysis.getAction()).startsWith(\n\t\t\t\tString.format(\"Consider defining a bean of type '%s' in your configuration.\", String.class.getName()));\n\t}\n\n\t@Test\n\tvoid failureAnalysisForMissingPropertyExactType() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(StringPropertyTypeConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);\n\t\tassertBeanMethodDisabled(analysis, \"did not find property 'spring.string.enabled'\",\n\t\t\t\tTestPropertyAutoConfiguration.class, \"string\");\n\t\tassertActionMissingType(analysis, String.class);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForMissingPropertySubType() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(IntegerPropertyTypeConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, NumberHandler.class, 0, Number.class);\n\t\tassertBeanMethodDisabled(analysis, \"did not find property 'spring.integer.enabled'\",\n\t\t\t\tTestPropertyAutoConfiguration.class, \"integer\");\n\t\tassertActionMissingType(analysis, Number.class);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForMissingClassOnAutoConfigurationType() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(MissingClassOnAutoConfigurationConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);\n\t\tassertClassDisabled(analysis, \"did not find required class 'com.example.FooBar'\", \"string\",\n\t\t\t\tClassUtils.getShortName(TestTypeClassAutoConfiguration.class));\n\t\tassertActionMissingType(analysis, String.class);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForExcludedAutoConfigurationType() {\n\t\tFatalBeanException failure = createFailure(StringHandler.class);\n\t\taddExclusions(this.analyzer, TestPropertyAutoConfiguration.class);\n\t\tFailureAnalysis analysis = analyzeFailure(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);\n\t\tString configClass = ClassUtils.getShortName(TestPropertyAutoConfiguration.class.getName());\n\t\tassertClassDisabled(analysis, String.format(\"auto-configuration '%s' was excluded\", configClass), \"string\",\n\t\t\t\tClassUtils.getShortName(TestPropertyAutoConfiguration.class));\n\t\tassertActionMissingType(analysis, String.class);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForSeveralConditionsType() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(SeveralAutoConfigurationTypeConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);\n\t\tassertBeanMethodDisabled(analysis, \"did not find property 'spring.string.enabled'\",\n\t\t\t\tTestPropertyAutoConfiguration.class, \"string\");\n\t\tassertClassDisabled(analysis, \"did not find required class 'com.example.FooBar'\", \"string\",\n\t\t\t\tClassUtils.getShortName(TestPropertyAutoConfiguration.class));\n\t\tassertActionMissingType(analysis, String.class);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForNoMatchName() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(StringNameHandler.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.startsWith(String.format(\"Constructor in %s required a bean named '%s' that could not be found\",\n\t\t\t\t\tStringNameHandler.class.getName(), \"test-string\"));\n\t\tassertThat(analysis.getAction())\n\t\t\t.startsWith(String.format(\"Consider defining a bean named '%s' in your configuration.\", \"test-string\"));\n\t}\n\n\t@Test\n\tvoid failureAnalysisForMissingBeanName() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(StringMissingBeanNameConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.startsWith(String.format(\"Constructor in %s required a bean named '%s' that could not be found\",\n\t\t\t\t\tStringNameHandler.class.getName(), \"test-string\"));\n\t\tassertBeanMethodDisabled(analysis,\n\t\t\t\t\"@ConditionalOnBean (types: java.lang.Integer; SearchStrategy: all) did not find any beans\",\n\t\t\t\tTestMissingBeanAutoConfiguration.class, \"string\");\n\t\tassertActionMissingName(analysis, \"test-string\");\n\t}\n\n\t@Test\n\tvoid failureAnalysisForNullBeanByType() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(StringNullBeanConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertDescriptionConstructorMissingType(analysis, StringHandler.class, 0, String.class);\n\t\tassertUserDefinedBean(analysis, \"as the bean value is null\", TestNullBeanConfiguration.class, \"string\");\n\t\tassertActionMissingType(analysis, String.class);\n\t}\n\n\t@Test\n\tvoid failureAnalysisForUnmatchedQualifier() {\n\t\tFailureAnalysis analysis = analyzeFailure(createFailure(QualifiedBeanConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.containsPattern(\"@org.springframework.beans.factory.annotation.Qualifier\\\\(\\\"*alpha\\\"*\\\\)\");\n\t}\n\n\tprivate void assertDescriptionConstructorMissingType(FailureAnalysis analysis, Class<?> component, int index,\n\t\t\tClass<?> type) {\n\t\tString expected = String.format(\n\t\t\t\t\"Parameter %s of constructor in %s required a bean of type '%s' that could not be found.\", index,\n\t\t\t\tcomponent.getName(), type.getName());\n\t\tassertThat(analysis.getDescription()).startsWith(expected);\n\t}\n\n\tprivate void assertActionMissingType(FailureAnalysis analysis, Class<?> type) {\n\t\tassertThat(analysis.getAction()).startsWith(String.format(\n\t\t\t\t\"Consider revisiting the entries above or defining a bean of type '%s' in your configuration.\",\n\t\t\t\ttype.getName()));\n\t\tassertThat(analysis.getAction()).doesNotContain(\"@ConstructorBinding\");\n\t}\n\n\tprivate void assertActionMissingName(FailureAnalysis analysis, String name) {\n\t\tassertThat(analysis.getAction()).startsWith(String.format(\n\t\t\t\t\"Consider revisiting the entries above or defining a bean named '%s' in your configuration.\", name));\n\t}\n\n\tprivate void assertBeanMethodDisabled(FailureAnalysis analysis, String description, Class<?> target,\n\t\t\tString methodName) {\n\t\tString expected = String.format(\"Bean method '%s' in '%s' not loaded because\", methodName,\n\t\t\t\tClassUtils.getShortName(target));\n\t\tassertThat(analysis.getDescription()).contains(expected);\n\t\tassertThat(analysis.getDescription()).contains(description);\n\t}\n\n\tprivate void assertClassDisabled(FailureAnalysis analysis, String description, String methodName,\n\t\t\tString className) {\n\t\tString expected = String.format(\"Bean method '%s' in '%s' not loaded because\", methodName, className);\n\t\tassertThat(analysis.getDescription()).contains(expected);\n\t\tassertThat(analysis.getDescription()).contains(description);\n\t}\n\n\tprivate void assertUserDefinedBean(FailureAnalysis analysis, String description, Class<?> target,\n\t\t\tString methodName) {\n\t\tString expected = String.format(\"User-defined bean method '%s' in '%s' ignored\", methodName,\n\t\t\t\tClassUtils.getShortName(target));\n\t\tassertThat(analysis.getDescription()).contains(expected);\n\t\tassertThat(analysis.getDescription()).contains(description);\n\t}\n\n\tprivate static void addExclusions(NoSuchBeanDefinitionFailureAnalyzer analyzer, Class<?>... classes) {\n\t\tConditionEvaluationReport report = (ConditionEvaluationReport) ReflectionTestUtils.getField(analyzer, \"report\");\n\t\tassertThat(report).isNotNull();\n\t\tList<String> exclusions = new ArrayList<>(report.getExclusions());\n\t\tfor (Class<?> c : classes) {\n\t\t\texclusions.add(c.getName());\n\t\t}\n\t\treport.recordExclusions(exclusions);\n\t}\n\n\tprivate FatalBeanException createFailure(Class<?> config, String... environment) {\n\t\ttry {\n\t\t\tTestPropertyValues.of(environment).applyTo(this.context);\n\t\t\tthis.context.register(config);\n\t\t\tthis.context.refresh();\n\t\t\tthrow new IllegalStateException(\"This should not be reached\");\n\t\t}\n\t\tcatch (FatalBeanException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\tprivate @Nullable FailureAnalysis analyzeFailure(Exception failure) {\n\t\tFailureAnalysis analysis = this.analyzer.analyze(failure);\n\t\tif (analysis != null) {\n\t\t\tnew LoggingFailureAnalysisReporter().report(analysis);\n\t\t}\n\t\treturn analysis;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(TestPropertyAutoConfiguration.class)\n\t@Import(StringHandler.class)\n\tstatic class StringPropertyTypeConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(TestPropertyAutoConfiguration.class)\n\t@Import(NumberHandler.class)\n\tstatic class IntegerPropertyTypeConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(TestTypeClassAutoConfiguration.class)\n\t@Import(StringHandler.class)\n\tstatic class MissingClassOnAutoConfigurationConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ TestPropertyAutoConfiguration.class, TestTypeClassAutoConfiguration.class })\n\t@Import(StringHandler.class)\n\tstatic class SeveralAutoConfigurationTypeConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(TestMissingBeanAutoConfiguration.class)\n\t@Import(StringNameHandler.class)\n\tstatic class StringMissingBeanNameConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(TestNullBeanConfiguration.class)\n\t@Import(StringHandler.class)\n\tstatic class StringNullBeanConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestPropertyAutoConfiguration {\n\n\t\t@ConditionalOnProperty(\"spring.string.enabled\")\n\t\t@Bean\n\t\tString string() {\n\t\t\treturn \"Test\";\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.integer.enabled\")\n\t\t@Bean\n\t\tInteger integer() {\n\t\t\treturn 42;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = \"com.example.FooBar\")\n\tstatic class TestTypeClassAutoConfiguration {\n\n\t\t@Bean\n\t\tString string() {\n\t\t\treturn \"Test\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestMissingBeanAutoConfiguration {\n\n\t\t@ConditionalOnBean(Integer.class)\n\t\t@Bean(name = \"test-string\")\n\t\tString string() {\n\t\t\treturn \"Test\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestNullBeanConfiguration {\n\n\t\t@Bean\n\t\t@Nullable String string() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class QualifiedBeanConfiguration {\n\n\t\t@Bean\n\t\tString consumer(@Qualifier(\"alpha\") Thing thing) {\n\t\t\treturn \"consumer\";\n\t\t}\n\n\t\t@Bean\n\t\tThing producer() {\n\t\t\treturn new Thing();\n\t\t}\n\n\t\tclass Thing {\n\n\t\t}\n\n\t}\n\n\tstatic class StringHandler {\n\n\t\tStringHandler(String foo) {\n\t\t}\n\n\t}\n\n\tstatic class NumberHandler {\n\n\t\tNumberHandler(Number foo) {\n\t\t}\n\n\t}\n\n\tstatic class StringNameHandler {\n\n\t\tStringNameHandler(BeanFactory beanFactory) {\n\t\t\tbeanFactory.getBean(\"test-string\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/info/ProjectInfoAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.info;\n\nimport java.time.Instant;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.info.BuildProperties;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ProjectInfoAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass ProjectInfoAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, ProjectInfoAutoConfiguration.class));\n\n\t@Test\n\tvoid gitPropertiesUnavailableIfResourceNotAvailable() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBeansOfType(GitProperties.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid gitPropertiesWithNoData() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.info.git.location=\"\n\t\t\t\t\t+ \"classpath:/org/springframework/boot/autoconfigure/info/git-no-data.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tGitProperties gitProperties = context.getBean(GitProperties.class);\n\t\t\t\tassertThat(gitProperties.getBranch()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid gitPropertiesFallbackWithGitPropertiesBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomInfoPropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.info.git.location=classpath:/org/springframework/boot/autoconfigure/info/git.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tGitProperties gitProperties = context.getBean(GitProperties.class);\n\t\t\t\tassertThat(gitProperties).isSameAs(context.getBean(\"customGitProperties\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid gitPropertiesUsesUtf8ByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.info.git.location=classpath:/org/springframework/boot/autoconfigure/info/git.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tGitProperties gitProperties = context.getBean(GitProperties.class);\n\t\t\t\tassertThat(gitProperties.get(\"commit.charset\")).isEqualTo(\"test™\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid gitPropertiesEncodingCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.info.git.encoding=US-ASCII\",\n\t\t\t\t\t\"spring.info.git.location=classpath:/org/springframework/boot/autoconfigure/info/git.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tGitProperties gitProperties = context.getBean(GitProperties.class);\n\t\t\t\tassertThat(gitProperties.get(\"commit.charset\")).isNotEqualTo(\"test™\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/build-info.properties\", content = \"\"\"\n\t\t\tbuild.group=com.example\n\t\t\tbuild.artifact=demo\n\t\t\tbuild.name=Demo Project\n\t\t\tbuild.version=0.0.1-SNAPSHOT\n\t\t\tbuild.time=2016-03-04T14:16:05.000Z\n\t\t\t\"\"\")\n\tvoid buildPropertiesDefaultLocation() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tBuildProperties buildProperties = context.getBean(BuildProperties.class);\n\t\t\tassertThat(buildProperties.getGroup()).isEqualTo(\"com.example\");\n\t\t\tassertThat(buildProperties.getArtifact()).isEqualTo(\"demo\");\n\t\t\tassertThat(buildProperties.getName()).isEqualTo(\"Demo Project\");\n\t\t\tassertThat(buildProperties.getVersion()).isEqualTo(\"0.0.1-SNAPSHOT\");\n\t\t\tInstant time = buildProperties.getTime();\n\t\t\tassertThat(time).isNotNull();\n\t\t\tassertThat(time.toEpochMilli()).isEqualTo(1457100965000L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid buildPropertiesCustomLocation() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.info.build.location=\"\n\t\t\t\t\t+ \"classpath:/org/springframework/boot/autoconfigure/info/build-info.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tBuildProperties buildProperties = context.getBean(BuildProperties.class);\n\t\t\t\tassertThat(buildProperties.getGroup()).isEqualTo(\"com.example.acme\");\n\t\t\t\tassertThat(buildProperties.getArtifact()).isEqualTo(\"acme\");\n\t\t\t\tassertThat(buildProperties.getName()).isEqualTo(\"acme\");\n\t\t\t\tassertThat(buildProperties.getVersion()).isEqualTo(\"1.0.1-SNAPSHOT\");\n\t\t\t\tInstant time = buildProperties.getTime();\n\t\t\t\tassertThat(time).isNotNull();\n\t\t\t\tassertThat(time.toEpochMilli()).isEqualTo(1457088120000L);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid buildPropertiesCustomInvalidLocation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.info.build.location=classpath:/org/acme/no-build-info.properties\")\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(BuildProperties.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid buildPropertiesFallbackWithBuildInfoBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomInfoPropertiesConfiguration.class).run((context) -> {\n\t\t\tBuildProperties buildProperties = context.getBean(BuildProperties.class);\n\t\t\tassertThat(buildProperties).isSameAs(context.getBean(\"customBuildProperties\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid buildPropertiesUsesUtf8ByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.info.build.location=classpath:/org/springframework/boot/autoconfigure/info/build-info.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tBuildProperties buildProperties = context.getBean(BuildProperties.class);\n\t\t\t\tassertThat(buildProperties.get(\"charset\")).isEqualTo(\"test™\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid buildPropertiesEncodingCanBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.info.build.encoding=US-ASCII\",\n\t\t\t\t\"spring.info.build.location=classpath:/org/springframework/boot/autoconfigure/info/build-info.properties\")\n\t\t\t.run((context) -> {\n\t\t\t\tBuildProperties buildProperties = context.getBean(BuildProperties.class);\n\t\t\t\tassertThat(buildProperties.get(\"charset\")).isNotEqualTo(\"test™\");\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomInfoPropertiesConfiguration {\n\n\t\t@Bean\n\t\tGitProperties customGitProperties() {\n\t\t\treturn new GitProperties(new Properties());\n\t\t}\n\n\t\t@Bean\n\t\tBuildProperties customBuildProperties() {\n\t\t\treturn new BuildProperties(new Properties());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jmx;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.annotation.UserConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jmx.export.MBeanExporter;\nimport org.springframework.jmx.export.annotation.ManagedAttribute;\nimport org.springframework.jmx.export.annotation.ManagedOperation;\nimport org.springframework.jmx.export.annotation.ManagedResource;\nimport org.springframework.jmx.export.naming.MetadataNamingStrategy;\nimport org.springframework.jmx.export.naming.ObjectNamingStrategy;\nimport org.springframework.jmx.support.RegistrationPolicy;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JmxAutoConfiguration}.\n *\n * @author Christian Dupuis\n * @author Artsiom Yudovin\n * @author Scott Frederick\n */\nclass JmxAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultMBeanExport() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(MBeanExporter.class);\n\t\t\tassertThat(context).doesNotHaveBean(ObjectNamingStrategy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDisabledMBeanExport() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jmx.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(MBeanExporter.class);\n\t\t\tassertThat(context).doesNotHaveBean(ObjectNamingStrategy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testEnabledMBeanExport() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jmx.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MBeanExporter.class);\n\t\t\tassertThat(context).hasSingleBean(ParentAwareNamingStrategy.class);\n\t\t\tMBeanExporter exporter = context.getBean(MBeanExporter.class);\n\t\t\tassertThat(exporter).hasFieldOrPropertyWithValue(\"ensureUniqueRuntimeObjectNames\", false);\n\t\t\tassertThat(exporter).hasFieldOrPropertyWithValue(\"registrationPolicy\", RegistrationPolicy.FAIL_ON_EXISTING);\n\n\t\t\tMetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(exporter,\n\t\t\t\t\t\"namingStrategy\");\n\t\t\tassertThat(naming).hasFieldOrPropertyWithValue(\"ensureUniqueRuntimeObjectNames\", false);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultDomainConfiguredOnMBeanExport() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.jmx.default-domain=my-test-domain\",\n\t\t\t\t\t\"spring.jmx.unique-names=true\", \"spring.jmx.registration-policy=IGNORE_EXISTING\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(MBeanExporter.class);\n\t\t\t\tMBeanExporter exporter = context.getBean(MBeanExporter.class);\n\t\t\t\tassertThat(exporter).hasFieldOrPropertyWithValue(\"ensureUniqueRuntimeObjectNames\", true);\n\t\t\t\tassertThat(exporter).hasFieldOrPropertyWithValue(\"registrationPolicy\",\n\t\t\t\t\t\tRegistrationPolicy.IGNORE_EXISTING);\n\n\t\t\t\tMetadataNamingStrategy naming = (MetadataNamingStrategy) ReflectionTestUtils.getField(exporter,\n\t\t\t\t\t\t\"namingStrategy\");\n\t\t\t\tassertThat(naming).hasFieldOrPropertyWithValue(\"defaultDomain\", \"my-test-domain\");\n\t\t\t\tassertThat(naming).hasFieldOrPropertyWithValue(\"ensureUniqueRuntimeObjectNames\", true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testBasicParentContext() {\n\t\ttry (AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext()) {\n\t\t\tparent.register(JmxAutoConfiguration.class);\n\t\t\tparent.refresh();\n\t\t\tthis.contextRunner.withParent(parent).run((context) -> assertThat(context.isRunning()));\n\t\t}\n\t}\n\n\t@Test\n\tvoid testParentContext() {\n\t\ttry (AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext()) {\n\t\t\tparent.register(JmxAutoConfiguration.class, TestConfiguration.class);\n\t\t\tparent.refresh();\n\t\t\tthis.contextRunner.withParent(parent)\n\t\t\t\t.withConfiguration(UserConfigurations.of(TestConfiguration.class))\n\t\t\t\t.run((context) -> assertThat(context.isRunning()));\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tCounter counter() {\n\t\t\treturn new Counter();\n\t\t}\n\n\t}\n\n\t@ManagedResource\n\tpublic static class Counter {\n\n\t\tprivate int counter;\n\n\t\t@ManagedAttribute\n\t\tpublic int get() {\n\t\t\treturn this.counter;\n\t\t}\n\n\t\t@ManagedOperation\n\t\tpublic void increment() {\n\t\t\tthis.counter++;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jmx/ParentAwareNamingStrategyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jmx;\n\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;\nimport org.springframework.jmx.export.annotation.ManagedResource;\nimport org.springframework.util.ObjectUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ParentAwareNamingStrategy}.\n *\n * @author Andy Wilkinson\n */\nclass ParentAwareNamingStrategyTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid objectNameMatchesManagedResourceByDefault() {\n\t\tthis.contextRunner.withBean(\"testManagedResource\", TestManagedResource.class).run((context) -> {\n\t\t\tParentAwareNamingStrategy strategy = new ParentAwareNamingStrategy(new AnnotationJmxAttributeSource());\n\t\t\tstrategy.setApplicationContext(context);\n\t\t\tassertThat(strategy.getObjectName(context.getBean(\"testManagedResource\"), \"testManagedResource\")\n\t\t\t\t.getKeyPropertyListString()).isEqualTo(\"type=something,name1=def,name2=ghi\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid uniqueObjectNameAddsIdentityProperty() {\n\t\tthis.contextRunner.withBean(\"testManagedResource\", TestManagedResource.class).run((context) -> {\n\t\t\tParentAwareNamingStrategy strategy = new ParentAwareNamingStrategy(new AnnotationJmxAttributeSource());\n\t\t\tstrategy.setApplicationContext(context);\n\t\t\tstrategy.setEnsureUniqueRuntimeObjectNames(true);\n\t\t\tObject resource = context.getBean(\"testManagedResource\");\n\t\t\tObjectName objectName = strategy.getObjectName(resource, \"testManagedResource\");\n\t\t\tassertThat(objectName.getDomain()).isEqualTo(\"ABC\");\n\t\t\tassertThat(objectName.getCanonicalKeyPropertyListString()).isEqualTo(\n\t\t\t\t\t\"identity=\" + ObjectUtils.getIdentityHexString(resource) + \",name1=def,name2=ghi,type=something\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid sameBeanInParentContextAddsContextProperty() {\n\t\tthis.contextRunner.withBean(\"testManagedResource\", TestManagedResource.class)\n\t\t\t.run((parent) -> this.contextRunner.withBean(\"testManagedResource\", TestManagedResource.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tParentAwareNamingStrategy strategy = new ParentAwareNamingStrategy(\n\t\t\t\t\t\t\tnew AnnotationJmxAttributeSource());\n\t\t\t\t\tstrategy.setApplicationContext(context);\n\t\t\t\t\tObject resource = context.getBean(\"testManagedResource\");\n\t\t\t\t\tObjectName objectName = strategy.getObjectName(resource, \"testManagedResource\");\n\t\t\t\t\tassertThat(objectName.getDomain()).isEqualTo(\"ABC\");\n\t\t\t\t\tassertThat(objectName.getCanonicalKeyPropertyListString()).isEqualTo(\"context=\"\n\t\t\t\t\t\t\t+ ObjectUtils.getIdentityHexString(context) + \",name1=def,name2=ghi,type=something\");\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid uniqueObjectNameAndSameBeanInParentContextOnlyAddsIdentityProperty() {\n\t\tthis.contextRunner.withBean(\"testManagedResource\", TestManagedResource.class)\n\t\t\t.run((parent) -> this.contextRunner.withBean(\"testManagedResource\", TestManagedResource.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tParentAwareNamingStrategy strategy = new ParentAwareNamingStrategy(\n\t\t\t\t\t\t\tnew AnnotationJmxAttributeSource());\n\t\t\t\t\tstrategy.setApplicationContext(context);\n\t\t\t\t\tstrategy.setEnsureUniqueRuntimeObjectNames(true);\n\t\t\t\t\tObject resource = context.getBean(\"testManagedResource\");\n\t\t\t\t\tObjectName objectName = strategy.getObjectName(resource, \"testManagedResource\");\n\t\t\t\t\tassertThat(objectName.getDomain()).isEqualTo(\"ABC\");\n\t\t\t\t\tassertThat(objectName.getCanonicalKeyPropertyListString()).isEqualTo(\"identity=\"\n\t\t\t\t\t\t\t+ ObjectUtils.getIdentityHexString(resource) + \",name1=def,name2=ghi,type=something\");\n\t\t\t\t}));\n\t}\n\n\t@ManagedResource(objectName = \"ABC:type=something,name1=def,name2=ghi\")\n\tpublic static class TestManagedResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLoggerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport java.time.Duration;\nimport java.util.Arrays;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\nimport ch.qos.logback.classic.LoggerContext;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ConditionEvaluationReportLogger}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ConditionEvaluationReportLoggerTests {\n\n\t@Test\n\tvoid noErrorIfNotInitialized(CapturedOutput output) {\n\t\tnew ConditionEvaluationReportLogger(LogLevel.INFO, () -> null).logReport(true);\n\t\tassertThat(output).contains(\"Unable to provide the condition evaluation report\");\n\t}\n\n\t@Test\n\tvoid supportsOnlyInfoAndDebugLogLevels() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ConditionEvaluationReportLogger(LogLevel.TRACE, () -> null))\n\t\t\t.withMessageContaining(\"'logLevel' must be INFO or DEBUG\");\n\t}\n\n\t@Test\n\tvoid loggerWithInfoLevelShouldLogAtInfo(CapturedOutput output) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tConditionEvaluationReportLogger logger = new ConditionEvaluationReportLogger(LogLevel.INFO,\n\t\t\t\t\t() -> ConditionEvaluationReport.get(context.getBeanFactory()));\n\t\t\tcontext.register(Config.class);\n\t\t\tcontext.refresh();\n\t\t\tlogger.logReport(false);\n\t\t\tassertThat(output).contains(\"CONDITIONS EVALUATION REPORT\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid loggerWithDebugLevelShouldLogAtDebug(CapturedOutput output) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tConditionEvaluationReportLogger logger = new ConditionEvaluationReportLogger(LogLevel.DEBUG,\n\t\t\t\t\t() -> ConditionEvaluationReport.get(context.getBeanFactory()));\n\t\t\tcontext.register(Config.class);\n\t\t\tcontext.refresh();\n\t\t\tlogger.logReport(false);\n\t\t\tassertThat(output).doesNotContain(\"CONDITIONS EVALUATION REPORT\");\n\t\t\twithDebugLogging(() -> logger.logReport(false));\n\t\t\tassertThat(output).contains(\"CONDITIONS EVALUATION REPORT\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid logsInfoOnErrorIfDebugDisabled(CapturedOutput output) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tConditionEvaluationReportLogger logger = new ConditionEvaluationReportLogger(LogLevel.DEBUG,\n\t\t\t\t\t() -> ConditionEvaluationReport.get(context.getBeanFactory()));\n\t\t\tcontext.register(Config.class);\n\t\t\tcontext.refresh();\n\t\t\tlogger.logReport(true);\n\t\t\tassertThat(output).contains(\"Error starting ApplicationContext. To display the condition \"\n\t\t\t\t\t+ \"evaluation report re-run your application with 'debug' enabled.\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid logsOutput(CapturedOutput output) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tConditionEvaluationReportLogger logger = new ConditionEvaluationReportLogger(LogLevel.DEBUG,\n\t\t\t\t\t() -> ConditionEvaluationReport.get(context.getBeanFactory()));\n\t\t\tcontext.register(Config.class);\n\t\t\tConditionEvaluationReport.get(context.getBeanFactory()).recordExclusions(Arrays.asList(\"com.foo.Bar\"));\n\t\t\tcontext.refresh();\n\t\t\twithDebugLogging(() -> logger.logReport(false));\n\t\t\tassertThat(output).contains(\"did not find any beans of type java.time.Duration (OnBeanCondition)\")\n\t\t\t\t.contains(\"@ConditionalOnProperty (com.example.property) matched (OnPropertyCondition)\");\n\t\t}\n\t}\n\n\tprivate void withDebugLogging(Runnable runnable) {\n\t\tLogger logger = ((LoggerContext) LoggerFactory.getILoggerFactory())\n\t\t\t.getLogger(ConditionEvaluationReportLogger.class);\n\t\tLevel currentLevel = logger.getLevel();\n\t\tlogger.setLevel(Level.DEBUG);\n\t\ttry {\n\t\t\trunnable.run();\n\t\t}\n\t\tfinally {\n\t\t\tlogger.setLevel(currentLevel);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ MatchingAutoConfiguration.class, NonMatchingAutoConfiguration.class })\n\tstatic class Config {\n\n\t}\n\n\t@AutoConfiguration\n\t@ConditionalOnProperty(name = \"com.example.property\", matchIfMissing = true)\n\tpublic static final class MatchingAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\t@ConditionalOnBean(Duration.class)\n\tpublic static final class NonMatchingAutoConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLoggingListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport java.time.Duration;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\nimport ch.qos.logback.classic.LoggerContext;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.web.MockServletContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Tests for {@link ConditionEvaluationReportLoggingListener}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ConditionEvaluationReportLoggingListenerTests {\n\n\tprivate final ConditionEvaluationReportLoggingListener initializer = new ConditionEvaluationReportLoggingListener();\n\n\t@Test\n\tvoid logsDebugOnContextRefresh(CapturedOutput output) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tthis.initializer.initialize(context);\n\t\tcontext.register(Config.class);\n\t\twithDebugLogging(context::refresh);\n\t\tassertThat(output).contains(\"CONDITIONS EVALUATION REPORT\");\n\t}\n\n\t@Test\n\tvoid logsDebugOnApplicationFailedEvent(CapturedOutput output) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tthis.initializer.initialize(context);\n\t\tcontext.register(ErrorConfig.class);\n\t\tassertThatException().isThrownBy(context::refresh)\n\t\t\t.satisfies((ex) -> withDebugLogging(() -> context\n\t\t\t\t.publishEvent(new ApplicationFailedEvent(new SpringApplication(), new String[0], context, ex))));\n\t\tassertThat(output).contains(\"CONDITIONS EVALUATION REPORT\");\n\t}\n\n\t@Test\n\tvoid logsInfoGuidanceToEnableDebugLoggingOnApplicationFailedEvent(CapturedOutput output) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tthis.initializer.initialize(context);\n\t\tcontext.register(ErrorConfig.class);\n\t\tassertThatException().isThrownBy(context::refresh)\n\t\t\t.satisfies((ex) -> withInfoLogging(() -> context\n\t\t\t\t.publishEvent(new ApplicationFailedEvent(new SpringApplication(), new String[0], context, ex))));\n\t\tassertThat(output).doesNotContain(\"CONDITIONS EVALUATION REPORT\")\n\t\t\t.contains(\"re-run your application with 'debug' enabled\");\n\t}\n\n\t@Test\n\tvoid canBeUsedInApplicationContext() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(Config.class);\n\t\tnew ConditionEvaluationReportLoggingListener().initialize(context);\n\t\tcontext.refresh();\n\t\tassertThat(context.getBean(ConditionEvaluationReport.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid canBeUsedInNonGenericApplicationContext() {\n\t\tAnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\t\tcontext.setServletContext(new MockServletContext());\n\t\tcontext.register(Config.class);\n\t\tnew ConditionEvaluationReportLoggingListener().initialize(context);\n\t\tcontext.refresh();\n\t\tassertThat(context.getBean(ConditionEvaluationReport.class)).isNotNull();\n\t}\n\n\tprivate void withDebugLogging(Runnable runnable) {\n\t\twithLoggingLevel(Level.DEBUG, runnable);\n\t}\n\n\tprivate void withInfoLogging(Runnable runnable) {\n\t\twithLoggingLevel(Level.INFO, runnable);\n\t}\n\n\tprivate void withLoggingLevel(Level logLevel, Runnable runnable) {\n\t\tLogger logger = ((LoggerContext) LoggerFactory.getILoggerFactory())\n\t\t\t.getLogger(ConditionEvaluationReportLogger.class);\n\t\tLevel currentLevel = logger.getLevel();\n\t\tlogger.setLevel(logLevel);\n\t\ttry {\n\t\t\trunnable.run();\n\t\t}\n\t\tfinally {\n\t\t\tlogger.setLevel(currentLevel);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ MatchingAutoConfiguration.class, NonMatchingAutoConfiguration.class,\n\t\t\tUnconditionalAutoConfiguration.class })\n\tstatic class Config {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ MatchingAutoConfiguration.class, NonMatchingAutoConfiguration.class,\n\t\t\tUnconditionalAutoConfiguration.class })\n\tstatic class ErrorConfig {\n\n\t\t@Bean\n\t\tString iBreak() {\n\t\t\tthrow new RuntimeException();\n\t\t}\n\n\t}\n\n\t@AutoConfiguration\n\t@ConditionalOnProperty(name = \"com.example.property\", matchIfMissing = true)\n\tpublic static final class MatchingAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\t@ConditionalOnBean(Duration.class)\n\tpublic static final class NonMatchingAutoConfiguration {\n\n\t}\n\n\t@AutoConfiguration\n\tpublic static final class UnconditionalAutoConfiguration {\n\n\t\t@Bean\n\t\tString example() {\n\t\t\treturn \"example\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/ConditionEvaluationReportLoggingProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.logging;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\nimport ch.qos.logback.classic.LoggerContext;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Condition;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConditionEvaluationReportLoggingProcessor}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ConditionEvaluationReportLoggingProcessorTests {\n\n\t@Test\n\tvoid logsDebugOnProcessAheadOfTime(CapturedOutput output) {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tConditionEvaluationReport.get(beanFactory)\n\t\t\t.recordConditionEvaluation(\"test\", mock(Condition.class), ConditionOutcome.match());\n\t\tConditionEvaluationReportLoggingProcessor processor = new ConditionEvaluationReportLoggingProcessor();\n\t\tprocessor.processAheadOfTime(beanFactory);\n\t\tassertThat(output).doesNotContain(\"CONDITIONS EVALUATION REPORT\");\n\t\twithDebugLogging(() -> processor.processAheadOfTime(beanFactory));\n\t\tassertThat(output).contains(\"CONDITIONS EVALUATION REPORT\");\n\t}\n\n\tprivate void withDebugLogging(Runnable runnable) {\n\t\tLogger logger = ((LoggerContext) LoggerFactory.getILoggerFactory())\n\t\t\t.getLogger(ConditionEvaluationReportLogger.class);\n\t\tLevel currentLevel = logger.getLevel();\n\t\tlogger.setLevel(Level.DEBUG);\n\t\ttry {\n\t\t\trunnable.run();\n\t\t}\n\t\tfinally {\n\t\t\tlogger.setLevel(currentLevel);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/one/FirstConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.packagestest.one;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackage;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Sample configuration used in {@code AutoConfigurationPackagesTests}.\n *\n * @author Oliver Gierke\n */\n@Configuration(proxyBeanMethods = false)\n@AutoConfigurationPackage\npublic class FirstConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/one/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.packagestest.one;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/two/SecondConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.packagestest.two;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackage;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Sample configuration used in {@code AutoConfigurationPackagesTests}.\n *\n * @author Oliver Gierke\n */\n@Configuration(proxyBeanMethods = false)\n@AutoConfigurationPackage\npublic class SecondConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/two/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.autoconfigure.packagestest.two;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/service/connection/ConnectionDetailsFactoriesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.service.connection;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories.Registration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.test.io.support.MockSpringFactoriesLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link ConnectionDetailsFactories}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConnectionDetailsFactoriesTests {\n\n\tprivate final MockSpringFactoriesLoader loader = new MockSpringFactoriesLoader();\n\n\t@Test\n\tvoid getRequiredConnectionDetailsWhenNoFactoryForSourceThrowsException() {\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tassertThatExceptionOfType(ConnectionDetailsFactoryNotFoundException.class)\n\t\t\t.isThrownBy(() -> factories.getConnectionDetails(\"source\", true));\n\t}\n\n\t@Test\n\tvoid getOptionalConnectionDetailsWhenNoFactoryForSourceThrowsException() {\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tassertThat(factories.getConnectionDetails(\"source\", false)).isEmpty();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenSourceHasOneMatchReturnsSingleResult() {\n\t\tthis.loader.addInstance(ConnectionDetailsFactory.class, new TestConnectionDetailsFactory());\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tMap<Class<?>, ConnectionDetails> connectionDetails = factories.getConnectionDetails(\"source\", false);\n\t\tassertThat(connectionDetails).hasSize(1);\n\t\tassertThat(connectionDetails.get(TestConnectionDetails.class)).isInstanceOf(TestConnectionDetailsImpl.class);\n\t}\n\n\t@Test\n\tvoid getRequiredConnectionDetailsWhenSourceHasNoMatchTheowsException() {\n\t\tthis.loader.addInstance(ConnectionDetailsFactory.class, new NullResultTestConnectionDetailsFactory());\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tassertThatExceptionOfType(ConnectionDetailsNotFoundException.class)\n\t\t\t.isThrownBy(() -> factories.getConnectionDetails(\"source\", true));\n\t}\n\n\t@Test\n\tvoid getOptionalConnectionDetailsWhenSourceHasNoMatchReturnsEmptyMap() {\n\t\tthis.loader.addInstance(ConnectionDetailsFactory.class, new NullResultTestConnectionDetailsFactory());\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tMap<Class<?>, ConnectionDetails> connectionDetails = factories.getConnectionDetails(\"source\", false);\n\t\tassertThat(connectionDetails).isEmpty();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenSourceHasMultipleMatchesReturnsMultipleResults() {\n\t\tthis.loader.addInstance(ConnectionDetailsFactory.class, new TestConnectionDetailsFactory(),\n\t\t\t\tnew OtherConnectionDetailsFactory());\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tMap<Class<?>, ConnectionDetails> connectionDetails = factories.getConnectionDetails(\"source\", false);\n\t\tassertThat(connectionDetails).hasSize(2);\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenDuplicatesThrowsException() {\n\t\tthis.loader.addInstance(ConnectionDetailsFactory.class, new TestConnectionDetailsFactory(),\n\t\t\t\tnew TestConnectionDetailsFactory());\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tassertThatIllegalStateException().isThrownBy(() -> factories.getConnectionDetails(\"source\", false))\n\t\t\t.withMessage(\"Duplicate connection details supplied for \" + TestConnectionDetails.class.getName());\n\t}\n\n\t@Test\n\tvoid getRegistrationsReturnsOrderedDelegates() {\n\t\tTestConnectionDetailsFactory orderOne = new TestConnectionDetailsFactory(1);\n\t\tTestConnectionDetailsFactory orderTwo = new TestConnectionDetailsFactory(2);\n\t\tTestConnectionDetailsFactory orderThree = new TestConnectionDetailsFactory(3);\n\t\tthis.loader.addInstance(ConnectionDetailsFactory.class, orderOne, orderThree, orderTwo);\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(this.loader);\n\t\tList<Registration<String, ?>> registrations = factories.getRegistrations(\"source\", false);\n\t\tassertThat(registrations.get(0).factory()).isEqualTo(orderOne);\n\t\tassertThat(registrations.get(1).factory()).isEqualTo(orderTwo);\n\t\tassertThat(registrations.get(2).factory()).isEqualTo(orderThree);\n\t}\n\n\t@Test\n\tvoid factoryLoadFailureDoesNotPreventOtherFactoriesFromLoading() {\n\t\tthis.loader.add(ConnectionDetailsFactory.class.getName(), \"com.example.NonExistentConnectionDetailsFactory\");\n\t\tassertThatNoException().isThrownBy(() -> new ConnectionDetailsFactories(this.loader));\n\t}\n\n\tprivate static final class TestConnectionDetailsFactory\n\t\t\timplements ConnectionDetailsFactory<String, TestConnectionDetails>, Ordered {\n\n\t\tprivate final int order;\n\n\t\tprivate TestConnectionDetailsFactory() {\n\t\t\tthis(0);\n\t\t}\n\n\t\tprivate TestConnectionDetailsFactory(int order) {\n\t\t\tthis.order = order;\n\t\t}\n\n\t\t@Override\n\t\tpublic TestConnectionDetails getConnectionDetails(String source) {\n\t\t\treturn new TestConnectionDetailsImpl();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn this.order;\n\t\t}\n\n\t}\n\n\tprivate static final class NullResultTestConnectionDetailsFactory\n\t\t\timplements ConnectionDetailsFactory<String, TestConnectionDetails> {\n\n\t\t@Override\n\t\tpublic @Nullable TestConnectionDetails getConnectionDetails(String source) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate static final class OtherConnectionDetailsFactory\n\t\t\timplements ConnectionDetailsFactory<String, OtherConnectionDetails> {\n\n\t\t@Override\n\t\tpublic OtherConnectionDetails getConnectionDetails(String source) {\n\t\t\treturn new OtherConnectionDetailsImpl();\n\t\t}\n\n\t}\n\n\tprivate interface TestConnectionDetails extends ConnectionDetails {\n\n\t}\n\n\tprivate static final class TestConnectionDetailsImpl implements TestConnectionDetails {\n\n\t}\n\n\tprivate interface OtherConnectionDetails extends ConnectionDetails {\n\n\t}\n\n\tprivate static final class OtherConnectionDetailsImpl implements OtherConnectionDetails {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/BundleContentNotWatchableFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BundleContentNotWatchableFailureAnalyzer}.\n *\n * @author Moritz Halbritter\n */\nclass BundleContentNotWatchableFailureAnalyzerTests {\n\n\t@Test\n\tvoid shouldAnalyze() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(null);\n\t\tassertThat(failureAnalysis).isNotNull();\n\t\tassertThat(failureAnalysis.getDescription()).isEqualTo(\n\t\t\t\t\"The content of 'name' is not watchable. Only 'file:' resources are watchable, but 'classpath:resource.pem' has been set\");\n\t\tassertThat(failureAnalysis.getAction())\n\t\t\t.isEqualTo(\"Update your application to correct the invalid configuration:\\n\"\n\t\t\t\t\t+ \"Either use a watchable resource, or disable bundle reloading by setting reload-on-update = false on the bundle.\");\n\t}\n\n\t@Test\n\tvoid shouldAnalyzeWithBundle() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(\"bundle-1\");\n\t\tassertThat(failureAnalysis).isNotNull();\n\t\tassertThat(failureAnalysis.getDescription()).isEqualTo(\n\t\t\t\t\"The content of 'name' from bundle 'bundle-1' is not watchable'. Only 'file:' resources are watchable, but 'classpath:resource.pem' has been set\");\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(@Nullable String bundle) {\n\t\tBundleContentNotWatchableException failure = new BundleContentNotWatchableException(\n\t\t\t\tnew BundleContentProperty(\"name\", \"classpath:resource.pem\"));\n\t\tif (bundle != null) {\n\t\t\tfailure = failure.withBundleName(bundle);\n\t\t}\n\t\treturn new BundleContentNotWatchableFailureAnalyzer().analyze(failure);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/BundleContentPropertyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link BundleContentProperty}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass BundleContentPropertyTests {\n\n\tprivate static final String PEM_TEXT = \"\"\"\n\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t-----END CERTIFICATE-----\n\t\t\t\"\"\";\n\n\t@Test\n\tvoid isPemContentWhenValueIsPemTextReturnsTrue() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", PEM_TEXT);\n\t\tassertThat(property.isPemContent()).isTrue();\n\t}\n\n\t@Test\n\tvoid isPemContentWhenValueIsNotPemTextReturnsFalse() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", \"file.pem\");\n\t\tassertThat(property.isPemContent()).isFalse();\n\t}\n\n\t@Test\n\tvoid hasValueWhenHasValueReturnsTrue() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", \"file.pem\");\n\t\tassertThat(property.hasValue()).isTrue();\n\t}\n\n\t@Test\n\tvoid hasValueWhenHasNullValueReturnsFalse() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", null);\n\t\tassertThat(property.hasValue()).isFalse();\n\t}\n\n\t@Test\n\tvoid hasValueWhenHasEmptyValueReturnsFalse() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", \"\");\n\t\tassertThat(property.hasValue()).isFalse();\n\t}\n\n\t@Test\n\tvoid toWatchPathWhenNotPathThrowsException() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", PEM_TEXT);\n\t\tassertThatIllegalStateException().isThrownBy(() -> property.toWatchPath(ApplicationResourceLoader.get()))\n\t\t\t.withMessage(\"Unable to convert value of property 'name' to a path\");\n\t}\n\n\t@Test\n\tvoid toWatchPathWhenPathReturnsPath() throws URISyntaxException {\n\t\tURL resource = getClass().getResource(\"keystore.jks\");\n\t\tPath file = Path.of(resource.toURI()).toAbsolutePath();\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", file.toString());\n\t\tassertThat(property.toWatchPath(ApplicationResourceLoader.get())).isEqualTo(file);\n\t}\n\n\t@Test\n\tvoid toWatchPathUsesResourceLoader() throws URISyntaxException {\n\t\tURL resource = getClass().getResource(\"keystore.jks\");\n\t\tPath file = Path.of(resource.toURI()).toAbsolutePath();\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", file.toString());\n\t\tResourceLoader resourceLoader = spy(ApplicationResourceLoader.get());\n\t\tassertThat(property.toWatchPath(resourceLoader)).isEqualTo(file);\n\t\tthen(resourceLoader).should(atLeastOnce()).getResource(file.toString());\n\t}\n\n\t@Test\n\tvoid shouldThrowBundleContentNotWatchableExceptionIfContentIsNotWatchable() {\n\t\tBundleContentProperty property = new BundleContentProperty(\"name\", \"https://example.com/\");\n\t\tassertThatExceptionOfType(BundleContentNotWatchableException.class)\n\t\t\t.isThrownBy(() -> property.toWatchPath(ApplicationResourceLoader.get()))\n\t\t\t.withMessageContaining(\"Only 'file:' resources are watchable\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/CertificateMatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.security.cert.Certificate;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CertificateMatcher}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass CertificateMatcherTests {\n\n\t@CertificateMatchingTest\n\tvoid matchesWhenMatchReturnsTrue(CertificateMatchingTestSource source) {\n\t\tCertificateMatcher matcher = new CertificateMatcher(source.privateKey());\n\t\tassertThat(matcher.matches(source.matchingCertificate())).isTrue();\n\t}\n\n\t@CertificateMatchingTest\n\tvoid matchesWhenNoMatchReturnsFalse(CertificateMatchingTestSource source) {\n\t\tCertificateMatcher matcher = new CertificateMatcher(source.privateKey());\n\t\tfor (Certificate nonMatchingCertificate : source.nonMatchingCertificates()) {\n\t\t\tassertThat(matcher.matches(nonMatchingCertificate)).isFalse();\n\t\t}\n\t}\n\n\t@CertificateMatchingTest\n\tvoid matchesAnyWhenNoneMatchReturnsFalse(CertificateMatchingTestSource source) {\n\t\tCertificateMatcher matcher = new CertificateMatcher(source.privateKey());\n\t\tassertThat(matcher.matchesAny(source.nonMatchingCertificates())).isFalse();\n\t}\n\n\t@CertificateMatchingTest\n\tvoid matchesAnyWhenOneMatchesReturnsTrue(CertificateMatchingTestSource source) {\n\t\tCertificateMatcher matcher = new CertificateMatcher(source.privateKey());\n\t\tList<Certificate> certificates = new ArrayList<>(source.nonMatchingCertificates());\n\t\tcertificates.add(source.matchingCertificate());\n\t\tassertThat(matcher.matchesAny(certificates)).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/CertificateMatchingTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\n/**\n * Annotation for a {@code ParameterizedTest @ParameterizedTest} with a\n * {@link CertificateMatchingTestSource} parameter.\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ParameterizedTest(name = \"{0}\")\n@MethodSource(\"org.springframework.boot.autoconfigure.ssl.CertificateMatchingTestSource#create\")\npublic @interface CertificateMatchingTest {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/CertificateMatchingTestSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.security.spec.AlgorithmParameterSpec;\nimport java.security.spec.ECGenParameterSpec;\nimport java.security.spec.NamedParameterSpec;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Source used with {@link CertificateMatchingTest @CertificateMatchingTest} annotated\n * tests that provides access to useful test material.\n *\n * @param algorithm the algorithm\n * @param privateKey the private key to use for matching\n * @param matchingCertificate a certificate that matches the private key\n * @param nonMatchingCertificates a list of certificate that do not match the private key\n * @param nonMatchingPrivateKeys a list of private keys that do not match the certificate\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nrecord CertificateMatchingTestSource(CertificateMatchingTestSource.Algorithm algorithm, PrivateKey privateKey,\n\t\tX509Certificate matchingCertificate, List<X509Certificate> nonMatchingCertificates,\n\t\tList<PrivateKey> nonMatchingPrivateKeys) {\n\n\tprivate static final List<Algorithm> ALGORITHMS;\n\tstatic {\n\t\tList<Algorithm> algorithms = new ArrayList<>();\n\t\tStream.of(\"RSA\", \"DSA\", \"ed25519\", \"ed448\").map(Algorithm::of).forEach(algorithms::add);\n\t\tStream.of(\"secp256r1\", \"secp521r1\").map(Algorithm::ec).forEach(algorithms::add);\n\t\tALGORITHMS = List.copyOf(algorithms);\n\t}\n\n\tCertificateMatchingTestSource(Algorithm algorithm, KeyPair matchingKeyPair, List<KeyPair> nonMatchingKeyPairs) {\n\t\tthis(algorithm, matchingKeyPair.getPrivate(), asCertificate(matchingKeyPair),\n\t\t\t\tnonMatchingKeyPairs.stream().map(CertificateMatchingTestSource::asCertificate).toList(),\n\t\t\t\tnonMatchingKeyPairs.stream().map(KeyPair::getPrivate).toList());\n\t}\n\n\tprivate static X509Certificate asCertificate(KeyPair keyPair) {\n\t\tX509Certificate certificate = mock(X509Certificate.class);\n\t\tgiven(certificate.getPublicKey()).willReturn(keyPair.getPublic());\n\t\treturn certificate;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.algorithm.toString();\n\t}\n\n\tstatic List<CertificateMatchingTestSource> create()\n\t\t\tthrows NoSuchAlgorithmException, InvalidAlgorithmParameterException {\n\t\tMap<Algorithm, KeyPair> keyPairs = new LinkedHashMap<>();\n\t\tfor (Algorithm algorithm : ALGORITHMS) {\n\t\t\tkeyPairs.put(algorithm, algorithm.generateKeyPair());\n\t\t}\n\t\tList<CertificateMatchingTestSource> parameters = new ArrayList<>();\n\t\tkeyPairs.forEach((algorithm, matchingKeyPair) -> {\n\t\t\tList<KeyPair> nonMatchingKeyPairs = new ArrayList<>(keyPairs.values());\n\t\t\tnonMatchingKeyPairs.remove(matchingKeyPair);\n\t\t\tparameters.add(new CertificateMatchingTestSource(algorithm, matchingKeyPair, nonMatchingKeyPairs));\n\t\t});\n\t\treturn List.copyOf(parameters);\n\t}\n\n\t/**\n\t * An individual algorithm.\n\t *\n\t * @param name the algorithm name\n\t * @param spec the algorithm spec or {@code null}\n\t */\n\trecord Algorithm(String name, @Nullable AlgorithmParameterSpec spec) {\n\n\t\tKeyPair generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {\n\t\t\tKeyPairGenerator generator = KeyPairGenerator.getInstance(this.name);\n\t\t\tif (this.spec != null) {\n\t\t\t\tgenerator.initialize(this.spec);\n\t\t\t}\n\t\t\treturn generator.generateKeyPair();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tString spec = (this.spec instanceof NamedParameterSpec namedSpec) ? namedSpec.getName() : \"\";\n\t\t\treturn this.name + ((!spec.isEmpty()) ? \":\" + spec : \"\");\n\t\t}\n\n\t\tstatic Algorithm of(String name) {\n\t\t\treturn new Algorithm(name, null);\n\t\t}\n\n\t\tstatic Algorithm ec(String curve) {\n\t\t\treturn new Algorithm(\"EC\", new ECGenParameterSpec(curve));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/FileWatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.AccessDeniedException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.time.Duration;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatCode;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link FileWatcher}.\n *\n * @author Moritz Halbritter\n * @author Brian Clozel\n */\nclass FileWatcherTests {\n\n\tprivate FileWatcher fileWatcher;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.fileWatcher = new FileWatcher(Duration.ofMillis(10));\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws IOException {\n\t\tthis.fileWatcher.close();\n\t}\n\n\t@Test\n\tvoid shouldTriggerOnFileCreation(@TempDir Path tempDir) throws Exception {\n\t\tPath newFile = tempDir.resolve(\"new-file.txt\");\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(tempDir), callback);\n\t\tFiles.createFile(newFile);\n\t\tcallback.expectChanges();\n\t}\n\n\t@Test\n\tvoid shouldTriggerOnFileDeletion(@TempDir Path tempDir) throws Exception {\n\t\tPath deletedFile = tempDir.resolve(\"deleted-file.txt\");\n\t\tFiles.createFile(deletedFile);\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(tempDir), callback);\n\t\tFiles.delete(deletedFile);\n\t\tcallback.expectChanges();\n\t}\n\n\t@Test\n\tvoid shouldTriggerOnFileModification(@TempDir Path tempDir) throws Exception {\n\t\tPath deletedFile = tempDir.resolve(\"modified-file.txt\");\n\t\tFiles.createFile(deletedFile);\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(tempDir), callback);\n\t\tFiles.writeString(deletedFile, \"Some content\");\n\t\tcallback.expectChanges();\n\t}\n\n\t@Test\n\tvoid shouldWatchFile(@TempDir Path tempDir) throws Exception {\n\t\tPath watchedFile = tempDir.resolve(\"watched.txt\");\n\t\tFiles.createFile(watchedFile);\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(watchedFile), callback);\n\t\tFiles.writeString(watchedFile, \"Some content\");\n\t\tcallback.expectChanges();\n\t}\n\n\t@Test\n\tvoid shouldFollowSymlink(@TempDir Path tempDir) throws Exception {\n\t\tPath realFile = tempDir.resolve(\"realFile.txt\");\n\t\tPath symLink = tempDir.resolve(\"symlink.txt\");\n\t\tFiles.createFile(realFile);\n\t\tFiles.createSymbolicLink(symLink, realFile);\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(symLink), callback);\n\t\tFiles.writeString(realFile, \"Some content\");\n\t\tcallback.expectChanges();\n\t}\n\n\t@Test\n\tvoid shouldFollowSymlinkRecursively(@TempDir Path tempDir) throws Exception {\n\t\tPath realFile = tempDir.resolve(\"realFile.txt\");\n\t\tPath symLink = tempDir.resolve(\"symlink.txt\");\n\t\tPath symLink2 = tempDir.resolve(\"symlink2.txt\");\n\t\tFiles.createFile(realFile);\n\t\tFiles.createSymbolicLink(symLink, symLink2);\n\t\tFiles.createSymbolicLink(symLink2, realFile);\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(symLink), callback);\n\t\tFiles.writeString(realFile, \"Some content\");\n\t\tcallback.expectChanges();\n\t}\n\n\t@Test\n\tvoid shouldIgnoreNotWatchedFiles(@TempDir Path tempDir) throws Exception {\n\t\tPath watchedFile = tempDir.resolve(\"watched.txt\");\n\t\tPath notWatchedFile = tempDir.resolve(\"not-watched.txt\");\n\t\tFiles.createFile(watchedFile);\n\t\tFiles.createFile(notWatchedFile);\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(watchedFile), callback);\n\t\tFiles.writeString(notWatchedFile, \"Some content\");\n\t\tcallback.expectNoChanges();\n\t}\n\n\t@Test\n\tvoid shouldFailIfDirectoryOrFileDoesNotExist(@TempDir Path tempDir) {\n\t\tPath directory = tempDir.resolve(\"dir1\");\n\t\tassertThatExceptionOfType(UncheckedIOException.class)\n\t\t\t.isThrownBy(() -> this.fileWatcher.watch(Set.of(directory), new WaitingCallback()))\n\t\t\t.withMessage(\"Failed to register paths for watching: [%s]\".formatted(directory));\n\t}\n\n\t@Test\n\tvoid shouldNotFailIfDirectoryIsRegisteredMultipleTimes(@TempDir Path tempDir) {\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tassertThatCode(() -> {\n\t\t\tthis.fileWatcher.watch(Set.of(tempDir), callback);\n\t\t\tthis.fileWatcher.watch(Set.of(tempDir), callback);\n\t\t}).doesNotThrowAnyException();\n\t}\n\n\t@Test\n\tvoid shouldNotFailIfStoppedMultipleTimes(@TempDir Path tempDir) {\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(tempDir), callback);\n\t\tassertThatCode(() -> {\n\t\t\tthis.fileWatcher.close();\n\t\t\tthis.fileWatcher.close();\n\t\t}).doesNotThrowAnyException();\n\t}\n\n\t@Test\n\tvoid testRelativeFiles() throws Exception {\n\t\tPath watchedFile = Path.of(UUID.randomUUID() + \".txt\");\n\t\tFiles.createFile(watchedFile);\n\t\ttry {\n\t\t\tWaitingCallback callback = new WaitingCallback();\n\t\t\tthis.fileWatcher.watch(Set.of(watchedFile), callback);\n\t\t\tFiles.delete(watchedFile);\n\t\t\tcallback.expectChanges();\n\t\t}\n\t\tfinally {\n\t\t\tFiles.deleteIfExists(watchedFile);\n\t\t}\n\t}\n\n\t@Test\n\tvoid testRelativeDirectories() throws Exception {\n\t\tPath watchedDirectory = Path.of(UUID.randomUUID() + \"/\");\n\t\tPath file = watchedDirectory.resolve(\"file.txt\");\n\t\tFiles.createDirectory(watchedDirectory);\n\t\ttry {\n\t\t\tWaitingCallback callback = new WaitingCallback();\n\t\t\tthis.fileWatcher.watch(Set.of(watchedDirectory), callback);\n\t\t\tFiles.createFile(file);\n\t\t\tcallback.expectChanges();\n\t\t}\n\t\tfinally {\n\t\t\tFiles.deleteIfExists(file);\n\t\t\tFiles.deleteIfExists(watchedDirectory);\n\t\t}\n\t}\n\n\t/*\n\t * Replicating a letsencrypt folder structure like:\n\t * \"/folder/live/certname/privkey.pem -> ../../archive/certname/privkey32.pem\"\n\t */\n\t@Test\n\tvoid shouldFollowRelativePathSymlinks(@TempDir Path tempDir) throws Exception {\n\t\tPath folder = tempDir.resolve(\"folder\");\n\t\tPath live = folder.resolve(\"live\").resolve(\"certname\");\n\t\tPath archive = folder.resolve(\"archive\").resolve(\"certname\");\n\t\tPath link = live.resolve(\"privkey.pem\");\n\t\tPath targetFile = archive.resolve(\"privkey32.pem\");\n\t\tFiles.createDirectories(live);\n\t\tFiles.createDirectories(archive);\n\t\tFiles.createFile(targetFile);\n\t\tPath relativePath = Path.of(\"../../archive/certname/privkey32.pem\");\n\t\tFiles.createSymbolicLink(link, relativePath);\n\t\ttry {\n\t\t\tWaitingCallback callback = new WaitingCallback();\n\t\t\tthis.fileWatcher.watch(Set.of(link), callback);\n\t\t\tFiles.writeString(targetFile, \"Some content\");\n\t\t\tcallback.expectChanges();\n\t\t}\n\t\tfinally {\n\t\t\tFileSystemUtils.deleteRecursively(folder);\n\t\t}\n\t}\n\n\t/*\n\t * Replicating a k8s configmap folder structure like:\n\t * \"secret.txt -> ..data/secret.txt\",\n\t * \"..data/ -> ..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f/\",\n\t * \"..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f/secret.txt\"\n\t *\n\t * After a secret update, this will look like: \"secret.txt -> ..data/secret.txt\",\n\t * \"..data/ -> ..bba2a61f-ce04-4c35-93aa-e455110d4487/\",\n\t * \"..bba2a61f-ce04-4c35-93aa-e455110d4487/secret.txt\"\n\t */\n\t@Test\n\tvoid shouldTriggerOnConfigMapUpdates(@TempDir Path tempDir) throws Exception {\n\t\tPath configMap1 = createConfigMap(tempDir, \"secret.txt\");\n\t\tPath configMap2 = createConfigMap(tempDir, \"secret.txt\");\n\t\tPath data = tempDir.resolve(\"..data\");\n\t\tFiles.createSymbolicLink(data, configMap1);\n\t\tPath secretFile = tempDir.resolve(\"secret.txt\");\n\t\tFiles.createSymbolicLink(secretFile, data.resolve(\"secret.txt\"));\n\t\ttry {\n\t\t\tWaitingCallback callback = new WaitingCallback();\n\t\t\tthis.fileWatcher.watch(Set.of(secretFile), callback);\n\t\t\tFiles.delete(data);\n\t\t\tFiles.createSymbolicLink(data, configMap2);\n\t\t\tFileSystemUtils.deleteRecursively(configMap1);\n\t\t\tcallback.expectChanges();\n\t\t}\n\t\tfinally {\n\t\t\tFileSystemUtils.deleteRecursively(configMap2);\n\t\t\tFiles.delete(data);\n\t\t\tFiles.delete(secretFile);\n\t\t}\n\t}\n\n\t/**\n\t * Updates many times K8s ConfigMap/Secret with atomic move. <pre>\n\t * .\n\t * +─ ..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f\n\t * │  +─ keystore.jks\n\t * +─ ..data -&gt; ..a72e81ff-f0e1-41d8-a19b-068d3d1d4e2f\n\t * +─ keystore.jks -&gt; ..data/keystore.jks\n\t * </pre>\n\t *\n\t * After a first a ConfigMap/Secret update, this will look like: <pre>\n\t * .\n\t * +─ ..bba2a61f-ce04-4c35-93aa-e455110d4487\n\t * │  +─ keystore.jks\n\t * +─ ..data -&gt; ..bba2a61f-ce04-4c35-93aa-e455110d4487\n\t * +─ keystore.jks -&gt; ..data/keystore.jks\n\t * </pre> After a second a ConfigMap/Secret update, this will look like: <pre>\n\t * .\n\t * +─ ..134887f0-df8f-4433-b70c-7784d2a33bd1\n\t * │  +─ keystore.jks\n\t * +─ ..data -&gt; ..134887f0-df8f-4433-b70c-7784d2a33bd1\n\t * +─ keystore.jks -&gt; ..data/keystore.jks\n\t *</pre>\n\t * <p>\n\t * When Kubernetes updates either the ConfigMap or Secret, it performs the following\n\t * steps:\n\t * <ul>\n\t * <li>Creates a new unique directory.</li>\n\t * <li>Writes the ConfigMap/Secret content to the newly created directory.</li>\n\t * <li>Creates a symlink {@code ..data_tmp} pointing to the newly created\n\t * directory.</li>\n\t * <li>Performs an atomic rename of {@code ..data_tmp} to {@code ..data}.</li>\n\t * <li>Deletes the old ConfigMap/Secret directory.</li>\n\t * </ul>\n\t * @param tempDir temp directory\n\t * @throws Exception if a failure occurs\n\t */\n\t@Test\n\tvoid shouldTriggerOnConfigMapAtomicMoveUpdates(@TempDir Path tempDir) throws Exception {\n\t\tPath configMap1 = createConfigMap(tempDir, \"keystore.jks\");\n\t\tPath data = Files.createSymbolicLink(tempDir.resolve(\"..data\"), configMap1);\n\t\tFiles.createSymbolicLink(tempDir.resolve(\"keystore.jks\"), data.resolve(\"keystore.jks\"));\n\t\tWaitingCallback callback = new WaitingCallback();\n\t\tthis.fileWatcher.watch(Set.of(tempDir.resolve(\"keystore.jks\")), callback);\n\t\t// First update\n\t\tPath configMap2 = createConfigMap(tempDir, \"keystore.jks\");\n\t\tPath dataTmp = Files.createSymbolicLink(tempDir.resolve(\"..data_tmp\"), configMap2);\n\t\tmove(dataTmp, data);\n\t\tFileSystemUtils.deleteRecursively(configMap1);\n\t\tcallback.expectChanges();\n\t\tcallback.reset();\n\t\t// Second update\n\t\tPath configMap3 = createConfigMap(tempDir, \"keystore.jks\");\n\t\tdataTmp = Files.createSymbolicLink(tempDir.resolve(\"..data_tmp\"), configMap3);\n\t\tmove(dataTmp, data);\n\t\tFileSystemUtils.deleteRecursively(configMap2);\n\t\tcallback.expectChanges();\n\t}\n\n\tPath createConfigMap(Path parentDir, String secretFileName) throws IOException {\n\t\tPath configMapFolder = parentDir.resolve(\"..\" + UUID.randomUUID());\n\t\tFiles.createDirectory(configMapFolder);\n\t\tPath secret = configMapFolder.resolve(secretFileName);\n\t\tFiles.createFile(secret);\n\t\treturn configMapFolder;\n\t}\n\n\tprivate void move(Path source, Path target) throws IOException {\n\t\ttry {\n\t\t\tFiles.move(source, target, StandardCopyOption.ATOMIC_MOVE);\n\t\t}\n\t\tcatch (AccessDeniedException ex) {\n\t\t\t// Windows\n\t\t\tFiles.move(source, target, StandardCopyOption.REPLACE_EXISTING);\n\t\t}\n\t}\n\n\tprivate static final class WaitingCallback implements Runnable {\n\n\t\tprivate CountDownLatch latch = new CountDownLatch(1);\n\n\t\tvolatile boolean changed;\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tthis.changed = true;\n\t\t\tthis.latch.countDown();\n\t\t}\n\n\t\tvoid expectChanges() throws InterruptedException {\n\t\t\twaitForChanges(true);\n\t\t\tassertThat(this.changed).as(\"changed\").isTrue();\n\t\t}\n\n\t\tvoid expectNoChanges() throws InterruptedException {\n\t\t\twaitForChanges(false);\n\t\t\tassertThat(this.changed).as(\"changed\").isFalse();\n\t\t}\n\n\t\tvoid waitForChanges(boolean fail) throws InterruptedException {\n\t\t\tif (!this.latch.await(5, TimeUnit.SECONDS)) {\n\t\t\t\tif (fail) {\n\t\t\t\t\tfail(\"Timeout while waiting for changes\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid reset() {\n\t\t\tthis.latch = new CountDownLatch(1);\n\t\t\tthis.changed = false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/PropertiesSslBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.security.Key;\nimport java.security.KeyStore;\nimport java.security.cert.Certificate;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link PropertiesSslBundle}.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass PropertiesSslBundleTests {\n\n\tprivate static final char[] EMPTY_KEY_PASSWORD = new char[] {};\n\n\t@Test\n\tvoid pemPropertiesAreMappedToSslBundle() throws Exception {\n\t\tPemSslBundleProperties properties = new PemSslBundleProperties();\n\t\tproperties.getKey().setAlias(\"alias\");\n\t\tproperties.getKey().setPassword(\"secret\");\n\t\tproperties.getOptions().setCiphers(Set.of(\"cipher1\", \"cipher2\", \"cipher3\"));\n\t\tproperties.getOptions().setEnabledProtocols(Set.of(\"protocol1\", \"protocol2\"));\n\t\tproperties.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem\");\n\t\tproperties.getKeystore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem\");\n\t\tproperties.getKeystore().setPrivateKeyPassword(null);\n\t\tproperties.getKeystore().setType(\"PKCS12\");\n\t\tproperties.getTruststore()\n\t\t\t.setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem\");\n\t\tproperties.getTruststore()\n\t\t\t.setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem\");\n\t\tproperties.getTruststore().setPrivateKeyPassword(\"secret\");\n\t\tproperties.getTruststore().setType(\"PKCS12\");\n\t\tSslBundle sslBundle = PropertiesSslBundle.get(properties);\n\t\tassertThat(sslBundle.getKey().getAlias()).isEqualTo(\"alias\");\n\t\tassertThat(sslBundle.getKey().getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(sslBundle.getOptions().getCiphers()).containsExactlyInAnyOrder(\"cipher1\", \"cipher2\", \"cipher3\");\n\t\tassertThat(sslBundle.getOptions().getEnabledProtocols()).containsExactlyInAnyOrder(\"protocol1\", \"protocol2\");\n\t\tassertThat(sslBundle.getStores()).isNotNull();\n\t\tKeyStore keyStore = sslBundle.getStores().getKeyStore();\n\t\tassertThat(keyStore).isNotNull();\n\t\tCertificate certificate = keyStore.getCertificate(\"alias\");\n\t\tassertThat(certificate).isNotNull();\n\t\tassertThat(certificate.getType()).isEqualTo(\"X.509\");\n\t\tKey key = keyStore.getKey(\"alias\", \"secret\".toCharArray());\n\t\tassertThat(key).isNotNull();\n\t\tassertThat(key.getAlgorithm()).isEqualTo(\"RSA\");\n\t\tKeyStore trustStore = sslBundle.getStores().getTrustStore();\n\t\tassertThat(trustStore).isNotNull();\n\t\tcertificate = trustStore.getCertificate(\"ssl\");\n\t\tassertThat(certificate).isNotNull();\n\t\tassertThat(certificate.getType()).isEqualTo(\"X.509\");\n\t}\n\n\t@Test\n\tvoid jksPropertiesAreMappedToSslBundle() {\n\t\tJksSslBundleProperties properties = new JksSslBundleProperties();\n\t\tproperties.getKey().setAlias(\"alias\");\n\t\tproperties.getKey().setPassword(\"secret\");\n\t\tproperties.getOptions().setCiphers(Set.of(\"cipher1\", \"cipher2\", \"cipher3\"));\n\t\tproperties.getOptions().setEnabledProtocols(Set.of(\"protocol1\", \"protocol2\"));\n\t\tproperties.getKeystore().setPassword(\"secret\");\n\t\tproperties.getKeystore().setProvider(\"SUN\");\n\t\tproperties.getKeystore().setType(\"JKS\");\n\t\tproperties.getKeystore().setLocation(\"classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks\");\n\t\tproperties.getTruststore().setPassword(\"secret\");\n\t\tproperties.getTruststore().setProvider(\"SUN\");\n\t\tproperties.getTruststore().setType(\"PKCS12\");\n\t\tproperties.getTruststore().setLocation(\"classpath:org/springframework/boot/autoconfigure/ssl/keystore.pkcs12\");\n\t\tSslBundle sslBundle = PropertiesSslBundle.get(properties);\n\t\tassertThat(sslBundle.getKey().getAlias()).isEqualTo(\"alias\");\n\t\tassertThat(sslBundle.getKey().getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(sslBundle.getOptions().getCiphers()).containsExactlyInAnyOrder(\"cipher1\", \"cipher2\", \"cipher3\");\n\t\tassertThat(sslBundle.getOptions().getEnabledProtocols()).containsExactlyInAnyOrder(\"protocol1\", \"protocol2\");\n\t\tassertThat(sslBundle.getStores()).isNotNull();\n\t\tassertThat(sslBundle.getStores()).extracting(\"keyStoreDetails\")\n\t\t\t.extracting(\"location\", \"password\", \"provider\", \"type\")\n\t\t\t.containsExactly(\"classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks\", \"secret\", \"SUN\",\n\t\t\t\t\t\"JKS\");\n\t\tKeyStore trustStore = sslBundle.getStores().getTrustStore();\n\t\tassertThat(trustStore).isNotNull();\n\t\tassertThat(trustStore.getType()).isEqualTo(\"PKCS12\");\n\t\tassertThat(trustStore.getProvider().getName()).isEqualTo(\"SUN\");\n\t}\n\n\t@Test\n\tvoid getWithPemSslBundlePropertiesWhenVerifyKeyStoreAgainstSingleCertificateWithMatchCreatesBundle() {\n\t\tPemSslBundleProperties properties = new PemSslBundleProperties();\n\t\tproperties.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/key1.crt\");\n\t\tproperties.getKeystore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/key1.pem\");\n\t\tproperties.getKeystore().setVerifyKeys(true);\n\t\tproperties.getKey().setAlias(\"test-alias\");\n\t\tSslBundle bundle = PropertiesSslBundle.get(properties);\n\t\tassertThat(bundle.getStores().getKeyStore()).satisfies(storeContainingCertAndKey(\"test-alias\"));\n\t}\n\n\t@Test\n\tvoid getWithPemSslBundlePropertiesWhenVerifyKeyStoreAgainstCertificateChainWithMatchCreatesBundle() {\n\t\tPemSslBundleProperties properties = new PemSslBundleProperties();\n\t\tproperties.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/key2-chain.crt\");\n\t\tproperties.getKeystore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/key2.pem\");\n\t\tproperties.getKeystore().setVerifyKeys(true);\n\t\tproperties.getKey().setAlias(\"test-alias\");\n\t\tSslBundle bundle = PropertiesSslBundle.get(properties);\n\t\tassertThat(bundle.getStores().getKeyStore()).satisfies(storeContainingCertAndKey(\"test-alias\"));\n\t}\n\n\t@Test\n\tvoid getWithPemSslBundlePropertiesWhenVerifyKeyStoreWithNoMatchThrowsException() {\n\t\tPemSslBundleProperties properties = new PemSslBundleProperties();\n\t\tproperties.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/key2.crt\");\n\t\tproperties.getKeystore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/key1.pem\");\n\t\tproperties.getKeystore().setVerifyKeys(true);\n\t\tproperties.getKey().setAlias(\"test-alias\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> PropertiesSslBundle.get(properties))\n\t\t\t.withMessageContaining(\"Private key in keystore matches none of the certificates\");\n\t}\n\n\t@Test\n\tvoid getWithResourceLoader() {\n\t\tPemSslBundleProperties properties = new PemSslBundleProperties();\n\t\tproperties.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/key2-chain.crt\");\n\t\tproperties.getKeystore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/key2.pem\");\n\t\tproperties.getKeystore().setVerifyKeys(true);\n\t\tproperties.getKey().setAlias(\"test-alias\");\n\t\tResourceLoader resourceLoader = spy(new DefaultResourceLoader());\n\t\tSslBundle bundle = PropertiesSslBundle.get(properties, resourceLoader);\n\t\tassertThat(bundle.getStores().getKeyStore()).satisfies(storeContainingCertAndKey(\"test-alias\"));\n\t\tthen(resourceLoader).should(atLeastOnce())\n\t\t\t.getResource(\"classpath:org/springframework/boot/autoconfigure/ssl/key2-chain.crt\");\n\t\tthen(resourceLoader).should(atLeastOnce())\n\t\t\t.getResource(\"classpath:org/springframework/boot/autoconfigure/ssl/key2.pem\");\n\t}\n\n\tprivate Consumer<KeyStore> storeContainingCertAndKey(String keyAlias) {\n\t\treturn ThrowingConsumer.of((keyStore) -> {\n\t\t\tassertThat(keyStore).isNotNull();\n\t\t\tassertThat(keyStore.getType()).isEqualTo(KeyStore.getDefaultType());\n\t\t\tassertThat(keyStore.containsAlias(keyAlias)).isTrue();\n\t\t\tassertThat(keyStore.getCertificate(keyAlias)).isNotNull();\n\t\t\tassertThat(keyStore.getKey(keyAlias, EMPTY_KEY_PASSWORD)).isNotNull();\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.security.KeyStore;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslAutoConfiguration}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass SslAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class));\n\n\t@Test\n\tvoid sslBundlesCreatedWithNoConfiguration() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(SslBundleRegistry.class));\n\t}\n\n\t@Test\n\tvoid sslBundlesCreatedWithCertificates() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/autoconfigure/ssl/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.key.alias=alias1\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.key.password=secret1\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.keystore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.keystore.private-key=\" + location + \"rsa-key.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.keystore.type=PKCS12\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.truststore.type=PKCS12\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.truststore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.first.truststore.private-key=\" + location + \"rsa-key.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.key.alias=alias2\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.key.password=secret2\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.keystore.certificate=\" + location + \"ed25519-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.keystore.private-key=\" + location + \"ed25519-key.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.keystore.type=PKCS12\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.truststore.certificate=\" + location + \"ed25519-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.truststore.private-key=\" + location + \"ed25519-key.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.second.truststore.type=PKCS12\");\n\t\tthis.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SslBundles.class);\n\t\t\tSslBundles bundles = context.getBean(SslBundles.class);\n\t\t\tSslBundle first = bundles.getBundle(\"first\");\n\t\t\tassertThat(first).isNotNull();\n\t\t\tassertThat(first.getStores()).isNotNull();\n\t\t\tassertThat(first.getManagers()).isNotNull();\n\t\t\tassertThat(first.getKey().getAlias()).isEqualTo(\"alias1\");\n\t\t\tassertThat(first.getKey().getPassword()).isEqualTo(\"secret1\");\n\t\t\tKeyStore firstKeyStore = first.getStores().getKeyStore();\n\t\t\tassertThat(firstKeyStore).isNotNull();\n\t\t\tassertThat(firstKeyStore.getType()).isEqualTo(\"PKCS12\");\n\t\t\tKeyStore firstTrustStore = first.getStores().getTrustStore();\n\t\t\tassertThat(firstTrustStore).isNotNull();\n\t\t\tassertThat(firstTrustStore.getType()).isEqualTo(\"PKCS12\");\n\t\t\tSslBundle second = bundles.getBundle(\"second\");\n\t\t\tassertThat(second).isNotNull();\n\t\t\tassertThat(second.getStores()).isNotNull();\n\t\t\tassertThat(second.getManagers()).isNotNull();\n\t\t\tassertThat(second.getKey().getAlias()).isEqualTo(\"alias2\");\n\t\t\tassertThat(second.getKey().getPassword()).isEqualTo(\"secret2\");\n\t\t\tKeyStore secondKeyStore = second.getStores().getKeyStore();\n\t\t\tassertThat(secondKeyStore).isNotNull();\n\t\t\tassertThat(secondKeyStore.getType()).isEqualTo(\"PKCS12\");\n\t\t\tKeyStore secondTrustStore = second.getStores().getTrustStore();\n\t\t\tassertThat(secondTrustStore).isNotNull();\n\t\t\tassertThat(secondTrustStore.getType()).isEqualTo(\"PKCS12\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid sslBundlesCreatedWithCustomSslBundle() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/autoconfigure/ssl/\";\n\t\tpropertyValues.add(\"custom.ssl.key.alias=alias1\");\n\t\tpropertyValues.add(\"custom.ssl.key.password=secret1\");\n\t\tpropertyValues.add(\"custom.ssl.keystore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"custom.ssl.keystore.keystore.private-key=\" + location + \"rsa-key.pem\");\n\t\tpropertyValues.add(\"custom.ssl.truststore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"custom.ssl.keystore.type=PKCS12\");\n\t\tpropertyValues.add(\"custom.ssl.truststore.type=PKCS12\");\n\t\tthis.contextRunner.withUserConfiguration(CustomSslBundleConfiguration.class)\n\t\t\t.withPropertyValues(propertyValues.toArray(String[]::new))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SslBundles.class);\n\t\t\t\tSslBundles bundles = context.getBean(SslBundles.class);\n\t\t\t\tSslBundle bundle = bundles.getBundle(\"custom\");\n\t\t\t\tassertThat(bundle).isNotNull();\n\t\t\t\tassertThat(bundle.getStores()).isNotNull();\n\t\t\t\tassertThat(bundle.getManagers()).isNotNull();\n\t\t\t\tassertThat(bundle.getKey().getAlias()).isEqualTo(\"alias1\");\n\t\t\t\tassertThat(bundle.getKey().getPassword()).isEqualTo(\"secret1\");\n\t\t\t\tKeyStore keyStore = bundle.getStores().getKeyStore();\n\t\t\t\tassertThat(keyStore).isNotNull();\n\t\t\t\tassertThat(keyStore.getType()).isEqualTo(\"PKCS12\");\n\t\t\t\tKeyStore trustStore = bundle.getStores().getTrustStore();\n\t\t\t\tassertThat(trustStore).isNotNull();\n\t\t\t\tassertThat(trustStore.getType()).isEqualTo(\"PKCS12\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid sslBundleWithoutClassPathPrefix() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"src/test/resources/org/springframework/boot/autoconfigure/ssl/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.key.alias=alias1\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.key.password=secret1\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.keystore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.keystore.keystore.private-key=\" + location + \"rsa-key.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tthis.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SslBundles.class);\n\t\t\tSslBundles bundles = context.getBean(SslBundles.class);\n\t\t\tSslBundle bundle = bundles.getBundle(\"test\");\n\t\t\tKeyStore keyStore = bundle.getStores().getKeyStore();\n\t\t\tassertThat(keyStore).isNotNull();\n\t\t\tassertThat(keyStore.getCertificate(\"alias1\")).isNotNull();\n\t\t\tKeyStore trustStore = bundle.getStores().getTrustStore();\n\t\t\tassertThat(trustStore).isNotNull();\n\t\t\tassertThat(trustStore.getCertificate(\"ssl\")).isNotNull();\n\t\t});\n\t}\n\n\t@Configuration\n\t@EnableConfigurationProperties(CustomSslProperties.class)\n\tpublic static class CustomSslBundleConfiguration {\n\n\t\t@Bean\n\t\tpublic SslBundleRegistrar customSslBundlesRegistrar(CustomSslProperties properties) {\n\t\t\treturn new CustomSslBundlesRegistrar(properties);\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"custom.ssl\")\n\tstatic class CustomSslProperties extends PemSslBundleProperties {\n\n\t}\n\n\tstatic class CustomSslBundlesRegistrar implements SslBundleRegistrar {\n\n\t\tprivate final CustomSslProperties properties;\n\n\t\tCustomSslBundlesRegistrar(CustomSslProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerBundles(SslBundleRegistry registry) {\n\t\t\tregistry.registerBundle(\"custom\", PropertiesSslBundle.get(this.properties));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ssl/SslPropertiesBundleRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.ssl;\n\nimport java.nio.file.Path;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundleRegistry;\nimport org.springframework.core.io.DefaultResourceLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link SslPropertiesBundleRegistrar}.\n *\n * @author Moritz Halbritter\n */\nclass SslPropertiesBundleRegistrarTests {\n\n\tprivate SslPropertiesBundleRegistrar registrar;\n\n\tprivate FileWatcher fileWatcher;\n\n\tprivate DefaultResourceLoader resourceLoader;\n\n\tprivate SslProperties properties;\n\n\tprivate SslBundleRegistry registry;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new SslProperties();\n\t\tthis.fileWatcher = Mockito.mock(FileWatcher.class);\n\t\tthis.resourceLoader = spy(new DefaultResourceLoader());\n\t\tthis.registrar = new SslPropertiesBundleRegistrar(this.properties, this.fileWatcher, this.resourceLoader);\n\t\tthis.registry = Mockito.mock(SslBundleRegistry.class);\n\t}\n\n\t@Test\n\tvoid shouldWatchJksBundles() {\n\t\tJksSslBundleProperties jks = new JksSslBundleProperties();\n\t\tjks.setReloadOnUpdate(true);\n\t\tjks.getKeystore().setLocation(\"classpath:org/springframework/boot/autoconfigure/ssl/test.jks\");\n\t\tjks.getKeystore().setPassword(\"secret\");\n\t\tjks.getTruststore().setLocation(\"classpath:org/springframework/boot/autoconfigure/ssl/test.jks\");\n\t\tjks.getTruststore().setPassword(\"secret\");\n\t\tthis.properties.getBundle().getJks().put(\"bundle1\", jks);\n\t\tthis.registrar.registerBundles(this.registry);\n\t\tthen(this.registry).should(times(1)).registerBundle(eq(\"bundle1\"), any());\n\t\tthen(this.fileWatcher).should().watch(assertArg((set) -> pathEndingWith(set, \"test.jks\")), any());\n\t}\n\n\t@Test\n\tvoid shouldWatchPemBundles() {\n\t\tPemSslBundleProperties pem = new PemSslBundleProperties();\n\t\tpem.setReloadOnUpdate(true);\n\t\tpem.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem\");\n\t\tpem.getKeystore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem\");\n\t\tpem.getTruststore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem\");\n\t\tpem.getTruststore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem\");\n\t\tthis.properties.getBundle().getPem().put(\"bundle1\", pem);\n\t\tthis.registrar.registerBundles(this.registry);\n\t\tthen(this.registry).should(times(1)).registerBundle(eq(\"bundle1\"), any());\n\t\tthen(this.fileWatcher).should()\n\t\t\t.watch(assertArg((set) -> pathEndingWith(set, \"rsa-cert.pem\", \"rsa-key.pem\")), any());\n\t}\n\n\t@Test\n\tvoid shouldUseResourceLoader() {\n\t\tPemSslBundleProperties pem = new PemSslBundleProperties();\n\t\tpem.getTruststore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem\");\n\t\tpem.getTruststore().setPrivateKey(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem\");\n\t\tthis.properties.getBundle().getPem().put(\"bundle1\", pem);\n\t\tDefaultSslBundleRegistry registry = new DefaultSslBundleRegistry();\n\t\tthis.registrar.registerBundles(registry);\n\t\tregistry.getBundle(\"bundle1\").createSslContext();\n\t\tthen(this.resourceLoader).should(atLeastOnce())\n\t\t\t.getResource(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem\");\n\t\tthen(this.resourceLoader).should(atLeastOnce())\n\t\t\t.getResource(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfPemKeystoreCertificateIsEmbedded() {\n\t\tPemSslBundleProperties pem = new PemSslBundleProperties();\n\t\tpem.setReloadOnUpdate(true);\n\t\tpem.getKeystore().setCertificate(\"\"\"\n\t\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t\tMIICCzCCAb2gAwIBAgIUZbDi7G5czH+Yi0k2EMWxdf00XagwBQYDK2VwMHsxCzAJ\n\t\t\t\tBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5hbWUxETAPBgNVBAcMCENpdHlOYW1l\n\t\t\t\tMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkGA1UECwwSQ29tcGFueVNlY3Rpb25O\n\t\t\t\tYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjMwOTExMTIxNDMwWhcNMzMwOTA4\n\t\t\t\tMTIxNDMwWjB7MQswCQYDVQQGEwJYWDESMBAGA1UECAwJU3RhdGVOYW1lMREwDwYD\n\t\t\t\tVQQHDAhDaXR5TmFtZTEUMBIGA1UECgwLQ29tcGFueU5hbWUxGzAZBgNVBAsMEkNv\n\t\t\t\tbXBhbnlTZWN0aW9uTmFtZTESMBAGA1UEAwwJbG9jYWxob3N0MCowBQYDK2VwAyEA\n\t\t\t\tQ/DDA4BSgZ+Hx0DUxtIRjVjN+OcxXVURwAWc3Gt9GUyjUzBRMB0GA1UdDgQWBBSv\n\t\t\t\tEdpoaBMBoxgO96GFbf03k07DSTAfBgNVHSMEGDAWgBSvEdpoaBMBoxgO96GFbf03\n\t\t\t\tk07DSTAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAHMXDkGd57d4F4cRk/8UjhxD\n\t\t\t\t7OtRBZfdfznSvlhJIMNfH5q0zbC2eO3hWCB3Hrn/vIeswGP8Ov4AJ6eXeX44BQM=\n\t\t\t\t-----END CERTIFICATE-----\n\t\t\t\t\"\"\".strip());\n\t\tthis.properties.getBundle().getPem().put(\"bundle1\", pem);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))\n\t\t\t.withMessageContaining(\"Unable to register SSL bundle 'bundle1'\")\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"Unable to watch for reload on update\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfPemKeystorePrivateKeyIsEmbedded() {\n\t\tPemSslBundleProperties pem = new PemSslBundleProperties();\n\t\tpem.setReloadOnUpdate(true);\n\t\tpem.getKeystore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem\");\n\t\tpem.getKeystore().setPrivateKey(\"\"\"\n\t\t\t\t-----BEGIN PRIVATE KEY-----\n\t\t\t\tMC4CAQAwBQYDK2VwBCIEIC29RnMVTcyqXEAIO1b/6p7RdbM6TiqvnztVQ4IxYxUh\n\t\t\t\t-----END PRIVATE KEY-----\n\t\t\t\t\"\"\".strip());\n\t\tthis.properties.getBundle().getPem().put(\"bundle1\", pem);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))\n\t\t\t.withMessageContaining(\"Unable to register SSL bundle 'bundle1'\")\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"Unable to watch for reload on update\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfPemTruststoreCertificateIsEmbedded() {\n\t\tPemSslBundleProperties pem = new PemSslBundleProperties();\n\t\tpem.setReloadOnUpdate(true);\n\t\tpem.getTruststore().setCertificate(\"\"\"\n\t\t\t\t-----BEGIN CERTIFICATE-----\n\t\t\t\tMIICCzCCAb2gAwIBAgIUZbDi7G5czH+Yi0k2EMWxdf00XagwBQYDK2VwMHsxCzAJ\n\t\t\t\tBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5hbWUxETAPBgNVBAcMCENpdHlOYW1l\n\t\t\t\tMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkGA1UECwwSQ29tcGFueVNlY3Rpb25O\n\t\t\t\tYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjMwOTExMTIxNDMwWhcNMzMwOTA4\n\t\t\t\tMTIxNDMwWjB7MQswCQYDVQQGEwJYWDESMBAGA1UECAwJU3RhdGVOYW1lMREwDwYD\n\t\t\t\tVQQHDAhDaXR5TmFtZTEUMBIGA1UECgwLQ29tcGFueU5hbWUxGzAZBgNVBAsMEkNv\n\t\t\t\tbXBhbnlTZWN0aW9uTmFtZTESMBAGA1UEAwwJbG9jYWxob3N0MCowBQYDK2VwAyEA\n\t\t\t\tQ/DDA4BSgZ+Hx0DUxtIRjVjN+OcxXVURwAWc3Gt9GUyjUzBRMB0GA1UdDgQWBBSv\n\t\t\t\tEdpoaBMBoxgO96GFbf03k07DSTAfBgNVHSMEGDAWgBSvEdpoaBMBoxgO96GFbf03\n\t\t\t\tk07DSTAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAHMXDkGd57d4F4cRk/8UjhxD\n\t\t\t\t7OtRBZfdfznSvlhJIMNfH5q0zbC2eO3hWCB3Hrn/vIeswGP8Ov4AJ6eXeX44BQM=\n\t\t\t\t-----END CERTIFICATE-----\n\t\t\t\t\"\"\".strip());\n\t\tthis.properties.getBundle().getPem().put(\"bundle1\", pem);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))\n\t\t\t.withMessageContaining(\"Unable to register SSL bundle 'bundle1'\")\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"Unable to watch for reload on update\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfPemTruststorePrivateKeyIsEmbedded() {\n\t\tPemSslBundleProperties pem = new PemSslBundleProperties();\n\t\tpem.setReloadOnUpdate(true);\n\t\tpem.getTruststore().setCertificate(\"classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem\");\n\t\tpem.getTruststore().setPrivateKey(\"\"\"\n\t\t\t\t-----BEGIN PRIVATE KEY-----\n\t\t\t\tMC4CAQAwBQYDK2VwBCIEIC29RnMVTcyqXEAIO1b/6p7RdbM6TiqvnztVQ4IxYxUh\n\t\t\t\t-----END PRIVATE KEY-----\n\t\t\t\t\"\"\".strip());\n\t\tthis.properties.getBundle().getPem().put(\"bundle1\", pem);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.registrar.registerBundles(this.registry))\n\t\t\t.withMessageContaining(\"Unable to register SSL bundle 'bundle1'\")\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"Unable to watch for reload on update\");\n\t}\n\n\tprivate void pathEndingWith(Set<Path> paths, String... suffixes) {\n\t\tfor (String suffix : suffixes) {\n\t\t\tassertThat(paths).anyMatch((path) -> path.getFileName().toString().endsWith(suffix));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/OrderedTaskDecorator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.core.task.TaskDecorator;\n\n/**\n * {@link TaskDecorator} that is {@link Ordered ordered}.\n *\n * @author Andy Wilkinson\n */\nclass OrderedTaskDecorator implements TaskDecorator, Ordered {\n\n\tprivate final int order;\n\n\tOrderedTaskDecorator() {\n\t\tthis(0);\n\t}\n\n\tOrderedTaskDecorator(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t@Override\n\tpublic Runnable decorate(Runnable runnable) {\n\t\treturn runnable;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/ScheduledBeanLazyInitializationExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.scheduling.annotation.Schedules;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ScheduledBeanLazyInitializationExcludeFilter}.\n *\n * @author Stephane Nicoll\n */\nclass ScheduledBeanLazyInitializationExcludeFilterTests {\n\n\tprivate final ScheduledBeanLazyInitializationExcludeFilter filter = new ScheduledBeanLazyInitializationExcludeFilter();\n\n\t@Test\n\tvoid beanWithScheduledMethodIsDetected() {\n\t\tassertThat(isExcluded(TestBean.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid beanWithSchedulesMethodIsDetected() {\n\t\tassertThat(isExcluded(AnotherTestBean.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid beanWithoutScheduledMethodIsDetected() {\n\t\tassertThat(isExcluded(ScheduledBeanLazyInitializationExcludeFilterTests.class)).isFalse();\n\t}\n\n\tprivate boolean isExcluded(Class<?> type) {\n\t\treturn this.filter.isExcluded(\"test\", new RootBeanDefinition(type), type);\n\t}\n\n\tprivate static final class TestBean {\n\n\t\t@Scheduled\n\t\tvoid doStuff() {\n\t\t}\n\n\t}\n\n\tprivate static final class AnotherTestBean {\n\n\t\t@Schedules({ @Scheduled(fixedRate = 5000), @Scheduled(fixedRate = 2500) })\n\t\tvoid doStuff() {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Consumer;\n\nimport io.micrometer.context.ThreadLocalAccessor;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.support.BeanDefinitionOverrideException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;\nimport org.springframework.boot.task.ThreadPoolTaskExecutorBuilder;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.SyncTaskExecutor;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.core.task.support.CompositeTaskDecorator;\nimport org.springframework.core.task.support.ContextPropagatingTaskDecorator;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.annotation.Async;\nimport org.springframework.scheduling.annotation.AsyncConfigurer;\nimport org.springframework.scheduling.annotation.EnableAsync;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TaskExecutionAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Camille Vienot\n * @author Moritz Halbritter\n * @author Yanming Zhou\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass TaskExecutionAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class);\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskExecutor.class);\n\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskExecutorBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid simpleAsyncTaskExecutorBuilderShouldReadProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.execution.thread-name-prefix=mytest-\",\n\t\t\t\t\t\"spring.task.execution.simple.cancel-remaining-tasks-on-close=true\",\n\t\t\t\t\t\"spring.task.execution.simple.reject-tasks-when-limit-reached=true\",\n\t\t\t\t\t\"spring.task.execution.simple.concurrency-limit=1\",\n\t\t\t\t\t\"spring.task.execution.shutdown.await-termination=true\",\n\t\t\t\t\t\"spring.task.execution.shutdown.await-termination-period=30s\")\n\t\t\t.run(assertSimpleAsyncTaskExecutor((taskExecutor) -> {\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"cancelRemainingTasksOnClose\", true);\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"rejectTasksWhenLimitReached\", true);\n\t\t\t\tassertThat(taskExecutor.getConcurrencyLimit()).isEqualTo(1);\n\t\t\t\tassertThat(taskExecutor.getThreadNamePrefix()).isEqualTo(\"mytest-\");\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"taskTerminationTimeout\", 30000L);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid threadPoolTaskExecutorBuilderShouldApplyCustomSettings() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.execution.pool.queue-capacity=10\",\n\t\t\t\t\"spring.task.execution.pool.core-size=2\", \"spring.task.execution.pool.max-size=4\",\n\t\t\t\t\"spring.task.execution.pool.allow-core-thread-timeout=true\", \"spring.task.execution.pool.keep-alive=5s\",\n\t\t\t\t\"spring.task.execution.pool.shutdown.accept-tasks-after-context-close=true\",\n\t\t\t\t\"spring.task.execution.shutdown.await-termination=true\",\n\t\t\t\t\"spring.task.execution.shutdown.await-termination-period=30s\",\n\t\t\t\t\"spring.task.execution.thread-name-prefix=mytest-\")\n\t\t\t.run(assertThreadPoolTaskExecutor((taskExecutor) -> {\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"queueCapacity\", 10);\n\t\t\t\tassertThat(taskExecutor.getCorePoolSize()).isEqualTo(2);\n\t\t\t\tassertThat(taskExecutor.getMaxPoolSize()).isEqualTo(4);\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"allowCoreThreadTimeOut\", true);\n\t\t\t\tassertThat(taskExecutor.getKeepAliveSeconds()).isEqualTo(5);\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"acceptTasksAfterContextClose\", true);\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"waitForTasksToCompleteOnShutdown\", true);\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"awaitTerminationMillis\", 30000L);\n\t\t\t\tassertThat(taskExecutor.getThreadNamePrefix()).isEqualTo(\"mytest-\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid threadPoolTaskExecutorBuilderWhenHasCustomBuilderShouldUseCustomBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(CustomThreadPoolTaskExecutorBuilderConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class);\n\t\t\tassertThat(context.getBean(ThreadPoolTaskExecutorBuilder.class))\n\t\t\t\t.isSameAs(context.getBean(CustomThreadPoolTaskExecutorBuilderConfig.class).builder);\n\t\t});\n\t}\n\n\t@Test\n\tvoid threadPoolTaskExecutorBuilderShouldUseTaskDecorator() {\n\t\tthis.contextRunner.withBean(TaskDecorator.class, OrderedTaskDecorator::new).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class);\n\t\t\tThreadPoolTaskExecutor executor = context.getBean(ThreadPoolTaskExecutorBuilder.class).build();\n\t\t\tassertThat(executor).extracting(\"taskDecorator\").isSameAs(context.getBean(TaskDecorator.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid threadPoolTaskExecutorBuilderShouldUseCompositeTaskDecorator() {\n\t\tthis.contextRunner.withBean(\"taskDecorator1\", TaskDecorator.class, () -> new OrderedTaskDecorator(1))\n\t\t\t.withBean(\"taskDecorator2\", TaskDecorator.class, () -> new OrderedTaskDecorator(3))\n\t\t\t.withBean(\"taskDecorator3\", TaskDecorator.class, () -> new OrderedTaskDecorator(2))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class);\n\t\t\t\tThreadPoolTaskExecutor executor = context.getBean(ThreadPoolTaskExecutorBuilder.class).build();\n\t\t\t\tassertThat(executor).extracting(\"taskDecorator\")\n\t\t\t\t\t.isInstanceOf(CompositeTaskDecorator.class)\n\t\t\t\t\t.extracting(\"taskDecorators\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(TaskDecorator.class))\n\t\t\t\t\t.containsExactly(context.getBean(\"taskDecorator1\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator3\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator2\", TaskDecorator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenThreadPoolTaskExecutorIsAutoConfiguredThenItIsLazy() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Executor.class).hasBean(\"applicationTaskExecutor\");\n\t\t\tBeanDefinition beanDefinition = context.getSourceApplicationContext()\n\t\t\t\t.getBeanFactory()\n\t\t\t\t.getBeanDefinition(\"applicationTaskExecutor\");\n\t\t\tassertThat(beanDefinition.isLazyInit()).isTrue();\n\t\t\tassertThat(context).getBean(\"applicationTaskExecutor\").isInstanceOf(ThreadPoolTaskExecutor.class);\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenVirtualThreadsAreEnabledThenSimpleAsyncTaskExecutorWithVirtualThreadsIsAutoConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Executor.class).hasBean(\"applicationTaskExecutor\");\n\t\t\tassertThat(context).getBean(\"applicationTaskExecutor\").isInstanceOf(SimpleAsyncTaskExecutor.class);\n\t\t\tSimpleAsyncTaskExecutor taskExecutor = context.getBean(\"applicationTaskExecutor\",\n\t\t\t\t\tSimpleAsyncTaskExecutor.class);\n\t\t\tassertThat(virtualThreadName(taskExecutor)).startsWith(\"task-\");\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenTaskNamePrefixIsConfiguredThenSimpleAsyncTaskExecutorWithVirtualThreadsUsesIt() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.threads.virtual.enabled=true\",\n\t\t\t\t\t\"spring.task.execution.thread-name-prefix=custom-\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleAsyncTaskExecutor taskExecutor = context.getBean(\"applicationTaskExecutor\",\n\t\t\t\t\t\tSimpleAsyncTaskExecutor.class);\n\t\t\t\tassertThat(virtualThreadName(taskExecutor)).startsWith(\"custom-\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenVirtualThreadsAreAvailableButNotEnabledThenThreadPoolTaskExecutorIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Executor.class).hasBean(\"applicationTaskExecutor\");\n\t\t\tassertThat(context).getBean(\"applicationTaskExecutor\").isInstanceOf(ThreadPoolTaskExecutor.class);\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenTaskDecoratorIsDefinedThenSimpleAsyncTaskExecutorWithVirtualThreadsUsesIt() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withBean(TaskDecorator.class, OrderedTaskDecorator::new)\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleAsyncTaskExecutor executor = context.getBean(SimpleAsyncTaskExecutor.class);\n\t\t\t\tassertThat(executor).extracting(\"taskDecorator\").isSameAs(context.getBean(TaskDecorator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenTaskDecoratorsAreDefinedThenSimpleAsyncTaskExecutorWithVirtualThreadsUsesThem() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withBean(\"taskDecorator1\", TaskDecorator.class, () -> new OrderedTaskDecorator(1))\n\t\t\t.withBean(\"taskDecorator2\", TaskDecorator.class, () -> new OrderedTaskDecorator(3))\n\t\t\t.withBean(\"taskDecorator3\", TaskDecorator.class, () -> new OrderedTaskDecorator(2))\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleAsyncTaskExecutor executor = context.getBean(SimpleAsyncTaskExecutor.class);\n\t\t\t\tassertThat(executor).extracting(\"taskDecorator\")\n\t\t\t\t\t.isInstanceOf(CompositeTaskDecorator.class)\n\t\t\t\t\t.extracting(\"taskDecorators\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(TaskDecorator.class))\n\t\t\t\t\t.containsExactly(context.getBean(\"taskDecorator1\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator3\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator2\", TaskDecorator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid simpleAsyncTaskExecutorBuilderUsesPlatformThreadsByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tSimpleAsyncTaskExecutorBuilder builder = context.getBean(SimpleAsyncTaskExecutorBuilder.class);\n\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"virtualThreads\", null);\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid simpleAsyncTaskExecutorBuilderUsesVirtualThreadsWhenEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tSimpleAsyncTaskExecutorBuilder builder = context.getBean(SimpleAsyncTaskExecutorBuilder.class);\n\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"virtualThreads\", true);\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/services/io.micrometer.context.ThreadLocalAccessor\",\n\t\t\tcontent = \"org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfigurationTests$TestThreadLocalAccessor\")\n\tvoid asyncTaskExecutorShouldNotNotRegisterContextPropagatingTaskDecoratorByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(AsyncConfiguration.class, TestBean.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ContextPropagatingTaskDecorator.class);\n\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\tTestThreadLocalHolder.setValue(\"from-context\");\n\t\t\tString text = bean.echoContext().get();\n\t\t\tassertThat(text).contains(\"task-\").endsWith(\"null\");\n\t\t});\n\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/services/io.micrometer.context.ThreadLocalAccessor\",\n\t\t\tcontent = \"org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfigurationTests$TestThreadLocalAccessor\")\n\tvoid asyncTaskExecutorWhenContextPropagationIsEnabledShouldRegisterBean() {\n\t\tthis.contextRunner.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.withPropertyValues(\"spring.task.execution.propagate-context=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ContextPropagatingTaskDecorator.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tTestThreadLocalHolder.setValue(\"from-context\");\n\t\t\t\tString text = bean.echoContext().get();\n\t\t\t\tassertThat(text).contains(\"task-\").endsWith(\"from-context\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskExecutorWhenHasCustomTaskExecutorShouldBackOff() {\n\t\tthis.contextRunner.withBean(\"customTaskExecutor\", Executor.class, SyncTaskExecutor::new).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Executor.class);\n\t\t\tassertThat(context.getBean(Executor.class)).isSameAs(context.getBean(\"customTaskExecutor\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid taskExecutorWhenModeIsAutoAndHasCustomTaskExecutorShouldBackOff() {\n\t\tthis.contextRunner.withBean(\"customTaskExecutor\", Executor.class, SyncTaskExecutor::new)\n\t\t\t.withPropertyValues(\"spring.task.execution.mode=auto\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Executor.class);\n\t\t\t\tassertThat(context.getBean(Executor.class)).isSameAs(context.getBean(\"customTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskExecutorWhenModeIsForceAndHasCustomTaskExecutorShouldCreateApplicationTaskExecutor() {\n\t\tthis.contextRunner.withBean(\"customTaskExecutor\", Executor.class, SyncTaskExecutor::new)\n\t\t\t.withPropertyValues(\"spring.task.execution.mode=force\")\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(Executor.class)).hasSize(2)\n\t\t\t\t.containsKeys(\"customTaskExecutor\", \"applicationTaskExecutor\"));\n\t}\n\n\t@Test\n\tvoid taskExecutorWhenModeIsForceAndHasCustomTaskExecutorWithReservedNameShouldThrowException() {\n\t\tthis.contextRunner.withBean(\"applicationTaskExecutor\", Executor.class, SyncTaskExecutor::new)\n\t\t\t.withPropertyValues(\"spring.task.execution.mode=force\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.isInstanceOf(BeanDefinitionOverrideException.class));\n\t}\n\n\t@Test\n\tvoid taskExecutorWhenModeIsForceAndHasCustomBFPPCanRestoreTaskExecutorAlias() {\n\t\tthis.contextRunner.withBean(\"customTaskExecutor\", Executor.class, SyncTaskExecutor::new)\n\t\t\t.withPropertyValues(\"spring.task.execution.mode=force\")\n\t\t\t.withBean(BeanFactoryPostProcessor.class,\n\t\t\t\t\t() -> (beanFactory) -> beanFactory.registerAlias(\"applicationTaskExecutor\", \"taskExecutor\"))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2)\n\t\t\t\t\t.containsKeys(\"customTaskExecutor\", \"applicationTaskExecutor\");\n\t\t\t\tassertThat(context).hasBean(\"taskExecutor\");\n\t\t\t\tassertThat(context.getBean(\"taskExecutor\")).isSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenVirtualThreadsAreEnabledAndCustomTaskExecutorIsDefinedThenSimpleAsyncTaskExecutorThatUsesVirtualThreadsBacksOff() {\n\t\tthis.contextRunner.withBean(\"customTaskExecutor\", Executor.class, SyncTaskExecutor::new)\n\t\t\t.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Executor.class);\n\t\t\t\tassertThat(context.getBean(Executor.class)).isSameAs(context.getBean(\"customTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesAutoConfiguredOneByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\")\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context).hasSingleBean(TaskExecutor.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"auto-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesCustomExecutorIfPresent() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\")\n\t\t\t.withBean(\"customTaskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom-task-\"))\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context).hasSingleBean(Executor.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"custom-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesAutoConfiguredExecutorWhenModeIsForceAndHasCustomTaskExecutor() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\",\n\t\t\t\t\t\"spring.task.execution.mode=force\")\n\t\t\t.withBean(\"customTaskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom-task-\"))\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"auto-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesAutoConfiguredExecutorWhenModeIsForceAndHasCustomTaskExecutorWithReservedName() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\",\n\t\t\t\t\t\"spring.task.execution.mode=force\")\n\t\t\t.withBean(\"taskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom-task-\"))\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"auto-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesAsyncConfigurerWhenModeIsForce() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\",\n\t\t\t\t\t\"spring.task.execution.mode=force\")\n\t\t\t.withBean(\"taskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom-task-\"))\n\t\t\t.withBean(\"customAsyncConfigurer\", AsyncConfigurer.class, () -> new AsyncConfigurer() {\n\t\t\t\t@Override\n\t\t\t\tpublic Executor getAsyncExecutor() {\n\t\t\t\t\treturn createCustomAsyncExecutor(\"async-task-\");\n\t\t\t\t}\n\t\t\t})\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2)\n\t\t\t\t\t.containsOnlyKeys(\"taskExecutor\", \"applicationTaskExecutor\");\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"async-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncLinksToCustomTaskExecutorWhenAsyncConfigurerOverridesIt() {\n\t\tExecutor executor = createCustomAsyncExecutor(\"async-task-\");\n\t\tAsyncUncaughtExceptionHandler asyncUncaughtExceptionHandler = mock(AsyncUncaughtExceptionHandler.class);\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\")\n\t\t\t.withBean(\"taskScheduler\", TaskScheduler.class, () -> mock(ThreadPoolTaskScheduler.class))\n\t\t\t.withBean(\"customAsyncConfigurer\", AsyncConfigurer.class, () -> new AsyncConfigurer() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable Executor getAsyncExecutor() {\n\t\t\t\t\treturn executor;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {\n\t\t\t\t\treturn asyncUncaughtExceptionHandler;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).containsOnlyKeys(\"applicationTaskExecutor\",\n\t\t\t\t\t\t\"taskScheduler\");\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"async-task-\").contains(\"something\");\n\t\t\t\tAsyncConfigurer asyncConfigurer = context.getBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(asyncConfigurer.getAsyncExecutor()).isEqualTo(executor);\n\t\t\t\tassertThat(asyncConfigurer.getAsyncUncaughtExceptionHandler()).isEqualTo(asyncUncaughtExceptionHandler);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncLinksToApplicationTaskExecutorWhenAsyncConfigurerDoesNotOverrideIt() {\n\t\tAsyncUncaughtExceptionHandler asyncUncaughtExceptionHandler = mock(AsyncUncaughtExceptionHandler.class);\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\")\n\t\t\t.withBean(\"taskScheduler\", TaskScheduler.class, () -> mock(ThreadPoolTaskScheduler.class))\n\t\t\t.withBean(\"customAsyncConfigurer\", AsyncConfigurer.class, () -> new AsyncConfigurer() {\n\t\t\t\t@Override\n\t\t\t\tpublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {\n\t\t\t\t\treturn asyncUncaughtExceptionHandler;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).containsOnlyKeys(\"applicationTaskExecutor\",\n\t\t\t\t\t\t\"taskScheduler\");\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"auto-task-\").contains(\"something\");\n\t\t\t\tassertThat(context.getBean(AsyncConfigurer.class).getAsyncUncaughtExceptionHandler())\n\t\t\t\t\t.isEqualTo(asyncUncaughtExceptionHandler);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesAutoConfiguredExecutorWhenModeIsForceAndHasPrimaryCustomTaskExecutor() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\",\n\t\t\t\t\t\"spring.task.execution.mode=force\")\n\t\t\t.withBean(\"taskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom-task-\"),\n\t\t\t\t\t(beanDefinition) -> beanDefinition.setPrimary(true))\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncConfigurer.class);\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"auto-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableAsyncUsesAutoConfiguredOneByDefaultEvenThoughSchedulingIsConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.execution.thread-name-prefix=auto-task-\")\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.withUserConfiguration(AsyncConfiguration.class, SchedulingConfiguration.class, TestBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tString text = bean.echo(\"something\").get();\n\t\t\t\tassertThat(text).contains(\"auto-task-\").contains(\"something\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldAliasApplicationTaskExecutorToBootstrapExecutor() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Executor.class)\n\t\t\t\t.hasBean(\"applicationTaskExecutor\")\n\t\t\t\t.hasBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\tassertThat(context.getAliases(\"applicationTaskExecutor\"))\n\t\t\t\t.containsExactly(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\tassertThat(context.getBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME))\n\t\t\t\t.isSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotAliasApplicationTaskExecutorWhenBootstrapExecutorIsDefined() {\n\t\tthis.contextRunner.withBean(\"applicationTaskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"app-\"))\n\t\t\t.withBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME, Executor.class,\n\t\t\t\t\t() -> createCustomAsyncExecutor(\"bootstrap-\"))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2);\n\t\t\t\tassertThat(context).hasBean(\"applicationTaskExecutor\")\n\t\t\t\t\t.hasBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\t\tassertThat(context.getAliases(\"applicationTaskExecutor\")).isEmpty();\n\t\t\t\tassertThat(context.getBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME))\n\t\t\t\t\t.isNotSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotAliasApplicationTaskExecutorWhenApplicationTaskExecutorIsMissing() {\n\t\tthis.contextRunner.withBean(\"customExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom-\"))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Executor.class)\n\t\t\t\t.hasBean(\"customExecutor\")\n\t\t\t\t.doesNotHaveBean(\"applicationTaskExecutor\")\n\t\t\t\t.doesNotHaveBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME));\n\t}\n\n\t@Test\n\tvoid shouldNotAliasApplicationTaskExecutorWhenBootstrapExecutorRegisteredAsSingleton() {\n\t\tthis.contextRunner.withBean(\"applicationTaskExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"app-\"))\n\t\t\t.withInitializer((context) -> context.getBeanFactory()\n\t\t\t\t.registerSingleton(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME,\n\t\t\t\t\t\tcreateCustomAsyncExecutor(\"bootstrap-\")))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2);\n\t\t\t\tassertThat(context).hasBean(\"applicationTaskExecutor\")\n\t\t\t\t\t.hasBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\t\tassertThat(context.getAliases(\"applicationTaskExecutor\")).isEmpty();\n\t\t\t\tassertThat(context.getBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME))\n\t\t\t\t\t.isNotSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotAliasApplicationTaskExecutorWhenBootstrapExecutorAliasIsDefined() {\n\t\tExecutor executor = Runnable::run;\n\t\tthis.contextRunner.withBean(\"applicationTaskExecutor\", Executor.class, () -> executor)\n\t\t\t.withBean(\"customExecutor\", Executor.class, () -> createCustomAsyncExecutor(\"custom\"))\n\t\t\t.withInitializer((context) -> context.getBeanFactory()\n\t\t\t\t.registerAlias(\"customExecutor\", ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Executor.class)).hasSize(2);\n\t\t\t\tassertThat(context).hasBean(\"applicationTaskExecutor\").hasBean(\"customExecutor\");\n\t\t\t\tassertThat(context.getAliases(\"applicationTaskExecutor\")).isEmpty();\n\t\t\t\tassertThat(context.getAliases(\"customExecutor\"))\n\t\t\t\t\t.contains(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME);\n\t\t\t\tassertThat(context.getBean(ConfigurableApplicationContext.BOOTSTRAP_EXECUTOR_BEAN_NAME))\n\t\t\t\t\t.isNotSameAs(context.getBean(\"applicationTaskExecutor\"))\n\t\t\t\t\t.isSameAs(context.getBean(\"customExecutor\"));\n\t\t\t});\n\t}\n\n\tprivate Executor createCustomAsyncExecutor(String threadNamePrefix) {\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();\n\t\texecutor.setThreadNamePrefix(threadNamePrefix);\n\t\treturn executor;\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertThreadPoolTaskExecutor(\n\t\t\tConsumer<ThreadPoolTaskExecutor> taskExecutor) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class);\n\t\t\tThreadPoolTaskExecutorBuilder builder = context.getBean(ThreadPoolTaskExecutorBuilder.class);\n\t\t\ttaskExecutor.accept(builder.build());\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertSimpleAsyncTaskExecutor(\n\t\t\tConsumer<SimpleAsyncTaskExecutor> taskExecutor) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskExecutorBuilder.class);\n\t\t\tSimpleAsyncTaskExecutorBuilder builder = context.getBean(SimpleAsyncTaskExecutorBuilder.class);\n\t\t\ttaskExecutor.accept(builder.build());\n\t\t};\n\t}\n\n\tprivate String virtualThreadName(SimpleAsyncTaskExecutor taskExecutor) throws InterruptedException {\n\t\tAtomicReference<Thread> threadReference = new AtomicReference<>();\n\t\tCountDownLatch latch = new CountDownLatch(1);\n\t\ttaskExecutor.execute(() -> {\n\t\t\tThread currentThread = Thread.currentThread();\n\t\t\tthreadReference.set(currentThread);\n\t\t\tlatch.countDown();\n\t\t});\n\t\tassertThat(latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\tThread thread = threadReference.get();\n\t\tassertThat(thread).isNotNull();\n\t\tassertThat(thread).extracting(\"virtual\").as(\"%s is virtual\", thread).isEqualTo(true);\n\t\treturn thread.getName();\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"META-INF/services/io.micrometer.context.ThreadLocalAccessor\",\n\t\t\tcontent = \"org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfigurationTests.TestThreadLocalAccessor\")\n\t@interface WithThreadLocalAccessor {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomThreadPoolTaskExecutorBuilderConfig {\n\n\t\tprivate final ThreadPoolTaskExecutorBuilder builder = new ThreadPoolTaskExecutorBuilder();\n\n\t\t@Bean\n\t\tThreadPoolTaskExecutorBuilder customThreadPoolTaskExecutorBuilder() {\n\t\t\treturn this.builder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAsync\n\tstatic class AsyncConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableScheduling\n\tstatic class SchedulingConfiguration {\n\n\t}\n\n\tstatic class TestBean {\n\n\t\t@Async\n\t\tFuture<String> echo(String text) {\n\t\t\treturn CompletableFuture.completedFuture(Thread.currentThread().getName() + \" \" + text);\n\t\t}\n\n\t\t@Async\n\t\tFuture<String> echoContext() {\n\t\t\treturn CompletableFuture\n\t\t\t\t.completedFuture(Thread.currentThread().getName() + \" \" + TestThreadLocalHolder.getValue());\n\t\t}\n\n\t}\n\n\tstatic class TestThreadLocalHolder {\n\n\t\tprivate static final ThreadLocal<String> holder = new ThreadLocal<>();\n\n\t\tstatic void setValue(String value) {\n\t\t\tholder.set(value);\n\t\t}\n\n\t\tstatic String getValue() {\n\t\t\treturn holder.get();\n\t\t}\n\n\t\tstatic void reset() {\n\t\t\tholder.remove();\n\t\t}\n\n\t}\n\n\tpublic static class TestThreadLocalAccessor implements ThreadLocalAccessor<String> {\n\n\t\tstatic final String KEY = \"test.threadlocal\";\n\n\t\t@Override\n\t\tpublic Object key() {\n\t\t\treturn KEY;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getValue() {\n\t\t\treturn TestThreadLocalHolder.getValue();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setValue(String value) {\n\t\t\tTestThreadLocalHolder.setValue(value);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setValue() {\n\t\t\tTestThreadLocalHolder.reset();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.task;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.task.SimpleAsyncTaskSchedulerBuilder;\nimport org.springframework.boot.task.SimpleAsyncTaskSchedulerCustomizer;\nimport org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder;\nimport org.springframework.boot.task.ThreadPoolTaskSchedulerCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.TaskDecorator;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.core.task.support.CompositeTaskDecorator;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.scheduling.annotation.SchedulingConfigurer;\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\nimport org.springframework.scheduling.config.ScheduledTaskRegistrar;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TaskSchedulingAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass TaskSchedulingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class));\n\n\t@Test\n\tvoid noSchedulingDoesNotExposeTaskScheduler() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(TaskScheduler.class));\n\t}\n\n\t@Test\n\tvoid noSchedulingDoesNotExposeScheduledBeanLazyInitializationExcludeFilter() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ScheduledBeanLazyInitializationExcludeFilter.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskSchedulerBuilder.class);\n\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskScheduler.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableSchedulingWithNoTaskExecutorAutoConfiguresOne() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.scheduling.shutdown.await-termination=true\",\n\t\t\t\t\t\"spring.task.scheduling.shutdown.await-termination-period=30s\",\n\t\t\t\t\t\"spring.task.scheduling.thread-name-prefix=scheduling-test-\")\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TaskExecutor.class);\n\t\t\t\tTaskExecutor taskExecutor = context.getBean(TaskExecutor.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tassertThat(bean.latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"waitForTasksToCompleteOnShutdown\", true);\n\t\t\t\tassertThat(taskExecutor).hasFieldOrPropertyWithValue(\"awaitTerminationMillis\", 30000L);\n\t\t\t\tassertThat(bean.threadNames).allMatch((name) -> name.contains(\"scheduling-test-\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid simpleAsyncTaskSchedulerBuilderShouldReadProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.task.scheduling.simple.concurrency-limit=1\",\n\t\t\t\t\t\"spring.task.scheduling.thread-name-prefix=scheduling-test-\",\n\t\t\t\t\t\"spring.task.scheduling.shutdown.await-termination=true\",\n\t\t\t\t\t\"spring.task.scheduling.shutdown.await-termination-period=30s\")\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tSimpleAsyncTaskSchedulerBuilder builder = context.getBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"threadNamePrefix\", \"scheduling-test-\");\n\t\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"concurrencyLimit\", 1);\n\t\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"taskTerminationTimeout\", Duration.ofSeconds(30));\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid simpleAsyncTaskSchedulerBuilderShouldUseVirtualThreadsIfEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tSimpleAsyncTaskSchedulerBuilder builder = context.getBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"virtualThreads\", true);\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid simpleAsyncTaskSchedulerBuilderShouldUsePlatformThreadsByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\tSimpleAsyncTaskSchedulerBuilder builder = context.getBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"virtualThreads\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid simpleAsyncTaskSchedulerBuilderShouldApplyTaskDecorator() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.withBean(TaskDecorator.class, OrderedTaskDecorator::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tassertThat(context).hasSingleBean(TaskDecorator.class);\n\t\t\t\tTaskDecorator taskDecorator = context.getBean(TaskDecorator.class);\n\t\t\t\tSimpleAsyncTaskScheduler scheduler = context.getBean(SimpleAsyncTaskSchedulerBuilder.class).build();\n\t\t\t\tassertThat(scheduler).extracting(\"taskDecorator\").isSameAs(taskDecorator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid simpleAsyncTaskSchedulerBuilderShouldApplyCompositeTaskDecorator() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.withBean(\"taskDecorator1\", TaskDecorator.class, () -> new OrderedTaskDecorator(1))\n\t\t\t.withBean(\"taskDecorator2\", TaskDecorator.class, () -> new OrderedTaskDecorator(3))\n\t\t\t.withBean(\"taskDecorator3\", TaskDecorator.class, () -> new OrderedTaskDecorator(2))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tSimpleAsyncTaskScheduler scheduler = context.getBean(SimpleAsyncTaskSchedulerBuilder.class).build();\n\t\t\t\tassertThat(scheduler).extracting(\"taskDecorator\")\n\t\t\t\t\t.isInstanceOf(CompositeTaskDecorator.class)\n\t\t\t\t\t.extracting(\"taskDecorators\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(TaskDecorator.class))\n\t\t\t\t\t.containsExactly(context.getBean(\"taskDecorator1\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator3\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator2\", TaskDecorator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid threadPoolTaskSchedulerBuilderShouldApplyTaskDecorator() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.withBean(TaskDecorator.class, OrderedTaskDecorator::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskSchedulerBuilder.class);\n\t\t\t\tassertThat(context).hasSingleBean(TaskDecorator.class);\n\t\t\t\tTaskDecorator taskDecorator = context.getBean(TaskDecorator.class);\n\t\t\t\tThreadPoolTaskScheduler scheduler = context.getBean(ThreadPoolTaskSchedulerBuilder.class).build();\n\t\t\t\tassertThat(scheduler).extracting(\"taskDecorator\").isSameAs(taskDecorator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid threadPoolTaskSchedulerBuilderShouldApplyCompositeTaskDecorator() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.withBean(\"taskDecorator1\", TaskDecorator.class, () -> new OrderedTaskDecorator(1))\n\t\t\t.withBean(\"taskDecorator2\", TaskDecorator.class, () -> new OrderedTaskDecorator(3))\n\t\t\t.withBean(\"taskDecorator3\", TaskDecorator.class, () -> new OrderedTaskDecorator(2))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ThreadPoolTaskSchedulerBuilder.class);\n\t\t\t\tThreadPoolTaskScheduler scheduler = context.getBean(ThreadPoolTaskSchedulerBuilder.class).build();\n\t\t\t\tassertThat(scheduler).extracting(\"taskDecorator\")\n\t\t\t\t\t.isInstanceOf(CompositeTaskDecorator.class)\n\t\t\t\t\t.extracting(\"taskDecorators\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(TaskDecorator.class))\n\t\t\t\t\t.containsExactly(context.getBean(\"taskDecorator1\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator3\", TaskDecorator.class),\n\t\t\t\t\t\t\tcontext.getBean(\"taskDecorator2\", TaskDecorator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid simpleAsyncTaskSchedulerBuilderShouldApplyCustomizers() {\n\t\tSimpleAsyncTaskSchedulerCustomizer customizer = (scheduler) -> {\n\t\t};\n\t\tthis.contextRunner.withBean(SimpleAsyncTaskSchedulerCustomizer.class, () -> customizer)\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tSimpleAsyncTaskSchedulerBuilder builder = context.getBean(SimpleAsyncTaskSchedulerBuilder.class);\n\t\t\t\tassertThat(builder).extracting(\"customizers\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.collection(SimpleAsyncTaskSchedulerCustomizer.class))\n\t\t\t\t\t.containsExactly(customizer);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSchedulingWithNoTaskExecutorAppliesCustomizers() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.task.scheduling.thread-name-prefix=scheduling-test-\")\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class, ThreadPoolTaskSchedulerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TaskExecutor.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tassertThat(bean.latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\t\t\tassertThat(bean.threadNames).allMatch((name) -> name.contains(\"customized-scheduler-\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSchedulingWithExistingTaskSchedulerBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(SchedulingConfiguration.class, TaskSchedulerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TaskScheduler.class);\n\t\t\t\tassertThat(context.getBean(TaskScheduler.class)).isInstanceOf(TestTaskScheduler.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tassertThat(bean.latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\t\t\tassertThat(bean.threadNames).containsExactly(\"test-1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSchedulingWithExistingScheduledExecutorServiceBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class, ScheduledExecutorServiceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(TaskScheduler.class);\n\t\t\t\tassertThat(context).hasSingleBean(ScheduledExecutorService.class);\n\t\t\t\tTestBean bean = context.getBean(TestBean.class);\n\t\t\t\tassertThat(bean.latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\t\t\tassertThat(bean.threadNames).allMatch((name) -> name.contains(\"pool-\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSchedulingWithLazyInitializationInvokeScheduledMethods() {\n\t\tList<String> threadNames = new ArrayList<>();\n\t\tnew ApplicationContextRunner()\n\t\t\t.withInitializer(\n\t\t\t\t\t(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))\n\t\t\t.withPropertyValues(\"spring.task.scheduling.thread-name-prefix=scheduling-test-\")\n\t\t\t.withBean(LazyTestBean.class, () -> new LazyTestBean(threadNames))\n\t\t\t.withUserConfiguration(SchedulingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\t// No lazy lookup.\n\t\t\t\tAwaitility.waitAtMost(Duration.ofSeconds(3)).until(() -> !threadNames.isEmpty());\n\t\t\t\tassertThat(threadNames).allMatch((name) -> name.contains(\"scheduling-test-\"));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableScheduling\n\tstatic class SchedulingConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TaskSchedulerConfiguration {\n\n\t\t@Bean\n\t\tTaskScheduler customTaskScheduler() {\n\t\t\treturn new TestTaskScheduler();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ScheduledExecutorServiceConfiguration {\n\n\t\t@Bean\n\t\tScheduledExecutorService customScheduledExecutorService() {\n\t\t\treturn Executors.newScheduledThreadPool(2);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ThreadPoolTaskSchedulerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tThreadPoolTaskSchedulerCustomizer testTaskSchedulerCustomizer() {\n\t\t\treturn ((taskScheduler) -> taskScheduler.setThreadNamePrefix(\"customized-scheduler-\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SchedulingConfigurerConfiguration implements SchedulingConfigurer {\n\n\t\tprivate final TaskScheduler taskScheduler = new TestTaskScheduler();\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\ttaskRegistrar.setScheduler(this.taskScheduler);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestBean testBean() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\tstatic class TestBean {\n\n\t\tprivate final Set<String> threadNames = ConcurrentHashMap.newKeySet();\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\t@Scheduled(fixedRate = 60000)\n\t\tvoid accumulate() {\n\t\t\tthis.threadNames.add(Thread.currentThread().getName());\n\t\t\tthis.latch.countDown();\n\t\t}\n\n\t}\n\n\tstatic class LazyTestBean {\n\n\t\tprivate final List<String> threadNames;\n\n\t\tLazyTestBean(List<String> threadNames) {\n\t\t\tthis.threadNames = threadNames;\n\t\t}\n\n\t\t@Scheduled(fixedRate = 2000)\n\t\tvoid accumulate() {\n\t\t\tthis.threadNames.add(Thread.currentThread().getName());\n\t\t}\n\n\t}\n\n\tstatic class TestTaskScheduler extends ThreadPoolTaskScheduler {\n\n\t\tTestTaskScheduler() {\n\t\t\tsetPoolSize(1);\n\t\t\tsetThreadNamePrefix(\"test-\");\n\t\t\tafterPropertiesSet();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/template/TemplateAvailabilityProvidersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link TemplateAvailabilityProviders}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass TemplateAvailabilityProvidersTests {\n\n\tprivate TemplateAvailabilityProviders providers;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate TemplateAvailabilityProvider provider;\n\n\tprivate final String view = \"view\";\n\n\tprivate final ClassLoader classLoader = getClass().getClassLoader();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ResourceLoader resourceLoader;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.providers = new TemplateAvailabilityProviders(Collections.singleton(this.provider));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenApplicationContextIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TemplateAvailabilityProviders((ApplicationContext) null))\n\t\t\t.withMessageContaining(\"'applicationContext' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\t@WithTestTemplateAvailabilityProvider\n\tvoid createWhenUsingApplicationContextShouldLoadProviders() {\n\t\tApplicationContext applicationContext = mock(ApplicationContext.class);\n\t\tgiven(applicationContext.getClassLoader()).willReturn(Thread.currentThread().getContextClassLoader());\n\t\tTemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(applicationContext);\n\t\tassertThat(providers.getProviders()).extracting((provider) -> (Class) provider.getClass())\n\t\t\t.containsExactly(TestTemplateAvailabilityProvider.class);\n\t\tthen(applicationContext).should().getClassLoader();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenClassLoaderIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TemplateAvailabilityProviders((ClassLoader) null))\n\t\t\t.withMessageContaining(\"'classLoader' must not be null\");\n\t}\n\n\t@Test\n\t@WithTestTemplateAvailabilityProvider\n\tvoid createWhenUsingClassLoaderShouldLoadProviders() {\n\t\tTemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(\n\t\t\t\tThread.currentThread().getContextClassLoader());\n\t\tassertThat(providers.getProviders()).isNotEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenProvidersIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TemplateAvailabilityProviders((Collection<TemplateAvailabilityProvider>) null))\n\t\t\t.withMessageContaining(\"'providers' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenUsingProvidersShouldUseProviders() {\n\t\tTemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(\n\t\t\t\tCollections.singleton(this.provider));\n\t\tassertThat(providers.getProviders()).containsOnly(this.provider);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getProviderWhenApplicationContextIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.providers.getProvider(this.view, null))\n\t\t\t.withMessageContaining(\"'applicationContext' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getProviderWhenViewIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.providers.getProvider(null, this.environment, this.classLoader, this.resourceLoader))\n\t\t\t.withMessageContaining(\"'view' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getProviderWhenEnvironmentIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.providers.getProvider(this.view, null, this.classLoader, this.resourceLoader))\n\t\t\t.withMessageContaining(\"'environment' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getProviderWhenClassLoaderIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.providers.getProvider(this.view, this.environment, null, this.resourceLoader))\n\t\t\t.withMessageContaining(\"'classLoader' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getProviderWhenResourceLoaderIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.providers.getProvider(this.view, this.environment, this.classLoader, null))\n\t\t\t.withMessageContaining(\"'resourceLoader' must not be null\");\n\t}\n\n\t@Test\n\tvoid getProviderWhenNoneMatchShouldReturnNull() {\n\t\tTemplateAvailabilityProvider found = this.providers.getProvider(this.view, this.environment, this.classLoader,\n\t\t\t\tthis.resourceLoader);\n\t\tassertThat(found).isNull();\n\t\tthen(this.provider).should()\n\t\t\t.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t}\n\n\t@Test\n\tvoid getProviderWhenMatchShouldReturnProvider() {\n\t\tgiven(this.provider.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader))\n\t\t\t.willReturn(true);\n\t\tTemplateAvailabilityProvider found = this.providers.getProvider(this.view, this.environment, this.classLoader,\n\t\t\t\tthis.resourceLoader);\n\t\tassertThat(found).isSameAs(this.provider);\n\n\t}\n\n\t@Test\n\tvoid getProviderShouldCacheMatchResult() {\n\t\tgiven(this.provider.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader))\n\t\t\t.willReturn(true);\n\t\tthis.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t\tthis.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t\tthen(this.provider).should()\n\t\t\t.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t}\n\n\t@Test\n\tvoid getProviderShouldCacheNoMatchResult() {\n\t\tthis.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t\tthis.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t\tthen(this.provider).should()\n\t\t\t.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t}\n\n\t@Test\n\tvoid getProviderWhenCacheDisabledShouldNotUseCache() {\n\t\tgiven(this.provider.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader))\n\t\t\t.willReturn(true);\n\t\tthis.environment.setProperty(\"spring.template.provider.cache\", \"false\");\n\t\tthis.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t\tthis.providers.getProvider(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t\tthen(this.provider).should(times(2))\n\t\t\t.isTemplateAvailable(this.view, this.environment, this.classLoader, this.resourceLoader);\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\"\n\t\t\t\t\t+ \"org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvidersTests$TestTemplateAvailabilityProvider\")\n\t@interface WithTestTemplateAvailabilityProvider {\n\n\t}\n\n\tstatic class TestTemplateAvailabilityProvider implements TemplateAvailabilityProvider {\n\n\t\t@Override\n\t\tpublic boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\t\tResourceLoader resourceLoader) {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/template/TemplateRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.template;\n\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TemplateRuntimeHints}.\n *\n * @author Stephane Nicoll\n */\nclass TemplateRuntimeHintsTests {\n\n\tprivate static final Predicate<RuntimeHints> TEST_PREDICATE = RuntimeHintsPredicates.resource()\n\t\t.forResource(\"templates/something/hello.html\");\n\n\t@Test\n\tvoid templateRuntimeHintsIsRegistered() {\n\t\tIterable<RuntimeHintsRegistrar> registrar = AotServices.factories().load(RuntimeHintsRegistrar.class);\n\t\tassertThat(registrar).anyMatch(TemplateRuntimeHints.class::isInstance);\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/test.html\")\n\tvoid contributeWhenTemplateLocationExists() {\n\t\tRuntimeHints runtimeHints = contribute(Thread.currentThread().getContextClassLoader());\n\t\tassertThat(TEST_PREDICATE.test(runtimeHints)).isTrue();\n\t}\n\n\t@Test\n\tvoid contributeWhenTemplateLocationDoesNotExist() {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(new ClassPathResource(\"templates\"));\n\t\tRuntimeHints runtimeHints = contribute(classLoader);\n\t\tassertThat(TEST_PREDICATE.test(runtimeHints)).isFalse();\n\t}\n\n\tprivate RuntimeHints contribute(ClassLoader classLoader) {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew TemplateRuntimeHints().registerHints(runtimeHints, classLoader);\n\t\treturn runtimeHints;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/ConditionalOnEnabledResourceChainTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnEnabledResourceChain @ConditionalOnEnabledResourceChain}.\n *\n * @author Stephane Nicoll\n */\nclass ConditionalOnEnabledResourceChainTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid disabledByDefault() {\n\t\tload();\n\t\tassertThat(this.context.containsBean(\"foo\")).isFalse();\n\t}\n\n\t@Test\n\tvoid disabledExplicitly() {\n\t\tload(\"spring.web.resources.chain.enabled:false\");\n\t\tassertThat(this.context.containsBean(\"foo\")).isFalse();\n\t}\n\n\t@Test\n\tvoid enabledViaMainEnabledFlag() {\n\t\tload(\"spring.web.resources.chain.enabled:true\");\n\t\tassertThat(this.context.containsBean(\"foo\")).isTrue();\n\t}\n\n\t@Test\n\tvoid enabledViaFixedStrategyFlag() {\n\t\tload(\"spring.web.resources.chain.strategy.fixed.enabled:true\");\n\t\tassertThat(this.context.containsBean(\"foo\")).isTrue();\n\t}\n\n\t@Test\n\tvoid enabledViaContentStrategyFlag() {\n\t\tload(\"spring.web.resources.chain.strategy.content.enabled:true\");\n\t\tassertThat(this.context.containsBean(\"foo\")).isTrue();\n\t}\n\n\tprivate void load(String... environment) {\n\t\tthis.context.register(Config.class);\n\t\tTestPropertyValues.of(environment).applyTo(this.context);\n\t\tthis.context.refresh();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\t@ConditionalOnEnabledResourceChain\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebPropertiesResourcesBindingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Binding tests for {@link WebProperties.Resources}.\n *\n * @author Stephane Nicoll\n */\nclass WebPropertiesResourcesBindingTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfiguration.class);\n\n\t@Test\n\tvoid staticLocationsExpandArray() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.resources.static-locations[0]=classpath:/one/\",\n\t\t\t\t\t\"spring.web.resources.static-locations[1]=classpath:/two\",\n\t\t\t\t\t\"spring.web.resources.static-locations[2]=classpath:/three/\",\n\t\t\t\t\t\"spring.web.resources.static-locations[3]=classpath:/four\",\n\t\t\t\t\t\"spring.web.resources.static-locations[4]=classpath:/five/\",\n\t\t\t\t\t\"spring.web.resources.static-locations[5]=classpath:/six\")\n\t\t\t.run(assertResourceProperties((properties) -> assertThat(properties.getStaticLocations()).contains(\n\t\t\t\t\t\"classpath:/one/\", \"classpath:/two/\", \"classpath:/three/\", \"classpath:/four/\", \"classpath:/five/\",\n\t\t\t\t\t\"classpath:/six/\")));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertResourceProperties(Consumer<Resources> consumer) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(WebProperties.class);\n\t\t\tconsumer.accept(context.getBean(WebProperties.class).getResources());\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WebProperties.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebPropertiesResourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources.Cache;\nimport org.springframework.http.CacheControl;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebProperties.Resources}.\n *\n * @author Stephane Nicoll\n * @author Kristine Jetzke\n */\nclass WebPropertiesResourcesTests {\n\n\tprivate final Resources properties = new WebProperties().getResources();\n\n\t@Test\n\tvoid resourceChainNoCustomization() {\n\t\tassertThat(this.properties.getChain().getEnabled()).isNull();\n\t}\n\n\t@Test\n\tvoid resourceChainStrategyEnabled() {\n\t\tthis.properties.getChain().getStrategy().getFixed().setEnabled(true);\n\t\tassertThat(this.properties.getChain().getEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid resourceChainEnabled() {\n\t\tthis.properties.getChain().setEnabled(true);\n\t\tassertThat(this.properties.getChain().getEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid resourceChainDisabled() {\n\t\tthis.properties.getChain().setEnabled(false);\n\t\tassertThat(this.properties.getChain().getEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid defaultStaticLocationsAllEndWithTrailingSlash() {\n\t\tassertThat(this.properties.getStaticLocations()).allMatch((location) -> location.endsWith(\"/\"));\n\t}\n\n\t@Test\n\tvoid customStaticLocationsAreNormalizedToEndWithTrailingSlash() {\n\t\tthis.properties.setStaticLocations(new String[] { \"/foo\", \"/bar\", \"/baz/\" });\n\t\tString[] actual = this.properties.getStaticLocations();\n\t\tassertThat(actual).containsExactly(\"/foo/\", \"/bar/\", \"/baz/\");\n\t}\n\n\t@Test\n\tvoid emptyCacheControl() {\n\t\tCacheControl cacheControl = this.properties.getCache().getCachecontrol().toHttpCacheControl();\n\t\tassertThat(cacheControl).isNull();\n\t}\n\n\t@Test\n\tvoid cacheControlAllPropertiesSet() {\n\t\tCache.Cachecontrol properties = this.properties.getCache().getCachecontrol();\n\t\tproperties.setMaxAge(Duration.ofSeconds(4));\n\t\tproperties.setCachePrivate(true);\n\t\tproperties.setCachePublic(true);\n\t\tproperties.setMustRevalidate(true);\n\t\tproperties.setNoTransform(true);\n\t\tproperties.setProxyRevalidate(true);\n\t\tproperties.setSMaxAge(Duration.ofSeconds(5));\n\t\tproperties.setStaleIfError(Duration.ofSeconds(6));\n\t\tproperties.setStaleWhileRevalidate(Duration.ofSeconds(7));\n\t\tCacheControl cacheControl = properties.toHttpCacheControl();\n\t\tassertThat(cacheControl).isNotNull();\n\t\tassertThat(cacheControl.getHeaderValue())\n\t\t\t.isEqualTo(\"max-age=4, must-revalidate, no-transform, public, private, proxy-revalidate,\"\n\t\t\t\t\t+ \" s-maxage=5, stale-if-error=6, stale-while-revalidate=7\");\n\t}\n\n\t@Test\n\tvoid invalidCacheControlCombination() {\n\t\tCache.Cachecontrol properties = this.properties.getCache().getCachecontrol();\n\t\tproperties.setMaxAge(Duration.ofSeconds(4));\n\t\tproperties.setNoStore(true);\n\t\tCacheControl cacheControl = properties.toHttpCacheControl();\n\t\tassertThat(cacheControl).isNotNull();\n\t\tassertThat(cacheControl.getHeaderValue()).isEqualTo(\"no-store\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/WebResourcesRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web;\n\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.ResourcePatternHint;\nimport org.springframework.aot.hint.ResourcePatternHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebResourcesRuntimeHints}.\n *\n * @author Stephane Nicoll\n */\n@WithResource(name = \"web/custom-resource.txt\")\nclass WebResourcesRuntimeHintsTests {\n\n\t@Test\n\tvoid registerHintsWithAllLocations() {\n\t\tRuntimeHints hints = register(\n\t\t\t\tnew TestClassLoader(List.of(\"META-INF/resources/\", \"resources/\", \"static/\", \"public/\")));\n\t\tassertThat(hints.resources().resourcePatternHints()).singleElement()\n\t\t\t.satisfies(include(\"META-INF/resources/**\", \"resources/**\", \"static/**\", \"public/**\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWithOnlyStaticLocations() {\n\t\tRuntimeHints hints = register(new TestClassLoader(List.of(\"static/\")));\n\t\tassertThat(hints.resources().resourcePatternHints()).singleElement().satisfies(include(\"static/**\"));\n\t}\n\n\t@Test\n\tvoid registerHintsWithNoLocation() {\n\t\tRuntimeHints hints = register(new TestClassLoader(Collections.emptyList()));\n\t\tassertThat(hints.resources().resourcePatternHints()).isEmpty();\n\t}\n\n\tprivate RuntimeHints register(ClassLoader classLoader) {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tWebResourcesRuntimeHints registrar = new WebResourcesRuntimeHints();\n\t\tregistrar.registerHints(hints, classLoader);\n\t\treturn hints;\n\t}\n\n\tprivate Consumer<ResourcePatternHints> include(String... patterns) {\n\t\treturn (hint) -> assertThat(hint.getIncludes()).map(ResourcePatternHint::getPattern).contains(patterns);\n\t}\n\n\tprivate static class TestClassLoader extends ClassLoader {\n\n\t\tprivate final List<String> availableResources;\n\n\t\tTestClassLoader(List<String> availableResources) {\n\t\t\tsuper(Thread.currentThread().getContextClassLoader());\n\t\t\tthis.availableResources = availableResources;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable URL getResource(String name) {\n\t\t\treturn (this.availableResources.contains(name)) ? super.getResource(\"web/custom-resource.txt\") : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/format/WebConversionServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.web.format;\n\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.OffsetDateTime;\nimport java.time.OffsetTime;\nimport java.time.ZoneId;\nimport java.time.ZoneOffset;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.time.format.FormatStyle;\nimport java.util.Calendar;\nimport java.util.Date;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebConversionService}.\n *\n * @author Brian Clozel\n * @author Madhura Bhave\n * @author Gaurav Pareek\n */\nclass WebConversionServiceTests {\n\n\t@Test\n\tvoid defaultDateFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters());\n\t\tLocalDate date = LocalDate.of(2020, 4, 26);\n\t\tassertThat(conversionService.convert(date, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(date));\n\t}\n\n\t@Test\n\tvoid isoDateFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat(\"iso\"));\n\t\tLocalDate date = LocalDate.of(2020, 4, 26);\n\t\tassertThat(conversionService.convert(date, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ISO_LOCAL_DATE.format(date));\n\t}\n\n\t@Test\n\tvoid customDateFormatWithJavaUtilDate() {\n\t\tcustomDateFormat(Date.from(ZonedDateTime.of(2018, 1, 1, 20, 30, 0, 0, ZoneId.systemDefault()).toInstant()));\n\t}\n\n\t@Test\n\tvoid customDateFormatWithJavaTime() {\n\t\tcustomDateFormat(java.time.LocalDate.of(2018, 1, 1));\n\t}\n\n\t@Test\n\tvoid defaultTimeFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters());\n\t\tLocalTime time = LocalTime.of(12, 45, 23);\n\t\tassertThat(conversionService.convert(time, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(time));\n\t}\n\n\t@Test\n\tvoid isoTimeFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters().timeFormat(\"iso\"));\n\t\tLocalTime time = LocalTime.of(12, 45, 23);\n\t\tassertThat(conversionService.convert(time, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ISO_LOCAL_TIME.format(time));\n\t}\n\n\t@Test\n\tvoid isoOffsetTimeFormat() {\n\t\tisoOffsetTimeFormat(new DateTimeFormatters().timeFormat(\"isooffset\"));\n\t}\n\n\t@Test\n\tvoid hyphenatedIsoOffsetTimeFormat() {\n\t\tisoOffsetTimeFormat(new DateTimeFormatters().timeFormat(\"iso-offset\"));\n\t}\n\n\tprivate void isoOffsetTimeFormat(DateTimeFormatters formatters) {\n\t\tWebConversionService conversionService = new WebConversionService(formatters);\n\t\tOffsetTime offsetTime = OffsetTime.of(LocalTime.of(12, 45, 23), ZoneOffset.ofHoursMinutes(1, 30));\n\t\tassertThat(conversionService.convert(offsetTime, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ISO_OFFSET_TIME.format(offsetTime));\n\t}\n\n\t@Test\n\tvoid customTimeFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\tnew DateTimeFormatters().timeFormat(\"HH*mm*ss\"));\n\t\tLocalTime time = LocalTime.of(12, 45, 23);\n\t\tassertThat(conversionService.convert(time, String.class)).isEqualTo(\"12*45*23\");\n\t}\n\n\t@Test\n\tvoid defaultDateTimeFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters());\n\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 26, 12, 45, 23);\n\t\tassertThat(conversionService.convert(dateTime, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).format(dateTime));\n\t}\n\n\t@Test\n\tvoid isoDateTimeFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\tnew DateTimeFormatters().dateTimeFormat(\"iso\"));\n\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 26, 12, 45, 23);\n\t\tassertThat(conversionService.convert(dateTime, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(dateTime));\n\t}\n\n\t@Test\n\tvoid isoOffsetDateTimeFormat() {\n\t\tisoOffsetDateTimeFormat(new DateTimeFormatters().dateTimeFormat(\"isooffset\"));\n\t}\n\n\t@Test\n\tvoid hyphenatedIsoOffsetDateTimeFormat() {\n\t\tisoOffsetDateTimeFormat(new DateTimeFormatters().dateTimeFormat(\"iso-offset\"));\n\t}\n\n\tprivate void isoOffsetDateTimeFormat(DateTimeFormatters formatters) {\n\t\tWebConversionService conversionService = new WebConversionService(formatters);\n\t\tOffsetDateTime offsetDateTime = OffsetDateTime.of(LocalDate.of(2020, 4, 26), LocalTime.of(12, 45, 23),\n\t\t\t\tZoneOffset.ofHoursMinutes(1, 30));\n\t\tassertThat(conversionService.convert(offsetDateTime, String.class))\n\t\t\t.isEqualTo(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime));\n\t}\n\n\t@Test\n\tvoid customDateTimeFormat() {\n\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\tnew DateTimeFormatters().dateTimeFormat(\"dd*MM*yyyy HH*mm*ss\"));\n\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 26, 12, 45, 23);\n\t\tassertThat(conversionService.convert(dateTime, String.class)).isEqualTo(\"26*04*2020 12*45*23\");\n\t}\n\n\t@Test\n\tvoid convertFromStringToLocalDate() {\n\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\tnew DateTimeFormatters().dateFormat(\"yyyy-MM-dd\"));\n\t\tLocalDate date = conversionService.convert(\"2018-01-01\", LocalDate.class);\n\t\tassertThat(date).isEqualTo(java.time.LocalDate.of(2018, 1, 1));\n\t}\n\n\t@Test\n\tvoid convertFromStringToLocalDateWithIsoFormatting() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat(\"iso\"));\n\t\tLocalDate date = conversionService.convert(\"2018-01-01\", LocalDate.class);\n\t\tassertThat(date).isEqualTo(java.time.LocalDate.of(2018, 1, 1));\n\t}\n\n\t@Test\n\tvoid convertFromStringToDateWithIsoFormatting() {\n\t\tWebConversionService conversionService = new WebConversionService(new DateTimeFormatters().dateFormat(\"iso\"));\n\t\tDate date = conversionService.convert(\"2018-01-01\", Date.class);\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.setTime(date);\n\t\tassertThat(calendar.get(Calendar.YEAR)).isEqualTo(2018);\n\t\tassertThat(calendar.get(Calendar.MONTH)).isZero();\n\t\tassertThat(calendar.get(Calendar.DAY_OF_MONTH)).isOne();\n\t}\n\n\tprivate void customDateFormat(Object input) {\n\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\tnew DateTimeFormatters().dateFormat(\"dd*MM*yyyy\"));\n\t\tassertThat(conversionService.convert(input, String.class)).isEqualTo(\"01*01*2018\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/condition/factorybean.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t<bean id=\"example\"\n\t\tclass=\"org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBeanTests.ExampleFactoryBean\">\n\t\t<constructor-arg value=\"${value:bar}\" />\n\t</bean>\n\n</beans>\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/condition/foo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t<bean id=\"foo\" class=\"java.lang.String\">\n\t\t<constructor-arg value=\"foo\" />\n\t</bean>\n\n</beans>\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/build-info.properties",
    "content": "build.group=com.example.acme\nbuild.artifact=acme\nbuild.name=acme\nbuild.version=1.0.1-SNAPSHOT\nbuild.time=2016-03-04T10:42:00.000Z\nbuild.charset=test™\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git-epoch.properties",
    "content": "git.branch=master\ngit.commit.user.email=john@example.com\ngit.commit.id=5009933788f5f8c687719de6a697074ff80b1b69\ngit.commit.user.name=John Smith\ngit.commit.time=1457103850\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git-no-data.properties",
    "content": "foo=bar\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/info/git.properties",
    "content": "git.commit.user.email=john@example.com\ngit.commit.id=f95038ec09e29d8f91982fd1cbcc0f3b131b1d0a\ngit.commit.user.name=John Smith\ngit.commit.time=2016-03-03T10\\:02\\:00+0100\ngit.commit.charset=test™\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIICCzCCAb2gAwIBAgIUZbDi7G5czH+Yi0k2EMWxdf00XagwBQYDK2VwMHsxCzAJ\nBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5hbWUxETAPBgNVBAcMCENpdHlOYW1l\nMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkGA1UECwwSQ29tcGFueVNlY3Rpb25O\nYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjMwOTExMTIxNDMwWhcNMzMwOTA4\nMTIxNDMwWjB7MQswCQYDVQQGEwJYWDESMBAGA1UECAwJU3RhdGVOYW1lMREwDwYD\nVQQHDAhDaXR5TmFtZTEUMBIGA1UECgwLQ29tcGFueU5hbWUxGzAZBgNVBAsMEkNv\nbXBhbnlTZWN0aW9uTmFtZTESMBAGA1UEAwwJbG9jYWxob3N0MCowBQYDK2VwAyEA\nQ/DDA4BSgZ+Hx0DUxtIRjVjN+OcxXVURwAWc3Gt9GUyjUzBRMB0GA1UdDgQWBBSv\nEdpoaBMBoxgO96GFbf03k07DSTAfBgNVHSMEGDAWgBSvEdpoaBMBoxgO96GFbf03\nk07DSTAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAHMXDkGd57d4F4cRk/8UjhxD\n7OtRBZfdfznSvlhJIMNfH5q0zbC2eO3hWCB3Hrn/vIeswGP8Ov4AJ6eXeX44BQM=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/ed25519-key.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIC29RnMVTcyqXEAIO1b/6p7RdbM6TiqvnztVQ4IxYxUh\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/key1.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAhECFHuJXZO0JDPtCSc1/r0llpyc/j9TMA0GCSqGSIb3DQEBCwUAME8x\nCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAkNBMCAXDTIzMTAwNTA3Mjg0NVoY\nDzIxMjMwOTExMDcyODQ1WjBRMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs\ndCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQ0wCwYDVQQDDARr\nZXkxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoYU2afupPq/b6PIy\n6MWDOMRdJk5uW51lrw6oudXpWlUQMXKdsaZT4sqbgjGLggfo7WWsPeCzQN3kIX3T\nOqBog5EMkXnlQhAfP2Htj0uXPFj97leZ+FqJrzgPnZY8wSqDXfy9/ycR3PgWjRsS\nGZJb05hTNVGTU2vpNQDDo+XBKgybB0afGU8Nk/InWfs1xd/Jv0YcVADQiQEmg41w\ng18B3LMIBZPWIJUQ1b7wMlhxWaCNXHfB1bUTIYCUAUOZyEaxPaOOiJo32xKmqOlU\nTCLM8zgWCBCEgHtQwSD0GMLhUarLPNE5GP3yo5qHBYqOque7BBjP4e58r6wAyBoe\n7kMYRQIDAQABMA0GCSqGSIb3DQEBCwUAA4H/AAMIYpTDxgQwpfk+U1IhkqJjb+Uh\nhj6KlT5TEdpn/saGYLZQECZAO21MWrUDTsV2Pax2Ee8ezarCg8Cthu4YOtPauPaL\nXpyrIagUOgrDcmXr6QxMKUqifiMurLRFaAS7mWXp0TAFNgzDg3WvF9zMJgkjUp/O\ngNSG9U7kXuFfxpVtoalyC2C3g3UeieVXSek3a28h5c/0/DomHqLbyqZh5rYwAJ7C\nq1bqA5TnZNVvV731SVueycj9+5PKHKG6eeRRh7roZ34l54O9adNEeDAF0Lqn4sbn\na/h4GPK/u6J6Y3nwrdajipZ2DmfiQwoimxprMGNQKuKA0lc025SGHNno\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/key1.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChhTZp+6k+r9vo\n8jLoxYM4xF0mTm5bnWWvDqi51elaVRAxcp2xplPiypuCMYuCB+jtZaw94LNA3eQh\nfdM6oGiDkQyReeVCEB8/Ye2PS5c8WP3uV5n4WomvOA+dljzBKoNd/L3/JxHc+BaN\nGxIZklvTmFM1UZNTa+k1AMOj5cEqDJsHRp8ZTw2T8idZ+zXF38m/RhxUANCJASaD\njXCDXwHcswgFk9YglRDVvvAyWHFZoI1cd8HVtRMhgJQBQ5nIRrE9o46ImjfbEqao\n6VRMIszzOBYIEISAe1DBIPQYwuFRqss80TkY/fKjmocFio6q57sEGM/h7nyvrADI\nGh7uQxhFAgMBAAECggEABUfEGCHkjgqUv2BPnsF6QTxWKT7uJ6uVG+x4Qp8GInBe\nd6deFWUxH9xsygxRmb4ldMFaqKk0Yv3+C8Q/yA5fbFGtHgJkpsy9IMbUS9d2ScBF\nCOovO+nFz4cfJ5E2SkBYDBYLphBCar1ni1RjupdIzjmQGtGgZd1EwflU7AJCVtwG\nS7ltIs2nSOqUFGTfjb9j0NiATZvWTDRtavNMhyrZplKK6M6VoH1ZcnmcvEfF7j5L\noSmXrNKYs4iKn1qKypykfCQoEFK0/EEjj5EdnPaSeI9EERrZK1QnHafB2qK38LSr\n8cGaWH24mPW6c/26bDQnHkN3SqKLCODXZMBGhPlLDwKBgQDdMqOzRR3SpTx7KPqp\nh+P0diBZb1e6c+Ob0lXD/rfJEtkAqyFLqpi8hN9xodxw++JYbhC69kJE7VWtQLIt\nLc+DG72KTS/cbpnvERL1+AoM0TRbO9Ds9aFP4+Zmm/VDxi9rR5yTgl9iAHJ46VrE\nBhnG8JQPBm4n5JU5/wJ9qCQCywKBgQC67uWchaewzDHCiefhTVgwTm1BmHiV/OR4\n50Je2x3GPW6VJGFnBjVzlScKrNyFeOYwscvVS8pTmFP8c5laTbQMC3pVqiWs28Ip\n6sy6cXfepVyc0njLFGbiek8ab0rjVYU27D0O9tucrxDx4pKOurilds1Gbm4HjfyE\nR7pWn/AfLwKBgQC+5wJzKLaJYsQlAwP6pmYtSHm41ihfqb8Jb2lHwyD4r4SLWCZf\nOHejVAXH+0rWU/1QFoXn5brh4/cqlIhyB3RtkdZucxlYZDgEJLc5g32g/Dj0eFZi\n+8bhvS3O5tCxUm0AaIiQolcRrJMfGT6VqTI8CMuvf/w3/8ZujFCpBCE4KwKBgBiw\nlQMnZA6l6ayYKlhHru4ybZvMV6D31fViFhIRPs2AL6rjMzo4R7cMbCusyTOX1E96\nLEHv0LlZ1T3yxr52pOEyYuYNowxBulNu/7tgYUS28pSD+BBakXw4S1pieLGuCfpH\nGYlwcXEwbjyEgHb5konINzSmQUIeLswJ7UKjvUNhAoGAXmXvyHqdL04SD99G3B/5\n+azzzAVR1fvGYOvq+/hWZMG5PS0kx2V3txCVyY8E1/lCysp9BuUHtW+vOS8YGhAT\nwkZ/X9igZteQvvdVw+E5CXS05b4EBI+7ZViL9ulXFZ4YC70lKcUE52bmaPM+onQJ\nY1s9JWTe2EAkxsuxm+hkjo0=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/key2-chain.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAhECFFjLlXVdTxDdLlCifzrA0dTHHJ2mMA0GCSqGSIb3DQEBCwUAME8x\nCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAkNBMCAXDTIzMTAwNTA3Mjg1MFoY\nDzIxMjMwOTExMDcyODUwWjBRMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs\ndCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQ0wCwYDVQQDDARr\nZXkyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAspCMUdFGyKkgpMbW\n+UwSg4fdKM4qLSH7voTdsdVM9aAvLvYjBQ4gpORxDZNfUz67R0Ua0/oJt9jD49Wp\nqcq+tDOnp0dPtn2hFluV5PxM6d+MCSx/frPsfvyt9234okLL1zdLDNFYEbLhSPjA\nku3vHw/OwlJOxCRwTkPqcElIV4+IvIbzAgSffyokzm/wKVKEhoT6NcfeU+6wCkTu\nal1X8loJ+27N6jN13oGZfH7EveBqgR8rPs55+54S/OcVG/uqL9ggOGRJiIZ3jUBk\nm5cN27wKkaNg/CQwa1UjcU4qshVpknHw1dpgJ2Gbs/yUphwpEZl/FTsZFcK1KCHD\nrOp3PQIDAQABMA0GCSqGSIb3DQEBCwUAA4H/AAFmEq86broBFxs0cpImaM884PBT\nbvJBSsFhsOg6mi4Gt01G/lPSj/ExNtH3G5bytCYAPaRxNx/dCs7uON3p86ta4zL8\n2PxgyhX1oY/GG63ETwn5s3GKpRaGTNVDWvPIM9RX6+bvX/wOg8eYXVaQlG5XYadC\nMs9lWqHaM1C/iLGNmUTGcdbvhnmQDky2CwPNm+lXogSWbrsGpAmCkXJD1H+0Mx8I\nwjDVtGLBwr/8oXI8WbhvISMnS9+dd7+GLm6mU+14Kswi5I7EmBmREvkswi2IVJ6M\nGL7EY3qA6iqJWqsseYyLxiMr3nBT0SETphzoDanUQI1/jXQPrWIyjqvs\n-----END CERTIFICATE-----\n-----BEGIN TRUSTED CERTIFICATE-----\nMIIDIDCCAgsCFH3lh1RXOEy2ESqUPyzb+9zxMYUnMA0GCSqGSIb3DQEBCwUAME8x\nCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAkNBMCAXDTIzMTAwNTA3MjU1M1oY\nDzIxMjMwOTExMDcyNTUzWjBPMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs\ndCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQswCQYDVQQDDAJD\nQTCCAR4wDQYJKoZIhvcNAQEBBQADggELADCCAQYCgf4NNpc+6B3qvwKcRYgoXmJ4\n3wyWktBK7BdShz/YnW1OlFZ+R845ZiDw0KdzElZWkYqn+BYJus6lPIS5dfLcrGSf\na1e8IK02RpBiY/WJvupetnSk8gKA7emF94NlV4gXr4ICJAhXvXUFyBLpdEUE/lcg\nlgCbVJzs5jWUnffEF9mrClzzo0+iXw34zwmyYyBTFmlOEr+QUEdAb6Lr/klpTVit\nas2Ddg1QT4EaSIdTEpkVRZp2dyYVdqSxpaBq21xg0viDHsYQrP96IfacmUB7kFFn\nHsnptDHFvJj2WSQDX+PRS7tLl4mmfizZg80eGfLD22ShNspRSGnbJc0OzegPiwID\nAQABMA0GCSqGSIb3DQEBCwUAA4H/AAnC+FQqdeJaG5I7R+pNjgKplL2UsxW983kA\nCVVkv/Dt0+4rbPC67o9/8Tr+g4eo/wUntMNo2ghF3oBItGr7pJE16zPiLwIvha9c\n8BDhCEZWyhz3vkamZUi19lOnkm3zTmmDE/nX4WYH6CL4UWjxvniZYwW8AdVSnFXY\nncriuvfliLa3dw1SJ7FtxdcBn4yfzrZWcY+psYNHpftLGYRmQF/VCDSB9EAIEggr\nyBcP749u2y8s44WvKAnnwfLcALIrylY25zN0pao/l2X8HI6qHUeA/QbbEBpDoQvR\ndu/rgaHCVvFFxATefhBJ0CUA1Nn5nrGwyRTKnZWtR080qwUp\n-----END TRUSTED CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/key2.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAhECFFjLlXVdTxDdLlCifzrA0dTHHJ2mMA0GCSqGSIb3DQEBCwUAME8x\nCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAkNBMCAXDTIzMTAwNTA3Mjg1MFoY\nDzIxMjMwOTExMDcyODUwWjBRMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs\ndCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQ0wCwYDVQQDDARr\nZXkyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAspCMUdFGyKkgpMbW\n+UwSg4fdKM4qLSH7voTdsdVM9aAvLvYjBQ4gpORxDZNfUz67R0Ua0/oJt9jD49Wp\nqcq+tDOnp0dPtn2hFluV5PxM6d+MCSx/frPsfvyt9234okLL1zdLDNFYEbLhSPjA\nku3vHw/OwlJOxCRwTkPqcElIV4+IvIbzAgSffyokzm/wKVKEhoT6NcfeU+6wCkTu\nal1X8loJ+27N6jN13oGZfH7EveBqgR8rPs55+54S/OcVG/uqL9ggOGRJiIZ3jUBk\nm5cN27wKkaNg/CQwa1UjcU4qshVpknHw1dpgJ2Gbs/yUphwpEZl/FTsZFcK1KCHD\nrOp3PQIDAQABMA0GCSqGSIb3DQEBCwUAA4H/AAFmEq86broBFxs0cpImaM884PBT\nbvJBSsFhsOg6mi4Gt01G/lPSj/ExNtH3G5bytCYAPaRxNx/dCs7uON3p86ta4zL8\n2PxgyhX1oY/GG63ETwn5s3GKpRaGTNVDWvPIM9RX6+bvX/wOg8eYXVaQlG5XYadC\nMs9lWqHaM1C/iLGNmUTGcdbvhnmQDky2CwPNm+lXogSWbrsGpAmCkXJD1H+0Mx8I\nwjDVtGLBwr/8oXI8WbhvISMnS9+dd7+GLm6mU+14Kswi5I7EmBmREvkswi2IVJ6M\nGL7EY3qA6iqJWqsseYyLxiMr3nBT0SETphzoDanUQI1/jXQPrWIyjqvs\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/key2.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCykIxR0UbIqSCk\nxtb5TBKDh90oziotIfu+hN2x1Uz1oC8u9iMFDiCk5HENk19TPrtHRRrT+gm32MPj\n1ampyr60M6enR0+2faEWW5Xk/Ezp34wJLH9+s+x+/K33bfiiQsvXN0sM0VgRsuFI\n+MCS7e8fD87CUk7EJHBOQ+pwSUhXj4i8hvMCBJ9/KiTOb/ApUoSGhPo1x95T7rAK\nRO5qXVfyWgn7bs3qM3XegZl8fsS94GqBHys+znn7nhL85xUb+6ov2CA4ZEmIhneN\nQGSblw3bvAqRo2D8JDBrVSNxTiqyFWmScfDV2mAnYZuz/JSmHCkRmX8VOxkVwrUo\nIcOs6nc9AgMBAAECggEAPN9dDolG1aIeYD3uzCa8Sv2WjdIWe7NRlEXMI9MgvL1i\nSGKdVpxV0ZCU37llLkY85tNujWP4SyXIxdMxVxIoR9syJKsBSCd0sl//bgP6nmHY\nZco3HnTswu+VyLtDHuGhhtkxKwn0uXffKBaw44XcVhz38bPIaUI4zN2HPscks8BG\nj2MEl0N8P/TVrTkhgdjfoRi73VAisrEe+1wCg74BT7cmR8fEr7iNFrv955sdPGdw\nUTmx8U26++wbeYQs1ZE1713SYnRQuCUFs5GGjzOhNFi27zuhI6TafoVm9PO4j+ZC\nJUKTyUTBUsRMvm9z1IoHdjM8yInAv2g0J1bAeCTY+wKBgQDuMNMbNVoiXRKsSUry\n22T3W6HVLfLNKiYMNxsAkJjOiyyJcC+yg9BErn/haIHSafD2WmuWbW5ASViyl6fn\nD8qMluTwEaSrTgHXWI4ahWyapDShDQYp1s4dB75Aa/LVcFCay54YEtyCPzCPlj1K\njz5OBV14NEVVA2cf59fIc/LXCwKBgQC/6m3TefUp5jnN/QUOx2OtZo8Y1pVrsuMB\nAuTtb21Khxn/86ZpVzySzg79/DkSNf9/sZhzj0IkviWNP5S8iAAaFC1q08CYhdCX\nd7tVnHlzpZmmoHUhG6dlJZayr1duZrURp2rP18+wIsKiFRImAyjc6yswVRpZgAiG\ngOkHCB231wKBgGlwXZMWy/6YOtLfYvkcm5ZQDtSCkY+2j78qiZ53Y91SiHWSntqk\nNQaiRGOw0n8lfJBhOG0PphV5InV0YtQLDnurtE59UOqwDmqYfddJpujRtaZxUIAm\n4XjCW7rCzm0jWdscNbCscMaLWGDHffxKaqc5AsZaRTK73eOmysOmaCI/AoGAf/yd\nRZ1dzJWHE0Kb7uE2LlvpLo1clLh1/ySo+1eGMV+sDS+2WSYedWEKSoO8o9JzE/ui\nSd7OI6bTcEFotdqVBs9SAp45IP6Mv5bPziZOMLvNnnv/4RaKKkBJId0hl7TTKHTY\nHMg176ce2eznb4ZH6BzFbrQyoGFsThcGUPQurX0CgYBYtkDTp21TI1nuak7xpMIY\nBJQpqF5ahBf/+QYWtL0f3ca9MO2++zv5/XXitvt48cY1bCHNrVvSHgRzwSrOorZA\n5u7a5zyvfXjY3LY3k0VHddaVjU0mHsjx/1ux0wO2v8wQjOVZpT7XweB3WlUEGV7C\n5T/p+rmGg5Y5dTKUVCyvbQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/rsa-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL\nBQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI\nQ2l0eU5hbWUxFDASBgNVBAoMC0NvbXBhbnlOYW1lMRswGQYDVQQLDBJDb21wYW55\nU2VjdGlvbk5hbWUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzA5MTExMjExNTha\nFw0zMzA5MDgxMjExNThaMHsxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5h\nbWUxETAPBgNVBAcMCENpdHlOYW1lMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkG\nA1UECwwSQ29tcGFueVNlY3Rpb25OYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfdkeEiCk+5mpXUhJ1FLmOCx6/\njAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dgpHqds/84pb+3\nOlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1U6zk1iwrbiO3\nhu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf4RhoE6krDdV1\nJD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAPuwXHO5BNw504\n3Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3TOhyA1ueXAgMB\nAAGjUzBRMB0GA1UdDgQWBBRHYz8OjqU/4JZMegJaN/jQbdj4MjAfBgNVHSMEGDAW\ngBRHYz8OjqU/4JZMegJaN/jQbdj4MjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\nDQEBCwUAA4IBAQBr9zqlNx7Mr1ordGfhk+xFrDtyBnk1vXbwVdnog66REqpPLH+K\nMfCKdj6wFoPa8ZjPb4VYFp2DvMxVXtFMzqGfLjYJPqefEzQCleOcA5aiE/ENIaaD\nybYh99V5CsFAqyKuHLBFEzeYJ028SR3QsCISom0k/Fh6y2IwHJJEHykjqJKvL4bb\nV0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds\nHEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb\nngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/ssl/rsa-key.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfdkeEiCk+5mpX\nUhJ1FLmOCx6/jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dg\npHqds/84pb+3OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1\nU6zk1iwrbiO3hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf\n4RhoE6krDdV1JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAP\nuwXHO5BNw5043Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3T\nOhyA1ueXAgMBAAECggEAPK1LqmULWMlhdoeeyVlQ//lAQn+6X4/MwycG/UsCSJC2\nBCV4nfgyv853UFRkM0jPBhDQ7h1wz1ohuWbs11xaBcqgKE7ywe3ZQULD5tqnO64y\nBU8V2+rnO4gjpbdMHQLlxdgy5KHxtR3Q4+6Kj+rlFMOMqLWZSmke8na7H+SczzGf\n+dZO4LRTbjGmFdUidehovm2icSM8OdU2w3FHlFRu2NBsTHGeAhRw86Yw24KfJp4R\nGSDQIBdwp1wCs5w7w4zPjxS7Zi+Uwspyq31KDJwyfK2O1WLI05bQ6FLqVRD/xy+Y\nb4WCse1O08SYWze2No915LB07sokgmomr3//bOwuEQKBgQDPBrPQXokn0BoTlgsa\nJohgWzQ5P9u/2WY+u2SG/xgNEx0s+lk/AmAH80wsBJ68FV6z5Non7TzD7xCsf2HJ\n3cP/EHl2ngTctz/eqpCcS5UPZBHmay60q6WKIkH/3ml7c0UhlqSqS3EDVyEe05hk\nmsWAN+fV4ajVlhWgiUZRVdxMpwKBgQDFLyPBOEn6zLOHfkQWcibVf8s2LTe76R/S\n8Gk3jbk5mimR3vNm0L/rHqGwl75rOuFiFOHVkfuY9Dawaht0QnagjayT5hDqr6aD\ns5Chyoy9qpXnfnqOgk6rQZqj+/ODkjqEkBdRCKWvCVnDIi3Au2kS3QIc4iTsGrBW\nygZdbxM7kQKBgEuzS7T5nHVuZtqaltytElkJgIMekqAIQpbVtuCWDplZT+XOdSvR\nFoRRtpyx48kql0J4gDzxRrLui85Hld5WtQBjacax6V07tKMbA13jVVIXaWQz9RQj\nX5ivBisljLSTZcfuaa/LfjuWdIntHWBMJ8PGrYNLzIytIKNfDtNW7gMpAoGAIRZQ\n5JpCZ7Azq9e3KyEKfSbNfZDG2mQ679Vhgm3ol87TjOOhai47FgP008IStMGTkja4\n0nKFilvoVV/orXB9oWFEhSjEy+yff1gBO/TV+vmF3+tsOz+IXdpLTZr4eKpv4VCg\naPuPebiS9Fhm3wFTl1O4iAo2cdvknRuXR9RcoNECgYADksGk1lJGW5kMIMJ+6os+\nCJdGnJiX7XsnM0VzkagswnqDe03SqkJuFOmIp96eitxLT4EfB+585pYQRSy2fyJX\nWR2AAnC7oqUcQFkgDt9WBZAazI6aLXYO+trRoGKuWynGM8mjetr5C75g0auj4lsN\nrGiie2UnjshJ67FrG4kZoA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/cache/autoconfigure/hazelcast-specific.xml",
    "content": "<hazelcast xsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t   xmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n\t<queue name=\"foobar\"/>\n\n\t<map name=\"foobar\">\n\t\t<time-to-live-seconds>3600</time-to-live-seconds>\n\t\t<max-idle-seconds>600</max-idle-seconds>\n\t</map>\n\n\t<network>\n\t\t<join>\n\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t<multicast enabled=\"false\"/>\n\t\t</join>\n\t</network>\n\n</hazelcast>\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/testFixtures/java/org/springframework/boot/autoconfigure/AutoConfigurationImportedCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport org.assertj.core.api.Condition;\nimport org.assertj.core.description.TextDescription;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * AssertJ {@link Condition} that checks that an auto-configuration has been imported.\n *\n * @author Andy Wilkinson\n */\npublic final class AutoConfigurationImportedCondition extends Condition<ApplicationContext> {\n\n\tprivate final Class<?> autoConfigurationClass;\n\n\tprivate AutoConfigurationImportedCondition(Class<?> autoConfigurationClass) {\n\t\tsuper(new TextDescription(\"%s imported\", autoConfigurationClass.getName()));\n\t\tthis.autoConfigurationClass = autoConfigurationClass;\n\t}\n\n\t@Override\n\tpublic boolean matches(ApplicationContext context) {\n\t\tConditionEvaluationReport report = ConditionEvaluationReport\n\t\t\t.get((ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory());\n\t\treturn report.getConditionAndOutcomesBySource().containsKey(this.autoConfigurationClass.getName())\n\t\t\t\t|| report.getUnconditionalClasses().contains(this.autoConfigurationClass.getName());\n\t}\n\n\t/**\n\t * Returns a {@link Condition} that verifies that the given\n\t * {@code autoConfigurationClass} has been imported.\n\t * @param autoConfigurationClass the auto-configuration class\n\t * @return the condition\n\t */\n\tpublic static AutoConfigurationImportedCondition importedAutoConfiguration(Class<?> autoConfigurationClass) {\n\t\treturn new AutoConfigurationImportedCondition(autoConfigurationClass);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/testFixtures/java/org/springframework/boot/autoconfigure/TestAutoConfigurationPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\n\n/**\n * Test annotation to configure the {@link AutoConfigurationPackages} to an arbitrary\n * value.\n *\n * @author Phillip Webb\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(TestAutoConfigurationPackageRegistrar.class)\npublic @interface TestAutoConfigurationPackage {\n\n\tClass<?> value();\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/testFixtures/java/org/springframework/boot/autoconfigure/TestAutoConfigurationPackageRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} to store the base package for tests.\n *\n * @author Phillip Webb\n */\npublic class TestAutoConfigurationPackageRegistrar implements ImportBeanDefinitionRegistrar {\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {\n\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t.fromMap(metadata.getAnnotationAttributes(TestAutoConfigurationPackage.class.getName(), true));\n\t\tAutoConfigurationPackages.register(registry, ClassUtils.getPackageName(attributes.getString(\"value\")));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/testFixtures/java/org/springframework/boot/autoconfigure/jndi/JndiPropertiesHidingClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jndi;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.Enumeration;\n\n/**\n * Used as the thread context classloader to prevent {@code jndi.properties} resources\n * found on the classpath from triggering configuration of an InitialContextFactory.\n *\n * @author Andy Wilkinson\n */\npublic class JndiPropertiesHidingClassLoader extends ClassLoader {\n\n\tpublic JndiPropertiesHidingClassLoader(ClassLoader parent) {\n\t\tsuper(parent);\n\t}\n\n\t@Override\n\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\tif (\"jndi.properties\".equals(name)) {\n\t\t\treturn Collections.emptyEnumeration();\n\t\t}\n\t\treturn super.getResources(name);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure/src/testFixtures/java/org/springframework/boot/autoconfigure/jndi/TestableInitialContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigure.jndi;\n\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.Map;\n\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\nimport javax.naming.spi.InitialContextFactory;\n\n/**\n * An {@code InitialContextFactory} implementation to be used for testing JNDI.\n *\n * @author Stephane Nicoll\n */\npublic class TestableInitialContextFactory implements InitialContextFactory {\n\n\tprivate static TestableContext context;\n\n\t@Override\n\tpublic Context getInitialContext(Hashtable<?, ?> environment) {\n\t\treturn getContext();\n\t}\n\n\tpublic static void bind(String name, Object obj) {\n\t\ttry {\n\t\t\tgetContext().bind(name, obj);\n\t\t}\n\t\tcatch (NamingException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tpublic static void clearAll() {\n\t\tgetContext().clearAll();\n\t}\n\n\tprivate static TestableContext getContext() {\n\t\tif (context == null) {\n\t\t\ttry {\n\t\t\t\tcontext = new TestableContext();\n\t\t\t}\n\t\t\tcatch (NamingException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\t\treturn context;\n\t}\n\n\tprivate static final class TestableContext extends InitialContext {\n\n\t\tprivate final Map<String, Object> bindings = new HashMap<>();\n\n\t\tprivate TestableContext() throws NamingException {\n\t\t\tsuper(true);\n\t\t}\n\n\t\t@Override\n\t\tpublic void bind(String name, Object obj) throws NamingException {\n\t\t\tthis.bindings.put(name, obj);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object lookup(String name) {\n\t\t\treturn this.bindings.get(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic Hashtable<?, ?> getEnvironment() throws NamingException {\n\t\t\treturn new Hashtable<>(); // Used to detect if JNDI is\n\t\t\t\t\t\t\t\t\t\t// available\n\t\t}\n\n\t\tvoid clearAll() {\n\t\t\tthis.bindings.clear();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.annotation-processor\"\n}\n\ndescription = \"Spring Boot AutoConfigure Annotation Processor\"\n\ndependencies {\n\ttestImplementation(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.stream.Stream;\n\nimport javax.annotation.processing.AbstractProcessor;\nimport javax.annotation.processing.Filer;\nimport javax.annotation.processing.RoundEnvironment;\nimport javax.annotation.processing.SupportedAnnotationTypes;\nimport javax.lang.model.SourceVersion;\nimport javax.lang.model.element.AnnotationMirror;\nimport javax.lang.model.element.AnnotationValue;\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.tools.FileObject;\nimport javax.tools.StandardLocation;\n\n/**\n * Annotation processor to store certain annotations from auto-configuration classes in a\n * property file.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 1.5.0\n */\n@SupportedAnnotationTypes({ \"org.springframework.boot.autoconfigure.condition.ConditionalOnClass\",\n\t\t\"org.springframework.boot.autoconfigure.condition.ConditionalOnBean\",\n\t\t\"org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate\",\n\t\t\"org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication\",\n\t\t\"org.springframework.boot.autoconfigure.AutoConfigureBefore\",\n\t\t\"org.springframework.boot.autoconfigure.AutoConfigureAfter\",\n\t\t\"org.springframework.boot.autoconfigure.AutoConfigureOrder\",\n\t\t\"org.springframework.boot.autoconfigure.AutoConfiguration\" })\npublic class AutoConfigureAnnotationProcessor extends AbstractProcessor {\n\n\tprotected static final String PROPERTIES_PATH = \"META-INF/spring-autoconfigure-metadata.properties\";\n\n\tprivate final Map<String, String> properties = new TreeMap<>();\n\n\tprivate final List<PropertyGenerator> propertyGenerators;\n\n\tpublic AutoConfigureAnnotationProcessor() {\n\t\tthis.propertyGenerators = Collections.unmodifiableList(getPropertyGenerators());\n\t}\n\n\tprotected List<PropertyGenerator> getPropertyGenerators() {\n\t\tList<PropertyGenerator> generators = new ArrayList<>();\n\t\taddConditionPropertyGenerators(generators);\n\t\taddAutoConfigurePropertyGenerators(generators);\n\t\treturn generators;\n\t}\n\n\tprivate void addConditionPropertyGenerators(List<PropertyGenerator> generators) {\n\t\tString annotationPackage = \"org.springframework.boot.autoconfigure.condition\";\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnClass\")\n\t\t\t.withAnnotation(new OnClassConditionValueExtractor()));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnBean\")\n\t\t\t.withAnnotation(new OnBeanConditionValueExtractor()));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnSingleCandidate\")\n\t\t\t.withAnnotation(new OnBeanConditionValueExtractor()));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnWebApplication\")\n\t\t\t.withAnnotation(ValueExtractor.allFrom(\"type\")));\n\t}\n\n\tprivate void addAutoConfigurePropertyGenerators(List<PropertyGenerator> generators) {\n\t\tString annotationPackage = \"org.springframework.boot.autoconfigure\";\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"AutoConfigureBefore\", true)\n\t\t\t.withAnnotation(ValueExtractor.allFrom(\"value\", \"name\"))\n\t\t\t.withAnnotation(\"AutoConfiguration\", ValueExtractor.allFrom(\"before\", \"beforeName\")));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"AutoConfigureAfter\", true)\n\t\t\t.withAnnotation(ValueExtractor.allFrom(\"value\", \"name\"))\n\t\t\t.withAnnotation(\"AutoConfiguration\", ValueExtractor.allFrom(\"after\", \"afterName\")));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"AutoConfigureOrder\")\n\t\t\t.withAnnotation(ValueExtractor.allFrom(\"value\")));\n\t}\n\n\t@Override\n\tpublic SourceVersion getSupportedSourceVersion() {\n\t\treturn SourceVersion.latestSupported();\n\t}\n\n\t@Override\n\tpublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {\n\t\tfor (PropertyGenerator generator : this.propertyGenerators) {\n\t\t\tprocess(roundEnv, generator);\n\t\t}\n\t\tif (roundEnv.processingOver()) {\n\t\t\ttry {\n\t\t\t\twriteProperties();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to write metadata\", ex);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate void process(RoundEnvironment roundEnv, PropertyGenerator generator) {\n\t\tfor (String annotationName : generator.getSupportedAnnotations()) {\n\t\t\tTypeElement annotationType = this.processingEnv.getElementUtils().getTypeElement(annotationName);\n\t\t\tif (annotationType != null) {\n\t\t\t\tfor (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) {\n\t\t\t\t\tprocessElement(element, generator, annotationName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void processElement(Element element, PropertyGenerator generator, String annotationName) {\n\t\ttry {\n\t\t\tString qualifiedName = Elements.getQualifiedName(element);\n\t\t\tAnnotationMirror annotation = getAnnotation(element, annotationName);\n\t\t\tif (qualifiedName != null && annotation != null) {\n\t\t\t\tList<Object> values = getValues(generator, annotationName, annotation);\n\t\t\t\tgenerator.applyToProperties(this.properties, qualifiedName, values);\n\t\t\t\tthis.properties.put(qualifiedName, \"\");\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Error processing configuration meta-data on \" + element, ex);\n\t\t}\n\t}\n\n\tprivate AnnotationMirror getAnnotation(Element element, String type) {\n\t\tif (element != null) {\n\t\t\tfor (AnnotationMirror annotation : element.getAnnotationMirrors()) {\n\t\t\t\tif (type.equals(annotation.getAnnotationType().toString())) {\n\t\t\t\t\treturn annotation;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<Object> getValues(PropertyGenerator generator, String annotationName, AnnotationMirror annotation) {\n\t\tValueExtractor extractor = generator.getValueExtractor(annotationName);\n\t\tif (extractor == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\treturn extractor.getValues(annotation);\n\t}\n\n\tprivate void writeProperties() throws IOException {\n\t\tif (!this.properties.isEmpty()) {\n\t\t\tFiler filer = this.processingEnv.getFiler();\n\t\t\tFileObject file = filer.createResource(StandardLocation.CLASS_OUTPUT, \"\", PROPERTIES_PATH);\n\t\t\ttry (Writer writer = new OutputStreamWriter(file.openOutputStream(), StandardCharsets.UTF_8)) {\n\t\t\t\tfor (Map.Entry<String, String> entry : this.properties.entrySet()) {\n\t\t\t\t\twriter.append(entry.getKey());\n\t\t\t\t\twriter.append(\"=\");\n\t\t\t\t\twriter.append(entry.getValue());\n\t\t\t\t\twriter.append(System.lineSeparator());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@FunctionalInterface\n\tinterface ValueExtractor {\n\n\t\tList<Object> getValues(AnnotationMirror annotation);\n\n\t\tstatic ValueExtractor allFrom(String... names) {\n\t\t\treturn new NamedValuesExtractor(names);\n\t\t}\n\n\t}\n\n\tprivate abstract static class AbstractValueExtractor implements ValueExtractor {\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprotected Stream<Object> extractValues(AnnotationValue annotationValue) {\n\t\t\tif (annotationValue == null) {\n\t\t\t\treturn Stream.empty();\n\t\t\t}\n\t\t\tObject value = annotationValue.getValue();\n\t\t\tif (value instanceof List) {\n\t\t\t\treturn ((List<AnnotationValue>) value).stream()\n\t\t\t\t\t.map((annotation) -> extractValue(annotation.getValue()));\n\t\t\t}\n\t\t\treturn Stream.of(extractValue(value));\n\t\t}\n\n\t\tprivate Object extractValue(Object value) {\n\t\t\tif (value instanceof DeclaredType declaredType) {\n\t\t\t\treturn Elements.getQualifiedName(declaredType.asElement());\n\t\t\t}\n\t\t\treturn value;\n\t\t}\n\n\t}\n\n\tprivate static class NamedValuesExtractor extends AbstractValueExtractor {\n\n\t\tprivate final Set<String> names;\n\n\t\tNamedValuesExtractor(String... names) {\n\t\t\tthis.names = new HashSet<>(Arrays.asList(names));\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Object> getValues(AnnotationMirror annotation) {\n\t\t\tList<Object> result = new ArrayList<>();\n\t\t\tannotation.getElementValues().forEach((key, value) -> {\n\t\t\t\tif (this.names.contains(key.getSimpleName().toString())) {\n\t\t\t\t\textractValues(value).forEach(result::add);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tstatic class OnBeanConditionValueExtractor extends AbstractValueExtractor {\n\n\t\t@Override\n\t\tpublic List<Object> getValues(AnnotationMirror annotation) {\n\t\t\tMap<String, AnnotationValue> attributes = new LinkedHashMap<>();\n\t\t\tannotation.getElementValues()\n\t\t\t\t.forEach((key, value) -> attributes.put(key.getSimpleName().toString(), value));\n\t\t\tif (attributes.containsKey(\"name\")) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\tList<Object> result = new ArrayList<>();\n\t\t\textractValues(attributes.get(\"value\")).forEach(result::add);\n\t\t\textractValues(attributes.get(\"type\")).forEach(result::add);\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tstatic class OnClassConditionValueExtractor extends NamedValuesExtractor {\n\n\t\tOnClassConditionValueExtractor() {\n\t\t\tsuper(\"value\", \"name\");\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Object> getValues(AnnotationMirror annotation) {\n\t\t\tList<Object> values = super.getValues(annotation);\n\t\t\tvalues.sort(this::compare);\n\t\t\treturn values;\n\t\t}\n\n\t\tprivate int compare(Object o1, Object o2) {\n\t\t\treturn Comparator.comparing(this::isSpringClass)\n\t\t\t\t.thenComparing(String.CASE_INSENSITIVE_ORDER)\n\t\t\t\t.compare(o1.toString(), o2.toString());\n\t\t}\n\n\t\tprivate boolean isSpringClass(String type) {\n\t\t\treturn type.startsWith(\"org.springframework.\");\n\t\t}\n\n\t}\n\n\tstatic final class PropertyGenerator {\n\n\t\tprivate final String annotationPackage;\n\n\t\tprivate final String propertyName;\n\n\t\tprivate final boolean omitEmptyValues;\n\n\t\tprivate final Map<String, ValueExtractor> valueExtractors;\n\n\t\tprivate PropertyGenerator(String annotationPackage, String propertyName, boolean omitEmptyValues,\n\t\t\t\tMap<String, ValueExtractor> valueExtractors) {\n\t\t\tthis.annotationPackage = annotationPackage;\n\t\t\tthis.propertyName = propertyName;\n\t\t\tthis.omitEmptyValues = omitEmptyValues;\n\t\t\tthis.valueExtractors = valueExtractors;\n\t\t}\n\n\t\tPropertyGenerator withAnnotation(ValueExtractor valueExtractor) {\n\t\t\treturn withAnnotation(this.propertyName, valueExtractor);\n\t\t}\n\n\t\tPropertyGenerator withAnnotation(String name, ValueExtractor ValueExtractor) {\n\t\t\tMap<String, ValueExtractor> valueExtractors = new LinkedHashMap<>(this.valueExtractors);\n\t\t\tvalueExtractors.put(this.annotationPackage + \".\" + name, ValueExtractor);\n\t\t\treturn new PropertyGenerator(this.annotationPackage, this.propertyName, this.omitEmptyValues,\n\t\t\t\t\tvalueExtractors);\n\t\t}\n\n\t\tSet<String> getSupportedAnnotations() {\n\t\t\treturn this.valueExtractors.keySet();\n\t\t}\n\n\t\tValueExtractor getValueExtractor(String annotation) {\n\t\t\treturn this.valueExtractors.get(annotation);\n\t\t}\n\n\t\tvoid applyToProperties(Map<String, String> properties, String className, List<Object> annotationValues) {\n\t\t\tif (this.omitEmptyValues && annotationValues.isEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmergeProperties(properties, className + \".\" + this.propertyName, toCommaDelimitedString(annotationValues));\n\t\t}\n\n\t\tprivate void mergeProperties(Map<String, String> properties, String key, String value) {\n\t\t\tString existingKey = properties.get(key);\n\t\t\tif (existingKey == null || existingKey.isEmpty()) {\n\t\t\t\tproperties.put(key, value);\n\t\t\t}\n\t\t\telse if (!value.isEmpty()) {\n\t\t\t\tproperties.put(key, existingKey + \",\" + value);\n\t\t\t}\n\t\t}\n\n\t\tprivate String toCommaDelimitedString(List<Object> list) {\n\t\t\tif (list.isEmpty()) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tfor (Object item : list) {\n\t\t\t\tresult.append((!result.isEmpty()) ? \",\" : \"\");\n\t\t\t\tresult.append(item);\n\t\t\t}\n\t\t\treturn result.toString();\n\t\t}\n\n\t\tstatic PropertyGenerator of(String annotationPackage, String propertyName) {\n\t\t\treturn of(annotationPackage, propertyName, false);\n\t\t}\n\n\t\tstatic PropertyGenerator of(String annotationPackage, String propertyName, boolean omitEmptyValues) {\n\t\t\treturn new PropertyGenerator(annotationPackage, propertyName, omitEmptyValues, Collections.emptyMap());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/Elements.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport javax.lang.model.element.Element;\nimport javax.lang.model.element.TypeElement;\nimport javax.lang.model.type.DeclaredType;\nimport javax.lang.model.type.TypeMirror;\n\n/**\n * Utilities for dealing with {@link Element} classes.\n *\n * @author Phillip Webb\n */\nfinal class Elements {\n\n\tprivate Elements() {\n\t}\n\n\tstatic String getQualifiedName(Element element) {\n\t\tif (element != null) {\n\t\t\tTypeElement enclosingElement = getEnclosingTypeElement(element.asType());\n\t\t\tif (enclosingElement != null) {\n\t\t\t\treturn getQualifiedName(enclosingElement) + \"$\"\n\t\t\t\t\t\t+ ((DeclaredType) element.asType()).asElement().getSimpleName().toString();\n\t\t\t}\n\t\t\tif (element instanceof TypeElement typeElement) {\n\t\t\t\treturn typeElement.getQualifiedName().toString();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static TypeElement getEnclosingTypeElement(TypeMirror type) {\n\t\tif (type instanceof DeclaredType declaredType) {\n\t\t\tElement enclosingElement = declaredType.asElement().getEnclosingElement();\n\t\t\tif (enclosingElement instanceof TypeElement typeElement) {\n\t\t\t\treturn typeElement;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Annotation processor for compile-time capturing of information about auto-configuration\n * classes.\n */\npackage org.springframework.boot.autoconfigureprocessor;\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/main/resources/META-INF/gradle/incremental.annotation.processors",
    "content": "org.springframework.boot.autoconfigureprocessor.AutoConfigureAnnotationProcessor,aggregating"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor",
    "content": "org.springframework.boot.autoconfigureprocessor.AutoConfigureAnnotationProcessor\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link AutoConfigureAnnotationProcessor}.\n *\n * @author Madhura Bhave\n * @author Moritz Halbritter\n * @author Scott Frederick\n */\nclass AutoConfigureAnnotationProcessorTests {\n\n\t@Test\n\tvoid annotatedClass() {\n\t\tcompile(TestClassConfiguration.class, (properties) -> {\n\t\t\tassertThat(properties).hasSize(7);\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration.ConditionalOnClass\",\n\t\t\t\t\t\"java.io.InputStream,org.springframework.boot.autoconfigureprocessor.\"\n\t\t\t\t\t\t\t+ \"TestClassConfiguration$Nested,org.springframework.foo\");\n\t\t\tassertThat(properties)\n\t\t\t\t.containsKey(\"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration\");\n\t\t\tassertThat(properties)\n\t\t\t\t.containsKey(\"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration$Nested\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestClassConfiguration.ConditionalOnBean\",\n\t\t\t\t\t\"java.io.OutputStream\");\n\t\t\tassertThat(properties).containsEntry(\"org.springframework.boot.autoconfigureprocessor.\"\n\t\t\t\t\t+ \"TestClassConfiguration.ConditionalOnSingleCandidate\", \"java.io.OutputStream\");\n\t\t\tassertThat(properties).containsEntry(\"org.springframework.boot.autoconfigureprocessor.\"\n\t\t\t\t\t+ \"TestClassConfiguration.ConditionalOnWebApplication\", \"SERVLET\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid annotatedClassWithOnlyAutoConfiguration() {\n\t\tcompile(TestAutoConfigurationOnlyConfiguration.class, (properties) -> {\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationOnlyConfiguration\", \"\");\n\t\t\tassertThat(properties).doesNotContainEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationOnlyConfiguration.AutoConfigureAfter\",\n\t\t\t\t\t\"\");\n\t\t\tassertThat(properties).doesNotContainEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationOnlyConfiguration.AutoConfigureBefore\",\n\t\t\t\t\t\"\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid annotatedClassWithOnBeanThatHasName() {\n\t\tcompile(TestOnBeanWithNameClassConfiguration.class, (properties) -> {\n\t\t\tassertThat(properties).hasSize(2);\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestOnBeanWithNameClassConfiguration.ConditionalOnBean\",\n\t\t\t\t\t\"\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid annotatedMethod() {\n\t\tprocess(TestMethodConfiguration.class, (properties) -> assertThat(properties).isNull());\n\t}\n\n\t@Test\n\tvoid annotatedClassWithOrder() {\n\t\tcompile(TestOrderedClassConfiguration.class, (properties) -> {\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestOrderedClassConfiguration.ConditionalOnClass\",\n\t\t\t\t\t\"java.io.InputStream,java.io.OutputStream\");\n\t\t\tassertThat(properties).containsEntry(\"org.springframework.boot.autoconfigureprocessor.\"\n\t\t\t\t\t+ \"TestOrderedClassConfiguration.AutoConfigureBefore\", \"test.before1,test.before2\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestOrderedClassConfiguration.AutoConfigureAfter\",\n\t\t\t\t\t\"java.io.ObjectInputStream\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestOrderedClassConfiguration.AutoConfigureOrder\",\n\t\t\t\t\t\"123\");\n\t\t});\n\n\t}\n\n\t@Test\n\tvoid annotatedClassWithAutoConfiguration() {\n\t\tcompile(TestAutoConfigurationConfiguration.class, (properties) -> {\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationConfiguration\", \"\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationConfiguration.AutoConfigureBefore\",\n\t\t\t\t\t\"java.io.InputStream,test.before1,test.before2\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationConfiguration.AutoConfigureAfter\",\n\t\t\t\t\t\"java.io.OutputStream,test.after1,test.after2\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid annotatedClassWithAutoConfigurationMerged() {\n\t\tcompile(TestMergedAutoConfigurationConfiguration.class, (properties) -> {\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestMergedAutoConfigurationConfiguration\", \"\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestMergedAutoConfigurationConfiguration.AutoConfigureBefore\",\n\t\t\t\t\t\"java.io.InputStream,test.before1,test.before2,java.io.ObjectInputStream,test.before3,test.before4\");\n\t\t\tassertThat(properties).containsEntry(\n\t\t\t\t\t\"org.springframework.boot.autoconfigureprocessor.TestMergedAutoConfigurationConfiguration.AutoConfigureAfter\",\n\t\t\t\t\t\"java.io.OutputStream,test.after1,test.after2,java.io.ObjectOutputStream,test.after3,test.after4\");\n\t\t});\n\t}\n\n\t@Test // gh-19370\n\tvoid propertiesAreFullRepeatable() {\n\t\tprocess(TestOrderedClassConfiguration.class, (firstFile) -> {\n\t\t\tString first = getFileContents(firstFile);\n\t\t\tprocess(TestOrderedClassConfiguration.class, (secondFile) -> {\n\t\t\t\tString second = getFileContents(secondFile);\n\t\t\t\tassertThat(first).isEqualTo(second).doesNotContain(\"#\");\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate void compile(Class<?> type, Consumer<Properties> consumer) {\n\t\tprocess(type, (writtenFile) -> consumer.accept(getWrittenProperties(writtenFile)));\n\t}\n\n\tprivate void process(Class<?> type, Consumer<InputStream> consumer) {\n\t\tTestAutoConfigureAnnotationProcessor processor = new TestAutoConfigureAnnotationProcessor();\n\t\tSourceFile sourceFile = SourceFile.forTestClass(type);\n\t\tTestCompiler compiler = TestCompiler.forSystem().withProcessors(processor).withSources(sourceFile);\n\t\tcompiler.compile((compiled) -> {\n\t\t\tInputStream propertiesFile = compiled.getClassLoader()\n\t\t\t\t.getResourceAsStream(AutoConfigureAnnotationProcessor.PROPERTIES_PATH);\n\t\t\tconsumer.accept(propertiesFile);\n\t\t});\n\t}\n\n\tprivate Properties getWrittenProperties(InputStream inputStream) {\n\t\ttry {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.load(inputStream);\n\t\t\treturn properties;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tfail(\"Error reading properties\", ex);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String getFileContents(InputStream inputStream) {\n\t\ttry {\n\t\t\treturn new String(inputStream.readAllBytes());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tfail(\"Error reading contents of properties file\", ex);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Alternative to Spring Boot's {@code @AutoConfiguration} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Moritz Halbritter\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@TestAutoConfigureBefore\n@TestAutoConfigureAfter\npublic @interface TestAutoConfiguration {\n\n\t@AliasFor(annotation = TestAutoConfigureBefore.class, attribute = \"value\")\n\tClass<?>[] before() default {};\n\n\t@AliasFor(annotation = TestAutoConfigureBefore.class, attribute = \"name\")\n\tString[] beforeName() default {};\n\n\t@AliasFor(annotation = TestAutoConfigureAfter.class, attribute = \"value\")\n\tClass<?>[] after() default {};\n\n\t@AliasFor(annotation = TestAutoConfigureAfter.class, attribute = \"name\")\n\tString[] afterName() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigurationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Test @AutoConfiguration aliases for @AutoConfigureBefore and @AutoConfigureAfter.\n *\n * @author Moritz Halbritter\n */\n@TestAutoConfiguration(before = InputStream.class, beforeName = { \"test.before1\", \"test.before2\" },\n\t\tafter = OutputStream.class, afterName = { \"test.after1\", \"test.after2\" })\nclass TestAutoConfigurationConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigurationOnlyConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\n/**\n * Tests a plain {@code @AutoConfiguration} annotated class.\n *\n * @author Moritz Halbritter\n */\n@TestAutoConfiguration\nclass TestAutoConfigurationOnlyConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAfter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @AutoConfigureAfter} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE })\n@Documented\npublic @interface TestAutoConfigureAfter {\n\n\tClass<?>[] value() default {};\n\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.annotation.processing.SupportedAnnotationTypes;\n\n/**\n * Version of {@link AutoConfigureAnnotationProcessor} used for testing.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n */\n@SupportedAnnotationTypes({ \"org.springframework.boot.autoconfigureprocessor.TestConditionalOnClass\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestConditionalOnBean\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestConditionalOnSingleCandidate\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestConditionalOnWebApplication\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigureBefore\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigureAfter\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfigureOrder\",\n\t\t\"org.springframework.boot.autoconfigureprocessor.TestAutoConfiguration\" })\npublic class TestAutoConfigureAnnotationProcessor extends AutoConfigureAnnotationProcessor {\n\n\tpublic TestAutoConfigureAnnotationProcessor() {\n\t}\n\n\t@Override\n\tprotected List<PropertyGenerator> getPropertyGenerators() {\n\t\tList<PropertyGenerator> generators = new ArrayList<>();\n\t\tString annotationPackage = \"org.springframework.boot.autoconfigureprocessor\";\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnClass\")\n\t\t\t.withAnnotation(\"TestConditionalOnClass\", new OnClassConditionValueExtractor()));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnBean\")\n\t\t\t.withAnnotation(\"TestConditionalOnBean\", new OnBeanConditionValueExtractor()));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnSingleCandidate\")\n\t\t\t.withAnnotation(\"TestConditionalOnSingleCandidate\", new OnBeanConditionValueExtractor()));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"ConditionalOnWebApplication\")\n\t\t\t.withAnnotation(\"TestConditionalOnWebApplication\", ValueExtractor.allFrom(\"type\")));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"AutoConfigureBefore\", true)\n\t\t\t.withAnnotation(\"TestAutoConfigureBefore\", ValueExtractor.allFrom(\"value\", \"name\"))\n\t\t\t.withAnnotation(\"TestAutoConfiguration\", ValueExtractor.allFrom(\"before\", \"beforeName\")));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"AutoConfigureAfter\", true)\n\t\t\t.withAnnotation(\"TestAutoConfigureAfter\", ValueExtractor.allFrom(\"value\", \"name\"))\n\t\t\t.withAnnotation(\"TestAutoConfiguration\", ValueExtractor.allFrom(\"after\", \"afterName\")));\n\t\tgenerators.add(PropertyGenerator.of(annotationPackage, \"AutoConfigureOrder\")\n\t\t\t.withAnnotation(\"TestAutoConfigureOrder\", ValueExtractor.allFrom(\"value\")));\n\t\treturn generators;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureBefore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @AutoConfigureBefore} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE })\n@Documented\npublic @interface TestAutoConfigureBefore {\n\n\tClass<?>[] value() default {};\n\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureOrder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @AutoConfigureOrder} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD })\n@Documented\npublic @interface TestAutoConfigureOrder {\n\n\tint value() default Integer.MAX_VALUE;\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestClassConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport org.springframework.boot.autoconfigureprocessor.TestConditionalOnWebApplication.Type;\n\n/**\n * Test configuration with an annotated class.\n *\n * @author Madhura Bhave\n */\n@TestConditionalOnClass(name = { \"org.springframework.foo\", \"java.io.InputStream\" },\n\t\tvalue = TestClassConfiguration.Nested.class)\n@TestConditionalOnBean(type = \"java.io.OutputStream\")\n@TestConditionalOnSingleCandidate(type = \"java.io.OutputStream\")\n@TestConditionalOnWebApplication(type = Type.SERVLET)\npublic class TestClassConfiguration {\n\n\t@TestAutoConfigureOrder\n\tstatic class Nested {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code ConditionalOnBean} for testing (removes the need\n * for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConditionalOnBean {\n\n\tClass<?>[] value() default {};\n\n\tString[] type() default {};\n\n\tClass<? extends Annotation>[] annotation() default {};\n\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Fake {@code @ConditionalOnClass} annotation used for testing.\n *\n * @author Madhura Bhave\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConditionalOnClass {\n\n\tClass<?>[] value() default {};\n\n\tString[] name() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnSingleCandidate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code ConditionalOnSingleCandidate} for testing (removes\n * the need for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConditionalOnSingleCandidate {\n\n\tClass<?> value() default Object.class;\n\n\tString type() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestConditionalOnWebApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Alternative to Spring Boot's {@code @ConditionalOnWebApplication} for testing (removes\n * the need for a dependency on the real annotation).\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface TestConditionalOnWebApplication {\n\n\tType type() default Type.ANY;\n\n\tenum Type {\n\n\t\tANY, SERVLET, REACTIVE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestMergedAutoConfigurationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.io.InputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.io.OutputStream;\n\n/**\n * Test @AutoConfiguration aliases together with @AutoConfigureBefore\n * and @AutoConfigureAfter.\n *\n * @author Moritz Halbritter\n */\n@TestAutoConfigureBefore(value = InputStream.class, name = { \"test.before1\", \"test.before2\" })\n@TestAutoConfigureAfter(value = OutputStream.class, name = { \"test.after1\", \"test.after2\" })\n@TestAutoConfiguration(before = ObjectInputStream.class, beforeName = { \"test.before3\", \"test.before4\" },\n\t\tafter = ObjectOutputStream.class, afterName = { \"test.after3\", \"test.after4\" })\nclass TestMergedAutoConfigurationConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestMethodConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.io.OutputStream;\n\n/**\n * Test configuration with an annotated method.\n *\n * @author Madhura Bhave\n */\npublic class TestMethodConfiguration {\n\n\t@TestConditionalOnClass(name = \"java.io.InputStream\", value = OutputStream.class)\n\tpublic Object method() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOnBeanWithNameClassConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\n/**\n * Test configuration with an annotated class.\n *\n * @author Phillip Webb\n */\n@TestConditionalOnBean(name = \"test\", type = \"java.io.OutputStream\")\npublic class TestOnBeanWithNameClassConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestOrderedClassConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.autoconfigureprocessor;\n\nimport java.io.ObjectInputStream;\nimport java.io.OutputStream;\n\n/**\n * Test configuration with an annotated class.\n *\n * @author Phillip Webb\n */\n@TestAutoConfigureBefore(name = { \"test.before1\", \"test.before2\" })\n@TestAutoConfigureAfter(ObjectInputStream.class)\n@TestConditionalOnClass(name = \"java.io.InputStream\", value = OutputStream.class)\n@TestAutoConfigureOrder(123)\npublic class TestOrderedClassConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Docker Compose\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-autoconfigure\"))\n\n\timplementation(\"tools.jackson.core:jackson-databind\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\n\tdockerTestRuntimeOnly(\"org.testcontainers:testcontainers\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"ch.qos.logback:logback-classic\")\n\n\ttestFixturesImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link DefaultDockerCompose}.\n *\n * @author Moritz Halbritter\n */\n@DisabledIfDockerUnavailable\n@DisabledIfProcessUnavailable({ \"docker\", \"compose\" })\nclass DefaultDockerComposeIntegrationTests {\n\n\t@Test\n\tvoid shouldWorkWithProfiles(@TempDir Path tempDir) throws IOException {\n\t\t// Profile 1 contains redis1 and redis3\n\t\t// Profile 2 contains redis2 and redis3\n\t\tFile composeFile = createComposeFile(tempDir, \"profiles.yaml\").toFile();\n\t\tDefaultDockerCompose dockerComposeWithProfile1 = new DefaultDockerCompose(new DockerCli(tempDir.toFile(),\n\t\t\t\tnew DockerComposeOptions(DockerComposeFile.of(composeFile), Set.of(\"1\"), Collections.emptyList())),\n\t\t\t\tnull);\n\t\tDefaultDockerCompose dockerComposeWithProfile2 = new DefaultDockerCompose(new DockerCli(tempDir.toFile(),\n\t\t\t\tnew DockerComposeOptions(DockerComposeFile.of(composeFile), Set.of(\"2\"), Collections.emptyList())),\n\t\t\t\tnull);\n\t\tDefaultDockerCompose dockerComposeWithAllProfiles = new DefaultDockerCompose(new DockerCli(tempDir.toFile(),\n\t\t\t\tnew DockerComposeOptions(DockerComposeFile.of(composeFile), Set.of(\"1\", \"2\"), Collections.emptyList())),\n\t\t\t\tnull);\n\t\tdockerComposeWithAllProfiles.up(LogLevel.DEBUG);\n\t\ttry {\n\t\t\tList<RunningService> runningServicesProfile1 = dockerComposeWithProfile1.getRunningServices();\n\t\t\tassertThatContainsService(runningServicesProfile1, \"redis1\");\n\t\t\tassertThatDoesNotContainService(runningServicesProfile1, \"redis2\");\n\t\t\tassertThatContainsService(runningServicesProfile1, \"redis3\");\n\n\t\t\tList<RunningService> runningServicesProfile2 = dockerComposeWithProfile2.getRunningServices();\n\t\t\tassertThatDoesNotContainService(runningServicesProfile2, \"redis1\");\n\t\t\tassertThatContainsService(runningServicesProfile2, \"redis2\");\n\t\t\tassertThatContainsService(runningServicesProfile2, \"redis3\");\n\n\t\t\t// Assert that redis3 is started only once and is shared between profile 1 and\n\t\t\t// profile 2\n\t\t\tassertThat(dockerComposeWithAllProfiles.getRunningServices()).hasSize(3);\n\t\t\tRunningService redis3Profile1 = findService(runningServicesProfile1, \"redis3\");\n\t\t\tRunningService redis3Profile2 = findService(runningServicesProfile2, \"redis3\");\n\t\t\tassertThat(redis3Profile1).isNotNull();\n\t\t\tassertThat(redis3Profile2).isNotNull();\n\t\t\tassertThat(redis3Profile1.name()).isEqualTo(redis3Profile2.name());\n\t\t}\n\t\tfinally {\n\t\t\tdockerComposeWithAllProfiles.down(Duration.ofSeconds(10));\n\t\t}\n\t}\n\n\tprivate @Nullable RunningService findService(List<RunningService> runningServices, String serviceName) {\n\t\tfor (RunningService runningService : runningServices) {\n\t\t\tif (runningService.name().contains(serviceName)) {\n\t\t\t\treturn runningService;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void assertThatDoesNotContainService(List<RunningService> runningServices, String service) {\n\t\tif (findService(runningServices, service) != null) {\n\t\t\tfail(\"Did not expect service '%s', but found it in [%s]\", service, runningServices);\n\t\t}\n\t}\n\n\tprivate void assertThatContainsService(List<RunningService> runningServices, String service) {\n\t\tif (findService(runningServices, service) == null) {\n\t\t\tfail(\"Expected service '%s', but hasn't been found in [%s]\", service, runningServices);\n\t\t}\n\t}\n\n\tprivate static Path createComposeFile(Path tempDir, String resource) throws IOException {\n\t\tString composeFileTemplate = new ClassPathResource(resource, DockerCliIntegrationTests.class)\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tString content = composeFileTemplate.replace(\"{imageName}\", TestImage.REDIS.toString());\n\t\tPath composeFile = tempDir.resolve(resource);\n\t\tFiles.writeString(composeFile, content);\n\t\treturn composeFile;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/core/DockerCliIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeConfig;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeDown;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposePs;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeStart;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeStop;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeUp;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.Inspect;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCli}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DisabledIfDockerUnavailable\n@DisabledIfProcessUnavailable({ \"docker\", \"compose\" })\nclass DockerCliIntegrationTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate static Path tempDir;\n\n\t@Test\n\tvoid runBasicCommand() {\n\t\tDockerCli cli = new DockerCli(null, null);\n\t\tList<DockerCliContextResponse> context = cli.run(new DockerCliCommand.Context());\n\t\tassertThat(context).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid runLifecycle() throws IOException {\n\t\tFile composeFile = createComposeFile(\"redis-compose.yaml\");\n\t\tString projectName = UUID.randomUUID().toString();\n\t\tDockerCli cli = new DockerCli(null, new DockerComposeOptions(DockerComposeFile.of(composeFile),\n\t\t\t\tCollections.emptySet(), List.of(\"--project-name=\" + projectName)));\n\t\ttry {\n\t\t\t// Verify that no services are running (this is a fresh compose project)\n\t\t\tList<DockerCliComposePsResponse> ps = cli.run(new ComposePs());\n\t\t\tassertThat(ps).isEmpty();\n\t\t\t// List the config and verify that redis is there\n\t\t\tDockerCliComposeConfigResponse config = cli.run(new ComposeConfig());\n\t\t\tassertThat(config.services()).containsOnlyKeys(\"redis\");\n\t\t\tassertThat(config.name()).isEqualTo(projectName);\n\t\t\t// Run up\n\t\t\tcli.run(new ComposeUp(LogLevel.INFO, Collections.emptyList()));\n\t\t\t// Run ps and use id to run inspect on the id\n\t\t\tps = cli.run(new ComposePs());\n\t\t\tassertThat(ps).hasSize(1);\n\t\t\tString id = ps.get(0).id();\n\t\t\tList<DockerCliInspectResponse> inspect = cli.run(new Inspect(List.of(id)));\n\t\t\tassertThat(inspect).isNotEmpty();\n\t\t\tassertThat(inspect.get(0).id()).startsWith(id);\n\t\t\t// Run stop, then run ps and verify the services are stopped\n\t\t\tcli.run(new ComposeStop(Duration.ofSeconds(10), Collections.emptyList()));\n\t\t\tps = cli.run(new ComposePs());\n\t\t\tassertThat(ps).isEmpty();\n\t\t\t// Run start, verify service is there, then run down and verify they are gone\n\t\t\tcli.run(new ComposeStart(LogLevel.INFO, Collections.emptyList()));\n\t\t\tps = cli.run(new ComposePs());\n\t\t\tassertThat(ps).hasSize(1);\n\t\t\tcli.run(new ComposeDown(Duration.ofSeconds(10), Collections.emptyList()));\n\t\t\tps = cli.run(new ComposePs());\n\t\t\tassertThat(ps).isEmpty();\n\t\t}\n\t\tfinally {\n\t\t\t// Clean up in any case\n\t\t\tquietComposeDown(cli);\n\t\t}\n\t}\n\n\t@Test\n\tvoid shouldWorkWithMultipleComposeFiles() throws IOException {\n\t\tList<File> composeFiles = createComposeFiles();\n\t\tDockerCli cli = new DockerCli(null,\n\t\t\t\tnew DockerComposeOptions(DockerComposeFile.of(composeFiles), Set.of(\"dev\"), Collections.emptyList()));\n\t\ttry {\n\t\t\t// List the config and verify that both redis are there\n\t\t\tDockerCliComposeConfigResponse config = cli.run(new ComposeConfig());\n\t\t\tassertThat(config.services()).containsOnlyKeys(\"redis1\", \"redis2\");\n\t\t\t// Run up\n\t\t\tcli.run(new ComposeUp(LogLevel.INFO, Collections.emptyList()));\n\t\t\t// Run ps and use id to run inspect on the id\n\t\t\tList<DockerCliComposePsResponse> ps = cli.run(new ComposePs());\n\t\t\tassertThat(ps).hasSize(2);\n\t\t}\n\t\tfinally {\n\t\t\t// Clean up in any case\n\t\t\tquietComposeDown(cli);\n\t\t}\n\t}\n\n\tprivate static void quietComposeDown(DockerCli cli) {\n\t\ttry {\n\t\t\tcli.run(new ComposeDown(Duration.ZERO, Collections.emptyList()));\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate static File createComposeFile(String resource) throws IOException {\n\t\tFile source = new ClassPathResource(resource, DockerCliIntegrationTests.class).getFile();\n\t\tFile target = Path.of(tempDir.toString(), source.getName()).toFile();\n\t\tString content = FileCopyUtils.copyToString(new FileReader(source));\n\t\tcontent = content.replace(\"{imageName}\", TestImage.REDIS.toString());\n\t\ttry (FileWriter writer = new FileWriter(target)) {\n\t\t\tFileCopyUtils.copy(content, writer);\n\t\t}\n\t\treturn target;\n\t}\n\n\tprivate static List<File> createComposeFiles() throws IOException {\n\t\tFile file1 = createComposeFile(\"1.yaml\");\n\t\tFile file2 = createComposeFile(\"2.yaml\");\n\t\tFile file3 = createComposeFile(\"3.yaml\");\n\t\treturn List.of(file1, file2, file3);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/1.yaml",
    "content": "services:\n  redis1:\n    profiles: [ 'dev' ]\n    image: '{imageName}'\n    ports:\n      - '6379'\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/2.yaml",
    "content": "services:\n  redis2:\n    image: '{imageName}'\n    ports:\n      - '6379'\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/3.yaml",
    "content": "services:\n  redis3:\n    profiles: [ 'prod' ]\n    image: '{imageName}'\n    ports:\n      - '6379'\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/profiles.yaml",
    "content": "services:\n  redis1:\n    profiles:\n      - '1'\n    image: '{imageName}'\n    ports:\n      - '6379'\n  redis2:\n    profiles:\n      - '2'\n    image: '{imageName}'\n    ports:\n      - '6379'\n  redis3:\n    image: '{imageName}'\n    ports:\n      - '6379'\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/dockerTest/resources/org/springframework/boot/docker/compose/core/redis-compose.yaml",
    "content": "services:\n  redis:\n    image: '{imageName}'\n    ports:\n      - '6379'\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ConnectionPorts.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides access to the ports that can be used to connect to a {@link RunningService}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n * @see RunningService\n */\npublic interface ConnectionPorts {\n\n\t/**\n\t * Return the host port mapped to the given container port.\n\t * @param containerPort the container port. This is usually the standard port for the\n\t * service (e.g. port 80 for HTTP)\n\t * @return the host port. This can be an ephemeral port that is different from the\n\t * container port\n\t * @throws IllegalStateException if the container port is not mapped\n\t */\n\tint get(int containerPort);\n\n\t/**\n\t * Return all host ports in use.\n\t * @return a list of all host ports\n\t * @see #getAll(String)\n\t */\n\tList<Integer> getAll();\n\n\t/**\n\t * Return all host ports in use that match the given protocol.\n\t * @param protocol the protocol in use (for example 'tcp') or {@code null} to return\n\t * all host ports\n\t * @return a list of all host ports using the given protocol\n\t */\n\tList<Integer> getAll(@Nullable String protocol);\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultConnectionPorts.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostPort;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Default {@link ConnectionPorts} implementation backed by {@link DockerCli} responses.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultConnectionPorts implements ConnectionPorts {\n\n\tprivate final Map<ContainerPort, Integer> mappings;\n\n\tprivate final Map<Integer, Integer> portMappings;\n\n\tDefaultConnectionPorts(DockerCliInspectResponse inspectResponse) {\n\t\tthis.mappings = !isHostNetworkMode(inspectResponse)\n\t\t\t\t? buildMappingsForNetworkSettings(inspectResponse.networkSettings())\n\t\t\t\t: buildMappingsForHostNetworking(inspectResponse.config());\n\t\tMap<Integer, Integer> portMappings = new HashMap<>();\n\t\tthis.mappings.forEach((containerPort, hostPort) -> portMappings.put(containerPort.number(), hostPort));\n\t\tthis.portMappings = Collections.unmodifiableMap(portMappings);\n\t}\n\n\tprivate static boolean isHostNetworkMode(DockerCliInspectResponse inspectResponse) {\n\t\tHostConfig config = inspectResponse.hostConfig();\n\t\treturn (config != null) && \"host\".equals(config.networkMode());\n\t}\n\n\tprivate Map<ContainerPort, Integer> buildMappingsForNetworkSettings(@Nullable NetworkSettings networkSettings) {\n\t\tif (networkSettings == null || CollectionUtils.isEmpty(networkSettings.ports())) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<ContainerPort, Integer> mappings = new HashMap<>();\n\t\tnetworkSettings.ports().forEach((containerPortString, hostPorts) -> {\n\t\t\tif (!CollectionUtils.isEmpty(hostPorts)) {\n\t\t\t\tContainerPort containerPort = ContainerPort.parse(containerPortString);\n\t\t\t\thostPorts.stream()\n\t\t\t\t\t.filter(this::isIpV4)\n\t\t\t\t\t.forEach((hostPort) -> mappings.put(containerPort, getPortNumber(hostPort)));\n\t\t\t}\n\t\t});\n\t\treturn Collections.unmodifiableMap(mappings);\n\t}\n\n\tprivate boolean isIpV4(@Nullable HostPort hostPort) {\n\t\tString ip = (hostPort != null) ? hostPort.hostIp() : null;\n\t\treturn !StringUtils.hasLength(ip) || ip.contains(\".\");\n\t}\n\n\tprivate static int getPortNumber(HostPort hostPort) {\n\t\treturn Integer.parseInt(hostPort.hostPort());\n\t}\n\n\tprivate Map<ContainerPort, Integer> buildMappingsForHostNetworking(Config config) {\n\t\tif (CollectionUtils.isEmpty(config.exposedPorts())) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<ContainerPort, Integer> mappings = new HashMap<>();\n\t\tfor (String entry : config.exposedPorts().keySet()) {\n\t\t\tContainerPort containerPort = ContainerPort.parse(entry);\n\t\t\tmappings.put(containerPort, containerPort.number());\n\t\t}\n\t\treturn Collections.unmodifiableMap(mappings);\n\t}\n\n\t@Override\n\tpublic int get(int containerPort) {\n\t\tInteger hostPort = this.portMappings.get(containerPort);\n\t\tAssert.state(hostPort != null,\n\t\t\t\t() -> \"No host port mapping found for container port %s\".formatted(containerPort));\n\t\treturn hostPort;\n\t}\n\n\t@Override\n\tpublic List<Integer> getAll() {\n\t\treturn getAll(null);\n\t}\n\n\t@Override\n\tpublic List<Integer> getAll(@Nullable String protocol) {\n\t\tList<Integer> hostPorts = new ArrayList<>();\n\t\tthis.mappings.forEach((containerPort, hostPort) -> {\n\t\t\tif (protocol == null || protocol.equalsIgnoreCase(containerPort.protocol())) {\n\t\t\t\thostPorts.add(hostPort);\n\t\t\t}\n\t\t});\n\t\treturn Collections.unmodifiableList(hostPorts);\n\t}\n\n\tMap<ContainerPort, Integer> getMappings() {\n\t\treturn this.mappings;\n\t}\n\n\t/**\n\t * A container port consisting of a number and protocol.\n\t *\n\t * @param number the port number\n\t * @param protocol the protocol (e.g. tcp)\n\t */\n\trecord ContainerPort(int number, String protocol) {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"%d/%s\".formatted(this.number, this.protocol);\n\t\t}\n\n\t\tstatic ContainerPort parse(String value) {\n\t\t\ttry {\n\t\t\t\tString[] parts = value.split(\"/\");\n\t\t\t\tAssert.state(parts.length == 2, \"Unable to split string\");\n\t\t\t\treturn new ContainerPort(Integer.parseInt(parts[0]), parts[1]);\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to parse container port '%s'\".formatted(value), ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultDockerCompose.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.util.Assert;\n\n/**\n * Default {@link DockerCompose} implementation backed by {@link DockerCli}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultDockerCompose implements DockerCompose {\n\n\tprivate final DockerCli cli;\n\n\tprivate final DockerHost hostname;\n\n\tDefaultDockerCompose(DockerCli cli, @Nullable String host) {\n\t\tthis.cli = cli;\n\t\tthis.hostname = DockerHost.get(host, () -> cli.run(new DockerCliCommand.Context()));\n\t}\n\n\t@Override\n\tpublic void up(LogLevel logLevel) {\n\t\tup(logLevel, Collections.emptyList());\n\t}\n\n\t@Override\n\tpublic void up(LogLevel logLevel, List<String> arguments) {\n\t\tthis.cli.run(new DockerCliCommand.ComposeUp(logLevel, arguments));\n\t}\n\n\t@Override\n\tpublic void down(Duration timeout) {\n\t\tdown(timeout, Collections.emptyList());\n\t}\n\n\t@Override\n\tpublic void down(Duration timeout, List<String> arguments) {\n\t\tthis.cli.run(new DockerCliCommand.ComposeDown(timeout, arguments));\n\t}\n\n\t@Override\n\tpublic void start(LogLevel logLevel) {\n\t\tstart(logLevel, Collections.emptyList());\n\t}\n\n\t@Override\n\tpublic void start(LogLevel logLevel, List<String> arguments) {\n\t\tthis.cli.run(new DockerCliCommand.ComposeStart(logLevel, arguments));\n\t}\n\n\t@Override\n\tpublic void stop(Duration timeout) {\n\t\tstop(timeout, Collections.emptyList());\n\t}\n\n\t@Override\n\tpublic void stop(Duration timeout, List<String> arguments) {\n\t\tthis.cli.run(new DockerCliCommand.ComposeStop(timeout, arguments));\n\t}\n\n\t@Override\n\tpublic String logs() {\n\t\treturn this.cli.run(new DockerCliCommand.ComposeLogs());\n\t}\n\n\t@Override\n\tpublic boolean hasDefinedServices() {\n\t\treturn !this.cli.run(new DockerCliCommand.ComposeConfig()).services().isEmpty();\n\t}\n\n\t@Override\n\tpublic List<RunningService> getRunningServices() {\n\t\tList<DockerCliComposePsResponse> runningPsResponses = runComposePs().stream().filter(this::isRunning).toList();\n\t\tif (runningPsResponses.isEmpty()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tDockerComposeFile dockerComposeFile = this.cli.getDockerComposeFile();\n\t\tList<RunningService> result = new ArrayList<>();\n\t\tMap<String, DockerCliInspectResponse> inspected = inspect(runningPsResponses);\n\t\tfor (DockerCliComposePsResponse psResponse : runningPsResponses) {\n\t\t\tDockerCliInspectResponse inspectResponse = inspectContainer(psResponse.id(), inspected);\n\t\t\tAssert.state(inspectResponse != null, () -> \"Failed to inspect container '%s'\".formatted(psResponse.id()));\n\t\t\tresult.add(new DefaultRunningService(this.hostname, dockerComposeFile, psResponse, inspectResponse));\n\t\t}\n\t\treturn Collections.unmodifiableList(result);\n\t}\n\n\tprivate Map<String, DockerCliInspectResponse> inspect(List<DockerCliComposePsResponse> runningPsResponses) {\n\t\tList<String> ids = runningPsResponses.stream().map(DockerCliComposePsResponse::id).toList();\n\t\tList<DockerCliInspectResponse> inspectResponses = this.cli.run(new DockerCliCommand.Inspect(ids));\n\t\treturn inspectResponses.stream().collect(Collectors.toMap(DockerCliInspectResponse::id, Function.identity()));\n\t}\n\n\tprivate @Nullable DockerCliInspectResponse inspectContainer(String id,\n\t\t\tMap<String, DockerCliInspectResponse> inspected) {\n\t\tDockerCliInspectResponse inspect = inspected.get(id);\n\t\tif (inspect != null) {\n\t\t\treturn inspect;\n\t\t}\n\t\t// Docker Compose v2.23.0 returns truncated ids, so we have to do a prefix match\n\t\tfor (Entry<String, DockerCliInspectResponse> entry : inspected.entrySet()) {\n\t\t\tif (entry.getKey().startsWith(id)) {\n\t\t\t\treturn entry.getValue();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<DockerCliComposePsResponse> runComposePs() {\n\t\treturn this.cli.run(new DockerCliCommand.ComposePs());\n\t}\n\n\tprivate boolean isRunning(DockerCliComposePsResponse psResponse) {\n\t\treturn !\"exited\".equals(psResponse.state());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DefaultRunningService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\n\n/**\n * Default {@link RunningService} implementation backed by {@link DockerCli} responses.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultRunningService implements RunningService, OriginProvider {\n\n\tprivate final Origin origin;\n\n\tprivate final String name;\n\n\tprivate final ImageReference image;\n\n\tprivate final DockerHost host;\n\n\tprivate final DefaultConnectionPorts ports;\n\n\tprivate final Map<String, String> labels;\n\n\tprivate final DockerEnv env;\n\n\tprivate final @Nullable DockerComposeFile composeFile;\n\n\tDefaultRunningService(DockerHost host, @Nullable DockerComposeFile composeFile,\n\t\t\tDockerCliComposePsResponse composePsResponse, DockerCliInspectResponse inspectResponse) {\n\t\tthis.origin = new DockerComposeOrigin(composeFile, composePsResponse.name());\n\t\tthis.name = composePsResponse.name();\n\t\tthis.image = ImageReference\n\t\t\t.of((composePsResponse.image() != null) ? composePsResponse.image() : inspectResponse.config().image());\n\t\tthis.host = host;\n\t\tthis.ports = new DefaultConnectionPorts(inspectResponse);\n\t\tthis.env = new DockerEnv(inspectResponse.config().env());\n\t\tthis.labels = Collections.unmodifiableMap(inspectResponse.config().labels());\n\t\tthis.composeFile = composeFile;\n\t}\n\n\t@Override\n\tpublic Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Override\n\tpublic String name() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic ImageReference image() {\n\t\treturn this.image;\n\t}\n\n\t@Override\n\tpublic String host() {\n\t\treturn this.host.toString();\n\t}\n\n\t@Override\n\tpublic ConnectionPorts ports() {\n\t\treturn this.ports;\n\t}\n\n\t@Override\n\tpublic Map<String, @Nullable String> env() {\n\t\treturn this.env.asMap();\n\t}\n\n\t@Override\n\tpublic Map<String, String> labels() {\n\t\treturn this.labels;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic @Nullable DockerComposeFile composeFile() {\n\t\treturn this.composeFile;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCli.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeVersion;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.Type;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Wrapper around {@code docker} and {@code docker-compose} command line tools.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCli {\n\n\tprivate static final Map<@Nullable File, DockerCommands> dockerCommandsCache = new HashMap<>();\n\n\tprivate static final Log logger = LogFactory.getLog(DockerCli.class);\n\n\tprivate final ProcessRunner processRunner;\n\n\tprivate final DockerCommands dockerCommands;\n\n\tprivate final DockerComposeOptions dockerComposeOptions;\n\n\tprivate final ComposeVersion composeVersion;\n\n\t/**\n\t * Create a new {@link DockerCli} instance.\n\t * @param workingDirectory the working directory or {@code null}\n\t * @param dockerComposeOptions the Docker Compose options to use or {@code null}.\n\t */\n\tDockerCli(@Nullable File workingDirectory, @Nullable DockerComposeOptions dockerComposeOptions) {\n\t\tthis.processRunner = new ProcessRunner(workingDirectory);\n\t\tthis.dockerCommands = dockerCommandsCache.computeIfAbsent(workingDirectory,\n\t\t\t\t(key) -> new DockerCommands(this.processRunner));\n\t\tthis.dockerComposeOptions = (dockerComposeOptions != null) ? dockerComposeOptions : DockerComposeOptions.none();\n\t\tthis.composeVersion = ComposeVersion.of(this.dockerCommands.get(Type.DOCKER_COMPOSE).version());\n\t}\n\n\t/**\n\t * Run the given {@link DockerCli} command and return the response.\n\t * @param <R> the response type\n\t * @param dockerCommand the command to run\n\t * @return the response\n\t */\n\t<R> R run(DockerCliCommand<R> dockerCommand) {\n\t\tList<String> command = createCommand(dockerCommand.getType());\n\t\tcommand.addAll(dockerCommand.getCommand(this.composeVersion));\n\t\tConsumer<String> outputConsumer = createOutputConsumer(dockerCommand.getLogLevel());\n\t\tString response = this.processRunner.run(outputConsumer, command.toArray(new String[0]));\n\t\treturn dockerCommand.convert(response);\n\t}\n\n\tprivate @Nullable Consumer<String> createOutputConsumer(@Nullable LogLevel logLevel) {\n\t\tif (logLevel == null || logLevel == LogLevel.OFF) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (line) -> logLevel.log(logger, line);\n\t}\n\n\tprivate List<String> createCommand(Type type) {\n\t\treturn switch (type) {\n\t\t\tcase DOCKER -> new ArrayList<>(this.dockerCommands.get(type).command());\n\t\t\tcase DOCKER_COMPOSE -> {\n\t\t\t\tList<String> result = new ArrayList<>(this.dockerCommands.get(type).command());\n\t\t\t\tDockerComposeFile composeFile = this.dockerComposeOptions.composeFile();\n\t\t\t\tif (composeFile != null) {\n\t\t\t\t\tfor (File file : composeFile.getFiles()) {\n\t\t\t\t\t\tresult.add(\"--file\");\n\t\t\t\t\t\tresult.add(file.getPath());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tresult.add(\"--ansi\");\n\t\t\t\tresult.add(\"never\");\n\t\t\t\tSet<String> activeProfiles = this.dockerComposeOptions.activeProfiles();\n\t\t\t\tif (!CollectionUtils.isEmpty(activeProfiles)) {\n\t\t\t\t\tfor (String profile : activeProfiles) {\n\t\t\t\t\t\tresult.add(\"--profile\");\n\t\t\t\t\t\tresult.add(profile);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tList<String> arguments = this.dockerComposeOptions.arguments();\n\t\t\t\tif (!CollectionUtils.isEmpty(arguments)) {\n\t\t\t\t\tresult.addAll(arguments);\n\t\t\t\t}\n\t\t\t\tyield result;\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Return the {@link DockerComposeFile} being used by this CLI instance.\n\t * @return the Docker Compose file\n\t */\n\t@Nullable DockerComposeFile getDockerComposeFile() {\n\t\treturn this.dockerComposeOptions.composeFile();\n\t}\n\n\t/**\n\t * Holds details of the actual CLI commands to invoke.\n\t */\n\tprivate static class DockerCommands {\n\n\t\tprivate final DockerCommand dockerCommand;\n\n\t\tprivate final DockerCommand dockerComposeCommand;\n\n\t\tDockerCommands(ProcessRunner processRunner) {\n\t\t\tthis.dockerCommand = getDockerCommand(processRunner);\n\t\t\tthis.dockerComposeCommand = getDockerComposeCommand(processRunner);\n\t\t}\n\n\t\tprivate DockerCommand getDockerCommand(ProcessRunner processRunner) {\n\t\t\ttry {\n\t\t\t\tString version = processRunner.run(\"docker\", \"version\", \"--format\", \"{{.Client.Version}}\");\n\t\t\t\tlogger.trace(LogMessage.format(\"Using docker %s\", version));\n\t\t\t\treturn new DockerCommand(version, List.of(\"docker\"));\n\t\t\t}\n\t\t\tcatch (ProcessStartException ex) {\n\t\t\t\tthrow new DockerProcessStartException(\"Unable to start docker process. Is docker correctly installed?\",\n\t\t\t\t\t\tex);\n\t\t\t}\n\t\t\tcatch (ProcessExitException ex) {\n\t\t\t\tif (ex.getStdErr().contains(\"docker daemon is not running\")\n\t\t\t\t\t\t|| ex.getStdErr().contains(\"Cannot connect to the Docker daemon\")) {\n\t\t\t\t\tthrow new DockerNotRunningException(ex.getStdErr(), ex);\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate DockerCommand getDockerComposeCommand(ProcessRunner processRunner) {\n\t\t\ttry {\n\t\t\t\tDockerCliComposeVersionResponse response = DockerJson.deserialize(\n\t\t\t\t\t\tprocessRunner.run(\"docker\", \"compose\", \"version\", \"--format\", \"json\"),\n\t\t\t\t\t\tDockerCliComposeVersionResponse.class);\n\t\t\t\tlogger.trace(LogMessage.format(\"Using Docker Compose %s\", response.version()));\n\t\t\t\treturn new DockerCommand(response.version(), List.of(\"docker\", \"compose\"));\n\t\t\t}\n\t\t\tcatch (ProcessExitException ex) {\n\t\t\t\t// Ignore and try docker-compose\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tDockerCliComposeVersionResponse response = DockerJson.deserialize(\n\t\t\t\t\t\tprocessRunner.run(\"docker-compose\", \"version\", \"--format\", \"json\"),\n\t\t\t\t\t\tDockerCliComposeVersionResponse.class);\n\t\t\t\tlogger.trace(LogMessage.format(\"Using docker-compose %s\", response.version()));\n\t\t\t\treturn new DockerCommand(response.version(), List.of(\"docker-compose\"));\n\t\t\t}\n\t\t\tcatch (ProcessStartException ex) {\n\t\t\t\tthrow new DockerProcessStartException(\n\t\t\t\t\t\t\"Unable to start 'docker-compose' process or use 'docker compose'. Is docker correctly installed?\",\n\t\t\t\t\t\tex);\n\t\t\t}\n\t\t}\n\n\t\tDockerCommand get(Type type) {\n\t\t\treturn switch (type) {\n\t\t\t\tcase DOCKER -> this.dockerCommand;\n\t\t\t\tcase DOCKER_COMPOSE -> this.dockerComposeCommand;\n\t\t\t};\n\t\t}\n\n\t}\n\n\tprivate record DockerCommand(String version, List<String> command) {\n\n\t}\n\n\t/**\n\t * Options for Docker Compose.\n\t *\n\t * @param composeFile the Docker Compose file to use\n\t * @param activeProfiles the profiles to activate\n\t * @param arguments the arguments to pass to Docker Compose\n\t */\n\trecord DockerComposeOptions(@Nullable DockerComposeFile composeFile, Set<String> activeProfiles,\n\t\t\tList<String> arguments) {\n\n\t\tDockerComposeOptions(@Nullable DockerComposeFile composeFile, @Nullable Set<String> activeProfiles,\n\t\t\t\t@Nullable List<String> arguments) {\n\t\t\tthis.composeFile = composeFile;\n\t\t\tthis.activeProfiles = (activeProfiles != null) ? activeProfiles : Collections.emptySet();\n\t\t\tthis.arguments = (arguments != null) ? arguments : Collections.emptyList();\n\t\t}\n\n\t\tstatic DockerComposeOptions none() {\n\t\t\treturn new DockerComposeOptions(null, null, null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.function.Function;\n\nimport org.springframework.boot.logging.LogLevel;\n\n/**\n * Commands that can be executed by the {@link DockerCli}.\n *\n * @param <R> the response type\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nabstract sealed class DockerCliCommand<R> {\n\n\tprivate final Type type;\n\n\tprivate final LogLevel logLevel;\n\n\tprivate final Class<?> responseType;\n\n\tprivate final boolean listResponse;\n\n\tprivate final Function<ComposeVersion, List<String>> command;\n\n\tprivate DockerCliCommand(Type type, Class<?> responseType, boolean listResponse, String... command) {\n\t\tthis(type, LogLevel.OFF, responseType, listResponse, command);\n\t}\n\n\tprivate DockerCliCommand(Type type, LogLevel logLevel, Class<?> responseType, boolean listResponse,\n\t\t\tString... command) {\n\t\tthis(type, logLevel, responseType, listResponse, (version) -> List.of(command));\n\t}\n\n\tprivate DockerCliCommand(Type type, LogLevel logLevel, Class<?> responseType, boolean listResponse,\n\t\t\tFunction<ComposeVersion, List<String>> command) {\n\t\tthis.type = type;\n\t\tthis.logLevel = logLevel;\n\t\tthis.responseType = responseType;\n\t\tthis.listResponse = listResponse;\n\t\tthis.command = command;\n\t}\n\n\tType getType() {\n\t\treturn this.type;\n\t}\n\n\tLogLevel getLogLevel() {\n\t\treturn this.logLevel;\n\t}\n\n\tList<String> getCommand(ComposeVersion composeVersion) {\n\t\treturn this.command.apply(composeVersion);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tR convert(String response) {\n\t\tif (this.responseType == None.class) {\n\t\t\treturn (R) None.INSTANCE;\n\t\t}\n\t\tif (this.responseType == String.class) {\n\t\t\treturn (R) response;\n\t\t}\n\t\treturn (R) ((!this.listResponse) ? DockerJson.deserialize(response, this.responseType)\n\t\t\t\t: DockerJson.deserializeToList(response, this.responseType));\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tDockerCliCommand<?> other = (DockerCliCommand<?>) obj;\n\t\tboolean result = this.type == other.type;\n\t\tresult = result && this.responseType == other.responseType;\n\t\tresult = result && this.listResponse == other.listResponse;\n\t\tresult = result\n\t\t\t\t&& this.command.apply(ComposeVersion.UNKNOWN).equals(other.command.apply(ComposeVersion.UNKNOWN));\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.type, this.responseType, this.listResponse, this.command);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"DockerCliCommand [type=%s, responseType=%s, listResponse=%s, command=%s]\".formatted(this.type,\n\t\t\t\tthis.responseType, this.listResponse, this.command);\n\t}\n\n\tprotected static String[] join(Collection<String> command, Collection<String> args) {\n\t\tList<String> result = new ArrayList<>(command);\n\t\tresult.addAll(args);\n\t\treturn result.toArray(new String[0]);\n\t}\n\n\t/**\n\t * The {@code docker context} command.\n\t */\n\tstatic final class Context extends DockerCliCommand<List<DockerCliContextResponse>> {\n\n\t\tContext() {\n\t\t\tsuper(Type.DOCKER, DockerCliContextResponse.class, true, \"context\", \"ls\", \"--format={{ json . }}\");\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker inspect} command.\n\t */\n\tstatic final class Inspect extends DockerCliCommand<List<DockerCliInspectResponse>> {\n\n\t\tInspect(Collection<String> ids) {\n\t\t\tsuper(Type.DOCKER, DockerCliInspectResponse.class, true,\n\t\t\t\t\tjoin(List.of(\"inspect\", \"--format={{ json . }}\"), ids));\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose config} command.\n\t */\n\tstatic final class ComposeConfig extends DockerCliCommand<DockerCliComposeConfigResponse> {\n\n\t\tComposeConfig() {\n\t\t\tsuper(Type.DOCKER_COMPOSE, DockerCliComposeConfigResponse.class, false, \"config\", \"--format=json\");\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose ps} command.\n\t */\n\tstatic final class ComposePs extends DockerCliCommand<List<DockerCliComposePsResponse>> {\n\n\t\tprivate static final List<String> WITHOUT_ORPHANS = List.of(\"ps\", \"--format=json\");\n\n\t\tprivate static final List<String> WITH_ORPHANS = List.of(\"ps\", \"--orphans=false\", \"--format=json\");\n\n\t\tComposePs() {\n\t\t\tsuper(Type.DOCKER_COMPOSE, LogLevel.OFF, DockerCliComposePsResponse.class, true, ComposePs::getPsCommand);\n\t\t}\n\n\t\tprivate static List<String> getPsCommand(ComposeVersion composeVersion) {\n\t\t\treturn (composeVersion.isLessThan(2, 24)) ? WITHOUT_ORPHANS : WITH_ORPHANS;\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose up} command.\n\t */\n\tstatic final class ComposeUp extends DockerCliCommand<None> {\n\n\t\tComposeUp(LogLevel logLevel, List<String> arguments) {\n\t\t\tsuper(Type.DOCKER_COMPOSE, logLevel, None.class, false, getCommand(arguments));\n\t\t}\n\n\t\tprivate static String[] getCommand(List<String> arguments) {\n\t\t\tList<String> result = new ArrayList<>();\n\t\t\tresult.add(\"up\");\n\t\t\tresult.add(\"--no-color\");\n\t\t\tresult.add(\"--detach\");\n\t\t\tresult.add(\"--wait\");\n\t\t\tresult.addAll(arguments);\n\t\t\treturn result.toArray(String[]::new);\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose down} command.\n\t */\n\tstatic final class ComposeDown extends DockerCliCommand<None> {\n\n\t\tComposeDown(Duration timeout, List<String> arguments) {\n\t\t\tsuper(Type.DOCKER_COMPOSE, None.class, false, getCommand(timeout, arguments));\n\t\t}\n\n\t\tprivate static String[] getCommand(Duration timeout, List<String> arguments) {\n\t\t\tList<String> command = new ArrayList<>();\n\t\t\tcommand.add(\"down\");\n\t\t\tcommand.add(\"--timeout\");\n\t\t\tcommand.add(Long.toString(timeout.toSeconds()));\n\t\t\tcommand.addAll(arguments);\n\t\t\treturn command.toArray(String[]::new);\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose start} command.\n\t */\n\tstatic final class ComposeStart extends DockerCliCommand<None> {\n\n\t\tComposeStart(LogLevel logLevel, List<String> arguments) {\n\t\t\tsuper(Type.DOCKER_COMPOSE, logLevel, None.class, false, getCommand(arguments));\n\t\t}\n\n\t\tprivate static String[] getCommand(List<String> arguments) {\n\t\t\tList<String> command = new ArrayList<>();\n\t\t\tcommand.add(\"start\");\n\t\t\tcommand.addAll(arguments);\n\t\t\treturn command.toArray(String[]::new);\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose stop} command.\n\t */\n\tstatic final class ComposeStop extends DockerCliCommand<None> {\n\n\t\tComposeStop(Duration timeout, List<String> arguments) {\n\t\t\tsuper(Type.DOCKER_COMPOSE, None.class, false, getCommand(timeout, arguments));\n\t\t}\n\n\t\tprivate static String[] getCommand(Duration timeout, List<String> arguments) {\n\t\t\tList<String> command = new ArrayList<>();\n\t\t\tcommand.add(\"stop\");\n\t\t\tcommand.add(\"--timeout\");\n\t\t\tcommand.add(Long.toString(timeout.toSeconds()));\n\t\t\tcommand.addAll(arguments);\n\t\t\treturn command.toArray(String[]::new);\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@code docker compose logs} command.\n\t */\n\tstatic final class ComposeLogs extends DockerCliCommand<String> {\n\n\t\tComposeLogs() {\n\t\t\tsuper(Type.DOCKER_COMPOSE, String.class, false, \"logs\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Command Types.\n\t */\n\tenum Type {\n\n\t\t/**\n\t\t * A command executed using {@code docker}.\n\t\t */\n\t\tDOCKER,\n\n\t\t/**\n\t\t * A command executed using {@code docker compose} or {@code docker-compose}.\n\t\t */\n\t\tDOCKER_COMPOSE\n\n\t}\n\n\tstatic final class None {\n\n\t\tpublic static final None INSTANCE = new None();\n\n\t\tprivate None() {\n\t\t}\n\n\t}\n\n\t/**\n\t * Docker compose version.\n\t *\n\t * @param major the major component\n\t * @param minor the minor component\n\t */\n\trecord ComposeVersion(int major, int minor) {\n\n\t\tstatic final ComposeVersion UNKNOWN = new ComposeVersion(0, 0);\n\n\t\tboolean isLessThan(int major, int minor) {\n\t\t\treturn major() < major || major() == major && minor() < minor;\n\t\t}\n\n\t\tstatic ComposeVersion of(String value) {\n\t\t\ttry {\n\t\t\t\tvalue = (!value.toLowerCase(Locale.ROOT).startsWith(\"v\")) ? value : value.substring(1);\n\t\t\t\tString[] parts = value.split(\"\\\\.\");\n\t\t\t\treturn new ComposeVersion(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn UNKNOWN;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliComposeConfigResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.Map;\n\n/**\n * Response from {@link DockerCliCommand.ComposeConfig docker compose config}.\n *\n * @param name project name\n * @param services services\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nrecord DockerCliComposeConfigResponse(String name, Map<String, DockerCliComposeConfigResponse.Service> services) {\n\n\t/**\n\t * Docker compose service.\n\t *\n\t * @param image the image\n\t */\n\trecord Service(String image) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliComposePsResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Response from {@link DockerCliCommand.ComposePs docker compose ps}.\n *\n * @param id the container ID\n * @param name the name of the service\n * @param image the image reference\n * @param state the state of the container\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nrecord DockerCliComposePsResponse(String id, String name, @Nullable String image, String state) {\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliComposeVersionResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\n/**\n * Response from {@code docker compose version}.\n *\n * @param version the Docker Compose version\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nrecord DockerCliComposeVersionResponse(String version) {\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliContextResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Response from {@link DockerCliCommand.Context docker context}.\n *\n * @param name the name of the context\n * @param current if the context is the current one\n * @param dockerEndpoint the endpoint of the docker daemon, or {@code null} if not known\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nrecord DockerCliContextResponse(String name, boolean current, @Nullable String dockerEndpoint) {\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCliInspectResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Response from {@link DockerCliCommand.Inspect docker inspect}.\n *\n * @param id the container id\n * @param config the config\n * @param hostConfig the host config\n * @param networkSettings the network settings\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nrecord DockerCliInspectResponse(String id, DockerCliInspectResponse.Config config,\n\t\tDockerCliInspectResponse.@Nullable NetworkSettings networkSettings,\n\t\tDockerCliInspectResponse.@Nullable HostConfig hostConfig) {\n\n\t/**\n\t * Configuration for the container that is portable between hosts.\n\t *\n\t * @param image the name (or reference) of the image\n\t * @param labels user-defined key/value metadata\n\t * @param exposedPorts the mapping of exposed ports\n\t * @param env a list of environment variables in the form {@code VAR=value}\n\t */\n\trecord Config(String image, Map<String, String> labels, Map<String, ExposedPort> exposedPorts, List<String> env) {\n\n\t}\n\n\t/**\n\t * Empty object used with {@link Config#exposedPorts()}.\n\t */\n\trecord ExposedPort() {\n\n\t}\n\n\t/**\n\t * A container's resources (cgroups config, ulimits, etc.).\n\t *\n\t * @param networkMode the network mode to use for this container\n\t */\n\trecord HostConfig(String networkMode) {\n\n\t}\n\n\t/**\n\t * The network settings in the API.\n\t *\n\t * @param ports the mapping of container ports to host ports\n\t */\n\trecord NetworkSettings(Map<String, List<HostPort>> ports) {\n\n\t}\n\n\t/**\n\t * Port mapping details.\n\t *\n\t * @param hostIp the host IP\n\t * @param hostPort the host port\n\t */\n\trecord HostPort(String hostIp, String hostPort) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerCompose.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.DockerCli.DockerComposeOptions;\nimport org.springframework.boot.logging.LogLevel;\n\n/**\n * Provides a high-level API to work with Docker compose.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic interface DockerCompose {\n\n\t/**\n\t * Timeout duration used to request a forced stop.\n\t */\n\tDuration FORCE_STOP = Duration.ZERO;\n\n\t/**\n\t * Run {@code docker compose up} to create and start services. Waits until all\n\t * contains are started and healthy.\n\t * @param logLevel the log level used to report progress\n\t */\n\tvoid up(LogLevel logLevel);\n\n\t/**\n\t * Run {@code docker compose up} to create and start services. Waits until all\n\t * contains are started and healthy.\n\t * @param logLevel the log level used to report progress\n\t * @param arguments the arguments to pass to the up command\n\t * @since 3.4.0\n\t */\n\tvoid up(LogLevel logLevel, List<String> arguments);\n\n\t/**\n\t * Run {@code docker compose down} to stop and remove any running services.\n\t * @param timeout the amount of time to wait or {@link #FORCE_STOP} to stop without\n\t * waiting.\n\t */\n\tvoid down(Duration timeout);\n\n\t/**\n\t * Run {@code docker compose down} to stop and remove any running services.\n\t * @param timeout the amount of time to wait or {@link #FORCE_STOP} to stop without\n\t * waiting.\n\t * @param arguments the arguments to pass to the down command\n\t * @since 3.4.0\n\t */\n\tvoid down(Duration timeout, List<String> arguments);\n\n\t/**\n\t * Run {@code docker compose start} to start services. Waits until all containers are\n\t * started and healthy.\n\t * @param logLevel the log level used to report progress\n\t */\n\tvoid start(LogLevel logLevel);\n\n\t/**\n\t * Run {@code docker compose start} to start services. Waits until all containers are\n\t * started and healthy.\n\t * @param logLevel the log level used to report progress\n\t * @param arguments the arguments to pass to the start command\n\t * @since 3.4.0\n\t */\n\tvoid start(LogLevel logLevel, List<String> arguments);\n\n\t/**\n\t * Run {@code docker compose stop} to stop any running services.\n\t * @param timeout the amount of time to wait or {@link #FORCE_STOP} to stop without\n\t * waiting.\n\t */\n\tvoid stop(Duration timeout);\n\n\t/**\n\t * Run {@code docker compose stop} to stop any running services.\n\t * @param timeout the amount of time to wait or {@link #FORCE_STOP} to stop without\n\t * waiting.\n\t * @param arguments the arguments to pass to the stop command\n\t * @since 3.4.0\n\t */\n\tvoid stop(Duration timeout, List<String> arguments);\n\n\t/**\n\t * Run {@code docker compose logs} to view Docker Compose's recent logs.\n\t * @return the recent logs\n\t * @since 4.1.0\n\t */\n\tString logs();\n\n\t/**\n\t * Return if services have been defined in the {@link DockerComposeFile} for the\n\t * active profiles.\n\t * @return {@code true} if services have been defined\n\t * @see #hasDefinedServices()\n\t */\n\tboolean hasDefinedServices();\n\n\t/**\n\t * Return the running services for the active profile, or an empty list if no services\n\t * are running.\n\t * @return the list of running services\n\t */\n\tList<RunningService> getRunningServices();\n\n\t/**\n\t * Factory method used to create a {@link DockerCompose} instance.\n\t * @param file the Docker Compose file\n\t * @param hostname the hostname used for services or {@code null} if the hostname\n\t * should be deduced\n\t * @param activeProfiles a set of the profiles that should be activated\n\t * @return a {@link DockerCompose} instance\n\t */\n\tstatic DockerCompose get(DockerComposeFile file, @Nullable String hostname, Set<String> activeProfiles) {\n\t\treturn get(file, hostname, activeProfiles, Collections.emptyList());\n\t}\n\n\t/**\n\t * Factory method used to create a {@link DockerCompose} instance.\n\t * @param file the Docker Compose file\n\t * @param hostname the hostname used for services or {@code null} if the hostname\n\t * should be deduced\n\t * @param activeProfiles a set of the profiles that should be activated\n\t * @param arguments the arguments to pass to Docker Compose\n\t * @return a {@link DockerCompose} instance\n\t * @since 3.4.0\n\t */\n\tstatic DockerCompose get(DockerComposeFile file, @Nullable String hostname, Set<String> activeProfiles,\n\t\t\tList<String> arguments) {\n\t\tDockerCli cli = new DockerCli(null, new DockerComposeOptions(file, activeProfiles, arguments));\n\t\treturn new DefaultDockerCompose(cli, hostname);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerComposeFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A reference to a Docker Compose file (usually named {@code compose.yaml}).\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n * @see #of(File)\n * @see #of(Collection)\n * @see #find(File)\n */\npublic final class DockerComposeFile {\n\n\tprivate static final List<String> SEARCH_ORDER = List.of(\"compose.yaml\", \"compose.yml\", \"docker-compose.yaml\",\n\t\t\t\"docker-compose.yml\");\n\n\tprivate final List<File> files;\n\n\tprivate DockerComposeFile(List<File> files) {\n\t\tAssert.isTrue(!files.isEmpty(), \"'files' must not be empty\");\n\t\tthis.files = files.stream().map(DockerComposeFile::toCanonicalFile).toList();\n\t}\n\n\tprivate static File toCanonicalFile(File file) {\n\t\ttry {\n\t\t\treturn file.getCanonicalFile();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the source Docker Compose files.\n\t * @return the source Docker Compose files\n\t * @since 3.4.0\n\t */\n\tpublic List<File> getFiles() {\n\t\treturn this.files;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tDockerComposeFile other = (DockerComposeFile) obj;\n\t\treturn this.files.equals(other.files);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.files.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tif (this.files.size() == 1) {\n\t\t\treturn this.files.get(0).getPath();\n\t\t}\n\t\treturn this.files.stream().map(File::toString).collect(Collectors.joining(\", \"));\n\t}\n\n\t/**\n\t * Find the Docker Compose file by searching in the given working directory. Files are\n\t * considered in the same order that {@code docker compose} uses, namely:\n\t * <ul>\n\t * <li>{@code compose.yaml}</li>\n\t * <li>{@code compose.yml}</li>\n\t * <li>{@code docker-compose.yaml}</li>\n\t * <li>{@code docker-compose.yml}</li>\n\t * </ul>\n\t * @param workingDirectory the working directory to search or {@code null} to use the\n\t * current directory\n\t * @return the located file or {@code null} if no Docker Compose file can be found\n\t */\n\tpublic static @Nullable DockerComposeFile find(@Nullable File workingDirectory) {\n\t\tFile base = (workingDirectory != null) ? workingDirectory : new File(\".\");\n\t\tif (!base.exists()) {\n\t\t\treturn null;\n\t\t}\n\t\tAssert.state(base.isDirectory(), () -> \"'%s' is not a directory\".formatted(base));\n\t\tPath basePath = base.toPath();\n\t\tfor (String candidate : SEARCH_ORDER) {\n\t\t\tPath resolved = basePath.resolve(candidate);\n\t\t\tif (Files.exists(resolved)) {\n\t\t\t\treturn of(resolved.toAbsolutePath().toFile());\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create a new {@link DockerComposeFile} for the given {@link File}.\n\t * @param file the source file\n\t * @return the Docker Compose file\n\t */\n\tpublic static DockerComposeFile of(File file) {\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tAssert.isTrue(file.exists(), () -> \"'file' [%s] must exist\".formatted(file));\n\t\tAssert.isTrue(file.isFile(), () -> \"'file' [%s] must be a normal file\".formatted(file));\n\t\treturn new DockerComposeFile(Collections.singletonList(file));\n\t}\n\n\t/**\n\t * Creates a new {@link DockerComposeFile} for the given {@link File files}.\n\t * @param files the source files\n\t * @return the Docker Compose file\n\t * @since 3.4.0\n\t */\n\tpublic static DockerComposeFile of(Collection<? extends File> files) {\n\t\tAssert.notNull(files, \"'files' must not be null\");\n\t\tfor (File file : files) {\n\t\t\tAssert.notNull(file, \"'files' must not contain null elements\");\n\t\t\tAssert.isTrue(file.exists(), () -> \"'files' content [%s] must exist\".formatted(file));\n\t\t\tAssert.isTrue(file.isFile(), () -> \"'files' content [%s] must be a normal file\".formatted(file));\n\t\t}\n\t\treturn new DockerComposeFile(List.copyOf(files));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerComposeOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.origin.Origin;\n\n/**\n * An origin which points to a service defined in Docker Compose.\n *\n * @param composeFile the Docker Compose file\n * @param serviceName name of the Docker Compose service\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @since 3.1.0\n */\npublic record DockerComposeOrigin(@Nullable DockerComposeFile composeFile, String serviceName) implements Origin {\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Docker compose service '%s' defined in %s\".formatted(this.serviceName,\n\t\t\t\t(this.composeFile != null) ? this.composeFile : \"default compose file\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerEnv.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Parses and provides access to docker {@code env} data.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerEnv {\n\n\tprivate final Map<String, @Nullable String> map;\n\n\t/**\n\t * Create a new {@link DockerEnv} instance.\n\t * @param env a list of env entries in the form {@code name=value} or {@code name}.\n\t */\n\tDockerEnv(@Nullable List<String> env) {\n\t\tthis.map = parse(env);\n\t}\n\n\tprivate Map<String, @Nullable String> parse(@Nullable List<String> env) {\n\t\tif (CollectionUtils.isEmpty(env)) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<String, @Nullable String> result = new LinkedHashMap<>();\n\t\tenv.stream().map(this::parseEntry).forEach((entry) -> result.put(entry.key(), entry.value()));\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n\tprivate Entry parseEntry(String entry) {\n\t\tint index = entry.indexOf('=');\n\t\tif (index != -1) {\n\t\t\tString key = entry.substring(0, index);\n\t\t\tString value = entry.substring(index + 1);\n\t\t\treturn new Entry(key, value);\n\t\t}\n\t\treturn new Entry(entry, null);\n\t}\n\n\t/**\n\t * Return the env as a {@link Map}.\n\t * @return the env as a map\n\t */\n\tMap<String, @Nullable String> asMap() {\n\t\treturn this.map;\n\t}\n\n\tprivate record Entry(String key, @Nullable String value) {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\n/**\n * Base class for docker exceptions.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic abstract class DockerException extends RuntimeException {\n\n\tpublic DockerException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic DockerException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerHost.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.net.URI;\nimport java.util.List;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * A docker host as defined by the user or deduced.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nfinal class DockerHost {\n\n\tprivate static final String LOCALHOST = \"127.0.0.1\";\n\n\tprivate final String host;\n\n\tprivate DockerHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tDockerHost other = (DockerHost) obj;\n\t\treturn this.host.equals(other.host);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.host.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.host;\n\t}\n\n\t/**\n\t * Get or deduce a new {@link DockerHost} instance.\n\t * @param host the host to use or {@code null} to deduce\n\t * @param contextsSupplier a supplier to provide a list of\n\t * {@link DockerCliContextResponse}\n\t * @return a new docker host instance\n\t */\n\tstatic DockerHost get(@Nullable String host, Supplier<List<DockerCliContextResponse>> contextsSupplier) {\n\t\treturn get(host, System::getenv, contextsSupplier);\n\t}\n\n\t/**\n\t * Get or deduce a new {@link DockerHost} instance.\n\t * @param host the host to use or {@code null} to deduce\n\t * @param systemEnv access to the system environment\n\t * @param contextsSupplier a supplier to provide a list of\n\t * {@link DockerCliContextResponse}\n\t * @return a new docker host instance\n\t */\n\tstatic DockerHost get(@Nullable String host, Function<String, @Nullable String> systemEnv,\n\t\t\tSupplier<List<DockerCliContextResponse>> contextsSupplier) {\n\t\thost = (StringUtils.hasText(host)) ? host : fromServicesHostEnv(systemEnv);\n\t\thost = (StringUtils.hasText(host)) ? host : fromDockerHostEnv(systemEnv);\n\t\thost = (StringUtils.hasText(host)) ? host : fromCurrentContext(contextsSupplier);\n\t\thost = (StringUtils.hasText(host)) ? host : LOCALHOST;\n\t\treturn new DockerHost(host);\n\t}\n\n\tprivate static @Nullable String fromServicesHostEnv(Function<String, @Nullable String> systemEnv) {\n\t\treturn systemEnv.apply(\"SERVICES_HOST\");\n\t}\n\n\tprivate static @Nullable String fromDockerHostEnv(Function<String, @Nullable String> systemEnv) {\n\t\treturn fromEndpoint(systemEnv.apply(\"DOCKER_HOST\"));\n\t}\n\n\tprivate static @Nullable String fromCurrentContext(Supplier<List<DockerCliContextResponse>> contextsSupplier) {\n\t\tDockerCliContextResponse current = getCurrentContext(contextsSupplier.get());\n\t\treturn (current != null) ? fromEndpoint(current.dockerEndpoint()) : null;\n\t}\n\n\tprivate static @Nullable DockerCliContextResponse getCurrentContext(List<DockerCliContextResponse> candidates) {\n\t\treturn candidates.stream().filter(DockerCliContextResponse::current).findFirst().orElse(null);\n\t}\n\n\tprivate static @Nullable String fromEndpoint(@Nullable String endpoint) {\n\t\treturn (StringUtils.hasLength(endpoint)) ? fromUri(URI.create(endpoint)) : null;\n\t}\n\n\tprivate static @Nullable String fromUri(URI uri) {\n\t\ttry {\n\t\t\treturn switch (uri.getScheme()) {\n\t\t\t\tcase \"http\", \"https\", \"tcp\" -> uri.getHost();\n\t\t\t\tdefault -> null;\n\t\t\t};\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerJson.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.List;\nimport java.util.Locale;\n\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.JavaType;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * Support class used to handle JSON returned from the {@link DockerCli}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nfinal class DockerJson {\n\n\tprivate static final JsonMapper jsonMapper = JsonMapper.builder()\n\t\t.defaultLocale(Locale.ENGLISH)\n\t\t.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)\n\t\t.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)\n\t\t.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)\n\t\t.build();\n\n\tprivate DockerJson() {\n\t}\n\n\t/**\n\t * Deserialize JSON to a list. Handles JSON arrays and multiple JSON objects in\n\t * separate lines.\n\t * @param <T> the item type\n\t * @param json the source JSON\n\t * @param itemType the item type\n\t * @return a list of items\n\t */\n\tstatic <T> List<T> deserializeToList(String json, Class<T> itemType) {\n\t\tif (json.startsWith(\"[\")) {\n\t\t\tJavaType javaType = jsonMapper.getTypeFactory().constructCollectionType(List.class, itemType);\n\t\t\treturn deserialize(json, javaType);\n\t\t}\n\t\treturn json.trim().lines().map((line) -> deserialize(line, itemType)).toList();\n\t}\n\n\t/**\n\t * Deserialize JSON to an object instance.\n\t * @param <T> the result type\n\t * @param json the source JSON\n\t * @param type the result type\n\t * @return the deserialized result\n\t */\n\tstatic <T> T deserialize(String json, Class<T> type) {\n\t\treturn deserialize(json, jsonMapper.getTypeFactory().constructType(type));\n\t}\n\n\tprivate static <T> T deserialize(String json, JavaType type) {\n\t\treturn jsonMapper.readValue(json.trim(), type);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerNotRunningException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\n/**\n * {@link DockerException} thrown if the docker daemon is not running.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class DockerNotRunningException extends DockerException {\n\n\tprivate final String errorOutput;\n\n\tDockerNotRunningException(String errorOutput, Throwable cause) {\n\t\tsuper(\"Docker is not running\", cause);\n\t\tthis.errorOutput = errorOutput;\n\t}\n\n\t/**\n\t * Return the error output returned from docker.\n\t * @return the error output\n\t */\n\tpublic String getErrorOutput() {\n\t\treturn this.errorOutput;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerOutputParseException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\n/**\n * {@link DockerException} thrown if the docker JSON cannot be parsed.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class DockerOutputParseException extends DockerException {\n\n\tDockerOutputParseException(String json, Throwable cause) {\n\t\tsuper(\"Failed to parse docker JSON:\\n\\n\" + json, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/DockerProcessStartException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\n/**\n * {@link DockerException} thrown if the docker process cannot be started. Usually\n * indicates that docker is not installed.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class DockerProcessStartException extends DockerException {\n\n\tDockerProcessStartException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ImageName.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A Docker image name of the form {@literal \"docker.io/library/ubuntu\"}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ImageName {\n\n\tprivate static final String DEFAULT_DOMAIN = \"docker.io\";\n\n\tprivate static final String OFFICIAL_REPOSITORY_NAME = \"library\";\n\n\tprivate static final String LEGACY_DOMAIN = \"index.docker.io\";\n\n\tprivate final String domain;\n\n\tprivate final String name;\n\n\tprivate final String string;\n\n\tImageName(@Nullable String domain, String path) {\n\t\tAssert.hasText(path, \"'path' must not be empty\");\n\t\tthis.domain = getDomainOrDefault(domain);\n\t\tthis.name = getNameWithDefaultPath(this.domain, path);\n\t\tthis.string = this.domain + \"/\" + this.name;\n\t}\n\n\t/**\n\t * Return the domain for this image name.\n\t * @return the domain\n\t */\n\tString getDomain() {\n\t\treturn this.domain;\n\t}\n\n\t/**\n\t * Return the name of this image.\n\t * @return the image name\n\t */\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tImageName other = (ImageName) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.domain.equals(other.domain);\n\t\tresult = result && this.name.equals(other.name);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.domain.hashCode();\n\t\tresult = prime * result + this.name.hashCode();\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.string;\n\t}\n\n\tprivate String getDomainOrDefault(@Nullable String domain) {\n\t\tif (domain == null || LEGACY_DOMAIN.equals(domain)) {\n\t\t\treturn DEFAULT_DOMAIN;\n\t\t}\n\t\treturn domain;\n\t}\n\n\tprivate String getNameWithDefaultPath(String domain, String name) {\n\t\tif (DEFAULT_DOMAIN.equals(domain) && !name.contains(\"/\")) {\n\t\t\treturn OFFICIAL_REPOSITORY_NAME + \"/\" + name;\n\t\t}\n\t\treturn name;\n\t}\n\n\tstatic @Nullable String parseDomain(String value) {\n\t\tint firstSlash = value.indexOf('/');\n\t\tString candidate = (firstSlash != -1) ? value.substring(0, firstSlash) : null;\n\t\tif (candidate != null && Regex.DOMAIN.matcher(candidate).matches()) {\n\t\t\treturn candidate;\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic ImageName of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tString domain = parseDomain(value);\n\t\tString path = (domain != null) ? value.substring(domain.length() + 1) : value;\n\t\tAssert.isTrue(Regex.PATH.matcher(path).matches(),\n\t\t\t\t() -> \"'value' path must contain an image reference in the form '[domainHost:port/][path/]name' \"\n\t\t\t\t\t\t+ \"(with 'path' and 'name' containing only [a-z0-9][.][_][-]) [\" + value + \"]\");\n\t\treturn new ImageName(domain, path);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ImageReference.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.regex.Matcher;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A reference to a Docker image of the form {@code \"imagename[:tag|@digest]\"}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 3.1.0\n */\npublic final class ImageReference {\n\n\tprivate final ImageName name;\n\n\tprivate final @Nullable String tag;\n\n\tprivate final @Nullable String digest;\n\n\tprivate final String string;\n\n\tprivate ImageReference(ImageName name, @Nullable String tag, @Nullable String digest) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.name = name;\n\t\tthis.tag = tag;\n\t\tthis.digest = digest;\n\t\tthis.string = buildString(name.toString(), tag, digest);\n\t}\n\n\t/**\n\t * Return the domain for this image name.\n\t * @return the domain\n\t * @see ImageName#getDomain()\n\t */\n\tpublic String getDomain() {\n\t\treturn this.name.getDomain();\n\t}\n\n\t/**\n\t * Return the name of this image.\n\t * @return the image name\n\t * @see ImageName#getName()\n\t */\n\tpublic String getName() {\n\t\treturn this.name.getName();\n\t}\n\n\t/**\n\t * Return the tag from the reference or {@code null}.\n\t * @return the referenced tag\n\t */\n\tpublic @Nullable String getTag() {\n\t\treturn this.tag;\n\t}\n\n\t/**\n\t * Return the digest from the reference or {@code null}.\n\t * @return the referenced digest\n\t */\n\tpublic @Nullable String getDigest() {\n\t\treturn this.digest;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tImageReference other = (ImageReference) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.name.equals(other.name);\n\t\tresult = result && ObjectUtils.nullSafeEquals(this.tag, other.tag);\n\t\tresult = result && ObjectUtils.nullSafeEquals(this.digest, other.digest);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.name.hashCode();\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.tag);\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.digest);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.string;\n\t}\n\n\tprivate String buildString(String name, @Nullable String tag, @Nullable String digest) {\n\t\tStringBuilder string = new StringBuilder(name);\n\t\tif (tag != null) {\n\t\t\tstring.append(\":\").append(tag);\n\t\t}\n\t\tif (digest != null) {\n\t\t\tstring.append(\"@\").append(digest);\n\t\t}\n\t\treturn string.toString();\n\t}\n\n\t/**\n\t * Create a new {@link ImageReference} from the given value. The following value forms\n\t * can be used:\n\t * <ul>\n\t * <li>{@code name} (maps to {@code docker.io/library/name})</li>\n\t * <li>{@code domain/name}</li>\n\t * <li>{@code domain:port/name}</li>\n\t * <li>{@code domain:port/name:tag}</li>\n\t * <li>{@code domain:port/name@digest}</li>\n\t * </ul>\n\t * @param value the value to parse\n\t * @return an {@link ImageReference} instance\n\t */\n\tpublic static ImageReference of(String value) {\n\t\tAssert.hasText(value, \"'value' must not be null\");\n\t\tString domain = ImageName.parseDomain(value);\n\t\tString path = (domain != null) ? value.substring(domain.length() + 1) : value;\n\t\tString digest = null;\n\t\tint digestSplit = path.indexOf(\"@\");\n\t\tif (digestSplit != -1) {\n\t\t\tString remainder = path.substring(digestSplit + 1);\n\t\t\tMatcher matcher = Regex.DIGEST.matcher(remainder);\n\t\t\tif (matcher.find()) {\n\t\t\t\tdigest = remainder.substring(0, matcher.end());\n\t\t\t\tremainder = remainder.substring(matcher.end());\n\t\t\t\tpath = path.substring(0, digestSplit) + remainder;\n\t\t\t}\n\t\t}\n\t\tString tag = null;\n\t\tint tagSplit = path.lastIndexOf(\":\");\n\t\tif (tagSplit != -1) {\n\t\t\tString remainder = path.substring(tagSplit + 1);\n\t\t\tMatcher matcher = Regex.TAG.matcher(remainder);\n\t\t\tif (matcher.find()) {\n\t\t\t\ttag = remainder.substring(0, matcher.end());\n\t\t\t\tremainder = remainder.substring(matcher.end());\n\t\t\t\tpath = path.substring(0, tagSplit) + remainder;\n\t\t\t}\n\t\t}\n\t\tAssert.isTrue(Regex.PATH.matcher(path).matches(),\n\t\t\t\t() -> \"'value' path must contain an image reference in the form \"\n\t\t\t\t\t\t+ \"'[domainHost:port/][path/]name[:tag][@digest] \"\n\t\t\t\t\t\t+ \"(with 'path' and 'name' containing only [a-z0-9][.][_][-]) [\" + value + \"]\");\n\t\tImageName name = new ImageName(domain, path);\n\t\treturn new ImageReference(name, tag, digest);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessExitException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Exception thrown by {@link ProcessRunner} when the process exits with a non-zero code.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ProcessExitException extends RuntimeException {\n\n\tprivate final int exitCode;\n\n\tprivate final String[] command;\n\n\tprivate final String stdOut;\n\n\tprivate final String stdErr;\n\n\tProcessExitException(int exitCode, String[] command, String stdOut, String stdErr) {\n\t\tthis(exitCode, command, stdOut, stdErr, null);\n\t}\n\n\tProcessExitException(int exitCode, String[] command, String stdOut, String stdErr, @Nullable Throwable cause) {\n\t\tsuper(buildMessage(exitCode, command, stdOut, stdErr), cause);\n\t\tthis.exitCode = exitCode;\n\t\tthis.command = command;\n\t\tthis.stdOut = stdOut;\n\t\tthis.stdErr = stdErr;\n\t}\n\n\tprivate static String buildMessage(int exitCode, String[] command, String stdOut, String strErr) {\n\t\treturn \"'%s' failed with exit code %d.\\n\\nStdout:\\n%s\\n\\nStderr:\\n%s\".formatted(String.join(\" \", command),\n\t\t\t\texitCode, stdOut, strErr);\n\t}\n\n\tint getExitCode() {\n\t\treturn this.exitCode;\n\t}\n\n\tString[] getCommand() {\n\t\treturn this.command;\n\t}\n\n\tString getStdOut() {\n\t\treturn this.stdOut;\n\t}\n\n\tString getStdErr() {\n\t\treturn this.stdErr;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Locale;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Runs a process and captures the result.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ProcessRunner {\n\n\tprivate static final String USR_LOCAL_BIN = \"/usr/local/bin\";\n\n\tprivate static final boolean MAC_OS = System.getProperty(\"os.name\").toLowerCase(Locale.ROOT).contains(\"mac\");\n\n\tprivate static final Log logger = LogFactory.getLog(ProcessRunner.class);\n\n\tprivate final @Nullable File workingDirectory;\n\n\t/**\n\t * Create a new {@link ProcessRunner} instance.\n\t */\n\tProcessRunner() {\n\t\tthis(null);\n\t}\n\n\t/**\n\t * Create a new {@link ProcessRunner} instance.\n\t * @param workingDirectory the working directory for the process\n\t */\n\tProcessRunner(@Nullable File workingDirectory) {\n\t\tthis.workingDirectory = workingDirectory;\n\t}\n\n\t/**\n\t * Runs the given {@code command}. If the process exits with an error code other than\n\t * zero, an {@link ProcessExitException} will be thrown.\n\t * @param command the command to run\n\t * @return the output of the command\n\t * @throws ProcessExitException if execution failed\n\t */\n\tString run(String... command) {\n\t\treturn run(null, command);\n\t}\n\n\t/**\n\t * Runs the given {@code command}. If the process exits with an error code other than\n\t * zero, an {@link ProcessExitException} will be thrown.\n\t * @param outputConsumer consumer used to accept output one line at a time\n\t * @param command the command to run\n\t * @return the output of the command\n\t * @throws ProcessExitException if execution failed\n\t */\n\tString run(@Nullable Consumer<String> outputConsumer, String... command) {\n\t\tlogger.trace(LogMessage.of(() -> \"Running '%s'\".formatted(String.join(\" \", command))));\n\t\tProcess process = startProcess(command);\n\t\tReaderThread stdOutReader = new ReaderThread(process.getInputStream(), \"stdout\", outputConsumer);\n\t\tReaderThread stdErrReader = new ReaderThread(process.getErrorStream(), \"stderr\", outputConsumer);\n\t\tlogger.trace(\"Waiting for process exit\");\n\t\tint exitCode = waitForProcess(process);\n\t\tlogger.trace(LogMessage.format(\"Process exited with exit code %d\", exitCode));\n\t\tString stdOut = stdOutReader.toString();\n\t\tString stdErr = stdErrReader.toString();\n\t\tif (exitCode != 0) {\n\t\t\tthrow new ProcessExitException(exitCode, command, stdOut, stdErr);\n\t\t}\n\t\treturn stdOut;\n\t}\n\n\tprivate Process startProcess(String[] command) {\n\t\tProcessBuilder processBuilder = new ProcessBuilder(command);\n\t\tprocessBuilder.directory(this.workingDirectory);\n\t\ttry {\n\t\t\treturn processBuilder.start();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tString path = processBuilder.environment().get(\"PATH\");\n\t\t\tif (MAC_OS && path != null && !path.contains(USR_LOCAL_BIN)\n\t\t\t\t\t&& !command[0].startsWith(USR_LOCAL_BIN + \"/\")) {\n\t\t\t\tString[] localCommand = command.clone();\n\t\t\t\tlocalCommand[0] = USR_LOCAL_BIN + \"/\" + localCommand[0];\n\t\t\t\treturn startProcess(localCommand);\n\t\t\t}\n\t\t\tthrow new ProcessStartException(command, ex);\n\t\t}\n\t}\n\n\tprivate int waitForProcess(Process process) {\n\t\ttry {\n\t\t\treturn process.waitFor();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tthrow new IllegalStateException(\"Interrupted waiting for %s\".formatted(process));\n\t\t}\n\t}\n\n\t/**\n\t * Thread used to read stream input from the process.\n\t */\n\tprivate static class ReaderThread extends Thread {\n\n\t\tprivate final InputStream source;\n\n\t\tprivate final @Nullable Consumer<String> outputConsumer;\n\n\t\tprivate final StringBuilder output = new StringBuilder();\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tReaderThread(InputStream source, String name, @Nullable Consumer<String> outputConsumer) {\n\t\t\tthis.source = source;\n\t\t\tthis.outputConsumer = outputConsumer;\n\t\t\tsetName(\"OutputReader-\" + name);\n\t\t\tsetDaemon(true);\n\t\t\tstart();\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\ttry (BufferedReader reader = new BufferedReader(\n\t\t\t\t\tnew InputStreamReader(this.source, StandardCharsets.UTF_8))) {\n\t\t\t\tString line = reader.readLine();\n\t\t\t\twhile (line != null) {\n\t\t\t\t\tthis.output.append(line);\n\t\t\t\t\tthis.output.append(\"\\n\");\n\t\t\t\t\tif (this.outputConsumer != null) {\n\t\t\t\t\t\tthis.outputConsumer.accept(line);\n\t\t\t\t\t}\n\t\t\t\t\tline = reader.readLine();\n\t\t\t\t}\n\t\t\t\tthis.latch.countDown();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(\"Failed to read process stream\", ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\ttry {\n\t\t\t\tthis.latch.await();\n\t\t\t\treturn this.output.toString();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/ProcessStartException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\n\n/**\n * Exception thrown by {@link ProcessRunner} when a processes will not start.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ProcessStartException extends RuntimeException {\n\n\tProcessStartException(String[] command, IOException ex) {\n\t\tsuper(\"Unable to start command %s\".formatted(String.join(\" \", command)), ex);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/Regex.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.regex.Pattern;\n\n/**\n * Regular Expressions for image names and references based on those found in the CNCF\n * Distribution Project codebase.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @see <a href=\"https://github.com/distribution/reference/blob/main/reference.go\">OCI\n * Image grammar reference</a>\n * @see <a href=\"https://github.com/distribution/reference/blob/main/regexp.go\">OCI Image\n * grammar implementation</a>\n * @see <a href=\n * \"https://stackoverflow.com/questions/37861791/how-are-docker-image-names-parsed\">How\n * are Docker image names parsed?</a>\n */\nfinal class Regex implements CharSequence {\n\n\tstatic final Pattern DOMAIN;\n\tstatic {\n\t\tRegex component = Regex.oneOf(\"[a-zA-Z0-9]\", \"[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]\");\n\t\tRegex dotComponent = Regex.group(\"[.]\", component);\n\t\tRegex colonPort = Regex.of(\"[:][0-9]+\");\n\t\tRegex dottedDomain = Regex.group(component, dotComponent.oneOrMoreTimes());\n\t\tRegex dottedDomainAndPort = Regex.group(component, dotComponent.oneOrMoreTimes(), colonPort);\n\t\tRegex nameAndPort = Regex.group(component, colonPort);\n\t\tDOMAIN = Regex.oneOf(dottedDomain, nameAndPort, dottedDomainAndPort, \"localhost\").compile();\n\t}\n\n\tprivate static final Regex PATH_COMPONENT;\n\tstatic {\n\t\tRegex segment = Regex.of(\"[a-z0-9]+\");\n\t\tRegex separator = Regex.group(\"[._-]{1,2}\");\n\t\tRegex separatedSegment = Regex.group(separator, segment).oneOrMoreTimes();\n\t\tPATH_COMPONENT = Regex.of(segment, Regex.group(separatedSegment).zeroOrOnce());\n\t}\n\n\tstatic final Pattern PATH;\n\tstatic {\n\t\tRegex component = PATH_COMPONENT;\n\t\tRegex slashComponent = Regex.group(\"[/]\", component);\n\t\tRegex slashComponents = Regex.group(slashComponent.oneOrMoreTimes());\n\t\tPATH = Regex.of(component, slashComponents.zeroOrOnce()).compile();\n\t}\n\n\tstatic final Pattern TAG = Regex.of(\"^[\\\\w][\\\\w.-]{0,127}\").compile();\n\n\tstatic final Pattern DIGEST = Regex.of(\"^[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[A-Fa-f0-9]]{32,}\")\n\t\t.compile();\n\n\tprivate final String value;\n\n\tprivate Regex(CharSequence value) {\n\t\tthis.value = value.toString();\n\t}\n\n\tprivate Regex oneOrMoreTimes() {\n\t\treturn new Regex(this.value + \"+\");\n\t}\n\n\tprivate Regex zeroOrOnce() {\n\t\treturn new Regex(this.value + \"?\");\n\t}\n\n\tPattern compile() {\n\t\treturn Pattern.compile(\"^\" + this.value + \"$\");\n\t}\n\n\t@Override\n\tpublic int length() {\n\t\treturn this.value.length();\n\t}\n\n\t@Override\n\tpublic char charAt(int index) {\n\t\treturn this.value.charAt(index);\n\t}\n\n\t@Override\n\tpublic CharSequence subSequence(int start, int end) {\n\t\treturn this.value.subSequence(start, end);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\tprivate static Regex of(CharSequence... expressions) {\n\t\treturn new Regex(String.join(\"\", expressions));\n\t}\n\n\tprivate static Regex oneOf(CharSequence... expressions) {\n\t\treturn new Regex(\"(?:\" + String.join(\"|\", expressions) + \")\");\n\t}\n\n\tprivate static Regex group(CharSequence... expressions) {\n\t\treturn new Regex(\"(?:\" + String.join(\"\", expressions) + \")\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/RunningService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides details of a running Docker Compose service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic interface RunningService {\n\n\t/**\n\t * Return the name of the service.\n\t * @return the service name\n\t */\n\tString name();\n\n\t/**\n\t * Return the image being used by the service.\n\t * @return the service image\n\t */\n\tImageReference image();\n\n\t/**\n\t * Return the host that can be used to connect to the service.\n\t * @return the service host\n\t */\n\tString host();\n\n\t/**\n\t * Return the ports that can be used to connect to the service.\n\t * @return the service ports\n\t */\n\tConnectionPorts ports();\n\n\t/**\n\t * Return the environment defined for the service.\n\t * @return the service env\n\t */\n\tMap<String, @Nullable String> env();\n\n\t/**\n\t * Return the labels attached to the service.\n\t * @return the service labels\n\t */\n\tMap<String, String> labels();\n\n\t/**\n\t * Return the Docker Compose file for the service.\n\t * @return the Docker Compose file\n\t * @since 3.5.0\n\t */\n\tdefault @Nullable DockerComposeFile composeFile() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/core/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core interfaces and classes for working with Docker Compose.\n */\n@NullMarked\npackage org.springframework.boot.docker.compose.core;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.SpringApplicationShutdownHandlers;\nimport org.springframework.boot.docker.compose.core.DockerCompose;\nimport org.springframework.boot.docker.compose.core.DockerComposeFile;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start.Skip;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Stop;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.context.event.SimpleApplicationEventMulticaster;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Manages the lifecycle for Docker Compose services.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @see DockerComposeListener\n */\nclass DockerComposeLifecycleManager {\n\n\tprivate static final Log logger = LogFactory.getLog(DockerComposeLifecycleManager.class);\n\n\tprivate static final String IGNORE_LABEL = \"org.springframework.boot.ignore\";\n\n\tprivate final @Nullable File workingDirectory;\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final @Nullable ClassLoader classLoader;\n\n\tprivate final SpringApplicationShutdownHandlers shutdownHandlers;\n\n\tprivate final DockerComposeProperties properties;\n\n\tprivate final Set<ApplicationListener<?>> eventListeners;\n\n\tprivate final DockerComposeSkipCheck skipCheck;\n\n\tprivate final ServiceReadinessChecks serviceReadinessChecks;\n\n\tDockerComposeLifecycleManager(ApplicationContext applicationContext,\n\t\t\tSpringApplicationShutdownHandlers shutdownHandlers, DockerComposeProperties properties,\n\t\t\tSet<ApplicationListener<?>> eventListeners) {\n\t\tthis(null, applicationContext, shutdownHandlers, properties, eventListeners, new DockerComposeSkipCheck(),\n\t\t\t\tnull);\n\t}\n\n\tDockerComposeLifecycleManager(@Nullable File workingDirectory, ApplicationContext applicationContext,\n\t\t\tSpringApplicationShutdownHandlers shutdownHandlers, DockerComposeProperties properties,\n\t\t\tSet<ApplicationListener<?>> eventListeners, DockerComposeSkipCheck skipCheck,\n\t\t\t@Nullable ServiceReadinessChecks serviceReadinessChecks) {\n\t\tthis.workingDirectory = workingDirectory;\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.classLoader = applicationContext.getClassLoader();\n\t\tthis.shutdownHandlers = shutdownHandlers;\n\t\tthis.properties = properties;\n\t\tthis.eventListeners = eventListeners;\n\t\tthis.skipCheck = skipCheck;\n\t\tthis.serviceReadinessChecks = (serviceReadinessChecks != null) ? serviceReadinessChecks\n\t\t\t\t: new ServiceReadinessChecks(properties.getReadiness());\n\t}\n\n\tvoid start() {\n\t\tif (Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING) || AotDetector.useGeneratedArtifacts()) {\n\t\t\tlogger.trace(\"Docker Compose support disabled with AOT and native images\");\n\t\t\treturn;\n\t\t}\n\t\tif (!this.properties.isEnabled()) {\n\t\t\tlogger.trace(\"Docker Compose support not enabled\");\n\t\t\treturn;\n\t\t}\n\t\tif (this.skipCheck.shouldSkip(this.classLoader, this.properties.getSkip())) {\n\t\t\tlogger.trace(\"Docker Compose support skipped\");\n\t\t\treturn;\n\t\t}\n\t\tDockerComposeFile composeFile = getComposeFile();\n\t\tSet<String> activeProfiles = this.properties.getProfiles().getActive();\n\t\tList<String> arguments = this.properties.getArguments();\n\t\tDockerCompose dockerCompose = getDockerCompose(composeFile, activeProfiles, arguments);\n\t\tif (!dockerCompose.hasDefinedServices()) {\n\t\t\tlogger.warn(LogMessage.format(\"No services defined in Docker Compose file %s with active profiles %s\",\n\t\t\t\t\tcomposeFile, activeProfiles));\n\t\t\treturn;\n\t\t}\n\t\tLifecycleManagement lifecycleManagement = this.properties.getLifecycleManagement();\n\t\tStart start = this.properties.getStart();\n\t\tStop stop = this.properties.getStop();\n\t\tWait wait = this.properties.getReadiness().getWait();\n\t\tList<RunningService> runningServices = dockerCompose.getRunningServices();\n\t\tif (lifecycleManagement.shouldStart()) {\n\t\t\tSkip skip = this.properties.getStart().getSkip();\n\t\t\tif (skip.shouldSkip(runningServices)) {\n\t\t\t\tlogger.info(skip.getLogMessage());\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttry {\n\t\t\t\t\tstart.getCommand().applyTo(dockerCompose, start.getLogLevel(), start.getArguments());\n\t\t\t\t}\n\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\tlogDockerComposeLogs(dockerCompose, start);\n\t\t\t\t\tthrow ex;\n\t\t\t\t}\n\t\t\t\trunningServices = dockerCompose.getRunningServices();\n\t\t\t\tif (wait == Wait.ONLY_IF_STARTED) {\n\t\t\t\t\twait = Wait.ALWAYS;\n\t\t\t\t}\n\t\t\t\tif (lifecycleManagement.shouldStop()) {\n\t\t\t\t\tthis.shutdownHandlers\n\t\t\t\t\t\t.add(() -> stop.getCommand().applyTo(dockerCompose, stop.getTimeout(), stop.getArguments()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tList<RunningService> relevantServices = new ArrayList<>(runningServices);\n\t\trelevantServices.removeIf(this::isIgnored);\n\t\tif (wait == Wait.ALWAYS || wait == null) {\n\t\t\tthis.serviceReadinessChecks.waitUntilReady(relevantServices);\n\t\t}\n\t\tpublishEvent(new DockerComposeServicesReadyEvent(this.applicationContext, relevantServices));\n\t}\n\n\tprivate void logDockerComposeLogs(DockerCompose dockerCompose, Start start) {\n\t\tString command = start.getCommand().name().toLowerCase(Locale.ROOT);\n\t\tString logs = retrieveLogsIfPossible(dockerCompose);\n\t\tif (logs == null) {\n\t\t\tstart.getLogLevel()\n\t\t\t\t.log(logger, \"docker compose %s failed and its logs were unavailable\".formatted(command));\n\t\t}\n\t\telse {\n\t\t\tstart.getLogLevel()\n\t\t\t\t.log(logger, \"docker compose %s failed with the following logs:%n%n%s\".formatted(command, logs));\n\t\t}\n\t}\n\n\tprivate @Nullable String retrieveLogsIfPossible(DockerCompose dockerCompose) {\n\t\ttry {\n\t\t\treturn dockerCompose.logs();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected DockerComposeFile getComposeFile() {\n\t\tDockerComposeFile composeFile = (CollectionUtils.isEmpty(this.properties.getFile()))\n\t\t\t\t? DockerComposeFile.find(this.workingDirectory) : DockerComposeFile.of(this.properties.getFile());\n\t\tAssert.state(composeFile != null, () -> \"No Docker Compose file found in directory '%s'\".formatted(\n\t\t\t\t((this.workingDirectory != null) ? this.workingDirectory : new File(\".\")).toPath().toAbsolutePath()));\n\t\tif (composeFile.getFiles().size() == 1) {\n\t\t\tlogger.info(LogMessage.format(\"Using Docker Compose file %s\", composeFile.getFiles().get(0)));\n\t\t}\n\t\telse {\n\t\t\tlogger.info(LogMessage.format(\"Using Docker Compose files %s\", composeFile.toString()));\n\t\t}\n\t\treturn composeFile;\n\t}\n\n\tprotected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles,\n\t\t\tList<String> arguments) {\n\t\treturn DockerCompose.get(composeFile, this.properties.getHost(), activeProfiles, arguments);\n\t}\n\n\tprivate boolean isIgnored(RunningService service) {\n\t\treturn service.labels().containsKey(IGNORE_LABEL);\n\t}\n\n\t/**\n\t * Publish a {@link DockerComposeServicesReadyEvent} directly to the event listeners\n\t * since we cannot call {@link ApplicationContext#publishEvent} this early.\n\t * @param event the event to publish\n\t */\n\tprivate void publishEvent(DockerComposeServicesReadyEvent event) {\n\t\tSimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();\n\t\tthis.eventListeners.forEach(multicaster::addApplicationListener);\n\t\tmulticaster.multicastEvent(event);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.Set;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplicationShutdownHandlers;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * {@link ApplicationListener} used to set up a {@link DockerComposeLifecycleManager}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposeListener implements ApplicationListener<ApplicationPreparedEvent> {\n\n\tprivate final SpringApplicationShutdownHandlers shutdownHandlers;\n\n\tDockerComposeListener() {\n\t\tthis(SpringApplication.getShutdownHandlers());\n\t}\n\n\tDockerComposeListener(SpringApplicationShutdownHandlers shutdownHandlers) {\n\t\tthis.shutdownHandlers = shutdownHandlers;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationPreparedEvent event) {\n\t\tConfigurableApplicationContext applicationContext = event.getApplicationContext();\n\t\tBinder binder = Binder.get(applicationContext.getEnvironment());\n\t\tDockerComposeProperties properties = DockerComposeProperties.get(binder);\n\t\tSet<ApplicationListener<?>> eventListeners = event.getSpringApplication().getListeners();\n\t\tcreateDockerComposeLifecycleManager(applicationContext, binder, properties, eventListeners).start();\n\t}\n\n\tprotected DockerComposeLifecycleManager createDockerComposeLifecycleManager(\n\t\t\tConfigurableApplicationContext applicationContext, Binder binder, DockerComposeProperties properties,\n\t\t\tSet<ApplicationListener<?>> eventListeners) {\n\t\treturn new DockerComposeLifecycleManager(applicationContext, this.shutdownHandlers, properties, eventListeners);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.logging.LogLevel;\n\n/**\n * Configuration properties for Docker Compose.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\n@ConfigurationProperties(DockerComposeProperties.NAME)\npublic class DockerComposeProperties {\n\n\tstatic final String NAME = \"spring.docker.compose\";\n\n\t/**\n\t * Whether Docker Compose support is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Arguments to pass to the Docker Compose command.\n\t */\n\tprivate final List<String> arguments = new ArrayList<>();\n\n\t/**\n\t * Paths to the Docker Compose configuration files.\n\t */\n\tprivate final List<File> file = new ArrayList<>();\n\n\t/**\n\t * Docker compose lifecycle management.\n\t */\n\tprivate LifecycleManagement lifecycleManagement = LifecycleManagement.START_AND_STOP;\n\n\t/**\n\t * Hostname or IP of the machine where the docker containers are started.\n\t */\n\tprivate @Nullable String host;\n\n\t/**\n\t * Start configuration.\n\t */\n\tprivate final Start start = new Start();\n\n\t/**\n\t * Stop configuration.\n\t */\n\tprivate final Stop stop = new Stop();\n\n\t/**\n\t * Profiles configuration.\n\t */\n\tprivate final Profiles profiles = new Profiles();\n\n\tprivate final Skip skip = new Skip();\n\n\tprivate final Readiness readiness = new Readiness();\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic List<String> getArguments() {\n\t\treturn this.arguments;\n\t}\n\n\tpublic List<File> getFile() {\n\t\treturn this.file;\n\t}\n\n\tpublic LifecycleManagement getLifecycleManagement() {\n\t\treturn this.lifecycleManagement;\n\t}\n\n\tpublic void setLifecycleManagement(LifecycleManagement lifecycleManagement) {\n\t\tthis.lifecycleManagement = lifecycleManagement;\n\t}\n\n\tpublic @Nullable String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(@Nullable String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic Start getStart() {\n\t\treturn this.start;\n\t}\n\n\tpublic Stop getStop() {\n\t\treturn this.stop;\n\t}\n\n\tpublic Profiles getProfiles() {\n\t\treturn this.profiles;\n\t}\n\n\tpublic Skip getSkip() {\n\t\treturn this.skip;\n\t}\n\n\tpublic Readiness getReadiness() {\n\t\treturn this.readiness;\n\t}\n\n\tstatic DockerComposeProperties get(Binder binder) {\n\t\treturn binder.bind(NAME, DockerComposeProperties.class).orElseGet(DockerComposeProperties::new);\n\t}\n\n\t/**\n\t * Start properties.\n\t */\n\tpublic static class Start {\n\n\t\t/**\n\t\t * Command used to start Docker Compose.\n\t\t */\n\t\tprivate StartCommand command = StartCommand.UP;\n\n\t\t/**\n\t\t * Log level for output.\n\t\t */\n\t\tprivate LogLevel logLevel = LogLevel.INFO;\n\n\t\t/**\n\t\t * Whether to skip executing the start command.\n\t\t */\n\t\tprivate Skip skip = Skip.IF_RUNNING;\n\n\t\t/**\n\t\t * Arguments to pass to the start command.\n\t\t */\n\t\tprivate final List<String> arguments = new ArrayList<>();\n\n\t\tpublic StartCommand getCommand() {\n\t\t\treturn this.command;\n\t\t}\n\n\t\tpublic void setCommand(StartCommand command) {\n\t\t\tthis.command = command;\n\t\t}\n\n\t\tpublic LogLevel getLogLevel() {\n\t\t\treturn this.logLevel;\n\t\t}\n\n\t\tpublic void setLogLevel(LogLevel logLevel) {\n\t\t\tthis.logLevel = logLevel;\n\t\t}\n\n\t\tpublic Skip getSkip() {\n\t\t\treturn this.skip;\n\t\t}\n\n\t\tpublic void setSkip(Skip skip) {\n\t\t\tthis.skip = skip;\n\t\t}\n\n\t\tpublic List<String> getArguments() {\n\t\t\treturn this.arguments;\n\t\t}\n\n\t\t/**\n\t\t * Start command skip mode.\n\t\t */\n\t\tpublic enum Skip {\n\n\t\t\t/**\n\t\t\t * Never skip start.\n\t\t\t */\n\t\t\tNEVER {\n\t\t\t\t@Override\n\t\t\t\tboolean shouldSkip(List<RunningService> runningServices) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\t/**\n\t\t\t * Skip start if there are already services running.\n\t\t\t */\n\t\t\tIF_RUNNING {\n\t\t\t\t@Override\n\t\t\t\tboolean shouldSkip(List<RunningService> runningServices) {\n\t\t\t\t\treturn !runningServices.isEmpty();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tString getLogMessage() {\n\t\t\t\t\treturn \"There are already Docker Compose services running, skipping startup\";\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tabstract boolean shouldSkip(List<RunningService> runningServices);\n\n\t\t\tString getLogMessage() {\n\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Stop properties.\n\t */\n\tpublic static class Stop {\n\n\t\t/**\n\t\t * Command used to stop Docker Compose.\n\t\t */\n\t\tprivate StopCommand command = StopCommand.STOP;\n\n\t\t/**\n\t\t * Timeout for stopping Docker Compose. Use '0' for forced stop.\n\t\t */\n\t\tprivate Duration timeout = Duration.ofSeconds(10);\n\n\t\t/**\n\t\t * Arguments to pass to the stop command.\n\t\t */\n\t\tprivate final List<String> arguments = new ArrayList<>();\n\n\t\tpublic StopCommand getCommand() {\n\t\t\treturn this.command;\n\t\t}\n\n\t\tpublic void setCommand(StopCommand command) {\n\t\t\tthis.command = command;\n\t\t}\n\n\t\tpublic Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\tpublic List<String> getArguments() {\n\t\t\treturn this.arguments;\n\t\t}\n\n\t}\n\n\t/**\n\t * Profiles properties.\n\t */\n\tpublic static class Profiles {\n\n\t\t/**\n\t\t * Docker compose profiles that should be active.\n\t\t */\n\t\tprivate Set<String> active = new LinkedHashSet<>();\n\n\t\tpublic Set<String> getActive() {\n\t\t\treturn this.active;\n\t\t}\n\n\t\tpublic void setActive(Set<String> active) {\n\t\t\tthis.active = active;\n\t\t}\n\n\t}\n\n\t/**\n\t * Skip options.\n\t */\n\tpublic static class Skip {\n\n\t\t/**\n\t\t * Whether to skip in tests.\n\t\t */\n\t\tprivate boolean inTests = true;\n\n\t\tpublic boolean isInTests() {\n\t\t\treturn this.inTests;\n\t\t}\n\n\t\tpublic void setInTests(boolean inTests) {\n\t\t\tthis.inTests = inTests;\n\t\t}\n\n\t}\n\n\t/**\n\t * Readiness properties.\n\t */\n\tpublic static class Readiness {\n\n\t\t/**\n\t\t * Wait strategy to use.\n\t\t */\n\t\tprivate Wait wait = Wait.ALWAYS;\n\n\t\t/**\n\t\t * Timeout of the readiness checks.\n\t\t */\n\t\tprivate Duration timeout = Duration.ofMinutes(2);\n\n\t\t/**\n\t\t * TCP properties.\n\t\t */\n\t\tprivate final Tcp tcp = new Tcp();\n\n\t\tpublic Wait getWait() {\n\t\t\treturn this.wait;\n\t\t}\n\n\t\tpublic void setWait(Wait wait) {\n\t\t\tthis.wait = wait;\n\t\t}\n\n\t\tpublic Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\tpublic Tcp getTcp() {\n\t\t\treturn this.tcp;\n\t\t}\n\n\t\t/**\n\t\t * Readiness wait strategies.\n\t\t */\n\t\tpublic enum Wait {\n\n\t\t\t/**\n\t\t\t * Always perform readiness checks.\n\t\t\t */\n\t\t\tALWAYS,\n\n\t\t\t/**\n\t\t\t * Never perform readiness checks.\n\t\t\t */\n\t\t\tNEVER,\n\n\t\t\t/**\n\t\t\t * Only perform readiness checks if docker was started with lifecycle\n\t\t\t * management.\n\t\t\t */\n\t\t\tONLY_IF_STARTED\n\n\t\t}\n\n\t\t/**\n\t\t * TCP properties.\n\t\t */\n\t\tpublic static class Tcp {\n\n\t\t\t/**\n\t\t\t * Timeout for connections.\n\t\t\t */\n\t\t\tprivate Duration connectTimeout = Duration.ofMillis(200);\n\n\t\t\t/**\n\t\t\t * Timeout for reads.\n\t\t\t */\n\t\t\tprivate Duration readTimeout = Duration.ofMillis(200);\n\n\t\t\tpublic Duration getConnectTimeout() {\n\t\t\t\treturn this.connectTimeout;\n\t\t\t}\n\n\t\t\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\t\t\tthis.connectTimeout = connectTimeout;\n\t\t\t}\n\n\t\t\tpublic Duration getReadTimeout() {\n\t\t\t\treturn this.readTimeout;\n\t\t\t}\n\n\t\t\tpublic void setReadTimeout(Duration readTimeout) {\n\t\t\t\tthis.readTimeout = readTimeout;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeServicesReadyEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.List;\n\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * {@link ApplicationEvent} published when Docker Compose {@link RunningService} instances\n * are available. This event is published from the {@link ApplicationPreparedEvent}\n * listener that starts Docker Compose.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class DockerComposeServicesReadyEvent extends ApplicationEvent {\n\n\tprivate final List<RunningService> runningServices;\n\n\tDockerComposeServicesReadyEvent(ApplicationContext source, List<RunningService> runningServices) {\n\t\tsuper(source);\n\t\tthis.runningServices = runningServices;\n\t}\n\n\t@Override\n\tpublic ApplicationContext getSource() {\n\t\treturn (ApplicationContext) super.getSource();\n\t}\n\n\t/**\n\t * Return the relevant Docker Compose services that are running.\n\t * @return the running services\n\t */\n\tpublic List<RunningService> getRunningServices() {\n\t\treturn this.runningServices;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeSkipCheck.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplicationAotProcessor;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Checks if Docker Compose support should be skipped.\n *\n * @author Phillip Webb\n */\nclass DockerComposeSkipCheck {\n\n\tprivate static final Set<String> REQUIRED_CLASSES = Set.of(\"org.junit.jupiter.api.Test\", \"org.junit.Test\");\n\n\tprivate static final Set<String> SKIPPED_STACK_ELEMENTS;\n\n\tstatic {\n\t\tSet<String> skipped = new LinkedHashSet<>();\n\t\tskipped.add(\"org.junit.runners.\");\n\t\tskipped.add(\"org.junit.platform.\");\n\t\tskipped.add(\"org.springframework.boot.test.\");\n\t\tskipped.add(SpringApplicationAotProcessor.class.getName());\n\t\tskipped.add(\"cucumber.runtime.\");\n\t\tSKIPPED_STACK_ELEMENTS = Collections.unmodifiableSet(skipped);\n\t}\n\n\tboolean shouldSkip(@Nullable ClassLoader classLoader, DockerComposeProperties.Skip properties) {\n\t\tif (properties.isInTests() && hasAtLeastOneRequiredClass(classLoader)) {\n\t\t\tThread thread = Thread.currentThread();\n\t\t\tfor (StackTraceElement element : thread.getStackTrace()) {\n\t\t\t\tif (isSkippedStackElement(element)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean hasAtLeastOneRequiredClass(@Nullable ClassLoader classLoader) {\n\t\tfor (String requiredClass : REQUIRED_CLASSES) {\n\t\t\tif (ClassUtils.isPresent(requiredClass, classLoader)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static boolean isSkippedStackElement(StackTraceElement element) {\n\t\tfor (String skipped : SKIPPED_STACK_ELEMENTS) {\n\t\t\tif (element.getClassName().startsWith(skipped)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/LifecycleManagement.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\n/**\n * Docker Compose lifecycle management.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic enum LifecycleManagement {\n\n\t/**\n\t * Don't start or stop Docker Compose.\n\t */\n\tNONE(false, false),\n\n\t/**\n\t * Start Docker Compose if it's not running.\n\t */\n\tSTART_ONLY(true, false),\n\n\t/**\n\t * Start Docker Compose if it's not running and stop it when the JVM exits.\n\t */\n\tSTART_AND_STOP(true, true);\n\n\tprivate final boolean start;\n\n\tprivate final boolean stop;\n\n\tLifecycleManagement(boolean start, boolean stop) {\n\t\tthis.start = start;\n\t\tthis.stop = stop;\n\t}\n\n\t/**\n\t * Return whether Docker Compose should be started.\n\t * @return whether Docker Compose should be started\n\t */\n\tboolean shouldStart() {\n\t\treturn this.start;\n\t}\n\n\t/**\n\t * Return whether Docker Compose should be stopped.\n\t * @return whether Docker Compose should be stopped\n\t */\n\tboolean shouldStop() {\n\t\treturn this.stop;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\n\n/**\n * Exception thrown if readiness checking has timed out.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic final class ReadinessTimeoutException extends RuntimeException {\n\n\tprivate final Duration timeout;\n\n\tReadinessTimeoutException(Duration timeout, List<ServiceNotReadyException> exceptions) {\n\t\tsuper(buildMessage(timeout, exceptions));\n\t\tthis.timeout = timeout;\n\t\texceptions.forEach(this::addSuppressed);\n\t}\n\n\tprivate static String buildMessage(Duration timeout, List<ServiceNotReadyException> exceptions) {\n\t\tList<String> serviceNames = exceptions.stream()\n\t\t\t.map(ServiceNotReadyException::getService)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.map(RunningService::name)\n\t\t\t.toList();\n\t\treturn \"Readiness timeout of %s reached while waiting for services %s\".formatted(timeout, serviceNames);\n\t}\n\n\t/**\n\t * Return the timeout that was reached.\n\t * @return the timeout\n\t */\n\tpublic Duration getTimeout() {\n\t\treturn this.timeout;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\n\n/**\n * Exception thrown when a single {@link RunningService} is not ready.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceNotReadyException extends RuntimeException {\n\n\tprivate final RunningService service;\n\n\tServiceNotReadyException(RunningService service, String message) {\n\t\tthis(service, message, null);\n\t}\n\n\tServiceNotReadyException(RunningService service, String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.service = service;\n\t}\n\n\tRunningService getService() {\n\t\treturn this.service;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecks.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Utility used to {@link #wait() wait} for {@link RunningService services} to be ready.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceReadinessChecks {\n\n\tprivate static final Log logger = LogFactory.getLog(ServiceReadinessChecks.class);\n\n\tprivate static final String DISABLE_LABEL = \"org.springframework.boot.readiness-check.disable\";\n\n\tprivate static final Duration SLEEP_BETWEEN_READINESS_TRIES = Duration.ofSeconds(1);\n\n\tprivate final Clock clock;\n\n\tprivate final Consumer<Duration> sleep;\n\n\tprivate final DockerComposeProperties.Readiness properties;\n\n\tprivate final TcpConnectServiceReadinessCheck check;\n\n\tServiceReadinessChecks(DockerComposeProperties.Readiness properties) {\n\t\tthis(properties, Clock.systemUTC(), ServiceReadinessChecks::sleep,\n\t\t\t\tnew TcpConnectServiceReadinessCheck(properties.getTcp()));\n\t}\n\n\tServiceReadinessChecks(DockerComposeProperties.Readiness properties, Clock clock, Consumer<Duration> sleep,\n\t\t\tTcpConnectServiceReadinessCheck check) {\n\t\tthis.clock = clock;\n\t\tthis.sleep = sleep;\n\t\tthis.properties = properties;\n\t\tthis.check = check;\n\t}\n\n\t/**\n\t * Wait for the given services to be ready.\n\t * @param runningServices the services to wait for\n\t */\n\tvoid waitUntilReady(List<RunningService> runningServices) {\n\t\tDuration timeout = this.properties.getTimeout();\n\t\tInstant start = this.clock.instant();\n\t\twhile (true) {\n\t\t\tList<ServiceNotReadyException> exceptions = check(runningServices);\n\t\t\tif (exceptions.isEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tDuration elapsed = Duration.between(start, this.clock.instant());\n\t\t\tif (elapsed.compareTo(timeout) > 0) {\n\t\t\t\tthrow new ReadinessTimeoutException(timeout, exceptions);\n\t\t\t}\n\t\t\tthis.sleep.accept(SLEEP_BETWEEN_READINESS_TRIES);\n\t\t}\n\t}\n\n\tprivate List<ServiceNotReadyException> check(List<RunningService> runningServices) {\n\t\tList<ServiceNotReadyException> exceptions = null;\n\t\tfor (RunningService service : runningServices) {\n\t\t\tif (isDisabled(service)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlogger.trace(LogMessage.format(\"Checking readiness of service '%s'\", service));\n\t\t\ttry {\n\t\t\t\tthis.check.check(service);\n\t\t\t\tlogger.trace(LogMessage.format(\"Service '%s' is ready\", service));\n\t\t\t}\n\t\t\tcatch (ServiceNotReadyException ex) {\n\t\t\t\tlogger.trace(LogMessage.format(\"Service '%s' is not ready\", service), ex);\n\t\t\t\texceptions = (exceptions != null) ? exceptions : new ArrayList<>();\n\t\t\t\texceptions.add(ex);\n\t\t\t}\n\t\t}\n\t\treturn (exceptions != null) ? exceptions : Collections.emptyList();\n\t}\n\n\tprivate boolean isDisabled(RunningService service) {\n\t\treturn service.labels().containsKey(DISABLE_LABEL);\n\t}\n\n\tprivate static void sleep(Duration duration) {\n\t\ttry {\n\t\t\tThread.sleep(duration.toMillis());\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/StartCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.List;\n\nimport org.springframework.boot.docker.compose.core.DockerCompose;\nimport org.springframework.boot.logging.LogLevel;\n\n/**\n * Command used to start Docker Compose.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic enum StartCommand {\n\n\t/**\n\t * Start using {@code docker compose up}.\n\t */\n\tUP(DockerCompose::up),\n\n\t/**\n\t * Start using {@code docker compose start}.\n\t */\n\tSTART(DockerCompose::start);\n\n\tprivate final Command command;\n\n\tStartCommand(Command command) {\n\t\tthis.command = command;\n\t}\n\n\tvoid applyTo(DockerCompose dockerCompose, LogLevel logLevel, List<String> arguments) {\n\t\tthis.command.applyTo(dockerCompose, logLevel, arguments);\n\t}\n\n\t@FunctionalInterface\n\tprivate interface Command {\n\n\t\tvoid applyTo(DockerCompose dockerCompose, LogLevel logLevel, List<String> arguments);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/StopCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.springframework.boot.docker.compose.core.DockerCompose;\n\n/**\n * Command used to stop Docker Compose.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic enum StopCommand {\n\n\t/**\n\t * Stop using {@code docker compose down}.\n\t */\n\tDOWN(DockerCompose::down),\n\n\t/**\n\t * Stop using {@code docker compose stop}.\n\t */\n\tSTOP(DockerCompose::stop);\n\n\tprivate final Command command;\n\n\tStopCommand(Command command) {\n\t\tthis.command = command;\n\t}\n\n\tvoid applyTo(DockerCompose dockerCompose, Duration timeout, List<String> arguments) {\n\t\tthis.command.applyTo(dockerCompose, timeout, arguments);\n\t}\n\n\t@FunctionalInterface\n\tprivate interface Command {\n\n\t\tvoid applyTo(DockerCompose dockerCompose, Duration timeout, List<String> arguments);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheck.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\n\n/**\n * Checks readiness by connecting to the exposed TCP ports.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass TcpConnectServiceReadinessCheck {\n\n\tprivate static final String DISABLE_LABEL = \"org.springframework.boot.readiness-check.tcp.disable\";\n\n\tprivate final DockerComposeProperties.Readiness.Tcp properties;\n\n\tTcpConnectServiceReadinessCheck(DockerComposeProperties.Readiness.Tcp properties) {\n\t\tthis.properties = properties;\n\t}\n\n\tvoid check(RunningService service) {\n\t\tif (service.labels().containsKey(DISABLE_LABEL)) {\n\t\t\treturn;\n\t\t}\n\t\tfor (int port : service.ports().getAll(\"tcp\")) {\n\t\t\tcheck(service, port);\n\t\t}\n\t}\n\n\tprivate void check(RunningService service, int port) {\n\t\tint connectTimeout = (int) this.properties.getConnectTimeout().toMillis();\n\t\tint readTimeout = (int) this.properties.getReadTimeout().toMillis();\n\t\ttry (Socket socket = new Socket()) {\n\t\t\tsocket.setSoTimeout(readTimeout);\n\t\t\tsocket.connect(new InetSocketAddress(service.host(), port), connectTimeout);\n\t\t\tcheck(service, port, socket);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new ServiceNotReadyException(service, \"IOException while connecting to port %s\".formatted(port), ex);\n\t\t}\n\t}\n\n\tprivate void check(RunningService service, int port, Socket socket) throws IOException {\n\t\ttry {\n\t\t\t// -1 indicates the socket has been closed immediately\n\t\t\t// Other responses or a timeout are considered as success\n\t\t\tif (socket.getInputStream().read() == -1) {\n\t\t\t\tthrow new ServiceNotReadyException(service,\n\t\t\t\t\t\t\"Immediate disconnect while connecting to port %s\".formatted(port));\n\t\t\t}\n\t\t}\n\t\tcatch (SocketTimeoutException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/lifecycle/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Lifecycle management for Docker Compose with the context of a Spring application.\n */\n@NullMarked\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/ConnectionNamePredicate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection;\n\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.docker.compose.core.ImageReference;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Predicate} that matches against connection name.\n *\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nclass ConnectionNamePredicate implements Predicate<DockerComposeConnectionSource> {\n\n\tprivate final Set<String> required;\n\n\tConnectionNamePredicate(String... required) {\n\t\tAssert.notEmpty(required, \"'required' must not be empty\");\n\t\tthis.required = Arrays.stream(required).map(this::asCanonicalName).collect(Collectors.toSet());\n\t}\n\n\t@Override\n\tpublic boolean test(DockerComposeConnectionSource source) {\n\t\tString actual = getActual(source.getRunningService());\n\t\treturn this.required.contains(actual);\n\t}\n\n\tprivate String getActual(RunningService service) {\n\t\tString label = service.labels().get(\"org.springframework.boot.service-connection\");\n\t\treturn asCanonicalName((label != null) ? label : service.image().getName());\n\t}\n\n\tprivate String asCanonicalName(String name) {\n\t\treturn ImageReference.of(name).getName();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/DockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection;\n\nimport java.nio.file.Path;\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.core.DockerComposeFile;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.ssl.pem.PemSslStore;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for {@link ConnectionDetailsFactory} implementations that provide\n * {@link ConnectionDetails} from a {@link DockerComposeConnectionSource}.\n *\n * @param <D> the connection details type\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic abstract class DockerComposeConnectionDetailsFactory<D extends ConnectionDetails>\n\t\timplements ConnectionDetailsFactory<DockerComposeConnectionSource, D> {\n\n\tprivate final Predicate<DockerComposeConnectionSource> predicate;\n\n\tprivate final String[] requiredClassNames;\n\n\t/**\n\t * Create a new {@link DockerComposeConnectionDetailsFactory} instance.\n\t * @param connectionName the required connection name\n\t * @param requiredClassNames the names of classes that must be present\n\t */\n\tprotected DockerComposeConnectionDetailsFactory(String connectionName, String... requiredClassNames) {\n\t\tthis(new ConnectionNamePredicate(connectionName), requiredClassNames);\n\t}\n\n\t/**\n\t * Create a new {@link DockerComposeConnectionDetailsFactory} instance.\n\t * @param connectionNames the required connection name\n\t * @param requiredClassNames the names of classes that must be present\n\t * @since 3.2.0\n\t */\n\tprotected DockerComposeConnectionDetailsFactory(String[] connectionNames, String... requiredClassNames) {\n\t\tthis(new ConnectionNamePredicate(connectionNames), requiredClassNames);\n\t}\n\n\t/**\n\t * Create a new {@link DockerComposeConnectionDetailsFactory} instance.\n\t * @param predicate a predicate used to check when a service is accepted\n\t * @param requiredClassNames the names of classes that must be present\n\t */\n\tprotected DockerComposeConnectionDetailsFactory(Predicate<DockerComposeConnectionSource> predicate,\n\t\t\tString... requiredClassNames) {\n\t\tthis.predicate = predicate;\n\t\tthis.requiredClassNames = requiredClassNames;\n\t}\n\n\t@Override\n\tpublic final @Nullable D getConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn (!accept(source)) ? null : getDockerComposeConnectionDetails(source);\n\t}\n\n\tprivate boolean accept(DockerComposeConnectionSource source) {\n\t\treturn hasRequiredClasses() && this.predicate.test(source);\n\t}\n\n\tprivate boolean hasRequiredClasses() {\n\t\treturn ObjectUtils.isEmpty(this.requiredClassNames) || Arrays.stream(this.requiredClassNames)\n\t\t\t.allMatch((requiredClassName) -> ClassUtils.isPresent(requiredClassName, null));\n\t}\n\n\t/**\n\t * Get the {@link ConnectionDetails} from the given {@link RunningService}\n\t * {@code source}. May return {@code null} if no connection can be created. Result\n\t * types should consider extending {@link DockerComposeConnectionDetails}.\n\t * @param source the source\n\t * @return the service connection or {@code null}.\n\t */\n\tprotected abstract @Nullable D getDockerComposeConnectionDetails(DockerComposeConnectionSource source);\n\n\t/**\n\t * Convenient base class for {@link ConnectionDetails} results that are backed by a\n\t * {@link RunningService}.\n\t */\n\tprotected static class DockerComposeConnectionDetails implements ConnectionDetails, OriginProvider {\n\n\t\tprivate final @Nullable Origin origin;\n\n\t\tprivate volatile @Nullable SslBundle sslBundle;\n\n\t\t/**\n\t\t * Create a new {@link DockerComposeConnectionDetails} instance.\n\t\t * @param runningService the source {@link RunningService}\n\t\t */\n\t\tprotected DockerComposeConnectionDetails(RunningService runningService) {\n\t\t\tAssert.notNull(runningService, \"'runningService' must not be null\");\n\t\t\tthis.origin = Origin.from(runningService);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getOrigin() {\n\t\t\treturn this.origin;\n\t\t}\n\n\t\tprotected @Nullable SslBundle getSslBundle(RunningService service) {\n\t\t\tif (this.sslBundle != null) {\n\t\t\t\treturn this.sslBundle;\n\t\t\t}\n\t\t\tSslBundle jksSslBundle = getJksSslBundle(service);\n\t\t\tSslBundle pemSslBundle = getPemSslBundle(service);\n\t\t\tif (jksSslBundle == null && pemSslBundle == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (jksSslBundle != null && pemSslBundle != null) {\n\t\t\t\tthrow new IllegalStateException(\"Mutually exclusive JKS and PEM ssl bundles have been configured\");\n\t\t\t}\n\t\t\tSslBundle sslBundle = (jksSslBundle != null) ? jksSslBundle : pemSslBundle;\n\t\t\tthis.sslBundle = sslBundle;\n\t\t\treturn sslBundle;\n\t\t}\n\n\t\tprivate @Nullable SslBundle getJksSslBundle(RunningService service) {\n\t\t\tJksSslStoreDetails keyStoreDetails = getJksSslStoreDetails(service, \"keystore\");\n\t\t\tJksSslStoreDetails trustStoreDetails = getJksSslStoreDetails(service, \"truststore\");\n\t\t\tif (keyStoreDetails == null && trustStoreDetails == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tSslBundleKey key = SslBundleKey.of(service.labels().get(\"org.springframework.boot.sslbundle.jks.key.alias\"),\n\t\t\t\t\tservice.labels().get(\"org.springframework.boot.sslbundle.jks.key.password\"));\n\t\t\tSslOptions options = createSslOptions(\n\t\t\t\t\tservice.labels().get(\"org.springframework.boot.sslbundle.jks.options.ciphers\"),\n\t\t\t\t\tservice.labels().get(\"org.springframework.boot.sslbundle.jks.options.enabled-protocols\"));\n\t\t\tString protocol = service.labels().get(\"org.springframework.boot.sslbundle.jks.protocol\");\n\t\t\tPath workingDirectory = getWorkingDirectory(service);\n\t\t\treturn SslBundle.of(\n\t\t\t\t\tnew JksSslStoreBundle(keyStoreDetails, trustStoreDetails, getResourceLoader(workingDirectory)), key,\n\t\t\t\t\toptions, protocol);\n\t\t}\n\n\t\tprivate ResourceLoader getResourceLoader(@Nullable Path workingDirectory) {\n\t\t\tClassLoader classLoader = ApplicationResourceLoader.get().getClassLoader();\n\t\t\treturn ApplicationResourceLoader.get(classLoader,\n\t\t\t\t\tSpringFactoriesLoader.forDefaultResourceLocation(classLoader), workingDirectory);\n\t\t}\n\n\t\tprivate @Nullable JksSslStoreDetails getJksSslStoreDetails(RunningService service, String storeType) {\n\t\t\tString type = service.labels().get(\"org.springframework.boot.sslbundle.jks.%s.type\".formatted(storeType));\n\t\t\tString provider = service.labels()\n\t\t\t\t.get(\"org.springframework.boot.sslbundle.jks.%s.provider\".formatted(storeType));\n\t\t\tString location = service.labels()\n\t\t\t\t.get(\"org.springframework.boot.sslbundle.jks.%s.location\".formatted(storeType));\n\t\t\tString password = service.labels()\n\t\t\t\t.get(\"org.springframework.boot.sslbundle.jks.%s.password\".formatted(storeType));\n\t\t\tif (location == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn new JksSslStoreDetails(type, provider, location, password);\n\t\t}\n\n\t\tprivate @Nullable Path getWorkingDirectory(RunningService runningService) {\n\t\t\tDockerComposeFile composeFile = runningService.composeFile();\n\t\t\tif (composeFile == null || CollectionUtils.isEmpty(composeFile.getFiles())) {\n\t\t\t\treturn Path.of(\".\");\n\t\t\t}\n\t\t\treturn composeFile.getFiles().get(0).toPath().getParent();\n\t\t}\n\n\t\tprivate SslOptions createSslOptions(@Nullable String ciphers, @Nullable String enabledProtocols) {\n\t\t\tSet<String> ciphersSet = null;\n\t\t\tif (StringUtils.hasLength(ciphers)) {\n\t\t\t\tciphersSet = StringUtils.commaDelimitedListToSet(ciphers);\n\t\t\t}\n\t\t\tSet<String> enabledProtocolsSet = null;\n\t\t\tif (StringUtils.hasLength(enabledProtocols)) {\n\t\t\t\tenabledProtocolsSet = StringUtils.commaDelimitedListToSet(enabledProtocols);\n\t\t\t}\n\t\t\treturn SslOptions.of(ciphersSet, enabledProtocolsSet);\n\t\t}\n\n\t\tprivate @Nullable SslBundle getPemSslBundle(RunningService service) {\n\t\t\tPemSslStoreDetails keyStoreDetails = getPemSslStoreDetails(service, \"keystore\");\n\t\t\tPemSslStoreDetails trustStoreDetails = getPemSslStoreDetails(service, \"truststore\");\n\t\t\tif (keyStoreDetails == null && trustStoreDetails == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tSslBundleKey key = SslBundleKey.of(service.labels().get(\"org.springframework.boot.sslbundle.pem.key.alias\"),\n\t\t\t\t\tservice.labels().get(\"org.springframework.boot.sslbundle.pem.key.password\"));\n\t\t\tSslOptions options = createSslOptions(\n\t\t\t\t\tservice.labels().get(\"org.springframework.boot.sslbundle.pem.options.ciphers\"),\n\t\t\t\t\tservice.labels().get(\"org.springframework.boot.sslbundle.pem.options.enabled-protocols\"));\n\t\t\tString protocol = service.labels().get(\"org.springframework.boot.sslbundle.pem.protocol\");\n\t\t\tPath workingDirectory = getWorkingDirectory(service);\n\t\t\tResourceLoader resourceLoader = getResourceLoader(workingDirectory);\n\t\t\treturn SslBundle.of(new PemSslStoreBundle(PemSslStore.load(keyStoreDetails, resourceLoader),\n\t\t\t\t\tPemSslStore.load(trustStoreDetails, resourceLoader)), key, options, protocol);\n\t\t}\n\n\t\tprivate @Nullable PemSslStoreDetails getPemSslStoreDetails(RunningService service, String storeType) {\n\t\t\tString type = service.labels().get(\"org.springframework.boot.sslbundle.pem.%s.type\".formatted(storeType));\n\t\t\tString certificate = service.labels()\n\t\t\t\t.get(\"org.springframework.boot.sslbundle.pem.%s.certificate\".formatted(storeType));\n\t\t\tString privateKey = service.labels()\n\t\t\t\t.get(\"org.springframework.boot.sslbundle.pem.%s.private-key\".formatted(storeType));\n\t\t\tString privateKeyPassword = service.labels()\n\t\t\t\t.get(\"org.springframework.boot.sslbundle.pem.%s.private-key-password\".formatted(storeType));\n\t\t\tif (certificate == null && privateKey == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn new PemSslStoreDetails(type, certificate, privateKey, privateKeyPassword);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/DockerComposeConnectionSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.core.env.Environment;\n\n/**\n * Passed to {@link DockerComposeConnectionDetailsFactory} to provide details of the\n * {@link RunningService running Docker Compose service}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n * @see DockerComposeConnectionDetailsFactory\n */\npublic final class DockerComposeConnectionSource {\n\n\tprivate final RunningService runningService;\n\n\tprivate final Environment environment;\n\n\t/**\n\t * Create a new {@link DockerComposeConnectionSource} instance.\n\t * @param runningService the running Docker Compose service\n\t * @param environment environment in which the current application is running\n\t */\n\tDockerComposeConnectionSource(RunningService runningService, Environment environment) {\n\t\tthis.runningService = runningService;\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * Return the running Docker Compose service.\n\t * @return the running service\n\t */\n\tpublic RunningService getRunningService() {\n\t\treturn this.runningService;\n\t}\n\n\t/**\n\t * Environment in which the current application is running.\n\t * @return the environment\n\t * @since 3.5.0\n\t */\n\tpublic Environment getEnvironment() {\n\t\treturn this.environment;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/DockerComposeServiceConnectionsApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.container.ContainerImageMetadata;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeServicesReadyEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationListener} that listens for an {@link DockerComposeServicesReadyEvent}\n * in order to establish service connections.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposeServiceConnectionsApplicationListener\n\t\timplements ApplicationListener<DockerComposeServicesReadyEvent> {\n\n\tprivate final ConnectionDetailsFactories factories;\n\n\tDockerComposeServiceConnectionsApplicationListener() {\n\t\tthis(new ConnectionDetailsFactories(null));\n\t}\n\n\tDockerComposeServiceConnectionsApplicationListener(ConnectionDetailsFactories factories) {\n\t\tthis.factories = factories;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(DockerComposeServicesReadyEvent event) {\n\t\tApplicationContext applicationContext = event.getSource();\n\t\tif (applicationContext instanceof BeanDefinitionRegistry registry) {\n\t\t\tEnvironment environment = applicationContext.getEnvironment();\n\t\t\tregisterConnectionDetails(registry, environment, event.getRunningServices());\n\t\t}\n\t}\n\n\tprivate void registerConnectionDetails(BeanDefinitionRegistry registry, Environment environment,\n\t\t\tList<RunningService> runningServices) {\n\t\tfor (RunningService runningService : runningServices) {\n\t\t\tDockerComposeConnectionSource source = new DockerComposeConnectionSource(runningService, environment);\n\t\t\tthis.factories.getConnectionDetails(source, false).forEach((connectionDetailsType, connectionDetails) -> {\n\t\t\t\tregister(registry, runningService, connectionDetailsType, connectionDetails);\n\t\t\t\tthis.factories.getConnectionDetails(connectionDetails, false)\n\t\t\t\t\t.forEach((adaptedType, adaptedDetails) -> register(registry, runningService, adaptedType,\n\t\t\t\t\t\t\tadaptedDetails));\n\t\t\t});\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> void register(BeanDefinitionRegistry registry, RunningService runningService,\n\t\t\tClass<?> connectionDetailsType, ConnectionDetails connectionDetails) {\n\t\tContainerImageMetadata containerMetadata = new ContainerImageMetadata(runningService.image().toString());\n\t\tString beanName = getBeanName(runningService, connectionDetailsType);\n\t\tClass<T> beanType = (Class<T>) connectionDetails.getClass();\n\t\tSupplier<T> beanSupplier = () -> (T) connectionDetails;\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(beanType, beanSupplier);\n\t\tcontainerMetadata.addTo(beanDefinition);\n\t\tregistry.registerBeanDefinition(beanName, beanDefinition);\n\t}\n\n\tprivate String getBeanName(RunningService runningService, Class<?> connectionDetailsType) {\n\t\tList<String> parts = new ArrayList<>();\n\t\tparts.add(ClassUtils.getShortNameAsProperty(connectionDetailsType));\n\t\tparts.add(\"for\");\n\t\tparts.addAll(Arrays.asList(runningService.name().split(\"-\")));\n\t\treturn StringUtils.uncapitalize(parts.stream().map(StringUtils::capitalize).collect(Collectors.joining()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/java/org/springframework/boot/docker/compose/service/connection/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Service connection support for Docker Compose.\n */\n@NullMarked\npackage org.springframework.boot.docker.compose.service.connection;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.docker.compose.readiness.wait=only-if-started\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories",
    "content": "# Application Listeners\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.docker.compose.lifecycle.DockerComposeListener,\\\norg.springframework.boot.docker.compose.service.connection.DockerComposeServiceConnectionsApplicationListener\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultConnectionPortsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DefaultConnectionPorts.ContainerPort;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link DefaultConnectionPorts}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultConnectionPortsTests {\n\n\t@Test\n\tvoid createWhenBridgeNetwork() throws IOException {\n\t\tDefaultConnectionPorts ports = createForJson(\"docker-inspect-bridge-network.json\");\n\t\tassertThat(ports.getMappings()).containsExactly(entry(new ContainerPort(6379, \"tcp\"), 32770));\n\t}\n\n\t@Test\n\tvoid createWhenHostNetwork() throws Exception {\n\t\tDefaultConnectionPorts ports = createForJson(\"docker-inspect-host-network.json\");\n\t\tassertThat(ports.getMappings()).containsExactly(entry(new ContainerPort(6379, \"tcp\"), 6379));\n\t}\n\n\tprivate DefaultConnectionPorts createForJson(String path) throws IOException {\n\t\tString json = new ClassPathResource(path, getClass()).getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliInspectResponse inspectResponse = DockerJson.deserialize(json, DockerCliInspectResponse.class);\n\t\treturn new DefaultConnectionPorts(inspectResponse);\n\t}\n\n\t@Nested\n\tclass ContainerPortTests {\n\n\t\t@Test\n\t\tvoid parse() {\n\t\t\tContainerPort port = ContainerPort.parse(\"123/tcp\");\n\t\t\tassertThat(port).isEqualTo(new ContainerPort(123, \"tcp\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid parseWhenNoSlashThrowsException() {\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> ContainerPort.parse(\"123\"))\n\t\t\t\t.withMessage(\"Unable to parse container port '123'\");\n\t\t}\n\n\t\t@Test\n\t\tvoid parseWhenMultipleSlashesThrowsException() {\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> ContainerPort.parse(\"123/tcp/ip\"))\n\t\t\t\t.withMessage(\"Unable to parse container port '123/tcp/ip'\");\n\t\t}\n\n\t\t@Test\n\t\tvoid parseWhenNotNumberThrowsException() {\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> ContainerPort.parse(\"tcp/123\"))\n\t\t\t\t.withMessage(\"Unable to parse container port 'tcp/123'\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultDockerComposeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.ExposedPort;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;\nimport org.springframework.boot.logging.LogLevel;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willReturn;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultDockerCompose}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultDockerComposeTests {\n\n\tprivate static final String HOST = \"192.168.1.1\";\n\n\tprivate final DockerCli cli = mock(DockerCli.class);\n\n\t@Test\n\tvoid upRunsUpCommand() {\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tcompose.up(LogLevel.OFF, Collections.emptyList());\n\t\tthen(this.cli).should().run(new DockerCliCommand.ComposeUp(LogLevel.OFF, Collections.emptyList()));\n\t}\n\n\t@Test\n\tvoid downRunsDownCommand() {\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tDuration timeout = Duration.ofSeconds(1);\n\t\tcompose.down(timeout, Collections.emptyList());\n\t\tthen(this.cli).should().run(new DockerCliCommand.ComposeDown(timeout, Collections.emptyList()));\n\t}\n\n\t@Test\n\tvoid startRunsStartCommand() {\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tcompose.start(LogLevel.OFF, Collections.emptyList());\n\t\tthen(this.cli).should().run(new DockerCliCommand.ComposeStart(LogLevel.OFF, Collections.emptyList()));\n\t}\n\n\t@Test\n\tvoid stopRunsStopCommand() {\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tDuration timeout = Duration.ofSeconds(1);\n\t\tcompose.stop(timeout, Collections.emptyList());\n\t\tthen(this.cli).should().run(new DockerCliCommand.ComposeStop(timeout, Collections.emptyList()));\n\t}\n\n\t@Test\n\tvoid hasDefinedServicesWhenComposeConfigServicesIsEmptyReturnsFalse() {\n\t\twillReturn(new DockerCliComposeConfigResponse(\"test\", Collections.emptyMap())).given(this.cli)\n\t\t\t.run(new DockerCliCommand.ComposeConfig());\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tassertThat(compose.hasDefinedServices()).isFalse();\n\t}\n\n\t@Test\n\tvoid hasDefinedServicesWhenComposeConfigServicesIsNotEmptyReturnsTrue() {\n\t\twillReturn(new DockerCliComposeConfigResponse(\"test\",\n\t\t\t\tMap.of(\"redis\", new DockerCliComposeConfigResponse.Service(\"redis\"))))\n\t\t\t.given(this.cli)\n\t\t\t.run(new DockerCliCommand.ComposeConfig());\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tassertThat(compose.hasDefinedServices()).isTrue();\n\t}\n\n\t@Test\n\tvoid getRunningServicesReturnsServices() {\n\t\tString id = \"123\";\n\t\tDockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(id, \"name\", \"redis\", \"running\");\n\t\tMap<String, ExposedPort> exposedPorts = Collections.emptyMap();\n\t\tConfig config = new Config(\"redis\", Map.of(\"spring\", \"boot\"), exposedPorts, List.of(\"a=b\"));\n\t\tNetworkSettings networkSettings = null;\n\t\tHostConfig hostConfig = null;\n\t\tDockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings,\n\t\t\t\thostConfig);\n\t\twillReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs());\n\t\twillReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(id)));\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, HOST);\n\t\tList<RunningService> runningServices = compose.getRunningServices();\n\t\tassertThat(runningServices).hasSize(1);\n\t\tRunningService runningService = runningServices.get(0);\n\t\tassertThat(runningService.name()).isEqualTo(\"name\");\n\t\tassertThat(runningService.image()).hasToString(\"docker.io/library/redis\");\n\t\tassertThat(runningService.host()).isEqualTo(HOST);\n\t\tassertThat(runningService.ports().getAll()).isEmpty();\n\t\tassertThat(runningService.env()).containsExactly(entry(\"a\", \"b\"));\n\t\tassertThat(runningService.labels()).containsExactly(entry(\"spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid getRunningServicesWhenNoHostUsesHostFromContext() {\n\t\tString id = \"123\";\n\t\tDockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(id, \"name\", \"redis\", \"running\");\n\t\tMap<String, ExposedPort> exposedPorts = Collections.emptyMap();\n\t\tConfig config = new Config(\"redis\", Map.of(\"spring\", \"boot\"), exposedPorts, List.of(\"a=b\"));\n\t\tNetworkSettings networkSettings = null;\n\t\tHostConfig hostConfig = null;\n\t\tDockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings,\n\t\t\t\thostConfig);\n\t\twillReturn(List.of(new DockerCliContextResponse(\"test\", true, \"https://192.168.1.1\"))).given(this.cli)\n\t\t\t.run(new DockerCliCommand.Context());\n\t\twillReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs());\n\t\twillReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(id)));\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, null);\n\t\tList<RunningService> runningServices = compose.getRunningServices();\n\t\tassertThat(runningServices).hasSize(1);\n\t\tRunningService runningService = runningServices.get(0);\n\t\tassertThat(runningService.host()).isEqualTo(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid worksWithTruncatedIds() {\n\t\tString shortId = \"123\";\n\t\tString longId = \"123456\";\n\t\tDockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(shortId, \"name\", \"redis\", \"running\");\n\t\tConfig config = new Config(\"redis\", Collections.emptyMap(), Collections.emptyMap(), Collections.emptyList());\n\t\tDockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(longId, config, null, null);\n\t\twillReturn(List.of(new DockerCliContextResponse(\"test\", true, \"https://192.168.1.1\"))).given(this.cli)\n\t\t\t.run(new DockerCliCommand.Context());\n\t\twillReturn(List.of(psResponse)).given(this.cli).run(new DockerCliCommand.ComposePs());\n\t\twillReturn(List.of(inspectResponse)).given(this.cli).run(new DockerCliCommand.Inspect(List.of(shortId)));\n\t\tDefaultDockerCompose compose = new DefaultDockerCompose(this.cli, null);\n\t\tList<RunningService> runningServices = compose.getRunningServices();\n\t\tassertThat(runningServices).hasSize(1);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DefaultRunningServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.ExposedPort;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostPort;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link DefaultRunningService}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultRunningServiceTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\tprivate DefaultRunningService runningService;\n\n\tprivate DockerComposeFile composeFile;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.composeFile = createComposeFile();\n\t\tthis.runningService = createRunningService(true);\n\t}\n\n\tprivate DockerComposeFile createComposeFile() throws IOException {\n\t\tFile file = new File(this.temp, \"compose.yaml\");\n\t\tFileCopyUtils.copy(new byte[0], file);\n\t\treturn DockerComposeFile.of(file);\n\t}\n\n\t@Test\n\tvoid getOriginReturnsOrigin() {\n\t\tassertThat(Origin.from(this.runningService)).isEqualTo(new DockerComposeOrigin(this.composeFile, \"my-service\"));\n\t}\n\n\t@Test\n\tvoid nameReturnsNameFromPsResponse() {\n\t\tassertThat(this.runningService.name()).isEqualTo(\"my-service\");\n\t}\n\n\t@Test\n\tvoid imageReturnsImageFromPsResponse() {\n\t\tassertThat(this.runningService.image()).hasToString(\"docker.io/library/redis\");\n\t}\n\n\t@Test // gh-34992\n\tvoid imageWhenUsingEarlierDockerVersionReturnsImageFromInspectResult() {\n\t\tDefaultRunningService runningService = createRunningService(false);\n\t\tassertThat(runningService.image()).hasToString(\"docker.io/library/redis\");\n\n\t}\n\n\t@Test\n\tvoid hostReturnsHost() {\n\t\tassertThat(this.runningService.host()).isEqualTo(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid portsReturnsPortsFromInspectResponse() {\n\t\tConnectionPorts ports = this.runningService.ports();\n\t\tassertThat(ports.getAll(\"tcp\")).containsExactly(9090);\n\t\tassertThat(ports.get(8080)).isEqualTo(9090);\n\t}\n\n\t@Test\n\tvoid envReturnsEnvFromInspectResponse() {\n\t\tassertThat(this.runningService.env()).containsExactly(entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid labelReturnsLabelsFromInspectResponse() {\n\t\tassertThat(this.runningService.labels()).containsExactly(entry(\"spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid toStringReturnsServiceName() {\n\t\tassertThat(this.runningService).hasToString(\"my-service\");\n\t}\n\n\tprivate DefaultRunningService createRunningService(boolean psResponseHasImage) {\n\t\tDockerHost host = DockerHost.get(\"192.168.1.1\", Collections::emptyList);\n\t\tString id = \"123\";\n\t\tString name = \"my-service\";\n\t\tString image = \"redis\";\n\t\tString state = \"running\";\n\t\tDockerCliComposePsResponse psResponse = new DockerCliComposePsResponse(id, name,\n\t\t\t\t(!psResponseHasImage) ? null : image, state);\n\t\tMap<String, String> labels = Map.of(\"spring\", \"boot\");\n\t\tMap<String, ExposedPort> exposedPorts = Map.of(\"8080/tcp\", new ExposedPort());\n\t\tList<String> env = List.of(\"a=b\");\n\t\tConfig config = new Config(image, labels, exposedPorts, env);\n\t\tMap<String, List<HostPort>> ports = Map.of(\"8080/tcp\", List.of(new HostPort(\"127.0.0.1\", \"9090\")));\n\t\tNetworkSettings networkSettings = new NetworkSettings(ports);\n\t\tHostConfig hostConfig = new HostConfig(\"bridge\");\n\t\tDockerCliInspectResponse inspectResponse = new DockerCliInspectResponse(id, config, networkSettings,\n\t\t\t\thostConfig);\n\t\treturn new DefaultRunningService(host, this.composeFile, psResponse, inspectResponse);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.ComposeVersion;\nimport org.springframework.boot.docker.compose.core.DockerCliCommand.None;\nimport org.springframework.boot.logging.LogLevel;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCliCommand}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCliCommandTests {\n\n\tprivate static final ComposeVersion COMPOSE_VERSION = ComposeVersion.of(\"2.31.0\");\n\n\t@Test\n\tvoid context() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.Context();\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"context\", \"ls\", \"--format={{ json . }}\");\n\t\tassertThat(command.convert(\"[]\")).isInstanceOf(List.class);\n\t}\n\n\t@Test\n\tvoid inspect() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.Inspect(List.of(\"123\", \"345\"));\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"inspect\", \"--format={{ json . }}\", \"123\",\n\t\t\t\t\"345\");\n\t\tassertThat(command.convert(\"[]\")).isInstanceOf(List.class);\n\t}\n\n\t@Test\n\tvoid composeConfig() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposeConfig();\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"config\", \"--format=json\");\n\t\tassertThat(command.convert(\"{}\")).isInstanceOf(DockerCliComposeConfigResponse.class);\n\t}\n\n\t@Test\n\tvoid composePs() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposePs();\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"ps\", \"--orphans=false\", \"--format=json\");\n\t\tassertThat(command.convert(\"[]\")).isInstanceOf(List.class);\n\t}\n\n\t@Test\n\tvoid composePsWhenLessThanV224() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposePs();\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getCommand(ComposeVersion.of(\"2.23\"))).containsExactly(\"ps\", \"--format=json\");\n\t\tassertThat(command.convert(\"[]\")).isInstanceOf(List.class);\n\t}\n\n\t@Test\n\tvoid composeUp() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposeUp(LogLevel.INFO, List.of(\"--renew-anon-volumes\"));\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getLogLevel()).isEqualTo(LogLevel.INFO);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"up\", \"--no-color\", \"--detach\", \"--wait\",\n\t\t\t\t\"--renew-anon-volumes\");\n\t\tassertThat(command.convert(\"[]\")).isSameAs(None.INSTANCE);\n\t}\n\n\t@Test\n\tvoid composeDown() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposeDown(Duration.ofSeconds(1),\n\t\t\t\tList.of(\"--remove-orphans\"));\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"down\", \"--timeout\", \"1\", \"--remove-orphans\");\n\t\tassertThat(command.convert(\"[]\")).isSameAs(None.INSTANCE);\n\t}\n\n\t@Test\n\tvoid composeStart() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposeStart(LogLevel.INFO, List.of(\"--dry-run\"));\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getLogLevel()).isEqualTo(LogLevel.INFO);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"start\", \"--dry-run\");\n\t\tassertThat(command.convert(\"[]\")).isSameAs(None.INSTANCE);\n\t}\n\n\t@Test\n\tvoid composeStop() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposeStop(Duration.ofSeconds(1), List.of(\"--dry-run\"));\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"stop\", \"--timeout\", \"1\", \"--dry-run\");\n\t\tassertThat(command.convert(\"[]\")).isSameAs(None.INSTANCE);\n\t}\n\n\t@Test\n\tvoid composeVersionTests() {\n\t\tComposeVersion version = ComposeVersion.of(\"2.31.0-desktop\");\n\t\tassertThat(version.major()).isEqualTo(2);\n\t\tassertThat(version.minor()).isEqualTo(31);\n\t\tassertThat(version.isLessThan(1, 0)).isFalse();\n\t\tassertThat(version.isLessThan(2, 0)).isFalse();\n\t\tassertThat(version.isLessThan(2, 31)).isFalse();\n\t\tassertThat(version.isLessThan(2, 32)).isTrue();\n\t\tassertThat(version.isLessThan(3, 0)).isTrue();\n\t\tComposeVersion versionWithPrefix = ComposeVersion.of(\"v2.31.0-desktop\");\n\t\tassertThat(versionWithPrefix.major()).isEqualTo(2);\n\t\tassertThat(versionWithPrefix.minor()).isEqualTo(31);\n\t}\n\n\t@Test\n\tvoid composeLogs() {\n\t\tDockerCliCommand<?> command = new DockerCliCommand.ComposeLogs();\n\t\tassertThat(command.getType()).isEqualTo(DockerCliCommand.Type.DOCKER_COMPOSE);\n\t\tassertThat(command.getCommand(COMPOSE_VERSION)).containsExactly(\"logs\");\n\t\tassertThat(command.convert(\"\"\"\n\t\t\t\tmulti\n\t\t\t\tline\n\t\t\t\tlogs\"\"\")).isEqualTo(\"\"\"\n\t\t\t\tmulti\n\t\t\t\tline\n\t\t\t\tlogs\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliComposeConfigResponseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DockerCliComposeConfigResponse.Service;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCliComposeConfigResponse}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCliComposeConfigResponseTests {\n\n\t@Test\n\tvoid deserializeJson() throws IOException {\n\t\tString json = new ClassPathResource(\"docker-compose-config.json\", getClass())\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliComposeConfigResponse response = DockerJson.deserialize(json, DockerCliComposeConfigResponse.class);\n\t\tDockerCliComposeConfigResponse expected = new DockerCliComposeConfigResponse(\"redis-docker\",\n\t\t\t\tMap.of(\"redis\", new Service(\"redis:7.0\")));\n\t\tassertThat(response).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliComposePsResponseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCliComposePsResponse}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCliComposePsResponseTests {\n\n\t@Test\n\tvoid deserializeJson() throws IOException {\n\t\tString json = new ClassPathResource(\"docker-compose-ps.json\", getClass())\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliComposePsResponse response = DockerJson.deserialize(json, DockerCliComposePsResponse.class);\n\t\tDockerCliComposePsResponse expected = new DockerCliComposePsResponse(\"f5af31dae7f6\", \"redis-docker-redis-1\",\n\t\t\t\t\"redis:7.0\", \"running\");\n\t\tassertThat(response).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliComposeVersionResponseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCliComposeVersionResponse}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCliComposeVersionResponseTests {\n\n\t@Test\n\tvoid deserializeJson() throws IOException {\n\t\tString json = new ClassPathResource(\"docker-compose-version.json\", getClass())\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliComposeVersionResponse response = DockerJson.deserialize(json, DockerCliComposeVersionResponse.class);\n\t\tDockerCliComposeVersionResponse expected = new DockerCliComposeVersionResponse(\"123\");\n\t\tassertThat(response).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliContextResponseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCliContextResponse}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCliContextResponseTests {\n\n\t@Test\n\tvoid deserializeJson() throws IOException {\n\t\tString json = new ClassPathResource(\"docker-context.json\", getClass())\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliContextResponse response = DockerJson.deserialize(json, DockerCliContextResponse.class);\n\t\tDockerCliContextResponse expected = new DockerCliContextResponse(\"default\", true,\n\t\t\t\t\"unix:///var/run/docker.sock\");\n\t\tassertThat(response).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid deserializePodmanJson() throws IOException {\n\t\tString json = new ClassPathResource(\"docker-context-podman.json\", getClass())\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliContextResponse response = DockerJson.deserialize(json, DockerCliContextResponse.class);\n\t\tDockerCliContextResponse expected = new DockerCliContextResponse(\"podman-machine-default\", false, null);\n\t\tassertThat(response).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerCliInspectResponseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.Config;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.ExposedPort;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostConfig;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.HostPort;\nimport org.springframework.boot.docker.compose.core.DockerCliInspectResponse.NetworkSettings;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerCliInspectResponse}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerCliInspectResponseTests {\n\n\t@Test\n\tvoid deserializeJson() throws IOException {\n\t\tString json = new ClassPathResource(\"docker-inspect.json\", getClass())\n\t\t\t.getContentAsString(StandardCharsets.UTF_8);\n\t\tDockerCliInspectResponse response = DockerJson.deserialize(json, DockerCliInspectResponse.class);\n\t\tLinkedHashMap<String, String> expectedLabels = linkedMapOf(\"com.docker.compose.config-hash\",\n\t\t\t\t\"cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0\",\n\t\t\t\t\"com.docker.compose.container-number\", \"1\", \"com.docker.compose.depends_on\", \"\",\n\t\t\t\t\"com.docker.compose.image\", \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\t\t\t\"com.docker.compose.oneoff\", \"False\", \"com.docker.compose.project\", \"redis-docker\",\n\t\t\t\t\"com.docker.compose.project.config_files\", \"compose.yaml\", \"com.docker.compose.project.working_dir\",\n\t\t\t\t\"/\", \"com.docker.compose.service\", \"redis\", \"com.docker.compose.version\", \"2.16.0\");\n\t\tList<String> expectedEnv = List.of(\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\t\"GOSU_VERSION=1.16\", \"REDIS_VERSION=7.0.8\");\n\t\tConfig expectedConfig = new Config(\"redis:7.0\", expectedLabels, Map.of(\"6379/tcp\", new ExposedPort()),\n\t\t\t\texpectedEnv);\n\t\tNetworkSettings expectedNetworkSettings = new NetworkSettings(\n\t\t\t\tMap.of(\"6379/tcp\", List.of(new HostPort(\"0.0.0.0\", \"32770\"), new HostPort(\"::\", \"32770\"))));\n\t\tDockerCliInspectResponse expected = new DockerCliInspectResponse(\n\t\t\t\t\"f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc\", expectedConfig,\n\t\t\t\texpectedNetworkSettings, new HostConfig(\"redis-docker_default\"));\n\t\tassertThat(response).isEqualTo(expected);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <K, V> LinkedHashMap<K, V> linkedMapOf(Object... values) {\n\t\tLinkedHashMap<K, V> result = new LinkedHashMap<>();\n\t\tfor (int i = 0; i < values.length; i = i + 2) {\n\t\t\tresult.put((K) values[i], (V) values[i + 1]);\n\t\t}\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerComposeFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link DockerComposeFile}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposeFileTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid hashCodeAndEquals() throws Exception {\n\t\tFile f1 = new File(this.temp, \"compose.yml\");\n\t\tFile f2 = new File(this.temp, \"docker-compose.yml\");\n\t\tFileCopyUtils.copy(new byte[0], f1);\n\t\tFileCopyUtils.copy(new byte[0], f2);\n\t\tDockerComposeFile c1 = DockerComposeFile.of(f1);\n\t\tDockerComposeFile c2 = DockerComposeFile.of(f1);\n\t\tDockerComposeFile c3 = DockerComposeFile.find(f1.getParentFile());\n\t\tDockerComposeFile c4 = DockerComposeFile.of(f2);\n\t\tassertThat(c1).hasSameHashCodeAs(c2).hasSameHashCodeAs(c3);\n\t\tassertThat(c1).isEqualTo(c1).isEqualTo(c2).isEqualTo(c3).isNotEqualTo(c4);\n\t}\n\n\t@Test\n\tvoid toStringReturnsFileName() throws Exception {\n\t\tDockerComposeFile composeFile = createComposeFile(\"compose.yml\");\n\t\tassertThat(composeFile.toString()).endsWith(File.separator + \"compose.yml\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsFileNameList() throws Exception {\n\t\tFile file1 = createTempFile(\"1.yml\");\n\t\tFile file2 = createTempFile(\"2.yml\");\n\t\tDockerComposeFile composeFile = DockerComposeFile.of(List.of(file1, file2));\n\t\tassertThat(composeFile).hasToString(file1 + \", \" + file2);\n\t}\n\n\t@Test\n\tvoid findFindsSingleFile() throws Exception {\n\t\tFile file = new File(this.temp, \"docker-compose.yml\").getCanonicalFile();\n\t\tFileCopyUtils.copy(new byte[0], file);\n\t\tDockerComposeFile composeFile = DockerComposeFile.find(file.getParentFile());\n\t\tassertThat(composeFile).isNotNull();\n\t\tassertThat(composeFile.getFiles()).containsExactly(file);\n\t}\n\n\t@Test\n\tvoid findWhenMultipleFilesPicksBest() throws Exception {\n\t\tFile f1 = new File(this.temp, \"docker-compose.yml\").getCanonicalFile();\n\t\tFileCopyUtils.copy(new byte[0], f1);\n\t\tFile f2 = new File(this.temp, \"compose.yml\").getCanonicalFile();\n\t\tFileCopyUtils.copy(new byte[0], f2);\n\t\tDockerComposeFile composeFile = DockerComposeFile.find(f1.getParentFile());\n\t\tassertThat(composeFile).isNotNull();\n\t\tassertThat(composeFile.getFiles()).containsExactly(f2);\n\t}\n\n\t@Test\n\tvoid findWhenNoComposeFilesReturnsNull() throws Exception {\n\t\tFile file = new File(this.temp, \"not-a-compose.yml\");\n\t\tFileCopyUtils.copy(new byte[0], file);\n\t\tDockerComposeFile composeFile = DockerComposeFile.find(file.getParentFile());\n\t\tassertThat(composeFile).isNull();\n\t}\n\n\t@Test\n\tvoid findWhenWorkingDirectoryDoesNotExistReturnsNull() {\n\t\tFile directory = new File(this.temp, \"missing\");\n\t\tDockerComposeFile composeFile = DockerComposeFile.find(directory);\n\t\tassertThat(composeFile).isNull();\n\t}\n\n\t@Test\n\tvoid findWhenWorkingDirectoryIsNotDirectoryThrowsException() throws Exception {\n\t\tFile file = createTempFile(\"iamafile\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> DockerComposeFile.find(file))\n\t\t\t.withMessageEndingWith(\"is not a directory\");\n\t}\n\n\t@Test\n\tvoid ofReturnsDockerComposeFile() throws Exception {\n\t\tFile file = createTempFile(\"compose.yml\");\n\t\tDockerComposeFile composeFile = DockerComposeFile.of(file);\n\t\tassertThat(composeFile).isNotNull();\n\t\tassertThat(composeFile.getFiles()).containsExactly(file);\n\t}\n\n\t@Test\n\tvoid ofWithMultipleFilesReturnsDockerComposeFile() throws Exception {\n\t\tFile file1 = createTempFile(\"1.yml\");\n\t\tFile file2 = createTempFile(\"2.yml\");\n\t\tDockerComposeFile composeFile = DockerComposeFile.of(List.of(file1, file2));\n\t\tassertThat(composeFile).isNotNull();\n\t\tassertThat(composeFile.getFiles()).containsExactly(file1, file2);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenFileIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.of((File) null))\n\t\t\t.withMessage(\"'file' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofWhenFileDoesNotExistThrowsException() {\n\t\tFile file = new File(this.temp, \"missing\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.of(file))\n\t\t\t.withMessageEndingWith(\"must exist\");\n\t}\n\n\t@Test\n\tvoid ofWhenFileIsNotFileThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DockerComposeFile.of(this.temp))\n\t\t\t.withMessageEndingWith(\"must be a normal file\");\n\t}\n\n\tprivate DockerComposeFile createComposeFile(String name) throws IOException {\n\t\treturn DockerComposeFile.of(createTempFile(name));\n\t}\n\n\tprivate File createTempFile(String name) throws IOException {\n\t\tFile file = new File(this.temp, name);\n\t\tFileCopyUtils.copy(new byte[0], file);\n\t\treturn file.getCanonicalFile();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerComposeOriginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerComposeOrigin}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposeOriginTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid hasToString() throws Exception {\n\t\tDockerComposeFile composeFile = createTempComposeFile();\n\t\tDockerComposeOrigin origin = new DockerComposeOrigin(composeFile, \"service-1\");\n\t\tassertThat(origin.toString()).startsWith(\"Docker compose service 'service-1' defined in \")\n\t\t\t.endsWith(\"compose.yaml\");\n\t}\n\n\t@Test\n\tvoid hasToStringWithMultipleFiles() throws IOException {\n\t\tFile file1 = createTempFile(\"1.yaml\");\n\t\tFile file2 = createTempFile(\"2.yaml\");\n\t\tDockerComposeOrigin origin = new DockerComposeOrigin(DockerComposeFile.of(List.of(file1, file2)), \"service-1\");\n\t\tassertThat(origin.toString())\n\t\t\t.startsWith(\"Docker compose service 'service-1' defined in %s, %s\".formatted(file1, file2));\n\t}\n\n\t@Test\n\tvoid equalsAndHashcode() throws Exception {\n\t\tDockerComposeFile composeFile = createTempComposeFile();\n\t\tDockerComposeOrigin origin1 = new DockerComposeOrigin(composeFile, \"service-1\");\n\t\tDockerComposeOrigin origin2 = new DockerComposeOrigin(composeFile, \"service-1\");\n\t\tDockerComposeOrigin origin3 = new DockerComposeOrigin(composeFile, \"service-3\");\n\t\tassertThat(origin1).isEqualTo(origin1);\n\t\tassertThat(origin1).isEqualTo(origin2);\n\t\tassertThat(origin1).hasSameHashCodeAs(origin2);\n\t\tassertThat(origin2).isEqualTo(origin1);\n\t\tassertThat(origin1).isNotEqualTo(origin3);\n\t\tassertThat(origin2).isNotEqualTo(origin3);\n\t\tassertThat(origin3).isNotEqualTo(origin1);\n\t\tassertThat(origin3).isNotEqualTo(origin2);\n\t}\n\n\tprivate DockerComposeFile createTempComposeFile() throws IOException {\n\t\treturn DockerComposeFile.of(createTempFile(\"compose.yaml\"));\n\t}\n\n\tprivate File createTempFile(String filename) throws IOException {\n\t\tFile file = new File(this.temp, filename);\n\t\tFileCopyUtils.copy(new byte[0], file);\n\t\treturn file.getCanonicalFile();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerEnvTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link DockerEnv}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerEnvTests {\n\n\t@Test\n\tvoid createWhenEnvIsNullReturnsEmpty() {\n\t\tDockerEnv env = new DockerEnv(null);\n\t\tassertThat(env.asMap()).isEmpty();\n\t}\n\n\t@Test\n\tvoid createWhenEnvIsEmptyReturnsEmpty() {\n\t\tDockerEnv env = new DockerEnv(Collections.emptyList());\n\t\tassertThat(env.asMap()).isEmpty();\n\t}\n\n\t@Test\n\tvoid createParsesEnv() {\n\t\tDockerEnv env = new DockerEnv(List.of(\"a=b\", \"c\"));\n\t\tassertThat(env.asMap()).containsExactly(entry(\"a\", \"b\"), entry(\"c\", null));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerHostTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerHost}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerHostTests {\n\n\tprivate static final String MAC_HOST = \"unix:///var/run/docker.sock\";\n\n\tprivate static final String LINUX_HOST = \"unix:///var/run/docker.sock\";\n\n\tprivate static final String WINDOWS_HOST = \"npipe:////./pipe/docker_engine\";\n\n\tprivate static final String WSL_HOST = \"unix:///var/run/docker.sock\";\n\n\tprivate static final String HTTP_HOST = \"http://192.168.1.1\";\n\n\tprivate static final String HTTPS_HOST = \"https://192.168.1.1\";\n\n\tprivate static final String TCP_HOST = \"tcp://192.168.1.1\";\n\n\tprivate static final Function<String, @Nullable String> NO_SYSTEM_ENV = (key) -> null;\n\n\tprivate static final Supplier<List<DockerCliContextResponse>> NO_CONTEXT = Collections::emptyList;\n\n\t@Test\n\tvoid getWhenHasHost() {\n\t\tDockerHost host = DockerHost.get(\"192.168.1.1\", NO_SYSTEM_ENV, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasServiceHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"SERVICES_HOST\", \"192.168.1.2\");\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"192.168.1.2\");\n\t}\n\n\t@Test\n\tvoid getWhenHasMacDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", MAC_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasLinuxDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", LINUX_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasWindowsDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", WINDOWS_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasWslDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", WSL_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasHttpDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", HTTP_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasHttpsDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", HTTPS_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasTcpDockerHostEnv() {\n\t\tMap<String, String> systemEnv = Map.of(\"DOCKER_HOST\", TCP_HOST);\n\t\tDockerHost host = DockerHost.get(null, systemEnv::get, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasMacContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, MAC_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasLinuxContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, LINUX_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasWindowsContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, WINDOWS_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasWslContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, WSL_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasHttpContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, HTTP_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasHttpsContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, HTTPS_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenHasTcpContext() {\n\t\tList<DockerCliContextResponse> context = List.of(new DockerCliContextResponse(\"test\", true, TCP_HOST));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"192.168.1.1\");\n\t}\n\n\t@Test\n\tvoid getWhenContextHasMultiple() {\n\t\tList<DockerCliContextResponse> context = new ArrayList<>();\n\t\tcontext.add(new DockerCliContextResponse(\"test\", false, \"http://192.168.1.1\"));\n\t\tcontext.add(new DockerCliContextResponse(\"test\", true, \"http://192.168.1.2\"));\n\t\tcontext.add(new DockerCliContextResponse(\"test\", false, \"http://192.168.1.3\"));\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, () -> context);\n\t\tassertThat(host).hasToString(\"192.168.1.2\");\n\t}\n\n\t@Test\n\tvoid getWhenHasNone() {\n\t\tDockerHost host = DockerHost.get(null, NO_SYSTEM_ENV, NO_CONTEXT);\n\t\tassertThat(host).hasToString(\"127.0.0.1\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/DockerJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport java.util.List;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerJson}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerJsonTests {\n\n\t@Test\n\tvoid deserializeWhenSentenceCase() {\n\t\tString json = \"\"\"\n\t\t\t\t{ \"Value\": 1 }\n\t\t\t\t\"\"\";\n\t\tTestResponse response = DockerJson.deserialize(json, TestResponse.class);\n\t\tassertThat(response).isEqualTo(new TestResponse(1));\n\t}\n\n\t@Test\n\tvoid deserializeWhenLowerCase() {\n\t\tString json = \"\"\"\n\t\t\t\t{ \"value\": 1 }\n\t\t\t\t\"\"\";\n\t\tTestResponse response = DockerJson.deserialize(json, TestResponse.class);\n\t\tassertThat(response).isEqualTo(new TestResponse(1));\n\t}\n\n\t@Test\n\tvoid deserializeToListWhenArray() {\n\t\tString json = \"\"\"\n\t\t\t\t[{ \"value\": 1 }, { \"value\": 2 }]\n\t\t\t\t\"\"\";\n\t\tList<TestResponse> response = DockerJson.deserializeToList(json, TestResponse.class);\n\t\tassertThat(response).containsExactly(new TestResponse(1), new TestResponse(2));\n\t}\n\n\t@Test\n\tvoid deserializeToListWhenMultipleLines() {\n\t\tString json = \"\"\"\n\t\t\t\t{ \"Value\": 1 }\n\t\t\t\t{ \"Value\": 2 }\n\t\t\t\t\"\"\";\n\t\tList<TestResponse> response = DockerJson.deserializeToList(json, TestResponse.class);\n\t\tassertThat(response).containsExactly(new TestResponse(1), new TestResponse(2));\n\t}\n\n\t@Test\n\tvoid shouldBeLocaleAgnostic() {\n\t\t// Turkish locale lower cases the 'I' to a 'ı', not to an 'i'\n\t\twithLocale(Locale.forLanguageTag(\"tr-TR\"), () -> {\n\t\t\tString json = \"\"\"\n\t\t\t\t\t{ \"INTEGER\": 42 }\n\t\t\t\t\t\"\"\";\n\t\t\tTestLowercaseResponse response = DockerJson.deserialize(json, TestLowercaseResponse.class);\n\t\t\tassertThat(response.integer()).isEqualTo(42);\n\t\t});\n\t}\n\n\tprivate void withLocale(Locale locale, Runnable runnable) {\n\t\tLocale defaultLocale = Locale.getDefault();\n\t\ttry {\n\t\t\tLocale.setDefault(locale);\n\t\t\trunnable.run();\n\t\t}\n\t\tfinally {\n\t\t\tLocale.setDefault(defaultLocale);\n\t\t}\n\t}\n\n\trecord TestResponse(int value) {\n\t}\n\n\trecord TestLowercaseResponse(int integer) {\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/ImageNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ImageName}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ImageNameTests {\n\n\t@Test\n\tvoid ofWhenNameOnlyCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/library/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenSlashedNameCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLocalhostNameCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"localhost/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"localhost/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"localhost\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenDomainAndNameCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo.spring.io/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo.spring.io/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo.spring.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenDomainNameAndPortCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo.spring.io:8080/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo.spring.io:8080/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo.spring.io:8080\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenSimpleNameAndPortCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo:8080/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo:8080/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo:8080\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenSimplePathAndPortCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"repo:8080/canonical/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"repo:8080/canonical/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"repo:8080\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"canonical/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameWithLongPathCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"path1/path2/path3/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/path1/path2/path3/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"path1/path2/path3/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLocalhostDomainCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"localhost/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"localhost\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLocalhostDomainAndPathCreatesImageName() {\n\t\tImageName imageName = ImageName.of(\"localhost/library/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"localhost\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofWhenLegacyDomainUsesNewDomain() {\n\t\tImageName imageName = ImageName.of(\"index.docker.io/ubuntu\");\n\t\tassertThat(imageName).hasToString(\"docker.io/library/ubuntu\");\n\t\tassertThat(imageName.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(imageName.getName()).isEqualTo(\"library/ubuntu\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(\"\"))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsUppercaseThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(\"Test\"))\n\t\t\t.withMessageContaining(\"must contain an image reference\")\n\t\t\t.withMessageContaining(\"Test\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameIncludesTagThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageName.of(\"ubuntu:latest\"))\n\t\t\t.withMessageContaining(\"must contain an image reference\")\n\t\t\t.withMessageContaining(\":latest\");\n\t}\n\n\t@Test\n\tvoid ofWhenNameIncludeDigestThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(\n\t\t\t\t() -> ImageName.of(\"ubuntu@sha256:47bfdb88c3ae13e488167607973b7688f69d9e8c142c2045af343ec199649c09\"))\n\t\t\t.withMessageContaining(\"must contain an image reference\")\n\t\t\t.withMessageContaining(\"@sha256:47b\");\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tImageName n1 = ImageName.of(\"ubuntu\");\n\t\tImageName n2 = ImageName.of(\"library/ubuntu\");\n\t\tImageName n3 = ImageName.of(\"docker.io/ubuntu\");\n\t\tImageName n4 = ImageName.of(\"docker.io/library/ubuntu\");\n\t\tImageName n5 = ImageName.of(\"index.docker.io/library/ubuntu\");\n\t\tImageName n6 = ImageName.of(\"alpine\");\n\t\tassertThat(n1).hasSameHashCodeAs(n2).hasSameHashCodeAs(n3).hasSameHashCodeAs(n4).hasSameHashCodeAs(n5);\n\t\tassertThat(n1).isEqualTo(n1).isEqualTo(n2).isEqualTo(n3).isEqualTo(n4).isNotEqualTo(n6);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/ImageReferenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\nimport org.junit.jupiter.api.Timeout.ThreadMode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ImageReference}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ImageReferenceTests {\n\n\t@Test\n\tvoid ofSimpleName() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofSimpleNameWithSingleCharacterSuffix() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu-a\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu-a\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu-a\");\n\t}\n\n\t@Test\n\tvoid ofLibrarySlashName() {\n\t\tImageReference reference = ImageReference.of(\"library/ubuntu\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofSlashName() {\n\t\tImageReference reference = ImageReference.of(\"adoptopenjdk/openjdk11\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"adoptopenjdk/openjdk11\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/adoptopenjdk/openjdk11\");\n\t}\n\n\t@Test\n\tvoid ofCustomDomain() {\n\t\tImageReference reference = ImageReference.of(\"repo.example.com/java/jdk\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"repo.example.com\");\n\t\tassertThat(reference.getName()).isEqualTo(\"java/jdk\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"repo.example.com/java/jdk\");\n\t}\n\n\t@Test\n\tvoid ofCustomDomainAndPort() {\n\t\tImageReference reference = ImageReference.of(\"repo.example.com:8080/java/jdk\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"repo.example.com:8080\");\n\t\tassertThat(reference.getName()).isEqualTo(\"java/jdk\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"repo.example.com:8080/java/jdk\");\n\t}\n\n\t@Test\n\tvoid ofLegacyDomain() {\n\t\tImageReference reference = ImageReference.of(\"index.docker.io/ubuntu\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu\");\n\t}\n\n\t@Test\n\tvoid ofNameAndTag() {\n\t\tImageReference reference = ImageReference.of(\"ubuntu:bionic\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"bionic\");\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"docker.io/library/ubuntu:bionic\");\n\t}\n\n\t@Test\n\tvoid ofDomainPortAndTag() {\n\t\tImageReference reference = ImageReference.of(\"repo.example.com:8080/library/ubuntu:v1\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"repo.example.com:8080\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"v1\");\n\t\tassertThat(reference.getDigest()).isNull();\n\t\tassertThat(reference).hasToString(\"repo.example.com:8080/library/ubuntu:v1\");\n\t}\n\n\t@Test\n\tvoid ofNameAndDigest() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isNull();\n\t\tassertThat(reference.getDigest())\n\t\t\t.isEqualTo(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofNameAndTagAndDigest() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"docker.io\");\n\t\tassertThat(reference.getName()).isEqualTo(\"library/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"bionic\");\n\t\tassertThat(reference.getDigest())\n\t\t\t.isEqualTo(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"docker.io/library/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofCustomDomainAndPortWithTag() {\n\t\tImageReference reference = ImageReference\n\t\t\t.of(\"example.com:8080/canonical/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference.getDomain()).isEqualTo(\"example.com:8080\");\n\t\tassertThat(reference.getName()).isEqualTo(\"canonical/ubuntu\");\n\t\tassertThat(reference.getTag()).isEqualTo(\"bionic\");\n\t\tassertThat(reference.getDigest())\n\t\t\t.isEqualTo(\"sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t\tassertThat(reference).hasToString(\n\t\t\t\t\"example.com:8080/canonical/ubuntu:bionic@sha256:6e9f67fa63b0323e9a1e587fd71c561ba48a034504fb804fd26fd8800039835d\");\n\t}\n\n\t@Test\n\tvoid ofWhenHasIllegalCharacterThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ImageReference\n\t\t\t\t.of(\"registry.example.com/example/example-app:1.6.0-dev.2.uncommitted+wip.foo.c75795d\"))\n\t\t\t.withMessageContaining(\"must contain an image reference\");\n\t}\n\n\t@Test\n\t@Timeout(value = 1, threadMode = ThreadMode.SEPARATE_THREAD)\n\tvoid ofWhenImageNameIsVeryLongAndHasIllegalCharacterThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ImageReference\n\t\t\t.of(\"docker.io/library/this-image-has-a-long-name-with-an-invalid-tag-which-is-at-danger-of-catastrophic-backtracking:1.0.0+1234\"))\n\t\t\t.withMessageContaining(\"must contain an image reference\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tImageReference r1 = ImageReference.of(\"ubuntu:bionic\");\n\t\tImageReference r2 = ImageReference.of(\"docker.io/library/ubuntu:bionic\");\n\t\tImageReference r3 = ImageReference.of(\"docker.io/library/ubuntu:latest\");\n\t\tassertThat(r1).hasSameHashCodeAs(r2);\n\t\tassertThat(r1).isEqualTo(r1).isEqualTo(r2).isNotEqualTo(r3);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/core/ProcessRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.core;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ProcessRunner}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DisabledIfProcessUnavailable(\"docker\")\nclass ProcessRunnerTests {\n\n\tprivate ProcessRunner processRunner = new ProcessRunner();\n\n\t@Test\n\tvoid run() {\n\t\tString out = this.processRunner.run(\"docker\", \"--version\");\n\t\tassertThat(out).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid runWhenHasOutputConsumer() {\n\t\tStringBuilder output = new StringBuilder();\n\t\tthis.processRunner.run(output::append, \"docker\", \"--version\");\n\t\tassertThat(output.toString()).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid runWhenProcessDoesNotStart() {\n\t\tassertThatExceptionOfType(ProcessStartException.class)\n\t\t\t.isThrownBy(() -> this.processRunner.run(\"iverymuchdontexist\", \"--version\"));\n\t}\n\n\t@Test\n\tvoid runWhenProcessReturnsNonZeroExitCode() {\n\t\tassertThatExceptionOfType(ProcessExitException.class)\n\t\t\t.isThrownBy(() -> this.processRunner.run(\"docker\", \"-thisdoesntwork\"))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getExitCode()).isGreaterThan(0);\n\t\t\t\tassertThat(ex.getStdOut()).isEmpty();\n\t\t\t\tassertThat(ex.getStdErr()).isNotEmpty();\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeLifecycleManagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Paths;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.SpringApplicationShutdownHandlers;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.docker.compose.core.DockerCompose;\nimport org.springframework.boot.docker.compose.core.DockerComposeFile;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start.Skip;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link DockerComposeLifecycleManager}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass DockerComposeLifecycleManagerTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\tprivate DockerComposeFile dockerComposeFile;\n\n\tprivate DockerCompose dockerCompose;\n\n\tprivate @Nullable Set<String> activeProfiles;\n\n\tprivate @Nullable List<String> arguments;\n\n\tprivate GenericApplicationContext applicationContext;\n\n\tprivate TestSpringApplicationShutdownHandlers shutdownHandlers;\n\n\tprivate ServiceReadinessChecks serviceReadinessChecks;\n\n\tprivate @Nullable List<RunningService> runningServices;\n\n\tprivate DockerComposeProperties properties;\n\n\tprivate LinkedHashSet<ApplicationListener<?>> eventListeners;\n\n\tprivate DockerComposeLifecycleManager lifecycleManager;\n\n\tprivate DockerComposeSkipCheck skipCheck;\n\n\t@BeforeEach\n\tvoid setup() throws IOException {\n\t\tFile file = new File(this.temp, \"compose.yml\");\n\t\tFileCopyUtils.copy(new byte[0], file);\n\t\tthis.dockerComposeFile = DockerComposeFile.of(file);\n\t\tthis.dockerCompose = mock(DockerCompose.class);\n\t\tFile workingDirectory = new File(\".\");\n\t\tthis.applicationContext = new GenericApplicationContext();\n\t\tthis.applicationContext.refresh();\n\t\tBinder binder = Binder.get(this.applicationContext.getEnvironment());\n\t\tthis.shutdownHandlers = new TestSpringApplicationShutdownHandlers();\n\t\tthis.properties = DockerComposeProperties.get(binder);\n\t\tthis.eventListeners = new LinkedHashSet<>();\n\t\tthis.skipCheck = mock(DockerComposeSkipCheck.class);\n\t\tthis.serviceReadinessChecks = mock(ServiceReadinessChecks.class);\n\t\tthis.lifecycleManager = new TestDockerComposeLifecycleManager(workingDirectory, this.applicationContext,\n\t\t\t\tthis.shutdownHandlers, this.properties, this.eventListeners, this.skipCheck,\n\t\t\t\tthis.serviceReadinessChecks);\n\t}\n\n\t@Test\n\tvoid startWhenEnabledFalseDoesNotStart() {\n\t\tthis.properties.setEnabled(false);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(listener.getEvent()).isNull();\n\t\tthen(this.dockerCompose).should(never()).hasDefinedServices();\n\t}\n\n\t@Test\n\tvoid startWhenAotProcessingDoesNotStart() {\n\t\twithSystemProperty(AbstractAotProcessor.AOT_PROCESSING, \"true\", () -> {\n\t\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\t\tthis.eventListeners.add(listener);\n\t\t\tsetUpRunningServices();\n\t\t\tthis.lifecycleManager.start();\n\t\t\tassertThat(listener.getEvent()).isNull();\n\t\t\tthen(this.dockerCompose).should(never()).hasDefinedServices();\n\t\t});\n\t}\n\n\t@Test\n\tvoid startWhenUsingAotArtifactsDoesNotStart() {\n\t\twithSystemProperty(AotDetector.AOT_ENABLED, \"true\", () -> {\n\t\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\t\tthis.eventListeners.add(listener);\n\t\t\tsetUpRunningServices();\n\t\t\tthis.lifecycleManager.start();\n\t\t\tassertThat(listener.getEvent()).isNull();\n\t\t\tthen(this.dockerCompose).should(never()).hasDefinedServices();\n\t\t});\n\t}\n\n\t@Test\n\tvoid startWhenComposeFileNotFoundThrowsException() {\n\t\tDockerComposeLifecycleManager manager = new DockerComposeLifecycleManager(new File(\".\"),\n\t\t\t\tthis.applicationContext, this.shutdownHandlers, this.properties, this.eventListeners, this.skipCheck,\n\t\t\t\tthis.serviceReadinessChecks);\n\t\tassertThatIllegalStateException().isThrownBy(manager::start)\n\t\t\t.withMessageContaining(Paths.get(\".\").toAbsolutePath().toString());\n\t}\n\n\t@Test\n\tvoid startWhenComposeFileNotFoundAndWorkingDirectoryNullThrowsException() {\n\t\tDockerComposeLifecycleManager manager = new DockerComposeLifecycleManager(null, this.applicationContext,\n\t\t\t\tthis.shutdownHandlers, this.properties, this.eventListeners, this.skipCheck,\n\t\t\t\tthis.serviceReadinessChecks);\n\t\tassertThatIllegalStateException().isThrownBy(manager::start)\n\t\t\t.withMessageContaining(Paths.get(\".\").toAbsolutePath().toString());\n\t}\n\n\t@Test\n\tvoid startWhenInTestDoesNotStart() {\n\t\tgiven(this.skipCheck.shouldSkip(any(), any())).willReturn(true);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(listener.getEvent()).isNull();\n\t\tthen(this.dockerCompose).should(never()).hasDefinedServices();\n\t}\n\n\t@Test\n\tvoid startWhenHasNoDefinedServicesDoesNothing() {\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(listener.getEvent()).isNull();\n\t\tthen(this.dockerCompose).should().hasDefinedServices();\n\t\tthen(this.dockerCompose).should(never()).up(any(), any());\n\t\tthen(this.dockerCompose).should(never()).start(any(), any());\n\t\tthen(this.dockerCompose).should(never()).down(any(), any());\n\t\tthen(this.dockerCompose).should(never()).stop(any(), any());\n\t}\n\n\t@Test\n\tvoid startWhenLifecycleStartAndStopAndHasNoRunningServicesDoesUpAndStop() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should().up(any(), any());\n\t\tthen(this.dockerCompose).should(never()).start(any(), any());\n\t\tthen(this.dockerCompose).should().stop(any(), any());\n\t\tthen(this.dockerCompose).should(never()).down(any(), any());\n\t}\n\n\t@Test\n\tvoid startWhenLifecycleStartAndStopAndHasRunningServicesDoesNothing() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should(never()).up(any(), any());\n\t\tthen(this.dockerCompose).should(never()).start(any(), any());\n\t\tthen(this.dockerCompose).should(never()).down(any(), any());\n\t\tthen(this.dockerCompose).should(never()).stop(any(), any());\n\t}\n\n\t@Test\n\tvoid startWhenLifecycleNoneDoesNothing() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.NONE);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should(never()).up(any(), any());\n\t\tthen(this.dockerCompose).should(never()).start(any(), any());\n\t\tthen(this.dockerCompose).should(never()).down(any(), any());\n\t\tthen(this.dockerCompose).should(never()).stop(any(), any());\n\t}\n\n\t@Test\n\tvoid startWhenLifecycleStartOnlyDoesOnlyStart() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.START_ONLY);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should().up(any(), any());\n\t\tthen(this.dockerCompose).should(never()).start(any(), any());\n\t\tthen(this.dockerCompose).should(never()).down(any(), any());\n\t\tthen(this.dockerCompose).should(never()).stop(any(), any());\n\t\tthis.shutdownHandlers.assertNoneAdded();\n\t}\n\n\t@Test\n\tvoid startWhenStartCommandStartDoesStartAndStop() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);\n\t\tthis.properties.getStart().setCommand(StartCommand.START);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should(never()).up(any(), any());\n\t\tthen(this.dockerCompose).should().start(any(), any());\n\t\tthen(this.dockerCompose).should().stop(any(), any());\n\t\tthen(this.dockerCompose).should(never()).down(any(), any());\n\t}\n\n\t@Test\n\tvoid startWhenStopCommandDownDoesStartAndDown() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);\n\t\tthis.properties.getStop().setCommand(StopCommand.DOWN);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should().up(any(), any());\n\t\tthen(this.dockerCompose).should(never()).start(any(), any());\n\t\tthen(this.dockerCompose).should(never()).stop(any(), any());\n\t\tthen(this.dockerCompose).should().down(any(), any());\n\t}\n\n\t@Test\n\tvoid startWhenHasStopTimeoutUsesDuration() {\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.START_AND_STOP);\n\t\tDuration timeout = Duration.ofDays(1);\n\t\tthis.properties.getStop().setTimeout(timeout);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tthen(this.dockerCompose).should().stop(timeout, Collections.emptyList());\n\t}\n\n\t@Test\n\tvoid startWhenHasIgnoreLabelIgnoresService() {\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices(true, Map.of(\"org.springframework.boot.ignore\", \"true\"));\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(listener.getEvent()).isNotNull();\n\t\tassertThat(listener.getEvent().getRunningServices()).isEmpty();\n\t}\n\n\t@Test\n\tvoid startWaitsUntilReady() {\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(this.runningServices).isNotNull();\n\t\tthen(this.serviceReadinessChecks).should().waitUntilReady(this.runningServices);\n\t}\n\n\t@Test\n\tvoid startWhenWaitNeverDoesNotWaitUntilReady() {\n\t\tthis.properties.getReadiness().setWait(Wait.NEVER);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(this.runningServices).isNotNull();\n\t\tthen(this.serviceReadinessChecks).should(never()).waitUntilReady(this.runningServices);\n\t}\n\n\t@Test\n\tvoid startWhenWaitOnlyIfStartedAndNotStartedDoesNotWaitUntilReady() {\n\t\tthis.properties.getReadiness().setWait(Wait.ONLY_IF_STARTED);\n\t\tthis.properties.setLifecycleManagement(LifecycleManagement.NONE);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(this.runningServices).isNotNull();\n\t\tthen(this.serviceReadinessChecks).should(never()).waitUntilReady(this.runningServices);\n\t}\n\n\t@Test\n\tvoid startWhenWaitOnlyIfStartedAndStartedWaitsUntilReady() {\n\t\tthis.properties.getReadiness().setWait(Wait.ONLY_IF_STARTED);\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices(false);\n\t\tthis.lifecycleManager.start();\n\t\tthis.shutdownHandlers.run();\n\t\tassertThat(this.runningServices).isNotNull();\n\t\tthen(this.serviceReadinessChecks).should().waitUntilReady(this.runningServices);\n\t}\n\n\t@Test\n\tvoid startGetsDockerComposeWithActiveProfiles() {\n\t\tthis.properties.getProfiles().setActive(Set.of(\"my-profile\"));\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(this.activeProfiles).containsExactly(\"my-profile\");\n\t}\n\n\t@Test\n\tvoid startGetsDockerComposeWithArguments() {\n\t\tthis.properties.getArguments().add(\"--project-name=test\");\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(this.arguments).containsExactly(\"--project-name=test\");\n\t}\n\n\t@Test\n\tvoid startPublishesEvent() {\n\t\tEventCapturingListener listener = new EventCapturingListener();\n\t\tthis.eventListeners.add(listener);\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tDockerComposeServicesReadyEvent event = listener.getEvent();\n\t\tassertThat(event).isNotNull();\n\t\tassertThat(event.getSource()).isEqualTo(this.applicationContext);\n\t\tassertThat(event.getRunningServices()).isEqualTo(this.runningServices);\n\t}\n\n\t@Test\n\tvoid shouldLogIfServicesAreAlreadyRunning(CapturedOutput output) {\n\t\tsetUpRunningServices();\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(output).contains(\"There are already Docker Compose services running, skipping startup\");\n\t}\n\n\t@Test\n\tvoid shouldNotLogIfThereAreNoServicesRunning(CapturedOutput output) {\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tgiven(this.dockerCompose.getRunningServices()).willReturn(Collections.emptyList());\n\t\tthis.lifecycleManager.start();\n\t\tassertThat(output).doesNotContain(\"There are already Docker Compose services running, skipping startup\");\n\t}\n\n\t@Test\n\tvoid shouldStartIfSkipModeIsIfRunningAndNoServicesAreRunning() {\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.properties.getStart().setSkip(Skip.IF_RUNNING);\n\t\tthis.lifecycleManager.start();\n\t\tthen(this.dockerCompose).should().up(any(), any());\n\t}\n\n\t@Test\n\tvoid shouldNotStartIfSkipModeIsIfRunningAndServicesAreAlreadyRunning() {\n\t\tsetUpRunningServices();\n\t\tthis.properties.getStart().setSkip(Skip.IF_RUNNING);\n\t\tthis.lifecycleManager.start();\n\t\tthen(this.dockerCompose).should(never()).up(any(), any());\n\t}\n\n\t@Test\n\tvoid shouldStartIfSkipModeIsNeverAndNoServicesAreRunning() {\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tthis.properties.getStart().setSkip(Skip.NEVER);\n\t\tthis.lifecycleManager.start();\n\t\tthen(this.dockerCompose).should().up(any(), any());\n\t}\n\n\t@Test\n\tvoid shouldStartIfSkipModeIsNeverAndServicesAreAlreadyRunning() {\n\t\tsetUpRunningServices();\n\t\tthis.properties.getStart().setSkip(Skip.NEVER);\n\t\tthis.lifecycleManager.start();\n\t\tthen(this.dockerCompose).should().up(any(), any());\n\t}\n\n\t@Test\n\tvoid whenStartFailsLogsAreRetrieved(CapturedOutput output) {\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tgiven(this.dockerCompose.logs()).willReturn(\"\"\"\n\t\t\t\tmulti\n\t\t\t\tline\n\t\t\t\tlogs\"\"\");\n\t\twillThrow(RuntimeException.class).given(this.dockerCompose).up(any(), any());\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(this.lifecycleManager::start);\n\t\tassertThat(output).contains(\"docker compose up failed with the following logs:\").contains(\"\"\"\n\t\t\t\tmulti\n\t\t\t\tline\n\t\t\t\tlogs\"\"\");\n\t}\n\n\t@Test\n\tvoid whenStartUsesStartAndItFailsLogsAreRetrieved(CapturedOutput output) {\n\t\tthis.properties.getStart().setCommand(StartCommand.START);\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tgiven(this.dockerCompose.logs()).willReturn(\"\"\"\n\t\t\t\tmulti\n\t\t\t\tline\n\t\t\t\tlogs\"\"\");\n\t\twillThrow(RuntimeException.class).given(this.dockerCompose).start(any(), any());\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(this.lifecycleManager::start);\n\t\tassertThat(output).contains(\"docker compose start failed with the following logs:\").contains(\"\"\"\n\t\t\t\tmulti\n\t\t\t\tline\n\t\t\t\tlogs\"\"\");\n\t}\n\n\t@Test\n\tvoid whenLogsAreUnavailableFailureIsHandled(CapturedOutput output) {\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tgiven(this.dockerCompose.logs()).willThrow(RuntimeException.class);\n\t\twillThrow(RuntimeException.class).given(this.dockerCompose).up(any(), any());\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(this.lifecycleManager::start);\n\t\tassertThat(output).contains(\"docker compose up failed and its logs were unavailable\");\n\t}\n\n\tprivate void setUpRunningServices() {\n\t\tsetUpRunningServices(true);\n\t}\n\n\tprivate void setUpRunningServices(boolean started) {\n\t\tsetUpRunningServices(started, Collections.emptyMap());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void setUpRunningServices(boolean started, Map<String, String> labels) {\n\t\tgiven(this.dockerCompose.hasDefinedServices()).willReturn(true);\n\t\tRunningService runningService = mock(RunningService.class);\n\t\tgiven(runningService.labels()).willReturn(labels);\n\t\tthis.runningServices = List.of(runningService);\n\t\tif (started) {\n\t\t\tgiven(this.dockerCompose.getRunningServices()).willReturn(this.runningServices);\n\t\t}\n\t\telse {\n\t\t\tgiven(this.dockerCompose.getRunningServices()).willReturn(Collections.emptyList(), this.runningServices);\n\t\t}\n\t}\n\n\tprivate void withSystemProperty(String key, String value, Runnable action) {\n\t\tString previous = System.getProperty(key);\n\t\ttry {\n\t\t\tSystem.setProperty(key, value);\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tif (previous == null) {\n\t\t\t\tSystem.clearProperty(key);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.setProperty(key, previous);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Testable {@link SpringApplicationShutdownHandlers}.\n\t */\n\tstatic class TestSpringApplicationShutdownHandlers implements SpringApplicationShutdownHandlers {\n\n\t\tprivate final List<Runnable> actions = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic void add(Runnable action) {\n\t\t\tthis.actions.add(action);\n\t\t}\n\n\t\t@Override\n\t\tpublic void remove(Runnable action) {\n\t\t\tthis.actions.remove(action);\n\t\t}\n\n\t\tvoid run() {\n\t\t\tthis.actions.forEach(Runnable::run);\n\t\t}\n\n\t\tvoid assertNoneAdded() {\n\t\t\tassertThat(this.actions).isEmpty();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ApplicationListener} to capture the {@link DockerComposeServicesReadyEvent}.\n\t */\n\tstatic class EventCapturingListener implements ApplicationListener<DockerComposeServicesReadyEvent> {\n\n\t\tprivate @Nullable DockerComposeServicesReadyEvent event;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(DockerComposeServicesReadyEvent event) {\n\t\t\tthis.event = event;\n\t\t}\n\n\t\t@Nullable DockerComposeServicesReadyEvent getEvent() {\n\t\t\treturn this.event;\n\t\t}\n\n\t}\n\n\t/**\n\t * Testable {@link DockerComposeLifecycleManager}.\n\t */\n\tclass TestDockerComposeLifecycleManager extends DockerComposeLifecycleManager {\n\n\t\tTestDockerComposeLifecycleManager(File workingDirectory, ApplicationContext applicationContext,\n\t\t\t\tSpringApplicationShutdownHandlers shutdownHandlers, DockerComposeProperties properties,\n\t\t\t\tSet<ApplicationListener<?>> eventListeners, DockerComposeSkipCheck skipCheck,\n\t\t\t\tServiceReadinessChecks serviceReadinessChecks) {\n\t\t\tsuper(workingDirectory, applicationContext, shutdownHandlers, properties, eventListeners, skipCheck,\n\t\t\t\t\tserviceReadinessChecks);\n\t\t}\n\n\t\t@Override\n\t\tprotected DockerComposeFile getComposeFile() {\n\t\t\treturn DockerComposeLifecycleManagerTests.this.dockerComposeFile;\n\t\t}\n\n\t\t@Override\n\t\tprotected DockerCompose getDockerCompose(DockerComposeFile composeFile, Set<String> activeProfiles,\n\t\t\t\tList<String> arguments) {\n\t\t\tDockerComposeLifecycleManagerTests.this.activeProfiles = activeProfiles;\n\t\t\tDockerComposeLifecycleManagerTests.this.arguments = arguments;\n\t\t\treturn DockerComposeLifecycleManagerTests.this.dockerCompose;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplicationShutdownHandlers;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DockerComposeListener}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposeListenerTests {\n\n\t@Test\n\tvoid onApplicationPreparedEventCreatesAndStartsDockerComposeLifecycleManager() {\n\t\tSpringApplicationShutdownHandlers shutdownHandlers = mock(SpringApplicationShutdownHandlers.class);\n\t\tSpringApplication application = mock(SpringApplication.class);\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tgiven(context.getEnvironment()).willReturn(environment);\n\t\tTestDockerComposeListener listener = new TestDockerComposeListener(shutdownHandlers, context);\n\t\tApplicationPreparedEvent event = new ApplicationPreparedEvent(application, new String[0], context);\n\t\tlistener.onApplicationEvent(event);\n\t\tassertThat(listener.getManager()).isNotNull();\n\t\tthen(listener.getManager()).should().start();\n\t}\n\n\tstatic class TestDockerComposeListener extends DockerComposeListener {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tprivate @Nullable DockerComposeLifecycleManager manager;\n\n\t\tTestDockerComposeListener(SpringApplicationShutdownHandlers shutdownHandlers,\n\t\t\t\tConfigurableApplicationContext context) {\n\t\t\tsuper(shutdownHandlers);\n\t\t\tthis.context = context;\n\t\t}\n\n\t\t@Override\n\t\tprotected DockerComposeLifecycleManager createDockerComposeLifecycleManager(\n\t\t\t\tConfigurableApplicationContext applicationContext, Binder binder, DockerComposeProperties properties,\n\t\t\t\tSet<ApplicationListener<?>> eventListeners) {\n\t\t\tthis.manager = mock(DockerComposeLifecycleManager.class);\n\t\t\tassertThat(applicationContext).isSameAs(this.context);\n\t\t\tassertThat(binder).isNotNull();\n\t\t\tassertThat(properties).isNotNull();\n\t\t\treturn this.manager;\n\t\t}\n\n\t\t@Nullable DockerComposeLifecycleManager getManager() {\n\t\t\treturn this.manager;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Wait;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Start.Skip;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DockerComposeProperties}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposePropertiesTests {\n\n\t@Test\n\tvoid getWhenNoPropertiesReturnsNew() {\n\t\tBinder binder = new Binder(new MapConfigurationPropertySource());\n\t\tDockerComposeProperties properties = DockerComposeProperties.get(binder);\n\t\tassertThat(properties.getFile()).isEmpty();\n\t\tassertThat(properties.getLifecycleManagement()).isEqualTo(LifecycleManagement.START_AND_STOP);\n\t\tassertThat(properties.getHost()).isNull();\n\t\tassertThat(properties.getStart().getCommand()).isEqualTo(StartCommand.UP);\n\t\tassertThat(properties.getStop().getCommand()).isEqualTo(StopCommand.STOP);\n\t\tassertThat(properties.getStop().getTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t\tassertThat(properties.getProfiles().getActive()).isEmpty();\n\t\tassertThat(properties.getReadiness().getWait()).isEqualTo(Wait.ALWAYS);\n\t\tassertThat(properties.getReadiness().getTimeout()).isEqualTo(Duration.ofMinutes(2));\n\t\tassertThat(properties.getReadiness().getTcp().getConnectTimeout()).isEqualTo(Duration.ofMillis(200));\n\t\tassertThat(properties.getReadiness().getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(200));\n\t}\n\n\t@Test\n\tvoid getWhenPropertiesReturnsBound() {\n\t\tMap<String, String> source = new LinkedHashMap<>();\n\t\tsource.put(\"spring.docker.compose.arguments\", \"--project-name=test,--progress=auto\");\n\t\tsource.put(\"spring.docker.compose.file\", \"my-compose.yml\");\n\t\tsource.put(\"spring.docker.compose.lifecycle-management\", \"start-only\");\n\t\tsource.put(\"spring.docker.compose.host\", \"myhost\");\n\t\tsource.put(\"spring.docker.compose.start.command\", \"start\");\n\t\tsource.put(\"spring.docker.compose.stop.command\", \"down\");\n\t\tsource.put(\"spring.docker.compose.stop.timeout\", \"5s\");\n\t\tsource.put(\"spring.docker.compose.profiles.active\", \"myprofile\");\n\t\tsource.put(\"spring.docker.compose.readiness.wait\", \"only-if-started\");\n\t\tsource.put(\"spring.docker.compose.readiness.timeout\", \"10s\");\n\t\tsource.put(\"spring.docker.compose.readiness.tcp.connect-timeout\", \"400ms\");\n\t\tsource.put(\"spring.docker.compose.readiness.tcp.read-timeout\", \"500ms\");\n\t\tBinder binder = new Binder(new MapConfigurationPropertySource(source));\n\t\tDockerComposeProperties properties = DockerComposeProperties.get(binder);\n\t\tassertThat(properties.getArguments()).containsExactly(\"--project-name=test\", \"--progress=auto\");\n\t\tassertThat(properties.getFile()).containsExactly(new File(\"my-compose.yml\"));\n\t\tassertThat(properties.getLifecycleManagement()).isEqualTo(LifecycleManagement.START_ONLY);\n\t\tassertThat(properties.getHost()).isEqualTo(\"myhost\");\n\t\tassertThat(properties.getStart().getCommand()).isEqualTo(StartCommand.START);\n\t\tassertThat(properties.getStop().getCommand()).isEqualTo(StopCommand.DOWN);\n\t\tassertThat(properties.getStop().getTimeout()).isEqualTo(Duration.ofSeconds(5));\n\t\tassertThat(properties.getProfiles().getActive()).containsExactly(\"myprofile\");\n\t\tassertThat(properties.getReadiness().getWait()).isEqualTo(Wait.ONLY_IF_STARTED);\n\t\tassertThat(properties.getReadiness().getTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t\tassertThat(properties.getReadiness().getTcp().getConnectTimeout()).isEqualTo(Duration.ofMillis(400));\n\t\tassertThat(properties.getReadiness().getTcp().getReadTimeout()).isEqualTo(Duration.ofMillis(500));\n\t}\n\n\t@Test\n\tvoid skipModeNeverShouldNeverSkip() {\n\t\tassertThat(Skip.NEVER.shouldSkip(Collections.emptyList())).isFalse();\n\t\tassertThat(Skip.NEVER.shouldSkip(List.of(mock(RunningService.class)))).isFalse();\n\t}\n\n\t@Test\n\tvoid skipModeIfRunningShouldSkipWhenServicesAreRunning() {\n\t\tassertThat(Skip.IF_RUNNING.shouldSkip(Collections.emptyList())).isFalse();\n\t\tassertThat(Skip.IF_RUNNING.shouldSkip(List.of(mock(RunningService.class)))).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/DockerComposeServicesReadyEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DockerComposeServicesReadyEvent}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DockerComposeServicesReadyEventTests {\n\n\tprivate ApplicationContext applicationContext = mock(ApplicationContext.class);\n\n\tprivate List<RunningService> runningServices = List.of(mock(RunningService.class));\n\n\tprivate DockerComposeServicesReadyEvent event = new DockerComposeServicesReadyEvent(this.applicationContext,\n\t\t\tthis.runningServices);\n\n\t@Test\n\tvoid getSourceReturnsSource() {\n\t\tassertThat(this.event.getSource()).isSameAs(this.applicationContext);\n\t}\n\n\t@Test\n\tvoid getRunningServicesReturnsRunningServices() {\n\t\tassertThat(this.event.getRunningServices()).isSameAs(this.runningServices);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/LifecycleManagementTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LifecycleManagement}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass LifecycleManagementTests {\n\n\t@Test\n\tvoid shouldStartupWhenNone() {\n\t\tassertThat(LifecycleManagement.NONE.shouldStart()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldShutdownWhenNone() {\n\t\tassertThat(LifecycleManagement.NONE.shouldStop()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldStartupWhenStartOnly() {\n\t\tassertThat(LifecycleManagement.START_ONLY.shouldStart()).isTrue();\n\t}\n\n\t@Test\n\tvoid shouldShutdownWhenStartOnly() {\n\t\tassertThat(LifecycleManagement.START_ONLY.shouldStop()).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldStartupWhenStartAndStop() {\n\t\tassertThat(LifecycleManagement.START_AND_STOP.shouldStart()).isTrue();\n\t}\n\n\t@Test\n\tvoid shouldShutdownWhenStartAndStop() {\n\t\tassertThat(LifecycleManagement.START_AND_STOP.shouldStop()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ReadinessTimeoutExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReadinessTimeoutException}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ReadinessTimeoutExceptionTests {\n\n\t@Test\n\tvoid createCreatesException() {\n\t\tDuration timeout = Duration.ofSeconds(10);\n\t\tRunningService s1 = mock(RunningService.class);\n\t\tgiven(s1.name()).willReturn(\"s1\");\n\t\tRunningService s2 = mock(RunningService.class);\n\t\tgiven(s2.name()).willReturn(\"s2\");\n\t\tServiceNotReadyException cause1 = new ServiceNotReadyException(s1, \"1 not ready\");\n\t\tServiceNotReadyException cause2 = new ServiceNotReadyException(s2, \"2 not ready\");\n\t\tList<ServiceNotReadyException> exceptions = List.of(cause1, cause2);\n\t\tReadinessTimeoutException exception = new ReadinessTimeoutException(timeout, exceptions);\n\t\tassertThat(exception).hasMessage(\"Readiness timeout of PT10S reached while waiting for services [s1, s2]\");\n\t\tassertThat(exception).hasSuppressedException(cause1).hasSuppressedException(cause2);\n\t\tassertThat(exception.getTimeout()).isEqualTo(timeout);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceNotReadyExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ServiceNotReadyException}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceNotReadyExceptionTests {\n\n\t@Test\n\tvoid getServiceReturnsService() {\n\t\tRunningService service = mock(RunningService.class);\n\t\tServiceNotReadyException exception = new ServiceNotReadyException(service, \"fail\");\n\t\tassertThat(exception.getService()).isEqualTo(service);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/ServiceReadinessChecksTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.lifecycle.DockerComposeProperties.Readiness.Tcp;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ServiceReadinessChecks}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceReadinessChecksTests {\n\n\tprivate Clock clock;\n\n\tInstant now = Instant.now();\n\n\tprivate RunningService runningService;\n\n\tprivate List<RunningService> runningServices;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.clock = mock(Clock.class);\n\t\tgiven(this.clock.instant()).willAnswer((args) -> this.now);\n\t\tthis.runningService = mock(RunningService.class);\n\t\tthis.runningServices = List.of(this.runningService);\n\t}\n\n\t@Test\n\tvoid waitUntilReadyWhenImmediatelyReady() {\n\t\tMockServiceReadinessCheck check = new MockServiceReadinessCheck();\n\t\tcreateChecks(check).waitUntilReady(this.runningServices);\n\t\tassertThat(check.getChecked()).contains(this.runningService);\n\t}\n\n\t@Test\n\tvoid waitUntilReadyWhenTakesTimeToBeReady() {\n\t\tMockServiceReadinessCheck check = new MockServiceReadinessCheck(2);\n\t\tcreateChecks(check).waitUntilReady(this.runningServices);\n\t\tassertThat(check.getChecked()).hasSize(2).contains(this.runningService);\n\t}\n\n\t@Test\n\tvoid waitUntilReadyWhenTimeout() {\n\t\tMockServiceReadinessCheck check = new MockServiceReadinessCheck(Integer.MAX_VALUE);\n\t\tassertThatExceptionOfType(ReadinessTimeoutException.class)\n\t\t\t.isThrownBy(() -> createChecks(check).waitUntilReady(this.runningServices))\n\t\t\t.satisfies((ex) -> assertThat(ex.getSuppressed()).hasSize(1));\n\t\tassertThat(check.getChecked()).hasSizeGreaterThan(10);\n\t}\n\n\t@Test\n\tvoid waitForWhenServiceHasDisableLabelDoesNotCheck() {\n\t\tgiven(this.runningService.labels()).willReturn(Map.of(\"org.springframework.boot.readiness-check.disable\", \"\"));\n\t\tMockServiceReadinessCheck check = new MockServiceReadinessCheck();\n\t\tcreateChecks(check).waitUntilReady(this.runningServices);\n\t\tassertThat(check.getChecked()).isEmpty();\n\t}\n\n\tvoid sleep(Duration duration) {\n\t\tthis.now = this.now.plus(duration);\n\t}\n\n\tprivate ServiceReadinessChecks createChecks(TcpConnectServiceReadinessCheck check) {\n\t\tDockerComposeProperties properties = new DockerComposeProperties();\n\t\treturn new ServiceReadinessChecks(properties.getReadiness(), this.clock, this::sleep, check);\n\t}\n\n\t/**\n\t * Mock {@link TcpConnectServiceReadinessCheck}.\n\t */\n\tstatic class MockServiceReadinessCheck extends TcpConnectServiceReadinessCheck {\n\n\t\tprivate final @Nullable Integer failUntil;\n\n\t\tprivate final List<RunningService> checked = new ArrayList<>();\n\n\t\tMockServiceReadinessCheck() {\n\t\t\tthis(null);\n\t\t}\n\n\t\tMockServiceReadinessCheck(@Nullable Integer failUntil) {\n\t\t\tsuper(new Tcp());\n\t\t\tthis.failUntil = failUntil;\n\t\t}\n\n\t\t@Override\n\t\tpublic void check(RunningService service) throws ServiceNotReadyException {\n\t\t\tthis.checked.add(service);\n\t\t\tif (this.failUntil != null && this.checked.size() < this.failUntil) {\n\t\t\t\tthrow new ServiceNotReadyException(service, \"Waiting\");\n\t\t\t}\n\t\t}\n\n\t\tList<RunningService> getChecked() {\n\t\t\treturn this.checked;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/StartCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DockerCompose;\nimport org.springframework.boot.logging.LogLevel;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StartCommand}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass StartCommandTests {\n\n\tprivate DockerCompose dockerCompose;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.dockerCompose = mock(DockerCompose.class);\n\t}\n\n\t@Test\n\tvoid applyToWhenUp() {\n\t\tStartCommand.UP.applyTo(this.dockerCompose, LogLevel.INFO, Collections.emptyList());\n\t\tthen(this.dockerCompose).should().up(LogLevel.INFO, Collections.emptyList());\n\t}\n\n\t@Test\n\tvoid applyToWhenStart() {\n\t\tStartCommand.START.applyTo(this.dockerCompose, LogLevel.INFO, Collections.emptyList());\n\t\tthen(this.dockerCompose).should().start(LogLevel.INFO, Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/StopCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.time.Duration;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.DockerCompose;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StopCommand}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass StopCommandTests {\n\n\tprivate DockerCompose dockerCompose;\n\n\tprivate final Duration duration = Duration.ofSeconds(10);\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.dockerCompose = mock(DockerCompose.class);\n\t}\n\n\t@Test\n\tvoid applyToWhenDown() {\n\t\tStopCommand.DOWN.applyTo(this.dockerCompose, this.duration, Collections.emptyList());\n\t\tthen(this.dockerCompose).should().down(this.duration, Collections.emptyList());\n\t}\n\n\t@Test\n\tvoid applyToWhenStart() {\n\t\tStopCommand.STOP.applyTo(this.dockerCompose, this.duration, Collections.emptyList());\n\t\tthen(this.dockerCompose).should().stop(this.duration, Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/lifecycle/TcpConnectServiceReadinessCheckTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.lifecycle;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.ConnectionPorts;\nimport org.springframework.boot.docker.compose.core.RunningService;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TcpConnectServiceReadinessCheck}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass TcpConnectServiceReadinessCheckTests {\n\n\tprivate static final int EPHEMERAL_PORT = 0;\n\n\tprivate TcpConnectServiceReadinessCheck readinessCheck;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tDockerComposeProperties.Readiness.Tcp tcpProperties = new DockerComposeProperties.Readiness.Tcp();\n\t\ttcpProperties.setConnectTimeout(Duration.ofMillis(100));\n\t\ttcpProperties.setReadTimeout(Duration.ofMillis(100));\n\t\tthis.readinessCheck = new TcpConnectServiceReadinessCheck(tcpProperties);\n\t}\n\n\t@Test\n\tvoid checkWhenServerWritesData() throws Exception {\n\t\twithServer((socket) -> socket.getOutputStream().write('!'), this::check);\n\t}\n\n\t@Test\n\tvoid checkWhenNoSocketOutput() throws Exception {\n\t\t// Simulate waiting for traffic from client to server. The sleep duration must\n\t\t// be longer than the read timeout of the ready check!\n\t\twithServer((socket) -> sleep(Duration.ofSeconds(10)), this::check);\n\t}\n\n\t@Test\n\tvoid checkWhenImmediateDisconnect() throws IOException {\n\t\twithServer(Socket::close,\n\t\t\t\t(port) -> assertThatExceptionOfType(ServiceNotReadyException.class).isThrownBy(() -> check(port))\n\t\t\t\t\t.withMessage(\"Immediate disconnect while connecting to port %d\".formatted(port)));\n\t}\n\n\t@Test\n\tvoid checkWhenNoServerListening() {\n\t\tassertThatExceptionOfType(ServiceNotReadyException.class).isThrownBy(() -> check(12345))\n\t\t\t.withMessage(\"IOException while connecting to port 12345\");\n\t}\n\n\tprivate void withServer(ThrowingConsumer<Socket> socketAction, ThrowingConsumer<Integer> portAction)\n\t\t\tthrows IOException {\n\t\ttry (ServerSocket serverSocket = new ServerSocket()) {\n\t\t\tserverSocket.bind(new InetSocketAddress(\"127.0.0.1\", EPHEMERAL_PORT));\n\t\t\tThread thread = new Thread(() -> {\n\t\t\t\ttry (Socket socket = serverSocket.accept()) {\n\t\t\t\t\tsocketAction.accept(socket);\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t\t}\n\t\t\t});\n\t\t\tthread.setName(\"Acceptor-%d\".formatted(serverSocket.getLocalPort()));\n\t\t\tthread.setUncaughtExceptionHandler((ignored, ex) -> ex.printStackTrace());\n\t\t\tthread.setDaemon(true);\n\t\t\tthread.start();\n\t\t\tportAction.accept(serverSocket.getLocalPort());\n\t\t}\n\t}\n\n\tprivate void check(Integer port) {\n\t\tthis.readinessCheck.check(mockRunningService(port));\n\t}\n\n\tprivate RunningService mockRunningService(Integer port) {\n\t\tRunningService runningService = mock(RunningService.class);\n\t\tConnectionPorts ports = mock(ConnectionPorts.class);\n\t\tgiven(ports.getAll(\"tcp\")).willReturn(List.of(port));\n\t\tgiven(runningService.host()).willReturn(\"localhost\");\n\t\tgiven(runningService.ports()).willReturn(ports);\n\t\treturn runningService;\n\t}\n\n\tprivate void sleep(Duration duration) {\n\t\ttry {\n\t\t\tThread.sleep(duration.toMillis());\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/java/org/springframework/boot/docker/compose/service/connection/ConnectionNamePredicateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection;\n\nimport java.util.Map;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.ImageReference;\nimport org.springframework.boot.docker.compose.core.RunningService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionNamePredicate}.\n *\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nclass ConnectionNamePredicateTests {\n\n\t@Test\n\tvoid official() {\n\t\tassertThat(predicateOf(\"elasticsearch\")).accepts(sourceOf(\"elasticsearch\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).accepts(sourceOf(\"library/elasticsearch\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).accepts(sourceOf(\"docker.io/library/elasticsearch\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).accepts(sourceOf(\"docker.io/elasticsearch\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).accepts(sourceOf(\"docker.io/elasticsearch:latest\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).rejects(sourceOf(\"redis\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).rejects(sourceOf(\"library/redis\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).rejects(sourceOf(\"docker.io/library/redis\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).rejects(sourceOf(\"docker.io/redis\"));\n\t\tassertThat(predicateOf(\"elasticsearch\")).rejects(sourceOf(\"docker.io/redis\"));\n\t\tassertThat(predicateOf(\"zipkin\")).rejects(sourceOf(\"openzipkin/zipkin\"));\n\t}\n\n\t@Test\n\tvoid organization() {\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).accepts(sourceOf(\"openzipkin/zipkin\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).accepts(sourceOf(\"openzipkin/zipkin:latest\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).rejects(sourceOf(\"openzipkin/zapkin\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).rejects(sourceOf(\"zipkin\"));\n\t}\n\n\t@Test\n\tvoid customDomain() {\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"internalhost:8080/redis\"));\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"internalhost:8080/library/redis\"));\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"myhost.com/redis\"));\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"myhost.com/library/redis\"));\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"myhost.com:8080/library/redis\"));\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"docker.my-company.com/library/redis:latest\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).rejects(sourceOf(\"myhost.com:8080/zipkin\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).rejects(sourceOf(\"myhost.com:8080/library/zipkin\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\")).accepts(sourceOf(\"myhost.com:8080/openzipkin/zipkin\"));\n\t\tassertThat(predicateOf(\"postgres\")).accepts(sourceOf(\"docker.my-company.com/postgres:latest\"));\n\t}\n\n\t@Test\n\tvoid labeled() {\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"internalhost:8080/myredis\", \"redis\"));\n\t\tassertThat(predicateOf(\"redis\")).accepts(sourceOf(\"internalhost:8080/myredis\", \"library/redis\"));\n\t\tassertThat(predicateOf(\"openzipkin/zipkin\"))\n\t\t\t.accepts(sourceOf(\"internalhost:8080/libs/libs/mzipkin\", \"openzipkin/zipkin\"));\n\t}\n\n\t@Test\n\tvoid multiple() {\n\t\tassertThat(predicateOf(\"elasticsearch1\", \"elasticsearch2\")).accepts(sourceOf(\"elasticsearch1\"))\n\t\t\t.accepts(sourceOf(\"elasticsearch2\"));\n\n\t}\n\n\tprivate Predicate<DockerComposeConnectionSource> predicateOf(String... required) {\n\t\treturn new ConnectionNamePredicate(required);\n\t}\n\n\tprivate DockerComposeConnectionSource sourceOf(String connectionName) {\n\t\treturn sourceOf(connectionName, null);\n\t}\n\n\tprivate DockerComposeConnectionSource sourceOf(String connectionName, @Nullable String label) {\n\t\tDockerComposeConnectionSource source = mock(DockerComposeConnectionSource.class);\n\t\tRunningService runningService = mock(RunningService.class);\n\t\tgiven(source.getRunningService()).willReturn(runningService);\n\t\tgiven(runningService.image()).willReturn(ImageReference.of(connectionName));\n\t\tif (label != null) {\n\t\t\tgiven(runningService.labels()).willReturn(Map.of(\"org.springframework.boot.service-connection\", label));\n\t\t}\n\t\treturn source;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-compose-config.json",
    "content": "{\n\t\"name\": \"redis-docker\",\n\t\"services\": {\n\t\t\"redis\": {\n\t\t\t\"command\": null,\n\t\t\t\"entrypoint\": null,\n\t\t\t\"image\": \"redis:7.0\",\n\t\t\t\"networks\": {\n\t\t\t\t\"default\": null\n\t\t\t},\n\t\t\t\"ports\": [\n\t\t\t\t{\n\t\t\t\t\t\"mode\": \"ingress\",\n\t\t\t\t\t\"target\": 6379,\n\t\t\t\t\t\"protocol\": \"tcp\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t},\n\t\"networks\": {\n\t\t\"default\": {\n\t\t\t\"name\": \"redis-docker_default\",\n\t\t\t\"ipam\": {\n\n\t\t\t},\n\t\t\t\"external\": false\n\t\t}\n\t}\n}"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-compose-ps.json",
    "content": "{\n\t\"Command\": \"/command\",\n\t\"CreatedAt\": \"2023-02-21 13:35:10 +0100 CET\",\n\t\"ID\": \"f5af31dae7f6\",\n\t\"Image\": \"redis:7.0\",\n\t\"Labels\": \"com.docker.compose.project.config_files=/compose.yaml,com.docker.compose.project.working_dir=/,com.docker.compose.container-number=1,com.docker.compose.image=sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82,com.docker.compose.oneoff=False,com.docker.compose.project=redis-docker,com.docker.compose.config-hash=cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0,com.docker.compose.depends_on=,com.docker.compose.service=redis,com.docker.compose.version=2.16.0\",\n\t\"LocalVolumes\": \"1\",\n\t\"Mounts\": \"9edc7fa2fe6c9e…\",\n\t\"Name\": \"redis-docker-redis-1\",\n\t\"Networks\": \"redis-docker_default\",\n\t\"Ports\": \"0.0.0.0:32770-\\\\u003e6379/tcp, :::32770-\\\\u003e6379/tcp\",\n\t\"RunningFor\": \"2 days ago\",\n\t\"Size\": \"0B\",\n\t\"State\": \"running\",\n\t\"Status\": \"Up 3 seconds\"\n}"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-compose-version.json",
    "content": "{\n\t\"version\": \"123\"\n}"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-context-podman.json",
    "content": "{\n    \"Name\": \"podman-machine-default\",\n    \"URI\": \"ssh://core@127.0.0.1:55599/run/user/501/podman/podman.sock\",\n    \"Identity\": \"/Users/user/.local/share/containers/podman/machine/machine\",\n    \"IsMachine\": true,\n    \"Default\": false,\n    \"ReadWrite\": true\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-context.json",
    "content": "{\n\t\"Current\": true,\n\t\"Description\": \"Current DOCKER_HOST based configuration\",\n\t\"DockerEndpoint\": \"unix:///var/run/docker.sock\",\n\t\"Error\": \"\",\n\t\"KubernetesEndpoint\": \"\",\n\t\"Name\": \"default\"\n}"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-inspect-bridge-network.json",
    "content": "{\n\t\"Id\": \"f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc\",\n\t\"Created\": \"2023-02-21T12:35:10.468917704Z\",\n\t\"Path\": \"docker-entrypoint.sh\",\n\t\"Args\": [\n\t\t\"redis-server\"\n\t],\n\t\"State\": {\n\t\t\"Status\": \"running\",\n\t\t\"Running\": true,\n\t\t\"Paused\": false,\n\t\t\"Restarting\": false,\n\t\t\"OOMKilled\": false,\n\t\t\"Dead\": false,\n\t\t\"Pid\": 38657,\n\t\t\"ExitCode\": 0,\n\t\t\"Error\": \"\",\n\t\t\"StartedAt\": \"2023-02-23T12:55:27.585705588Z\",\n\t\t\"FinishedAt\": \"2023-02-23T12:46:42.013469854Z\"\n\t},\n\t\"Image\": \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\"ResolvConfPath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/resolv.conf\",\n\t\"HostnamePath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hostname\",\n\t\"HostsPath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hosts\",\n\t\"LogPath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc-json.log\",\n\t\"Name\": \"/redis-docker-redis-1\",\n\t\"RestartCount\": 0,\n\t\"Driver\": \"btrfs\",\n\t\"Platform\": \"linux\",\n\t\"MountLabel\": \"\",\n\t\"ProcessLabel\": \"\",\n\t\"AppArmorProfile\": \"\",\n\t\"ExecIDs\": null,\n\t\"HostConfig\": {\n\t\t\"Binds\": null,\n\t\t\"ContainerIDFile\": \"\",\n\t\t\"LogConfig\": {\n\t\t\t\"Type\": \"json-file\",\n\t\t\t\"Config\": {\n\n\t\t\t}\n\t\t},\n\t\t\"NetworkMode\": \"redis-docker_default\",\n\t\t\"PortBindings\": {\n\t\t\t\"6379/tcp\": [\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"\",\n\t\t\t\t\t\"HostPort\": \"\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"RestartPolicy\": {\n\t\t\t\"Name\": \"\",\n\t\t\t\"MaximumRetryCount\": 0\n\t\t},\n\t\t\"AutoRemove\": false,\n\t\t\"VolumeDriver\": \"\",\n\t\t\"VolumesFrom\": null,\n\t\t\"ConsoleSize\": [\n\t\t\t0,\n\t\t\t0\n\t\t],\n\t\t\"CapAdd\": null,\n\t\t\"CapDrop\": null,\n\t\t\"CgroupnsMode\": \"private\",\n\t\t\"Dns\": [],\n\t\t\"DnsOptions\": [],\n\t\t\"DnsSearch\": [],\n\t\t\"ExtraHosts\": [],\n\t\t\"GroupAdd\": null,\n\t\t\"IpcMode\": \"private\",\n\t\t\"Cgroup\": \"\",\n\t\t\"Links\": null,\n\t\t\"OomScoreAdj\": 0,\n\t\t\"PidMode\": \"\",\n\t\t\"Privileged\": false,\n\t\t\"PublishAllPorts\": false,\n\t\t\"ReadonlyRootfs\": false,\n\t\t\"SecurityOpt\": null,\n\t\t\"UTSMode\": \"\",\n\t\t\"UsernsMode\": \"\",\n\t\t\"ShmSize\": 67108864,\n\t\t\"Runtime\": \"runc\",\n\t\t\"Isolation\": \"\",\n\t\t\"CpuShares\": 0,\n\t\t\"Memory\": 0,\n\t\t\"NanoCpus\": 0,\n\t\t\"CgroupParent\": \"\",\n\t\t\"BlkioWeight\": 0,\n\t\t\"BlkioWeightDevice\": null,\n\t\t\"BlkioDeviceReadBps\": null,\n\t\t\"BlkioDeviceWriteBps\": null,\n\t\t\"BlkioDeviceReadIOps\": null,\n\t\t\"BlkioDeviceWriteIOps\": null,\n\t\t\"CpuPeriod\": 0,\n\t\t\"CpuQuota\": 0,\n\t\t\"CpuRealtimePeriod\": 0,\n\t\t\"CpuRealtimeRuntime\": 0,\n\t\t\"CpusetCpus\": \"\",\n\t\t\"CpusetMems\": \"\",\n\t\t\"Devices\": null,\n\t\t\"DeviceCgroupRules\": null,\n\t\t\"DeviceRequests\": null,\n\t\t\"MemoryReservation\": 0,\n\t\t\"MemorySwap\": 0,\n\t\t\"MemorySwappiness\": null,\n\t\t\"OomKillDisable\": null,\n\t\t\"PidsLimit\": null,\n\t\t\"Ulimits\": null,\n\t\t\"CpuCount\": 0,\n\t\t\"CpuPercent\": 0,\n\t\t\"IOMaximumIOps\": 0,\n\t\t\"IOMaximumBandwidth\": 0,\n\t\t\"MaskedPaths\": [\n\t\t\t\"/proc/asound\",\n\t\t\t\"/proc/acpi\",\n\t\t\t\"/proc/kcore\",\n\t\t\t\"/proc/keys\",\n\t\t\t\"/proc/latency_stats\",\n\t\t\t\"/proc/timer_list\",\n\t\t\t\"/proc/timer_stats\",\n\t\t\t\"/proc/sched_debug\",\n\t\t\t\"/proc/scsi\",\n\t\t\t\"/sys/firmware\"\n\t\t],\n\t\t\"ReadonlyPaths\": [\n\t\t\t\"/proc/bus\",\n\t\t\t\"/proc/fs\",\n\t\t\t\"/proc/irq\",\n\t\t\t\"/proc/sys\",\n\t\t\t\"/proc/sysrq-trigger\"\n\t\t]\n\t},\n\t\"GraphDriver\": {\n\t\t\"Data\": null,\n\t\t\"Name\": \"btrfs\"\n\t},\n\t\"Mounts\": [\n\t\t{\n\t\t\t\"Type\": \"volume\",\n\t\t\t\"Name\": \"9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3\",\n\t\t\t\"Source\": \"/var/lib/docker/volumes/9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3/_data\",\n\t\t\t\"Destination\": \"/data\",\n\t\t\t\"Driver\": \"local\",\n\t\t\t\"Mode\": \"\",\n\t\t\t\"RW\": true,\n\t\t\t\"Propagation\": \"\"\n\t\t}\n\t],\n\t\"Config\": {\n\t\t\"Hostname\": \"f5af31dae7f6\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": true,\n\t\t\"AttachStderr\": true,\n\t\t\"ExposedPorts\": {\n\t\t\t\"6379/tcp\": {\n\n\t\t\t}\n\t\t},\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"GOSU_VERSION=1.16\",\n\t\t\t\"REDIS_VERSION=7.0.8\",\n\t\t\t\"REDIS_DOWNLOAD_URL=https://download.redis.io/releases/redis-7.0.8.tar.gz\",\n\t\t\t\"REDIS_DOWNLOAD_SHA=06a339e491306783dcf55b97f15a5dbcbdc01ccbde6dc23027c475cab735e914\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"redis-server\"\n\t\t],\n\t\t\"Image\": \"redis:7.0\",\n\t\t\"Volumes\": {\n\t\t\t\"/data\": {\n\n\t\t\t}\n\t\t},\n\t\t\"WorkingDir\": \"/data\",\n\t\t\"Entrypoint\": [\n\t\t\t\"docker-entrypoint.sh\"\n\t\t],\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"com.docker.compose.config-hash\": \"cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0\",\n\t\t\t\"com.docker.compose.container-number\": \"1\",\n\t\t\t\"com.docker.compose.depends_on\": \"\",\n\t\t\t\"com.docker.compose.image\": \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\t\t\"com.docker.compose.oneoff\": \"False\",\n\t\t\t\"com.docker.compose.project\": \"redis-docker\",\n\t\t\t\"com.docker.compose.project.config_files\": \"/compose.yaml\",\n\t\t\t\"com.docker.compose.project.working_dir\": \"/\",\n\t\t\t\"com.docker.compose.service\": \"redis\",\n\t\t\t\"com.docker.compose.version\": \"2.16.0\"\n\t\t}\n\t},\n\t\"NetworkSettings\": {\n\t\t\"Bridge\": \"\",\n\t\t\"SandboxID\": \"3df878d8ed31b2686e41437f141bebba8afcf3bdf8c47ea07c34c2e0b365ec88\",\n\t\t\"HairpinMode\": false,\n\t\t\"LinkLocalIPv6Address\": \"\",\n\t\t\"LinkLocalIPv6PrefixLen\": 0,\n\t\t\"Ports\": {\n\t\t\t\"6379/tcp\": [\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"0.0.0.0\",\n\t\t\t\t\t\"HostPort\": \"32770\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"::\",\n\t\t\t\t\t\"HostPort\": \"32770\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"SandboxKey\": \"/var/run/docker/netns/3df878d8ed31\",\n\t\t\"SecondaryIPAddresses\": null,\n\t\t\"SecondaryIPv6Addresses\": null,\n\t\t\"EndpointID\": \"\",\n\t\t\"Gateway\": \"\",\n\t\t\"GlobalIPv6Address\": \"\",\n\t\t\"GlobalIPv6PrefixLen\": 0,\n\t\t\"IPAddress\": \"\",\n\t\t\"IPPrefixLen\": 0,\n\t\t\"IPv6Gateway\": \"\",\n\t\t\"MacAddress\": \"\",\n\t\t\"Networks\": {\n\t\t\t\"redis-docker_default\": {\n\t\t\t\t\"IPAMConfig\": null,\n\t\t\t\t\"Links\": null,\n\t\t\t\t\"Aliases\": [\n\t\t\t\t\t\"redis-docker-redis-1\",\n\t\t\t\t\t\"redis\",\n\t\t\t\t\t\"f5af31dae7f6\"\n\t\t\t\t],\n\t\t\t\t\"NetworkID\": \"9cb2b8b6fb20703841b9337b48e65ed2a71e2da2e995e4782066d146c44fc205\",\n\t\t\t\t\"EndpointID\": \"e155c61c1608b20ba7a0bd34790fc342ec576310f75ef4399e96bf3a67e8b3f6\",\n\t\t\t\t\"Gateway\": \"192.168.32.1\",\n\t\t\t\t\"IPAddress\": \"192.168.32.2\",\n\t\t\t\t\"IPPrefixLen\": 20,\n\t\t\t\t\"IPv6Gateway\": \"\",\n\t\t\t\t\"GlobalIPv6Address\": \"\",\n\t\t\t\t\"GlobalIPv6PrefixLen\": 0,\n\t\t\t\t\"MacAddress\": \"02:42:c0:a8:20:02\",\n\t\t\t\t\"DriverOpts\": null\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-inspect-host-network.json",
    "content": "{\n\t\"Id\": \"111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1\",\n\t\"Created\": \"2023-02-23T14:19:06.668158561Z\",\n\t\"Path\": \"docker-entrypoint.sh\",\n\t\"Args\": [\n\t\t\"redis-server\"\n\t],\n\t\"State\": {\n\t\t\"Status\": \"running\",\n\t\t\"Running\": true,\n\t\t\"Paused\": false,\n\t\t\"Restarting\": false,\n\t\t\"OOMKilled\": false,\n\t\t\"Dead\": false,\n\t\t\"Pid\": 46377,\n\t\t\"ExitCode\": 0,\n\t\t\"Error\": \"\",\n\t\t\"StartedAt\": \"2023-02-23T14:19:07.001096801Z\",\n\t\t\"FinishedAt\": \"0001-01-01T00:00:00Z\"\n\t},\n\t\"Image\": \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\"ResolvConfPath\": \"/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/resolv.conf\",\n\t\"HostnamePath\": \"/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/hostname\",\n\t\"HostsPath\": \"/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/hosts\",\n\t\"LogPath\": \"/var/lib/docker/containers/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1/111b22dba993f3282257cbafc87c77763cb4f8a8e534804ef1feae9c8ef282a1-json.log\",\n\t\"Name\": \"/redis-docker-redis-1\",\n\t\"RestartCount\": 0,\n\t\"Driver\": \"btrfs\",\n\t\"Platform\": \"linux\",\n\t\"MountLabel\": \"\",\n\t\"ProcessLabel\": \"\",\n\t\"AppArmorProfile\": \"\",\n\t\"ExecIDs\": null,\n\t\"HostConfig\": {\n\t\t\"Binds\": null,\n\t\t\"ContainerIDFile\": \"\",\n\t\t\"LogConfig\": {\n\t\t\t\"Type\": \"json-file\",\n\t\t\t\"Config\": {\n\n\t\t\t}\n\t\t},\n\t\t\"NetworkMode\": \"host\",\n\t\t\"PortBindings\": {\n\t\t\t\"6379/tcp\": [\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"\",\n\t\t\t\t\t\"HostPort\": \"\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"RestartPolicy\": {\n\t\t\t\"Name\": \"\",\n\t\t\t\"MaximumRetryCount\": 0\n\t\t},\n\t\t\"AutoRemove\": false,\n\t\t\"VolumeDriver\": \"\",\n\t\t\"VolumesFrom\": null,\n\t\t\"ConsoleSize\": [\n\t\t\t0,\n\t\t\t0\n\t\t],\n\t\t\"CapAdd\": null,\n\t\t\"CapDrop\": null,\n\t\t\"CgroupnsMode\": \"private\",\n\t\t\"Dns\": null,\n\t\t\"DnsOptions\": null,\n\t\t\"DnsSearch\": null,\n\t\t\"ExtraHosts\": [],\n\t\t\"GroupAdd\": null,\n\t\t\"IpcMode\": \"private\",\n\t\t\"Cgroup\": \"\",\n\t\t\"Links\": null,\n\t\t\"OomScoreAdj\": 0,\n\t\t\"PidMode\": \"\",\n\t\t\"Privileged\": false,\n\t\t\"PublishAllPorts\": false,\n\t\t\"ReadonlyRootfs\": false,\n\t\t\"SecurityOpt\": null,\n\t\t\"UTSMode\": \"\",\n\t\t\"UsernsMode\": \"\",\n\t\t\"ShmSize\": 67108864,\n\t\t\"Runtime\": \"runc\",\n\t\t\"Isolation\": \"\",\n\t\t\"CpuShares\": 0,\n\t\t\"Memory\": 0,\n\t\t\"NanoCpus\": 0,\n\t\t\"CgroupParent\": \"\",\n\t\t\"BlkioWeight\": 0,\n\t\t\"BlkioWeightDevice\": null,\n\t\t\"BlkioDeviceReadBps\": null,\n\t\t\"BlkioDeviceWriteBps\": null,\n\t\t\"BlkioDeviceReadIOps\": null,\n\t\t\"BlkioDeviceWriteIOps\": null,\n\t\t\"CpuPeriod\": 0,\n\t\t\"CpuQuota\": 0,\n\t\t\"CpuRealtimePeriod\": 0,\n\t\t\"CpuRealtimeRuntime\": 0,\n\t\t\"CpusetCpus\": \"\",\n\t\t\"CpusetMems\": \"\",\n\t\t\"Devices\": null,\n\t\t\"DeviceCgroupRules\": null,\n\t\t\"DeviceRequests\": null,\n\t\t\"MemoryReservation\": 0,\n\t\t\"MemorySwap\": 0,\n\t\t\"MemorySwappiness\": null,\n\t\t\"OomKillDisable\": null,\n\t\t\"PidsLimit\": null,\n\t\t\"Ulimits\": null,\n\t\t\"CpuCount\": 0,\n\t\t\"CpuPercent\": 0,\n\t\t\"IOMaximumIOps\": 0,\n\t\t\"IOMaximumBandwidth\": 0,\n\t\t\"MaskedPaths\": [\n\t\t\t\"/proc/asound\",\n\t\t\t\"/proc/acpi\",\n\t\t\t\"/proc/kcore\",\n\t\t\t\"/proc/keys\",\n\t\t\t\"/proc/latency_stats\",\n\t\t\t\"/proc/timer_list\",\n\t\t\t\"/proc/timer_stats\",\n\t\t\t\"/proc/sched_debug\",\n\t\t\t\"/proc/scsi\",\n\t\t\t\"/sys/firmware\"\n\t\t],\n\t\t\"ReadonlyPaths\": [\n\t\t\t\"/proc/bus\",\n\t\t\t\"/proc/fs\",\n\t\t\t\"/proc/irq\",\n\t\t\t\"/proc/sys\",\n\t\t\t\"/proc/sysrq-trigger\"\n\t\t]\n\t},\n\t\"GraphDriver\": {\n\t\t\"Data\": null,\n\t\t\"Name\": \"btrfs\"\n\t},\n\t\"Mounts\": [\n\t\t{\n\t\t\t\"Type\": \"volume\",\n\t\t\t\"Name\": \"0ff245e74dc368da772d4d1139b2aafd423ca1ce1fbe502b4635d7d15f0faf8c\",\n\t\t\t\"Source\": \"/var/lib/docker/volumes/0ff245e74dc368da772d4d1139b2aafd423ca1ce1fbe502b4635d7d15f0faf8c/_data\",\n\t\t\t\"Destination\": \"/data\",\n\t\t\t\"Driver\": \"local\",\n\t\t\t\"Mode\": \"\",\n\t\t\t\"RW\": true,\n\t\t\t\"Propagation\": \"\"\n\t\t}\n\t],\n\t\"Config\": {\n\t\t\"Hostname\": \"fedora\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": true,\n\t\t\"AttachStderr\": true,\n\t\t\"ExposedPorts\": {\n\t\t\t\"6379/tcp\": {\n\n\t\t\t}\n\t\t},\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"GOSU_VERSION=1.16\",\n\t\t\t\"REDIS_VERSION=7.0.8\",\n\t\t\t\"REDIS_DOWNLOAD_URL=https://download.redis.io/releases/redis-7.0.8.tar.gz\",\n\t\t\t\"REDIS_DOWNLOAD_SHA=06a339e491306783dcf55b97f15a5dbcbdc01ccbde6dc23027c475cab735e914\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"redis-server\"\n\t\t],\n\t\t\"Image\": \"redis:7.0\",\n\t\t\"Volumes\": {\n\t\t\t\"/data\": {\n\n\t\t\t}\n\t\t},\n\t\t\"WorkingDir\": \"/data\",\n\t\t\"Entrypoint\": [\n\t\t\t\"docker-entrypoint.sh\"\n\t\t],\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"com.docker.compose.config-hash\": \"204d00fc2f8ffd749769e3f6c160b2a2366e76cf8980bb2984bc65674748b3ca\",\n\t\t\t\"com.docker.compose.container-number\": \"1\",\n\t\t\t\"com.docker.compose.depends_on\": \"\",\n\t\t\t\"com.docker.compose.image\": \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\t\t\"com.docker.compose.oneoff\": \"False\",\n\t\t\t\"com.docker.compose.project\": \"redis-docker\",\n\t\t\t\"com.docker.compose.project.config_files\": \"/compose.yaml\",\n\t\t\t\"com.docker.compose.project.working_dir\": \"/\",\n\t\t\t\"com.docker.compose.service\": \"redis\",\n\t\t\t\"com.docker.compose.version\": \"2.16.0\"\n\t\t}\n\t},\n\t\"NetworkSettings\": {\n\t\t\"Bridge\": \"\",\n\t\t\"SandboxID\": \"6ec5c12e14078b424707534b8b64d0953ce9da21eaebd422daefff2d6a08f14d\",\n\t\t\"HairpinMode\": false,\n\t\t\"LinkLocalIPv6Address\": \"\",\n\t\t\"LinkLocalIPv6PrefixLen\": 0,\n\t\t\"Ports\": {\n\n\t\t},\n\t\t\"SandboxKey\": \"/var/run/docker/netns/default\",\n\t\t\"SecondaryIPAddresses\": null,\n\t\t\"SecondaryIPv6Addresses\": null,\n\t\t\"EndpointID\": \"\",\n\t\t\"Gateway\": \"\",\n\t\t\"GlobalIPv6Address\": \"\",\n\t\t\"GlobalIPv6PrefixLen\": 0,\n\t\t\"IPAddress\": \"\",\n\t\t\"IPPrefixLen\": 0,\n\t\t\"IPv6Gateway\": \"\",\n\t\t\"MacAddress\": \"\",\n\t\t\"Networks\": {\n\t\t\t\"host\": {\n\t\t\t\t\"IPAMConfig\": null,\n\t\t\t\t\"Links\": null,\n\t\t\t\t\"Aliases\": null,\n\t\t\t\t\"NetworkID\": \"c8fa8aac531ce4630465de4baf8d0310a2ff3243b3986e5251611c1a4ee6e1b3\",\n\t\t\t\t\"EndpointID\": \"cfdc6016b0dd724f7714ae116c5fa33127401f5e6853f07c4c1db5e967871136\",\n\t\t\t\t\"Gateway\": \"\",\n\t\t\t\t\"IPAddress\": \"\",\n\t\t\t\t\"IPPrefixLen\": 0,\n\t\t\t\t\"IPv6Gateway\": \"\",\n\t\t\t\t\"GlobalIPv6Address\": \"\",\n\t\t\t\t\"GlobalIPv6PrefixLen\": 0,\n\t\t\t\t\"MacAddress\": \"\",\n\t\t\t\t\"DriverOpts\": null\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/test/resources/org/springframework/boot/docker/compose/core/docker-inspect.json",
    "content": "{\n\t\"Id\": \"f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc\",\n\t\"Created\": \"2023-02-21T12:35:10.468917704Z\",\n\t\"Path\": \"docker-entrypoint.sh\",\n\t\"Args\": [\n\t\t\"redis-server\"\n\t],\n\t\"State\": {\n\t\t\"Status\": \"running\",\n\t\t\"Running\": true,\n\t\t\"Paused\": false,\n\t\t\"Restarting\": false,\n\t\t\"OOMKilled\": false,\n\t\t\"Dead\": false,\n\t\t\"Pid\": 38657,\n\t\t\"ExitCode\": 0,\n\t\t\"Error\": \"\",\n\t\t\"StartedAt\": \"2023-02-23T12:55:27.585705588Z\",\n\t\t\"FinishedAt\": \"2023-02-23T12:46:42.013469854Z\"\n\t},\n\t\"Image\": \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\"ResolvConfPath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/resolv.conf\",\n\t\"HostnamePath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hostname\",\n\t\"HostsPath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/hosts\",\n\t\"LogPath\": \"/var/lib/docker/containers/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc/f5af31dae7f665bd194ec7261bdc84e5df9c64753abb4a6cec6c33f7cf64c3fc-json.log\",\n\t\"Name\": \"/redis-docker-redis-1\",\n\t\"RestartCount\": 0,\n\t\"Driver\": \"btrfs\",\n\t\"Platform\": \"linux\",\n\t\"MountLabel\": \"\",\n\t\"ProcessLabel\": \"\",\n\t\"AppArmorProfile\": \"\",\n\t\"ExecIDs\": null,\n\t\"HostConfig\": {\n\t\t\"Binds\": null,\n\t\t\"ContainerIDFile\": \"\",\n\t\t\"LogConfig\": {\n\t\t\t\"Type\": \"json-file\",\n\t\t\t\"Config\": {\n\n\t\t\t}\n\t\t},\n\t\t\"NetworkMode\": \"redis-docker_default\",\n\t\t\"PortBindings\": {\n\t\t\t\"6379/tcp\": [\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"\",\n\t\t\t\t\t\"HostPort\": \"\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"RestartPolicy\": {\n\t\t\t\"Name\": \"\",\n\t\t\t\"MaximumRetryCount\": 0\n\t\t},\n\t\t\"AutoRemove\": false,\n\t\t\"VolumeDriver\": \"\",\n\t\t\"VolumesFrom\": null,\n\t\t\"ConsoleSize\": [\n\t\t\t0,\n\t\t\t0\n\t\t],\n\t\t\"CapAdd\": null,\n\t\t\"CapDrop\": null,\n\t\t\"CgroupnsMode\": \"private\",\n\t\t\"Dns\": [],\n\t\t\"DnsOptions\": [],\n\t\t\"DnsSearch\": [],\n\t\t\"ExtraHosts\": [],\n\t\t\"GroupAdd\": null,\n\t\t\"IpcMode\": \"private\",\n\t\t\"Cgroup\": \"\",\n\t\t\"Links\": null,\n\t\t\"OomScoreAdj\": 0,\n\t\t\"PidMode\": \"\",\n\t\t\"Privileged\": false,\n\t\t\"PublishAllPorts\": false,\n\t\t\"ReadonlyRootfs\": false,\n\t\t\"SecurityOpt\": null,\n\t\t\"UTSMode\": \"\",\n\t\t\"UsernsMode\": \"\",\n\t\t\"ShmSize\": 67108864,\n\t\t\"Runtime\": \"runc\",\n\t\t\"Isolation\": \"\",\n\t\t\"CpuShares\": 0,\n\t\t\"Memory\": 0,\n\t\t\"NanoCpus\": 0,\n\t\t\"CgroupParent\": \"\",\n\t\t\"BlkioWeight\": 0,\n\t\t\"BlkioWeightDevice\": null,\n\t\t\"BlkioDeviceReadBps\": null,\n\t\t\"BlkioDeviceWriteBps\": null,\n\t\t\"BlkioDeviceReadIOps\": null,\n\t\t\"BlkioDeviceWriteIOps\": null,\n\t\t\"CpuPeriod\": 0,\n\t\t\"CpuQuota\": 0,\n\t\t\"CpuRealtimePeriod\": 0,\n\t\t\"CpuRealtimeRuntime\": 0,\n\t\t\"CpusetCpus\": \"\",\n\t\t\"CpusetMems\": \"\",\n\t\t\"Devices\": null,\n\t\t\"DeviceCgroupRules\": null,\n\t\t\"DeviceRequests\": null,\n\t\t\"MemoryReservation\": 0,\n\t\t\"MemorySwap\": 0,\n\t\t\"MemorySwappiness\": null,\n\t\t\"OomKillDisable\": null,\n\t\t\"PidsLimit\": null,\n\t\t\"Ulimits\": null,\n\t\t\"CpuCount\": 0,\n\t\t\"CpuPercent\": 0,\n\t\t\"IOMaximumIOps\": 0,\n\t\t\"IOMaximumBandwidth\": 0,\n\t\t\"MaskedPaths\": [\n\t\t\t\"/proc/asound\",\n\t\t\t\"/proc/acpi\",\n\t\t\t\"/proc/kcore\",\n\t\t\t\"/proc/keys\",\n\t\t\t\"/proc/latency_stats\",\n\t\t\t\"/proc/timer_list\",\n\t\t\t\"/proc/timer_stats\",\n\t\t\t\"/proc/sched_debug\",\n\t\t\t\"/proc/scsi\",\n\t\t\t\"/sys/firmware\"\n\t\t],\n\t\t\"ReadonlyPaths\": [\n\t\t\t\"/proc/bus\",\n\t\t\t\"/proc/fs\",\n\t\t\t\"/proc/irq\",\n\t\t\t\"/proc/sys\",\n\t\t\t\"/proc/sysrq-trigger\"\n\t\t]\n\t},\n\t\"GraphDriver\": {\n\t\t\"Data\": null,\n\t\t\"Name\": \"btrfs\"\n\t},\n\t\"Mounts\": [\n\t\t{\n\t\t\t\"Type\": \"volume\",\n\t\t\t\"Name\": \"9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3\",\n\t\t\t\"Source\": \"/var/lib/docker/volumes/9edc7fa2fe6c9e8f67fd31a8649a4b5d7edbc9c1604462e04a5f35d6bfda87c3/_data\",\n\t\t\t\"Destination\": \"/data\",\n\t\t\t\"Driver\": \"local\",\n\t\t\t\"Mode\": \"\",\n\t\t\t\"RW\": true,\n\t\t\t\"Propagation\": \"\"\n\t\t}\n\t],\n\t\"Config\": {\n\t\t\"Hostname\": \"f5af31dae7f6\",\n\t\t\"Domainname\": \"\",\n\t\t\"User\": \"\",\n\t\t\"AttachStdin\": false,\n\t\t\"AttachStdout\": true,\n\t\t\"AttachStderr\": true,\n\t\t\"ExposedPorts\": {\n\t\t\t\"6379/tcp\": {\n\n\t\t\t}\n\t\t},\n\t\t\"Tty\": false,\n\t\t\"OpenStdin\": false,\n\t\t\"StdinOnce\": false,\n\t\t\"Env\": [\n\t\t\t\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\",\n\t\t\t\"GOSU_VERSION=1.16\",\n\t\t\t\"REDIS_VERSION=7.0.8\"\n\t\t],\n\t\t\"Cmd\": [\n\t\t\t\"redis-server\"\n\t\t],\n\t\t\"Image\": \"redis:7.0\",\n\t\t\"Volumes\": {\n\t\t\t\"/data\": {\n\n\t\t\t}\n\t\t},\n\t\t\"WorkingDir\": \"/data\",\n\t\t\"Entrypoint\": [\n\t\t\t\"docker-entrypoint.sh\"\n\t\t],\n\t\t\"OnBuild\": null,\n\t\t\"Labels\": {\n\t\t\t\"com.docker.compose.config-hash\": \"cfdc8e119d85a53c7d47edb37a3b160a8c83ba48b0428ebc07713befec991dd0\",\n\t\t\t\"com.docker.compose.container-number\": \"1\",\n\t\t\t\"com.docker.compose.depends_on\": \"\",\n\t\t\t\"com.docker.compose.image\": \"sha256:e79ba23ed43baa22054741136bf45bdb041824f41c5e16c0033ea044ca164b82\",\n\t\t\t\"com.docker.compose.oneoff\": \"False\",\n\t\t\t\"com.docker.compose.project\": \"redis-docker\",\n\t\t\t\"com.docker.compose.project.config_files\": \"compose.yaml\",\n\t\t\t\"com.docker.compose.project.working_dir\": \"/\",\n\t\t\t\"com.docker.compose.service\": \"redis\",\n\t\t\t\"com.docker.compose.version\": \"2.16.0\"\n\t\t}\n\t},\n\t\"NetworkSettings\": {\n\t\t\"Bridge\": \"\",\n\t\t\"SandboxID\": \"3df878d8ed31b2686e41437f141bebba8afcf3bdf8c47ea07c34c2e0b365ec88\",\n\t\t\"HairpinMode\": false,\n\t\t\"LinkLocalIPv6Address\": \"\",\n\t\t\"LinkLocalIPv6PrefixLen\": 0,\n\t\t\"Ports\": {\n\t\t\t\"6379/tcp\": [\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"0.0.0.0\",\n\t\t\t\t\t\"HostPort\": \"32770\"\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"HostIp\": \"::\",\n\t\t\t\t\t\"HostPort\": \"32770\"\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t\"SandboxKey\": \"/var/run/docker/netns/3df878d8ed31\",\n\t\t\"SecondaryIPAddresses\": null,\n\t\t\"SecondaryIPv6Addresses\": null,\n\t\t\"EndpointID\": \"\",\n\t\t\"Gateway\": \"\",\n\t\t\"GlobalIPv6Address\": \"\",\n\t\t\"GlobalIPv6PrefixLen\": 0,\n\t\t\"IPAddress\": \"\",\n\t\t\"IPPrefixLen\": 0,\n\t\t\"IPv6Gateway\": \"\",\n\t\t\"MacAddress\": \"\",\n\t\t\"Networks\": {\n\t\t\t\"redis-docker_default\": {\n\t\t\t\t\"IPAMConfig\": null,\n\t\t\t\t\"Links\": null,\n\t\t\t\t\"Aliases\": [\n\t\t\t\t\t\"redis-docker-redis-1\",\n\t\t\t\t\t\"redis\",\n\t\t\t\t\t\"f5af31dae7f6\"\n\t\t\t\t],\n\t\t\t\t\"NetworkID\": \"9cb2b8b6fb20703841b9337b48e65ed2a71e2da2e995e4782066d146c44fc205\",\n\t\t\t\t\"EndpointID\": \"e155c61c1608b20ba7a0bd34790fc342ec576310f75ef4399e96bf3a67e8b3f6\",\n\t\t\t\t\"Gateway\": \"192.168.32.1\",\n\t\t\t\t\"IPAddress\": \"192.168.32.2\",\n\t\t\t\t\"IPPrefixLen\": 20,\n\t\t\t\t\"IPv6Gateway\": \"\",\n\t\t\t\t\"GlobalIPv6Address\": \"\",\n\t\t\t\t\"GlobalIPv6PrefixLen\": 0,\n\t\t\t\t\"MacAddress\": \"02:42:c0:a8:20:02\",\n\t\t\t\t\"DriverOpts\": null\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "core/spring-boot-docker-compose/src/testFixtures/java/org/springframework/boot/docker/compose/service/connection/test/DockerComposeTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection.test;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.process.DisabledIfProcessUnavailable;\n\n/**\n * A {@link Test test} that exercises Spring Boot's Docker Compose support.\n * <p>\n * Before the test is executed, a {@link SpringApplication} that is configured to use the\n * specified Docker Compose file is started. Any bean that exists in the resulting\n * application context can be injected as a parameter into the test method. Typically,\n * this will be a {@link ConnectionDetails} implementation.\n * <p>\n * Once the test has executed, the {@link SpringApplication} is tidied up such that the\n * Docker Compose services are stopped and destroyed and the application context is\n * closed.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\n@Test\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ExtendWith(DockerComposeTestExtension.class)\n@DisabledIfDockerUnavailable\n@DisabledIfProcessUnavailable({ \"docker\", \"compose\" })\npublic @interface DockerComposeTest {\n\n\t/**\n\t * The name of the compose file to use. Loaded as a classpath resource relative to the\n\t * test class. The image name in the compose file can be parameterized using\n\t * <code>{image}</code> and it will be replaced using the specified {@link #image}\n\t * reference.\n\t * @return the compose file\n\t */\n\tString composeFile();\n\n\t/**\n\t * Additional resources to copy next to the compose file. Loaded as a classpath\n\t * resource relative to the test class.\n\t * @return the additional resources to copy\n\t */\n\tString[] additionalResources() default {};\n\n\t/**\n\t * The Docker image reference.\n\t * @return the Docker image reference\n\t * @see TestImage\n\t */\n\tTestImage image();\n\n}\n"
  },
  {
    "path": "core/spring-boot-docker-compose/src/testFixtures/java/org/springframework/boot/docker/compose/service/connection/test/DockerComposeTestExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docker.compose.service.connection.test;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.extension.AfterTestExecutionCallback;\nimport org.junit.jupiter.api.extension.BeforeTestExecutionCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ExtensionContext.Namespace;\nimport org.junit.jupiter.api.extension.ExtensionContext.Store;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolutionException;\nimport org.junit.jupiter.api.extension.ParameterResolver;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplicationShutdownHandlers;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * {@link Extension} for {@link DockerComposeTest @DockerComposeTest}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\nclass DockerComposeTestExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver {\n\n\tprivate static final Namespace NAMESPACE = Namespace.create(DockerComposeTestExtension.class);\n\n\tprivate static final String STORE_KEY_WORKSPACE = \"workspace\";\n\n\tprivate static final String STORE_KEY_APPLICATION_CONTEXT = \"application-context\";\n\n\t@Override\n\tpublic void beforeTestExecution(ExtensionContext context) throws Exception {\n\t\tPath logFile = Files.createTempFile(\"docker-compose-test\", \".log\");\n\t\tStore store = context.getStore(NAMESPACE);\n\t\tPath workspace = Files.createTempDirectory(\"DockerComposeTestExtension-\");\n\t\tstore.put(STORE_KEY_WORKSPACE, workspace);\n\t\ttry {\n\t\t\tPath composeFile = prepareComposeFile(workspace, context);\n\t\t\tcopyAdditionalResources(workspace, context);\n\t\t\tSpringApplication application = prepareApplication(composeFile, logFile);\n\t\t\tstore.put(STORE_KEY_APPLICATION_CONTEXT, application.run());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tcleanUp(context);\n\t\t\tthrow new DockerComposeApplicationRunException(readLogs(logFile));\n\t\t}\n\t\tfinally {\n\t\t\tFiles.delete(logFile);\n\t\t}\n\t}\n\n\tprivate String readLogs(Path logFile) {\n\t\ttry {\n\t\t\treturn Files.readString(logFile);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn \"Unavailable: \" + ex.getMessage();\n\t\t}\n\t}\n\n\tprivate Path prepareComposeFile(Path workspace, ExtensionContext context) {\n\t\tDockerComposeTest dockerComposeTest = context.getRequiredTestMethod().getAnnotation(DockerComposeTest.class);\n\t\tTestImage image = dockerComposeTest.image();\n\t\tResource composeResource = new ClassPathResource(dockerComposeTest.composeFile(),\n\t\t\t\tcontext.getRequiredTestClass());\n\t\treturn transformedComposeFile(workspace, composeResource, image);\n\t}\n\n\tprivate Path transformedComposeFile(Path workspace, Resource composeFileResource, TestImage image) {\n\t\ttry {\n\t\t\tString template = composeFileResource.getContentAsString(StandardCharsets.UTF_8);\n\t\t\tString content = template.replace(\"{imageName}\", image.toString());\n\t\t\tPath composeFile = workspace.resolve(\"compose.yaml\");\n\t\t\tFiles.writeString(composeFile, content);\n\t\t\treturn composeFile;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tfail(\"Error transforming Docker compose file '\" + composeFileResource + \"': \" + ex.getMessage(), ex);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate void copyAdditionalResources(Path workspace, ExtensionContext context) {\n\t\tDockerComposeTest dockerComposeTest = context.getRequiredTestMethod().getAnnotation(DockerComposeTest.class);\n\t\tfor (String additionalResource : dockerComposeTest.additionalResources()) {\n\t\t\tResource resource = new ClassPathResource(additionalResource, context.getRequiredTestClass());\n\t\t\tcopyAdditionalResource(workspace, resource);\n\t\t}\n\t}\n\n\tprivate void copyAdditionalResource(Path workspace, Resource resource) {\n\t\ttry {\n\t\t\tPath source = resource.getFile().toPath();\n\t\t\tFiles.copy(source, workspace.resolve(source.getFileName()));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tfail(\"Error copying additional resource '\" + resource + \"': \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate SpringApplication prepareApplication(Path composeFile, Path logFile) {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tMap<String, Object> properties = new LinkedHashMap<>();\n\t\tproperties.put(\"spring.docker.compose.skip.in-tests\", \"false\");\n\t\tproperties.put(\"spring.docker.compose.file\", composeFile);\n\t\tproperties.put(\"spring.docker.compose.stop.command\", \"down\");\n\t\tproperties.put(\"spring.docker.compose.start.arguments[0]\", \"--wait-timeout\");\n\t\tproperties.put(\"spring.docker.compose.start.arguments[1]\", \"120\");\n\t\tproperties.put(\"logging.file.name\", logFile.toString());\n\t\tapplication.setDefaultProperties(properties);\n\t\treturn application;\n\t}\n\n\t@Override\n\tpublic void afterTestExecution(ExtensionContext context) throws Exception {\n\t\tcleanUp(context);\n\t}\n\n\tprivate void cleanUp(ExtensionContext context) throws Exception {\n\t\tStore store = context.getStore(NAMESPACE);\n\t\trunShutdownHandlers();\n\t\tdeleteWorkspace(store);\n\t}\n\n\tprivate void runShutdownHandlers() {\n\t\tSpringApplicationShutdownHandlers shutdownHandlers = SpringApplication.getShutdownHandlers();\n\t\t((Runnable) shutdownHandlers).run();\n\t}\n\n\tprivate void deleteWorkspace(Store store) throws IOException {\n\t\tPath workspace = (Path) store.get(STORE_KEY_WORKSPACE);\n\t\tif (workspace != null) {\n\t\t\tFileSystemUtils.deleteRecursively(workspace);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\tthrows ParameterResolutionException {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\tthrows ParameterResolutionException {\n\t\tConfigurableApplicationContext applicationContext = extensionContext.getStore(NAMESPACE)\n\t\t\t.get(STORE_KEY_APPLICATION_CONTEXT, ConfigurableApplicationContext.class);\n\t\treturn (applicationContext != null) ? applicationContext.getBean(parameterContext.getParameter().getType())\n\t\t\t\t: null;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\tstatic class DockerComposeApplicationRunException extends RuntimeException {\n\n\t\tDockerComposeApplicationRunException(String logs) {\n\t\t\tsuper(\"Docker Compose failed. Application logs:%n%n%s\".formatted(logs));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Properties Migrator\"\n\ndependencies {\n\timplementation(project(\":configuration-metadata:spring-boot-configuration-metadata\"))\n\timplementation(project(\":core:spring-boot\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.springframework:spring-test\")\n}\n\ntasks.named(\"javadoc\").configure {\n\t// No public or protected classes\n\tenabled = false\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/main/java/org/springframework/boot/context/properties/migrator/PropertiesMigrationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.migrator;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.SpringApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\n/**\n * An {@link ApplicationListener} that inspects the {@link ConfigurableEnvironment\n * environment} for configuration keys that need to be migrated. Automatically renames the\n * keys that have a matching replacement and logs a report of what was discovered.\n *\n * @author Stephane Nicoll\n */\nclass PropertiesMigrationListener implements ApplicationListener<SpringApplicationEvent> {\n\n\tprivate static final Log logger = LogFactory.getLog(PropertiesMigrationListener.class);\n\n\tprivate @Nullable PropertiesMigrationReport report;\n\n\tprivate boolean reported;\n\n\t@Override\n\tpublic void onApplicationEvent(SpringApplicationEvent event) {\n\t\tif (event instanceof ApplicationPreparedEvent preparedEvent) {\n\t\t\tonApplicationPreparedEvent(preparedEvent);\n\t\t}\n\t\tif (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) {\n\t\t\tlogLegacyPropertiesReport();\n\t\t}\n\t}\n\n\tprivate void onApplicationPreparedEvent(ApplicationPreparedEvent event) {\n\t\tConfigurationMetadataRepository repository = loadRepository();\n\t\tPropertiesMigrationReporter reporter = new PropertiesMigrationReporter(repository,\n\t\t\t\tevent.getApplicationContext().getEnvironment());\n\t\tthis.report = reporter.getReport();\n\t}\n\n\tprivate ConfigurationMetadataRepository loadRepository() {\n\t\ttry {\n\t\t\treturn loadRepository(ConfigurationMetadataRepositoryJsonBuilder.create());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to load metadata\", ex);\n\t\t}\n\t}\n\n\tprivate ConfigurationMetadataRepository loadRepository(ConfigurationMetadataRepositoryJsonBuilder builder)\n\t\t\tthrows IOException {\n\t\tResource[] resources = new PathMatchingResourcePatternResolver()\n\t\t\t.getResources(\"classpath*:/META-INF/spring-configuration-metadata.json\");\n\t\tfor (Resource resource : resources) {\n\t\t\ttry (InputStream inputStream = resource.getInputStream()) {\n\t\t\t\tbuilder.withJsonResource(inputStream);\n\t\t\t}\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\tprivate void logLegacyPropertiesReport() {\n\t\tif (this.report == null || this.reported) {\n\t\t\treturn;\n\t\t}\n\t\tString warningReport = this.report.getWarningReport();\n\t\tif (warningReport != null) {\n\t\t\tlogger.warn(warningReport);\n\t\t}\n\t\tString errorReport = this.report.getErrorReport();\n\t\tif (errorReport != null) {\n\t\t\tlogger.error(errorReport);\n\t\t}\n\t\tthis.reported = true;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/main/java/org/springframework/boot/context/properties/migrator/PropertiesMigrationReport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.migrator;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides a properties migration report.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass PropertiesMigrationReport {\n\n\tprivate final Map<String, LegacyProperties> content = new LinkedHashMap<>();\n\n\t/**\n\t * Return a report for all the properties that were automatically renamed. If no such\n\t * properties were found, return {@code null}.\n\t * @return a report with the configurations keys that should be renamed\n\t */\n\t@Nullable String getWarningReport() {\n\t\tMap<String, List<PropertyMigration>> content = getContent(LegacyProperties::getRenamed);\n\t\tif (content.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuilder report = new StringBuilder();\n\t\treport.append(String\n\t\t\t.format(\"%nThe use of configuration keys that have been renamed was found in the environment:%n%n\"));\n\t\tappend(report, content);\n\t\treport.append(String.format(\"%n\"));\n\t\treport.append(\"Each configuration key has been temporarily mapped to its \"\n\t\t\t\t+ \"replacement for your convenience. To silence this warning, please \"\n\t\t\t\t+ \"update your configuration to use the new keys.\");\n\t\treport.append(String.format(\"%n\"));\n\t\treturn report.toString();\n\t}\n\n\t/**\n\t * Return a report for all the properties that are no longer supported. If no such\n\t * properties were found, return {@code null}.\n\t * @return a report with the configurations keys that are no longer supported\n\t */\n\t@Nullable String getErrorReport() {\n\t\tMap<String, List<PropertyMigration>> content = getContent(LegacyProperties::getUnsupported);\n\t\tif (content.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuilder report = new StringBuilder();\n\t\treport.append(String\n\t\t\t.format(\"%nThe use of configuration keys that are no longer supported was found in the environment:%n%n\"));\n\t\tappend(report, content);\n\t\treport.append(String.format(\"%n\"));\n\t\treport.append(\"Please refer to the release notes or reference guide for potential alternatives.\");\n\t\treport.append(String.format(\"%n\"));\n\t\treturn report.toString();\n\t}\n\n\tprivate Map<String, List<PropertyMigration>> getContent(\n\t\t\tFunction<LegacyProperties, List<PropertyMigration>> extractor) {\n\t\treturn this.content.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((entry) -> !extractor.apply(entry.getValue()).isEmpty())\n\t\t\t.collect(\n\t\t\t\t\tCollectors.toMap(Map.Entry::getKey, (entry) -> new ArrayList<>(extractor.apply(entry.getValue()))));\n\t}\n\n\tprivate void append(StringBuilder report, Map<String, List<PropertyMigration>> content) {\n\t\tcontent.forEach((name, properties) -> {\n\t\t\treport.append(String.format(\"Property source '%s':%n\", name));\n\t\t\tproperties.sort(PropertyMigration.COMPARATOR);\n\t\t\tproperties.forEach((property) -> {\n\t\t\t\treport.append(String.format(\"\\tKey: %s%n\", property.getProperty().getName()));\n\t\t\t\tif (property.getLineNumber() != null) {\n\t\t\t\t\treport.append(String.format(\"\\t\\tLine: %d%n\", property.getLineNumber()));\n\t\t\t\t}\n\t\t\t\treport.append(String.format(\"\\t\\t%s%n\", property.determineReason()));\n\t\t\t});\n\t\t\treport.append(String.format(\"%n\"));\n\t\t});\n\t}\n\n\t/**\n\t * Register a new property source.\n\t * @param name the name of the property source\n\t * @param properties the {@link PropertyMigration} instances\n\t */\n\tvoid add(String name, List<PropertyMigration> properties) {\n\t\tthis.content.put(name, new LegacyProperties(properties));\n\t}\n\n\tprivate static class LegacyProperties {\n\n\t\tprivate final List<PropertyMigration> properties;\n\n\t\tLegacyProperties(List<PropertyMigration> properties) {\n\t\t\tthis.properties = new ArrayList<>(properties);\n\t\t}\n\n\t\tList<PropertyMigration> getRenamed() {\n\t\t\treturn this.properties.stream().filter(PropertyMigration::isCompatibleType).toList();\n\t\t}\n\n\t\tList<PropertyMigration> getUnsupported() {\n\t\t\treturn this.properties.stream().filter((property) -> !property.isCompatibleType()).toList();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/main/java/org/springframework/boot/context/properties/migrator/PropertiesMigrationReporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.migrator;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.IterableConfigurationPropertySource;\nimport org.springframework.boot.env.OriginTrackedMapPropertySource;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * Report on {@link PropertyMigration properties migration}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass PropertiesMigrationReporter {\n\n\tprivate final Map<String, ConfigurationMetadataProperty> allProperties;\n\n\tprivate final ConfigurableEnvironment environment;\n\n\tPropertiesMigrationReporter(ConfigurationMetadataRepository metadataRepository,\n\t\t\tConfigurableEnvironment environment) {\n\t\tthis.allProperties = Collections.unmodifiableMap(metadataRepository.getAllProperties());\n\t\tthis.environment = environment;\n\t}\n\n\t/**\n\t * Analyse the {@link ConfigurableEnvironment environment} and attempt to rename\n\t * legacy properties if a replacement exists.\n\t * @return a report of the migration\n\t */\n\tPropertiesMigrationReport getReport() {\n\t\tPropertiesMigrationReport report = new PropertiesMigrationReport();\n\t\tMap<String, List<PropertyMigration>> properties = getPropertySourceMigrations(\n\t\t\t\tConfigurationMetadataProperty::isDeprecated);\n\t\tif (properties.isEmpty()) {\n\t\t\treturn report;\n\t\t}\n\t\tproperties.forEach((name, candidates) -> {\n\t\t\tPropertySource<?> propertySource = mapPropertiesWithReplacement(report, name, candidates);\n\t\t\tif (propertySource != null) {\n\t\t\t\tthis.environment.getPropertySources().addBefore(name, propertySource);\n\t\t\t}\n\t\t});\n\t\treturn report;\n\t}\n\n\tprivate Map<String, List<PropertyMigration>> getPropertySourceMigrations(\n\t\t\tPredicate<ConfigurationMetadataProperty> filter) {\n\t\treturn getPropertySourceMigrations(this.allProperties.values().stream().filter(filter).toList());\n\t}\n\n\tprivate Map<String, List<PropertyMigration>> getPropertySourceMigrations(\n\t\t\tList<ConfigurationMetadataProperty> metadataProperties) {\n\t\tMultiValueMap<String, PropertyMigration> result = new LinkedMultiValueMap<>();\n\t\tgetPropertySourcesAsMap().forEach((propertySourceName, propertySource) -> {\n\t\t\tfor (ConfigurationMetadataProperty metadataProperty : metadataProperties) {\n\t\t\t\tresult.addAll(propertySourceName, getMigrations(propertySource, metadataProperty));\n\t\t\t}\n\t\t});\n\t\treturn result;\n\t}\n\n\tprivate Map<String, ConfigurationPropertySource> getPropertySourcesAsMap() {\n\t\tMap<String, ConfigurationPropertySource> map = new LinkedHashMap<>();\n\t\tfor (ConfigurationPropertySource source : ConfigurationPropertySources.get(this.environment)) {\n\t\t\tmap.put(determinePropertySourceName(source), source);\n\t\t}\n\t\treturn map;\n\t}\n\n\tprivate String determinePropertySourceName(ConfigurationPropertySource source) {\n\t\tif (source.getUnderlyingSource() instanceof PropertySource<?> underlyingSource) {\n\t\t\treturn underlyingSource.getName();\n\t\t}\n\t\tObject underlyingSource = source.getUnderlyingSource();\n\t\tAssert.state(underlyingSource != null, \"'underlyingSource' must not be null\");\n\t\treturn underlyingSource.toString();\n\t}\n\n\tprivate List<PropertyMigration> getMigrations(ConfigurationPropertySource propertySource,\n\t\t\tConfigurationMetadataProperty metadataProperty) {\n\t\tConfigurationPropertyName propertyName = asConfigurationPropertyName(metadataProperty);\n\t\tList<PropertyMigration> migrations = new ArrayList<>();\n\t\taddMigration(propertySource, metadataProperty, propertyName, false, migrations);\n\t\tif (isMapType(metadataProperty) && propertySource instanceof IterableConfigurationPropertySource iterable) {\n\t\t\titerable.stream()\n\t\t\t\t.filter(propertyName::isAncestorOf)\n\t\t\t\t.forEach((ancestorPropertyName) -> addMigration(propertySource, metadataProperty, ancestorPropertyName,\n\t\t\t\t\t\ttrue, migrations));\n\t\t}\n\t\treturn migrations;\n\t}\n\n\tprivate ConfigurationPropertyName asConfigurationPropertyName(ConfigurationMetadataProperty metadataProperty) {\n\t\treturn ConfigurationPropertyName.isValid(metadataProperty.getId())\n\t\t\t\t? ConfigurationPropertyName.of(metadataProperty.getId())\n\t\t\t\t: ConfigurationPropertyName.adapt(metadataProperty.getId(), '.');\n\t}\n\n\tprivate void addMigration(ConfigurationPropertySource propertySource,\n\t\t\tConfigurationMetadataProperty metadataProperty, ConfigurationPropertyName propertyName,\n\t\t\tboolean mapMigration, List<PropertyMigration> migrations) {\n\t\tConfigurationProperty property = propertySource.getConfigurationProperty(propertyName);\n\t\tif (property != null) {\n\t\t\tConfigurationMetadataProperty replacement = determineReplacementMetadata(metadataProperty);\n\t\t\tif (replacement == null || !hasSameName(property, replacement)) {\n\t\t\t\tmigrations.add(new PropertyMigration(property, metadataProperty, replacement, mapMigration));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean hasSameName(ConfigurationProperty property, ConfigurationMetadataProperty replacement) {\n\t\treturn (property.getOrigin() instanceof PropertySourceOrigin propertySourceOrigin)\n\t\t\t\t&& Objects.equals(propertySourceOrigin.getPropertyName(), replacement.getId());\n\t}\n\n\tprivate @Nullable ConfigurationMetadataProperty determineReplacementMetadata(\n\t\t\tConfigurationMetadataProperty metadata) {\n\t\tString replacementId = metadata.getDeprecation().getReplacement();\n\t\tif (StringUtils.hasText(replacementId)) {\n\t\t\tConfigurationMetadataProperty replacement = this.allProperties.get(replacementId);\n\t\t\tif (replacement != null) {\n\t\t\t\treturn replacement;\n\t\t\t}\n\t\t\treturn detectMapValueReplacement(replacementId);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable ConfigurationMetadataProperty detectMapValueReplacement(String fullId) {\n\t\tint lastDot = fullId.lastIndexOf('.');\n\t\tif (lastDot == -1) {\n\t\t\treturn null;\n\t\t}\n\t\tConfigurationMetadataProperty metadata = this.allProperties.get(fullId.substring(0, lastDot));\n\t\tif (metadata != null && isMapType(metadata)) {\n\t\t\treturn metadata;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isMapType(ConfigurationMetadataProperty property) {\n\t\tString type = property.getType();\n\t\treturn type != null && type.startsWith(Map.class.getName());\n\t}\n\n\tprivate @Nullable PropertySource<?> mapPropertiesWithReplacement(PropertiesMigrationReport report, String name,\n\t\t\tList<PropertyMigration> properties) {\n\t\treport.add(name, properties);\n\t\tList<PropertyMigration> renamed = properties.stream().filter(PropertyMigration::isCompatibleType).toList();\n\t\tif (renamed.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tNameTrackingPropertySource nameTrackingPropertySource = new NameTrackingPropertySource();\n\t\tthis.environment.getPropertySources().addFirst(nameTrackingPropertySource);\n\t\ttry {\n\t\t\tString target = \"migrate-\" + name;\n\t\t\tMap<String, OriginTrackedValue> content = new LinkedHashMap<>();\n\t\t\tfor (PropertyMigration candidate : renamed) {\n\t\t\t\tString newPropertyName = candidate.getNewPropertyName();\n\t\t\t\tObject value = candidate.getProperty().getValue();\n\t\t\t\tif (nameTrackingPropertySource.isPlaceholderThatAccessesName(value, newPropertyName)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tOriginTrackedValue originTrackedValue = OriginTrackedValue.of(value,\n\t\t\t\t\t\tcandidate.getProperty().getOrigin());\n\t\t\t\tcontent.put(newPropertyName, originTrackedValue);\n\t\t\t}\n\t\t\treturn new OriginTrackedMapPropertySource(target, content);\n\t\t}\n\t\tfinally {\n\t\t\tthis.environment.getPropertySources().remove(nameTrackingPropertySource.getName());\n\t\t}\n\t}\n\n\t/**\n\t * {@link PropertySource} used to track accessed properties to protect against\n\t * circular references.\n\t */\n\tprivate class NameTrackingPropertySource extends PropertySource<Object> {\n\n\t\tprivate final Set<String> accessedNames = new HashSet<>();\n\n\t\tNameTrackingPropertySource() {\n\t\t\tsuper(NameTrackingPropertySource.class.getName());\n\t\t}\n\n\t\tboolean isPlaceholderThatAccessesName(Object value, String name) {\n\t\t\tif (value instanceof String) {\n\t\t\t\tthis.accessedNames.clear();\n\t\t\t\tPropertiesMigrationReporter.this.environment.resolvePlaceholders((String) value);\n\t\t\t\treturn this.accessedNames.contains(name);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\tthis.accessedNames.add(name);\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/main/java/org/springframework/boot/context/properties/migrator/PropertyMigration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.migrator;\n\nimport java.time.Duration;\nimport java.util.Comparator;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\nimport org.springframework.boot.configurationmetadata.Deprecation;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Description of a property migration.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass PropertyMigration {\n\n\tpublic static final Comparator<PropertyMigration> COMPARATOR = Comparator\n\t\t.comparing((property) -> property.getMetadata().getId());\n\n\tprivate final ConfigurationProperty property;\n\n\tprivate final @Nullable Integer lineNumber;\n\n\tprivate final ConfigurationMetadataProperty metadata;\n\n\tprivate final @Nullable ConfigurationMetadataProperty replacementMetadata;\n\n\t/**\n\t * Whether this migration happened from a map type.\n\t */\n\tprivate final boolean mapMigration;\n\n\tprivate final boolean compatibleType;\n\n\tPropertyMigration(ConfigurationProperty property, ConfigurationMetadataProperty metadata,\n\t\t\t@Nullable ConfigurationMetadataProperty replacementMetadata, boolean mapMigration) {\n\t\tthis.property = property;\n\t\tthis.lineNumber = determineLineNumber(property);\n\t\tthis.metadata = metadata;\n\t\tthis.replacementMetadata = replacementMetadata;\n\t\tthis.mapMigration = mapMigration;\n\t\tthis.compatibleType = determineCompatibleType(metadata, replacementMetadata);\n\t}\n\n\tprivate static @Nullable Integer determineLineNumber(ConfigurationProperty property) {\n\t\tOrigin origin = property.getOrigin();\n\t\tif (origin instanceof PropertySourceOrigin propertySourceOrigin) {\n\t\t\torigin = propertySourceOrigin.getOrigin();\n\t\t}\n\t\tif (origin instanceof TextResourceOrigin textOrigin) {\n\t\t\tif (textOrigin.getLocation() != null) {\n\t\t\t\treturn textOrigin.getLocation().getLine() + 1;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static boolean determineCompatibleType(ConfigurationMetadataProperty metadata,\n\t\t\t@Nullable ConfigurationMetadataProperty replacementMetadata) {\n\t\tString currentType = determineType(metadata);\n\t\tString replacementType = determineType(replacementMetadata);\n\t\tif (currentType == null || replacementType == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (replacementType.equals(currentType)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn replacementType.equals(Duration.class.getName())\n\t\t\t\t&& (currentType.equals(Long.class.getName()) || currentType.equals(Integer.class.getName()));\n\t}\n\n\tprivate static @Nullable String determineType(@Nullable ConfigurationMetadataProperty metadata) {\n\t\tif (metadata == null || metadata.getType() == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString candidate = metadata.getType();\n\t\tif (candidate.startsWith(Map.class.getName())) {\n\t\t\tint lastComma = candidate.lastIndexOf(',');\n\t\t\tif (lastComma != -1) {\n\t\t\t\t// Use Map value type\n\t\t\t\treturn candidate.substring(lastComma + 1, candidate.length() - 1).trim();\n\t\t\t}\n\t\t}\n\t\treturn candidate;\n\t}\n\n\tConfigurationProperty getProperty() {\n\t\treturn this.property;\n\t}\n\n\t@Nullable Integer getLineNumber() {\n\t\treturn this.lineNumber;\n\t}\n\n\tConfigurationMetadataProperty getMetadata() {\n\t\treturn this.metadata;\n\t}\n\n\tboolean isCompatibleType() {\n\t\treturn this.compatibleType;\n\t}\n\n\tString getNewPropertyName() {\n\t\tif (this.mapMigration) {\n\t\t\tConfigurationMetadataProperty replacementMetadata = this.replacementMetadata;\n\t\t\tAssert.state(replacementMetadata != null, \"'replacementMetadata' must not be null\");\n\t\t\treturn getNewMapPropertyName(this.property, this.metadata, replacementMetadata).toString();\n\t\t}\n\t\treturn this.metadata.getDeprecation().getReplacement();\n\t}\n\n\tString determineReason() {\n\t\tif (this.compatibleType) {\n\t\t\treturn \"Replacement: \" + getNewPropertyName();\n\t\t}\n\t\tDeprecation deprecation = this.metadata.getDeprecation();\n\t\tif (StringUtils.hasText(deprecation.getShortReason())) {\n\t\t\treturn \"Reason: \" + deprecation.getShortReason();\n\t\t}\n\t\tif (StringUtils.hasText(deprecation.getReplacement())) {\n\t\t\tif (this.replacementMetadata != null) {\n\t\t\t\treturn String.format(\"Reason: Replacement key '%s' uses an incompatible target type\",\n\t\t\t\t\t\tdeprecation.getReplacement());\n\t\t\t}\n\t\t\treturn String.format(\"Reason: No metadata found for replacement key '%s'\", deprecation.getReplacement());\n\t\t}\n\t\treturn \"Reason: none\";\n\t}\n\n\tprivate static ConfigurationPropertyName getNewMapPropertyName(ConfigurationProperty property,\n\t\t\tConfigurationMetadataProperty metadata, ConfigurationMetadataProperty replacement) {\n\t\tConfigurationPropertyName oldName = property.getName();\n\t\tConfigurationPropertyName oldPrefix = ConfigurationPropertyName.of(metadata.getId());\n\t\tAssert.state(oldPrefix.isAncestorOf(oldName),\n\t\t\t\t() -> \"'%s' is not an ancestor of '%s'\".formatted(oldPrefix, oldName));\n\t\tConfigurationPropertyName newPrefix = ConfigurationPropertyName.of(replacement.getId());\n\t\treturn newPrefix.append(oldName.subName(oldPrefix.getNumberOfElements()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/main/java/org/springframework/boot/context/properties/migrator/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for migrating legacy Spring Boot properties.\n */\n@NullMarked\npackage org.springframework.boot.context.properties.migrator;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/main/resources/META-INF/spring.factories",
    "content": "# Application Listeners\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.context.properties.migrator.PropertiesMigrationListener\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/java/org/springframework/boot/context/properties/migrator/PropertiesMigrationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.migrator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesMigrationListener}.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass PropertiesMigrationListenerTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid sampleReport(CapturedOutput output) {\n\t\tthis.context = createSampleApplication().run(\"--logging.file=test.log\");\n\t\tassertThat(output).contains(\"commandLineArgs\")\n\t\t\t.contains(\"logging.file.name\")\n\t\t\t.contains(\"Each configuration key has been temporarily mapped\")\n\t\t\t.doesNotContain(\"Please refer to the release notes\");\n\t}\n\n\tprivate SpringApplication createSampleApplication() {\n\t\treturn new SpringApplication(TestApplication.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/java/org/springframework/boot/context/properties/migrator/PropertiesMigrationReporterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.properties.migrator;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;\nimport org.springframework.boot.configurationmetadata.SimpleConfigurationMetadataRepository;\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesMigrationReporter}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass PropertiesMigrationReporterTests {\n\n\tprivate final ConfigurableEnvironment environment = new MockEnvironment();\n\n\t@Test\n\tvoid reportIsNullWithNoMatchingKeys() {\n\t\tString report = createWarningReport(new SimpleConfigurationMetadataRepository());\n\t\tassertThat(report).isNull();\n\t}\n\n\t@Test\n\tvoid replacementKeysAreRemapped() throws IOException {\n\t\tMutablePropertySources propertySources = this.environment.getPropertySources();\n\t\tPropertySource<?> one = loadPropertySource(\"one\", \"config/config-error.properties\");\n\t\tPropertySource<?> two = loadPropertySource(\"two\", \"config/config-warnings.properties\");\n\t\tpropertySources.addFirst(one);\n\t\tpropertySources.addAfter(\"one\", two);\n\t\tassertThat(propertySources).hasSize(3);\n\t\tcreateAnalyzer(loadRepository(\"metadata/sample-metadata.json\")).getReport();\n\t\tassertThat(mapToNames(propertySources)).containsExactly(\"one\", \"migrate-two\", \"two\", \"mockProperties\");\n\t\tPropertySource<?> migrateTwo = propertySources.get(\"migrate-two\");\n\t\tassertThat(migrateTwo).isNotNull();\n\t\tassertMappedProperty(migrateTwo, \"test.two\", \"another\", getOrigin(two, \"wrong.two\"));\n\t\tassertMappedProperty(migrateTwo, \"custom.the-map-replacement.key\", \"value\",\n\t\t\t\tgetOrigin(two, \"custom.map-with-replacement.key\"));\n\t}\n\n\t@Test\n\tvoid warningReport() throws IOException {\n\t\tthis.environment.getPropertySources().addFirst(loadPropertySource(\"test\", \"config/config-warnings.properties\"));\n\t\tthis.environment.getPropertySources().addFirst(loadPropertySource(\"ignore\", \"config/config-error.properties\"));\n\t\tString report = createWarningReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).containsSubsequence(\"Property source 'test'\", \"Key: custom.map-with-replacement.key\",\n\t\t\t\t\"Line: 8\", \"Replacement: custom.the-map-replacement.key\", \"wrong.four.test\", \"Line: 5\",\n\t\t\t\t\"test.four.test\", \"wrong.two\", \"Line: 2\", \"test.two\");\n\t\tassertThat(report).doesNotContain(\"wrong.one\");\n\t}\n\n\t@Test\n\tvoid warningReportReplacedWithSameRelaxedName() throws IOException {\n\t\tthis.environment.getPropertySources().addFirst(loadPropertySource(\"test\", \"config/config-relaxed.properties\"));\n\t\tString report = createWarningReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNull();\n\t}\n\n\t@Test\n\tvoid errorReport() throws IOException {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(loadPropertySource(\"test1\", \"config/config-warnings.properties\"));\n\t\tthis.environment.getPropertySources().addFirst(loadPropertySource(\"test2\", \"config/config-error.properties\"));\n\t\tString report = createErrorReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).containsSubsequence(\"Property source 'test2'\", \"wrong.one\", \"Line: 2\",\n\t\t\t\t\"This is no longer supported.\");\n\t\tassertThat(report).doesNotContain(\"wrong.four.test\").doesNotContain(\"wrong.two\");\n\t}\n\n\t@Test\n\tvoid errorReportNoReplacement() throws IOException {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(loadPropertySource(\"first\", \"config/config-error-no-replacement.properties\"));\n\t\tthis.environment.getPropertySources().addFirst(loadPropertySource(\"second\", \"config/config-error.properties\"));\n\t\tString report = createErrorReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).containsSubsequence(\"Property source 'first'\", \"wrong.three\", \"Line: 6\", \"none\",\n\t\t\t\t\"Property source 'second'\", \"wrong.one\", \"Line: 2\", \"This is no longer supported.\");\n\t\tassertThat(report).doesNotContain(\"null\").doesNotContain(\"server.port\").doesNotContain(\"debug\");\n\t}\n\n\t@Test\n\tvoid durationTypeIsHandledTransparently() {\n\t\tMutablePropertySources propertySources = this.environment.getPropertySources();\n\t\tMap<String, Object> content = new LinkedHashMap<>();\n\t\tcontent.put(\"test.cache-seconds\", 50);\n\t\tcontent.put(\"test.time-to-live-ms\", 1234L);\n\t\tcontent.put(\"test.ttl\", 5678L);\n\t\tpropertySources.addFirst(new MapPropertySource(\"test\", content));\n\t\tassertThat(propertySources).hasSize(2);\n\t\tString report = createWarningReport(loadRepository(\"metadata/type-conversion-metadata.json\"));\n\t\tassertThat(report).contains(\"Property source 'test'\", \"test.cache-seconds\", \"test.cache\",\n\t\t\t\t\"test.time-to-live-ms\", \"test.time-to-live\", \"test.ttl\", \"test.mapped.ttl\");\n\t\tassertThat(mapToNames(propertySources)).containsExactly(\"migrate-test\", \"test\", \"mockProperties\");\n\t\tPropertySource<?> propertySource = propertySources.get(\"migrate-test\");\n\t\tassertThat(propertySource).isNotNull();\n\t\tassertMappedProperty(propertySource, \"test.cache\", 50, null);\n\t\tassertMappedProperty(propertySource, \"test.time-to-live\", 1234L, null);\n\t\tassertMappedProperty(propertySource, \"test.mapped.ttl\", 5678L, null);\n\t}\n\n\t@Test\n\tvoid reasonIsProvidedIfPropertyCouldNotBeRenamed() throws IOException {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(loadPropertySource(\"test\", \"config/config-error-no-compatible-type.properties\"));\n\t\tString report = createErrorReport(loadRepository(\"metadata/type-conversion-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).containsSubsequence(\"Property source 'test'\", \"wrong.inconvertible\", \"Line: 1\",\n\t\t\t\t\"Reason: Replacement key 'test.inconvertible' uses an incompatible target type\");\n\t}\n\n\t@Test\n\tvoid invalidReplacementHandled() throws IOException {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(loadPropertySource(\"first\", \"config/config-error-invalid-replacement.properties\"));\n\t\tString report = createErrorReport(loadRepository(\"metadata/sample-metadata-invalid-replacement.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).containsSubsequence(\"Property source 'first'\", \"deprecated.six.test\", \"Line: 1\", \"Reason\",\n\t\t\t\t\"No metadata found for replacement key 'does.not.exist'\");\n\t\tassertThat(report).doesNotContain(\"null\");\n\t}\n\n\t@Test\n\tvoid invalidNameHandledGracefully() {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"first\", Collections.singletonMap(\"invalid.property-name\", \"value\")));\n\t\tString report = createWarningReport(loadRepository(\"metadata/sample-metadata-invalid-name.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).contains(\"Key: invalid.propertyname\").contains(\"Replacement: valid.property-name\");\n\t}\n\n\t@Test\n\tvoid mapPropertiesDeprecatedNoReplacement() {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(\n\t\t\t\t\tnew MapPropertySource(\"first\", Collections.singletonMap(\"custom.map-no-replacement.key\", \"value\")));\n\t\tString report = createErrorReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).contains(\"Key: custom.map-no-replacement.key\")\n\t\t\t.contains(\"Reason: This is no longer supported.\");\n\t}\n\n\t@Test\n\tvoid mapPropertiesDeprecatedWithReplacement() {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"first\",\n\t\t\t\t\tCollections.singletonMap(\"custom.map-with-replacement.key\", \"value\")));\n\t\tString report = createWarningReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).contains(\"Key: custom.map-with-replacement.key\")\n\t\t\t.contains(\"Replacement: custom.the-map-replacement.key\");\n\t}\n\n\t@Test\n\tvoid mapPropertiesDeprecatedWithReplacementRelaxedBindingUnderscore() {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"first\",\n\t\t\t\t\tCollections.singletonMap(\"custom.map_with_replacement.key\", \"value\")));\n\t\tString report = createWarningReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).contains(\"Key: custom.mapwithreplacement.key\")\n\t\t\t.contains(\"Replacement: custom.the-map-replacement.key\");\n\t}\n\n\t@Test\n\tvoid mapPropertiesDeprecatedWithReplacementRelaxedBindingCamelCase() {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(\n\t\t\t\t\tnew MapPropertySource(\"first\", Collections.singletonMap(\"custom.MapWithReplacement.key\", \"value\")));\n\t\tString report = createWarningReport(loadRepository(\"metadata/sample-metadata.json\"));\n\t\tassertThat(report).isNotNull();\n\t\tassertThat(report).contains(\"Key: custom.mapwithreplacement.key\")\n\t\t\t.contains(\"Replacement: custom.the-map-replacement.key\");\n\t}\n\n\t@Test // gh-35919\n\tvoid directCircularReference() {\n\t\tthis.environment.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"backcompat\", Collections.singletonMap(\"wrong.two\", \"${test.two}\")));\n\t\tcreateAnalyzer(loadRepository(\"metadata/sample-metadata.json\")).getReport();\n\t\tassertThat(this.environment.getProperty(\"test.two\")).isNull();\n\t}\n\n\tprivate List<String> mapToNames(PropertySources sources) {\n\t\tList<String> names = new ArrayList<>();\n\t\tfor (PropertySource<?> source : sources) {\n\t\t\tnames.add(source.getName());\n\t\t}\n\t\treturn names;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate @Nullable Origin getOrigin(PropertySource<?> propertySource, String name) {\n\t\treturn ((OriginLookup<String>) propertySource).getOrigin(name);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void assertMappedProperty(PropertySource<?> propertySource, String name, Object value,\n\t\t\t@Nullable Origin origin) {\n\t\tassertThat(propertySource.containsProperty(name)).isTrue();\n\t\tassertThat(propertySource.getProperty(name)).isEqualTo(value);\n\t\tif (origin != null) {\n\t\t\tassertThat(propertySource).isInstanceOf(OriginLookup.class);\n\t\t\tOrigin actualOrigin = ((OriginLookup<Object>) propertySource).getOrigin(name);\n\t\t\tif (actualOrigin instanceof PropertySourceOrigin propertySourceOrigin) {\n\t\t\t\tactualOrigin = propertySourceOrigin.getOrigin();\n\t\t\t}\n\t\t\tassertThat(actualOrigin).isEqualTo(origin);\n\t\t}\n\t}\n\n\tprivate PropertySource<?> loadPropertySource(String name, String path) throws IOException {\n\t\tClassPathResource resource = new ClassPathResource(path);\n\t\tList<PropertySource<?>> propertySources = new PropertiesPropertySourceLoader().load(name, resource);\n\t\tassertThat(propertySources).isNotEmpty();\n\t\treturn propertySources.get(0);\n\t}\n\n\tprivate ConfigurationMetadataRepository loadRepository(String... content) {\n\t\ttry {\n\t\t\tConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create();\n\t\t\tfor (String path : content) {\n\t\t\t\tResource resource = new ClassPathResource(path);\n\t\t\t\tbuilder.withJsonResource(resource.getInputStream());\n\t\t\t}\n\t\t\treturn builder.build();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to load metadata\", ex);\n\t\t}\n\t}\n\n\tprivate @Nullable String createWarningReport(ConfigurationMetadataRepository repository) {\n\t\treturn createAnalyzer(repository).getReport().getWarningReport();\n\t}\n\n\tprivate @Nullable String createErrorReport(ConfigurationMetadataRepository repository) {\n\t\treturn createAnalyzer(repository).getReport().getErrorReport();\n\t}\n\n\tprivate PropertiesMigrationReporter createAnalyzer(ConfigurationMetadataRepository repository) {\n\t\treturn new PropertiesMigrationReporter(repository, this.environment);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/config/config-error-invalid-replacement.properties",
    "content": "deprecated.six.test=abc\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/config/config-error-no-compatible-type.properties",
    "content": "wrong.inconvertible=abc\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/config/config-error-no-replacement.properties",
    "content": "server.port=8080\n\ndebug=false\n\n\nwrong.three=invalid\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/config/config-error.properties",
    "content": "\nwrong.one=test\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/config/config-relaxed.properties",
    "content": "relaxed.this-that-the-other=test\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/config/config-warnings.properties",
    "content": "\nwrong.two=another\n\n\nwrong.four.test=value\n\n\ncustom.map-with-replacement.key=value\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/metadata/sample-metadata-invalid-name.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"invalid.PropertyName\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"valid.property-name\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"valid.property-name\",\n      \"type\": \"java.lang.String\"\n    }\n  ]\n}"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/metadata/sample-metadata-invalid-replacement.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"deprecated.six.test\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"does.not.exist\",\n        \"level\": \"error\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/metadata/sample-metadata.json",
    "content": "{\n  \"groups\": [\n    {\n      \"name\": \"relaxed\",\n      \"type\": \"com.example.SourceType\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"test.two\",\n      \"type\": \"java.lang.String\"\n    },\n    {\n      \"name\": \"test.four\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\"\n    },\n    {\n      \"name\": \"wrong.one\",\n      \"deprecation\": {\n        \"reason\": \"This is no longer supported.\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"wrong.two\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"test.two\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"wrong.three\",\n      \"deprecation\": {\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"wrong.four.test\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"test.four.test\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"custom.map-no-replacement\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"reason\": \"This is no longer supported.\"\n      }\n    },\n    {\n      \"name\": \"custom.map-with-replacement\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"replacement\": \"custom.the-map-replacement\"\n      }\n    },\n    {\n      \"name\": \"custom.the-map-replacement\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\"\n    },\n    {\n      \"name\": \"relaxed.thisthat-theother\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"relaxed.this-that-the-other\"\n      }\n    },\n    {\n      \"name\": \"relaxed.this-that-the-other\",\n      \"type\": \"java.lang.String\",\n      \"sourceType\": \"com.example.SourceType\"\n    }\n  ]\n}\n"
  },
  {
    "path": "core/spring-boot-properties-migrator/src/test/resources/metadata/type-conversion-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"test.cache\",\n      \"type\": \"java.time.Duration\"\n    },\n    {\n      \"name\": \"test.time-to-live\",\n      \"type\": \"java.time.Duration\"\n    },\n    {\n      \"name\": \"test.mapped\",\n      \"type\": \"java.util.Map<java.lang.String, java.time.Duration>\"\n    },\n    {\n      \"name\": \"test.inconvertible\",\n      \"type\": \"com.example.One\"\n    },\n    {\n      \"name\": \"test.cache-seconds\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"test.cache\"\n      }\n    },\n    {\n      \"name\": \"test.time-to-live-ms\",\n      \"type\": \"java.lang.Long\",\n      \"deprecation\": {\n        \"replacement\": \"test.time-to-live\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"test.ttl\",\n      \"type\": \"java.lang.Long\",\n      \"deprecation\": {\n        \"replacement\": \"test.mapped.ttl\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"wrong.inconvertible\",\n      \"type\": \"com.example.Two\",\n      \"deprecation\": {\n        \"replacement\": \"test.inconvertible\",\n        \"level\": \"error\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "core/spring-boot-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-test\")\n\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"com.google.code.gson:gson\")\n\toptional(\"com.jayway.jsonpath:json-path\")\n\toptional(\"jakarta.json.bind:jakarta.json.bind-api\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"junit:junit\")\n\toptional(\"io.projectreactor.netty:reactor-netty-http\")\n\toptional(\"org.assertj:assertj-core\")\n\toptional(\"org.hamcrest:hamcrest-core\")\n\toptional(\"org.hamcrest:hamcrest-library\")\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\toptional(\"org.mockito:mockito-core\")\n\toptional(\"org.seleniumhq.selenium:htmlunit3-driver\") {\n\t\texclude(group: \"com.sun.activation\", module: \"jakarta.activation\")\n\t}\n\toptional(\"org.seleniumhq.selenium:selenium-api\")\n\toptional(\"org.skyscreamer:jsonassert\")\n\toptional(\"org.springframework:spring-web\")\n\toptional(\"tools.jackson.core:jackson-databind\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"ch.qos.logback:logback-classic\")\n\ttestImplementation(\"com.google.code.gson:gson\")\n\ttestImplementation(\"org.eclipse:yasson\")\n\ttestImplementation(\"org.jetbrains.kotlin:kotlin-reflect\")\n\ttestImplementation(\"org.jetbrains.kotlin:kotlin-stdlib\")\n\ttestImplementation(\"org.slf4j:slf4j-api\")\n\ttestImplementation(\"org.spockframework:spock-core\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\ttestImplementation(\"org.testng:testng\")\n\n\ttestRuntimeOnly(\"org.aspectj:aspectjrt\")\n\ttestRuntimeOnly(\"org.aspectj:aspectjweaver\")\n\ttestRuntimeOnly(\"org.junit.vintage:junit-vintage-engine\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotatedClassFinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Utility class to find a class annotated with a particular annotation in a hierarchy.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Stephane Nicoll\n * @since 2.1.0\n */\npublic final class AnnotatedClassFinder {\n\n\tprivate static final Map<String, @Nullable Class<?>> cache = Collections.synchronizedMap(new Cache(40));\n\n\tprivate final Class<? extends Annotation> annotationType;\n\n\tprivate final ClassPathScanningCandidateComponentProvider scanner;\n\n\t/**\n\t * Create a new instance with the {@code annotationType} to find.\n\t * @param annotationType the annotation to find\n\t */\n\tpublic AnnotatedClassFinder(Class<? extends Annotation> annotationType) {\n\t\tAssert.notNull(annotationType, \"'annotationType' must not be null\");\n\t\tthis.annotationType = annotationType;\n\t\tthis.scanner = new ClassPathScanningCandidateComponentProvider(false);\n\t\tthis.scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));\n\t\tthis.scanner.setResourcePattern(\"*.class\");\n\t}\n\n\t/**\n\t * Find the first {@link Class} that is annotated with the target annotation, starting\n\t * from the package defined by the given {@code source} up to the root.\n\t * @param source the source class to use to initiate the search\n\t * @return the first {@link Class} annotated with the target annotation within the\n\t * hierarchy defined by the given {@code source} or {@code null} if none is found.\n\t */\n\tpublic @Nullable Class<?> findFromClass(Class<?> source) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\treturn findFromPackage(ClassUtils.getPackageName(source));\n\t}\n\n\t/**\n\t * Find the first {@link Class} that is annotated with the target annotation, starting\n\t * from the package defined by the given {@code source} up to the root.\n\t * @param source the source package to use to initiate the search\n\t * @return the first {@link Class} annotated with the target annotation within the\n\t * hierarchy defined by the given {@code source} or {@code null} if none is found.\n\t */\n\tpublic @Nullable Class<?> findFromPackage(String source) {\n\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\tClass<?> configuration = cache.get(source);\n\t\tif (configuration == null) {\n\t\t\tconfiguration = scanPackage(source);\n\t\t\tcache.put(source, configuration);\n\t\t}\n\t\treturn configuration;\n\t}\n\n\tprivate @Nullable Class<?> scanPackage(String source) {\n\t\twhile (!source.isEmpty()) {\n\t\t\tSet<BeanDefinition> components = this.scanner.findCandidateComponents(source);\n\t\t\tif (!components.isEmpty()) {\n\t\t\t\tAssert.state(components.size() == 1, () -> \"Found multiple @\" + this.annotationType.getSimpleName()\n\t\t\t\t\t\t+ \" annotated classes \" + components);\n\t\t\t\tString beanClassName = components.iterator().next().getBeanClassName();\n\t\t\t\tAssert.state(beanClassName != null, \"'beanClassName' must not be null\");\n\t\t\t\treturn ClassUtils.resolveClassName(beanClassName, null);\n\t\t\t}\n\t\t\tsource = getParentPackage(source);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String getParentPackage(String sourcePackage) {\n\t\tint lastDot = sourcePackage.lastIndexOf('.');\n\t\treturn (lastDot != -1) ? sourcePackage.substring(0, lastDot) : \"\";\n\t}\n\n\t/**\n\t * Cache implementation based on {@link LinkedHashMap}.\n\t */\n\tprivate static class Cache extends LinkedHashMap<String, @Nullable Class<?>> {\n\n\t\tprivate final int maxSize;\n\n\t\tCache(int maxSize) {\n\t\t\tsuper(16, 0.75f, true);\n\t\t\tthis.maxSize = maxSize;\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean removeEldestEntry(Map.Entry<String, @Nullable Class<?>> eldest) {\n\t\t\treturn size() > this.maxSize;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/AnnotationsPropertySource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.context.PropertyMapping.Skip;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotationPredicates;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.test.context.TestContextAnnotationUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnumerablePropertySource} to adapt annotations marked with\n * {@link PropertyMapping @PropertyMapping}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass AnnotationsPropertySource extends EnumerablePropertySource<Class<?>> {\n\n\tprivate static final Pattern CAMEL_CASE_PATTERN = Pattern.compile(\"([^A-Z-])([A-Z])\");\n\n\tprivate final Map<String, Object> properties;\n\n\tAnnotationsPropertySource(Class<?> source) {\n\t\tthis(\"Annotations\", source);\n\t}\n\n\tAnnotationsPropertySource(String name, Class<?> source) {\n\t\tsuper(name, source);\n\t\tthis.properties = getProperties(source);\n\t}\n\n\tprivate Map<String, Object> getProperties(Class<?> source) {\n\t\tMap<String, Object> properties = new LinkedHashMap<>();\n\t\tgetProperties(source, properties);\n\t\treturn properties;\n\t}\n\n\tprivate void getProperties(Class<?> source, Map<String, Object> properties) {\n\t\tMergedAnnotations.from(source, SearchStrategy.SUPERCLASS)\n\t\t\t.stream()\n\t\t\t.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getType))\n\t\t\t.forEach((annotation) -> {\n\t\t\t\tClass<Annotation> type = annotation.getType();\n\t\t\t\tMergedAnnotation<?> typeMapping = MergedAnnotations.from(type)\n\t\t\t\t\t.get(PropertyMapping.class, MergedAnnotation::isDirectlyPresent);\n\t\t\t\tString prefix = typeMapping.getValue(MergedAnnotation.VALUE, String.class).orElse(\"\");\n\t\t\t\tSkip defaultSkip = typeMapping.getValue(\"skip\", Skip.class).orElse(Skip.YES);\n\t\t\t\tfor (Method attribute : type.getDeclaredMethods()) {\n\t\t\t\t\tcollectProperties(prefix, defaultSkip, annotation, attribute, properties);\n\t\t\t\t}\n\t\t\t});\n\t\tif (TestContextAnnotationUtils.searchEnclosingClass(source)) {\n\t\t\tgetProperties(source.getEnclosingClass(), properties);\n\t\t}\n\t}\n\n\tprivate void collectProperties(String prefix, Skip skip, MergedAnnotation<?> annotation, Method attribute,\n\t\t\tMap<String, Object> properties) {\n\t\tMergedAnnotation<?> attributeMapping = MergedAnnotations.from(attribute).get(PropertyMapping.class);\n\t\tskip = attributeMapping.getValue(\"skip\", Skip.class).orElse(skip);\n\t\tif (skip == Skip.YES) {\n\t\t\treturn;\n\t\t}\n\t\tOptional<Object> value = annotation.getValue(attribute.getName());\n\t\tif (value.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tif (skip == Skip.ON_DEFAULT_VALUE) {\n\t\t\tif (ObjectUtils.nullSafeEquals(value.get(), annotation.getDefaultValue(attribute.getName()).orElse(null))) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tString name = getName(prefix, attributeMapping, attribute);\n\t\tputProperties(name, skip, value.get(), properties);\n\t}\n\n\tprivate String getName(String prefix, MergedAnnotation<?> attributeMapping, Method attribute) {\n\t\tString name = attributeMapping.getValue(MergedAnnotation.VALUE, String.class).orElse(\"\");\n\t\tif (!StringUtils.hasText(name)) {\n\t\t\tname = toKebabCase(attribute.getName());\n\t\t}\n\t\treturn dotAppend(prefix, name);\n\t}\n\n\tprivate String toKebabCase(String name) {\n\t\tMatcher matcher = CAMEL_CASE_PATTERN.matcher(name);\n\t\tStringBuilder result = new StringBuilder();\n\t\twhile (matcher.find()) {\n\t\t\tmatcher.appendReplacement(result, matcher.group(1) + '-' + StringUtils.uncapitalize(matcher.group(2)));\n\t\t}\n\t\tmatcher.appendTail(result);\n\t\treturn result.toString().toLowerCase(Locale.ENGLISH);\n\t}\n\n\tprivate String dotAppend(String prefix, String postfix) {\n\t\tif (StringUtils.hasText(prefix)) {\n\t\t\treturn prefix.endsWith(\".\") ? prefix + postfix : prefix + \".\" + postfix;\n\t\t}\n\t\treturn postfix;\n\t}\n\n\tprivate void putProperties(String name, Skip defaultSkip, Object value, Map<String, Object> properties) {\n\t\tif (ObjectUtils.isArray(value)) {\n\t\t\tObject[] array = ObjectUtils.toObjectArray(value);\n\t\t\tfor (int i = 0; i < array.length; i++) {\n\t\t\t\tputProperties(name + \"[\" + i + \"]\", defaultSkip, array[i], properties);\n\t\t\t}\n\t\t}\n\t\telse if (value instanceof MergedAnnotation<?> annotation) {\n\t\t\tfor (Method attribute : annotation.getType().getDeclaredMethods()) {\n\t\t\t\tcollectProperties(name, defaultSkip, annotation, attribute, properties);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tproperties.put(name, value);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean containsProperty(String name) {\n\t\treturn this.properties.containsKey(name);\n\t}\n\n\t@Override\n\tpublic @Nullable Object getProperty(String name) {\n\t\treturn this.properties.get(name);\n\t}\n\n\t@Override\n\tpublic String[] getPropertyNames() {\n\t\treturn StringUtils.toStringArray(this.properties.keySet());\n\t}\n\n\tboolean isEmpty() {\n\t\treturn this.properties.isEmpty();\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.properties.equals(((AnnotationsPropertySource) obj).properties);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.properties.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/ConfigDataApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.config.ConfigData;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;\nimport org.springframework.boot.env.DefaultPropertiesPropertySource;\nimport org.springframework.boot.env.RandomValuePropertySource;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.test.context.ContextConfiguration;\n\n/**\n * {@link ApplicationContextInitializer} that can be used with the\n * {@link ContextConfiguration#initializers()} to trigger loading of {@link ConfigData}\n * such as {@literal application.properties}.\n *\n * @author Phillip Webb\n * @since 2.4.0\n * @see ConfigDataEnvironmentPostProcessor\n */\npublic class ConfigDataApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tConfigurableEnvironment environment = applicationContext.getEnvironment();\n\t\tRandomValuePropertySource.addToEnvironment(environment);\n\t\tDefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\t\tConfigDataEnvironmentPostProcessor.applyTo(environment, applicationContext, bootstrapContext);\n\t\tbootstrapContext.close(applicationContext);\n\t\tDefaultPropertiesPropertySource.moveToEnd(environment);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/FilteredClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.security.ProtectionDomain;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.SmartClassLoader;\nimport org.springframework.core.io.ClassPathResource;\n\n/**\n * Test {@link URLClassLoader} that can filter the classes and resources it can load.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Roy Jacobs\n * @since 2.0.0\n */\npublic class FilteredClassLoader extends URLClassLoader implements SmartClassLoader {\n\n\tprivate final Collection<Predicate<String>> classesFilters;\n\n\tprivate final Collection<Predicate<String>> resourcesFilters;\n\n\t/**\n\t * Create a {@link FilteredClassLoader} that hides the given classes.\n\t * @param hiddenClasses the classes to hide\n\t */\n\tpublic FilteredClassLoader(Class<?>... hiddenClasses) {\n\t\tthis(Collections.singleton(ClassFilter.of(hiddenClasses)), Collections.emptyList());\n\t}\n\n\t/**\n\t * Create a {@link FilteredClassLoader} with the given {@code parent} that hides the\n\t * given classes.\n\t * @param parent the parent class loader\n\t * @param hiddenClasses the classes to hide\n\t */\n\tpublic FilteredClassLoader(ClassLoader parent, Class<?>... hiddenClasses) {\n\t\tthis(parent, Collections.singleton(ClassFilter.of(hiddenClasses)), Collections.emptyList());\n\t}\n\n\t/**\n\t * Create a {@link FilteredClassLoader} that hides classes from the given packages.\n\t * @param hiddenPackages the packages to hide\n\t */\n\tpublic FilteredClassLoader(String... hiddenPackages) {\n\t\tthis(Collections.singleton(PackageFilter.of(hiddenPackages)), Collections.emptyList());\n\t}\n\n\t/**\n\t * Create a {@link FilteredClassLoader} that hides resources from the given\n\t * {@link ClassPathResource classpath resources}.\n\t * @param hiddenResources the resources to hide\n\t * @since 2.1.0\n\t */\n\tpublic FilteredClassLoader(ClassPathResource... hiddenResources) {\n\t\tthis(Collections.emptyList(), Collections.singleton(ClassPathResourceFilter.of(hiddenResources)));\n\t}\n\n\t/**\n\t * Create a {@link FilteredClassLoader} that filters based on the given predicate.\n\t * @param filters a set of filters to determine when a class name or resource should\n\t * be hidden. A {@link Predicate#test(Object) result} of {@code true} indicates a\n\t * filtered class or resource. The input of the predicate can either be the binary\n\t * name of a class or a resource name.\n\t */\n\t@SafeVarargs\n\t@SuppressWarnings(\"varargs\")\n\tpublic FilteredClassLoader(Predicate<String>... filters) {\n\t\tthis(Arrays.asList(filters), Arrays.asList(filters));\n\t}\n\n\tprivate FilteredClassLoader(Collection<Predicate<String>> classesFilters,\n\t\t\tCollection<Predicate<String>> resourcesFilters) {\n\t\tthis(FilteredClassLoader.class.getClassLoader(), classesFilters, resourcesFilters);\n\t}\n\n\tprivate FilteredClassLoader(ClassLoader parent, Collection<Predicate<String>> classesFilters,\n\t\t\tCollection<Predicate<String>> resourcesFilters) {\n\t\tsuper(new URL[0], parent);\n\t\tthis.classesFilters = classesFilters;\n\t\tthis.resourcesFilters = resourcesFilters;\n\t}\n\n\t@Override\n\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\tfor (Predicate<String> filter : this.classesFilters) {\n\t\t\tif (filter.test(name)) {\n\t\t\t\tthrow new ClassNotFoundException();\n\t\t\t}\n\t\t}\n\t\treturn super.loadClass(name, resolve);\n\t}\n\n\t@Override\n\tpublic @Nullable URL getResource(String name) {\n\t\tfor (Predicate<String> filter : this.resourcesFilters) {\n\t\t\tif (filter.test(name)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn super.getResource(name);\n\t}\n\n\t@Override\n\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\tfor (Predicate<String> filter : this.resourcesFilters) {\n\t\t\tif (filter.test(name)) {\n\t\t\t\treturn Collections.emptyEnumeration();\n\t\t\t}\n\t\t}\n\t\treturn super.getResources(name);\n\t}\n\n\t@Override\n\tpublic @Nullable InputStream getResourceAsStream(String name) {\n\t\tfor (Predicate<String> filter : this.resourcesFilters) {\n\t\t\tif (filter.test(name)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn super.getResourceAsStream(name);\n\t}\n\n\t@Override\n\tpublic Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) {\n\t\tfor (Predicate<String> filter : this.classesFilters) {\n\t\t\tif (filter.test(name)) {\n\t\t\t\tthrow new IllegalArgumentException(String.format(\"Defining class with name %s is not supported\", name));\n\t\t\t}\n\t\t}\n\t\treturn defineClass(name, b, 0, b.length, protectionDomain);\n\t}\n\n\t/**\n\t * Filter to restrict the classes that can be loaded.\n\t */\n\tpublic static final class ClassFilter implements Predicate<String> {\n\n\t\tprivate final Class<?>[] hiddenClasses;\n\n\t\tprivate ClassFilter(Class<?>[] hiddenClasses) {\n\t\t\tthis.hiddenClasses = hiddenClasses;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean test(String className) {\n\t\t\tfor (Class<?> hiddenClass : this.hiddenClasses) {\n\t\t\t\tif (className.equals(hiddenClass.getName())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static ClassFilter of(Class<?>... hiddenClasses) {\n\t\t\treturn new ClassFilter(hiddenClasses);\n\t\t}\n\n\t}\n\n\t/**\n\t * Filter to restrict the packages that can be loaded.\n\t */\n\tpublic static final class PackageFilter implements Predicate<String> {\n\n\t\tprivate final String[] hiddenPackages;\n\n\t\tprivate PackageFilter(String[] hiddenPackages) {\n\t\t\tthis.hiddenPackages = hiddenPackages;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean test(String className) {\n\t\t\tfor (String hiddenPackage : this.hiddenPackages) {\n\t\t\t\tif (className.startsWith(hiddenPackage)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static PackageFilter of(String... hiddenPackages) {\n\t\t\treturn new PackageFilter(hiddenPackages);\n\t\t}\n\n\t}\n\n\t/**\n\t * Filter to restrict the resources that can be loaded.\n\t *\n\t * @since 2.1.0\n\t */\n\tpublic static final class ClassPathResourceFilter implements Predicate<String> {\n\n\t\tprivate final ClassPathResource[] hiddenResources;\n\n\t\tprivate ClassPathResourceFilter(ClassPathResource[] hiddenResources) {\n\t\t\tthis.hiddenResources = hiddenResources;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean test(String resourceName) {\n\t\t\tfor (ClassPathResource hiddenResource : this.hiddenResources) {\n\t\t\t\tif (hiddenResource.getFilename() != null && resourceName.equals(hiddenResource.getPath())) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic static ClassPathResourceFilter of(ClassPathResource... hiddenResources) {\n\t\t\treturn new ClassPathResourceFilter(hiddenResources);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/ImportsContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Constructor;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.boot.context.annotation.DeterminableImports;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AnnotationFilter;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link ContextCustomizer} to allow {@code @Import} annotations to be used directly on\n * test classes.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Laurent Martelli\n * @see ImportsContextCustomizerFactory\n */\nclass ImportsContextCustomizer implements ContextCustomizer {\n\n\tprivate static final String TEST_CLASS_NAME_ATTRIBUTE = \"testClassName\";\n\n\tprivate final String testClassName;\n\n\tprivate final ContextCustomizerKey key;\n\n\tImportsContextCustomizer(Class<?> testClass) {\n\t\tthis.testClassName = testClass.getName();\n\t\tthis.key = new ContextCustomizerKey(testClass);\n\t}\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context,\n\t\t\tMergedContextConfiguration mergedContextConfiguration) {\n\t\tBeanDefinitionRegistry registry = getBeanDefinitionRegistry(context);\n\t\tAnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);\n\t\tregisterCleanupPostProcessor(registry, reader);\n\t\tregisterImportsConfiguration(registry, reader);\n\t}\n\n\tprivate void registerCleanupPostProcessor(BeanDefinitionRegistry registry, AnnotatedBeanDefinitionReader reader) {\n\t\tBeanDefinition definition = registerBean(registry, reader, ImportsCleanupPostProcessor.BEAN_NAME,\n\t\t\t\tImportsCleanupPostProcessor.class);\n\t\tdefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\t\tdefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, this.testClassName);\n\t}\n\n\tprivate void registerImportsConfiguration(BeanDefinitionRegistry registry, AnnotatedBeanDefinitionReader reader) {\n\t\tBeanDefinition definition = registerBean(registry, reader, ImportsConfiguration.BEAN_NAME,\n\t\t\t\tImportsConfiguration.class);\n\t\tdefinition.setAttribute(TEST_CLASS_NAME_ATTRIBUTE, this.testClassName);\n\t}\n\n\tprivate BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {\n\t\tif (context instanceof BeanDefinitionRegistry beanDefinitionRegistry) {\n\t\t\treturn beanDefinitionRegistry;\n\t\t}\n\t\tif (context instanceof AbstractApplicationContext abstractContext) {\n\t\t\treturn (BeanDefinitionRegistry) abstractContext.getBeanFactory();\n\t\t}\n\t\tthrow new IllegalStateException(\"Could not locate BeanDefinitionRegistry\");\n\t}\n\n\tprivate BeanDefinition registerBean(BeanDefinitionRegistry registry, AnnotatedBeanDefinitionReader reader,\n\t\t\tString beanName, Class<?> type) {\n\t\treader.registerBean(type, beanName);\n\t\treturn registry.getBeanDefinition(beanName);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\t// ImportSelectors are flexible so the only safe cache key is the test class\n\t\tImportsContextCustomizer other = (ImportsContextCustomizer) obj;\n\t\treturn this.key.equals(other.key);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.key.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new ToStringCreator(this).append(\"key\", this.key).toString();\n\t}\n\n\t/**\n\t * {@link Configuration @Configuration} registered to trigger the\n\t * {@link ImportsSelector}.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ImportsSelector.class)\n\tstatic class ImportsConfiguration {\n\n\t\tstatic final String BEAN_NAME = ImportsConfiguration.class.getName();\n\n\t}\n\n\t/**\n\t * {@link ImportSelector} that returns the original test class so that direct\n\t * {@code @Import} annotations are processed.\n\t */\n\tstatic class ImportsSelector implements ImportSelector, BeanFactoryAware {\n\n\t\tprivate static final String[] NO_IMPORTS = {};\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ConfigurableListableBeanFactory beanFactory;\n\n\t\t@Override\n\t\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\t\tthis.beanFactory = (ConfigurableListableBeanFactory) beanFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\tBeanDefinition definition = this.beanFactory.getBeanDefinition(ImportsConfiguration.BEAN_NAME);\n\t\t\tObject testClassName = definition.getAttribute(TEST_CLASS_NAME_ATTRIBUTE);\n\t\t\treturn (testClassName != null) ? new String[] { (String) testClassName } : NO_IMPORTS;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link BeanDefinitionRegistryPostProcessor} to cleanup temporary configuration\n\t * added to load imports.\n\t */\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class ImportsCleanupPostProcessor implements BeanDefinitionRegistryPostProcessor {\n\n\t\tstatic final String BEAN_NAME = ImportsCleanupPostProcessor.class.getName();\n\n\t\tprivate final String testClassName;\n\n\t\tImportsCleanupPostProcessor(String testClassName) {\n\t\t\tthis.testClassName = testClassName;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n\t\t\ttry {\n\t\t\t\tString[] names = registry.getBeanDefinitionNames();\n\t\t\t\tfor (String name : names) {\n\t\t\t\t\tBeanDefinition definition = registry.getBeanDefinition(name);\n\t\t\t\t\tif (this.testClassName.equals(definition.getBeanClassName())) {\n\t\t\t\t\t\tregistry.removeBeanDefinition(name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tregistry.removeBeanDefinition(ImportsConfiguration.BEAN_NAME);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * The key used to ensure correct application context caching. Keys are generated\n\t * based on <em>all</em> the annotations used with the test that aren't core Java or\n\t * Kotlin annotations. We must use something broader than just {@link Import @Import}\n\t * annotations since an {@code @Import} may use an {@link ImportSelector} which could\n\t * make decisions based on anything available from {@link AnnotationMetadata}.\n\t */\n\tstatic class ContextCustomizerKey {\n\n\t\tprivate static final Set<AnnotationFilter> ANNOTATION_FILTERS;\n\t\tstatic {\n\t\t\tSet<AnnotationFilter> annotationFilters = new LinkedHashSet<>();\n\t\t\tannotationFilters.add(AnnotationFilter.PLAIN);\n\t\t\tannotationFilters.add(\"kotlin.Metadata\"::equals);\n\t\t\tannotationFilters.add(AnnotationFilter.packages(\"kotlin.annotation\"));\n\t\t\tannotationFilters.add(AnnotationFilter.packages(\"org.spockframework\", \"spock\"));\n\t\t\tannotationFilters.add(AnnotationFilter.packages(\"org.junit\"));\n\t\t\tANNOTATION_FILTERS = Collections.unmodifiableSet(annotationFilters);\n\t\t}\n\t\tprivate final Set<Object> key;\n\n\t\tContextCustomizerKey(Class<?> testClass) {\n\t\t\tMergedAnnotations annotations = MergedAnnotations.search(MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.withAnnotationFilter(this::isFilteredAnnotation)\n\t\t\t\t.from(testClass);\n\t\t\tSet<Object> determinedImports = determineImports(annotations, testClass);\n\t\t\tif (determinedImports == null) {\n\t\t\t\tthis.key = Collections.unmodifiableSet(synthesize(annotations));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSet<Object> key = new HashSet<>(determinedImports);\n\t\t\t\tSet<Annotation> componentScanning = annotations.stream()\n\t\t\t\t\t.filter((annotation) -> annotation.getType().equals(ComponentScan.class))\n\t\t\t\t\t.map(MergedAnnotation::synthesize)\n\t\t\t\t\t.collect(Collectors.toSet());\n\t\t\t\tkey.addAll(componentScanning);\n\t\t\t\tthis.key = Collections.unmodifiableSet(key);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isFilteredAnnotation(String typeName) {\n\t\t\treturn ANNOTATION_FILTERS.stream().anyMatch((filter) -> filter.matches(typeName));\n\t\t}\n\n\t\tprivate @Nullable Set<Object> determineImports(MergedAnnotations annotations, Class<?> testClass) {\n\t\t\tSet<Object> determinedImports = new LinkedHashSet<>();\n\t\t\tAnnotationMetadata metadata = AnnotationMetadata.introspect(testClass);\n\t\t\tfor (MergedAnnotation<Import> annotation : annotations.stream(Import.class).toList()) {\n\t\t\t\tfor (Class<?> source : annotation.getClassArray(MergedAnnotation.VALUE)) {\n\t\t\t\t\tSet<Object> determinedSourceImports = determineImports(source, metadata);\n\t\t\t\t\tif (determinedSourceImports == null) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tdeterminedImports.addAll(determinedSourceImports);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn determinedImports;\n\t\t}\n\n\t\tprivate @Nullable Set<Object> determineImports(Class<?> source, AnnotationMetadata metadata) {\n\t\t\tif (DeterminableImports.class.isAssignableFrom(source)) {\n\t\t\t\t// We can determine the imports\n\t\t\t\treturn ((DeterminableImports) instantiate(source)).determineImports(metadata);\n\t\t\t}\n\t\t\tif (ImportSelector.class.isAssignableFrom(source)\n\t\t\t\t\t|| ImportBeanDefinitionRegistrar.class.isAssignableFrom(source)) {\n\t\t\t\t// Standard ImportSelector and ImportBeanDefinitionRegistrar could\n\t\t\t\t// use anything to determine the imports so we can't be sure\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// The source itself is the import\n\t\t\treturn Collections.singleton(source.getName());\n\t\t}\n\n\t\tprivate Set<Object> synthesize(MergedAnnotations annotations) {\n\t\t\treturn annotations.stream().map(MergedAnnotation::synthesize).collect(Collectors.toSet());\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate <T> T instantiate(Class<T> source) {\n\t\t\ttry {\n\t\t\t\tConstructor<?> constructor = source.getDeclaredConstructor();\n\t\t\t\tReflectionUtils.makeAccessible(constructor);\n\t\t\t\treturn (T) constructor.newInstance();\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to instantiate DeterminableImportSelector \" + source.getName(),\n\t\t\t\t\t\tex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\treturn (obj != null && getClass() == obj.getClass() && this.key.equals(((ContextCustomizerKey) obj).key));\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.key.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.key.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/ImportsContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.TestContextAnnotationUtils;\nimport org.springframework.test.context.TestContextAnnotationUtils.AnnotationDescriptor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link ContextCustomizerFactory} to allow {@code @Import} annotations to be used\n * directly on test classes.\n *\n * @author Phillip Webb\n * @see ImportsContextCustomizer\n */\nclass ImportsContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn null;\n\t\t}\n\t\tAnnotationDescriptor<Import> descriptor = TestContextAnnotationUtils.findAnnotationDescriptor(testClass,\n\t\t\t\tImport.class);\n\t\tif (descriptor != null) {\n\t\t\tassertHasNoBeanMethods(descriptor.getRootDeclaringClass());\n\t\t\treturn new ImportsContextCustomizer(descriptor.getRootDeclaringClass());\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void assertHasNoBeanMethods(Class<?> testClass) {\n\t\tReflectionUtils.doWithMethods(testClass, this::assertHasNoBeanMethods);\n\t}\n\n\tprivate void assertHasNoBeanMethods(Method method) {\n\t\tAssert.state(!MergedAnnotations.from(method).isPresent(Bean.class),\n\t\t\t\t\"Test classes cannot include @Bean methods\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/PropertyMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.test.context.TestPropertySource;\n\n/**\n * Indicates that attributes from a test annotation should be mapped into a\n * {@link PropertySource @PropertySource}. Can be used at the type level, or on individual\n * attributes. For example, the following annotation declaration: <pre class=\"code\">\n * &#064;Retention(RUNTIME)\n * &#064;PropertyMapping(\"my.example\")\n * public &#064;interface Example {\n *\n *   String name();\n *\n * }\n * </pre> When used on a test class as follows: <pre class=\"code\">\n * &#064;Example(name=\"Spring\")\n * public class MyTest {\n * }\n * </pre> will result in a {@literal my.example.name} property being added with the value\n * {@literal \"Spring\"}.\n * <p>\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see AnnotationsPropertySource\n * @see TestPropertySource\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\npublic @interface PropertyMapping {\n\n\t/**\n\t * Defines the property mapping. When used at the type-level, this value will be used\n\t * as a prefix for all mapped attributes. When used on an attribute, the value\n\t * overrides the generated (kebab case) name.\n\t * @return the property mapping\n\t */\n\tString value() default \"\";\n\n\t/**\n\t * Determines if mapping should be skipped. When specified at the type-level indicates\n\t * if skipping should occur by default or not. When used at the attribute-level,\n\t * overrides the type-level default.\n\t * @return if mapping should be skipped\n\t */\n\tSkip skip() default Skip.NO;\n\n\t/**\n\t * Controls when mapping is skipped.\n\t */\n\tenum Skip {\n\n\t\t/**\n\t\t * Skip mapping the property.\n\t\t */\n\t\tYES,\n\n\t\t/**\n\t\t * Skip mapping the property when the default attribute value is specified.\n\t\t */\n\t\tON_DEFAULT_VALUE,\n\n\t\t/**\n\t\t * Don't skip mapping the property.\n\t\t */\n\t\tNO\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/PropertyMappingContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.stereotype.Component;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ContextCustomizer} to map annotation attributes to {@link Environment}\n * properties.\n *\n * @author Phillip Webb\n */\nclass PropertyMappingContextCustomizer implements ContextCustomizer {\n\n\tprivate final AnnotationsPropertySource propertySource;\n\n\tPropertyMappingContextCustomizer(AnnotationsPropertySource propertySource) {\n\t\tthis.propertySource = propertySource;\n\t}\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context,\n\t\t\tMergedContextConfiguration mergedContextConfiguration) {\n\t\tif (!this.propertySource.isEmpty()) {\n\t\t\tcontext.getEnvironment().getPropertySources().addFirst(this.propertySource);\n\t\t}\n\t\tcontext.getBeanFactory()\n\t\t\t.registerSingleton(PropertyMappingCheckBeanPostProcessor.class.getName(),\n\t\t\t\t\tnew PropertyMappingCheckBeanPostProcessor());\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\treturn (obj != null) && (getClass() == obj.getClass())\n\t\t\t\t&& this.propertySource.equals(((PropertyMappingContextCustomizer) obj).propertySource);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.propertySource.hashCode();\n\t}\n\n\t/**\n\t * {@link BeanPostProcessor} to check that {@link PropertyMapping @PropertyMapping} is\n\t * only used on test classes.\n\t */\n\tstatic class PropertyMappingCheckBeanPostProcessor implements BeanPostProcessor {\n\n\t\t@Override\n\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tClass<?> beanClass = bean.getClass();\n\t\t\tMergedAnnotations annotations = MergedAnnotations.from(beanClass, SearchStrategy.SUPERCLASS);\n\t\t\tSet<Class<?>> components = annotations.stream(Component.class)\n\t\t\t\t.map(this::getRoot)\n\t\t\t\t.collect(Collectors.toSet());\n\t\t\tSet<Class<?>> propertyMappings = annotations.stream(PropertyMapping.class)\n\t\t\t\t.map(this::getRoot)\n\t\t\t\t.collect(Collectors.toSet());\n\t\t\tif (!components.isEmpty() && !propertyMappings.isEmpty()) {\n\t\t\t\tthrow new IllegalStateException(\"The @PropertyMapping \" + getAnnotationsDescription(propertyMappings)\n\t\t\t\t\t\t+ \" cannot be used in combination with the @Component \"\n\t\t\t\t\t\t+ getAnnotationsDescription(components));\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate Class<?> getRoot(MergedAnnotation<?> annotation) {\n\t\t\treturn annotation.getRoot().getType();\n\t\t}\n\n\t\tprivate String getAnnotationsDescription(Set<Class<?>> annotations) {\n\t\t\tStringBuilder result = new StringBuilder();\n\t\t\tfor (Class<?> annotation : annotations) {\n\t\t\t\tif (!result.isEmpty()) {\n\t\t\t\t\tresult.append(\", \");\n\t\t\t\t}\n\t\t\t\tresult.append('@').append(ClassUtils.getShortName(annotation));\n\t\t\t}\n\t\t\tresult.insert(0, (annotations.size() != 1) ? \"annotations \" : \"annotation \");\n\t\t\treturn result.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/PropertyMappingContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.List;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\n\n/**\n * {@link ContextCustomizerFactory} to map annotation attributes to {@link Environment}\n * properties.\n *\n * @author Phillip Webb\n */\nclass PropertyMappingContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configurationAttributes) {\n\t\tAnnotationsPropertySource propertySource = new AnnotationsPropertySource(testClass);\n\t\treturn new PropertyMappingContextCustomizer(propertySource);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/ReactiveWebMergedContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.springframework.test.context.MergedContextConfiguration;\n\n/**\n * Encapsulates the <em>merged</em> context configuration declared on a test class and all\n * of its superclasses for a reactive web application.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class ReactiveWebMergedContextConfiguration extends MergedContextConfiguration {\n\n\tpublic ReactiveWebMergedContextConfiguration(MergedContextConfiguration mergedConfig) {\n\t\tsuper(mergedConfig);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootContextLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringApplication.AbandonedRunException;\nimport org.springframework.boot.SpringApplicationHook;\nimport org.springframework.boot.SpringApplicationRunListener;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.bootstrap.ConfigurableBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod;\nimport org.springframework.boot.test.mock.web.SpringBootMockServletContext;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.test.util.TestPropertyValues.Type;\nimport org.springframework.boot.web.context.reactive.GenericReactiveWebApplicationContext;\nimport org.springframework.boot.web.servlet.support.ServletContextApplicationContextInitializer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.aot.AotApplicationContextInitializer;\nimport org.springframework.core.KotlinDetector;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextLoadException;\nimport org.springframework.test.context.ContextLoader;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.SmartContextLoader;\nimport org.springframework.test.context.aot.AotContextLoader;\nimport org.springframework.test.context.support.AbstractContextLoader;\nimport org.springframework.test.context.support.AnnotationConfigContextLoaderUtils;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.test.context.web.WebMergedContextConfiguration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.ThrowingSupplier;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\n\n/**\n * A {@link ContextLoader} that can be used to test Spring Boot applications (those that\n * normally startup using {@link SpringApplication}). Although this loader can be used\n * directly, most test will instead want to use it with\n * {@link SpringBootTest @SpringBootTest}.\n * <p>\n * The loader supports both standard {@link MergedContextConfiguration} as well as\n * {@link WebMergedContextConfiguration}. If {@link WebMergedContextConfiguration} is used\n * the context will either use a mock servlet environment, or start the full embedded web\n * server.\n * <p>\n * If {@code @ActiveProfiles} are provided in the test class they will be used to create\n * the application context.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 1.4.0\n * @see SpringBootTest\n */\npublic class SpringBootContextLoader extends AbstractContextLoader implements AotContextLoader {\n\n\tprivate static final Consumer<SpringApplication> ALREADY_CONFIGURED = (springApplication) -> {\n\t};\n\n\tprivate static final Object NONE = new Object();\n\n\t@Override\n\tpublic ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {\n\t\treturn loadContext(mergedConfig, Mode.STANDARD, null, null);\n\t}\n\n\t@Override\n\tpublic ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig,\n\t\t\tRuntimeHints runtimeHints) throws Exception {\n\t\treturn loadContext(mergedConfig, Mode.AOT_PROCESSING, null, runtimeHints);\n\t}\n\n\t@Override\n\tpublic ApplicationContext loadContextForAotRuntime(MergedContextConfiguration mergedConfig,\n\t\t\tApplicationContextInitializer<ConfigurableApplicationContext> initializer) throws Exception {\n\t\treturn loadContext(mergedConfig, Mode.AOT_RUNTIME, initializer, null);\n\t}\n\n\tprivate ApplicationContext loadContext(MergedContextConfiguration mergedConfig, Mode mode,\n\t\t\t@Nullable ApplicationContextInitializer<ConfigurableApplicationContext> initializer,\n\t\t\t@Nullable RuntimeHints runtimeHints) throws Exception {\n\t\tassertHasClassesOrLocations(mergedConfig);\n\t\tSpringBootTestAnnotation annotation = SpringBootTestAnnotation.get(mergedConfig);\n\t\tString[] args = annotation.getArgs();\n\t\tUseMainMethod useMainMethod = annotation.getUseMainMethod();\n\t\tMethod mainMethod = getMainMethod(mergedConfig, useMainMethod);\n\t\tif (mainMethod != null) {\n\t\t\tif (runtimeHints != null) {\n\t\t\t\truntimeHints.reflection().registerMethod(mainMethod, ExecutableMode.INVOKE);\n\t\t\t}\n\t\t\tContextLoaderHook hook = new ContextLoaderHook(mode, initializer,\n\t\t\t\t\t(application) -> configure(mergedConfig, application));\n\t\t\treturn hook.runMain(() -> {\n\t\t\t\tif (mainMethod.getParameterCount() == 0) {\n\t\t\t\t\tReflectionUtils.invokeMethod(mainMethod, null);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tReflectionUtils.invokeMethod(mainMethod, null, new Object[] { args });\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tSpringApplication application = getSpringApplication();\n\t\tconfigure(mergedConfig, application);\n\t\tContextLoaderHook hook = new ContextLoaderHook(mode, initializer, ALREADY_CONFIGURED);\n\t\treturn hook.run(() -> application.run(args));\n\t}\n\n\tprivate void assertHasClassesOrLocations(MergedContextConfiguration mergedConfig) {\n\t\tAssert.state(mergedConfig.hasResources(),\n\t\t\t\t() -> \"No configuration classes or locations found. Check your test's configuration.\");\n\t}\n\n\tprivate @Nullable Method getMainMethod(MergedContextConfiguration mergedConfig, UseMainMethod useMainMethod) {\n\t\tif (useMainMethod == UseMainMethod.NEVER) {\n\t\t\treturn null;\n\t\t}\n\t\tAssert.state(mergedConfig.getParent() == null,\n\t\t\t\t() -> \"UseMainMethod.%s cannot be used with @ContextHierarchy tests\".formatted(useMainMethod));\n\t\tClass<?> springBootConfiguration = Arrays.stream(mergedConfig.getClasses())\n\t\t\t.filter(this::isSpringBootConfiguration)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t\tAssert.state(springBootConfiguration != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE,\n\t\t\t\t\"Cannot use main method as no @SpringBootConfiguration-annotated class is available\");\n\t\tMethod mainMethod = findMainMethod(springBootConfiguration);\n\t\tAssert.state(mainMethod != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE,\n\t\t\t\t() -> \"Main method not found on '%s'\"\n\t\t\t\t\t.formatted((springBootConfiguration != null) ? springBootConfiguration.getName() : null));\n\t\treturn mainMethod;\n\t}\n\n\tprivate static @Nullable Method findMainMethod(@Nullable Class<?> type) {\n\t\tMethod mainMethod = (type != null) ? findMainJavaMethod(type) : null;\n\t\tif (mainMethod == null && KotlinDetector.isKotlinPresent()) {\n\t\t\ttry {\n\t\t\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\t\t\tClass<?> kotlinClass = ClassUtils.forName(type.getName() + \"Kt\", type.getClassLoader());\n\t\t\t\tmainMethod = ReflectionUtils.findMethod(kotlinClass, \"main\", String[].class);\n\t\t\t}\n\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn mainMethod;\n\t}\n\n\tprivate static @Nullable Method findMainJavaMethod(Class<?> type) {\n\t\ttry {\n\t\t\tMethod method = getMainMethod(type);\n\t\t\tif (Modifier.isStatic(method.getModifiers())) {\n\t\t\t\tmethod.setAccessible(true);\n\t\t\t\treturn method;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static Method getMainMethod(Class<?> type) throws NoSuchMethodException {\n\t\ttry {\n\t\t\treturn type.getDeclaredMethod(\"main\", String[].class);\n\t\t}\n\t\tcatch (NoSuchMethodException ex) {\n\t\t\treturn type.getDeclaredMethod(\"main\");\n\t\t}\n\n\t}\n\n\tprivate boolean isSpringBootConfiguration(Class<?> candidate) {\n\t\treturn MergedAnnotations.from(candidate, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.isPresent(SpringBootConfiguration.class);\n\t}\n\n\tprivate void configure(MergedContextConfiguration mergedConfig, SpringApplication application) {\n\t\tapplication.setMainApplicationClass(mergedConfig.getTestClass());\n\t\tapplication.addPrimarySources(Arrays.asList(mergedConfig.getClasses()));\n\t\tapplication.getSources().addAll(Arrays.asList(mergedConfig.getLocations()));\n\t\tList<ApplicationContextInitializer<?>> initializers = getInitializers(mergedConfig, application);\n\t\tif (mergedConfig instanceof WebMergedContextConfiguration) {\n\t\t\tapplication.setWebApplicationType(WebApplicationType.SERVLET);\n\t\t\tif (!isEmbeddedWebEnvironment(mergedConfig)) {\n\t\t\t\tnew WebConfigurer().configure(mergedConfig, initializers);\n\t\t\t}\n\t\t}\n\t\telse if (mergedConfig instanceof ReactiveWebMergedContextConfiguration) {\n\t\t\tapplication.setWebApplicationType(WebApplicationType.REACTIVE);\n\t\t}\n\t\telse {\n\t\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\t}\n\t\tapplication.setApplicationContextFactory(getApplicationContextFactory(mergedConfig));\n\t\tif (mergedConfig.getParent() != null) {\n\t\t\tapplication.setBannerMode(Banner.Mode.OFF);\n\t\t}\n\t\tapplication.setInitializers(initializers);\n\t\tConfigurableEnvironment environment = getEnvironment();\n\t\tif (environment != null) {\n\t\t\tprepareEnvironment(mergedConfig, application, environment, false);\n\t\t\tapplication.setEnvironment(environment);\n\t\t}\n\t\telse {\n\t\t\tapplication.addListeners(new PrepareEnvironmentListener(mergedConfig));\n\t\t}\n\t}\n\n\t/**\n\t * Return the {@link ApplicationContextFactory} that should be used for the test. By\n\t * default this method will return a factory that will create an appropriate\n\t * {@link ApplicationContext} for the {@link WebApplicationType}.\n\t * @param mergedConfig the merged context configuration\n\t * @return the application context factory to use\n\t * @since 3.2.0\n\t */\n\tprotected ApplicationContextFactory getApplicationContextFactory(MergedContextConfiguration mergedConfig) {\n\t\treturn (webApplicationType) -> {\n\t\t\tif (webApplicationType != WebApplicationType.NONE && !isEmbeddedWebEnvironment(mergedConfig)) {\n\t\t\t\tif (webApplicationType == WebApplicationType.REACTIVE) {\n\t\t\t\t\treturn new GenericReactiveWebApplicationContext();\n\t\t\t\t}\n\t\t\t\tif (webApplicationType == WebApplicationType.SERVLET) {\n\t\t\t\t\treturn new GenericWebApplicationContext();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ApplicationContextFactory.DEFAULT.create(webApplicationType);\n\t\t};\n\t}\n\n\tprivate void prepareEnvironment(MergedContextConfiguration mergedConfig, SpringApplication application,\n\t\t\tConfigurableEnvironment environment, boolean applicationEnvironment) {\n\t\tsetActiveProfiles(environment, mergedConfig.getActiveProfiles(), applicationEnvironment);\n\t\tResourceLoader resourceLoader = (application.getResourceLoader() != null) ? application.getResourceLoader()\n\t\t\t\t: new DefaultResourceLoader(null);\n\t\tTestPropertySourceUtils.addPropertySourcesToEnvironment(environment, resourceLoader,\n\t\t\t\tmergedConfig.getPropertySourceDescriptors());\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(environment, getInlinedProperties(mergedConfig));\n\t}\n\n\tprivate void setActiveProfiles(ConfigurableEnvironment environment, String[] profiles,\n\t\t\tboolean applicationEnvironment) {\n\t\tif (ObjectUtils.isEmpty(profiles)) {\n\t\t\treturn;\n\t\t}\n\t\tif (!applicationEnvironment) {\n\t\t\tenvironment.setActiveProfiles(profiles);\n\t\t}\n\t\tString[] pairs = new String[profiles.length];\n\t\tfor (int i = 0; i < profiles.length; i++) {\n\t\t\tpairs[i] = \"spring.profiles.active[\" + i + \"]=\" + profiles[i];\n\t\t}\n\t\tTestPropertyValues.of(pairs).applyTo(environment, Type.MAP, \"active-test-profiles\");\n\t}\n\n\t/**\n\t * Builds new {@link org.springframework.boot.SpringApplication} instance. This method\n\t * is only called when a {@code main} method isn't being used to create the\n\t * {@link SpringApplication}.\n\t * @return a {@link SpringApplication} instance\n\t */\n\tprotected SpringApplication getSpringApplication() {\n\t\treturn new SpringApplication();\n\t}\n\n\t/**\n\t * Returns the {@link ConfigurableEnvironment} instance that should be applied to\n\t * {@link SpringApplication} or {@code null} to use the default. You can override this\n\t * method if you need a custom environment.\n\t * @return a {@link ConfigurableEnvironment} instance\n\t */\n\tprotected @Nullable ConfigurableEnvironment getEnvironment() {\n\t\treturn null;\n\t}\n\n\tprotected String[] getInlinedProperties(MergedContextConfiguration mergedConfig) {\n\t\tArrayList<String> properties = new ArrayList<>();\n\t\t// JMX bean names will clash if the same bean is used in multiple contexts\n\t\tproperties.add(\"spring.jmx.enabled=false\");\n\t\tproperties.addAll(Arrays.asList(mergedConfig.getPropertySourceProperties()));\n\t\treturn StringUtils.toStringArray(properties);\n\t}\n\n\t/**\n\t * Return the {@link ApplicationContextInitializer initializers} that will be applied\n\t * to the context. By default this method will adapt {@link ContextCustomizer context\n\t * customizers}, add {@link SpringApplication#getInitializers() application\n\t * initializers} and add\n\t * {@link MergedContextConfiguration#getContextInitializerClasses() initializers\n\t * specified on the test}.\n\t * @param mergedConfig the source context configuration\n\t * @param application the application instance\n\t * @return the initializers to apply\n\t * @since 2.0.0\n\t */\n\tprotected List<ApplicationContextInitializer<?>> getInitializers(MergedContextConfiguration mergedConfig,\n\t\t\tSpringApplication application) {\n\t\tList<ApplicationContextInitializer<?>> initializers = new ArrayList<>();\n\t\tfor (ContextCustomizer contextCustomizer : mergedConfig.getContextCustomizers()) {\n\t\t\tinitializers.add(new ContextCustomizerAdapter(contextCustomizer, mergedConfig));\n\t\t}\n\t\tinitializers.addAll(application.getInitializers());\n\t\tfor (Class<? extends ApplicationContextInitializer<?>> initializerClass : mergedConfig\n\t\t\t.getContextInitializerClasses()) {\n\t\t\tinitializers.add(BeanUtils.instantiateClass(initializerClass));\n\t\t}\n\t\tif (mergedConfig.getParent() != null) {\n\t\t\tApplicationContext parentApplicationContext = mergedConfig.getParentApplicationContext();\n\t\t\tinitializers.add(new ParentContextApplicationContextInitializer(parentApplicationContext));\n\t\t}\n\t\treturn initializers;\n\t}\n\n\tprivate boolean isEmbeddedWebEnvironment(MergedContextConfiguration mergedConfig) {\n\t\treturn SpringBootTestAnnotation.get(mergedConfig).getWebEnvironment().isEmbedded();\n\t}\n\n\t@Override\n\tpublic void processContextConfiguration(ContextConfigurationAttributes configAttributes) {\n\t\tsuper.processContextConfiguration(configAttributes);\n\t\tif (!configAttributes.hasResources()) {\n\t\t\tClass<?>[] defaultConfigClasses = detectDefaultConfigurationClasses(configAttributes.getDeclaringClass());\n\t\t\tconfigAttributes.setClasses(defaultConfigClasses);\n\t\t}\n\t}\n\n\t/**\n\t * Detect the default configuration classes for the supplied test class. By default\n\t * simply delegates to\n\t * {@link AnnotationConfigContextLoaderUtils#detectDefaultConfigurationClasses}.\n\t * @param declaringClass the test class that declared {@code @ContextConfiguration}\n\t * @return an array of default configuration classes, potentially empty but never\n\t * {@code null}\n\t * @see AnnotationConfigContextLoaderUtils\n\t */\n\tprotected Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {\n\t\treturn AnnotationConfigContextLoaderUtils.detectDefaultConfigurationClasses(declaringClass);\n\t}\n\n\t@Override\n\tprotected String[] getResourceSuffixes() {\n\t\treturn new String[] { \"-context.xml\", \"Context.groovy\" };\n\t}\n\n\t@Override\n\tprotected String getResourceSuffix() {\n\t\tthrow new IllegalStateException();\n\t}\n\n\t/**\n\t * Modes that the {@link SpringBootContextLoader} can operate.\n\t */\n\tprivate enum Mode {\n\n\t\t/**\n\t\t * Load for regular usage.\n\t\t * @see SmartContextLoader#loadContext\n\t\t */\n\t\tSTANDARD,\n\n\t\t/**\n\t\t * Load for AOT processing.\n\t\t * @see AotContextLoader#loadContextForAotProcessing\n\t\t */\n\t\tAOT_PROCESSING,\n\n\t\t/**\n\t\t * Load for AOT runtime.\n\t\t * @see AotContextLoader#loadContextForAotRuntime\n\t\t */\n\t\tAOT_RUNTIME\n\n\t}\n\n\t/**\n\t * Inner class to configure {@link WebMergedContextConfiguration}.\n\t */\n\tprivate static final class WebConfigurer {\n\n\t\tvoid configure(MergedContextConfiguration mergedConfig, List<ApplicationContextInitializer<?>> initializers) {\n\t\t\tWebMergedContextConfiguration webMergedConfig = (WebMergedContextConfiguration) mergedConfig;\n\t\t\taddMockServletContext(initializers, webMergedConfig);\n\t\t}\n\n\t\tprivate void addMockServletContext(List<ApplicationContextInitializer<?>> initializers,\n\t\t\t\tWebMergedContextConfiguration webMergedConfig) {\n\t\t\tSpringBootMockServletContext servletContext = new SpringBootMockServletContext(\n\t\t\t\t\twebMergedConfig.getResourceBasePath());\n\t\t\tinitializers.add(0, new DefensiveWebApplicationContextInitializer(\n\t\t\t\t\tnew ServletContextApplicationContextInitializer(servletContext, true)));\n\t\t}\n\n\t\t/**\n\t\t * Decorator for {@link ServletContextApplicationContextInitializer} that prevents\n\t\t * a failure when the context type is not as was predicted when the initializer\n\t\t * was registered. This can occur when spring.main.web-application-type is set to\n\t\t * something other than servlet.\n\t\t */\n\t\tprivate static final class DefensiveWebApplicationContextInitializer\n\t\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t\tprivate final ServletContextApplicationContextInitializer delegate;\n\n\t\t\tprivate DefensiveWebApplicationContextInitializer(ServletContextApplicationContextInitializer delegate) {\n\t\t\t\tthis.delegate = delegate;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\t\tif (applicationContext instanceof ConfigurableWebApplicationContext webApplicationContext) {\n\t\t\t\t\tthis.delegate.initialize(webApplicationContext);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts a {@link ContextCustomizer} to a {@link ApplicationContextInitializer} so\n\t * that it can be triggered through {@link SpringApplication}.\n\t */\n\tprivate static class ContextCustomizerAdapter\n\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\tprivate final ContextCustomizer contextCustomizer;\n\n\t\tprivate final MergedContextConfiguration mergedConfig;\n\n\t\tContextCustomizerAdapter(ContextCustomizer contextCustomizer, MergedContextConfiguration mergedConfig) {\n\t\t\tthis.contextCustomizer = contextCustomizer;\n\t\t\tthis.mergedConfig = mergedConfig;\n\t\t}\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tthis.contextCustomizer.customizeContext(applicationContext, this.mergedConfig);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ApplicationContextInitializer} used to set the parent context.\n\t */\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tprivate static class ParentContextApplicationContextInitializer\n\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\tprivate final @Nullable ApplicationContext parent;\n\n\t\tParentContextApplicationContextInitializer(@Nullable ApplicationContext parent) {\n\t\t\tthis.parent = parent;\n\t\t}\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tapplicationContext.setParent(this.parent);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ApplicationListener} used to prepare the application created environment.\n\t */\n\tprivate class PrepareEnvironmentListener\n\t\t\timplements ApplicationListener<ApplicationEnvironmentPreparedEvent>, PriorityOrdered {\n\n\t\tprivate final MergedContextConfiguration mergedConfig;\n\n\t\tPrepareEnvironmentListener(MergedContextConfiguration mergedConfig) {\n\t\t\tthis.mergedConfig = mergedConfig;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\t\tprepareEnvironment(this.mergedConfig, event.getSpringApplication(), event.getEnvironment(), true);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SpringApplicationHook} used to capture {@link ApplicationContext} instances\n\t * and to trigger early exit for the {@link Mode#AOT_PROCESSING} mode.\n\t */\n\tprivate static class ContextLoaderHook implements SpringApplicationHook {\n\n\t\tprivate final Mode mode;\n\n\t\tprivate final @Nullable ApplicationContextInitializer<ConfigurableApplicationContext> initializer;\n\n\t\tprivate final Consumer<SpringApplication> configurer;\n\n\t\tprivate final List<ApplicationContext> contexts = Collections.synchronizedList(new ArrayList<>());\n\n\t\tprivate final List<ApplicationContext> failedContexts = Collections.synchronizedList(new ArrayList<>());\n\n\t\tContextLoaderHook(Mode mode,\n\t\t\t\t@Nullable ApplicationContextInitializer<ConfigurableApplicationContext> initializer,\n\t\t\t\tConsumer<SpringApplication> configurer) {\n\t\t\tthis.mode = mode;\n\t\t\tthis.initializer = initializer;\n\t\t\tthis.configurer = configurer;\n\t\t}\n\n\t\t@Override\n\t\tpublic SpringApplicationRunListener getRunListener(SpringApplication application) {\n\t\t\treturn new SpringApplicationRunListener() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void starting(ConfigurableBootstrapContext bootstrapContext) {\n\t\t\t\t\tContextLoaderHook.this.configurer.accept(application);\n\t\t\t\t\tif (ContextLoaderHook.this.mode == Mode.AOT_RUNTIME) {\n\t\t\t\t\t\tAssert.state(ContextLoaderHook.this.initializer != null, \"'initializer' must not be null\");\n\t\t\t\t\t\tapplication.addInitializers(\n\t\t\t\t\t\t\t\t(AotApplicationContextInitializer<?>) ContextLoaderHook.this.initializer::initialize);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void contextLoaded(ConfigurableApplicationContext context) {\n\t\t\t\t\tContextLoaderHook.this.contexts.add(context);\n\t\t\t\t\tif (ContextLoaderHook.this.mode == Mode.AOT_PROCESSING) {\n\t\t\t\t\t\tthrow new AbandonedRunException(context);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {\n\t\t\t\t\tif (context != null) {\n\t\t\t\t\t\tContextLoaderHook.this.failedContexts.add(context);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\tprivate ApplicationContext runMain(Runnable action) throws Exception {\n\t\t\treturn run(() -> {\n\t\t\t\taction.run();\n\t\t\t\treturn NONE;\n\t\t\t});\n\t\t}\n\n\t\tprivate ApplicationContext run(ThrowingSupplier<?> action) throws Exception {\n\t\t\ttry {\n\t\t\t\tObject result = SpringApplication.withHook(this, action);\n\t\t\t\tif (result instanceof ApplicationContext context) {\n\t\t\t\t\treturn context;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (AbandonedRunException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tif (this.failedContexts.size() == 1) {\n\t\t\t\t\tthrow new ContextLoadException(this.failedContexts.get(0), ex);\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tList<ApplicationContext> rootContexts = this.contexts.stream()\n\t\t\t\t.filter((context) -> context.getParent() == null)\n\t\t\t\t.toList();\n\t\t\tAssert.state(!rootContexts.isEmpty(), \"No root application context located\");\n\t\t\tAssert.state(rootContexts.size() == 1, \"No unique root application context located\");\n\t\t\treturn rootContexts.get(0);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.ContextLoader;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Annotation that can be specified on a test class that runs Spring Boot based tests.\n * Provides the following features over and above the regular <em>Spring TestContext\n * Framework</em>:\n * <ul>\n * <li>Uses {@link SpringBootContextLoader} as the default {@link ContextLoader} when no\n * specific {@link ContextConfiguration#loader() @ContextConfiguration(loader=...)} is\n * defined.</li>\n * <li>Automatically searches for a\n * {@link SpringBootConfiguration @SpringBootConfiguration} when nested\n * {@code @Configuration} is not used, and no explicit {@link #classes() classes} are\n * specified.</li>\n * <li>Allows custom {@link Environment} properties to be defined using the\n * {@link #properties() properties attribute}.</li>\n * <li>Allows application arguments to be defined using the {@link #args() args\n * attribute}.</li>\n * <li>Provides support for different {@link #webEnvironment() webEnvironment} modes,\n * including the ability to start a fully running web server listening on a\n * {@link WebEnvironment#DEFINED_PORT defined} or {@link WebEnvironment#RANDOM_PORT\n * random} port when {@code spring-boot-web-server} is on the classpath.</li>\n * </ul>\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.4.0\n * @see ContextConfiguration\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(SpringBootTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\npublic @interface SpringBootTest {\n\n\t/**\n\t * Alias for {@link #properties()}.\n\t * @return the properties to apply\n\t */\n\t@AliasFor(\"properties\")\n\tString[] value() default {};\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\t@AliasFor(\"value\")\n\tString[] properties() default {};\n\n\t/**\n\t * Application arguments that should be passed to the application under test.\n\t * @return the application arguments to pass to the application under test.\n\t * @see ApplicationArguments\n\t * @see SpringApplication#run(String...)\n\t * @since 2.2.0\n\t */\n\tString[] args() default {};\n\n\t/**\n\t * The <em>component classes</em> to use for loading an\n\t * {@link org.springframework.context.ApplicationContext ApplicationContext}. Can also\n\t * be specified using\n\t * {@link ContextConfiguration#classes() @ContextConfiguration(classes=...)}. If no\n\t * explicit classes are defined the test will look for nested\n\t * {@link Configuration @Configuration} classes, before falling back to a\n\t * {@link SpringBootConfiguration @SpringBootConfiguration} search.\n\t * @see ContextConfiguration#classes()\n\t * @return the component classes used to load the application context\n\t */\n\tClass<?>[] classes() default {};\n\n\t/**\n\t * The type of web environment to create when applicable. Defaults to\n\t * {@link WebEnvironment#MOCK}.\n\t * @return the type of web environment\n\t */\n\tWebEnvironment webEnvironment() default WebEnvironment.MOCK;\n\n\t/**\n\t * The type of main method usage to employ when creating the {@link SpringApplication}\n\t * under test.\n\t * @return the type of main method usage\n\t * @since 3.0.0\n\t */\n\tUseMainMethod useMainMethod() default UseMainMethod.NEVER;\n\n\t/**\n\t * An enumeration of web environment modes.\n\t */\n\tenum WebEnvironment {\n\n\t\t/**\n\t\t * Creates a {@link WebApplicationContext} with a mock servlet environment if\n\t\t * servlet APIs are on the classpath, a {@link ReactiveWebApplicationContext} if\n\t\t * Spring WebFlux is on the classpath or a regular {@link ApplicationContext}\n\t\t * otherwise.\n\t\t */\n\t\tMOCK(false),\n\n\t\t/**\n\t\t * Creates a web application context (reactive or servlet based) and sets a\n\t\t * {@code server.port=0} {@link Environment} property (which usually triggers\n\t\t * listening on a random port). Requires a dependency on\n\t\t * {@code spring-boot-web-server}. Often used in conjunction with a\n\t\t * {@code @LocalServerPort} injected field on the test.\n\t\t */\n\t\tRANDOM_PORT(true),\n\n\t\t/**\n\t\t * Creates a web application context (reactive or servlet based) without defining\n\t\t * any {@code server.port=0} {@link Environment} property. Requires a dependency\n\t\t * on {@code spring-boot-web-server}.\n\t\t */\n\t\tDEFINED_PORT(true),\n\n\t\t/**\n\t\t * Creates an {@link ApplicationContext} and sets\n\t\t * {@link SpringApplication#setWebApplicationType(WebApplicationType)} to\n\t\t * {@link WebApplicationType#NONE}.\n\t\t */\n\t\tNONE(false);\n\n\t\tprivate final boolean embedded;\n\n\t\tWebEnvironment(boolean embedded) {\n\t\t\tthis.embedded = embedded;\n\t\t}\n\n\t\t/**\n\t\t * Return if the environment uses an embedded web server.\n\t\t * @return if an embedded web server is used\n\t\t */\n\t\tpublic boolean isEmbedded() {\n\t\t\treturn this.embedded;\n\t\t}\n\n\t}\n\n\t/**\n\t * Enumeration of how the main method of the\n\t * {@link SpringBootConfiguration @SpringBootConfiguration}-annotated class is used\n\t * when creating and running the {@link SpringApplication} under test.\n\t *\n\t * @since 3.0.0\n\t */\n\tenum UseMainMethod {\n\n\t\t/**\n\t\t * Always use the {@code main} method. A failure will occur if there is no\n\t\t * {@link SpringBootConfiguration @SpringBootConfiguration}-annotated class or\n\t\t * that class does not have a main method.\n\t\t */\n\t\tALWAYS,\n\n\t\t/**\n\t\t * Never use the {@code main} method, creating a test-specific\n\t\t * {@link SpringApplication} instead.\n\t\t */\n\t\tNEVER,\n\n\t\t/**\n\t\t * Use the {@code main} method when it is available. If there is no\n\t\t * {@link SpringBootConfiguration @SpringBootConfiguration}-annotated class or\n\t\t * that class does not have a main method, a test-specific\n\t\t * {@link SpringApplication} will be used.\n\t\t */\n\t\tWHEN_AVAILABLE\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestAnnotation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextAnnotationUtils;\n\n/**\n * {@link ContextCustomizer} to track attributes of {@link SpringBootTest @SpringBootTest}\n * that are taken into account when evaluating a {@link MergedContextConfiguration} to\n * determine if a context can be shared between tests.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass SpringBootTestAnnotation implements ContextCustomizer {\n\n\tprivate static final String[] NO_ARGS = new String[0];\n\n\tprivate static final SpringBootTestAnnotation DEFAULT = new SpringBootTestAnnotation((SpringBootTest) null);\n\n\tprivate final String[] args;\n\n\tprivate final WebEnvironment webEnvironment;\n\n\tprivate final UseMainMethod useMainMethod;\n\n\tSpringBootTestAnnotation(Class<?> testClass) {\n\t\tthis(TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class));\n\t}\n\n\tprivate SpringBootTestAnnotation(@Nullable SpringBootTest annotation) {\n\t\tthis.args = (annotation != null) ? annotation.args() : NO_ARGS;\n\t\tthis.webEnvironment = (annotation != null) ? annotation.webEnvironment() : WebEnvironment.NONE;\n\t\tthis.useMainMethod = (annotation != null) ? annotation.useMainMethod() : UseMainMethod.NEVER;\n\t}\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tSpringBootTestAnnotation other = (SpringBootTestAnnotation) obj;\n\t\tboolean result = Arrays.equals(this.args, other.args);\n\t\tresult = result && this.useMainMethod == other.useMainMethod;\n\t\tresult = result && this.webEnvironment == other.webEnvironment;\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + Arrays.hashCode(this.args);\n\t\tresult = prime * result + Objects.hash(this.useMainMethod, this.webEnvironment);\n\t\treturn result;\n\t}\n\n\tString[] getArgs() {\n\t\treturn this.args;\n\t}\n\n\tWebEnvironment getWebEnvironment() {\n\t\treturn this.webEnvironment;\n\t}\n\n\tUseMainMethod getUseMainMethod() {\n\t\treturn this.useMainMethod;\n\t}\n\n\t/**\n\t * Return the application arguments from the given {@link MergedContextConfiguration}.\n\t * @param mergedConfig the merged config to check\n\t * @return a {@link SpringBootTestAnnotation} instance\n\t */\n\tstatic SpringBootTestAnnotation get(MergedContextConfiguration mergedConfig) {\n\t\tfor (ContextCustomizer customizer : mergedConfig.getContextCustomizers()) {\n\t\t\tif (customizer instanceof SpringBootTestAnnotation annotation) {\n\t\t\t\treturn annotation;\n\t\t\t}\n\t\t}\n\t\treturn DEFAULT;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.io.File;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.springframework.test.context.aot.TestAotProcessor;\nimport org.springframework.util.Assert;\n\n/**\n * Entry point for AOT processing of a Spring Boot application's tests.\n *\n * <strong>For internal use only.</strong>\n *\n * @author Andy Wilkinson\n * @since 3.0.0\n */\npublic class SpringBootTestAotProcessor extends TestAotProcessor {\n\n\t/**\n\t * Create a new processor for the specified test classpath roots and general settings.\n\t * @param classpathRoots the classpath roots to scan for test classes\n\t * @param settings the general AOT processor settings\n\t */\n\tpublic SpringBootTestAotProcessor(Set<Path> classpathRoots, Settings settings) {\n\t\tsuper(classpathRoots, settings);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tint requiredArgs = 6;\n\t\tAssert.isTrue(args.length >= requiredArgs,\n\t\t\t\t() -> \"Usage: %s <classpathRoots> <sourceOutput> <resourceOutput> <classOutput> <groupId> <artifactId>\"\n\t\t\t\t\t.formatted(TestAotProcessor.class.getName()));\n\t\tSet<Path> classpathRoots = Arrays.stream(args[0].split(File.pathSeparator))\n\t\t\t.map(Paths::get)\n\t\t\t.collect(Collectors.toSet());\n\t\tSettings settings = Settings.builder()\n\t\t\t.sourceOutput(Paths.get(args[1]))\n\t\t\t.resourceOutput(Paths.get(args[2]))\n\t\t\t.classOutput(Paths.get(args[3]))\n\t\t\t.groupId(args[4])\n\t\t\t.artifactId(args[5])\n\t\t\t.build();\n\t\tnew SpringBootTestAotProcessor(classpathRoots, settings).process();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/SpringBootTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextHierarchy;\nimport org.springframework.test.context.ContextLoader;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestContextAnnotationUtils;\nimport org.springframework.test.context.TestContextBootstrapper;\nimport org.springframework.test.context.aot.AotTestAttributes;\nimport org.springframework.test.context.support.DefaultTestContextBootstrapper;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.test.context.web.WebMergedContextConfiguration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link TestContextBootstrapper} for Spring Boot. Provides support for\n * {@link SpringBootTest @SpringBootTest} and may also be used directly or subclassed.\n * Provides the following features over and above {@link DefaultTestContextBootstrapper}:\n * <ul>\n * <li>Uses {@link SpringBootContextLoader} as the\n * {@link #getDefaultContextLoaderClass(Class) default context loader}.</li>\n * <li>Automatically searches for a\n * {@link SpringBootConfiguration @SpringBootConfiguration} when required.</li>\n * <li>Allows custom {@link Environment} {@link #getProperties(Class)} to be defined.</li>\n * <li>Provides support for different {@link WebEnvironment webEnvironment} modes.</li>\n * </ul>\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @author Madhura Bhave\n * @author Lorenzo Dee\n * @since 1.4.0\n * @see SpringBootTest\n * @see TestConfiguration\n */\npublic class SpringBootTestContextBootstrapper extends DefaultTestContextBootstrapper {\n\n\tprivate static final String ACTIVATE_SERVLET_LISTENER = \"org.springframework.test.\"\n\t\t\t+ \"context.web.ServletTestExecutionListener.activateListener\";\n\n\tprivate static final Log logger = LogFactory.getLog(SpringBootTestContextBootstrapper.class);\n\n\tprivate final AotTestAttributes aotTestAttributes;\n\n\tpublic SpringBootTestContextBootstrapper() {\n\t\tthis(AotTestAttributes.getInstance());\n\t}\n\n\tSpringBootTestContextBootstrapper(AotTestAttributes aotTestAttributes) {\n\t\tthis.aotTestAttributes = aotTestAttributes;\n\t}\n\n\t@Override\n\tpublic TestContext buildTestContext() {\n\t\tTestContext context = super.buildTestContext();\n\t\tverifyConfiguration(context.getTestClass());\n\t\tWebEnvironment webEnvironment = getWebEnvironment(context.getTestClass());\n\t\tif (webEnvironment == WebEnvironment.MOCK && WebApplicationType.deduce() == WebApplicationType.SERVLET) {\n\t\t\tcontext.setAttribute(ACTIVATE_SERVLET_LISTENER, true);\n\t\t}\n\t\telse if (webEnvironment != null && webEnvironment.isEmbedded()) {\n\t\t\tcontext.setAttribute(ACTIVATE_SERVLET_LISTENER, false);\n\t\t}\n\t\treturn context;\n\t}\n\n\t@Override\n\tprotected ContextLoader resolveContextLoader(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributesList) {\n\t\tClass<?>[] classes = getClasses(testClass);\n\t\tif (!ObjectUtils.isEmpty(classes)) {\n\t\t\tfor (ContextConfigurationAttributes configAttributes : configAttributesList) {\n\t\t\t\taddConfigAttributesClasses(configAttributes, classes);\n\t\t\t}\n\t\t}\n\t\treturn super.resolveContextLoader(testClass, configAttributesList);\n\t}\n\n\tprivate void addConfigAttributesClasses(ContextConfigurationAttributes configAttributes, Class<?>[] classes) {\n\t\tSet<Class<?>> combined = new LinkedHashSet<>(Arrays.asList(classes));\n\t\tif (configAttributes.getClasses() != null) {\n\t\t\tcombined.addAll(Arrays.asList(configAttributes.getClasses()));\n\t\t}\n\t\tconfigAttributes.setClasses(ClassUtils.toClassArray(combined));\n\t}\n\n\t@Override\n\tprotected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) {\n\t\treturn SpringBootContextLoader.class;\n\t}\n\n\t@Override\n\tprotected MergedContextConfiguration processMergedContextConfiguration(MergedContextConfiguration mergedConfig) {\n\t\tClass<?>[] classes = getOrFindConfigurationClasses(mergedConfig);\n\t\tList<String> propertySourceProperties = getAndProcessPropertySourceProperties(mergedConfig);\n\t\tmergedConfig = createModifiedConfig(mergedConfig, classes, StringUtils.toStringArray(propertySourceProperties));\n\t\tWebEnvironment webEnvironment = getWebEnvironment(mergedConfig.getTestClass());\n\t\tif (webEnvironment != null && isWebEnvironmentSupported(mergedConfig)) {\n\t\t\tWebApplicationType webApplicationType = getWebApplicationType(mergedConfig);\n\t\t\tif (webApplicationType == WebApplicationType.SERVLET\n\t\t\t\t\t&& (webEnvironment.isEmbedded() || webEnvironment == WebEnvironment.MOCK)) {\n\t\t\t\tmergedConfig = new WebMergedContextConfiguration(mergedConfig, determineResourceBasePath(mergedConfig));\n\t\t\t}\n\t\t\telse if (webApplicationType == WebApplicationType.REACTIVE\n\t\t\t\t\t&& (webEnvironment.isEmbedded() || webEnvironment == WebEnvironment.MOCK)) {\n\t\t\t\treturn new ReactiveWebMergedContextConfiguration(mergedConfig);\n\t\t\t}\n\t\t}\n\t\treturn mergedConfig;\n\t}\n\n\tprivate WebApplicationType getWebApplicationType(MergedContextConfiguration configuration) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(\n\t\t\t\tTestPropertySourceUtils.convertInlinedPropertiesToMap(configuration.getPropertySourceProperties()));\n\t\tBinder binder = new Binder(source);\n\t\treturn binder.bind(\"spring.main.web-application-type\", Bindable.of(WebApplicationType.class))\n\t\t\t.orElseGet(WebApplicationType::deduce);\n\t}\n\n\t/**\n\t * Determines the resource base path for web applications using the value of\n\t * {@link WebAppConfiguration @WebAppConfiguration}, if any, on the test class of the\n\t * given {@code configuration}. Defaults to {@code src/main/webapp} in its absence.\n\t * @param configuration the configuration to examine\n\t * @return the resource base path\n\t * @since 2.1.6\n\t */\n\tprotected String determineResourceBasePath(MergedContextConfiguration configuration) {\n\t\treturn MergedAnnotations.from(configuration.getTestClass(), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(WebAppConfiguration.class)\n\t\t\t.getValue(MergedAnnotation.VALUE, String.class)\n\t\t\t.orElse(\"src/main/webapp\");\n\t}\n\n\tprivate boolean isWebEnvironmentSupported(MergedContextConfiguration mergedConfig) {\n\t\tClass<?> testClass = mergedConfig.getTestClass();\n\t\tContextHierarchy hierarchy = AnnotationUtils.getAnnotation(testClass, ContextHierarchy.class);\n\t\tif (hierarchy == null || hierarchy.value().length == 0) {\n\t\t\treturn true;\n\t\t}\n\t\tContextConfiguration[] configurations = hierarchy.value();\n\t\treturn isFromConfiguration(mergedConfig, configurations[configurations.length - 1]);\n\t}\n\n\tprivate boolean isFromConfiguration(MergedContextConfiguration candidateConfig,\n\t\t\tContextConfiguration configuration) {\n\t\tContextConfigurationAttributes attributes = new ContextConfigurationAttributes(candidateConfig.getTestClass(),\n\t\t\t\tconfiguration);\n\t\tSet<Class<?>> configurationClasses = new HashSet<>(Arrays.asList(attributes.getClasses()));\n\t\tfor (Class<?> candidate : candidateConfig.getClasses()) {\n\t\t\tif (configurationClasses.contains(candidate)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprotected Class<?>[] getOrFindConfigurationClasses(MergedContextConfiguration mergedConfig) {\n\t\tClass<?>[] classes = mergedConfig.getClasses();\n\t\tif (containsNonTestComponent(classes) || mergedConfig.hasLocations()) {\n\t\t\treturn classes;\n\t\t}\n\t\tClass<?> found = findConfigurationClass(mergedConfig.getTestClass());\n\t\tlogger.info(\"Found @SpringBootConfiguration \" + found.getName() + \" for test \" + mergedConfig.getTestClass());\n\t\treturn merge(found, classes);\n\t}\n\n\tprivate Class<?> findConfigurationClass(Class<?> testClass) {\n\t\tString propertyName = \"%s.SpringBootConfiguration.%s\"\n\t\t\t.formatted(SpringBootTestContextBootstrapper.class.getName(), testClass.getName());\n\t\tString foundClassName = this.aotTestAttributes.getString(propertyName);\n\t\tif (foundClassName != null) {\n\t\t\treturn ClassUtils.resolveClassName(foundClassName, testClass.getClassLoader());\n\t\t}\n\t\tClass<?> found = new AnnotatedClassFinder(SpringBootConfiguration.class).findFromClass(testClass);\n\t\tAssert.state(found != null,\n\t\t\t\t\"Unable to find a @SpringBootConfiguration by searching packages upwards from the test. \"\n\t\t\t\t\t\t+ \"You can use @ContextConfiguration, @SpringBootTest(classes=...) or other Spring Test \"\n\t\t\t\t\t\t+ \"supported mechanisms to explicitly declare the configuration classes to load. Classes \"\n\t\t\t\t\t\t+ \"annotated with @TestConfiguration are not considered.\");\n\t\tthis.aotTestAttributes.setAttribute(propertyName, found.getName());\n\t\treturn found;\n\t}\n\n\tprivate boolean containsNonTestComponent(Class<?>[] classes) {\n\t\tfor (Class<?> candidate : classes) {\n\t\t\tif (!MergedAnnotations.from(candidate, SearchStrategy.INHERITED_ANNOTATIONS)\n\t\t\t\t.isPresent(TestConfiguration.class)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Class<?>[] merge(Class<?> head, Class<?>[] existing) {\n\t\tClass<?>[] result = new Class<?>[existing.length + 1];\n\t\tresult[0] = head;\n\t\tSystem.arraycopy(existing, 0, result, 1, existing.length);\n\t\treturn result;\n\t}\n\n\tprivate List<String> getAndProcessPropertySourceProperties(MergedContextConfiguration mergedConfig) {\n\t\tList<String> propertySourceProperties = new ArrayList<>(\n\t\t\t\tArrays.asList(mergedConfig.getPropertySourceProperties()));\n\t\tString differentiator = getDifferentiatorPropertySourceProperty();\n\t\tif (differentiator != null) {\n\t\t\tpropertySourceProperties.add(differentiator);\n\t\t}\n\t\tprocessPropertySourceProperties(mergedConfig, propertySourceProperties);\n\t\treturn propertySourceProperties;\n\t}\n\n\t/**\n\t * Return a \"differentiator\" property to ensure that there is something to\n\t * differentiate regular tests and bootstrapped tests. Without this property a cached\n\t * context could be returned that wasn't created by this bootstrapper. By default uses\n\t * the bootstrapper class as a property.\n\t * @return the differentiator or {@code null}\n\t */\n\tprotected @Nullable String getDifferentiatorPropertySourceProperty() {\n\t\treturn getClass().getName() + \"=true\";\n\t}\n\n\t/**\n\t * Post process the property source properties, adding or removing elements as\n\t * required.\n\t * @param mergedConfig the merged context configuration\n\t * @param propertySourceProperties the property source properties to process\n\t */\n\tprotected void processPropertySourceProperties(MergedContextConfiguration mergedConfig,\n\t\t\tList<String> propertySourceProperties) {\n\t\tClass<?> testClass = mergedConfig.getTestClass();\n\t\tString[] properties = getProperties(testClass);\n\t\tif (!ObjectUtils.isEmpty(properties)) {\n\t\t\t// Added first so that inlined properties from @TestPropertySource take\n\t\t\t// precedence\n\t\t\tpropertySourceProperties.addAll(0, Arrays.asList(properties));\n\t\t}\n\t\tWebEnvironment webEnvironment = getWebEnvironment(testClass);\n\t\tif (webEnvironment == WebEnvironment.RANDOM_PORT) {\n\t\t\tpropertySourceProperties.add(\"server.port=0\");\n\t\t}\n\t\telse if (webEnvironment == WebEnvironment.NONE) {\n\t\t\tpropertySourceProperties.add(\"spring.main.web-application-type=none\");\n\t\t}\n\t}\n\n\t/**\n\t * Return the {@link WebEnvironment} type for this test or null if undefined.\n\t * @param testClass the source test class\n\t * @return the {@link WebEnvironment} or {@code null}\n\t */\n\tprotected @Nullable WebEnvironment getWebEnvironment(Class<?> testClass) {\n\t\tSpringBootTest annotation = getAnnotation(testClass);\n\t\treturn (annotation != null) ? annotation.webEnvironment() : null;\n\t}\n\n\tprotected Class<?> @Nullable [] getClasses(Class<?> testClass) {\n\t\tSpringBootTest annotation = getAnnotation(testClass);\n\t\treturn (annotation != null) ? annotation.classes() : null;\n\t}\n\n\tprotected String @Nullable [] getProperties(Class<?> testClass) {\n\t\tSpringBootTest annotation = getAnnotation(testClass);\n\t\treturn (annotation != null) ? annotation.properties() : null;\n\t}\n\n\tprotected @Nullable SpringBootTest getAnnotation(Class<?> testClass) {\n\t\treturn TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class);\n\t}\n\n\tprotected void verifyConfiguration(Class<?> testClass) {\n\t\tSpringBootTest springBootTest = getAnnotation(testClass);\n\t\tif (springBootTest != null && isListeningOnPort(springBootTest.webEnvironment())\n\t\t\t\t&& MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)\n\t\t\t\t\t.isPresent(WebAppConfiguration.class)) {\n\t\t\tthrow new IllegalStateException(\"@WebAppConfiguration should only be used \"\n\t\t\t\t\t+ \"with @SpringBootTest when @SpringBootTest is configured with a \"\n\t\t\t\t\t+ \"mock web environment. Please remove @WebAppConfiguration or reconfigure @SpringBootTest.\");\n\t\t}\n\t}\n\n\tprivate boolean isListeningOnPort(WebEnvironment webEnvironment) {\n\t\treturn webEnvironment == WebEnvironment.DEFINED_PORT || webEnvironment == WebEnvironment.RANDOM_PORT;\n\t}\n\n\t/**\n\t * Create a new {@link MergedContextConfiguration} with different classes.\n\t * @param mergedConfig the source config\n\t * @param classes the replacement classes\n\t * @return a new {@link MergedContextConfiguration}\n\t */\n\tprotected final MergedContextConfiguration createModifiedConfig(MergedContextConfiguration mergedConfig,\n\t\t\tClass<?>[] classes) {\n\t\treturn createModifiedConfig(mergedConfig, classes, mergedConfig.getPropertySourceProperties());\n\t}\n\n\t/**\n\t * Create a new {@link MergedContextConfiguration} with different classes and\n\t * properties.\n\t * @param mergedConfig the source config\n\t * @param classes the replacement classes\n\t * @param propertySourceProperties the replacement properties\n\t * @return a new {@link MergedContextConfiguration}\n\t */\n\tprotected final MergedContextConfiguration createModifiedConfig(MergedContextConfiguration mergedConfig,\n\t\t\tClass<?>[] classes, String[] propertySourceProperties) {\n\t\tSet<ContextCustomizer> contextCustomizers = new LinkedHashSet<>(mergedConfig.getContextCustomizers());\n\t\tcontextCustomizers.add(new SpringBootTestAnnotation(mergedConfig.getTestClass()));\n\t\treturn new MergedContextConfiguration(mergedConfig.getTestClass(), mergedConfig.getLocations(), classes,\n\t\t\t\tmergedConfig.getContextInitializerClasses(), mergedConfig.getActiveProfiles(),\n\t\t\t\tmergedConfig.getPropertySourceDescriptors(), propertySourceProperties, contextCustomizers,\n\t\t\t\tmergedConfig.getContextLoader(), getCacheAwareContextLoaderDelegate(), mergedConfig.getParent());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/TestComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link Component @Component} that can be used when a bean is intended only for tests,\n * and should be excluded from Spring Boot's component scanning.\n * <p>\n * Note that if you directly use {@link ComponentScan @ComponentScan} rather than relying\n * on {@code @SpringBootApplication} you should ensure that a {@link TypeExcludeFilter} is\n * declared as an {@link ComponentScan#excludeFilters() excludeFilter}.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see TypeExcludeFilter\n * @see TestConfiguration\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Component\npublic @interface TestComponent {\n\n\t/**\n\t * The value may indicate a suggestion for a logical component name, to be turned into\n\t * a Spring bean in case of an auto-detected component.\n\t * @return the specified bean name, if any\n\t */\n\t@AliasFor(annotation = Component.class)\n\tString value() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/TestConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * {@link Configuration @Configuration} that can be used to define additional beans or\n * customizations for a test. Unlike regular {@code @Configuration} classes the use of\n * {@code @TestConfiguration} does not prevent auto-detection of\n * {@link SpringBootConfiguration @SpringBootConfiguration}.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see SpringBootTestContextBootstrapper\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Configuration\n@TestComponent\npublic @interface TestConfiguration {\n\n\t/**\n\t * Explicitly specify the name of the Spring bean definition associated with this\n\t * Configuration class. See {@link Configuration#value()} for details.\n\t * @return the specified bean name, if any\n\t */\n\t@AliasFor(annotation = Configuration.class)\n\tString value() default \"\";\n\n\t/**\n\t * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce\n\t * bean lifecycle behavior, e.g. to return shared singleton bean instances even in\n\t * case of direct {@code @Bean} method calls in user code. This feature requires\n\t * method interception, implemented through a runtime-generated CGLIB subclass which\n\t * comes with limitations such as the configuration class and its methods not being\n\t * allowed to declare {@code final}.\n\t * <p>\n\t * The default is {@code true}, allowing for 'inter-bean references' within the\n\t * configuration class as well as for external calls to this configuration's\n\t * {@code @Bean} methods, e.g. from another configuration class. If this is not needed\n\t * since each of this particular configuration's {@code @Bean} methods is\n\t * self-contained and designed as a plain factory method for container use, switch\n\t * this flag to {@code false} in order to avoid CGLIB subclass processing.\n\t * <p>\n\t * Turning off bean method interception effectively processes {@code @Bean} methods\n\t * individually like when declared on non-{@code @Configuration} classes, a.k.a.\n\t * \"@Bean Lite Mode\" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally\n\t * equivalent to removing the {@code @Configuration} stereotype.\n\t * @return whether to proxy {@code @Bean} methods\n\t * @since 2.2.1\n\t */\n\t@AliasFor(annotation = Configuration.class)\n\tboolean proxyBeanMethods() default true;\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.io.BufferedReader;\nimport java.io.PrintWriter;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.util.Map;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AbstractObjectArrayAssert;\nimport org.assertj.core.api.AbstractObjectAssert;\nimport org.assertj.core.api.AbstractThrowableAssert;\nimport org.assertj.core.api.MapAssert;\nimport org.assertj.core.error.BasicErrorMessageFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.lang.CheckReturnValue;\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied to an\n * {@link ApplicationContext}.\n *\n * @param <C> the application context type\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.0.0\n * @see ApplicationContextRunner\n * @see AssertableApplicationContext\n */\npublic class ApplicationContextAssert<C extends ApplicationContext>\n\t\textends AbstractAssert<ApplicationContextAssert<C>, C> {\n\n\tprivate final @Nullable Throwable startupFailure;\n\n\t/**\n\t * Create a new {@link ApplicationContextAssert} instance.\n\t * @param applicationContext the source application context\n\t * @param startupFailure the startup failure or {@code null}\n\t */\n\tApplicationContextAssert(C applicationContext, @Nullable Throwable startupFailure) {\n\t\tsuper(applicationContext, ApplicationContextAssert.class);\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tthis.startupFailure = startupFailure;\n\t}\n\n\t/**\n\t * Verifies that the application context contains a bean with the given name.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).hasBean(\"fooBean\"); </pre>\n\t * @param name the name of the bean\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context does not contain a bean with the\n\t * given name\n\t */\n\tpublic ApplicationContextAssert<C> hasBean(String name) {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(\n\t\t\t\t\tcontextFailedToStartWhenExpecting(this.startupFailure, \"to have bean named:%n <%s>\", name));\n\t\t}\n\t\tif (findBean(name) == null) {\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nto have bean named:%n <%s>%nbut found no such bean\", getApplicationContext(),\n\t\t\t\t\tname));\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the application context (or ancestors) contains a single bean with\n\t * the given type.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).hasSingleBean(Foo.class); </pre>\n\t * @param type the bean type\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context does no beans of the given type\n\t * @throws AssertionError if the application context contains multiple beans of the\n\t * given type\n\t */\n\tpublic ApplicationContextAssert<C> hasSingleBean(Class<?> type) {\n\t\treturn hasSingleBean(type, Scope.INCLUDE_ANCESTORS);\n\t}\n\n\t/**\n\t * Verifies that the application context contains a single bean with the given type.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).hasSingleBean(Foo.class, Scope.NO_ANCESTORS); </pre>\n\t * @param type the bean type\n\t * @param scope the scope of the assertion\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context does no beans of the given type\n\t * @throws AssertionError if the application context contains multiple beans of the\n\t * given type\n\t */\n\tpublic ApplicationContextAssert<C> hasSingleBean(Class<?> type, Scope scope) {\n\t\tAssert.notNull(scope, \"'scope' must not be null\");\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,\n\t\t\t\t\t\"to have a single bean of type:%n <%s>\", type));\n\t\t}\n\t\tString[] names = scope.getBeanNamesForType(getApplicationContext(), type);\n\t\tif (names.length == 0) {\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nto have a single bean of type:%n <%s>%nbut found no beans of that type\",\n\t\t\t\t\tgetApplicationContext(), type));\n\t\t}\n\t\tif (names.length > 1) {\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nto have a single bean of type:%n <%s>%nbut found:%n <%s>\",\n\t\t\t\t\tgetApplicationContext(), type, names));\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the application context (or ancestors) does not contain any beans of\n\t * the given type.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).doesNotHaveBean(Foo.class); </pre>\n\t * @param type the bean type\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context contains any beans of the given\n\t * type\n\t */\n\tpublic ApplicationContextAssert<C> doesNotHaveBean(Class<?> type) {\n\t\treturn doesNotHaveBean(type, Scope.INCLUDE_ANCESTORS);\n\t}\n\n\t/**\n\t * Verifies that the application context does not contain any beans of the given type.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).doesNotHaveBean(Foo.class, Scope.NO_ANCESTORS); </pre>\n\t * @param type the bean type\n\t * @param scope the scope of the assertion\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context contains any beans of the given\n\t * type\n\t */\n\tpublic ApplicationContextAssert<C> doesNotHaveBean(Class<?> type, Scope scope) {\n\t\tAssert.notNull(scope, \"'scope' must not be null\");\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,\n\t\t\t\t\t\"not to have any beans of type:%n <%s>\", type));\n\t\t}\n\t\tString[] names = scope.getBeanNamesForType(getApplicationContext(), type);\n\t\tif (names.length > 0) {\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nnot to have any beans of type:%n <%s>%nbut found:%n <%s>\",\n\t\t\t\t\tgetApplicationContext(), type, names));\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the application context does not contain a beans of the given name.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).doesNotHaveBean(\"fooBean\"); </pre>\n\t * @param name the name of the bean\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context contains a beans of the given\n\t * name\n\t */\n\tpublic ApplicationContextAssert<C> doesNotHaveBean(String name) {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,\n\t\t\t\t\t\"not to have any beans of name:%n <%s>\", name));\n\t\t}\n\t\ttry {\n\t\t\tObject bean = getApplicationContext().getBean(name);\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nnot to have a bean of name:%n <%s>%nbut found:%n <%s>\",\n\t\t\t\t\tgetApplicationContext(), name, bean));\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Obtain the beans names of the given type from the application context, the names\n\t * becoming the object array under test.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBeanNames(Foo.class).containsOnly(\"fooBean\"); </pre>\n\t * @param <T> the bean type\n\t * @param type the bean type\n\t * @return array assertions for the bean names\n\t * @throws AssertionError if the application context did not start\n\t */\n\t@CheckReturnValue\n\tpublic <T> AbstractObjectArrayAssert<?, String> getBeanNames(Class<T> type) {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,\n\t\t\t\t\t\"to get beans names with type:%n <%s>\", type));\n\t\t}\n\t\treturn assertThat(getApplicationContext().getBeanNamesForType(type)).as(\"Bean names of type <%s> from <%s>\",\n\t\t\t\ttype, getApplicationContext());\n\t}\n\n\t/**\n\t * Obtain a single bean of the given type from the application context (or ancestors),\n\t * the bean becoming the object under test. If no beans of the specified type can be\n\t * found an assert on {@code null} is returned.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBean(Foo.class).isInstanceOf(DefaultFoo.class);\n\t * assertThat(context).getBean(Bar.class).isNull();</pre>\n\t * @param <T> the bean type\n\t * @param type the bean type\n\t * @return bean assertions for the bean, or an assert on {@code null} if the no bean\n\t * is found\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context contains multiple beans of the\n\t * given type\n\t */\n\t@CheckReturnValue\n\tpublic <T> AbstractObjectAssert<?, T> getBean(Class<T> type) {\n\t\treturn getBean(type, Scope.INCLUDE_ANCESTORS);\n\t}\n\n\t/**\n\t * Obtain a single bean of the given type from the application context, the bean\n\t * becoming the object under test. If no beans of the specified type can be found an\n\t * assert on {@code null} is returned.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBean(Foo.class, Scope.NO_ANCESTORS).isInstanceOf(DefaultFoo.class);\n\t * assertThat(context).getBean(Bar.class, Scope.NO_ANCESTORS).isNull();</pre>\n\t * @param <T> the bean type\n\t * @param type the bean type\n\t * @param scope the scope of the assertion\n\t * @return bean assertions for the bean, or an assert on {@code null} if the no bean\n\t * is found\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context contains multiple beans of the\n\t * given type\n\t */\n\t@CheckReturnValue\n\tpublic <T> AbstractObjectAssert<?, T> getBean(Class<T> type, Scope scope) {\n\t\tAssert.notNull(scope, \"'scope' must not be null\");\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(\n\t\t\t\t\tcontextFailedToStartWhenExpecting(this.startupFailure, \"to contain bean of type:%n <%s>\", type));\n\t\t}\n\t\tString[] names = scope.getBeanNamesForType(getApplicationContext(), type);\n\t\tString name = (names.length > 0) ? getPrimary(names, scope) : null;\n\t\tif (names.length > 1 && name == null) {\n\t\t\tthrowAssertionError(\n\t\t\t\t\tnew BasicErrorMessageFactory(\"%nExpecting:%n <%s>%nsingle bean of type:%n <%s>%nbut found:%n <%s>\",\n\t\t\t\t\t\t\tgetApplicationContext(), type, names));\n\t\t}\n\t\tT bean = (name != null) ? getApplicationContext().getBean(name, type) : null;\n\t\treturn assertThat(bean).as(\"Bean of type <%s> from <%s>\", type, getApplicationContext());\n\t}\n\n\tprivate @Nullable String getPrimary(String[] names, Scope scope) {\n\t\tif (names.length == 1) {\n\t\t\treturn names[0];\n\t\t}\n\t\tString primary = null;\n\t\tfor (String name : names) {\n\t\t\tif (isPrimary(name, scope)) {\n\t\t\t\tif (primary != null) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tprimary = name;\n\t\t\t}\n\t\t}\n\t\treturn primary;\n\t}\n\n\tprivate boolean isPrimary(String name, Scope scope) {\n\t\tApplicationContext context = getApplicationContext();\n\t\twhile (context != null) {\n\t\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\t\tConfigurableListableBeanFactory factory = configurableContext.getBeanFactory();\n\t\t\t\tif (factory.containsBean(name) && factory.getMergedBeanDefinition(name).isPrimary()) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontext = (scope != Scope.NO_ANCESTORS) ? context.getParent() : null;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Obtain a single bean of the given name from the application context, the bean\n\t * becoming the object under test. If no bean of the specified name can be found an\n\t * assert on {@code null} is returned.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBean(\"foo\").isInstanceOf(Foo.class);\n\t * assertThat(context).getBean(\"foo\").isNull();</pre>\n\t * @param name the name of the bean\n\t * @return bean assertions for the bean, or an assert on {@code null} if the no bean\n\t * is found\n\t * @throws AssertionError if the application context did not start\n\t */\n\t@CheckReturnValue\n\tpublic AbstractObjectAssert<?, Object> getBean(String name) {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(\n\t\t\t\t\tcontextFailedToStartWhenExpecting(this.startupFailure, \"to contain a bean of name:%n <%s>\", name));\n\t\t}\n\t\tObject bean = findBean(name);\n\t\treturn assertThat(bean).as(\"Bean of name <%s> from <%s>\", name, getApplicationContext());\n\t}\n\n\t/**\n\t * Obtain a single bean of the given name and type from the application context, the\n\t * bean becoming the object under test. If no bean of the specified name can be found\n\t * an assert on {@code null} is returned.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBean(\"foo\", Foo.class).isInstanceOf(DefaultFoo.class);\n\t * assertThat(context).getBean(\"foo\", Foo.class).isNull();</pre>\n\t * @param <T> the bean type\n\t * @param name the name of the bean\n\t * @param type the bean type\n\t * @return bean assertions for the bean, or an assert on {@code null} if the no bean\n\t * is found\n\t * @throws AssertionError if the application context did not start\n\t * @throws AssertionError if the application context contains a bean with the given\n\t * name but a different type\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\t@CheckReturnValue\n\tpublic <T> AbstractObjectAssert<?, T> getBean(String name, Class<T> type) {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(contextFailedToStartWhenExpecting(this.startupFailure,\n\t\t\t\t\t\"to contain a bean of name:%n <%s> (%s)\", name, type));\n\t\t}\n\t\tObject bean = findBean(name);\n\t\tif (bean != null && type != null && !type.isInstance(bean)) {\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nto contain a bean of name:%n <%s> (%s)%nbut found:%n <%s> of type <%s>\",\n\t\t\t\t\tgetApplicationContext(), name, type, bean, bean.getClass()));\n\t\t}\n\t\treturn assertThat((T) bean).as(\"Bean of name <%s> and type <%s> from <%s>\", name, type,\n\t\t\t\tgetApplicationContext());\n\t}\n\n\tprivate @Nullable Object findBean(String name) {\n\t\ttry {\n\t\t\treturn getApplicationContext().getBean(name);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Obtain a map bean names and instances of the given type from the application\n\t * context (or ancestors), the map becoming the object under test. If no bean of the\n\t * specified type can be found an assert on an empty {@code map} is returned.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBeans(Foo.class).containsKey(\"foo\");\n\t * </pre>\n\t * @param <T> the bean type\n\t * @param type the bean type\n\t * @return bean assertions for the beans, or an assert on an empty {@code map} if the\n\t * no beans are found\n\t * @throws AssertionError if the application context did not start\n\t */\n\t@CheckReturnValue\n\tpublic <T> MapAssert<String, T> getBeans(Class<T> type) {\n\t\treturn getBeans(type, Scope.INCLUDE_ANCESTORS);\n\t}\n\n\t/**\n\t * Obtain a map bean names and instances of the given type from the application\n\t * context, the map becoming the object under test. If no bean of the specified type\n\t * can be found an assert on an empty {@code map} is returned.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getBeans(Foo.class, Scope.NO_ANCESTORS).containsKey(\"foo\");\n\t * </pre>\n\t * @param <T> the bean type\n\t * @param type the bean type\n\t * @param scope the scope of the assertion\n\t * @return bean assertions for the beans, or an assert on an empty {@code map} if the\n\t * no beans are found\n\t * @throws AssertionError if the application context did not start\n\t */\n\t@CheckReturnValue\n\tpublic <T> MapAssert<String, T> getBeans(Class<T> type, Scope scope) {\n\t\tAssert.notNull(scope, \"'scope' must not be null\");\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(\n\t\t\t\t\tcontextFailedToStartWhenExpecting(this.startupFailure, \"to get beans of type:%n <%s>\", type));\n\t\t}\n\t\treturn assertThat(scope.getBeansOfType(getApplicationContext(), type)).as(\"Beans of type <%s> from <%s>\", type,\n\t\t\t\tgetApplicationContext());\n\t}\n\n\t/**\n\t * Obtain the failure that stopped the application context from running, the failure\n\t * becoming the object under test.\n\t * <p>\n\t * Example: <pre class=\"code\">\n\t * assertThat(context).getFailure().hasMessageContaining(\"missing bean\");\n\t * </pre>\n\t * @return assertions on the cause of the failure\n\t * @throws AssertionError if the application context started without a failure\n\t */\n\t@CheckReturnValue\n\tpublic AbstractThrowableAssert<?, ? extends Throwable> getFailure() {\n\t\thasFailed();\n\t\treturn assertThat(this.startupFailure);\n\t}\n\n\t/**\n\t * Verifies that the application has failed to start.\n\t * <p>\n\t * Example: <pre class=\"code\"> assertThat(context).hasFailed();\n\t * </pre>\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context started without a failure\n\t */\n\tpublic ApplicationContextAssert<C> hasFailed() {\n\t\tif (this.startupFailure == null) {\n\t\t\tthrowAssertionError(new BasicErrorMessageFactory(\n\t\t\t\t\t\"%nExpecting:%n <%s>%nto have failed%nbut context started successfully\", getApplicationContext()));\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the application has not failed to start.\n\t * <p>\n\t * Example: <pre class=\"code\"> assertThat(context).hasNotFailed();\n\t * </pre>\n\t * @return {@code this} assertion object.\n\t * @throws AssertionError if the application context failed to start\n\t */\n\tpublic ApplicationContextAssert<C> hasNotFailed() {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrowAssertionError(contextFailedToStartWhenExpecting(this.startupFailure, \"to have not failed\"));\n\t\t}\n\t\treturn this;\n\t}\n\n\tprotected final C getApplicationContext() {\n\t\treturn this.actual;\n\t}\n\n\tprotected final @Nullable Throwable getStartupFailure() {\n\t\treturn this.startupFailure;\n\t}\n\n\tprivate ContextFailedToStart<C> contextFailedToStartWhenExpecting(Throwable startupFailure,\n\t\t\tString expectationFormat, Object... arguments) {\n\t\treturn new ContextFailedToStart<>(getApplicationContext(), startupFailure, expectationFormat, arguments);\n\t}\n\n\t/**\n\t * The scope of an assertion.\n\t */\n\tpublic enum Scope {\n\n\t\t/**\n\t\t * Limited to the current context.\n\t\t */\n\t\tNO_ANCESTORS {\n\t\t\t@Override\n\t\t\tString[] getBeanNamesForType(ApplicationContext applicationContext, Class<?> type) {\n\t\t\t\treturn applicationContext.getBeanNamesForType(type);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\t<T> Map<String, T> getBeansOfType(ApplicationContext applicationContext, Class<T> type) {\n\t\t\t\treturn applicationContext.getBeansOfType(type);\n\t\t\t}\n\n\t\t},\n\n\t\t/**\n\t\t * Consider the ancestor contexts as well as the current context.\n\t\t */\n\t\tINCLUDE_ANCESTORS {\n\t\t\t@Override\n\t\t\tString[] getBeanNamesForType(ApplicationContext applicationContext, Class<?> type) {\n\t\t\t\treturn BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, type);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\t<T> Map<String, T> getBeansOfType(ApplicationContext applicationContext, Class<T> type) {\n\t\t\t\treturn BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, type);\n\t\t\t}\n\n\t\t};\n\n\t\tabstract String[] getBeanNamesForType(ApplicationContext applicationContext, Class<?> type);\n\n\t\tabstract <T> Map<String, T> getBeansOfType(ApplicationContext applicationContext, Class<T> type);\n\n\t}\n\n\tprivate static final class ContextFailedToStart<C extends ApplicationContext> extends BasicErrorMessageFactory {\n\n\t\tprivate ContextFailedToStart(C context, Throwable ex, String expectationFormat, Object... arguments) {\n\t\t\tsuper(\"%nExpecting:%n <%s>%n\" + expectationFormat + \":%nbut context failed to start:%n%s\",\n\t\t\t\t\tcombineArguments(context.toString(), ex, arguments));\n\t\t}\n\n\t\tprivate static Object[] combineArguments(String context, Throwable ex, Object[] arguments) {\n\t\t\tObject[] combinedArguments = new Object[arguments.length + 2];\n\t\t\tcombinedArguments[0] = unquotedString(context);\n\t\t\tSystem.arraycopy(arguments, 0, combinedArguments, 1, arguments.length);\n\t\t\tcombinedArguments[combinedArguments.length - 1] = unquotedString(getIndentedStackTraceAsString(ex));\n\t\t\treturn combinedArguments;\n\t\t}\n\n\t\tprivate static String getIndentedStackTraceAsString(Throwable ex) {\n\t\t\tString stackTrace = getStackTraceAsString(ex);\n\t\t\treturn indent(stackTrace);\n\t\t}\n\n\t\tprivate static String getStackTraceAsString(Throwable ex) {\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\tPrintWriter printer = new PrintWriter(writer);\n\t\t\tex.printStackTrace(printer);\n\t\t\treturn writer.toString();\n\t\t}\n\n\t\tprivate static String indent(String input) {\n\t\t\tBufferedReader reader = new BufferedReader(new StringReader(input));\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\tPrintWriter printer = new PrintWriter(writer);\n\t\t\treader.lines().forEach((line) -> {\n\t\t\t\tprinter.print(\" \");\n\t\t\t\tprinter.println(line);\n\t\t\t});\n\t\t\treturn writer.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.io.Closeable;\nimport java.lang.reflect.Proxy;\nimport java.util.Arrays;\nimport java.util.function.Supplier;\n\nimport org.assertj.core.api.AssertProvider;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * An {@link ApplicationContext} that additionally supports AssertJ style assertions. Can\n * be used to decorate an existing application context or an application context that\n * failed to start.\n * <p>\n * Assertions can be applied using the standard AssertJ {@code assertThat(...)} style (see\n * {@link ApplicationContextAssert} for a complete list). For example: <pre class=\"code\">\n * assertThat(applicationContext).hasSingleBean(MyBean.class);\n * </pre>\n * <p>\n * If the original {@link ApplicationContext} is needed for any reason the\n * {@link #getSourceApplicationContext()} method can be used.\n * <p>\n * Any {@link ApplicationContext} method called on a context that has failed to start will\n * throw an {@link IllegalStateException}.\n *\n * @param <C> the application context type\n * @author Phillip Webb\n * @since 2.0.0\n * @see AssertableApplicationContext\n * @see AssertableWebApplicationContext\n * @see AssertableReactiveWebApplicationContext\n * @see ApplicationContextAssert\n */\npublic interface ApplicationContextAssertProvider<C extends ApplicationContext>\n\t\textends ApplicationContext, AssertProvider<ApplicationContextAssert<C>>, Closeable {\n\n\t/**\n\t * Return an assert for AspectJ.\n\t * @return an AspectJ assert\n\t * @deprecated to prevent accidental use. Prefer standard AssertJ\n\t * {@code assertThat(context)...} calls instead.\n\t */\n\t@Deprecated(since = \"2.0.0\", forRemoval = false)\n\t@Override\n\tApplicationContextAssert<C> assertThat();\n\n\t/**\n\t * Return the original source {@link ApplicationContext}.\n\t * @return the source application context\n\t * @throws IllegalStateException if the source context failed to start\n\t */\n\tC getSourceApplicationContext();\n\n\t/**\n\t * Return the original source {@link ApplicationContext}, casting it to the requested\n\t * type.\n\t * @param <T> the context type\n\t * @param requiredType the required context type\n\t * @return the source application context\n\t * @throws IllegalStateException if the source context failed to start\n\t */\n\t<T extends C> T getSourceApplicationContext(Class<T> requiredType);\n\n\t/**\n\t * Return the failure that caused application context to fail or {@code null} if the\n\t * context started without issue.\n\t * @return the startup failure or {@code null}\n\t */\n\t@Nullable Throwable getStartupFailure();\n\n\t@Override\n\tvoid close();\n\n\t/**\n\t * Factory method to create a new {@link ApplicationContextAssertProvider} instance.\n\t * @param <T> the assert provider type\n\t * @param <C> the context type\n\t * @param type the type of {@link ApplicationContextAssertProvider} required (must be\n\t * an interface)\n\t * @param contextType the type of {@link ApplicationContext} being managed (must be an\n\t * interface)\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ApplicationContext} or throw an exception if the context fails to start.\n\t * @return a {@link ApplicationContextAssertProvider} instance\n\t */\n\tstatic <T extends ApplicationContextAssertProvider<C>, C extends ApplicationContext> T get(Class<T> type,\n\t\t\tClass<? extends C> contextType, Supplier<? extends C> contextSupplier) {\n\t\treturn get(type, contextType, contextSupplier, new Class<?>[0]);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link ApplicationContextAssertProvider} instance.\n\t * @param <T> the assert provider type\n\t * @param <C> the context type\n\t * @param type the type of {@link ApplicationContextAssertProvider} required (must be\n\t * an interface)\n\t * @param contextType the type of {@link ApplicationContext} being managed (must be an\n\t * interface)\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ApplicationContext} or throw an exception if the context fails to start.\n\t * @param additionalContextInterfaces and additional context interfaces to add to the\n\t * proxy\n\t * @return a {@link ApplicationContextAssertProvider} instance\n\t * @since 3.4.0\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <T extends ApplicationContextAssertProvider<C>, C extends ApplicationContext> T get(Class<T> type,\n\t\t\tClass<? extends C> contextType, Supplier<? extends C> contextSupplier,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tAssert.isTrue(type.isInterface(), \"'type' must be an interface\");\n\t\tAssert.notNull(contextType, \"'contextType' must not be null\");\n\t\tAssert.isTrue(contextType.isInterface(), \"'contextType' must be an interface\");\n\t\tClass<?>[] interfaces = merge(new Class<?>[] { type, contextType }, additionalContextInterfaces);\n\t\treturn (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces,\n\t\t\t\tnew AssertProviderApplicationContextInvocationHandler(contextType, contextSupplier));\n\t}\n\n\tprivate static Class<?>[] merge(Class<?>[] classes, Class<?>[] additional) {\n\t\tif (ObjectUtils.isEmpty(additional)) {\n\t\t\treturn classes;\n\t\t}\n\t\tClass<?>[] result = Arrays.copyOf(classes, classes.length + additional.length);\n\t\tSystem.arraycopy(additional, 0, result, classes.length, additional.length);\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertProviderApplicationContextInvocationHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link InvocationHandler} used by {@link ApplicationContextAssertProvider} generated\n * proxies.\n *\n * @author Phillip Webb\n */\nclass AssertProviderApplicationContextInvocationHandler implements InvocationHandler {\n\n\tprivate final Class<?> applicationContextType;\n\n\tprivate final @Nullable ApplicationContext applicationContext;\n\n\tprivate final @Nullable RuntimeException startupFailure;\n\n\tAssertProviderApplicationContextInvocationHandler(Class<?> applicationContextType, Supplier<?> contextSupplier) {\n\t\tthis.applicationContextType = applicationContextType;\n\t\tObject contextOrStartupFailure = getContextOrStartupFailure(contextSupplier);\n\t\tif (contextOrStartupFailure instanceof RuntimeException runtimeException) {\n\t\t\tthis.applicationContext = null;\n\t\t\tthis.startupFailure = runtimeException;\n\t\t}\n\t\telse {\n\t\t\tthis.applicationContext = (ApplicationContext) contextOrStartupFailure;\n\t\t\tthis.startupFailure = null;\n\t\t}\n\t}\n\n\tprivate Object getContextOrStartupFailure(Supplier<?> contextSupplier) {\n\t\ttry {\n\t\t\treturn contextSupplier.get();\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n\t\tif (isToString(method)) {\n\t\t\treturn toString();\n\t\t}\n\t\tif (isGetSourceContext(method)) {\n\t\t\treturn getSourceContext(args);\n\t\t}\n\t\tif (isGetStartupFailure(method)) {\n\t\t\treturn getStartupFailure();\n\t\t}\n\t\tif (isAssertThat(method)) {\n\t\t\treturn getAssertThat(proxy);\n\t\t}\n\t\tif (isCloseMethod(method)) {\n\t\t\treturn invokeClose();\n\t\t}\n\t\treturn invokeApplicationContextMethod(method, args);\n\t}\n\n\tprivate boolean isToString(Method method) {\n\t\treturn (\"toString\".equals(method.getName()) && method.getParameterCount() == 0);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tif (this.startupFailure != null) {\n\t\t\treturn \"Unstarted application context \" + this.applicationContextType.getName() + \"[startupFailure=\"\n\t\t\t\t\t+ this.startupFailure.getClass().getName() + \"]\";\n\t\t}\n\t\tAssert.state(this.applicationContext != null, \"'applicationContext' must not be null\");\n\t\tToStringCreator builder = new ToStringCreator(this.applicationContext)\n\t\t\t.append(\"id\", this.applicationContext.getId())\n\t\t\t.append(\"applicationName\", this.applicationContext.getApplicationName())\n\t\t\t.append(\"beanDefinitionCount\", this.applicationContext.getBeanDefinitionCount());\n\t\treturn \"Started application \" + builder;\n\t}\n\n\tprivate boolean isGetSourceContext(Method method) {\n\t\treturn \"getSourceApplicationContext\".equals(method.getName()) && ((method.getParameterCount() == 0)\n\t\t\t\t|| Arrays.equals(new Class<?>[] { Class.class }, method.getParameterTypes()));\n\t}\n\n\tprivate Object getSourceContext(Object[] args) {\n\t\tApplicationContext context = getStartedApplicationContext();\n\t\tif (!ObjectUtils.isEmpty(args)) {\n\t\t\tAssert.isInstanceOf((Class<?>) args[0], context);\n\t\t}\n\t\treturn context;\n\t}\n\n\tprivate boolean isGetStartupFailure(Method method) {\n\t\treturn (\"getStartupFailure\".equals(method.getName()) && method.getParameterCount() == 0);\n\t}\n\n\tprivate @Nullable Object getStartupFailure() {\n\t\treturn this.startupFailure;\n\t}\n\n\tprivate boolean isAssertThat(Method method) {\n\t\treturn (\"assertThat\".equals(method.getName()) && method.getParameterCount() == 0);\n\t}\n\n\tprivate Object getAssertThat(Object proxy) {\n\t\treturn new ApplicationContextAssert<>((ApplicationContext) proxy, this.startupFailure);\n\t}\n\n\tprivate boolean isCloseMethod(Method method) {\n\t\treturn (\"close\".equals(method.getName()) && method.getParameterCount() == 0);\n\t}\n\n\tprivate @Nullable Object invokeClose() throws IOException {\n\t\tif (this.applicationContext instanceof Closeable closeable) {\n\t\t\tcloseable.close();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Object invokeApplicationContextMethod(Method method, Object[] args) throws Throwable {\n\t\ttry {\n\t\t\treturn method.invoke(getStartedApplicationContext(), args);\n\t\t}\n\t\tcatch (InvocationTargetException ex) {\n\t\t\tthrow ex.getTargetException();\n\t\t}\n\t}\n\n\tprivate ApplicationContext getStartedApplicationContext() {\n\t\tif (this.startupFailure != null) {\n\t\t\tthrow new IllegalStateException(this + \" failed to start\", this.startupFailure);\n\t\t}\n\t\tAssert.state(this.applicationContext != null, \"'applicationContext' must not be null\");\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * An {@link ApplicationContext} that additionally supports AssertJ style assertions. Can\n * be used to decorate an existing application context or an application context that\n * failed to start.\n * <p>\n * See {@link ApplicationContextAssertProvider} for more details.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see ApplicationContextRunner\n * @see ApplicationContext\n */\npublic interface AssertableApplicationContext\n\t\textends ApplicationContextAssertProvider<ConfigurableApplicationContext>, ConfigurableApplicationContext {\n\n\t/**\n\t * Factory method to create a new {@link AssertableApplicationContext} instance.\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ConfigurableApplicationContext} or throw an exception if the context fails\n\t * to start.\n\t * @return an {@link AssertableApplicationContext} instance\n\t */\n\tstatic AssertableApplicationContext get(Supplier<? extends ConfigurableApplicationContext> contextSupplier) {\n\t\treturn ApplicationContextAssertProvider.get(AssertableApplicationContext.class,\n\t\t\t\tConfigurableApplicationContext.class, contextSupplier);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link AssertableApplicationContext} instance.\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ConfigurableApplicationContext} or throw an exception if the context fails\n\t * to start.\n\t * @param additionalContextInterfaces and additional context interfaces to add to the\n\t * proxy\n\t * @return an {@link AssertableApplicationContext} instance\n\t * @since 3.4.0\n\t */\n\tstatic AssertableApplicationContext get(Supplier<? extends ConfigurableApplicationContext> contextSupplier,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\treturn ApplicationContextAssertProvider.get(AssertableApplicationContext.class,\n\t\t\t\tConfigurableApplicationContext.class, contextSupplier, additionalContextInterfaces);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\n\n/**\n * A {@link ReactiveWebApplicationContext} that additionally supports AssertJ style\n * assertions. Can be used to decorate an existing reactive web application context or an\n * application context that failed to start.\n * <p>\n * See {@link ApplicationContextAssertProvider} for more details.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see ReactiveWebApplicationContext\n * @see ReactiveWebApplicationContext\n */\npublic interface AssertableReactiveWebApplicationContext\n\t\textends ApplicationContextAssertProvider<ConfigurableReactiveWebApplicationContext>,\n\t\tConfigurableReactiveWebApplicationContext {\n\n\t/**\n\t * Factory method to create a new {@link AssertableReactiveWebApplicationContext}\n\t * instance.\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ConfigurableReactiveWebApplicationContext} or throw an exception if the\n\t * context fails to start.\n\t * @return a {@link AssertableReactiveWebApplicationContext} instance\n\t */\n\tstatic AssertableReactiveWebApplicationContext get(\n\t\t\tSupplier<? extends ConfigurableReactiveWebApplicationContext> contextSupplier) {\n\t\treturn ApplicationContextAssertProvider.get(AssertableReactiveWebApplicationContext.class,\n\t\t\t\tConfigurableReactiveWebApplicationContext.class, contextSupplier);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link AssertableReactiveWebApplicationContext}\n\t * instance.\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ConfigurableReactiveWebApplicationContext} or throw an exception if the\n\t * context fails to start.\n\t * @param additionalContextInterfaces and additional context interfaces to add to the\n\t * proxy\n\t * @return a {@link AssertableReactiveWebApplicationContext} instance\n\t * @since 3.4.0\n\t */\n\tstatic AssertableReactiveWebApplicationContext get(\n\t\t\tSupplier<? extends ConfigurableReactiveWebApplicationContext> contextSupplier,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\treturn ApplicationContextAssertProvider.get(AssertableReactiveWebApplicationContext.class,\n\t\t\t\tConfigurableReactiveWebApplicationContext.class, contextSupplier, additionalContextInterfaces);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * A {@link WebApplicationContext} that additionally supports AssertJ style assertions.\n * Can be used to decorate an existing servlet web application context or an application\n * context that failed to start.\n * <p>\n * See {@link ApplicationContextAssertProvider} for more details.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see WebApplicationContextRunner\n * @see WebApplicationContext\n */\npublic interface AssertableWebApplicationContext\n\t\textends ApplicationContextAssertProvider<ConfigurableWebApplicationContext>, ConfigurableWebApplicationContext {\n\n\t/**\n\t * Factory method to create a new {@link AssertableWebApplicationContext} instance.\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ConfigurableWebApplicationContext} or throw an exception if the context\n\t * fails to start.\n\t * @return a {@link AssertableWebApplicationContext} instance\n\t */\n\tstatic AssertableWebApplicationContext get(Supplier<? extends ConfigurableWebApplicationContext> contextSupplier) {\n\t\treturn ApplicationContextAssertProvider.get(AssertableWebApplicationContext.class,\n\t\t\t\tConfigurableWebApplicationContext.class, contextSupplier);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link AssertableWebApplicationContext} instance.\n\t * @param contextSupplier a supplier that will either return a fully configured\n\t * {@link ConfigurableWebApplicationContext} or throw an exception if the context\n\t * fails to start.\n\t * @param additionalContextInterfaces and additional context interfaces to add to the\n\t * proxy\n\t * @return a {@link AssertableWebApplicationContext} instance\n\t * @since 3.4.0\n\t */\n\tstatic AssertableWebApplicationContext get(Supplier<? extends ConfigurableWebApplicationContext> contextSupplier,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\treturn ApplicationContextAssertProvider.get(AssertableWebApplicationContext.class,\n\t\t\t\tConfigurableWebApplicationContext.class, contextSupplier, additionalContextInterfaces);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * AssertJ support for ApplicationContexts.\n */\n@NullMarked\npackage org.springframework.boot.test.context.assertj;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/ExcludeFilterApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * {@link ApplicationContextInitializer} to register the {@link TestTypeExcludeFilter} for\n * when {@link SpringApplication#from} is being used with the test classpath.\n *\n * @author Phillip Webb\n */\nclass ExcludeFilterApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tTestTypeExcludeFilter.registerWith(applicationContext.getBeanFactory());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/ExcludeFilterContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\n\n/**\n * {@link ContextCustomizer} to add the {@link TestTypeExcludeFilter} to the\n * {@link ApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass ExcludeFilterContextCustomizer implements ContextCustomizer {\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context,\n\t\t\tMergedContextConfiguration mergedContextConfiguration) {\n\t\tTestTypeExcludeFilter.registerWith(context.getBeanFactory());\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\treturn (obj != null) && (getClass() == obj.getClass());\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn getClass().hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/ExcludeFilterContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport java.util.List;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\n\n/**\n * {@link ContextCustomizerFactory} to add the {@link TestTypeExcludeFilter} to the\n * {@link ApplicationContext}.\n *\n * @author Phillip Webb\n * @see ExcludeFilterContextCustomizer\n */\nclass ExcludeFilterContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\treturn new ExcludeFilterContextCustomizer();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/TestTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport java.io.IOException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.TestComponent;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\n\n/**\n * {@link TypeExcludeFilter} to exclude classes annotated with\n * {@link TestComponent @TestComponent} as well as inner-classes of tests.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass TestTypeExcludeFilter extends TypeExcludeFilter {\n\n\tprivate static final String BEAN_NAME = TestTypeExcludeFilter.class.getName();\n\n\tprivate static final String[] CLASS_ANNOTATIONS = { \"org.junit.runner.RunWith\",\n\t\t\t\"org.junit.jupiter.api.extension.ExtendWith\", \"org.junit.platform.commons.annotation.Testable\",\n\t\t\t\"org.testng.annotations.Test\" };\n\n\tprivate static final String[] METHOD_ANNOTATIONS = { \"org.junit.Test\",\n\t\t\t\"org.junit.platform.commons.annotation.Testable\", \"org.testng.annotations.Test\" };\n\n\tprivate static final TestTypeExcludeFilter INSTANCE = new TestTypeExcludeFilter();\n\n\t@Override\n\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\tif (isTestConfiguration(metadataReader)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (isTestClass(metadataReader)) {\n\t\t\treturn true;\n\t\t}\n\t\tString enclosing = metadataReader.getClassMetadata().getEnclosingClassName();\n\t\tif (enclosing != null) {\n\t\t\ttry {\n\t\t\t\tif (match(metadataReaderFactory.getMetadataReader(enclosing), metadataReaderFactory)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\treturn (obj != null) && (getClass() == obj.getClass());\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn getClass().hashCode();\n\t}\n\n\tprivate boolean isTestConfiguration(MetadataReader metadataReader) {\n\t\treturn (metadataReader.getAnnotationMetadata().isAnnotated(TestComponent.class.getName()));\n\t}\n\n\tprivate boolean isTestClass(MetadataReader metadataReader) {\n\t\tfor (String annotation : CLASS_ANNOTATIONS) {\n\t\t\tif (metadataReader.getAnnotationMetadata().hasAnnotation(annotation)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t}\n\t\tfor (String annotation : METHOD_ANNOTATIONS) {\n\t\t\tif (metadataReader.getAnnotationMetadata().hasAnnotatedMethods(annotation)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tstatic void registerWith(ConfigurableListableBeanFactory beanFactory) {\n\t\tif (!beanFactory.containsSingleton(BEAN_NAME)) {\n\t\t\tbeanFactory.registerSingleton(BEAN_NAME, INSTANCE);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/AnnotationCustomizableTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.core.type.filter.AssignableTypeFilter;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Abstract base class for a {@link TypeExcludeFilter} that can be customized using an\n * annotation.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class AnnotationCustomizableTypeExcludeFilter extends TypeExcludeFilter\n\t\timplements BeanClassLoaderAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader classLoader;\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t@Override\n\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\tif (hasAnnotation()) {\n\t\t\treturn !(include(metadataReader, metadataReaderFactory) && !exclude(metadataReader, metadataReaderFactory));\n\t\t}\n\t\treturn false;\n\t}\n\n\tprotected boolean include(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\tif (new FilterAnnotations(this.classLoader, getFilters(FilterType.INCLUDE)).anyMatches(metadataReader,\n\t\t\t\tmetadataReaderFactory)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn isUseDefaultFilters() && defaultInclude(metadataReader, metadataReaderFactory);\n\t}\n\n\tprotected boolean defaultInclude(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\tfor (Class<?> include : getDefaultIncludes()) {\n\t\t\tif (isTypeOrAnnotated(metadataReader, metadataReaderFactory, include)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tfor (Class<?> component : getComponentIncludes()) {\n\t\t\tif (isTypeOrAnnotated(metadataReader, metadataReaderFactory, component)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprotected boolean exclude(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\tthrows IOException {\n\t\treturn new FilterAnnotations(this.classLoader, getFilters(FilterType.EXCLUDE)).anyMatches(metadataReader,\n\t\t\t\tmetadataReaderFactory);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected final boolean isTypeOrAnnotated(MetadataReader metadataReader,\n\t\t\tMetadataReaderFactory metadataReaderFactory, Class<?> type) throws IOException {\n\t\tAnnotationTypeFilter annotationFilter = new AnnotationTypeFilter((Class<? extends Annotation>) type);\n\t\tAssignableTypeFilter typeFilter = new AssignableTypeFilter(type);\n\t\treturn annotationFilter.match(metadataReader, metadataReaderFactory)\n\t\t\t\t|| typeFilter.match(metadataReader, metadataReaderFactory);\n\t}\n\n\tprotected abstract boolean hasAnnotation();\n\n\tprotected abstract Filter[] getFilters(FilterType type);\n\n\tprotected abstract boolean isUseDefaultFilters();\n\n\tprotected abstract Set<Class<?>> getDefaultIncludes();\n\n\tprotected abstract Set<Class<?>> getComponentIncludes();\n\n\tprotected enum FilterType {\n\n\t\tINCLUDE, EXCLUDE\n\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tAnnotationCustomizableTypeExcludeFilter other = (AnnotationCustomizableTypeExcludeFilter) obj;\n\t\tboolean result = hasAnnotation() == other.hasAnnotation();\n\t\tfor (FilterType filterType : FilterType.values()) {\n\t\t\tresult &= ObjectUtils.nullSafeEquals(getFilters(filterType), other.getFilters(filterType));\n\t\t}\n\t\tresult = result && isUseDefaultFilters() == other.isUseDefaultFilters();\n\t\tresult = result && ObjectUtils.nullSafeEquals(getDefaultIncludes(), other.getDefaultIncludes());\n\t\tresult = result && ObjectUtils.nullSafeEquals(getComponentIncludes(), other.getComponentIncludes());\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 0;\n\t\tresult = prime * result + Boolean.hashCode(hasAnnotation());\n\t\tfor (FilterType filterType : FilterType.values()) {\n\t\t\tresult = prime * result + Arrays.hashCode(getFilters(filterType));\n\t\t}\n\t\tresult = prime * result + Boolean.hashCode(isUseDefaultFilters());\n\t\tresult = prime * result + Objects.hashCode(getDefaultIncludes());\n\t\tresult = prime * result + Objects.hashCode(getComponentIncludes());\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/FilterAnnotations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.io.IOException;\nimport java.lang.annotation.Annotation;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.core.type.filter.AspectJTypeFilter;\nimport org.springframework.core.type.filter.AssignableTypeFilter;\nimport org.springframework.core.type.filter.RegexPatternTypeFilter;\nimport org.springframework.core.type.filter.TypeFilter;\nimport org.springframework.util.Assert;\n\n/**\n * Utility to load {@link TypeFilter TypeFilters} from {@link Filter @Filter} annotations.\n *\n * @author Phillip Webb\n */\nclass FilterAnnotations implements Iterable<TypeFilter> {\n\n\tprivate final ClassLoader classLoader;\n\n\tprivate final List<TypeFilter> filters;\n\n\tFilterAnnotations(ClassLoader classLoader, Filter[] filters) {\n\t\tAssert.notNull(filters, \"'filters' must not be null\");\n\t\tthis.classLoader = classLoader;\n\t\tthis.filters = createTypeFilters(filters);\n\t}\n\n\tprivate List<TypeFilter> createTypeFilters(Filter[] filters) {\n\t\tList<TypeFilter> typeFilters = new ArrayList<>();\n\t\tfor (Filter filter : filters) {\n\t\t\tfor (Class<?> filterClass : filter.classes()) {\n\t\t\t\ttypeFilters.add(createTypeFilter(filter.type(), filterClass));\n\t\t\t}\n\t\t\tfor (String pattern : filter.pattern()) {\n\t\t\t\ttypeFilters.add(createTypeFilter(filter.type(), pattern));\n\t\t\t}\n\t\t}\n\t\treturn Collections.unmodifiableList(typeFilters);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate TypeFilter createTypeFilter(FilterType filterType, Class<?> filterClass) {\n\t\treturn switch (filterType) {\n\t\t\tcase ANNOTATION -> {\n\t\t\t\tAssert.isAssignable(Annotation.class, filterClass,\n\t\t\t\t\t\t\"'filterClass' must be an Annotation when 'filterType' is ANNOTATION\");\n\t\t\t\tyield new AnnotationTypeFilter((Class<Annotation>) filterClass);\n\t\t\t}\n\t\t\tcase ASSIGNABLE_TYPE -> new AssignableTypeFilter(filterClass);\n\t\t\tcase CUSTOM -> {\n\t\t\t\tAssert.isAssignable(TypeFilter.class, filterClass,\n\t\t\t\t\t\t\"'filterClass' must be a TypeFilter when 'filterType' is CUSTOM\");\n\t\t\t\tyield BeanUtils.instantiateClass(filterClass, TypeFilter.class);\n\t\t\t}\n\t\t\tdefault -> throw new IllegalArgumentException(\"'filterClass' not supported [\" + filterType + \"]\");\n\t\t};\n\t}\n\n\tprivate TypeFilter createTypeFilter(FilterType filterType, String pattern) {\n\t\treturn switch (filterType) {\n\t\t\tcase ASPECTJ -> new AspectJTypeFilter(pattern, this.classLoader);\n\t\t\tcase REGEX -> new RegexPatternTypeFilter(Pattern.compile(pattern));\n\t\t\tdefault ->\n\t\t\t\tthrow new IllegalArgumentException(\"Filter type not supported with String pattern: \" + filterType);\n\t\t};\n\t}\n\n\t@Override\n\tpublic Iterator<TypeFilter> iterator() {\n\t\treturn this.filters.iterator();\n\t}\n\n\tboolean anyMatches(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {\n\t\tfor (TypeFilter filter : this) {\n\t\t\tif (filter.match(metadataReader, metadataReaderFactory)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/StandardAnnotationCustomizableTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.Assert;\n\n/**\n * {@link AnnotationCustomizableTypeExcludeFilter} that can be used to any test annotation\n * that uses the standard {@code includeFilters}, {@code excludeFilters} and\n * {@code useDefaultFilters} attributes.\n *\n * @param <A> the annotation type\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class StandardAnnotationCustomizableTypeExcludeFilter<A extends Annotation>\n\t\textends AnnotationCustomizableTypeExcludeFilter {\n\n\tprivate static final Filter[] NO_FILTERS = {};\n\n\tprivate static final String[] FILTER_TYPE_ATTRIBUTES;\n\tstatic {\n\t\tFilterType[] filterValues = FilterType.values();\n\t\tFILTER_TYPE_ATTRIBUTES = new String[filterValues.length];\n\t\tfor (int i = 0; i < filterValues.length; i++) {\n\t\t\tFILTER_TYPE_ATTRIBUTES[i] = filterValues[i].name().toLowerCase(Locale.ROOT) + \"Filters\";\n\t\t}\n\t}\n\n\tprivate final MergedAnnotation<A> annotation;\n\n\tprotected StandardAnnotationCustomizableTypeExcludeFilter(Class<?> testClass) {\n\t\tthis.annotation = MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS)\n\t\t\t.get(getAnnotationType());\n\t}\n\n\tprotected final MergedAnnotation<A> getAnnotation() {\n\t\treturn this.annotation;\n\t}\n\n\t@Override\n\tprotected boolean hasAnnotation() {\n\t\treturn this.annotation.isPresent();\n\t}\n\n\t@Override\n\tprotected Filter[] getFilters(FilterType type) {\n\t\treturn this.annotation.getValue(FILTER_TYPE_ATTRIBUTES[type.ordinal()], Filter[].class).orElse(NO_FILTERS);\n\t}\n\n\t@Override\n\tprotected boolean isUseDefaultFilters() {\n\t\treturn this.annotation.getValue(\"useDefaultFilters\", Boolean.class).orElse(false);\n\t}\n\n\t@Override\n\tprotected final Set<Class<?>> getDefaultIncludes() {\n\t\tSet<Class<?>> defaultIncludes = new HashSet<>();\n\t\tdefaultIncludes.addAll(getKnownIncludes());\n\t\tdefaultIncludes.addAll(TypeIncludes.load(this.annotation.getType(), getClass().getClassLoader()).getIncludes());\n\t\treturn defaultIncludes;\n\t}\n\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\treturn Collections.emptySet();\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn Collections.emptySet();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected Class<A> getAnnotationType() {\n\t\tResolvableType type = ResolvableType.forClass(StandardAnnotationCustomizableTypeExcludeFilter.class,\n\t\t\t\tgetClass());\n\t\tClass<A> generic = (Class<A>) type.resolveGeneric();\n\t\tAssert.state(generic != null, \"'generic' must not be null\");\n\t\treturn generic;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/TypeExcludeFilters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Annotation that can be on tests to define a set of {@link TypeExcludeFilter} classes\n * that should be registered with the {@link ApplicationContext}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see TypeExcludeFilter\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\npublic @interface TypeExcludeFilters {\n\n\t/**\n\t * Specifies {@link TypeExcludeFilter} classes that should be registered. Classes\n\t * specified here can either have a no-arg constructor or accept a single\n\t * {@code Class<?>} argument if they need access to the {@code testClass}.\n\t * @see TypeExcludeFilter\n\t * @return the type exclude filters to apply\n\t */\n\tClass<? extends TypeExcludeFilter>[] value();\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/TypeExcludeFiltersContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link ContextCustomizer} to support {@link TypeExcludeFilters @TypeExcludeFilters}.\n *\n * @author Phillip Webb\n * @see TypeExcludeFilters\n */\nclass TypeExcludeFiltersContextCustomizer implements ContextCustomizer {\n\n\tprivate static final String EXCLUDE_FILTER_BEAN_NAME = TypeExcludeFilters.class.getName();\n\n\tprivate final Set<TypeExcludeFilter> filters;\n\n\tTypeExcludeFiltersContextCustomizer(Class<?> testClass, Set<Class<? extends TypeExcludeFilter>> filterClasses) {\n\t\tthis.filters = instantiateTypeExcludeFilters(testClass, filterClasses);\n\t}\n\n\tprivate Set<TypeExcludeFilter> instantiateTypeExcludeFilters(Class<?> testClass,\n\t\t\tSet<Class<? extends TypeExcludeFilter>> filterClasses) {\n\t\tSet<TypeExcludeFilter> filters = new LinkedHashSet<>();\n\t\tfor (Class<? extends TypeExcludeFilter> filterClass : filterClasses) {\n\t\t\tfilters.add(instantiateTypeExcludeFilter(testClass, filterClass));\n\t\t}\n\t\treturn Collections.unmodifiableSet(filters);\n\t}\n\n\tprivate TypeExcludeFilter instantiateTypeExcludeFilter(Class<?> testClass, Class<?> filterClass) {\n\t\ttry {\n\t\t\tConstructor<?> constructor = getTypeExcludeFilterConstructor(filterClass);\n\t\t\tReflectionUtils.makeAccessible(constructor);\n\t\t\tif (constructor.getParameterCount() == 1) {\n\t\t\t\treturn (TypeExcludeFilter) constructor.newInstance(testClass);\n\t\t\t}\n\t\t\treturn (TypeExcludeFilter) constructor.newInstance();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create filter for \" + filterClass, ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\treturn (obj != null) && (getClass() == obj.getClass())\n\t\t\t\t&& this.filters.equals(((TypeExcludeFiltersContextCustomizer) obj).filters);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.filters.hashCode();\n\t}\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context,\n\t\t\tMergedContextConfiguration mergedContextConfiguration) {\n\t\tif (!this.filters.isEmpty()) {\n\t\t\tcontext.getBeanFactory().registerSingleton(EXCLUDE_FILTER_BEAN_NAME, createDelegatingTypeExcludeFilter());\n\t\t}\n\t}\n\n\tprivate TypeExcludeFilter createDelegatingTypeExcludeFilter() {\n\t\treturn new TypeExcludeFilter() {\n\n\t\t\t@Override\n\t\t\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)\n\t\t\t\t\tthrows IOException {\n\t\t\t\tfor (TypeExcludeFilter filter : TypeExcludeFiltersContextCustomizer.this.filters) {\n\t\t\t\t\tif (filter.match(metadataReader, metadataReaderFactory)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate Constructor<?> getTypeExcludeFilterConstructor(Class<?> type) throws NoSuchMethodException {\n\t\ttry {\n\t\t\treturn type.getDeclaredConstructor(Class.class);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn type.getDeclaredConstructor();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/TypeExcludeFiltersContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.TestContextAnnotationUtils;\nimport org.springframework.test.context.TestContextAnnotationUtils.AnnotationDescriptor;\n\n/**\n * {@link ContextCustomizerFactory} to support\n * {@link TypeExcludeFilters @TypeExcludeFilters}.\n *\n * @author Phillip Webb\n * @see TypeExcludeFiltersContextCustomizer\n */\nclass TypeExcludeFiltersContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configurationAttributes) {\n\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn null;\n\t\t}\n\t\tAnnotationDescriptor<TypeExcludeFilters> descriptor = TestContextAnnotationUtils\n\t\t\t.findAnnotationDescriptor(testClass, TypeExcludeFilters.class);\n\t\tif (descriptor == null) {\n\t\t\treturn null;\n\t\t}\n\t\tClass<?>[] filterClasses = descriptor.getAnnotation().value();\n\t\treturn createContextCustomizer(descriptor.getRootDeclaringClass(), filterClasses);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ContextCustomizer createContextCustomizer(Class<?> testClass, Class<?>[] filterClasses) {\n\t\treturn new TypeExcludeFiltersContextCustomizer(testClass,\n\t\t\t\tnew LinkedHashSet<>(Arrays.asList((Class<? extends TypeExcludeFilter>[]) filterClasses)));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/TypeIncludes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.core.io.UrlResource;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Contains types to be included by a {@link TypeExcludeFilter}.\n *\n * The {@link #load(Class, ClassLoader)} method can be used to discover the includes.\n *\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @author Andy Wilkinson\n */\nfinal class TypeIncludes implements Iterable<Class<?>> {\n\n\tprivate static final String LOCATION = \"META-INF/spring/%s.includes\";\n\n\tprivate static final String COMMENT_START = \"#\";\n\n\tprivate static final Log logger = LogFactory.getLog(TypeIncludes.class);\n\n\tprivate final Set<Class<?>> includes;\n\n\tprivate TypeIncludes(Set<Class<?>> includes) {\n\t\tAssert.notNull(includes, \"'includes' must not be null\");\n\t\tthis.includes = Collections.unmodifiableSet(includes);\n\t}\n\n\t@Override\n\tpublic Iterator<Class<?>> iterator() {\n\t\treturn this.includes.iterator();\n\t}\n\n\tSet<Class<?>> getIncludes() {\n\t\treturn this.includes;\n\t}\n\n\t/**\n\t * Loads the includes from the classpath. The names of the includes are stored in\n\t * files named {@code META-INF/spring/fully-qualified-annotation-name.includes} on the\n\t * classpath. Every line contains the fully qualified name of the included class.\n\t * Comments are supported using the # character.\n\t * @param annotation annotation to load\n\t * @param classLoader class loader to use for loading\n\t * @return list of names of included classes\n\t */\n\tstatic TypeIncludes load(Class<?> annotation, @Nullable ClassLoader classLoader) {\n\t\tAssert.notNull(annotation, \"'annotation' must not be null\");\n\t\tClassLoader classLoaderToUse = decideClassloader(classLoader);\n\t\tString location = String.format(LOCATION, annotation.getName());\n\t\tEnumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);\n\t\tSet<Class<?>> includes = new HashSet<>();\n\t\twhile (urls.hasMoreElements()) {\n\t\t\tURL url = urls.nextElement();\n\t\t\tincludes.addAll(loadIncludes(url, classLoader));\n\t\t}\n\t\treturn new TypeIncludes(includes);\n\t}\n\n\tprivate static ClassLoader decideClassloader(@Nullable ClassLoader classLoader) {\n\t\tif (classLoader == null) {\n\t\t\treturn TypeIncludes.class.getClassLoader();\n\t\t}\n\t\treturn classLoader;\n\t}\n\n\tprivate static Enumeration<URL> findUrlsInClasspath(ClassLoader classLoader, String location) {\n\t\ttry {\n\t\t\treturn classLoader.getResources(location);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to load includes from location [\" + location + \"]\", ex);\n\t\t}\n\t}\n\n\tprivate static Set<Class<?>> loadIncludes(URL url, @Nullable ClassLoader classLoader) {\n\t\tSet<String> includeNames = readIncludes(url);\n\t\tSet<Class<?>> includes = new HashSet<>(includeNames.size());\n\t\tfor (String includeName : includeNames) {\n\t\t\ttry {\n\t\t\t\tincludes.add(ClassUtils.forName(includeName, classLoader));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlogger.debug(LogMessage.format(\"Include '%s' declared in '%s' could not be loaded and has been ignored\",\n\t\t\t\t\t\tincludeName, url), ex);\n\t\t\t}\n\t\t}\n\t\treturn includes;\n\t}\n\n\tprivate static Set<String> readIncludes(URL url) {\n\t\ttry (BufferedReader reader = new BufferedReader(\n\t\t\t\tnew InputStreamReader(new UrlResource(url).getInputStream(), StandardCharsets.UTF_8))) {\n\t\t\tSet<String> includes = new HashSet<>();\n\t\t\tString line;\n\t\t\twhile ((line = reader.readLine()) != null) {\n\t\t\t\tline = stripComment(line);\n\t\t\t\tline = line.trim();\n\t\t\t\tif (line.isEmpty()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tincludes.add(line);\n\t\t\t}\n\t\t\treturn includes;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Unable to load includes from location [\" + url + \"]\", ex);\n\t\t}\n\t}\n\n\tprivate static String stripComment(String line) {\n\t\tint commentStart = line.indexOf(COMMENT_START);\n\t\tif (commentStart == -1) {\n\t\t\treturn line;\n\t\t}\n\t\treturn line.substring(0, commentStart);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/annotation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Test annotations support for\n * {@link org.springframework.boot.context.TypeExcludeFilter}.\n */\n@NullMarked\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/filter/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Test support for {@link org.springframework.boot.context.TypeExcludeFilter}.\n */\n@NullMarked\npackage org.springframework.boot.test.context.filter;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for mapping annotation attribute values in the Spring {@code Environment}.\n */\n@NullMarked\npackage org.springframework.boot.test.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionCustomizer;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.context.annotation.Configurations;\nimport org.springframework.boot.context.annotation.UserConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssert;\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Utility design to run an {@link ApplicationContext} and provide AssertJ style\n * assertions. The test is best used as a field of a test class, describing the shared\n * configuration required for the test:\n *\n * <pre class=\"code\">\n * public class MyContextTests {\n *     private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n *             .withPropertyValues(\"spring.foo=bar\")\n *             .withUserConfiguration(MyConfiguration.class);\n * }</pre>\n *\n * <p>\n * The initialization above makes sure to register {@code MyConfiguration} for all tests\n * and set the {@code spring.foo} property to {@code bar} unless specified otherwise.\n * <p>\n * Based on the configuration above, a specific test can simulate what will happen when\n * the context runs, perhaps with overridden property values:\n *\n * <pre class=\"code\">\n * &#064;Test\n * public someTest() {\n *     this.contextRunner.withPropertyValues(\"spring.foo=biz\").run((context) -&gt; {\n *         assertThat(context).containsSingleBean(MyBean.class);\n *         // other assertions\n *     });\n * }</pre>\n * <p>\n * The test above has changed the {@code spring.foo} property to {@code biz} and is\n * asserting that the context contains a single {@code MyBean} bean. The\n * {@link #run(ContextConsumer) run} method takes a {@link ContextConsumer} that can apply\n * assertions to the context. Upon completion, the context is automatically closed.\n * <p>\n * If the application context fails to start the {@code #run(ContextConsumer)} method is\n * called with a \"failed\" application context. Calls to the context will throw an\n * {@link IllegalStateException} and assertions that expect a running context will fail.\n * The {@link ApplicationContextAssert#getFailure() getFailure()} assertion can be used if\n * further checks are required on the cause of the failure: <pre class=\"code\">\n * &#064;Test\n * public someTest() {\n *     this.context.withPropertyValues(\"spring.foo=fails\").run((loaded) -&gt; {\n *         assertThat(loaded).getFailure().hasCauseInstanceOf(BadPropertyException.class);\n *         // other assertions\n *     });\n * }</pre>\n * <p>\n *\n * @param <SELF> the \"self\" type for this runner\n * @param <C> the context type\n * @param <A> the application context assertion provider\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n * @see ApplicationContextRunner\n * @see WebApplicationContextRunner\n * @see ReactiveWebApplicationContextRunner\n * @see ApplicationContextAssert\n */\npublic abstract class AbstractApplicationContextRunner<SELF extends AbstractApplicationContextRunner<SELF, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> {\n\n\tprivate final RunnerConfiguration<C> runnerConfiguration;\n\n\tprivate final Function<RunnerConfiguration<C>, SELF> instanceFactory;\n\n\t/**\n\t * Create a new {@link AbstractApplicationContextRunner} instance.\n\t * @param instanceFactory the factory used to create new instance of the runner\n\t * @param contextFactory the factory used to create the actual context\n\t * @param additionalContextInterfaces any additional application context interfaces to\n\t * be added to the application context proxy\n\t * @since 3.4.0\n\t */\n\tprotected AbstractApplicationContextRunner(Function<RunnerConfiguration<C>, SELF> instanceFactory,\n\t\t\tSupplier<C> contextFactory, Class<?>... additionalContextInterfaces) {\n\t\tAssert.notNull(instanceFactory, \"'instanceFactory' must not be null\");\n\t\tAssert.notNull(contextFactory, \"'contextFactory' must not be null\");\n\t\tthis.instanceFactory = instanceFactory;\n\t\tthis.runnerConfiguration = new RunnerConfiguration<>(contextFactory, additionalContextInterfaces);\n\t}\n\n\t/**\n\t * Create a new {@link AbstractApplicationContextRunner} instance.\n\t * @param configuration the configuration for the runner to use\n\t * @param instanceFactory the factory used to create new instance of the runner\n\t * @since 2.6.0\n\t */\n\tprotected AbstractApplicationContextRunner(RunnerConfiguration<C> configuration,\n\t\t\tFunction<RunnerConfiguration<C>, SELF> instanceFactory) {\n\t\tAssert.notNull(configuration, \"'configuration' must not be null\");\n\t\tAssert.notNull(instanceFactory, \"'instanceFactory' must not be null\");\n\t\tthis.runnerConfiguration = configuration;\n\t\tthis.instanceFactory = instanceFactory;\n\t}\n\n\t/**\n\t * Specify if bean definition overriding, by registering a definition with the same\n\t * name as an existing definition, should be allowed.\n\t * @param allowBeanDefinitionOverriding if bean overriding is allowed\n\t * @return a new instance with the updated bean definition overriding policy\n\t * @since 2.3.0\n\t * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean)\n\t */\n\tpublic SELF withAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {\n\t\treturn newInstance(this.runnerConfiguration.withAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding));\n\t}\n\n\t/**\n\t * Specify if circular references between beans should be allowed.\n\t * @param allowCircularReferences if circular references between beans are allowed\n\t * @return a new instance with the updated circular references policy\n\t * @since 2.6.0\n\t * @see AbstractAutowireCapableBeanFactory#setAllowCircularReferences(boolean)\n\t */\n\tpublic SELF withAllowCircularReferences(boolean allowCircularReferences) {\n\t\treturn newInstance(this.runnerConfiguration.withAllowCircularReferences(allowCircularReferences));\n\t}\n\n\t/**\n\t * Add an {@link ApplicationContextInitializer} to be called when the context is\n\t * created.\n\t * @param initializer the initializer to add\n\t * @return a new instance with the updated initializers\n\t */\n\tpublic SELF withInitializer(ApplicationContextInitializer<? super C> initializer) {\n\t\tAssert.notNull(initializer, \"'initializer' must not be null\");\n\t\treturn newInstance(this.runnerConfiguration.withInitializer(initializer));\n\t}\n\n\t/**\n\t * Add the specified {@link Environment} property pairs. Key-value pairs can be\n\t * specified with colon (\":\") or equals (\"=\") separators. Override matching keys that\n\t * might have been specified previously.\n\t * @param pairs the key-value pairs for properties that need to be added to the\n\t * environment\n\t * @return a new instance with the updated property values\n\t * @see TestPropertyValues\n\t * @see #withSystemProperties(String...)\n\t */\n\tpublic SELF withPropertyValues(String... pairs) {\n\t\treturn newInstance(this.runnerConfiguration.withPropertyValues(pairs));\n\t}\n\n\t/**\n\t * Add the specified {@link System} property pairs. Key-value pairs can be specified\n\t * with colon (\":\") or equals (\"=\") separators. System properties are added before the\n\t * context is {@link #run(ContextConsumer) run} and restored when the context is\n\t * closed.\n\t * @param pairs the key-value pairs for properties that need to be added to the system\n\t * @return a new instance with the updated system properties\n\t * @see TestPropertyValues\n\t * @see #withSystemProperties(String...)\n\t */\n\tpublic SELF withSystemProperties(String... pairs) {\n\t\treturn newInstance(this.runnerConfiguration.withSystemProperties(pairs));\n\t}\n\n\t/**\n\t * Customize the {@link ClassLoader} that the {@link ApplicationContext} should use\n\t * for resource loading and bean class loading.\n\t * @param classLoader the classloader to use (or {@code null} to use the default)\n\t * @return a new instance with the updated class loader\n\t * @see FilteredClassLoader\n\t */\n\tpublic SELF withClassLoader(@Nullable ClassLoader classLoader) {\n\t\treturn newInstance(this.runnerConfiguration.withClassLoader(classLoader));\n\t}\n\n\t/**\n\t * Configure the {@link ConfigurableApplicationContext#setParent(ApplicationContext)\n\t * parent} of the {@link ApplicationContext}.\n\t * @param parent the parent\n\t * @return a new instance with the updated parent\n\t */\n\tpublic SELF withParent(ApplicationContext parent) {\n\t\treturn newInstance(this.runnerConfiguration.withParent(parent));\n\t}\n\n\t/**\n\t * Register the specified user bean with the {@link ApplicationContext}. The bean name\n\t * is generated from the configured {@link BeanNameGenerator} on the underlying\n\t * context.\n\t * <p>\n\t * Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])\n\t * user configurations} in the order of registration.\n\t * @param type the type of the bean\n\t * @param constructorArgs custom argument values to be fed into Spring's constructor\n\t * resolution algorithm, resolving either all arguments or just specific ones, with\n\t * the rest to be resolved through regular autowiring (may be {@code null} or empty)\n\t * @param <T> the type of the bean\n\t * @return a new instance with the updated bean\n\t */\n\tpublic <T> SELF withBean(Class<T> type, Object... constructorArgs) {\n\t\treturn withBean(null, type, constructorArgs);\n\t}\n\n\t/**\n\t * Register the specified user bean with the {@link ApplicationContext}.\n\t * <p>\n\t * Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])\n\t * user configurations} in the order of registration.\n\t * @param name the bean name or {@code null} to use a generated name\n\t * @param type the type of the bean\n\t * @param constructorArgs custom argument values to be fed into Spring's constructor\n\t * resolution algorithm, resolving either all arguments or just specific ones, with\n\t * the rest to be resolved through regular autowiring (may be {@code null} or empty)\n\t * @param <T> the type of the bean\n\t * @return a new instance with the updated bean\n\t */\n\tpublic <T> SELF withBean(@Nullable String name, Class<T> type, Object... constructorArgs) {\n\t\treturn newInstance(this.runnerConfiguration.withBean(name, type, constructorArgs));\n\t}\n\n\t/**\n\t * Register the specified user bean with the {@link ApplicationContext}. The bean name\n\t * is generated from the configured {@link BeanNameGenerator} on the underlying\n\t * context.\n\t * <p>\n\t * Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])\n\t * user configurations} in the order of registration.\n\t * @param type the type of the bean\n\t * @param supplier a supplier for the bean\n\t * @param customizers one or more callbacks for customizing the factory's\n\t * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag\n\t * @param <T> the type of the bean\n\t * @return a new instance with the updated bean\n\t */\n\tpublic <T> SELF withBean(Class<T> type, Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {\n\t\treturn withBean(null, type, supplier, customizers);\n\t}\n\n\t/**\n\t * Register the specified user bean with the {@link ApplicationContext}. The bean name\n\t * is generated from the configured {@link BeanNameGenerator} on the underlying\n\t * context.\n\t * <p>\n\t * Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])\n\t * user configurations} in the order of registration.\n\t * @param name the bean name or {@code null} to use a generated name\n\t * @param type the type of the bean\n\t * @param supplier a supplier for the bean\n\t * @param customizers one or more callbacks for customizing the factory's\n\t * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag\n\t * @param <T> the type of the bean\n\t * @return a new instance with the updated bean\n\t */\n\tpublic <T> SELF withBean(@Nullable String name, Class<T> type, Supplier<T> supplier,\n\t\t\tBeanDefinitionCustomizer... customizers) {\n\t\treturn newInstance(this.runnerConfiguration.withBean(name, type, supplier, customizers));\n\t}\n\n\t/**\n\t * Register the specified user configuration classes with the\n\t * {@link ApplicationContext}.\n\t * @param configurationClasses the user configuration classes to add\n\t * @return a new instance with the updated configuration\n\t */\n\tpublic SELF withUserConfiguration(Class<?>... configurationClasses) {\n\t\treturn withConfiguration(UserConfigurations.of(configurationClasses));\n\t}\n\n\t/**\n\t * Register the specified configuration classes with the {@link ApplicationContext}.\n\t * @param configurations the configurations to add\n\t * @return a new instance with the updated configuration\n\t */\n\tpublic SELF withConfiguration(Configurations configurations) {\n\t\tAssert.notNull(configurations, \"'configurations' must not be null\");\n\t\treturn newInstance(this.runnerConfiguration.withConfiguration(configurations));\n\t}\n\n\t/**\n\t * Apply customization to this runner.\n\t * @param customizer the customizer to call\n\t * @return a new instance with the customizations applied\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic SELF with(Function<SELF, SELF> customizer) {\n\t\treturn customizer.apply((SELF) this);\n\t}\n\n\tprivate SELF newInstance(RunnerConfiguration<C> runnerConfiguration) {\n\t\treturn this.instanceFactory.apply(runnerConfiguration);\n\t}\n\n\t/**\n\t * Create and refresh a new {@link ApplicationContext} based on the current state of\n\t * this loader. The context is consumed by the specified {@code consumer} and closed\n\t * upon completion.\n\t * @param consumer the consumer of the created {@link ApplicationContext}\n\t * @return this instance\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic SELF run(ContextConsumer<? super A> consumer) {\n\t\twithContextClassLoader(this.runnerConfiguration.classLoader, () -> this.runnerConfiguration.systemProperties\n\t\t\t.applyToSystemProperties(() -> consumeAssertableContext(true, consumer)));\n\t\treturn (SELF) this;\n\t}\n\n\t/**\n\t * Prepare a new {@link ApplicationContext} based on the current state of this loader.\n\t * The context is consumed by the specified {@code consumer} and closed upon\n\t * completion. Unlike {@link #run(ContextConsumer)}, this method does not refresh the\n\t * consumed context.\n\t * @param consumer the consumer of the created {@link ApplicationContext}\n\t * @return this instance\n\t * @since 3.0.0\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic SELF prepare(ContextConsumer<? super A> consumer) {\n\t\twithContextClassLoader(this.runnerConfiguration.classLoader, () -> this.runnerConfiguration.systemProperties\n\t\t\t.applyToSystemProperties(() -> consumeAssertableContext(false, consumer)));\n\t\treturn (SELF) this;\n\t}\n\n\tprivate void consumeAssertableContext(boolean refresh, ContextConsumer<? super A> consumer) {\n\t\ttry (A context = createAssertableContext(refresh)) {\n\t\t\taccept(consumer, context);\n\t\t}\n\t}\n\n\tprivate void withContextClassLoader(@Nullable ClassLoader classLoader, Runnable action) {\n\t\tif (classLoader == null) {\n\t\t\taction.run();\n\t\t}\n\t\telse {\n\t\t\tThread currentThread = Thread.currentThread();\n\t\t\tClassLoader previous = currentThread.getContextClassLoader();\n\t\t\tcurrentThread.setContextClassLoader(classLoader);\n\t\t\ttry {\n\t\t\t\taction.run();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tcurrentThread.setContextClassLoader(previous);\n\t\t\t}\n\t\t}\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"resource\" })\n\tprivate A createAssertableContext(boolean refresh) {\n\t\tResolvableType resolvableType = ResolvableType.forClass(AbstractApplicationContextRunner.class, getClass());\n\t\tClass<A> assertType = (Class<A>) resolvableType.resolveGeneric(1);\n\t\tClass<C> contextType = (Class<C>) resolvableType.resolveGeneric(2);\n\t\tAssert.state(assertType != null, \"'assertType' must not be null\");\n\t\tAssert.state(contextType != null, \"'contextType' must not be null\");\n\t\treturn ApplicationContextAssertProvider.get(assertType, contextType, () -> createAndLoadContext(refresh),\n\t\t\t\tthis.runnerConfiguration.additionalContextInterfaces);\n\t}\n\n\tprivate C createAndLoadContext(boolean refresh) {\n\t\tC context = this.runnerConfiguration.contextFactory.get();\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tif (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {\n\t\t\tautowireCapableBeanFactory.setAllowCircularReferences(this.runnerConfiguration.allowCircularReferences);\n\t\t\tif (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {\n\t\t\t\tlistableBeanFactory\n\t\t\t\t\t.setAllowBeanDefinitionOverriding(this.runnerConfiguration.allowBeanDefinitionOverriding);\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tconfigureContext(context, refresh);\n\t\t\treturn context;\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tcontext.close();\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate void configureContext(C context, boolean refresh) {\n\t\tif (this.runnerConfiguration.parent != null) {\n\t\t\tcontext.setParent(this.runnerConfiguration.parent);\n\t\t}\n\t\tif (this.runnerConfiguration.classLoader != null) {\n\t\t\tAssert.isInstanceOf(DefaultResourceLoader.class, context);\n\t\t\t((DefaultResourceLoader) context).setClassLoader(this.runnerConfiguration.classLoader);\n\t\t}\n\t\tthis.runnerConfiguration.environmentProperties.applyTo(context);\n\t\tthis.runnerConfiguration.beanRegistrations.forEach((registration) -> registration.apply(context));\n\t\tthis.runnerConfiguration.initializers.forEach((initializer) -> initializer.initialize(context));\n\t\tif (!CollectionUtils.isEmpty(this.runnerConfiguration.configurations)) {\n\t\t\tBiConsumer<Class<?>, @Nullable String> registrar = getRegistrar(context);\n\t\t\tfor (Configurations configurations : Configurations.collate(this.runnerConfiguration.configurations)) {\n\t\t\t\tfor (Class<?> beanClass : Configurations.getClasses(configurations)) {\n\t\t\t\t\tString beanName = configurations.getBeanName(beanClass);\n\t\t\t\t\tregistrar.accept(beanClass, beanName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (refresh) {\n\t\t\tcontext.refresh();\n\t\t}\n\t}\n\n\tprivate BiConsumer<Class<?>, @Nullable String> getRegistrar(C context) {\n\t\tif (context instanceof BeanDefinitionRegistry registry) {\n\t\t\treturn new AnnotatedBeanDefinitionReader(registry, context.getEnvironment())::registerBean;\n\t\t}\n\t\treturn (beanClass, beanName) -> ((AnnotationConfigRegistry) context).register(beanClass);\n\t}\n\n\tprivate void accept(ContextConsumer<? super A> consumer, A context) {\n\t\ttry {\n\t\t\tconsumer.accept(context);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\trethrow(ex);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <E extends Throwable> void rethrow(Throwable e) throws E {\n\t\tthrow (E) e;\n\t}\n\n\t/**\n\t * A Bean registration to be applied when the context loaded.\n\t *\n\t * @param <T> the bean type\n\t */\n\tprotected static final class BeanRegistration<T> {\n\n\t\tConsumer<GenericApplicationContext> registrar;\n\n\t\tpublic BeanRegistration(@Nullable String name, Class<T> type, Object... constructorArgs) {\n\t\t\tthis.registrar = (context) -> context.registerBean(name, type, constructorArgs);\n\t\t}\n\n\t\tpublic BeanRegistration(@Nullable String name, Class<T> type, Supplier<T> supplier,\n\t\t\t\tBeanDefinitionCustomizer... customizers) {\n\t\t\tthis.registrar = (context) -> context.registerBean(name, type, supplier, customizers);\n\t\t}\n\n\t\tpublic void apply(ConfigurableApplicationContext context) {\n\t\t\tAssert.isInstanceOf(GenericApplicationContext.class, context);\n\t\t\tthis.registrar.accept(((GenericApplicationContext) context));\n\t\t}\n\n\t}\n\n\tprotected static final class RunnerConfiguration<C extends ConfigurableApplicationContext> {\n\n\t\tprivate final Supplier<C> contextFactory;\n\n\t\tprivate final Class<?>[] additionalContextInterfaces;\n\n\t\tprivate boolean allowBeanDefinitionOverriding;\n\n\t\tprivate boolean allowCircularReferences;\n\n\t\tprivate List<ApplicationContextInitializer<? super C>> initializers = Collections.emptyList();\n\n\t\tprivate TestPropertyValues environmentProperties = TestPropertyValues.empty();\n\n\t\tprivate TestPropertyValues systemProperties = TestPropertyValues.empty();\n\n\t\tprivate @Nullable ClassLoader classLoader;\n\n\t\tprivate @Nullable ApplicationContext parent;\n\n\t\tprivate List<BeanRegistration<?>> beanRegistrations = Collections.emptyList();\n\n\t\tprivate List<Configurations> configurations = Collections.emptyList();\n\n\t\tprivate RunnerConfiguration(Supplier<C> contextFactory, Class<?>[] additionalContextInterfaces) {\n\t\t\tthis.contextFactory = contextFactory;\n\t\t\tthis.additionalContextInterfaces = additionalContextInterfaces;\n\t\t}\n\n\t\tprivate RunnerConfiguration(RunnerConfiguration<C> source) {\n\t\t\tthis.contextFactory = source.contextFactory;\n\t\t\tthis.additionalContextInterfaces = source.additionalContextInterfaces;\n\t\t\tthis.allowBeanDefinitionOverriding = source.allowBeanDefinitionOverriding;\n\t\t\tthis.allowCircularReferences = source.allowCircularReferences;\n\t\t\tthis.initializers = source.initializers;\n\t\t\tthis.environmentProperties = source.environmentProperties;\n\t\t\tthis.systemProperties = source.systemProperties;\n\t\t\tthis.classLoader = source.classLoader;\n\t\t\tthis.parent = source.parent;\n\t\t\tthis.beanRegistrations = source.beanRegistrations;\n\t\t\tthis.configurations = source.configurations;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withAllowCircularReferences(boolean allowCircularReferences) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.allowCircularReferences = allowCircularReferences;\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withInitializer(ApplicationContextInitializer<? super C> initializer) {\n\t\t\tAssert.notNull(initializer, \"'initializer' must not be null\");\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.initializers = add(config.initializers, initializer);\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withPropertyValues(String... pairs) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.environmentProperties = config.environmentProperties.and(pairs);\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withSystemProperties(String... pairs) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.systemProperties = config.systemProperties.and(pairs);\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withClassLoader(@Nullable ClassLoader classLoader) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.classLoader = classLoader;\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withParent(ApplicationContext parent) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.parent = parent;\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate <T> RunnerConfiguration<C> withBean(@Nullable String name, Class<T> type, Object... constructorArgs) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.beanRegistrations = add(config.beanRegistrations,\n\t\t\t\t\tnew BeanRegistration<>(name, type, constructorArgs));\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate <T> RunnerConfiguration<C> withBean(@Nullable String name, Class<T> type, Supplier<T> supplier,\n\t\t\t\tBeanDefinitionCustomizer... customizers) {\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.beanRegistrations = add(config.beanRegistrations,\n\t\t\t\t\tnew BeanRegistration<>(name, type, supplier, customizers));\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate RunnerConfiguration<C> withConfiguration(Configurations configurations) {\n\t\t\tAssert.notNull(configurations, \"'configurations' must not be null\");\n\t\t\tRunnerConfiguration<C> config = new RunnerConfiguration<>(this);\n\t\t\tconfig.configurations = add(config.configurations, configurations);\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate static <T> List<T> add(List<T> list, T element) {\n\t\t\tList<T> result = new ArrayList<>(list);\n\t\t\tresult.add(element);\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\n/**\n * An {@link AbstractApplicationContextRunner ApplicationContext runner} for a standard,\n * non-web environment {@link ConfigurableApplicationContext}.\n * <p>\n * See {@link AbstractApplicationContextRunner} for details.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class ApplicationContextRunner extends\n\t\tAbstractApplicationContextRunner<ApplicationContextRunner, ConfigurableApplicationContext, AssertableApplicationContext> {\n\n\t/**\n\t * Create a new {@link ApplicationContextRunner} instance using an\n\t * {@link AnnotationConfigApplicationContext} as the underlying source.\n\t */\n\tpublic ApplicationContextRunner() {\n\t\tthis(AnnotationConfigApplicationContext::new);\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationContextRunner} instance using the specified\n\t * {@code contextFactory} as the underlying source.\n\t * @param contextFactory a supplier that returns a new instance on each call be added\n\t * to the application context proxy\n\t */\n\tpublic ApplicationContextRunner(Supplier<ConfigurableApplicationContext> contextFactory) {\n\t\tsuper(ApplicationContextRunner::new, contextFactory);\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationContextRunner} instance using the specified\n\t * {@code contextFactory} as the underlying source.\n\t * @param contextFactory a supplier that returns a new instance on each call\n\t * @param additionalContextInterfaces any additional application context interfaces to\n\t * be added to the application context proxy\n\t * @since 3.4.0\n\t */\n\tpublic ApplicationContextRunner(Supplier<ConfigurableApplicationContext> contextFactory,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\tsuper(ApplicationContextRunner::new, contextFactory, additionalContextInterfaces);\n\t}\n\n\tprivate ApplicationContextRunner(RunnerConfiguration<ConfigurableApplicationContext> runnerConfiguration) {\n\t\tsuper(runnerConfiguration, ApplicationContextRunner::new);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ContextConsumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.Assert;\n\n/**\n * Callback interface used to process an {@link ApplicationContext} with the ability to\n * throw a (checked) exception.\n *\n * @param <C> the application context type\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 2.0.0\n * @see AbstractApplicationContextRunner\n */\n@FunctionalInterface\npublic interface ContextConsumer<C extends ApplicationContext> {\n\n\t/**\n\t * Performs this operation on the supplied {@code context}.\n\t * @param context the application context to consume\n\t * @throws Throwable any exception that might occur in assertions\n\t */\n\tvoid accept(C context) throws Throwable;\n\n\t/**\n\t * Returns a composed {@code ContextConsumer} that performs, in sequence, this\n\t * operation followed by the {@code after} operation.\n\t * @param after the operation to perform after this operation\n\t * @return a composed {@code ContextConsumer} that performs in sequence this operation\n\t * followed by the {@code after} operation\n\t * @since 2.6.0\n\t */\n\tdefault ContextConsumer<C> andThen(ContextConsumer<? super C> after) {\n\t\tAssert.notNull(after, \"'after' must not be null\");\n\t\treturn (context) -> {\n\t\t\taccept(context);\n\t\t\tafter.accept(context);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.reactive.AnnotationConfigReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;\n\n/**\n * An {@link AbstractApplicationContextRunner ApplicationContext runner} for a\n * {@link ConfigurableReactiveWebApplicationContext}.\n * <p>\n * See {@link AbstractApplicationContextRunner} for details.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic final class ReactiveWebApplicationContextRunner extends\n\t\tAbstractApplicationContextRunner<ReactiveWebApplicationContextRunner, ConfigurableReactiveWebApplicationContext, AssertableReactiveWebApplicationContext> {\n\n\t/**\n\t * Create a new {@link ReactiveWebApplicationContextRunner} instance using a\n\t * {@link AnnotationConfigReactiveWebApplicationContext} as the underlying source.\n\t */\n\tpublic ReactiveWebApplicationContextRunner() {\n\t\tthis(AnnotationConfigReactiveWebApplicationContext::new);\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationContextRunner} instance using the specified\n\t * {@code contextFactory} as the underlying source.\n\t * @param contextFactory a supplier that returns a new instance on each call be added\n\t * to the application context proxy\n\t * @since 3.4.0\n\t */\n\tpublic ReactiveWebApplicationContextRunner(Supplier<ConfigurableReactiveWebApplicationContext> contextFactory) {\n\t\tsuper(ReactiveWebApplicationContextRunner::new, contextFactory);\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationContextRunner} instance using the specified\n\t * {@code contextFactory} as the underlying source.\n\t * @param contextFactory a supplier that returns a new instance on each call\n\t * @param additionalContextInterfaces any additional application context interfaces to\n\t * be added to the application context proxy\n\t * @since 3.4.0\n\t */\n\tpublic ReactiveWebApplicationContextRunner(Supplier<ConfigurableReactiveWebApplicationContext> contextFactory,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\tsuper(ReactiveWebApplicationContextRunner::new, contextFactory, additionalContextInterfaces);\n\t}\n\n\tprivate ReactiveWebApplicationContextRunner(\n\t\t\tRunnerConfiguration<ConfigurableReactiveWebApplicationContext> configuration) {\n\t\tsuper(configuration, ReactiveWebApplicationContextRunner::new);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.lang.Contract;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * An {@link AbstractApplicationContextRunner ApplicationContext runner} for a Servlet\n * based {@link ConfigurableWebApplicationContext}.\n * <p>\n * See {@link AbstractApplicationContextRunner} for details.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic final class WebApplicationContextRunner extends\n\t\tAbstractApplicationContextRunner<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {\n\n\t/**\n\t * Create a new {@link WebApplicationContextRunner} instance using an\n\t * {@link AnnotationConfigServletWebApplicationContext} with a\n\t * {@link MockServletContext} as the underlying source.\n\t * @see #withMockServletContext(Supplier)\n\t */\n\tpublic WebApplicationContextRunner() {\n\t\tthis(withMockServletContext(AnnotationConfigServletWebApplicationContext::new));\n\t}\n\n\t/**\n\t * Create a new {@link WebApplicationContextRunner} instance using the specified\n\t * {@code contextFactory} as the underlying source.\n\t * @param contextFactory a supplier that returns a new instance on each call be added\n\t * to the application context proxy\n\t */\n\tpublic WebApplicationContextRunner(Supplier<ConfigurableWebApplicationContext> contextFactory) {\n\t\tsuper(WebApplicationContextRunner::new, contextFactory);\n\t}\n\n\t/**\n\t * Create a new {@link WebApplicationContextRunner} instance using the specified\n\t * {@code contextFactory} as the underlying source.\n\t * @param contextFactory a supplier that returns a new instance on each call\n\t * @param additionalContextInterfaces any additional application context interfaces to\n\t * be added to the application context proxy\n\t * @since 3.4.0\n\t */\n\tpublic WebApplicationContextRunner(Supplier<ConfigurableWebApplicationContext> contextFactory,\n\t\t\tClass<?>... additionalContextInterfaces) {\n\t\tsuper(WebApplicationContextRunner::new, contextFactory, additionalContextInterfaces);\n\t}\n\n\tprivate WebApplicationContextRunner(RunnerConfiguration<ConfigurableWebApplicationContext> configuration) {\n\t\tsuper(configuration, WebApplicationContextRunner::new);\n\t}\n\n\t/**\n\t * Decorate the specified {@code contextFactory} to set a {@link MockServletContext}\n\t * on each newly created {@link WebApplicationContext}.\n\t * @param contextFactory the context factory to decorate\n\t * @return an updated supplier that will set the {@link MockServletContext}\n\t */\n\t@Contract(\"!null -> !null\")\n\tpublic static @Nullable Supplier<ConfigurableWebApplicationContext> withMockServletContext(\n\t\t\t@Nullable Supplier<ConfigurableWebApplicationContext> contextFactory) {\n\t\treturn (contextFactory != null) ? () -> {\n\t\t\tConfigurableWebApplicationContext context = contextFactory.get();\n\t\t\tcontext.setServletContext(new MockServletContext());\n\t\t\treturn context;\n\t\t} : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Test utilities to run application contexts for testing.\n */\n@NullMarked\npackage org.springframework.boot.test.context.runner;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/http/client/DisableReactorResourceFactoryGlobalResourcesBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.http.client;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.http.client.ReactorResourceFactory;\n\n/**\n * {@link BeanPostProcessor} to disable the use of global resources in\n * {@link ReactorResourceFactory} preventing test cleanup issues.\n *\n * @author Phillip Webb\n */\nclass DisableReactorResourceFactoryGlobalResourcesBeanPostProcessor implements BeanPostProcessor {\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof ReactorResourceFactory reactorResourceFactory) {\n\t\t\treactorResourceFactory.setUseGlobalResources(false);\n\t\t}\n\t\treturn bean;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/http/client/DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.http.client;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ContextCustomizerFactory} to disable the use of global resources in\n * {@link ReactorResourceFactory} preventing test cleanup issues.\n *\n * @author Phillip Webb\n */\nclass DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory implements ContextCustomizerFactory {\n\n\tprivate static final String REACTOR_RESOURCE_FACTORY_CLASS = \"org.springframework.http.client.ReactorResourceFactory\";\n\n\tprivate static final String REACTOR_NETTY_CLASS = \"reactor.netty.ReactorNetty\";\n\n\t@Override\n\tpublic @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\tClassLoader classLoader = testClass.getClassLoader();\n\t\tif (ClassUtils.isPresent(REACTOR_RESOURCE_FACTORY_CLASS, classLoader)\n\t\t\t\t&& ClassUtils.isPresent(REACTOR_NETTY_CLASS, classLoader)) {\n\t\t\treturn new DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer();\n\t\t}\n\t\treturn null;\n\n\t}\n\n\tstatic final class DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer\n\t\t\timplements ContextCustomizer {\n\n\t\tprivate DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer() {\n\t\t}\n\n\t\t@Override\n\t\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\t\tcontext.getBeanFactory()\n\t\t\t\t.registerSingleton(DisableReactorResourceFactoryGlobalResourcesBeanPostProcessor.class.getName(),\n\t\t\t\t\t\tnew DisableReactorResourceFactoryGlobalResourcesBeanPostProcessor());\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\treturn (obj instanceof DisableReactorResourceFactoryGlobalResourcesContextCustomizerCustomizer);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn getClass().hashCode();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/http/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot support for HTTP client testing.\n */\n@NullMarked\npackage org.springframework.boot.test.http.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/LazyUriBuilderFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.http.server;\n\nimport java.net.URI;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.function.SingletonSupplier;\nimport org.springframework.web.util.UriBuilder;\nimport org.springframework.web.util.UriBuilderFactory;\n\n/**\n * Lazy {@link UriBuilderFactory} that only obtains the delegate on first call.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass LazyUriBuilderFactory implements UriBuilderFactory {\n\n\tprivate final Supplier<UriBuilderFactory> supplier;\n\n\tLazyUriBuilderFactory(Supplier<UriBuilderFactory> supplier) {\n\t\tthis.supplier = SingletonSupplier.of(supplier);\n\t}\n\n\t@Override\n\tpublic URI expand(String uriTemplate, Map<String, ? extends @Nullable Object> uriVariables) {\n\t\treturn delegate().expand(uriTemplate, uriVariables);\n\t}\n\n\t@Override\n\tpublic URI expand(String uriTemplate, @Nullable Object... uriVariables) {\n\t\treturn delegate().expand(uriTemplate, uriVariables);\n\t}\n\n\t@Override\n\tpublic UriBuilder uriString(String uriTemplate) {\n\t\treturn delegate().uriString(uriTemplate);\n\t}\n\n\t@Override\n\tpublic UriBuilder builder() {\n\t\treturn delegate().builder();\n\t}\n\n\tprivate UriBuilderFactory delegate() {\n\t\treturn this.supplier.get();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/LocalTestWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.http.server;\n\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.util.Assert;\nimport org.springframework.util.function.SingletonSupplier;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriBuilder;\nimport org.springframework.web.util.UriBuilderFactory;\n\n/**\n * Provides details of a locally running test web server which may have been started on a\n * dynamic port.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class LocalTestWebServer {\n\n\tprivate final Scheme scheme;\n\n\tprivate final SingletonSupplier<BaseUriDetails> baseUriDetails;\n\n\tprivate final UriBuilderFactory uriBuilderFactory;\n\n\tprivate LocalTestWebServer(Scheme scheme, Supplier<BaseUriDetails> baseUriDetailsSupplier) {\n\t\tAssert.notNull(scheme, \"'scheme' must not be null\");\n\t\tAssert.notNull(baseUriDetailsSupplier, \"'baseUriDetailsSupplier' must not be null\");\n\t\tthis.scheme = scheme;\n\t\tthis.baseUriDetails = SingletonSupplier.of(baseUriDetailsSupplier);\n\t\tthis.uriBuilderFactory = new LazyUriBuilderFactory(\n\t\t\t\t() -> new DefaultUriBuilderFactory(this.baseUriDetails.obtain().uri(scheme())));\n\t}\n\n\t/**\n\t * Return if URI scheme used for the request. This method can be safely called before\n\t * the local test server is fully running.\n\t * @return if the web server uses an HTTPS address\n\t */\n\tpublic Scheme scheme() {\n\t\treturn this.scheme;\n\t}\n\n\t/**\n\t * Return the URI of the running local test server. This method should only be called\n\t * once the local test server is fully running.\n\t * @return the URI of the server\n\t */\n\tpublic String uri() {\n\t\treturn uri(null);\n\t}\n\n\t/**\n\t * Return the URI of the running local test server taking into account the given\n\t * {@code uri}. This method should only be called once the local test server is fully\n\t * running.\n\t * @param uri a URI template for the builder or {@code null}\n\t * @return the URI of the server\n\t */\n\tpublic String uri(@Nullable String uri) {\n\t\treturn uriBuilder(uri).toUriString();\n\t}\n\n\t/**\n\t * Return a new {@link UriBuilder} with the base URI template initialized from the\n\t * local server {@link #uri()}. This method should only be called once the local test\n\t * server is fully running.\n\t * @param uri a URI template for the builder or {@code null}\n\t * @return a new {@link UriBuilder} instance\n\t */\n\tpublic UriBuilder uriBuilder(@Nullable String uri) {\n\t\tUriBuilderFactory factory = uriBuilderFactory();\n\t\treturn (uri != null) ? factory.uriString(uri) : factory.builder();\n\t}\n\n\t/**\n\t * Return a new {@link UriBuilderFactory} with the base URI template initialized from\n\t * the local server {@link #uri()}. Methods of the return UriBuilderFactory should\n\t * only be called once the local test server is fully running.\n\t * @return a new {@link UriBuilderFactory}\n\t */\n\tpublic UriBuilderFactory uriBuilderFactory() {\n\t\treturn this.uriBuilderFactory;\n\t}\n\n\t/**\n\t * Return a new {@link LocalTestWebServer} instance that applies the given\n\t * {@code path}.\n\t * @param path a path to append\n\t * @return a new instance with the path added\n\t */\n\tpublic LocalTestWebServer withPath(String path) {\n\t\treturn of(this.scheme, () -> this.baseUriDetails.obtain().withPath(path));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link LocalTestWebServer} instance.\n\t * @param scheme the URL scheme\n\t * @param port the port of the running server\n\t * @return a new {@link LocalTestWebServer} instance\n\t */\n\tpublic static LocalTestWebServer of(Scheme scheme, int port) {\n\t\treturn of(scheme, port, null);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link LocalTestWebServer} instance.\n\t * @param scheme the URL scheme\n\t * @param port the port of the running server\n\t * @param contextPath the context path of the running server\n\t * @return a new {@link LocalTestWebServer} instance\n\t */\n\tpublic static LocalTestWebServer of(Scheme scheme, int port, @Nullable String contextPath) {\n\t\treturn of(scheme, () -> new BaseUriDetails(port, (contextPath != null) ? contextPath : \"\"));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link LocalTestWebServer} instance.\n\t * @param scheme the URL scheme\n\t * @param baseUriDetailsSupplier a supplier to provide the details of the base URI\n\t * @return a new {@link LocalTestWebServer} instance\n\t */\n\tpublic static LocalTestWebServer of(Scheme scheme, Supplier<BaseUriDetails> baseUriDetailsSupplier) {\n\t\treturn new LocalTestWebServer(scheme, baseUriDetailsSupplier);\n\t}\n\n\t/**\n\t * Obtain the {@link LocalTestWebServer} instance provided from the\n\t * {@link ApplicationContext}.\n\t * @param applicationContext the application context\n\t * @return the local test web server (never {@code null})\n\t */\n\tpublic static LocalTestWebServer obtain(ApplicationContext applicationContext) {\n\t\tLocalTestWebServer localTestWebServer = get(applicationContext);\n\t\tAssert.state(localTestWebServer != null, \"No local test web server available\");\n\t\treturn localTestWebServer;\n\t}\n\n\t/**\n\t * Return the {@link LocalTestWebServer} instance provided from the\n\t * {@link ApplicationContext} or {@code null} of no local server is started or could\n\t * be provided.\n\t * @param applicationContext the application context\n\t * @return the local test web server or {@code null}\n\t */\n\tpublic static @Nullable LocalTestWebServer get(ApplicationContext applicationContext) {\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tSpringFactoriesLoader loader = SpringFactoriesLoader\n\t\t\t.forDefaultResourceLocation(applicationContext.getClassLoader());\n\t\treturn loader.load(Provider.class, ArgumentResolver.of(ApplicationContext.class, applicationContext))\n\t\t\t.stream()\n\t\t\t.map(Provider::getLocalTestWebServer)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t/**\n\t * Details of the base URI to the local test web server.\n\t *\n\t * @param port the port of the running server\n\t * @param path the path to use\n\t */\n\tpublic record BaseUriDetails(int port, String path) {\n\n\t\tString uri(Scheme scheme) {\n\t\t\treturn scheme.name().toLowerCase(Locale.ROOT) + \"://localhost:\" + port() + path();\n\t\t}\n\n\t\tBaseUriDetails withPath(String path) {\n\t\t\treturn new BaseUriDetails(port(), path() + path);\n\t\t}\n\n\t}\n\n\t/**\n\t * Supported HTTP schemes.\n\t */\n\tpublic enum Scheme {\n\n\t\t/**\n\t\t * HTTP scheme.\n\t\t */\n\t\tHTTP,\n\n\t\t/**\n\t\t * HTTPS scheme.\n\t\t */\n\t\tHTTPS\n\n\t}\n\n\t/**\n\t * Internal strategy used to provide the running {@link LocalTestWebServer}.\n\t * Implementations can be registered in {@code spring.factories} and may accept an\n\t * {@link ApplicationContext} constructor argument.\n\t */\n\t@FunctionalInterface\n\tpublic interface Provider {\n\n\t\t/**\n\t\t * Return the provided {@link LocalTestWebServer} or {@code null}.\n\t\t * @return the local test web server\n\t\t */\n\t\t@Nullable LocalTestWebServer getLocalTestWebServer();\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for HTTP server testing.\n */\n@NullMarked\npackage org.springframework.boot.test.http.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/AbstractJsonMarshalTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.BufferedReader;\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.lang.reflect.Field;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.InputStreamResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Base class for AssertJ based JSON marshal testers. Exposes specific Asserts following a\n * {@code read}, {@code write} or {@code parse} of JSON content. Typically used in\n * combination with an AssertJ {@link org.assertj.core.api.Assertions#assertThat(Object)\n * assertThat} call. For example:\n *\n * <pre class=\"code\">\n * public class ExampleObjectJsonTests {\n *\n *     private AbstractJsonTester&lt;ExampleObject&gt; json = //...\n *\n *     &#064;Test\n *     public void testWriteJson() {\n *         ExampleObject object = //...\n *         assertThat(json.write(object)).isEqualToJson(\"expected.json\");\n *         assertThat(json.read(\"expected.json\")).isEqualTo(object);\n *     }\n *\n * }\n * </pre>\n *\n * For a complete list of supported assertions see {@link JsonContentAssert} and\n * {@link ObjectContentAssert}.\n * <p>\n * To use this library JSONAssert must be on the test classpath.\n *\n * @param <T> the type under test\n * @author Phillip Webb\n * @since 1.4.0\n * @see JsonContentAssert\n * @see ObjectContentAssert\n */\npublic abstract class AbstractJsonMarshalTester<T> {\n\n\tprivate @Nullable Class<?> resourceLoadClass;\n\n\tprivate @Nullable ResolvableType type;\n\n\t/**\n\t * Create a new uninitialized {@link AbstractJsonMarshalTester} instance.\n\t */\n\tprotected AbstractJsonMarshalTester() {\n\t}\n\n\t/**\n\t * Create a new {@link AbstractJsonMarshalTester} instance.\n\t * @param resourceLoadClass the source class used when loading relative classpath\n\t * resources\n\t * @param type the type under test\n\t */\n\tpublic AbstractJsonMarshalTester(Class<?> resourceLoadClass, ResolvableType type) {\n\t\tAssert.notNull(resourceLoadClass, \"'resourceLoadClass' must not be null\");\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tinitialize(resourceLoadClass, type);\n\t}\n\n\t/**\n\t * Initialize the marshal tester for use.\n\t * @param resourceLoadClass the source class used when loading relative classpath\n\t * resources\n\t * @param type the type under test\n\t */\n\tprotected final void initialize(Class<?> resourceLoadClass, ResolvableType type) {\n\t\tif (this.resourceLoadClass == null && this.type == null) {\n\t\t\tthis.resourceLoadClass = resourceLoadClass;\n\t\t\tthis.type = type;\n\t\t}\n\t}\n\n\t/**\n\t * Return the type under test.\n\t * @return the type under test\n\t */\n\tprotected final @Nullable ResolvableType getType() {\n\t\treturn this.type;\n\t}\n\n\tprivate ResolvableType getTypeNotNull() {\n\t\tResolvableType type = getType();\n\t\tAssert.state(type != null, \"Instance has not been initialized\");\n\t\treturn type;\n\t}\n\n\t/**\n\t * Return class used to load relative resources.\n\t * @return the resource load class\n\t */\n\tprotected final @Nullable Class<?> getResourceLoadClass() {\n\t\treturn this.resourceLoadClass;\n\t}\n\n\tprivate Class<?> getResourceLoadClassNotNull() {\n\t\tClass<?> resourceLoadClass = getResourceLoadClass();\n\t\tAssert.state(resourceLoadClass != null, \"Instance has not been initialized\");\n\t\treturn resourceLoadClass;\n\t}\n\n\t/**\n\t * Return {@link JsonContent} from writing the specific value.\n\t * @param value the value to write\n\t * @return the {@link JsonContent}\n\t * @throws IOException on write error\n\t */\n\tpublic JsonContent<T> write(T value) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\tString json = writeObject(value, getTypeNotNull());\n\t\treturn getJsonContent(json);\n\t}\n\n\t/**\n\t * Factory method used to get a {@link JsonContent} instance from a source JSON\n\t * string.\n\t * @param json the source JSON\n\t * @return a new {@link JsonContent} instance\n\t * @since 2.1.5\n\t */\n\tprotected JsonContent<T> getJsonContent(String json) {\n\t\treturn new JsonContent<>(getResourceLoadClassNotNull(), getType(), json);\n\t}\n\n\t/**\n\t * Return the object created from parsing the specific JSON bytes.\n\t * @param jsonBytes the source JSON bytes\n\t * @return the resulting object\n\t * @throws IOException on parse error\n\t */\n\tpublic T parseObject(byte[] jsonBytes) throws IOException {\n\t\tverify();\n\t\treturn parse(jsonBytes).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from parsing the specific JSON bytes.\n\t * @param jsonBytes the source JSON bytes\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on parse error\n\t */\n\tpublic ObjectContent<T> parse(byte[] jsonBytes) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(jsonBytes, \"'jsonBytes' must not be null\");\n\t\treturn read(new ByteArrayResource(jsonBytes));\n\t}\n\n\t/**\n\t * Return the object created from parsing the specific JSON String.\n\t * @param jsonString the source JSON string\n\t * @return the resulting object\n\t * @throws IOException on parse error\n\t */\n\tpublic T parseObject(String jsonString) throws IOException {\n\t\tverify();\n\t\treturn parse(jsonString).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from parsing the specific JSON String.\n\t * @param jsonString the source JSON string\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on parse error\n\t */\n\tpublic ObjectContent<T> parse(String jsonString) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(jsonString, \"'jsonString' must not be null\");\n\t\treturn read(new StringReader(jsonString));\n\t}\n\n\t/**\n\t * Return the object created from reading from the specified classpath resource.\n\t * @param resourcePath the source resource path. May be a full path or a path relative\n\t * to the {@code resourceLoadClass} passed to the constructor\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tpublic T readObject(String resourcePath) throws IOException {\n\t\tverify();\n\t\treturn read(resourcePath).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from reading from the specified classpath resource.\n\t * @param resourcePath the source resource path. May be a full path or a path relative\n\t * to the {@code resourceLoadClass} passed to the constructor\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on read error\n\t */\n\tpublic ObjectContent<T> read(String resourcePath) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(resourcePath, \"'resourcePath' must not be null\");\n\t\treturn read(new ClassPathResource(resourcePath, this.resourceLoadClass));\n\t}\n\n\t/**\n\t * Return the object created from reading from the specified file.\n\t * @param file the source file\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tpublic T readObject(File file) throws IOException {\n\t\tverify();\n\t\treturn read(file).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from reading from the specified file.\n\t * @param file the source file\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on read error\n\t */\n\tpublic ObjectContent<T> read(File file) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\treturn read(new FileSystemResource(file));\n\t}\n\n\t/**\n\t * Return the object created from reading from the specified input stream.\n\t * @param inputStream the source input stream\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tpublic T readObject(InputStream inputStream) throws IOException {\n\t\tverify();\n\t\treturn read(inputStream).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from reading from the specified input stream.\n\t * @param inputStream the source input stream\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on read error\n\t */\n\tpublic ObjectContent<T> read(InputStream inputStream) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(inputStream, \"'inputStream' must not be null\");\n\t\treturn read(new InputStreamResource(inputStream));\n\t}\n\n\t/**\n\t * Return the object created from reading from the specified resource.\n\t * @param resource the source resource\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tpublic T readObject(Resource resource) throws IOException {\n\t\tverify();\n\t\treturn read(resource).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from reading from the specified resource.\n\t * @param resource the source resource\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on read error\n\t */\n\tpublic ObjectContent<T> read(Resource resource) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(resource, \"'resource' must not be null\");\n\t\tInputStream inputStream = resource.getInputStream();\n\t\tT object = readObject(inputStream, getTypeNotNull());\n\t\tcloseQuietly(inputStream);\n\t\treturn new ObjectContent<>(this.type, object);\n\t}\n\n\t/**\n\t * Return the object created from reading from the specified reader.\n\t * @param reader the source reader\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tpublic T readObject(Reader reader) throws IOException {\n\t\tverify();\n\t\treturn read(reader).getObject();\n\t}\n\n\t/**\n\t * Return {@link ObjectContent} from reading from the specified reader.\n\t * @param reader the source reader\n\t * @return the {@link ObjectContent}\n\t * @throws IOException on read error\n\t */\n\tpublic ObjectContent<T> read(Reader reader) throws IOException {\n\t\tverify();\n\t\tAssert.notNull(reader, \"'reader' must not be null\");\n\t\tT object = readObject(reader, getTypeNotNull());\n\t\tcloseQuietly(reader);\n\t\treturn new ObjectContent<>(this.type, object);\n\t}\n\n\tprivate void closeQuietly(Closeable closeable) {\n\t\ttry {\n\t\t\tcloseable.close();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate void verify() {\n\t\tAssert.state(this.resourceLoadClass != null, \"Uninitialized JsonMarshalTester (ResourceLoadClass is null)\");\n\t\tAssert.state(this.type != null, \"Uninitialized JsonMarshalTester (Type is null)\");\n\t}\n\n\t/**\n\t * Write the specified object to a JSON string.\n\t * @param value the source value (never {@code null})\n\t * @param type the resulting type (never {@code null})\n\t * @return the JSON string\n\t * @throws IOException on write error\n\t */\n\tprotected abstract String writeObject(T value, ResolvableType type) throws IOException;\n\n\t/**\n\t * Read from the specified input stream to create an object of the specified type. The\n\t * default implementation delegates to {@link #readObject(Reader, ResolvableType)}.\n\t * @param inputStream the source input stream (never {@code null})\n\t * @param type the resulting type (never {@code null})\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tprotected T readObject(InputStream inputStream, ResolvableType type) throws IOException {\n\t\tBufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));\n\t\treturn readObject(reader, type);\n\t}\n\n\t/**\n\t * Read from the specified reader to create an object of the specified type.\n\t * @param reader the source reader (never {@code null})\n\t * @param type the resulting type (never {@code null})\n\t * @return the resulting object\n\t * @throws IOException on read error\n\t */\n\tprotected abstract T readObject(Reader reader, ResolvableType type) throws IOException;\n\n\t/**\n\t * Utility class used to support field initialization. Used by subclasses to support\n\t * {@code initFields}.\n\t *\n\t * @param <M> the marshaller type\n\t */\n\tprotected abstract static class FieldInitializer<M> {\n\n\t\tprivate final Class<?> testerClass;\n\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tprotected FieldInitializer(Class<? extends AbstractJsonMarshalTester> testerClass) {\n\t\t\tAssert.notNull(testerClass, \"'testerClass' must not be null\");\n\t\t\tthis.testerClass = testerClass;\n\t\t}\n\n\t\tpublic void initFields(Object testInstance, M marshaller) {\n\t\t\tAssert.notNull(testInstance, \"'testInstance' must not be null\");\n\t\t\tAssert.notNull(marshaller, \"'marshaller' must not be null\");\n\t\t\tinitFields(testInstance, () -> marshaller);\n\t\t}\n\n\t\tpublic void initFields(Object testInstance, final ObjectFactory<M> marshaller) {\n\t\t\tAssert.notNull(testInstance, \"'testInstance' must not be null\");\n\t\t\tAssert.notNull(marshaller, \"'marshaller' must not be null\");\n\t\t\tReflectionUtils.doWithFields(testInstance.getClass(),\n\t\t\t\t\t(field) -> doWithField(field, testInstance, marshaller));\n\t\t}\n\n\t\tprotected void doWithField(Field field, Object test, ObjectFactory<M> marshaller) {\n\t\t\tif (this.testerClass.isAssignableFrom(field.getType())) {\n\t\t\t\tReflectionUtils.makeAccessible(field);\n\t\t\t\tObject existingValue = ReflectionUtils.getField(field, test);\n\t\t\t\tif (existingValue == null) {\n\t\t\t\t\tsetupField(field, test, marshaller);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void setupField(Field field, Object test, ObjectFactory<M> marshaller) {\n\t\t\tResolvableType type = ResolvableType.forField(field).getGeneric();\n\t\t\tReflectionUtils.setField(field, test, createTester(test.getClass(), type, marshaller.getObject()));\n\t\t}\n\n\t\tprotected abstract AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass,\n\t\t\t\tResolvableType type, M marshaller);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/BasicJsonTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * AssertJ based JSON tester that works with basic JSON strings. Allows testing of JSON\n * payloads created from any source, for example:<pre class=\"code\">\n * public class ExampleObjectJsonTests {\n *\n *     private BasicJsonTester json = new BasicJsonTester(getClass());\n *\n *     &#064;Test\n *     public void testWriteJson() throws IOException {\n *         assertThat(json.from(\"example.json\")).extractingJsonPathStringValue(\"@.name\")\n\t\t\t\t.isEqualTo(\"Spring\");\n *     }\n *\n * }\n * </pre>\n *\n * See {@link AbstractJsonMarshalTester} for more details.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.4.0\n */\npublic class BasicJsonTester {\n\n\tprivate @Nullable JsonLoader loader;\n\n\t/**\n\t * Create a new uninitialized {@link BasicJsonTester} instance.\n\t */\n\tprotected BasicJsonTester() {\n\t}\n\n\t/**\n\t * Create a new {@link BasicJsonTester} instance that will load resources as UTF-8.\n\t * @param resourceLoadClass the source class used to load resources\n\t */\n\tpublic BasicJsonTester(Class<?> resourceLoadClass) {\n\t\tthis(resourceLoadClass, null);\n\t}\n\n\t/**\n\t * Create a new {@link BasicJsonTester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param charset the charset used to load resources\n\t * @since 1.4.1\n\t */\n\tpublic BasicJsonTester(Class<?> resourceLoadClass, @Nullable Charset charset) {\n\t\tAssert.notNull(resourceLoadClass, \"'resourceLoadClass' must not be null\");\n\t\tthis.loader = new JsonLoader(resourceLoadClass, charset);\n\t}\n\n\t/**\n\t * Initialize the marshal tester for use, configuring it to load JSON resources as\n\t * UTF-8.\n\t * @param resourceLoadClass the source class used when loading relative classpath\n\t * resources\n\t */\n\tprotected final void initialize(Class<?> resourceLoadClass) {\n\t\tinitialize(resourceLoadClass, null);\n\t}\n\n\t/**\n\t * Initialize the marshal tester for use.\n\t * @param resourceLoadClass the source class used when loading relative classpath\n\t * resources\n\t * @param charset the charset used when loading relative classpath resources\n\t * @since 1.4.1\n\t */\n\tprotected final void initialize(Class<?> resourceLoadClass, @Nullable Charset charset) {\n\t\tif (this.loader == null) {\n\t\t\tthis.loader = new JsonLoader(resourceLoadClass, charset);\n\t\t}\n\t}\n\n\t/**\n\t * Create JSON content from the specified String source. The source can contain the\n\t * JSON itself or, if it ends with {@code .json}, the name of a resource to be loaded\n\t * using {@code resourceLoadClass}.\n\t * @param source the JSON content or a {@code .json} resource name\n\t * @return the JSON content\n\t */\n\tpublic JsonContent<Object> from(CharSequence source) {\n\t\tJsonLoader loader = verify();\n\t\treturn getJsonContent(loader, loader.getJson(source));\n\t}\n\n\t/**\n\t * Create JSON content from the specified resource path.\n\t * @param path the path of the resource to load\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @return the JSON content\n\t */\n\tpublic JsonContent<Object> from(String path, Class<?> resourceLoadClass) {\n\t\tJsonLoader loader = verify();\n\t\treturn getJsonContent(loader, loader.getJson(path, resourceLoadClass));\n\t}\n\n\t/**\n\t * Create JSON content from the specified JSON bytes.\n\t * @param source the bytes of JSON\n\t * @return the JSON content\n\t */\n\tpublic JsonContent<Object> from(byte[] source) {\n\t\tJsonLoader loader = verify();\n\t\treturn getJsonContent(loader, loader.getJson(source));\n\t}\n\n\t/**\n\t * Create JSON content from the specified JSON file.\n\t * @param source the file containing JSON\n\t * @return the JSON content\n\t */\n\tpublic JsonContent<Object> from(File source) {\n\t\tJsonLoader loader = verify();\n\t\treturn getJsonContent(loader, loader.getJson(source));\n\t}\n\n\t/**\n\t * Create JSON content from the specified JSON input stream.\n\t * @param source the input stream containing JSON\n\t * @return the JSON content\n\t */\n\tpublic JsonContent<Object> from(InputStream source) {\n\t\tJsonLoader loader = verify();\n\t\treturn getJsonContent(loader, loader.getJson(source));\n\t}\n\n\t/**\n\t * Create JSON content from the specified JSON resource.\n\t * @param source the resource containing JSON\n\t * @return the JSON content\n\t */\n\tpublic JsonContent<Object> from(Resource source) {\n\t\tJsonLoader loader = verify();\n\t\treturn getJsonContent(loader, loader.getJson(source));\n\t}\n\n\tprivate JsonLoader verify() {\n\t\tAssert.state(this.loader != null, \"Uninitialized BasicJsonTester\");\n\t\treturn this.loader;\n\t}\n\n\tprivate JsonContent<Object> getJsonContent(JsonLoader loader, String json) {\n\t\treturn new JsonContent<>(loader.getResourceLoadClass(), null, json);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.MergedContextConfiguration;\n\n/**\n * A {@link ContextCustomizerFactory} that produces a {@link ContextCustomizer} that warns\n * the user when multiple occurrences of {@code JSONObject} are found on the class path.\n *\n * @author Andy Wilkinson\n */\nclass DuplicateJsonObjectContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\treturn new DuplicateJsonObjectContextCustomizer();\n\t}\n\n\tprivate static final class DuplicateJsonObjectContextCustomizer implements ContextCustomizer {\n\n\t\tprivate final Log logger = LogFactory.getLog(DuplicateJsonObjectContextCustomizer.class);\n\n\t\t@Override\n\t\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\t\tList<URL> jsonObjects = findJsonObjects();\n\t\t\tif (jsonObjects.size() > 1) {\n\t\t\t\tlogDuplicateJsonObjectsWarning(jsonObjects);\n\t\t\t}\n\t\t}\n\n\t\tprivate List<URL> findJsonObjects() {\n\t\t\ttry {\n\t\t\t\tEnumeration<URL> resources = getClass().getClassLoader().getResources(\"org/json/JSONObject.class\");\n\t\t\t\treturn Collections.list(resources);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Continue\n\t\t\t}\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t\tprivate void logDuplicateJsonObjectsWarning(List<URL> jsonObjects) {\n\t\t\tStringBuilder message = new StringBuilder(\n\t\t\t\t\tString.format(\"%n%nFound multiple occurrences of org.json.JSONObject on the class path:%n%n\"));\n\t\t\tfor (URL jsonObject : jsonObjects) {\n\t\t\t\tmessage.append(String.format(\"\\t%s%n\", jsonObject));\n\t\t\t}\n\t\t\tmessage.append(\n\t\t\t\t\tString.format(\"%nYou may wish to exclude one of them to ensure predictable runtime behavior%n\"));\n\t\t\tthis.logger.warn(message);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\treturn (obj != null) && (getClass() == obj.getClass());\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn getClass().hashCode();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/GsonTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.IOException;\nimport java.io.Reader;\n\nimport com.google.gson.Gson;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * AssertJ based JSON tester backed by Gson. Usually instantiated via\n * {@link #initFields(Object, Gson)}, for example: <pre class=\"code\">\n * public class ExampleObjectJsonTests {\n *\n *     private GsonTester&lt;ExampleObject&gt; json;\n *\n *     &#064;Before\n *     public void setup() {\n *         Gson gson = new GsonBuilder().create();\n *         GsonTester.initFields(this, gson);\n *     }\n *\n *     &#064;Test\n *     public void testWriteJson() throws IOException {\n *         ExampleObject object = //...\n *         assertThat(json.write(object)).isEqualToJson(\"expected.json\");\n *     }\n *\n * }\n * </pre>\n *\n * See {@link AbstractJsonMarshalTester} for more details.\n *\n * @param <T> the type under test\n * @author Phillip Webb\n * @since 1.4.0\n */\npublic class GsonTester<T> extends AbstractJsonMarshalTester<T> {\n\n\tprivate final Gson gson;\n\n\t/**\n\t * Create a new uninitialized {@link GsonTester} instance.\n\t * @param gson the Gson instance\n\t */\n\tprotected GsonTester(Gson gson) {\n\t\tAssert.notNull(gson, \"'gson' must not be null\");\n\t\tthis.gson = gson;\n\t}\n\n\t/**\n\t * Create a new {@link GsonTester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test\n\t * @param gson the Gson instance\n\t * @see #initFields(Object, Gson)\n\t */\n\tpublic GsonTester(Class<?> resourceLoadClass, ResolvableType type, Gson gson) {\n\t\tsuper(resourceLoadClass, type);\n\t\tAssert.notNull(gson, \"'gson' must not be null\");\n\t\tthis.gson = gson;\n\t}\n\n\t@Override\n\tprotected String writeObject(T value, ResolvableType type) throws IOException {\n\t\treturn this.gson.toJson(value, type.getType());\n\t}\n\n\t@Override\n\tprotected T readObject(Reader reader, ResolvableType type) throws IOException {\n\t\treturn this.gson.fromJson(reader, type.getType());\n\t}\n\n\t/**\n\t * Utility method to initialize {@link GsonTester} fields. See {@link GsonTester\n\t * class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param gson the Gson instance\n\t */\n\tpublic static void initFields(Object testInstance, Gson gson) {\n\t\tnew GsonFieldInitializer().initFields(testInstance, gson);\n\t}\n\n\t/**\n\t * Utility method to initialize {@link GsonTester} fields. See {@link GsonTester\n\t * class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param gson an object factory to create the Gson instance\n\t */\n\tpublic static void initFields(Object testInstance, ObjectFactory<Gson> gson) {\n\t\tnew GsonFieldInitializer().initFields(testInstance, gson);\n\t}\n\n\t/**\n\t * {@link FieldInitializer} for Gson.\n\t */\n\tprivate static class GsonFieldInitializer extends FieldInitializer<Gson> {\n\n\t\tprotected GsonFieldInitializer() {\n\t\t\tsuper(GsonTester.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,\n\t\t\t\tGson marshaller) {\n\t\t\treturn new GsonTester<>(resourceLoadClass, type, marshaller);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/Jackson2Tester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\n\nimport com.fasterxml.jackson.databind.JavaType;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.ObjectReader;\nimport com.fasterxml.jackson.databind.ObjectWriter;\nimport com.jayway.jsonpath.Configuration;\nimport com.jayway.jsonpath.spi.json.JacksonJsonProvider;\nimport com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * AssertJ based JSON tester backed by Jackson 2. Usually instantiated via\n * {@link #initFields(Object, ObjectMapper)}, for example: <pre class=\"code\">\n * public class ExampleObjectJsonTests {\n *\n *     private Jackson2Tester&lt;ExampleObject&gt; json;\n *\n *     &#064;Before\n *     public void setup() {\n *         ObjectMapper objectMapper = new ObjectMapper();\n *         Jackson2Tester.initFields(this, objectMapper);\n *     }\n *\n *     &#064;Test\n *     public void testWriteJson() throws IOException {\n *         ExampleObject object = //...\n *         assertThat(json.write(object)).isEqualToJson(\"expected.json\");\n *     }\n *\n * }\n * </pre>\n *\n * See {@link AbstractJsonMarshalTester} for more details.\n *\n * @param <T> the type under test\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Diego Berrueta\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic class Jackson2Tester<T> extends AbstractJsonMarshalTester<T> {\n\n\tprivate final ObjectMapper objectMapper;\n\n\tprivate @Nullable Class<?> view;\n\n\t/**\n\t * Create a new {@link Jackson2Tester} instance.\n\t * @param objectMapper the Jackson object mapper\n\t */\n\tprotected Jackson2Tester(ObjectMapper objectMapper) {\n\t\tAssert.notNull(objectMapper, \"'objectMapper' must not be null\");\n\t\tthis.objectMapper = objectMapper;\n\t}\n\n\t/**\n\t * Create a new {@link Jackson2Tester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test\n\t * @param objectMapper the Jackson object mapper\n\t */\n\tpublic Jackson2Tester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper) {\n\t\tthis(resourceLoadClass, type, objectMapper, null);\n\t}\n\n\t/**\n\t * Create a new {@link Jackson2Tester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test\n\t * @param objectMapper the Jackson object mapper\n\t * @param view the JSON view\n\t */\n\tpublic Jackson2Tester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper,\n\t\t\t@Nullable Class<?> view) {\n\t\tsuper(resourceLoadClass, type);\n\t\tAssert.notNull(objectMapper, \"'objectMapper' must not be null\");\n\t\tthis.objectMapper = objectMapper;\n\t\tthis.view = view;\n\t}\n\n\t@Override\n\tprotected JsonContent<T> getJsonContent(String json) {\n\t\tConfiguration configuration = Configuration.builder()\n\t\t\t.jsonProvider(new JacksonJsonProvider(this.objectMapper))\n\t\t\t.mappingProvider(new JacksonMappingProvider(this.objectMapper))\n\t\t\t.build();\n\t\tClass<?> resourceLoadClass = getResourceLoadClass();\n\t\tAssert.state(resourceLoadClass != null, \"'resourceLoadClass' must not be null\");\n\t\treturn new JsonContent<>(resourceLoadClass, getType(), json, configuration);\n\t}\n\n\t@Override\n\tprotected T readObject(InputStream inputStream, ResolvableType type) throws IOException {\n\t\treturn getObjectReader(type).readValue(inputStream);\n\t}\n\n\t@Override\n\tprotected T readObject(Reader reader, ResolvableType type) throws IOException {\n\t\treturn getObjectReader(type).readValue(reader);\n\t}\n\n\tprivate ObjectReader getObjectReader(ResolvableType type) {\n\t\tObjectReader objectReader = this.objectMapper.readerFor(getType(type));\n\t\tif (this.view != null) {\n\t\t\treturn objectReader.withView(this.view);\n\t\t}\n\t\treturn objectReader;\n\t}\n\n\t@Override\n\tprotected String writeObject(T value, ResolvableType type) throws IOException {\n\t\treturn getObjectWriter(type).writeValueAsString(value);\n\t}\n\n\tprivate ObjectWriter getObjectWriter(ResolvableType type) {\n\t\tObjectWriter objectWriter = this.objectMapper.writerFor(getType(type));\n\t\tif (this.view != null) {\n\t\t\treturn objectWriter.withView(this.view);\n\t\t}\n\t\treturn objectWriter;\n\t}\n\n\tprivate JavaType getType(ResolvableType type) {\n\t\treturn this.objectMapper.constructType(type.getType());\n\t}\n\n\t/**\n\t * Utility method to initialize {@link Jackson2Tester} fields. See\n\t * {@link Jackson2Tester class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param objectMapper the JSON mapper\n\t * @see #initFields(Object, ObjectMapper)\n\t */\n\tpublic static void initFields(Object testInstance, ObjectMapper objectMapper) {\n\t\tnew Jackson2FieldInitializer().initFields(testInstance, objectMapper);\n\t}\n\n\t/**\n\t * Utility method to initialize {@link Jackson2Tester} fields. See\n\t * {@link Jackson2Tester class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param objectMapperFactory a factory to create the object mapper\n\t * @see #initFields(Object, ObjectMapper)\n\t */\n\tpublic static void initFields(Object testInstance, ObjectFactory<ObjectMapper> objectMapperFactory) {\n\t\tnew Jackson2FieldInitializer().initFields(testInstance, objectMapperFactory);\n\t}\n\n\t/**\n\t * Returns a new instance of {@link Jackson2Tester} with the view that should be used\n\t * for json serialization/deserialization.\n\t * @param view the view class\n\t * @return the new instance\n\t */\n\tpublic Jackson2Tester<T> forView(Class<?> view) {\n\t\tClass<?> resourceLoadClass = getResourceLoadClass();\n\t\tResolvableType type = getType();\n\t\tAssert.state(resourceLoadClass != null, \"'resourceLoadClass' must not be null\");\n\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\treturn new Jackson2Tester<>(resourceLoadClass, type, this.objectMapper, view);\n\t}\n\n\t/**\n\t * {@link FieldInitializer} for Jackson.\n\t */\n\tprivate static class Jackson2FieldInitializer extends FieldInitializer<ObjectMapper> {\n\n\t\tprotected Jackson2FieldInitializer() {\n\t\t\tsuper(Jackson2Tester.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,\n\t\t\t\tObjectMapper marshaller) {\n\t\t\treturn new Jackson2Tester<>(resourceLoadClass, type, marshaller);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JacksonTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.StringWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport com.jayway.jsonpath.Configuration;\nimport com.jayway.jsonpath.InvalidJsonException;\nimport com.jayway.jsonpath.TypeRef;\nimport com.jayway.jsonpath.spi.json.AbstractJsonProvider;\nimport com.jayway.jsonpath.spi.mapper.MappingException;\nimport com.jayway.jsonpath.spi.mapper.MappingProvider;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JacksonException;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.JavaType;\nimport tools.jackson.databind.ObjectReader;\nimport tools.jackson.databind.ObjectWriter;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * AssertJ based JSON tester backed by Jackson. Usually instantiated via\n * {@link #initFields(Object, JsonMapper)}, for example: <pre class=\"code\">\n * public class ExampleObjectJsonTests {\n *\n *     private JacksonTester&lt;ExampleObject&gt; json;\n *\n *     &#064;Before\n *     public void setup() {\n *         JsonMapper jsonMapper = new JsonMapper();\n *         JacksonTester.initFields(this, jsonMapper);\n *     }\n *\n *     &#064;Test\n *     public void testWriteJson() throws IOException {\n *         ExampleObject object = //...\n *         assertThat(json.write(object)).isEqualToJson(\"expected.json\");\n *     }\n *\n * }\n * </pre>\n *\n * See {@link AbstractJsonMarshalTester} for more details.\n *\n * @param <T> the type under test\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Diego Berrueta\n * @since 1.4.0\n */\npublic class JacksonTester<T> extends AbstractJsonMarshalTester<T> {\n\n\tprivate final JsonMapper jsonMapper;\n\n\tprivate @Nullable Class<?> view;\n\n\t/**\n\t * Create a new {@link JacksonTester} instance.\n\t * @param jsonMapper the Jackson JSON mapper\n\t * @since 4.0.0\n\t */\n\tprotected JacksonTester(JsonMapper jsonMapper) {\n\t\tAssert.notNull(jsonMapper, \"'jsonMapper' must not be null\");\n\t\tthis.jsonMapper = jsonMapper;\n\t}\n\n\t/**\n\t * Create a new {@link JacksonTester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test\n\t * @param jsonMapper the Jackson JSON mapper\n\t * @since 4.0.0\n\t */\n\tpublic JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper) {\n\t\tthis(resourceLoadClass, type, jsonMapper, null);\n\t}\n\n\t/**\n\t * Create a new {@link JacksonTester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test\n\t * @param jsonMapper the Jackson JSON mapper\n\t * @param view the JSON view\n\t * @since 4.0.0\n\t */\n\tpublic JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper,\n\t\t\t@Nullable Class<?> view) {\n\t\tsuper(resourceLoadClass, type);\n\t\tAssert.notNull(jsonMapper, \"'jsonMapper' must not be null\");\n\t\tthis.jsonMapper = jsonMapper;\n\t\tthis.view = view;\n\t}\n\n\t@Override\n\tprotected JsonContent<T> getJsonContent(String json) {\n\t\tConfiguration configuration = Configuration.builder()\n\t\t\t.jsonProvider(new JacksonJsonProvider(this.jsonMapper))\n\t\t\t.mappingProvider(new JacksonMappingProvider(this.jsonMapper))\n\t\t\t.build();\n\t\tClass<?> resourceLoadClass = getResourceLoadClass();\n\t\tAssert.state(resourceLoadClass != null, \"'resourceLoadClass' must not be null\");\n\t\treturn new JsonContent<>(resourceLoadClass, getType(), json, configuration);\n\t}\n\n\t@Override\n\tprotected T readObject(InputStream inputStream, ResolvableType type) throws IOException {\n\t\treturn getObjectReader(type).readValue(inputStream);\n\t}\n\n\t@Override\n\tprotected T readObject(Reader reader, ResolvableType type) throws IOException {\n\t\treturn getObjectReader(type).readValue(reader);\n\t}\n\n\tprivate ObjectReader getObjectReader(ResolvableType type) {\n\t\tObjectReader objectReader = this.jsonMapper.readerFor(getType(type));\n\t\tif (this.view != null) {\n\t\t\treturn objectReader.withView(this.view);\n\t\t}\n\t\treturn objectReader;\n\t}\n\n\t@Override\n\tprotected String writeObject(T value, ResolvableType type) throws IOException {\n\t\treturn getObjectWriter(type).writeValueAsString(value);\n\t}\n\n\tprivate ObjectWriter getObjectWriter(ResolvableType type) {\n\t\tObjectWriter objectWriter = this.jsonMapper.writerFor(getType(type));\n\t\tif (this.view != null) {\n\t\t\treturn objectWriter.withView(this.view);\n\t\t}\n\t\treturn objectWriter;\n\t}\n\n\tprivate JavaType getType(ResolvableType type) {\n\t\treturn this.jsonMapper.constructType(type.getType());\n\t}\n\n\t/**\n\t * Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester\n\t * class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param jsonMapper the JSON mapper\n\t * @since 4.0.0\n\t * @see #initFields(Object, JsonMapper)\n\t */\n\tpublic static void initFields(Object testInstance, JsonMapper jsonMapper) {\n\t\tnew JacksonFieldInitializer().initFields(testInstance, jsonMapper);\n\t}\n\n\t/**\n\t * Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester\n\t * class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param jsonMapperFactory a factory to create the JSON mapper\n\t * @since 4.0.0\n\t * @see #initFields(Object, JsonMapper)\n\t */\n\tpublic static void initFields(Object testInstance, ObjectFactory<JsonMapper> jsonMapperFactory) {\n\t\tnew JacksonFieldInitializer().initFields(testInstance, jsonMapperFactory);\n\t}\n\n\t/**\n\t * Returns a new instance of {@link JacksonTester} with the view that should be used\n\t * for json serialization/deserialization.\n\t * @param view the view class\n\t * @return the new instance\n\t */\n\tpublic JacksonTester<T> forView(Class<?> view) {\n\t\tClass<?> resourceLoadClass = getResourceLoadClass();\n\t\tResolvableType type = getType();\n\t\tAssert.state(resourceLoadClass != null, \"'resourceLoadClass' must not be null\");\n\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\treturn new JacksonTester<>(resourceLoadClass, type, this.jsonMapper, view);\n\t}\n\n\t/**\n\t * {@link FieldInitializer} for Jackson.\n\t */\n\tprivate static class JacksonFieldInitializer extends FieldInitializer<JsonMapper> {\n\n\t\tprotected JacksonFieldInitializer() {\n\t\t\tsuper(JacksonTester.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,\n\t\t\t\tJsonMapper marshaller) {\n\t\t\treturn new JacksonTester<>(resourceLoadClass, type, marshaller);\n\t\t}\n\n\t}\n\n\tprivate static final class JacksonJsonProvider extends AbstractJsonProvider {\n\n\t\tprivate final JsonMapper jsonMapper;\n\n\t\tprivate final ObjectReader objectReader;\n\n\t\tprivate JacksonJsonProvider(JsonMapper jsonMapper) {\n\t\t\tthis.jsonMapper = jsonMapper;\n\t\t\tthis.objectReader = jsonMapper.reader().forType(Object.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object parse(String json) throws InvalidJsonException {\n\t\t\ttry {\n\t\t\t\treturn this.objectReader.readValue(json);\n\t\t\t}\n\t\t\tcatch (JacksonException ex) {\n\t\t\t\tthrow new InvalidJsonException(ex, json);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Object parse(byte[] json) throws InvalidJsonException {\n\t\t\ttry {\n\t\t\t\treturn this.objectReader.readValue(json);\n\t\t\t}\n\t\t\tcatch (JacksonException ex) {\n\t\t\t\tthrow new InvalidJsonException(ex, new String(json, StandardCharsets.UTF_8));\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Object parse(InputStream jsonStream, String charset) throws InvalidJsonException {\n\t\t\ttry {\n\t\t\t\treturn this.objectReader.readValue(new InputStreamReader(jsonStream, charset));\n\t\t\t}\n\t\t\tcatch (UnsupportedEncodingException | JacksonException ex) {\n\t\t\t\tthrow new InvalidJsonException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String toJson(Object obj) {\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\ttry (JsonGenerator generator = this.jsonMapper.createGenerator(writer)) {\n\t\t\t\tthis.jsonMapper.writeValue(generator, obj);\n\t\t\t}\n\t\t\tcatch (JacksonException ex) {\n\t\t\t\tthrow new InvalidJsonException(ex);\n\t\t\t}\n\t\t\treturn writer.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Object> createArray() {\n\t\t\treturn new LinkedList<>();\n\t\t}\n\n\t\t@Override\n\t\tpublic Object createMap() {\n\t\t\treturn new LinkedHashMap<String, Object>();\n\t\t}\n\n\t}\n\n\tprivate static final class JacksonMappingProvider implements MappingProvider {\n\n\t\tprivate final JsonMapper jsonMapper;\n\n\t\tprivate JacksonMappingProvider(JsonMapper jsonMapper) {\n\t\t\tthis.jsonMapper = jsonMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> @Nullable T map(Object source, Class<T> targetType, Configuration configuration) {\n\t\t\tif (source == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.jsonMapper.convertValue(source, targetType);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new MappingException(ex);\n\t\t\t}\n\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic <T> @Nullable T map(Object source, final TypeRef<T> targetType, Configuration configuration) {\n\t\t\tif (source == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tJavaType type = this.jsonMapper.getTypeFactory().constructType(targetType.getType());\n\t\t\ttry {\n\t\t\t\treturn (T) this.jsonMapper.convertValue(source, type);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new MappingException(ex);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport com.jayway.jsonpath.Configuration;\nimport org.assertj.core.api.AssertProvider;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * JSON content usually created from a JSON tester. Generally used only to\n * {@link AssertProvider provide} {@link JsonContentAssert} to AssertJ {@code assertThat}\n * calls.\n *\n * @param <T> the source type that created the content\n * @author Phillip Webb\n * @author Diego Berrueta\n * @since 1.4.0\n */\npublic final class JsonContent<T> implements AssertProvider<JsonContentAssert> {\n\n\tprivate final Class<?> resourceLoadClass;\n\n\tprivate final @Nullable ResolvableType type;\n\n\tprivate final String json;\n\n\tprivate final Configuration configuration;\n\n\t/**\n\t * Create a new {@link JsonContent} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test (or {@code null} if not known)\n\t * @param json the actual JSON content\n\t */\n\tpublic JsonContent(Class<?> resourceLoadClass, @Nullable ResolvableType type, String json) {\n\t\tthis(resourceLoadClass, type, json, Configuration.defaultConfiguration());\n\t}\n\n\t/**\n\t * Create a new {@link JsonContent} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test (or {@code null} if not known)\n\t * @param json the actual JSON content\n\t * @param configuration the JsonPath configuration\n\t */\n\tJsonContent(Class<?> resourceLoadClass, @Nullable ResolvableType type, String json, Configuration configuration) {\n\t\tAssert.notNull(resourceLoadClass, \"'resourceLoadClass' must not be null\");\n\t\tAssert.notNull(json, \"'json' must not be null\");\n\t\tAssert.notNull(configuration, \"'configuration' must not be null\");\n\t\tthis.resourceLoadClass = resourceLoadClass;\n\t\tthis.type = type;\n\t\tthis.json = json;\n\t\tthis.configuration = configuration;\n\t}\n\n\t/**\n\t * Use AssertJ's {@link org.assertj.core.api.Assertions#assertThat assertThat}\n\t * instead.\n\t * @deprecated to prevent accidental use. Prefer standard AssertJ\n\t * {@code assertThat(context)...} calls instead.\n\t */\n\t@Override\n\t@Deprecated(since = \"1.5.7\", forRemoval = false)\n\tpublic JsonContentAssert assertThat() {\n\t\treturn new JsonContentAssert(this.resourceLoadClass, null, this.json, this.configuration);\n\t}\n\n\t/**\n\t * Return the actual JSON content string.\n\t * @return the JSON content\n\t */\n\tpublic String getJson() {\n\t\treturn this.json;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tString createdFrom = (this.type != null) ? \" created from \" + this.type : \"\";\n\t\treturn \"JsonContent \" + this.json + createdFrom;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonContentAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.jayway.jsonpath.Configuration;\nimport com.jayway.jsonpath.JsonPath;\nimport com.jayway.jsonpath.PathNotFoundException;\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AbstractBooleanAssert;\nimport org.assertj.core.api.AbstractCharSequenceAssert;\nimport org.assertj.core.api.AbstractObjectAssert;\nimport org.assertj.core.api.Assert;\nimport org.assertj.core.api.ListAssert;\nimport org.assertj.core.api.MapAssert;\nimport org.jspecify.annotations.Nullable;\nimport org.skyscreamer.jsonassert.JSONCompare;\nimport org.skyscreamer.jsonassert.JSONCompareMode;\nimport org.skyscreamer.jsonassert.JSONCompareResult;\nimport org.skyscreamer.jsonassert.comparator.JSONComparator;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.lang.CheckReturnValue;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.ThrowingFunction;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * AssertJ {@link Assert} for {@link JsonContent}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Diego Berrueta\n * @author Camille Vienot\n * @since 1.4.0\n */\npublic class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSequence> {\n\n\tprivate final JsonLoader loader;\n\n\tprivate final Configuration configuration;\n\n\t/**\n\t * Create a new {@link JsonContentAssert} instance that will load resources as UTF-8.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param json the actual JSON content\n\t */\n\tpublic JsonContentAssert(Class<?> resourceLoadClass, @Nullable CharSequence json) {\n\t\tthis(resourceLoadClass, null, json);\n\t}\n\n\t/**\n\t * Create a new {@link JsonContentAssert} instance that will load resources in the\n\t * given {@code charset}.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param charset the charset of the JSON resources\n\t * @param json the actual JSON content\n\t * @since 1.4.1\n\t */\n\tpublic JsonContentAssert(Class<?> resourceLoadClass, @Nullable Charset charset, @Nullable CharSequence json) {\n\t\tthis(resourceLoadClass, charset, json, Configuration.defaultConfiguration());\n\t}\n\n\t/**\n\t * Create a new {@link JsonContentAssert} instance that will load resources in the\n\t * given {@code charset}.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param charset the charset of the JSON resources\n\t * @param json the actual JSON content\n\t * @param configuration the json-path configuration\n\t */\n\tJsonContentAssert(Class<?> resourceLoadClass, @Nullable Charset charset, @Nullable CharSequence json,\n\t\t\tConfiguration configuration) {\n\t\tsuper(json, JsonContentAssert.class);\n\t\tthis.configuration = configuration;\n\t\tthis.loader = new JsonLoader(resourceLoadClass, charset);\n\t}\n\n\t/**\n\t * Overridden version of {@code isEqualTo} to perform JSON tests based on the object\n\t * type.\n\t * @see org.assertj.core.api.AbstractAssert#isEqualTo(java.lang.Object)\n\t */\n\t@Override\n\tpublic JsonContentAssert isEqualTo(@Nullable Object expected) {\n\t\tif (expected == null || expected instanceof CharSequence) {\n\t\t\treturn isEqualToJson((CharSequence) expected);\n\t\t}\n\t\tif (expected instanceof byte[] bytes) {\n\t\t\treturn isEqualToJson(bytes);\n\t\t}\n\t\tif (expected instanceof File file) {\n\t\t\treturn isEqualToJson(file);\n\t\t}\n\t\tif (expected instanceof InputStream inputStream) {\n\t\t\treturn isEqualToJson(inputStream);\n\t\t}\n\t\tif (expected instanceof Resource resource) {\n\t\t\treturn isEqualToJson(resource);\n\t\t}\n\t\tfailWithMessage(\"Unsupported type for JSON assert %s\", expected.getClass());\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal\n\t * to the specified JSON. The {@code expected} value can contain the JSON itself or,\n\t * if it ends with {@code .json}, the name of a resource to be loaded using\n\t * {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(@Nullable CharSequence expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal\n\t * to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal\n\t * to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(byte[] expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal\n\t * to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(File expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal\n\t * to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(InputStream expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#LENIENT leniently} equal\n\t * to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(Resource expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to\n\t * the specified JSON. The {@code expected} value can contain the JSON itself or, if\n\t * it ends with {@code .json}, the name of a resource to be loaded using\n\t * {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isStrictlyEqualToJson(CharSequence expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to\n\t * the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isStrictlyEqualToJson(String path, Class<?> resourceLoadClass) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to\n\t * the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isStrictlyEqualToJson(byte[] expected) {\n\t\treturn assertNotFailed(compare(this.loader.getJson(expected), JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to\n\t * the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isStrictlyEqualToJson(File expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to\n\t * the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isStrictlyEqualToJson(InputStream expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is {@link JSONCompareMode#STRICT strictly} equal to\n\t * the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isStrictlyEqualToJson(Resource expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON. The {@code expected}\n\t * value can contain the JSON itself or, if it ends with {@code .json}, the name of a\n\t * resource to be loaded using {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(CharSequence expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotFailed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(byte[] expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(File expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(InputStream expected, JSONCompareMode compareMode) {\n\t\treturn assertNotFailed(compare(this.loader.getJson(expected), compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(Resource expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON. The {@code expected}\n\t * value can contain the JSON itself or, if it ends with {@code .json}, the name of a\n\t * resource to be loaded using {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(CharSequence expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotFailed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(byte[] expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(File expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(InputStream expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is equal to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is not equal to the given one\n\t */\n\tpublic JsonContentAssert isEqualToJson(Resource expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotFailed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Overridden version of {@code isNotEqualTo} to perform JSON tests based on the\n\t * object type.\n\t * @see org.assertj.core.api.AbstractAssert#isEqualTo(java.lang.Object)\n\t */\n\t@Override\n\tpublic JsonContentAssert isNotEqualTo(@Nullable Object expected) {\n\t\tif (expected == null || expected instanceof CharSequence) {\n\t\t\treturn isNotEqualToJson((CharSequence) expected);\n\t\t}\n\t\tif (expected instanceof byte[] bytes) {\n\t\t\treturn isNotEqualToJson(bytes);\n\t\t}\n\t\tif (expected instanceof File file) {\n\t\t\treturn isNotEqualToJson(file);\n\t\t}\n\t\tif (expected instanceof InputStream inputStream) {\n\t\t\treturn isNotEqualToJson(inputStream);\n\t\t}\n\t\tif (expected instanceof Resource resource) {\n\t\t\treturn isNotEqualToJson(resource);\n\t\t}\n\t\tfailWithMessage(\"Unsupported type for JSON assert %s\", expected.getClass());\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently}\n\t * equal to the specified JSON. The {@code expected} value can contain the JSON itself\n\t * or, if it ends with {@code .json}, the name of a resource to be loaded using\n\t * {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(@Nullable CharSequence expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently}\n\t * equal to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(String path, Class<?> resourceLoadClass) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently}\n\t * equal to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(byte[] expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently}\n\t * equal to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(File expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently}\n\t * equal to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(InputStream expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#LENIENT leniently}\n\t * equal to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(Resource expected) {\n\t\treturn assertNotPassed(compare(this.loader.getJson(expected), JSONCompareMode.LENIENT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal\n\t * to the specified JSON. The {@code expected} value can contain the JSON itself or,\n\t * if it ends with {@code .json}, the name of a resource to be loaded using\n\t * {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotStrictlyEqualToJson(CharSequence expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal\n\t * to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotStrictlyEqualToJson(String path, Class<?> resourceLoadClass) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal\n\t * to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotStrictlyEqualToJson(byte[] expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal\n\t * to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotStrictlyEqualToJson(File expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal\n\t * to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotStrictlyEqualToJson(InputStream expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not {@link JSONCompareMode#STRICT strictly} equal\n\t * to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotStrictlyEqualToJson(Resource expected) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, JSONCompareMode.STRICT));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON. The\n\t * {@code expected} value can contain the JSON itself or, if it ends with\n\t * {@code .json}, the name of a resource to be loaded using {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(CharSequence expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(String path, Class<?> resourceLoadClass, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotPassed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(byte[] expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(File expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(InputStream expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @param compareMode the compare mode used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(Resource expected, JSONCompareMode compareMode) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, compareMode));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON. The\n\t * {@code expected} value can contain the JSON itself or, if it ends with\n\t * {@code .json}, the name of a resource to be loaded using {@code resourceLoadClass}.\n\t * @param expected the expected JSON or the name of a resource containing the expected\n\t * JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(CharSequence expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON resource.\n\t * @param path the name of a resource containing the expected JSON\n\t * @param resourceLoadClass the source class used to load the resource\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(String path, Class<?> resourceLoadClass, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(path, resourceLoadClass);\n\t\treturn assertNotPassed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON bytes.\n\t * @param expected the expected JSON bytes\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(byte[] expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON file.\n\t * @param expected a file containing the expected JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(File expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON input stream.\n\t * @param expected an input stream containing the expected JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(InputStream expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verifies that the actual value is not equal to the specified JSON resource.\n\t * @param expected a resource containing the expected JSON\n\t * @param comparator the comparator used when checking\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual JSON value is equal to the given one\n\t */\n\tpublic JsonContentAssert isNotEqualToJson(Resource expected, JSONComparator comparator) {\n\t\tString expectedJson = this.loader.getJson(expected);\n\t\treturn assertNotPassed(compare(expectedJson, comparator));\n\t}\n\n\t/**\n\t * Verify that the JSON path is present without checking if it has a value.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing\n\t * @since 2.2.0\n\t * @see #hasJsonPathValue(CharSequence, Object...)\n\t */\n\tpublic JsonContentAssert hasJsonPath(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasPath();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces a non-null result. If\n\t * the JSON path expression is not {@linkplain JsonPath#isDefinite() definite}, this\n\t * method verifies that the value at the given path is not <em>empty</em>.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing\n\t */\n\tpublic JsonContentAssert hasJsonPathValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasValue(Object.class, \"an object\");\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces a non-null string\n\t * result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing or not a string\n\t */\n\tpublic JsonContentAssert hasJsonPathStringValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasValue(String.class, \"a string\");\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces a non-null number\n\t * result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing or not a number\n\t */\n\tpublic JsonContentAssert hasJsonPathNumberValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasValue(Number.class, \"a number\");\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces a non-null boolean\n\t * result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing or not a boolean\n\t */\n\tpublic JsonContentAssert hasJsonPathBooleanValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasValue(Boolean.class, \"a boolean\");\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces a non-null array\n\t * result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing or not an array\n\t */\n\tpublic JsonContentAssert hasJsonPathArrayValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasValue(List.class, \"an array\");\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces a non-null map result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is missing or not a map\n\t */\n\tpublic JsonContentAssert hasJsonPathMapValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasValue(Map.class, \"a map\");\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces an\n\t * {@link ObjectUtils#isEmpty(Object) empty} result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is not empty\n\t */\n\tpublic JsonContentAssert hasEmptyJsonPathValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertHasEmptyValue();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the JSON path is not present, even if it has a {@code null} value.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is not missing\n\t * @since 2.2.0\n\t * @see #doesNotHaveJsonPathValue(CharSequence, Object...)\n\t */\n\tpublic JsonContentAssert doesNotHaveJsonPath(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertDoesNotHavePath();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path produces no result. If the JSON\n\t * path expression is not {@linkplain JsonPath#isDefinite() definite}, this method\n\t * verifies that the value at the given path is <em>empty</em>.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is not missing\n\t */\n\tpublic JsonContentAssert doesNotHaveJsonPathValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertDoesNotHaveValue();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verify that the actual value at the given JSON path does not produce an\n\t * {@link ObjectUtils#isEmpty(Object) empty} result.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the value at the given path is empty\n\t */\n\tpublic JsonContentAssert doesNotHaveEmptyJsonPathValue(CharSequence expression, Object... args) {\n\t\tnew JsonPathValue(expression, args).assertDoesNotHaveEmptyValue();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Extract the value at the given JSON path for further object assertions.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return a new assertion object whose object under test is the extracted item\n\t * @throws AssertionError if the path is not valid\n\t */\n\t@CheckReturnValue\n\tpublic AbstractObjectAssert<?, Object> extractingJsonPathValue(CharSequence expression, Object... args) {\n\t\treturn assertThat(new JsonPathValue(expression, args).getValue(false));\n\t}\n\n\t/**\n\t * Extract the string value at the given JSON path for further object assertions.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return a new assertion object whose object under test is the extracted item\n\t * @throws AssertionError if the path is not valid or does not result in a string\n\t */\n\t@CheckReturnValue\n\tpublic AbstractCharSequenceAssert<?, String> extractingJsonPathStringValue(CharSequence expression,\n\t\t\tObject... args) {\n\t\treturn assertThat(extractingJsonPathValue(expression, args, String.class, \"a string\"));\n\t}\n\n\t/**\n\t * Extract the number value at the given JSON path for further object assertions.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return a new assertion object whose object under test is the extracted item\n\t * @throws AssertionError if the path is not valid or does not result in a number\n\t */\n\t@CheckReturnValue\n\tpublic AbstractObjectAssert<?, Number> extractingJsonPathNumberValue(CharSequence expression, Object... args) {\n\t\treturn assertThat(extractingJsonPathValue(expression, args, Number.class, \"a number\"));\n\t}\n\n\t/**\n\t * Extract the boolean value at the given JSON path for further object assertions.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @return a new assertion object whose object under test is the extracted item\n\t * @throws AssertionError if the path is not valid or does not result in a boolean\n\t */\n\t@CheckReturnValue\n\tpublic AbstractBooleanAssert<?> extractingJsonPathBooleanValue(CharSequence expression, Object... args) {\n\t\treturn assertThat(extractingJsonPathValue(expression, args, Boolean.class, \"a boolean\"));\n\t}\n\n\t/**\n\t * Extract the array value at the given JSON path for further object assertions.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @param <E> element type\n\t * @return a new assertion object whose object under test is the extracted item\n\t * @throws AssertionError if the path is not valid or does not result in an array\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\t@CheckReturnValue\n\tpublic <E> ListAssert<E> extractingJsonPathArrayValue(CharSequence expression, Object... args) {\n\t\treturn assertThat(extractingJsonPathValue(expression, args, List.class, \"an array\"));\n\t}\n\n\t/**\n\t * Extract the map value at the given JSON path for further object assertions.\n\t * @param expression the {@link JsonPath} expression\n\t * @param args arguments to parameterize the {@code JsonPath} expression with, using\n\t * formatting specifiers defined in {@link String#format(String, Object...)}\n\t * @param <K> key type\n\t * @param <V> value type\n\t * @return a new assertion object whose object under test is the extracted item\n\t * @throws AssertionError if the path is not valid or does not result in a map\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\t@CheckReturnValue\n\tpublic <K, V> MapAssert<K, V> extractingJsonPathMapValue(CharSequence expression, Object... args) {\n\t\treturn assertThat(extractingJsonPathValue(expression, args, Map.class, \"a map\"));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T extractingJsonPathValue(CharSequence expression, Object[] args, Class<T> type,\n\t\t\tString expectedDescription) {\n\t\tJsonPathValue value = new JsonPathValue(expression, args);\n\t\tif (value.getValue(false) != null) {\n\t\t\tvalue.assertHasValue(type, expectedDescription);\n\t\t}\n\t\treturn (T) value.getValue(false);\n\t}\n\n\tprivate JSONCompareResult compare(@Nullable CharSequence expectedJson, JSONCompareMode compareMode) {\n\t\treturn compare(expectedJson,\n\t\t\t\t(expected) -> JSONCompare.compareJSON(expected, this.actual.toString(), compareMode));\n\t}\n\n\tprivate JSONCompareResult compare(@Nullable CharSequence expectedJson, JSONComparator comparator) {\n\t\treturn compare(expectedJson,\n\t\t\t\t(expected) -> JSONCompare.compareJSON(expected, this.actual.toString(), comparator));\n\t}\n\n\tprivate JSONCompareResult compare(@Nullable CharSequence expectedJson,\n\t\t\tThrowingFunction<String, JSONCompareResult> compareAction) {\n\t\tif (this.actual == null) {\n\t\t\treturn compareForNull(expectedJson);\n\t\t}\n\t\tif (expectedJson == null) {\n\t\t\treturn fail(\"Expected JSON but got null\");\n\t\t}\n\t\ttry {\n\t\t\treturn compareAction.applyWithException(expectedJson.toString());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof RuntimeException runtimeException) {\n\t\t\t\tthrow runtimeException;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate JSONCompareResult compareForNull(@Nullable CharSequence expectedJson) {\n\t\tJSONCompareResult result = new JSONCompareResult();\n\t\tresult.passed();\n\t\tif (expectedJson != null) {\n\t\t\tresult.fail(\"Expected null JSON\");\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate JSONCompareResult fail(String message) {\n\t\tJSONCompareResult result = new JSONCompareResult();\n\t\tresult.fail(message);\n\t\treturn result;\n\t}\n\n\tprivate JsonContentAssert assertNotFailed(JSONCompareResult result) {\n\t\tif (result.failed()) {\n\t\t\tfailWithMessage(\"JSON Comparison failure: %s\", result.getMessage());\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate JsonContentAssert assertNotPassed(JSONCompareResult result) {\n\t\tif (result.passed()) {\n\t\t\tfailWithMessage(\"JSON Comparison failure: %s\", result.getMessage());\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * A {@link JsonPath} value.\n\t */\n\tprivate class JsonPathValue {\n\n\t\tprivate final String expression;\n\n\t\tprivate final JsonPath jsonPath;\n\n\t\tJsonPathValue(CharSequence expression, Object... args) {\n\t\t\torg.springframework.util.Assert.hasText((expression != null) ? expression.toString() : null,\n\t\t\t\t\t\"'expression' must not be empty\");\n\t\t\tthis.expression = String.format(expression.toString(), args);\n\t\t\tthis.jsonPath = JsonPath.compile(this.expression);\n\t\t}\n\n\t\tvoid assertHasEmptyValue() {\n\t\t\tif (ObjectUtils.isEmpty(getValue(false)) || isIndefiniteAndEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailWithMessage(getExpectedValueMessage(\"an empty value\"));\n\t\t}\n\n\t\tvoid assertDoesNotHaveEmptyValue() {\n\t\t\tif (!ObjectUtils.isEmpty(getValue(false))) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailWithMessage(getExpectedValueMessage(\"a non-empty value\"));\n\n\t\t}\n\n\t\tvoid assertHasPath() {\n\t\t\ttry {\n\t\t\t\tread();\n\t\t\t}\n\t\t\tcatch (PathNotFoundException ex) {\n\t\t\t\tfailWithMessage(\"No JSON path \\\"%s\\\" found\", this.expression);\n\t\t\t}\n\t\t}\n\n\t\tvoid assertDoesNotHavePath() {\n\t\t\ttry {\n\t\t\t\tread();\n\t\t\t\tfailWithMessage(\"Expecting no JSON path \\\"%s\\\"\", this.expression);\n\t\t\t}\n\t\t\tcatch (PathNotFoundException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\n\t\tvoid assertHasValue(@Nullable Class<?> type, String expectedDescription) {\n\t\t\tObject value = getValue(true);\n\t\t\tif (value == null || isIndefiniteAndEmpty()) {\n\t\t\t\tfailWithNoValueMessage();\n\t\t\t}\n\t\t\tif (type != null && !type.isInstance(value)) {\n\t\t\t\tfailWithMessage(getExpectedValueMessage(expectedDescription));\n\t\t\t}\n\t\t}\n\n\t\tvoid assertDoesNotHaveValue() {\n\t\t\tif (getValue(false) == null || isIndefiniteAndEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfailWithMessage(getExpectedValueMessage(\"no value\"));\n\t\t}\n\n\t\tprivate boolean isIndefiniteAndEmpty() {\n\t\t\treturn !isDefinite() && isEmpty();\n\t\t}\n\n\t\tprivate boolean isDefinite() {\n\t\t\treturn this.jsonPath.isDefinite();\n\t\t}\n\n\t\tprivate boolean isEmpty() {\n\t\t\treturn ObjectUtils.isEmpty(getValue(false));\n\t\t}\n\n\t\t@Nullable Object getValue(boolean required) {\n\t\t\ttry {\n\t\t\t\treturn read();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tif (required) {\n\t\t\t\t\tfailWithNoValueMessage();\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprivate void failWithNoValueMessage() {\n\t\t\tfailWithMessage(\"No value at JSON path \\\"%s\\\"\", this.expression);\n\t\t}\n\n\t\tprivate Object read() {\n\t\t\tCharSequence json = JsonContentAssert.this.actual;\n\t\t\treturn this.jsonPath.read((json != null) ? json.toString() : null, JsonContentAssert.this.configuration);\n\t\t}\n\n\t\tprivate String getExpectedValueMessage(String expectedDescription) {\n\t\t\treturn String.format(\"Expected %s at JSON path \\\"%s\\\" but found: %s\", expectedDescription, this.expression,\n\t\t\t\t\tObjectUtils.nullSafeToString(StringUtils.quoteIfString(getValue(false))));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * Internal helper used to load JSON from various sources.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass JsonLoader {\n\n\tprivate final Class<?> resourceLoadClass;\n\n\tprivate final Charset charset;\n\n\tJsonLoader(Class<?> resourceLoadClass, @Nullable Charset charset) {\n\t\tthis.resourceLoadClass = resourceLoadClass;\n\t\tthis.charset = (charset != null) ? charset : StandardCharsets.UTF_8;\n\t}\n\n\tClass<?> getResourceLoadClass() {\n\t\treturn this.resourceLoadClass;\n\t}\n\n\t@Contract(\"!null -> !null\")\n\t@Nullable String getJson(@Nullable CharSequence source) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (source.toString().endsWith(\".json\")) {\n\t\t\treturn getJson(new ClassPathResource(source.toString(), this.resourceLoadClass));\n\t\t}\n\t\treturn source.toString();\n\t}\n\n\tString getJson(String path, Class<?> resourceLoadClass) {\n\t\treturn getJson(new ClassPathResource(path, resourceLoadClass));\n\t}\n\n\tString getJson(byte[] source) {\n\t\treturn getJson(new ByteArrayInputStream(source));\n\t}\n\n\tString getJson(File source) {\n\t\ttry {\n\t\t\treturn getJson(new FileInputStream(source));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load JSON from \" + source, ex);\n\t\t}\n\t}\n\n\tString getJson(Resource source) {\n\t\ttry {\n\t\t\treturn getJson(source.getInputStream());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load JSON from \" + source, ex);\n\t\t}\n\t}\n\n\tString getJson(InputStream source) {\n\t\ttry {\n\t\t\treturn FileCopyUtils.copyToString(new InputStreamReader(source, this.charset));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load JSON from InputStream\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/JsonbTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.IOException;\nimport java.io.Reader;\n\nimport jakarta.json.bind.Jsonb;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * AssertJ based JSON tester backed by Jsonb. Usually instantiated via\n * {@link #initFields(Object, Jsonb)}, for example: <pre class=\"code\">\n * public class ExampleObjectJsonTests {\n *\n * \tprivate JsonbTester&lt;ExampleObject&gt; json;\n *\n * \t&#064;Before\n * \tpublic void setup() {\n * \t\tJsonb jsonb = JsonbBuilder.create();\n * \t\tJsonbTester.initFields(this, jsonb);\n * \t}\n *\n * \t&#064;Test\n * \tpublic void testWriteJson() throws IOException {\n * \t\tExampleObject object = // ...\n * \t\tassertThat(json.write(object)).isEqualToJson(&quot;expected.json&quot;);\n * \t}\n *\n * }\n * </pre>\n *\n * See {@link AbstractJsonMarshalTester} for more details.\n *\n * @param <T> the type under test\n * @author Eddú Meléndez\n * @since 2.0.0\n */\npublic class JsonbTester<T> extends AbstractJsonMarshalTester<T> {\n\n\tprivate final Jsonb jsonb;\n\n\t/**\n\t * Create a new uninitialized {@link JsonbTester} instance.\n\t * @param jsonb the Jsonb instance\n\t */\n\tprotected JsonbTester(Jsonb jsonb) {\n\t\tAssert.notNull(jsonb, \"'jsonb' must not be null\");\n\t\tthis.jsonb = jsonb;\n\t}\n\n\t/**\n\t * Create a new {@link JsonbTester} instance.\n\t * @param resourceLoadClass the source class used to load resources\n\t * @param type the type under test\n\t * @param jsonb the Jsonb instance\n\t * @see #initFields(Object, Jsonb)\n\t */\n\tpublic JsonbTester(Class<?> resourceLoadClass, ResolvableType type, Jsonb jsonb) {\n\t\tsuper(resourceLoadClass, type);\n\t\tAssert.notNull(jsonb, \"'jsonb' must not be null\");\n\t\tthis.jsonb = jsonb;\n\t}\n\n\t@Override\n\tprotected String writeObject(T value, ResolvableType type) throws IOException {\n\t\treturn this.jsonb.toJson(value, type.getType());\n\t}\n\n\t@Override\n\tprotected T readObject(Reader reader, ResolvableType type) throws IOException {\n\t\treturn this.jsonb.fromJson(reader, type.getType());\n\t}\n\n\t/**\n\t * Utility method to initialize {@link JsonbTester} fields. See {@link JsonbTester\n\t * class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param jsonb the Jsonb instance\n\t */\n\tpublic static void initFields(Object testInstance, Jsonb jsonb) {\n\t\tnew JsonbFieldInitializer().initFields(testInstance, jsonb);\n\t}\n\n\t/**\n\t * Utility method to initialize {@link JsonbTester} fields. See {@link JsonbTester\n\t * class-level documentation} for example usage.\n\t * @param testInstance the test instance\n\t * @param jsonb an object factory to create the Jsonb instance\n\t */\n\tpublic static void initFields(Object testInstance, ObjectFactory<Jsonb> jsonb) {\n\t\tnew JsonbTester.JsonbFieldInitializer().initFields(testInstance, jsonb);\n\t}\n\n\t/**\n\t * {@link FieldInitializer} for Jsonb.\n\t */\n\tprivate static class JsonbFieldInitializer extends FieldInitializer<Jsonb> {\n\n\t\tprotected JsonbFieldInitializer() {\n\t\t\tsuper(JsonbTester.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,\n\t\t\t\tJsonb marshaller) {\n\t\t\treturn new JsonbTester<>(resourceLoadClass, type, marshaller);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/ObjectContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport org.assertj.core.api.AssertProvider;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\n\n/**\n * Object content usually created from {@link AbstractJsonMarshalTester}. Generally used\n * only to {@link AssertProvider provide} {@link ObjectContentAssert} to AssertJ\n * {@code assertThat} calls.\n *\n * @param <T> the content type\n * @author Phillip Webb\n * @since 1.4.0\n */\npublic final class ObjectContent<T> implements AssertProvider<ObjectContentAssert<T>> {\n\n\tprivate final @Nullable ResolvableType type;\n\n\tprivate final T object;\n\n\t/**\n\t * Create a new {@link ObjectContent} instance.\n\t * @param type the type under test (or {@code null} if not known)\n\t * @param object the actual object content\n\t */\n\tpublic ObjectContent(@Nullable ResolvableType type, T object) {\n\t\tAssert.notNull(object, \"'object' must not be null\");\n\t\tthis.type = type;\n\t\tthis.object = object;\n\t}\n\n\t@Override\n\tpublic ObjectContentAssert<T> assertThat() {\n\t\treturn new ObjectContentAssert<>(this.object);\n\t}\n\n\t/**\n\t * Return the actual object content.\n\t * @return the object content\n\t */\n\tpublic T getObject() {\n\t\treturn this.object;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tString createdFrom = (this.type != null) ? \" created from \" + this.type : \"\";\n\t\treturn \"ObjectContent \" + this.object + createdFrom;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/ObjectContentAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport org.assertj.core.api.AbstractMapAssert;\nimport org.assertj.core.api.AbstractObjectArrayAssert;\nimport org.assertj.core.api.AbstractObjectAssert;\nimport org.assertj.core.api.Assert;\nimport org.assertj.core.api.InstanceOfAssertFactories;\n\nimport org.springframework.lang.CheckReturnValue;\n\n/**\n * AssertJ {@link Assert} for {@link ObjectContent}.\n *\n * @param <A> the actual type\n * @author Phillip Webb\n * @author Stefano Cordio\n * @since 1.4.0\n */\npublic class ObjectContentAssert<A> extends AbstractObjectAssert<ObjectContentAssert<A>, A> {\n\n\tprotected ObjectContentAssert(A actual) {\n\t\tsuper(actual, ObjectContentAssert.class);\n\t}\n\n\t/**\n\t * Verifies that the actual value is an array, and returns an array assertion, to\n\t * allow chaining of array-specific assertions from this call.\n\t * @return an array assertion object\n\t */\n\t@CheckReturnValue\n\tpublic AbstractObjectArrayAssert<?, Object> asArray() {\n\t\treturn asInstanceOf(InstanceOfAssertFactories.ARRAY);\n\t}\n\n\t/**\n\t * Verifies that the actual value is a map, and returns a map assertion, to allow\n\t * chaining of map-specific assertions from this call.\n\t * @return a map assertion object\n\t */\n\t@CheckReturnValue\n\tpublic AbstractMapAssert<?, ?, Object, Object> asMap() {\n\t\treturn asInstanceOf(InstanceOfAssertFactories.MAP);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/json/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testing JSON.\n */\n@NullMarked\npackage org.springframework.boot.test.json;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/mock/web/SpringBootMockServletContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.mock.web;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.file.Files;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.io.FileSystemResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.web.MockServletContext;\n\n/**\n * {@link MockServletContext} implementation for Spring Boot. Respects well-known Spring\n * Boot resource locations and uses an empty directory for \"/\" if no locations can be\n * found.\n *\n * @author Phillip Webb\n * @since 1.4.0\n */\npublic class SpringBootMockServletContext extends MockServletContext {\n\n\tprivate static final String[] SPRING_BOOT_RESOURCE_LOCATIONS = new String[] { \"classpath:META-INF/resources\",\n\t\t\t\"classpath:resources\", \"classpath:static\", \"classpath:public\" };\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate @Nullable File emptyRootDirectory;\n\n\tpublic SpringBootMockServletContext(String resourceBasePath) {\n\t\tthis(resourceBasePath, new FileSystemResourceLoader());\n\t}\n\n\tpublic SpringBootMockServletContext(String resourceBasePath, ResourceLoader resourceLoader) {\n\t\tsuper(resourceBasePath, resourceLoader);\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tprotected String getResourceLocation(String path) {\n\t\tif (!path.startsWith(\"/\")) {\n\t\t\tpath = \"/\" + path;\n\t\t}\n\t\tString resourceLocation = getResourceBasePathLocation(path);\n\t\tif (exists(resourceLocation)) {\n\t\t\treturn resourceLocation;\n\t\t}\n\t\tfor (String prefix : SPRING_BOOT_RESOURCE_LOCATIONS) {\n\t\t\tresourceLocation = prefix + path;\n\t\t\tif (exists(resourceLocation)) {\n\t\t\t\treturn resourceLocation;\n\t\t\t}\n\t\t}\n\t\treturn super.getResourceLocation(path);\n\t}\n\n\tprotected final String getResourceBasePathLocation(String path) {\n\t\treturn super.getResourceLocation(path);\n\t}\n\n\tprivate boolean exists(String resourceLocation) {\n\t\ttry {\n\t\t\tResource resource = this.resourceLoader.getResource(resourceLocation);\n\t\t\treturn resource.exists();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable URL getResource(String path) throws MalformedURLException {\n\t\tURL resource = super.getResource(path);\n\t\tif (resource == null && \"/\".equals(path)) {\n\t\t\t// Liquibase assumes that \"/\" always exists, if we don't have a directory\n\t\t\t// use a temporary location.\n\t\t\ttry {\n\t\t\t\tif (this.emptyRootDirectory == null) {\n\t\t\t\t\tsynchronized (this) {\n\t\t\t\t\t\tFile tempDirectory = Files.createTempDirectory(\"spr-servlet\").toFile();\n\t\t\t\t\t\ttempDirectory.deleteOnExit();\n\t\t\t\t\t\tthis.emptyRootDirectory = tempDirectory;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this.emptyRootDirectory.toURI().toURL();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn resource;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/mock/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Mock web classes specific to Spring Boot.\n */\n@NullMarked\npackage org.springframework.boot.test.mock.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/system/CapturedOutput.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\n/**\n * Provides access to {@link System#out System.out} and {@link System#err System.err}\n * output that has been captured by the {@link OutputCaptureExtension} or\n * {@link OutputCaptureRule}. Can be used to apply assertions either using AssertJ or\n * standard JUnit assertions. For example: <pre class=\"code\">\n * assertThat(output).contains(\"started\"); // Checks all output\n * assertThat(output.getErr()).contains(\"failed\"); // Only checks System.err\n * assertThat(output.getOut()).contains(\"ok\"); // Only checks System.out\n * </pre>\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.2.0\n * @see OutputCaptureExtension\n */\npublic interface CapturedOutput extends CharSequence {\n\n\t@Override\n\tdefault int length() {\n\t\treturn toString().length();\n\t}\n\n\t@Override\n\tdefault char charAt(int index) {\n\t\treturn toString().charAt(index);\n\t}\n\n\t@Override\n\tdefault CharSequence subSequence(int start, int end) {\n\t\treturn toString().subSequence(start, end);\n\t}\n\n\t/**\n\t * Return all content (both {@link System#out System.out} and {@link System#err\n\t * System.err}) in the order that it was captured.\n\t * @return all captured output\n\t */\n\tString getAll();\n\n\t/**\n\t * Return {@link System#out System.out} content in the order that it was captured.\n\t * @return {@link System#out System.out} captured output\n\t */\n\tString getOut();\n\n\t/**\n\t * Return {@link System#err System.err} content in the order that it was captured.\n\t * @return {@link System#err System.err} captured output\n\t */\n\tString getErr();\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCapture.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ansi.AnsiOutput;\nimport org.springframework.boot.ansi.AnsiOutput.Enabled;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Provides support for capturing {@link System#out System.out} and {@link System#err\n * System.err}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Sam Brannen\n * @author Daniel Schmidt\n * @see OutputCaptureExtension\n * @see OutputCaptureRule\n */\nclass OutputCapture implements CapturedOutput {\n\n\tprivate final Deque<SystemCapture> systemCaptures = new ArrayDeque<>();\n\n\tprivate @Nullable AnsiOutputState ansiOutputState;\n\n\tprivate final AtomicReference<Object> out = new AtomicReference<>();\n\n\tprivate final AtomicReference<Object> err = new AtomicReference<>();\n\n\tprivate final AtomicReference<Object> all = new AtomicReference<>();\n\n\tOutputCapture() {\n\t\tclearExisting();\n\t}\n\n\t/**\n\t * Push a new system capture session onto the stack.\n\t */\n\tfinal void push() {\n\t\tif (this.systemCaptures.isEmpty()) {\n\t\t\tthis.ansiOutputState = AnsiOutputState.saveAndDisable();\n\t\t}\n\t\tclearExisting();\n\t\tthis.systemCaptures.addLast(new SystemCapture(this::clearExisting));\n\t}\n\n\t/**\n\t * Pop the last system capture session from the stack.\n\t */\n\tfinal void pop() {\n\t\tclearExisting();\n\t\tthis.systemCaptures.removeLast().release();\n\t\tif (this.systemCaptures.isEmpty() && this.ansiOutputState != null) {\n\t\t\tthis.ansiOutputState.restore();\n\t\t\tthis.ansiOutputState = null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof CharSequence) {\n\t\t\treturn getAll().equals(obj.toString());\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn toString().hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getAll();\n\t}\n\n\t/**\n\t * Return all content (both {@link System#out System.out} and {@link System#err\n\t * System.err}) in the order that it was captured.\n\t * @return all captured output\n\t */\n\t@Override\n\tpublic String getAll() {\n\t\treturn get(this.all, (type) -> true);\n\t}\n\n\t/**\n\t * Return {@link System#out System.out} content in the order that it was captured.\n\t * @return {@link System#out System.out} captured output\n\t */\n\t@Override\n\tpublic String getOut() {\n\t\treturn get(this.out, Type.OUT::equals);\n\t}\n\n\t/**\n\t * Return {@link System#err System.err} content in the order that it was captured.\n\t * @return {@link System#err System.err} captured output\n\t */\n\t@Override\n\tpublic String getErr() {\n\t\treturn get(this.err, Type.ERR::equals);\n\t}\n\n\t/**\n\t * Resets the current capture session, clearing its captured output.\n\t */\n\tvoid reset() {\n\t\tclearExisting();\n\t\tSystemCapture peeked = this.systemCaptures.peek();\n\t\tif (peeked != null) {\n\t\t\tpeeked.reset();\n\t\t}\n\t}\n\n\tvoid clearExisting() {\n\t\tthis.out.set(new NoOutput());\n\t\tthis.err.set(new NoOutput());\n\t\tthis.all.set(new NoOutput());\n\t}\n\n\tprivate String get(AtomicReference<Object> existing, Predicate<Type> filter) {\n\t\tAssert.state(!this.systemCaptures.isEmpty(),\n\t\t\t\t\"No system captures found. Please check your output capture registration.\");\n\t\tObject existingOutput = existing.get();\n\t\tif (existingOutput instanceof String) {\n\t\t\treturn (String) existingOutput;\n\t\t}\n\t\tString builtOutput = build(filter);\n\t\texisting.compareAndSet(existingOutput, builtOutput);\n\t\treturn builtOutput;\n\t}\n\n\tString build(Predicate<Type> filter) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tfor (SystemCapture systemCapture : this.systemCaptures) {\n\t\t\tsystemCapture.append(builder, filter);\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n\t/**\n\t * A capture session that captures {@link System#out System.out} and {@link System#out\n\t * System.err}.\n\t */\n\tprivate static class SystemCapture {\n\n\t\tprivate final Runnable onCapture;\n\n\t\tprivate final Object monitor = new Object();\n\n\t\tprivate final PrintStreamCapture out;\n\n\t\tprivate final PrintStreamCapture err;\n\n\t\tprivate final List<CapturedString> capturedStrings = new ArrayList<>();\n\n\t\tSystemCapture(Runnable onCapture) {\n\t\t\tthis.onCapture = onCapture;\n\t\t\tthis.out = new PrintStreamCapture(System.out, this::captureOut);\n\t\t\tthis.err = new PrintStreamCapture(System.err, this::captureErr);\n\t\t\tSystem.setOut(this.out);\n\t\t\tSystem.setErr(this.err);\n\t\t}\n\n\t\tvoid release() {\n\t\t\tSystem.setOut(this.out.getParent());\n\t\t\tSystem.setErr(this.err.getParent());\n\t\t}\n\n\t\tprivate void captureOut(String string) {\n\t\t\tcapture(new CapturedString(Type.OUT, string));\n\t\t}\n\n\t\tprivate void captureErr(String string) {\n\t\t\tcapture(new CapturedString(Type.ERR, string));\n\t\t}\n\n\t\tprivate void capture(CapturedString e) {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.onCapture.run();\n\t\t\t\tthis.capturedStrings.add(e);\n\t\t\t}\n\t\t}\n\n\t\tvoid append(StringBuilder builder, Predicate<Type> filter) {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tfor (CapturedString stringCapture : this.capturedStrings) {\n\t\t\t\t\tif (filter.test(stringCapture.getType())) {\n\t\t\t\t\t\tbuilder.append(stringCapture);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid reset() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.capturedStrings.clear();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@link PrintStream} implementation that captures written strings.\n\t */\n\tprivate static class PrintStreamCapture extends PrintStream {\n\n\t\tprivate final PrintStream parent;\n\n\t\tPrintStreamCapture(PrintStream parent, Consumer<String> copy) {\n\t\t\tsuper(new OutputStreamCapture(getSystemStream(parent), copy));\n\t\t\tthis.parent = parent;\n\t\t}\n\n\t\tPrintStream getParent() {\n\t\t\treturn this.parent;\n\t\t}\n\n\t\tprivate static PrintStream getSystemStream(PrintStream printStream) {\n\t\t\twhile (printStream instanceof PrintStreamCapture printStreamCapture) {\n\t\t\t\tprintStream = printStreamCapture.getParent();\n\t\t\t}\n\t\t\treturn printStream;\n\t\t}\n\n\t}\n\n\t/**\n\t * An {@link OutputStream} implementation that captures written strings.\n\t */\n\tprivate static class OutputStreamCapture extends OutputStream {\n\n\t\tprivate final PrintStream systemStream;\n\n\t\tprivate final Consumer<String> copy;\n\n\t\tOutputStreamCapture(PrintStream systemStream, Consumer<String> copy) {\n\t\t\tthis.systemStream = systemStream;\n\t\t\tthis.copy = copy;\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(int b) throws IOException {\n\t\t\twrite(new byte[] { (byte) (b & 0xFF) });\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(byte[] b, int off, int len) throws IOException {\n\t\t\tthis.copy.accept(new String(b, off, len));\n\t\t\tthis.systemStream.write(b, off, len);\n\t\t}\n\n\t\t@Override\n\t\tpublic void flush() throws IOException {\n\t\t\tthis.systemStream.flush();\n\t\t}\n\n\t}\n\n\t/**\n\t * A captured string that forms part of the full output.\n\t */\n\tprivate static class CapturedString {\n\n\t\tprivate final Type type;\n\n\t\tprivate final String string;\n\n\t\tCapturedString(Type type, String string) {\n\t\t\tthis.type = type;\n\t\t\tthis.string = string;\n\t\t}\n\n\t\tType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t}\n\n\t/**\n\t * Types of content that can be captured.\n\t */\n\tenum Type {\n\n\t\tOUT, ERR\n\n\t}\n\n\t/**\n\t * Save, disable and restore AnsiOutput without it needing to be on the classpath.\n\t */\n\tprivate static class AnsiOutputState {\n\n\t\tprivate final Enabled saved;\n\n\t\tAnsiOutputState() {\n\t\t\tthis.saved = AnsiOutput.getEnabled();\n\t\t\tAnsiOutput.setEnabled(Enabled.NEVER);\n\t\t}\n\n\t\tvoid restore() {\n\t\t\tAnsiOutput.setEnabled(this.saved);\n\t\t}\n\n\t\tstatic @Nullable AnsiOutputState saveAndDisable() {\n\t\t\tif (!ClassUtils.isPresent(\"org.springframework.boot.ansi.AnsiOutput\",\n\t\t\t\t\tOutputCapture.class.getClassLoader())) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn new AnsiOutputState();\n\t\t}\n\n\t}\n\n\tstatic class NoOutput {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCaptureExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\nimport org.junit.jupiter.api.extension.AfterAllCallback;\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeAllCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ExtensionContext.Namespace;\nimport org.junit.jupiter.api.extension.ExtensionContext.Store;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolutionException;\nimport org.junit.jupiter.api.extension.ParameterResolver;\n\n/**\n * JUnit Jupiter {@code @Extension} to capture {@link System#out System.out} and\n * {@link System#err System.err}. Can be registered for an entire test class or for an\n * individual test method through {@link ExtendWith @ExtendWith}. This extension provides\n * {@linkplain ParameterResolver parameter resolution} for a {@link CapturedOutput}\n * instance which can be used to assert that the correct output was written.\n * <p>\n * To use with {@link ExtendWith @ExtendWith}, inject the {@link CapturedOutput} as an\n * argument to your test class constructor, test method, or lifecycle methods:\n *\n * <pre class=\"code\">\n * &#064;ExtendWith(OutputCaptureExtension.class)\n * class MyTest {\n *\n *     &#064;Test\n *     void test(CapturedOutput output) {\n *         System.out.println(\"ok\");\n *         assertThat(output).contains(\"ok\");\n *         System.err.println(\"error\");\n *     }\n *\n *     &#064;AfterEach\n *     void after(CapturedOutput output) {\n *         assertThat(output.getOut()).contains(\"ok\");\n *         assertThat(output.getErr()).contains(\"error\");\n *     }\n *\n * }\n * </pre>\n * <p>\n * To ensure that their output can be captured, Java Util Logging (JUL) and Log4j2 require\n * additional configuration.\n * <p>\n * To reliably capture output from Java Util Logging, reset its configuration after each\n * test:\n *\n * <pre class=\"code\">\n * &#064;AfterEach\n * void reset() throws Exception {\n *     LogManager.getLogManager().readConfiguration();\n * }\n * </pre>\n * <p>\n * To reliably capture output from Log4j2, set the <code>follow</code> attribute of the\n * console appender to <code>true</code>:\n *\n * <pre class=\"code\">\n * &lt;Appenders&gt;\n *     &lt;Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\"&gt;\n *         ...\n *     &lt;/Console&gt;\n*  &lt;/Appenders&gt;\n * </pre>\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Sam Brannen\n * @since 2.2.0\n * @see CapturedOutput\n */\npublic class OutputCaptureExtension\n\t\timplements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver {\n\n\tOutputCaptureExtension() {\n\t\t// Package private to prevent users from directly creating an instance.\n\t}\n\n\t@Override\n\tpublic void beforeAll(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).push();\n\t}\n\n\t@Override\n\tpublic void afterAll(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).pop();\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).push();\n\t}\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).pop();\n\t}\n\n\t@Override\n\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\tthrows ParameterResolutionException {\n\t\treturn CapturedOutput.class.equals(parameterContext.getParameter().getType());\n\t}\n\n\t@Override\n\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\treturn getOutputCapture(extensionContext);\n\t}\n\n\tprivate OutputCapture getOutputCapture(ExtensionContext context) {\n\t\treturn getStore(context).computeIfAbsent(OutputCapture.class, (key) -> new OutputCapture(),\n\t\t\t\tOutputCapture.class);\n\t}\n\n\tprivate Store getStore(ExtensionContext context) {\n\t\treturn context.getStore(Namespace.create(getClass()));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/system/OutputCaptureRule.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.hamcrest.Matcher;\nimport org.hamcrest.MatcherAssert;\nimport org.junit.Rule;\nimport org.junit.rules.TestRule;\nimport org.junit.runner.Description;\nimport org.junit.runners.model.Statement;\n\nimport static org.hamcrest.Matchers.allOf;\n\n/**\n * JUnit {@code @Rule} to capture output from {@code System.out} and {@code System.err}.\n * <p>\n * To use add as a {@link Rule @Rule}:\n *\n * <pre class=\"code\">\n * public class MyTest {\n *\n *     &#064;Rule\n *     public OutputCaptureRule output = new OutputCaptureRule();\n *\n *     &#064;Test\n *     public void test() {\n *         assertThat(output).contains(\"ok\");\n *     }\n *\n * }\n * </pre>\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.2.0\n * @deprecated since 4.0.0 in favor of JUnit 5 and {@link OutputCaptureExtension}\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic class OutputCaptureRule implements TestRule, CapturedOutput {\n\n\tprivate final OutputCapture delegate = new OutputCapture();\n\n\tprivate final List<Matcher<? super String>> matchers = new ArrayList<>();\n\n\t@Override\n\tpublic Statement apply(Statement base, Description description) {\n\t\treturn new Statement() {\n\t\t\t@Override\n\t\t\tpublic void evaluate() throws Throwable {\n\t\t\t\tOutputCaptureRule.this.delegate.push();\n\t\t\t\ttry {\n\t\t\t\t\tbase.evaluate();\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!OutputCaptureRule.this.matchers.isEmpty()) {\n\t\t\t\t\t\t\tString output = OutputCaptureRule.this.delegate.toString();\n\t\t\t\t\t\t\tMatcherAssert.assertThat(output, allOf(OutputCaptureRule.this.matchers));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\tOutputCaptureRule.this.delegate.pop();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t@Override\n\tpublic String getAll() {\n\t\treturn this.delegate.getAll();\n\t}\n\n\t@Override\n\tpublic String getOut() {\n\t\treturn this.delegate.getOut();\n\t}\n\n\t@Override\n\tpublic String getErr() {\n\t\treturn this.delegate.getErr();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.delegate.toString();\n\t}\n\n\t/**\n\t * Verify that the output is matched by the supplied {@code matcher}. Verification is\n\t * performed after the test method has executed.\n\t * @param matcher the matcher\n\t */\n\tpublic void expect(Matcher<? super String> matcher) {\n\t\tthis.matchers.add(matcher);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for {@link java.lang.System System}-related testing.\n */\n@NullMarked\npackage org.springframework.boot.test.system;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/util/ApplicationContextTestUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.util;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Application context related test utilities.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\npublic abstract class ApplicationContextTestUtils {\n\n\t/**\n\t * Closes this {@link ApplicationContext} and its parent hierarchy if any.\n\t * @param context the context to close (can be {@code null})\n\t */\n\tpublic static void closeAll(@Nullable ApplicationContext context) {\n\t\tif (context != null) {\n\t\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\t\tconfigurableContext.close();\n\t\t\t}\n\t\t\tcloseAll(context.getParent());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/util/TestPropertyValues.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.util;\n\nimport java.io.Closeable;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.Callable;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Test utilities for adding properties. Properties can be applied to a Spring\n * {@link Environment} or to the {@link System#getProperties() system environment}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic final class TestPropertyValues {\n\n\tprivate static final TestPropertyValues EMPTY = new TestPropertyValues(Collections.emptyMap());\n\n\tprivate final Map<String, @Nullable Object> properties;\n\n\tprivate TestPropertyValues(Map<String, @Nullable Object> properties) {\n\t\tthis.properties = Collections.unmodifiableMap(properties);\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} instance with additional entries.\n\t * Name-value pairs can be specified with colon (\":\") or equals (\"=\") separators.\n\t * @param pairs the property pairs to add\n\t * @return a new {@link TestPropertyValues} instance\n\t */\n\tpublic TestPropertyValues and(String... pairs) {\n\t\treturn and(Arrays.stream(pairs), Pair::parse);\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} instance with additional entries.\n\t * Name-value pairs can be specified with colon (\":\") or equals (\"=\") separators.\n\t * @param pairs the property pairs to add\n\t * @return a new {@link TestPropertyValues} instance\n\t * @since 2.4.0\n\t */\n\tpublic TestPropertyValues and(@Nullable Iterable<String> pairs) {\n\t\treturn (pairs != null) ? and(StreamSupport.stream(pairs.spliterator(), false)) : this;\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} instance with additional entries.\n\t * Name-value pairs can be specified with colon (\":\") or equals (\"=\") separators.\n\t * @param pairs the property pairs to add\n\t * @return a new {@link TestPropertyValues} instance\n\t * @since 2.4.0\n\t */\n\tpublic TestPropertyValues and(@Nullable Stream<String> pairs) {\n\t\treturn (pairs != null) ? and(pairs, Pair::parse) : this;\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} instance with additional entries.\n\t * @param map the map of properties that need to be added to the environment\n\t * @return a new {@link TestPropertyValues} instance\n\t * @since 2.4.0\n\t */\n\tpublic TestPropertyValues and(@Nullable Map<String, String> map) {\n\t\treturn (map != null) ? and(map.entrySet().stream(), Pair::fromMapEntry) : this;\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} instance with additional entries.\n\t * @param <T> the stream element type\n\t * @param stream the elements that need to be added to the environment\n\t * @param mapper a mapper function to convert an element from the stream into a\n\t * {@link Pair}\n\t * @return a new {@link TestPropertyValues} instance\n\t * @since 2.4.0\n\t */\n\tpublic <T> TestPropertyValues and(@Nullable Stream<T> stream, Function<T, @Nullable Pair> mapper) {\n\t\tif (stream == null) {\n\t\t\treturn this;\n\t\t}\n\t\tMap<String, @Nullable Object> properties = new LinkedHashMap<>(this.properties);\n\t\tstream.map(mapper).filter(Objects::nonNull).forEach((pair) -> pair.addTo(properties));\n\t\treturn new TestPropertyValues(properties);\n\t}\n\n\t/**\n\t * Add the properties from the underlying map to the environment owned by an\n\t * {@link ApplicationContext}.\n\t * @param context the context with an environment to modify\n\t */\n\tpublic void applyTo(ConfigurableApplicationContext context) {\n\t\tapplyTo(context.getEnvironment());\n\t}\n\n\t/**\n\t * Add the properties from the underlying map to the environment. The default property\n\t * source used is {@link MapPropertySource}.\n\t * @param environment the environment that needs to be modified\n\t */\n\tpublic void applyTo(ConfigurableEnvironment environment) {\n\t\tapplyTo(environment, Type.MAP);\n\t}\n\n\t/**\n\t * Add the properties from the underlying map to the environment using the specified\n\t * property source type.\n\t * @param environment the environment that needs to be modified\n\t * @param type the type of {@link PropertySource} to be added. See {@link Type}\n\t */\n\tpublic void applyTo(ConfigurableEnvironment environment, Type type) {\n\t\tapplyTo(environment, type, type.applySuffix(\"test\"));\n\t}\n\n\t/**\n\t * Add the properties from the underlying map to the environment using the specified\n\t * property source type and name.\n\t * @param environment the environment that needs to be modified\n\t * @param type the type of {@link PropertySource} to be added. See {@link Type}\n\t * @param name the name for the property source\n\t */\n\tpublic void applyTo(ConfigurableEnvironment environment, Type type, String name) {\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\taddToSources(sources, type, name);\n\t\tConfigurationPropertySources.attach(environment);\n\t}\n\n\t/**\n\t * Add the properties to the {@link System#getProperties() system properties} for the\n\t * duration of the {@code action}, restoring previous values when it completes.\n\t * @param action the action to take\n\t * @since 3.0.0\n\t */\n\tpublic void applyToSystemProperties(Runnable action) {\n\t\tapplyToSystemProperties(() -> {\n\t\t\taction.run();\n\t\t\treturn new Object();\n\t\t});\n\t}\n\n\t/**\n\t * Add the properties to the {@link System#getProperties() system properties} for the\n\t * duration of the {@code call}, restoring previous values when it completes.\n\t * @param <T> the result type\n\t * @param call the call to make\n\t * @return the result of the call\n\t */\n\tpublic <T extends @Nullable Object> T applyToSystemProperties(Callable<T> call) {\n\t\ttry (SystemPropertiesHandler handler = new SystemPropertiesHandler()) {\n\t\t\treturn call.call();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\trethrow(ex);\n\t\t\tthrow new IllegalStateException(\"Original cause not rethrown\", ex);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <E extends Throwable> void rethrow(Throwable e) throws E {\n\t\tthrow (E) e;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void addToSources(MutablePropertySources sources, Type type, String name) {\n\t\tPropertySource<?> propertySource = sources.get(name);\n\t\tif (propertySource != null) {\n\t\t\tif (propertySource.getClass() == type.getSourceClass()) {\n\t\t\t\t((Map<String, Object>) propertySource.getSource()).putAll(this.properties);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tMap<String, Object> source = new LinkedHashMap<>(this.properties);\n\t\tsources.addFirst((type.equals(Type.MAP) ? new MapPropertySource(name, source)\n\t\t\t\t: new SystemEnvironmentPropertySource(name, source)));\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} with the underlying map populated with the\n\t * given property pairs. Name-value pairs can be specified with colon (\":\") or equals\n\t * (\"=\") separators.\n\t * @param pairs the name-value pairs for properties that need to be added to the\n\t * environment\n\t * @return the new instance\n\t */\n\tpublic static TestPropertyValues of(String... pairs) {\n\t\treturn of(Stream.of(pairs));\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} with the underlying map populated with the\n\t * given property pairs. Name-value pairs can be specified with colon (\":\") or equals\n\t * (\"=\") separators.\n\t * @param pairs the name-value pairs for properties that need to be added to the\n\t * environment\n\t * @return the new instance\n\t */\n\tpublic static TestPropertyValues of(@Nullable Iterable<String> pairs) {\n\t\treturn (pairs != null) ? of(StreamSupport.stream(pairs.spliterator(), false)) : empty();\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} with the underlying map populated with the\n\t * given property pairs. Name-value pairs can be specified with colon (\":\") or equals\n\t * (\"=\") separators.\n\t * @param pairs the name-value pairs for properties that need to be added to the\n\t * environment\n\t * @return the new instance\n\t */\n\tpublic static TestPropertyValues of(@Nullable Stream<String> pairs) {\n\t\treturn (pairs != null) ? of(pairs, Pair::parse) : empty();\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} with the underlying map populated with the\n\t * given map entries.\n\t * @param map the map of properties that need to be added to the environment\n\t * @return the new instance\n\t */\n\tpublic static TestPropertyValues of(@Nullable Map<String, String> map) {\n\t\treturn (map != null) ? of(map.entrySet().stream(), Pair::fromMapEntry) : empty();\n\t}\n\n\t/**\n\t * Return a new {@link TestPropertyValues} with the underlying map populated with the\n\t * given stream.\n\t * @param <T> the stream element type\n\t * @param stream the elements that need to be added to the environment\n\t * @param mapper a mapper function to convert an element from the stream into a\n\t * {@link Pair}\n\t * @return the new instance\n\t */\n\tpublic static <T> TestPropertyValues of(@Nullable Stream<T> stream, Function<T, @Nullable Pair> mapper) {\n\t\treturn (stream != null) ? empty().and(stream, mapper) : empty();\n\t}\n\n\t/**\n\t * Return an empty {@link TestPropertyValues} instance.\n\t * @return an empty instance\n\t */\n\tpublic static TestPropertyValues empty() {\n\t\treturn EMPTY;\n\t}\n\n\t/**\n\t * The type of property source.\n\t */\n\tpublic enum Type {\n\n\t\t/**\n\t\t * Used for {@link SystemEnvironmentPropertySource}.\n\t\t */\n\t\tSYSTEM_ENVIRONMENT(SystemEnvironmentPropertySource.class,\n\t\t\t\tStandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME),\n\n\t\t/**\n\t\t * Used for {@link MapPropertySource}.\n\t\t */\n\t\tMAP(MapPropertySource.class, null);\n\n\t\tprivate final Class<? extends MapPropertySource> sourceClass;\n\n\t\tprivate final @Nullable String suffix;\n\n\t\tType(Class<? extends MapPropertySource> sourceClass, @Nullable String suffix) {\n\t\t\tthis.sourceClass = sourceClass;\n\t\t\tthis.suffix = suffix;\n\t\t}\n\n\t\tpublic Class<? extends MapPropertySource> getSourceClass() {\n\t\t\treturn this.sourceClass;\n\t\t}\n\n\t\tprivate String applySuffix(String name) {\n\t\t\treturn (this.suffix != null) ? name + \"-\" + this.suffix : name;\n\t\t}\n\n\t}\n\n\t/**\n\t * A single name value pair.\n\t */\n\tpublic static final class Pair {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable String value;\n\n\t\tprivate Pair(String name, @Nullable String value) {\n\t\t\tthis.name = name;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic void addTo(Map<String, @Nullable Object> properties) {\n\t\t\tproperties.put(this.name, this.value);\n\t\t}\n\n\t\tpublic static Pair parse(String pair) {\n\t\t\tint index = getSeparatorIndex(pair);\n\t\t\tString name = (index > 0) ? pair.substring(0, index) : pair;\n\t\t\tString value = (index > 0) ? pair.substring(index + 1) : \"\";\n\t\t\treturn of(name.trim(), value.trim());\n\t\t}\n\n\t\tprivate static int getSeparatorIndex(String pair) {\n\t\t\tint colonIndex = pair.indexOf(':');\n\t\t\tint equalIndex = pair.indexOf('=');\n\t\t\tif (colonIndex == -1) {\n\t\t\t\treturn equalIndex;\n\t\t\t}\n\t\t\tif (equalIndex == -1) {\n\t\t\t\treturn colonIndex;\n\t\t\t}\n\t\t\treturn Math.min(colonIndex, equalIndex);\n\t\t}\n\n\t\t/**\n\t\t * Factory method to create a {@link Pair} from a {@code Map.Entry}.\n\t\t * @param entry the map entry\n\t\t * @return the {@link Pair} instance or {@code null}\n\t\t * @since 2.4.0\n\t\t */\n\t\tpublic static Pair fromMapEntry(Map.Entry<String, @Nullable String> entry) {\n\t\t\treturn of(entry.getKey(), entry.getValue());\n\t\t}\n\n\t\t/**\n\t\t * Factory method to create a {@link Pair} from a name and value.\n\t\t * @param name the name\n\t\t * @param value the value\n\t\t * @return the {@link Pair}\n\t\t * @since 2.4.0\n\t\t */\n\t\tpublic static Pair of(String name, @Nullable String value) {\n\t\t\treturn new Pair(name, value);\n\t\t}\n\n\t}\n\n\t/**\n\t * Handler to apply and restore system properties.\n\t */\n\tprivate class SystemPropertiesHandler implements Closeable {\n\n\t\tprivate final Map<String, @Nullable String> previous;\n\n\t\tSystemPropertiesHandler() {\n\t\t\tthis.previous = apply(TestPropertyValues.this.properties);\n\t\t}\n\n\t\tprivate Map<String, @Nullable String> apply(Map<String, @Nullable Object> properties) {\n\t\t\tMap<String, @Nullable String> previous = new LinkedHashMap<>();\n\t\t\tproperties.forEach((name, value) -> previous.put(name, setOrClear(name, (String) value)));\n\t\t\treturn previous;\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t\tthis.previous.forEach(this::setOrClear);\n\t\t}\n\n\t\tprivate @Nullable String setOrClear(String name, @Nullable String value) {\n\t\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\t\tif (!StringUtils.hasLength(value)) {\n\t\t\t\treturn (String) System.getProperties().remove(name);\n\t\t\t}\n\t\t\treturn (String) System.getProperties().setProperty(name, value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General purpose test utilities.\n */\n@NullMarked\npackage org.springframework.boot.test.util;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.htmlunit;\n\nimport java.io.IOException;\n\nimport org.htmlunit.FailingHttpStatusCodeException;\nimport org.htmlunit.Page;\nimport org.htmlunit.WebClient;\n\nimport org.springframework.util.Assert;\nimport org.springframework.web.util.UriBuilderFactory;\n\n/**\n * HTML Unit {@link WebClient} supported by a {@link UriBuilderFactory}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class UriBuilderFactoryWebClient extends WebClient {\n\n\tprivate final UriBuilderFactory uriBuilderFactory;\n\n\tpublic UriBuilderFactoryWebClient(UriBuilderFactory uriBuilderFactory) {\n\t\tAssert.notNull(uriBuilderFactory, \"'uriBuilderFactory' must not be null\");\n\t\tthis.uriBuilderFactory = uriBuilderFactory;\n\t}\n\n\t@Override\n\tpublic <P extends Page> P getPage(String url) throws IOException, FailingHttpStatusCodeException {\n\t\treturn super.getPage(this.uriBuilderFactory.uriString(url).toUriString());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebConnectionHtmlUnitDriver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.htmlunit;\n\nimport org.htmlunit.BrowserVersion;\nimport org.openqa.selenium.Capabilities;\n\nimport org.springframework.test.web.servlet.htmlunit.webdriver.WebConnectionHtmlUnitDriver;\nimport org.springframework.util.Assert;\nimport org.springframework.web.util.UriBuilderFactory;\n\n/**\n * HTML Unit {@link WebConnectionHtmlUnitDriver} supported by a {@link UriBuilderFactory}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class UriBuilderFactoryWebConnectionHtmlUnitDriver extends WebConnectionHtmlUnitDriver {\n\n\tprivate final UriBuilderFactory uriBuilderFactory;\n\n\tpublic UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory) {\n\t\tAssert.notNull(uriBuilderFactory, \"'uriBuilderFactory' must not be null\");\n\t\tthis.uriBuilderFactory = uriBuilderFactory;\n\t}\n\n\tpublic UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory, boolean enableJavascript) {\n\t\tsuper(enableJavascript);\n\t\tAssert.notNull(uriBuilderFactory, \"'uriBuilderFactory' must not be null\");\n\t\tthis.uriBuilderFactory = uriBuilderFactory;\n\t}\n\n\tpublic UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory,\n\t\t\tBrowserVersion browserVersion) {\n\t\tsuper(browserVersion);\n\t\tAssert.notNull(uriBuilderFactory, \"'uriBuilderFactory' must not be null\");\n\t\tthis.uriBuilderFactory = uriBuilderFactory;\n\t}\n\n\tpublic UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory,\n\t\t\tCapabilities capabilities) {\n\t\tsuper(capabilities);\n\t\tAssert.notNull(uriBuilderFactory, \"'uriBuilderFactory' must not be null\");\n\t\tthis.uriBuilderFactory = uriBuilderFactory;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"ConstantValue\") // default constructor calls this method\n\tpublic void get(String url) {\n\t\tsuper.get((this.uriBuilderFactory != null) ? this.uriBuilderFactory.uriString(url).toUriString() : url);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * HtmlUnit support classes.\n */\n@NullMarked\npackage org.springframework.boot.test.web.htmlunit;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/web/server/LocalManagementPort.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Annotation at the field or method/constructor parameter level that injects the HTTP\n * management port that was allocated at runtime. Provides a convenient alternative for\n * <code>&#064;Value(&quot;${local.management.port}&quot;)</code> with the assumption that\n * the management web server implementation has configured such a property.\n *\n * @author Stephane Nicoll\n * @since 2.7.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Value(\"${local.management.port}\")\npublic @interface LocalManagementPort {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/web/server/LocalServerPort.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Annotation at the field or method/constructor parameter level that injects the HTTP\n * server port that was allocated at runtime. Provides a convenient alternative for\n * <code>&#064;Value(&quot;${local.server.port}&quot;)</code> with the assumption that the\n * web server implementation has configured such a property.\n *\n * @author Anand Shah\n * @author Stephane Nicoll\n * @since 2.7.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Value(\"${local.server.port}\")\npublic @interface LocalServerPort {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/main/java/org/springframework/boot/test/web/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Web server test utilities and support classes.\n */\n@NullMarked\npackage org.springframework.boot.test.web.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Context Customizer Factories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.test.context.ImportsContextCustomizerFactory,\\\norg.springframework.boot.test.context.PropertyMappingContextCustomizerFactory,\\\norg.springframework.boot.test.context.filter.ExcludeFilterContextCustomizerFactory,\\\norg.springframework.boot.test.context.filter.annotation.TypeExcludeFiltersContextCustomizerFactory,\\\norg.springframework.boot.test.http.client.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory,\\\norg.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory\n\n# Application Context Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.test.context.filter.ExcludeFilterApplicationContextInitializer\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotatedClassFinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.context.example.ExampleConfig;\nimport org.springframework.boot.test.context.example.scan.Example;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AnnotatedClassFinder}.\n *\n * @author Phillip Webb\n */\nclass AnnotatedClassFinderTests {\n\n\tprivate final AnnotatedClassFinder finder = new AnnotatedClassFinder(SpringBootConfiguration.class);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid findFromClassWhenSourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.finder.findFromClass((Class<?>) null))\n\t\t\t.withMessageContaining(\"'source' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid findFromPackageWhenSourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.finder.findFromPackage((String) null))\n\t\t\t.withMessageContaining(\"'source' must not be null\");\n\t}\n\n\t@Test\n\tvoid findFromPackageWhenNoConfigurationFoundShouldReturnNull() {\n\t\tClass<?> config = this.finder.findFromPackage(\"org.springframework.boot\");\n\t\tassertThat(config).isNull();\n\t}\n\n\t@Test\n\tvoid findFromClassWhenConfigurationIsFoundShouldReturnConfiguration() {\n\t\tClass<?> config = this.finder.findFromClass(Example.class);\n\t\tassertThat(config).isEqualTo(ExampleConfig.class);\n\t}\n\n\t@Test\n\tvoid findFromPackageWhenConfigurationIsFoundShouldReturnConfiguration() {\n\t\tClass<?> config = this.finder.findFromPackage(\"org.springframework.boot.test.context.example.scan\");\n\t\tassertThat(config).isEqualTo(ExampleConfig.class);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/AnnotationsPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.AnnotationsPropertySourceTests.DeeplyNestedAnnotations.Level1;\nimport org.springframework.boot.test.context.AnnotationsPropertySourceTests.DeeplyNestedAnnotations.Level2;\nimport org.springframework.boot.test.context.AnnotationsPropertySourceTests.EnclosingClass.PropertyMappedAnnotationOnEnclosingClass;\nimport org.springframework.boot.test.context.AnnotationsPropertySourceTests.NestedAnnotations.Entry;\nimport org.springframework.boot.test.context.PropertyMapping.Skip;\nimport org.springframework.core.annotation.AliasFor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AnnotationsPropertySource}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass AnnotationsPropertySourceTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSourceIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new AnnotationsPropertySource(null))\n\t\t\t.withMessageContaining(\"Property source must not be null\");\n\t}\n\n\t@Test\n\tvoid propertiesWhenHasNoAnnotationShouldBeEmpty() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(NoAnnotation.class);\n\t\tassertThat(source.getPropertyNames()).isEmpty();\n\t\tassertThat(source.getProperty(\"value\")).isNull();\n\t}\n\n\t@Test\n\tvoid propertiesWhenHasTypeLevelAnnotationShouldUseAttributeName() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(TypeLevel.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\");\n\t\tassertThat(source.getProperty(\"value\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid propertiesWhenHasTypeLevelWithPrefixShouldUsePrefixedName() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(TypeLevelWithPrefix.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"test.value\");\n\t\tassertThat(source.getProperty(\"test.value\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid propertiesWhenHasAttributeLevelWithPrefixShouldUsePrefixedName() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(AttributeLevelWithPrefix.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"test\");\n\t\tassertThat(source.getProperty(\"test\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid propertiesWhenHasTypeAndAttributeLevelWithPrefixShouldUsePrefixedName() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(TypeAndAttributeLevelWithPrefix.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"test.example\");\n\t\tassertThat(source.getProperty(\"test.example\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid propertiesWhenNotMappedAtTypeLevelShouldIgnoreAttributes() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(NotMappedAtTypeLevel.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\");\n\t\tassertThat(source.getProperty(\"ignore\")).isNull();\n\t}\n\n\t@Test\n\tvoid propertiesWhenNotMappedAtAttributeLevelShouldIgnoreAttributes() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(NotMappedAtAttributeLevel.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\");\n\t\tassertThat(source.getProperty(\"ignore\")).isNull();\n\t}\n\n\t@Test\n\tvoid propertiesWhenContainsArraysShouldExpandNames() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(Arrays.class);\n\t\tassertThat(source.getPropertyNames()).contains(\"strings[0]\", \"strings[1]\", \"classes[0]\", \"classes[1]\",\n\t\t\t\t\"ints[0]\", \"ints[1]\", \"longs[0]\", \"longs[1]\", \"floats[0]\", \"floats[1]\", \"doubles[0]\", \"doubles[1]\",\n\t\t\t\t\"booleans[0]\", \"booleans[1]\");\n\t\tassertThat(source.getProperty(\"strings[0]\")).isEqualTo(\"a\");\n\t\tassertThat(source.getProperty(\"strings[1]\")).isEqualTo(\"b\");\n\t\tassertThat(source.getProperty(\"classes[0]\")).isEqualTo(Integer.class);\n\t\tassertThat(source.getProperty(\"classes[1]\")).isEqualTo(Long.class);\n\t\tassertThat(source.getProperty(\"ints[0]\")).isEqualTo(1);\n\t\tassertThat(source.getProperty(\"ints[1]\")).isEqualTo(2);\n\t\tassertThat(source.getProperty(\"longs[0]\")).isEqualTo(1L);\n\t\tassertThat(source.getProperty(\"longs[1]\")).isEqualTo(2L);\n\t\tassertThat(source.getProperty(\"floats[0]\")).isEqualTo(1.0f);\n\t\tassertThat(source.getProperty(\"floats[1]\")).isEqualTo(2.0f);\n\t\tassertThat(source.getProperty(\"doubles[0]\")).isEqualTo(1.0);\n\t\tassertThat(source.getProperty(\"doubles[1]\")).isEqualTo(2.0);\n\t\tassertThat(source.getProperty(\"booleans[0]\")).isEqualTo(false);\n\t\tassertThat(source.getProperty(\"booleans[1]\")).isEqualTo(true);\n\t}\n\n\t@Test\n\tvoid propertiesWhenHasCamelCaseShouldConvertToKebabCase() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(CamelCaseToKebabCase.class);\n\t\tassertThat(source.getPropertyNames()).contains(\"camel-case-to-kebab-case\");\n\t}\n\n\t@Test\n\tvoid propertiesFromMetaAnnotationsAreMapped() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(PropertiesFromSingleMetaAnnotation.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\");\n\t\tassertThat(source.getProperty(\"value\")).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid propertiesFromMultipleMetaAnnotationsAreMappedUsingTheirOwnPropertyMapping() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(PropertiesFromMultipleMetaAnnotations.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\", \"test.value\", \"test.example\");\n\t\tassertThat(source.getProperty(\"value\")).isEqualTo(\"alpha\");\n\t\tassertThat(source.getProperty(\"test.value\")).isEqualTo(\"bravo\");\n\t\tassertThat(source.getProperty(\"test.example\")).isEqualTo(\"charlie\");\n\t}\n\n\t@Test\n\tvoid propertyMappedAttributesCanBeAliased() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(PropertyMappedAttributeWithAnAlias.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"aliasing.value\");\n\t\tassertThat(source.getProperty(\"aliasing.value\")).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid selfAnnotatingAnnotationDoesNotCauseStackOverflow() {\n\t\tnew AnnotationsPropertySource(PropertyMappedWithSelfAnnotatingAnnotation.class);\n\t}\n\n\t@Test\n\tvoid typeLevelAnnotationOnSuperClass() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(PropertyMappedAnnotationOnSuperClass.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\");\n\t\tassertThat(source.getProperty(\"value\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid typeLevelAnnotationOnEnclosingClass() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(\n\t\t\t\tPropertyMappedAnnotationOnEnclosingClass.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"value\");\n\t\tassertThat(source.getProperty(\"value\")).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid aliasedPropertyMappedAttributeOnSuperClass() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(\n\t\t\t\tAliasedPropertyMappedAnnotationOnSuperClass.class);\n\t\tassertThat(source.getPropertyNames()).containsExactly(\"aliasing.value\");\n\t\tassertThat(source.getProperty(\"aliasing.value\")).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid enumValueMapped() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(EnumValueMapped.class);\n\t\tassertThat(source.getProperty(\"testenum.value\")).isEqualTo(EnumItem.TWO);\n\t}\n\n\t@Test\n\tvoid enumValueNotMapped() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(EnumValueNotMapped.class);\n\t\tassertThat(source.containsProperty(\"testenum.value\")).isFalse();\n\t}\n\n\t@Test\n\tvoid nestedAnnotationsMapped() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(PropertyMappedWithNestedAnnotations.class);\n\t\tassertThat(source.getProperty(\"testnested\")).isNull();\n\t\tassertThat(source.getProperty(\"testnested.entries[0]\")).isNull();\n\t\tassertThat(source.getProperty(\"testnested.entries[0].value\")).isEqualTo(\"one\");\n\t\tassertThat(source.getProperty(\"testnested.entries[1]\")).isNull();\n\t\tassertThat(source.getProperty(\"testnested.entries[1].value\")).isEqualTo(\"two\");\n\t}\n\n\t@Test\n\tvoid deeplyNestedAnnotationsMapped() {\n\t\tAnnotationsPropertySource source = new AnnotationsPropertySource(\n\t\t\t\tPropertyMappedWithDeeplyNestedAnnotations.class);\n\t\tassertThat(source.getProperty(\"testdeeplynested\")).isNull();\n\t\tassertThat(source.getProperty(\"testdeeplynested.level1\")).isNull();\n\t\tassertThat(source.getProperty(\"testdeeplynested.level1.level2\")).isNull();\n\t\tassertThat(source.getProperty(\"testdeeplynested.level1.level2.value\")).isEqualTo(\"level2\");\n\t}\n\n\tstatic class NoAnnotation {\n\n\t}\n\n\t@TypeLevelAnnotation(\"abc\")\n\tstatic class TypeLevel {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping\n\t@interface TypeLevelAnnotation {\n\n\t\tString value();\n\n\t}\n\n\t@TypeLevelWithPrefixAnnotation(\"abc\")\n\tstatic class TypeLevelWithPrefix {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(\"test\")\n\t@interface TypeLevelWithPrefixAnnotation {\n\n\t\tString value();\n\n\t}\n\n\t@AttributeLevelWithPrefixAnnotation(\"abc\")\n\tstatic class AttributeLevelWithPrefix {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface AttributeLevelWithPrefixAnnotation {\n\n\t\t@PropertyMapping(\"test\")\n\t\tString value();\n\n\t}\n\n\t@TypeAndAttributeLevelWithPrefixAnnotation(\"abc\")\n\tstatic class TypeAndAttributeLevelWithPrefix {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(\"test\")\n\t@interface TypeAndAttributeLevelWithPrefixAnnotation {\n\n\t\t@PropertyMapping(\"example\")\n\t\tString value();\n\n\t}\n\n\t@NotMappedAtTypeLevelAnnotation(\"abc\")\n\tstatic class NotMappedAtTypeLevel {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(skip = Skip.YES)\n\t@interface NotMappedAtTypeLevelAnnotation {\n\n\t\t@PropertyMapping\n\t\tString value();\n\n\t\tString ignore() default \"xyz\";\n\n\t}\n\n\t@NotMappedAtAttributeLevelAnnotation(\"abc\")\n\tstatic class NotMappedAtAttributeLevel {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping\n\t@interface NotMappedAtAttributeLevelAnnotation {\n\n\t\tString value();\n\n\t\t@PropertyMapping(skip = Skip.YES)\n\t\tString ignore() default \"xyz\";\n\n\t}\n\n\t@ArraysAnnotation(strings = { \"a\", \"b\" }, classes = { Integer.class, Long.class }, ints = { 1, 2 },\n\t\t\tlongs = { 1, 2 }, floats = { 1.0f, 2.0f }, doubles = { 1.0, 2.0 }, booleans = { false, true })\n\tstatic class Arrays {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping\n\t@interface ArraysAnnotation {\n\n\t\tString[] strings();\n\n\t\tClass<?>[] classes();\n\n\t\tint[] ints();\n\n\t\tlong[] longs();\n\n\t\tfloat[] floats();\n\n\t\tdouble[] doubles();\n\n\t\tboolean[] booleans();\n\n\t}\n\n\t@CamelCaseToKebabCaseAnnotation\n\tstatic class CamelCaseToKebabCase {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping\n\t@interface CamelCaseToKebabCaseAnnotation {\n\n\t\tString camelCaseToKebabCase() default \"abc\";\n\n\t}\n\n\t@PropertiesFromSingleMetaAnnotationAnnotation\n\tstatic class PropertiesFromSingleMetaAnnotation {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@TypeLevelAnnotation(\"foo\")\n\t@interface PropertiesFromSingleMetaAnnotationAnnotation {\n\n\t}\n\n\t@PropertiesFromMultipleMetaAnnotationsAnnotation\n\tstatic class PropertiesFromMultipleMetaAnnotations {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@TypeLevelAnnotation(\"alpha\")\n\t@TypeLevelWithPrefixAnnotation(\"bravo\")\n\t@TypeAndAttributeLevelWithPrefixAnnotation(\"charlie\")\n\t@interface PropertiesFromMultipleMetaAnnotationsAnnotation {\n\n\t}\n\n\t@AttributeWithAliasAnnotation(\"baz\")\n\tstatic class PropertyMappedAttributeWithAnAlias {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@AliasedAttributeAnnotation\n\t@interface AttributeWithAliasAnnotation {\n\n\t\t@AliasFor(annotation = AliasedAttributeAnnotation.class)\n\t\tString value() default \"foo\";\n\n\t\tString someOtherAttribute() default \"shouldNotBeMapped\";\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(\"aliasing\")\n\t@interface AliasedAttributeAnnotation {\n\n\t\tString value() default \"bar\";\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@SelfAnnotating\n\t@interface SelfAnnotating {\n\n\t}\n\n\t@SelfAnnotating\n\tstatic class PropertyMappedWithSelfAnnotatingAnnotation {\n\n\t}\n\n\tstatic class PropertyMappedAnnotationOnSuperClass extends TypeLevel {\n\n\t}\n\n\t@TypeLevelAnnotation(\"abc\")\n\tstatic class EnclosingClass {\n\n\t\tclass PropertyMappedAnnotationOnEnclosingClass {\n\n\t\t}\n\n\t}\n\n\tstatic class AliasedPropertyMappedAnnotationOnSuperClass extends PropertyMappedAttributeWithAnAlias {\n\n\t}\n\n\t@EnumAnnotation(EnumItem.TWO)\n\tstatic class EnumValueMapped {\n\n\t}\n\n\t@EnumAnnotation(EnumItem.DEFAULT)\n\tstatic class EnumValueNotMapped {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(\"testenum\")\n\t@interface EnumAnnotation {\n\n\t\t@PropertyMapping(skip = Skip.ON_DEFAULT_VALUE)\n\t\tEnumItem value() default EnumItem.DEFAULT;\n\n\t}\n\n\tenum EnumItem {\n\n\t\tDEFAULT,\n\n\t\tONE,\n\n\t\tTWO\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(\"testnested\")\n\t@interface NestedAnnotations {\n\n\t\tEntry[] entries();\n\n\t\t@Retention(RetentionPolicy.RUNTIME)\n\t\t@interface Entry {\n\n\t\t\tString value();\n\n\t\t}\n\n\t}\n\n\t@NestedAnnotations(entries = { @Entry(\"one\"), @Entry(\"two\") })\n\tstatic class PropertyMappedWithNestedAnnotations {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping(\"testdeeplynested\")\n\t@interface DeeplyNestedAnnotations {\n\n\t\tLevel1 level1();\n\n\t\t@Retention(RetentionPolicy.RUNTIME)\n\t\t@interface Level1 {\n\n\t\t\tLevel2 level2();\n\n\t\t}\n\n\t\t@Retention(RetentionPolicy.RUNTIME)\n\t\t@interface Level2 {\n\n\t\t\tString value();\n\n\t\t}\n\n\t}\n\n\t@DeeplyNestedAnnotations(level1 = @Level1(level2 = @Level2(\"level2\")))\n\tstatic class PropertyMappedWithDeeplyNestedAnnotations {\n\n\t}\n\n\t@TypeLevelAnnotation(\"outer\")\n\tstatic class OuterWithTypeLevel {\n\n\t\t@Nested\n\t\tstatic class NestedClass {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/ConfigDataApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataApplicationContextInitializer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@DirtiesContext\n@ContextConfiguration(classes = ConfigDataApplicationContextInitializerTests.Config.class,\n\t\tinitializers = ConfigDataApplicationContextInitializer.class)\nclass ConfigDataApplicationContextInitializerTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid initializerPopulatesEnvironment() {\n\t\tassertThat(this.environment.getProperty(\"foo\")).isEqualTo(\"bucket\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/ConfigDataApplicationContextInitializerWithLegacySwitchTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigDataApplicationContextInitializer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@DirtiesContext\n@TestPropertySource(properties = \"spring.config.use-legacy-processing=true\")\n@ContextConfiguration(classes = ConfigDataApplicationContextInitializerWithLegacySwitchTests.Config.class,\n\t\tinitializers = ConfigDataApplicationContextInitializer.class)\nclass ConfigDataApplicationContextInitializerWithLegacySwitchTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid initializerPopulatesEnvironment() {\n\t\tassertThat(this.environment.getProperty(\"foo\")).isEqualTo(\"bucket\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/ExampleMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Example {@link PropertyMapping @PropertyMapping} annotation for use with\n * {@link PropertyMappingTests}.\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@PropertyMapping\n@interface ExampleMapping {\n\n\tString exampleProperty();\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/FilteredClassLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.Enumeration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link FilteredClassLoader}.\n *\n * @author Phillip Webb\n * @author Roy Jacobs\n */\nclass FilteredClassLoaderTests {\n\n\tstatic ClassPathResource TEST_RESOURCE = new ClassPathResource(\n\t\t\t\"org/springframework/boot/test/context/FilteredClassLoaderTestsResource.txt\");\n\n\t@Test\n\tvoid loadClassWhenFilteredOnPackageShouldThrowClassNotFound() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader(\n\t\t\t\tFilteredClassLoaderTests.class.getPackage().getName())) {\n\t\t\tassertThatExceptionOfType(ClassNotFoundException.class)\n\t\t\t\t.isThrownBy(() -> Class.forName(getClass().getName(), false, classLoader));\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadClassWhenFilteredOnClassShouldThrowClassNotFound() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader(FilteredClassLoaderTests.class)) {\n\t\t\tassertThatExceptionOfType(ClassNotFoundException.class)\n\t\t\t\t.isThrownBy(() -> Class.forName(getClass().getName(), false, classLoader));\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadClassWhenNotFilteredShouldLoadClass() throws Exception {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader((className) -> false);\n\t\tClass<?> loaded = Class.forName(getClass().getName(), false, classLoader);\n\t\tassertThat(loaded.getName()).isEqualTo(getClass().getName());\n\t\tclassLoader.close();\n\t}\n\n\t@Test\n\tvoid loadResourceWhenFilteredOnResourceShouldReturnNotFound() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader(TEST_RESOURCE)) {\n\t\t\tfinal URL loaded = classLoader.getResource(TEST_RESOURCE.getPath());\n\t\t\tassertThat(loaded).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadResourceWhenNotFilteredShouldLoadResource() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader((resourceName) -> false)) {\n\t\t\tfinal URL loaded = classLoader.getResource(TEST_RESOURCE.getPath());\n\t\t\tassertThat(loaded).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadResourcesWhenFilteredOnResourceShouldReturnNotFound() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader(TEST_RESOURCE)) {\n\t\t\tfinal Enumeration<URL> loaded = classLoader.getResources(TEST_RESOURCE.getPath());\n\t\t\tassertThat(loaded.hasMoreElements()).isFalse();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadResourcesWhenNotFilteredShouldLoadResource() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader((resourceName) -> false)) {\n\t\t\tfinal Enumeration<URL> loaded = classLoader.getResources(TEST_RESOURCE.getPath());\n\t\t\tassertThat(loaded.hasMoreElements()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadResourceAsStreamWhenFilteredOnResourceShouldReturnNotFound() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader(TEST_RESOURCE)) {\n\t\t\tfinal InputStream loaded = classLoader.getResourceAsStream(TEST_RESOURCE.getPath());\n\t\t\tassertThat(loaded).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadResourceAsStreamWhenNotFilteredShouldLoadResource() throws Exception {\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader((resourceName) -> false)) {\n\t\t\tfinal InputStream loaded = classLoader.getResourceAsStream(TEST_RESOURCE.getPath());\n\t\t\tassertThat(loaded).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid publicDefineClassWhenFilteredThrowsException() throws Exception {\n\t\tClass<FilteredClassLoaderTests> hiddenClass = FilteredClassLoaderTests.class;\n\t\ttry (FilteredClassLoader classLoader = new FilteredClassLoader(hiddenClass)) {\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> classLoader.publicDefineClass(hiddenClass.getName(), new byte[] {}, null));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/ImportsContextCustomizerFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.ImportsContextCustomizerFactoryIntegrationTests.ImportedBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.stereotype.Component;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Integration tests for {@link ImportsContextCustomizerFactory} and\n * {@link ImportsContextCustomizer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@Import(ImportedBean.class)\nclass ImportsContextCustomizerFactoryIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Autowired\n\tprivate ImportedBean bean;\n\n\t@Test\n\tvoid beanWasImported() {\n\t\tassertThat(this.bean).isNotNull();\n\t}\n\n\t@Test\n\tvoid testItselfIsNotABean() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.context.getBean(getClass()));\n\t}\n\n\t@Component\n\tstatic class ImportedBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/ImportsContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.stereotype.Component;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ImportsContextCustomizerFactory} and {@link ImportsContextCustomizer}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ImportsContextCustomizerFactoryTests {\n\n\tprivate final ImportsContextCustomizerFactory factory = new ImportsContextCustomizerFactory();\n\n\t@Test\n\tvoid getContextCustomizerWhenHasNoImportAnnotationShouldReturnNull() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(TestWithNoImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasImportAnnotationShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(TestWithImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasMetaImportAnnotationShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(TestWithMetaImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid contextCustomizerEqualsAndHashCode() {\n\t\tContextCustomizer customizer1 = this.factory.createContextCustomizer(TestWithImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer2 = this.factory.createContextCustomizer(TestWithImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer3 = this.factory.createContextCustomizer(TestWithImportAndMetaImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer4 = this.factory.createContextCustomizer(TestWithSameImportAndMetaImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer1);\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t\tassertThat(customizer1).isEqualTo(customizer1).isEqualTo(customizer2).isNotEqualTo(customizer3);\n\t\tassertThat(customizer3).isEqualTo(customizer4);\n\t}\n\n\t@Test\n\tvoid contextCustomizerEqualsAndHashCodeConsidersComponentScan() {\n\t\tContextCustomizer customizer1 = this.factory\n\t\t\t.createContextCustomizer(TestWithImportAndComponentScanOfSomePackage.class, Collections.emptyList());\n\t\tContextCustomizer customizer2 = this.factory\n\t\t\t.createContextCustomizer(TestWithImportAndComponentScanOfSomePackage.class, Collections.emptyList());\n\t\tContextCustomizer customizer3 = this.factory\n\t\t\t.createContextCustomizer(TestWithImportAndComponentScanOfAnotherPackage.class, Collections.emptyList());\n\t\tassertThat(customizer1).isEqualTo(customizer2);\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t\tassertThat(customizer3).isNotEqualTo(customizer2).isNotEqualTo(customizer1);\n\t\tassertThat(customizer3).doesNotHaveSameHashCodeAs(customizer2).doesNotHaveSameHashCodeAs(customizer1);\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenClassHasBeanMethodsShouldThrowException() {\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> this.factory.createContextCustomizer(TestWithImportAndBeanMethod.class, Collections.emptyList()))\n\t\t\t.withMessageContaining(\"Test classes cannot include @Bean methods\");\n\t}\n\n\t@Test\n\tvoid contextCustomizerImportsBeans() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(TestWithImport.class,\n\t\t\t\tCollections.emptyList());\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tassertThat(customizer).isNotNull();\n\t\tcustomizer.customizeContext(context, mock(MergedContextConfiguration.class));\n\t\tcontext.refresh();\n\t\tassertThat(context.getBean(ImportedBean.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid selfAnnotatingAnnotationDoesNotCauseStackOverflow() {\n\t\tassertThat(this.factory.createContextCustomizer(TestWithImportAndSelfAnnotatingAnnotation.class,\n\t\t\t\tCollections.emptyList()))\n\t\t\t.isNotNull();\n\t}\n\n\tstatic class TestWithNoImport {\n\n\t}\n\n\t@Import(ImportedBean.class)\n\tstatic class TestWithImport {\n\n\t}\n\n\t@Import(ImportedBean.class)\n\t@ComponentScan(\"some.package\")\n\tstatic class TestWithImportAndComponentScanOfSomePackage {\n\n\t}\n\n\t@Import(ImportedBean.class)\n\t@ComponentScan(\"another.package\")\n\tstatic class TestWithImportAndComponentScanOfAnotherPackage {\n\n\t}\n\n\t@MetaImport\n\tstatic class TestWithMetaImport {\n\n\t}\n\n\t@MetaImport\n\t@Import(AnotherImportedBean.class)\n\tstatic class TestWithImportAndMetaImport {\n\n\t}\n\n\t@MetaImport\n\t@Import(AnotherImportedBean.class)\n\tstatic class TestWithSameImportAndMetaImport {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ImportedBean.class)\n\tstatic class TestWithImportAndBeanMethod {\n\n\t\t@Bean\n\t\tString bean() {\n\t\t\treturn \"bean\";\n\t\t}\n\n\t}\n\n\t@SelfAnnotating\n\t@Import(ImportedBean.class)\n\tstatic class TestWithImportAndSelfAnnotatingAnnotation {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Import(ImportedBean.class)\n\t@interface MetaImport {\n\n\t}\n\n\t@Component\n\tstatic class ImportedBean {\n\n\t}\n\n\t@Component\n\tstatic class AnotherImportedBean {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@SelfAnnotating\n\t@interface SelfAnnotating {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/ImportsContextCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport kotlin.Metadata;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport org.spockframework.runtime.model.SpecMetadata;\nimport spock.lang.Issue;\nimport spock.lang.Stepwise;\n\nimport org.springframework.boot.context.annotation.DeterminableImports;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.type.AnnotationMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImportsContextCustomizer}.\n *\n * @author Andy Wilkinson\n * @author Laurent Martelli\n */\nclass ImportsContextCustomizerTests {\n\n\t@Test\n\tvoid importSelectorsCouldUseAnyAnnotations() {\n\t\tassertThat(new ImportsContextCustomizer(FirstImportSelectorAnnotatedClass.class))\n\t\t\t.isNotEqualTo(new ImportsContextCustomizer(SecondImportSelectorAnnotatedClass.class));\n\t}\n\n\t@Test\n\tvoid determinableImportSelector() {\n\t\tassertThat(new ImportsContextCustomizer(FirstDeterminableImportSelectorAnnotatedClass.class))\n\t\t\t.isEqualTo(new ImportsContextCustomizer(SecondDeterminableImportSelectorAnnotatedClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForTestClassesWithDifferentKotlinMetadataAreEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstKotlinAnnotatedTestClass.class))\n\t\t\t.isEqualTo(new ImportsContextCustomizer(SecondKotlinAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForTestClassesWithDifferentSpockFrameworkAnnotationsAreEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstSpockFrameworkAnnotatedTestClass.class))\n\t\t\t.isEqualTo(new ImportsContextCustomizer(SecondSpockFrameworkAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForTestClassesWithDifferentSpockLangAnnotationsAreEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstSpockLangAnnotatedTestClass.class))\n\t\t\t.isEqualTo(new ImportsContextCustomizer(SecondSpockLangAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForTestClassesWithDifferentJUnitAnnotationsAreEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstJUnitAnnotatedTestClass.class))\n\t\t\t.isEqualTo(new ImportsContextCustomizer(SecondJUnitAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForClassesWithDifferentImportsAreNotEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstAnnotatedTestClass.class))\n\t\t\t.isNotEqualTo(new ImportsContextCustomizer(SecondAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForClassesWithDifferentMetaImportsAreNotEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstMetaAnnotatedTestClass.class))\n\t\t\t.isNotEqualTo(new ImportsContextCustomizer(SecondMetaAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid customizersForClassesWithDifferentAliasedImportsAreNotEqual() {\n\t\tassertThat(new ImportsContextCustomizer(FirstAliasAnnotatedTestClass.class))\n\t\t\t.isNotEqualTo(new ImportsContextCustomizer(SecondAliasAnnotatedTestClass.class));\n\t}\n\n\t@Test\n\tvoid importsCanBeScatteredOnMultipleAnnotations() {\n\t\tassertThat(new ImportsContextCustomizer(SingleImportAnnotationTestClass.class))\n\t\t\t.isEqualTo(new ImportsContextCustomizer(MultipleImportAnnotationTestClass.class));\n\t}\n\n\t@Import(TestImportSelector.class)\n\t@Indicator1\n\tstatic class FirstImportSelectorAnnotatedClass {\n\n\t}\n\n\t@Import(TestImportSelector.class)\n\t@Indicator2\n\tstatic class SecondImportSelectorAnnotatedClass {\n\n\t}\n\n\t@Import(TestDeterminableImportSelector.class)\n\t@Indicator1\n\tstatic class FirstDeterminableImportSelectorAnnotatedClass {\n\n\t}\n\n\t@Import(TestDeterminableImportSelector.class)\n\t@Indicator2\n\tstatic class SecondDeterminableImportSelectorAnnotatedClass {\n\n\t}\n\n\t@Metadata(d2 = \"foo\")\n\t@Import(TestImportSelector.class)\n\tstatic class FirstKotlinAnnotatedTestClass {\n\n\t}\n\n\t@Metadata(d2 = \"bar\")\n\t@Import(TestImportSelector.class)\n\tstatic class SecondKotlinAnnotatedTestClass {\n\n\t}\n\n\t@SpecMetadata(filename = \"foo\", line = 10)\n\t@Import(TestImportSelector.class)\n\tstatic class FirstSpockFrameworkAnnotatedTestClass {\n\n\t}\n\n\t@SpecMetadata(filename = \"bar\", line = 10)\n\t@Import(TestImportSelector.class)\n\tstatic class SecondSpockFrameworkAnnotatedTestClass {\n\n\t}\n\n\t@Stepwise\n\t@Import(TestImportSelector.class)\n\tstatic class FirstSpockLangAnnotatedTestClass {\n\n\t}\n\n\t@Issue(\"1234\")\n\t@Import(TestImportSelector.class)\n\tstatic class SecondSpockLangAnnotatedTestClass {\n\n\t}\n\n\t@Nested\n\t@Import(TestImportSelector.class)\n\tstatic class FirstJUnitAnnotatedTestClass {\n\n\t}\n\n\t@Tag(\"test\")\n\t@Import(TestImportSelector.class)\n\tstatic class SecondJUnitAnnotatedTestClass {\n\n\t}\n\n\t@Import({ FirstImportedClass.class, SecondImportedClass.class })\n\tstatic class SingleImportAnnotationTestClass {\n\n\t}\n\n\t@FirstMetaImport\n\t@Import(SecondImportedClass.class)\n\tstatic class MultipleImportAnnotationTestClass {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface Indicator1 {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface Indicator2 {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Import(AliasFor.class)\n\tpublic @interface AliasedImport {\n\n\t\t@AliasFor(annotation = Import.class)\n\t\tClass<?>[] value();\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Import(FirstImportedClass.class)\n\tpublic @interface FirstMetaImport {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Import(SecondImportedClass.class)\n\tpublic @interface SecondMetaImport {\n\n\t}\n\n\tstatic class FirstImportedClass {\n\n\t}\n\n\tstatic class SecondImportedClass {\n\n\t}\n\n\t@AliasedImport(FirstImportedClass.class)\n\tstatic class FirstAliasAnnotatedTestClass {\n\n\t}\n\n\t@AliasedImport(SecondImportedClass.class)\n\tstatic class SecondAliasAnnotatedTestClass {\n\n\t}\n\n\t@FirstMetaImport\n\tstatic class FirstMetaAnnotatedTestClass {\n\n\t}\n\n\t@SecondMetaImport\n\tstatic class SecondMetaAnnotatedTestClass {\n\n\t}\n\n\t@Import(FirstImportedClass.class)\n\tstatic class FirstAnnotatedTestClass {\n\n\t}\n\n\t@Import(SecondImportedClass.class)\n\tstatic class SecondAnnotatedTestClass {\n\n\t}\n\n\tstatic class TestImportSelector implements ImportSelector {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata arg0) {\n\t\t\treturn new String[] {};\n\t\t}\n\n\t}\n\n\tstatic class TestDeterminableImportSelector implements ImportSelector, DeterminableImports {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata arg0) {\n\t\t\treturn new String[] { TestConfig.class.getName() };\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<Object> determineImports(AnnotationMetadata metadata) {\n\t\t\treturn Collections.singleton(TestConfig.class.getName());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/PropertyMappingContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextLoader;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PropertyMappingContextCustomizerFactory}.\n *\n * @author Phillip Webb\n */\nclass PropertyMappingContextCustomizerFactoryTests {\n\n\tprivate final PropertyMappingContextCustomizerFactory factory = new PropertyMappingContextCustomizerFactory();\n\n\t@Test\n\tvoid getContextCustomizerWhenHasNoMappingShouldNotAddPropertySource() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(NoMapping.class, Collections.emptyList());\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tConfigurableEnvironment environment = mock(ConfigurableEnvironment.class);\n\t\tConfigurableListableBeanFactory beanFactory = mock(ConfigurableListableBeanFactory.class);\n\t\tgiven(context.getEnvironment()).willReturn(environment);\n\t\tgiven(context.getBeanFactory()).willReturn(beanFactory);\n\t\tcustomizer.customizeContext(context, getMergedConfigConfiguration());\n\t\tthen(environment).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasTypeMappingShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(TypeMapping.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasAttributeMappingShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(AttributeMapping.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid hashCodeAndEqualsShouldBeBasedOnPropertyValues() {\n\t\tContextCustomizer customizer1 = this.factory.createContextCustomizer(TypeMapping.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer2 = this.factory.createContextCustomizer(AttributeMapping.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer3 = this.factory.createContextCustomizer(OtherMapping.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t\tassertThat(customizer1).isEqualTo(customizer1).isEqualTo(customizer2).isNotEqualTo(customizer3);\n\t}\n\n\t@Test\n\tvoid prepareContextShouldAddPropertySource() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(AttributeMapping.class,\n\t\t\t\tCollections.emptyList());\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcustomizer.customizeContext(context, getMergedConfigConfiguration());\n\t\tassertThat(context.getEnvironment().getProperty(\"mapped\")).isEqualTo(\"Mapped\");\n\t}\n\n\t@Test\n\tvoid propertyMappingShouldNotBeUsedWithComponent() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(AttributeMapping.class,\n\t\t\t\tCollections.emptyList());\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(ConfigMapping.class);\n\t\tcustomizer.customizeContext(context, getMergedConfigConfiguration());\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(context::refresh)\n\t\t\t.withMessageContaining(\"The @PropertyMapping annotation \"\n\t\t\t\t\t+ \"@PropertyMappingContextCustomizerFactoryTests.TypeMappingAnnotation \"\n\t\t\t\t\t+ \"cannot be used in combination with the @Component annotation @Configuration\");\n\t}\n\n\tprivate MergedContextConfiguration getMergedConfigConfiguration() {\n\t\treturn new MergedContextConfiguration(getClass(), null, null, null, mock(ContextLoader.class));\n\t}\n\n\t@NoMappingAnnotation\n\tstatic class NoMapping {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface NoMappingAnnotation {\n\n\t}\n\n\t@TypeMappingAnnotation\n\tstatic class TypeMapping {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TypeMappingAnnotation\n\tstatic class ConfigMapping {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@PropertyMapping\n\t@interface TypeMappingAnnotation {\n\n\t\tString mapped() default \"Mapped\";\n\n\t}\n\n\t@AttributeMappingAnnotation\n\tstatic class AttributeMapping {\n\n\t}\n\n\t@AttributeMappingAnnotation(\"Other\")\n\tstatic class OtherMapping {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface AttributeMappingAnnotation {\n\n\t\t@PropertyMapping(\"mapped\")\n\t\tString value() default \"Mapped\";\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/PropertyMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link PropertyMapping @PropertyMapping} annotations.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@ExampleMapping(exampleProperty = \"abc\")\nclass PropertyMappingTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid hasProperty() {\n\t\tassertThat(this.environment.getProperty(\"example-property\")).isEqualTo(\"abc\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderAotTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.aot.generate.InMemoryGeneratedFiles;\nimport org.springframework.aot.test.generate.CompilerFiles;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.GenericBeanDefinition;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.test.context.BootstrapUtils;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextBootstrapper;\nimport org.springframework.test.context.aot.AotContextLoader;\nimport org.springframework.test.context.aot.AotTestContextInitializers;\nimport org.springframework.test.context.aot.TestContextAotGenerator;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootContextLoader} when used in AOT mode.\n *\n * @author Phillip Webb\n */\n@CompileWithForkedClassLoader\nclass SpringBootContextLoaderAotTests {\n\n\t@Test\n\tvoid loadContextForAotProcessingAndAotRuntime() {\n\t\tInMemoryGeneratedFiles generatedFiles = new InMemoryGeneratedFiles();\n\t\tTestContextAotGenerator generator = new TestContextAotGenerator(generatedFiles);\n\t\tClass<?> testClass = ExampleTest.class;\n\t\tgenerator.processAheadOfTime(Stream.of(testClass));\n\t\tTestCompiler.forSystem()\n\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t.with(CompilerFiles.from(generatedFiles))\n\t\t\t.compile(ThrowingConsumer.of((compiled) -> assertCompiledTest(testClass)));\n\t}\n\n\tprivate void assertCompiledTest(Class<?> testClass) throws Exception {\n\t\ttry {\n\t\t\tSystem.setProperty(AotDetector.AOT_ENABLED, \"true\");\n\t\t\tresetAotClasses();\n\t\t\tAotTestContextInitializers aotContextInitializers = new AotTestContextInitializers();\n\t\t\tTestContextBootstrapper testContextBootstrapper = BootstrapUtils.resolveTestContextBootstrapper(testClass);\n\t\t\tMergedContextConfiguration mergedConfig = testContextBootstrapper.buildMergedContextConfiguration();\n\t\t\tApplicationContextInitializer<ConfigurableApplicationContext> contextInitializer = aotContextInitializers\n\t\t\t\t.getContextInitializer(testClass);\n\t\t\tassertThat(contextInitializer).isNotNull();\n\t\t\tConfigurableApplicationContext context = (ConfigurableApplicationContext) ((AotContextLoader) mergedConfig\n\t\t\t\t.getContextLoader()).loadContextForAotRuntime(mergedConfig, contextInitializer);\n\t\t\tassertThat(context).isExactlyInstanceOf(GenericApplicationContext.class);\n\t\t\tString[] beanNames = context.getBeanNamesForType(ExampleBean.class);\n\t\t\tBeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(beanNames[0]);\n\t\t\tassertThat(beanDefinition).isNotExactlyInstanceOf(GenericBeanDefinition.class);\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(AotDetector.AOT_ENABLED);\n\t\t\tresetAotClasses();\n\t\t}\n\t}\n\n\tprivate void resetAotClasses() {\n\t\treset(\"org.springframework.test.context.aot.AotTestAttributesFactory\");\n\t\treset(\"org.springframework.test.context.aot.AotTestContextInitializersFactory\");\n\t}\n\n\tprivate void reset(String className) {\n\t\tClass<?> targetClass = ClassUtils.resolveClassName(className, null);\n\t\tReflectionTestUtils.invokeMethod(targetClass, \"reset\");\n\t}\n\n\t@SpringBootTest(classes = ExampleConfig.class, webEnvironment = WebEnvironment.NONE)\n\tstatic class ExampleTest {\n\n\t}\n\n\t@SpringBootConfiguration\n\t@Import(ExampleBean.class)\n\tstatic class ExampleConfig {\n\n\t}\n\n\tstatic class ExampleBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderMockMvcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebAppConfiguration @WebAppConfiguration} integration.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(SpringExtension.class)\n@DirtiesContext\n@ContextConfiguration(loader = SpringBootContextLoader.class)\n@WebAppConfiguration\nclass SpringBootContextLoaderMockMvcTests {\n\n\t@Autowired\n\tprivate WebApplicationContext context;\n\n\t@Autowired\n\tprivate ServletContext servletContext;\n\n\tprivate MockMvcTester mvc;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.mvc = MockMvcTester.from(this.context);\n\t}\n\n\t@Test\n\tvoid testMockHttpEndpoint() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).hasStatusOk().hasBodyTextEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid validateWebApplicationContextIsSet() {\n\t\tassertThat(this.context).isSameAs(WebApplicationContextUtils.getWebApplicationContext(this.servletContext));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@RestController\n\tstatic class Config {\n\n\t\t@RequestMapping(\"/\")\n\t\tString home() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootContextLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.reactive.GenericReactiveWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.ApplicationContextFailureProcessor;\nimport org.springframework.test.context.BootstrapUtils;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.ContextHierarchy;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestContextManager;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringBootContextLoader}\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Madhura Bhave\n * @author Sijun Yang\n */\nclass SpringBootContextLoaderTests {\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tContextLoaderApplicationContextFailureProcessor.reset();\n\t}\n\n\t@Test\n\tvoid environmentPropertiesSimple() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(SimpleConfig.class);\n\t\tassertKey(config, \"key\", \"myValue\");\n\t\tassertKey(config, \"anotherKey\", \"anotherValue\");\n\t}\n\n\t@Test\n\tvoid environmentPropertiesSimpleNonAlias() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(SimpleConfigNonAlias.class);\n\t\tassertKey(config, \"key\", \"myValue\");\n\t\tassertKey(config, \"anotherKey\", \"anotherValue\");\n\t}\n\n\t@Test\n\tvoid environmentPropertiesOverrideDefaults() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(OverrideConfig.class);\n\t\tassertKey(config, \"server.port\", \"2345\");\n\t}\n\n\t@Test\n\tvoid environmentPropertiesAppend() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(AppendConfig.class);\n\t\tassertKey(config, \"key\", \"myValue\");\n\t\tassertKey(config, \"otherKey\", \"otherValue\");\n\t}\n\n\t@Test\n\tvoid environmentPropertiesSeparatorInValue() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(SameSeparatorInValue.class);\n\t\tassertKey(config, \"key\", \"my=Value\");\n\t\tassertKey(config, \"anotherKey\", \"another:Value\");\n\t}\n\n\t@Test\n\tvoid environmentPropertiesAnotherSeparatorInValue() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(AnotherSeparatorInValue.class);\n\t\tassertKey(config, \"key\", \"my:Value\");\n\t\tassertKey(config, \"anotherKey\", \"another=Value\");\n\t}\n\n\t@Test // gh-4384\n\t@Disabled\n\tvoid environmentPropertiesNewLineInValue() {\n\t\tMap<String, Object> config = getMergedContextConfigurationProperties(NewLineInValue.class);\n\t\tassertKey(config, \"key\", \"myValue\");\n\t\tassertKey(config, \"variables\", \"foo=FOO\\n bar=BAR\");\n\t}\n\n\t@Test\n\tvoid noActiveProfiles() {\n\t\tassertThat(getActiveProfiles(SimpleConfig.class)).isEmpty();\n\t}\n\n\t@Test\n\tvoid multipleActiveProfiles() {\n\t\tassertThat(getActiveProfiles(MultipleActiveProfiles.class)).containsExactly(\"profile1\", \"profile2\");\n\t}\n\n\t@Test // gh-28776\n\tvoid testPropertyValuesShouldTakePrecedenceWhenInlinedPropertiesPresent() {\n\t\tTestContext context = new ExposedTestContextManager(SimpleConfig.class).getExposedTestContext();\n\t\tStandardEnvironment environment = (StandardEnvironment) context.getApplicationContext().getEnvironment();\n\t\tTestPropertyValues.of(\"key=thisValue\").applyTo(environment);\n\t\tassertThat(environment.getProperty(\"key\")).isEqualTo(\"thisValue\");\n\t\tassertThat(environment.getPropertySources().get(\"active-test-profiles\")).isNull();\n\t}\n\n\t@Test\n\tvoid testPropertyValuesShouldTakePrecedenceWhenInlinedPropertiesPresentAndProfilesActive() {\n\t\tTestContext context = new ExposedTestContextManager(ActiveProfileWithInlinedProperties.class)\n\t\t\t.getExposedTestContext();\n\t\tStandardEnvironment environment = (StandardEnvironment) context.getApplicationContext().getEnvironment();\n\t\tTestPropertyValues.of(\"key=thisValue\").applyTo(environment);\n\t\tassertThat(environment.getProperty(\"key\")).isEqualTo(\"thisValue\");\n\t\tassertThat(environment.getPropertySources().get(\"active-test-profiles\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid propertySourceOrdering() {\n\t\tTestContext context = new ExposedTestContextManager(PropertySourceOrdering.class).getExposedTestContext();\n\t\tConfigurableEnvironment environment = (ConfigurableEnvironment) context.getApplicationContext()\n\t\t\t.getEnvironment();\n\t\tList<String> names = environment.getPropertySources()\n\t\t\t.stream()\n\t\t\t.map(PropertySource::getName)\n\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\tString configResource = names.remove(names.size() - 2);\n\t\tassertThat(names).containsExactly(\"configurationProperties\", \"Inlined Test Properties\", \"commandLineArgs\",\n\t\t\t\t\"systemProperties\", \"systemEnvironment\", \"random\", \"applicationInfo\");\n\t\tassertThat(configResource).startsWith(\"Config resource\");\n\t}\n\n\t@Test\n\tvoid whenEnvironmentChangesWebApplicationTypeToNoneThenContextTypeChangesAccordingly() {\n\t\tTestContext context = new ExposedTestContextManager(ChangingWebApplicationTypeToNone.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThat(context.getApplicationContext()).isNotInstanceOf(WebApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid whenEnvironmentChangesWebApplicationTypeToReactiveThenContextTypeChangesAccordingly() {\n\t\tTestContext context = new ExposedTestContextManager(ChangingWebApplicationTypeToReactive.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThat(context.getApplicationContext()).isInstanceOf(GenericReactiveWebApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid whenUseMainMethodAlwaysAndMainMethodThrowsException() {\n\t\tTestContext testContext = new ExposedTestContextManager(UseMainMethodAlwaysAndMainMethodThrowsException.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThatIllegalStateException().isThrownBy(testContext::getApplicationContext)\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"ThrownFromMain\");\n\t}\n\n\t@Test\n\tvoid whenUseMainMethodWhenAvailableAndNoMainMethod() {\n\t\tTestContext testContext = new ExposedTestContextManager(UseMainMethodWhenAvailableAndNoMainMethod.class)\n\t\t\t.getExposedTestContext();\n\t\tApplicationContext applicationContext = testContext.getApplicationContext();\n\t\tassertThat(applicationContext.getEnvironment().getActiveProfiles()).isEmpty();\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(classes = { UsePublicMainMethodWhenAvailableAndMainMethod.class,\n\t\t\tUsePublicParameterlessMainMethodWhenAvailableAndMainMethod.class,\n\t\t\tUsePackagePrivateMainMethodWhenAvailableAndMainMethod.class,\n\t\t\tUsePackagePrivateParameterlessMainMethodWhenAvailableAndMainMethod.class })\n\tvoid whenUseMainMethodWhenAvailableAndMainMethod(Class<?> testClass) {\n\t\tTestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext();\n\t\tApplicationContext applicationContext = testContext.getApplicationContext();\n\t\tassertThat(applicationContext.getEnvironment().getActiveProfiles()).contains(\"frommain\");\n\t}\n\n\t@Test\n\tvoid whenUseMainMethodNever() {\n\t\tTestContext testContext = new ExposedTestContextManager(UseMainMethodNever.class).getExposedTestContext();\n\t\tApplicationContext applicationContext = testContext.getApplicationContext();\n\t\tassertThat(applicationContext.getEnvironment().getActiveProfiles()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenUseMainMethodWithBeanThrowingException() {\n\t\tTestContext testContext = new ExposedTestContextManager(UseMainMethodWithBeanThrowingException.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThatIllegalStateException().isThrownBy(testContext::getApplicationContext)\n\t\t\t.havingCause()\n\t\t\t.satisfies((exception) -> {\n\t\t\t\tassertThat(exception).isInstanceOf(BeanCreationException.class);\n\t\t\t\tassertThat(exception).isSameAs(ContextLoaderApplicationContextFailureProcessor.contextLoadException);\n\t\t\t});\n\t\tassertThat(ContextLoaderApplicationContextFailureProcessor.failedContext).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenNoMainMethodWithBeanThrowingException() {\n\t\tTestContext testContext = new ExposedTestContextManager(NoMainMethodWithBeanThrowingException.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThatIllegalStateException().isThrownBy(testContext::getApplicationContext)\n\t\t\t.havingCause()\n\t\t\t.satisfies((exception) -> {\n\t\t\t\tassertThat(exception).isInstanceOf(BeanCreationException.class);\n\t\t\t\tassertThat(exception).isSameAs(ContextLoaderApplicationContextFailureProcessor.contextLoadException);\n\t\t\t});\n\t\tassertThat(ContextLoaderApplicationContextFailureProcessor.failedContext).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenUseMainMethodWithContextHierarchyThrowsException() {\n\t\tTestContext testContext = new ExposedTestContextManager(UseMainMethodWithContextHierarchy.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThatIllegalStateException().isThrownBy(testContext::getApplicationContext)\n\t\t\t.havingCause()\n\t\t\t.withMessage(\"UseMainMethod.ALWAYS cannot be used with @ContextHierarchy tests\");\n\t}\n\n\t@Test\n\tvoid whenMainMethodNotAvailableReturnsNoAotContribution() throws Exception {\n\t\tSpringBootContextLoader contextLoader = new SpringBootContextLoader();\n\t\tMergedContextConfiguration contextConfiguration = BootstrapUtils\n\t\t\t.resolveTestContextBootstrapper(UseMainMethodWhenAvailableAndNoMainMethod.class)\n\t\t\t.buildMergedContextConfiguration();\n\t\tRuntimeHints runtimeHints = mock(RuntimeHints.class);\n\t\tcontextLoader.loadContextForAotProcessing(contextConfiguration, runtimeHints);\n\t\tthen(runtimeHints).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid whenMainMethodPresentRegisterReflectionHints() throws Exception {\n\t\tSpringBootContextLoader contextLoader = new SpringBootContextLoader();\n\t\tMergedContextConfiguration contextConfiguration = BootstrapUtils\n\t\t\t.resolveTestContextBootstrapper(UsePublicMainMethodWhenAvailableAndMainMethod.class)\n\t\t\t.buildMergedContextConfiguration();\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tcontextLoader.loadContextForAotProcessing(contextConfiguration, runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(ConfigWithPublicMain.class, \"main\"))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid whenSubclassProvidesCustomApplicationContextFactory() {\n\t\tTestContext testContext = new ExposedTestContextManager(CustomApplicationContextTest.class)\n\t\t\t.getExposedTestContext();\n\t\tassertThat(testContext.getApplicationContext()).isInstanceOf(CustomAnnotationConfigApplicationContext.class);\n\t}\n\n\tprivate String[] getActiveProfiles(Class<?> testClass) {\n\t\tTestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext();\n\t\tApplicationContext applicationContext = testContext.getApplicationContext();\n\t\treturn applicationContext.getEnvironment().getActiveProfiles();\n\t}\n\n\tprivate Map<String, Object> getMergedContextConfigurationProperties(Class<?> testClass) {\n\t\tTestContext context = new ExposedTestContextManager(testClass).getExposedTestContext();\n\t\tMergedContextConfiguration config = (MergedContextConfiguration) ReflectionTestUtils.getField(context,\n\t\t\t\t\"mergedConfig\");\n\t\tassertThat(config).isNotNull();\n\t\treturn TestPropertySourceUtils.convertInlinedPropertiesToMap(config.getPropertySourceProperties());\n\t}\n\n\tprivate void assertKey(Map<String, Object> actual, String key, Object value) {\n\t\tassertThat(actual).as(\"Key '\" + key + \"' not found\").containsKey(key);\n\t\tassertThat(actual).containsEntry(key, value);\n\t}\n\n\t@SpringBootTest(properties = { \"key=myValue\", \"anotherKey:anotherValue\" }, classes = Config.class)\n\tstatic class SimpleConfig {\n\n\t}\n\n\t@SpringBootTest(properties = { \"key=myValue\", \"anotherKey:anotherValue\" }, classes = Config.class)\n\tstatic class SimpleConfigNonAlias {\n\n\t}\n\n\t@SpringBootTest(properties = \"server.port=2345\", classes = Config.class)\n\tstatic class OverrideConfig {\n\n\t}\n\n\t@SpringBootTest(properties = { \"key=myValue\", \"otherKey=otherValue\" }, classes = Config.class)\n\tstatic class AppendConfig {\n\n\t}\n\n\t@SpringBootTest(properties = { \"key=my=Value\", \"anotherKey:another:Value\" }, classes = Config.class)\n\tstatic class SameSeparatorInValue {\n\n\t}\n\n\t@SpringBootTest(properties = { \"key=my:Value\", \"anotherKey:another=Value\" }, classes = Config.class)\n\tstatic class AnotherSeparatorInValue {\n\n\t}\n\n\t@SpringBootTest(properties = { \"key=myValue\", \"variables=foo=FOO\\n bar=BAR\" }, classes = Config.class)\n\tstatic class NewLineInValue {\n\n\t}\n\n\t@SpringBootTest(classes = Config.class)\n\t@ActiveProfiles({ \"profile1\", \"profile2\" })\n\tstatic class MultipleActiveProfiles {\n\n\t}\n\n\t@SpringBootTest(properties = { \"key=myValue\" }, classes = Config.class)\n\t@ActiveProfiles({ \"profile1\" })\n\tstatic class ActiveProfileWithInlinedProperties {\n\n\t}\n\n\t@SpringBootTest(classes = Config.class, args = \"args\", properties = \"one=1\")\n\t@TestPropertySource(properties = \"two=2\")\n\tstatic class PropertySourceOrdering {\n\n\t}\n\n\t@SpringBootTest(classes = Config.class, args = \"--spring.main.web-application-type=none\")\n\tstatic class ChangingWebApplicationTypeToNone {\n\n\t}\n\n\t@SpringBootTest(classes = Config.class, args = \"--spring.main.web-application-type=reactive\")\n\tstatic class ChangingWebApplicationTypeToReactive {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithMainThrowingException.class, useMainMethod = UseMainMethod.ALWAYS)\n\tstatic class UseMainMethodAlwaysAndMainMethodThrowsException {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithNoMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)\n\tstatic class UseMainMethodWhenAvailableAndNoMainMethod {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithPublicMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)\n\tstatic class UsePublicMainMethodWhenAvailableAndMainMethod {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithPublicParameterlessMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)\n\tstatic class UsePublicParameterlessMainMethodWhenAvailableAndMainMethod {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithPackagePrivateMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)\n\tstatic class UsePackagePrivateMainMethodWhenAvailableAndMainMethod {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithPackagePrivateParameterlessMain.class,\n\t\t\tuseMainMethod = UseMainMethod.WHEN_AVAILABLE)\n\tstatic class UsePackagePrivateParameterlessMainMethodWhenAvailableAndMainMethod {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithPublicMain.class, useMainMethod = UseMainMethod.NEVER)\n\tstatic class UseMainMethodNever {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithMainWithBeanThrowingException.class, useMainMethod = UseMainMethod.ALWAYS)\n\tstatic class UseMainMethodWithBeanThrowingException {\n\n\t}\n\n\t@SpringBootTest(classes = ConfigWithNoMainWithBeanThrowingException.class, useMainMethod = UseMainMethod.NEVER)\n\tstatic class NoMainMethodWithBeanThrowingException {\n\n\t}\n\n\t@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)\n\t@ContextHierarchy({ @ContextConfiguration(classes = ConfigWithPublicMain.class),\n\t\t\t@ContextConfiguration(classes = AnotherConfigWithMain.class) })\n\tstatic class UseMainMethodWithContextHierarchy {\n\n\t}\n\n\t@SpringBootTest\n\t@ContextConfiguration(classes = Config.class, loader = CustomApplicationContextSpringBootContextLoader.class)\n\tstatic class CustomApplicationContextTest {\n\n\t}\n\n\tstatic class CustomApplicationContextSpringBootContextLoader extends SpringBootContextLoader {\n\n\t\t@Override\n\t\tprotected ApplicationContextFactory getApplicationContextFactory(MergedContextConfiguration mergedConfig) {\n\t\t\treturn (webApplicationType) -> new CustomAnnotationConfigApplicationContext();\n\t\t}\n\n\t}\n\n\tstatic class CustomAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithPublicMain {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tnew SpringApplication(ConfigWithPublicMain.class).run(\"--spring.profiles.active=frommain\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithPublicParameterlessMain {\n\n\t\tpublic static void main() {\n\t\t\tnew SpringApplication(ConfigWithPublicMain.class).run(\"--spring.profiles.active=frommain\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithPackagePrivateMain {\n\n\t\tstatic void main(String[] args) {\n\t\t\tnew SpringApplication(ConfigWithPublicMain.class).run(\"--spring.profiles.active=frommain\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithPackagePrivateParameterlessMain {\n\n\t\tstatic void main() {\n\t\t\tnew SpringApplication(ConfigWithPublicMain.class).run(\"--spring.profiles.active=frommain\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class AnotherConfigWithMain {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tnew SpringApplication(AnotherConfigWithMain.class).run(\"--spring.profiles.active=anotherfrommain\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tstatic class ConfigWithNoMain {\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithMainWithBeanThrowingException {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tnew SpringApplication(ConfigWithMainWithBeanThrowingException.class).run();\n\t\t}\n\n\t\t@Bean\n\t\tString failContextLoad() {\n\t\t\tthrow new RuntimeException(\"ThrownFromBeanMethod\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tstatic class ConfigWithNoMainWithBeanThrowingException {\n\n\t\t@Bean\n\t\tString failContextLoad() {\n\t\t\tthrow new RuntimeException(\"ThrownFromBeanMethod\");\n\t\t}\n\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithMainThrowingException {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tthrow new RuntimeException(\"ThrownFromMain\");\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link TestContextManager} which exposes the {@link TestContext}.\n\t */\n\tstatic class ExposedTestContextManager extends TestContextManager {\n\n\t\tExposedTestContextManager(Class<?> testClass) {\n\t\t\tsuper(testClass);\n\t\t}\n\n\t\tfinal TestContext getExposedTestContext() {\n\t\t\treturn super.getTestContext();\n\t\t}\n\n\t}\n\n\tprivate static final class ContextLoaderApplicationContextFailureProcessor\n\t\t\timplements ApplicationContextFailureProcessor {\n\n\t\tstatic @Nullable ApplicationContext failedContext;\n\n\t\tstatic @Nullable Throwable contextLoadException;\n\n\t\t@Override\n\t\tpublic void processLoadFailure(ApplicationContext context, @Nullable Throwable exception) {\n\t\t\tfailedContext = context;\n\t\t\tcontextLoadException = exception;\n\t\t}\n\n\t\tprivate static void reset() {\n\t\t\tfailedContext = null;\n\t\t\tcontextLoadException = null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestActiveProfileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ActiveProfiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with active profiles. See gh-1469.\n *\n * @author Phillip Webb\n */\n@DirtiesContext\n@SpringBootTest(\"spring.config.name=enableother\")\n@ActiveProfiles(\"override\")\nclass SpringBootTestActiveProfileTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid profiles() {\n\t\tassertThat(this.context.getEnvironment().getActiveProfiles()).containsExactly(\"override\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestArgsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with application arguments.\n *\n * @author Justin Griffin\n * @author Stephane Nicoll\n */\n@SpringBootTest(args = { \"--option.foo=foo-value\", \"other.bar=other-bar-value\" })\nclass SpringBootTestArgsTests {\n\n\t@Autowired\n\tprivate ApplicationArguments args;\n\n\t@Test\n\tvoid applicationArgumentsPopulated() {\n\t\tassertThat(this.args.getOptionNames()).containsOnly(\"option.foo\");\n\t\tassertThat(this.args.getOptionValues(\"option.foo\")).containsOnly(\"foo-value\");\n\t\tassertThat(this.args.getNonOptionArgs()).containsOnly(\"other.bar=other-bar-value\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestContextHierarchyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.context.SpringBootTestContextHierarchyTests.ChildConfiguration;\nimport org.springframework.boot.test.context.SpringBootTestContextHierarchyTests.ParentConfiguration;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.ContextHierarchy;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} and\n * {@link ContextHierarchy @ContextHierarchy}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@ContextHierarchy({ @ContextConfiguration(classes = ParentConfiguration.class),\n\t\t@ContextConfiguration(classes = ChildConfiguration.class) })\n@ExtendWith(OutputCaptureExtension.class)\nclass SpringBootTestContextHierarchyTests {\n\n\t@Test\n\tvoid contextLoads(CapturedOutput capturedOutput) {\n\t\tassertThat(capturedOutput).containsOnlyOnce(\":: Spring Boot ::\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParentConfiguration {\n\n\t\t@Bean\n\t\tMyBean myBean() {\n\t\t\treturn new MyBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ChildConfiguration {\n\n\t\tChildConfiguration(MyBean myBean) {\n\n\t\t}\n\n\t}\n\n\tstatic class MyBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestCustomConfigNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with a custom config name\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(properties = \"spring.config.name=custom-config-name\")\nclass SpringBootTestCustomConfigNameTests {\n\n\t@Value(\"${test.foo}\")\n\tprivate @Nullable String foo;\n\n\t@Test\n\tvoid propertyIsLoadedFromConfigFileWithCustomName() {\n\t\tassertThat(this.foo).isEqualTo(\"bar\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\tPropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestCustomPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link SpringBootTest @SpringBootTest} with a custom inline server.port in a\n * non-embedded web environment.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(properties = \"server.port=12345\")\nclass SpringBootTestCustomPortTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid validatePortIsNotOverwritten() {\n\t\tString port = this.environment.getProperty(\"server.port\");\n\t\tassertThat(port).isEqualTo(\"12345\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestDefaultConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} (detectDefaultConfigurationClasses).\n *\n * @author Dave Syer\n */\n@ExtendWith(SpringExtension.class)\n@DirtiesContext\nclass SpringBootTestDefaultConfigurationTests {\n\n\t@Autowired\n\tprivate Config config;\n\n\t@Test\n\tvoid nestedConfigClasses() {\n\t\tassertThat(this.config).isNotNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestGroovyConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} (detectDefaultConfigurationClasses).\n *\n * @author Dave Syer\n */\n@DirtiesContext\n@SpringBootTest\n@ContextConfiguration(locations = \"classpath:test.groovy\")\nclass SpringBootTestGroovyConfigurationTests {\n\n\t@Autowired\n\tprivate String foo;\n\n\t@Test\n\tvoid groovyConfigLoaded() {\n\t\tassertThat(this.foo).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestGroovyConventionConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} finding groovy config.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@DirtiesContext\nclass SpringBootTestGroovyConventionConfigurationTests {\n\n\t@Autowired\n\tprivate String foo;\n\n\t@Test\n\tvoid groovyConfigLoaded() {\n\t\tassertThat(this.foo).isEqualTo(\"World\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestJmxTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for disabling JMX by default\n *\n * @author Dave Syer\n */\n@DirtiesContext\n@SpringBootTest\nclass SpringBootTestJmxTests {\n\n\t@Value(\"${spring.jmx.enabled}\")\n\tprivate boolean jmx;\n\n\t@Test\n\tvoid disabledByDefault() {\n\t\tassertThat(this.jmx).isFalse();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestMixedConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTestMixedConfigurationTests.Config;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest}.\n *\n * @author Dave Syer\n */\n@DirtiesContext\n@SpringBootTest\n@ContextConfiguration(classes = Config.class, locations = \"classpath:test.groovy\")\nclass SpringBootTestMixedConfigurationTests {\n\n\t@Autowired\n\tprivate String foo;\n\n\t@Autowired\n\tprivate Config config;\n\n\t@Test\n\tvoid mixedConfigClasses() {\n\t\tassertThat(this.foo).isNotNull();\n\t\tassertThat(this.config).isNotNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestUseMainMethodWithPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest} when using {@link UseMainMethod#ALWAYS} and setting\n * properties.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(properties = \"test=123\", useMainMethod = UseMainMethod.ALWAYS)\nclass SpringBootTestUseMainMethodWithPropertiesTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid propertyIsSet() {\n\t\tassertThat(this.applicationContext.getEnvironment().getProperty(\"test\")).isEqualTo(\"123\");\n\t}\n\n\t@SpringBootConfiguration(proxyBeanMethods = false)\n\tpublic static class ConfigWithMain {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tnew SpringApplication(ConfigWithMain.class).run();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentMockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.request.RequestAttributes;\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with\n * {@link WebEnvironment#MOCK}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@SpringBootTest(\"value=123\")\n@DirtiesContext\nclass SpringBootTestWebEnvironmentMockTests {\n\n\t@Value(\"${value}\")\n\tprivate int value;\n\n\t@Autowired\n\tprivate WebApplicationContext context;\n\n\t@Autowired\n\tprivate ServletContext servletContext;\n\n\t@Test\n\tvoid annotationAttributesOverridePropertiesFile() {\n\t\tassertThat(this.value).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid validateWebApplicationContextIsSet() {\n\t\tWebApplicationContext fromServletContext = WebApplicationContextUtils\n\t\t\t.getWebApplicationContext(this.servletContext);\n\t\tassertThat(fromServletContext).isSameAs(this.context);\n\t}\n\n\t@Test\n\tvoid setsRequestContextHolder() {\n\t\tRequestAttributes attributes = RequestContextHolder.getRequestAttributes();\n\t\tassertThat(attributes).isNotNull();\n\t}\n\n\t@Test\n\tvoid resourcePath() {\n\t\tassertThat(this.servletContext).hasFieldOrPropertyWithValue(\"resourceBasePath\", \"src/main/webapp\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class Config {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertyPlaceholder() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWebEnvironmentMockWithWebAppConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with\n * {@link WebEnvironment#MOCK}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@DirtiesContext\n@WebAppConfiguration(\"src/mymain/mywebapp\")\nclass SpringBootTestWebEnvironmentMockWithWebAppConfigurationTests {\n\n\t@Autowired\n\tprivate ServletContext servletContext;\n\n\t@Test\n\tvoid resourcePath() {\n\t\tassertThat(this.servletContext).hasFieldOrPropertyWithValue(\"resourceBasePath\", \"src/mymain/mywebapp\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class Config {\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertyPlaceholder() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWithActiveProfilesAndEnvironmentPropertyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with an\n * {@link ActiveProfiles @ActiveProfiles} annotation.\n *\n * @author Johnny Lim\n * @author Phillip Webb\n */\n@SpringBootTest\n@ActiveProfiles({ \"test1\", \"test2\" })\n@ContextConfiguration(loader = SpringBootTestWithActiveProfilesAndEnvironmentPropertyTests.Loader.class)\nclass SpringBootTestWithActiveProfilesAndEnvironmentPropertyTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid getActiveProfiles() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsOnly(\"test1\", \"test2\");\n\t}\n\n\t@Configuration\n\tstatic class Config {\n\n\t}\n\n\tstatic class Loader extends SpringBootContextLoader {\n\n\t\t@Override\n\t\tprotected ConfigurableEnvironment getEnvironment() {\n\t\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\t\tmap.put(\"spring.profiles.active\", \"local\");\n\t\t\tsources.addLast(new MapPropertySource(\"profiletest\", map));\n\t\t\treturn environment;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWithActiveProfilesAndSystemEnvironmentPropertyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with an\n * {@link ActiveProfiles @ActiveProfiles} annotation.\n *\n * @author Johnny Lim\n * @author Phillip Webb\n */\n@SpringBootTest\n@ActiveProfiles({ \"test1\", \"test2\" })\n@ContextConfiguration(loader = SpringBootTestWithActiveProfilesAndSystemEnvironmentPropertyTests.Loader.class)\nclass SpringBootTestWithActiveProfilesAndSystemEnvironmentPropertyTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid getActiveProfiles() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsOnly(\"test1\", \"test2\");\n\t}\n\n\t@Configuration\n\tstatic class Config {\n\n\t}\n\n\tstatic class Loader extends SpringBootContextLoader {\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprotected ConfigurableEnvironment getEnvironment() {\n\t\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\t\tPropertySource<?> source = sources.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);\n\t\t\tassertThat(source).isNotNull();\n\t\t\tMap<String, Object> map = new LinkedHashMap<>((Map<String, Object>) source.getSource());\n\t\t\tmap.put(\"SPRING_PROFILES_ACTIVE\", \"local\");\n\t\t\tsources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,\n\t\t\t\t\tnew MapPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, map));\n\t\t\treturn environment;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWithClassesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with specific classes.\n *\n * @author Phillip Webb\n */\n@DirtiesContext\n@SpringBootTest(classes = SpringBootTestWithClassesIntegrationTests.Config.class)\nclass SpringBootTestWithClassesIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid injectsOnlyConfig() {\n\t\tassertThat(this.context.getBean(Config.class)).isNotNull();\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.context.getBean(AdditionalConfig.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AdditionalConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWithContextConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with\n * {@link ContextConfiguration @ContextConfiguration}.\n *\n * @author Phillip Webb\n */\n@DirtiesContext\n@SpringBootTest\n@ContextConfiguration(classes = SpringBootTestWithContextConfigurationIntegrationTests.Config.class)\nclass SpringBootTestWithContextConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid injectsOnlyConfig() {\n\t\tassertThat(this.context.getBean(Config.class)).isNotNull();\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.context.getBean(AdditionalConfig.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AdditionalConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWithCustomEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with a custom\n * {@link Environment}.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest\n@ActiveProfiles({ \"test1\", \"test2\" })\n@ContextConfiguration(loader = SpringBootTestWithCustomEnvironmentTests.Loader.class)\nclass SpringBootTestWithCustomEnvironmentTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid getActiveProfiles() {\n\t\tassertThat(this.environment).isInstanceOf(MockEnvironment.class);\n\t\tassertThat(this.environment.getActiveProfiles()).containsOnly(\"test1\", \"test2\");\n\t}\n\n\t@Configuration\n\tstatic class Config {\n\n\t}\n\n\tstatic class Loader extends SpringBootContextLoader {\n\n\t\t@Override\n\t\tprotected ConfigurableEnvironment getEnvironment() {\n\t\t\treturn new MockEnvironment();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestWithTestPropertySourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for using {@link SpringBootTest @SpringBootTest} with\n * {@link TestPropertySource @TestPropertySource}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.NONE,\n\t\tproperties = { \"boot-test-inlined=foo\", \"b=boot-test-inlined\", \"c=boot-test-inlined\" })\n@TestPropertySource(\n\t\tproperties = { \"property-source-inlined=bar\", \"a=property-source-inlined\", \"c=property-source-inlined\" },\n\t\tlocations = \"classpath:/test-property-source-annotation.properties\")\nclass SpringBootTestWithTestPropertySourceTests {\n\n\t@Autowired\n\tprivate Config config;\n\n\t@Test\n\tvoid propertyFromSpringBootTestProperties() {\n\t\tassertThat(this.config.bootTestInlined).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid propertyFromTestPropertySourceProperties() {\n\t\tassertThat(this.config.propertySourceInlined).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid propertyFromTestPropertySourceLocations() {\n\t\tassertThat(this.config.propertySourceLocation).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid propertyFromPropertySourcePropertiesOverridesPropertyFromPropertySourceLocations() {\n\t\tassertThat(this.config.propertySourceInlinedOverridesPropertySourceLocation)\n\t\t\t.isEqualTo(\"property-source-inlined\");\n\t}\n\n\t@Test\n\tvoid propertyFromBootTestPropertiesOverridesPropertyFromPropertySourceLocations() {\n\t\tassertThat(this.config.bootTestInlinedOverridesPropertySourceLocation).isEqualTo(\"boot-test-inlined\");\n\t}\n\n\t@Test\n\tvoid propertyFromPropertySourcePropertiesOverridesPropertyFromBootTestProperties() {\n\t\tassertThat(this.config.propertySourceInlinedOverridesBootTestInlined).isEqualTo(\"property-source-inlined\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Value(\"${boot-test-inlined}\")\n\t\tprivate @Nullable String bootTestInlined;\n\n\t\t@Value(\"${property-source-inlined}\")\n\t\tprivate @Nullable String propertySourceInlined;\n\n\t\t@Value(\"${property-source-location}\")\n\t\tprivate @Nullable String propertySourceLocation;\n\n\t\t@Value(\"${a}\")\n\t\tprivate @Nullable String propertySourceInlinedOverridesPropertySourceLocation;\n\n\t\t@Value(\"${b}\")\n\t\tprivate @Nullable String bootTestInlinedOverridesPropertySourceLocation;\n\n\t\t@Value(\"${c}\")\n\t\tprivate @Nullable String propertySourceInlinedOverridesBootTestInlined;\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertyPlaceholder() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/SpringBootTestXmlConventionConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} finding XML config.\n *\n * @author Phillip Webb\n */\n@DirtiesContext\n@SpringBootTest\nclass SpringBootTestXmlConventionConfigurationTests {\n\n\t@Autowired\n\tprivate String foo;\n\n\t@Test\n\tvoid xmlConfigLoaded() {\n\t\tassertThat(this.foo).isEqualTo(\"World\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/TestConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestConfiguration @TestConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass TestConfigurationTests {\n\n\t@Test\n\tvoid proxyBeanMethodsIsEnabledByDefault() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(DefaultTestConfiguration.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", true);\n\t}\n\n\t@Test\n\tvoid proxyBeanMethodsCanBeDisabled() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(NoBeanMethodProxyingTestConfiguration.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", false);\n\t}\n\n\t@TestConfiguration\n\tstatic class DefaultTestConfiguration {\n\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class NoBeanMethodProxyingTestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AdditionalContextInterface.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Tests extra interface that can be applied to an {@link ApplicationContext}\n *\n * @author Phillip Webb\n */\ninterface AdditionalContextInterface {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.StaticApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link ApplicationContextAssertProvider} and\n * {@link AssertProviderApplicationContextInvocationHandler}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass ApplicationContextAssertProviderTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigurableApplicationContext mockContext;\n\n\tprivate RuntimeException startupFailure;\n\n\tprivate Supplier<ApplicationContext> mockContextSupplier;\n\n\tprivate Supplier<ApplicationContext> startupFailureSupplier;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.startupFailure = new RuntimeException();\n\t\tthis.mockContextSupplier = () -> this.mockContext;\n\t\tthis.startupFailureSupplier = () -> {\n\t\t\tthrow this.startupFailure;\n\t\t};\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWhenTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(\n\t\t\t\t() -> ApplicationContextAssertProvider.get(null, ApplicationContext.class, this.mockContextSupplier))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWhenTypeIsClassShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(\n\t\t\t\t() -> ApplicationContextAssertProvider.get(null, ApplicationContext.class, this.mockContextSupplier))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid getWhenContextTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ApplicationContextAssertProvider.get(TestAssertProviderApplicationContextClass.class,\n\t\t\t\t\tApplicationContext.class, this.mockContextSupplier))\n\t\t\t.withMessageContaining(\"'type' must be an interface\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWhenContextTypeIsClassShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ApplicationContextAssertProvider.get(TestAssertProviderApplicationContext.class, null,\n\t\t\t\t\tthis.mockContextSupplier))\n\t\t\t.withMessageContaining(\"'contextType' must not be null\");\n\t}\n\n\t@Test\n\tvoid getWhenSupplierIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ApplicationContextAssertProvider.get(TestAssertProviderApplicationContext.class,\n\t\t\t\t\tStaticApplicationContext.class, this.mockContextSupplier))\n\t\t\t.withMessageContaining(\"'contextType' must be an interface\");\n\t}\n\n\t@Test\n\tvoid getWhenContextStartsShouldReturnProxyThatCallsRealMethods() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tassertThat((Object) context).isNotNull();\n\t\tcontext.getBean(\"foo\");\n\t\tthen(this.mockContext).should().getBean(\"foo\");\n\t}\n\n\t@Test\n\tvoid getWhenContextFailsShouldReturnProxyThatThrowsExceptions() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.startupFailureSupplier);\n\t\tassertThat((Object) context).isNotNull();\n\t\tassertThatIllegalStateException().isThrownBy(() -> context.getBean(\"foo\"))\n\t\t\t.withCause(this.startupFailure)\n\t\t\t.withMessageContaining(\"failed to start\");\n\t}\n\n\t@Test\n\tvoid getSourceContextWhenContextStartsShouldReturnSourceContext() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tassertThat(context.getSourceApplicationContext()).isSameAs(this.mockContext);\n\t}\n\n\t@Test\n\tvoid getSourceContextWhenContextFailsShouldThrowException() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.startupFailureSupplier);\n\t\tassertThatIllegalStateException().isThrownBy(context::getSourceApplicationContext)\n\t\t\t.withCause(this.startupFailure)\n\t\t\t.withMessageContaining(\"failed to start\");\n\t}\n\n\t@Test\n\tvoid getSourceContextOfTypeWhenContextStartsShouldReturnSourceContext() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tassertThat(context.getSourceApplicationContext(ApplicationContext.class)).isSameAs(this.mockContext);\n\t}\n\n\t@Test\n\tvoid getSourceContextOfTypeWhenContextFailsToStartShouldThrowException() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.startupFailureSupplier);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> context.getSourceApplicationContext(ApplicationContext.class))\n\t\t\t.withCause(this.startupFailure)\n\t\t\t.withMessageContaining(\"failed to start\");\n\t}\n\n\t@Test\n\tvoid getStartupFailureWhenContextStartsShouldReturnNull() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tassertThat(context.getStartupFailure()).isNull();\n\t}\n\n\t@Test\n\tvoid getStartupFailureWhenContextFailsToStartShouldReturnException() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.startupFailureSupplier);\n\t\tassertThat(context.getStartupFailure()).isEqualTo(this.startupFailure);\n\t}\n\n\t@Test\n\tvoid assertThatWhenContextStartsShouldReturnAssertions() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tApplicationContextAssert<ApplicationContext> contextAssert = assertThat(context);\n\t\tassertThat(contextAssert.getApplicationContext()).isSameAs(context);\n\t\tassertThat(contextAssert.getStartupFailure()).isNull();\n\t}\n\n\t@Test\n\tvoid assertThatWhenContextFailsShouldReturnAssertions() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.startupFailureSupplier);\n\t\tApplicationContextAssert<ApplicationContext> contextAssert = assertThat(context);\n\t\tassertThat(contextAssert.getApplicationContext()).isSameAs(context);\n\t\tassertThat(contextAssert.getStartupFailure()).isSameAs(this.startupFailure);\n\t}\n\n\t@Test\n\tvoid toStringWhenContextStartsShouldReturnSimpleString() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tassertThat(context.toString()).startsWith(\"Started application [ConfigurableApplicationContext.MockitoMock\")\n\t\t\t.endsWith(\"id = [null], applicationName = [null], beanDefinitionCount = 0]\");\n\t}\n\n\t@Test\n\tvoid toStringWhenContextFailsToStartShouldReturnSimpleString() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.startupFailureSupplier);\n\t\tassertThat(context).hasToString(\"Unstarted application context \"\n\t\t\t\t+ \"org.springframework.context.ApplicationContext[startupFailure=java.lang.RuntimeException]\");\n\t}\n\n\t@Test\n\tvoid closeShouldCloseContext() {\n\t\tApplicationContextAssertProvider<ApplicationContext> context = get(this.mockContextSupplier);\n\t\tcontext.close();\n\t\tthen(this.mockContext).should().close();\n\t}\n\n\tprivate ApplicationContextAssertProvider<ApplicationContext> get(Supplier<ApplicationContext> contextSupplier) {\n\t\treturn ApplicationContextAssertProvider.get(TestAssertProviderApplicationContext.class,\n\t\t\t\tApplicationContext.class, contextSupplier);\n\t}\n\n\tinterface TestAssertProviderApplicationContext extends ApplicationContextAssertProvider<ApplicationContext> {\n\n\t}\n\n\tabstract static class TestAssertProviderApplicationContextClass implements TestAssertProviderApplicationContext {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssert.Scope;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.support.StaticApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ApplicationContextAssert}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ApplicationContextAssertTests {\n\n\tprivate StaticApplicationContext parent;\n\n\tprivate StaticApplicationContext context;\n\n\tprivate final RuntimeException failure = new RuntimeException();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.parent = new StaticApplicationContext();\n\t\tthis.context = new StaticApplicationContext();\n\t\tthis.context.setParent(this.parent);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tthis.context.close();\n\t\tthis.parent.close();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenApplicationContextIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ApplicationContextAssert<>(null, null))\n\t\t\t.withMessageContaining(\"'applicationContext' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenHasApplicationContextShouldSetActual() {\n\t\tassertThat(getAssert(this.context).getSourceApplicationContext()).isSameAs(this.context);\n\t}\n\n\t@Test\n\tvoid createWhenHasExceptionShouldSetFailure() {\n\t\tassertThat(getAssert(this.failure)).getFailure().isSameAs(this.failure);\n\t}\n\n\t@Test\n\tvoid hasBeanWhenHasBeanShouldPass() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).hasBean(\"foo\");\n\t}\n\n\t@Test\n\tvoid hasBeanWhenHasNoBeanShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).hasBean(\"foo\"))\n\t\t\t.withMessageContaining(\"no such bean\");\n\t}\n\n\t@Test\n\tvoid hasBeanWhenNotStartedShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).hasBean(\"foo\"))\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid hasSingleBeanWhenHasSingleBeanShouldPass() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).hasSingleBean(Foo.class);\n\t}\n\n\t@Test\n\tvoid hasSingleBeanWhenHasNoBeansShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).hasSingleBean(Foo.class))\n\t\t\t.withMessageContaining(\"to have a single bean of type\");\n\t}\n\n\t@Test\n\tvoid hasSingleBeanWhenHasMultipleShouldFail() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).hasSingleBean(Foo.class))\n\t\t\t.withMessageContaining(\"but found:\");\n\t}\n\n\t@Test\n\tvoid hasSingleBeanWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).hasSingleBean(Foo.class))\n\t\t\t.withMessageContaining(\"to have a single bean of type\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid hasSingleBeanWhenInParentShouldFail() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).hasSingleBean(Foo.class))\n\t\t\t.withMessageContaining(\"but found:\");\n\t}\n\n\t@Test\n\tvoid hasSingleBeanWithLimitedScopeWhenInParentShouldPass() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThat(getAssert(this.context)).hasSingleBean(Foo.class, Scope.NO_ANCESTORS);\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfTypeWhenHasNoBeanOfTypeShouldPass() {\n\t\tassertThat(getAssert(this.context)).doesNotHaveBean(Foo.class);\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfTypeWhenHasBeanOfTypeShouldFail() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).doesNotHaveBean(Foo.class))\n\t\t\t.withMessageContaining(\"but found\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfTypeWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).doesNotHaveBean(Foo.class))\n\t\t\t.withMessageContaining(\"not to have any beans of type\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfTypeWhenInParentShouldFail() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).doesNotHaveBean(Foo.class))\n\t\t\t.withMessageContaining(\"but found\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfTypeWithLimitedScopeWhenInParentShouldPass() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).doesNotHaveBean(Foo.class, Scope.NO_ANCESTORS);\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfNameWhenHasNoBeanOfTypeShouldPass() {\n\t\tassertThat(getAssert(this.context)).doesNotHaveBean(\"foo\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfNameWhenHasBeanOfTypeShouldFail() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).doesNotHaveBean(\"foo\"))\n\t\t\t.withMessageContaining(\"but found\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveBeanOfNameWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).doesNotHaveBean(\"foo\"))\n\t\t\t.withMessageContaining(\"not to have any beans of name\")\n\t\t\t.withMessageContaining(\"failed to start\");\n\t}\n\n\t@Test\n\tvoid getBeanNamesWhenHasNamesShouldReturnNamesAssert() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBeanNames(Foo.class).containsOnly(\"foo\", \"bar\");\n\t}\n\n\t@Test\n\tvoid getBeanNamesWhenHasNoNamesShouldReturnEmptyAssert() {\n\t\tassertThat(getAssert(this.context)).getBeanNames(Foo.class).isEmpty();\n\t}\n\n\t@Test\n\tvoid getBeanNamesWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).doesNotHaveBean(\"foo\"))\n\t\t\t.withMessageContaining(\"not to have any beans of name\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenHasBeanShouldReturnBeanAssert() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBean(Foo.class).isNotNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenHasNoBeanShouldReturnNullAssert() {\n\t\tassertThat(getAssert(this.context)).getBean(Foo.class).isNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenHasMultipleBeansShouldFail() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).getBean(Foo.class))\n\t\t\t.withMessageContaining(\"but found\");\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenHasPrimaryBeanShouldReturnPrimary() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrimaryFooConfig.class);\n\t\tassertThat(getAssert(context)).getBean(Foo.class).isInstanceOf(Bar.class);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).getBean(Foo.class))\n\t\t\t.withMessageContaining(\"to contain bean of type\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenInParentShouldReturnBeanAssert() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBean(Foo.class).isNotNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenInParentWithLimitedScopeShouldReturnNullAssert() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBean(Foo.class, Scope.NO_ANCESTORS).isNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWhenHasMultipleBeansIncludingParentShouldFail() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).getBean(Foo.class))\n\t\t\t.withMessageContaining(\"but found\");\n\t}\n\n\t@Test\n\tvoid getBeanOfTypeWithLimitedScopeWhenHasMultipleBeansIncludingParentShouldReturnBeanAssert() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBean(Foo.class, Scope.NO_ANCESTORS).isNotNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfNameWhenHasBeanShouldReturnBeanAssert() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBean(\"foo\").isNotNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfNameWhenHasNoBeanOfNameShouldReturnNullAssert() {\n\t\tassertThat(getAssert(this.context)).getBean(\"foo\").isNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfNameWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).getBean(\"foo\"))\n\t\t\t.withMessageContaining(\"to contain a bean of name\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid getBeanOfNameAndTypeWhenHasBeanShouldReturnBeanAssert() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBean(\"foo\", Foo.class).isNotNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfNameAndTypeWhenHasNoBeanOfNameShouldReturnNullAssert() {\n\t\tassertThat(getAssert(this.context)).getBean(\"foo\", Foo.class).isNull();\n\t}\n\n\t@Test\n\tvoid getBeanOfNameAndTypeWhenHasNoBeanOfNameButDifferentTypeShouldFail() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).getBean(\"foo\", String.class))\n\t\t\t.withMessageContaining(\"of type\");\n\t}\n\n\t@Test\n\tvoid getBeanOfNameAndTypeWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).getBean(\"foo\", Foo.class))\n\t\t\t.withMessageContaining(\"to contain a bean of name\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid getBeansWhenHasBeansShouldReturnMapAssert() {\n\t\tthis.context.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBeans(Foo.class).hasSize(2).containsKeys(\"foo\", \"bar\");\n\t}\n\n\t@Test\n\tvoid getBeansWhenHasNoBeansShouldReturnEmptyMapAssert() {\n\t\tassertThat(getAssert(this.context)).getBeans(Foo.class).isEmpty();\n\t}\n\n\t@Test\n\tvoid getBeansWhenFailedToStartShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).getBeans(Foo.class))\n\t\t\t.withMessageContaining(\"to get beans of type\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid getBeansShouldIncludeBeansFromParentScope() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBeans(Foo.class).hasSize(2).containsKeys(\"foo\", \"bar\");\n\t}\n\n\t@Test\n\tvoid getBeansWithLimitedScopeShouldNotIncludeBeansFromParentScope() {\n\t\tthis.parent.registerSingleton(\"foo\", Foo.class);\n\t\tthis.context.registerSingleton(\"bar\", Foo.class);\n\t\tassertThat(getAssert(this.context)).getBeans(Foo.class, Scope.NO_ANCESTORS).hasSize(1).containsKeys(\"bar\");\n\t}\n\n\t@Test\n\tvoid getFailureWhenFailedShouldReturnFailure() {\n\t\tassertThat(getAssert(this.failure)).getFailure().isSameAs(this.failure);\n\t}\n\n\t@Test\n\tvoid getFailureWhenDidNotFailShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).getFailure())\n\t\t\t.withMessageContaining(\"context started\");\n\t}\n\n\t@Test\n\tvoid hasFailedWhenFailedShouldPass() {\n\t\tassertThat(getAssert(this.failure)).hasFailed();\n\t}\n\n\t@Test\n\tvoid hasFailedWhenNotFailedShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.context)).hasFailed())\n\t\t\t.withMessageContaining(\"to have failed\");\n\t}\n\n\t@Test\n\tvoid hasNotFailedWhenFailedShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(getAssert(this.failure)).hasNotFailed())\n\t\t\t.withMessageContaining(\"to have not failed\")\n\t\t\t.withMessageContaining(String.format(\"but context failed to start:%n java.lang.RuntimeException\"));\n\t}\n\n\t@Test\n\tvoid hasNotFailedWhenNotFailedShouldPass() {\n\t\tassertThat(getAssert(this.context)).hasNotFailed();\n\t}\n\n\tprivate AssertableApplicationContext getAssert(ConfigurableApplicationContext applicationContext) {\n\t\treturn AssertableApplicationContext.get(() -> applicationContext);\n\t}\n\n\tprivate AssertableApplicationContext getAssert(RuntimeException failure) {\n\t\treturn AssertableApplicationContext.get(() -> {\n\t\t\tthrow failure;\n\t\t});\n\t}\n\n\tstatic class Foo {\n\n\t}\n\n\tstatic class Bar extends Foo {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrimaryFooConfig {\n\n\t\t@Bean\n\t\tFoo foo() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tBar bar() {\n\t\t\treturn new Bar();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link AssertableApplicationContext}.\n *\n * @author Phillip Webb\n * @see ApplicationContextAssertProviderTests\n */\nclass AssertableApplicationContextTests {\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid getShouldReturnProxy() {\n\t\tAssertableApplicationContext context = AssertableApplicationContext\n\t\t\t.get(() -> mock(ConfigurableApplicationContext.class));\n\t\tassertThat(context).isInstanceOf(ConfigurableApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid getWhenHasAdditionalInterfaceShouldReturnProxy() {\n\t\ttry (AssertableApplicationContext context = AssertableApplicationContext.get(\n\t\t\t\t() -> mock(ConfigurableApplicationContext.class,\n\t\t\t\t\t\twithSettings().extraInterfaces(AdditionalContextInterface.class)),\n\t\t\t\tAdditionalContextInterface.class)) {\n\t\t\tassertThat(context).isInstanceOf(ConfigurableApplicationContext.class)\n\t\t\t\t.isInstanceOf(AdditionalContextInterface.class);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link AssertableReactiveWebApplicationContext}.\n *\n * @author Phillip Webb\n * @see ApplicationContextAssertProviderTests\n */\nclass AssertableReactiveWebApplicationContextTests {\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid getShouldReturnProxy() {\n\t\tAssertableReactiveWebApplicationContext context = AssertableReactiveWebApplicationContext\n\t\t\t.get(() -> mock(ConfigurableReactiveWebApplicationContext.class));\n\t\tassertThat(context).isInstanceOf(ConfigurableReactiveWebApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid getWhenHasAdditionalInterfaceShouldReturnProxy() {\n\t\ttry (AssertableReactiveWebApplicationContext context = AssertableReactiveWebApplicationContext.get(\n\t\t\t\t() -> mock(ConfigurableReactiveWebApplicationContext.class,\n\t\t\t\t\t\twithSettings().extraInterfaces(AdditionalContextInterface.class)),\n\t\t\t\tAdditionalContextInterface.class)) {\n\t\t\tassertThat(context).isInstanceOf(ConfigurableReactiveWebApplicationContext.class)\n\t\t\t\t.isInstanceOf(AdditionalContextInterface.class);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.assertj;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link AssertableWebApplicationContext}.\n *\n * @author Phillip Webb\n * @see ApplicationContextAssertProviderTests\n */\nclass AssertableWebApplicationContextTests {\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid getShouldReturnProxy() {\n\t\tAssertableWebApplicationContext context = AssertableWebApplicationContext\n\t\t\t.get(() -> mock(ConfigurableWebApplicationContext.class));\n\t\tassertThat(context).isInstanceOf(ConfigurableWebApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid getWhenHasAdditionalInterfaceShouldReturnProxy() {\n\t\ttry (ConfigurableWebApplicationContext context = AssertableWebApplicationContext.get(\n\t\t\t\t() -> mock(ConfigurableWebApplicationContext.class,\n\t\t\t\t\t\twithSettings().extraInterfaces(AdditionalContextInterface.class)),\n\t\t\t\tAdditionalContextInterface.class)) {\n\t\t\tassertThat(context).isInstanceOf(ConfigurableWebApplicationContext.class)\n\t\t\t\t.isInstanceOf(AdditionalContextInterface.class);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperExampleConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.bootstrap;\n\nimport org.springframework.boot.SpringBootConfiguration;\n\n/**\n * Example configuration used in\n * {@link SpringBootTestContextBootstrapperIntegrationTests}.\n *\n * @author Phillip Webb\n */\n@SpringBootConfiguration\npublic class SpringBootTestContextBootstrapperExampleConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.bootstrap;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTestContextBootstrapper} (in its own package so\n * we can test detection).\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@BootstrapWith(SpringBootTestContextBootstrapper.class)\nclass SpringBootTestContextBootstrapperIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Autowired\n\tprivate SpringBootTestContextBootstrapperExampleConfig config;\n\n\t@Test\n\tvoid findConfigAutomatically() {\n\t\tassertThat(this.config).isNotNull();\n\t}\n\n\t@Test\n\tvoid contextWasCreatedViaSpringApplication() {\n\t\tassertThat(this.context.getId()).startsWith(\"application\");\n\t}\n\n\t@Test\n\tvoid testConfigurationWasApplied() {\n\t\tassertThat(this.context.getBean(ExampleBean.class)).isNotNull();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tExampleBean exampleBean() {\n\t\t\treturn new ExampleBean();\n\t\t}\n\n\t}\n\n\tstatic class ExampleBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.bootstrap;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.test.context.BootstrapContext;\nimport org.springframework.test.context.CacheAwareContextLoaderDelegate;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpringBootTestContextBootstrapper}.\n *\n * @author Andy Wilkinson\n */\nclass SpringBootTestContextBootstrapperTests {\n\n\t@Test\n\tvoid springBootTestWithANonMockWebEnvironmentAndWebAppConfigurationFailsFast() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> buildTestContext(SpringBootTestNonMockWebEnvironmentAndWebAppConfiguration.class))\n\t\t\t.withMessageContaining(\"@WebAppConfiguration should only be used with \"\n\t\t\t\t\t+ \"@SpringBootTest when @SpringBootTest is configured with a mock web \"\n\t\t\t\t\t+ \"environment. Please remove @WebAppConfiguration or reconfigure @SpringBootTest.\");\n\t}\n\n\t@Test\n\tvoid springBootTestWithAMockWebEnvironmentCanBeUsedWithWebAppConfiguration() {\n\t\tbuildTestContext(SpringBootTestMockWebEnvironmentAndWebAppConfiguration.class);\n\t}\n\n\t@Test\n\tvoid mergedContextConfigurationWhenArgsDifferentShouldNotBeConsideredEqual() {\n\t\tTestContext context = buildTestContext(SpringBootTestArgsConfiguration.class);\n\t\tMergedContextConfiguration contextConfiguration = getMergedContextConfiguration(context);\n\t\tTestContext otherContext2 = buildTestContext(SpringBootTestOtherArgsConfiguration.class);\n\t\tMergedContextConfiguration otherContextConfiguration = getMergedContextConfiguration(otherContext2);\n\t\tassertThat(contextConfiguration).isNotEqualTo(otherContextConfiguration);\n\t}\n\n\t@Test\n\tvoid mergedContextConfigurationWhenArgsSameShouldBeConsideredEqual() {\n\t\tTestContext context = buildTestContext(SpringBootTestArgsConfiguration.class);\n\t\tMergedContextConfiguration contextConfiguration = getMergedContextConfiguration(context);\n\t\tTestContext otherContext2 = buildTestContext(SpringBootTestSameArgsConfiguration.class);\n\t\tMergedContextConfiguration otherContextConfiguration = getMergedContextConfiguration(otherContext2);\n\t\tassertThat(contextConfiguration).isEqualTo(otherContextConfiguration);\n\t}\n\n\t@Test\n\tvoid mergedContextConfigurationWhenWebEnvironmentsDifferentShouldNotBeConsideredEqual() {\n\t\tTestContext context = buildTestContext(SpringBootTestMockWebEnvironmentConfiguration.class);\n\t\tMergedContextConfiguration contextConfiguration = getMergedContextConfiguration(context);\n\t\tTestContext otherContext = buildTestContext(SpringBootTestDefinedPortWebEnvironmentConfiguration.class);\n\t\tMergedContextConfiguration otherContextConfiguration = getMergedContextConfiguration(otherContext);\n\t\tassertThat(contextConfiguration).isNotEqualTo(otherContextConfiguration);\n\t}\n\n\t@Test\n\tvoid mergedContextConfigurationWhenWebEnvironmentsSameShouldBeConsideredEqual() {\n\t\tTestContext context = buildTestContext(SpringBootTestMockWebEnvironmentConfiguration.class);\n\t\tMergedContextConfiguration contextConfiguration = getMergedContextConfiguration(context);\n\t\tTestContext otherContext = buildTestContext(SpringBootTestAnotherMockWebEnvironmentConfiguration.class);\n\t\tMergedContextConfiguration otherContextConfiguration = getMergedContextConfiguration(otherContext);\n\t\tassertThat(contextConfiguration).isEqualTo(otherContextConfiguration);\n\t}\n\n\t@Test\n\tvoid mergedContextConfigurationClassesShouldNotContainDuplicates() {\n\t\tTestContext context = buildTestContext(SpringBootTestClassesConfiguration.class);\n\t\tMergedContextConfiguration contextConfiguration = getMergedContextConfiguration(context);\n\t\tClass<?>[] classes = contextConfiguration.getClasses();\n\t\tassertThat(classes).containsExactly(SpringBootTestContextBootstrapperExampleConfig.class);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate TestContext buildTestContext(Class<?> testClass) {\n\t\tSpringBootTestContextBootstrapper bootstrapper = new SpringBootTestContextBootstrapper();\n\t\tBootstrapContext bootstrapContext = mock(BootstrapContext.class);\n\t\tbootstrapper.setBootstrapContext(bootstrapContext);\n\t\tgiven((Class) bootstrapContext.getTestClass()).willReturn(testClass);\n\t\tCacheAwareContextLoaderDelegate contextLoaderDelegate = mock(CacheAwareContextLoaderDelegate.class);\n\t\tgiven(bootstrapContext.getCacheAwareContextLoaderDelegate()).willReturn(contextLoaderDelegate);\n\t\treturn bootstrapper.buildTestContext();\n\t}\n\n\tprivate MergedContextConfiguration getMergedContextConfiguration(TestContext context) {\n\t\tMergedContextConfiguration mergedConfig = (MergedContextConfiguration) ReflectionTestUtils.getField(context,\n\t\t\t\t\"mergedConfig\");\n\t\tAssert.notNull(mergedConfig, context + \" had no MergedContextConfiguration\");\n\t\treturn mergedConfig;\n\t}\n\n\t@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n\t@WebAppConfiguration\n\tstatic class SpringBootTestNonMockWebEnvironmentAndWebAppConfiguration {\n\n\t}\n\n\t@SpringBootTest\n\t@WebAppConfiguration\n\tstatic class SpringBootTestMockWebEnvironmentAndWebAppConfiguration {\n\n\t}\n\n\t@SpringBootTest(args = \"--app.test=same\")\n\tstatic class SpringBootTestArgsConfiguration {\n\n\t}\n\n\t@SpringBootTest(webEnvironment = WebEnvironment.MOCK)\n\tstatic class SpringBootTestMockWebEnvironmentConfiguration {\n\n\t}\n\n\t@SpringBootTest(webEnvironment = WebEnvironment.MOCK)\n\tstatic class SpringBootTestAnotherMockWebEnvironmentConfiguration {\n\n\t}\n\n\t@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)\n\tstatic class SpringBootTestDefinedPortWebEnvironmentConfiguration {\n\n\t}\n\n\t@SpringBootTest(args = \"--app.test=same\")\n\tstatic class SpringBootTestSameArgsConfiguration {\n\n\t}\n\n\t@SpringBootTest(args = \"--app.test=different\")\n\tstatic class SpringBootTestOtherArgsConfiguration {\n\n\t}\n\n\t@SpringBootTest(classes = SpringBootTestContextBootstrapperExampleConfig.class)\n\tstatic class SpringBootTestClassesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperWithContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.bootstrap;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTestContextBootstrapper} + {@code @ContextConfiguration} (in\n * its own package so we can test detection).\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@BootstrapWith(SpringBootTestContextBootstrapper.class)\n@ContextConfiguration\nclass SpringBootTestContextBootstrapperWithContextConfigurationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Autowired\n\tprivate SpringBootTestContextBootstrapperExampleConfig config;\n\n\t@Test\n\tvoid findConfigAutomatically() {\n\t\tassertThat(this.config).isNotNull();\n\t}\n\n\t@Test\n\tvoid contextWasCreatedViaSpringApplication() {\n\t\tassertThat(this.context.getId()).startsWith(\"application\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/SpringBootTestContextBootstrapperWithInitializersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.bootstrap;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.boot.test.context.bootstrap.SpringBootTestContextBootstrapperWithInitializersTests.CustomInitializer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTestContextBootstrapper} with\n * {@link ApplicationContextInitializer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@BootstrapWith(SpringBootTestContextBootstrapper.class)\n@ContextConfiguration(initializers = CustomInitializer.class)\nclass SpringBootTestContextBootstrapperWithInitializersTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid foundConfiguration() {\n\t\tObject bean = this.context.getBean(SpringBootTestContextBootstrapperExampleConfig.class);\n\t\tassertThat(bean).isNotNull();\n\t}\n\n\t// gh-8483\n\n\tstatic class CustomInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/bootstrap/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.bootstrap;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/ExampleConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.example;\n\nimport org.springframework.boot.SpringBootConfiguration;\n\n/**\n * Example config used in {@code AnnotatedClassFinderTests}.\n *\n * @author Phillip Webb\n */\n@SpringBootConfiguration\npublic class ExampleConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/duplicate/first/EmptyConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.example.duplicate.first;\n\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Example configuration to showcase handing of duplicate class names.\n *\n * @author Stephane Nicoll\n */\n@Configuration\npublic class EmptyConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/duplicate/first/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.example.duplicate.first;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/duplicate/second/EmptyConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.example.duplicate.second;\n\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Example configuration to showcase handing of duplicate class names.\n *\n * @author Stephane Nicoll\n */\n@Configuration\npublic class EmptyConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/duplicate/second/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.example.duplicate.second;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.example;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/Example.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.example.scan;\n\n/**\n * Example class used in {@code AnnotatedClassFinderTests}.\n *\n * @author Phillip Webb\n */\npublic class Example {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.example.scan;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/SubExampleConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.example.scan.sub;\n\nimport org.springframework.boot.SpringBootConfiguration;\n\n/**\n * Example config used in {@code AnnotatedClassFinderTests}. Should not be found since\n * scanner should only search upwards.\n *\n * @author Phillip Webb\n */\n@SpringBootConfiguration\npublic class SubExampleConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/example/scan/sub/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.example.scan.sub;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/AbstractJupiterTestWithConfigAndExtendWith.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n@ExtendWith(SpringExtension.class)\npublic abstract class AbstractJupiterTestWithConfigAndExtendWith {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/AbstractJupiterTestWithConfigAndTestable.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.junit.platform.commons.annotation.Testable;\n\nimport org.springframework.context.annotation.Configuration;\n\n@Testable\npublic abstract class AbstractJupiterTestWithConfigAndTestable {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/AbstractTestNgTestWithConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.testng.annotations.Test;\n\nimport org.springframework.context.annotation.Configuration;\n\n@Test\npublic abstract class AbstractTestNgTestWithConfig {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/AbstractTestWithConfigAndRunWith.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Abstract test with nest {@code @Configuration} and {@code @RunWith} used by\n * {@link TestTypeExcludeFilter}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\npublic abstract class AbstractTestWithConfigAndRunWith {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/ExcludeFilterApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.FilterType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests {@link ExcludeFilterApplicationContextInitializer}.\n *\n * @author Phillip Webb\n */\nclass ExcludeFilterApplicationContextInitializerTests {\n\n\t@Test\n\tvoid testConfigurationIsExcluded() {\n\t\tSpringApplication application = new SpringApplication(TestApplication.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tAssertableApplicationContext applicationContext = AssertableApplicationContext.get(application::run);\n\t\tassertThat(applicationContext).hasSingleBean(TestApplication.class);\n\t\tassertThat(applicationContext).doesNotHaveBean(ExcludedTestConfiguration.class);\n\t}\n\n\t@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class) })\n\tstatic class TestApplication {\n\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class ExcludedTestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/JupiterRepeatedTestExample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.junit.jupiter.api.RepeatedTest;\n\nclass JupiterRepeatedTestExample {\n\n\t@RepeatedTest(5)\n\tvoid repeatedTest() {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/JupiterTestExample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.junit.jupiter.api.Test;\n\nclass JupiterTestExample {\n\n\t@Test\n\tvoid repeatedTest() {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/JupiterTestFactoryExample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.DynamicNode;\nimport org.junit.jupiter.api.DynamicTest;\nimport org.junit.jupiter.api.TestFactory;\n\nclass JupiterTestFactoryExample {\n\n\t@TestFactory\n\tCollection<DynamicNode> testFactory() {\n\t\treturn Arrays.asList(DynamicTest.dynamicTest(\"Some dynamic test\", () -> {\n\t\t\t// Test\n\t\t}));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/SampleConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class SampleConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/SampleTestConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport org.springframework.boot.test.context.TestComponent;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@TestComponent\npublic class SampleTestConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/TestTypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestTypeExcludeFilter}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass TestTypeExcludeFilterTests {\n\n\tprivate final TestTypeExcludeFilter filter = new TestTypeExcludeFilter();\n\n\tprivate final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\t@Test\n\tvoid matchesJUnit4TestClass() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(TestTypeExcludeFilterTests.class), this.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid matchesJUnitJupiterTestClass() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(JupiterTestExample.class), this.metadataReaderFactory)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesJUnitJupiterRepeatedTestClass() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(JupiterRepeatedTestExample.class), this.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid matchesJUnitJupiterTestFactoryClass() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(JupiterTestFactoryExample.class), this.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid matchesNestedConfiguration() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(NestedConfig.class), this.metadataReaderFactory)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesNestedConfigurationClassWithoutTestMethodsIfItHasRunWith() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(AbstractTestWithConfigAndRunWith.Config.class),\n\t\t\t\tthis.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid matchesNestedConfigurationClassWithoutTestMethodsIfItHasExtendWith() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(AbstractJupiterTestWithConfigAndExtendWith.Config.class),\n\t\t\t\tthis.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid matchesNestedConfigurationClassWithoutTestMethodsIfItHasTestable() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(AbstractJupiterTestWithConfigAndTestable.Config.class),\n\t\t\t\tthis.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid matchesTestConfiguration() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(SampleTestConfig.class), this.metadataReaderFactory)).isTrue();\n\t}\n\n\t@Test\n\tvoid doesNotMatchRegularConfiguration() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(SampleConfig.class), this.metadataReaderFactory)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesNestedConfigurationClassWithoutTestNgAnnotation() throws Exception {\n\t\tassertThat(this.filter.match(getMetadataReader(AbstractTestNgTestWithConfig.Config.class),\n\t\t\t\tthis.metadataReaderFactory))\n\t\t\t.isTrue();\n\t}\n\n\tprivate MetadataReader getMetadataReader(Class<?> source) throws IOException {\n\t\treturn this.metadataReaderFactory.getMetadataReader(source.getName());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NestedConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/annotation/FilterAnnotationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.io.IOException;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.core.type.filter.TypeFilter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FilterAnnotations}.\n *\n * @author Phillip Webb\n */\nclass FilterAnnotationsTests {\n\n\t@Test\n\tvoid filterAnnotation() throws Exception {\n\t\tFilterAnnotations filterAnnotations = get(FilterByAnnotation.class);\n\t\tassertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isTrue();\n\t\tassertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid filterAssignableType() throws Exception {\n\t\tFilterAnnotations filterAnnotations = get(FilterByType.class);\n\t\tassertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse();\n\t\tassertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid filterCustom() throws Exception {\n\t\tFilterAnnotations filterAnnotations = get(FilterByCustom.class);\n\t\tassertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse();\n\t\tassertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid filterAspectJ() throws Exception {\n\t\tFilterAnnotations filterAnnotations = get(FilterByAspectJ.class);\n\t\tassertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse();\n\t\tassertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid filterRegex() throws Exception {\n\t\tFilterAnnotations filterAnnotations = get(FilterByRegex.class);\n\t\tassertThat(match(filterAnnotations, ExampleWithAnnotation.class)).isFalse();\n\t\tassertThat(match(filterAnnotations, ExampleWithoutAnnotation.class)).isTrue();\n\t}\n\n\tprivate FilterAnnotations get(Class<?> type) {\n\t\tFilters filters = AnnotatedElementUtils.getMergedAnnotation(type, Filters.class);\n\t\tassertThat(filters).isNotNull();\n\t\treturn new FilterAnnotations(getClass().getClassLoader(), filters.value());\n\t}\n\n\tprivate boolean match(FilterAnnotations filterAnnotations, Class<?> type) throws IOException {\n\t\tMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\t\tMetadataReader metadataReader = metadataReaderFactory.getMetadataReader(type.getName());\n\t\treturn filterAnnotations.anyMatches(metadataReader, metadataReaderFactory);\n\t}\n\n\t@Filters(@Filter(Service.class))\n\tstatic class FilterByAnnotation {\n\n\t}\n\n\t@Filters(@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = ExampleWithoutAnnotation.class))\n\tstatic class FilterByType {\n\n\t}\n\n\t@Filters(@Filter(type = FilterType.CUSTOM, classes = ExampleCustomFilter.class))\n\tstatic class FilterByCustom {\n\n\t}\n\n\t@Filters(@Filter(type = FilterType.ASPECTJ, pattern = \"(*..*ExampleWithoutAnnotation)\"))\n\tstatic class FilterByAspectJ {\n\n\t}\n\n\t@Filters(@Filter(type = FilterType.REGEX, pattern = \".*ExampleWithoutAnnotation\"))\n\tstatic class FilterByRegex {\n\n\t}\n\n\t@Target({ ElementType.TYPE })\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@interface Filters {\n\n\t\tFilter[] value();\n\n\t}\n\n\tstatic class ExampleCustomFilter implements TypeFilter {\n\n\t\t@Override\n\t\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {\n\t\t\treturn metadataReader.getClassMetadata().getClassName().equals(ExampleWithoutAnnotation.class.getName());\n\t\t}\n\n\t}\n\n\t@Service\n\tstatic class ExampleWithAnnotation {\n\n\t}\n\n\tstatic class ExampleWithoutAnnotation {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/annotation/TypeExcludeFiltersContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFiltersContextCustomizerFactoryTests.EnclosingClass.WithEnclosingClassExcludeFilters;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TypeExcludeFiltersContextCustomizerFactory}.\n *\n * @author Phillip Webb\n */\nclass TypeExcludeFiltersContextCustomizerFactoryTests {\n\n\tprivate final TypeExcludeFiltersContextCustomizerFactory factory = new TypeExcludeFiltersContextCustomizerFactory();\n\n\tprivate final MergedContextConfiguration mergedContextConfiguration = mock(MergedContextConfiguration.class);\n\n\tprivate final ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@Test\n\tvoid getContextCustomizerWhenHasNoAnnotationShouldReturnNull() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(NoAnnotation.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasAnnotationShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(WithExcludeFilters.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenEnclosingClassHasAnnotationShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(WithEnclosingClassExcludeFilters.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tContextCustomizer customizer1 = this.factory.createContextCustomizer(WithExcludeFilters.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer2 = this.factory.createContextCustomizer(WithSameExcludeFilters.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer3 = this.factory.createContextCustomizer(WithDifferentExcludeFilters.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t\tassertThat(customizer1).isEqualTo(customizer1).isEqualTo(customizer2).isNotEqualTo(customizer3);\n\t}\n\n\t@Test\n\tvoid getContextCustomizerShouldAddExcludeFilters() throws Exception {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(WithExcludeFilters.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tcustomizer.customizeContext(this.context, this.mergedContextConfiguration);\n\t\tthis.context.refresh();\n\t\tTypeExcludeFilter filter = this.context.getBean(TypeExcludeFilter.class);\n\t\tMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\t\tMetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NoAnnotation.class.getName());\n\t\tassertThat(filter.match(metadataReader, metadataReaderFactory)).isFalse();\n\t\tmetadataReader = metadataReaderFactory.getMetadataReader(SimpleExclude.class.getName());\n\t\tassertThat(filter.match(metadataReader, metadataReaderFactory)).isTrue();\n\t\tmetadataReader = metadataReaderFactory.getMetadataReader(TestClassAwareExclude.class.getName());\n\t\tassertThat(filter.match(metadataReader, metadataReaderFactory)).isTrue();\n\t}\n\n\tstatic class NoAnnotation {\n\n\t}\n\n\t@TypeExcludeFilters({ SimpleExclude.class, TestClassAwareExclude.class })\n\tstatic class WithExcludeFilters {\n\n\t}\n\n\t@TypeExcludeFilters({ SimpleExclude.class, TestClassAwareExclude.class })\n\tstatic class EnclosingClass {\n\n\t\tclass WithEnclosingClassExcludeFilters {\n\n\t\t}\n\n\t}\n\n\t@TypeExcludeFilters({ TestClassAwareExclude.class, SimpleExclude.class })\n\tstatic class WithSameExcludeFilters {\n\n\t}\n\n\t@TypeExcludeFilters(SimpleExclude.class)\n\tstatic class WithDifferentExcludeFilters {\n\n\t}\n\n\tstatic class SimpleExclude extends TypeExcludeFilter {\n\n\t\t@Override\n\t\tpublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {\n\t\t\treturn metadataReader.getClassMetadata().getClassName().equals(getClass().getName());\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object obj) {\n\t\t\treturn obj != null && obj.getClass() == getClass();\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn SimpleExclude.class.hashCode();\n\t\t}\n\n\t}\n\n\tstatic class TestClassAwareExclude extends SimpleExclude {\n\n\t\tTestClassAwareExclude(Class<?> testClass) {\n\t\t\tassertThat(testClass).isNotNull();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/filter/annotation/TypeIncludesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.filter.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TypeIncludes}.\n *\n * @author Moritz Halbritter\n */\nclass TypeIncludesTests {\n\n\tprivate static final String IMPORTS_FILE = \"META-INF/spring/org.springframework.boot.test.context.filter.annotation.TypeIncludesTests$TestAnnotation.includes\";\n\n\t@Test\n\t@WithResource(name = IMPORTS_FILE, content = \"\"\"\n\t\t\torg.springframework.boot.test.context.filter.annotation.TypeIncludesTests\n\t\t\torg.springframework.boot.test.context.filter.annotation.DoesNotExist\n\t\t\t\"\"\")\n\tvoid loadReadsFromClasspathFileIgnoringNonExistentIncludes() {\n\t\tTypeIncludes candidates = TypeIncludes.load(TestAnnotation.class,\n\t\t\t\tThread.currentThread().getContextClassLoader());\n\t\tassertThat(candidates).containsExactly(TypeIncludesTests.class);\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\tpublic @interface TestAnnotation {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/nestedtests/InheritedNestedTestConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.nestedtests;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.nestedtests.InheritedNestedTestConfigurationTests.ActionPerformer;\nimport org.springframework.boot.test.context.nestedtests.InheritedNestedTestConfigurationTests.AppConfiguration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.stereotype.Component;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for nested test configuration when the configuration is inherited from the\n * enclosing class (the default behaviour).\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(classes = AppConfiguration.class)\n@Import(ActionPerformer.class)\nclass InheritedNestedTestConfigurationTests {\n\n\t@MockitoBean\n\tAction action;\n\n\t@Autowired\n\tActionPerformer performer;\n\n\t@Test\n\tvoid mockWasInvokedOnce() {\n\t\tthis.performer.run();\n\t\tthen(this.action).should().perform();\n\t}\n\n\t@Test\n\tvoid mockWasInvokedTwice() {\n\t\tthis.performer.run();\n\t\tthis.performer.run();\n\t\tthen(this.action).should(times(2)).perform();\n\t}\n\n\t@Nested\n\tclass InnerTests {\n\n\t\t@Test\n\t\tvoid mockWasInvokedOnce() {\n\t\t\tInheritedNestedTestConfigurationTests.this.performer.run();\n\t\t\tthen(InheritedNestedTestConfigurationTests.this.action).should().perform();\n\t\t}\n\n\t\t@Test\n\t\tvoid mockWasInvokedTwice() {\n\t\t\tInheritedNestedTestConfigurationTests.this.performer.run();\n\t\t\tInheritedNestedTestConfigurationTests.this.performer.run();\n\t\t\tthen(InheritedNestedTestConfigurationTests.this.action).should(times(2)).perform();\n\t\t}\n\n\t}\n\n\t@Component\n\tstatic class ActionPerformer {\n\n\t\tprivate final Action action;\n\n\t\tActionPerformer(Action action) {\n\t\t\tthis.action = action;\n\t\t}\n\n\t\tvoid run() {\n\t\t\tthis.action.perform();\n\t\t}\n\n\t}\n\n\tpublic interface Action {\n\n\t\tvoid perform();\n\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class AppConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/nestedtests/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.context.nestedtests;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport com.google.gson.Gson;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.beans.factory.BeanDefinitionStoreException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.support.BeanDefinitionOverrideException;\nimport org.springframework.boot.context.annotation.Configurations;\nimport org.springframework.boot.context.annotation.UserConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Abstract tests for {@link AbstractApplicationContextRunner} implementations.\n *\n * @param <T> The runner type\n * @param <C> the context type\n * @param <A> the assertable context type\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nabstract class AbstractApplicationContextRunnerTests<T extends AbstractApplicationContextRunner<T, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> {\n\n\t@Test\n\tvoid runWithInitializerShouldInitialize() {\n\t\tAtomicBoolean called = new AtomicBoolean();\n\t\tget().withInitializer((context) -> called.set(true)).run((context) -> {\n\t\t});\n\t\tassertThat(called).isTrue();\n\t}\n\n\t@Test\n\tvoid runWithSystemPropertiesShouldSetAndRemoveProperties() {\n\t\tString key = \"test.\" + UUID.randomUUID();\n\t\tassertThat(System.getProperties()).doesNotContainKey(key);\n\t\tget().withSystemProperties(key + \"=value\")\n\t\t\t.run((context) -> assertThat(System.getProperties()).containsEntry(key, \"value\"));\n\t\tassertThat(System.getProperties()).doesNotContainKey(key);\n\t}\n\n\t@Test\n\tvoid runWithSystemPropertiesWhenContextFailsShouldRemoveProperties() {\n\t\tString key = \"test.\" + UUID.randomUUID();\n\t\tassertThat(System.getProperties()).doesNotContainKey(key);\n\t\tget().withSystemProperties(key + \"=value\")\n\t\t\t.withUserConfiguration(FailingConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t\tassertThat(System.getProperties()).doesNotContainKey(key);\n\t}\n\n\t@Test\n\tvoid runWithSystemPropertiesShouldRestoreOriginalProperties() {\n\t\tString key = \"test.\" + UUID.randomUUID();\n\t\tSystem.setProperty(key, \"value\");\n\t\ttry {\n\t\t\tassertThat(System.getProperties().getProperty(key)).isEqualTo(\"value\");\n\t\t\tget().withSystemProperties(key + \"=newValue\")\n\t\t\t\t.run((context) -> assertThat(System.getProperties()).containsEntry(key, \"newValue\"));\n\t\t\tassertThat(System.getProperties().getProperty(key)).isEqualTo(\"value\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(key);\n\t\t}\n\t}\n\n\t@Test\n\tvoid runWithSystemPropertiesWhenValueIsNullShouldRemoveProperty() {\n\t\tString key = \"test.\" + UUID.randomUUID();\n\t\tSystem.setProperty(key, \"value\");\n\t\ttry {\n\t\t\tassertThat(System.getProperties().getProperty(key)).isEqualTo(\"value\");\n\t\t\tget().withSystemProperties(key + \"=\")\n\t\t\t\t.run((context) -> assertThat(System.getProperties()).doesNotContainKey(key));\n\t\t\tassertThat(System.getProperties().getProperty(key)).isEqualTo(\"value\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(key);\n\t\t}\n\t}\n\n\t@Test\n\tvoid runWithMultiplePropertyValuesShouldAllAllValues() {\n\t\tget().withPropertyValues(\"test.foo=1\").withPropertyValues(\"test.bar=2\").run((context) -> {\n\t\t\tEnvironment environment = context.getEnvironment();\n\t\t\tassertThat(environment.getProperty(\"test.foo\")).isEqualTo(\"1\");\n\t\t\tassertThat(environment.getProperty(\"test.bar\")).isEqualTo(\"2\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWithPropertyValuesWhenHasExistingShouldReplaceValue() {\n\t\tget().withPropertyValues(\"test.foo=1\").withPropertyValues(\"test.foo=2\").run((context) -> {\n\t\t\tEnvironment environment = context.getEnvironment();\n\t\t\tassertThat(environment.getProperty(\"test.foo\")).isEqualTo(\"2\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWithConfigurationsShouldRegisterConfigurations() {\n\t\tget().withUserConfiguration(FooConfig.class).run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid runWithUserConfigurationsRegistersDefaultBeanName() {\n\t\tget().withUserConfiguration(FooConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"abstractApplicationContextRunnerTests.FooConfig\"));\n\t}\n\n\t@Test\n\tvoid runWithUserConfigurationsWhenHasSameShortClassNamedRegistersWithoutBeanName() {\n\t\tget()\n\t\t\t.withUserConfiguration(org.springframework.boot.test.context.example.duplicate.first.EmptyConfig.class,\n\t\t\t\t\torg.springframework.boot.test.context.example.duplicate.second.EmptyConfig.class)\n\t\t\t.run((context) -> assertThat(context.getStartupFailure())\n\t\t\t\t.isInstanceOf(BeanDefinitionOverrideException.class));\n\t}\n\n\t@Test\n\tvoid runFullyQualifiedNameConfigurationsRegistersFullyQualifiedBeanName() {\n\t\tget().withConfiguration(FullyQualifiedNameConfigurations.of(FooConfig.class))\n\t\t\t.run((context) -> assertThat(context).hasBean(FooConfig.class.getName()));\n\t}\n\n\t@Test\n\tvoid runWithFullyQualifiedNameConfigurationsWhenHasSameShortClassNamedRegistersWithFullyQualifiedBeanName() {\n\t\tget()\n\t\t\t.withConfiguration(FullyQualifiedNameConfigurations.of(\n\t\t\t\t\torg.springframework.boot.test.context.example.duplicate.first.EmptyConfig.class,\n\t\t\t\t\torg.springframework.boot.test.context.example.duplicate.second.EmptyConfig.class))\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasSingleBean(org.springframework.boot.test.context.example.duplicate.first.EmptyConfig.class)\n\t\t\t\t.hasSingleBean(org.springframework.boot.test.context.example.duplicate.second.EmptyConfig.class));\n\t}\n\n\t@Test\n\tvoid runWithUserNamedBeanShouldRegisterBean() {\n\t\tget().withBean(\"foo\", String.class, () -> \"foo\").run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid runWithUserBeanShouldRegisterBeanWithDefaultName() {\n\t\tget().withBean(String.class, () -> \"foo\").run((context) -> assertThat(context).hasBean(\"string\"));\n\t}\n\n\t@Test\n\tvoid runWithMultipleConfigurationsShouldRegisterAllConfigurations() {\n\t\tget().withUserConfiguration(FooConfig.class)\n\t\t\t.withConfiguration(UserConfigurations.of(BarConfig.class))\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\").hasBean(\"bar\"));\n\t}\n\n\t@Test\n\tvoid runWithFailedContextShouldReturnFailedAssertableContext() {\n\t\tget().withUserConfiguration(FailingConfig.class).run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid runWithClassLoaderShouldSetClassLoaderOnContext() {\n\t\tget().withClassLoader(new FilteredClassLoader(Gson.class.getPackage().getName()))\n\t\t\t.run((context) -> assertThatExceptionOfType(ClassNotFoundException.class)\n\t\t\t\t.isThrownBy(() -> ClassUtils.forName(Gson.class.getName(), context.getClassLoader())));\n\t}\n\n\t@Test\n\tvoid runWithClassLoaderShouldSetClassLoaderOnConditionContext() {\n\t\tget().withClassLoader(new FilteredClassLoader(Gson.class.getPackage().getName()))\n\t\t\t.withUserConfiguration(ConditionalConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConditionalConfig.class));\n\t}\n\n\t@Test\n\tvoid consecutiveRunWithFilteredClassLoaderShouldHaveBeanWithLazyProperties() {\n\t\tget().withClassLoader(new FilteredClassLoader(Gson.class))\n\t\t\t.withUserConfiguration(LazyConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ExampleBeanWithLazyProperties.class));\n\n\t\tget().withClassLoader(new FilteredClassLoader(Gson.class))\n\t\t\t.withUserConfiguration(LazyConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ExampleBeanWithLazyProperties.class));\n\t}\n\n\t@Test\n\tvoid thrownRuleWorksWithCheckedException() {\n\t\tget().run((context) -> assertThatIOException().isThrownBy(() -> throwCheckedException(\"Expected message\"))\n\t\t\t.withMessageContaining(\"Expected message\"));\n\t}\n\n\t@Test\n\tvoid runDisablesBeanOverridingByDefault() {\n\t\tget().withUserConfiguration(FooConfig.class).withBean(\"foo\", Integer.class, () -> 42).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(BeanDefinitionStoreException.class)\n\t\t\t\t.hasMessageContaining(\"Invalid bean definition with name 'foo'\")\n\t\t\t\t.hasMessageContaining(\"@Bean definition illegally overridden by existing bean definition\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runDisablesCircularReferencesByDefault() {\n\t\tget().withUserConfiguration(ExampleConsumerConfiguration.class, ExampleProducerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(BeanCurrentlyInCreationException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid circularReferencesCanBeAllowed() {\n\t\tget().withAllowCircularReferences(true)\n\t\t\t.withUserConfiguration(ExampleConsumerConfiguration.class, ExampleProducerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid runWithUserBeanShouldBeRegisteredInOrder() {\n\t\tget().withAllowBeanDefinitionOverriding(true)\n\t\t\t.withBean(String.class, () -> \"one\")\n\t\t\t.withBean(String.class, () -> \"two\")\n\t\t\t.withBean(String.class, () -> \"three\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"string\");\n\t\t\t\tassertThat(context.getBean(\"string\")).isEqualTo(\"three\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithConfigurationsAndUserBeanShouldRegisterUserBeanLast() {\n\t\tget().withAllowBeanDefinitionOverriding(true)\n\t\t\t.withUserConfiguration(FooConfig.class)\n\t\t\t.withBean(\"foo\", String.class, () -> \"overridden\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"foo\");\n\t\t\t\tassertThat(context.getBean(\"foo\")).isEqualTo(\"overridden\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid changesMadeByInitializersShouldBeVisibleToRegisteredClasses() {\n\t\tget().withInitializer((context) -> context.getEnvironment().setActiveProfiles(\"test\"))\n\t\t\t.withUserConfiguration(ProfileConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ProfileConfig.class));\n\t}\n\n\t@Test\n\tvoid prepareDoesNotRefreshContext() {\n\t\tget().withUserConfiguration(FooConfig.class).prepare((context) -> {\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> context.getBean(String.class))\n\t\t\t\t.withMessageContaining(\"not been refreshed\");\n\t\t\tcontext.getSourceApplicationContext().refresh();\n\t\t\tassertThat(context.getBean(String.class)).isEqualTo(\"foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid getWithAdditionalContextInterfaceHasCorrectInstanceOf() {\n\t\tgetWithAdditionalContextInterface()\n\t\t\t.run((context) -> assertThat(context).isInstanceOf(AdditionalContextInterface.class));\n\t}\n\n\tprotected abstract T get();\n\n\tprotected abstract T getWithAdditionalContextInterface();\n\n\tprivate static void throwCheckedException(String message) throws IOException {\n\t\tthrow new IOException(message);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FailingConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\tthrow new IllegalStateException(\"Failed\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FooConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BarConfig {\n\n\t\t@Bean\n\t\tString bar() {\n\t\t\treturn \"bar\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(FilteredClassLoaderCondition.class)\n\tstatic class ConditionalConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ExampleProperties.class)\n\tstatic class LazyConfig {\n\n\t\t@Bean\n\t\tExampleBeanWithLazyProperties exampleBeanWithLazyProperties() {\n\t\t\treturn new ExampleBeanWithLazyProperties();\n\t\t}\n\n\t}\n\n\tstatic class ExampleBeanWithLazyProperties {\n\n\t\t@Autowired\n\t\t@Lazy\n\t\tExampleProperties exampleProperties;\n\n\t}\n\n\t@ConfigurationProperties\n\tpublic static class ExampleProperties {\n\n\t}\n\n\tstatic class FilteredClassLoaderCondition implements Condition {\n\n\t\t@Override\n\t\tpublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\treturn context.getClassLoader() instanceof FilteredClassLoader;\n\t\t}\n\n\t}\n\n\tstatic class Example {\n\n\t}\n\n\t@FunctionalInterface\n\tinterface ExampleConfigurer {\n\n\t\tvoid configure(Example example);\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleProducerConfiguration {\n\n\t\t@Bean\n\t\tExample example(ObjectProvider<ExampleConfigurer> configurers) {\n\t\t\tExample example = new Example();\n\t\t\tconfigurers.orderedStream().forEach((configurer) -> configurer.configure(example));\n\t\t\treturn example;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleConsumerConfiguration {\n\n\t\t@Autowired\n\t\tExample example;\n\n\t\t@Bean\n\t\tExampleConfigurer configurer() {\n\t\t\treturn (example) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Profile(\"test\")\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ProfileConfig {\n\n\t}\n\n\tstatic class FullyQualifiedNameConfigurations extends Configurations {\n\n\t\tprotected FullyQualifiedNameConfigurations(Collection<Class<?>> classes) {\n\t\t\tsuper(null, classes, Class::getName);\n\t\t}\n\n\t\t@Override\n\t\tprotected Configurations merge(Set<Class<?>> mergedClasses) {\n\t\t\treturn new FullyQualifiedNameConfigurations(mergedClasses);\n\t\t}\n\n\t\tstatic FullyQualifiedNameConfigurations of(Class<?>... classes) {\n\t\t\treturn new FullyQualifiedNameConfigurations(List.of(classes));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AdditionalContextInterface.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Tests extra interface that can be applied to an {@link ApplicationContext}\n *\n * @author Phillip Webb\n */\ninterface AdditionalContextInterface {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ApplicationContextRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\n/**\n * Tests for {@link ApplicationContextRunner}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ApplicationContextRunnerTests extends\n\t\tAbstractApplicationContextRunnerTests<ApplicationContextRunner, ConfigurableApplicationContext, AssertableApplicationContext> {\n\n\t@Override\n\tprotected ApplicationContextRunner get() {\n\t\treturn new ApplicationContextRunner();\n\t}\n\n\t@Override\n\tprotected ApplicationContextRunner getWithAdditionalContextInterface() {\n\t\treturn new ApplicationContextRunner(TestAnnotationConfigApplicationContext::new,\n\t\t\t\tAdditionalContextInterface.class);\n\t}\n\n\tstatic class TestAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext\n\t\t\timplements AdditionalContextInterface {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ContextConsumerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport java.util.function.IntPredicate;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ContextConsumer}.\n *\n * @author Stephane Nicoll\n */\nclass ContextConsumerTests {\n\n\t@Test\n\tvoid andThenInvokeInOrder() throws Throwable {\n\t\tIntPredicate predicate = mock(IntPredicate.class);\n\t\tgiven(predicate.test(42)).willReturn(true);\n\t\tgiven(predicate.test(24)).willReturn(false);\n\t\tContextConsumer<ApplicationContext> firstConsumer = (context) -> assertThat(predicate.test(42)).isTrue();\n\t\tContextConsumer<ApplicationContext> secondConsumer = (context) -> assertThat(predicate.test(24)).isFalse();\n\t\tfirstConsumer.andThen(secondConsumer).accept(mock(ApplicationContext.class));\n\t\tInOrder ordered = inOrder(predicate);\n\t\tordered.verify(predicate).test(42);\n\t\tordered.verify(predicate).test(24);\n\t\tordered.verifyNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid andThenNoInvokedIfThisFails() {\n\t\tIntPredicate predicate = mock(IntPredicate.class);\n\t\tgiven(predicate.test(42)).willReturn(true);\n\t\tgiven(predicate.test(24)).willReturn(false);\n\t\tContextConsumer<ApplicationContext> firstConsumer = (context) -> assertThat(predicate.test(42)).isFalse();\n\t\tContextConsumer<ApplicationContext> secondConsumer = (context) -> assertThat(predicate.test(24)).isFalse();\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> firstConsumer.andThen(secondConsumer).accept(mock(ApplicationContext.class)));\n\t\tthen(predicate).should().test(42);\n\t\tthen(predicate).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid andThenWithNull() {\n\t\tContextConsumer<?> consumer = (context) -> {\n\t\t};\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> consumer.andThen(null))\n\t\t\t.withMessage(\"'after' must not be null\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.reactive.AnnotationConfigReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;\n\n/**\n * Tests for {@link ReactiveWebApplicationContextRunner}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ReactiveWebApplicationContextRunnerTests extends\n\t\tAbstractApplicationContextRunnerTests<ReactiveWebApplicationContextRunner, ConfigurableReactiveWebApplicationContext, AssertableReactiveWebApplicationContext> {\n\n\t@Override\n\tprotected ReactiveWebApplicationContextRunner get() {\n\t\treturn new ReactiveWebApplicationContextRunner();\n\t}\n\n\t@Override\n\tprotected ReactiveWebApplicationContextRunner getWithAdditionalContextInterface() {\n\t\treturn new ReactiveWebApplicationContextRunner(TestAnnotationConfigReactiveWebApplicationContext::new,\n\t\t\t\tAdditionalContextInterface.class);\n\t}\n\n\tstatic class TestAnnotationConfigReactiveWebApplicationContext extends AnnotationConfigReactiveWebApplicationContext\n\t\t\timplements AdditionalContextInterface {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/WebApplicationContextRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context.runner;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebApplicationContextRunner}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass WebApplicationContextRunnerTests extends\n\t\tAbstractApplicationContextRunnerTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {\n\n\t@Test\n\tvoid contextShouldHaveMockServletContext() {\n\t\tget().run((context) -> assertThat(context.getServletContext()).isInstanceOf(MockServletContext.class));\n\t}\n\n\t@Override\n\tprotected WebApplicationContextRunner get() {\n\t\treturn new WebApplicationContextRunner();\n\t}\n\n\t@Override\n\tprotected WebApplicationContextRunner getWithAdditionalContextInterface() {\n\t\treturn new WebApplicationContextRunner(TestAnnotationConfigServletWebApplicationContext::new,\n\t\t\t\tAdditionalContextInterface.class);\n\t}\n\n\tstatic class TestAnnotationConfigServletWebApplicationContext extends AnnotationConfigServletWebApplicationContext\n\t\t\timplements AdditionalContextInterface {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/http/client/DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.http.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory}.\n *\n * @author Phillip Webb\n */\n@SpringJUnitConfig\nclass DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactoryTests {\n\n\t@Autowired\n\tprivate ReactorResourceFactory reactorResourceFactory;\n\n\t@Test\n\tvoid disablesUseGlobalResources() {\n\t\tassertThat(this.reactorResourceFactory.isUseGlobalResources()).isFalse();\n\t}\n\n\t@Configuration\n\tstatic class Config {\n\n\t\t@Bean\n\t\tReactorResourceFactory reactorResourceFactory() {\n\t\t\treturn new ReactorResourceFactory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/LocalTestWebServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.http.server;\n\nimport java.net.URI;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.http.server.LocalTestWebServer.BaseUriDetails;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.web.util.UriBuilder;\nimport org.springframework.web.util.UriBuilderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link LocalTestWebServer}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass LocalTestWebServerTests {\n\n\tprivate final LocalTestWebServer server = LocalTestWebServer.of(Scheme.HTTPS, 8080, \"\");\n\n\t@Test\n\tvoid schemeWhenHttpsSchemeReturnsHttpsScheme() {\n\t\tassertThat(LocalTestWebServer.of(Scheme.HTTPS, 8080, \"\").scheme()).isEqualTo(Scheme.HTTPS);\n\t}\n\n\t@Test\n\tvoid schemeWhenHttpSchemeReturnsHttpScheme() {\n\t\tassertThat(LocalTestWebServer.of(Scheme.HTTP, 8080, \"\").scheme()).isEqualTo(Scheme.HTTP);\n\t}\n\n\t@Test\n\tvoid uriBuilderWhenHasSlashUriUsesLocalServer() {\n\t\tUriBuilder builder = this.server.uriBuilder(\"/\");\n\t\tassertThat(builder.toUriString()).isEqualTo(\"https://localhost:8080/\");\n\t}\n\n\t@Test\n\tvoid uriBuilderWhenHasEmptyUriUsesLocalServer() {\n\t\tUriBuilder builder = this.server.uriBuilder(\"\");\n\t\tassertThat(builder.toUriString()).isEqualTo(\"https://localhost:8080\");\n\t}\n\n\t@Test\n\tvoid uriBuilderWhenHasNestedPathUsesLocalServer() {\n\t\tUriBuilder builder = this.server.uriBuilder(\"/foo/bar\");\n\t\tassertThat(builder.toUriString()).isEqualTo(\"https://localhost:8080/foo/bar\");\n\t}\n\n\t@Test\n\tvoid uriBuilderWhenHasPathNoStartingWithSlashUsesLocalServer() {\n\t\tUriBuilder builder = this.server.uriBuilder(\"foo/bar\");\n\t\tassertThat(builder.toUriString()).isEqualTo(\"https://localhost:8080/foo/bar\");\n\t}\n\n\t@Test\n\tvoid uriBuilderWhenHasFullUriDoesNotUseLocalServer() {\n\t\tUriBuilder builder = this.server.uriBuilder(\"https://sub.example.com\");\n\t\tassertThat(builder.toUriString()).isEqualTo(\"https://sub.example.com\");\n\t}\n\n\t@Test\n\tvoid uriBuilderFactoryExpandWithMap() {\n\t\tUriBuilderFactory factory = this.server.uriBuilderFactory();\n\t\tassertThat(factory.expand(\"/test/{name}\", Map.of(\"name\", \"value\")))\n\t\t\t.isEqualTo(URI.create(\"https://localhost:8080/test/value\"));\n\t}\n\n\t@Test\n\tvoid uriBuilderFactoryExpandsWithMap() {\n\t\tUriBuilderFactory factory = this.server.uriBuilderFactory();\n\t\tassertThat(factory.expand(\"/test/{name}\", \"value\")).isEqualTo(URI.create(\"https://localhost:8080/test/value\"));\n\t}\n\n\t@Test\n\tvoid uriBuilderFactoryExpandsWithVariables() {\n\t\tUriBuilderFactory factory = this.server.uriBuilderFactory();\n\t\tassertThat(factory.uriString(\"https://example.com\").build()).isEqualTo(URI.create(\"https://example.com\"));\n\t}\n\n\t@Test\n\tvoid uriWhenHttp() {\n\t\tassertThat(LocalTestWebServer.of(Scheme.HTTP, 8080, \"\").uri()).isEqualTo(\"http://localhost:8080\");\n\t}\n\n\t@Test\n\tvoid uriWhenHttps() {\n\t\tassertThat(LocalTestWebServer.of(Scheme.HTTPS, 4343, \"\").uri()).isEqualTo(\"https://localhost:4343\");\n\t}\n\n\t@Test\n\tvoid uriWhenHasPath() {\n\t\tassertThat(LocalTestWebServer.of(Scheme.HTTPS, 8080, \"/path\").uri()).isEqualTo(\"https://localhost:8080/path\");\n\t}\n\n\t@Test\n\tvoid uriWithUri() {\n\t\tassertThat(this.server.uri(null)).isEqualTo(\"https://localhost:8080\");\n\t\tassertThat(this.server.uri(\"\")).isEqualTo(\"https://localhost:8080\");\n\t\tassertThat(this.server.uri(\"/\")).isEqualTo(\"https://localhost:8080/\");\n\t\tassertThat(this.server.uri(\"/foo\")).isEqualTo(\"https://localhost:8080/foo\");\n\t\tassertThat(this.server.uri(\"https://example.com/foo\")).isEqualTo(\"https://example.com/foo\");\n\t}\n\n\t@Test\n\tvoid uriUsesSingletonBaseUriDetails() {\n\t\tAtomicInteger counter = new AtomicInteger();\n\t\tLocalTestWebServer server = LocalTestWebServer.of(Scheme.HTTPS,\n\t\t\t\t() -> new BaseUriDetails(8080, \"/\" + counter.incrementAndGet()));\n\t\tassertThat(server.uri()).isEqualTo(\"https://localhost:8080/1\");\n\t\tassertThat(server.uri()).isEqualTo(\"https://localhost:8080/1\");\n\t}\n\n\t@Test\n\tvoid uriBuilderFactoryUsesSingletonUriBuilderFactory() {\n\t\tLocalTestWebServer server = LocalTestWebServer.of(Scheme.HTTPS, () -> new BaseUriDetails(8080, \"/\"));\n\t\tUriBuilderFactory uriBuilderFactory = server.uriBuilderFactory();\n\t\tassertThat(server.uriBuilderFactory()).isSameAs(uriBuilderFactory);\n\t}\n\n\t@Test\n\tvoid withPathCreatedNewInstance() {\n\t\tassertThat(LocalTestWebServer.of(Scheme.HTTPS, 8080, \"/path\").withPath(\"/other\").uri())\n\t\t\t.isEqualTo(\"https://localhost:8080/path/other\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenBaseUriDetailsSupplierIsNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> LocalTestWebServer.of(Scheme.HTTPS, null))\n\t\t\t.withMessage(\"'baseUriDetailsSupplier' must not be null\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServerTests$Provider1,\\\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServerTests$Provider2,\\\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServerTests$Provider3\n\t\t\t\"\"\")\n\tvoid getReturnsFirstProvided() {\n\t\tApplicationContext applicationContext = new GenericApplicationContext();\n\t\tLocalTestWebServer provided = LocalTestWebServer.get(applicationContext);\n\t\tassertThat(provided).isNotNull();\n\t\tassertThat(provided.uri()).isEqualTo(\"https://localhost:7070/p2\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServerTests$Provider1\n\t\t\t\"\"\")\n\tvoid getWhenNoneReturnsNull() {\n\t\tApplicationContext applicationContext = new GenericApplicationContext();\n\t\tLocalTestWebServer provided = LocalTestWebServer.get(applicationContext);\n\t\tassertThat(provided).isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\", content = \"\"\"\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\torg.springframework.boot.test.http.server.LocalTestWebServerTests$Provider1\n\t\t\t\"\"\")\n\tvoid obtainWhenNoneProvidedThrowsException() {\n\t\tApplicationContext applicationContext = new GenericApplicationContext();\n\t\tassertThatIllegalStateException().isThrownBy(() -> LocalTestWebServer.obtain(applicationContext))\n\t\t\t.withMessage(\"No local test web server available\");\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class Provider1 implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class Provider2 implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\treturn LocalTestWebServer.of(Scheme.HTTPS, 7070, \"/p2\");\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class Provider3 implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/AbstractJsonMarshalTesterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.lang.reflect.Field;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AbstractJsonMarshalTester}.\n *\n * @author Phillip Webb\n */\nabstract class AbstractJsonMarshalTesterTests {\n\n\tprivate static final String JSON = \"{\\\"name\\\":\\\"Spring\\\",\\\"age\\\":123}\";\n\n\tprivate static final String MAP_JSON = \"{\\\"a\\\":\" + JSON + \"}\";\n\n\tprivate static final String ARRAY_JSON = \"[\" + JSON + \"]\";\n\n\tprivate static final ExampleObject OBJECT = createExampleObject(\"Spring\", 123);\n\n\tprivate static final ResolvableType TYPE = ResolvableType.forClass(ExampleObject.class);\n\n\t@Test\n\tvoid writeShouldReturnJsonContent() throws Exception {\n\t\tJsonContent<Object> content = createTester(TYPE).write(OBJECT);\n\t\tassertThat(content).isEqualToJson(JSON);\n\t}\n\n\t@Test\n\tvoid writeListShouldReturnJsonContent() throws Exception {\n\t\tResolvableType type = ResolvableTypes.get(\"listOfExampleObject\");\n\t\tList<ExampleObject> value = Collections.singletonList(OBJECT);\n\t\tJsonContent<Object> content = createTester(type).write(value);\n\t\tassertThat(content).isEqualToJson(ARRAY_JSON);\n\t}\n\n\t@Test\n\tvoid writeArrayShouldReturnJsonContent() throws Exception {\n\t\tResolvableType type = ResolvableTypes.get(\"arrayOfExampleObject\");\n\t\tExampleObject[] value = new ExampleObject[] { OBJECT };\n\t\tJsonContent<Object> content = createTester(type).write(value);\n\t\tassertThat(content).isEqualToJson(ARRAY_JSON);\n\t}\n\n\t@Test\n\tvoid writeMapShouldReturnJsonContent() throws Exception {\n\t\tResolvableType type = ResolvableTypes.get(\"mapOfExampleObject\");\n\t\tMap<String, Object> value = new LinkedHashMap<>();\n\t\tvalue.put(\"a\", OBJECT);\n\t\tJsonContent<Object> content = createTester(type).write(value);\n\t\tassertThat(content).isEqualToJson(MAP_JSON);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResourceLoadClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> createTester(null, ResolvableType.forClass(ExampleObject.class)))\n\t\t\t.withMessageContaining(\"'resourceLoadClass' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createTester(getClass(), null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid parseBytesShouldReturnObject() throws Exception {\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.parse(JSON.getBytes())).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid parseStringShouldReturnObject() throws Exception {\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.parse(JSON)).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid readResourcePathShouldReturnObject() throws Exception {\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.read(\"example.json\")).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid readFileShouldReturnObject(@TempDir Path temp) throws Exception {\n\t\tFile file = new File(temp.toFile(), \"example.json\");\n\t\tFileCopyUtils.copy(JSON.getBytes(), file);\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.read(file)).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid readInputStreamShouldReturnObject() throws Exception {\n\t\tInputStream stream = new ByteArrayInputStream(JSON.getBytes());\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.read(stream)).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid readResourceShouldReturnObject() throws Exception {\n\t\tResource resource = new ByteArrayResource(JSON.getBytes());\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.read(resource)).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid readReaderShouldReturnObject() throws Exception {\n\t\tReader reader = new StringReader(JSON);\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(TYPE);\n\t\tassertThat(tester.read(reader)).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid parseListShouldReturnContent() throws Exception {\n\t\tResolvableType type = ResolvableTypes.get(\"listOfExampleObject\");\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(type);\n\t\tassertThat(tester.parse(ARRAY_JSON)).asInstanceOf(InstanceOfAssertFactories.LIST).containsOnly(OBJECT);\n\t}\n\n\t@Test\n\tvoid parseArrayShouldReturnContent() throws Exception {\n\t\tResolvableType type = ResolvableTypes.get(\"arrayOfExampleObject\");\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(type);\n\t\tassertThat(tester.parse(ARRAY_JSON)).asArray().containsOnly(OBJECT);\n\t}\n\n\t@Test\n\tvoid parseMapShouldReturnContent() throws Exception {\n\t\tResolvableType type = ResolvableTypes.get(\"mapOfExampleObject\");\n\t\tAbstractJsonMarshalTester<Object> tester = createTester(type);\n\t\tassertThat(tester.parse(MAP_JSON)).asMap().containsEntry(\"a\", OBJECT);\n\t}\n\n\tprotected static ExampleObject createExampleObject(String name, int age) {\n\t\tExampleObject exampleObject = new ExampleObject();\n\t\texampleObject.setName(name);\n\t\texampleObject.setAge(age);\n\t\treturn exampleObject;\n\t}\n\n\tprotected final AbstractJsonMarshalTester<Object> createTester(ResolvableType type) {\n\t\treturn createTester(AbstractJsonMarshalTesterTests.class, type);\n\t}\n\n\tprotected abstract AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type);\n\n\t/**\n\t * Access to field backed by {@link ResolvableType}.\n\t */\n\tstatic class ResolvableTypes {\n\n\t\tpublic @Nullable List<ExampleObject> listOfExampleObject;\n\n\t\tpublic ExampleObject @Nullable [] arrayOfExampleObject;\n\n\t\tpublic @Nullable Map<String, ExampleObject> mapOfExampleObject;\n\n\t\tstatic ResolvableType get(String name) {\n\t\t\tField field = ReflectionUtils.findField(ResolvableTypes.class, name);\n\t\t\tassertThat(field).isNotNull();\n\t\t\treturn ResolvableType.forField(field);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/BasicJsonTesterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link BasicJsonTester}.\n *\n * @author Phillip Webb\n */\nclass BasicJsonTesterTests {\n\n\tprivate static final String JSON = \"{\\\"spring\\\":[\\\"boot\\\",\\\"framework\\\"]}\";\n\n\tprivate final BasicJsonTester json = new BasicJsonTester(getClass());\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResourceLoadClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new BasicJsonTester(null))\n\t\t\t.withMessageContaining(\"'resourceLoadClass' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromJsonStringShouldReturnJsonContent() {\n\t\tassertThat(this.json.from(JSON)).isEqualToJson(\"source.json\");\n\t}\n\n\t@Test\n\tvoid fromResourceStringShouldReturnJsonContent() {\n\t\tassertThat(this.json.from(\"source.json\")).isEqualToJson(JSON);\n\t}\n\n\t@Test\n\tvoid fromResourceStringWithClassShouldReturnJsonContent() {\n\t\tassertThat(this.json.from(\"source.json\", getClass())).isEqualToJson(JSON);\n\t}\n\n\t@Test\n\tvoid fromByteArrayShouldReturnJsonContent() {\n\t\tassertThat(this.json.from(JSON.getBytes())).isEqualToJson(\"source.json\");\n\t}\n\n\t@Test\n\tvoid fromFileShouldReturnJsonContent(@TempDir Path temp) throws Exception {\n\t\tFile file = new File(temp.toFile(), \"file.json\");\n\t\tFileCopyUtils.copy(JSON.getBytes(), file);\n\t\tassertThat(this.json.from(file)).isEqualToJson(\"source.json\");\n\t}\n\n\t@Test\n\tvoid fromInputStreamShouldReturnJsonContent() {\n\t\tInputStream inputStream = new ByteArrayInputStream(JSON.getBytes());\n\t\tassertThat(this.json.from(inputStream)).isEqualToJson(\"source.json\");\n\t}\n\n\t@Test\n\tvoid fromResourceShouldReturnJsonContent() {\n\t\tResource resource = new ByteArrayResource(JSON.getBytes());\n\t\tassertThat(this.json.from(resource)).isEqualToJson(\"source.json\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/DuplicateJsonObjectContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DuplicateJsonObjectContextCustomizerFactory}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathOverrides(\"org.json:json:20140107\")\nclass DuplicateJsonObjectContextCustomizerFactoryTests {\n\n\tprivate CapturedOutput output;\n\n\t@BeforeEach\n\tvoid setup(CapturedOutput output) {\n\t\tthis.output = output;\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Uses null for quick test setup\n\tvoid warningForMultipleVersions() {\n\t\tnew DuplicateJsonObjectContextCustomizerFactory().createContextCustomizer(null, null)\n\t\t\t.customizeContext(null, null);\n\t\tassertThat(this.output).contains(\"Found multiple occurrences of org.json.JSONObject on the class path:\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/ExampleObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Example object used for serialization.\n */\npublic class ExampleObject {\n\n\tprivate @Nullable String name;\n\n\tprivate int age;\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn this.age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tExampleObject other = (ExampleObject) obj;\n\t\treturn ObjectUtils.nullSafeEquals(this.name, other.name) && ObjectUtils.nullSafeEquals(this.age, other.age);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name + \" \" + this.age;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/ExampleObjectWithView.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport com.fasterxml.jackson.annotation.JsonView;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Example object used for serialization/deserialization with view.\n *\n * @author Madhura Bhave\n */\npublic class ExampleObjectWithView {\n\n\t@JsonView(TestView.class)\n\tprivate @Nullable String name;\n\n\tprivate int age;\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getAge() {\n\t\treturn this.age;\n\t}\n\n\tpublic void setAge(int age) {\n\t\tthis.age = age;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tExampleObjectWithView other = (ExampleObjectWithView) obj;\n\t\treturn ObjectUtils.nullSafeEquals(this.name, other.name) && ObjectUtils.nullSafeEquals(this.age, other.age);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name + \" \" + this.age;\n\t}\n\n\tstatic class TestView {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/GsonTesterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.google.gson.Gson;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link GsonTester}. Shows typical usage.\n *\n * @author Andy Wilkinson\n * @author Diego Berrueta\n */\nclass GsonTesterIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate GsonTester<ExampleObject> simpleJson;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate GsonTester<List<ExampleObject>> listJson;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate GsonTester<Map<String, Integer>> mapJson;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate GsonTester<String> stringJson;\n\n\tprivate Gson gson;\n\n\tprivate static final String JSON = \"{\\\"name\\\":\\\"Spring\\\",\\\"age\\\":123}\";\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.gson = new Gson();\n\t\tGsonTester.initFields(this, this.gson);\n\t}\n\n\t@Test\n\tvoid typicalTest() throws Exception {\n\t\tString example = JSON;\n\t\tassertThat(this.simpleJson.parse(example).getObject().getName()).isEqualTo(\"Spring\");\n\t}\n\n\t@Test\n\tvoid typicalListTest() throws Exception {\n\t\tString example = \"[\" + JSON + \"]\";\n\t\tassertThat(this.listJson.parse(example)).asInstanceOf(InstanceOfAssertFactories.LIST).hasSize(1);\n\t\tassertThat(this.listJson.parse(example).getObject().get(0).getName()).isEqualTo(\"Spring\");\n\t}\n\n\t@Test\n\tvoid typicalMapTest() throws Exception {\n\t\tMap<String, Integer> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", 1);\n\t\tmap.put(\"b\", 2);\n\t\tassertThat(this.mapJson.write(map)).extractingJsonPathNumberValue(\"@.a\").isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid stringLiteral() throws Exception {\n\t\tString stringWithSpecialCharacters = \"myString\";\n\t\tassertThat(this.stringJson.write(stringWithSpecialCharacters)).extractingJsonPathStringValue(\"@\")\n\t\t\t.isEqualTo(stringWithSpecialCharacters);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/GsonTesterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.util.List;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link GsonTester}.\n *\n * @author Phillip Webb\n */\nclass GsonTesterTests extends AbstractJsonMarshalTesterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenTestIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> GsonTester.initFields(null, new GsonBuilder().create()))\n\t\t\t.withMessageContaining(\"'testInstance' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenMarshallerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> GsonTester.initFields(new InitFieldsTestClass(), (Gson) null))\n\t\t\t.withMessageContaining(\"'marshaller' must not be null\");\n\t}\n\n\t@Test\n\tvoid initFieldsShouldSetNullFields() {\n\t\tInitFieldsTestClass test = new InitFieldsTestClass();\n\t\tassertThat(test.test).isNull();\n\t\tassertThat(test.base).isNull();\n\t\tGsonTester.initFields(test, new GsonBuilder().create());\n\t\tassertThat(test.test).isNotNull();\n\t\tassertThat(test.base).isNotNull();\n\t\tResolvableType type = test.test.getType();\n\t\tassertThat(type).isNotNull();\n\t\tassertThat(type.resolve()).isEqualTo(List.class);\n\t\tassertThat(type.resolveGeneric()).isEqualTo(ExampleObject.class);\n\t}\n\n\t@Override\n\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {\n\t\treturn new GsonTester<>(resourceLoadClass, type, new GsonBuilder().create());\n\t}\n\n\tabstract static class InitFieldsBaseClass {\n\n\t\tpublic @Nullable GsonTester<ExampleObject> base;\n\n\t\tpublic GsonTester<ExampleObject> baseSet = new GsonTester<>(InitFieldsBaseClass.class,\n\t\t\t\tResolvableType.forClass(ExampleObject.class), new GsonBuilder().create());\n\n\t}\n\n\tstatic class InitFieldsTestClass extends InitFieldsBaseClass {\n\n\t\tpublic @Nullable GsonTester<List<ExampleObject>> test;\n\n\t\tpublic GsonTester<ExampleObject> testSet = new GsonTester<>(InitFieldsBaseClass.class,\n\t\t\t\tResolvableType.forClass(ExampleObject.class), new GsonBuilder().create());\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/Jackson2TesterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.util.List;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Jackson2Tester}.\n *\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of JacksonTesterTests\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass Jackson2TesterTests extends AbstractJsonMarshalTesterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenTestIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Jackson2Tester.initFields(null, new ObjectMapper()))\n\t\t\t.withMessageContaining(\"'testInstance' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenMarshallerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> Jackson2Tester.initFields(new InitFieldsTestClass(), (ObjectMapper) null))\n\t\t\t.withMessageContaining(\"'marshaller' must not be null\");\n\t}\n\n\t@Test\n\tvoid initFieldsShouldSetNullFields() {\n\t\tInitFieldsTestClass test = new InitFieldsTestClass();\n\t\tassertThat(test.test).isNull();\n\t\tassertThat(test.base).isNull();\n\t\tJackson2Tester.initFields(test, new ObjectMapper());\n\t\tassertThat(test.test).isNotNull();\n\t\tassertThat(test.base).isNotNull();\n\t\tResolvableType type = test.test.getType();\n\t\tassertThat(type).isNotNull();\n\t\tassertThat(type.resolve()).isEqualTo(List.class);\n\t\tassertThat(type.resolveGeneric()).isEqualTo(ExampleObject.class);\n\t}\n\n\t@Override\n\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {\n\t\treturn new org.springframework.boot.test.json.Jackson2Tester<>(resourceLoadClass, type, new ObjectMapper());\n\t}\n\n\tabstract static class InitFieldsBaseClass {\n\n\t\tpublic org.springframework.boot.test.json.@Nullable Jackson2Tester<ExampleObject> base;\n\n\t\tpublic org.springframework.boot.test.json.Jackson2Tester<ExampleObject> baseSet = new org.springframework.boot.test.json.Jackson2Tester<>(\n\t\t\t\tInitFieldsBaseClass.class, ResolvableType.forClass(ExampleObject.class), new ObjectMapper());\n\n\t}\n\n\tstatic class InitFieldsTestClass extends InitFieldsBaseClass {\n\n\t\tpublic org.springframework.boot.test.json.@Nullable Jackson2Tester<List<ExampleObject>> test;\n\n\t\tpublic org.springframework.boot.test.json.Jackson2Tester<ExampleObject> testSet = new org.springframework.boot.test.json.Jackson2Tester<>(\n\t\t\t\tInitFieldsBaseClass.class, ResolvableType.forClass(ExampleObject.class), new ObjectMapper());\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/JacksonTesterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.core.io.ByteArrayResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JacksonTester}. Shows typical usage.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Diego Berrueta\n */\nclass JacksonTesterIntegrationTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate JacksonTester<ExampleObject> simpleJson;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate JacksonTester<ExampleObjectWithView> jsonWithView;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate JacksonTester<List<ExampleObject>> listJson;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate JacksonTester<Map<String, Integer>> mapJson;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate JacksonTester<String> stringJson;\n\n\tprivate static final String JSON = \"{\\\"name\\\":\\\"Spring\\\",\\\"age\\\":123}\";\n\n\t@Test\n\tvoid typicalTest() throws Exception {\n\t\tJacksonTester.initFields(this, new JsonMapper());\n\t\tassertThat(this.simpleJson.parse(JSON).getObject().getName()).isEqualTo(\"Spring\");\n\t}\n\n\t@Test\n\tvoid typicalListTest() throws Exception {\n\t\tJacksonTester.initFields(this, new JsonMapper());\n\t\tString example = \"[\" + JSON + \"]\";\n\t\tassertThat(this.listJson.parse(example)).asInstanceOf(InstanceOfAssertFactories.LIST).hasSize(1);\n\t\tassertThat(this.listJson.parse(example).getObject().get(0).getName()).isEqualTo(\"Spring\");\n\t}\n\n\t@Test\n\tvoid typicalMapTest() throws Exception {\n\t\tJacksonTester.initFields(this, new JsonMapper());\n\t\tMap<String, Integer> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", 1);\n\t\tmap.put(\"b\", 2);\n\t\tassertThat(this.mapJson.write(map)).extractingJsonPathNumberValue(\"@.a\").isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid stringLiteral() throws Exception {\n\t\tJacksonTester.initFields(this, new JsonMapper());\n\t\tString stringWithSpecialCharacters = \"myString\";\n\t\tassertThat(this.stringJson.write(stringWithSpecialCharacters)).extractingJsonPathStringValue(\"@\")\n\t\t\t.isEqualTo(stringWithSpecialCharacters);\n\t}\n\n\t@Test\n\tvoid parseSpecialCharactersTest() throws Exception {\n\t\tJacksonTester.initFields(this, new JsonMapper());\n\t\t// Confirms that the handling of special characters is symmetrical between\n\t\t// the serialization (through the JacksonTester) and the parsing (through\n\t\t// json-path). By default json-path uses SimpleJson as its parser, which has a\n\t\t// slightly different behavior to Jackson and breaks the symmetry. JacksonTester\n\t\t// configures json-path to use Jackson for evaluating the path expressions and\n\t\t// restores the symmetry. See gh-15727\n\t\tString stringWithSpecialCharacters = \"\\u0006\\u007F\";\n\t\tassertThat(this.stringJson.write(stringWithSpecialCharacters)).extractingJsonPathStringValue(\"@\")\n\t\t\t.isEqualTo(stringWithSpecialCharacters);\n\t}\n\n\t@Test\n\tvoid writeWithView() throws Exception {\n\t\tJacksonTester.initFields(this, JsonMapper.builder().disable(MapperFeature.DEFAULT_VIEW_INCLUSION).build());\n\t\tExampleObjectWithView object = new ExampleObjectWithView();\n\t\tobject.setName(\"Spring\");\n\t\tobject.setAge(123);\n\t\tJsonContent<ExampleObjectWithView> content = this.jsonWithView.forView(ExampleObjectWithView.TestView.class)\n\t\t\t.write(object);\n\t\tassertThat(content).extractingJsonPathStringValue(\"@.name\").isEqualTo(\"Spring\");\n\t\tassertThat(content).doesNotHaveJsonPathValue(\"age\");\n\t}\n\n\t@Test\n\tvoid readWithResourceAndView() throws Exception {\n\t\tJacksonTester.initFields(this, JsonMapper.builder().disable(MapperFeature.DEFAULT_VIEW_INCLUSION).build());\n\t\tByteArrayResource resource = new ByteArrayResource(JSON.getBytes());\n\t\tObjectContent<ExampleObjectWithView> content = this.jsonWithView.forView(ExampleObjectWithView.TestView.class)\n\t\t\t.read(resource);\n\t\tassertThat(content.getObject().getName()).isEqualTo(\"Spring\");\n\t\tassertThat(content.getObject().getAge()).isZero();\n\t}\n\n\t@Test\n\tvoid readWithReaderAndView() throws Exception {\n\t\tJacksonTester.initFields(this, JsonMapper.builder().disable(MapperFeature.DEFAULT_VIEW_INCLUSION).build());\n\t\tReader reader = new StringReader(JSON);\n\t\tObjectContent<ExampleObjectWithView> content = this.jsonWithView.forView(ExampleObjectWithView.TestView.class)\n\t\t\t.read(reader);\n\t\tassertThat(content.getObject().getName()).isEqualTo(\"Spring\");\n\t\tassertThat(content.getObject().getAge()).isZero();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/JacksonTesterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link JacksonTester}.\n *\n * @author Phillip Webb\n */\nclass JacksonTesterTests extends AbstractJsonMarshalTesterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenTestIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> JacksonTester.initFields(null, new JsonMapper()))\n\t\t\t.withMessageContaining(\"'testInstance' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenMarshallerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> JacksonTester.initFields(new InitFieldsTestClass(), (JsonMapper) null))\n\t\t\t.withMessageContaining(\"'marshaller' must not be null\");\n\t}\n\n\t@Test\n\tvoid initFieldsShouldSetNullFields() {\n\t\tInitFieldsTestClass test = new InitFieldsTestClass();\n\t\tassertThat(test.test).isNull();\n\t\tassertThat(test.base).isNull();\n\t\tJacksonTester.initFields(test, new JsonMapper());\n\t\tassertThat(test.test).isNotNull();\n\t\tassertThat(test.base).isNotNull();\n\t\tResolvableType type = test.test.getType();\n\t\tassertThat(type).isNotNull();\n\t\tassertThat(type.resolve()).isEqualTo(List.class);\n\t\tassertThat(type.resolveGeneric()).isEqualTo(ExampleObject.class);\n\t}\n\n\t@Override\n\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {\n\t\treturn new JacksonTester<>(resourceLoadClass, type, new JsonMapper());\n\t}\n\n\tabstract static class InitFieldsBaseClass {\n\n\t\tpublic @Nullable JacksonTester<ExampleObject> base;\n\n\t\tpublic JacksonTester<ExampleObject> baseSet = new JacksonTester<>(InitFieldsBaseClass.class,\n\t\t\t\tResolvableType.forClass(ExampleObject.class), new JsonMapper());\n\n\t}\n\n\tstatic class InitFieldsTestClass extends InitFieldsBaseClass {\n\n\t\tpublic @Nullable JacksonTester<List<ExampleObject>> test;\n\n\t\tpublic JacksonTester<ExampleObject> testSet = new JacksonTester<>(InitFieldsBaseClass.class,\n\t\t\t\tResolvableType.forClass(ExampleObject.class), new JsonMapper());\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/JsonContentAssertTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\n\nimport org.assertj.core.api.AssertProvider;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.skyscreamer.jsonassert.JSONCompareMode;\nimport org.skyscreamer.jsonassert.comparator.DefaultComparator;\nimport org.skyscreamer.jsonassert.comparator.JSONComparator;\n\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.test.util.JsonPathExpectationsHelper;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link JsonContentAssert}. Some tests here are based on Spring Framework\n * tests for {@link JsonPathExpectationsHelper}.\n *\n * @author Phillip Webb\n */\nclass JsonContentAssertTests {\n\n\tprivate static final String SOURCE = loadJson(\"source.json\");\n\n\tprivate static final String LENIENT_SAME = loadJson(\"lenient-same.json\");\n\n\tprivate static final String DIFFERENT = loadJson(\"different.json\");\n\n\tprivate static final String TYPES = loadJson(\"types.json\");\n\n\tprivate static final String SIMPSONS = loadJson(\"simpsons.json\");\n\n\tprivate static final String NULLS = loadJson(\"nulls.json\");\n\n\tprivate static final JSONComparator COMPARATOR = new DefaultComparator(JSONCompareMode.LENIENT);\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tpublic Path tempDir;\n\n\tprivate File temp;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.temp = new File(this.tempDir.toFile(), \"file.json\");\n\t}\n\n\t@Test\n\tvoid isEqualToWhenStringIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualTo(LENIENT_SAME);\n\t}\n\n\t@Test\n\tvoid isEqualToWhenNullActualShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(forJson(null)).isEqualTo(SOURCE));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenStringIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualTo(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenResourcePathIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualTo(\"lenient-same.json\");\n\t}\n\n\t@Test\n\tvoid isEqualToWhenResourcePathIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualTo(\"different.json\"));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenBytesAreMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualTo(LENIENT_SAME.getBytes());\n\t}\n\n\t@Test\n\tvoid isEqualToWhenBytesAreNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualTo(DIFFERENT.getBytes()));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenFileIsMatchingShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isEqualTo(createFile(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenFileIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualTo(createFile(DIFFERENT)));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenInputStreamIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualTo(createInputStream(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenInputStreamIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualTo(createInputStream(DIFFERENT)));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenResourceIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualTo(createResource(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isEqualToWhenResourceIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualTo(createResource(DIFFERENT)));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenStringIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(LENIENT_SAME);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenNullActualShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(null)).isEqualToJson(SOURCE));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenStringIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(\"lenient-same.json\");\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(\"different.json\"));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathAndClassIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(\"lenient-same.json\", getClass());\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathAndClassIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(\"different.json\", getClass()));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenBytesAreMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(LENIENT_SAME.getBytes());\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenBytesAreNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(DIFFERENT.getBytes()));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenFileIsMatchingShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createFile(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenFileIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(createFile(DIFFERENT)));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenInputStreamIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createInputStream(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenInputStreamIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(createInputStream(DIFFERENT)));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourceIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createResource(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourceIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(createResource(DIFFERENT)));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenStringIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(SOURCE);\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenStringIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenResourcePathIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(\"source.json\");\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenResourcePathIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(\"lenient-same.json\"));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenResourcePathAndClassIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(\"source.json\", getClass());\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenResourcePathAndClassIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(\"lenient-same.json\", getClass()));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenBytesAreMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(SOURCE.getBytes());\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenBytesAreNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(LENIENT_SAME.getBytes()));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenFileIsMatchingShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(createFile(SOURCE));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenFileIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(createFile(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenInputStreamIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(createInputStream(SOURCE));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenInputStreamIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(createInputStream(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenResourceIsMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isStrictlyEqualToJson(createResource(SOURCE));\n\t}\n\n\t@Test\n\tvoid isStrictlyEqualToJsonWhenResourceIsNotMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualToJson(createResource(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenStringIsMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(LENIENT_SAME, JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenStringIsNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(DIFFERENT, JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathIsMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(\"lenient-same.json\", JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathIsNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(\"different.json\", JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathAndClassIsMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(\"lenient-same.json\", getClass(), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathAndClassIsNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isEqualToJson(\"different.json\", getClass(), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenBytesAreMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(LENIENT_SAME.getBytes(), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenBytesAreNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(DIFFERENT.getBytes(), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenFileIsMatchingAndLenientShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createFile(LENIENT_SAME), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenFileIsNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isEqualToJson(createFile(DIFFERENT), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenInputStreamIsMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createInputStream(LENIENT_SAME), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenInputStreamIsNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isEqualToJson(createInputStream(DIFFERENT), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourceIsMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createResource(LENIENT_SAME), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourceIsNotMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isEqualToJson(createResource(DIFFERENT), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenStringIsMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(LENIENT_SAME, COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenStringIsNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(DIFFERENT, COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathIsMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(\"lenient-same.json\", COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathIsNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(\"different.json\", COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathAndClassAreMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(\"lenient-same.json\", getClass(), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourcePathAndClassAreNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(\"different.json\", getClass(), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenBytesAreMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(LENIENT_SAME.getBytes(), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenBytesAreNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(DIFFERENT.getBytes(), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenFileIsMatchingAndComparatorShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createFile(LENIENT_SAME), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenFileIsNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(createFile(DIFFERENT), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenInputStreamIsMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createInputStream(LENIENT_SAME), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenInputStreamIsNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(createInputStream(DIFFERENT), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourceIsMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isEqualToJson(createResource(LENIENT_SAME), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isEqualToJsonWhenResourceIsNotMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isEqualToJson(createResource(DIFFERENT), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenStringIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualTo(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenNullActualShouldPass() {\n\t\tassertThat(forJson(null)).isNotEqualTo(SOURCE);\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenStringIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualTo(DIFFERENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenResourcePathIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualTo(\"lenient-same.json\"));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenResourcePathIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualTo(\"different.json\");\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenBytesAreMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualTo(LENIENT_SAME.getBytes()));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenBytesAreNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualTo(DIFFERENT.getBytes());\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenFileIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualTo(createFile(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenFileIsNotMatchingShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isNotEqualTo(createFile(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenInputStreamIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualTo(createInputStream(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenInputStreamIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualTo(createInputStream(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenResourceIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualTo(createResource(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isNotEqualToWhenResourceIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualTo(createResource(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenStringIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenNullActualShouldPass() {\n\t\tassertThat(forJson(null)).isNotEqualToJson(SOURCE);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenStringIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(DIFFERENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(\"lenient-same.json\"));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(\"different.json\");\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathAndClassAreMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(\"lenient-same.json\", getClass()));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathAndClassAreNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(\"different.json\", getClass());\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenBytesAreMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(LENIENT_SAME.getBytes()));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenBytesAreNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(DIFFERENT.getBytes());\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenFileIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createFile(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenFileIsNotMatchingShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createFile(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenInputStreamIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createInputStream(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenInputStreamIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createInputStream(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourceIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createResource(LENIENT_SAME)));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourceIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createResource(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenStringIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(SOURCE));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenStringIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(LENIENT_SAME);\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenResourcePathIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(\"source.json\"));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenResourcePathIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(\"lenient-same.json\");\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenResourcePathAndClassAreMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(\"source.json\", getClass()));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenResourcePathAndClassAreNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(\"lenient-same.json\", getClass());\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenBytesAreMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(SOURCE.getBytes()));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenBytesAreNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(LENIENT_SAME.getBytes());\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenFileIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(createFile(SOURCE)));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenFileIsNotMatchingShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(createFile(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenInputStreamIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(createInputStream(SOURCE)));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenInputStreamIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(createInputStream(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenResourceIsMatchingShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(createResource(SOURCE)));\n\t}\n\n\t@Test\n\tvoid isNotStrictlyEqualToJsonWhenResourceIsNotMatchingShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotStrictlyEqualToJson(createResource(LENIENT_SAME));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenStringIsMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(LENIENT_SAME, JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenStringIsNotMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(DIFFERENT, JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathIsMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isNotEqualToJson(\"lenient-same.json\", JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathIsNotMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(\"different.json\", JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathAndClassAreMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(forJson(SOURCE))\n\t\t\t.isNotEqualToJson(\"lenient-same.json\", getClass(), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathAndClassAreNotMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(\"different.json\", getClass(), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenBytesAreMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isNotEqualToJson(LENIENT_SAME.getBytes(), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenBytesAreNotMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(DIFFERENT.getBytes(), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenFileIsMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createFile(LENIENT_SAME), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenFileIsNotMatchingAndLenientShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createFile(DIFFERENT), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenInputStreamIsMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(forJson(SOURCE))\n\t\t\t.isNotEqualToJson(createInputStream(LENIENT_SAME), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenInputStreamIsNotMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createInputStream(DIFFERENT), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourceIsMatchingAndLenientShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(forJson(SOURCE))\n\t\t\t.isNotEqualToJson(createResource(LENIENT_SAME), JSONCompareMode.LENIENT));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourceIsNotMatchingAndLenientShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createResource(DIFFERENT), JSONCompareMode.LENIENT);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenStringIsMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(LENIENT_SAME, COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenStringIsNotMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(DIFFERENT, COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathIsMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(\"lenient-same.json\", COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathIsNotMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(\"different.json\", COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathAndClassAreMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isNotEqualToJson(\"lenient-same.json\", getClass(), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourcePathAndClassAreNotMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(\"different.json\", getClass(), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenBytesAreMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(LENIENT_SAME.getBytes(), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenBytesAreNotMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(DIFFERENT.getBytes(), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenFileIsMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createFile(LENIENT_SAME), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenFileIsNotMatchingAndComparatorShouldPass() throws Exception {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createFile(DIFFERENT), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenInputStreamIsMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(\n\t\t\t\t() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createInputStream(LENIENT_SAME), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenInputStreamIsNotMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createInputStream(DIFFERENT), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourceIsMatchingAndComparatorShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SOURCE)).isNotEqualToJson(createResource(LENIENT_SAME), COMPARATOR));\n\t}\n\n\t@Test\n\tvoid isNotEqualToJsonWhenResourceIsNotMatchingAndComparatorShouldPass() {\n\t\tassertThat(forJson(SOURCE)).isNotEqualToJson(createResource(DIFFERENT), COMPARATOR);\n\t}\n\n\t@Test\n\tvoid hasJsonPathForPresentAndNotNull() {\n\t\tassertThat(forJson(NULLS)).hasJsonPath(\"valuename\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathForPresentAndNull() {\n\t\tassertThat(forJson(NULLS)).hasJsonPath(\"nullname\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathForNotPresent() {\n\t\tString expression = \"missing\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(NULLS)).hasJsonPath(expression))\n\t\t\t.withMessageContaining(\"No JSON path \\\"\" + expression + \"\\\" found\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValue() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathValue(\"$.str\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValueForAnEmptyArray() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathValue(\"$.emptyArray\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValueForAnEmptyMap() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathValue(\"$.emptyMap\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValueForANullValue() {\n\t\tString expression = \"nullname\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(NULLS)).hasJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"No value at JSON path \\\"\" + expression + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValueForMissingValue() {\n\t\tString expression = \"missing\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(NULLS)).hasJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"No value at JSON path \\\"\" + expression + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValueForIndefinitePathWithResults() {\n\t\tassertThat(forJson(SIMPSONS)).hasJsonPathValue(\"$.familyMembers[?(@.name == 'Bart')]\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathValueForIndefinitePathWithEmptyResults() {\n\t\tString expression = \"$.familyMembers[?(@.name == 'Dilbert')]\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SIMPSONS)).hasJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"No value at JSON path \\\"\" + expression + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathForMissing() {\n\t\tassertThat(forJson(NULLS)).doesNotHaveJsonPath(\"missing\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathForNull() {\n\t\tString expression = \"nullname\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(NULLS)).doesNotHaveJsonPath(expression))\n\t\t\t.withMessageContaining(\"Expecting no JSON path \\\"\" + expression + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathForPresent() {\n\t\tString expression = \"valuename\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(NULLS)).doesNotHaveJsonPath(expression))\n\t\t\t.withMessageContaining(\"Expecting no JSON path \\\"\" + expression + \"\\\"\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathValue() {\n\t\tassertThat(forJson(TYPES)).doesNotHaveJsonPathValue(\"$.bogus\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathValueForAnEmptyArray() {\n\t\tString expression = \"$.emptyArray\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).doesNotHaveJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected no value at JSON path \\\"\" + expression + \"\\\" but found: []\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathValueForAnEmptyMap() {\n\t\tString expression = \"$.emptyMap\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).doesNotHaveJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected no value at JSON path \\\"\" + expression + \"\\\" but found: {}\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathValueForIndefinitePathWithResults() {\n\t\tString expression = \"$.familyMembers[?(@.name == 'Bart')]\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SIMPSONS)).doesNotHaveJsonPathValue(expression))\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Expected no value at JSON path \\\"\" + expression + \"\\\" but found: [{\\\"name\\\":\\\"Bart\\\"}]\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathValueForIndefinitePathWithEmptyResults() {\n\t\tassertThat(forJson(SIMPSONS)).doesNotHaveJsonPathValue(\"$.familyMembers[?(@.name == 'Dilbert')]\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveJsonPathValueForNull() {\n\t\tassertThat(forJson(NULLS)).doesNotHaveJsonPathValue(\"nullname\");\n\t}\n\n\t@Test\n\tvoid hasEmptyJsonPathValueForAnEmptyString() {\n\t\tassertThat(forJson(TYPES)).hasEmptyJsonPathValue(\"$.emptyString\");\n\t}\n\n\t@Test\n\tvoid hasEmptyJsonPathValueForAnEmptyArray() {\n\t\tassertThat(forJson(TYPES)).hasEmptyJsonPathValue(\"$.emptyArray\");\n\t}\n\n\t@Test\n\tvoid hasEmptyJsonPathValueForAnEmptyMap() {\n\t\tassertThat(forJson(TYPES)).hasEmptyJsonPathValue(\"$.emptyMap\");\n\t}\n\n\t@Test\n\tvoid hasEmptyJsonPathValueForIndefinitePathWithEmptyResults() {\n\t\tassertThat(forJson(SIMPSONS)).hasEmptyJsonPathValue(\"$.familyMembers[?(@.name == 'Dilbert')]\");\n\t}\n\n\t@Test\n\tvoid hasEmptyJsonPathValueForIndefinitePathWithResults() {\n\t\tString expression = \"$.familyMembers[?(@.name == 'Bart')]\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SIMPSONS)).hasEmptyJsonPathValue(expression))\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Expected an empty value at JSON path \\\"\" + expression + \"\\\" but found: [{\\\"name\\\":\\\"Bart\\\"}]\");\n\t}\n\n\t@Test\n\tvoid hasEmptyJsonPathValueForWhitespace() {\n\t\tString expression = \"$.whitespace\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).hasEmptyJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected an empty value at JSON path \\\"\" + expression + \"\\\" but found: '    '\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForString() {\n\t\tassertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(\"$.str\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForNumber() {\n\t\tassertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(\"$.num\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForBoolean() {\n\t\tassertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(\"$.bool\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForArray() {\n\t\tassertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(\"$.arr\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForMap() {\n\t\tassertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(\"$.colorMap\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForIndefinitePathWithResults() {\n\t\tassertThat(forJson(SIMPSONS)).doesNotHaveEmptyJsonPathValue(\"$.familyMembers[?(@.name == 'Bart')]\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForIndefinitePathWithEmptyResults() {\n\t\tString expression = \"$.familyMembers[?(@.name == 'Dilbert')]\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(SIMPSONS)).doesNotHaveEmptyJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected a non-empty value at JSON path \\\"\" + expression + \"\\\" but found: []\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForAnEmptyString() {\n\t\tString expression = \"$.emptyString\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected a non-empty value at JSON path \\\"\" + expression + \"\\\" but found: ''\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForForAnEmptyArray() {\n\t\tString expression = \"$.emptyArray\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected a non-empty value at JSON path \\\"\" + expression + \"\\\" but found: []\");\n\t}\n\n\t@Test\n\tvoid doesNotHaveEmptyJsonPathValueForAnEmptyMap() {\n\t\tString expression = \"$.emptyMap\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).doesNotHaveEmptyJsonPathValue(expression))\n\t\t\t.withMessageContaining(\"Expected a non-empty value at JSON path \\\"\" + expression + \"\\\" but found: {}\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathStringValue() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathStringValue(\"$.str\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathStringValueForAnEmptyString() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathStringValue(\"$.emptyString\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathStringValueForNonString() {\n\t\tString expression = \"$.bool\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).hasJsonPathStringValue(expression))\n\t\t\t.withMessageContaining(\"Expected a string at JSON path \\\"\" + expression + \"\\\" but found: true\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathNumberValue() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathNumberValue(\"$.num\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathNumberValueForNonNumber() {\n\t\tString expression = \"$.bool\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).hasJsonPathNumberValue(expression))\n\t\t\t.withMessageContaining(\"Expected a number at JSON path \\\"\" + expression + \"\\\" but found: true\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathBooleanValue() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathBooleanValue(\"$.bool\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathBooleanValueForNonBoolean() {\n\t\tString expression = \"$.num\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).hasJsonPathBooleanValue(expression))\n\t\t\t.withMessageContaining(\"Expected a boolean at JSON path \\\"\" + expression + \"\\\" but found: 5\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathArrayValue() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathArrayValue(\"$.arr\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathArrayValueForAnEmptyArray() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathArrayValue(\"$.emptyArray\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathArrayValueForNonArray() {\n\t\tString expression = \"$.str\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).hasJsonPathArrayValue(expression))\n\t\t\t.withMessageContaining(\"Expected an array at JSON path \\\"\" + expression + \"\\\" but found: 'foo'\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathMapValue() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathMapValue(\"$.colorMap\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathMapValueForAnEmptyMap() {\n\t\tassertThat(forJson(TYPES)).hasJsonPathMapValue(\"$.emptyMap\");\n\t}\n\n\t@Test\n\tvoid hasJsonPathMapValueForNonMap() {\n\t\tString expression = \"$.str\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).hasJsonPathMapValue(expression))\n\t\t\t.withMessageContaining(\"Expected a map at JSON path \\\"\" + expression + \"\\\" but found: 'foo'\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathValue() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathValue(\"@.str\").isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathValueForMissing() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathValue(\"@.bogus\").isNull();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathStringValue() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathStringValue(\"@.str\").isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathStringValueForMissing() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathStringValue(\"@.bogus\").isNull();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathStringValueForEmptyString() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathStringValue(\"@.emptyString\").isEmpty();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathStringValueForWrongType() {\n\t\tString expression = \"$.num\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).extractingJsonPathStringValue(expression))\n\t\t\t.withMessageContaining(\"Expected a string at JSON path \\\"\" + expression + \"\\\" but found: 5\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathNumberValue() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathNumberValue(\"@.num\").isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid extractingJsonPathNumberValueForMissing() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathNumberValue(\"@.bogus\").isNull();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathNumberValueForWrongType() {\n\t\tString expression = \"$.str\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).extractingJsonPathNumberValue(expression))\n\t\t\t.withMessageContaining(\"Expected a number at JSON path \\\"\" + expression + \"\\\" but found: 'foo'\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathBooleanValue() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathBooleanValue(\"@.bool\").isTrue();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathBooleanValueForMissing() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathBooleanValue(\"@.bogus\").isNull();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathBooleanValueForWrongType() {\n\t\tString expression = \"$.str\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).extractingJsonPathBooleanValue(expression))\n\t\t\t.withMessageContaining(\"Expected a boolean at JSON path \\\"\" + expression + \"\\\" but found: 'foo'\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathArrayValue() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathArrayValue(\"@.arr\").containsExactly(42);\n\t}\n\n\t@Test\n\tvoid extractingJsonPathArrayValueForMissing() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathArrayValue(\"@.bogus\").isNull();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathArrayValueForEmpty() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathArrayValue(\"@.emptyArray\").isEmpty();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathArrayValueForWrongType() {\n\t\tString expression = \"$.str\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).extractingJsonPathArrayValue(expression))\n\t\t\t.withMessageContaining(\"Expected an array at JSON path \\\"\" + expression + \"\\\" but found: 'foo'\");\n\t}\n\n\t@Test\n\tvoid extractingJsonPathMapValue() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathMapValue(\"@.colorMap\").contains(entry(\"red\", \"rojo\"));\n\t}\n\n\t@Test\n\tvoid extractingJsonPathMapValueForMissing() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathMapValue(\"@.bogus\").isNull();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathMapValueForEmpty() {\n\t\tassertThat(forJson(TYPES)).extractingJsonPathMapValue(\"@.emptyMap\").isEmpty();\n\t}\n\n\t@Test\n\tvoid extractingJsonPathMapValueForWrongType() {\n\t\tString expression = \"$.str\";\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forJson(TYPES)).extractingJsonPathMapValue(expression))\n\t\t\t.withMessageContaining(\"Expected a map at JSON path \\\"\" + expression + \"\\\" but found: 'foo'\");\n\t}\n\n\t@Test\n\tvoid isNullWhenActualIsNullShouldPass() {\n\t\tassertThat(forJson(null)).isNull();\n\t}\n\n\tprivate File createFile(String content) throws IOException {\n\t\tFile file = this.temp;\n\t\tFileCopyUtils.copy(content.getBytes(), file);\n\t\treturn file;\n\t}\n\n\tprivate InputStream createInputStream(String content) {\n\t\treturn new ByteArrayInputStream(content.getBytes());\n\t}\n\n\tprivate Resource createResource(String content) {\n\t\treturn new ByteArrayResource(content.getBytes());\n\t}\n\n\tprivate static String loadJson(String path) {\n\t\ttry {\n\t\t\tClassPathResource resource = new ClassPathResource(path, JsonContentAssertTests.class);\n\t\t\treturn new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\n\t}\n\n\tprivate AssertProvider<JsonContentAssert> forJson(@Nullable String json) {\n\t\treturn () -> new JsonContentAssert(JsonContentAssertTests.class, json);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/JsonContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport com.jayway.jsonpath.Configuration;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link JsonContent}.\n *\n * @author Phillip Webb\n */\nclass JsonContentTests {\n\n\tprivate static final String JSON = \"{\\\"name\\\":\\\"spring\\\", \\\"age\\\":100}\";\n\n\tprivate static final ResolvableType TYPE = ResolvableType.forClass(ExampleObject.class);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResourceLoadClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new JsonContent<ExampleObject>(null, TYPE, JSON, Configuration.defaultConfiguration()))\n\t\t\t.withMessageContaining(\"'resourceLoadClass' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenJsonIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new JsonContent<ExampleObject>(getClass(), TYPE, null, Configuration.defaultConfiguration()))\n\t\t\t.withMessageContaining(\"'json' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenConfigurationIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new JsonContent<ExampleObject>(getClass(), TYPE, JSON, null))\n\t\t\t.withMessageContaining(\"'configuration' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenTypeIsNullShouldCreateContent() {\n\t\tJsonContent<ExampleObject> content = new JsonContent<>(getClass(), null, JSON,\n\t\t\t\tConfiguration.defaultConfiguration());\n\t\tassertThat(content).isNotNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"deprecation\")\n\tvoid assertThatShouldReturnJsonContentAssert() {\n\t\tJsonContent<ExampleObject> content = new JsonContent<>(getClass(), TYPE, JSON,\n\t\t\t\tConfiguration.defaultConfiguration());\n\t\tassertThat(content.assertThat()).isInstanceOf(JsonContentAssert.class);\n\t}\n\n\t@Test\n\tvoid getJsonShouldReturnJson() {\n\t\tJsonContent<ExampleObject> content = new JsonContent<>(getClass(), TYPE, JSON,\n\t\t\t\tConfiguration.defaultConfiguration());\n\t\tassertThat(content.getJson()).isEqualTo(JSON);\n\n\t}\n\n\t@Test\n\tvoid toStringWhenHasTypeShouldReturnString() {\n\t\tJsonContent<ExampleObject> content = new JsonContent<>(getClass(), TYPE, JSON,\n\t\t\t\tConfiguration.defaultConfiguration());\n\t\tassertThat(content.toString()).isEqualTo(\"JsonContent \" + JSON + \" created from \" + TYPE);\n\t}\n\n\t@Test\n\tvoid toStringWhenHasNoTypeShouldReturnString() {\n\t\tJsonContent<ExampleObject> content = new JsonContent<>(getClass(), null, JSON,\n\t\t\t\tConfiguration.defaultConfiguration());\n\t\tassertThat(content.toString()).isEqualTo(\"JsonContent \" + JSON);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/JsonbTesterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.util.List;\n\nimport jakarta.json.bind.Jsonb;\nimport jakarta.json.bind.JsonbBuilder;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link JsonbTester}.\n *\n * @author Eddú Meléndez\n */\nclass JsonbTesterTests extends AbstractJsonMarshalTesterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenTestIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> JsonbTester.initFields(null, JsonbBuilder.create()))\n\t\t\t.withMessageContaining(\"'testInstance' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid initFieldsWhenMarshallerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> JsonbTester.initFields(new InitFieldsTestClass(), (Jsonb) null))\n\t\t\t.withMessageContaining(\"'marshaller' must not be null\");\n\t}\n\n\t@Test\n\tvoid initFieldsShouldSetNullFields() {\n\t\tInitFieldsTestClass test = new InitFieldsTestClass();\n\t\tassertThat(test.test).isNull();\n\t\tassertThat(test.base).isNull();\n\t\tJsonbTester.initFields(test, JsonbBuilder.create());\n\t\tassertThat(test.test).isNotNull();\n\t\tassertThat(test.base).isNotNull();\n\t\tResolvableType type = test.test.getType();\n\t\tassertThat(type).isNotNull();\n\t\tassertThat(type.resolve()).isEqualTo(List.class);\n\t\tassertThat(type.resolveGeneric()).isEqualTo(ExampleObject.class);\n\t}\n\n\t@Override\n\tprotected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {\n\t\treturn new JsonbTester<>(resourceLoadClass, type, JsonbBuilder.create());\n\t}\n\n\tabstract static class InitFieldsBaseClass {\n\n\t\tpublic @Nullable JsonbTester<ExampleObject> base;\n\n\t\tpublic JsonbTester<ExampleObject> baseSet = new JsonbTester<>(InitFieldsBaseClass.class,\n\t\t\t\tResolvableType.forClass(ExampleObject.class), JsonbBuilder.create());\n\n\t}\n\n\tstatic class InitFieldsTestClass extends InitFieldsBaseClass {\n\n\t\tpublic @Nullable JsonbTester<List<ExampleObject>> test;\n\n\t\tpublic JsonbTester<ExampleObject> testSet = new JsonbTester<>(InitFieldsBaseClass.class,\n\t\t\t\tResolvableType.forClass(ExampleObject.class), JsonbBuilder.create());\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/ObjectContentAssertTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.assertj.core.api.AssertProvider;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ObjectContentAssert}.\n *\n * @author Phillip Webb\n */\nclass ObjectContentAssertTests {\n\n\tprivate static final ExampleObject SOURCE = new ExampleObject();\n\n\tprivate static final ExampleObject DIFFERENT;\n\n\tstatic {\n\t\tDIFFERENT = new ExampleObject();\n\t\tDIFFERENT.setAge(123);\n\t}\n\n\t@Test\n\tvoid isEqualToWhenObjectsAreEqualShouldPass() {\n\t\tassertThat(forObject(SOURCE)).isEqualTo(SOURCE);\n\t}\n\n\t@Test\n\tvoid isEqualToWhenObjectsAreDifferentShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> assertThat(forObject(SOURCE)).isEqualTo(DIFFERENT));\n\t}\n\n\t@Test\n\tvoid asArrayForArrayShouldReturnObjectArrayAssert() {\n\t\tExampleObject[] source = new ExampleObject[] { SOURCE };\n\t\tassertThat(forObject(source)).asArray().containsExactly(SOURCE);\n\t}\n\n\t@Test\n\tvoid asArrayForNonArrayShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(forObject(SOURCE)).asArray());\n\t}\n\n\t@Test\n\tvoid asMapForMapShouldReturnMapAssert() {\n\t\tMap<String, ExampleObject> source = Collections.singletonMap(\"a\", SOURCE);\n\t\tassertThat(forObject(source)).asMap().containsEntry(\"a\", SOURCE);\n\t}\n\n\t@Test\n\tvoid asMapForNonMapShouldFail() {\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(forObject(SOURCE)).asMap());\n\t}\n\n\tprivate AssertProvider<ObjectContentAssert<Object>> forObject(Object source) {\n\t\treturn () -> new ObjectContentAssert<>(source);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/json/ObjectContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.json;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.ResolvableType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ObjectContent}.\n *\n * @author Phillip Webb\n */\nclass ObjectContentTests {\n\n\tprivate static final ExampleObject OBJECT = new ExampleObject();\n\n\tprivate static final ResolvableType TYPE = ResolvableType.forClass(ExampleObject.class);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenObjectIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ObjectContent<ExampleObject>(TYPE, null))\n\t\t\t.withMessageContaining(\"'object' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenTypeIsNullShouldCreateContent() {\n\t\tObjectContent<ExampleObject> content = new ObjectContent<>(null, OBJECT);\n\t\tassertThat(content).isNotNull();\n\t}\n\n\t@Test\n\tvoid assertThatShouldReturnObjectContentAssert() {\n\t\tObjectContent<ExampleObject> content = new ObjectContent<>(TYPE, OBJECT);\n\t\tassertThat(content.assertThat()).isInstanceOf(ObjectContentAssert.class);\n\t}\n\n\t@Test\n\tvoid getObjectShouldReturnObject() {\n\t\tObjectContent<ExampleObject> content = new ObjectContent<>(TYPE, OBJECT);\n\t\tassertThat(content.getObject()).isEqualTo(OBJECT);\n\t}\n\n\t@Test\n\tvoid toStringWhenHasTypeShouldReturnString() {\n\t\tObjectContent<ExampleObject> content = new ObjectContent<>(TYPE, OBJECT);\n\t\tassertThat(content.toString()).isEqualTo(\"ObjectContent \" + OBJECT + \" created from \" + TYPE);\n\t}\n\n\t@Test\n\tvoid toStringWhenHasNoTypeShouldReturnString() {\n\t\tObjectContent<ExampleObject> content = new ObjectContent<>(null, OBJECT);\n\t\tassertThat(content.toString()).isEqualTo(\"ObjectContent \" + OBJECT);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/mock/web/SpringBootMockServletContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.mock.web;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.context.SpringBootContextLoader;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.context.web.WebAppConfiguration;\nimport org.springframework.web.context.ServletContextAware;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootMockServletContext}.\n *\n * @author Phillip Webb\n */\n@DirtiesContext\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(loader = SpringBootContextLoader.class)\n@WebAppConfiguration(\"src/test/webapp\")\nclass SpringBootMockServletContextTests implements ServletContextAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletContext servletContext;\n\n\t@Override\n\tpublic void setServletContext(ServletContext servletContext) {\n\t\tthis.servletContext = servletContext;\n\t}\n\n\t@Test\n\tvoid getResourceLocation() throws Exception {\n\t\ttestResource(\"/inwebapp\", \"src/test/webapp\");\n\t\ttestResource(\"/inmetainfresources\", \"/META-INF/resources\");\n\t\ttestResource(\"/inresources\", \"/resources\");\n\t\ttestResource(\"/instatic\", \"/static\");\n\t\ttestResource(\"/inpublic\", \"/public\");\n\t}\n\n\tprivate void testResource(String path, String expectedLocation) throws MalformedURLException {\n\t\tURL resource = this.servletContext.getResource(path);\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.getPath()).contains(expectedLocation);\n\t}\n\n\t// gh-2654\n\t@Test\n\tvoid getRootUrlExistsAndIsEmpty() throws Exception {\n\t\tSpringBootMockServletContext context = new SpringBootMockServletContext(\"src/test/doesntexist\") {\n\t\t\t@Override\n\t\t\tprotected String getResourceLocation(String path) {\n\t\t\t\t// Don't include the Spring Boot defaults for this test\n\t\t\t\treturn getResourceBasePathLocation(path);\n\t\t\t}\n\t\t};\n\t\tURL resource = context.getResource(\"/\");\n\t\tassertThat(resource).isNotNull();\n\t\tFile file = new File(URLDecoder.decode(resource.getPath(), StandardCharsets.UTF_8));\n\t\tassertThat(file).exists().isDirectory();\n\t\tString[] contents = file.list((dir, name) -> !(\".\".equals(name) || \"..\".equals(name)));\n\t\tassertThat(contents).isNotNull();\n\t\tassertThat(contents).isEmpty();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/system/OutputCaptureRuleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\nimport org.junit.Rule;\nimport org.junit.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OutputCaptureRule}.\n *\n * @author Roland Weisleder\n */\n@SuppressWarnings(\"removal\")\npublic class OutputCaptureRuleTests {\n\n\t@Rule\n\tpublic OutputCaptureRule output = new OutputCaptureRule();\n\n\t@Test\n\tpublic void toStringShouldReturnAllCapturedOutput() {\n\t\tSystem.out.println(\"Hello World\");\n\t\tassertThat(this.output.toString()).contains(\"Hello World\");\n\t}\n\n\t@Test\n\tpublic void getAllShouldReturnAllCapturedOutput() {\n\t\tSystem.out.println(\"Hello World\");\n\t\tSystem.err.println(\"Hello Error\");\n\t\tassertThat(this.output.getAll()).contains(\"Hello World\", \"Hello Error\");\n\t}\n\n\t@Test\n\tpublic void getOutShouldOnlyReturnOutputCapturedFromSystemOut() {\n\t\tSystem.out.println(\"Hello World\");\n\t\tSystem.err.println(\"Hello Error\");\n\t\tassertThat(this.output.getOut()).contains(\"Hello World\");\n\t\tassertThat(this.output.getOut()).doesNotContain(\"Hello Error\");\n\t}\n\n\t@Test\n\tpublic void getErrShouldOnlyReturnOutputCapturedFromSystemErr() {\n\t\tSystem.out.println(\"Hello World\");\n\t\tSystem.err.println(\"Hello Error\");\n\t\tassertThat(this.output.getErr()).contains(\"Hello Error\");\n\t\tassertThat(this.output.getErr()).doesNotContain(\"Hello World\");\n\t}\n\n\t@Test\n\tpublic void captureShouldBeAssertable() {\n\t\tSystem.out.println(\"Hello World\");\n\t\tassertThat(this.output).contains(\"Hello World\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/system/OutputCaptureTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.PrintStream;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link OutputCapture}.\n *\n * @author Phillip Webb\n * @author Daniel Schmidt\n */\nclass OutputCaptureTests {\n\n\tprivate PrintStream originalOut;\n\n\tprivate PrintStream originalErr;\n\n\tprivate TestPrintStream systemOut;\n\n\tprivate TestPrintStream systemErr;\n\n\tprivate final TestOutputCapture output = new TestOutputCapture();\n\n\t@BeforeEach\n\tvoid replaceSystemStreams() {\n\t\tthis.originalOut = System.out;\n\t\tthis.originalErr = System.err;\n\t\tthis.systemOut = new TestPrintStream();\n\t\tthis.systemErr = new TestPrintStream();\n\t\tSystem.setOut(this.systemOut);\n\t\tSystem.setErr(this.systemErr);\n\t}\n\n\t@AfterEach\n\tvoid restoreSystemStreams() {\n\t\tSystem.setOut(this.originalOut);\n\t\tSystem.setErr(this.originalErr);\n\t}\n\n\t@Test\n\tvoid pushWhenEmptyStartsCapture() {\n\t\tSystem.out.print(\"A\");\n\t\tthis.output.push();\n\t\tSystem.out.print(\"B\");\n\t\tassertThat(this.output).isEqualTo(\"B\");\n\t}\n\n\t@Test\n\tvoid pushWhenHasExistingStartsNewCapture() {\n\t\tSystem.out.print(\"A\");\n\t\tthis.output.push();\n\t\tSystem.out.print(\"B\");\n\t\tthis.output.push();\n\t\tSystem.out.print(\"C\");\n\t\tassertThat(this.output).isEqualTo(\"BC\");\n\t}\n\n\t@Test\n\tvoid popWhenEmptyThrowsException() {\n\t\tassertThatExceptionOfType(NoSuchElementException.class).isThrownBy(this.output::pop);\n\t}\n\n\t@Test\n\tvoid popWhenHasExistingEndsCapture() {\n\t\tthis.output.push();\n\t\tSystem.out.print(\"A\");\n\t\tthis.output.pop();\n\t\tSystem.out.print(\"B\");\n\t\tassertThat(this.systemOut).hasToString(\"AB\");\n\t}\n\n\t@Test\n\tvoid captureAlsoWritesToSystemOut() {\n\t\tthis.output.push();\n\t\tSystem.out.print(\"A\");\n\t\tassertThat(this.systemOut).hasToString(\"A\");\n\t}\n\n\t@Test\n\tvoid captureAlsoWritesToSystemErr() {\n\t\tthis.output.push();\n\t\tSystem.err.print(\"A\");\n\t\tassertThat(this.systemErr).hasToString(\"A\");\n\t}\n\n\t@Test\n\tvoid lengthReturnsCapturedLength() {\n\t\tthis.output.push();\n\t\tSystem.out.print(\"ABC\");\n\t\tassertThat(this.output).hasSize(3);\n\t}\n\n\t@Test\n\tvoid charAtReturnsCapturedCharAt() {\n\t\tthis.output.push();\n\t\tSystem.out.print(\"ABC\");\n\t\tassertThat(this.output.charAt(1)).isEqualTo('B');\n\t}\n\n\t@Test\n\tvoid subSequenceReturnsCapturedSubSequence() {\n\t\tthis.output.push();\n\t\tSystem.out.print(\"ABC\");\n\t\tassertThat(this.output.subSequence(1, 3)).isEqualTo(\"BC\");\n\t}\n\n\t@Test\n\tvoid getAllReturnsAllCapturedOutput() {\n\t\tpushAndPrint();\n\t\tassertThat(this.output.getAll()).isEqualTo(\"ABC\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsAllCapturedOutput() {\n\t\tpushAndPrint();\n\t\tassertThat(this.output).hasToString(\"ABC\");\n\t}\n\n\t@Test\n\tvoid getErrReturnsOnlyCapturedErrOutput() {\n\t\tpushAndPrint();\n\t\tassertThat(this.output.getErr()).isEqualTo(\"B\");\n\t}\n\n\t@Test\n\tvoid getOutReturnsOnlyCapturedOutOutput() {\n\t\tpushAndPrint();\n\t\tassertThat(this.output.getOut()).isEqualTo(\"AC\");\n\t}\n\n\t@Test\n\tvoid getAllUsesCache() {\n\t\tpushAndPrint();\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tassertThat(this.output.getAll()).isEqualTo(\"ABC\");\n\t\t}\n\t\tassertThat(this.output.buildCount).isOne();\n\t\tSystem.out.print(\"X\");\n\t\tassertThat(this.output.getAll()).isEqualTo(\"ABCX\");\n\t\tassertThat(this.output.buildCount).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid getOutUsesCache() {\n\t\tpushAndPrint();\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tassertThat(this.output.getOut()).isEqualTo(\"AC\");\n\t\t}\n\t\tassertThat(this.output.buildCount).isOne();\n\t\tSystem.out.print(\"X\");\n\t\tassertThat(this.output.getOut()).isEqualTo(\"ACX\");\n\t\tassertThat(this.output.buildCount).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid getErrUsesCache() {\n\t\tpushAndPrint();\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tassertThat(this.output.getErr()).isEqualTo(\"B\");\n\t\t}\n\t\tassertThat(this.output.buildCount).isOne();\n\t\tSystem.err.print(\"X\");\n\t\tassertThat(this.output.getErr()).isEqualTo(\"BX\");\n\t\tassertThat(this.output.buildCount).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid getOutCacheShouldNotReturnStaleDataWhenDataIsLoggedWhileReading() throws Exception {\n\t\tTestLatchedOutputCapture output = new TestLatchedOutputCapture();\n\t\toutput.push();\n\t\tSystem.out.print(\"A\");\n\t\tExecutorService executor = Executors.newFixedThreadPool(2);\n\t\ttry {\n\t\t\tFuture<?> reader = executor.submit(output::releaseAfterBuildAndAssertResultIsA);\n\t\t\tFuture<?> writer = executor.submit(output::awaitReleaseAfterBuildThenWriteBAndRelease);\n\t\t\treader.get();\n\t\t\twriter.get();\n\t\t}\n\t\tfinally {\n\t\t\texecutor.shutdown();\n\t\t\texecutor.awaitTermination(10, TimeUnit.SECONDS);\n\t\t}\n\t\tassertThat(output.getOut()).isEqualTo(\"AB\");\n\t}\n\n\tprivate void pushAndPrint() {\n\t\tthis.output.push();\n\t\tSystem.out.print(\"A\");\n\t\tSystem.err.print(\"B\");\n\t\tSystem.out.print(\"C\");\n\t}\n\n\tstatic class TestPrintStream extends PrintStream {\n\n\t\tTestPrintStream() {\n\t\t\tsuper(new ByteArrayOutputStream());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.out.toString();\n\t\t}\n\n\t}\n\n\tstatic class TestOutputCapture extends OutputCapture {\n\n\t\tint buildCount;\n\n\t\t@Override\n\t\tString build(Predicate<Type> filter) {\n\t\t\tthis.buildCount++;\n\t\t\treturn super.build(filter);\n\t\t}\n\n\t}\n\n\tstatic class TestLatchedOutputCapture extends OutputCapture {\n\n\t\tprivate final CountDownLatch waitAfterBuild = new CountDownLatch(1);\n\n\t\tprivate final CountDownLatch releaseAfterBuild = new CountDownLatch(1);\n\n\t\t@Override\n\t\tString build(Predicate<Type> filter) {\n\t\t\tvar result = super.build(filter);\n\t\t\tthis.releaseAfterBuild.countDown();\n\t\t\tawait(this.waitAfterBuild);\n\t\t\treturn result;\n\t\t}\n\n\t\tvoid releaseAfterBuildAndAssertResultIsA() {\n\t\t\tassertThat(getOut()).isEqualTo(\"A\");\n\t\t}\n\n\t\tvoid awaitReleaseAfterBuildThenWriteBAndRelease() {\n\t\t\tawait(this.releaseAfterBuild);\n\t\t\tSystem.out.print(\"B\");\n\t\t\tthis.waitAfterBuild.countDown();\n\t\t}\n\n\t\tprivate void await(CountDownLatch latch) {\n\t\t\ttry {\n\t\t\t\tlatch.await();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/system/OutputExtensionExtendWithTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.system;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.BeforeAllCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OutputCaptureExtension} when used through\n * {@link ExtendWith @ExtendWith}.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ExtendWith(OutputExtensionExtendWithTests.BeforeAllExtension.class)\n@ExtendWith(OutputExtensionExtendWithTests.BeforeEachExtension.class)\nclass OutputExtensionExtendWithTests {\n\n\t@Test\n\tvoid captureShouldReturnOutputCapturedBeforeAllTestMethod(CapturedOutput output) {\n\t\tassertThat(output).contains(\"Before all\").doesNotContain(\"Hello\");\n\t}\n\n\t@Test\n\tvoid captureShouldReturnOutputCapturedBeforeEachTestMethod(CapturedOutput output) {\n\t\tassertThat(output).contains(\"Before each\").doesNotContain(\"Hello\");\n\t}\n\n\t@Test\n\tvoid captureShouldReturnAllCapturedOutput(CapturedOutput output) {\n\t\tSystem.out.println(\"Hello World\");\n\t\tSystem.err.println(\"Error!!!\");\n\t\tassertThat(output).contains(\"Before all\").contains(\"Before each\").contains(\"Hello World\").contains(\"Error!!!\");\n\t}\n\n\tstatic class BeforeAllExtension implements BeforeAllCallback {\n\n\t\t@Override\n\t\tpublic void beforeAll(ExtensionContext context) {\n\t\t\tSystem.out.println(\"Before all\");\n\t\t}\n\n\t}\n\n\tstatic class BeforeEachExtension implements BeforeEachCallback {\n\n\t\t@Override\n\t\tpublic void beforeEach(ExtensionContext context) {\n\t\t\tSystem.out.println(\"Before each\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/util/ApplicationContextTestUtilsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ApplicationContextTestUtils}.\n *\n * @author Stephane Nicoll\n */\nclass ApplicationContextTestUtilsTests {\n\n\t@Test\n\tvoid closeNull() {\n\t\tApplicationContextTestUtils.closeAll(null);\n\t}\n\n\t@Test\n\tvoid closeNonClosableContext() {\n\t\tApplicationContext mock = mock(ApplicationContext.class);\n\t\tApplicationContextTestUtils.closeAll(mock);\n\t}\n\n\t@Test\n\tvoid closeContextAndParent() {\n\t\tConfigurableApplicationContext mock = mock(ConfigurableApplicationContext.class);\n\t\tConfigurableApplicationContext parent = mock(ConfigurableApplicationContext.class);\n\t\tgiven(mock.getParent()).willReturn(parent);\n\t\tgiven(parent.getParent()).willReturn(null);\n\t\tApplicationContextTestUtils.closeAll(mock);\n\t\tthen(mock).should().getParent();\n\t\tthen(mock).should().close();\n\t\tthen(parent).should().getParent();\n\t\tthen(parent).should().close();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/util/TestPropertyValuesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.util;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues.Pair;\nimport org.springframework.boot.test.util.TestPropertyValues.Type;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.env.SystemEnvironmentPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link TestPropertyValues}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass TestPropertyValuesTests {\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\t@Test\n\tvoid ofStringArrayCreatesValues() {\n\t\tTestPropertyValues.of(\"spring:boot\", \"version:latest\").applyTo(this.environment);\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(this.environment.getProperty(\"version\")).isEqualTo(\"latest\");\n\t}\n\n\t@Test\n\tvoid ofIterableCreatesValues() {\n\t\tTestPropertyValues.of(Arrays.asList(\"spring:boot\", \"version:latest\")).applyTo(this.environment);\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(this.environment.getProperty(\"version\")).isEqualTo(\"latest\");\n\t}\n\n\t@Test\n\tvoid ofStreamCreatesValues() {\n\t\tTestPropertyValues.of(Stream.of(\"spring:boot\", \"version:latest\")).applyTo(this.environment);\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(this.environment.getProperty(\"version\")).isEqualTo(\"latest\");\n\t}\n\n\t@Test\n\tvoid ofMapCreatesValues() {\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"spring\", \"boot\");\n\t\tmap.put(\"version\", \"latest\");\n\t\tTestPropertyValues.of(map).applyTo(this.environment);\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(this.environment.getProperty(\"version\")).isEqualTo(\"latest\");\n\t}\n\n\t@Test\n\tvoid ofMappedStreamCreatesValues() {\n\t\tTestPropertyValues.of(Stream.of(\"spring|boot\", \"version|latest\"), (string) -> {\n\t\t\tString[] split = string.split(\"\\\\|\");\n\t\t\treturn Pair.of(split[0], split[1]);\n\t\t}).applyTo(this.environment);\n\t\tassertThat(this.environment.getProperty(\"spring\")).isEqualTo(\"boot\");\n\t\tassertThat(this.environment.getProperty(\"version\")).isEqualTo(\"latest\");\n\t}\n\n\t@Test\n\tvoid applyToEnvironmentShouldAttachConfigurationPropertySource() {\n\t\tTestPropertyValues.of(\"foo.bar=baz\").applyTo(this.environment);\n\t\tPropertySource<?> source = this.environment.getPropertySources().get(\"configurationProperties\");\n\t\tassertThat(source).isNotNull();\n\t}\n\n\t@Test\n\tvoid applyToDefaultPropertySource() {\n\t\tTestPropertyValues.of(\"foo.bar=baz\", \"hello.world=hi\").applyTo(this.environment);\n\t\tassertThat(this.environment.getProperty(\"foo.bar\")).isEqualTo(\"baz\");\n\t\tassertThat(this.environment.getProperty(\"hello.world\")).isEqualTo(\"hi\");\n\t}\n\n\t@Test\n\tvoid applyToSystemPropertySource() {\n\t\tTestPropertyValues.of(\"FOO_BAR=BAZ\").applyTo(this.environment, Type.SYSTEM_ENVIRONMENT);\n\t\tassertThat(this.environment.getProperty(\"foo.bar\")).isEqualTo(\"BAZ\");\n\t\tassertThat(this.environment.getPropertySources()\n\t\t\t.contains(\"test-\" + StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)).isTrue();\n\t}\n\n\t@Test\n\tvoid applyToWithSpecificName() {\n\t\tTestPropertyValues.of(\"foo.bar=baz\").applyTo(this.environment, Type.MAP, \"other\");\n\t\tassertThat(this.environment.getPropertySources().get(\"other\")).isNotNull();\n\t\tassertThat(this.environment.getProperty(\"foo.bar\")).isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tvoid applyToExistingNameAndDifferentTypeShouldOverrideExistingOne() {\n\t\tTestPropertyValues.of(\"foo.bar=baz\", \"hello.world=hi\").applyTo(this.environment, Type.MAP, \"other\");\n\t\tTestPropertyValues.of(\"FOO_BAR=BAZ\").applyTo(this.environment, Type.SYSTEM_ENVIRONMENT, \"other\");\n\t\tassertThat(this.environment.getPropertySources().get(\"other\"))\n\t\t\t.isInstanceOf(SystemEnvironmentPropertySource.class);\n\t\tassertThat(this.environment.getProperty(\"foo.bar\")).isEqualTo(\"BAZ\");\n\t\tassertThat(this.environment.getProperty(\"hello.world\")).isNull();\n\t}\n\n\t@Test\n\tvoid applyToExistingNameAndSameTypeShouldMerge() {\n\t\tTestPropertyValues.of(\"foo.bar=baz\", \"hello.world=hi\").applyTo(this.environment, Type.MAP);\n\t\tTestPropertyValues.of(\"foo.bar=new\").applyTo(this.environment, Type.MAP);\n\t\tassertThat(this.environment.getProperty(\"foo.bar\")).isEqualTo(\"new\");\n\t\tassertThat(this.environment.getProperty(\"hello.world\")).isEqualTo(\"hi\");\n\t}\n\n\t@Test\n\tvoid andShouldChainAndAddSingleKeyValue() {\n\t\tTestPropertyValues.of(\"foo.bar=baz\")\n\t\t\t.and(\"hello.world=hi\")\n\t\t\t.and(\"bling.blah=bing\")\n\t\t\t.applyTo(this.environment, Type.MAP);\n\t\tassertThat(this.environment.getProperty(\"foo.bar\")).isEqualTo(\"baz\");\n\t\tassertThat(this.environment.getProperty(\"hello.world\")).isEqualTo(\"hi\");\n\t\tassertThat(this.environment.getProperty(\"bling.blah\")).isEqualTo(\"bing\");\n\t}\n\n\t@Test\n\tvoid applyToSystemPropertiesWithCallableShouldSetSystemProperties() {\n\t\tTestPropertyValues.of(\"foo=bar\").applyToSystemProperties(() -> {\n\t\t\tassertThat(System.getProperty(\"foo\")).isEqualTo(\"bar\");\n\t\t\treturn null;\n\t\t});\n\t}\n\n\t@Test\n\tvoid applyToSystemPropertiesWithRunnableShouldSetSystemProperties() {\n\t\tTestPropertyValues.of(\"foo=bar\")\n\t\t\t.applyToSystemProperties(() -> assertThat(System.getProperty(\"foo\")).isEqualTo(\"bar\"));\n\t}\n\n\t@Test\n\tvoid applyToSystemPropertiesShouldRestoreSystemProperties() {\n\t\tSystem.setProperty(\"foo\", \"bar1\");\n\t\tSystem.clearProperty(\"baz\");\n\t\ttry {\n\t\t\tTestPropertyValues.of(\"foo=bar2\", \"baz=bing\").applyToSystemProperties(() -> {\n\t\t\t\tassertThat(System.getProperty(\"foo\")).isEqualTo(\"bar2\");\n\t\t\t\tassertThat(System.getProperty(\"baz\")).isEqualTo(\"bing\");\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\tassertThat(System.getProperty(\"foo\")).isEqualTo(\"bar1\");\n\t\t\tassertThat(System.getProperties()).doesNotContainKey(\"baz\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"foo\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid applyToSystemPropertiesWhenValueIsNullShouldRemoveProperty() {\n\t\tSystem.setProperty(\"foo\", \"bar1\");\n\t\ttry {\n\t\t\tTestPropertyValues.of(\"foo\").applyToSystemProperties(() -> {\n\t\t\t\tassertThat(System.getProperties()).doesNotContainKey(\"foo\");\n\t\t\t\treturn null;\n\t\t\t});\n\t\t\tassertThat(System.getProperty(\"foo\")).isEqualTo(\"bar1\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"foo\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid pairOfCreatesPair() {\n\t\tMap<String, @Nullable Object> map = new LinkedHashMap<>();\n\t\tPair pair = Pair.of(\"spring\", \"boot\");\n\t\tassertThat(pair).isNotNull();\n\t\tpair.addTo(map);\n\t\tassertThat(map).containsOnly(entry(\"spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid pairOfWhenNameAndValueAreEmptyReturnsPair() {\n\t\tassertThat(Pair.of(\"\", \"\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid pairFromMapEntryCreatesPair() {\n\t\tMap<String, @Nullable Object> map = new LinkedHashMap<>();\n\t\tPair pair = Pair.fromMapEntry(entry(\"spring\", \"boot\"));\n\t\tassertThat(pair).isNotNull();\n\t\tpair.addTo(map);\n\t\tassertThat(map).containsOnly(entry(\"spring\", \"boot\"));\n\t}\n\n\t@Test\n\tvoid pairFromMapEntryWithEmptyKeyCreatesPair() {\n\t\tMap<String, @Nullable Object> map = new LinkedHashMap<>();\n\t\tPair pair = Pair.fromMapEntry(entry(\"\", \"empty-key\"));\n\t\tassertThat(pair).isNotNull();\n\t\tpair.addTo(map);\n\t\tassertThat(map).containsOnly(entry(\"\", \"empty-key\"));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebClientTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.htmlunit;\n\nimport java.io.IOException;\nimport java.net.URL;\n\nimport org.htmlunit.StringWebResponse;\nimport org.htmlunit.WebClient;\nimport org.htmlunit.WebConnection;\nimport org.htmlunit.WebResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link UriBuilderFactoryWebClient}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"resource\")\nclass UriBuilderFactoryWebClientTests {\n\n\t@Test\n\tvoid getPageWhenUriIsRelativeUsesBuilder() throws Exception {\n\t\tWebClient client = new UriBuilderFactoryWebClient(new DefaultUriBuilderFactory(\"https://localhost:8080\"));\n\t\tWebConnection connection = mockConnection();\n\t\tclient.setWebConnection(connection);\n\t\tclient.getPage(\"/test\");\n\t\tthenConnectionRequests(connection, new URL(\"https://localhost:8080/test\"));\n\t}\n\n\t@Test\n\tvoid getPageWhenUriIsNotRelativeUsesUri() throws Exception {\n\t\tWebClient client = new UriBuilderFactoryWebClient(new DefaultUriBuilderFactory(\"https://localhost\"));\n\t\tWebConnection connection = mockConnection();\n\t\tclient.setWebConnection(connection);\n\t\tclient.getPage(\"https://example.com:9000/test\");\n\t\tthenConnectionRequests(connection, new URL(\"https://example.com:9000/test\"));\n\t}\n\n\tprivate void thenConnectionRequests(WebConnection connection, URL url) throws IOException {\n\t\tthen(connection).should().getResponse(assertArg((request) -> assertThat(request.getUrl()).isEqualTo(url)));\n\t}\n\n\tprivate WebConnection mockConnection() throws IOException {\n\t\tWebConnection connection = mock(WebConnection.class);\n\t\tWebResponse response = new StringWebResponse(\"test\", new URL(\"http://localhost\"));\n\t\tgiven(connection.getResponse(any())).willReturn(response);\n\t\treturn connection;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebConnectionHtmlUnitDriverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.htmlunit;\n\nimport java.net.URL;\n\nimport org.htmlunit.TopLevelWindow;\nimport org.htmlunit.WebClient;\nimport org.htmlunit.WebClientOptions;\nimport org.htmlunit.WebConsole;\nimport org.htmlunit.WebRequest;\nimport org.htmlunit.WebWindow;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentMatcher;\n\nimport org.springframework.test.web.servlet.htmlunit.webdriver.WebConnectionHtmlUnitDriver;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriBuilderFactory;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link UriBuilderFactoryWebConnectionHtmlUnitDriver}.\n *\n * @author Phillip Webb\n */\nclass UriBuilderFactoryWebConnectionHtmlUnitDriverTests {\n\n\tprivate final WebClient webClient;\n\n\tUriBuilderFactoryWebConnectionHtmlUnitDriverTests() {\n\t\tthis.webClient = mock();\n\t\tgiven(this.webClient.getOptions()).willReturn(new WebClientOptions());\n\t\tgiven(this.webClient.getWebConsole()).willReturn(new WebConsole());\n\t\tWebWindow currentWindow = mock(WebWindow.class);\n\t\tgiven(currentWindow.isClosed()).willReturn(false);\n\t\tgiven(this.webClient.getCurrentWindow()).willReturn(currentWindow);\n\t}\n\n\t@Test\n\tvoid getWhenUrlIsRelativeUsesBaseUrl() throws Exception {\n\t\tWebConnectionHtmlUnitDriver driver = new TestUriBuilderFactoryWebConnectionHtmlUnitDriver(\n\t\t\t\tnew DefaultUriBuilderFactory(\"https://localhost:8080\"));\n\t\tdriver.get(\"/test\");\n\t\tthen(this.webClient).should()\n\t\t\t.getPage(any(TopLevelWindow.class), requestToUrl(new URL(\"https://localhost:8080/test\")));\n\t}\n\n\tprivate WebRequest requestToUrl(URL url) {\n\t\treturn argThat(new WebRequestUrlArgumentMatcher(url));\n\t}\n\n\tclass TestUriBuilderFactoryWebConnectionHtmlUnitDriver extends UriBuilderFactoryWebConnectionHtmlUnitDriver {\n\n\t\tTestUriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory) {\n\t\t\tsuper(uriBuilderFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic WebClient getWebClient() {\n\t\t\treturn UriBuilderFactoryWebConnectionHtmlUnitDriverTests.this.webClient;\n\t\t}\n\n\t}\n\n\tprivate static final class WebRequestUrlArgumentMatcher implements ArgumentMatcher<WebRequest> {\n\n\t\tprivate final URL expectedUrl;\n\n\t\tprivate WebRequestUrlArgumentMatcher(URL expectedUrl) {\n\t\t\tthis.expectedUrl = expectedUrl;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(WebRequest argument) {\n\t\t\treturn argument.getUrl().equals(this.expectedUrl);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/web/server/LocalManagementPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.server;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LocalManagementPort @LocalManagementPort}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(SpringExtension.class)\n@TestPropertySource(properties = \"local.management.port=8181\")\nclass LocalManagementPortTests {\n\n\t@Value(\"${local.management.port}\")\n\tprivate @Nullable String fromValue;\n\n\t@LocalManagementPort\n\tprivate @Nullable String fromAnnotation;\n\n\t@Test\n\tvoid testLocalManagementPortAnnotation() {\n\t\tassertThat(this.fromAnnotation).isNotNull().isEqualTo(this.fromValue);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/java/org/springframework/boot/test/web/server/LocalServerPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.web.server;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LocalServerPort @LocalServerPort}.\n *\n * @author Anand Shah\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@TestPropertySource(properties = \"local.server.port=8181\")\nclass LocalServerPortTests {\n\n\t@Value(\"${local.server.port}\")\n\tprivate @Nullable String fromValue;\n\n\t@LocalServerPort\n\tprivate @Nullable String fromAnnotation;\n\n\t@Test\n\tvoid testLocalServerPortAnnotation() {\n\t\tassertThat(this.fromAnnotation).isNotNull().isEqualTo(this.fromValue);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/kotlin/org/springframework/boot/test/context/KotlinApplicationWithMainThrowingException.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context\n\nimport org.springframework.boot.SpringBootConfiguration\nimport org.springframework.boot.runApplication\n\n@SpringBootConfiguration(proxyBeanMethods = false)\nopen class KotlinApplicationWithMainThrowingException\n\nfun main(args: Array<String>) {\n\trunApplication<KotlinApplicationWithMainThrowingException>(*args)\n\tthrow IllegalStateException(\"ThrownFromMain\")\n}\n\n"
  },
  {
    "path": "core/spring-boot-test/src/test/kotlin/org/springframework/boot/test/context/SpringBootContextLoaderKotlinTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.context\n\nimport org.assertj.core.api.Assertions.assertThatIllegalStateException\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod\nimport org.springframework.test.context.TestContext\nimport org.springframework.test.context.TestContextManager\n\n/**\n * Kotlin tests for [SpringBootContextLoader].\n */\nclass SpringBootContextLoaderKotlinTests {\n\n\t@Test\n\tfun `when UseMainMethod ALWAYS and main method throws exception`() {\n\t\tval testContext = ExposedTestContextManager(\n\t\t\tUseMainMethodAlwaysAndKotlinMainMethodThrowsException::class.java\n\t\t).exposedTestContext\n\t\tassertThatIllegalStateException().isThrownBy { testContext.applicationContext }\n\t\t\t.havingCause()\n\t\t\t.withMessageContaining(\"ThrownFromMain\")\n\t}\n\n\t/**\n\t * [TestContextManager] which exposes the [TestContext].\n\t */\n\tinternal class ExposedTestContextManager(testClass: Class<*>) : TestContextManager(testClass) {\n\t\tval exposedTestContext: TestContext\n\t\t\tget() = super.getTestContext()\n\t}\n\n\t@SpringBootTest(classes = [KotlinApplicationWithMainThrowingException::class], useMainMethod = UseMainMethod.ALWAYS)\n\tinternal class UseMainMethodAlwaysAndKotlinMainMethodThrowsException\n\n}\n\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/META-INF/resources/inmetainfresources",
    "content": "\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.test.context.DefaultTestExecutionListenersPostProcessor=\\\norg.springframework.boot.test.context.bootstrap.TestDefaultTestExecutionListenersPostProcessor\n\norg.springframework.test.context.ApplicationContextFailureProcessor=\\\norg.springframework.boot.test.context.SpringBootContextLoaderTests.ContextLoaderApplicationContextFailureProcessor"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/application.properties",
    "content": "foo: bucket\nvalue: 1234\nmy.property: fromapplicationproperties\nsample.app.test.prop: *\nmy.placeholder: ${my.fallback}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/custom-config-name.properties",
    "content": "test.foo=bar\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/SpringApplicationConfigurationGroovyConventionConfigurationTestsContext.groovy",
    "content": "beans {\n\tfoo String, \"World\"\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/SpringApplicationConfigurationXmlConventionConfigurationTests-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\n\t\t\t\thttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\n\t<bean id=\"foo\" class=\"java.lang.String\">\n\t\t<constructor-arg>\n\t\t\t<value>World</value>\n\t\t</constructor-arg>\n\t</bean>\n\n</beans>\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/context/FilteredClassLoaderTestsResource.txt",
    "content": "Used by FilteredClassLoaderTests.java"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/context/SpringBootTestGroovyConventionConfigurationTestsContext.groovy",
    "content": "beans {\n\tfoo String, \"World\"\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/context/SpringBootTestXmlConventionConfigurationTests-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\n\t\t\t\thttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\n\t<bean id=\"foo\" class=\"java.lang.String\">\n\t\t<constructor-arg>\n\t\t\t<value>World</value>\n\t\t</constructor-arg>\n\t</bean>\n\n</beans>\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/different.json",
    "content": "{\n   \"gnirps\":[\n      \"boot\",\n      \"framework\"\n   ]\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/example.json",
    "content": "{\n   \"name\" : \"Spring\",\n   \"age\" : 123\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/lenient-same.json",
    "content": "{\n   \"spring\":[\n      \"framework\",\n      \"boot\"\n   ]\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/nulls.json",
    "content": "{\n   \"valuename\" : \"spring\",\n   \"nullname\" : null\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/simpsons.json",
    "content": "{\n   \"familyMembers\":[\n      {\n         \"name\":\"Homer\"\n      },\n      {\n         \"name\":\"Marge\"\n      },\n      {\n         \"name\":\"Bart\"\n      },\n      {\n         \"name\":\"Lisa\"\n      },\n      {\n         \"name\":\"Maggie\"\n      }\n   ]\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/source.json",
    "content": "{\n   \"spring\":[\n      \"boot\",\n      \"framework\"\n   ]\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/org/springframework/boot/test/json/types.json",
    "content": "{\n   \"str\":\"foo\",\n   \"num\":5,\n   \"bool\":true,\n   \"arr\":[\n      42\n   ],\n   \"colorMap\":{\n      \"red\":\"rojo\"\n   },\n   \"whitespace\":\"    \",\n   \"emptyString\":\"\",\n   \"emptyArray\":[\n\n   ],\n   \"emptyMap\":{\n\n   }\n}\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/public/inpublic",
    "content": "\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/resources/inresources",
    "content": "\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/static/instatic",
    "content": "\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/test-property-source-annotation.properties",
    "content": "property-source-location=baz\na=property-source-location\nb=property-source-location\n"
  },
  {
    "path": "core/spring-boot-test/src/test/resources/test.groovy",
    "content": "beans {\n  foo String, \"World\"\n}"
  },
  {
    "path": "core/spring-boot-test/src/test/webapp/inwebapp",
    "content": "\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-metadata\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Test AutoConfigure\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test\"))\n\n\tcompileOnly(\"org.mockito:mockito-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"jakarta.json.bind:jakarta.json.bind-api\")\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"ch.qos.logback:logback-classic\")\n\ttestImplementation(\"org.junit.platform:junit-platform-launcher\")\n\n\ttestRuntimeOnly(\"org.aspectj:aspectjrt\")\n\ttestRuntimeOnly(\"org.aspectj:aspectjweaver\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/OnFailureConditionReportContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.MergedContextConfiguration;\n\n/**\n * {@link ContextCustomizerFactory} that customizes the {@link ApplicationContext\n * application context} such that a {@link ConditionEvaluationReport condition evaluation\n * report} is output when the application under test {@link ApplicationFailedEvent fails\n * to start}.\n *\n * @author Andy Wilkinson\n */\nclass OnFailureConditionReportContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\treturn new OnFailureConditionReportContextCustomizer();\n\t}\n\n\tstatic class OnFailureConditionReportContextCustomizer implements ContextCustomizer {\n\n\t\t@Override\n\t\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\t\tSupplier<ConditionEvaluationReport> reportSupplier;\n\t\t\tif (context instanceof GenericApplicationContext) {\n\t\t\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());\n\t\t\t\treportSupplier = () -> report;\n\t\t\t}\n\t\t\telse {\n\t\t\t\treportSupplier = () -> ConditionEvaluationReport.get(context.getBeanFactory());\n\t\t\t}\n\t\t\tcontext.addApplicationListener(new ApplicationFailureListener(reportSupplier));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\treturn (obj != null) && (obj.getClass() == getClass());\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn getClass().hashCode();\n\t\t}\n\n\t}\n\n\tprivate static final class ApplicationFailureListener implements ApplicationListener<ApplicationFailedEvent> {\n\n\t\tprivate final Supplier<ConditionEvaluationReport> reportSupplier;\n\n\t\tprivate ApplicationFailureListener(Supplier<ConditionEvaluationReport> reportSupplier) {\n\t\t\tthis.reportSupplier = reportSupplier;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationFailedEvent event) {\n\t\t\tif (shouldPrintReport(event.getApplicationContext())) {\n\t\t\t\tSystem.err.println(new ConditionEvaluationReportMessage(this.reportSupplier.get()));\n\t\t\t}\n\t\t}\n\n\t\tprivate static boolean shouldPrintReport(@Nullable ConfigurableApplicationContext context) {\n\t\t\treturn (context == null) || context.getEnvironment()\n\t\t\t\t.getProperty(\"spring.test.print-condition-evaluation-report\", Boolean.class, true);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Annotation that can be used to override\n * {@link EnableAutoConfiguration @EnableAutoConfiguration}. Often used in combination\n * with {@link ImportAutoConfiguration @ImportAutoConfiguration} to limit the\n * auto-configuration classes that are loaded.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see EnableAutoConfiguration#ENABLED_OVERRIDE_PROPERTY\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface OverrideAutoConfiguration {\n\n\t/**\n\t * The value of the {@link EnableAutoConfiguration#ENABLED_OVERRIDE_PROPERTY enabled\n\t * override property}.\n\t * @return the override value\n\t */\n\tboolean enabled();\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextAnnotationUtils;\n\n/**\n * {@link ContextCustomizerFactory} to support\n * {@link OverrideAutoConfiguration @OverrideAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass OverrideAutoConfigurationContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configurationAttributes) {\n\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn null;\n\t\t}\n\t\tOverrideAutoConfiguration overrideAutoConfiguration = TestContextAnnotationUtils.findMergedAnnotation(testClass,\n\t\t\t\tOverrideAutoConfiguration.class);\n\t\tboolean enabled = (overrideAutoConfiguration == null) || overrideAutoConfiguration.enabled();\n\t\treturn !enabled ? new DisableAutoConfigurationContextCustomizer() : null;\n\t}\n\n\t/**\n\t * {@link ContextCustomizer} to disable full auto-configuration.\n\t */\n\tprivate static final class DisableAutoConfigurationContextCustomizer implements ContextCustomizer {\n\n\t\t@Override\n\t\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\t\tTestPropertyValues.of(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY + \"=false\").applyTo(context);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object obj) {\n\t\t\treturn (obj != null) && (obj.getClass() == getClass());\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn getClass().hashCode();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/TestSliceTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.test.context.TestContextAnnotationUtils;\nimport org.springframework.test.context.TestContextBootstrapper;\nimport org.springframework.util.Assert;\n\n/**\n * Base class for test slice {@link TestContextBootstrapper test context bootstrappers}.\n *\n * @param <T> the test slice annotation\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic abstract class TestSliceTestContextBootstrapper<T extends Annotation> extends SpringBootTestContextBootstrapper {\n\n\tprivate final Class<T> annotationType;\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected TestSliceTestContextBootstrapper() {\n\t\tClass<T> annotationType = (Class<T>) ResolvableType.forClass(getClass())\n\t\t\t.as(TestSliceTestContextBootstrapper.class)\n\t\t\t.getGeneric(0)\n\t\t\t.resolve();\n\t\tAssert.notNull(annotationType, \"'%s' doesn't contain type parameter of '%s'\".formatted(getClass().getName(),\n\t\t\t\tTestSliceTestContextBootstrapper.class.getName()));\n\t\tthis.annotationType = annotationType;\n\t}\n\n\t@Override\n\tprotected String @Nullable [] getProperties(Class<?> testClass) {\n\t\tMergedAnnotation<T> annotation = MergedAnnotations.search(SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.withEnclosingClasses(TestContextAnnotationUtils::searchEnclosingClass)\n\t\t\t.from(testClass)\n\t\t\t.get(this.annotationType);\n\t\treturn annotation.isPresent() ? annotation.getStringArray(\"properties\") : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/AutoConfigureDataSourceInitialization.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.jdbc;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Annotation that can be applied to a test class to enable DataSource initialization.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataSourceInitialization {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/jdbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for core JDBC test concerns.\n */\n@NullMarked\npackage org.springframework.boot.test.autoconfigure.jdbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/AutoConfigureJson.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical JSON tests. Most\n * tests should consider using {@link JsonTest @JsonTest} rather than using this\n * annotation directly.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see JsonTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureJson {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/AutoConfigureJsonTesters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.boot.test.json.BasicJsonTester;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.boot.test.json.JsonbTester;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of JSON testers.\n *\n * @author Phillip Webb\n * @since 1.4.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJson\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.jsontesters\")\npublic @interface AutoConfigureJsonTesters {\n\n\t/**\n\t * If {@link BasicJsonTester}, {@link JacksonTester}, {@link JsonbTester} and\n\t * {@link GsonTester} beans should be registered. Defaults to {@code true}.\n\t * @return if tester support is enabled\n\t */\n\tboolean enabled() default true;\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/ConditionalOnJsonTesters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks if JSON testers are enabled.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ConditionalOnBooleanProperty(\"spring.test.jsontesters.enabled\")\n@ConditionalOnClass(name = \"org.assertj.core.api.Assert\")\npublic @interface ConditionalOnJsonTesters {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonMarshalTesterRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.test.json.AbstractJsonMarshalTester;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Base class for {@link AbstractJsonMarshalTester} runtime hints.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@SuppressWarnings(\"rawtypes\")\npublic abstract class JsonMarshalTesterRuntimeHints implements RuntimeHintsRegistrar {\n\n\tprivate final Class<? extends AbstractJsonMarshalTester> tester;\n\n\tprotected JsonMarshalTesterRuntimeHints(Class<? extends AbstractJsonMarshalTester> tester) {\n\t\tthis.tester = tester;\n\t}\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tReflectionHints reflection = hints.reflection();\n\t\treflection.registerType(this.tester, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\tMethod method = ReflectionUtils.findMethod(this.tester, \"initialize\", Class.class, ResolvableType.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\treflection.registerMethod(method, ExecutableMode.INVOKE);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.boot.test.json.JsonbTester;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation for a JSON test that focuses <strong>only</strong> on JSON serialization.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to JSON tests.\n * Similarly, component scanning is limited to beans annotated with:\n * <ul>\n * <li>{@code @JacksonComponent}</li>\n * </ul>\n * <p>\n * as well as beans that implement:\n * <ul>\n * <li>{@code JacksonModule}, if Jackson is available</li>\n * </ul>\n * <p>\n * By default, tests annotated with {@code JsonTest} will also initialize\n * {@link JacksonTester}, {@link JsonbTester} and {@link GsonTester} fields. More\n * fine-grained control can be provided through the\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters} annotation.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @see AutoConfigureJson\n * @see AutoConfigureJsonTesters\n * @since 1.4.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(JsonTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(JsonTypeExcludeFilter.class)\n@AutoConfigureJsonTesters\n@ImportAutoConfiguration\npublic @interface JsonTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t * @since 2.1.0\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default, only\n\t * {@code @JacksonComponent} and {@code JacksonModule} beans are included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link JsonTest @JsonTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass JsonTestContextBootstrapper extends TestSliceTestContextBootstrapper<JsonTest> {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTesterFactoryBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.reflect.Constructor;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link FactoryBean} used to create JSON Tester instances.\n *\n * @param <T> the object type\n * @param <M> the marshaller type\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class JsonTesterFactoryBean<T, M> implements FactoryBean<T> {\n\n\tprivate final Class<?> objectType;\n\n\tprivate final @Nullable M marshaller;\n\n\tpublic JsonTesterFactoryBean(Class<?> objectType, @Nullable M marshaller) {\n\t\tthis.objectType = objectType;\n\t\tthis.marshaller = marshaller;\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn false;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic T getObject() throws Exception {\n\t\tif (this.marshaller == null) {\n\t\t\tConstructor<?> constructor = this.objectType.getDeclaredConstructor();\n\t\t\tReflectionUtils.makeAccessible(constructor);\n\t\t\treturn (T) BeanUtils.instantiateClass(constructor);\n\t\t}\n\t\tConstructor<?>[] constructors = this.objectType.getDeclaredConstructors();\n\t\tfor (Constructor<?> constructor : constructors) {\n\t\t\tif (constructor.getParameterCount() == 1\n\t\t\t\t\t&& constructor.getParameterTypes()[0].isInstance(this.marshaller)) {\n\t\t\t\tReflectionUtils.makeAccessible(constructor);\n\t\t\t\treturn (T) BeanUtils.instantiateClass(constructor, this.marshaller);\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(this.objectType + \" does not have a usable constructor\");\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn this.objectType;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTestersAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.test.json.AbstractJsonMarshalTester;\nimport org.springframework.boot.test.json.BasicJsonTester;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Auto-configuration for Json testers.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @since 1.4.0\n * @see AutoConfigureJsonTesters\n */\n@AutoConfiguration\n@ConditionalOnJsonTesters\npublic final class JsonTestersAutoConfiguration {\n\n\t@Bean\n\tstatic JsonMarshalTestersBeanPostProcessor jsonMarshalTestersBeanPostProcessor() {\n\t\treturn new JsonMarshalTestersBeanPostProcessor();\n\t}\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ImportRuntimeHints(BasicJsonTesterRuntimeHints.class)\n\tFactoryBean<BasicJsonTester> basicJsonTesterFactoryBean() {\n\t\treturn new JsonTesterFactoryBean<BasicJsonTester, Void>(BasicJsonTester.class, null);\n\t}\n\n\t/**\n\t * {@link BeanPostProcessor} used to initialize JSON testers.\n\t */\n\tstatic class JsonMarshalTestersBeanPostProcessor implements InstantiationAwareBeanPostProcessor {\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tReflectionUtils.doWithFields(bean.getClass(), (field) -> processField(bean, field));\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate void processField(Object bean, Field field) {\n\t\t\tif (AbstractJsonMarshalTester.class.isAssignableFrom(field.getType())) {\n\t\t\t\tinitializeTester(bean, field, bean.getClass(), ResolvableType.forField(field).getGeneric());\n\t\t\t}\n\t\t\telse if (BasicJsonTester.class.isAssignableFrom(field.getType())) {\n\t\t\t\tinitializeTester(bean, field, bean.getClass());\n\t\t\t}\n\t\t}\n\n\t\tprivate void initializeTester(Object bean, Field field, Object... args) {\n\t\t\tReflectionUtils.makeAccessible(field);\n\t\t\tObject tester = ReflectionUtils.getField(field, bean);\n\t\t\tif (tester != null) {\n\t\t\t\tReflectionTestUtils.invokeMethod(tester, \"initialize\", args);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class BasicJsonTesterRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tReflectionHints reflection = hints.reflection();\n\t\t\treflection.registerType(BasicJsonTester.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t\tMethod method = ReflectionUtils.findMethod(BasicJsonTester.class, \"initialize\", Class.class);\n\t\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\t\treflection.registerMethod(method, ExecutableMode.INVOKE);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/JsonTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link JsonTest @JsonTest}.\n *\n * @author Phillip Webb\n */\nclass JsonTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<JsonTest> {\n\n\tJsonTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/json/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JSON tests.\n */\n@NullMarked\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Test auto-configuration support.\n */\n@NullMarked\npackage org.springframework.boot.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters.imports",
    "content": "org.springframework.boot.test.autoconfigure.json.JsonTestersAutoConfiguration\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.jsontesters.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether auto-configuration of JSON testers is enabled.\",\n      \"defaultValue\": \"true\"\n    },\n    {\n      \"name\": \"spring.test.observability.auto-configure\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Superseded by 'spring.test.metrics.export' and 'spring.test.tracing.export'.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.test.print-condition-evaluation-report\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether the condition evaluation report should be printed when the ApplicationContext fails to start.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Context Customizer Factories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.test.autoconfigure.OnFailureConditionReportContextCustomizerFactory,\\\norg.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/json/test/autoconfigure/app/ExampleBasicObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json.test.autoconfigure.app;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Example object to read/write as JSON.\n *\n * @author Phillip Webb\n */\npublic class ExampleBasicObject {\n\n\tprivate @Nullable String value;\n\n\tpublic @Nullable String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj != null && obj.getClass() == getClass()) {\n\t\t\treturn Objects.equals(this.value, ((ExampleBasicObject) obj).value);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hashCode(this.value);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/json/test/autoconfigure/app/ExampleJsonApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.json.test.autoconfigure.app;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link JsonTest @JsonTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleJsonApplication {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/json/test/autoconfigure/app/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.json.test.autoconfigure.app;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ExampleSpringBootApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link OverrideAutoConfiguration @OverrideAutoConfiguration} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootConfiguration\n@EnableAutoConfiguration\npublic class ExampleSpringBootApplication {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ExampleTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Example sliced-test annotation.\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(ExampleTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@ImportAutoConfiguration\n@interface ExampleTest {\n\n\tString[] properties() default {};\n\n\t@PropertyMapping(\"example.attribute\")\n\tboolean attribute() default true;\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ExampleTestConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport org.springframework.boot.test.context.TestConfiguration;\n\n/**\n * Example {@link TestConfiguration @TestConfiguration} for\n * {@link OverrideAutoConfiguration @OverrideAutoConfiguration} tests.\n *\n * @author Phillip Webb\n */\n@TestConfiguration(proxyBeanMethods = false)\npublic class ExampleTestConfig {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ExampleTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link ExampleTest @ExampleTest}.\n *\n * @author Andy Wilkinson\n */\nclass ExampleTestContextBootstrapper extends TestSliceTestContextBootstrapper<ExampleTest> {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/ImportsContextCustomizerFactoryWithAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.platform.engine.discovery.DiscoverySelectors;\nimport org.junit.platform.launcher.Launcher;\nimport org.junit.platform.launcher.LauncherDiscoveryRequest;\nimport org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;\nimport org.junit.platform.launcher.core.LauncherFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@code ImportsContextCustomizerFactory} when used with\n * {@link ImportAutoConfiguration @ImportAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ImportsContextCustomizerFactoryWithAutoConfigurationTests {\n\n\tstatic @Nullable ApplicationContext contextFromTest;\n\n\t@Test\n\tvoid testClassesThatHaveSameAnnotationsShareAContext() {\n\t\texecuteTests(ExampleTest1.class);\n\t\tApplicationContext test1Context = contextFromTest;\n\t\tassertThat(test1Context).isNotNull();\n\t\texecuteTests(ExampleTest3.class);\n\t\tApplicationContext test2Context = contextFromTest;\n\t\tassertThat(test2Context).isNotNull();\n\t\tassertThat(test1Context).isSameAs(test2Context);\n\t}\n\n\t@Test\n\tvoid testClassesThatOnlyHaveDifferingUnrelatedAnnotationsShareAContext() {\n\t\texecuteTests(ExampleTest1.class);\n\t\tApplicationContext test1Context = contextFromTest;\n\t\tassertThat(test1Context).isNotNull();\n\t\texecuteTests(ExampleTest2.class);\n\t\tApplicationContext test2Context = contextFromTest;\n\t\tassertThat(test2Context).isNotNull();\n\t\tassertThat(test1Context).isSameAs(test2Context);\n\t}\n\n\t@Test\n\tvoid testClassesThatOnlyHaveDifferingPropertyMappedAnnotationAttributesDoNotShareAContext() {\n\t\texecuteTests(ExampleTest1.class);\n\t\tApplicationContext test1Context = contextFromTest;\n\t\tassertThat(test1Context).isNotNull();\n\t\texecuteTests(ExampleTest4.class);\n\t\tApplicationContext test2Context = contextFromTest;\n\t\tassertThat(test2Context).isNotNull();\n\t\tassertThat(test1Context).isNotSameAs(test2Context);\n\t}\n\n\tprivate void executeTests(Class<?> testClass) {\n\t\tLauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()\n\t\t\t.selectors(DiscoverySelectors.selectClass(testClass))\n\t\t\t.build();\n\t\tLauncher launcher = LauncherFactory.create();\n\t\tlauncher.execute(request);\n\t}\n\n\t@ExampleTest\n\t@ContextConfiguration(classes = EmptyConfig.class)\n\t@Unrelated1\n\tstatic class ExampleTest1 {\n\n\t\t@Autowired\n\t\tprivate ApplicationContext context;\n\n\t\t@Test\n\t\tvoid test() {\n\t\t\tcontextFromTest = this.context;\n\t\t}\n\n\t}\n\n\t@ExampleTest\n\t@ContextConfiguration(classes = EmptyConfig.class)\n\t@Unrelated2\n\tstatic class ExampleTest2 {\n\n\t\t@Autowired\n\t\tprivate ApplicationContext context;\n\n\t\t@Test\n\t\tvoid test() {\n\t\t\tcontextFromTest = this.context;\n\t\t}\n\n\t}\n\n\t@ExampleTest\n\t@ContextConfiguration(classes = EmptyConfig.class)\n\t@Unrelated1\n\tstatic class ExampleTest3 {\n\n\t\t@Autowired\n\t\tprivate ApplicationContext context;\n\n\t\t@Test\n\t\tvoid test() {\n\t\t\tcontextFromTest = this.context;\n\t\t}\n\n\t}\n\n\t@ExampleTest(attribute = false)\n\t@ContextConfiguration(classes = EmptyConfig.class)\n\t@Unrelated1\n\tstatic class ExampleTest4 {\n\n\t\t@Autowired\n\t\tprivate ApplicationContext context;\n\n\t\t@Test\n\t\tvoid test() {\n\t\t\tcontextFromTest = this.context;\n\t\t}\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface Unrelated1 {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface Unrelated2 {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigurationPackage\n\tstatic class EmptyConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OnFailureConditionReportContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestContextManager;\nimport org.springframework.test.context.cache.ContextCache;\nimport org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link OnFailureConditionReportContextCustomizerFactory}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass OnFailureConditionReportContextCustomizerFactoryTests {\n\n\t@BeforeEach\n\tvoid clearCache() {\n\t\tContextCache contextCache = (ContextCache) ReflectionTestUtils\n\t\t\t.getField(DefaultCacheAwareContextLoaderDelegate.class, \"defaultContextCache\");\n\t\tif (contextCache != null) {\n\t\t\tcontextCache.reset();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadFailureShouldPrintReport(CapturedOutput output) {\n\t\tload();\n\t\tassertThat(output.getErr()).contains(\"TestAutoConfiguration matched\");\n\t\tassertThat(output).contains(\"Error creating bean with name 'faultyBean'\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.xml\", content = \"invalid xml\")\n\tvoid loadFailureShouldNotPrintReportWhenApplicationPropertiesIsBroken(CapturedOutput output) {\n\t\tload();\n\t\tassertThat(output).doesNotContain(\"TestAutoConfiguration matched\")\n\t\t\t.doesNotContain(\"Error creating bean with name 'faultyBean'\")\n\t\t\t.contains(\"java.util.InvalidPropertiesFormatException\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application.properties\", content = \"spring.test.print-condition-evaluation-report=false\")\n\tvoid loadFailureShouldNotPrintReportWhenDisabled(CapturedOutput output) {\n\t\tload();\n\t\tassertThat(output).doesNotContain(\"TestAutoConfiguration matched\")\n\t\t\t.contains(\"Error creating bean with name 'faultyBean'\");\n\t}\n\n\tprivate void load() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new TestContextManager(FailingTests.class).getTestContext().getApplicationContext());\n\t}\n\n\t@SpringBootTest\n\tstatic class FailingTests {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ImportAutoConfiguration(TestAutoConfiguration.class)\n\t\tstatic class TestConfig {\n\n\t\t\t@Bean\n\t\t\tString faultyBean() {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ConditionalOnProperty(value = \"com.example.test.enabled\", matchIfMissing = true)\n\tstatic class TestAutoConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/OverrideAutoConfigurationContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.test.context.ContextCustomizer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OverrideAutoConfigurationContextCustomizerFactory}.\n *\n * @author Phillip Webb\n */\nclass OverrideAutoConfigurationContextCustomizerFactoryTests {\n\n\tprivate final OverrideAutoConfigurationContextCustomizerFactory factory = new OverrideAutoConfigurationContextCustomizerFactory();\n\n\t@Test\n\tvoid getContextCustomizerWhenHasNoAnnotationShouldReturnNull() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(NoAnnotation.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasAnnotationEnabledTrueShouldReturnNull() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(WithAnnotationEnabledTrue.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNull();\n\t}\n\n\t@Test\n\tvoid getContextCustomizerWhenHasAnnotationEnabledFalseShouldReturnCustomizer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(WithAnnotationEnabledFalse.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tContextCustomizer customizer1 = this.factory.createContextCustomizer(WithAnnotationEnabledFalse.class,\n\t\t\t\tCollections.emptyList());\n\t\tContextCustomizer customizer2 = this.factory.createContextCustomizer(WithSameAnnotation.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t\tassertThat(customizer1).isEqualTo(customizer1).isEqualTo(customizer2);\n\t}\n\n\tstatic class NoAnnotation {\n\n\t}\n\n\t@OverrideAutoConfiguration(enabled = true)\n\tstatic class WithAnnotationEnabledTrue {\n\n\t}\n\n\t@OverrideAutoConfiguration(enabled = false)\n\tstatic class WithAnnotationEnabledFalse {\n\n\t}\n\n\t@OverrideAutoConfiguration(enabled = false)\n\tstatic class WithSameAnnotation {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/ExampleJsonApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link JsonTest @JsonTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleJsonApplication {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.json.test.autoconfigure.app.ExampleJsonApplication;\nimport org.springframework.boot.test.json.BasicJsonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Eddú Meléndez\n */\n@JsonTest\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestIntegrationTests {\n\n\t@Autowired\n\tprivate BasicJsonTester basicJson;\n\n\t@Test\n\tvoid basicJson() {\n\t\tassertThat(this.basicJson.from(\"{\\\"a\\\":\\\"b\\\"}\")).hasJsonPathStringValue(\"@.a\");\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link JsonTest#properties properties} attribute of\n * {@link JsonTest @JsonTest}.\n *\n * @author Artsiom Yudovin\n */\n@JsonTest(properties = \"spring.profiles.active=test\")\nclass JsonTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(JsonTestPropertiesIntegrationTests.this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.json.test.autoconfigure.app.ExampleJsonApplication;\nimport org.springframework.boot.test.json.BasicJsonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Phillip Webb\n */\n@JsonTest\n@AutoConfigureJsonTesters(enabled = false)\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired(required = false)\n\tprivate BasicJsonTester basicJson;\n\n\t@Test\n\tvoid basicJson() {\n\t\tassertThat(this.basicJson).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/JsonTestersAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.boot.test.json.BasicJsonTester;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonTestersAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass JsonTestersAutoConfigurationTests {\n\n\t@Test\n\tvoid basicJsonTesterHintsAreContributed() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tTestPropertyValues.of(\"spring.test.jsontesters.enabled=true\").applyTo(context);\n\t\t\tcontext.register(JsonTestersAutoConfiguration.class);\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\t\tnew ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\t\tassertThat(reflection.onType(BasicJsonTester.class)).accepts(runtimeHints);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/json/SpringBootTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.json;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.json.test.autoconfigure.app.ExampleJsonApplication;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.json.BasicJsonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureJsonTesters\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass SpringBootTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired\n\tprivate BasicJsonTester basicJson;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.basicJson).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledFalseIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.override;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;\nimport org.springframework.boot.test.autoconfigure.ExampleTestConfig;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Integration tests for {@link OverrideAutoConfiguration @OverrideAutoConfiguration} when\n * {@code enabled} is {@code false}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@BootstrapWith(SpringBootTestContextBootstrapper.class)\n@ImportAutoConfiguration(ExampleTestConfig.class)\nclass OverrideAutoConfigurationEnabledFalseIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid disabledAutoConfiguration() {\n\t\tApplicationContext context = this.context;\n\t\tassertThat(context.getBean(ExampleTestConfig.class)).isNotNull();\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> context.getBean(ConfigurationPropertiesBindingPostProcessor.class));\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationEnabledTrueIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.override;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;\nimport org.springframework.boot.test.autoconfigure.ExampleTestConfig;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTestContextBootstrapper;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OverrideAutoConfiguration @OverrideAutoConfiguration} when\n * {@code enabled} is {@code true}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = true)\n@BootstrapWith(SpringBootTestContextBootstrapper.class)\n@ImportAutoConfiguration(ExampleTestConfig.class)\nclass OverrideAutoConfigurationEnabledTrueIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid autoConfiguredContext() {\n\t\tApplicationContext context = this.context;\n\t\tassertThat(context.getBean(OverrideAutoConfigurationSpringBootApplication.class)).isNotNull();\n\t\tassertThat(context.getBean(ConfigurationPropertiesBindingPostProcessor.class)).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/OverrideAutoConfigurationSpringBootApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.override;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link OverrideAutoConfiguration @OverrideAutoConfiguration} tests.\n *\n * @author Andy Wilkinson\n */\n@SpringBootConfiguration\n@EnableAutoConfiguration\npublic class OverrideAutoConfigurationSpringBootApplication {\n\n}\n"
  },
  {
    "path": "core/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/override/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.autoconfigure.override;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Testcontainers Support\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-autoconfigure\"))\n\tapi(\"org.testcontainers:testcontainers\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.junit.platform:junit-platform-launcher\")\n\tdockerTestImplementation(\"org.mockito:mockito-core\")\n\tdockerTestImplementation(\"org.springframework:spring-core-test\")\n\tdockerTestImplementation(\"org.springframework:spring-jdbc\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\n\tdockerTestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\tdockerTestRuntimeOnly(\"com.h2database:h2\")\n\tdockerTestRuntimeOnly(\"org.postgresql:postgresql\")\n\n\toptional(\"org.springframework:spring-test\")\n\toptional(\"org.springframework.data:spring-data-mongodb\")\n\toptional(\"org.springframework.data:spring-data-neo4j\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\ttestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n}\n\ndockerTest {\n\tjvmArgs += \"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/ImportTestcontainersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.testcontainers.beans.TestcontainerBeanDefinition;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ImportTestcontainers}.\n *\n * @author Phillip Webb\n */\n@DisabledIfDockerUnavailable\nclass ImportTestcontainersTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext applicationContext;\n\n\t@AfterEach\n\tvoid teardown() {\n\t\tif (this.applicationContext != null) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid importWithoutValueRegistersBeans() {\n\t\tthis.applicationContext = new AnnotationConfigApplicationContext(ImportWithoutValue.class);\n\t\tString[] beanNames = this.applicationContext.getBeanNamesForType(PostgreSQLContainer.class);\n\t\tassertThat(beanNames).hasSize(1);\n\t\tassertThat(this.applicationContext.getBean(beanNames[0])).isSameAs(ImportWithoutValue.container);\n\t\tTestcontainerBeanDefinition beanDefinition = (TestcontainerBeanDefinition) this.applicationContext\n\t\t\t.getBeanDefinition(beanNames[0]);\n\t\tassertThat(beanDefinition.getContainerImageName()).isEqualTo(ImportWithoutValue.container.getDockerImageName());\n\t\tassertThat(beanDefinition.getAnnotations().isPresent(ContainerAnnotation.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid importWithValueRegistersBeans() {\n\t\tthis.applicationContext = new AnnotationConfigApplicationContext(ImportWithValue.class);\n\t\tString[] beanNames = this.applicationContext.getBeanNamesForType(PostgreSQLContainer.class);\n\t\tassertThat(beanNames).hasSize(1);\n\t\tassertThat(this.applicationContext.getBean(beanNames[0])).isSameAs(ContainerDefinitions.container);\n\t\tTestcontainerBeanDefinition beanDefinition = (TestcontainerBeanDefinition) this.applicationContext\n\t\t\t.getBeanDefinition(beanNames[0]);\n\t\tassertThat(beanDefinition.getContainerImageName())\n\t\t\t.isEqualTo(ContainerDefinitions.container.getDockerImageName());\n\t\tassertThat(beanDefinition.getAnnotations().isPresent(ContainerAnnotation.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid importWhenHasNoContainerFieldsDoesNothing() {\n\t\tthis.applicationContext = new AnnotationConfigApplicationContext(NoContainers.class);\n\t\tString[] beanNames = this.applicationContext.getBeanNamesForType(Container.class);\n\t\tassertThat(beanNames).isEmpty();\n\t}\n\n\t@Test\n\tvoid importWhenHasNullContainerFieldThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.applicationContext = new AnnotationConfigApplicationContext(NullContainer.class))\n\t\t\t.withMessage(\"Container field 'container' must not have a null value\");\n\t}\n\n\t@Test\n\tvoid importWhenHasNonStaticContainerFieldThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.applicationContext = new AnnotationConfigApplicationContext(NonStaticContainer.class))\n\t\t\t.withMessage(\"Container field 'container' must be static\");\n\t}\n\n\t@Test\n\tvoid importWhenHasContainerDefinitionsWithDynamicPropertySource() {\n\t\tthis.applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\tContainerDefinitionsWithDynamicPropertySource.class);\n\t\tassertThat(this.applicationContext.getEnvironment().getProperty(\"container.port\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid importWhenHasNonStaticDynamicPropertySourceMethod() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\t\tNonStaticDynamicPropertySourceMethod.class))\n\t\t\t.withMessage(\"@DynamicPropertySource method 'containerProperties' must be static\");\n\t}\n\n\t@Test\n\tvoid importWhenHasBadArgsDynamicPropertySourceMethod() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.applicationContext = new AnnotationConfigApplicationContext(\n\t\t\t\t\tBadArgsDynamicPropertySourceMethod.class))\n\t\t\t.withMessage(\"@DynamicPropertySource method 'containerProperties' must be static\");\n\t}\n\n\t@ImportTestcontainers\n\tstatic class ImportWithoutValue {\n\n\t\t@ContainerAnnotation\n\t\tstatic PostgreSQLContainer container = TestImage.container(PostgreSQLContainer.class);\n\n\t}\n\n\t@ImportTestcontainers(ContainerDefinitions.class)\n\tstatic class ImportWithValue {\n\n\t}\n\n\t@ImportTestcontainers\n\tstatic class NoContainers {\n\n\t}\n\n\t@ImportTestcontainers\n\tstatic class NullContainer {\n\n\t\tstatic @Nullable PostgreSQLContainer container;\n\n\t}\n\n\t@ImportTestcontainers\n\tstatic class NonStaticContainer {\n\n\t\tPostgreSQLContainer container = TestImage.container(PostgreSQLContainer.class);\n\n\t}\n\n\tinterface ContainerDefinitions {\n\n\t\t@ContainerAnnotation\n\t\tPostgreSQLContainer container = TestImage.container(PostgreSQLContainer.class);\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@interface ContainerAnnotation {\n\n\t}\n\n\t@ImportTestcontainers\n\tstatic class ContainerDefinitionsWithDynamicPropertySource {\n\n\t\tstatic PostgreSQLContainer container = TestImage.container(PostgreSQLContainer.class);\n\n\t\t@DynamicPropertySource\n\t\tstatic void containerProperties(DynamicPropertyRegistry registry) {\n\t\t\tregistry.add(\"container.port\", container::getFirstMappedPort);\n\t\t}\n\n\t}\n\n\t@ImportTestcontainers\n\tstatic class NonStaticDynamicPropertySourceMethod {\n\n\t\t@DynamicPropertySource\n\t\tvoid containerProperties(DynamicPropertyRegistry registry) {\n\t\t}\n\n\t}\n\n\t@ImportTestcontainers\n\tstatic class BadArgsDynamicPropertySourceMethod {\n\n\t\t@DynamicPropertySource\n\t\tvoid containerProperties() {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/LoadTimeWeaverAwareConsumerContainers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers;\n\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * Container definitions for {@link LoadTimeWeaverAwareConsumerImportTestcontainersTests}.\n *\n * @author Andy Wilkinson\n */\ninterface LoadTimeWeaverAwareConsumerContainers {\n\n\t@Container\n\t@ServiceConnection\n\tPostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(\"postgres:16.1\");\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/LoadTimeWeaverAwareConsumerImportTestcontainersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\nimport org.springframework.boot.testcontainers.service.connection.DatabaseConnectionDetails;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.weaving.LoadTimeWeaverAware;\nimport org.springframework.instrument.classloading.LoadTimeWeaver;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@DisabledIfDockerUnavailable\n@ImportTestcontainers(LoadTimeWeaverAwareConsumerContainers.class)\nclass LoadTimeWeaverAwareConsumerImportTestcontainersTests implements LoadTimeWeaverAwareConsumerContainers {\n\n\t@Autowired\n\tprivate LoadTimeWeaverAwareConsumer consumer;\n\n\t@Test\n\tvoid loadTimeWeaverAwareBeanCanUseJdbcUrlFromContainerBasedConnectionDetails() {\n\t\tassertThat(this.consumer.jdbcUrl).isNotNull();\n\t}\n\n\t@Configuration\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tEmbeddedDatabaseFactory embeddedDatabaseFactory = new EmbeddedDatabaseFactory();\n\t\t\tembeddedDatabaseFactory.setGenerateUniqueDatabaseName(true);\n\t\t\tembeddedDatabaseFactory.setDatabaseType(EmbeddedDatabaseType.H2);\n\t\t\treturn embeddedDatabaseFactory.getDatabase();\n\t\t}\n\n\t\t@Bean\n\t\tLoadTimeWeaverAwareConsumer loadTimeWeaverAwareConsumer(DatabaseConnectionDetails connectionDetails) {\n\t\t\treturn new LoadTimeWeaverAwareConsumer(connectionDetails);\n\t\t}\n\n\t}\n\n\tstatic class LoadTimeWeaverAwareConsumer implements LoadTimeWeaverAware {\n\n\t\tprivate final String jdbcUrl;\n\n\t\tLoadTimeWeaverAwareConsumer(DatabaseConnectionDetails connectionDetails) {\n\t\t\tthis.jdbcUrl = connectionDetails.getJdbcUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/ResetStartablesExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.lang.reflect.InaccessibleObjectException;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.testcontainers.lifecycle.Startables;\n\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * JUnit extension used by reset startables.\n *\n * @author Phillip Webb\n */\nclass ResetStartablesExtension implements BeforeEachCallback, AfterEachCallback {\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\treset();\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\treset();\n\t}\n\n\tprivate void reset() {\n\t\ttry {\n\t\t\tObject executor = ReflectionTestUtils.getField(Startables.class, \"EXECUTOR\");\n\t\t\tassertThat(executor).isNotNull();\n\t\t\tObject threadFactory = ReflectionTestUtils.getField(executor, \"threadFactory\");\n\t\t\tassertThat(threadFactory).isNotNull();\n\t\t\tAtomicLong counter = (AtomicLong) ReflectionTestUtils.getField(threadFactory, \"COUNTER\");\n\t\t\tassertThat(counter).isNotNull();\n\t\t\tcounter.set(0);\n\t\t}\n\t\tcatch (InaccessibleObjectException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to reset field. Please run with '--add-opens=java.base/java.util.concurrent=ALL-UNNAMED'\",\n\t\t\t\t\tex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersImportWithPropertiesInjectedIntoLoadTimeWeaverAwareBeanIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersImportWithPropertiesInjectedIntoLoadTimeWeaverAwareBeanIntegrationTests.Containers;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.weaving.LoadTimeWeaverAware;\nimport org.springframework.instrument.classloading.LoadTimeWeaver;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Tests for {@link ImportTestcontainers} when properties are being injected into a\n * {@link LoadTimeWeaverAware} bean.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@DisabledIfDockerUnavailable\n@ImportTestcontainers(Containers.class)\nclass TestcontainersImportWithPropertiesInjectedIntoLoadTimeWeaverAwareBeanIntegrationTests {\n\n\t// gh-38913\n\n\t@Test\n\tvoid starts() {\n\t}\n\n\t@TestConfiguration\n\t@EnableConfigurationProperties(MockDataSourceProperties.class)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tMockEntityManager mockEntityManager(MockDataSourceProperties properties) {\n\t\t\treturn new MockEntityManager();\n\t\t}\n\n\t}\n\n\tstatic class MockEntityManager implements LoadTimeWeaverAware {\n\n\t\t@Override\n\t\tpublic void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"spring.datasource\")\n\tpublic static class MockDataSourceProperties {\n\n\t\tprivate @Nullable String url;\n\n\t\tpublic @Nullable String getUrl() {\n\t\t\treturn this.url;\n\t\t}\n\n\t\tpublic void setUrl(@Nullable String url) {\n\t\t\tthis.url = url;\n\t\t}\n\n\t}\n\n\tstatic class Containers {\n\n\t\t@Container\n\t\tstatic PostgreSQLContainer container = TestImage.container(PostgreSQLContainer.class);\n\n\t\t@DynamicPropertySource\n\t\tstatic void setConnectionProperties(DynamicPropertyRegistry registry) {\n\t\t\tregistry.add(\"spring.datasource.url\", container::getJdbcUrl);\n\t\t\tregistry.add(\"spring.datasource.password\", container::getPassword);\n\t\t\tregistry.add(\"spring.datasource.username\", container::getUsername);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleOrderIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderIntegrationTests.AssertingSpringExtension;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderIntegrationTests.ContainerConfig;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderIntegrationTests.TestConfig;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link TestcontainersLifecycleBeanPostProcessor} to ensure create\n * and destroy events happen in the correct order.\n *\n * @author Phillip Webb\n */\n@ExtendWith(AssertingSpringExtension.class)\n@ContextConfiguration(classes = { TestConfig.class, ContainerConfig.class })\n@DirtiesContext\n@DisabledIfDockerUnavailable\nclass TestcontainersLifecycleOrderIntegrationTests {\n\n\tstatic List<String> events = Collections.synchronizedList(new ArrayList<>());\n\n\t@Test\n\tvoid eventsAreOrderedCorrectlyAfterStartup() {\n\t\tassertThat(events).containsExactly(\"start-container\", \"create-bean\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ContainerConfig {\n\n\t\t@Bean\n\t\t@ServiceConnection\n\t\tRedisContainer redisContainer() {\n\t\t\treturn TestImage.container(EventRecordingRedisContainer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tTestBean testBean() {\n\t\t\tevents.add(\"create-bean\");\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\tstatic class TestBean implements AutoCloseable {\n\n\t\t@Override\n\t\tpublic void close() throws Exception {\n\t\t\tevents.add(\"destroy-bean\");\n\t\t}\n\n\t}\n\n\tstatic class AssertingSpringExtension extends SpringExtension {\n\n\t\t@Override\n\t\tpublic void afterAll(ExtensionContext context) throws Exception {\n\t\t\tsuper.afterAll(context);\n\t\t\tassertThat(events).containsExactly(\"start-container\", \"create-bean\", \"destroy-bean\", \"stop-container\");\n\t\t}\n\n\t}\n\n\tstatic class EventRecordingRedisContainer extends RedisContainer {\n\n\t\tEventRecordingRedisContainer(DockerImageName dockerImageName) {\n\t\t\tsuper(dockerImageName);\n\t\t}\n\n\t\t@Override\n\t\tpublic void start() {\n\t\t\tevents.add(\"start-container\");\n\t\t\tsuper.start();\n\t\t}\n\n\t\t@Override\n\t\tpublic void stop() {\n\t\t\tevents.add(\"stop-container\");\n\t\t\tsuper.stop();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleOrderWithScopeIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderWithScopeIntegrationTests.AssertingSpringExtension;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderWithScopeIntegrationTests.ContainerConfig;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderWithScopeIntegrationTests.ScopedContextLoader;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleOrderWithScopeIntegrationTests.TestConfig;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.context.support.AnnotationConfigContextLoader;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link TestcontainersLifecycleBeanPostProcessor} to ensure create\n * and destroy events happen in the correct order.\n *\n * @author Phillip Webb\n */\n@ExtendWith(AssertingSpringExtension.class)\n@ContextConfiguration(loader = ScopedContextLoader.class, classes = { TestConfig.class, ContainerConfig.class })\n@DirtiesContext\n@DisabledIfDockerUnavailable\nclass TestcontainersLifecycleOrderWithScopeIntegrationTests {\n\n\tstatic List<String> events = Collections.synchronizedList(new ArrayList<>());\n\n\t@Test\n\tvoid eventsAreOrderedCorrectlyAfterStartup() {\n\t\tassertThat(events).containsExactly(\"start-container\", \"create-bean\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ContainerConfig {\n\n\t\t@Bean\n\t\t@Scope(\"custom\")\n\t\t@ServiceConnection\n\t\tRedisContainer redisContainer() {\n\t\t\treturn TestImage.container(EventRecordingRedisContainer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tTestBean testBean() {\n\t\t\tevents.add(\"create-bean\");\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\tstatic class TestBean implements AutoCloseable {\n\n\t\t@Override\n\t\tpublic void close() throws Exception {\n\t\t\tevents.add(\"destroy-bean\");\n\t\t}\n\n\t}\n\n\tstatic class AssertingSpringExtension extends SpringExtension {\n\n\t\t@Override\n\t\tpublic void afterAll(ExtensionContext context) throws Exception {\n\t\t\tsuper.afterAll(context);\n\t\t\tassertThat(events).containsExactly(\"start-container\", \"create-bean\", \"destroy-bean\", \"stop-container\");\n\t\t}\n\n\t}\n\n\tstatic class EventRecordingRedisContainer extends RedisContainer {\n\n\t\tEventRecordingRedisContainer(DockerImageName dockerImageName) {\n\t\t\tsuper(dockerImageName);\n\t\t}\n\n\t\t@Override\n\t\tpublic void start() {\n\t\t\tevents.add(\"start-container\");\n\t\t\tsuper.start();\n\t\t}\n\n\t\t@Override\n\t\tpublic void stop() {\n\t\t\tevents.add(\"stop-container\");\n\t\t\tsuper.stop();\n\t\t}\n\n\t}\n\n\tstatic class ScopedContextLoader extends AnnotationConfigContextLoader {\n\n\t\t@Override\n\t\tprotected GenericApplicationContext createContext() {\n\t\t\tCustomScope customScope = new CustomScope();\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void onClose() {\n\t\t\t\t\tcustomScope.destroy();\n\t\t\t\t\tsuper.onClose();\n\t\t\t\t}\n\n\t\t\t};\n\t\t\tcontext.getBeanFactory().registerScope(\"custom\", customScope);\n\t\t\treturn context;\n\t\t}\n\n\t}\n\n\tstatic class CustomScope implements org.springframework.beans.factory.config.Scope {\n\n\t\tprivate Map<String, Object> instances = new HashMap<>();\n\n\t\tprivate MultiValueMap<String, Runnable> destructors = new LinkedMultiValueMap<>();\n\n\t\t@Override\n\t\tpublic Object get(String name, ObjectFactory<?> objectFactory) {\n\t\t\treturn this.instances.computeIfAbsent(name, (key) -> objectFactory.getObject());\n\t\t}\n\n\t\t@Override\n\t\tpublic Object remove(String name) {\n\t\t\tsynchronized (this) {\n\t\t\t\tObject removed = this.instances.remove(name);\n\t\t\t\tList<Runnable> destructor = this.destructors.get(name);\n\t\t\t\tassertThat(destructor).isNotNull();\n\t\t\t\tdestructor.forEach(Runnable::run);\n\t\t\t\tthis.destructors.remove(name);\n\t\t\t\treturn removed;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerDestructionCallback(String name, Runnable callback) {\n\t\t\tthis.destructors.add(name, callback);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object resolveContextualObject(String key) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getConversationId() {\n\t\t\treturn null;\n\t\t}\n\n\t\tvoid destroy() {\n\t\t\tsynchronized (this) {\n\t\t\t\tthis.destructors.forEach((name, actions) -> actions.forEach(Runnable::run));\n\t\t\t\tthis.destructors.clear();\n\t\t\t\tthis.instances.clear();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersParallelStartupIntegrationTests.ContainerConfig;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for parallel startup.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = ContainerConfig.class)\n@TestPropertySource(properties = \"spring.testcontainers.beans.startup=parallel\")\n@DisabledIfDockerUnavailable\n@ExtendWith(OutputCaptureExtension.class)\nclass TestcontainersParallelStartupIntegrationTests {\n\n\t@Test\n\tvoid startsInParallel(CapturedOutput out) {\n\t\tassertThat(out).contains(\"-lifecycle-0\").contains(\"-lifecycle-1\").contains(\"-lifecycle-2\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ContainerConfig {\n\n\t\t@Bean\n\t\tstatic PostgreSQLContainer container1() {\n\t\t\treturn TestImage.container(PostgreSQLContainer.class);\n\t\t}\n\n\t\t@Bean\n\t\tstatic PostgreSQLContainer container2() {\n\t\t\treturn TestImage.container(PostgreSQLContainer.class);\n\t\t}\n\n\t\t@Bean\n\t\tstatic PostgreSQLContainer container3() {\n\t\t\treturn TestImage.container(PostgreSQLContainer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersParallelStartupWithImportTestcontainersIntegrationTests.Containers;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for parallel startup.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@TestPropertySource(properties = \"spring.testcontainers.beans.startup=parallel\")\n@DisabledIfDockerUnavailable\n@ExtendWith({ OutputCaptureExtension.class, ResetStartablesExtension.class })\n@ImportTestcontainers(Containers.class)\nclass TestcontainersParallelStartupWithImportTestcontainersIntegrationTests {\n\n\t@Test\n\tvoid startsInParallel(CapturedOutput out) {\n\t\tassertThat(out).contains(\"-lifecycle-0\").contains(\"-lifecycle-1\").contains(\"-lifecycle-2\");\n\t}\n\n\tstatic class Containers {\n\n\t\t@Container\n\t\tstatic PostgreSQLContainer container1 = TestImage.container(PostgreSQLContainer.class);\n\n\t\t@Container\n\t\tstatic PostgreSQLContainer container2 = TestImage.container(PostgreSQLContainer.class);\n\n\t\t@Container\n\t\tstatic PostgreSQLContainer container3 = TestImage.container(PostgreSQLContainer.class);\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/properties/TestcontainersPropertySourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.properties;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleApplicationContextInitializer;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.context.DynamicPropertyRegistrar;\nimport org.springframework.test.context.DynamicPropertyRegistry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestcontainersPropertySourceAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@DisabledIfDockerUnavailable\n@ExtendWith(OutputCaptureExtension.class)\nclass TestcontainersPropertySourceAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withInitializer(new TestcontainersLifecycleApplicationContextInitializer())\n\t\t.withConfiguration(AutoConfigurations.of(TestcontainersPropertySourceAutoConfiguration.class));\n\n\t@Test\n\tvoid dynamicPropertyRegistrarBeanContributesProperties(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(ContainerAndPropertyRegistrarConfiguration.class).run((context) -> {\n\t\t\tTestBean testBean = context.getBean(TestBean.class);\n\t\t\tRedisContainer redisContainer = context.getBean(RedisContainer.class);\n\t\t\tassertThat(testBean.getUsingPort()).isEqualTo(redisContainer.getFirstMappedPort());\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ContainerProperties.class)\n\t@Import(TestBean.class)\n\tstatic class ContainerAndPropertiesConfiguration {\n\n\t\t@Bean\n\t\tRedisContainer redisContainer(DynamicPropertyRegistry properties) {\n\t\t\tRedisContainer container = TestImage.container(RedisContainer.class);\n\t\t\tproperties.add(\"container.port\", container::getFirstMappedPort);\n\t\t\treturn container;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ContainerProperties.class)\n\t@Import(TestBean.class)\n\tstatic class ContainerAndPropertyRegistrarConfiguration {\n\n\t\t@Bean\n\t\tRedisContainer redisContainer() {\n\t\t\treturn TestImage.container(RedisContainer.class);\n\t\t}\n\n\t\t@Bean\n\t\tDynamicPropertyRegistrar redisProperties(RedisContainer container) {\n\t\t\treturn (registry) -> registry.add(\"container.port\", container::getFirstMappedPort);\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"container\")\n\trecord ContainerProperties(int port) {\n\t}\n\n\tstatic class TestBean {\n\n\t\tprivate int usingPort;\n\n\t\tTestBean(ContainerProperties containerProperties) {\n\t\t\tthis.usingPort = containerProperties.port();\n\t\t}\n\n\t\tint getUsingPort() {\n\t\t\treturn this.usingPort;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/properties/TestcontainersPropertySourceAutoConfigurationWithSpringBootTestIntegrationTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.properties.TestcontainersPropertySourceAutoConfigurationWithSpringBootTestIntegrationTest.TestConfig;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.DynamicPropertyRegistrar;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestcontainersPropertySourceAutoConfiguration} when combined with\n * {@link SpringBootTest @SpringBootTest}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@SpringBootTest(classes = TestConfig.class,\n\t\tproperties = \"spring.testcontainers.dynamic-property-registry-injection=allow\")\nclass TestcontainersPropertySourceAutoConfigurationWithSpringBootTestIntegrationTest {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid callsRegistrars() {\n\t\tassertThat(this.environment.getProperty(\"from.registrar\")).isEqualTo(\"two\");\n\t}\n\n\t@TestConfiguration\n\t@ImportAutoConfiguration(TestcontainersPropertySourceAutoConfiguration.class)\n\t@SpringBootConfiguration\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tDynamicPropertyRegistrar propertyRegistrar() {\n\t\t\treturn (registry) -> registry.add(\"from.registrar\", () -> \"two\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.beans.TestcontainerBeanDefinition;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleApplicationContextInitializer;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ServiceConnectionAutoConfiguration} and\n * {@link ServiceConnectionAutoConfigurationRegistrar}.\n *\n * @author Phillip Webb\n */\n@DisabledIfDockerUnavailable\nclass ServiceConnectionAutoConfigurationTests {\n\n\tprivate static final String DATABASE_CONTAINER_CONNECTION_DETAILS = TestDatabaseConnectionDetails.class.getName();\n\n\t@Test\n\tvoid whenNoExistingBeansRegistersServiceConnection() {\n\t\ttry (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {\n\t\t\tapplicationContext.register(WithNoExtraAutoConfiguration.class, ContainerConfiguration.class);\n\t\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\t\tapplicationContext.refresh();\n\t\t\tDatabaseConnectionDetails connectionDetails = applicationContext.getBean(DatabaseConnectionDetails.class);\n\t\t\tassertThat(connectionDetails.getClass().getName()).isEqualTo(DATABASE_CONTAINER_CONNECTION_DETAILS);\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenHasExistingAutoConfigurationRegistersReplacement() {\n\t\ttry (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {\n\t\t\tapplicationContext.register(WithDatasourceConfiguration.class, ContainerConfiguration.class);\n\t\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\t\tapplicationContext.refresh();\n\t\t\tDatabaseConnectionDetails connectionDetails = applicationContext.getBean(DatabaseConnectionDetails.class);\n\t\t\tassertThat(connectionDetails.getClass().getName()).isEqualTo(DATABASE_CONTAINER_CONNECTION_DETAILS);\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenHasUserConfigurationDoesNotRegisterReplacement() {\n\t\ttry (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {\n\t\t\tapplicationContext.register(UserConfiguration.class, WithDatasourceConfiguration.class,\n\t\t\t\t\tContainerConfiguration.class);\n\t\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\t\tapplicationContext.refresh();\n\t\t\tDatabaseConnectionDetails connectionDetails = applicationContext.getBean(DatabaseConnectionDetails.class);\n\t\t\tassertThat(Mockito.mockingDetails(connectionDetails).isMock()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenHasTestcontainersBeanDefinition() {\n\t\ttry (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {\n\t\t\tapplicationContext.register(WithNoExtraAutoConfiguration.class,\n\t\t\t\t\tTestcontainerBeanDefinitionConfiguration.class);\n\t\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\t\tapplicationContext.refresh();\n\t\t\tDatabaseConnectionDetails connectionDetails = applicationContext.getBean(DatabaseConnectionDetails.class);\n\t\t\tassertThat(connectionDetails.getClass().getName()).isEqualTo(DATABASE_CONTAINER_CONNECTION_DETAILS);\n\t\t}\n\t}\n\n\t@Test\n\tvoid serviceConnectionBeansDoNotCauseAotProcessingToFail() {\n\t\ttry (AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext()) {\n\t\t\tapplicationContext.register(WithNoExtraAutoConfiguration.class, ContainerConfiguration.class);\n\t\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\t\tassertThatNoException().isThrownBy(() -> new ApplicationContextAotGenerator()\n\t\t\t\t.processAheadOfTime(applicationContext, generationContext));\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(ServiceConnectionAutoConfiguration.class)\n\tstatic class WithNoExtraAutoConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(ServiceConnectionAutoConfiguration.class)\n\tstatic class WithDatasourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tEmbeddedDatabaseFactory embeddedDatabaseFactory = new EmbeddedDatabaseFactory();\n\t\t\tembeddedDatabaseFactory.setGenerateUniqueDatabaseName(true);\n\t\t\tembeddedDatabaseFactory.setDatabaseType(EmbeddedDatabaseType.H2);\n\t\t\treturn embeddedDatabaseFactory.getDatabase();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ContainerConfiguration {\n\n\t\t@Bean\n\t\t@ServiceConnection\n\t\tPostgreSQLContainer postgresContainer() {\n\t\t\treturn TestImage.container(PostgreSQLContainer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserConfiguration {\n\n\t\t@Bean\n\t\tDatabaseConnectionDetails databaseConnectionDetails() {\n\t\t\treturn mock(DatabaseConnectionDetails.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestcontainerBeanDefinitionRegistrar.class)\n\tstatic class TestcontainerBeanDefinitionConfiguration {\n\n\t}\n\n\tstatic class TestcontainerBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,\n\t\t\t\tBeanNameGenerator importBeanNameGenerator) {\n\t\t\tregistry.registerBeanDefinition(\"postgresContainer\", new TestcontainersRootBeanDefinition());\n\t\t}\n\n\t}\n\n\tstatic class TestcontainersRootBeanDefinition extends RootBeanDefinition implements TestcontainerBeanDefinition {\n\n\t\tprivate final PostgreSQLContainer container = TestImage.container(PostgreSQLContainer.class);\n\n\t\tTestcontainersRootBeanDefinition() {\n\t\t\tsetBeanClass(PostgreSQLContainer.class);\n\t\t\tsetInstanceSupplier(() -> this.container);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getContainerImageName() {\n\t\t\treturn this.container.getDockerImageName();\n\t\t}\n\n\t\t@Override\n\t\tpublic MergedAnnotations getAnnotations() {\n\t\t\tMergedAnnotation<ServiceConnection> annotation = MergedAnnotation.of(ServiceConnection.class);\n\t\t\treturn MergedAnnotations.of(Set.of(annotation));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionStartsConnectionOnceIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests to ensure containers are started only once.\n *\n * @author Phillip Webb\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass ServiceConnectionStartsConnectionOnceIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final StartCountingPostgreSQLContainer postgres = TestImage\n\t\t.container(StartCountingPostgreSQLContainer.class);\n\n\t@Test\n\tvoid startedOnlyOnce() {\n\t\tassertThat(postgres.startCount.get()).isOne();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tEmbeddedDatabaseFactory embeddedDatabaseFactory = new EmbeddedDatabaseFactory();\n\t\t\tembeddedDatabaseFactory.setGenerateUniqueDatabaseName(true);\n\t\t\tembeddedDatabaseFactory.setDatabaseType(EmbeddedDatabaseType.H2);\n\t\t\treturn embeddedDatabaseFactory.getDatabase();\n\t\t}\n\n\t}\n\n\tstatic class StartCountingPostgreSQLContainer extends PostgreSQLContainer {\n\n\t\tfinal AtomicInteger startCount = new AtomicInteger();\n\n\t\tStartCountingPostgreSQLContainer(DockerImageName dockerImageName) {\n\t\t\tsuper(dockerImageName);\n\t\t}\n\n\t\t@Override\n\t\tpublic void start() {\n\t\t\tthis.startCount.incrementAndGet();\n\t\t\tsuper.start();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/beans/TestcontainerBeanDefinition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.beans;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.core.annotation.MergedAnnotations;\n\n/**\n * Extended {@link org.springframework.beans.factory.config.BeanDefinition} interface used\n * to register testcontainer beans.\n *\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic interface TestcontainerBeanDefinition extends BeanDefinition {\n\n\t/**\n\t * Return the container image name or {@code null} if the image name is not yet known.\n\t * @return the container image name\n\t */\n\t@Nullable String getContainerImageName();\n\n\t/**\n\t * Return any annotations declared alongside the container.\n\t * @return annotations declared with the container\n\t */\n\tMergedAnnotations getAnnotations();\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/beans/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring bean support classes for Testcontainers.\n */\n@NullMarked\npackage org.springframework.boot.testcontainers.beans;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ContainerFieldsImporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.context;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.container.ContainerImageMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Used by {@link ImportTestcontainersRegistrar} to import {@link Container} fields.\n *\n * @author Phillip Webb\n */\nclass ContainerFieldsImporter {\n\n\tSet<Startable> registerBeanDefinitions(BeanDefinitionRegistry registry, Class<?> definitionClass) {\n\t\tSet<Startable> importedContainers = new HashSet<>();\n\t\tfor (Field field : getContainerFields(definitionClass)) {\n\t\t\tassertValid(field);\n\t\t\tContainer<?> container = getContainer(field);\n\t\t\tif (container instanceof Startable startable) {\n\t\t\t\timportedContainers.add(startable);\n\t\t\t}\n\t\t\tregisterBeanDefinition(registry, field, container);\n\t\t}\n\t\treturn importedContainers;\n\t}\n\n\tprivate List<Field> getContainerFields(Class<?> containersClass) {\n\t\tList<Field> containerFields = new ArrayList<>();\n\t\tReflectionUtils.doWithFields(containersClass, containerFields::add, this::isContainerField);\n\t\treturn List.copyOf(containerFields);\n\t}\n\n\tprivate boolean isContainerField(Field candidate) {\n\t\treturn Container.class.isAssignableFrom(candidate.getType());\n\t}\n\n\tprivate void assertValid(Field field) {\n\t\tAssert.state(Modifier.isStatic(field.getModifiers()),\n\t\t\t\t() -> \"Container field '\" + field.getName() + \"' must be static\");\n\t}\n\n\tprivate Container<?> getContainer(Field field) {\n\t\tReflectionUtils.makeAccessible(field);\n\t\tContainer<?> container = (Container<?>) ReflectionUtils.getField(field, null);\n\t\tAssert.state(container != null, () -> \"Container field '\" + field.getName() + \"' must not have a null value\");\n\t\treturn container;\n\t}\n\n\tprivate void registerBeanDefinition(BeanDefinitionRegistry registry, Field field, Container<?> container) {\n\t\tContainerImageMetadata containerMetadata = new ContainerImageMetadata(container.getDockerImageName());\n\t\tTestcontainerFieldBeanDefinition beanDefinition = new TestcontainerFieldBeanDefinition(field, container);\n\t\tcontainerMetadata.addTo(beanDefinition);\n\t\tString beanName = generateBeanName(field);\n\t\tregistry.registerBeanDefinition(beanName, beanDefinition);\n\t}\n\n\tprivate String generateBeanName(Field field) {\n\t\treturn \"importTestContainer.%s.%s\".formatted(field.getDeclaringClass().getName(), field.getName());\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/DynamicPropertySourceMethodsImporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.context;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.beans.factory.config.ConstructorArgumentValues;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.core.MethodIntrospector;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.test.context.DynamicPropertyRegistrar;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Used by {@link ImportTestcontainersRegistrar} to import\n * {@link DynamicPropertySource @DynamicPropertySource} through a\n * {@link DynamicPropertyRegistrar}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass DynamicPropertySourceMethodsImporter {\n\n\tvoid registerDynamicPropertySources(BeanDefinitionRegistry beanDefinitionRegistry, Class<?> definitionClass,\n\t\t\tSet<Startable> importedContainers) {\n\t\tSet<Method> methods = MethodIntrospector.selectMethods(definitionClass, this::isAnnotated);\n\t\tif (methods.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tmethods.forEach(this::assertValid);\n\t\tRootBeanDefinition registrarDefinition = new RootBeanDefinition();\n\t\tregistrarDefinition.setBeanClass(DynamicPropertySourcePropertyRegistrar.class);\n\t\tConstructorArgumentValues arguments = new ConstructorArgumentValues();\n\t\targuments.addGenericArgumentValue(methods);\n\t\targuments.addGenericArgumentValue(importedContainers);\n\t\tregistrarDefinition.setConstructorArgumentValues(arguments);\n\t\tbeanDefinitionRegistry.registerBeanDefinition(definitionClass.getName() + \".dynamicPropertyRegistrar\",\n\t\t\t\tregistrarDefinition);\n\t}\n\n\tprivate boolean isAnnotated(Method method) {\n\t\treturn MergedAnnotations.from(method).isPresent(DynamicPropertySource.class);\n\t}\n\n\tprivate void assertValid(Method method) {\n\t\tAssert.state(Modifier.isStatic(method.getModifiers()),\n\t\t\t\t() -> \"@DynamicPropertySource method '\" + method.getName() + \"' must be static\");\n\t\tClass<?>[] types = method.getParameterTypes();\n\t\tAssert.state(types.length == 1 && types[0] == DynamicPropertyRegistry.class,\n\t\t\t\t() -> \"@DynamicPropertySource method '\" + method.getName()\n\t\t\t\t\t\t+ \"' must accept a single DynamicPropertyRegistry argument\");\n\t}\n\n\tstatic class DynamicPropertySourcePropertyRegistrar implements DynamicPropertyRegistrar {\n\n\t\tprivate final Set<Method> methods;\n\n\t\tprivate final Set<Startable> containers;\n\n\t\tDynamicPropertySourcePropertyRegistrar(Set<Method> methods, Set<Startable> containers) {\n\t\t\tthis.methods = methods;\n\t\t\tthis.containers = containers;\n\t\t}\n\n\t\t@Override\n\t\tpublic void accept(DynamicPropertyRegistry registry) {\n\t\t\tDynamicPropertyRegistry containersBackedRegistry = new ContainersBackedDynamicPropertyRegistry(registry,\n\t\t\t\t\tthis.containers);\n\t\t\tthis.methods.forEach((method) -> {\n\t\t\t\tReflectionUtils.makeAccessible(method);\n\t\t\t\tReflectionUtils.invokeMethod(method, null, containersBackedRegistry);\n\t\t\t});\n\t\t}\n\n\t}\n\n\tstatic class ContainersBackedDynamicPropertyRegistry implements DynamicPropertyRegistry {\n\n\t\tprivate final DynamicPropertyRegistry delegate;\n\n\t\tprivate final Set<Startable> containers;\n\n\t\tContainersBackedDynamicPropertyRegistry(DynamicPropertyRegistry delegate, Set<Startable> containers) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.containers = containers;\n\t\t}\n\n\t\t@Override\n\t\tpublic void add(String name, Supplier<Object> valueSupplier) {\n\t\t\tthis.delegate.add(name, () -> {\n\t\t\t\tstartContainers();\n\t\t\t\treturn valueSupplier.get();\n\t\t\t});\n\t\t}\n\n\t\tprivate void startContainers() {\n\t\t\tthis.containers.forEach(Startable::start);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ImportTestcontainers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.context;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.properties.TestcontainersPropertySourceAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Imports idiomatic Testcontainers declaration classes into the Spring\n * {@link ApplicationContext}. The following elements will be considered from the imported\n * classes:\n * <ul>\n * <li>All static fields that declare {@link Container} values.</li>\n * <li>All {@code @DynamicPropertySource} annotated methods.</li>\n * </ul>\n *\n * @author Phillip Webb\n * @since 3.1.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(ImportTestcontainersRegistrar.class)\n@ImportAutoConfiguration(TestcontainersPropertySourceAutoConfiguration.class)\npublic @interface ImportTestcontainers {\n\n\t/**\n\t * The declaration classes to import. If no {@code value} is defined then the class\n\t * that declares the {@link ImportTestcontainers @ImportTestcontainers} annotation\n\t * will be searched.\n\t * @return the definition classes to import\n\t */\n\tClass<?>[] value() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/ImportTestcontainersRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.context;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} for\n * {@link ImportTestcontainers @ImportTestcontainers}.\n *\n * @author Phillip Webb\n * @see ContainerFieldsImporter\n * @see DynamicPropertySourceMethodsImporter\n */\nclass ImportTestcontainersRegistrar implements ImportBeanDefinitionRegistrar {\n\n\tprivate static final String DYNAMIC_PROPERTY_SOURCE_CLASS = \"org.springframework.test.context.DynamicPropertySource\";\n\n\tprivate final ContainerFieldsImporter containerFieldsImporter;\n\n\tprivate final @Nullable DynamicPropertySourceMethodsImporter dynamicPropertySourceMethodsImporter;\n\n\tImportTestcontainersRegistrar(Environment environment) {\n\t\tthis.containerFieldsImporter = new ContainerFieldsImporter();\n\t\tthis.dynamicPropertySourceMethodsImporter = (!ClassUtils.isPresent(DYNAMIC_PROPERTY_SOURCE_CLASS, null)) ? null\n\t\t\t\t: new DynamicPropertySourceMethodsImporter();\n\t}\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tMergedAnnotation<ImportTestcontainers> annotation = importingClassMetadata.getAnnotations()\n\t\t\t.get(ImportTestcontainers.class);\n\t\tClass<?>[] definitionClasses = annotation.getClassArray(MergedAnnotation.VALUE);\n\t\tif (ObjectUtils.isEmpty(definitionClasses)) {\n\t\t\tClass<?> importingClass = ClassUtils.resolveClassName(importingClassMetadata.getClassName(), null);\n\t\t\tdefinitionClasses = new Class<?>[] { importingClass };\n\t\t}\n\t\tregisterBeanDefinitions(registry, definitionClasses);\n\t}\n\n\tprivate void registerBeanDefinitions(BeanDefinitionRegistry registry, Class<?>[] definitionClasses) {\n\t\tfor (Class<?> definitionClass : definitionClasses) {\n\t\t\tSet<Startable> importedContainers = this.containerFieldsImporter.registerBeanDefinitions(registry,\n\t\t\t\t\tdefinitionClass);\n\t\t\tif (this.dynamicPropertySourceMethodsImporter != null) {\n\t\t\t\tthis.dynamicPropertySourceMethodsImporter.registerDynamicPropertySources(registry, definitionClass,\n\t\t\t\t\t\timportedContainers);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/TestcontainerFieldBeanDefinition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.context;\n\nimport java.lang.reflect.Field;\n\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.testcontainers.beans.TestcontainerBeanDefinition;\nimport org.springframework.core.annotation.MergedAnnotations;\n\n/**\n * {@link RootBeanDefinition} used for testcontainer bean definitions.\n *\n * @author Phillip Webb\n */\nclass TestcontainerFieldBeanDefinition extends RootBeanDefinition implements TestcontainerBeanDefinition {\n\n\tprivate final Container<?> container;\n\n\tprivate final MergedAnnotations annotations;\n\n\tTestcontainerFieldBeanDefinition(Field field, Container<?> container) {\n\t\tthis.container = container;\n\t\tthis.annotations = MergedAnnotations.from(field);\n\t\tthis.setBeanClass(container.getClass());\n\t\tsetInstanceSupplier(() -> container);\n\t\tsetRole(ROLE_INFRASTRUCTURE);\n\t}\n\n\t@Override\n\tpublic String getContainerImageName() {\n\t\treturn this.container.getDockerImageName();\n\t}\n\n\t@Override\n\tpublic MergedAnnotations getAnnotations() {\n\t\treturn this.annotations;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring context support classes for Testcontainers.\n */\n@NullMarked\npackage org.springframework.boot.testcontainers.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/DockerEnvironmentNotFoundFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@code FailureAnalyzer} that performs analysis of failures caused by Testcontainers\n * not finding a valid Docker environment.\n *\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n */\nclass DockerEnvironmentNotFoundFailureAnalyzer extends AbstractFailureAnalyzer<IllegalStateException> {\n\n\tprivate static final String EXPECTED_MESSAGE = \"Could not find a valid Docker environment\";\n\n\tprivate static final String DESCRIPTION = \"Could not find a valid Docker environment for Testcontainers.\";\n\n\tprivate static final String ACTION = \"\"\"\n\t\t\t    - Ensure a Docker-compatible container engine is installed and running.\n\t\t\t    - If running Testcontainers in CI, ensure the runner has access to the daemon, typically by using a mounted socket or a Docker-in-Docker setup.\n\t\t\t    - Review the Testcontainers documentation for troubleshooting and advanced configuration options.\n\t\t\t\"\"\";\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, IllegalStateException cause) {\n\t\tif (StringUtils.hasText(cause.getMessage()) && cause.getMessage().contains(EXPECTED_MESSAGE)) {\n\t\t\treturn new FailureAnalysis(DESCRIPTION, ACTION, cause);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * {@link ApplicationContextInitializer} to manage the lifecycle of {@link Startable\n * startable containers}.\n *\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic class TestcontainersLifecycleApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\tprivate static final Set<ConfigurableApplicationContext> applied = Collections.newSetFromMap(new WeakHashMap<>());\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tsynchronized (applied) {\n\t\t\tif (!applied.add(applicationContext)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();\n\t\tapplicationContext.addBeanFactoryPostProcessor(new TestcontainersLifecycleBeanFactoryPostProcessor());\n\t\tTestcontainersStartup startup = TestcontainersStartup.get(applicationContext.getEnvironment());\n\t\tTestcontainersLifecycleBeanPostProcessor beanPostProcessor = new TestcontainersLifecycleBeanPostProcessor(\n\t\t\t\tbeanFactory, startup);\n\t\tbeanFactory.addBeanPostProcessor(beanPostProcessor);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleBeanFactoryPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link BeanFactoryPostProcessor} to prevent {@link AutoCloseable} destruction calls so\n * that {@link TestcontainersLifecycleBeanPostProcessor} can be smarter about which\n * containers to close.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @see TestcontainersLifecycleApplicationContextInitializer\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass TestcontainersLifecycleBeanFactoryPostProcessor implements BeanFactoryPostProcessor {\n\n\t@Override\n\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\tfor (String beanName : beanFactory.getBeanNamesForType(Startable.class, false, false)) {\n\t\t\ttry {\n\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\tString destroyMethodName = beanDefinition.getDestroyMethodName();\n\t\t\t\tif (destroyMethodName == null || AbstractBeanDefinition.INFER_METHOD.equals(destroyMethodName)) {\n\t\t\t\t\tbeanDefinition.setDestroyMethodName(\"\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.ContainerState;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.lifecycle.Startable;\nimport org.testcontainers.utility.TestcontainersConfiguration;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * {@link BeanPostProcessor} to manage the lifecycle of {@link Startable startable\n * containers}.\n * <p>\n * As well as starting containers, this {@link BeanPostProcessor} will also ensure that\n * all containers are started as early as possible in the\n * {@link ConfigurableListableBeanFactory#preInstantiateSingletons() pre-instantiate\n * singletons} phase.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @see TestcontainersLifecycleApplicationContextInitializer\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPostProcessor {\n\n\tprivate static final Log logger = LogFactory.getLog(TestcontainersLifecycleBeanPostProcessor.class);\n\n\tprivate final ConfigurableListableBeanFactory beanFactory;\n\n\tprivate final TestcontainersStartup startup;\n\n\tprivate final AtomicReference<Startables> startables = new AtomicReference<>(Startables.UNSTARTED);\n\n\tprivate final AtomicBoolean containersInitialized = new AtomicBoolean();\n\n\tTestcontainersLifecycleBeanPostProcessor(ConfigurableListableBeanFactory beanFactory,\n\t\t\tTestcontainersStartup startup) {\n\t\tthis.beanFactory = beanFactory;\n\t\tthis.startup = startup;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (this.beanFactory.isConfigurationFrozen() && !isAotProcessingInProgress()) {\n\t\t\tinitializeContainers();\n\t\t}\n\t\tif (bean instanceof Startable startableBean) {\n\t\t\tif (this.startables.compareAndExchange(Startables.UNSTARTED, Startables.STARTING) == Startables.UNSTARTED) {\n\t\t\t\tinitializeStartables(startableBean, beanName);\n\t\t\t}\n\t\t\telse if (this.startables.get() == Startables.STARTED) {\n\t\t\t\tlogger.trace(LogMessage.format(\"Starting container %s\", beanName));\n\t\t\t\tTestcontainersStartup.start(startableBean);\n\t\t\t}\n\t\t}\n\t\treturn bean;\n\t}\n\n\tprivate boolean isAotProcessingInProgress() {\n\t\treturn Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING);\n\t}\n\n\tprivate void initializeStartables(Startable startableBean, String startableBeanName) {\n\t\tlogger.trace(LogMessage.format(\"Initializing startables\"));\n\t\tList<String> beanNames = new ArrayList<>(getBeanNames(Startable.class));\n\t\tbeanNames.remove(startableBeanName);\n\t\tList<Object> beans = getBeans(beanNames);\n\t\tif (beans == null) {\n\t\t\tlogger.trace(LogMessage.format(\"Failed to obtain startables %s\", beanNames));\n\t\t\tthis.startables.set(Startables.UNSTARTED);\n\t\t\treturn;\n\t\t}\n\t\tbeanNames.add(startableBeanName);\n\t\tbeans.add(startableBean);\n\t\tlogger.trace(LogMessage.format(\"Starting startables %s\", beanNames));\n\t\tstart(beans);\n\t\tthis.startables.set(Startables.STARTED);\n\t\tif (!beanNames.isEmpty()) {\n\t\t\tlogger.debug(LogMessage.format(\"Initialized and started startable beans '%s'\", beanNames));\n\t\t}\n\t}\n\n\tprivate void start(List<Object> beans) {\n\t\tSet<Startable> startables = beans.stream()\n\t\t\t.filter(Startable.class::isInstance)\n\t\t\t.map(Startable.class::cast)\n\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t\tthis.startup.start(startables);\n\t}\n\n\tprivate void initializeContainers() {\n\t\tif (this.containersInitialized.compareAndSet(false, true)) {\n\t\t\tlogger.trace(\"Initializing containers\");\n\t\t\tList<String> beanNames = getBeanNames(ContainerState.class);\n\t\t\tList<Object> beans = getBeans(beanNames);\n\t\t\tif (beans != null) {\n\t\t\t\tlogger.trace(LogMessage.format(\"Initialized containers %s\", beanNames));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.trace(LogMessage.format(\"Failed to initialize containers %s\", beanNames));\n\t\t\t\tthis.containersInitialized.set(false);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate List<String> getBeanNames(Class<?> type) {\n\t\treturn List.of(this.beanFactory.getBeanNamesForType(type, true, false));\n\t}\n\n\tprivate @Nullable List<Object> getBeans(List<String> beanNames) {\n\t\tList<Object> beans = new ArrayList<>(beanNames.size());\n\t\tfor (String beanName : beanNames) {\n\t\t\ttry {\n\t\t\t\tbeans.add(this.beanFactory.getBean(beanName));\n\t\t\t}\n\t\t\tcatch (BeanCreationException ex) {\n\t\t\t\tif (ex.contains(BeanCurrentlyInCreationException.class)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t\treturn beans;\n\t}\n\n\t@Override\n\tpublic boolean requiresDestruction(Object bean) {\n\t\treturn bean instanceof Startable;\n\t}\n\n\t@Override\n\tpublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof Startable startable && !isDestroyedByFramework(beanName) && !isReusedContainer(bean)) {\n\t\t\tstartable.close();\n\t\t}\n\t}\n\n\tprivate boolean isDestroyedByFramework(String beanName) {\n\t\ttry {\n\t\t\tBeanDefinition beanDefinition = this.beanFactory.getBeanDefinition(beanName);\n\t\t\tString destroyMethodName = beanDefinition.getDestroyMethodName();\n\t\t\treturn !\"\".equals(destroyMethodName);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean isReusedContainer(Object bean) {\n\t\treturn (bean instanceof GenericContainer<?> container) && container.isShouldBeReused()\n\t\t\t\t&& TestcontainersConfiguration.getInstance().environmentSupportsReuse();\n\t}\n\n\tenum Startables {\n\n\t\tUNSTARTED, STARTING, STARTED\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.lifecycle.Startable;\nimport org.testcontainers.lifecycle.Startables;\n\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\n\n/**\n * Testcontainers startup strategies. The strategy to use can be configured in the Spring\n * {@link Environment} with a {@value #PROPERTY} property.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic enum TestcontainersStartup {\n\n\t/**\n\t * Startup containers sequentially.\n\t */\n\tSEQUENTIAL {\n\n\t\t@Override\n\t\tvoid start(Collection<? extends Startable> startables) {\n\t\t\tstartables.forEach(TestcontainersStartup::start);\n\t\t}\n\n\t},\n\n\t/**\n\t * Startup containers in parallel.\n\t */\n\tPARALLEL {\n\n\t\t@Override\n\t\tvoid start(Collection<? extends Startable> startables) {\n\t\t\tSingleStartables singleStartables = new SingleStartables();\n\t\t\tStartables.deepStart(startables.stream().map(singleStartables::getOrCreate)).join();\n\t\t}\n\n\t};\n\n\t/**\n\t * The {@link Environment} property used to change the {@link TestcontainersStartup}\n\t * strategy.\n\t */\n\tpublic static final String PROPERTY = \"spring.testcontainers.beans.startup\";\n\n\tabstract void start(Collection<? extends Startable> startables);\n\n\tstatic TestcontainersStartup get(@Nullable ConfigurableEnvironment environment) {\n\t\treturn get((environment != null) ? environment.getProperty(PROPERTY) : null);\n\t}\n\n\tprivate static TestcontainersStartup get(@Nullable String value) {\n\t\tif (value == null) {\n\t\t\treturn SEQUENTIAL;\n\t\t}\n\t\tString canonicalName = getCanonicalName(value);\n\t\tfor (TestcontainersStartup candidate : values()) {\n\t\t\tif (candidate.name().equalsIgnoreCase(canonicalName)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Unknown '%s' property value '%s'\".formatted(PROPERTY, value));\n\t}\n\n\tprivate static String getCanonicalName(String name) {\n\t\tStringBuilder canonicalName = new StringBuilder(name.length());\n\t\tname.chars()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.forEach((c) -> canonicalName.append((char) c));\n\t\treturn canonicalName.toString();\n\t}\n\n\t/**\n\t * Start the given {@link Startable} unless is's detected as already running.\n\t * @param startable the startable to start\n\t * @since 3.4.1\n\t */\n\tpublic static void start(Startable startable) {\n\t\tif (!isRunning(startable)) {\n\t\t\tstartable.start();\n\t\t}\n\t}\n\n\tprivate static boolean isRunning(Startable startable) {\n\t\ttry {\n\t\t\treturn (startable instanceof Container<?> container) && container.isRunning();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn false;\n\n\t\t}\n\t}\n\n\t/**\n\t * Tracks and adapts {@link Startable} instances to use\n\t * {@link TestcontainersStartup#start(Startable)} so containers are only started once\n\t * even when calling {@link Startables#deepStart(java.util.stream.Stream)}.\n\t */\n\tprivate static final class SingleStartables {\n\n\t\tprivate final Map<Startable, SingleStartable> adapters = new HashMap<>();\n\n\t\tSingleStartable getOrCreate(Startable startable) {\n\t\t\treturn this.adapters.computeIfAbsent(startable, this::create);\n\t\t}\n\n\t\tprivate SingleStartable create(Startable startable) {\n\t\t\treturn new SingleStartable(this, startable);\n\t\t}\n\n\t\trecord SingleStartable(SingleStartables singleStartables, Startable startable) implements Startable {\n\n\t\t\t@Override\n\t\t\tpublic Set<Startable> getDependencies() {\n\t\t\t\tSet<Startable> dependencies = this.startable.getDependencies();\n\t\t\t\tif (dependencies.isEmpty()) {\n\t\t\t\t\treturn dependencies;\n\t\t\t\t}\n\t\t\t\treturn dependencies.stream()\n\t\t\t\t\t.map(this.singleStartables::getOrCreate)\n\t\t\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void start() {\n\t\t\t\tTestcontainersStartup.start(this.startable);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void stop() {\n\t\t\t\tthis.startable.stop();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/lifecycle/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Utilities and helpers to allow testcontainers to be used in a Spring\n * {@link org.springframework.context.ApplicationContext ApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers.\n */\n@NullMarked\npackage org.springframework.boot.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/properties/TestcontainersPropertySourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.properties;\n\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.support.DynamicPropertyRegistrarBeanInitializer;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration\n * Auto-configuration} to add support for properties sourced from a Testcontainers\n * {@link GenericContainer container}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 3.1.0\n */\n@AutoConfiguration\n@Order(Ordered.HIGHEST_PRECEDENCE)\n@ConditionalOnClass(DynamicPropertyRegistry.class)\npublic final class TestcontainersPropertySourceAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\tstatic DynamicPropertyRegistrarBeanInitializer dynamicPropertyRegistrarBeanInitializer() {\n\t\treturn new DynamicPropertyRegistrarBeanInitializer();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/properties/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Dynamic container properties support.\n */\n@NullMarked\npackage org.springframework.boot.testcontainers.properties;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/BeanOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.origin.Origin;\n\n/**\n * {@link Origin} backed by a Spring Bean.\n *\n * @author Phillip Webb\n */\nclass BeanOrigin implements Origin {\n\n\tprivate final String beanName;\n\n\tprivate final @Nullable String resourceDescription;\n\n\tBeanOrigin(String beanName, @Nullable BeanDefinition beanDefinition) {\n\t\tthis.beanName = beanName;\n\t\tthis.resourceDescription = (beanDefinition != null) ? beanDefinition.getResourceDescription() : null;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tBeanOrigin other = (BeanOrigin) obj;\n\t\treturn Objects.equals(this.beanName, other.beanName);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.beanName.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder result = new StringBuilder();\n\t\tresult.append(\"Bean '\");\n\t\tresult.append(this.beanName);\n\t\tresult.append(\"'\");\n\t\tif (this.resourceDescription != null) {\n\t\t\tresult.append(\" defined in \");\n\t\t\tresult.append(this.resourceDescription);\n\t\t}\n\t\treturn result.toString();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ConnectionDetailsRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.BiFunction;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.container.ContainerImageMetadata;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactoryNotFoundException;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsNotFoundException;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Class used to register {@link ConnectionDetails} bean definitions from\n * {@link ContainerConnectionSource} instances.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConnectionDetailsRegistrar {\n\n\tprivate static final Log logger = LogFactory.getLog(ConnectionDetailsRegistrar.class);\n\n\tprivate final ListableBeanFactory beanFactory;\n\n\tprivate final ConnectionDetailsFactories connectionDetailsFactories;\n\n\tConnectionDetailsRegistrar(ListableBeanFactory beanFactory, ConnectionDetailsFactories connectionDetailsFactories) {\n\t\tthis.beanFactory = beanFactory;\n\t\tthis.connectionDetailsFactories = connectionDetailsFactories;\n\t}\n\n\tvoid registerBeanDefinitions(BeanDefinitionRegistry registry, Collection<ContainerConnectionSource<?>> sources) {\n\t\tsources.forEach((source) -> registerBeanDefinitions(registry, source));\n\t}\n\n\tvoid registerBeanDefinitions(BeanDefinitionRegistry registry, ContainerConnectionSource<?> source) {\n\t\ttry {\n\t\t\tthis.connectionDetailsFactories.getConnectionDetails(source, true)\n\t\t\t\t.forEach((connectionDetailsType, connectionDetails) -> registerBeanDefinition(registry, source,\n\t\t\t\t\t\tconnectionDetailsType, connectionDetails));\n\t\t}\n\t\tcatch (ConnectionDetailsFactoryNotFoundException ex) {\n\t\t\trethrowConnectionDetails(source, ex, ConnectionDetailsFactoryNotFoundException::new);\n\t\t}\n\t\tcatch (ConnectionDetailsNotFoundException ex) {\n\t\t\trethrowConnectionDetails(source, ex, ConnectionDetailsNotFoundException::new);\n\t\t}\n\t}\n\n\tprivate void rethrowConnectionDetails(ContainerConnectionSource<?> source, RuntimeException ex,\n\t\t\tBiFunction<String, Throwable, RuntimeException> exceptionFactory) {\n\t\tif (!StringUtils.hasText(source.getConnectionName())) {\n\t\t\tStringBuilder message = new StringBuilder(ex.getMessage());\n\t\t\tmessage.append((!message.toString().endsWith(\".\")) ? \".\" : \"\");\n\t\t\tmessage.append(\" You may need to add a 'name' to your @ServiceConnection annotation\");\n\t\t\tthrow exceptionFactory.apply(message.toString(), ex.getCause());\n\t\t}\n\t\tthrow ex;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> void registerBeanDefinition(BeanDefinitionRegistry registry, ContainerConnectionSource<?> source,\n\t\t\tClass<?> connectionDetailsType, ConnectionDetails connectionDetails) {\n\t\tString[] existingBeans = this.beanFactory.getBeanNamesForType(connectionDetailsType);\n\t\tif (!ObjectUtils.isEmpty(existingBeans)) {\n\t\t\tlogger.debug(LogMessage.of(() -> \"Skipping registration of %s due to existing beans %s\".formatted(source,\n\t\t\t\t\tArrays.asList(existingBeans))));\n\t\t\treturn;\n\t\t}\n\t\tContainerImageMetadata containerMetadata = new ContainerImageMetadata(source.getContainerImageName());\n\t\tString beanName = getBeanName(source, connectionDetails);\n\t\tClass<T> beanType = (Class<T>) connectionDetails.getClass();\n\t\tSupplier<T> beanSupplier = () -> (T) connectionDetails;\n\t\tlogger.debug(LogMessage.of(() -> \"Registering '%s' for %s\".formatted(beanName, source)));\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(beanType, beanSupplier);\n\t\tbeanDefinition.setAttribute(ServiceConnection.class.getName(), true);\n\t\tcontainerMetadata.addTo(beanDefinition);\n\t\tregistry.registerBeanDefinition(beanName, beanDefinition);\n\t}\n\n\tprivate String getBeanName(ContainerConnectionSource<?> source, ConnectionDetails connectionDetails) {\n\t\tList<String> parts = new ArrayList<>();\n\t\tparts.add(ClassUtils.getShortNameAsProperty(connectionDetails.getClass()));\n\t\tparts.add(\"for\");\n\t\tparts.add(source.getBeanNameSuffix());\n\t\treturn StringUtils.uncapitalize(parts.stream().map(StringUtils::capitalize).collect(Collectors.joining()));\n\t}\n\n\tclass ServiceConnectionBeanRegistrationExcludeFilter implements BeanRegistrationExcludeFilter {\n\n\t\t@Override\n\t\tpublic boolean isExcludedFromAotProcessing(RegisteredBean registeredBean) {\n\t\t\treturn registeredBean.getMergedBeanDefinition().getAttribute(ServiceConnection.class.getName()) != null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersStartup;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.FailureHandler;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Base class for {@link ConnectionDetailsFactory} implementations that provide\n * {@link ConnectionDetails} from a {@link ContainerConnectionSource}.\n *\n * @param <D> the connection details type\n * @param <C> the container type\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic abstract class ContainerConnectionDetailsFactory<C extends Container<?>, D extends ConnectionDetails>\n\t\timplements ConnectionDetailsFactory<ContainerConnectionSource<C>, D> {\n\n\t/**\n\t * Constant passed to the constructor when any connection name is accepted.\n\t */\n\tprotected static final @Nullable String ANY_CONNECTION_NAME = null;\n\n\tprivate final List<String> connectionNames;\n\n\tprivate final String[] requiredClassNames;\n\n\t/**\n\t * Create a new {@link ContainerConnectionDetailsFactory} instance that accepts\n\t * {@link #ANY_CONNECTION_NAME any connection name}.\n\t */\n\tprotected ContainerConnectionDetailsFactory() {\n\t\tthis(ANY_CONNECTION_NAME);\n\t}\n\n\t/**\n\t * Create a new {@link ContainerConnectionDetailsFactory} instance with the given\n\t * connection name restriction.\n\t * @param connectionName the required connection name or {@link #ANY_CONNECTION_NAME}\n\t * @param requiredClassNames the names of classes that must be present\n\t */\n\tprotected ContainerConnectionDetailsFactory(@Nullable String connectionName, String... requiredClassNames) {\n\t\tthis(Arrays.asList(connectionName), requiredClassNames);\n\t}\n\n\t/**\n\t * Create a new {@link ContainerConnectionDetailsFactory} instance with the given\n\t * supported connection names.\n\t * @param connectionNames the supported connection names\n\t * @param requiredClassNames the names of classes that must be present\n\t * @since 3.4.0\n\t */\n\tprotected ContainerConnectionDetailsFactory(List<String> connectionNames, String... requiredClassNames) {\n\t\tAssert.notEmpty(connectionNames, \"'connectionNames' must not be empty\");\n\t\tthis.connectionNames = connectionNames;\n\t\tthis.requiredClassNames = requiredClassNames;\n\t}\n\n\t@Override\n\tpublic final @Nullable D getConnectionDetails(ContainerConnectionSource<C> source) {\n\t\tif (!hasRequiredClasses()) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\t@Nullable Class<?>[] generics = resolveGenerics();\n\t\t\tClass<?> requiredContainerType = generics[0];\n\t\t\tClass<?> requiredConnectionDetailsType = generics[1];\n\t\t\tAssert.state(requiredContainerType != null, \"'requiredContainerType' must not be null\");\n\t\t\tAssert.state(requiredConnectionDetailsType != null, \"'requiredConnectionDetailsType' must not be null\");\n\t\t\tif (sourceAccepts(source, requiredContainerType, requiredConnectionDetailsType)) {\n\t\t\t\treturn getContainerConnectionDetails(source);\n\t\t\t}\n\t\t}\n\t\tcatch (NoClassDefFoundError ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return if the given source accepts the connection. By default this method checks\n\t * each connection name.\n\t * @param source the container connection source\n\t * @param requiredContainerType the required container type\n\t * @param requiredConnectionDetailsType the required connection details type\n\t * @return if the source accepts the connection\n\t * @since 3.4.0\n\t */\n\tprotected boolean sourceAccepts(ContainerConnectionSource<C> source, Class<?> requiredContainerType,\n\t\t\tClass<?> requiredConnectionDetailsType) {\n\t\tfor (String requiredConnectionName : this.connectionNames) {\n\t\t\tif (source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean hasRequiredClasses() {\n\t\treturn ObjectUtils.isEmpty(this.requiredClassNames) || Arrays.stream(this.requiredClassNames)\n\t\t\t.allMatch((requiredClassName) -> ClassUtils.isPresent(requiredClassName, null));\n\t}\n\n\tprivate @Nullable Class<?>[] resolveGenerics() {\n\t\treturn ResolvableType.forClass(ContainerConnectionDetailsFactory.class, getClass()).resolveGenerics();\n\t}\n\n\t/**\n\t * Get the {@link ConnectionDetails} from the given {@link ContainerConnectionSource}\n\t * {@code source}. May return {@code null} if no connection can be created. Result\n\t * types should consider extending {@link ContainerConnectionDetails}.\n\t * @param source the source\n\t * @return the service connection or {@code null}.\n\t */\n\tprotected abstract @Nullable D getContainerConnectionDetails(ContainerConnectionSource<C> source);\n\n\t/**\n\t * Base class for {@link ConnectionDetails} results that are backed by a\n\t * {@link ContainerConnectionSource}.\n\t *\n\t * @param <C> the container type\n\t */\n\tprotected static class ContainerConnectionDetails<C extends Container<?>>\n\t\t\timplements ConnectionDetails, OriginProvider, InitializingBean, ApplicationContextAware {\n\n\t\tprivate final ContainerConnectionSource<C> source;\n\n\t\tprivate volatile @Nullable C container;\n\n\t\tprivate volatile @Nullable SslBundle sslBundle;\n\n\t\t/**\n\t\t * Create a new {@link ContainerConnectionDetails} instance.\n\t\t * @param source the source {@link ContainerConnectionSource}\n\t\t */\n\t\tprotected ContainerConnectionDetails(ContainerConnectionSource<C> source) {\n\t\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\t\tthis.source = source;\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterPropertiesSet() throws Exception {\n\t\t\tthis.container = this.source.getContainerSupplier().get();\n\t\t}\n\n\t\t/**\n\t\t * Return the container that back this connection details instance. This method\n\t\t * can only be called once the connection details bean has been initialized.\n\t\t * @return the container instance\n\t\t */\n\t\tprotected final C getContainer() {\n\t\t\tC container = this.container;\n\t\t\tAssert.state(container != null,\n\t\t\t\t\t\"Container cannot be obtained before the connection details bean has been initialized\");\n\t\t\tif (container instanceof Startable startable) {\n\t\t\t\tTestcontainersStartup.start(startable);\n\t\t\t}\n\t\t\treturn container;\n\t\t}\n\n\t\t/**\n\t\t * Return the {@link SslBundle} to use with this connection or {@code null}.\n\t\t * @return the ssl bundle or {@code null}\n\t\t * @since 3.5.0\n\t\t */\n\t\tprotected @Nullable SslBundle getSslBundle() {\n\t\t\tif (this.source.getSslBundleSource() == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tSslBundle sslBundle = this.sslBundle;\n\t\t\tif (sslBundle == null) {\n\t\t\t\tsslBundle = this.source.getSslBundleSource().getSslBundle();\n\t\t\t\tthis.sslBundle = sslBundle;\n\t\t\t}\n\t\t\treturn sslBundle;\n\t\t}\n\n\t\t/**\n\t\t * Whether the field or bean is annotated with the given annotation.\n\t\t * @param annotationType the annotation to check\n\t\t * @return whether the field or bean is annotated with the annotation\n\t\t * @since 3.5.0\n\t\t */\n\t\tprotected boolean hasAnnotation(Class<? extends Annotation> annotationType) {\n\t\t\treturn this.source.hasAnnotation(annotationType);\n\t\t}\n\n\t\t@Override\n\t\tpublic Origin getOrigin() {\n\t\t\treturn this.source.getOrigin();\n\t\t}\n\n\t\t@Override\n\t\t@Deprecated(since = \"3.4.0\", forRemoval = true)\n\t\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\t}\n\n\t}\n\n\tstatic class ContainerConnectionDetailsFactoriesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate static final Log logger = LogFactory.getLog(ContainerConnectionDetailsFactoriesRuntimeHints.class);\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tSpringFactoriesLoader.forDefaultResourceLocation(classLoader)\n\t\t\t\t.load(ConnectionDetailsFactory.class, FailureHandler.logging(logger))\n\t\t\t\t.stream()\n\t\t\t\t.flatMap(this::requiredClassNames)\n\t\t\t\t.forEach((requiredClassName) -> hints.reflection()\n\t\t\t\t\t.registerTypeIfPresent(classLoader, requiredClassName));\n\t\t}\n\n\t\tprivate Stream<String> requiredClassNames(ConnectionDetailsFactory<?, ?> connectionDetailsFactory) {\n\t\t\treturn (connectionDetailsFactory instanceof ContainerConnectionDetailsFactory<?, ?> containerConnectionDetailsFactory)\n\t\t\t\t\t? Stream.of(containerConnectionDetailsFactory.requiredClassNames) : Stream.empty();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginProvider;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.StringUtils;\n\n/**\n * Passed to {@link ContainerConnectionDetailsFactory} to provide details of the\n * {@link ServiceConnection @ServiceConnection} annotated {@link Container} that provides\n * the service.\n *\n * @param <C> the generic container type\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n * @see ContainerConnectionDetailsFactory\n */\npublic final class ContainerConnectionSource<C extends Container<?>> implements OriginProvider {\n\n\tprivate static final Log logger = LogFactory.getLog(ContainerConnectionSource.class);\n\n\tprivate final String beanNameSuffix;\n\n\tprivate final Origin origin;\n\n\tprivate final Class<C> containerType;\n\n\tprivate final @Nullable String containerImageName;\n\n\tprivate final @Nullable String connectionName;\n\n\tprivate final Set<Class<?>> connectionDetailsTypes;\n\n\tprivate final Supplier<C> containerSupplier;\n\n\tprivate final @Nullable SslBundleSource sslBundleSource;\n\n\tprivate final @Nullable MergedAnnotations annotations;\n\n\tContainerConnectionSource(String beanNameSuffix, Origin origin, Class<C> containerType,\n\t\t\t@Nullable String containerImageName, MergedAnnotation<ServiceConnection> annotation,\n\t\t\tSupplier<C> containerSupplier, @Nullable SslBundleSource sslBundleSource,\n\t\t\t@Nullable MergedAnnotations annotations) {\n\t\tthis.beanNameSuffix = beanNameSuffix;\n\t\tthis.origin = origin;\n\t\tthis.containerType = containerType;\n\t\tthis.containerImageName = containerImageName;\n\t\tthis.connectionName = getOrDeduceConnectionName(annotation.getString(\"name\"), containerImageName);\n\t\tthis.connectionDetailsTypes = Set.of(annotation.getClassArray(\"type\"));\n\t\tthis.containerSupplier = containerSupplier;\n\t\tthis.sslBundleSource = sslBundleSource;\n\t\tthis.annotations = annotations;\n\t}\n\n\tContainerConnectionSource(String beanNameSuffix, Origin origin, Class<C> containerType,\n\t\t\t@Nullable String containerImageName, ServiceConnection annotation, Supplier<C> containerSupplier,\n\t\t\t@Nullable SslBundleSource sslBundleSource, @Nullable MergedAnnotations annotations) {\n\t\tthis.beanNameSuffix = beanNameSuffix;\n\t\tthis.origin = origin;\n\t\tthis.containerType = containerType;\n\t\tthis.containerImageName = containerImageName;\n\t\tthis.connectionName = getOrDeduceConnectionName(annotation.name(), containerImageName);\n\t\tthis.connectionDetailsTypes = Set.of(annotation.type());\n\t\tthis.containerSupplier = containerSupplier;\n\t\tthis.sslBundleSource = sslBundleSource;\n\t\tthis.annotations = annotations;\n\t}\n\n\tprivate static @Nullable String getOrDeduceConnectionName(@Nullable String connectionName,\n\t\t\t@Nullable String containerImageName) {\n\t\tif (StringUtils.hasText(connectionName)) {\n\t\t\treturn connectionName;\n\t\t}\n\t\tif (StringUtils.hasText(containerImageName)) {\n\t\t\tDockerImageName imageName = DockerImageName.parse(containerImageName);\n\t\t\timageName.assertValid();\n\t\t\treturn imageName.getRepository();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return if this source accepts the given connection.\n\t * @param requiredConnectionName the required connection name or {@code null}\n\t * @param requiredContainerType the required container type\n\t * @param requiredConnectionDetailsType the required connection details type\n\t * @return if the connection is accepted by this source\n\t * @since 3.4.0\n\t */\n\tpublic boolean accepts(@Nullable String requiredConnectionName, Class<?> requiredContainerType,\n\t\t\tClass<?> requiredConnectionDetailsType) {\n\t\tif (StringUtils.hasText(requiredConnectionName)\n\t\t\t\t&& !requiredConnectionName.equalsIgnoreCase(this.connectionName)) {\n\t\t\tlogger.trace(LogMessage\n\t\t\t\t.of(() -> \"%s not accepted as source connection name '%s' does not match required connection name '%s'\"\n\t\t\t\t\t.formatted(this, this.connectionName, requiredConnectionName)));\n\t\t\treturn false;\n\t\t}\n\t\tif (!requiredContainerType.isAssignableFrom(this.containerType)) {\n\t\t\tlogger.trace(LogMessage.of(() -> \"%s not accepted as source container type %s is not assignable from %s\"\n\t\t\t\t.formatted(this, this.containerType.getName(), requiredContainerType.getName())));\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.connectionDetailsTypes.isEmpty() && this.connectionDetailsTypes.stream()\n\t\t\t.noneMatch((candidate) -> candidate.isAssignableFrom(requiredConnectionDetailsType))) {\n\t\t\tlogger.trace(LogMessage\n\t\t\t\t.of(() -> \"%s not accepted as source connection details types %s has no element assignable from %s\"\n\t\t\t\t\t.formatted(this, this.connectionDetailsTypes.stream().map(Class::getName).toList(),\n\t\t\t\t\t\t\trequiredConnectionDetailsType.getName())));\n\t\t\treturn false;\n\t\t}\n\t\tlogger.trace(\n\t\t\t\tLogMessage.of(() -> \"%s accepted for connection name '%s' container type %s, connection details type %s\"\n\t\t\t\t\t.formatted(this, requiredConnectionName, requiredContainerType.getName(),\n\t\t\t\t\t\t\trequiredConnectionDetailsType.getName())));\n\t\treturn true;\n\t}\n\n\tString getBeanNameSuffix() {\n\t\treturn this.beanNameSuffix;\n\t}\n\n\t@Override\n\tpublic Origin getOrigin() {\n\t\treturn this.origin;\n\t}\n\n\t@Nullable String getContainerImageName() {\n\t\treturn this.containerImageName;\n\t}\n\n\t@Nullable String getConnectionName() {\n\t\treturn this.connectionName;\n\t}\n\n\tSupplier<C> getContainerSupplier() {\n\t\treturn this.containerSupplier;\n\t}\n\n\t/**\n\t * Returns the requested connection details types.\n\t * @return the requested connection details types.\n\t * @since 4.1.0\n\t */\n\tpublic Set<Class<?>> getConnectionDetailsTypes() {\n\t\treturn this.connectionDetailsTypes;\n\t}\n\n\t@Nullable SslBundleSource getSslBundleSource() {\n\t\treturn this.sslBundleSource;\n\t}\n\n\tboolean hasAnnotation(Class<? extends Annotation> annotationType) {\n\t\tif (this.annotations == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.annotations.isPresent(annotationType);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"@ServiceConnection source for %s\".formatted(this.origin);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/FieldOrigin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.reflect.Field;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link Origin} backed by a {@link Field}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass FieldOrigin implements Origin {\n\n\tprivate final Field field;\n\n\tFieldOrigin(Field field) {\n\t\tAssert.notNull(field, \"'field' must not be null\");\n\t\tthis.field = field;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tFieldOrigin other = (FieldOrigin) obj;\n\t\treturn this.field.equals(other.field);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.field.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn ClassUtils.getShortName(this.field.getDeclaringClass()) + \".\" + this.field.getName();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/JksKeyStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Configures the {@link JksSslStoreBundle} key store to use with an {@link SslBundle SSL}\n * supported {@link ServiceConnection @ServiceConnection}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })\npublic @interface JksKeyStore {\n\n\t/**\n\t * Alias for {@link #location()}.\n\t * @return the store location\n\t */\n\t@AliasFor(\"location\")\n\tString value() default \"\";\n\n\t/**\n\t * The location of the resource containing the store content.\n\t * @return the store location\n\t */\n\t@AliasFor(\"value\")\n\tString location() default \"\";\n\n\t/**\n\t * The password used to access the store.\n\t * @return the store password\n\t */\n\tString password() default \"\";\n\n\t/**\n\t * The type of the store to create, e.g. JKS.\n\t * @return store type\n\t */\n\tString type() default \"\";\n\n\t/**\n\t * The provider for the store.\n\t * @return the store provider\n\t */\n\tString provider() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/JksTrustStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Configures the {@link JksSslStoreBundle} trust store to use with an {@link SslBundle\n * SSL} supported {@link ServiceConnection @ServiceConnection}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })\npublic @interface JksTrustStore {\n\n\t/**\n\t * Alias for {@link #location()}.\n\t * @return the store location\n\t */\n\t@AliasFor(\"location\")\n\tString value() default \"\";\n\n\t/**\n\t * The location of the resource containing the store content.\n\t * @return the store location\n\t */\n\t@AliasFor(\"value\")\n\tString location() default \"\";\n\n\t/**\n\t * The password used to access the store.\n\t * @return the store password\n\t */\n\tString password() default \"\";\n\n\t/**\n\t * The type of the store to create, e.g. JKS.\n\t * @return store type\n\t */\n\tString type() default \"\";\n\n\t/**\n\t * The provider for the store.\n\t * @return the store provider\n\t */\n\tString provider() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/PemKeyStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Configures the {@link PemSslStoreBundle} key store to use with an {@link SslBundle SSL}\n * supported {@link ServiceConnection @ServiceConnection}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })\npublic @interface PemKeyStore {\n\n\t/**\n\t * Alias for {@link #certificate()}.\n\t * @return the store certificate\n\t */\n\t@AliasFor(\"certificate\")\n\tString value() default \"\";\n\n\t/**\n\t * The location or content of the certificate or certificate chain in PEM format.\n\t * @return the store certificate location or content\n\t */\n\t@AliasFor(\"value\")\n\tString certificate() default \"\";\n\n\t/**\n\t * The location or content of the private key in PEM format.\n\t * @return the store private key location or content\n\t */\n\tString privateKey() default \"\";\n\n\t/**\n\t * The password used to decrypt an encrypted private key.\n\t * @return the store private key password\n\t */\n\tString privateKeyPassword() default \"\";\n\n\t/**\n\t * The type of the store to create, e.g. JKS.\n\t * @return the store type\n\t */\n\tString type() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/PemTrustStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Configures the {@link PemSslStoreBundle} trust store to use with an {@link SslBundle\n * SSL} supported {@link ServiceConnection @ServiceConnection}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })\npublic @interface PemTrustStore {\n\n\t/**\n\t * Alias for {@link #certificate()}.\n\t * @return the store certificate\n\t */\n\t@AliasFor(\"certificate\")\n\tString value() default \"\";\n\n\t/**\n\t * The location or content of the certificate or certificate chain in PEM format.\n\t * @return the store certificate location or content\n\t */\n\t@AliasFor(\"value\")\n\tString certificate() default \"\";\n\n\t/**\n\t * The location or content of the private key in PEM format.\n\t * @return the store private key location or content\n\t */\n\tString privateKey() default \"\";\n\n\t/**\n\t * The password used to decrypt an encrypted private key.\n\t * @return the store private key password\n\t */\n\tString privateKeyPassword() default \"\";\n\n\t/**\n\t * The type of the store to create, e.g. JKS.\n\t * @return the store type\n\t */\n\tString type() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Indicates that a field or method is a {@link ContainerConnectionSource} which provides\n * a service that can be connected to.\n * <p>\n * If the underling connection supports SSL, the {@link PemKeyStore @PemKeyStore},\n * {@link PemTrustStore @PemTrustStore}, {@link JksKeyStore @JksKeyStore},\n * {@link JksTrustStore @JksTrustStore}, {@link Ssl @Ssl} annotations may be used to\n * provide additional configuration.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.1.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })\npublic @interface ServiceConnection {\n\n\t/**\n\t * The name of the service being connected to. Container names are used to determine\n\t * the connection details that should be created when a technology-specific\n\t * {@link Container} subclass is not available.\n\t * <p>\n\t * If not specified, and if the {@link Container} instance is available, the\n\t * {@link DockerImageName#getRepository() repository} part of the\n\t * {@link Container#getDockerImageName() docker image name} will be used. Note that\n\t * {@link Container} instances are <em>not</em> available early enough when the\n\t * container is defined as a {@link Bean @Bean} method. All\n\t * {@link ServiceConnection @ServiceConnection} {@link Bean @Bean} methods that need\n\t * to match on the connection name <em>must</em> declare this attribute.\n\t * <p>\n\t * This attribute is an alias for {@link #name()}.\n\t * @return the name of the service\n\t * @see #name()\n\t */\n\t@AliasFor(\"name\")\n\tString value() default \"\";\n\n\t/**\n\t * The name of the service being connected to. Container names are used to determine\n\t * the connection details that should be created when a technology-specific\n\t * {@link Container} subclass is not available.\n\t * <p>\n\t * If not specified, and if the {@link Container} instance is available, the\n\t * {@link DockerImageName#getRepository() repository} part of the\n\t * {@link Container#getDockerImageName() docker image name} will be used. Note that\n\t * {@link Container} instances are <em>not</em> available early enough when the\n\t * container is defined as a {@link Bean @Bean} method. All\n\t * {@link ServiceConnection @ServiceConnection} {@link Bean @Bean} methods that need\n\t * to match on the connection name <em>must</em> declare this attribute.\n\t * <p>\n\t * This attribute is an alias for {@link #value()}.\n\t * @return the name of the service\n\t * @see #value()\n\t */\n\t@AliasFor(\"value\")\n\tString name() default \"\";\n\n\t/**\n\t * A restriction to types of {@link ConnectionDetails} that can be created from this\n\t * connection. The default value does not restrict the types that can be created.\n\t * @return the connection detail types that can be created to establish the connection\n\t */\n\tClass<? extends ConnectionDetails>[] type() default {};\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration\n * Auto-configuration} for {@link ServiceConnection @ServiceConnection} annotated\n * {@link Container} beans.\n *\n * @author Phillip Webb\n * @since 3.1.0\n */\n@AutoConfiguration\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)\n@Import(ServiceConnectionAutoConfigurationRegistrar.class)\npublic final class ServiceConnectionAutoConfiguration {\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionAutoConfigurationRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.testcontainers.beans.TestcontainerBeanDefinition;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used by\n * {@link ServiceConnectionAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass ServiceConnectionAutoConfigurationRegistrar implements ImportBeanDefinitionRegistrar {\n\n\tprivate final BeanFactory beanFactory;\n\n\tServiceConnectionAutoConfigurationRegistrar(BeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tif (this.beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {\n\t\t\tregisterBeanDefinitions(listableBeanFactory, registry);\n\t\t}\n\t}\n\n\tprivate void registerBeanDefinitions(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry) {\n\t\tConnectionDetailsRegistrar registrar = new ConnectionDetailsRegistrar(beanFactory,\n\t\t\t\tnew ConnectionDetailsFactories(null));\n\t\tfor (String beanName : beanFactory.getBeanNamesForType(Container.class)) {\n\t\t\tBeanDefinition beanDefinition = getBeanDefinition(beanFactory, beanName);\n\t\t\tMergedAnnotations annotations = (beanDefinition instanceof TestcontainerBeanDefinition testcontainerBeanDefinition)\n\t\t\t\t\t? testcontainerBeanDefinition.getAnnotations() : null;\n\t\t\tfor (ServiceConnection serviceConnection : getServiceConnections(beanFactory, beanName, annotations)) {\n\t\t\t\tContainerConnectionSource<?> source = createSource(beanFactory, beanName, beanDefinition, annotations,\n\t\t\t\t\t\tserviceConnection);\n\t\t\t\tregistrar.registerBeanDefinitions(registry, source);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Set<ServiceConnection> getServiceConnections(ConfigurableListableBeanFactory beanFactory, String beanName,\n\t\t\t@Nullable MergedAnnotations annotations) {\n\t\tSet<ServiceConnection> serviceConnections = beanFactory.findAllAnnotationsOnBean(beanName,\n\t\t\t\tServiceConnection.class, false);\n\t\tif (annotations != null) {\n\t\t\tserviceConnections = new LinkedHashSet<>(serviceConnections);\n\t\t\tannotations.stream(ServiceConnection.class)\n\t\t\t\t.map(MergedAnnotation::synthesize)\n\t\t\t\t.forEach(serviceConnections::add);\n\t\t}\n\t\treturn serviceConnections;\n\t}\n\n\tprivate @Nullable BeanDefinition getBeanDefinition(ConfigurableListableBeanFactory beanFactory, String beanName) {\n\t\ttry {\n\t\t\treturn beanFactory.getBeanDefinition(beanName);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <C extends Container<?>> ContainerConnectionSource<C> createSource(\n\t\t\tConfigurableListableBeanFactory beanFactory, String beanName, @Nullable BeanDefinition beanDefinition,\n\t\t\t@Nullable MergedAnnotations annotations, ServiceConnection serviceConnection) {\n\t\tOrigin origin = new BeanOrigin(beanName, beanDefinition);\n\t\tClass<C> containerType = (Class<C>) beanFactory.getType(beanName, false);\n\t\tString containerImageName = (beanDefinition instanceof TestcontainerBeanDefinition testcontainerBeanDefinition)\n\t\t\t\t? testcontainerBeanDefinition.getContainerImageName() : null;\n\t\tAssert.state(containerType != null, \"'containerType' must not be null\");\n\t\treturn new ContainerConnectionSource<>(beanName, origin, containerType, containerImageName, serviceConnection,\n\t\t\t\t() -> beanFactory.getBean(beanName, containerType),\n\t\t\t\tSslBundleSource.get(beanFactory, beanName, annotations), annotations);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\n\n/**\n * Spring Test {@link ContextCustomizer} to support registering {@link ConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceConnectionContextCustomizer implements ContextCustomizer {\n\n\tprivate final List<ContainerConnectionSource<?>> sources;\n\n\tprivate final Set<CacheKey> keys;\n\n\tprivate final ConnectionDetailsFactories connectionDetailsFactories;\n\n\tServiceConnectionContextCustomizer(List<ContainerConnectionSource<?>> sources) {\n\t\tthis(sources, new ConnectionDetailsFactories(null));\n\t}\n\n\tServiceConnectionContextCustomizer(List<ContainerConnectionSource<?>> sources,\n\t\t\tConnectionDetailsFactories connectionDetailsFactories) {\n\t\tthis.sources = sources;\n\t\tthis.keys = sources.stream().map(CacheKey::new).collect(Collectors.toUnmodifiableSet());\n\t\tthis.connectionDetailsFactories = connectionDetailsFactories;\n\t}\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(context);\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tif (beanFactory instanceof BeanDefinitionRegistry registry) {\n\t\t\tnew ConnectionDetailsRegistrar(beanFactory, this.connectionDetailsFactories)\n\t\t\t\t.registerBeanDefinitions(registry, this.sources);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.keys.equals(((ServiceConnectionContextCustomizer) obj).keys);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.keys.hashCode();\n\t}\n\n\tList<ContainerConnectionSource<?>> getSources() {\n\t\treturn this.sources;\n\t}\n\n\t/**\n\t * Relevant details from {@link ContainerConnectionSource} used as a\n\t * MergedContextConfiguration cache key.\n\t */\n\tprivate record CacheKey(@Nullable String connectionName, Set<Class<?>> connectionDetailsTypes,\n\t\t\tContainer<?> container, @Nullable SslBundleSource sslBundleSource) {\n\n\t\tCacheKey(ContainerConnectionSource<?> source) {\n\t\t\tthis(source.getConnectionName(), source.getConnectionDetailsTypes(), source.getContainerSupplier().get(),\n\t\t\t\t\tsource.getSslBundleSource());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.TestContextAnnotationUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Spring Test {@link ContextCustomizerFactory} to support\n * {@link ServiceConnection @ServiceConnection} annotated {@link Container} fields in\n * tests.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ServiceConnectionContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\tList<ContainerConnectionSource<?>> sources = new ArrayList<>();\n\t\tcollectSources(testClass, sources);\n\t\treturn new ServiceConnectionContextCustomizer(sources);\n\t}\n\n\tprivate void collectSources(@Nullable Class<?> candidate, List<ContainerConnectionSource<?>> sources) {\n\t\tif (candidate == Object.class || candidate == null) {\n\t\t\treturn;\n\t\t}\n\t\tReflectionUtils.doWithLocalFields(candidate, (field) -> {\n\t\t\tMergedAnnotations annotations = MergedAnnotations.from(field);\n\t\t\tannotations.stream(ServiceConnection.class)\n\t\t\t\t.forEach((serviceConnection) -> sources.add(createSource(field, annotations, serviceConnection)));\n\t\t});\n\t\tif (TestContextAnnotationUtils.searchEnclosingClass(candidate)) {\n\t\t\tcollectSources(candidate.getEnclosingClass(), sources);\n\t\t}\n\t\tfor (Class<?> implementedInterface : candidate.getInterfaces()) {\n\t\t\tcollectSources(implementedInterface, sources);\n\t\t}\n\t\tcollectSources(candidate.getSuperclass(), sources);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <C extends Container<?>> ContainerConnectionSource<?> createSource(Field field,\n\t\t\tMergedAnnotations annotations, MergedAnnotation<ServiceConnection> serviceConnection) {\n\t\tAssert.state(Modifier.isStatic(field.getModifiers()),\n\t\t\t\t() -> \"@ServiceConnection field '%s' must be static\".formatted(field.getName()));\n\t\tOrigin origin = new FieldOrigin(field);\n\t\tObject fieldValue = getFieldValue(field);\n\t\tAssert.state(fieldValue instanceof Container, () -> \"Field '%s' in %s must be a %s\".formatted(field.getName(),\n\t\t\t\tfield.getDeclaringClass().getName(), Container.class.getName()));\n\t\tClass<C> containerType = (Class<C>) fieldValue.getClass();\n\t\tC container = (C) fieldValue;\n\t\t// container.getDockerImageName() fails if there is no running docker environment\n\t\t// When running tests that doesn't matter, but running AOT processing should be\n\t\t// possible without a Docker environment\n\t\tString dockerImageName = isAotProcessingInProgress() ? null : container.getDockerImageName();\n\t\treturn new ContainerConnectionSource<>(\"test\", origin, containerType, dockerImageName, serviceConnection,\n\t\t\t\t() -> container, SslBundleSource.get(annotations), annotations);\n\t}\n\n\tprivate @Nullable Object getFieldValue(Field field) {\n\t\tReflectionUtils.makeAccessible(field);\n\t\treturn ReflectionUtils.getField(field, null);\n\t}\n\n\tprivate boolean isAotProcessingInProgress() {\n\t\treturn Boolean.getBoolean(AbstractAotProcessor.AOT_PROCESSING);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/Ssl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\n\n/**\n * Configures the {@link SslOptions}, {@link SslBundleKey @SslBundleKey} and\n * {@link SslBundle#getProtocol() protocol} to use with an {@link SslBundle SSL} supported\n * {@link ServiceConnection @ServiceConnection}.\n * <p>\n * Also serves as a signal to enable automatic {@link SslBundle} extraction from supported\n * containers.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })\npublic @interface Ssl {\n\n\t/**\n\t * The protocol to use for the SSL connection.\n\t * @return the SSL protocol\n\t * @see SslBundle#getProtocol()\n\t */\n\tString protocol() default SslBundle.DEFAULT_PROTOCOL;\n\n\t/**\n\t * The ciphers that can be used for the SSL connection.\n\t * @return the SSL ciphers\n\t * @see SslOptions#getCiphers()\n\t */\n\tString[] ciphers() default {};\n\n\t/**\n\t * The protocols that are enabled for the SSL connection.\n\t * @return the enabled SSL protocols\n\t * @see SslOptions#getEnabledProtocols()\n\t */\n\tString[] enabledProtocols() default {};\n\n\t/**\n\t * The password that should be used to access the key.\n\t * @return the key password\n\t * @see SslBundleKey#getPassword()\n\t */\n\tString keyPassword() default \"\";\n\n\t/**\n\t * The alias that should be used to access the key.\n\t * @return the key alias\n\t * @see SslBundleKey#getAlias()\n\t */\n\tString keyAlias() default \"\";\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/SslBundleSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link SslBundle} source created from annotations. Used as a cache key and as a\n * {@link SslBundle} factory.\n *\n * @param ssl the {@link Ssl @Ssl} annotation\n * @param pemKeyStore the {@link PemKeyStore @PemKeyStore} annotation\n * @param pemTrustStore the {@link PemTrustStore @PemTrustStore} annotation\n * @param jksKeyStore the {@link JksKeyStore @JksKeyStore} annotation\n * @param jksTrustStore the {@link JksTrustStore @JksTrustStore} annotation\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nrecord SslBundleSource(@Nullable Ssl ssl, @Nullable PemKeyStore pemKeyStore, @Nullable PemTrustStore pemTrustStore,\n\t\t@Nullable JksKeyStore jksKeyStore, @Nullable JksTrustStore jksTrustStore) {\n\n\tSslBundleSource {\n\t\tboolean hasPem = (pemKeyStore != null || pemTrustStore != null);\n\t\tboolean hasJks = (jksKeyStore != null || jksTrustStore != null);\n\t\tif (hasJks && hasPem) {\n\t\t\tthrow new IllegalStateException(\"PEM and JKS store annotations cannot be used together\");\n\t\t}\n\t}\n\n\t@Nullable SslBundle getSslBundle() {\n\t\tSslStoreBundle stores = stores();\n\t\tif (stores == null) {\n\t\t\treturn null;\n\t\t}\n\t\tSsl ssl = (this.ssl != null) ? this.ssl : MergedAnnotation.of(Ssl.class).synthesize();\n\t\tSslOptions options = SslOptions.of(nullIfEmpty(ssl.ciphers()), nullIfEmpty(ssl.enabledProtocols()));\n\t\tSslBundleKey key = SslBundleKey.of(nullIfEmpty(ssl.keyPassword()), nullIfEmpty(ssl.keyAlias()));\n\t\tString protocol = ssl.protocol();\n\t\treturn SslBundle.of(stores, key, options, protocol);\n\t}\n\n\tprivate @Nullable SslStoreBundle stores() {\n\t\tif (this.pemKeyStore != null || this.pemTrustStore != null) {\n\t\t\treturn new PemSslStoreBundle(pemKeyStoreDetails(), pemTrustStoreDetails());\n\t\t}\n\t\tif (this.jksKeyStore != null || this.jksTrustStore != null) {\n\t\t\treturn new JksSslStoreBundle(jksKeyStoreDetails(), jksTrustStoreDetails());\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable PemSslStoreDetails pemKeyStoreDetails() {\n\t\tPemKeyStore store = this.pemKeyStore;\n\t\treturn (store != null) ? new PemSslStoreDetails(nullIfEmpty(store.type()), nullIfEmpty(store.certificate()),\n\t\t\t\tnullIfEmpty(store.privateKey()), nullIfEmpty(store.privateKeyPassword())) : null;\n\t}\n\n\tprivate @Nullable PemSslStoreDetails pemTrustStoreDetails() {\n\t\tPemTrustStore store = this.pemTrustStore;\n\t\treturn (store != null) ? new PemSslStoreDetails(nullIfEmpty(store.type()), nullIfEmpty(store.certificate()),\n\t\t\t\tnullIfEmpty(store.privateKey()), nullIfEmpty(store.privateKeyPassword())) : null;\n\t}\n\n\tprivate @Nullable JksSslStoreDetails jksKeyStoreDetails() {\n\t\tJksKeyStore store = this.jksKeyStore;\n\t\treturn (store != null) ? new JksSslStoreDetails(nullIfEmpty(store.type()), nullIfEmpty(store.provider()),\n\t\t\t\tnullIfEmpty(store.location()), nullIfEmpty(store.password())) : null;\n\t}\n\n\tprivate @Nullable JksSslStoreDetails jksTrustStoreDetails() {\n\t\tJksTrustStore store = this.jksTrustStore;\n\t\treturn (store != null) ? new JksSslStoreDetails(nullIfEmpty(store.type()), nullIfEmpty(store.provider()),\n\t\t\t\tnullIfEmpty(store.location()), nullIfEmpty(store.password())) : null;\n\t}\n\n\tprivate @Nullable String nullIfEmpty(@Nullable String string) {\n\t\tif (StringUtils.hasLength(string)) {\n\t\t\treturn string;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String @Nullable [] nullIfEmpty(String @Nullable [] array) {\n\t\tif (array == null || array.length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\treturn array;\n\t}\n\n\tstatic @Nullable SslBundleSource get(MergedAnnotations annotations) {\n\t\treturn get(null, null, annotations);\n\t}\n\n\tstatic @Nullable SslBundleSource get(@Nullable ListableBeanFactory beanFactory, @Nullable String beanName,\n\t\t\t@Nullable MergedAnnotations annotations) {\n\t\tSsl ssl = getAnnotation(beanFactory, beanName, annotations, Ssl.class);\n\t\tPemKeyStore pemKeyStore = getAnnotation(beanFactory, beanName, annotations, PemKeyStore.class);\n\t\tPemTrustStore pemTrustStore = getAnnotation(beanFactory, beanName, annotations, PemTrustStore.class);\n\t\tJksKeyStore jksKeyStore = getAnnotation(beanFactory, beanName, annotations, JksKeyStore.class);\n\t\tJksTrustStore jksTrustStore = getAnnotation(beanFactory, beanName, annotations, JksTrustStore.class);\n\t\tif (ssl == null && pemKeyStore == null && pemTrustStore == null && jksKeyStore == null\n\t\t\t\t&& jksTrustStore == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new SslBundleSource(ssl, pemKeyStore, pemTrustStore, jksKeyStore, jksTrustStore);\n\t}\n\n\tprivate static <A extends Annotation> @Nullable A getAnnotation(@Nullable ListableBeanFactory beanFactory,\n\t\t\t@Nullable String beanName, @Nullable MergedAnnotations annotations, Class<A> annotationType) {\n\t\tSet<A> found = (beanFactory != null && beanName != null)\n\t\t\t\t? beanFactory.findAllAnnotationsOnBean(beanName, annotationType, false) : Collections.emptySet();\n\t\tif (annotations != null) {\n\t\t\tfound = new LinkedHashSet<>(found);\n\t\t\tannotations.stream(annotationType).map(MergedAnnotation::synthesize).forEach(found::add);\n\t\t}\n\t\tint size = found.size();\n\t\tAssert.state(size <= 1,\n\t\t\t\t() -> \"Expected single %s annotation, but found %d\".formatted(annotationType.getName(), size));\n\t\treturn (size > 0) ? found.iterator().next() : null;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General support for service connections in tests.\n */\n@NullMarked\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.testcontainers.beans.startup\",\n      \"type\": \"org.springframework.boot.testcontainers.lifecycle.TestcontainersStartup\",\n      \"description\": \"Testcontainers startup modes.\",\n      \"defaultValue\": \"sequential\"\n    },\n    {\n      \"name\": \"spring.testcontainers.dynamic-property-registry-injection\",\n      \"description\": \"How to treat injection of DynamicPropertyRegistry into a @Bean method.\",\n      \"defaultValue\": \"fail\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.testcontainers.dynamic-property-registry-injection\",\n      \"values\": [\n        {\n          \"value\": \"fail\",\n          \"description\": \"Fail with an exception.\"\n        },\n        {\n          \"value\": \"warn\",\n          \"description\": \"Log a warning.\"\n        },\n        {\n          \"value\": \"allow\",\n          \"description\": \"Allow the use despite its deprecation.\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter=\\\norg.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar$ServiceConnectionBeanRegistrationExcludeFilter\n\norg.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory$ContainerConnectionDetailsFactoriesRuntimeHints\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.testcontainers.properties.TestcontainersPropertySourceAutoConfiguration\norg.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories",
    "content": "# Application Context Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleApplicationContextInitializer\n\n# Spring Test ContextCustomizerFactories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.testcontainers.lifecycle.DockerEnvironmentNotFoundFailureAnalyzer\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/DockerEnvironmentNotFoundFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DockerEnvironmentNotFoundFailureAnalyzer}.\n *\n * @author Dmytro Nosan\n */\nclass DockerEnvironmentNotFoundFailureAnalyzerTests {\n\n\tprivate final DockerEnvironmentNotFoundFailureAnalyzer analyzer = new DockerEnvironmentNotFoundFailureAnalyzer();\n\n\t@Test\n\tvoid shouldReturnFailureAnalysisWhenMessageMatches() {\n\t\tIllegalStateException cause = new IllegalStateException(\n\t\t\t\t\"Could not find a valid Docker environment. Please see logs and check configuration\");\n\t\tFailureAnalysis analysis = this.analyzer\n\t\t\t.analyze(new RuntimeException(\"Root\", new RuntimeException(\"Intermediate\", cause)));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.isEqualTo(\"Could not find a valid Docker environment for Testcontainers.\");\n\t\tassertThat(analysis.getAction())\n\t\t\t.contains(\"Ensure a Docker-compatible container engine is installed and running\");\n\t\tassertThat(analysis.getCause()).isSameAs(cause);\n\t}\n\n\t@Test\n\tvoid shouldReturnNullWhenMessageDoesNotMatch() {\n\t\tFailureAnalysis analysis = this.analyzer.analyze(new IllegalStateException(\"Some message\"));\n\t\tassertThat(analysis).isNull();\n\t}\n\n\t@Test\n\tvoid shouldReturnNullWhenMessageIsNull() {\n\t\tFailureAnalysis analysis = this.analyzer.analyze(new IllegalStateException());\n\t\tassertThat(analysis).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersLifecycleApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.lifecycle.Startable;\nimport org.testcontainers.utility.TestcontainersConfiguration;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.support.AbstractBeanFactory;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.AbstractAotProcessor;\nimport org.springframework.core.env.MapPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link TestcontainersLifecycleApplicationContextInitializer},\n * {@link TestcontainersLifecycleBeanPostProcessor}, and\n * {@link TestcontainersLifecycleBeanFactoryPostProcessor}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass TestcontainersLifecycleApplicationContextInitializerTests {\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tTestcontainersConfiguration.getInstance().updateUserConfig(\"testcontainers.reuse.enable\", \"false\");\n\t}\n\n\t@Test\n\tvoid whenStartableBeanInvokesStartOnRefresh() {\n\t\tStartable container = mock(Startable.class);\n\t\tAnnotationConfigApplicationContext applicationContext = createApplicationContext(container);\n\t\tthen(container).shouldHaveNoInteractions();\n\t\tapplicationContext.refresh();\n\t\tthen(container).should().start();\n\t\tapplicationContext.close();\n\t}\n\n\t@Test\n\tvoid whenStartableBeanInvokesCloseOnShutdown() {\n\t\tStartable container = mock(Startable.class);\n\t\tAnnotationConfigApplicationContext applicationContext = createApplicationContext(container);\n\t\tapplicationContext.refresh();\n\t\tthen(container).should(never()).close();\n\t\tapplicationContext.close();\n\t\tthen(container).should(times(1)).close();\n\t}\n\n\t@Test\n\tvoid whenReusableContainerAndReuseEnabledBeanInvokesStartButNotClose() {\n\t\tTestcontainersConfiguration.getInstance().updateUserConfig(\"testcontainers.reuse.enable\", \"true\");\n\t\tGenericContainer<?> container = mock(GenericContainer.class);\n\t\tgiven(container.isShouldBeReused()).willReturn(true);\n\t\tAnnotationConfigApplicationContext applicationContext = createApplicationContext(container);\n\t\tthen(container).shouldHaveNoInteractions();\n\t\tapplicationContext.refresh();\n\t\tthen(container).should().start();\n\t\tapplicationContext.close();\n\t\tthen(container).should(never()).close();\n\t}\n\n\t@Test\n\tvoid whenReusableContainerButReuseNotEnabledBeanInvokesStartAndClose() {\n\t\tGenericContainer<?> container = mock(GenericContainer.class);\n\t\tgiven(container.isShouldBeReused()).willReturn(true);\n\t\tAnnotationConfigApplicationContext applicationContext = createApplicationContext(container);\n\t\tthen(container).shouldHaveNoInteractions();\n\t\tapplicationContext.refresh();\n\t\tthen(container).should().start();\n\t\tapplicationContext.close();\n\t\tthen(container).should(times(1)).close();\n\t}\n\n\t@Test\n\tvoid whenReusableContainerAndReuseEnabledBeanFromConfigurationInvokesStartButNotClose() {\n\t\tTestcontainersConfiguration.getInstance().updateUserConfig(\"testcontainers.reuse.enable\", \"true\");\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\tapplicationContext.register(ReusableContainerConfiguration.class);\n\t\tapplicationContext.refresh();\n\t\tGenericContainer<?> container = applicationContext.getBean(GenericContainer.class);\n\t\tthen(container).should().start();\n\t\tapplicationContext.close();\n\t\tthen(container).should(never()).close();\n\t}\n\n\t@Test\n\tvoid whenReusableContainerButReuseNotEnabledBeanFromConfigurationInvokesStartAndClose() {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\tapplicationContext.register(ReusableContainerConfiguration.class);\n\t\tapplicationContext.refresh();\n\t\tGenericContainer<?> container = applicationContext.getBean(GenericContainer.class);\n\t\tthen(container).should().start();\n\t\tapplicationContext.close();\n\t\tthen(container).should(times(1)).close();\n\t}\n\n\t@Test\n\tvoid doesNotInitializeSameContextMoreThanOnce() {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tint initialNumberOfPostProcessors = applicationContext.getBeanFactoryPostProcessors().size();\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\t}\n\t\tassertThat(applicationContext.getBeanFactoryPostProcessors()).hasSize(initialNumberOfPostProcessors + 1);\n\t}\n\n\t@Test\n\tvoid dealsWithBeanCurrentlyInCreationException() {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\tapplicationContext.register(BeanCurrentlyInCreationExceptionConfiguration2.class,\n\t\t\t\tBeanCurrentlyInCreationExceptionConfiguration1.class);\n\t\tapplicationContext.refresh();\n\t}\n\n\t@Test\n\tvoid doesNotStartContainersWhenAotProcessingIsInProgress() {\n\t\tGenericContainer<?> container = mock(GenericContainer.class);\n\t\tAnnotationConfigApplicationContext applicationContext = createApplicationContext(container);\n\t\tthen(container).shouldHaveNoInteractions();\n\t\twithSystemProperty(AbstractAotProcessor.AOT_PROCESSING, \"true\",\n\t\t\t\t() -> applicationContext.refreshForAotProcessing(new RuntimeHints()));\n\t\tthen(container).shouldHaveNoInteractions();\n\t\tapplicationContext.close();\n\t}\n\n\t@Test\n\tvoid setupStartupBasedOnEnvironmentProperty() {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tapplicationContext.getEnvironment()\n\t\t\t.getPropertySources()\n\t\t\t.addLast(new MapPropertySource(\"test\", Map.of(\"spring.testcontainers.beans.startup\", \"parallel\")));\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\tAbstractBeanFactory beanFactory = (AbstractBeanFactory) applicationContext.getBeanFactory();\n\t\tBeanPostProcessor beanPostProcessor = beanFactory.getBeanPostProcessors()\n\t\t\t.stream()\n\t\t\t.filter(TestcontainersLifecycleBeanPostProcessor.class::isInstance)\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tassertThat(beanPostProcessor).extracting(\"startup\").isEqualTo(TestcontainersStartup.PARALLEL);\n\t}\n\n\tprivate void withSystemProperty(String name, String value, Runnable action) {\n\t\tString previousValue = System.getProperty(name);\n\t\tSystem.setProperty(name, value);\n\t\ttry {\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tif (previousValue == null) {\n\t\t\t\tSystem.clearProperty(name);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.setProperty(name, previousValue);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate AnnotationConfigApplicationContext createApplicationContext(Startable container) {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\tapplicationContext.registerBean(\"container\", Startable.class, () -> container);\n\t\treturn applicationContext;\n\t}\n\n\tprivate AnnotationConfigApplicationContext createApplicationContext(GenericContainer<?> container) {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tnew TestcontainersLifecycleApplicationContextInitializer().initialize(applicationContext);\n\t\tapplicationContext.registerBean(\"container\", GenericContainer.class, () -> container);\n\t\treturn applicationContext;\n\t}\n\n\t@Configuration\n\tstatic class ReusableContainerConfiguration {\n\n\t\t@Bean\n\t\tGenericContainer<?> container() {\n\t\t\tGenericContainer<?> container = mock(GenericContainer.class);\n\t\t\tgiven(container.isShouldBeReused()).willReturn(true);\n\t\t\treturn container;\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class BeanCurrentlyInCreationExceptionConfiguration1 {\n\n\t\t@Bean\n\t\tTestBean testBean() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class BeanCurrentlyInCreationExceptionConfiguration2 {\n\n\t\tBeanCurrentlyInCreationExceptionConfiguration2(TestBean testBean) {\n\t\t}\n\n\t\t@Bean\n\t\tGenericContainer<?> container(TestBean testBean) {\n\t\t\tGenericContainer<?> container = mock(GenericContainer.class);\n\t\t\tgiven(container.isShouldBeReused()).willReturn(true);\n\t\t\treturn container;\n\t\t}\n\n\t}\n\n\tstatic class TestBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/lifecycle/TestcontainersStartupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.lifecycle;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.lifecycle.Startable;\n\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link TestcontainersStartup}.\n *\n * @author Phillip Webb\n */\nclass TestcontainersStartupTests {\n\n\tprivate static final String PROPERTY = TestcontainersStartup.PROPERTY;\n\n\tprivate final AtomicInteger counter = new AtomicInteger();\n\n\t@Test\n\tvoid startSingleStartsOnlyOnce() {\n\t\tTestStartable startable = new TestStartable();\n\t\tassertThat(startable.startCount).isZero();\n\t\tTestcontainersStartup.start(startable);\n\t\tassertThat(startable.startCount).isOne();\n\t\tTestcontainersStartup.start(startable);\n\t\tassertThat(startable.startCount).isOne();\n\t}\n\n\t@Test\n\tvoid startWhenSquentialStartsSequentially() {\n\t\tList<TestStartable> startables = createTestStartables(100);\n\t\tTestcontainersStartup.SEQUENTIAL.start(startables);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getIndex()).isEqualTo(i);\n\t\t\tassertThat(startables.get(i).getThreadName()).isEqualTo(Thread.currentThread().getName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid startWhenSquentialStartsOnlyOnce() {\n\t\tList<TestStartable> startables = createTestStartables(10);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getStartCount()).isZero();\n\t\t}\n\t\tTestcontainersStartup.SEQUENTIAL.start(startables);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getStartCount()).isOne();\n\t\t}\n\t\tTestcontainersStartup.SEQUENTIAL.start(startables);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getStartCount()).isOne();\n\t\t}\n\t}\n\n\t@Test\n\tvoid startWhenParallelStartsInParallel() {\n\t\tList<TestStartable> startables = createTestStartables(100);\n\t\tTestcontainersStartup.PARALLEL.start(startables);\n\t\tassertThat(startables.stream().map(TestStartable::getThreadName)).hasSizeGreaterThan(1);\n\t}\n\n\t@Test\n\tvoid startWhenParallelStartsOnlyOnce() {\n\t\tList<TestStartable> startables = createTestStartables(10);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getStartCount()).isZero();\n\t\t}\n\t\tTestcontainersStartup.PARALLEL.start(startables);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getStartCount()).isOne();\n\t\t}\n\t\tTestcontainersStartup.PARALLEL.start(startables);\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(startables.get(i).getStartCount()).isOne();\n\t\t}\n\t}\n\n\t@Test\n\tvoid startWhenParallelStartsDependenciesOnlyOnce() {\n\t\tList<TestStartable> dependencies = createTestStartables(10);\n\t\tTestStartable first = new TestStartable(dependencies);\n\t\tTestStartable second = new TestStartable(dependencies);\n\t\tList<TestStartable> startables = List.of(first, second);\n\t\tassertThat(first.getStartCount()).isZero();\n\t\tassertThat(second.getStartCount()).isZero();\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(dependencies.get(i).getStartCount()).isZero();\n\t\t}\n\t\tTestcontainersStartup.PARALLEL.start(startables);\n\t\tassertThat(first.getStartCount()).isOne();\n\t\tassertThat(second.getStartCount()).isOne();\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(dependencies.get(i).getStartCount()).isOne();\n\t\t}\n\t\tTestcontainersStartup.PARALLEL.start(startables);\n\t\tassertThat(first.getStartCount()).isOne();\n\t\tassertThat(second.getStartCount()).isOne();\n\t\tfor (int i = 0; i < startables.size(); i++) {\n\t\t\tassertThat(dependencies.get(i).getStartCount()).isOne();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getWhenNoPropertyReturnsDefault() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tassertThat(TestcontainersStartup.get(environment)).isEqualTo(TestcontainersStartup.SEQUENTIAL);\n\t}\n\n\t@Test\n\tvoid getWhenPropertyReturnsBasedOnValue() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tassertThat(TestcontainersStartup.get(environment.withProperty(PROPERTY, \"SEQUENTIAL\")))\n\t\t\t.isEqualTo(TestcontainersStartup.SEQUENTIAL);\n\t\tassertThat(TestcontainersStartup.get(environment.withProperty(PROPERTY, \"sequential\")))\n\t\t\t.isEqualTo(TestcontainersStartup.SEQUENTIAL);\n\t\tassertThat(TestcontainersStartup.get(environment.withProperty(PROPERTY, \"SEQuenTIaL\")))\n\t\t\t.isEqualTo(TestcontainersStartup.SEQUENTIAL);\n\t\tassertThat(TestcontainersStartup.get(environment.withProperty(PROPERTY, \"S-E-Q-U-E-N-T-I-A-L\")))\n\t\t\t.isEqualTo(TestcontainersStartup.SEQUENTIAL);\n\t\tassertThat(TestcontainersStartup.get(environment.withProperty(PROPERTY, \"parallel\")))\n\t\t\t.isEqualTo(TestcontainersStartup.PARALLEL);\n\t}\n\n\t@Test\n\tvoid getWhenUnknownPropertyThrowsException() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> TestcontainersStartup.get(environment.withProperty(PROPERTY, \"bad\")))\n\t\t\t.withMessage(\"Unknown 'spring.testcontainers.beans.startup' property value 'bad'\");\n\t}\n\n\tprivate List<TestStartable> createTestStartables(int size) {\n\t\tList<TestStartable> testStartables = new ArrayList<>(size);\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\ttestStartables.add(new TestStartable());\n\t\t}\n\t\treturn testStartables;\n\t}\n\n\tprivate class TestStartable extends GenericContainer<TestStartable> {\n\n\t\tprivate int startCount;\n\n\t\tprivate int index;\n\n\t\tprivate @Nullable String threadName;\n\n\t\tTestStartable() {\n\t\t\tsuper(\"test\");\n\t\t}\n\n\t\tTestStartable(Collection<TestStartable> startables) {\n\t\t\tsuper(\"test\");\n\t\t\tthis.dependencies.addAll(startables);\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<Startable> getDependencies() {\n\t\t\treturn this.dependencies;\n\t\t}\n\n\t\t@Override\n\t\tpublic void start() {\n\t\t\tthis.startCount++;\n\t\t\tthis.index = TestcontainersStartupTests.this.counter.getAndIncrement();\n\t\t\tthis.threadName = Thread.currentThread().getName();\n\t\t}\n\n\t\t@Override\n\t\tpublic void stop() {\n\t\t\tthis.startCount--;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isRunning() {\n\t\t\treturn this.startCount > 0;\n\t\t}\n\n\t\tint getIndex() {\n\t\t\treturn this.index;\n\t\t}\n\n\t\t@Nullable String getThreadName() {\n\t\t\treturn this.threadName;\n\t\t}\n\n\t\tint getStartCount() {\n\t\t\treturn this.startCount;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ConnectionDetailsRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactoryNotFoundException;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsNotFoundException;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.annotation.MergedAnnotation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionDetailsRegistrar}.\n *\n * @author Phillip Webb\n */\nclass ConnectionDetailsRegistrarTests {\n\n\tprivate Origin origin;\n\n\tprivate PostgreSQLContainer container;\n\n\tprivate MergedAnnotation<ServiceConnection> annotation;\n\n\tprivate ContainerConnectionSource<?> source;\n\n\tprivate ConnectionDetailsFactories factories;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.origin = mock(Origin.class);\n\t\tthis.container = mock(PostgreSQLContainer.class);\n\t\tthis.annotation = MergedAnnotation.of(ServiceConnection.class, Map.of(\"name\", \"\", \"type\", new Class<?>[0]));\n\t\tthis.source = new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, null,\n\t\t\t\tthis.annotation, () -> this.container, null, null);\n\t\tthis.factories = mock(ConnectionDetailsFactories.class);\n\t}\n\n\t@Test\n\tvoid registerBeanDefinitionsWhenConnectionDetailsFactoryNotFoundAndNoConnectionNameThrowsExceptionWithBetterMessage() {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tConnectionDetailsRegistrar registrar = new ConnectionDetailsRegistrar(beanFactory, this.factories);\n\t\tgiven(this.factories.getConnectionDetails(this.source, true))\n\t\t\t.willThrow(new ConnectionDetailsFactoryNotFoundException(\"fail\"));\n\t\tassertThatExceptionOfType(ConnectionDetailsFactoryNotFoundException.class)\n\t\t\t.isThrownBy(() -> registrar.registerBeanDefinitions(beanFactory, this.source))\n\t\t\t.withMessage(\"fail. You may need to add a 'name' to your @ServiceConnection annotation\");\n\t}\n\n\t@Test\n\tvoid registerBeanDefinitionsWhenConnectionDetailsNotFoundExceptionAndNoConnectionNameThrowsExceptionWithBetterMessage() {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tConnectionDetailsRegistrar registrar = new ConnectionDetailsRegistrar(beanFactory, this.factories);\n\t\tgiven(this.factories.getConnectionDetails(this.source, true))\n\t\t\t.willThrow(new ConnectionDetailsNotFoundException(\"fail\"));\n\t\tassertThatExceptionOfType(ConnectionDetailsNotFoundException.class)\n\t\t\t.isThrownBy(() -> registrar.registerBeanDefinitions(beanFactory, this.source))\n\t\t\t.withMessage(\"fail. You may need to add a 'name' to your @ServiceConnection annotation\");\n\t}\n\n\t@Test\n\tvoid registerBeanDefinitionsWhenExistingBeanSkipsRegistration() {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tbeanFactory.registerBeanDefinition(\"testbean\", new RootBeanDefinition(CustomTestConnectionDetails.class));\n\t\tConnectionDetailsRegistrar registrar = new ConnectionDetailsRegistrar(beanFactory, this.factories);\n\t\tgiven(this.factories.getConnectionDetails(this.source, true))\n\t\t\t.willReturn(Map.of(TestConnectionDetails.class, new TestConnectionDetails()));\n\t\tregistrar.registerBeanDefinitions(beanFactory, this.source);\n\t\tassertThat(beanFactory.getBean(TestConnectionDetails.class)).isInstanceOf(CustomTestConnectionDetails.class);\n\t}\n\n\t@Test\n\tvoid registerBeanDefinitionsRegistersDefinition() {\n\t\tDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\t\tConnectionDetailsRegistrar registrar = new ConnectionDetailsRegistrar(beanFactory, this.factories);\n\t\tgiven(this.factories.getConnectionDetails(this.source, true))\n\t\t\t.willReturn(Map.of(TestConnectionDetails.class, new TestConnectionDetails()));\n\t\tregistrar.registerBeanDefinitions(beanFactory, this.source);\n\t\tassertThat(beanFactory.getBean(TestConnectionDetails.class)).isNotNull();\n\t}\n\n\tstatic class TestConnectionDetails implements ConnectionDetails {\n\n\t}\n\n\tstatic class CustomTestConnectionDetails extends TestConnectionDetails {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.JdbcDatabaseContainer;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.annotation.MergedAnnotation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ContainerConnectionDetailsFactoryTests {\n\n\tprivate String beanNameSuffix;\n\n\tprivate Origin origin;\n\n\tprivate PostgreSQLContainer container;\n\n\tprivate MergedAnnotation<ServiceConnection> annotation;\n\n\tprivate ContainerConnectionSource<?> source;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.beanNameSuffix = \"MyBean\";\n\t\tthis.origin = mock(Origin.class);\n\t\tthis.container = mock(PostgreSQLContainer.class);\n\t\tthis.annotation = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"name\", \"myname\", \"type\", new Class<?>[0]));\n\t\tthis.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, PostgreSQLContainer.class,\n\t\t\t\tthis.container.getDockerImageName(), this.annotation, () -> this.container, null, null);\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenTypesMatchAndNoNameRestrictionReturnsDetails() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNotNull();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenTypesMatchAndNameRestrictionMatchesReturnsDetails() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory(\"myname\");\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNotNull();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenTypesMatchAndNameRestrictionsMatchReturnsDetails() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory(\n\t\t\t\tList.of(\"notmyname\", \"myname\"));\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNotNull();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenTypesMatchAndNameRestrictionDoesNotMatchReturnsNull() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory(\"notmyname\");\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNull();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenTypesMatchAndNameRestrictionsDoNotMatchReturnsNull() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory(\n\t\t\t\tList.of(\"notmyname\", \"alsonotmyname\"));\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid getConnectionDetailsWhenContainerTypeDoesNotMatchReturnsNull() {\n\t\tGenericContainer<?> container = mock(GenericContainer.class);\n\t\tContainerConnectionSource<?> source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin,\n\t\t\t\tGenericContainer.class, container.getDockerImageName(), this.annotation, () -> container, null, null);\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, source);\n\t\tassertThat(connectionDetails).isNull();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsHasOrigin() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();\n\t\tConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(Origin.from(connectionDetails)).isSameAs(this.origin);\n\t}\n\n\t@Test\n\tvoid getContainerWhenNotInitializedThrowsException() {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();\n\t\tTestDatabaseConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNotNull();\n\t\tassertThatIllegalStateException().isThrownBy(connectionDetails::callGetContainer)\n\t\t\t.withMessage(\"Container cannot be obtained before the connection details bean has been initialized\");\n\t}\n\n\t@Test\n\tvoid getContainerWhenInitializedReturnsSuppliedContainer() throws Exception {\n\t\tTestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();\n\t\tTestDatabaseConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);\n\t\tassertThat(connectionDetails).isNotNull();\n\t\tconnectionDetails.afterPropertiesSet();\n\t\tassertThat(connectionDetails.callGetContainer()).isSameAs(this.container);\n\t}\n\n\t@Test\n\tvoid creatingFactoryWithEmptyNamesThrows() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestContainerConnectionDetailsFactory(Collections.emptyList()));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid creatingFactoryWithNullNamesThrows() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestContainerConnectionDetailsFactory((List<String>) null));\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate @Nullable TestDatabaseConnectionDetails getConnectionDetails(ConnectionDetailsFactory<?, ?> factory,\n\t\t\tContainerConnectionSource<?> source) {\n\t\treturn (TestDatabaseConnectionDetails) ((ConnectionDetailsFactory) factory).getConnectionDetails(source);\n\t}\n\n\t/**\n\t * Test {@link ContainerConnectionDetailsFactory}.\n\t */\n\tstatic class TestContainerConnectionDetailsFactory\n\t\t\textends ContainerConnectionDetailsFactory<JdbcDatabaseContainer<?>, DatabaseConnectionDetails> {\n\n\t\tTestContainerConnectionDetailsFactory() {\n\t\t\tthis(ANY_CONNECTION_NAME);\n\t\t}\n\n\t\tTestContainerConnectionDetailsFactory(@Nullable String connectionName) {\n\t\t\tsuper(connectionName);\n\t\t}\n\n\t\tTestContainerConnectionDetailsFactory(List<String> connectionNames) {\n\t\t\tsuper(connectionNames);\n\t\t}\n\n\t\t@Override\n\t\tprotected DatabaseConnectionDetails getContainerConnectionDetails(\n\t\t\t\tContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\t\treturn new TestDatabaseConnectionDetails(source);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionSourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.FutureContainer;\nimport org.testcontainers.containers.JdbcDatabaseContainer;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.annotation.MergedAnnotation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ContainerConnectionSource}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ContainerConnectionSourceTests {\n\n\tprivate String beanNameSuffix;\n\n\tprivate Origin origin;\n\n\tprivate PostgreSQLContainer container;\n\n\tprivate MergedAnnotation<ServiceConnection> annotation;\n\n\tprivate ContainerConnectionSource<?> source;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.beanNameSuffix = \"MyBean\";\n\t\tthis.origin = mock(Origin.class);\n\t\tthis.container = mock(PostgreSQLContainer.class);\n\t\tgiven(this.container.getDockerImageName()).willReturn(\"postgres\");\n\t\tthis.annotation = MergedAnnotation.of(ServiceConnection.class, Map.of(\"name\", \"\", \"type\", new Class<?>[0]));\n\t\tthis.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, PostgreSQLContainer.class,\n\t\t\t\tthis.container.getDockerImageName(), this.annotation, () -> this.container, null, null);\n\t}\n\n\t@Test\n\tvoid acceptsWhenContainerIsNotInstanceOfRequiredContainerTypeReturnsFalse() {\n\t\tString requiredConnectionName = null;\n\t\tClass<?> requiredContainerType = FutureContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid acceptsWhenContainerIsInstanceOfRequiredContainerTypeReturnsTrue() {\n\t\tString requiredConnectionName = null;\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionNameDoesNotMatchNameTakenFromAnnotationReturnsFalse() {\n\t\tsetupSourceAnnotatedWithName(\"myname\");\n\t\tString requiredConnectionName = \"othername\";\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionNameDoesNotMatchNameTakenFromContainerReturnsFalse() {\n\t\tString requiredConnectionName = \"othername\";\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionNameIsUnrestrictedReturnsTrue() {\n\t\tString requiredConnectionName = null;\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionNameMatchesNameTakenFromAnnotationReturnsTrue() {\n\t\tsetupSourceAnnotatedWithName(\"myname\");\n\t\tString requiredConnectionName = \"myname\";\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionNameMatchesNameTakenFromContainerReturnsTrue() {\n\t\tString requiredConnectionName = \"postgres\";\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionDetailsTypeNotInAnnotationRestrictionReturnsFalse() {\n\t\tsetupSourceAnnotatedWithType(ExampleConnectionDetails.class);\n\t\tString requiredConnectionName = null;\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionDetailsTypeInAnnotationRestrictionReturnsTrue() {\n\t\tsetupSourceAnnotatedWithType(DatabaseConnectionDetails.class);\n\t\tString requiredConnectionName = null;\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid acceptsWhenRequiredConnectionDetailsTypeIsNotRestrictedReturnsTrue() {\n\t\tString requiredConnectionName = null;\n\t\tClass<?> requiredContainerType = JdbcDatabaseContainer.class;\n\t\tClass<?> requiredConnectionDetailsType = DatabaseConnectionDetails.class;\n\t\tassertThat(this.source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid getBeanNameSuffixReturnsBeanNameSuffix() {\n\t\tassertThat(this.source.getBeanNameSuffix()).isEqualTo(this.beanNameSuffix);\n\t}\n\n\t@Test\n\tvoid getOriginReturnsOrigin() {\n\t\tassertThat(this.source.getOrigin()).isEqualTo(this.origin);\n\t}\n\n\t@Test\n\tvoid getContainerSupplierReturnsSupplierSupplyingContainer() {\n\t\tassertThat(this.source.getContainerSupplier().get()).isSameAs(this.container);\n\t}\n\n\t@Test\n\tvoid toStringReturnsSensibleString() {\n\t\tassertThat(this.source.toString()).startsWith(\"@ServiceConnection source for Mock for Origin\");\n\t}\n\n\tprivate void setupSourceAnnotatedWithName(String name) {\n\t\tthis.annotation = MergedAnnotation.of(ServiceConnection.class, Map.of(\"name\", name, \"type\", new Class<?>[0]));\n\t\tthis.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, PostgreSQLContainer.class,\n\t\t\t\tthis.container.getDockerImageName(), this.annotation, () -> this.container, null, null);\n\t}\n\n\tprivate void setupSourceAnnotatedWithType(Class<?> type) {\n\t\tthis.annotation = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"name\", \"\", \"type\", new Class<?>[] { type }));\n\t\tthis.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, PostgreSQLContainer.class,\n\t\t\t\tthis.container.getDockerImageName(), this.annotation, () -> this.container, null, null);\n\t}\n\n\tinterface ExampleConnectionDetails extends ConnectionDetails {\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/DatabaseConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\npublic interface DatabaseConnectionDetails extends ConnectionDetails {\n\n\tString getJdbcUrl();\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/DatabaseContainerDatabaseConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport org.testcontainers.containers.JdbcDatabaseContainer;\n\npublic class DatabaseContainerDatabaseConnectionDetails\n\t\textends ContainerConnectionDetailsFactory<JdbcDatabaseContainer<?>, DatabaseConnectionDetails> {\n\n\t@Override\n\tprotected DatabaseConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\treturn new TestDatabaseConnectionDetails(source);\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/FieldOriginTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.lang.reflect.Field;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link FieldOrigin}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass FieldOriginTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenFieldIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new FieldOrigin(null))\n\t\t\t.withMessage(\"'field' must not be null\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tOrigin o1 = new FieldOrigin(findField(\"one\"));\n\t\tOrigin o2 = new FieldOrigin(findField(\"one\"));\n\t\tOrigin o3 = new FieldOrigin(findField(\"two\"));\n\t\tassertThat(o1).isEqualTo(o1).isEqualTo(o2).isNotEqualTo(o3);\n\t\tassertThat(o1).hasSameHashCodeAs(o2);\n\t}\n\n\t@Test\n\tvoid toStringReturnsSensibleString() {\n\t\tOrigin origin = new FieldOrigin(findField(\"one\"));\n\t\tassertThat(origin).hasToString(\"FieldOriginTests.Fields.one\");\n\t}\n\n\tprivate Field findField(String name) {\n\t\tField field = ReflectionUtils.findField(Fields.class, name);\n\t\tassertThat(field).isNotNull();\n\t\treturn field;\n\t}\n\n\tstatic class Fields {\n\n\t\t@Nullable String one;\n\n\t\t@Nullable String two;\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStream;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ServiceConnectionContextCustomizerFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceConnectionContextCustomizerFactoryTests {\n\n\tprivate final ServiceConnectionContextCustomizerFactory factory = new ServiceConnectionContextCustomizerFactory();\n\n\t@Test\n\tvoid createContextCustomizerWhenNoServiceConnectionsReturnsCustomizerToApplyInitializer() {\n\t\tContextCustomizer customizer = this.factory.createContextCustomizer(NoServiceConnections.class,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tint initialNumberOfPostProcessors = context.getBeanFactoryPostProcessors().size();\n\t\tMergedContextConfiguration mergedConfig = mock(MergedContextConfiguration.class);\n\t\tcustomizer.customizeContext(context, mergedConfig);\n\t\tassertThat(context.getBeanFactoryPostProcessors()).hasSize(initialNumberOfPostProcessors + 1);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenClassHasServiceConnectionsReturnsCustomizer() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(ServiceConnections.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tassertThat(customizer.getSources()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenEnclosingClassHasServiceConnectionsReturnsCustomizer() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(ServiceConnections.NestedClass.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tassertThat(customizer.getSources()).hasSize(3);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenInterfaceHasServiceConnectionsReturnsCustomizer() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(ServiceConnectionsInterface.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tassertThat(customizer.getSources()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenSuperclassHasServiceConnectionsReturnsCustomizer() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(ServiceConnectionsSubclass.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tassertThat(customizer.getSources()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenImplementedInterfaceHasServiceConnectionsReturnsCustomizer() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(ServiceConnectionsImpl.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tassertThat(customizer.getSources()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenInheritedImplementedInterfaceHasServiceConnectionsReturnsCustomizer() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(ServiceConnectionsImplSubclass.class, Collections.emptyList());\n\t\tassertThat(customizer).isNotNull();\n\t\tassertThat(customizer.getSources()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenClassHasNonStaticServiceConnectionFailsWithHelpfulException() {\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> this.factory.createContextCustomizer(NonStaticServiceConnection.class, Collections.emptyList()))\n\t\t\t.withMessage(\"@ServiceConnection field 'service' must be static\");\n\n\t}\n\n\t@Test\n\tvoid createContextCustomizerWhenClassHasAnnotationOnNonConnectionFieldFailsWithHelpfulException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.factory.createContextCustomizer(ServiceConnectionOnWrongFieldType.class,\n\t\t\t\t\tCollections.emptyList()))\n\t\t\t.withMessage(\"Field 'service2' in \" + ServiceConnectionOnWrongFieldType.class.getName()\n\t\t\t\t\t+ \" must be a org.testcontainers.containers.Container\");\n\t}\n\n\t@Test\n\tvoid createContextCustomizerCreatesCustomizerSourceWithSensibleBeanNameSuffix() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(SingleServiceConnection.class, Collections.emptyList());\n\t\tContainerConnectionSource<?> source = customizer.getSources().get(0);\n\t\tassertThat(source.getBeanNameSuffix()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid createContextCustomizerCreatesCustomizerSourceWithSensibleOrigin() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(SingleServiceConnection.class, Collections.emptyList());\n\t\tContainerConnectionSource<?> source = customizer.getSources().get(0);\n\t\tassertThat(source.getOrigin())\n\t\t\t.hasToString(\"ServiceConnectionContextCustomizerFactoryTests.SingleServiceConnection.service1\");\n\t}\n\n\t@Test\n\tvoid createContextCustomizerCreatesCustomizerSourceWithSensibleToString() {\n\t\tServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory\n\t\t\t.createContextCustomizer(SingleServiceConnection.class, Collections.emptyList());\n\t\tContainerConnectionSource<?> source = customizer.getSources().get(0);\n\t\tassertThat(source).hasToString(\n\t\t\t\t\"@ServiceConnection source for ServiceConnectionContextCustomizerFactoryTests.SingleServiceConnection.service1\");\n\t}\n\n\tstatic class NoServiceConnections {\n\n\t}\n\n\tstatic class SingleServiceConnection {\n\n\t\t@ServiceConnection\n\t\tprivate static GenericContainer<?> service1 = new MockContainer();\n\n\t}\n\n\tstatic class ServiceConnections {\n\n\t\t@ServiceConnection\n\t\tprivate static Container<?> service1 = new MockContainer();\n\n\t\t@ServiceConnection\n\t\tprivate static Container<?> service2 = new MockContainer();\n\n\t\t@Nested\n\t\tclass NestedClass {\n\n\t\t\t@ServiceConnection\n\t\t\tprivate static Container<?> service3 = new MockContainer();\n\n\t\t}\n\n\t}\n\n\tinterface ServiceConnectionsInterface {\n\n\t\t@ServiceConnection\n\t\tContainer<?> service1 = new MockContainer();\n\n\t\t@ServiceConnection\n\t\tContainer<?> service2 = new MockContainer();\n\n\t\tdefault void dummy() {\n\t\t}\n\n\t}\n\n\tstatic class ServiceConnectionsSubclass extends ServiceConnections {\n\n\t}\n\n\tstatic class ServiceConnectionsImpl implements ServiceConnectionsInterface {\n\n\t}\n\n\tstatic class ServiceConnectionsImplSubclass extends ServiceConnectionsImpl {\n\n\t}\n\n\tstatic class NonStaticServiceConnection {\n\n\t\t@ServiceConnection\n\t\tprivate Container<?> service = new MockContainer(\"example\");\n\n\t}\n\n\tstatic class ServiceConnectionOnWrongFieldType {\n\n\t\t@ServiceConnection\n\t\tprivate static InputStream service2 = new ByteArrayInputStream(new byte[0]);\n\n\t}\n\n\tstatic class MockContainer extends GenericContainer<MockContainer> {\n\n\t\tprivate final String dockerImageName;\n\n\t\tMockContainer() {\n\t\t\tthis(\"example\");\n\t\t}\n\n\t\tMockContainer(String dockerImageName) {\n\t\t\tsuper(dockerImageName);\n\t\t\tthis.dockerImageName = dockerImageName;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDockerImageName() {\n\t\t\treturn this.dockerImageName;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ServiceConnectionContextCustomizer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ServiceConnectionContextCustomizerTests {\n\n\tprivate Origin origin;\n\n\tprivate PostgreSQLContainer container;\n\n\tprivate MergedAnnotation<ServiceConnection> annotation;\n\n\tprivate ContainerConnectionSource<?> source;\n\n\tprivate ConnectionDetailsFactories factories;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.origin = mock(Origin.class);\n\t\tthis.container = mock(PostgreSQLContainer.class);\n\t\tthis.annotation = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"name\", \"myname\", \"type\", new Class<?>[0]));\n\t\tthis.source = new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class,\n\t\t\t\tthis.container.getDockerImageName(), this.annotation, () -> this.container, null, null);\n\t\tthis.factories = mock(ConnectionDetailsFactories.class);\n\t}\n\n\t@Test\n\tvoid customizeContextRegistersServiceConnections() {\n\t\tServiceConnectionContextCustomizer customizer = new ServiceConnectionContextCustomizer(List.of(this.source),\n\t\t\t\tthis.factories);\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tDefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());\n\t\tgiven(context.getBeanFactory()).willReturn(beanFactory);\n\t\tMergedContextConfiguration mergedConfig = mock(MergedContextConfiguration.class);\n\t\tDatabaseConnectionDetails connectionDetails = new TestConnectionDetails();\n\t\tgiven(this.factories.getConnectionDetails(this.source, true))\n\t\t\t.willReturn(Map.of(DatabaseConnectionDetails.class, connectionDetails));\n\t\tcustomizer.customizeContext(context, mergedConfig);\n\t\tthen(beanFactory).should()\n\t\t\t.registerBeanDefinition(eq(\"testConnectionDetailsForTest\"),\n\t\t\t\t\tArgumentMatchers.<RootBeanDefinition>assertArg((beanDefinition) -> {\n\t\t\t\t\t\tSupplier<?> instanceSupplier = beanDefinition.getInstanceSupplier();\n\t\t\t\t\t\tassertThat(instanceSupplier).isNotNull();\n\t\t\t\t\t\tassertThat(instanceSupplier.get()).isSameAs(connectionDetails);\n\t\t\t\t\t\tassertThat(beanDefinition.getBeanClass()).isEqualTo(TestConnectionDetails.class);\n\t\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tPostgreSQLContainer container1 = mock(PostgreSQLContainer.class);\n\t\tPostgreSQLContainer container2 = mock(PostgreSQLContainer.class);\n\t\tMergedAnnotation<ServiceConnection> annotation1 = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"name\", \"\", \"type\", new Class<?>[0]));\n\t\tMergedAnnotation<ServiceConnection> annotation2 = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"name\", \"\", \"type\", new Class<?>[0]));\n\t\tMergedAnnotation<ServiceConnection> annotation3 = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"name\", \"\", \"type\", new Class<?>[] { DatabaseConnectionDetails.class }));\n\t\t// Connection Names\n\t\tServiceConnectionContextCustomizer n1 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation1, () -> container1, null, null)));\n\t\tServiceConnectionContextCustomizer n2 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation1, () -> container1, null, null)));\n\t\tServiceConnectionContextCustomizer n3 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"namex\",\n\t\t\t\t\t\tannotation1, () -> container1, null, null)));\n\t\tassertThat(n1.hashCode()).isEqualTo(n2.hashCode()).isNotEqualTo(n3.hashCode());\n\t\tassertThat(n1).isEqualTo(n2).isNotEqualTo(n3);\n\t\t// Connection Details Types\n\t\tServiceConnectionContextCustomizer t1 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation1, () -> container1, null, null)));\n\t\tServiceConnectionContextCustomizer t2 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation2, () -> container1, null, null)));\n\t\tServiceConnectionContextCustomizer t3 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation3, () -> container1, null, null)));\n\t\tassertThat(t1.hashCode()).isEqualTo(t2.hashCode()).isNotEqualTo(t3.hashCode());\n\t\tassertThat(t1).isEqualTo(t2).isNotEqualTo(t3);\n\t\t// Container\n\t\tServiceConnectionContextCustomizer c1 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation1, () -> container1, null, null)));\n\t\tServiceConnectionContextCustomizer c2 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation1, () -> container1, null, null)));\n\t\tServiceConnectionContextCustomizer c3 = new ServiceConnectionContextCustomizer(\n\t\t\t\tList.of(new ContainerConnectionSource<>(\"test\", this.origin, PostgreSQLContainer.class, \"name\",\n\t\t\t\t\t\tannotation1, () -> container2, null, null)));\n\t\tassertThat(c1.hashCode()).isEqualTo(c2.hashCode()).isNotEqualTo(c3.hashCode());\n\t\tassertThat(c1).isEqualTo(c2).isNotEqualTo(c3);\n\t}\n\n\tstatic class TestConnectionDetails implements DatabaseConnectionDetails {\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/TestDatabaseConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport org.testcontainers.containers.JdbcDatabaseContainer;\n\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory.ContainerConnectionDetails;\n\nclass TestDatabaseConnectionDetails extends ContainerConnectionDetails<JdbcDatabaseContainer<?>>\n\t\timplements DatabaseConnectionDetails {\n\n\tTestDatabaseConnectionDetails(ContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\tsuper(source);\n\t}\n\n\t@Override\n\tpublic String getJdbcUrl() {\n\t\treturn getContainer().getJdbcUrl();\n\t}\n\n\tJdbcDatabaseContainer<?> callGetContainer() {\n\t\treturn super.getContainer();\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/resources/META-INF/spring.factories",
    "content": "# Test Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.testcontainers.service.connection.DatabaseContainerDatabaseConnectionDetails\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/test/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "core/spring-boot-testcontainers/src/testFixtures/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactoryHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory.ContainerConnectionDetailsFactoriesRuntimeHints;\n\npublic final class ContainerConnectionDetailsFactoryHints {\n\n\tprivate ContainerConnectionDetailsFactoryHints() {\n\t}\n\n\tpublic static RuntimeHints getRegisteredHints(ClassLoader classLoader) {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ContainerConnectionDetailsFactoriesRuntimeHints().registerHints(hints, classLoader);\n\t\treturn hints;\n\t}\n\n}\n"
  },
  {
    "path": "core/spring-boot-testcontainers/src/testFixtures/java/org/springframework/boot/testcontainers/service/connection/TestContainerConnectionSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testcontainers.service.connection;\n\nimport java.util.function.Supplier;\n\nimport org.testcontainers.containers.Container;\n\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.core.annotation.MergedAnnotation;\n\n/**\n * Factory for tests to create a {@link ContainerConnectionSource}.\n *\n * @author Phillip Webb\n */\npublic final class TestContainerConnectionSource {\n\n\tprivate TestContainerConnectionSource() {\n\t}\n\n\tpublic static <C extends Container<?>> ContainerConnectionSource<C> create(String beanNameSuffix, Origin origin,\n\t\t\tClass<C> containerType, String containerImageName, MergedAnnotation<ServiceConnection> annotation,\n\t\t\tSupplier<C> containerSupplier) {\n\t\treturn new ContainerConnectionSource<>(beanNameSuffix, origin, containerType, containerImageName, annotation,\n\t\t\t\tcontainerSupplier, null, null);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.antora-contributor\"\n}\n\ndescription = \"Spring Boot Actuator Docs\"\n\ndependencies {\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-actuator-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-cache\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-health\"))\n\ttestImplementation(project(\":module:spring-boot-http-converter\"))\n\ttestImplementation(project(\":module:spring-boot-integration\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-jdbc\"))\n\ttestImplementation(project(\":module:spring-boot-liquibase\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-metrics\"))\n\ttestImplementation(project(\":module:spring-boot-quartz\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":module:spring-boot-session\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":module:spring-boot-webflux\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-core\")\n\ttestImplementation(\"io.micrometer:micrometer-registry-prometheus\")\n\ttestImplementation(\"io.prometheus:prometheus-metrics-exposition-formats\")\n\ttestImplementation(\"org.springframework.restdocs:spring-restdocs-mockmvc\")\n\ttestImplementation(\"org.springframework.restdocs:spring-restdocs-webtestclient\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n}\n\ntasks.named(\"test\") {\n\toutputs.dir(layout.buildDirectory.dir(\"generated-snippets\"))\n}\n\ntasks.named(\"generateAntoraPlaybook\") {\n\tantoraExtensions.xref.stubs = [\"appendix:.*\", \"api:.*\", \"reference:.*\"]\n}\n\nantoraContributions {\n\t'actuator-rest-api' {\n\t\taggregateContent {\n\t\t\tfrom(tasks.named('test').map { layout.buildDirectory.dir(\"generated-snippets\") }) {\n\t\t\t\tinto \"modules/api/partials/rest/actuator\"\n\t\t\t}\n\t\t}\n\t\tlocalAggregateContent {\n\t\t\tfrom(tasks.named(\"generateAntoraYml\")) {\n\t\t\t\tinto \"modules\"\n\t\t\t}\n\t\t}\n\t\tsource()\n\t}\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/antora.yml",
    "content": "name: boot\nversion: true\next:\n  zip_contents_collector:\n    include:\n    - name: actuator-rest-api\n      classifier: aggregate-content\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/local-nav.adoc",
    "content": "include::api:partial$nav-actuator-rest-api.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/auditevents.adoc",
    "content": "[[audit-events]]\n= Audit Events (`auditevents`)\n\nThe `auditevents` endpoint provides information about the application's audit events.\n\n\n\n[[audit-events.retrieving]]\n== Retrieving Audit Events\n\nTo retrieve the audit events, make a `GET` request to `/actuator/auditevents`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/auditevents/filtered/curl-request.adoc[]\n\nThe preceding example retrieves `logout` events for the principal, `alice`, that occurred after 09:37 on 7 November 2017 in the UTC timezone.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/auditevents/filtered/http-response.adoc[]\n\n\n\n[[audit-events.retrieving.query-parameters]]\n=== Query Parameters\n\nThe endpoint uses query parameters to limit the events that it returns.\nThe following table shows the supported query parameters:\n\n[cols=\"2,4\"]\ninclude::partial$rest/actuator/auditevents/filtered/query-parameters.adoc[]\n\n\n\n[[audit-events.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of all of the audit events that matched the query.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/auditevents/all/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/beans.adoc",
    "content": "[[beans]]\n= Beans (`beans`)\n\nThe `beans` endpoint provides information about the application's beans.\n\n\n\n[[beans.retrieving]]\n== Retrieving the Beans\n\nTo retrieve the beans, make a `GET` request to `/actuator/beans`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/beans/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/beans/http-response.adoc[]\n\n\n\n[[beans.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's beans.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/beans/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/caches.adoc",
    "content": "[[caches]]\n= Caches (`caches`)\n\nThe `caches` endpoint provides access to the application's caches.\n\n\n\n[[caches.all]]\n== Retrieving All Caches\n\nTo retrieve the application's caches, make a `GET` request to `/actuator/caches`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/caches/all/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/caches/all/http-response.adoc[]\n\n\n\n[[caches.all.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's caches.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/caches/all/response-fields.adoc[]\n\n\n\n[[caches.named]]\n== Retrieving Caches by Name\n\nTo retrieve a cache by name, make a `GET` request to `/actuator/caches/\\{name}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/caches/named/curl-request.adoc[]\n\nThe preceding example retrieves information about the cache named `cities`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/caches/named/http-response.adoc[]\n\n\n\n[[caches.named.query-parameters]]\n=== Query Parameters\n\nIf the requested name is specific enough to identify a single cache, no extra parameter is required.\nOtherwise, the `cacheManager` must be specified.\nThe following table shows the supported query parameters:\n\n[cols=\"2,4\"]\ninclude::partial$rest/actuator/caches/named/query-parameters.adoc[]\n\n\n\n[[caches.named.response-structure]]\n=== Response Structure\n\nThe response contains details of the requested cache.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/caches/named/response-fields.adoc[]\n\n\n\n[[caches.evict-all]]\n== Evict All Caches\n\nTo clear all available caches, make a `DELETE` request to `/actuator/caches` as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/caches/evict-all/curl-request.adoc[]\n\n\n\n[[caches.evict-named]]\n== Evict a Cache by Name\n\nTo evict a particular cache, make a `DELETE` request to `/actuator/caches/\\{name}` as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/caches/evict-named/curl-request.adoc[]\n\nNOTE: As there are two caches named `countries`, the `cacheManager` has to be provided to specify which `Cache` should be cleared.\n\n\n\n[[caches.evict-named.request-structure]]\n=== Request Structure\n\nIf the requested name is specific enough to identify a single cache, no extra parameter is required.\nOtherwise, the `cacheManager` must be specified.\nThe following table shows the supported query parameters:\n\n[cols=\"2,4\"]\ninclude::partial$rest/actuator/caches/evict-named/query-parameters.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/conditions.adoc",
    "content": "[[conditions]]\n= Conditions Evaluation Report (`conditions`)\n\nThe `conditions` endpoint provides information about the evaluation of conditions on configuration and auto-configuration classes.\n\n\n\n[[conditions.retrieving]]\n== Retrieving the Report\n\nTo retrieve the report, make a `GET` request to `/actuator/conditions`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/conditions/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/conditions/http-response.adoc[]\n\n\n\n[[conditions.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's condition evaluation.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/conditions/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/configprops.adoc",
    "content": "[[configprops]]\n= Configuration Properties (`configprops`)\n\nThe `configprops` endpoint provides information about the application's `@ConfigurationProperties` beans.\n\n\n\n[[configprops.retrieving]]\n== Retrieving All @ConfigurationProperties Beans\n\nTo retrieve all of the `@ConfigurationProperties` beans, make a `GET` request to `/actuator/configprops`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/configprops/all/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/configprops/all/http-response.adoc[]\n\n\n\n[[configprops.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's `@ConfigurationProperties` beans.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/configprops/all/response-fields.adoc[]\n\n\n\n[[configprops.retrieving-by-prefix]]\n== Retrieving @ConfigurationProperties Beans By Prefix\n\nTo retrieve the `@ConfigurationProperties` beans mapped under a certain prefix, make a `GET` request to `/actuator/configprops/\\{prefix}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/configprops/prefixed/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/configprops/prefixed/http-response.adoc[]\n\nNOTE: The `\\{prefix}` does not need to be exact, a more general prefix will return all beans mapped under that prefix stem.\n\n\n\n[[configprops.retrieving-by-prefix.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's `@ConfigurationProperties` beans.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/configprops/prefixed/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/env.adoc",
    "content": "[[env]]\n= Environment (`env`)\n\nThe `env` endpoint provides information about the application's `Environment`.\n\n\n\n[[env.entire]]\n== Retrieving the Entire Environment\n\nTo retrieve the entire environment, make a `GET` request to `/actuator/env`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/env/all/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/env/all/http-response.adoc[]\n\nNOTE: Sanitization of sensitive values has been switched off for this example.\n\n\n\n[[env.entire.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's `Environment`.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/env/all/response-fields.adoc[]\n\n\n\n[[env.single-property]]\n== Retrieving a Single Property\n\nTo retrieve a single property, make a `GET` request to `/actuator/env/{property.name}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/env/single/curl-request.adoc[]\n\nThe preceding example retrieves information about the property named `com.example.cache.max-size`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/env/single/http-response.adoc[]\n\nNOTE: Sanitization of sensitive values has been switched off for this example.\n\n\n\n[[env.single-property.response-structure]]\n=== Response Structure\n\nThe response contains details of the requested property.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/env/single/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/flyway.adoc",
    "content": "[[flyway]]\n= Flyway (`flyway`)\n\nThe `flyway` endpoint provides information about database migrations performed by Flyway.\n\n\n\n[[flyway.retrieving]]\n== Retrieving the Migrations\n\nTo retrieve the migrations, make a `GET` request to `/actuator/flyway`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/flyway/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/flyway/http-response.adoc[]\n\n\n\n[[flyway.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's Flyway migrations.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/flyway/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/health.adoc",
    "content": "[[health]]\n= Health (`health`)\n\nThe `health` endpoint provides detailed information about the health of the application.\n\n\n\n[[health.retrieving]]\n== Retrieving the Health of the Application\n\nTo retrieve the health of the application, make a `GET` request to `/actuator/health`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/health/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/health/http-response.adoc[]\n\n\n\n[[health.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the health of the application.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/health/response-fields.adoc[]\n\nNOTE: The response fields above are for the V3 API.\nIf you need to return V2 JSON you should use an accept header or `application/vnd.spring-boot.actuator.v2+json`\n\n\n\n[[health.retrieving-component]]\n== Retrieving the Health of a Component\n\nTo retrieve the health of a particular component of the application's health, make a `GET` request to `/actuator/health/\\{component}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/health/component/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/health/component/http-response.adoc[]\n\n\n\n[[health.retrieving-component.response-structure]]\n=== Response Structure\n\nThe response contains details of the health of a particular component of the application's health.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/health/component/response-fields.adoc[]\n\n\n\n[[health.retrieving-component-nested]]\n== Retrieving the Health of a Nested Component\n\nIf a particular component contains other nested components (as the `broker` indicator in the example above), the health of such a nested component can be retrieved by issuing a `GET` request to `/actuator/health/\\{component}/\\{subcomponent}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/health/instance/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/health/instance/http-response.adoc[]\n\nComponents of an application's health may be nested arbitrarily deep depending on the application's health indicators and how they have been grouped.\nThe health endpoint supports any number of `/\\{component}` identifiers in the URL to allow the health of a component at any depth to be retrieved.\n\n\n\n[[health.retrieving-component-nested.response-structure]]\n=== Response Structure\n\nThe response contains details of the health of an instance of a particular component of the application.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/health/instance/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/heapdump.adoc",
    "content": "[[heapdump]]\n= Heap Dump (`heapdump`)\n\nThe `heapdump` endpoint provides a heap dump from the application's JVM.\n\n\n\n[[heapdump.retrieving]]\n== Retrieving the Heap Dump\n\nTo retrieve the heap dump, make a `GET` request to `/actuator/heapdump`.\nThe response is binary data and can be large.\nIts format depends upon the JVM on which the application is running.\nWhen running on a HotSpot JVM the format is https://docs.oracle.com/javase/8/docs/technotes/samples/hprof.html[HPROF]\nand on OpenJ9 it is https://www.eclipse.org/openj9/docs/dump_heapdump/#portable-heap-dump-phd-format[PHD].\nTypically, you should save the response to disk for subsequent analysis.\nWhen using curl, this can be achieved by using the `-O` option, as shown in the following example:\n\ninclude::partial$rest/actuator/heapdump/curl-request.adoc[]\n\nThe preceding example results in a file named `heapdump` being written to the current working directory.\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/httpexchanges.adoc",
    "content": "[[httpexchanges]]\n= HTTP Exchanges (`httpexchanges`)\n\nThe `httpexchanges` endpoint provides information about HTTP request-response exchanges.\n\n\n\n[[httpexchanges.retrieving]]\n== Retrieving the HTTP Exchanges\n\nTo retrieve the HTTP exchanges, make a `GET` request to `/actuator/httpexchanges`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/httpexchanges/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/httpexchanges/http-response.adoc[]\n\n\n\n[[httpexchanges.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the traced HTTP request-response exchanges.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/httpexchanges/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/index.adoc",
    "content": ":navtitle: Actuator\n[[overview]]\n= Actuator REST API\n\nThis API documentation describes Spring Boot Actuators web endpoints.\n\nBefore you proceed, you should read the following topics:\n\n* xref:#overview.endpoint-urls[]\n* xref:#overview.timestamps[]\n\nNOTE: In order to get the correct JSON responses documented below, Jackson must be available.\n\n\n\n[[overview.endpoint-urls]]\n== URLs\n\nBy default, all web endpoints are available beneath the path `/actuator` with URLs of\nthe form `/actuator/\\{id}`. The `/actuator` base path can be configured by using the\n`management.endpoints.web.base-path` property, as shown in the following example:\n\n[source,properties]\n----\nmanagement.endpoints.web.base-path=/manage\n----\n\nThe preceding `application.properties` example changes the form of the endpoint URLs from\n`/actuator/\\{id}` to `/manage/\\{id}`. For example, the URL `info` endpoint would become\n`/manage/info`.\n\n\n\n[[overview.timestamps]]\n== Timestamps\n\nAll timestamps that are consumed by the endpoints, either as query parameters or in the\nrequest body, must be formatted as an offset date and time as specified in\nhttps://en.wikipedia.org/wiki/ISO_8601[ISO 8601].\n\n\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/info.adoc",
    "content": "[[info]]\n= Info (`info`)\n\nThe `info` endpoint provides general information about the application.\n\n\n\n[[info.retrieving]]\n== Retrieving the Info\n\nTo retrieve the information about the application, make a `GET` request to `/actuator/info`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/info/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/info/http-response.adoc[]\n\n\n\n[[info.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains general information about the application.\nEach section of the response is contributed by an `InfoContributor`.\nSpring Boot provides several contributors that are described below.\n\n\n\n[[info.retrieving.response-structure.build]]\n==== Build Response Structure\n\nThe following table describe the structure of the `build` section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/info/response-fields-beneath-build.adoc[]\n\n\n\n[[info.retrieving.response-structure.git]]\n==== Git Response Structure\n\nThe following table describes the structure of the `git` section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/info/response-fields-beneath-git.adoc[]\n\nNOTE: This is the \"simple\" output.\nThe contributor can also be configured to output all available data.\n\n\n[[info.retrieving.response-structure.os]]\n==== OS Response Structure\n\nThe following table describes the structure of the `os` section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/info/response-fields-beneath-os.adoc[]\n\n\n\n[[info.retrieving.response-structure.process]]\n==== Process Response Structure\n\nThe following table describes the structure of the `process` section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/info/response-fields-beneath-process.adoc[]\n\n\n\n[[info.retrieving.response-structure.java]]\n==== Java Response Structure\n\nThe following table describes the structure of the `java` section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/info/response-fields-beneath-java.adoc[]\n\n\n\n[[info.retrieving.response-structure.ssl]]\n==== SSL Response Structure\n\nThe following table describes the structure of the `ssl` section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/info/response-fields-beneath-ssl.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/integrationgraph.adoc",
    "content": "[[integrationgraph]]\n= Spring Integration Graph (`integrationgraph`)\n\nThe `integrationgraph` endpoint exposes a graph containing all Spring Integration components.\n\n\n\n[[integrationgraph.retrieving]]\n== Retrieving the Spring Integration Graph\n\nTo retrieve the information about the application, make a `GET` request to `/actuator/integrationgraph`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/integrationgraph/graph/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/integrationgraph/graph/http-response.adoc[]\n\n\n\n[[integrationgraph.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains all Spring Integration components used within the application, as well as the links between them.\nMore information about the structure can be found in the {url-spring-integration-docs}/graph.html[reference documentation].\n\n\n\n[[integrationgraph.rebuilding]]\n== Rebuilding the Spring Integration Graph\n\nTo rebuild the exposed graph, make a `POST` request to `/actuator/integrationgraph`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/integrationgraph/rebuild/curl-request.adoc[]\n\nThis will result in a `204 - No Content` response:\n\ninclude::partial$rest/actuator/integrationgraph/rebuild/http-response.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/liquibase.adoc",
    "content": "[[liquibase]]\n= Liquibase (`liquibase`)\n\nThe `liquibase` endpoint provides information about database change sets applied by Liquibase.\n\n\n\n[[liquibase.retrieving]]\n== Retrieving the Changes\n\nTo retrieve the changes, make a `GET` request to `/actuator/liquibase`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/liquibase/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/liquibase/http-response.adoc[]\n\n\n\n[[liquibase.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's Liquibase change sets.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/liquibase/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/logfile.adoc",
    "content": "[[logfile]]\n= Log File (`logfile`)\n\nThe `logfile` endpoint provides access to the contents of the application's log file.\n\n\n\n[[logfile.retrieving]]\n== Retrieving the Log File\n\nTo retrieve the log file, make a `GET` request to `/actuator/logfile`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/logfile/entire/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/logfile/entire/http-response.adoc[]\n\n\n\n[[logfile.retrieving-part]]\n== Retrieving Part of the Log File\n\nNOTE: Retrieving part of the log file is not supported when using Jersey.\n\nTo retrieve part of the log file, make a `GET` request to `/actuator/logfile` by using the `Range` header, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/logfile/range/curl-request.adoc[]\n\nThe preceding example retrieves the first 1024 bytes of the log file.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/logfile/range/http-response.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/loggers.adoc",
    "content": "[[loggers]]\n= Loggers (`loggers`)\n\nThe `loggers` endpoint provides access to the application's loggers and the configuration of their levels.\n\n\n\n[[loggers.all]]\n== Retrieving All Loggers\n\nTo retrieve the application's loggers, make a `GET` request to `/actuator/loggers`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/loggers/all/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/loggers/all/http-response.adoc[]\n\n\n\n[[loggers.all.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's loggers.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/loggers/all/response-fields.adoc[]\n\n\n\n[[loggers.single]]\n== Retrieving a Single Logger\n\nTo retrieve a single logger, make a `GET` request to `/actuator/loggers/{logger.name}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/loggers/single/curl-request.adoc[]\n\nThe preceding example retrieves information about the logger named `com.example`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/loggers/single/http-response.adoc[]\n\n\n\n[[loggers.single.response-structure]]\n=== Response Structure\n\nThe response contains details of the requested logger.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/loggers/single/response-fields.adoc[]\n\n\n\n[[loggers.group]]\n== Retrieving a Single Group\n\nTo retrieve a single group, make a `GET` request to `/actuator/loggers/{group.name}`,\nas shown in the following curl-based example:\n\ninclude::partial$rest/actuator/loggers/group/curl-request.adoc[]\n\nThe preceding example retrieves information about the logger group named `test`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/loggers/group/http-response.adoc[]\n\n\n\n[[loggers.group.response-structure]]\n=== Response Structure\n\nThe response contains details of the requested group.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/loggers/group/response-fields.adoc[]\n\n\n\n[[loggers.setting-level]]\n== Setting a Log Level\n\nTo set the level of a logger, make a `POST` request to `/actuator/loggers/{logger.name}` with a JSON body that specifies the configured level for the logger, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/loggers/set/curl-request.adoc[]\n\nThe preceding example sets the `configuredLevel` of the `com.example` logger to `DEBUG`.\n\n\n\n[[loggers.setting-level.request-structure]]\n=== Request Structure\n\nThe request specifies the desired level of the logger.\nThe following table describes the structure of the request:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/loggers/set/request-fields.adoc[]\n\n\n\n[[loggers.group-setting-level]]\n== Setting a Log Level for a Group\n\nTo set the level of a logger, make a `POST` request to `/actuator/loggers/{group.name}` with a JSON body that specifies the configured level for the logger group, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/loggers/setGroup/curl-request.adoc[]\n\nThe preceding example sets the `configuredLevel` of the `test` logger group to `DEBUG`.\n\n\n\n[[loggers.group-setting-level.request-structure]]\n=== Request Structure\n\nThe request specifies the desired level of the logger group.\nThe following table describes the structure of the request:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/loggers/set/request-fields.adoc[]\n\n\n\n[[loggers.clearing-level]]\n== Clearing a Log Level\n\nTo clear the level of a logger, make a `POST` request to `/actuator/loggers/{logger.name}` with a JSON body containing an empty object, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/loggers/clear/curl-request.adoc[]\n\nThe preceding example clears the configured level of the `com.example` logger.\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/mappings.adoc",
    "content": "[[mappings]]\n= Mappings (`mappings`)\n\nThe `mappings` endpoint provides information about the application's request mappings.\n\n\n\n[[mappings.retrieving]]\n== Retrieving the Mappings\n\nTo retrieve the mappings, make a `GET` request to `/actuator/mappings`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/mappings/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/mappings/http-response.adoc[]\n\n\n\n[[mappings.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's mappings.\nThe items found in the response depend on the type of web application (reactive or Servlet-based).\nThe following table describes the structure of the common elements of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/mappings/response-fields.adoc[]\n\nThe entries that may be found in `contexts.*.mappings` are described in the following sections.\n\n\n\n[[mappings.retrieving.response-structure-dispatcher-servlets]]\n=== Dispatcher Servlets Response Structure\n\nWhen using Spring MVC, the response contains details of any `DispatcherServlet` request mappings beneath `contexts.*.mappings.dispatcherServlets`.\nThe following table describes the structure of this section of the response:\n\n[cols=\"4,1,2\"]\ninclude::partial$rest/actuator/mappings/response-fields-dispatcher-servlets.adoc[]\n\n\n\n[[mappings.retrieving.response-structure-servlets]]\n=== Servlets Response Structure\n\nWhen using the Servlet stack, the response contains details of any `Servlet` mappings beneath `contexts.*.mappings.servlets`.\nThe following table describes the structure of this section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/mappings/response-fields-servlets.adoc[]\n\n\n\n[[mappings.retrieving.response-structure-servlet-filters]]\n=== Servlet Filters Response Structure\n\nWhen using the Servlet stack, the response contains details of any `Filter` mappings beneath `contexts.*.mappings.servletFilters`.\nThe following table describes the structure of this section of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/mappings/response-fields-servlet-filters.adoc[]\n\n\n\n[[mappings.retrieving.response-structure-dispatcher-handlers]]\n=== Dispatcher Handlers Response Structure\n\nWhen using Spring WebFlux, the response contains details of any `DispatcherHandler` request mappings beneath `contexts.*.mappings.dispatcherHandlers`.\nThe following table describes the structure of this section of the response:\n\n[cols=\"4,1,2\"]\ninclude::partial$rest/actuator/mappings/response-fields-dispatcher-handlers.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/metrics.adoc",
    "content": "[[metrics]]\n= Metrics (`metrics`)\n\nThe `metrics` endpoint provides access to application metrics to diagnose the metrics the application has recorded.\nThis endpoint should not be \"scraped\" or used as a metrics backend in production.\nIts purpose is to show the currently registered metrics so users can see what metrics are available, what their current values are, and if triggering certain operations causes any change in certain values.\nIf you want to diagnose your applications through the metrics they collect, you should use an xref:reference:actuator/metrics.adoc[external metrics backend].\nIn this case, the `metrics` endpoint can still be useful.\n\n\n\n[[metrics.retrieving-names]]\n== Retrieving Metric Names\n\nTo retrieve the names of the available metrics, make a `GET` request to `/actuator/metrics`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/metrics/names/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/metrics/names/http-response.adoc[]\n\n\n\n[[metrics.retrieving-names.response-structure]]\n=== Response Structure\n\nThe response contains details of the metric names.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,2\"]\ninclude::partial$rest/actuator/metrics/names/response-fields.adoc[]\n\n\n\n[[metrics.retrieving-metric]]\n== Retrieving a Metric\n\nTo retrieve a metric, make a `GET` request to `/actuator/metrics/{metric.name}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/metrics/metric/curl-request.adoc[]\n\nThe preceding example retrieves information about the metric named `jvm.memory.max`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/metrics/metric/http-response.adoc[]\n\n\n\n[[metrics.retrieving-metric.query-parameters]]\n=== Query Parameters\n\nThe endpoint uses query parameters to xref:rest/actuator/metrics.adoc#metrics.drilling-down[drill down] into a metric by using its tags.\nThe following table shows the single supported query parameter:\n\n[cols=\"2,4\"]\ninclude::partial$rest/actuator/metrics/metric-with-tags/query-parameters.adoc[]\n\n\n\n[[metrics.retrieving-metric.response-structure]]\n=== Response Structure\n\nThe response contains details of the metric.\nThe following table describes the structure of the response:\n\ninclude::partial$rest/actuator/metrics/metric/response-fields.adoc[]\n\n\n\n[[metrics.drilling-down]]\n== Drilling Down\n\nTo drill down into a metric, make a `GET` request to `/actuator/metrics/{metric.name}` using the `tag` query parameter, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/metrics/metric-with-tags/curl-request.adoc[]\n\nThe preceding example retrieves the `jvm.memory.max` metric, where the `area` tag has a value of `nonheap` and the `id` attribute has a value of `Compressed Class Space`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/metrics/metric-with-tags/http-response.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/prometheus.adoc",
    "content": "[[prometheus]]\n= Prometheus (`prometheus`)\n\nThe `prometheus` endpoint provides Spring Boot application's metrics in the format required for scraping by a Prometheus server.\n\n\n\n[[prometheus.retrieving]]\n== Retrieving All Metrics\n\nTo retrieve all metrics, make a `GET` request to `/actuator/prometheus`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/prometheus/all/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/prometheus/all/http-response.adoc[]\n\nThe default response content type is `text/plain;version=0.0.4`.\nThe endpoint can also produce `application/openmetrics-text;version=1.0.0` when called with an appropriate `Accept` header, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/prometheus/openmetrics/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/prometheus/openmetrics/http-response.adoc[]\n\n\n\n[[prometheus.retrieving.query-parameters]]\n=== Query Parameters\n\nThe endpoint uses query parameters to limit the samples that it returns.\nThe following table shows the supported query parameters:\n\n[cols=\"2,4\"]\ninclude::partial$rest/actuator/prometheus/names/query-parameters.adoc[]\n\n\n\n[[prometheus.retrieving-names]]\n== Retrieving Filtered Metrics\n\nTo retrieve metrics matching specific names, make a `GET` request to `/actuator/prometheus` with the `includedNames` query parameter, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/prometheus/names/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/prometheus/names/http-response.adoc[]\n\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/quartz.adoc",
    "content": "[[quartz]]\n= Quartz (`quartz`)\n\nThe `quartz` endpoint provides information about jobs and triggers that are managed by the Quartz Scheduler.\n\n\n\n[[quartz.report]]\n== Retrieving Registered Groups\n\nJobs and triggers are managed in groups.\nTo retrieve the list of registered job and trigger groups, make a `GET` request to `/actuator/quartz`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/report/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/quartz/report/http-response.adoc[]\n\n\n\n[[quartz.report.response-structure]]\n=== Response Structure\n\nThe response contains the groups names for registered jobs and triggers.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/quartz/report/response-fields.adoc[]\n\n\n\n[[quartz.job-groups]]\n== Retrieving Registered Job Names\n\nTo retrieve the list of registered job names, make a `GET` request to `/actuator/quartz/jobs`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/jobs/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/quartz/jobs/http-response.adoc[]\n\n\n\n[[quartz.job-groups.response-structure]]\n=== Response Structure\n\nThe response contains the registered job names for each group.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/quartz/jobs/response-fields.adoc[]\n\n\n\n[[quartz.trigger-groups]]\n== Retrieving Registered Trigger Names\n\nTo retrieve the list of registered trigger names, make a `GET` request to `/actuator/quartz/triggers`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/triggers/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/quartz/triggers/http-response.adoc[]\n\n\n\n[[quartz.trigger-groups.response-structure]]\n=== Response Structure\n\nThe response contains the registered trigger names for each group.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/quartz/triggers/response-fields.adoc[]\n\n\n\n[[quartz.job-group]]\n== Retrieving Overview of a Job Group\n\nTo retrieve an overview of the jobs in a particular group, make a `GET` request to `/actuator/quartz/jobs/\\{groupName}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/job-group/curl-request.adoc[]\n\nThe preceding example retrieves the summary for jobs in the `samples` group.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/quartz/job-group/http-response.adoc[]\n\n\n\n[[quartz.job-group.response-structure]]\n=== Response Structure\n\nThe response contains an overview of jobs in a particular group.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/quartz/job-group/response-fields.adoc[]\n\n\n\n[[quartz.trigger-group]]\n== Retrieving Overview of a Trigger Group\n\nTo retrieve an overview of the triggers in a particular group, make a `GET` request to `/actuator/quartz/triggers/\\{groupName}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/trigger-group/curl-request.adoc[]\n\nThe preceding example retrieves the summary for triggers in the `tests` group.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-group/http-response.adoc[]\n\n\n\n[[quartz.trigger-group.response-structure]]\n=== Response Structure\n\nThe response contains an overview of triggers in a particular group.\nTrigger implementation specific details are available.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-group/response-fields.adoc[]\n\n\n\n[[quartz.job]]\n== Retrieving Details of a Job\n\nTo retrieve the details about a particular job, make a `GET` request to `/actuator/quartz/jobs/\\{groupName}/\\{jobName}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/job-details/curl-request.adoc[]\n\nThe preceding example retrieves the details of the job identified by the `samples` group and `jobOne` name.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/quartz/job-details/http-response.adoc[]\n\nIf a key in the data map is identified as sensitive, its value is sanitized.\n\n\n\n[[quartz.job.response-structure]]\n=== Response Structure\n\nThe response contains the full details of a job including a summary of the triggers associated with it, if any.\nThe triggers are sorted by next fire time and priority.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/job-details/response-fields.adoc[]\n\n\n\n[[quartz.trigger-job]]\n== Trigger Quartz Job On Demand\n\nTo trigger a particular Quartz job, make a `POST` request to `/actuator/quartz/jobs/\\{groupName}/\\{jobName}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/trigger-job/curl-request.adoc[]\n\nThe preceding example demonstrates how to trigger a job that belongs to the `samples` group and is named `jobOne`.\n\nThe response will look similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-job/http-response.adoc[]\n\n\n\n[[quartz.trigger-job.request-structure]]\n=== Request Structure\n\nThe request specifies a desired `state` associated with a particular job.\nSending an HTTP request with a `\"state\": \"running\"` body indicates that the job should be run now.\nThe following table describes the structure of the request:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-job/request-fields.adoc[]\n\n[[quartz.trigger-job.response-structure]]\n=== Response Structure\n\nThe response contains the details of a triggered job.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-job/response-fields.adoc[]\n\n\n\n[[quartz.trigger]]\n== Retrieving Details of a Trigger\n\nTo retrieve the details about a particular trigger, make a `GET` request to `/actuator/quartz/triggers/\\{groupName}/\\{triggerName}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/quartz/trigger-details-cron/curl-request.adoc[]\n\nThe preceding example retrieves the details of trigger identified by the `samples` group and `example` name.\n\n\n\n[[quartz.trigger.common-response-structure]]\n=== Common Response Structure\n\nThe response has a common structure and an additional object that is specific to the trigger's type.\nThere are five supported types:\n\n* `cron` for `CronTrigger`\n* `simple` for `SimpleTrigger`\n* `dailyTimeInterval` for `DailyTimeIntervalTrigger`\n* `calendarInterval` for `CalendarIntervalTrigger`\n* `custom` for any other trigger implementations\n\nThe following table describes the structure of the common elements of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-details-common/response-fields.adoc[]\n\n\n\n[[quartz.trigger.cron-response-structure]]\n=== Cron Trigger Response Structure\n\nA cron trigger defines the cron expression that is used to determine when it has to fire.\nThe resulting response for such a trigger implementation is similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-details-cron/http-response.adoc[]\n\n\nMuch of the response is common to all trigger types.\nThe structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].\nThe following table describes the structure of the parts of the response that are specific to cron triggers:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-details-cron/response-fields.adoc[]\n\n\n\n[[quartz.trigger.simple-response-structure]]\n=== Simple Trigger Response Structure\n\nA simple trigger is used to fire a Job at a given moment in time, and optionally repeated at a specified interval.\nThe resulting response for such a trigger implementation is similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-details-simple/http-response.adoc[]\n\n\nMuch of the response is common to all trigger types.\nThe structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].\nThe following table describes the structure of the parts of the response that are specific to simple triggers:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-details-simple/response-fields.adoc[]\n\n\n\n[[quartz.trigger.daily-time-interval-response-structure]]\n=== Daily Time Interval Trigger Response Structure\n\nA daily time interval trigger is used to fire a Job based upon daily repeating time intervals.\nThe resulting response for such a trigger implementation is similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-details-daily-time-interval/http-response.adoc[]\n\n\nMuch of the response is common to all trigger types.\nThe structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].\nThe following table describes the structure of the parts of the response that are specific to daily time interval triggers:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-details-daily-time-interval/response-fields.adoc[]\n\n\n\n[[quartz.trigger.calendar-interval-response-structure]]\n=== Calendar Interval Trigger Response Structure\n\nA calendar interval trigger is used to fire a Job based upon repeating calendar time intervals.\nThe resulting response for such a trigger implementation is similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-details-calendar-interval/http-response.adoc[]\n\n\nMuch of the response is common to all trigger types.\nThe structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].\nThe following table describes the structure of the parts of the response that are specific to calendar interval triggers:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-details-calendar-interval/response-fields.adoc[]\n\n\n\n[[quartz.trigger.custom-response-structure]]\n=== Custom Trigger Response Structure\n\nA custom trigger is any other implementation.\nThe resulting response for such a trigger implementation is similar to the following:\n\ninclude::partial$rest/actuator/quartz/trigger-details-custom/http-response.adoc[]\n\n\nMuch of the response is common to all trigger types.\nThe structure of the common elements of the response was xref:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[described previously].\nThe following table describes the structure of the parts of the response that are specific to custom triggers:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/quartz/trigger-details-custom/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/sbom.adoc",
    "content": "[[sbom]]\n= Software Bill of Materials (`sbom`)\n\nThe `sbom` endpoint provides information about the software bill of materials (SBOM).\n\n\n\n[[sbom.retrieving-available-sboms]]\n== Retrieving the Available SBOMs\n\nTo retrieve the available SBOMs, make a `GET` request to `/actuator/sbom`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/sbom/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/sbom/http-response.adoc[]\n\n\n\n[[sbom.retrieving-available-sboms.response-structure]]\n=== Response Structure\n\nThe response contains the available SBOMs.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/sbom/response-fields.adoc[]\n\n\n\n[[sbom.retrieving-single-sbom]]\n== Retrieving a Single SBOM\n\nTo retrieve the available SBOMs, make a `GET` request to `/actuator/sbom/\\{id}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/sbom/id/curl-request.adoc[]\n\nThe preceding example retrieves the SBOM named application.\nThe resulting response depends on the format of the SBOM.\nThis example uses the CycloneDX format.\n\n[source,http,options=\"nowrap\"]\n----\nHTTP/1.1 200 OK\nContent-Type: application/vnd.cyclonedx+json\nAccept-Ranges: bytes\nContent-Length: 160316\n\n{\n  \"bomFormat\" : \"CycloneDX\",\n  \"specVersion\" : \"1.5\",\n  \"serialNumber\" : \"urn:uuid:13862013-3360-43e5-8055-3645aa43c548\",\n  \"version\" : 1,\n  // ...\n}\n----\n\n\n\n[[sbom.retrieving-single-sbom.response-structure]]\n=== Response Structure\nThe response depends on the format of the SBOM:\n\n* https://cyclonedx.org/specification/overview/[CycloneDX]\n\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/scheduledtasks.adoc",
    "content": "[[scheduled-tasks]]\n= Scheduled Tasks (`scheduledtasks`)\n\nThe `scheduledtasks` endpoint provides information about the application's scheduled tasks.\n\n\n\n[[scheduled-tasks.retrieving]]\n== Retrieving the Scheduled Tasks\n\nTo retrieve the scheduled tasks, make a `GET` request to `/actuator/scheduledtasks`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/scheduled-tasks/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/scheduled-tasks/http-response.adoc[]\n\n\n\n[[scheduled-tasks.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application's scheduled tasks.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/scheduled-tasks/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/sessions.adoc",
    "content": "[[sessions]]\n= Sessions (`sessions`)\n\nThe `sessions` endpoint provides information about the application's HTTP sessions that are managed by Spring Session.\n\n\n\n[[sessions.retrieving]]\n== Retrieving Sessions\n\nTo retrieve the sessions, make a `GET` request to `/actuator/sessions`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/sessions/username/curl-request.adoc[]\n\nThe preceding examples retrieves all of the sessions for the user whose username is `alice`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/sessions/username/http-response.adoc[]\n\n\n\n[[sessions.retrieving.query-parameters]]\n=== Query Parameters\n\nThe endpoint uses query parameters to limit the sessions that it returns.\nThe following table shows the single required query parameter:\n\n[cols=\"2,4\"]\ninclude::partial$rest/actuator/sessions/username/query-parameters.adoc[]\n\n\n\n[[sessions.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the matching sessions.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/sessions/username/response-fields.adoc[]\n\n\n\n[[sessions.retrieving-id]]\n== Retrieving a Single Session\n\nTo retrieve a single session, make a `GET` request to `/actuator/sessions/\\{id}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/sessions/id/curl-request.adoc[]\n\nThe preceding example retrieves the session with the `id` of `4db5efcc-99cb-4d05-a52c-b49acfbb7ea9`.\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/sessions/id/http-response.adoc[]\n\n\n\n[[sessions.retrieving-id.response-structure]]\n=== Response Structure\n\nThe response contains details of the requested session.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/sessions/id/response-fields.adoc[]\n\n\n\n[[sessions.deleting]]\n== Deleting a Session\n\nTo delete a session, make a `DELETE` request to `/actuator/sessions/\\{id}`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/sessions/delete/curl-request.adoc[]\n\nThe preceding example deletes the session with the `id` of `4db5efcc-99cb-4d05-a52c-b49acfbb7ea9`.\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/shutdown.adoc",
    "content": "[[shutdown]]\n= Shutdown (`shutdown`)\n\nThe `shutdown` endpoint is used to shut down the application.\n\n\n\n[[shutdown.shutting-down]]\n== Shutting Down the Application\n\nTo shut down the application, make a `POST` request to `/actuator/shutdown`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/shutdown/curl-request.adoc[]\n\nA response similar to the following is produced:\n\ninclude::partial$rest/actuator/shutdown/http-response.adoc[]\n\n\n\n[[shutdown.shutting-down.response-structure]]\n=== Response Structure\n\nThe response contains details of the result of the shutdown request.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,3\"]\ninclude::partial$rest/actuator/shutdown/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/startup.adoc",
    "content": "[[startup]]\n= Application Startup (`startup`)\n\nThe `startup` endpoint provides information about the application's startup sequence.\n\n\n\n[[startup.retrieving]]\n== Retrieving the Application Startup Steps\n\nThe application startup steps can either be retrieved as a snapshot (`GET`) or drained from the buffer (`POST`).\n\n\n\n[[startup.retrieving.snapshot]]\n=== Retrieving a snapshot of the Application Startup Steps\n\nTo retrieve the steps recorded so far during the application startup phase, make a `GET` request to `/actuator/startup`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/startup-snapshot/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/startup-snapshot/http-response.adoc[]\n\n\n\n[[startup.retrieving.drain]]\n=== Draining the Application Startup Steps\n\nTo drain and return the steps recorded so far during the application startup phase, make a `POST` request to `/actuator/startup`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/startup/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/startup/http-response.adoc[]\n\n\n\n[[startup.retrieving.response-structure]]\n=== Response Structure\n\nThe response contains details of the application startup steps.\nThe following table describes the structure of the response:\n\n[cols=\"2,1,3\"]\ninclude::partial$rest/actuator/startup/response-fields.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/pages/rest/actuator/threaddump.adoc",
    "content": "[[threaddump]]\n= Thread Dump (`threaddump`)\n\nThe `threaddump` endpoint provides a thread dump from the application's JVM.\n\n\n\n[[threaddump.retrieving-json]]\n== Retrieving the Thread Dump as JSON\n\nTo retrieve the thread dump as JSON, make a `GET` request to `/actuator/threaddump` with an appropriate `Accept` header, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/threaddump/json/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/threaddump/json/http-response.adoc[]\n\n\n\n[[threaddump.retrieving-json.response-structure]]\n=== Response Structure\n\nThe response contains details of the JVM's threads.\nThe following table describes the structure of the response:\n\n[cols=\"3,1,2\"]\ninclude::partial$rest/actuator/threaddump/json/response-fields.adoc[]\n\n\n\n[[threaddump.retrieving-text]]\n== Retrieving the Thread Dump as Text\n\nTo retrieve the thread dump as text, make a `GET` request to `/actuator/threaddump` that\naccepts `text/plain`, as shown in the following curl-based example:\n\ninclude::partial$rest/actuator/threaddump/text/curl-request.adoc[]\n\nThe resulting response is similar to the following:\n\ninclude::partial$rest/actuator/threaddump/text/http-response.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/docs/antora/modules/api/partials/nav-actuator-rest-api.adoc",
    "content": "* xref:api:rest/actuator/index.adoc[]\n** xref:api:rest/actuator/auditevents.adoc[]\n** xref:api:rest/actuator/beans.adoc[]\n** xref:api:rest/actuator/caches.adoc[]\n** xref:api:rest/actuator/conditions.adoc[]\n** xref:api:rest/actuator/configprops.adoc[]\n** xref:api:rest/actuator/env.adoc[]\n** xref:api:rest/actuator/flyway.adoc[]\n** xref:api:rest/actuator/health.adoc[]\n** xref:api:rest/actuator/heapdump.adoc[]\n** xref:api:rest/actuator/httpexchanges.adoc[]\n** xref:api:rest/actuator/info.adoc[]\n** xref:api:rest/actuator/integrationgraph.adoc[]\n** xref:api:rest/actuator/liquibase.adoc[]\n** xref:api:rest/actuator/logfile.adoc[]\n** xref:api:rest/actuator/loggers.adoc[]\n** xref:api:rest/actuator/mappings.adoc[]\n** xref:api:rest/actuator/metrics.adoc[]\n** xref:api:rest/actuator/prometheus.adoc[]\n** xref:api:rest/actuator/quartz.adoc[]\n** xref:api:rest/actuator/sbom.adoc[]\n** xref:api:rest/actuator/scheduledtasks.adoc[]\n** xref:api:rest/actuator/sessions.adoc[]\n** xref:api:rest/actuator/shutdown.adoc[]\n** xref:api:rest/actuator/startup.adoc[]\n** xref:api:rest/actuator/threaddump.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/AbstractEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests.BaseDocumentationConfiguration;\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.actuate.web.WebFluxEndpointManagementContextConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.actuate.web.WebMvcEndpointManagementContextConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;\nimport org.springframework.restdocs.operation.preprocess.OperationPreprocessor;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.util.StringUtils;\n\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\n\n/**\n * Abstract base class for tests that generate endpoint documentation using Spring REST\n * Docs.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = { \"management.endpoints.web.exposure.include=*\" })\n@Import(BaseDocumentationConfiguration.class)\npublic abstract class AbstractEndpointDocumentationTests {\n\n\tprotected static String describeEnumValues(Class<? extends Enum<?>> enumType) {\n\t\treturn StringUtils.collectionToDelimitedString(\n\t\t\t\tStream.of(enumType.getEnumConstants()).map((constant) -> \"`\" + constant.name() + \"`\").toList(), \", \");\n\t}\n\n\tprotected OperationPreprocessor limit(String... keys) {\n\t\treturn limit((candidate) -> true, keys);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected <T> OperationPreprocessor limit(Predicate<T> filter, String... keys) {\n\t\treturn new ContentModifyingOperationPreprocessor((content, mediaType) -> {\n\t\t\tJsonMapper jsonMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();\n\t\t\tMap<String, Object> payload = jsonMapper.readValue(content, Map.class);\n\t\t\tObject target = payload;\n\t\t\tMap<Object, Object> parent = null;\n\t\t\tfor (String key : keys) {\n\t\t\t\tif (!(target instanceof Map)) {\n\t\t\t\t\tthrow new IllegalStateException();\n\t\t\t\t}\n\t\t\t\tparent = (Map<Object, Object>) target;\n\t\t\t\ttarget = parent.get(key);\n\t\t\t}\n\t\t\tif (target instanceof Map) {\n\t\t\t\tparent.put(keys[keys.length - 1], select((Map<String, Object>) target, filter));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tparent.put(keys[keys.length - 1], select((List<Object>) target, filter));\n\t\t\t}\n\t\t\treturn jsonMapper.writeValueAsBytes(payload);\n\t\t});\n\t}\n\n\tprotected FieldDescriptor parentIdField() {\n\t\treturn fieldWithPath(\"contexts.*.parentId\").description(\"Id of the parent application context, if any.\")\n\t\t\t.optional()\n\t\t\t.type(JsonFieldType.STRING);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> Map<String, Object> select(Map<String, Object> candidates, Predicate<T> filter) {\n\t\tMap<String, Object> selected = new HashMap<>();\n\t\tcandidates.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((candidate) -> filter.test((T) candidate))\n\t\t\t.limit(3)\n\t\t\t.forEach((entry) -> selected.put(entry.getKey(), entry.getValue()));\n\t\treturn selected;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> List<Object> select(List<Object> candidates, Predicate<T> filter) {\n\t\treturn candidates.stream().filter((candidate) -> filter.test((T) candidate)).limit(3).toList();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tWebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\tWebEndpointAutoConfiguration.class, WebMvcEndpointManagementContextConfiguration.class,\n\t\t\tWebFluxEndpointManagementContextConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\tWebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class,\n\t\t\tJacksonEndpointAutoConfiguration.class })\n\tstatic class BaseDocumentationConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor endpointJsonMapperBeanPostProcessor() {\n\t\t\treturn new BeanPostProcessor() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\t\t\tif (bean instanceof EndpointJsonMapper) {\n\t\t\t\t\t\treturn (EndpointJsonMapper) () -> ((EndpointJsonMapper) bean).get()\n\t\t\t\t\t\t\t.rebuild()\n\t\t\t\t\t\t\t.enable(SerializationFeature.INDENT_OUTPUT)\n\t\t\t\t\t\t\t.build();\n\t\t\t\t\t}\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/MockMvcEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.restdocs.RestDocumentationContextProvider;\nimport org.springframework.restdocs.RestDocumentationExtension;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Abstract base class for tests that generate endpoint documentation using Spring REST\n * Docs and {@link MockMvcTester}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(RestDocumentationExtension.class)\n@SpringBootTest\npublic abstract class MockMvcEndpointDocumentationTests extends AbstractEndpointDocumentationTests {\n\n\tprotected MockMvcTester mvc;\n\n\t@Autowired\n\tprivate WebApplicationContext applicationContext;\n\n\t@BeforeEach\n\tvoid setup(RestDocumentationContextProvider restDocumentation) {\n\t\tthis.mvc = MockMvcTester.from(this.applicationContext,\n\t\t\t\t(builder) -> builder\n\t\t\t\t\t.apply(MockMvcRestDocumentation.documentationConfiguration(restDocumentation).uris())\n\t\t\t\t\t.build());\n\t}\n\n\tprotected WebApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/audit/AuditEventsEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.audit;\n\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.AuditEventRepository;\nimport org.springframework.boot.actuate.audit.AuditEventsEndpoint;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;\nimport static org.springframework.restdocs.request.RequestDocumentation.queryParameters;\n\n/**\n * Tests for generating documentation describing {@link AuditEventsEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass AuditEventsEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@MockitoBean\n\tprivate AuditEventRepository repository;\n\n\t@Test\n\tvoid allAuditEvents() {\n\t\tString queryTimestamp = \"2017-11-07T09:37Z\";\n\t\tgiven(this.repository.find(any(), any(), any()))\n\t\t\t.willReturn(List.of(new AuditEvent(\"alice\", \"logout\", Collections.emptyMap())));\n\t\tassertThat(this.mvc.get().uri(\"/actuator/auditevents\").param(\"after\", queryTimestamp)).hasStatusOk()\n\t\t\t.apply(document(\"auditevents/all\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"events\").description(\"An array of audit events.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"events.[].timestamp\")\n\t\t\t\t\t\t\t\t.description(\"The timestamp of when the event occurred.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"events.[].principal\").description(\"The principal that triggered the event.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"events.[].type\").description(\"The type of the event.\"))));\n\t}\n\n\t@Test\n\tvoid filteredAuditEvents() {\n\t\tString queryTimestamp = \"2017-11-07T09:37Z\";\n\t\tInstant instant = Instant.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(queryTimestamp));\n\t\tgiven(this.repository.find(\"alice\", instant, \"logout\"))\n\t\t\t.willReturn(List.of(new AuditEvent(instant.plusSeconds(73), \"alice\", \"logout\", Collections.emptyMap())));\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/actuator/auditevents\")\n\t\t\t.param(\"principal\", \"alice\")\n\t\t\t.param(\"after\", queryTimestamp)\n\t\t\t.param(\"type\", \"logout\"))\n\t\t\t.hasStatusOk()\n\t\t\t.apply(document(\"auditevents/filtered\",\n\t\t\t\t\tqueryParameters(\n\t\t\t\t\t\t\tparameterWithName(\"after\").description(\n\t\t\t\t\t\t\t\t\t\"Restricts the events to those that occurred after the given time. Optional.\"),\n\t\t\t\t\t\t\tparameterWithName(\"principal\")\n\t\t\t\t\t\t\t\t.description(\"Restricts the events to those with the given principal. Optional.\"),\n\t\t\t\t\t\t\tparameterWithName(\"type\")\n\t\t\t\t\t\t\t\t.description(\"Restricts the events to those with the given type. Optional.\"))));\n\t\tthen(this.repository).should().find(\"alice\", instant, \"logout\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tAuditEventsEndpoint auditEventsEndpoint(AuditEventRepository repository) {\n\t\t\treturn new AuditEventsEndpoint(repository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/beans/BeansEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.beans;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.beans.BeansEndpoint;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.restdocs.payload.ResponseFieldsSnippet;\nimport org.springframework.util.CollectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing {@link BeansEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass BeansEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid beans() {\n\t\tList<FieldDescriptor> beanFields = List.of(fieldWithPath(\"aliases\").description(\"Names of any aliases.\"),\n\t\t\t\tfieldWithPath(\"scope\").description(\"Scope of the bean.\"),\n\t\t\t\tfieldWithPath(\"type\").description(\"Fully qualified type of the bean.\"),\n\t\t\t\tfieldWithPath(\"resource\").description(\"Resource in which the bean was defined, if any.\")\n\t\t\t\t\t.optional()\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"dependencies\").description(\"Names of any dependencies.\"));\n\t\tResponseFieldsSnippet responseFields = responseFields(\n\t\t\t\tfieldWithPath(\"contexts\").description(\"Application contexts keyed by id.\"), parentIdField(),\n\t\t\t\tfieldWithPath(\"contexts.*.beans\").description(\"Beans in the application context keyed by name.\"))\n\t\t\t.andWithPrefix(\"contexts.*.beans.*.\", beanFields);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/beans\")).hasStatusOk()\n\t\t\t.apply(document(\"beans\",\n\t\t\t\t\tpreprocessResponse(\n\t\t\t\t\t\t\tlimit(this::isIndependentBean, \"contexts\", getApplicationContext().getId(), \"beans\")),\n\t\t\t\t\tresponseFields));\n\t}\n\n\tprivate boolean isIndependentBean(Entry<String, Map<String, Object>> bean) {\n\t\treturn CollectionUtils.isEmpty((Collection<?>) bean.getValue().get(\"aliases\"))\n\t\t\t\t&& CollectionUtils.isEmpty((Collection<?>) bean.getValue().get(\"dependencies\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tBeansEndpoint beansEndpoint(ConfigurableApplicationContext context) {\n\t\t\treturn new BeansEndpoint(context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/cache/CachesEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.cache;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpointWebExtension;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.request.ParameterDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;\nimport static org.springframework.restdocs.request.RequestDocumentation.queryParameters;\n\n/**\n * Tests for generating documentation describing the {@link CachesEndpoint}\n *\n * @author Stephane Nicoll\n */\nclass CachesEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\tprivate static final List<FieldDescriptor> levelFields = List.of(fieldWithPath(\"name\").description(\"Cache name.\"),\n\t\t\tfieldWithPath(\"cacheManager\").description(\"Cache manager name.\"),\n\t\t\tfieldWithPath(\"target\").description(\"Fully qualified name of the native cache.\"));\n\n\tprivate static final List<ParameterDescriptor> queryParameters = Collections\n\t\t.singletonList(parameterWithName(\"cacheManager\")\n\t\t\t.description(\"Name of the cacheManager to qualify the cache. May be omitted if the cache name is unique.\")\n\t\t\t.optional());\n\n\t@Test\n\tvoid allCaches() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/caches\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"caches/all\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"cacheManagers\").description(\"Cache managers keyed by id.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"cacheManagers.*.caches\")\n\t\t\t\t\t\t\t\t.description(\"Caches in the application context keyed by name.\"))\n\t\t\t\t\t\t.andWithPrefix(\"cacheManagers.*.caches.*.\",\n\t\t\t\t\t\t\t\tfieldWithPath(\"target\").description(\"Fully qualified name of the native cache.\"))));\n\t}\n\n\t@Test\n\tvoid namedCache() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/caches/cities\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"caches/named\", queryParameters(queryParameters),\n\t\t\t\t\tresponseFields(levelFields)));\n\t}\n\n\t@Test\n\tvoid evictAllCaches() {\n\t\tassertThat(this.mvc.delete().uri(\"/actuator/caches\")).hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"caches/evict-all\"));\n\t}\n\n\t@Test\n\tvoid evictNamedCache() {\n\t\tassertThat(this.mvc.delete().uri(\"/actuator/caches/countries?cacheManager=anotherCacheManager\"))\n\t\t\t.hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"caches/evict-named\", queryParameters(queryParameters)));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tCachesEndpoint endpoint() {\n\t\t\tMap<String, CacheManager> cacheManagers = new HashMap<>();\n\t\t\tcacheManagers.put(\"cacheManager\", new ConcurrentMapCacheManager(\"countries\", \"cities\"));\n\t\t\tcacheManagers.put(\"anotherCacheManager\", new ConcurrentMapCacheManager(\"countries\"));\n\t\t\treturn new CachesEndpoint(cacheManagers);\n\t\t}\n\n\t\t@Bean\n\t\tCachesEndpointWebExtension endpointWebExtension(CachesEndpoint endpoint) {\n\t\t\treturn new CachesEndpointWebExtension(endpoint);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/condition/ConditionsReportEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.condition;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpoint;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing {@link ConditionsReportEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass ConditionsReportEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid conditions() {\n\t\tList<FieldDescriptor> positiveMatchFields = List.of(\n\t\t\t\tfieldWithPath(\"\").description(\"Classes and methods with conditions that were matched.\"),\n\t\t\t\tfieldWithPath(\".*.[].condition\").description(\"Name of the condition.\"),\n\t\t\t\tfieldWithPath(\".*.[].message\").description(\"Details of why the condition was matched.\"));\n\t\tList<FieldDescriptor> negativeMatchFields = List.of(\n\t\t\t\tfieldWithPath(\"\").description(\"Classes and methods with conditions that were not matched.\"),\n\t\t\t\tfieldWithPath(\".*.notMatched\").description(\"Conditions that were matched.\"),\n\t\t\t\tfieldWithPath(\".*.notMatched.[].condition\").description(\"Name of the condition.\"),\n\t\t\t\tfieldWithPath(\".*.notMatched.[].message\").description(\"Details of why the condition was not matched.\"),\n\t\t\t\tfieldWithPath(\".*.matched\").description(\"Conditions that were matched.\"),\n\t\t\t\tfieldWithPath(\".*.matched.[].condition\").description(\"Name of the condition.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\".*.matched.[].message\").description(\"Details of why the condition was matched.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional());\n\t\tFieldDescriptor unconditionalClassesField = fieldWithPath(\"contexts.*.unconditionalClasses\")\n\t\t\t.description(\"Names of unconditional auto-configuration classes if any.\");\n\t\tassertThat(this.mvc.get().uri(\"/actuator/conditions\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"conditions\",\n\t\t\t\t\tpreprocessResponse(limit(\"contexts\", getApplicationContext().getId(), \"positiveMatches\"),\n\t\t\t\t\t\t\tlimit(\"contexts\", getApplicationContext().getId(), \"negativeMatches\")),\n\t\t\t\t\tresponseFields(fieldWithPath(\"contexts\").description(\"Application contexts keyed by id.\"))\n\t\t\t\t\t\t.andWithPrefix(\"contexts.*.positiveMatches\", positiveMatchFields)\n\t\t\t\t\t\t.andWithPrefix(\"contexts.*.negativeMatches\", negativeMatchFields)\n\t\t\t\t\t\t.and(unconditionalClassesField, parentIdField())));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tConditionsReportEndpoint autoConfigurationReportEndpoint(ConfigurableApplicationContext context) {\n\t\t\tConditionEvaluationReport conditionEvaluationReport = ConditionEvaluationReport\n\t\t\t\t.get(context.getBeanFactory());\n\t\t\tconditionEvaluationReport\n\t\t\t\t.recordEvaluationCandidates(List.of(PropertyPlaceholderAutoConfiguration.class.getName()));\n\t\t\treturn new ConditionsReportEndpoint(context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/context/ShutdownEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.ShutdownEndpoint;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link ShutdownEndpoint}.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = \"management.endpoint.shutdown.access=unrestricted\")\nclass ShutdownEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid shutdown() {\n\t\tassertThat(this.mvc.post().uri(\"/actuator/shutdown\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"shutdown\", responseFields(\n\t\t\t\t\tfieldWithPath(\"message\").description(\"Message describing the result of the request.\"))));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tShutdownEndpoint endpoint() {\n\t\t\tShutdownEndpoint endpoint = new ShutdownEndpoint();\n\t\t\tendpoint.setApplicationContext(new AnnotationConfigApplicationContext());\n\t\t\treturn endpoint;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/context/properties/ConfigurationPropertiesReportEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.context.properties;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;\n\n/**\n * Tests for generating documentation describing\n * {@link ConfigurationPropertiesReportEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Chris Bono\n */\nclass ConfigurationPropertiesReportEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid configProps() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/configprops\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"configprops/all\",\n\t\t\t\t\tpreprocessResponse(limit(\"contexts\", getApplicationContext().getId(), \"beans\")),\n\t\t\t\t\tresponseFields(fieldWithPath(\"contexts\").description(\"Application contexts keyed by id.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"contexts.*.beans.*\")\n\t\t\t\t\t\t\t\t.description(\"`@ConfigurationProperties` beans keyed by bean name.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"contexts.*.beans.*.prefix\")\n\t\t\t\t\t\t\t\t.description(\"Prefix applied to the names of the bean's properties.\"),\n\t\t\t\t\t\t\tsubsectionWithPath(\"contexts.*.beans.*.properties\")\n\t\t\t\t\t\t\t\t.description(\"Properties of the bean as name-value pairs.\"),\n\t\t\t\t\t\t\tsubsectionWithPath(\"contexts.*.beans.*.inputs\").description(\n\t\t\t\t\t\t\t\t\t\"Origin and value of the configuration property used when binding to this bean.\"),\n\t\t\t\t\t\t\tparentIdField())));\n\t}\n\n\t@Test\n\tvoid configPropsFilterByPrefix() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/configprops/spring.jackson\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"configprops/prefixed\",\n\t\t\t\t\tpreprocessResponse(limit(\"contexts\", getApplicationContext().getId(), \"beans\")),\n\t\t\t\t\tresponseFields(fieldWithPath(\"contexts\").description(\"Application contexts keyed by id.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"contexts.*.beans.*\")\n\t\t\t\t\t\t\t\t.description(\"`@ConfigurationProperties` beans keyed by bean name.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"contexts.*.beans.*.prefix\")\n\t\t\t\t\t\t\t\t.description(\"Prefix applied to the names of the bean's properties.\"),\n\t\t\t\t\t\t\tsubsectionWithPath(\"contexts.*.beans.*.properties\")\n\t\t\t\t\t\t\t\t.description(\"Properties of the bean as name-value pairs.\"),\n\t\t\t\t\t\t\tsubsectionWithPath(\"contexts.*.beans.*.inputs\").description(\n\t\t\t\t\t\t\t\t\t\"Origin and value of the configuration property used when binding to this bean.\"),\n\t\t\t\t\t\t\tparentIdField())));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/env/EnvironmentEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.env;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.AbstractEnvironment;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;\nimport org.springframework.restdocs.operation.preprocess.OperationPreprocessor;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link EnvironmentEndpoint}.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = \"spring.config.location=classpath:/org/springframework/boot/actuate/docs/env/\")\nclass EnvironmentEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\tprivate static final FieldDescriptor activeProfiles = fieldWithPath(\"activeProfiles\")\n\t\t.description(\"Names of the active profiles, if any.\");\n\n\tprivate static final FieldDescriptor defaultProfiles = fieldWithPath(\"defaultProfiles\")\n\t\t.description(\"Names of the default profiles, if any.\");\n\n\tprivate static final FieldDescriptor propertySources = fieldWithPath(\"propertySources\")\n\t\t.description(\"Property sources in order of precedence.\");\n\n\tprivate static final FieldDescriptor propertySourceName = fieldWithPath(\"propertySources.[].name\")\n\t\t.description(\"Name of the property source.\");\n\n\t@Test\n\tvoid env() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/env\")).hasStatusOk()\n\t\t\t.apply(document(\"env/all\",\n\t\t\t\t\tpreprocessResponse(\n\t\t\t\t\t\t\treplacePattern(Pattern.compile(\n\t\t\t\t\t\t\t\t\t\"org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/\"), \"\"),\n\t\t\t\t\t\t\tfilterProperties()),\n\t\t\t\t\tresponseFields(activeProfiles, defaultProfiles, propertySources, propertySourceName,\n\t\t\t\t\t\t\tfieldWithPath(\"propertySources.[].properties\")\n\t\t\t\t\t\t\t\t.description(\"Properties in the property source keyed by property name.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"propertySources.[].properties.*.value\")\n\t\t\t\t\t\t\t\t.description(\"Value of the property.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"propertySources.[].properties.*.origin\")\n\t\t\t\t\t\t\t\t.description(\"Origin of the property, if any.\")\n\t\t\t\t\t\t\t\t.optional())));\n\t}\n\n\t@Test\n\tvoid singlePropertyFromEnv() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/env/com.example.cache.max-size\")).hasStatusOk()\n\t\t\t.apply(document(\"env/single\",\n\t\t\t\t\tpreprocessResponse(replacePattern(Pattern\n\t\t\t\t\t\t.compile(\"org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/\"), \"\")),\n\t\t\t\t\tresponseFields(\n\t\t\t\t\t\t\tfieldWithPath(\"property\").description(\"Property from the environment, if found.\")\n\t\t\t\t\t\t\t\t.optional(),\n\t\t\t\t\t\t\tfieldWithPath(\"property.source\").description(\"Name of the source of the property.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"property.value\").description(\"Value of the property.\"), activeProfiles,\n\t\t\t\t\t\t\tdefaultProfiles, propertySources, propertySourceName,\n\t\t\t\t\t\t\tfieldWithPath(\"propertySources.[].property\")\n\t\t\t\t\t\t\t\t.description(\"Property in the property source, if any.\")\n\t\t\t\t\t\t\t\t.optional(),\n\t\t\t\t\t\t\tfieldWithPath(\"propertySources.[].property.value\").description(\"Value of the property.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"propertySources.[].property.origin\")\n\t\t\t\t\t\t\t\t.description(\"Origin of the property, if any.\")\n\t\t\t\t\t\t\t\t.optional())));\n\t}\n\n\tprivate OperationPreprocessor filterProperties() {\n\t\treturn new ContentModifyingOperationPreprocessor(this::filterProperties);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate byte[] filterProperties(byte[] content, MediaType mediaType) {\n\t\tJsonMapper jsonMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();\n\t\tMap<String, Object> payload = jsonMapper.readValue(content, Map.class);\n\t\tList<Map<String, Object>> propertySources = (List<Map<String, Object>>) payload.get(\"propertySources\");\n\t\tfor (Map<String, Object> propertySource : propertySources) {\n\t\t\tMap<String, String> properties = (Map<String, String>) propertySource.get(\"properties\");\n\t\t\tSet<String> filteredKeys = properties.keySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter(this::retainKey)\n\t\t\t\t.limit(3)\n\t\t\t\t.collect(Collectors.toSet());\n\t\t\tproperties.keySet().retainAll(filteredKeys);\n\t\t}\n\t\treturn jsonMapper.writeValueAsBytes(payload);\n\t}\n\n\tprivate boolean retainKey(String key) {\n\t\treturn key.startsWith(\"java.\") || key.equals(\"JAVA_HOME\") || key.startsWith(\"com.example.\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tEnvironmentEndpoint endpoint(ConfigurableEnvironment environment) {\n\t\t\treturn new EnvironmentEndpoint(new AbstractEnvironment() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void customizePropertySources(MutablePropertySources propertySources) {\n\t\t\t\t\tenvironment.getPropertySources()\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.filter(this::includedPropertySource)\n\t\t\t\t\t\t.forEach(propertySources::addLast);\n\t\t\t\t}\n\n\t\t\t\tprivate boolean includedPropertySource(PropertySource<?> propertySource) {\n\t\t\t\t\treturn propertySource instanceof EnumerablePropertySource\n\t\t\t\t\t\t\t&& !\"Inlined Test Properties\".equals(propertySource.getName());\n\t\t\t\t}\n\n\t\t\t}, Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/flyway/FlywayEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.flyway;\n\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.flywaydb.core.api.MigrationState;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.flyway.actuate.endpoint.FlywayEndpoint;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link FlywayEndpoint}.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = \"spring.flyway.locations=classpath:org/springframework/boot/actuate/docs/flyway\")\nclass FlywayEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid flyway() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/flyway\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"flyway\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"contexts\").description(\"Application contexts keyed by id\"),\n\t\t\t\t\t\t\tfieldWithPath(\"contexts.*.flywayBeans.*.migrations\")\n\t\t\t\t\t\t\t\t.description(\"Migrations performed by the Flyway instance, keyed by Flyway bean name.\"))\n\t\t\t\t\t\t.andWithPrefix(\"contexts.*.flywayBeans.*.migrations.[].\", migrationFieldDescriptors())\n\t\t\t\t\t\t.and(parentIdField())));\n\t}\n\n\tprivate List<FieldDescriptor> migrationFieldDescriptors() {\n\t\treturn List.of(fieldWithPath(\"checksum\").description(\"Checksum of the migration, if any.\").optional(),\n\t\t\t\tfieldWithPath(\"description\").description(\"Description of the migration, if any.\").optional(),\n\t\t\t\tfieldWithPath(\"executionTime\").description(\"Execution time in milliseconds of an applied migration.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"installedBy\").description(\"User that installed the applied migration, if any.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"installedOn\")\n\t\t\t\t\t.description(\"Timestamp of when the applied migration was installed, if any.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"installedRank\")\n\t\t\t\t\t.description(\"Rank of the applied migration, if any. Later migrations have higher ranks.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"script\").description(\"Name of the script used to execute the migration, if any.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"state\")\n\t\t\t\t\t.description(\"State of the migration. (\" + describeEnumValues(MigrationState.class) + \")\"),\n\t\t\t\tfieldWithPath(\"type\").description(\"Type of the migration.\"),\n\t\t\t\tfieldWithPath(\"version\").description(\"Version of the database after applying the migration, if any.\")\n\t\t\t\t\t.optional());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(FlywayAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true)\n\t\t\t\t.setType(EmbeddedDatabaseConnection.get(getClass().getClassLoader()).getType())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tFlywayEndpoint endpoint(ApplicationContext context) {\n\t\t\treturn new FlywayEndpoint(context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/health/HealthEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.health;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.boot.health.application.DiskSpaceHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorNameGenerator;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.health.DataSourceHealthIndicator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;\n\n/**\n * Tests for generating documentation describing the {@link HealthEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass HealthEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\tprivate static final List<FieldDescriptor> componentFields = List.of(\n\t\t\tfieldWithPath(\"status\").description(\"Status of a specific part of the application\"),\n\t\t\tsubsectionWithPath(\"details\").description(\"Details of the health of a specific part of the application.\"));\n\n\t@Test\n\tvoid health() {\n\t\tFieldDescriptor status = fieldWithPath(\"status\").description(\"Overall status of the application.\");\n\t\tFieldDescriptor components = fieldWithPath(\"components\").description(\"The components that make up the health.\");\n\t\tFieldDescriptor componentStatus = fieldWithPath(\"components.*.status\")\n\t\t\t.description(\"Status of a specific part of the application.\");\n\t\tFieldDescriptor nestedComponents = subsectionWithPath(\"components.*.components\")\n\t\t\t.description(\"The nested components that make up the health.\")\n\t\t\t.optional();\n\t\tFieldDescriptor componentDetails = subsectionWithPath(\"components.*.details\")\n\t\t\t.description(\"Details of the health of a specific part of the application. \"\n\t\t\t\t\t+ \"Presence is controlled by `management.endpoint.health.show-details`.\")\n\t\t\t.optional();\n\t\tassertThat(this.mvc.get().uri(\"/actuator/health\").accept(MediaType.APPLICATION_JSON)).hasStatusOk()\n\t\t\t.apply(document(\"health\",\n\t\t\t\t\tresponseFields(status, components, componentStatus, nestedComponents, componentDetails)));\n\t}\n\n\t@Test\n\tvoid healthComponent() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/health/db\").accept(MediaType.APPLICATION_JSON)).hasStatusOk()\n\t\t\t.apply(document(\"health/component\", responseFields(componentFields)));\n\t}\n\n\t@Test\n\tvoid healthComponentInstance() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/health/broker/us1\").accept(MediaType.APPLICATION_JSON)).hasStatusOk()\n\t\t\t.apply(document(\"health/instance\", responseFields(componentFields)));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tHealthEndpoint healthEndpoint(Map<String, HealthContributor> contributors) {\n\t\t\tHealthContributorRegistry registry = new DefaultHealthContributorRegistry(null,\n\t\t\t\t\tHealthContributorNameGenerator.withoutStandardSuffixes().registrar(contributors));\n\t\t\tHealthEndpointGroup primary = new TestHealthEndpointGroup();\n\t\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(primary, Collections.emptyMap());\n\t\t\treturn new HealthEndpoint(registry, null, groups, null);\n\t\t}\n\n\t\t@Bean\n\t\tDiskSpaceHealthIndicator diskSpaceHealthIndicator() {\n\t\t\treturn new DiskSpaceHealthIndicator(new File(\".\"), DataSize.ofMegabytes(10));\n\t\t}\n\n\t\t@Bean\n\t\tDataSourceHealthIndicator dbHealthIndicator(DataSource dataSource) {\n\t\t\treturn new DataSourceHealthIndicator(dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tCompositeHealthContributor brokerHealthContributor() {\n\t\t\tMap<String, HealthIndicator> indicators = new LinkedHashMap<>();\n\t\t\tindicators.put(\"us1\", () -> Health.up().withDetail(\"version\", \"1.0.2\").build());\n\t\t\tindicators.put(\"us2\", () -> Health.up().withDetail(\"version\", \"1.0.4\").build());\n\t\t\treturn CompositeHealthContributor.fromMap(indicators);\n\t\t}\n\n\t}\n\n\tprivate static final class TestHealthEndpointGroup implements HealthEndpointGroup {\n\n\t\tprivate final StatusAggregator statusAggregator = StatusAggregator.getDefault();\n\n\t\tprivate final HttpCodeStatusMapper httpCodeStatusMapper = HttpCodeStatusMapper.getDefault();\n\n\t\t@Override\n\t\tpublic boolean isMember(String name) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean showComponents(SecurityContext securityContext) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean showDetails(SecurityContext securityContext) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic StatusAggregator getStatusAggregator() {\n\t\t\treturn this.statusAggregator;\n\t\t}\n\n\t\t@Override\n\t\tpublic HttpCodeStatusMapper getHttpCodeStatusMapper() {\n\t\t\treturn this.httpCodeStatusMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic AdditionalHealthEndpointPath getAdditionalPath() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/info/InfoEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.info;\n\nimport java.time.Instant;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.info.BuildInfoContributor;\nimport org.springframework.boot.actuate.info.GitInfoContributor;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.boot.actuate.info.InfoEndpoint;\nimport org.springframework.boot.actuate.info.JavaInfoContributor;\nimport org.springframework.boot.actuate.info.OsInfoContributor;\nimport org.springframework.boot.actuate.info.ProcessInfoContributor;\nimport org.springframework.boot.actuate.info.SslInfoContributor;\nimport org.springframework.boot.info.BuildProperties;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.restdocs.payload.ResponseFieldsSnippet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link InfoEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass InfoEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid info() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/info\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"info\", gitInfo(), buildInfo(), osInfo(), processInfo(),\n\t\t\t\t\tjavaInfo(), sslInfo()));\n\t}\n\n\tprivate ResponseFieldsSnippet gitInfo() {\n\t\treturn responseFields(beneathPath(\"git\"),\n\t\t\t\tfieldWithPath(\"branch\").description(\"Name of the Git branch, if any.\"),\n\t\t\t\tfieldWithPath(\"commit\").description(\"Details of the Git commit, if any.\"),\n\t\t\t\tfieldWithPath(\"commit.time\").description(\"Timestamp of the commit, if any.\").type(JsonFieldType.VARIES),\n\t\t\t\tfieldWithPath(\"commit.id\").description(\"ID of the commit, if any.\"));\n\t}\n\n\tprivate ResponseFieldsSnippet buildInfo() {\n\t\treturn responseFields(beneathPath(\"build\"),\n\t\t\t\tfieldWithPath(\"artifact\").description(\"Artifact ID of the application, if any.\").optional(),\n\t\t\t\tfieldWithPath(\"group\").description(\"Group ID of the application, if any.\").optional(),\n\t\t\t\tfieldWithPath(\"name\").description(\"Name of the application, if any.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"version\").description(\"Version of the application, if any.\").optional(),\n\t\t\t\tfieldWithPath(\"time\").description(\"Timestamp of when the application was built, if any.\")\n\t\t\t\t\t.type(JsonFieldType.VARIES)\n\t\t\t\t\t.optional());\n\t}\n\n\tprivate ResponseFieldsSnippet osInfo() {\n\t\treturn responseFields(beneathPath(\"os\"), osInfoField(\"name\", \"Name of the operating system\"),\n\t\t\t\tosInfoField(\"version\", \"Version of the operating system\"),\n\t\t\t\tosInfoField(\"arch\", \"Architecture of the operating system\"));\n\t}\n\n\tprivate FieldDescriptor osInfoField(String field, String desc) {\n\t\treturn fieldWithPath(field).description(desc + \" (as obtained from the 'os.\" + field + \"' system property).\")\n\t\t\t.type(JsonFieldType.STRING)\n\t\t\t.optional();\n\t}\n\n\tprivate ResponseFieldsSnippet processInfo() {\n\t\treturn responseFields(beneathPath(\"process\"),\n\t\t\t\tfieldWithPath(\"pid\").description(\"Process ID.\").type(JsonFieldType.NUMBER),\n\t\t\t\tfieldWithPath(\"parentPid\").description(\"Parent Process ID (or -1).\").type(JsonFieldType.NUMBER),\n\t\t\t\tfieldWithPath(\"owner\").description(\"Process owner.\").type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"uptime\").description(\"Process uptime, if available.\")\n\t\t\t\t\t.optional()\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"startTime\").description(\"Process start time, if availabe.\")\n\t\t\t\t\t.optional()\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"currentTime\").description(\"Current time known by the process.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"timezone\").description(\"Process timezone.\").type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"locale\").description(\"Process locale.\").type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"workingDirectory\").description(\"Working directory of the process.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"cpus\").description(\"Number of CPUs available to the process.\")\n\t\t\t\t\t.type(JsonFieldType.NUMBER),\n\t\t\t\tfieldWithPath(\"memory\").description(\"Memory information.\"),\n\t\t\t\tfieldWithPath(\"memory.heap\").description(\"Heap memory.\"),\n\t\t\t\tfieldWithPath(\"memory.heap.init\").description(\"Number of bytes initially requested by the JVM.\"),\n\t\t\t\tfieldWithPath(\"memory.heap.used\").description(\"Number of bytes currently being used.\"),\n\t\t\t\tfieldWithPath(\"memory.heap.committed\").description(\"Number of bytes committed for JVM use.\"),\n\t\t\t\tfieldWithPath(\"memory.heap.max\")\n\t\t\t\t\t.description(\"Maximum number of bytes that can be used by the JVM (or -1).\"),\n\t\t\t\tfieldWithPath(\"memory.nonHeap\").description(\"Non-heap memory.\"),\n\t\t\t\tfieldWithPath(\"memory.nonHeap.init\").description(\"Number of bytes initially requested by the JVM.\"),\n\t\t\t\tfieldWithPath(\"memory.nonHeap.used\").description(\"Number of bytes currently being used.\"),\n\t\t\t\tfieldWithPath(\"memory.nonHeap.committed\").description(\"Number of bytes committed for JVM use.\"),\n\t\t\t\tfieldWithPath(\"memory.nonHeap.max\")\n\t\t\t\t\t.description(\"Maximum number of bytes that can be used by the JVM (or -1).\"),\n\t\t\t\tfieldWithPath(\"memory.garbageCollectors\").description(\"Details for garbage collectors.\"),\n\t\t\t\tfieldWithPath(\"memory.garbageCollectors[].name\").description(\"Name of of the garbage collector.\"),\n\t\t\t\tfieldWithPath(\"memory.garbageCollectors[].collectionCount\")\n\t\t\t\t\t.description(\"Total number of collections that have occurred.\"),\n\t\t\t\tfieldWithPath(\"virtualThreads\")\n\t\t\t\t\t.description(\"Virtual thread information (if VirtualThreadSchedulerMXBean is available)\")\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"virtualThreads.mounted\")\n\t\t\t\t\t.description(\"Estimate of the number of virtual threads currently mounted by the scheduler.\")\n\t\t\t\t\t.type(JsonFieldType.NUMBER)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"virtualThreads.queued\").description(\n\t\t\t\t\t\t\"Estimate of the number of virtual threads queued to the scheduler to start or continue execution.\")\n\t\t\t\t\t.type(JsonFieldType.NUMBER)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"virtualThreads.parallelism\").description(\"Scheduler's target parallelism.\")\n\t\t\t\t\t.type(JsonFieldType.NUMBER)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"virtualThreads.poolSize\")\n\t\t\t\t\t.description(\n\t\t\t\t\t\t\t\"Current number of platform threads that the scheduler has started but have not terminated\")\n\t\t\t\t\t.type(JsonFieldType.NUMBER)\n\t\t\t\t\t.optional());\n\t}\n\n\tprivate ResponseFieldsSnippet javaInfo() {\n\t\treturn responseFields(beneathPath(\"java\"),\n\t\t\t\tfieldWithPath(\"version\").description(\"Java version, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"vendor\").description(\"Vendor details.\"),\n\t\t\t\tfieldWithPath(\"vendor.name\").description(\"Vendor name, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"vendor.version\").description(\"Vendor version, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"runtime\").description(\"Runtime details.\"),\n\t\t\t\tfieldWithPath(\"runtime.name\").description(\"Runtime name, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"runtime.version\").description(\"Runtime version, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"jvm\").description(\"JVM details.\"),\n\t\t\t\tfieldWithPath(\"jvm.name\").description(\"JVM name, if available.\").type(JsonFieldType.STRING).optional(),\n\t\t\t\tfieldWithPath(\"jvm.vendor\").description(\"JVM vendor, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"jvm.version\").description(\"JVM version, if available.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional());\n\t}\n\n\tprivate ResponseFieldsSnippet sslInfo() {\n\t\treturn responseFields(beneathPath(\"ssl\"),\n\t\t\t\tfieldWithPath(\"bundles\").description(\"SSL bundles information.\").type(JsonFieldType.ARRAY),\n\t\t\t\tfieldWithPath(\"bundles[].name\").description(\"Name of the SSL bundle.\").type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains\").description(\"Certificate chains in the bundle.\")\n\t\t\t\t\t.type(JsonFieldType.ARRAY),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].alias\").description(\"Alias of the certificate chain.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates\").description(\"Certificates in the chain.\")\n\t\t\t\t\t.type(JsonFieldType.ARRAY),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].subject\")\n\t\t\t\t\t.description(\"Subject of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].version\")\n\t\t\t\t\t.description(\"Version of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].issuer\")\n\t\t\t\t\t.description(\"Issuer of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].validityStarts\")\n\t\t\t\t\t.description(\"Certificate validity start date.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].serialNumber\")\n\t\t\t\t\t.description(\"Serial number of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].validityEnds\")\n\t\t\t\t\t.description(\"Certificate validity end date.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].validity\")\n\t\t\t\t\t.description(\"Certificate validity information.\")\n\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].validity.status\")\n\t\t\t\t\t.description(\"Certificate validity status.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].certificateChains[].certificates[].signatureAlgorithmName\")\n\t\t\t\t\t.description(\"Signature algorithm name.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains\")\n\t\t\t\t\t.description(\"Certificate chains in the trust store.\")\n\t\t\t\t\t.type(JsonFieldType.ARRAY),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].alias\")\n\t\t\t\t\t.description(\"Alias of the certificate chain.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates\")\n\t\t\t\t\t.description(\"Certificates in the chain.\")\n\t\t\t\t\t.type(JsonFieldType.ARRAY),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].subject\")\n\t\t\t\t\t.description(\"Subject of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].version\")\n\t\t\t\t\t.description(\"Version of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].issuer\")\n\t\t\t\t\t.description(\"Issuer of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].validityStarts\")\n\t\t\t\t\t.description(\"Certificate validity start date.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].serialNumber\")\n\t\t\t\t\t.description(\"Serial number of the certificate.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].validityEnds\")\n\t\t\t\t\t.description(\"Certificate validity end date.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].validity\")\n\t\t\t\t\t.description(\"Certificate validity information.\")\n\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].validity.status\")\n\t\t\t\t\t.description(\"Certificate validity status.\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"bundles[].trustStoreCertificateChains[].certificates[].signatureAlgorithmName\")\n\t\t\t\t\t.description(\"Signature algorithm name.\")\n\t\t\t\t\t.type(JsonFieldType.STRING));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tInfoEndpoint endpoint(List<InfoContributor> infoContributors) {\n\t\t\treturn new InfoEndpoint(infoContributors);\n\t\t}\n\n\t\t@Bean\n\t\tGitInfoContributor gitInfoContributor() {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(\"branch\", \"main\");\n\t\t\tproperties.put(\"commit.id\", \"df027cf1ec5aeba2d4fedd7b8c42b88dc5ce38e5\");\n\t\t\tproperties.put(\"commit.id.abbrev\", \"df027cf\");\n\t\t\tproperties.put(\"commit.time\", Long.toString(Instant.now().getEpochSecond()));\n\t\t\tGitProperties gitProperties = new GitProperties(properties);\n\t\t\treturn new GitInfoContributor(gitProperties);\n\t\t}\n\n\t\t@Bean\n\t\tBuildInfoContributor buildInfoContributor() {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(\"group\", \"com.example\");\n\t\t\tproperties.put(\"artifact\", \"application\");\n\t\t\tproperties.put(\"version\", \"1.0.3\");\n\t\t\tBuildProperties buildProperties = new BuildProperties(properties);\n\t\t\treturn new BuildInfoContributor(buildProperties);\n\t\t}\n\n\t\t@Bean\n\t\tOsInfoContributor osInfoContributor() {\n\t\t\treturn new OsInfoContributor();\n\t\t}\n\n\t\t@Bean\n\t\tProcessInfoContributor processInfoContributor() {\n\t\t\treturn new ProcessInfoContributor();\n\t\t}\n\n\t\t@Bean\n\t\tJavaInfoContributor javaInfoContributor() {\n\t\t\treturn new JavaInfoContributor();\n\t\t}\n\n\t\t@Bean\n\t\tSslInfo sslInfo() {\n\t\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\t\tJksSslStoreDetails storeDetails = JksSslStoreDetails.forLocation(\"classpath:test.p12\")\n\t\t\t\t.withPassword(\"secret\");\n\t\t\tSslStoreBundle sslStoreBundle = new JksSslStoreBundle(storeDetails, storeDetails);\n\t\t\tsslBundleRegistry.registerBundle(\"test-0\", SslBundle.of(sslStoreBundle));\n\t\t\treturn new SslInfo(sslBundleRegistry);\n\t\t}\n\n\t\t@Bean\n\t\tSslInfoContributor sslInfoContributor(SslInfo sslInfo) {\n\t\t\treturn new SslInfoContributor(sslInfo);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/integration/IntegrationGraphEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.integration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.integration.actuate.endpoint.IntegrationGraphEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.integration.config.EnableIntegration;\nimport org.springframework.integration.graph.IntegrationGraphServer;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for generating documentation describing the {@link IntegrationGraphEndpoint}.\n *\n * @author Tim Ysewyn\n */\nclass IntegrationGraphEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid graph() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/integrationgraph\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"integrationgraph/graph\"));\n\t}\n\n\t@Test\n\tvoid rebuild() {\n\t\tassertThat(this.mvc.post().uri(\"/actuator/integrationgraph\")).hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"integrationgraph/rebuild\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableIntegration\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tIntegrationGraphServer integrationGraphServer() {\n\t\t\treturn new IntegrationGraphServer();\n\t\t}\n\n\t\t@Bean\n\t\tIntegrationGraphEndpoint endpoint(IntegrationGraphServer integrationGraphServer) {\n\t\t\treturn new IntegrationGraphEndpoint(integrationGraphServer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/liquibase/LiquibaseEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.liquibase;\n\nimport java.util.List;\n\nimport liquibase.changelog.ChangeSet.ExecType;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.liquibase.actuate.endpoint.LiquibaseEndpoint;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link LiquibaseEndpoint}.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(\n\t\tproperties = \"spring.liquibase.change-log=classpath:org/springframework/boot/actuate/docs/liquibase/db.changelog-master.yaml\")\nclass LiquibaseEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid liquibase() {\n\t\tFieldDescriptor changeSetsField = fieldWithPath(\"contexts.*.liquibaseBeans.*.changeSets\")\n\t\t\t.description(\"Change sets made by the Liquibase beans, keyed by bean name.\");\n\t\tassertThat(this.mvc.get().uri(\"/actuator/liquibase\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"liquibase\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"contexts\").description(\"Application contexts keyed by id\"),\n\t\t\t\t\t\t\tchangeSetsField)\n\t\t\t\t\t\t.andWithPrefix(\"contexts.*.liquibaseBeans.*.changeSets[].\", getChangeSetFieldDescriptors())\n\t\t\t\t\t\t.and(parentIdField())));\n\t}\n\n\tprivate List<FieldDescriptor> getChangeSetFieldDescriptors() {\n\t\treturn List.of(fieldWithPath(\"author\").description(\"Author of the change set.\"),\n\t\t\t\tfieldWithPath(\"changeLog\").description(\"Change log that contains the change set.\"),\n\t\t\t\tfieldWithPath(\"comments\").description(\"Comments on the change set.\"),\n\t\t\t\tfieldWithPath(\"contexts\").description(\"Contexts of the change set.\"),\n\t\t\t\tfieldWithPath(\"dateExecuted\").description(\"Timestamp of when the change set was executed.\"),\n\t\t\t\tfieldWithPath(\"deploymentId\").description(\"ID of the deployment that ran the change set.\"),\n\t\t\t\tfieldWithPath(\"description\").description(\"Description of the change set.\"),\n\t\t\t\tfieldWithPath(\"execType\")\n\t\t\t\t\t.description(\"Execution type of the change set (\" + describeEnumValues(ExecType.class) + \").\"),\n\t\t\t\tfieldWithPath(\"id\").description(\"ID of the change set.\"),\n\t\t\t\tfieldWithPath(\"labels\").description(\"Labels associated with the change set.\"),\n\t\t\t\tfieldWithPath(\"checksum\").description(\"Checksum of the change set.\"),\n\t\t\t\tfieldWithPath(\"orderExecuted\").description(\"Order of the execution of the change set.\"),\n\t\t\t\tfieldWithPath(\"tag\").description(\"Tag associated with the change set, if any.\")\n\t\t\t\t\t.optional()\n\t\t\t\t\t.type(JsonFieldType.STRING));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ EmbeddedDataSourceConfiguration.class, LiquibaseAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tLiquibaseEndpoint endpoint(ApplicationContext context) {\n\t\t\treturn new LiquibaseEndpoint(context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/logging/LogFileWebEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.logging;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.logging.LogFileWebEndpoint;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for generating documentation describing the {@link LogFileWebEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass LogFileWebEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid logFile() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/logfile\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"logfile/entire\"));\n\t}\n\n\t@Test\n\tvoid logFileRange() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/logfile\").header(\"Range\", \"bytes=0-1023\"))\n\t\t\t.hasStatus(HttpStatus.PARTIAL_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"logfile/range\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tLogFileWebEndpoint endpoint() {\n\t\t\tMockEnvironment environment = new MockEnvironment();\n\t\t\tenvironment.setProperty(\"logging.file.name\",\n\t\t\t\t\t\"src/test/resources/org/springframework/boot/actuate/docs/logging/sample.log\");\n\t\t\treturn new LogFileWebEndpoint(LogFile.get(environment), null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/logging/LoggersEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.logging;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link LoggersEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass LoggersEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\tprivate static final List<FieldDescriptor> levelFields = List.of(\n\t\t\tfieldWithPath(\"configuredLevel\").description(\"Configured level of the logger, if any.\").optional(),\n\t\t\tfieldWithPath(\"effectiveLevel\").description(\"Effective level of the logger.\"));\n\n\tprivate static final List<FieldDescriptor> groupLevelFields = List\n\t\t.of(fieldWithPath(\"configuredLevel\").description(\"Configured level of the logger group, if any.\")\n\t\t\t.type(JsonFieldType.STRING)\n\t\t\t.optional(), fieldWithPath(\"members\").description(\"Loggers that are part of this group\"));\n\n\t@MockitoBean\n\tprivate LoggingSystem loggingSystem;\n\n\t@Autowired\n\tprivate LoggerGroups loggerGroups;\n\n\t@Test\n\tvoid allLoggers() {\n\t\tgiven(this.loggingSystem.getSupportedLogLevels()).willReturn(EnumSet.allOf(LogLevel.class));\n\t\tgiven(this.loggingSystem.getLoggerConfigurations())\n\t\t\t.willReturn(List.of(new LoggerConfiguration(\"ROOT\", LogLevel.INFO, LogLevel.INFO),\n\t\t\t\t\tnew LoggerConfiguration(\"com.example\", LogLevel.DEBUG, LogLevel.DEBUG)));\n\t\tassertThat(this.mvc.get().uri(\"/actuator/loggers\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"loggers/all\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"levels\").description(\"Levels support by the logging system.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"loggers\").description(\"Loggers keyed by name.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"groups\").description(\"Logger groups keyed by name\"))\n\t\t\t\t\t\t.andWithPrefix(\"loggers.*.\", levelFields)\n\t\t\t\t\t\t.andWithPrefix(\"groups.*.\", groupLevelFields)));\n\t}\n\n\t@Test\n\tvoid logger() {\n\t\tgiven(this.loggingSystem.getLoggerConfiguration(\"com.example\"))\n\t\t\t.willReturn(new LoggerConfiguration(\"com.example\", LogLevel.INFO, LogLevel.INFO));\n\t\tassertThat(this.mvc.get().uri(\"/actuator/loggers/com.example\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"loggers/single\", responseFields(levelFields)));\n\t}\n\n\t@Test\n\tvoid loggerGroups() {\n\t\tthis.loggerGroups.get(\"test\").configureLogLevel(LogLevel.INFO, (member, level) -> {\n\t\t});\n\t\tassertThat(this.mvc.get().uri(\"/actuator/loggers/test\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"loggers/group\", responseFields(groupLevelFields)));\n\t\tresetLogger();\n\t}\n\n\t@Test\n\tvoid setLogLevel() {\n\t\tassertThat(this.mvc.post()\n\t\t\t.uri(\"/actuator/loggers/com.example\")\n\t\t\t.content(\"{\\\"configuredLevel\\\":\\\"debug\\\"}\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON))\n\t\t\t.hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"loggers/set\",\n\t\t\t\t\trequestFields(fieldWithPath(\"configuredLevel\")\n\t\t\t\t\t\t.description(\"Level for the logger. May be omitted to clear the level.\")\n\t\t\t\t\t\t.optional())));\n\t\tthen(this.loggingSystem).should().setLogLevel(\"com.example\", LogLevel.DEBUG);\n\t}\n\n\t@Test\n\tvoid setLogLevelOfLoggerGroup() {\n\t\tassertThat(this.mvc.post()\n\t\t\t.uri(\"/actuator/loggers/test\")\n\t\t\t.content(\"{\\\"configuredLevel\\\":\\\"debug\\\"}\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON))\n\t\t\t.hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"loggers/setGroup\",\n\t\t\t\t\trequestFields(fieldWithPath(\"configuredLevel\")\n\t\t\t\t\t\t.description(\"Level for the logger group. May be omitted to clear the level of the loggers.\")\n\t\t\t\t\t\t.optional())));\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member1\", LogLevel.DEBUG);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member2\", LogLevel.DEBUG);\n\t\tresetLogger();\n\t}\n\n\tprivate void resetLogger() {\n\t\tthis.loggerGroups.get(\"test\").configureLogLevel(LogLevel.INFO, (a, b) -> {\n\t\t});\n\t}\n\n\t@Test\n\tvoid clearLogLevel() {\n\t\tassertThat(this.mvc.post()\n\t\t\t.uri(\"/actuator/loggers/com.example\")\n\t\t\t.content(\"{}\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)).hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(MockMvcRestDocumentation.document(\"loggers/clear\"));\n\t\tthen(this.loggingSystem).should().setLogLevel(\"com.example\", null);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tLoggersEndpoint endpoint(LoggingSystem loggingSystem, LoggerGroups groups) {\n\t\t\tgroups.putAll(getLoggerGroups());\n\t\t\tgroups.get(\"test\").configureLogLevel(LogLevel.INFO, (member, level) -> {\n\t\t\t});\n\t\t\treturn new LoggersEndpoint(loggingSystem, groups);\n\t\t}\n\n\t\tprivate Map<String, List<String>> getLoggerGroups() {\n\t\t\treturn Collections.singletonMap(\"test\", List.of(\"test.member1\", \"test.member2\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/management/HeapDumpWebEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.management;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.nio.file.Files;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.management.HeapDumpWebEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.cli.CliDocumentation;\nimport org.springframework.restdocs.cli.CurlRequestSnippet;\nimport org.springframework.restdocs.operation.Operation;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\n\n/**\n * Tests for generating documentation describing the {@link HeapDumpWebEndpoint}.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = \"management.endpoint.heapdump.access=unrestricted\")\nclass HeapDumpWebEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid heapDump() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/heapdump\")).hasStatusOk()\n\t\t\t.apply(document(\"heapdump\", new CurlRequestSnippet(CliDocumentation.multiLineFormat()) {\n\n\t\t\t\t@Override\n\t\t\t\tprotected Map<String, Object> createModel(Operation operation) {\n\t\t\t\t\tMap<String, Object> model = super.createModel(operation);\n\t\t\t\t\tmodel.put(\"options\", \"-O\");\n\t\t\t\t\treturn model;\n\t\t\t\t}\n\n\t\t\t}));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tHeapDumpWebEndpoint endpoint() {\n\t\t\treturn new HeapDumpWebEndpoint() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected HeapDumper createHeapDumper() {\n\t\t\t\t\treturn (live) -> {\n\t\t\t\t\t\tFile file = Files.createTempFile(\"heap-\", \".hprof\").toFile();\n\t\t\t\t\t\tFileCopyUtils.copy(\"<<binary content>>\", new FileWriter(file));\n\t\t\t\t\t\treturn file;\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/management/ThreadDumpEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.management;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.management.ThreadDumpEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.operation.preprocess.ContentModifyingOperationPreprocessor;\nimport org.springframework.restdocs.payload.JsonFieldType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;\n\n/**\n * Tests for generating documentation describing {@link ThreadDumpEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass ThreadDumpEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid jsonThreadDump() {\n\t\tReentrantLock lock = new ReentrantLock();\n\t\tCountDownLatch latch = new CountDownLatch(1);\n\t\tnew Thread(() -> {\n\t\t\ttry {\n\t\t\t\tlock.lock();\n\t\t\t\ttry {\n\t\t\t\t\tlatch.await();\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tlock.unlock();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}).start();\n\t\tassertThat(this.mvc.get().uri(\"/actuator/threaddump\").accept(MediaType.APPLICATION_JSON)).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation\n\t\t\t\t.document(\"threaddump/json\", preprocessResponse(limit(\"threads\")), responseFields(\n\t\t\t\t\t\tfieldWithPath(\"threads\").description(\"JVM's threads.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].blockedCount\")\n\t\t\t\t\t\t\t.description(\"Total number of times that the thread has been blocked.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].blockedTime\")\n\t\t\t\t\t\t\t.description(\"Time in milliseconds that the thread has spent \"\n\t\t\t\t\t\t\t\t\t+ \"blocked. -1 if thread contention \" + \"monitoring is disabled.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].daemon\")\n\t\t\t\t\t\t\t.description(\n\t\t\t\t\t\t\t\t\t\"Whether the thread is a daemon \" + \"thread. Only available on Java 9 or later.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.BOOLEAN),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].inNative\")\n\t\t\t\t\t\t\t.description(\"Whether the thread is executing native code.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockName\")\n\t\t\t\t\t\t\t.description(\"Description of the object on which the \" + \"thread is blocked, if any.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockInfo\")\n\t\t\t\t\t\t\t.description(\"Object for which the thread is blocked waiting.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockInfo.className\")\n\t\t\t\t\t\t\t.description(\"Fully qualified class name of the lock object.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockInfo.identityHashCode\")\n\t\t\t\t\t\t\t.description(\"Identity hash code of the lock object.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.NUMBER),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedMonitors\")\n\t\t\t\t\t\t\t.description(\"Monitors locked by this thread, if any\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedMonitors.[].className\")\n\t\t\t\t\t\t\t.description(\"Class name of the lock object.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedMonitors.[].identityHashCode\")\n\t\t\t\t\t\t\t.description(\"Identity hash code of the lock object.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.NUMBER),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedMonitors.[].lockedStackDepth\")\n\t\t\t\t\t\t\t.description(\"Stack depth where the monitor was locked.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.NUMBER),\n\t\t\t\t\t\tsubsectionWithPath(\"threads.[].lockedMonitors.[].lockedStackFrame\")\n\t\t\t\t\t\t\t.description(\"Stack frame that locked the monitor.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedSynchronizers\")\n\t\t\t\t\t\t\t.description(\"Synchronizers locked by this thread.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedSynchronizers.[].className\")\n\t\t\t\t\t\t\t.description(\"Class name of the locked synchronizer.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockedSynchronizers.[].identityHashCode\")\n\t\t\t\t\t\t\t.description(\"Identity hash code of the locked synchronizer.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.NUMBER),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockOwnerId\")\n\t\t\t\t\t\t\t.description(\"ID of the thread that owns the object on which \"\n\t\t\t\t\t\t\t\t\t+ \"the thread is blocked. `-1` if the \" + \"thread is not blocked.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].lockOwnerName\")\n\t\t\t\t\t\t\t.description(\"Name of the thread that owns the \"\n\t\t\t\t\t\t\t\t\t+ \"object on which the thread is blocked, if any.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].priority\")\n\t\t\t\t\t\t\t.description(\"Priority of the thread. Only \" + \"available on Java 9 or later.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.NUMBER),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace\").description(\"Stack trace of the thread.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].classLoaderName\")\n\t\t\t\t\t\t\t.description(\"Name of the class loader of the \" + \"class that contains the execution \"\n\t\t\t\t\t\t\t\t\t+ \"point identified by this entry, if \" + \"any. Only available on Java 9 or later.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].className\").description(\n\t\t\t\t\t\t\t\t\"Name of the class that contains the \" + \"execution point identified by this entry.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].fileName\")\n\t\t\t\t\t\t\t.description(\"Name of the source file that \" + \"contains the execution point \"\n\t\t\t\t\t\t\t\t\t+ \"identified by this entry, if any.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].lineNumber\").description(\"Line number of the execution \"\n\t\t\t\t\t\t\t\t+ \"point identified by this entry. \" + \"Negative if unknown.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].methodName\").description(\"Name of the method.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].moduleName\")\n\t\t\t\t\t\t\t.description(\"Name of the module that contains \" + \"the execution point identified by \"\n\t\t\t\t\t\t\t\t\t+ \"this entry, if any. Only available \" + \"on Java 9 or later.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].moduleVersion\")\n\t\t\t\t\t\t\t.description(\"Version of the module that \" + \"contains the execution point \"\n\t\t\t\t\t\t\t\t\t+ \"identified by this entry, if any. \" + \"Only available on Java 9 or later.\")\n\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].stackTrace.[].nativeMethod\")\n\t\t\t\t\t\t\t.description(\"Whether the execution point is a native method.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].suspended\").description(\"Whether the thread is suspended.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].threadId\").description(\"ID of the thread.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].threadName\").description(\"Name of the thread.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].threadState\")\n\t\t\t\t\t\t\t.description(\"State of the thread (\" + describeEnumValues(Thread.State.class) + \").\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].waitedCount\")\n\t\t\t\t\t\t\t.description(\"Total number of times that the thread has waited\" + \" for notification.\"),\n\t\t\t\t\t\tfieldWithPath(\"threads.[].waitedTime\")\n\t\t\t\t\t\t\t.description(\"Time in milliseconds that the thread has spent \"\n\t\t\t\t\t\t\t\t\t+ \"waiting. -1 if thread contention \" + \"monitoring is disabled\"))));\n\t\tlatch.countDown();\n\t}\n\n\t@Test\n\tvoid textThreadDump() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/threaddump\").accept(MediaType.TEXT_PLAIN)).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"threaddump/text\",\n\t\t\t\t\tpreprocessResponse(new ContentModifyingOperationPreprocessor((bytes, mediaType) -> {\n\t\t\t\t\t\tString content = new String(bytes, StandardCharsets.UTF_8);\n\t\t\t\t\t\tint mainThreadIndex = content.indexOf(\"\\\"main\\\" - Thread\");\n\t\t\t\t\t\tString truncatedContent = (mainThreadIndex >= 0) ? content.substring(0, mainThreadIndex)\n\t\t\t\t\t\t\t\t: content;\n\t\t\t\t\t\treturn truncatedContent.getBytes();\n\t\t\t\t\t}))));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tThreadDumpEndpoint endpoint() {\n\t\t\treturn new ThreadDumpEndpoint();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/metrics/MetricsEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.metrics;\n\nimport io.micrometer.core.instrument.Statistic;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;\nimport static org.springframework.restdocs.request.RequestDocumentation.queryParameters;\n\n/**\n * Tests for generating documentation describing the {@link MetricsEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass MetricsEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid metricNames() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/metrics\")).hasStatusOk()\n\t\t\t.apply(document(\"metrics/names\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"names\").description(\"Names of the known metrics.\"))));\n\t}\n\n\t@Test\n\tvoid metric() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/metrics/jvm.memory.max\")).hasStatusOk()\n\t\t\t.apply(document(\"metrics/metric\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"name\").description(\"Name of the metric\"),\n\t\t\t\t\t\t\tfieldWithPath(\"description\").description(\"Description of the metric\"),\n\t\t\t\t\t\t\tfieldWithPath(\"baseUnit\").description(\"Base unit of the metric\"),\n\t\t\t\t\t\t\tfieldWithPath(\"measurements\").description(\"Measurements of the metric\"),\n\t\t\t\t\t\t\tfieldWithPath(\"measurements[].statistic\").description(\n\t\t\t\t\t\t\t\t\t\"Statistic of the measurement. (\" + describeEnumValues(Statistic.class) + \").\"),\n\t\t\t\t\t\t\tfieldWithPath(\"measurements[].value\").description(\"Value of the measurement.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"availableTags\").description(\"Tags that are available for drill-down.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"availableTags[].tag\").description(\"Name of the tag.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"availableTags[].values\").description(\"Possible values of the tag.\"))));\n\t}\n\n\t@Test\n\tvoid metricWithTags() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/actuator/metrics/jvm.memory.max\")\n\t\t\t.param(\"tag\", \"area:nonheap\")\n\t\t\t.param(\"tag\", \"id:Compressed Class Space\")).hasStatusOk()\n\t\t\t.apply(document(\"metrics/metric-with-tags\", queryParameters(\n\t\t\t\t\tparameterWithName(\"tag\").description(\"A tag to use for drill-down in the form `name:value`.\"))));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tMetricsEndpoint endpoint() {\n\t\t\tSimpleMeterRegistry registry = new SimpleMeterRegistry();\n\t\t\tnew JvmMemoryMetrics().bindTo(registry);\n\t\t\treturn new MetricsEndpoint(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/metrics/export/prometheus/PrometheusScrapeEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.metrics.export.prometheus;\n\nimport java.util.Properties;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;\nimport io.prometheus.metrics.model.registry.PrometheusRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus.PrometheusScrapeEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;\nimport static org.springframework.restdocs.request.RequestDocumentation.queryParameters;\n\n/**\n * Tests for generating documentation describing the {@link PrometheusScrapeEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Johnny Lim\n */\nclass PrometheusScrapeEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid prometheus() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/prometheus\")).hasStatusOk().apply(document(\"prometheus/all\"));\n\t}\n\n\t@Test\n\tvoid prometheusOpenmetrics() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/prometheus\").accept(OpenMetricsTextFormatWriter.CONTENT_TYPE))\n\t\t\t.satisfies((result) -> {\n\t\t\t\tassertThat(result).hasStatusOk()\n\t\t\t\t\t.headers()\n\t\t\t\t\t.hasValue(\"Content-Type\", \"application/openmetrics-text;version=1.0.0;charset=utf-8\");\n\t\t\t\tassertThat(result).apply(document(\"prometheus/openmetrics\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid filteredPrometheus() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/actuator/prometheus\")\n\t\t\t.param(\"includedNames\", \"jvm_memory_used_bytes,jvm_memory_committed_bytes\"))\n\t\t\t.hasStatusOk()\n\t\t\t.apply(document(\"prometheus/names\",\n\t\t\t\t\tqueryParameters(parameterWithName(\"includedNames\")\n\t\t\t\t\t\t.description(\"Restricts the samples to those that match the names. Optional.\")\n\t\t\t\t\t\t.optional())));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tPrometheusScrapeEndpoint endpoint() {\n\t\t\tPrometheusRegistry prometheusRegistry = new PrometheusRegistry();\n\t\t\tPrometheusMeterRegistry meterRegistry = new PrometheusMeterRegistry((key) -> null, prometheusRegistry,\n\t\t\t\t\tClock.SYSTEM);\n\t\t\tnew JvmMemoryMetrics().bindTo(meterRegistry);\n\t\t\treturn new PrometheusScrapeEndpoint(prometheusRegistry, new Properties());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/quartz/QuartzEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.quartz;\n\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Calendar;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.TimeZone;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.CalendarIntervalScheduleBuilder;\nimport org.quartz.CalendarIntervalTrigger;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.DailyTimeIntervalScheduleBuilder;\nimport org.quartz.DailyTimeIntervalTrigger;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.Job;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.TimeOfDay;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.OperableTrigger;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpointWebExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.scheduling.quartz.DelegatingJob;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.relaxedResponseFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;\n\n/**\n * Tests for generating documentation describing the {@link QuartzEndpoint}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\nclass QuartzEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\tprivate static final TimeZone timeZone = TimeZone.getTimeZone(\"Europe/Paris\");\n\n\tprivate static final JobDetail jobOne = JobBuilder.newJob(DelegatingJob.class)\n\t\t.withIdentity(\"jobOne\", \"samples\")\n\t\t.withDescription(\"A sample job\")\n\t\t.usingJobData(\"user\", \"admin\")\n\t\t.usingJobData(\"password\", \"secret\")\n\t\t.build();\n\n\tprivate static final JobDetail jobTwo = JobBuilder.newJob(Job.class).withIdentity(\"jobTwo\", \"samples\").build();\n\n\tprivate static final JobDetail jobThree = JobBuilder.newJob(Job.class).withIdentity(\"jobThree\", \"tests\").build();\n\n\tprivate static final CronTrigger cronTrigger = TriggerBuilder.newTrigger()\n\t\t.forJob(jobOne)\n\t\t.withPriority(3)\n\t\t.withDescription(\"3AM on weekdays\")\n\t\t.withIdentity(\"3am-weekdays\", \"samples\")\n\t\t.withSchedule(CronScheduleBuilder.atHourAndMinuteOnGivenDaysOfWeek(3, 0, 1, 2, 3, 4, 5).inTimeZone(timeZone))\n\t\t.build();\n\n\tprivate static final SimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()\n\t\t.forJob(jobOne)\n\t\t.withPriority(7)\n\t\t.withDescription(\"Once a day\")\n\t\t.withIdentity(\"every-day\", \"samples\")\n\t\t.withSchedule(SimpleScheduleBuilder.repeatHourlyForever(24))\n\t\t.build();\n\n\tprivate static final CalendarIntervalTrigger calendarIntervalTrigger = TriggerBuilder.newTrigger()\n\t\t.forJob(jobTwo)\n\t\t.withDescription(\"Once a week\")\n\t\t.withIdentity(\"once-a-week\", \"samples\")\n\t\t.withSchedule(\n\t\t\t\tCalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInWeeks(1).inTimeZone(timeZone))\n\t\t.build();\n\n\tprivate static final DailyTimeIntervalTrigger dailyTimeIntervalTrigger = TriggerBuilder.newTrigger()\n\t\t.forJob(jobThree)\n\t\t.withDescription(\"Every hour between 9AM and 6PM on Tuesday and Thursday\")\n\t\t.withIdentity(\"every-hour-tue-thu\")\n\t\t.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n\t\t\t.onDaysOfTheWeek(Calendar.TUESDAY, Calendar.THURSDAY)\n\t\t\t.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))\n\t\t\t.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(18, 0))\n\t\t\t.withInterval(1, IntervalUnit.HOUR))\n\t\t.build();\n\n\tprivate static final List<FieldDescriptor> triggerSummary = List.of(previousFireTime(\"\"), nextFireTime(\"\"),\n\t\t\tpriority(\"\"));\n\n\tprivate static final List<FieldDescriptor> cronTriggerSummary = List.of(\n\t\t\tfieldWithPath(\"expression\").description(\"Cron expression to use.\"),\n\t\t\tfieldWithPath(\"timeZone\").type(JsonFieldType.STRING)\n\t\t\t\t.optional()\n\t\t\t\t.description(\"Time zone for which the expression will be resolved, if any.\"));\n\n\tprivate static final List<FieldDescriptor> simpleTriggerSummary = Collections\n\t\t.singletonList(fieldWithPath(\"interval\").description(\"Interval, in milliseconds, between two executions.\"));\n\n\tprivate static final List<FieldDescriptor> dailyTimeIntervalTriggerSummary = Arrays\n\t\t.asList(fieldWithPath(\"interval\").description(\n\t\t\t\t\"Interval, in milliseconds, added to the fire time in order to calculate the time of the next trigger repeat.\"),\n\t\t\t\tfieldWithPath(\"daysOfWeek\").type(JsonFieldType.ARRAY)\n\t\t\t\t\t.description(\"An array of days of the week upon which to fire.\"),\n\t\t\t\tfieldWithPath(\"startTimeOfDay\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Time of day to start firing at the given interval, if any.\"),\n\t\t\t\tfieldWithPath(\"endTimeOfDay\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Time of day to complete firing at the given interval, if any.\"));\n\n\tprivate static final List<FieldDescriptor> calendarIntervalTriggerSummary = Arrays\n\t\t.asList(fieldWithPath(\"interval\").description(\n\t\t\t\t\"Interval, in milliseconds, added to the fire time in order to calculate the time of the next trigger repeat.\"),\n\t\t\t\tfieldWithPath(\"timeZone\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Time zone within which time calculations will be performed, if any.\"));\n\n\tprivate static final List<FieldDescriptor> customTriggerSummary = List\n\t\t.of(fieldWithPath(\"trigger\").description(\"A toString representation of the custom trigger instance.\"));\n\n\tprivate static final FieldDescriptor[] commonCronDetails = new FieldDescriptor[] {\n\t\t\tfieldWithPath(\"group\").description(\"Name of the group.\"),\n\t\t\tfieldWithPath(\"name\").description(\"Name of the trigger.\"),\n\t\t\tfieldWithPath(\"description\").description(\"Description of the trigger, if any.\"),\n\t\t\tfieldWithPath(\"state\")\n\t\t\t\t.description(\"State of the trigger (\" + describeEnumValues(TriggerState.class) + \").\"),\n\t\t\tfieldWithPath(\"type\").description(\n\t\t\t\t\t\"Type of the trigger (`calendarInterval`, `cron`, `custom`, `dailyTimeInterval`, `simple`). \"\n\t\t\t\t\t\t\t+ \"Determines the key of the object containing type-specific details.\"),\n\t\t\tfieldWithPath(\"calendarName\").description(\"Name of the Calendar associated with this Trigger, if any.\"),\n\t\t\tstartTime(\"\"), endTime(\"\"), previousFireTime(\"\"), nextFireTime(\"\"), priority(\"\"),\n\t\t\tfieldWithPath(\"finalFireTime\").optional()\n\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t.description(\"Last time at which the Trigger will fire, if any.\"),\n\t\t\tfieldWithPath(\"data\").optional()\n\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t.description(\"Job data map keyed by name, if any.\") };\n\n\t@MockitoBean\n\tprivate Scheduler scheduler;\n\n\t@Test\n\tvoid quartzReport() throws Exception {\n\t\tmockJobs(jobOne, jobTwo, jobThree);\n\t\tmockTriggers(cronTrigger, simpleTrigger, calendarIntervalTrigger, dailyTimeIntervalTrigger);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/report\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"jobs.groups\").description(\"An array of job group names.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggers.groups\").description(\"An array of trigger group names.\"))));\n\t}\n\n\t@Test\n\tvoid quartzJobs() throws Exception {\n\t\tmockJobs(jobOne, jobTwo, jobThree);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/jobs\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/jobs\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"groups\").description(\"Job groups keyed by name.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"groups.*.jobs\").description(\"An array of job names.\"))));\n\t}\n\n\t@Test\n\tvoid quartzTriggers() throws Exception {\n\t\tmockTriggers(cronTrigger, simpleTrigger, calendarIntervalTrigger, dailyTimeIntervalTrigger);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/triggers\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"groups\").description(\"Trigger groups keyed by name.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"groups.*.paused\").description(\"Whether this trigger group is paused.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"groups.*.triggers\").description(\"An array of trigger names.\"))));\n\t}\n\n\t@Test\n\tvoid quartzJobGroup() throws Exception {\n\t\tmockJobs(jobOne, jobTwo, jobThree);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/jobs/samples\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/job-group\", responseFields(fieldWithPath(\"group\").description(\"Name of the group.\"),\n\t\t\t\t\tfieldWithPath(\"jobs\").description(\"Job details keyed by name.\"),\n\t\t\t\t\tfieldWithPath(\"jobs.*.className\").description(\"Fully qualified name of the job implementation.\"))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroup() throws Exception {\n\t\tCronTrigger cron = cronTrigger.getTriggerBuilder()\n\t\t\t.startAt(fromUtc(\"2020-11-30T17:00:00Z\"))\n\t\t\t.endAt(fromUtc(\"2020-12-30T03:00:00Z\"))\n\t\t\t.withIdentity(\"3am-week\", \"tests\")\n\t\t\t.build();\n\t\tsetPreviousNextFireTime(cron, \"2020-12-04T03:00:00Z\", \"2020-12-07T03:00:00Z\");\n\t\tSimpleTrigger simple = simpleTrigger.getTriggerBuilder().withIdentity(\"every-day\", \"tests\").build();\n\t\tsetPreviousNextFireTime(simple, null, \"2020-12-04T12:00:00Z\");\n\t\tCalendarIntervalTrigger calendarInterval = calendarIntervalTrigger.getTriggerBuilder()\n\t\t\t.withIdentity(\"once-a-week\", \"tests\")\n\t\t\t.startAt(fromUtc(\"2019-07-10T14:00:00Z\"))\n\t\t\t.endAt(fromUtc(\"2023-01-01T12:00:00Z\"))\n\t\t\t.build();\n\t\tsetPreviousNextFireTime(calendarInterval, \"2020-12-02T14:00:00Z\", \"2020-12-08T14:00:00Z\");\n\t\tDailyTimeIntervalTrigger tueThuTrigger = dailyTimeIntervalTrigger.getTriggerBuilder()\n\t\t\t.withIdentity(\"tue-thu\", \"tests\")\n\t\t\t.build();\n\t\tTrigger customTrigger = mock(Trigger.class);\n\t\tgiven(customTrigger.getKey()).willReturn(TriggerKey.triggerKey(\"once-a-year-custom\", \"tests\"));\n\t\tgiven(customTrigger.toString()).willReturn(\"com.example.CustomTrigger@fdsfsd\");\n\t\tgiven(customTrigger.getPriority()).willReturn(10);\n\t\tgiven(customTrigger.getPreviousFireTime()).willReturn(fromUtc(\"2020-07-14T16:00:00Z\"));\n\t\tgiven(customTrigger.getNextFireTime()).willReturn(fromUtc(\"2021-07-14T16:00:00Z\"));\n\t\tmockTriggers(cron, simple, calendarInterval, tueThuTrigger, customTrigger);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/tests\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-group\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"group\").description(\"Name of the group.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"paused\").description(\"Whether the group is paused.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggers.cron\").description(\"Cron triggers keyed by name, if any.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggers.simple\").description(\"Simple triggers keyed by name, if any.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggers.dailyTimeInterval\")\n\t\t\t\t\t\t\t\t.description(\"Daily time interval triggers keyed by name, if any.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggers.calendarInterval\")\n\t\t\t\t\t\t\t\t.description(\"Calendar interval triggers keyed by name, if any.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggers.custom\").description(\"Any other triggers keyed by name, if any.\"))\n\t\t\t\t\t\t.andWithPrefix(\"triggers.cron.*.\", concat(triggerSummary, cronTriggerSummary))\n\t\t\t\t\t\t.andWithPrefix(\"triggers.simple.*.\", concat(triggerSummary, simpleTriggerSummary))\n\t\t\t\t\t\t.andWithPrefix(\"triggers.dailyTimeInterval.*.\",\n\t\t\t\t\t\t\t\tconcat(triggerSummary, dailyTimeIntervalTriggerSummary))\n\t\t\t\t\t\t.andWithPrefix(\"triggers.calendarInterval.*.\",\n\t\t\t\t\t\t\t\tconcat(triggerSummary, calendarIntervalTriggerSummary))\n\t\t\t\t\t\t.andWithPrefix(\"triggers.custom.*.\", concat(triggerSummary, customTriggerSummary))));\n\t}\n\n\t@Test\n\tvoid quartzJob() throws Exception {\n\t\tmockJobs(jobOne);\n\t\tCronTrigger firstTrigger = cronTrigger.getTriggerBuilder().build();\n\t\tsetPreviousNextFireTime(firstTrigger, null, \"2020-12-07T03:00:00Z\");\n\t\tSimpleTrigger secondTrigger = simpleTrigger.getTriggerBuilder().build();\n\t\tsetPreviousNextFireTime(secondTrigger, \"2020-12-04T03:00:00Z\", \"2020-12-04T12:00:00Z\");\n\t\tmockTriggers(firstTrigger, secondTrigger);\n\t\tgiven(this.scheduler.getTriggersOfJob(jobOne.getKey()))\n\t\t\t.willAnswer((invocation) -> List.of(firstTrigger, secondTrigger));\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/jobs/samples/jobOne\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/job-details\", responseFields(\n\t\t\t\t\tfieldWithPath(\"group\").description(\"Name of the group.\"),\n\t\t\t\t\tfieldWithPath(\"name\").description(\"Name of the job.\"),\n\t\t\t\t\tfieldWithPath(\"description\").description(\"Description of the job, if any.\"),\n\t\t\t\t\tfieldWithPath(\"className\").description(\"Fully qualified name of the job implementation.\"),\n\t\t\t\t\tfieldWithPath(\"durable\").description(\"Whether the job should remain stored after it is orphaned.\"),\n\t\t\t\t\tfieldWithPath(\"requestRecovery\").description(\n\t\t\t\t\t\t\t\"Whether the job should be re-executed if a 'recovery' or 'fail-over' situation is encountered.\"),\n\t\t\t\t\tfieldWithPath(\"data.*\").description(\"Job data map as key/value pairs, if any.\"),\n\t\t\t\t\tfieldWithPath(\"triggers\").description(\"An array of triggers associated to the job, if any.\"),\n\t\t\t\t\tfieldWithPath(\"triggers.[].group\").description(\"Name of the trigger group.\"),\n\t\t\t\t\tfieldWithPath(\"triggers.[].name\").description(\"Name of the trigger.\"),\n\t\t\t\t\tpreviousFireTime(\"triggers.[].\"), nextFireTime(\"triggers.[].\"), priority(\"triggers.[].\"))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerCommon() throws Exception {\n\t\tsetupTriggerDetails(cronTrigger.getTriggerBuilder(), TriggerState.NORMAL);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/samples/example\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-details-common\", responseFields(commonCronDetails).and(subsectionWithPath(\n\t\t\t\t\t\"calendarInterval\")\n\t\t\t\t.description(\n\t\t\t\t\t\t\"Calendar time interval trigger details, if any. Present when `type` is `calendarInterval`.\")\n\t\t\t\t.optional()\n\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\t\tsubsectionWithPath(\"custom\")\n\t\t\t\t\t\t.description(\"Custom trigger details, if any. Present when `type` is `custom`.\")\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\t\tsubsectionWithPath(\"cron\")\n\t\t\t\t\t\t.description(\"Cron trigger details, if any. Present when `type` is `cron`.\")\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\t\tsubsectionWithPath(\"dailyTimeInterval\").description(\n\t\t\t\t\t\t\t\"Daily time interval trigger details, if any. Present when `type` is `dailyTimeInterval`.\")\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\t\tsubsectionWithPath(\"simple\")\n\t\t\t\t\t\t.description(\"Simple trigger details, if any. Present when `type` is `simple`.\")\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.type(JsonFieldType.OBJECT))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerCron() throws Exception {\n\t\tsetupTriggerDetails(cronTrigger.getTriggerBuilder(), TriggerState.NORMAL);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/samples/example\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-details-cron\",\n\t\t\t\t\trelaxedResponseFields(fieldWithPath(\"cron\").description(\"Cron trigger specific details.\"))\n\t\t\t\t\t\t.andWithPrefix(\"cron.\", cronTriggerSummary)));\n\t}\n\n\t@Test\n\tvoid quartzTriggerSimple() throws Exception {\n\t\tsetupTriggerDetails(simpleTrigger.getTriggerBuilder(), TriggerState.NORMAL);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/samples/example\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-details-simple\",\n\t\t\t\t\trelaxedResponseFields(fieldWithPath(\"simple\").description(\"Simple trigger specific details.\"))\n\t\t\t\t\t\t.andWithPrefix(\"simple.\", simpleTriggerSummary)\n\t\t\t\t\t\t.and(repeatCount(\"simple.\"), timesTriggered(\"simple.\"))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerCalendarInterval() throws Exception {\n\t\tsetupTriggerDetails(calendarIntervalTrigger.getTriggerBuilder(), TriggerState.NORMAL);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/samples/example\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-details-calendar-interval\",\n\t\t\t\t\trelaxedResponseFields(fieldWithPath(\"calendarInterval\")\n\t\t\t\t\t\t.description(\"Calendar interval trigger specific details.\"))\n\t\t\t\t\t\t.andWithPrefix(\"calendarInterval.\", calendarIntervalTriggerSummary)\n\t\t\t\t\t\t.and(timesTriggered(\"calendarInterval.\"),\n\t\t\t\t\t\t\t\tfieldWithPath(\"calendarInterval.preserveHourOfDayAcrossDaylightSavings\").description(\n\t\t\t\t\t\t\t\t\t\t\"Whether to fire the trigger at the same time of day, regardless of daylight \"\n\t\t\t\t\t\t\t\t\t\t\t\t+ \"saving time transitions.\"),\n\t\t\t\t\t\t\t\tfieldWithPath(\"calendarInterval.skipDayIfHourDoesNotExist\").description(\n\t\t\t\t\t\t\t\t\t\t\"Whether to skip if the hour of the day does not exist on a given day.\"))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerDailyTimeInterval() throws Exception {\n\t\tsetupTriggerDetails(dailyTimeIntervalTrigger.getTriggerBuilder(), TriggerState.PAUSED);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/samples/example\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-details-daily-time-interval\",\n\t\t\t\t\trelaxedResponseFields(fieldWithPath(\"dailyTimeInterval\")\n\t\t\t\t\t\t.description(\"Daily time interval trigger specific details.\"))\n\t\t\t\t\t\t.andWithPrefix(\"dailyTimeInterval.\", dailyTimeIntervalTriggerSummary)\n\t\t\t\t\t\t.and(repeatCount(\"dailyTimeInterval.\"), timesTriggered(\"dailyTimeInterval.\"))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerCustom() throws Exception {\n\t\tTrigger trigger = mock(Trigger.class);\n\t\tgiven(trigger.getKey()).willReturn(TriggerKey.triggerKey(\"example\", \"samples\"));\n\t\tgiven(trigger.getDescription()).willReturn(\"Example trigger.\");\n\t\tgiven(trigger.toString()).willReturn(\"com.example.CustomTrigger@fdsfsd\");\n\t\tgiven(trigger.getPriority()).willReturn(10);\n\t\tgiven(trigger.getStartTime()).willReturn(fromUtc(\"2020-11-30T17:00:00Z\"));\n\t\tgiven(trigger.getEndTime()).willReturn(fromUtc(\"2020-12-30T03:00:00Z\"));\n\t\tgiven(trigger.getCalendarName()).willReturn(\"bankHolidays\");\n\t\tgiven(trigger.getPreviousFireTime()).willReturn(fromUtc(\"2020-12-04T03:00:00Z\"));\n\t\tgiven(trigger.getNextFireTime()).willReturn(fromUtc(\"2020-12-07T03:00:00Z\"));\n\t\tgiven(this.scheduler.getTriggerState(trigger.getKey())).willReturn(TriggerState.NORMAL);\n\t\tmockTriggers(trigger);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/quartz/triggers/samples/example\")).hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-details-custom\",\n\t\t\t\t\trelaxedResponseFields(fieldWithPath(\"custom\").description(\"Custom trigger specific details.\"))\n\t\t\t\t\t\t.andWithPrefix(\"custom.\", customTriggerSummary)));\n\t}\n\n\t@Test\n\tvoid quartzTriggerJob() throws Exception {\n\t\tmockJobs(jobOne);\n\t\tString json = JsonWriter.standard().writeToString(Map.of(\"state\", \"running\"));\n\t\tassertThat(this.mvc.post()\n\t\t\t.content(json)\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.uri(\"/actuator/quartz/jobs/samples/jobOne\"))\n\t\t\t.hasStatusOk()\n\t\t\t.apply(document(\"quartz/trigger-job\", preprocessRequest(), preprocessResponse(prettyPrint()),\n\t\t\t\t\trequestFields(fieldWithPath(\"state\").description(\"Desired state of the job. Must be `running`.\")),\n\t\t\t\t\tresponseFields(fieldWithPath(\"group\").description(\"Name of the group.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"name\").description(\"Name of the job.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"className\").description(\"Fully qualified name of the job implementation.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"triggerTime\").description(\"Time the job is triggered.\"))));\n\t}\n\n\tprivate <T extends Trigger> void setupTriggerDetails(TriggerBuilder<T> builder, TriggerState state)\n\t\t\tthrows SchedulerException {\n\t\tT trigger = builder.withIdentity(\"example\", \"samples\")\n\t\t\t.withDescription(\"Example trigger\")\n\t\t\t.startAt(fromUtc(\"2020-11-30T17:00:00Z\"))\n\t\t\t.modifiedByCalendar(\"bankHolidays\")\n\t\t\t.endAt(fromUtc(\"2020-12-30T03:00:00Z\"))\n\t\t\t.build();\n\t\tsetPreviousNextFireTime(trigger, \"2020-12-04T03:00:00Z\", \"2020-12-07T03:00:00Z\");\n\t\tgiven(this.scheduler.getTriggerState(trigger.getKey())).willReturn(state);\n\t\tmockTriggers(trigger);\n\t}\n\n\tprivate static FieldDescriptor startTime(String prefix) {\n\t\treturn fieldWithPath(prefix + \"startTime\").description(\"Time at which the Trigger should take effect, if any.\");\n\t}\n\n\tprivate static FieldDescriptor endTime(String prefix) {\n\t\treturn fieldWithPath(prefix + \"endTime\").description(\n\t\t\t\t\"Time at which the Trigger should quit repeating, regardless of any remaining repeats, if any.\");\n\t}\n\n\tprivate static FieldDescriptor previousFireTime(String prefix) {\n\t\treturn fieldWithPath(prefix + \"previousFireTime\").optional()\n\t\t\t.type(JsonFieldType.STRING)\n\t\t\t.description(\"Last time the trigger fired, if any.\");\n\t}\n\n\tprivate static FieldDescriptor nextFireTime(String prefix) {\n\t\treturn fieldWithPath(prefix + \"nextFireTime\").optional()\n\t\t\t.type(JsonFieldType.STRING)\n\t\t\t.description(\"Next time at which the Trigger is scheduled to fire, if any.\");\n\t}\n\n\tprivate static FieldDescriptor priority(String prefix) {\n\t\treturn fieldWithPath(prefix + \"priority\")\n\t\t\t.description(\"Priority to use if two triggers have the same scheduled fire time.\");\n\t}\n\n\tprivate static FieldDescriptor repeatCount(String prefix) {\n\t\treturn fieldWithPath(prefix + \"repeatCount\")\n\t\t\t.description(\"Number of times the trigger should repeat, or -1 to repeat indefinitely.\");\n\t}\n\n\tprivate static FieldDescriptor timesTriggered(String prefix) {\n\t\treturn fieldWithPath(prefix + \"timesTriggered\").description(\"Number of times the trigger has already fired.\");\n\t}\n\n\tprivate static List<FieldDescriptor> concat(List<FieldDescriptor> initial, List<FieldDescriptor> additionalFields) {\n\t\tList<FieldDescriptor> result = new ArrayList<>(initial);\n\t\tresult.addAll(additionalFields);\n\t\treturn result;\n\t}\n\n\tprivate void mockJobs(JobDetail... jobs) throws SchedulerException {\n\t\tMultiValueMap<String, JobKey> jobKeys = new LinkedMultiValueMap<>();\n\t\tfor (JobDetail jobDetail : jobs) {\n\t\t\tJobKey key = jobDetail.getKey();\n\t\t\tgiven(this.scheduler.getJobDetail(key)).willReturn(jobDetail);\n\t\t\tjobKeys.add(key.getGroup(), key);\n\t\t}\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(new ArrayList<>(jobKeys.keySet()));\n\t\tfor (Entry<String, List<JobKey>> entry : jobKeys.entrySet()) {\n\t\t\tgiven(this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(entry.getKey())))\n\t\t\t\t.willReturn(new LinkedHashSet<>(entry.getValue()));\n\t\t}\n\t}\n\n\tprivate void mockTriggers(Trigger... triggers) throws SchedulerException {\n\t\tMultiValueMap<String, TriggerKey> triggerKeys = new LinkedMultiValueMap<>();\n\t\tfor (Trigger trigger : triggers) {\n\t\t\tTriggerKey key = trigger.getKey();\n\t\t\tgiven(this.scheduler.getTrigger(key)).willReturn(trigger);\n\t\t\ttriggerKeys.add(key.getGroup(), key);\n\t\t}\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(new ArrayList<>(triggerKeys.keySet()));\n\t\tfor (Entry<String, List<TriggerKey>> entry : triggerKeys.entrySet()) {\n\t\t\tgiven(this.scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(entry.getKey())))\n\t\t\t\t.willReturn(new LinkedHashSet<>(entry.getValue()));\n\t\t}\n\t}\n\n\tprivate <T extends Trigger> void setPreviousNextFireTime(T trigger, String previousFireTime, String nextFireTime) {\n\t\tOperableTrigger operableTrigger = (OperableTrigger) trigger;\n\t\tif (previousFireTime != null) {\n\t\t\toperableTrigger.setPreviousFireTime(fromUtc(previousFireTime));\n\t\t}\n\t\tif (nextFireTime != null) {\n\t\t\toperableTrigger.setNextFireTime(fromUtc(nextFireTime));\n\t\t}\n\t}\n\n\tprivate static Date fromUtc(String utcTime) {\n\t\treturn Date.from(Instant.parse(utcTime));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tQuartzEndpoint endpoint(Scheduler scheduler) {\n\t\t\treturn new QuartzEndpoint(scheduler, Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tQuartzEndpointWebExtension endpointWebExtension(QuartzEndpoint endpoint) {\n\t\t\treturn new QuartzEndpointWebExtension(endpoint, Show.ALWAYS, Collections.emptySet());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/sbom/SbomEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.sbom;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.sbom.SbomEndpoint;\nimport org.springframework.boot.actuate.sbom.SbomEndpointWebExtension;\nimport org.springframework.boot.actuate.sbom.SbomProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link SbomEndpoint}.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid sbom() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/sbom\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"sbom\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"ids\").description(\"An array of available SBOM ids.\"))));\n\t}\n\n\t@Test\n\tvoid sboms() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/sbom/application\")).hasStatusOk()\n\t\t\t.apply(MockMvcRestDocumentation.document(\"sbom/id\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSbomProperties sbomProperties() {\n\t\t\tSbomProperties properties = new SbomProperties();\n\t\t\tproperties.getApplication()\n\t\t\t\t.setLocation(\"classpath:org/springframework/boot/actuate/docs/sbom/cyclonedx.json\");\n\t\t\treturn properties;\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpoint endpoint(SbomProperties properties, ResourceLoader resourceLoader) {\n\t\t\treturn new SbomEndpoint(properties, resourceLoader);\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpointWebExtension sbomEndpointWebExtension(SbomEndpoint endpoint, SbomProperties properties) {\n\t\t\treturn new SbomEndpointWebExtension(endpoint, properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/scheduling/ScheduledTasksEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.scheduling;\n\nimport java.time.Instant;\nimport java.util.Collection;\nimport java.util.regex.Pattern;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.scheduling.Trigger;\nimport org.springframework.scheduling.TriggerContext;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.scheduling.annotation.SchedulingConfigurer;\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\nimport org.springframework.scheduling.config.ScheduledTaskHolder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;\nimport static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing the {@link ScheduledTasksEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass ScheduledTasksEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@Test\n\tvoid scheduledTasks() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/scheduledtasks\")).hasStatusOk()\n\t\t\t.apply(document(\"scheduled-tasks\",\n\t\t\t\t\tpreprocessResponse(replacePattern(\n\t\t\t\t\t\t\tPattern.compile(\"org.*\\\\.ScheduledTasksEndpointDocumentationTests\\\\$TestConfiguration\"),\n\t\t\t\t\t\t\t\"com.example.Processor\")),\n\t\t\t\t\tresponseFields(fieldWithPath(\"cron\").description(\"Cron tasks, if any.\"),\n\t\t\t\t\t\t\ttargetFieldWithPrefix(\"cron.[].\"),\n\t\t\t\t\t\t\tnextExecutionWithPrefix(\"cron.[].\").description(\"Time of the next scheduled execution.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"cron.[].expression\").description(\"Cron expression.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"fixedDelay\").description(\"Fixed delay tasks, if any.\"),\n\t\t\t\t\t\t\ttargetFieldWithPrefix(\"fixedDelay.[].\"), initialDelayWithPrefix(\"fixedDelay.[].\"),\n\t\t\t\t\t\t\tnextExecutionWithPrefix(\"fixedDelay.[].\"),\n\t\t\t\t\t\t\tfieldWithPath(\"fixedDelay.[].interval\")\n\t\t\t\t\t\t\t\t.description(\"Interval, in milliseconds, between the end of the last\"\n\t\t\t\t\t\t\t\t\t\t+ \" execution and the start of the next.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"fixedRate\").description(\"Fixed rate tasks, if any.\"),\n\t\t\t\t\t\t\ttargetFieldWithPrefix(\"fixedRate.[].\"),\n\t\t\t\t\t\t\tfieldWithPath(\"fixedRate.[].interval\")\n\t\t\t\t\t\t\t\t.description(\"Interval, in milliseconds, between the start of each execution.\"),\n\t\t\t\t\t\t\tinitialDelayWithPrefix(\"fixedRate.[].\"), nextExecutionWithPrefix(\"fixedRate.[].\"),\n\t\t\t\t\t\t\tfieldWithPath(\"custom\").description(\"Tasks with custom triggers, if any.\"),\n\t\t\t\t\t\t\ttargetFieldWithPrefix(\"custom.[].\"),\n\t\t\t\t\t\t\tfieldWithPath(\"custom.[].trigger\").description(\"Trigger for the task.\"))\n\t\t\t\t\t\t.andWithPrefix(\"*.[].\",\n\t\t\t\t\t\t\t\tfieldWithPath(\"lastExecution\").description(\"Last execution of this task, if any.\")\n\t\t\t\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t\t\t\t.type(JsonFieldType.OBJECT))\n\t\t\t\t\t\t.andWithPrefix(\"*.[].lastExecution.\", lastExecution())));\n\t}\n\n\tprivate FieldDescriptor targetFieldWithPrefix(String prefix) {\n\t\treturn fieldWithPath(prefix + \"runnable.target\").description(\"Target that will be executed.\");\n\t}\n\n\tprivate FieldDescriptor initialDelayWithPrefix(String prefix) {\n\t\treturn fieldWithPath(prefix + \"initialDelay\").description(\"Delay, in milliseconds, before first execution.\");\n\t}\n\n\tprivate FieldDescriptor nextExecutionWithPrefix(String prefix) {\n\t\treturn fieldWithPath(prefix + \"nextExecution.time\")\n\t\t\t.description(\"Time of the next scheduled execution, if known.\")\n\t\t\t.type(JsonFieldType.STRING)\n\t\t\t.optional();\n\t}\n\n\tprivate FieldDescriptor[] lastExecution() {\n\t\treturn new FieldDescriptor[] {\n\t\t\t\tfieldWithPath(\"status\").description(\"Status of the last execution (STARTED, SUCCESS, ERROR).\")\n\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"time\").description(\"Time of the last execution.\").type(JsonFieldType.STRING),\n\t\t\t\tfieldWithPath(\"exception.type\").description(\"Exception type thrown by the task, if any.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"exception.message\").description(\"Message of the exception thrown by the task, if any.\")\n\t\t\t\t\t.type(JsonFieldType.STRING)\n\t\t\t\t\t.optional() };\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableScheduling\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tScheduledTasksEndpoint endpoint(Collection<ScheduledTaskHolder> holders) {\n\t\t\treturn new ScheduledTasksEndpoint(holders);\n\t\t}\n\n\t\t@Scheduled(cron = \"0 0 0/3 1/1 * ?\")\n\t\tvoid processOrders() {\n\n\t\t}\n\n\t\t@Scheduled(fixedDelay = 5000, initialDelay = 0)\n\t\tvoid purge() {\n\n\t\t}\n\n\t\t@Scheduled(fixedRate = 3000, initialDelay = 10000)\n\t\tvoid retrieveIssues() {\n\n\t\t}\n\n\t\t@Bean\n\t\tSchedulingConfigurer schedulingConfigurer() {\n\t\t\treturn (registrar) -> {\n\t\t\t\tregistrar.setTaskScheduler(new TestTaskScheduler());\n\t\t\t\tregistrar.addTriggerTask(new CustomTriggeredRunnable(), new CustomTrigger());\n\t\t\t};\n\t\t}\n\n\t\tstatic class CustomTrigger implements Trigger {\n\n\t\t\t@Override\n\t\t\tpublic Instant nextExecution(TriggerContext triggerContext) {\n\t\t\t\treturn Instant.now();\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class CustomTriggeredRunnable implements Runnable {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tthrow new IllegalStateException(\"Failed while running custom task\");\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class TestTaskScheduler extends SimpleAsyncTaskScheduler {\n\n\t\t\tTestTaskScheduler() {\n\t\t\t\tsetThreadNamePrefix(\"test-\");\n\t\t\t\t// do not log task errors\n\t\t\t\tsetErrorHandler((throwable) -> {\n\t\t\t\t});\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/session/SessionsEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.session;\n\nimport java.time.Instant;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.ShutdownEndpoint;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.session.actuate.endpoint.SessionsEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.session.FindByIndexNameSessionRepository;\nimport org.springframework.session.MapSession;\nimport org.springframework.session.Session;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;\nimport static org.springframework.restdocs.request.RequestDocumentation.queryParameters;\n\n/**\n * Tests for generating documentation describing the {@link ShutdownEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass SessionsEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\tprivate static final Session sessionOne = createSession(Instant.now().minusSeconds(60 * 60 * 12),\n\t\t\tInstant.now().minusSeconds(45));\n\n\tprivate static final Session sessionTwo = createSession(\"4db5efcc-99cb-4d05-a52c-b49acfbb7ea9\",\n\t\t\tInstant.now().minusSeconds(60 * 60 * 5), Instant.now().minusSeconds(37));\n\n\tprivate static final Session sessionThree = createSession(Instant.now().minusSeconds(60 * 60 * 2),\n\t\t\tInstant.now().minusSeconds(12));\n\n\tprivate static final List<FieldDescriptor> sessionFields = List.of(\n\t\t\tfieldWithPath(\"id\").description(\"ID of the session.\"),\n\t\t\tfieldWithPath(\"attributeNames\").description(\"Names of the attributes stored in the session.\"),\n\t\t\tfieldWithPath(\"creationTime\").description(\"Timestamp of when the session was created.\"),\n\t\t\tfieldWithPath(\"lastAccessedTime\").description(\"Timestamp of when the session was last accessed.\"),\n\t\t\tfieldWithPath(\"maxInactiveInterval\")\n\t\t\t\t.description(\"Maximum permitted period of inactivity, in seconds, before the session will expire.\"),\n\t\t\tfieldWithPath(\"expired\").description(\"Whether the session has expired.\"));\n\n\t@MockitoBean\n\tprivate FindByIndexNameSessionRepository<Session> sessionRepository;\n\n\t@Test\n\tvoid sessionsForUsername() {\n\t\tMap<String, Session> sessions = new HashMap<>();\n\t\tsessions.put(sessionOne.getId(), sessionOne);\n\t\tsessions.put(sessionTwo.getId(), sessionTwo);\n\t\tsessions.put(sessionThree.getId(), sessionThree);\n\t\tgiven(this.sessionRepository.findByPrincipalName(\"alice\")).willReturn(sessions);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/sessions\").param(\"username\", \"alice\")).hasStatusOk()\n\t\t\t.apply(document(\"sessions/username\",\n\t\t\t\t\tresponseFields(fieldWithPath(\"sessions\").description(\"Sessions for the given username.\"))\n\t\t\t\t\t\t.andWithPrefix(\"sessions.[].\", sessionFields),\n\t\t\t\t\tqueryParameters(parameterWithName(\"username\").description(\"Name of the user.\"))));\n\t}\n\n\t@Test\n\tvoid sessionWithId() {\n\t\tgiven(this.sessionRepository.findById(sessionTwo.getId())).willReturn(sessionTwo);\n\t\tassertThat(this.mvc.get().uri(\"/actuator/sessions/{id}\", sessionTwo.getId())).hasStatusOk()\n\t\t\t.apply(document(\"sessions/id\", responseFields(sessionFields)));\n\t}\n\n\t@Test\n\tvoid deleteASession() {\n\t\tassertThat(this.mvc.delete().uri(\"/actuator/sessions/{id}\", sessionTwo.getId()))\n\t\t\t.hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.apply(document(\"sessions/delete\"));\n\t\tthen(this.sessionRepository).should().deleteById(sessionTwo.getId());\n\t}\n\n\tprivate static MapSession createSession(Instant creationTime, Instant lastAccessedTime) {\n\t\treturn createSession(UUID.randomUUID().toString(), creationTime, lastAccessedTime);\n\t}\n\n\tprivate static MapSession createSession(String id, Instant creationTime, Instant lastAccessedTime) {\n\t\tMapSession session = new MapSession(id);\n\t\tsession.setCreationTime(creationTime);\n\t\tsession.setLastAccessedTime(lastAccessedTime);\n\t\treturn session;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSessionsEndpoint endpoint(FindByIndexNameSessionRepository<?> sessionRepository) {\n\t\t\treturn new SessionsEndpoint(sessionRepository, sessionRepository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/startup/StartupEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.startup;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.startup.StartupEndpoint;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.restdocs.payload.PayloadDocumentation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\n\n/**\n * Tests for generating documentation describing {@link StartupEndpoint}.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n */\nclass StartupEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@BeforeEach\n\tvoid appendSampleStartupSteps(@Autowired BufferingApplicationStartup applicationStartup) {\n\t\tStartupStep starting = applicationStartup.start(\"spring.boot.application.starting\");\n\t\tstarting.tag(\"mainApplicationClass\", \"com.example.startup.StartupApplication\");\n\t\tStartupStep instantiate = applicationStartup.start(\"spring.beans.instantiate\");\n\t\tinstantiate.tag(\"beanName\", \"homeController\");\n\t\tinstantiate.end();\n\t\tstarting.end();\n\t}\n\n\t@Test\n\tvoid startupSnapshot() {\n\t\tassertThat(this.mvc.get().uri(\"/actuator/startup\")).hasStatusOk()\n\t\t\t.apply(document(\"startup-snapshot\", PayloadDocumentation.responseFields(responseFields())));\n\t}\n\n\t@Test\n\tvoid startup() {\n\t\tassertThat(this.mvc.post().uri(\"/actuator/startup\")).hasStatusOk()\n\t\t\t.apply(document(\"startup\", PayloadDocumentation.responseFields(responseFields())));\n\t}\n\n\tprivate FieldDescriptor[] responseFields() {\n\t\treturn new FieldDescriptor[] {\n\t\t\t\tfieldWithPath(\"springBootVersion\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Spring Boot version for this application.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"timeline.startTime\").description(\"Start time of the application.\"),\n\t\t\t\tfieldWithPath(\"timeline.events\")\n\t\t\t\t\t.description(\"An array of steps collected during application startup so far.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startTime\").description(\"The timestamp of the start of this event.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].endTime\").description(\"The timestamp of the end of this event.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].duration\").description(\"The precise duration of this event.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startupStep.name\").description(\"The name of the StartupStep.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startupStep.id\").description(\"The id of this StartupStep.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startupStep.parentId\")\n\t\t\t\t\t.description(\"The parent id for this StartupStep.\")\n\t\t\t\t\t.optional(),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startupStep.tags\")\n\t\t\t\t\t.description(\"An array of key/value pairs with additional step info.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startupStep.tags[].key\")\n\t\t\t\t\t.description(\"The key of the StartupStep Tag.\"),\n\t\t\t\tfieldWithPath(\"timeline.events.[].startupStep.tags[].value\")\n\t\t\t\t\t.description(\"The value of the StartupStep Tag.\") };\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tStartupEndpoint startupEndpoint(BufferingApplicationStartup startup) {\n\t\t\treturn new StartupEndpoint(startup);\n\t\t}\n\n\t\t@Bean\n\t\tBufferingApplicationStartup bufferingApplicationStartup() {\n\t\t\treturn new BufferingApplicationStartup(16);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/web/exchanges/HttpExchangesEndpointDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.web.exchanges;\n\nimport java.net.URI;\nimport java.security.Principal;\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangesEndpoint;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.boot.actuate.web.exchanges.RecordableHttpRequest;\nimport org.springframework.boot.actuate.web.exchanges.RecordableHttpResponse;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Tests for generating documentation describing {@link HttpExchangesEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass HttpExchangesEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {\n\n\t@MockitoBean\n\tprivate HttpExchangeRepository repository;\n\n\t@Test\n\tvoid httpExchanges() {\n\t\tRecordableHttpRequest request = mock(RecordableHttpRequest.class);\n\t\tgiven(request.getUri()).willReturn(URI.create(\"https://api.example.com\"));\n\t\tgiven(request.getMethod()).willReturn(\"GET\");\n\t\tgiven(request.getHeaders())\n\t\t\t.willReturn(Collections.singletonMap(HttpHeaders.ACCEPT, List.of(\"application/json\")));\n\t\tRecordableHttpResponse response = mock(RecordableHttpResponse.class);\n\t\tgiven(response.getStatus()).willReturn(200);\n\t\tgiven(response.getHeaders())\n\t\t\t.willReturn(Collections.singletonMap(HttpHeaders.CONTENT_TYPE, List.of(\"application/json\")));\n\t\tPrincipal principal = mock(Principal.class);\n\t\tgiven(principal.getName()).willReturn(\"alice\");\n\t\tInstant instant = Instant.parse(\"2022-12-22T13:43:41.00Z\");\n\t\tClock start = Clock.fixed(instant, ZoneId.systemDefault());\n\t\tClock end = Clock.offset(start, Duration.ofMillis(23));\n\t\tHttpExchange exchange = HttpExchange.start(start, request)\n\t\t\t.finish(end, response, () -> principal, () -> UUID.randomUUID().toString(), EnumSet.allOf(Include.class));\n\t\tgiven(this.repository.findAll()).willReturn(List.of(exchange));\n\t\tassertThat(this.mvc.get().uri(\"/actuator/httpexchanges\")).hasStatusOk()\n\t\t\t.apply(document(\"httpexchanges\", responseFields(\n\t\t\t\t\tfieldWithPath(\"exchanges\").description(\"An array of HTTP request-response exchanges.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].timestamp\").description(\"Timestamp of when the exchange occurred.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].principal\").description(\"Principal of the exchange, if any.\")\n\t\t\t\t\t\t.optional(),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].principal.name\").description(\"Name of the principal.\").optional(),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].request.method\").description(\"HTTP method of the request.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].request.remoteAddress\")\n\t\t\t\t\t\t.description(\"Remote address from which the request was received, if known.\")\n\t\t\t\t\t\t.optional()\n\t\t\t\t\t\t.type(JsonFieldType.STRING),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].request.uri\").description(\"URI of the request.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].request.headers\")\n\t\t\t\t\t\t.description(\"Headers of the request, keyed by header name.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].request.headers.*.[]\").description(\"Values of the header\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].response.status\").description(\"Status of the response\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].response.headers\")\n\t\t\t\t\t\t.description(\"Headers of the response, keyed by header name.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].response.headers.*.[]\").description(\"Values of the header\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].session\").description(\"Session associated with the exchange, if any.\")\n\t\t\t\t\t\t.optional(),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].session.id\").description(\"ID of the session.\"),\n\t\t\t\t\tfieldWithPath(\"exchanges.[].timeTaken\").description(\"Time taken to handle the exchange.\"))));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tHttpExchangesEndpoint httpExchangesEndpoint(HttpExchangeRepository repository) {\n\t\t\treturn new HttpExchangesEndpoint(repository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/web/mappings/MappingsEndpointReactiveDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.web.mappings;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlersMappingDescriptionProvider;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.RestDocumentationContextProvider;\nimport org.springframework.restdocs.RestDocumentationExtension;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.GET;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n/**\n * Tests for generating documentation describing {@link MappingsEndpoint}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(RestDocumentationExtension.class)\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.main.web-application-type=reactive\")\nclass MappingsEndpointReactiveDocumentationTests extends AbstractEndpointDocumentationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\tprivate WebTestClient client;\n\n\t@BeforeEach\n\tvoid webTestClient(RestDocumentationContextProvider restDocumentation) {\n\t\tthis.client = WebTestClient.bindToServer()\n\t\t\t.filter(documentationConfiguration(restDocumentation).snippets().withDefaults())\n\t\t\t.baseUrl(\"http://localhost:\" + this.port)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\t@Test\n\tvoid mappings() {\n\t\tList<FieldDescriptor> requestMappingConditions = List.of(\n\t\t\t\trequestMappingConditionField(\"\").description(\"Details of the request mapping conditions.\").optional(),\n\t\t\t\trequestMappingConditionField(\".consumes\").description(\"Details of the consumes condition\"),\n\t\t\t\trequestMappingConditionField(\".consumes.[].mediaType\").description(\"Consumed media type.\"),\n\t\t\t\trequestMappingConditionField(\".consumes.[].negated\").description(\"Whether the media type is negated.\"),\n\t\t\t\trequestMappingConditionField(\".headers\").description(\"Details of the headers condition.\"),\n\t\t\t\trequestMappingConditionField(\".headers.[].name\").description(\"Name of the header.\"),\n\t\t\t\trequestMappingConditionField(\".headers.[].value\").description(\"Required value of the header, if any.\"),\n\t\t\t\trequestMappingConditionField(\".headers.[].negated\").description(\"Whether the value is negated.\"),\n\t\t\t\trequestMappingConditionField(\".methods\").description(\"HTTP methods that are handled.\"),\n\t\t\t\trequestMappingConditionField(\".params\").description(\"Details of the params condition.\"),\n\t\t\t\trequestMappingConditionField(\".params.[].name\").description(\"Name of the parameter.\"),\n\t\t\t\trequestMappingConditionField(\".params.[].value\")\n\t\t\t\t\t.description(\"Required value of the parameter, if any.\"),\n\t\t\t\trequestMappingConditionField(\".params.[].negated\").description(\"Whether the value is negated.\"),\n\t\t\t\trequestMappingConditionField(\".patterns\")\n\t\t\t\t\t.description(\"Patterns identifying the paths handled by the mapping.\"),\n\t\t\t\trequestMappingConditionField(\".produces\").description(\"Details of the produces condition.\"),\n\t\t\t\trequestMappingConditionField(\".produces.[].mediaType\").description(\"Produced media type.\"),\n\t\t\t\trequestMappingConditionField(\".produces.[].negated\").description(\"Whether the media type is negated.\"));\n\t\tList<FieldDescriptor> handlerMethod = List.of(\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod\").optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.description(\"Details of the method, if any, that will handle requests to this mapping.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod.className\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Fully qualified name of the class of the method.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod.name\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Name of the method.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod.descriptor\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Descriptor of the method as specified in the Java Language Specification.\"));\n\t\tList<FieldDescriptor> handlerFunction = List.of(\n\t\t\t\tfieldWithPath(\"*.[].details.handlerFunction\").optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.description(\"Details of the function, if any, that will handle requests to this mapping.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerFunction.className\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Fully qualified name of the class of the function.\"));\n\t\tList<FieldDescriptor> dispatcherHandlerFields = new ArrayList<>(List.of(\n\t\t\t\tfieldWithPath(\"*\")\n\t\t\t\t\t.description(\"Dispatcher handler mappings, if any, keyed by dispatcher handler bean name.\"),\n\t\t\t\tfieldWithPath(\"*.[].details\").optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.description(\"Additional implementation-specific details about the mapping. Optional.\"),\n\t\t\t\tfieldWithPath(\"*.[].handler\").description(\"Handler for the mapping.\"),\n\t\t\t\tfieldWithPath(\"*.[].predicate\").description(\"Predicate for the mapping.\")));\n\t\tdispatcherHandlerFields.addAll(requestMappingConditions);\n\t\tdispatcherHandlerFields.addAll(handlerMethod);\n\t\tdispatcherHandlerFields.addAll(handlerFunction);\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/mappings\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.consumeWith(document(\"mappings\", responseFields(\n\t\t\t\t\tbeneathPath(\"contexts.*.mappings.dispatcherHandlers\").withSubsectionId(\"dispatcher-handlers\"),\n\t\t\t\t\tdispatcherHandlerFields)));\n\t}\n\n\tprivate FieldDescriptor requestMappingConditionField(String path) {\n\t\treturn fieldWithPath(\"*.[].details.requestMappingConditions\" + path);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tNettyReactiveWebServerFactory netty() {\n\t\t\treturn new NettyReactiveWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {\n\t\t\treturn new DispatcherHandlersMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tMappingsEndpoint mappingsEndpoint(Collection<MappingDescriptionProvider> descriptionProviders,\n\t\t\t\tConfigurableApplicationContext context) {\n\t\t\treturn new MappingsEndpoint(descriptionProviders, context);\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> exampleRouter() {\n\t\t\treturn route(GET(\"/foo\"), (request) -> ServerResponse.ok().build());\n\t\t}\n\n\t\t@Bean\n\t\tExampleController exampleController() {\n\t\t\treturn new ExampleController();\n\t\t}\n\n\t}\n\n\t@RestController\n\tstatic class ExampleController {\n\n\t\t@PostMapping(path = \"/\", consumes = { MediaType.APPLICATION_JSON_VALUE, \"!application/xml\" },\n\t\t\t\tproduces = MediaType.TEXT_PLAIN_VALUE, headers = \"X-Custom=Foo\", params = \"a!=alpha\")\n\t\tString example() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/java/org/springframework/boot/actuate/docs/web/mappings/MappingsEndpointServletDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.docs.web.mappings;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.servlet.actuate.web.mappings.FiltersMappingDescriptionProvider;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletsMappingDescriptionProvider;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletsMappingDescriptionProvider;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.restdocs.RestDocumentationContextProvider;\nimport org.springframework.restdocs.RestDocumentationExtension;\nimport org.springframework.restdocs.payload.FieldDescriptor;\nimport org.springframework.restdocs.payload.JsonFieldType;\nimport org.springframework.restdocs.payload.ResponseFieldsSnippet;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.servlet.function.RouterFunction;\nimport org.springframework.web.servlet.function.RouterFunctions;\nimport org.springframework.web.servlet.function.ServerResponse;\n\nimport static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration;\nimport static org.springframework.web.servlet.function.RequestPredicates.GET;\n\n/**\n * Tests for generating documentation describing {@link MappingsEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Xiong Tang\n */\n@ExtendWith(RestDocumentationExtension.class)\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\nclass MappingsEndpointServletDocumentationTests extends AbstractEndpointDocumentationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\tprivate WebTestClient client;\n\n\t@BeforeEach\n\tvoid webTestClient(RestDocumentationContextProvider restDocumentation) {\n\t\tthis.client = WebTestClient.bindToServer()\n\t\t\t.filter(documentationConfiguration(restDocumentation))\n\t\t\t.baseUrl(\"http://localhost:\" + this.port)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\t@Test\n\tvoid mappings() {\n\t\tResponseFieldsSnippet commonResponseFields = responseFields(\n\t\t\t\tfieldWithPath(\"contexts\").description(\"Application contexts keyed by id.\"),\n\t\t\t\tfieldWithPath(\"contexts.*.mappings\").description(\"Mappings in the context, keyed by mapping type.\"),\n\t\t\t\tsubsectionWithPath(\"contexts.*.mappings.dispatcherServlets\")\n\t\t\t\t\t.description(\"Dispatcher servlet mappings, if any.\"),\n\t\t\t\tsubsectionWithPath(\"contexts.*.mappings.servletFilters\")\n\t\t\t\t\t.description(\"Servlet filter mappings, if any.\"),\n\t\t\t\tsubsectionWithPath(\"contexts.*.mappings.servlets\").description(\"Servlet mappings, if any.\"),\n\t\t\t\tsubsectionWithPath(\"contexts.*.mappings.dispatcherHandlers\")\n\t\t\t\t\t.description(\"Dispatcher handler mappings, if any.\")\n\t\t\t\t\t.optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT),\n\t\t\t\tparentIdField());\n\t\tList<FieldDescriptor> dispatcherServletFields = new ArrayList<>(List.of(\n\t\t\t\tfieldWithPath(\"*\")\n\t\t\t\t\t.description(\"Dispatcher servlet mappings, if any, keyed by dispatcher servlet bean name.\"),\n\t\t\t\tfieldWithPath(\"*.[].details\").optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.description(\"Additional implementation-specific details about the mapping. Optional.\"),\n\t\t\t\tfieldWithPath(\"*.[].handler\").description(\"Handler for the mapping.\"),\n\t\t\t\tfieldWithPath(\"*.[].predicate\").description(\"Predicate for the mapping.\")));\n\t\tList<FieldDescriptor> requestMappingConditions = List.of(\n\t\t\t\trequestMappingConditionField(\"\").description(\"Details of the request mapping conditions.\").optional(),\n\t\t\t\trequestMappingConditionField(\".consumes\").description(\"Details of the consumes condition\"),\n\t\t\t\trequestMappingConditionField(\".consumes.[].mediaType\").description(\"Consumed media type.\"),\n\t\t\t\trequestMappingConditionField(\".consumes.[].negated\").description(\"Whether the media type is negated.\"),\n\t\t\t\trequestMappingConditionField(\".headers\").description(\"Details of the headers condition.\"),\n\t\t\t\trequestMappingConditionField(\".headers.[].name\").description(\"Name of the header.\"),\n\t\t\t\trequestMappingConditionField(\".headers.[].value\").description(\"Required value of the header, if any.\"),\n\t\t\t\trequestMappingConditionField(\".headers.[].negated\").description(\"Whether the value is negated.\"),\n\t\t\t\trequestMappingConditionField(\".methods\").description(\"HTTP methods that are handled.\"),\n\t\t\t\trequestMappingConditionField(\".params\").description(\"Details of the params condition.\"),\n\t\t\t\trequestMappingConditionField(\".params.[].name\").description(\"Name of the parameter.\"),\n\t\t\t\trequestMappingConditionField(\".params.[].value\")\n\t\t\t\t\t.description(\"Required value of the parameter, if any.\"),\n\t\t\t\trequestMappingConditionField(\".params.[].negated\").description(\"Whether the value is negated.\"),\n\t\t\t\trequestMappingConditionField(\".patterns\")\n\t\t\t\t\t.description(\"Patterns identifying the paths handled by the mapping.\"),\n\t\t\t\trequestMappingConditionField(\".produces\").description(\"Details of the produces condition.\"),\n\t\t\t\trequestMappingConditionField(\".produces.[].mediaType\").description(\"Produced media type.\"),\n\t\t\t\trequestMappingConditionField(\".produces.[].negated\").description(\"Whether the media type is negated.\"));\n\t\tList<FieldDescriptor> handlerMethod = List.of(\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod\").optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.description(\"Details of the method, if any, that will handle requests to this mapping.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod.className\")\n\t\t\t\t\t.description(\"Fully qualified name of the class of the method.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod.name\").description(\"Name of the method.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerMethod.descriptor\")\n\t\t\t\t\t.description(\"Descriptor of the method as specified in the Java Language Specification.\"));\n\t\tList<FieldDescriptor> handlerFunction = List.of(\n\t\t\t\tfieldWithPath(\"*.[].details.handlerFunction\").optional()\n\t\t\t\t\t.type(JsonFieldType.OBJECT)\n\t\t\t\t\t.description(\"Details of the function, if any, that will handle requests to this mapping.\"),\n\t\t\t\tfieldWithPath(\"*.[].details.handlerFunction.className\").type(JsonFieldType.STRING)\n\t\t\t\t\t.description(\"Fully qualified name of the class of the function.\"));\n\t\tdispatcherServletFields.addAll(handlerFunction);\n\t\tdispatcherServletFields.addAll(handlerMethod);\n\t\tdispatcherServletFields.addAll(requestMappingConditions);\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/mappings\")\n\t\t\t.exchange()\n\t\t\t.expectBody()\n\t\t\t.consumeWith(document(\"mappings\", commonResponseFields,\n\t\t\t\t\tresponseFields(beneathPath(\"contexts.*.mappings.dispatcherServlets\")\n\t\t\t\t\t\t.withSubsectionId(\"dispatcher-servlets\"), dispatcherServletFields),\n\t\t\t\t\tresponseFields(\n\t\t\t\t\t\t\tbeneathPath(\"contexts.*.mappings.servletFilters\").withSubsectionId(\"servlet-filters\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].servletNameMappings\")\n\t\t\t\t\t\t\t\t.description(\"Names of the servlets to which the filter is mapped.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].urlPatternMappings\")\n\t\t\t\t\t\t\t\t.description(\"URL pattern to which the filter is mapped.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].name\").description(\"Name of the filter.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].className\").description(\"Class name of the filter\")),\n\t\t\t\t\tresponseFields(beneathPath(\"contexts.*.mappings.servlets\").withSubsectionId(\"servlets\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].mappings\").description(\"Mappings of the servlet.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].name\").description(\"Name of the servlet.\"),\n\t\t\t\t\t\t\tfieldWithPath(\"[].className\").description(\"Class name of the servlet\"))));\n\t}\n\n\tprivate FieldDescriptor requestMappingConditionField(String path) {\n\t\treturn fieldWithPath(\"*.[].details.requestMappingConditions\" + path);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServletsMappingDescriptionProvider dispatcherServletsMappingDescriptionProvider() {\n\t\t\treturn new DispatcherServletsMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tServletsMappingDescriptionProvider servletsMappingDescriptionProvider() {\n\t\t\treturn new ServletsMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tFiltersMappingDescriptionProvider filtersMappingDescriptionProvider() {\n\t\t\treturn new FiltersMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tMappingsEndpoint mappingsEndpoint(Collection<MappingDescriptionProvider> descriptionProviders,\n\t\t\t\tConfigurableApplicationContext context) {\n\t\t\treturn new MappingsEndpoint(descriptionProviders, context);\n\t\t}\n\n\t\t@Bean\n\t\tExampleController exampleController() {\n\t\t\treturn new ExampleController();\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> exampleRouter() {\n\t\t\treturn RouterFunctions.route(GET(\"/foo\"), (request) -> ServerResponse.ok().build());\n\t\t}\n\n\t}\n\n\t@RestController\n\tstatic class ExampleController {\n\n\t\t@PostMapping(path = \"/\", consumes = { MediaType.APPLICATION_JSON_VALUE, \"!application/xml\" },\n\t\t\t\tproduces = MediaType.TEXT_PLAIN_VALUE, headers = \"X-Custom=Foo\", params = \"a!=alpha\")\n\t\tString example() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/resources/org/springframework/boot/actuate/docs/env/application.properties",
    "content": "com.example.cache.max-size: 1000\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/resources/org/springframework/boot/actuate/docs/flyway/V1__init.sql",
    "content": "DROP TABLE IF EXISTS TEST;\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/resources/org/springframework/boot/actuate/docs/liquibase/db.changelog-master.yaml",
    "content": "databaseChangeLog:\n  - changeSet:\n      id: 1\n      author: marceloverdijk\n      changes:\n        - createTable:\n            tableName: customer\n            columns:\n              - column:\n                  name: id\n                  type: int\n                  autoIncrement: true\n                  constraints:\n                    primaryKey: true\n                    nullable: false\n              - column:\n                  name: name\n                  type: varchar(50)\n                  constraints:\n                    nullable: false\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/resources/org/springframework/boot/actuate/docs/logging/sample.log",
    "content": "  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::\n\n2017-08-08 17:12:30.910  INFO 19866 --- [           main] s.f.SampleWebFreeMarkerApplication       : Starting SampleWebFreeMarkerApplication with PID 19866\n2017-08-08 17:12:30.913  INFO 19866 --- [           main] s.f.SampleWebFreeMarkerApplication       : No active profile set, falling back to default profiles: default\n2017-08-08 17:12:30.952  INFO 19866 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@76b10754: startup date [Tue Aug 08 17:12:30 BST 2017]; root of context hierarchy\n2017-08-08 17:12:31.878  INFO 19866 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)\n2017-08-08 17:12:31.889  INFO 19866 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]\n2017-08-08 17:12:31.890  INFO 19866 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.16\n2017-08-08 17:12:31.978  INFO 19866 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext\n2017-08-08 17:12:31.978  INFO 19866 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1028 ms\n2017-08-08 17:12:32.080  INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]\n2017-08-08 17:12:32.084  INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]\n2017-08-08 17:12:32.084  INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]\n2017-08-08 17:12:32.084  INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]\n2017-08-08 17:12:32.084  INFO 19866 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]\n2017-08-08 17:12:32.349  INFO 19866 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@76b10754: startup date [Tue Aug 08 17:12:30 BST 2017]; root of context hierarchy\n2017-08-08 17:12:32.420  INFO 19866 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped \"{[/error]}\" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(jakarta.servlet.http.HttpServletRequest)\n2017-08-08 17:12:32.421  INFO 19866 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped \"{[/error],produces=[text/html]}\" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(jakarta.servlet.http.HttpServletRequest,jakarta.servlet.http.HttpServletResponse)\n2017-08-08 17:12:32.444  INFO 19866 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]\n2017-08-08 17:12:32.444  INFO 19866 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]\n2017-08-08 17:12:32.471  INFO 19866 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]\n2017-08-08 17:12:32.600  INFO 19866 --- [           main] o.s.w.s.v.f.FreeMarkerConfigurer         : ClassTemplateLoader for Spring macros added to FreeMarker configuration\n2017-08-08 17:12:32.681  INFO 19866 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup\n2017-08-08 17:12:32.744  INFO 19866 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http)\n2017-08-08 17:12:32.750  INFO 19866 --- [           main] s.f.SampleWebFreeMarkerApplication       : Started SampleWebFreeMarkerApplication in 2.172 seconds (JVM running for 2.479)\n"
  },
  {
    "path": "documentation/spring-boot-actuator-docs/src/test/resources/org/springframework/boot/actuate/docs/sbom/cyclonedx.json",
    "content": "{\n  \"bomFormat\" : \"CycloneDX\",\n  \"specVersion\" : \"1.5\",\n  \"serialNumber\" : \"urn:uuid:13862013-3360-43e5-8055-3645aa43c548\",\n  \"version\" : 1,\n  \"metadata\" : {\n    \"timestamp\" : \"2024-01-12T11:10:49Z\",\n    \"tools\" : [\n      {\n        \"vendor\" : \"CycloneDX\",\n        \"name\" : \"cyclonedx-gradle-plugin\",\n        \"version\" : \"1.8.1\"\n      }\n    ],\n    \"component\" : {\n      \"group\" : \"org.example\",\n      \"name\" : \"cyclonedx\",\n      \"version\" : \"0.0.1-SNAPSHOT\",\n      \"purl\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\"\n    }\n  },\n  \"components\" : [\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-aop\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring AOP\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c9b8757051ed6c1cc9fda0e379283348\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a247bd81df8fa9c6a002b95969692bfd146a70b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e47b66833ebec281374d55b4e36352b80fe3fa64c94252481a8a7e8d31d9d601\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1cb69feb2931bd4af48b2329614f8e2a0d1afe77267af5f5ea9717ab24c83fd524c8bc7aa8d357a6ccbc497535c4fd282ddfb6d78364a349895a14825af8b9c\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"09c3c2711a054993922d28b76357c376649a942bf0d7410915e540339c3fa42d5a498211b02e0b09493e68fac7a0d833\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b30a6ea50e454373bd74779d983fc941bb1775368ea67ff0464edbdf0dd3d1c137760bee64a620bd51daf5b65281f15e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"291404410acd2cfbcc804bd91a9777276f622fb3b82788298254c0bf1856b49f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8101ef2cc88af43b2bfc6126547de4e4a4cc29bf49bffd83aa9d299cab9e9cdb6a5246d46c00119dd88ca02dbf7959c3076dbd32d23e8e1366144ccbbda13316\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jdk8\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support JDK 8 data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3b6579ff944e128c4eccb34e76ff67e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"80158cb020c7bd4e4ba94d8d752a65729dc943b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"29995d3677f72dde74bf32bbf268b96beb952492b742d93f4c70af6c44b2156e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1b13d4f0a955af18a2c68ca45deca79c38d7f9f065d7053bddf2a3dc2fafe729b3355676f7442012451e363aa0da0cd8a0b7a44ded7057cf513df98a475cbbf6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a29961097a15d3aeabc1ab870699dce827511df9902fc66fe9f836d294c8cea68617498d52fe7dbe920bb5c745f2789\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"55570097f9979197eafda91156db909f25dd1b37387656893564060a673dcbc6d85c1f5dc6fd5c8b379b48a4974e6757\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"362c3a494e16016f7adc3f512ebe8c8f8da4dbdfc1ca285d05ac085a9198258f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1aebbe19a11236b7dbf85fd4c457e1a9b5a60fad9c818cc9fd462d7eb489dd5d3a378b4c7c42c6e3777e0b70263968c964cf1aaf8247fc97ec445481af2418a8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apiguardian\",\n      \"name\" : \"apiguardian-api\",\n      \"version\" : \"1.1.2\",\n      \"description\" : \"@API Guardian\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8c7de3f82037fa4a2e8be2a2f13092af\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a231e0d844d2721b0fa1b238006d15c6ded6842a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d7ccd0e7019f1a997de39d66dc0ad4efe150428fdd7f4c743c93884f1602a3e90135ad34baea96d5b6d925ad6c0c8487c8e78304f0a089a12383d4a62e2c9a61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ae11cfedcee7da43a506a67946ddc8a7a2622284a924ba78f74541e9a22db6868a15f5d84edb91a541e38afded734ea\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c146116b3dfd969200b2ce52d96b92dd02d6f5a45a86e7e85edf35600ddbc2f3c6e8a1ad7e2db4dcd2c398c09fad0927\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b4b436d7f615fc0b820204e69f83c517d1c1ccc5f6b99e459209ede4482268de\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7b95b7ac68a6891b8901b5507acd2c24a0c1e20effa63cd513764f513eab4eb55f8de5178edbe0a400c11f3a18d3f56243569d6d663100f06dd98288504c09c5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/apiguardian-team/apiguardian\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.annotation\",\n      \"name\" : \"jakarta.annotation-api\",\n      \"version\" : \"2.1.1\",\n      \"description\" : \"Jakarta Annotations API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5dac2f68e8288d0add4dc92cb161711d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5f65fdaf424eee2b55e1d882ba9bb376be93fb09b37b808be6e22e8851c909fe\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eabe8b855b735663684052ec4cc357cc737936fa57cebf144eb09f70b3b6c600db7fa6f1c93a4f36c5994b1b37dad2dfcec87a41448872e69552accfd7f52af6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"798597a6b80b423844d70609c54b00d725a357031888da7e5c3efd3914d1770be69aa7135de13ddb89a4420a5550e35b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9629b8ca82f61674f5573723bbb3c137060e1442062eb52fa9c90fc8f57ea7d836eb2fb765d160ec8bf300bcb6b820be\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f71ffc2a2c2bd1a00dfc00c4be67dbe5f374078bd50d5b24c0b29fbcc6634ecb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa4e29025a55878db6edb0d984bd3a0633f3af03fa69e1d26c97c87c6d29339714003c96e29ff0a977132ce9c2729d0e27e36e9e245a7488266138239bdba15e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"GPL-2.0-with-classpath-exception\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://dev.eclipse.org/mhonarc/lists/ca-dev\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-annotations\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core annotations used for value types, used by Jackson data binding package.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f478f693731e4a2f0f0d3c7bba119b32\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"79baf4e605eb3bbb60b1c475d44a7aecceea1d60\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"aae865c3d88256d61b11523cb1e88bd48d5b9ad5855fa1fc859504fd2204708a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c496afd736fa8acbf8126887e2ff375f162212f451326451fbb4b9194231d814e25bccacbaead9db98beec454f6b8d9ed706c5c88e2145bf7e1a37e13fd81af0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"13b4d153cc113a69008147974d8887f868f2f3f0a551ef0bacaccf0add17a3168465a94a471e075913f9c6649980a3cb\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"dcf8ed73f748eb32e1ab25eba3c294344cc0ddb2cc7bb4376814f1866df42c3093f1336291ce9ed9e1c8730663e0017c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"59f42bc85ee3a8a5b422085b0462aed2a770cf52d7a3660f2cd6dd257ec6e694\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1d1a6fd0e6851d419e79f82170f4060981c233ec8dc61656b84ce7988e9b71bbeecd7364cdadac066ddaf0b3de4dc8aa5acc411ebd1641f549a3af5ba214667b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-annotations\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-jcl\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Commons Logging Bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1638acc7030a001c37f803185dbd6eaf\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"285eb725861c9eacf2a3e4965d4e897932e335ea\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"eb9ebadb1581f0fe598216f7cf032a3b44a84c96de06ffa8d6f41bcc47305134\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2e80d7485b7ad4de6cc372d86ed73db9808be6a5a33e3c9fabccc7915fe57b73011bed75b4567c44456fedad5ae2186658a7f5cc331b4aad64e2a7cc78acdcfa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a6a6422a6c2654eff951af0d6dfb6e93501bdcb4e38ec353d515ca8de919a34b9e1fe37c562106f3f33f844cf071e010\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71098eb263af3ab42d93b8e7a96ceb90fb2069f2ecca85754e702b82f9876255abf5e3f9b48beb4a200f2d9e13599794\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"7f49ddd5db9841bb2d7ca8cb5ce52fa1e8982c7c37bc0c6e987eca8f5fc70d38\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4a417d058ecd3619a9716c5d47ecc506f4cb9c3684ee589c443c7b7996b630949932295186135cb3ce5fb0154c29436de4b6c1dbf7f135563449050973510200\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-webmvc\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web MVC\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0fcf00ac160e0d42ad9cd242c796e47a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"906ee995372076e22ef9666d8628845c75bf5c42\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de42748c3c94c06131c3fe97d81f5c685e4492b9e986baa88af768bb12ea7738\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8e7ad7afa2a605d8dbb6cb36c11caf0e626a5ca5849c06f0b35524e5ad6a13eec1ddff8625e1cc278b3082555a940ec3865657828458ab8d60d1c99d513aba0f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ec328ff12f857baf85ce6f44c849f8818658aaabb4e4d0940ea6b5ad2b009ce3c7717b6b02843f641f8125d0cec4291\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"75605b286d839df688bbfb9594dbb83d1eb22f2cae52a6f4b35d485e91ab94a55e94158086684ef3b059f1346af6dc85\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2e67bcc31eede462f5105a09dbf5b40a3e0ccc52d637c6e2720b43412da01525\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d7c5330069c3c0f5eda1417a52384a4b5adc4451c405315a992ed147f26466a19487ffc5e39b90a1ec4cb0df3f804a4d26203f9aaf4e74cf906d1e811abfbf3b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-websocket\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cfc1778713fba9b5bc33d3db64071dff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ee2f34b51144b75878c9b42768e17de8fbdc74b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"00b16e507bea58c6e8a7cb64f129cd2ffd62da092a67a693a8a6af1efdc7dd6d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"72da073d4ec4f7473c9a91b4d11607d02a3d18ca8af10348f9130a280f898814625a5865cb44244e6be6d6ab915099805bf06a60f80fd9b8ff2c47840d5266e9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f4c1d108ca60a7a658839b8ac45eba94354ad20e641d36d2ecf777bac252d371df1e8806a5460ccaf9da222f72a4a9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2d0703de58338d38fbae7f4a38390a766d66e3875e3a6a7f2620ae478c838c8f306a39cdac8652890e1116a3859e56e1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e594abbc4cb6dc0896c08a89cb3fa376980587d5995bace2b3c0798d99c1e454\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3a35964398627fc8bcd323dd9fb6d4e51ea183b704074320822906c074aeb50a0f8732e42b98bdad9c5f0aa4eb421da96dde7e97f094ccdbcb70f668c6d4ff6e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"Byte Buddy is a Java library for creating Java classes at run time. This artifact is a build of Byte Buddy with all ASM dependencies repackaged into its own name space.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4e5bd83559bf8533b51f92dcd911d16c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8117daf4a612122eb4f517f66adff778cb8b4737\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"30e6e0446437a67db37e2b7f7d33f50787ddfd970359319dfd05469daa2dcbce\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"583512f3c47513cf17735aad4e600be44c97e9978c9f6a45227de8a160a879960b1fe01672751e7583176935e0db5477aba581bf68ef5c94f52436a0683a306e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"efcce5a139f498de410e182a52e5b2465823a2ebf845001c9a733d87418118342c3854d00a0fae7945ae8dcb1916ba90\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cace3217b1c2c77a4bc194ecc602a28886d9e448efa26b1985e9fd09d90c92bc2e1b50ed70475106ddf266f8c2d14160\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"71647273afb1561b70d2cfa519f707a98711f9ae5b891249ae5803c00c25a788\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4aba6f5dcac177c8f8aed902307c62916c32be61841adcf12b9c9885de2de9795a965c0b939729ed67ee7d49b0fbfaf0dfd922be1bf1cdbfbe7b1f09e083831b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d6f93aa42df4cb27a58835750597d835\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bfc34c523b3ab295fb01f46373e903f9729cdd43\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"86c51c743babfc591be09af7fedcd778410706e567e9ed27218448ccd2297ef4\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"701b6ee27c87081e4a65ba76fe721f74e917a655575b19b9205b314f4a561889564e09ceadaa880aaf30f70cd8b48dc70fc5e32f511204b1ea031a12349fd9be\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"74d4cf202399e946789a5572007aa4fbf1daf26cfac27f83a3d8550711f99700083029b1f900037b8f263543ac9824a1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ac0b64ec94b558b4f806c09f68247eff80bcc8e33b97f5d09f5517a2339187e4b11c8e2287400a173cb128e3fdb4ab06\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5ca85cd0c052076d625c262cf445e4e8fb255b13323ba4ab08cbfcf32ec236b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"04ce88c724852938057c723a7ec637af2f8e601879a592a6fe135eaa26940f8fd9d9ac8f6917e761cb0ff31547bb849ff88a66e1f6e93c1032a4009fe1fdef1d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-json\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for reading and writing json\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"bea54cf408b022894c0b1b013c58c0a9\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ecda50de20ab6d3c49ea30df4c1982048f5d31ac\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"572f1a4171dff33b5a9260bbd704473442adf24f890386abe33ecc18c047836a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c611e0d07093d99dbcded7a00e7c00355a7c13c24a69d33105ca88ec63cc68ba76339b5a96b84f2b666bb883849980776e1e24ee2df9c7dd07b2dde0992289b5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed40ffb527cf8442dbe3eb7b542970317e4827ed00196387d78f123490a77b08b3bc2fd5f53b83f6bee1d4eed29215bf\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"26d5852f479f1c72f501569a8ea0c0e4c93f9049676921dca94b467e68f221214e4485c41647e6a92005e5090a6a7c80\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"dc69eefb2f1441bbec58c219ccedd895b863b1e1d25cc3805936f0c9b072f2e6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bf6fce60937e78550fb3d411c19aad2200d8129138fade809e9d0abc307c7f06b54732f1e94fa86ebb82d4da0293f7bce43345416b3fdae1b3c2edbac6706310\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jsr310\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module to support JSR-310 (Java 8 Date & Time API) data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"acd8ae6da000eb831a69b4acdc182b7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4a20a0e104931bfa72f24ef358c2eb63f1ef2aaf\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bea1d78009ebc4e5d54918a3f7aec5da9fbd09f662c191a217ffcf37e8527c5e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1c5bde6c91a2a89f3c1f231f4e17c435063d9012babbfcba509a3b25363b1fd99f0dcd4234f1e00559e43d3dc8e6c71834282c72f2ebf15484ae900754c5d757\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cc72f54d89bc0f7ffae9af36dfba38e5a61ac83db2f0d8de3c74e405a0bfd77b6d463217ece19c64eeb16291d80a69f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"096944bac7583e5c97e8afcfbc928ca4a87a7d3e5eb74cc77394a19ca8bc6f26185da7fdf5d6bd2179582bf51940edc5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"0301cf719fd327643b3228b91c36688aaea3fccf3487c3e09bae3de636340dc7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b9a4a8c9785e8ec2786690bfede18c76e08d81fc9c77bb2dad88e1a034f97f7d20020531ac1cb9b0b6e61645b08ea441aba35fc0732edc2fc1dc4b36d6f1695c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.hdrhistogram\",\n      \"name\" : \"HdrHistogram\",\n      \"version\" : \"2.1.12\",\n      \"description\" : \"HdrHistogram supports the recording and analyzing sampled data value counts across a configurable integer value range with configurable value precision within the range. Value precision is expressed as the number of significant digits in the value recording, and provides control over value quantization behavior across the value range and the subsequent value resolution at any given level.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4b1acf3448b750cb485da7e37384fcd8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9b47fbae444feaac4b7e04f0ea294569e4bc282bc69d8c2ce2ac3f23577281e2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b03b7270eb7962c88324858f94313adb3a53876f1e11568a78a5b7e00a9419e4d7ab8774747427bff6974b971b6dfc47a127fca11cb30eaf7d83b716e09b1a0d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"06977d680dafd803d32441994474e598384a584411a67c95ab4a64698c9e4cbd613e0119b54685cea275b507a0a6f362\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b5ccb4d39bf7cc8ccc33f0f8fcbab0a63c99a94feda840b5d80fc3ae061127f1475cfb869b060933783a1f2eafb103a1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ef2113f27862af1d24d90c2028fc566902720248468d3c0f2f1807cc86918882\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4fca2f75bdfd3f2ac40dc227ae2ef0272142802b1546d4f5edf9155eaeed84eff07b0c3a978291a1df096ec94724b0defb045365e6a51acfdd5da68d72c5a8eb\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"BSD-2-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-2-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/HdrHistogram/HdrHistogram/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/HdrHistogram/HdrHistogram.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-commons\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing common code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2518ae277e56aea5e37e3fc2f578dfa4\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abcc6b294e60582afdfae6c559c94ad1d412ce2d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"295785b04cd4de7711bb16730da5e9829bac55a8879d52120625dac6c89904ed\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"25d65699a25fe3b90de17a0539233fdad37df864f6d493475976e9a513bd7767520a882cbf6bbd98714a1fe94acdb77a160cd68f549475d2b93624ffe8672a00\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8523ae45ce6dd4a068cce108cd31da24629839d3d293fca92353cf45db9eae88107744c9e66b82ed14abb96782c562da\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9af1fc3aad2d0131c337b843c38b05510d31e7931a48841a4bdb618257f185286ed393f8a4418ae4c5f91da7f9c76cbf\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d5dbeadc5f629430202c81a6736dff2efbfbf3ea2c09844b1194f316772a93f7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c7b1dd1727000936bf51c02f9bf9b262a412e2b815531df4a9f7aad675ef0f728d4492327a404b37b1ef36d41a240b83dbfeea3367b3b4faa22cdc2decc5bac9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-core\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito mock objects library core API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4df8dd230071bc192161d0e54a76f6b5\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a1c258331ab91d66863c983aff7136357e9de056\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dbad5e746654910a11a59ecb4d01e38461f3e5d16161689dc2588d5554432521\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5a2f00df2b1b2dbca06686f88806b86990f1eea6f7c25281c0e7ec7cf7904a0a9227477279b11630d80f8e88d6b6e9dbdb40ad094a4077cc6a44cd2072d12662\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f2caa05fe4a5d5b385654ce60d0655724200fdd333652459b86848c3b895a9ad0b0daca8a014851d6b5c744cd0e9372\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"06ba4583220a4aaa47d79ccab11783d48900d8850a346e4a1efc61c057630fcf0bb9c95cec74833ab5e6ee08e55625ec\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f1f9899edf629fffaf8b4483ac04430945996393f4fdcedc38eba22a9a5c715d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d6f479d52534b382088012e3d1a83fa267dfb046322a72e84438d21973165617d1d710bb42f1cb2d2d3d7f891969320232031be33f4abb2ea1526217e16e8c63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3afea56b25f872cee2c929c761b0790d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0fe81034352a15731322fba326447ba70bfa3962\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3850d85c0f6074fe9286dece9b44f8bded5e194e9b816860735e0fc728173d65\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7197158ef14a580edc836ab7af10a9f5f567ba60e21267b624fc4143debd2638c7b8bd8e2e5973fdd5c5d512be73df96500fb0a4273f20a21b42161e9f7add75\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4a35eb1f124d8d7812d32f87b16a24dd56d4cb43278ce66f216f4a4af34db357e7481fc1b26de9bde7c2dd6847687721\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8369a8b49cae80b92abbfcc0218d55b9cecd86778735c66b9b0cc6fbc7251784725249392e716c314e3ec08c995557bb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ee742160e4951e1f6145d575f6c6ebb908a46f38a8b3b81b7d61aac7c111a87f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"dcb1b214577203c9b3e2e5dcb3aaef8e46aec5f75a40a606f42e230c6e1af39c37250d58de6bf694c5a62d70fb1a6dcba436d696f71d7aa1a52b9f4dea5aa9a9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-tomcat\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"db4df0f653e84bfd545894c4567b19ff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d8efc48034015522958cb3fea5831b4cbcd4fcfb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bf93da73a8fb4caf9fa68e4f3b97adcc9dbb8c79220a828b3d70ecf12d410117\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d2bce5bb0271525766283e17160513de530c20e0452cecc3c9d5be3890986cc071c1423a3c11c54a36d2f83bd3a238b0fcbcc6218976a5633f0753a313418f6f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1f9ae7504b1345595377a4d35163315824dcf25f29ac9d522385e6e1672b813719655989708eb03b419e808f1f102be9\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9d890c3314b5ec30f39de30bf70471aef5f19e64d6d2f60b6fe66b3c57978bbda0a981cf92e42f18f27b72ed2ddb3574\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"43d38219fbe556c2bac8670fa0aa4f89e2ac273fda77d8bceac8d9d34d7b27c2\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"6a4e9a2ff89293c60c8a05cb79a65695dbe9823978be93f1b309d702338f87f108aabeaeafe8ff0ebf08bcd5483efbbb4a85c566e1357acd1d2fab565c910a80\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-to-slf4j\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j binding between Log4j 2 API and SLF4J.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"00b957af4a40bea6a7bf61400b6ccf63\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d77b2ba81711ed596cd797cc2b5b5bd7409d841c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de143c565ba78b0f2c0be58f132c7aec75e6e1a10845ebda5a4f17c2a35d9990\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8a7a682dc5ae6a123c8de6002f1470ad2682795c65b47b06397d9ad9a31729e588c406013bfa989f9c2a51750c353cd7a147bc036f2d66b0f8f0b3f13798a637\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8f3e4f1eea069f47b2c6111f1233448ea9ccc723b7c8a8bd308b7317a6ec1f47008d2952c1cb274152a38d3e21da750b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"822f93c3bba450b89a7f64b4d81aab48a7f5c2f693b53a4dcc83eba3a8300ff90c9e7727223f3491c782c80bee9dc707\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1f3f3aace32b45e9a6271c7b4ac76ddf86eb4f32e28e147a3e054dc8c836def1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bb61c16d22aeed2d6b18972f68a6c4670fb8a07eeb79407748a7d499bc64e8ad8eb9774d372d9286227665686fe90878f2ef7e7f8595b74cd448d0f847aec02e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.xml.bind\",\n      \"name\" : \"jakarta.xml.bind-api\",\n      \"version\" : \"4.0.1\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e62084f1afb23eccde6645bf3a9eb06f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca2330866cbc624c7e5ce982e121db1125d23e15\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"287f3b6d0600082e0b60265d7de32be403ee7d7269369c9718d9424305b89d95\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dcc70e8301a7f274bbb6d6b3fe84ad8c9e5beda318699c05aeac0c42b9e1e210fc6953911be2cb1a2ef49ac5159c331608365b1b83a14a8e86f89f630830dd28\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ff377d0cfd7d8f23f45417e1e0df72de7f77780832ae78a1d2c51d77c4b2f8d270bd9ce4b73d07b70b060a9c39c56e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"773fd2d1e1a647bea7a5365490483fd56e7a49d9b731298d3202b4f93602c9a1a7add0eee868bc5a7ac961da7dda8c8e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"26214bba5cee45014859be8018dc631c14146e0a5959bb88e05d98472c88de8b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"32bdc043b7d616d73bbc26e0b36308126b15658cd032a354770760c5b5656429a4240dd3ddcea835556e813b6ae8618307ebeb96e2e46ba8ab16f6a485fa4d32\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.yaml\",\n      \"name\" : \"snakeyaml\",\n      \"version\" : \"2.2\",\n      \"description\" : \"YAML 1.1 parser and emitter for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d78aacf5f2de5b52f1a327470efd1ad7\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"11547e75cc80bee26f532e2598bc6e4ffa802941496dc0d8ce017f1b15e01ebbb80e91ed17d1047916e32bf2fc58da532bc71a1dfe93afccc277a296d86634ba\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"dae0cb1a7ab9ccc75413f46f18ae160e12e91dfef0c17a07ea547a365e9fb422c071aa01579f2a320f15ce6ee4c29038\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"654b418f330fa02f1111a20c27395ec5c7f463907ae44f60057c94da04f81e815cf1c3959f005026381ef79030049694\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2c4deb8d79876b80b210ef72dc5de2b19607e50fbe3abf09a4324576ca0881fc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0d9be5610b2bcb6bb7562ee8bcc0d68f81d3771958ce9299c5e57e8ec952c96906d711587b7f72936328c72fb41687b4f908c4de3070b78cc1f3e257cf4b715e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/src\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-commons\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-commons\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cd430f3f7345c0888f8408ce8795c751\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2bfcd4a4e38b10c671b6916d7e543c20afe25579\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7d9855ee3f3f71f015eb1479559bf923783243c24fbfbd8b29bed8e8099b5672\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4aa83350e7a6df21feb9ba8756bb4a68986f33f8c6e384720d1daa448444016c0def1781729788e3e884664abd6703b1e3c0ec6b79893a9d5645c3a4809c0ad2\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"d264f2c8ceaff384b0f22ee77890195ed3d918b01f338e35fc2ee12f82df15e59533918509f535883b4f4befed28595e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d1fa76d6b2567e831b37ff7843df6d7d65028d4e53c570c6f580cbbf13269d2aa2afedfedfe5a3f2cf92d7de6d3c89b2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"eef0f968f2d2fc31f8b4a4ed43bafeb46977de1ac3d59477ab6e2b014f97e070\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"93340cc2c378c830c755b25006bc4f73ec77ad10661f05625b23efa0854d456da8e62bdbe7e7edf3418dda864e6e0d7a6b9d34cea23d525b8991258f3d75fc9c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-web\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"a39761bc7a706c70f6ca3ab805a97b34\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0f26b98778376cc39afb04fbb6fdd7543bef89f2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3f2012a24c6213f155b6bc69aa3ecafe2a373c1e92a26dbecc62ff575c3a1fb3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"f07f054feaf53c2a97b82150882281035824cf0b815f317a22ba1954afa721bc5d57cb07faa19bad99fc235373b62edd7013f7ac2cd0a3d0db91faf49f216741\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"57418cf2a9b3256201c0874e7721966b09929030c64f5e5a85007bd645294dfbf1a14d4632a5aa5fcf70af5bf733d542\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"83daa608abc0124ec237f65231d5f1dd1a5d751e459d3ea255a3d12a56e92ac83037fb72c5793f497fbecb9e389eb299\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1a17acdfa8920b1849a16e4260bb4b960f60da07732148a5281cfcba21d1e4a8\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3e5e020cb1068250eb0e58e9bc0368c44db96d59022047ecffe286a51b0896e4320d9696f2f9136b4c0aed547d8dd1af1bbc2b4b053aa994246bb43bd7397f05\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.objenesis\",\n      \"name\" : \"objenesis\",\n      \"version\" : \"3.3\",\n      \"description\" : \"A library for instantiating Java objects\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab0e0b2ab81affdd7f38bcc60fd85571\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1049c09f1de4331e8193e579448d0916d75b7631\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fa990d15bd179f07ffbc460d580a6fd0562e45dee8bd4a9405917536b78f45c0d6f644b67f85d781c758aa56eff90aef23eedcc9bd7f5ff887a67b716083e61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"2f6878f91a12db32c244afcee619d57c3ad6ff0297f4e41c2247e737c1ccc5fcc1ce03256b479b0f9b87900410bc4502\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"a3dd9f6908fe732900d50eb209988183ffcf511afb4e401ef95b75c51777709d2d10e1dc9ee386b7357c5c2cbcf8c00e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"fd2b66d174ed68cbfcda41d5cbd29db766c5676866d6b2324b446a87afab3a9f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ef509e8bcea73bc282287205ffc7625508080be44c16948137274f189459624891dcf109118c9feff109e1aa99becf176f8db837ac4fd586201510c3ae2ea30a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\"\n    },\n    {\n      \"group\" : \"com.vaadin.external.google\",\n      \"name\" : \"android-json\",\n      \"version\" : \"0.0.20131108.vaadin1\",\n      \"description\" : \"  JSON (JavaScript Object Notation) is a lightweight data-interchange format. This is the org.json compatible Android implementation extracted from the Android SDK  \",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10612241a9cc269501a7a2b8a984b949\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fa26d351fe62a6a17f5cda1287c1c6110dec413f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c4a06a0a3ce7bdbee702c06944265c050a4c8d2fbd21c248936e2edfdab63acea30f2cf3568d3c21a559940d939985a8b10d30aff972a3e8cbeb392c0b02da3a\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"60d1044b5439cdf5eb621118cb0581365ab4f023a30998b238b87854236f03d8395d45b0262fb812335ff904cb77f25f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b80ebdbec2127279ca402ca52e50374d3ca773376258f6aa588b442822ee7362de8cca206db71b79862bde84018cf450\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6285b1ac8ec5fd339c7232affd9c08e6daf91dfa18ef8ae7855f52281d76627e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"de7ed83f73670213b4eeacfd7b3ceb7fec7d88ac877f41aeaacf43351d04b34572f2edc9a8f623af5b3fccab3dac2cc048f5c8803c1d4dcd1ff975cd6005124d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"http://oss.sonatype.org/content/repositories/vaadin-releases/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"http://developer.android.com/sdk/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-logging\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for logging using Logback. Default logging starter\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7ac01b9dee045285c365cf6a3d8d8451\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0df8ec78dc87885298998ca3c9bd603ee7bfe5b8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0b7e411cfc44a15fc63a36cd05a73b34c3558f1b06e4f297b1919361b8a351a7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"23baf0a59d56809db43101fbddb712b515012c64530362665cebe84c53bbd716218d3602024315f3250dea923138845c09d5c56dd9c7fb26a53d5e21a325e52e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f5ff55d346828eaec7b535bdd1d6096acc3819e81f6fa0a3d2396d523616e2e356d58115de8b8c49adf035216fa6ea83\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e5bd5c09d127a2984a55bbfc296cc515e399f35ee2ca949b10639c5ef583bee58dc9eeb60f6bec1f05904f8b91b4a26\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"99b21628e6efb820b4955e0e17bb54345a6974dc785b79abb7af8186a261159e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"91625907d0200fb80f025aa6ed098372955053bfb277db124d95ce2dd5049c20e9e7f2b97cffd6f247d9ae8da1bc26c004b688687056a87ccb3033d57a7c20f3\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d5ede97972b567fe75db1d2bbfc035d8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9089b9fff0c17eae54aabc466b78e010eac3a04f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b870c0a601dc0d6d98b33a6b59d41799285848de267f7cfb466a6f167f30c4d2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9577f4ba268b688ad100d4038f6dba97139a29b82127f6a581b948f0ee08fc8159f51fa5f7deb200e5a61559fd321559d2255af75c3e28cf293e815b8b1bb8ac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"96adde3cd5a4f729a6d382566800e62e89c93d1c3b9120ffefcd9a666d755fc5d6dc3dd12577f927bcaf03b7f1b0922b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c3f71bfae2d560ec46f76e833aee6964b5ad57639cb4ded937cd6d1e39b213a4c255d9b83ba59882d22dd31a4ef7b5f5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a251040e99b14a5d926f86bdcb1fcf505518d31cb421e6aaf32d59d8f7f2eb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3b642b5433989ba548cffebd7c155d5ada680b96996eac432895de56a27d7529c795d7263e8419854c9d118cddc0492d142d260a2e5434058134c9bc17ab8253\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-core\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-core module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7367629d307fa3d0b82d76b9d3f1d09a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f8c2f05f42530b1852739507c1792f0080167850ed8f396444c6913d6617a293\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d18159d4b378973e49182c4711b3d5b1f3600674ddd7bde26793247854bbd3a7233df7f74c356ecc86e4160ac6f866e0b32c109df6e1b428a10cddd4bc7f44e8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"afe21cf21e8804d069514a1f0d57c92b4caf56f8b010bd681d19fff67f237fcf0bbe1e1c9bfc4cedcfe602a3ea859b57\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"38cc28c8a578f4053412440d88b41938fa029a8ee3d350fe7474b34afa0f17889298d00f3c2cec4510d72d3342d29a77\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6c7d3be575969be97a49e90a97a8dc1bb25380b1b302073e00d2e21cb266e6a6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8e9ce45d599bffac71e35a0d59c4dcff067f628157a75e9e28c1930f31537fb1dd058ddd9906322c1154f29436252a36bc50595578bfee9bcad4a9705c85726a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5c793b3b61ba2637840a6c865aa2901e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"142fbe3cfe3370c57d0ed55cca0d8d96e1d6f26e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fb27aeb59ab757e60c48f9810d0ab54dc858a4c1cd9cc75b4ad07456c9c3e7c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"975428c3f753ec1375f9c0ca2c47756a22896cc510193b53f7a8501255634a2e0d2165e699055667f4127cbaa8e79c9c128aef6de0854fccd4e158dce4422939\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"c3abb4c4a9961cab0fde6119d5b86755ea0c43fdd266b51d369a8544818463ce1876df2b13b0a2478f36b1e5282a305d\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"641f9090f373f299d61bf54dd06e7ea15217c5b06424e970ddaed1f64e2a25aae74bdc10e04c9c4e934f2a3a5ab95c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"45d05dd704757c997b11f13961762e371309bec11292b32af3f244ca3b49642c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"53001dd1610347d6cf92f737067271fe3c638828a0b1e0b6aca62429e97a85018daf6ab3e10f065acd79ed7c93dc3a4c57f89eda3e2feb48ab548ca7e906b414\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-jakarta9\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module for Jakarta 9+ based instrumentations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0e247019d91d3c357b440436e1af2fba\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2dc7257970669fa45e342b0b36902d868af2dbed\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e8c66d7aee8fbc8a9d2e15c6c53df92bd7ecbf94f1ca8562d62d9a2693aa4633\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3a481de081b216d42bd9b741b3a830c93d917c5ae8a11f670785b53b55cff601e1cdfd037b12d8b95cd8557c4493d6e04e51980860e421f444f2b4a953070969\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cdbca1958c2502bcdad18446401f7f21ec2bc2c4055fd2fafa8fdad30cb8c8fd9aa9863de5ddd9cb852cafda487d29b0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"13f29eca056350277ee80d786945386abdd1c8b7c04dc35a94c7ac8146e7b6cafa617652fca15e79b8376341ae5576d0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f095b2247aa3ada3c824121b4720dcceb3b65f7a2b9e880acdedc613a62d9be6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"773cd6f711b68a27d958ecb01f85d8480835014d23d3484e69e1c63bc736f50697bd6cf7d5e7776a13ae946ed10621334cb84ba8357b26d45cb6c9990826f993\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.module\",\n      \"name\" : \"jackson-module-parameter-names\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support introspection of method/constructor parameter names, without having to add explicit property name annotation.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"495868f770056602bfe13ea781656f03\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8d251b90c5358677e7d8161e0c2488e6f84f49da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baf1a3156a23cb407e05374161a07ed8560f78a7ae249955de04a9a2fa2d0f2b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"497b08f55f601b7ff6294e0b8307e015e60ad45c7949bd80ed3f5ee19daa93fad7f0b5a93abb8082ec46480667ab8539337633213d0fd5992e4a10c710f0a7aa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1a50ca6c0e0b4e3ecf83e3f327670a3b36f2b847b46ab5e193e9bccc36fee3bd41c1aa937dda88c4936339eafc73fc93\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"30d05f1dd78a796ba4abb79be93dae2d7e4e5269de18d85a9d89b1c92f6ff8fe09ac1953a48a0b2b51906bbaadb56fca\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e50d137efbe3de957a64fa4b90532cbb67efc2b09ba11824362315d1f57b812\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9418c5c18e429e201d7f6a4d5f05a52a433dbe4bf72a82e3ea69010c1d4b9ec99fc651804f2f8339a53841f88416318e3ab7fb1a07391cde5ea745ebbfcf98bc\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-engine\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4d571057589cd109f3f4bedf7bbf5e7a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"f32ae4af74fde68414b8a3d2b7cf1fb43824a83a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baa48e470d6dee7369a0a8820c51da89c1463279eda6e13a304d11f45922c760\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"52ea2f11ec2ef0457384335d1b09263f4efecf63d9df99c5f8396f74d972722c51f8f766370e85e030f4476e805dac72603296942593c5bbe56993454b9d8e30\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7c520e04c995a47c19c94fdcbbcba9bb117696191e6a989a82d9f960e0e315e5cf87d28022ac5cb2701c85d5f38eefde\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"79d4f2fb987d6a44174dda99b1bd827e8dfd0399495c3e994371d4f69631212768dee8b891313aac89045388a1bed9db\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5c3fcec688368188688cb6949c1230c2822211e53f3a65b7b3abf4a38051798b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"30a0834e88bbc62287e5f49302c4a07b6da1bf4d9774faddbe7e606fb296c0dcd71c7e90ef8fff3e18dd050e5a19f7b903c91674ff4806cdb97111e4f0cfc199\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"29fb14fe1d383588e87a73da4508604d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b100d2d21d45dddd740d496357ca6f3813d777d0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"371f0f36d226a8db972c37c73f0a0896ee4d3e77c29b54dbce8a64af731a6e53\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"42bc3a99f9c9ffc9fd08447303a946fce1c81e3a869a5788c7d3b669536455eedc8009428ae4660d66b0d74ab170968b6aad905455b53342d7c521e7ec4c262f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f47603c4009bb767f9d5cb0bf3fcba69167daab53cbfafd217450977464073e8b814c76aa545b1eccee587201fe93eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"bbd77376c9a46de290522662f327a8e6b0221a6c0105632e73b527799bec8a162d98948d0d05b32509650b4f47a6465e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e9549dda419ad6f482e3b376c595c69ccb93cebf365c1b18a59bf226c3264db\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1473f0de013447eb40d0b6d2a30013d2a7d262ce1e0259d4a27f88e421e5538234a46704f88b27c227aab7ae2261995a73f4075a6a43124e39c7234c6d164fe2\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-engine\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"71d86cd027062c4da0796c2493ae94fe\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6c9ff773f9aa842b91d1f2fe4658973252ce2428\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02930dfe495f93fe70b26550ace3a28f7e1b900c84426c2e4626ce020c7282d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fcc9406d1e0301e27538757c9649545d784e83743a8800932971881cfd78a14a264ad13c0b92fad9ae1be50963c540427a19cb2d1fee06888ef48105aad4c8b\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6657ac1bb11d7a40bbcb020add01e57edbbc521645116908d857074d9ea319eab3e7b7f2e9fa1ff8df08b5db3774f4dc\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"607313914c11274c577b0aaaae6c68aa6ecf25d8302f55d4e334aa6b58df2e543d2399785e2019a56b85aac7716c9623\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"be3560971111d3f548bef24aa6660ec2a126fd17b3bd68b7deeb1ab48735a9d1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4ba6cb70f8fc1918dcedc874340488909c48e0f976d1834ec433f4b5c6cff55b16a996a0443a1b68a0d0ad84a37bf51386633905628728bde08b5820ee67dfaa\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-observation\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing Observation related code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b55c9caac5c8f778996937c3f6cf4101\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fbd0e0e9b6a36effd53e0eee35b050ed1f548ae5\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48f6607b248e8b77ee9f7b3934f70124471daf947b30480c1b9c0e9d9f996c83\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3e12e101b161715e5c30eb166578de7ae76749a2c4d22435bc57395be14d1313073d5fa76dcc883ed807d4982d343addfa24540e283cd0432f1428ff00962d98\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"791f99b503d7fa16733a74d92ebd02e72dfce4d648245f149f5363019beabe7e317e7ef0df0bcb67832dbab03943ff53\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ccb83eb15cd8004295bdb40b948cb9d3efaa4281b0d02a97b49970a2699822d7cd15b83206c236c3a41e49063caa5ded\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"773e3647329d707d79efcb92c88cbe0719b4dcd820f06983e6e283e666875acc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"922f6c81c3a7b8e8c1296eb3359723161e91bac646d4bef954904c70a40ccfd9dc95c783715fcedc788f67ef06ea5514a918c7cc6811f2bdd39eb011a36698e7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.awaitility\",\n      \"name\" : \"awaitility\",\n      \"version\" : \"4.2.0\",\n      \"description\" : \"A Java DSL for synchronizing asynchronous operations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8f3644827b9e3037de42068c57006260\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2c39784846001a9cffd6c6b89c78de62c0d80fb8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2d23b79211fdd19036f6940cc783543779320aaf86f38d6e385a2ff26da41272\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4c422b4aef3dfceb040898f45cd1b2efb7bbf213ef9487334a0d0e674e494e120fef61348f8a81ce726f2f66dc426e133917de20c52b5d39d792e2dca7bc82d8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"11d15d6efb32707cae528eefb8fa4ab7820649ed528c3447660efd984518ee2906421af5ee76ea8181c904d594e8e719\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71eff4441379fb1d13bec42264d48dd1ed4817c7a226a4ef1e5255e5afcc8e5e61aa92677ae98fdce2bf4824b4dbe4fc\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4fc8b38b34625336be520d2be1edcab4c8dd8e0667fecb2aa6aea83b9bad7f28\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"074f8629ab499c28155e505513e0a25c83ce722747d196966eac6327de604853503ca5f54b84effe8e2e3ab78d9ce285bdba82bf738ff8bff0f1009549230521\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.hamcrest\",\n      \"name\" : \"hamcrest\",\n      \"version\" : \"2.2\",\n      \"description\" : \"Core API and libraries of hamcrest matcher framework.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10b47e837f271d0662f28780e60388e8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1820c0968dba3a11a1b30669bb1f01978a91dedc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"6b1141329b83224f69f074cb913dbff6921d6b8693ede8d2599acb626481255dae63de42eb123cbd5f59a261ac32faae012be64e8e90406ae9215543fbca5546\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"89bdcfdb28da13eaa09a40f5e3fd5667c3cf789cf43e237b8581d1cd814fee392ada66a79cbe77295950e996f485f887\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0d011b75ed22fe456ff683b420875636c4c05b3b837d8819f3f38fd33ec52b3ce2f854acfb7bebffc6659046af8fa204\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"92d05019d2aec2c45f0464df5bf29a2e41c1af1ee3de05ec9d8ca82e0ee4f0b0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4c5cbbe0dcaa9878e1dc6d3caa523c795a96280cb53843577164e5af458572cde0e82310cf5b52c1ea370c434d5631f02e06980d63126843d9b16e357a5f7483\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/hamcrest/JavaHamcrest\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-api\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-api\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c6b8b04f2910f6cef6ac10846f43a92d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"eb90c7d8bfaae8fdc97b225733fcb595ddd72843\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"60d5c398c32dc7039b99282514ad6064061d8417cf959a1f6bd2038cc907c913\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1fef44d4aa781bb119ab723c3c2a6f0d27efc4493a1fa26b603c7c7a8884c4d6274bccec6536f120d55f876f8d052aaf6cc003074c27cc704deb2c4bc08b6f0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fd81f893be859a50766bfbf3bd74bd7d359c6d481b7fe3099e220402f585d3d46b6ad42a36b1d88eefbb6fd27a3cefa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5e13ba92f757499ca52d719869d318cade9bde9c948ee9c68d753a21ec273f7b56ad68ff8cb281614efeef1d4c479db0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"997c9e0cc57d61a85a8eec568d0f014d47af5bf655602a2c3518b6530b089905\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97c3e2c1faa1f77b174ef6ce7b24a2339e547f5976a4e40348653e84498e0c3bb96068447facef6df6b54d4af34b807f19b4d2bb1d31e26f97d6dae07843bf6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.skyscreamer\",\n      \"name\" : \"jsonassert\",\n      \"version\" : \"1.5.1\",\n      \"description\" : \"A library to develop RESTful but flexible APIs\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"60a7d3d352b233487d735f4b86802717\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6d842d0faf4cf6725c509a5e5347d319ee0431c3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1e9a7c443d0dd579906646d767f3701918a78cb88a93112f528305fc9095d261\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"51221bbeb30ed47840494d31128e605e29a96249f3e4b9c00985a865f8ed58b73e045772e3b0af74a35018a9dd004b5cc2182344b9154d9a50604ad1a073f2dd\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"941cec8d4ce1fab19f32b36f0afd2c7de27325659c5f85ab90948182098de4afe327b49cea57b946f18671af8037aefd\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3fb46460472c82901ec6fa5deab84eea18369e74aad920e3ee9e0fb8a859e8397a287428d0bf1c2b137368b6579c5c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"24b6c0f73ee51c19d5fdae62588dff9d0bf172da7e6ad1595e275920c8de829c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"686fb7b0ee0849bc78b6eeb74a941795252cec9a62ea153e6bd1e77d51fb6ee14f64970cb52cc13f581d21b166c6f1b28b8fbc4c7ae0c3b225df385a92635f0c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-junit-jupiter\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito JUnit 5 support\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab44b412aa650651eedf323e945fe367\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ac2d6a3431747a7986b8f4abef465f72bf3a21ae\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e2416a260c3a45ba77d674cfe27d49428e57efe21a7b2ddeae733ebb5c5d85bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"39cccb119c0767f4e443567873af78d882c4a1e99c553ad39d4efae2698933de602d9c0046a70a05be552793569d4b43e75c2a798fd1f7f0a8c5ab34db8b9c94\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f02eeae7fe867ff8580164b4d20d269efbad2a18ba2ffc8ba9744c603c589fb5155399361b14ab2a6549d605d26a4694\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6b95b5f5efcc97a2531c9c108e53fe5465ae0249d46988fe7fd47df7ad4d154de40a66471a996ae7abd75bd0c1f6c9b4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"30978340a8749b094a5b0f42dffbb91e72f7d7eaea6924efce13f47a44048fdf\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"80601cb4de8850a0255b7c28cb7993be667a238d961fd281c7152b7ba40eec399240a2ab9d686cd1463872652876e88ef221d699acb61a2acf041c9f187053ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-api\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b5e9bf76dd128b37666ecd9a252b50ec\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"74c65e87b9ce1694a01524e192d7be989ba70486\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1db48e180881bef1deb502022006a025a248d8f6a26186789b0c7ce487c602d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4cbf72fbea7009ec2fc363aae2ccfe11ea2023967d65be39335eedd1d8917b7402eeb2219efd5a1f11d03833dd1f57eecab428616b03124ef2266c6cca06ac56\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"edd8429f2f88476afbfa63314f7846d1341a4cfc58d3abe55b3cda236613feb6859f711e0ae60bd7821b74e488fb0666\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b67292ff0c7ca988a4b40b6ec14582ef579990d275a37944ac9572ecdfd4bf6e9fff2ab982b21d159a1135c21a32495f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b2641c2db75d3c676e451a53b5f60dfaf030a84e0230747bd50d00414f8a27b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"f1f4d9c48a9d088460e1ad3d71126b243069e522588cdc5534ac8f201ec0574287e8f1fba182f8925ee75b78726269487cc0160f7f8bd1aa21cc8e587fdb5c4a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.assertj\",\n      \"name\" : \"assertj-core\",\n      \"version\" : \"3.24.2\",\n      \"description\" : \"Rich and fluent assertions for testing in Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b596a91049e6ce526bc5595c1bebea2c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ebbf338e33f893139459ce5df023115971c2786f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"df3d0b348f1fe806bdddcb10fa4ae63c6679e9888d4bc7055f09848517976aa3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d8e3159effc7954258f2398e26c34eab6c243675408c7b5fcd7ed04a7b7dc06006514510ad15be9e7725f724cbf6e5c534cb22cbfb7c0aed71b81d4ed5755220\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4f06196b5329e215282476d8e3aa5065092924bccb91da4eb0aa2e8fcd2509f249369654f0c17b59c38f11b878a305e3\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3029ae58aef975843e9205f130dcdd8f8e7da5ff1bfad62b7d918ffe52b74a3c34a859af13393abe122124a9132f3feb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2db6965251a03be26f5baa83792a002444b4de34aaaefb0e6cf3cccf0a20939e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"fa3ffb87bc40c3f881fb477d41c8565cbc1ce46ead2030442674bb86a425c722b75fce5bb3c22425b21cc3122ac46e0f28b2eaba2bcf5d5ddcb31f47d967b890\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-web\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8a6aea9e1fbdbabbd00e35038739200f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e27e36d4222fd4d589e634e1c7f5f09f0316147c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2f14d3a4a0ae3ad634bcfa07117542001c1789c0bdce3504baee8f2bc45ef006\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2fcfc8d9abfcd0518b6755737c6e520544600b3c26b42b60d1ab3fcfceb31582d5dbcd5d86a98ec312442d335e49f0db0ecf21d8e99089ef41d962ece42d97ae\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e3c8cb02b18ea5b7aa2a7c9c97c62385fcaa8fc53f41d7bf0b98d262a10473e9674924ad287964f6e58fb9c5915da8d1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"713c9200480f14fd4bcd073d43ac7900771c9d36b4e72b50ddf80733670948ad57700ea37336de5078d16557e426de79\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3346906c7b4b455c00226fd9804a237d3a667523800e0c2083413fde4592b7c3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"99ba750d8e1c97636eb47122ce259b1bc9b91c51fecc50d13604f7ae7096a20f1fa38562d83786c1d4c3ba07ff94b286d869d671a5f0d00fd6c378f032332f63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f808bed72032367a1170477e74e57f7e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e6a20062864e3a9a0bba0ac3b0c5a819453045b9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2e0a11d69fed912dd6f5a6b0f492ce1530e2ac932de9588d4b7df0ab548eea0a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"83c1f7e7b404be7b9f603a386ca2d0c84c7e0b73190ffb19ef2b0dff5cbc1ebd57ce73be663ee01ed28f1c4f41d91db7f070d7b37a3f2ae6b9b6814dd930a089\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3a5159cad10587b250f0a1f7cf6ebea9f2cbda539c008094fec1dff47eeced5b2119be3ad007eab0598445b9282164f4\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9303b808eed6e0425d5c7e968601960d9ff2e0c2fd840ffd041b01f0499b1f86ae05c50e968e925374a54b26e9298410\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"a18f18bd0a077a38ea0b3aeae85730b9f104d65d4d48f88210f2954c45739eae\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e021bfc51b8d6b8cdc1b44cf5042778c208db09b349250e33630b28ace2ed97d52bd89750ab70e14b650578f379a7e6172838c83bbb2c974394132cb80381f27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.activation\",\n      \"name\" : \"jakarta.activation-api\",\n      \"version\" : \"2.1.2\",\n      \"description\" : \"${project.name} ${spec.version} Specification\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1af11450fafc7ee26c633d940286bc16\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"640c0d5aff45dbff1e1a1bc09673ff3a02b1ba12\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f53f578dd0eb4170c195a4e215c59a38abfb4123dcb95dd902fef92876499fbb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"383283f469aba01a274591e29f1aa398fefa273bca180162d9d11c87509ffb55cb2dde51783bd6cae6f2c4347e0ac7358cf11f4c85787d5d2857354b9e29d877\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e34ac294c104cb67ac06f7fc60752e54a881c04f68271b758899739a5df5be2d2d0e707face2705b95fa5a26cedf9313\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ffd74b0335a4bfdd9a0c733c77ecdfa967d5280500c7d2f01e2be8499d39a9f0cd29c9063ae634223347bb00f4e60c33\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c97236eaebb15b8aefa034b23834eaeed848dacf119746c6d87832c47581e74d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"147dfa2bf46bb47c81462c36ac6612f9f807169ffb785e2bbd45538205c5713f33af4373f3324a2063350c2367baff37e9c2cf085c38c96870ad88c60a7fbea4\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api/issues/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-core\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Core module of Micrometer containing instrumentation API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"30dcc7ea6a0e99663e5908bce7371206\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b72e9a2f26355ecb8ababa0148a5c3c4ac648f14\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"97d0a5309e9c584f4dec6f549a383ae25d8727abff43cff8e0b90580ee797b67\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2acd080a1b40cb5a1ca0b7266af829392e318291dab57e6239ca97d15112cc206992b78316f4c02400454124519a084341e4de55dd729c96805b3fb196707a64\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a3998a9a219fc049ace5731fde94944948332eccbe589dbc34456057a2df173ef17e3b0642233e513d3118bcfba565f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"22c97b3fb49d299ebc36674a6e32d9fd05726d88109ede3323e3e97e82100d1ed6d7010e86749a2b07ffe994fb3b7833\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3b272686c89e274b5944715db002871e072f0f8c7099228f6d6909656b6ba3f4\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b1d82086950a2e61ed3e016fa962af2e9c3b2d543c4c311d40d9f7fc402b9beb3e5d09261d336cb1634b186f723bf584874f3fb8a29c38198d5ddd2b386c4413\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-params\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-params\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5e8e17f6f2a5dedb42d9846a3352dd31\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c8f15d4e99940c4564098af78c10809c00fdca06\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c8cf62debcbb354deefe1ffd0671eff785514907567d22a615ff8a8de4522b21\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dbd8a3bca0a03b6eef54de2b489685c8125e0c6f23cbdb633174b21e07cc7b97a24b55dcb5b60ec1a496683a918bfdf1ea0459950689e3755aa965ea9e106ee9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"882b3106163d7c195867e08db9948a0997e1469a23c847bff523efa30a9b274c0588f8228fca98c78abf9b61709a7ff2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e4e9a7dbb32cc3f16f21a14fe036aa13488c5b94e3cb6cc53b417c4588b90b5ae118caa3eb9f4bc9c513d06e2c1f408\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"171a08027b527e3be1ad66082405eacf4a55746dd983c46d9ff7ee5552276615\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c435b4a17208b67f6fa35ebe74872c3d2c3557b290437bb682ac86701402bbe17d0e53446c674bb94c7feaae4bbfa99d888c7bf7181707e27fe08ff7934c00f6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-databind\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"General data-binding functionality for Jackson: works on core streaming API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5f453c55f127690fa8491ce347aa055c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a734bc2c47a9453c4efa772461a3aeb273c010d9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c3c53333a2172a80678bda1803e39cff45bec6ae3e9c7d4f44a81ec4e2ab18dc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"490ccc99a9c28238fe28455bae08196b83df034cae8a1947d27ff89e500a5d812cf4be36c61942e647c62ad540d8eb4428f49855f0cc8db0ee9e7a5b12ba2454\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"b53f4a6fddbf677a8d02c65e9f0a96372140c68286d68740987fb462f946de878abaeea421d3e4716751f04d88c16ad1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5a407605544e303abf8a212651bf5e5594fa313804a399bf03401f449c0baf26ef965def518b05c275b2f38f18457739\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d0880002ac261d181e663499627fcce5763f3a9120bb76e758adfb9939d17c98\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97bfe0e9117dad82e0799cb2c105c4553c6aa5ce9abdefee4fd5b584876555309aafa9a19ca586e928e292e32f23452849a10da7364966e11e4f7afcc6aec78\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-databind\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"jul-to-slf4j\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"JUL to SLF4J bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"24f86e89ee3f71ea91f644150c507740\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"09ef7c70b248185845f013f49a33ff9ca65b7975\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"69b4e5f8d3bd3f6f54367d19f2c1ee95dd5877802f12d868282e218dd76b00bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c1cdfbc0c867917d65ab58e039b01c5b119368aef82abcb406d91646da208a4bfad91831a5a425eacfa8253ccd5713a9d4325d45665288483929cce7a6a56eb7\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a8d45375ec27c0833a441f28055ba2c07b601fb7a9bc54945672fc2f7b957d8ada5d574ab607ef3f9a279c32c0a7b0a5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d65edaa8f6ad8bbea84617e414ede438ec4aafffa3734f2d38e6dd0a01c1f42f9397acaf6291a73489fb252d7369c71e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"69416188261a8af7cb686a6d68a809f4e7cab668f6b12d4456ce8fd9df7a1c25\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"52d54c80e3934913a184efc091978201934b0ee47a6b4f9c8555a4d549becd26957e17592aff46dfdcfcbcb2313bfad09699ee84cfd7112ed2a00422c87399e8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"6f7384977eae04c804b1062df9217959\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"faa2ce019bee68a8d17529d0a08ebc427f927e13\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"6fde604399114e77b12519b3d117117c607cb73b89a88800856fb0e0cc82ea7a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8619959d143ef38f5c846591b8b10b0c50906a3301a5e9ed3e3df44124bdfbe3197cd4ecfb214c3250f40a0c1b11138b7a3f6865755445879f0685d2e88a6846\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e237fdf6fdb8d21f2fc19fc15a370901c368266ae8d2b157f41b5eeed50b211a871fabc352dda10bb3aec60975d233f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cd6240fc102daf1efcd9fdd6532ce21297d5477e9bde3f5651cc9ec9505d526f63ea2284e484c2aee2a8e63841137839\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3959b52aebe7405a95f82d8990b8122cf21b89967f691dad851b85191973f9cb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1b4ef33997158ddb97ccbcec7011cd55f0e019428d25410b01a83ca58c9420f2f8805be955cf704605145abe582522db0c8afb9698ae4efac141a3807a457ae5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.latencyutils\",\n      \"name\" : \"LatencyUtils\",\n      \"version\" : \"2.0.3\",\n      \"description\" : \"LatencyUtils is a package that provides latency recording and reporting utilities.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2ad12e1ef7614cecfb0483fa9ac6da73\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a32a9ffa06b2f4e01c5360f8f9df7bc5d9454a5d373cd8f361347fa5a57165ec\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"bb81a42498c65389366205f4e07cee336920e2f05cc0daae213f2784b1d0ce9a908b038daec20478f23eb00b2bf704f96c5b00f63c99615193ab2a3cc4a9f890\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ca4640dc9d848e6c6d15441897e1b5a9f27f34207b0bb456dd54d8f267b73b348092e548e78634144de44ba3515205\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"406c2b5c6f64b0c090568e479b5e6136a04a4e77f8eea65d32b4e2b01deebcdf6a0a851240cdb740c25b5a5e61e6c179\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"50ae828358301033542fd7c412e86ee318d5451f89a182e2a679aaf18099d26d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"456c337b9fb385579aae707409ed6a04d08e5fc87b1a46733dca617c22c625bf253dc4747e0cdbf5e7d8b48102d2938cb482b6b688a79aab645a7459c592258f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/LatencyUtils/LatencyUtils/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/LatencyUtils/LatencyUtils.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-el\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f9171a84574782d1d68acd8b07177172\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ad7312421535d7d3aabe0f541e852baccb59726\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bac12b9c993a9181ffc88ea8ba085491a482729e64ae105750a7475a7b85e549\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77cf7be4536d7f1f4761fec33562134150c0ebc74d582160ff913c8be37b1502ed63e90bce81bc8617cfcd76c774903c2dca4209a972146f4c976f786456c596\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"62b14b49de8ee6efb41831ff172114af56a18379a797de732915ac356bce3e5582764253852c9831a3c3b6c1e52dea65\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"05cb21cbf8b221332d7ad588cc6aa2087c60e8ce92c5ff2bddcd16465ef2a0198f74d4595dc3313d1acc68ea945c8672\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c18e9b240138c21a23b0bf2f502d1d667084c5a50d7b3340a4a08799a3175de9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"663d02ece35a989d8da1cdbdea002974f0115ae8c727dd71f0505f299c63f04c0e83b718e4c3e65412bea1c79d872e9ca7d9431c7deb63a312d3191d419620ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-context\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Context\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ca23d3013c2afc6d3b30b993f3c5cd69\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"15df19852991220556b4462a366269b8e15278eb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"af22a435469956415bbee873de6c05995ef12f2d29622abf510a94581ea52de2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eca3cb14e8c0fb65d27bc21a8041aab3baea14f278fb546356fcec9874d0dcd10353fe697e94ebc35a78abb3387d5a41b67c1cbc9341eb05359c1b535147a9c9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"374207d989f7f27ded5468f35867d0aace78927cdaf98c31b2b6345210fbbe960ae5e5143bb0308347b7ef386159fa04\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"236c1d366734b231ef4a334da4220b311dd58b1707ae854b2a50ff89b6b348913458fecdab14d196128b695de6dc9832\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1e1e87df37dbc064315d7afaa59480c830a0f445ed0df2ff5968931f96e9e86\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a600b2720ed8e5c6ecbb2a68b6a5fb5320811818e2128016b9888df705901a8d0f38dfa99b8d458724a85e769b4da2ce14d461133e085f8aab23f59e9e520c11\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.opentest4j\",\n      \"name\" : \"opentest4j\",\n      \"version\" : \"1.3.0\",\n      \"description\" : \"Open Test Alliance for the JVM\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"03c404f727531f3fd3b4c73997899327\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"152ea56b3a72f655d4fd677fc0ef2596c3dd5e6e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"78fc698a7871bb50305e3657893c10500595f043348d875f57bc39ca4a6a51eda3967b7c8c8a7ec3e8f85f2171bca4aa98823e912e416e87e81c6ba5b70a37c3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"10398b6998c9202a0731e2e19ae1c3f9d8a83582c2663fe7bdda15794ee6fa816727dbd8f7c7164bd5395ee1cfe7c97e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3abe706fd78509c25a402c7bbf6f9ddf71ffb5b35054864ba0fdf7902207115f888a0ba728fd71d2e87a9360d2498121\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d961907a1bfa1dcda329dca494ffbc251b31fabcaca5ab7095661a8ce3c1d654\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0ad661617bcac51bcd26f7ad4611c69b1fd9811b50dbf734e041a3243ab1f845e7796620e8a7c40c4a2df3946864598b1251396c7d9bd813203d82710788cce0\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/ota4j-team/opentest4j\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-core\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Core\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"98bedebd5de314d344ed3a7dcad01c66\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e43c71a9eaca454654621f7d272f15b53c68d583\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e3f7378e98c26500bdb5ecd6865778f57a22787eb2f11b9bd5fb8e438a0c631\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9654f2d77899116d66dbf5808815c866da0bc7a965532da059c7819bde3928e8d3692f0dc97e06f94c44e5452b785b50eb364a1cb7e46385653ba0e2c7195306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3b63b4a26c5706ef2e379ff7bce89df983e7ae449a927905ce23ecf26e22bbcf8e91dc53cc75f4f7cd72bc09d7e7bb20\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ca29e88f0764a6a9279fc93d5cb9284a04c6ccca6a8a5beaa404079b90674286fc6458d14b0b0a727d31e00b8009e4f9\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"861fc1147deae5a55165bd32c3fd4e18687afcc37876205c10bf1feede582ff9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"659a0d2e5ba153be219e1ebbafb28f9b48c44a2acd78d695e7479551a1c1641b7893d7df071a3cc7436de03735b0c8024b2f758bd0286711eae64ab005f6e929\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.jayway.jsonpath\",\n      \"name\" : \"json-path\",\n      \"version\" : \"2.8.0\",\n      \"description\" : \"A library to query and verify JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"501b9f34e6a05c20dd74e6b40e066617\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b4ab3b7a9e425655a0ca65487bbbd6d7ddb75160\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8d1521092a2acb13a2667774b8b81debc1f2a0e937007e27e5bd28bb222910774b64d6e269f33473f765c810c03a34e715d16065dc9a4be8d8d081436282ba7e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"aeea493be7c23574a77df50a0652776b768d52e4238efd504b8ef3b142bbe6caf0dae8955b30c2173a54f70243d36a36\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c11c80614c007f350fa2fe758c0f4505e7ed7d25590622f133abc59ccffeb4e0b2abfd393b83e58dff4668307f28704f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a7d1d7845dde343617ec009dd0d76e6bf012f182324e3b9d0f23c52bb7f67f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"da023255dfa2271a0b6b35b7d35980c3c502f3f63b3d515714f7dea54046f527bd6cbd903fec9492aad88ad03a1b85dc2b05fca4b34ded3c3b427c4cbfab02fe\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/jayway/JsonPath.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"slf4j-api\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"The slf4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"45630e54b0f0ac2b3c80462515ad8fda\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"7cf2726fdcfbc8610f9a71fb3ed639871f315340\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"069e6ddce79617e37d61758120c7e68348ee62f255781948937f7bec3058e46244026d7f6a11e90fbc15cd4288c4bb1acee4f242af521c721a9e68a05e64d526\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"fd6f7ad85d02ac63cd1a586c8bb158c1fc000495f512f097731ea9f749b5da2637615b821294962805ba312c738f40aa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"17cd61f59a162250b52a89c7c56eb60da253b776210500313c7b82744483ff84717946f969251fb4d76f9bb12a2458fe\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9dcb04582c64c79e788f9191195834ec75bb3457133d22a176a0ccb069b97103\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"990faffa454598a3fa82affe30f1323db769d2e1fff20d9c7163ef6fd95ac7a0874c06a634207a2eaed9e5afbdee68b225138fc75018717ba97efe3ffe92c88a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-classic\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-classic module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"204b49a7fa041b2b2c455193079dc1d2\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e832f7263ca606ae36dabb2d8b24c2f43d82cf634e81dad9d1640fa6ee3c596\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b535f2cf5a2fdb807017cb6fe456c40dcb11491e743ff86f99df2714a1b12bb9182ac193d37c8a6dd7eb2bf4c7d24390a6d551d02a280083673516eecdabc4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"606400251082b8193a57bb20f1774ee2d6e439fab2ddb0207643fe9cee66cf61edba5e5c80d4b3bc9785a7bab910f8df\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d9d9b1412d2fea3eeb5d110a0e7d44c9bc13459fd2b2f5cbb30b95174081f0184758abe43b5e6b6197a716c3ba7b310f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1b0d59a9a91fd7878c92b3680cde8c34896823612a2f04715c05e977c09db82\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e0a39dacbb91b7d9f00bdf78829918079f6f2e749c28f31a359064bac9ac7eb65c87e581795946814460f787e33b8829a9cf0e933a0f87dd7d48f288d45f5064\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"accessors-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"Java reflect give poor performance on getter setter an constructor calls, accessors-smart use ASM to speed up those calls.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fc814b28882dd9f2552eda21add0698f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"aca011492dfe9c26f4e0659028a4fe0970829dd8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"12314fc6881d66a413fd66370787adba16e504fbf7e138690b0f3952e3fbd321\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b21fdd3401a0557d2d04a14c27563897afe9e001fc520398e22083bc18afee5e48dd9f5fc6561d0f327a30a9303bf5cc20f0a2ce741d80b3792e258276faac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7464bf3917d11712b235c7e1af339766d01cb4b41ec98941c3c69bc4ab9a4d0e6c832cbf01482425100dc8f1611ce3a0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"be26dc2bfc5fdc1a45e14f1c2fcfe224994e66d39049e235ea83c714fb90bb685d3f2209c0d550528e2cd9b2d9d95a6e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6a914eb757ec313842f13c837eeb628e606323cc63dc24127e7a9804e2746d12\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"edbddef0538aac87bf6af714e12c4078fd6ada069b6fd0e1e5c1038b060999764e06c28b3ca38b8d540d0f60c72f7321ddc22d2537156999bad5098c89b6975a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-core\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core Jackson processing abstractions (aka Streaming API), implementation for JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c86c75392bf138d54d2a219bb1d0cbcd\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"60d600567c1862840397bf9ff5a92398edc5797b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"51fab7aad51ed588482edc507fd542747936c5094d1ab76ed21ddb63b96b610d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"112de40a31dc7d011f256f1d2fe0d9e2afc301a1f31974318f8d070c3e362b2ba96005167384244f630b915451db6694bd3cf6a9b793872351bc18f21c9de5e4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9daaf08467525e462234c53ddbf7287bcef15d8df7fbc64bcd558a91d11e8335b3a79368d194b126d3c8fb846800025b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0b4fdc8d11fc060461e74e773fce2e64d1a98bed7db6edf51784bb1b801da4bae744a2958e81c2e24cb992fec892fb6c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"751ad4f10a78cb36fccbbe1dfe208816f17619edd5adeabc86b7509201e03c3d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa5807b7d92d150fada6a4ecdbfce998bbea825a09af8381127ba3736de029ae9923f54d770b2e5c3f5c85d9b4bcf21e6893a5a3089db2d02f1432b85dfa0fe7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-core\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.xmlunit\",\n      \"name\" : \"xmlunit-core\",\n      \"version\" : \"2.9.1\",\n      \"description\" : \"XMLUnit for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"011288450a3905a7d97e3957b69e713e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e5833662d9a1279a37da3ef6f62a1da29fcd68c4\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7e70f23d4f75e05f0ee79f0f6b9e13b6cf51d34f36c5fc3a6b839429dde1efef\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1d07dc1582a1930664ab3cffd1443e85c83fec138c663f3070a9d3b283f818157b2cdd1589595867281a96d3b444b18c22c1ee3249a75c857c6ee9682785e8a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f54a506a08b66776d92d4379712ae9f7658cc89bd7b780eb629bd37143ff68e28cb2314539dc3c1ff13dc9cccba394f2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"7fd679371624f72417612491bac721a49f229744df3fc7455e5fd3983bd2de452a4eaabb707be7bac328f3beeea88d99\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c517aa9c543a4a3df361c30ba6609082a1dd5dc2abc351643ad5b733a1282773\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3797bade2087f791697f6736296381f8b158a2a93f50faeabcd96b4c9f48ad26fd78af56cc1036c449c35e624181961d54acdd7623b84c23c81c72d5d0fa57f1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"OW2\",\n      \"group\" : \"org.ow2.asm\",\n      \"name\" : \"asm\",\n      \"version\" : \"9.3\",\n      \"description\" : \"ASM, a very small and fast Java bytecode manipulation framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e1c3b96035117ab516ffe0de9bd696e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8e6300ef51c1d801a7ed62d07cd221aca3a90640\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1263369b59e29c943918de11d6d6152e2ec6085ce63e5710516f8c67d368e4bc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"04362f50a2b66934c2635196bf8e6bd2adbe4435f312d1d97f4733c911e070f5693941a70f586928437043d01d58994325e63744e71886ae53a62c824927a4d4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"304aa6673d587a68a06dd8601c6db0dc4d387f89a058b7600459522d94780e9e8d87a2778604fc41b81c43a57bf49ad6\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9744884ed03ced46ed36c68c7bb1f523678bcbb4f32ebeaa220157b8631e862d6573066dfc2092ed77dc7826ad17aef2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2be2d22fdbafe87b7cdda0498fc4f45db8d77a720b63ec1f7ffe8351e173b77b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a3ff403dd3eefbb7511d2360ab1ca3d1bf33b2f9d1c5738284be9d132eb6ad869f2d97e790ed0969132af30271e544d3725c02252267fe55e0339f89f3669ce1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"http://www.ow2.org/\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://mail.ow2.org/wws/arc/asm/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Core starter, including auto-configuration support, logging and YAML\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d9eb815815944bcdaeed5e63f32e5d7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bc03d7075fb9d9d4877218db48d5dae3dd72a65d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a25f2f4172c34f46b73fff03293370c3daf231a1db2883ef8032aa471779fb8b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"35cc80f9b10e81624324083a024c97e247e12f54762cfaadf40504903b0ebdc76d0226af1e4646bca445211b039913709ff48289dd57e27ecab18fd6e427d306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9acae9f3f77733a83d37641d3bd32d762225a08dcb20d61ff33a9038e8a4fe2dd39026bb08026cdb618437f68fc11382\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"1e605937a46c8371423b7876d5dae4363f718f70200a1276056bd6466d03096aa580708c7abc76618a141a542df29b24\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"331b3c120493fb5d9dd628beb8aa10382772a08d0a687103a2e87a4516fffde6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9f2612fbecec4664979896868e4766b1f66aaebc914e46a07a7ef7e5ff76786e5a73ae9ca5f364d23ae41f8bea2fb44e5034014950423fdc3a438ae1dc275820\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-core\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"81d2d784780b1fe54275ab4f3d0c3830\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"5b9185ee002f9e194d2cb21ddcf8bc5f3d4a69da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5d70fa6ae0548f89fb4c070423ecc2db050cebf248b0d5f3f2294375a6762382\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9fb1726f3a10f5e0bdd1cafcdc9532536679d04e5cdde9e54bdf18819ea2651bcaac0efddd6a8b5dbf3cfb8dfcd7ab0453f2ff3fa4e21a0f3796d4dd6d630433\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e644a094c17574fc9334772913aeabd6de0be8eacb0718981dbd97ee197a21f43ff3efe2c073f8863a4ff111f4ccb303\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2e8d5d4b1e202e19529270adc7992e9d187ad34bdd62ab7633359f3394059cdade69c88dddd3879dea40487cb17702da\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"25826af7f0a6fd192e83cd14481055b0c5477c325e51d17355d9ff97963380a0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0b2513e578a484562ad47a8a1a4d1fe8253a9a276fac49ea9732877d976a2d1827037caa5a6401d5659c765317acb94127e62f99373a4efea63b44ab4a1824be\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy-agent\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"The Byte Buddy agent offers convenience for attaching an agent to the local or a remote VM.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"389b6aca1ee862684592f6f041f81724\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"90ed94ac044ea8953b224304c762316e91fd6b31\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"67993a89d47ca58ff868802a4448ddd150e5fe4e5a5645ded990d7b4d557a6b9\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7f1a1310b1a0f60d6ff07dee8d9b7e404e8fb9a25a5c0c186e00cafc834e5a026a7694fb65279367dabfa1789c1f16192d0ea794b7f511f0bb3414b8d519e9a5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed1e1d594a7c2837311accf3f718cbc7c6e2034afcab13c63d72313ee1ffd18a53863f1ccd194b85b7e0ffed78bafc9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b3baeae67826ec4e4f71b2870220c362f153d2a126b04557302b5b8e24a58b9741bef7afa9c4e4f0fa1ea9371cbcb1df\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"01ccb9e430868deef5b51124073643eaf6dd2c8c7e4d6e70b59042c9d28e3361\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b621fa443ade355b10cc45329a5e0f700942dd39e633a8f2343ece00446cd42f5c1217b041a67b3143df86397c363f8dcad226f1e70b8755126512a74f878262\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-test\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring TestContext Framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fadfe62dd198a4acce4416acb28e2869\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c393079051398e02c20d8b24e02822f365123719\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2155779c3e461df55f3b093f0e6e4bda398664e3452efe599690bc9a3f1932f0\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5e6e4f76edbf17a321302bf6257c09ed7893e32c50fb3cace37b2271f3c488d397c67b5315ef3019ee6d28544f52cf593e0475bf00927cd67f0c668d6b3909a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"151df7daac9a3e3e74732405bd4feb17ad9ff3e4de196e767f39da675d4480994ed8da13e3b1b27c7b4ee9ebc17feef8\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9069193468f2ae4c65c94d3950541efe37498a4e19245ddc67909181e83e14019f956baba54da0b9d2e8a262db13abd0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"8ccf71564f5ee7e6a578031c7c8530a5ddf136cc1dce483818ebd30d53c851df\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"31049da217d1115b589780ffaa3ddfbf676cc58e70bd4cbc1f24c0cb2aea6b155539f8f9b3f6757f19719fed0a6102110f195b34cdd464b5e375132c25e7bb51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"32fd55a03f648868767c1bebedd198df\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6e5c7dd668d6349cb99e52ab8321e73479a309bc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c1a386e901fae28e493185a47c8cea988fb1a37422b353a0f8b4df2e6c5d6037\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c97a2f9eefa6f34441fc0c97744873040bbe49d335954edab43bab25876a33f4b3f11347459420569ef660449728aa093bbae5d42c0fa733a0b624706b57a65d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"873dfccaf8366ce5b14dc0b5498205debecd90ecba20b1f1c924721764d546b5b9629dd57c486e5a5a2bc38954bf3824\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"67f09e3174ae3fac6ddea13b56dcf078165e715cb18afd73d86bb980357e365cef6e62083231f09ae2accddfe62f5bcb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1c2a60003b13025c959e7728b3f4469b67bad8649d2080c0871418fb52b1c078\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7c03cfaeabed9c57b26e083bcb0ca9a114c491216fc7e9652a39a5468579175e575ace315493610fdc7711c6557eff11933fbd28f5433c237d2277bee102c5a6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"json-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"af9b7eda9c435acaf22e840991c7b10f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"57a64f421b472849c40e77d2e7cce3a141b41e99\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"432b9e545848c4141b80717b26e367f83bf33f19250a228ce75da6e967da2bc7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"56284bb3cee2bcc3684cdcc610115c7eacafdbd70aa852cb0209616b0503dfd448c5110b50e11a71b1c61a6e7ea27594ff63cc968230374555cc6f652d69d372\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fbbd6899d344c3158007f2f033165284323f1ecdfa49e17730d9d2bed8b3d77bbdc209a72a388e9e15a5bed9d9c8eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0f18f178117f8c640e7e1ac2ed4c2b28e331f658f40eac2f5974e891f7130b760e4f057859a537caaa046ba9c086a24a\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4c91eaa12f7c0ee08264ad95d016cfa41af08c963055b7f9076771da402e93e0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0c5fad6395cf3fd25c04fd1e2c915351da4849475b463e017b760ef97800addb170d11f89791dd29ab867e343c35fd1f3ea7935622ba728d789c9f2e7fd1da51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-expression\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Expression Language (SpEL)\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2f56216dc7ee08cbeafa54ccf18cad35\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"98786397734b27b7c8843a6b01a7fa34d40d6806\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fef5fb19f375a8632d2a117f4b3aed059b959e9693e90c3b7f57b7cad2f9e0b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"a28e984d9ff1d4078d57f139ff28065ffba7f325c891c74c0774cd3ccfe50a9462cd93483c28c8ca4674b581ab723687c37c5c88e7cb080823d5629fa684e7f8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a84fb64144a67b56ce322fc9f4948a9491f6f5876d198eb57c99f38540971a0779a2949b93cc5f32662f97a83823ea87\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b099ce06de6a5543e52a2d43c97c4ed6567e82263db29849ff09cf37bf48e3e9974308698c2f272187508e242f756576\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"efa3768de47e3b1ff9257f8367a528e38b3eec9c972eb7ba3dd8f60da626fb17\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"95d7011482520e797a25f9d9b8db1b1bf6c24b3ddb3ca4b70fe5a1a58ed04ea870f86f8393f884dad8b893a6fc53ad8da1b21fdc01d9169564c3dc0229824b27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Spring Boot's Actuator which provides production ready features to help you monitor and manage your application\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"59713236dc4fc4b1562a3ea9788bde1e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca17ff67e80a230f04d40d73321d623b769e361d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"31c28021755feab49cc9310a8353382b3ca35d0adf02926b83e4c44ea4942898\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"ed618c7f1e3337c90919551ad4f14996bb2a78f773ba00c1e02d5a991d1c578e940d9b73f5e01045115c7b5d3f096f8de6720ba0d28992a586ef834948f17766\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"45956cbd019f099f96f36391c98fd23ea32698035f90f6e4e4df0d9a43dc03ef6db2954c2871da76a038511280591b43\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3a08b673deb39ab5db9561281245b76e9f57410601e5ce4040cefedb02e2a19abb45a98d2de170fbbac7b7f0b93eceb3\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"12151432b32e26bab903572023ea022757a31177e4a6315d8fcd15bbbf34731c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"911f109b63d07f20de51f8a2de8799e32fdff05a52def36d408cb1da72a3bb63ff0878f850a7ad1cc9e85393f24ac58c6b8dd4068f11d9e70bc1e130974db00f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-beans\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Beans\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5ee147f2234968eeab4b469af4d3b5f1\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abf52f2254975a3b1e95b2b63fb8b01d891cdc51\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"742baa41c1b0282ef01b3d542dc1b1de71db2578bd9ddd9a7d57fb191234b194\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"efd0eb5a073c899515ae144a4fcb4fc97cc53cbd4236d0e6a30df8fa8873fcd9bc509bc3fa88d1bff86a94dc3dbc5106374d0117f64ec8df9e6affe8f98aaa07\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6214558d1024fa3b5545079268b0b2fbeda93768a0665d617612ddf4e42e11b770c38c05cb86e3ae558025afa67beea5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8170ccea30165f25c533e27c0de38b590ca72f285cfc365c60e97745e78532213d6c93bdbea56f561dd180297a8c5ab4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2761e0814e167de13ed08ce748880006407eda2fa744a347f57684c2bc9bb6fe\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ecdeb4cd558af513ed381942f35bd2d8dfa9b0db446dbc8c5326656ade960682283c71fcaae5578ca431f705f1a86041b0764bd453f30e738be65c4f0bbf37d1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\"\n    }\n  ],\n  \"dependencies\" : [\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n        \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n        \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n        \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n        \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n        \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n        \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n        \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n        \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n        \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n        \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n        \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"dependsOn\" : [ ]\n    }\n  ]\n}"
  },
  {
    "path": "documentation/spring-boot-docs/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nimport org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask\n\nimport org.springframework.boot.build.docs.ConfigureJavadocLinks\nimport org.springframework.boot.build.optional.OptionalDependenciesPlugin\n\nplugins {\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"org.jetbrains.dokka\"\n\tid \"java\"\n\tid \"org.antora\"\n\tid \"org.springframework.boot.aggregator\"\n\tid \"org.springframework.boot.antora-contributor\"\n\tid \"org.springframework.boot.antora-dependencies\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Docs\"\n\nconfigurations {\n\tremoteSpringApplicationExample\n\tresolvedBom\n\tspringApplicationExample\n\ttestSlices\n\tall {\n\t\tresolutionStrategy.eachDependency { DependencyResolveDetails details ->\n\t\t\tif (details.requested.module.group == \"org.apache.kafka\" && details.requested.module.name == \"kafka-server-common\") {\n\t\t\t\tdetails.artifactSelection {\n\t\t\t\t\tselectArtifact(DependencyArtifact.DEFAULT_TYPE, null, null)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\njar {\n\tenabled = false\n}\n\njavadoc {\n\tenabled = false\n}\n\njavadocJar {\n\tenabled = false\n}\n\nsourcesJar {\n\tenabled = false\n}\n\n// To avoid a redeclaration error with Kotlin compiler\ntasks.named('compileKotlin', KotlinCompilationTask.class) {\n    javaSources.from = []\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nplugins.withType(EclipsePlugin) {\n\teclipse.classpath { classpath ->\n\t\tclasspath.plusConfigurations.add(configurations.getByName(sourceSets.main.runtimeClasspathConfigurationName))\n\t}\n}\n\ndependencies {\n\tcompileOnly(\"org.hamcrest:hamcrest-core\")\n\n\tdokka(project(path: \":core:spring-boot\"))\n\tdokka(project(path: \":module:spring-boot-resttestclient\"))\n\n\timplementation(project(path: \":cli:spring-boot-cli\"))\n\timplementation(project(path: \":core:spring-boot-docker-compose\"))\n\timplementation(project(path: \":core:spring-boot-test\"))\n\timplementation(project(path: \":core:spring-boot-test-autoconfigure\"))\n\timplementation(project(path: \":core:spring-boot-testcontainers\"))\n\timplementation(project(path: \":loader:spring-boot-loader-tools\"))\n\timplementation(project(path: \":module:spring-boot-actuator\"))\n\timplementation(project(path: \":module:spring-boot-actuator-autoconfigure\"))\n\timplementation(project(path: \":module:spring-boot-amqp\"))\n\timplementation(project(path: \":module:spring-boot-cache\"))\n\timplementation(project(path: \":module:spring-boot-cache-test\"))\n\timplementation(project(path: \":module:spring-boot-data-cassandra\"))\n\timplementation(project(path: \":module:spring-boot-data-cassandra-test\"))\n\timplementation(project(path: \":module:spring-boot-data-couchbase-test\"))\n\timplementation(project(path: \":module:spring-boot-data-elasticsearch\"))\n\timplementation(project(path: \":module:spring-boot-data-elasticsearch-test\"))\n\timplementation(project(path: \":module:spring-boot-data-jpa-test\"))\n\timplementation(project(path: \":module:spring-boot-data-ldap-test\"))\n\timplementation(project(path: \":module:spring-boot-data-mongodb-test\"))\n\timplementation(project(path: \":module:spring-boot-data-neo4j\"))\n\timplementation(project(path: \":module:spring-boot-data-neo4j-test\"))\n\timplementation(project(path: \":module:spring-boot-data-redis-test\"))\n\timplementation(project(path: \":module:spring-boot-devtools\"))\n\timplementation(project(path: \":module:spring-boot-graphql-test\"))\n\timplementation(project(path: \":module:spring-boot-grpc-client\"))\n\timplementation(project(path: \":module:spring-boot-grpc-server\"))\n\timplementation(project(path: \":module:spring-boot-grpc-test\"))\n\timplementation(project(path: \":module:spring-boot-health\"))\n\timplementation(project(path: \":module:spring-boot-hibernate\"))\n\timplementation(project(path: \":module:spring-boot-http-converter\"))\n\timplementation(project(path: \":module:spring-boot-http-codec\"))\n\timplementation(project(path: \":module:spring-boot-integration\"))\n\timplementation(project(path: \":module:spring-boot-jackson\"))\n\timplementation(project(path: \":module:spring-boot-jdbc\"))\n\timplementation(project(path: \":module:spring-boot-jdbc-test\"))\n\timplementation(project(path: \":module:spring-boot-jooq-test\"))\n\timplementation(project(path: \":module:spring-boot-jpa\"))\n\timplementation(project(path: \":module:spring-boot-jms\"))\n\timplementation(project(path: \":module:spring-boot-jsonb\"))\n\timplementation(project(path: \":module:spring-boot-ldap\"))\n\timplementation(project(path: \":module:spring-boot-micrometer-metrics\"))\n\timplementation(project(path: \":module:spring-boot-persistence\"))\n\timplementation(project(path: \":module:spring-boot-r2dbc\"))\n\timplementation(project(path: \":module:spring-boot-restdocs\"))\n\timplementation(project(path: \":module:spring-boot-reactor-netty\"))\n\timplementation(project(path: \":module:spring-boot-restclient\"))\n\timplementation(project(path: \":module:spring-boot-restclient-test\"))\n\timplementation(project(path: \":module:spring-boot-resttestclient\"))\n\timplementation(project(path: \":module:spring-boot-security\"))\n\timplementation(project(path: \":module:spring-boot-tomcat\"))\n\timplementation(project(path: \":module:spring-boot-web-server-test\"))\n\timplementation(project(path: \":module:spring-boot-webclient\"))\n\timplementation(project(path: \":module:spring-boot-webclient-test\"))\n\timplementation(project(path: \":module:spring-boot-webflux\"))\n\timplementation(project(path: \":module:spring-boot-webflux-test\"))\n\timplementation(project(path: \":module:spring-boot-webmvc\"))\n\timplementation(project(path: \":module:spring-boot-webmvc-test\"))\n\timplementation(project(path: \":module:spring-boot-webservices\"))\n\timplementation(project(path: \":module:spring-boot-webservices-test\"))\n\timplementation(project(path: \":module:spring-boot-webtestclient\"))\n\timplementation(\"ch.qos.logback:logback-classic\")\n\timplementation(\"com.redis:testcontainers-redis\")\n\timplementation(\"com.zaxxer:HikariCP\")\n\timplementation(\"io.micrometer:micrometer-jakarta9\")\n\timplementation(\"io.micrometer:micrometer-tracing\")\n\timplementation(\"io.micrometer:micrometer-registry-graphite\")\n\timplementation(\"io.micrometer:micrometer-registry-jmx\")\n\timplementation(\"io.opentelemetry:opentelemetry-exporter-otlp\")\n\timplementation(\"io.opentelemetry:opentelemetry-sdk-extension-autoconfigure\")\n\timplementation(\"io.opentelemetry:opentelemetry-sdk-metrics\")\n\timplementation(\"io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0\")\n\timplementation(\"io.projectreactor.netty:reactor-netty-http\")\n\timplementation(\"jakarta.annotation:jakarta.annotation-api\")\n\timplementation(\"jakarta.jms:jakarta.jms-api\")\n\timplementation(\"jakarta.persistence:jakarta.persistence-api\")\n\timplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\timplementation(\"jakarta.validation:jakarta.validation-api\")\n\timplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\timplementation(\"org.apache.commons:commons-dbcp2\")\n\timplementation(\"org.apache.kafka:kafka-streams\") {\n\t\texclude group: \"org.lz4\", module: \"lz4-java\"\n\t}\n\timplementation(\"org.apache.logging.log4j:log4j-to-slf4j\")\n\timplementation(\"org.apache.tomcat.embed:tomcat-embed-core\")\n\timplementation(\"org.assertj:assertj-core\")\n\timplementation(\"org.cache2k:cache2k-spring\")\n\timplementation(\"org.apache.groovy:groovy\")\n\timplementation(\"org.glassfish.jersey.containers:jersey-container-servlet\")\n\timplementation(\"org.glassfish.jersey.core:jersey-server\")\n\timplementation(\"org.hibernate.orm:hibernate-jcache\") {\n\t\texclude group: \"javax.activation\", module: \"javax.activation-api\"\n\t\texclude group: \"javax.persistence\", module: \"javax.persistence-api\"\n\t\texclude group: \"org.jboss.spec.javax.transaction\", module: \"jboss-transaction-api_1.2_spec\"\n\t}\n\timplementation(\"org.htmlunit:htmlunit\") {\n\t\texclude group: \"xml-apis\", module: \"xml-apis\"\n\t}\n\timplementation(\"org.jetbrains.kotlin:kotlin-stdlib-jdk8\")\n\timplementation(\"org.jooq:jooq\")\n\timplementation(\"org.mockito:mockito-core\")\n\timplementation(\"org.mongodb:mongodb-driver-sync\")\n\timplementation(\"org.postgresql:r2dbc-postgresql\")\n\timplementation(\"org.quartz-scheduler:quartz\")\n\timplementation(\"org.slf4j:jul-to-slf4j\")\n\timplementation(\"org.springframework:spring-jdbc\")\n\timplementation(\"org.springframework:spring-jms\")\n\timplementation(\"org.springframework:spring-orm\")\n\timplementation(\"org.springframework:spring-test\")\n\timplementation(\"org.springframework:spring-web\")\n\timplementation(\"org.springframework:spring-webflux\")\n\timplementation(\"org.springframework:spring-webmvc\")\n\timplementation(\"org.springframework:spring-websocket\")\n\timplementation(\"org.springframework.amqp:spring-amqp\")\n\timplementation(\"org.springframework.amqp:spring-rabbit\")\n\timplementation(\"org.springframework.batch:spring-batch-core\")\n\timplementation(\"org.springframework.data:spring-data-couchbase\")\n\timplementation(\"org.springframework.data:spring-data-envers\") {\n\t\texclude group: \"javax.activation\", module: \"javax.activation-api\"\n\t\texclude group: \"javax.persistence\", module: \"javax.persistence-api\"\n\t\texclude group: \"org.jboss.spec.javax.transaction\", module: \"jboss-transaction-api_1.2_spec\"\n\t}\n\timplementation(\"org.springframework.data:spring-data-jpa\")\n\timplementation(\"org.springframework.data:spring-data-ldap\")\n\timplementation(\"org.springframework.data:spring-data-mongodb\")\n\timplementation(\"org.springframework.data:spring-data-redis\")\n\timplementation(\"org.springframework.data:spring-data-r2dbc\")\n\timplementation(\"org.springframework.graphql:spring-graphql\")\n\timplementation(\"org.springframework.graphql:spring-graphql-test\")\n\timplementation(\"org.springframework.kafka:spring-kafka\") {\n\t\texclude group: \"org.lz4\", module: \"lz4-java\"\n\t}\n\timplementation(\"org.springframework.kafka:spring-kafka-test\")\n\timplementation(\"org.springframework.pulsar:spring-pulsar\")\n\timplementation(\"org.springframework.restdocs:spring-restdocs-mockmvc\")\n\timplementation(\"org.springframework.restdocs:spring-restdocs-webtestclient\")\n\timplementation(\"org.springframework.security:spring-security-config\")\n\timplementation(\"org.springframework.security:spring-security-oauth2-client\")\n\timplementation(\"org.springframework.security:spring-security-test\")\n\timplementation(\"org.springframework.security:spring-security-web\")\n\timplementation(\"org.springframework.ws:spring-ws-core\")\n\timplementation(\"org.springframework.ws:spring-ws-test\")\n\timplementation(\"org.testcontainers:testcontainers-elasticsearch\")\n\timplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\timplementation(\"org.testcontainers:testcontainers-mongodb\")\n\timplementation(\"org.testcontainers:testcontainers-neo4j\")\n\timplementation(\"org.junit.jupiter:junit-jupiter\")\n\timplementation(\"org.yaml:snakeyaml\")\n\n\tjavadocMacros(project(\":loader:spring-boot-loader\"))\n\tjavadocMacros(project(\":module:spring-boot-activemq\"))\n\tjavadocMacros(project(\":module:spring-boot-artemis\"))\n\tjavadocMacros(project(\":module:spring-boot-batch\"))\n\tjavadocMacros(project(\":module:spring-boot-batch-data-mongodb\"))\n\tjavadocMacros(project(\":module:spring-boot-batch-jdbc\"))\n\tjavadocMacros(project(\":module:spring-boot-cache-test\"))\n\tjavadocMacros(project(\":module:spring-boot-data-r2dbc-test\"))\n\tjavadocMacros(project(\":module:spring-boot-data-redis\"))\n\tjavadocMacros(project(\":module:spring-boot-data-jdbc-test\"))\n\tjavadocMacros(project(\":module:spring-boot-flyway\"))\n\tjavadocMacros(project(\":module:spring-boot-freemarker\"))\n\tjavadocMacros(project(\":module:spring-boot-gson\"))\n\tjavadocMacros(project(\":module:spring-boot-hazelcast\"))\n\tjavadocMacros(project(\":module:spring-boot-http-codec\"))\n\tjavadocMacros(project(\":module:spring-boot-jackson\"))\n\tjavadocMacros(project(\":module:spring-boot-jackson2\"))\n\tjavadocMacros(project(\":module:spring-boot-jersey\"))\n\tjavadocMacros(project(\":module:spring-boot-jetty\"))\n\tjavadocMacros(project(\":module:spring-boot-kafka\"))\n\tjavadocMacros(project(\":module:spring-boot-liquibase\"))\n\tjavadocMacros(project(\":module:spring-boot-mail\"))\n\tjavadocMacros(project(\":module:spring-boot-micrometer-metrics-test\"))\n\tjavadocMacros(project(\":module:spring-boot-micrometer-tracing-opentelemetry\"))\n\tjavadocMacros(project(\":module:spring-boot-micrometer-tracing-test\"))\n\tjavadocMacros(project(\":module:spring-boot-mustache\"))\n\tjavadocMacros(project(\":module:spring-boot-opentelemetry\"))\n\tjavadocMacros(project(\":module:spring-boot-pulsar\"))\n\tjavadocMacros(project(\":module:spring-boot-quartz\"))\n\tjavadocMacros(project(\":module:spring-boot-rsocket\"))\n\tjavadocMacros(project(\":module:spring-boot-security-oauth2-client\"))\n\tjavadocMacros(project(\":module:spring-boot-security-saml2\"))\n\tjavadocMacros(project(\":module:spring-boot-servlet\"))\n\tjavadocMacros(project(\":module:spring-boot-tomcat\"))\n\tjavadocMacros(project(\":module:spring-boot-validation\"))\n\tjavadocMacros(project(\":module:spring-boot-web-server\"))\n\tjavadocMacros(project(\":module:spring-boot-webflux-test\"))\n\tjavadocMacros(project(\":module:spring-boot-webtestclient\"))\n\tjavadocMacros(project(\":module:spring-boot-zipkin\"))\n\tjavadocMacros(\"co.elastic.clients:elasticsearch-rest5-client\")\n\tjavadocMacros(\"com.h2database:h2\")\n\tjavadocMacros(\"com.hazelcast:hazelcast-spring\")\n\tjavadocMacros(\"com.redis:testcontainers-redis\")\n\tjavadocMacros(\"io.lettuce:lettuce-core\")\n\tjavadocMacros(\"io.micrometer:micrometer-registry-new-relic\")\n\tjavadocMacros(\"io.micrometer:micrometer-registry-otlp\")\n\tjavadocMacros(\"io.opentelemetry:opentelemetry-sdk-logs\")\n\tjavadocMacros(\"io.opentelemetry:opentelemetry-sdk-metrics\")\n\tjavadocMacros(\"io.opentelemetry:opentelemetry-sdk-trace\")\n\tjavadocMacros(\"io.prometheus:prometheus-metrics-tracer-common\")\n\tjavadocMacros(\"io.prometheus:simpleclient_tracer_common\")\n\tjavadocMacros(\"io.rsocket:rsocket-core\")\n\tjavadocMacros(\"jakarta.json.bind:jakarta.json.bind-api\")\n\tjavadocMacros(\"jakarta.mail:jakarta.mail-api\")\n\tjavadocMacros(\"jakarta.websocket:jakarta.websocket-api\")\n\tjavadocMacros(\"org.apache.artemis:artemis-jakarta-server\")\n\tjavadocMacros(\"org.apache.logging.log4j:log4j-core\")\n\tjavadocMacros(\"org.eclipse.jetty:jetty-client\")\n\tjavadocMacros(\"org.infinispan:infinispan-core\")\n\tjavadocMacros(\"org.liquibase:liquibase-core\")\n\tjavadocMacros(\"org.messaginghub:pooled-jms\")\n\tjavadocMacros(\"org.neo4j.driver:neo4j-java-driver-observation-micrometer\")\n\tjavadocMacros(\"org.postgresql:postgresql\")\n\tjavadocMacros(\"org.projectlombok:lombok\")\n\tjavadocMacros(\"org.seleniumhq.selenium:selenium-api\")\n\tjavadocMacros(\"org.springframework.amqp:spring-rabbit-stream\")\n\tjavadocMacros(\"org.springframework.data:spring-data-rest-webmvc\")\n\tjavadocMacros(\"org.springframework.hateoas:spring-hateoas\")\n\tjavadocMacros(\"org.springframework.integration:spring-integration-core\")\n\tjavadocMacros(\"org.springframework.integration:spring-integration-rsocket\")\n\tjavadocMacros(\"org.springframework.security:spring-security-oauth2-authorization-server\")\n\tjavadocMacros(\"org.springframework.security:spring-security-oauth2-resource-server\")\n\tjavadocMacros(\"org.springframework.session:spring-session-core\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-activemq\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-cassandra\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-clickhouse\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-couchbase\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-elasticsearch\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-grafana\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-jdbc\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-kafka\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-ldap\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-mariadb\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-mssqlserver\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-mysql\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-oracle-free\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-oracle-xe\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-postgresql\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-pulsar\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-rabbitmq\")\n\tjavadocMacros(\"org.testcontainers:testcontainers-redpanda\")\n\tjavadocMacros(\"org.thymeleaf:thymeleaf-spring6\")\n\tjavadocMacros(\"tools.jackson.dataformat:jackson-dataformat-xml\")\n\n\tremoteSpringApplicationExample(platform(project(\":platform:spring-boot-dependencies\")))\n\tremoteSpringApplicationExample(project(\":module:spring-boot-devtools\"))\n\tremoteSpringApplicationExample(project(\":starter:spring-boot-starter-logging\"))\n\tremoteSpringApplicationExample(\"org.springframework:spring-web\")\n\n\tresolvedBom(project(path: \":platform:spring-boot-dependencies\", configuration: \"resolvedBom\"))\n\n\tspringApplicationExample(platform(project(\":platform:spring-boot-dependencies\")))\n\tspringApplicationExample(project(path: \":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":module:spring-boot-actuator-autoconfigure\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(project(\":starter:spring-boot-starter-webmvc\"))\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"org.springframework:spring-jdbc\")\n\n\ttestSlices(project(path: \":core:spring-boot-test-autoconfigure\", configuration: \"testSliceMetadata\"))\n}\n\ndokka {\n\tmoduleName.set(\"Spring Boot Kotlin API\")\n}\n\nconfigurations {\n\tjavadoc {\n\t\tcanBeConsumed = true\n\t\tcanBeResolved = false\n\t\tattributes {\n\t\t\tattribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))\n\t\t\tattribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EMBEDDED))\n\t\t\tattribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, DocsType.JAVADOC))\n\t\t}\n\t}\n\tjavadocSource {\n\t\ttransitive = false\n\t\tcanBeConsumed = false\n\t\tcanBeResolved = true\n\t\tattributes {\n\t\t\tattribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.VERIFICATION))\n\t\t\tattribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, DocsType.SOURCES))\n\t\t\tattribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE, objects.named(VerificationType.class, VerificationType.MAIN_SOURCES))\n\t\t}\n\t\textendsFrom configurations.javadoc\n\t}\n\tjavadocClasspath {\n\t\tcanBeConsumed = false\n\t\tcanBeResolved = true\n\t\tattributes {\n\t\t\tattribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME))\n\t\t}\n\t\textendsFrom configurations.javadoc\n\t\tresolutionStrategy.eachDependency {\n\t\t\tif (it.requested.group == 'org.opensaml') {\n\t\t\t\tit.useVersion '4.0.1'\n\t\t\t}\n\t\t}\n\t}\n}\n\ndef aggregatedJavadoc = tasks.register('aggregatedJavadoc', Javadoc) {\n\tdependsOn configurations.resolvedBom\n\tdestinationDir = project.file(project.layout.buildDirectory.dir(\"docs/javadoc\"))\n\tsource = configurations.javadocSource\n\tclasspath = configurations.javadocClasspath\n\tinclude(\"**/*.java\")\n\toptions {\n\t\tauthor = true\n\t\tdocTitle = \"Spring Boot ${project.version} API\"\n\t\tmemberLevel = \"protected\"\n\t\toutputLevel = \"quiet\"\n\t\tsplitIndex = true\n\t\tuse = true\n\t\twindowTitle = \"Spring Boot ${project.version} API\"\n\t}\n\tdoFirst(new ConfigureJavadocLinks(configurations.resolvedBom, [\"Spring Framework\", \"Spring Security\", \"Tomcat\"]))\n}\n\nproject.rootProject.gradle.projectsEvaluated {\n\trootProject.subprojects\n\t\t.findAll { it != project }\n\t\t.findAll { it.plugins.hasPlugin(JavaPlugin) && it.plugins.hasPlugin(MavenPublishPlugin) }\n\t\t.findAll { !it.path.contains(\":build-plugin:\") }\n\t\t.findAll { !it.path.contains(\":cli:\") }\n\t\t.findAll { !it.path.contains(\":configuration-metadata:\") }\n\t\t.findAll { !it.path.contains(\":core:spring-boot-properties-migrator\") }\n\t\t.findAll { !it.path.contains(\":loader:spring-boot-jarmode-tools\") }\n\t\t.findAll { !it.name.startsWith('spring-boot-starter') }\n\t\t.each { javadocProject ->\n\t\t\tdependencies {\n\t\t\t\tjavadoc(project(javadocProject.path)) {\n\t\t\t\t\texclude group: \"org.lz4\", module: \"lz4-java\"\n\t\t\t\t}\n\t\t\t\tif (javadocProject.plugins.hasPlugin(OptionalDependenciesPlugin)) {\n\t\t\t\t\tjavadoc(project(path: javadocProject.path, configuration: 'optional')) {\n\t\t\t\t\t\texclude group: \"org.lz4\", module: \"lz4-java\"\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n}\n\naggregates {\n\ttestSliceMetadata {\n\t\tcategory = Category.DOCUMENTATION\n\t\tusage = \"test-slice-metadata\"\n\t}\n\tdevtoolsPropertyDefaults {\n\t\tcategory = Category.LIBRARY\n\t\tusage = \"java-runtime\"\n\t}\n}\n\ntasks.register(\"documentTestSlices\", org.springframework.boot.build.test.autoconfigure.DocumentTestSlices) {\n\ttestSlices = aggregates.testSliceMetadata.files\n\toutputFile = layout.buildDirectory.file(\"generated/docs/test-auto-configuration/documented-slices.adoc\")\n}\n\ntasks.register(\"documentStarters\", org.springframework.boot.build.starters.DocumentStarters) {\n\toutputDir = layout.buildDirectory.dir(\"generated/docs/using/starters/\")\n}\n\ndef autoConfigurationMetadataAggregate = aggregates.create(\"autoConfigurationMetadata\") {\n\tcategory = Category.DOCUMENTATION\n\tusage = \"auto-configuration-metadata\"\n}\n\ntasks.register(\"documentAutoConfigurationClasses\", org.springframework.boot.build.autoconfigure.DocumentAutoConfigurationClasses) {\n\tautoConfiguration = autoConfigurationMetadataAggregate.files\n\toutputDir = layout.buildDirectory.dir(\"generated/docs/auto-configuration-classes/documented-auto-configuration-classes/\")\n}\n\ntasks.register(\"documentDependencyVersionCoordinates\", org.springframework.boot.build.docs.DocumentManagedDependencies) {\n\toutputFile = layout.buildDirectory.file(\"generated/docs/dependency-versions/documented-coordinates.adoc\")\n\tresolvedBoms = configurations.resolvedBom\n}\n\ntasks.register(\"documentDependencyVersionProperties\", org.springframework.boot.build.docs.DocumentVersionProperties) {\n\toutputFile = layout.buildDirectory.file(\"generated/docs/dependency-versions/documented-properties.adoc\")\n\tresolvedBoms = configurations.resolvedBom\n}\n\ndef configurationPropertiesMetadataAggregate = aggregates.create(\"configurationPropertiesMetadata\") {\n\tcategory = Category.DOCUMENTATION\n\tusage = \"configuration-properties-metadata\"\n}\n\ndef checkAggregatedSpringConfigurationMetadata = tasks.register(\"checkAggregatedSpringConfigurationMetadata\", org.springframework.boot.build.context.properties.CheckAggregatedSpringConfigurationMetadata) {\n\tconfigurationPropertyMetadata = configurationPropertiesMetadataAggregate.files\n\treportLocation = layout.buildDirectory.file(\"checkAggregatedSpringConfigurationMetadata/report.txt\")\n}\ntasks.named(\"check\") { dependsOn checkAggregatedSpringConfigurationMetadata }\n\ntasks.register(\"documentConfigurationProperties\", org.springframework.boot.build.context.properties.DocumentConfigurationProperties) {\n\tconfigurationPropertyMetadata = configurationPropertiesMetadataAggregate.files\n\tdeprecated = false\n\toutputDir = layout.buildDirectory.dir(\"generated/docs/application-properties\")\n}\n\ntasks.register(\"documentDeprecatedConfigurationProperties\", org.springframework.boot.build.context.properties.DocumentConfigurationProperties) {\n\tconfigurationPropertyMetadata = configurationPropertiesMetadataAggregate.files\n\tdeprecated = true\n\toutputDir = layout.buildDirectory.dir(\"generated/docs/deprecated-application-properties\")\n}\n\ntasks.register(\"documentDevtoolsPropertyDefaults\", org.springframework.boot.build.devtools.DocumentDevtoolsPropertyDefaults) {\n\tdefaults = aggregates.devtoolsPropertyDefaults.files\n}\n\ntasks.register(\"runRemoteSpringApplicationExample\", org.springframework.boot.build.docs.ApplicationRunner) {\n\tclasspath = configurations.remoteSpringApplicationExample\n\tmainClass = \"org.springframework.boot.devtools.RemoteSpringApplication\"\n\targs = [\"https://myapp.example.com\", \"--spring.devtools.remote.secret=secret\", \"--spring.devtools.livereload.enabled=true\", \"--spring.devtools.livereload.port=0\"]\n\toutput = layout.buildDirectory.file(\"example-output/remote-spring-application.txt\")\n\texpectedLogging = \"Started RemoteSpringApplication in \"\n\tapplicationJar = \"/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/${project.version}/spring-boot-devtools-${project.version}.jar\"\n\tnormalizeLiveReloadPort()\n}\n\ntasks.register(\"runSpringApplicationExample\", org.springframework.boot.build.docs.ApplicationRunner) {\n\tclasspath = configurations.springApplicationExample + sourceSets.main.output\n\tmainClass = \"org.springframework.boot.docs.features.logexample.MyApplication\"\n\targs = [\"--server.port=0\"]\n\toutput = layout.buildDirectory.file(\"example-output/spring-application.txt\")\n\texpectedLogging = \"Started MyApplication in \"\n\tnormalizeTomcatPort()\n}\n\ntasks.register(\"runLoggingFormatExample\", org.springframework.boot.build.docs.ApplicationRunner) {\n\tclasspath = configurations.springApplicationExample + sourceSets.main.output\n\tmainClass = \"org.springframework.boot.docs.features.logexample.MyApplication\"\n\targs = [\"--spring.main.banner-mode=off\", \"--server.port=0\", \"--spring.application.name=myapp\"]\n\toutput = layout.buildDirectory.file(\"example-output/logging-format.txt\")\n\texpectedLogging = \"Started MyApplication in \"\n\tnormalizeTomcatPort()\n}\n\ndef getRelativeExamplesPath(var outputs) {\n\tdef fileName = outputs.files.singleFile.name\n\t'example$example-output/' + fileName\n}\n\nantoraDependencies {\n\t'actuator-rest-api' {\n\t\tpath = \":documentation:spring-boot-actuator-docs\"\n\t\tsource()\n\t\taggregateContent()\n\t}\n\t'gradle-plugin' {\n\t\tpath = \":build-plugin:spring-boot-gradle-plugin\"\n\t\tsource()\n\t\tcatalogContent()\n\t}\n\t'maven-plugin' {\n\t\tpath = \":build-plugin:spring-boot-maven-plugin\"\n\t\tsource()\n\t\tcatalogContent()\n\t\taggregateContent()\n\t}\n}\n\nantoraContributions {\n\t'api' {\n\t\tpublish()\n\t\tcatalogContent {\n\t\t\tfrom(aggregatedJavadoc) {\n\t\t\t\tinto \"java\"\n\t\t\t}\n\t\t\tfrom(tasks.named(\"dokkaGeneratePublicationHtml\")) {\n\t\t\t\tinto \"kotlin\"\n\t\t\t}\n\t\t}\n\t}\n\t'root' {\n\t\tpublish()\n\t\taggregateContent {\n\t\t\tfrom(\"src/main\") {\n\t\t\t\tinto \"modules/ROOT/examples\"\n\t\t\t}\n\t\t\tfrom(configurationPropertiesMetadataAggregate.files) {\n\t\t\t\teachFile {\n\t\t\t\t\tit.path = rootProject\n\t\t\t\t\t\t.projectDir\n\t\t\t\t\t\t.toPath()\n\t\t\t\t\t\t.relativize(it.file.toPath())\n\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t.replace('\\\\', '/')\n\t\t\t\t\t\t.replaceAll('.*/([^/]+)/build.*', 'modules/ROOT/partials/$1/spring-configuration-metadata.json')\n\t\t\t\t}\n\t\t\t}\n\t\t\tfrom(runRemoteSpringApplicationExample) {\n\t\t\t\tinto \"modules/ROOT/examples\"\n\t\t\t}\n\t\t\tfrom(documentDevtoolsPropertyDefaults) {\n\t\t\t\tinto \"modules/ROOT/partials/propertydefaults\"\n\t\t\t}\n\t\t\tfrom(documentStarters) {\n\t\t\t\tinto \"modules/ROOT/partials/starters\"\n\t\t\t}\n\t\t\tfrom(documentTestSlices) {\n\t\t\t\tinto \"modules/appendix/partials/slices\"\n\t\t\t}\n\t\t\tfrom(runSpringApplicationExample) {\n\t\t\t\tinto \"modules/ROOT/partials/application\"\n\t\t\t}\n\t\t\tfrom(runLoggingFormatExample) {\n\t\t\t\tinto \"modules/ROOT/partials/logging\"\n\t\t\t}\n\t\t\tfrom(documentDependencyVersionCoordinates) {\n\t\t\t\tinto \"modules/appendix/partials/dependency-versions\"\n\t\t\t}\n\t\t\tfrom(documentDependencyVersionProperties) {\n\t\t\t\tinto \"modules/appendix/partials/dependency-versions\"\n\t\t\t}\n\t\t\tfrom(documentAutoConfigurationClasses) {\n\t\t\t\tinto \"modules/appendix/partials/auto-configuration-classes\"\n\t\t\t\tinclude \"nav.adoc\"\n\t\t\t}\n\t\t\tfrom(documentAutoConfigurationClasses) {\n\t\t\t\tinto \"modules/appendix/pages/auto-configuration-classes\"\n\t\t\t\texclude \"nav.adoc\"\n\t\t\t}\n\t\t\tfrom(documentConfigurationProperties) {\n\t\t\t\tinto \"modules/appendix/partials/configuration-properties\"\n\t\t\t}\n\t\t\tfrom(documentDeprecatedConfigurationProperties) {\n\t\t\t\tinto \"modules/appendix/partials/deprecated-configuration-properties\"\n\t\t\t}\n\t\t\tfrom(tasks.getByName(\"generateAntoraYml\")) {\n\t\t\t\tinto \"modules\"\n\t\t\t}\n\t\t}\n\t}\n}\n\ndokka {\n\tdokkaPublications.configureEach {\n\t\tincludes.from(\"src/docs/dokka/dokka-overview.md\")\n\t}\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/antora.yml",
    "content": "name: boot\nversion: true\next:\n  zip_contents_collector:\n    include:\n    - name: root\n      classifier: aggregate-content\n    - name: api\n      classifier: catalog-content\n      module: api\n      destination: content-catalog\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/community.adoc",
    "content": "[[community]]\n= Community\n\nIf you have trouble with Spring Boot, we would like to help.\n\n* Try the xref:how-to:index.adoc[How-to documents].\nThey provide solutions to the most common questions.\n* Learn the Spring basics.\nSpring Boot builds on many other Spring projects.\nCheck the https://spring.io[spring.io] web-site for a wealth of reference documentation.\nIf you are starting out with Spring, try one of the https://spring.io/guides[guides].\n* Ask a question.\nWe monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-boot[`spring-boot`].\n* Report bugs with Spring Boot at https://github.com/spring-projects/spring-boot/issues.\n\nNOTE: All of Spring Boot is open source, including the documentation.\nIf you find problems with the docs or if you want to improve them, please {url-github}[get involved].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/documentation.adoc",
    "content": ":navtitle: Documentation\n[[documentation]]\n= Documentation Overview\n\nThis section provides a brief overview of Spring Boot reference documentation.\nIt serves as a map for the rest of the document.\n\n\n\n[[documentation.first-steps]]\n== First Steps\n\nIf you are getting started with Spring Boot or 'Spring' in general, start with the following topics:\n\n* *From scratch:* xref:index.adoc[Overview] | xref:system-requirements.adoc[Requirements] | xref:installing.adoc[Installation]\n* *Tutorial:* xref:tutorial:first-application/index.adoc[Part 1] | xref:tutorial:first-application/index.adoc#getting-started.first-application.code[Part 2]\n* *Running your example:* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[Part 1] | xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[Part 2]\n\n\n\n[[documentation.upgrading]]\n== Upgrading From an Earlier Version\n\nYou should always ensure that you are running a {url-github-wiki}/Supported-Versions[supported version] of Spring Boot.\n\nDepending on the version that you are upgrading to, you can find some additional tips here:\n\n* *From 1.x to 2.x:* xref:upgrading.adoc#upgrading.from-1x[Upgrading from 1.x]\n* *From 2.x:* xref:upgrading.adoc#upgrading.from-2x[Upgrading from 2.x]\n* *From 3.x:* xref:upgrading.adoc#upgrading.from-3x[Upgrading from 3.x]\n* *To a new feature release:* xref:upgrading.adoc#upgrading.to-feature[Upgrading to New Feature Release]\n* *Spring Boot CLI:* xref:upgrading.adoc#upgrading.cli[Upgrading the Spring Boot CLI]\n\n\n\n[[documentation.using]]\n== Developing With Spring Boot\n\nReady to actually start using Spring Boot? xref:reference:using/index.adoc[We have you covered]:\n\n* *Build systems:* xref:reference:using/build-systems.adoc#using.build-systems.maven[Maven] | xref:reference:using/build-systems.adoc#using.build-systems.gradle[Gradle] | xref:reference:using/build-systems.adoc#using.build-systems.ant[Ant] | xref:reference:using/build-systems.adoc#using.build-systems.starters[Starters]\n* *Best practices:* xref:reference:using/structuring-your-code.adoc[Code Structure] | xref:reference:using/configuration-classes.adoc[@Configuration] | xref:reference:using/auto-configuration.adoc[@EnableAutoConfiguration] | xref:reference:using/spring-beans-and-dependency-injection.adoc[Beans and Dependency Injection]\n* *Running your code:* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[IDE] | xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[Packaged] | xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[Maven] | xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[Gradle]\n* *Packaging your app:* xref:reference:using/packaging-for-production.adoc[Production jars]\n* *Spring Boot CLI:* xref:cli:index.adoc[Using the CLI]\n\n\n\n[[documentation.features]]\n== Learning About Spring Boot Features\n\nNeed more details about Spring Boot's core features?\nxref:reference:features/index.adoc[The following content is for you]:\n\n* *Spring Application:* xref:reference:features/spring-application.adoc[SpringApplication]\n* *External Configuration:* xref:reference:features/external-config.adoc[External Configuration]\n* *Profiles:* xref:reference:features/profiles.adoc[Profiles]\n* *Logging:* xref:reference:features/logging.adoc[Logging]\n\n\n\n[[documentation.web]]\n== Web\n\nIf you develop Spring Boot web applications, take a look at the following content:\n\n* *Servlet Web Applications:* xref:reference:web/servlet.adoc[Spring MVC, Jersey, Embedded Servlet Containers]\n* *Reactive Web Applications:* xref:reference:web/reactive.adoc[Spring Webflux, Embedded Servlet Containers]\n* *Graceful Shutdown:* xref:reference:web/graceful-shutdown.adoc[Graceful Shutdown]\n* *Spring Security:* xref:reference:web/spring-security.adoc[Default Security Configuration, Auto-configuration for OAuth2, SAML]\n* *Spring Session:* xref:reference:web/spring-session.adoc[Auto-configuration for Spring Session]\n* *Spring HATEOAS:* xref:reference:web/spring-hateoas.adoc[Auto-configuration for Spring HATEOAS]\n\n\n\n[[documentation.data]]\n== Data\n\nIf your application deals with a datastore, you can see how to configure that here:\n\n* *SQL:* xref:reference:data/sql.adoc[Configuring a SQL Datastore, Embedded Database support, Connection pools, and more.]\n* *NOSQL:* xref:reference:data/nosql.adoc[Auto-configuration for NOSQL stores such as Redis, MongoDB, Neo4j, and others.]\n\n\n\n[[documentation.messaging]]\n== Messaging\n\nIf your application uses any messaging protocol, see one or more of the following sections:\n\n* *JMS:* xref:reference:messaging/jms.adoc[Auto-configuration for ActiveMQ and Artemis, Sending and Receiving messages through JMS]\n* *AMQP:* xref:reference:messaging/amqp.adoc[Auto-configuration for RabbitMQ]\n* *Kafka:* xref:reference:messaging/kafka.adoc[Auto-configuration for Spring Kafka]\n* *Pulsar:* xref:reference:messaging/pulsar.adoc[Auto-configuration for Spring for Apache Pulsar]\n* *RSocket:* xref:reference:messaging/rsocket.adoc[Auto-configuration for Spring Framework's RSocket Support]\n* *Spring Integration:* xref:reference:messaging/spring-integration.adoc[Auto-configuration for Spring Integration]\n\n\n\n[[documentation.io]]\n== IO\n\nIf your application needs IO capabilities, see one or more of the following sections:\n\n* *Caching:* xref:reference:io/caching.adoc[Caching support with EhCache, Hazelcast, Infinispan, and more]\n* *Quartz:* xref:reference:io/quartz.adoc[Quartz Scheduling]\n* *Mail:* xref:reference:io/email.adoc[Sending Email]\n* *Validation:* xref:reference:io/validation.adoc[JSR-303 Validation]\n* *REST Clients:* xref:reference:io/rest-client.adoc[Calling REST Services with RestTemplate and WebClient]\n* *Webservices:* xref:reference:io/webservices.adoc[Auto-configuration for Spring Web Services]\n* *JTA:* xref:reference:io/jta.adoc[Distributed Transactions with JTA]\n\n\n\n[[documentation.container-images]]\n== Container Images\n\nSpring Boot provides first-class support for building efficient container images. You can read more about it here:\n\n* *Efficient Container Images:* xref:reference:packaging/container-images/efficient-images.adoc[Tips to optimize container images such as Docker images]\n* *Dockerfiles:* xref:reference:packaging/container-images/dockerfiles.adoc[Building container images using dockerfiles]\n* *Cloud Native Buildpacks:* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc[Support for Cloud Native Buildpacks with Maven and Gradle]\n\n\n\n[[documentation.actuator]]\n== Moving to Production\n\nWhen you are ready to push your Spring Boot application to production, we have xref:how-to:actuator.adoc[some tricks] that you might like:\n\n* *Management endpoints:* xref:reference:actuator/endpoints.adoc[Overview]\n* *Connection options:* xref:reference:actuator/monitoring.adoc[HTTP] | xref:reference:actuator/jmx.adoc[JMX]\n* *Monitoring:* xref:reference:actuator/metrics.adoc[Metrics] | xref:reference:actuator/auditing.adoc[Auditing] | xref:reference:actuator/http-exchanges.adoc[HTTP Exchanges] | xref:reference:actuator/process-monitoring.adoc[Process]\n\n\n\n[[documentation.packaging]]\n== Optimizing for Production\n\nSpring Boot applications can be optimized for production using technologies described in these sections:\n\n* *Efficient Deployments:* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[Unpacking the Executable JAR]\n* *GraalVM Native Images:* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc[Introduction] | xref:reference:packaging/native-image/advanced-topics.adoc[Advanced Topics] | xref:how-to:native-image/developing-your-first-application.adoc[Getting Started] | xref:how-to:native-image/testing-native-applications.adoc[Testing]\n* *AOT cache:* xref:reference:packaging/aot-cache.adoc[Overview]\n* *Checkpoint and Restore* xref:reference:packaging/checkpoint-restore.adoc[Overview]\n\n\n[[documentation.advanced]]\n== Advanced Topics\n\nFinally, we have a few topics for more advanced users:\n\n* *Spring Boot Applications Deployment:* xref:how-to:deployment/cloud.adoc[Cloud Deployment] | xref:how-to:deployment/installing.adoc[OS Service]\n* *Build tool plugins:* xref:maven-plugin:index.adoc[Maven] | xref:gradle-plugin:index.adoc[Gradle]\n* *Appendix:* xref:appendix:application-properties/index.adoc[Application Properties] | xref:specification:configuration-metadata/index.adoc[Configuration Metadata] | xref:appendix:auto-configuration-classes/index.adoc[Auto-configuration Classes] | xref:appendix:test-auto-configuration/index.adoc[Test Auto-configuration Annotations] | xref:specification:executable-jar/index.adoc[Executable Jars] | xref:appendix:dependency-versions/index.adoc[Dependency Versions]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/index.adoc",
    "content": ":navtitle: Overview\n= Spring Boot\n\nSpring Boot helps you to create stand-alone, production-grade Spring-based applications that you can run.\nWe take an opinionated view of the Spring platform and third-party libraries, so that you can get started with minimum fuss.\nMost Spring Boot applications need very little Spring configuration.\n\nYou can use Spring Boot to create Java applications that can be started by using `java -jar` or more traditional war deployments.\n\nOur primary goals are:\n\n* Provide a radically faster and widely accessible getting-started experience for all Spring development.\n* Be opinionated out of the box but get out of the way quickly as requirements start to diverge from the defaults.\n* Provide a range of non-functional features that are common to large classes of projects (such as embedded servers, security, metrics, health checks, and externalized configuration).\n* Absolutely no code generation (when not targeting native image) and no requirement for XML configuration.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/installing.adoc",
    "content": "[[getting-started.installing]]\n= Installing Spring Boot\n\nSpring Boot can be used with \"`classic`\" Java development tools or installed as a command line tool.\nEither way, you need https://www.java.com[Java SDK v17] or higher.\nBefore you begin, you should check your current Java installation by using the following command:\n\n[source,shell]\n----\n$ java -version\n----\n\nIf you are new to Java development or if you want to experiment with Spring Boot, you might want to try the xref:installing.adoc#getting-started.installing.cli[Spring Boot CLI] (Command Line Interface) first.\nOtherwise, read on for \"`classic`\" installation instructions.\n\n\n\n[[getting-started.installing.java]]\n== Installation Instructions for the Java Developer\n\nYou can use Spring Boot in the same way as any standard Java library.\nTo do so, include the appropriate `+spring-boot-*.jar+` files on your classpath.\nSpring Boot does not require any special tools integration, so you can use any IDE or text editor.\nAlso, there is nothing special about a Spring Boot application, so you can run and debug a Spring Boot application as you would any other Java program.\n\nAlthough you _could_ copy Spring Boot jars, we generally recommend that you use a build tool that supports dependency management (such as Maven or Gradle).\n\n\n\n[[getting-started.installing.java.maven]]\n=== Maven Installation\n\nSpring Boot is compatible with Apache Maven 3.6.3 or later.\nIf you do not already have Maven installed, you can follow the instructions at https://maven.apache.org.\n\nTIP: On many operating systems, Maven can be installed with a package manager.\nIf you use OSX Homebrew, try `brew install maven`.\nUbuntu users can run `sudo apt-get install maven`.\nWindows users with https://chocolatey.org/[Chocolatey] can run `choco install maven` from an elevated (administrator) prompt.\n\nSpring Boot dependencies use the `org.springframework.boot` group id.\nTypically, your Maven POM file inherits from the `spring-boot-starter-parent` project and declares dependencies to one or more xref:reference:using/build-systems.adoc#using.build-systems.starters[starters].\nSpring Boot also provides an optional xref:maven-plugin:index.adoc[Maven plugin] to create executable jars.\n\nMore details on getting started with Spring Boot and Maven can be found in the xref:maven-plugin:getting-started.adoc[] section of the Maven plugin's reference guide.\n\n\n\n[[getting-started.installing.java.gradle]]\n=== Gradle Installation\n\nSpring Boot is compatible with Gradle 8.x (8.14 or later) or 9.x.\nIf you do not already have Gradle installed, you can follow the instructions at https://gradle.org.\n\nSpring Boot dependencies can be declared by using the `org.springframework.boot` `group`.\nTypically, your project declares dependencies to one or more xref:reference:using/build-systems.adoc#using.build-systems.starters[starters].\nSpring Boot provides a useful xref:gradle-plugin:index.adoc[Gradle plugin] that can be used to simplify dependency declarations and to create executable jars.\n\n.Gradle Wrapper\n****\nThe Gradle Wrapper provides a nice way of \"`obtaining`\" Gradle when you need to build a project.\nIt is a small script and library that you commit alongside your code to bootstrap the build process.\nSee {url-gradle-docs}/gradle_wrapper.html for details.\n****\n\nMore details on getting started with Spring Boot and Gradle can be found in the xref:gradle-plugin:getting-started.adoc[] section of the Gradle plugin's reference guide.\n\n\n\n[[getting-started.installing.cli]]\n== Installing the Spring Boot CLI\n\nThe Spring Boot CLI (Command Line Interface) is a command line tool that you can use to quickly prototype with Spring.\n\nYou do not need to use the CLI to work with Spring Boot, but it is a quick way to get a Spring application off the ground without an IDE.\n\n\n\n[[getting-started.installing.cli.manual-installation]]\n=== Manual Installation\n\nifeval::[\"{artifact-release-type}\" == \"snapshot\"]\nYou can download one of the `spring-boot-cli-\\*-bin.zip` or `spring-boot-cli-*-bin.tar.gz` files from the {url-artifact-repository}/org/springframework/boot/spring-boot-cli/{version-spring-boot}/[Spring software repository].\nendif::[]\nifeval::[\"{artifact-release-type}\" != \"snapshot\"]\nYou can download the Spring CLI distribution from one of the following locations:\n\n* {url-artifact-repository}/org/springframework/boot/spring-boot-cli/{version-spring-boot}/spring-boot-cli-{version-spring-boot}-bin.zip[spring-boot-cli-{version-spring-boot}-bin.zip]\n* {url-artifact-repository}/org/springframework/boot/spring-boot-cli/{version-spring-boot}/spring-boot-cli-{version-spring-boot}-bin.tar.gz[spring-boot-cli-{version-spring-boot}-bin.tar.gz]\nendif::[]\n\n\nOnce downloaded, follow the {url-github-raw}/cli/spring-boot-cli/src/main/content/INSTALL.txt[INSTALL.txt] instructions from the unpacked archive.\nIn summary, there is a `spring` script (`spring.bat` for Windows) in a `bin/` directory in the `.zip` file.\nAlternatively, you can use `java -jar` with the `.jar` file (the script helps you to be sure that the classpath is set correctly).\n\n\n\n[[getting-started.installing.cli.sdkman]]\n=== Installation with SDKMAN!\n\nSDKMAN! (The Software Development Kit Manager) can be used for managing multiple versions of various binary SDKs, including Groovy and the Spring Boot CLI.\nGet SDKMAN! from https://sdkman.io and install Spring Boot by using the following commands:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ sdk install springboot\n$ spring --version\nSpring CLI v{version-spring-boot}\n----\n\nIf you develop features for the CLI and want access to the version you built, use the following commands:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ sdk install springboot dev /path/to/spring-boot/spring-boot-cli/target/spring-boot-cli-{version-spring-boot}-bin/spring-{version-spring-boot}/\n$ sdk default springboot dev\n$ spring --version\nSpring CLI v{version-spring-boot}\n----\n\nThe preceding instructions install a local instance of `spring` called the `dev` instance.\nIt points at your target build location, so every time you rebuild Spring Boot, `spring` is up-to-date.\n\nYou can see it by running the following command:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ sdk ls springboot\n\n================================================================================\nAvailable Springboot Versions\n================================================================================\n> + dev\n* {version-spring-boot}\n\n================================================================================\n+ - local version\n* - installed\n> - currently in use\n================================================================================\n----\n\n\n\n[[getting-started.installing.cli.homebrew]]\n=== OSX Homebrew Installation\n\nIf you are on a Mac and use https://brew.sh/[Homebrew], you can install the Spring Boot CLI by using the following commands:\n\n[source,shell]\n----\n$ brew tap spring-io/tap\n$ brew install spring-boot\n----\n\nHomebrew installs `spring` to `/usr/local/bin`.\n\nNOTE: If you do not see the formula, your installation of brew might be out-of-date.\nIn that case, run `brew update` and try again.\n\n\n\n[[getting-started.installing.cli.macports]]\n=== MacPorts Installation\n\nIf you are on a Mac and use https://www.macports.org/[MacPorts], you can install the Spring Boot CLI by using the following command:\n\n[source,shell]\n----\n$ sudo port install spring-boot-cli\n----\n\n\n\n[[getting-started.installing.cli.completion]]\n=== Command-line Completion\n\nThe Spring Boot CLI includes scripts that provide command completion for the https://en.wikipedia.org/wiki/Bash_%28Unix_shell%29[BASH] and https://en.wikipedia.org/wiki/Z_shell[zsh] shells.\nYou can `source` the script named `spring` (`_spring` for zsh) or put it in your personal or system-wide bash completion initialization.\nOn a Debian system, the system-wide scripts are in `<installation location>/shell-completion/<bash|zsh>` and all scripts in that directory are executed when a new shell starts.\nFor example, to run the script manually if you have installed by using SDKMAN!, use the following commands:\n\n[source,shell]\n----\n$ . ~/.sdkman/candidates/springboot/current/shell-completion/bash/spring\n$ spring <HIT TAB HERE>\n  encodepassword  help  init  shell  version\n----\n\nNOTE: If you install the Spring Boot CLI by using Homebrew or MacPorts, the command-line completion scripts are automatically registered with your shell.\n\n\n\n[[getting-started.installing.cli.scoop]]\n=== Windows Scoop Installation\n\nIf you are on a Windows and use https://scoop.sh/[Scoop], you can install the Spring Boot CLI by using the following commands:\n\n[source,shell]\n----\n$ scoop bucket add extras\n$ scoop install springboot\n----\n\nScoop installs `spring` to `~/scoop/apps/springboot/current/bin`.\n\nNOTE: If you do not see the app manifest, your installation of scoop might be out-of-date.\nIn that case, run `scoop update` and try again.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/redirect.adoc",
    "content": ":page-layout: redirect\n\n* xref:ROOT:community.adoc#community[#boot-documentation-getting-help]\n* xref:ROOT:community.adoc#community[#community]\n* xref:ROOT:documentation.adoc#documentation.actuator[#boot-documentation-production]\n* xref:ROOT:documentation.adoc#documentation.actuator[#documentation.actuator]\n* xref:ROOT:documentation.adoc#documentation.advanced[#boot-documentation-advanced]\n* xref:ROOT:documentation.adoc#documentation.advanced[#documentation.advanced]\n* xref:ROOT:documentation.adoc#documentation.container-images[#documentation.container-images]\n* xref:ROOT:documentation.adoc#documentation.data[#documentation.data]\n* xref:ROOT:documentation.adoc#documentation.features[#boot-documentation-learning]\n* xref:ROOT:documentation.adoc#documentation.features[#documentation.features]\n* xref:ROOT:documentation.adoc#documentation.first-steps[#boot-documentation-first-steps]\n* xref:ROOT:documentation.adoc#documentation.first-steps[#documentation.first-steps]\n* xref:ROOT:documentation.adoc#documentation.io[#documentation.io]\n* xref:ROOT:documentation.adoc#documentation.messaging[#documentation.messaging]\n* xref:ROOT:documentation.adoc#documentation.packaging[#documentation.packaging]\n* xref:ROOT:documentation.adoc#documentation.upgrading[#boot-documentation-upgrading]\n* xref:ROOT:documentation.adoc#documentation.upgrading[#documentation.upgrading]\n* xref:ROOT:documentation.adoc#documentation.using[#boot-documentation-workingwith]\n* xref:ROOT:documentation.adoc#documentation.using[#documentation.using]\n* xref:ROOT:documentation.adoc#documentation.web[#documentation.web]\n* xref:ROOT:documentation.adoc#documentation[#boot-documentation]\n* xref:ROOT:documentation.adoc#documentation[#documentation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.completion[#getting-started-cli-command-line-completion]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.completion[#getting-started.installing.cli.completion]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.homebrew[#getting-started-homebrew-cli-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.homebrew[#getting-started.installing.cli.homebrew]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.macports[#getting-started-macports-cli-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.macports[#getting-started.installing.cli.macports]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.manual-installation[#getting-started-manual-cli-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.manual-installation[#getting-started.installing.cli.manual-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.scoop[#getting-started-scoop-cli-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.scoop[#getting-started.installing.cli.scoop]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.sdkman[#getting-started-sdkman-cli-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.cli.sdkman[#getting-started.installing.cli.sdkman]\n* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started-installing-the-cli]\n* xref:ROOT:installing.adoc#getting-started.installing.cli[#getting-started.installing.cli]\n* xref:ROOT:installing.adoc#getting-started.installing.java.gradle[#getting-started-gradle-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.java.gradle[#getting-started.installing.java.gradle]\n* xref:ROOT:installing.adoc#getting-started.installing.java.maven[#getting-started-maven-installation]\n* xref:ROOT:installing.adoc#getting-started.installing.java.maven[#getting-started.installing.java.maven]\n* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started-installation-instructions-for-java]\n* xref:ROOT:installing.adoc#getting-started.installing.java[#getting-started.installing.java]\n* xref:ROOT:installing.adoc#getting-started.installing[#getting-started-installing-spring-boot]\n* xref:ROOT:installing.adoc#getting-started.installing[#getting-started.installing]\n* xref:ROOT:system-requirements.adoc#getting-started.system-requirements.graal[#getting-started.system-requirements.graal]\n* xref:ROOT:system-requirements.adoc#getting-started.system-requirements.servlet-containers[#getting-started-system-requirements-servlet-containers]\n* xref:ROOT:system-requirements.adoc#getting-started.system-requirements.servlet-containers[#getting-started.system-requirements.servlet-containers]\n* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started-system-requirements]\n* xref:ROOT:system-requirements.adoc#getting-started.system-requirements[#getting-started.system-requirements]\n* xref:ROOT:upgrading.adoc#upgrading.cli[#upgrading.cli]\n* xref:ROOT:upgrading.adoc#upgrading.from-1x[#upgrading.from-1x]\n* xref:ROOT:upgrading.adoc#upgrading.to-feature[#upgrading.to-feature]\n* xref:ROOT:upgrading.adoc#upgrading[#getting-started-upgrading-from-an-earlier-version]\n* xref:ROOT:upgrading.adoc#upgrading[#getting-started.installing.upgrading]\n* xref:ROOT:upgrading.adoc#upgrading[#upgrading]\n* xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving.query-parameters[actuator-api#audit-events.retrieving.query-parameters]\n* xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving.response-structure[actuator-api#audit-events.retrieving.response-structure]\n* xref:api:rest/actuator/auditevents.adoc#audit-events.retrieving[actuator-api#audit-events.retrieving]\n* xref:api:rest/actuator/auditevents.adoc#audit-events[actuator-api#audit-events]\n* xref:api:rest/actuator/beans.adoc#beans.retrieving.response-structure[actuator-api#beans.retrieving.response-structure]\n* xref:api:rest/actuator/beans.adoc#beans.retrieving[actuator-api#beans.retrieving]\n* xref:api:rest/actuator/beans.adoc#beans[actuator-api#beans]\n* xref:api:rest/actuator/caches.adoc#caches.all.response-structure[actuator-api#caches.all.response-structure]\n* xref:api:rest/actuator/caches.adoc#caches.all[actuator-api#caches.all]\n* xref:api:rest/actuator/caches.adoc#caches.evict-all[actuator-api#caches.evict-all]\n* xref:api:rest/actuator/caches.adoc#caches.evict-named.request-structure[actuator-api#caches.evict-named.request-structure]\n* xref:api:rest/actuator/caches.adoc#caches.evict-named[actuator-api#caches.evict-named]\n* xref:api:rest/actuator/caches.adoc#caches.named.query-parameters[actuator-api#caches.named.query-parameters]\n* xref:api:rest/actuator/caches.adoc#caches.named.response-structure[actuator-api#caches.named.response-structure]\n* xref:api:rest/actuator/caches.adoc#caches.named[actuator-api#caches.named]\n* xref:api:rest/actuator/caches.adoc#caches[actuator-api#caches]\n* xref:api:rest/actuator/conditions.adoc#conditions.retrieving.response-structure[actuator-api#conditions.retrieving.response-structure]\n* xref:api:rest/actuator/conditions.adoc#conditions.retrieving[actuator-api#conditions.retrieving]\n* xref:api:rest/actuator/conditions.adoc#conditions[actuator-api#conditions]\n* xref:api:rest/actuator/configprops.adoc#configprops.retrieving-by-prefix.response-structure[actuator-api#configprops.retrieving-by-prefix.response-structure]\n* xref:api:rest/actuator/configprops.adoc#configprops.retrieving-by-prefix[actuator-api#configprops.retrieving-by-prefix]\n* xref:api:rest/actuator/configprops.adoc#configprops.retrieving.response-structure[actuator-api#configprops.retrieving.response-structure]\n* xref:api:rest/actuator/configprops.adoc#configprops.retrieving[actuator-api#configprops.retrieving]\n* xref:api:rest/actuator/configprops.adoc#configprops[actuator-api#configprops]\n* xref:api:rest/actuator/env.adoc#env.entire.response-structure[actuator-api#env.entire.response-structure]\n* xref:api:rest/actuator/env.adoc#env.entire[actuator-api#env.entire]\n* xref:api:rest/actuator/env.adoc#env.single-property.response-structure[actuator-api#env.single-property.response-structure]\n* xref:api:rest/actuator/env.adoc#env.single-property[actuator-api#env.single-property]\n* xref:api:rest/actuator/env.adoc#env[actuator-api#env]\n* xref:api:rest/actuator/flyway.adoc#flyway.retrieving.response-structure[actuator-api#flyway.retrieving.response-structure]\n* xref:api:rest/actuator/flyway.adoc#flyway.retrieving[actuator-api#flyway.retrieving]\n* xref:api:rest/actuator/flyway.adoc#flyway[actuator-api#flyway]\n* xref:api:rest/actuator/health.adoc#health.retrieving-component-nested.response-structure[actuator-api#health.retrieving-component-nested.response-structure]\n* xref:api:rest/actuator/health.adoc#health.retrieving-component-nested[actuator-api#health.retrieving-component-nested]\n* xref:api:rest/actuator/health.adoc#health.retrieving-component.response-structure[actuator-api#health.retrieving-component.response-structure]\n* xref:api:rest/actuator/health.adoc#health.retrieving-component[actuator-api#health.retrieving-component]\n* xref:api:rest/actuator/health.adoc#health.retrieving.response-structure[actuator-api#health.retrieving.response-structure]\n* xref:api:rest/actuator/health.adoc#health.retrieving[actuator-api#health.retrieving]\n* xref:api:rest/actuator/health.adoc#health[actuator-api#health]\n* xref:api:rest/actuator/heapdump.adoc#heapdump.retrieving[actuator-api#heapdump.retrieving]\n* xref:api:rest/actuator/heapdump.adoc#heapdump[actuator-api#heapdump]\n* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving.response-structure[actuator-api#http-trace-retrieving-response-structure]\n* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving.response-structure[actuator-api#httpexchanges.retrieving.response-structure]\n* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving[actuator-api#http-trace-retrieving]\n* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges.retrieving[actuator-api#httpexchanges.retrieving]\n* xref:api:rest/actuator/httpexchanges.adoc#httpexchanges[actuator-api#httpexchanges]\n* xref:api:rest/actuator/index.adoc#overview.endpoint-urls[actuator-api#overview.endpoint-urls]\n* xref:api:rest/actuator/index.adoc#overview.timestamps[actuator-api#overview.timestamps]\n* xref:api:rest/actuator/index.adoc#overview[actuator-api#overview]\n* xref:api:rest/actuator/info.adoc#info.retrieving.response-structure.build[actuator-api#info.retrieving.response-structure.build]\n* xref:api:rest/actuator/info.adoc#info.retrieving.response-structure.git[actuator-api#info.retrieving.response-structure.git]\n* xref:api:rest/actuator/info.adoc#info.retrieving.response-structure[actuator-api#info.retrieving.response-structure]\n* xref:api:rest/actuator/info.adoc#info.retrieving[actuator-api#info.retrieving]\n* xref:api:rest/actuator/info.adoc#info[actuator-api#info]\n* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.rebuilding[actuator-api#integrationgraph.rebuilding]\n* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.retrieving.response-structure[actuator-api#integrationgraph.retrieving.response-structure]\n* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph.retrieving[actuator-api#integrationgraph.retrieving]\n* xref:api:rest/actuator/integrationgraph.adoc#integrationgraph[actuator-api#integrationgraph]\n* xref:api:rest/actuator/liquibase.adoc#liquibase.retrieving.response-structure[actuator-api#liquibase.retrieving.response-structure]\n* xref:api:rest/actuator/liquibase.adoc#liquibase.retrieving[actuator-api#liquibase.retrieving]\n* xref:api:rest/actuator/liquibase.adoc#liquibase[actuator-api#liquibase]\n* xref:api:rest/actuator/logfile.adoc#logfile.retrieving-part[actuator-api#logfile.retrieving-part]\n* xref:api:rest/actuator/logfile.adoc#logfile.retrieving[actuator-api#logfile.retrieving]\n* xref:api:rest/actuator/logfile.adoc#logfile[actuator-api#logfile]\n* xref:api:rest/actuator/loggers.adoc#loggers.all.response-structure[actuator-api#loggers.all.response-structure]\n* xref:api:rest/actuator/loggers.adoc#loggers.all[actuator-api#loggers.all]\n* xref:api:rest/actuator/loggers.adoc#loggers.clearing-level[actuator-api#loggers.clearing-level]\n* xref:api:rest/actuator/loggers.adoc#loggers.group-setting-level.request-structure[actuator-api#loggers.group-setting-level.request-structure]\n* xref:api:rest/actuator/loggers.adoc#loggers.group-setting-level[actuator-api#loggers.group-setting-level]\n* xref:api:rest/actuator/loggers.adoc#loggers.group.response-structure[actuator-api#loggers.group.response-structure]\n* xref:api:rest/actuator/loggers.adoc#loggers.group[actuator-api#loggers.group]\n* xref:api:rest/actuator/loggers.adoc#loggers.setting-level.request-structure[actuator-api#loggers.setting-level.request-structure]\n* xref:api:rest/actuator/loggers.adoc#loggers.setting-level[actuator-api#loggers.setting-level]\n* xref:api:rest/actuator/loggers.adoc#loggers.single.response-structure[actuator-api#loggers.single.response-structure]\n* xref:api:rest/actuator/loggers.adoc#loggers.single[actuator-api#loggers.single]\n* xref:api:rest/actuator/loggers.adoc#loggers[actuator-api#loggers]\n* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-dispatcher-handlers[actuator-api#mappings.retrieving.response-structure-dispatcher-handlers]\n* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-dispatcher-servlets[actuator-api#mappings.retrieving.response-structure-dispatcher-servlets]\n* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-servlet-filters[actuator-api#mappings.retrieving.response-structure-servlet-filters]\n* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure-servlets[actuator-api#mappings.retrieving.response-structure-servlets]\n* xref:api:rest/actuator/mappings.adoc#mappings.retrieving.response-structure[actuator-api#mappings.retrieving.response-structure]\n* xref:api:rest/actuator/mappings.adoc#mappings.retrieving[actuator-api#mappings.retrieving]\n* xref:api:rest/actuator/mappings.adoc#mappings[actuator-api#mappings]\n* xref:api:rest/actuator/metrics.adoc#metrics.drilling-down[actuator-api#metrics.drilling-down]\n* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric.query-parameters[actuator-api#metrics.retrieving-metric.query-parameters]\n* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric.response-structure[actuator-api#metrics.retrieving-metric.response-structure]\n* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-metric[actuator-api#metrics.retrieving-metric]\n* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-names.response-structure[actuator-api#metrics.retrieving-names.response-structure]\n* xref:api:rest/actuator/metrics.adoc#metrics.retrieving-names[actuator-api#metrics.retrieving-names]\n* xref:api:rest/actuator/metrics.adoc#metrics[actuator-api#metrics]\n* xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving-names[actuator-api#prometheus.retrieving-names]\n* xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving.query-parameters[actuator-api#prometheus.retrieving.query-parameters]\n* xref:api:rest/actuator/prometheus.adoc#prometheus.retrieving[actuator-api#prometheus.retrieving]\n* xref:api:rest/actuator/prometheus.adoc#prometheus[actuator-api#prometheus]\n* xref:api:rest/actuator/quartz.adoc#quartz.job-group.response-structure[actuator-api#quartz.job-group.response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.job-group[actuator-api#quartz.job-group]\n* xref:api:rest/actuator/quartz.adoc#quartz.job-groups.response-structure[actuator-api#quartz.job-groups.response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.job-groups[actuator-api#quartz.job-groups]\n* xref:api:rest/actuator/quartz.adoc#quartz.job.response-structure[actuator-api#quartz.job.response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.job[actuator-api#quartz.job]\n* xref:api:rest/actuator/quartz.adoc#quartz.report.response-structure[actuator-api#quartz.report.response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.report[actuator-api#quartz.report]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger-group.response-structure[actuator-api#quartz.trigger-group.response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger-group[actuator-api#quartz.trigger-group]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger-groups.response-structure[actuator-api#quartz.trigger-groups.response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger-groups[actuator-api#quartz.trigger-groups]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger.calendar-interval-response-structure[actuator-api#quartz.trigger.calendar-interval-response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger.common-response-structure[actuator-api#quartz.trigger.common-response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger.cron-response-structure[actuator-api#quartz.trigger.cron-response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger.custom-response-structure[actuator-api#quartz.trigger.custom-response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger.daily-time-interval-response-structure[actuator-api#quartz.trigger.daily-time-interval-response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger.simple-response-structure[actuator-api#quartz.trigger.simple-response-structure]\n* xref:api:rest/actuator/quartz.adoc#quartz.trigger[actuator-api#quartz.trigger]\n* xref:api:rest/actuator/quartz.adoc#quartz[actuator-api#quartz]\n* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-available-sboms.response-structure[actuator-api#sbom.retrieving-available-sboms.response-structure]\n* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-available-sboms[actuator-api#sbom.retrieving-available-sboms]\n* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-single-sbom.response-structure[actuator-api#sbom.retrieving-single-sbom.response-structure]\n* xref:api:rest/actuator/sbom.adoc#sbom.retrieving-single-sbom[actuator-api#sbom.retrieving-single-sbom]\n* xref:api:rest/actuator/sbom.adoc#sbom[actuator-api#sbom]\n* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks.retrieving.response-structure[actuator-api#scheduled-tasks.retrieving.response-structure]\n* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks.retrieving[actuator-api#scheduled-tasks.retrieving]\n* xref:api:rest/actuator/scheduledtasks.adoc#scheduled-tasks[actuator-api#scheduled-tasks]\n* xref:api:rest/actuator/sessions.adoc#sessions.deleting[actuator-api#sessions.deleting]\n* xref:api:rest/actuator/sessions.adoc#sessions.retrieving-id.response-structure[actuator-api#sessions.retrieving-id.response-structure]\n* xref:api:rest/actuator/sessions.adoc#sessions.retrieving-id[actuator-api#sessions.retrieving-id]\n* xref:api:rest/actuator/sessions.adoc#sessions.retrieving.query-parameters[actuator-api#sessions.retrieving.query-parameters]\n* xref:api:rest/actuator/sessions.adoc#sessions.retrieving.response-structure[actuator-api#sessions.retrieving.response-structure]\n* xref:api:rest/actuator/sessions.adoc#sessions.retrieving[actuator-api#sessions.retrieving]\n* xref:api:rest/actuator/sessions.adoc#sessions[actuator-api#sessions]\n* xref:api:rest/actuator/shutdown.adoc#shutdown.shutting-down.response-structure[actuator-api#shutdown.shutting-down.response-structure]\n* xref:api:rest/actuator/shutdown.adoc#shutdown.shutting-down[actuator-api#shutdown.shutting-down]\n* xref:api:rest/actuator/shutdown.adoc#shutdown[actuator-api#shutdown]\n* xref:api:rest/actuator/startup.adoc#startup.retrieving.drain[actuator-api#startup.retrieving.drain]\n* xref:api:rest/actuator/startup.adoc#startup.retrieving.response-structure[actuator-api#startup.retrieving.response-structure]\n* xref:api:rest/actuator/startup.adoc#startup.retrieving.snapshot[actuator-api#startup.retrieving.snapshot]\n* xref:api:rest/actuator/startup.adoc#startup.retrieving[actuator-api#startup.retrieving]\n* xref:api:rest/actuator/startup.adoc#startup[actuator-api#startup]\n* xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-json.response-structure[actuator-api#threaddump.retrieving-json.response-structure]\n* xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-json[actuator-api#threaddump.retrieving-json]\n* xref:api:rest/actuator/threaddump.adoc#threaddump.retrieving-text[actuator-api#threaddump.retrieving-text]\n* xref:api:rest/actuator/threaddump.adoc#threaddump[actuator-api#threaddump]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.actuator[#appendix.application-properties.actuator]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.actuator[#common-application-properties-actuator]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.cache[#appendix.application-properties.cache]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.cache[#common-application-properties-cache]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.core[#appendix.application-properties.core]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.core[#core-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.data-migration[#appendix.application-properties.data-migration]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.data-migration[#data-migration-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#appendix.application-properties.data]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.data[#data-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.devtools[#appendix.application-properties.devtools]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.devtools[#devtools-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.docker-compose[#appendix.application-properties.docker-compose]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[#appendix.application-properties.integration]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[#integration-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.json[#appendix.application-properties.json]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.json[#json-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.mail[#appendix.application-properties.mail]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.mail[#mail-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.rsocket[#appendix.application-properties.rsocket]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.rsocket[#rsocket-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.security[#appendix.application-properties.security]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.security[#security-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.server[#appendix.application-properties.server]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.server[#server-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.templating[#appendix.application-properties.templating]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.templating[#templating-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.testcontainers[#appendix.application-properties.testcontainers]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.testing[#appendix.application-properties.testing]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.testing[#testing-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.transaction[#appendix.application-properties.transaction]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.transaction[#transaction-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.web[#appendix.application-properties.web]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties.web[#web-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties[#appendix.application-properties]\n* xref:appendix:application-properties/index.adoc#appendix.application-properties[#common-application-properties]\n* xref:appendix:application-properties/index.adoc[#application-properties]\n* xref:appendix:application-properties/index.adoc[application-properties]\n* xref:appendix:auto-configuration-classes/index.adoc#appendix.auto-configuration-classes[#appendix.auto-configuration-classes]\n* xref:appendix:auto-configuration-classes/index.adoc#appendix.auto-configuration-classes[#auto-configuration-classes]\n* xref:appendix:auto-configuration-classes/index.adoc[#auto-configuration-classes]\n* xref:appendix:auto-configuration-classes/index.adoc[auto-configuration-classes]\n* xref:appendix:auto-configuration-classes/spring-boot-actuator-autoconfigure.adoc#appendix.auto-configuration-classes.spring-boot-actuator-autoconfigure[#appendix.auto-configuration-classes.actuator]\n* xref:appendix:auto-configuration-classes/spring-boot-actuator-autoconfigure.adoc#appendix.auto-configuration-classes.spring-boot-actuator-autoconfigure[#auto-configuration-classes.actuator]\n* xref:appendix:auto-configuration-classes/spring-boot-autoconfigure.adoc#appendix.auto-configuration-classes.spring-boot-autoconfigure[#appendix.auto-configuration-classes.core]\n* xref:appendix:auto-configuration-classes/spring-boot-autoconfigure.adoc#appendix.auto-configuration-classes.spring-boot-autoconfigure[#auto-configuration-classes.core]\n* xref:appendix:dependency-versions/coordinates.adoc#appendix.dependency-versions.coordinates[#appendix.dependency-versions.coordinates]\n* xref:appendix:dependency-versions/coordinates.adoc#appendix.dependency-versions.coordinates[#dependency-versions.coordinates]\n* xref:appendix:dependency-versions/index.adoc#appendix.dependency-versions[#appendix.dependency-versions]\n* xref:appendix:dependency-versions/index.adoc#appendix.dependency-versions[#dependency-versions]\n* xref:appendix:dependency-versions/index.adoc[#dependency-versions]\n* xref:appendix:dependency-versions/index.adoc[dependency-versions]\n* xref:appendix:dependency-versions/properties.adoc#appendix.dependency-versions.properties[#appendix.dependency-versions.properties]\n* xref:appendix:dependency-versions/properties.adoc#appendix.dependency-versions.properties[#dependency-versions.properties]\n* xref:appendix:test-auto-configuration/index.adoc#appendix.test-auto-configuration[#appendix.test-auto-configuration]\n* xref:appendix:test-auto-configuration/index.adoc#appendix.test-auto-configuration[#test-auto-configuration]\n* xref:appendix:test-auto-configuration/index.adoc[#test-auto-configuration]\n* xref:appendix:test-auto-configuration/index.adoc[test-auto-configuration]\n* xref:appendix:test-auto-configuration/slices.adoc#appendix.test-auto-configuration.slices[#appendix.test-auto-configuration.slices]\n* xref:appendix:test-auto-configuration/slices.adoc#appendix.test-auto-configuration.slices[#test-auto-configuration.slices]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass.examples[#build-tool-plugins.antlib.findmainclass.examples]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass.examples[#spring-boot-ant-findmainclass-examples]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#build-tool-plugins.antlib.findmainclass]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.findmainclass[#spring-boot-ant-findmainclass]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.examples[#build-tool-plugins.antlib.tasks.examples]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.examples[#spring-boot-ant-exejar-examples]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[#build-tool-plugins.antlib.tasks.exejar]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[#spring-boot-ant-exejar]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#build-tool-plugins.antlib.tasks]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib.tasks[#spring-boot-ant-tasks]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins-antlib]\n* xref:build-tool-plugin:antlib.adoc#build-tool-plugins.antlib[#build-tool-plugins.antlib]\n* xref:build-tool-plugin:index.adoc#build-tool-plugins[#build-tool-plugins]\n* xref:build-tool-plugin:index.adoc[#build-tool-plugins]\n* xref:build-tool-plugin:index.adoc[build-tool-plugins]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.example-repackage-implementation[#build-tool-plugins-repackage-implementation]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.example-repackage-implementation[#build-tool-plugins.other-build-systems.example-repackage-implementation]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.finding-main-class[#build-tool-plugins-find-a-main-class]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.finding-main-class[#build-tool-plugins.other-build-systems.finding-main-class]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.nested-libraries[#build-tool-plugins-nested-libraries]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.nested-libraries[#build-tool-plugins.other-build-systems.nested-libraries]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.repackaging-archives[#build-tool-plugins-repackaging-archives]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems.repackaging-archives[#build-tool-plugins.other-build-systems.repackaging-archives]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins-other-build-systems]\n* xref:build-tool-plugin:other-build-systems.adoc#build-tool-plugins.other-build-systems[#build-tool-plugins.other-build-systems]\n* xref:cli:index.adoc#cli[#cli]\n* xref:cli:index.adoc[#cli]\n* xref:cli:index.adoc[cli]\n* xref:cli:installation.adoc#cli.installation[#cli-installation]\n* xref:cli:installation.adoc#cli.installation[#cli.installation]\n* xref:cli:using-the-cli.adoc#cli.using-the-cli.embedded-shell[#cli-shell]\n* xref:cli:using-the-cli.adoc#cli.using-the-cli.embedded-shell[#cli.using-the-cli.embedded-shell]\n* xref:cli:using-the-cli.adoc#cli.using-the-cli.initialize-new-project[#cli-init]\n* xref:cli:using-the-cli.adoc#cli.using-the-cli.initialize-new-project[#cli.using-the-cli.initialize-new-project]\n* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli-using-the-cli]\n* xref:cli:using-the-cli.adoc#cli.using-the-cli[#cli.using-the-cli]\n* xref:community.adoc[#boot-documentation-getting-help]\n* xref:community.adoc[#documentation.getting-help]\n* xref:community.adoc[#getting-help]\n* xref:community.adoc[getting-help]\n* xref:documentation.adoc[#boot-documentation-about]\n* xref:documentation.adoc[#documentation.about]\n* xref:documentation.adoc[#documentation]\n* xref:documentation.adoc[documentation]\n* xref:gradle-plugin:aot.adoc#aot.processing-applications[gradle-plugin#aot.processing-applications]\n* xref:gradle-plugin:aot.adoc#aot.processing-tests[gradle-plugin#aot.processing-tests]\n* xref:gradle-plugin:aot.adoc#aot[gradle-plugin#aot]\n* xref:gradle-plugin:getting-started.adoc#getting-started[gradle-plugin#getting-started]\n* xref:gradle-plugin:index.adoc#gradle-plugin[gradle-plugin#gradle-plugin]\n* xref:gradle-plugin:integrating-with-actuator.adoc#integrating-with-actuator.build-info[gradle-plugin#integrating-with-actuator.build-info]\n* xref:gradle-plugin:integrating-with-actuator.adoc#integrating-with-actuator[gradle-plugin#integrating-with-actuator]\n* xref:gradle-plugin:introduction.adoc#introduction[gradle-plugin#introduction]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.customizing[gradle-plugin#managing-dependencies.dependency-management-plugin.customizing]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.learning-more[gradle-plugin#managing-dependencies.dependency-management-plugin.learning-more]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.using-in-isolation[gradle-plugin#managing-dependencies.dependency-management-plugin.using-in-isolation]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin[gradle-plugin#managing-dependencies.dependency-management-plugin]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.gradle-bom-support.customizing[gradle-plugin#managing-dependencies.gradle-bom-support.customizing]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.gradle-bom-support[gradle-plugin#managing-dependencies.gradle-bom-support]\n* xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies[gradle-plugin#managing-dependencies]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.customization.tags[gradle-plugin#build-image.customization.tags]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.customization[gradle-plugin#build-image.customization]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.docker-daemon[gradle-plugin#build-image.docker-daemon]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.docker-registry[gradle-plugin#build-image.docker-registry]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.builder-configuration[gradle-plugin#build-image.examples.builder-configuration]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.buildpacks[gradle-plugin#build-image.examples.buildpacks]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.caches[gradle-plugin#build-image.examples.caches]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.custom-image-builder[gradle-plugin#build-image.examples.custom-image-builder]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.custom-image-name[gradle-plugin#build-image.examples.custom-image-name]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.auth[gradle-plugin#build-image.examples.docker.auth]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.colima[gradle-plugin#build-image.examples.docker.colima]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.minikube[gradle-plugin#build-image.examples.docker.minikube]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker.podman[gradle-plugin#build-image.examples.docker.podman]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.docker[gradle-plugin#build-image.examples.docker]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.publish[gradle-plugin#build-image.examples.publish]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.runtime-jvm-configuration[gradle-plugin#build-image.examples.runtime-jvm-configuration]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples[gradle-plugin#build-image.examples]\n* xref:gradle-plugin:packaging-oci-image.adoc#build-image[gradle-plugin#build-image]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.and-plain-archives[gradle-plugin#packaging-executable.and-plain-archives]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.including-development-only-dependencies[gradle-plugin#packaging-executable.configuring.including-development-only-dependencies]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.layered-archives.configuration[gradle-plugin#packaging-executable.configuring.layered-archives.configuration]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.layered-archives[gradle-plugin#packaging-executable.configuring.layered-archives]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.main-class[gradle-plugin#packaging-executable.configuring.main-class]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.properties-launcher[gradle-plugin#packaging-executable.configuring.properties-launcher]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.unpacking[gradle-plugin#packaging-executable.configuring.unpacking]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.configuring[gradle-plugin#packaging-executable.configuring]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.jars[gradle-plugin#packaging-executable.jars]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.wars.deployable[gradle-plugin#packaging-executable.wars.deployable]\n* xref:gradle-plugin:packaging.adoc#packaging-executable.wars[gradle-plugin#packaging-executable.wars]\n* xref:gradle-plugin:packaging.adoc#packaging-executable[gradle-plugin#packaging-executable]\n* xref:gradle-plugin:publishing.adoc#publishing-your-application.distribution[gradle-plugin#publishing-your-application.distribution]\n* xref:gradle-plugin:publishing.adoc#publishing-your-application.maven-publish[gradle-plugin#publishing-your-application-maven]\n* xref:gradle-plugin:publishing.adoc#publishing-your-application.maven-publish[gradle-plugin#publishing-your-application.maven-publish]\n* xref:gradle-plugin:publishing.adoc#publishing-your-application[gradle-plugin#publishing-your-application]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.application[gradle-plugin#reacting-to-other-plugins.application]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.dependency-management[gradle-plugin#reacting-to-other-plugins.dependency-management]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.java[gradle-plugin#reacting-to-other-plugins.java]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.kotlin[gradle-plugin#reacting-to-other-plugins.kotlin]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.nbt[gradle-plugin#reacting-to-other-plugins.nbt]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins.war[gradle-plugin#reacting-to-other-plugins.war]\n* xref:gradle-plugin:reacting.adoc#reacting-to-other-plugins[gradle-plugin#reacting-to-other-plugins]\n* xref:gradle-plugin:running.adoc#running-your-application.passing-arguments[gradle-plugin#running-your-application.passing-arguments]\n* xref:gradle-plugin:running.adoc#running-your-application.passing-system-properties[gradle-plugin#running-your-application.passing-system-properties]\n* xref:gradle-plugin:running.adoc#running-your-application.reloading-resources[gradle-plugin#running-your-application.reloading-resources]\n* xref:gradle-plugin:running.adoc#running-your-application.using-a-test-main-class[gradle-plugin#running-your-application.using-a-test-main-class]\n* xref:gradle-plugin:running.adoc#running-your-application[gradle-plugin#running-your-application]\n* xref:how-to:actuator.adoc#howto.actuator.change-http-port-or-address[#howto-change-the-http-port-or-address-of-the-actuator-endpoints]\n* xref:how-to:actuator.adoc#howto.actuator.change-http-port-or-address[#howto.actuator.change-http-port-or-address]\n* xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[#howto.actuator.customizing-sanitization]\n* xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[#howto.actuator.sanitize-sensitive-values.customizing-sanitization]\n* xref:how-to:actuator.adoc#howto.actuator.map-health-indicators-to-metrics[#howto-map-health-indicators-to-metrics]\n* xref:how-to:actuator.adoc#howto.actuator.map-health-indicators-to-metrics[#howto.actuator.map-health-indicators-to-metrics]\n* xref:how-to:actuator.adoc#howto.actuator[#howto-actuator]\n* xref:how-to:actuator.adoc#howto.actuator[#howto.actuator]\n* xref:how-to:aot-cache.adoc#howto.aot-cache.buildpacks[#howto.class-data-sharing.buildpacks]\n* xref:how-to:aot-cache.adoc#howto.aot-cache.dockerfiles[#howto.class-data-sharing.dockerfiles]\n* xref:how-to:aot-cache.adoc#howto.aot-cache.training-run-configuration[#howto.class-data-sharing.training-run-configuration]\n* xref:how-to:aot-cache.adoc#howto.aot-cache[#howto.class-data-sharing]\n* xref:how-to:aot.adoc#howto.aot.conditions[#howto.aot.conditions]\n* xref:how-to:aot.adoc#howto.aot[#howto.aot]\n* xref:how-to:application.adoc#howto.application.context-hierarchy[#howto-build-an-application-context-hierarchy]\n* xref:how-to:application.adoc#howto.application.context-hierarchy[#howto.application.context-hierarchy]\n* xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[#howto-customize-the-environment-or-application-context]\n* xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[#howto.application.customize-the-environment-or-application-context]\n* xref:how-to:application.adoc#howto.application.failure-analyzer[#howto-failure-analyzer]\n* xref:how-to:application.adoc#howto.application.failure-analyzer[#howto.application.failure-analyzer]\n* xref:how-to:application.adoc#howto.application.non-web-application[#howto-create-a-non-web-application]\n* xref:how-to:application.adoc#howto.application.non-web-application[#howto.application.non-web-application]\n* xref:how-to:application.adoc#howto.application.troubleshoot-auto-configuration[#howto-troubleshoot-auto-configuration]\n* xref:how-to:application.adoc#howto.application.troubleshoot-auto-configuration[#howto.application.troubleshoot-auto-configuration]\n* xref:how-to:application.adoc#howto.application[#howto-spring-boot-application]\n* xref:how-to:application.adoc#howto.application[#howto.application]\n* xref:how-to:batch.adoc#howto.batch.restarting-a-failed-job[#howto.batch.restarting-a-failed-job]\n* xref:how-to:batch.adoc#howto.batch.running-from-the-command-line[#howto-spring-batch-running-command-line]\n* xref:how-to:batch.adoc#howto.batch.running-from-the-command-line[#howto.batch.running-from-the-command-line]\n* xref:how-to:batch.adoc#howto.batch.specifying-a-data-source[#howto-spring-batch-specifying-a-data-source]\n* xref:how-to:batch.adoc#howto.batch.specifying-a-data-source[#howto.batch.specifying-a-data-source]\n* xref:how-to:batch.adoc#howto.batch.specifying-a-transaction-manager[#howto.batch.specifying-a-transaction-manager]\n* xref:reference:io/spring-batch.adoc#io.spring-batch[#howto-spring-batch-storing-job-repository]\n* xref:reference:io/spring-batch.adoc#io.spring-batch[#howto.batch.storing-job-repository]\n* xref:how-to:batch.adoc#howto.batch[#howto-batch-applications]\n* xref:how-to:batch.adoc#howto.batch[#howto.batch]\n* xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[#howto-build-an-executable-archive-with-ant]\n* xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib]\n* xref:how-to:build.adoc#howto.build.create-a-nonexecutable-jar[#howto-create-a-nonexecutable-jar]\n* xref:how-to:build.adoc#howto.build.create-a-nonexecutable-jar[#howto.build.create-a-nonexecutable-jar]\n* xref:how-to:build.adoc#howto.build.create-an-executable-jar-with-maven[#howto-create-an-executable-jar-with-maven]\n* xref:how-to:build.adoc#howto.build.create-an-executable-jar-with-maven[#howto.build.create-an-executable-jar-with-maven]\n* xref:how-to:build.adoc#howto.build.customize-dependency-versions[#howto-customize-dependency-versions]\n* xref:how-to:build.adoc#howto.build.customize-dependency-versions[#howto.build.customize-dependency-versions]\n* xref:how-to:build.adoc#howto.build.extract-specific-libraries-when-an-executable-jar-runs[#howto-extract-specific-libraries-when-an-executable-jar-runs]\n* xref:how-to:build.adoc#howto.build.extract-specific-libraries-when-an-executable-jar-runs[#howto.build.extract-specific-libraries-when-an-executable-jar-runs]\n* xref:how-to:build.adoc#howto.build.generate-git-info[#howto-git-info]\n* xref:how-to:build.adoc#howto.build.generate-git-info[#howto.build.generate-git-info]\n* xref:how-to:build.adoc#howto.build.generate-info[#howto-build-info]\n* xref:how-to:build.adoc#howto.build.generate-info[#howto.build.generate-info]\n* xref:how-to:build.adoc#howto.build.remote-debug-maven[#howto-remote-debug-maven-run]\n* xref:how-to:build.adoc#howto.build.remote-debug-maven[#howto.build.remote-debug-maven]\n* xref:how-to:build.adoc#howto.build.use-a-spring-boot-application-as-dependency[#howto-create-an-additional-executable-jar]\n* xref:how-to:build.adoc#howto.build.use-a-spring-boot-application-as-dependency[#howto.build.use-a-spring-boot-application-as-dependency]\n* xref:how-to:build.adoc#howto.build[#howto-build]\n* xref:how-to:build.adoc#howto.build[#howto.build]\n* xref:how-to:data-access.adoc#howto.data-access.configure-a-component-that-is-used-by-jpa[#howto-configure-a-component-that-is-used-by-JPA]\n* xref:how-to:data-access.adoc#howto.data-access.configure-a-component-that-is-used-by-jpa[#howto.data-access.configure-a-component-that-is-used-by-jpa]\n* xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[#howto-configure-a-datasource]\n* xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[#howto.data-access.configure-custom-datasource]\n* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-naming-strategy[#howto-configure-hibernate-naming-strategy]\n* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-naming-strategy[#howto.data-access.configure-hibernate-naming-strategy]\n* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-second-level-caching[#howto-configure-hibernate-second-level-caching]\n* xref:how-to:data-access.adoc#howto.data-access.configure-hibernate-second-level-caching[#howto.data-access.configure-hibernate-second-level-caching]\n* xref:how-to:data-access.adoc#howto.data-access.configure-jooq-with-multiple-datasources[#howto-configure-jOOQ-with-multiple-datasources]\n* xref:how-to:data-access.adoc#howto.data-access.configure-jooq-with-multiple-datasources[#howto.data-access.configure-jooq-with-multiple-datasources]\n* xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[#howto-two-datasources]\n* xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[#howto.data-access.configure-two-datasources]\n* xref:how-to:data-access.adoc#howto.data-access.customize-spring-data-web-support[#howto-use-customize-spring-datas-web-support]\n* xref:how-to:data-access.adoc#howto.data-access.customize-spring-data-web-support[#howto.data-access.customize-spring-data-web-support]\n* xref:how-to:data-access.adoc#howto.data-access.dependency-injection-in-hibernate-components[#howto-use-dependency-injection-hibernate-components]\n* xref:how-to:data-access.adoc#howto.data-access.dependency-injection-in-hibernate-components[#howto.data-access.dependency-injection-in-hibernate-components]\n* xref:how-to:data-access.adoc#howto.data-access.exposing-spring-data-repositories-as-rest[#howto-use-exposing-spring-data-repositories-rest-endpoint]\n* xref:how-to:data-access.adoc#howto.data-access.exposing-spring-data-repositories-as-rest[#howto.data-access.exposing-spring-data-repositories-as-rest]\n* xref:how-to:data-access.adoc#howto.data-access.jpa-properties[#howto-configure-jpa-properties]\n* xref:how-to:data-access.adoc#howto.data-access.jpa-properties[#howto.data-access.jpa-properties]\n* xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[#howto-separate-entity-definitions-from-spring-configuration]\n* xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[#howto.data-access.separate-entity-definitions-from-spring-configuration]\n* xref:how-to:data-access.adoc#howto.data-access.spring-data-repositories[#howto-use-spring-data-repositories]\n* xref:how-to:data-access.adoc#howto.data-access.spring-data-repositories[#howto.data-access.spring-data-repositories]\n* xref:how-to:data-access.adoc#howto.data-access.use-custom-entity-manager[#howto-use-custom-entity-manager]\n* xref:how-to:data-access.adoc#howto.data-access.use-custom-entity-manager[#howto.data-access.use-custom-entity-manager]\n* xref:how-to:data-access.adoc#howto.data-access.use-multiple-entity-managers[#howto-use-two-entity-managers]\n* xref:how-to:data-access.adoc#howto.data-access.use-multiple-entity-managers[#howto.data-access.use-multiple-entity-managers]\n* xref:how-to:data-access.adoc#howto.data-access.use-spring-data-jpa-and-mongo-repositories[#howto-use-spring-data-jpa--and-mongo-repositories]\n* xref:how-to:data-access.adoc#howto.data-access.use-spring-data-jpa-and-mongo-repositories[#howto.data-access.use-spring-data-jpa-and-mongo-repositories]\n* xref:how-to:data-access.adoc#howto.data-access.use-traditional-persistence-xml[#howto-use-traditional-persistence-xml]\n* xref:how-to:data-access.adoc#howto.data-access.use-traditional-persistence-xml[#howto.data-access.use-traditional-persistence-xml]\n* xref:how-to:data-access.adoc#howto.data-access[#howto-data-access]\n* xref:how-to:data-access.adoc#howto.data-access[#howto.data-access]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.batch[#howto-initialize-a-spring-batch-database]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.batch[#howto.data-initialization.batch]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.depends-on-initialization-detection[#howto-initialize-a-database-configuring-dependencies-depends-on-initialization-detection]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.depends-on-initialization-detection[#howto.data-initialization.dependencies.depends-on-initialization-detection]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.initializer-detection[#howto-initialize-a-database-configuring-dependencies-initializer-detection]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies.initializer-detection[#howto.data-initialization.dependencies.initializer-detection]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto-initialize-a-database-configuring-dependencies]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.dependencies[#howto.data-initialization.dependencies]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway-tests[#howto.data-initialization.migration-tool.flyway-tests]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto-execute-flyway-database-migrations-on-startup]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.flyway[#howto.data-initialization.migration-tool.flyway]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase-tests[#howto.data-initialization.migration-tool.liquibase-tests]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto-execute-liquibase-database-migrations-on-startup]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase[#howto.data-initialization.migration-tool.liquibase]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto-use-a-higher-level-database-migration-tool]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.migration-tool[#howto.data-initialization.migration-tool]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[#howto-initialize-a-database-using-basic-scripts]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[#howto.data-initialization.using-basic-sql-scripts]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.using-hibernate[#howto.data-initialization.using-hibernate]\n* xref:how-to:data-initialization.adoc#howto.data-initialization.using-hibernate[#howto.data-initialization.using-jpa]\n* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto-database-initialization]\n* xref:how-to:data-initialization.adoc#howto.data-initialization[#howto.data-initialization]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#cloud-deployment-aws-java-se-platform]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.java-se-platform[#deployment.cloud.aws.beanstalk.java-se-platform]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#cloud-deployment-aws-tomcat-platform]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk.tomcat-platform[#deployment.cloud.aws.beanstalk.tomcat-platform]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#cloud-deployment-aws-beanstalk]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws.beanstalk[#deployment.cloud.aws.beanstalk]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#cloud-deployment-aws]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.aws[#deployment.cloud.aws]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.azure[#deployment.cloud.azure]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#cloud-deployment-boxfuse]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.boxfuse[#deployment.cloud.boxfuse]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#cloud-deployment-cloud-foundry-services]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry.binding-to-services[#deployment.cloud.cloud-foundry.binding-to-services]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#cloud-deployment-cloud-foundry]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.cloud-foundry[#deployment.cloud.cloud-foundry]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#cloud-deployment-gae]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.google[#deployment.cloud.google]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#cloud-deployment-heroku]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.heroku[#deployment.cloud.heroku]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#cloud-deployment-kubernetes-container-lifecycle]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[#deployment.cloud.kubernetes.container-lifecycle]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#cloud-deployment-kubernetes]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[#deployment.cloud.kubernetes]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#cloud-deployment-openshift]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.openshift[#deployment.cloud.openshift]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#cloud-deployment]\n* xref:how-to:deployment/cloud.adoc#howto.deployment.cloud[#deployment.cloud]\n* xref:how-to:deployment/index.adoc#howto.deployment[#deployment]\n* xref:how-to:deployment/index.adoc[#deployment]\n* xref:how-to:deployment/index.adoc[deployment]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment-systemd-service]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.nix-services.system-d]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing.system-d[#deployment.installing.system-d]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment-windows]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing.windows-services[#deployment.installing.windows-services]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment-install-supported-operating-systems]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment-service]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing.supported-operating-systems]\n* xref:how-to:deployment/installing.adoc#howto.deployment.installing[#deployment.installing]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto-convert-an-existing-application-to-spring-boot]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.convert-existing-application[#howto.traditional-deployment.convert-existing-application]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto-create-a-deployable-war-file]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.war[#howto.traditional-deployment.war]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto-weblogic]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment.weblogic[#howto.traditional-deployment.weblogic]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto-traditional-deployment]\n* xref:how-to:deployment/traditional-deployment.adoc#howto.traditional-deployment[#howto.traditional-deployment]\n* xref:how-to:docker-compose.adoc#howto.docker-compose.jdbc-url[#howto.docker-compose.jdbc-url]\n* xref:how-to:docker-compose.adoc#howto.docker-compose.sharing-services[#howto.docker-compose.sharing-services]\n* xref:how-to:docker-compose.adoc#howto.docker-compose[#howto.docker-compose]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.fast-application-restarts[#howto-reload-fast-restart]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.fast-application-restarts[#howto.hotswapping.fast-application-restarts]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-java-classes-without-restarting[#howto-reload-java-classes-without-restarting]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-java-classes-without-restarting[#howto.hotswapping.reload-java-classes-without-restarting]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-static-content[#howto-reload-static-content]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-static-content[#howto.hotswapping.reload-static-content]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.freemarker[#howto-reload-freemarker-content]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.freemarker[#howto.hotswapping.reload-templates.freemarker]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.groovy[#howto-reload-groovy-template-content]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.groovy[#howto.hotswapping.reload-templates.groovy]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.thymeleaf[#howto-reload-thymeleaf-content]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates.thymeleaf[#howto.hotswapping.reload-templates.thymeleaf]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto-reload-thymeleaf-template-content]\n* xref:how-to:hotswapping.adoc#howto.hotswapping.reload-templates[#howto.hotswapping.reload-templates]\n* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto-hotswapping]\n* xref:how-to:hotswapping.adoc#howto.hotswapping[#howto.hotswapping]\n* xref:how-to:http-clients.adoc#howto.http-clients.rest-template-proxy-configuration[#howto-http-clients-proxy-configuration]\n* xref:how-to:http-clients.adoc#howto.http-clients.rest-template-proxy-configuration[#howto.http-clients.rest-template-proxy-configuration]\n* xref:how-to:http-clients.adoc#howto.http-clients.webclient-reactor-netty-customization[#howto-webclient-reactor-netty-customization]\n* xref:how-to:http-clients.adoc#howto.http-clients.webclient-reactor-netty-customization[#howto.http-clients.webclient-reactor-netty-customization]\n* xref:how-to:http-clients.adoc#howto.http-clients[#howto-http-clients]\n* xref:how-to:http-clients.adoc#howto.http-clients[#howto.http-clients]\n* xref:how-to:index.adoc#howto[#howto]\n* xref:how-to:index.adoc[#howto]\n* xref:how-to:index.adoc[howto]\n* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto-jersey-alongside-another-web-framework]\n* xref:how-to:jersey.adoc#howto.jersey.alongside-another-web-framework[#howto.jersey.alongside-another-web-framework]\n* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto-jersey-spring-security]\n* xref:how-to:jersey.adoc#howto.jersey.spring-security[#howto.jersey.spring-security]\n* xref:how-to:jersey.adoc#howto.jersey[#howto-jersey]\n* xref:how-to:jersey.adoc#howto.jersey[#howto.jersey]\n* xref:how-to:logging.adoc#howto.logging.log4j.composite-configuration[#howto.logging.log4j.composite-configuration]\n* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto-configure-log4j-for-logging-yaml-or-json-config]\n* xref:how-to:logging.adoc#howto.logging.log4j.yaml-or-json-config[#howto.logging.log4j.yaml-or-json-config]\n* xref:how-to:logging.adoc#howto.logging.log4j[#howto-configure-log4j-for-logging]\n* xref:how-to:logging.adoc#howto.logging.log4j[#howto.logging.log4j]\n* xref:how-to:logging.adoc#howto.logging.logback.file-only-output[#howto-configure-logback-for-logging-fileonly]\n* xref:how-to:logging.adoc#howto.logging.logback.file-only-output[#howto.logging.logback.file-only-output]\n* xref:how-to:logging.adoc#howto.logging.logback[#howto-configure-logback-for-logging]\n* xref:how-to:logging.adoc#howto.logging.logback[#howto.logging.logback]\n* xref:how-to:logging.adoc#howto.logging[#howto-logging]\n* xref:how-to:logging.adoc#howto.logging[#howto.logging]\n* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto-jms-disable-transaction]\n* xref:how-to:messaging.adoc#howto.messaging.disable-transacted-jms-session[#howto.messaging.disable-transacted-jms-session]\n* xref:how-to:messaging.adoc#howto.messaging[#howto-messaging]\n* xref:how-to:messaging.adoc#howto.messaging[#howto.messaging]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.gradle[#native-image.developing-your-first-application.buildpacks.gradle]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.maven[#native-image.developing-your-first-application.buildpacks.maven]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.running[#native-image.developing-your-first-application.buildpacks.running]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.system-requirements[#native-image.developing-your-first-application.buildpacks.system-requirements]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks[#native-image.developing-your-first-application.buildpacks]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.gradle[#native-image.developing-your-first-application.native-build-tools.gradle]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.maven[#native-image.developing-your-first-application.native-build-tools.maven]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos[#native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites.windows[#native-image.developing-your-first-application.native-build-tools.prerequisites.windows]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.prerequisites[#native-image.developing-your-first-application.native-build-tools.prerequisites]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools.running[#native-image.developing-your-first-application.native-build-tools.running]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.native-build-tools[#native-image.developing-your-first-application.native-build-tools]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.sample-application[#native-image.developing-your-first-application.sample-application]\n* xref:how-to:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application[#native-image.developing-your-first-application]\n* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools.gradle[#native-image.testing.with-native-build-tools.gradle]\n* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools.maven[#native-image.testing.with-native-build-tools.maven]\n* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-native-build-tools[#native-image.testing.with-native-build-tools]\n* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing.with-the-jvm[#native-image.testing.with-the-jvm]\n* xref:how-to:native-image/testing-native-applications.adoc#howto.native-image.testing[#native-image.testing]\n* xref:how-to:nosql.adoc#howto.nosql.jedis-instead-of-lettuce[#howto-use-jedis-instead-of-lettuce]\n* xref:how-to:nosql.adoc#howto.nosql.jedis-instead-of-lettuce[#howto.nosql.jedis-instead-of-lettuce]\n* xref:how-to:nosql.adoc#howto.nosql[#howto.nosql]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.change-configuration-depending-on-the-environment[#howto-change-configuration-depending-on-the-environment]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.change-configuration-depending-on-the-environment[#howto.properties-and-configuration.change-configuration-depending-on-the-environment]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[#howto-discover-build-in-options-for-external-properties]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[#howto.properties-and-configuration.discover-build-in-options-for-external-properties]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.gradle[#howto-automatic-expansion-gradle]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.gradle[#howto.properties-and-configuration.expand-properties.gradle]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.maven[#howto-automatic-expansion-maven]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties.maven[#howto.properties-and-configuration.expand-properties.maven]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto-automatic-expansion]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[#howto.properties-and-configuration.expand-properties]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.external-properties-location[#howto-change-the-location-of-external-properties]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.external-properties-location[#howto.properties-and-configuration.external-properties-location]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.externalize-configuration[#howto-externalize-configuration]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.externalize-configuration[#howto.properties-and-configuration.externalize-configuration]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-active-spring-profiles[#howto-set-active-spring-profiles]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-active-spring-profiles[#howto.properties-and-configuration.set-active-spring-profiles]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.set-default-spring-profile-name[#howto.properties-and-configuration.set-default-spring-profile-name]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[#howto-use-short-command-line-arguments]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[#howto.properties-and-configuration.short-command-line-arguments]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.yaml[#howto-use-yaml-for-external-properties]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.yaml[#howto.properties-and-configuration.yaml]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto-properties-and-configuration]\n* xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration[#howto.properties-and-configuration]\n* xref:how-to:security.adoc#howto.security.change-user-details-service-and-add-user-accounts[#howto-change-the-user-details-service-and-add-user-accounts]\n* xref:how-to:security.adoc#howto.security.change-user-details-service-and-add-user-accounts[#howto.security.change-user-details-service-and-add-user-accounts]\n* xref:how-to:security.adoc#howto.security.enable-https[#howto-enable-https]\n* xref:how-to:security.adoc#howto.security.enable-https[#howto.security.enable-https]\n* xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto-switch-off-spring-boot-security-configuration]\n* xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto.security.switch-off-spring-boot-configuration]\n* xref:how-to:security.adoc#howto.security[#howto-security]\n* xref:how-to:security.adoc#howto.security[#howto.security]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-jsonmapper[#howto-customize-the-jackson-objectmapper]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-jsonmapper[#howto.spring-mvc.customize-jackson-objectmapper]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto-customize-the-responsebody-rendering]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto.spring-mvc.customize-responsebody-rendering]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto-customize-view-resolvers]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto.spring-mvc.customize-view-resolvers]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-whitelabel-error-page[#howto-customize-the-whitelabel-error-page]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-whitelabel-error-page[#howto.actuator.customize-whitelabel-error-page]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.multipart-file-uploads[#howto-multipart-file-upload-configuration]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.multipart-file-uploads[#howto.spring-mvc.multipart-file-uploads]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-default-configuration[#howto-switch-off-default-mvc-configuration]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-default-configuration[#howto.spring-mvc.switch-off-default-configuration]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-dispatcherservlet[#howto-switch-off-the-spring-mvc-dispatcherservlet]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.switch-off-dispatcherservlet[#howto.spring-mvc.switch-off-dispatcherservlet]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-json-rest-service[#howto-write-a-json-rest-service]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-json-rest-service[#howto.spring-mvc.write-json-rest-service]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-xml-rest-service[#howto-write-an-xml-rest-service]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc.write-xml-rest-service[#howto.spring-mvc.write-xml-rest-service]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto-spring-mvc]\n* xref:how-to:spring-mvc.adoc#howto.spring-mvc[#howto.spring-mvc]\n* xref:how-to:testing.adoc#howto.testing.slice-tests[#howto.testing.slice-tests]\n* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto-use-test-with-spring-security]\n* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.spring-mvc.testing.with-spring-security]\n* xref:how-to:testing.adoc#howto.testing.with-spring-security[#howto.testing.with-spring-security]\n* xref:how-to:testing.adoc#howto.testing[#howto.testing]\n* xref:how-to:webserver.adoc#howto-configure-webserver-customizers[#howto-configure-webserver-customizers]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean.disable[#howto-disable-registration-of-a-servlet-or-filter]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean.disable[#howto.webserver.add-servlet-filter-listener.spring-bean.disable]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto-add-a-servlet-filter-or-listener-as-spring-bean]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[#howto.webserver.add-servlet-filter-listener.spring-bean]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[#howto-add-a-servlet-filter-or-listener-using-scanning]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[#howto.webserver.add-servlet-filter-listener.using-scanning]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto-add-a-servlet-filter-or-listener]\n* xref:how-to:webserver.adoc#howto.webserver.add-servlet-filter-listener[#howto.webserver.add-servlet-filter-listener]\n* xref:how-to:webserver.adoc#howto.webserver.change-port[#howto-change-the-http-port]\n* xref:how-to:webserver.adoc#howto.webserver.change-port[#howto.webserver.change-port]\n* xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[#howto-configure-accesslogs]\n* xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[#howto.webserver.configure-access-logs]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2.jetty[#howto-configure-http2-jetty]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2.jetty[#howto.webserver.configure-http2.jetty]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto-configure-http2-netty]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2.netty[#howto.webserver.configure-http2.netty]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto-configure-http2-tomcat]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2.tomcat[#howto.webserver.configure-http2.tomcat]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto-configure-http2]\n* xref:how-to:webserver.adoc#howto.webserver.configure-http2[#howto.webserver.configure-http2]\n* xref:how-to:webserver.adoc#howto.webserver.configure-ssl.pem-files[#howto.webserver.configure-ssl.pem-files]\n* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto-configure-ssl]\n* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[#howto.webserver.configure-ssl]\n* xref:how-to:webserver.adoc#howto.webserver.configure[#howto-configure-webserver]\n* xref:how-to:webserver.adoc#howto.webserver.configure[#howto.webserver.configure]\n* xref:how-to:webserver.adoc#howto.webserver.create-websocket-endpoints-using-serverendpoint[#howto-create-websocket-endpoints-using-serverendpoint]\n* xref:how-to:webserver.adoc#howto.webserver.create-websocket-endpoints-using-serverendpoint[#howto.webserver.create-websocket-endpoints-using-serverendpoint]\n* xref:how-to:webserver.adoc#howto.webserver.disable[#howto-disable-web-server]\n* xref:how-to:webserver.adoc#howto.webserver.disable[#howto.webserver.disable]\n* xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto-discover-the-http-port-at-runtime]\n* xref:how-to:webserver.adoc#howto.webserver.discover-port[#howto.webserver.discover-port]\n* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto-enable-multiple-connectors-in-tomcat]\n* xref:how-to:webserver.adoc#howto.webserver.enable-multiple-connectors-in-tomcat[#howto.webserver.enable-multiple-connectors-in-tomcat]\n* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#how-to-enable-http-response-compression]\n* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[#howto.webserver.enable-response-compression]\n* xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto-enable-tomcat-mbean-registry]\n* xref:how-to:webserver.adoc#howto.webserver.enable-tomcat-mbean-registry[#howto.webserver.enable-tomcat-mbean-registry]\n* xref:how-to:webserver.adoc#howto.webserver.use-another[#howto-use-another-web-server]\n* xref:how-to:webserver.adoc#howto.webserver.use-another[#howto.webserver.use-another]\n* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server.tomcat[#howto-customize-tomcat-behind-a-proxy-server]\n* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server.tomcat[#howto.webserver.use-behind-a-proxy-server.tomcat]\n* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto-use-behind-a-proxy-server]\n* xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[#howto.webserver.use-behind-a-proxy-server]\n* xref:how-to:webserver.adoc#howto.webserver.use-random-port[#howto-user-a-random-unassigned-http-port]\n* xref:how-to:webserver.adoc#howto.webserver.use-random-port[#howto.webserver.use-random-port]\n* xref:how-to:webserver.adoc#howto.webserver[#howto-embedded-web-servers]\n* xref:how-to:webserver.adoc#howto.webserver[#howto.webserver]\n* xref:index.adoc[#getting-started.introducing-spring-boot]\n* xref:index.adoc[#getting-started]\n* xref:index.adoc[#index]\n* xref:index.adoc[#spring-boot-reference-documentation]\n* xref:index.adoc[getting-started]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.optional-parameters[maven-plugin#aot.process-aot-goal.optional-parameters]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.arguments[maven-plugin#aot.process-aot-goal.parameter-details.arguments]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.classes-directory[maven-plugin#aot.process-aot-goal.parameter-details.classes-directory]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.compiler-arguments[maven-plugin#aot.process-aot-goal.parameter-details.compiler-arguments]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.exclude-group-ids[maven-plugin#aot.process-aot-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.excludes[maven-plugin#aot.process-aot-goal.parameter-details.excludes]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.generated-classes[maven-plugin#aot.process-aot-goal.parameter-details.generated-classes]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.generated-resources[maven-plugin#aot.process-aot-goal.parameter-details.generated-resources]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.generated-sources[maven-plugin#aot.process-aot-goal.parameter-details.generated-sources]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.includes[maven-plugin#aot.process-aot-goal.parameter-details.includes]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.jvm-arguments[maven-plugin#aot.process-aot-goal.parameter-details.jvm-arguments]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.main-class[maven-plugin#aot.process-aot-goal.parameter-details.main-class]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.profiles[maven-plugin#aot.process-aot-goal.parameter-details.profiles]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.skip[maven-plugin#aot.process-aot-goal.parameter-details.skip]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details.system-property-variables[maven-plugin#aot.process-aot-goal.parameter-details.system-property-variables]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.parameter-details[maven-plugin#aot.process-aot-goal.parameter-details]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal.required-parameters[maven-plugin#aot.process-aot-goal.required-parameters]\n* xref:maven-plugin:aot.adoc#aot.process-aot-goal[maven-plugin#aot.process-aot-goal]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.optional-parameters[maven-plugin#aot.process-test-aot-goal.optional-parameters]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.classes-directory[maven-plugin#aot.process-test-aot-goal.parameter-details.classes-directory]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.compiler-arguments[maven-plugin#aot.process-test-aot-goal.parameter-details.compiler-arguments]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.exclude-group-ids[maven-plugin#aot.process-test-aot-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.excludes[maven-plugin#aot.process-test-aot-goal.parameter-details.excludes]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.generated-classes[maven-plugin#aot.process-test-aot-goal.parameter-details.generated-classes]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.generated-resources[maven-plugin#aot.process-test-aot-goal.parameter-details.generated-resources]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.generated-sources[maven-plugin#aot.process-test-aot-goal.parameter-details.generated-sources]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.generated-test-classes[maven-plugin#aot.process-test-aot-goal.parameter-details.generated-test-classes]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.includes[maven-plugin#aot.process-test-aot-goal.parameter-details.includes]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.jvm-arguments[maven-plugin#aot.process-test-aot-goal.parameter-details.jvm-arguments]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.skip[maven-plugin#aot.process-test-aot-goal.parameter-details.skip]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.system-property-variables[maven-plugin#aot.process-test-aot-goal.parameter-details.system-property-variables]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details.test-classes-directory[maven-plugin#aot.process-test-aot-goal.parameter-details.test-classes-directory]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.parameter-details[maven-plugin#aot.process-test-aot-goal.parameter-details]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal.required-parameters[maven-plugin#aot.process-test-aot-goal.required-parameters]\n* xref:maven-plugin:aot.adoc#aot.process-test-aot-goal[maven-plugin#aot.process-test-aot-goal]\n* xref:maven-plugin:aot.adoc#aot.processing-applications.using-the-native-profile[maven-plugin#aot.processing-applications.using-the-native-profile]\n* xref:maven-plugin:aot.adoc#aot.processing-applications[maven-plugin#aot.processing-applications]\n* xref:maven-plugin:aot.adoc#aot.processing-tests[maven-plugin#aot.processing-tests]\n* xref:maven-plugin:aot.adoc#aot[maven-plugin#aot]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.optional-parameters[maven-plugin#build-image.build-image-goal.optional-parameters]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.classifier[maven-plugin#build-image.build-image-goal.parameter-details.classifier]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.docker[maven-plugin#build-image.build-image-goal.parameter-details.docker]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.exclude-devtools[maven-plugin#build-image.build-image-goal.parameter-details.exclude-devtools]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.exclude-docker-compose[maven-plugin#build-image.build-image-goal.parameter-details.exclude-docker-compose]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.exclude-group-ids[maven-plugin#build-image.build-image-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.excludes[maven-plugin#build-image.build-image-goal.parameter-details.excludes]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.image[maven-plugin#build-image.build-image-goal.parameter-details.image]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.include-system-scope[maven-plugin#build-image.build-image-goal.parameter-details.include-system-scope]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.include-tools[maven-plugin#build-image.build-image-goal.parameter-details.include-tools]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.includes[maven-plugin#build-image.build-image-goal.parameter-details.includes]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layers[maven-plugin#build-image.build-image-goal.parameter-details.layers]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layout-factory[maven-plugin#build-image.build-image-goal.parameter-details.layout-factory]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.layout[maven-plugin#build-image.build-image-goal.parameter-details.layout]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.main-class[maven-plugin#build-image.build-image-goal.parameter-details.main-class]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.skip[maven-plugin#build-image.build-image-goal.parameter-details.skip]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details.source-directory[maven-plugin#build-image.build-image-goal.parameter-details.source-directory]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.parameter-details[maven-plugin#build-image.build-image-goal.parameter-details]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal.required-parameters[maven-plugin#build-image.build-image-goal.required-parameters]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-goal[maven-plugin#build-image.build-image-goal]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.optional-parameters[maven-plugin#build-image.build-image-no-fork-goal.optional-parameters]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.classifier[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.classifier]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.docker[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.docker]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.exclude-devtools[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.exclude-devtools]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.exclude-docker-compose[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.exclude-docker-compose]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.exclude-group-ids[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.excludes[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.excludes]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.image[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.image]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.include-system-scope[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.include-system-scope]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.include-tools[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.include-tools]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.includes[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.includes]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layers[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layers]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layout-factory[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layout-factory]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.layout[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.layout]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.main-class[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.main-class]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.skip[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.skip]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details.source-directory[maven-plugin#build-image.build-image-no-fork-goal.parameter-details.source-directory]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.parameter-details[maven-plugin#build-image.build-image-no-fork-goal.parameter-details]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal.required-parameters[maven-plugin#build-image.build-image-no-fork-goal.required-parameters]\n* xref:maven-plugin:build-image.adoc#build-image.build-image-no-fork-goal[maven-plugin#build-image.build-image-no-fork-goal]\n* xref:maven-plugin:build-image.adoc#build-image.customization.tags[maven-plugin#build-image.customization.tags]\n* xref:maven-plugin:build-image.adoc#build-image.customization[maven-plugin#build-image.customization]\n* xref:maven-plugin:build-image.adoc#build-image.docker-daemon[maven-plugin#build-image.docker-daemon]\n* xref:maven-plugin:build-image.adoc#build-image.docker-registry[maven-plugin#build-image.docker-registry]\n* xref:maven-plugin:build-image.adoc#build-image.examples.builder-configuration[maven-plugin#build-image.examples.builder-configuration]\n* xref:maven-plugin:build-image.adoc#build-image.examples.buildpacks[maven-plugin#build-image.examples.buildpacks]\n* xref:maven-plugin:build-image.adoc#build-image.examples.caches[maven-plugin#build-image.examples.caches]\n* xref:maven-plugin:build-image.adoc#build-image.examples.custom-image-builder[maven-plugin#build-image.examples.custom-image-builder]\n* xref:maven-plugin:build-image.adoc#build-image.examples.custom-image-name[maven-plugin#build-image.examples.custom-image-name]\n* xref:maven-plugin:build-image.adoc#build-image.examples.docker.auth[maven-plugin#build-image.examples.docker.auth]\n* xref:maven-plugin:build-image.adoc#build-image.examples.docker.colima[maven-plugin#build-image.examples.docker.colima]\n* xref:maven-plugin:build-image.adoc#build-image.examples.docker.minikube[maven-plugin#build-image.examples.docker.minikube]\n* xref:maven-plugin:build-image.adoc#build-image.examples.docker.podman[maven-plugin#build-image.examples.docker.podman]\n* xref:maven-plugin:build-image.adoc#build-image.examples.docker[maven-plugin#build-image.examples.docker]\n* xref:maven-plugin:build-image.adoc#build-image.examples.publish[maven-plugin#build-image.examples.publish]\n* xref:maven-plugin:build-image.adoc#build-image.examples.runtime-jvm-configuration[maven-plugin#build-image.examples.runtime-jvm-configuration]\n* xref:maven-plugin:build-image.adoc#build-image.examples[maven-plugin#build-image.examples]\n* xref:maven-plugin:build-image.adoc#build-image[maven-plugin#build-image]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.optional-parameters[maven-plugin#build-info.build-info-goal.optional-parameters]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.additional-properties[maven-plugin#build-info.build-info-goal.parameter-details.additional-properties]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.exclude-info-properties[maven-plugin#build-info.build-info-goal.parameter-details.exclude-info-properties]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.output-file[maven-plugin#build-info.build-info-goal.parameter-details.output-file]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.skip[maven-plugin#build-info.build-info-goal.parameter-details.skip]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details.time[maven-plugin#build-info.build-info-goal.parameter-details.time]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal.parameter-details[maven-plugin#build-info.build-info-goal.parameter-details]\n* xref:maven-plugin:build-info.adoc#build-info.build-info-goal[maven-plugin#build-info.build-info-goal]\n* xref:maven-plugin:build-info.adoc#build-info[maven-plugin#build-info]\n* xref:maven-plugin:getting-started.adoc#getting-started[maven-plugin#getting-started]\n* xref:maven-plugin:goals.adoc#goals[maven-plugin#goals]\n* xref:maven-plugin:help.adoc#help.help-goal.optional-parameters[maven-plugin#help.help-goal.optional-parameters]\n* xref:maven-plugin:help.adoc#help.help-goal.parameter-details.detail[maven-plugin#help.help-goal.parameter-details.detail]\n* xref:maven-plugin:help.adoc#help.help-goal.parameter-details.goal[maven-plugin#help.help-goal.parameter-details.goal]\n* xref:maven-plugin:help.adoc#help.help-goal.parameter-details.indent-size[maven-plugin#help.help-goal.parameter-details.indent-size]\n* xref:maven-plugin:help.adoc#help.help-goal.parameter-details.line-length[maven-plugin#help.help-goal.parameter-details.line-length]\n* xref:maven-plugin:help.adoc#help.help-goal.parameter-details[maven-plugin#help.help-goal.parameter-details]\n* xref:maven-plugin:help.adoc#help.help-goal[maven-plugin#help.help-goal]\n* xref:maven-plugin:help.adoc#help[maven-plugin#help]\n* xref:maven-plugin:index.adoc#maven-plugin[maven-plugin#maven-plugin]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.examples.jmx-port[maven-plugin#integration-tests.examples.jmx-port]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.examples.random-port[maven-plugin#integration-tests.examples.random-port]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.examples.skip[maven-plugin#integration-tests.examples.skip]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.examples[maven-plugin#integration-tests.examples]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.no-starter-parent[maven-plugin#integration-tests.no-starter-parent]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.optional-parameters[maven-plugin#integration-tests.start-goal.optional-parameters]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.add-resources[maven-plugin#integration-tests.start-goal.parameter-details.add-resources]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.additional-classpath-elements[maven-plugin#integration-tests.start-goal.parameter-details.additional-classpath-elements]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.additional-classpath-elements[maven-plugin#integration-tests.start-goal.parameter-details.directories]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.agents[maven-plugin#integration-tests.start-goal.parameter-details.agents]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.arguments[maven-plugin#integration-tests.start-goal.parameter-details.arguments]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.classes-directory[maven-plugin#integration-tests.start-goal.parameter-details.classes-directory]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.commandline-arguments[maven-plugin#integration-tests.start-goal.parameter-details.commandline-arguments]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.environment-variables[maven-plugin#integration-tests.start-goal.parameter-details.environment-variables]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.exclude-group-ids[maven-plugin#integration-tests.start-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.excludes[maven-plugin#integration-tests.start-goal.parameter-details.excludes]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.includes[maven-plugin#integration-tests.start-goal.parameter-details.includes]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.jmx-name[maven-plugin#integration-tests.start-goal.parameter-details.jmx-name]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.jmx-port[maven-plugin#integration-tests.start-goal.parameter-details.jmx-port]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.jvm-arguments[maven-plugin#integration-tests.start-goal.parameter-details.jvm-arguments]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.main-class[maven-plugin#integration-tests.start-goal.parameter-details.main-class]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.max-attempts[maven-plugin#integration-tests.start-goal.parameter-details.max-attempts]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.noverify[maven-plugin#integration-tests.start-goal.parameter-details.noverify]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.profiles[maven-plugin#integration-tests.start-goal.parameter-details.profiles]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.skip[maven-plugin#integration-tests.start-goal.parameter-details.skip]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.system-property-variables[maven-plugin#integration-tests.start-goal.parameter-details.system-property-variables]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.use-test-classpath[maven-plugin#integration-tests.start-goal.parameter-details.use-test-classpath]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.wait[maven-plugin#integration-tests.start-goal.parameter-details.wait]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details.working-directory[maven-plugin#integration-tests.start-goal.parameter-details.working-directory]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.parameter-details[maven-plugin#integration-tests.start-goal.parameter-details]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal.required-parameters[maven-plugin#integration-tests.start-goal.required-parameters]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.start-goal[maven-plugin#integration-tests.start-goal]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.optional-parameters[maven-plugin#integration-tests.stop-goal.optional-parameters]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details.jmx-name[maven-plugin#integration-tests.stop-goal.parameter-details.jmx-name]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details.jmx-port[maven-plugin#integration-tests.stop-goal.parameter-details.jmx-port]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details.skip[maven-plugin#integration-tests.stop-goal.parameter-details.skip]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal.parameter-details[maven-plugin#integration-tests.stop-goal.parameter-details]\n* xref:maven-plugin:integration-tests.adoc#integration-tests.stop-goal[maven-plugin#integration-tests.stop-goal]\n* xref:maven-plugin:integration-tests.adoc#integration-tests[maven-plugin#integration-tests]\n* xref:maven-plugin:packaging.adoc#packaging.examples.custom-classifier[maven-plugin#packaging.examples.custom-classifier]\n* xref:maven-plugin:packaging.adoc#packaging.examples.custom-layers-configuration[maven-plugin#packaging.examples.custom-layers-configuration]\n* xref:maven-plugin:packaging.adoc#packaging.examples.custom-layout[maven-plugin#packaging.examples.custom-layout]\n* xref:maven-plugin:packaging.adoc#packaging.examples.custom-name[maven-plugin#packaging.examples.custom-name]\n* xref:maven-plugin:packaging.adoc#packaging.examples.exclude-dependency[maven-plugin#packaging.examples.exclude-dependency]\n* xref:maven-plugin:packaging.adoc#packaging.examples.layered-archive-tools[maven-plugin#packaging.examples.layered-archive-tools]\n* xref:maven-plugin:packaging.adoc#packaging.examples.local-artifact[maven-plugin#packaging.examples.local-artifact]\n* xref:maven-plugin:packaging.adoc#packaging.examples[maven-plugin#packaging.examples]\n* xref:maven-plugin:packaging.adoc#packaging.layers.configuration[maven-plugin#packaging.layers.configuration]\n* xref:maven-plugin:packaging.adoc#packaging.layers[maven-plugin#packaging.layers]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.optional-parameters[maven-plugin#packaging.repackage-goal.optional-parameters]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.attach[maven-plugin#packaging.repackage-goal.parameter-details.attach]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.classifier[maven-plugin#packaging.repackage-goal.parameter-details.classifier]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.exclude-devtools[maven-plugin#packaging.repackage-goal.parameter-details.exclude-devtools]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.exclude-docker-compose[maven-plugin#packaging.repackage-goal.parameter-details.exclude-docker-compose]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.exclude-group-ids[maven-plugin#packaging.repackage-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.excludes[maven-plugin#packaging.repackage-goal.parameter-details.excludes]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.include-system-scope[maven-plugin#packaging.repackage-goal.parameter-details.include-system-scope]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.include-tools[maven-plugin#packaging.repackage-goal.parameter-details.include-tools]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.includes[maven-plugin#packaging.repackage-goal.parameter-details.includes]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layers[maven-plugin#packaging.repackage-goal.parameter-details.layers]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layout-factory[maven-plugin#packaging.repackage-goal.parameter-details.layout-factory]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.layout[maven-plugin#packaging.repackage-goal.parameter-details.layout]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.main-class[maven-plugin#packaging.repackage-goal.parameter-details.main-class]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.output-directory[maven-plugin#packaging.repackage-goal.parameter-details.output-directory]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.output-timestamp[maven-plugin#packaging.repackage-goal.parameter-details.output-timestamp]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.requires-unpack[maven-plugin#packaging.repackage-goal.parameter-details.requires-unpack]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details.skip[maven-plugin#packaging.repackage-goal.parameter-details.skip]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.parameter-details[maven-plugin#packaging.repackage-goal.parameter-details]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal.required-parameters[maven-plugin#packaging.repackage-goal.required-parameters]\n* xref:maven-plugin:packaging.adoc#packaging.repackage-goal[maven-plugin#packaging.repackage-goal]\n* xref:maven-plugin:packaging.adoc#packaging[maven-plugin#packaging]\n* xref:maven-plugin:run.adoc#run.examples.debug[maven-plugin#run.examples.debug]\n* xref:maven-plugin:run.adoc#run.examples.environment-variables[maven-plugin#run.examples.environment-variables]\n* xref:maven-plugin:run.adoc#run.examples.specify-active-profiles[maven-plugin#run.examples.specify-active-profiles]\n* xref:maven-plugin:run.adoc#run.examples.system-properties[maven-plugin#run.examples.system-properties]\n* xref:maven-plugin:run.adoc#run.examples.using-application-arguments[maven-plugin#run.examples.using-application-arguments]\n* xref:maven-plugin:run.adoc#run.examples[maven-plugin#run.examples]\n* xref:maven-plugin:run.adoc#run.run-goal.optional-parameters[maven-plugin#run.run-goal.optional-parameters]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.add-resources[maven-plugin#run.run-goal.parameter-details.add-resources]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.additional-classpath-elements[maven-plugin#run.run-goal.parameter-details.additional-classpath-elements]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.additional-classpath-elements[maven-plugin#run.run-goal.parameter-details.directories]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.agents[maven-plugin#run.run-goal.parameter-details.agents]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.arguments[maven-plugin#run.run-goal.parameter-details.arguments]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.classes-directory[maven-plugin#run.run-goal.parameter-details.classes-directory]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.commandline-arguments[maven-plugin#run.run-goal.parameter-details.commandline-arguments]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.environment-variables[maven-plugin#run.run-goal.parameter-details.environment-variables]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.exclude-group-ids[maven-plugin#run.run-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.excludes[maven-plugin#run.run-goal.parameter-details.excludes]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.includes[maven-plugin#run.run-goal.parameter-details.includes]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.jvm-arguments[maven-plugin#run.run-goal.parameter-details.jvm-arguments]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.main-class[maven-plugin#run.run-goal.parameter-details.main-class]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.noverify[maven-plugin#run.run-goal.parameter-details.noverify]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.optimized-launch[maven-plugin#run.run-goal.parameter-details.optimized-launch]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.profiles[maven-plugin#run.run-goal.parameter-details.profiles]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.skip[maven-plugin#run.run-goal.parameter-details.skip]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.system-property-variables[maven-plugin#run.run-goal.parameter-details.system-property-variables]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.use-test-classpath[maven-plugin#run.run-goal.parameter-details.use-test-classpath]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details.working-directory[maven-plugin#run.run-goal.parameter-details.working-directory]\n* xref:maven-plugin:run.adoc#run.run-goal.parameter-details[maven-plugin#run.run-goal.parameter-details]\n* xref:maven-plugin:run.adoc#run.run-goal.required-parameters[maven-plugin#run.run-goal.required-parameters]\n* xref:maven-plugin:run.adoc#run.run-goal[maven-plugin#run.run-goal]\n* xref:maven-plugin:run.adoc#run.test-run-goal.optional-parameters[maven-plugin#run.test-run-goal.optional-parameters]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.add-resources[maven-plugin#run.test-run-goal.parameter-details.add-resources]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.additional-classpath-elements[maven-plugin#run.test-run-goal.parameter-details.additional-classpath-elements]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.additional-classpath-elements[maven-plugin#run.test-run-goal.parameter-details.directories]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.agents[maven-plugin#run.test-run-goal.parameter-details.agents]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.arguments[maven-plugin#run.test-run-goal.parameter-details.arguments]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.classes-directory[maven-plugin#run.test-run-goal.parameter-details.classes-directory]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.commandline-arguments[maven-plugin#run.test-run-goal.parameter-details.commandline-arguments]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.environment-variables[maven-plugin#run.test-run-goal.parameter-details.environment-variables]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.exclude-group-ids[maven-plugin#run.test-run-goal.parameter-details.exclude-group-ids]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.excludes[maven-plugin#run.test-run-goal.parameter-details.excludes]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.includes[maven-plugin#run.test-run-goal.parameter-details.includes]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.jvm-arguments[maven-plugin#run.test-run-goal.parameter-details.jvm-arguments]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.main-class[maven-plugin#run.test-run-goal.parameter-details.main-class]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.noverify[maven-plugin#run.test-run-goal.parameter-details.noverify]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.optimized-launch[maven-plugin#run.test-run-goal.parameter-details.optimized-launch]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.profiles[maven-plugin#run.test-run-goal.parameter-details.profiles]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.skip[maven-plugin#run.test-run-goal.parameter-details.skip]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.system-property-variables[maven-plugin#run.test-run-goal.parameter-details.system-property-variables]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.test-classes-directory[maven-plugin#run.test-run-goal.parameter-details.test-classes-directory]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details.working-directory[maven-plugin#run.test-run-goal.parameter-details.working-directory]\n* xref:maven-plugin:run.adoc#run.test-run-goal.parameter-details[maven-plugin#run.test-run-goal.parameter-details]\n* xref:maven-plugin:run.adoc#run.test-run-goal.required-parameters[maven-plugin#run.test-run-goal.required-parameters]\n* xref:maven-plugin:run.adoc#run.test-run-goal[maven-plugin#run.test-run-goal]\n* xref:maven-plugin:run.adoc#run[maven-plugin#run]\n* xref:maven-plugin:using.adoc#using.import[maven-plugin#using.import]\n* xref:maven-plugin:using.adoc#using.overriding-command-line[maven-plugin#using.overriding-command-line]\n* xref:maven-plugin:using.adoc#using.parent-pom[maven-plugin#using.parent-pom]\n* xref:maven-plugin:using.adoc#using[maven-plugin#using]\n* xref:reference:actuator/auditing.adoc#actuator.auditing.custom[#actuator.auditing.custom]\n* xref:reference:actuator/auditing.adoc#actuator.auditing.custom[#production-ready-auditing-custom]\n* xref:reference:actuator/auditing.adoc#actuator.auditing[#actuator.auditing]\n* xref:reference:actuator/auditing.adoc#actuator.auditing[#production-ready-auditing]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.custom-context-path[#actuator.cloud-foundry.custom-context-path]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.custom-context-path[#production-ready-custom-context-path]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.disable[#actuator.cloud-foundry.disable]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.disable[#production-ready-cloudfoundry-disable]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.ssl[#actuator.cloud-foundry.ssl]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry.ssl[#production-ready-cloudfoundry-ssl]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#actuator.cloud-foundry]\n* xref:reference:actuator/cloud-foundry.adoc#actuator.cloud-foundry[#production-ready-cloudfoundry]\n* xref:reference:actuator/enabling.adoc#actuator.enabling[#actuator.enabling]\n* xref:reference:actuator/enabling.adoc#actuator.enabling[#production-ready-enabling]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.caching[#actuator.endpoints.caching]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.caching[#production-ready-endpoints-caching]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.controlling-access[#actuator.endpoints.enabling]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.controlling-access[#production-ready-endpoints-enabling-endpoints]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.cors[#actuator.endpoints.cors]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.cors[#production-ready-endpoints-cors]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.exposing[#actuator.endpoints.exposing]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.exposing[#production-ready-endpoints-exposing-endpoints]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[#actuator.endpoints.health.auto-configured-health-indicators]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[#production-ready-health-indicators]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-reactive-health-indicators[#actuator.endpoints.health.auto-configured-reactive-health-indicators]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-reactive-health-indicators[#reactive-health-indicators-autoconfigured]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.datasource[#actuator.endpoints.health.datasource]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.datasource[#production-ready-health-datasource]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.groups[#actuator.endpoints.health.groups]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.groups[#production-ready-health-groups]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.reactive-health-indicators[#actuator.endpoints.health.reactive-health-indicators]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.reactive-health-indicators[#reactive-health-indicators]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.writing-custom-health-indicators[#actuator.endpoints.health.writing-custom-health-indicators]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health.writing-custom-health-indicators[#production-ready-health-indicators-writing]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#actuator.endpoints.health]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.health[#production-ready-health]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.hypermedia[#actuator.endpoints.hypermedia]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.hypermedia[#production-ready-endpoints-hypermedia]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input.conversion[#actuator.endpoints.implementing-custom.input.conversion]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input.conversion[#production-ready-endpoints-custom-input-conversion]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#actuator.endpoints.implementing-custom.input]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.input[#production-ready-endpoints-custom-input]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.consumes-predicates[#actuator.endpoints.implementing-custom.web.consumes-predicates]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.consumes-predicates[#production-ready-endpoints-custom-web-predicate-consumes]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.method-predicates[#actuator.endpoints.implementing-custom.web.method-predicates]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.method-predicates[#production-ready-endpoints-custom-web-predicate-http-method]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.path-predicates[#actuator.endpoints.implementing-custom.web.path-predicates]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.path-predicates[#production-ready-endpoints-custom-web-predicate-path]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.produces-predicates[#actuator.endpoints.implementing-custom.web.produces-predicates]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.produces-predicates[#production-ready-endpoints-custom-web-predicate-produces]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.range-requests[#actuator.endpoints.implementing-custom.web.range-requests]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.range-requests[#production-ready-endpoints-custom-web-range-requests]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.request-predicates[#actuator.endpoints.implementing-custom.web.request-predicates]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.request-predicates[#production-ready-endpoints-custom-web-predicate]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.response-status[#actuator.endpoints.implementing-custom.web.response-status]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.response-status[#production-ready-endpoints-custom-web-response-status]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.security[#actuator.endpoints.implementing-custom.web.security]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web.security[#production-ready-endpoints-custom-web-security]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#actuator.endpoints.implementing-custom.web]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom.web[#production-ready-endpoints-custom-web]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#actuator.endpoints.implementing-custom]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.implementing-custom[#production-ready-endpoints-custom]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.auto-configured-info-contributors[#actuator.endpoints.info.auto-configured-info-contributors]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.auto-configured-info-contributors[#production-ready-application-info-autoconfigure]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.build-information[#actuator.endpoints.info.build-information]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.build-information[#production-ready-application-info-build]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.custom-application-information[#actuator.endpoints.info.custom-application-information]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.custom-application-information[#production-ready-application-info-env]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.git-commit-information[#actuator.endpoints.info.git-commit-information]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.git-commit-information[#production-ready-application-info-git]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.java-information[#actuator.endpoints.info.java-information]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.os-information[#actuator.endpoints.info.os-information]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.process-information[#actuator.endpoints.info.process-information]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.writing-custom-info-contributors[#actuator.endpoints.info.writing-custom-info-contributors]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info.writing-custom-info-contributors[#production-ready-application-info-custom]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#actuator.endpoints.info]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.info[#production-ready-application-info]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.external-state[#actuator.endpoints.kubernetes-probes.external-state]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.external-state[#production-ready-kubernetes-probes-external-state]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[#actuator.endpoints.kubernetes-probes.lifecycle]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[#production-ready-kubernetes-probes-lifecycle]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#actuator.endpoints.kubernetes-probes]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[#production-ready-kubernetes-probes]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#actuator.endpoints.sanitization]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto-sanitize-sensible-values]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto-sanitize-sensitive-values]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sanitization[#howto.actuator.sanitize-sensitive-values]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom.additional[#actuator.endpoints.sbom.additional]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom.other-formats[#actuator.endpoints.sbom.other-formats]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.sbom[#actuator.endpoints.sbom]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#actuator.endpoints.security.csrf]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#boot-features-security-csrf]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security.csrf[#features.security.actuator.csrf]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#actuator.endpoints.security]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#boot-features-security-actuator]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints.security[#production-ready-endpoints-security]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#actuator.endpoints]\n* xref:reference:actuator/endpoints.adoc#actuator.endpoints[#production-ready-endpoints]\n* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#actuator.http-exchanges.custom]\n* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#actuator.tracing.custom]\n* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges.custom[#production-ready-http-tracing-custom]\n* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.http-exchanges]\n* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#actuator.tracing]\n* xref:reference:actuator/http-exchanges.adoc#actuator.http-exchanges[#production-ready-http-tracing]\n* xref:reference:actuator/index.adoc#actuator[#actuator]\n* xref:reference:actuator/index.adoc#actuator[#production-ready]\n* xref:reference:actuator/index.adoc[#actuator]\n* xref:reference:actuator/index.adoc[actuator]\n* xref:reference:actuator/jmx.adoc#actuator.jmx.custom-mbean-names[#actuator.jmx.custom-mbean-names]\n* xref:reference:actuator/jmx.adoc#actuator.jmx.custom-mbean-names[#production-ready-custom-mbean-names]\n* xref:reference:actuator/jmx.adoc#actuator.jmx.disable-jmx-endpoints[#actuator.jmx.disable-jmx-endpoints]\n* xref:reference:actuator/jmx.adoc#actuator.jmx.disable-jmx-endpoints[#production-ready-disable-jmx-endpoints]\n* xref:reference:actuator/jmx.adoc#actuator.jmx[#actuator.jmx]\n* xref:reference:actuator/jmx.adoc#actuator.jmx[#boot-features-jmx]\n* xref:reference:actuator/jmx.adoc#actuator.jmx[#production-ready-jmx]\n* xref:reference:actuator/loggers.adoc#actuator.loggers.configure[#actuator.loggers.configure]\n* xref:reference:actuator/loggers.adoc#actuator.loggers.configure[#production-ready-logger-configuration]\n* xref:reference:actuator/loggers.adoc#actuator.loggers[#actuator.loggers]\n* xref:reference:actuator/loggers.adoc#actuator.loggers[#production-ready-loggers]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.common-tags[#actuator.metrics.customizing.common-tags]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.common-tags[#production-ready-metrics-common-tags]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.per-meter-properties[#actuator.metrics.customizing.per-meter-properties]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing.per-meter-properties[#production-ready-metrics-per-meter-properties]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#actuator.metrics.customizing]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.customizing[#production-ready-metrics-customizing]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.endpoint[#actuator.metrics.endpoint]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.endpoint[#production-ready-metrics-endpoint]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.appoptics[#actuator.metrics.export.appoptics]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.appoptics[#production-ready-metrics-export-appoptics]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.atlas[#actuator.metrics.export.atlas]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.atlas[#production-ready-metrics-export-atlas]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.datadog[#actuator.metrics.export.datadog]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.datadog[#production-ready-metrics-export-datadog]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v1-api[#actuator.metrics.export.dynatrace.v1-api]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api.auto-config[#actuator.metrics.export.dynatrace.v2-api.auto-config]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api.manual-config[#actuator.metrics.export.dynatrace.v2-api.manual-config]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.v2-api[#actuator.metrics.export.dynatrace.v2-api]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace.version-independent-settings[#actuator.metrics.export.dynatrace.version-independent-settings]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#actuator.metrics.export.dynatrace]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.dynatrace[#production-ready-metrics-export-dynatrace]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.elastic[#actuator.metrics.export.elastic]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.elastic[#production-ready-metrics-export-elastic]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.ganglia[#actuator.metrics.export.ganglia]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.ganglia[#production-ready-metrics-export-ganglia]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.graphite[#actuator.metrics.export.graphite]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.graphite[#production-ready-metrics-export-graphite]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.humio[#actuator.metrics.export.humio]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.humio[#production-ready-metrics-export-humio]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.influx[#actuator.metrics.export.influx]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.influx[#production-ready-metrics-export-influx]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.jmx[#actuator.metrics.export.jmx]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.jmx[#production-ready-metrics-export-jmx]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.kairos[#actuator.metrics.export.kairos]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.kairos[#production-ready-metrics-export-kairos]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.newrelic[#actuator.metrics.export.newrelic]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.newrelic[#production-ready-metrics-export-newrelic]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.otlp[#actuator.metrics.export.otlp]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.prometheus[#actuator.metrics.export.prometheus]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.prometheus[#production-ready-metrics-export-prometheus]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.simple[#actuator.metrics.export.simple]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.simple[#production-ready-metrics-export-simple]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#actuator.metrics.export.stackdriver]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.stackdriver[#production-ready-metrics-export-stackdriver]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#actuator.metrics.export.statsd]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export.statsd[#production-ready-metrics-export-statsd]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#actuator.metrics.export]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.export[#production-ready-metrics-export]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#actuator.metrics.getting-started]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.getting-started[#production-ready-metrics-getting-started]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.micrometer-observation[#actuator.metrics.micrometer-observation]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.registering-custom[#actuator.metrics.registering-custom]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.registering-custom[#production-ready-metrics-custom]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.application-startup[#actuator.metrics.supported.application-startup]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.cache[#actuator.metrics.supported.cache]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.cache[#production-ready-metrics-cache]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.hibernate[#actuator.metrics.supported.hibernate]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.hibernate[#production-ready-metrics-hibernate]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#actuator.metrics.supported.http-clients]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.http-clients[#production-ready-metrics-http-clients]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#actuator.metrics.supported.jdbc]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jdbc[#production-ready-metrics-jdbc]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#actuator.metrics.supported.jersey]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jersey[#production-ready-metrics-jersey-server]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jetty[#actuator.metrics.supported.jetty]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jms[#actuator.metrics.supported.jms]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#actuator.metrics.supported.jvm]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.jvm[#production-ready-metrics-jvm]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.kafka[#actuator.metrics.supported.kafka]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.kafka[#production-ready-metrics-kafka]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.logger[#actuator.metrics.supported.logger]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.logger[#production-ready-metrics-logger]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.command[#actuator.metrics.supported.mongodb.command]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.command[#production-ready-metrics-mongodb-command]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.connection-pool[#actuator.metrics.supported.mongodb.connection-pool]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb.connection-pool[#production-ready-metrics-mongodb-connectionpool]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#actuator.metrics.supported.mongodb]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.mongodb[#production-ready-metrics-mongodb]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.rabbitmq[#actuator.metrics.supported.rabbitmq]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.rabbitmq[#production-ready-metrics-rabbitmq]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.redis[#actuator.metrics.supported.redis]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-batch[#actuator.metrics.supported.spring-batch]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[#actuator.metrics.supported.spring-data-repository]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[#production-ready-metrics-data-repository]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-graphql[#actuator.metrics.supported.spring-graphql]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-integration[#actuator.metrics.supported.spring-integration]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-integration[#production-ready-metrics-integration]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[#actuator.metrics.supported.spring-mvc]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[#production-ready-metrics-spring-mvc]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[#actuator.metrics.supported.spring-webflux]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[#production-ready-metrics-web-flux]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.system[#actuator.metrics.supported.system]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.system[#production-ready-metrics-system]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tasks[#actuator.metrics.supported.tasks]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tomcat[#actuator.metrics.supported.tomcat]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported.tomcat[#production-ready-metrics-tomcat]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#actuator.metrics.supported]\n* xref:reference:actuator/metrics.adoc#actuator.metrics.supported[#production-ready-metrics-meter]\n* xref:reference:actuator/metrics.adoc#actuator.metrics[#actuator.metrics]\n* xref:reference:actuator/metrics.adoc#actuator.metrics[#production-ready-metrics]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-address[#actuator.monitoring.customizing-management-server-address]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-address[#production-ready-customizing-management-server-address]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-context-path[#actuator.monitoring.customizing-management-server-context-path]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-context-path[#production-ready-customizing-management-server-context-path]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[#actuator.monitoring.customizing-management-server-port]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[#production-ready-customizing-management-server-port]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.disabling-http-endpoints[#actuator.monitoring.disabling-http-endpoints]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.disabling-http-endpoints[#production-ready-disabling-http-endpoints]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.management-specific-ssl[#actuator.monitoring.management-specific-ssl]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring.management-specific-ssl[#production-ready-management-specific-ssl]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#actuator.monitoring]\n* xref:reference:actuator/monitoring.adoc#actuator.monitoring[#production-ready-monitoring]\n* xref:reference:actuator/observability.adoc#actuator.observability.annotations[#actuator.metrics.supported.timed-annotation]\n* xref:reference:actuator/observability.adoc#actuator.observability.annotations[#actuator.observability.annotations]\n* xref:reference:actuator/observability.adoc#actuator.observability.annotations[#production-ready-metrics-timed-annotation]\n* xref:reference:actuator/observability.adoc#actuator.observability.common-tags[#actuator.observability.common-tags]\n* xref:reference:actuator/observability.adoc#actuator.observability.opentelemetry[#actuator.observability.opentelemetry]\n* xref:reference:actuator/observability.adoc#actuator.observability.preventing-observations[#actuator.observability.preventing-observations]\n* xref:reference:actuator/observability.adoc#actuator.observability[#actuator.observability]\n* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[#actuator.process-monitoring.configuration]\n* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[#production-ready-process-monitoring-configuration]\n* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[#actuator.process-monitoring.programmatically]\n* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[#production-ready-process-monitoring-programmatically]\n* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#actuator.process-monitoring]\n* xref:reference:actuator/process-monitoring.adoc#actuator.process-monitoring[#production-ready-process-monitoring]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.baggage[#actuator.micrometer-tracing.baggage]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.creating-spans[#actuator.micrometer-tracing.creating-spans]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.getting-started[#actuator.micrometer-tracing.getting-started]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.logging[#actuator.micrometer-tracing.logging]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.micrometer-observation[#actuator.micrometer-tracing.micrometer-observation]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.propagating-traces[#actuator.micrometer-tracing.propagating-traces]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tests[#actuator.micrometer-tracing.tests]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.brave-zipkin[#actuator.micrometer-tracing.tracer-implementations.brave-zipkin]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-otlp[#actuator.micrometer-tracing.tracer-implementations.otel-otlp]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations.otel-zipkin[#actuator.micrometer-tracing.tracer-implementations.otel-zipkin]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracer-implementations[#actuator.micrometer-tracing.tracer-implementations]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.tracers[#actuator.micrometer-tracing.tracers]\n* xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing[#actuator.micrometer-tracing]\n* xref:reference:data/index.adoc#data[#data]\n* xref:reference:data/index.adoc[#data]\n* xref:reference:data/index.adoc[data]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#boot-features-connecting-to-cassandra]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#data.nosql.cassandra.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra.connecting[#features.nosql.cassandra.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#boot-features-spring-data-cassandra-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#data.nosql.cassandra.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra.repositories[#features.nosql.cassandra.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra[#boot-features-cassandra]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra[#data.nosql.cassandra]\n* xref:reference:data/nosql.adoc#data.nosql.cassandra[#features.nosql.cassandra]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#boot-features-connecting-to-couchbase]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#data.nosql.couchbase.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase.connecting[#features.nosql.couchbase.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#boot-features-spring-data-couchbase-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#data.nosql.couchbase.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase.repositories[#features.nosql.couchbase.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase[#boot-features-couchbase]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase[#data.nosql.couchbase]\n* xref:reference:data/nosql.adoc#data.nosql.couchbase[#features.nosql.couchbase]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.javaapiclient[#data.nosql.elasticsearch.connecting-using-rest.javaapiclient]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[#data.nosql.elasticsearch.connecting-using-rest.reactiveclient]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[#data.nosql.elasticsearch.connecting-using-rest.webclient]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.restclient[#data.nosql.elasticsearch.connecting-using-rest.restclient]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#boot-features-connecting-to-elasticsearch-rest]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-reactive-rest]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#data.nosql.elasticsearch.connecting-using-rest]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest[#features.nosql.elasticsearch.connecting-using-rest]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#boot-features-connecting-to-elasticsearch-spring-data]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#data.nosql.elasticsearch.connecting-using-spring-data]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-spring-data[#features.nosql.elasticsearch.connecting-using-spring-data]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#boot-features-spring-data-elasticsearch-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#data.nosql.elasticsearch.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch.repositories[#features.nosql.elasticsearch.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#boot-features-connecting-to-elasticsearch-reactive-rest]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#boot-features-elasticsearch]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#data.nosql.elasticsearch]\n* xref:reference:data/nosql.adoc#data.nosql.elasticsearch[#features.nosql.elasticsearch]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#boot-features-ldap-connecting]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#data.nosql.ldap.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.connecting[#features.nosql.ldap.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#boot-features-ldap-embedded]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#data.nosql.ldap.embedded]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.embedded[#features.nosql.ldap.embedded]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#boot-features-ldap-spring-data-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#data.nosql.ldap.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.ldap.repositories[#features.nosql.ldap.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.ldap[#boot-features-ldap]\n* xref:reference:data/nosql.adoc#data.nosql.ldap[#data.nosql.ldap]\n* xref:reference:data/nosql.adoc#data.nosql.ldap[#features.nosql.ldap]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#boot-features-connecting-to-mongodb]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#data.nosql.mongodb.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.connecting[#features.nosql.mongodb.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#boot-features-spring-data-mongo-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#boot-features-spring-data-mongodb-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#data.nosql.mongodb.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.repositories[#features.nosql.mongodb.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#boot-features-mongo-template]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#data.nosql.mongodb.template]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb.template[#features.nosql.mongodb.template]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb[#boot-features-mongodb]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb[#data.nosql.mongodb]\n* xref:reference:data/nosql.adoc#data.nosql.mongodb[#features.nosql.mongodb]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#boot-features-connecting-to-neo4j]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#data.nosql.neo4j.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j.connecting[#features.nosql.neo4j.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#boot-features-spring-data-neo4j-repositories]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#data.nosql.neo4j.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j.repositories[#features.nosql.neo4j.repositories]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j[#boot-features-neo4j]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j[#data.nosql.neo4j]\n* xref:reference:data/nosql.adoc#data.nosql.neo4j[#features.nosql.neo4j]\n* xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#boot-features-connecting-to-redis]\n* xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#data.nosql.redis.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.redis.connecting[#features.nosql.redis.connecting]\n* xref:reference:data/nosql.adoc#data.nosql.redis[#boot-features-redis]\n* xref:reference:data/nosql.adoc#data.nosql.redis[#data.nosql.redis]\n* xref:reference:data/nosql.adoc#data.nosql.redis[#features.nosql.redis]\n* xref:reference:data/nosql.adoc#data.nosql[#boot-features-nosql]\n* xref:reference:data/nosql.adoc#data.nosql[#data.nosql]\n* xref:reference:data/nosql.adoc#data.nosql[#features.nosql]\n* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#boot-features-connect-to-production-database-configuration]\n* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#data.sql.datasource.configuration]\n* xref:reference:data/sql.adoc#data.sql.datasource.configuration[#features.sql.datasource.configuration]\n* xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#boot-features-connect-to-production-database-connection-pool]\n* xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#data.sql.datasource.connection-pool]\n* xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[#features.sql.datasource.connection-pool]\n* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#boot-features-embedded-database-support]\n* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#data.sql.datasource.embedded]\n* xref:reference:data/sql.adoc#data.sql.datasource.embedded[#features.sql.datasource.embedded]\n* xref:reference:data/sql.adoc#data.sql.datasource.jndi[#boot-features-connecting-to-a-jndi-datasource]\n* xref:reference:data/sql.adoc#data.sql.datasource.jndi[#data.sql.datasource.jndi]\n* xref:reference:data/sql.adoc#data.sql.datasource.jndi[#features.sql.datasource.jndi]\n* xref:reference:data/sql.adoc#data.sql.datasource.production[#boot-features-connect-to-production-database]\n* xref:reference:data/sql.adoc#data.sql.datasource.production[#data.sql.datasource.production]\n* xref:reference:data/sql.adoc#data.sql.datasource.production[#features.sql.datasource.production]\n* xref:reference:data/sql.adoc#data.sql.datasource[#boot-features-configure-datasource]\n* xref:reference:data/sql.adoc#data.sql.datasource[#data.sql.datasource]\n* xref:reference:data/sql.adoc#data.sql.datasource[#features.sql.datasource]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#boot-features-sql-h2-console-custom-path]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#data.sql.h2-web-console.custom-path]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console.custom-path[#features.sql.h2-web-console.custom-path]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console.spring-security[#data.sql.h2-web-console.spring-security]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console[#boot-features-sql-h2-console]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console[#data.sql.h2-web-console]\n* xref:reference:data/sql.adoc#data.sql.h2-web-console[#features.sql.h2-web-console]\n* xref:reference:data/sql.adoc#data.sql.jdbc-client[#data.sql.jdbc-client]\n* xref:reference:data/sql.adoc#data.sql.jdbc-template[#boot-features-using-jdbc-template]\n* xref:reference:data/sql.adoc#data.sql.jdbc-template[#data.sql.jdbc-template]\n* xref:reference:data/sql.adoc#data.sql.jdbc-template[#features.sql.jdbc-template]\n* xref:reference:data/sql.adoc#data.sql.jdbc[#boot-features-data-jdbc]\n* xref:reference:data/sql.adoc#data.sql.jdbc[#data.sql.jdbc]\n* xref:reference:data/sql.adoc#data.sql.jdbc[#features.sql.jdbc]\n* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#boot-features-jooq-codegen]\n* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#data.sql.jooq.codegen]\n* xref:reference:data/sql.adoc#data.sql.jooq.codegen[#features.sql.jooq.codegen]\n* xref:reference:data/sql.adoc#data.sql.jooq.customizing[#boot-features-jooq-customizing]\n* xref:reference:data/sql.adoc#data.sql.jooq.customizing[#data.sql.jooq.customizing]\n* xref:reference:data/sql.adoc#data.sql.jooq.customizing[#features.sql.jooq.customizing]\n* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#boot-features-jooq-dslcontext]\n* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#data.sql.jooq.dslcontext]\n* xref:reference:data/sql.adoc#data.sql.jooq.dslcontext[#features.sql.jooq.dslcontext]\n* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#boot-features-jooq-sqldialect]\n* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#data.sql.jooq.sqldialect]\n* xref:reference:data/sql.adoc#data.sql.jooq.sqldialect[#features.sql.jooq.sqldialect]\n* xref:reference:data/sql.adoc#data.sql.jooq[#boot-features-jooq]\n* xref:reference:data/sql.adoc#data.sql.jooq[#data.sql.jooq]\n* xref:reference:data/sql.adoc#data.sql.jooq[#features.sql.jooq]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#boot-features-creating-and-dropping-jpa-databases]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#data.sql.jpa-and-spring-data.creating-and-dropping]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.creating-and-dropping[#features.sql.jpa-and-spring-data.creating-and-dropping]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#boot-features-entity-classes]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#data.sql.jpa-and-spring-data.entity-classes]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.entity-classes[#features.sql.jpa-and-spring-data.entity-classes]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.envers-repositories[#data.sql.jpa-and-spring-data.envers-repositories]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.envers-repositories[#features.sql.jpa-and-spring-data.envers-repositories]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#boot-features-jpa-in-web-environment]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#data.sql.jpa-and-spring-data.open-entity-manager-in-view]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.open-entity-manager-in-view[#features.sql.jpa-and-spring-data.open-entity-manager-in-view]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#boot-features-spring-data-jpa-repositories]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#data.sql.jpa-and-spring-data.repositories]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data.repositories[#features.sql.jpa-and-spring-data.repositories]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#boot-features-jpa-and-spring-data]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#data.sql.jpa-and-spring-data]\n* xref:reference:data/sql.adoc#data.sql.jpa-and-spring-data[#features.sql.jpa-and-spring-data]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#boot-features-r2dbc-embedded-database]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#data.sql.r2dbc.embedded]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.embedded[#features.sql.r2dbc.embedded]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#boot-features-spring-data-r2dbc-repositories]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#data.sql.r2dbc.repositories]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.repositories[#features.sql.r2dbc.repositories]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#boot-features-r2dbc-using-database-client]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#data.sql.r2dbc.using-database-client]\n* xref:reference:data/sql.adoc#data.sql.r2dbc.using-database-client[#features.sql.r2dbc.using-database-client]\n* xref:reference:data/sql.adoc#data.sql.r2dbc[#boot-features-r2dbc]\n* xref:reference:data/sql.adoc#data.sql.r2dbc[#data.sql.r2dbc]\n* xref:reference:data/sql.adoc#data.sql.r2dbc[#features.sql.r2dbc]\n* xref:reference:data/sql.adoc#data.sql[#boot-features-sql]\n* xref:reference:data/sql.adoc#data.sql[#data.sql]\n* xref:reference:data/sql.adoc#data.sql[#features.sql]\n* xref:reference:features/aop.adoc#features.aop[#features.aop]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.custom-images[#features.docker-compose.custom-images]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.lifecycle[#features.docker-compose.lifecycle]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.prerequisites[#features.docker-compose.prerequisites]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.profiles[#features.docker-compose.profiles]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.readiness[#features.docker-compose.readiness]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.service-connections[#features.docker-compose.service-connections]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.skipping[#features.docker-compose.skipping]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose.specific-file[#features.docker-compose.specific-file]\n* xref:reference:features/dev-services.adoc#features.dev-services.docker-compose[#features.docker-compose]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testcontainers.at-development-time.devtools]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.devtools[#features.testing.testcontainers.at-development-time.devtools]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testcontainers.at-development-time.dynamic-properties]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.dynamic-properties[#features.testing.testcontainers.at-development-time.dynamic-properties]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testcontainers.at-development-time.importing-container-declarations]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time.importing-container-declarations[#features.testing.testcontainers.at-development-time.importing-container-declarations]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testcontainers.at-development-time]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers.at-development-time[#features.testing.testcontainers.at-development-time]\n* xref:reference:features/dev-services.adoc#features.dev-services.testcontainers[#features.testcontainers]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[#boot-features-bean-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[#features.developing-auto-configuration.condition-annotations.bean-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[#boot-features-class-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[#features.developing-auto-configuration.condition-annotations.class-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[#boot-features-property-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[#features.developing-auto-configuration.condition-annotations.property-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[#boot-features-resource-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[#features.developing-auto-configuration.condition-annotations.resource-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[#boot-features-spel-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[#features.developing-auto-configuration.condition-annotations.spel-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[#boot-features-web-application-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[#features.developing-auto-configuration.condition-annotations.web-application-conditions]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#boot-features-condition-annotations]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations[#features.developing-auto-configuration.condition-annotations]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.autoconfigure-module[#boot-features-custom-starter-module-autoconfigure]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.autoconfigure-module[#features.developing-auto-configuration.custom-starter.autoconfigure-module]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.configuration-keys[#boot-features-custom-starter-configuration-keys]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.configuration-keys[#features.developing-auto-configuration.custom-starter.configuration-keys]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.naming[#boot-features-custom-starter-naming]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.naming[#features.developing-auto-configuration.custom-starter.naming]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.starter-module[#boot-features-custom-starter-module-starter]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter.starter-module[#features.developing-auto-configuration.custom-starter.starter-module]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#boot-features-custom-starter]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[#features.developing-auto-configuration.custom-starter]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.locating-auto-configuration-candidates[#boot-features-locating-auto-configuration-candidates]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.locating-auto-configuration-candidates[#features.developing-auto-configuration.locating-auto-configuration-candidates]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.overriding-classpath[#boot-features-test-autoconfig-overriding-classpath]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.overriding-classpath[#features.developing-auto-configuration.testing.overriding-classpath]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.simulating-a-web-context[#boot-features-test-autoconfig-simulating-web-context]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing.simulating-a-web-context[#features.developing-auto-configuration.testing.simulating-a-web-context]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#boot-features-test-autoconfig]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.testing[#features.developing-auto-configuration.testing]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.understanding-auto-configured-beans[#boot-features-understanding-auto-configured-beans]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration.understanding-auto-configured-beans[#features.developing-auto-configuration.understanding-auto-configured-beans]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#boot-features-developing-auto-configuration]\n* xref:reference:features/developing-auto-configuration.adoc#features.developing-auto-configuration[#features.developing-auto-configuration]\n* xref:reference:features/external-config.adoc#features.external-config.application-json[#boot-features-external-config-application-json]\n* xref:reference:features/external-config.adoc#features.external-config.application-json[#features.external-config.application-json]\n* xref:reference:features/external-config.adoc#features.external-config.command-line-args[#boot-features-external-config-command-line-args]\n* xref:reference:features/external-config.adoc#features.external-config.command-line-args[#features.external-config.command-line-args]\n* xref:reference:features/external-config.adoc#features.external-config.encrypting[#boot-features-encrypting-properties]\n* xref:reference:features/external-config.adoc#features.external-config.encrypting[#features.external-config.encrypting]\n* xref:reference:features/external-config.adoc#features.external-config.files.activation-properties[#boot-features-external-config-file-activation-properties]\n* xref:reference:features/external-config.adoc#features.external-config.files.activation-properties[#features.external-config.files.activation-properties]\n* xref:reference:features/external-config.adoc#features.external-config.files.configtree[#boot-features-external-config-files-configtree]\n* xref:reference:features/external-config.adoc#features.external-config.files.configtree[#features.external-config.files.configtree]\n* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#boot-features-external-config-files-importing-extensionless]\n* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#features.external-config.file.importing-extensionless]\n* xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[#features.external-config.files.importing-extensionless]\n* xref:reference:features/external-config.adoc#features.external-config.files.importing[#boot-features-external-config-files-importing]\n* xref:reference:features/external-config.adoc#features.external-config.files.importing[#features.external-config.files.importing]\n* xref:reference:features/external-config.adoc#features.external-config.files.location-groups[#features.external-config.files.location-groups]\n* xref:reference:features/external-config.adoc#features.external-config.files.multi-document[#boot-features-external-config-files-multi-document]\n* xref:reference:features/external-config.adoc#features.external-config.files.multi-document[#features.external-config.files.multi-document]\n* xref:reference:features/external-config.adoc#features.external-config.files.optional-prefix[#boot-features-external-config-optional-prefix]\n* xref:reference:features/external-config.adoc#features.external-config.files.optional-prefix[#features.external-config.files.optional-prefix]\n* xref:reference:features/external-config.adoc#features.external-config.files.profile-specific[#boot-features-external-config-files-profile-specific]\n* xref:reference:features/external-config.adoc#features.external-config.files.profile-specific[#features.external-config.files.profile-specific]\n* xref:reference:features/external-config.adoc#features.external-config.files.property-placeholders[#boot-features-external-config-placeholders-in-properties]\n* xref:reference:features/external-config.adoc#features.external-config.files.property-placeholders[#features.external-config.files.property-placeholders]\n* xref:reference:features/external-config.adoc#features.external-config.files.wildcard-locations[#boot-features-external-config-files-wildcards]\n* xref:reference:features/external-config.adoc#features.external-config.files.wildcard-locations[#features.external-config.files.wildcard-locations]\n* xref:reference:features/external-config.adoc#features.external-config.files[#boot-features-external-config-files]\n* xref:reference:features/external-config.adoc#features.external-config.files[#features.external-config.files]\n* xref:reference:features/external-config.adoc#features.external-config.random-values[#boot-features-external-config-random-values]\n* xref:reference:features/external-config.adoc#features.external-config.random-values[#features.external-config.random-values]\n* xref:reference:features/external-config.adoc#features.external-config.system-environment[#boot-features-external-config-system-environment]\n* xref:reference:features/external-config.adoc#features.external-config.system-environment[#features.external-config.system-environment]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[#boot-features-external-config-constructor-binding]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[#features.external-config.typesafe-configuration-properties.constructor-binding]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.data-sizes[#boot-features-external-config-conversion-datasize]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.data-sizes[#features.external-config.typesafe-configuration-properties.conversion.data-sizes]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.durations[#boot-features-external-config-conversion-duration]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.durations[#features.external-config.typesafe-configuration-properties.conversion.durations]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.periods[#boot-features-external-config-conversion-period]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.periods[#features.external-config.typesafe-configuration-properties.conversion.periods]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#boot-features-external-config-conversion]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[#features.external-config.typesafe-configuration-properties.conversion]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.enabling-annotated-types[#boot-features-external-config-enabling]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.enabling-annotated-types[#features.external-config.typesafe-configuration-properties.enabling-annotated-types]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.java-bean-binding[#boot-features-external-config-java-bean-binding]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.java-bean-binding[#features.external-config.typesafe-configuration-properties.java-bean-binding]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[#boot-features-external-config-complex-type-merge]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[#features.external-config.typesafe-configuration-properties.merging-complex-types]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.caching[#features.external-config.typesafe-configuration-properties.relaxed-binding.caching]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[#boot-features-external-config-relaxed-binding-from-environment-variables]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps[#boot-features-external-config-relaxed-binding-maps]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps[#features.external-config.typesafe-configuration-properties.relaxed-binding.maps]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#boot-features-external-config-relaxed-binding]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[#features.external-config.typesafe-configuration-properties.relaxed-binding]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[#boot-features-external-config-3rd-party-configuration]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[#features.external-config.typesafe-configuration-properties.third-party-configuration]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.using-annotated-types[#boot-features-external-config-using]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.using-annotated-types[#features.external-config.typesafe-configuration-properties.using-annotated-types]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.validation[#boot-features-external-config-validation]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.validation[#features.external-config.typesafe-configuration-properties.validation]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation.note[#features.external-config.typesafe-configuration-properties.vs-value-annotation.note]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#boot-features-external-config-vs-value]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[#features.external-config.typesafe-configuration-properties.vs-value-annotation]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#boot-features-external-config-typesafe-configuration-properties]\n* xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties[#features.external-config.typesafe-configuration-properties]\n* xref:reference:features/external-config.adoc#features.external-config.yaml.directly-loading[#boot-features-external-config-loading-yaml]\n* xref:reference:features/external-config.adoc#features.external-config.yaml.directly-loading[#features.external-config.yaml.directly-loading]\n* xref:reference:features/external-config.adoc#features.external-config.yaml.mapping-to-properties[#boot-features-external-config-yaml-to-properties]\n* xref:reference:features/external-config.adoc#features.external-config.yaml.mapping-to-properties[#features.external-config.yaml.mapping-to-properties]\n* xref:reference:features/external-config.adoc#features.external-config.yaml[#boot-features-external-config-yaml]\n* xref:reference:features/external-config.adoc#features.external-config.yaml[#features.external-config.yaml]\n* xref:reference:features/external-config.adoc#features.external-config[#boot-features-external-config]\n* xref:reference:features/external-config.adoc#features.external-config[#features.external-config]\n* xref:reference:features/index.adoc#features[#boot-features]\n* xref:reference:features/index.adoc#features[#features]\n* xref:reference:features/index.adoc[#features]\n* xref:reference:features/index.adoc[features]\n* xref:reference:features/internationalization.adoc#features.internationalization[#boot-features-internationalization]\n* xref:reference:features/internationalization.adoc#features.internationalization[#features.internationalization]\n* xref:reference:features/json.adoc#features.json.gson[#boot-features-json-gson]\n* xref:reference:features/json.adoc#features.json.gson[#features.json.gson]\n* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#boot-features-json-components]\n* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#features.developing-web-applications.spring-mvc.json]\n* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#features.json.jackson.custom-serializers-and-deserializers]\n* xref:reference:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[#web.servlet.spring-mvc.json]\n* xref:reference:features/json.adoc#features.json.jackson.mixins[#features.json.jackson.mixins]\n* xref:reference:features/json.adoc#features.json.jackson[#boot-features-json-jackson]\n* xref:reference:features/json.adoc#features.json.jackson[#features.json.jackson]\n* xref:reference:features/json.adoc#features.json.json-b[#boot-features-json-json-b]\n* xref:reference:features/json.adoc#features.json.json-b[#features.json.json-b]\n* xref:reference:features/json.adoc#features.json[#boot-features-json]\n* xref:reference:features/json.adoc#features.json[#features.json]\n* xref:reference:features/kotlin.adoc#features.kotlin.api.extensions[#boot-features-kotlin-api-extensions]\n* xref:reference:features/kotlin.adoc#features.kotlin.api.extensions[#features.kotlin.api.extensions]\n* xref:reference:features/kotlin.adoc#features.kotlin.api.run-application[#boot-features-kotlin-api-runapplication]\n* xref:reference:features/kotlin.adoc#features.kotlin.api.run-application[#features.kotlin.api.run-application]\n* xref:reference:features/kotlin.adoc#features.kotlin.api[#boot-features-kotlin-api]\n* xref:reference:features/kotlin.adoc#features.kotlin.api[#features.kotlin.api]\n* xref:reference:features/kotlin.adoc#features.kotlin.configuration-properties[#boot-features-kotlin-configuration-properties]\n* xref:reference:features/kotlin.adoc#features.kotlin.configuration-properties[#features.kotlin.configuration-properties]\n* xref:reference:features/kotlin.adoc#features.kotlin.dependency-management[#boot-features-kotlin-dependency-management]\n* xref:reference:features/kotlin.adoc#features.kotlin.dependency-management[#features.kotlin.dependency-management]\n* xref:reference:features/kotlin.adoc#features.kotlin.null-safety[#boot-features-kotlin-null-safety]\n* xref:reference:features/kotlin.adoc#features.kotlin.null-safety[#features.kotlin.null-safety]\n* xref:reference:features/kotlin.adoc#features.kotlin.requirements[#boot-features-kotlin-requirements]\n* xref:reference:features/kotlin.adoc#features.kotlin.requirements[#features.kotlin.requirements]\n* xref:reference:features/kotlin.adoc#features.kotlin.resources.examples[#boot-features-kotlin-resources-examples]\n* xref:reference:features/kotlin.adoc#features.kotlin.resources.examples[#features.kotlin.resources.examples]\n* xref:reference:features/kotlin.adoc#features.kotlin.resources.further-reading[#boot-features-kotlin-resources-further-reading]\n* xref:reference:features/kotlin.adoc#features.kotlin.resources.further-reading[#features.kotlin.resources.further-reading]\n* xref:reference:features/kotlin.adoc#features.kotlin.resources[#boot-features-kotlin-resources]\n* xref:reference:features/kotlin.adoc#features.kotlin.resources[#features.kotlin.resources]\n* xref:reference:features/kotlin.adoc#features.kotlin.testing[#boot-features-kotlin-testing]\n* xref:reference:features/kotlin.adoc#features.kotlin.testing[#features.kotlin.testing]\n* xref:reference:features/kotlin.adoc#features.kotlin[#boot-features-kotlin]\n* xref:reference:features/kotlin.adoc#features.kotlin[#features.kotlin]\n* xref:reference:features/logging.adoc#features.logging.console-output.color-coded[#boot-features-logging-color-coded-output]\n* xref:reference:features/logging.adoc#features.logging.console-output.color-coded[#features.logging.console-output.color-coded]\n* xref:reference:features/logging.adoc#features.logging.console-output[#boot-features-logging-console-output]\n* xref:reference:features/logging.adoc#features.logging.console-output[#features.logging.console-output]\n* xref:reference:features/logging.adoc#features.logging.custom-log-configuration[#boot-features-custom-log-configuration]\n* xref:reference:features/logging.adoc#features.logging.custom-log-configuration[#features.logging.custom-log-configuration]\n* xref:reference:features/logging.adoc#features.logging.file-output[#boot-features-logging-file-output]\n* xref:reference:features/logging.adoc#features.logging.file-output[#features.logging.file-output]\n* xref:reference:features/logging.adoc#features.logging.file-rotation[#boot-features-logging-file-rotation]\n* xref:reference:features/logging.adoc#features.logging.file-rotation[#features.logging.file-rotation]\n* xref:reference:features/logging.adoc#features.logging.log-format[#boot-features-logging-format]\n* xref:reference:features/logging.adoc#features.logging.log-format[#features.logging.log-format]\n* xref:reference:features/logging.adoc#features.logging.log-groups[#boot-features-custom-log-groups]\n* xref:reference:features/logging.adoc#features.logging.log-groups[#features.logging.log-groups]\n* xref:reference:features/logging.adoc#features.logging.log-levels[#boot-features-custom-log-levels]\n* xref:reference:features/logging.adoc#features.logging.log-levels[#features.logging.log-levels]\n* xref:reference:features/logging.adoc#features.logging.log4j2-extensions.environment-properties-lookup[#features.logging.log4j2-extensions.environment-properties-lookup]\n* xref:reference:features/logging.adoc#features.logging.log4j2-extensions.environment-property-source[#features.logging.log4j2-extensions.environment-property-source]\n* xref:reference:features/logging.adoc#features.logging.log4j2-extensions.profile-specific[#features.logging.log4j2-extensions.profile-specific]\n* xref:reference:features/logging.adoc#features.logging.log4j2-extensions[#features.logging.log4j2-extensions]\n* xref:reference:features/logging.adoc#features.logging.logback-extensions.environment-properties[#boot-features-logback-environment-properties]\n* xref:reference:features/logging.adoc#features.logging.logback-extensions.environment-properties[#features.logging.logback-extensions.environment-properties]\n* xref:reference:features/logging.adoc#features.logging.logback-extensions.profile-specific[#boot-features-logback-extensions-profile-specific]\n* xref:reference:features/logging.adoc#features.logging.logback-extensions.profile-specific[#features.logging.logback-extensions.profile-specific]\n* xref:reference:features/logging.adoc#features.logging.logback-extensions[#boot-features-logback-extensions]\n* xref:reference:features/logging.adoc#features.logging.logback-extensions[#features.logging.logback-extensions]\n* xref:reference:features/logging.adoc#features.logging.shutdown-hook[#boot-features-log-shutdown-hook]\n* xref:reference:features/logging.adoc#features.logging.shutdown-hook[#features.logging.shutdown-hook]\n* xref:reference:features/logging.adoc#features.logging[#boot-features-logging]\n* xref:reference:features/logging.adoc#features.logging[#features.logging]\n* xref:reference:features/profiles.adoc#features.profiles.adding-active-profiles[#boot-features-adding-active-profiles]\n* xref:reference:features/profiles.adoc#features.profiles.adding-active-profiles[#features.profiles.adding-active-profiles]\n* xref:reference:features/profiles.adoc#features.profiles.groups[#boot-features-profiles-groups]\n* xref:reference:features/profiles.adoc#features.profiles.groups[#features.profiles.groups]\n* xref:reference:features/profiles.adoc#features.profiles.profile-specific-configuration-files[#boot-features-profile-specific-configuration]\n* xref:reference:features/profiles.adoc#features.profiles.profile-specific-configuration-files[#features.profiles.profile-specific-configuration-files]\n* xref:reference:features/profiles.adoc#features.profiles.programmatically-setting-profiles[#boot-features-programmatically-setting-profiles]\n* xref:reference:features/profiles.adoc#features.profiles.programmatically-setting-profiles[#features.profiles.programmatically-setting-profiles]\n* xref:reference:features/profiles.adoc#features.profiles[#boot-features-profiles]\n* xref:reference:features/profiles.adoc#features.profiles[#features.profiles]\n* xref:reference:features/spring-application.adoc#features.spring-application.admin[#boot-features-application-admin]\n* xref:reference:features/spring-application.adoc#features.spring-application.admin[#features.spring-application.admin]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-arguments[#boot-features-application-arguments]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-arguments[#features.spring-application.application-arguments]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.liveness[#boot-features-application-availability-liveness-state]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.liveness[#features.spring-application.application-availability.liveness]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.managing[#boot-features-application-availability-managing]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.managing[#features.spring-application.application-availability.managing]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.readiness[#boot-features-application-availability-readiness-state]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability.readiness[#features.spring-application.application-availability.readiness]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#boot-features-application-availability]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-availability[#features.spring-application.application-availability]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[#boot-features-application-events-and-listeners]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[#features.spring-application.application-events-and-listeners]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-exit[#boot-features-application-exit]\n* xref:reference:features/spring-application.adoc#features.spring-application.application-exit[#features.spring-application.application-exit]\n* xref:reference:features/spring-application.adoc#features.spring-application.banner[#boot-features-banner]\n* xref:reference:features/spring-application.adoc#features.spring-application.banner[#features.spring-application.banner]\n* xref:reference:features/spring-application.adoc#features.spring-application.command-line-runner[#boot-features-command-line-runner]\n* xref:reference:features/spring-application.adoc#features.spring-application.command-line-runner[#features.spring-application.command-line-runner]\n* xref:reference:features/spring-application.adoc#features.spring-application.customizing-spring-application[#boot-features-customizing-spring-application]\n* xref:reference:features/spring-application.adoc#features.spring-application.customizing-spring-application[#features.spring-application.customizing-spring-application]\n* xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[#boot-features-fluent-builder-api]\n* xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[#features.spring-application.fluent-builder-api]\n* xref:reference:features/spring-application.adoc#features.spring-application.lazy-initialization[#boot-features-lazy-initialization]\n* xref:reference:features/spring-application.adoc#features.spring-application.lazy-initialization[#features.spring-application.lazy-initialization]\n* xref:reference:features/spring-application.adoc#features.spring-application.startup-failure[#boot-features-startup-failure]\n* xref:reference:features/spring-application.adoc#features.spring-application.startup-failure[#features.spring-application.startup-failure]\n* xref:reference:features/spring-application.adoc#features.spring-application.startup-tracking[#boot-features-application-startup-tracking]\n* xref:reference:features/spring-application.adoc#features.spring-application.startup-tracking[#features.spring-application.startup-tracking]\n* xref:reference:features/spring-application.adoc#features.spring-application.virtual-threads[#features.spring-application.virtual-threads]\n* xref:reference:features/spring-application.adoc#features.spring-application.web-environment[#boot-features-web-environment]\n* xref:reference:features/spring-application.adoc#features.spring-application.web-environment[#features.spring-application.web-environment]\n* xref:reference:features/spring-application.adoc#features.spring-application[#boot-features-spring-application]\n* xref:reference:features/spring-application.adoc#features.spring-application[#features.spring-application]\n* xref:reference:features/ssl.adoc#features.ssl.applying[#features.ssl.applying]\n* xref:reference:features/ssl.adoc#features.ssl.bundles[#features.ssl.bundles]\n* xref:reference:features/ssl.adoc#features.ssl.jks[#features.ssl.jks]\n* xref:reference:features/ssl.adoc#features.ssl.pem[#features.ssl.pem]\n* xref:reference:features/ssl.adoc#features.ssl.reloading[#features.ssl.reloading]\n* xref:reference:features/ssl.adoc#features.ssl[#features.ssl]\n* xref:reference:features/task-execution-and-scheduling.adoc#features.task-execution-and-scheduling[#boot-features-task-execution-scheduling]\n* xref:reference:features/task-execution-and-scheduling.adoc#features.task-execution-and-scheduling[#features.task-execution-and-scheduling]\n* xref:reference:io/caching.adoc#io.caching.provider.cache2k[#io.caching.provider.cache2k]\n* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#boot-features-caching-provider-caffeine]\n* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#features.caching.provider.caffeine]\n* xref:reference:io/caching.adoc#io.caching.provider.caffeine[#io.caching.provider.caffeine]\n* xref:reference:io/caching.adoc#io.caching.provider.couchbase[#boot-features-caching-provider-couchbase]\n* xref:reference:io/caching.adoc#io.caching.provider.couchbase[#features.caching.provider.couchbase]\n* xref:reference:io/caching.adoc#io.caching.provider.couchbase[#io.caching.provider.couchbase]\n* xref:reference:io/caching.adoc#io.caching.provider.generic[#boot-features-caching-provider-generic]\n* xref:reference:io/caching.adoc#io.caching.provider.generic[#features.caching.provider.generic]\n* xref:reference:io/caching.adoc#io.caching.provider.generic[#io.caching.provider.generic]\n* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#boot-features-caching-provider-hazelcast]\n* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#features.caching.provider.hazelcast]\n* xref:reference:io/caching.adoc#io.caching.provider.hazelcast[#io.caching.provider.hazelcast]\n* xref:reference:io/caching.adoc#io.caching.provider.infinispan[#boot-features-caching-provider-infinispan]\n* xref:reference:io/caching.adoc#io.caching.provider.infinispan[#features.caching.provider.infinispan]\n* xref:reference:io/caching.adoc#io.caching.provider.infinispan[#io.caching.provider.infinispan]\n* xref:reference:io/caching.adoc#io.caching.provider.jcache[#boot-features-caching-provider-jcache]\n* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.ehcache2]\n* xref:reference:io/caching.adoc#io.caching.provider.jcache[#features.caching.provider.jcache]\n* xref:reference:io/caching.adoc#io.caching.provider.jcache[#io.caching.provider.jcache]\n* xref:reference:io/caching.adoc#io.caching.provider.none[#boot-features-caching-provider-none]\n* xref:reference:io/caching.adoc#io.caching.provider.none[#features.caching.provider.none]\n* xref:reference:io/caching.adoc#io.caching.provider.none[#io.caching.provider.none]\n* xref:reference:io/caching.adoc#io.caching.provider.redis[#boot-features-caching-provider-redis]\n* xref:reference:io/caching.adoc#io.caching.provider.redis[#features.caching.provider.redis]\n* xref:reference:io/caching.adoc#io.caching.provider.redis[#io.caching.provider.redis]\n* xref:reference:io/caching.adoc#io.caching.provider.simple[#boot-features-caching-provider-simple]\n* xref:reference:io/caching.adoc#io.caching.provider.simple[#features.caching.provider.simple]\n* xref:reference:io/caching.adoc#io.caching.provider.simple[#io.caching.provider.simple]\n* xref:reference:io/caching.adoc#io.caching.provider[#boot-features-caching-provider]\n* xref:reference:io/caching.adoc#io.caching.provider[#features.caching.provider]\n* xref:reference:io/caching.adoc#io.caching.provider[#io.caching.provider]\n* xref:reference:io/caching.adoc#io.caching[#boot-features-caching]\n* xref:reference:io/caching.adoc#io.caching[#features.caching]\n* xref:reference:io/caching.adoc#io.caching[#io.caching]\n* xref:reference:io/email.adoc#io.email[#boot-features-email]\n* xref:reference:io/email.adoc#io.email[#features.email]\n* xref:reference:io/email.adoc#io.email[#io.email]\n* xref:reference:io/hazelcast.adoc#io.hazelcast[#boot-features-hazelcast]\n* xref:reference:io/hazelcast.adoc#io.hazelcast[#features.hazelcast]\n* xref:reference:io/hazelcast.adoc#io.hazelcast[#io.hazelcast]\n* xref:reference:io/index.adoc#io[#io]\n* xref:reference:io/index.adoc[#io]\n* xref:reference:io/index.adoc[io]\n* xref:reference:io/jta.adoc#io.jta.jakartaee[#boot-features-jta-javaee]\n* xref:reference:io/jta.adoc#io.jta.jakartaee[#features.jta.javaee]\n* xref:reference:io/jta.adoc#io.jta.jakartaee[#io.jta.jakartaee]\n* xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#boot-features-jta-mixed-jms]\n* xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#features.jta.mixing-xa-and-non-xa-connections]\n* xref:reference:io/jta.adoc#io.jta.mixing-xa-and-non-xa-connections[#io.jta.mixing-xa-and-non-xa-connections]\n* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#boot-features-jta-supporting-alternative-embedded]\n* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#features.jta.supporting-alternative-embedded-transaction-manager]\n* xref:reference:io/jta.adoc#io.jta.supporting-embedded-transaction-manager[#io.jta.supporting-embedded-transaction-manager]\n* xref:reference:io/jta.adoc#io.jta[#boot-features-jta]\n* xref:reference:io/jta.adoc#io.jta[#features.jta]\n* xref:reference:io/jta.adoc#io.jta[#io.jta]\n* xref:reference:io/quartz.adoc#io.quartz[#boot-features-quartz]\n* xref:reference:io/quartz.adoc#io.quartz[#features.quartz]\n* xref:reference:io/quartz.adoc#io.quartz[#io.quartz]\n* xref:reference:io/rest-client.adoc#io.rest-client.clienthttprequestfactory[#io.rest-client.clienthttprequestfactory]\n* xref:reference:io/rest-client.adoc#io.rest-client.restclient.customization[#io.rest-client.restclient.customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.restclient.ssl[#io.rest-client.restclient.ssl]\n* xref:reference:io/rest-client.adoc#io.rest-client.restclient[#io.rest-client.restclient]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#boot-features-resttemplate-customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#features.resttemplate.customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[#io.rest-client.resttemplate.customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.ssl[#io.rest-client.resttemplate.ssl]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#boot-features-resttemplate]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#features.resttemplate]\n* xref:reference:io/rest-client.adoc#io.rest-client.resttemplate[#io.rest-client.resttemplate]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#boot-features-webclient-customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#features.webclient.customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.customization[#io.rest-client.webclient.customization]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#boot-features-webclient-runtime]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#features.webclient.runtime]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.runtime[#io.rest-client.webclient.runtime]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient.ssl[#io.rest-client.webclient.ssl]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#boot-features-webclient]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#features.webclient]\n* xref:reference:io/rest-client.adoc#io.rest-client.webclient[#io.rest-client.webclient]\n* xref:reference:io/rest-client.adoc#io.rest-client[#io.rest-client]\n* xref:reference:io/spring-batch.adoc#io.spring-batch.running-jobs-on-startup[#howto-spring-batch-running-jobs-on-startup]\n* xref:reference:io/spring-batch.adoc#io.spring-batch.running-jobs-on-startup[#howto.batch.running-jobs-on-startup]\n* xref:reference:io/validation.adoc#io.validation[#boot-features-validation]\n* xref:reference:io/validation.adoc#io.validation[#features.validation]\n* xref:reference:io/validation.adoc#io.validation[#io.validation]\n* xref:reference:io/webservices.adoc#io.webservices.template[#boot-features-webservices-template]\n* xref:reference:io/webservices.adoc#io.webservices.template[#features.webservices.template]\n* xref:reference:io/webservices.adoc#io.webservices.template[#io.webservices.template]\n* xref:reference:io/webservices.adoc#io.webservices[#boot-features-webservices]\n* xref:reference:io/webservices.adoc#io.webservices[#features.webservices]\n* xref:reference:io/webservices.adoc#io.webservices[#io.webservices]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#boot-features-rabbitmq]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#features.messaging.amqp.rabbit]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbit]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.rabbitmq[#messaging.amqp.rabbitmq]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#boot-features-using-amqp-receiving]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#features.messaging.amqp.receiving]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.receiving[#messaging.amqp.receiving]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.sending-stream[#messaging.amqp.sending-stream]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#boot-features-using-amqp-sending]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#features.messaging.amqp.sending]\n* xref:reference:messaging/amqp.adoc#messaging.amqp.sending[#messaging.amqp.sending]\n* xref:reference:messaging/amqp.adoc#messaging.amqp[#boot-features-amqp]\n* xref:reference:messaging/amqp.adoc#messaging.amqp[#features.messaging.amqp]\n* xref:reference:messaging/amqp.adoc#messaging.amqp[#messaging.amqp]\n* xref:reference:messaging/index.adoc#messaging[#boot-features-messaging]\n* xref:reference:messaging/index.adoc#messaging[#features.messaging]\n* xref:reference:messaging/index.adoc#messaging[#messaging]\n* xref:reference:messaging/index.adoc[#messaging]\n* xref:reference:messaging/index.adoc[messaging]\n* xref:reference:messaging/jms.adoc#messaging.jms.activemq[#boot-features-activemq]\n* xref:reference:messaging/jms.adoc#messaging.jms.activemq[#features.messaging.jms.activemq]\n* xref:reference:messaging/jms.adoc#messaging.jms.activemq[#messaging.jms.activemq]\n* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#boot-features-artemis]\n* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#features.messaging.jms.artemis]\n* xref:reference:messaging/jms.adoc#messaging.jms.artemis[#messaging.jms.artemis]\n* xref:reference:messaging/jms.adoc#messaging.jms.jndi[#boot-features-jms-jndi]\n* xref:reference:messaging/jms.adoc#messaging.jms.jndi[#features.messaging.jms.jndi]\n* xref:reference:messaging/jms.adoc#messaging.jms.jndi[#messaging.jms.jndi]\n* xref:reference:messaging/jms.adoc#messaging.jms.receiving[#boot-features-using-jms-receiving]\n* xref:reference:messaging/jms.adoc#messaging.jms.receiving[#features.messaging.jms.receiving]\n* xref:reference:messaging/jms.adoc#messaging.jms.receiving[#messaging.jms.receiving]\n* xref:reference:messaging/jms.adoc#messaging.jms.sending[#boot-features-using-jms-sending]\n* xref:reference:messaging/jms.adoc#messaging.jms.sending[#features.messaging.jms.sending]\n* xref:reference:messaging/jms.adoc#messaging.jms.sending[#messaging.jms.sending]\n* xref:reference:messaging/jms.adoc#messaging.jms[#boot-features-jms]\n* xref:reference:messaging/jms.adoc#messaging.jms[#features.messaging.jms]\n* xref:reference:messaging/jms.adoc#messaging.jms[#messaging.jms]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#boot-features-kafka-extra-props]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#features.messaging.kafka.additional-properties]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.additional-properties[#messaging.kafka.additional-properties]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#boot-features-embedded-kafka]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#features.messaging.kafka.embedded]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.embedded[#messaging.kafka.embedded]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#boot-features-kafka-receiving-a-message]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#features.messaging.kafka.receiving]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.receiving[#messaging.kafka.receiving]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#boot-features-kafka-sending-a-message]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#features.messaging.kafka.sending]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.sending[#messaging.kafka.sending]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#boot-features-kafka-streams]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#features.messaging.kafka.streams]\n* xref:reference:messaging/kafka.adoc#messaging.kafka.streams[#messaging.kafka.streams]\n* xref:reference:messaging/kafka.adoc#messaging.kafka[#boot-features-kafka]\n* xref:reference:messaging/kafka.adoc#messaging.kafka[#features.messaging.kafka]\n* xref:reference:messaging/kafka.adoc#messaging.kafka[#messaging.kafka]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.additional-properties[#messaging.pulsar.additional-properties]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.admin.auth[#messaging.pulsar.admin.auth]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.admin[#messaging.pulsar.admin]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting.auth[#messaging.pulsar.connecting.auth]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting.ssl[#messaging.pulsar.connecting.ssl]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.connecting[#messaging.pulsar.connecting]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.reading[#messaging.pulsar.reading]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.receiving[#messaging.pulsar.receiving]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar.sending[#messaging.pulsar.sending]\n* xref:reference:messaging/pulsar.adoc#messaging.pulsar[#messaging.pulsar]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#boot-features-rsocket-messaging]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#features.rsocket.messaging]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.messaging[#messaging.rsocket.messaging]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#boot-features-rsocket-requester]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#features.rsocket.requester]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.requester[#messaging.rsocket.requester]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#boot-features-rsocket-server-auto-configuration]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#features.rsocket.server-auto-configuration]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[#messaging.rsocket.server-auto-configuration]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#boot-features-rsocket-strategies-auto-configuration]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#features.rsocket.strategies-auto-configuration]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket.strategies-auto-configuration[#messaging.rsocket.strategies-auto-configuration]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#boot-features-rsocket]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#features.rsocket]\n* xref:reference:messaging/rsocket.adoc#messaging.rsocket[#messaging.rsocket]\n* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#boot-features-integration]\n* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#features.spring-integration]\n* xref:reference:messaging/spring-integration.adoc#messaging.spring-integration[#messaging.spring-integration]\n* xref:reference:messaging/websockets.adoc#messaging.websockets[#boot-features-websockets]\n* xref:reference:messaging/websockets.adoc#messaging.websockets[#features.websockets]\n* xref:reference:messaging/websockets.adoc#messaging.websockets[#messaging.websockets]\n* xref:reference:packaging/aot-cache.adoc#packaging.aot-cache.aot-cache[#packaging.class-data-sharing.aot-cache]\n* xref:reference:packaging/aot-cache.adoc#packaging.aot-cache.cds[#packaging.class-data-sharing.cds]\n* xref:reference:packaging/aot-cache.adoc#packaging.aot-cache[#packaging.class-data-sharing]\n* xref:reference:packaging/aot.adoc#packaging.aot[#deployment.efficient.aot]\n* xref:reference:packaging/checkpoint-restore.adoc#packaging.checkpoint-restore[#deployment.efficient.checkpoint-restore]\n* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#boot-features-container-images-buildpacks]\n* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#container-images.buildpacks]\n* xref:reference:packaging/container-images/cloud-native-buildpacks.adoc#packaging.container-images.buildpacks[#features.container-images.building.buildpacks]\n* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#boot-features-container-images-docker]\n* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#container-images.dockerfiles]\n* xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles[#features.container-images.building.dockerfiles]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#boot-layering-docker-images]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#container-images.efficient-images.layering]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[#features.container-images.layering]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#boot-features-container-images-building]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#boot-features-container-images]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#container-images.efficient-images]\n* xref:reference:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images[#features.container-images.building]\n* xref:reference:packaging/container-images/index.adoc#packaging.container-images[#container-images]\n* xref:reference:packaging/container-images/index.adoc[#container-images]\n* xref:reference:packaging/container-images/index.adoc[container-images]\n* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#container-images.efficient-images.unpacking]\n* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#containers-deployment]\n* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#deployment.containers]\n* xref:reference:packaging/efficient.adoc#packaging.efficient.unpacking[#deployment.efficient.unpacking]\n* xref:reference:packaging/efficient.adoc#packaging.efficient[#deployment.efficient]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars.buildpacks[#native-image.advanced.converting-executable-jars.buildpacks]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars.native-image[#native-image.advanced.converting-executable-jars.native-image]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.converting-executable-jars[#native-image.advanced.converting-executable-jars]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.custom-hints.testing[#native-image.advanced.custom-hints.testing]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.custom-hints[#native-image.advanced.custom-hints]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.known-limitations[#native-image.advanced.known-limitations]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.nested-configuration-properties[#native-image.advanced.nested-configuration-properties]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.using-the-tracing-agent.launch[#native-image.advanced.using-the-tracing-agent.launch]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.using-the-tracing-agent[#native-image.advanced.using-the-tracing-agent]\n* xref:reference:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced[#native-image.advanced]\n* xref:reference:packaging/native-image/index.adoc#packaging.native-image[#native-image]\n* xref:reference:packaging/native-image/index.adoc[#native-image]\n* xref:reference:packaging/native-image/index.adoc[native-image]\n* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments[#packaging.native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments]\n* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.hint-file-generation[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.hint-file-generation]\n* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.proxy-class-generation[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.proxy-class-generation]\n* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation]\n* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing]\n* xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images[#native-image.introducing-graalvm-native-images]\n* xref:reference:testing/index.adoc#testing[#boot-features-testing]\n* xref:reference:testing/index.adoc#testing[#features.testing]\n* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#boot-features-testing-spring-applications]\n* xref:reference:testing/spring-applications.adoc#testing.spring-applications[#features.testing.spring-applications]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#boot-features-testing-spring-boot-applications-testing-auto-configured-additional-auto-config]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.additional-autoconfiguration-and-slicing[#features.testing.spring-boot-applications.additional-autoconfiguration-and-slicing]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jdbc-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[#features.testing.spring-boot-applications.autoconfigured-jdbc]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jooq-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jooq[#features.testing.spring-boot-applications.autoconfigured-jooq]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-rest-client[#features.testing.spring-boot-applications.autoconfigured-rest-client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#boot-features-testing-spring-boot-applications-testing-autoconfigured-cassandra-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-cassandra[#features.testing.spring-boot-applications.autoconfigured-spring-data-cassandra]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-couchbase[#features.testing.spring-boot-applications.autoconfigured-spring-data-couchbase]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch[#features.testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-data-jdbc-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jdbc[#features.testing.spring-boot-applications.autoconfigured-spring-data-jdbc]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[#features.testing.spring-boot-applications.autoconfigured-spring-data-jpa]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#boot-features-testing-spring-boot-applications-testing-autoconfigured-ldap-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-ldap[#features.testing.spring-boot-applications.autoconfigured-spring-data-ldap]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mongo-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-mongodb[#features.testing.spring-boot-applications.autoconfigured-spring-data-mongodb]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#boot-features-testing-spring-boot-applications-testing-autoconfigured-neo4j-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-neo4j[#features.testing.spring-boot-applications.autoconfigured-spring-data-neo4j]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-r2dbc[#features.testing.spring-boot-applications.autoconfigured-spring-data-r2dbc]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#boot-features-testing-spring-boot-applications-testing-autoconfigured-redis-test]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-redis[#features.testing.spring-boot-applications.autoconfigured-spring-data-redis]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-mock-mvc]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs-web-test-client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-restdocs[#features.testing.spring-boot-applications.autoconfigured-spring-restdocs]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[#features.testing.spring-boot-applications.autoconfigured-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices.client[#features.testing.spring-boot-applications.autoconfigured-webservices.client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices.server[#features.testing.spring-boot-applications.autoconfigured-webservices.server]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webservices]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-webservices[#features.testing.spring-boot-applications.autoconfigured-webservices]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#boot-features-testing-spring-boot-applications-customizing-web-test-client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.customizing-web-test-client[#features.testing.spring-boot-applications.customizing-web-test-client]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#boot-features-testing-spring-boot-applications-detecting-config]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[#features.testing.spring-boot-applications.detecting-configuration]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#boot-features-testing-spring-boot-applications-detecting-web-app-type]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-web-app-type[#features.testing.spring-boot-applications.detecting-web-app-type]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#boot-features-testing-spring-boot-applications-excluding-config]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.excluding-configuration[#features.testing.spring-boot-applications.excluding-configuration]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#boot-features-testing-spring-boot-applications-jmx]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.jmx[#features.testing.spring-boot-applications.jmx]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-json-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.json-tests[#features.testing.spring-boot-applications.json-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#boot-features-testing-spring-boot-applications-metrics]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.metrics[#features.testing.spring-boot-applications.metrics]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#boot-features-testing-spring-boot-applications-mocking-beans]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[#features.testing.spring-boot-applications.mocking-beans]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.observations[#features.testing.spring-boot-applications.observations]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#boot-features-testing-spring-boot-applications-with-spock]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spock[#features.testing.spring-boot-applications.spock]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-graphql-tests[#features.testing.spring-boot-applications.spring-graphql-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[#features.testing.spring-boot-applications.spring-mvc-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#boot-features-testing-spring-boot-applications-testing-autoconfigured-webflux-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[#features.testing.spring-boot-applications.spring-webflux-tests]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.tracing[#features.testing.spring-boot-applications.tracing]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#boot-features-testing-spring-boot-applications-testing-user-configuration]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[#features.testing.spring-boot-applications.user-configuration-and-slicing]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#boot-features-testing-spring-boot-application-arguments]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-application-arguments[#features.testing.spring-boot-applications.using-application-arguments]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.using-main[#features.testing.spring-boot-applications.using-main]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#boot-features-testing-spring-boot-applications-testing-with-mock-environment]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[#features.testing.spring-boot-applications.with-mock-environment]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#boot-features-testing-spring-boot-applications-testing-with-running-server]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[#features.testing.spring-boot-applications.with-running-server]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#boot-features-testing-spring-boot-applications]\n* xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications[#features.testing.spring-boot-applications]\n* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#boot-features-test-scope-dependencies]\n* xref:reference:testing/test-scope-dependencies.adoc#testing.test-scope-dependencies[#features.testing.test-scope-dependencies]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#boot-features-configfileapplicationcontextinitializer-test-utility]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.config-data-application-context-initializer[#features.testing.utilities.config-data-application-context-initializer]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#boot-features-output-capture-test-utility]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.output-capture[#features.testing.utilities.output-capture]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#boot-features-test-property-values]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.test-property-values[#features.testing.utilities.test-property-values]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#boot-features-rest-templates-test-utility]\n* xref:reference:testing/test-utilities.adoc#testing.utilities.test-rest-template[#features.testing.utilities.test-rest-template]\n* xref:reference:testing/test-utilities.adoc#testing.utilities[#boot-features-test-utilities]\n* xref:reference:testing/test-utilities.adoc#testing.utilities[#features.testing.utilities]\n* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#features.testing.testcontainers.dynamic-properties]\n* xref:reference:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[#howto.testing.testcontainers.dynamic-properties]\n* xref:reference:testing/testcontainers.adoc#testing.testcontainers.service-connections[#features.testing.testcontainers.service-connections]\n* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#features.testing.testcontainers]\n* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto-testcontainers]\n* xref:reference:testing/testcontainers.adoc#testing.testcontainers[#howto.testing.testcontainers]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration.disabling-specific[#using-boot-disabling-specific-auto-configuration]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration.disabling-specific[#using.auto-configuration.disabling-specific]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[#using.auto-configuration.packages]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration.replacing[#using-boot-replacing-auto-configuration]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration.replacing[#using.auto-configuration.replacing]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using-boot-auto-configuration]\n* xref:reference:using/auto-configuration.adoc#using.auto-configuration[#using.auto-configuration]\n* xref:reference:using/build-systems.adoc#using.build-systems.ant[#using-boot-ant]\n* xref:reference:using/build-systems.adoc#using.build-systems.ant[#using.build-systems.ant]\n* xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[#using-boot-dependency-management]\n* xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[#using.build-systems.dependency-management]\n* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#build-tool-plugins.gradle]\n* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#using-boot-gradle]\n* xref:reference:using/build-systems.adoc#using.build-systems.gradle[#using.build-systems.gradle]\n* xref:reference:using/build-systems.adoc#using.build-systems.maven[#build-tool-plugins.maven]\n* xref:reference:using/build-systems.adoc#using.build-systems.maven[#using-boot-maven]\n* xref:reference:using/build-systems.adoc#using.build-systems.maven[#using.build-systems.maven]\n* xref:reference:using/build-systems.adoc#using.build-systems.starters[#using-boot-starter]\n* xref:reference:using/build-systems.adoc#using.build-systems.starters[#using.build-systems.starters]\n* xref:reference:using/build-systems.adoc#using.build-systems[#using-boot-build-systems]\n* xref:reference:using/build-systems.adoc#using.build-systems[#using.build-systems]\n* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-additional-configuration[#using-boot-importing-configuration]\n* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-additional-configuration[#using.configuration-classes.importing-additional-configuration]\n* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-xml-configuration[#using-boot-importing-xml-configuration]\n* xref:reference:using/configuration-classes.adoc#using.configuration-classes.importing-xml-configuration[#using.configuration-classes.importing-xml-configuration]\n* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using-boot-configuration-classes]\n* xref:reference:using/configuration-classes.adoc#using.configuration-classes[#using.configuration-classes]\n* xref:reference:using/devtools.adoc#using.devtools.diagnosing-classloading-issues[#using.devtools.diagnosing-classloading-issues]\n* xref:reference:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[#configuring-file-system-watcher]\n* xref:reference:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[#using.devtools.globalsettings.configuring-file-system-watcher]\n* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using-boot-devtools-globalsettings]\n* xref:reference:using/devtools.adoc#using.devtools.globalsettings[#using.devtools.globalsettings]\n* xref:reference:using/devtools.adoc#using.devtools.livereload[#using-boot-devtools-livereload]\n* xref:reference:using/devtools.adoc#using.devtools.livereload[#using.devtools.livereload]\n* xref:reference:using/devtools.adoc#using.devtools.property-defaults[#using-boot-devtools-property-defaults]\n* xref:reference:using/devtools.adoc#using.devtools.property-defaults[#using.devtools.property-defaults]\n* xref:reference:using/devtools.adoc#using.devtools.remote-applications.client[#running-remote-client-application]\n* xref:reference:using/devtools.adoc#using.devtools.remote-applications.client[#using.devtools.remote-applications.client]\n* xref:reference:using/devtools.adoc#using.devtools.remote-applications.update[#using-boot-devtools-remote-update]\n* xref:reference:using/devtools.adoc#using.devtools.remote-applications.update[#using.devtools.remote-applications.update]\n* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using-boot-devtools-remote]\n* xref:reference:using/devtools.adoc#using.devtools.remote-applications[#using.devtools.remote-applications]\n* xref:reference:using/devtools.adoc#using.devtools.restart.customizing-the-classload[#using-boot-devtools-customizing-classload]\n* xref:reference:using/devtools.adoc#using.devtools.restart.customizing-the-classload[#using.devtools.restart.customizing-the-classload]\n* xref:reference:using/devtools.adoc#using.devtools.restart.disable[#using-boot-devtools-restart-disable]\n* xref:reference:using/devtools.adoc#using.devtools.restart.disable[#using.devtools.restart.disable]\n* xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[#using-boot-devtools-restart-exclude]\n* xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[#using.devtools.restart.excluding-resources]\n* xref:reference:using/devtools.adoc#using.devtools.restart.limitations[#using-boot-devtools-known-restart-limitations]\n* xref:reference:using/devtools.adoc#using.devtools.restart.limitations[#using.devtools.restart.limitations]\n* xref:reference:using/devtools.adoc#using.devtools.restart.logging-condition-delta[#using-boot-devtools-restart-logging-condition-delta]\n* xref:reference:using/devtools.adoc#using.devtools.restart.logging-condition-delta[#using.devtools.restart.logging-condition-delta]\n* xref:reference:using/devtools.adoc#using.devtools.restart.restart-vs-reload[#using-spring-boot-restart-vs-reload]\n* xref:reference:using/devtools.adoc#using.devtools.restart.restart-vs-reload[#using.devtools.restart.restart-vs-reload]\n* xref:reference:using/devtools.adoc#using.devtools.restart.triggerfile[#using-boot-devtools-restart-triggerfile]\n* xref:reference:using/devtools.adoc#using.devtools.restart.triggerfile[#using.devtools.restart.triggerfile]\n* xref:reference:using/devtools.adoc#using.devtools.restart.watching-additional-paths[#using-boot-devtools-restart-additional-paths]\n* xref:reference:using/devtools.adoc#using.devtools.restart.watching-additional-paths[#using.devtools.restart.watching-additional-paths]\n* xref:reference:using/devtools.adoc#using.devtools.restart[#using-boot-devtools-restart]\n* xref:reference:using/devtools.adoc#using.devtools.restart[#using.devtools.restart]\n* xref:reference:using/devtools.adoc#using.devtools[#using-boot-devtools]\n* xref:reference:using/devtools.adoc#using.devtools[#using.devtools]\n* xref:reference:using/index.adoc#using[#using-boot]\n* xref:reference:using/index.adoc#using[#using]\n* xref:reference:using/index.adoc#using[using]\n* xref:reference:using/packaging-for-production.adoc#using.packaging-for-production[#using-boot-packaging-for-production]\n* xref:reference:using/packaging-for-production.adoc#using.packaging-for-production[#using.packaging-for-production]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[#using-boot-running-as-a-packaged-application]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.as-a-packaged-application[#using.running-your-application.as-a-packaged-application]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[#using-boot-running-from-an-ide]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.from-an-ide[#using.running-your-application.from-an-ide]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.hot-swapping[#using-boot-hot-swapping]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.hot-swapping[#using.running-your-application.hot-swapping]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[#using-boot-running-with-the-gradle-plugin]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-gradle-plugin[#using.running-your-application.with-the-gradle-plugin]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[#using-boot-running-with-the-maven-plugin]\n* xref:reference:using/running-your-application.adoc#using.running-your-application.with-the-maven-plugin[#using.running-your-application.with-the-maven-plugin]\n* xref:reference:using/running-your-application.adoc#using.running-your-application[#using-boot-running-your-application]\n* xref:reference:using/running-your-application.adoc#using.running-your-application[#using.running-your-application]\n* xref:reference:using/spring-beans-and-dependency-injection.adoc#using.spring-beans-and-dependency-injection[#using-boot-spring-beans-and-dependency-injection]\n* xref:reference:using/spring-beans-and-dependency-injection.adoc#using.spring-beans-and-dependency-injection[#using.spring-beans-and-dependency-injection]\n* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.locating-the-main-class[#using-boot-locating-the-main-class]\n* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.locating-the-main-class[#using.structuring-your-code.locating-the-main-class]\n* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.using-the-default-package[#using-boot-using-the-default-package]\n* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code.using-the-default-package[#using.structuring-your-code.using-the-default-package]\n* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using-boot-structuring-your-code]\n* xref:reference:using/structuring-your-code.adoc#using.structuring-your-code[#using.structuring-your-code]\n* xref:reference:using/using-the-springbootapplication-annotation.adoc#using.using-the-springbootapplication-annotation[#using-boot-using-springbootapplication-annotation]\n* xref:reference:using/using-the-springbootapplication-annotation.adoc#using.using-the-springbootapplication-annotation[#using.using-the-springbootapplication-annotation]\n* xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#boot-features-graceful-shutdown]\n* xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#features.graceful-shutdown]\n* xref:reference:web/graceful-shutdown.adoc#web.graceful-shutdown[#web.graceful-shutdown]\n* xref:reference:web/index.adoc#web[#boot-features-developing-web-applications]\n* xref:reference:web/index.adoc#web[#features.developing-web-applications]\n* xref:reference:web/index.adoc#web[#web]\n* xref:reference:web/index.adoc[#web]\n* xref:reference:web/index.adoc[web]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#boot-features-reactive-server-resources]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#features.developing-web-applications.reactive-server-resources-configuration]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server-resources-configuration[#web.reactive.reactive-server-resources-configuration]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing.direct[#web.reactive.reactive-server.customizing.direct]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing.programmatic[#web.reactive.reactive-server.customizing.programmatic]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server.customizing[#web.reactive.reactive-server.customizing]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#boot-features-reactive-server]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#features.developing-web-applications.reactive-server]\n* xref:reference:web/reactive.adoc#web.reactive.reactive-server[#web.reactive.reactive-server]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#boot-features-webflux-auto-configuration]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#features.developing-web-applications.spring-webflux.auto-configuration]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.auto-configuration[#web.reactive.webflux.auto-configuration]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.conversion-service[#web.reactive.webflux.conversion-service]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#boot-features-webflux-error-handling-custom-error-pages]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#features.developing-web-applications.spring-webflux.error-pages]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[#web.reactive.webflux.error-handling.error-pages]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#boot-features-webflux-error-handling]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#features.developing-web-applications.spring-webflux.error-handling]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.error-handling[#web.reactive.webflux.error-handling]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#boot-features-webflux-httpcodecs]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#features.developing-web-applications.spring-webflux.httpcodecs]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.httpcodecs[#web.reactive.webflux.httpcodecs]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#boot-features-webflux-static-content]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#features.developing-web-applications.spring-webflux.static-context]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.static-content[#web.reactive.webflux.static-content]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#boot-features-webflux-template-engines]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#features.developing-web-applications.spring-webflux.template-engines]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.template-engines[#web.reactive.webflux.template-engines]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#boot-features-webflux-web-filters]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#features.developing-web-applications.spring-webflux.web-filters]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.web-filters[#web.reactive.webflux.web-filters]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#boot-features-webflux-welcome-page]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#features.developing-web-applications.spring-webflux.welcome-page]\n* xref:reference:web/reactive.adoc#web.reactive.webflux.welcome-page[#web.reactive.webflux.welcome-page]\n* xref:reference:web/reactive.adoc#web.reactive.webflux[#boot-features-webflux]\n* xref:reference:web/reactive.adoc#web.reactive.webflux[#features.developing-web-applications.spring-webflux]\n* xref:reference:web/reactive.adoc#web.reactive.webflux[#web.reactive.webflux]\n* xref:reference:web/reactive.adoc#web.reactive[#web.reactive]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#boot-features-embedded-container-application-context]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#features.developing-web-applications.embedded-container.application-context]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.application-context[#web.servlet.embedded-container.application-context]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#boot-features-embedded-container-servlets-filters-listeners-scanning]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#features.developing-web-applications.embedded-container.context-initializer.scanning]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer.scanning[#web.servlet.embedded-container.context-initializer.scanning]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#boot-features-embedded-container-context-initializer]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#features.developing-web-applications.embedded-container.context-initializer]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.context-initializer[#web.servlet.embedded-container.context-initializer]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#boot-features-customizing-configurableservletwebserverfactory-directly]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#features.developing-web-applications.embedded-container.customizing.direct]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.direct[#web.servlet.embedded-container.customizing.direct]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.encoding[#web.servlet.embedded-container.customizing.encoding]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#boot-features-programmatic-embedded-container-customization]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#features.developing-web-applications.embedded-container.customizing.programmatic]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.programmatic[#web.servlet.embedded-container.customizing.programmatic]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing.samesite[#web.servlet.embedded-container.customizing.samesite]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#boot-features-customizing-embedded-containers]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#features.developing-web-applications.embedded-container.customizing]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[#web.servlet.embedded-container.customizing]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#boot-features-jsp-limitations]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#features.developing-web-applications.embedded-container.jsp-limitations]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[#web.servlet.embedded-container.jsp-limitations]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#boot-features-embedded-container-servlets-filters-listeners-beans]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#features.developing-web-applications.embedded-container.servlets-filters-listeners.beans]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[#web.servlet.embedded-container.servlets-filters-listeners.beans]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#boot-features-embedded-container-servlets-filters-listeners]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#features.developing-web-applications.embedded-container.servlets-filters-listeners]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners[#web.servlet.embedded-container.servlets-filters-listeners]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#boot-features-embedded-container]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#features.developing-web-applications.embedded-container]\n* xref:reference:web/servlet.adoc#web.servlet.embedded-container[#web.servlet.embedded-container]\n* xref:reference:web/servlet.adoc#web.servlet.jersey[#boot-features-jersey]\n* xref:reference:web/servlet.adoc#web.servlet.jersey[#features.developing-web-applications.jersey]\n* xref:reference:web/servlet.adoc#web.servlet.jersey[#web.servlet.jersey]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#boot-features-spring-mvc-auto-configuration]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#features.developing-web-applications.spring-mvc.auto-configuration]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.auto-configuration[#web.servlet.spring-mvc.auto-configuration]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#boot-features-spring-mvc-web-binding-initializer]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#features.developing-web-applications.spring-mvc.binding-initializer]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[#web.servlet.spring-mvc.binding-initializer]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#boot-features-spring-mvc-pathmatch]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#features.developing-web-applications.spring-mvc.content-negotiation]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.content-negotiation[#web.servlet.spring-mvc.content-negotiation]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.conversion-service[#web.servlet.spring-mvc.conversion-service]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#boot-features-cors]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#features.developing-web-applications.spring-mvc.cors]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.cors[#web.servlet.spring-mvc.cors]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#boot-features-error-handling-mapping-error-pages-without-mvc]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#features.developing-web-applications.spring-mvc.error-handling.error-pages-without-spring-mvc]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc[#web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#boot-features-error-handling-custom-error-pages]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#features.developing-web-applications.spring-mvc.error-handling.error-pages]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[#web.servlet.spring-mvc.error-handling.error-pages]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#boot-features-error-handling-war-deployment]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#features.developing-web-applications.spring-mvc.error-handling.in-a-war-deployment]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling.in-a-war-deployment[#web.servlet.spring-mvc.error-handling.in-a-war-deployment]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#boot-features-error-handling]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#features.developing-web-applications.spring-mvc.error-handling]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[#web.servlet.spring-mvc.error-handling]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.favicon[#features.developing-web-applications.spring-mvc.favicon]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.favicon[#web.servlet.spring-mvc.favicon]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#boot-features-spring-message-codes]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#features.developing-web-applications.spring-mvc.message-codes]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-codes[#web.servlet.spring-mvc.message-codes]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#boot-features-spring-mvc-message-converters]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#features.developing-web-applications.spring-mvc.message-converters]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.message-converters[#web.servlet.spring-mvc.message-converters]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#boot-features-spring-mvc-static-content]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#features.developing-web-applications.spring-mvc.static-content]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.static-content[#web.servlet.spring-mvc.static-content]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#boot-features-spring-mvc-template-engines]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#features.developing-web-applications.spring-mvc.template-engines]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.template-engines[#web.servlet.spring-mvc.template-engines]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#boot-features-spring-mvc-welcome-page]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#features.developing-web-applications.spring-mvc.welcome-page]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc.welcome-page[#web.servlet.spring-mvc.welcome-page]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#boot-features-spring-mvc]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#features.developing-web-applications.spring-mvc]\n* xref:reference:web/servlet.adoc#web.servlet.spring-mvc[#web.servlet.spring-mvc]\n* xref:reference:web/servlet.adoc#web.servlet[#web.servlet]\n* xref:reference:web/spring-graphql.adoc#web.graphql.data-query[#web.graphql.data-query]\n* xref:reference:web/spring-graphql.adoc#web.graphql.exception-handling[#web.graphql.exception-handling]\n* xref:reference:web/spring-graphql.adoc#web.graphql.graphiql[#web.graphql.graphiql]\n* xref:reference:web/spring-graphql.adoc#web.graphql.runtimewiring[#web.graphql.runtimewiring]\n* xref:reference:web/spring-graphql.adoc#web.graphql.schema[#web.graphql.schema]\n* xref:reference:web/spring-graphql.adoc#web.graphql.transports.http-websocket[#web.graphql.transports.http-websocket]\n* xref:reference:web/spring-graphql.adoc#web.graphql.transports.rsocket[#web.graphql.transports.rsocket]\n* xref:reference:web/spring-graphql.adoc#web.graphql.transports[#web.graphql.transports]\n* xref:reference:web/spring-graphql.adoc#web.graphql[#web.graphql]\n* xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#boot-features-spring-hateoas]\n* xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#features.spring-hateoas]\n* xref:reference:web/spring-hateoas.adoc#web.spring-hateoas[#web.spring-hateoas]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#boot-features-security-authorization-server]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#features.security.authorization-server]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.authorization-server[#web.security.oauth2.authorization-server]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#boot-features-security-oauth2-common-providers]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#features.security.oauth2.client.common-providers]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.client.common-providers[#web.security.oauth2.client.common-providers]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#boot-features-security-oauth2-client]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#features.security.oauth2.client]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.client[#web.security.oauth2.client]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#boot-features-security-oauth2-server]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#features.security.oauth2.server]\n* xref:reference:web/spring-security.adoc#web.security.oauth2.server[#web.security.oauth2.server]\n* xref:reference:web/spring-security.adoc#web.security.oauth2[#boot-features-security-oauth2]\n* xref:reference:web/spring-security.adoc#web.security.oauth2[#features.security.oauth2]\n* xref:reference:web/spring-security.adoc#web.security.oauth2[#web.security.oauth2]\n* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#boot-features-security-saml2-relying-party]\n* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#features.security.saml2.relying-party]\n* xref:reference:web/spring-security.adoc#web.security.saml2.relying-party[#web.security.saml2.relying-party]\n* xref:reference:web/spring-security.adoc#web.security.saml2[#boot-features-security-saml]\n* xref:reference:web/spring-security.adoc#web.security.saml2[#features.security.saml2]\n* xref:reference:web/spring-security.adoc#web.security.saml2[#web.security.saml2]\n* xref:reference:web/spring-security.adoc#web.security.spring-mvc[#boot-features-security-mvc]\n* xref:reference:web/spring-security.adoc#web.security.spring-mvc[#features.security.spring-mvc]\n* xref:reference:web/spring-security.adoc#web.security.spring-mvc[#web.security.spring-mvc]\n* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#boot-features-security-webflux]\n* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#features.security.spring-webflux]\n* xref:reference:web/spring-security.adoc#web.security.spring-webflux[#web.security.spring-webflux]\n* xref:reference:web/spring-security.adoc#web.security[#boot-features-security]\n* xref:reference:web/spring-security.adoc#web.security[#features.security]\n* xref:reference:web/spring-security.adoc#web.security[#web.security]\n* xref:reference:web/spring-session.adoc#web.spring-session[#boot-features-session]\n* xref:reference:web/spring-session.adoc#web.spring-session[#features.spring-session]\n* xref:reference:web/spring-session.adoc#web.spring-session[#web.spring-session]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[#appendix.configuration-metadata.annotation-processor.adding-additional-metadata]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[#configuration-metadata.annotation-processor.adding-additional-metadata]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties[#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties[#configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation[#configuration-metadata.annotation-processor.automatic-metadata-generation]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.configuring[#appendix.configuration-metadata.annotation-processor.configuring]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.configuring[#configuration-metadata.annotation-processor.configuring]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#appendix.configuration-metadata.annotation-processor]\n* xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor[#configuration-metadata.annotation-processor]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.group[#appendix.configuration-metadata.format.group]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.group[#configuration-metadata.format.group]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.hints[#appendix.configuration-metadata.format.hints]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.hints[#configuration-metadata.format.hints]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.property[#appendix.configuration-metadata.format.property]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.property[#configuration-metadata.format.property]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.repeated-items[#appendix.configuration-metadata.format.repeated-items]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format.repeated-items[#configuration-metadata.format.repeated-items]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#appendix.configuration-metadata.format]\n* xref:specification:configuration-metadata/format.adoc#appendix.configuration-metadata.format[#configuration-metadata.format]\n* xref:specification:configuration-metadata/index.adoc#appendix.configuration-metadata[#appendix.configuration-metadata]\n* xref:specification:configuration-metadata/index.adoc#appendix.configuration-metadata[#configuration-metadata]\n* xref:specification:configuration-metadata/index.adoc[#configuration-metadata]\n* xref:specification:configuration-metadata/index.adoc[configuration-metadata]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-hint[#appendix.configuration-metadata.manual-hints.value-hint]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-hint[#configuration-metadata.manual-hints.value-hint]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.any[#appendix.configuration-metadata.manual-hints.value-providers.any]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.any[#configuration-metadata.manual-hints.value-providers.any]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.class-reference[#appendix.configuration-metadata.manual-hints.value-providers.class-reference]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.class-reference[#configuration-metadata.manual-hints.value-providers.class-reference]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.handle-as[#appendix.configuration-metadata.manual-hints.value-providers.handle-as]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.handle-as[#configuration-metadata.manual-hints.value-providers.handle-as]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.logger-name[#appendix.configuration-metadata.manual-hints.value-providers.logger-name]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.logger-name[#configuration-metadata.manual-hints.value-providers.logger-name]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference[#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference[#configuration-metadata.manual-hints.value-providers.spring-bean-reference]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name[#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name[#configuration-metadata.manual-hints.value-providers.spring-profile-name]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#appendix.configuration-metadata.manual-hints.value-providers]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints.value-providers[#configuration-metadata.manual-hints.value-providers]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#appendix.configuration-metadata.manual-hints]\n* xref:specification:configuration-metadata/manual-hints.adoc#appendix.configuration-metadata.manual-hints[#configuration-metadata.manual-hints]\n* xref:specification:executable-jar/alternatives.adoc#appendix.executable-jar.alternatives[#appendix.executable-jar.alternatives]\n* xref:specification:executable-jar/alternatives.adoc#appendix.executable-jar.alternatives[#executable-jar.alternatives]\n* xref:specification:executable-jar/index.adoc#appendix.executable-jar[#appendix.executable-jar]\n* xref:specification:executable-jar/index.adoc#appendix.executable-jar[#executable-jar]\n* xref:specification:executable-jar/index.adoc[#executable-jar]\n* xref:specification:executable-jar/index.adoc[executable-jar]\n* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class.compatibility[#appendix.executable-jar.jarfile-class.compatibility]\n* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class.compatibility[#executable-jar.jarfile-class.compatibility]\n* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#appendix.executable-jar.jarfile-class]\n* xref:specification:executable-jar/jarfile-class.adoc#appendix.executable-jar.jarfile-class[#executable-jar.jarfile-class]\n* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching.manifest[#appendix.executable-jar.launching.manifest]\n* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching.manifest[#executable-jar.launching.manifest]\n* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#appendix.executable-jar.launching]\n* xref:specification:executable-jar/launching.adoc#appendix.executable-jar.launching[#executable-jar.launching]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.classpath-index[#appendix.executable-jar.nested-jars.classpath-index]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.classpath-index[#executable-jar.nested-jars.classpath-index]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.index-files[#appendix.executable-jar.nested-jars.index-files]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.index-files[#executable-jar.nested-jars.index-files]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[#appendix.executable-jar.nested-jars.jar-structure]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[#executable-jar.nested-jars.jar-structure]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.layer-index[#appendix.executable-jar.nested-jars.layer-index]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.layer-index[#executable-jar.nested-jars.layer-index]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.war-structure[#appendix.executable-jar.nested-jars.war-structure]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.war-structure[#executable-jar.nested-jars.war-structure]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#appendix.executable-jar.nested-jars]\n* xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars[#executable-jar.nested-jars]\n* xref:specification:executable-jar/property-launcher.adoc#appendix.executable-jar.property-launcher[#appendix.executable-jar.property-launcher]\n* xref:specification:executable-jar/property-launcher.adoc#appendix.executable-jar.property-launcher[#executable-jar.property-launcher]\n* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar-system-classloader[#appendix.executable-jar-system-classloader]\n* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar-zip-entry-compression[#appendix.executable-jar-zip-entry-compression]\n* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar.restrictions[#appendix.executable-jar.restrictions]\n* xref:specification:executable-jar/restrictions.adoc#appendix.executable-jar.restrictions[#executable-jar.restrictions]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.main-method[#getting-started-first-application-main-method]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.main-method[#getting-started.first-application.code.main-method]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.mvc-annotations[#getting-started-first-application-annotations]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.mvc-annotations[#getting-started.first-application.code.mvc-annotations]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started-first-application-auto-configuration]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started.first-application.code.enable-auto-configuration]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code.spring-boot-application[#getting-started.first-application.code.spring-boot-application]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started-first-application-code]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.code[#getting-started.first-application.code]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies.gradle[#getting-started.first-application.dependencies.gradle]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies.maven[#getting-started.first-application.dependencies.maven]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started-first-application-dependencies]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.dependencies[#getting-started.first-application.dependencies]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar.gradle[#getting-started.first-application.executable-jar.gradle]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar.maven[#getting-started.first-application.executable-jar.maven]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started-first-application-executable-jar]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.executable-jar[#getting-started.first-application.executable-jar]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.gradle[#getting-started.first-application.gradle]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.pom[#getting-started-first-application-pom]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.pom[#getting-started.first-application.pom]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites.gradle[#getting-started.first-application.prerequisites.gradle]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites.maven[#getting-started.first-application.prerequisites.maven]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.prerequisites[#getting-started.first-application.prerequisites]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.run.gradle[#getting-started.first-application.run.gradle]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.run.maven[#getting-started.first-application.run.maven]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started-first-application-run]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application.run[#getting-started.first-application.run]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started-first-application]\n* xref:tutorial:first-application/index.adoc#getting-started.first-application[#getting-started.first-application]\n* xref:upgrading.adoc[#upgrading]\n* xref:upgrading.adoc[upgrading]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/system-requirements.adoc",
    "content": "[[getting-started.system-requirements]]\n= System Requirements\n\nSpring Boot {version-spring-boot} requires at least https://www.java.com[Java 17] and is compatible with versions up to and including Java 26.\n{url-spring-framework-docs}/[Spring Framework {version-spring-framework}] or above is also required.\n\nSupport for third-party projects may have additional or higher requirements.\nRefer to the documentation for that support for further details.\n\nExplicit build support is provided for the following build tools:\n\n|===\n| Build Tool | Version\n\n| Maven\n| 3.6.3 or later\n\n| Gradle\n| Gradle 8.x (8.14 or later) and 9.x\n|===\n\n\n\n[[getting-started.system-requirements.servlet-containers]]\n== Servlet Containers\n\nSpring Boot supports the following embedded servlet containers:\n\n|===\n| Name | Servlet Version\n\n| Tomcat 11.0.x\n| 6.1\n\n| Jetty 12.1.x\n| 6.1\n\n|===\n\nYou can also deploy Spring Boot applications to any Servlet 6.1+ compatible container.\n\n\n\n[[getting-started.system-requirements.graal]]\n== GraalVM Native Images\n\nSpring Boot applications can be xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc[converted into a Native Image] using GraalVM {version-graal} or above.\n\nImages can be created using the https://github.com/graalvm/native-build-tools[native build tools] Gradle/Maven plugins or `native-image` tool provided by GraalVM.\nYou can also create native images using the https://github.com/paketo-buildpacks/native-image[native-image Paketo buildpack].\n\nThe following versions are supported:\n\n|===\n| Name | Version\n\n| GraalVM Community\n| {version-graal}\n\n| Native Build Tools\n| {version-native-build-tools}\n|===\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/pages/upgrading.adoc",
    "content": "[[upgrading]]\n= Upgrading Spring Boot\n\nInstructions for how to upgrade from earlier versions of Spring Boot are provided on the project {url-github-wiki}[wiki].\nFollow the links in the {url-github-wiki}#release-notes[release notes] section to find the version that you want to upgrade to.\n\nUpgrading instructions are always the first item in the release notes.\nIf you are more than one release behind, please make sure that you also review the release notes of the versions that you jumped.\n\n\n\n[[upgrading.from-1x]]\n== Upgrading From 1.x\n\nIf you are upgrading from the `1.x` release of Spring Boot, check the {url-github-wiki}/Spring-Boot-2.0-Migration-Guide[migration guide] on the project wiki that provides detailed upgrade instructions to upgrade to Spring Boot 2.x.\nCheck also the {url-github-wiki}#release-notes[release notes] for a list of \"`new and noteworthy`\" features for each release.\n\n\n\n[[upgrading.from-2x]]\n== Upgrading From 2.x\n\nIf you are upgrading from the `2.x` release of Spring Boot, check the {url-github-wiki}/Spring-Boot-3.0-Migration-Guide[migration guide] on the project wiki that provides detailed upgrade instructions.\nCheck also the {url-github-wiki}#release-notes[release notes] for a list of \"`new and noteworthy`\" features for each release.\n\n\n\n[[upgrading.from-3x]]\n== Upgrading From 3.x\n\nIf you are upgrading from the `3.x` release of Spring Boot, check the {url-github-wiki}/Spring-Boot-4.0-Migration-Guide[migration guide] on the project wiki that provides detailed upgrade instructions.\nCheck also the {url-github-wiki}#release-notes[release notes] for a list of \"`new and noteworthy`\" features for each release.\n\n\n\n[[upgrading.to-feature]]\n== Upgrading to a New Feature Release\n\nWhen upgrading to a new feature release, some properties may have been renamed or removed.\nSpring Boot provides a way to analyze your application's environment and print diagnostics at startup, but also temporarily migrate properties at runtime for you.\nTo enable that feature, add the following dependency to your project:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-properties-migrator</artifactId>\n\t<scope>runtime</scope>\n</dependency>\n----\n\nWARNING: Properties that are added late to the environment, such as when using javadoc:org.springframework.context.annotation.PropertySource[format=annotation], will not be taken into account.\n\nNOTE: Once you finish the migration, please make sure to remove this module from your project's dependencies.\n\n\n\n[[upgrading.cli]]\n== Upgrading the Spring Boot CLI\n\nTo upgrade an existing CLI installation, use the appropriate package manager command (for example, `brew upgrade`).\nIf you manually installed the CLI, follow the xref:installing.adoc#getting-started.installing.cli.manual-installation[standard instructions], remembering to update your `PATH` environment variable to remove any older references.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/ROOT/partials/nav-root.adoc",
    "content": "* xref:index.adoc[,role=navtree-icon-home]\n* xref:documentation.adoc[,role=navtree-icon-book]\n* xref:community.adoc[,role=navtree-icon-question]\n* xref:system-requirements.adoc[,role=navtree-icon-server]\n* xref:installing.adoc[,role=navtree-icon-gift]\n* xref:upgrading.adoc[,role=navtree-icon-rocket]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/api/partials/nav-java-api.adoc",
    "content": "* Java APIs\n** xref:api:java/index.html[Spring Boot,role=link-external, window=_blank]\n** xref:gradle-plugin:api/java/index.html[Gradle Plugin,role=link-external, window=_blank]\n** xref:maven-plugin:api/java/index.html[Maven Plugin,role=link-external, window=_blank]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/api/partials/nav-kotlin-api.adoc",
    "content": "* Kotlin APIs\n** xref:api:kotlin/index.html[Spring Boot,role=link-external, window=_blank]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/api/partials/nav-rest-api.adoc",
    "content": "* Rest APIs\n+\n--\ninclude::api:partial$nav-actuator-rest-api.adoc[]\n--\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/application-properties/index.adoc",
    "content": "[appendix]\n[[appendix.application-properties]]\n= Common Application Properties\n\nVarious properties can be specified inside your `application.properties` file, inside your `application.yaml` file, or as command line switches.\nThis appendix provides a list of common Spring Boot properties and references to the underlying classes that consume them.\n\nTIP: Spring Boot provides various conversion mechanisms with advanced value formatting.\nMake sure to review xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion[the properties conversion section].\n\nNOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.\nAlso, you can define your own properties.\n\ninclude::partial$configuration-properties/actuator.adoc[]\n\ninclude::partial$configuration-properties/cache.adoc[]\n\ninclude::partial$configuration-properties/core.adoc[]\n\ninclude::partial$configuration-properties/data-migration.adoc[]\n\ninclude::partial$configuration-properties/data.adoc[]\n\ninclude::partial$configuration-properties/devtools.adoc[]\n\ninclude::partial$configuration-properties/docker-compose.adoc[]\n\ninclude::partial$configuration-properties/integration.adoc[]\n\ninclude::partial$configuration-properties/json.adoc[]\n\ninclude::partial$configuration-properties/mail.adoc[]\n\ninclude::partial$configuration-properties/rsocket.adoc[]\n\ninclude::partial$configuration-properties/security.adoc[]\n\ninclude::partial$configuration-properties/server.adoc[]\n\ninclude::partial$configuration-properties/templating.adoc[]\n\ninclude::partial$configuration-properties/testcontainers.adoc[]\n\ninclude::partial$configuration-properties/testing.adoc[]\n\ninclude::partial$configuration-properties/transaction.adoc[]\n\ninclude::partial$configuration-properties/web.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/auto-configuration-classes/index.adoc",
    "content": "[appendix]\n[[appendix.auto-configuration-classes]]\n= Auto-configuration Classes\n\nThis appendix contains details of all of the auto-configuration classes provided by Spring Boot, with links to documentation and source code.\nRemember to also look at the conditions report in your application for more details of which features are switched on.\n(To do so, start the app with `--debug` or `-Ddebug` or, in an Actuator application, use the `conditions` endpoint).\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/dependency-versions/coordinates.adoc",
    "content": "[[appendix.dependency-versions.coordinates]]\n= Managed Dependency Coordinates\n\nThe following table provides details of all of the dependency versions that are provided by Spring Boot in its CLI (Command Line Interface), Maven dependency management, and Gradle plugin.\nWhen you declare a dependency on one of these artifacts without declaring a version, the version listed in the table is used.\n\ninclude::partial$dependency-versions/documented-coordinates.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/dependency-versions/index.adoc",
    "content": "[appendix]\n[[appendix.dependency-versions]]\n= Dependency Versions\n\nThis appendix provides details of the dependencies that are managed by Spring Boot.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/dependency-versions/properties.adoc",
    "content": "[[appendix.dependency-versions.properties]]\n= Version Properties\n\nThe following table provides all properties that can be used to override the versions managed by Spring Boot.\nBrowse the {code-spring-boot}/platform/spring-boot-dependencies/build.gradle[`spring-boot-dependencies` build.gradle] for a complete list of dependencies.\nYou can learn how to customize these versions in your application in the xref:build-tool-plugin:index.adoc[] documentation.\n\ninclude::partial$dependency-versions/documented-properties.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/deprecated-application-properties/index.adoc",
    "content": "[appendix]\n[[appendix.deprecated-application-properties]]\n= Deprecated Application Properties\n\nThe following deprecated properties can be specified inside your `application.properties` file, inside your `application.yaml` file, or as command line switches.\nSupport for these properties will be removed in a future release and should you should migrate away from them.\n\n[TIP]\n====\nSpring Boot includes a useful `spring-boot-properties-migrator` tool to help you migrate away from deprecated properties.\nTo use the property migrator tool, add the following dependency to your project:\n\n[tabs]\n======\nMaven::\n+\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-properties-migrator</artifactId>\n\t<scope>runtime</scope>\n</dependency>\n----\nGradle::\n+\n[source,gradle]\n----\nruntimeOnly(\"org.springframework.boot:spring-boot-properties-migrator\")\n----\n======\n\nOnce added as a dependency to your project, the tool will not only analyze your application’s environment and print diagnostics at startup, but also temporarily migrate properties at runtime for you.\n\nRemember to remove the dependency when your migration is complete.\n====\n\n\ninclude::partial$deprecated-configuration-properties/actuator.adoc[]\n\ninclude::partial$deprecated-configuration-properties/cache.adoc[]\n\ninclude::partial$deprecated-configuration-properties/core.adoc[]\n\ninclude::partial$deprecated-configuration-properties/data-migration.adoc[]\n\ninclude::partial$deprecated-configuration-properties/data.adoc[]\n\ninclude::partial$deprecated-configuration-properties/devtools.adoc[]\n\ninclude::partial$deprecated-configuration-properties/docker-compose.adoc[]\n\ninclude::partial$deprecated-configuration-properties/integration.adoc[]\n\ninclude::partial$deprecated-configuration-properties/json.adoc[]\n\ninclude::partial$deprecated-configuration-properties/mail.adoc[]\n\ninclude::partial$deprecated-configuration-properties/rsocket.adoc[]\n\ninclude::partial$deprecated-configuration-properties/security.adoc[]\n\ninclude::partial$deprecated-configuration-properties/server.adoc[]\n\ninclude::partial$deprecated-configuration-properties/templating.adoc[]\n\ninclude::partial$deprecated-configuration-properties/testcontainers.adoc[]\n\ninclude::partial$deprecated-configuration-properties/testing.adoc[]\n\ninclude::partial$deprecated-configuration-properties/transaction.adoc[]\n\ninclude::partial$deprecated-configuration-properties/web.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/test-auto-configuration/index.adoc",
    "content": "[appendix]\n[[appendix.test-auto-configuration]]\n= Test Auto-configuration Annotations\n\nThis appendix describes the `@...Test` auto-configuration annotations that Spring Boot provides to test slices of your application.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/pages/test-auto-configuration/slices.adoc",
    "content": "[[appendix.test-auto-configuration.slices]]\n= Test Slices\n\nThe following table lists the various `@...Test` annotations that can be used to test slices of your application and the auto-configuration that they import by default:\n\ninclude::partial$slices/documented-slices.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/appendix/partials/nav-appendix.adoc",
    "content": "* Appendix\n\n** xref:appendix:application-properties/index.adoc[]\n\n** xref:appendix:deprecated-application-properties/index.adoc[]\n\n** xref:appendix:auto-configuration-classes/index.adoc[]\ninclude::appendix:partial$auto-configuration-classes/nav.adoc[]\n\n** xref:appendix:test-auto-configuration/index.adoc[]\n*** xref:appendix:test-auto-configuration/slices.adoc[]\n\n** xref:appendix:dependency-versions/index.adoc[]\n*** xref:appendix:dependency-versions/coordinates.adoc[]\n*** xref:appendix:dependency-versions/properties.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/build-tool-plugin/pages/antlib.adoc",
    "content": "[[build-tool-plugins.antlib]]\n= Spring Boot AntLib Module\n\nThe Spring Boot AntLib module provides basic Spring Boot support for Apache Ant.\nYou can use the module to create executable jars.\nTo use the module, you need to declare an additional `spring-boot` namespace in your `build.xml`, as shown in the following example:\n\n[source,xml]\n----\n<project xmlns:ivy=\"antlib:org.apache.ivy.ant\"\n\txmlns:spring-boot=\"antlib:org.springframework.boot.ant\"\n\tname=\"myapp\" default=\"build\">\n\t...\n</project>\n----\n\nYou need to remember to start Ant using the `-lib` option, as shown in the following example:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ ant -lib <directory containing spring-boot-antlib-{version-spring-boot}.jar>\n----\n\nTIP: The \"`Using Spring Boot`\" section includes a more complete example of xref:reference:using/build-systems.adoc#using.build-systems.ant[using Apache Ant with `spring-boot-antlib`].\n\n\n\n[[build-tool-plugins.antlib.tasks]]\n== Spring Boot Ant Tasks\n\nOnce the `spring-boot-antlib` namespace has been declared, the following additional tasks are available:\n\n* xref:antlib.adoc#build-tool-plugins.antlib.tasks.exejar[]\n* xref:antlib.adoc#build-tool-plugins.antlib.findmainclass[]\n\n\n\n[[build-tool-plugins.antlib.tasks.exejar]]\n=== Using the \"`exejar`\" Task\n\nYou can use the `exejar` task to create a Spring Boot executable jar.\nThe following attributes are supported by the task:\n\n[cols=\"1,2,2\"]\n|====\n| Attribute | Description | Required\n\n| `destfile`\n| The destination jar file to create\n| Yes\n\n| `classes`\n| The root directory of Java class files\n| Yes\n\n| `start-class`\n| The main application class to run\n| No _(the default is the first class found that declares a `main` method)_\n|====\n\nThe following nested elements can be used with the task:\n\n[cols=\"1,4\"]\n|====\n| Element | Description\n\n| `resources`\n| One or more {url-ant-docs}/Types/resources.html#collection[Resource Collections] describing a set of {url-ant-docs}/Types/resources.html[Resources] that should be added to the content of the created +jar+ file.\n\n| `lib`\n| One or more {url-ant-docs}/Types/resources.html#collection[Resource Collections] that should be added to the set of jar libraries that make up the runtime dependency classpath of the application.\n|====\n\n\n\n[[build-tool-plugins.antlib.tasks.examples]]\n=== Examples\n\nThis section shows two examples of Ant tasks.\n\n.Specify +start-class+\n[source,xml]\n----\n<spring-boot:exejar destfile=\"target/my-application.jar\"\n\t\tclasses=\"target/classes\" start-class=\"com.example.MyApplication\">\n\t<resources>\n\t\t<fileset dir=\"src/main/resources\" />\n\t</resources>\n\t<lib>\n\t\t<fileset dir=\"lib\" />\n\t</lib>\n</spring-boot:exejar>\n----\n\n.Detect +start-class+\n[source,xml]\n----\n<exejar destfile=\"target/my-application.jar\" classes=\"target/classes\">\n\t<lib>\n\t\t<fileset dir=\"lib\" />\n\t</lib>\n</exejar>\n----\n\n\n\n[[build-tool-plugins.antlib.findmainclass]]\n== Using the \"`findmainclass`\" Task\n\nThe `findmainclass` task is used internally by `exejar` to locate a class declaring a `main`.\nIf necessary, you can also use this task directly in your build.\nThe following attributes are supported:\n\n[cols=\"1,2,2\"]\n|====\n| Attribute | Description | Required\n\n| `classesroot`\n| The root directory of Java class files\n| Yes _(unless `mainclass` is specified)_\n\n| `mainclass`\n| Can be used to short-circuit the `main` class search\n| No\n\n| `property`\n| The Ant property that should be set with the result\n| No _(result will be logged if unspecified)_\n|====\n\n\n\n[[build-tool-plugins.antlib.findmainclass.examples]]\n=== Examples\n\nThis section contains three examples of using `findmainclass`.\n\n.Find and log\n[source,xml]\n----\n<findmainclass classesroot=\"target/classes\" />\n----\n\n.Find and set\n[source,xml]\n----\n<findmainclass classesroot=\"target/classes\" property=\"main-class\" />\n----\n\n.Override and set\n[source,xml]\n----\n<findmainclass mainclass=\"com.example.MainClass\" property=\"main-class\" />\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/build-tool-plugin/pages/index.adoc",
    "content": "[[build-tool-plugins]]\n= Build Tool Plugins\n\nSpring Boot provides build tool plugins for Maven and Gradle.\nThe plugins offer a variety of features, including the packaging of executable jars.\nThis section provides more details on both plugins as well as some help should you need to extend an unsupported build system.\nIf you are just getting started, you might want to read xref:reference:using/build-systems.adoc[] from the xref:reference:using/index.adoc[] section first.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/build-tool-plugin/pages/other-build-systems.adoc",
    "content": "[[build-tool-plugins.other-build-systems]]\n= Supporting Other Build Systems\n\nIf you want to use a build tool other than Maven, Gradle, or Ant, you likely need to develop your own plugin.\nExecutable jars need to follow a specific format and certain entries need to be written in an uncompressed form (see the xref:specification:/executable-jar/index.adoc[executable jar format] section in the appendix for details).\n\nThe Spring Boot Maven and Gradle plugins both make use of `spring-boot-loader-tools` to actually generate jars.\nIf you need to, you may use this library directly.\n\n\n\n[[build-tool-plugins.other-build-systems.repackaging-archives]]\n== Repackaging Archives\n\nTo repackage an existing archive so that it becomes a self-contained executable archive, use javadoc:org.springframework.boot.loader.tools.Repackager[].\nThe javadoc:org.springframework.boot.loader.tools.Repackager[] class takes a single constructor argument that refers to an existing jar or war archive.\nUse one of the two available `repackage()` methods to either replace the original file or write to a new destination.\nVarious settings can also be configured on the repackager before it is run.\n\n\n\n[[build-tool-plugins.other-build-systems.nested-libraries]]\n== Nested Libraries\n\nWhen repackaging an archive, you can include references to dependency files by using the javadoc:org.springframework.boot.loader.tools.Libraries[] interface.\nWe do not provide any concrete implementations of javadoc:org.springframework.boot.loader.tools.Libraries[] here as they are usually build-system-specific.\n\nIf your archive already includes libraries, you can use javadoc:org.springframework.boot.loader.tools.Libraries#NONE[].\n\n\n\n[[build-tool-plugins.other-build-systems.finding-main-class]]\n== Finding a Main Class\n\nIf you do not use `Repackager.setMainClass()` to specify a main class, the repackager uses https://asm.ow2.io/[ASM] to read class files and tries to find a suitable class with a `public static void main(String[] args)` method.\nAn exception is thrown if more than one candidate is found.\n\n\n\n[[build-tool-plugins.other-build-systems.example-repackage-implementation]]\n== Example Repackage Implementation\n\nThe following example shows a typical repackage implementation:\n\ninclude-code::MyBuildTool[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/build-tool-plugin/partials/nav-build-tool-plugin.adoc",
    "content": "* xref:build-tool-plugin:index.adoc[]\n+\n--\ninclude::maven-plugin:partial$nav-maven-plugin.adoc[]\n--\n+\n--\ninclude::gradle-plugin:partial$nav-gradle-plugin.adoc[]\n--\n** xref:build-tool-plugin:antlib.adoc[]\n** xref:build-tool-plugin:other-build-systems.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/cli/pages/index.adoc",
    "content": "[[cli]]\n= Spring Boot CLI\n\nThe Spring Boot CLI is a command line tool that you can use to bootstrap a new project from https://start.spring.io or encode a password.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/cli/pages/installation.adoc",
    "content": "[[cli.installation]]\n= Installing the CLI\n\nThe Spring Boot CLI (Command-Line Interface) can be installed manually by using SDKMAN! (the SDK Manager) or by using Homebrew or MacPorts if you are an OSX user.\nSee xref:ROOT:installing.adoc#getting-started.installing.cli[] in the \"`Getting Started`\" section for comprehensive installation instructions.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/cli/pages/using-the-cli.adoc",
    "content": "[[cli.using-the-cli]]\n= Using the CLI\n\nOnce you have installed the CLI, you can run it by typing `spring` and pressing Enter at the command line.\nIf you run `spring` without any arguments, a help screen is displayed, as follows:\n\n[source,shell]\n----\n$ spring\nusage: spring [--help] [--version]\n       <command> [<args>]\n\nAvailable commands are:\n\n  init [options] [location]\n    Initialize a new project using Spring Initializr (start.spring.io)\n\n  encodepassword [options] <password to encode>\n    Encode a password for use with Spring Security\n\n  shell\n    Start a nested shell\n\nCommon options:\n\n  --debug Verbose mode\n    Print additional status information for the command you are running\n\n\nSee 'spring help <command>' for more information on a specific command.\n----\n\nYou can type `spring help` to get more details about any of the supported commands, as shown in the following example:\n\n[source,shell]\n----\n$ spring help init\nspring init - Initialize a new project using Spring Initializr (start.spring.io)\n\nusage: spring init [options] [location]\n\nOption                       Description\n------                       -----------\n-a, --artifact-id <String>   Project coordinates; infer archive name (for\n                               example 'test')\n-b, --boot-version <String>  Spring Boot version (for example '1.2.0.RELEASE')\n--build <String>             Build system to use (for example 'maven' or\n                               'gradle') (default: maven)\n-d, --dependencies <String>  Comma-separated list of dependency identifiers to\n                               include in the generated project\n--description <String>       Project description\n-f, --force                  Force overwrite of existing files\n--format <String>            Format of the generated content (for example\n                               'build' for a build file, 'project' for a\n                               project archive) (default: project)\n-g, --group-id <String>      Project coordinates (for example 'org.test')\n-j, --java-version <String>  Language level (for example '1.8')\n-l, --language <String>      Programming language  (for example 'java')\n--list                       List the capabilities of the service. Use it to\n                               discover the dependencies and the types that are\n                               available\n-n, --name <String>          Project name; infer application name\n-p, --packaging <String>     Project packaging (for example 'jar')\n--package-name <String>      Package name\n-t, --type <String>          Project type. Not normally needed if you use --\n                               build and/or --format. Check the capabilities of\n                               the service (--list) for more details\n--target <String>            URL of the service to use (default: https://start.\n                               spring.io)\n-v, --version <String>       Project version (for example '0.0.1-SNAPSHOT')\n-x, --extract                Extract the project archive. Inferred if a\n                               location is specified without an extension\n\nexamples:\n\n    To list all the capabilities of the service:\n        $ spring init --list\n\n    To creates a default project:\n        $ spring init\n\n    To create a web my-app.zip:\n        $ spring init -d=web my-app.zip\n\n    To create a web/data-jpa gradle project unpacked:\n        $ spring init -d=web,jpa --build=gradle my-dir\n----\n\nThe `version` command provides a quick way to check which version of Spring Boot you are using, as follows:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ spring version\nSpring CLI v{version-spring-boot}\n----\n\n\n\n[[cli.using-the-cli.initialize-new-project]]\n== Initialize a New Project\n\nThe `init` command lets you create a new project by using https://start.spring.io without leaving the shell, as shown in the following example:\n\n[source,shell]\n----\n$ spring init --dependencies=web,data-jpa my-project\nUsing service at https://start.spring.io\nProject extracted to '/Users/developer/example/my-project'\n----\n\nThe preceding example creates a `my-project` directory with a Maven-based project that uses `spring-boot-starter-web` and `spring-boot-starter-data-jpa`.\nYou can list the capabilities of the service by using the `--list` flag, as shown in the following example:\n\n[source,shell]\n----\n$ spring init --list\n=======================================\nCapabilities of https://start.spring.io\n=======================================\n\nAvailable dependencies:\n-----------------------\nactuator - Actuator: Production ready features to help you monitor and manage your application\n...\nweb - Web: Support for full-stack web development, including Tomcat and spring-webmvc\nwebsocket - Websocket: Support for WebSocket development\nws - WS: Support for Spring Web Services\n\nAvailable project types:\n------------------------\ngradle-build -  Gradle Config [format:build, build:gradle]\ngradle-project -  Gradle Project [format:project, build:gradle]\nmaven-build -  Maven POM [format:build, build:maven]\nmaven-project -  Maven Project [format:project, build:maven] (default)\n\n...\n----\n\nThe `init` command supports many options.\nSee the `help` output for more details.\nFor instance, the following command creates a Gradle project that uses Java 17 and `war` packaging:\n\n[source,shell]\n----\n$ spring init --build=gradle --java-version=17 --dependencies=websocket --packaging=war sample-app.zip\nUsing service at https://start.spring.io\nContent saved to 'sample-app.zip'\n----\n\n\n\n[[cli.using-the-cli.embedded-shell]]\n== Using the Embedded Shell\n\nSpring Boot includes command-line completion scripts for the BASH and zsh shells.\nIf you do not use either of these shells (perhaps you are a Windows user), you can use the `shell` command to launch an integrated shell, as shown in the following example:\n\n[source,shell,subs=\"verbatim,quotes,attributes\"]\n----\n$ spring shell\n*Spring Boot* (v{version-spring-boot})\nHit TAB to complete. Type \\'help' and hit RETURN for help, and \\'exit' to quit.\n----\n\nFrom inside the embedded shell, you can run other commands directly:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ version\nSpring CLI v{version-spring-boot}\n----\n\nThe embedded shell supports ANSI color output as well as `tab` completion.\nIf you need to run a native command, you can use the `!` prefix.\nTo exit the embedded shell, press `ctrl-c`.\n\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/cli/partials/nav-cli.adoc",
    "content": "* xref:cli:index.adoc[]\n\n** xref:cli:installation.adoc[]\n** xref:cli:using-the-cli.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/actuator.adoc",
    "content": "[[howto.actuator]]\n= Actuator\n\nSpring Boot includes the Spring Boot Actuator.\nThis section answers questions that often arise from its use.\n\n\n\n[[howto.actuator.change-http-port-or-address]]\n== Change the HTTP Port or Address of the Actuator Endpoints\n\nIn a standalone application, the Actuator HTTP port defaults to the same as the main HTTP port.\nTo make the application listen on a different port, set the external property: configprop:management.server.port[].\nTo listen on a completely different network address (such as when you have an internal network for management and an external one for user applications), you can also set `management.server.address` to a valid IP address to which the server is able to bind.\n\nFor more detail, see the javadoc:org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties[] source code and xref:reference:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[Customizing the Management Server Port] in the \"`Production-Ready Features`\" section.\n\n\n\n[[howto.actuator.customizing-sanitization]]\n== Customizing Sanitization\n\nTo take control over the sanitization, define a javadoc:org.springframework.boot.actuate.endpoint.SanitizingFunction[] bean.\nThe javadoc:org.springframework.boot.actuate.endpoint.SanitizableData[] with which the function is called provides access to the key and value as well as the javadoc:org.springframework.core.env.PropertySource[] from which they came.\nThis allows you to, for example, sanitize every value that comes from a particular property source.\nEach javadoc:org.springframework.boot.actuate.endpoint.SanitizingFunction[] is called in order until a function changes the value of the sanitizable data.\n\n\n\n[[howto.actuator.map-health-indicators-to-metrics]]\n== Map Health Indicators to Micrometer Metrics\n\nSpring Boot health indicators return a javadoc:org.springframework.boot.health.contributor.Status[] type to indicate the overall system health.\nIf you want to monitor or alert on levels of health for a particular application, you can export these statuses as metrics with Micrometer.\nBy default, the status codes \"`UP`\", \"`DOWN`\", \"`OUT_OF_SERVICE`\" and \"`UNKNOWN`\" are used by Spring Boot.\nTo export these, you will need to convert these states to some set of numbers so that they can be used with a Micrometer javadoc:io.micrometer.core.instrument.Gauge[].\n\nThe following example shows one way to write such an exporter:\n\ninclude-code::MyHealthMetricsExportConfiguration[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/aot-cache.adoc",
    "content": "[[howto.aot-cache]]\n= AOT Cache\n:page-aliases: class-data-sharing.adoc\n\nThis section includes information about using AOT cache with Spring Boot applications.\nFor an overview of Spring Boot support for AOT cache, see xref:reference:packaging/aot-cache.adoc[].\n\n\n\n[[howto.aot-cache.buildpacks]]\n== Packaging an Application Using AOT Cache and Buildpacks\n\nSpring Boot's xref:reference:packaging/container-images/cloud-native-buildpacks.adoc[support for Cloud Native Buildpacks] along with the https://paketo.io/docs/reference/java-reference[Paketo Java buildpack] and its https://paketo.io/docs/reference/java-reference/#spring-boot-applications[Spring Boot support] can be used to generate a Docker image containing an AOT Cache-optimized application.\n\nTo enable the AOT Cache in a generated Docker image, you have to use Java 25 or later, and the buildpack environment variable `BP_JVM_AOTCACHE_ENABLED` should be set to `true` when building the image as described in the xref:maven-plugin:build-image.adoc#build-image.examples.builder-configuration[Maven plugin] and xref:gradle-plugin:packaging-oci-image.adoc#build-image.examples.builder-configuration[Gradle plugin] documentation.\nThis will cause the buildpack to do a training run of the application, save the AOT Cache in the image, and use the AOT Cache when launching the application.\n\nThe Paketo Buildpack for Spring Boot https://github.com/paketo-buildpacks/spring-boot?tab=readme-ov-file#configuration[documentation] has information on other configuration options that can be enabled with builder environment variables, like `TRAINING_RUN_JAVA_TOOL_OPTIONS` that allows to override the default `JAVA_TOOL_OPTIONS`, only for the AOT Cache training run.\n\n\n\n[[howto.aot-cache.dockerfiles]]\n== Packaging an Application Using AOT Cache and Dockerfiles\n\nIf you don't want to use Cloud Native Buildpacks, it is possible to use AOT cache (or CDS) with a `Dockerfile`.\nFor more information about that, please see the xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles.aot-cache[Dockerfiles reference documentation].\n\n\n\n[[howto.aot-cache.training-run-configuration]]\n== Preventing Remote Services Interaction During the Training Run\n\nWhen performing the training run, it may be needed to customize the Spring Boot application configuration to prevent connections to remote services that may happen before the Spring lifecycle is started.\nThis can typically happen with early database interactions and can be handled via related configuration that can be applied by default to your application (or specifically to the training run) to prevent such interactions, see https://github.com/spring-projects/spring-lifecycle-smoke-tests/blob/main/README.adoc#training-run-configuration[related documentation].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/aot.adoc",
    "content": "[[howto.aot]]\n= Ahead-of-Time Processing\n\nA number of questions often arise when people use the ahead-of-time processing of Spring Boot applications.\nThis section addresses those questions.\n\n\n\n[[howto.aot.conditions]]\n== Conditions\n\nAhead-of-time processing optimizes the application and evaluates javadoc:org.springframework.context.annotation.Conditional[format=annotation] annotations based on the environment at build time.\nxref:reference:features/profiles.adoc[Profiles] are implemented through conditions and are therefore affected, too.\n\nIf you want beans that are created based on a condition in an ahead-of-time optimized application, you have to set up the environment when building the application.\nThe beans which are created while ahead-of-time processing at build time are then always created when running the application and can't be switched off.\nTo do this, you can set the profiles which should be used when building the application.\n\nFor Maven, this works by setting the `profiles` configuration of the `spring-boot-maven-plugin:process-aot` execution:\n\n[source,xml]\n----\n<profile>\n    <id>native</id>\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-maven-plugin</artifactId>\n                    <executions>\n                        <execution>\n                            <id>process-aot</id>\n                            <configuration>\n                                <profiles>profile-a,profile-b</profiles>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</profile>\n----\n\nFor Gradle, you need to configure the `ProcessAot` task:\n\n[source,gradle]\n----\ntasks.withType(org.springframework.boot.gradle.tasks.aot.ProcessAot).configureEach {\n    args('--spring.profiles.active=profile-a,profile-b')\n}\n----\n\nProfiles which only change configuration properties that don't influence conditions are supported without limitations when running ahead-of-time optimized applications.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/application.adoc",
    "content": "[[howto.application]]\n= Spring Boot Application\n\nThis section includes topics relating directly to Spring Boot applications.\n\n\n\n[[howto.application.failure-analyzer]]\n== Create Your Own FailureAnalyzer\n\njavadoc:org.springframework.boot.diagnostics.FailureAnalyzer[] is a great way to intercept an exception on startup and turn it into a human-readable message, wrapped in a javadoc:org.springframework.boot.diagnostics.FailureAnalysis[].\nSpring Boot provides such an analyzer for application-context-related exceptions, JSR-303 validations, and more.\nYou can also create your own.\n\njavadoc:org.springframework.boot.diagnostics.AbstractFailureAnalyzer[] is a convenient extension of javadoc:org.springframework.boot.diagnostics.FailureAnalyzer[] that checks the presence of a specified exception type in the exception to handle.\nYou can extend from that so that your implementation gets a chance to handle the exception only when it is actually present.\nIf, for whatever reason, you cannot handle the exception, return `null` to give another implementation a chance to handle the exception.\n\njavadoc:org.springframework.boot.diagnostics.FailureAnalyzer[] implementations must be registered in `META-INF/spring.factories`.\nThe following example registers `ProjectConstraintViolationFailureAnalyzer`:\n\n[source,properties]\n----\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\ncom.example.ProjectConstraintViolationFailureAnalyzer\n----\n\nNOTE: If you need access to the javadoc:org.springframework.beans.factory.BeanFactory[] or the javadoc:org.springframework.core.env.Environment[], declare them as constructor arguments in your javadoc:org.springframework.boot.diagnostics.FailureAnalyzer[] implementation.\n\n\n\n[[howto.application.troubleshoot-auto-configuration]]\n== Troubleshoot Auto-configuration\n\nThe Spring Boot auto-configuration tries its best to \"`do the right thing`\", but sometimes things fail, and it can be hard to tell why.\n\nThere is a really useful javadoc:org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport[] available in any Spring Boot javadoc:org.springframework.context.ApplicationContext[].\nYou can see it if you enable `DEBUG` logging output.\nIf you use the `spring-boot-actuator` (see the xref:actuator.adoc[] section), there is also a `conditions` endpoint that renders the report in JSON.\nUse that endpoint to debug the application and see what features have been added (and which have not been added) by Spring Boot at runtime.\n\nMany more questions can be answered by looking at the source code and the API documentation.\nWhen reading the code, remember the following rules of thumb:\n\n* Look for classes called `+*AutoConfiguration+` and read their sources.\n  Pay special attention to the `+@Conditional*+` annotations to find out what features they enable and when.\n  Add `--debug` to the command line or the System property `-Ddebug` to get a log on the console of all the auto-configuration decisions that were made in your app.\n  In a running application with actuator enabled, look at the `conditions` endpoint (`/actuator/conditions` or the JMX equivalent) for the same information.\n* Look for classes that are javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] (such as javadoc:org.springframework.boot.web.server.autoconfigure.ServerProperties[]) and read from there the available external configuration options.\n  The javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] annotation has a `name` attribute that acts as a prefix to external properties.\n  Thus, javadoc:org.springframework.boot.web.server.autoconfigure.ServerProperties[] has `prefix=\"server\"` and its configuration properties are `server.port`, `server.address`, and others.\n  In a running application with actuator enabled, look at the `configprops` endpoint.\n* Look for uses of the `bind` method on the javadoc:org.springframework.boot.context.properties.bind.Binder[] to pull configuration values explicitly out of the javadoc:org.springframework.core.env.Environment[] in a relaxed manner.\n  It is often used with a prefix.\n* Look for javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotations that bind directly to the javadoc:org.springframework.core.env.Environment[].\n* Look for javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnExpression[format=annotation] annotations that switch features on and off in response to SpEL expressions, normally evaluated with placeholders resolved from the javadoc:org.springframework.core.env.Environment[].\n\n\n\n[[howto.application.customize-the-environment-or-application-context]]\n== Customize the Environment or ApplicationContext Before It Starts\n\nA javadoc:org.springframework.boot.SpringApplication[] has javadoc:org.springframework.context.ApplicationListener[] and javadoc:org.springframework.context.ApplicationContextInitializer[] implementations that are used to apply customizations to the context or environment.\nSpring Boot loads a number of such customizations for use internally from `META-INF/spring.factories`.\nThere is more than one way to register additional customizations:\n\n* Programmatically, per application, by calling the `addListeners` and `addInitializers` methods on javadoc:org.springframework.boot.SpringApplication[] before you run it.\n* Declaratively, for all applications, by adding a `META-INF/spring.factories` and packaging a jar file that the applications all use as a library.\n\nThe javadoc:org.springframework.boot.SpringApplication[] sends some special javadoc:org.springframework.test.context.event.ApplicationEvents[] to the listeners (some even before the context is created) and then registers the listeners for events published by the javadoc:org.springframework.context.ApplicationContext[] as well.\nSee xref:reference:features/spring-application.adoc#features.spring-application.application-events-and-listeners[] in the \"`Spring Boot Features`\" section for a complete list.\n\nIt is also possible to customize the javadoc:org.springframework.core.env.Environment[] before the application context is refreshed by using javadoc:org.springframework.boot.EnvironmentPostProcessor[].\nEach implementation should be registered in `META-INF/spring.factories`, as shown in the following example:\n\n[source]\n----\norg.springframework.boot.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor\n----\n\nThe implementation can load arbitrary files and add them to the javadoc:org.springframework.core.env.Environment[].\nFor instance, the following example loads a YAML configuration file from the classpath:\n\ninclude-code::MyEnvironmentPostProcessor[]\n\nTIP: The javadoc:org.springframework.core.env.Environment[] has already been prepared with all the usual property sources that Spring Boot loads by default.\nIt is therefore possible to get the location of the file from the environment.\nThe preceding example adds the `custom-resource` property source at the end of the list so that a key defined in any of the usual other locations takes precedence.\nA custom implementation may define another order.\n\nCAUTION: While using javadoc:org.springframework.context.annotation.PropertySource[format=annotation] on your javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] may seem to be a convenient way to load a custom resource in the javadoc:org.springframework.core.env.Environment[], we do not recommend it.\nSuch property sources are not added to the javadoc:org.springframework.core.env.Environment[] until the application context is being refreshed.\nThis is too late to configure certain properties such as `+logging.*+` and `+spring.main.*+` which are read before refresh begins.\n\n\n\n[[howto.application.context-hierarchy]]\n== Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)\n\nYou can use the javadoc:org.springframework.boot.builder.SpringApplicationBuilder[] class to create parent/child javadoc:org.springframework.context.ApplicationContext[] hierarchies.\nSee xref:reference:features/spring-application.adoc#features.spring-application.fluent-builder-api[] in the \"`Spring Boot Features`\" section for more information.\n\n\n\n[[howto.application.non-web-application]]\n== Create a Non-web Application\n\nNot all Spring applications have to be web applications (or web services).\nIf you want to execute some code in a `main` method but also bootstrap a Spring application to set up the infrastructure to use, you can use the javadoc:org.springframework.boot.SpringApplication[] features of Spring Boot.\nA javadoc:org.springframework.boot.SpringApplication[] changes its javadoc:org.springframework.context.ApplicationContext[] class, depending on whether it thinks it needs a web application or not.\nThe first thing you can do to help it is to leave server-related dependencies (such as the servlet API) off the classpath.\nIf you cannot do that (for example, if you run two applications from the same code base) then you can explicitly call `setWebApplicationType(WebApplicationType.NONE)` on your javadoc:org.springframework.boot.SpringApplication[] instance or set the `applicationContextClass` property (through the Java API or with external properties).\nApplication code that you want to run as your business logic can be implemented as a javadoc:org.springframework.boot.CommandLineRunner[] and dropped into the context as a javadoc:org.springframework.context.annotation.Bean[format=annotation] definition.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/batch.adoc",
    "content": "[[howto.batch]]\n= Batch Applications\n\nA number of questions often arise when people use Spring Batch from within a Spring Boot application.\nThis section addresses those questions.\n\n\n\n[[howto.batch.specifying-a-data-source]]\n== Specifying a Batch Data Source\n\nBatch applications that store job details in an SQL database require a javadoc:javax.sql.DataSource[] bean.\nA single javadoc:javax.sql.DataSource[] bean is required by default.\nTo have Spring Batch use a javadoc:javax.sql.DataSource[] other than the application’s main javadoc:javax.sql.DataSource[], declare a javadoc:javax.sql.DataSource[] bean, annotating its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.batch.jdbc.autoconfigure.BatchDataSource[format=annotation].\nIf you do so and want two data sources (for example by retaining the main auto-configured javadoc:javax.sql.DataSource[]), set the `defaultCandidate` attribute of the javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation to `false`.\n\n\n\n[[howto.batch.specifying-a-transaction-manager]]\n== Specifying a Batch Transaction Manager\n\nSimilar to xref:batch.adoc#howto.batch.specifying-a-data-source[], you can define a javadoc:org.springframework.transaction.PlatformTransactionManager[] for use in batch processing by annotating its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.batch.autoconfigure.BatchTransactionManager[format=annotation].\nIf you do so and want two transaction managers (for example by retaining the auto-configured javadoc:org.springframework.transaction.PlatformTransactionManager[]), set the `defaultCandidate` attribute of the javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation to `false`.\n\n\n\n[[howto.batch.specifying-a-task-executor]]\n== Specifying a Batch Task Executor\n\nSimilar to xref:batch.adoc#howto.batch.specifying-a-data-source[], you can define a javadoc:org.springframework.core.task.TaskExecutor[] for use in batch processing by annotating its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.batch.autoconfigure.BatchTaskExecutor[format=annotation].\nIf you do so and want two task executors (for example by retaining the auto-configured javadoc:org.springframework.core.task.TaskExecutor[]), set the `defaultCandidate` attribute of the javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation to `false`.\n\n\n\n[[howto.batch.running-from-the-command-line]]\n== Running From the Command Line\n\nSpring Boot converts any command line argument starting with `--` to a property to add to the javadoc:org.springframework.core.env.Environment[], see xref:reference:features/external-config.adoc#features.external-config.command-line-args[accessing command line properties].\nThis should not be used to pass arguments to batch jobs.\nTo specify batch arguments on the command line, use the regular format (that is without `--`), as shown in the following example:\n\n[source,shell]\n----\n$ java -jar myapp.jar someParameter=someValue anotherParameter=anotherValue\n----\n\nIf you specify a property of the javadoc:org.springframework.core.env.Environment[] on the command line, it is ignored by the job.\nConsider the following command:\n\n[source,shell]\n----\n$ java -jar myapp.jar --server.port=7070 someParameter=someValue\n----\n\nThis provides only one argument to the batch job: `someParameter=someValue`.\n\n\n\n[[howto.batch.restarting-a-failed-job]]\n== Restarting a Stopped or Failed Job\n\nTo restart a failed javadoc:org.springframework.batch.core.job.Job[], all parameters (identifying and non-identifying) must be re-specified on the command line.\nNon-identifying parameters are *not* copied from the previous execution.\nThis allows them to be modified or removed.\n\nNOTE: When you're using a custom javadoc:org.springframework.batch.core.job.parameters.JobParametersIncrementer[], you have to gather all parameters managed by the incrementer to restart a failed execution.\n\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/build.adoc",
    "content": "[[howto.build]]\n= Build\n\nSpring Boot includes build plugins for Maven and Gradle.\nThis section answers common questions about these plugins.\n\n\n\n[[howto.build.generate-info]]\n== Generate Build Information\n\nBoth the Maven plugin and the Gradle plugin allow generating build information containing the coordinates, name, and version of the project.\nThe plugins can also be configured to add additional properties through configuration.\nWhen such a file is present, Spring Boot auto-configures a javadoc:org.springframework.boot.info.BuildProperties[] bean.\n\nTo generate build information with Maven, add an execution for the `build-info` goal, as shown in the following example:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t<version>{version-spring-boot}</version>\n\t\t\t<executions>\n\t\t\t\t<execution>\n\t\t\t\t\t<goals>\n\t\t\t\t\t\t<goal>build-info</goal>\n\t\t\t\t\t</goals>\n\t\t\t\t</execution>\n\t\t\t</executions>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\nTIP: See the xref:maven-plugin:build-info.adoc[Spring Boot Maven Plugin documentation] for more details.\n\nThe following example does the same with Gradle:\n\n[source,gradle]\n----\nspringBoot {\n\tbuildInfo()\n}\n----\n\nTIP: See the xref:gradle-plugin:integrating-with-actuator.adoc[Spring Boot Gradle Plugin documentation] for more details.\n\n\n\n[[howto.build.generate-git-info]]\n== Generate Git Information\n\nBoth Maven and Gradle allow generating a `git.properties` file containing information about the state of your `git` source code repository when the project was built.\n\nFor Maven users, the `spring-boot-starter-parent` POM includes a pre-configured plugin to generate a `git.properties` file.\nTo use it, add the following declaration for the {url-git-commit-id-maven-plugin}[`Git Commit Id Plugin`] to your POM:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>io.github.git-commit-id</groupId>\n\t\t\t<artifactId>git-commit-id-maven-plugin</artifactId>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\nGradle users can achieve the same result by using the https://plugins.gradle.org/plugin/com.gorylenko.gradle-git-properties[`gradle-git-properties`] plugin, as shown in the following example:\n\n[source,gradle]\n----\nplugins {\n\tid \"com.gorylenko.gradle-git-properties\" version \"2.4.1\"\n}\n----\n\nBoth the Maven and Gradle plugins allow the properties that are included in `git.properties` to be configured.\n\nTIP: The commit time in `git.properties` is expected to match the following format: `yyyy-MM-dd'T'HH:mm:ssZ`.\nThis is the default format for both plugins listed above.\nUsing this format lets the time be parsed into a javadoc:java.util.Date[] and its format, when serialized to JSON, to be controlled by Jackson's date serialization configuration settings.\n\n\n\n[[howto.build.generate-cyclonedx-sbom]]\n== Generate a CycloneDX SBOM\n\nBoth Maven and Gradle allow generating a CycloneDX SBOM at project build time.\n\nFor Maven users, the `spring-boot-starter-parent` POM includes a pre-configured plugin to generate the SBOM.\nTo use it, add the following declaration for the {url-cyclonedx-docs-maven-plugin}[`cyclonedx-maven-plugin`] to your POM:\n\n[source,xml]\n----\n<build>\n    <plugins>\n        <plugin>\n            <groupId>org.cyclonedx</groupId>\n            <artifactId>cyclonedx-maven-plugin</artifactId>\n        </plugin>\n    </plugins>\n</build>\n----\n\nGradle users can achieve the same result by using the {url-cyclonedx-docs-gradle-plugin}[`cyclonedx-gradle-plugin`] plugin, as shown in the following example:\n\n[source,gradle]\n----\nplugins {\n    id 'org.cyclonedx.bom' version '3.0.0'\n}\n----\n\n\n\n[[howto.build.customize-dependency-versions]]\n== Customize Dependency Versions\n\nThe `spring-boot-dependencies` POM manages the versions of common dependencies.\nThe Spring Boot plugins for Maven and Gradle allow these managed dependency versions to be customized using build properties.\n\nWARNING: Each Spring Boot release is designed and tested against this specific set of third-party dependencies.\nOverriding versions may cause compatibility issues.\n\nTo override dependency versions with Maven, see xref:maven-plugin:using.adoc[] in the Maven plugin's documentation.\n\nTo override dependency versions in Gradle, see xref:gradle-plugin:managing-dependencies.adoc#managing-dependencies.dependency-management-plugin.customizing[] in the Gradle plugin's documentation.\n\n\n\n[[howto.build.create-an-executable-jar-with-maven]]\n== Create an Executable JAR with Maven\n\nThe `spring-boot-maven-plugin` can be used to create an executable \"`fat`\" JAR.\nIf you use the `spring-boot-starter-parent` POM, you can declare the plugin and your jars are repackaged as follows:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\nIf you do not use the parent POM, you can still use the plugin.\nHowever, you must additionally add an `<executions>` section, as follows:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t<version>{version-spring-boot}</version>\n\t\t\t<executions>\n\t\t\t\t<execution>\n\t\t\t\t\t<goals>\n\t\t\t\t\t\t<goal>repackage</goal>\n\t\t\t\t\t</goals>\n\t\t\t\t</execution>\n\t\t\t</executions>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\nSee the xref:maven-plugin:packaging.adoc#packaging.repackage-goal[plugin documentation] for full usage details.\n\n\n\n[[howto.build.use-a-spring-boot-application-as-dependency]]\n== Use a Spring Boot Application as a Dependency\n\nLike a war file, a Spring Boot application is not intended to be used as a dependency.\nIf your application contains classes that you want to share with other projects, the recommended approach is to move that code into a separate module.\nThe separate module can then be depended upon by your application and other projects.\n\nIf you cannot rearrange your code as recommended above, Spring Boot's Maven and Gradle plugins must be configured to produce a separate artifact that is suitable for use as a dependency.\nThe executable archive cannot be used as a dependency as the xref:specification:executable-jar/nested-jars.adoc#appendix.executable-jar.nested-jars.jar-structure[executable jar format] packages application classes in `BOOT-INF/classes`.\nThis means that they cannot be found when the executable jar is used as a dependency.\n\nTo produce the two artifacts, one that can be used as a dependency and one that is executable, a classifier must be specified.\nThis classifier is applied to the name of the executable archive, leaving the default archive for use as a dependency.\n\nTo configure a classifier of `exec` in Maven, you can use the following configuration:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t<configuration>\n\t\t\t\t<classifier>exec</classifier>\n\t\t\t</configuration>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\n\n\n[[howto.build.extract-specific-libraries-when-an-executable-jar-runs]]\n== Extract Specific Libraries When an Executable Jar Runs\n\nMost nested libraries in an executable jar do not need to be unpacked in order to run.\nHowever, certain libraries can have problems.\nFor example, JRuby includes its own nested jar support, which assumes that the `jruby-complete.jar` is always directly available as a file in its own right.\n\nTo deal with any problematic libraries, you can flag that specific nested jars should be automatically unpacked when the executable jar first runs.\nSuch nested jars are written beneath the temporary directory identified by the `java.io.tmpdir` system property.\n\nWARNING: Care should be taken to ensure that your operating system is configured so that it will not delete the jars that have been unpacked to the temporary directory while the application is still running.\n\nFor example, to indicate that JRuby should be flagged for unpacking by using the Maven Plugin, you would add the following configuration:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t<configuration>\n\t\t\t\t<requiresUnpack>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.jruby</groupId>\n\t\t\t\t\t\t<artifactId>jruby-complete</artifactId>\n\t\t\t\t\t</dependency>\n\t\t\t\t</requiresUnpack>\n\t\t\t</configuration>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\n\n\n[[howto.build.create-a-nonexecutable-jar]]\n== Create a Non-executable JAR with Exclusions\n\nOften, if you have an executable and a non-executable jar as two separate build products, the executable version has additional configuration files that are not needed in a library jar.\nFor example, the `application.yaml` configuration file might be excluded from the non-executable JAR.\n\nIn Maven, the executable jar must be the main artifact and you can add a classified jar for the library, as follows:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t</plugin>\n\t\t<plugin>\n\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t<executions>\n\t\t\t\t<execution>\n\t\t\t\t\t<id>lib</id>\n\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t<goals>\n\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t</goals>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<classifier>lib</classifier>\n\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t<exclude>application.yaml</exclude>\n\t\t\t\t\t\t</excludes>\n\t\t\t\t\t</configuration>\n\t\t\t\t</execution>\n\t\t\t</executions>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\n\n\n[[howto.build.remote-debug-maven]]\n== Remote Debug a Spring Boot Application Started with Maven\n\nTo attach a remote debugger to a Spring Boot application that was started with Maven, you can use the `jvmArguments` property of the xref:maven-plugin:index.adoc[maven plugin].\n\nSee xref:maven-plugin:run.adoc#run.examples.debug[this example] for more details.\n\n\n\n[[howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib]]\n== Build an Executable Archive From Ant without Using spring-boot-antlib\n\nTo build with Ant, you need to grab dependencies, compile, and then create a jar or war archive.\nTo make it executable, you can either use the `spring-boot-antlib` module or you can follow these instructions:\n\n. If you are building a jar, package the application's classes and resources in a nested `BOOT-INF/classes` directory.\n  If you are building a war, package the application's classes in a nested `WEB-INF/classes` directory as usual.\n. Add the runtime dependencies in a nested `BOOT-INF/lib` directory for a jar or `WEB-INF/lib` for a war.\n  Remember *not* to compress the entries in the archive.\n. Add the `provided` (embedded container) dependencies in a nested `BOOT-INF/lib` directory for a jar or `WEB-INF/lib-provided` for a war.\n  Remember *not* to compress the entries in the archive.\n. Add the `spring-boot-loader` classes at the root of the archive (so that the `Main-Class` is available).\n. Use the appropriate launcher (such as javadoc:org.springframework.boot.loader.launch.JarLauncher[] for a jar file) as a `Main-Class` attribute in the manifest and specify the other properties it needs as manifest entries -- principally, by setting a `Start-Class` property.\n\nThe following example shows how to build an executable archive with Ant:\n\n[source,xml]\n----\n<target name=\"build\" depends=\"compile\">\n\t<jar destfile=\"target/${ant.project.name}-${spring-boot.version}.jar\" compress=\"false\">\n\t\t<mappedresources>\n\t\t\t<fileset dir=\"target/classes\" />\n\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/classes/*\"/>\n\t\t</mappedresources>\n\t\t<mappedresources>\n\t\t\t<fileset dir=\"src/main/resources\" erroronmissingdir=\"false\"/>\n\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/classes/*\"/>\n\t\t</mappedresources>\n\t\t<mappedresources>\n\t\t\t<fileset dir=\"${lib.dir}/runtime\" />\n\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/lib/*\"/>\n\t\t</mappedresources>\n\t\t<zipfileset src=\"${lib.dir}/loader/spring-boot-loader-jar-${spring-boot.version}.jar\" />\n\t\t<manifest>\n\t\t\t<attribute name=\"Main-Class\" value=\"org.springframework.boot.loader.launch.JarLauncher\" />\n\t\t\t<attribute name=\"Start-Class\" value=\"${start-class}\" />\n\t\t</manifest>\n\t</jar>\n</target>\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/data-access.adoc",
    "content": "[[howto.data-access]]\n= Data Access\n\nSpring Boot includes a number of starters for working with data sources.\nThis section answers questions related to doing so.\n\n\n\n[[howto.data-access.configure-custom-datasource]]\n== Configure a Custom DataSource\n\nTo configure your own javadoc:javax.sql.DataSource[], define a javadoc:org.springframework.context.annotation.Bean[format=annotation] of that type in your configuration.\nSpring Boot reuses your javadoc:javax.sql.DataSource[] anywhere one is required, including database initialization.\nIf you need to externalize some settings, you can bind your javadoc:javax.sql.DataSource[] to the environment (see xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.third-party-configuration[]).\n\nThe following example shows how to define a data source in a bean:\n\ninclude-code::custom/MyDataSourceConfiguration[]\n\nThe following example shows how to define a data source by setting its properties:\n\n[configprops%novalidate,yaml]\n----\napp:\n  datasource:\n    url: \"jdbc:h2:mem:mydb\"\n    username: \"sa\"\n    pool-size: 30\n----\n\nAssuming that `SomeDataSource` has regular JavaBean properties for the URL, the username, and the pool size, these settings are bound automatically before the javadoc:javax.sql.DataSource[] is made available to other components.\n\nSpring Boot also provides a utility builder class, called javadoc:org.springframework.boot.jdbc.DataSourceBuilder[], that can be used to create one of the standard data sources (if it is on the classpath).\nThe builder can detect which one to use based on what is available on the classpath.\nIt also auto-detects the driver based on the JDBC URL.\n\nThe following example shows how to create a data source by using a javadoc:org.springframework.boot.jdbc.DataSourceBuilder[]:\n\ninclude-code::builder/MyDataSourceConfiguration[]\n\nTo run an app with that javadoc:javax.sql.DataSource[], all you need is the connection information.\nPool-specific settings can also be provided.\nCheck the implementation that is going to be used at runtime for more details.\n\nThe following example shows how to define a JDBC data source by setting properties:\n\n[configprops%novalidate,yaml]\n----\napp:\n  datasource:\n    url: \"jdbc:mysql://localhost/test\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n    pool-size: 30\n----\n\nHowever, there is a catch due to the method's javadoc:javax.sql.DataSource[] return type.\nThis hides the actual type of the connection pool so no configuration property metadata is generated for your custom javadoc:javax.sql.DataSource[] and no auto-completion is available in your IDE.\nTo address this problem, use the builder's `type(Class)` method to specify the type of javadoc:javax.sql.DataSource[] to be built and update the method's return type.\nFor example, the following shows how to create a javadoc:com.zaxxer.hikari.HikariDataSource[] with javadoc:org.springframework.boot.jdbc.DataSourceBuilder[]:\n\ninclude-code::simple/MyDataSourceConfiguration[]\n\nUnfortunately, this basic setup does not work because Hikari has no `url` property.\nInstead, it has a `jdbc-url` property which means that you must rewrite your configuration as follows:\n\n[configprops%novalidate,yaml]\n----\napp:\n  datasource:\n    jdbc-url: \"jdbc:mysql://localhost/test\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n    pool-size: 30\n----\n\nTo address this problem, make use of javadoc:org.springframework.boot.jdbc.autoconfigure.DataSourceProperties[] which will handle the `url` to `jdbc-url` translation for you.\nYou can initialize a javadoc:org.springframework.boot.jdbc.DataSourceBuilder[] from the state of any javadoc:org.springframework.boot.jdbc.autoconfigure.DataSourceProperties[] object using its `initializeDataSourceBuilder()` method.\nYou could inject the javadoc:org.springframework.boot.jdbc.autoconfigure.DataSourceProperties[] that Spring Boot creates automatically, however, that would split your configuration across `+spring.datasource.*+` and `+app.datasource.*+`.\nTo avoid this, define a custom javadoc:org.springframework.boot.jdbc.autoconfigure.DataSourceProperties[] with a custom configuration properties prefix, as shown in the following example:\n\ninclude-code::configurable/MyDataSourceConfiguration[]\n\nThis setup is equivalent to what Spring Boot does for you by default, except that the pool's type is specified in code and its settings are exposed as `app.datasource.configuration.*` properties.\njavadoc:org.springframework.boot.jdbc.autoconfigure.DataSourceProperties[] takes care of the `url` to `jdbc-url` translation, so you can configure it as follows:\n\n[configprops%novalidate,yaml]\n----\napp:\n  datasource:\n    url: \"jdbc:mysql://localhost/test\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n    configuration:\n      maximum-pool-size: 30\n----\n\nNote that, as the custom configuration specifies in code that Hikari should be used, `app.datasource.type` will have no effect.\n\nAs described in xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[], javadoc:org.springframework.boot.jdbc.DataSourceBuilder[] supports several different connection pools.\nTo use a pool other than Hikari, add it to the classpath, use the `type(Class)` method to specify the pool class to use, and update the javadoc:org.springframework.context.annotation.Bean[format=annotation] method's return type to match.\nThis will also provide you with configuration property metadata for the specific connection pool that you've chosen.\n\nTIP: Spring Boot will expose Hikari-specific settings to `spring.datasource.hikari`.\nThis example uses a more generic `configuration` sub namespace as the example does not support multiple datasource implementations.\n\nSee xref:reference:data/sql.adoc#data.sql.datasource[] and the {code-spring-boot-jdbc-src}/autoconfigure/DataSourceAutoConfiguration.java[`DataSourceAutoConfiguration`] class for more details.\n\n\n\n[[howto.data-access.configure-two-datasources]]\n== Configure Two DataSources\n\nTo define an additional javadoc:javax.sql.DataSource[], an approach that's similar to the previous section can be used.\nA key difference is that the javadoc:javax.sql.DataSource[] javadoc:org.springframework.context.annotation.Bean[format=annotation] must be declared with `defaultCandidate=false`.\nThis prevents the auto-configured javadoc:javax.sql.DataSource[] from backing off.\n\nNOTE: The {url-spring-framework-docs}/core/beans/dependencies/factory-autowire.html#beans-factory-autowire-candidate[Spring Framework reference documentation] describes this feature in more details.\n\nTo allow the additional javadoc:javax.sql.DataSource[] to be injected where it's needed, also annotate it with javadoc:org.springframework.beans.factory.annotation.Qualifier[format=annotation] as shown in the following example:\n\ninclude-code::MyAdditionalDataSourceConfiguration[]\n\nTo consume the additional javadoc:javax.sql.DataSource[], annotate the injection point with the same javadoc:org.springframework.beans.factory.annotation.Qualifier[format=annotation].\n\nThe auto-configured and additional data sources can be configured as follows:\n\n[configprops%novalidate,yaml]\n----\nspring:\n  datasource:\n    url: \"jdbc:mysql://localhost/first\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n    configuration:\n      maximum-pool-size: 30\napp:\n  datasource:\n    url: \"jdbc:mysql://localhost/second\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n    max-total: 30\n----\n\nMore advanced, implementation-specific, configuration of the auto-configured javadoc:javax.sql.DataSource[] is available through the `spring.datasource.configuration.*` properties.\nYou can apply the same concept to the additional javadoc:javax.sql.DataSource[] as well, as shown in the following example:\n\ninclude-code::MyCompleteAdditionalDataSourceConfiguration[]\n\nThe preceding example configures the additional data source with the same logic as Spring Boot would use in auto-configuration.\nNote that the `app.datasource.configuration.*` properties provide advanced settings based on the chosen implementation.\n\nAs with xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[configuring a single custom javadoc:javax.sql.DataSource[]], the type of one or both of the javadoc:javax.sql.DataSource[] beans can be customized using the `type(Class)` method on javadoc:org.springframework.boot.jdbc.DataSourceBuilder[].\nSee xref:reference:data/sql.adoc#data.sql.datasource.connection-pool[] for details of the supported types.\n\n\n\n[[howto.data-access.spring-data-repositories]]\n== Use Spring Data Repositories\n\nSpring Data can create implementations of javadoc:org.springframework.data.repository.Repository[] interfaces of various flavors.\nSpring Boot handles all of that for you, as long as those javadoc:org.springframework.data.repository.Repository[] implementations are included in one of the xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages], typically the package (or a sub-package) of your main application class that is annotated with javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] or javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation].\n\nFor many applications, all you need is to put the right Spring Data dependencies on your classpath.\nThere is a `spring-boot-starter-data-jpa` for JPA, `spring-boot-starter-data-mongodb` for Mongodb, and various other starters for supported technologies.\nTo get started, create some repository interfaces to handle your javadoc:jakarta.persistence.Entity[format=annotation] objects.\n\nSpring Boot determines the location of your javadoc:org.springframework.data.repository.Repository[] implementations by scanning the xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages].\nFor more control, use the `@Enable…Repositories` annotations from Spring Data.\n\nFor more about Spring Data, see the {url-spring-data-site}[Spring Data project page].\n\n\n\n[[howto.data-access.separate-entity-definitions-from-spring-configuration]]\n== Separate @Entity Definitions from Spring Configuration\n\nSpring Boot determines the location of your javadoc:jakarta.persistence.Entity[format=annotation] definitions by scanning the xref:reference:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages].\nFor more control, use the javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] annotation, as shown in the following example:\n\ninclude-code::MyApplication[]\n\n\n\n[[howto.data-access.filter-scanned-entity-definitions]]\n== Filter Scanned @Entity Definitions\n\nIt is possible to filter the javadoc:jakarta.persistence.Entity[format=annotation] definitions using a javadoc:org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter[] bean.\nThis can be useful in tests when only a sub-set of the available entities should be considered.\nIn the following example, only entities from the `com.example.app.customer` package are included:\n\ninclude-code::MyEntityScanConfiguration[]\n\n\n\n[[howto.data-access.jpa-properties]]\n== Configure JPA Properties\n\nSpring Data JPA already provides some vendor-independent configuration options (such as those for SQL logging), and Spring Boot exposes those options and a few more for Hibernate as external configuration properties.\nSome of them are automatically detected according to the context so you should not have to set them.\n\nThe `spring.jpa.hibernate.ddl-auto` is a special case, because, depending on runtime conditions, it has different defaults.\nIf an embedded database is used and no schema manager (such as Liquibase or Flyway) is handling the javadoc:javax.sql.DataSource[], it defaults to `create-drop`.\nIn all other cases, it defaults to `none`.\n\nThe dialect to use is detected by the JPA provider.\nIf you prefer to set the dialect yourself, set the configprop:spring.jpa.database-platform[] property.\n\nThe most common options to set are shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  jpa:\n    hibernate:\n      naming:\n        physical-strategy: \"com.example.MyPhysicalNamingStrategy\"\n    show-sql: true\n----\n\nIn addition, all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties (with the prefix stripped) when the local javadoc:jakarta.persistence.EntityManagerFactory[] is created.\n\n[WARNING]\n====\nYou need to ensure that names defined under `+spring.jpa.properties.*+` exactly match those expected by your JPA provider.\nSpring Boot will not attempt any kind of relaxed binding for these entries.\n\nFor example, if you want to configure Hibernate's batch size you must use `+spring.jpa.properties.hibernate.jdbc.batch_size+`.\nIf you use other forms, such as `batchSize` or `batch-size`, Hibernate will not apply the setting.\n====\n\nTIP: If you need to apply advanced customization to Hibernate properties, consider registering a javadoc:org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer[] bean that will be invoked prior to creating the javadoc:jakarta.persistence.EntityManagerFactory[].\nThis takes precedence over anything that is applied by the auto-configuration.\n\n\n\n[[howto.data-access.configure-hibernate-naming-strategy]]\n== Configure Hibernate Naming Strategy\n\nHibernate uses {url-hibernate-userguide}#naming[two different naming strategies] to map names from the object model to the corresponding database names.\nThe fully qualified class name of the physical and the implicit strategy implementations can be configured by setting the `spring.jpa.hibernate.naming.physical-strategy` and `spring.jpa.hibernate.naming.implicit-strategy` properties, respectively.\nAlternatively, if javadoc:org.hibernate.boot.model.naming.ImplicitNamingStrategy[] or javadoc:org.hibernate.boot.model.naming.PhysicalNamingStrategy[] beans are available in the application context, Hibernate will be automatically configured to use them.\n\nBy default, Spring Boot configures the physical naming strategy with javadoc:org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy[].\nUsing this strategy, all dots are replaced by underscores and camel casing is replaced by underscores as well.\nAdditionally, by default, all table names are generated in lower case.\nFor example, a `TelephoneNumber` entity is mapped to the `telephone_number` table.\nIf your schema requires mixed-case identifiers, define a custom javadoc:org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy[] bean, as shown in the following example:\n\ninclude-code::spring/MyHibernateConfiguration[]\n\nIf you prefer to use Hibernate's default instead, set the following property:\n\n[configprops,yaml]\n----\nspring:\n  jpa:\n    hibernate:\n      naming:\n        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl\n----\n\nAlternatively, you can configure the following bean:\n\ninclude-code::standard/MyHibernateConfiguration[]\n\nSee {code-spring-boot-hibernate-src}/autoconfigure/HibernateJpaAutoConfiguration.java[`HibernateJpaAutoConfiguration`] and {code-spring-boot-jpa-src}/autoconfigure/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for more details.\n\n\n\n[[howto.data-access.configure-hibernate-second-level-caching]]\n== Configure Hibernate Second-Level Caching\n\nHibernate {url-hibernate-userguide}#caching[second-level cache] can be configured for a range of cache providers.\nRather than configuring Hibernate to lookup the cache provider again, it is better to provide the one that is available in the context whenever possible.\n\nTo do this with JCache, first make sure that `org.hibernate.orm:hibernate-jcache` is available on the classpath.\nThen, add a javadoc:org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer[] bean as shown in the following example:\n\ninclude-code::MyHibernateSecondLevelCacheConfiguration[]\n\nThis customizer will configure Hibernate to use the same javadoc:org.springframework.cache.CacheManager[] as the one that the application uses.\nIt is also possible to use separate javadoc:org.springframework.cache.CacheManager[] instances.\nFor details, see {url-hibernate-userguide}#caching-provider-jcache[the Hibernate user guide].\n\n\n\n[[howto.data-access.dependency-injection-in-hibernate-components]]\n== Use Dependency Injection in Hibernate Components\n\nBy default, Spring Boot registers a javadoc:org.hibernate.resource.beans.container.spi.BeanContainer[] implementation that uses the javadoc:org.springframework.beans.factory.BeanFactory[] so that converters and entity listeners can use regular dependency injection.\n\nYou can disable or tune this behavior by registering a javadoc:org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer[] that removes or changes the `hibernate.resource.beans.container` property.\n\n\n\n[[howto.data-access.use-custom-entity-manager]]\n== Use a Custom EntityManagerFactory\n\nTo take full control of the configuration of the javadoc:jakarta.persistence.EntityManagerFactory[], you need to add a javadoc:org.springframework.context.annotation.Bean[format=annotation] named '`entityManagerFactory`'.\nSpring Boot auto-configuration switches off its entity manager in the presence of a bean of that type.\n\nNOTE: When you create a bean for javadoc:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean[] yourself, any customization that was applied during the creation of the auto-configured javadoc:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean[] is lost.\nMake sure to use the auto-configured javadoc:org.springframework.boot.jpa.EntityManagerFactoryBuilder[] to retain JPA and vendor properties.\nThis is particularly important if you were relying on `spring.jpa.*` properties for configuring things like the naming strategy or the DDL mode.\n\n\n\n[[howto.data-access.use-multiple-entity-managers]]\n== Using Multiple EntityManagerFactories\n\nIf you need to use JPA against multiple datasources, you likely need one javadoc:jakarta.persistence.EntityManagerFactory[] per datasource.\nThe javadoc:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean[] from Spring ORM allows you to configure an javadoc:jakarta.persistence.EntityManagerFactory[] for your needs.\nYou can also reuse javadoc:org.springframework.boot.jpa.autoconfigure.JpaProperties[] to bind settings for a second javadoc:jakarta.persistence.EntityManagerFactory[].\nBuilding upon xref:how-to:data-access.adoc#howto.data-access.configure-two-datasources[the example for configuring a second javadoc:javax.sql.DataSource[]], a second javadoc:jakarta.persistence.EntityManagerFactory[] can be defined as shown in the following example:\n\ninclude-code::MyAdditionalEntityManagerFactoryConfiguration[]\n\nThe example above creates an javadoc:jakarta.persistence.EntityManagerFactory[] using the javadoc:javax.sql.DataSource[] bean qualified with `@Qualifier(\"second\")`.\nIt scans entities located in the same package as `Order`.\nIt is possible to map additional JPA properties using the `app.jpa` namespace.\nThe use of `@Bean(defaultCandidate=false)` allows the `secondJpaProperties` and `secondEntityManagerFactory` beans to be defined without interfering with auto-configured beans of the same type.\n\nNOTE: The {url-spring-framework-docs}/core/beans/dependencies/factory-autowire.html#beans-factory-autowire-candidate[Spring Framework reference documentation] describes this feature in more details.\n\nYou should provide a similar configuration for any more additional data sources for which you need JPA access.\nTo complete the picture, you need to configure a javadoc:org.springframework.orm.jpa.JpaTransactionManager[] for each javadoc:jakarta.persistence.EntityManagerFactory[] as well.\nAlternatively, you might be able to use a JTA transaction manager that spans both.\n\nIf you use Spring Data, you need to configure javadoc:org.springframework.data.jpa.repository.config.EnableJpaRepositories[format=annotation] accordingly, as shown in the following examples:\n\ninclude-code::OrderConfiguration[]\n\ninclude-code::CustomerConfiguration[]\n\n\n\n[[howto.data-access.use-traditional-persistence-xml]]\n== Use a Traditional persistence.xml File\n\nSpring Boot will not search for or use a `META-INF/persistence.xml` by default.\nIf you prefer to use a traditional `persistence.xml`, you need to define your own javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.orm.jpa.LocalEntityManagerFactoryBean[] (with an ID of '`entityManagerFactory`') and set the persistence unit name there.\n\nSee {code-spring-boot-jpa-src}/autoconfigure/JpaBaseConfiguration.java[`JpaBaseConfiguration`] for the default settings.\n\n\n\n[[howto.data-access.use-spring-data-jpa-and-mongo-repositories]]\n== Use Spring Data JPA and Mongo Repositories\n\nSpring Data JPA and Spring Data Mongo can both automatically create javadoc:org.springframework.data.repository.Repository[] implementations for you.\nIf they are both present on the classpath, you might have to do some extra configuration to tell Spring Boot which repositories to create.\nThe most explicit way to do that is to use the standard Spring Data javadoc:org.springframework.data.jpa.repository.config.EnableJpaRepositories[format=annotation] and javadoc:org.springframework.data.mongodb.repository.config.EnableMongoRepositories[format=annotation] annotations and provide the location of your javadoc:org.springframework.data.repository.Repository[] interfaces.\n\nThere are also flags (`+spring.data.*.repositories.enabled+` and `+spring.data.*.repositories.type+`) that you can use to switch the auto-configured repositories on and off in external configuration.\nDoing so is useful, for instance, in case you want to switch off the Mongo repositories and still use the auto-configured javadoc:org.springframework.data.mongodb.core.MongoTemplate[].\n\nThe same obstacle and the same features exist for other auto-configured Spring Data repository types (Elasticsearch, Redis, and others).\nTo work with them, change the names of the annotations and flags accordingly.\n\n\n\n[[howto.data-access.customize-spring-data-web-support]]\n== Customize Spring Data's Web Support\n\nSpring Data provides web support that simplifies the use of Spring Data repositories in a web application.\nSpring Boot provides properties in the `spring.data.web` namespace for customizing its configuration.\nNote that if you are using Spring Data REST, you must use the properties in the `spring.data.rest` namespace instead.\n\n\n\n[[howto.data-access.exposing-spring-data-repositories-as-rest]]\n== Expose Spring Data Repositories as REST Endpoint\n\nSpring Data REST can expose the javadoc:org.springframework.data.repository.Repository[] implementations as REST endpoints for you,\nprovided Spring MVC has been enabled for the application.\n\nSpring Boot exposes a set of useful properties (from the `spring.data.rest` namespace) that customize the javadoc:org.springframework.data.rest.core.config.RepositoryRestConfiguration[].\nIf you need to provide additional customization, you should use a javadoc:org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer[] bean.\n\nNOTE: If you do not specify any order on your custom javadoc:org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer[], it runs after the one Spring Boot uses internally.\nIf you need to specify an order, make sure it is higher than 0.\n\n\n\n[[howto.data-access.configure-a-component-that-is-used-by-jpa]]\n== Configure a Component that is Used by JPA\n\nIf you want to configure a component that JPA uses, then you need to ensure that the component is initialized before JPA.\nWhen the component is auto-configured, Spring Boot takes care of this for you.\nFor example, when Flyway is auto-configured, Hibernate is configured to depend on Flyway so that Flyway has a chance to initialize the database before Hibernate tries to use it.\n\nIf you are configuring a component yourself, you can use an javadoc:org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor[] subclass as a convenient way of setting up the necessary dependencies.\nFor example, if you use Hibernate Search with Elasticsearch as its index manager, any javadoc:jakarta.persistence.EntityManagerFactory[] beans must be configured to depend on the `elasticsearchClient` bean, as shown in the following example:\n\ninclude-code::ElasticsearchEntityManagerFactoryDependsOnPostProcessor[]\n\n\n\n[[howto.data-access.configure-jooq-with-multiple-datasources]]\n== Configure jOOQ with Two DataSources\n\nIf you need to use jOOQ with multiple data sources, you should create your own javadoc:org.jooq.DSLContext[] for each one.\nSee {code-spring-boot-jooq-src}/autoconfigure/JooqAutoConfiguration.java[`JooqAutoConfiguration`] for more details.\n\nTIP: In particular, javadoc:org.springframework.boot.jooq.autoconfigure.ExceptionTranslatorExecuteListener[] and javadoc:org.springframework.boot.jooq.autoconfigure.SpringTransactionProvider[] can be reused to provide similar features to what the auto-configuration does with a single javadoc:javax.sql.DataSource[].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/data-initialization.adoc",
    "content": "[[howto.data-initialization]]\n= Database Initialization\n\nAn SQL database can be initialized in different ways depending on what your stack is.\nOf course, you can also do it manually, provided the database is a separate process.\nIt is recommended to use a single mechanism for schema generation.\n\n\n\n[[howto.data-initialization.using-hibernate]]\n== Initialize a Database Using Hibernate\n\nYou can set configprop:spring.jpa.hibernate.ddl-auto[] to control Hibernate's database initialization.\nSupported values are `none`, `validate`, `update`, `create`, and `create-drop`.\nSpring Boot chooses a default value for you based on whether you are using an embedded database.\nAn embedded database is identified by looking at the javadoc:java.sql.Connection[] type and JDBC url.\n`hsqldb`, `h2`, or `derby` (deprecated) are embedded databases and others are not.\nIf an embedded database is identified and no schema manager (Flyway or Liquibase) has been detected, `ddl-auto` defaults to `create-drop`.\nIn all other cases, it defaults to `none`.\n\nBe careful when switching from in-memory to a '`real`' database that you do not make assumptions about the existence of the tables and data in the new platform.\nYou either have to set `ddl-auto` explicitly or use one of the other mechanisms to initialize the database.\n\nNOTE: You can output the schema creation by enabling the `org.hibernate.SQL` logger.\nThis is done for you automatically if you enable the xref:reference:features/logging.adoc#features.logging.console-output[debug mode].\n\nIn addition, a file named `import.sql` in the root of the classpath is executed on startup if Hibernate creates the schema from scratch (that is, if the `ddl-auto` property is set to `create` or `create-drop`).\nThis can be useful for demos and for testing if you are careful but is probably not something you want to be on the classpath in production.\nIt is a Hibernate feature (and has nothing to do with Spring).\n\n\n\n[[howto.data-initialization.using-basic-sql-scripts]]\n== Initialize a Database Using Basic SQL Scripts\n\nSpring Boot can automatically create the schema (DDL scripts) of your JDBC javadoc:javax.sql.DataSource[] or R2DBC javadoc:io.r2dbc.spi.ConnectionFactory[] and initialize its data (DML scripts).\n\nBy default, it loads schema scripts from `optional:classpath*:schema.sql` and data scripts from `optional:classpath*:data.sql`.\nThe locations of these schema and data scripts can be customized using configprop:spring.sql.init.schema-locations[] and configprop:spring.sql.init.data-locations[] respectively.\nThe `optional:` prefix means that the application will start even when the files do not exist.\nTo have the application fail to start when the files are absent, remove the `optional:` prefix.\n\nIn addition, Spring Boot processes the `optional:classpath*:schema-$\\{platform}.sql` and `optional:classpath*:data-$\\{platform}.sql` files (if present), where `$\\{platform}` is the value of configprop:spring.sql.init.platform[].\nThis allows you to switch to database-specific scripts if necessary.\nFor example, you might choose to set it to the vendor name of the database (`hsqldb`, `h2`, `oracle`, `mysql`, `postgresql`, and so on).\n\nBy default, SQL database initialization is only performed when using an embedded in-memory database.\nTo always initialize an SQL database, irrespective of its type, set configprop:spring.sql.init.mode[] to `always`.\nSimilarly, to disable initialization, set configprop:spring.sql.init.mode[] to `never`.\nBy default, Spring Boot enables the fail-fast feature of its script-based database initializer.\nThis means that, if the scripts cause exceptions, the application fails to start.\nYou can tune that behavior by setting configprop:spring.sql.init.continue-on-error[].\n\nScript-based javadoc:javax.sql.DataSource[] initialization is performed, by default, before any JPA javadoc:jakarta.persistence.EntityManagerFactory[] beans are created.\n`schema.sql` can be used to create the schema for JPA-managed entities and `data.sql` can be used to populate it.\nWhile we do not recommend using multiple data source initialization technologies, if you want script-based javadoc:javax.sql.DataSource[] initialization to be able to build upon the schema creation performed by Hibernate, set configprop:spring.jpa.defer-datasource-initialization[] to `true`.\nThis will defer data source initialization until after any javadoc:jakarta.persistence.EntityManagerFactory[] beans have been created and initialized.\n`schema.sql` can then be used to make additions to any schema creation performed by Hibernate and `data.sql` can be used to populate it.\n\nNOTE: The initialization scripts support `--` for single line comments and `/++*++ ++*++/` for block comments.\nOther comment formats are not supported.\n\nIf you are using a xref:data-initialization.adoc#howto.data-initialization.migration-tool[higher-level database migration tool], like Flyway or Liquibase, you should use them alone to create and initialize the schema.\nUsing the basic `schema.sql` and `data.sql` scripts alongside Flyway or Liquibase is not recommended and support will be removed in a future release.\n\nIf you need to initialize test data using a higher-level database migration tool, please see the sections about xref:data-initialization.adoc#howto.data-initialization.migration-tool.flyway-tests[Flyway] and xref:data-initialization.adoc#howto.data-initialization.migration-tool.liquibase-tests[Liquibase].\n\n\n\n[[howto.data-initialization.batch]]\n== Initialize a Spring Batch Database\n\nIf you use Spring Batch, it comes pre-packaged with SQL initialization scripts for most popular database platforms.\nSpring Boot can detect your database type and execute those scripts on startup.\nIf you use an embedded database, this happens by default.\nYou can also enable it for any database type, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  batch:\n    jdbc:\n      initialize-schema: \"always\"\n----\n\nYou can also switch off the initialization explicitly by setting `spring.batch.jdbc.initialize-schema` to `never`.\n\n\n\n[[howto.data-initialization.migration-tool]]\n== Use a Higher-level Database Migration Tool\n\nSpring Boot supports two higher-level migration tools: https://flywaydb.org/[Flyway] and https://www.liquibase.org/[Liquibase].\n\n\n\n[[howto.data-initialization.migration-tool.flyway]]\n=== Execute Flyway Database Migrations on Startup\n\nTo automatically run Flyway database migrations on startup, add the appropriate Flyway module to your classpath.\nIn-memory and file-based databases are supported by `org.flywaydb:flyway-core`.\nOtherwise, a database-specific module is required.\nFor example, use `org.flywaydb:flyway-database-postgresql` with PostgreSQL and `org.flywaydb:flyway-mysql` with MySQL.\nSee https://documentation.red-gate.com/fd/supported-databases-and-versions-143754067.html[the Flyway Documentation] for further details.\n\nTypically, migrations are scripts in the form `V<VERSION>__<NAME>.sql` (with `<VERSION>` an underscore-separated version, such as '`1`' or '`2_1`').\nBy default, they are in a directory called `classpath:db/migration`, but you can modify that location by setting `spring.flyway.locations`.\nThis is a comma-separated list of one or more `classpath:` or `filesystem:` locations.\nFor example, the following configuration would search for scripts in both the default classpath location and the `/opt/migration` directory:\n\n[configprops,yaml]\n----\nspring:\n  flyway:\n    locations: \"classpath:db/migration,filesystem:/opt/migration\"\n----\n\nYou can also add a special `\\{vendor}` placeholder to use vendor-specific scripts.\nAssume the following:\n\n[configprops,yaml]\n----\nspring:\n  flyway:\n    locations: \"classpath:db/migration/{vendor}\"\n----\n\nRather than using `db/migration`, the preceding configuration sets the directory to use according to the type of the database (such as `db/migration/mysql` for MySQL).\nThe list of supported databases is available in javadoc:org.springframework.boot.jdbc.DatabaseDriver[].\n\nMigrations can also be written in Java.\nFlyway will be auto-configured with any beans that implement javadoc:org.flywaydb.core.api.migration.JavaMigration[].\n\njavadoc:org.springframework.boot.flyway.autoconfigure.FlywayProperties[] provides most of Flyway's settings and a small set of additional properties that can be used to disable the migrations or switch off the location checking.\nIf you need more control over the configuration, consider registering a javadoc:org.springframework.boot.flyway.autoconfigure.FlywayConfigurationCustomizer[] bean.\n\nSpring Boot calls `Flyway.migrate()` to perform the database migration.\nIf you would like more control, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:org.springframework.boot.flyway.autoconfigure.FlywayMigrationStrategy[].\n\nFlyway supports SQL and Java https://documentation.red-gate.com/fd/callbacks-275218509.html[callbacks].\nTo use SQL-based callbacks, place the callback scripts in the `classpath:db/migration` directory.\nTo use Java-based callbacks, create one or more beans that implement javadoc:org.flywaydb.core.api.callback.Callback[].\nAny such beans are automatically registered with javadoc:org.flywaydb.core.Flyway[].\nThey can be ordered by using javadoc:org.springframework.core.annotation.Order[format=annotation] or by implementing javadoc:org.springframework.core.Ordered[].\n\nBy default, Flyway autowires the (`@Primary`) javadoc:javax.sql.DataSource[] in your context and uses that for migrations.\nIf you like to use a different javadoc:javax.sql.DataSource[], you can create one and mark its javadoc:org.springframework.context.annotation.Bean[format=annotation] as javadoc:org.springframework.boot.flyway.autoconfigure.FlywayDataSource[format=annotation].\nIf you do so and want two data sources (for example by retaining the main auto-configured javadoc:javax.sql.DataSource[]), remember to set the `defaultCandidate` attribute of the javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation to `false`.\nAlternatively, you can use Flyway's native javadoc:javax.sql.DataSource[] by setting `spring.flyway.[url,user,password]` in external properties.\nSetting either `spring.flyway.url` or `spring.flyway.user` is sufficient to cause Flyway to use its own javadoc:javax.sql.DataSource[].\nIf any of the three properties has not been set, the value of its equivalent `spring.datasource` property will be used.\n\nYou can also use Flyway to provide data for specific scenarios.\nFor example, you can place test-specific migrations in `src/test/resources` and they are run only when your application starts for testing.\nAlso, you can use profile-specific configuration to customize `spring.flyway.locations` so that certain migrations run only when a particular profile is active.\nFor example, in `application-dev.properties`, you might specify the following setting:\n\n[configprops,yaml]\n----\nspring:\n  flyway:\n    locations: \"classpath:/db/migration,classpath:/dev/db/migration\"\n----\n\nWith that setup, migrations in `dev/db/migration` run only when the `dev` profile is active.\n\n\n\n[[howto.data-initialization.migration-tool.liquibase]]\n=== Execute Liquibase Database Migrations on Startup\n\nTo automatically run Liquibase database migrations on startup, add the `org.liquibase:liquibase-core` to your classpath.\n\n[NOTE]\n====\nWhen you add the `org.liquibase:liquibase-core` to your classpath, database migrations run by default for both during application startup and before your tests run.\nThis behavior can be customized by using the configprop:spring.liquibase.enabled[] property, setting different values in the `main` and `test` configurations.\nIt is not possible to use two different ways to initialize the database (for example Liquibase for application startup, JPA for test runs).\n====\n\nBy default, the master change log is read from `db/changelog/db.changelog-master.yaml`, but you can change the location by setting `spring.liquibase.change-log`.\nIn addition to YAML, Liquibase also supports JSON, XML, and SQL change log formats.\n\nBy default, Liquibase autowires the (`@Primary`) javadoc:javax.sql.DataSource[] in your context and uses that for migrations.\nIf you need to use a different javadoc:javax.sql.DataSource[], you can create one and mark its javadoc:org.springframework.context.annotation.Bean[format=annotation] as javadoc:org.springframework.boot.liquibase.autoconfigure.LiquibaseDataSource[format=annotation].\nIf you do so and want two data sources (for example by retaining the main auto-configured javadoc:javax.sql.DataSource[]), remember to set the `defaultCandidate` attribute of the javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation to `false`.\nAlternatively, you can use Liquibase's native javadoc:javax.sql.DataSource[] by setting `spring.liquibase.[driver-class-name,url,user,password]` in external properties.\nSetting either `spring.liquibase.url` or `spring.liquibase.user` is sufficient to cause Liquibase to use its own javadoc:javax.sql.DataSource[].\nIf any of the three properties has not been set, the value of its equivalent `spring.datasource` property will be used.\n\nSee javadoc:org.springframework.boot.liquibase.autoconfigure.LiquibaseProperties[] for details about available settings such as contexts, the default schema, and others.\n\nYou can also use a `Customizer<Liquibase>` bean if you want to customize the javadoc:{url-liquibase-javadoc}/liquibase.Liquibase[] instance before it is being used.\n\n\n\n[[howto.data-initialization.migration-tool.flyway-tests]]\n=== Use Flyway for Test-only Migrations\n\nIf you want to create Flyway migrations which populate your test database, place them in `src/test/resources/db/migration`.\nA file named, for example, `src/test/resources/db/migration/V9999__test-data.sql` will be executed after your production migrations and only if you're running the tests.\nYou can use this file to create the needed test data.\nThis file will not be packaged in your uber jar or your container.\n\n\n\n[[howto.data-initialization.migration-tool.liquibase-tests]]\n=== Use Liquibase for Test-only Migrations\n\nIf you want to create Liquibase migrations which populate your test database, you can leverage https://docs.liquibase.com/reference-guide/changelog-attributes/what-are-contexts[Liquibase contexts].\nSee also the related https://www.liquibase.com/blog/contexts-vs-labels[blog post].\n\nIn practical terms, this translates into adding a `context:@test` attribute to changesets containing test data, for example:\n\n[source,sql]\n----\n--liquibase formatted sql\n\n--changeset alice:1 context:@test\ninsert into project (id, name) values (1, 'Spring Boot');\n----\n\nAnd using `spring.liquibase.contexts=test` in environments where you would like changesets containing test data to be applied.\n\n\n\n[[howto.data-initialization.dependencies]]\n== Depend Upon an Initialized Database\n\nDatabase initialization is performed while the application is starting up as part of application context refresh.\nTo allow an initialized database to be accessed during startup, beans that act as database initializers and beans that require that database to have been initialized are detected automatically.\nBeans whose initialization depends upon the database having been initialized are configured to depend upon those that initialize it.\nIf, during startup, your application tries to access the database and it has not been initialized, you can configure additional detection of beans that initialize the database and require the database to have been initialized.\n\n\n\n[[howto.data-initialization.dependencies.initializer-detection]]\n=== Detect a Database Initializer\n\nSpring Boot will automatically detect beans of the following types that initialize an SQL database:\n\n- javadoc:org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer[]\n- javadoc:jakarta.persistence.EntityManagerFactory[]\n- javadoc:org.flywaydb.core.Flyway[]\n- javadoc:org.springframework.boot.flyway.autoconfigure.FlywayMigrationInitializer[]\n- javadoc:org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer[]\n- javadoc:liquibase.integration.spring.SpringLiquibase[]\n\nIf you are using a third-party starter for a database initialization library, it may provide a detector such that beans of other types are also detected automatically.\nTo have other beans be detected, register an implementation of javadoc:org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector[] in `META-INF/spring.factories`.\n\n\n\n[[howto.data-initialization.dependencies.depends-on-initialization-detection]]\n=== Detect a Bean That Depends On Database Initialization\n\nSpring Boot will automatically detect beans of the following types that depends upon database initialization:\n\n- javadoc:org.springframework.orm.jpa.AbstractEntityManagerFactoryBean[] (unless configprop:spring.jpa.defer-datasource-initialization[] is set to `true`)\n- javadoc:org.jooq.DSLContext[] (jOOQ)\n- javadoc:jakarta.persistence.EntityManagerFactory[] (unless configprop:spring.jpa.defer-datasource-initialization[] is set to `true`)\n- javadoc:org.springframework.jdbc.core.simple.JdbcClient[]\n- javadoc:org.springframework.jdbc.core.JdbcOperations[]\n- javadoc:org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations[]\n\nIf you are using a third-party starter data access library, it may provide a detector such that beans of other types are also detected automatically.\nTo have other beans be detected, register an implementation of javadoc:org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector[] in `META-INF/spring.factories`.\nAlternatively, annotate the bean's class or its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization[format=annotation].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/cloud.adoc",
    "content": "[[howto.deployment.cloud]]\n= Deploying to the Cloud\n\nSpring Boot's executable jars are ready-made for most popular cloud PaaS (Platform-as-a-Service) providers.\nThese providers tend to require that you \"`bring your own container`\".\nThey manage application processes (not Java applications specifically), so they need an intermediary layer that adapts _your_ application to the _cloud's_ notion of a running process.\n\nTwo popular cloud providers, Heroku and Cloud Foundry, employ a \"`buildpack`\" approach.\nThe buildpack wraps your deployed code in whatever is needed to _start_ your application.\nIt might be a JDK and a call to `java`, an embedded web server, or a full-fledged application server.\nA buildpack is pluggable, but ideally you should be able to get by with as few customizations to it as possible.\nThis reduces the footprint of functionality that is not under your control.\nIt minimizes divergence between development and production environments.\n\nIdeally, your application, like a Spring Boot executable jar, has everything that it needs to run packaged within it.\n\nIn this section, we look at what it takes to get the xref:tutorial:first-application/index.adoc[application that we developed] in the \"`Getting Started`\" section up and running in the Cloud.\n\n\n\n[[howto.deployment.cloud.security]]\n== Security considerations\n\nSupport for xref:how-to:webserver.adoc#howto.webserver.use-behind-a-proxy-server[forwarded headers] should only be enabled when the application receives traffic from a trusted HTTP proxy, and is only directly accessible from a trusted network.\nWhen running on a cloud platform, forward headers are enabled automatically.\nThis builds on the assumption that the platform will ensure that individual application instances will only be directly accessible from a trusted network.\nIf that is not the case for your specific platform, set `spring.forward-headers-strategy` to `none`.\n\n\n[[howto.deployment.cloud.cloud-foundry]]\n== Cloud Foundry\n\nCloud Foundry provides default buildpacks that come into play if no other buildpack is specified.\nThe Cloud Foundry https://github.com/cloudfoundry/java-buildpack[Java buildpack] has excellent support for Spring applications, including Spring Boot.\nYou can deploy stand-alone executable jar applications as well as traditional `.war` packaged applications.\n\nOnce you have built your application (by using, for example, `mvn clean package`) and have https://docs.cloudfoundry.org/cf-cli/install-go-cli.html[installed the `cf` command line tool], deploy your application by using the `cf push` command, substituting the path to your compiled `.jar`.\nBe sure to have https://docs.cloudfoundry.org/cf-cli/getting-started.html#login[logged in with your `cf` command line client] before pushing an application.\nThe following line shows using the `cf push` command to deploy an application:\n\n[source,shell]\n----\n$ cf push acloudyspringtime -p target/demo-0.0.1-SNAPSHOT.jar\n----\n\nNOTE: In the preceding example, we substitute `acloudyspringtime` for whatever value you give `cf` as the name of your application.\n\nSee the https://docs.cloudfoundry.org/cf-cli/getting-started.html#push[`cf push` documentation] for more options.\nIf there is a Cloud Foundry https://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html[`manifest.yml`] file present in the same directory, it is considered.\n\nAt this point, `cf` starts uploading your application, producing output similar to the following example:\n\n[source,subs=\"verbatim,quotes\"]\n----\nUploading acloudyspringtime... *OK*\nPreparing to start acloudyspringtime... *OK*\n-----> Downloaded app package (*8.9M*)\n-----> Java Buildpack Version: v3.12 (offline) | https://github.com/cloudfoundry/java-buildpack.git#6f25b7e\n-----> Downloading Open Jdk JRE\n       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.6s)\n-----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (found in cache)\n       Memory Settings: -Xss349K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xms681574K -XX:MetaspaceSize=104857K\n-----> Downloading Container Certificate Trust Store 1.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-certificate-trust-store/container-certificate-trust-store-1.0.0_RELEASE.jar (found in cache)\n       Adding certificates to .java-buildpack/container_certificate_trust_store/truststore.jks (0.6s)\n-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (found in cache)\nChecking status of app 'acloudyspringtime'...\n  0 of 1 instances running (1 starting)\n  ...\n  0 of 1 instances running (1 starting)\n  ...\n  0 of 1 instances running (1 starting)\n  ...\n  1 of 1 instances running (1 running)\n\nApp started\n----\n\nCongratulations! The application is now live!\n\nOnce your application is live, you can verify the status of the deployed application by using the `cf apps` command, as shown in the following example:\n\n[source,shell]\n----\n$ cf apps\nGetting applications in ...\nOK\n\nname                 requested state   instances   memory   disk   urls\n...\nacloudyspringtime    started           1/1         512M     1G     acloudyspringtime.cfapps.io\n...\n----\n\nOnce Cloud Foundry acknowledges that your application has been deployed, you should be able to find the application at the URI given.\nIn the preceding example, you could find it at `\\https://acloudyspringtime.cfapps.io/`.\n\n\n\n[[howto.deployment.cloud.cloud-foundry.binding-to-services]]\n=== Binding to Services\n\nBy default, metadata about the running application as well as service connection information is exposed to the application as environment variables (for example: `$VCAP_SERVICES`).\nThis architecture decision is due to Cloud Foundry's polyglot (any language and platform can be supported as a buildpack) nature.\nProcess-scoped environment variables are language agnostic.\n\nEnvironment variables do not always make for the easiest API, so Spring Boot automatically extracts them and flattens the data into properties that can be accessed through Spring's javadoc:org.springframework.core.env.Environment[] abstraction, as shown in the following example:\n\ninclude-code::MyBean[]\n\nAll Cloud Foundry properties are prefixed with `vcap`.\nYou can use `vcap` properties to access application information (such as the public URL of the application) and service information (such as database credentials).\nSee the javadoc:org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor[] API documentation for complete details.\n\nTIP: The https://github.com/pivotal-cf/java-cfenv/[Java CFEnv] project is a better fit for tasks such as configuring a DataSource.\n\n\n\n[[howto.deployment.cloud.kubernetes]]\n== Kubernetes\n\nSpring Boot auto-detects Kubernetes deployment environments by checking the environment for `\"*_SERVICE_HOST\"` and `\"*_SERVICE_PORT\"` variables.\nYou can override this detection with the configprop:spring.main.cloud-platform[] configuration property.\n\nSpring Boot helps you to xref:reference:features/spring-application.adoc#features.spring-application.application-availability[manage the state of your application] and export it with xref:reference:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[HTTP Kubernetes Probes using Actuator].\n\n\n\n[[howto.deployment.cloud.kubernetes.container-lifecycle]]\n=== Kubernetes Container Lifecycle\n\nWhen Kubernetes deletes an application instance, the shutdown process involves several subsystems concurrently: shutdown hooks, unregistering the service, removing the instance from the load-balancer...\nBecause this shutdown processing happens in parallel (and due to the nature of distributed systems), there is a window during which traffic can be routed to a pod that has also begun its shutdown processing.\n\nYou can configure a sleep execution in a preStop handler to avoid requests being routed to a pod that has already begun shutting down.\nThis sleep should be long enough for new requests to stop being routed to the pod and its duration will vary from deployment to deployment.\nThe delay should be at least as long as the longest time it takes to process an in-flight request.\nYou should not rely on the Spring Boot graceful shutdown period alone, as the platform will not be getting any liveness data in the period that the app is shutting down.\n\nIf you're using Kubernetes 1.32 or up, the preStop handler can be configured by using the PodSpec in the pod's configuration file as follows:\n\n[source,yaml]\n----\nspec:\n  containers:\n  - name: \"example-container\"\n    image: \"example-image\"\n    lifecycle:\n      preStop:\n        sleep:\n          seconds: 10\n----\n\nIf you're not on Kubernetes 1.32 yet, you can use an `exec` command to invoke `sleep`.\n\n[source,yaml]\n----\nspec:\n  containers:\n  - name: \"example-container\"\n    image: \"example-image\"\n    lifecycle:\n      preStop:\n        exec:\n          command: [\"sh\", \"-c\", \"sleep 10\"]\n----\n\nNOTE: The container needs to have a shell for this to work.\n\nOnce the pre-stop hook has completed, SIGTERM will be sent to the container and xref:reference:web/graceful-shutdown.adoc[graceful shutdown] will begin, allowing any remaining in-flight requests to complete.\n\nNOTE: When Kubernetes sends a SIGTERM signal to the pod, it waits for a specified time called the termination grace period (the default for which is 30 seconds).\nIf the containers are still running after the grace period, they are sent the SIGKILL signal and forcibly removed.\nIf the pod takes longer than 30 seconds to shut down, which could be because you have increased configprop:spring.lifecycle.timeout-per-shutdown-phase[], make sure to increase the termination grace period by setting the `terminationGracePeriodSeconds` option in the Pod YAML.\n\n\n\n[[howto.deployment.cloud.heroku]]\n== Heroku\n\nHeroku is another popular PaaS platform.\nTo customize Heroku builds, you provide a `Procfile`, which provides the incantation required to deploy an application.\nHeroku assigns a `port` for the Java application to use and then ensures that routing to the external URI works.\n\nYou must configure your application to listen on the correct port.\nThe following example shows the `Procfile` for our starter REST application:\n\n[source]\n----\nweb: java -Dserver.port=$PORT -jar target/demo-0.0.1-SNAPSHOT.jar\n----\n\nSpring Boot makes `-D` arguments available as properties accessible from a Spring javadoc:org.springframework.core.env.Environment[] instance.\nThe `server.port` configuration property is fed to the embedded Tomcat or Jetty instance, which then uses the port when it starts up.\nThe `$PORT` environment variable is assigned to us by the Heroku PaaS.\n\nThis should be everything you need.\nThe most common deployment workflow for Heroku deployments is to `git push` the code to production, as shown in the following example:\n\n[source,shell]\n----\n$ git push heroku main\n----\n\nWhich will result in the following:\n\n[source,subs=\"verbatim,quotes\"]\n----\nInitializing repository, *done*.\nCounting objects: 95, *done*.\nDelta compression using up to 8 threads.\nCompressing objects: 100% (78/78), *done*.\nWriting objects: 100% (95/95), 8.66 MiB | 606.00 KiB/s, *done*.\nTotal 95 (delta 31), reused 0 (delta 0)\n\n-----> Java app detected\n-----> Installing OpenJDK... *done*\n-----> Installing Maven... *done*\n-----> Installing settings.xml... *done*\n-----> Executing: mvn -B -DskipTests=true clean install\n\n       [INFO] Scanning for projects...\n       Downloading: https://repo.spring.io/...\n       Downloaded: https://repo.spring.io/... (818 B at 1.8 KB/sec)\n\t\t....\n       Downloaded: https://s3pository.heroku.com/jvm/... (152 KB at 595.3 KB/sec)\n       [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/target/...\n       [INFO] Installing /tmp/build_0c35a5d2-a067-4abc-a232-14b1fb7a8229/pom.xml ...\n       [INFO] ------------------------------------------------------------------------\n       [INFO] *BUILD SUCCESS*\n       [INFO] ------------------------------------------------------------------------\n       [INFO] Total time: 59.358s\n       [INFO] Finished at: Fri Mar 07 07:28:25 UTC 2014\n       [INFO] Final Memory: 20M/493M\n       [INFO] ------------------------------------------------------------------------\n\n-----> Discovering process types\n       Procfile declares types -> *web*\n\n-----> Compressing... *done*, 70.4MB\n-----> Launching... *done*, v6\n       https://agile-sierra-1405.herokuapp.com/ *deployed to Heroku*\n\nTo git@heroku.com:agile-sierra-1405.git\n * [new branch]      main -> main\n----\n\nYour application should now be up and running on Heroku.\nFor more details, see https://devcenter.heroku.com/articles/deploying-spring-boot-apps-to-heroku[Deploying Spring Boot Applications to Heroku].\n\n\n\n[[howto.deployment.cloud.openshift]]\n== OpenShift\n\nhttps://www.openshift.com/[OpenShift] has many resources describing how to deploy Spring Boot applications, including:\n\n* https://blog.openshift.com/using-openshift-enterprise-grade-spring-boot-deployments/[Using the S2I builder]\n* https://blog.openshift.com/using-spring-boot-on-openshift/[Running as a traditional web application on Wildfly]\n* https://blog.openshift.com/openshift-commons-briefing-96-cloud-native-applications-spring-rhoar/[OpenShift Commons Briefing]\n\n\n\n[[howto.deployment.cloud.aws]]\n== Amazon Web Services (AWS)\n\nAmazon Web Services provides several options that are suitable for running Spring Boot-based applications, either as containers, traditional web applications (war), or self-contained executable jar files.\nPopular options are:\n\n* Amazon Elastic Container Service (ECS)\n* AWS Elastic Beanstalk\n\n\n\n[[howto.deployment.cloud.aws.ecs]]\n=== Amazon Elastic Container Service (ECS)\n\nOfficial https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html[Amazon ECS developer guide] provides comprehensive overview of platform's features and includes https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started.html[getting started guide] that walks you through the steps needed to get your containers up and running.\n\nNOTE: Spring Boot applications can be packaged in Docker containers using techniques described in xref:reference:packaging/container-images/index.adoc[].\n\nIn addition to the developer guide, AWS also provides a https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-container-image.html[topical guide] for deploying containerized Java services on Amazon ECS using AWS Fargate.\n\nTIP: Spring Boot auto-detects AWS ECS deployment environments by checking the environment for the `AWS_EXECUTION_ENV` variable.\nYou can override this detection with the configprop:spring.main.cloud-platform[] configuration property.\n\n\n\n[[howto.deployment.cloud.aws.beanstalk]]\n=== AWS Elastic Beanstalk\n\nAs described in the official https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_Java.html[Elastic Beanstalk Java guide], there are two main options to deploy a Java application.\nYou can either use the \"`Tomcat Platform`\" or the \"`Java SE platform`\".\n\n\n\n[[howto.deployment.cloud.aws.beanstalk.tomcat-platform]]\n==== Using the Tomcat Platform\n\nThis option applies to Spring Boot projects that produce a war file.\nFollow the official guide and https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/tomcat-quickstart.html[Java on Tomcat tutorial].\n\nNOTE: Creating deployable war for a Spring Boot application is described in xref:deployment/traditional-deployment.adoc[].\n\n\n\n[[howto.deployment.cloud.aws.beanstalk.java-se-platform]]\n==== Using the Java SE Platform\n\nThis option applies to Spring Boot projects that produce a jar file and run an embedded web container.\nFollow the official guide and https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-quickstart.html[Java tutorial].\nThere are also community provided tutorials such as https://www.baeldung.com/spring-boot-deploy-aws-beanstalk[this one].\n\n\n\n[[howto.deployment.cloud.boxfuse]]\n== CloudCaptain and Amazon Web Services\n\nhttps://cloudcaptain.sh/[CloudCaptain] works by turning your Spring Boot executable jar or war into a minimal VM image that can be deployed unchanged either on VirtualBox or on AWS.\nCloudCaptain comes with deep integration for Spring Boot and uses the information from your Spring Boot configuration file to automatically configure ports and health check URLs.\nCloudCaptain leverages this information both for the images it produces as well as for all the resources it provisions (instances, security groups, elastic load balancers, and so on).\n\nOnce you have created a https://console.cloudcaptain.sh[CloudCaptain account], connected it to your AWS account, installed the latest version of the CloudCaptain Client, and ensured that the application has been built by Maven or Gradle (by using, for example, `mvn clean package`), you can deploy your Spring Boot application to AWS with a command similar to the following:\n\n[source,shell]\n----\n$ boxfuse run myapp-1.0.jar -env=prod\n----\n\nSee the https://cloudcaptain.sh/docs/commandline/run.html[`boxfuse run` documentation] for more options.\nIf there is a https://cloudcaptain.sh/docs/commandline/#configuration[`boxfuse.conf`] file present in the current directory, it is considered.\n\nTIP: By default, CloudCaptain activates a Spring profile named `boxfuse` on startup.\nIf your executable jar or war contains an https://cloudcaptain.sh/docs/payloads/springboot.html#configuration[`application-boxfuse.properties`] file, CloudCaptain bases its configuration on the properties it contains.\n\nAt this point, CloudCaptain creates an image for your application, uploads it, and configures and starts the necessary resources on AWS, resulting in output similar to the following example:\n\n[source]\n----\nFusing Image for myapp-1.0.jar ...\nImage fused in 00:06.838s (53937 K) -> axelfontaine/myapp:1.0\nCreating axelfontaine/myapp ...\nPushing axelfontaine/myapp:1.0 ...\nVerifying axelfontaine/myapp:1.0 ...\nCreating Elastic IP ...\nMapping myapp-axelfontaine.boxfuse.io to 52.28.233.167 ...\nWaiting for AWS to create an AMI for axelfontaine/myapp:1.0 in eu-central-1 (this may take up to 50 seconds) ...\nAMI created in 00:23.557s -> ami-d23f38cf\nCreating security group boxfuse-sg_axelfontaine/myapp:1.0 ...\nLaunching t2.micro instance of axelfontaine/myapp:1.0 (ami-d23f38cf) in eu-central-1 ...\nInstance launched in 00:30.306s -> i-92ef9f53\nWaiting for AWS to boot Instance i-92ef9f53 and Payload to start at https://52.28.235.61/ ...\nPayload started in 00:29.266s -> https://52.28.235.61/\nRemapping Elastic IP 52.28.233.167 to i-92ef9f53 ...\nWaiting 15s for AWS to complete Elastic IP Zero Downtime transition ...\nDeployment completed successfully. axelfontaine/myapp:1.0 is up and running at https://myapp-axelfontaine.boxfuse.io/\n----\n\nYour application should now be up and running on AWS.\n\nSee the blog post on https://cloudcaptain.sh/blog/spring-boot-ec2.html[deploying Spring Boot apps on EC2] as well as the https://cloudcaptain.sh/docs/payloads/springboot.html[documentation for the CloudCaptain Spring Boot integration] to get started with a Maven build to run the app.\n\n\n\n[[howto.deployment.cloud.azure]]\n== Azure\n\nThis https://spring.io/guides/gs/spring-boot-for-azure/[Getting Started guide] walks you through deploying your Spring Boot application to either https://azure.microsoft.com/en-us/services/spring-cloud/[Azure Spring Cloud] or https://docs.microsoft.com/en-us/azure/app-service/overview[Azure App Service].\n\n\n\n[[howto.deployment.cloud.google]]\n== Google Cloud\n\nGoogle Cloud has several options that can be used to launch Spring Boot applications.\nThe easiest to get started with is probably App Engine, but you could also find ways to run Spring Boot in a container with Container Engine or on a virtual machine with Compute Engine.\n\nTo deploy your first app to App Engine standard environment, follow https://codelabs.developers.google.com/codelabs/cloud-app-engine-springboot#0[this tutorial].\n\nAlternatively, App Engine Flex requires you to create an `app.yaml` file to describe the resources your app requires.\nNormally, you put this file in `src/main/appengine`, and it should resemble the following file:\n\n[source,yaml]\n----\nservice: \"default\"\n\nruntime: \"java17\"\nenv: \"flex\"\n\nhandlers:\n- url: \"/.*\"\n  script: \"this field is required, but ignored\"\n\nmanual_scaling:\n  instances: 1\n\nhealth_check:\n  enable_health_check: false\n\nenv_variables:\n  ENCRYPT_KEY: \"your_encryption_key_here\"\n----\n\nYou can deploy the app (for example, with a Maven plugin) by adding the project ID to the build configuration, as shown in the following example:\n\n[source,xml]\n----\n<plugin>\n\t<groupId>com.google.cloud.tools</groupId>\n\t<artifactId>appengine-maven-plugin</artifactId>\n\t<version>2.4.4</version>\n\t<configuration>\n\t\t<project>myproject</project>\n\t</configuration>\n</plugin>\n----\n\nThen deploy with `mvn appengine:deploy` (you need to authenticate first, otherwise the build fails).\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/index.adoc",
    "content": "[[howto.deployment]]\n= Deploying Spring Boot Applications\n\nSpring Boot's flexible packaging options provide a great deal of choice when it comes to deploying your application.\nYou can deploy Spring Boot applications to a variety of cloud platforms and to virtual or real machines.\n\nThis section covers some of the more common deployment scenarios.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/installing.adoc",
    "content": "[[howto.deployment.installing]]\n= Installing Spring Boot Applications\n\nIn addition to running Spring Boot applications by using `java -jar` directly, it is also possible to run them as services.\n\n\n\n[[howto.deployment.installing.system-d]]\n== Installation as a systemd Service\n\n`systemd` is the successor of the System V init system and is now being used by many modern Linux distributions.\nSpring Boot applications can be launched by using `systemd` '`service`' scripts.\n\nAssuming that you have a Spring Boot application packaged as an uber jar in `/var/myapp`, to install it as a `systemd` service, create a script named `myapp.service` and place it in `/etc/systemd/system` directory.\nThe following script offers an example:\n\n[source]\n----\n[Unit]\nDescription=myapp\nAfter=syslog.target network.target\n\n[Service]\nUser=myapp\nGroup=myapp\n\nType=exec\nExecStart=/path/to/java/home/bin/java -jar /var/myapp/myapp.jar\nWorkingDirectory=/var/myapp\nSuccessExitStatus=143\n\n[Install]\nWantedBy=multi-user.target\n----\n\nIMPORTANT: Remember to change the `Description`, `User`, `Group`, `ExecStart` and `WorkingDirectory` fields for your application.\n\nNOTE: The `ExecStart` field does not declare the script action command, which means that the `run` command is used by default.\n\nThe user that runs the application, the PID file, and the console log file are managed by `systemd` itself and therefore must be configured by using appropriate fields in the '`service`' script.\nConsult the https://www.freedesktop.org/software/systemd/man/systemd.service.html[service unit configuration man page] for more details.\n\nTo flag the application to start automatically on system boot, use the following command:\n\n[source,shell]\n----\n$ systemctl enable myapp.service\n----\n\nRun `man systemctl` for more details.\n\n\n\n[[howto.deployment.installing.windows-services]]\n== Microsoft Windows Services\n\nA Spring Boot application can be started as a Windows service by using https://github.com/kohsuke/winsw[`winsw`].\n\nA (https://github.com/snicoll/spring-boot-daemon[separately maintained sample]) describes step-by-step how you can create a Windows service for your Spring Boot application.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/deployment/traditional-deployment.adoc",
    "content": "[[howto.traditional-deployment]]\n= Traditional Deployment\n\nSpring Boot supports traditional deployment as well as more modern forms of deployment.\nThis section answers common questions about traditional deployment.\n\n\n\n[[howto.traditional-deployment.war]]\n== Create a Deployable War File\n\nWARNING: Because Spring WebFlux does not strictly depend on the servlet API and applications are deployed by default on an embedded Reactor Netty server, War deployment is not supported for WebFlux applications.\n\nThe first step in producing a deployable war file is to provide a javadoc:org.springframework.boot.web.servlet.support.SpringBootServletInitializer[] subclass and override its `configure` method.\nDoing so makes use of Spring Framework's servlet 3.0 support and lets you configure your application when it is launched by the servlet container.\nTypically, you should update your application's main class to extend javadoc:org.springframework.boot.web.servlet.support.SpringBootServletInitializer[], as shown in the following example:\n\ninclude-code::MyApplication[]\n\nThe next step is to update your build configuration such that your project produces a war file rather than a jar file.\nIf you use Maven and `spring-boot-starter-parent` (which configures Maven's war plugin for you), all you need to do is to modify `pom.xml` to change the packaging to war, as follows:\n\n[source,xml]\n----\n<packaging>war</packaging>\n----\n\nIf you use Gradle, you need to modify `build.gradle` to apply the war plugin to the project, as follows:\n\n[source,gradle]\n----\napply plugin: 'war'\n----\n\nThe final step in the process is to ensure that the embedded servlet container does not interfere with the servlet container to which the war file is deployed.\n\nFor Maven, you need to mark the embedded servlet container dependency as being `provided`.\nFor example:\n\n[source,xml]\n----\n<dependencies>\n\t<!-- ... -->\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t<scope>provided</scope>\n\t</dependency>\n\t<!-- ... -->\n</dependencies>\n----\n\nIf you use Gradle, you need to move only the runtime dependencies into the `providedRuntime` configuration.\nFor example:\n\n[source,gradle]\n----\ndependencies {\n\t// ...\n\tprovidedRuntime 'org.springframework.boot:spring-boot-starter-tomcat-runtime'\n\t// ...\n}\n----\n\nTIP: `providedRuntime` is preferred to Gradle's `compileOnly` configuration.\nAmong other limitations, `compileOnly` dependencies are not on the test classpath, so any web-based integration tests fail.\n\nIf you use the Spring Boot xref:build-tool-plugin:index.adoc[], marking the embedded servlet container dependency as provided produces an executable war file with the provided dependencies packaged in a `lib-provided` directory.\nThis means that, in addition to being deployable to a servlet container, you can also run your application by using `java -jar` on the command line.\n\n\n\n[[howto.traditional-deployment.convert-existing-application]]\n== Convert an Existing Application to Spring Boot\n\nTo convert an existing non-web Spring application to a Spring Boot application, replace the code that creates your javadoc:org.springframework.context.ApplicationContext[] and replace it with calls to javadoc:org.springframework.boot.SpringApplication[] or javadoc:org.springframework.boot.builder.SpringApplicationBuilder[].\nSpring MVC web applications are generally amenable to first creating a deployable war application and then migrating it later to an executable war or jar.\n\nTo create a deployable war by extending javadoc:org.springframework.boot.web.servlet.support.SpringBootServletInitializer[] (for example, in a class called `Application`) and adding the Spring Boot javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotation, use code similar to that shown in the following example:\n\ninclude-code::MyApplication[tag=!main]\n\nRemember that, whatever you put in the `sources` is merely a Spring javadoc:org.springframework.context.ApplicationContext[].\nNormally, anything that already works should work here.\nThere might be some beans you can remove later and let Spring Boot provide its own defaults for them, but it should be possible to get something working before you need to do that.\n\nStatic resources can be moved to `/public` (or `/static` or `/resources` or `/META-INF/resources`) in the classpath root.\nThe same applies to `messages.properties` (which Spring Boot automatically detects in the root of the classpath).\n\nVanilla usage of Spring javadoc:org.springframework.web.servlet.DispatcherServlet[] and Spring Security should require no further changes.\nIf you have other features in your application (for instance, using other servlets or filters), you may need to add some configuration to your `Application` context, by replacing those elements from the `web.xml`, as follows:\n\n* A javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:jakarta.servlet.Servlet[] or javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] installs that bean in the container as if it were a `<servlet/>` and `<servlet-mapping/>` in `web.xml`.\n* A javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:jakarta.servlet.Filter[] or javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[] behaves similarly (as a `<filter/>` and `<filter-mapping/>`).\n* An javadoc:org.springframework.context.ApplicationContext[] in an XML file can be added through an javadoc:org.springframework.context.annotation.ImportResource[format=annotation] in your `+Application+`.\n  Alternatively, cases where annotation configuration is heavily used already can be recreated in a few lines as javadoc:org.springframework.context.annotation.Bean[format=annotation] definitions.\n\nOnce the war file is working, you can make it executable by adding a `main` method to your `Application`, as shown in the following example:\n\ninclude-code::MyApplication[tag=main]\n\n[NOTE]\n====\nIf you intend to start your application as a war or as an executable application, you need to share the customizations of the builder in a method that is both available to the javadoc:org.springframework.boot.web.servlet.support.SpringBootServletInitializer[] callback and in the `main` method in a class similar to the following:\n\ninclude-code::both/MyApplication[]\n====\n\nApplications can fall into more than one category:\n\n* Servlet 3.0+ applications with no `web.xml`.\n* Applications with a `web.xml`.\n* Applications with a context hierarchy.\n* Applications without a context hierarchy.\n\nAll of these should be amenable to translation, but each might require slightly different techniques.\n\nServlet 3.0+ applications might translate pretty easily if they already use the Spring Servlet 3.0+ initializer support classes.\nNormally, all the code from an existing javadoc:org.springframework.web.WebApplicationInitializer[] can be moved into a javadoc:org.springframework.boot.web.servlet.support.SpringBootServletInitializer[].\nIf your existing application has more than one javadoc:org.springframework.context.ApplicationContext[] (for example, if it uses javadoc:org.springframework.web.servlet.support.AbstractDispatcherServletInitializer[]) then you might be able to combine all your context sources into a single javadoc:org.springframework.boot.SpringApplication[].\nThe main complication you might encounter is if combining does not work and you need to maintain the context hierarchy.\nSee the xref:application.adoc#howto.application.context-hierarchy[entry on building a hierarchy] for examples.\nAn existing parent context that contains web-specific features usually needs to be broken up so that all the javadoc:org.springframework.web.context.ServletContextAware[] components are in the child context.\n\nApplications that are not already Spring applications might be convertible to Spring Boot applications, and the previously mentioned guidance may help.\nHowever, you may yet encounter problems.\nIn that case, we suggest https://stackoverflow.com/questions/tagged/spring-boot[asking questions on Stack Overflow with a tag of `spring-boot`].\n\n\n\n[[howto.traditional-deployment.weblogic]]\n==  Deploying a WAR to WebLogic\n\nTo deploy a Spring Boot application to WebLogic, you must ensure that your servlet initializer *directly* implements javadoc:org.springframework.web.WebApplicationInitializer[] (even if you extend from a base class that already implements it).\n\nA typical initializer for WebLogic should resemble the following example:\n\ninclude-code::MyApplication[]\n\nIf you use Logback, you also need to tell WebLogic to prefer the packaged version rather than the version that was pre-installed with the server.\nYou can do so by adding a `WEB-INF/weblogic.xml` file with the following contents:\n\n[source,xml]\n----\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<wls:weblogic-web-app\n\txmlns:wls=\"http://xmlns.oracle.com/weblogic/weblogic-web-app\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee\n\t\thttps://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd\n\t\thttp://xmlns.oracle.com/weblogic/weblogic-web-app\n\t\thttps://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd\">\n\t<wls:container-descriptor>\n\t\t<wls:prefer-application-packages>\n\t\t\t<wls:package-name>org.slf4j</wls:package-name>\n\t\t</wls:prefer-application-packages>\n\t</wls:container-descriptor>\n</wls:weblogic-web-app>\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/docker-compose.adoc",
    "content": "[[howto.docker-compose]]\n= Docker Compose\n\nThis section includes topics relating to the Docker Compose support in Spring Boot.\n\n\n\n[[howto.docker-compose.jdbc-url]]\n== Customizing the JDBC URL\n\nWhen using javadoc:org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails[] with Docker Compose, the parameters of the JDBC URL\ncan be customized by applying the `org.springframework.boot.jdbc.parameters` label to the\nservice. For example:\n\n[source,yaml]\n----\nservices:\n  postgres:\n    image: 'postgres:15.3'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_PASSWORD=secret'\n      - 'POSTGRES_DB=mydb'\n    ports:\n      - '5432:5432'\n    labels:\n      org.springframework.boot.jdbc.parameters: 'ssl=true&sslmode=require'\n----\n\nWith this Docker Compose file in place, the JDBC URL used is `jdbc:postgresql://127.0.0.1:5432/mydb?ssl=true&sslmode=require`.\n\n\n\n[[howto.docker-compose.sharing-services]]\n== Sharing Services Between Multiple Applications\n\nIf you want to share services between multiple applications, create the `compose.yaml` file in one of the applications and then use the configuration property configprop:spring.docker.compose.file[] in the other applications to reference the `compose.yaml` file.\nYou should also set configprop:spring.docker.compose.lifecycle-management[] to `start-only`, as it defaults to `start-and-stop` and stopping one application would shut down the shared services for the other still running applications as well.\nSetting it to `start-only` won't stop the shared services on application stop, but a caveat is that if you shut down all applications, the services remain running.\nYou can stop the services manually by running `docker compose stop` on the command line in the directory which contains the `compose.yaml` file.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/hotswapping.adoc",
    "content": "[[howto.hotswapping]]\n= Hot Swapping\n\nSpring Boot supports hot swapping.\nThis section answers questions about how it works.\n\n\n\n[[howto.hotswapping.reload-static-content]]\n== Reload Static Content\n\nThere are several options for hot reloading.\nThe recommended approach is to use xref:reference:using/devtools.adoc[`spring-boot-devtools`], as it provides additional development-time features, such as support for fast application restarts and LiveReload as well as sensible development-time configuration (such as template caching).\nDevtools works by monitoring the classpath for changes.\nThis means that static resource changes must be \"built\" for the change to take effect.\nBy default, this happens automatically in Eclipse when you save your changes.\nIn IntelliJ IDEA, the Make Project command triggers the necessary build.\nDue to the xref:reference:using/devtools.adoc#using.devtools.restart.excluding-resources[default restart exclusions], changes to static resources do not trigger a restart of your application.\nThey do, however, trigger a live reload.\n\nAlternatively, running in an IDE (especially with debugging on) is a good way to do development (all modern IDEs allow reloading of static resources and usually also allow hot-swapping of Java class changes).\n\nFinally, the xref:build-tool-plugin:index.adoc[Maven and Gradle plugins] can be configured (see the `addResources` property) to support running from the command line with reloading of static files directly from source.\nYou can use that with an external css/js compiler process if you are writing that code with higher-level tools.\n\n\n\n[[howto.hotswapping.reload-templates]]\n== Reload Templates without Restarting the Container\n\nMost of the templating technologies supported by Spring Boot include a configuration option to disable caching (described later in this document).\nIf you use the `spring-boot-devtools` module, these properties are xref:reference:using/devtools.adoc#using.devtools.property-defaults[automatically configured] for you at development time.\n\n\n\n[[howto.hotswapping.reload-templates.thymeleaf]]\n=== Thymeleaf Templates\n\nIf you use Thymeleaf, set `spring.thymeleaf.cache` to `false`.\nSee {code-spring-boot-thymeleaf-src}/autoconfigure/ThymeleafAutoConfiguration.java[`ThymeleafAutoConfiguration`] for other Thymeleaf customization options.\n\n\n\n[[howto.hotswapping.reload-templates.freemarker]]\n=== FreeMarker Templates\n\nIf you use FreeMarker, set `spring.freemarker.cache` to `false`.\nSee {code-spring-boot-freemarker-src}/autoconfigure/FreeMarkerAutoConfiguration.java[`FreeMarkerAutoConfiguration`] for other FreeMarker customization options.\n\nNOTE: Template caching for FreeMarker is not supported with WebFlux.\n\n\n\n[[howto.hotswapping.reload-templates.groovy]]\n=== Groovy Templates\n\nIf you use Groovy templates, set `spring.groovy.template.cache` to `false`.\nSee {code-spring-boot-groovy-templates-src}/autoconfigure/GroovyTemplateAutoConfiguration.java[`GroovyTemplateAutoConfiguration`] for other Groovy customization options.\n\n\n\n[[howto.hotswapping.fast-application-restarts]]\n== Fast Application Restarts\n\nThe `spring-boot-devtools` module includes support for automatic application restarts.\nWhile not as fast as technologies such as https://www.jrebel.com/products/jrebel[JRebel] it is usually significantly faster than a \"`cold start`\".\nYou should probably give it a try before investigating some of the more complex reload options discussed later in this document.\n\nFor more details, see the xref:reference:using/devtools.adoc[] section.\n\n\n\n[[howto.hotswapping.reload-java-classes-without-restarting]]\n== Reload Java Classes without Restarting the Container\n\nMany modern IDEs (Eclipse, IntelliJ IDEA, and others) support hot swapping of bytecode.\nConsequently, if you make a change that does not affect class or method signatures, it should reload cleanly with no side effects.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/http-clients.adoc",
    "content": "[[howto.http-clients]]\n= HTTP Clients\n\nSpring Boot offers a number of starters that work with HTTP clients.\nThis section answers questions related to using them.\n\n\n\n[[howto.http-clients.rest-template-proxy-configuration]]\n== Configure RestTemplate to Use a Proxy\n\nAs described in xref:reference:io/rest-client.adoc#io.rest-client.resttemplate.customization[RestTemplate Customization], you can use a javadoc:org.springframework.boot.restclient.RestTemplateCustomizer[] with javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] to build a customized javadoc:org.springframework.web.client.RestTemplate[].\nThis is the recommended approach for creating a javadoc:org.springframework.web.client.RestTemplate[] configured to use a proxy.\n\nThe exact details of the proxy configuration depend on the underlying client request factory that is being used.\n\n\n\n[[howto.http-clients.webclient-reactor-netty-customization]]\n== Configure the TcpClient used by a Reactor Netty-based WebClient\n\nWhen Reactor Netty is on the classpath a Reactor Netty-based javadoc:org.springframework.web.reactive.function.client.WebClient[] is auto-configured.\nTo customize the client's handling of network connections, provide a javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] bean.\nThe following example configures a 60 second connect timeout and adds a javadoc:io.netty.handler.timeout.ReadTimeoutHandler[]:\n\ninclude-code::MyReactorNettyClientConfiguration[]\n\nTIP: Note the use of javadoc:org.springframework.http.client.ReactorResourceFactory[] for the connection provider and event loop resources.\nThis ensures efficient sharing of resources for the server receiving requests and the client making requests.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/index.adoc",
    "content": "[[howto]]\n= How-to Guides\n\nThis section provides answers to some common '`how do I do that...`' questions that often arise when using Spring Boot.\nIts coverage is not exhaustive, but it does cover quite a lot.\n\nIf you have a specific problem that we do not cover here, you might want to check https://stackoverflow.com/tags/spring-boot[stackoverflow.com] to see if someone has already provided an answer.\nThis is also a great place to ask new questions (please use the `spring-boot` tag).\n\nWe are also more than happy to extend this section.\nIf you want to add a '`how-to`', send us a {url-github}[pull request].\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/jersey.adoc",
    "content": "[[howto.jersey]]\n= Jersey\n\n\n\n[[howto.jersey.spring-security]]\n== Secure Jersey Endpoints with Spring Security\n\nSpring Security can be used to secure a Jersey-based web application in much the same way as it can be used to secure a Spring MVC-based web application.\nHowever, if you want to use Spring Security's method-level security with Jersey, you must configure Jersey to use `setStatus(int)` rather `sendError(int)`.\nThis prevents Jersey from committing the response before Spring Security has had an opportunity to report an authentication or authorization failure to the client.\n\nThe `jersey.config.server.response.setStatusOverSendError` property must be set to `true` on the application's javadoc:org.glassfish.jersey.server.ResourceConfig[] bean, as shown in the following example:\n\ninclude-code::JerseySetStatusOverSendErrorConfig[]\n\n\n\n[[howto.jersey.alongside-another-web-framework]]\n== Use Jersey Alongside Another Web Framework\n\nTo use Jersey alongside another web framework, such as Spring MVC, it should be configured so that it will allow the other framework to handle requests that it cannot handle.\nFirst, configure Jersey to use a filter rather than a servlet by configuring the configprop:spring.jersey.type[] application property with a value of `filter`.\nSecond, configure your javadoc:org.glassfish.jersey.server.ResourceConfig[] to forward requests that would have resulted in a 404, as shown in the following example.\n\ninclude-code::JerseyConfig[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/logging.adoc",
    "content": "[[howto.logging]]\n= Logging\n\nSpring Boot has no mandatory logging dependency, except for the Commons Logging API, which is typically provided by Spring Framework's `spring-jcl` module.\nTo use https://logback.qos.ch[Logback], you need to include it and `spring-jcl` on the classpath.\nThe recommended way to do that is through the starters, which all depend on `spring-boot-starter-logging`.\nFor a web application, you only need `spring-boot-starter-web`, since it depends transitively on the logging starter.\nIf you use Maven, the following dependency adds logging for you:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-web</artifactId>\n</dependency>\n----\n\nSpring Boot has a javadoc:org.springframework.boot.logging.LoggingSystem[] abstraction that attempts to configure logging based on the content of the classpath.\nIf Logback is available, it is the first choice.\n\nIf the only change you need to make to logging is to set the levels of various loggers, you can do so in `application.properties` by using the \"logging.level\" prefix, as shown in the following example:\n\n[configprops,yaml]\n----\nlogging:\n  level:\n    org.springframework.web: \"debug\"\n    org.hibernate: \"error\"\n----\n\nYou can also set the location of a file to which the log will be written (in addition to the console) by using `logging.file.name`.\n\nTo configure the more fine-grained settings of a logging system, you need to use the native configuration format supported by the javadoc:org.springframework.boot.logging.LoggingSystem[] in question.\nBy default, Spring Boot picks up the native configuration from its default location for the system (such as `classpath:logback.xml` for Logback), but you can set the location of the config file by using the configprop:logging.config[] property.\n\n\n\n[[howto.logging.logback]]\n== Configure Logback for Logging\n\nIf you need to apply customizations to logback beyond those that can be achieved with `application.properties`, you will need to add a standard logback configuration file.\nYou can add a `logback.xml` file to the root of your classpath for logback to find.\nYou can also use `logback-spring.xml` if you want to use the Spring Boot xref:reference:features/logging.adoc#features.logging.logback-extensions[].\n\nTIP: The Logback documentation has a https://logback.qos.ch/manual/configuration.html[dedicated section that covers configuration] in some detail.\n\nSpring Boot provides a number of logback configurations that can be `included` in your own configuration.\nThese includes are designed to allow certain common Spring Boot conventions to be re-applied.\n\nThe following files are provided under `org/springframework/boot/logging/logback/`:\n\n* `defaults.xml` - Provides conversion rules, pattern properties and common logger configurations.\n* `console-appender.xml` - Adds a javadoc:ch.qos.logback.core.ConsoleAppender[] using the `CONSOLE_LOG_PATTERN`.\n* `structured-console-appender.xml` - Adds a javadoc:ch.qos.logback.core.ConsoleAppender[] using structured logging in the `CONSOLE_LOG_STRUCTURED_FORMAT`.\n* `file-appender.xml` - Adds a javadoc:ch.qos.logback.core.rolling.RollingFileAppender[] using the `FILE_LOG_PATTERN` and `ROLLING_FILE_NAME_PATTERN` with appropriate settings.\n* `structured-file-appender.xml` - Adds a javadoc:ch.qos.logback.core.rolling.RollingFileAppender[] using the `ROLLING_FILE_NAME_PATTERN` with structured logging in the `FILE_LOG_STRUCTURED_FORMAT`.\n\nIn addition, a legacy `base.xml` file is provided for compatibility with earlier versions of Spring Boot.\n\nA typical custom `logback.xml` file would look something like this:\n\n[source,xml]\n----\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/defaults.xml\"/>\n\t<include resource=\"org/springframework/boot/logging/logback/console-appender.xml\" />\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"CONSOLE\" />\n\t</root>\n\t<logger name=\"org.springframework.web\" level=\"DEBUG\"/>\n</configuration>\n----\n\nYour logback configuration file can also make use of System properties that the javadoc:org.springframework.boot.logging.LoggingSystem[] takes care of creating for you:\n\n* `$\\{PID}`: The current process ID.\n* `$\\{LOG_FILE}`: Whether `logging.file.name` was set in Boot's external configuration.\n* `$\\{LOG_PATH}`: Whether `logging.file.path` (representing a directory for log files to live in) was set in Boot's external configuration.\n* `$\\{LOG_EXCEPTION_CONVERSION_WORD}`: Whether `logging.exception-conversion-word` was set in Boot's external configuration.\n* `$\\{ROLLING_FILE_NAME_PATTERN}`: Whether `logging.pattern.rolling-file-name` was set in Boot's external configuration.\n\nSpring Boot also provides some nice ANSI color terminal output on a console (but not in a log file) by using a custom Logback converter.\nSee the `CONSOLE_LOG_PATTERN` in the `defaults.xml` configuration for an example.\n\nIf Groovy is on the classpath, you should be able to configure Logback with `logback.groovy` as well.\nIf present, this setting is given preference.\n\nNOTE: Spring extensions are not supported with Groovy configuration.\nAny `logback-spring.groovy` files will not be detected.\n\n\n\n[[howto.logging.logback.file-only-output]]\n=== Configure Logback for File-only Output\n\nIf you want to disable console logging and write output only to a file, you need a custom `logback-spring.xml` that imports `file-appender.xml` but not `console-appender.xml`, as shown in the following example:\n\n[source,xml]\n----\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/defaults.xml\" />\n\t<property name=\"LOG_FILE\" value=\"${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}\"/>\n\t<include resource=\"org/springframework/boot/logging/logback/file-appender.xml\" />\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"FILE\" />\n\t</root>\n</configuration>\n----\n\nYou also need to add `logging.file.name` to your `application.properties` or `application.yaml`, as shown in the following example:\n\n[configprops,yaml]\n----\nlogging:\n  file:\n    name: \"myapplication.log\"\n----\n\n\n\n[[howto.logging.log4j]]\n== Configure Log4j for Logging\n\nSpring Boot supports https://logging.apache.org/log4j/2.x/[Log4j 2] for logging configuration if it is on the classpath.\nIf you use the starters for assembling dependencies, you have to exclude Logback and then include Log4j 2 instead.\nIf you do not use the starters, you need to provide (at least) `spring-jcl` in addition to Log4j 2.\n\nThe recommended path is through the starters, even though it requires some jiggling.\nThe following example shows how to set up the starters in Maven:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-web</artifactId>\n</dependency>\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter</artifactId>\n\t<exclusions>\n\t\t<exclusion>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-logging</artifactId>\n\t\t</exclusion>\n\t</exclusions>\n</dependency>\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-log4j2</artifactId>\n</dependency>\n----\n\nGradle provides a few different ways to set up the starters.\nOne way is to use a {url-gradle-docs}/resolution_rules.html#sec:module_replacement[module replacement].\nTo do so, declare a dependency on the Log4j 2 starter and tell Gradle that any occurrences of the default logging starter should be replaced by the Log4j 2 starter, as shown in the following example:\n\n[source,gradle]\n----\ndependencies {\n\timplementation \"org.springframework.boot:spring-boot-starter-log4j2\"\n\tmodules {\n\t\tmodule(\"org.springframework.boot:spring-boot-starter-logging\") {\n\t\t\treplacedBy(\"org.springframework.boot:spring-boot-starter-log4j2\", \"Use Log4j2 instead of Logback\")\n\t\t}\n\t}\n}\n----\n\nNOTE: The Log4j starters gather together the dependencies for common logging requirements (such as having Tomcat use `java.util.logging` but configuring the output using Log4j 2).\n\nNOTE: To ensure that debug logging performed using `java.util.logging` is routed into Log4j 2, configure its https://logging.apache.org/log4j/2.x/log4j-jul.html[JDK logging adapter] by setting the `java.util.logging.manager` system property to `org.apache.logging.log4j.jul.LogManager`.\n\n\n\n[[howto.logging.log4j.yaml-or-json-config]]\n=== Use YAML or JSON to Configure Log4j 2\n\nIn addition to its default XML configuration format, Log4j 2 also supports YAML and JSON configuration files.\nTo configure Log4j 2 to use an alternative configuration file format, add the appropriate dependencies to the classpath and name your configuration files to match your chosen file format, as shown in the following example:\n\n[cols=\"10,75a,15a\"]\n|===\n| Format | Dependencies | File names\n\n|YAML\n| `com.fasterxml.jackson.core:jackson-databind` + `com.fasterxml.jackson.dataformat:jackson-dataformat-yaml`\n| `log4j2.yaml` + `log4j2.yml`\n\n|JSON\n| `com.fasterxml.jackson.core:jackson-databind`\n| `log4j2.json` + `log4j2.jsn`\n|===\n\n\n\n[[howto.logging.log4j.composite-configuration]]\n=== Use Composite Configuration to Configure Log4j 2\n\nLog4j 2 has support for combining multiple configuration files into a single composite configuration.\nTo use this support in Spring Boot, configure configprop:logging.log4j2.config.override[] with the locations of one or more secondary configuration files.\nThe secondary configuration files will be merged with the primary configuration, whether the primary's source is Spring Boot's defaults, a standard location such as `log4j.xml`, or the location configured by the configprop:logging.config[] property.\n\n[NOTE]\n====\nLog4j2 override configuration file locations can be prefixed with `optional:`.\nFor example, `optional:classpath:log4j2-override.xml` indicates that `log4j2-override.xml` should only be loaded if the resource exists.\n====\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/messaging.adoc",
    "content": "[[howto.messaging]]\n= Messaging\n\nSpring Boot offers a number of starters to support messaging.\nThis section answers questions that arise from using messaging with Spring Boot.\n\n\n\n[[howto.messaging.disable-transacted-jms-session]]\n== Disable Transacted JMS Session\n\nIf your JMS broker does not support transacted sessions, you have to disable the support of transactions altogether.\nIf you create your own javadoc:org.springframework.jms.config.JmsListenerContainerFactory[], there is nothing to do, since, by default it cannot be transacted.\nIf you want to use the javadoc:org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer[] to reuse Spring Boot's default, you can disable transacted sessions, as follows:\n\ninclude-code::MyJmsConfiguration[]\n\nThe preceding example overrides the default factory, and it should be applied to any other factory that your application defines, if any.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/native-image/developing-your-first-application.adoc",
    "content": "[[howto.native-image.developing-your-first-application]]\n= Developing Your First GraalVM Native Application\n\nThere are two main ways to build a Spring Boot native image application:\n\n* Using Spring Boot xref:reference:packaging/container-images/cloud-native-buildpacks.adoc[support for Cloud Native Buildpacks] with the https://paketo.io/docs/reference/java-native-image-reference/[Paketo Java Native Image buildpack] to generate a lightweight container containing a native executable.\n* Using GraalVM Native Build Tools to generate a native executable.\n\nTIP: The easiest way to start a new native Spring Boot project is to go to https://start.spring.io[start.spring.io], add the `GraalVM Native Support` dependency and generate the project.\nThe included `HELP.md` file will provide getting started hints.\n\n\n\n[[howto.native-image.developing-your-first-application.sample-application]]\n== Sample Application\n\nWe need an example application that we can use to create our native image.\nFor our purposes, the simple \"Hello World!\" web application that's covered in the xref:tutorial:first-application/index.adoc[] section will suffice.\n\nTo recap, our main application code looks like this:\n\ninclude-code::MyApplication[]\n\nThis application uses Spring MVC and embedded Tomcat, both of which have been tested and verified to work with GraalVM native images.\n\n\n\n[[howto.native-image.developing-your-first-application.buildpacks]]\n== Building a Native Image Using Buildpacks\n\nSpring Boot supports building Docker images containing native executables, using Cloud Native Buildpacks (CNB) integration with both Maven and Gradle and the https://paketo.io/docs/reference/java-native-image-reference/[Paketo Java Native Image buildpack].\nThis means you can just type a single command and quickly get a sensible image into your locally running Docker daemon.\nThe resulting image doesn't contain a JVM, instead the native image is compiled statically.\nThis leads to smaller images.\n\nNOTE: The CNB builder used for the images is `paketobuildpacks/builder-noble-java-tiny:latest`.\nIt has a small footprint and reduced attack surface. It does not include a shell and contains a reduced set of system libraries.\nIf you need more tools in the resulting image, you can use `paketobuildpacks/ubuntu-noble-run:latest` as the *run* image.\n\nNOTE: You have to build your application with at least JDK 25, because Buildpacks use the same GraalVM native-image version as the Java version used for compilation.\n\n\n\n[[howto.native-image.developing-your-first-application.buildpacks.system-requirements]]\n=== System Requirements\n\nDocker should be installed. See https://docs.docker.com/installation/#installation[Get Docker] for more details.\nhttps://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user[Configure it to allow non-root user] if you are on Linux.\n\nNOTE: You can run `docker run hello-world` (without `sudo`) to check the Docker daemon is reachable as expected.\nCheck the xref:maven-plugin:build-image.adoc#build-image.docker-daemon[Maven] or xref:gradle-plugin:packaging-oci-image.adoc#build-image.docker-daemon[Gradle] Spring Boot plugin documentation for more details.\n\nTIP: On macOS, it is recommended to increase the memory allocated to Docker to at least `8GB`, and potentially add more CPUs as well.\nSee this https://stackoverflow.com/questions/44533319/how-to-assign-more-memory-to-docker-container/44533437#44533437[Stack Overflow answer] for more details.\nOn Microsoft Windows, make sure to enable the https://docs.docker.com/docker-for-windows/wsl/[Docker WSL 2 backend] for better performance.\n\n\n\n[[howto.native-image.developing-your-first-application.buildpacks.maven]]\n=== Using Maven\n\nTo build a native image container using Maven you should ensure that your `pom.xml` file uses the `spring-boot-starter-parent` and the `org.graalvm.buildtools:native-maven-plugin`.\nYou should have a `<parent>` section that looks like this:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<parent>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-parent</artifactId>\n\t<version>{version-spring-boot}</version>\n</parent>\n----\n\nYou additionally should have this in the `<build> <plugins>` section:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<plugin>\n\t<groupId>org.graalvm.buildtools</groupId>\n\t<artifactId>native-maven-plugin</artifactId>\n</plugin>\n----\n\nThe `spring-boot-starter-parent` declares a `native` profile that configures the executions that need to run in order to create a native image.\nYou can activate profiles using the `-P` flag on the command line.\n\nTIP: If you don't want to use `spring-boot-starter-parent` you'll need to configure executions for the `process-aot` goal from Spring Boot's plugin and the `add-reachability-metadata` goal from the Native Build Tools plugin.\n\nTo build the image, you can run the `spring-boot:build-image` goal with the `native` profile active:\n\n[source,shell]\n----\n$ mvn -Pnative spring-boot:build-image\n----\n\n\n\n[[howto.native-image.developing-your-first-application.buildpacks.gradle]]\n=== Using Gradle\n\nThe Spring Boot Gradle plugin automatically configures AOT tasks when the GraalVM Native Image plugin is applied.\nYou should check that your Gradle build contains a `plugins` block that includes `org.graalvm.buildtools.native`.\n\nAs long as the `org.graalvm.buildtools.native` plugin is applied, the `bootBuildImage` task will generate a native image rather than a JVM one.\nYou can run the task using:\n\n[source,shell]\n----\n$ gradle bootBuildImage\n----\n\n\n\n[[howto.native-image.developing-your-first-application.buildpacks.running]]\n=== Running the example\n\nOnce you have run the appropriate build command, a Docker image should be available.\nYou can start your application using `docker run`:\n\n[source,shell]\n----\n$ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT\n----\n\nYou should see output similar to the following:\n\n[source,shell]\n----\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::  (v{version-spring-boot})\n....... . . .\n....... . . . (log output here)\n....... . . .\n........ Started MyApplication in 0.08 seconds (process running for 0.095)\n----\n\nNOTE: The startup time differs from machine to machine, but it should be much faster than a Spring Boot application running on a JVM.\n\nIf you open a web browser to `http://localhost:8080`, you should see the following output:\n\n[source]\n----\nHello World!\n----\n\nTo gracefully exit the application, press `ctrl-c`.\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools]]\n== Building a Native Image using Native Build Tools\n\nIf you want to generate a native executable directly without using Docker, you can use GraalVM Native Build Tools.\nNative Build Tools are plugins shipped by GraalVM for both Maven and Gradle.\nYou can use them to perform a variety of GraalVM tasks, including generating a native image.\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools.prerequisites]]\n=== Prerequisites\n\nTo build a native image using the Native Build Tools, you'll need a GraalVM distribution on your machine.\nYou can either download it manually on the {url-download-liberica-nik}[Liberica Native Image Kit page], or you can use a download manager like SDKMAN!.\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools.prerequisites.linux-macos]]\n==== Linux and macOS\n\nTo install the native image compiler on macOS or Linux, we recommend using SDKMAN!.\nGet SDKMAN! from https://sdkman.io and install the Liberica GraalVM distribution by using the following commands:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ sdk install java 25.r25-nik\n$ sdk use java 25.r25-nik\n----\n\nVerify that the correct version has been configured by checking the output of `java -version`:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ java -version\nopenjdk version \"25\" 2025-09-16 LTS\nOpenJDK Runtime Environment Liberica-NIK-25.0.0-1 (build 25+37-LTS)\nOpenJDK 64-Bit Server VM Liberica-NIK-25.0.0-1 (build 25+37-LTS, mixed mode, sharing)\n----\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools.prerequisites.windows]]\n==== Windows\n\nOn Windows, follow https://medium.com/graalvm/using-graalvm-and-native-image-on-windows-10-9954dc071311[these instructions] to install either https://www.graalvm.org/downloads/[GraalVM] or {url-download-liberica-nik}[Liberica Native Image Kit] in version {version-graal}, the Visual Studio Build Tools and the Windows SDK.\nDue to the https://docs.microsoft.com/en-US/troubleshoot/windows-client/shell-experience/command-line-string-limitation[Windows related command-line maximum length], make sure to use x64 Native Tools Command Prompt instead of the regular Windows command line to run Maven or Gradle plugins.\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools.maven]]\n=== Using Maven\n\nAs with the xref:native-image/developing-your-first-application.adoc#howto.native-image.developing-your-first-application.buildpacks.maven[buildpacks support], you need to make sure that you're using `spring-boot-starter-parent` in order to inherit the `native` profile and that the `org.graalvm.buildtools:native-maven-plugin` plugin is used.\n\nWith the `native` profile active, you can invoke the `native:compile` goal to trigger `native-image` compilation:\n\n[source,shell]\n----\n$ mvn -Pnative native:compile\n----\n\nThe native image executable can be found in the `target` directory.\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools.gradle]]\n=== Using Gradle\n\nWhen the Native Build Tools Gradle plugin is applied to your project, the Spring Boot Gradle plugin will automatically trigger the Spring AOT engine.\nTask dependencies are automatically configured, so you can just run the standard `nativeCompile` task to generate a native image:\n\n[source,shell]\n----\n$ gradle nativeCompile\n----\n\nThe native image executable can be found in the `build/native/nativeCompile` directory.\n\n\n\n[[howto.native-image.developing-your-first-application.native-build-tools.running]]\n=== Running the Example\n\nAt this point, your application should work. You can now start the application by running it directly:\n\n[tabs]\n======\nMaven::\n+\n[source,shell]\n----\n$ target/myproject\n----\nGradle::\n+\n[source,shell]\n----\n$ build/native/nativeCompile/myproject\n----\n======\n\nYou should see output similar to the following:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::  (v{version-spring-boot})\n....... . . .\n....... . . . (log output here)\n....... . . .\n........ Started MyApplication in 0.08 seconds (process running for 0.095)\n----\n\nNOTE: The startup time differs from machine to machine, but it should be much faster than a Spring Boot application running on a JVM.\n\nIf you open a web browser to `http://localhost:8080`, you should see the following output:\n\n[source]\n----\nHello World!\n----\n\nTo gracefully exit the application, press `ctrl-c`.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/native-image/index.adoc",
    "content": "[[howto.native-image]]\n= GraalVM Native Applications\n\nThis section contains details on developing and testing Spring Boot applications as GraalVM native images.\n\nTIP: For an overview of GraalVM native image concepts, see the xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc[] section.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/native-image/testing-native-applications.adoc",
    "content": "[[howto.native-image.testing]]\n= Testing GraalVM Native Images\n\nWhen writing native image applications, we recommend that you continue to use the JVM whenever possible to develop the majority of your unit and integration tests.\nThis will help keep developer build times down and allow you to use existing IDE integrations.\nWith broad test coverage on the JVM, you can then focus native image testing on the areas that are likely to be different.\n\nFor native image testing, you're generally looking to ensure that the following aspects work:\n\n* The Spring AOT engine is able to process your application, and it will run in an AOT-processed mode.\n* GraalVM has enough hints to ensure that a valid native image can be produced.\n\n\n\n\n[[howto.native-image.testing.with-the-jvm]]\n== Testing Ahead-of-Time Processing With the JVM\n\nWhen a Spring Boot application runs, it attempts to detect if it is running as a native image.\nIf it is running as a native image, it will initialize the application using the code that was generated during at build-time by the Spring AOT engine.\n\nIf the application is running on a regular JVM, then any AOT generated code is ignored.\n\nSince the `native-image` compilation phase can take a while to complete, it's sometimes useful to run your application on the JVM but have it use the AOT generated initialization code.\nDoing so helps you to quickly validate that there are no errors in the AOT generated code and nothing is missing when your application is eventually converted to a native image.\n\nTo run a Spring Boot application on the JVM and have it use AOT generated code you can set the `spring.aot.enabled` system property to `true`.\n\nFor example:\n\n[source,shell]\n----\n$ java -Dspring.aot.enabled=true -jar myapplication.jar\n----\n\nNOTE: You need to ensure that the jar you are testing includes AOT generated code.\nFor Maven, this means that you should build with `-Pnative` to activate the `native` profile.\nFor Gradle, you need to ensure that your build includes the `org.graalvm.buildtools.native` plugin.\n\nIf your application starts with the `spring.aot.enabled` property set to `true`, then you have higher confidence that it will work when converted to a native image.\n\nYou can also consider running integration tests against the running application.\nFor example, you could use the Spring javadoc:org.springframework.web.reactive.function.client.WebClient[] to call your application REST endpoints.\nOr you might consider using a project like Selenium to check your application's HTML responses.\n\n\n\n[[howto.native-image.testing.with-native-build-tools]]\n== Testing With Native Build Tools\n\nGraalVM Native Build Tools includes the ability to run tests inside a native image.\nThis can be helpful when you want to deeply test that the internals of your application work in a GraalVM native image.\n\nGenerating the native image that contains the tests to run can be a time-consuming operation, so most developers will probably prefer to use the JVM locally.\nThey can, however, be very useful as part of a CI pipeline.\nFor example, you might choose to run native tests once a day.\n\nSpring Framework includes ahead-of-time support for running tests.\nAll the usual Spring testing features work with native image tests.\nFor example, you can continue to use the javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] annotation.\nYou can also use Spring Boot xref:reference:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[test slices] to test only specific parts of your application.\n\nSpring Framework's native testing support works in the following way:\n\n* Tests are analyzed in order to discover any javadoc:org.springframework.context.ApplicationContext[] instances that will be required.\n* Ahead-of-time processing is applied to each of these application contexts and assets are generated.\n* A native image is created, with the generated assets being processed by GraalVM.\n* The native image also includes the JUnit javadoc:org.junit.platform.engine.TestEngine[] configured with a list of the discovered tests.\n* The native image is started, triggering the engine which will run each test and report results.\n\n\n\n[[howto.native-image.testing.with-native-build-tools.maven]]\n=== Using Maven\n\nTo run native tests using Maven, ensure that your `pom.xml` file uses the `spring-boot-starter-parent`.\nYou should have a `<parent>` section that looks like this:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<parent>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-parent</artifactId>\n\t<version>{version-spring-boot}</version>\n</parent>\n----\n\nThe `spring-boot-starter-parent` defines a `nativeTest` profile that provides the necessary configuration for the Spring Boot and Native Build Tools plugins.\nFirst you need to add those two plugin in the module to opt-in for the feature.\nYour tests are executed in native mode only when the `nativeTest` is enabled.\nYou can activate profiles using the `-P` flag on the command line.\n\nTIP: If you don't want to use `spring-boot-starter-parent` you'll need to configure executions for the `process-test-aot` goal from the Spring Boot plugin and the `test` goal from the Native Build Tools plugin.\n\nTo build the image and run the tests, use the `test` goal with the `nativeTest` profile active:\n\n[source,shell]\n----\n$ mvn -PnativeTest test\n----\n\n\n\n[[howto.native-image.testing.with-native-build-tools.gradle]]\n=== Using Gradle\n\nThe Spring Boot Gradle plugin automatically configures AOT test tasks when the GraalVM Native Image plugin is applied.\nYou should check that your Gradle build contains a `plugins` block that includes `org.graalvm.buildtools.native`.\n\nTo run native tests using Gradle you can use the `nativeTest` task:\n\n[source,shell]\n----\n$ gradle nativeTest\n----\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/nosql.adoc",
    "content": "[[howto.nosql]]\n= NoSQL\n\nSpring Boot offers a number of starters that support NoSQL technologies.\nThis section answers questions that arise from using NoSQL with Spring Boot.\n\n\n\n[[howto.nosql.jedis-instead-of-lettuce]]\n== Use Jedis Instead of Lettuce\n\nBy default, the Spring Boot starter (`spring-boot-starter-data-redis`) uses https://github.com/redis/lettuce/[Lettuce].\nYou need to exclude that dependency and include the https://github.com/redis/jedis/[Jedis] one instead.\nSpring Boot manages both of these dependencies, allowing you to switch to Jedis without specifying a version.\n\nThe following example shows how to accomplish this in Maven:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-data-redis</artifactId>\n\t<exclusions>\n\t\t<exclusion>\n\t\t\t<groupId>io.lettuce</groupId>\n\t\t\t<artifactId>lettuce-core</artifactId>\n\t\t</exclusion>\n\t</exclusions>\n</dependency>\n<dependency>\n\t<groupId>redis.clients</groupId>\n\t<artifactId>jedis</artifactId>\n</dependency>\n----\n\nThe following example shows how to accomplish this in Gradle:\n\n[source,gradle]\n----\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter-data-redis') {\n\t    exclude group: 'io.lettuce', module: 'lettuce-core'\n\t}\n\timplementation 'redis.clients:jedis'\n\t// ...\n}\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/properties-and-configuration.adoc",
    "content": "[[howto.properties-and-configuration]]\n= Properties and Configuration\n\nThis section includes topics about setting and reading properties and configuration settings and their interaction with Spring Boot applications.\n\n\n\n[[howto.properties-and-configuration.expand-properties]]\n== Automatically Expand Properties at Build Time\n\nRather than hardcoding some properties that are also specified in your project's build configuration, you can automatically expand them by instead using the existing build configuration.\nThis is possible in both Maven and Gradle.\n\n\n\n[[howto.properties-and-configuration.expand-properties.maven]]\n=== Automatic Property Expansion Using Maven\n\nYou can automatically expand properties in the Maven project by using resource filtering.\nIf you use the `spring-boot-starter-parent`, you can then refer to your Maven '`project properties`' with `@..@` placeholders, as shown in the following example:\n\n[configprops%novalidate,yaml]\n----\napp:\n  encoding: \"@project.build.sourceEncoding@\"\n  java:\n    version: \"@java.version@\"\n----\n\nNOTE: Only production configuration is filtered that way (in other words, no filtering is applied on `src/test/resources`).\n\nTIP: If you enable the `addResources` flag, the `spring-boot:run` goal can add `src/main/resources` directly to the classpath (for hot reloading purposes).\nDoing so circumvents the resource filtering and this feature.\nInstead, you can use the `exec:java` goal or customize the plugin's configuration.\nSee the xref:maven-plugin:using.adoc[plugin usage page] for more details.\n\nIf you do not use the starter parent, you need to include the following  element inside the `<build/>` element of your `pom.xml`:\n\n[source,xml]\n----\n<resources>\n\t<resource>\n\t\t<directory>src/main/resources</directory>\n\t\t<filtering>true</filtering>\n\t</resource>\n</resources>\n----\n\nYou also need to include the following element inside `<plugins/>`:\n\n[source,xml]\n----\n<plugin>\n\t<groupId>org.apache.maven.plugins</groupId>\n\t<artifactId>maven-resources-plugin</artifactId>\n\t<version>2.7</version>\n\t<configuration>\n\t\t<delimiters>\n\t\t\t<delimiter>@</delimiter>\n\t\t</delimiters>\n\t\t<useDefaultDelimiters>false</useDefaultDelimiters>\n\t</configuration>\n</plugin>\n----\n\nNOTE: The `useDefaultDelimiters` property is important if you use standard Spring placeholders (such as `$\\{placeholder}`) in your configuration.\nIf that property is not set to `false`, these may be expanded by the build.\n\n\n\n[[howto.properties-and-configuration.expand-properties.gradle]]\n=== Automatic Property Expansion Using Gradle\n\nYou can automatically expand properties from the Gradle project by configuring the Java plugin's `processResources` task to do so, as shown in the following example:\n\n[source,gradle]\n----\ntasks.named('processResources') {\n\texpand(project.properties)\n}\n----\n\nYou can then refer to your Gradle project's properties by using placeholders, as shown in the following example:\n\n[configprops%novalidate,yaml]\n----\napp:\n  name: \"${name}\"\n  description: \"${description}\"\n----\n\nNOTE: Gradle's `expand` method uses Groovy's `SimpleTemplateEngine`, which transforms `${..}` tokens.\nThe `${..}` style conflicts with Spring's own property placeholder mechanism.\nTo use Spring property placeholders together with automatic expansion, escape the Spring property placeholders as follows: `\\${..}`.\n\n\n\n[[howto.properties-and-configuration.externalize-configuration]]\n== Externalize the Configuration of SpringApplication\n\nA javadoc:org.springframework.boot.SpringApplication[] has bean property setters, so you can use its Java API as you create the application to modify its behavior.\nAlternatively, you can externalize the configuration by setting properties in `+spring.main.*+`.\nFor example, in `application.properties`, you might have the following settings:\n\n[configprops,yaml]\n----\nspring:\n  main:\n    web-application-type: \"none\"\n    banner-mode: \"off\"\n----\n\nThen the Spring Boot banner is not printed on startup, and the application is not starting an embedded web server.\n\nProperties defined in external configuration override and replace the values specified with the Java API, with the notable exception of the primary sources.\nPrimary sources are those provided to the javadoc:org.springframework.boot.SpringApplication[] constructor:\n\ninclude-code::application/MyApplication[]\n\nOr to `sources(...)` method of a javadoc:org.springframework.boot.builder.SpringApplicationBuilder[]:\n\ninclude-code::builder/MyApplication[]\n\nGiven the examples above, if we have the following configuration:\n\n[configprops,yaml]\n----\nspring:\n  main:\n    sources: \"com.example.MyDatabaseConfig,com.example.MyJmsConfig\"\n    banner-mode: \"console\"\n----\n\nThe actual application will show the banner (as overridden by configuration) and use three sources for the javadoc:org.springframework.context.ApplicationContext[].\nThe application sources are:\n\n. `MyApplication` (from the code)\n. `MyDatabaseConfig` (from the external config)\n. `MyJmsConfig`(from the external config)\n\n\n\n[[howto.properties-and-configuration.external-properties-location]]\n== Change the Location of External Properties of an Application\n\nBy default, properties from different sources are added to the Spring javadoc:org.springframework.core.env.Environment[] in a defined order (see xref:reference:features/external-config.adoc[] in the \"`Spring Boot Features`\" section for the exact order).\n\nYou can also provide the following System properties (or environment variables) to change the behavior:\n\n* configprop:spring.config.name[] (configprop:spring.config.name[format=envvar]): Defaults to `application` as the root of the file name.\n* configprop:spring.config.location[] (configprop:spring.config.location[format=envvar]): The file to load (such as a classpath resource or a URL).\n  A separate javadoc:org.springframework.core.env.Environment[] property source is set up for this document and it can be overridden by system properties, environment variables, or the command line.\n\nNo matter what you set in the environment, Spring Boot always loads `application.properties` as described above.\nBy default, if YAML is used, then files with the '`.yaml`' and '`.yml`' extensions are also added to the list.\n\nTIP: If you want detailed information about the files that are being loaded you can xref:reference:features/logging.adoc#features.logging.log-levels[set the logging level] of `org.springframework.boot.context.config` to `trace`.\n\n\n\n[[howto.properties-and-configuration.short-command-line-arguments]]\n== Use '`Short`' Command Line Arguments\n\nSome people like to use (for example) `--port=9000` instead of `--server.port=9000` to set configuration properties on the command line.\nYou can enable this behavior by using placeholders in `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  port: \"${port:8080}\"\n----\n\nTIP: If you inherit from the `spring-boot-starter-parent` POM, the default filter token of the `maven-resources-plugins` has been changed from `+${*}+` to `@` (that is, `@maven.token@` instead of `${maven.token}`) to prevent conflicts with Spring-style placeholders.\nIf you have enabled Maven filtering for the `application.properties` directly, you may want to also change the default filter token to use https://maven.apache.org/plugins/maven-resources-plugin/resources-mojo.html#delimiters[other delimiters].\n\nNOTE: In this specific case, the port binding works in a PaaS environment such as Heroku or Cloud Foundry.\nOn those two platforms, the `PORT` environment variable is set automatically and Spring can bind to capitalized synonyms for javadoc:org.springframework.core.env.Environment[] properties.\n\n\n\n[[howto.properties-and-configuration.yaml]]\n== Use YAML for External Properties\n\nYAML is a superset of JSON and, as such, is a convenient syntax for storing external properties in a hierarchical format, as shown in the following example:\n\n[source,yaml]\n----\nspring:\n  application:\n    name: \"cruncher\"\n  datasource:\n    driver-class-name: \"com.mysql.jdbc.Driver\"\n    url: \"jdbc:mysql://localhost/test\"\nserver:\n  port: 9000\n----\n\nCreate a file called `application.yaml` and put it in the root of your classpath.\nThen add `snakeyaml` to your dependencies (Maven coordinates `org.yaml:snakeyaml`, already included if you use the `spring-boot-starter`).\nA YAML file is parsed to a Java `Map<String,Object>` (like a JSON object), and Spring Boot flattens the map so that it is one level deep and has period-separated keys, as many people are used to with javadoc:java.util.Properties[] files in Java.\n\nThe preceding example YAML corresponds to the following `application.properties` file:\n\n[source,properties,subs=\"verbatim\",configprops]\n----\nspring.application.name=cruncher\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\nspring.datasource.url=jdbc:mysql://localhost/test\nserver.port=9000\n----\n\nSee xref:reference:features/external-config.adoc#features.external-config.yaml[] in the \"`Spring Boot Features`\" section for more information about YAML.\n\n\n\n[[howto.properties-and-configuration.set-active-spring-profiles]]\n== Set the Active Spring Profiles\n\nThe Spring javadoc:org.springframework.core.env.Environment[] has an API for this, but you would normally set a System property (configprop:spring.profiles.active[]) or an OS environment variable (configprop:spring.profiles.active[format=envvar]).\nAlso, you can launch your application with a `-D` argument (remember to put it before the main class or jar archive), as follows:\n\n[source,shell]\n----\n$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar\n----\n\nIn Spring Boot, you can also set the active profile in `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    active: \"production\"\n----\n\nA value set this way is replaced by the System property or environment variable setting but not by the `SpringApplicationBuilder.profiles()` method.\nThus, the latter Java API can be used to augment the profiles without changing the defaults.\n\nSee xref:reference:features/profiles.adoc[] in the \"`Spring Boot Features`\" section for more information.\n\n\n\n[[howto.properties-and-configuration.set-default-spring-profile-name]]\n== Set the Default Profile Name\n\nThe default profile is a profile that is enabled if no profile is active.\nBy default, the name of the default profile is `default`, but it could be changed using a System property (configprop:spring.profiles.default[]) or an OS environment variable (configprop:spring.profiles.default[format=envvar]).\n\nIn Spring Boot, you can also set the default profile name in `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    default: \"dev\"\n----\n\nSee xref:reference:features/profiles.adoc[] in the \"`Spring Boot Features`\" section for more information.\n\n\n\n[[howto.properties-and-configuration.change-configuration-depending-on-the-environment]]\n== Change Configuration Depending on the Environment\n\nSpring Boot supports multi-document YAML and Properties files (see xref:reference:features/external-config.adoc#features.external-config.files.multi-document[] for details) which can be activated conditionally based on the active profiles.\n\nIf a document contains a `spring.config.activate.on-profile` key, then the profiles value (a comma-separated list of profiles or a profile expression) is fed into the Spring `Environment.acceptsProfiles()` method.\nIf the profile expression matches, then that document is included in the final merge (otherwise, it is not), as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  port: 9000\n---\nspring:\n  config:\n    activate:\n      on-profile: \"development\"\nserver:\n  port: 9001\n---\nspring:\n  config:\n    activate:\n      on-profile: \"production\"\nserver:\n  port: 0\n----\n\nIn the preceding example, the default port is 9000.\nHowever, if the Spring profile called '`development`' is active, then the port is 9001.\nIf '`production`' is active, then the port is 0.\n\nNOTE: The documents are merged in the order in which they are encountered.\nLater values override earlier values.\n\n\n\n[[howto.properties-and-configuration.discover-build-in-options-for-external-properties]]\n== Discover Built-in Options for External Properties\n\nSpring Boot binds external properties from `application.properties` (or YAML files and other places) into an application at runtime.\nThere is not (and technically cannot be) an exhaustive list of all supported properties in a single location, because contributions can come from additional jar files on your classpath.\n\nA running application with the Actuator features has a `configprops` endpoint that shows all the bound and bindable properties available through javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\n\nThe appendix includes an xref:appendix:application-properties/index.adoc[`application.properties`] example with a list of the most common properties supported by Spring Boot.\nThe definitive list comes from searching the source code for javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] and javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotations as well as the occasional use of javadoc:org.springframework.boot.context.properties.bind.Binder[].\nFor more about the exact ordering of loading properties, see xref:reference:features/external-config.adoc[].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/security.adoc",
    "content": "[[howto.security]]\n= Security\n\nThis section addresses questions about security when working with Spring Boot, including questions that arise from using Spring Security with Spring Boot.\n\nFor more about Spring Security, see the {url-spring-security-site}[Spring Security project page].\n\n\n\n[[howto.security.switch-off-spring-boot-configuration]]\n== Switch Off the Spring Boot Security Configuration\n\nIf you define a javadoc:org.springframework.context.annotation.Configuration[format=annotation] with a javadoc:org.springframework.security.web.SecurityFilterChain[] bean in your application, this action switches off the default webapp security settings in Spring Boot.\n\n\n\n[[howto.security.change-user-details-service-and-add-user-accounts]]\n== Change the UserDetailsService and Add User Accounts\n\nIf you provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.security.authentication.AuthenticationManager[], javadoc:org.springframework.security.authentication.AuthenticationProvider[], or javadoc:org.springframework.security.core.userdetails.UserDetailsService[], the default javadoc:org.springframework.context.annotation.Bean[format=annotation] for javadoc:org.springframework.security.provisioning.InMemoryUserDetailsManager[] is not created.\nThis means you have the full feature set of Spring Security available (such as {url-spring-security-docs}/servlet/authentication/index.html[various authentication options]).\n\nThe easiest way to add user accounts is by providing your own javadoc:org.springframework.security.core.userdetails.UserDetailsService[] bean.\n\n\n\n[[howto.security.enable-https]]\n== Enable HTTPS When Running Behind a Proxy Server\n\nEnsuring that all your main endpoints are only available over HTTPS is an important chore for any application.\nIf you use Tomcat as a servlet container, then Spring Boot adds Tomcat's own javadoc:org.apache.catalina.valves.RemoteIpValve[] automatically if it detects some environment settings, allowing you to rely on the javadoc:jakarta.servlet.http.HttpServletRequest[] to report whether it is secure or not (even downstream of a proxy server that handles the real SSL termination).\nThe standard behavior is determined by the presence or absence of certain request headers (`x-forwarded-for` and `x-forwarded-proto`), whose names are conventional, so it should work with most front-end proxies.\nYou can switch on the valve by adding some entries to `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  tomcat:\n    remoteip:\n      remote-ip-header: \"x-forwarded-for\"\n      protocol-header: \"x-forwarded-proto\"\n----\n\n(The presence of either of those properties switches on the valve.\nAlternatively, you can add the javadoc:org.apache.catalina.valves.RemoteIpValve[] by customizing the javadoc:org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory[] using a javadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] bean.)\n\nTo configure Spring Security to require a secure channel for all (or some) requests, consider adding your own javadoc:org.springframework.security.web.SecurityFilterChain[] bean that adds the following javadoc:org.springframework.security.config.annotation.web.builders.HttpSecurity[] configuration:\n\ninclude-code::MySecurityConfig[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/spring-mvc.adoc",
    "content": "[[howto.spring-mvc]]\n= Spring MVC\n\nSpring Boot has a number of starters that include Spring MVC.\nNote that some starters include a dependency on Spring MVC rather than include it directly.\nThis section answers common questions about Spring MVC and Spring Boot.\n\n\n\n[[howto.spring-mvc.write-json-rest-service]]\n== Write a JSON REST Service\n\nAny Spring javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] in a Spring Boot application should render JSON response by default as long as Jackson 3 is on the classpath, as shown in the following example:\n\ninclude-code::MyController[]\n\nAs long as `MyThing` can be serialized by Jackson 3 (true for a normal POJO or Groovy object), then `http://localhost:8080/thing` serves a JSON representation of it by default.\nNote that, in a browser, you might sometimes see XML responses, because browsers tend to send accept headers that prefer XML.\n\n\n\n[[howto.spring-mvc.write-xml-rest-service]]\n== Write an XML REST Service\n\nIf you have the Jackson XML extension (`jackson-dataformat-xml`) on the classpath, you can use it to render XML responses.\nThe previous example that we used for JSON would work.\nTo use the Jackson XML renderer, add the following dependency to your project:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>tools.jackson.dataformat</groupId>\n\t<artifactId>jackson-dataformat-xml</artifactId>\n</dependency>\n----\n\nIf Jackson's XML extension is not available and JAXB is available, XML can be rendered with the additional requirement of having `MyThing` annotated as javadoc:jakarta.xml.bind.annotation.XmlRootElement[format=annotation], as shown in the following example:\n\ninclude-code::MyThing[]\n\nYou will need to ensure that the JAXB library is part of your project, for example by adding:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.glassfish.jaxb</groupId>\n\t<artifactId>jaxb-runtime</artifactId>\n</dependency>\n----\n\nNOTE: To get the server to render XML instead of JSON, you might have to send an `Accept: text/xml` header (or use a browser).\n\n\n\n[[howto.spring-mvc.customize-jackson-jsonmapper]]\n== Customize the Jackson JsonMapper\n\nYou can configure the javadoc:tools.jackson.databind.json.JsonMapper[] by using the environment.\nJackson provides an extensive suite of on/off features that can be used to configure various aspects of its processing.\nThese features are described in several enums (in Jackson) that map onto properties in the environment:\n\n|===\n| Enum | Property | Values\n\n| javadoc:tools.jackson.databind.cfg.DateTimeFeature[]\n| `spring.jackson.datatype.datetime.<feature_name>`\n| `true`, `false`\n\n| javadoc:tools.jackson.databind.cfg.EnumFeature[]\n| `spring.jackson.datatype.enum.<feature_name>`\n| `true`, `false`\n\n| javadoc:tools.jackson.databind.cfg.JsonNodeFeature[]\n| `spring.jackson.datatype.json-node.<feature_name>`\n| `true`, `false`\n\n| javadoc:com.fasterxml.jackson.annotation.JsonInclude$Include[]\n| configprop:spring.jackson.default-property-inclusion[]\n| `always`, `non_null`, `non_absent`, `non_default`, `non_empty`\n\n| javadoc:tools.jackson.databind.DeserializationFeature[]\n| `spring.jackson.deserialization.<feature_name>`\n| `true`, `false`\n\n| javadoc:tools.jackson.core.json.JsonReadFeature[]\n| `spring.jackson.json.read.<feature_name>`\n| `true`, `false`\n\n| javadoc:tools.jackson.core.json.JsonWriteFeature[]\n| `spring.jackson.json.write.<feature_name>`\n| `true`, `false`\n\n| javadoc:tools.jackson.databind.MapperFeature[]\n| `spring.jackson.mapper.<feature_name>`\n| `true`, `false`\n\n| javadoc:tools.jackson.databind.SerializationFeature[]\n| `spring.jackson.serialization.<feature_name>`\n| `true`, `false`\n|===\n\nFor example, to enable pretty print, set `spring.jackson.serialization.indent_output=true`.\nNote that, thanks to the use of xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[relaxed binding], the case of `indent_output` does not have to match the case of the corresponding enum constant, which is `INDENT_OUTPUT`.\n\nThis environment-based configuration is applied to the auto-configured javadoc:tools.jackson.databind.json.JsonMapper$Builder[] bean and applies to any mappers created by using the builder, including the auto-configured javadoc:tools.jackson.databind.json.JsonMapper[] bean.\n\nTo ease the migration when working on an application that previously used Jackson 2, the auto-configured `JsonMapper` can be configured to use defaults that are as close as possible to those that Spring Boot used for Jackson 2. To enable these defaults, set configprop:spring.jackson.use-jackson2-defaults[] to `true`.\n\nThe context's javadoc:tools.jackson.databind.json.JsonMapper$Builder[] can be customized by one or more javadoc:org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer[] beans.\nSuch customizer beans can be ordered (Boot's own customizer has an order of 0), letting additional customization be applied both before and after Boot's customization.\nFurthermore, the `JsonFactory` used by the builder and the mapper that it creates can be customized by one or more javadoc:org.springframework.boot.jackson.autoconfigure.JsonFactoryBuilderCustomizer[] beans.\nVarious `spring.jackson.factory` properties can also be used to configure the factory.\n\nAny beans of type javadoc:tools.jackson.databind.JacksonModule[] are automatically registered with the auto-configured javadoc:tools.jackson.databind.json.JsonMapper$Builder[] and are applied to any javadoc:tools.jackson.databind.json.JsonMapper[] instances that it creates.\nThis provides an application-wide mechanism for contributing custom modules when you add new features to your application.\n\nAny modules that participate in the Java `ServiceLoader` mechanism are, by default, found and added to the auto-configured javadoc:tools.jackson.databind.json.JsonMapper$Builder[]. To disable this behavior, set configprop:spring.jackson.find-and-add-modules[] to `false`.\n\nIf you want to replace the default javadoc:tools.jackson.databind.json.JsonMapper[] completely, either define a javadoc:org.springframework.context.annotation.Bean[format=annotation] of that type or, if you prefer the builder-based approach, define a javadoc:tools.jackson.databind.json.JsonMapper$Builder[] javadoc:org.springframework.context.annotation.Bean[format=annotation].\nWhen defining an javadoc:tools.jackson.databind.json.JsonMapper[] bean, marking it as javadoc:org.springframework.context.annotation.Primary[format=annotation] is recommended as the auto-configuration's javadoc:tools.jackson.databind.json.JsonMapper[] that it will replace is javadoc:org.springframework.context.annotation.Primary[format=annotation].\nNote that, in either case, doing so disables all auto-configuration of the javadoc:tools.jackson.databind.json.JsonMapper[].\n\nIf you provide any javadoc:org.springframework.context.annotation.Bean[format=annotation]s of type javadoc:org.springframework.http.converter.json.JacksonJsonHttpMessageConverter[], they replace the default value in the MVC configuration.\nAlso, a convenience bean of type javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] is provided (and is always available if you use the default MVC configuration).\nIt has some useful methods to access the default and user-enhanced message converters.\n\nSee the xref:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[] section and the {code-spring-boot-webmvc-src}/autoconfigure/WebMvcAutoConfiguration.java[`WebMvcAutoConfiguration`] source code for more details.\n\n\n\n[[howto.spring-mvc.customize-responsebody-rendering]]\n== Customize the @ResponseBody Rendering\n\nSpring uses javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] to render javadoc:org.springframework.web.bind.annotation.ResponseBody[format=annotation] (or responses from javadoc:org.springframework.web.bind.annotation.RestController[format=annotation]).\nYou can contribute additional converters by adding beans of the appropriate type in a Spring Boot context.\nIf a bean you add is of a type that would have been included by default anyway (such as javadoc:org.springframework.http.converter.json.JacksonJsonHttpMessageConverter[] for JSON conversions), it replaces the default value.\nA convenience bean of type javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] is provided and is always available if you use the default MVC configuration.\nIt has some useful methods to access the default and user-enhanced message converters (For example, it can be useful if you want to manually inject them into a custom javadoc:org.springframework.web.client.RestTemplate[]).\n\nAs in normal MVC usage, any javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] beans that you provide can also contribute converters by overriding the `configureMessageConverters` method.\nHowever, unlike with normal MVC, you can supply only additional converters that you need (because Spring Boot uses the same mechanism to contribute its defaults).\nFinally, if you opt out of the default Spring Boot MVC configuration by providing your own javadoc:org.springframework.web.servlet.config.annotation.EnableWebMvc[format=annotation] configuration, you can take control completely and do everything manually by using `getMessageConverters` from javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport[].\n\nSee the {code-spring-boot-webmvc-src}/autoconfigure/WebMvcAutoConfiguration.java[`WebMvcAutoConfiguration`] source code for more details.\n\n\n\n[[howto.spring-mvc.multipart-file-uploads]]\n== Handling Multipart File Uploads\n\nSpring Boot embraces the servlet 5 javadoc:jakarta.servlet.http.Part[] API to support uploading files.\nBy default, Spring Boot configures Spring MVC with a maximum size of 1MB per file and a maximum of 10MB of file data in a single request.\nYou may override these values, the location to which intermediate data is stored (for example, to the `/tmp` directory), and the threshold past which data is flushed to disk by using the properties exposed in the javadoc:org.springframework.boot.servlet.autoconfigure.MultipartProperties[] class.\nFor example, if you want to specify that files be unlimited, set the configprop:spring.servlet.multipart.max-file-size[] property to `-1`.\n\nThe multipart support is helpful when you want to receive multipart encoded file data as a javadoc:org.springframework.web.bind.annotation.RequestParam[format=annotation]-annotated parameter of type javadoc:org.springframework.web.multipart.MultipartFile[] in a Spring MVC controller handler method.\n\nSee the {code-spring-boot-servlet-src}/autoconfigure/MultipartAutoConfiguration.java[`MultipartAutoConfiguration`] source for more details.\n\nNOTE: It is recommended to use the container's built-in support for multipart uploads rather than introduce an additional dependency such as Apache Commons File Upload.\n\n\n\n[[howto.spring-mvc.switch-off-dispatcherservlet]]\n== Switch Off the Spring MVC DispatcherServlet\n\nBy default, all content is served from the root of your application (`/`).\nIf you would rather map to a different path, you can configure one as follows:\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    servlet:\n      path: \"/mypath\"\n----\n\nIf you have additional servlets you can declare a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:jakarta.servlet.Servlet[] or javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] for each and Spring Boot will register them transparently to the container.\nIt is also possible to use javadoc:org.springframework.boot.web.servlet.ServletRegistration[format=annotation] as an annotation-based alternative to javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[].\nBecause servlets are registered that way, they can be mapped to a sub-context of the javadoc:org.springframework.web.servlet.DispatcherServlet[] without invoking it.\n\nConfiguring the javadoc:org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath[] yourself is unusual but if you really need to do it, a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath[] must be provided as well to provide the path of your custom javadoc:org.springframework.web.servlet.DispatcherServlet[].\n\n\n\n[[howto.spring-mvc.switch-off-default-configuration]]\n== Switch Off the Default MVC Configuration\n\nThe easiest way to take complete control over MVC configuration is to provide your own javadoc:org.springframework.context.annotation.Configuration[format=annotation] with the javadoc:org.springframework.web.servlet.config.annotation.EnableWebMvc[format=annotation] annotation.\nDoing so leaves all MVC configuration in your hands.\n\n\n\n[[howto.spring-mvc.customize-view-resolvers]]\n== Customize ViewResolvers\n\nA javadoc:org.springframework.web.servlet.ViewResolver[] is a core component of Spring MVC, translating view names in javadoc:org.springframework.stereotype.Controller[format=annotation] to actual javadoc:org.springframework.web.servlet.View[] implementations.\nNote that view resolvers are mainly used in UI applications, rather than REST-style services (a javadoc:org.springframework.web.servlet.View[] is not used to render a javadoc:org.springframework.web.bind.annotation.ResponseBody[format=annotation]).\nThere are many implementations of javadoc:org.springframework.web.servlet.ViewResolver[] to choose from, and Spring on its own is not opinionated about which ones you should use.\nSpring Boot, on the other hand, installs one or two for you, depending on what it finds on the classpath and in the application context.\nThe javadoc:org.springframework.web.servlet.DispatcherServlet[] uses all the resolvers it finds in the application context, trying each one in turn until it gets a result.\nIf you add your own, you have to be aware of the order and in which position your resolver is added.\n\njavadoc:org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration[] adds the following javadoc:org.springframework.web.servlet.ViewResolver[] beans to your context:\n\n* An javadoc:org.springframework.web.servlet.view.InternalResourceViewResolver[] named '`defaultViewResolver`'.\n  This one locates physical resources that can be rendered by using the `DefaultServlet` (including static resources and JSP pages, if you use those).\n  It applies a prefix and a suffix to the view name and then looks for a physical resource with that path in the servlet context (the defaults are both empty but are accessible for external configuration through `spring.mvc.view.prefix` and `spring.mvc.view.suffix`).\n  You can override it by providing a bean of the same type.\n* A javadoc:org.springframework.web.servlet.view.BeanNameViewResolver[] named '`beanNameViewResolver`'.\n  This is a useful member of the view resolver chain and picks up any beans with the same name as the javadoc:org.springframework.web.servlet.View[] being resolved.\n  It should not be necessary to override or replace it.\n* A javadoc:org.springframework.web.servlet.view.ContentNegotiatingViewResolver[] named '`viewResolver`' is added only if there *are* actually beans of type javadoc:org.springframework.web.servlet.View[] present.\n  This is a composite resolver, delegating to all the others and attempting to find a match to the '`Accept`' HTTP header sent by the client.\n  There is a useful https://spring.io/blog/2013/06/03/content-negotiation-using-views[blog about javadoc:org.springframework.web.servlet.view.ContentNegotiatingViewResolver[]] that you might like to study to learn more, and you might also look at the source code for detail.\n  You can switch off the auto-configured javadoc:org.springframework.web.servlet.view.ContentNegotiatingViewResolver[] by defining a bean named '`viewResolver`'.\n* If you use Thymeleaf, you also have a javadoc:org.thymeleaf.spring6.view.ThymeleafViewResolver[] named '`thymeleafViewResolver`'.\n  It looks for resources by surrounding the view name with a prefix and suffix.\n  The prefix is `spring.thymeleaf.prefix`, and the suffix is `spring.thymeleaf.suffix`.\n  The values of the prefix and suffix default to '`classpath:/templates/`' and '`.html`', respectively.\n  You can override javadoc:org.thymeleaf.spring6.view.ThymeleafViewResolver[] by providing a bean of the same name.\n* If you use FreeMarker, you also have a javadoc:org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver[] named '`freeMarkerViewResolver`'.\n  It looks for resources in a loader path (which is externalized to `spring.freemarker.templateLoaderPath` and has a default value of '`classpath:/templates/`') by surrounding the view name with a prefix and a suffix.\n  The prefix is externalized to `spring.freemarker.prefix`, and the suffix is externalized to `spring.freemarker.suffix`.\n  The default values of the prefix and suffix are empty and '`.ftlh`', respectively.\n  You can override javadoc:org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver[] by providing a bean of the same name.\n  FreeMarker variables can be customized by defining a bean of type javadoc:org.springframework.boot.freemarker.autoconfigure.FreeMarkerVariablesCustomizer[].\n* If you use Groovy templates (actually, if `groovy-templates` is on your classpath), you also have a javadoc:org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver[] named '`groovyMarkupViewResolver`'.\n  It looks for resources in a loader path by surrounding the view name with a prefix and suffix (externalized to `spring.groovy.template.prefix` and `spring.groovy.template.suffix`).\n  The prefix and suffix have default values of '`classpath:/templates/`' and '`.tpl`', respectively.\n  You can override javadoc:org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver[] by providing a bean of the same name.\n* If you use Mustache, you also have a javadoc:org.springframework.boot.mustache.servlet.view.MustacheViewResolver[] named '`mustacheViewResolver`'.\n  It looks for resources by surrounding the view name with a prefix and suffix.\n  The prefix is `spring.mustache.prefix`, and the suffix is `spring.mustache.suffix`.\n  The values of the prefix and suffix default to '`classpath:/templates/`' and '`.mustache`', respectively.\n  You can override javadoc:org.springframework.boot.mustache.servlet.view.MustacheViewResolver[] by providing a bean of the same name.\n\nFor more detail, see the following sections:\n\n* {code-spring-boot-webmvc-src}/autoconfigure/WebMvcAutoConfiguration.java[`WebMvcAutoConfiguration`]\n* {code-spring-boot-thymeleaf-src}/autoconfigure/ThymeleafAutoConfiguration.java[`ThymeleafAutoConfiguration`]\n* {code-spring-boot-freemarker-src}/autoconfigure/FreeMarkerAutoConfiguration.java[`FreeMarkerAutoConfiguration`]\n* {code-spring-boot-groovy-templates-src}/autoconfigure/GroovyTemplateAutoConfiguration.java[`GroovyTemplateAutoConfiguration`]\n\n\n\n[[howto.spring-mvc.customize-whitelabel-error-page]]\n== Customize the '`whitelabel`' Error Page\n\nSpring Boot installs a '`whitelabel`' error page that you see in a browser client if you encounter a server error (machine clients consuming JSON and other media types should see a sensible response with the right error code).\n\nNOTE: Set configprop:spring.web.error.whitelabel.enabled[] to `false` to switch the default error page off.\nDoing so restores the default of the servlet container that you are using.\nNote that Spring Boot still tries to resolve the error view, so you should probably add your own error page rather than disabling it completely.\n\nOverriding the error page with your own depends on the templating technology that you use.\nFor example, if you use Thymeleaf, you can add an `error.html` template.\nIf you use FreeMarker, you can add an `error.ftlh` template.\nIn general, you need a javadoc:org.springframework.web.servlet.View[] that resolves with a name of `error` or a javadoc:org.springframework.stereotype.Controller[format=annotation] that handles the `/error` path.\nUnless you replaced some of the default configuration, you should find a javadoc:org.springframework.web.servlet.view.BeanNameViewResolver[] in your javadoc:org.springframework.context.ApplicationContext[], so a javadoc:org.springframework.context.annotation.Bean[format=annotation] named `error` would be one way of doing that.\nSee {code-spring-boot-webmvc-src}/autoconfigure/error/ErrorMvcAutoConfiguration.java[`ErrorMvcAutoConfiguration`] for more options.\n\nSee also the section on xref:reference:web/servlet.adoc#web.servlet.spring-mvc.error-handling[] for details of how to register handlers in the servlet container.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/testing.adoc",
    "content": "[[howto.testing]]\n= Testing\n\nSpring Boot includes a number of testing utilities and support classes as well as a dedicated starter that provides common test dependencies.\nThis section answers common questions about testing.\n\n\n\n[[howto.testing.with-spring-security]]\n== Testing With Spring Security\n\nSpring Security provides support for running tests as a specific user.\nFor example, the test in the snippet below will run with an authenticated user that has the `ADMIN` role.\n\ninclude-code::MySecurityTests[]\n\nSpring Security provides comprehensive integration with Spring MVC Test, and this can also be used when testing controllers using the javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] slice and javadoc:org.springframework.test.web.servlet.MockMvc[].\n\nFor additional details on Spring Security's testing support, see Spring Security's {url-spring-security-docs}/servlet/test/index.html[reference documentation].\n\n\n\n\n[[howto.testing.slice-tests]]\n== Structure javadoc:org.springframework.context.annotation.Configuration[format=annotation] Classes for Inclusion in Slice Tests\n\nSlice tests work by restricting Spring Framework's component scanning to a limited set of components based on their type.\nFor any beans that are not created through component scanning, for example, beans that are created using the javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation, slice tests will not be able to include/exclude them from the application context.\nConsider this example:\n\ninclude-code::MyConfiguration[]\n\nFor a javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] for an application with the above javadoc:org.springframework.context.annotation.Configuration[format=annotation] class, you might expect to have the javadoc:org.springframework.security.web.SecurityFilterChain[] bean in the application context so that you can test if your controller endpoints are secured properly.\nHowever, `MyConfiguration` is not picked up by @WebMvcTest's component scanning filter because it doesn't match any of the types specified by the filter.\nYou can include the configuration explicitly by annotating the test class with `@Import(MyConfiguration.class)`.\nThis will load all the beans in `MyConfiguration` including the javadoc:com.zaxxer.hikari.HikariDataSource[] bean which isn't required when testing the web tier.\nSplitting the configuration class into two will enable importing just the security configuration.\n\ninclude-code::MySecurityConfiguration[]\n\ninclude-code::MyDatasourceConfiguration[]\n\nHaving a single configuration class can be inefficient when beans from a certain domain need to be included in slice tests.\nInstead, structuring the application's configuration as multiple granular classes with beans for a specific domain can enable importing them only for specific slice tests.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/pages/webserver.adoc",
    "content": "[[howto.webserver]]\n= Embedded Web Servers\n\nEach Spring Boot web application includes an embedded web server.\nThis feature leads to a number of how-to questions, including how to change the embedded server and how to configure the embedded server.\nThis section answers those questions.\n\n\n\n[[howto.webserver.use-another]]\n== Use Another Web Server\n\nMany Spring Boot starters include default embedded containers.\n\n* For servlet stack applications, the `spring-boot-starter-web` includes Tomcat by including `spring-boot-starter-tomcat`, but you can use `spring-boot-starter-jetty` instead.\n* For reactive stack applications, the `spring-boot-starter-webflux` includes  Reactor Netty by including `spring-boot-starter-reactor-netty`, but you can use `spring-boot-starter-tomcat` or `spring-boot-starter-jetty` instead.\n\nWhen switching to a different HTTP server, you need to swap the default dependencies for those that you need instead.\nTo help with this process, Spring Boot provides a separate starter for each of the supported HTTP servers.\n\nThe following example shows how to exclude Tomcat and include Jetty for Spring MVC:\n\n[tabs]\n======\n\nMaven::\n+\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-webmvc</artifactId>\n\t<exclusions>\n\t\t<!-- Exclude the Tomcat dependency -->\n\t\t<exclusion>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t</exclusion>\n\t</exclusions>\n</dependency>\n<!-- Use Jetty instead -->\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-jetty</artifactId>\n</dependency>\n----\n+\n\nGradle::\n+\n[source,gradle]\n----\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter-webmvc') {\n\t\t// Exclude the Tomcat dependency\n\t\texclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'\n\t}\n\t// Use Jetty instead\n\timplementation \"org.springframework.boot:spring-boot-starter-jetty\"\n}\n----\n+\n======\n\nIf you are creating a war file, you can use a similar approach, but you must indicate provided dependencies:\n\n\n[tabs]\n======\n\nMaven::\n+\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-webmvc</artifactId>\n\t<exclusions>\n\t\t<!-- Exclude the Tomcat dependency -->\n\t\t<exclusion>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-tomcat</artifactId>\n\t\t</exclusion>\n\t</exclusions>\n</dependency>\n<!-- Use Jetty instead -->\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-jetty</artifactId>\n\t<scope>provided</scope>\n</dependency>\n----\n+\n\nGradle::\n+\n[source,gradle]\n----\ndependencies {\n\timplementation('org.springframework.boot:spring-boot-starter-webmvc') {\n\t\t// Exclude the Tomcat dependency\n\t\texclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'\n\t}\n\t// Use Jetty instead\n\timplementation \"org.springframework.boot:spring-boot-starter-jetty\"\n\tprovidedRuntime \"org.springframework.boot:spring-boot-starter-jetty-runtime\"\n}\n----\n+\n======\n\n\n\n[[howto.webserver.disable]]\n== Disabling the Web Server\n\nIf your classpath contains the necessary bits to start a web server, Spring Boot will automatically start it.\nTo disable this behavior configure the javadoc:org.springframework.boot.WebApplicationType[] in your `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  main:\n    web-application-type: \"none\"\n----\n\n\n\n[[howto.webserver.change-port]]\n== Change the HTTP Port\n\nIn a standalone application, the main HTTP port defaults to `8080` but can be set with configprop:server.port[] (for example, in `application.properties` or as a System property).\nThanks to relaxed binding of javadoc:org.springframework.core.env.Environment[] values, you can also use configprop:server.port[format=envvar] (for example, as an OS environment variable).\n\nTo switch off the HTTP endpoints completely but still create a javadoc:org.springframework.web.context.WebApplicationContext[], use `server.port=-1` (doing so is sometimes useful for testing).\n\nFor more details, see xref:reference:web/servlet.adoc#web.servlet.embedded-container.customizing[Customizing Embedded Servlet Containers] in the '`Spring Boot Features`' section, or the javadoc:org.springframework.boot.web.server.autoconfigure.ServerProperties[] class.\n\n\n\n[[howto.webserver.use-random-port]]\n== Use a Random Unassigned HTTP Port\n\nTo scan for a free port (using OS natives to prevent clashes) use `server.port=0`.\n\n\n\n[[howto.webserver.discover-port]]\n== Discover the HTTP Port at Runtime\n\nYou can access the port the server is running on from log output or from the javadoc:org.springframework.boot.web.server.context.WebServerApplicationContext[] through its javadoc:org.springframework.boot.web.server.WebServer[].\nThe best way to get that and be sure it has been initialized is to add a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type `ApplicationListener<WebServerInitializedEvent>` and pull the container out of the event when it is published.\n\nTests that use `@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)` can also inject the actual port into a field by using the javadoc:org.springframework.boot.test.web.server.LocalServerPort[format=annotation] annotation, as shown in the following example:\n\ninclude-code::MyWebIntegrationTests[]\n\n[NOTE]\n====\njavadoc:org.springframework.boot.test.web.server.LocalServerPort[format=annotation] is a meta-annotation for `@Value(\"${local.server.port}\")`.\nDo not try to inject the port in a regular application.\nAs we just saw, the value is set only after the container has been initialized.\nContrary to a test, application code callbacks are processed early (before the value is actually available).\n====\n\n\n\n[[howto.webserver.build-uri-test-web-server]]\n== Build URI Against the Test Web Server\n\nTests that start a javadoc:org.springframework.boot.web.server.WebServer[] such as  `@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)` can get information about\nthe running server using javadoc:org.springframework.boot.test.http.server.LocalTestWebServer[], as shown in the following example:\n\ninclude-code::MyWebIntegrationTests[]\n\njavadoc:org.springframework.boot.test.http.server.LocalTestWebServer[] provides access to a suitable javadoc:org.springframework.web.util.UriBuilderFactory[].\nIt can also be customized to build such an instance on a sub-path of your application.\n\n\n\n[[howto.webserver.enable-response-compression]]\n== Enable HTTP Response Compression\n\nHTTP response compression is supported by Jetty, Tomcat and Reactor Netty.\nIt can be enabled in `application.properties`, as follows:\n\n[configprops,yaml]\n----\nserver:\n  compression:\n    enabled: true\n----\n\nBy default, responses must be at least 2048 bytes in length for compression to be performed.\nYou can configure this behavior by setting the configprop:server.compression.min-response-size[] property.\n\nBy default, responses are compressed only if their content type is one of the following:\n\n* `text/html`\n* `text/xml`\n* `text/plain`\n* `text/css`\n* `text/javascript`\n* `application/javascript`\n* `application/json`\n* `application/xml`\n\nTo configure the mime types that will be compressed, replacing the defaults, set the configprop:server.compression.mime-types[] property.\nTo keep the defaults and configure additional mime types, set the configprop:server.compression.additional-mime-types[] property instead.\n\n\n\n[[howto.webserver.configure-ssl]]\n== Configure SSL\n\nSSL can be configured declaratively by setting the various `+server.ssl.*+` properties, typically in `application.properties` or `application.yaml`.\nSee javadoc:org.springframework.boot.web.server.Ssl[] for details of all of the supported properties.\n\nThe following example shows setting SSL properties using a Java KeyStore file:\n\n[configprops,yaml]\n----\nserver:\n  port: 8443\n  ssl:\n    key-store: \"classpath:keystore.jks\"\n    key-store-password: \"secret\"\n    key-password: \"another-secret\"\n----\n\nUsing configuration such as the preceding example means the application no longer supports a plain HTTP connector at port 8080.\nSpring Boot does not support the configuration of both an HTTP connector and an HTTPS connector through `application.properties`.\nIf you want to have both, you need to configure one of them programmatically.\nWe recommend using `application.properties` to configure HTTPS, as the HTTP connector is the easier of the two to configure programmatically.\n\n\n\n[[howto.webserver.configure-ssl.pem-files]]\n=== Using PEM-encoded files\n\nYou can use PEM-encoded files instead of Java KeyStore files.\nYou should use PKCS#8 key files wherever possible.\nPEM-encoded PKCS#8 key files start with a `-----BEGIN PRIVATE KEY-----` or `-----BEGIN ENCRYPTED PRIVATE KEY-----` header.\n\nIf you have files in other formats, e.g., PKCS#1 (`-----BEGIN RSA PRIVATE KEY-----`) or SEC 1 (`-----BEGIN EC PRIVATE KEY-----`), you can convert them to PKCS#8 using OpenSSL:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\nopenssl pkcs8 -topk8 -nocrypt -in <input file> -out <output file>\n----\n\nThe following example shows setting SSL properties using PEM-encoded certificate and private key files:\n\n[configprops,yaml]\n----\nserver:\n  port: 8443\n  ssl:\n    certificate: \"classpath:my-cert.crt\"\n    certificate-private-key: \"classpath:my-cert.key\"\n    trust-certificate: \"classpath:ca-cert.crt\"\n----\n\n[[howto.webserver.configure-ssl.bundles]]\n=== Using SSL Bundles\n\nAlternatively, the SSL trust material can be configured in an xref:reference:features/ssl.adoc[SSL bundle] and applied to the web server as shown in this example:\n\n[configprops,yaml]\n----\nserver:\n  port: 8443\n  ssl:\n    bundle: \"example\"\n----\n\n[NOTE]\n====\nThe `server.ssl.bundle` property can not be combined with the discrete Java KeyStore or PEM property options under `server.ssl`.\n\nThe configprop:server.ssl.ciphers[], configprop:server.ssl.enabled-protocols[], configprop:server.ssl.protocol[] properties are also ignored when using a bundle.\nThese properties should instead be defined using `spring.ssl.bundle.<type>.<name>.options` properties.\n====\n\n\n\n[[howto.webserver.configure-ssl.sni]]\n=== Configure Server Name Indication\n\nTomcat, and Netty can be configured to use unique SSL trust material for individual host names to support Server Name Indication (SNI).\nSNI configuration is not supported with Jetty, but Jetty can https://eclipse.dev/jetty/documentation/jetty-12/operations-guide/index.html#og-protocols-ssl-sni[automatically set up SNI] if multiple certificates are provided to it.\n\nAssuming xref:reference:features/ssl.adoc[SSL bundles] named `web`, `web-alt1`, and `web-alt2` have been configured, the following configuration can be used to assign each bundle to a host name served by the embedded web server:\n\n[configprops,yaml]\n----\nserver:\n  port: 8443\n  ssl:\n    bundle: \"web\"\n    server-name-bundles:\n      - server-name: \"alt1.example.com\"\n        bundle: \"web-alt1\"\n      - server-name: \"alt2.example.com\"\n        bundle: \"web-alt2\"\n----\n\nThe bundle specified with `server.ssl.bundle` will be used for the default host, and for any client that does support SNI.\nThis default bundle must be configured if any `server.ssl.server-name-bundles` are configured.\n\n\n\n[[howto.webserver.configure-http2]]\n== Configure HTTP/2\n\nYou can enable HTTP/2 support in your Spring Boot application with the configprop:server.http2.enabled[] configuration property.\nBoth `h2` (HTTP/2 over TLS) and `h2c` (HTTP/2 over TCP) are supported.\nTo use `h2`, SSL must also be enabled.\nWhen SSL is not enabled, `h2c` will be used.\nYou may, for example, want to use `h2c` when your application is xref:webserver.adoc#howto.webserver.use-behind-a-proxy-server[running behind a proxy server] that is performing TLS termination.\n\n\n\n[[howto.webserver.configure-http2.tomcat]]\n=== HTTP/2 With Tomcat\n\nSpring Boot ships by default with Tomcat 11.0.x which supports `h2c` and `h2` out of the box.\nAlternatively, you can use `libtcnative` for `h2` support if the library and its dependencies are installed on the host operating system.\n\nThe library directory must be made available, if not already, to the JVM library path.\nYou can do so with a JVM argument such as `-Djava.library.path=/usr/local/opt/tomcat-native/lib`.\nMore on this in the {url-tomcat-docs}/apr.html[official Tomcat documentation].\n\n\n\n[[howto.webserver.configure-http2.jetty]]\n=== HTTP/2 With Jetty\n\nFor HTTP/2 support, Jetty requires the additional `org.eclipse.jetty.http2:jetty-http2-server` dependency.\nTo use `h2c` no other dependencies are required.\nTo use `h2`, you also need to choose one of the following dependencies, depending on your deployment:\n\n* `org.eclipse.jetty:jetty-alpn-java-server` to use the JDK built-in support\n* `org.eclipse.jetty:jetty-alpn-conscrypt-server` and the https://www.conscrypt.org/[Conscrypt library]\n\n\n\n[[howto.webserver.configure-http2.netty]]\n=== HTTP/2 With Reactor Netty\n\nThe `spring-boot-webflux-starter` is using by default Reactor Netty as a server.\nReactor Netty supports `h2c` and `h2` out of the box.\nFor optimal runtime performance, this server also supports `h2` with native libraries.\nTo enable that, your application needs to have an additional dependency.\n\nSpring Boot manages the version for the `io.netty:netty-tcnative-boringssl-static` \"uber jar\", containing native libraries for all platforms.\nDevelopers can choose to import only the required dependencies using a classifier (see https://netty.io/wiki/forked-tomcat-native.html[the Netty official documentation]).\n\n\n\n[[howto.webserver.configure]]\n== Configure the Web Server\n\nGenerally, you should first consider using one of the many available configuration keys and customize your web server by adding new entries in your `application.properties` or `application.yaml` file.\nSee xref:properties-and-configuration.adoc#howto.properties-and-configuration.discover-build-in-options-for-external-properties[]).\nThe `server.{asterisk}` namespace is quite useful here, and it includes namespaces like `server.tomcat.{asterisk}`, `server.jetty.{asterisk}` and others, for server-specific features.\nSee the list of xref:appendix:application-properties/index.adoc[].\n\nThe previous sections covered already many common use cases, such as compression, SSL or HTTP/2.\nHowever, if a configuration key does not exist for your use case, you should then look at javadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[].\nYou can declare such a component and get access to the server factory relevant to your choice: you should select the variant for the chosen Server (Tomcat, Jetty, Reactor Netty) and the chosen web stack (servlet or reactive).\n\nThe example below is for Tomcat with the `spring-boot-starter-web` (servlet stack):\n\ninclude-code::MyTomcatWebServerCustomizer[]\n\nNOTE: Spring Boot uses that infrastructure internally to auto-configure the server.\nAuto-configured javadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] beans have an order of `0` and will be processed before any user-defined customizers, unless it has an explicit order that states otherwise.\n\nOnce you have got access to a javadoc:org.springframework.boot.web.server.WebServerFactory[] using the customizer, you can use it to configure specific parts, like connectors, server resources, or the server itself - all using server-specific APIs.\n\nIn addition Spring Boot provides:\n\n[[howto-configure-webserver-customizers]]\n[cols=\"1,2,2\", options=\"header\"]\n|===\n| Server | Servlet stack | Reactive stack\n\n| Tomcat\n| javadoc:org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory[]\n| javadoc:org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory[]\n\n| Jetty\n| javadoc:org.springframework.boot.jetty.servlet.JettyServletWebServerFactory[]\n| javadoc:org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory[]\n\n| Reactor\n| N/A\n| javadoc:org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory[]\n|===\n\nAs a last resort, you can also declare your own javadoc:org.springframework.boot.web.server.WebServerFactory[] bean, which will override the one provided by Spring Boot.\nWhen you do so, auto-configured customizers are still applied on your custom factory, so use that option carefully.\n\n\n\n[[howto.webserver.add-servlet-filter-listener]]\n== Add a Servlet, Filter, or Listener to an Application\n\nIn a servlet stack application, that is with the `spring-boot-starter-web`, there are two ways to add javadoc:jakarta.servlet.Servlet[], javadoc:jakarta.servlet.Filter[], javadoc:jakarta.servlet.ServletContextListener[], and the other listeners supported by the Servlet API to your application:\n\n* xref:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[]\n* xref:webserver.adoc#howto.webserver.add-servlet-filter-listener.using-scanning[]\n\n\n\n[[howto.webserver.add-servlet-filter-listener.spring-bean]]\n=== Add a Servlet, Filter, or Listener by Using a Spring Bean\n\nTo add a javadoc:jakarta.servlet.Servlet[], javadoc:jakarta.servlet.Filter[], or servlet `*Listener` by using a Spring bean, you must provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] definition for it.\nDoing so can be very useful when you want to inject configuration or dependencies.\nHowever, you must be very careful that they do not cause eager initialization of too many other beans, because they have to be installed in the container very early in the application lifecycle.\n(For example, it is not a good idea to have them depend on your javadoc:javax.sql.DataSource[] or JPA configuration.)\nYou can work around such restrictions by initializing the beans lazily when first used instead of on initialization.\n\nIn the case of filters and servlets, you can also add mappings and init parameters by adding a javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[] or a javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] instead of or in addition to the underlying component.\nYou can also use javadoc:org.springframework.boot.web.servlet.ServletRegistration[format=annotation] and javadoc:org.springframework.boot.web.servlet.FilterRegistration[format=annotation] as an annotation-based alternative to javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] and javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[].\n\n[NOTE]\n====\nIf no `dispatcherType` is specified on a filter registration, `REQUEST` is used.\nThis aligns with the servlet specification's default dispatcher type.\n====\n\nLike any other Spring bean, you can define the order of servlet filter beans; please make sure to check the xref:reference:web/servlet.adoc#web.servlet.embedded-container.servlets-filters-listeners.beans[] section.\n\n\n\n[[howto.webserver.add-servlet-filter-listener.spring-bean.disable]]\n==== Disable Registration of a Servlet or Filter\n\nAs xref:webserver.adoc#howto.webserver.add-servlet-filter-listener.spring-bean[described earlier], any javadoc:jakarta.servlet.Servlet[] or javadoc:jakarta.servlet.Filter[] beans are registered with the servlet container automatically.\nTo disable registration of a particular javadoc:jakarta.servlet.Filter[] or javadoc:jakarta.servlet.Servlet[] bean, create a registration bean for it and mark it as disabled, as shown in the following example:\n\ninclude-code::MyFilterConfiguration[]\n\n\n\n[[howto.webserver.add-servlet-filter-listener.using-scanning]]\n=== Add Servlets, Filters, and Listeners by Using Classpath Scanning\n\njavadoc:jakarta.servlet.annotation.WebServlet[format=annotation], javadoc:jakarta.servlet.annotation.WebFilter[format=annotation], and javadoc:jakarta.servlet.annotation.WebListener[format=annotation] annotated classes can be automatically registered with an embedded servlet container by annotating a javadoc:org.springframework.context.annotation.Configuration[format=annotation] class with javadoc:org.springframework.boot.web.server.servlet.context.ServletComponentScan[format=annotation] and specifying the package(s) containing the components that you want to register.\nBy default, javadoc:org.springframework.boot.web.server.servlet.context.ServletComponentScan[format=annotation] scans from the package of the annotated class.\n\n\n\n[[howto.webserver.configure-access-logs]]\n== Configure Access Logging\n\nAccess logs can be configured for Tomcat and Jetty through their respective namespaces.\n\nFor instance, the following settings log access on Tomcat with a {url-tomcat-docs}/config/valve.html#Access_Logging[custom pattern].\n\n[configprops,yaml]\n----\nserver:\n  tomcat:\n    basedir: \"my-tomcat\"\n    accesslog:\n      enabled: true\n      pattern: \"%t %a %r %s (%D microseconds)\"\n----\n\nNOTE: The default location for logs is a `logs` directory relative to the Tomcat base directory.\nBy default, the `logs` directory is a temporary directory, so you may want to fix Tomcat's base directory or use an absolute path for the logs.\nIn the preceding example, the logs are available in `my-tomcat/logs` relative to the working directory of the application.\n\n\nFinally, access logging for Jetty can also be configured as follows:\n\n[configprops,yaml]\n----\nserver:\n  jetty:\n    accesslog:\n      enabled: true\n      filename: \"/var/log/jetty-access.log\"\n----\n\nBy default, logs are redirected to javadoc:java.lang.System#err[].\nFor more details, see the Jetty documentation.\n\n\n\n[[howto.webserver.use-behind-a-proxy-server]]\n== Running Behind a Front-end Proxy Server\n\nIf your application is running behind a proxy, a load-balancer or in the cloud, the request information (like the host, port, scheme...) might change along the way.\nYour application may be running on `10.10.10.10:8080`, but HTTP clients should only see `example.org`.\n\nhttps://tools.ietf.org/html/rfc7239[RFC7239 \"Forwarded Headers\"] defines the `Forwarded` HTTP header; proxies can use this header to provide information about the original request.\nYou can configure your application to read those headers and automatically use that information when creating links and sending them to clients in HTTP 302 responses, JSON documents or HTML pages.\nThere are also non-standard headers, like `X-Forwarded-Host`, `X-Forwarded-Port`, `X-Forwarded-Proto`, `X-Forwarded-Ssl`, and `X-Forwarded-Prefix`.\n\nIf the proxy adds the commonly used `X-Forwarded-For` and `X-Forwarded-Proto` headers, setting `server.forward-headers-strategy` to `NATIVE` is enough to support those.\nWith this option, the Web servers themselves natively support this feature; you can check their specific documentation to learn about specific behavior.\n\nIf this is not enough, Spring Framework provides a {url-spring-framework-docs}/web/webmvc/filters.html#filters-forwarded-headers[ForwardedHeaderFilter] for the servlet stack and a {url-spring-framework-docs}/web/webflux/reactive-spring.html#webflux-forwarded-headers[ForwardedHeaderTransformer] for the reactive stack.\nYou can use them in your application by setting configprop:server.forward-headers-strategy[] to `FRAMEWORK`.\n\nTIP: If you are using Tomcat and terminating SSL at the proxy, configprop:server.tomcat.redirect-context-root[] should be set to `false`.\nThis allows the `X-Forwarded-Proto` header to be honored before any redirects are performed.\n\nNOTE: If your application runs javadoc:org.springframework.boot.cloud.CloudPlatform#enum-constant-summary[in a supported Cloud Platform], the configprop:server.forward-headers-strategy[] property defaults to `NATIVE`.\nIn all other instances, it defaults to `NONE`.\n\n\n\n[[howto.webserver.use-behind-a-proxy-server.tomcat]]\n=== Customize Tomcat's Proxy Configuration\n\nIf you use Tomcat, you can additionally configure the names of the headers used to carry \"`forwarded`\" information, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  tomcat:\n    remoteip:\n      remote-ip-header: \"x-your-remote-ip-header\"\n      protocol-header: \"x-your-protocol-header\"\n----\n\nTomcat is also configured with a regular expression that matches internal proxies that are to be trusted.\nSee the xref:appendix:application-properties/index.adoc#application-properties.server.server.tomcat.remoteip.internal-proxies[configprop:server.tomcat.remoteip.internal-proxies[] entry in the appendix] for its default value.\nYou can customize the valve's configuration by adding an entry to `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  tomcat:\n    remoteip:\n      internal-proxies: \"192\\\\.168\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\"\n----\n\nNOTE: You can trust all proxies by setting the `internal-proxies` to empty (but do not do so in production).\n\nYou can take complete control of the configuration of Tomcat's javadoc:org.apache.catalina.valves.RemoteIpValve[] by switching the automatic one off (to do so, set `server.forward-headers-strategy=NONE`) and adding a new valve instance using a javadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] bean.\n\n\n\n[[howto.webserver.enable-multiple-connectors-in-tomcat]]\n== Enable Multiple Connectors with Tomcat\n\nYou can add an javadoc:org.apache.catalina.connector.Connector[] to the javadoc:org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory[], which can allow multiple connectors, including HTTP and HTTPS connectors, as shown in the following example:\n\ninclude-code::MyTomcatConfiguration[]\n\n\n\n[[howto.webserver.enable-tomcat-mbean-registry]]\n== Enable Tomcat's MBean Registry\n\nEmbedded Tomcat's MBean registry is disabled by default.\nThis minimizes Tomcat's memory footprint.\nIf you want to use Tomcat's MBeans, for example so that they can be used by Micrometer to expose metrics, you must use the configprop:server.tomcat.mbeanregistry.enabled[] property to do so, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  tomcat:\n    mbeanregistry:\n      enabled: true\n----\n\n\n\n\n[[howto.webserver.create-websocket-endpoints-using-serverendpoint]]\n== Create WebSocket Endpoints Using @ServerEndpoint\n\nIf you want to use javadoc:jakarta.websocket.server.ServerEndpoint[format=annotation] in a Spring Boot application that used an embedded container, you must declare a single javadoc:org.springframework.web.socket.server.standard.ServerEndpointExporter[] javadoc:org.springframework.context.annotation.Bean[format=annotation], as shown in the following example:\n\ninclude-code::MyWebSocketConfiguration[]\n\nThe bean shown in the preceding example registers any javadoc:jakarta.websocket.server.ServerEndpoint[format=annotation] annotated beans with the underlying WebSocket container.\nWhen deployed to a standalone servlet container, this role is performed by a servlet container initializer, and the javadoc:org.springframework.web.socket.server.standard.ServerEndpointExporter[] bean is not required.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/how-to/partials/nav-how-to.adoc",
    "content": "* xref:how-to:index.adoc[]\n\n** xref:how-to:application.adoc[]\n** xref:how-to:properties-and-configuration.adoc[]\n** xref:how-to:webserver.adoc[]\n** xref:how-to:spring-mvc.adoc[]\n** xref:how-to:jersey.adoc[]\n** xref:how-to:http-clients.adoc[]\n** xref:how-to:logging.adoc[]\n** xref:how-to:data-access.adoc[]\n** xref:how-to:data-initialization.adoc[]\n** xref:how-to:nosql.adoc[]\n** xref:how-to:messaging.adoc[]\n** xref:how-to:batch.adoc[]\n** xref:how-to:actuator.adoc[]\n** xref:how-to:security.adoc[]\n** xref:how-to:hotswapping.adoc[]\n** xref:how-to:testing.adoc[]\n** xref:how-to:build.adoc[]\n** xref:how-to:aot.adoc[]\n** xref:how-to:native-image/index.adoc[]\n*** xref:how-to:native-image/developing-your-first-application.adoc[]\n*** xref:how-to:native-image/testing-native-applications.adoc[]\n** xref:how-to:aot-cache.adoc[]\n** xref:how-to:deployment/index.adoc[]\n*** xref:how-to:deployment/traditional-deployment.adoc[]\n*** xref:how-to:deployment/cloud.adoc[]\n*** xref:how-to:deployment/installing.adoc[]\n** xref:how-to:docker-compose.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/auditing.adoc",
    "content": "[[actuator.auditing]]\n= Auditing\n\nOnce Spring Security is in play, Spring Boot Actuator has a flexible audit framework that publishes events (by default, \"`authentication success`\", \"`failure`\" and \"`access denied`\" exceptions).\nThis feature can be very useful for reporting and for implementing a lock-out policy based on authentication failures.\n\nYou can enable auditing by providing a bean of type javadoc:org.springframework.boot.actuate.audit.AuditEventRepository[] in your application's configuration.\nFor convenience, Spring Boot offers an javadoc:org.springframework.boot.actuate.audit.InMemoryAuditEventRepository[].\njavadoc:org.springframework.boot.actuate.audit.InMemoryAuditEventRepository[] has limited capabilities, and we recommend using it only for development environments.\nFor production environments, consider creating your own alternative javadoc:org.springframework.boot.actuate.audit.AuditEventRepository[] implementation.\n\n\n\n[[actuator.auditing.custom]]\n== Custom Auditing\n\nTo customize published security events, you can provide your own implementations of javadoc:org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener[] and javadoc:org.springframework.boot.actuate.security.AbstractAuthorizationAuditListener[].\n\nYou can also use the audit services for your own business events.\nTo do so, either inject the javadoc:org.springframework.boot.actuate.audit.AuditEventRepository[] bean into your own components and use that directly or publish an javadoc:org.springframework.boot.actuate.audit.listener.AuditApplicationEvent[] with the Spring javadoc:org.springframework.context.ApplicationEventPublisher[] (by implementing javadoc:org.springframework.context.ApplicationEventPublisherAware[]).\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/cloud-foundry.adoc",
    "content": "[[actuator.cloud-foundry]]\n= Cloud Foundry Support\n\nSpring Boot's `spring-boot-cloudfoundry` module (part of `spring-boot-starter-cloudfoundry`) includes additional support that is activated when you deploy to a compatible Cloud Foundry instance.\nThe `/cloudfoundryapplication` path provides an alternative secured route to all javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation] beans.\n\nThe extended support lets Cloud Foundry management UIs (such as the web application that you can use to view deployed applications) be augmented with Spring Boot actuator information.\nFor example, an application status page can include full health information instead of the typical \"`running`\" or \"`stopped`\" status.\n\nNOTE: The `/cloudfoundryapplication` path is not directly accessible to regular users.\nTo use the endpoint, you must pass a valid UAA token with the request.\n\n\n\n[[actuator.cloud-foundry.disable]]\n== Disabling Extended Cloud Foundry Actuator Support\n\nIf you want to fully disable the `/cloudfoundryapplication` endpoints, you can add the following setting to your `application.properties` file:\n\n[configprops,yaml]\n----\nmanagement:\n  cloudfoundry:\n    enabled: false\n----\n\n\n\n[[actuator.cloud-foundry.ssl]]\n== Cloud Foundry Self-signed Certificates\n\nBy default, the security verification for `/cloudfoundryapplication` endpoints makes SSL calls to various Cloud Foundry services.\nIf your Cloud Foundry UAA or Cloud Controller services use self-signed certificates, you need to set the following property:\n\n[configprops,yaml]\n----\nmanagement:\n  cloudfoundry:\n    skip-ssl-validation: true\n----\n\n\n\n[[actuator.cloud-foundry.custom-context-path]]\n== Custom Context Path\n\nIf the server's context-path has been configured to anything other than `/`, the Cloud Foundry endpoints are not available at the root of the application.\nFor example, if `server.servlet.context-path=/app`, Cloud Foundry endpoints are available at `/app/cloudfoundryapplication/*`.\n\nIf you expect the Cloud Foundry endpoints to always be available at `/cloudfoundryapplication/*`, regardless of the server's context-path, you need to explicitly configure that in your application.\nThe configuration differs, depending on the web server in use.\nFor Tomcat, you can add the following configuration:\n\ninclude-code::MyCloudFoundryConfiguration[]\n\nIf you're using a Webflux based application, you can use the following configuration:\n\ninclude-code::MyReactiveCloudFoundryConfiguration[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/enabling.adoc",
    "content": "[[actuator.enabling]]\n= Enabling Production-ready Features\n\nThe {code-spring-boot}/module/spring-boot-actuator[`spring-boot-actuator`] module provides all of Spring Boot's production-ready features.\nThe recommended way to enable the features is to add a dependency on the `spring-boot-starter-actuator` starter.\n\n.Definition of Actuator\n****\nAn actuator is a manufacturing term that refers to a mechanical device for moving or controlling something.\nActuators can generate a large amount of motion from a small change.\n****\n\nTo add the actuator to a Maven-based project, add the following starter dependency:\n\n[source,xml]\n----\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-actuator</artifactId>\n\t</dependency>\n</dependencies>\n----\n\nFor Gradle, use the following declaration:\n\n[source,gradle]\n----\ndependencies {\n\timplementation 'org.springframework.boot:spring-boot-starter-actuator'\n}\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/endpoints.adoc",
    "content": "[[actuator.endpoints]]\n= Endpoints\n\nActuator endpoints let you monitor and interact with your application.\nSpring Boot includes a number of built-in endpoints and lets you add your own.\nFor example, the `health` endpoint provides basic application health information.\n\nYou can xref:actuator/endpoints.adoc#actuator.endpoints.controlling-access[control access] to each individual endpoint and xref:actuator/endpoints.adoc#actuator.endpoints.exposing[expose them (make them remotely accessible) over HTTP or JMX].\nAn endpoint is considered to be available when access to it is permitted and it is exposed.\nThe built-in endpoints are auto-configured only when they are available.\nMost applications choose exposure over HTTP, where the ID of the endpoint and a prefix of `/actuator` is mapped to a URL.\nFor example, by default, the `health` endpoint is mapped to `/actuator/health`.\n\nTIP: To learn more about the Actuator's endpoints and their request and response formats, see the xref:api:rest/actuator/index.adoc[API documentation].\n\nThe following technology-agnostic endpoints are available:\n\n[cols=\"2,5\"]\n|===\n| ID | Description\n\n| `auditevents`\n| Exposes audit events information for the current application.\n  Requires an javadoc:org.springframework.boot.actuate.audit.AuditEventRepository[] bean.\n\n| `beans`\n| Displays a complete list of all the Spring beans in your application.\n\n| `caches`\n| Exposes available caches.\n\n| `conditions`\n| Shows the conditions that were evaluated on configuration and auto-configuration classes and the reasons why they did or did not match.\n\n| `configprops`\n| Displays a collated list of all javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\nSubject to xref:actuator/endpoints.adoc#actuator.endpoints.sanitization[sanitization].\n\n| `env`\n| Exposes properties from Spring's javadoc:org.springframework.core.env.ConfigurableEnvironment[].\nSubject to xref:actuator/endpoints.adoc#actuator.endpoints.sanitization[sanitization].\n\n| `flyway`\n| Shows any Flyway database migrations that have been applied.\n  Requires one or more javadoc:org.flywaydb.core.Flyway[] beans.\n\n| `health`\n| Shows application health information.\n\n| `httpexchanges`\n| Displays HTTP exchange information (by default, the last 100 HTTP request-response exchanges).\n  Requires an javadoc:org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository[] bean.\n\n| `info`\n| Displays arbitrary application info.\n\n| `integrationgraph`\n| Shows the Spring Integration graph.\n  Requires a dependency on `spring-integration-core`.\n\n| `loggers`\n| Shows and modifies the configuration of loggers in the application.\n\n| `liquibase`\n| Shows any Liquibase database migrations that have been applied.\n  Requires one or more javadoc:{url-liquibase-javadoc}/liquibase.Liquibase[] beans.\n\n| `metrics`\n| Shows \"`metrics`\" information for the current application to diagnose the metrics the application has recorded.\n\n| `mappings`\n| Displays a collated list of all javadoc:org.springframework.web.bind.annotation.RequestMapping[format=annotation] paths.\n\n|`quartz`\n|Shows information about Quartz Scheduler jobs.\nSubject to xref:actuator/endpoints.adoc#actuator.endpoints.sanitization[sanitization].\n\n| `scheduledtasks`\n| Displays the scheduled tasks in your application.\n\n| `sessions`\n| Allows retrieval and deletion of user sessions from a Spring Session-backed session store.\n  Requires a servlet-based web application that uses Spring Session.\n\n| `shutdown`\n| Lets the application be gracefully shutdown.\n  Only works when using jar packaging.\n  Disabled by default.\n\n| `startup`\n| Shows the xref:features/spring-application.adoc#features.spring-application.startup-tracking[startup steps data] collected by the javadoc:org.springframework.core.metrics.ApplicationStartup[].\n  Requires the javadoc:org.springframework.boot.SpringApplication[] to be configured with a javadoc:org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup[].\n\n| `threaddump`\n| Performs a thread dump.\n|===\n\nIf your application is a web application (Spring MVC, Spring WebFlux, or Jersey), you can use the following additional endpoints:\n\n[cols=\"2,5\"]\n|===\n| ID | Description\n\n| `heapdump`\n| Returns a heap dump file.\n  On a HotSpot JVM, an `HPROF`-format file is returned.\n  On an OpenJ9 JVM, a `PHD`-format file is returned.\n\n| `logfile`\n| Returns the contents of the logfile (if the `logging.file.name` or the `logging.file.path` property has been set).\n  Supports the use of the HTTP `Range` header to retrieve part of the log file's content.\n\n| `prometheus`\n| Exposes metrics in a format that can be scraped by a Prometheus server.\n  Requires a dependency on `micrometer-registry-prometheus`.\n|===\n\n\n\n[[actuator.endpoints.controlling-access]]\n== Controlling Access to Endpoints\n\nBy default, access to all endpoints except for `shutdown` and `heapdump` is unrestricted.\nTo configure the permitted access to an endpoint, use its `management.endpoint.<id>.access` property.\nThe following example allows unrestricted access to the `shutdown` endpoint:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    shutdown:\n      access: unrestricted\n----\n\nIf you prefer access to be opt-in rather than opt-out, set the configprop:management.endpoints.access.default[] property to `none` and use individual endpoint `access` properties to opt back in.\nThe following example allows read-only access to the `loggers` endpoint and denies access to all other endpoints:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    access:\n      default: none\n  endpoint:\n    loggers:\n      access: read-only\n----\n\nNOTE: Inaccessible endpoints are removed entirely from the application context.\nIf you want to change only the technologies over which an endpoint is exposed, use the xref:actuator/endpoints.adoc#actuator.endpoints.exposing[`include` and `exclude` properties] instead.\n\n\n\n[[actuator.endpoints.controlling-access.limiting]]\n=== Limiting Access\n\nApplication-wide endpoint access can be limited using the configprop:management.endpoints.access.max-permitted[] property.\nThis property takes precedence over the default access or an individual endpoint's access level.\nSet it to `none` to make all endpoints inaccessible.\nSet it to `read-only` to only allow read access to endpoints.\n\nFor javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint[format=annotation], and javadoc:org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint[format=annotation], read access equates to the endpoint methods annotated with javadoc:org.springframework.boot.actuate.endpoint.annotation.ReadOperation[format=annotation].\nFor javadoc:org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint[format=annotation] and javadoc:org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint[format=annotation], read access equates to request mappings that can handle `GET` and `HEAD` requests.\nFor javadoc:org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint[format=annotation], read access equates to `GET` and `HEAD` requests.\n\n\n\n[[actuator.endpoints.exposing]]\n== Exposing Endpoints\n\nBy default, only the health endpoint is exposed over HTTP and JMX.\nSince Endpoints may contain sensitive information, you should carefully consider when to expose them.\n\nTo change which endpoints are exposed, use the following technology-specific `include` and `exclude` properties:\n\n[cols=\"3,1\"]\n|===\n| Property | Default\n\n| configprop:management.endpoints.jmx.exposure.exclude[]\n|\n\n| configprop:management.endpoints.jmx.exposure.include[]\n| `health`\n\n| configprop:management.endpoints.web.exposure.exclude[]\n|\n\n| configprop:management.endpoints.web.exposure.include[]\n| `health`\n|===\n\nThe `include` property lists the IDs of the endpoints that are exposed.\nThe `exclude` property lists the IDs of the endpoints that should not be exposed.\nThe `exclude` property takes precedence over the `include` property.\nYou can configure both the `include` and the `exclude` properties with a list of endpoint IDs.\n\nFor example, to only expose the `health` and `info` endpoints over JMX, use the following property:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    jmx:\n      exposure:\n        include: \"health,info\"\n----\n\n`*` can be used to select all endpoints.\nFor example, to expose everything over HTTP except the `env` and `beans` endpoints, use the following properties:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      exposure:\n        include: \"*\"\n        exclude: \"env,beans\"\n----\n\nNOTE: `*` has a special meaning in YAML, so be sure to add quotation marks if you want to include (or exclude) all endpoints.\n\nNOTE: If your application is exposed publicly, we strongly recommend that you also xref:actuator/endpoints.adoc#actuator.endpoints.security[secure your endpoints].\n\nTIP: If you want to implement your own strategy for when endpoints are exposed, you can register an javadoc:org.springframework.boot.actuate.endpoint.EndpointFilter[] bean.\n\n\n\n[[actuator.endpoints.security]]\n== Security\n\nFor security purposes, only the `/health` endpoint is exposed over HTTP by default.\nYou can use the configprop:management.endpoints.web.exposure.include[] property to configure the endpoints that are exposed.\n\nNOTE: Before setting the `management.endpoints.web.exposure.include`, ensure that the exposed actuators do not contain sensitive information, are secured by placing them behind a firewall, or are secured by something like Spring Security.\n\nIf Spring Security is on the classpath and no other javadoc:org.springframework.security.web.SecurityFilterChain[] bean is present, all actuators other than `/health` are secured by Spring Boot auto-configuration.\nIf you define a custom javadoc:org.springframework.security.web.SecurityFilterChain[] bean, Spring Boot auto-configuration backs off and lets you fully control the actuator access rules.\n\nIf you wish to configure custom security for HTTP endpoints (for example, to allow only users with a certain role to access them), Spring Boot provides some convenient javadoc:org.springframework.security.web.util.matcher.RequestMatcher[] objects that you can use in combination with Spring Security.\n\nA typical Spring Security configuration might look something like the following example:\n\ninclude-code::typical/MySecurityConfiguration[]\n\nThe preceding example uses `EndpointRequest.toAnyEndpoint()` to match a request to any endpoint and then ensures that all have the `ENDPOINT_ADMIN` role.\nSeveral other matcher methods are also available on javadoc:org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest[].\nSee the xref:api:rest/actuator/index.adoc[API documentation] for details.\n\nNOTE: When matching for Actuator endpoints, `EndpointRequest.to(\"endpoint\")` will consider the endpoint root and all its subpaths,\neffectively matching `\"/actuator/endpoint/**\"` even if the endpoint does not declare nested routes.\n\nIf you deploy applications behind a firewall, you may prefer that all your actuator endpoints can be accessed without requiring authentication.\nYou can do so by changing the configprop:management.endpoints.web.exposure.include[] property, as follows:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      exposure:\n        include: \"*\"\n----\n\nAdditionally, if Spring Security is present, you would need to add custom security configuration that allows unauthenticated access to the endpoints, as the following example shows:\n\ninclude-code::exposeall/MySecurityConfiguration[]\n\nNOTE: In both of the preceding examples, the configuration applies only to the actuator endpoints.\nSince Spring Boot's security configuration backs off completely in the presence of any javadoc:org.springframework.security.web.SecurityFilterChain[] bean, you need to configure an additional javadoc:org.springframework.security.web.SecurityFilterChain[] bean with rules that apply to the rest of the application.\n\n\n\n[[actuator.endpoints.security.csrf]]\n=== Cross Site Request Forgery Protection\n\nSince Spring Boot relies on Spring Security's defaults, CSRF protection is turned on by default.\nThis means that the actuator endpoints that require a `POST` (shutdown and loggers endpoints), a `PUT`, or a `DELETE` get a 403 (forbidden) error when the default security configuration is in use.\n\nNOTE: We recommend disabling CSRF protection completely only if you are creating a service that is used by non-browser clients.\n\nYou can find additional information about CSRF protection in the {url-spring-security-docs}/features/exploits/csrf.html[Spring Security Reference Guide].\n\n\n\n[[actuator.endpoints.caching]]\n== Configuring Endpoints\n\nEndpoints automatically cache responses to read operations that do not take any parameters.\nTo configure the amount of time for which an endpoint caches a response, use its `cache.time-to-live` property.\nThe following example sets the time-to-live of the `beans` endpoint's cache to 10 seconds:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    beans:\n      cache:\n        time-to-live: \"10s\"\n----\n\nNOTE: The `management.endpoint.<name>` prefix uniquely identifies the endpoint that is being configured.\n\n\n\n[[actuator.endpoints.sanitization]]\n== Sanitize Sensitive Values\n\nInformation returned by the `/env`, `/configprops` and `/quartz` endpoints can be sensitive, so by default values are always fully sanitized (replaced by `+******+`).\n\nValues can only be viewed in an unsanitized form when:\n\n- The `show-values` property has been set to something other than `never`\n- No custom xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[`SanitizingFunction`] beans apply\n\nThe `show-values` property can be configured for sanitizable endpoints to one of the following values:\n\n- `never`  - values are always fully sanitized (replaced by `+******+`)\n- `always` - values are shown to all users (as long as no javadoc:org.springframework.boot.actuate.endpoint.SanitizingFunction[] bean applies)\n- `when-authorized` - values are shown only to authorized users (as long as no javadoc:org.springframework.boot.actuate.endpoint.SanitizingFunction[] bean applies)\n\nFor HTTP endpoints, a user is considered to be authorized if they have authenticated and have the roles configured by the endpoint's roles property.\nBy default, any authenticated user is authorized.\n\nFor JMX endpoints, all users are always authorized.\n\nThe following example allows all users with the `admin` role to view values from the `/env` endpoint in their original form.\nUnauthorized users, or users without the `admin` role, will see only sanitized values.\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    env:\n      show-values: when-authorized\n      roles: \"admin\"\n----\n\nNOTE: This example assumes that no xref:how-to:actuator.adoc#howto.actuator.customizing-sanitization[`SanitizingFunction`] beans have been defined.\n\n\n\n[[actuator.endpoints.hypermedia]]\n== Hypermedia for Actuator Web Endpoints\n\nA \"`discovery page`\" is added with links to all the endpoints.\nThe \"`discovery page`\" is available on `/actuator` by default.\n\nTo disable the \"`discovery page`\", add the following property to your application properties:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      discovery:\n        enabled: false\n----\n\nWhen a custom management context path is configured, the \"`discovery page`\" automatically moves from `/actuator` to the root of the management context.\nFor example, if the management context path is `/management`, the discovery page is available from `/management`.\nWhen the management context path is set to `/`, the discovery page is disabled to prevent the possibility of a clash with other mappings.\n\n\n\n[[actuator.endpoints.cors]]\n== CORS Support\n\nhttps://en.wikipedia.org/wiki/Cross-origin_resource_sharing[Cross-origin resource sharing] (CORS) is a https://www.w3.org/TR/cors/[W3C specification] that lets you specify in a flexible way what kind of cross-domain requests are authorized.\nIf you use Spring MVC or Spring WebFlux, you can configure Actuator's web endpoints to support such scenarios.\n\nCORS support is disabled by default and is only enabled once you have set the configprop:management.endpoints.web.cors.allowed-origins[] property.\nThe following configuration permits `GET` and `POST` calls from the `example.com` domain:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      cors:\n        allowed-origins: \"https://example.com\"\n        allowed-methods: \"GET,POST\"\n----\n\nTIP: See javadoc:org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties[] for a complete list of options.\n\n\n[[actuator.endpoints.json]]\n== JSON\n\nWhen working with JSON, Jackson is used for serialization and deserialization.\nBy default, an isolated javadoc:tools.jackson.databind.json.JsonMapper[] is used.\nThis isolation means that it does not share the same configuration as the application's `JsonMapper` and it is not affected by `spring.jackson.*` properties.\nTo disable this behavior and configure Actuator to use the application's `JsonMapper`, set configprop:management.endpoints.jackson.isolated-json-mapper[] to `false`.\nAlternatively, you can define your own javadoc:org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper[] bean that produces a `JsonMapper` that meets your needs.\nActuator will then use it for JSON processing.\n\n\n\n[[actuator.endpoints.implementing-custom]]\n== Implementing Custom Endpoints\n\nIf you add a javadoc:org.springframework.context.annotation.Bean[format=annotation] annotated with javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation], any methods annotated with javadoc:org.springframework.boot.actuate.endpoint.annotation.ReadOperation[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.annotation.WriteOperation[format=annotation], or javadoc:org.springframework.boot.actuate.endpoint.annotation.DeleteOperation[format=annotation] are automatically exposed over JMX and, in a web application, over HTTP as well.\nEndpoints can be exposed over HTTP by using Jersey, Spring MVC, or Spring WebFlux.\nIf both Jersey and Spring MVC are available, Spring MVC is used.\n\nThe following example exposes a read operation that returns a custom object:\n\ninclude-code::MyEndpoint[tag=read]\n\nYou can also write technology-specific endpoints by using javadoc:org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint[format=annotation] or javadoc:org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint[format=annotation].\nThese endpoints are restricted to their respective technologies.\nFor example, javadoc:org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint[format=annotation] is exposed only over HTTP and not over JMX.\n\nYou can write technology-specific extensions by using javadoc:org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension[format=annotation] and javadoc:org.springframework.boot.actuate.endpoint.jmx.annotation.EndpointJmxExtension[format=annotation].\nThese annotations let you provide technology-specific operations to augment an existing endpoint.\nAn endpoint may have at most one extension of each type.\n\nFinally, if you need access to web-framework-specific functionality, you can implement servlet or Spring javadoc:org.springframework.stereotype.Controller[format=annotation] and javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] endpoints at the cost of them not being available over JMX or when using a different web framework.\n\n\n\n[[actuator.endpoints.implementing-custom.input]]\n=== Receiving Input\n\nOperations on an endpoint receive input through their parameters.\nWhen exposed over the web, the values for these parameters are taken from the URL's query parameters and from the JSON request body.\nWhen exposed over JMX, the parameters are mapped to the parameters of the MBean's operations.\nParameters are required by default.\nThey can be made optional by annotating them with JSpecify's javadoc:org.jspecify.annotations.Nullable[format=annotation].\nKotlin null safety is also supported.\n\nYou can map each root property in the JSON request body to a parameter of the endpoint.\nConsider the following JSON request body:\n\n[source,json]\n----\n{\n\t\"name\": \"test\",\n\t\"counter\": 42\n}\n----\n\nYou can use this to invoke a write operation that takes `String name` and `int counter` parameters, as the following example shows:\n\ninclude-code::../MyEndpoint[tag=write]\n\nTIP: Because endpoints are technology agnostic, only simple types can be specified in the method signature.\nIn particular, declaring a single parameter with a javadoc:liquibase.report.CustomData[] type that defines a `name` and `counter` properties is not supported.\n\nNOTE: To let the input be mapped to the operation method's parameters, Java code that implements an endpoint should be compiled with `-parameters`.\nFor Kotlin code, please review {url-spring-framework-docs}/languages/kotlin/classes-interfaces.html[the recommendation] of the Spring Framework reference.\nThis will happen automatically if you use Spring Boot's Gradle plugin or if you use Maven and `spring-boot-starter-parent`.\n\n\n\n[[actuator.endpoints.implementing-custom.input.conversion]]\n==== Input Type Conversion\n\nThe parameters passed to endpoint operation methods are, if necessary, automatically converted to the required type.\nBefore calling an operation method, the input received over JMX or HTTP is converted to the required types by using an instance of javadoc:org.springframework.boot.convert.ApplicationConversionService[] as well as any javadoc:org.springframework.core.convert.converter.Converter[] or javadoc:org.springframework.core.convert.converter.GenericConverter[] beans qualified with javadoc:org.springframework.boot.actuate.endpoint.annotation.EndpointConverter[format=annotation].\n\n\n\n[[actuator.endpoints.implementing-custom.web]]\n=== Custom Web Endpoints\n\nOperations on an javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint[format=annotation], or javadoc:org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension[format=annotation] are automatically exposed over HTTP using Jersey, Spring MVC, or Spring WebFlux.\nIf both Jersey and Spring MVC are available, Spring MVC is used.\n\n\n\n[[actuator.endpoints.implementing-custom.web.request-predicates]]\n==== Web Endpoint Request Predicates\n\nA request predicate is automatically generated for each operation on a web-exposed endpoint.\n\n\n\n[[actuator.endpoints.implementing-custom.web.path-predicates]]\n==== Path\n\nThe path of the predicate is determined by the ID of the endpoint and the base path of the web-exposed endpoints.\nThe default base path is `/actuator`.\nFor example, an endpoint with an ID of `sessions` uses `/actuator/sessions` as its path in the predicate.\n\nYou can further customize the path by annotating one or more parameters of the operation method with javadoc:org.springframework.boot.actuate.endpoint.annotation.Selector[format=annotation].\nSuch a parameter is added to the path predicate as a path variable.\nThe variable's value is passed into the operation method when the endpoint operation is invoked.\nIf you want to capture all remaining path elements, you can add `@Selector(Match=ALL_REMAINING)` to the last parameter and make it a type that is conversion-compatible with a `String[]`.\n\n\n\n[[actuator.endpoints.implementing-custom.web.method-predicates]]\n==== HTTP method\n\nThe HTTP method of the predicate is determined by the operation type, as shown in the following table:\n\n[cols=\"3, 1\"]\n|===\n| Operation | HTTP method\n\n| javadoc:org.springframework.boot.actuate.endpoint.annotation.ReadOperation[format=annotation]\n| `GET`\n\n| javadoc:org.springframework.boot.actuate.endpoint.annotation.WriteOperation[format=annotation]\n| `POST`\n\n| javadoc:org.springframework.boot.actuate.endpoint.annotation.DeleteOperation[format=annotation]\n| `DELETE`\n|===\n\n\n\n[[actuator.endpoints.implementing-custom.web.consumes-predicates]]\n==== Consumes\n\nFor a javadoc:org.springframework.boot.actuate.endpoint.annotation.WriteOperation[format=annotation] (HTTP `POST`) that uses the request body, the `consumes` clause of the predicate is `application/vnd.spring-boot.actuator.v2+json, application/json`.\nFor all other operations, the `consumes` clause is empty.\n\n\n\n[[actuator.endpoints.implementing-custom.web.produces-predicates]]\n==== Produces\n\nThe `produces` clause of the predicate can be determined by the `produces` attribute of the javadoc:org.springframework.boot.actuate.endpoint.annotation.DeleteOperation[format=annotation], javadoc:org.springframework.boot.actuate.endpoint.annotation.ReadOperation[format=annotation], and javadoc:org.springframework.boot.actuate.endpoint.annotation.WriteOperation[format=annotation] annotations.\nThe attribute is optional.\nIf it is not used, the `produces` clause is determined automatically.\n\nIf the operation method returns `void` or javadoc:java.lang.Void[], the `produces` clause is empty.\nIf the operation method returns a javadoc:org.springframework.core.io.Resource[], the `produces` clause is `application/octet-stream`.\nFor all other operations, the `produces` clause is `application/vnd.spring-boot.actuator.v2+json, application/json`.\n\n\n\n[[actuator.endpoints.implementing-custom.web.response-status]]\n==== Web Endpoint Response Status\n\nThe default response status for an endpoint operation depends on the operation type (read, write, or delete) and what, if anything, the operation returns.\n\nIf a javadoc:org.springframework.boot.actuate.endpoint.annotation.ReadOperation[format=annotation] returns a value, the response status will be 200 (OK).\nIf it does not return a value, the response status will be 404 (Not Found).\n\nIf a javadoc:org.springframework.boot.actuate.endpoint.annotation.WriteOperation[format=annotation] or javadoc:org.springframework.boot.actuate.endpoint.annotation.DeleteOperation[format=annotation] returns a value, the response status will be 200 (OK).\nIf it does not return a value, the response status will be 204 (No Content).\n\nIf an operation is invoked without a required parameter or with a parameter that cannot be converted to the required type, the operation method is not called, and the response status will be 400 (Bad Request).\n\n\n\n[[actuator.endpoints.implementing-custom.web.range-requests]]\n==== Web Endpoint Range Requests\n\nYou can use an HTTP range request to request part of an HTTP resource.\nWhen using Spring MVC or Spring Web Flux, operations that return a javadoc:org.springframework.core.io.Resource[] automatically support range requests.\n\nNOTE: Range requests are not supported when using Jersey.\n\n\n\n[[actuator.endpoints.implementing-custom.web.security]]\n==== Web Endpoint Security\n\nAn operation on a web endpoint or a web-specific endpoint extension can receive the current javadoc:java.security.Principal[] or javadoc:org.springframework.boot.actuate.endpoint.SecurityContext[] as a method parameter.\nThe former is typically used in conjunction with javadoc:org.jspecify.annotations.Nullable[format=annotation] to provide different behavior for authenticated and unauthenticated users.\nThe latter is typically used to perform authorization checks by using its `isUserInRole(String)` method.\n\n\n\n[[actuator.endpoints.health]]\n== Health Information\n\nYou can use health information to check the status of your running application.\nIt is often used by monitoring software to alert someone when a production system goes down.\nThe information exposed by the `health` endpoint depends on the configprop:management.endpoint.health.show-details[] and configprop:management.endpoint.health.show-components[] properties, which can be configured with one of the following values:\n\n[cols=\"1, 3\"]\n|===\n| Name | Description\n\n| `never`\n| Details are never shown.\n\n| `when-authorized`\n| Details are shown only to authorized users.\n  Authorized roles can be configured by using `management.endpoint.health.roles`.\n\n| `always`\n| Details are shown to all users.\n|===\n\nThe default value is `never`.\nA user is considered to be authorized when they are in one or more of the endpoint's roles.\nIf the endpoint has no configured roles (the default), all authenticated users are considered to be authorized.\nYou can configure the roles by using the configprop:management.endpoint.health.roles[] property.\n\nNOTE: If you have secured your application and wish to use `always`, your security configuration must permit access to the health endpoint for both authenticated and unauthenticated users.\n\nHealth information is collected from the content of a javadoc:org.springframework.boot.health.registry.HealthContributorRegistry[] (by default, all javadoc:org.springframework.boot.health.contributor.HealthContributor[] instances defined in your javadoc:org.springframework.context.ApplicationContext[]).\nSpring Boot includes a number of auto-configured javadoc:org.springframework.boot.health.contributor.HealthContributor[] beans, and you can also write your own.\n\nA javadoc:org.springframework.boot.health.contributor.HealthContributor[] can be either a javadoc:org.springframework.boot.health.contributor.HealthIndicator[] or a javadoc:org.springframework.boot.health.contributor.CompositeHealthContributor[].\nA javadoc:org.springframework.boot.health.contributor.HealthIndicator[] provides actual health information, including a javadoc:org.springframework.boot.health.contributor.Status[].\nA javadoc:org.springframework.boot.health.contributor.CompositeHealthContributor[] provides a composite of other javadoc:org.springframework.boot.health.contributor.HealthContributor[] instances.\nTaken together, contributors form a tree structure to represent the overall system health.\n\nBy default, the final system health is derived by a javadoc:org.springframework.boot.health.actuate.endpoint.StatusAggregator[], which sorts the statuses from each javadoc:org.springframework.boot.health.contributor.HealthIndicator[] based on an ordered list of statuses.\nThe first status in the sorted list is used as the overall health status.\nIf no javadoc:org.springframework.boot.health.contributor.HealthIndicator[] returns a status that is known to the javadoc:org.springframework.boot.health.actuate.endpoint.StatusAggregator[], an `UNKNOWN` status is used.\n\nTIP: You can use the javadoc:org.springframework.boot.health.registry.HealthContributorRegistry[] to register and unregister health indicators at runtime.\n\n\n\n[[actuator.endpoints.health.auto-configured-health-indicators]]\n=== Auto-configured HealthIndicators\n\nWhen appropriate, Spring Boot auto-configures the javadoc:org.springframework.boot.health.contributor.HealthIndicator[] beans listed in the following table.\nYou can also enable or disable selected indicators by configuring `management.health.key.enabled`,\nwith the `key` listed in the following table:\n\n[cols=\"2,4,6\"]\n|===\n| Key | Name | Description\n\n| `cassandra`\n| javadoc:org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator[]\n| Checks that a Cassandra database is up.\n\n| `couchbase`\n| javadoc:org.springframework.boot.couchbase.health.CouchbaseHealthIndicator[]\n| Checks that a Couchbase cluster is up.\n\n| `db`\n| javadoc:org.springframework.boot.jdbc.health.DataSourceHealthIndicator[]\n| Checks that a connection to javadoc:javax.sql.DataSource[] can be obtained.\n\n| `diskspace`\n| javadoc:org.springframework.boot.health.application.DiskSpaceHealthIndicator[]\n| Checks for low disk space.\n\n| `elasticsearch`\n| javadoc:org.springframework.boot.elasticsearch.health.ElasticsearchRestClientHealthIndicator[]\n| Checks that an Elasticsearch cluster is up.\n\n| `hazelcast`\n| javadoc:org.springframework.boot.hazelcast.health.HazelcastHealthIndicator[]\n| Checks that a Hazelcast server is up.\n\n| `jms`\n| javadoc:org.springframework.boot.jms.health.JmsHealthIndicator[]\n| Checks that a JMS broker is up.\n\n| `ldap`\n| javadoc:org.springframework.boot.ldap.health.LdapHealthIndicator[]\n| Checks that an LDAP server is up.\n\n| `mail`\n| javadoc:org.springframework.boot.mail.health.MailHealthIndicator[]\n| Checks that a mail server is up.\n\n| `mongo`\n| javadoc:org.springframework.boot.mongodb.health.MongoHealthIndicator[]\n| Checks that a Mongo database is up.\n\n| `neo4j`\n| javadoc:org.springframework.boot.neo4j.health.Neo4jHealthIndicator[]\n| Checks that a Neo4j database is up.\n\n| `ping`\n| javadoc:org.springframework.boot.health.contributor.PingHealthIndicator[]\n| Always responds with `UP`.\n\n| `rabbit`\n| javadoc:org.springframework.boot.amqp.health.RabbitHealthIndicator[]\n| Checks that a Rabbit server is up.\n\n| `redis`\n| javadoc:org.springframework.boot.data.redis.health.DataRedisHealthIndicator[]\n| Checks that a Redis server is up.\n\n| `ssl`\n| javadoc:org.springframework.boot.health.application.SslHealthIndicator[]\n| Checks that SSL certificates are ok.\n|===\n\nTIP: You can disable them all by setting the configprop:management.health.defaults.enabled[] property.\n\nTIP: The `ssl` javadoc:org.springframework.boot.health.contributor.HealthIndicator[] has a \"warning threshold\" property named configprop:management.health.ssl.certificate-validity-warning-threshold[].\nYou can use this threshold to give yourself enough lead time to rotate the soon-to-be-expired certificate.\nIf an SSL certificate will become invalid within the period defined by this threshold, the javadoc:org.springframework.boot.health.contributor.HealthIndicator[] will report this in the details section of its response where `details.validChains.certificates.[*].validity.status` will have the value `WILL_EXPIRE_SOON`.\n\nAdditional javadoc:org.springframework.boot.health.contributor.HealthIndicator[] beans are enabled by default:\n\n[cols=\"3,4,6\"]\n|===\n| Key | Name | Description\n\n| `livenessstate`\n| javadoc:org.springframework.boot.health.application.LivenessStateHealthIndicator[]\n| Exposes the \"`Liveness`\" application availability state.\n\n| `readinessstate`\n| javadoc:org.springframework.boot.health.application.ReadinessStateHealthIndicator[]\n| Exposes the \"`Readiness`\" application availability state.\n|===\n\nThese can be disabled by using the configprop:management.endpoint.health.probes.enabled[] configuration property.\n\n\n\n[[actuator.endpoints.health.writing-custom-health-indicators]]\n=== Writing Custom HealthIndicators\n\nTo provide custom health information, you can register Spring beans that implement the javadoc:org.springframework.boot.health.contributor.HealthIndicator[] interface.\nYou need to provide an implementation of the `health()` method and return a javadoc:org.springframework.boot.health.contributor.Health[] response.\nThe javadoc:org.springframework.boot.health.contributor.Health[] response should include a status and can optionally include additional details to be displayed.\nThe following code shows a sample javadoc:org.springframework.boot.health.contributor.HealthIndicator[] implementation:\n\ninclude-code::MyHealthIndicator[]\n\nNOTE: The identifier for a given javadoc:org.springframework.boot.health.contributor.HealthIndicator[] is the name of the bean without the javadoc:org.springframework.boot.health.contributor.HealthIndicator[] suffix, if it exists.\nIn the preceding example, the health information is available in an entry named `my`.\n\nTIP: Health indicators are usually called over HTTP and need to respond before any connection timeouts.\nSpring Boot will log a warning message for any health indicator that takes longer than 10 seconds to respond.\nIf you want to configure this threshold, you can use the configprop:management.endpoint.health.logging.slow-indicator-threshold[] property.\n\nIn addition to Spring Boot's predefined javadoc:org.springframework.boot.health.contributor.Status[] types, javadoc:org.springframework.boot.health.contributor.Health[] can return a custom javadoc:org.springframework.boot.health.contributor.Status[] that represents a new system state.\nIn such cases, you also need to provide a custom implementation of the javadoc:org.springframework.boot.health.actuate.endpoint.StatusAggregator[] interface, or you must configure the default implementation by using the configprop:management.endpoint.health.status.order[] configuration property.\n\nFor example, assume a new javadoc:org.springframework.boot.health.contributor.Status[] with a code of `FATAL` is being used in one of your javadoc:org.springframework.boot.health.contributor.HealthIndicator[] implementations.\nTo configure the severity order, add the following property to your application properties:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    health:\n      status:\n        order: \"fatal,down,out-of-service,unknown,up\"\n----\n\nThe HTTP status code in the response reflects the overall health status.\nBy default, `OUT_OF_SERVICE` and `DOWN` map to 503.\nAny unmapped health statuses, including `UP`, map to 200.\nYou might also want to register custom status mappings if you access the health endpoint over HTTP.\nConfiguring a custom mapping disables the defaults mappings for `DOWN` and `OUT_OF_SERVICE`.\nIf you want to retain the default mappings, you must explicitly configure them, alongside any custom mappings.\nFor example, the following property maps `FATAL` to 503 (service unavailable) and retains the default mappings for `DOWN` and `OUT_OF_SERVICE`:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    health:\n      status:\n        http-mapping:\n          down: 503\n          fatal: 503\n          out-of-service: 503\n----\n\nTIP: If you need more control, you can define your own javadoc:org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper[] bean.\n\nThe following table shows the default status mappings for the built-in statuses:\n\n[cols=\"1,3\"]\n|===\n| Status | Mapping\n\n| `DOWN`\n| `SERVICE_UNAVAILABLE` (`503`)\n\n| `OUT_OF_SERVICE`\n| `SERVICE_UNAVAILABLE` (`503`)\n\n| `UP`\n| No mapping by default, so HTTP status is `200`\n\n| `UNKNOWN`\n| No mapping by default, so HTTP status is `200`\n|===\n\n\n\n[[actuator.endpoints.health.reactive-health-indicators]]\n=== Reactive Health Indicators\n\nFor reactive applications, such as those that use Spring WebFlux, javadoc:org.springframework.boot.health.contributor.ReactiveHealthContributor[] provides a non-blocking contract for getting application health.\nSimilar to a traditional javadoc:org.springframework.boot.health.contributor.HealthContributor[], health information is collected from the content of a javadoc:org.springframework.boot.health.registry.ReactiveHealthContributorRegistry[] (by default, all javadoc:org.springframework.boot.health.contributor.HealthContributor[] and javadoc:org.springframework.boot.health.contributor.ReactiveHealthContributor[] instances defined in your javadoc:org.springframework.context.ApplicationContext[]).\nRegular javadoc:org.springframework.boot.health.contributor.HealthContributor[] instances that do not check against a reactive API are executed on the elastic scheduler.\n\nTIP: In a reactive application, you should use the javadoc:org.springframework.boot.health.registry.ReactiveHealthContributorRegistry[] to register and unregister health indicators at runtime.\nIf you need to register a regular javadoc:org.springframework.boot.health.contributor.HealthContributor[], you should wrap it with `ReactiveHealthContributor#adapt`.\n\nTo provide custom health information from a reactive API, you can register Spring beans that implement the javadoc:org.springframework.boot.health.contributor.ReactiveHealthIndicator[] interface.\nThe following code shows a sample javadoc:org.springframework.boot.health.contributor.ReactiveHealthIndicator[] implementation:\n\ninclude-code::MyReactiveHealthIndicator[]\n\nTIP: To handle the error automatically, consider extending from javadoc:org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator[].\n\n\n\n[[actuator.endpoints.health.auto-configured-reactive-health-indicators]]\n=== Auto-configured ReactiveHealthIndicators\n\nWhen appropriate, Spring Boot auto-configures the following javadoc:org.springframework.boot.health.contributor.ReactiveHealthIndicator[] beans:\n\n[cols=\"2,4,6\"]\n|===\n| Key | Name | Description\n\n| `cassandra`\n| javadoc:org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator[]\n| Checks that a Cassandra database is up.\n\n| `couchbase`\n| javadoc:org.springframework.boot.couchbase.health.CouchbaseReactiveHealthIndicator[]\n| Checks that a Couchbase cluster is up.\n\n| `elasticsearch`\n| javadoc:org.springframework.boot.data.elasticsearch.health.DataElasticsearchReactiveHealthIndicator[]\n| Checks that an Elasticsearch cluster is up.\n\n| `mongo`\n| javadoc:org.springframework.boot.mongodb.health.MongoReactiveHealthIndicator[]\n| Checks that a Mongo database is up.\n\n| `neo4j`\n| javadoc:org.springframework.boot.neo4j.health.Neo4jReactiveHealthIndicator[]\n| Checks that a Neo4j database is up.\n\n| `redis`\n| javadoc:org.springframework.boot.data.redis.health.DataRedisReactiveHealthIndicator[]\n| Checks that a Redis server is up.\n|===\n\nTIP: If necessary, reactive indicators replace the regular ones.\nAlso, any javadoc:org.springframework.boot.health.contributor.HealthIndicator[] that is not handled explicitly is wrapped automatically.\n\n\n\n[[actuator.endpoints.health.groups]]\n=== Health Groups\n\nIt is sometimes useful to organize health indicators into groups that you can use for different purposes.\n\nTo create a health indicator group, you can use the `management.endpoint.health.group.<name>` property and specify a list of health indicator IDs to `include` or `exclude`.\nFor example, to create a group that includes only database indicators you can define the following:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    health:\n      group:\n        custom:\n          include: \"db\"\n----\n\nYou can then check the result by hitting `http://localhost:8080/actuator/health/custom`.\n\nSimilarly, to create a group that excludes the database indicators from the group and includes all the other indicators, you can define the following:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    health:\n      group:\n        custom:\n          exclude: \"db\"\n----\n\nBy default, startup will fail if a health group includes or excludes a health indicator that does not exist.\nTo disable this behavior set configprop:management.endpoint.health.validate-group-membership[] to `false`.\n\nBy default, groups inherit the same javadoc:org.springframework.boot.health.actuate.endpoint.StatusAggregator[] and javadoc:org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper[] settings as the system health.\nHowever, you can also define these on a per-group basis.\nYou can also override the `show-details` and `roles` properties if required:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    health:\n      group:\n        custom:\n          show-details: \"when-authorized\"\n          roles: \"admin\"\n          status:\n            order: \"fatal,up\"\n            http-mapping:\n              fatal: 500\n              out-of-service: 500\n----\n\nTIP: You can use `@Qualifier(\"groupname\")` if you need to register custom javadoc:org.springframework.boot.health.actuate.endpoint.StatusAggregator[] or javadoc:org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper[] beans for use with the group.\n\nA health group can also include/exclude a javadoc:org.springframework.boot.health.contributor.CompositeHealthContributor[].\nYou can also include/exclude only a certain component of a javadoc:org.springframework.boot.health.contributor.CompositeHealthContributor[].\nThis can be done using the fully qualified name of the component as follows:\n\n[source,properties]\n----\nmanagement.endpoint.health.group.custom.include=\"test/primary\"\nmanagement.endpoint.health.group.custom.exclude=\"test/primary/b\"\n----\n\nIn the example above, the `custom` group will include the javadoc:org.springframework.boot.health.contributor.HealthContributor[] with the name `primary` which is a component of the composite `test`.\nHere, `primary` itself is a composite and the javadoc:org.springframework.boot.health.contributor.HealthContributor[] with the name `b` will be excluded from the `custom` group.\n\n\nHealth groups can be made available at an additional path on either the main or management port.\nThis is useful in cloud environments such as Kubernetes, where it is quite common to use a separate management port for the actuator endpoints for security purposes.\nHaving a separate port could lead to unreliable health checks because the main application might not work properly even if the health check is successful.\nThe health group can be configured with an additional path as follows:\n\n[source,properties]\n----\nmanagement.endpoint.health.group.live.additional-path=\"server:/healthz\"\n----\n\nThis would make the `live` health group available on the main server port at `/healthz`.\nThe prefix is mandatory and must be either `server:` (represents the main server port) or `management:` (represents the management port, if configured.)\nThe path must be a single path segment.\n\n\n\n[[actuator.endpoints.health.datasource]]\n=== DataSource Health\n\nThe javadoc:javax.sql.DataSource[] health indicator shows the health of both standard data sources and routing data source beans.\nThe health of a routing data source includes the health of each of its target data sources.\nIn the health endpoint's response, each of a routing data source's targets is named by using its routing key.\nIf you prefer not to include routing data sources in the indicator's output, set configprop:management.health.db.ignore-routing-data-sources[] to `true`.\n\n\n\n[[actuator.endpoints.kubernetes-probes]]\n== Kubernetes Probes\n\nApplications deployed on Kubernetes can provide information about their internal state with https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes[Container Probes].\nDepending on https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/[your Kubernetes configuration], the kubelet calls those probes and reacts to the result.\n\nBy default, Spring Boot manages your xref:features/spring-application.adoc#features.spring-application.application-availability[Application Availability] state.\nIf deployed in a Kubernetes environment, actuator gathers the \"`Liveness`\" and \"`Readiness`\" information from the javadoc:org.springframework.boot.availability.ApplicationAvailability[] interface and uses that information in dedicated xref:actuator/endpoints.adoc#actuator.endpoints.health.auto-configured-health-indicators[health indicators]: javadoc:org.springframework.boot.health.application.LivenessStateHealthIndicator[] and javadoc:org.springframework.boot.health.application.ReadinessStateHealthIndicator[].\nThese indicators are shown on the global health endpoint (`\"/actuator/health\"`).\nThey are also exposed as separate HTTP Probes by using xref:actuator/endpoints.adoc#actuator.endpoints.health.groups[health groups]: `\"/actuator/health/liveness\"` and `\"/actuator/health/readiness\"`.\n\nYou can then configure your Kubernetes infrastructure with the following endpoint information:\n\n[source,yaml]\n----\nlivenessProbe:\n  httpGet:\n    path: \"/actuator/health/liveness\"\n    port: <actuator-port>\n  failureThreshold: ...\n  periodSeconds: ...\n\nreadinessProbe:\n  httpGet:\n    path: \"/actuator/health/readiness\"\n    port: <actuator-port>\n  failureThreshold: ...\n  periodSeconds: ...\n----\n\nNOTE: `<actuator-port>` should be set to the port that the actuator endpoints are available on.\nIt could be the main web server port or a separate management port if the `\"management.server.port\"` property has been set.\n\nThese health groups are automatically enabled.\nYou can disable them by using the configprop:management.endpoint.health.probes.enabled[] configuration property.\n\nNOTE: If an application takes longer to start than the configured liveness period, Kubernetes mentions the `\"startupProbe\"` as a possible solution.\nGenerally speaking, the `\"startupProbe\"` is not necessarily needed here, as the `\"readinessProbe\"` fails until all startup tasks are done.\nThis means your application will not receive traffic until it is ready.\nHowever, if your application takes a long time to start, consider using a `\"startupProbe\"` to make sure that Kubernetes won't kill your application while it is in the process of starting.\nSee the section that describes xref:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes.lifecycle[how probes behave during the application lifecycle].\n\nIf your Actuator endpoints are deployed on a separate management context, the endpoints do not use the same web infrastructure (port, connection pools, framework components) as the main application.\nIn this case, a probe check could be successful even if the main application does not work properly (for example, it cannot accept new connections).\nFor this reason, it is a good idea to make the `liveness` and `readiness` health groups available on the main server port.\nThis can be done by setting the following property:\n\n[source,properties]\n----\nmanagement.endpoint.health.probes.add-additional-paths=true\n----\n\nThis would make the `liveness` group available at `/livez` and the `readiness` group available at `/readyz` on the main server port.\nPaths can be customized using the `additional-path` property on each group, see xref:actuator/endpoints.adoc#actuator.endpoints.health.groups[health groups] for details.\n\n\n\n[[actuator.endpoints.kubernetes-probes.external-state]]\n=== Checking External State With Kubernetes Probes\n\nActuator configures the \"`liveness`\" and \"`readiness`\" probes as Health Groups.\nThis means that all the xref:actuator/endpoints.adoc#actuator.endpoints.health.groups[health groups features] are available for them.\nYou can, for example, configure additional Health Indicators:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    health:\n      group:\n        readiness:\n          include: \"readinessState,customCheck\"\n----\n\nBy default, Spring Boot does not add other health indicators to these groups.\n\nThe \"`liveness`\" probe should not depend on health checks for external systems.\nIf the xref:features/spring-application.adoc#features.spring-application.application-availability.liveness[liveness state of an application] is broken, Kubernetes tries to solve that problem by restarting the application instance.\nThis means that if an external system (such as a database, a Web API, or an external cache) fails, Kubernetes might restart all application instances and create cascading failures.\n\nAs for the \"`readiness`\" probe, the choice of checking external systems must be made carefully by the application developers.\nFor this reason, Spring Boot does not include any additional health checks in the readiness probe.\nIf the xref:features/spring-application.adoc#features.spring-application.application-availability.readiness[readiness state of an application instance] is unready, Kubernetes does not route traffic to that instance.\nSome external systems might not be shared by application instances, in which case they could be included in a readiness probe.\nOther external systems might not be essential to the application (the application could have circuit breakers and fallbacks), in which case they definitely should not be included.\nUnfortunately, an external system that is shared by all application instances is common, and you have to make a judgement call: Include it in the readiness probe and expect that the application is taken out of service when the external service is down or leave it out and deal with failures higher up the stack, perhaps by using a circuit breaker in the caller.\n\nNOTE: If all instances of an application are unready, a Kubernetes Service with `type=ClusterIP` or `NodePort` does not accept any incoming connections.\nThere is no HTTP error response (503 and so on), since there is no connection.\nA service with `type=LoadBalancer` might or might not accept connections, depending on the provider.\nA service that has an explicit https://kubernetes.io/docs/concepts/services-networking/ingress/[ingress] also responds in a way that depends on the implementation -- the ingress service itself has to decide how to handle the \"`connection refused`\" from downstream.\nHTTP 503 is quite likely in the case of both load balancer and ingress.\n\nAlso, if an application uses Kubernetes https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/[autoscaling], it may react differently to applications being taken out of the load-balancer, depending on its autoscaler configuration.\n\n\n\n[[actuator.endpoints.kubernetes-probes.lifecycle]]\n=== Application Lifecycle and Probe States\n\nAn important aspect of the Kubernetes Probes support is its consistency with the application lifecycle.\nThere is a significant difference between the javadoc:org.springframework.boot.availability.AvailabilityState[] (which is the in-memory, internal state of the application)\nand the actual probe (which exposes that state).\nDepending on the phase of application lifecycle, the probe might not be available.\n\nSpring Boot publishes xref:features/spring-application.adoc#features.spring-application.application-events-and-listeners[application events during startup and shutdown],\nand probes can listen to such events and expose the javadoc:org.springframework.boot.availability.AvailabilityState[] information.\n\nThe following tables show the javadoc:org.springframework.boot.availability.AvailabilityState[] and the state of HTTP connectors at different stages.\n\nWhen a Spring Boot application starts:\n\n[cols=\"2,2,2,3,5\"]\n|===\n|Startup phase |LivenessState |ReadinessState |HTTP server |Notes\n\n|Starting\n|`BROKEN`\n|`REFUSING_TRAFFIC`\n|Not started\n|Kubernetes checks the \"liveness\" Probe and restarts the application if it takes too long.\n\n|Started\n|`CORRECT`\n|`REFUSING_TRAFFIC`\n|Refuses requests\n|The application context is refreshed. The application performs startup tasks and does not receive traffic yet.\n\n|Ready\n|`CORRECT`\n|`ACCEPTING_TRAFFIC`\n|Accepts requests\n|Startup tasks are finished. The application is receiving traffic.\n|===\n\nWhen a Spring Boot application shuts down:\n\n[cols=\"2,2,2,3,5\"]\n|===\n|Shutdown phase |Liveness State |Readiness State |HTTP server |Notes\n\n|Running\n|`CORRECT`\n|`ACCEPTING_TRAFFIC`\n|Accepts requests\n|Shutdown has been requested.\n\n|Graceful shutdown\n|`CORRECT`\n|`REFUSING_TRAFFIC`\n|New requests are rejected\n|If enabled, xref:web/graceful-shutdown.adoc[graceful shutdown processes in-flight requests].\nHTTP probes also stop accepting traffic, so the availability states are not readily available externally.\n\n|Shutdown complete\n|N/A\n|N/A\n|Server is shut down\n|The application context is closed and the application is shut down.\n|===\n\nTIP: See xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes.container-lifecycle[] for more information about Kubernetes deployment.\nIn particular, it describes how to use the `preStop` hook to give your application time to shut down gracefully before Kubernetes kills it.\n\n\n\n[[actuator.endpoints.info]]\n== Application Information\n\nApplication information exposes various information collected from all javadoc:org.springframework.boot.actuate.info.InfoContributor[] beans defined in your javadoc:org.springframework.context.ApplicationContext[].\nSpring Boot includes a number of auto-configured javadoc:org.springframework.boot.actuate.info.InfoContributor[] beans, and you can write your own.\n\n\n\n[[actuator.endpoints.info.auto-configured-info-contributors]]\n=== Auto-configured InfoContributors\n\nWhen appropriate, Spring auto-configures the following javadoc:org.springframework.boot.actuate.info.InfoContributor[] beans:\n\n[cols=\"1,4,8,4\"]\n|===\n| ID | Name | Description | Prerequisites\n\n| `build`\n| javadoc:org.springframework.boot.actuate.info.BuildInfoContributor[]\n| Exposes build information.\n| A `META-INF/build-info.properties` resource.\n\n| `env`\n| javadoc:org.springframework.boot.actuate.info.EnvironmentInfoContributor[]\n| Exposes any property from the javadoc:org.springframework.core.env.Environment[] whose name starts with `info.`.\n| None.\n\n| `git`\n| javadoc:org.springframework.boot.actuate.info.GitInfoContributor[]\n| Exposes git information.\n| A `git.properties` resource.\n\n| `java`\n| javadoc:org.springframework.boot.actuate.info.JavaInfoContributor[]\n| Exposes Java runtime information.\n| None.\n\n| `os`\n| javadoc:org.springframework.boot.actuate.info.OsInfoContributor[]\n| Exposes Operating System information.\n| None.\n\n| `process`\n| javadoc:org.springframework.boot.actuate.info.ProcessInfoContributor[]\n| Exposes process information.\n| None.\n\n| `ssl`\n| javadoc:org.springframework.boot.actuate.info.SslInfoContributor[]\n| Exposes SSL certificate information.\n| An xref:features/ssl.adoc#features.ssl.bundles[SSL Bundle] configured.\n\n|===\n\nWhether an individual contributor is enabled is controlled by its `management.info.<id>.enabled` property.\nDifferent contributors have different defaults for this property, depending on their prerequisites and the nature of the information that they expose.\n\nWith no prerequisites to indicate that they should be enabled, the `env`, `java`, `os`, and `process` contributors are disabled by default. The `ssl` contributor has a prerequisite of having an xref:features/ssl.adoc#features.ssl.bundles[SSL Bundle] configured but it is disabled by default.\nEach can be enabled by setting its `management.info.<id>.enabled` property to `true`.\n\nThe `build` and `git` info contributors are enabled by default.\nEach can be disabled by setting its `management.info.<id>.enabled` property to `false`.\nAlternatively, to disable every contributor that is usually enabled by default, set the configprop:management.info.defaults.enabled[] property to `false`.\n\n\n\n[[actuator.endpoints.info.custom-application-information]]\n=== Custom Application Information\n\nWhen the `env` contributor is enabled, you can customize the data exposed by the `info` endpoint by setting `+info.*+` Spring properties.\nAll javadoc:org.springframework.core.env.Environment[] properties under the `info` key are automatically exposed.\nFor example, you could add the following settings to your `application.properties` file:\n\n[configprops,yaml]\n----\ninfo:\n  app:\n    encoding: \"UTF-8\"\n    java:\n      source: \"17\"\n      target: \"17\"\n----\n\n[TIP]\n====\nRather than hardcoding those values, you could also xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.expand-properties[expand info properties at build time].\n\nAssuming you use Maven, you could rewrite the preceding example as follows:\n\n[configprops,yaml]\n----\ninfo:\n  app:\n    encoding: \"@project.build.sourceEncoding@\"\n    java:\n      source: \"@java.version@\"\n      target: \"@java.version@\"\n----\n====\n\n\n\n[[actuator.endpoints.info.git-commit-information]]\n=== Git Commit Information\n\nAnother useful feature of the `info` endpoint is its ability to publish information about the state of your `git` source code repository when the project was built.\nIf a javadoc:org.springframework.boot.info.GitProperties[] bean is available, you can use the `info` endpoint to expose these properties.\n\nTIP: A javadoc:org.springframework.boot.info.GitProperties[] bean is auto-configured if a `git.properties` file is available at the root of the classpath.\nSee xref:how-to:build.adoc#howto.build.generate-git-info[] for more detail.\n\nBy default, the endpoint exposes `git.branch`, `git.commit.id`, and `git.commit.time` properties, if present.\nIf you do not want any of these properties in the endpoint response, they need to be excluded from the `git.properties` file.\nIf you want to display the full git information (that is, the full content of `git.properties`), use the configprop:management.info.git.mode[] property, as follows:\n\n[configprops,yaml]\n----\nmanagement:\n  info:\n    git:\n      mode: \"full\"\n----\n\nTo disable the git commit information from the `info` endpoint completely, set the configprop:management.info.git.enabled[] property to `false`, as follows:\n\n[configprops,yaml]\n----\nmanagement:\n  info:\n    git:\n      enabled: false\n----\n\n\n\n[[actuator.endpoints.info.build-information]]\n=== Build Information\n\nIf a javadoc:org.springframework.boot.info.BuildProperties[] bean is available, the `info` endpoint can also publish information about your build.\nThis happens if a `META-INF/build-info.properties` file is available in the classpath.\n\nTIP: The Maven and Gradle plugins can both generate that file.\nSee xref:how-to:build.adoc#howto.build.generate-info[] for more details.\n\n\n\n[[actuator.endpoints.info.java-information]]\n=== Java Information\n\nThe `info` endpoint publishes information about your Java runtime environment, see javadoc:org.springframework.boot.info.JavaInfo[] for more details.\n\n\n\n[[actuator.endpoints.info.os-information]]\n=== OS Information\n\nThe `info` endpoint publishes information about your Operating System, see javadoc:org.springframework.boot.info.OsInfo[] for more details.\n\n\n\n[[actuator.endpoints.info.process-information]]\n=== Process Information\n\nThe `info` endpoint publishes information about your process, see javadoc:org.springframework.boot.info.ProcessInfo[] for more details.\n\n\n\n[[actuator.endpoints.info.ssl-information]]\n=== SSL Information\n\nThe `info` endpoint publishes information about your SSL certificates (that are configured through xref:features/ssl.adoc#features.ssl.bundles[SSL Bundles]), see javadoc:org.springframework.boot.info.SslInfo[] for more details.\n\n\n\n[[actuator.endpoints.info.writing-custom-info-contributors]]\n=== Writing Custom InfoContributors\n\nTo provide custom application information, you can register Spring beans that implement the javadoc:org.springframework.boot.actuate.info.InfoContributor[] interface.\n\nThe following example contributes an `example` entry with a single value:\n\ninclude-code::MyInfoContributor[]\n\nIf you reach the `info` endpoint, you should see a response that contains the following additional entry:\n\n[source,json]\n----\n{\n\t\"example\": {\n\t\t\"key\" : \"value\"\n\t}\n}\n----\n\n\n\n[[actuator.endpoints.sbom]]\n== Software Bill of Materials (SBOM)\n\nThe `sbom` endpoint exposes the https://en.wikipedia.org/wiki/Software_supply_chain[Software Bill of Materials].\nCycloneDX SBOMs can be auto-detected, but other formats can be manually configured, too.\n\nThe `sbom` actuator endpoint will then expose an SBOM called \"application\", which describes the contents of your application.\n\nTIP: To automatically generate a CycloneDX SBOM at project build time, please see the xref:how-to:build.adoc#howto.build.generate-cyclonedx-sbom[] section.\n\n\n\n[[actuator.endpoints.sbom.other-formats]]\n=== Other SBOM formats\n\nIf you want to publish an SBOM in a different format, there are some configuration properties which you can use.\n\nThe configuration property configprop:management.endpoint.sbom.application.location[] sets the location for the application SBOM.\nFor example, setting this to `classpath:sbom.json` will use the contents of the `/sbom.json` resource on the classpath.\n\nThe media type for SBOMs in CycloneDX, SPDX and Syft format is detected automatically.\nTo override the auto-detected media type, use the configuration property configprop:management.endpoint.sbom.application.media-type[].\n\n\n\n[[actuator.endpoints.sbom.additional]]\n=== Additional SBOMs\n\nThe actuator endpoint can handle multiple SBOMs.\nTo add SBOMs, use the configuration property configprop:management.endpoint.sbom.additional[], as shown in this example:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoint:\n    sbom:\n      additional:\n        system:\n          location: \"optional:file:/system.spdx.json\"\n          media-type: \"application/spdx+json\"\n----\n\nThis will add an SBOM called \"system\", which is stored in `/system.spdx.json`.\nThe `optional:` prefix can be used to prevent a startup failure if the file doesn't exist.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/http-exchanges.adoc",
    "content": "[[actuator.http-exchanges]]\n= Recording HTTP Exchanges\n\nYou can enable recording of HTTP exchanges by providing a bean of type javadoc:org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository[] in your application's configuration.\nFor convenience, Spring Boot offers javadoc:org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository[], which, by default, stores the last 100 request-response exchanges.\njavadoc:org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository[] is limited compared to tracing solutions, and we recommend using it only for development environments.\nFor production environments, we recommend using a production-ready tracing or observability solution, such as Zipkin or OpenTelemetry.\nAlternatively, you can create your own javadoc:org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository[].\n\nYou can use the `httpexchanges` endpoint to obtain information about the request-response exchanges that are stored in the javadoc:org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository[].\n\n\n\n[[actuator.http-exchanges.custom]]\n== Custom HTTP Exchange Recording\n\nTo customize the items that are included in each recorded exchange, use the configprop:management.httpexchanges.recording.include[] configuration property.\n\nTo disable recording entirely, set configprop:management.httpexchanges.recording.enabled[] to `false`.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/index.adoc",
    "content": "\n[[actuator]]\n= Production-ready Features\n\nSpring Boot includes a number of additional features to help you monitor and manage your application when you push it to production.\nYou can choose to manage and monitor your application by using HTTP endpoints or with JMX.\nAuditing, health, and metrics gathering can also be automatically applied to your application.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/jmx.adoc",
    "content": "[[actuator.jmx]]\n= Monitoring and Management over JMX\n\nJava Management Extensions (JMX) provide a standard mechanism to monitor and manage applications.\nBy default, this feature is not enabled.\nYou can turn it on by setting the configprop:spring.jmx.enabled[] configuration property to `true`.\nSpring Boot exposes the most suitable javadoc:javax.management.MBeanServer[] as a bean with an ID of `mbeanServer`.\nAny of your beans that are annotated with Spring JMX annotations (`@org.springframework.jmx.export.annotation.ManagedResource`, javadoc:org.springframework.jmx.export.annotation.ManagedAttribute[format=annotation], or javadoc:org.springframework.jmx.export.annotation.ManagedOperation[format=annotation]) are exposed to it.\n\nIf your platform provides a standard javadoc:javax.management.MBeanServer[], Spring Boot uses that and defaults to the VM javadoc:javax.management.MBeanServer[], if necessary.\nIf all that fails, a new javadoc:javax.management.MBeanServer[] is created.\n\nNOTE: `spring.jmx.enabled` affects only the management beans provided by Spring.\nEnabling management beans provided by other libraries (for example {url-log4j2-docs}/jmx.html[Log4j2] or {url-quartz-javadoc}/constant-values.html#org.quartz.impl.StdSchedulerFactory.PROP_SCHED_JMX_EXPORT[Quartz]) is independent.\n\nSee the {code-spring-boot-autoconfigure-src}/jmx/JmxAutoConfiguration.java[`JmxAutoConfiguration`] class for more details.\n\nBy default, Spring Boot also exposes management endpoints as JMX MBeans under the `org.springframework.boot` domain.\nTo take full control over endpoint registration in the JMX domain, consider registering your own javadoc:org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory[] implementation.\n\n\n\n[[actuator.jmx.custom-mbean-names]]\n== Customizing MBean Names\n\nThe name of the MBean is usually generated from the `id` of the endpoint.\nFor example, the `health` endpoint is exposed as `org.springframework.boot:type=Endpoint,name=Health`.\n\nIf your application contains more than one Spring javadoc:org.springframework.context.ApplicationContext[], you may find that names clash.\nTo solve this problem, you can set the configprop:spring.jmx.unique-names[] property to `true` so that MBean names are always unique.\n\nYou can also customize the JMX domain under which endpoints are exposed.\nThe following settings show an example of doing so in `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  jmx:\n    unique-names: true\nmanagement:\n  endpoints:\n    jmx:\n      domain: \"com.example.myapp\"\n----\n\n\n\n[[actuator.jmx.disable-jmx-endpoints]]\n== Disabling JMX Endpoints\n\nIf you do not want to expose endpoints over JMX, you can set the configprop:management.endpoints.jmx.exposure.exclude[] property to `*`, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    jmx:\n      exposure:\n        exclude: \"*\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/loggers.adoc",
    "content": "[[actuator.loggers]]\n= Loggers\n\nSpring Boot Actuator includes the ability to view and configure the log levels of your application at runtime.\nYou can view either the entire list or an individual logger's configuration, which is made up of both the explicitly configured logging level as well as the effective logging level given to it by the logging framework.\nThese levels can be one of:\n\n* `TRACE`\n* `DEBUG`\n* `INFO`\n* `WARN`\n* `ERROR`\n* `FATAL`\n* `OFF`\n* `null`\n\n`null` indicates that there is no explicit configuration.\n\n\n\n[[actuator.loggers.configure]]\n== Configure a Logger\n\nTo configure a given logger, `POST` a partial entity to the resource's URI, as the following example shows:\n\n[source,json]\n----\n{\n\t\"configuredLevel\": \"DEBUG\"\n}\n----\n\nTIP: To \"`reset`\" the specific level of the logger (and use the default configuration instead), you can pass a value of `null` as the `configuredLevel`.\n\n\n\n[[actuator.loggers.opentelemetry]]\n== OpenTelemetry\nBy default, logging via OpenTelemetry is not configured.\nYou have to provide the location of the OpenTelemetry logs endpoint to configure it:\n\n[configprops,yaml]\n----\nmanagement:\n  opentelemetry:\n    logging:\n      export:\n        otlp:\n          endpoint: \"https://otlp.example.com:4318/v1/logs\"\n----\n\nThe `management.opentelemetry.logging.export.*` configuration properties can be used to configure the javadoc:io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor[].\nFor example, to change the export interval to 15 seconds:\n\n[configprops,yaml]\n----\nmanagement:\n  opentelemetry:\n    logging:\n      export:\n        schedule-delay: \"15s\"\n----\n\nThe `management.opentelemetry.logging.limits.*` configuration properties can be used to configure log record limits.\nFor example, to limit the number of attributes per log record to 64 and the maximum attribute value length to 256 characters:\n\n[configprops,yaml]\n----\nmanagement:\n  opentelemetry:\n    logging:\n      limits:\n        max-attributes: 64\n        max-attribute-value-length: 256\n----\n\nIf you need full control, you can register a custom javadoc:io.opentelemetry.sdk.logs.LogLimits[] bean.\n\nNOTE: The OpenTelemetry Logback appender and Log4j appender are not part of Spring Boot.\nFor more details, see the https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-appender-1.0/library[OpenTelemetry Logback appender] or the https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-appender-2.17/library[OpenTelemetry Log4j2 appender] in the https://github.com/open-telemetry/opentelemetry-java-instrumentation[OpenTelemetry Java instrumentation GitHub repository].\n\nTIP: You have to configure the appender in your `logback-spring.xml` or `log4j2-spring.xml` configuration to get OpenTelemetry logging working.\n\nThe `OpenTelemetryAppender` for both Logback and Log4j requires access to an javadoc:io.opentelemetry.api.OpenTelemetry[] instance to function properly.\nThis instance must be set programmatically during application startup, which can be done like this:\n\ninclude-code::OpenTelemetryAppenderInitializer[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/metrics.adoc",
    "content": "[[actuator.metrics]]\n= Metrics\n\nSpring Boot Actuator provides dependency management and auto-configuration for {url-micrometer-site}[Micrometer], an application metrics facade that supports {url-micrometer-docs}[numerous monitoring systems], including:\n\n- xref:actuator/metrics.adoc#actuator.metrics.export.appoptics[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.atlas[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.datadog[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.dynatrace[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.elastic[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.ganglia[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.graphite[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.humio[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.influx[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.jmx[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.kairos[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.newrelic[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.otlp[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.prometheus[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.simple[] (in-memory)\n- xref:actuator/metrics.adoc#actuator.metrics.export.stackdriver[]\n- xref:actuator/metrics.adoc#actuator.metrics.export.statsd[]\n\nTIP: To learn more about Micrometer's capabilities, see its {url-micrometer-docs}[reference documentation], in particular the {url-micrometer-docs-concepts}[concepts section].\n\n\n\n[[actuator.metrics.getting-started]]\n== Getting Started\n\nSpring Boot auto-configures a composite javadoc:io.micrometer.core.instrument.MeterRegistry[] and adds a registry to the composite for each of the supported implementations that it finds on the classpath.\nHaving a dependency on `micrometer-registry-\\{system}` in your runtime classpath is enough for Spring Boot to configure the registry.\n\nMost registries share common features.\nFor instance, you can disable a particular registry even if the Micrometer registry implementation is on the classpath.\nThe following example disables Datadog:\n\n[configprops,yaml]\n----\nmanagement:\n  datadog:\n    metrics:\n      export:\n        enabled: false\n----\n\nYou can also disable all registries unless stated otherwise by the registry-specific property, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  defaults:\n    metrics:\n      export:\n        enabled: false\n----\n\nSpring Boot also adds any auto-configured registries to the global static composite registry on the javadoc:io.micrometer.core.instrument.Metrics[] class, unless you explicitly tell it not to:\n\n[configprops,yaml]\n----\nmanagement:\n  metrics:\n    use-global-registry: false\n----\n\nYou can register any number of javadoc:org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer[] beans to further configure the registry, such as applying common tags, before any meters are registered with the registry:\n\ninclude-code::commontags/MyMeterRegistryConfiguration[]\n\nYou can apply customizations to particular registry implementations by being more specific about the generic type:\n\ninclude-code::specifictype/MyMeterRegistryConfiguration[]\n\nSpring Boot also xref:actuator/metrics.adoc#actuator.metrics.supported[configures built-in instrumentation] that you can control through configuration or dedicated annotation markers.\n\n\n\n[[actuator.metrics.export]]\n== Supported Monitoring Systems\n\nThis section briefly describes each of the supported monitoring systems.\n\n\n\n[[actuator.metrics.export.appoptics]]\n=== AppOptics\n\nBy default, the AppOptics registry periodically pushes metrics to `https://api.appoptics.com/v1/measurements`.\nTo export metrics to SaaS {url-micrometer-docs-implementations}/appOptics[AppOptics], your API token must be provided:\n\n[configprops,yaml]\n----\nmanagement:\n  appoptics:\n    metrics:\n      export:\n        api-token: \"YOUR_TOKEN\"\n----\n\n\n\n[[actuator.metrics.export.atlas]]\n=== Atlas\n\nBy default, metrics are exported to {url-micrometer-docs-implementations}/atlas[Atlas] running on your local machine.\nYou can provide the location of the https://github.com/Netflix/atlas[Atlas server]:\n\n[configprops,yaml]\n----\nmanagement:\n  atlas:\n    metrics:\n      export:\n        uri: \"https://atlas.example.com:7101/api/v1/publish\"\n----\n\n\n\n[[actuator.metrics.export.datadog]]\n=== Datadog\n\nA Datadog registry periodically pushes metrics to https://www.datadoghq.com[datadoghq].\nTo export metrics to {url-micrometer-docs-implementations}/datadog[Datadog], you must provide your API key:\n\n[configprops,yaml]\n----\nmanagement:\n  datadog:\n    metrics:\n      export:\n        api-key: \"YOUR_KEY\"\n----\n\nIf you additionally provide an application key (optional), then metadata such as meter descriptions, types, and base units will also be exported:\n\n[configprops,yaml]\n----\nmanagement:\n  datadog:\n    metrics:\n      export:\n        api-key: \"YOUR_API_KEY\"\n        application-key: \"YOUR_APPLICATION_KEY\"\n----\n\nBy default, metrics are sent to the Datadog US https://docs.datadoghq.com/getting_started/site[site] (`https://api.datadoghq.com`).\nIf your Datadog project is hosted on one of the other sites, or you need to send metrics through a proxy, configure the URI accordingly:\n\n[configprops,yaml]\n----\nmanagement:\n  datadog:\n    metrics:\n      export:\n        uri: \"https://api.datadoghq.eu\"\n----\n\nYou can also change the interval at which metrics are sent to Datadog:\n\n[configprops,yaml]\n----\nmanagement:\n  datadog:\n    metrics:\n      export:\n        step: \"30s\"\n----\n\n\n\n[[actuator.metrics.export.dynatrace]]\n=== Dynatrace\n\nDynatrace offers two metrics ingest APIs, both of which are implemented for {url-micrometer-docs-implementations}/dynatrace[Micrometer].\nYou can find the Dynatrace documentation on Micrometer metrics ingest {url-dynatrace-docs-shortlink}/micrometer-metrics-ingest[here].\n\nConfiguration properties in the `v1` namespace apply only when exporting to the {url-dynatrace-docs-shortlink}/api-metrics[Timeseries v1 API].\nSupport for the V1 API is deprecated.\n\nConfiguration properties in the `v2` namespace apply only when exporting to the {url-dynatrace-docs-shortlink}/api-metrics-v2-post-datapoints[Metrics v2 API].\n\nNote that this integration can export only to either the `v1` or `v2` version of the API at a time, with `v2` being strongly recommended due to the deprecation of the v1 API.\nIf the `device-id` (required for v1 but not used in v2) is set in the `v1` namespace, metrics are exported to the `v1` endpoint.\nOtherwise, `v2` is assumed.\n\n\n\n[[actuator.metrics.export.dynatrace.v2-api]]\n==== v2 API\n\nYou can use the v2 API in two ways.\n\n\n\n[[actuator.metrics.export.dynatrace.v2-api.auto-config]]\n===== Auto-configuration\n\nDynatrace auto-configuration is available for hosts that are monitored by the OneAgent or by the Dynatrace Operator for Kubernetes.\n\n**Local OneAgent:** If a OneAgent is running on the host, metrics are automatically exported to the {url-dynatrace-docs-shortlink}/local-api[local OneAgent ingest endpoint].\nThe ingest endpoint forwards the metrics to the Dynatrace backend.\n\n**Dynatrace Kubernetes Operator:** When running in Kubernetes with the Dynatrace Operator installed, the registry will automatically pick up your endpoint URI and API token from the operator instead.\n\nThis is the default behavior and requires no special setup beyond a dependency on `io.micrometer:micrometer-registry-dynatrace`.\n\n\n\n[[actuator.metrics.export.dynatrace.v2-api.manual-config]]\n===== Manual Configuration\n\nIf no auto-configuration is available, the endpoint of the {url-dynatrace-docs-shortlink}/api-metrics-v2-post-datapoints[Metrics v2 API] and an API token are required.\nThe {url-dynatrace-docs-shortlink}/api-authentication[API token] must have the \"`Ingest metrics`\" (`metrics.ingest`) permission set.\nWe recommend limiting the scope of the token to this one permission.\nYou must ensure that the endpoint URI contains the path (for example, `/api/v2/metrics/ingest`):\n\nThe URL of the Metrics API v2 ingest endpoint is different according to your deployment option:\n\n* SaaS: `+https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest+`\n* Managed deployments: `+https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest+`\n\nThe example below configures metrics export using the `example` environment id:\n\n[configprops,yaml]\n----\nmanagement:\n  dynatrace:\n    metrics:\n      export:\n        uri: \"https://example.live.dynatrace.com/api/v2/metrics/ingest\"\n        api-token: \"YOUR_TOKEN\"\n----\n\nWhen using the Dynatrace v2 API, the following optional features are available (more details can be found in the {url-dynatrace-docs-shortlink}/micrometer-metrics-ingest#dt-configuration-properties[Dynatrace documentation]):\n\n* Metric key prefix: Sets a prefix that is prepended to all exported metric keys.\n* Enrich with Dynatrace metadata: If a OneAgent or Dynatrace operator is running, enrich metrics with additional metadata (for example, about the host, process, or pod).\n* Default dimensions: Specify key-value pairs that are added to all exported metrics.\nIf tags with the same key are specified with Micrometer, they overwrite the default dimensions.\n* Use Dynatrace Summary instruments: In some cases the Micrometer Dynatrace registry created metrics that were rejected.\nIn Micrometer 1.9.x, this was fixed by introducing Dynatrace-specific summary instruments.\nSetting this toggle to `false` forces Micrometer to fall back to the behavior that was the default before 1.9.x.\nIt should only be used when encountering problems while migrating from Micrometer 1.8.x to 1.9.x.\n* Export meter metadata: Starting from Micrometer 1.12.0, the Dynatrace exporter will also export meter metadata, such as unit and description by default.\nUse the `export-meter-metadata` toggle to turn this feature off.\n\nIt is possible to not specify a URI and API token, as shown in the following example.\nIn this scenario, the automatically configured endpoint is used:\n\n[configprops,yaml]\n----\nmanagement:\n  dynatrace:\n    metrics:\n      export:\n        # Specify uri and api-token here if not using the local OneAgent endpoint.\n        v2:\n          metric-key-prefix: \"your.key.prefix\"\n          enrich-with-dynatrace-metadata: true\n          default-dimensions:\n            key1: \"value1\"\n            key2: \"value2\"\n          use-dynatrace-summary-instruments: true # (default: true)\n          export-meter-metadata: true             # (default: true)\n----\n\n\n\n[[actuator.metrics.export.dynatrace.v1-api]]\n==== v1 API (Deprecated)\n\nThe Dynatrace v1 API metrics registry pushes metrics to the configured URI periodically by using the {url-dynatrace-docs-shortlink}/api-metrics[Timeseries v1 API].\nFor backwards-compatibility with existing setups, when `device-id` is set (required for v1, but not used in v2), metrics are exported to the Timeseries v1 endpoint.\nTo export metrics to {url-micrometer-docs-implementations}/dynatrace[Dynatrace], your API token, device ID, and URI must be provided:\n\n[configprops%novalidate,yaml]\n----\nmanagement:\n  dynatrace:\n    metrics:\n      export:\n        uri: \"https://{your-environment-id}.live.dynatrace.com\"\n        api-token: \"YOUR_TOKEN\"\n        v1:\n          device-id: \"YOUR_DEVICE_ID\"\n----\n\nFor the v1 API, you must specify the base environment URI without a path, as the v1 endpoint path is added automatically.\n\n\n\n[[actuator.metrics.export.dynatrace.version-independent-settings]]\n==== Version-independent Settings\n\nIn addition to the API endpoint and token, you can also change the interval at which metrics are sent to Dynatrace.\nThe default export interval is `60s`.\nThe following example sets the export interval to 30 seconds:\n\n[configprops,yaml]\n----\nmanagement:\n  dynatrace:\n    metrics:\n      export:\n        step: \"30s\"\n----\n\nYou can find more information on how to set up the Dynatrace exporter for Micrometer in the {url-micrometer-docs-implementations}/dynatrace[Micrometer documentation] and the {url-dynatrace-docs-shortlink}/micrometer-metrics-ingest[Dynatrace documentation].\n\n\n\n[[actuator.metrics.export.elastic]]\n=== Elastic\n\nBy default, metrics are exported to {url-micrometer-docs-implementations}/elastic[Elastic] running on your local machine.\nYou can provide the location of the Elastic server to use by using the following property:\n\n[configprops,yaml]\n----\nmanagement:\n  elastic:\n    metrics:\n      export:\n        host: \"https://elastic.example.com:8086\"\n----\n\n\n\n[[actuator.metrics.export.ganglia]]\n=== Ganglia\n\nBy default, metrics are exported to {url-micrometer-docs-implementations}/ganglia[Ganglia] running on your local machine.\nYou can provide the http://ganglia.sourceforge.net[Ganglia server] host and port, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  ganglia:\n    metrics:\n      export:\n        host: \"ganglia.example.com\"\n        port: 9649\n----\n\n\n\n[[actuator.metrics.export.graphite]]\n=== Graphite\n\nBy default, metrics are exported to {url-micrometer-docs-implementations}/graphite[Graphite] running on your local machine.\nYou can provide the https://graphiteapp.org[Graphite server] host and port, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  graphite:\n    metrics:\n      export:\n         host: \"graphite.example.com\"\n         port: 9004\n----\n\nMicrometer provides a default javadoc:io.micrometer.core.instrument.util.HierarchicalNameMapper[] that governs how a dimensional meter ID is {url-micrometer-docs-implementations}/graphite#_hierarchical_name_mapping[mapped to flat hierarchical names].\n\n[TIP]\n====\nTo take control over this behavior, define your javadoc:io.micrometer.graphite.GraphiteMeterRegistry[] and supply your own javadoc:io.micrometer.core.instrument.util.HierarchicalNameMapper[].\nAuto-configured javadoc:io.micrometer.graphite.GraphiteConfig[] and javadoc:io.micrometer.core.instrument.Clock[] beans are provided unless you define your own:\n\ninclude-code::MyGraphiteConfiguration[]\n====\n\n\n\n[[actuator.metrics.export.humio]]\n=== Humio\n\nBy default, the Humio registry periodically pushes metrics to https://cloud.humio.com.\nTo export metrics to SaaS {url-micrometer-docs-implementations}/humio[Humio], you must provide your API token:\n\n[configprops,yaml]\n----\nmanagement:\n  humio:\n    metrics:\n      export:\n        api-token: \"YOUR_TOKEN\"\n----\n\nYou should also configure one or more tags to identify the data source to which metrics are pushed:\n\n[configprops,yaml]\n----\nmanagement:\n  humio:\n    metrics:\n      export:\n        tags:\n          alpha: \"a\"\n          bravo: \"b\"\n----\n\n\n\n[[actuator.metrics.export.influx]]\n=== Influx\n\nBy default, metrics are exported to an {url-micrometer-docs-implementations}/influx[Influx] v1 instance running on your local machine with the default configuration.\nTo export metrics to InfluxDB v2, configure the `org`, `bucket`, and authentication `token` for writing metrics.\nYou can provide the location of the https://www.influxdata.com[Influx server] to use by using:\n\n[configprops,yaml]\n----\nmanagement:\n  influx:\n    metrics:\n      export:\n        uri: \"https://influx.example.com:8086\"\n----\n\n\n\n[[actuator.metrics.export.jmx]]\n=== JMX\n\nMicrometer provides a hierarchical mapping to {url-micrometer-docs-implementations}/jmx[JMX], primarily as a cheap and portable way to view metrics locally.\nBy default, metrics are exported to the `metrics` JMX domain.\nYou can provide the domain to use by using:\n\n[configprops,yaml]\n----\nmanagement:\n  jmx:\n    metrics:\n      export:\n        domain: \"com.example.app.metrics\"\n----\n\nMicrometer provides a default javadoc:io.micrometer.core.instrument.util.HierarchicalNameMapper[] that governs how a dimensional meter ID is {url-micrometer-docs-implementations}/jmx#_hierarchical_name_mapping[mapped to flat hierarchical names].\n\n[TIP]\n====\nTo take control over this behavior, define your javadoc:io.micrometer.jmx.JmxMeterRegistry[] and supply your own javadoc:io.micrometer.core.instrument.util.HierarchicalNameMapper[].\nAuto-configured javadoc:io.micrometer.jmx.JmxConfig[] and javadoc:io.micrometer.core.instrument.Clock[] beans are provided unless you define your own:\n\ninclude-code::MyJmxConfiguration[]\n====\n\n\n\n[[actuator.metrics.export.kairos]]\n=== KairosDB\n\nBy default, metrics are exported to {url-micrometer-docs-implementations}/kairos[KairosDB] running on your local machine.\nYou can provide the location of the https://kairosdb.github.io/[KairosDB server] to use by using:\n\n[configprops,yaml]\n----\nmanagement:\n  kairos:\n    metrics:\n      export:\n        uri: \"https://kairosdb.example.com:8080/api/v1/datapoints\"\n----\n\n\n\n[[actuator.metrics.export.newrelic]]\n=== New Relic\n\nA New Relic registry periodically pushes metrics to {url-micrometer-docs-implementations}/new-relic[New Relic].\nTo export metrics to https://newrelic.com[New Relic], you must provide your API key and account ID:\n\n[configprops,yaml]\n----\nmanagement:\n  newrelic:\n    metrics:\n      export:\n        api-key: \"YOUR_KEY\"\n        account-id: \"YOUR_ACCOUNT_ID\"\n----\n\nYou can also change the interval at which metrics are sent to New Relic:\n\n[configprops,yaml]\n----\nmanagement:\n  newrelic:\n    metrics:\n      export:\n        step: \"30s\"\n----\n\nBy default, metrics are published through REST calls, but you can also use the Java Agent API if you have it on the classpath:\n\n[configprops,yaml]\n----\nmanagement:\n  newrelic:\n    metrics:\n      export:\n        client-provider-type: \"insights-agent\"\n----\n\nFinally, you can take full control by defining your own javadoc:io.micrometer.newrelic.NewRelicClientProvider[] bean.\n\n\n\n[[actuator.metrics.export.otlp]]\n=== OTLP\n\nBy default, metrics are exported over the {url-micrometer-docs-implementations}/otlp[OpenTelemetry protocol (OTLP)] to a consumer running on your local machine.\nTo export to another location, provide the location of the https://opentelemetry.io/[OTLP metrics endpoint] using configprop:management.otlp.metrics.export.url[]:\n\n[configprops,yaml]\n----\nmanagement:\n  otlp:\n    metrics:\n      export:\n        url: \"https://otlp.example.com:4318/v1/metrics\"\n----\n\nCustom headers, for example for authentication, can also be provided using configprop:management.otlp.metrics.export.headers.*[] properties.\n\nIf an `OtlpMetricsSender` bean is available, it will be configured on the `OtlpMeterRegistry` that Spring Boot auto-configures.\n\nhttps://opentelemetry.io/docs/specs/otel/metrics/data-model/#exemplars[OTLP Exemplars] are also supported.\nTo enable this feature, an javadoc:io.micrometer.registry.otlp.ExemplarContextProvider[] bean should be present.\nIf you use xref:actuator/tracing.adoc[Micrometer Tracing], this will be auto-configured for you.\nBy default, only sampled traces are included as exemplars.\nYou can control this behavior using the configprop:management.tracing.exemplars.include[] property.\n\n\n\n[[actuator.metrics.export.prometheus]]\n=== Prometheus\n\n{url-micrometer-docs-implementations}/prometheus[Prometheus] expects to scrape or poll individual application instances for metrics.\nSpring Boot provides an actuator endpoint at `/actuator/prometheus` to present a https://prometheus.io[Prometheus scrape] with the appropriate format.\n\nTIP: By default, the endpoint is not available and must be exposed. See xref:actuator/endpoints.adoc#actuator.endpoints.exposing[exposing endpoints] for more details.\n\nThe following example `scrape_config` adds to `prometheus.yml`:\n\n[source,yaml]\n----\nscrape_configs:\n- job_name: \"spring\"\n  metrics_path: \"/actuator/prometheus\"\n  static_configs:\n  - targets: [\"HOST:PORT\"]\n----\n\nhttps://prometheus.io/docs/prometheus/latest/feature_flags/#exemplars-storage[Prometheus Exemplars] are also supported.\nTo enable this feature, a javadoc:io.prometheus.metrics.tracer.common.SpanContext[] bean should be present.\nIf you're using the deprecated Prometheus simpleclient support and want to enable that feature, a javadoc:io.prometheus.client.exemplars.tracer.common.SpanContextSupplier[] bean should be present.\nIf you use {url-micrometer-tracing-docs}[Micrometer Tracing], this will be auto-configured for you, but you can always create your own if you want.\nBy default, only sampled traces are included as exemplars.\nYou can control this behavior using the configprop:management.tracing.exemplars.include[] property.\nThe value `all` is not supported with Prometheus.\nPlease check the https://prometheus.io/docs/prometheus/latest/feature_flags/#exemplars-storage[Prometheus Docs], since this feature needs to be explicitly enabled on Prometheus' side, and it is only supported using the https://github.com/OpenObservability/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#exemplars[OpenMetrics] format.\n\nFor ephemeral or batch jobs that may not exist long enough to be scraped, you can use https://github.com/prometheus/pushgateway[Prometheus Pushgateway] support to expose the metrics to Prometheus.\n\nTo enable Prometheus Pushgateway support, add the following dependency to your project:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>io.prometheus</groupId>\n\t<artifactId>prometheus-metrics-exporter-pushgateway</artifactId>\n</dependency>\n----\n\nWhen the Prometheus Pushgateway dependency is present on the classpath and the configprop:management.prometheus.metrics.export.pushgateway.enabled[] property is set to `true`, a javadoc:org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager[] bean is auto-configured.\nThis manages the pushing of metrics to a Prometheus Pushgateway.\n\nYou can tune the javadoc:org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager[] by using properties under `management.prometheus.metrics.export.pushgateway`.\nFor advanced configuration, you can also provide your own javadoc:org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager[] bean.\n\n\n\n[[actuator.metrics.export.simple]]\n=== Simple\n\nMicrometer ships with a simple, in-memory backend that is automatically used as a fallback if no other registry is configured.\nThis lets you see what metrics are collected in the xref:actuator/metrics.adoc#actuator.metrics.endpoint[metrics endpoint].\n\nThe in-memory backend disables itself as soon as you use any other available backend.\nYou can also disable it explicitly:\n\n[configprops,yaml]\n----\nmanagement:\n  simple:\n    metrics:\n      export:\n        enabled: false\n----\n\n\n\n[[actuator.metrics.export.stackdriver]]\n=== Stackdriver\n\nThe Stackdriver registry periodically pushes metrics to https://cloud.google.com/stackdriver/[Stackdriver].\nTo export metrics to SaaS {url-micrometer-docs-implementations}/stackdriver[Stackdriver], you must provide your Google Cloud project ID:\n\n[configprops,yaml]\n----\nmanagement:\n  stackdriver:\n    metrics:\n      export:\n        project-id: \"my-project\"\n----\n\nYou can also change the interval at which metrics are sent to Stackdriver:\n\n[configprops,yaml]\n----\nmanagement:\n  stackdriver:\n    metrics:\n      export:\n        step: \"30s\"\n----\n\n\n\n[[actuator.metrics.export.statsd]]\n=== StatsD\n\nThe StatsD registry eagerly pushes metrics over UDP to a StatsD agent.\nBy default, metrics are exported to a {url-micrometer-docs-implementations}/statsD[StatsD] agent running on your local machine.\nYou can provide the StatsD agent host, port, and protocol to use by using:\n\n[configprops,yaml]\n----\nmanagement:\n  statsd:\n    metrics:\n      export:\n        host: \"statsd.example.com\"\n        port: 9125\n        protocol: \"udp\"\n----\n\nYou can also change the StatsD line protocol to use (it defaults to Datadog):\n\n[configprops,yaml]\n----\nmanagement:\n  statsd:\n    metrics:\n      export:\n        flavor: \"etsy\"\n----\n\n\n\n[[actuator.metrics.supported]]\n== Supported Metrics and Meters\n\nSpring Boot provides automatic meter registration for a wide variety of technologies.\nIn most situations, the defaults provide sensible metrics that can be published to any of the supported monitoring systems.\n\n\n\n[[actuator.metrics.supported.jvm]]\n=== JVM Metrics\n\nAuto-configuration enables JVM Metrics by using core Micrometer classes.\nJVM metrics are published under the `jvm.` meter name.\n\nThe following JVM metrics are provided:\n\n* Various memory and buffer pool details\n* Statistics related to garbage collection\n* Thread utilization\n* https://docs.micrometer.io/micrometer/reference/reference/jvm.html#_java_21_metrics[Virtual threads statistics] (for this, `io.micrometer:micrometer-java21` has to be on the classpath)\n* The number of classes loaded and unloaded\n* JVM version information\n* JIT compilation time\n\n\n\n[[actuator.metrics.supported.system]]\n=== System Metrics\n\nAuto-configuration enables system metrics by using core Micrometer classes.\nSystem metrics are published under the `system.`, `process.`, and `disk.` meter names.\n\nThe following system metrics are provided:\n\n* CPU metrics\n* File descriptor metrics\n* Uptime metrics (both the amount of time the application has been running and a fixed gauge of the absolute start time)\n* Disk space available\n\n\n\n[[actuator.metrics.supported.application-startup]]\n=== Application Startup Metrics\n\nAuto-configuration exposes application startup time metrics:\n\n* `application.started.time`: time taken to start the application.\n* `application.ready.time`: time taken for the application to be ready to service requests.\n\nMetrics are tagged by the fully qualified name of the application class.\n\n\n\n[[actuator.metrics.supported.logger]]\n=== Logger Metrics\n\nAuto-configuration enables the event metrics for both Logback and Log4J2.\nThe details are published under the `log4j2.events.` or `logback.events.` meter names.\n\n\n\n[[actuator.metrics.supported.tasks]]\n=== Task Execution and Scheduling Metrics\n\nAuto-configuration enables the instrumentation of all available javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] and javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler[] beans, as long as the underling javadoc:java.util.concurrent.ThreadPoolExecutor[] is available.\nMetrics are tagged by the name of the executor, which is derived from the bean name.\n\n\n\n[[actuator.metrics.supported.jms]]\n=== JMS Metrics\n\nAuto-configuration enables the instrumentation of all available javadoc:org.springframework.jms.core.JmsTemplate[] beans and javadoc:org.springframework.jms.annotation.JmsListener[format=annotation] annotated methods.\nThis will produce `\"jms.message.publish\"` and `\"jms.message.process\"` metrics respectively.\nSee the {url-spring-framework-docs}/integration/observability.html#observability.jms[Spring Framework reference documentation for more information on produced observations].\n\nNOTE: javadoc:org.springframework.jms.core.JmsClient[] and javadoc:org.springframework.jms.core.JmsMessagingTemplate[] that uses a javadoc:org.springframework.jms.core.JmsTemplate[] bean are also instrumented.\n\n\n[[actuator.metrics.supported.spring-mvc]]\n=== Spring MVC Metrics\n\nAuto-configuration enables the instrumentation of all requests handled by Spring MVC controllers and functional handlers.\nBy default, metrics are generated with the name, `http.server.requests`.\nYou can customize the name by setting the configprop:management.observations.http.server.requests.name[] property.\n\nSee the {url-spring-framework-docs}/integration/observability.html#observability.http-server.servlet[Spring Framework reference documentation for more information on produced observations].\n\nTo add to the default tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that extends javadoc:org.springframework.http.server.observation.DefaultServerRequestObservationConvention[] from the `org.springframework.http.server.observation` package.\nTo replace the default tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:org.springframework.http.server.observation.ServerRequestObservationConvention[].\n\nTIP: In some cases, exceptions handled in web controllers are not recorded as request metrics tags.\nApplications can opt in and record exceptions by xref:web/servlet.adoc#web.servlet.spring-mvc.error-handling[setting handled exceptions as request attributes].\n\nBy default, all requests are handled.\nTo customize the filter, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements `FilterRegistrationBean<ServerHttpObservationFilter>`.\n\n\n\n[[actuator.metrics.supported.spring-webflux]]\n=== Spring WebFlux Metrics\n\nAuto-configuration enables the instrumentation of all requests handled by Spring WebFlux controllers and functional handlers.\nBy default, metrics are generated with the name, `http.server.requests`.\nYou can customize the name by setting the configprop:management.observations.http.server.requests.name[] property.\n\nSee the {url-spring-framework-docs}/integration/observability.html#observability.http-server.reactive[Spring Framework reference documentation for more information on produced observations].\n\nTo add to the default tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that extends javadoc:org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention[] from the `org.springframework.http.server.reactive.observation` package.\nTo replace the default tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:org.springframework.http.server.reactive.observation.ServerRequestObservationConvention[].\n\nTIP: In some cases, exceptions handled in controllers and handler functions are not recorded as request metrics tags.\nApplications can opt in and record exceptions by xref:web/reactive.adoc#web.reactive.webflux.error-handling[setting handled exceptions as request attributes].\n\n\n\n[[actuator.metrics.supported.jersey]]\n=== Jersey Server Metrics\n\nAuto-configuration enables the instrumentation of all requests handled by the Jersey JAX-RS implementation.\nBy default, metrics are generated with the name, `http.server.requests`.\nYou can customize the name by setting the configprop:management.observations.http.server.requests.name[] property.\n\nBy default, Jersey server metrics are tagged with the following information:\n\n|===\n| Tag | Description\n\n| `exception`\n| The simple class name of any exception that was thrown while handling the request.\n\n| `method`\n| The request's method (for example, `GET` or `POST`)\n\n| `outcome`\n| The request's outcome, based on the status code of the response.\n  1xx is `INFORMATIONAL`, 2xx is `SUCCESS`, 3xx is `REDIRECTION`, 4xx is `CLIENT_ERROR`, and 5xx is `SERVER_ERROR`\n\n| `status`\n| The response's HTTP status code (for example, `200` or `500`)\n\n| `uri`\n| The request's URI template prior to variable substitution, if possible (for example, `/api/person/\\{id}`)\n|===\n\nTo customize the tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:io.micrometer.core.instrument.binder.jersey.server.JerseyObservationConvention[].\n\n\n\n[[actuator.metrics.supported.ssl]]\n=== SSL Bundle Metrics\n\nSpring Boot Actuator publishes expiry metrics about SSL bundles.\nThe metric `ssl.chain.expiry` gauges the expiry date of each certificate chain in seconds.\nThis number will be negative if the chain has already expired.\nThis metric is tagged with the following information:\n\n|===\n| Tag | Description\n\n| `bundle`\n| The name of the bundle which contains the certificate chain\n\n| `certificate`\n| The serial number (in hex format) of the certificate which is the soonest to expire in the chain\n\n| `chain`\n| The name of the certificate chain.\n|===\n\n\n\n[[actuator.metrics.supported.http-clients]]\n=== HTTP Client Metrics\n\nSpring Boot Actuator manages the instrumentation of javadoc:org.springframework.web.client.RestTemplate[], javadoc:org.springframework.web.reactive.function.client.WebClient[] and javadoc:org.springframework.web.client.RestClient[].\nFor that, you have to inject the auto-configured builder and use it to create instances:\n\n* javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] for javadoc:org.springframework.web.client.RestTemplate[]\n* javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] for javadoc:org.springframework.web.reactive.function.client.WebClient[]\n* javadoc:org.springframework.web.client.RestClient$Builder[] for javadoc:org.springframework.web.client.RestClient[]\n\nYou can also manually apply the customizers responsible for this instrumentation, namely javadoc:org.springframework.boot.restclient.observation.ObservationRestTemplateCustomizer[], javadoc:org.springframework.boot.webclient.observation.ObservationWebClientCustomizer[] and javadoc:org.springframework.boot.restclient.observation.ObservationRestClientCustomizer[].\n\nBy default, metrics are generated with the name, `http.client.requests`.\nYou can customize the name by setting the configprop:management.observations.http.client.requests.name[] property.\n\nSee the {url-spring-framework-docs}/integration/observability.html#observability.http-client[Spring Framework reference documentation for more information on produced observations].\n\nTo customize the tags when using javadoc:org.springframework.web.client.RestTemplate[] or javadoc:org.springframework.web.client.RestClient[], provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:org.springframework.http.client.observation.ClientRequestObservationConvention[] from the `org.springframework.http.client.observation` package.\nTo customize the tags when using javadoc:org.springframework.web.reactive.function.client.WebClient[], provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:org.springframework.web.reactive.function.client.ClientRequestObservationConvention[] from the `org.springframework.web.reactive.function.client` package.\n\n\n\n[[actuator.metrics.supported.tomcat]]\n=== Tomcat Metrics\n\nAuto-configuration enables the instrumentation of Tomcat only when an MBean javadoc:org.apache.tomcat.util.modeler.Registry[] is enabled.\nBy default, the MBean registry is disabled, but you can enable it by setting configprop:server.tomcat.mbeanregistry.enabled[] to `true`.\n\nTomcat metrics are published under the `tomcat.` meter name.\n\n\n\n[[actuator.metrics.supported.cache]]\n=== Cache Metrics\n\nAuto-configuration enables the instrumentation of all available javadoc:org.springframework.cache.Cache[] instances on startup, with metrics prefixed with `cache`.\nCache instrumentation is standardized for a basic set of metrics.\nAdditional, cache-specific metrics are also available.\n\nThe following cache libraries are supported:\n\n* Cache2k\n* Caffeine\n* Hazelcast\n* Any compliant JCache (JSR-107) implementation\n* Redis\n\nWARNING: Metrics should be enabled for the auto-configuration to pick them up.\nRefer to the documentation of the cache library you are using for more details.\n\nMetrics are tagged by the name of the cache and by the name of the javadoc:org.springframework.cache.CacheManager[], which is derived from the bean name.\n\nNOTE: Only caches that are configured on startup are bound to the registry.\nFor caches not defined in the cache’s configuration, such as caches created on the fly or programmatically after the startup phase, an explicit registration is required.\nA javadoc:org.springframework.boot.cache.metrics.CacheMetricsRegistrar[] bean is made available to make that process easier.\n\n\n\n[[actuator.metrics.supported.spring-batch]]\n=== Spring Batch Metrics\n\nSee the {url-spring-batch-docs}/monitoring-and-metrics.html[Spring Batch reference documentation].\n\n\n\n[[actuator.metrics.supported.spring-graphql]]\n=== Spring GraphQL Metrics\n\nSee the {url-spring-graphql-docs}/observability.html[Spring GraphQL reference documentation].\n\n\n\n[[actuator.metrics.supported.jdbc]]\n=== DataSource Metrics\n\nAuto-configuration enables the instrumentation of all available javadoc:javax.sql.DataSource[] objects with metrics prefixed with `jdbc.connections`.\nData source instrumentation results in gauges that represent the currently active, idle, maximum allowed, and minimum allowed connections in the pool.\n\nMetrics are also tagged by the name of the javadoc:javax.sql.DataSource[] computed based on the bean name.\n\nTIP: By default, Spring Boot provides metadata for all supported data sources.\nYou can add additional javadoc:org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider[] beans if your favorite data source is not supported.\nSee javadoc:org.springframework.boot.jdbc.autoconfigure.DataSourcePoolMetadataProvidersConfiguration[] for examples.\n\nAlso, Hikari-specific metrics are exposed with a `hikaricp` prefix.\nEach metric is tagged by the name of the pool (you can control it with `spring.datasource.name`).\n\n\n\n[[actuator.metrics.supported.hibernate]]\n=== Hibernate Metrics\n\nIf `org.hibernate.orm:hibernate-micrometer` is on the classpath, all available Hibernate javadoc:jakarta.persistence.EntityManagerFactory[] instances that have statistics enabled are instrumented with a metric named `hibernate`.\n\nMetrics are also tagged by the name of the javadoc:jakarta.persistence.EntityManagerFactory[], which is derived from the bean name.\n\nTo enable statistics, the standard JPA property `hibernate.generate_statistics` must be set to `true`.\nYou can enable that on the auto-configured javadoc:jakarta.persistence.EntityManagerFactory[]:\n\n[configprops,yaml]\n----\nspring:\n  jpa:\n    properties:\n      \"[hibernate.generate_statistics]\": true\n----\n\n\n\n[[actuator.metrics.supported.spring-data-repository]]\n=== Spring Data Repository Metrics\n\nAuto-configuration enables the instrumentation of all Spring Data javadoc:org.springframework.data.repository.Repository[] method invocations.\nBy default, metrics are generated with the name, `spring.data.repository.invocations`.\nYou can customize the name by setting the configprop:management.metrics.data.repository.metric-name[] property.\n\nThe javadoc:io.micrometer.core.annotation.Timed[format=annotation] annotation from the `io.micrometer.core.annotation` package is supported on javadoc:org.springframework.data.repository.Repository[] interfaces and methods.\nIf you do not want to record metrics for all javadoc:org.springframework.data.repository.Repository[] invocations, you can set configprop:management.metrics.data.repository.autotime.enabled[] to `false` and exclusively use javadoc:io.micrometer.core.annotation.Timed[format=annotation] annotations instead.\n\nNOTE: A javadoc:io.micrometer.core.annotation.Timed[format=annotation] annotation with `longTask = true` enables a long task timer for the method.\nLong task timers require a separate metric name and can be stacked with a short task timer.\n\nBy default, repository invocation related metrics are tagged with the following information:\n\n|===\n| Tag | Description\n\n| `repository`\n| The simple class name of the source javadoc:org.springframework.data.repository.Repository[].\n\n| `method`\n| The name of the javadoc:org.springframework.data.repository.Repository[] method that was invoked.\n\n| `state`\n| The result state (`SUCCESS`, `ERROR`, `CANCELED`, or `RUNNING`).\n\n| `exception`\n| The simple class name of any exception that was thrown from the invocation.\n|===\n\nTo replace the default tags, provide a javadoc:org.springframework.context.annotation.Bean[format=annotation] that implements javadoc:org.springframework.boot.data.metrics.RepositoryTagsProvider[].\n\n\n\n[[actuator.metrics.supported.rabbitmq]]\n=== RabbitMQ Metrics\n\nAuto-configuration enables the instrumentation of all available RabbitMQ connection factories with a metric named `rabbitmq`.\n\n\n\n[[actuator.metrics.supported.spring-integration]]\n=== Spring Integration Metrics\n\nSpring Integration automatically provides {url-spring-integration-docs}/metrics.html#micrometer-integration[Micrometer support] whenever a javadoc:io.micrometer.core.instrument.MeterRegistry[] bean is available.\nMetrics are published under the `spring.integration.` meter name.\n\n\n\n[[actuator.metrics.supported.kafka]]\n=== Kafka Metrics\n\nAuto-configuration registers a javadoc:org.springframework.kafka.core.MicrometerConsumerListener[] and javadoc:org.springframework.kafka.core.MicrometerProducerListener[] for the auto-configured consumer factory and producer factory, respectively.\nIt also registers a javadoc:org.springframework.kafka.streams.KafkaStreamsMicrometerListener[] for javadoc:org.springframework.kafka.config.StreamsBuilderFactoryBean[].\nFor more detail, see the {url-spring-kafka-docs}/kafka/micrometer.html#micrometer-native[Micrometer Native Metrics] section of the Spring Kafka documentation.\n\n\n\n[[actuator.metrics.supported.mongodb]]\n=== MongoDB Metrics\n\nThis section briefly describes the available metrics for MongoDB.\n\n\n\n[[actuator.metrics.supported.mongodb.command]]\n==== MongoDB Command Metrics\n\nAuto-configuration registers a javadoc:io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener[] with the auto-configured javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[].\n\nA timer metric named `mongodb.driver.commands` is created for each command issued to the underlying MongoDB driver.\nEach metric is tagged with the following information by default:\n|===\n| Tag | Description\n\n| `command`\n| The name of the command issued.\n\n| `cluster.id`\n| The identifier of the cluster to which the command was sent.\n\n| `server.address`\n| The address of the server to which the command was sent.\n\n| `status`\n| The outcome of the command (`SUCCESS` or `FAILED`).\n|===\n\nTo replace the default metric tags, define a javadoc:io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider[] bean, as the following example shows:\n\ninclude-code::MyCommandTagsProviderConfiguration[]\n\nTo disable the auto-configured command metrics, set the following property:\n\n[configprops,yaml]\n----\nmanagement:\n  metrics:\n    mongodb:\n      command:\n        enabled: false\n----\n\n\n\n[[actuator.metrics.supported.mongodb.connection-pool]]\n==== MongoDB Connection Pool Metrics\n\nAuto-configuration registers a javadoc:io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener[] with the auto-configured javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[].\n\nThe following gauge metrics are created for the connection pool:\n\n* `mongodb.driver.pool.size` reports the current size of the connection pool, including idle and in-use members.\n* `mongodb.driver.pool.checkedout` reports the count of connections that are currently in use.\n* `mongodb.driver.pool.waitqueuesize` reports the current size of the wait queue for a connection from the pool.\n\nEach metric is tagged with the following information by default:\n|===\n| Tag | Description\n\n| `cluster.id`\n| The identifier of the cluster to which the connection pool corresponds.\n\n| `server.address`\n| The address of the server to which the connection pool corresponds.\n|===\n\nTo replace the default metric tags, define a javadoc:io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider[] bean:\n\ninclude-code::MyConnectionPoolTagsProviderConfiguration[]\n\nTo disable the auto-configured connection pool metrics, set the following property:\n\n[configprops,yaml]\n----\nmanagement:\n  metrics:\n    mongodb:\n      connectionpool:\n        enabled: false\n----\n\n\n\n[[actuator.metrics.supported.neo4j]]\n=== Neo4j Metrics\n\nAuto-configuration registers a javadoc:org.neo4j.driver.observation.micrometer.MicrometerObservationProvider[] for the auto-configured javadoc:org.neo4j.driver.Driver[].\n\nTo override this behavior, you can register a javadoc:org.springframework.boot.neo4j.autoconfigure.ConfigBuilderCustomizer[] bean with an order higher than zero.\n\n\n\n[[actuator.metrics.supported.jetty]]\n=== Jetty Metrics\n\nAuto-configuration binds metrics for Jetty's javadoc:org.eclipse.jetty.util.thread.ThreadPool[] by using Micrometer's javadoc:io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics[].\nMetrics for Jetty's javadoc:org.eclipse.jetty.server.Connector[] instances are bound by using Micrometer's javadoc:io.micrometer.core.instrument.binder.jetty.JettyConnectionMetrics[] and, when configprop:server.ssl.enabled[] is set to `true`, Micrometer's javadoc:io.micrometer.core.instrument.binder.jetty.JettySslHandshakeMetrics[].\n\n\n\n[[actuator.metrics.supported.redis]]\n=== Redis Metrics\n\nAuto-configuration registers a javadoc:io.lettuce.core.tracing.MicrometerTracing[] for the auto-configured javadoc:org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory[].\nFor more detail, see the {url-lettuce-docs}/advanced-usage/#observability[Observability section] of the Lettuce documentation.\n\n\n\n[[actuator.metrics.registering-custom]]\n== Registering Custom Metrics\n\nTo register custom metrics, inject javadoc:io.micrometer.core.instrument.MeterRegistry[] into your component:\n\ninclude-code::MyBean[]\n\nIf your metrics depend on other beans, we recommend that you use a javadoc:io.micrometer.core.instrument.binder.MeterBinder[] to register them:\n\ninclude-code::MyMeterBinderConfiguration[]\n\nUsing a javadoc:io.micrometer.core.instrument.binder.MeterBinder[] ensures that the correct dependency relationships are set up and that the bean is available when the metric's value is retrieved.\nA javadoc:io.micrometer.core.instrument.binder.MeterBinder[] implementation can also be useful if you find that you repeatedly instrument a suite of metrics across components or applications.\n\nNOTE: By default, metrics from all javadoc:io.micrometer.core.instrument.binder.MeterBinder[] beans are automatically bound to the Spring-managed javadoc:io.micrometer.core.instrument.MeterRegistry[].\n\n\n\n[[actuator.metrics.customizing]]\n== Customizing Individual Metrics\n\nIf you need to apply customizations to specific javadoc:io.micrometer.core.instrument.Meter[] instances, you can use the javadoc:io.micrometer.core.instrument.config.MeterFilter[] interface.\n\nFor example, if you want to rename the `mytag.region` tag to `mytag.area` for all meter IDs beginning with `com.example`, you can do the following:\n\ninclude-code::MyMetricsFilterConfiguration[]\n\nNOTE: By default, all javadoc:io.micrometer.core.instrument.config.MeterFilter[] beans are automatically bound to the Spring-managed javadoc:io.micrometer.core.instrument.MeterRegistry[].\nMake sure to register your metrics by using the Spring-managed javadoc:io.micrometer.core.instrument.MeterRegistry[] and not any of the static methods on javadoc:io.micrometer.core.instrument.Metrics[].\nThese use the global registry that is not Spring-managed.\n\n\n\n[[actuator.metrics.customizing.common-tags]]\n=== Common Tags\n\nCommon tags are generally used for dimensional drill-down on the operating environment, such as host, instance, region, stack, and others.\nCommons tags are applied to all meters and can be configured, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  metrics:\n    tags:\n      region: \"us-east-1\"\n      stack: \"prod\"\n----\n\nThe preceding example adds `region` and `stack` tags to all meters with a value of `us-east-1` and `prod`, respectively.\n\nNOTE: The order of common tags is important if you use Graphite.\nAs the order of common tags cannot be guaranteed by using this approach, Graphite users are advised to define a custom javadoc:io.micrometer.core.instrument.config.MeterFilter[] instead.\n\n\n\n[[actuator.metrics.customizing.per-meter-properties]]\n=== Per-meter Properties\n\nIn addition to javadoc:io.micrometer.core.instrument.config.MeterFilter[] beans, you can apply a limited set of customization on a per-meter basis using properties.\nPer-meter customizations are applied, using Spring Boot's javadoc:org.springframework.boot.micrometer.metrics.autoconfigure.PropertiesMeterFilter[], to any meter IDs that start with the given name.\nThe following example filters out any meters that have an ID starting with `example.remote`.\n\n[configprops,yaml]\n----\nmanagement:\n  metrics:\n    enable:\n      example:\n        remote: false\n----\n\nThe following properties allow per-meter customization:\n\n.Per-meter customizations\n|===\n| Property | Description\n\n| configprop:management.metrics.enable[]\n| Whether to accept meters with certain IDs.\n  Meters that are not accepted are filtered from the javadoc:io.micrometer.core.instrument.MeterRegistry[].\n\n| configprop:management.metrics.distribution.percentiles-histogram[]\n| Whether to publish a histogram suitable for computing aggregable (across dimension) percentile approximations.\n\n| configprop:management.metrics.distribution.minimum-expected-value[], configprop:management.metrics.distribution.maximum-expected-value[]\n| Publish fewer histogram buckets by clamping the range of expected values.\n\n| configprop:management.metrics.distribution.percentiles[]\n| Publish percentile values computed in your application\n\n| configprop:management.metrics.distribution.expiry[], configprop:management.metrics.distribution.buffer-length[]\n| Give greater weight to recent samples by accumulating them in ring buffers which rotate after a configurable expiry, with a\nconfigurable buffer length.\n\n| configprop:management.metrics.distribution.slo[]\n| Publish a cumulative histogram with buckets defined by your service-level objectives.\n|===\n\nFor more details on the concepts behind `percentiles-histogram`, `percentiles`, and `slo`, see the {url-micrometer-docs-concepts}/histogram-quantiles.html[Histograms and percentiles] section of the Micrometer documentation.\n\n\n\n[[actuator.metrics.endpoint]]\n== Metrics Endpoint\n\nSpring Boot provides a `metrics` endpoint that you can use diagnostically to examine the metrics collected by an application.\nThe endpoint is not available by default and must be exposed.\nSee xref:actuator/endpoints.adoc#actuator.endpoints.exposing[exposing endpoints] for more details.\n\nNavigating to `/actuator/metrics` displays a list of available meter names.\nYou can drill down to view information about a particular meter by providing its name as a selector -- for example, `/actuator/metrics/jvm.memory.max`.\n\n[TIP]\n====\nThe name you use here should match the name used in the code, not the name after it has been naming-convention normalized for a monitoring system to which it is shipped.\nIn other words, if `jvm.memory.max` appears as `jvm_memory_max` in Prometheus because of its snake case naming convention, you should still use `jvm.memory.max` as the selector when inspecting the meter in the `metrics` endpoint.\n====\n\nYou can also add any number of `tag=KEY:VALUE` query parameters to the end of the URL to dimensionally drill down on a meter -- for example, `/actuator/metrics/jvm.memory.max?tag=area:nonheap`.\n\n[TIP]\n====\nThe reported measurements are the _sum_ of the statistics of all meters that match the meter name and any tags that have been applied.\nIn the preceding example, the returned `Value` statistic is the sum of the maximum memory footprints of the \"`Code Cache`\", \"`Compressed Class Space`\", and \"`Metaspace`\" areas of the heap.\nIf you wanted to see only the maximum size for the \"`Metaspace`\", you could add an additional `tag=id:Metaspace` -- that is, `/actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace`.\n====\n\n\n\n[[actuator.metrics.micrometer-observation]]\n== Integration with Micrometer Observation\n\nA javadoc:io.micrometer.core.instrument.observation.DefaultMeterObservationHandler[] is automatically registered on the javadoc:io.micrometer.observation.ObservationRegistry[], which creates metrics for every completed observation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/monitoring.adoc",
    "content": "[[actuator.monitoring]]\n= Monitoring and Management Over HTTP\n\nIf you are developing a web application, Spring Boot Actuator auto-configures all enabled endpoints to be exposed over HTTP.\nThe default convention is to use the `id` of the endpoint with a prefix of `/actuator` as the URL path.\nFor example, `health` is exposed as `/actuator/health`.\n\nTIP: Actuator is supported natively with Spring MVC, Spring WebFlux, and Jersey.\nIf both Jersey and Spring MVC are available, Spring MVC is used.\n\nNOTE: Jackson is a required dependency in order to get the correct JSON responses as documented in the xref:api:rest/actuator/index.adoc[API documentation].\nJackson 3 should be used for Spring MVC and Spring WebFlux.\nJersey does not yet have a Jackson 3 module, so you will need to use Jackson 2.\n\n\n\n[[actuator.monitoring.customizing-management-server-context-path]]\n== Customizing the Management Endpoint Paths\n\nSometimes, it is useful to customize the prefix for the management endpoints.\nFor example, your application might already use `/actuator` for another purpose.\nYou can use the configprop:management.endpoints.web.base-path[] property to change the prefix for your management endpoint, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      base-path: \"/manage\"\n----\n\nThe preceding `application.properties` example changes the endpoint from `/actuator/\\{id}` to `/manage/\\{id}` (for example, `/manage/info`).\n\nNOTE: Unless the management port has been configured to xref:actuator/monitoring.adoc#actuator.monitoring.customizing-management-server-port[expose endpoints by using a different HTTP port], `management.endpoints.web.base-path` is relative to `server.servlet.context-path` (for servlet web applications) or `spring.webflux.base-path` (for reactive web applications).\nIf `management.server.port` is configured, `management.endpoints.web.base-path` is relative to `management.server.base-path`.\n\nIf you want to map endpoints to a different path, you can use the configprop:management.endpoints.web.path-mapping[] property.\n\nThe following example remaps `/actuator/health` to `/healthcheck`:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      base-path: \"/\"\n      path-mapping:\n        health: \"healthcheck\"\n----\n\n\n\n[[actuator.monitoring.customizing-management-server-port]]\n== Customizing the Management Server Port\n\nExposing management endpoints by using the default HTTP port is a sensible choice for cloud-based deployments.\nIf, however, your application runs inside your own data center, you may prefer to expose endpoints by using a different HTTP port.\n\nYou can set the configprop:management.server.port[] property to change the HTTP port, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  server:\n    port: 8081\n----\n\nNOTE: On Cloud Foundry, by default, applications receive requests only on port 8080 for both HTTP and TCP routing.\nIf you want to use a custom management port on Cloud Foundry, you need to explicitly set up the application's routes to forward traffic to the custom port.\n\n\n\n[[actuator.monitoring.management-specific-ssl]]\n== Configuring Management-specific SSL\n\nWhen configured to use a custom port, you can also configure the management server with its own SSL by using the various `management.server.ssl.*` properties.\nFor example, doing so lets a management server be available over HTTP while the main application uses HTTPS, as the following property settings show:\n\n[configprops,yaml]\n----\nserver:\n  port: 8443\n  ssl:\n    enabled: true\n    key-store: \"classpath:store.jks\"\n    key-password: \"secret\"\nmanagement:\n  server:\n    port: 8080\n    ssl:\n      enabled: false\n----\n\nAlternatively, both the main server and the management server can use SSL but with different key stores, as follows:\n\n[configprops,yaml]\n----\nserver:\n  port: 8443\n  ssl:\n    enabled: true\n    key-store: \"classpath:main.jks\"\n    key-password: \"secret\"\nmanagement:\n  server:\n    port: 8080\n    ssl:\n      enabled: true\n      key-store: \"classpath:management.jks\"\n      key-password: \"secret\"\n----\n\n\n\n[[actuator.monitoring.customizing-management-server-address]]\n== Customizing the Management Server Address\n\nYou can customize the address on which the management endpoints are available by setting the configprop:management.server.address[] property.\nDoing so can be useful if you want to listen only on an internal or ops-facing network or to listen only for connections from `localhost`.\n\nNOTE: You can listen on a different address only when the port differs from the main server port.\n\nThe following example `application.properties` does not allow remote management connections:\n\n[configprops,yaml]\n----\nmanagement:\n  server:\n    port: 8081\n    address: \"127.0.0.1\"\n----\n\n\n\n[[actuator.monitoring.disabling-http-endpoints]]\n== Disabling HTTP Endpoints\n\nIf you do not want to expose endpoints over HTTP, you can set the management port to `-1`, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  server:\n    port: -1\n----\n\nYou can also achieve this by using the configprop:management.endpoints.web.exposure.exclude[] property, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  endpoints:\n    web:\n      exposure:\n        exclude: \"*\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/observability.adoc",
    "content": "[[actuator.observability]]\n= Observability\n\nObservability is the ability to observe the internal state of a running system from the outside.\nIt consists of the three pillars: logging, metrics and traces.\n\nFor metrics and traces, Spring Boot uses {url-micrometer-docs}/observation[Micrometer Observation].\nTo create your own observations (which will lead to metrics and traces), you can inject an javadoc:io.micrometer.observation.ObservationRegistry[].\n\ninclude-code::MyCustomObservation[]\n\nNOTE: Low cardinality tags will be added to metrics and traces, while high cardinality tags will only be added to traces.\n\nBeans of type javadoc:io.micrometer.observation.ObservationPredicate[], javadoc:io.micrometer.observation.GlobalObservationConvention[], javadoc:io.micrometer.observation.ObservationFilter[] and javadoc:io.micrometer.observation.ObservationHandler[] will be automatically registered on the javadoc:io.micrometer.observation.ObservationRegistry[].\nYou can additionally register any number of javadoc:org.springframework.boot.micrometer.observation.autoconfigure.ObservationRegistryCustomizer[] beans to further configure the registry.\n\nTIP: Observability for JDBC can be configured using a separate project.\nThe https://github.com/jdbc-observations/datasource-micrometer[Datasource Micrometer project] provides a Spring Boot starter which automatically creates observations when JDBC operations are invoked.\nRead more about it https://jdbc-observations.github.io/datasource-micrometer/docs/current/docs/html/[in the reference documentation].\n\nTIP: Observability for R2DBC is built into Spring Boot.\nTo enable it, add the `io.r2dbc:r2dbc-proxy` dependency to your project.\n\n\n\n[[actuator.observability.context-propagation]]\n== Context Propagation\nObservability support relies on the https://github.com/micrometer-metrics/context-propagation[Context Propagation library] for forwarding the current observation across threads and reactive pipelines.\nBy default, javadoc:java.lang.ThreadLocal[] values are not automatically reinstated in reactive operators.\nThis behavior is controlled with the configprop:spring.reactor.context-propagation[] property, which can be set to `auto` to enable automatic propagation.\n\nIf you're working with javadoc:org.springframework.scheduling.annotation.Async[format=annotation] methods and the javadoc:org.springframework.core.task.AsyncTaskExecutor[] is auto-configured, you have to opt-in for context propagation using the configprop:spring.task.execution.propagate-context[] property.\n\nIf you are configuring the javadoc:org.springframework.core.task.AsyncTaskExecutor[] yourself, then you need to register a javadoc:org.springframework.core.task.support.ContextPropagatingTaskDecorator[] bean, as shown in the following example:\n\ninclude-code::ContextPropagationConfiguration[]\n\nFor more details about observations please see the {url-micrometer-docs}/observation[Micrometer Observation documentation].\n\n\n\n[[actuator.observability.common-tags]]\n== Common Tags\n\nCommon tags are generally used for dimensional drill-down on the operating environment, such as host, instance, region, stack, and others.\nCommon tags are applied to all observations as low cardinality tags and can be configured, as the following example shows:\n\n[configprops,yaml]\n----\nmanagement:\n  observations:\n    key-values:\n      region: \"us-east-1\"\n      stack: \"prod\"\n----\n\nThe preceding example adds `region` and `stack` tags to all observations with a value of `us-east-1` and `prod`, respectively.\n\n\n\n[[actuator.observability.preventing-observations]]\n== Preventing Observations\n\nIf you'd like to prevent some observations from being reported, you can use the configprop:management.observations.enable[] properties:\n\n[configprops,yaml]\n----\nmanagement:\n  observations:\n    enable:\n      denied:\n        prefix: false\n      another:\n        denied:\n          prefix: false\n----\n\nThe preceding example will prevent all observations with a name starting with `denied.prefix` or `another.denied.prefix`.\n\nTIP: If you want to prevent Spring Security from reporting observations, set the property configprop:management.observations.enable.spring.security[] to `false`.\n\nIf you need greater control over the prevention of observations, you can register beans of type javadoc:io.micrometer.observation.ObservationPredicate[].\nObservations are only reported if all the javadoc:io.micrometer.observation.ObservationPredicate[] beans return `true` for that observation.\n\ninclude-code::MyObservationPredicate[]\n\nThe preceding example will prevent all observations whose name contains \"denied\".\n\n\n\n[[actuator.observability.annotations]]\n== Micrometer Observation Annotations support\n\nTo enable scanning of observability annotations like javadoc:io.micrometer.observation.annotation.Observed[format=annotation], javadoc:io.micrometer.core.annotation.Timed[format=annotation], javadoc:io.micrometer.core.annotation.Counted[format=annotation], javadoc:io.micrometer.core.aop.MeterTag[format=annotation] and javadoc:io.micrometer.tracing.annotation.NewSpan[format=annotation], set the configprop:management.observations.annotations.enabled[] property to `true`.\nA dependency on `org.aspectj:aspectjweaver`, which is part of `spring-boot-starter-aspectj`, is also required.\nThis feature is supported by Micrometer directly.\nPlease refer to the {url-micrometer-docs-concepts}/timers.html#_the_timed_annotation[Micrometer], {url-micrometer-docs-observation}/components.html#micrometer-observation-annotations[Micrometer Observation] and {url-micrometer-tracing-docs}/api.html#_aspect_oriented_programming[Micrometer Tracing] reference docs.\n\nNOTE: When you annotate methods or classes which are already instrumented (for example, xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-data-repository[Spring Data repositories] or xref:reference:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[Spring MVC controllers]), you will get duplicate observations.\nIn that case you can either disable the automatic instrumentation using xref:reference:actuator/observability.adoc#actuator.observability.preventing-observations[properties] or an javadoc:io.micrometer.observation.ObservationPredicate[] and rely on your annotations, or you can remove your annotations.\n\n\n\n[[actuator.observability.opentelemetry]]\n== OpenTelemetry Support\n\nNOTE: There are several ways to support https://opentelemetry.io/[OpenTelemetry] in your application.\nYou can use the https://opentelemetry.io/docs/zero-code/java/agent/[OpenTelemetry Java Agent] or the https://opentelemetry.io/docs/zero-code/java/spring-boot-starter/[OpenTelemetry Spring Boot Starter],\nwhich are supported by the OTel community; the metrics and traces use the semantic conventions defined by OTel libraries.\nThis documentation describes OpenTelemetry as officially supported by the Spring team, using Micrometer and the OTLP exporter;\nthe metrics and traces use the semantic conventions described in the Spring projects documentation, such as {url-spring-framework-docs}/integration/observability.html[Spring Framework].\n\nSpring Boot's actuator module includes basic support for OpenTelemetry.\n\nIt provides a bean of type javadoc:io.opentelemetry.api.OpenTelemetry[], and if there are beans of type javadoc:io.opentelemetry.sdk.trace.SdkTracerProvider[], javadoc:io.opentelemetry.context.propagation.ContextPropagators[], javadoc:io.opentelemetry.sdk.logs.SdkLoggerProvider[] or javadoc:io.opentelemetry.sdk.metrics.SdkMeterProvider[] in the application context, they automatically get registered.\nAdditionally, it provides a javadoc:io.opentelemetry.sdk.resources.Resource[] bean.\nThe attributes of the auto-configured javadoc:io.opentelemetry.sdk.resources.Resource[] can be configured via the configprop:management.opentelemetry.resource-attributes[] configuration property.\nAuto-configured attributes will be merged with attributes from the `OTEL_RESOURCE_ATTRIBUTES` and `OTEL_SERVICE_NAME` environment variables, with attributes configured through the configuration property taking precedence over those from the environment variables.\n\n\nIf you have defined your own javadoc:io.opentelemetry.sdk.resources.Resource[] bean, this will no longer be the case.\n\nNOTE: Spring Boot does not provide automatic exporting of OpenTelemetry metrics or logs.\nExporting OpenTelemetry traces is only auto-configured when used together with xref:actuator/tracing.adoc[Micrometer Tracing].\n\n\n\n[[actuator.observability.opentelemetry.disabling]]\n=== Disabling OpenTelemetry\n\nThe OpenTelemetry support can be disabled by setting the configprop:management.opentelemetry.enabled[] property to `false`.\nThis behaves similarly to the https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration[`OTEL_SDK_DISABLED`] environment variable (but negated): when the SDK is disabled, metrics, traces, and logging will use no-op implementations.\nContext propagators are not affected and continue to function normally.\n\nNOTE: Keep in mind that Spring Boot doesn't use OpenTelemetry's metrics functionality, so metrics might still be enabled even when disabling OpenTelemetry.\n\n\n\n[[actuator.observability.opentelemetry.environment-variables]]\n=== Environment variables\n\nSpring Boot supports a subset of the https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/[OpenTelemetry SDK environment variables].\nThese environment variables are automatically mapped to Spring Boot configuration properties at startup.\nWhen an environment variable has a signal-specific variant (for example, `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`) and a general variant (`OTEL_EXPORTER_OTLP_ENDPOINT`), the signal-specific variant takes precedence and is used as-is.\nWhen the general variant is used as a fallback, the signal-specific path (`v1/traces`, `v1/metrics`, or `v1/logs`) is appended to it.\nFor example, setting `OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318` results in `http://collector:4318/v1/traces` for traces.\n\nThis mapping can be disabled by setting configprop:management.opentelemetry.map-environment-variables[] to `false`.\n\n[[actuator.observability.opentelemetry.environment-variables.general]]\n==== General\n\n[cols=\"1,1\"]\n|===\n| Environment Variable | Spring Boot Property\n\n| `OTEL_SDK_DISABLED`\n| configprop:management.opentelemetry.enabled[] (inverted)\n\n| `OTEL_PROPAGATORS`\n| configprop:management.tracing.propagation.type[] and configprop:management.tracing.baggage.enabled[]\n\n| `OTEL_TRACES_SAMPLER`\n| configprop:management.opentelemetry.tracing.sampler[]\n\n| `OTEL_TRACES_SAMPLER_ARG`\n| configprop:management.tracing.sampling.probability[]\n\n| `OTEL_METRICS_EXEMPLAR_FILTER`\n| configprop:management.tracing.exemplars.include[]\n|===\n\n[[actuator.observability.opentelemetry.environment-variables.metrics]]\n==== Metrics Exporter\n\n[cols=\"1,1\"]\n|===\n| Environment Variable | Spring Boot Property\n\n| `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` / `OTEL_EXPORTER_OTLP_ENDPOINT`\n| configprop:management.otlp.metrics.export.url[]\n\n| `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE`\n| configprop:management.otlp.metrics.export.aggregation-temporality[]\n\n| `OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION`\n| configprop:management.otlp.metrics.export.histogram-flavor[]\n\n| `OTEL_EXPORTER_OTLP_METRICS_COMPRESSION` / `OTEL_EXPORTER_OTLP_COMPRESSION`\n| configprop:management.otlp.metrics.export.compression-mode[]\n\n| `OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` / `OTEL_EXPORTER_OTLP_TIMEOUT`\n| configprop:management.otlp.metrics.export.read-timeout[]\n\n| `OTEL_EXPORTER_OTLP_METRICS_HEADERS` / `OTEL_EXPORTER_OTLP_HEADERS`\n| configprop:management.otlp.metrics.export.headers[]\n\n| `OTEL_METRIC_EXPORT_INTERVAL`\n| configprop:management.otlp.metrics.export.step[]\n\n| `OTEL_METRICS_EXPORTER`\n| configprop:management.otlp.metrics.export.enabled[] (only `otlp` enables OTLP export; other values disable it but do not enable alternative exporters)\n\n| `OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE` / `OTEL_EXPORTER_OTLP_CERTIFICATE`\n| configprop:management.otlp.metrics.export.ssl.bundle[] (auto-configured SSL bundle)\n\n| `OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY` / `OTEL_EXPORTER_OTLP_CLIENT_KEY`\n| configprop:management.otlp.metrics.export.ssl.bundle[] (auto-configured SSL bundle)\n\n| `OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE` / `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE`\n| configprop:management.otlp.metrics.export.ssl.bundle[] (auto-configured SSL bundle)\n|===\n\n[[actuator.observability.opentelemetry.environment-variables.traces]]\n==== Traces Exporter\n\n[cols=\"1,1\"]\n|===\n| Environment Variable | Spring Boot Property\n\n| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` / `OTEL_EXPORTER_OTLP_ENDPOINT`\n| configprop:management.opentelemetry.tracing.export.otlp.endpoint[]\n\n| `OTEL_EXPORTER_OTLP_TRACES_COMPRESSION` / `OTEL_EXPORTER_OTLP_COMPRESSION`\n| configprop:management.opentelemetry.tracing.export.otlp.compression[]\n\n| `OTEL_EXPORTER_OTLP_TRACES_TIMEOUT` / `OTEL_EXPORTER_OTLP_TIMEOUT`\n| configprop:management.opentelemetry.tracing.export.otlp.timeout[]\n\n| `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` / `OTEL_EXPORTER_OTLP_PROTOCOL`\n| configprop:management.opentelemetry.tracing.export.otlp.transport[]\n\n| `OTEL_EXPORTER_OTLP_TRACES_HEADERS` / `OTEL_EXPORTER_OTLP_HEADERS`\n| configprop:management.opentelemetry.tracing.export.otlp.headers[]\n\n| `OTEL_BSP_SCHEDULE_DELAY`\n| configprop:management.opentelemetry.tracing.export.schedule-delay[]\n\n| `OTEL_BSP_EXPORT_TIMEOUT`\n| configprop:management.opentelemetry.tracing.export.timeout[]\n\n| `OTEL_BSP_MAX_QUEUE_SIZE`\n| configprop:management.opentelemetry.tracing.export.max-queue-size[]\n\n| `OTEL_BSP_MAX_EXPORT_BATCH_SIZE`\n| configprop:management.opentelemetry.tracing.export.max-batch-size[]\n\n| `OTEL_TRACES_EXPORTER`\n| configprop:management.tracing.export.otlp.enabled[] (only `otlp` enables OTLP export; other values disable it but do not enable alternative exporters)\n\n| `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` / `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT`\n| configprop:management.opentelemetry.tracing.limits.max-attribute-value-length[]\n\n| `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT` / `OTEL_ATTRIBUTE_COUNT_LIMIT`\n| configprop:management.opentelemetry.tracing.limits.max-attributes[]\n\n| `OTEL_SPAN_EVENT_COUNT_LIMIT`\n| configprop:management.opentelemetry.tracing.limits.max-events[]\n\n| `OTEL_SPAN_LINK_COUNT_LIMIT`\n| configprop:management.opentelemetry.tracing.limits.max-links[]\n\n| `OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT`\n| configprop:management.opentelemetry.tracing.limits.max-attributes-per-event[]\n\n| `OTEL_LINK_ATTRIBUTE_COUNT_LIMIT`\n| configprop:management.opentelemetry.tracing.limits.max-attributes-per-link[]\n\n| `OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE` / `OTEL_EXPORTER_OTLP_CERTIFICATE`\n| configprop:management.opentelemetry.tracing.export.otlp.ssl.bundle[] (auto-configured SSL bundle)\n\n| `OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY` / `OTEL_EXPORTER_OTLP_CLIENT_KEY`\n| configprop:management.opentelemetry.tracing.export.otlp.ssl.bundle[] (auto-configured SSL bundle)\n\n| `OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE` / `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE`\n| configprop:management.opentelemetry.tracing.export.otlp.ssl.bundle[] (auto-configured SSL bundle)\n|===\n\n[[actuator.observability.opentelemetry.environment-variables.logs]]\n==== Logs Exporter\n\n[cols=\"1,1\"]\n|===\n| Environment Variable | Spring Boot Property\n\n| `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` / `OTEL_EXPORTER_OTLP_ENDPOINT`\n| configprop:management.opentelemetry.logging.export.otlp.endpoint[]\n\n| `OTEL_EXPORTER_OTLP_LOGS_COMPRESSION` / `OTEL_EXPORTER_OTLP_COMPRESSION`\n| configprop:management.opentelemetry.logging.export.otlp.compression[]\n\n| `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT` / `OTEL_EXPORTER_OTLP_TIMEOUT`\n| configprop:management.opentelemetry.logging.export.otlp.timeout[]\n\n| `OTEL_EXPORTER_OTLP_LOGS_PROTOCOL` / `OTEL_EXPORTER_OTLP_PROTOCOL`\n| configprop:management.opentelemetry.logging.export.otlp.transport[]\n\n| `OTEL_EXPORTER_OTLP_LOGS_HEADERS` / `OTEL_EXPORTER_OTLP_HEADERS`\n| configprop:management.opentelemetry.logging.export.otlp.headers[]\n\n| `OTEL_BLRP_SCHEDULE_DELAY`\n| configprop:management.opentelemetry.logging.export.schedule-delay[]\n\n| `OTEL_BLRP_EXPORT_TIMEOUT`\n| configprop:management.opentelemetry.logging.export.timeout[]\n\n| `OTEL_BLRP_MAX_QUEUE_SIZE`\n| configprop:management.opentelemetry.logging.export.max-queue-size[]\n\n| `OTEL_BLRP_MAX_EXPORT_BATCH_SIZE`\n| configprop:management.opentelemetry.logging.export.max-batch-size[]\n\n| `OTEL_LOGS_EXPORTER`\n| configprop:management.logging.export.otlp.enabled[] (only `otlp` enables OTLP export; other values disable it but do not enable alternative exporters)\n\n| `OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT` / `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT`\n| configprop:management.opentelemetry.logging.limits.max-attribute-value-length[]\n\n| `OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT` / `OTEL_ATTRIBUTE_COUNT_LIMIT`\n| configprop:management.opentelemetry.logging.limits.max-attributes[]\n\n| `OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE` / `OTEL_EXPORTER_OTLP_CERTIFICATE`\n| configprop:management.opentelemetry.logging.export.otlp.ssl.bundle[] (auto-configured SSL bundle)\n\n| `OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY` / `OTEL_EXPORTER_OTLP_CLIENT_KEY`\n| configprop:management.opentelemetry.logging.export.otlp.ssl.bundle[] (auto-configured SSL bundle)\n\n| `OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE` / `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE`\n| configprop:management.opentelemetry.logging.export.otlp.ssl.bundle[] (auto-configured SSL bundle)\n|===\n\n[[actuator.observability.opentelemetry.environment-variables.resource]]\n==== Resource\n\nThe following environment variables configure the OpenTelemetry resource:\n\n* https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration[`OTEL_RESOURCE_ATTRIBUTES`]\n* https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration[`OTEL_SERVICE_NAME`]\n\nNOTE: The `OTEL_RESOURCE_ATTRIBUTES` environment variable consists of a list of key-value pairs.\nFor example: `key1=value1,key2=value2,key3=spring%20boot`.\nAll attribute values are treated as strings, and any characters outside the baggage-octet range must be **percent-encoded**.\n\n[[actuator.observability.opentelemetry.environment-variables.unsupported]]\n==== Unsupported Environment Variables\n\nOther environment variables as described in https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/[the OpenTelemetry documentation] are not supported.\n\nIf you want all environment variables specified by OpenTelemetry's SDK to be effective, you have to supply your own `OpenTelemetry` bean.\n\nWARNING: Doing this will switch off Spring Boot's OpenTelemetry auto-configuration and may break the built-in observability functionality.\n\nFirst, add a dependency to `io.opentelemetry:opentelemetry-sdk-extension-autoconfigure` to get https://opentelemetry.io/docs/languages/java/configuration/#zero-code-sdk-autoconfigure[OpenTelemetry's zero-code SDK autoconfigure module], then add this configuration:\n\ninclude-code::AutoConfiguredOpenTelemetrySdkConfiguration[]\n\n\n\n[[actuator.observability.opentelemetry.logging]]\n=== Logging\n\nThe javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration[] configures OpenTelemetry's javadoc:io.opentelemetry.sdk.logs.SdkLoggerProvider[].\nExporting logs via OTLP is supported through the javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration[], which enables OTLP log exporting over HTTP or gRPC.\n\nNOTE: If you need to apply advanced customizations to OTLP log record exporters, consider registering javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpHttpLogRecordExporterBuilderCustomizer[] or javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpGrpcLogRecordExporterBuilderCustomizer[] beans.\nThese will be invoked before the creation of the javadoc:io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter[] or javadoc:io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter[].\nThe customizers take precedence over anything applied by the auto-configuration.\n\nHowever, while there is a `SdkLoggerProvider` bean, Spring Boot doesn't support bridging logs to this bean out of the box.\nThis can be done with 3rd-party log bridges, as described in the xref:reference:actuator/loggers.adoc#actuator.loggers.opentelemetry[Logging with OpenTelemetry] section.\n\n\n\n[[actuator.observability.opentelemetry.metrics]]\n=== Metrics\n\nThe choice of metrics in the Spring portfolio is Micrometer, which means that metrics are not collected and exported through the OpenTelemetry's javadoc:io.opentelemetry.sdk.metrics.SdkMeterProvider[].\nSpring Boot doesn't provide a `SdkMeterProvider` bean.\n\n\nHowever, Micrometer metrics can be exported via OTLP to any OpenTelemetry capable backend using the javadoc:io.micrometer.registry.otlp.OtlpMeterRegistry[], as described in the xref:reference:actuator/metrics.adoc#actuator.metrics.export.otlp[Metrics with OTLP] section.\n\nNOTE: Micrometer's OTLP registry doesn't use the `Resource` bean, but setting `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME` or configprop:management.opentelemetry.resource-attributes[] works.\n\n[[actuator.observability.opentelemetry.metrics.api-and-sdk]]\n==== Metrics via the OpenTelemetry API and SDK\n\nIf you or a dependency you include make use of OpenTelemetry's javadoc:io.opentelemetry.api.metrics.MeterProvider[], those metrics are not exported.\n\nWe strongly recommend that you report your metrics with Micrometer.\nIf a dependency you include uses OpenTelemetry's `MeterProvider`, you can include this configuration in your application to configure a `MeterProvider` bean, which you then have to wire into your dependency:\n\ninclude-code::OpenTelemetryMetricsConfiguration[]\n\nThis configuration also enables metrics export via OTLP over HTTP.\n\n\n\n[[actuator.observability.opentelemetry.tracing]]\n=== Tracing\n\nIf Micrometer tracing is used, the javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryTracingAutoConfiguration[] configures OpenTelemetry's javadoc:io.opentelemetry.sdk.trace.SdkTracerProvider[].\nExporting traces through OTLP is enabled by the javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration[], which supports exporting traces with OTLP over HTTP or gRPC.\n\nWe strongly recommend using the Micrometer Observation or Tracing API instead of using the OpenTelemetry API directly.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/process-monitoring.adoc",
    "content": "[[actuator.process-monitoring]]\n= Process Monitoring\n\nIn the `spring-boot` module, you can find two classes to create files that are often useful for process monitoring:\n\n* javadoc:org.springframework.boot.context.ApplicationPidFileWriter[] creates a file that contains the application PID (by default, in the application directory with a file name of `application.pid`).\n* javadoc:org.springframework.boot.web.server.context.WebServerPortFileWriter[] creates a file (or files) that contain the ports of the running web server (by default, in the application directory with a file name of `application.port`).\n\nBy default, these writers are not activated, but you can enable them:\n\n* xref:actuator/process-monitoring.adoc#actuator.process-monitoring.configuration[]\n* xref:actuator/process-monitoring.adoc#actuator.process-monitoring.programmatically[]\n\n\n\n[[actuator.process-monitoring.configuration]]\n== Extending Configuration\n\nIn the `META-INF/spring.factories` file, you can activate the listener (or listeners) that writes a PID file:\n\n[source]\n----\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.context.ApplicationPidFileWriter,\\\norg.springframework.boot.web.server.context.WebServerPortFileWriter\n----\n\n\n\n[[actuator.process-monitoring.programmatically]]\n== Programmatically Enabling Process Monitoring\n\nYou can also activate a listener by invoking the `SpringApplication.addListeners(...)` method and passing the appropriate javadoc:java.io.Writer[] object.\nThis method also lets you customize the file name and path in the javadoc:java.io.Writer[] constructor.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/actuator/tracing.adoc",
    "content": "[[actuator.micrometer-tracing]]\n= Tracing\n\nSpring Boot Actuator provides dependency management and auto-configuration for {url-micrometer-tracing-docs}[Micrometer Tracing], a facade for popular tracer libraries.\n\nTIP: To learn more about Micrometer Tracing capabilities, see its {url-micrometer-tracing-docs}[reference documentation].\n\n\n\n[[actuator.micrometer-tracing.tracers]]\n== Supported Tracers\n\nSpring Boot ships auto-configuration for the following tracers:\n\n* https://opentelemetry.io/[OpenTelemetry] with https://opentelemetry.io/docs/reference/specification/protocol/[OTLP].\n* https://github.com/openzipkin/brave[OpenZipkin Brave] with https://zipkin.io/[Zipkin].\n\n\n\n[[actuator.micrometer-tracing.getting-started]]\n== Getting Started\n\nWe need an example application that we can use to get started with tracing.\nFor our purposes, the simple \"`Hello World!`\" web application that's covered in the xref:tutorial:first-application/index.adoc[] section will suffice.\nWe're going to use the Brave tracer with Zipkin as trace backend.\n\nTo recap, our main application code looks like this:\n\ninclude-code::MyApplication[]\n\nNOTE: There's an added logger statement in the `home()` method, which will be important later.\n\nNow we have to add the `org.springframework.boot:spring-boot-starter-zipkin` dependency.\n\nThen add the following application properties:\n\n[configprops,yaml]\n----\nmanagement:\n  tracing:\n    sampling:\n      probability: 1.0\n----\n\nBy default, Spring Boot samples only 10% of requests to prevent overwhelming the trace backend.\nThis property switches it to 100% so that every request is sent to the trace backend.\n\nTo collect and visualize the traces, we need a running trace backend.\nWe use Zipkin as our trace backend here.\nThe https://zipkin.io/pages/quickstart[Zipkin Quickstart guide] provides instructions how to start Zipkin locally.\n\nAfter Zipkin is running, you can start your application.\n\nIf you open a web browser to `http://localhost:8080`, you should see the following output:\n\n[source]\n----\nHello World!\n----\n\nBehind the scenes, an observation has been created for the HTTP request, which in turn gets bridged to Brave, which reports a new trace to Zipkin.\n\nNow open the Zipkin UI at `http://localhost:9411` and press the \"Run Query\" button to list all collected traces.\nYou should see one trace.\nPress the \"Show\" button to see the details of that trace.\n\n\n\n[[actuator.micrometer-tracing.logging]]\n== Logging Correlation IDs\n\nCorrelation IDs provide a helpful way to link lines in your log files to spans/traces.\nIf you are using Micrometer Tracing, Spring Boot will include correlation IDs in your logs by default.\n\nThe default correlation ID is built from `traceId` and `spanId` https://logback.qos.ch/manual/mdc.html[MDC] values.\nFor example, if Micrometer Tracing has added an MDC `traceId` of `803B448A0489F84084905D3093480352` and an MDC `spanId` of `3425F23BB2432450` the log output will include the correlation ID `[803B448A0489F84084905D3093480352-3425F23BB2432450]`.\n\nIf you prefer to use a different format for your correlation ID, you can use the configprop:logging.pattern.correlation[] property to define one.\nFor example, the following will provide a correlation ID for Logback in format previously used by Spring Cloud Sleuth:\n\n[configprops,yaml]\n----\nlogging:\n  pattern:\n    correlation: \"[${spring.application.name:},%X{traceId:-},%X{spanId:-}] \"\n  include-application-name: false\n----\n\nNOTE: In the example above, configprop:logging.include-application-name[] is set to `false` to avoid the application name being duplicated in the log messages (configprop:logging.pattern.correlation[] already contains it).\nIt's also worth mentioning that configprop:logging.pattern.correlation[] contains a trailing space so that it is separated from the logger name that comes right after it by default.\n\nTIP: Correlation IDs rely on context propagation.\nPlease read xref:reference:actuator/observability.adoc#actuator.observability.context-propagation[this documentation for more details].\n\n\n\n[[actuator.micrometer-tracing.propagating-traces]]\n== Propagating Traces\n\nTo automatically propagate traces over the network, use the auto-configured xref:io/rest-client.adoc#io.rest-client.resttemplate[`RestTemplateBuilder`], xref:io/rest-client.adoc#io.rest-client.restclient[`RestClient.Builder`] or xref:io/rest-client.adoc#io.rest-client.webclient[`WebClient.Builder`] to construct the client.\n\nWARNING: If you create the javadoc:org.springframework.web.client.RestTemplate[], the javadoc:org.springframework.web.client.RestClient[] or the javadoc:org.springframework.web.reactive.function.client.WebClient[] without using the auto-configured builders, automatic trace propagation won't work!\n\n\n\n[[actuator.micrometer-tracing.tracer-implementations]]\n== Tracer Implementations\n\nAs Micrometer Tracer supports multiple tracer implementations, there are multiple dependency combinations possible with Spring Boot.\nThe combinations OpenTelemetry with OTLP and Brave with Zipkin are common and have dedicated starters.\n\n\n[[actuator.micrometer-tracing.tracer-implementations.otel-otlp]]\n=== OpenTelemetry With OTLP\n\nTracing with OpenTelemetry and reporting using OTLP requires the following dependencies:\n\n* `org.springframework.boot:spring-boot-starter-opentelemetry`\n\nUse the `management.opentelemetry.tracing.export.otlp.*` configuration properties to configure reporting using OTLP.\n\nNOTE: If you need to apply advanced customizations to OTLP span exporters, consider registering javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpHttpSpanExporterBuilderCustomizer[] or javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpGrpcSpanExporterBuilderCustomizer[] beans.\nThese will be invoked before the creation of the `OtlpHttpSpanExporter` or `OtlpGrpcSpanExporter`.\nThe customizers take precedence over anything applied by the auto-configuration.\n\n\n\n[[actuator.micrometer-tracing.tracer-implementations.otel-zipkin]]\n=== OpenTelemetry With Zipkin\n\nWARNING: OpenTelemetry has https://opentelemetry.io/docs/specs/otel/trace/sdk_exporters/zipkin/[deprecated their Zipkin support].\nThe auto-configuration for it will be removed in Spring Boot 4.2.\nEither switch to Brave or consider using https://github.com/openzipkin-contrib/zipkin-otel[the Zipkin OTel module] for ingesting OTLP directly.\n\nTracing with OpenTelemetry and reporting to Zipkin requires the following dependencies:\n\n* `org.springframework.boot:spring-boot-micrometer-tracing-opentelemetry` - Spring Boot's support for Micrometer Tracing over OpenTelemetry.\n* `io.micrometer:micrometer-tracing-bridge-otel` - bridges the Micrometer Observation API to OpenTelemetry.\n* `org.springframework.boot:spring-boot-zipkin` - Spring Boot's support for Zipkin.\n* `io.opentelemetry:opentelemetry-exporter-zipkin` - OpenTelemetry exporter that reports traces to Zipkin.\n\nUse the `management.tracing.export.zipkin.*` configuration properties to configure reporting to Zipkin.\n\n\n\n[[actuator.micrometer-tracing.tracer-implementations.brave-zipkin]]\n=== OpenZipkin Brave With Zipkin\n\nTracing with OpenZipkin Brave and reporting to Zipkin requires the following dependencies:\n\n* `org.springframework.boot:spring-boot-starter-zipkin`\n\nUse the `management.tracing.export.zipkin.*` configuration properties to configure reporting to Zipkin.\n\n\n\n[[actuator.micrometer-tracing.sampling]]\n== Sampling\n\nBy default, Spring Boot samples only 10% of requests to prevent overwhelming the trace backend.\nThe configprop:management.tracing.sampling.probability[] property can be used to configure this.\n\nWhen using OpenTelemetry, you can also configure which sampler is used via the configprop:management.opentelemetry.tracing.sampler[] property.\nThe following samplers are supported:\n\n|===\n|Sampler |Description\n\n|`always-on`\n|Samples every trace.\n\n|`always-off`\n|Discards every trace.\n\n|`trace-id-ratio`\n|Samples a fraction of traces based on configprop:management.tracing.sampling.probability[].\n\n|`parent-based-always-on`\n|If the parent span is sampled, samples the child span. If there is no parent, samples every trace.\n\n|`parent-based-always-off`\n|If the parent span is sampled, samples the child span. If there is no parent, discards every trace.\n\n|`parent-based-trace-id-ratio` (default)\n|If the parent span is sampled, samples the child span. If there is no parent, samples a fraction of traces based on configprop:management.tracing.sampling.probability[].\n|===\n\n\n\n[[actuator.micrometer-tracing.span-limits]]\n== Span Limits\n\nWhen using OpenTelemetry, you can configure span limits via the `management.opentelemetry.tracing.limits.*` configuration properties.\nThese allow you to control the maximum number of attributes, events, and links per span, as well as the maximum length of string attribute values.\n\nFor example, to limit the number of attributes per span to 64 and the maximum attribute value length to 256 characters:\n\n[configprops,yaml]\n----\nmanagement:\n  opentelemetry:\n    tracing:\n      limits:\n        max-attributes: 64\n        max-attribute-value-length: 256\n----\n\nIf you need full control, you can register a custom javadoc:io.opentelemetry.sdk.trace.SpanLimits[] bean.\n\n\n\n[[actuator.micrometer-tracing.micrometer-observation]]\n== Integration with Micrometer Observation\n\nA javadoc:io.micrometer.tracing.handler.TracingAwareMeterObservationHandler[] is automatically registered on the javadoc:io.micrometer.observation.ObservationRegistry[], which creates spans for every completed observation.\n\n\n\n[[actuator.micrometer-tracing.creating-spans]]\n== Creating Custom Spans\n\nYou can create your own spans by starting an observation.\nFor this, inject javadoc:io.micrometer.observation.ObservationRegistry[] into your component:\n\ninclude-code::CustomObservation[]\n\nThis will create an observation named \"some-operation\" with the tag \"some-tag=some-value\".\n\nTIP: If you want to create a span without creating a metric, you need to use the {url-micrometer-tracing-docs}/api[lower-level `Tracer` API] from Micrometer.\n\n\n\n[[actuator.micrometer-tracing.baggage]]\n== Baggage\n\nYou can create baggage with the javadoc:io.micrometer.tracing.Tracer[] API:\n\ninclude-code::CreatingBaggage[]\n\nThis example creates baggage named `baggage1` with the value `value1`.\nThe baggage is automatically propagated over the network if you're using W3C propagation.\nIf you're using B3 propagation, baggage is not automatically propagated.\nTo manually propagate baggage over the network, use the configprop:management.tracing.baggage.remote-fields[] configuration property (this works for W3C, too).\nFor the example above, setting this property to `baggage1` results in an HTTP header `baggage1: value1`.\n\nIf you want to propagate the baggage to the MDC, use the configprop:management.tracing.baggage.correlation.fields[] configuration property.\nFor the example above, setting this property to `baggage1` results in an MDC entry named `baggage1`.\n\n\n\n[[actuator.micrometer-tracing.tests]]\n== Tests\n\nTracing components which are reporting data are not auto-configured when using javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation].\nSee xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.tracing[] for more details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/index.adoc",
    "content": "[[data]]\n= Data\n\nSpring Boot integrates with a number of data technologies, both SQL and NoSQL.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/nosql.adoc",
    "content": "[[data.nosql]]\n= Working with NoSQL Technologies\n\nSpring Data provides additional projects that help you access a variety of NoSQL technologies, including:\n\n* {url-spring-data-cassandra-site}[Cassandra]\n* {url-spring-data-couchbase-site}[Couchbase]\n* {url-spring-data-elasticsearch-site}[Elasticsearch]\n* {url-spring-data-geode-site}[Geode]\n* {url-spring-data-ldap-site}[LDAP]\n* {url-spring-data-mongodb-site}[MongoDB]\n* {url-spring-data-neo4j-site}[Neo4J]\n* {url-spring-data-redis-site}[Redis]\n\nOf these, Spring Boot provides auto-configuration for Cassandra, Couchbase, Elasticsearch, LDAP, MongoDB, Neo4J and Redis.\nAdditionally, {url-spring-boot-for-apache-geode-site}[Spring Boot for Apache Geode] provides {url-spring-boot-for-apache-geode-docs}#geode-repositories[auto-configuration for Apache Geode].\nYou can make use of the other projects, but you must configure them yourself.\nSee the appropriate reference documentation at {url-spring-data-site}.\n\nSpring Boot also provides auto-configuration for the InfluxDB client but it is deprecated in favor of https://github.com/influxdata/influxdb-client-java[the new InfluxDB Java client] that provides its own Spring Boot integration.\n\n\n\n[[data.nosql.redis]]\n== Redis\n\nhttps://redis.io/[Redis] is a cache, message broker, and richly-featured key-value store.\nSpring Boot offers basic auto-configuration for the https://github.com/redis/lettuce/[Lettuce] and https://github.com/redis/jedis/[Jedis] client libraries and the abstractions on top of them provided by https://github.com/spring-projects/spring-data-redis[Spring Data Redis].\n\nThere is a `spring-boot-starter-data-redis` starter for collecting the dependencies in a convenient way.\nBy default, it uses https://github.com/redis/lettuce/[Lettuce].\nThat starter handles both traditional and reactive applications.\n\nTIP: We also provide a `spring-boot-starter-data-redis-reactive` starter for consistency with the other stores with reactive support.\n\n\n\n[[data.nosql.redis.connecting]]\n=== Connecting to Redis\n\nYou can inject an auto-configured javadoc:org.springframework.data.redis.connection.RedisConnectionFactory[], javadoc:org.springframework.data.redis.core.StringRedisTemplate[], or vanilla javadoc:org.springframework.data.redis.core.RedisTemplate[] instance as you would any other Spring Bean.\nThe following listing shows an example of such a bean:\n\ninclude-code::MyBean[]\n\nBy default, the instance tries to connect to a Redis server at `localhost:6379`.\nYou can specify custom connection details using `spring.data.redis.*` properties, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  data:\n    redis:\n      host: \"localhost\"\n      port: 6379\n      database: 0\n      username: \"user\"\n      password: \"secret\"\n----\n\nYou can also specify the url of the Redis server directly.\nWhen setting the url, the host, port, username and password properties are ignored.\nThis is shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  data:\n    redis:\n      url: \"redis://user:secret@localhost:6379\"\n      database: 0\n----\n\n\nTIP: You can also register an arbitrary number of beans that implement javadoc:org.springframework.boot.data.redis.autoconfigure.LettuceClientConfigurationBuilderCustomizer[] for more advanced customizations.\njavadoc:io.lettuce.core.resource.ClientResources[] can also be customized using javadoc:org.springframework.boot.data.redis.autoconfigure.ClientResourcesBuilderCustomizer[].\nIf you use Jedis, javadoc:org.springframework.boot.data.redis.autoconfigure.JedisClientConfigurationBuilderCustomizer[] is also available.\n\nAlternatively, you can register a bean of type javadoc:org.springframework.data.redis.connection.RedisStandaloneConfiguration[], javadoc:org.springframework.data.redis.connection.RedisSentinelConfiguration[], javadoc:org.springframework.data.redis.connection.RedisClusterConfiguration[], or javadoc:org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration[] to take full control over the configuration.\n\nNOTE: master/replica is not supported by Jedis.\n\nIf you add your own javadoc:org.springframework.context.annotation.Bean[format=annotation] of any of the auto-configured types, it replaces the default (except in the case of javadoc:org.springframework.data.redis.core.RedisTemplate[], when the exclusion is based on the bean name, `redisTemplate`, not its type).\n\nBy default, a pooled connection factory is auto-configured if `commons-pool2` is on the classpath.\n\nThe auto-configured javadoc:org.springframework.data.redis.connection.RedisConnectionFactory[] can be configured to use SSL for communication with the server by setting the properties as shown in this example:\n\n[configprops,yaml]\n----\nspring:\n  data:\n    redis:\n      ssl:\n        enabled: true\n----\n\nCustom SSL trust material can be configured in an xref:features/ssl.adoc[SSL bundle] and applied to the javadoc:org.springframework.data.redis.connection.RedisConnectionFactory[] as shown in this example:\n\n[configprops,yaml]\n----\nspring:\n  data:\n    redis:\n      ssl:\n        bundle: \"example\"\n----\n\n\n\n[[data.nosql.mongodb]]\n== MongoDB\n\nhttps://www.mongodb.com/[MongoDB] is an open-source NoSQL document database that uses a JSON-like schema instead of traditional table-based relational data.\nSpring Boot offers several conveniences for working with MongoDB, including the `spring-boot-starter-data-mongodb` and `spring-boot-starter-data-mongodb-reactive` starters.\n\n\n\n[[data.nosql.mongodb.connecting]]\n=== Connecting to a MongoDB Database\n\nTo access MongoDB databases, you can inject an auto-configured javadoc:org.springframework.data.mongodb.MongoDatabaseFactory[].\nBy default, the instance tries to connect to a MongoDB server at `mongodb://localhost/test`.\nThe following example shows how to connect to a MongoDB database:\n\ninclude-code::MyBean[]\n\nIf you have defined your own javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[], it will be used to auto-configure a suitable javadoc:org.springframework.data.mongodb.MongoDatabaseFactory[].\n\nThe auto-configured javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[] is created using a javadoc:{url-mongodb-driver-core-javadoc}/com.mongodb.MongoClientSettings[] bean.\nIf you have defined your own javadoc:{url-mongodb-driver-core-javadoc}/com.mongodb.MongoClientSettings[], it will be used without modification and the `spring.data.mongodb` properties will be ignored.\nOtherwise a javadoc:{url-mongodb-driver-core-javadoc}/com.mongodb.MongoClientSettings[] will be auto-configured and will have the `spring.data.mongodb` properties applied to it.\nIn either case, you can declare one or more javadoc:org.springframework.boot.mongodb.autoconfigure.MongoClientSettingsBuilderCustomizer[] beans to fine-tune the javadoc:{url-mongodb-driver-core-javadoc}/com.mongodb.MongoClientSettings[] configuration.\nEach will be called in order with the javadoc:{url-mongodb-driver-core-javadoc}/com.mongodb.MongoClientSettings$Builder[] that is used to build the javadoc:{url-mongodb-driver-core-javadoc}/com.mongodb.MongoClientSettings[].\n\nYou can set the configprop:spring.mongodb.uri[] property to change the URL and configure additional settings such as the _replica set_, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  mongodb:\n    uri: \"mongodb://user:secret@mongoserver1.example.com:27017,mongoserver2.example.com:23456/test\"\n----\n\nAlternatively, you can specify connection details using discrete properties.\nFor example, you might declare the following settings in your `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  mongodb:\n    host: \"mongoserver1.example.com\"\n    port: 27017\n    additional-hosts:\n    - \"mongoserver2.example.com:23456\"\n    database: \"test\"\n    username: \"user\"\n    password: \"secret\"\n----\n\nThe auto-configured javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[] can be configured to use SSL for communication with the server by setting the properties as shown in this example:\n\n[configprops,yaml]\n----\nspring:\n  mongodb:\n    uri: \"mongodb://user:secret@mongoserver1.example.com:27017,mongoserver2.example.com:23456/test\"\n    ssl:\n      enabled: true\n----\n\nCustom SSL trust material can be configured in an xref:features/ssl.adoc[SSL bundle] and applied to the javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[] as shown in this example:\n\n[configprops,yaml]\n----\nspring:\n  mongodb:\n    uri: \"mongodb://user:secret@mongoserver1.example.com:27017,mongoserver2.example.com:23456/test\"\n    ssl:\n      bundle: \"example\"\n----\n\n\n[TIP]\n====\nIf configprop:spring.mongodb.port[] is not specified, the default of `27017` is used.\nYou could delete this line from the example shown earlier.\n\nYou can also specify the port as part of the host address by using the `host:port` syntax.\nThis format should be used if you need to change the port of an `additional-hosts` entry.\n====\n\nTIP: If you do not use Spring Data MongoDB, you can inject a javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[] bean instead of using javadoc:org.springframework.data.mongodb.MongoDatabaseFactory[].\nIf you want to take complete control of establishing the MongoDB connection, you can also declare your own javadoc:org.springframework.data.mongodb.MongoDatabaseFactory[] or javadoc:{url-mongodb-driver-sync-javadoc}/com.mongodb.client.MongoClient[] bean.\n\nNOTE: If you are using the reactive driver, Netty is required for SSL.\nThe auto-configuration configures this factory automatically if Netty is available and the factory to use has not been customized already.\n\n\n\n[[data.nosql.mongodb.template]]\n=== MongoTemplate\n\n{url-spring-data-mongodb-site}[Spring Data MongoDB] provides a javadoc:org.springframework.data.mongodb.core.MongoTemplate[] class that is very similar in its design to Spring's javadoc:org.springframework.jdbc.core.JdbcTemplate[].\nAs with javadoc:org.springframework.jdbc.core.JdbcTemplate[], Spring Boot auto-configures a bean for you to inject the template, as follows:\n\ninclude-code::MyBean[]\n\nSee the javadoc:org.springframework.data.mongodb.core.MongoOperations[] API documentation for complete details.\n\n\n\n[[data.nosql.mongodb.repositories]]\n=== Spring Data MongoDB Repositories\n\nSpring Data includes repository support for MongoDB.\nAs with the JPA repositories discussed earlier, the basic principle is that queries are constructed automatically, based on method names.\n\nIn fact, both Spring Data JPA and Spring Data MongoDB share the same common infrastructure.\nYou could take the JPA example from earlier and, assuming that `City` is now a MongoDB data class rather than a JPA javadoc:jakarta.persistence.Entity[format=annotation], it works in the same way, as shown in the following example:\n\ninclude-code::CityRepository[]\n\nRepositories and documents are found through scanning.\nBy default, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\nYou can customize the locations to look for repositories and documents by using javadoc:org.springframework.data.mongodb.repository.config.EnableMongoRepositories[format=annotation] and javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] respectively.\n\nTIP: For complete details of Spring Data MongoDB, including its rich object mapping technologies, see its {url-spring-data-mongodb-docs}[reference documentation].\n\n\n\n[[data.nosql.neo4j]]\n== Neo4j\n\nhttps://neo4j.com/[Neo4j] is an open-source NoSQL graph database that uses a rich data model of nodes connected by first class relationships, which is better suited for connected big data than traditional RDBMS approaches.\nSpring Boot offers several conveniences for working with Neo4j, including the `spring-boot-starter-data-neo4j` starter.\n\n\n\n[[data.nosql.neo4j.connecting]]\n=== Connecting to a Neo4j Database\n\nTo access a Neo4j server, you can inject an auto-configured javadoc:org.neo4j.driver.Driver[].\nBy default, the instance tries to connect to a Neo4j server at `localhost:7687` using the Bolt protocol.\nThe following example shows how to inject a Neo4j javadoc:org.neo4j.driver.Driver[] that gives you access, amongst other things, to a javadoc:org.neo4j.driver.Session[]:\n\ninclude-code::MyBean[]\n\nYou can configure various aspects of the driver using `spring.neo4j.*` properties.\nThe following example shows how to configure the uri and credentials to use:\n\n[configprops,yaml]\n----\nspring:\n  neo4j:\n    uri: \"bolt://my-server:7687\"\n    authentication:\n      username: \"neo4j\"\n      password: \"secret\"\n----\n\nThe auto-configured javadoc:org.neo4j.driver.Driver[] is created using `org.neo4j.driver.Config$ConfigBuilder`.\nTo fine-tune its configuration, declare one or more javadoc:org.springframework.boot.neo4j.autoconfigure.ConfigBuilderCustomizer[] beans.\nEach will be called in order with the `org.neo4j.driver.Config$ConfigBuilder` that is used to build the javadoc:org.neo4j.driver.Driver[].\n\n\n\n[[data.nosql.neo4j.repositories]]\n=== Spring Data Neo4j Repositories\n\nSpring Data includes repository support for Neo4j.\nFor complete details of Spring Data Neo4j, see the {url-spring-data-neo4j-docs}[reference documentation].\n\nSpring Data Neo4j shares the common infrastructure with Spring Data JPA as many other Spring Data modules do.\nYou could take the JPA example from earlier and define `City` as Spring Data Neo4j javadoc:org.springframework.data.neo4j.core.schema.Node[format=annotation] rather than JPA javadoc:jakarta.persistence.Entity[format=annotation] and the repository abstraction works in the same way, as shown in the following example:\n\ninclude-code::CityRepository[]\n\nThe `spring-boot-starter-data-neo4j` starter enables the repository support as well as transaction management.\nSpring Boot supports both classic and reactive Neo4j repositories, using the javadoc:org.springframework.data.neo4j.core.Neo4jTemplate[] or javadoc:org.springframework.data.neo4j.core.ReactiveNeo4jTemplate[] beans.\nWhen Project Reactor is available on the classpath, the reactive style is also auto-configured.\n\nRepositories and entities are found through scanning.\nBy default, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\nYou can customize the locations to look for repositories and entities by using javadoc:org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories[format=annotation] and javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] respectively.\n\n[NOTE]\n====\nIn an application using the reactive style, a javadoc:org.springframework.transaction.ReactiveTransactionManager[] is not auto-configured.\nTo enable transaction management, the following bean must be defined in your configuration:\n\ninclude-code::MyNeo4jConfiguration[]\n====\n\n\n\n[[data.nosql.elasticsearch]]\n== Elasticsearch\n\nhttps://www.elastic.co/products/elasticsearch[Elasticsearch] is an open source, distributed, RESTful search and analytics engine.\nSpring Boot offers basic auto-configuration for Elasticsearch clients.\n\nSpring Boot supports several clients:\n\n* The official low-level REST client\n* The official Java API client\n* The javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient[] provided by Spring Data Elasticsearch\n\nSpring Boot provides a dedicated starter, `spring-boot-starter-data-elasticsearch`.\n\n\n\n[[data.nosql.elasticsearch.connecting-using-rest]]\n=== Connecting to Elasticsearch Using REST clients\n\nElasticsearch ships two different REST clients that you can use to query a cluster: the https://www.elastic.co/docs/reference/elasticsearch/clients/java/transport/rest5-client/[low-level client] and the https://www.elastic.co/docs/reference/elasticsearch/clients/java[Java API client].\nThe Java API client is provided by the `co.elastic.clients:elasticsearch-java` module and\nthe low-level client is provided by the `co.elastic.clients:elasticsearch-rest5-client` module.\nAdditionally, Spring Boot provides support for a reactive client from the `org.springframework.data:spring-data-elasticsearch` module.\nBy default, the clients will target `http://localhost:9200`.\nYou can use `spring.elasticsearch.*` properties to further tune how the clients are configured, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  elasticsearch:\n    uris: \"https://search.example.com:9200\"\n    socket-timeout: \"10s\"\n    username: \"user\"\n    password: \"secret\"\n----\n\n\n\n[[data.nosql.elasticsearch.connecting-using-rest.restclient]]\n==== Connecting to Elasticsearch Using Rest5Client\n\nIf you have `co.elastic.clients:elasticsearch-rest5-client` on the classpath, Spring Boot will auto-configure and register a javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[] bean.\nIn addition to the properties described previously, to fine-tune the javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[] you can register an arbitrary number of beans that implement javadoc:org.springframework.boot.elasticsearch.autoconfigure.Rest5ClientBuilderCustomizer[] for more advanced customizations.\nTo take full control over the client's configuration, define a javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder[] bean.\n\n\n\nAdditionally, a javadoc:co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer[] can be auto-configured to automatically discover nodes from a running Elasticsearch cluster and set them on the javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[] bean.\nYou can further tune how javadoc:co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer[] is configured, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  elasticsearch:\n    restclient:\n      sniffer:\n        enabled: true\n        interval: \"10m\"\n        delay-after-failure: \"30s\"\n----\n\n\n\n[[data.nosql.elasticsearch.connecting-using-rest.javaapiclient]]\n==== Connecting to Elasticsearch Using ElasticsearchClient\n\nIf you use the `spring-boot-starter-elasticsearch` or have added `co.elastic.clients:elasticsearch-java` to the classpath, Spring Boot will auto-configure and register an javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[] bean.\n\nThe javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[] uses a transport that depends upon the previously described javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[].\nTherefore, the properties described previously can be used to configure the javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[].\nFurthermore, you can define a javadoc:co.elastic.clients.transport.rest5_client.Rest5ClientOptions[] bean to take further control of the behavior of the transport.\n\n\n\n[[data.nosql.elasticsearch.connecting-using-rest.reactiveclient]]\n==== Connecting to Elasticsearch using ReactiveElasticsearchClient\n\n{url-spring-data-elasticsearch-site}[Spring Data Elasticsearch] ships javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient[] for querying Elasticsearch instances in a reactive fashion.\nIf you have Spring Data Elasticsearch and Reactor on the classpath, Spring Boot will auto-configure and register a javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient[].\n\nThe javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient[] uses a transport that depends upon the previously described javadoc:co.elastic.clients.transport.rest5_client.low_level.Rest5Client[].\nTherefore, the properties described previously can be used to configure the javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient[].\nFurthermore, you can define a javadoc:co.elastic.clients.transport.rest5_client.Rest5ClientOptions[] bean to take further control of the behavior of the transport.\n\n\n\n[[data.nosql.elasticsearch.connecting-using-spring-data]]\n=== Connecting to Elasticsearch by Using Spring Data\n\nTo connect to Elasticsearch, an javadoc:co.elastic.clients.elasticsearch.ElasticsearchClient[] bean must be defined,\nauto-configured by Spring Boot or manually provided by the application (see previous sections).\nWith this configuration in place, an\njavadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate[] can be injected like any other Spring bean,\nas shown in the following example:\n\ninclude-code::MyBean[]\n\nIn the presence of `spring-data-elasticsearch` and Reactor, Spring Boot can also auto-configure a xref:data/nosql.adoc#data.nosql.elasticsearch.connecting-using-rest.reactiveclient[`ReactiveElasticsearchClient`] and a javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate[] as beans.\nThey are the reactive equivalent of the other REST clients.\n\n\n\n[[data.nosql.elasticsearch.repositories]]\n=== Spring Data Elasticsearch Repositories\n\nSpring Data includes repository support for Elasticsearch.\nAs with the JPA repositories discussed earlier, the basic principle is that queries are constructed for you automatically based on method names.\n\nIn fact, both Spring Data JPA and Spring Data Elasticsearch share the same common infrastructure.\nYou could take the JPA example from earlier and, assuming that `City` is now an Elasticsearch javadoc:org.springframework.data.elasticsearch.annotations.Document[format=annotation] class rather than a JPA javadoc:jakarta.persistence.Entity[format=annotation], it works in the same way.\n\nRepositories and documents are found through scanning.\nBy default, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\nYou can customize the locations to look for repositories and documents by using javadoc:org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories[format=annotation] and javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] respectively.\n\nTIP: For complete details of Spring Data Elasticsearch, see the {url-spring-data-elasticsearch-docs}[reference documentation].\n\nSpring Boot supports both classic and reactive Elasticsearch repositories, using the javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate[] or javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate[] beans.\nMost likely those beans are auto-configured by Spring Boot given the required dependencies are present.\n\nIf you wish to use your own template for backing the Elasticsearch repositories, you can add your own javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate[] or javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[] javadoc:org.springframework.context.annotation.Bean[format=annotation], as long as it is named `\"elasticsearchTemplate\"`.\nSame applies to javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate[] and javadoc:org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations[], with the bean name `\"reactiveElasticsearchTemplate\"`.\n\nYou can choose to disable the repositories support with the following property:\n\n[configprops,yaml]\n----\n    spring:\n      data:\n        elasticsearch:\n          repositories:\n            enabled: false\n----\n\n\n\n[[data.nosql.cassandra]]\n== Cassandra\n\nhttps://cassandra.apache.org/[Cassandra] is an open source, distributed database management system designed to handle large amounts of data across many commodity servers.\nSpring Boot offers auto-configuration for Cassandra and the abstractions on top of it provided by {url-spring-data-cassandra-site}[Spring Data Cassandra].\nThere is a `spring-boot-starter-data-cassandra` starter for collecting the dependencies in a convenient way.\n\n\n\n[[data.nosql.cassandra.connecting]]\n=== Connecting to Cassandra\n\nYou can inject an auto-configured javadoc:org.springframework.data.cassandra.core.cql.CqlTemplate[], javadoc:org.springframework.data.cassandra.core.CassandraTemplate[], or a Cassandra `CqlSession` instance as you would with any other Spring Bean.\nThe `spring.cassandra.*` properties can be used to customize the connection.\nGenerally, you provide `keyspace-name` and `contact-points` as well the local datacenter name, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  cassandra:\n    keyspace-name: \"mykeyspace\"\n    contact-points: \"cassandrahost1:9042,cassandrahost2:9042\"\n    local-datacenter: \"datacenter1\"\n----\n\nIf the port is the same for all your contact points you can use a shortcut and only specify the host names, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  cassandra:\n    keyspace-name: \"mykeyspace\"\n    contact-points: \"cassandrahost1,cassandrahost2\"\n    local-datacenter: \"datacenter1\"\n----\n\nTIP: Those two examples are identical as the port default to `9042`.\nIf you need to configure the port, use `spring.cassandra.port`.\n\nThe auto-configured `CqlSession` can be configured to use SSL for communication with the server by setting the properties as shown in this example:\n\n[configprops,yaml]\n----\nspring:\n  cassandra:\n    keyspace-name: \"mykeyspace\"\n    contact-points: \"cassandrahost1,cassandrahost2\"\n    local-datacenter: \"datacenter1\"\n    ssl:\n      enabled: true\n----\n\nCustom SSL trust material can be configured in an xref:features/ssl.adoc[SSL bundle] and applied to the `CqlSession` as shown in this example:\n\n[configprops,yaml]\n----\nspring:\n  cassandra:\n    keyspace-name: \"mykeyspace\"\n    contact-points: \"cassandrahost1,cassandrahost2\"\n    local-datacenter: \"datacenter1\"\n    ssl:\n      bundle: \"example\"\n----\n\n\n[NOTE]\n====\nThe Cassandra driver has its own configuration infrastructure that loads an `application.conf` at the root of the classpath.\n\nSpring Boot does not look for such a file by default but can load one using `spring.cassandra.config`.\nIf a property is both present in `+spring.cassandra.*+` and the configuration file, the value in `+spring.cassandra.*+` takes precedence.\n\nFor more advanced driver customizations, you can register an arbitrary number of beans that implement javadoc:org.springframework.boot.cassandra.autoconfigure.DriverConfigLoaderBuilderCustomizer[].\nThe `CqlSession` can be customized with a bean of type javadoc:org.springframework.boot.cassandra.autoconfigure.CqlSessionBuilderCustomizer[].\n====\n\nNOTE: If you use `CqlSessionBuilder` to create multiple `CqlSession` beans, keep in mind the builder is mutable so make sure to inject a fresh copy for each session.\n\nThe following code listing shows how to inject a Cassandra bean:\n\ninclude-code::MyBean[]\n\nIf you add your own javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.data.cassandra.core.CassandraTemplate[], it replaces the default.\n\n\n\n[[data.nosql.cassandra.repositories]]\n=== Spring Data Cassandra Repositories\n\nSpring Data includes basic repository support for Cassandra.\nCurrently, this is more limited than the JPA repositories discussed earlier and needs javadoc:org.springframework.data.cassandra.repository.Query[format=annotation] annotated finder methods.\n\nRepositories and entities are found through scanning.\nBy default, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\nYou can customize the locations to look for repositories and entities by using javadoc:org.springframework.data.cassandra.repository.config.EnableCassandraRepositories[format=annotation] and javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] respectively.\n\nTIP: For complete details of Spring Data Cassandra, see the {url-spring-data-cassandra-docs}[reference documentation].\n\n\n\n[[data.nosql.couchbase]]\n== Couchbase\n\nhttps://www.couchbase.com/[Couchbase] is an open-source, distributed, multi-model NoSQL document-oriented database that is optimized for interactive applications.\nSpring Boot offers auto-configuration for Couchbase and the abstractions on top of it provided by https://github.com/spring-projects/spring-data-couchbase[Spring Data Couchbase].\nThere are `spring-boot-starter-data-couchbase` and `spring-boot-starter-data-couchbase-reactive` starters for collecting the dependencies in a convenient way.\n\n\n\n[[data.nosql.couchbase.connecting]]\n=== Connecting to Couchbase\n\nYou can get a javadoc:com.couchbase.client.java.Cluster[] by adding the Couchbase SDK and some configuration.\nThe `spring.couchbase.*` properties can be used to customize the connection.\nGenerally, you provide the https://docs.couchbase.com/dotnet-sdk/current/howtos/managing-connections.html[connection string] and credentials for authentication. Basic authentication with username and password can be configured as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  couchbase:\n    connection-string: \"couchbase://192.168.1.123\"\n    username: \"user\"\n    password: \"secret\"\n----\n\nhttps://docs.couchbase.com/server/current/manage/manage-security/configure-client-certificates.html[Client certificates] can be used for authentication instead of username and password.\nThe location and password for a Java KeyStore containing client certificates can be configured as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  couchbase:\n    connection-string: \"couchbase://192.168.1.123\"\n    env:\n      ssl:\n        enabled: true\n    authentication:\n      jks:\n        location: \"classpath:client.p12\"\n        password: \"secret\"\n----\n\nPEM-encoded certificates and a private key can be configured as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  couchbase:\n    connection-string: \"couchbase://192.168.1.123\"\n    env:\n      ssl:\n        enabled: true\n    authentication:\n      pem:\n        certificates: \"classpath:client.crt\"\n        private-key: \"classpath:client.key\"\n----\n\nIt is also possible to customize some of the javadoc:com.couchbase.client.java.env.ClusterEnvironment[] settings.\nFor instance, the following configuration changes the timeout to open a new javadoc:com.couchbase.client.java.Bucket[] and enables SSL support with a reference to a configured xref:features/ssl.adoc[SSL bundle]:\n\n[configprops,yaml]\n----\nspring:\n  couchbase:\n    env:\n      timeouts:\n        connect: \"3s\"\n      ssl:\n        bundle: \"example\"\n----\n\nTIP: Check the `spring.couchbase.env.*` properties for more details.\nTo take more control, one or more javadoc:org.springframework.boot.couchbase.autoconfigure.ClusterEnvironmentBuilderCustomizer[] beans can be used.\n\n\n\n[[data.nosql.couchbase.repositories]]\n=== Spring Data Couchbase Repositories\n\nSpring Data includes repository support for Couchbase.\n\nRepositories and documents are found through scanning.\nBy default, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\nYou can customize the locations to look for repositories and documents by using javadoc:org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories[format=annotation] and javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] respectively.\n\nFor complete details of Spring Data Couchbase, see the {url-spring-data-couchbase-docs}[reference documentation].\n\nYou can inject an auto-configured javadoc:org.springframework.data.couchbase.core.CouchbaseTemplate[] instance as you would with any other Spring Bean, provided a javadoc:org.springframework.data.couchbase.CouchbaseClientFactory[] bean is available.\nThis happens when a javadoc:com.couchbase.client.java.Cluster[] is available, as described above, and a bucket name has been specified:\n\n[configprops,yaml]\n----\nspring:\n  data:\n    couchbase:\n      bucket-name: \"my-bucket\"\n----\n\nThe following examples shows how to inject a javadoc:org.springframework.data.couchbase.core.CouchbaseTemplate[] bean:\n\ninclude-code::MyBean[]\n\nThere are a few beans that you can define in your own configuration to override those provided by the auto-configuration:\n\n* A javadoc:org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext[] javadoc:org.springframework.context.annotation.Bean[format=annotation] with a name of `couchbaseMappingContext`.\n* A javadoc:org.springframework.data.convert.CustomConversions[] javadoc:org.springframework.context.annotation.Bean[format=annotation] with a name of `couchbaseCustomConversions`.\n* A javadoc:org.springframework.data.couchbase.core.CouchbaseTemplate[] javadoc:org.springframework.context.annotation.Bean[format=annotation] with a name of `couchbaseTemplate`.\n\nTo avoid hard-coding those names in your own config, you can reuse javadoc:org.springframework.data.couchbase.config.BeanNames[] provided by Spring Data Couchbase.\nFor instance, you can customize the converters to use, as follows:\n\ninclude-code::MyCouchbaseConfiguration[]\n\n\n\n[[data.nosql.ldap]]\n== LDAP\n\nhttps://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[LDAP] (Lightweight Directory Access Protocol) is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over an IP network.\nSpring Boot offers auto-configuration for any compliant LDAP server as well as support for the embedded in-memory LDAP server from https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID].\n\nLDAP abstractions are provided by https://github.com/spring-projects/spring-data-ldap[Spring Data LDAP].\nThere is a `spring-boot-starter-data-ldap` starter for collecting the dependencies in a convenient way.\n\n\n\n[[data.nosql.ldap.connecting]]\n=== Connecting to an LDAP Server\n\nTo connect to an LDAP server, make sure you declare a dependency on the `spring-boot-starter-data-ldap` starter or `spring-ldap-core` and then declare the URLs of your server in your application.properties, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  ldap:\n    urls: \"ldap://myserver:1235\"\n    username: \"admin\"\n    password: \"secret\"\n----\n\nIf you need to customize connection settings, you can use the `spring.ldap.base` and `spring.ldap.base-environment` properties.\n\nAn javadoc:org.springframework.ldap.core.support.LdapContextSource[] is auto-configured based on these settings.\nIf a javadoc:org.springframework.ldap.core.support.DirContextAuthenticationStrategy[] bean is available, it is associated to the auto-configured javadoc:org.springframework.ldap.core.support.LdapContextSource[].\nIf you need to customize it, for instance to use a javadoc:org.springframework.ldap.pool2.factory.PooledContextSource[], you can still inject the auto-configured javadoc:org.springframework.ldap.core.support.LdapContextSource[].\nMake sure to flag your customized javadoc:org.springframework.ldap.core.ContextSource[] as javadoc:org.springframework.context.annotation.Primary[format=annotation] so that the auto-configured javadoc:org.springframework.ldap.core.LdapTemplate[] uses it.\n\n\n\n[[data.nosql.ldap.repositories]]\n=== Spring Data LDAP Repositories\n\nSpring Data includes repository support for LDAP.\n\nRepositories and documents are found through scanning.\nBy default, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\nYou can customize the locations to look for repositories and documents by using javadoc:org.springframework.data.ldap.repository.config.EnableLdapRepositories[format=annotation] and javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] respectively.\n\nTIP: For complete details of Spring Data LDAP, see the {url-spring-data-ldap-docs}[reference documentation].\n\nYou can also inject an auto-configured javadoc:org.springframework.ldap.core.LdapTemplate[] instance as you would with any other Spring Bean, as shown in the following example:\n\n\ninclude-code::MyBean[]\n\n\n\n[[data.nosql.ldap.embedded]]\n=== Embedded In-memory LDAP Server\n\nFor testing purposes, Spring Boot supports auto-configuration of an in-memory LDAP server from https://ldap.com/unboundid-ldap-sdk-for-java/[UnboundID].\nTo configure the server, add a dependency to `com.unboundid:unboundid-ldapsdk` and declare a configprop:spring.ldap.embedded.base-dn[] property, as follows:\n\n[configprops,yaml]\n----\nspring:\n  ldap:\n    embedded:\n      base-dn: \"dc=spring,dc=io\"\n----\n\n[NOTE]\n====\nIt is possible to define multiple base-dn values, however, since distinguished names usually contain commas, they must be defined using the correct notation.\n\nIn yaml files, you can use the yaml list notation. In properties files, you must include the index as part of the property name:\n\n[configprops,yaml]\n----\nspring.ldap.embedded.base-dn:\n- \"dc=spring,dc=io\"\n- \"dc=vmware,dc=com\"\n----\n====\n\nBy default, the server starts on a random port and triggers the regular LDAP support.\nThere is no need to specify a configprop:spring.ldap.urls[] property.\n\nIf there is a `schema.ldif` file on your classpath, it is used to initialize the server.\nIf you want to load the initialization script from a different resource, you can also use the configprop:spring.ldap.embedded.ldif[] property.\n\nBy default, a standard schema is used to validate `LDIF` files.\nYou can turn off validation altogether by setting the configprop:spring.ldap.embedded.validation.enabled[] property.\nIf you have custom attributes, you can use configprop:spring.ldap.embedded.validation.schema[] to define your custom attribute types or object classes.\n\n\n\n[[data.nosql.ldap.embedded.ssl]]\n==== SSL\n\nThe in-memory LDAP server supports SSL (LDAPS).\nTo enable SSL, configure the xref:features/ssl.adoc[SSL bundle] to use by setting the configprop:spring.ldap.embedded.ssl.bundle[] property, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  ldap:\n    embedded:\n      ssl:\n        bundle: \"example\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/data/sql.adoc",
    "content": "[[data.sql]]\n= SQL Databases\n\nThe {url-spring-framework-site}[Spring Framework] provides extensive support for working with SQL databases, from direct JDBC access using javadoc:org.springframework.jdbc.core.simple.JdbcClient[] or javadoc:org.springframework.jdbc.core.JdbcTemplate[] to complete \"`object relational mapping`\" technologies such as Hibernate.\n{url-spring-data-site}[Spring Data] provides an additional level of functionality: creating javadoc:org.springframework.data.repository.Repository[] implementations directly from interfaces and using conventions to generate queries from your method names.\n\n\n\n[[data.sql.datasource]]\n== Configure a DataSource\n\nJava's javadoc:javax.sql.DataSource[] interface provides a standard method of working with database connections.\nTraditionally, a javadoc:javax.sql.DataSource[] uses a `URL` along with some credentials to establish a database connection.\n\nTIP: See the xref:how-to:data-access.adoc#howto.data-access.configure-custom-datasource[] section of the \"`How-to Guides`\" for more advanced examples, typically to take full control over the configuration of the DataSource.\n\n\n\n[[data.sql.datasource.embedded]]\n=== Embedded Database Support\n\nIt is often convenient to develop applications by using an in-memory embedded database.\nObviously, in-memory databases do not provide persistent storage.\nYou need to populate your database when your application starts and be prepared to throw away data when your application ends.\n\nTIP: The \"`How-to Guides`\" section includes a xref:how-to:data-initialization.adoc[section on how to initialize a database].\n\nSpring Boot can auto-configure embedded https://www.h2database.com[H2], https://hsqldb.org/[HSQL], and https://db.apache.org/derby/[Derby] (deprecated) databases.\nYou need not provide any connection URLs.\nYou need only include a build dependency to the embedded database that you want to use.\nIf there are multiple embedded databases on the classpath, set the configprop:spring.datasource.embedded-database-connection[] configuration property to control which one is used.\nSetting the property to `none` disables auto-configuration of an embedded database.\n\n[NOTE]\n====\nIf you are using this feature in your tests, you may notice that the same database is reused by your whole test suite regardless of the number of application contexts that you use.\nIf you want to make sure that each context has a separate embedded database, you should set `spring.datasource.generate-unique-name` to `true`.\n====\n\nFor example, the typical POM dependencies would be as follows:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.springframework.boot</groupId>\n\t<artifactId>spring-boot-starter-data-jpa</artifactId>\n</dependency>\n<dependency>\n\t<groupId>org.hsqldb</groupId>\n\t<artifactId>hsqldb</artifactId>\n\t<scope>runtime</scope>\n</dependency>\n----\n\nNOTE: You need a dependency on `spring-jdbc` for an embedded database to be auto-configured.\nIn this example, it is pulled in transitively through `spring-boot-starter-data-jpa`.\n\nTIP: If, for whatever reason, you do configure the connection URL for an embedded database, take care to ensure that the database's automatic shutdown is disabled.\nIf you use H2, you should use `DB_CLOSE_ON_EXIT=FALSE` to do so.\nIf you use HSQLDB, you should ensure that `shutdown=true` is not used.\nDisabling the database's automatic shutdown lets Spring Boot control when the database is closed, thereby ensuring that it happens once access to the database is no longer needed.\n\n\n\n[[data.sql.datasource.production]]\n=== Connection to a Production Database\n\nProduction database connections can also be auto-configured by using a pooling javadoc:javax.sql.DataSource[].\n\n\n\n[[data.sql.datasource.configuration]]\n=== DataSource Configuration\n\nDataSource configuration is controlled by external configuration properties in `+spring.datasource.*+`.\nFor example, you might declare the following section in `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  datasource:\n    url: \"jdbc:mysql://localhost/test\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n----\n\nNOTE: You should at least specify the URL by setting the configprop:spring.datasource.url[] property.\nOtherwise, Spring Boot tries to auto-configure an embedded database.\n\nTIP: Spring Boot can deduce the JDBC driver class for most databases from the URL.\nIf you need to specify a specific class, you can use the configprop:spring.datasource.driver-class-name[] property.\n\nNOTE: For a pooling javadoc:javax.sql.DataSource[] to be created, we need to be able to verify that a valid javadoc:java.sql.Driver[] class is available, so we check for that before doing anything.\nIn other words, if you set `spring.datasource.driver-class-name=com.mysql.jdbc.Driver`, then that class has to be loadable.\n\nSee javadoc:org.springframework.boot.jdbc.autoconfigure.DataSourceProperties[] API documentation for more of the supported options.\nThese are the standard options that work regardless of xref:data/sql.adoc#data.sql.datasource.connection-pool[the actual implementation].\nIt is also possible to fine-tune implementation-specific settings by using their respective prefix (`+spring.datasource.hikari.*+`, `+spring.datasource.tomcat.*+`, `+spring.datasource.dbcp2.*+`, and `+spring.datasource.oracleucp.*+`).\nSee the documentation of the connection pool implementation you are using for more details.\n\nFor instance, if you use the {url-tomcat-docs}/jdbc-pool.html#Common_Attributes[Tomcat connection pool], you could customize many additional settings, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  datasource:\n    tomcat:\n      max-wait: 10000\n      max-active: 50\n      test-on-borrow: true\n----\n\nThis will set the pool to wait 10000ms before throwing an exception if no connection is available, limit the maximum number of connections to 50 and validate the connection before borrowing it from the pool.\n\n\n\n[[data.sql.datasource.connection-pool]]\n=== Supported Connection Pools\n\nSpring Boot uses the following algorithm for choosing a specific implementation:\n\n. We prefer https://github.com/brettwooldridge/HikariCP[HikariCP] for its performance and concurrency.\nIf HikariCP is available, we always choose it.\n. Otherwise, if the Tomcat pooling javadoc:javax.sql.DataSource[] is available, we use it.\n. Otherwise, if https://commons.apache.org/proper/commons-dbcp/[Commons DBCP2] is available, we use it.\n. If none of HikariCP, Tomcat, and DBCP2 are available and if Oracle UCP is available, we use it.\n\nNOTE: If you use the `spring-boot-starter-jdbc` or `spring-boot-starter-data-jpa` starters, you automatically get a dependency to HikariCP.\n\nYou can bypass that algorithm completely and specify the connection pool to use by setting the configprop:spring.datasource.type[] property.\nThis is especially important if you run your application in a Tomcat container, as `tomcat-jdbc` is provided by default.\n\nAdditional connection pools can always be configured manually, using javadoc:org.springframework.boot.jdbc.DataSourceBuilder[].\nIf you define your own javadoc:javax.sql.DataSource[] bean, auto-configuration does not occur.\nThe following connection pools are supported by javadoc:org.springframework.boot.jdbc.DataSourceBuilder[]:\n\n* HikariCP\n* Tomcat pooling javadoc:javax.sql.DataSource[]\n* Commons DBCP2\n* Oracle UCP & `OracleDataSource`\n* Spring Framework's javadoc:org.springframework.jdbc.datasource.SimpleDriverDataSource[]\n* H2 javadoc:org.h2.jdbcx.JdbcDataSource[]\n* PostgreSQL javadoc:org.postgresql.ds.PGSimpleDataSource[]\n* C3P0\n* Vibur\n\n\n\n[[data.sql.datasource.jndi]]\n=== Connection to a JNDI DataSource\n\nIf you deploy your Spring Boot application to an Application Server, you might want to configure and manage your DataSource by using your Application Server's built-in features and access it by using JNDI.\n\nThe configprop:spring.datasource.jndi-name[] property can be used as an alternative to the configprop:spring.datasource.url[], configprop:spring.datasource.username[], and configprop:spring.datasource.password[] properties to access the javadoc:javax.sql.DataSource[] from a specific JNDI location.\nFor example, the following section in `application.properties` shows how you can access a JBoss AS defined javadoc:javax.sql.DataSource[]:\n\n[configprops,yaml]\n----\nspring:\n  datasource:\n    jndi-name: \"java:jboss/datasources/customers\"\n----\n\n\n\n[[data.sql.jdbc-template]]\n== Using JdbcTemplate\n\nSpring's javadoc:org.springframework.jdbc.core.JdbcTemplate[] and javadoc:org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate[] classes are auto-configured, and you can autowire them directly into your own beans, as shown in the following example:\n\ninclude-code::MyBean[]\n\nYou can customize some properties of the template by using the `spring.jdbc.template.*` properties, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  jdbc:\n    template:\n      max-rows: 500\n----\n\nIf tuning of SQL exceptions is required, you can define your own `SQLExceptionTranslator` bean so that it is associated with the auto-configured `JdbcTemplate`.\n\nNOTE: The javadoc:org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate[] reuses the same javadoc:org.springframework.jdbc.core.JdbcTemplate[] instance behind the scenes.\nIf more than one javadoc:org.springframework.jdbc.core.JdbcTemplate[] is defined and no primary candidate exists, the javadoc:org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate[] is not auto-configured.\n\n\n\n[[data.sql.jdbc-client]]\n== Using JdbcClient\n\nSpring's javadoc:org.springframework.jdbc.core.simple.JdbcClient[] is auto-configured based on the presence of a javadoc:org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate[].\nYou can inject it directly in your own beans as well, as shown in the following example:\n\ninclude-code::MyBean[]\n\nIf you rely on auto-configuration to create the underlying javadoc:org.springframework.jdbc.core.JdbcTemplate[], any customization using `spring.jdbc.template.*` properties is taken into account in the client as well.\n\n\n\n[[data.sql.jpa-and-spring-data]]\n== JPA and Spring Data JPA\n\nThe Java Persistence API is a standard technology that lets you \"`map`\" objects to relational databases.\nThe `spring-boot-starter-data-jpa` POM provides a quick way to get started.\nIt provides the following key dependencies:\n\n* Hibernate: One of the most popular JPA implementations.\n* Spring Data JPA: Helps you to implement JPA-based repositories.\n* Spring ORM: Core ORM support from the Spring Framework.\n\nTIP: We do not go into too many details of JPA or {url-spring-data-site}[Spring Data] here.\nYou can follow the https://spring.io/guides/gs/accessing-data-jpa/[Accessing Data with JPA] guide from https://spring.io and read the {url-spring-data-jpa-site}[Spring Data JPA] and https://hibernate.org/orm/documentation/[Hibernate] reference documentation.\n\n\n\n[[data.sql.jpa-and-spring-data.entity-classes]]\n=== Entity Classes\n\nTraditionally, JPA \"`Entity`\" classes are specified in a `persistence.xml` file.\nWith Spring Boot, this file is not necessary and \"`Entity Scanning`\" is used instead.\nBy default the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are scanned.\n\nAny classes annotated with javadoc:jakarta.persistence.Entity[format=annotation], javadoc:jakarta.persistence.Embeddable[format=annotation], or javadoc:jakarta.persistence.MappedSuperclass[format=annotation] are considered.\nA typical entity class resembles the following example:\n\ninclude-code::City[]\n\nTIP: You can customize entity scanning locations by using the javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation] annotation.\nSee the xref:how-to:data-access.adoc#howto.data-access.separate-entity-definitions-from-spring-configuration[] section of the \"`How-to Guides`\".\n\n\n\n[[data.sql.jpa-and-spring-data.repositories]]\n=== Spring Data JPA Repositories\n\n{url-spring-data-jpa-site}[Spring Data JPA] repositories are interfaces that you can define to access data.\nJPA queries are created automatically from your method names.\nFor example, a `CityRepository` interface might declare a `findAllByState(String state)` method to find all the cities in a given state.\n\nFor more complex queries, you can annotate your method with Spring Data's javadoc:org.springframework.data.jpa.repository.Query[] annotation.\n\nSpring Data repositories usually extend from the javadoc:org.springframework.data.repository.Repository[] or javadoc:org.springframework.data.repository.CrudRepository[] interfaces.\nIf you use auto-configuration, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are searched for repositories.\n\nTIP: You can customize the locations to look for repositories using javadoc:org.springframework.data.jpa.repository.config.EnableJpaRepositories[format=annotation].\n\nThe following example shows a typical Spring Data repository interface definition:\n\ninclude-code::CityRepository[]\n\nSpring Data JPA repositories support three different modes of bootstrapping: default, deferred, and lazy.\nTo enable deferred or lazy bootstrapping, set the configprop:spring.data.jpa.repositories.bootstrap-mode[] property to `deferred` or `lazy` respectively.\nWhen using deferred or lazy bootstrapping, the auto-configured javadoc:org.springframework.boot.jpa.EntityManagerFactoryBuilder[] will use the context's javadoc:org.springframework.core.task.AsyncTaskExecutor[], if any, as the bootstrap executor.\nIf more than one exists, the one named `applicationTaskExecutor` will be used.\n\n[NOTE]\n====\nWhen using deferred or lazy bootstrapping, make sure to defer any access to the JPA infrastructure after the application context bootstrap phase.\nYou can use javadoc:org.springframework.beans.factory.SmartInitializingSingleton[] to invoke any initialization that requires the JPA infrastructure.\nFor JPA components (such as converters) that are created as Spring beans, use javadoc:org.springframework.beans.factory.ObjectProvider[] to delay the resolution of dependencies, if any.\n====\n\nTIP: We have barely scratched the surface of Spring Data JPA.\nFor complete details, see the {url-spring-data-jpa-docs}[Spring Data JPA reference documentation].\n\n\n\n[[data.sql.jpa-and-spring-data.envers-repositories]]\n=== Spring Data Envers Repositories\n\nIf {url-spring-data-envers-site}[Spring Data Envers] is available, JPA repositories are auto-configured to support typical Envers queries.\n\nTo use Spring Data Envers, make sure your repository extends from javadoc:org.springframework.data.repository.history.RevisionRepository[] as shown in the following example:\n\ninclude-code::CountryRepository[]\n\nNOTE: For more details, check the {url-spring-data-jpa-docs}/envers.html[Spring Data Envers reference documentation].\n\n\n\n[[data.sql.jpa-and-spring-data.creating-and-dropping]]\n=== Creating and Dropping JPA Databases\n\nBy default, JPA databases are automatically created *only* if you use an embedded database, that is H2, HSQL, or Derby (deprecated).\nYou can explicitly configure JPA settings by using `+spring.jpa.*+` properties.\nFor example, to create and drop tables you can add the following line to your `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  jpa:\n    hibernate.ddl-auto: \"create-drop\"\n----\n\nNOTE: Hibernate's own internal property name for this (if you happen to remember it better) is `hibernate.hbm2ddl.auto`.\nYou can set it, along with other Hibernate native properties, by using `+spring.jpa.properties.*+` (the prefix is stripped before adding them to the entity manager).\nThe following line shows an example of setting JPA properties for Hibernate:\n\n[configprops,yaml]\n----\nspring:\n  jpa:\n    properties:\n      hibernate:\n        \"globally_quoted_identifiers\": \"true\"\n----\n\nThe line in the preceding example passes a value of `true` for the `hibernate.globally_quoted_identifiers` property to the Hibernate entity manager.\n\nBy default, the DDL execution (or validation) is deferred until the javadoc:org.springframework.context.ApplicationContext[] has started.\n\n\n\n[[data.sql.jpa-and-spring-data.open-entity-manager-in-view]]\n=== Open EntityManager in View\n\nIf you are running a web application, Spring Boot by default registers javadoc:org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor[] to apply the \"`Open EntityManager in View`\" pattern, to allow for lazy loading in web views.\nIf you do not want this behavior, you should set `spring.jpa.open-in-view` to `false` in your `application.properties`.\n\n\n\n[[data.sql.jdbc]]\n== Spring Data JDBC\n\nSpring Data includes repository support for JDBC and will automatically generate SQL for the methods on javadoc:org.springframework.data.repository.CrudRepository[].\nFor more advanced queries, a javadoc:org.springframework.data.jdbc.repository.query.Query[format=annotation] annotation is provided.\n\nSpring Boot will auto-configure Spring Data's JDBC repositories when the necessary dependencies are on the classpath.\nThey can be added to your project with a single dependency on `spring-boot-starter-data-jdbc`.\nIf necessary, you can take control of Spring Data JDBC's configuration by adding the javadoc:org.springframework.data.jdbc.repository.config.EnableJdbcRepositories[format=annotation] annotation or an javadoc:org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration[] subclass to your application.\n\nIf you're using Spring Data JDBC with xref:packaging/aot.adoc[ahead-of-time processing] (targeting either the JVM or a native image), some additional configuration is recommended.\nTo prevent the need for a DB connection during AOT processing, define a `JdbcDialect` bean that's appropriate for your application's database.\nFor example, if you're using Postgres, define a `JdbcPostgresDialect` bean.\n\nTIP: For complete details of Spring Data JDBC, see the {url-spring-data-jdbc-docs}[reference documentation].\n\n\n\n[[data.sql.h2-web-console]]\n== Using H2's Web Console\n\nThe https://www.h2database.com[H2 database] provides a https://www.h2database.com/html/quickstart.html#h2_console[browser-based console] that Spring Boot can auto-configure for you.\nThe console is auto-configured when the following conditions are met:\n\n* You are developing a servlet-based web application.\n* `org.springframework.boot:spring-boot-h2console` is on the classpath.\n* You are using xref:using/devtools.adoc[Spring Boot's developer tools].\n\nTIP: If you are not using Spring Boot's developer tools but would still like to make use of H2's console, you can configure the configprop:spring.h2.console.enabled[] property with a value of `true`.\n\nNOTE: The H2 console is only intended for use during development, so you should take care to ensure that `spring.h2.console.enabled` is not set to `true` in production.\n\n\n\n[[data.sql.h2-web-console.custom-path]]\n=== Changing the H2 Console's Path\n\nBy default, the console is available at `/h2-console`.\nYou can customize the console's path by using the configprop:spring.h2.console.path[] property.\n\n\n\n[[data.sql.h2-web-console.spring-security]]\n=== Accessing the H2 Console in a Secured Application\n\nH2 Console uses frames and, as it is intended for development only, does not implement CSRF protection measures.\nIf your application uses Spring Security, you need to configure it to\n\n* disable CSRF protection for requests against the console,\n* set the header `X-Frame-Options` to `SAMEORIGIN` on responses from the console.\n\nMore information on {url-spring-security-docs}/features/exploits/csrf.html[CSRF] and the header {url-spring-security-docs}/features/exploits/headers.html#headers-frame-options[X-Frame-Options] can be found in the Spring Security Reference Guide.\n\nIn simple setups, a javadoc:org.springframework.security.web.SecurityFilterChain[] like the following can be used:\n\ninclude-code::DevProfileSecurityConfiguration[tag=!customizer]\n\nWARNING: The H2 console is only intended for use during development.\nIn production, disabling CSRF protection or allowing frames for a website may create severe security risks.\n\nTIP: `PathRequest.toH2Console()` returns the correct request matcher also when the console's path has been customized.\n\n\n\n[[data.sql.jooq]]\n== Using jOOQ\n\njOOQ Object Oriented Querying (https://www.jooq.org/[jOOQ]) is a popular product from https://www.datageekery.com/[Data Geekery] which generates Java code from your database and lets you build type-safe SQL queries through its fluent API.\nBoth the commercial and open source editions can be used with Spring Boot.\njOOQ requires Java 21 or later.\n\n\n\n[[data.sql.jooq.codegen]]\n=== Code Generation\n\nIn order to use jOOQ type-safe queries, you need to generate Java classes from your database schema.\nYou can follow the instructions in the {url-jooq-docs}/#jooq-in-7-steps-step3[jOOQ user manual].\nIf you use the `jooq-codegen-maven` plugin and you also use the `spring-boot-starter-parent` \"`parent POM`\", you can safely omit the plugin's `<version>` tag.\nYou can also use Spring Boot-defined version variables (such as `h2.version`) to declare the plugin's database dependency.\nThe following listing shows an example:\n\n[source,xml]\n----\n<plugin>\n\t<groupId>org.jooq</groupId>\n\t<artifactId>jooq-codegen-maven</artifactId>\n\t<executions>\n\t\t...\n\t</executions>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<version>${h2.version}</version>\n\t\t</dependency>\n\t</dependencies>\n\t<configuration>\n\t\t<jdbc>\n\t\t\t<driver>org.h2.Driver</driver>\n\t\t\t<url>jdbc:h2:~/yourdatabase</url>\n\t\t</jdbc>\n\t\t<generator>\n\t\t\t...\n\t\t</generator>\n\t</configuration>\n</plugin>\n----\n\n\n\n[[data.sql.jooq.dslcontext]]\n=== Using DSLContext\n\nThe fluent API offered by jOOQ is initiated through the javadoc:org.jooq.DSLContext[] interface.\nSpring Boot auto-configures a javadoc:org.jooq.DSLContext[] as a Spring Bean and connects it to your application javadoc:javax.sql.DataSource[].\nTo use the javadoc:org.jooq.DSLContext[], you can inject it, as shown in the following example:\n\ninclude-code::MyBean[tag=!method]\n\nTIP: The jOOQ manual tends to use a variable named `create` to hold the javadoc:org.jooq.DSLContext[].\n\nYou can then use the javadoc:org.jooq.DSLContext[] to construct your queries, as shown in the following example:\n\ninclude-code::MyBean[tag=method]\n\n\n\n[[data.sql.jooq.sqldialect]]\n=== jOOQ SQL Dialect\n\nUnless the configprop:spring.jooq.sql-dialect[] property has been configured, Spring Boot determines the SQL dialect to use for your datasource.\nIf Spring Boot could not detect the dialect, it uses `DEFAULT`.\n\nNOTE: Spring Boot can only auto-configure dialects supported by the open source version of jOOQ.\n\n\n\n[[data.sql.jooq.customizing]]\n=== Customizing jOOQ\n\nMore advanced customizations can be achieved by defining your own javadoc:org.springframework.boot.jooq.autoconfigure.DefaultConfigurationCustomizer[] bean that will be invoked prior to creating the javadoc:org.jooq.Configuration[] javadoc:org.springframework.context.annotation.Bean[format=annotation].\nThis takes precedence to anything that is applied by the auto-configuration.\n\nYou can also create your own javadoc:org.jooq.Configuration[] javadoc:org.springframework.context.annotation.Bean[format=annotation] if you want to take complete control of the jOOQ configuration.\n\n\n\n[[data.sql.r2dbc]]\n== Using R2DBC\n\nThe Reactive Relational Database Connectivity (https://r2dbc.io[R2DBC]) project brings reactive programming APIs to relational databases.\nR2DBC's javadoc:io.r2dbc.spi.Connection[] provides a standard method of working with non-blocking database connections.\nConnections are provided by using a javadoc:io.r2dbc.spi.ConnectionFactory[], similar to a javadoc:javax.sql.DataSource[] with jdbc.\n\njavadoc:io.r2dbc.spi.ConnectionFactory[] configuration is controlled by external configuration properties in `+spring.r2dbc.*+`.\nFor example, you might declare the following section in `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  r2dbc:\n    url: \"r2dbc:postgresql://localhost/test\"\n    username: \"dbuser\"\n    password: \"dbpass\"\n----\n\nTIP: You do not need to specify a driver class name, since Spring Boot obtains the driver from R2DBC's Connection Factory discovery.\n\nNOTE: At least the url should be provided.\nInformation specified in the URL takes precedence over individual properties, that is `name`, `username`, `password` and pooling options.\n\nTIP: The \"`How-to Guides`\" section includes a xref:how-to:data-initialization.adoc#howto.data-initialization.using-basic-sql-scripts[section on how to initialize a database].\n\nTo customize the connections created by a javadoc:io.r2dbc.spi.ConnectionFactory[], that is, set specific parameters that you do not want (or cannot) configure in your central database configuration, you can use a javadoc:org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer[] javadoc:org.springframework.context.annotation.Bean[format=annotation].\nThe following example shows how to manually override the database port while the rest of the options are taken from the application configuration:\n\ninclude-code::MyR2dbcConfiguration[]\n\nThe following examples show how to set some PostgreSQL connection options:\n\ninclude-code::MyPostgresR2dbcConfiguration[]\n\nWhen a javadoc:io.r2dbc.spi.ConnectionFactory[] bean is available, the regular JDBC javadoc:javax.sql.DataSource[] auto-configuration backs off.\nIf you want to retain the JDBC javadoc:javax.sql.DataSource[] auto-configuration, and are comfortable with the risk of using the blocking JDBC API in a reactive application, add `@Import(DataSourceAutoConfiguration.class)` on a javadoc:org.springframework.context.annotation.Configuration[format=annotation] class in your application to re-enable it.\n\n\n\n[[data.sql.r2dbc.embedded]]\n=== Embedded Database Support\n\nSimilarly to xref:data/sql.adoc#data.sql.datasource.embedded[the JDBC support], Spring Boot can automatically configure an embedded database for reactive usage.\nYou need not provide any connection URLs.\nYou need only include a build dependency to the embedded database that you want to use, as shown in the following example:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>io.r2dbc</groupId>\n\t<artifactId>r2dbc-h2</artifactId>\n\t<scope>runtime</scope>\n</dependency>\n----\n\n[NOTE]\n====\nIf you are using this feature in your tests, you may notice that the same database is reused by your whole test suite regardless of the number of application contexts that you use.\nIf you want to make sure that each context has a separate embedded database, you should set `spring.r2dbc.generate-unique-name` to `true`.\n====\n\n\n\n[[data.sql.r2dbc.using-database-client]]\n=== Using DatabaseClient\n\nA javadoc:org.springframework.r2dbc.core.DatabaseClient[] bean is auto-configured, and you can autowire it directly into your own beans, as shown in the following example:\n\ninclude-code::MyBean[]\n\n\n\n[[data.sql.r2dbc.repositories]]\n=== Spring Data R2DBC Repositories\n\nhttps://spring.io/projects/spring-data-r2dbc[Spring Data R2DBC] repositories are interfaces that you can define to access data.\nQueries are created automatically from your method names.\nFor example, a `CityRepository` interface might declare a `findAllByState(String state)` method to find all the cities in a given state.\n\nFor more complex queries, you can annotate your method with Spring Data's javadoc:org.springframework.data.r2dbc.repository.Query[format=annotation] annotation.\n\nSpring Data repositories usually extend from the javadoc:org.springframework.data.repository.Repository[] or javadoc:org.springframework.data.repository.CrudRepository[] interfaces.\nIf you use auto-configuration, the xref:using/auto-configuration.adoc#using.auto-configuration.packages[auto-configuration packages] are searched for repositories.\n\nThe following example shows a typical Spring Data repository interface definition:\n\ninclude-code::CityRepository[]\n\nTIP: We have barely scratched the surface of Spring Data R2DBC. For complete details, see the {url-spring-data-r2dbc-docs}[Spring Data R2DBC reference documentation].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/aop.adoc",
    "content": "[[features.aop]]\n= Aspect-Oriented Programming\n\nSpring Boot provides auto-configuration for aspect-oriented programming (AOP).\nYou can learn more about AOP with Spring in the {url-spring-framework-docs}/core/aop-api.html[Spring Framework reference documentation].\n\nBy default, Spring Boot's auto-configuration configures Spring AOP to use CGLib proxies.\nTo use JDK proxies instead, set configprop:spring.aop.proxy-target-class[] to `false`.\n\nIf AspectJ is on the classpath, Spring Boot's auto-configuration will automatically enable AspectJ auto proxy such that javadoc:org.springframework.context.annotation.EnableAspectJAutoProxy[format=annotation] is not required.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc",
    "content": "[[features.dev-services]]\n= Development-time Services\n\nDevelopment-time services provide external dependencies needed to run the application while developing it.\nThey are only supposed to be used while developing and are disabled when the application is deployed.\n\nSpring Boot offers support for two development time services, Docker Compose and Testcontainers.\nThe next sections will provide more details about them.\n\n[[features.dev-services.docker-compose]]\n== Docker Compose Support\n\nDocker Compose is a popular technology that can be used to define and manage multiple containers for services that your application needs.\nA `compose.yml` file is typically created next to your application which defines and configures service containers.\n\nA typical workflow with Docker Compose is to run `docker compose up`, work on your application with it connecting to started services, then run `docker compose down` when you are finished.\n\nThe `spring-boot-docker-compose` module can be included in a project to provide support for working with containers using Docker Compose.\nAdd the module dependency to your build, as shown in the following listings for Maven and Gradle:\n\n.Maven\n[source,xml]\n----\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-docker-compose</artifactId>\n\t\t<optional>true</optional>\n\t</dependency>\n</dependencies>\n----\n\n.Gradle\n[source,gradle]\n----\ndependencies {\n\tdevelopmentOnly(\"org.springframework.boot:spring-boot-docker-compose\")\n}\n----\n\nWhen this module is included as a dependency Spring Boot will do the following:\n\n* Search for a `compose.yml` and other common compose filenames in your working directory\n* Call `docker compose up` with the discovered `compose.yml`\n* Create service connection beans for each supported container\n* Call `docker compose stop` when the application is shutdown\n\nIf the Docker Compose services are already running when starting the application, Spring Boot will only create the service connection beans for each supported container.\nIt will not call `docker compose up` again and it will not call `docker compose stop` when the application is shutdown.\n\nTIP: Repackaged archives do not contain Spring Boot's Docker Compose by default.\nIf you want to use this support, you need to include it.\nWhen using the Maven plugin, set the `excludeDockerCompose` property to `false`.\nWhen using the Gradle plugin, xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.including-development-only-dependencies[configure the task's classpath to include the `developmentOnly` configuration].\n\n\n\n[[features.dev-services.docker-compose.prerequisites]]\n=== Prerequisites\n\nYou need to have the `docker` and `docker compose` (or `docker-compose`) CLI applications on your path.\nThe minimum supported Docker Compose version is 2.2.0.\n\n\n\n[[features.dev-services.docker-compose.service-connections]]\n=== Service Connections\n\nA service connection is a connection to any remote service.\nSpring Boot’s auto-configuration can consume the details of a service connection and use them to establish a connection to a remote service.\nWhen doing so, the connection details take precedence over any connection-related configuration properties.\n\nWhen using Spring Boot’s Docker Compose support, service connections are established to the port mapped by the container.\n\nNOTE: Docker compose is usually used in such a way that the ports inside the container are mapped to ephemeral ports on your computer.\nFor example, a Postgres server may run inside the container using port 5432 but be mapped to a totally different port locally.\nThe service connection will always discover and use the locally mapped port.\n\nService connections are established by using the image name of the container.\nThe following service connections are currently supported:\n\n\n|===\n| Connection Details | Matched on\n\n| javadoc:org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails[]\n| Containers named \"symptoma/activemq\" or \"apache/activemq-classic\"\n\n| javadoc:org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails[]\n| Containers named \"apache/activemq-artemis\"\n\n| javadoc:org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails[]\n| Containers named \"cassandra\"\n\n| javadoc:org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails[]\n| Containers named \"elasticsearch\"\n\n| javadoc:org.springframework.boot.hazelcast.autoconfigure.HazelcastConnectionDetails[]\n| Containers named \"hazelcast/hazelcast\".\n\n| javadoc:org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails[]\n| Containers named \"clickhouse/clickhouse-server\", \"gvenzl/oracle-free\", \"gvenzl/oracle-xe\", \"mariadb\", \"mssql/server\", \"mysql\", or \"postgres\"\n\n| javadoc:org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails[]\n| Containers named \"osixia/openldap\", \"lldap/lldap\"\n\n| javadoc:org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails[]\n| Containers named \"mongo\"\n\n| javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[]\n| Containers named \"neo4j\"\n\n| javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails[]\n| Containers named \"otel/opentelemetry-collector-contrib\", \"grafana/otel-lgtm\"\n\n| javadoc:org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails[]\n| Containers named \"otel/opentelemetry-collector-contrib\", \"grafana/otel-lgtm\"\n\n| javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails[]\n| Containers named \"otel/opentelemetry-collector-contrib\", \"grafana/otel-lgtm\"\n\n| javadoc:org.springframework.boot.pulsar.autoconfigure.PulsarConnectionDetails[]\n| Containers named \"apachepulsar/pulsar\"\n\n| javadoc:org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails[]\n| Containers named \"clickhouse/clickhouse-server\", \"gvenzl/oracle-free\", \"gvenzl/oracle-xe\", \"mariadb\", \"mssql/server\", \"mysql\", or \"postgres\"\n\n| javadoc:org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails[]\n| Containers named \"rabbitmq\" with container port 5672 mapped\n\n| javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[]\n| Containers named \"rabbitmq\" with container port 5552 mapped\n\n| javadoc:org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails[]\n| Containers named \"redis\", \"redis/redis-stack\" or \"redis/redis-stack-server\"\n\n| javadoc:org.springframework.boot.zipkin.autoconfigure.ZipkinConnectionDetails[]\n| Containers named \"openzipkin/zipkin\".\n|===\n\n\n\n[[features.dev-services.docker-compose.ssl]]\n=== SSL support\n\nSome images come with SSL enabled out of the box, or maybe you want to enable SSL for the container to mirror your production setup.\nSpring Boot supports SSL configuration for supported service connections.\nPlease note that you still have to enable SSL on the service which is running inside the container yourself, this feature only configures SSL on the client side in your application.\n\nSSL is supported for the following service connections:\n\n* Cassandra\n* Elasticsearch\n* MongoDB\n* RabbitMQ\n* RabbitMQ Streams\n* Redis\n\nTo enable SSL support for a service, you can use https://docs.docker.com/reference/compose-file/services/#labels[service labels].\n\nFor JKS based keystores and truststores, you can use the following container labels:\n\n* `org.springframework.boot.sslbundle.jks.key.alias`\n* `org.springframework.boot.sslbundle.jks.key.password`\n* `org.springframework.boot.sslbundle.jks.options.ciphers`\n* `org.springframework.boot.sslbundle.jks.options.enabled-protocols`\n* `org.springframework.boot.sslbundle.jks.protocol`\n\n* `org.springframework.boot.sslbundle.jks.keystore.type`\n* `org.springframework.boot.sslbundle.jks.keystore.provider`\n* `org.springframework.boot.sslbundle.jks.keystore.location`\n* `org.springframework.boot.sslbundle.jks.keystore.password`\n\n* `org.springframework.boot.sslbundle.jks.truststore.type`\n* `org.springframework.boot.sslbundle.jks.truststore.provider`\n* `org.springframework.boot.sslbundle.jks.truststore.location`\n* `org.springframework.boot.sslbundle.jks.truststore.password`\n\nThese labels mirror the properties available for xref:reference:features/ssl.adoc#features.ssl.jks[SSL bundles].\n\nFor PEM based keystores and truststores, you can use the following container labels:\n\n* `org.springframework.boot.sslbundle.pem.key.alias`\n* `org.springframework.boot.sslbundle.pem.key.password`\n* `org.springframework.boot.sslbundle.pem.options.ciphers`\n* `org.springframework.boot.sslbundle.pem.options.enabled-protocols`\n* `org.springframework.boot.sslbundle.pem.protocol`\n\n* `org.springframework.boot.sslbundle.pem.keystore.type`\n* `org.springframework.boot.sslbundle.pem.keystore.certificate`\n* `org.springframework.boot.sslbundle.pem.keystore.private-key`\n* `org.springframework.boot.sslbundle.pem.keystore.private-key-password`\n\n* `org.springframework.boot.sslbundle.pem.truststore.type`\n* `org.springframework.boot.sslbundle.pem.truststore.certificate`\n* `org.springframework.boot.sslbundle.pem.truststore.private-key`\n* `org.springframework.boot.sslbundle.pem.truststore.private-key-password`\n\nThese labels mirror the properties available for xref:reference:features/ssl.adoc#features.ssl.pem[SSL bundles].\n\nThe following example enables SSL for a redis container:\n\n[source,yaml,]\n----\nservices:\n  redis:\n    image: 'redis:latest'\n    ports:\n      - '6379'\n    secrets:\n      - ssl-ca\n      - ssl-key\n      - ssl-cert\n    command: 'redis-server --tls-port 6379 --port 0 --tls-cert-file /run/secrets/ssl-cert --tls-key-file /run/secrets/ssl-key --tls-ca-cert-file /run/secrets/ssl-ca'\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'\n      - 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\nsecrets:\n  ssl-ca:\n    file: 'ca.crt'\n  ssl-key:\n    file: 'server.key'\n  ssl-cert:\n    file: 'server.crt'\n----\n\n[[features.dev-services.docker-compose.custom-images]]\n=== Custom Images\n\nSometimes you may need to use your own version of an image to provide a service.\nYou can use any custom image as long as it behaves in the same way as the standard image.\nSpecifically, any environment variables that the standard image supports must also be used in your custom image.\n\nIf your image uses a different name, you can use a label in your `compose.yml` file so that Spring Boot can provide a service connection.\nUse a label named `org.springframework.boot.service-connection` to provide the service name.\n\nFor example:\n\n[source,yaml,]\n----\nservices:\n  redis:\n    image: 'mycompany/mycustomredis:7.0'\n    ports:\n      - '6379'\n    labels:\n      org.springframework.boot.service-connection: redis\n----\n\n\n\n[[features.dev-services.docker-compose.skipping]]\n=== Skipping Specific Containers\n\nIf you have a container image defined in your `compose.yml` that you don’t want connected to your application you can use a label to ignore it.\nAny container with labeled with `org.springframework.boot.ignore` will be ignored by Spring Boot.\n\nFor example:\n\n[source,yaml]\n----\nservices:\n  redis:\n    image: 'redis:7.0'\n    ports:\n      - '6379'\n    labels:\n      org.springframework.boot.ignore: true\n----\n\n\n\n[[features.dev-services.docker-compose.specific-file]]\n=== Using a Specific Compose File\n\nIf your compose file is not in the same directory as your application, or if it’s named differently, you can use configprop:spring.docker.compose.file[] in your `application.properties` or `application.yaml` to point to a different file.\nProperties can be defined as an exact path or a path that’s relative to your application.\n\nFor example:\n\n[configprops,yaml]\n----\nspring:\n  docker:\n    compose:\n      file: \"../my-compose.yml\"\n----\n\n\n\n[[features.dev-services.docker-compose.readiness]]\n=== Waiting for Container Readiness\n\nContainers started by Docker Compose may take some time to become fully ready.\nThe recommended way of checking for readiness is to add a `healthcheck` section under the service definition in your `compose.yml` file.\n\nSince it's not uncommon for `healthcheck` configuration to be omitted from `compose.yml` files, Spring Boot also checks directly for service readiness.\nBy default, a container is considered ready when a TCP/IP connection can be established to its mapped port.\n\nYou can disable this on a per-container basis by adding a `org.springframework.boot.readiness-check.tcp.disable` label in your `compose.yml` file.\n\nFor example:\n\n[source,yaml]\n----\nservices:\n  redis:\n    image: 'redis:7.0'\n    ports:\n      - '6379'\n    labels:\n      org.springframework.boot.readiness-check.tcp.disable: true\n----\n\nYou can also change timeout values in your `application.properties` or `application.yaml` file:\n\n[configprops,yaml]\n----\nspring:\n  docker:\n    compose:\n      readiness:\n        tcp:\n          connect-timeout: 10s\n          read-timeout: 5s\n----\n\nThe overall timeout can be configured using configprop:spring.docker.compose.readiness.timeout[].\n\n\n\n[[features.dev-services.docker-compose.lifecycle]]\n=== Controlling the Docker Compose Lifecycle\n\nBy default Spring Boot calls `docker compose up` when your application starts and `docker compose stop` when it's shut down.\nIf you prefer to have different lifecycle management you can use the configprop:spring.docker.compose.lifecycle-management[] property.\n\nThe following values are supported:\n\n* `none` - Do not start or stop Docker Compose\n* `start-only` - Start Docker Compose when the application starts and leave it running\n* `start-and-stop` - Start Docker Compose when the application starts and stop it when the JVM exits\n\nIn addition you can use the configprop:spring.docker.compose.start.command[] property to change whether `docker compose up` or `docker compose start` is used.\nThe configprop:spring.docker.compose.stop.command[] allows you to configure if `docker compose down` or `docker compose stop` is used.\n\nYou can also pass additional arguments to Docker Compose commands.\nThe configprop:spring.docker.compose.arguments[] property allows you to specify arguments that are passed to all Docker Compose commands.\nThe configprop:spring.docker.compose.start.arguments[] property allows you to specify arguments that are passed only to the up (or start) command, while the configprop:spring.docker.compose.stop.arguments[] property allows you to specify arguments that are passed only to the down (or stop) command.\n\nThe following example shows how lifecycle management can be configured:\n\n[configprops,yaml]\n----\nspring:\n  docker:\n    compose:\n      lifecycle-management: start-and-stop\n      arguments:\n        - \"--project-name=myapp\"\n        - \"--progress=auto\"\n      start:\n        command: up\n        arguments:\n          - \"--build\"\n          - \"--force-recreate\"\n      stop:\n        command: down\n        timeout: 1m\n        arguments:\n          - \"--volumes\"\n          - \"--remove-orphans\"\n----\n\n\n\n[[features.dev-services.docker-compose.profiles]]\n=== Activating Docker Compose Profiles\n\nDocker Compose profiles are similar to Spring profiles in that they let you adjust your Docker Compose configuration for specific environments.\nIf you want to activate a specific Docker Compose profile you can use the configprop:spring.docker.compose.profiles.active[] property in your `application.properties` or `application.yaml` file:\n\n[configprops,yaml]\n----\nspring:\n  docker:\n    compose:\n      profiles:\n        active: \"myprofile\"\n----\n\n\n\n[[features.dev-services.docker-compose.tests]]\n=== Using Docker Compose in Tests\n\nBy default, Spring Boot's Docker Compose support is disabled when running tests.\n\nTo enable Docker Compose support in tests, set configprop:spring.docker.compose.skip.in-tests[] to `false`.\n\nWhen using Gradle, you also need to change the configuration of the `spring-boot-docker-compose` dependency from `developmentOnly` to `testAndDevelopmentOnly`:\n\n.Gradle\n[source,gradle,indent=0,subs=\"verbatim\"]\n----\n\tdependencies {\n\t\ttestAndDevelopmentOnly(\"org.springframework.boot:spring-boot-docker-compose\")\n\t}\n----\n\n\n\n[[features.dev-services.testcontainers]]\n== Testcontainers Support\n\nAs well as xref:testing/testcontainers.adoc#testing.testcontainers[using Testcontainers for integration testing], it's also possible to use them at development time.\nThe next sections will provide more details about that.\n\n\n\n[[features.dev-services.testcontainers.at-development-time]]\n=== Using Testcontainers at Development Time\n\nThis approach allows developers to quickly start containers for the services that the application depends on, removing the need to manually provision things like database servers.\nUsing Testcontainers in this way provides functionality similar to Docker Compose, except that your container configuration is in Java rather than YAML.\n\nTo use Testcontainers at development time you need to launch your application using your \"`test`\" classpath rather than \"`main`\".\nThis will allow you to access all declared test dependencies and give you a natural place to write your test configuration.\n\nTo create a test launchable version of your application you should create an \"`Application`\" class in the `src/test` directory.\nFor example, if your main application is in `src/main/java/com/example/MyApplication.java`, you should create `src/test/java/com/example/TestMyApplication.java`\n\nThe `TestMyApplication` class can use the `SpringApplication.from(...)` method to launch the real application:\n\ninclude-code::launch/TestMyApplication[]\n\nYou'll also need to define the javadoc:org.testcontainers.containers.Container[] instances that you want to start along with your application.\nTo do this, you need to make sure that the `spring-boot-testcontainers` module has been added as a `test` dependency.\nOnce that has been done, you can create a javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] class that declares javadoc:org.springframework.context.annotation.Bean[format=annotation] methods for the containers you want to start.\n\nYou can also annotate your javadoc:org.springframework.context.annotation.Bean[format=annotation] methods with javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation] in order to create javadoc:org.springframework.boot.autoconfigure.service.connection.ConnectionDetails[] beans.\nSee xref:testing/testcontainers.adoc#testing.testcontainers.service-connections[the service connections] section for details of the supported technologies.\n\nA typical Testcontainers configuration would look like this:\n\ninclude-code::test/MyContainersConfiguration[]\n\nNOTE: The lifecycle of javadoc:org.testcontainers.containers.Container[] beans is automatically managed by Spring Boot.\nContainers will be started and stopped automatically.\n\nTIP: You can use the configprop:spring.testcontainers.beans.startup[] property to change how containers are started.\nBy default `sequential` startup is used, but you may also choose `parallel` if you wish to start multiple containers in parallel.\n\nOnce you have defined your test configuration, you can use the `with(...)` method to attach it to your test launcher:\n\ninclude-code::test/TestMyApplication[]\n\nYou can now launch `TestMyApplication` as you would any regular Java `main` method application to start your application and the containers that it needs to run.\n\nTIP: You can use the Maven goal `spring-boot:test-run` or the Gradle task `bootTestRun` to do this from the command line.\n\n\n\n[[features.dev-services.testcontainers.at-development-time.dynamic-properties]]\n==== Contributing Dynamic Properties at Development Time\n\nIf you want to contribute dynamic properties at development time from your javadoc:org.testcontainers.containers.Container[] javadoc:org.springframework.context.annotation.Bean[format=annotation] methods, define an additional javadoc:org.springframework.test.context.DynamicPropertyRegistrar[] bean.\nThe registrar should be defined using a javadoc:org.springframework.context.annotation.Bean[format=annotation] method that injects the container from which the properties will be sourced as a parameter.\nThis arrangement ensures that container has been started before the properties are used.\n\nA typical configuration would look like this:\n\ninclude-code::MyContainersConfiguration[]\n\nNOTE: Using a javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation] is recommended whenever possible, however, dynamic properties can be a useful fallback for technologies that don't yet have javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation] support.\n\n\n\n[[features.dev-services.testcontainers.at-development-time.importing-container-declarations]]\n==== Importing Testcontainers Declaration Classes\n\nA common pattern when using Testcontainers is to declare javadoc:org.testcontainers.containers.Container[] instances as static fields.\nOften these fields are defined directly on the test class.\nThey can also be declared on a parent class or on an interface that the test implements.\n\nFor example, the following `MyContainers` interface declares `mongo` and `neo4j` containers:\n\ninclude-code::MyContainers[]\n\nIf you already have containers defined in this way, or you just prefer this style, you can import these declaration classes rather than defining your containers as javadoc:org.springframework.context.annotation.Bean[format=annotation] methods.\nTo do so, add the javadoc:org.springframework.boot.testcontainers.context.ImportTestcontainers[format=annotation] annotation to your test configuration class:\n\ninclude-code::MyContainersConfiguration[]\n\nTIP: If you don't intend to use the xref:testing/testcontainers.adoc#testing.testcontainers.service-connections[service connections feature] but want to use xref:testing/testcontainers.adoc#testing.testcontainers.dynamic-properties[`@DynamicPropertySource`] instead, remove the javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation] annotation from the javadoc:org.testcontainers.containers.Container[] fields.\nYou can also add javadoc:org.springframework.test.context.DynamicPropertySource[format=annotation] annotated methods to your declaration class.\n\n\n\n[[features.dev-services.testcontainers.at-development-time.devtools]]\n==== Using DevTools with Testcontainers at Development Time\n\nWhen using devtools, you can annotate beans and bean methods with javadoc:org.springframework.boot.devtools.restart.RestartScope[format=annotation].\nSuch beans won't be recreated when the devtools restart the application.\nThis is especially useful for javadoc:org.testcontainers.containers.Container[] beans, as they keep their state despite the application restart.\n\ninclude-code::MyContainersConfiguration[]\n\nWARNING: If you're using Gradle and want to use this feature, you need to change the configuration of the `spring-boot-devtools` dependency from `developmentOnly` to `testAndDevelopmentOnly`.\nWith the default scope of `developmentOnly`, the `bootTestRun` task will not pick up changes in your code, as the devtools are not active.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/developing-auto-configuration.adoc",
    "content": "[[features.developing-auto-configuration]]\n= Creating Your Own Auto-configuration\n\nIf you work in a company that develops shared libraries, or if you work on an open-source or commercial library, you might want to develop your own auto-configuration.\nAuto-configuration classes can be bundled in external jars and still be picked up by Spring Boot.\n\nAuto-configuration can be associated to a \"`starter`\" that provides the auto-configuration code as well as the typical libraries that you would use with it.\nWe first cover what you need to know to build your own auto-configuration and then we move on to the xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[typical steps required to create a custom starter].\n\n\n\n[[features.developing-auto-configuration.understanding-auto-configured-beans]]\n== Understanding Auto-configured Beans\n\nClasses that implement auto-configuration are annotated with javadoc:org.springframework.boot.autoconfigure.AutoConfiguration[format=annotation].\nThis annotation itself is meta-annotated with javadoc:org.springframework.context.annotation.Configuration[format=annotation], making auto-configurations standard javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes.\nAdditional javadoc:org.springframework.context.annotation.Conditional[format=annotation] annotations are used to constrain when the auto-configuration should apply.\nUsually, auto-configuration classes use javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnClass[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean[format=annotation] annotations.\nThis ensures that auto-configuration applies only when relevant classes are found and when you have not declared your own javadoc:org.springframework.context.annotation.Configuration[format=annotation].\n\nYou can browse the source code of {code-spring-boot-autoconfigure-src}[`spring-boot-autoconfigure`] to see the core javadoc:org.springframework.boot.autoconfigure.AutoConfiguration[format=annotation] classes that Spring provides (see the {code-spring-boot}/core/spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports[`META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`] file).\nYou can also look at the equivalent file in other modules to see the auto-configurations that they provide.\n\n\n\n[[features.developing-auto-configuration.locating-auto-configuration-candidates]]\n== Locating Auto-configuration Candidates\n\nSpring Boot checks for the presence of a `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` file within your published jar.\nThe file should list your configuration classes, with one class name per line, as shown in the following example:\n\n[source]\n----\ncom.mycorp.libx.autoconfigure.LibXAutoConfiguration\ncom.mycorp.libx.autoconfigure.LibXWebAutoConfiguration\n----\n\nTIP: You can add comments to the imports file using the `#` character.\n\nTIP:  In the unusual case that an auto-configuration class is not a top-level class, its class name should use `$` to separate it from its containing class, for example `com.example.Outer$NestedAutoConfiguration`.\n\nNOTE: Auto-configurations must be loaded _only_ by being named in the imports file.\nMake sure that they are defined in a specific package space and that they are never the target of component scanning.\nFurthermore, auto-configuration classes should not enable component scanning to find additional components.\nSpecific javadoc:org.springframework.context.annotation.Import[format=annotation] annotations should be used instead.\n\nIf your configuration needs to be applied in a specific order, you can use the `before`, `beforeName`, `after` and `afterName` attributes on the javadoc:org.springframework.boot.autoconfigure.AutoConfiguration[format=annotation] annotation or the dedicated javadoc:org.springframework.boot.autoconfigure.AutoConfigureBefore[format=annotation] and javadoc:org.springframework.boot.autoconfigure.AutoConfigureAfter[format=annotation] annotations.\nFor example, if you provide web-specific configuration, your class may need to be applied after javadoc:org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration[].\n\nIf you want to order certain auto-configurations that should not have any direct knowledge of each other, you can also use javadoc:org.springframework.boot.autoconfigure.AutoConfigureOrder[format=annotation].\nThat annotation has the same semantic as the regular javadoc:org.springframework.core.annotation.Order[format=annotation] annotation but provides a dedicated order for auto-configuration classes.\n\nAs with standard javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes, the order in which auto-configuration classes are applied only affects the order in which their beans are defined.\nThe order in which those beans are subsequently created is unaffected and is determined by each bean's dependencies and any javadoc:org.springframework.context.annotation.DependsOn[format=annotation] relationships.\n\n\n\n[[features.developing-auto-configuration.locating-auto-configuration-candidates.deprecating]]\n=== Deprecating and Replacing Auto-configuration Classes\n\nYou may need to occasionally deprecate auto-configuration classes and offer an alternative.\nFor example, you may want to change the package name where your auto-configuration class resides.\n\nSince auto-configuration classes may be referenced in `before`/`after` ordering and `excludes`, you'll need to add an additional file that tells Spring Boot how to deal with replacements.\nTo define replacements, create a `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.replacements` file indicating the link between the old class and the new one.\n\nFor example:\n\n[source]\n----\ncom.mycorp.libx.autoconfigure.LibXAutoConfiguration=com.mycorp.libx.autoconfigure.core.LibXAutoConfiguration\n----\n\nNOTE: The `AutoConfiguration.imports` file should also be updated to _only_ reference the replacement class.\n\n\n\n[[features.developing-auto-configuration.condition-annotations]]\n== Condition Annotations\n\nYou almost always want to include one or more javadoc:org.springframework.context.annotation.Conditional[format=annotation] annotations on your auto-configuration class.\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean[format=annotation] annotation is one common example that is used to allow developers to override auto-configuration if they are not happy with your defaults.\n\nSpring Boot includes a number of javadoc:org.springframework.context.annotation.Conditional[format=annotation] annotations that you can reuse in your own code by annotating javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes or individual javadoc:org.springframework.context.annotation.Bean[format=annotation] methods.\nThese annotations include:\n\n* xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.class-conditions[]\n* xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.bean-conditions[]\n* xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.property-conditions[]\n* xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.resource-conditions[]\n* xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.web-application-conditions[]\n* xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.condition-annotations.spel-conditions[]\n\n\n\n[[features.developing-auto-configuration.condition-annotations.class-conditions]]\n=== Class Conditions\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnClass[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass[format=annotation] annotations let javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes be included based on the presence or absence of specific classes.\nDue to the fact that annotation metadata is parsed by using https://asm.ow2.io/[ASM], you can use the `value` attribute to refer to the real class, even though that class might not actually appear on the running application classpath.\nYou can also use the `name` attribute if you prefer to specify the class name by using a javadoc:java.lang.String[] value.\n\nThis mechanism does not apply the same way to javadoc:org.springframework.context.annotation.Bean[format=annotation] methods where typically the return type is the target of the condition: before the condition on the method applies, the JVM will have loaded the class and potentially processed method references which will fail if the class is not present.\n\nTo handle this scenario, a separate javadoc:org.springframework.context.annotation.Configuration[format=annotation] class can be used to isolate the condition, as shown in the following example:\n\ninclude-code::MyAutoConfiguration[]\n\nTIP: If you use javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnClass[format=annotation] or javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass[format=annotation] as a part of a meta-annotation to compose your own composed annotations, you must use `name` as referring to the class in such a case is not handled.\n\n\n\n[[features.developing-auto-configuration.condition-annotations.bean-conditions]]\n=== Bean Conditions\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnBean[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean[format=annotation] annotations let a bean be included based on the presence or absence of specific beans.\nYou can use the `value` attribute to specify beans by type or `name` to specify beans by name.\nThe `search` attribute lets you limit the javadoc:org.springframework.context.ApplicationContext[] hierarchy that should be considered when searching for beans.\n\nWhen placed on a javadoc:org.springframework.context.annotation.Bean[format=annotation] method, the target type defaults to the return type of the method, as shown in the following example:\n\ninclude-code::MyAutoConfiguration[]\n\nIn the preceding example, the `someService` bean is going to be created if no bean of type `SomeService` is already contained in the javadoc:org.springframework.context.ApplicationContext[].\n\nTIP: You need to be very careful about the order in which bean definitions are added, as these conditions are evaluated based on what has been processed so far.\nFor this reason, we recommend using only javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnBean[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean[format=annotation] annotations on auto-configuration classes (since these are guaranteed to load after any user-defined bean definitions have been added).\n\nNOTE: javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnBean[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean[format=annotation] do not prevent javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes from being created.\nThe only difference between using these conditions at the class level and marking each contained javadoc:org.springframework.context.annotation.Bean[format=annotation] method with the annotation is that the former prevents registration of the javadoc:org.springframework.context.annotation.Configuration[format=annotation] class as a bean if the condition does not match.\n\nTIP: When declaring a javadoc:org.springframework.context.annotation.Bean[format=annotation] method, provide as much type information as possible in the method's return type.\nFor example, if your bean's concrete class implements an interface the bean method's return type should be the concrete class and not the interface.\nProviding as much type information as possible in javadoc:org.springframework.context.annotation.Bean[format=annotation] methods is particularly important when using bean conditions as their evaluation can only rely upon to type information that is available in the method signature.\n\n\n\n[[features.developing-auto-configuration.condition-annotations.property-conditions]]\n=== Property Conditions\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] annotation lets configuration be included based on a Spring Environment property.\nUse the `prefix` and `name` attributes to specify the property that should be checked.\nBy default, any property that exists and is not equal to `false` is matched.\nThere is also a dedicated javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty[format=annotation] annotation specifically made for boolean properties.\nWith both annotations you can also create more advanced checks by using the `havingValue` and `matchIfMissing` attributes.\n\nIf multiple names are given in the `name` attribute, all of the properties have to pass the test for the condition to match.\n\n\n\n[[features.developing-auto-configuration.condition-annotations.resource-conditions]]\n=== Resource Conditions\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnResource[format=annotation] annotation lets configuration be included only when a specific resource is present.\nResources can be specified by using the usual Spring conventions, as shown in the following example: `file:/home/user/test.dat`.\n\n\n\n[[features.developing-auto-configuration.condition-annotations.web-application-conditions]]\n=== Web Application Conditions\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication[format=annotation] annotations let configuration be included depending on whether the application is a web application.\nA servlet-based web application is any application that uses a Spring javadoc:org.springframework.web.context.WebApplicationContext[], defines a `session` scope, or has a javadoc:org.springframework.web.context.ConfigurableWebEnvironment[].\nA reactive web application is any application that uses a javadoc:org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext[], or has a javadoc:org.springframework.boot.web.context.reactive.ConfigurableReactiveWebEnvironment[].\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnWarDeployment[format=annotation] and javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment[format=annotation] annotations let configuration be included depending on whether the application is a traditional WAR application that is deployed to a servlet container.\nThis condition will not match for applications that are run with an embedded web server.\n\n\n\n[[features.developing-auto-configuration.condition-annotations.spel-conditions]]\n=== SpEL Expression Conditions\n\nThe javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnExpression[format=annotation] annotation lets configuration be included based on the result of a {url-spring-framework-docs}/core/expressions.html[SpEL expression].\n\nNOTE: Referencing a bean in the expression will cause that bean to be initialized very early in context refresh processing.\nAs a result, the bean won't be eligible for post-processing (such as configuration properties binding) and its state may be incomplete.\n\n\n\n[[features.developing-auto-configuration.testing]]\n== Testing your Auto-configuration\n\nAn auto-configuration can be affected by many factors: user configuration (`@Bean` definition and javadoc:org.springframework.core.env.Environment[] customization), condition evaluation (presence of a particular library), and others.\nConcretely, each test should create a well defined javadoc:org.springframework.context.ApplicationContext[] that represents a combination of those customizations.\njavadoc:org.springframework.boot.test.context.runner.ApplicationContextRunner[] provides a great way to achieve that.\n\nWARNING: javadoc:org.springframework.boot.test.context.runner.ApplicationContextRunner[] doesn't work when running the tests in a native image.\n\njavadoc:org.springframework.boot.test.context.runner.ApplicationContextRunner[] is usually defined as a field of the test class to gather the base, common configuration.\nThe following example makes sure that `MyServiceAutoConfiguration` is always invoked:\n\ninclude-code::MyServiceAutoConfigurationTests[tag=runner]\n\nTIP: If multiple auto-configurations have to be defined, there is no need to order their declarations as they are invoked in the exact same order as when running the application.\n\nEach test can use the runner to represent a particular use case.\nFor instance, the sample below invokes a user configuration (`UserConfiguration`) and checks that the auto-configuration backs off properly.\nInvoking `run` provides a callback context that can be used with AssertJ.\n\ninclude-code::MyServiceAutoConfigurationTests[tag=test-user-config]\n\nIt is also possible to easily customize the javadoc:org.springframework.core.env.Environment[], as shown in the following example:\n\ninclude-code::MyServiceAutoConfigurationTests[tag=test-env]\n\nThe runner can also be used to display the javadoc:org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport[].\nThe report can be printed at `INFO` or `DEBUG` level.\nThe following example shows how to use the javadoc:org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener[] to print the report in auto-configuration tests.\n\ninclude-code::MyConditionEvaluationReportingTests[]\n\n\n\n[[features.developing-auto-configuration.testing.simulating-a-web-context]]\n=== Simulating a Web Context\n\nIf you need to test an auto-configuration that only operates in a servlet or reactive web application context, use the javadoc:org.springframework.boot.test.context.runner.WebApplicationContextRunner[] or javadoc:org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner[] respectively.\n\n\n\n[[features.developing-auto-configuration.testing.overriding-classpath]]\n=== Overriding the Classpath\n\nIt is also possible to test what happens when a particular class and/or package is not present at runtime.\nSpring Boot ships with a javadoc:org.springframework.boot.test.context.FilteredClassLoader[] that can easily be used by the runner.\nIn the following example, we assert that if `MyService` is not present, the auto-configuration is properly disabled:\n\ninclude-code::../MyServiceAutoConfigurationTests[tag=test-classloader]\n\n\n\n[[features.developing-auto-configuration.custom-starter]]\n== Creating Your Own Starter\n\nA typical Spring Boot starter contains code to auto-configure and customize the infrastructure of a given technology, let's call that \"acme\".\nTo make it easily extensible, a number of configuration keys in a dedicated namespace can be exposed to the environment.\nFinally, a single \"starter\" dependency is provided to help users get started as easily as possible.\n\nConcretely, a custom starter can contain the following:\n\n* The `acme-spring-boot` module that contains the auto-configuration code for \"acme\" as well as any API to use the feature.\n* The `acme-spring-boot-starter` module that provides a dependency to the other starters required by \"acme\", `acme-spring-boot`, and potentially additional dependencies that are typically useful.\nIn a nutshell, adding the starter should provide everything needed to start using that library.\n\nThis separation in two modules is in no way necessary.\nIf \"acme\" has several flavors, options or optional features, then it is better to separate the auto-configuration as you can clearly express the fact some features are optional.\nBesides, you have the ability to craft a starter that provides an opinion about those optional dependencies.\nAt the same time, others can rely only on `acme-spring-boot` and craft their own starter with different opinions.\n\nIf the auto-configuration is relatively straightforward and does not have optional features, merging the two modules in the starter is definitely an option.\n\nIf \"acme\" has a basic set of dependencies that are required to work, but you want to express a more opinionated view, then having a separate starter is a good option.\n\nWhen testing \"acme\" features, you may need test-specific auto-configurations.\nFor example, you could offer a way to replace external dependencies with in-memory alternatives.\nA separate test-scoped starter can be created for this purpose, following the same principles.\n\n\n[[features.developing-auto-configuration.custom-starter.naming]]\n=== Naming\n\nYou should make sure to provide a proper namespace for your starter.\nDo not start your module names with `spring-boot`, even if you use a different Maven `groupId`.\nWe may offer official support for the thing you auto-configure in the future.\n\nAs a rule of thumb, you should name a combined module after the starter.\nFor example, assume that you are creating a starter for \"acme\" and that you name the auto-configure module `acme-spring-boot` and the starter `acme-spring-boot-starter`.\nIf you only have one module that combines the two, name it `acme-spring-boot-starter`.\n\nIf \"acme\" also has a test-scoped starter, name it `acme-spring-boot-starter-test`.\n\n\n[[features.developing-auto-configuration.custom-starter.configuration-keys]]\n=== Configuration keys\n\nIf your starter provides configuration keys, use a unique namespace for them.\nIn particular, do not include your keys in the namespaces that Spring Boot uses (such as `server`, `management`, `spring`, and so on).\nIf you use the same namespace, we may modify these namespaces in the future in ways that break your modules.\nAs a rule of thumb, prefix all your keys with a namespace that you own (for example `acme`).\n\nMake sure that configuration keys are documented by adding field Javadoc for each property, as shown in the following example:\n\ninclude-code::AcmeProperties[]\n\nNOTE: You should only use plain text with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] field Javadoc, since they are not processed before being added to the JSON.\n\nIf you use javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] with record class then record components' descriptions should be provided via class-level Javadoc tag `@param` (there are no explicit instance fields in record classes to put regular field-level Javadocs on).\n\nHere are some rules we follow internally to make sure descriptions are consistent:\n\n* Do not start the description by \"The\" or \"A\".\n* For `boolean` types, start the description with \"Whether\" or \"Enable\".\n* For collection-based types, start the description with \"Comma-separated list\"\n* Use javadoc:java.time.Duration[] rather than `long` and describe the default unit if it differs from milliseconds, such as \"If a duration suffix is not specified, seconds will be used\".\n* Do not provide the default value in the description unless it has to be determined at runtime.\n\nMake sure to xref:specification:configuration-metadata/annotation-processor.adoc[trigger meta-data generation] so that IDE assistance is available for your keys as well.\nYou may want to review the generated metadata (`META-INF/spring-configuration-metadata.json`) to make sure your keys are properly documented.\nUsing your own starter in a compatible IDE is also a good idea to validate that quality of the metadata.\n\n\n\n[[features.developing-auto-configuration.custom-starter.autoconfigure-module]]\n=== The \"`autoconfigure`\" Module\n\nThe `autoconfigure` module contains everything that is necessary to get started with the library.\nIt may also contain configuration key definitions (such as javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]) and any callback interface that can be used to further customize how the components are initialized.\n\nTIP: You should mark the dependencies to the library as optional so that you can include the `autoconfigure` module in your projects more easily.\nIf you do it that way, the library is not provided and, by default, Spring Boot backs off.\n\nSpring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (`META-INF/spring-autoconfigure-metadata.properties`).\nIf that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time.\n\nWhen building with Maven, configure the compiler plugin (3.12.0 or later) to add `spring-boot-autoconfigure-processor` to the annotation processor paths:\n\n[source,xml]\n----\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<annotationProcessorPaths>\n\t\t\t\t\t\t<path>\n\t\t\t\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t\t\t\t<artifactId>spring-boot-autoconfigure-processor</artifactId>\n\t\t\t\t\t\t</path>\n\t\t\t\t\t</annotationProcessorPaths>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n----\n\nWith Gradle, the dependency should be declared in the `annotationProcessor` configuration, as shown in the following example:\n\n[source,gradle]\n----\ndependencies {\n\tannotationProcessor \"org.springframework.boot:spring-boot-autoconfigure-processor\"\n}\n----\n\n\n\n[[features.developing-auto-configuration.custom-starter.starter-module]]\n=== Starter Module\n\nThe starter is really an empty jar.\nIts only purpose is to provide the necessary dependencies to work with the library.\nYou can think of it as an opinionated view of what is required to get started.\n\nDo not make assumptions about the project in which your starter is added.\nIf the library you are auto-configuring typically requires other starters, mention them as well.\nProviding a proper set of _default_ dependencies may be hard if the number of optional dependencies is high, as you should avoid including dependencies that are unnecessary for a typical usage of the library.\nIn other words, you should not include optional dependencies.\n\nNOTE: Either way, your starter must reference the core Spring Boot starter (`spring-boot-starter`) directly or indirectly (there is no need to add it if your starter relies on another starter).\nIf a project is created with only your custom starter, Spring Boot's core features will be honoured by the presence of the core starter.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/external-config.adoc",
    "content": "[[features.external-config]]\n= Externalized Configuration\n\nSpring Boot lets you externalize your configuration so that you can work with the same application code in different environments.\nYou can use a variety of external configuration sources including Java properties files, YAML files, environment variables, and command-line arguments.\n\nProperty values can be injected directly into your beans by using the javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotation, accessed through Spring's javadoc:org.springframework.core.env.Environment[] abstraction, or be xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties[bound to structured objects] through javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\n\nSpring Boot uses a very particular javadoc:org.springframework.core.env.PropertySource[] order that is designed to allow sensible overriding of values.\nLater property sources can override the values defined in earlier ones.\n\n[[features.external-config.order]]\nSources are considered in the following order:\n\n. Default properties (specified by setting javadoc:org.springframework.boot.SpringApplication#setDefaultProperties(java.util.Map)[]).\n. javadoc:org.springframework.context.annotation.PropertySource[format=annotation] annotations on your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes.\n  Please note that such property sources are not added to the javadoc:org.springframework.core.env.Environment[] until the application context is being refreshed.\n  This is too late to configure certain properties such as `+logging.*+` and `+spring.main.*+` which are read before refresh begins.\n. Config data (such as `application.properties` files).\n. A javadoc:org.springframework.boot.env.RandomValuePropertySource[] that has properties only in `+random.*+`.\n. OS environment variables.\n. Java System properties (`System.getProperties()`).\n. JNDI attributes from `java:comp/env`.\n. javadoc:jakarta.servlet.ServletContext[] init parameters.\n. javadoc:jakarta.servlet.ServletConfig[] init parameters.\n. Properties from `SPRING_APPLICATION_JSON` (inline JSON embedded in an environment variable or system property).\n. Command line arguments.\n. `properties` attribute on your tests.\n  Available on javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] and the xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[test annotations for testing a particular slice of your application].\n. javadoc:org.springframework.test.context.DynamicPropertySource[format=annotation] annotations in your tests.\n. javadoc:org.springframework.test.context.TestPropertySource[format=annotation] annotations on your tests.\n. xref:using/devtools.adoc#using.devtools.globalsettings[Devtools global settings properties] in the `$HOME/.config/spring-boot` directory when devtools is active.\n\nConfig data files are considered in the following order:\n\n. xref:features/external-config.adoc#features.external-config.files[Application properties] packaged inside your jar (`application.properties` and YAML variants).\n. xref:features/external-config.adoc#features.external-config.files.profile-specific[Profile-specific application properties] packaged inside your jar (`application-\\{profile}.properties` and YAML variants).\n. xref:features/external-config.adoc#features.external-config.files[Application properties] outside of your packaged jar (`application.properties` and YAML variants).\n. xref:features/external-config.adoc#features.external-config.files.profile-specific[Profile-specific application properties] outside of your packaged jar (`application-\\{profile}.properties` and YAML variants).\n\nNOTE: It is recommended to stick with one format for your entire application.\nIf you have configuration files with both `.properties` and YAML format in the same location, `.properties` takes precedence.\n\nNOTE: If you use environment variables rather than system properties, most operating systems disallow period-separated key names, but you can use underscores instead (for example, configprop:spring.config.name[format=envvar] instead of configprop:spring.config.name[]).\nSee xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[] for details.\n\nNOTE: If your application runs in a servlet container or application server, then JNDI properties (in `java:comp/env`) or servlet context initialization parameters can be used instead of, or as well as, environment variables or system properties.\n\nTo provide a concrete example, suppose you develop a javadoc:org.springframework.stereotype.Component[format=annotation] that uses a `name` property, as shown in the following example:\n\ninclude-code::MyBean[]\n\nOn your application classpath (for example, inside your jar) you can have an `application.properties` file that provides a sensible default property value for `name`.\nWhen running in a new environment, an `application.properties` file can be provided outside of your jar that overrides the `name`.\nFor one-off testing, you can launch with a specific command line switch (for example, `java -jar app.jar --name=\"Spring\"`).\n\nTIP: The `env` and `configprops` endpoints can be useful in determining why a property has a particular value.\nYou can use these two endpoints to diagnose unexpected property values.\nSee the xref:actuator/endpoints.adoc[Production ready features] section for details.\n\n\n\n[[features.external-config.command-line-args]]\n== Accessing Command Line Properties\n\nBy default, javadoc:org.springframework.boot.SpringApplication[] converts any command line option arguments (that is, arguments starting with `--`, such as `--server.port=9000`) to a `property` and adds them to the Spring javadoc:org.springframework.core.env.Environment[].\nAs mentioned previously, command line properties always take precedence over file-based property sources.\n\nIf you do not want command line properties to be added to the javadoc:org.springframework.core.env.Environment[], you can disable them by using `SpringApplication.setAddCommandLineProperties(false)`.\n\n\n\n[[features.external-config.application-json]]\n== JSON Application Properties\n\nEnvironment variables and system properties often have restrictions that mean some property names cannot be used.\nTo help with this, Spring Boot allows you to encode a block of properties into a single JSON structure.\n\nWhen your application starts, any `spring.application.json` or `SPRING_APPLICATION_JSON` properties will be parsed and added to the javadoc:org.springframework.core.env.Environment[].\n\nFor example, the `SPRING_APPLICATION_JSON` property can be supplied on the command line in a UN{asterisk}X shell as an environment variable:\n\n[source,shell]\n----\n$ SPRING_APPLICATION_JSON='{\"my\":{\"name\":\"test\"}}' java -jar myapp.jar\n----\n\nIn the preceding example, you end up with `my.name=test` in the Spring javadoc:org.springframework.core.env.Environment[].\n\nThe same JSON can also be provided as a system property:\n\n[source,shell]\n----\n$ java -Dspring.application.json='{\"my\":{\"name\":\"test\"}}' -jar myapp.jar\n----\n\nOr you could supply the JSON by using a command line argument:\n\n[source,shell]\n----\n$ java -jar myapp.jar --spring.application.json='{\"my\":{\"name\":\"test\"}}'\n----\n\nIf you are deploying to a classic Application Server, you could also use a JNDI variable named `java:comp/env/spring.application.json`.\n\nNOTE: Although `null` values from the JSON will be added to the resulting property source, the javadoc:org.springframework.core.env.PropertySourcesPropertyResolver[] treats `null` properties as missing values.\nThis means that the JSON cannot override properties from lower order property sources with a `null` value.\n\n\n\n[[features.external-config.files]]\n== External Application Properties\n\nSpring Boot will automatically find and load `application.properties` and `application.yaml` files from the following locations when your application starts:\n\n. From the classpath\n.. The classpath root\n.. The classpath `/config` package\n. From the current directory\n.. The current directory\n.. The `config/` subdirectory in the current directory\n.. Immediate child directories of the `config/` subdirectory\n\nThe list is ordered by precedence (with values from lower items overriding earlier ones).\nDocuments from the loaded files are added as javadoc:org.springframework.core.env.PropertySource[] instances to the Spring javadoc:org.springframework.core.env.Environment[].\n\nIf you do not like `application` as the configuration file name, you can switch to another file name by specifying a configprop:spring.config.name[] environment property.\nFor example, to look for `myproject.properties` and `myproject.yaml` files you can run your application as follows:\n\n[source,shell]\n----\n$ java -jar myproject.jar --spring.config.name=myproject\n----\n\nYou can also refer to an explicit location by using the configprop:spring.config.location[] environment property.\nThis property accepts a comma-separated list of one or more locations to check.\n\nThe following example shows how to specify two distinct files:\n\n[source,shell]\n----\n$ java -jar myproject.jar --spring.config.location=\\\n\toptional:classpath:/default.properties,\\\n\toptional:classpath:/override.properties\n----\n\nTIP: Use the prefix `optional:` if the xref:features/external-config.adoc#features.external-config.files.optional-prefix[locations are optional] and you do not mind if they do not exist.\n\nWARNING: `spring.config.name`, `spring.config.location`, and `spring.config.additional-location` are used very early to determine which files have to be loaded.\nThey must be defined as an environment property (typically an OS environment variable, a system property, or a command-line argument).\n\nIf `spring.config.location` contains directories (as opposed to files), they should end in `/`.\nAt runtime they will be appended with the names generated from `spring.config.name` before being loaded.\nFiles specified in `spring.config.location` are imported directly.\n\nNOTE: Both directory and file location values are also expanded to check for xref:features/external-config.adoc#features.external-config.files.profile-specific[profile-specific files].\nFor example, if you have a `spring.config.location` of `classpath:myconfig.properties`, you will also find appropriate `classpath:myconfig-<profile>.properties` files are loaded.\n\nIn most situations, each configprop:spring.config.location[] item you add will reference a single file or directory.\nLocations are processed in the order that they are defined and later ones can override the values of earlier ones.\n\n[[features.external-config.files.location-groups]]\nIf you have a complex location setup, and you use profile-specific configuration files, you may need to provide further hints so that Spring Boot knows how they should be grouped.\nA location group is a collection of locations that are all considered at the same level.\nFor example, you might want to group all classpath locations, then all external locations.\nItems within a location group should be separated with `;`.\nSee the example in the xref:features/external-config.adoc#features.external-config.files.profile-specific[] section for more details.\n\nLocations configured by using `spring.config.location` replace the default locations.\nFor example, if `spring.config.location` is configured with the value `optional:classpath:/custom-config/,optional:file:./custom-config/`, the complete set of locations considered is:\n\n. `optional:classpath:custom-config/`\n. `optional:file:./custom-config/`\n\nIf you prefer to add additional locations, rather than replacing them, you can use `spring.config.additional-location`.\nProperties loaded from additional locations can override those in the default locations.\nFor example, if `spring.config.additional-location` is configured with the value `optional:classpath:/custom-config/,optional:file:./custom-config/`, the complete set of locations considered is:\n\n. `optional:classpath:/;optional:classpath:/config/`\n. `optional:file:./;optional:file:./config/;optional:file:./config/*/`\n. `optional:classpath:custom-config/`\n. `optional:file:./custom-config/`\n\nThis search ordering lets you specify default values in one configuration file and then selectively override those values in another.\nYou can provide default values for your application in `application.properties` (or whatever other basename you choose with `spring.config.name`) in one of the default locations.\nThese default values can then be overridden at runtime with a different file located in one of the custom locations.\n\n\n\n[[features.external-config.files.optional-prefix]]\n=== Optional Locations\n\nBy default, when a specified config data location does not exist, Spring Boot will throw a javadoc:org.springframework.boot.context.config.ConfigDataLocationNotFoundException[] and your application will not start.\n\nIf you want to specify a location, but you do not mind if it does not always exist, you can use the `optional:` prefix.\nYou can use this prefix with the `spring.config.location` and `spring.config.additional-location` properties, as well as with xref:features/external-config.adoc#features.external-config.files.importing[`spring.config.import`] declarations.\n\nFor example, a `spring.config.import` value of `optional:file:./myconfig.properties` allows your application to start, even if the `myconfig.properties` file is missing.\n\nIf you want to ignore all javadoc:org.springframework.boot.context.config.ConfigDataLocationNotFoundException[] errors and always continue to start your application, you can use the `spring.config.on-not-found` property.\nSet the value to `ignore` using `SpringApplication.setDefaultProperties(...)` or with a system/environment variable.\n\n\n\n[[features.external-config.files.wildcard-locations]]\n=== Wildcard Locations\n\nIf a config file location includes the `{asterisk}` character for the last path segment, it is considered a wildcard location.\nWildcards are expanded when the config is loaded so that immediate subdirectories are also checked.\nWildcard locations are particularly useful in an environment such as Kubernetes when there are multiple sources of config properties.\n\nFor example, if you have some Redis configuration and some MySQL configuration, you might want to keep those two pieces of configuration separate, while requiring that both those are present in an `application.properties` file.\nThis might result in two separate `application.properties` files mounted at different locations such as `/config/redis/application.properties` and `/config/mysql/application.properties`.\nIn such a case, having a wildcard location of `config/*/`, will result in both files being processed.\n\nBy default, Spring Boot includes `config/*/` in the default search locations.\nIt means that all subdirectories of the `/config` directory outside of your jar will be searched.\n\nYou can use wildcard locations yourself with the `spring.config.location` and `spring.config.additional-location` properties.\n\nNOTE: A wildcard location must contain only one `{asterisk}` and end with `{asterisk}/` for search locations that are directories or `*/<filename>` for search locations that are files.\nLocations with wildcards are sorted alphabetically based on the absolute path of the file names.\n\nTIP: Wildcard locations only work with external directories.\nYou cannot use a wildcard in a `classpath:` location.\n\n\n\n[[features.external-config.files.profile-specific]]\n=== Profile Specific Files\n\nAs well as `application` property files, Spring Boot will also attempt to load profile-specific files using the naming convention `application-\\{profile}`.\nFor example, if your application activates a profile named `prod` and uses YAML files, then both `application.yaml` and `application-prod.yaml` will be considered.\n\nProfile-specific properties are loaded from the same locations as standard `application.properties`, with profile-specific files always overriding the non-specific ones.\nIf several profiles are specified, a last-wins strategy applies.\nFor example, if profiles `prod,live` are specified by the configprop:spring.profiles.active[] property, values in `application-prod.properties` can be overridden by those in `application-live.properties`.\n\n[NOTE]\n====\nThe last-wins strategy applies at the xref:features/external-config.adoc#features.external-config.files.location-groups[location group] level.\nA configprop:spring.config.location[] of `classpath:/cfg/,classpath:/ext/` will not have the same override rules as `classpath:/cfg/;classpath:/ext/`.\n\nFor example, continuing our `prod,live` example above, we might have the following files:\n\n----\n/cfg\n  application-live.properties\n/ext\n  application-live.properties\n  application-prod.properties\n----\n\nWhen we have a configprop:spring.config.location[] of `classpath:/cfg/,classpath:/ext/` we process all `/cfg` files before all `/ext` files:\n\n. `/cfg/application-live.properties`\n. `/ext/application-prod.properties`\n. `/ext/application-live.properties`\n\n\nWhen we have `classpath:/cfg/;classpath:/ext/` instead (with a `;` delimiter) we process `/cfg` and `/ext` at the same level:\n\n. `/ext/application-prod.properties`\n. `/cfg/application-live.properties`\n. `/ext/application-live.properties`\n====\n\nThe javadoc:org.springframework.core.env.Environment[] has a set of default profiles (by default, `[default]`) that are used if no active profiles are set.\nIn other words, if no profiles are explicitly activated, then properties from `application-default` are considered.\n\nNOTE: Properties files are only ever loaded once.\nIf you have already directly xref:features/external-config.adoc#features.external-config.files.importing[imported] a profile specific property files then it will not be imported a second time.\n\n\n\n[[features.external-config.files.importing]]\n=== Importing Additional Data\n\nApplication properties may import further config data from other locations using the configprop:spring.config.import[] property.\nImports are processed as they are discovered, and are treated as additional documents inserted immediately below the one that declares the import.\n\nFor example, you might have the following in your classpath `application.properties` file:\n\n[configprops,yaml]\n----\nspring:\n  application:\n    name: \"myapp\"\n  config:\n    import: \"optional:file:./dev.properties\"\n----\n\nThis will trigger the import of a `dev.properties` file in current directory (if such a file exists).\nValues from the imported `dev.properties` will take precedence over the file that triggered the import.\nIn the above example, the `dev.properties` could redefine `spring.application.name` to a different value.\n\nNOTE: An import will only be imported once no matter how many times it is declared.\n\nBy default, properties files are imported using the ISO-8859-1 charset. To change that, you can use the encoding attribute:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"classpath:import.properties[encoding=utf-8]\"\n----\n\nThe `import.properties` file will now be read in UTF-8 encoding.\n\n\n\n[[features.external-config.files.importing.fixed-and-relative-paths]]\n==== Using \"`Fixed`\" and \"`Import Relative`\" Locations\n\nImports may be specified as _fixed_ or _import relative_ locations.\nA fixed location always resolves to the same underlying resource, regardless of where the configprop:spring.config.import[] property is declared.\nAn import relative location resolves relative to the file that declares the configprop:spring.config.import[] property.\n\nA location starting with a forward slash (`/`) or a URL style prefix (`file:`, `classpath:`, etc.) is considered fixed.\nAll other locations are considered import relative.\n\nNOTE: `optional:` prefixes are not considered when determining if a location is fixed or import relative.\n\nAs an example, say we have a `/demo` directory containing our `application.jar` file.\nWe might add a `/demo/application.properties` file with the following content:\n\n[source,properties]\n----\nspring.config.import=optional:core/core.properties\n----\n\nThis is an import relative location and so will attempt to load the file `/demo/core/core.properties` if it exists.\n\nIf `/demo/core/core.properties` has the following content:\n\n[source,properties]\n----\nspring.config.import=optional:extra/extra.properties\n----\n\nIt will attempt to load `/demo/core/extra/extra.properties`.\nThe `optional:extra/extra.properties` is relative to `/demo/core/core.properties` so the full directory is `/demo/core/` + `extra/extra.properties`.\n\n\n\n[[features.external-config.files.importing.import-property-order]]\n==== Property Ordering\n\nThe order an import is defined inside a single document within the properties/yaml file does not matter.\nFor instance, the two examples below produce the same result:\n\n[configprops%novalidate,yaml]\n----\nspring:\n  config:\n    import: \"my.properties\"\nmy:\n  property: \"value\"\n----\n\n[configprops%novalidate,yaml]\n----\nmy:\n  property: \"value\"\nspring:\n  config:\n    import: \"my.properties\"\n----\n\nIn both of the above examples, the values from the `my.properties` file will take precedence over the file that triggered its import.\n\nSeveral locations can be specified under a single `spring.config.import` key.\nLocations will be processed in the order that they are defined, with later imports taking precedence.\n\nNOTE: When appropriate, xref:features/external-config.adoc#features.external-config.files.profile-specific[Profile-specific variants] are also considered for import.\nThe example above would import both `my.properties` as well as any `my-<profile>.properties` variants.\n\n[TIP]\n====\nSpring Boot includes pluggable API that allows various different location addresses to be supported.\nBy default you can import Java Properties, YAML and xref:features/external-config.adoc#features.external-config.files.configtree[configuration trees].\n\nThird-party jars can offer support for additional technologies (there is no requirement for files to be local).\nFor example, you can imagine config data being from external stores such as Consul, Apache ZooKeeper or Netflix Archaius.\n\nIf you want to support your own locations, see the javadoc:org.springframework.boot.context.config.ConfigDataLocationResolver[] and javadoc:org.springframework.boot.context.config.ConfigDataLoader[] classes in the `org.springframework.boot.context.config` package.\n====\n\n\n\n[[features.external-config.files.importing-extensionless]]\n=== Importing Extensionless Files\n\nSome cloud platforms cannot add a file extension to volume mounted files.\nTo import these extensionless files, you need to give Spring Boot a hint so that it knows how to load them.\nYou can do this by putting an extension hint in square brackets.\n\nFor example, suppose you have a `/etc/config/myconfig` file that you wish to import as yaml.\nYou can import it from your `application.properties` using the following:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"file:/etc/config/myconfig[.yaml]\"\n----\n\nThis is the shorthand for:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"file:/etc/config/myconfig[extension=.yaml]\"\n----\n\n\n\n[[features.external-config.files.attributes]]\n=== File attributes\n\nThe configprop:spring.config.import[] configuration property supports file attributes, as shown when specifying the xref:features/external-config.adoc#features.external-config.files.importing[encoding] or the xref:features/external-config.adoc#features.external-config.files.importing-extensionless[extension].\n\nIf you need to specify multiple attributes, you can use this syntax:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"file:/etc/config/myconfig[extension=.yaml][encoding=utf-8]\"\n----\n\n\n\n[[features.external-config.files.env-variables]]\n=== Using Environment Variables\n\nWhen running applications on a cloud platform (such as Kubernetes) you often need to read config values that the platform supplies.\nYou can either use environment variables for such purpose, or you can use xref:reference:features/external-config.adoc#features.external-config.files.configtree[configuration trees].\n\nYou can even store whole configurations in properties or yaml format in (multiline) environment variables and load them using the `env:` prefix.\nAssume there's an environment variable called `MY_CONFIGURATION` with this content:\n\n[source,properties]\n----\nmy.name=Service1\nmy.cluster=Cluster1\n----\n\nUsing the `env:` prefix it is possible to import all properties from this variable:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"env:MY_CONFIGURATION\"\n----\n\nTIP: This feature also supports xref:reference:features/external-config.adoc#features.external-config.files.importing-extensionless[specifying the extension].\nThe default extension is `.properties`.\n\n\n\n[[features.external-config.files.configtree]]\n=== Using Configuration Trees\n\nStoring config values in environment variables has drawbacks, especially if the value is supposed to be kept secret.\n\nAs an alternative to environment variables, many cloud platforms now allow you to map configuration into mounted data volumes.\nFor example, Kubernetes can volume mount both https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#populate-a-volume-with-data-stored-in-a-configmap[`ConfigMaps`] and https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-files-from-a-pod[`Secrets`].\n\nThere are two common volume mount patterns that can be used:\n\n. A single file contains a complete set of properties (usually written as YAML).\n. Multiple files are written to a directory tree, with the filename becoming the '`key`' and the contents becoming the '`value`'.\n\nFor the first case, you can import the YAML or Properties file directly using `spring.config.import` as described xref:features/external-config.adoc#features.external-config.files.importing[above].\nFor the second case, you need to use the `configtree:` prefix so that Spring Boot knows it needs to expose all the files as properties.\n\nAs an example, let's imagine that Kubernetes has mounted the following volume:\n\n[source]\n----\netc/\n  config/\n    myapp/\n      username\n      password\n----\n\nThe contents of the `username` file would be a config value, and the contents of `password` would be a secret.\n\nTo import these properties, you can add the following to your `application.properties` or `application.yaml` file:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"optional:configtree:/etc/config/\"\n----\n\nYou can then access or inject `myapp.username` and `myapp.password` properties from the javadoc:org.springframework.core.env.Environment[] in the usual way.\n\nTIP: The names of the folders and files under the config tree form the property name.\nIn the above example, to access the properties as `username` and `password`, you can set `spring.config.import` to `optional:configtree:/etc/config/myapp`.\n\nNOTE: Filenames with dot notation are also correctly mapped.\nFor example, in the above example, a file named `myapp.username` in `/etc/config` would result in a `myapp.username` property in the javadoc:org.springframework.core.env.Environment[].\n\nTIP: Configuration tree values can be bound to both string javadoc:java.lang.String[] and `byte[]` types depending on the contents expected.\n\nIf you have multiple config trees to import from the same parent folder you can use a wildcard shortcut.\nAny `configtree:` location that ends with `/*/` will import all immediate children as config trees.\nAs with a non-wildcard import, the names of the folders and files under each config tree form the property name.\n\nFor example, given the following volume:\n\n[source]\n----\netc/\n  config/\n    dbconfig/\n      db/\n        username\n        password\n    mqconfig/\n      mq/\n        username\n        password\n----\n\nYou can use `configtree:/etc/config/*/` as the import location:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"optional:configtree:/etc/config/*/\"\n----\n\nThis will add `db.username`, `db.password`, `mq.username` and `mq.password` properties.\n\nNOTE: Directories loaded using a wildcard are sorted alphabetically.\nIf you need a different order, then you should list each location as a separate import\n\n\nConfiguration trees can also be used for Docker secrets.\nWhen a Docker swarm service is granted access to a secret, the secret gets mounted into the container.\nFor example, if a secret named `db.password` is mounted at location `/run/secrets/`, you can make `db.password` available to the Spring environment using the following:\n\n[configprops,yaml]\n----\nspring:\n  config:\n    import: \"optional:configtree:/run/secrets/\"\n----\n\n\n\n[[features.external-config.files.property-placeholders]]\n=== Property Placeholders\n\nThe values in `application.properties` and `application.yaml` are filtered through the existing javadoc:org.springframework.core.env.Environment[] when they are used, so you can refer back to previously defined values (for example, from System properties or environment variables).\nThe standard `$\\{name}` property-placeholder syntax can be used anywhere within a value.\nProperty placeholders can also specify a default value using a `:` to separate the default value from the property name, for example `${name:default}`.\n\nThe use of placeholders with and without defaults is shown in the following example:\n\n[configprops%novalidate,yaml]\n----\napp:\n  name: \"MyApp\"\n  description: \"${app.name} is a Spring Boot application written by ${username:Unknown}\"\n----\n\nAssuming that the `username` property has not been set elsewhere, `app.description` will have the value `MyApp is a Spring Boot application written by Unknown`.\n\n[NOTE]\n====\nYou should always refer to property names in the placeholder using their canonical form (kebab-case using only lowercase letters).\nThis will allow Spring Boot to use the same logic as it does when xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[relaxed binding] javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\n\nFor example, `${demo.item-price}` will pick up `demo.item-price` and `demo.itemPrice` forms from the `application.properties` file, as well as `DEMO_ITEMPRICE` from the system environment.\nIf you use `${demo.itemPrice}` instead, it will pick up the `demo.itemPrice` form from the `application.properties` file, as well as `DEMO_ITEMPRICE` from the system environment, but `demo.item-price` would not be considered.\n====\n\nTIP: You can also use this technique to create \"`short`\" variants of existing Spring Boot properties.\nSee the xref:how-to:properties-and-configuration.adoc#howto.properties-and-configuration.short-command-line-arguments[] section in \"`How-to Guides`\" for details.\n\n\n\n[[features.external-config.files.multi-document]]\n=== Working With Multi-Document Files\n\nSpring Boot allows you to split a single physical file into multiple logical documents which are each added independently.\nDocuments are processed in order, from top to bottom.\nLater documents can override the properties defined in earlier ones.\n\nFor `application.yaml` files, the standard YAML multi-document syntax is used.\nThree consecutive hyphens represent the end of one document, and the start of the next.\n\nFor example, the following file has two logical documents:\n\n[source,yaml]\n----\nspring:\n  application:\n    name: \"MyApp\"\n---\nspring:\n  application:\n    name: \"MyCloudApp\"\n  config:\n    activate:\n      on-cloud-platform: \"kubernetes\"\n----\n\nFor `application.properties` files a special `#---` or `!---` comment is used to mark the document splits:\n\n[source,properties]\n----\nspring.application.name=MyApp\n#---\nspring.application.name=MyCloudApp\nspring.config.activate.on-cloud-platform=kubernetes\n----\n\nNOTE: Property file separators must not have any leading whitespace and must have exactly three hyphen characters.\nThe lines immediately before and after the separator must not be same comment prefix.\n\nTIP: Multi-document property files are often used in conjunction with activation properties such as `spring.config.activate.on-profile`.\nSee the xref:features/external-config.adoc#features.external-config.files.activation-properties[next section] for details.\n\nWARNING: Multi-document property files cannot be loaded by using the javadoc:org.springframework.context.annotation.PropertySource[format=annotation] or javadoc:org.springframework.test.context.TestPropertySource[format=annotation] annotations.\n\n\n\n[[features.external-config.files.activation-properties]]\n=== Activation Properties\n\nIt is sometimes useful to only activate a given set of properties when certain conditions are met.\nFor example, you might have properties that are only relevant when a specific profile is active.\n\nYou can conditionally activate a properties document using `spring.config.activate.*`.\n\nThe following activation properties are available:\n\n.activation properties\n[cols=\"1,4\"]\n|===\n| Property | Note\n\n| `on-profile`\n| A profile expression that must match for the document to be active, or a list of profile expressions of which at least one must match for the document to be active.\n\n| `on-cloud-platform`\n| The javadoc:org.springframework.boot.cloud.CloudPlatform[] that must be detected for the document to be active.\n|===\n\nFor example, the following specifies that the second document is only active when running on Kubernetes, and only when either the \"`prod`\" or \"`staging`\" profiles are active:\n\n[configprops%novalidate,yaml]\n----\nmyprop:\n  \"always-set\"\n---\nspring:\n  config:\n    activate:\n      on-cloud-platform: \"kubernetes\"\n      on-profile: \"prod | staging\"\nmyotherprop: \"sometimes-set\"\n----\n\n\n\n[[features.external-config.encrypting]]\n== Encrypting Properties\n\nSpring Boot does not provide any built-in support for encrypting property values, however, it does provide the hook points necessary to modify values contained in the Spring javadoc:org.springframework.core.env.Environment[].\nThe javadoc:org.springframework.boot.EnvironmentPostProcessor[] interface allows you to manipulate the javadoc:org.springframework.core.env.Environment[] before the application starts.\nSee xref:how-to:application.adoc#howto.application.customize-the-environment-or-application-context[] for details.\n\nIf you need a secure way to store credentials and passwords, the https://cloud.spring.io/spring-cloud-vault/[Spring Cloud Vault] project provides support for storing externalized configuration in https://www.vaultproject.io/[HashiCorp Vault].\n\n\n\n[[features.external-config.yaml]]\n== Working With YAML\n\nhttps://yaml.org[YAML] is a superset of JSON and, as such, is a convenient format for specifying hierarchical configuration data.\nThe javadoc:org.springframework.boot.SpringApplication[] class automatically supports YAML as an alternative to properties whenever you have the https://github.com/snakeyaml/snakeyaml[SnakeYAML] library on your classpath.\n\nNOTE: If you use starters, SnakeYAML is automatically provided by `spring-boot-starter`.\n\n\n\n[[features.external-config.yaml.mapping-to-properties]]\n=== Mapping YAML to Properties\n\nYAML documents need to be converted from their hierarchical format to a flat structure that can be used with the Spring javadoc:org.springframework.core.env.Environment[].\nFor example, consider the following YAML document:\n\n[source,yaml]\n----\nenvironments:\n  dev:\n    url: \"https://dev.example.com\"\n    name: \"Developer Setup\"\n  prod:\n    url: \"https://another.example.com\"\n    name: \"My Cool App\"\n----\n\nIn order to access these properties from the javadoc:org.springframework.core.env.Environment[], they would be flattened as follows:\n\n[source,properties]\n----\nenvironments.dev.url=https://dev.example.com\nenvironments.dev.name=Developer Setup\nenvironments.prod.url=https://another.example.com\nenvironments.prod.name=My Cool App\n----\n\nLikewise, YAML lists also need to be flattened.\nThey are represented as property keys with `[index]` dereferencers.\nFor example, consider the following YAML:\n\n[source,yaml]\n----\n my:\n  servers:\n  - \"dev.example.com\"\n  - \"another.example.com\"\n----\n\nThe preceding example would be transformed into these properties:\n\n[source,properties]\n----\nmy.servers[0]=dev.example.com\nmy.servers[1]=another.example.com\n----\n\nTIP: Properties that use the `[index]` notation can be bound to Java javadoc:java.util.List[] or javadoc:java.util.Set[] objects using Spring Boot's javadoc:org.springframework.boot.context.properties.bind.Binder[] class.\nFor more details see the xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties[] section below.\n\nWARNING: YAML files cannot be loaded by using the javadoc:org.springframework.context.annotation.PropertySource[format=annotation] or javadoc:org.springframework.test.context.TestPropertySource[format=annotation] annotations.\nSo, in the case that you need to load values that way, you need to use a properties file.\n\n\n\n[[features.external-config.yaml.directly-loading]]\n=== Directly Loading YAML\n\nSpring Framework provides two convenient classes that can be used to load YAML documents.\nThe javadoc:org.springframework.beans.factory.config.YamlPropertiesFactoryBean[] loads YAML as javadoc:java.util.Properties[] and the javadoc:org.springframework.beans.factory.config.YamlMapFactoryBean[] loads YAML as a javadoc:java.util.Map[].\n\nYou can also use the javadoc:org.springframework.boot.env.YamlPropertySourceLoader[] class if you want to load YAML as a Spring javadoc:org.springframework.core.env.PropertySource[].\n\n\n\n[[features.external-config.random-values]]\n== Configuring Random Values\n\nThe javadoc:org.springframework.boot.env.RandomValuePropertySource[] is useful for injecting random values (for example, into secrets or test cases).\nIt can produce integers, longs, uuids, or strings, as shown in the following example:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  secret: \"${random.value}\"\n  number: \"${random.int}\"\n  bignumber: \"${random.long}\"\n  uuid: \"${random.uuid}\"\n  number-less-than-ten: \"${random.int(10)}\"\n  number-in-range: \"${random.int[1024,65536]}\"\n----\n\nThe `+random.int*+` syntax is `OPEN value (,max) CLOSE` where the `OPEN,CLOSE` are any character and `value,max` are integers.\nIf `max` is provided, then `value` is the minimum value and `max` is the maximum value (exclusive).\n\n\n\n[[features.external-config.system-environment]]\n== Configuring System Environment Properties\n\nSpring Boot supports setting a prefix for environment properties.\nThis is useful if the system environment is shared by multiple Spring Boot applications with different configuration requirements.\nThe prefix for system environment properties can be set directly on javadoc:org.springframework.boot.SpringApplication[] by calling the `setEnvironmentPrefix(...)` method before the application is run.\n\nFor example, if you set the prefix to `input`, a property such as `remote.timeout` will be resolved as `INPUT_REMOTE_TIMEOUT` in the system environment.\n\nNOTE: The prefix _only_ applies to system environment properties.\nThe example above would continue to use `remote.timeout` when reading properties from other sources.\n\n\n\n[[features.external-config.typesafe-configuration-properties]]\n== Type-safe Configuration Properties\n\nUsing the `@Value(\"$\\{property}\")` annotation to inject configuration properties can sometimes be cumbersome, especially if you are working with multiple properties or your data is hierarchical in nature.\nSpring Boot provides an alternative method of working with properties that lets strongly typed beans govern and validate the configuration of your application.\n\nTIP: See also the xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation[differences between javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] and type-safe configuration properties].\n\n\n\n[[features.external-config.typesafe-configuration-properties.java-bean-binding]]\n=== JavaBean Properties Binding\n\nIt is possible to bind a bean declaring standard JavaBean properties as shown in the following example:\n\ninclude-code::MyProperties[]\n\nThe preceding POJO defines the following properties:\n\n* `my.service.enabled`, with a value of `false` by default.\n* `my.service.remote-address`, with a type that can be coerced from javadoc:java.lang.String[].\n* `my.service.security.username`, with a nested \"security\" object whose name is determined by the name of the property.\n  In particular, the type is not used at all there and could have been javadoc:org.springframework.boot.security.autoconfigure.SecurityProperties[].\n* `my.service.security.password`.\n* `my.service.security.roles`, with a collection of javadoc:java.lang.String[] that defaults to `USER`.\n\nTIP: To use a reserved keyword in the name of a property, such as `my.service.import`, use the javadoc:org.springframework.boot.context.properties.bind.Name[format=annotation] annotation on the property's field.\n\nNOTE: The properties that map to javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] classes available in Spring Boot, which are configured through properties files, YAML files, environment variables, and other mechanisms, are public API but the accessors (getters/setters) of the class itself are not meant to be used directly.\n\n[NOTE]\n====\nSuch arrangement relies on a default empty constructor and getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC.\nA setter may be omitted in the following cases:\n\n* Pre-initialized Maps and Collections, as long as they are initialized with a mutable implementation (like the `roles` field in the preceding example).\n* Pre-initialized nested POJOs (like the `Security` field in the preceding example).\n  If you want the binder to create the instance on the fly by using its default constructor, you need a setter.\n\nSome people use Project Lombok to add getters and setters automatically.\nMake sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object.\n\nFinally, only standard Java Bean properties are considered and binding on static properties is not supported.\n====\n\n\n\n[[features.external-config.typesafe-configuration-properties.constructor-binding]]\n=== Constructor Binding\n\nThe example in the previous section can be rewritten in an immutable fashion as shown in the following example:\n\ninclude-code::MyProperties[]\n\nIn this setup, the presence of a single parameterized constructor implies that constructor binding should be used.\nThis means that the binder will find a constructor with the parameters that you wish to have bound.\nIf your class has multiple constructors, the javadoc:org.springframework.boot.context.properties.bind.ConstructorBinding[format=annotation] annotation can be used to specify which constructor to use for constructor binding.\n\nTo opt-out of constructor binding for a class, the parameterized constructor must be annotated with javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] or made `private`.\nKotlin developers can use an empty primary constructor to opt-out of constructor binding.\n\nFor example:\n\ninclude-code::primaryconstructor/MyProperties[]\n\nConstructor binding can be used with records.\nUnless your record has multiple constructors, there is no need to use javadoc:org.springframework.boot.context.properties.bind.ConstructorBinding[format=annotation].\n\nNested members of a constructor bound class (such as `Security` in the example above) will also be bound through their constructor.\n\nNOTE: To use constructor binding the class must be enabled using javadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] or configuration property scanning.\nYou cannot use constructor binding with beans that are created by the regular Spring mechanisms (for example javadoc:org.springframework.stereotype.Component[format=annotation] beans, beans created by using javadoc:org.springframework.context.annotation.Bean[format=annotation] methods or beans loaded by using javadoc:org.springframework.context.annotation.Import[format=annotation])\n\nNOTE: To use constructor binding the class must be compiled with `-parameters`.\nThis will happen automatically if you use Spring Boot's Gradle plugin or if you use Maven and `spring-boot-starter-parent`.\n\nNOTE: The use of javadoc:java.util.Optional[] with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] is not recommended as it is primarily intended for use as a return type.\nAs such, it is not well-suited to configuration property injection.\nFor consistency with properties of other types, if you do declare an javadoc:java.util.Optional[] property and it has no value, `null` rather than an empty javadoc:java.util.Optional[] will be bound.\n\nTIP: To use a reserved keyword in the name of a property, such as `my.service.import`, use the javadoc:org.springframework.boot.context.properties.bind.Name[format=annotation] annotation on the constructor parameter.\n\n\n\n[[features.external-config.typesafe-configuration-properties.constructor-binding.default-values]]\n==== @DefaultValue and Binding\n\nDefault values can be specified using javadoc:org.springframework.boot.context.properties.bind.DefaultValue[format=annotation] on constructor parameters and record components.\nThe conversion service will be applied to coerce the annotation's javadoc:java.lang.String[] value to the target type of a missing property.\n\nIn the `MyProperties` example above, you can see the nested `Security` class uses `@DefaultValue(\"USER\")` for the `roles` parameter.\nThis means that if `security` properties are defined, but `roles` is not, the default of `\"USER\"` will be bound.\n\nFor example, the following properties:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  service:\n    enabled: true\n    security:\n      username: admin\n----\n\nWill be bound as `new MyProperties(true, null, new Security(\"admin\", null, List.of(\"USER\")))`\n\nIf the `security` property is not present at all, then the `Security` instance will be `null`.\n\nFor example, the following properties:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  service:\n    enabled: true\n----\n\nWill be bound as `new MyProperties(true, null, null)`\n\n[NOTE]\n====\nYou can define an empty `security` property if you want to trigger binding with fully default `Security` instance.\n\nFor YAML, you can use the following syntax:\n\n[,yaml]\n----\nmy:\n  service:\n    enabled: true\n    security: {}\n----\n\nWith `Properties` you can use:\n\n[,properties]\n----\nmy.service.enabled=true\nmy.service.security=\n----\n\nWill be bound as `new MyProperties(true, null, new Security(null, null, List.of(\"USER\")))`\n====\n\nIf you want to always bind a non-null instance of `Security`, even when properties are missing, you can use an empty javadoc:org.springframework.boot.context.properties.bind.DefaultValue[format=annotation] annotation:\n\ninclude-code::nonnull/MyProperties[tag=*]\n\nTIP: When using Kotlin, you will need to declare the `username` and `password` parameters as nullable since they do not have default values\n\n\n\n[[features.external-config.typesafe-configuration-properties.default-values]]\n=== Default Values\n\nDefault Values defined in configuration properties are not reflected in the javadoc:org.springframework.core.env.Environment[].\nIn the examples above, the `enabled` property of `MyProperties` bound to `my.service` is `false` by default.\n\nHowever,  `my.service.enabled` is not available in the `Environment` with a value of `false` if no such property is set by the user.\nConcretely, this prevents you to use `@Value(${\"my.service.enabled\"})` or `my.service.enabled` as a placeholder in configuration properties without explicitly providing a default.\nIf you need to query the javadoc:org.springframework.core.env.Environment[] for that property, for instance in a javadoc:org.springframework.context.annotation.Condition[] implementation, the default needs to be provided as well.\n\n\n\n[[features.external-config.typesafe-configuration-properties.enabling-annotated-types]]\n=== Enabling @ConfigurationProperties-annotated Types\n\nSpring Boot provides infrastructure to bind javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] types and register them as beans.\nYou can either enable configuration properties on a class-by-class basis or enable configuration property scanning that works in a similar manner to component scanning.\n\nSometimes, classes annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] might not be suitable for scanning, for example, if you're developing your own auto-configuration or you want to enable them conditionally.\nIn these cases, specify the list of types to process using the javadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] annotation.\nThis can be done on any javadoc:org.springframework.context.annotation.Configuration[format=annotation] class, as shown in the following example:\n\ninclude-code::MyConfiguration[]\ninclude-code::SomeProperties[]\n\nTo use configuration property scanning, add the javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesScan[format=annotation] annotation to your application.\nTypically, it is added to the main application class that is annotated with javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] but it can be added to any javadoc:org.springframework.context.annotation.Configuration[format=annotation] class.\nBy default, scanning will occur from the package of the class that declares the annotation.\nIf you want to define specific packages to scan, you can do so as shown in the following example:\n\ninclude-code::MyApplication[]\n\n[NOTE]\n====\nWhen the javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] bean is registered using configuration property scanning or through javadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation], the bean has a conventional name: `<prefix>-<fqn>`, where `<prefix>` is the environment key prefix specified in the javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] annotation and `<fqn>` is the fully qualified name of the bean.\nIf the annotation does not provide any prefix, only the fully qualified name of the bean is used.\n\nAssuming that it is in the `com.example.app` package, the bean name of the `SomeProperties` example above is `some.properties-com.example.app.SomeProperties`.\n====\n\nWe recommend that javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] only deal with the environment and, in particular, does not inject other beans from the context.\nFor corner cases, setter injection can be used or any of the `*Aware` interfaces provided by the framework (such as javadoc:org.springframework.context.EnvironmentAware[] if you need access to the javadoc:org.springframework.core.env.Environment[]).\nIf you still want to inject other beans using the constructor, the configuration properties bean must be annotated with javadoc:org.springframework.stereotype.Component[format=annotation] and use JavaBean-based property binding.\n\n\n\n[[features.external-config.typesafe-configuration-properties.using-annotated-types]]\n=== Using @ConfigurationProperties-annotated Types\n\nThis style of configuration works particularly well with the javadoc:org.springframework.boot.SpringApplication[] external YAML configuration, as shown in the following example:\n\n[source,yaml]\n----\nmy:\n  service:\n    remote-address: 192.168.1.1\n    security:\n      username: \"admin\"\n      roles:\n      - \"USER\"\n      - \"ADMIN\"\n----\n\nTo work with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans, you can inject them in the same way as any other bean, as shown in the following example:\n\ninclude-code::MyService[]\n\nTIP: Using javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] also lets you generate metadata files that can be used by IDEs to offer auto-completion for your own keys.\nSee the xref:specification:configuration-metadata/index.adoc[appendix] for details.\n\n\n\n[[features.external-config.typesafe-configuration-properties.third-party-configuration]]\n=== Third-party Configuration\n\nAs well as using javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] to annotate a class, you can also use it on public javadoc:org.springframework.context.annotation.Bean[format=annotation] methods.\nDoing so can be particularly useful when you want to bind properties to third-party components that are outside of your control.\n\nTo configure a bean from the javadoc:org.springframework.core.env.Environment[] properties, add javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] to its bean registration, as shown in the following example:\n\ninclude-code::ThirdPartyConfiguration[]\n\nAny JavaBean property defined with the `another` prefix is mapped onto that `AnotherComponent` bean in manner similar to the preceding `SomeProperties` example.\n\n\n\n[[features.external-config.typesafe-configuration-properties.relaxed-binding]]\n=== Relaxed Binding\n\nSpring Boot uses some relaxed rules for binding javadoc:org.springframework.core.env.Environment[] properties to javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans, so there does not need to be an exact match between the javadoc:org.springframework.core.env.Environment[] property name and the bean property name.\nCommon examples where this is useful include dash-separated environment properties (for example, `context-path` binds to `contextPath`), and capitalized environment properties (for example, `PORT` binds to `port`).\n\nAs an example, consider the following javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] class:\n\ninclude-code::MyPersonProperties[]\n\nWith the preceding code, the following properties names can all be used:\n\n.relaxed binding\n[cols=\"1,4\"]\n|===\n| Property | Note\n\n| `my.main-project.person.first-name`\n| Kebab case, which is recommended for use in `.properties` and YAML files.\n\n| `my.main-project.person.firstName`\n| Standard camel case syntax.\n\n| `my.main-project.person.first_name`\n| Underscore notation, which is an alternative format for use in `.properties` and YAML files.\n\n| `MY_MAINPROJECT_PERSON_FIRSTNAME`\n| Upper case format, which is recommended when using system environment variables.\n|===\n\nNOTE: The `prefix` value for the annotation _must_ be in kebab case (lowercase and separated by `-`, such as `my.main-project.person`).\n\n.relaxed binding rules per property source\n[cols=\"2,4,4\"]\n|===\n| Property Source | Simple | List\n\n| Properties Files\n| Camel case, kebab case, or underscore notation\n| Standard list syntax using `[ ]` or comma-separated values\n\n| YAML Files\n| Camel case, kebab case, or underscore notation\n| Standard YAML list syntax or comma-separated values\n\n| Environment Variables\n| Upper case format with underscore as the delimiter (see xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[]).\n| Numeric values surrounded by underscores (see xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables[])\n\n| System properties\n| Camel case, kebab case, or underscore notation\n| Standard list syntax using `[ ]` or comma-separated values\n|===\n\nTIP: We recommend that, when possible, properties are stored in lower-case kebab format, such as `my.person.first-name=Rod`.\n\n\n\n[[features.external-config.typesafe-configuration-properties.relaxed-binding.maps]]\n==== Binding Maps\n\nWhen binding to javadoc:java.util.Map[] properties you may need to use a special bracket notation so that the original `key` value is preserved.\nIf the key is not surrounded by `[]`, any characters that are not alpha-numeric, `-` or `.` are removed.\n\nFor example, consider binding the following properties to a `Map<String,String>`:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  map:\n    \"[/key1]\": \"value1\"\n    \"[/key2]\": \"value2\"\n    \"/key3\": \"value3\"\n----\n\nNOTE: For YAML files, the brackets need to be surrounded by quotes for the keys to be parsed properly.\n\nThe properties above will bind to a javadoc:java.util.Map[] with `/key1`, `/key2` and `key3` as the keys in the map.\nThe slash has been removed from `key3` because it was not surrounded by square brackets.\n\nWhen binding to scalar values, keys with `.` in them do not need to be surrounded by `[]`.\nScalar values include enums and all types in the `java.lang` package except for javadoc:java.lang.Object[].\nBinding `a.b=c` to `Map<String, String>` will preserve the `.` in the key and return a Map with the entry `{\"a.b\"=\"c\"}`.\nFor any other types you need to use the bracket notation if your `key` contains a `.`.\nFor example, binding `a.b=c` to `Map<String, Object>` will return a Map with the entry `{\"a\"={\"b\"=\"c\"}}` whereas `[a.b]=c` will return a Map with the entry `{\"a.b\"=\"c\"}`.\n\n\n\n[[features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables]]\n==== Binding From Environment Variables\n\nMost operating systems impose strict rules around the names that can be used for environment variables.\nFor example, Linux shell variables can contain only letters (`a` to `z` or `A` to `Z`), numbers (`0` to `9`) or the underscore character (`_`).\nBy convention, Unix shell variables will also have their names in UPPERCASE.\n\nSpring Boot's relaxed binding rules are, as much as possible, designed to be compatible with these naming restrictions.\n\nTo convert a property name in the canonical-form to an environment variable name you can follow these rules:\n\n* Replace dots (`.`) with underscores (`_`).\n* Remove any dashes (`-`).\n* Convert to uppercase.\n\nFor example, the configuration property `spring.main.log-startup-info` would be an environment variable named `SPRING_MAIN_LOGSTARTUPINFO`.\n\nEnvironment variables can also be used when binding to object lists.\nTo bind to a javadoc:java.util.List[], the element number should be surrounded with underscores in the variable name.\n\nFor example, the configuration property `my.service[0].other` would use an environment variable named `MY_SERVICE_0_OTHER`.\n\nSupport for binding from environment variables is applied to the `systemEnvironment` property source and to any additional property source whose name ends with `-systemEnvironment`.\n\n\n\n[[features.external-config.typesafe-configuration-properties.relaxed-binding.maps-from-environment-variables]]\n==== Binding Maps From Environment Variables\n\nWhen Spring Boot binds an environment variable to a property class, it lowercases the environment variable name before binding.\nMost of the time this detail isn't important, except when binding to javadoc:java.util.Map[] properties.\n\nThe keys in the javadoc:java.util.Map[] are always in lowercase, as seen in the following example:\n\ninclude-code::MyMapsProperties[]\n\nWhen setting `MY_PROPS_VALUES_KEY=value`, the `values` javadoc:java.util.Map[] contains a `{\"key\"=\"value\"}` entry.\n\nOnly the environment variable *name* is lower-cased, not the value.\nWhen setting `MY_PROPS_VALUES_KEY=VALUE`, the `values` javadoc:java.util.Map[] contains a `{\"key\"=\"VALUE\"}` entry.\n\n\n\n[[features.external-config.typesafe-configuration-properties.relaxed-binding.caching]]\n==== Caching\n\nRelaxed binding uses a cache to improve performance. By default, this caching is only applied to immutable property sources.\nTo customize this behavior, for example to enable caching for mutable property sources, use javadoc:org.springframework.boot.context.properties.source.ConfigurationPropertyCaching[].\n\n\n\n[[features.external-config.typesafe-configuration-properties.merging-complex-types]]\n=== Merging Complex Types\n\nWhen lists are configured in more than one place, overriding works by replacing the entire list.\n\nFor example, assume a `MyPojo` object with `name` and `description` attributes that are `null` by default.\nThe following example exposes a list of `MyPojo` objects from `MyProperties`:\n\ninclude-code::list/MyProperties[]\n\nConsider the following configuration:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  list:\n  - name: \"my name\"\n    description: \"my description\"\n---\nspring:\n  config:\n    activate:\n      on-profile: \"dev\"\nmy:\n  list:\n  - name: \"my another name\"\n----\n\nIf the `dev` profile is not active, `MyProperties.list` contains one `MyPojo` entry, as previously defined.\nIf the `dev` profile is enabled, however, the `list` _still_ contains only one entry (with a name of `my another name` and a description of `null`).\nThis configuration _does not_ add a second `MyPojo` instance to the list, and it does not merge the items.\n\nWhen a javadoc:java.util.List[] is specified in multiple profiles, the one with the highest priority (and only that one) is used.\nConsider the following example:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  list:\n  - name: \"my name\"\n    description: \"my description\"\n  - name: \"another name\"\n    description: \"another description\"\n---\nspring:\n  config:\n    activate:\n      on-profile: \"dev\"\nmy:\n  list:\n  - name: \"my another name\"\n----\n\nIn the preceding example, if the `dev` profile is active, `MyProperties.list` contains _one_ `MyPojo` entry (with a name of `my another name` and a description of `null`).\nFor YAML, both comma-separated lists and YAML lists can be used for completely overriding the contents of the list.\n\nFor javadoc:java.util.Map[] properties, you can bind with property values drawn from multiple sources.\nHowever, for the same property in multiple sources, the one with the highest priority is used.\nThe following example exposes a `Map<String, MyPojo>` from `MyProperties`:\n\ninclude-code::map/MyProperties[]\n\nConsider the following configuration:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  map:\n    key1:\n      name: \"my name 1\"\n      description: \"my description 1\"\n---\nspring:\n  config:\n    activate:\n      on-profile: \"dev\"\nmy:\n  map:\n    key1:\n      name: \"dev name 1\"\n    key2:\n      name: \"dev name 2\"\n      description: \"dev description 2\"\n----\n\nIf the `dev` profile is not active, `MyProperties.map` contains one entry with key `key1` (with a name of `my name 1` and a description of `my description 1`).\nIf the `dev` profile is enabled, however, `map` contains two entries with keys `key1` (with a name of `dev name 1` and a description of `my description 1`) and `key2` (with a name of `dev name 2` and a description of `dev description 2`).\n\nNOTE: The preceding merging rules apply to properties from all property sources, and not just files.\n\n\n\n[[features.external-config.typesafe-configuration-properties.conversion]]\n=== Properties Conversion\n\nSpring Boot attempts to coerce the external application properties to the right type when it binds to the javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\nIf you need custom type conversion, you can provide a javadoc:org.springframework.core.convert.ConversionService[] bean (with a bean named `conversionService`) or custom property editors (through a javadoc:org.springframework.beans.factory.config.CustomEditorConfigurer[] bean) or custom converters (with bean definitions annotated as javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesBinding[format=annotation]).\n\n[NOTE]\n====\nBeans used for property conversion are requested very early during the application lifecycle so make sure to limit the dependencies that your javadoc:org.springframework.core.convert.ConversionService[] is using.\nTypically, any dependency that you require may not be fully initialized at creation time.\n====\n\nTIP: You may want to rename your custom javadoc:org.springframework.core.convert.ConversionService[] if it is not required for configuration keys coercion and only rely on custom converters qualified with javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesBinding[format=annotation].\nWhen qualifying a `@Bean` method with `@ConfigurationPropertiesBinding`, the method should be `static` to avoid \"`bean is not eligible for getting processed by all BeanPostProcessors`\" warnings.\n\n\n\n[[features.external-config.typesafe-configuration-properties.conversion.durations]]\n==== Converting Durations\n\nSpring Boot has dedicated support for expressing durations.\nIf you expose a javadoc:java.time.Duration[] property, the following formats in application properties are available:\n\n* A regular `long` representation (using milliseconds as the default unit unless a javadoc:org.springframework.boot.convert.DurationUnit[format=annotation] has been specified)\n* The standard ISO-8601 format {apiref-openjdk}/java.base/java/time/Duration.html#parse(java.lang.CharSequence)[used by javadoc:java.time.Duration[]]\n* A more readable format where the value and the unit are coupled (`10s` means 10 seconds)\n\nConsider the following example:\n\ninclude-code::javabeanbinding/MyProperties[]\n\nTo specify a session timeout of 30 seconds, `30`, `PT30S` and `30s` are all equivalent.\nA read timeout of 500ms can be specified in any of the following form: `500`, `PT0.5S` and `500ms`.\n\nYou can also use any of the supported units.\nThese are:\n\n* `ns` for nanoseconds\n* `us` for microseconds\n* `ms` for milliseconds\n* `s` for seconds\n* `m` for minutes\n* `h` for hours\n* `d` for days\n\nThe default unit is milliseconds and can be overridden using javadoc:org.springframework.boot.convert.DurationUnit[format=annotation] as illustrated in the sample above.\n\nIf you prefer to use constructor binding, the same properties can be exposed, as shown in the following example:\n\ninclude-code::constructorbinding/MyProperties[]\n\n\nTIP: If you are upgrading a javadoc:java.lang.Long[] property, make sure to define the unit (using javadoc:org.springframework.boot.convert.DurationUnit[format=annotation]) if it is not milliseconds.\nDoing so gives a transparent upgrade path while supporting a much richer format.\n\n\n\n[[features.external-config.typesafe-configuration-properties.conversion.periods]]\n==== Converting Periods\n\nIn addition to durations, Spring Boot can also work with javadoc:java.time.Period[] type.\nThe following formats can be used in application properties:\n\n* A regular `int` representation (using days as the default unit unless a javadoc:org.springframework.boot.convert.PeriodUnit[format=annotation] has been specified)\n* The standard ISO-8601 format {apiref-openjdk}/java.base/java/time/Period.html#parse(java.lang.CharSequence)[used by javadoc:java.time.Period[]]\n* A simpler format where the value and the unit pairs are coupled (`1y3d` means 1 year and 3 days)\n\nThe following units are supported with the simple format:\n\n* `y` for years\n* `m` for months\n* `w` for weeks\n* `d` for days\n\nNOTE: The javadoc:java.time.Period[] type never actually stores the number of weeks, it is a shortcut that means \"`7 days`\".\n\n\n\n[[features.external-config.typesafe-configuration-properties.conversion.data-sizes]]\n==== Converting Data Sizes\n\nSpring Framework has a javadoc:org.springframework.util.unit.DataSize[] value type that expresses a size in bytes.\nIf you expose a javadoc:org.springframework.util.unit.DataSize[] property, the following formats in application properties are available:\n\n* A regular `long` representation (using bytes as the default unit unless a javadoc:org.springframework.boot.convert.DataSizeUnit[format=annotation] has been specified)\n* A more readable format where the value and the unit are coupled (`10MB` means 10 megabytes)\n\nConsider the following example:\n\ninclude-code::javabeanbinding/MyProperties[]\n\nTo specify a buffer size of 10 megabytes, `10` and `10MB` are equivalent.\nA size threshold of 256 bytes can be specified as `256` or `256B`.\n\nYou can also use any of the supported units.\nThese are:\n\n* `B` for bytes\n* `KB` for kilobytes\n* `MB` for megabytes\n* `GB` for gigabytes\n* `TB` for terabytes\n\nThe default unit is bytes and can be overridden using javadoc:org.springframework.boot.convert.DataSizeUnit[format=annotation] as illustrated in the sample above.\n\nIf you prefer to use constructor binding, the same properties can be exposed, as shown in the following example:\n\ninclude-code::constructorbinding/MyProperties[]\n\nTIP: If you are upgrading a javadoc:java.lang.Long[] property, make sure to define the unit (using javadoc:org.springframework.boot.convert.DataSizeUnit[format=annotation]) if it is not bytes.\nDoing so gives a transparent upgrade path while supporting a much richer format.\n\n\n\n[[features.external-config.typesafe-configuration-properties.conversion.base64]]\n==== Converting Base64 Data\n\nSpring Boot supports resolving binary data that have been Base64 encoded.\nIf you expose a `Resource` property, the base64 encoded text can be provided as the value with a `base64:` prefix, as shown in the following example:\n\n[configprops%novalidate,yaml]\n----\nmy:\n  property: base64:SGVsbG8gV29ybGQ=\n----\n\nNOTE: The `Resource` property can also be used to provide the path to the resource, making it more versatile.\n\n\n\n[[features.external-config.typesafe-configuration-properties.validation]]\n=== @ConfigurationProperties Validation\n\nSpring Boot attempts to validate javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] classes whenever they are annotated with Spring's javadoc:org.springframework.validation.annotation.Validated[format=annotation] annotation.\nYou can use JSR-303 `jakarta.validation` constraint annotations directly on your configuration class.\nTo do so, ensure that a compliant JSR-303 implementation is on your classpath and then add constraint annotations to your fields, as shown in the following example:\n\ninclude-code::MyProperties[]\n\nTIP: You can also trigger validation by annotating the javadoc:org.springframework.context.annotation.Bean[format=annotation] method that creates the configuration properties with javadoc:org.springframework.validation.annotation.Validated[format=annotation].\n\nTo cascade validation to nested properties the associated field must be annotated with javadoc:jakarta.validation.Valid[format=annotation].\nThe following example builds on the preceding `MyProperties` example:\n\ninclude-code::nested/MyProperties[]\n\nYou can also add a custom Spring javadoc:org.springframework.validation.Validator[] by creating a bean definition called `configurationPropertiesValidator`.\nThe javadoc:org.springframework.context.annotation.Bean[format=annotation] method should be declared `static`.\nThe configuration properties validator is created very early in the application's lifecycle, and declaring the javadoc:org.springframework.context.annotation.Bean[format=annotation] method as static lets the bean be created without having to instantiate the javadoc:org.springframework.context.annotation.Configuration[format=annotation] class.\nDoing so avoids any problems that may be caused by early instantiation.\n\nTIP: The `spring-boot-actuator` module includes an endpoint that exposes all javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\nPoint your web browser to `/actuator/configprops` or use the equivalent JMX endpoint.\nSee the xref:actuator/endpoints.adoc[Production ready features] section for details.\n\n\n\n[[features.external-config.typesafe-configuration-properties.vs-value-annotation]]\n=== @ConfigurationProperties vs. @Value\n\nThe javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotation is a core container feature, and it does not provide the same features as type-safe configuration properties.\nThe following table summarizes the features that are supported by javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] and javadoc:org.springframework.beans.factory.annotation.Value[format=annotation]:\n\n[cols=\"4,2,2\"]\n|===\n| Feature |`@ConfigurationProperties` |`@Value`\n\n| xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[Relaxed binding]\n| Yes\n| Limited (see xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.vs-value-annotation.note[note below])\n\n| xref:specification:configuration-metadata/index.adoc[Meta-data support]\n| Yes\n| No\n\n| `SpEL` evaluation\n| No\n| Yes\n|===\n\n[[features.external-config.typesafe-configuration-properties.vs-value-annotation.note]]\n[NOTE]\n====\nIf you do want to use javadoc:org.springframework.beans.factory.annotation.Value[format=annotation], we recommend that you refer to property names using their canonical form (kebab-case using only lowercase letters).\nThis will allow Spring Boot to use the same logic as it does when xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[relaxed binding] javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\n\nFor example, `@Value(\"${demo.item-price}\")` will pick up `demo.item-price` and `demo.itemPrice` forms from the `application.properties` file, as well as `DEMO_ITEMPRICE` from the system environment.\nIf you use `@Value(\"${demo.itemPrice}\")` instead, it will pickup the `demo.itemPrice` form from the `application.properties` file, as well as `DEMO_ITEMPRICE` from the system environment, but `demo.item-price` would not be considered.\n====\n\nIf you define a set of configuration keys for your own components, we recommend you group them in a POJO annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\nDoing so will provide you with structured, type-safe object that you can inject into your own beans.\n\n`SpEL` expressions from  xref:features/external-config.adoc#features.external-config.files[application property files] are not processed at time of parsing these files and populating the environment.\nHowever, it is possible to write a `SpEL` expression in javadoc:org.springframework.beans.factory.annotation.Value[format=annotation].\nIf the value of a property from an application property file is a `SpEL` expression, it will be evaluated when consumed through javadoc:org.springframework.beans.factory.annotation.Value[format=annotation].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/index.adoc",
    "content": "[[features]]\n= Core Features\n\nThis section dives into the details of Spring Boot.\nHere you can learn about the key features that you may want to use and customize.\nIf you have not already done so, you might want to read the xref:tutorial:index.adoc[] and xref:using/index.adoc[] sections, so that you have a good grounding of the basics.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/internationalization.adoc",
    "content": "[[features.internationalization]]\n= Internationalization\n\nSpring Boot supports localized messages so that your application can cater to users of different language preferences.\nBy default, Spring Boot looks for the presence of a `messages` resource bundle at the root of the classpath.\n\nNOTE: The auto-configuration applies when the default properties file for the configured resource bundle is available (`messages.properties` by default).\nIf your resource bundle contains only language-specific properties files, you are required to add the default.\nIf no properties file is found that matches any of the configured base names, there will be no auto-configured javadoc:org.springframework.context.MessageSource[].\n\nThe basename of the resource bundle as well as several other attributes can be configured using the `spring.messages` namespace, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  messages:\n    basename: \"messages, config.i18n.messages\"\n    common-messages: \"classpath:my-common-messages.properties\"\n    fallback-to-system-locale: false\n----\n\nTIP: The configprop:spring.messages.basename[] property supports a list of locations, either a package qualifier or a resource resolved from the classpath root.\nThe configprop:spring.messages.common-messages[] property supports a list of property file resources.\n\nSee javadoc:org.springframework.boot.autoconfigure.context.MessageSourceProperties[] for more supported options.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/json.adoc",
    "content": "[[features.json]]\n= JSON\n\nSpring Boot provides integration with the following JSON mapping libraries:\n\n- Jackson 3\n- Jackson 2\n- Gson\n- JSON-B\n- Kotlin Serialization\n\nJackson 3 is the preferred and default library.\n\nSupport for Jackson 2 is deprecated and will be removed in a future Spring Boot 4.x release.\nIt is provided purely to ease the migration from Jackson 2 to Jackson 3 and should not be relied up in the longer term.\n\n\n\n[[features.json.jackson]]\n== Jackson 3\n\nAuto-configuration for Jackson 3 is provided and Jackson is part of `spring-boot-starter-json`.\nWhen Jackson is on the classpath a javadoc:tools.jackson.databind.json.JsonMapper[] bean is automatically configured.\nSeveral configuration properties are provided for xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-jsonmapper[customizing the configuration of the javadoc:tools.jackson.databind.json.JsonMapper[]].\n\n\n\n[[features.json.jackson.custom-serializers-and-deserializers]]\n=== Custom Serializers and Deserializers\n\nIf you use Jackson to serialize and deserialize JSON data, you might want to write your own javadoc:tools.jackson.databind.ValueSerializer[] and javadoc:tools.jackson.databind.ValueDeserializer[] classes.\nCustom serializers are usually https://github.com/FasterXML/jackson-docs/wiki/JacksonHowToCustomSerializers[registered with Jackson through a module], but Spring Boot provides an alternative javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation] annotation that makes it easier to directly register Spring Beans.\n\nYou can use the javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation] annotation directly on javadoc:tools.jackson.databind.ValueSerializer[], javadoc:tools.jackson.databind.ValueDeserializer[] or javadoc:tools.jackson.databind.KeyDeserializer[] implementations.\nYou can also use it on classes that contain serializers/deserializers as inner classes, as shown in the following example:\n\ninclude-code::MyJacksonComponent[]\n\nAll javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation] beans in the javadoc:org.springframework.context.ApplicationContext[] are automatically registered with Jackson.\nBecause javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation] is meta-annotated with javadoc:org.springframework.stereotype.Component[format=annotation], the usual component-scanning rules apply.\n\nSpring Boot also provides javadoc:org.springframework.boot.jackson.ObjectValueSerializer[] and javadoc:org.springframework.boot.jackson.ObjectValueDeserializer[] base classes that provide useful alternatives to the standard Jackson versions when serializing objects.\nSee javadoc:org.springframework.boot.jackson.ObjectValueSerializer[] and javadoc:org.springframework.boot.jackson.ObjectValueDeserializer[] in the API documentation for details.\n\nThe example above can be rewritten to use javadoc:org.springframework.boot.jackson.ObjectValueSerializer[] and javadoc:org.springframework.boot.jackson.ObjectValueDeserializer[] as follows:\n\ninclude-code::object/MyJacksonComponent[]\n\n\n\n[[features.json.jackson.mixins]]\n=== Mixins\n\nJackson has support for mixins that can be used to mix additional annotations into those already declared on a target class.\nSpring Boot's Jackson auto-configuration will scan your application's packages for classes annotated with javadoc:org.springframework.boot.jackson.JacksonMixin[format=annotation] and register them with the auto-configured javadoc:tools.jackson.databind.json.JsonMapper[].\nThe registration is performed by Spring Boot's javadoc:org.springframework.boot.jackson.JacksonMixinModule[].\n\n\n\n[[features.json.jackson2]]\n== Jackson 2\n\nDeprecated auto-configuration for Jackson 2 is provided by the `spring-boot-jackson2` module.\nWhen this module is on the classpath a javadoc:com.fasterxml.jackson.databind.ObjectMapper[] bean is automatically configured.\nSeveral `+spring.jackson2.*+` configuration properties are provided for customizing the configuration.\nTo take more control, define one or more javadoc:org.springframework.boot.jackson2.autoconfigure.Jackson2ObjectMapperBuilderCustomizer[] beans.\n\nWhen both Jackson 3 and Jackson 2 are present, various configuration properties can be used to indicate that Jackson 2 is preferred:\n\n- configprop:spring.graphql.rsocket.preferred-json-mapper[]\n- configprop:spring.http.codecs.preferred-json-mapper[] (used by Spring WebFlux and reactive HTTP clients)\n- configprop:spring.http.converters.preferred-json-mapper[] (used by Spring MVC and imperative HTTP clients)\n- configprop:spring.rsocket.preferred-mapper[]\n- configprop:spring.websocket.messaging.preferred-json-mapper[]\n\nIn each case, set the relevant property to `jackson2` to indicate that Jackson 2 is preferred.\n\n\n\n[[features.json.gson]]\n== Gson\n\nAuto-configuration for Gson is provided.\nWhen Gson is on the classpath a javadoc:com.google.gson.Gson[] bean is automatically configured.\nSeveral `+spring.gson.*+` configuration properties are provided for customizing the configuration.\nTo take more control, one or more javadoc:org.springframework.boot.gson.autoconfigure.GsonBuilderCustomizer[] beans can be used.\n\n\n\n[[features.json.json-b]]\n== JSON-B\n\nAuto-configuration for JSON-B is provided.\nWhen the JSON-B API and an implementation are on the classpath a javadoc:jakarta.json.bind.Jsonb[] bean will be automatically configured.\nThe preferred JSON-B implementation is Eclipse Yasson for which dependency management is provided.\n\n\n\n[[features.json.kotlin-serialization]]\n== Kotlin Serialization\n\nAuto-configuration for Kotlin Serialization is provided.\nWhen `kotlinx-serialization-json` is on the classpath a https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/[Json] bean is automatically configured.\nSeveral `+spring.kotlinx.serialization.json.*+` configuration properties are provided for customizing the configuration.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/kotlin.adoc",
    "content": "[[features.kotlin]]\n= Kotlin Support\n\nhttps://kotlinlang.org[Kotlin] is a statically-typed language targeting the JVM (and other platforms) which allows writing concise and elegant code while providing {url-kotlin-docs}/java-interop.html[interoperability] with existing libraries written in Java.\n\nSpring Boot provides Kotlin support by leveraging the support in other Spring projects such as Spring Framework, Spring Data, and Reactor.\nSee the {url-spring-framework-docs}/languages/kotlin.html[Spring Framework Kotlin support documentation] for more information.\n\nThe easiest way to start with Spring Boot and Kotlin is to follow https://spring.io/guides/tutorials/spring-boot-kotlin/[this comprehensive tutorial].\nYou can create new Kotlin projects by using https://start.spring.io/#!language=kotlin[start.spring.io].\nFeel free to join the #spring channel of https://slack.kotlinlang.org/[Kotlin Slack] or ask a question with the `spring` and `kotlin` tags on https://stackoverflow.com/questions/tagged/spring+kotlin[Stack Overflow] if you need support.\n\n\n\n[[features.kotlin.requirements]]\n== Requirements\n\nSpring Boot requires at least Kotlin 2.2.x and manages a suitable Kotlin version through dependency management.\nTo use Kotlin, `org.jetbrains.kotlin:kotlin-stdlib` and `org.jetbrains.kotlin:kotlin-reflect` must be present on the classpath.\n\nKotlin 2.2.x introduces https://kotlinlang.org/docs/whatsnew22.html#new-defaulting-rules-for-use-site-annotation-targets[new defaulting rules for propagating annotations to parameters, fields, and properties]. In order to avoid related warnings and use what will likely become the Kotlin default behavior in an upcoming version, it is recommended to configure the `-Xannotation-default-target=param-property` compiler flag.\n\nSince https://discuss.kotlinlang.org/t/classes-final-by-default/166[Kotlin classes are final by default], you are likely to want to configure {url-kotlin-docs}/compiler-plugins.html#spring-support[kotlin-spring] plugin in order to automatically open Spring-annotated classes so that they can be proxied.\n\nhttps://github.com/FasterXML/jackson-module-kotlin[Jackson's Kotlin module] is required for serializing / deserializing JSON data in Kotlin.\nIt is automatically registered when found on the classpath.\n\nTIP: These dependencies and plugins are provided by default if one bootstraps a Kotlin project on https://start.spring.io/#!language=kotlin[start.spring.io].\n\n\n\n[[features.kotlin.null-safety]]\n== Null-safety\n\nOne of Kotlin's key features is {url-kotlin-docs}/null-safety.html[null-safety].\nIt deals with `null` values at compile time rather than deferring the problem to runtime and encountering a javadoc:java.lang.NullPointerException[].\nThis helps to eliminate a common source of bugs without paying the cost of wrappers like javadoc:java.util.Optional[].\nKotlin also allows using functional constructs with nullable values as described in this https://www.baeldung.com/kotlin-null-safety[comprehensive guide to null-safety in Kotlin].\n\nAlthough Java does not let you express null-safety in its type-system, most Spring projects\nprovide {url-spring-framework-docs}/core/null-safety.html[null-safety] via https://jspecify.dev/[JSpecify] annotations.\n\nAs of Kotlin 2.1, Kotlin enforces strict handling of nullability annotations from the `org.jspecify.annotations` package.\n\n\n\n[[features.kotlin.api]]\n== Kotlin API\n\n\n\n[[features.kotlin.api.run-application]]\n=== runApplication\n\nSpring Boot provides an idiomatic way to run an application with `runApplication<MyApplication>(*args)` as shown in the following example:\n\n[source,kotlin]\n----\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n----\n\nThis is a drop-in replacement for `SpringApplication.run(MyApplication::class.java, *args)`.\nIt also allows customization of the application as shown in the following example:\n\n[source,kotlin]\n----\nrunApplication<MyApplication>(*args) {\n\tsetBannerMode(OFF)\n}\n----\n\n\n\n[[features.kotlin.api.extensions]]\n=== Extensions\n\nKotlin {url-kotlin-docs}/extensions.html[extensions] provide the ability to extend existing classes with additional functionality.\nThe Spring Boot Kotlin API makes use of these extensions to add new Kotlin specific conveniences to existing APIs.\n\njavadoc:org.springframework.boot.resttestclient.TestRestTemplate[] extensions, similar to those provided by Spring Framework for javadoc:org.springframework.web.client.RestOperations[] in Spring Framework, are provided.\nAmong other things, the extensions make it possible to take advantage of Kotlin reified type parameters.\n\n\n\n[[features.kotlin.dependency-management]]\n== Dependency Management\n\nIn order to avoid mixing different versions of Kotlin dependencies on the classpath, Spring Boot imports the Kotlin BOM.\n\nWith Maven, the Kotlin version can be customized by setting the `kotlin.version` property and plugin management is provided for `kotlin-maven-plugin`.\nWith Gradle, the Spring Boot plugin automatically aligns the `kotlin.version` with the version of the Kotlin plugin.\n\nSpring Boot also manages the version of Coroutines dependencies by importing the Kotlin Coroutines BOM.\nThe version can be customized by setting the `kotlin-coroutines.version` property.\n\nTIP: `org.jetbrains.kotlinx:kotlinx-coroutines-reactor` dependency is provided by default if one bootstraps a Kotlin project with at least one reactive dependency on https://start.spring.io/#!language=kotlin[start.spring.io].\n\n\n\n[[features.kotlin.configuration-properties]]\n== @ConfigurationProperties\njavadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] when used in combination with xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.constructor-binding[constructor binding] supports data classes with immutable `val` properties as shown in the following example:\n\n[source,kotlin]\n----\n@ConfigurationProperties(\"example.kotlin\")\ndata class KotlinExampleProperties(\n\t\tval name: String,\n\t\tval description: String,\n\t\tval myService: MyService\n) {\n\n\tdata class MyService(\n\t\t\tval apiToken: String,\n\t\t\tval uri: URI\n\t)\n}\n----\n\nDue to the limitations of their interoperability with Java, support for value classes is limited.\nIn particular, relying upon a value class's default value will not work with configuration property binding.\nIn such cases, a data class should be used instead.\n\nTIP: To generate xref:specification:configuration-metadata/annotation-processor.adoc[your own metadata] using the annotation processor, {url-kotlin-docs}/kapt.html[`kapt` should be configured] with the `spring-boot-configuration-processor` dependency.\nNote that some features (such as detecting the default value or deprecated items) are not working due to limitations in the model kapt provides.\n\n\n\n[[features.kotlin.testing]]\n== Testing\n\nWhile it is possible to use JUnit 4 to test Kotlin code, JUnit 6 is provided by default and is recommended.\nJUnit 6 enables a test class to be instantiated once and reused for all of the class's tests.\nThis makes it possible to use javadoc:org.junit.jupiter.api.BeforeAll[format=annotation] and javadoc:org.junit.jupiter.api.AfterAll[format=annotation] annotations on non-static methods, which is a good fit for Kotlin.\n\nTo mock Kotlin classes, https://mockk.io/[MockK] is recommended.\nIf you need the `MockK` equivalent of the Mockito specific xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.mocking-beans[`@MockitoBean` and javadoc:org.springframework.test.context.bean.override.mockito.MockitoSpyBean[format=annotation] annotations], you can use https://github.com/Ninja-Squad/springmockk[SpringMockK] which provides similar `@MockkBean` and `@SpykBean` annotations.\n\n\n\n[[features.kotlin.resources]]\n== Resources\n\n\n\n[[features.kotlin.resources.further-reading]]\n=== Further Reading\n\n* {url-kotlin-docs}[Kotlin language reference]\n* https://kotlinlang.slack.com/[Kotlin Slack] (with a dedicated #spring channel)\n* https://stackoverflow.com/questions/tagged/spring+kotlin[Stack Overflow with `spring` and `kotlin` tags]\n* https://try.kotlinlang.org/[Try Kotlin in your browser]\n* https://blog.jetbrains.com/kotlin/[Kotlin blog]\n* https://kotlin.link/[Awesome Kotlin]\n* https://spring.io/guides/tutorials/spring-boot-kotlin/[Tutorial: building web applications with Spring Boot and Kotlin]\n* https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin[Developing Spring Boot applications with Kotlin]\n* https://spring.io/blog/2016/03/20/a-geospatial-messenger-with-kotlin-spring-boot-and-postgresql[A Geospatial Messenger with Kotlin, Spring Boot and PostgreSQL]\n* https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0[Introducing Kotlin support in Spring Framework 5.0]\n* https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-way[Spring Framework 5 Kotlin APIs, the functional way]\n\n\n\n[[features.kotlin.resources.examples]]\n=== Examples\n\n* https://github.com/sdeleuze/spring-boot-kotlin-demo[spring-boot-kotlin-demo]: regular Spring Boot + Spring Data JPA project\n* https://github.com/mixitconf/mixit[mixit]: Spring Boot 2 + WebFlux + Reactive Spring Data MongoDB\n* https://github.com/sdeleuze/spring-kotlin-fullstack[spring-kotlin-fullstack]: WebFlux Kotlin fullstack example with Kotlin2js for frontend instead of JavaScript or TypeScript\n* https://github.com/spring-petclinic/spring-petclinic-kotlin[spring-petclinic-kotlin]: Kotlin version of the Spring PetClinic Sample Application\n* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: a step by step migration for Boot 1.0 + Java to Boot 2.0 + Kotlin\n* https://github.com/sdeleuze/spring-boot-coroutines-demo[spring-boot-coroutines-demo]: Coroutines sample project\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/logging.adoc",
    "content": "[[features.logging]]\n= Logging\n\nSpring Boot uses https://commons.apache.org/logging[Commons Logging] for all internal logging but leaves the underlying log implementation open.\nDefault configurations are provided for {apiref-openjdk}/java.logging/java/util/logging/package-summary.html[Java Util Logging], https://logging.apache.org/log4j/2.x/[Log4j2], and https://logback.qos.ch/[Logback].\nIn each case, loggers are pre-configured to use console output with optional file output also available.\n\nBy default, if you use the starters, Logback is used for logging.\nAppropriate Logback routing is also included to ensure that dependent libraries that use Java Util Logging, Commons Logging, Log4J, or SLF4J all work correctly.\n\nTIP: There are a lot of logging frameworks available for Java.\nDo not worry if the above list seems confusing.\nGenerally, you do not need to change your logging dependencies and the Spring Boot defaults work just fine.\n\nTIP: When you deploy your application to a servlet container or application server, logging performed with the Java Util Logging API is not routed into your application's logs.\nThis prevents logging performed by the container or other applications that have been deployed to it from appearing in your application's logs.\n\n\n\n[[features.logging.log-format]]\n== Log Format\n\nThe default log output from Spring Boot resembles the following example:\n\n[source]\n----\ninclude::ROOT:partial$logging/logging-format.txt[]\n----\n\nThe following items are output:\n\n* Date and Time: Millisecond precision and easily sortable.\n* Log Level: `ERROR`, `WARN`, `INFO`, `DEBUG`, or `TRACE`.\n* Process ID.\n* A `---` separator to distinguish the start of actual log messages.\n* Application name: Enclosed in square brackets (logged by default only if configprop:spring.application.name[] is set)\n* Application group: Enclosed in square brackets (logged by default only if configprop:spring.application.group[] is set)\n* Thread name: Enclosed in square brackets (may be truncated for console output).\n* Correlation ID: If tracing is enabled (not shown in the sample above)\n* Logger name: This is usually the source class name (often abbreviated).\n* The log message.\n\nNOTE: Logback does not have a `FATAL` level.\nIt is mapped to `ERROR`.\n\nTIP: If you have a configprop:spring.application.name[] property but don't want it logged you can set configprop:logging.include-application-name[] to `false`.\n\nTIP: If you have a configprop:spring.application.group[] property but don't want it logged you can set configprop:logging.include-application-group[] to `false`.\n\nTIP: For more details about correlation IDs, please xref:reference:actuator/tracing.adoc#actuator.micrometer-tracing.logging[see this documentation].\n\n\n\n[[features.logging.console-output]]\n== Console Output\n\nThe default log configuration echoes messages to the console as they are written.\nBy default, `ERROR`-level, `WARN`-level, and `INFO`-level messages are logged.\nYou can also enable a \"`debug`\" mode by starting your application with a `--debug` flag.\n\n[source,shell]\n----\n$ java -jar myapp.jar --debug\n----\n\nNOTE: You can also specify `debug=true` in your `application.properties`.\n\nWhen the debug mode is enabled, a selection of core loggers (embedded container, Hibernate, and Spring Boot) are configured to output more information.\nEnabling the debug mode does _not_ configure your application to log all messages with `DEBUG` level.\n\nAlternatively, you can enable a \"`trace`\" mode by starting your application with a `--trace` flag (or `trace=true` in your `application.properties`).\nDoing so enables trace logging for a selection of core loggers (embedded container, Hibernate schema generation, and the whole Spring portfolio).\n\nIf you want to disable console-based logging, you can set the configprop:logging.console.enabled[] property to `false`.\n\n\n\n[[features.logging.console-output.color-coded]]\n=== Color-coded Output\n\nIf your terminal supports ANSI, color output is used to aid readability.\nYou can set `spring.output.ansi.enabled` to a javadoc:org.springframework.boot.ansi.AnsiOutput$Enabled[supported value] to override the auto-detection.\n\nColor coding is configured by using the `%clr` conversion word.\nIn its simplest form, the converter colors the output according to the log level, as shown in the following example:\n\n[source]\n----\n%clr(%5p)\n----\n\nThe following table describes the mapping of log levels to colors:\n\n|===\n| Level | Color\n\n| `FATAL`\n| Red\n\n| `ERROR`\n| Red\n\n| `WARN`\n| Yellow\n\n| `INFO`\n| Green\n\n| `DEBUG`\n| Green\n\n| `TRACE`\n| Green\n|===\n\nAlternatively, you can specify the color and styles that should be used by providing them as options to the conversion.\nFor example, to make the text yellow and bold, use the following setting:\n\n[source]\n----\n%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){yellow,bold}\n----\n\nThe following text colors are supported:\n\n* `black`\n* `blue`\n* `bright_black`\n* `bright_blue`\n* `bright_cyan`\n* `bright_green`\n* `bright_magenta`\n* `bright_red`\n* `bright_white`\n* `bright_yellow`\n* `cyan`\n* `green`\n* `magenta`\n* `red`\n* `white`\n* `yellow`\n\nThe following background colors are supported:\n\n* `bg_black`\n* `bg_blue`\n* `bg_bright_black`\n* `bg_bright_blue`\n* `bg_bright_cyan`\n* `bg_bright_green`\n* `bg_bright_magenta`\n* `bg_bright_red`\n* `bg_bright_white`\n* `bg_bright_yellow`\n* `bg_cyan`\n* `bg_green`\n* `bg_magenta`\n* `bg_red`\n* `bg_white`\n* `bg_yellow`\n\nThe following styles are supported:\n\n* `bold`\n* `faint`\n* `italic`\n* `normal`\n* `reverse`\n* `underline`\n\n\n\n[[features.logging.file-output]]\n== File Output\n\nBy default, Spring Boot logs only to the console and does not write log files.\nIf you want to write log files in addition to the console output, you need to set a configprop:logging.file.name[] or configprop:logging.file.path[] property (for example, in your `application.properties`).\nIf both properties are set, `logging.file.path` is ignored and only `logging.file.name` is used.\n\nThe following table shows how the `logging.*` properties can be used together:\n\n.Logging properties\n[cols=\"1,1,4\"]\n|===\n| configprop:logging.file.name[] | configprop:logging.file.path[] | Description\n\n| _(none)_\n| _(none)_\n| Console only logging.\n\n| Specific file (for example, `my.log`)\n| _(none)_\n| Writes to the location specified by `logging.file.name`.\n  The location can be absolute or relative to the current directory.\n\n| _(none)_\n| Specific directory (for example, `/var/log`)\n| Writes `spring.log` to the directory specified by `logging.file.path`.\n  The directory can be absolute or relative to the current directory.\n\n| Specific file\n| Specific directory\n| Writes to the location specified by `logging.file.name` and ignores `logging.file.path`.\n  The location can be absolute or relative to the current directory.\n|===\n\nLog files rotate when they reach 10 MB and, as with console output, `ERROR`-level, `WARN`-level, and `INFO`-level messages are logged by default.\nNote that Log4J2 requires `logging.file.path` to be set with such configuration.\n\nTIP: Logging properties are independent of the actual logging infrastructure.\nAs a result, specific configuration keys (such as `logback.configurationFile` for Logback) are not managed by spring Boot.\n\n\n\n[[features.logging.file-rotation]]\n== File Rotation\n\nIf you are using Logback of Log4J2, it is possible to fine-tune log rotation settings using your `application.properties` or `application.yaml` file.\nFor all other logging system, you will need to configure rotation settings directly yourself.\n\nThe following rotation policy properties are supported for Logback:\n\n|===\n| Name | Description\n\n| configprop:logging.logback.rollingpolicy.file-name-pattern[]\n| The filename pattern used to create log archives.\n\n| configprop:logging.logback.rollingpolicy.clean-history-on-start[]\n| If log archive cleanup should occur when the application starts.\n\n| configprop:logging.logback.rollingpolicy.max-file-size[]\n| The maximum size of log file before it is archived.\n\n| configprop:logging.logback.rollingpolicy.total-size-cap[]\n| The maximum amount of size log archives can take before being deleted.\n\n| configprop:logging.logback.rollingpolicy.max-history[]\n| The maximum number of archive log files to keep (defaults to 7).\n|===\n\nIf you are using Log4j2, the following rotation policy properties are available:\n\n|===\n| Name | Description\n\n| configprop:logging.log4j2.rollingpolicy.file-name-pattern[]\n| The filename pattern used to create log archives.\n\n| configprop:logging.log4j2.rollingpolicy.max-file-size[]\n| The maximum size of log file before it is archived (defaults to 10MB).\n\n| configprop:logging.log4j2.rollingpolicy.max-history[]\n| The maximum number of archive log files to keep (defaults to 7).\n\n| configprop:logging.log4j2.rollingpolicy.strategy[]\n| Rolling policy strategy (defaults to 'size').\n\n| configprop:logging.log4j2.rollingpolicy.cron[]\n| Cron expression used when the strategy is 'cron' (default to every day at midnight).\n\n| configprop:logging.log4j2.rollingpolicy.time-interval[]\n| Time based triggering interval when the strategy is 'time' or 'size-and-time' (default to 1).\n\n| configprop:logging.log4j2.rollingpolicy.time-modulate[]\n| Whether to align the next rollover time to occur at the top of the interval when the strategy is time based (defaults to `false`).\n\n|===\n\n\n[[features.logging.log-levels]]\n== Log Levels\n\nAll the supported logging systems can have the logger levels set in the Spring javadoc:org.springframework.core.env.Environment[] (for example, in `application.properties`) by using `+logging.level.<logger-name>=<level>+` where `level` is one of TRACE, DEBUG, INFO, WARN, ERROR, FATAL, or OFF.\nThe `root` logger can be configured by using `logging.level.root`.\n\nThe following example shows potential logging settings in `application.properties`:\n\n[configprops,yaml]\n----\nlogging:\n  level:\n    root: \"warn\"\n    org.springframework.web: \"debug\"\n    org.hibernate: \"error\"\n----\n\nIt is also possible to set logging levels using environment variables.\nFor example, `LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG` will set `org.springframework.web` to `DEBUG`.\n\nNOTE: The above approach will only work for package level logging.\nSince relaxed binding xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps-from-environment-variables[always converts environment variables to lowercase], it is not possible to configure logging for an individual class in this way.\nIf you need to configure logging for a class, you can use xref:features/external-config.adoc#features.external-config.application-json[the `SPRING_APPLICATION_JSON`] variable.\n\n\n\n[[features.logging.log-groups]]\n== Log Groups\n\nIt is often useful to be able to group related loggers together so that they can all be configured at the same time.\nFor example, you might commonly change the logging levels for _all_ Tomcat related loggers, but you can not easily remember top level packages.\n\nTo help with this, Spring Boot allows you to define logging groups in your Spring javadoc:org.springframework.core.env.Environment[].\nFor example, here is how you could define a \"`tomcat`\" group by adding it to your `application.properties`:\n\n[configprops,yaml]\n----\nlogging:\n  group:\n    tomcat: \"org.apache.catalina,org.apache.coyote,org.apache.tomcat\"\n----\n\nOnce defined, you can change the level for all the loggers in the group with a single line:\n\n[configprops,yaml]\n----\nlogging:\n  level:\n    tomcat: \"trace\"\n----\n\nSpring Boot includes the following pre-defined logging groups that can be used out-of-the-box:\n\n[cols=\"1,4\"]\n|===\n| Name | Loggers\n\n| web\n| `org.springframework.core.codec`, `org.springframework.http`, `org.springframework.web`, `org.springframework.boot.actuate.endpoint.web`, `org.springframework.boot.web.servlet.ServletContextInitializerBeans`\n\n| sql\n| `org.springframework.jdbc.core`, `org.hibernate.SQL`, javadoc:org.jooq.tools.LoggerListener[]\n|===\n\n\n\n[[features.logging.shutdown-hook]]\n== Using a Log Shutdown Hook\n\nIn order to release logging resources when your application terminates, a shutdown hook that will trigger log system cleanup when the JVM exits is provided.\nThis shutdown hook is registered automatically unless your application is deployed as a war file.\nIf your application has complex context hierarchies the shutdown hook may not meet your needs.\nIf it does not, disable the shutdown hook and investigate the options provided directly by the underlying logging system.\nFor example, Logback offers https://logback.qos.ch/manual/loggingSeparation.html[context selectors] which allow each Logger to be created in its own context.\nYou can use the configprop:logging.register-shutdown-hook[] property to disable the shutdown hook.\nSetting it to `false` will disable the registration.\nYou can set the property in your `application.properties` or `application.yaml` file:\n\n[configprops,yaml]\n----\nlogging:\n  register-shutdown-hook: false\n----\n\n\n\n[[features.logging.custom-log-configuration]]\n== Custom Log Configuration\n\nThe various logging systems can be activated by including the appropriate libraries on the classpath and can be further customized by providing a suitable configuration file in the root of the classpath or in a location specified by the following Spring javadoc:org.springframework.core.env.Environment[] property: configprop:logging.config[].\n\nYou can force Spring Boot to use a particular logging system by using the `org.springframework.boot.logging.LoggingSystem` system property.\nThe value should be the fully qualified class name of a javadoc:org.springframework.boot.logging.LoggingSystem[] implementation.\nYou can also disable Spring Boot's logging configuration entirely by using a value of `none`.\n\nNOTE: Since logging is initialized *before* the javadoc:org.springframework.context.ApplicationContext[] is created, it is not possible to control logging from javadoc:org.springframework.context.annotation.PropertySources[format=annotation] in Spring javadoc:org.springframework.context.annotation.Configuration[format=annotation] files.\nThe only way to change the logging system or disable it entirely is through System properties.\n\nDepending on your logging system, the following files are loaded:\n\n|===\n| Logging System | Customization\n\n| Logback\n| `logback-spring.xml`, `logback-spring.groovy`, `logback.xml`, or `logback.groovy`\n\n| Log4j2\n| `log4j2-spring.xml` or `log4j2.xml`\n\n| JDK (Java Util Logging)\n| `logging.properties`\n|===\n\nNOTE: When possible, we recommend that you use the `-spring` variants for your logging configuration (for example, `logback-spring.xml` rather than `logback.xml`).\nIf you use standard configuration locations, Spring cannot completely control log initialization.\n\nWARNING: There are known classloading issues with Java Util Logging that cause problems when running from an 'executable jar'.\nWe recommend that you avoid it when running from an 'executable jar' if at all possible.\n\nTo help with the customization, some other properties are transferred from the Spring javadoc:org.springframework.core.env.Environment[] to System properties.\nThis allows the properties to be consumed by logging system configuration. For example, setting `logging.file.name` in `application.properties` or `LOGGING_FILE_NAME` as an environment variable will result in the `LOG_FILE` System property being set.\nThe properties that are transferred are described in the following table:\n\n|===\n| Spring Environment | System Property | Comments\n\n| configprop:logging.exception-conversion-word[]\n| `LOG_EXCEPTION_CONVERSION_WORD`\n| The conversion word used when logging exceptions.\n\n| configprop:logging.file.name[]\n| `LOG_FILE`\n| If defined, it is used in the default log configuration.\n\n| configprop:logging.file.path[]\n| `LOG_PATH`\n| If defined, it is used in the default log configuration.\n\n| configprop:logging.pattern.console[]\n| `CONSOLE_LOG_PATTERN`\n| The log pattern to use on the console (stdout).\n\n| configprop:logging.pattern.dateformat[]\n| `LOG_DATEFORMAT_PATTERN`\n| Appender pattern for log date format.\n\n| configprop:logging.charset.console[]\n| `CONSOLE_LOG_CHARSET`\n| The charset to use for console logging.\n\n| configprop:logging.threshold.console[]\n| `CONSOLE_LOG_THRESHOLD`\n| The log level threshold to use for console logging.\n\n| configprop:logging.pattern.file[]\n| `FILE_LOG_PATTERN`\n| The log pattern to use in a file (if `LOG_FILE` is enabled).\n\n| configprop:logging.charset.file[]\n| `FILE_LOG_CHARSET`\n| The charset to use for file logging (if `LOG_FILE` is enabled).\n\n| configprop:logging.threshold.file[]\n| `FILE_LOG_THRESHOLD`\n| The log level threshold to use for file logging.\n\n| configprop:logging.pattern.level[]\n| `LOG_LEVEL_PATTERN`\n| The format to use when rendering the log level (default `%5p`).\n\n| configprop:logging.structured.format.console[]\n| `CONSOLE_LOG_STRUCTURED_FORMAT`\n| The structured logging format to use for console logging.\n\n| configprop:logging.structured.format.file[]\n| `FILE_LOG_STRUCTURED_FORMAT`\n| The structured logging format to use for file logging.\n\n| `PID`\n| `PID`\n| The current process ID (discovered if possible and when not already defined as an OS environment variable).\n|===\n\nIf you use Logback, the following properties are also transferred:\n\n|===\n| Spring Environment | System Property | Comments\n\n| configprop:logging.logback.rollingpolicy.file-name-pattern[]\n| `LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN`\n| Pattern for rolled-over log file names (default `$\\{LOG_FILE}.%d\\{yyyy-MM-dd}.%i.gz`).\n\n| configprop:logging.logback.rollingpolicy.clean-history-on-start[]\n| `LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START`\n| Whether to clean the archive log files on startup.\n\n| configprop:logging.logback.rollingpolicy.max-file-size[]\n| `LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE`\n| Maximum log file size.\n\n| configprop:logging.logback.rollingpolicy.total-size-cap[]\n| `LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP`\n| Total size of log backups to be kept.\n\n| configprop:logging.logback.rollingpolicy.max-history[]\n| `LOGBACK_ROLLINGPOLICY_MAX_HISTORY`\n| Maximum number of archive log files to keep.\n|===\n\n\nAll the supported logging systems can consult System properties when parsing their configuration files.\nSee the default configurations in `spring-boot.jar` for examples:\n\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml[Logback]\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml[Log4j 2]\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging-file.properties[Java Util logging]\n\n[TIP]\n====\nIf you want to use a placeholder in a logging property, you should use xref:features/external-config.adoc#features.external-config.files.property-placeholders[Spring Boot's syntax] and not the syntax of the underlying framework.\nNotably, if you use Logback, you should use `:` as the delimiter between a property name and its default value and not use `:-`.\n====\n\n[TIP]\n====\nYou can add MDC and other ad-hoc content to log lines by overriding only the `LOG_LEVEL_PATTERN` (or `logging.pattern.level` with Logback).\nFor example, if you use `logging.pattern.level=user:%X\\{user} %5p`, then the default log format contains an MDC entry for \"user\", if it exists, as shown in the following example.\n\n[source]\n----\n2019-08-30 12:30:04.031 user:someone INFO 22174 --- [  nio-8080-exec-0] demo.Controller\nHandling authenticated request\n----\n====\n\n\n\n[[features.logging.structured]]\n== Structured Logging\n\nStructured logging is a technique where the log output is written in a well-defined, often machine-readable format.\nSpring Boot supports structured logging and has support for the following JSON formats out of the box:\n\n* xref:#features.logging.structured.ecs[Elastic Common Schema (ECS)]\n* xref:#features.logging.structured.gelf[Graylog Extended Log Format (GELF)]\n* xref:#features.logging.structured.logstash[Logstash]\n\nTo enable structured logging, set the property configprop:logging.structured.format.console[] (for console output) or configprop:logging.structured.format.file[] (for file output) to the id of the format you want to use.\n\nIf you are using xref:#features.logging.custom-log-configuration[Custom Log Configuration], update your configuration to respect `CONSOLE_LOG_STRUCTURED_FORMAT` and `FILE_LOG_STRUCTURED_FORMAT` system properties.\nTake `CONSOLE_LOG_STRUCTURED_FORMAT` for example:\n[tabs]\n======\nLogback::\n+\n[source,xml]\n----\n<!-- replace your encoder with StructuredLogEncoder -->\n<encoder class=\"org.springframework.boot.logging.logback.StructuredLogEncoder\">\n\t<format>${CONSOLE_LOG_STRUCTURED_FORMAT}</format>\n\t<charset>${CONSOLE_LOG_CHARSET}</charset>\n</encoder>\n----\n+\nYou can also refer to the default configurations included in Spring Boot:\n+\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-console-appender.xml[Logback Structured Console Appender]\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/logback/structured-file-appender.xml[Logback Structured File Appender]\nLog4j2::\n+\n[source,xml]\n----\n<!-- replace your PatternLayout with StructuredLogLayout -->\n<StructuredLogLayout format=\"${sys:CONSOLE_LOG_STRUCTURED_FORMAT}\" charset=\"${sys:CONSOLE_LOG_CHARSET}\"/>\n----\n+\nYou can also refer to the default configurations included in Spring Boot:\n+\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml[Log4j2 Console Appender]\n* {code-spring-boot}/core/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2-file.xml[Log4j2 Console and File Appender]\n======\n\n\n[[features.logging.structured.ecs]]\n=== Elastic Common Schema\n\nhttps://www.elastic.co/guide/en/ecs/8.11/ecs-reference.html[Elastic Common Schema] is a JSON based logging format.\n\nTo enable the Elastic Common Schema log format, set the appropriate `format` property to `ecs`:\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    format:\n      console: ecs\n      file: ecs\n----\n\nA log line looks like this:\n\n[source,json]\n----\n{\"@timestamp\":\"2024-01-01T10:15:00.067462556Z\",\"log\":{\"level\":\"INFO\",\"logger\":\"org.example.Application\"},\"process\":{\"pid\":39599,\"thread\":{\"name\":\"main\"}},\"service\":{\"name\":\"simple\"},\"message\":\"No active profile set, falling back to 1 default profile: \\\"default\\\"\",\"ecs\":{\"version\":\"8.11\"}}\n----\n\nThis format also adds every key value pair contained in the MDC to the JSON object.\nYou can also use the https://www.slf4j.org/manual.html#fluent[SLF4J fluent logging API] to add key value pairs to the logged JSON object with the https://www.slf4j.org/apidocs/org/slf4j/spi/LoggingEventBuilder.html#addKeyValue(java.lang.String,java.lang.Object)[addKeyValue] method.\n\nThe `service` values can be customized using `logging.structured.ecs.service` properties:\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    ecs:\n      service:\n        name: MyService\n        version: 1.0\n        environment: Production\n        node-name: Primary\n----\n\nNOTE: configprop:logging.structured.ecs.service.name[] will default to configprop:spring.application.name[] if not specified.\n\nNOTE: configprop:logging.structured.ecs.service.version[] will default to configprop:spring.application.version[] if not specified.\n\n\n\n[[features.logging.structured.gelf]]\n=== Graylog Extended Log Format (GELF)\n\nhttps://go2docs.graylog.org/current/getting_in_log_data/gelf.html[Graylog Extended Log Format] is a JSON based logging format for the Graylog log analytics platform.\n\nTo enable the Graylog Extended Log Format, set the appropriate `format` property to `gelf`:\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    format:\n      console: gelf\n      file: gelf\n----\n\nA log line looks like this:\n\n[source,json]\n----\n{\"version\":\"1.1\",\"short_message\":\"No active profile set, falling back to 1 default profile: \\\"default\\\"\",\"timestamp\":1725958035.857,\"level\":6,\"_level_name\":\"INFO\",\"_process_pid\":47649,\"_process_thread_name\":\"main\",\"_log_logger\":\"org.example.Application\"}\n----\n\nThis format also adds every key value pair contained in the MDC to the JSON object.\nYou can also use the https://www.slf4j.org/manual.html#fluent[SLF4J fluent logging API] to add key value pairs to the logged JSON object with the https://www.slf4j.org/apidocs/org/slf4j/spi/LoggingEventBuilder.html#addKeyValue(java.lang.String,java.lang.Object)[addKeyValue] method.\n\nSeveral fields can be customized using `logging.structured.gelf` properties:\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    gelf:\n      host: MyService\n      service:\n        version: 1.0\n----\n\nNOTE: configprop:logging.structured.gelf.host[] will default to configprop:spring.application.name[] if not specified.\n\nNOTE: configprop:logging.structured.gelf.service.version[] will default to configprop:spring.application.version[] if not specified.\n\n\n\n[[features.logging.structured.logstash]]\n=== Logstash JSON format\n\nThe https://github.com/logfellow/logstash-logback-encoder?tab=readme-ov-file#standard-fields[Logstash JSON format] is a JSON based logging format.\n\nTo enable the Logstash JSON log format, set the appropriate `format` property to `logstash`:\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    format:\n      console: logstash\n      file: logstash\n----\n\nA log line looks like this:\n\n[source,json]\n----\n{\"@timestamp\":\"2024-01-01T10:15:00.111037681+02:00\",\"@version\":\"1\",\"message\":\"No active profile set, falling back to 1 default profile: \\\"default\\\"\",\"logger_name\":\"org.example.Application\",\"thread_name\":\"main\",\"level\":\"INFO\",\"level_value\":20000}\n----\n\nThis format also adds every key value pair contained in the MDC to the JSON object.\nYou can also use the https://www.slf4j.org/manual.html#fluent[SLF4J fluent logging API] to add key value pairs to the logged JSON object with the https://www.slf4j.org/apidocs/org/slf4j/spi/LoggingEventBuilder.html#addKeyValue(java.lang.String,java.lang.Object)[addKeyValue] method.\n\nIf you add https://www.slf4j.org/api/org/slf4j/Marker.html[markers], these will show up in a `tags` string array in the JSON.\n\n\n\n[[features.logging.structured.customizing-json]]\n=== Customizing Structured Logging JSON\n\nSpring Boot attempts to pick sensible defaults for the JSON names and values output for structured logging.\nSometimes, however, you may want to make small adjustments to the JSON for your own needs.\nFor example, it's possible that you might want to change some of the names to match the expectations of your log ingestion system.\nYou might also want to filter out certain members since you don't find them useful.\n\nThe following properties allow you to change the way that structured logging JSON is written:\n\n|===\n| Property | Description\n\n| configprop:logging.structured.json.include[] & configprop:logging.structured.json.exclude[]\n| Filters specific paths from the JSON\n\n| configprop:logging.structured.json.rename[]\n| Renames a specific member in the JSON\n\n| configprop:logging.structured.json.add[]\n| Adds additional members to the JSON\n|===\n\nFor example, the following will exclude `log.level`, rename `process.id` to `procid` and add a fixed `corpname` field:\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    json:\n      exclude: log.level\n      rename:\n        process.id: procid\n      add:\n        corpname: mycorp\n----\n\nTIP: For more advanced customizations, you can use the javadoc:org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer[] interface.\nYou can reference one or more implementations using the configprop:logging.structured.json.customizer[] property.\nYou can also declare implementations by listing them in a `META-INF/spring.factories` file.\n\n\n\n[[features.logging.structured.customizing-stack-traces]]\n=== Customizing Structured Logging Stack Traces\n\nComplete stack traces are included in the JSON output whenever a message is logged with an exception.\nThis amount of information may be costly to process by your log ingestion system, so you may want to tune the way that stack traces are printed.\n\nTo do this, you can use one or more of the following properties:\n\n|===\n| Property | Description\n\n| configprop:logging.structured.json.stacktrace.root[]\n| Use `last` to print the root item last (same as Java) or `first` to print the root item first.\n\n| configprop:logging.structured.json.stacktrace.max-length[]\n| The maximum length that should be printed\n\n| configprop:logging.structured.json.stacktrace.max-throwable-depth[]\n| The maximum number of frames to print per stack trace (including common and suppressed frames)\n\n| configprop:logging.structured.json.stacktrace.include-common-frames[]\n| If common frames should be included or removed\n\n| configprop:logging.structured.json.stacktrace.include-hashes[]\n| If a hash of the stack trace should be included\n|===\n\nFor example, the following will use root first stack traces, limit their length, and include hashes.\n\n[configprops,yaml]\n----\nlogging:\n  structured:\n    json:\n      stacktrace:\n        root: first\n        max-length: 1024\n        include-common-frames: true\n        include-hashes: true\n----\n\n[TIP]\n====\nIf you need complete control over stack trace printing you can set configprop:logging.structured.json.stacktrace.printer[] to the name of a javadoc:org.springframework.boot.logging.StackTracePrinter[] implementation.\nYou can also set it to `logging-system` to force regular logging system stack trace output to be used.\n\nYour `StackTracePrinter` implementation can also include a constructor argument that accepts a javadoc:org.springframework.boot.logging.StandardStackTracePrinter[] if it wishes to apply further customization to the stack trace printer created from the properties.\n====\n\n\n\n[[features.logging.structured.other-formats]]\n=== Supporting Other Structured Logging Formats\n\nThe structured logging support in Spring Boot is extensible, allowing you to define your own custom format.\nTo do this, implement the javadoc:org.springframework.boot.logging.structured.StructuredLogFormatter[] interface. The generic type argument has to be javadoc:ch.qos.logback.classic.spi.ILoggingEvent[] when using Logback and javadoc:org.apache.logging.log4j.core.LogEvent[] when using Log4j2 (that means your implementation is tied to a specific logging system).\nYour implementation is then called with the log event and returns the javadoc:java.lang.String[] to be logged, as seen in this example:\n\ninclude-code::MyCustomFormat[]\n\nAs you can see in the example, you can return any format, it doesn't have to be JSON.\n\nTo enable your custom format, set the property configprop:logging.structured.format.console[] or configprop:logging.structured.format.file[] to the fully qualified class name of your implementation.\n\nYour implementation can use some constructor parameters, which are injected automatically.\nPlease see the JavaDoc of javadoc:org.springframework.boot.logging.structured.StructuredLogFormatter[] for more details.\n\n\n\n[[features.logging.logback-extensions]]\n== Logback Extensions\n\nSpring Boot includes a number of extensions to Logback that can help with advanced configuration.\nYou can use these extensions in your `logback-spring.xml` configuration file.\n\nNOTE: Because the standard `logback.xml` configuration file is loaded too early, you cannot use extensions in it.\nYou need to either use `logback-spring.xml` or define a configprop:logging.config[] property.\n\nWARNING: The extensions cannot be used with Logback's https://logback.qos.ch/manual/configuration.html#autoScan[configuration scanning].\nIf you attempt to do so, making changes to the configuration file results in an error similar to one of the following being logged:\n\n[source]\n----\nERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]\nERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]\n----\n\n\n\n[[features.logging.logback-extensions.profile-specific]]\n=== Profile-specific Configuration\n\nThe `<springProfile>` tag lets you optionally include or exclude sections of configuration based on the active Spring profiles.\nProfile sections are supported anywhere within the `<configuration>` element.\nUse the `name` attribute to specify which profile accepts the configuration.\nThe `<springProfile>` tag can contain a profile name (for example `staging`) or a profile expression.\nA profile expression allows for more complicated profile logic to be expressed, for example `production & (eu-central | eu-west)`.\nCheck the {url-spring-framework-docs}/core/beans/environment.html#beans-definition-profiles-java[Spring Framework reference guide] for more details.\nThe following listing shows three sample profiles:\n\n[source,xml]\n----\n<springProfile name=\"staging\">\n\t<!-- configuration to be enabled when the \"staging\" profile is active -->\n</springProfile>\n\n<springProfile name=\"dev | staging\">\n\t<!-- configuration to be enabled when the \"dev\" or \"staging\" profiles are active -->\n</springProfile>\n\n<springProfile name=\"!production\">\n\t<!-- configuration to be enabled when the \"production\" profile is not active -->\n</springProfile>\n----\n\n\n\n[[features.logging.logback-extensions.environment-properties]]\n=== Environment Properties\n\nThe `<springProperty>` tag lets you expose properties from the Spring javadoc:org.springframework.core.env.Environment[] for use within Logback.\nDoing so can be useful if you want to access values from your `application.properties` file in your Logback configuration.\nThe tag works in a similar way to Logback's standard `<property>` tag.\nHowever, rather than specifying a direct `value`, you specify the `source` of the property (from the javadoc:org.springframework.core.env.Environment[]).\nIf you need to store the property somewhere other than in `local` scope, you can use the `scope` attribute.\nIf you need a fallback value (in case the property is not set in the javadoc:org.springframework.core.env.Environment[]), you can use the `defaultValue` attribute.\nThe following example shows how to expose properties for use within Logback:\n\n[source,xml]\n----\n<springProperty scope=\"context\" name=\"fluentHost\" source=\"myapp.fluentd.host\"\n\t\tdefaultValue=\"localhost\"/>\n<appender name=\"FLUENT\" class=\"ch.qos.logback.more.appenders.DataFluentAppender\">\n\t<remoteHost>${fluentHost}</remoteHost>\n\t...\n</appender>\n----\n\nNOTE: The `source` must be specified in kebab case (such as `my.property-name`).\nHowever, properties can be added to the javadoc:org.springframework.core.env.Environment[] by using the relaxed rules.\n\n\n\n[[features.logging.log4j2-extensions]]\n== Log4j2 Extensions\n\nSpring Boot includes a number of extensions to Log4j2 that can help with advanced configuration.\nYou can use these extensions in any `log4j2-spring.xml` configuration file.\n\nNOTE: Because the standard `log4j2.xml` configuration file is loaded too early, you cannot use extensions in it.\nYou need to either use `log4j2-spring.xml` or define a configprop:logging.config[] property.\n\nNOTE: The extensions supersede the https://logging.apache.org/log4j/2.x/log4j-spring-boot.html[Spring Boot support] provided by Log4J.\nYou should make sure not to include the `org.apache.logging.log4j:log4j-spring-boot` module in your build.\n\n\n\n[[features.logging.log4j2-extensions.profile-specific]]\n=== Profile-specific Configuration\n\nThe `<SpringProfile>` tag lets you optionally include or exclude sections of configuration based on the active Spring profiles.\nProfile sections are supported anywhere within the `<Configuration>` element.\nUse the `name` attribute to specify which profile accepts the configuration.\nThe `<SpringProfile>` tag can contain a profile name (for example `staging`) or a profile expression.\nA profile expression allows for more complicated profile logic to be expressed, for example `production & (eu-central | eu-west)`.\nCheck the {url-spring-framework-docs}/core/beans/environment.html#beans-definition-profiles-java[Spring Framework reference guide] for more details.\nThe following listing shows three sample profiles:\n\n[source,xml]\n----\n<SpringProfile name=\"staging\">\n\t<!-- configuration to be enabled when the \"staging\" profile is active -->\n</SpringProfile>\n\n<SpringProfile name=\"dev | staging\">\n\t<!-- configuration to be enabled when the \"dev\" or \"staging\" profiles are active -->\n</SpringProfile>\n\n<SpringProfile name=\"!production\">\n\t<!-- configuration to be enabled when the \"production\" profile is not active -->\n</SpringProfile>\n----\n\n\n\n[[features.logging.log4j2-extensions.environment-properties-lookup]]\n=== Environment Properties Lookup\n\nIf you want to refer to properties from your Spring javadoc:org.springframework.core.env.Environment[] within your Log4j2 configuration you can use `spring:` prefixed https://logging.apache.org/log4j/2.x/manual/lookups.html[lookups].\nDoing so can be useful if you want to access values from your `application.properties` file in your Log4j2 configuration.\n\nThe following example shows how to set Log4j2 properties named `applicationName` and `applicationGroup` that read `spring.application.name` and `spring.application.group` from the Spring javadoc:org.springframework.core.env.Environment[]:\n\n[source,xml]\n----\n<Properties>\n\t<Property name=\"applicationName\">${spring:spring.application.name}</Property>\n\t<Property name=\"applicationGroup\">${spring:spring.application.group}</Property>\n</Properties>\n----\n\nNOTE: The lookup key should be specified in kebab case (such as `my.property-name`).\n\n\n\n[[features.logging.log4j2-extensions.environment-property-source]]\n=== Log4j2 System Properties\n\nLog4j2 supports a number of https://logging.apache.org/log4j/2.x/manual/systemproperties.html[System Properties] that can be used to configure various items.\nFor example, the `log4j2.skipJansi` system property can be used to configure if the javadoc:org.apache.logging.log4j.core.appender.ConsoleAppender[] will try to use a https://github.com/fusesource/jansi[Jansi] output stream on Windows.\n\nAll system properties that are loaded after the Log4j2 initialization can be obtained from the Spring javadoc:org.springframework.core.env.Environment[].\nFor example, you could add `log4j2.skipJansi=false` to your `application.properties` file to have the javadoc:org.apache.logging.log4j.core.appender.ConsoleAppender[] use Jansi on Windows.\n\nNOTE: The Spring javadoc:org.springframework.core.env.Environment[] is only considered when system properties and OS environment variables do not contain the value being loaded.\n\nWARNING: System properties that are loaded during early Log4j2 initialization cannot reference the Spring javadoc:org.springframework.core.env.Environment[].\nFor example, the property Log4j2 uses to allow the default Log4j2 implementation to be chosen is used before the Spring Environment is available.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/profiles.adoc",
    "content": "[[features.profiles]]\n= Profiles\n\nSpring Profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments.\nAny javadoc:org.springframework.stereotype.Component[format=annotation], javadoc:org.springframework.context.annotation.Configuration[format=annotation] or javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] can be marked with javadoc:org.springframework.context.annotation.Profile[format=annotation] to limit when it is loaded, as shown in the following example:\n\ninclude-code::ProductionConfiguration[]\n\nNOTE: If javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are registered through javadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] instead of automatic scanning, the javadoc:org.springframework.context.annotation.Profile[format=annotation] annotation needs to be specified on the javadoc:org.springframework.context.annotation.Configuration[format=annotation] class that has the javadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] annotation.\nIn the case where javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] are scanned, javadoc:org.springframework.context.annotation.Profile[format=annotation] can be specified on the javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] class itself.\n\nYou can use a configprop:spring.profiles.active[] javadoc:org.springframework.core.env.Environment[] property to specify which profiles are active.\nYou can specify the property in any of the ways described earlier in this chapter.\nFor example, you could include it in your `application.properties`, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    active: \"dev,hsqldb\"\n----\n\nYou could also specify it on the command line by using the following switch: `--spring.profiles.active=dev,hsqldb`.\n\nIf no profile is active, a default profile is enabled.\nThe name of the default profile is `default` and it can be tuned using the configprop:spring.profiles.default[] javadoc:org.springframework.core.env.Environment[] property, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    default: \"none\"\n----\n\n`spring.profiles.active` and `spring.profiles.default` can only be used in non-profile-specific documents.\nThis means they cannot be included in xref:features/external-config.adoc#features.external-config.files.profile-specific[profile specific files] or xref:features/external-config.adoc#features.external-config.files.activation-properties[documents activated] by `spring.config.activate.on-profile`.\n\nFor example, the second document configuration is invalid:\n\n[configprops,yaml]\n----\n# this document is valid\nspring:\n  profiles:\n    active: \"prod\"\n---\n# this document is invalid\nspring:\n  config:\n    activate:\n      on-profile: \"prod\"\n  profiles:\n    active: \"metrics\"\n----\n\nThe configprop:spring.profiles.active[] property follows the same ordering rules as other properties.\nThe highest javadoc:org.springframework.core.env.PropertySource[] wins.\nThis means that you can specify active profiles in `application.properties` and then *replace* them by using the command line switch.\n\nTIP: See xref:features/external-config.adoc#features.external-config.order[the \"`Externalized Configuration`\"] for more details on the order in which property sources are considered.\n\n[NOTE]\n====\nBy default, profile names in Spring Boot may contain letters, numbers, or permitted characters (`-`, `_`, `.`, `+`, `@`).\nIn addition, they can only start and end with a letter or number.\n\nThis restriction helps to prevent common parsing issues.\nif, however, you prefer more flexible profile names you can set configprop:spring.profiles.validate[] to `false` in your `application.properties` or `application.yaml` file:\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    validate: false\n----\n====\n\n\n\n[[features.profiles.adding-active-profiles]]\n== Adding Active Profiles\n\nSometimes, it is useful to have properties that *add* to the active profiles rather than replace them.\nThe configprop:spring.profiles.include[] property can be used to add active profiles on top of those activated by the configprop:spring.profiles.active[] property.\nThe javadoc:org.springframework.boot.SpringApplication[] entry point also has a Java API for setting additional profiles.\nSee the `setAdditionalProfiles()` method in javadoc:org.springframework.boot.SpringApplication[].\n\nFor example, when an application with the following properties is run, the common and local profiles will be activated even when it runs using the `--spring.profiles.active` switch:\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    include:\n      - \"common\"\n      - \"local\"\n----\n\nNOTE: Included profiles are added before any configprop:spring.profiles.active[] profiles.\n\nTIP: The configprop:spring.profiles.include[] property is processed for each property source, as such the usual xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.merging-complex-types[complex type merging rules] for lists do not apply.\n\nWARNING: Similar to `spring.profiles.active`, `spring.profiles.include` can only be used in non-profile-specific documents.\nThis means it cannot be included in xref:features/external-config.adoc#features.external-config.files.profile-specific[profile specific files] or xref:features/external-config.adoc#features.external-config.files.activation-properties[documents activated] by `spring.config.activate.on-profile`.\n\nProfile groups, which are described in the xref:features/profiles.adoc#features.profiles.groups[next section] can also be used to add active profiles if a given profile is active.\n\n\n\n[[features.profiles.groups]]\n== Profile Groups\n\nOccasionally the profiles that you define and use in your application are too fine-grained and become cumbersome to use.\nFor example, you might have `proddb` and `prodmq` profiles that you use to enable database and messaging features independently.\n\nTo help with this, Spring Boot lets you define profile groups.\nA profile group allows you to define a logical name for a related group of profiles.\n\nFor example, we can create a `production` group that consists of our `proddb` and `prodmq` profiles.\n\n[configprops,yaml]\n----\nspring:\n  profiles:\n    group:\n      production:\n      - \"proddb\"\n      - \"prodmq\"\n----\n\nOur application can now be started using `--spring.profiles.active=production` to activate the `production`, `proddb` and `prodmq` profiles in one hit.\n\nWARNING: Similar to `spring.profiles.active` and `spring.profiles.include`, `spring.profiles.group` can only be used in non-profile-specific documents.\nThis means it cannot be included in xref:features/external-config.adoc#features.external-config.files.profile-specific[profile specific files] or xref:features/external-config.adoc#features.external-config.files.activation-properties[documents activated] by `spring.config.activate.on-profile`.\n\n\n[[features.profiles.programmatically-setting-profiles]]\n== Programmatically Setting Profiles\n\nYou can programmatically set active profiles by calling `SpringApplication.setAdditionalProfiles(...)` before your application runs.\nIt is also possible to activate profiles by using Spring's javadoc:org.springframework.core.env.ConfigurableEnvironment[] interface.\n\n\n\n[[features.profiles.profile-specific-configuration-files]]\n== Profile-specific Configuration Files\n\nProfile-specific variants of both `application.properties` (or `application.yaml`) and files referenced through javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] are considered as files and loaded.\nSee xref:features/external-config.adoc#features.external-config.files.profile-specific[] for details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/spring-application.adoc",
    "content": "[[features.spring-application]]\n= SpringApplication\n\nThe javadoc:org.springframework.boot.SpringApplication[] class provides a convenient way to bootstrap a Spring application that is started from a `main()` method.\nIn many situations, you can delegate to the static javadoc:org.springframework.boot.SpringApplication#run(java.lang.Class,java.lang.String...)[] method, as shown in the following example:\n\ninclude-code::MyApplication[]\n\nWhen your application starts, you should see something similar to the following output:\n\n[source,subs=\"verbatim,attributes\"]\n----\ninclude::ROOT:partial$application/spring-application.txt[]\n----\n\n\n\nBy default, `INFO` logging messages are shown, including some relevant startup details, such as the user that launched the application.\nIf you need a log level other than `INFO`, you can set it, as described in xref:features/logging.adoc#features.logging.log-levels[].\nThe application version is determined using the implementation version from the main application class's package.\nStartup information logging can be turned off by setting `spring.main.log-startup-info` to `false`.\nThis will also turn off logging of the application's active profiles.\n\nTIP: To add additional logging during startup, you can override `logStartupInfo(boolean)` in a subclass of javadoc:org.springframework.boot.SpringApplication[].\n\n\n\n[[features.spring-application.startup-failure]]\n== Startup Failure\n\nIf your application fails to start, registered javadoc:org.springframework.boot.diagnostics.FailureAnalyzer[] beans get a chance to provide a dedicated error message and a concrete action to fix the problem.\nFor instance, if you start a web application on port `8080` and that port is already in use, you should see something similar to the following message:\n\n[source]\n----\n***************************\nAPPLICATION FAILED TO START\n***************************\n\nDescription:\n\nEmbedded servlet container failed to start. Port 8080 was already in use.\n\nAction:\n\nIdentify and stop the process that is listening on port 8080 or configure this application to listen on another port.\n----\n\nNOTE: Spring Boot provides numerous javadoc:org.springframework.boot.diagnostics.FailureAnalyzer[] implementations, and you can xref:how-to:application.adoc#howto.application.failure-analyzer[add your own].\n\nIf no failure analyzers are able to handle the exception, you can still display the full conditions report to better understand what went wrong.\nTo do so, you need to xref:features/external-config.adoc[enable the `debug` property] or xref:features/logging.adoc#features.logging.log-levels[enable `DEBUG` logging] for javadoc:org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener[].\n\nFor instance, if you are running your application by using `java -jar`, you can enable the `debug` property as follows:\n\n[source,shell]\n----\n$ java -jar myproject-0.0.1-SNAPSHOT.jar --debug\n----\n\n\n\n[[features.spring-application.lazy-initialization]]\n== Lazy Initialization\n\njavadoc:org.springframework.boot.SpringApplication[] allows an application to be initialized lazily.\nWhen lazy initialization is enabled, beans are created as they are needed rather than during application startup.\nAs a result, enabling lazy initialization can reduce the time that it takes your application to start.\nIn a web application, enabling lazy initialization will result in many web-related beans not being initialized until an HTTP request is received.\n\nA downside of lazy initialization is that it can delay the discovery of a problem with the application.\nIf a misconfigured bean is initialized lazily, a failure will no longer occur during startup and the problem will only become apparent when the bean is initialized.\nCare must also be taken to ensure that the JVM has sufficient memory to accommodate all of the application's beans and not just those that are initialized during startup.\nFor these reasons, lazy initialization is not enabled by default and it is recommended that fine-tuning of the JVM's heap size is done before enabling lazy initialization.\n\nLazy initialization can be enabled programmatically using the `lazyInitialization` method on javadoc:org.springframework.boot.builder.SpringApplicationBuilder[] or the `setLazyInitialization` method on javadoc:org.springframework.boot.SpringApplication[].\nAlternatively, it can be enabled using the configprop:spring.main.lazy-initialization[] property as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  main:\n    lazy-initialization: true\n----\n\nTIP: If you want to disable lazy initialization for certain beans while using lazy initialization for the rest of the application, you can explicitly set their lazy attribute to false using the `@Lazy(false)` annotation.\n\n\n\n[[features.spring-application.banner]]\n== Customizing the Banner\n\nThe banner that is printed on start up can be changed by adding a `banner.txt` file to your classpath or by setting the configprop:spring.banner.location[] property to the location of such a file.\nIf the file has an encoding other than UTF-8, you can set `spring.banner.charset`.\n\nInside your `banner.txt` file, you can use any key available in the javadoc:org.springframework.core.env.Environment[] as well as any of the following placeholders:\n\n.Banner variables\n|===\n| Variable | Description\n\n| `${application.version}`\n| The version number of your application, as declared in `MANIFEST.MF`.\n  For example, `Implementation-Version: 1.0` is printed as `1.0`.\n\n| `${application.formatted-version}`\n| The version number of your application, as declared in `MANIFEST.MF` and formatted for display (surrounded with brackets and prefixed with `v`).\n  For example `(v1.0)`.\n\n| `${spring-boot.version}`\n| The Spring Boot version that you are using.\n  For example `{version-spring-boot}`.\n\n| `${spring-boot.formatted-version}`\n| The Spring Boot version that you are using, formatted for display (surrounded with brackets and prefixed with `v`).\n  For example `(v{version-spring-boot})`.\n\n| `${Ansi.NAME}` (or `${AnsiColor.NAME}`, `${AnsiBackground.NAME}`, `${AnsiStyle.NAME}`)\n| Where `NAME` is the name of an ANSI escape code.\n  See javadoc:org.springframework.boot.ansi.AnsiPropertySource[] for details.\n\n| `${application.title}`\n| The title of your application, as declared in `MANIFEST.MF`.\n  For example `Implementation-Title: MyApp` is printed as `MyApp`.\n|===\n\nTIP: The `SpringApplication.setBanner(...)` method can be used if you want to generate a banner programmatically.\nUse the javadoc:org.springframework.boot.Banner[] interface and implement your own `printBanner()` method.\n\nYou can also use the configprop:spring.main.banner-mode[] property to determine if the banner has to be printed on javadoc:java.lang.System#out[] (`console`), sent to the configured logger (`log`), or not produced at all (`off`).\n\nThe printed banner is registered as a singleton bean under the following name: `springBootBanner`.\n\n[NOTE]\n====\nThe `application.title`, `application.version`, and `application.formatted-version` properties are only available if you are using `java -jar` or `java -cp` with Spring Boot launchers.\nThe values will not be resolved if you are running an unpacked jar and starting it with `java -cp <classpath> <mainclass>`\nor running your application as a native image.\n\nTo use the `application.\\*` properties, launch your application as a packed jar using `java -jar` or as an unpacked jar using `java org.springframework.boot.loader.launch.JarLauncher`.\nThis will initialize the `application.*` banner properties before building the classpath and launching your app.\n====\n\n\n\n[[features.spring-application.customizing-spring-application]]\n== Customizing SpringApplication\n\nIf the javadoc:org.springframework.boot.SpringApplication[] defaults are not to your taste, you can instead create a local instance and customize it.\nFor example, to turn off the banner, you could write:\n\ninclude-code::MyApplication[]\n\nNOTE: The constructor arguments passed to javadoc:org.springframework.boot.SpringApplication[] are configuration sources for Spring beans.\nIn most cases, these are references to javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes, but they could also be direct references javadoc:org.springframework.stereotype.Component[format=annotation] classes.\n\nIt is also possible to configure the javadoc:org.springframework.boot.SpringApplication[] by using an `application.properties` file.\nSee xref:features/external-config.adoc[] for details.\n\nFor a complete list of the configuration options, see the javadoc:org.springframework.boot.SpringApplication[] API documentation.\n\n\n\n[[features.spring-application.fluent-builder-api]]\n== Fluent Builder API\n\nIf you need to build an javadoc:org.springframework.context.ApplicationContext[] hierarchy (multiple contexts with a parent/child relationship) or if you prefer using a fluent builder API, you can use the javadoc:org.springframework.boot.builder.SpringApplicationBuilder[].\n\nThe javadoc:org.springframework.boot.builder.SpringApplicationBuilder[] lets you chain together multiple method calls and includes `parent` and `child` methods that let you create a hierarchy, as shown in the following example:\n\ninclude-code::MyApplication[tag=*]\n\nNOTE: There are some restrictions when creating an javadoc:org.springframework.context.ApplicationContext[] hierarchy.\nFor example, Web components *must* be contained within the child context, and the same javadoc:org.springframework.core.env.Environment[] is used for both parent and child contexts.\nSee the javadoc:org.springframework.boot.builder.SpringApplicationBuilder[] API documentation for full details.\n\n\n\n[[features.spring-application.application-availability]]\n== Application Availability\n\nWhen deployed on platforms, applications can provide information about their availability to the platform using infrastructure such as https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/[Kubernetes Probes].\nSpring Boot includes out-of-the box support for the commonly used \"`liveness`\" and \"`readiness`\" availability states.\nIf you are using Spring Boot's \"`actuator`\" support then these states are exposed as health endpoint groups.\n\nIn addition, you can also obtain availability states by injecting the javadoc:org.springframework.boot.availability.ApplicationAvailability[] interface into your own beans.\n\n\n\n[[features.spring-application.application-availability.liveness]]\n=== Liveness State\n\nThe \"`Liveness`\" state of an application tells whether its internal state allows it to work correctly, or recover by itself if it is currently failing.\nA broken \"`Liveness`\" state means that the application is in a state that it cannot recover from, and the infrastructure should restart the application.\n\nNOTE: In general, the \"Liveness\" state should not be based on external checks, such as xref:actuator/endpoints.adoc#actuator.endpoints.health[health checks].\nIf it did, a failing external system (a database, a Web API, an external cache) would trigger massive restarts and cascading failures across the platform.\n\nThe internal state of Spring Boot applications is mostly represented by the Spring javadoc:org.springframework.context.ApplicationContext[].\nIf the application context has started successfully, Spring Boot assumes that the application is in a valid state.\nAn application is considered live as soon as the context has been refreshed, see xref:features/spring-application.adoc#features.spring-application.application-events-and-listeners[Spring Boot application lifecycle and related Application Events].\n\n\n\n[[features.spring-application.application-availability.readiness]]\n=== Readiness State\n\nThe \"`Readiness`\" state of an application tells whether the application is ready to handle traffic.\nA failing \"`Readiness`\" state tells the platform that it should not route traffic to the application for now.\nThis typically happens during startup, while javadoc:org.springframework.boot.CommandLineRunner[] and javadoc:org.springframework.boot.ApplicationRunner[] components are being processed, or at any time if the application decides that it is too busy for additional traffic.\n\nAn application is considered ready as soon as application and command-line runners have been called, see xref:features/spring-application.adoc#features.spring-application.application-events-and-listeners[Spring Boot application lifecycle and related Application Events].\n\nTIP: Tasks expected to run during startup should be executed by javadoc:org.springframework.boot.CommandLineRunner[] and javadoc:org.springframework.boot.ApplicationRunner[] components instead of using Spring component lifecycle callbacks such as javadoc:jakarta.annotation.PostConstruct[format=annotation].\n\n\n\n[[features.spring-application.application-availability.managing]]\n=== Managing the Application Availability State\n\nApplication components can retrieve the current availability state at any time, by injecting the javadoc:org.springframework.boot.availability.ApplicationAvailability[] interface and calling methods on it.\nMore often, applications will want to listen to state updates or update the state of the application.\n\nFor example, we can export the \"Readiness\" state of the application to a file so that a Kubernetes \"exec Probe\" can look at this file:\n\ninclude-code::MyReadinessStateExporter[]\n\nWe can also update the state of the application, when the application breaks and cannot recover:\n\ninclude-code::MyLocalCacheVerifier[]\n\nSpring Boot provides xref:actuator/endpoints.adoc#actuator.endpoints.kubernetes-probes[Kubernetes HTTP probes for \"Liveness\" and \"Readiness\" with Actuator Health Endpoints].\nYou can get more guidance about xref:how-to:deployment/cloud.adoc#howto.deployment.cloud.kubernetes[deploying Spring Boot applications on Kubernetes in the dedicated section].\n\n\n\n[[features.spring-application.application-events-and-listeners]]\n== Application Events and Listeners\n\nIn addition to the usual Spring Framework events, such as javadoc:org.springframework.context.event.ContextRefreshedEvent[], a javadoc:org.springframework.boot.SpringApplication[] sends some additional application events.\n\n[NOTE]\n====\nSome events are actually triggered before the javadoc:org.springframework.context.ApplicationContext[] is created, so you cannot register a listener on those as a javadoc:org.springframework.context.annotation.Bean[format=annotation].\nYou can register them with the `SpringApplication.addListeners(...)` method or the `SpringApplicationBuilder.listeners(...)` method.\n\nIf you want those listeners to be registered automatically, regardless of the way the application is created, you can add a `META-INF/spring.factories` file to your project and reference your listener(s) by using the javadoc:org.springframework.context.ApplicationListener[] key, as shown in the following example:\n\n[source]\n----\norg.springframework.context.ApplicationListener=com.example.project.MyListener\n----\n\n====\n\nApplication events are sent in the following order, as your application runs:\n\n. An javadoc:org.springframework.boot.context.event.ApplicationStartingEvent[] is sent at the start of a run but before any processing, except for the registration of listeners and initializers.\n. An javadoc:org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent[] is sent when the javadoc:org.springframework.core.env.Environment[] to be used in the context is known but before the context is created.\n. An javadoc:org.springframework.boot.context.event.ApplicationContextInitializedEvent[] is sent when the javadoc:org.springframework.context.ApplicationContext[] is prepared and ApplicationContextInitializers have been called but before any bean definitions are loaded.\n. An javadoc:org.springframework.boot.context.event.ApplicationPreparedEvent[] is sent just before the refresh is started but after bean definitions have been loaded.\n. An javadoc:org.springframework.boot.context.event.ApplicationStartedEvent[] is sent after the context has been refreshed but before any application and command-line runners have been called.\n. An javadoc:org.springframework.boot.availability.AvailabilityChangeEvent[] is sent right after with javadoc:org.springframework.boot.availability.LivenessState#CORRECT[] to indicate that the application is considered as live.\n. An javadoc:org.springframework.boot.context.event.ApplicationReadyEvent[] is sent after any xref:features/spring-application.adoc#features.spring-application.command-line-runner[application and command-line runners] have been called.\n. An javadoc:org.springframework.boot.availability.AvailabilityChangeEvent[] is sent right after with javadoc:org.springframework.boot.availability.ReadinessState#ACCEPTING_TRAFFIC[] to indicate that the application is ready to service requests.\n. An javadoc:org.springframework.boot.context.event.ApplicationFailedEvent[] is sent if there is an exception on startup.\n\nThe above list only includes ``SpringApplicationEvent``s that are tied to a javadoc:org.springframework.boot.SpringApplication[].\nIn addition to these, the following events are also published after javadoc:org.springframework.boot.context.event.ApplicationPreparedEvent[] and before javadoc:org.springframework.boot.context.event.ApplicationStartedEvent[]:\n\n- A javadoc:org.springframework.boot.web.server.context.WebServerInitializedEvent[] is sent after the javadoc:org.springframework.boot.web.server.WebServer[] is ready.\n  javadoc:org.springframework.boot.web.server.servlet.context.ServletWebServerInitializedEvent[] and javadoc:org.springframework.boot.web.server.reactive.context.ReactiveWebServerInitializedEvent[] are the servlet and reactive variants respectively.\n- A javadoc:org.springframework.context.event.ContextRefreshedEvent[] is sent when an javadoc:org.springframework.context.ApplicationContext[] is refreshed.\n\nTIP: You often need not use application events, but it can be handy to know that they exist.\nInternally, Spring Boot uses events to handle a variety of tasks.\n\nNOTE: Event listeners should not run potentially lengthy tasks as they execute in the same thread by default.\nConsider using xref:features/spring-application.adoc#features.spring-application.command-line-runner[application and command-line runners] instead.\n\nApplication events are sent by using Spring Framework's event publishing mechanism.\nPart of this mechanism ensures that an event published to the listeners in a child context is also published to the listeners in any ancestor contexts.\nAs a result of this, if your application uses a hierarchy of javadoc:org.springframework.boot.SpringApplication[] instances, a listener may receive multiple instances of the same type of application event.\n\nTo allow your listener to distinguish between an event for its context and an event for a descendant context, it should request that its application context is injected and then compare the injected context with the context of the event.\nThe context can be injected by implementing javadoc:org.springframework.context.ApplicationContextAware[] or, if the listener is a bean, by using javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation].\n\n\n\n[[features.spring-application.web-environment]]\n== Web Environment\n\nA javadoc:org.springframework.boot.SpringApplication[] attempts to create the right type of javadoc:org.springframework.context.ApplicationContext[] on your behalf.\nThe algorithm used to determine a javadoc:org.springframework.boot.WebApplicationType[] is the following:\n\n* If Spring MVC is present, an javadoc:org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext[] is used\n* If Spring MVC is not present and Spring WebFlux is present, an javadoc:org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext[] is used\n* Otherwise, javadoc:org.springframework.context.annotation.AnnotationConfigApplicationContext[] is used\n\nThis means that if you are using Spring MVC and the new javadoc:org.springframework.web.reactive.function.client.WebClient[] from Spring WebFlux in the same application, Spring MVC will be used by default.\nYou can override that easily by calling `setWebApplicationType(WebApplicationType)`.\n\nIt is also possible to take complete control of the javadoc:org.springframework.context.ApplicationContext[] type that is used by calling `setApplicationContextFactory(...)`.\n\nTIP: It is often desirable to call `setWebApplicationType(WebApplicationType.NONE)` when using javadoc:org.springframework.boot.SpringApplication[] within a JUnit test.\n\n\n\n[[features.spring-application.application-arguments]]\n== Accessing Application Arguments\n\nIf you need to access the application arguments that were passed to `SpringApplication.run(...)`, you can inject a javadoc:org.springframework.boot.ApplicationArguments[] bean.\nThe javadoc:org.springframework.boot.ApplicationArguments[] interface provides access to both the raw `String[]` arguments as well as parsed `option` and `non-option` arguments, as shown in the following example:\n\ninclude-code::MyBean[]\n\nTIP: Spring Boot also registers a javadoc:org.springframework.core.env.CommandLinePropertySource[] with the Spring javadoc:org.springframework.core.env.Environment[].\nThis lets you also inject single application arguments by using the javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotation.\n\n\n\n[[features.spring-application.command-line-runner]]\n== Using the ApplicationRunner or CommandLineRunner\n\nIf you need to run some specific code once the javadoc:org.springframework.boot.SpringApplication[] has started, you can implement the javadoc:org.springframework.boot.ApplicationRunner[] or javadoc:org.springframework.boot.CommandLineRunner[] interfaces.\nBoth interfaces work in the same way and offer a single `run` method, which is called just before `SpringApplication.run(...)` completes.\n\nNOTE: This contract is well suited for tasks that should run after application startup but before it starts accepting traffic.\n\n\nThe javadoc:org.springframework.boot.CommandLineRunner[] interfaces provides access to application arguments as a string array, whereas the javadoc:org.springframework.boot.ApplicationRunner[] uses the javadoc:org.springframework.boot.ApplicationArguments[] interface discussed earlier.\nThe following example shows a javadoc:org.springframework.boot.CommandLineRunner[] with a `run` method:\n\ninclude-code::MyCommandLineRunner[]\n\nIf several javadoc:org.springframework.boot.CommandLineRunner[] or javadoc:org.springframework.boot.ApplicationRunner[] beans are defined that must be called in a specific order, you can additionally implement the javadoc:org.springframework.core.Ordered[] interface or use the javadoc:org.springframework.core.annotation.Order[] annotation.\n\n\n\n[[features.spring-application.application-exit]]\n== Application Exit\n\nEach javadoc:org.springframework.boot.SpringApplication[] registers a shutdown hook with the JVM to ensure that the javadoc:org.springframework.context.ApplicationContext[] closes gracefully on exit.\nAll the standard Spring lifecycle callbacks (such as the javadoc:org.springframework.beans.factory.DisposableBean[] interface or the javadoc:jakarta.annotation.PreDestroy[format=annotation] annotation) can be used.\n\nIn addition, beans may implement the javadoc:org.springframework.boot.ExitCodeGenerator[] interface if they wish to return a specific exit code when `SpringApplication.exit()` is called.\nThis exit code can then be passed to `System.exit()` to return it as a status code, as shown in the following example:\n\ninclude-code::MyApplication[]\n\nAlso, the javadoc:org.springframework.boot.ExitCodeGenerator[] interface may be implemented by exceptions.\nWhen such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method.\n\nIf there is more than one javadoc:org.springframework.boot.ExitCodeGenerator[], the first non-zero exit code that is generated is used.\nTo control the order in which the generators are called, additionally implement the javadoc:org.springframework.core.Ordered[] interface or use the javadoc:org.springframework.core.annotation.Order[] annotation.\n\n\n\n[[features.spring-application.admin]]\n== Admin Features\n\nIt is possible to enable admin-related features for the application by specifying the configprop:spring.application.admin.enabled[] property.\nThis exposes the javadoc:org.springframework.boot.admin.SpringApplicationAdminMXBean[] on the platform javadoc:javax.management.MBeanServer[].\nYou could use this feature to administer your Spring Boot application remotely.\nThis feature could also be useful for any service wrapper implementation.\n\nTIP: If you want to know on which HTTP port the application is running, get the property with a key of `local.server.port`.\n\n\n\n[[features.spring-application.startup-tracking]]\n== Application Startup tracking\n\nDuring the application startup, the javadoc:org.springframework.boot.SpringApplication[] and the javadoc:org.springframework.context.ApplicationContext[] perform many tasks related to the application lifecycle,\nthe beans lifecycle or even processing application events.\nWith javadoc:org.springframework.core.metrics.ApplicationStartup[], Spring Framework {url-spring-framework-docs}/core/beans/context-introduction.html#context-functionality-startup[allows you to track the application startup sequence with javadoc:org.springframework.core.metrics.StartupStep[] objects].\nThis data can be collected for profiling purposes, or just to have a better understanding of an application startup process.\n\nYou can choose an javadoc:org.springframework.core.metrics.ApplicationStartup[] implementation when setting up the javadoc:org.springframework.boot.SpringApplication[] instance.\nFor example, to use the javadoc:org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup[], you could write:\n\ninclude-code::MyApplication[]\n\nThe first available implementation, javadoc:org.springframework.core.metrics.jfr.FlightRecorderApplicationStartup[] is provided by Spring Framework.\nIt adds Spring-specific startup events to a Java Flight Recorder session and is meant for profiling applications and correlating their Spring context lifecycle with JVM events (such as allocations, GCs, class loading...).\nOnce configured, you can record data by running the application with the Flight Recorder enabled:\n\n[source,shell]\n----\n$ java -XX:StartFlightRecording:filename=recording.jfr,duration=10s -jar demo.jar\n----\n\nSpring Boot ships with the javadoc:org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup[] variant; this implementation is meant for buffering the startup steps and draining them into an external metrics system.\nApplications can ask for the bean of type javadoc:org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup[] in any component.\n\nSpring Boot can also be configured to expose a xref:api:rest/actuator/startup.adoc[`startup` endpoint] that provides this information as a JSON document.\n\n\n\n[[features.spring-application.virtual-threads]]\n== Virtual threads\n\nVirtual threads require Java 21 or later.\nFor the best experience, Java 24 or later is strongly recommended.\nTo enable virtual threads, set the configprop:spring.threads.virtual.enabled[] property to `true`.\n\nBefore turning on this option for your application, you should consider https://docs.oracle.com/en/java/javase/24/core/virtual-threads.html[reading the official Java virtual threads documentation].\nIn some cases, applications can experience lower throughput because of \"Pinned Virtual Threads\"; this page also explains how to detect such cases with JDK Flight Recorder or the `jcmd` CLI.\n\nNOTE: If virtual threads are enabled, properties which configure thread pools don't have an effect anymore.\nThat's because virtual threads are scheduled on a JVM wide platform thread pool and not on dedicated thread pools.\n\nWARNING: One side effect of virtual threads is that they are daemon threads.\nA JVM will exit if all of its threads are daemon threads.\nThis behavior can be a problem when you rely on javadoc:org.springframework.scheduling.annotation.Scheduled[format=annotation] beans, for example, to keep your application alive.\nIf you use virtual threads, the scheduler thread is a virtual thread and therefore a daemon thread and won't keep the JVM alive.\nThis not only affects scheduling and can be the case with other technologies too.\nTo keep the JVM running in all cases, it is recommended to set the property configprop:spring.main.keep-alive[] to `true`.\nThis ensures that the JVM is kept alive, even if all threads are virtual threads.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/ssl.adoc",
    "content": "[[features.ssl]]\n= SSL\n\nSpring Boot provides the ability to configure SSL trust material that can be applied to several types of connections in order to support secure communications.\nConfiguration properties with the prefix `spring.ssl.bundle` can be used to specify named sets of trust material and associated information.\n\n\n\n[[features.ssl.jks]]\n== Configuring SSL With Java KeyStore Files\n\nConfiguration properties with the prefix `spring.ssl.bundle.jks` can be used to configure bundles of trust material created with the Java `keytool` utility and stored in Java KeyStore files in the JKS or PKCS12 format.\nEach bundle has a user-provided name that can be used to reference the bundle.\n\nWhen used to secure an embedded web server, a `keystore` is typically configured with a Java KeyStore containing a certificate and private key as shown in this example:\n\n[configprops,yaml]\n----\n    spring:\n      ssl:\n        bundle:\n          jks:\n            mybundle:\n              key:\n                alias: \"application\"\n              keystore:\n                location: \"classpath:application.p12\"\n                password: \"secret\"\n                type: \"PKCS12\"\n----\n\nWhen used to secure a client-side connection, a `truststore` is typically configured with a Java KeyStore containing the server certificate as shown in this example:\n\n[configprops,yaml]\n----\n    spring:\n      ssl:\n        bundle:\n          jks:\n            mybundle:\n              truststore:\n                location: \"classpath:server.p12\"\n                password: \"secret\"\n----\n\n[TIP]\n====\nRather than the location to a file, its xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.base64[Base64 encoded content] can be provided.\nIf you chose this option, the value of the property should start with `base64:`.\n====\n\nSee javadoc:org.springframework.boot.autoconfigure.ssl.JksSslBundleProperties[] for the full set of supported properties.\n\nNOTE: If you're using environment variables to configure the bundle, the name of the bundle is xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps-from-environment-variables[always converted to lowercase].\n\n\n\n[[features.ssl.pem]]\n== Configuring SSL With PEM-encoded Certificates\n\nConfiguration properties with the prefix `spring.ssl.bundle.pem` can be used to configure bundles of trust material in the form of PEM-encoded text.\nEach bundle has a user-provided name that can be used to reference the bundle.\n\nWhen used to secure an embedded web server, a `keystore` is typically configured with a certificate and private key as shown in this example:\n\n[configprops,yaml]\n----\n    spring:\n      ssl:\n        bundle:\n          pem:\n            mybundle:\n              keystore:\n                certificate: \"classpath:application.crt\"\n                private-key: \"classpath:application.key\"\n----\n\nWhen used to secure a client-side connection, a `truststore` is typically configured with the server certificate as shown in this example:\n\n[configprops,yaml]\n----\n    spring:\n      ssl:\n        bundle:\n          pem:\n            mybundle:\n              truststore:\n                certificate: \"classpath:server.crt\"\n----\n\n[TIP]\n====\nRather than the location to a file, its xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.conversion.base64[Base64 encoded content] can be provided.\nIf you chose this option, the value of the property should start with `base64:`.\n\nPEM content can also be used directly for both the `certificate` and `private-key` properties.\nIf the property values contain `BEGIN` and `END` markers then they will be treated as PEM content rather than a resource location.\n\nThe following example shows how a truststore certificate can be defined:\n\n[configprops,yaml]\n----\n    spring:\n      ssl:\n        bundle:\n          pem:\n            mybundle:\n              truststore:\n                certificate: |\n                  -----BEGIN CERTIFICATE-----\n                  MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL\n                  BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI\n                  ...\n                  V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds\n                  HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb\n                  ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8\n                  -----END CERTIFICATE-----\n----\n====\n\nSee javadoc:org.springframework.boot.autoconfigure.ssl.PemSslBundleProperties[] for the full set of supported properties.\n\nNOTE: If you're using environment variables to configure the bundle, the name of the bundle is xref:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding.maps-from-environment-variables[always converted to lowercase].\n\n\n\n[[features.ssl.applying]]\n== Applying SSL Bundles\n\nOnce configured using properties, SSL bundles can be referred to by name in configuration properties for various types of connections that are auto-configured by Spring Boot.\nSee the sections on xref:how-to:webserver.adoc#howto.webserver.configure-ssl[embedded web servers], xref:data/index.adoc[data technologies], and xref:io/rest-client.adoc[REST clients] for further information.\n\n\n\n[[features.ssl.bundles]]\n== Using SSL Bundles\n\nSpring Boot auto-configures a bean of type javadoc:org.springframework.boot.ssl.SslBundles[] that provides access to each of the named bundles configured using the `spring.ssl.bundle` properties.\n\nAn javadoc:org.springframework.boot.ssl.SslBundle[] can be retrieved from the auto-configured javadoc:org.springframework.boot.ssl.SslBundles[] bean and used to create objects that are used to configure SSL connectivity in client libraries.\nThe javadoc:org.springframework.boot.ssl.SslBundle[] provides a layered approach of obtaining these SSL objects:\n\n- `getStores()` provides access to the key store and trust store javadoc:java.security.KeyStore[] instances as well as any required key store password.\n- `getManagers()` provides access to the javadoc:javax.net.ssl.KeyManagerFactory[] and javadoc:javax.net.ssl.TrustManagerFactory[] instances as well as the javadoc:javax.net.ssl.KeyManager[] and javadoc:javax.net.ssl.TrustManager[] arrays that they create.\n- `createSslContext()` provides a convenient way to obtain a new javadoc:javax.net.ssl.SSLContext[] instance.\n\nIn addition, the javadoc:org.springframework.boot.ssl.SslBundle[] provides details about the key being used, the protocol to use and any option that should be applied to the SSL engine.\n\nThe following example shows retrieving an javadoc:org.springframework.boot.ssl.SslBundle[] and using it to create an javadoc:javax.net.ssl.SSLContext[]:\n\ninclude-code::MyComponent[]\n\n\n\n[[features.ssl.reloading]]\n== Reloading SSL bundles\n\nSSL bundles can be reloaded when the key material changes.\nThe component consuming the bundle has to be compatible with reloadable SSL bundles.\nCurrently the following components are compatible:\n\n* Tomcat web server\n* Netty web server\n\nTo enable reloading, you need to opt-in via a configuration property as shown in this example:\n\n[configprops,yaml]\n----\n    spring:\n      ssl:\n        bundle:\n          pem:\n            mybundle:\n              reload-on-update: true\n              keystore:\n                certificate: \"file:/some/directory/application.crt\"\n                private-key: \"file:/some/directory/application.key\"\n----\n\nA file watcher is then watching the files and if they change, the SSL bundle will be reloaded.\nThis in turn triggers a reload in the consuming component, e.g. Tomcat rotates the certificates in the SSL enabled connectors.\n\nYou can configure the quiet period (to make sure that there are no more changes) of the file watcher with the configprop:spring.ssl.bundle.watch.file.quiet-period[] property.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/features/task-execution-and-scheduling.adoc",
    "content": "[[features.task-execution-and-scheduling]]\n= Task Execution and Scheduling\n\nIn the absence of an javadoc:java.util.concurrent.Executor[] bean in the context, Spring Boot auto-configures an javadoc:org.springframework.core.task.AsyncTaskExecutor[].\nWhen virtual threads are enabled (using Java 21+ and configprop:spring.threads.virtual.enabled[] set to `true`) this will be a javadoc:org.springframework.core.task.SimpleAsyncTaskExecutor[] that uses virtual threads.\nOtherwise, it will be a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] with sensible defaults.\n\nThe auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[] is used for the following integrations unless a custom javadoc:java.util.concurrent.Executor[] bean is defined:\n\n- Execution of asynchronous tasks using javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation], unless a bean of type javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] is defined.\n- Asynchronous handling of javadoc:java.util.concurrent.Callable[] return values from controller methods in Spring for GraphQL.\n- Asynchronous request handling in Spring MVC.\n- Support for blocking execution in Spring WebFlux.\n- Utilized for inbound and outbound message channels in Spring WebSocket.\n- Bootstrap executor for JPA, based on the bootstrap mode of JPA repositories.\n- Bootstrap executor for {url-spring-framework-docs}/core/beans/java/composing-configuration-classes.html#beans-java-startup-background[background initialization] of beans in the `ApplicationContext`.\n\nWhile this approach works in most scenarios, Spring Boot allows you to override the auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[].\nBy default, when a custom javadoc:java.util.concurrent.Executor[] bean is registered, the auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[] backs off, and the custom javadoc:java.util.concurrent.Executor[] is used for regular task execution (via javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]).\n\nHowever, Spring MVC, Spring WebFlux, and Spring GraphQL all require a bean named `applicationTaskExecutor`.\nFor Spring MVC and Spring WebFlux, this bean must be of type javadoc:org.springframework.core.task.AsyncTaskExecutor[], whereas Spring GraphQL does not enforce this type requirement.\n\nSpring WebSocket and JPA will use javadoc:org.springframework.core.task.AsyncTaskExecutor[] if either a single bean of this type is available or a bean named `applicationTaskExecutor` is defined.\n\nFinally, the boostrap executor of the `ApplicationContext` uses a bean named `applicationTaskExecutor` unless a bean named `bootstrapExecutor` is defined.\n\nThe following code snippet demonstrates how to register a custom javadoc:org.springframework.core.task.AsyncTaskExecutor[] to be used with Spring MVC, Spring WebFlux, Spring GraphQL, Spring WebSocket, JPA, and background initialization of beans.\n\ninclude-code::application/MyTaskExecutorConfiguration[]\n\n[NOTE]\n====\nThe `applicationTaskExecutor` bean will also be used for regular task execution if there is no javadoc:org.springframework.context.annotation.Primary[format=annotation] bean or a bean named `taskExecutor` of type javadoc:java.util.concurrent.Executor[] or javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] present in the application context.\n====\n\n[WARNING]\n====\nIf neither the auto-configured `AsyncTaskExecutor` nor the `applicationTaskExecutor` bean is defined, the application defaults to a bean named `taskExecutor` for regular task execution (javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]), following Spring Framework's behavior.\nHowever, this bean will not be used for Spring MVC, Spring WebFlux, Spring GraphQL.\nIt could, however, be used for Spring WebSocket or JPA if the bean's type is javadoc:org.springframework.core.task.AsyncTaskExecutor[].\n====\n\nIf your application needs multiple `Executor` beans for different integrations, such as one for regular task execution with javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation] and other for Spring MVC, Spring WebFlux, Spring WebSocket and JPA, you can configure them as follows.\n\ninclude-code::multiple/MyTaskExecutorConfiguration[]\n\n[TIP]\n====\nThe auto-configured javadoc:org.springframework.boot.task.ThreadPoolTaskExecutorBuilder[] or javadoc:org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder[] allow you to easily create instances of type javadoc:org.springframework.core.task.AsyncTaskExecutor[] that replicate the default behavior of auto-configuration.\n\ninclude-code::builder/MyTaskExecutorConfiguration[]\n====\n\nIf a `taskExecutor` named bean is not an option, you can mark your bean as javadoc:org.springframework.context.annotation.Primary[format=annotation] or define an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[]  bean to specify the `Executor` responsible for handling regular task execution with javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation].\nThe following example demonstrates how to achieve this.\n\ninclude-code::async/MyTaskExecutorConfiguration[]\n\nTo register a custom javadoc:java.util.concurrent.Executor[] while keeping the auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[], you can create a custom javadoc:java.util.concurrent.Executor[] bean and set the `defaultCandidate=false` attribute in its javadoc:org.springframework.context.annotation.Bean[format=annotation] annotation, as demonstrated in the following example:\n\ninclude-code::defaultcandidate/MyTaskExecutorConfiguration[]\n\nIn that case, you will be able to autowire your custom javadoc:java.util.concurrent.Executor[] into other components while retaining the auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[].\nHowever, remember to use the javadoc:org.springframework.beans.factory.annotation.Qualifier[format=annotation] annotation alongside javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation].\n\nIf this is not possible for you, you can request Spring Boot to auto-configure an javadoc:org.springframework.core.task.AsyncTaskExecutor[] anyway, as follows:\n\n[configprops,yaml]\n----\nspring:\n  task:\n    execution:\n      mode: force\n----\n\nThe auto-configured javadoc:org.springframework.core.task.AsyncTaskExecutor[]  will be used automatically for all integrations, even if a custom javadoc:java.util.concurrent.Executor[] bean is registered, including those marked as javadoc:org.springframework.context.annotation.Primary[format=annotation].\nThese integrations include:\n\n- Asynchronous task execution (javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation]), unless an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean is present.\n- Spring for GraphQL's asynchronous handling of javadoc:java.util.concurrent.Callable[] return values from controller methods.\n- Spring MVC's asynchronous request processing.\n- Spring WebFlux's blocking execution support.\n- Utilized for inbound and outbound message channels in Spring WebSocket.\n- Bootstrap executor for JPA, based on the bootstrap mode of JPA repositories.\n- Bootstrap executor for {url-spring-framework-docs}/core/beans/java/composing-configuration-classes.html#beans-java-startup-background[background initialization] of beans in the `ApplicationContext`, unless a bean named `bootstrapExecutor` is defined.\n\n[TIP]\n====\nDepending on your target arrangement, you could set configprop:spring.task.execution.mode[] to `force` to auto-configure an `applicationTaskExecutor`, change your javadoc:java.util.concurrent.Executor[] into an javadoc:org.springframework.core.task.AsyncTaskExecutor[] or define both an javadoc:org.springframework.core.task.AsyncTaskExecutor[] and an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] wrapping your custom javadoc:java.util.concurrent.Executor[].\n====\n\n[WARNING]\n====\nWhen `force` mode is enabled, `applicationTaskExecutor` will also be configured for regular task execution with javadoc:org.springframework.scheduling.annotation.EnableAsync[format=annotation], even if a javadoc:org.springframework.context.annotation.Primary[format=annotation] bean or a bean named `taskExecutor` of type javadoc:java.util.concurrent.Executor[] is present.\nThe only way to override the `Executor` for regular tasks is by registering an javadoc:org.springframework.scheduling.annotation.AsyncConfigurer[] bean.\n====\n\nWhen a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor[] is auto-configured, the thread pool uses 8 core threads that can grow and shrink according to the load.\nThose default settings can be fine-tuned using the `spring.task.execution` namespace, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  task:\n    execution:\n      pool:\n        max-size: 16\n        queue-capacity: 100\n        keep-alive: \"10s\"\n----\n\nThis changes the thread pool to use a bounded queue so that when the queue is full (100 tasks), the thread pool increases to maximum 16 threads.\nShrinking of the pool is more aggressive as threads are reclaimed when they are idle for 10 seconds (rather than 60 seconds by default).\n\nA scheduler can also be auto-configured if it needs to be associated with scheduled task execution (using javadoc:org.springframework.scheduling.annotation.EnableScheduling[format=annotation] for instance).\n\nIf virtual threads are enabled (using Java 21+ and configprop:spring.threads.virtual.enabled[] set to `true`) this will be a javadoc:org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler[] that uses virtual threads.\nThis javadoc:org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler[] will ignore any pooling related properties.\n\nIf virtual threads are not enabled, it will be a javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler[] with sensible defaults.\nThe javadoc:org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler[] uses one thread by default and its settings can be fine-tuned using the `spring.task.scheduling` namespace, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  task:\n    scheduling:\n      thread-name-prefix: \"scheduling-\"\n      pool:\n        size: 2\n----\n\nA javadoc:org.springframework.boot.task.ThreadPoolTaskExecutorBuilder[] bean, a javadoc:org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder[] bean, a javadoc:org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder[] bean and a javadoc:org.springframework.boot.task.SimpleAsyncTaskSchedulerBuilder[] are made available in the context if a custom executor or scheduler needs to be created.\nThe javadoc:org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder[] and javadoc:org.springframework.boot.task.SimpleAsyncTaskSchedulerBuilder[] beans are auto-configured to use virtual threads if they are enabled (using Java 21+ and configprop:spring.threads.virtual.enabled[] set to `true`).\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/index.adoc",
    "content": "= Reference\n\nThis section provides information on using the features and capabilities of Spring Boot.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/caching.adoc",
    "content": "[[io.caching]]\n= Caching\n\nThe Spring Framework provides support for transparently adding caching to an application.\nAt its core, the abstraction applies caching to methods, thus reducing the number of executions based on the information available in the cache.\nThe caching logic is applied transparently, without any interference to the invoker.\nFor more details, check the {url-spring-framework-docs}/integration/cache.html[relevant section] of the Spring Framework reference documentation.\n\nSpring Boot auto-configures the cache infrastructure as long as caching support is enabled by using the javadoc:org.springframework.cache.annotation.EnableCaching[format=annotation] annotation.\n\nTIP: Avoid adding javadoc:org.springframework.cache.annotation.EnableCaching[format=annotation] to the main method's application class.\nDoing so makes caching a mandatory feature, including xref:io/caching.adoc#io.caching.testing[when running a test suite].\n\nTo add caching to an operation of your service add the relevant annotation to its method, as shown in the following example:\n\ninclude-code::MyMathService[]\n\nThis example demonstrates the use of caching on a potentially costly operation.\nBefore invoking `computePiDecimal`, the abstraction looks for an entry in the `piDecimals` cache that matches the `precision` argument.\nIf an entry is found, the content in the cache is immediately returned to the caller, and the method is not invoked.\nOtherwise, the method is invoked, and the cache is updated before returning the value.\n\nCAUTION: You can also use the standard JSR-107 (JCache) annotations (such as javadoc:javax.cache.annotation.CacheResult[format=annotation]) transparently.\nHowever, we strongly advise you to not mix and match the Spring Cache and JCache annotations.\n\nIf you do not add any specific cache library, Spring Boot auto-configures a xref:io/caching.adoc#io.caching.provider.simple[simple provider] that uses concurrent maps in memory.\nWhen a cache is required (such as `piDecimals` in the preceding example), this provider creates it for you.\nThe simple provider is not really recommended for production usage, but it is great for getting started and making sure that you understand the features.\nWhen you have made up your mind about the cache provider to use, please make sure to read its documentation to figure out how to configure the caches that your application uses.\nNearly all providers require you to explicitly configure every cache that you use in the application.\nSome offer a way to customize the default caches defined by the configprop:spring.cache.cache-names[] property.\n\nTIP: It is also possible to transparently {url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-put[update] or {url-spring-framework-docs}/integration/cache/annotations.html#cache-annotations-evict[evict] data from the cache.\n\n\n\n[[io.caching.provider]]\n== Supported Cache Providers\n\nThe cache abstraction does not provide an actual store and relies on abstraction materialized by the javadoc:org.springframework.cache.Cache[] and javadoc:org.springframework.cache.CacheManager[] interfaces.\n\nIf you have not defined a bean of type javadoc:org.springframework.cache.CacheManager[] or a javadoc:org.springframework.cache.interceptor.CacheResolver[] named `cacheResolver` (see javadoc:org.springframework.cache.annotation.CachingConfigurer[]), Spring Boot tries to detect the following providers (in the indicated order):\n\n. xref:io/caching.adoc#io.caching.provider.generic[]\n. xref:io/caching.adoc#io.caching.provider.jcache[] (EhCache 3, Hazelcast, Infinispan, and others)\n. xref:io/caching.adoc#io.caching.provider.hazelcast[]\n. xref:io/caching.adoc#io.caching.provider.infinispan[]\n. xref:io/caching.adoc#io.caching.provider.couchbase[]\n. xref:io/caching.adoc#io.caching.provider.redis[]\n. xref:io/caching.adoc#io.caching.provider.caffeine[]\n. xref:io/caching.adoc#io.caching.provider.cache2k[]\n. xref:io/caching.adoc#io.caching.provider.simple[]\n\nTIP: If the javadoc:org.springframework.cache.CacheManager[] is auto-configured by Spring Boot, it is possible to _force_ a particular cache provider by setting the configprop:spring.cache.type[] property.\n\nTIP: Use the `spring-boot-starter-cache` starter to quickly add basic caching dependencies.\nThe starter brings in `spring-context-support`.\nIf you add dependencies manually, you must include `spring-context-support` in order to use the JCache or Caffeine support.\n\nIf the javadoc:org.springframework.cache.CacheManager[] is auto-configured by Spring Boot, you can further tune its configuration before it is fully initialized by exposing a bean that implements the javadoc:org.springframework.boot.cache.autoconfigure.CacheManagerCustomizer[] interface.\nThe following example sets a flag to say that `null` values should not be passed down to the underlying map:\n\ninclude-code::MyCacheManagerConfiguration[]\n\nNOTE: In the preceding example, an auto-configured javadoc:org.springframework.cache.concurrent.ConcurrentMapCacheManager[] is expected.\nIf that is not the case (either you provided your own config or a different cache provider was auto-configured), the customizer is not invoked at all.\nYou can have as many customizers as you want, and you can also order them by using javadoc:org.springframework.core.annotation.Order[format=annotation] or javadoc:org.springframework.core.Ordered[].\n\n\n\n[[io.caching.provider.generic]]\n=== Generic\n\nGeneric caching is used if the context defines _at least_ one javadoc:org.springframework.cache.Cache[] bean.\nA javadoc:org.springframework.cache.CacheManager[] wrapping all beans of that type is created.\n\n\n\n[[io.caching.provider.jcache]]\n=== JCache (JSR-107)\n\nhttps://jcp.org/en/jsr/detail?id=107[JCache] is bootstrapped through the presence of a javadoc:javax.cache.spi.CachingProvider[] on the classpath (that is, a JSR-107 compliant caching library exists on the classpath), and the javadoc:org.springframework.cache.jcache.JCacheCacheManager[] is provided by the `spring-boot-starter-cache` starter.\nVarious compliant libraries are available, and Spring Boot provides dependency management for Ehcache 3, Hazelcast, and Infinispan.\nAny other compliant library can be added as well.\n\nIt might happen that more than one provider is present, in which case the provider must be explicitly specified.\nEven if the JSR-107 standard does not enforce a standardized way to define the location of the configuration file, Spring Boot does its best to accommodate setting a cache with implementation details, as shown in the following example:\n\n[configprops,yaml]\n----\n    # Only necessary if more than one provider is present\n\tspring:\n\t  cache:\n\t    jcache:\n\t      provider: \"com.example.MyCachingProvider\"\n\t      config: \"classpath:example.xml\"\n----\n\nNOTE: When a cache library offers both a native implementation and JSR-107 support, Spring Boot prefers the JSR-107 support, so that the same features are available if you switch to a different JSR-107 implementation.\n\nTIP: Spring Boot has xref:io/hazelcast.adoc[general support for Hazelcast].\nIf a single javadoc:com.hazelcast.core.HazelcastInstance[] is available, it is automatically reused for the javadoc:javax.cache.CacheManager[] as well, unless the configprop:spring.cache.jcache.config[] property is specified.\n\nThere are two ways to customize the underlying javadoc:javax.cache.CacheManager[]:\n\n* Caches can be created on startup by setting the configprop:spring.cache.cache-names[] property.\nIf a custom javadoc:javax.cache.configuration.Configuration[] bean is defined, it is used to customize them.\n* javadoc:org.springframework.boot.cache.autoconfigure.CacheManagerCustomizer[] beans are invoked with the reference of the javadoc:javax.cache.CacheManager[] for full customization.\n\nTIP: If a standard javadoc:javax.cache.CacheManager[] bean is defined, it is wrapped automatically in an javadoc:org.springframework.cache.CacheManager[] implementation that the abstraction expects.\nNo further customization is applied to it.\n\n\n\n[[io.caching.provider.hazelcast]]\n=== Hazelcast\n\nSpring Boot has xref:io/hazelcast.adoc[general support for Hazelcast].\nIf a javadoc:com.hazelcast.core.HazelcastInstance[] has been auto-configured and `com.hazelcast:hazelcast-spring` is on the classpath, it is automatically wrapped in a javadoc:org.springframework.cache.CacheManager[].\n\nNOTE: Hazelcast can be used as a JCache compliant cache or as a Spring javadoc:org.springframework.cache.CacheManager[] compliant cache.\nWhen setting configprop:spring.cache.type[] to `hazelcast`, Spring Boot will use the javadoc:org.springframework.cache.CacheManager[] based implementation.\nIf you want to use Hazelcast as a JCache compliant cache, set configprop:spring.cache.type[] to `jcache`.\nIf you have multiple JCache compliant cache providers and want to force the use of Hazelcast, you have to xref:io/caching.adoc#io.caching.provider.jcache[explicitly set the JCache provider].\n\n\n\n[[io.caching.provider.infinispan]]\n=== Infinispan\n\nhttps://infinispan.org/[Infinispan] has no default configuration file location, so it must be specified explicitly.\nOtherwise, the default bootstrap is used.\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    infinispan:\n      config: \"infinispan.xml\"\n----\n\nCaches can be created on startup by setting the configprop:spring.cache.cache-names[] property.\nIf a custom javadoc:org.infinispan.configuration.cache.ConfigurationBuilder[] bean is defined, it is used to customize the caches.\n\nFor more details, see https://infinispan.org/docs/stable/titles/spring/spring.html[the documentation].\n\n\n[[io.caching.provider.couchbase]]\n=== Couchbase\n\nIf Spring Data Couchbase is available and Couchbase is xref:data/nosql.adoc#data.nosql.couchbase[configured], a javadoc:org.springframework.data.couchbase.cache.CouchbaseCacheManager[] is auto-configured.\nIt is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using `spring.cache.couchbase.*` properties.\nFor instance, the following configuration creates `cache1` and `cache2` caches with an entry _expiration_ of 10 minutes:\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    cache-names: \"cache1,cache2\"\n    couchbase:\n      expiration: \"10m\"\n----\n\nIf you need more control over the configuration, consider registering a javadoc:org.springframework.boot.cache.autoconfigure.CouchbaseCacheManagerBuilderCustomizer[] bean.\nThe following example shows a customizer that configures a specific entry expiration for `cache1` and `cache2`:\n\ninclude-code::MyCouchbaseCacheManagerConfiguration[]\n\n\n\n[[io.caching.provider.redis]]\n=== Redis\n\nIf https://redis.io/[Redis] is available and configured, a javadoc:org.springframework.data.redis.cache.RedisCacheManager[] is auto-configured.\nIt is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using `spring.cache.redis.*` properties.\nFor instance, the following configuration creates `cache1` and `cache2` caches with a _time to live_ of 10 minutes:\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    cache-names: \"cache1,cache2\"\n    redis:\n      time-to-live: \"10m\"\n----\n\nNOTE: By default, a key prefix is added so that, if two separate caches use the same key, Redis does not have overlapping keys and cannot return invalid values.\nWe strongly recommend keeping this setting enabled if you create your own javadoc:org.springframework.data.redis.cache.RedisCacheManager[].\n\nTIP: You can take full control of the default configuration by adding a javadoc:org.springframework.data.redis.cache.RedisCacheConfiguration[] javadoc:org.springframework.context.annotation.Bean[format=annotation] of your own.\nThis can be useful if you need to customize the default serialization strategy.\n\nIf you need more control over the configuration, consider registering a javadoc:org.springframework.boot.cache.autoconfigure.RedisCacheManagerBuilderCustomizer[] bean.\nThe following example shows a customizer that configures a specific time to live for `cache1` and `cache2`:\n\ninclude-code::MyRedisCacheManagerConfiguration[]\n\n\n\n[[io.caching.provider.caffeine]]\n=== Caffeine\n\nhttps://github.com/ben-manes/caffeine[Caffeine] is a Java 8 rewrite of Guava's cache that supersedes support for Guava.\nIf Caffeine is present, a javadoc:org.springframework.cache.caffeine.CaffeineCacheManager[] (provided by the `spring-boot-starter-cache` starter) is auto-configured.\nCaches can be created on startup by setting the configprop:spring.cache.cache-names[] property and can be customized by one of the following (in the indicated order):\n\n. A cache spec defined by `spring.cache.caffeine.spec`\n. A javadoc:com.github.benmanes.caffeine.cache.CaffeineSpec[] bean is defined\n. A javadoc:com.github.benmanes.caffeine.cache.Caffeine[] bean is defined\n\nFor instance, the following configuration creates `cache1` and `cache2` caches with a maximum size of 500 and a _time to live_ of 10 minutes\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    cache-names: \"cache1,cache2\"\n    caffeine:\n      spec: \"maximumSize=500,expireAfterAccess=600s\"\n----\n\nIf a javadoc:com.github.benmanes.caffeine.cache.CacheLoader[] bean is defined, it is automatically associated to the javadoc:org.springframework.cache.caffeine.CaffeineCacheManager[].\nSince the javadoc:com.github.benmanes.caffeine.cache.CacheLoader[] is going to be associated with _all_ caches managed by the cache manager, it must be defined as `CacheLoader<Object, Object>`.\nThe auto-configuration ignores any other generic type.\n\n\n\n[[io.caching.provider.cache2k]]\n=== Cache2k\n\nhttps://cache2k.org/[Cache2k] is an in-memory cache.\nIf the Cache2k spring integration is present, a `SpringCache2kCacheManager` is auto-configured.\n\nCaches can be created on startup by setting the configprop:spring.cache.cache-names[] property.\nCache defaults can be customized using a javadoc:org.springframework.boot.cache.autoconfigure.Cache2kBuilderCustomizer[] bean.\nThe following example shows a customizer that configures the capacity of the cache to 200 entries, with an expiration of 5 minutes:\n\ninclude-code::MyCache2kDefaultsConfiguration[]\n\n\n\n[[io.caching.provider.simple]]\n=== Simple\n\nIf none of the other providers can be found, a simple implementation using a javadoc:java.util.concurrent.ConcurrentHashMap[] as the cache store is configured.\nThis is the default if no caching library is present in your application.\nBy default, caches are created as needed, but you can restrict the list of available caches by setting the `cache-names` property.\nFor instance, if you want only `cache1` and `cache2` caches, set the `cache-names` property as follows:\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    cache-names: \"cache1,cache2\"\n----\n\nIf you do so and your application uses a cache not listed, then it fails at runtime when the cache is needed, but not on startup.\nThis is similar to the way the \"real\" cache providers behave if you use an undeclared cache.\n\n\n\n[[io.caching.provider.none]]\n=== None\n\nIf you need to use a no-op cache rather than the auto-configured cache manager in a certain environment, set the cache type to `none`, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    type: \"none\"\n----\n\n\n\n[[io.caching.testing]]\n== Testing\n\nIt is generally useful to use a no-op implementation when running a test suite.\nThis section lists a number of strategies that are useful for tests.\n\nWhen a custom javadoc:org.springframework.cache.CacheManager[] is defined, the best option is to make sure that caching configuration is defined in an isolated javadoc:org.springframework.context.annotation.Configuration[format=annotation] class.\nDoing so makes sure that caching is not required by slice tests.\nFor tests that enable a full context, such as javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation], an explicit configuration overriding the regular configuration is required.\n\nIf caching is auto-configured, more options are available.\nTests can be annotated with javadoc:org.springframework.boot.test.autoconfigure.core.AutoConfigureCache[format=annotation] to replace the auto-configured javadoc:org.springframework.cache.CacheManager[] by a no-op implementation.\n\ninclude-code::MyIntegrationTests[]\n\nAnother option is to force a no-op implementation for the auto-configured javadoc:org.springframework.cache.CacheManager[]:\n\n[configprops,yaml]\n----\nspring:\n  cache:\n    type: \"none\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/email.adoc",
    "content": "[[io.email]]\n= Sending Email\n\nThe Spring Framework provides an abstraction for sending email by using the javadoc:org.springframework.mail.javamail.JavaMailSender[] interface, and Spring Boot provides auto-configuration for it as well as a starter module.\n\nTIP: See the {url-spring-framework-docs}/integration/email.html[reference documentation] for a detailed explanation of how you can use javadoc:org.springframework.mail.javamail.JavaMailSender[].\n\nIf `spring.mail.host` and the relevant libraries (as defined by `spring-boot-starter-mail`) are available, a default javadoc:org.springframework.mail.javamail.JavaMailSender[] is created if none exists.\nThe sender can be further customized by configuration items from the `spring.mail` namespace.\nSee javadoc:org.springframework.boot.mail.autoconfigure.MailProperties[] for more details.\n\nIn particular, certain default timeout values are infinite, and you may want to change that to avoid having a thread blocked by an unresponsive mail server, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  mail:\n    properties:\n      \"[mail.smtp.connectiontimeout]\": 5000\n      \"[mail.smtp.timeout]\": 3000\n      \"[mail.smtp.writetimeout]\": 5000\n----\n\nIt is also possible to configure a javadoc:org.springframework.mail.javamail.JavaMailSender[] with an existing javadoc:jakarta.mail.Session[] from JNDI:\n\n[configprops,yaml]\n----\nspring:\n  mail:\n    jndi-name: \"mail/Session\"\n----\n\nWhen a `jndi-name` is set, it takes precedence over all other Session-related settings.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/hazelcast.adoc",
    "content": "[[io.hazelcast]]\n= Hazelcast\n\nIf https://hazelcast.com/[Hazelcast] is on the classpath and a suitable configuration is found, Spring Boot auto-configures a javadoc:com.hazelcast.core.HazelcastInstance[] that you can inject in your application.\n\nSpring Boot first attempts to create a client by checking the following configuration options:\n\n* The presence of a javadoc:com.hazelcast.client.config.ClientConfig[] bean.\n* A configuration file defined by the configprop:spring.hazelcast.config[] property.\n* The presence of the `hazelcast.client.config` system property.\n* A `hazelcast-client.xml` in the working directory or at the root of the classpath.\n* A `hazelcast-client.yaml` (or `hazelcast-client.yml`) in the working directory or at the root of the classpath.\n\nIf a client can not be created, Spring Boot attempts to configure an embedded server.\nIf you define a javadoc:com.hazelcast.config.Config[] bean, Spring Boot uses it at is.\nIf your configuration defines an instance name, Spring Boot tries to locate an existing instance rather than creating a new one.\n\nYou could also specify the Hazelcast configuration file to use through configuration, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  hazelcast:\n    config: \"classpath:config/my-hazelcast.xml\"\n----\n\nOtherwise, Spring Boot tries to find the Hazelcast configuration from the default locations: `hazelcast.xml` in the working directory or at the root of the classpath, or a YAML counterpart in the same locations.\nWe also check if the `hazelcast.config` system property is set.\nSee the https://docs.hazelcast.org/docs/latest/manual/html-single/[Hazelcast documentation] for more details.\n\nTIP: By default, javadoc:com.hazelcast.spring.context.SpringAware[format=annotation] on Hazelcast components is supported.\nThe javadoc:com.hazelcast.core.ManagedContext[] can be overridden by declaring a javadoc:org.springframework.boot.hazelcast.autoconfigure.HazelcastConfigCustomizer[] bean with an javadoc:org.springframework.core.annotation.Order[format=annotation] higher than zero.\n\nNOTE: Spring Boot also has xref:io/caching.adoc#io.caching.provider.hazelcast[explicit caching support for Hazelcast].\nIf caching is enabled, the javadoc:com.hazelcast.core.HazelcastInstance[] is automatically wrapped in a javadoc:org.springframework.cache.CacheManager[] implementation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/index.adoc",
    "content": "[[io]]\n= IO\n\nMost applications will need to deal with input and output concerns at some point.\nSpring Boot provides utilities and integrations with a range of technologies to help when you need IO capabilities.\nThis section covers standard IO features such as caching and validation as well as more advanced topics such as batch, scheduling, and distributed transactions.\nWe will also cover calling remote REST or SOAP services and sending email.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/jta.adoc",
    "content": "[[io.jta]]\n= Distributed Transactions With JTA\n\nSpring Boot supports distributed JTA transactions across multiple XA resources by using a transaction manager retrieved from JNDI.\n\nWhen a JTA environment is detected, Spring's javadoc:org.springframework.transaction.jta.JtaTransactionManager[] is used to manage transactions.\nAuto-configured JMS, DataSource, and JPA beans are upgraded to support XA transactions.\nYou can use standard Spring idioms, such as javadoc:org.springframework.transaction.annotation.Transactional[format=annotation], to participate in a distributed transaction.\nIf you are within a JTA environment and still want to use local transactions, you can set the configprop:spring.jta.enabled[] property to `false` to disable the JTA auto-configuration.\n\n\n\n[[io.jta.jakartaee]]\n== Using a Jakarta EE Managed Transaction Manager\n\nIf you package your Spring Boot application as a `war` or `ear` file and deploy it to a Jakarta EE application server, you can use your application server's built-in transaction manager.\nSpring Boot tries to auto-configure a transaction manager by looking at common JNDI locations (`java:comp/UserTransaction`, `java:comp/TransactionManager`, and so on).\nWhen using a transaction service provided by your application server, you generally also want to ensure that all resources are managed by the server and exposed over JNDI.\nSpring Boot tries to auto-configure JMS by looking for a javadoc:jakarta.jms.ConnectionFactory[] at the JNDI path (`java:/JmsXA` or `java:/XAConnectionFactory`), and you can use the xref:data/sql.adoc#data.sql.datasource.jndi[configprop:spring.datasource.jndi-name[] property] to configure your javadoc:javax.sql.DataSource[].\n\n\n\n[[io.jta.mixing-xa-and-non-xa-connections]]\n== Mixing XA and Non-XA JMS Connections\n\nWhen using JTA, the primary JMS javadoc:jakarta.jms.ConnectionFactory[] bean is XA-aware and participates in distributed transactions.\nYou can inject into your bean without needing to use any javadoc:org.springframework.beans.factory.annotation.Qualifier[format=annotation]:\n\ninclude-code::primary/MyBean[]\n\nIn some situations, you might want to process certain JMS messages by using a non-XA javadoc:jakarta.jms.ConnectionFactory[].\nFor example, your JMS processing logic might take longer than the XA timeout.\n\nIf you want to use a non-XA javadoc:jakarta.jms.ConnectionFactory[], you can the `nonXaJmsConnectionFactory` bean:\n\ninclude-code::nonxa/MyBean[]\n\nFor consistency, the `jmsConnectionFactory` bean is also provided by using the bean alias `xaJmsConnectionFactory`:\n\ninclude-code::xa/MyBean[]\n\n\n\n[[io.jta.supporting-embedded-transaction-manager]]\n== Supporting an Embedded Transaction Manager\n\nThe javadoc:org.springframework.boot.jms.XAConnectionFactoryWrapper[] and javadoc:org.springframework.boot.jdbc.XADataSourceWrapper[] interfaces can be used to support embedded transaction managers.\nThe interfaces are responsible for wrapping javadoc:jakarta.jms.XAConnectionFactory[] and javadoc:javax.sql.XADataSource[] beans and exposing them as regular javadoc:jakarta.jms.ConnectionFactory[] and javadoc:javax.sql.DataSource[] beans, which transparently enroll in the distributed transaction.\nDataSource and JMS auto-configuration use JTA variants, provided you have a javadoc:org.springframework.transaction.jta.JtaTransactionManager[] bean and appropriate XA wrapper beans registered within your javadoc:org.springframework.context.ApplicationContext[].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/quartz.adoc",
    "content": "[[io.quartz]]\n= Quartz Scheduler\n\nSpring Boot offers several conveniences for working with the https://www.quartz-scheduler.org/[Quartz scheduler], including the `spring-boot-starter-quartz` starter.\nIf Quartz is available, a javadoc:org.quartz.Scheduler[] is auto-configured (through the javadoc:org.springframework.scheduling.quartz.SchedulerFactoryBean[] abstraction).\n\nBeans of the following types are automatically picked up and associated with the javadoc:org.quartz.Scheduler[]:\n\n* javadoc:org.quartz.JobDetail[]: defines a particular Job.\n  javadoc:org.quartz.JobDetail[] instances can be built with the javadoc:org.quartz.JobBuilder[] API.\n* javadoc:org.quartz.Calendar[].\n* javadoc:org.quartz.Trigger[]: defines when a particular job is triggered.\n\nBy default, an in-memory javadoc:org.quartz.spi.JobStore[] is used.\nHowever, it is possible to configure a JDBC-based store if a javadoc:javax.sql.DataSource[] bean is available in your application and if the configprop:spring.quartz.job-store-type[] property is configured accordingly, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  quartz:\n    job-store-type: \"jdbc\"\n----\n\nWhen the JDBC store is used, the schema can be initialized on startup, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  quartz:\n    jdbc:\n      initialize-schema: \"always\"\n----\n\nWARNING: By default, the database is detected and initialized by using the standard scripts provided with the Quartz library.\nThese scripts drop existing tables, deleting all triggers on every restart.\nTo use a custom script, set the configprop:spring.quartz.jdbc.schema[] property.\nSome of the standard scripts – such as those for SQL Server, Azure SQL, and Sybase – cannot be used without modification.\nIn these cases, make a copy of the script and edit it as directed in the script's comments then set configprop:spring.quartz.jdbc.schema[] to use your customized script.\n\nTo have Quartz use a javadoc:javax.sql.DataSource[] other than the application's main javadoc:javax.sql.DataSource[], declare a javadoc:javax.sql.DataSource[] bean, annotating its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.quartz.autoconfigure.QuartzDataSource[format=annotation].\nDoing so ensures that the Quartz-specific javadoc:javax.sql.DataSource[] is used by both the javadoc:org.springframework.scheduling.quartz.SchedulerFactoryBean[] and for schema initialization.\nSimilarly, to have Quartz use a javadoc:org.springframework.transaction.TransactionManager[] other than the application's main javadoc:org.springframework.transaction.TransactionManager[] declare a javadoc:org.springframework.transaction.TransactionManager[] bean, annotating its javadoc:org.springframework.context.annotation.Bean[format=annotation] method with javadoc:org.springframework.boot.quartz.autoconfigure.QuartzTransactionManager[format=annotation].\n\nBy default, jobs created by configuration will not overwrite already registered jobs that have been read from a persistent job store.\nTo enable overwriting existing job definitions set the configprop:spring.quartz.overwrite-existing-jobs[] property.\n\nQuartz Scheduler configuration can be customized using `spring.quartz` properties and javadoc:org.springframework.boot.quartz.autoconfigure.SchedulerFactoryBeanCustomizer[] beans, which allow programmatic javadoc:org.springframework.scheduling.quartz.SchedulerFactoryBean[] customization.\nAdvanced Quartz configuration properties can be customized using `spring.quartz.properties.*`.\n\nNOTE: In particular, an javadoc:java.util.concurrent.Executor[] bean is not associated with the scheduler as Quartz offers a way to configure the scheduler through `spring.quartz.properties`.\nIf you need to customize the task executor, consider implementing javadoc:org.springframework.boot.quartz.autoconfigure.SchedulerFactoryBeanCustomizer[].\n\nJobs can define setters to inject data map properties.\nRegular beans can also be injected in a similar manner, as shown in the following example:\n\ninclude-code::MySampleJob[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/rest-client.adoc",
    "content": "[[io.rest-client]]\n= Calling REST Services\n\nSpring Boot provides various convenient ways to call remote REST services.\nIf you are developing a non-blocking reactive application and you're using Spring WebFlux, then you can use javadoc:org.springframework.web.reactive.function.client.WebClient[].\nIf you prefer imperative APIs then you can use javadoc:org.springframework.web.client.RestClient[] or javadoc:org.springframework.web.client.RestTemplate[].\n\n\n\n[[io.rest-client.webclient]]\n== WebClient\n\nIf you have Spring WebFlux on your classpath we recommend that you use javadoc:org.springframework.web.reactive.function.client.WebClient[] to call remote REST services.\nThe javadoc:org.springframework.web.reactive.function.client.WebClient[] interface provides a functional style API and is fully reactive.\nYou can learn more about the javadoc:org.springframework.web.reactive.function.client.WebClient[] in the dedicated {url-spring-framework-docs}/web/webflux-webclient.html[section in the Spring Framework docs].\n\nTIP: If you are not writing a reactive Spring WebFlux application you can use the xref:io/rest-client.adoc#io.rest-client.restclient[`RestClient`] instead of a javadoc:org.springframework.web.reactive.function.client.WebClient[].\nThis provides a similar functional API, but is imperative rather than reactive.\n\nSpring Boot creates and pre-configures a prototype javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] bean for you.\nIt is strongly advised to inject it in your components and use it to create javadoc:org.springframework.web.reactive.function.client.WebClient[] instances.\nSpring Boot is configuring that builder to share HTTP resources and reflect codecs setup in the same fashion as the server ones (see xref:web/reactive.adoc#web.reactive.webflux.httpcodecs[WebFlux HTTP codecs auto-configuration]), and more.\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n\n\n\n[[io.rest-client.webclient.runtime]]\n=== WebClient Runtime\n\nSpring Boot will auto-detect which javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] to use to drive javadoc:org.springframework.web.reactive.function.client.WebClient[] depending on the libraries available on the application classpath.\nIn order of preference, the following clients are supported:\n\n. Reactor Netty\n. Jetty RS client\n. Apache HttpClient\n. JDK HttpClient\n\nIf multiple clients are available on the classpath, the most preferred client will be used.\n\nThe `spring-boot-starter-webflux` starter depends on `io.projectreactor.netty:reactor-netty` by default, which brings both server and client implementations.\nIf you choose to use Jetty as a reactive server instead, you should add a dependency on the Jetty Reactive HTTP client library, `org.eclipse.jetty:jetty-reactive-httpclient`.\nUsing the same technology for server and client has its advantages, as it will automatically share HTTP resources between client and server.\n\nDevelopers can override the resource configuration for Jetty and Reactor Netty by providing a custom javadoc:org.springframework.http.client.ReactorResourceFactory[] or javadoc:org.springframework.http.client.reactive.JettyResourceFactory[] bean - this will be applied to both clients and servers.\n\nIf you wish to override that choice for the client, you can define your own javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] bean and have full control over the client configuration.\n\nYou can learn more about the {url-spring-framework-docs}/web/webflux-webclient/client-builder.html[`WebClient` configuration options in the Spring Framework reference documentation].\n\n\n\n[[io.rest-client.webclient.configuration]]\n=== Global HTTP Connector Configuration\n\nIf the auto-detected javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] does not meet your needs, you can use the configprop:spring.http.clients.reactive.connector[] property to pick a specific connector.\nFor example, if you have Reactor Netty on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add the following:\n\n[configprops,yaml]\n----\nspring:\n  http:\n    clients:\n      reactive:\n        connector: jetty\n----\n\nTIP: You can also use xref:io/rest-client.adoc#io.rest-client.global-configuration[global configuration properties] which apply to all HTTP clients.\n\nFor more complex customizations, you can use javadoc:org.springframework.boot.http.client.autoconfigure.reactive.ClientHttpConnectorBuilderCustomizer[] or declare your own javadoc:org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder[] bean which will cause auto-configuration to back off.\nThis can be useful when you need to customize some of the internals of the underlying HTTP library.\n\nFor example, the following will use a JDK client configured with a specific javadoc:java.net.ProxySelector[]:\n\ninclude-code::MyConnectorHttpConfiguration[]\n\n\n\n[[io.rest-client.webclient.customization]]\n=== WebClient Customization\n\nThere are three main approaches to javadoc:org.springframework.web.reactive.function.client.WebClient[] customization, depending on how broadly you want the customizations to apply.\n\nTo make the scope of any customizations as narrow as possible, inject the auto-configured javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] and then call its methods as required.\njavadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] instances are stateful: Any change on the builder is reflected in all clients subsequently created with it.\nIf you want to create several clients with the same builder, you can also consider cloning the builder with `WebClient.Builder other = builder.clone();`.\n\nTo make an application-wide, additive customization to all javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] instances, you can declare javadoc:org.springframework.boot.webclient.WebClientCustomizer[] beans and change the javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] locally at the point of injection.\n\nFinally, you can fall back to the original API and use `WebClient.create()`.\nIn that case, no auto-configuration or javadoc:org.springframework.boot.webclient.WebClientCustomizer[] is applied.\n\n\n\n[[io.rest-client.webclient.ssl]]\n=== WebClient SSL Support\n\nIf you need custom SSL configuration on the javadoc:org.springframework.http.client.reactive.ClientHttpConnector[] used by the javadoc:org.springframework.web.reactive.function.client.WebClient[], you can inject a javadoc:org.springframework.boot.webclient.autoconfigure.WebClientSsl[] instance that can be used with the builder's `apply` method.\n\nThe javadoc:org.springframework.boot.webclient.autoconfigure.WebClientSsl[] interface provides access to any xref:features/ssl.adoc#features.ssl.bundles[SSL bundles] that you have defined in your `application.properties` or `application.yaml` file.\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n\n\n\n[[io.rest-client.restclient]]\n== RestClient\n\nIf you are not using Spring WebFlux or Project Reactor in your application we recommend that you use javadoc:org.springframework.web.client.RestClient[] to call remote REST services.\n\nThe javadoc:org.springframework.web.client.RestClient[] interface provides a functional style imperative API.\n\nSpring Boot creates and pre-configures a prototype javadoc:org.springframework.web.client.RestClient$Builder[] bean for you.\nIt is strongly advised to inject it in your components and use it to create javadoc:org.springframework.web.client.RestClient[] instances.\nSpring Boot is configuring that builder with javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] and an appropriate javadoc:org.springframework.http.client.ClientHttpRequestFactory[].\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n\n\n\n[[io.rest-client.restclient.customization]]\n=== RestClient Customization\n\nThere are three main approaches to javadoc:org.springframework.web.client.RestClient[] customization, depending on how broadly you want the customizations to apply.\n\nTo make the scope of any customizations as narrow as possible, inject the auto-configured javadoc:org.springframework.web.client.RestClient$Builder[] and then call its methods as required.\njavadoc:org.springframework.web.client.RestClient$Builder[] instances are stateful: Any change on the builder is reflected in all clients subsequently created with it.\nIf you want to create several clients with the same builder, you can also consider cloning the builder with `RestClient.Builder other = builder.clone();`.\n\nTo make an application-wide, additive customization to all javadoc:org.springframework.web.client.RestClient$Builder[] instances, you can declare javadoc:org.springframework.boot.restclient.RestClientCustomizer[] beans and change the javadoc:org.springframework.web.client.RestClient$Builder[] locally at the point of injection.\n\nFinally, you can fall back to the original API and use `RestClient.create()`.\nIn that case, no auto-configuration or javadoc:org.springframework.boot.restclient.RestClientCustomizer[] is applied.\n\nTIP: You can also change the xref:io/rest-client.adoc#io.rest-client.clienthttprequestfactory.configuration[global HTTP client configuration].\n\n\n\n[[io.rest-client.restclient.ssl]]\n=== RestClient SSL Support\n\nIf you need custom SSL configuration on the javadoc:org.springframework.http.client.ClientHttpRequestFactory[] used by the javadoc:org.springframework.web.client.RestClient[], you can inject a javadoc:org.springframework.boot.restclient.autoconfigure.RestClientSsl[] instance that can be used with the builder's `apply` method.\n\nThe javadoc:org.springframework.boot.restclient.autoconfigure.RestClientSsl[] interface provides access to any xref:features/ssl.adoc#features.ssl.bundles[SSL bundles] that you have defined in your `application.properties` or `application.yaml` file.\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n\nIf you need to apply other customization in addition to an SSL bundle, you can use the javadoc:org.springframework.boot.http.client.HttpClientSettings[] class with javadoc:org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder[]:\n\ninclude-code::settings/MyService[]\n\n\n\n[[io.rest-client.resttemplate]]\n== RestTemplate\n\nSpring Framework's javadoc:org.springframework.web.client.RestTemplate[] class predates javadoc:org.springframework.web.client.RestClient[] and is the classic way that many applications use to call remote REST services.\nYou might choose to use javadoc:org.springframework.web.client.RestTemplate[] when you have existing code that you don't want to migrate to javadoc:org.springframework.web.client.RestClient[], or because you're already familiar with the javadoc:org.springframework.web.client.RestTemplate[] API.\n\nSince javadoc:org.springframework.web.client.RestTemplate[] instances often need to be customized before being used, Spring Boot does not provide any single auto-configured javadoc:org.springframework.web.client.RestTemplate[] bean.\nIt does, however, auto-configure a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[], which can be used to create javadoc:org.springframework.web.client.RestTemplate[] instances when needed.\nThe auto-configured javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] ensures that sensible javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] and an appropriate javadoc:org.springframework.http.client.ClientHttpRequestFactory[] are applied to javadoc:org.springframework.web.client.RestTemplate[] instances.\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n\njavadoc:org.springframework.boot.restclient.RestTemplateBuilder[] includes a number of useful methods that can be used to quickly configure a javadoc:org.springframework.web.client.RestTemplate[].\nFor example, to add BASIC authentication support, you can use `builder.basicAuthentication(\"user\", \"password\").build()`.\n\n\n\n[[io.rest-client.resttemplate.customization]]\n=== RestTemplate Customization\n\nThere are three main approaches to javadoc:org.springframework.web.client.RestTemplate[] customization, depending on how broadly you want the customizations to apply.\n\nTo make the scope of any customizations as narrow as possible, inject the auto-configured javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] and then call its methods as required.\nEach method call returns a new javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] instance, so the customizations only affect this use of the builder.\n\nTo make an application-wide, additive customization, use a javadoc:org.springframework.boot.restclient.RestTemplateCustomizer[] bean.\nAll such beans are automatically registered with the auto-configured javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] and are applied to any templates that are built with it.\n\nThe following example shows a customizer that configures the use of a proxy for all hosts except `192.168.0.5`:\n\ninclude-code::MyRestTemplateCustomizer[]\n\nFinally, you can define your own javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] bean.\nDoing so will replace the auto-configured builder.\nIf you want any javadoc:org.springframework.boot.restclient.RestTemplateCustomizer[] beans to be applied to your custom builder, as the auto-configuration would have done, configure it using a javadoc:org.springframework.boot.restclient.autoconfigure.RestTemplateBuilderConfigurer[].\nThe following example exposes a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] that matches what Spring Boot's auto-configuration would have done, except that custom connect and read timeouts are also specified:\n\ninclude-code::MyRestTemplateBuilderConfiguration[]\n\nThe most extreme (and rarely used) option is to create your own javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] bean without using a configurer.\nIn addition to replacing the auto-configured builder, this also prevents any javadoc:org.springframework.boot.restclient.RestTemplateCustomizer[] beans from being used.\n\nTIP: You can also change the xref:io/rest-client.adoc#io.rest-client.clienthttprequestfactory.configuration[global HTTP client configuration].\n\n\n\n[[io.rest-client.resttemplate.ssl]]\n=== RestTemplate SSL Support\n\nIf you need custom SSL configuration on the javadoc:org.springframework.web.client.RestTemplate[], you can apply an xref:features/ssl.adoc#features.ssl.bundles[SSL bundle] to the javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] as shown in this example:\n\ninclude-code::MyService[]\n\n\n\n[[io.rest-client.clienthttprequestfactory]]\n== HTTP Client Detection for RestClient and RestTemplate\n\nSpring Boot will auto-detect which HTTP client to use with javadoc:org.springframework.web.client.RestClient[] and javadoc:org.springframework.web.client.RestTemplate[] depending on the libraries available on the application classpath.\nIn order of preference, the following clients are supported:\n\n. Apache HttpClient\n. Jetty HttpClient\n. Reactor Netty HttpClient\n. JDK client (`java.net.http.HttpClient`)\n. Simple JDK client (`java.net.HttpURLConnection`)\n\nIf multiple clients are available on the classpath, and no global configuration is provided, the most preferred client will be used.\n\n\n\n[[io.rest-client.clienthttprequestfactory.configuration]]\n=== Global HTTP Client Configuration\n\nIf the auto-detected HTTP client does not meet your needs, you can use the configprop:spring.http.clients.imperative.factory[] property to pick a specific factory.\nFor example, if you have Apache HttpClient on your classpath, but you prefer Jetty's javadoc:org.eclipse.jetty.client.HttpClient[] you can add the following:\n\n[configprops,yaml]\n----\nspring:\n  http:\n    clients:\n      imperative:\n        factory: jetty\n----\n\nTIP: You can also use xref:io/rest-client.adoc#io.rest-client.global-configuration[global configuration properties] which apply to all HTTP clients.\n\nFor more complex customizations, you can use javadoc:org.springframework.boot.http.client.autoconfigure.ClientHttpRequestFactoryBuilderCustomizer[] or declare your own javadoc:org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder[] bean which will cause auto-configuration to back off.\nThis can be useful when you need to customize some of the internals of the underlying HTTP library.\n\nFor example, the following will use a JDK client configured with a specific javadoc:java.net.ProxySelector[]:\n\ninclude-code::MyClientHttpConfiguration[]\n\n\n\n[[io.rest-client.apiversioning]]\n== API Versioning\n\nBoth `WebClient` and `RestClient` support making versioned remote HTTP calls so that APIs can be evolved over time.\nCommonly this involves sending an HTTP header, a query parameter or URL path segment that indicates the version of the API that should be used.\n\nYou can configure API versioning using methods on `WebClient.Builder` or `RestClient.Builder`.\n\nTIP: API versioning is also supported on the server-side.\nSee the xref:web/servlet.adoc#web.servlet.spring-mvc.api-versioning[Spring MVC] and xref:web/reactive.adoc#web.reactive.webflux.api-versioning[Spring WebFlux] sections for details.\n\nNOTE: The server-side API versioning configuration is not taken into account to auto-configure the client.\nClients that should use an API versioning strategy, typically for testing, need to configure it explicitly.\n\n\n\n[[io.rest-client.httpservice]]\n== HTTP Service Interface Clients\n\nInstead of directly using a javadoc:org.springframework.web.client.RestClient[] or javadoc:org.springframework.web.reactive.function.client.WebClient[] to call an HTTP service, it's also possible to call them using annotated Java interfaces.\n\nHTTP Service interfaces defines a service contract by using methods that are annotated with javadoc:org.springframework.web.service.annotation.HttpExchange[format=annotation], or more typically the method specific variants (javadoc:org.springframework.web.service.annotation.GetExchange[format=annotation], javadoc:org.springframework.web.service.annotation.PostExchange[format=annotation], javadoc:org.springframework.web.service.annotation.DeleteExchange[format=annotation], etc).\n\nFor example, the following code defines an HTTP Service for an \"`echo`\" API that will return a JSON object containing an echo of the request.\n\ninclude-code::EchoService[]\n\nMore details about how to develop HTTP Service interface clients can be found in the {url-spring-framework-docs}/integration/rest-clients.html#rest-http-service-client[Spring Framework reference documentation].\n\n\n\n[[io.rest-client.httpservice.importing]]\n=== Importing HTTP Services\n\nIn order to use an HTTP Service interface as client you need to import it.\nOne way to achieve this is to use the javadoc:org.springframework.web.service.registry.ImportHttpServices[format=annotation] annotation, typically on your main application class.\nYou can use the annotation to import specific classes, or scan for classes to import from specific packages.\n\nFor example, the following configuration will scan for HTTP Service interfaces in the `com.example.myclients` package:\n\ninclude-code::MyApplication[]\n\n\n\n[[io.rest-client.httpservice.groups]]\n=== Service Client Groups\n\nHard-coding absolute URLs in javadoc:org.springframework.web.service.annotation.HttpExchange[format=annotation] annotations is often not ideal in production applications.\nInstead, you will typically want to give the HTTP Service client a logical name in your code, and then lookup a URL from a property based on that name.\n\nHTTP Service clients allow you to do this by registering them into named groups.\nAn HTTP Service group is a collection of HTTP Service interfaces that all share common features.\n\nFor example, we may want to define an \"`echo`\" group to use for HTTP Service clients that call `\\https://echo.zuplo.io`.\n\nNOTE: HTTP Service groups can be used to define more than just URLs.\nFor example, your group could define connection timeouts and SSL settings.\nYou can also associate client customization logic to a group, such as adding code to insert required authorization headers.\n\nTo associate an HTTP Service interface with a group when using javadoc:org.springframework.web.service.registry.ImportHttpServices[format=annotation] you can use the `group` attribute.\n\nFor example, if we assume our example above is organized in such a way that all HTTP Service interfaces in the `com.example.myclients` package belong to the `echo` group.\nWe first remove the hardcoded URL from the service interface:\n\ninclude-code::EchoService[]\n\nWe can then write:\n\ninclude-code::MyApplication[]\n\nAnd finally we can then use a `base-url` property to link the `echo` group to an actual URL:\n\n[configprops,yaml]\n----\nspring:\n  http:\n    serviceclient:\n      echo:\n        base-url: \"https://echo.zuplo.io\"\n----\n\nTIP: HTTP Service clients will be associated with a group named \"`default`\" if you don't specify a group.\n\n[NOTE]\n====\nIf you have multiple HTTP Service interfaces in the same package that need to be associated with different groups you can list them individually.\nThe javadoc:org.springframework.web.service.registry.ImportHttpServices[format=annotation] is repeatable and the `types` attributes allows you to import individual classes.\n\nFor example:\n\ninclude-code::repeat/MyApplication[]\n====\n\n\n\n[[io.rest-client.httpservice.properties]]\n=== Configuration Properties\n\nConfiguration properties for HTTP Services can be specified under `spring.http.serviceclient.<group-name>`:\n\nYou can use properties to configure aspects such as:\n\n* The base URL.\n* Any default headers that should be sent.\n* API versioning configuration.\n* Redirect settings.\n* Connection and read timeouts.\n* SSL bundles to use.\n\nTIP: You can also use xref:io/rest-client.adoc#io.rest-client.global-configuration[global configuration properties] which apply to all HTTP clients.\n\nFor example, the properties below will:\n\n* Configure all HTTP clients to use a one second connect timeout (unless otherwise overridden).\n* Configure HTTP Service clients in the \"`echo`\" group to:\n** Use a specific base URL.\n** Have a two second read timeout.\n** Insert API version information using an `X-Version` header.\n\n[configprops,yaml]\n----\nspring:\n  http:\n    clients:\n      connect-timeout: 1s\n    serviceclient:\n      echo:\n        base-url: \"https://echo.zuplo.io\"\n        read-timeout: 2s\n        apiversion:\n          default: 1.0.0\n          insert:\n            header: X-Version\n----\n\n\n\n[[io.rest-client.httpservice.customization]]\n=== Customization\n\nIf you need to customize HTTP Service clients beyond basic properties, you can use an HTTP Service group configurer.\nFor `RestClient` backed HTTP Service clients, you can declare a bean that implements javadoc:org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer[].\nFor `WebClient` backed HTTP Service clients you can declare a bean that implements javadoc:org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer[].\n\nBoth work in the same way and will be automatically applied by Spring Boot's auto-configuration.\n\nFor example, the following configuration would add a group customizer that adds an HTTP header to each outgoing request containing the group name:\n\ninclude-code::MyHttpServiceGroupConfiguration[]\n\n\n\n[[io.rest-client.httpservice.advanced-configuration]]\n=== Advanced Configuration\n\nAs well as the javadoc:org.springframework.web.service.registry.ImportHttpServices[format=annotation] annotation, Spring Framework also offers an javadoc:org.springframework.web.service.registry.AbstractHttpServiceRegistrar[] class.\nYou can javadoc:org.springframework.context.annotation.Import[format=annotation] your own extension of this class to perform programmatic configuration.\nFor more details, see {url-spring-framework-docs}/integration/rest-clients.html#rest-http-service-client-group-config[Spring Framework reference documentation].\n\nRegardless of which method you use to register HTTP Service clients, Spring Boot's support remains the same.\n\n\n\n[[io.rest-client.global-configuration]]\n== Applying Global Configuration to All HTTP Clients\n\nRegardless of the underlying technology being used, all HTTP clients have common settings that can be configured.\n\nThese include:\n\n* Connection Timeouts.\n* Read Timeouts.\n* How HTTP redirects should be handled.\n* Which SSL bundle should be used when connecting.\n\nThese common settings are represented by the javadoc:org.springframework.boot.http.client.HttpClientSettings[] class which can be passed into the `build(...)` methods of javadoc:org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder[] and javadoc:org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder[].\n\nIf you want to apply the same configuration to all auto-configured clients, you can use `spring.http.clients` properties to do so:\n\n[configprops,yaml]\n----\nspring:\n  http:\n    clients:\n      connect-timeout: 2s\n      read-timeout: 1s\n      redirects: dont-follow\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/spring-batch.adoc",
    "content": "[[io.spring-batch]]\n= Spring Batch\n\nSpring Boot offers several conveniences for working with {url-spring-batch-site}[Spring Batch], including running a Job on startup.\n\nWhen building a batch application, the following stores can be auto-configured:\n\n* In-memory\n* JDBC\n* MongoDB\n\nEach store has specific additional settings.\nFor instance, it is possible to customize the tables prefix for the JDBC store, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  batch:\n    jdbc:\n      table-prefix: \"CUSTOM_\"\n----\n\nWhen using the MongoDB store, you can enable initialization of the Spring Batch job repository schema (collections and indexes):\n\n[configprops,yaml]\n----\nspring:\n  batch:\n    data:\n      mongodb:\n        schema:\n          initialize: true\n----\n\nTo disable Spring Boot's auto-configuration and take complete control of Spring Batch's configuration, add javadoc:org.springframework.batch.core.configuration.annotation.EnableBatchProcessing[format=annotation] to one of your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes or extend javadoc:org.springframework.batch.core.configuration.support.DefaultBatchConfiguration[].\nThis will cause the auto-configuration to back off, including initialization of Spring Batch's database schema (JDBC or MongoDB).\nSpring Batch can then be configured using the `@Enable*JobRepository` annotation's attributes rather than the previously described configuration properties.\n\nTo learn more about manually configuring Spring Batch, see the API documentation of:\n\n* javadoc:org.springframework.batch.core.configuration.support.DefaultBatchConfiguration[]\n* javadoc:org.springframework.batch.core.configuration.annotation.EnableBatchProcessing[format=annotation]\n* javadoc:org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository[format=annotation]\n* javadoc:org.springframework.batch.core.configuration.annotation.EnableMongoJobRepository[format=annotation]\n\nFor more information about Spring Batch, see the {url-spring-batch-site}[Spring Batch project page].\n\n\n\n[[io.spring-batch.running-jobs-on-startup]]\n== Running Spring Batch Jobs on Startup\n\nWhen Spring Boot auto-configures Spring Batch, and if a single javadoc:org.springframework.batch.core.job.Job[] bean is found in the application context, it is executed on startup (see javadoc:org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner[] for details).\nIf multiple javadoc:org.springframework.batch.core.job.Job[] beans are found, the job that should be executed must be specified using configprop:spring.batch.job.name[].\n\nYou can disable running a javadoc:org.springframework.batch.core.job.Job[] found in the application context, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  batch:\n    job:\n      enabled: false\n----\n\nSee {code-spring-boot-batch-src}/autoconfigure/BatchAutoConfiguration.java[`BatchAutoConfiguration`], {code-spring-boot-batch-jdbc-src}/autoconfigure/BatchJdbcAutoConfiguration.java[`BatchJdbcAutoConfiguration`], and {code-spring-boot-batch-data-mongodb-src}/autoconfigure/BatchDataMongoAutoConfiguration.java[`BatchDataMongoAutoConfiguration`] for more details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/validation.adoc",
    "content": "[[io.validation]]\n= Validation\n\nThe method validation feature supported by Bean Validation 1.1 is automatically enabled as long as a JSR-303 implementation (such as Hibernate validator) is on the classpath.\nThis lets bean methods be annotated with `jakarta.validation` constraints on their parameters and/or on their return value.\nTarget classes with such annotated methods need to be annotated with the javadoc:org.springframework.validation.annotation.Validated[format=annotation] annotation at the type level for their methods to be searched for inline constraint annotations.\n\nFor instance, the following service triggers the validation of the first argument, making sure its size is between 8 and 10:\n\ninclude-code::MyBean[]\n\nThe application's javadoc:org.springframework.context.MessageSource[] is used when resolving `+{parameters}+` in constraint messages.\nThis allows you to use xref:features/internationalization.adoc[your application's `messages.properties` files] for Bean Validation messages.\nOnce the parameters have been resolved, message interpolation is completed using Bean Validation's default interpolator.\n\nTo customize the javadoc:jakarta.validation.Configuration[] used to build the javadoc:jakarta.validation.ValidatorFactory[], define a javadoc:org.springframework.boot.validation.autoconfigure.ValidationConfigurationCustomizer[] bean.\nWhen multiple customizer beans are defined, they are called in order based on their javadoc:org.springframework.core.annotation.Order[format=annotation] annotation or javadoc:org.springframework.core.Ordered[] implementation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/io/webservices.adoc",
    "content": "[[io.webservices]]\n= Web Services\n\nSpring Boot provides Web Services auto-configuration so that all you must do is define your javadoc:org.springframework.ws.server.endpoint.annotation.Endpoint[format=annotation] beans.\n\nThe {url-spring-webservices-docs}[Spring Web Services features] can be easily accessed with the `spring-boot-starter-webservices` module.\n\njavadoc:org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition[] and javadoc:org.springframework.xml.xsd.SimpleXsdSchema[] beans can be automatically created for your WSDLs and XSDs respectively.\nTo do so, configure their location, as shown in the following example:\n\n\n[configprops,yaml]\n----\nspring:\n  webservices:\n    wsdl-locations: \"classpath:/wsdl\"\n----\n\n\n\n[[io.webservices.template]]\n== Calling Web Services with WebServiceTemplate\n\nIf you need to call remote Web services from your application, you can use the {url-spring-webservices-docs}#client-web-service-template[`WebServiceTemplate`] class.\nSince javadoc:org.springframework.ws.client.core.WebServiceTemplate[] instances often need to be customized before being used, Spring Boot does not provide any single auto-configured javadoc:org.springframework.ws.client.core.WebServiceTemplate[] bean.\nIt does, however, auto-configure a javadoc:org.springframework.boot.webservices.client.WebServiceTemplateBuilder[], which can be used to create javadoc:org.springframework.ws.client.core.WebServiceTemplate[] instances when needed.\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n\nBy default, javadoc:org.springframework.boot.webservices.client.WebServiceTemplateBuilder[] detects a suitable HTTP-based javadoc:org.springframework.ws.transport.WebServiceMessageSender[] using the available HTTP client libraries on the classpath.\nYou can also customize read and connection timeouts for an individual builder as follows:\n\ninclude-code::MyWebServiceTemplateConfiguration[]\n\nTIP: You can also change the xref:io/rest-client.adoc#io.rest-client.clienthttprequestfactory.configuration[global HTTP client configuration] used if not specific template customization code is applied.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/amqp.adoc",
    "content": "[[messaging.amqp]]\n= AMQP\n\nThe Advanced Message Queuing Protocol (AMQP) is a platform-neutral, wire-level protocol for message-oriented middleware.\nThe Spring AMQP project applies core Spring concepts to the development of AMQP-based messaging solutions.\nSpring Boot offers several conveniences for working with AMQP through RabbitMQ, including the `spring-boot-starter-amqp` starter.\n\n\n\n[[messaging.amqp.rabbitmq]]\n== RabbitMQ Support\n\nhttps://www.rabbitmq.com/[RabbitMQ] is a lightweight, reliable, scalable, and portable message broker based on the AMQP protocol.\nSpring uses RabbitMQ to communicate through the AMQP protocol.\n\nRabbitMQ configuration is controlled by external configuration properties in `+spring.rabbitmq.*+`.\nFor example, you might declare the following section in `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  rabbitmq:\n    host: \"localhost\"\n    port: 5672\n    username: \"admin\"\n    password: \"secret\"\n----\n\nAlternatively, you could configure the same connection using the `addresses` attribute:\n\n[configprops,yaml]\n----\nspring:\n  rabbitmq:\n    addresses: \"amqp://admin:secret@localhost\"\n----\n\nNOTE: When specifying addresses that way, the `host` and `port` properties are ignored.\nIf the address uses the `amqps` protocol, SSL support is enabled automatically.\n\nSee javadoc:org.springframework.boot.amqp.autoconfigure.RabbitProperties[] for more of the supported property-based configuration options.\nTo configure lower-level details of the RabbitMQ javadoc:com.rabbitmq.client.ConnectionFactory[] that is used by Spring AMQP, define a javadoc:org.springframework.boot.amqp.autoconfigure.ConnectionFactoryCustomizer[] bean.\n\nIf a javadoc:org.springframework.amqp.rabbit.connection.ConnectionNameStrategy[] bean exists in the context, it will be automatically used to name connections created by the auto-configured javadoc:org.springframework.amqp.rabbit.connection.CachingConnectionFactory[].\n\nTo make an application-wide, additive customization to the javadoc:org.springframework.amqp.rabbit.core.RabbitTemplate[], use a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitTemplateCustomizer[] bean.\n\nTIP: See https://spring.io/blog/2010/06/14/understanding-amqp-the-protocol-used-by-rabbitmq/[Understanding AMQP, the protocol used by RabbitMQ] for more details.\n\n\n\n[[messaging.amqp.sending]]\n== Sending a Message\n\nSpring's javadoc:org.springframework.amqp.core.AmqpTemplate[] and javadoc:org.springframework.amqp.core.AmqpAdmin[] are auto-configured, and you can autowire them directly into your own beans, as shown in the following example:\n\ninclude-code::MyBean[]\n\nNOTE: javadoc:org.springframework.amqp.rabbit.core.RabbitMessagingTemplate[] can be injected in a similar manner.\nIf a javadoc:org.springframework.amqp.support.converter.MessageConverter[] bean is defined, it is associated automatically to the auto-configured javadoc:org.springframework.amqp.core.AmqpTemplate[].\n\nIf necessary, any javadoc:org.springframework.amqp.core.Queue[] that is defined as a bean is automatically used to declare a corresponding queue on the RabbitMQ instance.\n\nTo retry operations, you can enable retries on the javadoc:org.springframework.amqp.core.AmqpTemplate[] (for example, in the event that the broker connection is lost):\n\n[configprops,yaml]\n----\nspring:\n  rabbitmq:\n    template:\n      retry:\n        enabled: true\n        initial-interval: \"2s\"\n----\n\nRetries are disabled by default.\nYou can also customize the javadoc:org.springframework.core.retry.RetryTemplate[] programmatically by declaring a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitTemplateRetrySettingsCustomizer[] bean.\n\nIf you need to create more javadoc:org.springframework.amqp.rabbit.core.RabbitTemplate[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitTemplateConfigurer[] bean that you can use to initialize a javadoc:org.springframework.amqp.rabbit.core.RabbitTemplate[] with the same settings as the factories used by the auto-configuration.\n\nIf there's a bean of type javadoc:org.springframework.amqp.rabbit.support.micrometer.RabbitTemplateObservationConvention[] in the context, it will automatically be configured on the javadoc:org.springframework.amqp.rabbit.core.RabbitTemplate[].\n\n\n\n[[messaging.amqp.sending-stream]]\n== Sending a Message To A Stream\n\nTo send a message to a particular stream, specify the name of the stream, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  rabbitmq:\n    stream:\n      name: \"my-stream\"\n----\n\nIf a javadoc:org.springframework.amqp.support.converter.MessageConverter[], javadoc:org.springframework.rabbit.stream.support.converter.StreamMessageConverter[], javadoc:org.springframework.rabbit.stream.producer.ProducerCustomizer[] or javadoc:org.springframework.rabbit.stream.micrometer.RabbitStreamTemplateObservationConvention[] bean is defined, it is associated automatically to the auto-configured javadoc:org.springframework.rabbit.stream.producer.RabbitStreamTemplate[].\n\nIf you need to create more javadoc:org.springframework.rabbit.stream.producer.RabbitStreamTemplate[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamTemplateConfigurer[] bean that you can use to initialize a javadoc:org.springframework.rabbit.stream.producer.RabbitStreamTemplate[] with the same settings as the factories used by the auto-configuration.\n\n\n\n[[messaging.amqp.sending-stream.ssl]]\n=== SSL\nTo use SSL with RabbitMQ Streams, set configprop:spring.rabbitmq.stream.ssl.enabled[] to `true` or set configprop:spring.rabbitmq.stream.ssl.bundle[] to configure the xref:features/ssl.adoc#features.ssl.bundles[SSL bundle] to use.\n\n\n\n[[messaging.amqp.receiving]]\n== Receiving a Message\n\nWhen the Rabbit infrastructure is present, any bean can be annotated with javadoc:org.springframework.amqp.rabbit.annotation.RabbitListener[format=annotation] to create a listener endpoint.\nIf no javadoc:org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory[] has been defined, a default javadoc:org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory[] is automatically configured and you can switch to a direct container using the configprop:spring.rabbitmq.listener.type[] property.\nIf a javadoc:org.springframework.amqp.support.converter.MessageConverter[], a javadoc:org.springframework.amqp.rabbit.retry.MessageRecoverer[] or a javadoc:org.springframework.amqp.rabbit.support.micrometer.RabbitListenerObservationConvention[] bean is defined, it is automatically associated with the default factory.\n\nThe following sample component creates a listener endpoint on the `someQueue` queue:\n\ninclude-code::MyBean[]\n\nTIP: See javadoc:org.springframework.amqp.rabbit.annotation.EnableRabbit[format=annotation] for more details.\n\nIf you need to create more javadoc:org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.amqp.autoconfigure.SimpleRabbitListenerContainerFactoryConfigurer[] and a javadoc:org.springframework.boot.amqp.autoconfigure.DirectRabbitListenerContainerFactoryConfigurer[] that you can use to initialize a javadoc:org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory[] and a javadoc:org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory[] with the same settings as the factories used by the auto-configuration.\n\nTIP: It does not matter which container type you chose.\nThose two beans are exposed by the auto-configuration.\n\nFor instance, the following configuration class exposes another factory that uses a specific javadoc:org.springframework.amqp.support.converter.MessageConverter[]:\n\ninclude-code::custom/MyRabbitConfiguration[]\n\nThen you can use the factory in any javadoc:org.springframework.amqp.rabbit.annotation.RabbitListener[format=annotation]-annotated method, as follows:\n\ninclude-code::custom/MyBean[]\n\nYou can enable retries to handle situations where your listener throws an exception.\nBy default, javadoc:org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer[] is used, but you can define a javadoc:org.springframework.amqp.rabbit.retry.MessageRecoverer[] of your own.\nWhen retries are exhausted, the message is rejected and either dropped or routed to a dead-letter exchange if the broker is configured to do so.\nBy default, retries are disabled.\nYou can also customize the javadoc:org.springframework.core.retry.RetryPolicy[] programmatically by declaring a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitListenerRetrySettingsCustomizer[] bean.\n\nIMPORTANT: By default, if retries are disabled and the listener throws an exception, the delivery is retried indefinitely.\nYou can modify this behavior in two ways: Set the `defaultRequeueRejected` property to `false` so that zero re-deliveries are attempted or throw an javadoc:org.springframework.amqp.AmqpRejectAndDontRequeueException[] to signal the message should be rejected.\nThe latter is the mechanism used when retries are enabled and the maximum number of delivery attempts is reached.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/index.adoc",
    "content": "[[messaging]]\n= Messaging\n\nThe Spring Framework provides extensive support for integrating with messaging systems, from simplified use of the JMS API using javadoc:org.springframework.jms.core.JmsClient[] to a complete infrastructure to receive messages asynchronously.\nSpring AMQP provides a similar feature set for the Advanced Message Queuing Protocol.\nSpring Boot also provides auto-configuration options for javadoc:org.springframework.amqp.rabbit.core.RabbitTemplate[] and RabbitMQ.\nSpring WebSocket natively includes support for STOMP messaging, and Spring Boot has support for that through starters and a small amount of auto-configuration.\nSpring Boot also has support for Apache Kafka and Apache Pulsar.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/jms.adoc",
    "content": "[[messaging.jms]]\n= JMS\n\nThe javadoc:jakarta.jms.ConnectionFactory[] interface provides a standard method of creating a javadoc:jakarta.jms.Connection[] for interacting with a JMS broker.\nAlthough Spring needs a javadoc:jakarta.jms.ConnectionFactory[] to work with JMS, you generally need not use it directly yourself and can instead rely on higher level messaging abstractions.\n(See the {url-spring-framework-docs}/integration/jms.html[relevant section] of the Spring Framework reference documentation for details.)\nSpring Boot also auto-configures the necessary infrastructure to send and receive messages.\n\n\n\n[[messaging.jms.activemq]]\n== ActiveMQ \"Classic\" Support\n\nWhen https://activemq.apache.org/components/classic[ActiveMQ \"Classic\"] is available on the classpath, Spring Boot can configure a javadoc:jakarta.jms.ConnectionFactory[].\nIf the broker is present, an embedded broker is automatically started and configured (provided no broker URL is specified through configuration and the embedded broker is not disabled in the configuration).\n\nNOTE: If you use `spring-boot-starter-activemq`, the necessary dependencies to connect to an ActiveMQ \"Classic\" instance are provided, as is the Spring infrastructure to integrate with JMS.\nAdding `org.apache.activemq:activemq-broker` to your application lets you use the embedded broker.\n\nActiveMQ \"Classic\" configuration is controlled by external configuration properties in `+spring.activemq.*+`.\n\nIf `activemq-broker` is on the classpath, ActiveMQ \"Classic\" is auto-configured to use the https://activemq.apache.org/vm-transport-reference.html[VM transport], which starts a broker embedded in the same JVM instance.\n\nYou can disable the embedded broker by configuring the configprop:spring.activemq.embedded.enabled[] property, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  activemq:\n    embedded:\n      enabled: false\n----\n\nThe embedded broker will also be disabled if you configure the broker URL, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  activemq:\n    broker-url: \"tcp://192.168.1.210:9876\"\n    user: \"admin\"\n    password: \"secret\"\n----\n\nIf you want to take full control over the embedded broker, see https://activemq.apache.org/how-do-i-embed-a-broker-inside-a-connection.html[the ActiveMQ \"Classic\" documentation] for further information.\n\nBy default, a javadoc:org.springframework.jms.connection.CachingConnectionFactory[] wraps the native javadoc:jakarta.jms.ConnectionFactory[] with sensible settings that you can control by external configuration properties in `+spring.jms.*+`:\n\n[configprops,yaml]\n----\nspring:\n  jms:\n    cache:\n      session-cache-size: 5\n----\n\nIf you'd rather use native pooling, you can do so by adding a dependency to `org.messaginghub:pooled-jms` and configuring the javadoc:org.messaginghub.pooled.jms.JmsPoolConnectionFactory[] accordingly, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  activemq:\n    pool:\n      enabled: true\n      max-connections: 50\n----\n\nTIP: See javadoc:org.springframework.boot.activemq.autoconfigure.ActiveMQProperties[] for more of the supported options.\nYou can also register an arbitrary number of beans that implement javadoc:org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionFactoryCustomizer[] for more advanced customizations.\n\nBy default, ActiveMQ \"Classic\" creates a destination if it does not yet exist so that destinations are resolved against their provided names.\n\n\n\n[[messaging.jms.artemis]]\n== ActiveMQ Artemis Support\n\nSpring Boot can auto-configure a javadoc:jakarta.jms.ConnectionFactory[] when it detects that https://activemq.apache.org/components/artemis/[ActiveMQ Artemis] is available on the classpath.\nIf the broker is present, an embedded broker is automatically started and configured (unless the mode property has been explicitly set).\nThe supported modes are `embedded` (to make explicit that an embedded broker is required and that an error should occur if the broker is not available on the classpath) and `native` (to connect to a broker using the `netty` transport protocol).\nWhen the latter is configured, Spring Boot configures a javadoc:jakarta.jms.ConnectionFactory[] that connects to a broker running on the local machine with the default settings.\n\nNOTE: If you use `spring-boot-starter-artemis`, the necessary dependencies to connect to an existing ActiveMQ Artemis instance are provided, as well as the Spring infrastructure to integrate with JMS.\nAdding `org.apache.activemq:artemis-jakarta-server` to your application lets you use embedded mode.\n\nActiveMQ Artemis configuration is controlled by external configuration properties in `+spring.artemis.*+`.\nFor example, you might declare the following section in `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  artemis:\n    mode: native\n    broker-url: \"tcp://192.168.1.210:9876\"\n    user: \"admin\"\n    password: \"secret\"\n----\n\nWhen embedding the broker, you can choose if you want to enable persistence and list the destinations that should be made available.\nThese can be specified as a comma-separated list to create them with the default options, or you can define bean(s) of type javadoc:org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration[] or javadoc:org.apache.activemq.artemis.jms.server.config.TopicConfiguration[], for advanced queue and topic configurations, respectively.\n\nBy default, a javadoc:org.springframework.jms.connection.CachingConnectionFactory[] wraps the native javadoc:jakarta.jms.ConnectionFactory[] with sensible settings that you can control by external configuration properties in `+spring.jms.*+`:\n\n[configprops,yaml]\n----\nspring:\n  jms:\n    cache:\n      session-cache-size: 5\n----\n\nIf you'd rather use native pooling, you can do so by adding a dependency on `org.messaginghub:pooled-jms` and configuring the javadoc:org.messaginghub.pooled.jms.JmsPoolConnectionFactory[] accordingly, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  artemis:\n    pool:\n      enabled: true\n      max-connections: 50\n----\n\nSee javadoc:org.springframework.boot.artemis.autoconfigure.ArtemisProperties[] for more supported options.\n\nNo JNDI lookup is involved, and destinations are resolved against their names, using either the `name` attribute in the ActiveMQ Artemis configuration or the names provided through configuration.\n\n\n\n[[messaging.jms.jndi]]\n== Using a JNDI ConnectionFactory\n\nIf you are running your application in an application server, Spring Boot tries to locate a JMS javadoc:jakarta.jms.ConnectionFactory[] by using JNDI.\nBy default, the `java:/JmsXA` and `java:/XAConnectionFactory` location are checked.\nYou can use the configprop:spring.jms.jndi-name[] property if you need to specify an alternative location, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  jms:\n    jndi-name: \"java:/MyConnectionFactory\"\n----\n\n\n\n[[messaging.jms.sending]]\n== Sending a Message\n\nSpring's javadoc:org.springframework.jms.core.JmsClient[] is auto-configured, and you can autowire it directly into your own beans, as shown in the following example:\n\ninclude-code::MyBean[]\n\nNOTE: javadoc:org.springframework.jms.core.JmsMessagingTemplate[] can be injected in a similar manner, and both use the traditional javadoc:org.springframework.jms.core.JmsTemplate[] that can be injected as well.\nIf a javadoc:org.springframework.jms.support.destination.DestinationResolver[] or a javadoc:org.springframework.jms.support.converter.MessageConverter[] bean is defined, it is associated automatically to the auto-configured javadoc:org.springframework.jms.core.JmsTemplate[].\n\n\n\n[[messaging.jms.receiving]]\n== Receiving a Message\n\nWhen the JMS infrastructure is present, any bean can be annotated with javadoc:org.springframework.jms.annotation.JmsListener[format=annotation] to create a listener endpoint.\nIf no javadoc:org.springframework.jms.config.JmsListenerContainerFactory[] has been defined, a default one is configured automatically.\nIf a javadoc:org.springframework.jms.support.destination.DestinationResolver[], a javadoc:org.springframework.jms.support.converter.MessageConverter[], or a javadoc:jakarta.jms.ExceptionListener[] beans are defined, they are associated automatically with the default factory.\n\nIn most scenarios, message listener containers should be configured against the native javadoc:jakarta.jms.ConnectionFactory[].\nThis way each listener container has its own connection and this gives full responsibility to it in terms of local recovery.\nThe auto-configuration uses javadoc:org.springframework.boot.jms.ConnectionFactoryUnwrapper[] to unwrap the native connection factory from the auto-configured one.\n\nNOTE: The auto-configuration only unwraps `CachedConnectionFactory`.\n\nBy default, the default factory is transactional.\nIf you run in an infrastructure where a javadoc:org.springframework.transaction.jta.JtaTransactionManager[] is present, it is associated to the listener container by default.\nIf not, the `sessionTransacted` flag is enabled.\nIn that latter scenario, you can associate your local data store transaction to the processing of an incoming message by adding javadoc:org.springframework.transaction.annotation.Transactional[format=annotation] on your listener method (or a delegate thereof).\nThis ensures that the incoming message is acknowledged, once the local transaction has completed.\nThis also includes sending response messages that have been performed on the same JMS session.\n\nThe following component creates a listener endpoint on the `someQueue` destination:\n\ninclude-code::MyBean[]\n\nTIP: See the javadoc:org.springframework.jms.annotation.EnableJms[format=annotation] API documentation for more details.\n\nIf you need to create more javadoc:org.springframework.jms.config.JmsListenerContainerFactory[] instances or if you want to override the default, Spring Boot provides a javadoc:org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer[] that you can use to initialize a javadoc:org.springframework.jms.config.DefaultJmsListenerContainerFactory[] with the same settings as the one that is auto-configured.\n\nFor instance, the following example exposes another factory that uses a specific javadoc:org.springframework.jms.support.converter.MessageConverter[]:\n\ninclude-code::custom/MyJmsConfiguration[]\n\nNOTE: In the example above, the customization uses javadoc:org.springframework.boot.jms.ConnectionFactoryUnwrapper[] to associate the native connection factory to the message listener container the same way the auto-configured factory does.\n\nThen you can use the factory in any javadoc:org.springframework.jms.annotation.JmsListener[format=annotation]-annotated method as follows:\n\ninclude-code::custom/MyBean[]\n\nAnalogous to `DefaultJmsListenerContainerFactoryConfigurer`, Spring Boot also provides a javadoc:org.springframework.boot.jms.autoconfigure.SimpleJmsListenerContainerFactoryConfigurer[] that you can use to initialize a javadoc:org.springframework.jms.config.SimpleJmsListenerContainerFactory[] and apply the related settings that auto-configuration provides.\n\nTIP: In contrast to javadoc:org.springframework.jms.listener.DefaultMessageListenerContainer[] that uses a pull-based mechanism (polling) to process messages, javadoc:org.springframework.jms.listener.SimpleMessageListenerContainer[] uses a push-based mechanism that's very close to the spirit of the standalone JMS specification.\nTo learn more about the differences between the two listener containers, consult their respective javadocs and {url-spring-framework-docs}/integration/jms/using.html#jms-mdp[Spring Framework reference documentation].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/kafka.adoc",
    "content": "[[messaging.kafka]]\n= Apache Kafka Support\n\nhttps://kafka.apache.org/[Apache Kafka] is supported by providing auto-configuration of the `spring-kafka` project.\n\nKafka configuration is controlled by external configuration properties in `spring.kafka.*`.\nFor example, you might declare the following section in `application.properties`:\n\n[configprops,yaml]\n----\nspring:\n  kafka:\n    bootstrap-servers: \"localhost:9092\"\n    consumer:\n      group-id: \"myGroup\"\n----\n\nTIP: To create a topic on startup, add a bean of type javadoc:org.apache.kafka.clients.admin.NewTopic[].\nIf the topic already exists, the bean is ignored.\n\nSee javadoc:org.springframework.boot.kafka.autoconfigure.KafkaProperties[] for more supported options.\n\n\n\n[[messaging.kafka.sending]]\n== Sending a Message\n\nSpring's javadoc:org.springframework.kafka.core.KafkaTemplate[] is auto-configured, and you can autowire it directly in your own beans, as shown in the following example:\n\ninclude-code::MyBean[]\n\nNOTE: If the property configprop:spring.kafka.producer.transaction-id-prefix[] is defined, a javadoc:org.springframework.kafka.transaction.KafkaTransactionManager[] is automatically configured.\nAlso, if a javadoc:org.springframework.kafka.support.converter.RecordMessageConverter[] bean is defined, it is automatically associated to the auto-configured javadoc:org.springframework.kafka.core.KafkaTemplate[].\n\nIf there's a bean of type `KafkaTemplateObservationConvention` in the context, it is automatically registered on the `KafkaTemplate`.\n\n\n\n[[messaging.kafka.receiving]]\n== Receiving a Message\n\nWhen the Apache Kafka infrastructure is present, any bean can be annotated with javadoc:org.springframework.kafka.annotation.KafkaListener[format=annotation] to create a listener endpoint.\nIf no javadoc:org.springframework.kafka.config.KafkaListenerContainerFactory[] has been defined, a default one is automatically configured with keys defined in `spring.kafka.listener.*`.\n\nThe following component creates a listener endpoint on the `someTopic` topic:\n\ninclude-code::MyBean[]\n\nIf a javadoc:org.springframework.kafka.transaction.KafkaTransactionManager[] bean is defined, it is automatically associated to the container factory.\nSimilarly, if a javadoc:org.springframework.kafka.listener.adapter.RecordFilterStrategy[], javadoc:org.springframework.kafka.listener.CommonErrorHandler[], javadoc:org.springframework.kafka.listener.AfterRollbackProcessor[] or javadoc:org.springframework.kafka.listener.ConsumerAwareRebalanceListener[] bean is defined, it is automatically associated to the default factory.\n\nDepending on the listener type, a javadoc:org.springframework.kafka.support.converter.RecordMessageConverter[] or javadoc:org.springframework.kafka.support.converter.BatchMessageConverter[] bean is associated to the default factory.\nIf only a javadoc:org.springframework.kafka.support.converter.RecordMessageConverter[] bean is present for a batch listener, it is wrapped in a javadoc:org.springframework.kafka.support.converter.BatchMessageConverter[].\n\nTIP: A custom javadoc:org.springframework.kafka.transaction.ChainedKafkaTransactionManager[] must be marked javadoc:org.springframework.context.annotation.Primary[format=annotation] as it usually references the auto-configured javadoc:org.springframework.kafka.transaction.KafkaTransactionManager[] bean.\n\nIf there's a bean of type `KafkaListenerObservationConvention` in the context, it is automatically registered on the container factory.\n\n\n\n[[messaging.kafka.streams]]\n== Kafka Streams\n\nSpring for Apache Kafka provides a factory bean to create a javadoc:org.apache.kafka.streams.StreamsBuilder[] object and manage the lifecycle of its streams.\nSpring Boot auto-configures the required javadoc:org.springframework.kafka.config.KafkaStreamsConfiguration[] bean as long as `kafka-streams` is on the classpath and Kafka Streams is enabled by the javadoc:org.springframework.kafka.annotation.EnableKafkaStreams[format=annotation] annotation.\n\nEnabling Kafka Streams means that the application id and bootstrap servers must be set.\nThe former can be configured using `spring.kafka.streams.application-id`, defaulting to `spring.application.name` if not set.\nThe latter can be set globally or specifically overridden only for streams.\n\nSeveral additional properties are available using dedicated properties; other arbitrary Kafka properties can be set using the `spring.kafka.streams.properties` namespace.\nSee also xref:messaging/kafka.adoc#messaging.kafka.additional-properties[] for more information.\n\nTo use the factory bean, wire javadoc:org.apache.kafka.streams.StreamsBuilder[] into your javadoc:org.springframework.context.annotation.Bean[format=annotation] as shown in the following example:\n\ninclude-code::MyKafkaStreamsConfiguration[]\n\nBy default, the streams managed by the javadoc:org.apache.kafka.streams.StreamsBuilder[] object are started automatically.\nYou can customize this behavior using the configprop:spring.kafka.streams.auto-startup[] property.\n\nTIP: You can also register an arbitrary number of beans that implement javadoc:org.springframework.kafka.config.StreamsBuilderFactoryBeanConfigurer[] for more advanced customizations.\n\n\n\n[[messaging.kafka.additional-properties]]\n== Additional Kafka Properties\n\nThe properties supported by auto configuration are shown in the xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[Integration Properties] section of the Appendix.\nNote that, for the most part, these properties (hyphenated or camelCase) map directly to the Apache Kafka dotted properties.\nSee the Apache Kafka documentation for details.\n\nProperties that don't include a client type (`producer`, `consumer`, `admin`, or `streams`) in their name are considered to be common and apply to all clients.\nMost of these common properties can be overridden for one or more of the client types, if needed.\n\nApache Kafka designates properties with an importance of HIGH, MEDIUM, or LOW.\nSpring Boot auto-configuration supports all HIGH importance properties, some selected MEDIUM and LOW properties, and any properties that do not have a default value.\n\nOnly a subset of the properties supported by Kafka are available directly through the javadoc:org.springframework.boot.kafka.autoconfigure.KafkaProperties[] class.\nIf you wish to configure the individual client types with additional properties that are not directly supported, use the following properties:\n\n[configprops,yaml]\n----\nspring:\n  kafka:\n    properties:\n      \"[prop.one]\": \"first\"\n    admin:\n      properties:\n        \"[prop.two]\": \"second\"\n    consumer:\n      properties:\n        \"[prop.three]\": \"third\"\n    producer:\n      properties:\n        \"[prop.four]\": \"fourth\"\n    streams:\n      properties:\n        \"[prop.five]\": \"fifth\"\n----\n\nThis sets the common `prop.one` Kafka property to `first` (applies to producers, consumers, admins, and streams), the `prop.two` admin property to `second`, the `prop.three` consumer property to `third`, the `prop.four` producer property to `fourth` and the `prop.five` streams property to `fifth`.\n\nYou can also configure the Spring Kafka javadoc:org.springframework.kafka.support.serializer.JacksonJsonDeserializer[] as follows:\n\n[configprops,yaml]\n----\nspring:\n  kafka:\n    consumer:\n      value-deserializer: \"org.springframework.kafka.support.serializer.JacksonJsonDeserializer\"\n      properties:\n        \"[spring.json.value.default.type]\": \"com.example.Invoice\"\n        \"[spring.json.trusted.packages]\": \"com.example.main,com.example.another\"\n----\n\nSimilarly, you can disable the javadoc:org.springframework.kafka.support.serializer.JacksonJsonSerializer[] default behavior of sending type information in headers:\n\n[configprops,yaml]\n----\nspring:\n  kafka:\n    producer:\n      value-serializer: \"org.springframework.kafka.support.serializer.JacksonJsonSerializer\"\n      properties:\n        \"[spring.json.add.type.headers]\": false\n----\n\nIMPORTANT: Properties set in this way override any configuration item that Spring Boot explicitly supports.\n\n\n\n[[messaging.kafka.embedded]]\n== Testing with Embedded Kafka\n\nSpring for Apache Kafka provides a convenient way to test projects with an embedded Apache Kafka broker.\nTo use this feature, annotate a test class with javadoc:org.springframework.kafka.test.context.EmbeddedKafka[format=annotation] from the `spring-kafka-test` module.\nFor more information, please see the Spring for Apache Kafka {url-spring-kafka-docs}/testing.html#ekb[reference manual].\n\nTo make Spring Boot auto-configuration work with the aforementioned embedded Apache Kafka broker, you need to remap a system property for embedded broker addresses (populated by the javadoc:org.springframework.kafka.test.EmbeddedKafkaBroker[]) into the Spring Boot configuration property for Apache Kafka.\nThere are several ways to do that:\n\n* Provide a system property to map embedded broker addresses into configprop:spring.kafka.bootstrap-servers[] in the test class:\n\ninclude-code::property/MyTest[tag=*]\n\n* Configure a property name on the javadoc:org.springframework.kafka.test.context.EmbeddedKafka[format=annotation] annotation:\n\ninclude-code::annotation/MyTest[]\n\n* Use a placeholder in configuration properties:\n\n[configprops,yaml]\n----\nspring:\n  kafka:\n    bootstrap-servers: \"${spring.embedded.kafka.brokers}\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/pulsar.adoc",
    "content": "[[messaging.pulsar]]\n= Apache Pulsar Support\n\nhttps://pulsar.apache.org/[Apache Pulsar] is supported by providing auto-configuration of the {url-spring-pulsar-site}[Spring for Apache Pulsar] project.\n\nSpring Boot will auto-configure and register the Spring for Apache Pulsar components when `org.springframework.pulsar:spring-pulsar` is on the classpath.\n\nThere is the `spring-boot-starter-pulsar` starter for conveniently collecting the dependencies for use.\n\n\n\n[[messaging.pulsar.connecting]]\n== Connecting to Pulsar\n\nWhen you use the Pulsar starter, Spring Boot will auto-configure and register a javadoc:org.apache.pulsar.client.api.PulsarClient[] bean.\n\nBy default, the application tries to connect to a local Pulsar instance at `pulsar://localhost:6650`.\nThis can be adjusted by setting the configprop:spring.pulsar.client.service-url[] property to a different value.\n\nNOTE: The value must be a valid https://pulsar.apache.org/docs/client-libraries-java/#connection-urls[Pulsar Protocol] URL\n\nYou can configure the client by specifying any of the `spring.pulsar.client.*` prefixed application properties.\n\nIf you need more control over the configuration, consider registering one or more javadoc:org.springframework.pulsar.core.PulsarClientBuilderCustomizer[] beans.\n\n\n\n[[messaging.pulsar.connecting.auth]]\n=== Authentication\n\nTo connect to a Pulsar cluster that requires authentication, you need to specify which authentication plugin to use by setting the `pluginClassName` and any parameters required by the plugin.\nYou can set the parameters as a map of parameter names to parameter values.\nThe following example shows how to configure the `AuthenticationOAuth2` plugin.\n\n[configprops,yaml]\n----\nspring:\n  pulsar:\n    client:\n      authentication:\n        plugin-class-name: org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2\n        param:\n          issuerUrl: https://auth.server.cloud/\n          privateKey: file:///Users/some-key.json\n          audience: urn:sn:acme:dev:my-instance\n----\n\n[NOTE]\n====\nYou need to ensure that names defined under `+spring.pulsar.client.authentication.param.*+` exactly match those expected by your auth plugin (which is typically camel cased).\nSpring Boot will not attempt any kind of relaxed binding for these entries.\n\nFor example, if you want to configure the issuer url for the `AuthenticationOAuth2` auth plugin you must use `+spring.pulsar.client.authentication.param.issuerUrl+`.\nIf you use other forms, such as `issuerurl` or `issuer-url`, the setting will not be applied to the plugin.\n\nThis lack of relaxed binding also makes using environment variables for authentication parameters problematic because the case sensitivity is lost during translation.\nIf you use environment variables for the parameters then you will need to follow {url-spring-pulsar-docs}/reference/pulsar/pulsar-client.html#client-authentication-env-vars[these steps] in the Spring for Apache Pulsar reference documentation for it to work properly.\n====\n\n\n\n[[messaging.pulsar.connecting.ssl]]\n=== SSL\n\nBy default, Pulsar clients communicate with Pulsar services in plain text.\nYou can follow {url-spring-pulsar-docs}/reference/pulsar/pulsar-client.html#tls-encryption[these steps] in the Spring for Apache Pulsar reference documentation to enable TLS encryption.\n\nFor complete details on the client and authentication see the Spring for Apache Pulsar {url-spring-pulsar-docs}/reference/pulsar/pulsar-client.html[reference documentation].\n\n\n\n[[messaging.pulsar.admin]]\n== Connecting to Pulsar Administration\n\nSpring for Apache Pulsar's javadoc:org.springframework.pulsar.core.PulsarAdministration[] client is also auto-configured.\n\nBy default, the application tries to connect to a local Pulsar instance at `\\http://localhost:8080`.\nThis can be adjusted by setting the configprop:spring.pulsar.admin.service-url[] property to a different value in the form `(http|https)://<host>:<port>`.\n\nIf you need more control over the configuration, consider registering one or more javadoc:org.springframework.pulsar.core.PulsarAdminBuilderCustomizer[] beans.\n\n\n\n[[messaging.pulsar.admin.auth]]\n=== Authentication\n\nWhen accessing a Pulsar cluster that requires authentication, the admin client requires the same security configuration as the regular Pulsar client.\nYou can use the aforementioned xref:messaging/pulsar.adoc#messaging.pulsar.connecting.auth[authentication configuration] by replacing `spring.pulsar.client.authentication` with `spring.pulsar.admin.authentication`.\n\nTIP: To create a topic on startup, add a bean of type javadoc:org.springframework.pulsar.core.PulsarTopic[].\nIf the topic already exists, the bean is ignored.\n\n\n\n[[messaging.pulsar.sending]]\n== Sending a Message\n\nSpring's javadoc:org.springframework.pulsar.core.PulsarTemplate[] is auto-configured, and you can use it to send messages, as shown in the following example:\n\ninclude-code::MyBean[]\n\nThe javadoc:org.springframework.pulsar.core.PulsarTemplate[] relies on a javadoc:org.springframework.pulsar.core.PulsarProducerFactory[] to create the underlying Pulsar producer.\nSpring Boot auto-configuration also provides this producer factory, which by default, caches the producers that it creates.\nYou can configure the producer factory and cache settings by specifying any of the `spring.pulsar.producer.\\*` and `spring.pulsar.producer.cache.*` prefixed application properties.\n\nIf you need more control over the producer factory configuration, consider registering one or more javadoc:org.springframework.pulsar.core.ProducerBuilderCustomizer[] beans.\nThese customizers are applied to all created producers.\nYou can also pass in a javadoc:org.springframework.pulsar.core.ProducerBuilderCustomizer[] when sending a message to only affect the current producer.\n\nIf you need more control over the message being sent, you can pass in a javadoc:org.springframework.pulsar.core.TypedMessageBuilderCustomizer[] when sending a message.\n\n\n\n[[messaging.pulsar.receiving]]\n== Receiving a Message\n\nWhen the Apache Pulsar infrastructure is present, any bean can be annotated with javadoc:org.springframework.pulsar.annotation.PulsarListener[format=annotation] to create a listener endpoint.\nThe following component creates a listener endpoint on the `someTopic` topic:\n\ninclude-code::MyBean[]\n\nSpring Boot auto-configuration provides all the components necessary for javadoc:org.springframework.pulsar.annotation.PulsarListener[], such as the javadoc:org.springframework.pulsar.config.PulsarListenerContainerFactory[] and the consumer factory it uses to construct the underlying Pulsar consumers.\nYou can configure these components by specifying any of the `spring.pulsar.listener.\\*` and `spring.pulsar.consumer.*` prefixed application properties.\n\nIf you need more control over the configuration of the consumer factory, consider registering one or more javadoc:org.springframework.pulsar.core.ConsumerBuilderCustomizer[] beans.\nThese customizers are applied to all consumers created by the factory, and therefore all javadoc:org.springframework.pulsar.annotation.PulsarListener[format=annotation] instances.\nYou can also customize a single listener by setting the `consumerCustomizer` attribute of the javadoc:org.springframework.pulsar.annotation.PulsarListener[format=annotation] annotation.\n\nIf you need more control over the actual container factory configuration, consider registering one or more `PulsarContainerFactoryCustomizer<ConcurrentPulsarListenerContainerFactory<?>>` beans.\n\n\n\n[[messaging.pulsar.reading]]\n== Reading a Message\n\nThe Pulsar reader interface enables applications to manually manage cursors.\nWhen you use a reader to connect to a topic you need to specify which message the reader begins reading from when it connects to a topic.\n\nWhen the Apache Pulsar infrastructure is present, any bean can be annotated with javadoc:org.springframework.pulsar.annotation.PulsarReader[format=annotation] to consume messages using a reader.\nThe following component creates a reader endpoint that starts reading messages from the beginning of the `someTopic` topic:\n\ninclude-code::MyBean[]\n\nThe javadoc:org.springframework.pulsar.annotation.PulsarReader[format=annotation] relies on a javadoc:org.springframework.pulsar.core.PulsarReaderFactory[] to create the underlying Pulsar reader.\nSpring Boot auto-configuration provides this reader factory which can be customized by setting any of the `spring.pulsar.reader.*` prefixed application properties.\n\nIf you need more control over the configuration of the reader factory, consider registering one or more javadoc:org.springframework.pulsar.core.ReaderBuilderCustomizer[] beans.\nThese customizers are applied to all readers created by the factory, and therefore all javadoc:org.springframework.pulsar.annotation.PulsarReader[format=annotation] instances.\nYou can also customize a single listener by setting the `readerCustomizer` attribute of the javadoc:org.springframework.pulsar.annotation.PulsarReader[format=annotation] annotation.\n\nIf you need more control over the actual container factory configuration, consider registering one or more `PulsarContainerFactoryCustomizer<DefaultPulsarReaderContainerFactory<?>>` beans.\n\nTIP: For more details on any of the above components and to discover other available features, see the Spring for Apache Pulsar {url-spring-pulsar-docs}[reference documentation].\n\n\n\n[[messaging.pulsar.transactions]]\n== Transaction Support\n\nSpring for Apache Pulsar supports transactions when using javadoc:org.springframework.pulsar.core.PulsarTemplate[] and javadoc:org.springframework.pulsar.annotation.PulsarListener[format=annotation].\n\nSetting the configprop:spring.pulsar.transaction.enabled[] property to `true` will:\n\n* Configure a javadoc:org.springframework.pulsar.transaction.PulsarTransactionManager[] bean\n* Enable transaction support for javadoc:org.springframework.pulsar.core.PulsarTemplate[]\n* Enable transaction support for javadoc:org.springframework.pulsar.annotation.PulsarListener[format=annotation] methods\n\nThe `transactional` attribute of javadoc:org.springframework.pulsar.annotation.PulsarListener[format=annotation] can be used to fine-tune when transactions should be used with listeners.\n\nFor more control of the Spring for Apache Pulsar transaction features you should define your own javadoc:org.springframework.pulsar.core.PulsarTemplate[] and/or javadoc:org.springframework.pulsar.config.ConcurrentPulsarListenerContainerFactory[] beans.\nYou can also define a javadoc:org.springframework.pulsar.transaction.PulsarAwareTransactionManager[] bean if the default auto-configured javadoc:org.springframework.pulsar.transaction.PulsarTransactionManager[] is not suitable.\n\n\n\n[[messaging.pulsar.additional-properties]]\n== Additional Pulsar Properties\n\nThe properties supported by auto-configuration are shown in the xref:appendix:application-properties/index.adoc#appendix.application-properties.integration[Integration Properties] section of the Appendix.\nNote that, for the most part, these properties (hyphenated or camelCase) map directly to the Apache Pulsar configuration properties.\nSee the Apache Pulsar documentation for details.\n\nOnly a subset of the properties supported by Pulsar are available directly through the javadoc:org.springframework.boot.pulsar.autoconfigure.PulsarProperties[] class.\nIf you wish to tune the auto-configured components with additional properties that are not directly supported, you can use the customizer supported by each aforementioned component.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/rsocket.adoc",
    "content": "[[messaging.rsocket]]\n= RSocket\n\nhttps://rsocket.io[RSocket] is a binary protocol for use on byte stream transports.\nIt enables symmetric interaction models through async message passing over a single connection.\n\n\nThe `spring-messaging` module of the Spring Framework provides support for RSocket requesters and responders, both on the client and on the server side.\nSee the {url-spring-framework-docs}/rsocket.html#rsocket-spring[RSocket section] of the Spring Framework reference for more details, including an overview of the RSocket protocol.\n\n\n\n[[messaging.rsocket.strategies-auto-configuration]]\n== RSocket Strategies Auto-configuration\n\nSpring Boot auto-configures an javadoc:org.springframework.messaging.rsocket.RSocketStrategies[] bean that provides all the required infrastructure for encoding and decoding RSocket payloads.\nBy default, the auto-configuration will try to configure the following (in order):\n\n. https://cbor.io/[CBOR] codecs with Jackson\n. JSON codecs with Jackson\n\nThe `spring-boot-starter-rsocket` starter provides both dependencies.\nSee the xref:features/json.adoc#features.json.jackson[Jackson support section] to know more about customization possibilities.\n\nDevelopers can customize the javadoc:org.springframework.messaging.rsocket.RSocketStrategies[] component by creating beans that implement the javadoc:org.springframework.boot.rsocket.messaging.RSocketStrategiesCustomizer[] interface.\nNote that their javadoc:org.springframework.core.annotation.Order[format=annotation] is important, as it determines the order of codecs.\n\n\n\n[[messaging.rsocket.server-auto-configuration]]\n== RSocket Server Auto-configuration\n\nSpring Boot provides RSocket server auto-configuration.\nThe required dependencies are provided by the `spring-boot-starter-rsocket`.\n\nSpring Boot allows exposing RSocket over WebSocket from a WebFlux server, or standing up an independent RSocket server.\nThis depends on the type of application and its configuration.\n\nFor WebFlux application (that is of type javadoc:org.springframework.boot.WebApplicationType#REACTIVE[]), the RSocket server will be plugged into the Web Server only if the following properties match:\n\n[configprops,yaml]\n----\nspring:\n  rsocket:\n    server:\n      mapping-path: \"/rsocket\"\n      transport: \"websocket\"\n----\n\nWARNING: Plugging RSocket into a web server is only supported with Reactor Netty, as RSocket itself is built with that library.\n\nAlternatively, an RSocket TCP or websocket server is started as an independent, embedded server.\nBesides the dependency requirements, the only required configuration is to define a port for that server:\n\n[configprops,yaml]\n----\nspring:\n  rsocket:\n    server:\n      port: 9898\n----\n\n\n\n[[messaging.rsocket.messaging]]\n== Spring Messaging RSocket Support\n\nSpring Boot will auto-configure the Spring Messaging infrastructure for RSocket.\n\nThis means that Spring Boot will create a javadoc:org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler[] bean that will handle RSocket requests to your application.\n\nTIP: You can use {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-advice.html[`@ControllerAdvice`] to handle exceptions.\n\n\n\n[[messaging.rsocket.requester]]\n== Calling RSocket Services with RSocketRequester\n\nOnce the javadoc:io.rsocket.RSocket[] channel is established between server and client, any party can send or receive requests to the other.\n\nAs a server, you can get injected with an javadoc:org.springframework.messaging.rsocket.RSocketRequester[] instance on any handler method of an RSocket javadoc:org.springframework.stereotype.Controller[format=annotation].\nAs a client, you need to configure and establish an RSocket connection first.\nSpring Boot auto-configures an javadoc:org.springframework.messaging.rsocket.RSocketRequester$Builder[] for such cases with the expected codecs and applies any javadoc:org.springframework.messaging.rsocket.RSocketConnectorConfigurer[] bean.\n\nThe javadoc:org.springframework.messaging.rsocket.RSocketRequester$Builder[] instance is a prototype bean, meaning each injection point will provide you with a new instance .\nThis is done on purpose since this builder is stateful and you should not create requesters with different setups using the same instance.\n\nThe following code shows a typical example:\n\ninclude-code::MyService[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/spring-integration.adoc",
    "content": "[[messaging.spring-integration]]\n= Spring Integration\n\nSpring Boot offers several conveniences for working with {url-spring-integration-site}[Spring Integration], including the `spring-boot-starter-integration` starter.\nSpring Integration provides abstractions over messaging and also other transports such as HTTP, TCP, and others.\nIf Spring Integration is available on your classpath, it is initialized through the javadoc:org.springframework.integration.config.EnableIntegration[format=annotation] annotation.\n\nSpring Integration polling logic relies xref:features/task-execution-and-scheduling.adoc[on the auto-configured javadoc:org.springframework.scheduling.TaskScheduler[]].\nThe default javadoc:org.springframework.integration.scheduling.PollerMetadata[] (poll unbounded number of messages every second) can be customized with `spring.integration.poller.*` configuration properties.\n\nSpring Boot also configures some features that are triggered by the presence of additional Spring Integration modules.\nIf `spring-integration-jmx` is also on the classpath, message processing statistics are published over JMX.\nIf `spring-integration-jdbc` is available, the default database schema can be created on startup, as shown in the following line:\n\n[configprops,yaml]\n----\nspring:\n  integration:\n    jdbc:\n      initialize-schema: \"always\"\n----\n\nIf `spring-integration-rsocket` is available, developers can configure an RSocket server using `spring.rsocket.server.*` properties and let it use javadoc:org.springframework.integration.rsocket.IntegrationRSocketEndpoint[] or javadoc:org.springframework.integration.rsocket.outbound.RSocketOutboundGateway[] components to handle incoming RSocket messages.\nThis infrastructure can handle Spring Integration RSocket channel adapters and javadoc:org.springframework.messaging.handler.annotation.MessageMapping[format=annotation] handlers (given `spring.integration.rsocket.server.message-mapping-enabled` is configured).\n\nSpring Boot can also auto-configure an javadoc:org.springframework.integration.rsocket.ClientRSocketConnector[] using configuration properties:\n\n[configprops,yaml]\n----\n# Connecting to a RSocket server over TCP\nspring:\n  integration:\n    rsocket:\n      client:\n        host: \"example.org\"\n        port: 9898\n----\n\n[configprops,yaml]\n----\n# Connecting to a RSocket Server over WebSocket\nspring:\n  integration:\n    rsocket:\n      client:\n        uri: \"ws://example.org\"\n----\n\nSee the {code-spring-boot-integration-src}/autoconfigure/IntegrationAutoConfiguration.java[`IntegrationAutoConfiguration`] and javadoc:org.springframework.boot.integration.autoconfigure.IntegrationProperties[] classes for more details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/messaging/websockets.adoc",
    "content": "[[messaging.websockets]]\n= WebSockets\n\nSpring Boot provides WebSockets auto-configuration for embedded Tomcat and Jetty.\nIf you deploy a war file to a standalone container, Spring Boot assumes that the container is responsible for the configuration of its WebSocket support.\n\nSpring Framework provides {url-spring-framework-docs}/web/websocket.html[rich WebSocket support] for MVC web applications that can be easily accessed through the `spring-boot-starter-websocket` module.\n\nWebSocket support is also available for {url-spring-framework-docs}/web/webflux-websocket.html[reactive web applications] and requires to include the WebSocket API alongside `spring-boot-starter-webflux`:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>jakarta.websocket</groupId>\n\t<artifactId>jakarta.websocket-api</artifactId>\n</dependency>\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/aot-cache.adoc",
    "content": "[[packaging.aot-cache]]\n= AOT Cache\n:page-aliases: class-data-sharing.adoc\n\nAOT cache is a https://openjdk.org/jeps/483[JVM feature] that can help reduce the startup time and memory footprint of Java applications.\n\nIf you're using Java < 24, you should read the sections about CDS.\nCDS is the predecessor of AOT cache, but works similarly.\n\nSpring Boot supports both CDS and AOT cache, and it is recommended that you use AOT cache if it is available in the JVM version you are using (Java 24 or later).\n\n[[packaging.aot-cache.aot-cache]]\n== AOT Cache\n\nNOTE: If you're using Java < 24, AOT cache is not available.\nYou have to use CDS instead.\n\nTo use the AOT cache feature, you should first perform a training run on your application in extracted form:\n\n[source,shell]\n----\n$ java -Djarmode=tools -jar my-app.jar extract --destination application\n$ cd application\n$ java -XX:AOTCacheOutput=app.aot -Dspring.context.exit=onRefresh -jar my-app.jar\n----\n\nThis creates an `app.aot` cache file that can be reused as long as the application is not updated and the same Java version is used.\n\nTo use the cache file, you need to add an extra parameter when starting the application:\n\n[source,shell]\n----\n$ java -XX:AOTCache=app.aot -jar my-app.jar\n----\n\nNOTE: You have to use the cache file with the extracted form of the application, otherwise it has no effect.\n\n\n\n[[packaging.aot-cache.cds]]\n== CDS\n\nNOTE: If you're using Java 24 or later, please use AOT cache instead of CDS.\n\nTo use CDS, you should first perform a training run on your application in extracted form:\n\n[source,shell]\n----\n$ java -Djarmode=tools -jar my-app.jar extract --destination application\n$ cd application\n$ java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar my-app.jar\n----\n\nThis creates an `application.jsa` archive file that can be reused as long as the application is not updated.\n\nTo use the archive file, you need to add an extra parameter when starting the application:\n\n[source,shell]\n----\n$ java -XX:SharedArchiveFile=application.jsa -jar my-app.jar\n----\n\nNOTE: You have to use the cache file with the extracted form of the application, otherwise it has no effect.\n\nNOTE: For more details about CDS, refer to the https://docs.oracle.com/en/java/javase/17/vm/class-data-sharing.html[Class Data Sharing documentation of the JDK].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/aot.adoc",
    "content": "[[packaging.aot]]\n= Ahead-of-Time Processing With the JVM\n\nIt's beneficial for the startup time to run your application using the AOT generated initialization code.\nFirst, you need to ensure that the jar you are building includes AOT generated code.\n\nNOTE: AOT cache and Spring's AOT can be combined to further improve startup time.\n\nFor Maven, this means that you should build with `-Pnative` to activate the `native` profile:\n\n[source,shell]\n----\n$ mvn -Pnative package\n----\n\nFor Gradle, you need to ensure that your build includes the `org.springframework.boot.aot` plugin.\n\nWhen the JAR has been built, run it with `spring.aot.enabled` system property set to `true`. For example:\n\n[source,shell]\n----\n$ java -Dspring.aot.enabled=true -jar myapplication.jar\n\n........ Starting AOT-processed MyApplication ...\n----\n\nBeware that using the ahead-of-time processing has drawbacks.\nIt implies the following restrictions:\n\n* The classpath is fixed and fully defined at build time\n* The beans defined in your application cannot change at runtime, meaning:\n- The Spring javadoc:org.springframework.context.annotation.Profile[format=annotation] annotation and profile-specific configuration xref:how-to:aot.adoc#howto.aot.conditions[have limitations].\n- Properties that change if a bean is created are not supported (for example, javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] and `.enabled` properties).\n\nTo learn more about ahead-of-time processing, please see the xref:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[] section.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/checkpoint-restore.adoc",
    "content": "[[packaging.checkpoint-restore]]\n= Checkpoint and Restore With the JVM\n\nhttps://wiki.openjdk.org/display/crac/Main[Coordinated Restore at Checkpoint] (CRaC) is an OpenJDK project that defines a new Java API to allow you to checkpoint and restore an application on the HotSpot JVM.\nIt is based on https://github.com/checkpoint-restore/criu[CRIU], a project that implements checkpoint/restore functionality on Linux.\n\nThe principle is the following: you start your application almost as usual but with a CRaC enabled version of the JDK like https://bell-sw.com/pages/downloads/?package=jdk-crac[BellSoft Liberica JDK with CRaC] or https://www.azul.com/downloads/?package=jdk-crac#zulu[Azul Zulu JDK with CRaC].\nThen at some point, potentially after some workloads that will warm up your JVM by executing all common code paths, you trigger a checkpoint using an API call, a `jcmd` command, an HTTP endpoint, or a different mechanism.\n\nA memory representation of the running JVM, including its warmness, is then serialized to disk, allowing a fast restoration at a later point, potentially on another machine with a similar operating system and CPU architecture.\nThe restored process retains all the capabilities of the HotSpot JVM, including further JIT optimizations at runtime.\n\nBased on the foundations provided by Spring Framework, Spring Boot provides support for checkpointing and restoring your application, and manages out-of-the-box the lifecycle of resources such as socket, files and thread pools https://github.com/spring-projects/spring-lifecycle-smoke-tests/blob/ci/STATUS.adoc[on a limited scope].\nAdditional lifecycle management is expected for other dependencies and potentially for the application code dealing with such resources.\n\nYou can find more details about the two modes supported (\"on demand checkpoint/restore of a running application\" and \"automatic checkpoint/restore at startup\"), how to enable checkpoint and restore support and some guidelines in {url-spring-framework-docs}/integration/checkpoint-restore.html[the Spring Framework JVM Checkpoint Restore support documentation].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/container-images/cloud-native-buildpacks.adoc",
    "content": "[[packaging.container-images.buildpacks]]\n= Cloud Native Buildpacks\n\nDocker images can be built directly from your Maven or Gradle plugin using https://buildpacks.io[Cloud Native Buildpacks].\nIf you’ve ever used an application platform such as Cloud Foundry or Heroku then you’ve probably used a buildpack.\nBuildpacks are the part of the platform that takes your application and converts it into something that the platform can actually run.\nFor example, Cloud Foundry’s Java buildpack will notice that you’re pushing a `.jar` file and automatically add a relevant JRE.\n\nWith Cloud Native Buildpacks, you can create Docker compatible images that you can run anywhere.\nSpring Boot includes buildpack support directly for both Maven and Gradle.\nThis means you can just type a single command and quickly get a sensible image into your locally running Docker daemon.\n\nSee the individual plugin documentation on how to use buildpacks with xref:maven-plugin:build-image.adoc#build-image[Maven] and xref:gradle-plugin:packaging-oci-image.adoc[Gradle].\n\nNOTE: The https://github.com/paketo-buildpacks/spring-boot[Paketo Spring Boot buildpack] supports the `layers.idx` file, so any xref:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[layer customization] that is applied to it will be reflected in the image created by the buildpacks.\n\nNOTE: In order to achieve reproducible builds and container image caching, buildpacks can manipulate the application resources metadata (such as the file \"last modified\" information).\nYou should ensure that your application does not rely on that metadata at runtime.\nSpring Boot can use that information when serving static resources, but this can be disabled with configprop:spring.web.resources.cache.use-last-modified[].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/container-images/dockerfiles.adoc",
    "content": "[[packaging.container-images.dockerfiles]]\n= Dockerfiles\n\nWhile it is possible to convert a Spring Boot uber jar into a Docker image with just a few lines in the `Dockerfile`, using the xref:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[layering feature] will result in an optimized image.\nWhen you create a jar containing the layers index file, the `spring-boot-jarmode-tools` jar will be added as a dependency to your jar.\nWith this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers.\n\nHere’s how you can launch your jar with a `tools` jar mode:\n\n[source,shell]\n----\n$ java -Djarmode=tools -jar my-app.jar\n----\n\nThis will provide the following output:\n\n[subs=\"verbatim\"]\n----\nUsage:\n  java -Djarmode=tools -jar my-app.jar\n\nAvailable commands:\n  extract      Extract the contents from the jar\n  list-layers  List layers from the jar that can be extracted\n  help         Help about any command\n----\n\nThe `extract` command can be used to easily split the application into layers to be added to the `Dockerfile`.\nHere is an example of a `Dockerfile` using `jarmode`.\n\n[source,dockerfile]\n----\ninclude::reference:partial$dockerfile[]\n# Start the application jar - this is not the uber jar used by the builder\n# This jar only contains application code and references to the extracted jar files\n# This layout is efficient to start up and AOT cache (and CDS) friendly\nENTRYPOINT [\"java\", \"-jar\", \"application.jar\"]\n----\n\nAssuming the above `Dockerfile` is in the current directory, your Docker image can be built with `docker build .`, or optionally specifying the path to your application jar, as shown in the following example:\n\n[source,shell]\n----\n$ docker build --build-arg JAR_FILE=path/to/myapp.jar .\n----\n\nThis is a multi-stage `Dockerfile`.\nThe builder stage extracts the directories that are needed later.\nEach of the `COPY` commands relates to the layers extracted by the jarmode.\n\nOf course, a `Dockerfile` can be written without using the `jarmode`.\nYou can use some combination of `unzip` and `mv` to move things to the right layer but `jarmode` simplifies that.\nAdditionally, the layout created by the `jarmode` is AOT cache (and CDS) friendly out of the box.\n\n\n\n[[packaging.container-images.dockerfiles.aot-cache]]\n== AOT Cache\n\nNOTE: If you're using Java < 24, AOT cache is not available.\nYou have to use CDS instead.\n\nIf you want to additionally enable the xref:reference:packaging/aot-cache.adoc#packaging.aot-cache.aot-cache[AOT cache], you can use this `Dockerfile`:\n[source,dockerfile]\n----\ninclude::reference:partial$dockerfile[]\n# Execute the AOT cache training run\nRUN java -XX:AOTCacheOutput=app.aot -Dspring.context.exit=onRefresh -jar application.jar\n# Start the application jar with AOT cache enabled - this is not the uber jar used by the builder\n# This jar only contains application code and references to the extracted jar files\n# This layout is efficient to start up and AOT cache friendly\nENTRYPOINT [\"java\", \"-XX:AOTCache=app.aot\", \"-jar\", \"application.jar\"]\n----\n\nThis is mostly the same as the above `Dockerfile`.\nAs the last steps, it creates the AOT cache file by doing a training run and passes the AOT cache parameter to `java -jar`.\n\n\n\n[[packaging.container-images.dockerfiles.cds]]\n== CDS\n\nNOTE: If you're using Java 24 or later, please use AOT cache instead of CDS.\n\nIf you want to additionally enable xref:reference:packaging/aot-cache.adoc#packaging.aot-cache.cds[CDS], you can use this `Dockerfile`:\n[source,dockerfile]\n----\ninclude::reference:partial$dockerfile[]\n# Execute the CDS training run\nRUN java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar application.jar\n# Start the application jar with CDS enabled - this is not the uber jar used by the builder\n# This jar only contains application code and references to the extracted jar files\n# This layout is efficient to start up and CDS friendly\nENTRYPOINT [\"java\", \"-XX:SharedArchiveFile=application.jsa\", \"-jar\", \"application.jar\"]\n----\n\nThis is mostly the same as the above `Dockerfile`.\nAs the last steps, it creates the CDS archive by doing a training run and passes the CDS parameter to `java -jar`.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/container-images/efficient-images.adoc",
    "content": "[[packaging.container-images.efficient-images]]\n= Efficient Container Images\n\nIt is easily possible to package a Spring Boot uber jar as a Docker image.\nHowever, there are various downsides to copying and running the uber jar as-is in the Docker image.\nThere’s always a certain amount of overhead when running an uber jar without unpacking it, and in a containerized environment this can be noticeable.\nThe other issue is that putting your application's code and all its dependencies in one layer in the Docker image is not optimal.\nSince you probably recompile your code more often than you upgrade the version of Spring Boot you use, it’s often better to separate things a bit more.\nIf you put jar files in the layer before your application classes, Docker often only needs to change the very bottom layer and can pick others up from its cache.\n\n\n\n[[packaging.container-images.efficient-images.layering]]\n== Layering Docker Images\n\nTo make it easier to create optimized Docker images, Spring Boot supports adding a layer index file to the jar.\nIt provides a list of layers and the parts of the jar that should be contained within them.\nThe list of layers in the index is ordered based on the order in which the layers should be added to the Docker/OCI image.\nOut-of-the-box, the following layers are supported:\n\n* `dependencies` (for regular released dependencies)\n* `spring-boot-loader` (for everything under `org/springframework/boot/loader`)\n* `snapshot-dependencies` (for snapshot dependencies)\n* `application` (for application classes and resources)\n\nThe following shows an example of a `layers.idx` file:\n\n[source,yaml]\n----\n- \"dependencies\":\n  - BOOT-INF/lib/library1.jar\n  - BOOT-INF/lib/library2.jar\n- \"spring-boot-loader\":\n  - org/springframework/boot/loader/launch/JarLauncher.class\n  - ... <other classes>\n- \"snapshot-dependencies\":\n  - BOOT-INF/lib/library3-SNAPSHOT.jar\n- \"application\":\n  - META-INF/MANIFEST.MF\n  - BOOT-INF/classes/a/b/C.class\n----\n\nThis layering is designed to separate code based on how likely it is to change between application builds.\nLibrary code is less likely to change between builds, so it is placed in its own layers to allow tooling to re-use the layers from cache.\nApplication code is more likely to change between builds so it is isolated in a separate layer.\n\nSpring Boot also supports layering for war files with the help of a `layers.idx`.\n\nFor Maven, see the xref:maven-plugin:packaging.adoc#packaging.layers[packaging layered jar or war section] for more details on adding a layer index to the archive.\nFor Gradle, see the xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.layered-archives[packaging layered jar or war section] of the Gradle plugin documentation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/container-images/index.adoc",
    "content": "[[packaging.container-images]]\n= Container Images\n\nSpring Boot applications can be containerized xref:packaging/container-images/dockerfiles.adoc[using Dockerfiles], or by xref:packaging/container-images/cloud-native-buildpacks.adoc[using Cloud Native Buildpacks] to create optimized docker compatible container images that you can run anywhere.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/efficient.adoc",
    "content": "[[packaging.efficient]]\n= Efficient Deployments\n\n\n\n[[packaging.efficient.unpacking]]\n== Unpacking the Executable jar\n\nYou can run your application using the executable jar, but loading the classes from nested jars has a small startup cost.\nDepending on the size of the jar, running the application from an exploded structure is faster and recommended in production.\nCertain PaaS implementations may also choose to extract archives before they run.\nFor example, Cloud Foundry operates this way.\n\nSpring Boot supports extracting your application to a directory using different layouts.\nThe default layout is the most efficient, and it is xref:reference:packaging/aot-cache.adoc#packaging.aot-cache.aot-cache[AOT cache] (and xref:reference:packaging/aot-cache.adoc#packaging.aot-cache.cds[CDS]) friendly.\n\nIn this layout, the libraries are extracted to a `lib/` folder, and the application jar\ncontains the application classes and a manifest which references the libraries in the `lib/` folder.\n\nTo unpack the executable jar, run this command:\n\n[source,shell]\n----\n$ java -Djarmode=tools -jar my-app.jar extract\n----\n\nAnd then in production, you can run the extracted jar:\n\n[source,shell]\n----\n$ java -jar my-app/my-app.jar\n----\n\nAfter startup, you should not expect any differences in execution time between running an executable jar and running an extracted jar.\n\nTIP: Run `java -Djarmode=tools -jar my-app.jar help extract` to see all possible options.\n\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/index.adoc",
    "content": "[[packaging]]\n= Packaging Spring Boot Applications\n\nSpring Boot supports several technologies for optimizing applications for deployment, including xref:packaging/native-image/index.adoc[GraalVM native images], xref:packaging/aot-cache.adoc[AOT cache], and xref:packaging/checkpoint-restore.adoc[Checkpoint and Restore].\n\nSpring Boot applications can be packaged in Docker containers using techniques described in xref:packaging/container-images/index.adoc[].\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/advanced-topics.adoc",
    "content": "[[packaging.native-image.advanced]]\n= Advanced Native Images Topics\n\n\n\n[[packaging.native-image.advanced.nested-configuration-properties]]\n== Nested Configuration Properties\n\nReflection hints are automatically created for configuration properties by the Spring ahead-of-time engine.\nNested configuration properties which are not inner classes, however, *must* be annotated with javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation], otherwise they won't be detected and will not be bindable.\n\ninclude-code::MyProperties[]\n\nwhere `Nested` is:\n\ninclude-code::Nested[]\n\nThe example above produces configuration properties for `my.properties.name` and `my.properties.nested.number`.\nWithout the javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation] annotation on the `nested` field, the `my.properties.nested.number` property would not be bindable in a native image.\nYou can also annotate the getter method.\n\nWhen using constructor binding, you have to annotate the field with javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation]:\n\ninclude-code::MyPropertiesCtor[]\n\nWhen using records, you have to annotate the parameter with javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation]:\n\ninclude-code::MyPropertiesRecord[]\n\nWhen using Kotlin, you need to annotate the parameter of a data class with javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation]:\n\ninclude-code::MyPropertiesKotlin[]\n\nNOTE: Please use public getters and setters in all cases, otherwise the properties will not be bindable.\n\n\n\n[[packaging.native-image.advanced.converting-executable-jars]]\n== Converting a Spring Boot Executable Jar\n\nIt is possible to convert a Spring Boot xref:specification:executable-jar/index.adoc[executable jar] into a native image as long as the jar contains the AOT generated assets.\nThis can be useful for a number of reasons, including:\n\n* You can keep your regular JVM pipeline and turn the JVM application into a native image on your CI/CD platform.\n* As `native-image` https://github.com/oracle/graal/issues/407[does not support cross-compilation], you can keep an OS neutral deployment artifact which you convert later to different OS architectures.\n\nYou can convert a Spring Boot executable jar into a native image using Cloud Native Buildpacks, or using the `native-image` tool that is shipped with GraalVM.\n\nNOTE: Your executable jar must include AOT generated assets such as generated classes and JSON hint files.\n\n\n\n[[packaging.native-image.advanced.converting-executable-jars.buildpacks]]\n=== Using Buildpacks\n\nSpring Boot applications usually use Cloud Native Buildpacks through the Maven (`mvn spring-boot:build-image`) or Gradle (`gradle bootBuildImage`) integrations.\nYou can, however, also use {url-buildpacks-docs}/for-platform-operators/how-to/integrate-ci/pack/[`pack`] to turn an AOT processed Spring Boot executable jar into a native container image.\n\nNOTE: You have to build your application with at least JDK 25, because Buildpacks use the same GraalVM native-image version as the Java version used for compilation.\n\nFirst, make sure that a Docker daemon is available (see https://docs.docker.com/installation/#installation[Get Docker] for more details).\nhttps://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user[Configure it to allow non-root user] if you are on Linux.\n\nYou also need to install `pack` by following {url-buildpacks-docs}/for-platform-operators/how-to/integrate-ci/pack/#install[the installation guide on buildpacks.io].\n\nAssuming an AOT processed Spring Boot executable jar built as `myproject-0.0.1-SNAPSHOT.jar` is in the `target` directory, run:\n\n[source,shell]\n----\n$ pack build --builder paketobuildpacks/builder-noble-java-tiny \\\n    --path target/myproject-0.0.1-SNAPSHOT.jar \\\n    --env 'BP_NATIVE_IMAGE=true' \\\n    my-application:0.0.1-SNAPSHOT\n----\n\nNOTE: You do not need to have a local GraalVM installation to generate an image in this way.\n\nOnce `pack` has finished, you can launch the application using `docker run`:\n\n[source,shell]\n----\n$ docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT\n----\n\n\n\n[[packaging.native-image.advanced.converting-executable-jars.native-image]]\n=== Using GraalVM native-image\n\nAnother option to turn an AOT processed Spring Boot executable jar into a native executable is to use the GraalVM `native-image` tool.\nFor this to work, you'll need a GraalVM distribution on your machine.\nYou can either download it manually on the {url-download-liberica-nik}[Liberica Native Image Kit page] or you can use a download manager like SDKMAN!.\n\nAssuming an AOT processed Spring Boot executable jar built as `myproject-0.0.1-SNAPSHOT.jar` is in the `target` directory, run:\n\n[source,shell]\n----\n$ rm -rf target/native\n$ mkdir -p target/native\n$ cd target/native\n$ jar -xvf ../myproject-0.0.1-SNAPSHOT.jar\n$ native-image -H:Name=myproject @META-INF/native-image/argfile -cp .:BOOT-INF/classes:`find BOOT-INF/lib | tr '\\n' ':'`\n$ mv myproject ../\n----\n\nNOTE: These commands work on Linux or macOS machines, but you will need to adapt them for Windows.\n\nTIP: The `@META-INF/native-image/argfile` might not be packaged in your jar.\nIt is only included when reachability metadata overrides are needed.\n\nWARNING: The `native-image` `-cp` flag does not accept wildcards.\nYou need to ensure that all jars are listed (the command above uses `find` and `tr` to do this).\n\n\n\n[[packaging.native-image.advanced.using-the-tracing-agent]]\n== Using the Tracing Agent\n\nThe GraalVM native image {url-graal-docs-native-image}/metadata/AutomaticMetadataCollection[tracing agent] allows you to intercept reflection, resources or proxy usage on the JVM in order to generate the related hints.\nSpring should generate most of these hints automatically, but the tracing agent can be used to quickly identify the missing entries.\n\nWhen using the agent to generate hints for a native image, there are a couple of approaches:\n\n* Launch the application directly and exercise it.\n* Run application tests to exercise the application.\n\nThe first option is interesting for identifying the missing hints when a library or a pattern is not recognized by Spring.\n\nThe second option sounds more appealing for a repeatable setup, but by default the generated hints will include anything required by the test infrastructure.\nSome of these will be unnecessary when the application runs for real.\nTo address this problem the agent supports an access-filter file that will cause certain data to be excluded from the generated output.\n\n\n\n[[packaging.native-image.advanced.using-the-tracing-agent.launch]]\n=== Launch the Application Directly\n\nUse the following command to launch the application with the native image tracing agent attached:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ java -Dspring.aot.enabled=true \\\n    -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/ \\\n    -jar target/myproject-0.0.1-SNAPSHOT.jar\n----\n\nNow you can exercise the code paths you want to have hints for and then stop the application with `ctrl-c`.\n\nOn application shutdown the native image tracing agent will write the hint files to the given config output directory.\nYou can either manually inspect these files, or use them as input to the native image build process.\nTo use them as input, copy them into the `src/main/resources/META-INF/native-image/` directory.\nThe next time you build the native image, GraalVM will take these files into consideration.\n\nThere are more advanced options which can be set on the native image tracing agent, for example filtering the recorded hints by caller classes, etc.\nFor further reading, please see {url-graal-docs-native-image}/metadata/AutomaticMetadataCollection[the official documentation].\n\n\n\n[[packaging.native-image.advanced.custom-hints]]\n== Custom Hints\n\nIf you need to provide your own hints for reflection, resources, serialization, proxy usage and so on, you can use the javadoc:org.springframework.aot.hint.RuntimeHintsRegistrar[] API.\nCreate a class that implements the javadoc:org.springframework.aot.hint.RuntimeHintsRegistrar[] interface, and then make appropriate calls to the provided javadoc:org.springframework.aot.hint.RuntimeHints[] instance:\n\ninclude-code::MyRuntimeHints[]\n\nYou can then use javadoc:org.springframework.context.annotation.ImportRuntimeHints[format=annotation] on any javadoc:org.springframework.context.annotation.Configuration[format=annotation] class (for example your javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotated application class) to activate those hints.\n\nIf you have classes which need binding (mostly needed when serializing or deserializing JSON), you can use {url-spring-framework-docs}/core/aot.html#aot.hints.register-reflection-for-binding[`@RegisterReflectionForBinding`] on any bean.\nMost of the hints are automatically inferred, for example when accepting or returning data from a javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] method.\nBut when you work with javadoc:org.springframework.web.reactive.function.client.WebClient[], javadoc:org.springframework.web.client.RestClient[] or javadoc:org.springframework.web.client.RestTemplate[] directly, you might need to use javadoc:org.springframework.aot.hint.annotation.RegisterReflectionForBinding[format=annotation].\n\n\n\n[[packaging.native-image.advanced.custom-hints.testing]]\n=== Testing Custom Hints\n\nThe javadoc:org.springframework.aot.hint.predicate.RuntimeHintsPredicates[] API can be used to test your hints.\nThe API provides methods that build a javadoc:java.util.function.Predicate[] that can be used to test a javadoc:org.springframework.aot.hint.RuntimeHints[] instance.\n\nIf you're using AssertJ, your test would look like this:\n\ninclude-code::MyRuntimeHintsTests[]\n\n\n\n[[packaging.native-image.advanced.custom-hints.static]]\n=== Providing Hints Statically\nIf you prefer, custom hints can be provided statically in one or more GraalVM JSON hint files.\nSuch files should be placed in `src/main/resources/` within a `+META-INF/native-image/*/*/+` directory.\nThe xref:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[hints generated during AOT processing] are written to a directory named `+META-INF/native-image/{groupId}/{artifactId}/+`.\nPlace your static hint files in a directory that does not clash with this location, such as `+META-INF/native-image/{groupId}/{artifactId}-additional-hints/+`.\n\n\n\n[[packaging.native-image.advanced.known-limitations]]\n== Known Limitations\n\nGraalVM native images are an evolving technology and not all libraries provide support.\nThe GraalVM community is helping by providing https://github.com/oracle/graalvm-reachability-metadata[reachability metadata] for projects that don't yet ship their own.\nSpring itself doesn't contain hints for 3rd party libraries and instead relies on the reachability metadata project.\n\nIf you encounter problems when generating native images for Spring Boot applications, please check the {url-github-wiki}/Spring-Boot-with-GraalVM[Spring Boot with GraalVM] page of the Spring Boot wiki.\nYou can also contribute issues to the https://github.com/spring-projects/spring-aot-smoke-tests[spring-aot-smoke-tests] project on GitHub which is used to confirm that common application types are working as expected.\n\nIf you find a library which doesn't work with GraalVM, please raise an issue on the https://github.com/oracle/graalvm-reachability-metadata[reachability metadata project].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/index.adoc",
    "content": "[[packaging.native-image]]\n= GraalVM Native Images\n\nhttps://www.graalvm.org/native-image/[GraalVM Native Images] are standalone executables that can be generated by processing compiled Java applications ahead-of-time.\nNative Images generally have a smaller memory footprint and start faster than their JVM counterparts.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/packaging/native-image/introducing-graalvm-native-images.adoc",
    "content": "[[packaging.native-image.introducing-graalvm-native-images]]\n= Introducing GraalVM Native Images\n\nGraalVM Native Images provide a new way to deploy and run Java applications.\nCompared to the Java Virtual Machine, native images can run with a smaller memory footprint and with much faster startup times.\n\nThey are well suited to applications that are deployed using container images and are especially interesting when combined with \"Function as a service\" (FaaS) platforms.\n\nUnlike traditional applications written for the JVM, GraalVM Native Image applications require ahead-of-time processing in order to create an executable.\nThis ahead-of-time processing involves statically analyzing your application code from its main entry point.\n\nA GraalVM Native Image is a complete, platform-specific executable.\nYou do not need to ship a Java Virtual Machine in order to run a native image.\n\nTIP: If you just want to get started and experiment with GraalVM you can jump to the xref:how-to:native-image/developing-your-first-application.adoc[] section and return to this section later.\n\n\n\n[[packaging.native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments]]\n== Key Differences with JVM Deployments\n\nThe fact that GraalVM Native Images are produced ahead-of-time means that there are some key differences between native and JVM based applications.\nThe main differences are:\n\n* Static analysis of your application is performed at build-time from the `main` entry point.\n* Code that cannot be reached when the native image is created will be removed and won't be part of the executable.\n* GraalVM is not directly aware of dynamic elements of your code and must be told about reflection, resources, serialization, and dynamic proxies.\n* The application classpath is fixed at build time and cannot change.\n* There is no lazy class loading, everything shipped in the executables will be loaded in memory on startup.\n* There are some limitations around some aspects of Java applications that are not fully supported.\n\nOn top of those differences, Spring uses a process called xref:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing[Spring Ahead-of-Time processing], which imposes further limitations.\nPlease make sure to read at least the beginning of the next section to learn about those.\n\nTIP: The {url-graal-docs-native-image}/metadata/Compatibility/[Native Image Compatibility Guide] section of the GraalVM reference documentation provides more details about GraalVM limitations.\n\n\n\n[[packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing]]\n== Understanding Spring Ahead-of-Time Processing\n\nTypical Spring Boot applications are quite dynamic and configuration is performed at runtime.\nIn fact, the concept of Spring Boot auto-configuration depends heavily on reacting to the state of the runtime in order to configure things correctly.\n\nAlthough it would be possible to tell GraalVM about these dynamic aspects of the application, doing so would undo most of the benefit of static analysis.\nSo instead, when using Spring Boot to create native images, a closed-world is assumed and the dynamic aspects of the application are restricted.\n\nA closed-world assumption implies, besides xref:packaging/native-image/introducing-graalvm-native-images.adoc#packaging.native-image.introducing-graalvm-native-images.key-differences-with-jvm-deployments[the limitations created by GraalVM itself], the following restrictions:\n\n* The beans defined in your application cannot change at runtime, meaning:\n- The Spring javadoc:org.springframework.context.annotation.Profile[format=annotation] annotation and profile-specific configuration xref:how-to:aot.adoc#howto.aot.conditions[have limitations].\n- Properties that change if a bean is created are not supported (for example, javadoc:org.springframework.boot.autoconfigure.condition.ConditionalOnProperty[format=annotation] and `.enabled` properties).\n\nWhen these restrictions are in place, it becomes possible for Spring to perform ahead-of-time processing during build-time and generate additional assets that GraalVM can use.\nA Spring AOT processed application will typically generate:\n\n* Java source code\n* Bytecode (for dynamic proxies, etc.)\n* GraalVM JSON hint files in `+META-INF/native-image/{groupId}/{artifactId}/+`:\n - Resource hints (`resource-config.json`)\n - Reflection hints (`reflect-config.json`)\n - Serialization hints (`serialization-config.json`)\n - Java Proxy Hints (`proxy-config.json`)\n - JNI Hints (`jni-config.json`)\n\nIf the generated hints are not sufficient, you can also xref:packaging/native-image/advanced-topics.adoc#packaging.native-image.advanced.custom-hints[provide your own].\n\n\n\n[[packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.source-code-generation]]\n=== Source Code Generation\n\nSpring applications are composed of Spring Beans.\nInternally, Spring Framework uses two distinct concepts to manage beans.\nThere are bean instances, which are the actual instances that have been created and can be injected into other beans.\nThere are also bean definitions which are used to define attributes of a bean and how its instance should be created.\n\nIf we take a typical javadoc:org.springframework.context.annotation.Configuration[format=annotation] class:\n\ninclude-code::MyConfiguration[]\n\nThe bean definition is created by parsing the javadoc:org.springframework.context.annotation.Configuration[format=annotation] class and finding the javadoc:org.springframework.context.annotation.Bean[format=annotation] methods.\nIn the above example, we're defining a javadoc:org.springframework.beans.factory.config.BeanDefinition[] for a singleton bean named `myBean`.\nWe're also creating a javadoc:org.springframework.beans.factory.config.BeanDefinition[] for the `MyConfiguration` class itself.\n\nWhen the `myBean` instance is required, Spring knows that it must invoke the `myBean()` method and use the result.\nWhen running on the JVM, javadoc:org.springframework.context.annotation.Configuration[format=annotation] class parsing happens when your application starts and javadoc:org.springframework.context.annotation.Bean[format=annotation] methods are invoked using reflection.\n\nWhen creating a native image, Spring operates in a different way.\nRather than parsing javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes and generating bean definitions at runtime, it does it at build-time.\nOnce the bean definitions have been discovered, they are processed and converted into source code that can be analyzed by the GraalVM compiler.\n\nThe Spring AOT process would convert the configuration class above to code like this:\n\ninclude-code::MyConfiguration__BeanDefinitions[]\n\nNOTE: The exact code generated may differ depending on the nature of your bean definitions.\n\nYou can see above that the generated code creates equivalent bean definitions to the javadoc:org.springframework.context.annotation.Configuration[format=annotation] class, but in a direct way that can be understood by GraalVM.\n\nThere is a bean definition for the `myConfiguration` bean, and one for `myBean`.\nWhen a `myBean` instance is required, a javadoc:org.springframework.beans.factory.aot.BeanInstanceSupplier[] is called.\nThis supplier will invoke the `myBean()` method on the `myConfiguration` bean.\n\nNOTE: During Spring AOT processing, your application is started up to the point that bean definitions are available.\nBean instances are not created during the AOT processing phase.\n\nSpring AOT will generate code like this for all your bean definitions.\nIt will also generate code when bean post-processing is required (for example, to call javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] methods).\nAn javadoc:org.springframework.context.ApplicationContextInitializer[] will also be generated which will be used by Spring Boot to initialize the javadoc:org.springframework.context.ApplicationContext[] when an AOT processed application is actually run.\n\nTIP: Although AOT generated source code can be verbose, it is quite readable and can be helpful when debugging an application.\nGenerated source files can be found in `target/spring-aot/main/sources` when using Maven and `build/generated/aotSources` with Gradle.\n\n\n\n[[packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.hint-file-generation]]\n=== Hint File Generation\n\nIn addition to generating source files, the Spring AOT engine will also generate hint files that are used by GraalVM.\nHint files contain JSON data that describes how GraalVM should deal with things that it can't understand by directly inspecting the code.\n\nFor example, you might be using a Spring annotation on a private method.\nSpring will need to use reflection in order to invoke private methods, even on GraalVM.\nWhen such situations arise, Spring can write a reflection hint so that GraalVM knows that even though the private method isn't called directly, it still needs to be available in the native image.\n\nHint files are generated under `META-INF/native-image` where they are automatically picked up by GraalVM.\n\nTIP: Generated hint files can be found in `target/spring-aot/main/resources` when using Maven and `build/generated/aotResources` with Gradle.\n\n\n\n[[packaging.native-image.introducing-graalvm-native-images.understanding-aot-processing.proxy-class-generation]]\n=== Proxy Class Generation\n\nSpring sometimes needs to generate proxy classes to enhance the code you've written with additional features.\nTo do this, it uses the cglib library which directly generates bytecode.\n\nWhen an application is running on the JVM, proxy classes are generated dynamically as the application runs.\nWhen creating a native image, these proxies need to be created at build-time so that they can be included by GraalVM.\n\nNOTE: Unlike source code generation, generated bytecode isn't particularly helpful when debugging an application.\nHowever, if you need to inspect the contents of the `.class` files using a tool such as `javap` you can find them in `target/spring-aot/main/classes` for Maven and `build/generated/aotClasses` for Gradle.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/index.adoc",
    "content": "[[testing]]\n= Testing\n\nSpring Boot provides a number of utilities and annotations to help when testing your application.\n\nTest support is provided by two general-purpose modules – `spring-boot-test` contains core items and `spring-boot-test-autoconfigure` supports auto-configuration for tests – and several focused `-test` modules that provide testing support for a particular feature.\n\nMost developers use the `spring-boot-starter-test` starter, which imports both general-purpose Spring Boot test modules as well as JUnit Jupiter, AssertJ, Hamcrest, and a number of other useful libraries, and the focused `-test` modules that are applicable to their particular application.\n\n[TIP]\n====\nIf you have tests that use JUnit 4, JUnit 6's vintage engine can be used to run them.\nTo use the vintage engine, add a dependency on `junit-vintage-engine`, as shown in the following example:\n\n[source,xml]\n----\n<dependency>\n\t<groupId>org.junit.vintage</groupId>\n\t<artifactId>junit-vintage-engine</artifactId>\n\t<scope>test</scope>\n\t<exclusions>\n\t\t<exclusion>\n\t\t\t<groupId>org.hamcrest</groupId>\n\t\t\t<artifactId>hamcrest-core</artifactId>\n\t\t</exclusion>\n\t</exclusions>\n</dependency>\n----\n====\n\n`hamcrest-core` is excluded in favor of `org.hamcrest:hamcrest` that is part of `spring-boot-starter-test`.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-applications.adoc",
    "content": "[[testing.spring-applications]]\n= Testing Spring Applications\n\nOne of the major advantages of dependency injection is that it should make your code easier to unit test.\nYou can instantiate objects by using the `new` operator without even involving Spring.\nYou can also use _mock objects_ instead of real dependencies.\n\nOften, you need to move beyond unit testing and start integration testing (with a Spring javadoc:org.springframework.context.ApplicationContext[]).\nIt is useful to be able to perform integration testing without requiring deployment of your application or needing to connect to other infrastructure.\n\nThe Spring Framework includes a dedicated test module for such integration testing.\nYou can declare a dependency directly to `org.springframework:spring-test` or use the `spring-boot-starter-test` starter to pull it in transitively.\n\nIf you have not used the `spring-test` module before, you should start by reading the {url-spring-framework-docs}/testing.html[relevant section] of the Spring Framework reference documentation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/spring-boot-applications.adoc",
    "content": "[[testing.spring-boot-applications]]\n= Testing Spring Boot Applications\n\nA Spring Boot application is a Spring javadoc:org.springframework.context.ApplicationContext[], so nothing very special has to be done to test it beyond what you would normally do with a vanilla Spring context.\n\nNOTE: External properties, logging, and other features of Spring Boot are installed in the context by default only if you use javadoc:org.springframework.boot.SpringApplication[] to create it.\n\nSpring Boot provides a javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] annotation, which can be used as an alternative to the standard `spring-test` javadoc:org.springframework.test.context.ContextConfiguration[format=annotation] annotation when you need Spring Boot features.\nThe annotation works by xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[creating the javadoc:org.springframework.context.ApplicationContext[] used in your tests through javadoc:org.springframework.boot.SpringApplication[]].\nIn addition to javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] a number of other annotations are also provided for xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[testing more specific slices] of an application.\n\nTIP: If you are using JUnit 4, do not forget to also add `@RunWith(SpringRunner.class)` to your test, otherwise the annotations will be ignored.\nIf you are using JUnit 6, there is no need to add the equivalent `@ExtendWith(SpringExtension.class)` as javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] and the other `@...Test` annotations are already annotated with it.\n\nBy default, javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] will not start a server.\nYou can use the `webEnvironment` attribute of javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] to further refine how your tests run:\n\n* `MOCK`(Default) : Loads a web javadoc:org.springframework.context.ApplicationContext[] and provides a mock web environment.\nEmbedded servers are not started when using this annotation.\nIf a web environment is not available on your classpath, this mode transparently falls back to creating a regular non-web javadoc:org.springframework.context.ApplicationContext[].\nIt can be used in conjunction with xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[`@AutoConfigureMockMvc`, javadoc:org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient[format=annotation]], or javadoc:org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient[format=annotation]] for mock-based testing of your web application.\n* `RANDOM_PORT`: Loads a javadoc:org.springframework.boot.web.server.context.WebServerApplicationContext[] and provides a real web environment.\nEmbedded servers are started and listen on a random port.\n* `DEFINED_PORT`: Loads a javadoc:org.springframework.boot.web.server.context.WebServerApplicationContext[] and provides a real web environment.\nEmbedded servers are started and listen on a defined port (from your `application.properties`) or on the default port of `8080`.\n* `NONE`: Loads an javadoc:org.springframework.context.ApplicationContext[] by using javadoc:org.springframework.boot.SpringApplication[] but does not provide _any_ web environment (mock or otherwise).\n\nNOTE: If your test is javadoc:org.springframework.transaction.annotation.Transactional[format=annotation], it rolls back the transaction at the end of each test method by default.\nHowever, as using this arrangement with either `RANDOM_PORT` or `DEFINED_PORT` implicitly provides a real servlet environment, the HTTP client and server run in separate threads and, thus, in separate transactions.\nAny transaction initiated on the server does not roll back in this case.\n\nNOTE: javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] with `webEnvironment = WebEnvironment.RANDOM_PORT` will also start the management server on a separate random port if your application uses a different port for the management server.\n\n\n\n[[testing.spring-boot-applications.detecting-web-app-type]]\n== Detecting Web Application Type\n\nIf Spring MVC is available, a regular MVC-based application context is configured.\nIf you have only Spring WebFlux, we will detect that and configure a WebFlux-based application context instead.\n\nIf both are present, Spring MVC takes precedence.\nIf you want to test a reactive web application in this scenario, you must set the configprop:spring.main.web-application-type[] property:\n\ninclude-code::MyWebFluxTests[]\n\n\n\n[[testing.spring-boot-applications.detecting-configuration]]\n== Detecting Test Configuration\n\nIf you are familiar with the Spring Test Framework, you may be used to using `@ContextConfiguration(classes=...)` in order to specify which Spring javadoc:org.springframework.context.annotation.Configuration[format=annotation] to load.\nAlternatively, you might have often used nested javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes within your test.\n\nWhen testing Spring Boot applications, this is often not required.\nSpring Boot's `@*Test` annotations search for your primary configuration automatically whenever you do not explicitly define one.\n\nThe search algorithm works up from the package that contains the test until it finds a class annotated with javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] or javadoc:org.springframework.boot.SpringBootConfiguration[format=annotation].\nAs long as you xref:using/structuring-your-code.adoc[structured your code] in a sensible way, your main configuration is usually found.\n\n[NOTE]\n====\nIf you use a xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[test annotation to test a more specific slice of your application], you should avoid adding configuration settings that are specific to a particular area on the xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.user-configuration-and-slicing[main method's application class].\n\nThe underlying component scan configuration of javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] defines exclude filters that are used to make sure slicing works as expected.\nIf you are using an explicit javadoc:org.springframework.context.annotation.ComponentScan[format=annotation] directive on your javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation]-annotated class, be aware that those filters will be disabled.\nIf you are using slicing, you should define them again.\n====\n\nIf you want to customize the primary configuration, you can use a nested javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] class.\nUnlike a nested javadoc:org.springframework.context.annotation.Configuration[format=annotation] class, which would be used instead of your application's primary configuration, a nested javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] class is used in addition to your application's primary configuration.\n\nNOTE: Spring's test framework caches application contexts between tests.\nTherefore, as long as your tests share the same configuration (no matter how it is discovered), the potentially time-consuming process of loading the context happens only once.\n\n\n\n[[testing.spring-boot-applications.using-main]]\n== Using the Test Configuration Main Method\n\nTypically the test configuration discovered by javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] will be your main javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation].\nIn most well structured applications, this configuration class will also include the `main` method used to launch the application.\n\nFor example, the following is a very common code pattern for a typical Spring Boot application:\n\ninclude-code::typical/MyApplication[]\n\nIn the example above, the `main` method doesn't do anything other than delegate to javadoc:org.springframework.boot.SpringApplication#run(java.lang.Class,java.lang.String...)[].\nIt is, however, possible to have a more complex `main` method that applies customizations before calling javadoc:org.springframework.boot.SpringApplication#run(java.lang.Class,java.lang.String...)[].\n\nFor example, here is an application that changes the banner mode and sets additional profiles:\n\ninclude-code::custom/MyApplication[]\n\nSince customizations in the `main` method can affect the resulting javadoc:org.springframework.context.ApplicationContext[], it's possible that you might also want to use the `main` method to create the javadoc:org.springframework.context.ApplicationContext[] used in your tests.\nBy default, javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] will not call your `main` method, and instead the class itself is used directly to create the javadoc:org.springframework.context.ApplicationContext[]\n\nIf you want to change this behavior, you can change the `useMainMethod` attribute of javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] to javadoc:org.springframework.boot.test.context.SpringBootTest$UseMainMethod#ALWAYS[] or javadoc:org.springframework.boot.test.context.SpringBootTest$UseMainMethod#WHEN_AVAILABLE[].\nWhen set to `ALWAYS`, the test will fail if no `main` method can be found.\nWhen set to `WHEN_AVAILABLE` the `main` method will be used if it is available, otherwise the standard loading mechanism will be used.\n\nFor example, the following test will invoke the `main` method of `MyApplication` in order to create the javadoc:org.springframework.context.ApplicationContext[].\nIf the main method sets additional profiles then those will be active when the javadoc:org.springframework.context.ApplicationContext[] starts.\n\ninclude-code::always/MyApplicationTests[]\n\n\n\n[[testing.spring-boot-applications.excluding-configuration]]\n== Excluding Test Configuration\n\nIf your application uses component scanning (for example, if you use javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] or javadoc:org.springframework.context.annotation.ComponentScan[format=annotation]), you may find top-level configuration classes that you created only for specific tests accidentally get picked up everywhere.\n\nAs we xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[have seen earlier], javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] can be used on an inner class of a test to customize the primary configuration.\njavadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] can also be used on a top-level class. Doing so indicates that the class should not be picked up by scanning.\nYou can then import the class explicitly where it is required, as shown in the following example:\n\ninclude-code::MyTests[]\n\nNOTE: If you directly use javadoc:org.springframework.context.annotation.ComponentScan[format=annotation] (that is, not through javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation]) you need to register the javadoc:org.springframework.boot.context.TypeExcludeFilter[] with it.\nSee the javadoc:org.springframework.boot.context.TypeExcludeFilter[] API documentation for details.\n\nNOTE: An imported javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] is processed earlier than an inner-class javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] and an imported javadoc:org.springframework.boot.test.context.TestConfiguration[format=annotation] will be processed before any configuration found through component scanning.\nGenerally speaking, this difference in ordering has no noticeable effect but it is something to be aware of if you're relying on bean overriding.\n\n\n\n[[testing.spring-boot-applications.using-application-arguments]]\n== Using Application Arguments\n\nIf your application expects xref:features/spring-application.adoc#features.spring-application.application-arguments[arguments], you can\nhave javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] inject them using the `args` attribute.\n\ninclude-code::MyApplicationArgumentTests[]\n\n\n\n[[testing.spring-boot-applications.with-mock-environment]]\n== Testing With a Mock Environment\n\nBy default, javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] does not start the server but instead sets up a mock environment for testing web endpoints.\n\nWith Spring MVC, we can query our web endpoints using {url-spring-framework-docs}/testing/mockmvc.html[`MockMvc`].\nThe following integrations are available:\n\n* The regular {url-spring-framework-docs}/testing/mockmvc/hamcrest.html[`MockMvc`] that uses Hamcrest.\n* {url-spring-framework-docs}/testing/mockmvc/assertj.html[`MockMvcTester`] that wraps javadoc:org.springframework.test.web.servlet.MockMvc[] and uses AssertJ.\n* {url-spring-framework-docs}/testing/resttestclient.html[`RestTestClient`] where javadoc:org.springframework.test.web.servlet.MockMvc[] is plugged in as the server to handle requests with.\n* {url-spring-framework-docs}/testing/webtestclient.html[`WebTestClient`] where javadoc:org.springframework.test.web.servlet.MockMvc[] is plugged in as the server to handle requests with.\n\nThe following example showcases the available integrations:\n\ninclude-code::MyMockMvcTests[]\n\nTIP: If you want to focus only on the web layer and not start a complete javadoc:org.springframework.context.ApplicationContext[], consider xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-mvc-tests[using javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] instead].\n\nWith Spring WebFlux endpoints, you can use {url-spring-framework-docs}/testing/webtestclient.html[`WebTestClient`] as shown in the following example:\n\ninclude-code::MyMockWebTestClientTests[]\n\n[TIP]\n====\nTesting within a mocked environment is usually faster than running with a full servlet container.\nHowever, since mocking occurs at the Spring MVC layer, code that relies on lower-level servlet container behavior cannot be directly tested with MockMvc.\n\nFor example, Spring Boot's error handling is based on the \"`error page`\" support provided by the servlet container.\nThis means that, whilst you can test your MVC layer throws and handles exceptions as expected, you cannot directly test that a specific xref:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[custom error page] is rendered.\nIf you need to test these lower-level concerns, you can start a fully running server as described in the next section.\n====\n\n\n\n[[testing.spring-boot-applications.with-running-server]]\n== Testing With a Running Server\n\nIf you need to start a full running server, we recommend that you use random ports.\nIf you use `@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)`, an available port is picked at random each time your test runs.\n\nThe javadoc:org.springframework.boot.test.web.server.LocalServerPort[format=annotation] annotation can be used to xref:how-to:webserver.adoc#howto.webserver.discover-port[inject the actual port used] into your test.\n\nTests that need to make REST calls to the started server can autowire a\n{url-spring-framework-docs}/testing/resttestclient.html[`RestTestClient`] by annotating the test class with javadoc:org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient[format=annotation].\n\nThe configured client resolves relative links to the running server and comes with a dedicated API for verifying responses, as shown in the following example:\n\ninclude-code::MyRandomPortRestTestClientTests[]\n\nIf you prefer to use AssertJ, dedicated assertions are available from javadoc:org.springframework.test.web.servlet.client.assertj.RestTestClientResponse[], as shown in the following example:\n\ninclude-code::MyRandomPortRestTestClientAssertJTests[]\n\nIf you have `spring-webflux` on the classpath, you can also autowire a {url-spring-framework-docs}/testing/webtestclient.html[`WebTestClient`] by annotating the test class with javadoc:org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient[format=annotation].\n\n`WebTestClient` provides a similar API, as shown in the following example:\n\ninclude-code::MyRandomPortWebTestClientTests[]\n\nTIP: javadoc:org.springframework.test.web.reactive.server.WebTestClient[] can also be used with a xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[mock environment], removing the need for a running server, by annotating your test class with javadoc:org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient[format=annotation] from `spring-boot-webflux-test`.\n\nNOTE: For certain xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[sliced tests] you may need to use the javadoc:org.springframework.boot.web.server.test.AutoConfigureWebServer[format=annotation] annotation to auto-configure an embedded web server.\n\nThe `spring-boot-resttestclient` module also provides a javadoc:org.springframework.boot.resttestclient.TestRestTemplate[] facility:\n\ninclude-code::MyRandomPortTestRestTemplateTests[]\n\nTo use `TestRestTemplate` a dependency on `spring-boot-restclient` is also required.\nTake care when adding this dependency as it will enable auto-configuration for `RestClient.Builder`.\nIf your main code uses `RestClient.Builder`, declare the `spring-boot-restclient` dependency so that it is on your application's main classpath and not only on its test classpath.\n\n\n\n[[testing.spring-boot-applications.customizing-rest-test-client]]\n== Customizing RestTestClient\n\nTo customize the javadoc:org.springframework.test.web.servlet.client.RestTestClient[] bean, configure a javadoc:org.springframework.boot.resttestclient.autoconfigure.RestTestClientBuilderCustomizer[] bean.\nAny such beans are called with the javadoc:org.springframework.test.web.servlet.client.RestTestClient$Builder[] that is used to create the javadoc:org.springframework.test.web.servlet.client.RestTestClient[].\n\n\n\n[[testing.spring-boot-applications.customizing-web-test-client]]\n== Customizing WebTestClient\n\nTo customize the javadoc:org.springframework.test.web.reactive.server.WebTestClient[] bean, configure a javadoc:org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer[] bean.\nAny such beans are called with the javadoc:org.springframework.test.web.reactive.server.WebTestClient$Builder[] that is used to create the javadoc:org.springframework.test.web.reactive.server.WebTestClient[].\n\n\n\n[[testing.spring-boot-applications.jmx]]\n== Using JMX\n\nAs the test context framework caches context, JMX is disabled by default to prevent identical components to register on the same domain.\nIf such test needs access to an javadoc:javax.management.MBeanServer[], consider marking it dirty as well:\n\ninclude-code::MyJmxTests[]\n\n\n\n[[testing.spring-boot-applications.observations]]\n== Using Observations\n\nIf you annotate xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[a sliced test] with javadoc:org.springframework.boot.micrometer.tracing.test.autoconfigure.AutoConfigureTracing[format=annotation] from `spring-boot-micrometer-tracing-test` or with javadoc:org.springframework.boot.micrometer.metrics.test.autoconfigure.AutoConfigureMetrics[format=annotation] from `spring-boot-micrometer-metrics-test`, it auto-configures an javadoc:io.micrometer.observation.ObservationRegistry[].\n\n\n\n[[testing.spring-boot-applications.metrics]]\n== Using Metrics\n\nRegardless of your classpath, meter registries, except the in-memory backed, are not auto-configured when using javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation].\n\nIf you need to export metrics to a different backend as part of an integration test, annotate it with javadoc:org.springframework.boot.micrometer.metrics.test.autoconfigure.AutoConfigureMetrics[format=annotation].\n\nIf you annotate xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[a sliced test] with javadoc:org.springframework.boot.micrometer.metrics.test.autoconfigure.AutoConfigureMetrics[format=annotation], it auto-configures an in-memory javadoc:io.micrometer.core.instrument.MeterRegistry[].\nData exporting in sliced tests is not supported with the javadoc:org.springframework.boot.micrometer.metrics.test.autoconfigure.AutoConfigureMetrics[format=annotation] annotation.\n\n\n\n[[testing.spring-boot-applications.tracing]]\n== Using Tracing\n\nRegardless of your classpath, tracing components which are reporting data are not auto-configured when using javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation].\n\nIf you need those components as part of an integration test, annotate the test with javadoc:org.springframework.boot.micrometer.tracing.test.autoconfigure.AutoConfigureTracing[format=annotation].\n\nIf you have created your own reporting components (e.g. a custom javadoc:io.opentelemetry.sdk.trace.export.SpanExporter[] or `brave.handler.SpanHandler`) and you don't want them to be active in tests, you can use the javadoc:org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport[format=annotation] annotation to disable them.\n\nIf you annotate xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-tests[a sliced test] with javadoc:org.springframework.boot.micrometer.tracing.test.autoconfigure.AutoConfigureTracing[format=annotation] , it auto-configures a no-op javadoc:io.micrometer.tracing.Tracer[].\nData exporting in sliced tests is not supported with the javadoc:org.springframework.boot.micrometer.tracing.test.autoconfigure.AutoConfigureTracing[format=annotation] annotation.\n\n\n\n[[testing.spring-boot-applications.mocking-beans]]\n== Mocking and Spying Beans\n\nWhen running tests, it is sometimes necessary to mock certain components within your application context.\nFor example, you may have a facade over some remote service that is unavailable during development.\nMocking can also be useful when you want to simulate failures that might be hard to trigger in a real environment.\n\nSpring Framework includes a javadoc:org.springframework.test.context.bean.override.mockito.MockitoBean[format=annotation] annotation that can be used to define a Mockito mock for a bean inside your javadoc:org.springframework.context.ApplicationContext[].\nAdditionally, javadoc:org.springframework.test.context.bean.override.mockito.MockitoSpyBean[format=annotation] can be used to define a Mockito spy.\nLearn more about these features in the {url-spring-framework-docs}/testing/annotations/integration-spring/annotation-mockitobean.html[Spring Framework documentation].\n\n\n\n[[testing.spring-boot-applications.autoconfigured-tests]]\n== Auto-configured Tests\n\nSpring Boot's auto-configuration system works well for applications but can sometimes be a little too much for tests.\nIt often helps to load only the parts of the configuration that are required to test a \"`slice`\" of your application.\nFor example, you might want to test that Spring MVC controllers are mapping URLs correctly, and you do not want to involve database calls in those tests, or you might want to test JPA entities, and you are not interested in the web layer when those tests run.\n\nWhen combined with `spring-boot-test-autoconfigure`, Spring Boot's xref:reference:testing/test-modules.adoc[test modules] include a number of annotations that can be used to automatically configure such \"`slices`\".\nEach of them works in a similar way, providing a `@...Test` annotation that loads the javadoc:org.springframework.context.ApplicationContext[] and one or more `@AutoConfigure...` annotations that can be used to customize auto-configuration settings.\n\nNOTE: Each slice restricts component scan to appropriate components and loads a very restricted set of auto-configuration classes.\nIf you need to exclude one of them, most `@...Test` annotations provide an `excludeAutoConfiguration` attribute.\nAlternatively, you can use `@ImportAutoConfiguration#exclude`.\n\nNOTE: Including multiple \"`slices`\" by using several `@...Test` annotations in one test is not supported.\nIf you need multiple \"`slices`\", pick one of the `@...Test` annotations and include the `@AutoConfigure...` annotations of the other \"`slices`\" by hand.\n\nTIP: It is also possible to use the `@AutoConfigure...` annotations with the standard javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] annotation.\nYou can use this combination if you are not interested in \"`slicing`\" your application but you want some of the auto-configured test beans.\n\n\n\n[[testing.spring-boot-applications.json-tests]]\n== Auto-configured JSON Tests\n\nTo test that object JSON serialization and deserialization is working as expected, you can use the javadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation] annotation from the `spring-boot-test-autoconfigure` module.\njavadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation] auto-configures the available supported JSON mapper, which can be one of the following libraries:\n\n* Jackson javadoc:tools.jackson.databind.json.JsonMapper[], any javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation] beans and any Jackson javadoc:tools.jackson.databind.JacksonModule[]\n* Jackson 2 (deprecated) javadoc:com.fasterxml.jackson.databind.ObjectMapper[], any javadoc:org.springframework.boot.jackson2.JsonComponent[format=annotation] beans and any Jackson javadoc:com.fasterxml.jackson.databind.Module[]\n* `Gson`\n* `Jsonb`\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nIf you need to configure elements of the auto-configuration, you can use the javadoc:org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters[format=annotation] annotation.\n\nSpring Boot includes AssertJ-based helpers that work with the JSONAssert and JsonPath libraries to check that JSON appears as expected.\nThe javadoc:org.springframework.boot.test.json.JacksonTester[], javadoc:org.springframework.boot.test.json.GsonTester[], javadoc:org.springframework.boot.test.json.JsonbTester[], and javadoc:org.springframework.boot.test.json.BasicJsonTester[] classes can be used for Jackson, Gson, Jsonb, and Strings respectively.\nAny helper fields on the test class can be javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] when using javadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation].\nThe following example shows a test class for Jackson:\n\ninclude-code::MyJsonTests[]\n\nNOTE: JSON helper classes can also be used directly in standard unit tests.\nTo do so, call the `initFields` method of the helper in your javadoc:org.junit.jupiter.api.BeforeEach[format=annotation] method if you do not use javadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation].\n\nIf you use Spring Boot's AssertJ-based helpers to assert on a number value at a given JSON path, you might not be able to use `isEqualTo` depending on the type.\nInstead, you can use AssertJ's `satisfies` to assert that the value matches the given condition.\nFor instance, the following example asserts that the actual number is a float value close to `0.15` within an offset of `0.01`.\n\ninclude-code::MyJsonAssertJTests[tag=*]\n\n\n\n[[testing.spring-boot-applications.spring-mvc-tests]]\n== Auto-configured Spring MVC Tests\n\nTo test whether Spring MVC controllers are working as expected, use the javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] annotation from the `spring-boot-webmvc-test` module.\njavadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] auto-configures the Spring MVC infrastructure and limits scanned beans to javadoc:org.springframework.stereotype.Controller[format=annotation],  javadoc:org.springframework.web.bind.annotation.ControllerAdvice[format=annotation], javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation], javadoc:org.springframework.boot.jackson2.JsonComponent[format=annotation] (deprecated), javadoc:org.springframework.core.convert.converter.Converter[], javadoc:org.springframework.core.convert.converter.GenericConverter[], javadoc:jakarta.servlet.Filter[], javadoc:org.springframework.web.servlet.HandlerInterceptor[], javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[], javadoc:org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations[], and javadoc:org.springframework.web.method.support.HandlerMethodArgumentResolver[].\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nTIP: If you need to register extra components, such as a javadoc:tools.jackson.databind.JacksonModule[], you can import additional configuration classes by using javadoc:org.springframework.context.annotation.Import[format=annotation] on your test.\n\nOften, javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] is limited to a single controller and is used in combination with javadoc:org.springframework.test.context.bean.override.mockito.MockitoBean[format=annotation] to provide mock implementations for required collaborators.\n\njavadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] also auto-configures javadoc:org.springframework.test.web.servlet.MockMvc[].\nMock MVC offers a powerful way to quickly test MVC controllers without needing to start a full HTTP server.\nIf AssertJ is available, the AssertJ support provided by javadoc:org.springframework.test.web.servlet.assertj.MockMvcTester[] is auto-configured as well.\nIf you'd like to use javadoc:org.springframework.test.web.servlet.client.RestTestClient[] in your tests, annotate your test class with javadoc:org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient[format=annotation].\nA `RestTestClient` that uses the Mock MVC infrastructure will then be auto-configured.\n\nTIP: You can also auto-configure javadoc:org.springframework.test.web.servlet.MockMvc[] and javadoc:org.springframework.test.web.servlet.assertj.MockMvcTester[] in a non-`@WebMvcTest` (such as javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation]) by annotating it with javadoc:org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc[format=annotation].\nThe following example uses javadoc:org.springframework.test.web.servlet.assertj.MockMvcTester[]:\n\ninclude-code::MyControllerTests[]\n\nTIP: If you need to configure elements of the auto-configuration (for example, when servlet filters should be applied) you can use attributes in the javadoc:org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc[format=annotation] annotation.\n\nIf you use HtmlUnit and Selenium, auto-configuration also provides an HtmlUnit javadoc:org.springframework.web.reactive.function.client.WebClient[] bean and/or a Selenium javadoc:org.openqa.selenium.WebDriver[] bean.\nThe following example uses HtmlUnit:\n\ninclude-code::MyHtmlUnitTests[]\n\nNOTE: By default, Spring Boot puts javadoc:org.openqa.selenium.WebDriver[] beans in a special \"`scope`\" to ensure that the driver exits after each test and that a new instance is injected.\nIf you do not want this behavior, you can add `@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)` to your javadoc:org.openqa.selenium.WebDriver[] javadoc:org.springframework.context.annotation.Bean[format=annotation] definition.\n\nWARNING: The `webDriver` scope created by Spring Boot will replace any user defined scope of the same name.\nIf you define your own `webDriver` scope you may find it stops working when you use javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation].\n\nIf you have Spring Security on the classpath, javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation] will also scan javadoc:org.springframework.security.config.annotation.web.WebSecurityConfigurer[] beans.\nInstead of disabling security completely for such tests, you can use Spring Security's test support.\nMore details on how to use Spring Security's javadoc:org.springframework.test.web.servlet.MockMvc[] support can be found in this xref:how-to:testing.adoc#howto.testing.with-spring-security[] \"`How-to Guides`\" section.\n\nTIP: Sometimes writing Spring MVC tests is not enough; Spring Boot can help you run xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[full end-to-end tests with an actual server].\n\n\n\n[[testing.spring-boot-applications.spring-webflux-tests]]\n== Auto-configured Spring WebFlux Tests\n\nTo test that {url-spring-framework-docs}/web-reactive.html[Spring WebFlux] controllers are working as expected, you can use the javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] annotation from the `spring-boot-webflux-test` module.\njavadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] auto-configures the Spring WebFlux infrastructure and limits scanned beans to javadoc:org.springframework.stereotype.Controller[format=annotation], javadoc:org.springframework.web.bind.annotation.ControllerAdvice[format=annotation], javadoc:org.springframework.boot.jackson.JacksonComponent[format=annotation], javadoc:org.springframework.boot.jackson2.JsonComponent[format=annotation] (deprecated), javadoc:org.springframework.core.convert.converter.Converter[], javadoc:org.springframework.core.convert.converter.GenericConverter[] and javadoc:org.springframework.web.reactive.config.WebFluxConfigurer[].\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nTIP: If you need to register extra components, such as a javadoc:tools.jackson.databind.JacksonModule[], you can import additional configuration classes using javadoc:org.springframework.context.annotation.Import[format=annotation] on your test.\n\nOften, javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] is limited to a single controller and used in combination with the javadoc:org.springframework.test.context.bean.override.mockito.MockitoBean[format=annotation] annotation to provide mock implementations for required collaborators.\n\njavadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] also auto-configures {url-spring-framework-docs}/testing/webtestclient.html[`WebTestClient`], which offers a powerful way to quickly test WebFlux controllers without needing to start a full HTTP server.\n\nTIP: You can also auto-configure javadoc:org.springframework.test.web.reactive.server.WebTestClient[] in a non-`@WebFluxTest` (such as javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation]) by annotating it with javadoc:org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient[format=annotation].\n\nThe following example shows a class that uses both javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] and a javadoc:org.springframework.test.web.reactive.server.WebTestClient[]:\n\ninclude-code::MyControllerTests[]\n\nTIP: This setup is only supported by WebFlux applications as using javadoc:org.springframework.test.web.reactive.server.WebTestClient[] in a mocked web application only works with WebFlux at the moment.\n\nNOTE: javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] cannot detect routes registered through the functional web framework.\nFor testing javadoc:org.springframework.web.reactive.function.server.RouterFunction[] beans in the context, consider importing your javadoc:org.springframework.web.reactive.function.server.RouterFunction[] yourself by using javadoc:org.springframework.context.annotation.Import[format=annotation] or by using javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation].\n\nNOTE: javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] cannot detect custom security configuration registered as a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.security.web.server.SecurityWebFilterChain[].\nTo include that in your test, you will need to import the configuration that registers the bean by using javadoc:org.springframework.context.annotation.Import[format=annotation] or by using javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation].\n\nTIP: Sometimes writing Spring WebFlux tests is not enough; Spring Boot can help you run xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[full end-to-end tests with an actual server].\n\n\n\n[[testing.spring-boot-applications.spring-graphql-tests]]\n== Auto-configured Spring GraphQL Tests\n\nSpring GraphQL offers a dedicated testing support module; you'll need to add it to your project:\n\n.Maven\n[source,xml]\n----\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.graphql</groupId>\n\t\t<artifactId>spring-graphql-test</artifactId>\n\t\t<scope>test</scope>\n\t</dependency>\n\t<!-- Unless already present in the compile scope -->\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-webflux</artifactId>\n\t\t<scope>test</scope>\n\t</dependency>\n</dependencies>\n----\n\n.Gradle\n[source,gradle]\n----\ndependencies {\n\ttestImplementation(\"org.springframework.graphql:spring-graphql-test\")\n\t// Unless already present in the implementation configuration\n\ttestImplementation(\"org.springframework.boot:spring-boot-starter-webflux\")\n}\n----\n\nThis testing module ships the {url-spring-graphql-docs}/testing.html#testing.graphqltester[GraphQlTester].\nThe tester is heavily used in test, so be sure to become familiar with using it.\nThere are javadoc:org.springframework.graphql.test.tester.GraphQlTester[] variants and Spring Boot will auto-configure them depending on the type of tests:\n\n* the javadoc:org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester[] performs tests on the server side, without a client nor a transport\n* the javadoc:org.springframework.graphql.test.tester.HttpGraphQlTester[] performs tests with a client that connects to a server, with or without a live server\n\nSpring Boot helps you to test your {url-spring-graphql-docs}/controllers.html[Spring GraphQL Controllers] with the javadoc:org.springframework.boot.graphql.test.autoconfigure.GraphQlTest[format=annotation] annotation from the `spring-boot-graphql-test` module.\njavadoc:org.springframework.boot.graphql.test.autoconfigure.GraphQlTest[format=annotation] auto-configures the Spring GraphQL infrastructure, without any transport nor server being involved.\nThis limits scanned beans to javadoc:org.springframework.stereotype.Controller[format=annotation], javadoc:org.springframework.web.bind.annotation.ControllerAdvice[format=annotation], javadoc:org.springframework.graphql.execution.RuntimeWiringConfigurer[], javadoc:org.springframework.boot.jackson.JacksonComponent[], javadoc:org.springframework.boot.jackson2.JsonComponent[format=annotation] (deprecated), javadoc:org.springframework.core.convert.converter.Converter[], javadoc:org.springframework.core.convert.converter.GenericConverter[], javadoc:org.springframework.graphql.execution.DataFetcherExceptionResolver[], javadoc:graphql.execution.instrumentation.Instrumentation[] and javadoc:org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer[].\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.graphql.test.autoconfigure.GraphQlTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.graphql.test.autoconfigure.GraphQlTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nOften, javadoc:org.springframework.boot.graphql.test.autoconfigure.GraphQlTest[format=annotation] is limited to a set of controllers and used in combination with the javadoc:org.springframework.test.context.bean.override.mockito.MockitoBean[format=annotation] annotation to provide mock implementations for required collaborators.\n\ninclude-code::GreetingControllerTests[]\n\njavadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] tests are full integration tests and involve the entire application.\nA javadoc:org.springframework.graphql.test.tester.HttpGraphQlTester[] bean can be added by annotating your test class with javadoc:org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester[format=annotation] from the `spring-boot-graphql-test` module:\n\ninclude-code::GraphQlIntegrationTests[]\n\nThe javadoc:org.springframework.graphql.test.tester.HttpGraphQlTester[] bean uses the relevant transport of the integration test.\nWhen using a random or defined port, the tester is configured against the live server.\nTo bind the tester to `MockMvc`, make sure to annotate your test class with javadoc:org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc[format=annotation].\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-cassandra]]\n== Auto-configured Data Cassandra Tests\n\nYou can use javadoc:org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest[format=annotation] from the `spring-boot-data-cassandra-test` module to test Data Cassandra applications.\nBy default, it configures a javadoc:org.springframework.data.cassandra.core.CassandraTemplate[], scans for javadoc:org.springframework.data.cassandra.core.mapping.Table[format=annotation] classes, and configures Spring Data Cassandra repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using Cassandra with Spring Boot, see xref:data/nosql.adoc#data.nosql.cassandra[].)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows a typical setup for using Cassandra tests in Spring Boot:\n\ninclude-code::MyDataCassandraTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-couchbase]]\n== Auto-configured Data Couchbase Tests\n\nYou can use javadoc:org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest[format=annotation] from the `spring-boot-data-couchbase-test` module to test Data Couchbase applications.\nBy default, it configures a javadoc:org.springframework.data.couchbase.core.CouchbaseTemplate[] or javadoc:org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate[], scans for javadoc:org.springframework.data.couchbase.core.mapping.Document[format=annotation] classes, and configures Spring Data Couchbase repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using Couchbase with Spring Boot, see xref:data/nosql.adoc#data.nosql.couchbase[], earlier in this chapter.)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows a typical setup for using Couchbase tests in Spring Boot:\n\ninclude-code::MyDataCouchbaseTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-elasticsearch]]\n== Auto-configured Data Elasticsearch Tests\n\nYou can use javadoc:org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest[format=annotation] from the `spring-boot-data-elasticsearch-test` module to test Data Elasticsearch applications.\nBy default, it configures an javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate[], scans for javadoc:org.springframework.data.elasticsearch.annotations.Document[format=annotation] classes, and configures Spring Data Elasticsearch repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using Elasticsearch with Spring Boot, see xref:data/nosql.adoc#data.nosql.elasticsearch[], earlier in this chapter.)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows a typical setup for using Elasticsearch tests in Spring Boot:\n\ninclude-code::MyDataElasticsearchTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-jpa]]\n== Auto-configured Data JPA Tests\n\nYou can use the javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation] annotation from the `spring-boot-data-jpa-test` module to test Data JPA applications.\nBy default, it scans for javadoc:jakarta.persistence.Entity[format=annotation] classes and configures Spring Data JPA repositories.\nIf an embedded database is available on the classpath, it configures one as well.\nSQL queries are logged by default by setting the `spring.jpa.show-sql` property to `true`.\nThis can be disabled using the `showSql` attribute of the annotation.\n\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nBy default, data JPA tests are transactional and roll back at the end of each test.\nSee the {url-spring-framework-docs}/testing/testcontext-framework/tx.html#testcontext-tx-enabling-transactions[relevant section] in the Spring Framework Reference Documentation for more details.\nIf that is not what you want, you can disable transaction management for a test or for the whole class as follows:\n\ninclude-code::MyNonTransactionalTests[]\n\nData JPA tests may also inject a javadoc:org.springframework.boot.jpa.test.autoconfigure.TestEntityManager[] bean, which provides an alternative to the standard JPA javadoc:jakarta.persistence.EntityManager[] that is specifically designed for tests.\n\nTIP: javadoc:org.springframework.boot.jpa.test.autoconfigure.TestEntityManager[] can also be auto-configured to any of your Spring-based test class by adding javadoc:org.springframework.boot.jpa.test.autoconfigure.AutoConfigureTestEntityManager[format=annotation].\nWhen doing so, make sure that your test is running in a transaction, for instance by adding  javadoc:org.springframework.transaction.annotation.Transactional[format=annotation] on your test class or method.\n\nA javadoc:org.springframework.jdbc.core.JdbcTemplate[] is also available if you need that.\nThe following example shows the javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation] annotation in use:\n\ninclude-code::withoutdb/MyRepositoryTests[]\n\nIn-memory embedded databases generally work well for tests, since they are fast and do not require any installation.\nIf, however, you prefer to run tests against a real database you can use the javadoc:org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase[format=annotation] annotation, as shown in the following example:\n\ninclude-code::withdb/MyRepositoryTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-jdbc]]\n== Auto-configured JDBC Tests\n\njavadoc:org.springframework.boot.jdbc.test.autoconfigure.JdbcTest[format=annotation] from the `spring-boot-jdbc-test` module is similar to javadoc:org.springframework.boot.data.jdbc.test.autoconfigure.DataJdbcTest[format=annotation] but is for tests that only require a javadoc:javax.sql.DataSource[] and do not use Spring Data JDBC.\nBy default, it configures an in-memory embedded database and a javadoc:org.springframework.jdbc.core.JdbcTemplate[].\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.jdbc.test.autoconfigure.JdbcTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.jdbc.test.autoconfigure.JdbcTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nBy default, JDBC tests are transactional and roll back at the end of each test.\nSee the {url-spring-framework-docs}/testing/testcontext-framework/tx.html#testcontext-tx-enabling-transactions[relevant section] in the Spring Framework Reference Documentation for more details.\nIf that is not what you want, you can disable transaction management for a test or for the whole class, as follows:\n\ninclude-code::MyTransactionalTests[]\n\nIf you prefer your test to run against a real database, you can use the javadoc:org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase[format=annotation] annotation in the same way as for javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation].\n(See xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[].)\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-jdbc]]\n== Auto-configured Data JDBC Tests\n\njavadoc:org.springframework.boot.data.jdbc.test.autoconfigure.DataJdbcTest[format=annotation] from the `spring-boot-data-jdbc-test` module is similar to javadoc:org.springframework.boot.jdbc.test.autoconfigure.JdbcTest[format=annotation] but is for tests that use Spring Data JDBC repositories.\nBy default, it configures an in-memory embedded database, a javadoc:org.springframework.jdbc.core.JdbcTemplate[], and Spring Data JDBC repositories.\nOnly javadoc:org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration[] subclasses are scanned when the javadoc:org.springframework.boot.data.jdbc.test.autoconfigure.DataJdbcTest[format=annotation] annotation is used, regular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.data.jdbc.test.autoconfigure.DataJdbcTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nBy default, Data JDBC tests are transactional and roll back at the end of each test.\nSee the {url-spring-framework-docs}/testing/testcontext-framework/tx.html#testcontext-tx-enabling-transactions[relevant section] in the Spring Framework Reference Documentation for more details.\nIf that is not what you want, you can disable transaction management for a test or for the whole test class as xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[shown in the JDBC example].\n\nIf you prefer your test to run against a real database, you can use the javadoc:org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase[format=annotation] annotation in the same way as for javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation].\n(See xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[].)\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-r2dbc]]\n== Auto-configured Data R2DBC Tests\n\njavadoc:org.springframework.boot.data.r2dbc.test.autoconfigure.DataR2dbcTest[format=annotation] from the `spring-boot-data-r2dbc-test` module is similar to javadoc:org.springframework.boot.data.jdbc.test.autoconfigure.DataJdbcTest[format=annotation] but is for tests that use Spring Data R2DBC repositories.\nBy default, it configures an in-memory embedded database, an javadoc:org.springframework.data.r2dbc.core.R2dbcEntityTemplate[], and Spring Data R2DBC repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.r2dbc.test.autoconfigure.DataR2dbcTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.data.r2dbc.test.autoconfigure.DataR2dbcTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nBy default, Data R2DBC tests are not transactional.\n\nIf you prefer your test to run against a real database, you can use the javadoc:org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase[format=annotation] annotation in the same way as for javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation].\n(See xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-spring-data-jpa[].)\n\n\n\n[[testing.spring-boot-applications.autoconfigured-jooq]]\n== Auto-configured jOOQ Tests\n\nYou can use javadoc:org.springframework.boot.jooq.test.autoconfigure.JooqTest[format=annotation] from `spring-boot-jooq-test` in a similar fashion as javadoc:org.springframework.boot.jdbc.test.autoconfigure.JdbcTest[format=annotation] but for jOOQ-related tests.\nAs jOOQ relies heavily on a Java-based schema that corresponds with the database schema, the existing javadoc:javax.sql.DataSource[] is used.\nIf you want to replace it with an in-memory database, you can use javadoc:org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase[format=annotation] to override those settings.\n(For more about using jOOQ with Spring Boot, see xref:data/sql.adoc#data.sql.jooq[].)\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.jooq.test.autoconfigure.JooqTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.jooq.test.autoconfigure.JooqTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\njavadoc:org.springframework.boot.jooq.test.autoconfigure.JooqTest[format=annotation] configures a javadoc:org.jooq.DSLContext[].\nThe following example shows the javadoc:org.springframework.boot.jooq.test.autoconfigure.JooqTest[format=annotation] annotation in use:\n\ninclude-code::MyJooqTests[]\n\nJOOQ tests are transactional and roll back at the end of each test by default.\nIf that is not what you want, you can disable transaction management for a test or for the whole test class as xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.autoconfigured-jdbc[shown in the JDBC example].\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-mongodb]]\n== Auto-configured Data MongoDB Tests\n\nYou can use javadoc:org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest[format=annotation] from the `spring-boot-data-mongodb-test` module to test MongoDB applications.\nBy default, it configures a javadoc:org.springframework.data.mongodb.core.MongoTemplate[], scans for javadoc:org.springframework.data.mongodb.core.mapping.Document[format=annotation] classes, and configures Spring Data MongoDB repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using MongoDB with Spring Boot, see xref:data/nosql.adoc#data.nosql.mongodb[].)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following class shows the javadoc:org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest[format=annotation] annotation in use:\n\ninclude-code::MyDataMongoDbTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-neo4j]]\n== Auto-configured Data Neo4j Tests\n\nYou can use javadoc:org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest[format=annotation] from the `spring-boot-data-neo4j-test` module to test Neo4j applications.\nBy default, it scans for javadoc:org.springframework.data.neo4j.core.schema.Node[format=annotation] classes, and configures Spring Data Neo4j repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using Neo4J with Spring Boot, see xref:data/nosql.adoc#data.nosql.neo4j[].)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows a typical setup for using Neo4J tests in Spring Boot:\n\ninclude-code::propagation/MyDataNeo4jTests[]\n\nBy default, Data Neo4j tests are transactional and roll back at the end of each test.\nSee the {url-spring-framework-docs}/testing/testcontext-framework/tx.html#testcontext-tx-enabling-transactions[relevant section] in the Spring Framework Reference Documentation for more details.\nIf that is not what you want, you can disable transaction management for a test or for the whole class, as follows:\n\ninclude-code::nopropagation/MyDataNeo4jTests[]\n\nNOTE: Transactional tests are not supported with reactive access.\nIf you are using this style, you must configure javadoc:org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest[format=annotation] tests as described above.\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-redis]]\n== Auto-configured Data Redis Tests\n\nYou can use javadoc:org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest[format=annotation] from the `spring-boot-data-redis-test` module to test Data Redis applications.\nBy default, it scans for javadoc:org.springframework.data.redis.core.RedisHash[format=annotation] classes and configures Spring Data Redis repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using Redis with Spring Boot, see xref:data/nosql.adoc#data.nosql.redis[].)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows the javadoc:org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest[format=annotation] annotation in use:\n\ninclude-code::MyDataRedisTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-data-ldap]]\n== Auto-configured Data LDAP Tests\n\nYou can use javadoc:org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest[format=annotation] to test Data LDAP applications.\nBy default, it configures an in-memory embedded LDAP (if available), configures an javadoc:org.springframework.ldap.core.LdapTemplate[], scans for javadoc:org.springframework.ldap.odm.annotations.Entry[format=annotation] classes, and configures Spring Data LDAP repositories.\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n(For more about using LDAP with Spring Boot, see xref:data/nosql.adoc#data.nosql.ldap[].)\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows the javadoc:org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest[format=annotation] annotation in use:\n\ninclude-code::inmemory/MyDataLdapTests[]\n\nIn-memory embedded LDAP generally works well for tests, since it is fast and does not require any developer installation.\nIf, however, you prefer to run tests against a real LDAP server, you should exclude the embedded LDAP auto-configuration, as shown in the following example:\n\ninclude-code::server/MyDataLdapTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-rest-client]]\n== Auto-configured REST Clients\n\nYou can use the javadoc:org.springframework.boot.restclient.test.autoconfigure.RestClientTest[format=annotation] annotation from the `spring-boot-restclient-test` module to test REST clients.\nBy default, it auto-configures Jackson, GSON, and Jsonb support, configures a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] and a javadoc:org.springframework.web.client.RestClient$Builder[], and adds support for javadoc:org.springframework.test.web.client.MockRestServiceServer[].\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.restclient.test.autoconfigure.RestClientTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.restclient.test.autoconfigure.RestClientTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe specific beans that you want to test should be specified by using the `value` or `components` attribute of javadoc:org.springframework.boot.restclient.test.autoconfigure.RestClientTest[format=annotation].\n\nWhen using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] in the beans under test and `RestTemplateBuilder.rootUri(String rootUri)` has been called when building the javadoc:org.springframework.web.client.RestTemplate[], then the root URI should be omitted from the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example:\n\ninclude-code::MyRestTemplateServiceTests[]\n\nWhen using a javadoc:org.springframework.web.client.RestClient$Builder[] in the beans under test, or when using a javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] without calling `rootUri(String rootURI)`, the full URI must be used in the javadoc:org.springframework.test.web.client.MockRestServiceServer[] expectations as shown in the following example:\n\ninclude-code::MyRestClientServiceTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-web-client]]\n== Auto-configured Web Clients\n\nYou can use the javadoc:org.springframework.boot.webclient.test.autoconfigure.WebClientTest[format=annotation] annotation from the `spring-boot-webclient-test` module to test code that uses `WebClient`.\nBy default, it auto-configures Jackson, GSON, and Jsonb support, and configures a javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[].\nRegular javadoc:org.springframework.stereotype.Component[format=annotation] and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans are not scanned when the javadoc:org.springframework.boot.webclient.test.autoconfigure.WebClientTest[format=annotation] annotation is used.\njavadoc:org.springframework.boot.context.properties.EnableConfigurationProperties[format=annotation] can be used to include javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] beans.\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.webclient.test.autoconfigure.WebClientTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe specific beans that you want to test should be specified by using the `value` or `components` attribute of javadoc:org.springframework.boot.webclient.test.autoconfigure.WebClientTest[format=annotation].\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-restdocs]]\n== Auto-configured Spring REST Docs Tests\n\nYou can use the javadoc:org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs[format=annotation] annotation from the `spring-boot-restdocs- module to use {url-spring-restdocs-site}[Spring REST Docs] in your tests with Mock MVC or WebTestClient.\nIt removes the need for the JUnit extension in Spring REST Docs.\n\njavadoc:org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs[format=annotation] can be used to override the default output directory (`target/generated-snippets` if you are using Maven or `build/generated-snippets` if you are using Gradle).\nIt can also be used to configure the host, scheme, and port that appears in any documented URIs.\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-restdocs.with-mock-mvc]]\n=== Auto-configured Spring REST Docs Tests With Mock MVC\n\njavadoc:org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs[format=annotation] customizes the javadoc:org.springframework.test.web.servlet.MockMvc[] bean to use Spring REST Docs when testing servlet-based web applications.\nYou can inject it by using javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] and use it in your tests as you normally would when using Mock MVC and Spring REST Docs, as shown in the following example:\n\ninclude-code::hamcrest/MyUserDocumentationTests[]\n\nIf you prefer to use the AssertJ integration, javadoc:org.springframework.test.web.servlet.assertj.MockMvcTester[] is available as well, as shown in the following example:\n\ninclude-code::assertj/MyUserDocumentationTests[]\n\nBoth reuses the same javadoc:org.springframework.test.web.servlet.MockMvc[] instance behind the scenes so any configuration to it applies to both.\n\nIf you require more control over Spring REST Docs configuration than offered by the attributes of javadoc:org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs[format=annotation], you can use a javadoc:org.springframework.boot.restdocs.test.autoconfigure.RestDocsMockMvcConfigurationCustomizer[] bean, as shown in the following example:\n\ninclude-code::MyRestDocsConfiguration[]\n\nIf you want to make use of Spring REST Docs support for a parameterized output directory, you can create a javadoc:org.springframework.restdocs.mockmvc.RestDocumentationResultHandler[] bean.\nThe auto-configuration calls `alwaysDo` with this result handler, thereby causing each javadoc:org.springframework.test.web.servlet.MockMvc[] call to automatically generate the default snippets.\nThe following example shows a javadoc:org.springframework.restdocs.mockmvc.RestDocumentationResultHandler[] being defined:\n\ninclude-code::MyResultHandlerConfiguration[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-spring-restdocs.with-web-test-client]]\n=== Auto-configured Spring REST Docs Tests With WebTestClient\n\njavadoc:org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs[format=annotation] can also be used with javadoc:org.springframework.test.web.reactive.server.WebTestClient[] when testing reactive web applications.\nYou can inject it by using javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] and use it in your tests as you normally would when using javadoc:org.springframework.boot.webflux.test.autoconfigure.WebFluxTest[format=annotation] and Spring REST Docs, as shown in the following example:\n\ninclude-code::MyUsersDocumentationTests[]\n\nIf you require more control over Spring REST Docs configuration than offered by the attributes of javadoc:org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs[format=annotation], you can use a javadoc:org.springframework.boot.restdocs.test.autoconfigure.RestDocsWebTestClientConfigurationCustomizer[] bean, as shown in the following example:\n\ninclude-code::MyRestDocsConfiguration[]\n\nIf you want to make use of Spring REST Docs support for a parameterized output directory, you can use a javadoc:org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer[] to configure a consumer for every entity exchange result.\nThe following example shows such a javadoc:org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer[] being defined:\n\ninclude-code::MyWebTestClientBuilderCustomizerConfiguration[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-webservices]]\n== Auto-configured Spring Web Services Tests\n\n\n\n[[testing.spring-boot-applications.autoconfigured-webservices.client]]\n=== Auto-configured Spring Web Services Client Tests\n\nYou can use javadoc:org.springframework.boot.webservices.test.autoconfigure.client.WebServiceClientTest[format=annotation] from the `spring-boot-webservices-test` module to test applications that call web services using the Spring Web Services project.\nBy default, it configures a javadoc:org.springframework.ws.test.client.MockWebServiceServer[] bean and automatically customizes your javadoc:org.springframework.boot.webservices.client.WebServiceTemplateBuilder[].\n(For more about using Web Services with Spring Boot, see xref:io/webservices.adoc[].)\n\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.webservices.test.autoconfigure.client.WebServiceClientTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows the javadoc:org.springframework.boot.webservices.test.autoconfigure.client.WebServiceClientTest[format=annotation] annotation in use:\n\ninclude-code::MyWebServiceClientTests[]\n\n\n\n[[testing.spring-boot-applications.autoconfigured-webservices.server]]\n=== Auto-configured Spring Web Services Server Tests\n\nYou can use javadoc:org.springframework.boot.webservices.test.autoconfigure.server.WebServiceServerTest[format=annotation] from the `spring-boot-webservices-test` module to test applications that implement web services using the Spring Web Services project.\nBy default, it configures a javadoc:org.springframework.ws.test.server.MockWebServiceClient[] bean that can be used to call your web service endpoints.\n(For more about using Web Services with Spring Boot, see xref:io/webservices.adoc[].)\n\n\nTIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.webservices.test.autoconfigure.server.WebServiceServerTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].\n\nThe following example shows the javadoc:org.springframework.boot.webservices.test.autoconfigure.server.WebServiceServerTest[format=annotation] annotation in use:\n\ninclude-code::MyWebServiceServerTests[]\n\n\n\n[[testing.spring-boot-applications.additional-autoconfiguration-and-slicing]]\n== Additional Auto-configuration and Slicing\n\nEach slice provides one or more `@AutoConfigure...` annotations that namely defines the auto-configurations that should be included as part of a slice.\nAdditional auto-configurations can be added on a test-by-test basis by creating a custom `@AutoConfigure...` annotation or by adding javadoc:org.springframework.boot.autoconfigure.ImportAutoConfiguration[format=annotation] to the test as shown in the following example:\n\ninclude-code::MyJdbcTests[]\n\nNOTE: Make sure to not use the regular javadoc:org.springframework.context.annotation.Import[format=annotation] annotation to import auto-configurations as they are handled in a specific way by Spring Boot.\n\nAlternatively, additional auto-configurations can be added for any use of a slice annotation by registering them in a file stored in `META-INF/spring` as shown in the following example:\n\n.META-INF/spring/org.springframework.boot.jdbc.test.autoconfigure.JdbcTest.imports\n[source]\n----\ncom.example.IntegrationAutoConfiguration\n----\n\nIn this example, the `+com.example.IntegrationAutoConfiguration+` is enabled on every test annotated with javadoc:org.springframework.boot.jdbc.test.autoconfigure.JdbcTest[format=annotation].\n\nTIP: You can use comments with `#` in this file.\n\nTIP: A slice or `@AutoConfigure...` annotation can be customized this way as long as it is meta-annotated with javadoc:org.springframework.boot.autoconfigure.ImportAutoConfiguration[format=annotation].\n\n\n\n[[testing.spring-boot-applications.user-configuration-and-slicing]]\n== User Configuration and Slicing\n\nIf you xref:using/structuring-your-code.adoc[structure your code] in a sensible way, your javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] class is xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[used by default] as the configuration of your tests.\n\nIt then becomes important not to litter the application's main class with configuration settings that are specific to a particular area of its functionality.\n\nAssume that you are using Spring Data MongoDB, you rely on the auto-configuration for it, and you have enabled auditing.\nYou could define your javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] as follows:\n\ninclude-code::MyApplication[]\n\nBecause this class is the source configuration for the test, any slice test actually tries to enable Mongo auditing, which is definitely not what you want to do.\nA recommended approach is to move that area-specific configuration to a separate javadoc:org.springframework.context.annotation.Configuration[format=annotation] class at the same level as your application, as shown in the following example:\n\ninclude-code::MyMongoConfiguration[]\n\nNOTE: Depending on the complexity of your application, you may either have a single javadoc:org.springframework.context.annotation.Configuration[format=annotation] class for your customizations or one class per domain area.\nThe latter approach lets you enable it in one of your tests, if necessary, with the javadoc:org.springframework.context.annotation.Import[format=annotation] annotation.\nSee xref:how-to:testing.adoc#howto.testing.slice-tests[this how-to section] for more details on when you might want to enable specific javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes for slice tests.\n\nTest slices exclude javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes from scanning.\nFor example, for a javadoc:org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest[format=annotation], the following configuration will not include the given javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] bean in the application context loaded by the test slice:\n\ninclude-code::MyWebConfiguration[]\n\nThe configuration below will, however, cause the custom javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] to be loaded by the test slice.\n\ninclude-code::MyWebMvcConfigurer[]\n\nAnother source of confusion is classpath scanning.\nAssume that, while you structured your code in a sensible way, you need to scan an additional package.\nYour application may resemble the following code:\n\ninclude-code::scan/MyApplication[]\n\nDoing so effectively overrides the default component scan directive with the side effect of scanning those two packages regardless of the slice that you chose.\nFor instance, a javadoc:org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest[format=annotation] seems to suddenly scan components and user configurations of your application.\nAgain, moving the custom directive to a separate class is a good way to fix this issue.\n\nTIP: If this is not an option for you, you can create a javadoc:org.springframework.boot.SpringBootConfiguration[format=annotation] somewhere in the hierarchy of your test so that it is used instead.\nAlternatively, you can specify a source for your test, which disables the behavior of finding a default one.\n\n\n\n[[testing.spring-boot-applications.spock]]\n== Using Spock to Test Spring Boot Applications\n\nSpock 2.4 or later can be used to test a Spring Boot application.\nTo do so, add a dependency on a `-groovy-5.0` version of Spock's `spock-spring` module to your application's build.\n`spock-spring` integrates Spring's test framework into Spock.\nSee https://spockframework.org/spock/docs/2.4/modules.html#spring-module[the documentation for Spock's Spring module] for further details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/test-modules.adoc",
    "content": "[[testing.test-modules]]\n= Test Modules\n\nSpring Boot offers several focused, feature-specific `-test` modules:\n\n[cols=\"1,3\"]\n|===\n|Module | Purpose\n\n|`spring-boot-cache-test`\n|Testing applications that use Spring Framework's cache abstraction.\n\n|`spring-boot-data-cassandra-test`\n|Testing applications that use Spring Data Cassandra. Provides the `@DataCassandraTest` test slice.\n\n|`spring-boot-data-couchbase-test`\n|Testing applications that use Spring Data Couchbase. Provides the `@DataCouchbaseTest` test slice.\n\n|`spring-boot-data-elasticsearch-test`\n|Testing applications that use Spring Data Elasticsearch. Provides the `@DataElasticsearchTest` test slice.\n\n|`spring-boot-data-jdbc-test`\n|Testing applications that use Spring Data JDBC. Provides the `@DataJdbcTest` test slice.\n\n|`spring-boot-data-jpa-test`\n|Testing applications that use Spring Data JPA. Provides the `@DataJpaTest` test slice.\n\n|`spring-boot-data-ldap-test`\n|Testing applications that use Spring Data LDAP. Provides the `@DataLdapTest` test slice.\n\n|`spring-boot-mongodb-test`\n|Testing applications that use Spring Data MongoDB. Provides the `@DataMongoTest` test slice.\n\n|`spring-boot-data-neo4j-test`\n|Testing applications that use Spring Data JPA. Provides the `@DataNeo4jTest` test slice.\n\n|`spring-boot-data-r2dbc-test`\n|Testing applications that use Spring Data R2DBC. Provides the `@DataR2dbcTest` test slice.\n\n|`spring-boot-data-redis-test`\n|Testing applications that use Spring Data Redis. Provides the `@DataRedisTest` test slice.\n\n|`spring-boot-graphql-test`\n|Testing applications that use Spring GraphQL. Provides the `@GraphQlTest` test slice.\n\n|`spring-boot-grpc-test`\n|Testing applications that use Spring gRPC.\n\n|`spring-boot-jdbc-test`\n|Testing applications that using Spring JDBC. Provides the `@JdbcTest` test slice.\n\n|`spring-boot-jooq-test`\n|Testing applications that using jOOQ. Provides the `@JooqTest` test slice.\n\n|`spring-boot-jpa-test`\n|Testing applications that use JPA.\n\n|`spring-boot-micrometer-metrics-test`\n|Testing applications that use Micrometer Metrics.\n\n|`spring-boot-micrometer-tracing-test`\n|Testing applications that use Micrometer Tracing.\n\n|`spring-boot-restclient-test`\n|Testing applications that use REST clients. Provides the `@RestClientTest` test slice.\n\n|`spring-boot-security-test`\n|Testing applications that use Spring Security.\n\n|`spring-boot-webserver-test`\n|Testing applications that use `WebServer` implementations. Provides the `@AutoconfigureWebServer` annotation.\n\n|`spring-boot-webclient-test`\n|Testing applications that use `WebClient`. Provides the `@WebClientTest` test slice.\n\n|`spring-boot-webflux-test`\n|Testing applications that use Spring WebFlux. Provides the `@WebFluxTest` test slice.\n\n|`spring-boot-webmvc-test`\n|Testing applications that use Spring Web MVC. Provides the `@WebMvcTest` test slice.\n\n|`spring-boot-webservices-test`\n|Testing applications that use Spring Web Services. Provides the `@WebServiceClientTest` and `@WebServiceServerTest` test slices.\n\n|==="
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/test-scope-dependencies.adoc",
    "content": "[[testing.test-scope-dependencies]]\n= Test Scope Dependencies\n\nThe `spring-boot-starter-test` starter (in the `test` `scope`) contains the following provided libraries:\n\n* https://junit.org[JUnit]: The de-facto standard for unit testing Java applications.\n* {url-spring-framework-docs}/testing/integration.html[Spring Test] & Spring Boot Test: Utilities and integration test support for Spring Boot applications.\n* https://assertj.github.io/doc/[AssertJ]: A fluent assertion library.\n* https://github.com/hamcrest/JavaHamcrest[Hamcrest]: A library of matcher objects (also known as constraints or predicates).\n* https://site.mockito.org/[Mockito]: A Java mocking framework.\n* https://github.com/skyscreamer/JSONassert[JSONassert]: An assertion library for JSON.\n* https://github.com/jayway/JsonPath[JsonPath]: XPath for JSON.\n* https://github.com/awaitility/awaitility[Awaitility]: A library for testing asynchronous systems.\n\nWe generally find these common libraries to be useful when writing tests.\nIf these libraries do not suit your needs, you can add additional test dependencies of your own.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/test-utilities.adoc",
    "content": "[[testing.utilities]]\n= Test Utilities\n\nA few test utility classes that are generally useful when testing your application are packaged as part of `spring-boot`.\n\n\n\n[[testing.utilities.config-data-application-context-initializer]]\n== ConfigDataApplicationContextInitializer\n\njavadoc:org.springframework.boot.test.context.ConfigDataApplicationContextInitializer[] is an javadoc:org.springframework.context.ApplicationContextInitializer[] that you can apply to your tests to load Spring Boot `application.properties` files.\nYou can use it when you do not need the full set of features provided by javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation], as shown in the following example:\n\ninclude-code::MyConfigFileTests[]\n\nNOTE: Using javadoc:org.springframework.boot.test.context.ConfigDataApplicationContextInitializer[] alone does not provide support for `@Value(\"${...}\")` injection.\nIts only job is to ensure that `application.properties` files are loaded into Spring's javadoc:org.springframework.core.env.Environment[].\nFor javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] support, you need to either additionally configure a javadoc:org.springframework.context.support.PropertySourcesPlaceholderConfigurer[] or use javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation], which auto-configures one for you.\n\n\n\n[[testing.utilities.test-property-values]]\n== TestPropertyValues\n\njavadoc:org.springframework.boot.test.util.TestPropertyValues[] lets you quickly add properties to a javadoc:org.springframework.core.env.ConfigurableEnvironment[] or javadoc:org.springframework.context.ConfigurableApplicationContext[].\nYou can call it with `key=value` strings, as follows:\n\ninclude-code::MyEnvironmentTests[]\n\n\n\n[[testing.utilities.output-capture]]\n== OutputCaptureExtension\n\njavadoc:org.springframework.boot.test.system.OutputCaptureExtension[] is a JUnit javadoc:org.junit.jupiter.api.extension.Extension[] that you can use to capture javadoc:java.lang.System#out[] and javadoc:java.lang.System#err[] output.\nTo use it, add `@ExtendWith(OutputCaptureExtension.class)` and inject javadoc:org.springframework.boot.test.system.CapturedOutput[] as an argument to your test class constructor or test method as follows:\n\ninclude-code::MyOutputCaptureTests[]\n\n\n\n[[testing.utilities.test-rest-template]]\n== TestRestTemplate\n\njavadoc:org.springframework.boot.resttestclient.TestRestTemplate[] is a convenience alternative to Spring's javadoc:org.springframework.web.client.RestTemplate[] that is useful in integration tests.\nIt's provided by the `spring-boot-resttestclient` module.\nA dependency on `spring-boot-restclient` is also required.\nTake care when adding this dependency as it will enable auto-configuration for `RestClient.Builder`.\nIf your main code uses `RestClient.Builder`, declare the `spring-boot-restclient` dependency so that it is on your application's main classpath and not only on its test classpath.\n\nYou can get a vanilla template or one that sends Basic HTTP authentication (with a username and password).\nIn either case, the template is fault tolerant.\nThis means that it behaves in a test-friendly way by not throwing exceptions on 4xx and 5xx errors.\nInstead, such errors can be detected through the returned javadoc:org.springframework.http.ResponseEntity[] and its status code.\n\nIf you need fluent API for assertions, consider using javadoc:org.springframework.test.web.servlet.client.RestTestClient[] that works with xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[mock environments] and xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[end-to-end tests].\n\nIf you are using Spring WebFlux, consider the javadoc:org.springframework.test.web.reactive.server.WebTestClient[] that provides a similar API and works with xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-mock-environment[mock environments], xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.spring-webflux-tests[WebFlux integration tests], and xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.with-running-server[end-to-end tests].\n\nIt is recommended, but not mandatory, to use the Apache HTTP Client (version 5.1 or better).\nIf you have that on your classpath, the javadoc:org.springframework.boot.resttestclient.TestRestTemplate[] responds by configuring the client appropriately.\n\njavadoc:org.springframework.boot.resttestclient.TestRestTemplate[] can be instantiated directly in your integration tests, as shown in the following example:\n\ninclude-code::MyTests[]\n\nAlternatively, if you use the javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation] annotation with `WebEnvironment.RANDOM_PORT` or `WebEnvironment.DEFINED_PORT`, you can inject a fully configured javadoc:org.springframework.boot.resttestclient.TestRestTemplate[] by annotating the test class with javadoc:org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate[format=annotation].\nIf necessary, additional customizations can be applied through the javadoc:org.springframework.boot.restclient.RestTemplateBuilder[] bean.\n\nAny URLs that do not specify a host and port automatically connect to the embedded server, as shown in the following example:\n\ninclude-code::MySpringBootTests[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc",
    "content": "[[testing.testcontainers]]\n= Testcontainers\n\nThe https://www.testcontainers.org/[Testcontainers] library provides a way to manage services running inside Docker containers.\nIt integrates with JUnit, allowing you to write a test class that can start up a container before any of the tests run.\nTestcontainers is especially useful for writing integration tests that talk to a real backend service such as MySQL, MongoDB, Cassandra and others.\n\nIn following sections we will describe some of the methods you can use to integrate Testcontainers with your tests.\n\n\n[[testing.testcontainers.spring-beans]]\n== Using Spring Beans\n\nThe containers provided by Testcontainers can be managed by Spring Boot as beans.\n\nTo declare a container as a bean, add a javadoc:org.springframework.context.annotation.Bean[format=annotation] method to your test configuration:\n\ninclude-code::MyTestConfiguration[]\n\nYou can then inject and use the container by importing the configuration class in the test class:\n\ninclude-code::MyIntegrationTests[]\n\nTIP: This method of managing containers is often used in combination with xref:#testing.testcontainers.service-connections[service connection annotations].\n\n\n\n[[testing.testcontainers.junit-extension]]\n== Using the JUnit Extension\n\nTestcontainers provides a JUnit extension which can be used to manage containers in your tests.\nThe extension is activated by applying the javadoc:org.testcontainers.junit.jupiter.Testcontainers[format=annotation] annotation from Testcontainers to your test class.\n\nYou can then use the javadoc:org.testcontainers.junit.jupiter.Container[format=annotation] annotation on static container fields.\n\nThe javadoc:org.testcontainers.junit.jupiter.Testcontainers[format=annotation] annotation can be used on vanilla JUnit tests, or in combination with javadoc:org.springframework.boot.test.context.SpringBootTest[format=annotation]:\n\ninclude-code::MyIntegrationTests[]\n\nThe example above will start up a Neo4j container before any of the tests are run.\nThe lifecycle of the container instance is managed by Testcontainers, as described in {url-testcontainers-docs}/test_framework_integration/junit_5/#extension[their official documentation].\n\nNOTE: In most cases, you will additionally need to configure the application to connect to the service running in the container.\n\n\n\n[[testing.testcontainers.importing-configuration-interfaces]]\n== Importing Container Configuration Interfaces\n\nA common pattern with Testcontainers is to declare the container instances as static fields in an interface.\n\nFor example, the following interface declares two containers, one named `mongo` of type javadoc:{url-testcontainers-mongodb-javadoc}/org.testcontainers.mongodb.MongoDBContainer[] and another named `neo4j` of type javadoc:{url-testcontainers-neo4j-javadoc}/org.testcontainers.neo4j.Neo4jContainer[]:\n\ninclude-code::MyContainers[]\n\nWhen you have containers declared in this way, you can reuse their configuration in multiple tests by having the test classes implement the interface.\n\nIt's also possible to use the same interface configuration in your Spring Boot tests.\nTo do so, add javadoc:org.springframework.boot.testcontainers.context.ImportTestcontainers[format=annotation] to your test configuration class:\n\ninclude-code::MyTestConfiguration[]\n\n\n\n[[testing.testcontainers.lifecycle]]\n== Lifecycle of Managed Containers\n\nIf you have used the annotations and extensions provided by Testcontainers, then the lifecycle of container instances is managed entirely by Testcontainers.\nPlease refer to the {url-testcontainers-docs}[official Testcontainers documentation] for the information.\n\nWhen the containers are managed by Spring as beans, then their lifecycle is managed by Spring:\n\n* Container beans are created and started before all other beans.\n\n* Container beans are stopped after the destruction of all other beans.\n\nThis process ensures that any beans, which rely on functionality provided by the containers, can use those functionalities.\nIt also ensures that they are cleaned up whilst the container is still available.\n\nTIP: When your application beans rely on functionality of containers, prefer configuring the containers as Spring beans to ensure the correct lifecycle behavior.\n\nNOTE: Having containers managed by Testcontainers instead of as Spring beans provides no guarantee of the order in which beans and containers will shutdown.\nIt can happen that containers are shutdown before the beans relying on container functionality are cleaned up.\nThis can lead to exceptions being thrown by client beans, for example, due to loss of connection.\n\nContainer beans are created and started once per application context managed by Spring's TestContext Framework.\nFor details about how TestContext Framework manages the underlying application contexts and beans therein, please refer to the {url-spring-framework-docs}[Spring Framework documentation].\n\nContainer beans are stopped as part of the TestContext Framework's standard application context shutdown process.\nWhen the application context gets shutdown, the containers are shutdown as well.\nThis usually happens after all tests using that specific cached application context have finished executing.\nIt may also happen earlier, depending on the caching behavior configured in TestContext Framework.\n\nNOTE: A single test container instance can, and often is, retained across execution of tests from multiple test classes.\n\n\n\n[[testing.testcontainers.service-connections]]\n== Service Connections\n\nA service connection is a connection to any remote service.\nSpring Boot's auto-configuration can consume the details of a service connection and use them to establish a connection to a remote service.\nWhen doing so, the connection details take precedence over any connection-related configuration properties.\n\nWhen using Testcontainers, connection details can be automatically created for a service running in a container by annotating the container field in the test class.\n\ninclude-code::MyIntegrationTests[]\n\nThanks to javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation], the above configuration allows Neo4j-related beans in the application to communicate with Neo4j running inside the Testcontainers-managed Docker container.\nThis is done by automatically defining a javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[] bean which is then used by the Neo4j auto-configuration, overriding any connection-related configuration properties.\n\nNOTE: You'll need to add the `spring-boot-testcontainers` module as a test dependency in order to use service connections with Testcontainers.\n\nService connection annotations are processed by javadoc:org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory[] classes registered with `spring.factories`.\nA javadoc:org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory[] can create a javadoc:org.springframework.boot.autoconfigure.service.connection.ConnectionDetails[] bean based on a specific javadoc:org.testcontainers.containers.Container[] subclass, or the Docker image name.\n\nThe following service connection factories are provided in the `spring-boot-testcontainers` jar:\n\n|===\n| Connection Details | Matched on\n\n| javadoc:org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails[]\n| Containers named \"symptoma/activemq\" or javadoc:org.testcontainers.activemq.ActiveMQContainer[]\n\n| javadoc:org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails[]\n| Containers of type javadoc:org.testcontainers.activemq.ArtemisContainer[]\n\n| javadoc:org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails[]\n| Containers of type javadoc:org.testcontainers.cassandra.CassandraContainer[]\n\n| javadoc:org.springframework.boot.couchbase.autoconfigure.CouchbaseConnectionDetails[]\n| Containers of type javadoc:org.testcontainers.couchbase.CouchbaseContainer[]\n\n| javadoc:org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails[]\n| Containers of type javadoc:org.testcontainers.elasticsearch.ElasticsearchContainer[]\n\n| javadoc:org.springframework.boot.flyway.autoconfigure.FlywayConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-jdbc-javadoc}/org.testcontainers.containers.JdbcDatabaseContainer[]\n\n| javadoc:org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-jdbc-javadoc}/org.testcontainers.containers.JdbcDatabaseContainer[]\n\n| javadoc:org.springframework.boot.kafka.autoconfigure.KafkaConnectionDetails[]\n| Containers of type javadoc:org.testcontainers.kafka.KafkaContainer[], javadoc:org.testcontainers.kafka.ConfluentKafkaContainer[] or javadoc:org.testcontainers.redpanda.RedpandaContainer[]\n\n| javadoc:org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails[]\n| Containers named \"osixia/openldap\" or of type javadoc:org.testcontainers.ldap.LLdapContainer[]\n\n| javadoc:org.springframework.boot.liquibase.autoconfigure.LiquibaseConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-jdbc-javadoc}/org.testcontainers.containers.JdbcDatabaseContainer[]\n\n| javadoc:org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-mongodb-javadoc}/org.testcontainers.mongodb.MongoDBContainer[] or javadoc:{url-testcontainers-mongodb-javadoc}/org.testcontainers.mongodb.MongoDBAtlasLocalContainer[]\n\n| javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-neo4j-javadoc}/org.testcontainers.neo4j.Neo4jContainer[]\n\n| javadoc:org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails[]\n| Containers named \"otel/opentelemetry-collector-contrib\" or of type javadoc:org.testcontainers.grafana.LgtmStackContainer[]\n\n| javadoc:org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails[]\n| Containers named \"otel/opentelemetry-collector-contrib\" or of type javadoc:org.testcontainers.grafana.LgtmStackContainer[]\n\n| javadoc:org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails[]\n| Containers named \"otel/opentelemetry-collector-contrib\" or of type javadoc:org.testcontainers.grafana.LgtmStackContainer[]\n\n| javadoc:org.springframework.boot.pulsar.autoconfigure.PulsarConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-pulsar-javadoc}/org.testcontainers.pulsar.PulsarContainer[]\n\n| javadoc:org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails[]\n| Containers of type\njavadoc:org.testcontainers.clickhouse.ClickHouseContainer[],\njavadoc:{url-testcontainers-mariadb-javadoc}/org.testcontainers.mariadb.MariaDBContainer[], javadoc:{url-testcontainers-mssqlserver-javadoc}/org.testcontainers.mssqlserver.MSSQLServerContainer[], javadoc:{url-testcontainers-mysql-javadoc}/org.testcontainers.mysql.MySQLContainer[],\njavadoc:org.testcontainers.oracle.OracleContainer[OracleContainer (free)], javadoc:{url-testcontainers-oracle-xe-javadoc}/org.testcontainers.containers.OracleContainer[OracleContainer (XE)] or javadoc:{url-testcontainers-postgresql-javadoc}/org.testcontainers.postgresql.PostgreSQLContainer[]\n\n| javadoc:org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[]\n\n| javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[]\n| Containers of type javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[] when the `@ServiceConnection` `type` attribute includes javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[]\n\n| javadoc:org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails[]\n| Containers of type javadoc:com.redis.testcontainers.RedisContainer[] or javadoc:com.redis.testcontainers.RedisStackContainer[], or containers named \"redis\", \"redis/redis-stack\" or \"redis/redis-stack-server\"\n\n| javadoc:org.springframework.boot.zipkin.autoconfigure.ZipkinConnectionDetails[]\n| Containers named \"openzipkin/zipkin\"\n|===\n\n[TIP]\n====\nBy default, with the exception of javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[], all applicable connection details beans will be created for a given javadoc:org.testcontainers.containers.Container[].\nFor example, a javadoc:{url-testcontainers-postgresql-javadoc}/org.testcontainers.postgresql.PostgreSQLContainer[] will create both javadoc:org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails[] and javadoc:org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails[].\n\nIf you want to create only a subset of the applicable types, you can use the `type` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation].\n\nTo create a javadoc:org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails[] bean from a javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[], you must opt in using the `type` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation].\nThe container must also expose port 5552, the RabbitMQ streams port.\n====\n\nBy default `Container.getDockerImageName().getRepository()` is used to obtain the name used to find connection details.\nThe repository portion of the Docker image name ignores any registry and the version.\nThis works as long as Spring Boot is able to get the instance of the javadoc:org.testcontainers.containers.Container[], which is the case when using a `static` field like in the example above.\n\nIf you're using a javadoc:org.springframework.context.annotation.Bean[format=annotation] method, Spring Boot won't call the bean method to get the Docker image name, because this would cause eager initialization issues.\nInstead, the return type of the bean method is used to find out which connection detail should be used.\nThis works as long as you're using typed containers such as javadoc:{url-testcontainers-neo4j-javadoc}/org.testcontainers.neo4j.Neo4jContainer[] or javadoc:{url-testcontainers-rabbitmq-javadoc}/org.testcontainers.rabbitmq.RabbitMQContainer[].\nThis stops working if you're using javadoc:org.testcontainers.containers.GenericContainer[], for example with Redis as shown in the following example:\n\ninclude-code::MyRedisConfiguration[]\n\nSpring Boot can't tell from javadoc:org.testcontainers.containers.GenericContainer[] which container image is used, so the `name` attribute from javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation] must be used to provide that hint.\n\nYou can also use the `name` attribute of javadoc:org.springframework.boot.testcontainers.service.connection.ServiceConnection[format=annotation] to override which connection detail will be used, for example when using custom images.\nIf you are using the Docker image `registry.mycompany.com/mirror/myredis`, you'd use `@ServiceConnection(name=\"redis\")` to ensure javadoc:org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails[] are created.\n\n\n\n[[testing.testcontainers.service-connections.ssl]]\n=== SSL with Service Connections\n\nYou can use the javadoc:org.springframework.boot.testcontainers.service.connection.Ssl[format=annotation], javadoc:org.springframework.boot.testcontainers.service.connection.JksKeyStore[format=annotation], javadoc:org.springframework.boot.testcontainers.service.connection.JksTrustStore[format=annotation], javadoc:org.springframework.boot.testcontainers.service.connection.PemKeyStore[format=annotation] and javadoc:org.springframework.boot.testcontainers.service.connection.PemTrustStore[format=annotation] annotations on a supported container to enable SSL support for that service connection.\nPlease note that you still have to enable SSL on the service which is running inside the Testcontainer yourself, the annotations only configure SSL on the client side in your application.\n\ninclude-code::MyRedisWithSslIntegrationTests[]\n\nThe above code uses the javadoc:org.springframework.boot.testcontainers.service.connection.PemKeyStore[format=annotation] annotation to load the client certificate and key into the keystore and the and javadoc:org.springframework.boot.testcontainers.service.connection.PemTrustStore[format=annotation] annotation to load the CA certificate into the truststore.\nThis will authenticate the client against the server, and the CA certificate in the truststore makes sure that the server certificate is valid and trusted.\n\nThe `SecureRedisContainer` in this example is a custom subclass of `RedisContainer` which copies certificates to the correct places and invokes `redis-server` with commandline parameters enabling SSL.\n\nThe SSL annotations are supported for the following service connections:\n\n* Cassandra\n* Couchbase\n* Elasticsearch\n* Kafka\n* MongoDB\n* RabbitMQ\n* RabbitMQ Streams\n* Redis\n\nThe `ElasticsearchContainer` additionally supports automatic detection of server side SSL.\nTo use this feature, annotate the container with javadoc:org.springframework.boot.testcontainers.service.connection.Ssl[format=annotation], as seen in the following example, and Spring Boot takes care of the client side SSL configuration for you:\n\ninclude-code::MyElasticsearchWithSslIntegrationTests[]\n\n\n\n[[testing.testcontainers.dynamic-properties]]\n== Dynamic Properties\n\nA slightly more verbose but also more flexible alternative to service connections is javadoc:org.springframework.test.context.DynamicPropertySource[format=annotation].\nA static javadoc:org.springframework.test.context.DynamicPropertySource[format=annotation] method allows adding dynamic property values to the Spring Environment.\n\ninclude-code::MyIntegrationTests[]\n\nThe above configuration allows Neo4j-related beans in the application to communicate with Neo4j running inside the Testcontainers-managed Docker container.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/auto-configuration.adoc",
    "content": "[[using.auto-configuration]]\n= Auto-configuration\n\nSpring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added.\nFor example, if `HSQLDB` is on your classpath, and you have not manually configured any database connection beans, then Spring Boot auto-configures an in-memory database.\n\nYou need to opt-in to auto-configuration by adding the javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] or javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotations to one of your javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes.\n\nTIP: You should only ever add one javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] or javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] annotation.\nWe generally recommend that you add one or the other to your primary javadoc:org.springframework.context.annotation.Configuration[format=annotation] class only.\n\n\n\n[[using.auto-configuration.replacing]]\n== Gradually Replacing Auto-configuration\n\nAuto-configuration is non-invasive.\nAt any point, you can start to define your own configuration to replace specific parts of the auto-configuration.\nFor example, if you add your own javadoc:javax.sql.DataSource[] bean, the default embedded database support backs away.\n\nIf you need to find out what auto-configuration is currently being applied, and why, start your application with the `--debug` switch.\nDoing so enables debug logs for a selection of core loggers and logs a conditions report to the console.\n\n\n\n[[using.auto-configuration.disabling-specific]]\n== Disabling Specific Auto-configuration Classes\n\nIf you find that specific auto-configuration classes that you do not want are being applied, you can use the exclude attribute of javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] to disable them, as shown in the following example:\n\ninclude-code::MyApplication[]\n\nIf the class is not on the classpath, you can use the `excludeName` attribute of the annotation and specify the fully qualified name instead.\nIf you prefer to use javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] rather than javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation], `exclude` and `excludeName` are also available.\nFinally, you can also control the list of auto-configuration classes to exclude by using the configprop:spring.autoconfigure.exclude[] property.\n\nTIP: You can define exclusions both at the annotation level and by using the property.\n\nNOTE: Even though auto-configuration classes are `public`, the only aspect of the class that is considered public API is the name of the class which can be used for disabling the auto-configuration.\nThe actual contents of those classes, such as nested configuration classes or bean methods are for internal use only and we do not recommend using those directly.\n\n\n\n[[using.auto-configuration.packages]]\n== Auto-configuration Packages\n\nAuto-configuration packages are the packages that various auto-configured features look in by default when scanning for things such as entities and Spring Data repositories.\nThe javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] annotation (either directly or through its presence on javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation]) determines the default auto-configuration package.\nAdditional packages can be configured using the javadoc:org.springframework.boot.autoconfigure.AutoConfigurationPackage[format=annotation] annotation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/build-systems.adoc",
    "content": "[[using.build-systems]]\n= Build Systems\n\nIt is strongly recommended that you choose a build system that supports xref:using/build-systems.adoc#using.build-systems.dependency-management[dependency management] and that can consume artifacts published to the Maven Central repository.\nWe would recommend that you choose Maven or Gradle.\nIt is possible to get Spring Boot to work with other build systems (Ant, for example), but they are not particularly well supported.\n\n\n\n[[using.build-systems.dependency-management]]\n== Dependency Management\n\nEach release of Spring Boot provides a curated list of dependencies that it supports.\nIn practice, you do not need to provide a version for any of these dependencies in your build configuration, as Spring Boot manages that for you.\nWhen you upgrade Spring Boot itself, these dependencies are upgraded as well in a consistent way.\n\nNOTE: You can still specify a version and override Spring Boot's recommendations if you need to do so.\n\nThe curated list contains all the Spring modules that you can use with Spring Boot as well as a refined list of third party libraries.\nThe list is available as a standard Bills of Materials (`spring-boot-dependencies`) that can be used with both xref:using/build-systems.adoc#using.build-systems.maven[Maven] and xref:using/build-systems.adoc#using.build-systems.gradle[Gradle].\n\nWARNING: Each release of Spring Boot is associated with a base version of the Spring Framework.\nWe **highly** recommend that you do not specify its version.\n\n\n\n[[using.build-systems.maven]]\n== Maven\n\nTo learn about using Spring Boot with Maven, see the documentation for Spring Boot's Maven plugin:\n\n* xref:maven-plugin:index.adoc[Reference]\n* xref:maven-plugin:api/java/index.html[API]\n\n\n\n[[using.build-systems.gradle]]\n== Gradle\n\nTo learn about using Spring Boot with Gradle, see the documentation for Spring Boot's Gradle plugin:\n\n* xref:gradle-plugin:index.adoc[Reference]\n* xref:gradle-plugin:api/java/index.html[API]\n\n\n\n[[using.build-systems.ant]]\n==  Ant\n\nIt is possible to build a Spring Boot project using Apache Ant+Ivy.\nThe `spring-boot-antlib` \"`AntLib`\" module is also available to help Ant create executable jars.\n\nTo declare dependencies, a typical `ivy.xml` file looks something like the following example:\n\n[source,xml]\n----\n<ivy-module version=\"2.0\">\n\t<info organisation=\"org.springframework.boot\" module=\"spring-boot-sample-ant\" />\n\t<configurations>\n\t\t<conf name=\"compile\" description=\"everything needed to compile this module\" />\n\t\t<conf name=\"runtime\" extends=\"compile\" description=\"everything needed to run this module\" />\n\t</configurations>\n\t<dependencies>\n\t\t<dependency org=\"org.springframework.boot\" name=\"spring-boot-starter\"\n\t\t\trev=\"${spring-boot.version}\" conf=\"compile\" />\n\t</dependencies>\n</ivy-module>\n----\n\nA typical `build.xml` looks like the following example:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<project\n\txmlns:ivy=\"antlib:org.apache.ivy.ant\"\n\txmlns:spring-boot=\"antlib:org.springframework.boot.ant\"\n\tname=\"myapp\" default=\"build\">\n\n\t<property name=\"spring-boot.version\" value=\"{version-spring-boot}\" />\n\n\t<target name=\"resolve\" description=\"--> retrieve dependencies with ivy\">\n\t\t<ivy:retrieve pattern=\"lib/[conf]/[artifact]-[type]-[revision].[ext]\" />\n\t</target>\n\n\t<target name=\"classpaths\" depends=\"resolve\">\n\t\t<path id=\"compile.classpath\">\n\t\t\t<fileset dir=\"lib/compile\" includes=\"*.jar\" />\n\t\t</path>\n\t</target>\n\n\t<target name=\"init\" depends=\"classpaths\">\n\t\t<mkdir dir=\"build/classes\" />\n\t</target>\n\n\t<target name=\"compile\" depends=\"init\" description=\"compile\">\n\t\t<javac srcdir=\"src/main/java\" destdir=\"build/classes\" classpathref=\"compile.classpath\" />\n\t</target>\n\n\t<target name=\"build\" depends=\"compile\">\n\t\t<spring-boot:exejar destfile=\"build/myapp.jar\" classes=\"build/classes\">\n\t\t\t<spring-boot:lib>\n\t\t\t\t<fileset dir=\"lib/runtime\" />\n\t\t\t</spring-boot:lib>\n\t\t</spring-boot:exejar>\n\t</target>\n</project>\n----\n\nTIP: If you do not want to use the `spring-boot-antlib` module, see the xref:how-to:build.adoc#howto.build.build-an-executable-archive-with-ant-without-using-spring-boot-antlib[] section of \"`How-to Guides`\".\n\n\n\n[[using.build-systems.starters]]\n== Starters\n\nStarters are a set of convenient dependency descriptors that you can include in your application.\nYou get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors.\nFor example, if you want to get started using Spring and JPA for database access, include the `spring-boot-starter-data-jpa` dependency in your project.\n\nThe starters contain a lot of the dependencies that you need to get a project up and running quickly and with a consistent, supported set of managed transitive dependencies.\n\n.What is in a name\n****\nAll **official** starters follow a similar naming pattern; `+spring-boot-starter-*+`, where `+*+` is a particular type of application.\nThis naming structure is intended to help when you need to find a starter.\nThe Maven integration in many IDEs lets you search dependencies by name.\nFor example, with the appropriate Eclipse or Spring Tools plugin installed, you can press `ctrl-space` in the POM editor and type \"`spring-boot-starter`\" for a complete list.\n\nAs explained in the xref:features/developing-auto-configuration.adoc#features.developing-auto-configuration.custom-starter[] section, third party starters should not start with `spring-boot`, as it is reserved for official Spring Boot artifacts.\nRather, a third-party starter typically starts with the name of the project.\nFor example, a third-party starter project called `thirdpartyproject` would typically be named `thirdpartyproject-spring-boot-starter`.\n****\n\nThe following application starters are provided by Spring Boot under the `org.springframework.boot` group:\n\n.Spring Boot application starters\ninclude::ROOT:partial$starters/application-starters.adoc[]\n\nIn addition to the application starters, the following starters can be used to add xref:how-to:actuator.adoc[production ready] features:\n\n.Spring Boot production starters\ninclude::ROOT:partial$starters/production-starters.adoc[]\n\nFinally, Spring Boot also includes the following starters that can be used if you want to exclude or swap specific technical facets:\n\n.Spring Boot technical starters\ninclude::ROOT:partial$starters/technical-starters.adoc[]\n\nTo learn how to swap technical facets, please see the how-to documentation for xref:how-to:webserver.adoc#howto.webserver.use-another[swapping web server] and xref:how-to:logging.adoc#howto.logging.log4j[logging system].\n\nTIP: For a list of additional community contributed starters, see the {code-spring-boot-latest}/starter/README.adoc[README file] in the `spring-boot-starters` module on GitHub.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/configuration-classes.adoc",
    "content": "[[using.configuration-classes]]\n= Configuration Classes\n\nSpring Boot favors Java-based configuration.\nAlthough it is possible to use javadoc:org.springframework.boot.SpringApplication[] with XML sources, we generally recommend that your primary source be a single javadoc:org.springframework.context.annotation.Configuration[format=annotation] class.\nUsually the class that defines the `main` method is a good candidate as the primary javadoc:org.springframework.context.annotation.Configuration[format=annotation].\n\nTIP: Many Spring configuration examples have been published on the Internet that use XML configuration.\nIf possible, always try to use the equivalent Java-based configuration.\nSearching for `+Enable*+` annotations can be a good starting point.\n\n\n\n[[using.configuration-classes.importing-additional-configuration]]\n== Importing Additional Configuration Classes\n\nYou need not put all your javadoc:org.springframework.context.annotation.Configuration[format=annotation] into a single class.\nThe javadoc:org.springframework.context.annotation.Import[format=annotation] annotation can be used to import additional configuration classes.\nAlternatively, you can use javadoc:org.springframework.context.annotation.ComponentScan[format=annotation] to automatically pick up all Spring components, including javadoc:org.springframework.context.annotation.Configuration[format=annotation] classes.\n\n\n\n[[using.configuration-classes.importing-xml-configuration]]\n== Importing XML Configuration\n\nIf you absolutely must use XML based configuration, we recommend that you still start with a javadoc:org.springframework.context.annotation.Configuration[format=annotation] class.\nYou can then use an javadoc:org.springframework.context.annotation.ImportResource[format=annotation] annotation to load XML configuration files.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/devtools.adoc",
    "content": "[[using.devtools]]\n= Developer Tools\n\nSpring Boot includes an additional set of tools that can make the application development experience a little more pleasant.\nThe `spring-boot-devtools` module can be included in any project to provide additional development-time features.\nTo include devtools support, add the module dependency to your build, as shown in the following listings for Maven and Gradle:\n\n.Maven\n[source,xml]\n----\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-devtools</artifactId>\n\t\t<optional>true</optional>\n\t</dependency>\n</dependencies>\n----\n\n.Gradle\n[source,gradle]\n----\ndependencies {\n\tdevelopmentOnly(\"org.springframework.boot:spring-boot-devtools\")\n}\n----\n\nCAUTION: Devtools might cause classloading issues, in particular in multi-module projects.\nxref:using/devtools.adoc#using.devtools.diagnosing-classloading-issues[] explains how to diagnose and solve them.\n\nNOTE: Developer tools are automatically disabled when running a fully packaged application.\nIf your application is launched from `java -jar` or if it is started from a special classloader, then it is considered a \"`production application`\".\nYou can control this behavior by using the `spring.devtools.restart.enabled` system property.\nTo enable devtools, irrespective of the classloader used to launch your application, set the `-Dspring.devtools.restart.enabled=true` system property.\nThis must not be done in a production environment where running devtools is a security risk.\nTo disable devtools, exclude the dependency or set the `-Dspring.devtools.restart.enabled=false` system property.\n\nTIP: Flagging the dependency as optional in Maven or using the `developmentOnly` configuration in Gradle (as shown above) prevents devtools from being transitively applied to other modules that use your project.\n\nTIP: Repackaged archives do not contain devtools by default.\nIf you want to use a xref:using/devtools.adoc#using.devtools.remote-applications[certain remote devtools feature], you need to include it.\nWhen using the Maven plugin, opt-in for optional dependencies by setting the `includeOptional` property to `true`.\nYou also need to set the `excludeDevtools` property to `false`.\nWhen using the Gradle plugin, xref:gradle-plugin:packaging.adoc#packaging-executable.configuring.including-development-only-dependencies[configure the task's classpath to include the `developmentOnly` configuration].\n\n\n\n[[using.devtools.diagnosing-classloading-issues]]\n== Diagnosing Classloading Issues\n\nAs described in the xref:#using.devtools.restart.restart-vs-reload[] section, restart functionality is implemented by using two classloaders.\nFor most applications, this approach works well.\nHowever, it can sometimes cause classloading issues, in particular in multi-module projects.\n\nTo diagnose whether the classloading issues are indeed caused by devtools and its two classloaders, xref:using/devtools.adoc#using.devtools.restart.disable[try disabling restart].\nIf this solves your problems, xref:using/devtools.adoc#using.devtools.restart.customizing-the-classload[customize the restart classloader] to include your entire project.\n\n\n\n[[using.devtools.property-defaults]]\n== Property Defaults\n\nSeveral of the libraries supported by Spring Boot use caches to improve performance.\nFor example, xref:web/servlet.adoc#web.servlet.spring-mvc.template-engines[template engines] cache compiled templates to avoid repeatedly parsing template files.\nAlso, Spring MVC can add HTTP caching headers to responses when serving static resources.\n\nWhile caching is very beneficial in production, it can be counter-productive during development, preventing you from seeing the changes you just made in your application.\nFor this reason, spring-boot-devtools disables the caching options by default.\n\nCache options are usually configured by settings in your `application.properties` file.\nFor example, Thymeleaf offers the configprop:spring.thymeleaf.cache[] property.\n\nThe same applies for tracing probability that's set to 100% as the default may not log all traces used for testing.\n\nRather than needing to set these properties manually, the `spring-boot-devtools` module automatically applies sensible development-time configuration.\n\nThe following table lists all the properties that are applied:\n\ninclude::ROOT:partial$propertydefaults/devtools-property-defaults.adoc[]\n\nNOTE: If you do not want property defaults to be applied you can set configprop:spring.devtools.add-properties[] to `false` in your `application.properties`.\n\nBecause you need more information about web requests while developing Spring MVC and Spring WebFlux applications, developer tools suggests you to enable `DEBUG` logging for the `web` logging group.\nThis will give you information about the incoming request, which handler is processing it, the response outcome, and other details.\nIf you wish to log all request details (including potentially sensitive information), you can turn on the configprop:spring.mvc.log-request-details[] or configprop:spring.http.codecs.log-request-details[] configuration properties.\n\n\n\n[[using.devtools.restart]]\n== Automatic Restart\n\nApplications that use `spring-boot-devtools` automatically restart whenever files on the classpath change.\nThis can be a useful feature when working in an IDE, as it gives a very fast feedback loop for code changes.\nBy default, any entry on the classpath that points to a directory is monitored for changes.\nNote that certain resources, such as static assets and view templates, xref:using/devtools.adoc#using.devtools.restart.excluding-resources[do not need to restart the application].\n\n.Triggering a restart\n****\nAs DevTools monitors classpath resources, the only way to trigger a restart is to update the classpath.\nWhether you're using an IDE or one of the build plugins, the modified files have to be recompiled to trigger a restart.\nThe way in which you cause the classpath to be updated depends on the tool that you are using:\n\n* In Eclipse, saving a modified file causes the classpath to be updated and triggers a restart.\n* In IntelliJ IDEA, building the project (`Build +->+ Build Project`) has the same effect.\n* If using a build plugin, running `mvn compile` for Maven or `gradle build` for Gradle will trigger a restart.\n****\n\nNOTE: If you are restarting with Maven or Gradle using the build plugin you must leave the `forking` set to `enabled`.\nIf you disable forking, the isolated application classloader used by devtools will not be created and restarts will not operate properly.\n\nTIP: If you use JRebel, automatic restarts are disabled in favor of dynamic class reloading.\nOther devtools features (such as property overrides) can still be used.\n\nNOTE: DevTools relies on the application context's shutdown hook to close it during a restart.\nIt does not work correctly if you have disabled the shutdown hook (`SpringApplication.setRegisterShutdownHook(false)`).\n\nNOTE: DevTools needs to customize the javadoc:org.springframework.core.io.ResourceLoader[] used by the javadoc:org.springframework.context.ApplicationContext[].\nIf your application provides one already, it is going to be wrapped.\nDirect override of the `getResource` method on the javadoc:org.springframework.context.ApplicationContext[] is not supported.\n\nCAUTION: Automatic restart is not supported when using AspectJ weaving.\n\n[[using.devtools.restart.restart-vs-reload]]\n.Restart vs Reload\n****\nThe restart technology provided by Spring Boot works by using two classloaders.\nClasses that do not change (for example, those from third-party jars) are loaded into a _base_ classloader.\nClasses that you are actively developing are loaded into a _restart_ classloader.\nWhen the application is restarted, the _restart_ classloader is thrown away and a new one is created.\nThis approach means that application restarts are typically much faster than \"`cold starts`\", since the _base_ classloader is already available and populated.\n\nIf you find that restarts are not quick enough for your applications or you encounter classloading issues, you could consider reloading technologies such as https://jrebel.com/software/jrebel/[JRebel] from ZeroTurnaround.\nThese work by rewriting classes as they are loaded to make them more amenable to reloading.\n****\n\n\n\n[[using.devtools.restart.logging-condition-delta]]\n=== Logging Changes in Condition Evaluation\n\nBy default, each time your application restarts, a report showing the condition evaluation delta is logged.\nThe report shows the changes to your application's auto-configuration as you make changes such as adding or removing beans and setting configuration properties.\n\nTo disable the logging of the report, set the following property:\n\n[configprops,yaml]\n----\nspring:\n  devtools:\n    restart:\n      log-condition-evaluation-delta: false\n----\n\n\n\n[[using.devtools.restart.excluding-resources]]\n=== Excluding Resources\n\nCertain resources do not necessarily need to trigger a restart when they are changed.\nFor example, Thymeleaf templates can be edited in-place.\nBy default, changing resources in `/META-INF/maven`, `/META-INF/resources`, `/resources`, `/static`, `/public`, or `/templates` does not trigger a restart but does trigger a xref:using/devtools.adoc#using.devtools.livereload[live reload].\nIf you want to customize these exclusions, you can use the configprop:spring.devtools.restart.exclude[] property.\nFor example, to exclude only `/static` and `/public` you would set the following property:\n\n[configprops,yaml]\n----\nspring:\n  devtools:\n    restart:\n      exclude: \"static/**,public/**\"\n----\n\nTIP: If you want to keep those defaults and _add_ additional exclusions, use the configprop:spring.devtools.restart.additional-exclude[] property instead.\n\n\n\n[[using.devtools.restart.watching-additional-paths]]\n=== Watching Additional Paths\n\nYou may want your application to be restarted or reloaded when you make changes to files that are not on the classpath.\nTo do so, use the configprop:spring.devtools.restart.additional-paths[] property to configure additional paths to watch for changes.\nYou can use the configprop:spring.devtools.restart.exclude[] property xref:using/devtools.adoc#using.devtools.restart.excluding-resources[described earlier] to control whether changes beneath the additional paths trigger a full restart or a xref:using/devtools.adoc#using.devtools.livereload[live reload].\n\n\n\n[[using.devtools.restart.disable]]\n=== Disabling Restart\n\nIf you do not want to use the restart feature, you can disable it by using the configprop:spring.devtools.restart.enabled[] property.\nIn most cases, you can set this property in your `application.properties` (doing so still initializes the restart classloader, but it does not watch for file changes).\n\nIf you need to _completely_ disable restart support (for example, because it does not work with a specific library), you need to set the configprop:spring.devtools.restart.enabled[] javadoc:java.lang.System[] property to `false` before calling `SpringApplication.run(...)`, as shown in the following example:\n\ninclude-code::MyApplication[]\n\n\n\n[[using.devtools.restart.triggerfile]]\n=== Using a Trigger File\n\nIf you work with an IDE that continuously compiles changed files, you might prefer to trigger restarts only at specific times.\nTo do so, you can use a \"`trigger file`\", which is a special file that must be modified when you want to actually trigger a restart check.\n\nNOTE: Any update to the file will trigger a check, but restart only actually occurs if Devtools has detected it has something to do.\n\nTo use a trigger file, set the configprop:spring.devtools.restart.trigger-file[] property to the name (excluding any path) of your trigger file.\nThe trigger file must appear somewhere on your classpath.\n\nFor example, if you have a project with the following structure:\n\n[source]\n----\nsrc\n+- main\n   +- resources\n      +- .reloadtrigger\n----\n\nThen your `trigger-file` property would be:\n\n[configprops,yaml]\n----\nspring:\n  devtools:\n    restart:\n      trigger-file: \".reloadtrigger\"\n----\n\nRestarts will now only happen when the `src/main/resources/.reloadtrigger` is updated.\n\nTIP: You might want to set `spring.devtools.restart.trigger-file` as a xref:using/devtools.adoc#using.devtools.globalsettings[global setting], so that all your projects behave in the same way.\n\nSome IDEs have features that save you from needing to update your trigger file manually.\nhttps://spring.io/tools[Spring Tools for Eclipse] and https://www.jetbrains.com/idea/[IntelliJ IDEA (Ultimate Edition)] both have such support.\nWith Spring Tools, you can use the \"`reload`\" button from the console view (as long as your `trigger-file` is named `.reloadtrigger`).\nFor IntelliJ IDEA, you can follow the https://www.jetbrains.com/help/idea/spring-boot.html#application-update-policies[instructions in their documentation].\n\n\n\n[[using.devtools.restart.customizing-the-classload]]\n=== Customizing the Restart Classloader\nAs described earlier in the xref:#using.devtools.restart.restart-vs-reload[] section, restart functionality is implemented by using two classloaders.\nIf this causes issues, you can diagnose the problem by using the `spring.devtools.restart.enabled` system property, and if the app works with restart switched off, you might need to customize what gets loaded by which classloader.\n\nBy default, any open project in your IDE is loaded with the \"`restart`\" classloader, and any regular `.jar` file is loaded with the \"`base`\" classloader.\nThe same is true if you use `mvn spring-boot:run` or `gradle bootRun`: the project containing your javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] is loaded with the \"`restart`\" classloader, and everything else with the \"`base`\" classloader.\nThe classpath is printed on the console when you start the app, which can help to identify any problematic entries.\nClasses used reflectively, especially annotations, can be loaded into the parent (fixed) classloader on startup before the application classes which use them, and this might lead to them not being detected by Spring in the application.\n\nYou can instruct Spring Boot to load parts of your project with a different classloader by creating a `META-INF/spring-devtools.properties` file.\nThe `spring-devtools.properties` file can contain properties prefixed with `restart.exclude` and `restart.include`.\nThe `include` elements are items that should be pulled up into the \"`restart`\" classloader, and the `exclude` elements are items that should be pushed down into the \"`base`\" classloader.\nThe value of the property is a regex pattern that is applied to the classpath passed to the JVM on startup.\nHere is an example where some local class files are excluded and some extra libraries are included in the restart class loader:\n\n[source,properties]\n----\nrestart.exclude.companycommonlibs=\"/mycorp-common-[\\\\w\\\\d-\\\\.]/(build|bin|out|target)/\"\nrestart.include.projectcommon=\"/mycorp-myproj-[\\\\w\\\\d-\\\\.]+\\\\.jar\"\n----\n\nNOTE: All property keys must be unique.\nAs long as a property starts with `restart.include.` or `restart.exclude.` it is considered.\n\nTIP: All `META-INF/spring-devtools.properties` from the classpath are loaded.\nYou can package files inside your project, or in the libraries that the project consumes.\nSystem properties can not be used, only the properties file.\n\n\n\n[[using.devtools.restart.limitations]]\n=== Known Limitations\n\nRestart functionality does not work well with objects that are deserialized by using a standard javadoc:java.io.ObjectInputStream[].\nIf you need to deserialize data, you may need to use Spring's javadoc:org.springframework.core.ConfigurableObjectInputStream[] in combination with `Thread.currentThread().getContextClassLoader()`.\n\nUnfortunately, several third-party libraries deserialize without considering the context classloader.\nIf you find such a problem, you need to request a fix with the original authors.\n\n\n\n[[using.devtools.livereload]]\n== LiveReload\n\nWARNING: Given its decrease in popularity and support, the LiveReload feature is deprecated as of Spring Boot 4.1.0 with no replacement.\n\nThe `spring-boot-devtools` module includes an embedded LiveReload server that can be used to trigger a browser refresh when a resource is changed.\nLiveReload browser extensions are freely available for Chrome, Firefox and Safari.\nYou can find these extensions by searching 'LiveReload' in the marketplace or store of your chosen browser.\n\nIf you want to start the LiveReload server when your application runs, you can set the configprop:spring.devtools.livereload.enabled[deprecated] property to `true`.\n\nNOTE: You can only run one LiveReload server at a time.\nBefore starting your application, ensure that no other LiveReload servers are running.\nIf you start multiple applications from your IDE, only the first has LiveReload support.\n\nWARNING: To trigger LiveReload when a file changes, xref:using/devtools.adoc#using.devtools.restart[] must be enabled.\n\n\n\n[[using.devtools.globalsettings]]\n== Global Settings\n\nYou can configure global devtools settings by adding any of the following files to the `$HOME/.config/spring-boot` directory:\n\n. `spring-boot-devtools.properties`\n. `spring-boot-devtools.yaml`\n. `spring-boot-devtools.yml`\n\nAny properties added to these files apply to _all_ Spring Boot applications on your machine that use devtools.\nFor example, to configure restart to always use a xref:using/devtools.adoc#using.devtools.restart.triggerfile[trigger file], you would add the following property to your `spring-boot-devtools` file:\n\n[configprops,yaml]\n----\nspring:\n  devtools:\n    restart:\n      trigger-file: \".reloadtrigger\"\n----\n\nBy default, `$HOME` is the user's home directory.\nTo customize this location, set the `SPRING_DEVTOOLS_HOME` environment variable or the `spring.devtools.home` system property.\n\nNOTE: If devtools configuration files are not found in `$HOME/.config/spring-boot`, the root of the `$HOME` directory is searched for the presence of a `.spring-boot-devtools.properties` file.\nThis allows you to share the devtools global configuration with applications that are on an older version of Spring Boot that does not support the `$HOME/.config/spring-boot` location.\n\n[NOTE]\n====\nProfiles are not supported in devtools properties/yaml files.\n\nAny profiles activated in `.spring-boot-devtools.properties` will not affect the loading of xref:features/external-config.adoc#features.external-config.files.profile-specific[profile-specific configuration files].\nProfile specific filenames (of the form `spring-boot-devtools-<profile>.properties`) and `spring.config.activate.on-profile` documents in both YAML and Properties files are not supported.\n====\n\n\n\n[[using.devtools.globalsettings.configuring-file-system-watcher]]\n=== Configuring File System Watcher\n\njavadoc:org.springframework.boot.devtools.filewatch.FileSystemWatcher[] works by polling the class changes with a certain time interval, and then waiting for a predefined quiet period to make sure there are no more changes.\nSince Spring Boot relies entirely on the IDE to compile and copy files into the location from where Spring Boot can read them, you might find that there are times when certain changes are not reflected when devtools restarts the application.\nIf you observe such problems constantly, try increasing the `spring.devtools.restart.poll-interval` and `spring.devtools.restart.quiet-period` parameters to the values that fit your development environment:\n\n[configprops,yaml]\n----\nspring:\n  devtools:\n    restart:\n      poll-interval: \"2s\"\n      quiet-period: \"1s\"\n----\n\nThe monitored classpath directories are now polled every 2 seconds for changes, and a 1 second quiet period is maintained to make sure there are no additional class changes.\n\n\n\n[[using.devtools.remote-applications]]\n== Remote Applications\n\nThe Spring Boot developer tools are not limited to local development.\nYou can also use several features when running applications remotely.\nRemote support is opt-in as enabling it can be a security risk.\nIt should only be enabled when running on a trusted network or when secured with SSL.\nIf neither of these options is available to you, you should not use DevTools' remote support.\nYou should never enable support on a production deployment.\n\nTo enable it, you need to make sure that `devtools` is included in the repackaged archive, as shown in the following listing:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t<configuration>\n\t\t\t\t<includeOptional>true</includeOptional>\n\t\t\t\t<excludeDevtools>false</excludeDevtools>\n\t\t\t</configuration>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\nNOTE: Optional dependencies are not included by default, which explains why `includeOptional` is also present.\n\nThen you need to set the configprop:spring.devtools.remote.secret[] property.\nLike any important password or secret, the value should be unique and strong such that it cannot be guessed or brute-forced.\n\nRemote devtools support is provided in two parts: a server-side endpoint that accepts connections and a client application that you run in your IDE.\nThe server component is automatically enabled when the configprop:spring.devtools.remote.secret[] property is set.\nThe client component must be launched manually.\n\nNOTE: Remote devtools is not supported for Spring WebFlux applications.\n\n\n\n[[using.devtools.remote-applications.client]]\n=== Running the Remote Client Application\n\nThe remote client application is designed to be run from within your IDE.\nYou need to run javadoc:org.springframework.boot.devtools.RemoteSpringApplication[] with the same classpath as the remote project that you connect to.\nThe application's single required argument is the remote URL to which it connects.\n\nFor example, if you are using Eclipse or Spring Tools and you have a project named `my-app` that you have deployed to Cloud Foundry, you would do the following:\n\n* Select `Run Configurations...` from the `Run` menu.\n* Create a new `Java Application` \"`launch configuration`\".\n* Browse for the `my-app` project.\n* Use javadoc:org.springframework.boot.devtools.RemoteSpringApplication[] as the main class.\n* Add `+++https://myapp.cfapps.io+++` to the `Program arguments` (or whatever your remote URL is).\n\nA running remote client might resemble the following listing:\n\n[source,subs=\"verbatim,attributes\"]\n----\ninclude::ROOT:example$remote-spring-application.txt[]\n----\n\nNOTE: Because the remote client is using the same classpath as the real application it can directly read application properties.\nThis is how the configprop:spring.devtools.remote.secret[] property is read and passed to the server for authentication.\n\nTIP: It is always advisable to use `https://` as the connection protocol, so that traffic is encrypted and passwords cannot be intercepted.\n\nTIP: If you need to use a proxy to access the remote application, configure the `spring.devtools.remote.proxy.host` and `spring.devtools.remote.proxy.port` properties.\n\n\n\n[[using.devtools.remote-applications.update]]\n=== Remote Update\n\nThe remote client monitors your application classpath for changes in the same way as the xref:using/devtools.adoc#using.devtools.restart[local restart].\nAny updated resource is pushed to the remote application and (_if required_) triggers a restart.\nThis can be helpful if you iterate on a feature that uses a cloud service that you do not have locally.\nGenerally, remote updates and restarts are much quicker than a full rebuild and deploy cycle.\n\nOn a slower development environment, it may happen that the quiet period is not enough, and the changes in the classes may be split into batches.\nThe server is restarted after the first batch of class changes is uploaded.\nThe next batch can’t be sent to the application, since the server is restarting.\n\nThis is typically manifested by a warning in the javadoc:org.springframework.boot.devtools.RemoteSpringApplication[] logs about failing to upload some of the classes, and a consequent retry.\nBut it may also lead to application code inconsistency and failure to restart after the first batch of changes is uploaded.\nIf you observe such problems constantly, try increasing the `spring.devtools.restart.poll-interval` and `spring.devtools.restart.quiet-period` parameters to the values that fit your development environment.\nSee the xref:using/devtools.adoc#using.devtools.globalsettings.configuring-file-system-watcher[] section for configuring these properties.\n\nNOTE: Files are only monitored when the remote client is running.\nIf you change a file before starting the remote client, it is not pushed to the remote server.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/index.adoc",
    "content": "[[using]]\n= Developing with Spring Boot\n\nThis section goes into more detail about how you should use Spring Boot.\nIt covers topics such as build systems, auto-configuration, and how to run your applications.\nWe also cover some Spring Boot best practices.\nAlthough there is nothing particularly special about Spring Boot (it is just another library that you can consume), there are a few recommendations that, when followed, make your development process a little easier.\n\nIf you are starting out with Spring Boot, you should probably read the xref:tutorial:first-application/index.adoc[] tutorial before diving into this section.\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/packaging-for-production.adoc",
    "content": "[[using.packaging-for-production]]\n= Packaging Your Application for Production\n\nOnce your Spring Boot application is ready for production deployment, there are many options for packaging and optimizing\nthe application.\nSee the xref:packaging/index.adoc[] section of the documentation to read about these features.\n\nFor additional \"production ready\" features, such as health, auditing, and metric REST or JMX end-points, consider adding `spring-boot-actuator`.\nSee xref:how-to:actuator.adoc[] for details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/running-your-application.adoc",
    "content": "[[using.running-your-application]]\n= Running Your Application\n\nOne of the biggest advantages of packaging your application as a jar and using an embedded HTTP server is that you can run your application as you would any other.\nThe same applies to debugging Spring Boot applications.\nYou do not need any special IDE plugins or extensions.\n\nNOTE: The options below are best suited for running an application locally for development.\nFor production deployment, see xref:reference:using/packaging-for-production.adoc[].\n\nNOTE: This section only covers jar-based packaging.\nIf you choose to package your application as a war file, see your server and IDE documentation.\n\n\n\n[[using.running-your-application.from-an-ide]]\n== Running From an IDE\n\nYou can run a Spring Boot application from your IDE as a Java application.\nHowever, you first need to import your project.\nImport steps vary depending on your IDE and build system.\nMost IDEs can import Maven projects directly.\nFor example, Eclipse users can select `Import...` -> `Existing Maven Projects` from the `File` menu.\n\nIf you cannot directly import your project into your IDE, you may be able to generate IDE metadata by using a build plugin.\nMaven includes plugins for https://maven.apache.org/plugins/maven-eclipse-plugin/[Eclipse] and https://maven.apache.org/plugins/maven-idea-plugin/[IntelliJ IDEA].\nGradle offers plugins for {url-gradle-docs}/userguide.html[various IDEs].\n\nTIP: If you accidentally run a web application twice, you see a \"`Port already in use`\" error.\nSpring Tools users can use the `Relaunch` button rather than the `Run` button to ensure that any existing instance is closed.\n\n\n\n[[using.running-your-application.as-a-packaged-application]]\n== Running as a Packaged Application\n\nIf you use the Spring Boot Maven or Gradle plugins to create an executable jar, you can run your application using `java -jar`, as shown in the following example:\n\n[source,shell]\n----\n$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar\n----\n\nIt is also possible to run a packaged application with remote debugging support enabled.\nDoing so lets you attach a debugger to your packaged application, as shown in the following example:\n\n[source,shell]\n----\n$ java -agentlib:jdwp=server=y,transport=dt_socket,address=8000,suspend=n \\\n       -jar target/myapplication-0.0.1-SNAPSHOT.jar\n----\n\n\n\n[[using.running-your-application.with-the-maven-plugin]]\n== Using the Maven Plugin\n\nThe Spring Boot Maven plugin includes a `run` goal that can be used to quickly compile and run your application.\nApplications run in an exploded form, as they do in your IDE.\nThe following example shows a typical Maven command to run a Spring Boot application:\n\n[source,shell]\n----\n$ mvn spring-boot:run\n----\n\nYou might also want to use the `MAVEN_OPTS` operating system environment variable, as shown in the following example:\n\n[source,shell]\n----\n$ export MAVEN_OPTS=-Xmx1024m\n----\n\n\n\n[[using.running-your-application.with-the-gradle-plugin]]\n== Using the Gradle Plugin\n\nThe Spring Boot Gradle plugin also includes a `bootRun` task that can be used to run your application in an exploded form.\nThe `bootRun` task is added whenever you apply the `org.springframework.boot` and `java` plugins and is shown in the following example:\n\n[source,shell]\n----\n$ gradle bootRun\n----\n\nYou might also want to use the `JAVA_OPTS` operating system environment variable, as shown in the following example:\n\n[source,shell]\n----\n$ export JAVA_OPTS=-Xmx1024m\n----\n\n\n\n[[using.running-your-application.hot-swapping]]\n== Hot Swapping\n\nSince Spring Boot applications are plain Java applications, JVM hot-swapping should work out of the box.\nJVM hot swapping is somewhat limited with the bytecode that it can replace.\nFor a more complete solution, https://www.jrebel.com/products/jrebel[JRebel] can be used.\n\nThe `spring-boot-devtools` module also includes support for quick application restarts.\nSee the xref:how-to:hotswapping.adoc[] section in  \"`How-to Guides`\" for details.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/spring-beans-and-dependency-injection.adoc",
    "content": "[[using.spring-beans-and-dependency-injection]]\n= Spring Beans and Dependency Injection\n\nYou are free to use any of the standard Spring Framework techniques to define your beans and their injected dependencies.\nWe generally recommend using constructor injection to wire up dependencies and javadoc:org.springframework.context.annotation.ComponentScan[format=annotation] to find beans.\n\nIf you structure your code as suggested above (locating your application class in a top package), you can add javadoc:org.springframework.context.annotation.ComponentScan[format=annotation] without any arguments or use the javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotation which implicitly includes it.\nAll of your application components (javadoc:org.springframework.stereotype.Component[format=annotation], javadoc:org.springframework.stereotype.Service[format=annotation], javadoc:org.springframework.stereotype.Repository[format=annotation], javadoc:org.springframework.stereotype.Controller[format=annotation], and others) are automatically registered as Spring Beans.\n\nThe following example shows a javadoc:org.springframework.stereotype.Service[format=annotation] Bean that uses constructor injection to obtain a required `RiskAssessor` bean:\n\ninclude-code::singleconstructor/MyAccountService[]\n\nIf a bean has more than one constructor, you will need to mark the one you want Spring to use with javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation]:\n\ninclude-code::multipleconstructors/MyAccountService[]\n\nTIP: Notice how using constructor injection lets the `riskAssessor` field be marked as `final`, indicating that it cannot be subsequently changed.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/structuring-your-code.adoc",
    "content": "[[using.structuring-your-code]]\n= Structuring Your Code\n\nSpring Boot does not require any specific code layout to work.\nHowever, there are some best practices that help.\n\nTIP: If you wish to enforce a structure based on domains, take a look at https://spring.io/projects/spring-modulith#overview[Spring Modulith].\n\n\n\n[[using.structuring-your-code.using-the-default-package]]\n== Using the \"`default`\" Package\n\nWhen a class does not include a `package` declaration, it is considered to be in the \"`default package`\".\nThe use of the \"`default package`\" is generally discouraged and should be avoided.\nIt can cause particular problems for Spring Boot applications that use the javadoc:org.springframework.context.annotation.ComponentScan[format=annotation], javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesScan[format=annotation], javadoc:org.springframework.boot.persistence.autoconfigure.EntityScan[format=annotation], or javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotations, since every class from every jar is read.\n\nTIP: We recommend that you follow Java's recommended package naming conventions and use a reversed domain name (for example, `com.example.project`).\n\n\n\n[[using.structuring-your-code.locating-the-main-class]]\n== Locating the Main Application Class\n\nWe generally recommend that you locate your main application class in a root package above other classes.\nThe xref:using/using-the-springbootapplication-annotation.adoc[`@SpringBootApplication` annotation] is often placed on your main class, and it implicitly defines a base \"`search package`\" for certain items.\nFor example, if you are writing a JPA application, the package of the javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotated class is used to search for javadoc:jakarta.persistence.Entity[format=annotation] items.\nUsing a root package also allows component scan to apply only on your project.\n\nTIP: If you do not want to use javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation], the javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] and javadoc:org.springframework.context.annotation.ComponentScan[format=annotation] annotations that it imports defines that behavior so you can also use those instead.\n\nThe following listing shows a typical layout:\n\n[source]\n----\ncom\n +- example\n     +- myapplication\n         +- MyApplication.java\n         |\n         +- customer\n         |   +- Customer.java\n         |   +- CustomerController.java\n         |   +- CustomerService.java\n         |   +- CustomerRepository.java\n         |\n         +- order\n             +- Order.java\n             +- OrderController.java\n             +- OrderService.java\n             +- OrderRepository.java\n----\n\nThe `MyApplication.java` file would declare the `main` method, along with the basic javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation], as follows:\n\ninclude-code::MyApplication[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/using/using-the-springbootapplication-annotation.adoc",
    "content": "[[using.using-the-springbootapplication-annotation]]\n= Using the @SpringBootApplication Annotation\n\nMany Spring Boot developers like their apps to use auto-configuration, component scan and be able to define extra configuration on their \"application class\".\nA single javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] annotation can be used to enable those three features, that is:\n\n* javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation]: enable xref:using/auto-configuration.adoc[Spring Boot's auto-configuration mechanism]\n* javadoc:org.springframework.context.annotation.ComponentScan[format=annotation]: enable javadoc:org.springframework.stereotype.Component[format=annotation] scan on the package where the application is located (see xref:using/structuring-your-code.adoc[the best practices])\n* javadoc:org.springframework.boot.SpringBootConfiguration[format=annotation]: enable registration of extra beans in the context or the import of additional configuration classes.\nAn alternative to Spring's standard javadoc:org.springframework.context.annotation.Configuration[format=annotation] that aids xref:testing/spring-boot-applications.adoc#testing.spring-boot-applications.detecting-configuration[configuration detection] in your integration tests.\n\ninclude-code::springapplication/MyApplication[]\n\nNOTE: javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation] also provides aliases to customize the attributes of javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] and javadoc:org.springframework.context.annotation.ComponentScan[format=annotation].\n\n[NOTE]\n====\nNone of these features are mandatory and you may choose to replace this single annotation by any of the features that it enables.\nFor instance, you may not want to use component scan or configuration properties scan in your application:\n\ninclude-code::individualannotations/MyApplication[]\n\nIn this example, `MyApplication` is just like any other Spring Boot application except that javadoc:org.springframework.stereotype.Component[format=annotation]-annotated classes and javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]-annotated classes are not detected automatically and the user-defined beans are imported explicitly (see javadoc:org.springframework.context.annotation.Import[format=annotation]).\n====\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/graceful-shutdown.adoc",
    "content": "[[web.graceful-shutdown]]\n= Graceful Shutdown\n\nGraceful shutdown is enabled by default with all three embedded web servers (Jetty, Reactor Netty, and Tomcat) and with both reactive and servlet-based web applications.\nIt occurs as part of closing the application context and is performed in the earliest phase of stopping javadoc:org.springframework.context.SmartLifecycle[] beans.\nThis stop processing uses a timeout which provides a grace period during which existing requests will be allowed to complete but no new requests will be permitted.\n\nTo configure the timeout period, configure the configprop:spring.lifecycle.timeout-per-shutdown-phase[] property, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  lifecycle:\n    timeout-per-shutdown-phase: \"20s\"\n----\n\nIMPORTANT: Shutdown in your IDE may be immediate rather than graceful if it does not send a proper `SIGTERM` signal.\nSee the documentation of your IDE for more details.\n\n\n\n[[web.graceful-shutdown.rejecting-requests-during-the-grace-period]]\n== Rejecting Requests During the Grace Period\n\nThe exact way in which new requests are not permitted varies depending on the web server that is being used.\nImplementations may stop accepting requests at the network layer, or they may return a response with a specific HTTP status code or HTTP header.\nThe use of persistent connections can also change the way that requests stop being accepted.\n\nTIP: To learn more about the specific method used with your web server, see the `shutDownGracefully` API documentation for javadoc:org.springframework.boot.tomcat.TomcatWebServer#shutDownGracefully(org.springframework.boot.web.server.GracefulShutdownCallback)[], javadoc:org.springframework.boot.reactor.netty.NettyWebServer#shutDownGracefully(org.springframework.boot.web.server.GracefulShutdownCallback)[], or javadoc:org.springframework.boot.jetty.JettyWebServer#shutDownGracefully(org.springframework.boot.web.server.GracefulShutdownCallback)[].\n\nJetty, Reactor Netty, and Tomcat will stop accepting new requests at the network layer.\n\n\n\n[[web.graceful-shutdown.disabling-graceful-shutdown]]\n== Disabling Graceful Shutdown\n\nTo disable graceful shutdown, configure the configprop:server.shutdown[] property, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  shutdown: \"immediate\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/index.adoc",
    "content": "[[web]]\n= Web\n\nSpring Boot is well suited for web application development.\nYou can create a self-contained HTTP server by using embedded Tomcat, Jetty, or Netty.\nMost web applications use the `spring-boot-starter-web` module to get up and running quickly.\nYou can also choose to build reactive web applications by using the `spring-boot-starter-webflux` module.\n\nIf you have not yet developed a Spring Boot web application, you can follow the \"`Hello World!`\" example in the xref:tutorial:first-application/index.adoc[Getting started] section.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/reactive.adoc",
    "content": "[[web.reactive]]\n= Reactive Web Applications\n\nSpring Boot simplifies development of reactive web applications by providing auto-configuration for Spring Webflux.\n\n\n\n[[web.reactive.webflux]]\n== The \"`Spring WebFlux Framework`\"\n\nSpring WebFlux is the new reactive web framework introduced in Spring Framework 5.0.\nUnlike Spring MVC, it does not require the servlet API, is fully asynchronous and non-blocking, and implements the https://www.reactive-streams.org/[Reactive Streams] specification through https://projectreactor.io/[the Reactor project].\n\nSpring WebFlux comes in two flavors: functional and annotation-based.\nThe annotation-based one is quite close to the Spring MVC model, as shown in the following example:\n\ninclude-code::MyRestController[]\n\nWebFlux is part of the Spring Framework and detailed information is available in its {url-spring-framework-docs}/web/webflux.html[reference documentation].\n\n\"`WebFlux.fn`\", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:\n\ninclude-code::MyRoutingConfiguration[]\n\ninclude-code::MyUserHandler[]\n\n\"`WebFlux.fn`\" is part of the Spring Framework and detailed information is available in its {url-spring-framework-docs}/web/webflux-functional.html[reference documentation].\n\nTIP: You can define as many javadoc:org.springframework.web.reactive.function.server.RouterFunction[] beans as you like to modularize the definition of the router.\nBeans can be ordered if you need to apply a precedence.\n\nTo get started, add the `spring-boot-starter-webflux` module to your application.\n\nNOTE: Adding both `spring-boot-starter-web` and `spring-boot-starter-webflux` modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux.\nThis behavior has been chosen because many Spring developers add `spring-boot-starter-webflux` to their Spring MVC application to use the reactive javadoc:org.springframework.web.reactive.function.client.WebClient[].\nYou can still enforce your choice by setting the chosen application type to `SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)`.\n\n\n\n[[web.reactive.webflux.auto-configuration]]\n=== Spring WebFlux Auto-configuration\n\nSpring Boot provides auto-configuration for Spring WebFlux that works well with most applications.\n\nThe auto-configuration adds the following features on top of Spring's defaults:\n\n* Configuring codecs for javadoc:org.springframework.http.codec.HttpMessageReader[] and javadoc:org.springframework.http.codec.HttpMessageWriter[] instances (described xref:web/reactive.adoc#web.reactive.webflux.httpcodecs[later in this document]).\n* Support for serving static resources, including support for WebJars (described xref:web/servlet.adoc#web.servlet.spring-mvc.static-content[later in this document]).\n\nIf you want to keep Spring Boot WebFlux features and you want to add additional {url-spring-framework-docs}/web/webflux/config.html[WebFlux configuration], you can add your own javadoc:org.springframework.context.annotation.Configuration[format=annotation] class of type javadoc:org.springframework.web.reactive.config.WebFluxConfigurer[] but *without* javadoc:org.springframework.web.reactive.config.EnableWebFlux[format=annotation].\n\nIf you want to add additional customization to the auto-configured javadoc:org.springframework.http.server.reactive.HttpHandler[], you can define beans of type javadoc:org.springframework.boot.webflux.autoconfigure.WebHttpHandlerBuilderCustomizer[] and use them to modify the javadoc:org.springframework.web.server.adapter.WebHttpHandlerBuilder[].\n\nIf you want to take complete control of Spring WebFlux, you can add your own javadoc:org.springframework.context.annotation.Configuration[format=annotation] annotated with javadoc:org.springframework.web.reactive.config.EnableWebFlux[format=annotation].\n\n\n\n[[web.reactive.webflux.conversion-service]]\n=== Spring WebFlux Conversion Service\n\nIf you want to customize the javadoc:org.springframework.core.convert.ConversionService[] used by Spring WebFlux, you can provide a javadoc:org.springframework.web.reactive.config.WebFluxConfigurer[] bean with an `addFormatters` method.\n\nConversion can also be customized using the `spring.webflux.format.*` configuration properties.\nWhen not configured, the following defaults are used:\n\n|===\n|Property |`DateTimeFormatter` |Formats\n\n|configprop:spring.webflux.format.date[]\n|`ofLocalizedDate(FormatStyle.SHORT)`\n|`java.util.Date` and javadoc:java.time.LocalDate[]\n\n|configprop:spring.webflux.format.time[]\n|`ofLocalizedTime(FormatStyle.SHORT)`\n|java.time's javadoc:java.time.LocalTime[] and javadoc:java.time.OffsetTime[]\n\n|configprop:spring.webflux.format.date-time[]\n|`ofLocalizedDateTime(FormatStyle.SHORT)`\n|java.time's javadoc:java.time.LocalDateTime[], javadoc:java.time.OffsetDateTime[], and javadoc:java.time.ZonedDateTime[]\n|===\n\n\n\n[[web.reactive.webflux.httpcodecs]]\n=== HTTP Codecs with HttpMessageReaders and HttpMessageWriters\n\nSpring WebFlux uses the javadoc:org.springframework.http.codec.HttpMessageReader[] and javadoc:org.springframework.http.codec.HttpMessageWriter[] interfaces to convert HTTP requests and responses.\nThey are configured with javadoc:org.springframework.http.codec.CodecConfigurer[] to have sensible defaults by looking at the libraries available in your classpath.\n\nSpring Boot provides dedicated configuration properties for codecs, `+spring.http.codecs.*+`.\nIt also applies further customization by using javadoc:org.springframework.boot.http.codec.CodecCustomizer[] instances.\nFor example, `+spring.jackson.*+` configuration keys are applied to the Jackson codec.\n\nIf you need to add or customize codecs, you can create a custom javadoc:org.springframework.boot.http.codec.CodecCustomizer[] component, as shown in the following example:\n\ninclude-code::MyCodecsConfiguration[]\n\nYou can also leverage xref:features/json.adoc#features.json.jackson.custom-serializers-and-deserializers[Boot's custom JSON serializers and deserializers].\n\n\n\n[[web.reactive.webflux.static-content]]\n=== Static Content\n\nBy default, Spring Boot serves static content from a directory called `/static` (or `/public` or `/resources` or `/META-INF/resources`) in the classpath.\nIt uses the javadoc:org.springframework.web.reactive.resource.ResourceWebHandler[] from Spring WebFlux so that you can modify that behavior by adding your own javadoc:org.springframework.web.reactive.config.WebFluxConfigurer[] and overriding the `addResourceHandlers` method.\n\nBy default, resources are mapped on `+/**+`, but you can tune that by setting the configprop:spring.webflux.static-path-pattern[] property.\nFor instance, relocating all resources to `/resources/**` can be achieved as follows:\n\n[configprops,yaml]\n----\nspring:\n  webflux:\n    static-path-pattern: \"/resources/**\"\n----\n\nYou can also customize the static resource locations by using `spring.web.resources.static-locations`.\nDoing so replaces the default values with a list of directory locations.\nIf you do so, the default welcome page detection switches to your custom locations.\nSo, if there is an `index.html` in any of your locations on startup, it is the home page of the application.\n\nIn addition to the \"`standard`\" static resource locations listed earlier, a special case is made for https://www.webjars.org/[Webjars content].\nBy default, any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format.\nThe path can be customized with the configprop:spring.webflux.webjars-path-pattern[] property.\n\nTIP: Spring WebFlux applications do not strictly depend on the servlet API, so they cannot be deployed as war files and do not use the `src/main/webapp` directory.\n\n\n\n[[web.reactive.webflux.welcome-page]]\n=== Welcome Page\n\nSpring Boot supports both static and templated welcome pages.\nIt first looks for an `index.html` file in the configured static content locations.\nIf one is not found, it then looks for an `index` template.\nIf either is found, it is automatically used as the welcome page of the application.\n\nThis only acts as a fallback for actual index routes defined by the application.\nThe ordering is defined by the order of javadoc:org.springframework.web.reactive.HandlerMapping[] beans which is by default the following:\n\n[cols=\"1,1\"]\n|===\n|`org.springframework.web.reactive.function.server.support.RouterFunctionMapping`\n|Endpoints declared with javadoc:org.springframework.web.reactive.function.server.RouterFunction[] beans\n\n|`org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping`\n|Endpoints declared in javadoc:org.springframework.stereotype.Controller[format=annotation] beans\n\n|`RouterFunctionMapping` for the Welcome Page\n|The welcome page support\n|===\n\n\n\n[[web.reactive.webflux.template-engines]]\n=== Template Engines\n\nAs well as REST web services, you can also use Spring WebFlux to serve dynamic HTML content.\nSpring WebFlux supports a variety of templating technologies, including Thymeleaf, FreeMarker, and Mustache.\n\nSpring Boot includes auto-configuration support for the following templating engines:\n\n* https://freemarker.apache.org/docs/[FreeMarker]\n* https://www.thymeleaf.org[Thymeleaf]\n* https://mustache.github.io/[Mustache]\n\nNOTE: Not all FreeMarker features are supported with WebFlux.\nFor more details, check the description of each property.\n\nWhen you use one of these templating engines with the default configuration, your templates are picked up automatically from `src/main/resources/templates`.\n\n\n\n[[web.reactive.webflux.error-handling]]\n=== Error Handling\n\nSpring Boot provides a javadoc:org.springframework.web.server.WebExceptionHandler[] that handles all errors in a sensible way.\nIts position in the processing order is immediately before the handlers provided by WebFlux, which are considered last.\nFor machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.\nFor browser clients, there is a \"`whitelabel`\" error handler that renders the same data in HTML format.\nYou can also provide your own HTML templates to display errors (see the xref:web/reactive.adoc#web.reactive.webflux.error-handling.error-pages[next section]).\n\nBefore customizing error handling in Spring Boot directly, you can leverage the {url-spring-framework-docs}/web/webflux/ann-rest-exceptions.html[RFC 9457 Problem Details] support in Spring WebFlux.\nSpring WebFlux can produce custom error messages with the `application/problem+json` media type, like:\n\n[source,json]\n----\n{\n\t\"type\": \"https://example.org/problems/unknown-project\",\n\t\"title\": \"Unknown project\",\n\t\"status\": 404,\n\t\"detail\": \"No project found for id 'spring-unknown'\",\n\t\"instance\": \"/projects/spring-unknown\"\n}\n----\n\nThis support can be enabled by setting configprop:spring.webflux.problemdetails.enabled[] to `true`.\n\n\nThe first step to customizing this feature often involves using the existing mechanism but replacing or augmenting the error contents.\nFor that, you can add a bean of type javadoc:org.springframework.boot.webflux.error.ErrorAttributes[].\n\nTo change the error handling behavior, you can implement javadoc:org.springframework.boot.webflux.error.ErrorWebExceptionHandler[] and register a bean definition of that type.\nBecause an javadoc:org.springframework.boot.webflux.error.ErrorWebExceptionHandler[] is quite low-level, Spring Boot also provides a convenient javadoc:org.springframework.boot.webflux.autoconfigure.error.AbstractErrorWebExceptionHandler[] to let you handle errors in a WebFlux functional way, as shown in the following example:\n\ninclude-code::MyErrorWebExceptionHandler[]\n\nFor a more complete picture, you can also subclass javadoc:org.springframework.boot.webflux.autoconfigure.error.DefaultErrorWebExceptionHandler[] directly and override specific methods.\n\nIn some cases, errors handled at the controller level are not recorded by web observations or the xref:actuator/metrics.adoc#actuator.metrics.supported.spring-webflux[metrics infrastructure].\nApplications can ensure that such exceptions are recorded with the observations by {url-spring-framework-docs}/integration/observability.html#observability.http-server.reactive[setting the handled exception on the observation context].\n\n\n\n[[web.reactive.webflux.error-handling.error-pages]]\n==== Custom Error Pages\n\nIf you want to display a custom HTML error page for a given status code, you can add views that resolve from `error/*`, for example by adding files to a `/error` directory.\nError pages can either be static HTML (that is, added under any of the static resource directories) or built with templates.\nThe name of the file should be the exact status code, a status code series mask, or `error` for a default if nothing else matches.\nNote that the path to the default error view is `error/error`, whereas with Spring MVC the default error view is `error`.\n\nFor example, to map `404` to a static HTML file, your directory structure would be as follows:\n\n[source]\n----\nsrc/\n +- main/\n     +- java/\n     |   + <source code>\n     +- resources/\n         +- public/\n             +- error/\n             |   +- 404.html\n             +- <other public assets>\n----\n\nTo map all `5xx` errors by using a Mustache template, your directory structure would be as follows:\n\n[source]\n----\nsrc/\n +- main/\n     +- java/\n     |   + <source code>\n     +- resources/\n         +- templates/\n             +- error/\n             |   +- 5xx.mustache\n             +- <other templates>\n----\n\n\n\n[[web.reactive.webflux.web-filters]]\n=== Web Filters\n\nSpring WebFlux provides a javadoc:org.springframework.web.server.WebFilter[] interface that can be implemented to filter HTTP request-response exchanges.\njavadoc:org.springframework.web.server.WebFilter[] beans found in the application context will be automatically used to filter each exchange.\n\nWhere the order of the filters is important they can implement javadoc:org.springframework.core.Ordered[] or be annotated with javadoc:org.springframework.core.annotation.Order[format=annotation].\nSpring Boot auto-configuration may configure web filters for you.\nWhen it does so, the orders shown in the following table will be used:\n\n|===\n| Web Filter | Order\n\n| javadoc:org.springframework.security.web.server.WebFilterChainProxy[] (Spring Security)\n| `-100`\n\n| javadoc:org.springframework.boot.webflux.actuate.web.exchanges.HttpExchangesWebFilter[]\n| `Ordered.LOWEST_PRECEDENCE - 10`\n|===\n\n\n\n[[web.reactive.webflux.api-versioning]]\n=== API Versioning\n\nSpring WebFlux supports API versioning which can be used to evolve an HTTP API over time.\nThe same `@Controller` path can be mapped multiple times to support different versions of the API.\n\nFor more details see {url-spring-framework-docs}/web/webflux/controller/ann-requestmapping.html#webflux-ann-requestmapping-version[Spring Framework's reference documentation].\n\nOnce mappings have been added, you additionally need to configure Spring WebFlux so that it is able to use any version information sent with a request.\nTypically, versions are sent as HTTP headers, query parameters or as part of the path.\n\nTo configure Spring WebFlux, you can either use a javadoc:org.springframework.web.reactive.config.WebFluxConfigurer[] bean and override the `configureApiVersioning(...)` method, or you can use properties.\n\nFor example, the following will use an `X-Version` HTTP header to obtain version information and default to `1.0.0` when no header is sent.\n\n[configprops,yaml]\n----\nspring:\n  webflux:\n    apiversion:\n      default: 1.0.0\n      use:\n        header: X-Version\n----\n\nFor more complete control, you can also define javadoc:org.springframework.web.reactive.accept.ApiVersionResolver[], javadoc:org.springframework.web.accept.ApiVersionParser[] and javadoc:org.springframework.web.reactive.accept.ApiVersionDeprecationHandler[] beans which will be injected into the auto-configured Spring MVC configuration.\n\nTIP: API versioning is also supported on the client-side with both `WebClient` and `RestClient`.\nSee xref:io/rest-client.adoc#io.rest-client.apiversioning[] for details.\n\n\n\n[[web.reactive.reactive-server]]\n== Embedded Reactive Server Support\n\nSpring Boot includes support for the following embedded reactive web servers: Reactor Netty, Tomcat, and Jetty.\nMost developers use the appropriate starter to obtain a fully configured instance.\nBy default, the embedded server listens for HTTP requests on port 8080.\n\n\n\n[[web.reactive.reactive-server.customizing]]\n=== Customizing Reactive Servers\n\nCommon reactive web server settings can be configured by using Spring javadoc:org.springframework.core.env.Environment[] properties.\nUsually, you would define the properties in your `application.properties` or `application.yaml` file.\n\nCommon server settings include:\n\n* Network settings: Listen port for incoming HTTP requests (`server.port`), interface address to bind to (`server.address`), and so on.\n* Error management: Location of the error page (configprop:spring.web.error.path[]) and so on.\n* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[SSL]\n* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[HTTP compression]\n\nSpring Boot tries as much as possible to expose common settings, but this is not always possible.\nFor those cases, dedicated namespaces such as `server.netty.*` offer server-specific customizations.\n\nTIP: See the javadoc:org.springframework.boot.web.server.autoconfigure.ServerProperties[] class for a complete list.\n\n\n\n[[web.reactive.reactive-server.customizing.programmatic]]\n==== Programmatic Customization\n\nIf you need to programmatically configure your reactive web server, you can register a Spring bean that implements the javadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] interface.\njavadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] provides access to the javadoc:org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory[], which includes numerous customization setter methods.\nThe following example shows programmatically setting the port:\n\ninclude-code::MyWebServerFactoryCustomizer[]\n\njavadoc:org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory[], javadoc:org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory[], and javadoc:org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory[] are dedicated variants of javadoc:org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory[] that have additional customization setter methods for Jetty, Reactor Netty, and Tomcat respectively.\nThe following example shows how to customize javadoc:org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory[] that provides access to Reactor Netty-specific configuration options:\n\ninclude-code::MyNettyWebServerFactoryCustomizer[]\n\n\n\n[[web.reactive.reactive-server.customizing.direct]]\n==== Customizing ConfigurableReactiveWebServerFactory Directly\n\nFor more advanced use cases that require you to extend from javadoc:org.springframework.boot.web.server.reactive.ReactiveWebServerFactory[], you can expose a bean of such type yourself.\n\nSetters are provided for many configuration options.\nSeveral protected method \"`hooks`\" are also provided should you need to do something more exotic.\nSee the javadoc:org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory[] API documentation for details.\n\nNOTE: Auto-configured customizers are still applied on your custom factory, so use that option carefully.\n\n\n\n[[web.reactive.reactive-server-resources-configuration]]\n== Reactive Server Resources Configuration\n\nWhen auto-configuring a Reactor Netty or Jetty server, Spring Boot will create specific beans that will provide HTTP resources to the server instance: javadoc:org.springframework.http.client.ReactorResourceFactory[] or javadoc:org.springframework.http.client.reactive.JettyResourceFactory[].\n\nBy default, those resources will be also shared with the Reactor Netty and Jetty clients for optimal performances, given:\n\n* the same technology is used for server and client\n* the client instance is built using the javadoc:org.springframework.web.reactive.function.client.WebClient$Builder[] bean auto-configured by Spring Boot\n\nDevelopers can override the resource configuration for Jetty and Reactor Netty by providing a custom javadoc:org.springframework.http.client.ReactorResourceFactory[] or javadoc:org.springframework.http.client.reactive.JettyResourceFactory[] bean - this will be applied to both clients and servers.\n\nYou can learn more about the resource configuration on the client side in the xref:io/rest-client.adoc#io.rest-client.webclient.runtime[] section.\n\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/servlet.adoc",
    "content": "[[web.servlet]]\n= Servlet Web Applications\n\nIf you want to build servlet-based web applications, you can take advantage of Spring Boot's auto-configuration for Spring MVC or Jersey.\n\n\n\n[[web.servlet.spring-mvc]]\n== The \"`Spring Web MVC Framework`\"\n\nThe {url-spring-framework-docs}/web/webmvc.html[Spring Web MVC framework] (often referred to as \"`Spring MVC`\") is a rich \"`model view controller`\" web framework.\nSpring MVC lets you create special javadoc:org.springframework.stereotype.Controller[format=annotation] or javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] beans to handle incoming HTTP requests.\nMethods in your controller are mapped to HTTP by using javadoc:org.springframework.web.bind.annotation.RequestMapping[format=annotation] annotations.\n\nThe following code shows a typical javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] that serves JSON data:\n\ninclude-code::MyRestController[]\n\n\"`WebMvc.fn`\", the functional variant, separates the routing configuration from the actual handling of the requests, as shown in the following example:\n\ninclude-code::MyRoutingConfiguration[]\n\ninclude-code::MyUserHandler[]\n\nSpring MVC is part of the core Spring Framework, and detailed information is available in the {url-spring-framework-docs}/web/webmvc.html[reference documentation].\nThere are also several guides that cover Spring MVC available at https://spring.io/guides.\n\nTIP: You can define as many javadoc:org.springframework.web.servlet.function.RouterFunction[] beans as you like to modularize the definition of the router.\nBeans can be ordered if you need to apply a precedence.\n\n\n\n[[web.servlet.spring-mvc.auto-configuration]]\n=== Spring MVC Auto-configuration\n\nSpring Boot provides auto-configuration for Spring MVC that works well with most applications.\nIt replaces the need for javadoc:org.springframework.web.servlet.config.annotation.EnableWebMvc[format=annotation] and the two cannot be used together.\nIn addition to Spring MVC's defaults, the auto-configuration provides the following features:\n\n* Inclusion of javadoc:org.springframework.web.servlet.view.ContentNegotiatingViewResolver[] and javadoc:org.springframework.web.servlet.view.BeanNameViewResolver[] beans.\n* Support for serving static resources, including support for WebJars (covered xref:web/servlet.adoc#web.servlet.spring-mvc.static-content[later in this document]).\n* Automatic registration of javadoc:org.springframework.core.convert.converter.Converter[], javadoc:org.springframework.core.convert.converter.GenericConverter[], and javadoc:org.springframework.format.Formatter[] beans.\n* Support for javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] (covered xref:web/servlet.adoc#web.servlet.spring-mvc.message-converters[later in this document]).\n* Automatic registration of javadoc:org.springframework.validation.MessageCodesResolver[] (covered xref:web/servlet.adoc#web.servlet.spring-mvc.message-codes[later in this document]).\n* Static `index.html` support.\n* Automatic use of a javadoc:org.springframework.web.bind.support.ConfigurableWebBindingInitializer[] bean (covered xref:web/servlet.adoc#web.servlet.spring-mvc.binding-initializer[later in this document]).\n\nIf you want to keep those Spring Boot MVC customizations and make more {url-spring-framework-docs}/web/webmvc.html[MVC customizations] (interceptors, formatters, view controllers, and other features), you can add your own javadoc:org.springframework.context.annotation.Configuration[format=annotation] class of type javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] but *without* javadoc:org.springframework.web.servlet.config.annotation.EnableWebMvc[format=annotation].\n\nIf you want to provide custom instances of javadoc:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping[], javadoc:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter[], or javadoc:org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver[], and still keep the Spring Boot MVC customizations, you can declare a bean of type javadoc:org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations[] and use it to provide custom instances of those components.\nThe custom instances will be subject to further initialization and configuration by Spring MVC.\nTo participate in, and if desired, override that subsequent processing, a javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] should be used.\n\nIf you do not want to use the auto-configuration and want to take complete control of Spring MVC, add your own javadoc:org.springframework.context.annotation.Configuration[format=annotation] annotated with javadoc:org.springframework.web.servlet.config.annotation.EnableWebMvc[format=annotation].\nAlternatively, add your own javadoc:org.springframework.context.annotation.Configuration[format=annotation]-annotated javadoc:org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration[] as described in the javadoc:org.springframework.web.servlet.config.annotation.EnableWebMvc[format=annotation] API documentation.\n\n\n\n[[web.servlet.spring-mvc.conversion-service]]\n=== Spring MVC Conversion Service\n\nSpring MVC uses a different javadoc:org.springframework.core.convert.ConversionService[] to the one used to convert values from your `application.properties` or `application.yaml` file.\nIt means that javadoc:java.time.Period[], javadoc:java.time.Duration[] and javadoc:org.springframework.util.unit.DataSize[] converters are not available and that javadoc:org.springframework.boot.convert.DurationUnit[format=annotation] and javadoc:org.springframework.boot.convert.DataSizeUnit[format=annotation] annotations will be ignored.\n\nIf you want to customize the javadoc:org.springframework.core.convert.ConversionService[] used by Spring MVC, you can provide a javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] bean with an `addFormatters` method.\nFrom this method you can register any converter that you like, or you can delegate to the static methods available on javadoc:org.springframework.boot.convert.ApplicationConversionService[].\n\nConversion can also be customized using the `spring.mvc.format.*` configuration properties.\nWhen not configured, the following defaults are used:\n\n|===\n|Property |`DateTimeFormatter` |Formats\n\n|configprop:spring.mvc.format.date[]\n|`ofLocalizedDate(FormatStyle.SHORT)`\n|`java.util.Date` and javadoc:java.time.LocalDate[]\n\n|configprop:spring.mvc.format.time[]\n|`ofLocalizedTime(FormatStyle.SHORT)`\n|java.time's javadoc:java.time.LocalTime[] and javadoc:java.time.OffsetTime[]\n\n|configprop:spring.mvc.format.date-time[]\n|`ofLocalizedDateTime(FormatStyle.SHORT)`\n|java.time's javadoc:java.time.LocalDateTime[], javadoc:java.time.OffsetDateTime[], and javadoc:java.time.ZonedDateTime[]\n|===\n\n\n\n[[web.servlet.spring-mvc.message-converters]]\n=== HttpMessageConverters\n\nSpring MVC uses the javadoc:org.springframework.http.converter.HttpMessageConverter[] interface to convert HTTP requests and responses.\nSensible defaults are included out of the box.\nFor example, objects can be automatically converted to JSON (by using the Jackson library) or XML (by using the Jackson XML extension, if available, or by using JAXB if the Jackson XML extension is not available).\nBy default, strings are encoded in `UTF-8`.\n\nAny javadoc:org.springframework.http.converter.HttpMessageConverter[] bean that is present in the context is added to the list of converters.\nYou can also override default converters in the same way.\n\nIf you need to add or customize converters, you can declare one or more javadoc:org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer[] or\njavadoc:org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer[] as beans. There, you can choose whether converter instances should be added\nbefore default ones (`addCustomConverter`) or if they should override a specific default converter (like `withJsonConverter`).\n\nSee the following listing for an example:\n\ninclude-code::MyHttpMessageConvertersConfiguration[]\n\n\n\n[[web.servlet.spring-mvc.message-codes]]\n=== MessageCodesResolver\n\nSpring MVC has a strategy for generating error codes for rendering error messages from binding errors: javadoc:org.springframework.validation.MessageCodesResolver[].\nIf you set the configprop:spring.mvc.message-codes-resolver-format[] property `PREFIX_ERROR_CODE` or `POSTFIX_ERROR_CODE`, Spring Boot creates one for you (see the enumeration in javadoc:org.springframework.validation.DefaultMessageCodesResolver$Format[]).\n\n\n\n[[web.servlet.spring-mvc.static-content]]\n=== Static Content\n\nBy default, Spring Boot serves static content from a directory called `/static` (or `/public` or `/resources` or `/META-INF/resources`) in the classpath or from the root of the javadoc:jakarta.servlet.ServletContext[].\nIt uses the javadoc:org.springframework.web.servlet.resource.ResourceHttpRequestHandler[] from Spring MVC so that you can modify that behavior by adding your own javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] and overriding the `addResourceHandlers` method.\n\nIn a stand-alone web application, the default servlet from the container is not enabled.\nIt can be enabled using the configprop:server.servlet.register-default-servlet[] property.\n\nThe default servlet acts as a fallback, serving content from the root of the javadoc:jakarta.servlet.ServletContext[] if Spring decides not to handle it.\nMost of the time, this does not happen (unless you modify the default MVC configuration), because Spring can always handle requests through the javadoc:org.springframework.web.servlet.DispatcherServlet[].\n\nBy default, resources are mapped on `+/**+`, but you can tune that with the configprop:spring.mvc.static-path-pattern[] property.\nFor instance, relocating all resources to `/resources/**` can be achieved as follows:\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    static-path-pattern: \"/resources/**\"\n----\n\nYou can also customize the static resource locations by using the configprop:spring.web.resources.static-locations[] property (replacing the default values with a list of directory locations).\nThe root servlet context path, `\"/\"`, is automatically added as a location as well.\n\nIn addition to the \"`standard`\" static resource locations mentioned earlier, a special case is made for https://www.webjars.org/[Webjars content].\nBy default, any resources with a path in `+/webjars/**+` are served from jar files if they are packaged in the Webjars format.\nThe path can be customized with the configprop:spring.mvc.webjars-path-pattern[] property.\n\nTIP: Do not use the `src/main/webapp` directory if your application is packaged as a jar.\nAlthough this directory is a common standard, it works *only* with war packaging, and it is silently ignored by most build tools if you generate a jar.\n\nSpring Boot also supports the advanced resource handling features provided by Spring MVC, allowing use cases such as cache-busting static resources or using version agnostic URLs for Webjars.\n\nTo use version agnostic URLs for Webjars, add the `org.webjars:webjars-locator-lite` dependency.\nThen declare your Webjar.\nUsing jQuery as an example, adding `\"/webjars/jquery/jquery.min.js\"` results in `\"/webjars/jquery/x.y.z/jquery.min.js\"` where `x.y.z` is the Webjar version.\n\nTo use cache busting, the following configuration configures a cache busting solution for all static resources, effectively adding a content hash, such as `<link href=\"/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css\"/>`, in URLs:\n\n[configprops,yaml]\n----\nspring:\n  web:\n    resources:\n      chain:\n        strategy:\n          content:\n            enabled: true\n            paths: \"/**\"\n----\n\nNOTE: Links to resources are rewritten in templates at runtime, thanks to a javadoc:org.springframework.web.servlet.resource.ResourceUrlEncodingFilter[] that is auto-configured for Thymeleaf and FreeMarker.\nYou should manually declare this filter when using JSPs.\nOther template engines are currently not automatically supported but can be with custom template macros/helpers and the use of the javadoc:org.springframework.web.servlet.resource.ResourceUrlProvider[].\n\nWhen loading resources dynamically with, for example, a JavaScript module loader, renaming files is not an option.\nThat is why other strategies are also supported and can be combined.\nA \"fixed\" strategy adds a static version string in the URL without changing the file name, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  web:\n    resources:\n      chain:\n        strategy:\n          content:\n            enabled: true\n            paths: \"/**\"\n          fixed:\n            enabled: true\n            paths: \"/js/lib/\"\n            version: \"v12\"\n----\n\nWith this configuration, JavaScript modules located under `\"/js/lib/\"` use a fixed versioning strategy (`\"/v12/js/lib/mymodule.js\"`), while other resources still use the content one (`<link href=\"/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css\"/>`).\n\nSee javadoc:org.springframework.boot.autoconfigure.web.WebProperties$Resources[] for more supported options.\n\n[TIP]\n====\nThis feature has been thoroughly described in a dedicated https://spring.io/blog/2014/07/24/spring-framework-4-1-handling-static-web-resources[blog post] and in Spring Framework's {url-spring-framework-docs}/web/webmvc/mvc-config/static-resources.html[reference documentation].\n====\n\n\n\n[[web.servlet.spring-mvc.welcome-page]]\n=== Welcome Page\n\nSpring Boot supports both static and templated welcome pages.\nIt first looks for an `index.html` file in the configured static content locations.\nIf one is not found, it then looks for an `index` template.\nIf either is found, it is automatically used as the welcome page of the application.\n\nThis only acts as a fallback for actual index routes defined by the application.\nThe ordering is defined by the order of javadoc:org.springframework.web.servlet.HandlerMapping[] beans which is by default the following:\n\n[cols=\"1,1\"]\n|===\n|`RouterFunctionMapping`\n|Endpoints declared with javadoc:org.springframework.web.servlet.function.RouterFunction[] beans\n\n|`RequestMappingHandlerMapping`\n|Endpoints declared in javadoc:org.springframework.stereotype.Controller[format=annotation] beans\n\n|`WelcomePageHandlerMapping`\n|The welcome page support\n|===\n\n\n\n[[web.servlet.spring-mvc.favicon]]\n=== Custom Favicon\n\nAs with other static resources, Spring Boot checks for a `favicon.ico` in the configured static content locations.\nIf such a file is present, it is automatically used as the favicon of the application.\n\n\n\n[[web.servlet.spring-mvc.content-negotiation]]\n=== Path Matching and Content Negotiation\n\nSpring MVC can map incoming HTTP requests to handlers by looking at the request path and matching it to the mappings defined in your application (for example, javadoc:org.springframework.web.bind.annotation.GetMapping[format=annotation] annotations on Controller methods).\n\nSpring Boot chooses to disable suffix pattern matching by default, which means that requests like `\"GET /projects/spring-boot.json\"` will not be matched to `@GetMapping(\"/projects/spring-boot\")` mappings.\nThis is considered as a {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-suffix-pattern-match[best practice for Spring MVC applications].\nThis feature was mainly useful in the past for HTTP clients which did not send proper \"Accept\" request headers; we needed to make sure to send the correct Content Type to the client.\nNowadays, Content Negotiation is much more reliable.\n\nThere are other ways to deal with HTTP clients that do not consistently send proper \"Accept\" request headers.\nInstead of using suffix matching, we can use a query parameter to ensure that requests like `\"GET /projects/spring-boot?format=json\"` will be mapped to `@GetMapping(\"/projects/spring-boot\")`:\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    contentnegotiation:\n      favor-parameter: true\n----\n\nOr if you prefer to use a different parameter name:\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    contentnegotiation:\n      favor-parameter: true\n      parameter-name: \"myparam\"\n----\n\nMost standard media types are supported out-of-the-box, but you can also define new ones:\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    contentnegotiation:\n      media-types:\n        markdown: \"text/markdown\"\n----\n\nAs of Spring Framework 5.3, Spring MVC supports two strategies for matching request paths to controllers.\nBy default, Spring Boot uses the javadoc:org.springframework.web.util.pattern.PathPatternParser[] strategy.\njavadoc:org.springframework.web.util.pattern.PathPatternParser[] is an https://spring.io/blog/2020/06/30/url-matching-with-pathpattern-in-spring-mvc[optimized implementation] but comes with some restrictions compared to the javadoc:org.springframework.util.AntPathMatcher[] strategy.\njavadoc:org.springframework.web.util.pattern.PathPatternParser[] restricts usage of {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-uri-templates[some path pattern variants].\nIt is also incompatible with configuring the javadoc:org.springframework.web.servlet.DispatcherServlet[] with a path prefix (configprop:spring.mvc.servlet.path[]).\n\nThe strategy can be configured using the configprop:spring.mvc.pathmatch.matching-strategy[] configuration property, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    pathmatch:\n      matching-strategy: \"ant-path-matcher\"\n----\n\nSpring MVC will throw a javadoc:org.springframework.web.servlet.NoHandlerFoundException[] if a handler is not found for a request.\nNote that, by default, the xref:web/servlet.adoc#web.servlet.spring-mvc.static-content[serving of static content] is mapped to `+/**+` and will, therefore, provide a handler for all requests.\nIf no static content is available, javadoc:org.springframework.web.servlet.resource.ResourceHttpRequestHandler[] will throw a javadoc:org.springframework.web.servlet.resource.NoResourceFoundException[].\nFor a javadoc:org.springframework.web.servlet.NoHandlerFoundException[] to be thrown, set configprop:spring.mvc.static-path-pattern[] to a more specific value such as `/resources/**` or set configprop:spring.web.resources.add-mappings[] to `false` to disable serving of static content entirely.\n\n\n\n[[web.servlet.spring-mvc.binding-initializer]]\n=== ConfigurableWebBindingInitializer\n\nSpring MVC uses a javadoc:org.springframework.web.bind.support.WebBindingInitializer[] to initialize a javadoc:org.springframework.web.bind.WebDataBinder[] for a particular request.\nIf you create your own javadoc:org.springframework.web.bind.support.ConfigurableWebBindingInitializer[] javadoc:org.springframework.context.annotation.Bean[format=annotation], Spring Boot automatically configures Spring MVC to use it.\n\n\n\n[[web.servlet.spring-mvc.template-engines]]\n=== Template Engines\n\nAs well as REST web services, you can also use Spring MVC to serve dynamic HTML content.\nSpring MVC supports a variety of templating technologies, including Thymeleaf, FreeMarker, and JSPs.\nAlso, many other templating engines include their own Spring MVC integrations.\n\nSpring Boot includes auto-configuration support for the following templating engines:\n\n* https://freemarker.apache.org/docs/[FreeMarker]\n* https://docs.groovy-lang.org/docs/next/html/documentation/template-engines.html#_the_markuptemplateengine[Groovy]\n* https://www.thymeleaf.org[Thymeleaf]\n* https://mustache.github.io/[Mustache]\n\nTIP: If possible, JSPs should be avoided.\nThere are several xref:web/servlet.adoc#web.servlet.embedded-container.jsp-limitations[known limitations] when using them with embedded servlet containers.\n\nWhen you use one of these templating engines with the default configuration, your templates are picked up automatically from `src/main/resources/templates`.\n\nTIP: Depending on how you run your application, your IDE may order the classpath differently.\nRunning your application in the IDE from its main method results in a different ordering than when you run your application by using Maven or Gradle or from its packaged jar.\nThis can cause Spring Boot to fail to find the expected template.\nIf you have this problem, you can reorder the classpath in the IDE to place the module's classes and resources first.\n\n\n\n[[web.servlet.spring-mvc.error-handling]]\n=== Error Handling\n\nBy default, Spring Boot provides an `/error` mapping that handles all errors in a sensible way, and it is registered as a \"`global`\" error page in the servlet container.\nFor machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.\nFor browser clients, there is a \"`whitelabel`\" error view that renders the same data in HTML format (to customize it, add a javadoc:org.springframework.web.servlet.View[] that resolves to `error`).\n\nThere are a number of `spring.web.error` properties that can be set if you want to customize the default error handling behavior.\nSee the xref:appendix:application-properties/index.adoc#appendix.application-properties.web[Web Properties] section of the Appendix.\n\nTo replace the default behavior completely, you can implement javadoc:org.springframework.boot.webmvc.error.ErrorController[] and register a bean definition of that type or add a bean of type javadoc:org.springframework.boot.webmvc.error.ErrorAttributes[] to use the existing mechanism but replace the contents.\n\nTIP: The javadoc:org.springframework.boot.webmvc.autoconfigure.error.BasicErrorController[] can be used as a base class for a custom javadoc:org.springframework.boot.webmvc.error.ErrorController[].\nThis is particularly useful if you want to add a handler for a new content type (the default is to handle `text/html` specifically and provide a fallback for everything else).\nTo do so, extend javadoc:org.springframework.boot.webmvc.autoconfigure.error.BasicErrorController[], add a public method with a javadoc:org.springframework.web.bind.annotation.RequestMapping[format=annotation] that has a `produces` attribute, and create a bean of your new type.\n\nAs of Spring Framework 6.0, {url-spring-framework-docs}/web/webmvc/mvc-ann-rest-exceptions.html[RFC 9457 Problem Details] is supported.\nSpring MVC can produce custom error messages with the `application/problem+json` media type, like:\n\n[source,json]\n----\n{\n\t\"type\": \"https://example.org/problems/unknown-project\",\n\t\"title\": \"Unknown project\",\n\t\"status\": 404,\n\t\"detail\": \"No project found for id 'spring-unknown'\",\n\t\"instance\": \"/projects/spring-unknown\"\n}\n----\n\nThis support can be enabled by setting configprop:spring.mvc.problemdetails.enabled[] to `true`.\n\nYou can also define a class annotated with javadoc:org.springframework.web.bind.annotation.ControllerAdvice[format=annotation] to customize the JSON document to return for a particular controller and/or exception type, as shown in the following example:\n\ninclude-code::MyControllerAdvice[]\n\nIn the preceding example, if `MyException` is thrown by a controller defined in the same package as `SomeController`, a JSON representation of the `MyErrorBody` POJO is used instead of the javadoc:org.springframework.boot.webmvc.error.ErrorAttributes[] representation.\n\nIn some cases, errors handled at the controller level are not recorded by web observations or the xref:actuator/metrics.adoc#actuator.metrics.supported.spring-mvc[metrics infrastructure].\nApplications can ensure that such exceptions are recorded with the observations by {url-spring-framework-docs}/integration/observability.html#observability.http-server.servlet[setting the handled exception on the observation context].\n\n\n\n[[web.servlet.spring-mvc.error-handling.error-pages]]\n==== Custom Error Pages\n\nIf you want to display a custom HTML error page for a given status code, you can add a file to an `/error` directory.\nError pages can either be static HTML (that is, added under any of the static resource directories) or be built by using templates.\nThe name of the file should be the exact status code or a series mask.\n\nFor example, to map `404` to a static HTML file, your directory structure would be as follows:\n\n[source]\n----\nsrc/\n +- main/\n     +- java/\n     |   + <source code>\n     +- resources/\n         +- public/\n             +- error/\n             |   +- 404.html\n             +- <other public assets>\n----\n\nTo map all `5xx` errors by using a FreeMarker template, your directory structure would be as follows:\n\n[source]\n----\nsrc/\n +- main/\n     +- java/\n     |   + <source code>\n     +- resources/\n         +- templates/\n             +- error/\n             |   +- 5xx.ftlh\n             +- <other templates>\n----\n\nFor more complex mappings, you can also add beans that implement the javadoc:org.springframework.boot.webmvc.autoconfigure.error.ErrorViewResolver[] interface, as shown in the following example:\n\ninclude-code::MyErrorViewResolver[]\n\nYou can also use regular Spring MVC features such as {url-spring-framework-docs}/web/webmvc/mvc-servlet/exceptionhandlers.html[`@ExceptionHandler` methods] and {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-advice.html[`@ControllerAdvice`].\nThe javadoc:org.springframework.boot.webmvc.error.ErrorController[] then picks up any unhandled exceptions.\n\n\n\n[[web.servlet.spring-mvc.error-handling.error-pages-without-spring-mvc]]\n==== Mapping Error Pages Outside of Spring MVC\n\nFor applications that do not use Spring MVC, you can use the javadoc:org.springframework.boot.web.error.ErrorPageRegistrar[] interface to directly register javadoc:org.springframework.boot.web.error.ErrorPage[] instances.\nThis abstraction works directly with the underlying embedded servlet container and works even if you do not have a Spring MVC javadoc:org.springframework.web.servlet.DispatcherServlet[].\n\ninclude-code::MyErrorPagesConfiguration[]\n\nNOTE: If you register an javadoc:org.springframework.boot.web.error.ErrorPage[] with a path that ends up being handled by a javadoc:jakarta.servlet.Filter[] (as is common with some non-Spring web frameworks, like Jersey and Wicket), then the javadoc:jakarta.servlet.Filter[] has to be explicitly registered as an `ERROR` dispatcher, as shown in the following example:\n\ninclude-code::MyFilterConfiguration[]\n\nNote that the default javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[] does not include the `ERROR` dispatcher type.\n\n\n\n[[web.servlet.spring-mvc.error-handling.in-a-war-deployment]]\n==== Error Handling in a WAR Deployment\n\nWhen deployed to a servlet container, Spring Boot uses its error page filter to forward a request with an error status to the appropriate error page.\nThis is necessary as the servlet specification does not provide an API for registering error pages.\nDepending on the container that you are deploying your war file to and the technologies that your application uses, some additional configuration may be required.\n\nThe error page filter can only forward the request to the correct error page if the response has not already been committed.\nBy default, WebSphere Application Server 8.0 and later commits the response upon successful completion of a servlet's service method.\nYou should disable this behavior by setting `com.ibm.ws.webcontainer.invokeFlushAfterService` to `false`.\n\n\n\n[[web.servlet.spring-mvc.cors]]\n=== CORS Support\n\nhttps://en.wikipedia.org/wiki/Cross-origin_resource_sharing[Cross-origin resource sharing] (CORS) is a https://www.w3.org/TR/cors/[W3C specification] implemented by https://caniuse.com/#feat=cors[most browsers] that lets you specify in a flexible way what kind of cross-domain requests are authorized, instead of using some less secure and less powerful approaches such as IFRAME or JSONP.\n\nAs of version 4.2, Spring MVC {url-spring-framework-docs}/web/webmvc-cors.html[supports CORS].\nUsing {url-spring-framework-docs}/web/webmvc-cors.html#mvc-cors-controller[controller method CORS configuration] with javadoc:{url-spring-framework-javadoc}/org.springframework.web.bind.annotation.CrossOrigin[format=annotation] annotations in your Spring Boot application does not require any specific configuration.\n{url-spring-framework-docs}/web/webmvc-cors.html#mvc-cors-global[Global CORS configuration] can be defined by registering a javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] bean with a customized `addCorsMappings(CorsRegistry)` method, as shown in the following example:\n\ninclude-code::MyCorsConfiguration[]\n\n\n\n[[web.servlet.spring-mvc.api-versioning]]\n=== API Versioning\n\nSpring MVC supports API versioning which can be used to evolve an HTTP API over time.\nThe same `@Controller` path can be mapped multiple times to support different versions of the API.\n\nFor more details see {url-spring-framework-docs}/web/webmvc/mvc-controller/ann-requestmapping.html#mvc-ann-requestmapping-version[Spring Framework's reference documentation].\n\nOne mappings have been added, you additionally need to configure Spring MVC so that it is able to use any version information sent with a request.\nTypically, versions are sent as HTTP headers, query parameters or as part of the path.\n\nTo configure Spring MVC, you can either use a javadoc:org.springframework.web.servlet.config.annotation.WebMvcConfigurer[] bean and override the `configureApiVersioning(...)` method, or you can use properties.\n\nFor example, the following will use an `X-Version` HTTP header to obtain version information and default to `1.0.0` when no header is sent.\n\n[configprops,yaml]\n----\nspring:\n  mvc:\n    apiversion:\n      default: 1.0.0\n      use:\n        header: X-Version\n----\n\nFor more complete control, you can also define javadoc:org.springframework.web.accept.ApiVersionResolver[], javadoc:org.springframework.web.accept.ApiVersionParser[] and javadoc:org.springframework.web.accept.ApiVersionDeprecationHandler[] beans which will be injected into the auto-configured Spring MVC configuration.\n\nTIP: API versioning is also supported with both `WebClient` and `RestClient`.\nSee xref:io/rest-client.adoc#io.rest-client.apiversioning[] for details.\n\n\n\n[[web.servlet.jersey]]\n== JAX-RS and Jersey\n\nIf you prefer the JAX-RS programming model for REST endpoints, you can use one of the available implementations instead of Spring MVC.\nhttps://jersey.github.io/[Jersey] and https://cxf.apache.org/[Apache CXF] work quite well out of the box.\nCXF requires you to register its javadoc:jakarta.servlet.Servlet[] or javadoc:jakarta.servlet.Filter[] as a javadoc:org.springframework.context.annotation.Bean[format=annotation] in your application context.\nJersey has some native Spring support, so we also provide auto-configuration support for it in Spring Boot, together with a starter.\n\nTo get started with Jersey, include the `spring-boot-starter-jersey` as a dependency and then you need one javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.glassfish.jersey.server.ResourceConfig[] in which you register all the endpoints, as shown in the following example:\n\ninclude-code::MyJerseyConfig[]\n\nWARNING: Jersey's support for scanning executable archives is rather limited.\nFor example, it cannot scan for endpoints in a package found in a xref:how-to:deployment/installing.adoc[fully executable jar file] or in `WEB-INF/classes` when running an executable war file.\nTo avoid this limitation, the `packages` method should not be used, and endpoints should be registered individually by using the `register` method, as shown in the preceding example.\n\nFor more advanced customizations, you can also register an arbitrary number of beans that implement javadoc:org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer[].\n\nAll the registered endpoints should be a javadoc:org.springframework.stereotype.Component[format=annotation] with HTTP resource annotations (`@GET` and others), as shown in the following example:\n\ninclude-code::MyEndpoint[]\n\nSince the javadoc:org.springframework.boot.actuate.endpoint.annotation.Endpoint[format=annotation] is a Spring javadoc:org.springframework.stereotype.Component[format=annotation], its lifecycle is managed by Spring and you can use the javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation] annotation to inject dependencies and use the javadoc:org.springframework.beans.factory.annotation.Value[format=annotation] annotation to inject external configuration.\nBy default, the Jersey servlet is registered and mapped to `/*`.\nYou can change the mapping by adding javadoc:jakarta.ws.rs.ApplicationPath[format=annotation] to your javadoc:org.glassfish.jersey.server.ResourceConfig[].\n\nBy default, Jersey is set up as a servlet in a javadoc:org.springframework.context.annotation.Bean[format=annotation] of type javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] named `jerseyServletRegistration`.\nBy default, the servlet is initialized lazily, but you can customize that behavior by setting `spring.jersey.servlet.load-on-startup`.\nYou can disable or override that bean by creating one of your own with the same name.\nYou can also use a filter instead of a servlet by setting `spring.jersey.type=filter` (in which case, the javadoc:org.springframework.context.annotation.Bean[format=annotation] to replace or override is `jerseyFilterRegistration`).\nThe filter has an javadoc:org.springframework.core.annotation.Order[format=annotation], which you can set with `spring.jersey.filter.order`.\nWhen using Jersey as a filter, a servlet that will handle any requests that are not intercepted by Jersey must be present.\nIf your application does not contain such a servlet, you may want to enable the default servlet by setting configprop:server.servlet.register-default-servlet[] to `true`.\nBoth the servlet and the filter registrations can be given init parameters by using `spring.jersey.init.*` to specify a map of properties.\n\n\n\n[[web.servlet.embedded-container]]\n== Embedded Servlet Container Support\n\nFor servlet application, Spring Boot includes support for embedded https://tomcat.apache.org/[Tomcat] and https://www.eclipse.org/jetty/[Jetty] servers.\nMost developers use the appropriate starter to obtain a fully configured instance.\nBy default, the embedded server listens for HTTP requests on port `8080`.\n\n\n\n[[web.servlet.embedded-container.servlets-filters-listeners]]\n=== Servlets, Filters, and Listeners\n\nWhen using an embedded servlet container, you can register servlets, filters, and all the listeners (such as javadoc:jakarta.servlet.http.HttpSessionListener[]) from the servlet spec, either by using Spring beans or by scanning for servlet components.\n\n\n\n[[web.servlet.embedded-container.servlets-filters-listeners.beans]]\n==== Registering Servlets, Filters, and Listeners as Spring Beans\n\nAny javadoc:jakarta.servlet.Servlet[], javadoc:jakarta.servlet.Filter[], or servlet `*Listener` instance that is a Spring bean is registered with the embedded container.\nThis can be particularly convenient if you want to refer to a value from your `application.properties` during configuration.\n\nBy default, if the context contains only a single Servlet, it is mapped to `/`.\nIn the case of multiple servlet beans, the bean name is used as a path prefix.\nFilters map to `+/*+`.\n\nIf convention-based mapping is not flexible enough, you can use the javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[], javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[], and javadoc:org.springframework.boot.web.servlet.ServletListenerRegistrationBean[] classes for complete control.\nIf you prefer annotations over javadoc:org.springframework.boot.web.servlet.ServletRegistrationBean[] and javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[], you can also use javadoc:org.springframework.boot.web.servlet.ServletRegistration[format=annotation] and\njavadoc:org.springframework.boot.web.servlet.FilterRegistration[format=annotation] as an alternative.\n\nIt is usually safe to leave filter beans unordered.\nIf a specific order is required, you should annotate the javadoc:jakarta.servlet.Filter[] with javadoc:org.springframework.core.annotation.Order[format=annotation] or make it implement javadoc:org.springframework.core.Ordered[].\nYou cannot configure the order of a javadoc:jakarta.servlet.Filter[] by annotating its bean method with javadoc:org.springframework.core.annotation.Order[format=annotation].\nIf you cannot change the javadoc:jakarta.servlet.Filter[] class to add javadoc:org.springframework.core.annotation.Order[format=annotation] or implement javadoc:org.springframework.core.Ordered[], you must define a javadoc:org.springframework.boot.web.servlet.FilterRegistrationBean[] for the javadoc:jakarta.servlet.Filter[] and set the registration bean's order using the `setOrder(int)` method.\nOr, if you prefer annotations, you can also use javadoc:org.springframework.boot.web.servlet.FilterRegistration[format=annotation] and set the `order` attribute.\nAvoid configuring a filter that reads the request body at `Ordered.HIGHEST_PRECEDENCE`, since it might go against the character encoding configuration of your application.\nIf a servlet filter wraps the request, it should be configured with an order that is less than or equal to `OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER`.\n\nTIP: To see the order of every javadoc:jakarta.servlet.Filter[] in your application, enable debug level logging for the `web` xref:features/logging.adoc#features.logging.log-groups[logging group] (`logging.level.web=debug`).\nDetails of the registered filters, including their order and URL patterns, will then be logged at startup.\n\nWARNING: Take care when registering javadoc:jakarta.servlet.Filter[] beans since they are initialized very early in the application lifecycle.\nIf you need to register a javadoc:jakarta.servlet.Filter[] that interacts with other beans, consider using a javadoc:org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean[] instead.\n\n\n\n[[web.servlet.embedded-container.context-initializer]]\n=== Servlet Context Initialization\n\nEmbedded servlet containers do not directly execute the javadoc:jakarta.servlet.ServletContainerInitializer[] interface or Spring's javadoc:org.springframework.web.WebApplicationInitializer[] interface.\nThis is an intentional design decision intended to reduce the risk that third party libraries designed to run inside a war may break Spring Boot applications.\n\nIf you need to perform servlet context initialization in a Spring Boot application, you should register a bean that implements the javadoc:org.springframework.boot.web.servlet.ServletContextInitializer[] interface.\nThe single `onStartup` method provides access to the javadoc:jakarta.servlet.ServletContext[] and, if necessary, can easily be used as an adapter to an existing javadoc:org.springframework.web.WebApplicationInitializer[].\n\n\n\n[[web.servlet.embedded-container.context-initializer.init-parameters]]\n==== Init Parameters\n\nInit parameters can be configured on the javadoc:jakarta.servlet.ServletContext[] using `server.servlet.context-parameters.*` properties.\nFor example, the property `server.servlet.context-parameters.com.example.parameter=example` will configure a `ServletContext` init parameter named `com.example.parameter` with the value `example`.\n\n\n\n[[web.servlet.embedded-container.context-initializer.scanning]]\n==== Scanning for Servlets, Filters, and listeners\n\nWhen using an embedded container, automatic registration of classes annotated with javadoc:jakarta.servlet.annotation.WebServlet[format=annotation], javadoc:jakarta.servlet.annotation.WebFilter[format=annotation], and javadoc:jakarta.servlet.annotation.WebListener[format=annotation] can be enabled by using javadoc:org.springframework.boot.web.server.servlet.context.ServletComponentScan[format=annotation].\n\nTIP: javadoc:org.springframework.boot.web.server.servlet.context.ServletComponentScan[format=annotation] has no effect in a standalone container, where the container's built-in discovery mechanisms are used instead.\n\n\n\n[[web.servlet.embedded-container.application-context]]\n=== The ServletWebServerApplicationContext\n\nUnder the hood, Spring Boot uses a different type of javadoc:org.springframework.context.ApplicationContext[] for embedded servlet container support.\nThe javadoc:org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext[] is a special type of javadoc:org.springframework.web.context.WebApplicationContext[] that bootstraps itself by searching for a single javadoc:org.springframework.boot.web.server.servlet.ServletWebServerFactory[] bean.\nUsually a javadoc:org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory[], or javadoc:org.springframework.boot.jetty.servlet.JettyServletWebServerFactory[] has been auto-configured.\n\nNOTE: You usually do not need to be aware of these implementation classes.\nMost applications are auto-configured, and the appropriate javadoc:org.springframework.context.ApplicationContext[] and javadoc:org.springframework.boot.web.server.servlet.ServletWebServerFactory[] are created on your behalf.\n\nIn an embedded container setup, the javadoc:jakarta.servlet.ServletContext[] is set as part of server startup which happens during application context initialization.\nBecause of this beans in the javadoc:org.springframework.context.ApplicationContext[] cannot be reliably initialized with a javadoc:jakarta.servlet.ServletContext[].\nOne way to get around this is to inject javadoc:org.springframework.context.ApplicationContext[] as a dependency of the bean and access the javadoc:jakarta.servlet.ServletContext[] only when it is needed.\nAnother way is to use a callback once the server has started.\nThis can be done using an javadoc:org.springframework.context.ApplicationListener[] which listens for the javadoc:org.springframework.boot.context.event.ApplicationStartedEvent[] as follows:\n\ninclude-code::MyDemoBean[]\n\n\n\n[[web.servlet.embedded-container.customizing]]\n=== Customizing Embedded Servlet Containers\n\nCommon servlet container settings can be configured by using Spring javadoc:org.springframework.core.env.Environment[] properties.\nUsually, you would define the properties in your `application.properties` or `application.yaml` file.\n\nCommon server settings include:\n\n* Network settings: Listen port for incoming HTTP requests (`server.port`), interface address to bind to (`server.address`), and so on.\n* Session settings: Whether the session is persistent (`server.servlet.session.persistent`), session timeout (`server.servlet.session.timeout`), location of session data (`server.servlet.session.store-dir`), and session-cookie configuration (`server.servlet.session.cookie.*`).\n* Error management: Location of the error page (configprop:spring.web.error.path[]) and so on.\n* xref:how-to:webserver.adoc#howto.webserver.configure-ssl[SSL]\n* xref:how-to:webserver.adoc#howto.webserver.enable-response-compression[HTTP compression]\n\nSpring Boot tries as much as possible to expose common settings, but this is not always possible.\nFor those cases, dedicated namespaces offer server-specific customizations (see `server.tomcat`).\nFor instance, xref:how-to:webserver.adoc#howto.webserver.configure-access-logs[access logs] can be configured with specific features of the embedded servlet container.\n\nTIP: See the javadoc:org.springframework.boot.web.server.autoconfigure.ServerProperties[] class for a complete list.\n\n\n\n[[web.servlet.embedded-container.customizing.samesite]]\n==== SameSite Cookies\n\nThe `SameSite` cookie attribute can be used by web browsers to control if and how cookies are submitted in cross-site requests.\nThe attribute is particularly relevant for modern web browsers which have started to change the default value that is used when the attribute is missing.\n\nIf you want to change the `SameSite` attribute of your session cookie, you can use the configprop:server.servlet.session.cookie.same-site[] property.\nThis property is supported by auto-configured Tomcat and Jetty servers.\nIt is also used to configure Spring Session servlet based javadoc:org.springframework.session.SessionRepository[] beans.\n\nFor example, if you want your session cookie to have a `SameSite` attribute of `None`, you can add the following to your `application.properties` or `application.yaml` file:\n\n[configprops,yaml]\n----\nserver:\n  servlet:\n    session:\n      cookie:\n        same-site: \"none\"\n----\n\nIf you want to change the `SameSite` attribute on other cookies added to your javadoc:jakarta.servlet.http.HttpServletResponse[], you can use a javadoc:org.springframework.boot.web.server.servlet.CookieSameSiteSupplier[].\nThe javadoc:org.springframework.boot.web.server.servlet.CookieSameSiteSupplier[] is passed a javadoc:jakarta.servlet.http.Cookie[] and may return a `SameSite` value, or `null`.\n\nThere are a number of convenience factory and filter methods that you can use to quickly match specific cookies.\nFor example, adding the following bean will automatically apply a `SameSite` of `Lax` for all cookies with a name that matches the regular expression `myapp.*`.\n\ninclude-code::MySameSiteConfiguration[]\n\n\n\n[[web.servlet.embedded-container.customizing.encoding]]\n==== Character Encoding\n\nThe character encoding behavior of the embedded servlet container for request and response handling can be configured using the `server.servlet.encoding.*` configuration properties.\n\nWhen a request's `Accept-Language` header indicates a locale for the request it will be automatically mapped to a charset by the servlet container.\nEach container provides default locale to charset mappings and you should verify that they meet your application's needs.\nWhen they do not, use the configprop:server.servlet.encoding.mapping[] configuration property to customize the mappings, as shown in the following example:\n\n[configprops,yaml]\n----\nserver:\n  servlet:\n    encoding:\n      mapping:\n        ko: \"UTF-8\"\n----\n\nIn the preceding example, the `ko` (Korean) locale has been mapped to `UTF-8`.\nThis is equivalent to a `<locale-encoding-mapping-list>` entry in a `web.xml` file of a traditional war deployment.\n\n\n\n[[web.servlet.embedded-container.customizing.programmatic]]\n==== Programmatic Customization\n\nIf you need to programmatically configure your embedded servlet container, you can register a Spring bean that implements the javadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] interface.\njavadoc:org.springframework.boot.web.server.WebServerFactoryCustomizer[] provides access to the javadoc:org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory[], which includes numerous customization setter methods.\nThe following example shows programmatically setting the port:\n\ninclude-code::MyWebServerFactoryCustomizer[]\n\njavadoc:org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory[], and javadoc:org.springframework.boot.jetty.servlet.JettyServletWebServerFactory[] are dedicated variants of javadoc:org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory[] that have additional customization setter methods for Tomcat, and Jetty respectively.\nThe following example shows how to customize javadoc:org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory[] that provides access to Tomcat-specific configuration options:\n\ninclude-code::MyTomcatWebServerFactoryCustomizer[]\n\n\n\n[[web.servlet.embedded-container.customizing.direct]]\n==== Customizing ConfigurableServletWebServerFactory Directly\n\nFor more advanced use cases that require you to extend from javadoc:org.springframework.boot.web.server.servlet.ServletWebServerFactory[], you can expose a bean of such type yourself.\n\nSetters are provided for many configuration options.\nSeveral protected method \"`hooks`\" are also provided should you need to do something more exotic.\nSee the javadoc:org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory[] API documentation for details.\n\nNOTE: Auto-configured customizers are still applied on your custom factory, so use that option carefully.\n\n\n\n[[web.servlet.embedded-container.jsp-limitations]]\n=== JSP Limitations\n\nWhen running a Spring Boot application that uses an embedded servlet container (and is packaged as an executable archive), there are some limitations in the JSP support.\n\n* With Jetty and Tomcat, it should work if you use war packaging.\nAn executable war will work when launched with `java -jar`, and will also be deployable to any standard container.\nJSPs are not supported when using an executable jar.\n\n* Creating a custom `error.jsp` page does not override the default view for xref:web/servlet.adoc#web.servlet.spring-mvc.error-handling[error handling].\n  xref:web/servlet.adoc#web.servlet.spring-mvc.error-handling.error-pages[Custom error pages] should be used instead.\n\n* If you run your application using `mvn spring-boot:run` or `gradle bootRun` and you deviate from the standard `src/main/webapp` directory structure you may need to set a `WAR_SOURCE_DIRECTORY` environment variable so that Spring Boot can find your JSPs.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-graphql.adoc",
    "content": "[[web.graphql]]\n= Spring for GraphQL\n\nIf you want to build GraphQL applications, you can take advantage of Spring Boot's auto-configuration for {url-spring-graphql-site}[Spring for GraphQL].\nThe Spring for GraphQL project is based on https://github.com/graphql-java/graphql-java[GraphQL Java].\nYou'll need the `spring-boot-starter-graphql` starter at a minimum.\nBecause GraphQL is transport-agnostic, you'll also need to have one or more additional starters in your application to expose your GraphQL API over the web:\n\n\n[cols=\"1,1,1\"]\n|===\n| Starter | Transport | Implementation\n\n| `spring-boot-starter-web`\n| HTTP\n| Spring MVC\n\n| `spring-boot-starter-websocket`\n| WebSocket\n| WebSocket for Servlet apps\n\n| `spring-boot-starter-webflux`\n| HTTP, WebSocket\n| Spring WebFlux\n\n| `spring-boot-starter-rsocket`\n| TCP, WebSocket\n| Spring WebFlux on Reactor Netty\n|===\n\n\n\n[[web.graphql.schema]]\n== GraphQL Schema\n\nA Spring GraphQL application requires a defined schema at startup.\nBy default, you can write \".graphqls\" or \".gqls\" schema files under `src/main/resources/graphql/**` and Spring Boot will pick them up automatically.\nYou can customize the locations with configprop:spring.graphql.schema.locations[] and the file extensions with configprop:spring.graphql.schema.file-extensions[].\n\nNOTE: If you want Spring Boot to detect schema files in all your application modules and dependencies for that location,\nyou can set configprop:spring.graphql.schema.locations[] to `+\"classpath*:graphql/**/\"+` (note the `classpath*:` prefix).\n\nIn the following sections, we'll consider this sample GraphQL schema, defining two types and two queries:\n\n[source,json,subs=\"verbatim,quotes\"]\n----\ninclude::ROOT:example$resources/graphql/schema.graphqls[]\n----\n\nNOTE: By default, https://spec.graphql.org/draft/#sec-Introspection[field introspection] will be allowed on the schema as it is required for tools such as GraphiQL.\nIf you wish to not expose information about the schema, you can disable introspection by setting configprop:spring.graphql.schema.introspection.enabled[] to `false`.\n\n\n\n[[web.graphql.runtimewiring]]\n== GraphQL RuntimeWiring\n\nThe GraphQL Java javadoc:graphql.schema.idl.RuntimeWiring$Builder[] can be used to register custom scalar types, directives, type resolvers, javadoc:graphql.schema.DataFetcher[], and more.\nYou can declare javadoc:org.springframework.graphql.execution.RuntimeWiringConfigurer[] beans in your Spring config to get access to the javadoc:graphql.schema.idl.RuntimeWiring$Builder[].\nSpring Boot detects such beans and adds them to the {url-spring-graphql-docs}/request-execution.html#execution.graphqlsource[GraphQlSource builder].\n\nTypically, however, applications will not implement javadoc:graphql.schema.DataFetcher[] directly and will instead create {url-spring-graphql-docs}/controllers.html[annotated controllers].\nSpring Boot will automatically detect javadoc:org.springframework.stereotype.Controller[format=annotation] classes with annotated handler methods and register those as ``DataFetcher``s.\nHere's a sample implementation for our greeting query with a javadoc:org.springframework.stereotype.Controller[format=annotation] class:\n\ninclude-code::GreetingController[]\n\n\n\n[[web.graphql.data-query]]\n== Querydsl and QueryByExample Repositories Support\n\nSpring Data offers support for both Querydsl and QueryByExample repositories.\nSpring GraphQL can {url-spring-graphql-docs}/data.html[configure Querydsl and QueryByExample repositories as javadoc:graphql.schema.DataFetcher[]].\n\nSpring Data repositories annotated with javadoc:org.springframework.graphql.data.GraphQlRepository[format=annotation] and extending one of:\n\n* javadoc:org.springframework.data.querydsl.QuerydslPredicateExecutor[]\n* javadoc:org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor[]\n* javadoc:org.springframework.data.repository.query.QueryByExampleExecutor[]\n* javadoc:org.springframework.data.repository.query.ReactiveQueryByExampleExecutor[]\n\nare detected by Spring Boot and considered as candidates for javadoc:graphql.schema.DataFetcher[] for matching top-level queries.\n\n\n\n[[web.graphql.transports]]\n== Transports\n\n\n\n[[web.graphql.transports.http-websocket]]\n=== HTTP and WebSocket\n\nThe GraphQL HTTP endpoint is at HTTP POST `/graphql` by default.\nIt also supports the `\"text/event-stream\"` media type over Server Sent Events for subscriptions only.\nThe path can be customized with configprop:spring.graphql.http.path[].\n\nTIP: The HTTP endpoint for both Spring MVC and Spring WebFlux is provided by a `RouterFunction` bean with an javadoc:org.springframework.core.annotation.Order[format=annotation] of `0`.\nIf you define your own `RouterFunction` beans, you may want to add appropriate javadoc:org.springframework.core.annotation.Order[format=annotation] annotations to ensure that they are sorted correctly.\n\nThe GraphQL WebSocket endpoint is off by default. To enable it:\n\n* For a Servlet application, add the WebSocket starter `spring-boot-starter-websocket`\n* For a WebFlux application, no additional dependency is required\n* For both, the configprop:spring.graphql.websocket.path[] application property must be set\n\nSpring GraphQL provides a {url-spring-graphql-docs}/transports.html#server.interception[Web Interception] model.\nThis is quite useful for retrieving information from an HTTP request header and set it in the GraphQL context or fetching information from the same context and writing it to a response header.\nWith Spring Boot, you can declare a javadoc:org.springframework.graphql.server.WebGraphQlInterceptor[] bean to have it registered with the web transport.\n\n{url-spring-framework-docs}/web/webmvc-cors.html[Spring MVC] and {url-spring-framework-docs}/web/webflux-cors.html[Spring WebFlux] support CORS (Cross-Origin Resource Sharing) requests.\nCORS is a critical part of the web config for GraphQL applications that are accessed from browsers using different domains.\n\nSpring Boot supports many configuration properties under the `spring.graphql.cors.*` namespace; here's a short configuration sample:\n\n[configprops,yaml]\n----\nspring:\n  graphql:\n    cors:\n      allowed-origins: \"https://example.org\"\n      allowed-methods: GET,POST\n      max-age: 1800s\n----\n\n\n\n[[web.graphql.transports.rsocket]]\n=== RSocket\n\nRSocket is also supported as a transport, on top of WebSocket or TCP.\nOnce the xref:messaging/rsocket.adoc#messaging.rsocket.server-auto-configuration[RSocket server is configured], we can configure our GraphQL handler on a particular route using configprop:spring.graphql.rsocket.mapping[].\nFor example, configuring that mapping as `\"graphql\"` means we can use that as a route when sending requests with the javadoc:org.springframework.graphql.client.RSocketGraphQlClient[].\n\nSpring Boot auto-configures a `RSocketGraphQlClient.Builder<?>` bean that you can inject in your components:\n\ninclude-code::RSocketGraphQlClientExample[tag=builder]\n\nAnd then send a request:\ninclude-code::RSocketGraphQlClientExample[tag=request]\n\n\n\n[[web.graphql.exception-handling]]\n== Exception Handling\n\nSpring GraphQL enables applications to register one or more Spring javadoc:org.springframework.graphql.execution.DataFetcherExceptionResolver[] components that are invoked sequentially.\nThe Exception must be resolved to a list of javadoc:{url-graphql-java-javadoc}/graphql.GraphQLError[] objects, see {url-spring-graphql-docs}/controllers.html#controllers.exception-handler[Spring GraphQL exception handling documentation].\nSpring Boot will automatically detect javadoc:org.springframework.graphql.execution.DataFetcherExceptionResolver[] beans and register them with the javadoc:org.springframework.graphql.execution.GraphQlSource$Builder[].\n\n\n\n[[web.graphql.graphiql]]\n== GraphiQL and Schema Printer\n\nSpring GraphQL offers infrastructure for helping developers when consuming or developing a GraphQL API.\n\nSpring GraphQL ships with a default https://github.com/graphql/graphiql[GraphiQL] page that is exposed at `\"/graphiql\"` by default.\nThis page is disabled by default and can be turned on with the configprop:spring.graphql.graphiql.enabled[] property.\nMany applications exposing such a page will prefer a custom build.\nA default implementation is very useful during development, this is why it is exposed automatically with xref:using/devtools.adoc[`spring-boot-devtools`] during development.\n\nYou can also choose to expose the GraphQL schema in text format at `/graphql/schema` when the configprop:spring.graphql.schema.printer.enabled[] property is enabled.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-hateoas.adoc",
    "content": "[[web.spring-hateoas]]\n= Spring HATEOAS\n\nIf you develop a RESTful API that makes use of hypermedia, Spring Boot provides auto-configuration for Spring HATEOAS that works well with most applications.\nThe auto-configuration replaces the need to use javadoc:org.springframework.hateoas.config.EnableHypermediaSupport[format=annotation] and registers a number of beans to ease building hypermedia-based applications, including a javadoc:org.springframework.hateoas.client.LinkDiscoverers[] (for client side support) and an javadoc:tools.jackson.databind.json.JsonMapper[] configured to correctly marshal responses into the desired representation.\nThe javadoc:tools.jackson.databind.json.JsonMapper[] is customized by setting the various `spring.jackson.*` properties or, if any exist, the javadoc:org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer[] beans.\n\nYou can take control of Spring HATEOAS's configuration by using javadoc:org.springframework.hateoas.config.EnableHypermediaSupport[format=annotation].\nNote that doing so disables the javadoc:tools.jackson.databind.json.JsonMapper[] customization described earlier.\n\nWARNING: `spring-boot-starter-hateoas` is specific to Spring MVC and should not be combined with Spring WebFlux.\nIn order to use Spring HATEOAS with Spring WebFlux, you can add a direct dependency on `org.springframework.hateoas:spring-hateoas` along with `spring-boot-starter-webflux`.\n\nBy default, requests that accept `application/json` will receive an `application/hal+json` response.\nTo disable this behavior set configprop:spring.hateoas.use-hal-as-default-json-media-type[] to `false` and define a javadoc:org.springframework.hateoas.config.HypermediaMappingInformation[] or javadoc:org.springframework.hateoas.mediatype.hal.HalConfiguration[] to configure Spring HATEOAS to meet the needs of your application and its clients.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-security.adoc",
    "content": "[[web.security]]\n= Spring Security\n\nIf {url-spring-security-site}[Spring Security] is on the classpath, then web applications are secured by default.\nThis includes securing Spring Boot's `/error` endpoint.\nSpring Boot relies on Spring Security's content-negotiation strategy to determine whether to use `httpBasic` or `formLogin`.\nTo add method-level security to a web application, you can also add javadoc:org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity[format=annotation] with your desired settings.\nAdditional information can be found in the {url-spring-security-docs}/servlet/authorization/method-security.html[Spring Security Reference Guide].\n\nThe default javadoc:org.springframework.security.core.userdetails.UserDetailsService[] has a single user.\nThe user name is `user`, and the password is random and is printed at WARN level when the application starts, as shown in the following example:\n\n[source]\n----\nUsing generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35\n\nThis generated password is for development use only. Your security configuration must be updated before running your application in production.\n----\n\nNOTE: If you fine-tune your logging configuration, ensure that the `org.springframework.boot.security.autoconfigure` category is set to log `WARN`-level messages.\nOtherwise, the default password is not printed.\n\nYou can change the username and password by providing a `spring.security.user.name` and `spring.security.user.password`.\n\nThe basic features you get by default in a web application are:\n\n* A javadoc:org.springframework.security.core.userdetails.UserDetailsService[] (or javadoc:org.springframework.security.core.userdetails.ReactiveUserDetailsService[] in case of a WebFlux application) bean with in-memory store and a single user with a generated password (see javadoc:org.springframework.boot.security.autoconfigure.SecurityProperties$User[] for the properties of the user).\n* Form-based login or HTTP Basic security (depending on the `Accept` header in the request) for the entire application (including actuator endpoints if actuator is on the classpath).\n* A javadoc:org.springframework.security.authentication.DefaultAuthenticationEventPublisher[] for publishing authentication events.\n\nYou can provide a different javadoc:org.springframework.security.authentication.AuthenticationEventPublisher[] by adding a bean for it.\n\n\n\n[[web.security.spring-mvc]]\n== MVC Security\n\nThe default security configuration is implemented in javadoc:org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration[] and javadoc:org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration[].\njavadoc:org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration[] imports `SpringBootWebSecurityConfiguration` for web security and javadoc:org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration[] for authentication.\n\nTo completely switch off the default web application security configuration, including Actuator security, or to combine multiple Spring Security components such as OAuth2 Client and Resource Server, add a bean of type javadoc:org.springframework.security.web.SecurityFilterChain[] (doing so does not disable the javadoc:org.springframework.security.core.userdetails.UserDetailsService[] configuration).\nTo also switch off the javadoc:org.springframework.security.core.userdetails.UserDetailsService[] configuration, add a bean of type javadoc:org.springframework.security.core.userdetails.UserDetailsService[], javadoc:org.springframework.security.authentication.AuthenticationProvider[], or javadoc:org.springframework.security.authentication.AuthenticationManager[].\n\nThe auto-configuration of a javadoc:org.springframework.security.core.userdetails.UserDetailsService[] will also back off when any of the following Spring Security modules is on the classpath:\n\n- `spring-security-oauth2-client`\n- `spring-security-oauth2-resource-server`\n- `spring-security-saml2-service-provider`\n\nTo use javadoc:org.springframework.security.core.userdetails.UserDetailsService[] in addition to one or more of these dependencies, define your own javadoc:org.springframework.security.provisioning.InMemoryUserDetailsManager[] bean.\n\nAccess rules can be overridden by adding a custom javadoc:org.springframework.security.web.SecurityFilterChain[] bean.\nSpring Boot provides convenience methods that can be used to override access rules for actuator endpoints and static resources.\njavadoc:org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest[] can be used to create a javadoc:org.springframework.security.web.util.matcher.RequestMatcher[] that is based on the configprop:management.endpoints.web.base-path[] property.\njavadoc:org.springframework.boot.security.autoconfigure.web.servlet.PathRequest[] can be used to create a javadoc:org.springframework.security.web.util.matcher.RequestMatcher[] for resources in commonly used locations.\n\n\n\n[[web.security.spring-webflux]]\n== WebFlux Security\n\nSimilar to Spring MVC applications, you can secure your WebFlux applications by adding the `spring-boot-starter-security` dependency.\nThe default security configuration is implemented in javadoc:org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration[] and javadoc:org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration[].\nIn addition to reactive web applications, the latter is also auto-configured when RSocket is in use.\njavadoc:org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration[] imports `WebFluxSecurityConfiguration` for web security.\njavadoc:org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration[] auto-configures authentication.\n\nTo completely switch off the default web application security configuration, including Actuator security, add a bean of type javadoc:org.springframework.security.web.server.WebFilterChainProxy[] (doing so does not disable the javadoc:org.springframework.security.core.userdetails.ReactiveUserDetailsService[] configuration).\nTo also switch off the javadoc:org.springframework.security.core.userdetails.ReactiveUserDetailsService[] configuration, add a bean of type javadoc:org.springframework.security.core.userdetails.ReactiveUserDetailsService[] or javadoc:org.springframework.security.authentication.ReactiveAuthenticationManager[].\n\nThe auto-configuration will also back off when any of the following Spring Security modules is on the classpath:\n\n- `spring-security-oauth2-client`\n- `spring-security-oauth2-resource-server`\n\nTo use javadoc:org.springframework.security.core.userdetails.ReactiveUserDetailsService[] in addition to one or more of these dependencies, define your own javadoc:org.springframework.security.core.userdetails.MapReactiveUserDetailsService[] bean.\n\nAccess rules and the use of multiple Spring Security components such as OAuth 2 Client and Resource Server can be configured by adding a custom javadoc:org.springframework.security.web.server.SecurityWebFilterChain[] bean.\nSpring Boot provides convenience methods that can be used to override access rules for actuator endpoints and static resources.\njavadoc:org.springframework.boot.security.autoconfigure.actuate.web.reactive.EndpointRequest[] can be used to create a javadoc:org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher[] that is based on the configprop:management.endpoints.web.base-path[] property.\n\njavadoc:org.springframework.boot.security.autoconfigure.web.reactive.PathRequest[] can be used to create a javadoc:org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher[] for resources in commonly used locations.\n\nFor example, you can customize your security configuration by adding something like:\n\ninclude-code::MyWebFluxSecurityConfiguration[]\n\n\n\n[[web.security.oauth2]]\n== OAuth2\n\nhttps://oauth.net/2/[OAuth2] is a widely used authorization framework that is supported by Spring.\n\n\n\n[[web.security.oauth2.client]]\n=== Client\n\nIf you have `spring-security-oauth2-client` on your classpath, you can take advantage of some auto-configuration to set up OAuth2/Open ID Connect clients.\nThis configuration makes use of the properties under javadoc:org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientProperties[].\nThe same properties are applicable to both servlet and reactive applications.\n\nEach registration must specify an OAuth 2 provider.\nWhen set, the value of the `spring.security.oauth2.client.registration.<registration-id>.provider` property is used to specify the registration's provider.\nIf the `provider` property is not set, the registration's ID is used instead.\nBoth approaches are shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      client:\n        registration:\n          my-client:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n            provider: \"example\"\n          example:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n----\n\nThe registrations `my-client` and `example` will both use the provider with ID `example`.\nThe former will do so due to the value of the `spring.security.oauth2.client.registration.my-client.provider` property.\nThe latter will do so due to its ID being `example` and there being no `provider` property configured for the registration.\n\nThe specified provider can either be a reference to a provider configured using `spring.security.oauth2.client.provider.<provider-id>.*` properties or one of the xref:web/spring-security.adoc#web.security.oauth2.client.common-providers[known common providers].\n\nYou can register multiple OAuth2 clients and providers under the `spring.security.oauth2.client` prefix, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      client:\n        registration:\n          my-login-client:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n            client-name: \"Client for OpenID Connect\"\n            provider: \"my-oauth-provider\"\n            scope: \"openid,profile,email,phone,address\"\n            redirect-uri: \"{baseUrl}/login/oauth2/code/{registrationId}\"\n            client-authentication-method: \"client_secret_basic\"\n            authorization-grant-type: \"authorization_code\"\n\n          my-client-1:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n            client-name: \"Client for user scope\"\n            provider: \"my-oauth-provider\"\n            scope: \"user\"\n            redirect-uri: \"{baseUrl}/authorized/user\"\n            client-authentication-method: \"client_secret_basic\"\n            authorization-grant-type: \"authorization_code\"\n\n          my-client-2:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n            client-name: \"Client for email scope\"\n            provider: \"my-oauth-provider\"\n            scope: \"email\"\n            redirect-uri: \"{baseUrl}/authorized/email\"\n            client-authentication-method: \"client_secret_basic\"\n            authorization-grant-type: \"authorization_code\"\n\n        provider:\n          my-oauth-provider:\n            authorization-uri: \"https://my-auth-server.com/oauth2/authorize\"\n            token-uri: \"https://my-auth-server.com/oauth2/token\"\n            user-info-uri: \"https://my-auth-server.com/userinfo\"\n            user-info-authentication-method: \"header\"\n            jwk-set-uri: \"https://my-auth-server.com/oauth2/jwks\"\n            user-name-attribute: \"name\"\n----\n\nIn this example, there are three registrations.\nIn order of declaration, their IDs are `my-login-client`, `my-client-1`, and `my-client-2`.\nThere is also a single provider with ID `my-oauth-provider`.\n\nFor OpenID Connect providers that support https://openid.net/specs/openid-connect-discovery-1_0.html[OpenID Connect discovery], the configuration can be further simplified.\nThe provider needs to be configured with an `issuer-uri` which is the URI that it asserts as its Issuer Identifier.\nFor example, if the `issuer-uri` provided is \"https://example.com\", then an \"OpenID Provider Configuration Request\" will be made to \"https://example.com/.well-known/openid-configuration\".\nThe result is expected to be an \"OpenID Provider Configuration Response\".\nThe following example shows how an OpenID Connect Provider can be configured with the `issuer-uri`:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      client:\n        provider:\n          oidc-provider:\n            issuer-uri: \"https://dev-123456.oktapreview.com/oauth2/default/\"\n----\n\nBy default, Spring Security's javadoc:org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter[] only processes URLs matching `/login/oauth2/code/*`.\nIf you want to customize the `redirect-uri` to use a different pattern, you need to provide configuration to process that custom pattern.\nFor example, for servlet applications, you can add your own javadoc:org.springframework.security.web.SecurityFilterChain[] that resembles the following:\n\ninclude-code::MyOAuthClientConfiguration[]\n\nTIP: Spring Boot auto-configures an javadoc:org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService[] which is used by Spring Security for the management of client registrations.\nThe javadoc:org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService[] has limited capabilities and we recommend using it only for development environments.\nFor production environments, consider using a javadoc:org.springframework.security.oauth2.client.JdbcOAuth2AuthorizedClientService[] or creating your own implementation of javadoc:org.springframework.security.oauth2.client.OAuth2AuthorizedClientService[].\n\n\n\n[[web.security.oauth2.client.common-providers]]\n==== OAuth2 Client Registration for Common Providers\n\nFor common OAuth2 and OpenID providers (Google, Github, Facebook, and Okta), we provide a set of provider defaults.\nThe IDs of these common provides are `google`, `github`, `facebook`, and `okta`, respectively.\n\nIf you do not need to customize these providers, set the registration's `provider` property to the ID of one of the common providers.\nAlternatively, you can xref:web/spring-security.adoc#web.security.oauth2.client[use a registration ID that matches the ID of the provider].\nThe two configurations in the following example use the common `google` provider:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      client:\n        registration:\n          my-client:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n            provider: \"google\"\n          google:\n            client-id: \"abcd\"\n            client-secret: \"password\"\n----\n\n\n\n[[web.security.oauth2.server]]\n=== Resource Server\n\nIf you have `spring-security-oauth2-resource-server` on your classpath, Spring Boot can set up an OAuth2 Resource Server.\nFor JWT configuration, a JWK Set URI or OIDC Issuer URI needs to be specified, as shown in the following examples:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      resourceserver:\n        jwt:\n          jwk-set-uri: \"https://example.com/oauth2/default/v1/keys\"\n----\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      resourceserver:\n        jwt:\n          issuer-uri: \"https://dev-123456.oktapreview.com/oauth2/default/\"\n----\n\nNOTE: If the authorization server does not support a JWK Set URI, you can configure the resource server with the Public Key used for verifying the signature of the JWT.\nThis can be done using the configprop:spring.security.oauth2.resourceserver.jwt.public-key-location[] property, where the value needs to point to a file containing the public key in the PEM-encoded x509 format.\n\nThe configprop:spring.security.oauth2.resourceserver.jwt.audiences[] property can be used to specify the expected values of the aud claim in JWTs.\nFor example, to require JWTs to contain an aud claim with the value `my-audience`:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      resourceserver:\n        jwt:\n          audiences:\n            - \"my-audience\"\n----\n\nThe same properties are applicable for both servlet and reactive applications.\nAlternatively, you can define your own javadoc:org.springframework.security.oauth2.jwt.JwtDecoder[] bean for servlet applications or a javadoc:org.springframework.security.oauth2.jwt.ReactiveJwtDecoder[] for reactive applications.\n\nIn cases where opaque tokens are used instead of JWTs, you can configure the following properties to validate tokens through introspection:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      resourceserver:\n        opaquetoken:\n          introspection-uri: \"https://example.com/check-token\"\n          client-id: \"my-client-id\"\n          client-secret: \"my-client-secret\"\n----\n\nAgain, the same properties are applicable for both servlet and reactive applications.\n\nThe result is an auto-configured introspector. Either a javadoc:org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector[] or, in a reactive application, a javadoc:org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector[].\nThese auto-configured introspectors can be customized using javadoc:org.springframework.boot.security.oauth2.server.resource.autoconfigure.SpringOpaqueTokenIntrospectorBuilderCustomizer[] and javadoc:org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive.SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer[] beans respectively.\n\nTo take complete control of the introspection, define your own javadoc:org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector[] or javadoc:org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector[] bean.\n\n\n\n[[web.security.oauth2.authorization-server]]\n=== Authorization Server\n\nIf you have `spring-security-oauth2-authorization-server` on your classpath, you can take advantage of some auto-configuration to set up a Servlet-based OAuth2 Authorization Server.\n\nYou can register multiple OAuth2 clients under the `spring.security.oauth2.authorizationserver.client` prefix, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    oauth2:\n      authorizationserver:\n        client:\n          my-client-1:\n            registration:\n              client-id: \"abcd\"\n              client-secret: \"{noop}secret1\"\n              client-authentication-methods:\n                - \"client_secret_basic\"\n              authorization-grant-types:\n                - \"authorization_code\"\n                - \"refresh_token\"\n              redirect-uris:\n                - \"https://my-client-1.com/login/oauth2/code/abcd\"\n                - \"https://my-client-1.com/authorized\"\n              scopes:\n                - \"openid\"\n                - \"profile\"\n                - \"email\"\n                - \"phone\"\n                - \"address\"\n            require-authorization-consent: true\n            token:\n              authorization-code-time-to-live: 5m\n              access-token-time-to-live: 10m\n              access-token-format: \"reference\"\n              reuse-refresh-tokens: false\n              refresh-token-time-to-live: 30m\n          my-client-2:\n            registration:\n              client-id: \"efgh\"\n              client-secret: \"{noop}secret2\"\n              client-authentication-methods:\n                - \"client_secret_jwt\"\n              authorization-grant-types:\n                - \"client_credentials\"\n              scopes:\n                - \"user.read\"\n                - \"user.write\"\n            jwk-set-uri: \"https://my-client-2.com/jwks\"\n\t        token-endpoint-authentication-signing-algorithm: \"RS256\"\n----\n\nNOTE: The `client-secret` property must be in a format that can be matched by the configured javadoc:org.springframework.security.crypto.password.PasswordEncoder[].\nThe default instance of javadoc:org.springframework.security.crypto.password.PasswordEncoder[] is created via `PasswordEncoderFactories.createDelegatingPasswordEncoder()`.\n\nThe auto-configuration Spring Boot provides for Spring Authorization Server is designed for getting started quickly.\nMost applications will require customization and will want to define several beans to override auto-configuration.\n\nThe following components can be defined as beans to override auto-configuration specific to Spring Authorization Server:\n\n* javadoc:org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository[]\n* javadoc:org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings[]\n* javadoc:org.springframework.security.web.SecurityFilterChain[]\n* `com.nimbusds.jose.jwk.source.JWKSource<com.nimbusds.jose.proc.SecurityContext>`\n* javadoc:org.springframework.security.oauth2.jwt.JwtDecoder[]\n\nTIP: Spring Boot auto-configures an javadoc:org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository[] which is used by Spring Authorization Server for the management of registered clients.\nThe javadoc:org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository[] has limited capabilities and we recommend using it only for development environments.\nFor production environments, consider using a javadoc:org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository[] or creating your own implementation of javadoc:org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository[].\n\nAdditional information can be found in the {url-spring-security-docs}/servlet/oauth2/authorization-server/getting-started.html[Getting Started] chapter of Spring Security Reference Documentation.\n\n\n\n[[web.security.saml2]]\n== SAML 2.0\n\n\n\n[[web.security.saml2.build]]\n=== Build Configuration\nSAML 2.0 support builds off of the OpenSAML library that https://shibboleth.atlassian.net/wiki/spaces/DEV/pages/1123844333/Use+of+Maven+Central#Publishing-to-Maven-Central[requires an extra repository] configuration.\n\n\n\n[[web.security.saml2.build.maven]]\n==== Using Maven\nWith Maven, you need to add an extra `repository` element to your POM as follows:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<repositories>\n\t<repository>\n\t\t<id>shibboleth-releases</id>\n\t\t<name>Shibboleth Releases Repository</name>\n\t\t<url>https://build.shibboleth.net/maven/releases</url>\n\t\t<snapshots>\n\t\t\t<enabled>false</enabled>\n\t\t</snapshots>\n\t</repository>\n</repositories>\n----\n\n\n[[web.security.saml2.build.gradle]]\n==== Using Gradle\nWith Gradle, a repository element should be added to your build script:\n\n[source,gradle,subs=\"verbatim,attributes\"]\n----\nrepositories {\n    maven { url \"https://build.shibboleth.net/maven/releases\" }\n}\n----\n\n\n\n[[web.security.saml2.relying-party]]\n=== Relying Party\n\nIf you have `spring-security-saml2-service-provider` on your classpath, you can take advantage of some auto-configuration to set up a SAML 2.0 Relying Party.\nThis configuration makes use of the properties under javadoc:org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties[].\n\nA relying party registration represents a paired configuration between an Identity Provider, IDP, and a Service Provider, SP.\nYou can register multiple relying parties under the `spring.security.saml2.relyingparty` prefix, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  security:\n    saml2:\n      relyingparty:\n        registration:\n          my-relying-party1:\n            signing:\n              credentials:\n              - private-key-location: \"path-to-private-key\"\n                certificate-location: \"path-to-certificate\"\n            decryption:\n              credentials:\n              - private-key-location: \"path-to-private-key\"\n                certificate-location: \"path-to-certificate\"\n            singlelogout:\n               url: \"https://myapp/logout/saml2/slo\"\n               response-url: \"https://remoteidp2.slo.url\"\n               binding: \"POST\"\n            assertingparty:\n              verification:\n                credentials:\n                - certificate-location: \"path-to-verification-cert\"\n              entity-id: \"remote-idp-entity-id1\"\n              sso-url: \"https://remoteidp1.sso.url\"\n\n          my-relying-party2:\n            signing:\n              credentials:\n              - private-key-location: \"path-to-private-key\"\n                certificate-location: \"path-to-certificate\"\n            decryption:\n              credentials:\n              - private-key-location: \"path-to-private-key\"\n                certificate-location: \"path-to-certificate\"\n            assertingparty:\n              verification:\n                credentials:\n                - certificate-location: \"path-to-other-verification-cert\"\n              entity-id: \"remote-idp-entity-id2\"\n              sso-url: \"https://remoteidp2.sso.url\"\n              singlelogout:\n                url: \"https://remoteidp2.slo.url\"\n                response-url: \"https://myapp/logout/saml2/slo\"\n                binding: \"POST\"\n----\n\nFor SAML2 logout, by default, Spring Security's javadoc:org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter[] and javadoc:org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutResponseFilter[] only process URLs matching `/logout/saml2/slo`.\nIf you want to customize the `url` to which AP-initiated logout requests get sent to or the `response-url` to which an AP sends logout responses to, to use a different pattern, you need to provide configuration to process that custom pattern.\nFor example, for servlet applications, you can add your own javadoc:org.springframework.security.web.SecurityFilterChain[] that resembles the following:\n\ninclude-code::MySamlRelyingPartyConfiguration[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-session.adoc",
    "content": "[[web.spring-session]]\n= Spring Session\n\nSpring Boot provides {url-spring-session-site}[Spring Session] auto-configuration for a range of data stores.\nFor each data store, a specific Spring Boot starter is provided.\n\nWhen building a servlet web application, the following stores can be auto-configured:\n\n* Redis (`spring-boot-starter-session-data-redis`)\n* JDBC (`spring-boot-starter-session-jdbc`)\n\nThe servlet auto-configuration replaces the need to use `@Enable*HttpSession`.\n\nWhen building a reactive web application, the Redis store can be auto-configured by depending on `spring-boot-starter-session-data-redis`.\nThis replaces the need to use `@EnableRedisWebSession`.\n\nEach store has specific additional settings.\nFor instance, it is possible to customize the name of the table for the JDBC store, as shown in the following example:\n\n[configprops,yaml]\n----\nspring:\n  session:\n    jdbc:\n      table-name: \"SESSIONS\"\n----\n\nFor setting the timeout of the session you can use the configprop:spring.session.timeout[] property.\nIf that property is not set with a servlet web application, the auto-configuration falls back to the value of configprop:server.servlet.session.timeout[].\n\nYou can take control over Spring Session's configuration using `@Enable*HttpSession` (servlet) or `@EnableRedisWebSession` (reactive).\nThis will cause the auto-configuration to back off.\nAlternatively, depend on the relevant Spring Session module directly rather than using one of Spring Boot's starters for Spring Session.\nWith either approach, Spring Session can then be configured using the annotation's attributes rather than the previously described configuration properties.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/partials/dockerfile",
    "content": "# Perform the extraction in a separate builder container\nFROM bellsoft/liberica-openjre-debian:25-cds AS builder\nWORKDIR /builder\n# This points to the built jar file in the target folder\n# Adjust this to 'build/libs/*.jar' if you're using Gradle\nARG JAR_FILE=target/*.jar\n# Copy the jar file to the working directory and rename it to application.jar\nCOPY ${JAR_FILE} application.jar\n# Extract the jar file using an efficient layout\nRUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted\n\n# This is the runtime container\nFROM bellsoft/liberica-openjre-debian:25-cds\nWORKDIR /application\n# Copy the extracted jar contents from the builder container into the working directory in the runtime container\n# Every copy step creates a new docker layer\n# This allows docker to only pull the changes it really needs\nCOPY --from=builder /builder/extracted/dependencies/ ./\nCOPY --from=builder /builder/extracted/spring-boot-loader/ ./\nCOPY --from=builder /builder/extracted/snapshot-dependencies/ ./\nCOPY --from=builder /builder/extracted/application/ ./\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/reference/partials/nav-reference.adoc",
    "content": "* xref:reference:index.adoc[]\n** xref:reference:using/index.adoc[]\n*** xref:reference:using/build-systems.adoc[]\n*** xref:reference:using/structuring-your-code.adoc[]\n*** xref:reference:using/configuration-classes.adoc[]\n*** xref:reference:using/auto-configuration.adoc[]\n*** xref:reference:using/spring-beans-and-dependency-injection.adoc[]\n*** xref:reference:using/using-the-springbootapplication-annotation.adoc[]\n*** xref:reference:using/running-your-application.adoc[]\n*** xref:reference:using/devtools.adoc[]\n*** xref:reference:using/packaging-for-production.adoc[]\n\n** xref:reference:features/index.adoc[]\n*** xref:reference:features/spring-application.adoc[]\n*** xref:reference:features/external-config.adoc[]\n*** xref:reference:features/profiles.adoc[]\n*** xref:reference:features/logging.adoc[]\n*** xref:reference:features/internationalization.adoc[]\n*** xref:reference:features/aop.adoc[]\n*** xref:reference:features/json.adoc[]\n*** xref:reference:features/task-execution-and-scheduling.adoc[]\n*** xref:reference:features/dev-services.adoc[]\n*** xref:reference:features/developing-auto-configuration.adoc[]\n*** xref:reference:features/kotlin.adoc[]\n*** xref:reference:features/ssl.adoc[]\n\n** xref:reference:web/index.adoc[]\n*** xref:reference:web/servlet.adoc[]\n*** xref:reference:web/reactive.adoc[]\n*** xref:reference:web/graceful-shutdown.adoc[]\n*** xref:reference:web/spring-security.adoc[]\n*** xref:reference:web/spring-session.adoc[]\n*** xref:reference:web/spring-graphql.adoc[]\n*** xref:reference:web/spring-hateoas.adoc[]\n\n** xref:reference:data/index.adoc[]\n*** xref:reference:data/sql.adoc[]\n*** xref:reference:data/nosql.adoc[]\n\n** xref:reference:io/index.adoc[]\n*** xref:reference:io/caching.adoc[]\n*** xref:reference:io/spring-batch.adoc[]\n*** xref:reference:io/hazelcast.adoc[]\n*** xref:reference:io/quartz.adoc[]\n*** xref:reference:io/email.adoc[]\n*** xref:reference:io/validation.adoc[]\n*** xref:reference:io/rest-client.adoc[]\n*** xref:reference:io/webservices.adoc[]\n*** xref:reference:io/jta.adoc[]\n\n** xref:reference:messaging/index.adoc[]\n*** xref:reference:messaging/jms.adoc[]\n*** xref:reference:messaging/amqp.adoc[]\n*** xref:reference:messaging/kafka.adoc[]\n*** xref:reference:messaging/pulsar.adoc[]\n*** xref:reference:messaging/rsocket.adoc[]\n*** xref:reference:messaging/spring-integration.adoc[]\n*** xref:reference:messaging/websockets.adoc[]\n\n** xref:reference:testing/index.adoc[]\n*** xref:reference:testing/test-modules.adoc[]\n*** xref:reference:testing/test-scope-dependencies.adoc[]\n*** xref:reference:testing/spring-applications.adoc[]\n*** xref:reference:testing/spring-boot-applications.adoc[]\n*** xref:reference:testing/testcontainers.adoc[]\n*** xref:reference:testing/test-utilities.adoc[]\n\n** xref:reference:packaging/index.adoc[]\n*** xref:reference:packaging/efficient.adoc[]\n*** xref:reference:packaging/aot-cache.adoc[]\n*** xref:reference:packaging/aot.adoc[]\n*** xref:reference:packaging/native-image/index.adoc[]\n**** xref:reference:packaging/native-image/introducing-graalvm-native-images.adoc[]\n**** xref:reference:packaging/native-image/advanced-topics.adoc[]\n*** xref:reference:packaging/checkpoint-restore.adoc[]\n*** xref:reference:packaging/container-images/index.adoc[]\n**** xref:reference:packaging/container-images/efficient-images.adoc[]\n**** xref:reference:packaging/container-images/dockerfiles.adoc[]\n**** xref:reference:packaging/container-images/cloud-native-buildpacks.adoc[]\n\n** xref:reference:actuator/index.adoc[]\n*** xref:reference:actuator/enabling.adoc[]\n*** xref:reference:actuator/endpoints.adoc[]\n*** xref:reference:actuator/monitoring.adoc[]\n*** xref:reference:actuator/jmx.adoc[]\n*** xref:reference:actuator/observability.adoc[]\n*** xref:reference:actuator/loggers.adoc[]\n*** xref:reference:actuator/metrics.adoc[]\n*** xref:reference:actuator/tracing.adoc[]\n*** xref:reference:actuator/auditing.adoc[]\n*** xref:reference:actuator/http-exchanges.adoc[]\n*** xref:reference:actuator/process-monitoring.adoc[]\n*** xref:reference:actuator/cloud-foundry.adoc[]\n\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/annotation-processor.adoc",
    "content": "[[appendix.configuration-metadata.annotation-processor]]\n= Generating Your Own Metadata by Using the Annotation Processor\n\nYou can easily generate your own configuration metadata file from items annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] by using the `spring-boot-configuration-processor` jar.\nThe jar includes a Java annotation processor which is invoked as your project is compiled.\n\n\n\n[[appendix.configuration-metadata.annotation-processor.configuring]]\n== Configuring the Annotation Processor\n\nWhen building with Maven, configure the compiler plugin (3.12.0 or later) to add `spring-boot-configuration-processor` to the annotation processor paths:\n\n[source,xml]\n----\n<project>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<annotationProcessorPaths>\n\t\t\t\t\t\t<path>\n\t\t\t\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t\t\t\t</path>\n\t\t\t\t\t</annotationProcessorPaths>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n----\n\nWith Gradle, a dependency should be declared in the `annotationProcessor` configuration, as shown in the following example:\n\n[source,gradle]\n----\ndependencies {\n\tannotationProcessor \"org.springframework.boot:spring-boot-configuration-processor\"\n}\n----\n\nIf you are using an `additional-spring-configuration-metadata.json` file, the `compileJava` task should be configured to depend on the `processResources` task, as shown in the following example:\n\n[source,gradle]\n----\ntasks.named('compileJava') {\n\tinputs.files(tasks.named('processResources'))\n}\n----\n\nThis dependency ensures that the additional metadata is available when the annotation processor runs during compilation.\n\n[NOTE]\n====\nIf you are using AspectJ in your project, you need to make sure that the annotation processor runs only once.\nThere are several ways to do this.\nWith Maven, you can configure the `maven-apt-plugin` explicitly and add the dependency to the annotation processor only there.\nYou could also let the AspectJ plugin run all the processing and disable annotation processing in the `maven-compiler-plugin` configuration, as follows:\n\n[source,xml]\n----\n<plugin>\n\t<groupId>org.apache.maven.plugins</groupId>\n\t<artifactId>maven-compiler-plugin</artifactId>\n\t<configuration>\n\t\t<proc>none</proc>\n\t</configuration>\n</plugin>\n----\n====\n\n[NOTE]\n====\nIf you are using Lombok in your project, you need to make sure that its annotation processor runs before `spring-boot-configuration-processor`.\nTo do so with Maven, list the annotation processors in the required order using the `annotationProcessors` attribute of the Maven compiler plugin.\nWith Gradle, declare the dependencies in the `annotationProcessor` configuration in the required order.\n====\n\n\n\n[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation]]\n== Automatic Metadata Generation\n\nThe processor picks up both classes and methods that are annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]. It also picks classes that are annotated with javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesSource[format=annotation]\n\nNOTE: Custom annotations that are meta-annotated with either of those annotations are not supported.\n\nIf the class has a single parameterized constructor, one property is created per constructor parameter, unless the constructor is annotated with javadoc:org.springframework.beans.factory.annotation.Autowired[format=annotation].\nIf the class has a constructor explicitly annotated with javadoc:org.springframework.boot.context.properties.bind.ConstructorBinding[format=annotation], one property is created per constructor parameter for that constructor.\nOtherwise, properties are discovered through the presence of standard getters and setters with special handling for collection and map types (that is detected even if only a getter is present).\nThe annotation processor also supports the use of the javadoc:{url-lombok-javadoc}/lombok.Data[format=annotation], javadoc:{url-lombok-javadoc}/lombok.Value[format=annotation], javadoc:{url-lombok-javadoc}/lombok.Getter[format=annotation], and javadoc:{url-lombok-javadoc}/lombok.Setter[format=annotation] lombok annotations.\n\nConsider the following example:\n\ninclude-code::MyServerProperties[]\n\nThis exposes three properties where `my.server.name` has no default and `my.server.ip` and `my.server.port` defaults to `\"127.0.0.1\"` and `9797` respectively.\nThe Javadoc on fields is used to populate the `description` attribute.\nFor instance, the description of `my.server.ip` is \"IP address to listen to.\".\n\nThe `description` attribute can only be populated when the type is available as source code that is being compiled.\nIt will not be populated when the type is only available as a compiled class from a dependency.\nFor such cases, you can xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.source[source the metadata] or xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[provide manual entries].\n\nNOTE: You should only use plain text with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] field Javadoc, since they are not processed before being added to the JSON.\n\nIf you use javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] with record class then record components' descriptions should be provided via class-level Javadoc tag `@param` (there are no explicit instance fields in record classes to put regular field-level Javadocs on).\n\nThe annotation processor applies a number of heuristics to extract the default value from the source model.\nDefault values can only be extracted when the type is available as source code that is being compiled.\nThey will not be extracted when the type is only available as a compiled class from a dependency.\nFurthermore, default values have to be provided statically.\nIn particular, do not refer to a constant defined in another class.\nAlso, the annotation processor cannot auto-detect default values for ``Collections``s.\n\nFor cases where the default value could not be detected, xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[manual metadata] should be provided.\nConsider the following example:\n\ninclude-code::MyMessagingProperties[]\n\nIn order to document default values for properties in the class above, you could add the following content to xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[the manual metadata of the module]:\n\n[source,json]\n----\n{\"properties\": [\n\t{\n\t\t\"name\": \"my.messaging.addresses\",\n\t\t\"defaultValue\": [\"a\", \"b\"]\n\t},\n\t{\n\t\t\"name\": \"my.messaging.container-type\",\n\t\t\"defaultValue\": \"simple\"\n\t}\n]}\n----\n\nNOTE: Only the `name` of the property is required to document additional metadata for existing properties.\n\n\n\n[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.nested-properties]]\n=== Nested Properties\n\nThe annotation processor automatically considers inner classes as nested properties.\nRather than documenting the `ip` and `port` at the root of the namespace, we could create a sub-namespace for it.\nConsider the updated example:\n\ninclude-code::MyServerProperties[]\n\nThe preceding example produces metadata information for `my.server.name`, `my.server.host.ip`, and `my.server.host.port` properties.\nYou can use the javadoc:org.springframework.boot.context.properties.NestedConfigurationProperty[format=annotation] annotation on a field or a getter method to indicate that a regular (non-inner) class should be treated as if it were nested.\n\nTIP: This has no effect on collections and maps, as those types are automatically identified, and a single metadata property is generated for each of them.\n\n\n\n[[appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.source]]\n=== Configuration Properties Source\n\nIf a type located in another module is used in a javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]-annotated type, some metadata elements cannot be discovered automatically.\nReusing the example above, if `Host` is located in another module, full metadata is not available as the annotation processor does not have access to the source of `Host`.\n\nTo handle this use case, add the annotation processor in the module that contains the `Host` type and annotate it with javadoc:org.springframework.boot.context.properties.ConfigurationPropertiesSource[format=annotation]:\n\ninclude-code::Host[]\n\nThis generates the metadata for `Host` in `META-INF/spring/configuration-metadata/com.example.Host.json` and is reused automatically by the annotation processor when it handles such type.\n\nYou can also annotate a parent class located in another module that a javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation]-annotated type extends from.\n\nTIP: If you need to reuse metadata for a type that you do not control, create a file named with the pattern above and it will be used as long as it is available on the classpath.\n\n\n\n[[appendix.configuration-metadata.annotation-processor.adding-additional-metadata]]\n== Adding Additional Metadata\n\nSpring Boot's configuration file handling is quite flexible, and it is often the case that properties may exist that are not bound to a javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] bean.\nYou may also need to tune some attributes of an existing key or to ignore the key altogether.\nTo support such cases and let you provide custom \"hints\", the annotation processor automatically merges items from `META-INF/additional-spring-configuration-metadata.json` into the main metadata file.\n\nWhen generating source metadata for a type, you can also craft custom metadata for that type, for example `com.example.SomeType`, in `META-INF/spring/configuration/metadata/com.example.SomeType.json`.\n\nIf you refer to a property that has been detected automatically, the description, default value, and deprecation information are overridden, if specified.\nIf the manual property declaration is not identified in the current module, it is added as a new property.\n\nThe format of the additional metadata file is exactly the same as the regular `spring-configuration-metadata.json`.\nThe items contained in the \"`ignored.properties`\" section are removed from the \"`properties`\" section of the generated  `spring-configuration-metadata.json` file.\n\nThe additional properties file is optional.\nIf you do not have any additional properties, do not add the file.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/format.adoc",
    "content": "[[appendix.configuration-metadata.format]]\n= Metadata Format\n\nConfiguration metadata files are located inside jars under `META-INF/spring-configuration-metadata.json`.\nThey use a JSON format with items categorized under either \"`groups`\" or \"`properties`\", additional values hints categorized under \"`hints`\", and ignored items under \"`ignored`\" as shown in the following example:\n\n[source,json]\n----\n{\"groups\": [\n\t{\n\t\t\"name\": \"server\",\n\t\t\"type\": \"org.springframework.boot.web.server.autoconfigure.ServerProperties\",\n\t\t\"sourceType\": \"org.springframework.boot.web.server.autoconfigure.ServerProperties\"\n\t},\n\t{\n\t\t\"name\": \"spring.jpa.hibernate\",\n\t\t\"type\": \"org.springframework.boot.jpa.autoconfigure.JpaProperties$Hibernate\",\n\t\t\"sourceType\": \"org.springframework.boot.jpa.autoconfigure.JpaProperties\",\n\t\t\"sourceMethod\": \"getHibernate()\"\n\t}\n\t...\n],\"properties\": [\n\t{\n\t\t\"name\": \"server.port\",\n\t\t\"type\": \"java.lang.Integer\",\n\t\t\"sourceType\": \"org.springframework.boot.web.server.autoconfigure.ServerProperties\"\n\t},\n\t{\n\t\t\"name\": \"server.address\",\n\t\t\"type\": \"java.net.InetAddress\",\n\t\t\"sourceType\": \"org.springframework.boot.web.server.autoconfigure.ServerProperties\"\n\t},\n\t{\n\t\t  \"name\": \"spring.jpa.hibernate.ddl-auto\",\n\t\t  \"type\": \"java.lang.String\",\n\t\t  \"description\": \"DDL mode. This is actually a shortcut for the \\\"hibernate.hbm2ddl.auto\\\" property.\",\n\t\t  \"sourceType\": \"org.springframework.boot.jpa.autoconfigure.JpaProperties$Hibernate\"\n\t}\n\t...\n],\"hints\": [\n\t{\n\t\t\"name\": \"spring.jpa.hibernate.ddl-auto\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"value\": \"none\",\n\t\t\t\t\"description\": \"Disable DDL handling.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"validate\",\n\t\t\t\t\"description\": \"Validate the schema, make no changes to the database.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"update\",\n\t\t\t\t\"description\": \"Update the schema if necessary.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"create\",\n\t\t\t\t\"description\": \"Create the schema and destroy previous data.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"create-drop\",\n\t\t\t\t\"description\": \"Create and then destroy the schema at the end of the session.\"\n\t\t\t}\n\t\t]\n\t}\n\t...\n],\"ignored\": {\n\t\"properties\": [\n\t\t{\n\t\t\t\"name\": \"server.ignored\"\n\t\t}\n\t\t...\n\t]\n}}\n----\n\nEach \"`property`\" is a configuration item that the user specifies with a given value.\nFor example, `server.port` and `server.address` might be specified in your `application.properties`/`application.yaml`, as follows:\n\n[configprops,yaml]\n----\nserver:\n  port: 9090\n  address: 127.0.0.1\n----\n\nThe \"`groups`\" are higher level items that do not themselves specify a value but instead provide a contextual grouping for properties.\nFor example, the `server.port` and `server.address` properties are part of the `server` group.\n\nNOTE: It is not required that every \"`property`\" has a \"`group`\".\nSome properties might exist in their own right.\n\nThe \"`hints`\" are additional information used to assist the user in configuring a given property.\nFor example, when a developer is configuring the configprop:spring.jpa.hibernate.ddl-auto[] property, a tool can use the hints to offer some auto-completion help for the `none`, `validate`, `update`, `create`, and `create-drop` values.\n\nFinally, \"`ignored`\" is for items which have been deliberately ignored.\nThe content of this section usually comes from the xref:specification:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[additional metadata].\n\n\n\n[[appendix.configuration-metadata.format.group]]\n== Group Attributes\n\nThe JSON object contained in the `groups` array can contain the attributes shown in the following table:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `name`\n| String\n| The full name of the group.\n  This attribute is mandatory.\n\n| `type`\n| String\n| The class name of the data type of the group.\n  For example, if the group were based on a class annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation], the attribute would contain the fully qualified name of that class.\n  If it were based on a javadoc:org.springframework.context.annotation.Bean[format=annotation] method, it would be the return type of that method.\n  If the type is not known, the attribute may be omitted.\n\n| `description`\n| String\n| A short description of the group that can be displayed to users.\n  If no description is available, it may be omitted.\n  It is recommended that descriptions be short paragraphs, with the first line providing a concise summary.\n  The last line in the description should end with a period (`.`).\n\n| `sourceType`\n| String\n| The class name of the source that contributed this group.\n  For example, if the group were based on a javadoc:org.springframework.context.annotation.Bean[format=annotation] method annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation], this attribute would contain the fully qualified name of the javadoc:org.springframework.context.annotation.Configuration[format=annotation] class that contains the method.\n  If the source type is not known, the attribute may be omitted.\n\n| `sourceMethod`\n| String\n| The full name of the method (include parenthesis and argument types) that contributed this group (for example, the name of a javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation] annotated javadoc:org.springframework.context.annotation.Bean[format=annotation] method).\n  If the source method is not known, it may be omitted.\n|===\n\n\n\n[[appendix.configuration-metadata.format.property]]\n== Property Attributes\n\nThe JSON object contained in the `properties` array can contain the attributes described in the following table:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `name`\n| String\n| The full name of the property.\n  Names are in lower-case period-separated form (for example, `server.address`).\n  This attribute is mandatory.\n\n| `type`\n| String\n| The full signature of the data type of the property (for example, javadoc:java.lang.String[]) but also a full generic type (such as `java.util.Map<java.lang.String,com.example.MyEnum>`).\n  You can use this attribute to guide the user as to the types of values that they can enter.\n  For consistency, the type of a primitive is specified by using its wrapper counterpart (for example, `boolean` becomes javadoc:java.lang.Boolean[]).\n  Note that this class may be a complex type that gets converted from a javadoc:java.lang.String[] as values are bound.\n  If the type is not known, it may be omitted.\n\n| `description`\n| String\n| A short description of the property that can be displayed to users.\n  If no description is available, it may be omitted.\n  It is recommended that descriptions be short paragraphs, with the first line providing a concise summary.\n  The last line in the description should end with a period (`.`).\n\n| `sourceType`\n| String\n| The class name of the source that contributed this property.\n  For example, if the property were from a class annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation], this attribute would contain the fully qualified name of that class.\n  If the source type is unknown, it may be omitted.\n\n| `defaultValue`\n| Object\n| The default value, which is used if the property is not specified.\n  If the type of the property is an array, it can be an array of value(s).\n  If the default value is unknown, it may be omitted.\n\n| `deprecation`\n| Deprecation\n| Specify whether the property is deprecated.\n  If the field is not deprecated or if that information is not known, it may be omitted.\n  The next table offers more detail about the `deprecation` attribute.\n|===\n\nThe JSON object contained in the `deprecation` attribute of each `properties` element can contain the following attributes:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `level`\n| String\n| The level of deprecation, which can be either `warning` (the default) or `error`.\n  When a property has a `warning` deprecation level, it should still be bound in the environment.\n  However, when it has an `error` deprecation level, the property is no longer managed and is not bound.\n\n| `reason`\n| String\n| A short description of the reason why the property was deprecated.\n  If no reason is available, it may be omitted.\n  It is recommended that descriptions be short paragraphs, with the first line providing a concise summary.\n  The last line in the description should end with a period (`.`).\n\n| `replacement`\n| String\n| The full name of the property that _replaces_ this deprecated property.\n  If there is no replacement for this property, it may be omitted.\n\n| `since`\n| String\n| The version in which the property became deprecated.\n  Can be omitted.\n|===\n\nNOTE: Prior to Spring Boot 1.3, a single `deprecated` boolean attribute can be used instead of the `deprecation` element.\nThis is still supported in a deprecated fashion and should no longer be used.\nIf no reason and replacement are available, an empty `deprecation` object should be set.\n\nDeprecation can also be specified declaratively in code by adding the javadoc:org.springframework.boot.context.properties.DeprecatedConfigurationProperty[format=annotation] annotation to the getter exposing the deprecated property.\nFor instance, assume that the `my.app.target` property was confusing and was renamed to `my.app.name`.\nThe following example shows how to handle that situation:\n\ninclude-code::MyProperties[]\n\nNOTE: There is no way to set a `level`.\n`warning` is always assumed, since code is still handling the property.\n\nThe preceding code makes sure that the deprecated property still works (delegating to the `name` property behind the scenes).\nOnce the `getTarget` and `setTarget` methods can be removed from your public API, the automatic deprecation hint in the metadata goes away as well.\nIf you want to keep a hint, adding manual metadata with an `error` deprecation level ensures that users are still informed about that property.\nDoing so is particularly useful when a `replacement` is provided.\n\n\n\n[[appendix.configuration-metadata.format.hints]]\n== Hint Attributes\n\nThe JSON object contained in the `hints` array can contain the attributes shown in the following table:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `name`\n| String\n| The full name of the property to which this hint refers.\n  Names are in lower-case period-separated form (such as `spring.mvc.servlet.path`).\n  If the property refers to a map (such as `system.contexts`), the hint either applies to the _keys_ of the map (`system.contexts.keys`) or the _values_ (`system.contexts.values`) of the map.\n  This attribute is mandatory.\n\n| `values`\n| ValueHint[]\n| A list of valid values as defined by the `ValueHint` object (described in the next table).\n  Each entry defines the value and may have a description.\n\n| `providers`\n| ValueProvider[]\n| A list of providers as defined by the `ValueProvider` object (described later in this document).\n  Each entry defines the name of the provider and its parameters, if any.\n|===\n\nThe JSON object contained in the `values` attribute of each `hint` element can contain the attributes described in the following table:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `value`\n| Object\n| A valid value for the element to which the hint refers.\n  If the type of the property is an array, it can also be an array of value(s).\n  This attribute is mandatory.\n\n| `description`\n| String\n| A short description of the value that can be displayed to users.\n  If no description is available, it may be omitted.\n  It is recommended that descriptions be short paragraphs, with the first line providing a concise summary.\n  The last line in the description should end with a period (`.`).\n|===\n\nThe JSON object contained in the `providers` attribute of each `hint` element can contain the attributes described in the following table:\n\n[cols=\"1,1,4\"]\n|===\n|Name | Type |Purpose\n\n| `name`\n| String\n| The name of the provider to use to offer additional content assistance for the element to which the hint refers.\n\n| `parameters`\n| JSON object\n| Any additional parameter that the provider supports (check the documentation of the provider for more details).\n|===\n\n\n\n[[appendix.configuration-metadata.format.ignored]]\n== Ignored Attributes\n\nThe `ignored` object can contain the attributes shown in the following table:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `properties`\n| ItemIgnore[]\n| A list of ignored properties as defined by the ItemIgnore object (described in the next table). Each entry defines the name of the ignored property.\n\n|===\n\nThe JSON object contained in the `properties` attribute of each `ignored` element can contain the attributes described in the following table:\n\n[cols=\"1,1,4\"]\n|===\n| Name | Type | Purpose\n\n| `name`\n| String\n| The full name of the property to ignore.\nNames are in lower-case period-separated form (such as `spring.mvc.servlet.path`).\nThis attribute is mandatory.\n\n|===\n\n\n[[appendix.configuration-metadata.format.repeated-items]]\n== Repeated Metadata Items\n\nObjects with the same \"`property`\" and \"`group`\" name can appear multiple times within a metadata file.\nFor example, you could bind two separate classes to the same prefix, with each having potentially overlapping property names.\nWhile the same names appearing in the metadata multiple times should not be common, consumers of metadata should take care to ensure that they support it.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/index.adoc",
    "content": "[appendix]\n[[appendix.configuration-metadata]]\n= Configuration Metadata\n\nSpring Boot jars include metadata files that provide details of all supported configuration properties.\nThe files are designed to let IDE developers offer contextual help and \"`code completion`\" as users are working with `application.properties` or `application.yaml` files.\n\nThe majority of the metadata file is generated automatically at compile time by processing all items annotated with javadoc:org.springframework.boot.context.properties.ConfigurationProperties[format=annotation].\nFor corner cases or more advanced use cases, it is possible to xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.source[source the metadata of external types ] or xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[write part of the metadata manually].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/configuration-metadata/manual-hints.adoc",
    "content": "[[appendix.configuration-metadata.manual-hints]]\n= Providing Manual Hints\n\nTo improve the user experience and further assist the user in configuring a given property, you can provide additional metadata that:\n\n* Describes the list of potential values for a property.\n* Associates a provider, to attach a well defined semantic to a property, so that a tool can discover the list of potential values based on the project's context.\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-hint]]\n== Value Hint\n\nThe `name` attribute of each hint refers to the `name` of a property.\nIn the xref:configuration-metadata/format.adoc[initial example shown earlier], we provide five values for the `spring.jpa.hibernate.ddl-auto` property: `none`, `validate`, `update`, `create`, and `create-drop`.\nEach value may have a description as well.\n\nIf your property is of type javadoc:java.util.Map[], you can provide hints for both the keys and the values (but not for the map itself).\nThe special `.keys` and `.values` suffixes must refer to the keys and the values, respectively.\n\nAssume a `my.contexts` maps magic javadoc:java.lang.String[] values to an integer, as shown in the following example:\n\ninclude-code::MyProperties[]\n\nThe magic values are (in this example) are `sample1` and `sample2`.\nIn order to offer additional content assistance for the keys, you could add the following JSON to xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.adding-additional-metadata[the manual metadata of the module]:\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"my.contexts.keys\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"value\": \"sample1\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"sample2\"\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n\nNOTE: Hints can also be added for xref:configuration-metadata/annotation-processor.adoc#appendix.configuration-metadata.annotation-processor.automatic-metadata-generation.source[external types] and are applied whenever that type is used.\n\nTIP: We recommend that you use an javadoc:java.lang.Enum[] for those two values instead.\nIf your IDE supports it, this is by far the most effective approach to auto-completion.\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers]]\n== Value Providers\n\nProviders are a powerful way to attach semantics to a property.\nIn this section, we define the official providers that you can use for your own hints.\nHowever, your favorite IDE may implement some of these or none of them.\nAlso, it could eventually provide its own.\n\nNOTE: As this is a new feature, IDE vendors must catch up with how it works.\nAdoption times naturally vary.\n\nThe following table summarizes the list of supported providers:\n\n[cols=\"2,4\"]\n|===\n| Name | Description\n\n| `any`\n| Permits any additional value to be provided.\n\n| `class-reference`\n| Auto-completes the classes available in the project.\n  Usually constrained by a base class that is specified by the `target` parameter.\n\n| `handle-as`\n| Handles the property as if it were defined by the type defined by the mandatory `target` parameter.\n\n| `logger-name`\n| Auto-completes valid logger names and xref:reference:features/logging.adoc#features.logging.log-groups[logger groups].\n  Typically, package and class names available in the current project can be auto-completed as well as defined groups.\n\n| `spring-bean-reference`\n| Auto-completes the available bean names in the current project.\n  Usually constrained by a base class that is specified by the `target` parameter.\n\n| `spring-profile-name`\n| Auto-completes the available Spring profile names in the project.\n|===\n\nTIP: Only one provider can be active for a given property, but you can specify several providers if they can all manage the property _in some way_.\nMake sure to place the most powerful provider first, as the IDE must use the first one in the JSON section that it can handle.\nIf no provider for a given property is supported, no special content assistance is provided, either.\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers.any]]\n=== Any\n\nThe special **any** provider value permits any additional values to be provided.\nRegular value validation based on the property type should be applied if this is supported.\n\nThis provider is typically used if you have a list of values and any extra values should still be considered as valid.\n\nThe following example offers `on` and `off` as auto-completion values for `system.state`:\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"system.state\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"value\": \"on\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"off\"\n\t\t\t}\n\t\t],\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"any\"\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n\nNote that, in the preceding example, any other value is also allowed.\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers.class-reference]]\n=== Class Reference\n\nThe **class-reference** provider auto-completes classes available in the project.\nThis provider supports the following parameters:\n\n[cols=\"1,1,2,4\"]\n|===\n| Parameter | Type | Default value | Description\n\n| `target`\n| javadoc:java.lang.String[] (`Class`)\n| _none_\n| The fully qualified name of the class that should be assignable to the chosen value.\n  Typically used to filter out-non candidate classes.\n  Note that this information can be provided by the type itself by exposing a class with the appropriate upper bound.\n\n| `concrete`\n| `boolean`\n| true\n| Specify whether only concrete classes are to be considered as valid candidates.\n|===\n\n\nThe following metadata snippet corresponds to the standard `server.servlet.jsp.class-name` property that defines the class name to use must be an javadoc:jakarta.servlet.http.HttpServlet[]:\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"server.servlet.jsp.class-name\",\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"class-reference\",\n\t\t\t\t\"parameters\": {\n\t\t\t\t\t\"target\": \"jakarta.servlet.http.HttpServlet\"\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers.handle-as]]\n=== Handle As\n\nThe **handle-as** provider lets you substitute the type of the property to a more high-level type.\nThis typically happens when the property has a javadoc:java.lang.String[] type, because you do not want your configuration classes to rely on classes that may not be on the classpath.\nThis provider supports the following parameters:\n\n[cols=\"1,1,2,4\"]\n|===\n| Parameter | Type | Default value | Description\n\n| **`target`**\n| javadoc:java.lang.String[] (`Class`)\n| _none_\n| The fully qualified name of the type to consider for the property.\n  This parameter is mandatory.\n|===\n\nThe following types can be used:\n\n* Any javadoc:java.lang.Enum[]: Lists the possible values for the property.\n  (We recommend defining the property with the javadoc:java.lang.Enum[] type, as no further hint should be required for the IDE to auto-complete the values)\n* javadoc:java.nio.charset.Charset[]: Supports auto-completion of charset/encoding values (such as `UTF-8`)\n* javadoc:java.util.Locale[]: auto-completion of locales (such as `en_US`)\n* javadoc:org.springframework.util.MimeType[]: Supports auto-completion of content type values (such as `text/plain`)\n* javadoc:org.springframework.core.io.Resource[]: Supports auto-completion of Spring’s Resource abstraction to refer to a file on the filesystem or on the classpath (such as `classpath:/sample.properties`)\n\nTIP: If multiple values can be provided, use a javadoc:java.util.Collection[] or _Array_ type to teach the IDE about it.\n\nThe following metadata snippet corresponds to the standard `spring.liquibase.change-log` property that defines the path to the changelog to use.\nIt is actually used internally as a javadoc:org.springframework.core.io.Resource[] but cannot be exposed as such, because we need to keep the original String value to pass it to the Liquibase API.\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"spring.liquibase.change-log\",\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"handle-as\",\n\t\t\t\t\"parameters\": {\n\t\t\t\t\t\"target\": \"org.springframework.core.io.Resource\"\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers.logger-name]]\n=== Logger Name\n\nThe **logger-name** provider auto-completes valid logger names and xref:reference:features/logging.adoc#features.logging.log-groups[logger groups].\nTypically, package and class names available in the current project can be auto-completed.\nIf groups are enabled (default) and if a custom logger group is identified in the configuration, auto-completion for it should be provided.\nSpecific frameworks may have extra magic logger names that can be supported as well.\n\nThis provider supports the following parameters:\n\n[cols=\"1,1,2,4\"]\n|===\n| Parameter | Type | Default value | Description\n\n| `group`\n| `boolean`\n| `true`\n| Specify whether known groups should be considered.\n|===\n\nSince a logger name can be any arbitrary name, this provider should allow any value but could highlight valid package and class names that are not available in the project's classpath.\n\nThe following metadata snippet corresponds to the standard `logging.level` property.\nKeys are _logger names_, and values correspond to the standard log levels or any custom level.\nAs Spring Boot defines a few logger groups out-of-the-box, dedicated value hints have been added for those.\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"logging.level.keys\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"value\": \"root\",\n\t\t\t\t\"description\": \"Root logger used to assign the default logging level.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"sql\",\n\t\t\t\t\"description\": \"SQL logging group including Hibernate SQL logger.\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"web\",\n\t\t\t\t\"description\": \"Web logging group including codecs.\"\n\t\t\t}\n\t\t],\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"logger-name\"\n\t\t\t}\n\t\t]\n\t},\n\t{\n\t\t\"name\": \"logging.level.values\",\n\t\t\"values\": [\n\t\t\t{\n\t\t\t\t\"value\": \"trace\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"debug\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"info\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"warn\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"error\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"fatal\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"value\": \"off\"\n\t\t\t}\n\n\t\t],\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"any\"\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers.spring-bean-reference]]\n=== Spring Bean Reference\n\nThe **spring-bean-reference** provider auto-completes the beans that are defined in the configuration of the current project.\nThis provider supports the following parameters:\n\n[cols=\"1,1,2,4\"]\n|===\n| Parameter | Type | Default value | Description\n\n| `target`\n| javadoc:java.lang.String[] (`Class`)\n| _none_\n| The fully qualified name of the bean class that should be assignable to the candidate.\n  Typically used to filter out non-candidate beans.\n|===\n\nThe following metadata snippet corresponds to the standard `spring.jmx.server` property that defines the name of the javadoc:javax.management.MBeanServer[] bean to use:\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"spring.jmx.server\",\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"spring-bean-reference\",\n\t\t\t\t\"parameters\": {\n\t\t\t\t\t\"target\": \"javax.management.MBeanServer\"\n\t\t\t\t}\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n\nNOTE: The binder is not aware of the metadata.\nIf you provide that hint, you still need to transform the bean name into an actual Bean reference using by the javadoc:org.springframework.context.ApplicationContext[].\n\n\n\n[[appendix.configuration-metadata.manual-hints.value-providers.spring-profile-name]]\n=== Spring Profile Name\n\nThe **spring-profile-name** provider auto-completes the Spring profiles that are defined in the configuration of the current project.\n\nThe following metadata snippet corresponds to the standard `spring.profiles.active` property that defines the name of the Spring profile(s) to enable:\n\n[source,json]\n----\n{\"hints\": [\n\t{\n\t\t\"name\": \"spring.profiles.active\",\n\t\t\"providers\": [\n\t\t\t{\n\t\t\t\t\"name\": \"spring-profile-name\"\n\t\t\t}\n\t\t]\n\t}\n]}\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/alternatives.adoc",
    "content": "[[appendix.executable-jar.alternatives]]\n= Alternative Single Jar Solutions\n\nIf the preceding restrictions mean that you cannot use Spring Boot Loader, consider the following alternatives:\n\n* https://maven.apache.org/plugins/maven-shade-plugin/[Maven Shade Plugin]\n* http://www.jdotsoft.com/JarClassLoader.php[JarClassLoader]\n* https://sourceforge.net/projects/one-jar/[OneJar]\n* https://gradleup.com/shadow/[Gradle Shadow Plugin]\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/index.adoc",
    "content": "[appendix]\n[[appendix.executable-jar]]\n= The Executable Jar Format\n\nThe `spring-boot-loader` modules lets Spring Boot support executable jar and war files.\nIf you use the Maven plugin or the Gradle plugin, executable jars are automatically generated, and you generally do not need to know the details of how they work.\n\nIf you need to create executable jars from a different build system or if you are just curious about the underlying technology, this appendix provides some background.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/jarfile-class.adoc",
    "content": "[[appendix.executable-jar.jarfile-class]]\n= Spring Boot's \"`NestedJarFile`\" Class\n\nThe core class used to support loading nested jars is javadoc:org.springframework.boot.loader.jar.NestedJarFile[].\nIt lets you load jar content from nested child jar data.\nWhen first loaded, the location of each javadoc:java.util.jar.JarEntry[] is mapped to a physical file offset of the outer jar, as shown in the following example:\n\n[source]\n----\nmyapp.jar\n+-------------------+-------------------------+\n| /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |\n|+-----------------+||+-----------+----------+|\n||     A.class      |||  B.class  |  C.class ||\n|+-----------------+||+-----------+----------+|\n+-------------------+-------------------------+\n ^                    ^           ^\n 0063                 3452        3980\n----\n\nThe preceding example shows how `A.class` can be found in `/BOOT-INF/classes` in `myapp.jar` at position `0063`.\n`B.class` from the nested jar can actually be found in `myapp.jar` at position `3452`, and `C.class` is at position `3980`.\n\nArmed with this information, we can load specific nested entries by seeking to the appropriate part of the outer jar.\nWe do not need to unpack the archive, and we do not need to read all entry data into memory.\n\n\n\n[[appendix.executable-jar.jarfile-class.compatibility]]\n== Compatibility With the Standard Java \"`JarFile`\"\n\nSpring Boot Loader strives to remain compatible with existing code and libraries.\njavadoc:org.springframework.boot.loader.jar.NestedJarFile[] extends from javadoc:java.util.jar.JarFile[] and should work as a drop-in replacement.\n\nNested JAR URLs of the form `jar:nested:/path/myjar.jar/!BOOT-INF/lib/mylib.jar!/B.class` are supported and open a connection compatible with javadoc:java.net.JarURLConnection[].\nThese can be used with Java's javadoc:java.net.URLClassLoader[].\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/launching.adoc",
    "content": "[[appendix.executable-jar.launching]]\n= Launching Executable Jars\n\nThe javadoc:org.springframework.boot.loader.launch.Launcher[] class is a special bootstrap class that is used as an executable jar's main entry point.\nIt is the actual `Main-Class` in your jar file, and it is used to setup an appropriate javadoc:java.lang.ClassLoader[] and ultimately call your `main()` method.\n\nThere are three launcher subclasses (javadoc:org.springframework.boot.loader.launch.JarLauncher[], javadoc:org.springframework.boot.loader.launch.WarLauncher[], and javadoc:org.springframework.boot.loader.launch.PropertiesLauncher[]).\nTheir purpose is to load resources (`.class` files and so on) from nested jar files or war files in directories (as opposed to those explicitly on the classpath).\nIn the case of javadoc:org.springframework.boot.loader.launch.JarLauncher[] and javadoc:org.springframework.boot.loader.launch.WarLauncher[], the nested paths are fixed.\njavadoc:org.springframework.boot.loader.launch.JarLauncher[] looks in `BOOT-INF/lib/`, and javadoc:org.springframework.boot.loader.launch.WarLauncher[] looks in `WEB-INF/lib/` and `WEB-INF/lib-provided/`.\nYou can add extra jars in those locations if you want more.\n\nThe javadoc:org.springframework.boot.loader.launch.PropertiesLauncher[] looks in `BOOT-INF/lib/` in your application archive by default.\nYou can add additional locations by setting an environment variable called `LOADER_PATH` or `loader.path` in `loader.properties` (which is a comma-separated list of directories, archives, or directories within archives).\n\n\n\n[[appendix.executable-jar.launching.manifest]]\n== Launcher Manifest\n\nYou need to specify an appropriate javadoc:org.springframework.boot.loader.launch.Launcher[] as the `Main-Class` attribute of `META-INF/MANIFEST.MF`.\nThe actual class that you want to launch (that is, the class that contains a `main` method) should be specified in the `Start-Class` attribute.\n\nThe following example shows a typical `MANIFEST.MF` for an executable jar file:\n\n[source,manifest]\n----\nMain-Class: org.springframework.boot.loader.launch.JarLauncher\nStart-Class: com.mycompany.project.MyApplication\n----\n\nFor a war file, it would be as follows:\n\n[source,manifest]\n----\nMain-Class: org.springframework.boot.loader.launch.WarLauncher\nStart-Class: com.mycompany.project.MyApplication\n----\n\nNOTE: You need not specify `Class-Path` entries in your manifest file.\nThe classpath is deduced from the nested jars.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/nested-jars.adoc",
    "content": "[[appendix.executable-jar.nested-jars]]\n= Nested JARs\n\nJava does not provide any standard way to load nested jar files (that is, jar files that are themselves contained within a jar).\nThis can be problematic if you need to distribute a self-contained application that can be run from the command line without unpacking.\n\nTo solve this problem, many developers use \"`shaded`\" jars.\nA shaded jar packages all classes, from all jars, into a single \"`uber jar`\".\nThe problem with shaded jars is that it becomes hard to see which libraries are actually in your application.\nIt can also be problematic if the same filename is used (but with different content) in multiple jars.\nSpring Boot takes a different approach and lets you actually nest jars directly.\n\n\n\n[[appendix.executable-jar.nested-jars.jar-structure]]\n== The Executable Jar File Structure\n\nSpring Boot Loader-compatible jar files should be structured in the following way:\n\n[source]\n----\nexample.jar\n |\n +-META-INF\n |  +-MANIFEST.MF\n +-org\n |  +-springframework\n |     +-boot\n |        +-loader\n |           +-<spring boot loader classes>\n +-BOOT-INF\n    +-classes\n    |  +-mycompany\n    |     +-project\n    |        +-YourClasses.class\n    +-lib\n       +-dependency1.jar\n       +-dependency2.jar\n----\n\nApplication classes should be placed in a nested `BOOT-INF/classes` directory.\nDependencies should be placed in a nested `BOOT-INF/lib` directory.\n\n\n\n[[appendix.executable-jar.nested-jars.war-structure]]\n== The Executable War File Structure\n\nSpring Boot Loader-compatible war files should be structured in the following way:\n\n[source]\n----\nexample.war\n |\n +-META-INF\n |  +-MANIFEST.MF\n +-org\n |  +-springframework\n |     +-boot\n |        +-loader\n |           +-<spring boot loader classes>\n +-WEB-INF\n    +-classes\n    |  +-com\n    |     +-mycompany\n    |        +-project\n    |           +-YourClasses.class\n    +-lib\n    |  +-dependency1.jar\n    |  +-dependency2.jar\n    +-lib-provided\n       +-servlet-api.jar\n       +-dependency3.jar\n----\n\nDependencies should be placed in a nested `WEB-INF/lib` directory.\nAny dependencies that are required when running embedded but are not required when deploying to a traditional web container should be placed in `WEB-INF/lib-provided`.\n\n\n\n[[appendix.executable-jar.nested-jars.index-files]]\n== Index Files\n\nSpring Boot Loader-compatible jar and war archives can include additional index files under the `BOOT-INF/` directory.\nA `classpath.idx` file can be provided for both jars and wars, and it provides the ordering that jars should be added to the classpath.\nThe `layers.idx` file can be used only for jars, and it allows a jar to be split into logical layers for Docker/OCI image creation.\n\nIndex files follow a YAML compatible syntax so that they can be easily parsed by third-party tools.\nThese files, however, are _not_ parsed internally as YAML and they must be written in exactly the formats described below in order to be used.\n\n\n\n[[appendix.executable-jar.nested-jars.classpath-index]]\n== Classpath Index\n\nThe classpath index file can be provided in `BOOT-INF/classpath.idx`.\nTypically, it is generated automatically by Spring Boot's Maven and Gradle build plugins.\nIt provides a list of jar names (including the directory) in the order that they should be added to the classpath.\nWhen generated by the build plugins, this classpath ordering matches that used by the build system for running and testing the application.\nEach line must start with dash space (`\"-&#183;\"`) and names must be in double quotes.\n\nFor example, given the following jar:\n\n[source]\n----\nexample.jar\n |\n +-META-INF\n |  +-...\n +-BOOT-INF\n    +-classes\n    |  +...\n    +-lib\n       +-dependency1.jar\n       +-dependency2.jar\n----\n\nThe index file would look like this:\n\n[source]\n----\n- \"BOOT-INF/lib/dependency2.jar\"\n- \"BOOT-INF/lib/dependency1.jar\"\n----\n\nNOTE: Spring Boot only uses the classpath index file when the jar or war file is executed with `java -jar`.\nIt is not used when running the application from the IDE or when using Maven's `spring-boot:run` or Gradle's `bootRun`.\n\nNOTE: When enabling reproducible builds, the entries in the classpath index file are sorted alphabetically.\n\n\n\n[[appendix.executable-jar.nested-jars.layer-index]]\n== Layer Index\n\nThe layers index file can be provided in `BOOT-INF/layers.idx`.\nIt provides a list of layers and the parts of the jar that should be contained within them.\nLayers are written in the order that they should be added to the Docker/OCI image.\nLayers names are written as quoted strings prefixed with dash space (`\"-&#183;\"`) and with a colon (`\":\"`) suffix.\nLayer content is either a file or directory name written as a quoted string prefixed by space space dash space (`\"&#183;&#183;-&#183;\"`).\nA directory name ends with `/`, a file name does not.\nWhen a directory name is used it means that all files inside that directory are in the same layer.\n\nA typical example of a layers index would be:\n\n[source]\n----\n- \"dependencies\":\n  - \"BOOT-INF/lib/dependency1.jar\"\n  - \"BOOT-INF/lib/dependency2.jar\"\n- \"application\":\n  - \"BOOT-INF/classes/\"\n  - \"META-INF/\"\n----\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/property-launcher.adoc",
    "content": "[[appendix.executable-jar.property-launcher]]\n= PropertiesLauncher Features\n\njavadoc:org.springframework.boot.loader.launch.PropertiesLauncher[] has a few special features that can be enabled with external properties (System properties, environment variables, manifest entries, or `loader.properties`).\nThe following table describes these properties:\n\n|===\n| Key | Purpose\n\n| `loader.path`\n| Comma-separated Classpath, such as `lib,$\\{HOME}/app/lib`.\n  Earlier entries take precedence, like a regular `-classpath` on the `javac` command line.\n\n| `loader.home`\n| Used to resolve relative paths in `loader.path`.\n  For example, given `loader.path=lib`, then `${loader.home}/lib` is a classpath location (along with all jar files in that directory).\n  This property is also used to locate a `loader.properties` file, as in the following example `file:///opt/app` It defaults to `${user.dir}`.\n\n| `loader.args`\n| Default arguments for the main method (space separated).\n\n| `loader.main`\n| Name of main class to launch (for example, `com.app.Application`).\n\n| `loader.config.name`\n| Name of properties file (for example, `launcher`).\n  It defaults to `loader`.\n\n| `loader.config.location`\n| Path to properties file (for example, `classpath:loader.properties`).\n  It defaults to `loader.properties`.\n\n| `loader.system`\n| Boolean flag to indicate that all properties should be added to System properties.\n  It defaults to `false`.\n|===\n\nWhen specified as environment variables or manifest entries, the following names should be used:\n\n|===\n| Key | Manifest entry | Environment variable\n\n| `loader.path`\n| `Loader-Path`\n| `LOADER_PATH`\n\n| `loader.home`\n| `Loader-Home`\n| `LOADER_HOME`\n\n| `loader.args`\n| `Loader-Args`\n| `LOADER_ARGS`\n\n| `loader.main`\n| `Start-Class`\n| `LOADER_MAIN`\n\n| `loader.config.location`\n| `Loader-Config-Location`\n| `LOADER_CONFIG_LOCATION`\n\n| `loader.system`\n| `Loader-System`\n| `LOADER_SYSTEM`\n|===\n\nTIP: Build plugins automatically move the `Main-Class` attribute to `Start-Class` when the uber jar is built.\nIf you use that, specify the name of the class to launch by using the `Main-Class` attribute and leaving out `Start-Class`.\n\nThe following rules apply to working with javadoc:org.springframework.boot.loader.launch.PropertiesLauncher[]:\n\n* `loader.properties` is searched for in `loader.home`, then in the root of the classpath, and then in `classpath:/BOOT-INF/classes`.\n  The first location where a file with that name exists is used.\n* `loader.home` is the directory location of an additional properties file (overriding the default) only when `loader.config.location` is not specified.\n* `loader.path` can contain directories (which are scanned recursively for jar and zip files), archive paths, a directory within an archive that is scanned for jar files (for example, `dependencies.jar!/lib`), or wildcard patterns (for the default JVM behavior).\n  Archive paths can be relative to `loader.home` or anywhere in the file system with a `jar:file:` prefix.\n* `loader.path` (if empty) defaults to `BOOT-INF/lib` (meaning a local directory or a nested one if running from an archive).\n  Because of this, javadoc:org.springframework.boot.loader.launch.PropertiesLauncher[] behaves the same as javadoc:org.springframework.boot.loader.launch.JarLauncher[] when no additional configuration is provided.\n* `loader.path` can not be used to configure the location of `loader.properties` (the classpath used to search for the latter is the JVM classpath when javadoc:org.springframework.boot.loader.launch.PropertiesLauncher[] is launched).\n* Placeholder replacement is done from System and environment variables plus the properties file itself on all values before use.\n* The search order for properties (where it makes sense to look in more than one place) is environment variables, system properties, `loader.properties`, the exploded archive manifest, and the archive manifest.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/pages/executable-jar/restrictions.adoc",
    "content": "[[appendix.executable-jar.restrictions]]\n= Executable Jar Restrictions\n\nYou need to consider the following restrictions when working with a Spring Boot Loader packaged application:\n\n\n\n[[appendix.executable-jar-zip-entry-compression]]\n* Zip entry compression:\nThe javadoc:java.util.zip.ZipEntry[] for a nested jar must be saved by using the javadoc:java.util.zip.ZipEntry#STORED[] method.\nThis is required so that we can seek directly to individual content within the nested jar.\nThe content of the nested jar file itself can still be compressed, as can any other entry in the outer jar.\n\n\n\n[[appendix.executable-jar-system-classloader]]\n* System classLoader:\nLaunched applications should use `Thread.getContextClassLoader()` when loading classes (most libraries and frameworks do so by default).\nTrying to load nested jar classes with `ClassLoader.getSystemClassLoader()` fails.\n`java.util.Logging` always uses the system classloader.\nFor this reason, you should consider a different logging implementation.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/specification/partials/nav-specification.adoc",
    "content": "* Specifications\n\n** xref:specification:configuration-metadata/index.adoc[]\n*** xref:specification:configuration-metadata/format.adoc[]\n*** xref:specification:configuration-metadata/manual-hints.adoc[]\n*** xref:specification:configuration-metadata/annotation-processor.adoc[]\n\n** xref:specification:executable-jar/index.adoc[]\n*** xref:specification:executable-jar/nested-jars.adoc[]\n*** xref:specification:executable-jar/jarfile-class.adoc[]\n*** xref:specification:executable-jar/launching.adoc[]\n*** xref:specification:executable-jar/property-launcher.adoc[]\n*** xref:specification:executable-jar/restrictions.adoc[]\n*** xref:specification:executable-jar/alternatives.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/tutorial/pages/first-application/index.adoc",
    "content": "[[getting-started.first-application]]\n= Developing Your First Spring Boot Application\n\nThis section describes how to develop a small \"`Hello World!`\" web application that highlights some of Spring Boot's key features.\nYou can choose between Maven or Gradle as the build system.\n\n[TIP]\n====\nThe https://spring.io[spring.io] website contains many \"`Getting Started`\" https://spring.io/guides[guides] that use Spring Boot.\nIf you need to solve a specific problem, check there first.\n\nYou can shortcut the steps below by going to https://start.spring.io and choosing the \"Web\" starter from the dependencies searcher.\nDoing so generates a new project structure so that you can xref:tutorial:first-application/index.adoc#getting-started.first-application.code[start coding right away].\nCheck the https://github.com/spring-io/start.spring.io/blob/main/USING.adoc[start.spring.io user guide] for more details.\n====\n\n\n\n[[getting-started.first-application.prerequisites]]\n== Prerequisites\n\nBefore we begin, open a terminal and run the following commands to ensure that you have a valid version of Java installed:\n\n[source,shell]\n----\n$ java -version\nopenjdk version \"17.0.18\" 2026-01-20 LTS\nOpenJDK Runtime Environment (build 17.0.18+10-LTS)\nOpenJDK 64-Bit Server VM (build 17.0.18+10-LTS, mixed mode, sharing)\n----\n\nNOTE: This sample needs to be created in its own directory.\nSubsequent instructions assume that you have created a suitable directory and that it is your current directory.\n\n\n\n[[getting-started.first-application.prerequisites.maven]]\n=== Maven\n\nIf you want to use Maven, ensure that you have Maven installed:\n\n[source,shell]\n----\n$ mvn -v\nApache Maven 3.9.12 (848fbb4bf2d427b72bdb2471c22fced7ebd9a7a1)\nMaven home: /Users/developer/.sdkman/candidates/maven/current\nJava version: 17.0.18, vendor: BellSoft, runtime: /Users/developer/.sdkman/candidates/java/17.0.18-librca\n----\n\n\n\n[[getting-started.first-application.prerequisites.gradle]]\n=== Gradle\n\nIf you want to use Gradle, ensure that you have Gradle installed:\n\n[source,shell]\n----\n$ gradle --version\n\n------------------------------------------------------------\nGradle 8.14.4\n------------------------------------------------------------\n\nBuild time:    2026-01-23 16:30:23 UTC\nRevision:      ad5ff774b4b0e9a8a0cf1a14ca70d7230003c3ad\n\nKotlin:        2.0.21\nGroovy:        3.0.25\nAnt:           Apache Ant(TM) version 1.10.15 compiled on August 25 2024\nLauncher JVM:  17.0.18 (BellSoft 17.0.18+10-LTS)\nDaemon JVM:    /Users/developer/.sdkman/candidates/java/17.0.18-librca (no JDK specified, using current Java home)\nOS:            Mac OS X 26.3 aarch64\n----\n\n\n\n[[getting-started.first-application.pom]]\n== Setting Up the Project With Maven\n\nWe need to start by creating a Maven `pom.xml` file.\nThe `pom.xml` is the recipe that is used to build your project.\nOpen your favorite text editor and add the following:\n\n[source,xml,subs=\"verbatim,attributes\"]\n----\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n    <parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>{version-spring-boot}</version>\n\t</parent>\n\t<groupId>com.example</groupId>\n\t<artifactId>myproject</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\n\t<!-- Additional lines to be added here... -->\n\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-snapshot\"]\n    <!-- you don't need this if you are using a release version -->\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <url>https://repo.spring.io/snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n    <pluginRepositories>\n        <pluginRepository>\n            <id>spring-snapshots</id>\n            <url>https://repo.spring.io/snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </pluginRepository>\n    </pluginRepositories>\nendif::[]\n</project>\n----\n\nifeval::[\"{build-type}\" == \"opensource\"]\nThe preceding listing should give you a working build.\nendif::[]\n\nifeval::[\"{build-type}\" == \"commercial\"]\nYou will also have to configure your build to access the Spring Commercial repository.\nThis is usual done through a local artifact repository that mirrors the content of the Spring Commercial repository.\nAlternatively, while it is not recommended, the Spring Commercial repository can also be accessed directly.\nIn either case, see https://docs.vmware.com/en/Tanzu-Spring-Runtime/Commercial/Tanzu-Spring-Runtime/spring-enterprise-subscription.html[the Tanzu Spring Runtime documentation] for further details.\n\nWith the addition of the necessary repository configuration, the preceding listing should give you a working build.\nendif::[]\n\nYou can test it by running `mvn package` (for now, you can ignore the \"`jar will be empty - no content was marked for inclusion!`\" warning).\n\nNOTE: At this point, you could import the project into an IDE (most modern Java IDEs include built-in support for Maven).\nFor simplicity, we continue to use a plain text editor for this example.\n\n\n\n[[getting-started.first-application.gradle]]\n== Setting Up the Project With Gradle\n\nWe need to start by creating a Gradle `build.gradle` file.\nThe `build.gradle` is the build script that is used to build your project.\nOpen your favorite text editor and add the following:\n\n[source,gradle,subs=\"verbatim,attributes\"]\n----\nplugins {\n\tid 'java'\n\tid 'org.springframework.boot' version '{version-spring-boot}'\n    id 'io.spring.dependency-management' version '{version-dependency-management-plugin}'\n}\n\ngroup = 'com.example'\nversion = '0.0.1-SNAPSHOT'\n\njava {\n\ttoolchain {\n\t\tlanguageVersion = JavaLanguageVersion.of(17)\n\t}\n}\n\nrepositories {\n\tmavenCentral()\nifeval::[\"{build-and-artifact-release-type}\" == \"opensource-snapshot\"]\n    // you don't need this if you are using a release version\n\tmaven { url 'https://repo.spring.io/snapshot' }\nendif::[]\n}\n\ndependencies {\n}\n----\n\nThe preceding listing should give you a working build.\nYou can test it by running `gradle classes`.\n\nNOTE: At this point, you could import the project into an IDE (most modern Java IDEs include built-in support for Gradle).\nFor simplicity, we continue to use a plain text editor for this example.\n\n\n\n[[getting-started.first-application.dependencies]]\n== Adding Classpath Dependencies\n\nSpring Boot provides a number of starters that let you add jars to your classpath.\nStarters provide dependencies that you are likely to need when developing a specific type of application.\n\n\n\n[[getting-started.first-application.dependencies.maven]]\n=== Maven\n\nMost Spring Boot applications use the `spring-boot-starter-parent` in the `parent` section of the POM.\nThe `spring-boot-starter-parent` is a special starter that provides useful Maven defaults.\nIt also provides a xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[`dependency-management`] section so that you can omit `version` tags for \"`blessed`\" dependencies.\n\nSince we are developing a web application, we add a `spring-boot-starter-webmvc` dependency.\nBefore that, we can look at what we currently have by running the following command:\n\n[source,shell]\n----\n$ mvn dependency:tree\n\n[INFO] com.example:myproject:jar:0.0.1-SNAPSHOT\n----\n\nThe `mvn dependency:tree` command prints a tree representation of your project dependencies.\nYou can see that `spring-boot-starter-parent` provides no dependencies by itself.\nTo add the necessary dependencies, edit your `pom.xml` and add the `spring-boot-starter-webmvc` dependency immediately below the `parent` section:\n\n[source,xml]\n----\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-webmvc</artifactId>\n\t</dependency>\n</dependencies>\n----\n\nIf you run `mvn dependency:tree` again, you see that there are now a number of additional dependencies, including the Tomcat web server and Spring Boot itself.\n\n\n\n[[getting-started.first-application.dependencies.gradle]]\n=== Gradle\n\nMost Spring Boot applications use the `org.springframework.boot` Gradle plugin.\nThis plugin provides useful defaults and Gradle tasks.\nThe `io.spring.dependency-management` Gradle plugin provides xref:reference:using/build-systems.adoc#using.build-systems.dependency-management[dependency management] so that you can omit `version` tags for \"`blessed`\" dependencies.\n\nSince we are developing a web application, we add a `spring-boot-starter-webmvc` dependency.\nBefore that, we can look at what we currently have by running the following command:\n\n[source,shell]\n----\n$ gradle dependencies\n\n> Task :dependencies\n\n------------------------------------------------------------\nRoot project 'myproject'\n------------------------------------------------------------\n----\n\nThe `gradle dependencies` command prints a tree representation of your project dependencies.\nRight now, the project has no dependencies.\nTo add the necessary dependencies, edit your `build.gradle` and add the `spring-boot-starter-webmvc` dependency in the `dependencies` section:\n\n[source,gradle]\n----\ndependencies {\n\timplementation 'org.springframework.boot:spring-boot-starter-webmvc'\n}\n----\n\nIf you run `gradle dependencies` again, you see that there are now a number of additional dependencies, including the Tomcat web server and Spring Boot itself.\n\n\n\n[[getting-started.first-application.code]]\n== Writing the Code\n\nTo finish our application, we need to create a single Java file.\nBy default, Maven and Gradle compile sources from `src/main/java`, so you need to create that directory structure and then add a file named `src/main/java/com/example/MyApplication.java` to contain the following code:\n\n[chomp_package_replacement=com.example]\ninclude-code::MyApplication[]\n\nAlthough there is not much code here, quite a lot is going on.\nWe step through the important parts in the next few sections.\n\n\n\n[[getting-started.first-application.code.mvc-annotations]]\n=== The @RestController and @RequestMapping Annotations\n\nThe first annotation on our `MyApplication` class is javadoc:org.springframework.web.bind.annotation.RestController[format=annotation].\nThis is known as a _stereotype_ annotation.\nIt provides hints for people reading the code and for Spring that the class plays a specific role.\nIn this case, our class is a web javadoc:org.springframework.stereotype.Controller[format=annotation], so Spring considers it when handling incoming web requests.\n\nThe javadoc:org.springframework.web.bind.annotation.RequestMapping[format=annotation] annotation provides \"`routing`\" information.\nIt tells Spring that any HTTP request with the `/` path should be mapped to the `home` method.\nThe javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] annotation tells Spring to render the resulting string directly back to the caller.\n\nTIP: The javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] and javadoc:org.springframework.web.bind.annotation.RequestMapping[format=annotation] annotations are Spring MVC annotations (they are not specific to Spring Boot).\nSee the {url-spring-framework-docs}/web/webmvc.html[MVC section] in the Spring Reference Documentation for more details.\n\n\n\n[[getting-started.first-application.code.spring-boot-application]]\n=== The @SpringBootApplication Annotation\n\nThe second class-level annotation is javadoc:org.springframework.boot.autoconfigure.SpringBootApplication[format=annotation].\nThis annotation is known as a _meta-annotation_, it combines javadoc:org.springframework.boot.SpringBootConfiguration[format=annotation], javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] and javadoc:org.springframework.context.annotation.ComponentScan[format=annotation].\n\nOf those, the annotation we're most interested in here is javadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation].\njavadoc:org.springframework.boot.autoconfigure.EnableAutoConfiguration[format=annotation] tells Spring Boot to \"`guess`\" how you want to configure Spring, based on the jar dependencies that you have added.\nSince `spring-boot-starter-webmvc` added Tomcat and Spring MVC, the auto-configuration assumes that you are developing a web application and sets up Spring accordingly.\n\n.Starters and Auto-configuration\n****\nAuto-configuration is designed to work well with starters, but the two concepts are not directly tied.\nYou are free to pick and choose jar dependencies outside of the starters.\nSpring Boot still does its best to auto-configure your application.\n****\n\n\n\n[[getting-started.first-application.code.main-method]]\n=== The \"`main`\" Method\n\nThe final part of our application is the `main` method.\nThis is a standard method that follows the Java convention for an application entry point.\nOur main method delegates to Spring Boot's javadoc:org.springframework.boot.SpringApplication[] class by calling `run`.\njavadoc:org.springframework.boot.SpringApplication[] bootstraps our application, starting Spring, which, in turn, starts the auto-configured Tomcat web server.\nWe need to pass `MyApplication.class` as an argument to the `run` method to tell javadoc:org.springframework.boot.SpringApplication[] which is the primary Spring component.\nThe `args` array is also passed through to expose any command-line arguments.\n\n\n\n[[getting-started.first-application.run]]\n== Running the Example\n\n\n\n[[getting-started.first-application.run.maven]]\n=== Maven\n\nAt this point, your application should work.\nSince you used the `spring-boot-starter-parent` POM, you have a useful `run` goal that you can use to start the application.\nType `mvn spring-boot:run` from the root project directory to start the application.\nYou should see output similar to the following:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ mvn spring-boot:run\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::  (v{version-spring-boot})\n....... . . .\n....... . . . (log output here)\n....... . . .\n........ Started MyApplication in 0.906 seconds (process running for 6.514)\n----\n\nIf you open a web browser to `http://localhost:8080`, you should see the following output:\n\n[source]\n----\nHello World!\n----\n\nTo gracefully exit the application, press `ctrl-c`.\n\n\n\n[[getting-started.first-application.run.gradle]]\n=== Gradle\n\nAt this point, your application should work.\nSince you used the `org.springframework.boot` Gradle plugin, you have a useful `bootRun` goal that you can use to start the application.\nType `gradle bootRun` from the root project directory to start the application.\nYou should see output similar to the following:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ gradle bootRun\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::  (v{version-spring-boot})\n....... . . .\n....... . . . (log output here)\n....... . . .\n........ Started MyApplication in 0.906 seconds (process running for 6.514)\n----\n\nIf you open a web browser to `http://localhost:8080`, you should see the following output:\n\n[source]\n----\nHello World!\n----\n\nTo gracefully exit the application, press `ctrl-c`.\n\n\n\n[[getting-started.first-application.executable-jar]]\n== Creating an Executable Jar\n\nWe finish our example by creating a completely self-contained executable jar file that we could run in production.\nExecutable jars (sometimes called \"`uber jars`\" or \"`fat jars`\") are archives containing your compiled classes along with all of the jar dependencies that your code needs to run.\n\n.Executable jars and Java\n****\nJava does not provide a standard way to load nested jar files (jar files that are themselves contained within a jar).\nThis can be problematic if you are looking to distribute a self-contained application.\n\nTo solve this problem, many developers use \"`uber`\" jars.\nAn uber jar packages all the classes from all the application's dependencies into a single archive.\nThe problem with this approach is that it becomes hard to see which libraries are in your application.\nIt can also be problematic if the same filename is used (but with different content) in multiple jars.\n\nSpring Boot takes a xref:specification:executable-jar/index.adoc[different approach] and lets you actually nest jars directly.\n****\n\n\n\n[[getting-started.first-application.executable-jar.maven]]\n=== Maven\n\nTo create an executable jar, we need to add the `spring-boot-maven-plugin` to our `pom.xml`.\nTo do so, insert the following lines just below the `dependencies` section:\n\n[source,xml]\n----\n<build>\n\t<plugins>\n\t\t<plugin>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t</plugin>\n\t</plugins>\n</build>\n----\n\nNOTE: The `spring-boot-starter-parent` POM includes `<executions>` configuration to bind the `repackage` goal.\nIf you do not use the parent POM, you need to declare this configuration yourself.\nSee the xref:maven-plugin:getting-started.adoc[plugin documentation] for details.\n\nSave your `pom.xml` and run `mvn package` from the command line, as follows:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ mvn package\n\n[INFO] Scanning for projects...\n[INFO]\n[INFO] ------------------------------------------------------------------------\n[INFO] Building myproject 0.0.1-SNAPSHOT\n[INFO] ------------------------------------------------------------------------\n[INFO] .... ..\n[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myproject ---\n[INFO] Building jar: /Users/developer/example/spring-boot-example/target/myproject-0.0.1-SNAPSHOT.jar\n[INFO]\n[INFO] --- spring-boot-maven-plugin:{version-spring-boot}:repackage (default) @ myproject ---\n[INFO] ------------------------------------------------------------------------\n[INFO] BUILD SUCCESS\n[INFO] ------------------------------------------------------------------------\n----\n\nIf you look in the `target` directory, you should see `myproject-0.0.1-SNAPSHOT.jar`.\nThe file should be around 18 MB in size.\nIf you want to peek inside, you can use `jar tvf`, as follows:\n\n[source,shell]\n----\n$ jar tvf target/myproject-0.0.1-SNAPSHOT.jar\n----\n\nYou should also see a much smaller file named `myproject-0.0.1-SNAPSHOT.jar.original` in the `target` directory.\nThis is the original jar file that Maven created before it was repackaged by Spring Boot.\n\nTo run that application, use the `java -jar` command, as follows:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ java -jar target/myproject-0.0.1-SNAPSHOT.jar\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::  (v{version-spring-boot})\n....... . . .\n....... . . . (log output here)\n....... . . .\n........ Started MyApplication in 0.497 seconds (process running for 0.651)\n----\n\nAs before, to exit the application, press `ctrl-c`.\n\n\n\n[[getting-started.first-application.executable-jar.gradle]]\n=== Gradle\n\nTo create an executable jar, we need to run `gradle bootJar` from the command line, as follows:\n\n[source,shell,subs=\"verbatim,attributes\"]\n----\n$ gradle bootJar\n\nBUILD SUCCESSFUL in 639ms\n3 actionable tasks: 3 executed\n----\n\nIf you look in the `build/libs` directory, you should see `myproject-0.0.1-SNAPSHOT.jar`.\nThe file should be around 18 MB in size.\nIf you want to peek inside, you can use `jar tvf`, as follows:\n\n[source,shell]\n----\n$ jar tvf build/libs/myproject-0.0.1-SNAPSHOT.jar\n----\n\nTo run that application, use the `java -jar` command, as follows:\n\n[source,shell]\n----\n$ java -jar build/libs/myproject-0.0.1-SNAPSHOT.jar\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::  (v{version-spring-boot})\n....... . . .\n....... . . . (log output here)\n....... . . .\n........ Started MyApplication in 0.484 seconds (process running for 0.642)\n----\n\nAs before, to exit the application, press `ctrl-c`.\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/tutorial/pages/index.adoc",
    "content": "= Tutorials\n\nThis section provides tutorials to help you get started using Spring Boot."
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/modules/tutorial/partials/nav-tutorial.adoc",
    "content": "* xref:tutorial:index.adoc[]\n** xref:tutorial:first-application/index.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/antora/nav.adoc",
    "content": "include::ROOT:partial$nav-root.adoc[]\ninclude::tutorial:partial$nav-tutorial.adoc[]\ninclude::reference:partial$nav-reference.adoc[]\ninclude::how-to:partial$nav-how-to.adoc[]\ninclude::build-tool-plugin:partial$nav-build-tool-plugin.adoc[]\ninclude::cli:partial$nav-cli.adoc[]\ninclude::api:partial$nav-rest-api.adoc[]\ninclude::api:partial$nav-java-api.adoc[]\ninclude::api:partial$nav-kotlin-api.adoc[]\ninclude::specification:partial$nav-specification.adoc[]\ninclude::appendix:partial$nav-appendix.adoc[]\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/docs/dokka/dokka-overview.md",
    "content": "# All Modules\n_See also the <a href=\"../java/index.html\" target=\"_blank\">Java API documentation (Javadoc)</a>._\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/cloudfoundry/customcontextpath/MyCloudFoundryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.cloudfoundry.customcontextpath;\n\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContainerInitializer;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.apache.catalina.Host;\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.startup.Tomcat;\n\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCloudFoundryConfiguration {\n\n\t@Bean\n\tpublic TomcatServletWebServerFactory servletWebServerFactory() {\n\t\treturn new TomcatServletWebServerFactory() {\n\n\t\t\t@Override\n\t\t\tprotected void prepareContext(Host host, ServletContextInitializer[] initializers, TempDirs tempDirs) {\n\t\t\t\tsuper.prepareContext(host, initializers, tempDirs);\n\t\t\t\tStandardContext child = new StandardContext();\n\t\t\t\tchild.addLifecycleListener(new Tomcat.FixContextListener());\n\t\t\t\tchild.setPath(\"/cloudfoundryapplication\");\n\t\t\t\tServletContainerInitializer initializer = getServletContextInitializer(getContextPath());\n\t\t\t\tchild.addServletContainerInitializer(initializer, Collections.emptySet());\n\t\t\t\tchild.setCrossContext(true);\n\t\t\t\thost.addChild(child);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate ServletContainerInitializer getServletContextInitializer(String contextPath) {\n\t\treturn (classes, context) -> {\n\t\t\tServlet servlet = new GenericServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n\t\t\t\t\tServletContext context = req.getServletContext().getContext(contextPath);\n\t\t\t\t\tcontext.getRequestDispatcher(\"/cloudfoundryapplication\").forward(req, res);\n\t\t\t\t}\n\n\t\t\t};\n\t\t\tcontext.addServlet(\"cloudfoundry\", servlet).addMapping(\"/*\");\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/cloudfoundry/customcontextpath/MyReactiveCloudFoundryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.cloudfoundry.customcontextpath;\n\nimport java.util.Map;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.reactive.ContextPathCompositeHandler;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(WebFluxProperties.class)\npublic class MyReactiveCloudFoundryConfiguration {\n\n\t@Bean\n\tpublic HttpHandler httpHandler(ApplicationContext applicationContext, WebFluxProperties properties) {\n\t\tHttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t\treturn new CloudFoundryHttpHandler(properties.getBasePath(), httpHandler);\n\t}\n\n\tprivate static final class CloudFoundryHttpHandler implements HttpHandler {\n\n\t\tprivate final HttpHandler delegate;\n\n\t\tprivate final ContextPathCompositeHandler contextPathDelegate;\n\n\t\tprivate CloudFoundryHttpHandler(String basePath, HttpHandler delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.contextPathDelegate = new ContextPathCompositeHandler(Map.of(basePath, delegate));\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\t// Remove underlying context path first (e.g. Servlet container)\n\t\t\tString path = request.getPath().pathWithinApplication().value();\n\t\t\tif (path.startsWith(\"/cloudfoundryapplication\")) {\n\t\t\t\treturn this.delegate.handle(request, response);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.contextPathDelegate.handle(request, response);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/health/reactivehealthindicators/MyReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.health.reactivehealthindicators;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyReactiveHealthIndicator implements ReactiveHealthIndicator {\n\n\t@Override\n\tpublic Mono<Health> health() {\n\t\t// @formatter:off\n\t\treturn doHealthCheck().onErrorResume((exception) ->\n\t\t\tMono.just(new Health.Builder().down(exception).build()));\n\t\t// @formatter:on\n\t}\n\n\tprivate Mono<Health> doHealthCheck() {\n\t\t// perform some specific health check\n\t\treturn /**/ null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/health/writingcustomhealthindicators/MyHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.health.writingcustomhealthindicators;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyHealthIndicator implements HealthIndicator {\n\n\t@Override\n\tpublic Health health() {\n\t\tint errorCode = check();\n\t\tif (errorCode != 0) {\n\t\t\treturn Health.down().withDetail(\"Error Code\", errorCode).build();\n\t\t}\n\t\treturn Health.up().build();\n\t}\n\n\tprivate int check() {\n\t\t// perform some specific health check\n\t\treturn /**/ 0;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/implementingcustom/CustomData.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.implementingcustom;\n\nclass CustomData {\n\n\tprivate final String name;\n\n\tprivate final int counter;\n\n\tCustomData(String name, int counter) {\n\t\tthis.name = name;\n\t\tthis.counter = counter;\n\t}\n\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\tint getCounter() {\n\t\treturn this.counter;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/implementingcustom/MyEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.implementingcustom;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\n\n@Endpoint(id = \"custom\")\npublic class MyEndpoint {\n\n\t// tag::read[]\n\t@ReadOperation\n\tpublic CustomData getData() {\n\t\treturn new CustomData(\"test\", 5);\n\t}\n\t// end::read[]\n\n\t// tag::write[]\n\t@WriteOperation\n\tpublic void updateData(String name, int counter) {\n\t\t// injects \"test\" and 42\n\t}\n\t// end::write[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/info/writingcustominfocontributors/MyInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.info.writingcustominfocontributors;\n\nimport java.util.Collections;\n\nimport org.springframework.boot.actuate.info.Info;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyInfoContributor implements InfoContributor {\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tbuilder.withDetail(\"example\", Collections.singletonMap(\"key\", \"value\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/security/exposeall/MySecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.security.exposeall;\n\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySecurityConfiguration {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\thttp.securityMatcher(EndpointRequest.toAnyEndpoint());\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/endpoints/security/typical/MySecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.security.typical;\n\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySecurityConfiguration {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\thttp.securityMatcher(EndpointRequest.toAnyEndpoint());\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole(\"ENDPOINT_ADMIN\"));\n\t\thttp.httpBasic(withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/loggers/opentelemetry/OpenTelemetryAppenderInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.loggers.opentelemetry;\n\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.stereotype.Component;\n\n@Component\nclass OpenTelemetryAppenderInitializer implements InitializingBean {\n\n\tprivate final OpenTelemetry openTelemetry;\n\n\tOpenTelemetryAppenderInitializer(OpenTelemetry openTelemetry) {\n\t\tthis.openTelemetry = openTelemetry;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tOpenTelemetryAppender.install(this.openTelemetry);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/customizing/MyMetricsFilterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.customizing;\n\nimport io.micrometer.core.instrument.config.MeterFilter;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyMetricsFilterConfiguration {\n\n\t@Bean\n\tpublic MeterFilter renameRegionTagMeterFilter() {\n\t\treturn MeterFilter.renameTag(\"com.example\", \"mytag.region\", \"mytag.area\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/export/graphite/MyGraphiteConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.export.graphite;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.config.NamingConvention;\nimport io.micrometer.core.instrument.util.HierarchicalNameMapper;\nimport io.micrometer.graphite.GraphiteConfig;\nimport io.micrometer.graphite.GraphiteMeterRegistry;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyGraphiteConfiguration {\n\n\t@Bean\n\tpublic GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig config, Clock clock) {\n\t\treturn new GraphiteMeterRegistry(config, clock, this::toHierarchicalName);\n\t}\n\n\tprivate String toHierarchicalName(Meter.Id id, NamingConvention convention) {\n\t\treturn /**/ HierarchicalNameMapper.DEFAULT.toHierarchicalName(id, convention);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/export/jmx/MyJmxConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.export.jmx;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.config.NamingConvention;\nimport io.micrometer.core.instrument.util.HierarchicalNameMapper;\nimport io.micrometer.jmx.JmxConfig;\nimport io.micrometer.jmx.JmxMeterRegistry;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyJmxConfiguration {\n\n\t@Bean\n\tpublic JmxMeterRegistry jmxMeterRegistry(JmxConfig config, Clock clock) {\n\t\treturn new JmxMeterRegistry(config, clock, this::toHierarchicalName);\n\t}\n\n\tprivate String toHierarchicalName(Meter.Id id, NamingConvention convention) {\n\t\treturn /**/ HierarchicalNameMapper.DEFAULT.toHierarchicalName(id, convention);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/gettingstarted/commontags/MyMeterRegistryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.gettingstarted.commontags;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyMeterRegistryConfiguration {\n\n\t@Bean\n\tpublic MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {\n\t\treturn (registry) -> registry.config().commonTags(\"region\", \"us-east-1\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/gettingstarted/specifictype/MyMeterRegistryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.gettingstarted.specifictype;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.config.NamingConvention;\nimport io.micrometer.graphite.GraphiteMeterRegistry;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyMeterRegistryConfiguration {\n\n\t@Bean\n\tpublic MeterRegistryCustomizer<GraphiteMeterRegistry> graphiteMetricsNamingConvention() {\n\t\treturn (registry) -> registry.config().namingConvention(this::name);\n\t}\n\n\tprivate String name(String name, Meter.Type type, String baseUnit) {\n\t\treturn /**/ NamingConvention.snakeCase.name(name, type, baseUnit);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/registeringcustom/Dictionary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom;\n\nimport java.util.Collections;\nimport java.util.List;\n\nclass Dictionary {\n\n\tstatic Dictionary load() {\n\t\treturn new Dictionary();\n\t}\n\n\tList<String> getWords() {\n\t\treturn Collections.emptyList();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/registeringcustom/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final Dictionary dictionary;\n\n\tpublic MyBean(MeterRegistry registry) {\n\t\tthis.dictionary = Dictionary.load();\n\t\tregistry.gauge(\"dictionary.size\", Tags.empty(), this.dictionary.getWords().size());\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/registeringcustom/MyMeterBinderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.binder.MeterBinder;\n\nimport org.springframework.context.annotation.Bean;\n\npublic class MyMeterBinderConfiguration {\n\n\t@Bean\n\tpublic MeterBinder queueSize(Queue queue) {\n\t\treturn (registry) -> Gauge.builder(\"queueSize\", queue::size).register(registry);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/registeringcustom/Queue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom;\n\nclass Queue {\n\n\tint size() {\n\t\treturn 5;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/supported/mongodb/command/CustomCommandTagsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.command;\n\nimport com.mongodb.event.CommandEvent;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;\n\nclass CustomCommandTagsProvider implements MongoCommandTagsProvider {\n\n\t@Override\n\tpublic Iterable<Tag> commandTags(CommandEvent commandEvent) {\n\t\treturn java.util.Collections.emptyList();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/supported/mongodb/command/MyCommandTagsProviderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.command;\n\nimport io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCommandTagsProviderConfiguration {\n\n\t@Bean\n\tpublic MongoCommandTagsProvider customCommandTagsProvider() {\n\t\treturn new CustomCommandTagsProvider();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/supported/mongodb/connectionpool/CustomConnectionPoolTagsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.connectionpool;\n\nimport com.mongodb.event.ConnectionPoolCreatedEvent;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;\n\npublic class CustomConnectionPoolTagsProvider implements MongoConnectionPoolTagsProvider {\n\n\t@Override\n\tpublic Iterable<Tag> connectionPoolTags(ConnectionPoolCreatedEvent event) {\n\t\treturn java.util.Collections.emptyList();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/metrics/supported/mongodb/connectionpool/MyConnectionPoolTagsProviderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.connectionpool;\n\nimport io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyConnectionPoolTagsProviderConfiguration {\n\n\t@Bean\n\tpublic MongoConnectionPoolTagsProvider customConnectionPoolTagsProvider() {\n\t\treturn new CustomConnectionPoolTagsProvider();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/micrometertracing/baggage/CreatingBaggage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.micrometertracing.baggage;\n\nimport io.micrometer.tracing.BaggageInScope;\nimport io.micrometer.tracing.Tracer;\n\nimport org.springframework.stereotype.Component;\n\n@Component\nclass CreatingBaggage {\n\n\tprivate final Tracer tracer;\n\n\tCreatingBaggage(Tracer tracer) {\n\t\tthis.tracer = tracer;\n\t}\n\n\tvoid doSomething() {\n\t\ttry (BaggageInScope scope = this.tracer.createBaggageInScope(\"baggage1\", \"value1\")) {\n\t\t\t// Business logic\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/micrometertracing/creatingspans/CustomObservation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.micrometertracing.creatingspans;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.stereotype.Component;\n\n@Component\nclass CustomObservation {\n\n\tprivate final ObservationRegistry observationRegistry;\n\n\tCustomObservation(ObservationRegistry observationRegistry) {\n\t\tthis.observationRegistry = observationRegistry;\n\t}\n\n\tvoid someOperation() {\n\t\tObservation observation = Observation.createNotStarted(\"some-operation\", this.observationRegistry);\n\t\tobservation.lowCardinalityKeyValue(\"some-tag\", \"some-value\");\n\t\tobservation.observe(() -> {\n\t\t\t// Business logic ...\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/micrometertracing/gettingstarted/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.micrometertracing.gettingstarted;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@SpringBootApplication\npublic class MyApplication {\n\n\tprivate static final Log logger = LogFactory.getLog(MyApplication.class);\n\n\t@RequestMapping(\"/\")\n\tString home() {\n\t\tlogger.info(\"home() has been called\");\n\t\treturn \"Hello World!\";\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/MyCustomObservation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyCustomObservation {\n\n\tprivate final ObservationRegistry observationRegistry;\n\n\tpublic MyCustomObservation(ObservationRegistry observationRegistry) {\n\t\tthis.observationRegistry = observationRegistry;\n\t}\n\n\tpublic void doSomething() {\n\t\tObservation.createNotStarted(\"doSomething\", this.observationRegistry)\n\t\t\t.lowCardinalityKeyValue(\"locale\", \"en-US\")\n\t\t\t.highCardinalityKeyValue(\"userId\", \"42\")\n\t\t\t.observe(() -> {\n\t\t\t\t// Execute business logic here\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/contextpropagation/ContextPropagationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability.contextpropagation;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.support.ContextPropagatingTaskDecorator;\n\n@Configuration(proxyBeanMethods = false)\nclass ContextPropagationConfiguration {\n\n\t@Bean\n\tContextPropagatingTaskDecorator contextPropagatingTaskDecorator() {\n\t\treturn new ContextPropagatingTaskDecorator();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/opentelemetry/environmentvariables/unsupported/AutoConfiguredOpenTelemetrySdkConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability.opentelemetry.environmentvariables.unsupported;\n\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\nclass AutoConfiguredOpenTelemetrySdkConfiguration {\n\n\t@Bean\n\tOpenTelemetry autoConfiguredOpenTelemetrySdk() {\n\t\treturn AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/opentelemetry/metrics/apiandsdk/OpenTelemetryMetricsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability.opentelemetry.metrics.apiandsdk;\n\nimport java.time.Duration;\n\nimport io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;\nimport io.opentelemetry.sdk.metrics.SdkMeterProvider;\nimport io.opentelemetry.sdk.metrics.export.MetricExporter;\nimport io.opentelemetry.sdk.metrics.export.MetricReader;\nimport io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;\nimport io.opentelemetry.sdk.resources.Resource;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\nclass OpenTelemetryMetricsConfiguration {\n\n\t@Bean\n\tOtlpHttpMetricExporter metricExporter() {\n\t\tString endpoint = \"http://localhost:4318/v1/metrics\";\n\t\treturn OtlpHttpMetricExporter.builder().setEndpoint(endpoint).build();\n\t}\n\n\t@Bean\n\tPeriodicMetricReader metricReader(MetricExporter exporter) {\n\t\tDuration interval = Duration.ofMinutes(1);\n\t\treturn PeriodicMetricReader.builder(exporter).setInterval(interval).build();\n\t}\n\n\t@Bean\n\tSdkMeterProvider meterProvider(Resource resource, MetricReader metricReader) {\n\t\treturn SdkMeterProvider.builder().registerMetricReader(metricReader).setResource(resource).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/actuator/observability/preventingobservations/MyObservationPredicate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability.preventingobservations;\n\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationPredicate;\n\nimport org.springframework.stereotype.Component;\n\n@Component\nclass MyObservationPredicate implements ObservationPredicate {\n\n\t@Override\n\tpublic boolean test(String name, Context context) {\n\t\treturn !name.contains(\"denied\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/MyMessagingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my.messaging\")\npublic class MyMessagingProperties {\n\n\tprivate List<String> addresses = new ArrayList<>(Arrays.asList(\"a\", \"b\"));\n\n\tprivate ContainerType containerType = ContainerType.SIMPLE;\n\n\t// @fold:on // getters/setters ...\n\tpublic List<String> getAddresses() {\n\t\treturn this.addresses;\n\t}\n\n\tpublic void setAddresses(List<String> addresses) {\n\t\tthis.addresses = addresses;\n\t}\n\n\tpublic ContainerType getContainerType() {\n\t\treturn this.containerType;\n\t}\n\n\tpublic void setContainerType(ContainerType containerType) {\n\t\tthis.containerType = containerType;\n\t}\n\t// @fold:off\n\n\tpublic enum ContainerType {\n\n\t\tSIMPLE, DIRECT\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/MyServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my.server\")\npublic class MyServerProperties {\n\n\t/**\n\t * Name of the server.\n\t */\n\tprivate String name;\n\n\t/**\n\t * IP address to listen to.\n\t */\n\tprivate String ip = \"127.0.0.1\";\n\n\t/**\n\t * Port to listener to.\n\t */\n\tprivate int port = 9797;\n\n\t// @fold:on // getters/setters ...\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getIp() {\n\t\treturn this.ip;\n\t}\n\n\tpublic void setIp(String ip) {\n\t\tthis.ip = ip;\n\t}\n\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/nestedproperties/MyServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration.nestedproperties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my.server\")\npublic class MyServerProperties {\n\n\tprivate String name;\n\n\tprivate Host host;\n\n\t// @fold:on // getters/setters ...\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Host getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(Host host) {\n\t\tthis.host = host;\n\t}\n\t// @fold:off\n\n\tpublic static class Host {\n\n\t\tprivate String ip;\n\n\t\tprivate int port;\n\n\t\t// @fold:on // getters/setters ...\n\t\tpublic String getIp() {\n\t\t\treturn this.ip;\n\t\t}\n\n\t\tpublic void setIp(String ip) {\n\t\t\tthis.ip = ip;\n\t\t}\n\n\t\tpublic int getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tpublic void setPort(int port) {\n\t\t\tthis.port = port;\n\t\t}\n\t\t// @fold:off\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/source/Host.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration.source;\n\nimport org.springframework.boot.context.properties.ConfigurationPropertiesSource;\n\n@ConfigurationPropertiesSource\npublic class Host {\n\n\t/**\n\t * IP address to listen to.\n\t */\n\tprivate String ip = \"127.0.0.1\";\n\n\t/**\n\t * Port to listener to.\n\t */\n\tprivate int port = 9797;\n\n\t// @fold:on // getters/setters ...\n\tpublic String getIp() {\n\t\treturn this.ip;\n\t}\n\n\tpublic void setIp(String ip) {\n\t\tthis.ip = ip;\n\t}\n\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/appendix/configurationmetadata/format/property/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.format.property;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.DeprecatedConfigurationProperty;\n\n@ConfigurationProperties(\"my.app\")\npublic class MyProperties {\n\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Deprecated\n\t@DeprecatedConfigurationProperty(replacement = \"my.app.name\", since = \"1.2.0\")\n\tpublic String getTarget() {\n\t\treturn this.name;\n\t}\n\n\t@Deprecated\n\tpublic void setTarget(String target) {\n\t\tthis.name = target;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/appendix/configurationmetadata/manualhints/valuehint/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.manualhints.valuehint;\n\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\tprivate Map<String, Integer> contexts;\n\n\t// @fold:on // getters/setters ...\n\tpublic Map<String, Integer> getContexts() {\n\t\treturn this.contexts;\n\t}\n\n\tpublic void setContexts(Map<String, Integer> contexts) {\n\t\tthis.contexts = contexts;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/buildtoolplugins/otherbuildsystems/examplerepackageimplementation/MyBuildTool.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.buildtoolplugins.otherbuildsystems.examplerepackageimplementation;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCallback;\nimport org.springframework.boot.loader.tools.LibraryScope;\nimport org.springframework.boot.loader.tools.Repackager;\n\npublic class MyBuildTool {\n\n\tpublic void build() throws IOException {\n\t\tFile sourceJarFile = /**/ null;\n\t\tRepackager repackager = new Repackager(sourceJarFile);\n\t\trepackager.setBackupSource(false);\n\t\trepackager.repackage(this::getLibraries);\n\t}\n\n\tprivate void getLibraries(LibraryCallback callback) throws IOException {\n\t\t// Build system specific implementation, callback for each dependency\n\t\tfor (File nestedJar : getCompileScopeJars()) {\n\t\t\tcallback.library(new Library(nestedJar, LibraryScope.COMPILE));\n\t\t}\n\t\t// ...\n\t}\n\n\tprivate List<File> getCompileScopeJars() {\n\t\treturn /**/ null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/cassandra/connecting/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.cassandra.connecting;\n\nimport org.springframework.data.cassandra.core.CassandraTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final CassandraTemplate template;\n\n\tpublic MyBean(CassandraTemplate template) {\n\t\tthis.template = template;\n\t}\n\n\t// @fold:on // ...\n\tpublic long someMethod() {\n\t\treturn this.template.count(User.class);\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/cassandra/connecting/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.cassandra.connecting;\n\nclass User {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/CouchbaseProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories;\n\nclass CouchbaseProperties {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories;\n\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final CouchbaseTemplate template;\n\n\tpublic MyBean(CouchbaseTemplate template) {\n\t\tthis.template = template;\n\t}\n\n\t// @fold:on // ...\n\tpublic String someMethod() {\n\t\treturn this.template.getBucketName();\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories;\n\nimport org.springframework.core.convert.converter.Converter;\n\nclass MyConverter implements Converter<CouchbaseProperties, Boolean> {\n\n\t@Override\n\tpublic Boolean convert(CouchbaseProperties value) {\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories;\n\nimport org.assertj.core.util.Arrays;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.config.BeanNames;\nimport org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCouchbaseConfiguration {\n\n\t@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)\n\tpublic CouchbaseCustomConversions myCustomConversions() {\n\t\treturn new CouchbaseCustomConversions(Arrays.asList(new MyConverter()));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/elasticsearch/connectingusingspringdata/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata;\n\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final ElasticsearchTemplate template;\n\n\tpublic MyBean(ElasticsearchTemplate template) {\n\t\tthis.template = template;\n\t}\n\n\t// @fold:on // ...\n\tpublic boolean someMethod(String id) {\n\t\treturn this.template.exists(id, User.class);\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/elasticsearch/connectingusingspringdata/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata;\n\nclass User {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/ldap/repositories/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.ldap.repositories;\n\nimport java.util.List;\n\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final LdapTemplate template;\n\n\tpublic MyBean(LdapTemplate template) {\n\t\tthis.template = template;\n\t}\n\n\t// @fold:on // ...\n\tpublic List<User> someMethod() {\n\t\treturn this.template.findAll(User.class);\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/ldap/repositories/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.ldap.repositories;\n\nclass User {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/mongodb/connecting/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.connecting;\n\nimport com.mongodb.client.MongoCollection;\nimport com.mongodb.client.MongoDatabase;\nimport org.bson.Document;\n\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final MongoDatabaseFactory mongo;\n\n\tpublic MyBean(MongoDatabaseFactory mongo) {\n\t\tthis.mongo = mongo;\n\t}\n\n\t// @fold:on // ...\n\tpublic MongoCollection<Document> someMethod() {\n\t\tMongoDatabase db = this.mongo.getMongoDatabase();\n\t\treturn db.getCollection(\"users\");\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/mongodb/repositories/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.repositories;\n\npublic class City {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/mongodb/repositories/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.repositories;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tPage<City> findAll(Pageable pageable);\n\n\tCity findByNameAndStateAllIgnoringCase(String name, String state);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/mongodb/template/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.template;\n\nimport com.mongodb.client.MongoCollection;\nimport org.bson.Document;\n\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final MongoTemplate mongoTemplate;\n\n\tpublic MyBean(MongoTemplate mongoTemplate) {\n\t\tthis.mongoTemplate = mongoTemplate;\n\t}\n\n\t// @fold:on // ...\n\tpublic MongoCollection<Document> someMethod() {\n\t\treturn this.mongoTemplate.getCollection(\"users\");\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/neo4j/connecting/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.connecting;\n\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Session;\nimport org.neo4j.driver.Values;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final Driver driver;\n\n\tpublic MyBean(Driver driver) {\n\t\tthis.driver = driver;\n\t}\n\n\t// @fold:on // ...\n\tpublic String someMethod(String message) {\n\t\ttry (Session session = this.driver.session()) {\n\t\t\treturn session.executeWrite(\n\t\t\t\t\t(transaction) -> transaction\n\t\t\t\t\t\t.run(\"CREATE (a:Greeting) SET a.message = $message RETURN a.message + ', from node ' + id(a)\",\n\t\t\t\t\t\t\t\tValues.parameters(\"message\", message))\n\t\t\t\t\t\t.single()\n\t\t\t\t\t\t.get(0)\n\t\t\t\t\t\t.asString());\n\t\t}\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/neo4j/repositories/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.repositories;\n\npublic class City {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/neo4j/repositories/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.repositories;\n\nimport java.util.Optional;\n\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\n\npublic interface CityRepository extends Neo4jRepository<City, Long> {\n\n\tOptional<City> findOneByNameAndState(String name, String state);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/neo4j/repositories/MyNeo4jConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.repositories;\n\nimport org.neo4j.driver.Driver;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;\nimport org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyNeo4jConfiguration {\n\n\t@Bean\n\tpublic ReactiveNeo4jTransactionManager reactiveTransactionManager(Driver driver,\n\t\t\tReactiveDatabaseSelectionProvider databaseNameProvider) {\n\t\treturn new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/redis/connecting/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.redis.connecting;\n\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final StringRedisTemplate template;\n\n\tpublic MyBean(StringRedisTemplate template) {\n\t\tthis.template = template;\n\t}\n\n\t// @fold:on // ...\n\tpublic Boolean someMethod() {\n\t\treturn this.template.hasKey(\"spring\");\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/h2webconsole/springsecurity/DevProfileSecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.h2webconsole.springsecurity;\n\nimport org.springframework.boot.security.autoconfigure.web.servlet.PathRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Profile(\"dev\")\n@Configuration(proxyBeanMethods = false)\npublic class DevProfileSecurityConfiguration {\n\n\t@Bean\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tSecurityFilterChain h2ConsoleSecurityFilterChain(HttpSecurity http) {\n\t\thttp.securityMatcher(PathRequest.toH2Console());\n\t\thttp.authorizeHttpRequests(yourCustomAuthorization());\n\t\thttp.csrf(CsrfConfigurer::disable);\n\t\thttp.headers((headers) -> headers.frameOptions(FrameOptionsConfig::sameOrigin));\n\t\treturn http.build();\n\t}\n\n\t// tag::customizer[]\n\t<T> Customizer<T> yourCustomAuthorization() {\n\t\treturn (t) -> {\n\t\t};\n\t}\n\t// end::customizer[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jdbcclient/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jdbcclient;\n\nimport org.springframework.jdbc.core.simple.JdbcClient;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final JdbcClient jdbcClient;\n\n\tpublic MyBean(JdbcClient jdbcClient) {\n\t\tthis.jdbcClient = jdbcClient;\n\t}\n\n\tpublic void doSomething() {\n\t\t/* @chomp:line this.jdbcClient ... */ this.jdbcClient.sql(\"delete from customer\").update();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jdbctemplate/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jdbctemplate;\n\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final JdbcTemplate jdbcTemplate;\n\n\tpublic MyBean(JdbcTemplate jdbcTemplate) {\n\t\tthis.jdbcTemplate = jdbcTemplate;\n\t}\n\n\tpublic void doSomething() {\n\t\t/* @chomp:line this.jdbcTemplate ... */ this.jdbcTemplate.execute(\"delete from customer\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jooq/dslcontext/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jooq.dslcontext;\n\nimport java.util.GregorianCalendar;\nimport java.util.List;\n\nimport org.jooq.DSLContext;\n\nimport org.springframework.stereotype.Component;\n\nimport static org.springframework.boot.docs.data.sql.jooq.dslcontext.Tables.AUTHOR;\n\n@Component\npublic class MyBean {\n\n\tprivate final DSLContext create;\n\n\tpublic MyBean(DSLContext dslContext) {\n\t\tthis.create = dslContext;\n\t}\n\n\t// tag::method[]\n\tpublic List<GregorianCalendar> authorsBornAfter1980() {\n\t\treturn this.create.selectFrom(AUTHOR)\n\t\t\t.where(AUTHOR.DATE_OF_BIRTH.greaterThan(new GregorianCalendar(1980, 0, 1)))\n\t\t\t.fetch(AUTHOR.DATE_OF_BIRTH);\n\t} // end::method[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jooq/dslcontext/Tables.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jooq.dslcontext;\n\nimport java.util.GregorianCalendar;\n\nimport org.jooq.Name;\nimport org.jooq.Table;\nimport org.jooq.TableField;\nimport org.jooq.impl.TableImpl;\nimport org.jooq.impl.TableRecordImpl;\n\nabstract class Tables {\n\n\tstatic final TAuthor AUTHOR = null;\n\n\tabstract class TAuthor extends TableImpl<TAuthorRecord> {\n\n\t\tTAuthor(Name name) {\n\t\t\tsuper(name);\n\t\t}\n\n\t\tpublic final TableField<TAuthorRecord, GregorianCalendar> DATE_OF_BIRTH = null;\n\n\t}\n\n\tabstract class TAuthorRecord extends TableRecordImpl<TAuthorRecord> {\n\n\t\tTAuthorRecord(Table<TAuthorRecord> table) {\n\t\t\tsuper(table);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jpaandspringdata/entityclasses/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n@Entity\npublic class City implements Serializable {\n\n\t@Id\n\t@GeneratedValue\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\tprivate String name;\n\n\t@Column(nullable = false)\n\tprivate String state;\n\n\t// ... additional members, often include @OneToMany mappings\n\n\tprotected City() {\n\t\t// no-args constructor required by JPA spec\n\t\t// this one is protected since it should not be used directly\n\t}\n\n\tpublic City(String name, String state) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\t// ... etc\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jpaandspringdata/entityclasses/Country.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport org.hibernate.envers.Audited;\n\n@Entity\npublic class Country implements Serializable {\n\n\t@Id\n\t@GeneratedValue\n\tprivate Long id;\n\n\t@Audited\n\t@Column(nullable = false)\n\tprivate String name;\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jpaandspringdata/enversrepositories/CountryRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.enversrepositories;\n\nimport org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\nimport org.springframework.data.repository.history.RevisionRepository;\n\npublic interface CountryRepository extends RevisionRepository<Country, Long, Integer>, Repository<Country, Long> {\n\n\tPage<Country> findAll(Pageable pageable);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/jpaandspringdata/repositories/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.repositories;\n\nimport org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tPage<City> findAll(Pageable pageable);\n\n\tCity findByNameAndStateAllIgnoringCase(String name, String state);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/r2dbc/MyPostgresR2dbcConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider;\n\nimport org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyPostgresR2dbcConfiguration {\n\n\t@Bean\n\tpublic ConnectionFactoryOptionsBuilderCustomizer postgresCustomizer() {\n\t\tMap<String, String> options = new HashMap<>();\n\t\toptions.put(\"lock_timeout\", \"30s\");\n\t\toptions.put(\"statement_timeout\", \"60s\");\n\t\treturn (builder) -> builder.option(PostgresqlConnectionFactoryProvider.OPTIONS, options);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/r2dbc/MyR2dbcConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyR2dbcConfiguration {\n\n\t@Bean\n\tpublic ConnectionFactoryOptionsBuilderCustomizer connectionFactoryPortCustomizer() {\n\t\treturn (builder) -> builder.option(ConnectionFactoryOptions.PORT, 5432);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/r2dbc/repositories/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc.repositories;\n\npublic class City {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/r2dbc/repositories/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc.repositories;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tMono<City> findByNameAndStateAllIgnoringCase(String name, String state);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/sql/r2dbc/usingdatabaseclient/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc.usingdatabaseclient;\n\nimport java.util.Map;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.r2dbc.core.DatabaseClient;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final DatabaseClient databaseClient;\n\n\tpublic MyBean(DatabaseClient databaseClient) {\n\t\tthis.databaseClient = databaseClient;\n\t}\n\n\t// @fold:on // ...\n\tpublic Flux<Map<String, Object>> someMethod() {\n\t\treturn this.databaseClient.sql(\"select * from user\").fetch().all();\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/beanconditions/MyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.beanconditions;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n@AutoConfiguration\npublic final class MyAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSomeService someService() {\n\t\treturn new SomeService();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/beanconditions/SomeService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.beanconditions;\n\npublic class SomeService {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/classconditions/MyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.classconditions;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@AutoConfiguration\n// Some conditions ...\npublic final class MyAutoConfiguration {\n\n\t// Auto-configured beans ...\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(SomeService.class)\n\tstatic class SomeServiceConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSomeService someService() {\n\t\t\treturn new SomeService();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/classconditions/SomeService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.classconditions;\n\nclass SomeService {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/customstarter/configurationkeys/AcmeProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.customstarter.configurationkeys;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"acme\")\npublic class AcmeProperties {\n\n\t/**\n\t * Whether to check the location of acme resources.\n\t */\n\tprivate boolean checkLocation = true;\n\n\t/**\n\t * Timeout for establishing a connection to the acme server.\n\t */\n\tprivate Duration loginTimeout = Duration.ofSeconds(3);\n\n\t// @fold:on // getters/setters ...\n\tpublic boolean isCheckLocation() {\n\t\treturn this.checkLocation;\n\t}\n\n\tpublic void setCheckLocation(boolean checkLocation) {\n\t\tthis.checkLocation = checkLocation;\n\t}\n\n\tpublic Duration getLoginTimeout() {\n\t\treturn this.loginTimeout;\n\t}\n\n\tpublic void setLoginTimeout(Duration loginTimeout) {\n\t\tthis.loginTimeout = loginTimeout;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyConditionEvaluationReportingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nclass MyConditionEvaluationReportingTests {\n\n\t@Test\n\tvoid autoConfigTest() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> {\n\t\t\t\t// Test something...\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing;\n\npublic class MyService {\n\n\tprivate final String name;\n\n\tpublic MyService(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyServiceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.docs.features.developingautoconfiguration.testing.MyServiceAutoConfiguration.UserProperties;\nimport org.springframework.context.annotation.Bean;\n\n@AutoConfiguration\n@ConditionalOnClass(MyService.class)\n@EnableConfigurationProperties(UserProperties.class)\npublic final class MyServiceAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMyService userService(UserProperties properties) {\n\t\treturn new MyService(properties.getName());\n\t}\n\n\t@ConfigurationProperties(\"user\")\n\tpublic static class UserProperties {\n\n\t\tprivate String name = \"test\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyServiceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass MyServiceAutoConfigurationTests {\n\n\t// tag::runner[]\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration.class));\n\n\t// end::runner[]\n\n\t// tag::test-env[]\n\t@Test\n\tvoid serviceNameCanBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"user.name=test123\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MyService.class);\n\t\t\tassertThat(context.getBean(MyService.class).getName()).isEqualTo(\"test123\");\n\t\t});\n\t}\n\t// end::test-env[]\n\n\t// tag::test-classloader[]\n\t@Test\n\tvoid serviceIsIgnoredIfLibraryIsNotPresent() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(MyService.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"myService\"));\n\t}\n\t// end::test-classloader[]\n\n\t// tag::test-user-config[]\n\t@Test\n\tvoid defaultServiceBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MyService.class);\n\t\t\tassertThat(context).getBean(\"myCustomService\").isSameAs(context.getBean(MyService.class));\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserConfiguration {\n\n\t\t@Bean\n\t\tMyService myCustomService() {\n\t\t\treturn new MyService(\"mine\");\n\t\t}\n\n\t}\n\t// end::test-user-config[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/devtools/MyContainersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.devtools;\n\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.boot.devtools.restart.RestartScope;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.context.annotation.Bean;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyContainersConfiguration {\n\n\t@Bean\n\t@RestartScope\n\t@ServiceConnection\n\tpublic MongoDBContainer mongoDbContainer() {\n\t\treturn new MongoDBContainer(\"mongo:5.0\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/dynamicproperties/MyContainersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.dynamicproperties;\n\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.DynamicPropertyRegistrar;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyContainersConfiguration {\n\n\t@Bean\n\tpublic MongoDBContainer mongoDbContainer() {\n\t\treturn new MongoDBContainer(\"mongo:5.0\");\n\t}\n\n\t@Bean\n\tpublic DynamicPropertyRegistrar mongoDbProperties(MongoDBContainer container) {\n\t\treturn (properties) -> {\n\t\t\tproperties.add(\"spring.mongodb.host\", container::getHost);\n\t\t\tproperties.add(\"spring.mongodb.port\", container::getFirstMappedPort);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/importingcontainerdeclarations/MyContainers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.importingcontainerdeclarations;\n\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.mongodb.MongoDBContainer;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\npublic interface MyContainers {\n\n\t@Container\n\t@ServiceConnection\n\tMongoDBContainer mongoContainer = new MongoDBContainer(\"mongo:5.0\");\n\n\t@Container\n\t@ServiceConnection\n\tNeo4jContainer neo4jContainer = new Neo4jContainer(\"neo4j:5\");\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/importingcontainerdeclarations/MyContainersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.importingcontainerdeclarations;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\n\n@TestConfiguration(proxyBeanMethods = false)\n@ImportTestcontainers(MyContainers.class)\npublic class MyContainersConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/launch/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.launch;\n\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/launch/TestMyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.launch;\n\nimport org.springframework.boot.SpringApplication;\n\npublic class TestMyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.from(MyApplication::main).run(args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/test/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.test;\n\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/test/MyContainersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.test;\n\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.context.annotation.Bean;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyContainersConfiguration {\n\n\t@Bean\n\t@ServiceConnection\n\tpublic Neo4jContainer neo4jContainer() {\n\t\treturn new Neo4jContainer(\"neo4j:5\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/test/TestMyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.test;\n\nimport org.springframework.boot.SpringApplication;\n\npublic class TestMyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.from(MyApplication::main).with(MyContainersConfiguration.class).run(args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@Value(\"${name}\")\n\tprivate String name;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding;\n\nimport java.net.InetAddress;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\n\n@ConfigurationProperties(\"my.service\")\npublic class MyProperties {\n\n\t// @fold:on // fields...\n\tprivate final boolean enabled;\n\n\tprivate final InetAddress remoteAddress;\n\n\tprivate final Security security;\n\n\t// @fold:off\n\n\tpublic MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {\n\t\tthis.enabled = enabled;\n\t\tthis.remoteAddress = remoteAddress;\n\t\tthis.security = security;\n\t}\n\n\t// @fold:on // getters...\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic InetAddress getRemoteAddress() {\n\t\treturn this.remoteAddress;\n\t}\n\n\tpublic Security getSecurity() {\n\t\treturn this.security;\n\t}\n\t// @fold:off\n\n\tpublic static class Security {\n\n\t\t// @fold:on // fields...\n\t\tprivate final String username;\n\n\t\tprivate final String password;\n\n\t\tprivate final List<String> roles;\n\n\t\t// @fold:off\n\n\t\tpublic Security(String username, String password, @DefaultValue(\"USER\") List<String> roles) {\n\t\t\tthis.username = username;\n\t\t\tthis.password = password;\n\t\t\tthis.roles = roles;\n\t\t}\n\n\t\t// @fold:on // getters...\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic List<String> getRoles() {\n\t\t\treturn this.roles;\n\t\t}\n\t\t// @fold:off\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/defaultvalues/nonnull/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding.defaultvalues.nonnull;\n\nimport java.net.InetAddress;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\n\n@ConfigurationProperties(\"my.service\")\npublic class MyProperties {\n\n\tprivate final boolean enabled;\n\n\tprivate final InetAddress remoteAddress;\n\n\tprivate final Security security;\n\n\t// tag::code[]\n\tpublic MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {\n\t\tthis.enabled = enabled;\n\t\tthis.remoteAddress = remoteAddress;\n\t\tthis.security = security;\n\t}\n\t// end::code[]\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic InetAddress getRemoteAddress() {\n\t\treturn this.remoteAddress;\n\t}\n\n\tpublic Security getSecurity() {\n\t\treturn this.security;\n\t}\n\n\tpublic static class Security {\n\n\t\tprivate final String username;\n\n\t\tprivate final String password;\n\n\t\tprivate final List<String> roles;\n\n\t\tpublic Security(String username, String password, @DefaultValue(\"USER\") List<String> roles) {\n\t\t\tthis.username = username;\n\t\t\tthis.password = password;\n\t\t\tthis.roles = roles;\n\t\t}\n\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic List<String> getRoles() {\n\t\t\treturn this.roles;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/primaryconstructor/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding.primaryconstructor;\n\nclass MyBean {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/primaryconstructor/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding.primaryconstructor;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\t// @fold:on // fields...\n\tfinal MyBean myBean;\n\n\tprivate String name;\n\n\t// @fold:off\n\n\t@Autowired\n\tpublic MyProperties(MyBean myBean) {\n\t\tthis.myBean = myBean;\n\t}\n\n\t// @fold:on // getters / setters...\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/datasizes/constructorbinding/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.datasizes.constructorbinding;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\nimport org.springframework.boot.convert.DataSizeUnit;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\t// @fold:on // fields...\n\tprivate final DataSize bufferSize;\n\n\tprivate final DataSize sizeThreshold;\n\n\t// @fold:off\n\tpublic MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue(\"2MB\") DataSize bufferSize,\n\t\t\t@DefaultValue(\"512B\") DataSize sizeThreshold) {\n\t\tthis.bufferSize = bufferSize;\n\t\tthis.sizeThreshold = sizeThreshold;\n\t}\n\n\t// @fold:on // getters...\n\tpublic DataSize getBufferSize() {\n\t\treturn this.bufferSize;\n\t}\n\n\tpublic DataSize getSizeThreshold() {\n\t\treturn this.sizeThreshold;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/datasizes/javabeanbinding/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.datasizes.javabeanbinding;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DataSizeUnit;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\t@DataSizeUnit(DataUnit.MEGABYTES)\n\tprivate DataSize bufferSize = DataSize.ofMegabytes(2);\n\n\tprivate DataSize sizeThreshold = DataSize.ofBytes(512);\n\n\t// @fold:on // getters/setters...\n\tpublic DataSize getBufferSize() {\n\t\treturn this.bufferSize;\n\t}\n\n\tpublic void setBufferSize(DataSize bufferSize) {\n\t\tthis.bufferSize = bufferSize;\n\t}\n\n\tpublic DataSize getSizeThreshold() {\n\t\treturn this.sizeThreshold;\n\t}\n\n\tpublic void setSizeThreshold(DataSize sizeThreshold) {\n\t\tthis.sizeThreshold = sizeThreshold;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/durations/constructorbinding/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.durations.constructorbinding;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\nimport org.springframework.boot.convert.DurationUnit;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\t// @fold:on // fields...\n\tprivate final Duration sessionTimeout;\n\n\tprivate final Duration readTimeout;\n\n\t// @fold:off\n\tpublic MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue(\"30s\") Duration sessionTimeout,\n\t\t\t@DefaultValue(\"1000ms\") Duration readTimeout) {\n\t\tthis.sessionTimeout = sessionTimeout;\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\t// @fold:on // getters...\n\tpublic Duration getSessionTimeout() {\n\t\treturn this.sessionTimeout;\n\t}\n\n\tpublic Duration getReadTimeout() {\n\t\treturn this.readTimeout;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/durations/javabeanbinding/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.durations.javabeanbinding;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate Duration sessionTimeout = Duration.ofSeconds(30);\n\n\tprivate Duration readTimeout = Duration.ofMillis(1000);\n\n\t// @fold:on // getters / setters...\n\tpublic Duration getSessionTimeout() {\n\t\treturn this.sessionTimeout;\n\t}\n\n\tpublic void setSessionTimeout(Duration sessionTimeout) {\n\t\tthis.sessionTimeout = sessionTimeout;\n\t}\n\n\tpublic Duration getReadTimeout() {\n\t\treturn this.readTimeout;\n\t}\n\n\tpublic void setReadTimeout(Duration readTimeout) {\n\t\tthis.readTimeout = readTimeout;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/enablingannotatedtypes/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.enablingannotatedtypes;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\n\n@SpringBootApplication\n@ConfigurationPropertiesScan({ \"com.example.app\", \"com.example.another\" })\npublic class MyApplication {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/enablingannotatedtypes/MyConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.enablingannotatedtypes;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(SomeProperties.class)\npublic class MyConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/enablingannotatedtypes/SomeProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.enablingannotatedtypes;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"some.properties\")\npublic class SomeProperties {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/javabeanbinding/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.javabeanbinding;\n\nimport java.net.InetAddress;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my.service\")\npublic class MyProperties {\n\n\tprivate boolean enabled;\n\n\tprivate InetAddress remoteAddress;\n\n\tprivate final Security security = new Security();\n\n\t// @fold:on // getters / setters...\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic InetAddress getRemoteAddress() {\n\t\treturn this.remoteAddress;\n\t}\n\n\tpublic void setRemoteAddress(InetAddress remoteAddress) {\n\t\tthis.remoteAddress = remoteAddress;\n\t}\n\n\tpublic Security getSecurity() {\n\t\treturn this.security;\n\t}\n\t// @fold:off\n\n\tpublic static class Security {\n\n\t\tprivate String username;\n\n\t\tprivate String password;\n\n\t\tprivate List<String> roles = new ArrayList<>(Collections.singleton(\"USER\"));\n\n\t\t// @fold:on // getters / setters...\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t\tpublic List<String> getRoles() {\n\t\t\treturn this.roles;\n\t\t}\n\n\t\tpublic void setRoles(List<String> roles) {\n\t\t\tthis.roles = roles;\n\t\t}\n\t\t// @fold:off\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/list/MyPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.list;\n\nclass MyPojo {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/list/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.list;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\tprivate final List<MyPojo> list = new ArrayList<>();\n\n\tpublic List<MyPojo> getList() {\n\t\treturn this.list;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/map/MyPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.map;\n\nclass MyPojo {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/map/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.map;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my\")\npublic class MyProperties {\n\n\tprivate final Map<String, MyPojo> map = new LinkedHashMap<>();\n\n\tpublic Map<String, MyPojo> getMap() {\n\t\treturn this.map;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/relaxedbinding/MyPersonProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.relaxedbinding;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my.main-project.person\")\npublic class MyPersonProperties {\n\n\tprivate String firstName;\n\n\tpublic String getFirstName() {\n\t\treturn this.firstName;\n\t}\n\n\tpublic void setFirstName(String firstName) {\n\t\tthis.firstName = firstName;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/relaxedbinding/mapsfromenvironmentvariables/MyMapsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.relaxedbinding.mapsfromenvironmentvariables;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"my.props\")\npublic class MyMapsProperties {\n\n\tprivate final Map<String, String> values = new HashMap<>();\n\n\tpublic Map<String, String> getValues() {\n\t\treturn this.values;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/thirdpartyconfiguration/AnotherComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.thirdpartyconfiguration;\n\nclass AnotherComponent {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/thirdpartyconfiguration/ThirdPartyConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.thirdpartyconfiguration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class ThirdPartyConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"another\")\n\tpublic AnotherComponent anotherComponent() {\n\t\treturn new AnotherComponent();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/usingannotatedtypes/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.usingannotatedtypes;\n\nclass MyProperties {\n\n\tObject getRemoteAddress() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/usingannotatedtypes/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.usingannotatedtypes;\n\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class MyService {\n\n\tprivate final MyProperties properties;\n\n\tpublic MyService(MyProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\tpublic void openConnection() {\n\t\tServer server = new Server(this.properties.getRemoteAddress());\n\t\tserver.start();\n\t\t// ...\n\t}\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/usingannotatedtypes/Server.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.usingannotatedtypes;\n\nclass Server {\n\n\tServer(Object remoteAddress) {\n\t}\n\n\tvoid start() {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/validation/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.validation;\n\nimport java.net.InetAddress;\n\nimport jakarta.validation.constraints.NotNull;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.validation.annotation.Validated;\n\n@ConfigurationProperties(\"my.service\")\n@Validated\npublic class MyProperties {\n\n\t@NotNull\n\tprivate InetAddress remoteAddress;\n\n\t// @fold:on // getters/setters...\n\tpublic InetAddress getRemoteAddress() {\n\t\treturn this.remoteAddress;\n\t}\n\n\tpublic void setRemoteAddress(InetAddress remoteAddress) {\n\t\tthis.remoteAddress = remoteAddress;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/validation/nested/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.validation.nested;\n\nimport java.net.InetAddress;\n\nimport jakarta.validation.Valid;\nimport jakarta.validation.constraints.NotEmpty;\nimport jakarta.validation.constraints.NotNull;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.validation.annotation.Validated;\n\n@ConfigurationProperties(\"my.service\")\n@Validated\npublic class MyProperties {\n\n\t@NotNull\n\tprivate InetAddress remoteAddress;\n\n\t@Valid\n\tprivate final Security security = new Security();\n\n\t// @fold:on // getters/setters...\n\tpublic InetAddress getRemoteAddress() {\n\t\treturn this.remoteAddress;\n\t}\n\n\tpublic void setRemoteAddress(InetAddress remoteAddress) {\n\t\tthis.remoteAddress = remoteAddress;\n\t}\n\n\tpublic Security getSecurity() {\n\t\treturn this.security;\n\t}\n\t// @fold:off\n\n\tpublic static class Security {\n\n\t\t@NotEmpty\n\t\tprivate String username;\n\n\t\t// @fold:on // getters/setters...\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(String username) {\n\t\t\tthis.username = username;\n\t\t}\n\t\t// @fold:off\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/MyJacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.ValueDeserializer;\nimport tools.jackson.databind.ValueSerializer;\n\nimport org.springframework.boot.jackson.JacksonComponent;\n\n@JacksonComponent\npublic class MyJacksonComponent {\n\n\tpublic static class Serializer extends ValueSerializer<MyObject> {\n\n\t\t@Override\n\t\tpublic void serialize(MyObject value, JsonGenerator jgen, SerializationContext context) {\n\t\t\tjgen.writeStartObject();\n\t\t\tjgen.writeStringProperty(\"name\", value.getName());\n\t\t\tjgen.writeNumberProperty(\"age\", value.getAge());\n\t\t\tjgen.writeEndObject();\n\t\t}\n\n\t}\n\n\tpublic static class Deserializer extends ValueDeserializer<MyObject> {\n\n\t\t@Override\n\t\tpublic MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) {\n\t\t\tJsonNode tree = jsonParser.readValueAsTree();\n\t\t\tString name = tree.get(\"name\").stringValue();\n\t\t\tint age = tree.get(\"age\").intValue();\n\t\t\treturn new MyObject(name, age);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/MyObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers;\n\nclass MyObject {\n\n\tMyObject(String name, int age) {\n\t}\n\n\tString getName() {\n\t\treturn null;\n\t}\n\n\tInteger getAge() {\n\t\treturn null;\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/object/MyJacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.object;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.SerializationContext;\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.jackson.ObjectValueDeserializer;\nimport org.springframework.boot.jackson.ObjectValueSerializer;\n\n@JacksonComponent\npublic class MyJacksonComponent {\n\n\tpublic static class Serializer extends ObjectValueSerializer<MyObject> {\n\n\t\t@Override\n\t\tprotected void serializeObject(MyObject value, JsonGenerator jgen, SerializationContext context) {\n\t\t\tjgen.writeStringProperty(\"name\", value.getName());\n\t\t\tjgen.writeNumberProperty(\"age\", value.getAge());\n\t\t}\n\n\t}\n\n\tpublic static class Deserializer extends ObjectValueDeserializer<MyObject> {\n\n\t\t@Override\n\t\tprotected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree) {\n\t\t\tString name = nullSafeValue(tree.get(\"name\"), String.class);\n\t\t\tint age = nullSafeValue(tree.get(\"age\"), Integer.class);\n\t\t\treturn new MyObject(name, age);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/object/MyObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.object;\n\nclass MyObject {\n\n\tMyObject(String name, int age) {\n\t}\n\n\tString getName() {\n\t\treturn null;\n\t}\n\n\tInteger getAge() {\n\t\treturn null;\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/logexample/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.logexample;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Sample application used to collect logs for the reference doc.\n *\n * @author Stephane Nicoll\n */\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/logging/structured/otherformats/MyCustomFormat.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.logging.structured.otherformats;\n\nimport ch.qos.logback.classic.spi.ILoggingEvent;\n\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\n\nclass MyCustomFormat implements StructuredLogFormatter<ILoggingEvent> {\n\n\t@Override\n\tpublic String format(ILoggingEvent event) {\n\t\treturn \"time=\" + event.getInstant() + \" level=\" + event.getLevel() + \" message=\" + event.getMessage() + \"\\n\";\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/profiles/ProductionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.profiles;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\n\n@Configuration(proxyBeanMethods = false)\n@Profile(\"production\")\npublic class ProductionConfiguration {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/applicationarguments/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationarguments;\n\nimport java.util.List;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tpublic MyBean(ApplicationArguments args) {\n\t\tboolean debug = args.containsOption(\"debug\");\n\t\tList<String> files = args.getNonOptionArgs();\n\t\tif (debug) {\n\t\t\tSystem.out.println(files);\n\t\t}\n\t\t// if run with \"--debug logfile.txt\" prints [\"logfile.txt\"]\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/applicationavailability/managing/CacheCompletelyBrokenException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationavailability.managing;\n\nclass CacheCompletelyBrokenException extends RuntimeException {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/applicationavailability/managing/MyLocalCacheVerifier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationavailability.managing;\n\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.LivenessState;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyLocalCacheVerifier {\n\n\tprivate final ApplicationEventPublisher eventPublisher;\n\n\tpublic MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {\n\t\tthis.eventPublisher = eventPublisher;\n\t}\n\n\tpublic void checkLocalCache() {\n\t\ttry {\n\t\t\t// ...\n\t\t}\n\t\tcatch (CacheCompletelyBrokenException ex) {\n\t\t\tAvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/applicationavailability/managing/MyReadinessStateExporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationavailability.managing;\n\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.context.event.EventListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyReadinessStateExporter {\n\n\t@EventListener\n\tpublic void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {\n\t\tswitch (event.getState()) {\n\t\t\tcase ACCEPTING_TRAFFIC -> {\n\t\t\t\t// create file /tmp/healthy\n\t\t\t}\n\t\t\tcase REFUSING_TRAFFIC -> {\n\t\t\t\t// remove file /tmp/healthy\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/applicationexit/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationexit;\n\nimport org.springframework.boot.ExitCodeGenerator;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\t@Bean\n\tpublic ExitCodeGenerator exitCodeGenerator() {\n\t\treturn () -> 42;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.exit(SpringApplication.exit(SpringApplication.run(MyApplication.class, args)));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/commandlinerunner/MyCommandLineRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.commandlinerunner;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyCommandLineRunner implements CommandLineRunner {\n\n\t@Override\n\tpublic void run(String... args) {\n\t\t// Do something...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/customizingspringapplication/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.customizingspringapplication;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication(MyApplication.class);\n\t\tapplication.setBannerMode(Banner.Mode.OFF);\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/fluentbuilderapi/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.fluentbuilderapi;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\n\npublic class MyApplication {\n\n\tpublic void hierarchyWithDisabledBanner(String[] args) {\n\t\t// tag::code[]\n\t\tnew SpringApplicationBuilder().sources(Parent.class)\n\t\t\t.child(Application.class)\n\t\t\t.bannerMode(Banner.Mode.OFF)\n\t\t\t.run(args);\n\t\t// end::code[]\n\t}\n\n\tstatic class Parent {\n\n\t}\n\n\tstatic class Application {\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/springapplication/startuptracking/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.startuptracking;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication(MyApplication.class);\n\t\tapplication.setApplicationStartup(new BufferingApplicationStartup(2048));\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/ssl/bundles/MyComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.ssl.bundles;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyComponent {\n\n\t@SuppressWarnings(\"unused\")\n\tpublic MyComponent(SslBundles sslBundles) {\n\t\tSslBundle sslBundle = sslBundles.getBundle(\"mybundle\");\n\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\t// do something with the created sslContext\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/taskexecutionandscheduling/application/MyTaskExecutorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.application;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyTaskExecutorConfiguration {\n\n\t@Bean(\"applicationTaskExecutor\")\n\tSimpleAsyncTaskExecutor applicationTaskExecutor() {\n\t\treturn new SimpleAsyncTaskExecutor(\"app-\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/taskexecutionandscheduling/async/MyTaskExecutorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.async;\n\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.annotation.AsyncConfigurer;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyTaskExecutorConfiguration {\n\n\t@Bean\n\tAsyncConfigurer asyncConfigurer(ExecutorService executorService) {\n\t\treturn new AsyncConfigurer() {\n\n\t\t\t@Override\n\t\t\tpublic Executor getAsyncExecutor() {\n\t\t\t\treturn executorService;\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Bean\n\tExecutorService executorService() {\n\t\treturn Executors.newCachedThreadPool();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/taskexecutionandscheduling/builder/MyTaskExecutorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.builder;\n\nimport org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyTaskExecutorConfiguration {\n\n\t@Bean\n\tSimpleAsyncTaskExecutor taskExecutor(SimpleAsyncTaskExecutorBuilder builder) {\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/taskexecutionandscheduling/defaultcandidate/MyTaskExecutorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.defaultcandidate;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyTaskExecutorConfiguration {\n\n\t@Bean(defaultCandidate = false)\n\t@Qualifier(\"scheduledExecutorService\")\n\tScheduledExecutorService scheduledExecutorService() {\n\t\treturn Executors.newSingleThreadScheduledExecutor();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/features/taskexecutionandscheduling/multiple/MyTaskExecutorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.multiple;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyTaskExecutorConfiguration {\n\n\t@Bean(\"applicationTaskExecutor\")\n\tSimpleAsyncTaskExecutor applicationTaskExecutor() {\n\t\treturn new SimpleAsyncTaskExecutor(\"app-\");\n\t}\n\n\t@Bean(\"taskExecutor\")\n\tThreadPoolTaskExecutor taskExecutor() {\n\t\tThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();\n\t\tthreadPoolTaskExecutor.setThreadNamePrefix(\"async-\");\n\t\treturn threadPoolTaskExecutor;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/gettingstarted/firstapplication/code/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.gettingstarted.firstapplication.code;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@SpringBootApplication\npublic class MyApplication {\n\n\t@RequestMapping(\"/\")\n\tString home() {\n\t\treturn \"Hello World!\";\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/actuator/maphealthindicatorstometrics/MetricsHealthMicrometerExport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.actuator.maphealthindicatorstometrics;\n\npublic class MetricsHealthMicrometerExport {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/actuator/maphealthindicatorstometrics/MyHealthMetricsExportConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.actuator.maphealthindicatorstometrics;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyHealthMetricsExportConfiguration {\n\n\tpublic MyHealthMetricsExportConfiguration(MeterRegistry registry, HealthEndpoint healthEndpoint) {\n\t\t// This example presumes common tags (such as the app) are applied elsewhere\n\t\tGauge.builder(\"health\", healthEndpoint, this::getStatusCode).strongReference(true).register(registry);\n\t}\n\n\tprivate int getStatusCode(HealthEndpoint health) {\n\t\tStatus status = health.health().getStatus();\n\t\tif (Status.UP.equals(status)) {\n\t\t\treturn 3;\n\t\t}\n\t\tif (Status.OUT_OF_SERVICE.equals(status)) {\n\t\t\treturn 2;\n\t\t}\n\t\tif (Status.DOWN.equals(status)) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/application/customizetheenvironmentorapplicationcontext/MyEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.application.customizetheenvironmentorapplicationcontext;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\npublic class MyEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\tprivate final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tResource path = new ClassPathResource(\"com/example/myapp/config.yml\");\n\t\tPropertySource<?> propertySource = loadYaml(path);\n\t\tenvironment.getPropertySources().addLast(propertySource);\n\t}\n\n\tprivate PropertySource<?> loadYaml(Resource path) {\n\t\tAssert.isTrue(path.exists(), () -> \"'path' [%s] must exist\".formatted(path));\n\t\ttry {\n\t\t\treturn this.loader.load(\"custom-resource\", path).get(0);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to load yaml configuration from \" + path, ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configureacomponentthatisusedbyjpa/ElasticsearchEntityManagerFactoryDependsOnPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configureacomponentthatisusedbyjpa;\n\nimport jakarta.persistence.EntityManagerFactory;\n\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link EntityManagerFactoryDependsOnPostProcessor} that ensures that\n * {@link EntityManagerFactory} beans depend on the {@code elasticsearchClient} bean.\n */\n@Component\npublic class ElasticsearchEntityManagerFactoryDependsOnPostProcessor\n\t\textends EntityManagerFactoryDependsOnPostProcessor {\n\n\tpublic ElasticsearchEntityManagerFactoryDependsOnPostProcessor() {\n\t\tsuper(\"elasticsearchClient\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/builder/MyDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.builder;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyDataSourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource\")\n\tpublic DataSource dataSource() {\n\t\treturn DataSourceBuilder.create().build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/configurable/MyDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.configurable;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyDataSourceConfiguration {\n\n\t@Bean\n\t@Primary\n\t@ConfigurationProperties(\"app.datasource\")\n\tpublic DataSourceProperties dataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource.configuration\")\n\tpublic HikariDataSource dataSource(DataSourceProperties properties) {\n\t\treturn properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/custom/MyDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.custom;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyDataSourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource\")\n\tpublic SomeDataSource dataSource() {\n\t\treturn new SomeDataSource();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/custom/SomeDataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.custom;\n\npublic class SomeDataSource {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/simple/MyDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.simple;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyDataSourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource\")\n\tpublic HikariDataSource dataSource() {\n\t\treturn DataSourceBuilder.create().type(HikariDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurehibernatenamingstrategy/spring/MyHibernateConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurehibernatenamingstrategy.spring;\n\nimport org.hibernate.boot.model.naming.Identifier;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;\nimport org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyHibernateConfiguration {\n\n\t@Bean\n\tpublic PhysicalNamingStrategySnakeCaseImpl caseSensitivePhysicalNamingStrategy() {\n\t\treturn new PhysicalNamingStrategySnakeCaseImpl() {\n\n\t\t\t@Override\n\t\t\tpublic Identifier toPhysicalColumnName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {\n\t\t\t\treturn logicalName;\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurehibernatenamingstrategy/standard/MyHibernateConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurehibernatenamingstrategy.standard;\n\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\nclass MyHibernateConfiguration {\n\n\t@Bean\n\tPhysicalNamingStrategyStandardImpl caseSensitivePhysicalNamingStrategy() {\n\t\treturn new PhysicalNamingStrategyStandardImpl();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configurehibernatesecondlevelcaching/MyHibernateSecondLevelCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurehibernatesecondlevelcaching;\n\nimport org.hibernate.cache.jcache.ConfigSettings;\n\nimport org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer;\nimport org.springframework.cache.jcache.JCacheCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyHibernateSecondLevelCacheConfiguration {\n\n\t@Bean\n\tpublic HibernatePropertiesCustomizer hibernateSecondLevelCacheCustomizer(JCacheCacheManager cacheManager) {\n\t\treturn (properties) -> properties.put(ConfigSettings.CACHE_MANAGER, cacheManager.getCacheManager());\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configuretwodatasources/MyAdditionalDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configuretwodatasources;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyAdditionalDataSourceConfiguration {\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.datasource\")\n\tpublic HikariDataSource secondDataSource() {\n\t\treturn DataSourceBuilder.create().type(HikariDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/configuretwodatasources/MyCompleteAdditionalDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configuretwodatasources;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCompleteAdditionalDataSourceConfiguration {\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.datasource\")\n\tpublic DataSourceProperties secondDataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.datasource.configuration\")\n\tpublic HikariDataSource secondDataSource(@Qualifier(\"second\") DataSourceProperties dataSourceProperties) {\n\t\treturn dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/filterscannedentitydefinitions/MyEntityScanConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.filterscannedentitydefinitions;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyEntityScanConfiguration {\n\n\t@Bean\n\tpublic ManagedClassNameFilter entityScanFilter() {\n\t\treturn (className) -> className.startsWith(\"com.example.app.customer.\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/separateentitydefinitionsfromspringconfiguration/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.separateentitydefinitionsfromspringconfiguration;\n\nclass City {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/separateentitydefinitionsfromspringconfiguration/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.separateentitydefinitionsfromspringconfiguration;\n\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.persistence.autoconfigure.EntityScan;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\n@EnableAutoConfiguration\n@EntityScan(basePackageClasses = City.class)\npublic class MyApplication {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/Customer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers;\n\npublic class Customer {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/CustomerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\n\n@Configuration(proxyBeanMethods = false)\n@EnableJpaRepositories(basePackageClasses = Customer.class, entityManagerFactoryRef = \"secondEntityManagerFactory\")\npublic class CustomerConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/MyAdditionalEntityManagerFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jpa.EntityManagerFactoryBuilder;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.orm.jpa.JpaVendorAdapter;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyAdditionalEntityManagerFactoryConfiguration {\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.jpa\")\n\tpublic JpaProperties secondJpaProperties() {\n\t\treturn new JpaProperties();\n\t}\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\tpublic LocalContainerEntityManagerFactoryBean secondEntityManagerFactory(@Qualifier(\"second\") DataSource dataSource,\n\t\t\t@Qualifier(\"second\") JpaProperties jpaProperties) {\n\t\tEntityManagerFactoryBuilder builder = createEntityManagerFactoryBuilder(jpaProperties);\n\t\treturn builder.dataSource(dataSource).packages(Order.class).persistenceUnit(\"second\").build();\n\t}\n\n\tprivate EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(JpaProperties jpaProperties) {\n\t\tJpaVendorAdapter jpaVendorAdapter = createJpaVendorAdapter(jpaProperties);\n\t\tFunction<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> createJpaProperties(dataSource,\n\t\t\t\tjpaProperties.getProperties());\n\t\treturn new EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null);\n\t}\n\n\tprivate JpaVendorAdapter createJpaVendorAdapter(JpaProperties jpaProperties) {\n\t\t// ... map JPA properties as needed\n\t\treturn new HibernateJpaVendorAdapter();\n\t}\n\n\tprivate Map<String, ?> createJpaProperties(DataSource dataSource, Map<String, ?> existingProperties) {\n\t\tMap<String, ?> jpaProperties = new LinkedHashMap<>(existingProperties);\n\t\t// ... map JPA properties that require the DataSource (e.g. DDL flags)\n\t\treturn jpaProperties;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/Order.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers;\n\npublic class Order {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/OrderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\n\n@Configuration(proxyBeanMethods = false)\n@EnableJpaRepositories(basePackageClasses = Order.class, entityManagerFactoryRef = \"entityManagerFactory\")\npublic class OrderConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/deployment/cloud/cloudfoundry/bindingtoservices/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.deployment.cloud.cloudfoundry.bindingtoservices;\n\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.core.env.Environment;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean implements EnvironmentAware {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate String instanceId;\n\n\t@Override\n\tpublic void setEnvironment(Environment environment) {\n\t\tthis.instanceId = environment.getProperty(\"vcap.application.instance_id\");\n\t}\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/httpclients/webclientreactornettycustomization/MyReactorNettyClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.httpclients.webclientreactornettycustomization;\n\nimport io.netty.channel.ChannelOption;\nimport io.netty.handler.timeout.ReadTimeoutHandler;\nimport reactor.netty.http.client.HttpClient;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyReactorNettyClientConfiguration {\n\n\t@Bean\n\tClientHttpConnector clientHttpConnector(ReactorResourceFactory resourceFactory) {\n\t\t// @formatter:off\n\t\tHttpClient httpClient = HttpClient.create(resourceFactory.getConnectionProvider())\n\t\t\t\t.runOn(resourceFactory.getLoopResources())\n\t\t\t\t.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)\n\t\t\t\t.doOnConnected((connection) -> connection.addHandlerLast(new ReadTimeoutHandler(60)));\n\t\treturn new ReactorClientHttpConnector(httpClient);\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/jersey/alongsideanotherwebframework/Endpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.jersey.alongsideanotherwebframework;\n\nclass Endpoint {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/jersey/alongsideanotherwebframework/JerseyConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.jersey.alongsideanotherwebframework;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.servlet.ServletProperties;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class JerseyConfig extends ResourceConfig {\n\n\tpublic JerseyConfig() {\n\t\tregister(Endpoint.class);\n\t\tproperty(ServletProperties.FILTER_FORWARD_ON_404, true);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/jersey/springsecurity/Endpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.jersey.springsecurity;\n\nclass Endpoint {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/jersey/springsecurity/JerseySetStatusOverSendErrorConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.jersey.springsecurity;\n\nimport java.util.Collections;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class JerseySetStatusOverSendErrorConfig extends ResourceConfig {\n\n\tpublic JerseySetStatusOverSendErrorConfig() {\n\t\tregister(Endpoint.class);\n\t\tsetProperties(Collections.singletonMap(\"jersey.config.server.response.setStatusOverSendError\", true));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.messaging.disabletransactedjmssession;\n\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.boot.jms.ConnectionFactoryUnwrapper;\nimport org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyJmsConfiguration {\n\n\t@Bean\n\tpublic DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory,\n\t\t\tDefaultJmsListenerContainerFactoryConfigurer configurer) {\n\t\tDefaultJmsListenerContainerFactory listenerFactory = new DefaultJmsListenerContainerFactory();\n\t\tconfigurer.configure(listenerFactory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory));\n\t\tlistenerFactory.setTransactionManager(null);\n\t\tlistenerFactory.setSessionTransacted(false);\n\t\treturn listenerFactory;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/nativeimage/developingyourfirstapplication/sampleapplication/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.nativeimage.developingyourfirstapplication.sampleapplication;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@SpringBootApplication\npublic class MyApplication {\n\n\t@RequestMapping(\"/\")\n\tString home() {\n\t\treturn \"Hello World!\";\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/propertiesandconfiguration/externalizeconfiguration/application/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.propertiesandconfiguration.externalizeconfiguration.application;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication(MyApplication.class);\n\t\tapplication.setBannerMode(Banner.Mode.OFF);\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/propertiesandconfiguration/externalizeconfiguration/builder/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.propertiesandconfiguration.externalizeconfiguration.builder;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\n\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\t// @formatter:off\n\t\tnew SpringApplicationBuilder()\n\t\t\t.bannerMode(Banner.Mode.OFF)\n\t\t\t.sources(MyApplication.class)\n\t\t\t.run(args);\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/security/enablehttps/MySecurityConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.security.enablehttps;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration\npublic class MySecurityConfig {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\t// Customize the application security ...\n\t\thttp.redirectToHttps(Customizer.withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/springmvc/writejsonrestservice/MyController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.springmvc.writejsonrestservice;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class MyController {\n\n\t@RequestMapping(\"/thing\")\n\tpublic MyThing thing() {\n\t\treturn new MyThing();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/springmvc/writejsonrestservice/MyThing.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.springmvc.writejsonrestservice;\n\npublic class MyThing {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/springmvc/writexmlrestservice/MyThing.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.springmvc.writexmlrestservice;\n\nimport jakarta.xml.bind.annotation.XmlRootElement;\n\n@XmlRootElement\npublic class MyThing {\n\n\tprivate String name;\n\n\t// @fold:on // getters/setters ...\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/testing/slicetests/MyConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.slicetests;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyConfiguration {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\treturn http.build();\n\t}\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource.second\")\n\tpublic HikariDataSource secondDataSource() {\n\t\treturn DataSourceBuilder.create().type(HikariDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/testing/slicetests/MyDatasourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.slicetests;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyDatasourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource.second\")\n\tpublic HikariDataSource secondDataSource() {\n\t\treturn DataSourceBuilder.create().type(HikariDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/testing/slicetests/MySecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.slicetests;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySecurityConfiguration {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/testing/withspringsecurity/MySecurityTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.withspringsecurity;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@WebMvcTest(UserController.class)\nclass MySecurityTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\t@WithMockUser(roles = \"ADMIN\")\n\tvoid requestProtectedUrlWithUser() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).doesNotHaveFailed();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/testing/withspringsecurity/UserController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.withspringsecurity;\n\nclass UserController {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/traditionaldeployment/convertexistingapplication/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.convertexistingapplication;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class MyApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\t// Customize the application or call application.sources(...) to add sources\n\t\t// Since our example is itself a @Configuration class (through\n\t\t// @SpringBootApplication)\n\t\t// we actually do not need to override this method.\n\t\treturn application;\n\t}\n\n\t// tag::main[]\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\t// end::main[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/traditionaldeployment/convertexistingapplication/both/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.convertexistingapplication.both;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class MyApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n\t\treturn customizerBuilder(builder);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tcustomizerBuilder(new SpringApplicationBuilder()).run(args);\n\t}\n\n\tprivate static SpringApplicationBuilder customizerBuilder(SpringApplicationBuilder builder) {\n\t\treturn builder.sources(MyApplication.class).bannerMode(Banner.Mode.OFF);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/traditionaldeployment/war/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.war;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class MyApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(MyApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/traditionaldeployment/weblogic/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.weblogic;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.web.WebApplicationInitializer;\n\n@SpringBootApplication\npublic class MyApplication extends SpringBootServletInitializer implements WebApplicationInitializer {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/addservletfilterlistener/springbean/disable/MyFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.addservletfilterlistener.springbean.disable;\n\nimport jakarta.servlet.Filter;\n\npublic abstract class MyFilter implements Filter {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/addservletfilterlistener/springbean/disable/MyFilterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.addservletfilterlistener.springbean.disable;\n\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyFilterConfiguration {\n\n\t@Bean\n\tpublic FilterRegistrationBean<MyFilter> registration(MyFilter filter) {\n\t\tFilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter);\n\t\tregistration.setEnabled(false);\n\t\treturn registration;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/builduritestwebserver/MyWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.builduritestwebserver;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\nclass MyWebIntegrationTests {\n\n\t@Autowired\n\tApplicationContext context;\n\n\t// ...\n\n\t@Test\n\tvoid test() {\n\t\tString urlToTest = LocalTestWebServer.obtain(this.context).uri(\"/test\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/configure/MyTomcatWebServerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.configure;\n\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyTomcatWebServerCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {\n\n\t@Override\n\tpublic void customize(TomcatServletWebServerFactory factory) {\n\t\t// customize the factory here\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/createwebsocketendpointsusingserverendpoint/MyWebSocketConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.createwebsocketendpointsusingserverendpoint;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.server.standard.ServerEndpointExporter;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyWebSocketConfiguration {\n\n\t@Bean\n\tpublic ServerEndpointExporter serverEndpointExporter() {\n\t\treturn new ServerEndpointExporter();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/discoverport/MyWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.discoverport;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\nclass MyWebIntegrationTests {\n\n\t@LocalServerPort\n\tint port;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/howto/webserver/enablemultipleconnectorsintomcat/MyTomcatConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.enablemultipleconnectorsintomcat;\n\nimport org.apache.catalina.connector.Connector;\n\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyTomcatConfiguration {\n\n\t@Bean\n\tpublic WebServerFactoryCustomizer<TomcatServletWebServerFactory> connectorCustomizer() {\n\t\treturn (tomcat) -> tomcat.addAdditionalConnectors(createConnector());\n\t}\n\n\tprivate Connector createConnector() {\n\t\tConnector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n\t\tconnector.setPort(8081);\n\t\treturn connector;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/MyMathService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching;\n\nimport org.springframework.cache.annotation.Cacheable;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyMathService {\n\n\t@Cacheable(\"piDecimals\")\n\tpublic int computePiDecimal(int precision) {\n\t\t/**/ return 0;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/MyCacheManagerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider;\n\nimport org.springframework.boot.cache.autoconfigure.CacheManagerCustomizer;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCacheManagerConfiguration {\n\n\t@Bean\n\tpublic CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {\n\t\treturn (cacheManager) -> cacheManager.setAllowNullValues(false);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/cache2k/MyCache2kDefaultsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider.cache2k;\n\nimport java.util.concurrent.TimeUnit;\n\nimport org.springframework.boot.cache.autoconfigure.Cache2kBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCache2kDefaultsConfiguration {\n\n\t@Bean\n\tpublic Cache2kBuilderCustomizer myCache2kDefaultsCustomizer() {\n\t\t// @formatter:off\n\t\treturn (builder) -> builder.entryCapacity(200)\n\t\t\t\t.expireAfterWrite(5, TimeUnit.MINUTES);\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider.couchbase;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.cache.autoconfigure.CouchbaseCacheManagerBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCouchbaseCacheManagerConfiguration {\n\n\t@Bean\n\tpublic CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() {\n\t\t// @formatter:off\n\t\treturn (builder) -> builder\n\t\t\t\t.withCacheConfiguration(\"cache1\", CouchbaseCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryExpiry(Duration.ofSeconds(10)))\n\t\t\t\t.withCacheConfiguration(\"cache2\", CouchbaseCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryExpiry(Duration.ofMinutes(1)));\n\t\t// @formatter:on\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/redis/MyRedisCacheManagerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider.redis;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.cache.autoconfigure.RedisCacheManagerBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.cache.RedisCacheConfiguration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyRedisCacheManagerConfiguration {\n\n\t@Bean\n\tpublic RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {\n\t\t// @formatter:off\n\t\treturn (builder) -> builder\n\t\t\t\t.withCacheConfiguration(\"cache1\", RedisCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))\n\t\t\t\t.withCacheConfiguration(\"cache2\", RedisCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));\n\t\t// @formatter:on\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/testing/MyIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.testing;\n\nimport org.springframework.boot.cache.test.autoconfigure.AutoConfigureCache;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\n@AutoConfigureCache\npublic class MyIntegrationTests {\n\n\t// Tests use a no-op cache manager\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/jta/mixingxaandnonxaconnections/nonxa/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.jta.mixingxaandnonxaconnections.nonxa;\n\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\npublic class MyBean {\n\n\tpublic MyBean(@Qualifier(\"nonXaJmsConnectionFactory\") ConnectionFactory connectionFactory) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/jta/mixingxaandnonxaconnections/primary/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.jta.mixingxaandnonxaconnections.primary;\n\nimport jakarta.jms.ConnectionFactory;\n\npublic class MyBean {\n\n\tpublic MyBean(ConnectionFactory connectionFactory) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/jta/mixingxaandnonxaconnections/xa/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.jta.mixingxaandnonxaconnections.xa;\n\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\npublic class MyBean {\n\n\tpublic MyBean(@Qualifier(\"xaJmsConnectionFactory\") ConnectionFactory connectionFactory) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/quartz/MySampleJob.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.quartz;\n\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\nimport org.springframework.scheduling.quartz.QuartzJobBean;\n\npublic class MySampleJob extends QuartzJobBean {\n\n\t// @fold:on // fields ...\n\tprivate MyService myService;\n\n\tprivate String name;\n\n\t// @fold:off\n\n\t// Inject \"MyService\" bean\n\tpublic void setMyService(MyService myService) {\n\t\tthis.myService = myService;\n\t}\n\n\t// Inject the \"name\" job data property\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {\n\t\tthis.myService.someMethod(context.getFireTime(), this.name);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/quartz/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.quartz;\n\nimport java.util.Date;\n\nclass MyService {\n\n\tvoid someMethod(Date date, String name) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/clienthttprequestfactory/configuration/MyClientHttpConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.clienthttprequestfactory.configuration;\n\nimport java.net.ProxySelector;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyClientHttpConfiguration {\n\n\t@Bean\n\tClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(ProxySelector proxySelector) {\n\t\treturn ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t.withHttpClientCustomizer((builder) -> builder.proxy(proxySelector));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/EchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice;\n\nimport java.util.Map;\n\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.service.annotation.HttpExchange;\nimport org.springframework.web.service.annotation.PostExchange;\n\n@HttpExchange(url = \"https://echo.zuplo.io\")\npublic interface EchoService {\n\n\t@PostExchange\n\tMap<?, ?> echo(@RequestBody Map<String, String> message);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/customization/MyHttpServiceGroupConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.customization;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyHttpServiceGroupConfiguration {\n\n\t@Bean\n\tRestClientHttpServiceGroupConfigurer myHttpServiceGroupConfigurer() {\n\t\treturn (groups) -> groups.forEachClient((group, clientBuilder) -> {\n\t\t\tString groupName = group.name();\n\t\t\tclientBuilder.defaultHeader(\"service-group\", groupName);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/groups/EchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.groups;\n\nimport java.util.Map;\n\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.service.annotation.PostExchange;\n\npublic interface EchoService {\n\n\t@PostExchange\n\tMap<?, ?> echo(@RequestBody Map<String, String> message);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/groups/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.groups;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.service.registry.ImportHttpServices;\n\n@SpringBootApplication\n@ImportHttpServices(group = \"echo\", basePackages = \"com.example.myclients\")\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/groups/repeat/EchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.groups.repeat;\n\nimport java.util.Map;\n\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.service.annotation.PostExchange;\n\npublic interface EchoService {\n\n\t@PostExchange(\"/echo\")\n\tMap<?, ?> echo(@RequestBody Map<String, String> message);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/groups/repeat/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.groups.repeat;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.service.registry.ImportHttpServices;\n\n@SpringBootApplication\n@ImportHttpServices(group = \"echo\", types = EchoService.class)\n@ImportHttpServices(group = \"other\", types = OtherService.class)\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/groups/repeat/OtherService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.groups.repeat;\n\nimport java.util.Map;\n\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.service.annotation.PostExchange;\n\npublic interface OtherService {\n\n\t@PostExchange(\"/other\")\n\tMap<?, ?> other(@RequestBody Map<String, String> message);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/httpservice/importing/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.httpservice.importing;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.web.service.registry.ImportHttpServices;\n\n@SpringBootApplication\n@ImportHttpServices(basePackages = \"com.example.myclients\")\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/Details.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient;\n\npublic class Details {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestClient;\n\n@Service\npublic class MyService {\n\n\tprivate final RestClient restClient;\n\n\tpublic MyService(RestClient.Builder restClientBuilder) {\n\t\tthis.restClient = restClientBuilder.baseUrl(\"https://example.org\").build();\n\t}\n\n\tpublic Details someRestCall(String name) {\n\t\treturn this.restClient.get().uri(\"/{name}/details\", name).retrieve().body(Details.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/ssl/Details.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl;\n\npublic class Details {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/ssl/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl;\n\nimport org.springframework.boot.restclient.autoconfigure.RestClientSsl;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestClient;\n\n@Service\npublic class MyService {\n\n\tprivate final RestClient restClient;\n\n\tpublic MyService(RestClient.Builder restClientBuilder, RestClientSsl ssl) {\n\t\tthis.restClient = restClientBuilder.baseUrl(\"https://example.org\").apply(ssl.fromBundle(\"mybundle\")).build();\n\t}\n\n\tpublic Details someRestCall(String name) {\n\t\treturn this.restClient.get().uri(\"/{name}/details\", name).retrieve().body(Details.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/ssl/settings/Details.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl.settings;\n\npublic class Details {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/restclient/ssl/settings/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl.settings;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestClient;\n\n@Service\npublic class MyService {\n\n\tprivate final RestClient restClient;\n\n\tpublic MyService(RestClient.Builder restClientBuilder, SslBundles sslBundles) {\n\t\tHttpClientSettings settings = HttpClientSettings.ofSslBundle(sslBundles.getBundle(\"mybundle\"))\n\t\t\t.withReadTimeout(Duration.ofMinutes(2));\n\t\tClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder.detect().build(settings);\n\t\tthis.restClient = restClientBuilder.baseUrl(\"https://example.org\").requestFactory(requestFactory).build();\n\t}\n\n\tpublic Details someRestCall(String name) {\n\t\treturn this.restClient.get().uri(\"/{name}/details\", name).retrieve().body(Details.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/resttemplate/Details.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate;\n\npublic class Details {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/resttemplate/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\n\n@Service\npublic class MyService {\n\n\tprivate final RestTemplate restTemplate;\n\n\tpublic MyService(RestTemplateBuilder restTemplateBuilder) {\n\t\tthis.restTemplate = restTemplateBuilder.build();\n\t}\n\n\tpublic Details someRestCall(String name) {\n\t\treturn this.restTemplate.getForObject(\"/{name}/details\", Details.class, name);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/resttemplate/customization/MyRestTemplateBuilderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate.customization;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.autoconfigure.RestTemplateBuilderConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyRestTemplateBuilderConfiguration {\n\n\t@Bean\n\tpublic RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {\n\t\treturn configurer.configure(new RestTemplateBuilder())\n\t\t\t.connectTimeout(Duration.ofSeconds(5))\n\t\t\t.readTimeout(Duration.ofSeconds(2));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/resttemplate/customization/MyRestTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate.customization;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;\nimport org.apache.hc.client5.http.routing.HttpRoutePlanner;\nimport org.apache.hc.core5.http.HttpException;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.protocol.HttpContext;\n\nimport org.springframework.boot.restclient.RestTemplateCustomizer;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.web.client.RestTemplate;\n\npublic class MyRestTemplateCustomizer implements RestTemplateCustomizer {\n\n\t@Override\n\tpublic void customize(RestTemplate restTemplate) {\n\t\tHttpRoutePlanner routePlanner = new CustomRoutePlanner(new HttpHost(\"proxy.example.com\"));\n\t\tHttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build();\n\t\trestTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));\n\t}\n\n\tstatic class CustomRoutePlanner extends DefaultProxyRoutePlanner {\n\n\t\tCustomRoutePlanner(HttpHost proxy) {\n\t\t\tsuper(proxy);\n\t\t}\n\n\t\t@Override\n\t\tprotected HttpHost determineProxy(HttpHost target, HttpContext context) throws HttpException {\n\t\t\tif (target.getHostName().equals(\"192.168.0.5\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn super.determineProxy(target, context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/resttemplate/ssl/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate.ssl;\n\nimport org.springframework.boot.docs.io.restclient.resttemplate.Details;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\n\n@Service\npublic class MyService {\n\n\tprivate final RestTemplate restTemplate;\n\n\tpublic MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {\n\t\tthis.restTemplate = restTemplateBuilder.sslBundle(sslBundles.getBundle(\"mybundle\")).build();\n\t}\n\n\tpublic Details someRestCall(String name) {\n\t\treturn this.restTemplate.getForObject(\"/{name}/details\", Details.class, name);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/webclient/Details.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient;\n\npublic class Details {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/webclient/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n@Service\npublic class MyService {\n\n\tprivate final WebClient webClient;\n\n\tpublic MyService(WebClient.Builder webClientBuilder) {\n\t\tthis.webClient = webClientBuilder.baseUrl(\"https://example.org\").build();\n\t}\n\n\tpublic Mono<Details> someRestCall(String name) {\n\t\treturn this.webClient.get().uri(\"/{name}/details\", name).retrieve().bodyToMono(Details.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/webclient/configuration/MyConnectorHttpConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient.configuration;\n\nimport java.net.ProxySelector;\n\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyConnectorHttpConfiguration {\n\n\t@Bean\n\tClientHttpConnectorBuilder<?> clientHttpConnectorBuilder(ProxySelector proxySelector) {\n\t\treturn ClientHttpConnectorBuilder.jdk().withHttpClientCustomizer((builder) -> builder.proxy(proxySelector));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/webclient/ssl/Details.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient.ssl;\n\npublic class Details {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/restclient/webclient/ssl/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient.ssl;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.webclient.autoconfigure.WebClientSsl;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n@Service\npublic class MyService {\n\n\tprivate final WebClient webClient;\n\n\tpublic MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {\n\t\tthis.webClient = webClientBuilder.baseUrl(\"https://example.org\").apply(ssl.fromBundle(\"mybundle\")).build();\n\t}\n\n\tpublic Mono<Details> someRestCall(String name) {\n\t\treturn this.webClient.get().uri(\"/{name}/details\", name).retrieve().bodyToMono(Details.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/validation/Archive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.validation;\n\nclass Archive {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/validation/Author.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.validation;\n\nclass Author {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/validation/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.validation;\n\nimport jakarta.validation.constraints.Size;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.validation.annotation.Validated;\n\n@Service\n@Validated\npublic class MyBean {\n\n\tpublic Archive findByCodeAndAuthor(@Size(min = 8, max = 10) String code, Author author) {\n\t\treturn /**/ null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/webservices/template/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template;\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.soap.client.core.SoapActionCallback;\n\n@Service\npublic class MyService {\n\n\tprivate final WebServiceTemplate webServiceTemplate;\n\n\tpublic MyService(WebServiceTemplateBuilder webServiceTemplateBuilder) {\n\t\tthis.webServiceTemplate = webServiceTemplateBuilder.build();\n\t}\n\n\tpublic SomeResponse someWsCall(SomeRequest detailsReq) {\n\t\treturn (SomeResponse) this.webServiceTemplate.marshalSendAndReceive(detailsReq,\n\t\t\t\tnew SoapActionCallback(\"https://ws.example.com/action\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/webservices/template/MyWebServiceTemplateConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.webservices.client.WebServiceMessageSenderFactory;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyWebServiceTemplateConfiguration {\n\n\t@Bean\n\tpublic WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults()\n\t\t\t.withConnectTimeout(Duration.ofSeconds(2))\n\t\t\t.withReadTimeout(Duration.ofSeconds(2));\n\t\tbuilder.httpMessageSenderFactory(WebServiceMessageSenderFactory.http(settings));\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/webservices/template/SomeRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template;\n\nclass SomeRequest {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/webservices/template/SomeResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template;\n\nclass SomeResponse {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/receiving/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving;\n\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@RabbitListener(queues = \"someQueue\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving.custom;\n\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@RabbitListener(queues = \"someQueue\", containerFactory = \"myFactory\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyMessageConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving.custom;\n\nimport org.springframework.amqp.core.Message;\nimport org.springframework.amqp.core.MessageProperties;\nimport org.springframework.amqp.support.converter.MessageConversionException;\nimport org.springframework.amqp.support.converter.MessageConverter;\n\nclass MyMessageConverter implements MessageConverter {\n\n\t@Override\n\tpublic Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Object fromMessage(Message message) throws MessageConversionException {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyRabbitConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving.custom;\n\nimport org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.boot.amqp.autoconfigure.SimpleRabbitListenerContainerFactoryConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyRabbitConfiguration {\n\n\t@Bean\n\tpublic SimpleRabbitListenerContainerFactory myFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer) {\n\t\tSimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();\n\t\tConnectionFactory connectionFactory = getCustomConnectionFactory();\n\t\tconfigurer.configure(factory, connectionFactory);\n\t\tfactory.setMessageConverter(new MyMessageConverter());\n\t\treturn factory;\n\t}\n\n\tprivate ConnectionFactory getCustomConnectionFactory() {\n\t\treturn /**/ null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/amqp/sending/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.sending;\n\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.core.AmqpTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final AmqpAdmin amqpAdmin;\n\n\tprivate final AmqpTemplate amqpTemplate;\n\n\tpublic MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {\n\t\tthis.amqpAdmin = amqpAdmin;\n\t\tthis.amqpTemplate = amqpTemplate;\n\t}\n\n\t// @fold:on // ...\n\tpublic void someMethod() {\n\t\tthis.amqpAdmin.getQueueInfo(\"someQueue\");\n\t}\n\n\tpublic void someOtherMethod() {\n\t\tthis.amqpTemplate.convertAndSend(\"hello\");\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving;\n\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@JmsListener(destination = \"someQueue\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving.custom;\n\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@JmsListener(destination = \"someQueue\", containerFactory = \"myFactory\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving.custom;\n\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.boot.jms.ConnectionFactoryUnwrapper;\nimport org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyJmsConfiguration {\n\n\t@Bean\n\tpublic DefaultJmsListenerContainerFactory myFactory(DefaultJmsListenerContainerFactoryConfigurer configurer,\n\t\t\tConnectionFactory connectionFactory) {\n\t\tDefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();\n\t\tconfigurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory));\n\t\tfactory.setMessageConverter(new MyMessageConverter());\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/receiving/custom/MyMessageConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving.custom;\n\nimport jakarta.jms.JMSException;\nimport jakarta.jms.Message;\nimport jakarta.jms.Session;\n\nimport org.springframework.jms.support.converter.MessageConversionException;\nimport org.springframework.jms.support.converter.MessageConverter;\n\nclass MyMessageConverter implements MessageConverter {\n\n\t@Override\n\tpublic Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Object fromMessage(Message message) throws JMSException, MessageConversionException {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/jms/sending/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.sending;\n\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final JmsClient jmsClient;\n\n\tpublic MyBean(JmsClient jmsClient) {\n\t\tthis.jmsClient = jmsClient;\n\t}\n\n\t// @fold:on // ...\n\tpublic void someMethod() {\n\t\tthis.jmsClient.destination(\"myQueue\").send(\"hello\");\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/embedded/annotation/MyTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.embedded.annotation;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.kafka.test.context.EmbeddedKafka;\n\n@SpringBootTest\n@EmbeddedKafka(topics = \"someTopic\", bootstrapServersProperty = \"spring.kafka.bootstrap-servers\")\nclass MyTest {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/embedded/property/MyTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.embedded.property;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.kafka.test.EmbeddedKafkaBroker;\n\n@SpringBootTest\nclass MyTest {\n\n\t// tag::code[]\n\tstatic {\n\t\tSystem.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, \"spring.kafka.bootstrap-servers\");\n\t}\n\t// end::code[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/receiving/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.receiving;\n\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@KafkaListener(topics = \"someTopic\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/sending/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.sending;\n\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final KafkaTemplate<String, String> kafkaTemplate;\n\n\tpublic MyBean(KafkaTemplate<String, String> kafkaTemplate) {\n\t\tthis.kafkaTemplate = kafkaTemplate;\n\t}\n\n\t// @fold:on // ...\n\tpublic void someMethod() {\n\t\tthis.kafkaTemplate.send(\"someTopic\", \"Hello\");\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/kafka/streams/MyKafkaStreamsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.streams;\n\nimport java.util.Locale;\n\nimport org.apache.kafka.common.serialization.Serdes;\nimport org.apache.kafka.streams.KeyValue;\nimport org.apache.kafka.streams.StreamsBuilder;\nimport org.apache.kafka.streams.kstream.KStream;\nimport org.apache.kafka.streams.kstream.Produced;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.EnableKafkaStreams;\n\n@Configuration(proxyBeanMethods = false)\n@EnableKafkaStreams\npublic class MyKafkaStreamsConfiguration {\n\n\t@Bean\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tpublic KStream<Integer, String> kStream(StreamsBuilder streamsBuilder) {\n\t\tKStream<Integer, String> stream = streamsBuilder.stream(\"ks1In\");\n\t\tstream.map(this::uppercaseValue)\n\t\t\t.to(\"ks1Out\",\n\t\t\t\t\tProduced.with(Serdes.Integer(), new org.springframework.kafka.support.serializer.JsonSerde<>()));\n\t\treturn stream;\n\t}\n\n\tprivate KeyValue<Integer, String> uppercaseValue(Integer key, String value) {\n\t\treturn new KeyValue<>(key, value.toUpperCase(Locale.getDefault()));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/pulsar/reading/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.pulsar.reading;\n\nimport org.springframework.pulsar.annotation.PulsarReader;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@PulsarReader(topics = \"someTopic\", startMessageId = \"earliest\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/pulsar/receiving/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.pulsar.receiving;\n\nimport org.springframework.pulsar.annotation.PulsarListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\t@PulsarListener(topics = \"someTopic\")\n\tpublic void processMessage(String content) {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/pulsar/sending/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.pulsar.sending;\n\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyBean {\n\n\tprivate final PulsarTemplate<String> pulsarTemplate;\n\n\tpublic MyBean(PulsarTemplate<String> pulsarTemplate) {\n\t\tthis.pulsarTemplate = pulsarTemplate;\n\t}\n\n\tpublic void someMethod() {\n\t\tthis.pulsarTemplate.send(\"someTopic\", \"Hello\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/rsocket/requester/MyService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.rsocket.requester;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class MyService {\n\n\tprivate final RSocketRequester rsocketRequester;\n\n\tpublic MyService(RSocketRequester.Builder rsocketRequesterBuilder) {\n\t\tthis.rsocketRequester = rsocketRequesterBuilder.tcp(\"example.org\", 9898);\n\t}\n\n\tpublic Mono<User> someRSocketCall(String name) {\n\t\treturn this.rsocketRequester.route(\"user\").data(name).retrieveMono(User.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/messaging/rsocket/requester/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.rsocket.requester;\n\nclass User {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/customhints/MyClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.customhints;\n\nclass MyClass {\n\n\tvoid sayHello(String name) {\n\t\tSystem.out.println(\"Hello \" + name);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/customhints/MyInterface.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.customhints;\n\ninterface MyInterface {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/customhints/MyRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.customhints;\n\nimport java.lang.reflect.Method;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.util.ReflectionUtils;\n\npublic class MyRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {\n\t\t// Register method for reflection\n\t\tMethod method = ReflectionUtils.findMethod(MyClass.class, \"sayHello\", String.class);\n\t\thints.reflection().registerMethod(method, ExecutableMode.INVOKE);\n\n\t\t// Register type for java serialization\n\t\thints.reflection().registerJavaSerialization(MySerializableClass.class);\n\n\t\t// Register resources\n\t\thints.resources().registerPattern(\"my-resource.txt\");\n\n\t\t// Register proxy\n\t\thints.proxies().registerJdkProxy(MyInterface.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/customhints/MySerializableClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.customhints;\n\nimport java.io.Serializable;\n\nclass MySerializableClass implements Serializable {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/customhints/testing/MyRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.customhints.testing;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.docs.packaging.nativeimage.advanced.customhints.MyRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass MyRuntimeHintsTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew MyRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"my-resource.txt\")).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/nestedconfigurationproperties/MyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.nestedconfigurationproperties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\n\n@ConfigurationProperties(\"my.properties\")\npublic class MyProperties {\n\n\tprivate String name;\n\n\t@NestedConfigurationProperty\n\tprivate final Nested nested = new Nested();\n\n\t// @fold:on // getters / setters...\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Nested getNested() {\n\t\treturn this.nested;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/nestedconfigurationproperties/MyPropertiesCtor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.nestedconfigurationproperties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\n\n@ConfigurationProperties(\"my.properties\")\npublic class MyPropertiesCtor {\n\n\tprivate final String name;\n\n\t@NestedConfigurationProperty\n\tprivate final Nested nested;\n\n\tpublic MyPropertiesCtor(String name, Nested nested) {\n\t\tthis.name = name;\n\t\tthis.nested = nested;\n\t}\n\n\t// @fold:on // getters / setters...\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic Nested getNested() {\n\t\treturn this.nested;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/nestedconfigurationproperties/MyPropertiesRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.nestedconfigurationproperties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\n\n@ConfigurationProperties(\"my.properties\")\npublic record MyPropertiesRecord(String name, @NestedConfigurationProperty Nested nested) {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/advanced/nestedconfigurationproperties/Nested.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.nestedconfigurationproperties;\n\npublic class Nested {\n\n\tprivate int number;\n\n\t// @fold:on // getters / setters...\n\tpublic int getNumber() {\n\t\treturn this.number;\n\t}\n\n\tpublic void setNumber(int number) {\n\t\tthis.number = number;\n\t}\n\t// @fold:off\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.introducinggraalvmnativeimages.understandingaotprocessing.sourcecodegeneration;\n\npublic class MyBean {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.introducinggraalvmnativeimages.understandingaotprocessing.sourcecodegeneration;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyConfiguration {\n\n\t@Bean\n\tpublic MyBean myBean() {\n\t\treturn new MyBean();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/packaging/nativeimage/introducinggraalvmnativeimages/understandingaotprocessing/sourcecodegeneration/MyConfiguration__BeanDefinitions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.introducinggraalvmnativeimages.understandingaotprocessing.sourcecodegeneration;\n\nimport org.springframework.beans.factory.aot.BeanInstanceSupplier;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\n\n/**\n * Bean definitions for {@link MyConfiguration}.\n */\n@SuppressWarnings(\"javadoc\")\npublic class MyConfiguration__BeanDefinitions {\n\n\t/**\n\t * Get the bean definition for 'myConfiguration'.\n\t */\n\tpublic static BeanDefinition getMyConfigurationBeanDefinition() {\n\t\tClass<?> beanType = MyConfiguration.class;\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);\n\t\tbeanDefinition.setInstanceSupplier(MyConfiguration::new);\n\t\treturn beanDefinition;\n\t}\n\n\t/**\n\t * Get the bean instance supplier for 'myBean'.\n\t */\n\tprivate static BeanInstanceSupplier<MyBean> getMyBeanInstanceSupplier() {\n\t\treturn BeanInstanceSupplier.<MyBean>forFactoryMethod(MyConfiguration.class, \"myBean\")\n\t\t\t.withGenerator((registeredBean) -> registeredBean.getBeanFactory().getBean(MyConfiguration.class).myBean());\n\t}\n\n\t/**\n\t * Get the bean definition for 'myBean'.\n\t */\n\tpublic static BeanDefinition getMyBeanBeanDefinition() {\n\t\tClass<?> beanType = MyBean.class;\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);\n\t\tbeanDefinition.setInstanceSupplier(getMyBeanInstanceSupplier());\n\t\treturn beanDefinition;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/additionalautoconfigurationandslicing/MyJdbcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.additionalautoconfigurationandslicing;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.JdbcTest;\n\n@JdbcTest\n@ImportAutoConfiguration(IntegrationAutoConfiguration.class)\nclass MyJdbcTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredjdbc/MyTransactionalTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredjdbc;\n\nimport org.springframework.boot.jdbc.test.autoconfigure.JdbcTest;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\n@JdbcTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\nclass MyTransactionalTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredjooq/MyJooqTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredjooq;\n\nimport org.jooq.DSLContext;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jooq.test.autoconfigure.JooqTest;\n\n@JooqTest\nclass MyJooqTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate DSLContext dslContext;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredrestclient/MyRestClientServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.autoconfigure.RestClientTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n@RestClientTest(RemoteVehicleDetailsService.class)\nclass MyRestClientServiceTests {\n\n\t@Autowired\n\tprivate RemoteVehicleDetailsService service;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {\n\t\tthis.server.expect(requestTo(\"https://example.com/greet/details\"))\n\t\t\t.andRespond(withSuccess(\"hello\", MediaType.TEXT_PLAIN));\n\t\tString greeting = this.service.callRestService();\n\t\tassertThat(greeting).isEqualTo(\"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredrestclient/MyRestTemplateServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.autoconfigure.RestClientTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n@RestClientTest(org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient.RemoteVehicleDetailsService.class)\nclass MyRestTemplateServiceTests {\n\n\t@Autowired\n\tprivate RemoteVehicleDetailsService service;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {\n\t\tthis.server.expect(requestTo(\"/greet/details\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_PLAIN));\n\t\tString greeting = this.service.callRestService();\n\t\tassertThat(greeting).isEqualTo(\"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredrestclient/RemoteVehicleDetailsService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient;\n\nclass RemoteVehicleDetailsService {\n\n\tString callRestService() {\n\t\treturn \"hello\";\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacassandra/MyDataCassandraTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacassandra;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\n\n@DataCassandraTest\nclass MyDataCassandraTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate SomeRepository repository;\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacassandra/SomeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacassandra;\n\ninterface SomeRepository {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacouchbase/MyDataCouchbaseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacouchbase;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest;\n\n@DataCouchbaseTest\nclass MyDataCouchbaseTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate SomeRepository repository;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacouchbase/SomeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacouchbase;\n\ninterface SomeRepository {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataelasticsearch/MyDataElasticsearchTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataelasticsearch;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;\n\n@DataElasticsearchTest\nclass MyDataElasticsearchTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate SomeRepository repository;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataelasticsearch/SomeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataelasticsearch;\n\npublic interface SomeRepository {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/MyNonTransactionalTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa;\n\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\n@DataJpaTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\nclass MyNonTransactionalTests {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withdb/MyRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withdb;\n\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;\n\n@DataJpaTest\n@AutoConfigureTestDatabase(replace = Replace.NONE)\nclass MyRepositoryTests {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withoutdb/MyRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withoutdb;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;\nimport org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@DataJpaTest\nclass MyRepositoryTests {\n\n\t@Autowired\n\tprivate TestEntityManager entityManager;\n\n\t@Autowired\n\tprivate UserRepository repository;\n\n\t@Test\n\tvoid testExample() {\n\t\tthis.entityManager.persist(new User(\"sboot\", \"1234\"));\n\t\tUser user = this.repository.findByUsername(\"sboot\");\n\t\tassertThat(user.getUsername()).isEqualTo(\"sboot\");\n\t\tassertThat(user.getEmployeeNumber()).isEqualTo(\"1234\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withoutdb/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withoutdb;\n\nclass User {\n\n\tUser(String username, String employeeNumber) {\n\t}\n\n\tString getEmployeeNumber() {\n\t\treturn null;\n\t}\n\n\tString getUsername() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withoutdb/UserRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withoutdb;\n\ninterface UserRepository {\n\n\tUser findByUsername(String username);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataldap/inmemory/MyDataLdapTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataldap.inmemory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest;\nimport org.springframework.ldap.core.LdapTemplate;\n\n@DataLdapTest\nclass MyDataLdapTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate LdapTemplate ldapTemplate;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataldap/server/MyDataLdapTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataldap.server;\n\nimport org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest;\nimport org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration;\n\n@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)\nclass MyDataLdapTests {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatamongodb/MyDataMongoDbTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatamongodb;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest;\nimport org.springframework.data.mongodb.core.MongoTemplate;\n\n@DataMongoTest\nclass MyDataMongoDbTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate MongoTemplate mongoTemplate;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataneo4j/nopropagation/MyDataNeo4jTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataneo4j.nopropagation;\n\nimport org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\n@DataNeo4jTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\nclass MyDataNeo4jTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataneo4j/propagation/MyDataNeo4jTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataneo4j.propagation;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest;\n\n@DataNeo4jTest\nclass MyDataNeo4jTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate SomeRepository repository;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataneo4j/propagation/SomeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataneo4j.propagation;\n\ninterface SomeRepository {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataredis/MyDataRedisTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataredis;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest;\n\n@DataRedisTest\nclass MyDataRedisTests {\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate SomeRepository repository;\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataredis/SomeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataredis;\n\ninterface SomeRepository {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/MyRestDocsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc;\n\nimport org.springframework.boot.restdocs.test.autoconfigure.RestDocsMockMvcConfigurationCustomizer;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;\nimport org.springframework.restdocs.templates.TemplateFormats;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer {\n\n\t@Override\n\tpublic void customize(MockMvcRestDocumentationConfigurer configurer) {\n\t\tconfigurer.snippets().withTemplateFormat(TemplateFormats.markdown());\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/MyResultHandlerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyResultHandlerConfiguration {\n\n\t@Bean\n\tpublic RestDocumentationResultHandler restDocumentation() {\n\t\treturn MockMvcRestDocumentation.document(\"{method-name}\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/assertj/MyUserDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc.assertj;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\n\n@WebMvcTest(UserController.class)\n@AutoConfigureRestDocs\nclass MyUserDocumentationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid listUsers() {\n\t\tassertThat(this.mvc.get().uri(\"/users\").accept(MediaType.TEXT_PLAIN)).hasStatusOk()\n\t\t\t.apply(document(\"list-users\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/assertj/UserController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc.assertj;\n\nclass UserController {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/hamcrest/MyUserDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc.hamcrest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\n\n@WebMvcTest(UserController.class)\n@AutoConfigureRestDocs\nclass MyUserDocumentationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid listUsers() {\n\t\tassertThat(this.mvc.get().uri(\"/users\").accept(MediaType.TEXT_PLAIN)).hasStatusOk()\n\t\t\t.apply(document(\"list-users\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/hamcrest/UserController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc.hamcrest;\n\nclass UserController {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyRestDocsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient;\n\nimport org.springframework.boot.restdocs.test.autoconfigure.RestDocsWebTestClientConfigurationCustomizer;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer {\n\n\t@Override\n\tpublic void customize(WebTestClientRestDocumentationConfigurer configurer) {\n\t\tconfigurer.snippets().withEncoding(\"UTF-8\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyUsersDocumentationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;\n\n@WebFluxTest\n@AutoConfigureRestDocs\nclass MyUsersDocumentationTests {\n\n\t@Autowired\n\tprivate WebTestClient webTestClient;\n\n\t@Test\n\tvoid listUsers() {\n\t\t// @formatter:off\n\t\tthis.webTestClient\n\t\t\t.get().uri(\"/\")\n\t\t.exchange()\n\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t.expectBody()\n\t\t\t.consumeWith(document(\"list-users\"));\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\n\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyWebTestClientBuilderCustomizerConfiguration {\n\n\t@Bean\n\tpublic WebTestClientBuilderCustomizer restDocumentation() {\n\t\treturn (builder) -> builder.entityExchangeResultConsumer(document(\"{method-name}\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/MyWebServiceClientTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webservices.test.autoconfigure.client.WebServiceClientTest;\nimport org.springframework.ws.test.client.MockWebServiceServer;\nimport org.springframework.xml.transform.StringSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.ws.test.client.RequestMatchers.payload;\nimport static org.springframework.ws.test.client.ResponseCreators.withPayload;\n\n@WebServiceClientTest(SomeWebService.class)\nclass MyWebServiceClientTests {\n\n\t@Autowired\n\tprivate MockWebServiceServer server;\n\n\t@Autowired\n\tprivate SomeWebService someWebService;\n\n\t@Test\n\tvoid mockServerCall() {\n\t\t// @formatter:off\n\t\tthis.server\n\t\t\t.expect(payload(new StringSource(\"<request/>\")))\n\t\t\t.andRespond(withPayload(new StringSource(\"<response><status>200</status></response>\")));\n\t\tassertThat(this.someWebService.test())\n\t\t\t.extracting(Response::getStatus)\n\t\t\t.isEqualTo(200);\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/Request.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client;\n\nimport jakarta.xml.bind.annotation.XmlRootElement;\n\n@XmlRootElement(name = \"request\")\nclass Request {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/Response.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client;\n\nimport jakarta.xml.bind.annotation.XmlAccessType;\nimport jakarta.xml.bind.annotation.XmlAccessorType;\nimport jakarta.xml.bind.annotation.XmlRootElement;\n\n@XmlRootElement(name = \"response\")\n@XmlAccessorType(XmlAccessType.FIELD)\nclass Response {\n\n\tprivate int status;\n\n\tint getStatus() {\n\t\treturn this.status;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/SomeWebService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client;\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n@Service\npublic class SomeWebService {\n\n\tprivate final WebServiceTemplate webServiceTemplate;\n\n\tpublic SomeWebService(WebServiceTemplateBuilder builder) {\n\t\tthis.webServiceTemplate = builder.build();\n\t}\n\n\tpublic Response test() {\n\t\treturn (Response) this.webServiceTemplate.marshalSendAndReceive(\"https://example.com\", new Request());\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/server/ExampleEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.server;\n\nimport javax.xml.transform.Source;\n\nimport org.springframework.ws.server.endpoint.annotation.Endpoint;\nimport org.springframework.ws.server.endpoint.annotation.PayloadRoot;\nimport org.springframework.ws.server.endpoint.annotation.ResponsePayload;\nimport org.springframework.xml.transform.StringSource;\n\n@Endpoint\npublic class ExampleEndpoint {\n\n\t@PayloadRoot(localPart = \"ExampleRequest\")\n\t@ResponsePayload\n\tpublic Source handleRequest() {\n\t\treturn new StringSource(\"<ExampleResponse>42</ExampleResponse>\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/server/MyWebServiceServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webservices.test.autoconfigure.server.WebServiceServerTest;\nimport org.springframework.ws.test.server.MockWebServiceClient;\nimport org.springframework.ws.test.server.RequestCreators;\nimport org.springframework.ws.test.server.ResponseMatchers;\nimport org.springframework.xml.transform.StringSource;\n\n@WebServiceServerTest(ExampleEndpoint.class)\nclass MyWebServiceServerTests {\n\n\t@Autowired\n\tprivate MockWebServiceClient client;\n\n\t@Test\n\tvoid mockServerCall() {\n\t\t// @formatter:off\n\t\tthis.client\n\t\t\t.sendRequest(RequestCreators.withPayload(new StringSource(\"<ExampleRequest/>\")))\n\t\t\t.andExpect(ResponseMatchers.payload(new StringSource(\"<ExampleResponse>42</ExampleResponse>\")));\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/detectingwebapptype/MyWebFluxTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.detectingwebapptype;\n\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest(properties = \"spring.main.web-application-type=reactive\")\nclass MyWebFluxTests {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/excludingconfiguration/MyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.excludingconfiguration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Import;\n\n@SpringBootTest\n@Import(MyTestsConfiguration.class)\nclass MyTests {\n\n\t@Test\n\tvoid exampleTest() {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/excludingconfiguration/MyTestsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.excludingconfiguration;\n\nclass MyTestsConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/jmx/MyJmxTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jmx;\n\nimport javax.management.MBeanServer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(properties = \"spring.jmx.enabled=true\")\n@DirtiesContext\nclass MyJmxTests {\n\n\t@Autowired\n\tprivate MBeanServer mBeanServer;\n\n\t@Test\n\tvoid exampleTest() {\n\t\tassertThat(this.mBeanServer.getDomains()).contains(\"java.lang\");\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/jmx/SampleApp.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jmx;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\n\n@SpringBootConfiguration\n@ImportAutoConfiguration(JmxAutoConfiguration.class)\npublic class SampleApp {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/jsontests/MyJsonAssertJTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JacksonTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.within;\n\n@JsonTest\nclass MyJsonAssertJTests {\n\n\t@Autowired\n\tprivate JacksonTester<SomeObject> json;\n\n\t// tag::code[]\n\t@Test\n\tvoid someTest() throws Exception {\n\t\tSomeObject value = new SomeObject(0.152f);\n\t\tassertThat(this.json.write(value)).extractingJsonPathNumberValue(\"@.test.numberValue\")\n\t\t\t.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));\n\t}\n\t// end::code[]\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/jsontests/MyJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JacksonTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@JsonTest\nclass MyJsonTests {\n\n\t@Autowired\n\tprivate JacksonTester<VehicleDetails> json;\n\n\t@Test\n\tvoid serialize() throws Exception {\n\t\tVehicleDetails details = new VehicleDetails(\"Honda\", \"Civic\");\n\t\t// Assert against a `.json` file in the same package as the test\n\t\tassertThat(this.json.write(details)).isEqualToJson(\"expected.json\");\n\t\t// Or use JSON path based assertions\n\t\tassertThat(this.json.write(details)).hasJsonPathStringValue(\"@.make\");\n\t\tassertThat(this.json.write(details)).extractingJsonPathStringValue(\"@.make\").isEqualTo(\"Honda\");\n\t}\n\n\t@Test\n\tvoid deserialize() throws Exception {\n\t\tString content = \"{\\\"make\\\":\\\"Ford\\\",\\\"model\\\":\\\"Focus\\\"}\";\n\t\tassertThat(this.json.parse(content)).isEqualTo(new VehicleDetails(\"Ford\", \"Focus\"));\n\t\tassertThat(this.json.parseObject(content).getMake()).isEqualTo(\"Ford\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/jsontests/SomeObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests;\n\nclass SomeObject {\n\n\tSomeObject(float value) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/jsontests/VehicleDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests;\n\nclass VehicleDetails {\n\n\tprivate final String make;\n\n\tprivate final String model;\n\n\tVehicleDetails(String make, String model) {\n\t\tthis.make = make;\n\t\tthis.model = model;\n\t}\n\n\tString getMake() {\n\t\treturn this.make;\n\t}\n\n\tString getModel() {\n\t\treturn this.model;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springgraphqltests/GraphQlIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springgraphqltests;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.graphql.test.tester.HttpGraphQlTester;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureHttpGraphQlTester\nclass GraphQlIntegrationTests {\n\n\t@Test\n\tvoid shouldGreetWithSpecificName(@Autowired HttpGraphQlTester graphQlTester) {\n\t\tHttpGraphQlTester authenticatedTester = graphQlTester.mutate()\n\t\t\t.webTestClient((client) -> client.defaultHeaders((headers) -> headers.setBasicAuth(\"admin\", \"ilovespring\")))\n\t\t\t.build();\n\t\tauthenticatedTester.document(\"{ greeting(name: \\\"Alice\\\") } \")\n\t\t\t.execute()\n\t\t\t.path(\"greeting\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Hello, Alice!\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springgraphqltests/GreetingControllerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springgraphqltests;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController;\nimport org.springframework.boot.graphql.test.autoconfigure.GraphQlTest;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\n@GraphQlTest(GreetingController.class)\nclass GreetingControllerTests {\n\n\t@Autowired\n\tprivate GraphQlTester graphQlTester;\n\n\t@Test\n\tvoid shouldGreetWithSpecificName() {\n\t\tthis.graphQlTester.document(\"{ greeting(name: \\\"Alice\\\") } \")\n\t\t\t.execute()\n\t\t\t.path(\"greeting\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Hello, Alice!\");\n\t}\n\n\t@Test\n\tvoid shouldGreetWithDefaultName() {\n\t\tthis.graphQlTester.document(\"{ greeting } \")\n\t\t\t.execute()\n\t\t\t.path(\"greeting\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Hello, Spring!\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springmvctests/MyControllerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n@WebMvcTest(UserVehicleController.class)\nclass MyControllerTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid testExample() {\n\t\t// @formatter:off\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\"))\n\t\t\t.willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle\").accept(MediaType.TEXT_PLAIN))\n\t\t\t.hasStatusOk()\n\t\t\t.hasBodyTextEqualTo(\"Honda Civic\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springmvctests/MyHtmlUnitTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests;\n\nimport org.htmlunit.WebClient;\nimport org.htmlunit.html.HtmlPage;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n@WebMvcTest(UserVehicleController.class)\nclass MyHtmlUnitTests {\n\n\t@Autowired\n\tprivate WebClient webClient;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid testExample() throws Exception {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tHtmlPage page = this.webClient.getPage(\"/sboot/vehicle.html\");\n\t\tassertThat(page.getBody().getTextContent()).isEqualTo(\"Honda Civic\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springmvctests/UserVehicleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests;\n\nclass UserVehicleController {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springmvctests/UserVehicleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests;\n\nclass UserVehicleService {\n\n\tVehicleDetails getVehicleDetails(String name) {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springmvctests/VehicleDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests;\n\nclass VehicleDetails {\n\n\tVehicleDetails(String make, String model) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/MyControllerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.mockito.BDDMockito.given;\n\n@WebFluxTest(UserVehicleController.class)\nclass MyControllerTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid testExample() {\n\t\t// @formatter:off\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\"))\n\t\t\t.willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tthis.webClient.get().uri(\"/sboot/vehicle\").accept(MediaType.TEXT_PLAIN).exchange()\n\t\t\t.expectStatus().isOk()\n\t\t\t.expectBody(String.class).isEqualTo(\"Honda Civic\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/UserVehicleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests;\n\nclass UserVehicleController {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/UserVehicleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests;\n\nclass UserVehicleService {\n\n\tVehicleDetails getVehicleDetails(String name) {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/VehicleDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests;\n\nclass VehicleDetails {\n\n\tVehicleDetails(String make, String model) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.data.mongodb.config.EnableMongoAuditing;\n\n@SpringBootApplication\n@EnableMongoAuditing\npublic class MyApplication {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyMongoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.mongodb.config.EnableMongoAuditing;\n\n@Configuration(proxyBeanMethods = false)\n@EnableMongoAuditing\npublic class MyMongoConfiguration {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyWebConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyWebConfiguration {\n\n\t@Bean\n\tpublic WebMvcConfigurer testConfigurer() {\n\t\treturn new WebMvcConfigurer() {\n\t\t\t// ...\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyWebMvcConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@Component\npublic class MyWebMvcConfigurer implements WebMvcConfigurer {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/scan/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing.scan;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.ComponentScan;\n\n@SpringBootApplication\n@ComponentScan({ \"com.example.app\", \"com.example.another\" })\npublic class MyApplication {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/usingapplicationarguments/MyApplicationArgumentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingapplicationarguments;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(args = \"--app.test=one\")\nclass MyApplicationArgumentTests {\n\n\t@Test\n\tvoid applicationArgumentsPopulated(@Autowired ApplicationArguments args) {\n\t\tassertThat(args.getOptionNames()).containsOnly(\"app.test\");\n\t\tassertThat(args.getOptionValues(\"app.test\")).containsOnly(\"one\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/usingmain/always/MyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingmain.always;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod;\n\n@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)\nclass MyApplicationTests {\n\n\t@Test\n\tvoid exampleTest() {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/usingmain/custom/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingmain.custom;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication(MyApplication.class);\n\t\tapplication.setBannerMode(Banner.Mode.OFF);\n\t\tapplication.setAdditionalProfiles(\"myprofile\");\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/usingmain/typical/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingmain.typical;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/withmockenvironment/MyMockMvcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withmockenvironment;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n@SpringBootTest\n@AutoConfigureMockMvc\n@AutoConfigureRestTestClient\n@AutoConfigureWebTestClient\nclass MyMockMvcTests {\n\n\t@Test\n\tvoid testWithMockMvc(@Autowired MockMvc mvc) throws Exception {\n\t\t// @formatter:off\n\t\tmvc.perform(get(\"/\"))\n\t\t\t\t.andExpect(status().isOk())\n\t\t\t\t.andExpect(content().string(\"Hello World\"));\n\t\t// @formatter:on\n\t}\n\n\t@Test // If AssertJ is on the classpath, you can use MockMvcTester\n\tvoid testWithMockMvcTester(@Autowired MockMvcTester mvc) {\n\t\t// @formatter:off\n\t\tassertThat(mvc.get().uri(\"/\"))\n\t\t\t\t.hasStatusOk()\n\t\t\t\t.hasBodyTextEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n\t@Test\n\tvoid testWithRestTestClient(@Autowired RestTestClient restClient) {\n\t\t// @formatter:off\n\t\trestClient\n\t\t\t\t.get().uri(\"/\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus().isOk()\n\t\t\t\t.expectBody(String.class).isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n\t@Test // If you prefer AssertJ, dedicated assertions are available\n\tvoid testWithRestTestClientAssertJ(@Autowired RestTestClient restClient) {\n\t\t// @formatter:off\n\t\tResponseSpec spec = restClient.get().uri(\"/\").exchange();\n\t\tRestTestClientResponse response = RestTestClientResponse.from(spec);\n\t\tassertThat(response).hasStatusOk()\n\t\t\t\t.bodyText().isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n\t@Test // If Spring WebFlux is on the classpath\n\tvoid testWithWebTestClient(@Autowired WebTestClient webClient) {\n\t\t// @formatter:off\n\t\twebClient\n\t\t\t\t.get().uri(\"/\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus().isOk()\n\t\t\t\t.expectBody(String.class).isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/withmockenvironment/MyMockWebTestClientTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withmockenvironment;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n@SpringBootTest\n@AutoConfigureWebTestClient\nclass MyMockWebTestClientTests {\n\n\t@Test\n\tvoid exampleTest(@Autowired WebTestClient webClient) {\n\t\t// @formatter:off\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk()\n\t\t\t.expectBody(String.class).isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortRestTestClientAssertJTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureRestTestClient\nclass MyRandomPortRestTestClientAssertJTests {\n\n\t@Test\n\tvoid exampleTest(@Autowired RestTestClient restClient) {\n\t\t// @formatter:off\n\t\tResponseSpec spec = restClient.get().uri(\"/\").exchange();\n\t\tRestTestClientResponse response = RestTestClientResponse.from(spec);\n\t\tassertThat(response).hasStatusOk().bodyText().isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortRestTestClientTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureRestTestClient\nclass MyRandomPortRestTestClientTests {\n\n\t@Test\n\tvoid exampleTest(@Autowired RestTestClient restClient) {\n\t\t// @formatter:off\n\t\trestClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk()\n\t\t\t.expectBody(String.class).isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortTestRestTemplateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass MyRandomPortTestRestTemplateTests {\n\n\t@Test\n\tvoid exampleTest(@Autowired TestRestTemplate restTemplate) {\n\t\tString body = restTemplate.getForObject(\"/\", String.class);\n\t\tassertThat(body).isEqualTo(\"Hello World\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortWebTestClientTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebTestClient\nclass MyRandomPortWebTestClientTests {\n\n\t@Test\n\tvoid exampleTest(@Autowired WebTestClient webClient) {\n\t\t// @formatter:off\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk()\n\t\t\t.expectBody(String.class).isEqualTo(\"Hello World\");\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/dynamicproperties/MyIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.dynamicproperties;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\n@Testcontainers\n@SpringBootTest\nclass MyIntegrationTests {\n\n\t@Container\n\tstatic Neo4jContainer neo4j = new Neo4jContainer(\"neo4j:5\");\n\n\t@Test\n\tvoid myTest() {\n\t\t// ...\n\t}\n\n\t@DynamicPropertySource\n\tstatic void neo4jProperties(DynamicPropertyRegistry registry) {\n\t\tregistry.add(\"spring.neo4j.uri\", neo4j::getBoltUrl);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importingconfigurationinterfaces/MyContainers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces;\n\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.mongodb.MongoDBContainer;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\ninterface MyContainers {\n\n\t@Container\n\tMongoDBContainer mongoContainer = new MongoDBContainer(\"mongo:5.0\");\n\n\t@Container\n\tNeo4jContainer neo4jContainer = new Neo4jContainer(\"neo4j:5\");\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/importingconfigurationinterfaces/MyTestConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\n\n@TestConfiguration(proxyBeanMethods = false)\n@ImportTestcontainers(MyContainers.class)\nclass MyTestConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/junitextension/MyIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.junitextension;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@Testcontainers\n@SpringBootTest\nclass MyIntegrationTests {\n\n\t@Container\n\tstatic Neo4jContainer neo4j = new Neo4jContainer(\"neo4j:5\");\n\n\t@Test\n\tvoid myTest() {\n\t\t/**/ System.out.println(neo4j);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/serviceconnections/MyIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n@Testcontainers\n@SpringBootTest\nclass MyIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic Neo4jContainer neo4j = new Neo4jContainer(\"neo4j:5\");\n\n\t@Test\n\tvoid myTest() {\n\t\t/**/ System.out.println(neo4j);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/serviceconnections/MyRedisConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections;\n\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.context.annotation.Bean;\n\n@TestConfiguration(proxyBeanMethods = false)\npublic class MyRedisConfiguration {\n\n\t@Bean\n\t@ServiceConnection(name = \"redis\")\n\tpublic GenericContainer<?> redisContainer() {\n\t\treturn new GenericContainer<>(\"redis:7\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/serviceconnections/ssl/MyElasticsearchWithSslIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections.ssl;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.Ssl;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\n\n@Testcontainers\n@DataElasticsearchTest\nclass MyElasticsearchWithSslIntegrationTests {\n\n\t@Ssl\n\t@Container\n\t@ServiceConnection\n\tstatic ElasticsearchContainer elasticsearch = new ElasticsearchContainer(\n\t\t\t\"docker.elastic.co/elasticsearch/elasticsearch:8.17.2\");\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate ElasticsearchTemplate elasticsearchTemplate;\n\n\t@Test\n\tvoid testElasticsearch() {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/serviceconnections/ssl/MyRedisWithSslIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections.ssl;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.data.redis.core.RedisOperations;\n\n@Testcontainers\n@SpringBootTest\nclass MyRedisWithSslIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:client.crt\", privateKey = \"classpath:client.key\")\n\t@PemTrustStore(\"classpath:ca.crt\")\n\tstatic RedisContainer redis = new SecureRedisContainer(\"redis:latest\");\n\n\t@Autowired\n\t@SuppressWarnings(\"unused\")\n\tprivate RedisOperations<Object, Object> operations;\n\n\t@Test\n\tvoid testRedis() {\n\t\t// ...\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/serviceconnections/ssl/SecureRedisContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections.ssl;\n\nimport com.redis.testcontainers.RedisContainer;\n\nclass SecureRedisContainer extends RedisContainer {\n\n\tSecureRedisContainer(String dockerImageName) {\n\t\tsuper(dockerImageName);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/springbeans/MyIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.springbeans;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Import;\n\n@SpringBootTest\n@Import(MyTestConfiguration.class)\nclass MyIntegrationTests {\n\n\t@Autowired\n\tprivate MongoDBContainer mongo;\n\n\t@Test\n\tvoid myTest() {\n\t\t/**/ System.out.println(this.mongo);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/testcontainers/springbeans/MyTestConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.springbeans;\n\nimport org.testcontainers.mongodb.MongoDBContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyTestConfiguration {\n\n\t@Bean\n\tMongoDBContainer mongoDbContainer() {\n\t\treturn new MongoDBContainer(DockerImageName.parse(\"mongo:5.0\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/configdataapplicationcontextinitializer/Config.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.configdataapplicationcontextinitializer;\n\nclass Config {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/configdataapplicationcontextinitializer/MyConfigFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.configdataapplicationcontextinitializer;\n\nimport org.springframework.boot.test.context.ConfigDataApplicationContextInitializer;\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class)\nclass MyConfigFileTests {\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/outputcapture/MyOutputCaptureTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.outputcapture;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass MyOutputCaptureTests {\n\n\t@Test\n\tvoid testName(CapturedOutput output) {\n\t\tSystem.out.println(\"Hello World!\");\n\t\tassertThat(output).contains(\"World\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/testpropertyvalues/MyEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testpropertyvalues;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass MyEnvironmentTests {\n\n\t@Test\n\tvoid testPropertySources() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tTestPropertyValues.of(\"org=Spring\", \"name=Boot\").applyTo(environment);\n\t\tassertThat(environment.getProperty(\"name\")).isEqualTo(\"Boot\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/testresttemplate/MySpringBootTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass MySpringBootTests {\n\n\t@Autowired\n\tprivate TestRestTemplate template;\n\n\t@Test\n\tvoid testRequest() {\n\t\tResponseEntity<String> response = this.template.getForEntity(\"/example\", String.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t// Other assertions to verify the response\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class RestTemplateBuilderConfiguration {\n\n\t\t@Bean\n\t\tRestTemplateBuilder restTemplateBuilder() {\n\t\t\treturn new RestTemplateBuilder().connectTimeout(Duration.ofSeconds(1)).readTimeout(Duration.ofSeconds(1));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/testresttemplate/MySpringBootTestsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate;\n\nimport java.net.URI;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@SpringBootConfiguration(proxyBeanMethods = false)\n@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\tJacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class })\npublic class MySpringBootTestsConfiguration {\n\n\t@RestController\n\tprivate static final class ExampleController {\n\n\t\t@RequestMapping(\"/example\")\n\t\tResponseEntity<String> example() {\n\t\t\treturn ResponseEntity.ok().location(URI.create(\"https://other.example.com/example\")).body(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/utilities/testresttemplate/MyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\nclass MyTests {\n\n\tprivate final TestRestTemplate template = new TestRestTemplate();\n\n\t@Test\n\tvoid testRequest() {\n\t\tResponseEntity<String> response = this.template.getForEntity(\"https://myhost.example.com/example\",\n\t\t\t\tString.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t// Other assertions to verify the response\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/autoconfiguration/disablingspecific/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.autoconfiguration.disablingspecific;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\n\n@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })\npublic class MyApplication {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/devtools/restart/disable/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.devtools.restart.disable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSystem.setProperty(\"spring.devtools.restart.enabled\", \"false\");\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/springbeansanddependencyinjection/multipleconstructors/AccountService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.multipleconstructors;\n\npublic interface AccountService {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/springbeansanddependencyinjection/multipleconstructors/MyAccountService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.multipleconstructors;\n\nimport java.io.PrintStream;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class MyAccountService implements AccountService {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate final RiskAssessor riskAssessor;\n\n\t@SuppressWarnings(\"unused\")\n\tprivate final PrintStream out;\n\n\t@Autowired\n\tpublic MyAccountService(RiskAssessor riskAssessor) {\n\t\tthis.riskAssessor = riskAssessor;\n\t\tthis.out = System.out;\n\t}\n\n\tpublic MyAccountService(RiskAssessor riskAssessor, PrintStream out) {\n\t\tthis.riskAssessor = riskAssessor;\n\t\tthis.out = out;\n\t}\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/springbeansanddependencyinjection/multipleconstructors/RiskAssessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.multipleconstructors;\n\npublic interface RiskAssessor {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/springbeansanddependencyinjection/singleconstructor/AccountService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.singleconstructor;\n\npublic interface AccountService {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/springbeansanddependencyinjection/singleconstructor/MyAccountService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.singleconstructor;\n\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class MyAccountService implements AccountService {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate final RiskAssessor riskAssessor;\n\n\tpublic MyAccountService(RiskAssessor riskAssessor) {\n\t\tthis.riskAssessor = riskAssessor;\n\t}\n\n\t// ...\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/springbeansanddependencyinjection/singleconstructor/RiskAssessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.singleconstructor;\n\npublic interface RiskAssessor {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/structuringyourcode/locatingthemainclass/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/individualannotations/AnotherConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.individualannotations;\n\npublic class AnotherConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/individualannotations/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.individualannotations;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.context.annotation.Import;\n\n@SpringBootConfiguration(proxyBeanMethods = false)\n@EnableAutoConfiguration\n@Import({ SomeConfiguration.class, AnotherConfiguration.class })\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/individualannotations/SomeConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.individualannotations;\n\npublic class SomeConfiguration {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/springapplication/MyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.springapplication;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n// Same as @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan\n@SpringBootApplication\npublic class MyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/graphql/runtimewiring/GreetingController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.graphql.runtimewiring;\n\nimport org.springframework.graphql.data.method.annotation.Argument;\nimport org.springframework.graphql.data.method.annotation.QueryMapping;\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class GreetingController {\n\n\t@QueryMapping\n\tpublic String greeting(@Argument String name) {\n\t\treturn \"Hello, \" + name + \"!\";\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/graphql/transports/rsocket/RSocketGraphQlClientExample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.graphql.transports.rsocket;\n\nimport java.time.Duration;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.graphql.client.RSocketGraphQlClient;\nimport org.springframework.stereotype.Component;\n\n// tag::builder[]\n@Component\npublic class RSocketGraphQlClientExample {\n\n\tprivate final RSocketGraphQlClient graphQlClient;\n\n\tpublic RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {\n\t\tthis.graphQlClient = builder.tcp(\"example.spring.io\", 8181).route(\"graphql\").build();\n\t}\n\t// end::builder[]\n\n\tpublic void rsocketOverTcp() {\n\t\t// tag::request[]\n\t\tMono<Book> book = this.graphQlClient.document(\"{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }\")\n\t\t\t.retrieve(\"bookById\")\n\t\t\t.toEntity(Book.class);\n\t\t// end::request[]\n\t\tbook.block(Duration.ofSeconds(5));\n\t}\n\n\tstatic class Book {\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/reactiveserver/customizing/programmatic/MyNettyWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.reactiveserver.customizing.programmatic;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyNettyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {\n\n\t@Override\n\tpublic void customize(NettyReactiveWebServerFactory factory) {\n\t\tfactory.addServerCustomizers((server) -> server.idleTimeout(Duration.ofSeconds(20)));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/reactiveserver/customizing/programmatic/MyWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.reactiveserver.customizing.programmatic;\n\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> {\n\n\t@Override\n\tpublic void customize(ConfigurableReactiveWebServerFactory server) {\n\t\tserver.setPort(9000);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/Customer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nclass Customer {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/CustomerRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\ninterface CustomerRepository extends ReactiveCrudRepository<Customer, Long> {\n\n\tFlux<Customer> findByUser(User user);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/MyRestController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@RequestMapping(\"/users\")\npublic class MyRestController {\n\n\tprivate final UserRepository userRepository;\n\n\tprivate final CustomerRepository customerRepository;\n\n\tpublic MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {\n\t\tthis.userRepository = userRepository;\n\t\tthis.customerRepository = customerRepository;\n\t}\n\n\t@GetMapping(\"/{userId}\")\n\tpublic Mono<User> getUser(@PathVariable Long userId) {\n\t\treturn this.userRepository.findById(userId);\n\t}\n\n\t@GetMapping(\"/{userId}/customers\")\n\tpublic Flux<Customer> getUserCustomers(@PathVariable Long userId) {\n\t\treturn this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser);\n\t}\n\n\t@DeleteMapping(\"/{userId}\")\n\tpublic Mono<Void> deleteUser(@PathVariable Long userId) {\n\t\treturn this.userRepository.deleteById(userId);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/MyRoutingConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.reactive.function.server.RequestPredicate;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.springframework.web.reactive.function.server.RequestPredicates.accept;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyRoutingConfiguration {\n\n\tprivate static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);\n\n\t@Bean\n\tpublic RouterFunction<ServerResponse> monoRouterFunction(MyUserHandler userHandler) {\n\t\t// @formatter:off\n\t\treturn route()\n\t\t\t\t.GET(\"/{user}\", ACCEPT_JSON, userHandler::getUser)\n\t\t\t\t.GET(\"/{user}/customers\", ACCEPT_JSON, userHandler::getUserCustomers)\n\t\t\t\t.DELETE(\"/{user}\", ACCEPT_JSON, userHandler::deleteUser)\n\t\t\t\t.build();\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/MyUserHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\n@Component\npublic class MyUserHandler {\n\n\tpublic Mono<ServerResponse> getUser(ServerRequest request) {\n\t\t/**/ return ServerResponse.ok().build();\n\t}\n\n\tpublic Mono<ServerResponse> getUserCustomers(ServerRequest request) {\n\t\t/**/ return ServerResponse.ok().build();\n\t}\n\n\tpublic Mono<ServerResponse> deleteUser(ServerRequest request) {\n\t\t/**/ return ServerResponse.ok().build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nimport java.util.List;\n\nclass User {\n\n\tList<Customer> getCustomers() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/UserRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\ninterface UserRepository extends ReactiveCrudRepository<User, Long> {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/errorhandling/MyErrorWebExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux.errorhandling;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.webflux.autoconfigure.error.AbstractErrorWebExceptionHandler;\nimport org.springframework.boot.webflux.error.ErrorAttributes;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.reactive.function.server.ServerResponse.BodyBuilder;\n\n@Component\npublic class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {\n\n\tpublic MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties,\n\t\t\tApplicationContext applicationContext, ServerCodecConfigurer serverCodecConfigurer) {\n\t\tsuper(errorAttributes, webProperties.getResources(), applicationContext);\n\t\tsetMessageReaders(serverCodecConfigurer.getReaders());\n\t\tsetMessageWriters(serverCodecConfigurer.getWriters());\n\t}\n\n\t@Override\n\tprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {\n\t\treturn RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml);\n\t}\n\n\tprivate boolean acceptsXml(ServerRequest request) {\n\t\treturn request.headers().accept().contains(MediaType.APPLICATION_XML);\n\t}\n\n\tpublic Mono<ServerResponse> handleErrorAsXml(ServerRequest request) {\n\t\tBodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\t// ... additional builder calls\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/reactive/webflux/httpcodecs/MyCodecsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux.httpcodecs;\n\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.codec.ServerSentEventHttpMessageReader;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCodecsConfiguration {\n\n\t@Bean\n\tpublic CodecCustomizer myCodecCustomizer() {\n\t\treturn (configurer) -> {\n\t\t\tconfigurer.registerDefaults(false);\n\t\t\tconfigurer.customCodecs().register(new ServerSentEventHttpMessageReader());\n\t\t\t// ...\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/security/oauth2/client/MyOAuthClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.security.oauth2.client;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration(proxyBeanMethods = false)\n@EnableWebSecurity\npublic class MyOAuthClientConfiguration {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\t// @formatter:off\n\t\thttp\n\t\t\t.authorizeHttpRequests((requests) -> requests\n\t\t\t\t.anyRequest().authenticated()\n\t\t\t)\n\t\t\t.oauth2Login((login) -> login\n\t\t\t\t.redirectionEndpoint((endpoint) -> endpoint\n\t\t\t\t\t.baseUri(\"/login/oauth2/callback/*\")\n\t\t\t\t)\n\t\t\t);\n\t\t// @formatter:on\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/security/saml2/relyingparty/MySamlRelyingPartyConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.security.saml2.relyingparty;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySamlRelyingPartyConfiguration {\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\thttp.saml2Login(withDefaults());\n\t\thttp.saml2Logout((saml2) -> saml2.logoutRequest((request) -> request.logoutUrl(\"/SLOService.saml2\"))\n\t\t\t.logoutResponse((response) -> response.logoutUrl(\"/SLOService.saml2\")));\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/security/springwebflux/MyWebFluxSecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.security.springwebflux;\n\nimport org.springframework.boot.security.autoconfigure.web.reactive.PathRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyWebFluxSecurityConfiguration {\n\n\t@Bean\n\tpublic SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\thttp.authorizeExchange((exchange) -> {\n\t\t\texchange.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();\n\t\t\texchange.pathMatchers(\"/foo\", \"/bar\").authenticated();\n\t\t});\n\t\thttp.formLogin(withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/embeddedcontainer/applicationcontext/MyDemoBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.applicationcontext;\n\nimport jakarta.servlet.ServletContext;\n\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.web.context.WebApplicationContext;\n\npublic class MyDemoBean implements ApplicationListener<ApplicationStartedEvent> {\n\n\t@SuppressWarnings(\"unused\")\n\tprivate ServletContext servletContext;\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationStartedEvent event) {\n\t\tApplicationContext applicationContext = event.getApplicationContext();\n\t\tthis.servletContext = ((WebApplicationContext) applicationContext).getServletContext();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/embeddedcontainer/customizing/programmatic/MyTomcatWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.customizing.programmatic;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyTomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {\n\n\t@Override\n\tpublic void customize(TomcatServletWebServerFactory server) {\n\t\tserver.addConnectorCustomizers((connector) -> connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis()));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/embeddedcontainer/customizing/programmatic/MyWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.customizing.programmatic;\n\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {\n\n\t@Override\n\tpublic void customize(ConfigurableServletWebServerFactory server) {\n\t\tserver.setPort(9000);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/embeddedcontainer/customizing/samesite/MySameSiteConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.customizing.samesite;\n\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MySameSiteConfiguration {\n\n\t@Bean\n\tpublic CookieSameSiteSupplier applicationCookieSameSiteSupplier() {\n\t\treturn CookieSameSiteSupplier.ofLax().whenHasNameMatching(\"myapp.*\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/jersey/MyEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.jersey;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\n\nimport org.springframework.stereotype.Component;\n\n@Component\n@Path(\"/hello\")\npublic class MyEndpoint {\n\n\t@GET\n\tpublic String message() {\n\t\treturn \"Hello\";\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/jersey/MyJerseyConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.jersey;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class MyJerseyConfig extends ResourceConfig {\n\n\tpublic MyJerseyConfig() {\n\t\tregister(MyEndpoint.class);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/Customer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nclass Customer {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/CustomerRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nimport java.util.List;\n\nimport org.springframework.data.repository.CrudRepository;\n\ninterface CustomerRepository extends CrudRepository<Customer, Long> {\n\n\tList<Customer> findByUser(User user);\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/MyRestController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nimport java.util.List;\n\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\n@RequestMapping(\"/users\")\npublic class MyRestController {\n\n\tprivate final UserRepository userRepository;\n\n\tprivate final CustomerRepository customerRepository;\n\n\tpublic MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {\n\t\tthis.userRepository = userRepository;\n\t\tthis.customerRepository = customerRepository;\n\t}\n\n\t@GetMapping(\"/{userId}\")\n\tpublic User getUser(@PathVariable Long userId) {\n\t\treturn this.userRepository.findById(userId).get();\n\t}\n\n\t@GetMapping(\"/{userId}/customers\")\n\tpublic List<Customer> getUserCustomers(@PathVariable Long userId) {\n\t\treturn this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();\n\t}\n\n\t@DeleteMapping(\"/{userId}\")\n\tpublic void deleteUser(@PathVariable Long userId) {\n\t\tthis.userRepository.deleteById(userId);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/MyRoutingConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.servlet.function.RequestPredicate;\nimport org.springframework.web.servlet.function.RouterFunction;\nimport org.springframework.web.servlet.function.ServerResponse;\n\nimport static org.springframework.web.servlet.function.RequestPredicates.accept;\nimport static org.springframework.web.servlet.function.RouterFunctions.route;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyRoutingConfiguration {\n\n\tprivate static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);\n\n\t@Bean\n\tpublic RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) {\n\t\t// @formatter:off\n\t\treturn route()\n\t\t\t\t.GET(\"/{user}\", ACCEPT_JSON, userHandler::getUser)\n\t\t\t\t.GET(\"/{user}/customers\", ACCEPT_JSON, userHandler::getUserCustomers)\n\t\t\t\t.DELETE(\"/{user}\", ACCEPT_JSON, userHandler::deleteUser)\n\t\t\t\t.build();\n\t\t// @formatter:on\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/MyUserHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.function.ServerRequest;\nimport org.springframework.web.servlet.function.ServerResponse;\n\n@Component\npublic class MyUserHandler {\n\n\tpublic ServerResponse getUser(ServerRequest request) {\n\t\t/**/ return ServerResponse.ok().build();\n\t}\n\n\tpublic ServerResponse getUserCustomers(ServerRequest request) {\n\t\t/**/ return ServerResponse.ok().build();\n\t}\n\n\tpublic ServerResponse deleteUser(ServerRequest request) {\n\t\t/**/ return ServerResponse.ok().build();\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nimport java.util.List;\n\nclass User {\n\n\tList<Customer> getCustomers() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/UserRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc;\n\nimport org.springframework.data.repository.CrudRepository;\n\ninterface UserRepository extends CrudRepository<User, Long> {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/cors/MyCorsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.cors;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyCorsConfiguration {\n\n\t@Bean\n\tpublic WebMvcConfigurer corsConfigurer() {\n\t\treturn new WebMvcConfigurer() {\n\n\t\t\t@Override\n\t\t\tpublic void addCorsMappings(CorsRegistry registry) {\n\t\t\t\tregistry.addMapping(\"/api/**\");\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/CustomException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling;\n\nclass CustomException extends RuntimeException {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/MyControllerAdvice.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling;\n\nimport jakarta.servlet.RequestDispatcher;\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;\n\n@ControllerAdvice(basePackageClasses = SomeController.class)\npublic class MyControllerAdvice extends ResponseEntityExceptionHandler {\n\n\t@ResponseBody\n\t@ExceptionHandler(MyException.class)\n\tpublic ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {\n\t\tHttpStatus status = getStatus(request);\n\t\treturn new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status);\n\t}\n\n\tprivate HttpStatus getStatus(HttpServletRequest request) {\n\t\tInteger code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);\n\t\tHttpStatus status = HttpStatus.resolve(code);\n\t\treturn (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/MyErrorBody.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling;\n\nclass MyErrorBody {\n\n\tMyErrorBody(int value, String message) {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/MyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling;\n\nclass MyException extends RuntimeException {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/SomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling;\n\nclass SomeController {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpages/MyErrorViewResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpages;\n\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.springframework.boot.webmvc.autoconfigure.error.ErrorViewResolver;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.servlet.ModelAndView;\n\npublic class MyErrorViewResolver implements ErrorViewResolver {\n\n\t@Override\n\tpublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {\n\t\t// Use the request or status to optionally return a ModelAndView\n\t\tif (status == HttpStatus.INSUFFICIENT_STORAGE) {\n\t\t\t// We could add custom model values here\n\t\t\treturn new ModelAndView(\"myview\");\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/MyErrorPagesConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc;\n\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.error.ErrorPageRegistrar;\nimport org.springframework.boot.web.error.ErrorPageRegistry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyErrorPagesConfiguration {\n\n\t@Bean\n\tpublic ErrorPageRegistrar errorPageRegistrar() {\n\t\treturn this::registerErrorPages;\n\t}\n\n\tprivate void registerErrorPages(ErrorPageRegistry registry) {\n\t\tregistry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, \"/400\"));\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/MyFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\n\nimport org.springframework.web.filter.GenericFilterBean;\n\nclass MyFilter extends GenericFilterBean {\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/MyFilterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc;\n\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\n\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyFilterConfiguration {\n\n\t@Bean\n\tpublic FilterRegistrationBean<MyFilter> myFilter() {\n\t\tFilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(new MyFilter());\n\t\t// ...\n\t\tregistration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));\n\t\treturn registration;\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/messageconverters/AdditionalHttpMessageConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.messageconverters;\n\nimport java.io.IOException;\n\nimport org.springframework.http.HttpInputMessage;\nimport org.springframework.http.HttpOutputMessage;\nimport org.springframework.http.converter.AbstractHttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageNotReadableException;\nimport org.springframework.http.converter.HttpMessageNotWritableException;\n\nclass AdditionalHttpMessageConverter extends AbstractHttpMessageConverter<Object> {\n\n\t@Override\n\tprotected boolean supports(Class<?> type) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tprotected Object readInternal(Class<?> type, HttpInputMessage inputMessage)\n\t\t\tthrows IOException, HttpMessageNotReadableException {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected void writeInternal(Object instance, HttpOutputMessage outputMessage)\n\t\t\tthrows IOException, HttpMessageNotWritableException {\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/messageconverters/AnotherHttpMessageConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.messageconverters;\n\nclass AnotherHttpMessageConverter extends AdditionalHttpMessageConverter {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/web/servlet/springmvc/messageconverters/MyHttpMessageConvertersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.messageconverters;\n\nimport java.text.SimpleDateFormat;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyHttpMessageConvertersConfiguration {\n\n\t@Bean\n\tpublic ClientHttpMessageConvertersCustomizer myClientConvertersCustomizer() {\n\t\treturn (clientBuilder) -> clientBuilder.addCustomConverter(new AdditionalHttpMessageConverter())\n\t\t\t.addCustomConverter(new AnotherHttpMessageConverter());\n\t}\n\n\t@Bean\n\tpublic JacksonConverterCustomizer jacksonConverterCustomizer() {\n\t\tJsonMapper jsonMapper = JsonMapper.builder().defaultDateFormat(new SimpleDateFormat(\"yyyy-MM\")).build();\n\t\treturn new JacksonConverterCustomizer(jsonMapper);\n\t}\n\n\t// contribute a custom JSON converter to both client and server\n\tstatic class JacksonConverterCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final JsonMapper jsonMapper;\n\n\t\tJacksonConverterCustomizer(JsonMapper jsonMapper) {\n\t\t\tthis.jsonMapper = jsonMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withJsonConverter(new JacksonJsonHttpMessageConverter(this.jsonMapper));\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withJsonConverter(new JacksonJsonHttpMessageConverter(this.jsonMapper));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/cloudfoundry/customcontextpath/MyCloudFoundryConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.cloudfoundry.customcontextpath\n\nimport jakarta.servlet.GenericServlet\nimport jakarta.servlet.Servlet\nimport jakarta.servlet.ServletContainerInitializer\nimport jakarta.servlet.ServletContext\nimport jakarta.servlet.ServletException\nimport jakarta.servlet.ServletRequest\nimport jakarta.servlet.ServletResponse\nimport org.apache.catalina.Host\nimport org.apache.catalina.core.StandardContext\nimport org.apache.catalina.startup.Tomcat.FixContextListener\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory\nimport org.springframework.boot.web.servlet.ServletContextInitializer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.io.IOException\nimport java.util.Collections.emptySet\n\n@Suppress(\"UNUSED_ANONYMOUS_PARAMETER\")\n@Configuration(proxyBeanMethods = false)\nclass MyCloudFoundryConfiguration {\n\n\t@Bean\n\tfun servletWebServerFactory(): TomcatServletWebServerFactory {\n\t\treturn object : TomcatServletWebServerFactory() {\n\n\t\t\toverride fun prepareContext(host: Host, initializers: Array<ServletContextInitializer>, tempDirs: TempDirs) {\n\t\t\t\tsuper.prepareContext(host, initializers, tempDirs)\n\t\t\t\tval child = StandardContext()\n\t\t\t\tchild.addLifecycleListener(FixContextListener())\n\t\t\t\tchild.path = \"/cloudfoundryapplication\"\n\t\t\t\tval initializer = getServletContextInitializer(contextPath)\n\t\t\t\tchild.addServletContainerInitializer(initializer, emptySet())\n\t\t\t\tchild.crossContext = true\n\t\t\t\thost.addChild(child)\n\t\t\t}\n\n\t\t}\n\t}\n\n\tprivate fun getServletContextInitializer(contextPath: String): ServletContainerInitializer {\n\t\treturn ServletContainerInitializer { classes: Set<Class<*>?>?, context: ServletContext ->\n\t\t\tval servlet: Servlet = object : GenericServlet() {\n\n\t\t\t\t@Throws(ServletException::class, IOException::class)\n\t\t\t\toverride fun service(req: ServletRequest, res: ServletResponse) {\n\t\t\t\t\tval servletContext = req.servletContext.getContext(contextPath)\n\t\t\t\t\tservletContext.getRequestDispatcher(\"/cloudfoundryapplication\").forward(req, res)\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tcontext.addServlet(\"cloudfoundry\", servlet).addMapping(\"/*\")\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/cloudfoundry/customcontextpath/MyReactiveCloudFoundryConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.actuator.cloudfoundry.customcontextpath\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties\nimport org.springframework.boot.webflux.autoconfigure.WebFluxProperties\nimport org.springframework.context.ApplicationContext\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.server.reactive.ContextPathCompositeHandler\nimport org.springframework.http.server.reactive.HttpHandler\nimport org.springframework.http.server.reactive.ServerHttpRequest\nimport org.springframework.http.server.reactive.ServerHttpResponse\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder\nimport reactor.core.publisher.Mono\n\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(WebFluxProperties::class)\nclass MyReactiveCloudFoundryConfiguration {\n\n\t@Bean\n\tfun httpHandler(applicationContext: ApplicationContext, properties: WebFluxProperties): HttpHandler {\n\t\tval httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build()\n\t\treturn CloudFoundryHttpHandler(properties.basePath ?: \"/\", httpHandler)\n\t}\n\n\tprivate class CloudFoundryHttpHandler(basePath: String, private val delegate: HttpHandler) : HttpHandler {\n\t\tprivate val contextPathDelegate = ContextPathCompositeHandler(mapOf(basePath to delegate))\n\n\t\toverride fun handle(request: ServerHttpRequest, response: ServerHttpResponse): Mono<Void> {\n\t\t\t// Remove underlying context path first (e.g. Servlet container)\n\t\t\tval path = request.path.pathWithinApplication().value()\n\t\t\treturn if (path.startsWith(\"/cloudfoundryapplication\")) {\n\t\t\t\tdelegate.handle(request, response)\n\t\t\t} else {\n\t\t\t\tcontextPathDelegate.handle(request, response)\n\t\t\t}\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/health/reactivehealthindicators/MyReactiveHealthIndicator.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.health.reactivehealthindicators\n\nimport org.springframework.boot.health.contributor.Health\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator\nimport org.springframework.stereotype.Component\nimport reactor.core.publisher.Mono\n\n@Component\nclass MyReactiveHealthIndicator : ReactiveHealthIndicator {\n\n\toverride fun health(): Mono<Health> {\n\t\t// @formatter:off\n\t\treturn doHealthCheck().onErrorResume { exception: Throwable ->\n\t\t\tMono.just(Health.Builder().down(exception).build())\n\t\t}\n\t\t// @formatter:on\n\t}\n\n\tprivate fun doHealthCheck(): Mono<Health> {\n\t\t// perform some specific health check\n\t\treturn  /**/ Mono.empty()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/health/writingcustomhealthindicators/MyHealthIndicator.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.health.writingcustomhealthindicators\n\nimport org.springframework.boot.health.contributor.Health\nimport org.springframework.boot.health.contributor.HealthIndicator\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyHealthIndicator : HealthIndicator {\n\n\toverride fun health(): Health {\n\t\tval errorCode = check()\n\t\tif (errorCode != 0) {\n\t\t\treturn Health.down().withDetail(\"Error Code\", errorCode).build()\n\t\t}\n\t\treturn Health.up().build()\n\t}\n\n\tprivate fun check(): Int {\n\t\t// perform some specific health check\n\t\treturn  /**/ 0\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/implementingcustom/CustomData.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.implementingcustom\n\nclass CustomData(val name: String, val counter: Int)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/implementingcustom/MyEndpoint.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.implementingcustom\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation\n\n@Endpoint(id = \"custom\")\n@Suppress(\"UNUSED_PARAMETER\")\nclass MyEndpoint {\n\n\t// tag::read[]\n\t@ReadOperation\n\tfun getData(): CustomData {\n\t\treturn CustomData(\"test\", 5)\n\t}\n\t// end::read[]\n\n\t// tag::write[]\n\t@WriteOperation\n\tfun updateData(name: String?, counter: Int) {\n\t\t// injects \"test\" and 42\n\t}\n\t// end::write[]\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/info/writingcustominfocontributors/MyInfoContributor.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.info.writingcustominfocontributors\n\nimport org.springframework.boot.actuate.info.Info\nimport org.springframework.boot.actuate.info.InfoContributor\nimport org.springframework.stereotype.Component\nimport java.util.Collections\n\n@Component\nclass MyInfoContributor : InfoContributor {\n\n\toverride fun contribute(builder: Info.Builder) {\n\t\tbuilder.withDetail(\"example\", Collections.singletonMap(\"key\", \"value\"))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/security/exposeall/MySecurityConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.security.exposeall\n\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity\nimport org.springframework.security.web.SecurityFilterChain\n\n@Configuration(proxyBeanMethods = false)\nclass MySecurityConfiguration {\n\n\t@Bean\n\tfun securityFilterChain(http: HttpSecurity): SecurityFilterChain {\n\t\thttp.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests { requests ->\n\t\t\trequests.anyRequest().permitAll()\n\t\t}\n\t\treturn http.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/endpoints/security/typical/MySecurityConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.endpoints.security.typical\n\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.security.config.Customizer.withDefaults\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity\nimport org.springframework.security.web.SecurityFilterChain\n\n@Configuration(proxyBeanMethods = false)\nclass MySecurityConfiguration {\n\n\t@Bean\n\tfun securityFilterChain(http: HttpSecurity): SecurityFilterChain {\n\t\thttp.securityMatcher(EndpointRequest.toAnyEndpoint()).authorizeHttpRequests { requests ->\n\t\t\trequests.anyRequest().hasRole(\"ENDPOINT_ADMIN\")\n\t\t}\n\t\thttp.httpBasic(withDefaults())\n\t\treturn http.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/loggers/opentelemetry/OpenTelemetryAppenderInitializer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.loggers.opentelemetry\n\nimport io.opentelemetry.api.OpenTelemetry\nimport io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender\nimport org.springframework.beans.factory.InitializingBean\nimport org.springframework.stereotype.Component\n\n@Component\nclass OpenTelemetryAppenderInitializer(\n\tprivate val openTelemetry: OpenTelemetry\n) : InitializingBean {\n\n\toverride fun afterPropertiesSet() = OpenTelemetryAppender.install(openTelemetry)\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/customizing/MyMetricsFilterConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.customizing\n\nimport io.micrometer.core.instrument.config.MeterFilter\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyMetricsFilterConfiguration {\n\n\t@Bean\n\tfun renameRegionTagMeterFilter(): MeterFilter {\n\t\treturn MeterFilter.renameTag(\"com.example\", \"mytag.region\", \"mytag.area\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/export/graphite/MyGraphiteConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.export.graphite\n\nimport io.micrometer.core.instrument.Clock\nimport io.micrometer.core.instrument.Meter\nimport io.micrometer.core.instrument.config.NamingConvention\nimport io.micrometer.core.instrument.util.HierarchicalNameMapper\nimport io.micrometer.graphite.GraphiteConfig\nimport io.micrometer.graphite.GraphiteMeterRegistry\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyGraphiteConfiguration {\n\n\t@Bean\n\tfun graphiteMeterRegistry(config: GraphiteConfig, clock: Clock): GraphiteMeterRegistry {\n\t\treturn GraphiteMeterRegistry(config, clock, this::toHierarchicalName)\n\t}\n\tprivate fun toHierarchicalName(id: Meter.Id, convention: NamingConvention): String {\n\t\treturn  /**/ HierarchicalNameMapper.DEFAULT.toHierarchicalName(id, convention)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/export/jmx/MyJmxConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.export.jmx\n\nimport io.micrometer.core.instrument.Clock\nimport io.micrometer.core.instrument.Meter\nimport io.micrometer.core.instrument.config.NamingConvention\nimport io.micrometer.core.instrument.util.HierarchicalNameMapper\nimport io.micrometer.jmx.JmxConfig\nimport io.micrometer.jmx.JmxMeterRegistry\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyJmxConfiguration {\n\n\t@Bean\n\tfun jmxMeterRegistry(config: JmxConfig, clock: Clock): JmxMeterRegistry {\n\t\treturn JmxMeterRegistry(config, clock, this::toHierarchicalName)\n\t}\n\n\tprivate fun toHierarchicalName(id: Meter.Id, convention: NamingConvention): String {\n\t\treturn  /**/ HierarchicalNameMapper.DEFAULT.toHierarchicalName(id, convention)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/gettingstarted/commontags/MyMeterRegistryConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.gettingstarted.commontags\n\nimport io.micrometer.core.instrument.MeterRegistry\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyMeterRegistryConfiguration {\n\n\t@Bean\n\tfun metricsCommonTags(): MeterRegistryCustomizer<MeterRegistry> {\n\t\treturn MeterRegistryCustomizer { registry ->\n\t\t\tregistry.config().commonTags(\"region\", \"us-east-1\")\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/gettingstarted/specifictype/MyMeterRegistryConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.gettingstarted.specifictype\n\nimport io.micrometer.core.instrument.Meter\nimport io.micrometer.core.instrument.config.NamingConvention\nimport io.micrometer.graphite.GraphiteMeterRegistry\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyMeterRegistryConfiguration {\n\n\t@Bean\n\tfun graphiteMetricsNamingConvention(): MeterRegistryCustomizer<GraphiteMeterRegistry> {\n\t\treturn MeterRegistryCustomizer { registry: GraphiteMeterRegistry ->\n\t\t\tregistry.config().namingConvention(this::name)\n\t\t}\n\t}\n\n\tprivate fun name(name: String, type: Meter.Type, baseUnit: String?): String {\n\t\treturn  /**/ NamingConvention.snakeCase.name(name, type, baseUnit)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/registeringcustom/Dictionary.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom\n\ninternal class Dictionary {\n\n\tval words: List<String>\n\t\tget() = emptyList()\n\n\tcompanion object {\n\t\tfun load(): Dictionary {\n\t\t\treturn Dictionary()\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/registeringcustom/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom\n\nimport io.micrometer.core.instrument.MeterRegistry\nimport io.micrometer.core.instrument.Tags\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(registry: MeterRegistry) {\n\n\tprivate val dictionary: Dictionary\n\n\tinit {\n\t\tdictionary = Dictionary.load()\n\t\tregistry.gauge(\"dictionary.size\", Tags.empty(), dictionary.words.size)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/registeringcustom/MyMeterBinderConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom\n\nimport io.micrometer.core.instrument.Gauge\nimport io.micrometer.core.instrument.binder.MeterBinder\nimport org.springframework.context.annotation.Bean\n\nclass MyMeterBinderConfiguration {\n\n\t@Bean\n\tfun queueSize(queue: Queue): MeterBinder {\n\t\treturn MeterBinder { registry ->\n\t\t\tGauge.builder(\"queueSize\", queue::size).register(registry)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/registeringcustom/Queue.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.registeringcustom\n\nclass Queue {\n\n\tfun size(): Int {\n\t\treturn 5\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/supported/mongodb/command/CustomCommandTagsProvider.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.command\n\nimport com.mongodb.event.CommandEvent\nimport io.micrometer.core.instrument.Tag\nimport io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider\n\nclass CustomCommandTagsProvider : MongoCommandTagsProvider {\n\n\toverride fun commandTags(commandEvent: CommandEvent): Iterable<Tag> {\n\t\treturn emptyList()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/supported/mongodb/command/MyCommandTagsProviderConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.command\n\nimport io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyCommandTagsProviderConfiguration {\n\n\t@Bean\n\tfun customCommandTagsProvider(): MongoCommandTagsProvider? {\n\t\treturn CustomCommandTagsProvider()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/supported/mongodb/connectionpool/CustomConnectionPoolTagsProvider.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.connectionpool\n\nimport com.mongodb.event.ConnectionPoolCreatedEvent\nimport io.micrometer.core.instrument.Tag\nimport io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider\n\nclass CustomConnectionPoolTagsProvider : MongoConnectionPoolTagsProvider {\n\n\toverride fun connectionPoolTags(event: ConnectionPoolCreatedEvent): Iterable<Tag> {\n\t\treturn emptyList()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/metrics/supported/mongodb/connectionpool/MyConnectionPoolTagsProviderConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.metrics.supported.mongodb.connectionpool\n\nimport io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyConnectionPoolTagsProviderConfiguration {\n\n\t@Bean\n\tfun customConnectionPoolTagsProvider(): MongoConnectionPoolTagsProvider {\n\t\treturn CustomConnectionPoolTagsProvider()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/micrometertracing/baggage/CreatingBaggage.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.micrometertracing.baggage\n\nimport io.micrometer.tracing.Tracer\nimport org.springframework.stereotype.Component\n\n@Component\nclass CreatingBaggage(private val tracer: Tracer) {\n\n\tfun doSomething() {\n\t\ttracer.createBaggageInScope(\"baggage1\", \"value1\").use {\n\t\t\t// Business logic\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/micrometertracing/creatingspans/CustomObservation.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.micrometertracing.creatingspans\n\nimport io.micrometer.observation.Observation\nimport io.micrometer.observation.ObservationRegistry\nimport org.springframework.stereotype.Component\n\n@Component\nclass CustomObservation(private val observationRegistry: ObservationRegistry) {\n\n\tfun someOperation() {\n\t\tObservation.createNotStarted(\"some-operation\", observationRegistry)\n\t\t\t.lowCardinalityKeyValue(\"some-tag\", \"some-value\")\n\t\t\t.observe {\n\t\t\t\t// Business logic ...\n\t\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/micrometertracing/gettingstarted/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.micrometertracing.gettingstarted\n\nimport org.apache.commons.logging.Log\nimport org.apache.commons.logging.LogFactory\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.web.bind.annotation.RequestMapping\nimport org.springframework.web.bind.annotation.RestController\n\n@RestController\n@SpringBootApplication\nclass MyApplication {\n\n\tprivate val logger: Log = LogFactory.getLog(MyApplication::class.java)\n\n\t@RequestMapping(\"/\")\n\tfun home(): String {\n\t\tlogger.info(\"home() has been called\")\n\t\treturn \"Hello, World!\"\n\t}\n\n}\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/observability/MyCustomObservation.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability\n\nimport io.micrometer.observation.Observation\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyCustomObservation(private val observationRegistry: ObservationRegistry) {\n\n\tfun doSomething() {\n\t\tObservation.createNotStarted(\"doSomething\", observationRegistry)\n\t\t\t.lowCardinalityKeyValue(\"locale\", \"en-US\")\n\t\t\t.highCardinalityKeyValue(\"userId\", \"42\")\n\t\t\t.observe {\n\t\t\t\t// Execute business logic here\n\t\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/observability/contextpropagation/ContextPropagationConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability.contextpropagation\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.core.task.support.ContextPropagatingTaskDecorator\n\n@Configuration(proxyBeanMethods = false)\nclass ContextPropagationConfiguration {\n\n\t@Bean\n\tfun contextPropagatingTaskDecorator(): ContextPropagatingTaskDecorator {\n\t\treturn ContextPropagatingTaskDecorator()\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/actuator/observability/preventingobservations/MyObservationPredicate.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.actuator.observability.preventingobservations\n\nimport io.micrometer.observation.Observation.Context\nimport io.micrometer.observation.ObservationPredicate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyObservationPredicate : ObservationPredicate {\n\n\toverride fun test(name: String, context: Context): Boolean {\n\t\treturn !name.contains(\"denied\")\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/MyMessagingProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport java.util.Arrays\n\n@ConfigurationProperties(\"my.messaging\")\nclass MyMessagingProperties(\n\n\tval addresses: List<String> = ArrayList(Arrays.asList(\"a\", \"b\")),\n\n\tvar containerType: ContainerType = ContainerType.SIMPLE) {\n\n\tenum class ContainerType {\n\t\tSIMPLE, DIRECT\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/MyServerProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my.server\")\nclass MyServerProperties(\n\n\t/**\n\t * Name of the server.\n\t */\n\tvar name: String,\n\n\t/**\n\t * IP address to listen to.\n\t */\n\tvar ip: String = \"127.0.0.1\",\n\n\t/**\n\t * Port to listen to.\n\t */\n\tvar port: Int = 9797)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/nestedproperties/MyServerProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration.nestedproperties\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my.server\")\nclass MyServerProperties(\n\tvar name: String,\n\tvar host: Host) {\n\n\tclass Host(val ip: String, val port: Int = 0)\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/appendix/configurationmetadata/annotationprocessor/automaticmetadatageneration/source/Host.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.annotationprocessor.automaticmetadatageneration.source\n\nimport org.springframework.boot.context.properties.ConfigurationPropertiesSource\n\n@ConfigurationPropertiesSource\nclass Host {\n\n\t/**\n\t * IP address to listen to.\n\t */\n\tvar ip: String = \"127.0.0.1\"\n\n\t/**\n\t * Port to listener to.\n\t */\n\tvar port = 9797\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/appendix/configurationmetadata/format/property/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.format.property\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.DeprecatedConfigurationProperty\n\n@ConfigurationProperties(\"my.app\")\nclass MyProperties(val name: String?) {\n\n\tvar target: String? = null\n\t\t@Deprecated(\"\") @DeprecatedConfigurationProperty(replacement = \"my.app.name\", since = \"1.2.0\") get\n\t\t@Deprecated(\"\") set\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/appendix/configurationmetadata/manualhints/valuehint/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.appendix.configurationmetadata.manualhints.valuehint\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my\")\nclass MyProperties(val contexts: Map<String, Int>)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/buildtoolplugins/otherbuildsystems/examplerepackageimplementation/MyBuildTool.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.buildtoolplugins.otherbuildsystems.examplerepackageimplementation\n\nimport org.springframework.boot.loader.tools.Library\nimport org.springframework.boot.loader.tools.LibraryCallback\nimport org.springframework.boot.loader.tools.LibraryScope\nimport org.springframework.boot.loader.tools.Repackager\nimport java.io.File\nimport java.io.IOException\n\nclass MyBuildTool {\n\n\t@Throws(IOException::class)\n\tfun build() {\n\t\tval sourceJarFile: File =  /**/File(\".\")\n\t\tval repackager = Repackager(sourceJarFile)\n\t\trepackager.setBackupSource(false)\n\t\trepackager.repackage { callback: LibraryCallback -> getLibraries(callback) }\n\t}\n\n\t@Throws(IOException::class)\n\tprivate fun getLibraries(callback: LibraryCallback) {\n\t\t// Build system specific implementation, callback for each dependency\n\t\tfor (nestedJar in getCompileScopeJars()) {\n\t\t\tcallback.library(Library(nestedJar, LibraryScope.COMPILE))\n\t\t}\n\t\t// ...\n\t}\n\n\tprivate fun getCompileScopeJars(): List<File> {\n\t\treturn  /**/ listOf()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/cassandra/connecting/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.cassandra.connecting\n\nimport org.springframework.data.cassandra.core.CassandraTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val template: CassandraTemplate) {\n\n\t// @fold:on // ...\n\tfun someMethod(): Long {\n\t\treturn template.count(User::class.java)\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/cassandra/connecting/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.cassandra.connecting\n\nclass User\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/couchbase/repositories/CouchbaseProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories\n\nclass CouchbaseProperties\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories\n\nimport org.springframework.data.couchbase.core.CouchbaseTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val template: CouchbaseTemplate) {\n\n\t// @fold:on // ...\n\tfun someMethod(): String {\n\t\treturn template.bucketName\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyConverter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories\n\nimport org.springframework.core.convert.converter.Converter\n\ninternal class MyConverter : Converter<CouchbaseProperties, Boolean> {\n\n\toverride fun convert(value: CouchbaseProperties): Boolean {\n\t\treturn true\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.couchbase.repositories\n\nimport org.assertj.core.util.Arrays\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.couchbase.config.BeanNames\nimport org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions\n\n@Configuration(proxyBeanMethods = false)\nclass MyCouchbaseConfiguration {\n\n\t@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)\n\tfun myCustomConversions(): CouchbaseCustomConversions {\n\t\treturn CouchbaseCustomConversions(Arrays.asList(MyConverter()))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/elasticsearch/connectingusingspringdata/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata\n\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val template: org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate ) {\n\n\t// @fold:on // ...\n\tfun someMethod(id: String): Boolean {\n\t\treturn template.exists(id, User::class.java)\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/elasticsearch/connectingusingspringdata/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata\n\nclass User\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/ldap/repositories/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.ldap.repositories\n\nimport org.springframework.ldap.core.LdapTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val template: LdapTemplate) {\n\n\t// @fold:on // ...\n\tfun someMethod(): List<User> {\n\t\treturn template.findAll(User::class.java)\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/ldap/repositories/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.ldap.repositories\n\nclass User\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/mongodb/connecting/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.connecting\n\nimport com.mongodb.client.MongoCollection\nimport org.bson.Document\nimport org.springframework.data.mongodb.MongoDatabaseFactory\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val mongo: MongoDatabaseFactory) {\n\n\t// @fold:on // ...\n\tfun someMethod(): MongoCollection<Document> {\n\t\tval db = mongo.mongoDatabase\n\t\treturn db.getCollection(\"users\")\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/mongodb/repositories/City.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.repositories\n\nclass City\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/mongodb/repositories/CityRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.repositories\n\nimport org.springframework.data.domain.Page\nimport org.springframework.data.domain.Pageable\nimport org.springframework.data.repository.Repository\n\ninterface CityRepository :\n\tRepository<City, Long> {\n\tfun findAll(pageable: Pageable?): Page<City>\n\tfun findByNameAndStateAllIgnoringCase(name: String, state: String): City?\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/mongodb/template/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.mongodb.template\n\nimport com.mongodb.client.MongoCollection\nimport org.bson.Document\nimport org.springframework.data.mongodb.core.MongoTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val mongoTemplate: MongoTemplate) {\n\n\t// @fold:on // ...\n\tfun someMethod(): MongoCollection<Document> {\n\t\treturn mongoTemplate.getCollection(\"users\")\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/neo4j/connecting/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.connecting\n\nimport org.neo4j.driver.Driver\nimport org.neo4j.driver.TransactionContext\nimport org.neo4j.driver.Values\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val driver: Driver) {\n\t// @fold:on // ...\n\tfun someMethod(message: String?): String {\n\t\tdriver.session().use { session ->\n\t\t\treturn@someMethod session.executeWrite { transaction: TransactionContext ->\n\t\t\t\ttransaction\n\t\t\t\t\t.run(\n\t\t\t\t\t\t\"CREATE (a:Greeting) SET a.message = \\$message RETURN a.message + ', from node ' + id(a)\",\n\t\t\t\t\t\tValues.parameters(\"message\", message)\n\t\t\t\t\t)\n\t\t\t\t\t.single()[0].asString()\n\t\t\t}\n\t\t}\n\t}\n\t// @fold:off\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/neo4j/repositories/City.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.repositories\n\nclass City\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/neo4j/repositories/CityRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.repositories\n\nimport org.springframework.data.neo4j.repository.Neo4jRepository\nimport java.util.Optional\n\ninterface CityRepository : Neo4jRepository<City, Long> {\n\n\tfun findOneByNameAndState(name: String?, state: String?): Optional<City?>?\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/neo4j/repositories/MyNeo4jConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.neo4j.repositories\n\nimport org.neo4j.driver.Driver\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider\nimport org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager\n\n@Configuration(proxyBeanMethods = false)\nclass MyNeo4jConfiguration {\n\n\t@Bean\n\tfun reactiveTransactionManager(driver: Driver,\n\t\t\tdatabaseNameProvider: ReactiveDatabaseSelectionProvider): ReactiveNeo4jTransactionManager {\n\t\treturn ReactiveNeo4jTransactionManager(driver, databaseNameProvider)\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/nosql/redis/connecting/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.nosql.redis.connecting\n\nimport org.springframework.data.redis.core.StringRedisTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val template: StringRedisTemplate) {\n\n\t// @fold:on // ...\n\tfun someMethod(): Boolean {\n\t\treturn template.hasKey(\"spring\")\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/h2webconsole/springsecurity/DevProfileSecurityConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.h2webconsole.springsecurity\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.context.annotation.Profile\nimport org.springframework.core.Ordered\nimport org.springframework.core.annotation.Order\nimport org.springframework.security.config.Customizer\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity\nimport org.springframework.security.web.SecurityFilterChain\n\n@Profile(\"dev\")\n@Configuration(proxyBeanMethods = false)\nclass DevProfileSecurityConfiguration {\n\n\t@Bean\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tfun h2ConsoleSecurityFilterChain(http: HttpSecurity): SecurityFilterChain {\n\t\treturn http.authorizeHttpRequests(yourCustomAuthorization())\n\t\t\t.csrf { csrf -> csrf.disable() }\n\t\t\t.headers { headers -> headers.frameOptions { frameOptions -> frameOptions.sameOrigin() } }\n\t\t\t.build()\n\t}\n\n\t// tag::customizer[]\n\tprivate fun <T> yourCustomAuthorization(): Customizer<T> {\n\t\treturn Customizer.withDefaults()\n\t}\n\t// end::customizer[]\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jdbcclient/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jdbcclient\n\nimport org.springframework.jdbc.core.simple.JdbcClient\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val jdbcClient: JdbcClient) {\n\n\tfun doSomething() {\n\t\tjdbcClient.sql(\"delete from customer\").update()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jdbctemplate/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jdbctemplate\n\nimport org.springframework.jdbc.core.JdbcTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val jdbcTemplate: JdbcTemplate) {\n\n\tfun doSomething() {\n\t\tjdbcTemplate.execute(\"delete from customer\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jooq/dslcontext/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jooq.dslcontext\n\nimport org.jooq.DSLContext\nimport org.springframework.stereotype.Component\nimport java.util.GregorianCalendar\n\n@Component\nclass MyBean(private val create: DSLContext) {\n\n\t// tag::method[]\n\tfun authorsBornAfter1980(): List<GregorianCalendar> {\n\t\treturn create.selectFrom<Tables.TAuthorRecord>(Tables.AUTHOR)\n\t\t\t.where(Tables.AUTHOR?.DATE_OF_BIRTH?.greaterThan(GregorianCalendar(1980, 0, 1)))\n\t\t\t.fetch(Tables.AUTHOR?.DATE_OF_BIRTH)\n\t}\n\t// end::method[]\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jooq/dslcontext/Tables.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jooq.dslcontext\n\nimport org.jooq.Name\nimport org.jooq.Table\nimport org.jooq.TableField\nimport org.jooq.impl.TableImpl\nimport org.jooq.impl.TableRecordImpl\nimport java.util.GregorianCalendar\n\nobject Tables {\n\n\tval AUTHOR: TAuthor? = null\n\n\tabstract class TAuthor(name: Name?) : TableImpl<TAuthorRecord?>(name) {\n\t\tval DATE_OF_BIRTH: TableField<TAuthorRecord, GregorianCalendar>? = null\n\t}\n\n\tabstract class TAuthorRecord(table: Table<TAuthorRecord?>?) : TableRecordImpl<TAuthorRecord?>(table)\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jpaandspringdata/entityclasses/City.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses\n\nimport jakarta.persistence.Column\nimport jakarta.persistence.Entity\nimport jakarta.persistence.GeneratedValue\nimport jakarta.persistence.Id\nimport java.io.Serializable\n\n@Entity\nclass City : Serializable {\n\n\t@Id\n\t@GeneratedValue\n\tprivate val id: Long? = null\n\n\t@Column(nullable = false)\n\tvar name: String? = null\n\t\tprivate set\n\n\t// ... etc\n\t@Column(nullable = false)\n\tvar state: String? = null\n\t\tprivate set\n\n\t// ... additional members, often include @OneToMany mappings\n\n\tprotected constructor() {\n\t\t// no-args constructor required by JPA spec\n\t\t// this one is protected since it should not be used directly\n\t}\n\n\tconstructor(name: String?, state: String?) {\n\t\tthis.name = name\n\t\tthis.state = state\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jpaandspringdata/entityclasses/Country.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses\n\nimport jakarta.persistence.Column\nimport jakarta.persistence.Entity\nimport jakarta.persistence.GeneratedValue\nimport jakarta.persistence.Id\nimport org.hibernate.envers.Audited\nimport java.io.Serializable\n\n@Entity\nclass Country : Serializable {\n\n\t@Id\n\t@GeneratedValue\n\tvar id: Long? = null\n\n\t@Audited\n\t@Column(nullable = false)\n\tvar name: String? = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jpaandspringdata/enversrepositories/CountryRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.enversrepositories\n\nimport org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.Country\nimport org.springframework.data.domain.Page\nimport org.springframework.data.domain.Pageable\nimport org.springframework.data.repository.Repository\nimport org.springframework.data.repository.history.RevisionRepository\n\ninterface CountryRepository :\n\t\tRevisionRepository<Country, Long, Int>,\n\t\tRepository<Country, Long> {\n\n\tfun findAll(pageable: Pageable?): Page<Country>?\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/jpaandspringdata/repositories/CityRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.jpaandspringdata.repositories\n\nimport org.springframework.boot.docs.data.sql.jpaandspringdata.entityclasses.City\nimport org.springframework.data.domain.Page\nimport org.springframework.data.domain.Pageable\nimport org.springframework.data.repository.Repository\n\ninterface CityRepository : Repository<City, Long> {\n\n\tfun findAll(pageable: Pageable?): Page<City>?\n\n\tfun findByNameAndStateAllIgnoringCase(name: String?, state: String?): City?\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/r2dbc/MyPostgresR2dbcConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc\n\nimport io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider\nimport org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyPostgresR2dbcConfiguration {\n\n\t@Bean\n\tfun postgresCustomizer(): ConnectionFactoryOptionsBuilderCustomizer {\n\t\tval options: MutableMap<String, String> = HashMap()\n\t\toptions[\"lock_timeout\"] = \"30s\"\n\t\toptions[\"statement_timeout\"] = \"60s\"\n\t\treturn ConnectionFactoryOptionsBuilderCustomizer { builder ->\n\t\t\tbuilder.option(PostgresqlConnectionFactoryProvider.OPTIONS, options)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/r2dbc/MyR2dbcConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc\n\nimport io.r2dbc.spi.ConnectionFactoryOptions\nimport org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsBuilderCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyR2dbcConfiguration {\n\n\t@Bean\n\tfun connectionFactoryPortCustomizer(): ConnectionFactoryOptionsBuilderCustomizer {\n\t\treturn ConnectionFactoryOptionsBuilderCustomizer { builder ->\n\t\t\tbuilder.option(ConnectionFactoryOptions.PORT, 5432)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/r2dbc/repositories/City.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc.repositories\n\nclass City\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/r2dbc/repositories/CityRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc.repositories\n\nimport org.springframework.data.repository.Repository\nimport reactor.core.publisher.Mono\n\ninterface CityRepository : Repository<City, Long> {\n\n\tfun findByNameAndStateAllIgnoringCase(name: String, state: String): Mono<City>\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/data/sql/r2dbc/usingdatabaseclient/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.data.sql.r2dbc.usingdatabaseclient\n\nimport org.springframework.r2dbc.core.DatabaseClient\nimport org.springframework.stereotype.Component\nimport reactor.core.publisher.Flux\n\n@Component\nclass MyBean(private val databaseClient: DatabaseClient) {\n\n\t// @fold:on // ...\n\tfun someMethod(): Flux<Map<String, Any>> {\n\t\treturn databaseClient.sql(\"select * from user\").fetch().all()\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/devtools/restart/disable/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.devtools.restart.disable\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\tSystem.setProperty(\"spring.devtools.restart.enabled\", \"false\")\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/beanconditions/MyAutoConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.beanconditions\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean\nimport org.springframework.context.annotation.Bean\n\n@AutoConfiguration\nclass MyAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tfun someService(): SomeService {\n\t\treturn SomeService()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/beanconditions/SomeService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.beanconditions\n\nclass SomeService\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/classconditions/MyAutoConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.classconditions\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@AutoConfiguration\n// Some conditions ...\nclass MyAutoConfiguration {\n\n\t// Auto-configured beans ...\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(SomeService::class)\n\tclass SomeServiceConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tfun someService(): SomeService {\n\t\t\treturn SomeService()\n\t\t}\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/conditionannotations/classconditions/SomeService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.conditionannotations.classconditions\n\nclass SomeService\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/customstarter/configurationkeys/AcmeProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.customstarter.configurationkeys\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport java.time.Duration\n\n@ConfigurationProperties(\"acme\")\nclass AcmeProperties(\n\n\t/**\n\t * Whether to check the location of acme resources.\n\t */\n\tvar isCheckLocation: Boolean = true,\n\n\t/**\n\t * Timeout for establishing a connection to the acme server.\n\t */\n\tvar loginTimeout:Duration = Duration.ofSeconds(3))\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyConditionEvaluationReportingTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener\nimport org.springframework.boot.logging.LogLevel\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner\n\n@Suppress(\"UNUSED_ANONYMOUS_PARAMETER\")\nclass MyConditionEvaluationReportingTests {\n\n\t@Test\n\tfun autoConfigTest() {\n\t\tApplicationContextRunner()\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run { context: AssertableApplicationContext? ->\n\t\t\t\t// Test something...\n\t\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing\n\nclass MyService(val name: String)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyServiceAutoConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.EnableConfigurationProperties\nimport org.springframework.boot.docs.features.developingautoconfiguration.testing.MyServiceAutoConfiguration.UserProperties\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(MyService::class)\n@EnableConfigurationProperties(\n\tUserProperties::class\n)\nclass MyServiceAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tfun userService(properties: UserProperties): MyService {\n\t\treturn MyService(properties.name)\n\t}\n\n\t@ConfigurationProperties(\"user\")\n\tclass UserProperties {\n\t\tvar name = \"test\"\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyServiceAutoConfigurationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.autoconfigure.AutoConfigurations\nimport org.springframework.boot.test.context.FilteredClassLoader\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\ninternal open class MyServiceAutoConfigurationTests {\n\n\t// tag::runner[]\n\tval contextRunner = ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MyServiceAutoConfiguration::class.java))\n\n\t// end::runner[]\n\n\t// tag::test-env[]\n\t@Test\n\tfun serviceNameCanBeConfigured() {\n\t\tcontextRunner.withPropertyValues(\"user.name=test123\").run { context: AssertableApplicationContext ->\n\t\t\tassertThat(context).hasSingleBean(MyService::class.java)\n\t\t\tassertThat(context.getBean(MyService::class.java).name).isEqualTo(\"test123\")\n\t\t}\n\t}\n\t// end::test-env[]\n\n\t// tag::test-classloader[]\n\t@Test\n\tfun serviceIsIgnoredIfLibraryIsNotPresent() {\n\t\tcontextRunner.withClassLoader(FilteredClassLoader(MyService::class.java))\n\t\t\t.run { context: AssertableApplicationContext? ->\n\t\t\t\tassertThat(context).doesNotHaveBean(\"myService\")\n\t\t\t}\n\t}\n\t// end::test-classloader[]\n\n\t// tag::test-user-config[]\n\t@Test\n\tfun defaultServiceBacksOff() {\n\t\tcontextRunner.withUserConfiguration(UserConfiguration::class.java)\n\t\t\t.run { context: AssertableApplicationContext ->\n\t\t\t\tassertThat(context).hasSingleBean(MyService::class.java)\n\t\t\t\tassertThat(context).getBean(\"myCustomService\")\n\t\t\t\t\t.isSameAs(context.getBean(MyService::class.java))\n\t\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tinternal class UserConfiguration {\n\n\t\t@Bean\n\t\tfun myCustomService(): MyService {\n\t\t\treturn MyService(\"mine\")\n\t\t}\n\n\t}\n\t// end::test-user-config[]\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/devtools/MyContainersConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.devtools\n\nimport org.springframework.boot.devtools.restart.RestartScope\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection\nimport org.springframework.context.annotation.Bean\nimport org.testcontainers.mongodb.MongoDBContainer\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyContainersConfiguration {\n\n\t@Bean\n\t@RestartScope\n\t@ServiceConnection\n\tfun mongoDbContainer(): MongoDBContainer {\n\t\treturn MongoDBContainer(\"mongo:5.0\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/dynamicproperties/MyContainersConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.dynamicproperties\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.context.annotation.Bean\nimport org.springframework.test.context.DynamicPropertyRegistrar;\nimport org.testcontainers.mongodb.MongoDBContainer\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyContainersConfiguration {\n\n\t@Bean\n\tfun mongoDbContainer(): MongoDBContainer {\n\t\treturn MongoDBContainer(\"mongo:5.0\")\n\t}\n\t\n\t@Bean\n\tfun mongoDbProperties(container: MongoDBContainer): DynamicPropertyRegistrar {\n\t\treturn DynamicPropertyRegistrar { properties ->\n\t\t\tproperties.add(\"spring.mongodb.host\") { container.host }\n\t\t\tproperties.add(\"spring.mongodb.port\") { container.firstMappedPort }\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/importingcontainerdeclarations/MyContainers.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.importingcontainerdeclarations\n\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection\nimport org.testcontainers.junit.jupiter.Container\nimport org.testcontainers.mongodb.MongoDBContainer\nimport org.testcontainers.neo4j.Neo4jContainer\n\ninterface MyContainers {\n\n\tcompanion object {\n\n\t\t@Container\n\t\t@ServiceConnection\n\t\t@JvmField\n\t\tval mongoContainer = MongoDBContainer(\"mongo:5.0\")\n\n\t\t@Container\n\t\t@ServiceConnection\n\t\t@JvmField\n\t\tval neo4jContainer = Neo4jContainer(\"neo4j:5\")\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/importingcontainerdeclarations/MyContainersConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.importingcontainerdeclarations\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers\n\n@TestConfiguration(proxyBeanMethods = false)\n@ImportTestcontainers(MyContainers::class)\nclass MyContainersConfiguration\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/launch/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.launch\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.docs.features.springapplication.MyApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/launch/TestMyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.launch\n\nimport org.springframework.boot.fromApplication\n\nfun main(args: Array<String>) {\n\tfromApplication<MyApplication>().run(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/test/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.test\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.docs.features.springapplication.MyApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/test/MyContainersConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.test\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection\nimport org.springframework.context.annotation.Bean\nimport org.testcontainers.neo4j.Neo4jContainer\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyContainersConfiguration {\n\n\t@Bean\n\t@ServiceConnection\n\tfun neo4jContainer(): Neo4jContainer {\n\t\treturn Neo4jContainer(\"neo4j:5\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/devservices/testcontainers/atdevelopmenttime/test/TestMyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.devservices.testcontainers.atdevelopmenttime.test\n\nimport org.springframework.boot.fromApplication\nimport org.springframework.boot.with\n\nfun main(args: Array<String>) {\n\tfromApplication<MyApplication>().with(MyContainersConfiguration::class).run(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig\n\nimport org.springframework.beans.factory.annotation.Value\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean {\n\n\t@Value(\"\\${name}\")\n\tprivate val name: String? = null\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.bind.DefaultValue\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\nclass MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,\n\t\tval security: Security) {\n\n\tclass Security(val username: String, val password: String,\n\t\t\t@param:DefaultValue(\"USER\") val roles: List<String>)\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/defaultvalues/nonnull/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding.defaultvalues.nonnull\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.bind.DefaultValue\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\n// tag::code[]\nclass MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,\n\t\t@DefaultValue val security: Security) {\n\n\tclass Security(val username: String?, val password: String?,\n\t\t\t@param:DefaultValue(\"USER\") val roles: List<String>)\n\n}\n// end::code[]\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/constructorbinding/primaryconstructor/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.constructorbinding.primaryconstructor\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my\")\nclass MyProperties() {\n\n\tconstructor(name: String) : this() {\n\t\tthis.name = name\n\t}\n\n\t// @fold:on // vars...\n\tvar name: String? = null\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/datasizes/constructorbinding/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.datasizes.constructorbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.bind.DefaultValue\nimport org.springframework.boot.convert.DataSizeUnit\nimport org.springframework.util.unit.DataSize\nimport org.springframework.util.unit.DataUnit\n\n@ConfigurationProperties(\"my\")\nclass MyProperties(@param:DataSizeUnit(DataUnit.MEGABYTES) @param:DefaultValue(\"2MB\") val bufferSize: DataSize,\n\t\t@param:DefaultValue(\"512B\") val sizeThreshold: DataSize)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/datasizes/javabeanbinding/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.datasizes.javabeanbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.convert.DataSizeUnit\nimport org.springframework.util.unit.DataSize\nimport org.springframework.util.unit.DataUnit\n\n@ConfigurationProperties(\"my\")\nclass MyProperties {\n\n\t@DataSizeUnit(DataUnit.MEGABYTES)\n\tvar bufferSize = DataSize.ofMegabytes(2)\n\n\tvar sizeThreshold = DataSize.ofBytes(512)\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/durations/constructorbinding/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.durations.constructorbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.bind.DefaultValue\nimport org.springframework.boot.convert.DurationUnit\nimport java.time.Duration\nimport java.time.temporal.ChronoUnit\n\n@ConfigurationProperties(\"my\")\nclass MyProperties(@param:DurationUnit(ChronoUnit.SECONDS) @param:DefaultValue(\"30s\") val sessionTimeout: Duration,\n\t\t@param:DefaultValue(\"1000ms\") val readTimeout: Duration)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/durations/javabeanbinding/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.durations.javabeanbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.convert.DurationUnit\nimport java.time.Duration\nimport java.time.temporal.ChronoUnit\n\n@ConfigurationProperties(\"my\")\nclass MyProperties {\n\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tvar sessionTimeout = Duration.ofSeconds(30)\n\n\tvar readTimeout = Duration.ofMillis(1000)\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/enablingannotatedtypes/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.enablingannotatedtypes\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan\n\n@SpringBootApplication\n@ConfigurationPropertiesScan(\"com.example.app\", \"com.example.another\")\nclass MyApplication\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/enablingannotatedtypes/MyConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.enablingannotatedtypes\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(SomeProperties::class)\nclass MyConfiguration\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/enablingannotatedtypes/SomeProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.enablingannotatedtypes\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"some.properties\")\nclass SomeProperties\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/javabeanbinding/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.javabeanbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\nclass MyProperties {\n\n\tvar isEnabled = false\n\n\tvar remoteAddress: InetAddress? = null\n\n\tval security = Security()\n\n\tclass Security {\n\n\t\tvar username: String? = null\n\n\t\tvar password: String? = null\n\n\t\tvar roles: List<String> = ArrayList(setOf(\"USER\"))\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/list/MyPojo.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.list\n\nclass MyPojo\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/list/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.list\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my\")\nclass MyProperties {\n\n\tval list: List<MyPojo> = ArrayList()\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/map/MyPojo.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.map\n\nclass MyPojo\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/mergingcomplextypes/map/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.mergingcomplextypes.map\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my\")\nclass MyProperties {\n\n\tval map: Map<String, MyPojo> = LinkedHashMap()\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/relaxedbinding/MyPersonProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.relaxedbinding\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my.main-project.person\")\nclass MyPersonProperties {\n\n\tvar firstName: String? = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/relaxedbinding/mapsfromenvironmentvariables/MyMapsProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.relaxedbinding.mapsfromenvironmentvariables\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\n\n@ConfigurationProperties(\"my.props\")\nclass MyMapsProperties {\n\n\tval values: Map<String, String> = HashMap()\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/thirdpartyconfiguration/AnotherComponent.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.thirdpartyconfiguration\n\nclass AnotherComponent\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/thirdpartyconfiguration/ThirdPartyConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.thirdpartyconfiguration\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass ThirdPartyConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"another\")\n\tfun anotherComponent(): AnotherComponent = AnotherComponent()\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/usingannotatedtypes/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.usingannotatedtypes\n\nclass MyProperties {\n\n\tval remoteAddress: Any?\n\t\tget() = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/usingannotatedtypes/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.usingannotatedtypes\n\nimport org.springframework.stereotype.Service\n\n@Service\nclass MyService(val properties: MyProperties) {\n\n\tfun openConnection() {\n\t\tval server = Server(properties.remoteAddress)\n\t\tserver.start()\n\t\t// ...\n\t}\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/usingannotatedtypes/Server.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.usingannotatedtypes\n\nclass Server(remoteAddress: Any?) {\n\tfun start() {\n\n\t}\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/validate/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.validate\n\nimport jakarta.validation.constraints.NotNull\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.validation.annotation.Validated\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\n@Validated\nclass MyProperties {\n\n\tvar remoteAddress: @NotNull InetAddress? = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/validate/nested/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.validate.nested\n\nimport jakarta.validation.Valid\nimport jakarta.validation.constraints.NotEmpty\nimport jakarta.validation.constraints.NotNull\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.validation.annotation.Validated\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\n@Validated\nclass MyProperties {\n\n\tvar remoteAddress: @NotNull InetAddress? = null\n\n\tval security: @Valid Security = Security()\n\n\tclass Security {\n\t\tvar username: @NotEmpty String? = null\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/validation/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.validation\n\nimport jakarta.validation.constraints.NotNull\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.validation.annotation.Validated\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\n@Validated\nclass MyProperties {\n\n\tvar remoteAddress: @NotNull InetAddress? = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/validation/nested/MyProperties.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.validation.nested\n\nimport jakarta.validation.Valid\nimport jakarta.validation.constraints.NotEmpty\nimport jakarta.validation.constraints.NotNull\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.validation.annotation.Validated\nimport java.net.InetAddress\n\n@ConfigurationProperties(\"my.service\")\n@Validated\nclass MyProperties {\n\n\tvar remoteAddress: @NotNull InetAddress? = null\n\n\t@Valid\n\tval security = Security()\n\n\tclass Security {\n\n\t\t@NotEmpty\n\t\tvar username: String? = null\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/MyJacksonComponent.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers\n\nimport tools.jackson.core.JsonGenerator\nimport tools.jackson.core.JsonParser\nimport tools.jackson.databind.DeserializationContext\nimport tools.jackson.databind.JsonNode\nimport tools.jackson.databind.SerializationContext\nimport tools.jackson.databind.ValueDeserializer\nimport tools.jackson.databind.ValueSerializer\n\nimport org.springframework.boot.jackson.JacksonComponent\n\n@JacksonComponent\nclass MyJacksonComponent {\n\n\tclass Serializer : ValueSerializer<MyObject>() {\n\t\toverride fun serialize(value: MyObject, jgen: JsonGenerator, serializers: SerializationContext) {\n\t\t\tjgen.writeStartObject()\n\t\t\tjgen.writeStringProperty(\"name\", value.name)\n\t\t\tjgen.writeNumberProperty(\"age\", value.age)\n\t\t\tjgen.writeEndObject()\n\t\t}\n\t}\n\n\tclass Deserializer : ValueDeserializer<MyObject>() {\n\t\toverride fun deserialize(jsonParser: JsonParser, ctxt: DeserializationContext): MyObject {\n\t\t\tval tree = jsonParser.readValueAsTree<JsonNode>()\n\t\t\tval name = tree[\"name\"].stringValue()\n\t\t\tval age = tree[\"age\"].intValue()\n\t\t\treturn MyObject(name, age)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/MyObject.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers\n\nclass MyObject(val name: String = \"\", val age: Int = 0)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/object/MyJacksonComponent.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.`object`\n\nimport tools.jackson.core.JsonGenerator\nimport tools.jackson.core.JsonParser\nimport tools.jackson.databind.DeserializationContext\nimport tools.jackson.databind.JsonNode\nimport tools.jackson.databind.SerializationContext\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.jackson.ObjectValueDeserializer\nimport org.springframework.boot.jackson.ObjectValueSerializer\n\n@JacksonComponent\nclass MyJacksonComponent {\n\n\tclass Serializer : ObjectValueSerializer<MyObject>() {\n\t\toverride fun serializeObject(value: MyObject, jgen: JsonGenerator, context: SerializationContext) {\n\t\t\tjgen.writeStringProperty(\"name\", value.name)\n\t\t\tjgen.writeNumberProperty(\"age\", value.age)\n\t\t}\n\t}\n\n\tclass Deserializer : ObjectValueDeserializer<MyObject>() {\n\t\toverride fun deserializeObject(jsonParser: JsonParser, context: DeserializationContext,\n\t\t\t\ttree: JsonNode): MyObject {\n\t\t\tval name = nullSafeValue(tree[\"name\"], String::class.java) ?: throw IllegalStateException(\"name is null\")\n\t\t\tval age = nullSafeValue(tree[\"age\"], Int::class.java) ?: throw IllegalStateException(\"age is null\")\n\t\t\treturn MyObject(name, age)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/json/jackson/customserializersanddeserializers/object/MyObject.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.`object`\n\nclass MyObject(val name: String = \"\", val age: Int = 0)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/logging/structured/otherformats/MyCustomFormat.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.logging.structured.otherformats\n\nimport ch.qos.logback.classic.spi.ILoggingEvent\nimport org.springframework.boot.logging.structured.StructuredLogFormatter\n\nclass MyCustomFormat : StructuredLogFormatter<ILoggingEvent> {\n\n\toverride fun format(event: ILoggingEvent): String {\n\t\treturn \"time=${event.instant} level=${event.level} message=${event.message}\\n\"\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/profiles/ProductionConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.profiles\n\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.context.annotation.Profile\n\n@Configuration(proxyBeanMethods = false)\n@Profile(\"production\")\nclass ProductionConfiguration {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/applicationarguments/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationarguments\n\nimport org.springframework.boot.ApplicationArguments\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(args: ApplicationArguments) {\n\n\tinit {\n\t\tval debug = args.containsOption(\"debug\")\n\t\tval files = args.nonOptionArgs\n\t\tif (debug) {\n\t\t\tprintln(files)\n\t\t}\n\t\t// if run with \"--debug logfile.txt\" prints [\"logfile.txt\"]\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/applicationavailability/managing/CacheCompletelyBrokenException.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationavailability.managing\n\nclass CacheCompletelyBrokenException: RuntimeException()\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/applicationavailability/managing/MyLocalCacheVerifier.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationavailability.managing\n\nimport org.springframework.boot.availability.AvailabilityChangeEvent\nimport org.springframework.boot.availability.LivenessState\nimport org.springframework.context.ApplicationEventPublisher\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyLocalCacheVerifier(private val eventPublisher: ApplicationEventPublisher) {\n\n\tfun checkLocalCache() {\n\t\ttry {\n\t\t\t// ...\n\t\t} catch (ex: CacheCompletelyBrokenException) {\n\t\t\tAvailabilityChangeEvent.publish(eventPublisher, ex, LivenessState.BROKEN)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/applicationavailability/managing/MyReadinessStateExporter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationavailability.managing\n\nimport org.springframework.boot.availability.AvailabilityChangeEvent\nimport org.springframework.boot.availability.ReadinessState\nimport org.springframework.context.event.EventListener\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyReadinessStateExporter {\n\n\t@EventListener\n\tfun onStateChange(event: AvailabilityChangeEvent<ReadinessState>) {\n\t\twhen (event.state) {\n\t\t\tReadinessState.ACCEPTING_TRAFFIC -> {\n\t\t\t\t// create file /tmp/healthy\n\t\t\t}\n\t\t\tReadinessState.REFUSING_TRAFFIC -> {\n\t\t\t\t// remove file /tmp/healthy\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/applicationexit/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.applicationexit\n\nimport org.springframework.boot.ExitCodeGenerator\nimport org.springframework.boot.SpringApplication\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.context.annotation.Bean\n\nimport kotlin.system.exitProcess\n\n@SpringBootApplication\nclass MyApplication {\n\n\t@Bean\n\tfun exitCodeGenerator() = ExitCodeGenerator { 42 }\n\n}\n\nfun main(args: Array<String>) {\n\texitProcess(SpringApplication.exit(\n\t\trunApplication<MyApplication>(*args)))\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/commandlinerunner/MyCommandLineRunner.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.commandlinerunner\n\nimport org.springframework.boot.CommandLineRunner\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyCommandLineRunner : CommandLineRunner {\n\n\toverride fun run(vararg args: String) {\n\t\t// Do something...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/customizingspringapplication/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.customizingspringapplication\n\nimport org.springframework.boot.Banner\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args) {\n\t\tsetBannerMode(Banner.Mode.OFF)\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/fluentbuilderapi/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.fluentbuilderapi\n\nimport org.springframework.boot.Banner\nimport org.springframework.boot.builder.SpringApplicationBuilder\n\nclass MyApplication {\n\tfun hierarchyWithDisabledBanner(args: Array<String>) {\n\t\t// tag::code[]\n\t\tSpringApplicationBuilder()\n\t\t\t.sources(Parent::class.java)\n\t\t\t.child(Application::class.java)\n\t\t\t.bannerMode(Banner.Mode.OFF)\n\t\t\t.run(*args)\n\t\t// end::code[]\n\t}\n\n\tinternal class Parent\n\n\tinternal class Application\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/springapplication/startuptracking/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.startuptracking\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args) {\n\t\tapplicationStartup = BufferingApplicationStartup(2048)\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/ssl/bundles/MyComponent.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.features.ssl.bundles\n\nimport org.springframework.boot.ssl.SslBundles\nimport org.springframework.stereotype.Component\n\n@Component\n@Suppress(\"UNUSED_VARIABLE\")\nclass MyComponent(sslBundles: SslBundles) {\n\n    init {\n        val sslBundle = sslBundles.getBundle(\"mybundle\")\n        val sslContext = sslBundle.createSslContext()\n        // do something with the created sslContext\n    }\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/taskexecutionandscheduling/application/MyTaskExecutorConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.application\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.core.task.SimpleAsyncTaskExecutor\n\n@Configuration(proxyBeanMethods = false)\nclass MyTaskExecutorConfiguration {\n\n\t@Bean(\"applicationTaskExecutor\")\n\tfun applicationTaskExecutor(): SimpleAsyncTaskExecutor {\n\t\treturn SimpleAsyncTaskExecutor(\"app-\")\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/taskexecutionandscheduling/async/MyTaskExecutorConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.async\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.scheduling.annotation.AsyncConfigurer\nimport java.util.concurrent.Executor\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\n\n@Configuration(proxyBeanMethods = false)\nclass MyTaskExecutorConfiguration {\n\n\t@Bean\n\tfun asyncConfigurer(executorService: ExecutorService): AsyncConfigurer {\n\t\treturn object : AsyncConfigurer {\n\t\t\toverride fun getAsyncExecutor(): Executor {\n\t\t\t\treturn executorService\n\t\t\t}\n\t\t}\n\t}\n\n\t@Bean\n\tfun executorService(): ExecutorService {\n\t\treturn Executors.newCachedThreadPool()\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/taskexecutionandscheduling/builder/MyTaskExecutorConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.builder\n\nimport org.springframework.boot.task.SimpleAsyncTaskExecutorBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.core.task.SimpleAsyncTaskExecutor\n\n@Configuration(proxyBeanMethods = false)\nclass MyTaskExecutorConfiguration {\n\n\t@Bean\n\tfun taskExecutor(builder: SimpleAsyncTaskExecutorBuilder): SimpleAsyncTaskExecutor {\n\t\treturn builder.build()\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/taskexecutionandscheduling/defaultcandidate/MyTaskExecutorConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.defaultcandidate\n\nimport org.springframework.beans.factory.annotation.Qualifier\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.util.concurrent.Executors\nimport java.util.concurrent.ScheduledExecutorService\n\n@Configuration(proxyBeanMethods = false)\nclass MyTaskExecutorConfiguration {\n\n\t@Bean(defaultCandidate = false)\n\t@Qualifier(\"scheduledExecutorService\")\n\tfun scheduledExecutorService(): ScheduledExecutorService {\n\t\treturn Executors.newSingleThreadScheduledExecutor()\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/features/taskexecutionandscheduling/multiple/MyTaskExecutorConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.taskexecutionandscheduling.multiple\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.core.task.SimpleAsyncTaskExecutor\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor\n\n\n@Configuration(proxyBeanMethods = false)\nclass MyTaskExecutorConfiguration {\n\n\t@Bean(\"applicationTaskExecutor\")\n\tfun applicationTaskExecutor(): SimpleAsyncTaskExecutor {\n\t\treturn SimpleAsyncTaskExecutor(\"app-\")\n\t}\n\n\t@Bean(\"taskExecutor\")\n\tfun taskExecutor(): ThreadPoolTaskExecutor {\n\t\tval threadPoolTaskExecutor = ThreadPoolTaskExecutor()\n\t\tthreadPoolTaskExecutor.setThreadNamePrefix(\"async-\")\n\t\treturn threadPoolTaskExecutor\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/gettingstarted/firstapplication/code/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.gettingstarted.firstapplication.code\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.web.bind.annotation.RequestMapping\nimport org.springframework.web.bind.annotation.RestController\n\n@RestController\n@SpringBootApplication\nclass MyApplication {\n\n\t@RequestMapping(\"/\")\n\tfun home() = \"Hello World!\"\n\n}\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/actuator/maphealthindicatorstometrics/MetricsHealthMicrometerExport.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.actuator.maphealthindicatorstometrics\n\nclass MetricsHealthMicrometerExport\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/actuator/maphealthindicatorstometrics/MyHealthMetricsExportConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.actuator.maphealthindicatorstometrics\n\nimport io.micrometer.core.instrument.Gauge\nimport io.micrometer.core.instrument.MeterRegistry\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint\nimport org.springframework.boot.health.contributor.Status\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyHealthMetricsExportConfiguration(registry: MeterRegistry, healthEndpoint: HealthEndpoint) {\n\n\tinit {\n\t\t// This example presumes common tags (such as the app) are applied elsewhere\n\t\tGauge.builder(\"health\", healthEndpoint) { health ->\n\t\t\tgetStatusCode(health).toDouble()\n\t\t}.strongReference(true).register(registry)\n\t}\n\n\tprivate fun getStatusCode(health: HealthEndpoint) = when (health.health().status) {\n\t\tStatus.UP -> 3\n\t\tStatus.OUT_OF_SERVICE -> 2\n\t\tStatus.DOWN -> 1\n\t\telse -> 0\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/application/customizetheenvironmentorapplicationcontext/MyEnvironmentPostProcessor.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.application.customizetheenvironmentorapplicationcontext\n\nimport org.springframework.boot.EnvironmentPostProcessor\nimport org.springframework.boot.SpringApplication\nimport org.springframework.boot.env.YamlPropertySourceLoader\nimport org.springframework.core.env.ConfigurableEnvironment\nimport org.springframework.core.env.PropertySource\nimport org.springframework.core.io.ClassPathResource\nimport org.springframework.core.io.Resource\nimport org.springframework.util.Assert\nimport java.io.IOException\n\nclass MyEnvironmentPostProcessor : EnvironmentPostProcessor {\n\n\tprivate val loader = YamlPropertySourceLoader()\n\n\toverride fun postProcessEnvironment(environment: ConfigurableEnvironment, application: SpringApplication) {\n\t\tval path: Resource = ClassPathResource(\"com/example/myapp/config.yml\")\n\t\tval propertySource = loadYaml(path)\n\t\tenvironment.propertySources.addLast(propertySource)\n\t}\n\n\tprivate fun loadYaml(path: Resource): PropertySource<*> {\n\t\tAssert.isTrue(path.exists()) { \"'path' [$path] must exist\" }\n\t\treturn try {\n\t\t\tloader.load(\"custom-resource\", path)[0]\n\t\t} catch (ex: IOException) {\n\t\t\tthrow IllegalStateException(\"Failed to load yaml configuration from $path\", ex)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configureacomponentthatisusedbyjpa/ElasticsearchEntityManagerFactoryDependsOnPostProcessor.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configureacomponentthatisusedbyjpa\n\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor\nimport org.springframework.stereotype.Component\n\n@Component\nclass ElasticsearchEntityManagerFactoryDependsOnPostProcessor :\n\tEntityManagerFactoryDependsOnPostProcessor(\"elasticsearchClient\")\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/builder/MyDataSourceConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.builder\n\nimport javax.sql.DataSource\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.jdbc.DataSourceBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyDataSourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource\")\n\tfun dataSource(): DataSource {\n\t\treturn DataSourceBuilder.create().build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/configurable/MyDataSourceConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.configurable\n\nimport com.zaxxer.hikari.HikariDataSource\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.context.annotation.Primary\n\n@Configuration(proxyBeanMethods = false)\nclass MyDataSourceConfiguration {\n\n\t@Bean\n\t@Primary\n\t@ConfigurationProperties(\"app.datasource\")\n\tfun dataSourceProperties(): DataSourceProperties {\n\t\treturn DataSourceProperties()\n\t}\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource.configuration\")\n\tfun dataSource(properties: DataSourceProperties): HikariDataSource {\n\t\treturn properties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/custom/MyDataSourceConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.custom\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyDataSourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource\")\n\tfun dataSource(): SomeDataSource {\n\t\treturn SomeDataSource()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/custom/SomeDataSource.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.custom\n\nclass SomeDataSource\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/simple/MyDataSourceConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.simple\n\nimport com.zaxxer.hikari.HikariDataSource\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.jdbc.DataSourceBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyDataSourceConfiguration {\n\n\t@Bean\n\t@ConfigurationProperties(\"app.datasource\")\n\tfun dataSource(): HikariDataSource {\n\t\treturn DataSourceBuilder.create().type(HikariDataSource::class.java).build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurehibernatenamingstrategy/spring/MyHibernateConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurehibernatenamingstrategy.spring\n\nimport org.hibernate.boot.model.naming.Identifier\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl\nimport org.hibernate.engine.jdbc.env.spi.JdbcEnvironment\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyHibernateConfiguration {\n\n\t@Bean\n\tfun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategySnakeCaseImpl {\n\t\treturn object : PhysicalNamingStrategySnakeCaseImpl() {\n\t\t\toverride fun toPhysicalColumnName(logicalName: Identifier, jdbcEnvironment: JdbcEnvironment): Identifier {\n\t\t\t\treturn logicalName\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurehibernatenamingstrategy/standard/MyHibernateConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurehibernatenamingstrategy.standard\n\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\ninternal class MyHibernateConfiguration {\n\n\t@Bean\n\tfun caseSensitivePhysicalNamingStrategy(): PhysicalNamingStrategyStandardImpl {\n\t\treturn PhysicalNamingStrategyStandardImpl()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configurehibernatesecondlevelcaching/MyHibernateSecondLevelCacheConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurehibernatesecondlevelcaching\n\nimport org.hibernate.cache.jcache.ConfigSettings\nimport org.springframework.boot.hibernate.autoconfigure.HibernatePropertiesCustomizer\nimport org.springframework.cache.jcache.JCacheCacheManager\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyHibernateSecondLevelCacheConfiguration {\n\n\t@Bean\n\tfun hibernateSecondLevelCacheCustomizer(cacheManager: JCacheCacheManager): HibernatePropertiesCustomizer {\n\t\treturn HibernatePropertiesCustomizer { properties ->\n\t\t\tval cacheManager = cacheManager.cacheManager\n\t\t\tif (cacheManager != null) {\n\t\t\t\tproperties[ConfigSettings.CACHE_MANAGER] = cacheManager\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configuretwodatasources/MyAdditionalDataSourceConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configuretwodatasources\n\nimport com.zaxxer.hikari.HikariDataSource\n\nimport org.springframework.beans.factory.annotation.Qualifier\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.jdbc.DataSourceBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyAdditionalDataSourceConfiguration {\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.datasource\")\n\tfun secondDataSource(): HikariDataSource {\n\t\treturn DataSourceBuilder.create().type(HikariDataSource::class.java).build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/configuretwodatasources/MyCompleteAdditionalDataSourceConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configuretwodatasources\n\nimport com.zaxxer.hikari.HikariDataSource\n\nimport org.springframework.beans.factory.annotation.Qualifier\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyCompleteAdditionalDataSourceConfiguration {\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.datasource\")\n\tfun secondDataSourceProperties(): DataSourceProperties {\n\t\treturn DataSourceProperties()\n\t}\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.datasource.configuration\")\n\tfun secondDataSource(@Qualifier(\"second\") dataSourceProperties: DataSourceProperties): HikariDataSource {\n\t\treturn dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/filterscannedentitydefinitions/MyEntityScanConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.filterscannedentitydefinitions\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter\n\n@Configuration(proxyBeanMethods = false)\nclass MyEntityScanConfiguration {\n\n\t@Bean\n\tfun entityScanFilter() : ManagedClassNameFilter {\n\t\treturn ManagedClassNameFilter { className ->\n\t\t\tclassName.startsWith(\"com.example.app.customer.\")\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/separateentitydefinitionsfromspringconfiguration/City.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.separateentitydefinitionsfromspringconfiguration\n\nclass City\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/separateentitydefinitionsfromspringconfiguration/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.separateentitydefinitionsfromspringconfiguration\n\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration\nimport org.springframework.boot.persistence.autoconfigure.EntityScan\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\n@EnableAutoConfiguration\n@EntityScan(basePackageClasses = [City::class])\nclass MyApplication {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/Customer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers\n\nclass Customer\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/CustomerConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers\n\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories\n\n@Configuration(proxyBeanMethods = false)\n@EnableJpaRepositories(basePackageClasses = [Customer::class], entityManagerFactoryRef = \"secondEntityManagerFactory\")\nclass CustomerConfiguration\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/MyAdditionalEntityManagerFactoryConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers\n\nimport org.springframework.beans.factory.annotation.Qualifier\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.jpa.EntityManagerFactoryBuilder\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.orm.jpa.JpaVendorAdapter\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter\nimport javax.sql.DataSource\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Configuration(proxyBeanMethods = false)\nclass MyAdditionalEntityManagerFactoryConfiguration {\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\t@ConfigurationProperties(\"app.jpa\")\n\tfun secondJpaProperties(): JpaProperties {\n\t\treturn JpaProperties()\n\t}\n\n\t@Qualifier(\"second\")\n\t@Bean(defaultCandidate = false)\n\tfun secondEntityManagerFactory(\n\t\t@Qualifier(\"second\") dataSource: DataSource,\n\t\t@Qualifier(\"second\") jpaProperties: JpaProperties\n\t): LocalContainerEntityManagerFactoryBean {\n\t\tval builder = createEntityManagerFactoryBuilder(jpaProperties)\n\t\treturn builder.dataSource(dataSource).packages(Order::class.java).persistenceUnit(\"second\").build()\n\t}\n\n\tprivate fun createEntityManagerFactoryBuilder(jpaProperties: JpaProperties): EntityManagerFactoryBuilder {\n\t\tval jpaVendorAdapter = createJpaVendorAdapter(jpaProperties)\n\t\tval jpaPropertiesFactory = { dataSource: DataSource ->\n\t\t\t\tcreateJpaProperties(dataSource, jpaProperties.properties) }\n\t\treturn EntityManagerFactoryBuilder(jpaVendorAdapter, jpaPropertiesFactory, null)\n\t}\n\n\tprivate fun createJpaVendorAdapter(jpaProperties: JpaProperties): JpaVendorAdapter {\n\t\t// ... map JPA properties as needed\n\t\treturn HibernateJpaVendorAdapter()\n\t}\n\n\tprivate fun createJpaProperties(dataSource: DataSource, existingProperties: Map<String, *>): Map<String, *> {\n\t\tval jpaProperties: Map<String, *> = LinkedHashMap(existingProperties)\n\t\t// ... map JPA properties that require the DataSource (e.g. DDL flags)\n\t\treturn jpaProperties\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/Order.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers\n\nclass Order\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/dataaccess/usemultipleentitymanagers/OrderConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.usemultipleentitymanagers\n\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories\n\n@Configuration(proxyBeanMethods = false)\n@EnableJpaRepositories(basePackageClasses = [Order::class], entityManagerFactoryRef = \"entityManagerFactory\")\nclass OrderConfiguration\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/deployment/cloud/cloudfoundry/bindingtoservices/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.deployment.cloud.cloudfoundry.bindingtoservices\n\nimport org.springframework.context.EnvironmentAware\nimport org.springframework.core.env.Environment\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean : EnvironmentAware {\n\n\tprivate var instanceId: String? = null\n\n\toverride fun setEnvironment(environment: Environment) {\n\t\tinstanceId = environment.getProperty(\"vcap.application.instance_id\")\n\t}\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/httpclients/webclientreactornettycustomization/MyReactorNettyClientConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.httpclients.webclientreactornettycustomization\n\nimport io.netty.channel.ChannelOption\nimport io.netty.handler.timeout.ReadTimeoutHandler\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.client.reactive.ClientHttpConnector\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector\nimport org.springframework.http.client.ReactorResourceFactory\nimport reactor.netty.http.client.HttpClient\n\n@Configuration(proxyBeanMethods = false)\nclass MyReactorNettyClientConfiguration {\n\n\t@Bean\n\tfun clientHttpConnector(resourceFactory: ReactorResourceFactory): ClientHttpConnector {\n\t\tval httpClient = HttpClient.create(resourceFactory.connectionProvider)\n\t\t\t.runOn(resourceFactory.loopResources)\n\t\t\t.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 60000)\n\t\t\t.doOnConnected { connection ->\n\t\t\t\tconnection.addHandlerLast(ReadTimeoutHandler(60))\n\t\t\t}\n\t\treturn ReactorClientHttpConnector(httpClient)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/messaging/disabletransactedjmssession/MyJmsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.messaging.disabletransactedjmssession\n\nimport jakarta.jms.ConnectionFactory\nimport org.springframework.boot.jms.ConnectionFactoryUnwrapper\nimport org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory\n\n@Suppress(\"NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS\")\n@Configuration(proxyBeanMethods = false)\nclass MyJmsConfiguration {\n\n\t@Bean\n\tfun jmsListenerContainerFactory(connectionFactory: ConnectionFactory,\n\t\t\tconfigurer: DefaultJmsListenerContainerFactoryConfigurer): DefaultJmsListenerContainerFactory {\n\t\tval listenerFactory = DefaultJmsListenerContainerFactory()\n\t\tconfigurer.configure(listenerFactory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory))\n\t\tlistenerFactory.setTransactionManager(null)\n\t\tlistenerFactory.setSessionTransacted(false)\n\t\treturn listenerFactory\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/propertiesandconfiguration/externalizeconfiguration/application/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.propertiesandconfiguration.externalizeconfiguration.application\n\nimport org.springframework.boot.Banner\nimport org.springframework.boot.SpringApplication\nimport org.springframework.boot.autoconfigure.SpringBootApplication\n\n@SpringBootApplication\nobject MyApplication {\n\n\t@JvmStatic\n\tfun main(args: Array<String>) {\n\t\tval application = SpringApplication(MyApplication::class.java)\n\t\tapplication.setBannerMode(Banner.Mode.OFF)\n\t\tapplication.run(*args)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/propertiesandconfiguration/externalizeconfiguration/builder/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.propertiesandconfiguration.externalizeconfiguration.builder\n\nimport org.springframework.boot.Banner\nimport org.springframework.boot.builder.SpringApplicationBuilder\n\nobject MyApplication {\n\n\t@JvmStatic\n\tfun main(args: Array<String>) {\n\t\tSpringApplicationBuilder()\n\t\t\t.bannerMode(Banner.Mode.OFF)\n\t\t\t.sources(MyApplication::class.java)\n\t\t\t.run(*args)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/security/enablehttps/MySecurityConfig.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.security.enablehttps\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity\nimport org.springframework.security.web.SecurityFilterChain\n\n@Configuration\nclass MySecurityConfig {\n\n\t@Bean\n\tfun securityFilterChain(http: HttpSecurity): SecurityFilterChain {\n\t\t// Customize the application security ...\n\t\thttp.redirectToHttps { }\n\t\treturn http.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/springmvc/writejsonrestservice/MyController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.springmvc.writejsonrestservice\n\nimport org.springframework.web.bind.annotation.RequestMapping\nimport org.springframework.web.bind.annotation.RestController\n\n@RestController\nclass MyController {\n\n\t@RequestMapping(\"/thing\")\n\tfun thing(): MyThing {\n\t\treturn MyThing()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/springmvc/writejsonrestservice/MyThing.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.springmvc.writejsonrestservice\n\nclass MyThing\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/springmvc/writexmlrestservice/MyThing.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.springmvc.writexmlrestservice\n\nimport jakarta.xml.bind.annotation.XmlRootElement\n\n@XmlRootElement\nclass MyThing {\n\n\tvar name: String? = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/testing/withspringsecurity/MySecurityTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.withspringsecurity\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest\nimport org.springframework.security.test.context.support.WithMockUser\nimport org.springframework.test.web.servlet.assertj.MockMvcTester\n\n@WebMvcTest(UserController::class)\nclass MySecurityTests(@Autowired val mvc: MockMvcTester) {\n\n\t@Test\n\t@WithMockUser(roles = [\"ADMIN\"])\n\tfun requestProtectedUrlWithUser() {\n\t\tassertThat(mvc.get().uri(\"/\"))\n\t\t\t\t.doesNotHaveFailed()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/testing/withspringsecurity/UserController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.testing.withspringsecurity\n\nclass UserController\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/traditionaldeployment/convertexistingapplication/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.convertexistingapplication\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.builder.SpringApplicationBuilder\nimport org.springframework.boot.runApplication\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer\n\n@SpringBootApplication\nclass MyApplication : SpringBootServletInitializer() {\n\n\toverride fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {\n\t\t// Customize the application or call application.sources(...) to add sources\n\t\t// Since our example is itself a @Configuration class (through @SpringBootApplication)\n\t\t// we actually do not need to override this method.\n\t\treturn application\n\t}\n\n}\n\n// tag::main[]\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n// end::main[]\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/traditionaldeployment/convertexistingapplication/both/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.convertexistingapplication.both\n\nimport org.springframework.boot.Banner\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.builder.SpringApplicationBuilder\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer\n\n@SpringBootApplication\nclass MyApplication : SpringBootServletInitializer() {\n\n\toverride fun configure(builder: SpringApplicationBuilder): SpringApplicationBuilder {\n\t\treturn customizerBuilder(builder)\n\t}\n\n\tcompanion object {\n\n\t\t@JvmStatic\n\t\tfun main(args: Array<String>) {\n\t\t\tcustomizerBuilder(SpringApplicationBuilder()).run(*args)\n\t\t}\n\n\t\tprivate fun customizerBuilder(builder: SpringApplicationBuilder): SpringApplicationBuilder {\n\t\t\treturn builder.sources(MyApplication::class.java).bannerMode(Banner.Mode.OFF)\n\t\t}\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/traditionaldeployment/war/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.war\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.builder.SpringApplicationBuilder\nimport org.springframework.boot.runApplication\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer\n\n@SpringBootApplication\nclass MyApplication : SpringBootServletInitializer() {\n\n\toverride fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {\n\t\treturn application.sources(MyApplication::class.java)\n\t}\n\n}\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/traditionaldeployment/weblogic/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.traditionaldeployment.weblogic\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer\nimport org.springframework.web.WebApplicationInitializer\n\n@SpringBootApplication\nclass MyApplication : SpringBootServletInitializer(), WebApplicationInitializer\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/addservletfilterlistener/springbean/disable/MyFilter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.addservletfilterlistener.springbean.disable\n\nimport jakarta.servlet.Filter\n\nabstract class MyFilter : Filter\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/addservletfilterlistener/springbean/disable/MyFilterConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.addservletfilterlistener.springbean.disable\n\nimport org.springframework.boot.web.servlet.FilterRegistrationBean\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyFilterConfiguration {\n\n\t@Bean\n\tfun registration(filter: MyFilter): FilterRegistrationBean<MyFilter> {\n\t\tval registration = FilterRegistrationBean(filter)\n\t\tregistration.isEnabled = false\n\t\treturn registration\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/builduritestwebserver/MyWebIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.builduritestwebserver\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.boot.test.http.server.LocalTestWebServer\nimport org.springframework.context.ApplicationContext\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\nclass MyWebIntegrationTests(@Autowired val context: ApplicationContext) {\n\n\t// ...\n\n\t@Test\n\tfun test() {\n\t\tval urlToTest = LocalTestWebServer.obtain(this.context).uri(\"/test\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/configure/MyTomcatWebServerCustomizer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.configure\n\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyTomcatWebServerCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory> {\n\n\toverride fun customize(factory: TomcatServletWebServerFactory) {\n\t\t// customize the factory here\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/createwebsocketendpointsusingserverendpoint/MyWebSocketConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.createwebsocketendpointsusingserverendpoint\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.web.socket.server.standard.ServerEndpointExporter\n\n@Configuration(proxyBeanMethods = false)\nclass MyWebSocketConfiguration {\n\n\t@Bean\n\tfun serverEndpointExporter(): ServerEndpointExporter {\n\t\treturn ServerEndpointExporter()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/discoverport/MyWebIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.discoverport\n\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.boot.test.web.server.LocalServerPort\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\nclass MyWebIntegrationTests {\n\n\t@LocalServerPort\n\tvar port = 0\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/howto/webserver/enablemultipleconnectorsintomcat/MyTomcatConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.webserver.enablemultipleconnectorsintomcat\n\nimport org.apache.catalina.connector.Connector\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyTomcatConfiguration {\n\n\t@Bean\n\tfun connectorCustomizer(): WebServerFactoryCustomizer<TomcatServletWebServerFactory> {\n\t\treturn WebServerFactoryCustomizer { tomcat: TomcatServletWebServerFactory ->\n\t\t\ttomcat.addAdditionalConnectors(createConnector())\n\t\t}\n\t}\n\n\tprivate fun createConnector(): Connector {\n\t\tval connector = Connector(\"org.apache.coyote.http11.Http11NioProtocol\")\n\t\tconnector.port = 8081\n\t\treturn connector\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/caching/MyMathService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching\n\nimport org.springframework.cache.annotation.Cacheable\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyMathService {\n\n\t@Cacheable(\"piDecimals\")\n\tfun computePiDecimal(precision: Int): Int {\n\t\t/**/ return 0\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/caching/provider/MyCacheManagerConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider\n\nimport org.springframework.boot.cache.autoconfigure.CacheManagerCustomizer\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyCacheManagerConfiguration {\n\n\t@Bean\n\tfun cacheManagerCustomizer(): CacheManagerCustomizer<ConcurrentMapCacheManager> {\n\t\treturn CacheManagerCustomizer { cacheManager ->\n\t\t\tcacheManager.isAllowNullValues = false\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/caching/provider/cache2k/MyCache2kDefaultsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider.cache2k\n\nimport org.springframework.boot.cache.autoconfigure.Cache2kBuilderCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.util.concurrent.TimeUnit\n\n@Configuration(proxyBeanMethods = false)\nclass MyCache2kDefaultsConfiguration {\n\n\t@Bean\n\tfun myCache2kDefaultsCustomizer(): Cache2kBuilderCustomizer {\n\t\treturn Cache2kBuilderCustomizer { builder ->\n\t\t\tbuilder.entryCapacity(200)\n\t\t\t\t.expireAfterWrite(5, TimeUnit.MINUTES)\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider.couchbase\n\nimport org.springframework.boot.cache.autoconfigure.CouchbaseCacheManagerBuilderCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration\nimport java.time.Duration\n\n@Configuration(proxyBeanMethods = false)\nclass MyCouchbaseCacheManagerConfiguration {\n\n\t@Bean\n\tfun myCouchbaseCacheManagerBuilderCustomizer(): CouchbaseCacheManagerBuilderCustomizer {\n\t\treturn CouchbaseCacheManagerBuilderCustomizer { builder ->\n\t\t\tbuilder\n\t\t\t\t.withCacheConfiguration(\n\t\t\t\t\t\"cache1\", CouchbaseCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryExpiry(Duration.ofSeconds(10))\n\t\t\t\t)\n\t\t\t\t.withCacheConfiguration(\n\t\t\t\t\t\"cache2\", CouchbaseCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryExpiry(Duration.ofMinutes(1))\n\t\t\t\t)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/caching/provider/redis/MyRedisCacheManagerConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.provider.redis\n\nimport org.springframework.boot.cache.autoconfigure.RedisCacheManagerBuilderCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.redis.cache.RedisCacheConfiguration\nimport java.time.Duration\n\n@Configuration(proxyBeanMethods = false)\nclass MyRedisCacheManagerConfiguration {\n\n\t@Bean\n\tfun myRedisCacheManagerBuilderCustomizer(): RedisCacheManagerBuilderCustomizer {\n\t\treturn RedisCacheManagerBuilderCustomizer { builder ->\n\t\t\tbuilder\n\t\t\t\t.withCacheConfiguration(\n\t\t\t\t\t\"cache1\", RedisCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryTtl(Duration.ofSeconds(10))\n\t\t\t\t)\n\t\t\t\t.withCacheConfiguration(\n\t\t\t\t\t\"cache2\", RedisCacheConfiguration\n\t\t\t\t\t\t.defaultCacheConfig().entryTtl(Duration.ofMinutes(1))\n\t\t\t\t)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/caching/testing/MyIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.caching.testing\n\nimport org.springframework.boot.cache.test.autoconfigure.AutoConfigureCache\nimport org.springframework.boot.test.context.SpringBootTest\n\n@SpringBootTest\n@AutoConfigureCache\nclass MyIntegrationTests {\n\n\t// Tests use a no-op cache manager\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/jta/mixingxaandnonxaconnections/nonxa/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.jta.mixingxaandnonxaconnections.nonxa\n\nimport jakarta.jms.ConnectionFactory\nimport org.springframework.beans.factory.annotation.Qualifier\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass MyBean(@Qualifier(\"nonXaJmsConnectionFactory\") connectionFactory: ConnectionFactory?)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/jta/mixingxaandnonxaconnections/primary/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.jta.mixingxaandnonxaconnections.primary\n\nimport jakarta.jms.ConnectionFactory\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass MyBean(connectionFactory: ConnectionFactory?)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/jta/mixingxaandnonxaconnections/xa/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.jta.mixingxaandnonxaconnections.xa\n\nimport jakarta.jms.ConnectionFactory\nimport org.springframework.beans.factory.annotation.Qualifier\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass MyBean(@Qualifier(\"xaJmsConnectionFactory\") connectionFactory: ConnectionFactory?)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/quartz/MySampleJob.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.quartz\n\nimport org.quartz.JobExecutionContext\nimport org.springframework.scheduling.quartz.QuartzJobBean\n\nclass MySampleJob : QuartzJobBean() {\n\n\t// @fold:on // fields ...\n\tprivate var myService: MyService? = null\n\n\tprivate var name: String? = null\n\t// @fold:off\n\n\t// Inject \"MyService\" bean\n\tfun setMyService(myService: MyService?) {\n\t\tthis.myService = myService\n\t}\n\n\t// Inject the \"name\" job data property\n\tfun setName(name: String?) {\n\t\tthis.name = name\n\t}\n\n\toverride fun executeInternal(context: JobExecutionContext) {\n\t\tmyService!!.someMethod(context.fireTime, name)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/quartz/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.quartz\n\nimport java.util.Date\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass MyService {\n\n\tfun someMethod(date: Date?, name: String?) {}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/clienthttprequestfactory/configuration/MyClientHttpConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.clienthttprequestfactory.configuration\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.net.ProxySelector\n\n@Configuration(proxyBeanMethods = false)\nclass MyClientHttpConfiguration {\n\n\t@Bean\n\tfun clientHttpRequestFactoryBuilder(proxySelector: ProxySelector): ClientHttpRequestFactoryBuilder<*> {\n\t\treturn ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t\t.withHttpClientCustomizer { builder -> builder.proxy(proxySelector) }\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/EchoService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.io.restclient.httpservice\n\nimport org.springframework.web.bind.annotation.RequestBody\nimport org.springframework.web.service.annotation.HttpExchange\nimport org.springframework.web.service.annotation.PostExchange\n\n@HttpExchange(url = \"https://echo.zuplo.io\")\ninterface EchoService {\n\n\t@PostExchange\n\tfun echo(@RequestBody message: Map<String, String>): Map<*, *>\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/customization/MyHttpServiceGroupConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.io.restclient.httpservice.customization\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer\n\n@Configuration(proxyBeanMethods = false)\nclass MyHttpServiceGroupConfiguration {\n\n\t@Bean\n\tfun myHttpServiceGroupConfigurer(): RestClientHttpServiceGroupConfigurer {\n\t\treturn RestClientHttpServiceGroupConfigurer { groups ->\n\t\t\tgroups.forEachClient { group, clientBuilder ->\n\t\t\t\tval groupName = group.name()\n\t\t\t\tclientBuilder.defaultHeader(\"service-group\", groupName)\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/groups/EchoService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.io.restclient.httpservice.groups\n\nimport org.springframework.web.bind.annotation.RequestBody\nimport org.springframework.web.service.annotation.HttpExchange\nimport org.springframework.web.service.annotation.PostExchange\n\ninterface EchoService {\n\n\t@PostExchange\n\tfun echo(@RequestBody message: Map<String, String>): Map<*, *>\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/groups/MyApplication.kt",
    "content": "package org.springframework.boot.docs.io.restclient.httpservice.groups\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.web.service.registry.ImportHttpServices\n\n@SpringBootApplication\n@ImportHttpServices(group = \"echo\", basePackages = [\"com.example.myclients\"])\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/groups/repeat/EchoService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.io.restclient.httpservice.groups.repeat\n\nimport org.springframework.web.bind.annotation.RequestBody\nimport org.springframework.web.service.annotation.PostExchange\n\ninterface EchoService {\n\n\t@PostExchange(\"/echo\")\n\tfun echo(@RequestBody message: Map<String, String>): Map<*, *>\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/groups/repeat/MyApplication.kt",
    "content": "package org.springframework.boot.docs.io.restclient.httpservice.groups.repeat\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.web.service.registry.ImportHttpServices\n\n@SpringBootApplication\n@ImportHttpServices(group = \"echo\", types = [EchoService::class])\n@ImportHttpServices(group = \"other\", types = [OtherService::class])\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/groups/repeat/OtherService.kt",
    "content": "package org.springframework.boot.docs.io.restclient.httpservice.groups.repeat\n\nimport org.springframework.web.bind.annotation.RequestBody\nimport org.springframework.web.service.annotation.PostExchange\n\ninterface OtherService {\n\n\t@PostExchange(\"/other\")\n\tfun echo(@RequestBody message: Map<String, String>): Map<*, *>\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/httpservice/importing/MyApplication.kt",
    "content": "package org.springframework.boot.docs.io.restclient.httpservice.importing\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.web.service.registry.ImportHttpServices\n\n@SpringBootApplication\n@ImportHttpServices(basePackages = [\"com.example.myclients\"])\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/Details.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient\n\nclass Details\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient\n\nimport org.springframework.boot.docs.io.restclient.restclient.ssl.Details\nimport org.springframework.stereotype.Service\nimport org.springframework.web.client.RestClient\n\n@Service\nclass MyService(restClientBuilder: RestClient.Builder) {\n\n\tprivate val restClient: RestClient\n\n\tinit {\n\t\trestClient = restClientBuilder.baseUrl(\"https://example.org\").build()\n\t}\n\n\tfun someRestCall(name: String): Details {\n\t\treturn restClient.get().uri(\"/{name}/details\", name)\n\t\t\t\t.retrieve().body(Details::class.java)!!\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/ssl/Details.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl\n\nclass Details\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/ssl/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl\n\nimport org.springframework.boot.docs.io.restclient.restclient.ssl.settings.Details\nimport org.springframework.boot.restclient.autoconfigure.RestClientSsl\nimport org.springframework.stereotype.Service\nimport org.springframework.web.client.RestClient\n\n@Service\nclass MyService(restClientBuilder: RestClient.Builder, ssl: RestClientSsl) {\n\n\tprivate val restClient: RestClient\n\n\tinit {\n\t\trestClient = restClientBuilder.baseUrl(\"https://example.org\")\n\t\t\t\t.apply(ssl.fromBundle(\"mybundle\")).build()\n\t}\n\n\tfun someRestCall(name: String): Details {\n\t\treturn restClient.get().uri(\"/{name}/details\", name)\n\t\t\t\t.retrieve().body(Details::class.java)!!\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/ssl/settings/Details.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl.settings\n\nclass Details\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/restclient/ssl/settings/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.restclient.ssl.settings\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings\nimport org.springframework.boot.ssl.SslBundles\nimport org.springframework.stereotype.Service\nimport org.springframework.web.client.RestClient\nimport java.time.Duration\n\n@Service\nclass MyService(restClientBuilder: RestClient.Builder, sslBundles: SslBundles) {\n\n\tprivate val restClient: RestClient\n\n\tinit {\n\t\tval settings = HttpClientSettings.defaults()\n\t\t\t\t.withReadTimeout(Duration.ofMinutes(2))\n\t\t\t\t.withSslBundle(sslBundles.getBundle(\"mybundle\"))\n\t\tval requestFactory = ClientHttpRequestFactoryBuilder.detect().build(settings);\n\t\trestClient = restClientBuilder\n\t\t\t\t.baseUrl(\"https://example.org\")\n\t\t\t\t.requestFactory(requestFactory).build()\n\t}\n\n\tfun someRestCall(name: String): Details {\n\t\treturn restClient.get().uri(\"/{name}/details\", name).retrieve().body(Details::class.java)!!\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/resttemplate/Details.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate\n\nclass Details\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/resttemplate/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate\n\nimport org.springframework.boot.restclient.RestTemplateBuilder\nimport org.springframework.stereotype.Service\nimport org.springframework.web.client.RestTemplate\n\n@Service\nclass MyService(restTemplateBuilder: RestTemplateBuilder) {\n\n\tprivate val restTemplate: RestTemplate\n\n\tinit {\n\t\trestTemplate = restTemplateBuilder.build()\n\t}\n\n\tfun someRestCall(name: String): Details {\n\t\treturn restTemplate.getForObject(\"/{name}/details\", Details::class.java, name)!!\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/resttemplate/customization/MyRestTemplateBuilderConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate.customization\n\nimport org.springframework.boot.restclient.autoconfigure.RestTemplateBuilderConfigurer\nimport org.springframework.boot.restclient.RestTemplateBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.time.Duration\n\n@Configuration(proxyBeanMethods = false)\nclass MyRestTemplateBuilderConfiguration {\n\n\t@Bean\n\tfun restTemplateBuilder(configurer: RestTemplateBuilderConfigurer): RestTemplateBuilder {\n\t\treturn configurer.configure(RestTemplateBuilder()).connectTimeout(Duration.ofSeconds(5))\n\t\t\t.readTimeout(Duration.ofSeconds(2))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/resttemplate/customization/MyRestTemplateCustomizer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.resttemplate.customization\n\nimport org.apache.hc.client5.http.classic.HttpClient\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder\nimport org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner\nimport org.apache.hc.client5.http.routing.HttpRoutePlanner\nimport org.apache.hc.core5.http.HttpException\nimport org.apache.hc.core5.http.HttpHost\nimport org.apache.hc.core5.http.protocol.HttpContext\nimport org.springframework.boot.restclient.RestTemplateCustomizer\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory\nimport org.springframework.web.client.RestTemplate\n\nclass MyRestTemplateCustomizer : RestTemplateCustomizer {\n\n\toverride fun customize(restTemplate: RestTemplate) {\n\t\tval routePlanner: HttpRoutePlanner = CustomRoutePlanner(HttpHost(\"proxy.example.com\"))\n\t\tval httpClient: HttpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build()\n\t\trestTemplate.requestFactory = HttpComponentsClientHttpRequestFactory(httpClient)\n\t}\n\n\tinternal class CustomRoutePlanner(proxy: HttpHost?) : DefaultProxyRoutePlanner(proxy) {\n\n\t\t@Throws(HttpException::class)\n\t\tpublic override fun determineProxy(target: HttpHost, context: HttpContext): HttpHost? {\n\t\t\tif (target.hostName == \"192.168.0.5\") {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn  super.determineProxy(target, context)\n\t\t}\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/resttemplate/ssl/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.io.restclient.resttemplate.ssl\n\nimport org.springframework.boot.docs.io.restclient.resttemplate.Details\nimport org.springframework.boot.ssl.SslBundles\nimport org.springframework.boot.restclient.RestTemplateBuilder\nimport org.springframework.stereotype.Service\nimport org.springframework.web.client.RestTemplate\n\n@Service\nclass MyService(restTemplateBuilder: RestTemplateBuilder, sslBundles: SslBundles) {\n\n    private val restTemplate: RestTemplate\n\n    init {\n        restTemplate = restTemplateBuilder.sslBundle(sslBundles.getBundle(\"mybundle\")).build()\n    }\n\n    fun someRestCall(name: String): Details {\n        return restTemplate.getForObject(\"/{name}/details\", Details::class.java, name)!!\n    }\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/webclient/Details.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient\n\nclass Details\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/webclient/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient\n\nimport org.springframework.stereotype.Service\nimport org.springframework.web.reactive.function.client.WebClient\nimport reactor.core.publisher.Mono\n\n@Service\nclass MyService(webClientBuilder: WebClient.Builder) {\n\n\tprivate val webClient: WebClient\n\n\tinit {\n\t\twebClient = webClientBuilder.baseUrl(\"https://example.org\").build()\n\t}\n\n\tfun someRestCall(name: String): Mono<Details> {\n\t\treturn webClient.get().uri(\"/{name}/details\", name)\n\t\t\t\t.retrieve().bodyToMono(Details::class.java)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/webclient/configuration/MyConnectorHttpConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient.configuration\n\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.net.ProxySelector\n\n@Configuration(proxyBeanMethods = false)\nclass MyConnectorHttpConfiguration {\n\n\t@Bean\n\tfun clientHttpConnectorBuilder(proxySelector: ProxySelector): ClientHttpConnectorBuilder<*> {\n\t\treturn ClientHttpConnectorBuilder.jdk().withHttpClientCustomizer { builder -> builder.proxy(proxySelector) }\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/webclient/ssl/Details.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient.ssl\n\nclass Details\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/restclient/webclient/ssl/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.restclient.webclient.ssl\n\nimport org.springframework.boot.webclient.autoconfigure.WebClientSsl\nimport org.springframework.stereotype.Service\nimport org.springframework.web.reactive.function.client.WebClient\nimport reactor.core.publisher.Mono\n\n@Service\nclass MyService(webClientBuilder: WebClient.Builder, ssl: WebClientSsl) {\n\n\tprivate val webClient: WebClient\n\n\tinit {\n\t\twebClient = webClientBuilder.baseUrl(\"https://example.org\")\n\t\t\t\t.apply(ssl.fromBundle(\"mybundle\")).build()\n\t}\n\n\tfun someRestCall(name: String): Mono<Details> {\n\t\treturn webClient.get().uri(\"/{name}/details\", name)\n\t\t\t\t.retrieve().bodyToMono(Details::class.java)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/validation/Archive.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.validation\n\nclass Archive\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/validation/Author.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.validation\n\nclass Author\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/validation/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.validation\n\nimport jakarta.validation.constraints.Size\nimport org.springframework.stereotype.Service\nimport org.springframework.validation.annotation.Validated\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Service\n@Validated\nclass MyBean {\n\n\tfun findByCodeAndAuthor(code: @Size(min = 8, max = 10) String?, author: Author?): Archive? {\n\t\treturn null\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/webservices/template/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder\nimport org.springframework.stereotype.Service\nimport org.springframework.ws.client.core.WebServiceTemplate\nimport org.springframework.ws.soap.client.core.SoapActionCallback\n\n@Service\nclass MyService(webServiceTemplateBuilder: WebServiceTemplateBuilder) {\n\n\tprivate val webServiceTemplate: WebServiceTemplate\n\n\tinit {\n\t\twebServiceTemplate = webServiceTemplateBuilder.build()\n\t}\n\n\tfun someWsCall(detailsReq: SomeRequest): SomeResponse {\n\t\treturn webServiceTemplate.marshalSendAndReceive(\n\t\t\tdetailsReq,\n\t\t\tSoapActionCallback(\"https://ws.example.com/action\")\n\t\t) as SomeResponse\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/webservices/template/MyWebServiceTemplateConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template\n\nimport org.springframework.boot.http.client.HttpClientSettings\nimport org.springframework.boot.webservices.client.WebServiceMessageSenderFactory\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.ws.client.core.WebServiceTemplate\nimport java.time.Duration\n\n@Configuration(proxyBeanMethods = false)\nclass MyWebServiceTemplateConfiguration {\n\n\t@Bean\n\tfun webServiceTemplate(builder: WebServiceTemplateBuilder): WebServiceTemplate {\n\t\tval settings = HttpClientSettings.defaults()\n\t\t\t\t.withConnectTimeout(Duration.ofSeconds(2))\n\t\t\t\t.withReadTimeout(Duration.ofSeconds(2))\n\t\tbuilder.httpMessageSenderFactory(WebServiceMessageSenderFactory.http(settings))\n\t\treturn builder.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/webservices/template/SomeRequest.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template\n\nclass SomeRequest\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/io/webservices/template/SomeResponse.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.io.webservices.template\n\nclass SomeResponse\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/amqp/receiving/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving\n\nimport org.springframework.amqp.rabbit.annotation.RabbitListener\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@RabbitListener(queues = [\"someQueue\"])\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving.custom\n\nimport org.springframework.amqp.rabbit.annotation.RabbitListener\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@RabbitListener(queues = [\"someQueue\"], containerFactory = \"myFactory\")\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyMessageConverter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving.custom\n\nimport org.springframework.amqp.core.Message\nimport org.springframework.amqp.core.MessageProperties\nimport org.springframework.amqp.support.converter.MessageConverter\n\ninternal class MyMessageConverter : MessageConverter {\n\n\toverride fun toMessage(`object`: Any, messageProperties: MessageProperties): Message {\n\t\treturn Message(byteArrayOf())\n\t}\n\n\toverride fun fromMessage(message: Message): Any {\n\t\treturn Any()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/amqp/receiving/custom/MyRabbitConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.receiving.custom\n\nimport org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory\nimport org.springframework.boot.amqp.autoconfigure.SimpleRabbitListenerContainerFactoryConfigurer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MyRabbitConfiguration {\n\n\t@Bean\n\tfun myFactory(configurer: SimpleRabbitListenerContainerFactoryConfigurer): SimpleRabbitListenerContainerFactory {\n\t\tval factory = SimpleRabbitListenerContainerFactory()\n\t\tval connectionFactory = getCustomConnectionFactory()\n\t\tconfigurer.configure(factory, connectionFactory)\n\t\tfactory.setMessageConverter(MyMessageConverter())\n\t\treturn factory\n\t}\n\n\tfun getCustomConnectionFactory() : ConnectionFactory {\n\t\treturn /**/ CachingConnectionFactory()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/amqp/sending/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.amqp.sending\n\nimport org.springframework.amqp.core.AmqpAdmin\nimport org.springframework.amqp.core.AmqpTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val amqpAdmin: AmqpAdmin, private val amqpTemplate: AmqpTemplate) {\n\n\t// @fold:on // ...\n\tfun someMethod() {\n\t\tamqpAdmin.getQueueInfo(\"someQueue\")\n\t}\n\n\tfun someOtherMethod() {\n\t\tamqpTemplate.convertAndSend(\"hello\")\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving\n\nimport org.springframework.jms.annotation.JmsListener\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@JmsListener(destination = \"someQueue\")\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving.custom\n\nimport org.springframework.jms.annotation.JmsListener\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@JmsListener(destination = \"someQueue\", containerFactory = \"myFactory\")\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyJmsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving.custom\n\nimport jakarta.jms.ConnectionFactory\nimport org.springframework.boot.jms.ConnectionFactoryUnwrapper\nimport org.springframework.boot.jms.autoconfigure.DefaultJmsListenerContainerFactoryConfigurer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory\n\n@Configuration(proxyBeanMethods = false)\nclass MyJmsConfiguration {\n\n\t@Bean\n\tfun myFactory(configurer: DefaultJmsListenerContainerFactoryConfigurer,\n\t\t\t\t  connectionFactory: ConnectionFactory): DefaultJmsListenerContainerFactory {\n\t\tval factory = DefaultJmsListenerContainerFactory()\n\t\tconfigurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory))\n\t\tfactory.setMessageConverter(MyMessageConverter())\n\t\treturn factory\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/receiving/custom/MyMessageConverter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.receiving.custom\n\nimport jakarta.jms.Message\nimport jakarta.jms.Session\nimport org.springframework.jms.support.converter.MessageConverter\n\ninternal class MyMessageConverter : MessageConverter {\n\n\toverride fun toMessage(`object`: Any, session: Session): Message {\n\t\treturn session.createObjectMessage()\n\t}\n\n\toverride fun fromMessage(message: Message): Any {\n\t\treturn Any()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/jms/sending/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.jms.sending\n\nimport org.springframework.jms.core.JmsClient\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val jmsClient: JmsClient) {\n\n\t// @fold:on // ...\n\tfun someMethod() {\n\t\tjmsClient.destination(\"myQueue\").send(\"hello\")\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/kafka/embedded/annotation/MyTest.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.embedded.annotation\n\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.kafka.test.context.EmbeddedKafka\n\n@SpringBootTest\n@EmbeddedKafka(topics = [\"someTopic\"], bootstrapServersProperty = \"spring.kafka.bootstrap-servers\")\nclass MyTest {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/kafka/embedded/property/MyTest.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.embedded.property\n\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.kafka.test.EmbeddedKafkaBroker\n\n@SpringBootTest\nobject MyTest {\n\n\t// tag::code[]\n\tinit {\n\t\tSystem.setProperty(EmbeddedKafkaBroker.BROKER_LIST_PROPERTY, \"spring.kafka.bootstrap-servers\")\n\t}\n\t// end::code[]\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/kafka/receiving/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.receiving\n\nimport org.springframework.kafka.annotation.KafkaListener\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@KafkaListener(topics = [\"someTopic\"])\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/kafka/sending/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.sending\n\nimport org.springframework.kafka.core.KafkaTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val kafkaTemplate: KafkaTemplate<String, String>) {\n\n\t// @fold:on // ...\n\tfun someMethod() {\n\t\tkafkaTemplate.send(\"someTopic\", \"Hello\")\n\t}\n\t// @fold:off\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/kafka/streams/MyKafkaStreamsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.kafka.streams\n\nimport org.apache.kafka.common.serialization.Serdes\nimport org.apache.kafka.streams.KeyValue\nimport org.apache.kafka.streams.StreamsBuilder\nimport org.apache.kafka.streams.kstream.KStream\nimport org.apache.kafka.streams.kstream.Produced\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.kafka.annotation.EnableKafkaStreams\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Configuration(proxyBeanMethods = false)\n@EnableKafkaStreams\nclass MyKafkaStreamsConfiguration {\n\n\t@Bean\n\t@Suppress(\"DEPRECATION\")\n\tfun kStream(streamsBuilder: StreamsBuilder): KStream<Int, String> {\n\t\tval stream = streamsBuilder.stream<Int, String>(\"ks1In\")\n\t\tstream.map(this::uppercaseValue).to(\"ks1Out\", Produced.with(Serdes.Integer(),\n\t\t\torg.springframework.kafka.support.serializer.JsonSerde()))\n\t\treturn stream\n\t}\n\n\tprivate fun uppercaseValue(key: Int, value: String): KeyValue<Int, String> {\n\t\treturn KeyValue(key, value.uppercase())\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/pulsar/reading/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.pulsar.reading\n\nimport org.springframework.pulsar.annotation.PulsarReader\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@PulsarReader(topics = [\"someTopic\"], startMessageId = \"earliest\")\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/pulsar/receiving/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.pulsar.receiving\n\nimport org.springframework.pulsar.annotation.PulsarListener\nimport org.springframework.stereotype.Component\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyBean {\n\n\t@PulsarListener(topics = [\"someTopic\"])\n\tfun processMessage(content: String?) {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/pulsar/sending/MyBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.pulsar.sending\n\nimport org.apache.pulsar.client.api.PulsarClientException\nimport org.springframework.pulsar.core.PulsarTemplate\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyBean(private val pulsarTemplate: PulsarTemplate<String>) {\n\n\t@Throws(PulsarClientException::class)\n\tfun someMethod() {\n\t\tpulsarTemplate.send(\"someTopic\", \"Hello\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/rsocket/requester/MyService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.rsocket.requester\n\nimport org.springframework.messaging.rsocket.RSocketRequester\nimport org.springframework.stereotype.Service\nimport reactor.core.publisher.Mono\n\n@Service\nclass MyService(rsocketRequesterBuilder: RSocketRequester.Builder) {\n\n\tprivate val rsocketRequester: RSocketRequester\n\n\tinit {\n\t\trsocketRequester = rsocketRequesterBuilder.tcp(\"example.org\", 9898)\n\t}\n\n\tfun someRSocketCall(name: String): Mono<User> {\n\t\treturn rsocketRequester.route(\"user\").data(name).retrieveMono(\n\t\t\tUser::class.java\n\t\t)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/messaging/rsocket/requester/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.messaging.rsocket.requester\n\nclass User\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/packaging/nativeimage/advanced/nestedconfigurationproperties/MyPropertiesKotlin.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.nestedconfigurationproperties\n\nimport org.springframework.boot.context.properties.ConfigurationProperties\nimport org.springframework.boot.context.properties.NestedConfigurationProperty\n\n@ConfigurationProperties(\"my.properties\")\ndata class MyPropertiesKotlin(\n\tval name: String,\n\t@NestedConfigurationProperty val nested: Nested\n)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/packaging/nativeimage/advanced/nestedconfigurationproperties/Nested.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.packaging.nativeimage.advanced.nestedconfigurationproperties\n\nclass Nested {\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/additionalautoconfigurationandslicing/MyJdbcTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.additionalautoconfigurationandslicing\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration\nimport org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration\nimport org.springframework.boot.jdbc.test.autoconfigure.JdbcTest\n\n@JdbcTest\n@ImportAutoConfiguration(IntegrationAutoConfiguration::class)\nclass MyJdbcTests\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredjdbc/MyTransactionalTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredjdbc\n\nimport org.springframework.boot.jdbc.test.autoconfigure.JdbcTest\nimport org.springframework.transaction.annotation.Propagation\nimport org.springframework.transaction.annotation.Transactional\n\n@JdbcTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\nclass MyTransactionalTests\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredjooq/MyJooqTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredjooq\n\nimport org.jooq.DSLContext\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.jooq.test.autoconfigure.JooqTest\n\n@JooqTest\nclass MyJooqTests(@Autowired val dslContext: DSLContext) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredrestclient/MyRestClientServiceTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.restclient.test.autoconfigure.RestClientTest\nimport org.springframework.http.MediaType\nimport org.springframework.test.web.client.MockRestServiceServer\nimport org.springframework.test.web.client.match.MockRestRequestMatchers\nimport org.springframework.test.web.client.response.MockRestResponseCreators\n\n@RestClientTest(RemoteVehicleDetailsService::class)\nclass MyRestClientServiceTests(\n\t@Autowired val service: RemoteVehicleDetailsService,\n\t@Autowired val server: MockRestServiceServer) {\n\n\t@Test\n\tfun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {\n\t\tserver.expect(MockRestRequestMatchers.requestTo(\"https://example.com/greet/details\"))\n\t\t\t.andRespond(MockRestResponseCreators.withSuccess(\"hello\", MediaType.TEXT_PLAIN))\n\t\tval greeting = service.callRestService()\n\t\tassertThat(greeting).isEqualTo(\"hello\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredrestclient/MyRestTemplateServiceTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.restclient.test.autoconfigure.RestClientTest\nimport org.springframework.http.MediaType\nimport org.springframework.test.web.client.MockRestServiceServer\nimport org.springframework.test.web.client.match.MockRestRequestMatchers\nimport org.springframework.test.web.client.response.MockRestResponseCreators\n\n@RestClientTest(RemoteVehicleDetailsService::class)\nclass MyRestTemplateServiceTests(\n\t@Autowired val service: RemoteVehicleDetailsService,\n\t@Autowired val server: MockRestServiceServer) {\n\n\t@Test\n\tfun getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {\n\t\tserver.expect(MockRestRequestMatchers.requestTo(\"/greet/details\"))\n\t\t\t.andRespond(MockRestResponseCreators.withSuccess(\"hello\", MediaType.TEXT_PLAIN))\n\t\tval greeting = service.callRestService()\n\t\tassertThat(greeting).isEqualTo(\"hello\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredrestclient/RemoteVehicleDetailsService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredrestclient\n\nclass RemoteVehicleDetailsService {\n\n\tfun callRestService(): String {\n\t\treturn \"hello\"\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacassandra/MyDataCassandraTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacassandra\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest\n\n@DataCassandraTest\nclass MyDataCassandraTests(@Autowired val repository: SomeRepository)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacassandra/SomeRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacassandra\n\ninterface SomeRepository\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacouchbase/MyDataCouchbaseTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacouchbase\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest\n\n@DataCouchbaseTest\nclass MyDataCouchbaseTests(@Autowired val repository: SomeRepository) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatacouchbase/SomeRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatacouchbase\n\ninterface SomeRepository\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataelasticsearch/MyDataElasticsearchTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataelasticsearch\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest\n\n@DataElasticsearchTest\nclass MyDataElasticsearchTests(@Autowired val repository: SomeRepository) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataelasticsearch/SomeRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataelasticsearch\n\ninterface SomeRepository\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/MyNonTransactionalTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa\n\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest\nimport org.springframework.transaction.annotation.Propagation\nimport org.springframework.transaction.annotation.Transactional\n\n@DataJpaTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\nclass MyNonTransactionalTests {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withdb/MyRepositoryTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withdb\n\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest\n\n@DataJpaTest\n@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)\nclass MyRepositoryTests {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withoutdb/MyRepositoryTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withoutdb\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest\nimport org.springframework.boot.jpa.test.autoconfigure.TestEntityManager\n\n@DataJpaTest\nclass MyRepositoryTests(@Autowired val entityManager: TestEntityManager, @Autowired val repository: UserRepository) {\n\n\t@Test\n\tfun testExample() {\n\t\tentityManager.persist(User(\"sboot\", \"1234\"))\n\t\tval user = repository.findByUsername(\"sboot\")\n\t\tassertThat(user?.username).isEqualTo(\"sboot\")\n\t\tassertThat(user?.employeeNumber).isEqualTo(\"1234\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withoutdb/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withoutdb\n\nclass User(val username: String, val employeeNumber: String)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatajpa/withoutdb/UserRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatajpa.withoutdb\n\ninterface UserRepository {\n\n\tfun findByUsername(username: String?): User?\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataldap/inmemory/MyDataLdapTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataldap.inmemory\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest\nimport org.springframework.ldap.core.LdapTemplate\n\n@DataLdapTest\nclass MyDataLdapTests(@Autowired val ldapTemplate: LdapTemplate) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataldap/server/MyDataLdapTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataldap.server\n\nimport org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration\nimport org.springframework.boot.data.ldap.test.autoconfigure.DataLdapTest\n\n@DataLdapTest(excludeAutoConfiguration = [EmbeddedLdapAutoConfiguration::class])\nclass MyDataLdapTests {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdatamongodb/MyDataMongoDbTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdatamongodb\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest\nimport org.springframework.data.mongodb.core.MongoTemplate\n\n@DataMongoTest\nclass MyDataMongoDbTests(@Autowired val mongoTemplate: MongoTemplate) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataneo4j/nopropagation/MyDataNeo4jTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataneo4j.nopropagation\n\nimport org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest\nimport org.springframework.transaction.annotation.Propagation\nimport org.springframework.transaction.annotation.Transactional\n\n@DataNeo4jTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\nclass MyDataNeo4jTests\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataneo4j/propagation/MyDataNeo4jTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataneo4j.propagation\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.neo4j.test.autoconfigure.DataNeo4jTest\n\n@DataNeo4jTest\nclass MyDataNeo4jTests(@Autowired val repository: SomeRepository) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataneo4j/propagation/SomeRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataneo4j.propagation\n\ninterface SomeRepository\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataredis/MyDataRedisTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataredis\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest\n\n@DataRedisTest\nclass MyDataRedisTests(@Autowired val repository: SomeRepository) {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringdataredis/SomeRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringdataredis\n\ninterface SomeRepository\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/MyRestDocsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc\n\nimport org.springframework.boot.restdocs.test.autoconfigure.RestDocsMockMvcConfigurationCustomizer\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer\nimport org.springframework.restdocs.templates.TemplateFormats\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyRestDocsConfiguration : RestDocsMockMvcConfigurationCustomizer {\n\n\toverride fun customize(configurer: MockMvcRestDocumentationConfigurer) {\n\t\tconfigurer.snippets().withTemplateFormat(TemplateFormats.markdown())\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/MyResultHandlerConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.context.annotation.Bean\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation\nimport org.springframework.restdocs.mockmvc.RestDocumentationResultHandler\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyResultHandlerConfiguration {\n\n\t@Bean\n\tfun restDocumentation(): RestDocumentationResultHandler {\n\t\treturn MockMvcRestDocumentation.document(\"{method-name}\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/MyUserDocumentationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest\nimport org.springframework.http.MediaType\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation\nimport org.springframework.test.web.servlet.assertj.MockMvcTester\n\n@WebMvcTest(UserController::class)\n@AutoConfigureRestDocs\nclass MyUserDocumentationTests(@Autowired val mvc: MockMvcTester) {\n\n\t@Test\n\tfun listUsers() {\n\t\tassertThat(mvc.get().uri(\"/users\").accept(MediaType.TEXT_PLAIN))\n\t\t\t\t.hasStatusOk().apply(MockMvcRestDocumentation.document(\"list-users\"))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withmockmvc/UserController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withmockmvc\n\nclass UserController\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyRestDocsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient\n\nimport org.springframework.boot.restdocs.test.autoconfigure.RestDocsWebTestClientConfigurationCustomizer\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyRestDocsConfiguration : RestDocsWebTestClientConfigurationCustomizer {\n\n\toverride fun customize(configurer: WebTestClientRestDocumentationConfigurer) {\n\t\tconfigurer.snippets().withEncoding(\"UTF-8\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyUsersDocumentationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation\nimport org.springframework.test.web.reactive.server.WebTestClient\n\n@WebFluxTest\n@AutoConfigureRestDocs\nclass MyUsersDocumentationTests(@Autowired val webTestClient: WebTestClient) {\n\n\t@Test\n\tfun listUsers() {\n\t\twebTestClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk\n\t\t\t.expectBody()\n\t\t\t.consumeWith(WebTestClientRestDocumentation.document(\"list-users\"))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation\nimport org.springframework.test.web.reactive.server.WebTestClient\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyWebTestClientBuilderCustomizerConfiguration {\n\n\t@Bean\n\tfun restDocumentation(): WebTestClientBuilderCustomizer {\n\t\treturn WebTestClientBuilderCustomizer { builder: WebTestClient.Builder ->\n\t\t\tbuilder.entityExchangeResultConsumer(\n\t\t\t\tWebTestClientRestDocumentation.document(\"{method-name}\")\n\t\t\t)\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/MyWebServiceClientTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.webservices.test.autoconfigure.client.WebServiceClientTest\nimport org.springframework.ws.test.client.MockWebServiceServer\nimport org.springframework.ws.test.client.RequestMatchers\nimport org.springframework.ws.test.client.ResponseCreators\nimport org.springframework.xml.transform.StringSource\n\n@WebServiceClientTest(SomeWebService::class)\nclass MyWebServiceClientTests(\n\t\t@Autowired val server: MockWebServiceServer, @Autowired val someWebService: SomeWebService) {\n\n\t@Test\n\tfun mockServerCall() {\n\t\tserver\n\t\t\t.expect(RequestMatchers.payload(StringSource(\"<request/>\")))\n\t\t\t.andRespond(ResponseCreators.withPayload(StringSource(\"<response><status>200</status></response>\")))\n\t\tassertThat(this.someWebService.test()).extracting(Response::status).isEqualTo(200)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/Request.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client\n\nimport jakarta.xml.bind.annotation.XmlRootElement\n\n@XmlRootElement(name = \"request\")\nclass Request\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/Response.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client\n\nimport jakarta.xml.bind.annotation.XmlAccessType\nimport jakarta.xml.bind.annotation.XmlAccessorType\nimport jakarta.xml.bind.annotation.XmlRootElement\n\n@XmlRootElement(name = \"response\")\n@XmlAccessorType(XmlAccessType.FIELD)\nclass Response {\n\tval status = 0\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/client/SomeWebService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.client\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder\nimport org.springframework.stereotype.Service\nimport org.springframework.ws.client.core.WebServiceTemplate\n\n@Service\nclass SomeWebService(builder: WebServiceTemplateBuilder) {\n\n\tprivate val webServiceTemplate: WebServiceTemplate\n\n\tinit {\n\t\twebServiceTemplate = builder.build()\n\t}\n\n\tfun test(): Response {\n\t\treturn webServiceTemplate.marshalSendAndReceive(\"https://example.com\", Request()) as Response\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/server/ExampleEndpoint.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.server\n\nimport javax.xml.transform.Source\n\nimport org.springframework.ws.server.endpoint.annotation.Endpoint\nimport org.springframework.ws.server.endpoint.annotation.PayloadRoot\nimport org.springframework.ws.server.endpoint.annotation.ResponsePayload\nimport org.springframework.xml.transform.StringSource\n\n@Endpoint\nclass ExampleEndpoint {\n\n\t@PayloadRoot(localPart = \"ExampleRequest\")\n\t@ResponsePayload\n\tfun handleRequest(): Source {\n\t\treturn StringSource(\"<ExampleResponse>42</ExampleResponse>\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredwebservices/server/MyWebServiceServerTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.autoconfiguredwebservices.server\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.webservices.test.autoconfigure.server.WebServiceServerTest\nimport org.springframework.ws.test.server.MockWebServiceClient\nimport org.springframework.ws.test.server.RequestCreators\nimport org.springframework.ws.test.server.ResponseMatchers\nimport org.springframework.xml.transform.StringSource\n\n@WebServiceServerTest(ExampleEndpoint::class)\nclass MyWebServiceServerTests(@Autowired val client: MockWebServiceClient) {\n\n\t@Test\n\tfun mockServerCall() {\n\t\tclient\n\t\t\t.sendRequest(RequestCreators.withPayload(StringSource(\"<ExampleRequest/>\")))\n\t\t\t.andExpect(ResponseMatchers.payload(StringSource(\"<ExampleResponse>42</ExampleResponse>\")))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/detectingwebapptype/MyWebFluxTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.detectingwebapptype\n\nimport org.springframework.boot.test.context.SpringBootTest\n\n@SpringBootTest(properties = [\"spring.main.web-application-type=reactive\"])\nclass MyWebFluxTests {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/excludingconfiguration/MyTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.excludingconfiguration\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.context.annotation.Import\n\n@SpringBootTest\n@Import(MyTestsConfiguration::class)\nclass MyTests {\n\n\t@Test\n\tfun exampleTest() {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/excludingconfiguration/MyTestsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.excludingconfiguration\n\nclass MyTestsConfiguration\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/jmx/MyJmxTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jmx\n\nimport javax.management.MBeanServer\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.test.annotation.DirtiesContext\n\n@SpringBootTest(properties = [\"spring.jmx.enabled=true\"])\n@DirtiesContext\nclass MyJmxTests(@Autowired val mBeanServer: MBeanServer) {\n\n\t@Test\n\tfun exampleTest() {\n\t\tassertThat(mBeanServer.domains).contains(\"java.lang\")\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/jmx/SampleApp.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jmx\n\nimport org.springframework.boot.SpringBootConfiguration\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration\n\n@SpringBootConfiguration\n@ImportAutoConfiguration(JmxAutoConfiguration::class)\nclass SampleApp\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/jsontests/MyJsonAssertJTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.assertj.core.api.Assertions.within\nimport org.assertj.core.api.ThrowingConsumer\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.autoconfigure.json.JsonTest\nimport org.springframework.boot.test.json.JacksonTester\n\n@JsonTest\nclass MyJsonAssertJTests(@Autowired val json: JacksonTester<SomeObject>) {\n\n\t// tag::code[]\n\t@Test\n\tfun someTest() {\n\t\tval value = SomeObject(0.152f)\n\t\tassertThat(json.write(value)).extractingJsonPathNumberValue(\"@.test.numberValue\")\n\t\t\t.satisfies(ThrowingConsumer { number ->\n\t\t\t\tassertThat(number.toFloat()).isCloseTo(0.15f, within(0.01f))\n\t\t\t})\n\t}\n\t// end::code[]\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/jsontests/MyJsonTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.autoconfigure.json.JsonTest\nimport org.springframework.boot.test.json.JacksonTester\n\n@JsonTest\nclass MyJsonTests(@Autowired val json: JacksonTester<VehicleDetails>) {\n\n\t@Test\n\tfun serialize() {\n\t\tval details = VehicleDetails(\"Honda\", \"Civic\")\n\t\t// Assert against a `.json` file in the same package as the test\n\t\tassertThat(json.write(details)).isEqualToJson(\"expected.json\")\n\t\t// Or use JSON path based assertions\n\t\tassertThat(json.write(details)).hasJsonPathStringValue(\"@.make\")\n\t\tassertThat(json.write(details)).extractingJsonPathStringValue(\"@.make\").isEqualTo(\"Honda\")\n\t}\n\n\t@Test\n\tfun deserialize() {\n\t\tval content = \"{\\\"make\\\":\\\"Ford\\\",\\\"model\\\":\\\"Focus\\\"}\"\n\t\tassertThat(json.parse(content)).isEqualTo(VehicleDetails(\"Ford\", \"Focus\"))\n\t\tassertThat(json.parseObject(content).make).isEqualTo(\"Ford\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/jsontests/SomeObject.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass SomeObject(value: Float)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/jsontests/VehicleDetails.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jsontests\n\ndata class VehicleDetails(val make: String, val model: String)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springgraphqltests/GraphQlIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springgraphqltests\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.graphql.test.tester.HttpGraphQlTester\nimport org.springframework.http.HttpHeaders\nimport org.springframework.test.web.reactive.server.WebTestClient\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureHttpGraphQlTester\nclass GraphQlIntegrationTests {\n\n\t@Test\n\tfun shouldGreetWithSpecificName(@Autowired graphQlTester: HttpGraphQlTester) {\n\t\tval authenticatedTester = graphQlTester.mutate()\n\t\t\t.webTestClient { client: WebTestClient.Builder ->\n\t\t\t\tclient.defaultHeaders { headers: HttpHeaders ->\n\t\t\t\t\theaders.setBasicAuth(\"admin\", \"ilovespring\")\n\t\t\t\t}\n\t\t\t}.build()\n\t\tauthenticatedTester.document(\"{ greeting(name: \\\"Alice\\\") } \").execute()\n\t\t\t.path(\"greeting\").entity(String::class.java).isEqualTo(\"Hello, Alice!\")\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springgraphqltests/GreetingControllerTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springgraphqltests\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.docs.web.graphql.runtimewiring.GreetingController\nimport org.springframework.boot.graphql.test.autoconfigure.GraphQlTest\nimport org.springframework.graphql.test.tester.GraphQlTester\n\n@GraphQlTest(GreetingController::class)\ninternal class GreetingControllerTests {\n\n\t@Autowired\n\tlateinit var graphQlTester: GraphQlTester\n\n\t@Test\n\tfun shouldGreetWithSpecificName() {\n\t\tgraphQlTester.document(\"{ greeting(name: \\\"Alice\\\") } \").execute().path(\"greeting\").entity(String::class.java)\n\t\t\t\t.isEqualTo(\"Hello, Alice!\")\n\t}\n\n\t@Test\n\tfun shouldGreetWithDefaultName() {\n\t\tgraphQlTester.document(\"{ greeting } \").execute().path(\"greeting\").entity(String::class.java)\n\t\t\t\t.isEqualTo(\"Hello, Spring!\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springmvctests/MyControllerTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.mockito.BDDMockito.given\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest\nimport org.springframework.http.MediaType\nimport org.springframework.test.context.bean.override.mockito.MockitoBean\nimport org.springframework.test.web.servlet.assertj.MockMvcTester\n\n@WebMvcTest(UserVehicleController::class)\nclass MyControllerTests(@Autowired val mvc: MockMvcTester) {\n\n\t@MockitoBean\n\tlateinit var userVehicleService: UserVehicleService\n\n\t@Test\n\tfun testExample() {\n\t\tgiven(userVehicleService.getVehicleDetails(\"sboot\"))\n\t\t\t\t.willReturn(VehicleDetails(\"Honda\", \"Civic\"))\n\t\tassertThat(mvc.get().uri(\"/sboot/vehicle\").accept(MediaType.TEXT_PLAIN))\n\t\t\t\t.hasStatusOk().hasBodyTextEqualTo(\"Honda Civic\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springmvctests/MyHtmlUnitTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.htmlunit.WebClient\nimport org.htmlunit.html.HtmlPage\nimport org.junit.jupiter.api.Test\nimport org.mockito.BDDMockito.given\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest\nimport org.springframework.test.context.bean.override.mockito.MockitoBean\n\n@WebMvcTest(UserVehicleController::class)\nclass MyHtmlUnitTests(@Autowired val webClient: WebClient) {\n\n\t@MockitoBean\n\tlateinit var userVehicleService: UserVehicleService\n\n\t@Test\n\tfun testExample() {\n\t\tgiven(userVehicleService.getVehicleDetails(\"sboot\")).willReturn(VehicleDetails(\"Honda\", \"Civic\"))\n\t\tval page = webClient.getPage<HtmlPage>(\"/sboot/vehicle.html\")\n\t\tassertThat(page.body.textContent).isEqualTo(\"Honda Civic\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springmvctests/UserVehicleController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests\n\nclass UserVehicleController\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springmvctests/UserVehicleService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass UserVehicleService {\n\n\tfun getVehicleDetails(name: String?): VehicleDetails? {\n\t\treturn null\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springmvctests/VehicleDetails.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springmvctests\n\ndata class VehicleDetails(val make: String, val model: String)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/MyControllerTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests\n\nimport org.junit.jupiter.api.Test\nimport org.mockito.BDDMockito.given\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest\nimport org.springframework.http.MediaType\nimport org.springframework.test.context.bean.override.mockito.MockitoBean\nimport org.springframework.test.web.reactive.server.WebTestClient\nimport org.springframework.test.web.reactive.server.expectBody\n\n@WebFluxTest(UserVehicleController::class)\nclass MyControllerTests(@Autowired val webClient: WebTestClient) {\n\n\t@MockitoBean\n\tlateinit var userVehicleService: UserVehicleService\n\n\t@Test\n\tfun testExample() {\n\t\tgiven(userVehicleService.getVehicleDetails(\"sboot\"))\n\t\t\t.willReturn(VehicleDetails(\"Honda\", \"Civic\"))\n\t\twebClient.get().uri(\"/sboot/vehicle\").accept(MediaType.TEXT_PLAIN).exchange()\n\t\t\t.expectStatus().isOk\n\t\t\t.expectBody<String>().isEqualTo(\"Honda Civic\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/UserVehicleController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests\n\nclass UserVehicleController\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/UserVehicleService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests\n\n@Suppress(\"UNUSED_PARAMETER\")\nclass UserVehicleService {\n\n\tfun getVehicleDetails(name: String?): VehicleDetails? {\n\t\treturn null\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/springwebfluxtests/VehicleDetails.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.springwebfluxtests\n\ndata class VehicleDetails(val make: String, val model: String)\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.data.mongodb.config.EnableMongoAuditing\n\n@SpringBootApplication\n@EnableMongoAuditing\nclass MyApplication {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyMongoConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing\n\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.data.mongodb.config.EnableMongoAuditing\n\n@Configuration(proxyBeanMethods = false)\n@EnableMongoAuditing\nclass MyMongoConfiguration {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyWebConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer\n\n@Configuration(proxyBeanMethods = false)\nclass MyWebConfiguration {\n\n\t@Bean\n\tfun testConfigurer(): WebMvcConfigurer {\n\t\treturn object : WebMvcConfigurer {\n\t\t\t// ...\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/MyWebMvcConfigurer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing\n\nimport org.springframework.stereotype.Component\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer\n\n@Component\nclass MyWebMvcConfigurer : WebMvcConfigurer {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/userconfigurationandslicing/scan/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.userconfigurationandslicing.scan\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.context.annotation.ComponentScan\n\n@SpringBootApplication\n@ComponentScan(\"com.example.app\", \"com.example.another\")\nclass MyApplication {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/usingapplicationarguments/MyApplicationArgumentTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingapplicationarguments\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.ApplicationArguments\nimport org.springframework.boot.test.context.SpringBootTest\n\n@SpringBootTest(args = [\"--app.test=one\"])\nclass MyApplicationArgumentTests {\n\n\t@Test\n\tfun applicationArgumentsPopulated(@Autowired args: ApplicationArguments) {\n\t\tassertThat(args.optionNames).containsOnly(\"app.test\")\n\t\tassertThat(args.getOptionValues(\"app.test\")).containsOnly(\"one\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/usingmain/always/MyApplicationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingmain.always\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.UseMainMethod\n\n@SpringBootTest(useMainMethod = UseMainMethod.ALWAYS)\nclass MyApplicationTests {\n\n\t@Test\n\tfun exampleTest() {\n\t\t// ...\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/usingmain/custom/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingmain.custom\n\nimport org.springframework.boot.Banner\nimport org.springframework.boot.runApplication\nimport org.springframework.boot.autoconfigure.SpringBootApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args) {\n\t\tsetBannerMode(Banner.Mode.OFF)\n\t\tsetAdditionalProfiles(\"myprofile\")\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/usingmain/typical/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.usingmain.typical\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/withmockenvironment/MyMockMvcTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withmockenvironment\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient\nimport org.springframework.test.web.reactive.server.WebTestClient\nimport org.springframework.test.web.reactive.server.expectBody\nimport org.springframework.test.web.servlet.MockMvc\nimport org.springframework.test.web.servlet.assertj.MockMvcTester\nimport org.springframework.test.web.servlet.client.RestTestClient\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse\nimport org.springframework.test.web.servlet.client.expectBody\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers.content\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers.status\n\n@SpringBootTest\n@AutoConfigureMockMvc\n@AutoConfigureRestTestClient\n@AutoConfigureWebTestClient\nclass MyMockMvcTests {\n\n\t@Test\n\tfun testWithMockMvc(@Autowired mvc: MockMvc) {\n\t\tmvc.perform(get(\"/\"))\n\t\t\t.andExpect(status().isOk())\n\t\t\t.andExpect(content().string(\"Hello World\"))\n\t}\n\n\t@Test // If AssertJ is on the classpath, you can use MockMvcTester\n\tfun testWithMockMvcTester(@Autowired mvc: MockMvcTester) {\n\t\tassertThat(mvc.get().uri(\"/\")).hasStatusOk()\n\t\t\t.hasBodyTextEqualTo(\"Hello World\")\n\t}\n\n\t@Test\n\tfun testWithRestTestClient(@Autowired webClient: RestTestClient) {\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk\n\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n\t@Test // If you prefer AssertJ, dedicated assertions are available\n\tfun testWithRestTestClientAssertJ(@Autowired webClient: RestTestClient) {\n\t\tval spec = webClient.get().uri(\"/\").exchange()\n\t\tval response = RestTestClientResponse.from(spec)\n\t\tassertThat(response).hasStatusOk().bodyText().isEqualTo(\"Hello World\")\n\t}\n\n\n\t@Test // If Spring WebFlux is on the classpath\n\tfun testWithWebTestClient(@Autowired webClient: WebTestClient) {\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk\n\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/withmockenvironment/MyMockWebTestClientTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withmockenvironment\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient\nimport org.springframework.test.web.reactive.server.WebTestClient\nimport org.springframework.test.web.reactive.server.expectBody\n\n@SpringBootTest\n@AutoConfigureWebTestClient\nclass MyMockWebTestClientTests {\n\n\t@Test\n\tfun exampleTest(@Autowired webClient: WebTestClient) {\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk\n\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortRestTestClientAssertJTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.test.web.servlet.client.RestTestClient\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureRestTestClient\nclass MyRandomPortRestTestClientAssertJTests {\n\n\t@Test\n\tfun exampleTest(@Autowired webClient: RestTestClient) {\n\t\tval exchange = webClient.get().uri(\"/\").exchange()\n\t\tval response = RestTestClientResponse.from(exchange)\n\t\tassertThat(response).hasStatusOk()\n\t\t\t.bodyText().isEqualTo(\"Hello World\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortRestTestClientTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.test.web.servlet.client.RestTestClient\nimport org.springframework.test.web.servlet.client.expectBody\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureRestTestClient\nclass MyRandomPortRestTestClientTests {\n\n\t@Test\n\tfun exampleTest(@Autowired webClient: RestTestClient) {\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk\n\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortTestRestTemplateTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.boot.resttestclient.TestRestTemplate\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass MyRandomPortTestRestTemplateTests {\n\n\t@Test\n\tfun exampleTest(@Autowired restTemplate: TestRestTemplate) {\n\t\tval body = restTemplate.getForObject(\"/\", String::class.java)\n\t\tassertThat(body).isEqualTo(\"Hello World\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/withrunningserver/MyRandomPortWebTestClientTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.withrunningserver\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient\nimport org.springframework.test.web.reactive.server.WebTestClient\nimport org.springframework.test.web.reactive.server.expectBody\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebTestClient\nclass MyRandomPortWebTestClientTests {\n\n\t@Test\n\tfun exampleTest(@Autowired webClient: WebTestClient) {\n\t\twebClient\n\t\t\t.get().uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus().isOk\n\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/dynamicproperties/MyIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.testing.testcontainers.dynamicproperties\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.test.context.DynamicPropertyRegistry\nimport org.springframework.test.context.DynamicPropertySource\nimport org.testcontainers.junit.jupiter.Container\nimport org.testcontainers.junit.jupiter.Testcontainers\nimport org.testcontainers.neo4j.Neo4jContainer\n\n@Testcontainers\n@SpringBootTest\nclass MyIntegrationTests {\n\n\t@Test\n\tfun myTest() {\n\t\t/**/ println()\n\t}\n\n\tcompanion object {\n\t\t@Container\n\t\t@JvmStatic\n\t\tval neo4j = Neo4jContainer(\"neo4j:5\");\n\n\t\t@DynamicPropertySource\n\t\t@JvmStatic\n\t\tfun neo4jProperties(registry: DynamicPropertyRegistry) {\n\t\t\tregistry.add(\"spring.neo4j.uri\") { neo4j.boltUrl }\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/importingconfigurationinterfaces/MyContainers.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces\n\nimport org.testcontainers.junit.jupiter.Container\nimport org.testcontainers.mongodb.MongoDBContainer\nimport org.testcontainers.neo4j.Neo4jContainer\n\ninterface MyContainers {\n\n\tcompanion object {\n\n\t\t@Container\n\t\tval mongoContainer: MongoDBContainer = MongoDBContainer(\"mongo:5.0\")\n\n\t\t@Container\n\t\tval neo4jContainer: Neo4jContainer = Neo4jContainer(\"neo4j:5\")\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/importingconfigurationinterfaces/MyTestConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.importingconfigurationinterfaces\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers\n\n@TestConfiguration(proxyBeanMethods = false)\n@ImportTestcontainers(MyContainers::class)\nclass MyTestConfiguration {\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/junitextension/MyIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.junitextension\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@Testcontainers\n@SpringBootTest\nclass MyIntegrationTests {\n\n\t@Test\n\tfun myTest() {\n\t\t/**/ println()\n\t}\n\n\tcompanion object {\n\n\t\t@Container\n\t\t@JvmStatic\n\t\tval neo4j = Neo4jContainer(\"neo4j:5\");\n\n\t}\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/serviceconnections/MyIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n@Testcontainers\n@SpringBootTest\nclass MyIntegrationTests {\n\n\t@Test\n\tfun myTest() {\n\t\t/**/ println()\n\t}\n\n\tcompanion object {\n\n\t\t@Container\n\t\t@ServiceConnection\n\t\t@JvmStatic\n\t\tval neo4j = Neo4jContainer(\"neo4j:5\");\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/serviceconnections/MyRedisConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.testcontainers.serviceconnections\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection\nimport org.springframework.context.annotation.Bean\nimport org.testcontainers.containers.GenericContainer\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyRedisConfiguration {\n\n\t@Bean\n\t@ServiceConnection(name = \"redis\")\n\tfun redisContainer(): GenericContainer<*> {\n\t\treturn GenericContainer(\"redis:7\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/springbeans/MyIntegrationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.testing.testcontainers.springbeans\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.context.annotation.Import\nimport org.testcontainers.mongodb.MongoDBContainer\n\n@SpringBootTest\n@Import(MyTestConfiguration::class)\nclass MyIntegrationTests {\n\n\t@Autowired\n\tprivate val mongo: MongoDBContainer? = null\n\n\t@Test\n\tfun myTest() {\n\t\t/**/ println()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/testcontainers/springbeans/MyTestConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.springframework.boot.docs.testing.testcontainers.springbeans\n\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.context.annotation.Bean\nimport org.testcontainers.mongodb.MongoDBContainer\nimport org.testcontainers.utility.DockerImageName\n\n@TestConfiguration(proxyBeanMethods = false)\nclass MyTestConfiguration {\n\n\t@Bean\n\tfun mongoDbContainer(): MongoDBContainer {\n\t\treturn MongoDBContainer(DockerImageName.parse(\"mongo:5.0\"))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/configdataapplicationcontextinitializer/Config.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.configdataapplicationcontextinitializer\n\nclass Config\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/configdataapplicationcontextinitializer/MyConfigFileTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.configdataapplicationcontextinitializer\n\nimport org.springframework.boot.test.context.ConfigDataApplicationContextInitializer\nimport org.springframework.test.context.ContextConfiguration\n\n@ContextConfiguration(classes = [Config::class], initializers = [ConfigDataApplicationContextInitializer::class])\nclass MyConfigFileTests {\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/outputcapture/MyOutputCaptureTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.outputcapture\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.extension.ExtendWith\nimport org.springframework.boot.test.system.CapturedOutput\nimport org.springframework.boot.test.system.OutputCaptureExtension\n\n@ExtendWith(OutputCaptureExtension::class)\nclass MyOutputCaptureTests {\n\n\t@Test\n\tfun testName(output: CapturedOutput?) {\n\t\tprintln(\"Hello World!\")\n\t\tassertThat(output).contains(\"World\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/testpropertyvalues/MyEnvironmentTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testpropertyvalues\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.test.util.TestPropertyValues\nimport org.springframework.mock.env.MockEnvironment\n\nclass MyEnvironmentTests {\n\n\t@Test\n\tfun testPropertySources() {\n\t\tval environment = MockEnvironment()\n\t\tTestPropertyValues.of(\"org=Spring\", \"name=Boot\").applyTo(environment)\n\t\tassertThat(environment.getProperty(\"name\")).isEqualTo(\"Boot\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/testresttemplate/MySpringBootTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.boot.test.context.TestConfiguration\nimport org.springframework.boot.restclient.RestTemplateBuilder\nimport org.springframework.boot.resttestclient.TestRestTemplate\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate\nimport org.springframework.context.annotation.Bean\nimport org.springframework.http.HttpStatus\nimport java.time.Duration\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass MySpringBootTests(@Autowired val template: TestRestTemplate) {\n\n\t@Test\n\tfun testRequest() {\n\t\tval response = template.getForEntity(\"/example\", String::class.java)\n\t\tassertThat(response.statusCode).isEqualTo(HttpStatus.OK)\n\t\t// Other assertions to verify the response\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tinternal class RestTemplateBuilderConfiguration {\n\n\t\t@Bean\n\t\tfun restTemplateBuilder(): RestTemplateBuilder {\n\t\t\treturn RestTemplateBuilder().connectTimeout(Duration.ofSeconds(1))\n\t\t\t\t.readTimeout(Duration.ofSeconds(1))\n\t\t}\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/testresttemplate/MySpringBootTestsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate\n\nimport org.springframework.boot.SpringBootConfiguration\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration\nimport org.springframework.http.ResponseEntity\nimport org.springframework.web.bind.annotation.RequestMapping\nimport org.springframework.web.bind.annotation.RestController\nimport java.net.URI\n\n@SpringBootConfiguration(proxyBeanMethods = false)\n@ImportAutoConfiguration(\n\tTomcatServletWebServerAutoConfiguration::class,\n\tDispatcherServletAutoConfiguration::class,\n\tJacksonAutoConfiguration::class,\n\tHttpMessageConvertersAutoConfiguration::class\n)\nclass MySpringBootTestsConfiguration {\n\n\t@RestController\n\tprivate class ExampleController {\n\n\t\t@RequestMapping(\"/example\")\n\t\tfun example(): ResponseEntity<String> {\n\t\t\treturn ResponseEntity.ok().location(URI.create(\"https://other.example.com/example\")).body(\"test\")\n\t\t}\n\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/utilities/testresttemplate/MyTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate\n\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.resttestclient.TestRestTemplate\nimport org.springframework.http.HttpStatus\n\nclass MyTests {\n\n\tprivate val template = TestRestTemplate()\n\n\t@Test\n\tfun testRequest() {\n\t\tval response = template.getForEntity(\"https://myhost.example.com/example\", String::class.java)\n\t\tassertThat(response.statusCode).isEqualTo(HttpStatus.OK)\n\t\t// Other assertions to verify the response\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/autoconfiguration/disablingspecific/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.autoconfiguration.disablingspecific\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\n\n@SpringBootApplication(exclude = [DataSourceAutoConfiguration::class])\nclass MyApplication\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/devtools/restart/disable/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.devtools.restart.disable\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\tSystem.setProperty(\"spring.devtools.restart.enabled\", \"false\")\n\trunApplication<MyApplication>(*args)\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/springbeansanddependencyinjection/multipleconstructors/AccountService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.multipleconstructors\n\ninterface AccountService {\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/springbeansanddependencyinjection/multipleconstructors/MyAccountService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.multipleconstructors\n\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.stereotype.Service\nimport java.io.PrintStream\n\n@Service\nclass MyAccountService : AccountService {\n\n\tprivate val riskAssessor: RiskAssessor\n\n\tprivate val out: PrintStream\n\n\t@Autowired\n\tconstructor(riskAssessor: RiskAssessor) {\n\t\tthis.riskAssessor = riskAssessor\n\t\tout = System.out\n\t}\n\n\tconstructor(riskAssessor: RiskAssessor, out: PrintStream) {\n\t\tthis.riskAssessor = riskAssessor\n\t\tthis.out = out\n\t}\n\n\t// ...\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/springbeansanddependencyinjection/multipleconstructors/RiskAssessor.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.multipleconstructors\n\ninterface RiskAssessor {\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/springbeansanddependencyinjection/singleconstructor/AccountService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.singleconstructor\n\ninterface AccountService {\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/springbeansanddependencyinjection/singleconstructor/MyAccountService.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.singleconstructor\n\nimport org.springframework.stereotype.Service\n\n@Service\nclass MyAccountService(private val riskAssessor: RiskAssessor) : AccountService\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/springbeansanddependencyinjection/singleconstructor/RiskAssessor.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.springbeansanddependencyinjection.singleconstructor\n\ninterface RiskAssessor {\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/structuringyourcode/locatingthemainclass/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/individualannotations/AnotherConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.individualannotations\n\nclass AnotherConfiguration\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/individualannotations/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.individualannotations\n\nimport org.springframework.boot.SpringBootConfiguration\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration\nimport org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication\nimport org.springframework.boot.runApplication\nimport org.springframework.context.annotation.Import\n\n@SpringBootConfiguration(proxyBeanMethods = false)\n@EnableAutoConfiguration\n@Import(SomeConfiguration::class, AnotherConfiguration::class)\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/individualannotations/SomeConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.individualannotations\n\nclass SomeConfiguration\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/using/usingthespringbootapplicationannotation/springapplication/MyApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.using.usingthespringbootapplicationannotation.springapplication\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n// Same as @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan\n@SpringBootApplication\nclass MyApplication\n\nfun main(args: Array<String>) {\n\trunApplication<MyApplication>(*args)\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/graphql/runtimewiring/GreetingController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.graphql.runtimewiring\n\nimport org.springframework.graphql.data.method.annotation.Argument\nimport org.springframework.graphql.data.method.annotation.QueryMapping\nimport org.springframework.stereotype.Controller\n\n@Controller\nclass GreetingController {\n\n\t@QueryMapping\n\tfun greeting(@Argument name: String): String {\n\t\treturn \"Hello, $name!\"\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/graphql/transports/rsocket/RSocketGraphQlClientExample.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.graphql.transports.rsocket\n\nimport org.springframework.graphql.client.RSocketGraphQlClient\nimport org.springframework.stereotype.Component\nimport java.time.Duration\n\n// tag::builder[]\n@Component\nclass RSocketGraphQlClientExample(private val builder: RSocketGraphQlClient.Builder<*>) {\n// end::builder[]\n\n\tval graphQlClient = builder.tcp(\"example.spring.io\", 8181)\n\t\t.route(\"graphql\")\n\t\t.build()\n\n\tfun rsocketOverTcp() {\n\t\t// tag::request[]\n\t\tval book = graphQlClient.document(\n\t\t\t\"\"\"\n\t\t\t{\n\t\t\t\tbookById(id: \"book-1\"){\n\t\t\t\t\tid\n\t\t\t\t\tname\n\t\t\t\t\tpageCount\n\t\t\t\t\tauthor\n\t\t\t\t}\n\t\t\t}\t\t\t\t\n\t\t\t\"\"\"\n\t\t)\n\t\t\t.retrieve(\"bookById\").toEntity(Book::class.java)\n\t\t// end::request[]\n\t\tbook.block(Duration.ofSeconds(5))\n\t}\n\n\tinternal class Book\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/reactiveserver/customizing/programmatic/MyNettyWebServerFactoryCustomizer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.reactiveserver.customizing.programmatic\n\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory\nimport org.springframework.stereotype.Component\nimport java.time.Duration\n\n@Component\nclass MyNettyWebServerFactoryCustomizer : WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {\n\n\toverride fun customize(factory: NettyReactiveWebServerFactory) {\n\t\tfactory.addServerCustomizers({ server -> server.idleTimeout(Duration.ofSeconds(20)) })\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/reactiveserver/customizing/programmatic/MyWebServerFactoryCustomizer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.reactiveserver.customizing.programmatic\n\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyWebServerFactoryCustomizer : WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> {\n\n\toverride fun customize(server: ConfigurableReactiveWebServerFactory) {\n\t\tserver.setPort(9000)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/Customer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nclass Customer\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/CustomerRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository\nimport reactor.core.publisher.Flux\n\ninterface CustomerRepository : ReactiveCrudRepository<Customer, Long> {\n\n\tfun findByUser(user: User?): Flux<Customer>\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/MyRestController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nimport org.springframework.web.bind.annotation.DeleteMapping\nimport org.springframework.web.bind.annotation.GetMapping\nimport org.springframework.web.bind.annotation.PathVariable\nimport org.springframework.web.bind.annotation.RequestMapping\nimport org.springframework.web.bind.annotation.RestController\nimport reactor.core.publisher.Flux\nimport reactor.core.publisher.Mono\n\n@RestController\n@RequestMapping(\"/users\")\nclass MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) {\n\n\t@GetMapping(\"/{userId}\")\n\tfun getUser(@PathVariable userId: Long): Mono<User> {\n\t\treturn userRepository.findById(userId)\n\t}\n\n\t@GetMapping(\"/{userId}/customers\")\n\tfun getUserCustomers(@PathVariable userId: Long): Flux<Customer> {\n\t\treturn userRepository.findById(userId).flatMapMany { user: User ->\n\t\t\tcustomerRepository.findByUser(user)\n\t\t}\n\t}\n\n\t@DeleteMapping(\"/{userId}\")\n\tfun deleteUser(@PathVariable userId: Long): Mono<Void> {\n\t\treturn userRepository.deleteById(userId)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/MyRoutingConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.MediaType\nimport org.springframework.web.reactive.function.server.RequestPredicates.DELETE\nimport org.springframework.web.reactive.function.server.RequestPredicates.GET\nimport org.springframework.web.reactive.function.server.RequestPredicates.accept\nimport org.springframework.web.reactive.function.server.RouterFunction\nimport org.springframework.web.reactive.function.server.RouterFunctions\nimport org.springframework.web.reactive.function.server.ServerResponse\n\n@Configuration(proxyBeanMethods = false)\nclass MyRoutingConfiguration {\n\n\t@Bean\n\tfun monoRouterFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> {\n\t\treturn RouterFunctions.route(\n\t\t\tGET(\"/{user}\").and(ACCEPT_JSON), userHandler::getUser).andRoute(\n\t\t\tGET(\"/{user}/customers\").and(ACCEPT_JSON), userHandler::getUserCustomers).andRoute(\n\t\t\tDELETE(\"/{user}\").and(ACCEPT_JSON), userHandler::deleteUser)\n\t}\n\n\tcompanion object {\n\t\tprivate val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/MyUserHandler.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nimport org.springframework.stereotype.Component\nimport org.springframework.web.reactive.function.server.ServerRequest\nimport org.springframework.web.reactive.function.server.ServerResponse\nimport reactor.core.publisher.Mono\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyUserHandler {\n\n\tfun getUser(request: ServerRequest?): Mono<ServerResponse> {\n\t\t/**/ return ServerResponse.ok().build()\n\t}\n\n\tfun getUserCustomers(request: ServerRequest?): Mono<ServerResponse> {\n\t\t/**/ return ServerResponse.ok().build()\n\t}\n\n\tfun deleteUser(request: ServerRequest?): Mono<ServerResponse> {\n\t\t/**/ return ServerResponse.ok().build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nclass User {\n\n\tval customers: List<Customer>?\n\t\tget() = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/UserRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository\n\ninterface UserRepository : ReactiveCrudRepository<User, Long>\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/errorhandling/MyErrorWebExceptionHandler.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux.errorhandling\n\nimport org.springframework.boot.autoconfigure.web.WebProperties\nimport org.springframework.boot.webflux.error.ErrorAttributes\nimport org.springframework.boot.webflux.autoconfigure.error.AbstractErrorWebExceptionHandler\nimport org.springframework.context.ApplicationContext\nimport org.springframework.http.HttpStatus\nimport org.springframework.http.MediaType\nimport org.springframework.http.codec.ServerCodecConfigurer\nimport org.springframework.stereotype.Component\nimport org.springframework.web.reactive.function.server.RouterFunction\nimport org.springframework.web.reactive.function.server.RouterFunctions\nimport org.springframework.web.reactive.function.server.ServerRequest\nimport org.springframework.web.reactive.function.server.ServerResponse\nimport reactor.core.publisher.Mono\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyErrorWebExceptionHandler(\n\t\terrorAttributes: ErrorAttributes, webProperties: WebProperties,\n\t\tapplicationContext: ApplicationContext, serverCodecConfigurer: ServerCodecConfigurer\n) : AbstractErrorWebExceptionHandler(errorAttributes, webProperties.resources, applicationContext) {\n\n\tinit {\n\t\tsetMessageReaders(serverCodecConfigurer.readers)\n\t\tsetMessageWriters(serverCodecConfigurer.writers)\n\t}\n\n\toverride fun getRoutingFunction(errorAttributes: ErrorAttributes): RouterFunction<ServerResponse> {\n\t\treturn RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml)\n\t}\n\n\tprivate fun acceptsXml(request: ServerRequest): Boolean {\n\t\treturn request.headers().accept().contains(MediaType.APPLICATION_XML)\n\t}\n\n\tfun handleErrorAsXml(request: ServerRequest): Mono<ServerResponse> {\n\t\tval builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t// ... additional builder calls\n\t\treturn builder.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/reactive/webflux/httpcodecs/MyCodecsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.reactive.webflux.httpcodecs\n\nimport org.springframework.boot.http.codec.CodecCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.http.codec.CodecConfigurer\nimport org.springframework.http.codec.ServerSentEventHttpMessageReader\n\nclass MyCodecsConfiguration {\n\n\t@Bean\n\tfun myCodecCustomizer(): CodecCustomizer {\n\t\treturn CodecCustomizer { configurer: CodecConfigurer ->\n\t\t\tconfigurer.registerDefaults(false)\n\t\t\tconfigurer.customCodecs().register(ServerSentEventHttpMessageReader())\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/security/oauth2/client/MyOAuthClientConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.security.oauth2.client\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity\nimport org.springframework.security.config.annotation.web.invoke\nimport org.springframework.security.web.SecurityFilterChain\n\n@Configuration(proxyBeanMethods = false)\n@EnableWebSecurity\nopen class MyOAuthClientConfiguration {\n\n\t@Bean\n\topen fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {\n\t\thttp {\n\t\t\tauthorizeHttpRequests {\n\t\t\t\tauthorize(anyRequest, authenticated)\n\t\t\t}\n\t\t\toauth2Login {\n\t\t\t\tredirectionEndpoint {\n\t\t\t\t\tbaseUri = \"/login/oauth2/callback/*\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn http.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/security/springwebflux/MyWebFluxSecurityConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.security.springwebflux\n\nimport org.springframework.boot.security.autoconfigure.web.reactive.PathRequest\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.security.config.Customizer.withDefaults\nimport org.springframework.security.config.web.server.ServerHttpSecurity\nimport org.springframework.security.web.server.SecurityWebFilterChain\n\n@Configuration(proxyBeanMethods = false)\nclass MyWebFluxSecurityConfiguration {\n\n\t@Bean\n\tfun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {\n\t\thttp.authorizeExchange { spec ->\n\t\t\tspec.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()\n\t\t\tspec.pathMatchers(\"/foo\", \"/bar\").authenticated()\n\t\t}\n\t\thttp.formLogin(withDefaults())\n\t\treturn http.build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/embeddedcontainer/applicationcontext/MyDemoBean.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.applicationcontext\n\nimport jakarta.servlet.ServletContext\nimport org.springframework.boot.context.event.ApplicationStartedEvent\nimport org.springframework.context.ApplicationContext\nimport org.springframework.context.ApplicationListener\nimport org.springframework.web.context.WebApplicationContext\n\nclass MyDemoBean : ApplicationListener<ApplicationStartedEvent> {\n\n\t@Suppress(\"unused\")\n\tprivate var servletContext: ServletContext? = null\n\n\toverride fun onApplicationEvent(event: ApplicationStartedEvent) {\n\t\tval applicationContext: ApplicationContext = event.applicationContext\n\t\tthis.servletContext = (applicationContext as WebApplicationContext).servletContext\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/embeddedcontainer/customizing/programmatic/MyTomcatWebServerFactoryCustomizer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.customizing.programmatic\n\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory\nimport org.springframework.stereotype.Component\nimport java.time.Duration\n\n@Component\nclass MyTomcatWebServerFactoryCustomizer : WebServerFactoryCustomizer<TomcatServletWebServerFactory> {\n\n\toverride fun customize(server: TomcatServletWebServerFactory) {\n\t\tserver.addConnectorCustomizers({ connector -> connector.asyncTimeout = Duration.ofSeconds(20).toMillis() })\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/embeddedcontainer/customizing/programmatic/MyWebServerFactoryCustomizer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.customizing.programmatic\n\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyWebServerFactoryCustomizer : WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {\n\n\toverride fun customize(server: ConfigurableServletWebServerFactory) {\n\t\tserver.setPort(9000)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/embeddedcontainer/customizing/samesite/MySameSiteConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.embeddedcontainer.customizing.samesite\n\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n@Configuration(proxyBeanMethods = false)\nclass MySameSiteConfiguration {\n\n\t@Bean\n\tfun applicationCookieSameSiteSupplier(): CookieSameSiteSupplier {\n\t\treturn CookieSameSiteSupplier.ofLax().whenHasNameMatching(\"myapp.*\")\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/jersey/MyEndpoint.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.jersey\n\nimport jakarta.ws.rs.GET\nimport jakarta.ws.rs.Path\nimport org.springframework.stereotype.Component\n\n@Component\n@Path(\"/hello\")\nclass MyEndpoint {\n\n\t@GET\n\tfun message(): String {\n\t\treturn \"Hello\"\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/jersey/MyJerseyConfig.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.jersey\n\nimport org.glassfish.jersey.server.ResourceConfig\nimport org.springframework.stereotype.Component\n\n@Component\nclass MyJerseyConfig : ResourceConfig() {\n\n\tinit {\n\t\tregister(MyEndpoint::class.java)\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/Customer.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nclass Customer\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/CustomerRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nimport org.springframework.data.repository.CrudRepository\n\ninterface CustomerRepository : CrudRepository<Customer, Long> {\n\n\tfun findByUser(user: User?): List<Customer>?\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/MyRestController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nimport org.springframework.web.bind.annotation.DeleteMapping\nimport org.springframework.web.bind.annotation.GetMapping\nimport org.springframework.web.bind.annotation.PathVariable\nimport org.springframework.web.bind.annotation.RequestMapping\nimport org.springframework.web.bind.annotation.RestController\n\n\n@RestController\n@RequestMapping(\"/users\")\nclass MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) {\n\n\t@GetMapping(\"/{userId}\")\n\tfun getUser(@PathVariable userId: Long): User {\n\t\treturn userRepository.findById(userId).get()\n\t}\n\n\t@GetMapping(\"/{userId}/customers\")\n\tfun getUserCustomers(@PathVariable userId: Long): List<Customer> {\n\t\treturn userRepository.findById(userId).map(customerRepository::findByUser).get()\n\t}\n\n\t@DeleteMapping(\"/{userId}\")\n\tfun deleteUser(@PathVariable userId: Long) {\n\t\tuserRepository.deleteById(userId)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/MyRoutingConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.MediaType\nimport org.springframework.web.servlet.function.RequestPredicates.accept\nimport org.springframework.web.servlet.function.RouterFunction\nimport org.springframework.web.servlet.function.RouterFunctions\nimport org.springframework.web.servlet.function.ServerResponse\n\n@Configuration(proxyBeanMethods = false)\nclass MyRoutingConfiguration {\n\n\t@Bean\n\tfun routerFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> {\n\t\treturn RouterFunctions.route()\n\t\t\t.GET(\"/{user}\", ACCEPT_JSON, userHandler::getUser)\n\t\t\t.GET(\"/{user}/customers\", ACCEPT_JSON, userHandler::getUserCustomers)\n\t\t\t.DELETE(\"/{user}\", ACCEPT_JSON, userHandler::deleteUser)\n\t\t\t.build()\n\t}\n\n\tcompanion object {\n\t\tprivate val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON)\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/MyUserHandler.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nimport org.springframework.stereotype.Component\nimport org.springframework.web.servlet.function.ServerRequest\nimport org.springframework.web.servlet.function.ServerResponse\n\n@Suppress(\"UNUSED_PARAMETER\")\n@Component\nclass MyUserHandler {\n\n\tfun getUser(request: ServerRequest?): ServerResponse {\n\t\t/**/ return ServerResponse.ok().build()\n\t}\n\n\tfun getUserCustomers(request: ServerRequest?): ServerResponse {\n\t\t/**/ return ServerResponse.ok().build()\n\t}\n\n\tfun deleteUser(request: ServerRequest?): ServerResponse {\n\t\t/**/ return ServerResponse.ok().build()\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/User.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nclass User {\n\n\tval customers: List<Customer>?\n\t\tget() = null\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/UserRepository.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc\n\nimport org.springframework.data.repository.CrudRepository\n\ninterface UserRepository : CrudRepository<User, Long>\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/cors/MyCorsConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.cors\n\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.web.servlet.config.annotation.CorsRegistry\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer\n\n@Configuration(proxyBeanMethods = false)\nclass MyCorsConfiguration {\n\n\t@Bean\n\tfun corsConfigurer(): WebMvcConfigurer {\n\t\treturn object : WebMvcConfigurer {\n\t\t\toverride fun addCorsMappings(registry: CorsRegistry) {\n\t\t\t\tregistry.addMapping(\"/api/**\")\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/CustomException.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling\n\nclass CustomException : RuntimeException()\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/MyControllerAdvice.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling\n\nimport jakarta.servlet.RequestDispatcher\nimport jakarta.servlet.http.HttpServletRequest\nimport org.springframework.http.HttpStatus\nimport org.springframework.http.ResponseEntity\nimport org.springframework.web.bind.annotation.ControllerAdvice\nimport org.springframework.web.bind.annotation.ExceptionHandler\nimport org.springframework.web.bind.annotation.ResponseBody\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler\n\n@ControllerAdvice(basePackageClasses = [SomeController::class])\nclass MyControllerAdvice : ResponseEntityExceptionHandler() {\n\n\t@ResponseBody\n\t@ExceptionHandler(MyException::class)\n\tfun handleControllerException(request: HttpServletRequest, ex: Throwable): ResponseEntity<*> {\n\t\tval status = getStatus(request)\n\t\treturn ResponseEntity(MyErrorBody(status.value(), ex.message), status)\n\t}\n\n\tprivate fun getStatus(request: HttpServletRequest): HttpStatus {\n\t\tval code = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE) as Int\n\t\tval status = HttpStatus.resolve(code)\n\t\treturn status ?: HttpStatus.INTERNAL_SERVER_ERROR\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/MyErrorBody.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling\n\nclass MyErrorBody(value: Int, message: String?)\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/MyException.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling\n\nclass MyException: RuntimeException()\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/SomeController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling\n\nclass SomeController\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpages/MyErrorViewResolver.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpages\n\nimport jakarta.servlet.http.HttpServletRequest\nimport org.springframework.boot.webmvc.autoconfigure.error.ErrorViewResolver\nimport org.springframework.http.HttpStatus\nimport org.springframework.web.servlet.ModelAndView\n\nclass MyErrorViewResolver : ErrorViewResolver {\n\n\toverride fun resolveErrorView(request: HttpServletRequest, status: HttpStatus,\n\t\t\tmodel: Map<String, Any>): ModelAndView? {\n\t\t// Use the request or status to optionally return a ModelAndView\n\t\tif (status == HttpStatus.INSUFFICIENT_STORAGE) {\n\t\t\t// We could add custom model values here\n\t\t\treturn ModelAndView(\"myview\")\n\t\t}\n\t\treturn null\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/MyErrorPagesConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc\n\nimport org.springframework.boot.web.error.ErrorPage\nimport org.springframework.boot.web.error.ErrorPageRegistrar\nimport org.springframework.boot.web.error.ErrorPageRegistry\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.HttpStatus\n\n@Configuration(proxyBeanMethods = false)\nclass MyErrorPagesConfiguration {\n\n\t@Bean\n\tfun errorPageRegistrar(): ErrorPageRegistrar {\n\t\treturn ErrorPageRegistrar { registry: ErrorPageRegistry -> registerErrorPages(registry) }\n\t}\n\n\tprivate fun registerErrorPages(registry: ErrorPageRegistry) {\n\t\tregistry.addErrorPages(ErrorPage(HttpStatus.BAD_REQUEST, \"/400\"))\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/MyFilter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc\n\nimport jakarta.servlet.FilterChain\nimport jakarta.servlet.ServletRequest\nimport jakarta.servlet.ServletResponse\nimport org.springframework.web.filter.GenericFilterBean\n\nclass MyFilter : GenericFilterBean() {\n\n\toverride fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/MyFilterConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc\n\nimport jakarta.servlet.DispatcherType\nimport org.springframework.boot.web.servlet.FilterRegistrationBean\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport java.util.EnumSet\n\n@Configuration(proxyBeanMethods = false)\nclass MyFilterConfiguration {\n\n\t@Bean\n\tfun myFilter(): FilterRegistrationBean<MyFilter> {\n\t\tval registration = FilterRegistrationBean(MyFilter())\n\t\t// ...\n\t\tregistration.setDispatcherTypes(EnumSet.allOf(DispatcherType::class.java))\n\t\treturn registration\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/errorhandling/errorpageswithoutspringmvc/SomeController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.errorhandling.errorpageswithoutspringmvc\n\nclass SomeController\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/messageconverters/AdditionalHttpMessageConverter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.messageconverters\n\nimport org.springframework.http.HttpInputMessage\nimport org.springframework.http.HttpOutputMessage\nimport org.springframework.http.converter.AbstractHttpMessageConverter\nimport org.springframework.http.converter.HttpMessageNotReadableException\nimport org.springframework.http.converter.HttpMessageNotWritableException\nimport java.io.IOException\n\nopen class AdditionalHttpMessageConverter : AbstractHttpMessageConverter<Any>() {\n\n\toverride fun supports(type: Class<*>): Boolean {\n\t\treturn false\n\t}\n\n\t@Throws(IOException::class, HttpMessageNotReadableException::class)\n\toverride fun readInternal(type: Class<*>, inputMessage: HttpInputMessage): Any {\n\t\treturn Any()\n\t}\n\n\t@Throws(IOException::class, HttpMessageNotWritableException::class)\n\toverride fun writeInternal(instance: Any, outputMessage: HttpOutputMessage) {\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/messageconverters/AnotherHttpMessageConverter.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.messageconverters\n\nclass AnotherHttpMessageConverter : AdditionalHttpMessageConverter()\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/web/servlet/springmvc/messageconverters/MyHttpMessageConvertersConfiguration.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.web.servlet.springmvc.messageconverters\n\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer\nimport org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\nimport org.springframework.http.converter.HttpMessageConverters\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter\nimport tools.jackson.databind.json.JsonMapper\nimport java.text.SimpleDateFormat\n\n@Configuration(proxyBeanMethods = false)\nclass MyHttpMessageConvertersConfiguration {\n\n\t@Bean\n\tfun myClientConvertersCustomizer(): ClientHttpMessageConvertersCustomizer {\n\t\treturn ClientHttpMessageConvertersCustomizer { clientBuilder: HttpMessageConverters.ClientBuilder ->\n\t\t\tclientBuilder\n\t\t\t\t.addCustomConverter(AdditionalHttpMessageConverter())\n\t\t\t\t.addCustomConverter(AnotherHttpMessageConverter())\n\t\t}\n\t}\n\n\t@Bean\n\tfun jacksonConverterCustomizer(): JacksonConverterCustomizer {\n\t\tval jsonMapper = JsonMapper.builder()\n\t\t\t.defaultDateFormat(SimpleDateFormat(\"yyyy-MM\"))\n\t\t\t.build()\n\t\treturn JacksonConverterCustomizer(jsonMapper)\n\t}\n\n\t// contribute a custom JSON converter to both client and server\n\tclass JacksonConverterCustomizer(private val jsonMapper: JsonMapper) :\n\t\tClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\toverride fun customize(builder: HttpMessageConverters.ClientBuilder) {\n\t\t\tbuilder.withJsonConverter(JacksonJsonHttpMessageConverter(this.jsonMapper))\n\t\t}\n\n\t\toverride fun customize(builder: HttpMessageConverters.ServerBuilder) {\n\t\t\tbuilder.withJsonConverter(JacksonJsonHttpMessageConverter(this.jsonMapper))\n\t\t}\n\t}\n\n}\n\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/main/resources/graphql/schema.graphqls",
    "content": "type Query {\n    greeting(name: String! = \"Spring\"): String!\n    project(slug: ID!): Project\n}\n\n\"\"\" A Project in the Spring portfolio \"\"\"\ntype Project {\n    \"\"\" Unique string id used in URLs \"\"\"\n    slug: ID!\n    \"\"\" Project name \"\"\"\n    name: String!\n    \"\"\" URL of the git repository \"\"\"\n    repositoryUrl: String!\n    \"\"\" Current support status \"\"\"\n    status: ProjectStatus!\n}\n\nenum ProjectStatus {\n    \"\"\" Actively supported by the Spring team \"\"\"\n    ACTIVE\n    \"\"\" Supported by the community \"\"\"\n    COMMUNITY\n    \"\"\" Prototype, not officially supported yet  \"\"\"\n    INCUBATING\n    \"\"\" Project being retired, in maintenance mode \"\"\"\n    ATTIC\n    \"\"\" End-Of-Lifed \"\"\"\n    EOL\n}"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/features/developingautoconfiguration/testing/MyServiceAutoConfigurationTestsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.developingautoconfiguration.testing;\n\n/**\n * Tests for {@link MyServiceAutoConfigurationTests}.\n *\n * @author Stephane Nicoll\n */\nclass MyServiceAutoConfigurationTestsTests extends MyServiceAutoConfigurationTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/durations/constructorbinding/MyPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.durations.constructorbinding;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MyProperties}.\n *\n * @author Stephane Nicoll\n */\nclass MyPropertiesTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(Config.class);\n\n\t@Test\n\tvoid bindWithDefaultUnit() {\n\t\tthis.contextRunner.withPropertyValues(\"my.session-timeout=40\", \"my.read-timeout=5000\")\n\t\t\t.run(assertBinding((properties) -> {\n\t\t\t\tassertThat(properties.getSessionTimeout()).hasSeconds(40);\n\t\t\t\tassertThat(properties.getReadTimeout()).hasMillis(5000);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid bindWithExplicitUnit() {\n\t\tthis.contextRunner.withPropertyValues(\"my.session-timeout=1h\", \"my.read-timeout=5s\")\n\t\t\t.run(assertBinding((properties) -> {\n\t\t\t\tassertThat(properties.getSessionTimeout()).hasMinutes(60);\n\t\t\t\tassertThat(properties.getReadTimeout()).hasMillis(5000);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid bindWithIso8601Format() {\n\t\tthis.contextRunner.withPropertyValues(\"my.session-timeout=PT15S\", \"my.read-timeout=PT0.5S\")\n\t\t\t.run(assertBinding((properties) -> {\n\t\t\t\tassertThat(properties.getSessionTimeout()).hasSeconds(15);\n\t\t\t\tassertThat(properties.getReadTimeout()).hasMillis(500);\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertBinding(Consumer<MyProperties> properties) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(MyProperties.class);\n\t\t\tproperties.accept(context.getBean(MyProperties.class));\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(MyProperties.class)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/features/externalconfig/typesafeconfigurationproperties/conversion/durations/javabeanbinding/MyPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.externalconfig.typesafeconfigurationproperties.conversion.durations.javabeanbinding;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MyProperties}.\n *\n * @author Stephane Nicoll\n */\nclass MyPropertiesTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(Config.class);\n\n\t@Test\n\tvoid bindWithDefaultUnit() {\n\t\tthis.contextRunner.withPropertyValues(\"my.session-timeout=40\", \"my.read-timeout=5000\")\n\t\t\t.run(assertBinding((properties) -> {\n\t\t\t\tassertThat(properties.getSessionTimeout()).hasSeconds(40);\n\t\t\t\tassertThat(properties.getReadTimeout()).hasMillis(5000);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid bindWithExplicitUnit() {\n\t\tthis.contextRunner.withPropertyValues(\"my.session-timeout=1h\", \"my.read-timeout=5s\")\n\t\t\t.run(assertBinding((properties) -> {\n\t\t\t\tassertThat(properties.getSessionTimeout()).hasMinutes(60);\n\t\t\t\tassertThat(properties.getReadTimeout()).hasMillis(5000);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid bindWithIso8601Format() {\n\t\tthis.contextRunner.withPropertyValues(\"my.session-timeout=PT15S\", \"my.read-timeout=PT0.5S\")\n\t\t\t.run(assertBinding((properties) -> {\n\t\t\t\tassertThat(properties.getSessionTimeout()).hasSeconds(15);\n\t\t\t\tassertThat(properties.getReadTimeout()).hasMillis(500);\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertBinding(Consumer<MyProperties> properties) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(MyProperties.class);\n\t\t\tproperties.accept(context.getBean(MyProperties.class));\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(MyProperties.class)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/features/springapplication/fluentbuilderapi/MyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.features.springapplication.fluentbuilderapi;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MyApplication}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass MyApplicationTests {\n\n\t@Test\n\tvoid contextHierarchyWithDisabledBanner(CapturedOutput output) {\n\t\tSystem.setProperty(\"spring.main.web-application-type\", \"none\");\n\t\ttry {\n\t\t\tnew MyApplication().hierarchyWithDisabledBanner(new String[0]);\n\t\t\tassertThat(output).doesNotContain(\":: Spring Boot ::\");\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"spring.main.web-application-type\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/actuator/maphealthindicatorstometrics/MetricsHealthMicrometerExportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.actuator.maphealthindicatorstometrics;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MetricsHealthMicrometerExport}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\nclass MetricsHealthMicrometerExportTests {\n\n\t@Autowired\n\tprivate MeterRegistry registry;\n\n\t@Test\n\tvoid registryExportsHealth() {\n\t\tGauge gauge = this.registry.get(\"health\").gauge();\n\t\tassertThat(gauge.value()).isEqualTo(2);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(MyHealthMetricsExportConfiguration.class)\n\t@ImportAutoConfiguration({ HealthContributorAutoConfiguration.class,\n\t\t\tHealthContributorRegistryAutoConfiguration.class, MetricsAutoConfiguration.class,\n\t\t\tHealthEndpointAutoConfiguration.class })\n\tstatic class Config {\n\n\t\t@Bean\n\t\tMetricsHealthMicrometerExport example() {\n\t\t\treturn new MetricsHealthMicrometerExport();\n\t\t}\n\n\t\t@Bean\n\t\tSimpleMeterRegistry simpleMeterRegistry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator outOfService() {\n\t\t\treturn () -> Health.outOfService().build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/application/customizetheenvironmentorapplicationcontext/MyEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.application.customizetheenvironmentorapplicationcontext;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MyEnvironmentPostProcessor}.\n *\n * @author Stephane Nicoll\n */\nclass MyEnvironmentPostProcessorTests {\n\n\tprivate final StandardEnvironment environment = new StandardEnvironment();\n\n\t@Test\n\tvoid applyEnvironmentPostProcessor() {\n\t\tassertThat(this.environment.containsProperty(\"test.foo.bar\")).isFalse();\n\t\tnew MyEnvironmentPostProcessor().postProcessEnvironment(this.environment, new SpringApplication());\n\t\tassertThat(this.environment.containsProperty(\"test.foo.bar\")).isTrue();\n\t\tassertThat(this.environment.getProperty(\"test.foo.bar\")).isEqualTo(\"value\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/dataaccess/SampleApp.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\n\n/**\n * A sample {@link SpringBootConfiguration @ConfigurationProperties} that only enables the\n * auto-configuration for the {@link DataSource}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootConfiguration\n@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\nclass SampleApp {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/builder/MyDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.builder;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link MyDataSourceConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(properties = \"app.datasource.jdbcUrl=jdbc:h2:mem:basic;DB_CLOSE_DELAY=-1\")\n@Import(MyDataSourceConfiguration.class)\nclass MyDataSourceConfigurationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid validateConfiguration() throws SQLException {\n\t\tassertThat(this.context.getBeansOfType(DataSource.class)).hasSize(1);\n\t\tDataSource dataSource = this.context.getBean(DataSource.class);\n\t\tassertThat(dataSource.getConnection().getMetaData().getURL()).isEqualTo(\"jdbc:h2:mem:basic\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/builder/configurable/MyDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.builder.configurable;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.configurable.MyDataSourceConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link MyDataSourceConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(properties = { \"app.datasource.url=jdbc:h2:mem:configurable;DB_CLOSE_DELAY=-1\",\n\t\t\"app.datasource.configuration.maximum-pool-size=42\" })\n@Import(MyDataSourceConfiguration.class)\nclass MyDataSourceConfigurationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid validateConfiguration() throws SQLException {\n\t\tassertThat(this.context.getBeansOfType(DataSource.class)).hasSize(1);\n\t\tHikariDataSource dataSource = this.context.getBean(HikariDataSource.class);\n\t\tassertThat(dataSource.getConnection().getMetaData().getURL()).isEqualTo(\"jdbc:h2:mem:configurable\");\n\t\tassertThat(dataSource.getMaximumPoolSize()).isEqualTo(42);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/dataaccess/configurecustomdatasource/builder/simple/MyDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.builder.simple;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.docs.howto.dataaccess.configurecustomdatasource.simple.MyDataSourceConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link MyDataSourceConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(properties = { \"app.datasource.jdbc-url=jdbc:h2:mem:simple;DB_CLOSE_DELAY=-1\",\n\t\t\"app.datasource.maximum-pool-size=42\" })\n@Import(MyDataSourceConfiguration.class)\nclass MyDataSourceConfigurationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid validateConfiguration() throws SQLException {\n\t\tassertThat(this.context.getBeansOfType(DataSource.class)).hasSize(1);\n\t\tHikariDataSource dataSource = this.context.getBean(HikariDataSource.class);\n\t\tassertThat(dataSource.getConnection().getMetaData().getURL()).isEqualTo(\"jdbc:h2:mem:simple\");\n\t\tassertThat(dataSource.getMaximumPoolSize()).isEqualTo(42);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/dataaccess/configuretwodatasources/MyCompleteDataSourcesConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configuretwodatasources;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MyCompleteAdditionalDataSourceConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@Import(MyCompleteAdditionalDataSourceConfiguration.class)\nclass MyCompleteDataSourcesConfigurationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n\t@Qualifier(\"second\")\n\tprivate DataSource secondDataSource;\n\n\t@Test\n\tvoid validateConfiguration() throws SQLException {\n\t\tassertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2);\n\t\tassertThat(this.context.getBean(\"dataSource\")).isSameAs(this.dataSource);\n\t\tassertThat(this.dataSource.getConnection().getMetaData().getURL()).startsWith(\"jdbc:h2:mem:\");\n\t\tassertThat(this.context.getBean(\"secondDataSource\")).isSameAs(this.secondDataSource);\n\t\tassertThat(this.secondDataSource.getConnection().getMetaData().getURL()).startsWith(\"jdbc:h2:mem:\");\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/howto/dataaccess/configuretwodatasources/MyDataSourcesConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.howto.dataaccess.configuretwodatasources;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MyAdditionalDataSourceConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(properties = { \"app.datasource.jdbc-url=jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1\",\n\t\t\"app.datasource.maximum-pool-size=42\" })\n@Import(MyAdditionalDataSourceConfiguration.class)\nclass MyDataSourcesConfigurationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n\t@Qualifier(\"second\")\n\tprivate DataSource secondDataSource;\n\n\t@Test\n\tvoid validateConfiguration() throws SQLException {\n\t\tassertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2);\n\t\tassertThat(this.context.getBean(\"dataSource\")).isSameAs(this.dataSource);\n\t\tassertThat(this.dataSource.getConnection().getMetaData().getURL()).startsWith(\"jdbc:h2:mem:\");\n\t\tassertThat(this.context.getBean(\"secondDataSource\")).isSameAs(this.secondDataSource);\n\t\tassertThat(this.secondDataSource).extracting((dataSource) -> ((HikariDataSource) dataSource).getJdbcUrl())\n\t\t\t.isEqualTo(\"jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1\");\n\t\tassertThat(this.secondDataSource)\n\t\t\t.extracting((dataSource) -> ((HikariDataSource) dataSource).getMaximumPoolSize())\n\t\t\t.isEqualTo(42);\n\t}\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/testing/springbootapplications/jmx/MyJmxTestsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.springbootapplications.jmx;\n\n/**\n * Tests for SampleJmxTests\n *\n * @author Stephane Nicoll\n */\nclass MyJmxTestsTests extends MyJmxTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/testing/utilities/outputcapture/MyOutputCaptureTestsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.outputcapture;\n\n/**\n * Tests for {@link MyOutputCaptureTests}.\n *\n * @author Stephane Nicoll\n */\nclass MyOutputCaptureTestsTests extends MyOutputCaptureTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/java/org/springframework/boot/docs/testing/utilities/testresttemplate/MySpringBootTestsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.docs.testing.utilities.testresttemplate;\n\n/**\n * Tests for {@link MySpringBootTests}.\n *\n * @author Stephane Nicoll\n */\nclass MySpringBootTestsTests extends MySpringBootTests {\n\n}\n"
  },
  {
    "path": "documentation/spring-boot-docs/src/test/resources/com/example/myapp/config.yml",
    "content": "test:\n  foo:\n    bar: value\n"
  },
  {
    "path": "eclipse/eclipse.properties",
    "content": "copyright-year=2012-present\n"
  },
  {
    "path": "eclipse/spring-boot-project.setup",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<setup:Project\n    xmi:version=\"2.0\"\n    xmlns:xmi=\"http://www.omg.org/XMI\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:jdt=\"http://www.eclipse.org/oomph/setup/jdt/1.0\"\n    xmlns:oomph=\"http://www.eclipse.org/buildship/oomph/1.0\"\n    xmlns:predicates=\"http://www.eclipse.org/oomph/predicates/1.0\"\n    xmlns:setup=\"http://www.eclipse.org/oomph/setup/1.0\"\n    xmlns:setup.p2=\"http://www.eclipse.org/oomph/setup/p2/1.0\"\n    xmlns:setup.workingsets=\"http://www.eclipse.org/oomph/setup/workingsets/1.0\"\n    xsi:schemaLocation=\"http://www.eclipse.org/oomph/setup/jdt/1.0 https://raw.githubusercontent.com/eclipse-oomph/oomph/master/setups/models/JDT.ecore http://www.eclipse.org/buildship/oomph/1.0 https://raw.githubusercontent.com/eclipse/buildship/master/org.eclipse.buildship.oomph/model/GradleImport-1.0.ecore http://www.eclipse.org/oomph/predicates/1.0 https://raw.githubusercontent.com/eclipse-oomph/oomph/master/setups/models/Predicates.ecore http://www.eclipse.org/oomph/setup/workingsets/1.0 https://raw.githubusercontent.com/eclipse-oomph/oomph/master/setups/models/SetupWorkingSets.ecore\"\n    name=\"spring.boot.4.1.x\"\n    label=\"Spring Boot 4.1.x\">\n  <setupTask\n      xsi:type=\"setup:VariableTask\"\n      type=\"FOLDER\"\n      name=\"checkout.location\"\n      defaultValue=\"\"\n      storageURI=\"scope://Workspace\"\n      label=\"Checkout Location\"/>\n  <setupTask\n      xsi:type=\"jdt:JRETask\"\n      version=\"JavaSE-24\"\n      location=\"${jre.location-24}\">\n    <description>\n      Define the JRE needed to compile and run the Java\n      projects of ${scope.project.label}\n    </description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:EclipseIniTask\"\n      option=\"-Xmx\"\n      value=\"2048m\"\n      vm=\"true\">\n    <description></description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:EclipseIniTask\"\n      option=\"-Xms\"\n      value=\"512m\"\n      vm=\"true\"/>\n  <setupTask\n      xsi:type=\"setup:ResourceCreationTask\"\n      excludedTriggers=\"STARTUP MANUAL\"\n      targetURL=\"${workspace.location|uri}/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml\"\n      encoding=\"UTF-8\">\n    <description>\n      Initialize JDT's package explorer to show working sets as\n      its root objects\n    </description>\n    <content>\n      &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>\n      &lt;section name=&quot;Workbench&quot;>\n      \t&lt;section name=&quot;org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart&quot;>\n      \t\t&lt;item value=&quot;true&quot; key=&quot;group_libraries&quot;/>\n      \t\t&lt;item value=&quot;false&quot; key=&quot;linkWithEditor&quot;/>\n      \t\t&lt;item value=&quot;2&quot; key=&quot;layout&quot;/>\n      \t\t&lt;item value=&quot;2&quot; key=&quot;rootMode&quot;/>\n      \t\t&lt;item value=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;packageExplorer configured=&amp;quot;true&amp;quot; group_libraries=&amp;quot;1&amp;quot; layout=&amp;quot;2&amp;quot; linkWithEditor=&amp;quot;0&amp;quot; rootMode=&amp;quot;2&amp;quot; sortWorkingSets=&amp;quot;false&amp;quot; workingSetName=&amp;quot;&amp;quot;&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;localWorkingSetManager&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;workingSet editPageId=&amp;quot;org.eclipse.jdt.internal.ui.OthersWorkingSet&amp;quot; factoryID=&amp;quot;org.eclipse.ui.internal.WorkingSetFactory&amp;quot; id=&amp;quot;1382792884467_1&amp;quot; label=&amp;quot;Other Projects&amp;quot; name=&amp;quot;Other Projects&amp;quot;/&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;/localWorkingSetManager&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;activeWorkingSet workingSetName=&amp;quot;Other Projects&amp;quot;/&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;allWorkingSets workingSetName=&amp;quot;Other Projects&amp;quot;/&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;/packageExplorer&amp;gt;&quot; key=&quot;memento&quot;/>\n      \t&lt;/section>\n      &lt;/section>\n\n    </content>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup.p2:P2Task\">\n    <requirement\n        name=\"org.eclipse.platform.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.jdt.feature.group\"/>\n    <requirement\n        name=\"io.spring.javaformat.eclipse.feature.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.m2e.feature.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.oomph.setup.maven.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.oomph.setup.workingsets.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.wst.server_adapters.feature.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.wst.web_ui.feature.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.buildship.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.buildship.oomph.feature.group\"/>\n    <repository\n        url=\"https://repo.spring.io/javaformat-eclipse-update-site/\"/>\n    <repository\n        url=\"https://repo.maven.apache.org/maven2/.m2e/connectors/m2eclipse-buildhelper/0.15.0/N/0.15.0.201405280027/\"/>\n    <repository\n        url=\"https://download.eclipse.org/buildship/updates/e49/releases/\"/>\n    <description>\n      Install the tools needed in the IDE to work with the\n      source code for ${scope.project.label}\n    </description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"oomph:GradleImportTask\"\n      javaHome=\"${jre.location-17}\">\n    <sourceLocator\n        rootFolder=\"${checkout.location}\"\n        locateNestedProjects=\"true\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"oomph:GradleImportTask\"\n      javaHome=\"${jre.location-17}\">\n    <sourceLocator\n        rootFolder=\"${checkout.location}/buildSrc\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup.workingsets:WorkingSetTask\">\n    <workingSet\n        name=\"platform\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/platform(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"core\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/core(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"module\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/module(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"loader\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/loader(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"configuration-metadata\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/configuration-metadata(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"buildpack\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/buildpack(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"build-plugin\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/build-plugin(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"cli\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/cli(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"test-support\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/test-support(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"integration-test\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/integration-test(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"smoke-test\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/smoke-test(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"system-test\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/system-test(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"starter\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/starter(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"documentation\">\n      <predicate\n          xsi:type=\"predicates:LocationPredicate\"\n          pattern=\".*/documentation(/.*)?\"/>\n    </workingSet>\n    <workingSet\n        name=\"build\">\n      <predicate\n          xsi:type=\"predicates:OrPredicate\">\n        <operand\n            xsi:type=\"predicates:NamePredicate\"\n            pattern=\"spring-boot-build\"/>\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*/buildSrc\"/>\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*/gradle(/.*)?\"/>\n      </predicate>\n    </workingSet>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.jdt.ui\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/content_assist_autoactivation_delay\"\n        value=\"40\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/content_assist_disabled_computers\"\n        value=\"org.eclipse.jdt.ui.javaNoTypeProposalCategory$${0x0}org.eclipse.jdt.ui.javaTypeProposalCategory$${0x0}org.eclipse.jdt.ui.textProposalCategory$${0x0}org.eclipse.recommenders.calls.rcp.proposalCategory.templates$${0x0}\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.typefilter.enabled\"\n        value=\"java.awt.*;org.hibernate.collection.*;\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/escape¥Strings\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/content_assist_favorite_static_members\"\n        value=\"org.assertj.core.api.Assertions.*;org.hamcrest.Matchers.*;org.junit.Assert.*;org.mockito.BDDMockito.*;org.mockito.Matchers.*;org.mockito.Mockito.*;org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;org.springframework.test.web.servlet.result.MockMvcResultMatchers.*\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/smart_backspace\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/smart_opening_brace\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/smart_semicolon\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/smart_tab\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/smartIndentAfterNewline\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/smartPaste\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.text.custom_templates\"\n        value=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?>&lt;templates>&lt;template autoinsert=&quot;false&quot; context=&quot;java&quot; deleted=&quot;false&quot; description=&quot;Surround code with formatter off and formatter on tags&quot; enabled=&quot;true&quot; name=&quot;noformat&quot;>// @formatter:off&#xA;$${cursor} $${line_selection}&#xA;// @formatter:on&lt;/template>&lt;/templates>\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.jdt.core\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral\"\n        value=\"ignore\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.core.resources\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.core.resources/encoding\"\n        value=\"UTF-8\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.core.resources/refresh.enabled\"\n        value=\"false\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.m2e.core\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.m2e.core/eclipse.m2.hideFoldersOfNestedProjects\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.m2e.core/eclipse.m2.updateIndexes\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.m2e.core/eclipse.m2.defaultPomEditorPage\"\n        value=\"true\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.ui.editors\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.editors/printMarginColumn\"\n        value=\"120\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.editors/lineNumberRuler\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.editors/printMargin\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.editors/showWhitespaceCharacters\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.editors/whitespaceCharacterAlphaValue\"\n        value=\"20\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.springframework.ide.eclipse.beans.core\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.beans.core/org.springframework.ide.eclipse.beans.core.BeansCorePlugin.DISABLE_AUTO_DETECTION\"\n        value=\"true\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.wst.xml.core\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.wst.xml.core/indicateNoGrammar\"\n        value=\"-1\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.springframework.ide.eclipse.core\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.builders.enable.beanmetadatabuilder\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.useChangeDetectionForJavaFiles\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.boot.bootvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinition-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinitionHolder-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanFactory-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanInitDestroyMethod-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanProperty-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanReference-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator\"\n        value=\"false\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.springframework.ide.eclipse.core/org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.boot.missingConfigurationProcessor-org.springframework.ide.eclipse.boot.bootvalidator\"\n        value=\"false\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"org.eclipse.ui.workbench\">\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.workbench/HeapStatus.showMax\"\n        value=\"true\"/>\n    <setupTask\n        xsi:type=\"setup:PreferenceTask\"\n        key=\"/instance/org.eclipse.ui.workbench/RUN_IN_BACKGROUND\"\n        value=\"true\"/>\n  </setupTask>\n  <stream name=\"default\"\n      label=\"Default\"/>\n  <logicalProjectContainer\n      xsi:type=\"setup:ProjectCatalog\"\n      href=\"index:/org.eclipse.setup#//@projectCatalogs[name='com.github']\"/>\n  <description>\n    Eclipse project setup for people wishing to contribute to\n    Spring Boot.\n  </description>\n</setup:Project>\n"
  },
  {
    "path": "git/hooks/forward-merge",
    "content": "#!/usr/bin/ruby\nrequire 'json'\nrequire 'net/http'\nrequire 'yaml'\nrequire 'logger'\n\n$log = Logger.new(STDOUT)\n$log.level = Logger::WARN\n\nclass ForwardMerge\n  attr_reader :issue, :milestone, :message, :line\n  def initialize(issue, milestone, message, line)\n    @issue = issue\n    @milestone = milestone\n    @message = message\n    @line = line\n  end\nend\n\ndef find_forward_merges(message_file)\n\n  $log.debug \"Searching for forward merge\"\n  branch=`git rev-parse -q --abbrev-ref HEAD`.strip\n  $log.debug \"Found #{branch} from git rev-parse --abbrev-ref\"\n  if( branch == \"docs-build\") then\n    $log.debug \"Skipping docs build\"\n    return nil\n  end\n  rev=`git rev-parse -q --verify MERGE_HEAD`.strip\n  $log.debug \"Found #{rev} from git rev-parse\"\n  return nil unless rev\n  message = File.read(message_file)\n  forward_merges = []\n  message.each_line do |line|\n    $log.debug \"Checking #{line} for message\"\n    match = /^(?:Fixes|Closes) gh-(\\d+) in (\\d\\.\\d\\.[\\dx](?:[\\.\\-](?:M|RC)\\d)?)$/.match(line)\n    if match then\n      issue = match[1]\n      milestone = match[2]\n      $log.debug \"Matched reference to issue #{issue} in milestone #{milestone}\"\n      forward_merges << ForwardMerge.new(issue, milestone, message, line)\n    end\n  end\n  $log.debug \"No match in merge message\" unless forward_merges\n  return forward_merges\nend\n\ndef get_issue(username, password, repository, number)\n  $log.debug \"Getting issue #{number} from GitHub repository #{repository}\"\n  uri = URI(\"https://api.github.com/repos/#{repository}/issues/#{number}\")\n  http = Net::HTTP.new(uri.host, uri.port)\n  http.use_ssl=true\n  request = Net::HTTP::Get.new(uri.path)\n  request.basic_auth(username, password)\n  response = http.request(request)\n  $log.debug \"Get HTTP response #{response.code}\"\n  return JSON.parse(response.body) unless response.code != '200'\n  puts \"Failed to retrieve issue #{number}: #{response.message}\"\n  exit 1\nend\n\ndef find_milestone(username, password, repository, title)\n  $log.debug \"Finding milestone #{title} from GitHub repository #{repository}\"\n  uri = URI(\"https://api.github.com/repos/#{repository}/milestones\")\n  http = Net::HTTP.new(uri.host, uri.port)\n  http.use_ssl=true\n  request = Net::HTTP::Get.new(uri.path)\n  request.basic_auth(username, password)\n  response = http.request(request)\n  milestones = JSON.parse(response.body)\n  if title.end_with?(\".x\")\n    prefix = title.delete_suffix('.x')\n    $log.debug \"Finding nearest milestone from candidates starting with #{prefix}\"\n    titles = milestones.map { |milestone| milestone['title'] }\n    titles = titles.select{ |title| title.start_with?(prefix) unless title.end_with?('.x') || (title.count('.') > 2)}\n    titles = titles.sort_by { |v| Gem::Version.new(v) }\n    $log.debug \"Considering candidates #{titles}\"\n    if(titles.empty?)\n      puts \"Cannot find nearest milestone for prefix #{title}\"\n      exit 1\n    end\n    title = titles.first\n    $log.debug \"Found nearest milestone #{title}\"\n  end\n  milestones.each do |milestone|\n    $log.debug \"Considering #{milestone['title']}\"\n    return milestone['number'] if milestone['title'] == title\n  end\n  puts \"Milestone #{title} not found\"\n  exit 1\nend\n\ndef create_issue(username, password, repository, original, title, labels, milestone, milestone_name, dry_run)\n  $log.debug \"Finding forward-merge issue in GitHub repository #{repository} for '#{title}'\"\n  uri = URI(\"https://api.github.com/repos/#{repository}/issues\")\n  http = Net::HTTP.new(uri.host, uri.port)\n  http.use_ssl=true\n  request = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')\n  request.basic_auth(username, password)\n  request.body = {\n    title: title,\n    labels: labels,\n    milestone: milestone.to_i,\n    body: \"Forward port of issue ##{original} to #{milestone_name}.\"\n  }.to_json\n  if dry_run then\n    puts \"Dry run\"\n    puts \"POSTing to #{uri} with body #{request.body}\"\n    return \"dry-run\"\n  end\n  response = JSON.parse(http.request(request).body)\n  $log.debug \"Created new issue #{response['number']}\"\n  return response['number']\nend\n\n$log.debug \"Running forward-merge hook script\"\nmessage_file=ARGV[0]\n\nforward_merges = find_forward_merges(message_file)\nexit 0 unless forward_merges\n\n$log.debug \"Loading config from ~/.spring-boot/forward-merge.yml\"\nconfig = YAML.load_file(File.join(Dir.home, '.spring-boot', 'forward-merge.yml'))\nusername = config['github']['credentials']['username']\npassword = config['github']['credentials']['password']\ndry_run = config['dry_run']\n\ngradleProperties = IO.read('gradle.properties')\nspringBuildType = gradleProperties.match(/^spring\\.build-type\\s?=\\s?(.*)$/)\nrepository = (springBuildType && springBuildType[1] != 'oss') ? \"spring-projects/spring-boot-#{springBuildType[1]}\" : \"spring-projects/spring-boot\";\n$log.debug \"Targeting repository #{repository}\"\n\nforward_merges.each do |forward_merge|\n  existing_issue = get_issue(username, password, repository, forward_merge.issue)\n  title = existing_issue['title']\n  labels = existing_issue['labels'].map { |label| label['name'] }\n  labels << \"status: forward-port\"\n  $log.debug \"Processing issue '#{title}'\"\n\n  milestone = find_milestone(username, password, repository, forward_merge.milestone)\n  new_issue_number = create_issue(username, password, repository, forward_merge.issue, title, labels, milestone, forward_merge.milestone, dry_run)\n\n  puts \"Created gh-#{new_issue_number} for forward port of gh-#{forward_merge.issue} into #{forward_merge.milestone}\"\n  rewritten_message = forward_merge.message.sub(forward_merge.line, \"Closes gh-#{new_issue_number}\\n\")\n  File.write(message_file, rewritten_message)\nend\n"
  },
  {
    "path": "git/hooks/prepare-forward-merge",
    "content": "#!/usr/bin/ruby\nrequire 'json'\nrequire 'net/http'\nrequire 'yaml'\nrequire 'logger'\n\n$main_branch = \"4.1.x\"\n\n$log = Logger.new(STDOUT)\n$log.level = Logger::WARN\n\ndef get_fixed_issues()\n  $log.debug \"Searching for forward merge\"\n  rev=`git rev-parse -q --verify MERGE_HEAD`.strip\n  $log.debug \"Found #{rev} from git rev-parse\"\n  return nil unless rev\n  fixed = []\n  message = `git log -1 --pretty=%B #{rev}`\n  message.each_line do |line|\n    $log.debug \"Checking #{line} for message\"\n    fixed << line.strip if /^(?:Fixes|Closes) gh-(\\d+)/.match(line)\n  end\n  $log.debug \"Found fixed issues #{fixed}\"\n  return fixed;\nend\n\ndef rewrite_message(message_file, fixed)\n  current_branch = `git rev-parse --abbrev-ref HEAD`.strip\n  if current_branch == \"main\"\n    current_branch = $main_branch\n  end\n  rewritten_message = \"\"\n  message = File.read(message_file)\n  message.each_line do |line|\n    match = /^Merge.*branch\\ '(.*)'(?:\\ into\\ (.*))?$/.match(line)\n    if match\n      from_branch = match[1]\n      if from_branch.include? \"/\"\n        from_branch = from_branch.partition(\"/\").last\n      end\n      to_branch = match[2]\n      $log.debug \"Rewriting merge message\"\n      line = \"Merge branch '#{from_branch}'\" + (to_branch ? \" into #{to_branch}\\n\" : \"\\n\")\n    end\n    if fixed and line.start_with?(\"#\")\n      $log.debug \"Adding fixed\"\n      rewritten_message << \"\\n\"\n      fixed.each do |fixes|\n        rewritten_message << \"#{fixes} in #{current_branch}\\n\"\n      end\n      fixed = nil\n    end\n    rewritten_message << line\n  end\n  return rewritten_message\nend\n\n$log.debug \"Running prepare-forward-merge hook script\"\n\nmessage_file=ARGV[0]\nmessage_type=ARGV[1]\n\nif message_type != \"merge\"\n  $log.debug \"Not a merge commit\"\n  exit 0;\nend\n\n$log.debug \"Searching for forward merge\"\nfixed = get_fixed_issues()\nrewritten_message = rewrite_message(message_file, fixed)\nFile.write(message_file, rewritten_message)\n"
  },
  {
    "path": "gradle/plugins/config/checkstyle/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n\t\t\"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\"\n\t\t\"https://checkstyle.org/dtds/configuration_1_3.dtd\">\n<module name=\"com.puppycrawl.tools.checkstyle.Checker\">\n\t<module name=\"io.spring.javaformat.checkstyle.SpringChecks\">\n\t\t<property name=\"excludes\" value=\"com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck\" />\n\t</module>\n</module>"
  },
  {
    "path": "gradle/plugins/cycle-detection-plugin/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nplugins {\n\tid 'java-gradle-plugin'\n\tid \"checkstyle\"\n\tid \"io.spring.javaformat\" version \"$javaFormatVersion\"\n\n}\n\nrepositories {\n\tmavenCentral()\n}\n\ncheckstyle {\n\ttoolVersion = \"${checkstyleToolVersion}\"\n}\n\ndependencies {\n\tcheckstyle(\"com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}\")\n\tcheckstyle(\"io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}\")\n\n\timplementation(\"org.jgrapht:jgrapht-core:1.5.2\")\n}\n\ngradlePlugin {\n\tplugins {\n\t\tcycleDetectionPlugin {\n\t\t\tid = \"org.springframework.boot.cycle-detection\"\n\t\t\timplementationClass = \"org.springframework.boot.build.cycledetection.CycleDetectionPlugin\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "gradle/plugins/cycle-detection-plugin/src/main/java/org/springframework/boot/build/cycledetection/CycleDetectionPlugin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.build.cycledetection;\n\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.gradle.api.GradleException;\nimport org.gradle.api.Plugin;\nimport org.gradle.api.Project;\nimport org.gradle.api.Task;\nimport org.gradle.api.execution.TaskExecutionGraph;\nimport org.gradle.api.initialization.Settings;\nimport org.jgrapht.Graph;\nimport org.jgrapht.alg.cycle.TarjanSimpleCycles;\nimport org.jgrapht.graph.DefaultDirectedGraph;\nimport org.jgrapht.graph.DefaultEdge;\n\n/**\n * A {@link Settings} {@link Plugin plugin} to detect cycles between a build's projects.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\npublic class CycleDetectionPlugin implements Plugin<Settings> {\n\n\tprivate static final Pattern layerPattern = Pattern.compile(\"^:(.+?):.*\");\n\n\t@Override\n\tpublic void apply(Settings settings) {\n\t\tsettings.getGradle().getTaskGraph().whenReady(this::detectCycles);\n\t}\n\n\tprivate void detectCycles(TaskExecutionGraph taskGraph) {\n\t\tMap<Project, Set<Project>> dependenciesByProject = getProjectsAndDependencies(taskGraph);\n\t\tassertNoCycles(createGraph(dependenciesByProject, Project::getPath), \"Project cycles detected:\\n\");\n\t\tassertNoCycles(createGraph(dependenciesByProject, this::getLayer), \"Layer cycles detected:\\n\");\n\t}\n\n\tprivate Map<Project, Set<Project>> getProjectsAndDependencies(TaskExecutionGraph taskGraph) {\n\t\tMap<Project, Set<Project>> dependenciesByProject = new HashMap<>();\n\t\tfor (Task task : taskGraph.getAllTasks()) {\n\t\t\tProject project = task.getProject();\n\t\t\tSet<Project> dependencies = dependenciesByProject.computeIfAbsent(project, (key) -> new LinkedHashSet<>());\n\t\t\ttaskGraph.getDependencies(task)\n\t\t\t\t.stream()\n\t\t\t\t.map(Task::getProject)\n\t\t\t\t.filter((taskProject) -> !taskProject.equals(project))\n\t\t\t\t.forEach(dependencies::add);\n\t\t}\n\t\treturn dependenciesByProject;\n\t}\n\n\tprivate Graph<String, DefaultEdge> createGraph(Map<Project, Set<Project>> dependenciesByProject,\n\t\t\tFunction<Project, String> vertexExtractor) {\n\t\tGraph<String, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);\n\t\tdependenciesByProject.keySet().stream().map(vertexExtractor).filter(Objects::nonNull).forEach(graph::addVertex);\n\t\tdependenciesByProject.forEach((project, dependencies) -> {\n\t\t\tString source = vertexExtractor.apply(project);\n\t\t\tdependencies.stream().map(vertexExtractor).filter(Objects::nonNull).forEach((target) -> {\n\t\t\t\tif (source != null && !Objects.equals(source, target)) {\n\t\t\t\t\tgraph.addEdge(source, target);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\treturn graph;\n\t}\n\n\tprivate String getLayer(Project project1) {\n\t\tMatcher matcher = layerPattern.matcher(project1.getPath());\n\t\treturn (matcher.matches()) ? matcher.group(1) : null;\n\t}\n\n\tprivate void assertNoCycles(Graph<String, DefaultEdge> projects, String str) {\n\t\tList<List<String>> cycles = new TarjanSimpleCycles<>(projects).findSimpleCycles();\n\t\tif (!cycles.isEmpty()) {\n\t\t\tStringBuilder message = new StringBuilder(str);\n\t\t\tfor (List<String> cycle : cycles) {\n\t\t\t\tcycle.add(cycle.get(0));\n\t\t\t\tmessage.append(\"  \" + String.join(\" -> \", cycle) + \"\\n\");\n\t\t\t}\n\t\t\tthrow new GradleException(message.toString());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "gradle/plugins/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\npluginManagement {\n\tnew File(rootDir.parentFile.parentFile, \"gradle.properties\").withInputStream {\n\t\tdef properties = new Properties()\n\t\tproperties.load(it)\n\t\tproperties.forEach(settings.ext::set)\n\t\tgradle.rootProject {\n\t\t\tproperties.forEach(project.ext::set)\n\t\t}\n\t}\n}\n\ninclude 'cycle-detection-plugin'\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-9.4.1-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "version=4.1.0-SNAPSHOT\nlatestVersion=true\nspring.build-type=oss\n\norg.gradle.caching=true\norg.gradle.parallel=true\norg.gradle.jvmargs=-Xmx3g -Dfile.encoding=UTF-8\n\nassertjVersion=3.27.7\ncheckstyleToolVersion=10.12.4\ncommonsCodecVersion=1.21.0\ngraalVersion=25\nhamcrestVersion=3.0\njackson2Version=2.21.2\njacksonVersion=3.1.0\njavaFormatVersion=0.0.47\njunitJupiterVersion=6.0.3\nkotlinVersion=2.3.20\nmavenVersion=3.9.13\nmockitoVersion=5.23.0\nnativeBuildToolsVersion=0.11.5\nnullabilityPluginVersion=0.0.11\nsnakeYamlVersion=2.6\nspringFrameworkVersion=7.0.6\nspringFramework60xVersion=6.0.23\ntomcatVersion=11.0.20\nprotobufGradlePluginVersion=0.9.6\n\nkotlin.stdlib.default.dependency=false\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -jar \"$APP_HOME/gradle/wrapper/gradle-wrapper.jar\" \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -jar \"%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\" %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nplugins {\n\tid \"java-library\"\n}\n\ndescription = \"Spring Boot Actuator Integration Tests\"\n\n\ndependencies {\n\ttestImplementation(project(\":module:spring-boot-actuator\"))\n\ttestImplementation(project(\":module:spring-boot-actuator-autoconfigure\"))\n\ttestImplementation(project(\":core:spring-boot-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-health\"))\n\ttestImplementation(project(\":module:spring-boot-http-converter\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-jersey\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-metrics\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-web-server\"))\n\ttestImplementation(project(\":module:spring-boot-webflux\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-jersey\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webflux\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webmvc\")))\n\ttestImplementation(\"io.micrometer:micrometer-registry-prometheus\")\n\ttestImplementation(\"io.prometheus:prometheus-metrics-exposition-formats\")\n\ttestImplementation(\"net.minidev:json-smart\")\n\ttestImplementation(\"org.springframework.security:spring-security-web\")\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\") // Required for Jersey\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": ""
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/audit/AuditEventsEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.time.Instant;\nimport java.util.Collections;\n\nimport net.minidev.json.JSONArray;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link AuditEventsEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Vedran Pavic\n * @author Andy Wilkinson\n */\nclass AuditEventsEndpointWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid allEvents(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/auditevents\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"events.[*].principal\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"admin\").appendElement(\"admin\").appendElement(\"user\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid eventsAfter(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/auditevents\")\n\t\t\t\t.queryParam(\"after\", \"2016-11-01T13:00:00%2B00:00\")\n\t\t\t\t.build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"events\")\n\t\t\t.isEmpty();\n\t}\n\n\t@WebEndpointTest\n\tvoid eventsWithPrincipal(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/auditevents\").queryParam(\"principal\", \"user\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"events.[*].principal\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"user\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid eventsWithType(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/auditevents\").queryParam(\"type\", \"logout\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"events.[*].principal\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"admin\"))\n\t\t\t.jsonPath(\"events.[*].type\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"logout\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tAuditEventRepository auditEventsRepository() {\n\t\t\tAuditEventRepository repository = new InMemoryAuditEventRepository(3);\n\t\t\trepository.add(createEvent(\"2016-11-01T11:00:00Z\", \"admin\", \"login\"));\n\t\t\trepository.add(createEvent(\"2016-11-01T12:00:00Z\", \"admin\", \"logout\"));\n\t\t\trepository.add(createEvent(\"2016-11-01T12:00:00Z\", \"user\", \"login\"));\n\t\t\treturn repository;\n\t\t}\n\n\t\t@Bean\n\t\tAuditEventsEndpoint auditEventsEndpoint(AuditEventRepository auditEventRepository) {\n\t\t\treturn new AuditEventsEndpoint(auditEventRepository);\n\t\t}\n\n\t\tprivate AuditEvent createEvent(String instant, String principal, String type) {\n\t\t\treturn new AuditEvent(Instant.parse(instant), principal, type, Collections.emptyMap());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAccessIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport javax.management.MBeanOperationInfo;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for controlling access to endpoints exposed by JMX.\n *\n * @author Andy Wilkinson\n */\nclass JmxEndpointAccessIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tJmxEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class))\n\t\t.withUserConfiguration(CustomJmxEndpoint.class)\n\t\t.withPropertyValues(\"spring.jmx.enabled=true\")\n\t\t.withConfiguration(AutoConfigurations.of(BeansEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid accessIsUnrestrictedByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\").run((context) -> {\n\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\tassertThat(hasOperation(mBeanServer, \"beans\", \"beans\")).isTrue();\n\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"read\")).isTrue();\n\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"write\")).isTrue();\n\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"delete\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeReadOnlyByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"beans\", \"beans\")).isTrue();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"read\")).isTrue();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"write\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"delete\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeNoneByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"beans\", \"beans\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"read\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"write\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"delete\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessForOneEndpointCanOverrideTheDefaultAccess() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\", \"management.endpoint.customjmx.access=UNRESTRICTED\")\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"beans\", \"beans\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"read\")).isTrue();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"write\")).isTrue();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"delete\")).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtReadOnly() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\",\n\t\t\t\t\t\"management.endpoints.access.max-permitted=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"beans\", \"beans\")).isTrue();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"read\")).isTrue();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"write\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"delete\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtNone() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\",\n\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\", \"management.endpoints.access.max-permitted=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"beans\", \"beans\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"read\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"write\")).isFalse();\n\t\t\t\tassertThat(hasOperation(mBeanServer, \"customjmx\", \"delete\")).isFalse();\n\t\t\t});\n\t}\n\n\tprivate ObjectName getDefaultObjectName(String endpointId) {\n\t\treturn getObjectName(\"org.springframework.boot\", endpointId);\n\t}\n\n\tprivate ObjectName getObjectName(String domain, String endpointId) {\n\t\ttry {\n\t\t\treturn new ObjectName(\n\t\t\t\t\tString.format(\"%s:type=Endpoint,name=%s\", domain, StringUtils.capitalize(endpointId)));\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid object name\", ex);\n\t\t}\n\n\t}\n\n\tprivate boolean hasOperation(MBeanServer mbeanServer, String endpoint, String operationName) {\n\t\ttry {\n\t\t\tfor (MBeanOperationInfo operation : mbeanServer.getMBeanInfo(getDefaultObjectName(endpoint))\n\t\t\t\t.getOperations()) {\n\t\t\t\tif (operation.getName().equals(operationName)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Continue\n\t\t}\n\t\treturn false;\n\t}\n\n\t@JmxEndpoint(id = \"customjmx\")\n\tstatic class CustomJmxEndpoint {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t\t@WriteOperation\n\t\tString write() {\n\t\t\treturn \"write\";\n\t\t}\n\n\t\t@DeleteOperation\n\t\tString delete() {\n\t\t\treturn \"delete\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport javax.management.InstanceNotFoundException;\nimport javax.management.IntrospectionException;\nimport javax.management.MBeanInfo;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\nimport javax.management.ReflectionException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for endpoints over JMX.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass JmxEndpointIntegrationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tJmxEndpointAutoConfiguration.class, HealthContributorRegistryAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class))\n\t\t.withUserConfiguration(HttpExchangeRepositoryConfiguration.class, AuditEventRepositoryConfiguration.class)\n\t\t.withPropertyValues(\"spring.jmx.enabled=true\")\n\t\t.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,\n\t\t\t\tBeansEndpointAutoConfiguration.class, ShutdownEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid jmxEndpointsExposeHealthByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\tcheckEndpointMBeans(mBeanServer, new String[] { \"health\" }, new String[] { \"beans\", \"shutdown\" });\n\t\t});\n\t}\n\n\t@Test\n\tvoid jmxEndpointsAreExposedWhenLazyInitializationIsEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.include:*\")\n\t\t\t.withBean(LazyInitializationBeanFactoryPostProcessor.class, LazyInitializationBeanFactoryPostProcessor::new)\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tcheckEndpointMBeans(mBeanServer, new String[] { \"beans\", \"health\" }, new String[] { \"shutdown\" });\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jmxEndpointsCanBeExcluded() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.exclude:*\").run((context) -> {\n\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\tcheckEndpointMBeans(mBeanServer, new String[0], new String[] { \"beans\", \"health\", \"shutdown\" });\n\n\t\t});\n\t}\n\n\t@Test\n\tvoid singleJmxEndpointCanBeExposed() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.include=beans\").run((context) -> {\n\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\tcheckEndpointMBeans(mBeanServer, new String[] { \"beans\" }, new String[] { \"health\", \"shutdown\" });\n\t\t});\n\t}\n\n\tprivate void checkEndpointMBeans(MBeanServer mBeanServer, String[] enabledEndpoints, String[] disabledEndpoints) {\n\t\tfor (String enabledEndpoint : enabledEndpoints) {\n\t\t\tassertThat(isRegistered(mBeanServer, getDefaultObjectName(enabledEndpoint)))\n\t\t\t\t.as(String.format(\"Endpoint %s\", enabledEndpoint))\n\t\t\t\t.isTrue();\n\t\t}\n\t\tfor (String disabledEndpoint : disabledEndpoints) {\n\t\t\tassertThat(isRegistered(mBeanServer, getDefaultObjectName(disabledEndpoint)))\n\t\t\t\t.as(String.format(\"Endpoint %s\", disabledEndpoint))\n\t\t\t\t.isFalse();\n\t\t}\n\t}\n\n\tprivate boolean isRegistered(MBeanServer mBeanServer, ObjectName objectName) {\n\t\ttry {\n\t\t\tgetMBeanInfo(mBeanServer, objectName);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (InstanceNotFoundException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate MBeanInfo getMBeanInfo(MBeanServer mBeanServer, ObjectName objectName) throws InstanceNotFoundException {\n\t\ttry {\n\t\t\treturn mBeanServer.getMBeanInfo(objectName);\n\t\t}\n\t\tcatch (ReflectionException | IntrospectionException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to retrieve MBeanInfo for ObjectName \" + objectName, ex);\n\t\t}\n\t}\n\n\tprivate ObjectName getDefaultObjectName(String endpointId) {\n\t\treturn getObjectName(\"org.springframework.boot\", endpointId);\n\t}\n\n\tprivate ObjectName getObjectName(String domain, String endpointId) {\n\t\ttry {\n\t\t\treturn new ObjectName(\n\t\t\t\t\tString.format(\"%s:type=Endpoint,name=%s\", domain, StringUtils.capitalize(endpointId)));\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid object name\", ex);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpExchangeRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryHttpExchangeRepository httpExchangeRepository() {\n\t\t\treturn new InMemoryHttpExchangeRepository();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuditEventRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryAuditEventRepository auditEventRepository() {\n\t\t\treturn new InMemoryAuditEventRepository();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointsAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.context.annotation.UserConfigurations;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the auto-configuration of web endpoints.\n *\n * @author Andy Wilkinson\n */\nclass WebEndpointsAutoConfigurationIntegrationTests {\n\n\t@Test\n\tvoid healthEndpointWebExtensionIsAutoConfigured() {\n\t\tservletWebRunner().run((context) -> context.getBean(WebEndpointTestApplication.class));\n\t\tservletWebRunner().run((context) -> assertThat(context).hasSingleBean(HealthEndpointWebExtension.class));\n\t}\n\n\t@Test\n\tvoid healthEndpointReactiveWebExtensionIsAutoConfigured() {\n\t\treactiveWebRunner()\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveHealthEndpointWebExtension.class));\n\t}\n\n\tprivate WebApplicationContextRunner servletWebRunner() {\n\t\treturn new WebApplicationContextRunner()\n\t\t\t.withConfiguration(UserConfigurations.of(WebEndpointTestApplication.class))\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\");\n\t}\n\n\tprivate ReactiveWebApplicationContextRunner reactiveWebRunner() {\n\t\treturn new ReactiveWebApplicationContextRunner()\n\t\t\t.withConfiguration(UserConfigurations.of(WebEndpointTestApplication.class))\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\");\n\t}\n\n\t@EnableAutoConfiguration\n\t@SpringBootConfiguration\n\tstatic class WebEndpointTestApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ConfigurationPropertiesReportEndpoint} exposed by Jersey,\n * Spring MVC, and WebFlux.\n *\n * @author Chris Bono\n */\nclass ConfigurationPropertiesReportEndpointWebIntegrationTests {\n\n\tprivate WebTestClient client;\n\n\t@BeforeEach\n\tvoid prepareEnvironment(ConfigurableApplicationContext context, WebTestClient client) {\n\t\tTestPropertyValues.of(\"com.foo.name=fooz\", \"com.bar.name=barz\").applyTo(context);\n\t\tthis.client = client;\n\t}\n\n\t@WebEndpointTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid noFilters() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/configprops\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$..beans[*]\")\n\t\t\t.value(List.class, (beans) -> assertThat(beans).hasSizeGreaterThanOrEqualTo(2))\n\t\t\t.jsonPath(\"$..beans['fooDotCom']\")\n\t\t\t.exists()\n\t\t\t.jsonPath(\"$..beans['barDotCom']\")\n\t\t\t.exists();\n\t}\n\n\t@WebEndpointTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid filterByExactPrefix() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/configprops/com.foo\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$..beans[*]\")\n\t\t\t.value(List.class, (beans) -> assertThat(beans).hasSize(1))\n\t\t\t.jsonPath(\"$..beans['fooDotCom']\")\n\t\t\t.exists();\n\t}\n\n\t@WebEndpointTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid filterByGeneralPrefix() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/configprops/com.\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$..beans[*]\")\n\t\t\t.value(List.class, (beans) -> assertThat(beans).hasSize(2))\n\t\t\t.jsonPath(\"$..beans['fooDotCom']\")\n\t\t\t.exists()\n\t\t\t.jsonPath(\"$..beans['barDotCom']\")\n\t\t\t.exists();\n\t}\n\n\t@WebEndpointTest\n\tvoid filterByNonExistentPrefix() {\n\t\tthis.client.get().uri(\"/actuator/configprops/com.zoo\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), null);\n\t\t}\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpointWebExtension endpointWebExtension(\n\t\t\t\tConfigurationPropertiesReportEndpoint endpoint) {\n\t\t\treturn new ConfigurationPropertiesReportEndpointWebExtension(endpoint, Show.ALWAYS, Collections.emptySet());\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"com.foo\")\n\t\tFoo fooDotCom() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"com.bar\")\n\t\tBar barDotCom() {\n\t\t\treturn new Bar();\n\t\t}\n\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name = \"5150\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\tpublic static class Bar {\n\n\t\tprivate String name = \"6160\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/AbstractWebEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.net.InetSocketAddress;\nimport java.security.Principal;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Abstract base class for web endpoint integration tests.\n *\n * @param <T> the type of application context used by the tests\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic abstract class AbstractWebEndpointIntegrationTests<T extends ConfigurableApplicationContext & AnnotationConfigRegistry> {\n\n\tprivate static final Duration TIMEOUT = Duration.ofMinutes(5);\n\n\tprivate static final String ACTUATOR_MEDIA_TYPE_PATTERN = \"application/vnd.test\\\\+json(;charset=UTF-8)?\";\n\n\tprivate static final String JSON_MEDIA_TYPE_PATTERN = \"application/json(;charset=UTF-8)?\";\n\n\tprivate final Supplier<T> applicationContextSupplier;\n\n\tprivate final Consumer<T> authenticatedContextCustomizer;\n\n\tprotected AbstractWebEndpointIntegrationTests(Supplier<T> applicationContextSupplier,\n\t\t\tConsumer<T> authenticatedContextCustomizer) {\n\t\tthis.applicationContextSupplier = applicationContextSupplier;\n\t\tthis.authenticatedContextCustomizer = authenticatedContextCustomizer;\n\t}\n\n\t@Test\n\tvoid readOperation() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/test\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"All\")\n\t\t\t\t\t.isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid readOperationWithEndpointsMappedToTheRoot() {\n\t\tload(TestEndpointConfiguration.class, \"\",\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/test\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"All\")\n\t\t\t\t\t.isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid readOperationWithEndpointPathMappedToTheRoot() {\n\t\tload(EndpointPathMappedToRootConfiguration.class, \"\", (client) -> {\n\t\t\tclient.get().uri(\"/\").exchange().expectStatus().isOk().expectBody().jsonPath(\"All\").isEqualTo(true);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/some-part\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"part\")\n\t\t\t\t.isEqualTo(\"some-part\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid readOperationWithSelector() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/test/one\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"part\")\n\t\t\t\t\t.isEqualTo(\"one\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithSelectorContainingADot() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/test/foo.bar\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"part\")\n\t\t\t\t\t.isEqualTo(\"foo.bar\"));\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsAreProvided() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"_links.length()\")\n\t\t\t\t\t.isEqualTo(3)\n\t\t\t\t\t.jsonPath(\"_links.self.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.self.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.test.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.test.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.test-part.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.test-part.templated\")\n\t\t\t\t\t.isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid linksMappingIsDisabledWhenEndpointPathIsEmpty() {\n\t\tload(TestEndpointConfiguration.class, \"\",\n\t\t\t\t(client) -> client.get().uri(\"\").exchange().expectStatus().isNotFound());\n\t}\n\n\t@Test\n\tprotected void operationWithTrailingSlashShouldNotMatch() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get().uri(\"/test/\").exchange().expectStatus().isNotFound());\n\t}\n\n\t@Test\n\tvoid matchAllRemainingPathsSelectorShouldMatchFullPath() {\n\t\tload(MatchAllRemainingEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/matchallremaining/one/two/three\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"selection\")\n\t\t\t\t\t.isEqualTo(\"one|two|three\"));\n\t}\n\n\t@Test\n\tvoid matchAllRemainingPathsSelectorShouldDecodePath() {\n\t\tload(MatchAllRemainingEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/matchallremaining/one/two three/\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"selection\")\n\t\t\t\t\t.isEqualTo(\"one|two three\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithSingleQueryParameters() {\n\t\tload(QueryEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/query?one=1&two=2\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"query\")\n\t\t\t\t\t.isEqualTo(\"1 2\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithQueryParametersMissing() {\n\t\tload(QueryEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get().uri(\"/query\").exchange().expectStatus().isBadRequest());\n\t}\n\n\t@Test\n\tvoid reactiveReadOperationWithSingleQueryParameters() {\n\t\tload(ReactiveQueryEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/query?param=test\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"query\")\n\t\t\t\t\t.isEqualTo(\"test\"));\n\t}\n\n\t@Test\n\tvoid reactiveReadOperationWithQueryParametersMissing() {\n\t\tload(ReactiveQueryEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get().uri(\"/query\").exchange().expectStatus().isBadRequest());\n\t}\n\n\t@Test\n\tvoid readOperationWithSingleQueryParametersAndMultipleValues() {\n\t\tload(QueryEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/query?one=1&one=1&two=2\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"query\")\n\t\t\t\t\t.isEqualTo(\"1,1 2\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithListQueryParameterAndSingleValue() {\n\t\tload(QueryWithListEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/query?one=1&two=2\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"query\")\n\t\t\t\t\t.isEqualTo(\"1 [2]\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithListQueryParameterAndMultipleValues() {\n\t\tload(QueryWithListEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/query?one=1&two=2&two=2\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"query\")\n\t\t\t\t\t.isEqualTo(\"1 [2, 2]\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithMappingFailureProducesBadRequestResponse() {\n\t\tload(QueryEndpointConfiguration.class, (client) -> {\n\t\t\tWebTestClient.BodyContentSpec body = client.get()\n\t\t\t\t.uri(\"/query?two=two\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody();\n\t\t\tvalidateErrorBody(body, HttpStatus.BAD_REQUEST, \"/endpoints/query\", \"Missing parameters: one\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid writeOperation() {\n\t\tload(TestEndpointConfiguration.class, (client) -> {\n\t\t\tMap<String, Object> body = new HashMap<>();\n\t\t\tbody.put(\"foo\", \"one\");\n\t\t\tbody.put(\"bar\", \"two\");\n\t\t\tclient.post().uri(\"/test\").bodyValue(body).exchange().expectStatus().isNoContent().expectBody().isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid writeOperationWithListOfValuesIsRejected() {\n\t\tload(TestEndpointConfiguration.class, (client) -> {\n\t\t\tMap<String, Object> body = new HashMap<>();\n\t\t\tbody.put(\"generic\", List.of(\"one\", \"two\"));\n\t\t\tclient.post().uri(\"/test/one\").bodyValue(body).exchange().expectStatus().isBadRequest();\n\t\t});\n\t}\n\n\t@Test\n\tvoid writeOperationWithNestedValueIsRejected() {\n\t\tload(TestEndpointConfiguration.class, (client) -> {\n\t\t\tMap<String, Object> body = new HashMap<>();\n\t\t\tbody.put(\"generic\", Map.of(\"nested\", \"one\"));\n\t\t\tclient.post().uri(\"/test/one\").bodyValue(body).exchange().expectStatus().isBadRequest();\n\t\t});\n\t}\n\n\t@Test\n\tvoid writeOperationWithVoidResponse() {\n\t\tload(VoidWriteResponseEndpointConfiguration.class, (context, client) -> {\n\t\t\tclient.post().uri(\"/voidwrite\").exchange().expectStatus().isNoContent().expectBody().isEmpty();\n\t\t\tthen(context.getBean(EndpointDelegate.class)).should().write();\n\t\t});\n\t}\n\n\t@Test\n\tvoid deleteOperation() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.delete()\n\t\t\t\t\t.uri(\"/test/one\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"part\")\n\t\t\t\t\t.isEqualTo(\"one\"));\n\t}\n\n\t@Test\n\tvoid deleteOperationWithVoidResponse() {\n\t\tload(VoidDeleteResponseEndpointConfiguration.class, (context, client) -> {\n\t\t\tclient.delete().uri(\"/voiddelete\").exchange().expectStatus().isNoContent().expectBody().isEmpty();\n\t\t\tthen(context.getBean(EndpointDelegate.class)).should().delete();\n\t\t});\n\t}\n\n\t@Test\n\tvoid nullIsPassedToTheOperationWhenArgumentIsNotFoundInPostRequestBody() {\n\t\tload(TestEndpointConfiguration.class, (context, client) -> {\n\t\t\tMap<String, Object> body = new HashMap<>();\n\t\t\tbody.put(\"foo\", \"one\");\n\t\t\tclient.post().uri(\"/test\").bodyValue(body).exchange().expectStatus().isNoContent().expectBody().isEmpty();\n\t\t\tthen(context.getBean(EndpointDelegate.class)).should().write(\"one\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid nullsArePassedToTheOperationWhenPostRequestHasNoBody() {\n\t\tload(TestEndpointConfiguration.class, (context, client) -> {\n\t\t\tclient.post()\n\t\t\t\t.uri(\"/test\")\n\t\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNoContent()\n\t\t\t\t.expectBody()\n\t\t\t\t.isEmpty();\n\t\t\tthen(context.getBean(EndpointDelegate.class)).should().write(null, null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid nullResponseFromReadOperationResultsInNotFoundResponseStatus() {\n\t\tload(NullReadResponseEndpointConfiguration.class,\n\t\t\t\t(context, client) -> client.get().uri(\"/nullread\").exchange().expectStatus().isNotFound());\n\t}\n\n\t@Test\n\tvoid nullResponseFromDeleteOperationResultsInNoContentResponseStatus() {\n\t\tload(NullDeleteResponseEndpointConfiguration.class,\n\t\t\t\t(context, client) -> client.delete().uri(\"/nulldelete\").exchange().expectStatus().isNoContent());\n\t}\n\n\t@Test\n\tvoid nullResponseFromWriteOperationResultsInNoContentResponseStatus() {\n\t\tload(NullWriteResponseEndpointConfiguration.class,\n\t\t\t\t(context, client) -> client.post().uri(\"/nullwrite\").exchange().expectStatus().isNoContent());\n\t}\n\n\t@Test\n\tvoid readOperationWithResourceResponse() {\n\t\tload(ResourceEndpointConfiguration.class, (context, client) -> {\n\t\t\tbyte[] responseBody = client.get()\n\t\t\t\t.uri(\"/resource\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(MediaType.APPLICATION_OCTET_STREAM)\n\t\t\t\t.returnResult(byte[].class)\n\t\t\t\t.getResponseBodyContent();\n\t\t\tassertThat(responseBody).containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);\n\t\t});\n\t}\n\n\t@Test\n\tvoid readOperationWithResourceWebOperationResponse() {\n\t\tload(ResourceWebEndpointResponseEndpointConfiguration.class, (context, client) -> {\n\t\t\tbyte[] responseBody = client.get()\n\t\t\t\t.uri(\"/resource\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(MediaType.APPLICATION_OCTET_STREAM)\n\t\t\t\t.returnResult(byte[].class)\n\t\t\t\t.getResponseBodyContent();\n\t\t\tassertThat(responseBody).containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);\n\t\t});\n\t}\n\n\t@Test\n\tvoid readOperationWithMonoResponse() {\n\t\tload(MonoResponseEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/mono\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"a\")\n\t\t\t\t\t.isEqualTo(\"alpha\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithFluxResponse() {\n\t\tload(FluxResponseEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/flux\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"[0].a\")\n\t\t\t\t\t.isEqualTo(\"alpha\")\n\t\t\t\t\t.jsonPath(\"[1].b\")\n\t\t\t\t\t.isEqualTo(\"bravo\")\n\t\t\t\t\t.jsonPath(\"[2].c\")\n\t\t\t\t\t.isEqualTo(\"charlie\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithCustomMediaType() {\n\t\tload(CustomMediaTypesEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/custommediatypes\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueMatches(\"Content-Type\", \"text/plain(;charset=.*)?\"));\n\t}\n\n\t@Test\n\tvoid readOperationWithMissingRequiredParametersReturnsBadRequestResponse() {\n\t\tload(RequiredParameterEndpointConfiguration.class, (client) -> {\n\t\t\tWebTestClient.BodyContentSpec body = client.get()\n\t\t\t\t.uri(\"/requiredparameters\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody();\n\t\t\tvalidateErrorBody(body, HttpStatus.BAD_REQUEST, \"/endpoints/requiredparameters\", \"Missing parameters: foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid readOperationWithMissingNullableParametersIsOk() {\n\t\tload(RequiredParameterEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get().uri(\"/requiredparameters?foo=hello\").exchange().expectStatus().isOk());\n\t}\n\n\t@Test\n\tvoid endpointsProducePrimaryMediaTypeByDefault() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/test\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueMatches(\"Content-Type\", ACTUATOR_MEDIA_TYPE_PATTERN));\n\t}\n\n\t@Test\n\tvoid endpointsProduceSecondaryMediaTypeWhenRequested() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/test\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueMatches(\"Content-Type\", JSON_MEDIA_TYPE_PATTERN));\n\t}\n\n\t@Test\n\tvoid linksProducesPrimaryMediaTypeByDefault() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueMatches(\"Content-Type\", ACTUATOR_MEDIA_TYPE_PATTERN));\n\t}\n\n\t@Test\n\tvoid linksProducesSecondaryMediaTypeWhenRequested() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueMatches(\"Content-Type\", JSON_MEDIA_TYPE_PATTERN));\n\t}\n\n\t@Test\n\tvoid principalIsNullWhenRequestHasNoPrincipal() {\n\t\tload(PrincipalEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/principal\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody(String.class)\n\t\t\t\t\t.isEqualTo(\"None\"));\n\t}\n\n\t@Test\n\tvoid principalIsAvailableWhenRequestHasAPrincipal() {\n\t\tload((context) -> {\n\t\t\tthis.authenticatedContextCustomizer.accept(context);\n\t\t\tcontext.register(PrincipalEndpointConfiguration.class);\n\t\t}, (client) -> client.get()\n\t\t\t.uri(\"/principal\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Alice\"));\n\t}\n\n\t@Test\n\tvoid operationWithAQueryNamedPrincipalCanBeAccessedWhenAuthenticated() {\n\t\tload((context) -> {\n\t\t\tthis.authenticatedContextCustomizer.accept(context);\n\t\t\tcontext.register(PrincipalQueryEndpointConfiguration.class);\n\t\t}, (client) -> client.get()\n\t\t\t.uri(\"/principalquery?principal=Zoe\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Zoe\"));\n\t}\n\n\t@Test\n\tvoid securityContextIsAvailableAndHasNullPrincipalWhenRequestHasNoPrincipal() {\n\t\tload(SecurityContextEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/securitycontext\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody(String.class)\n\t\t\t\t\t.isEqualTo(\"None\"));\n\t}\n\n\t@Test\n\tvoid securityContextIsAvailableAndHasPrincipalWhenRequestHasPrincipal() {\n\t\tload((context) -> {\n\t\t\tthis.authenticatedContextCustomizer.accept(context);\n\t\t\tcontext.register(SecurityContextEndpointConfiguration.class);\n\t\t}, (client) -> client.get()\n\t\t\t.uri(\"/securitycontext\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Alice\"));\n\t}\n\n\t@Test\n\tvoid userInRoleReturnsFalseWhenRequestHasNoPrincipal() {\n\t\tload(UserInRoleEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/userinrole?role=ADMIN\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody(String.class)\n\t\t\t\t\t.isEqualTo(\"ADMIN: false\"));\n\t}\n\n\t@Test\n\tvoid userInRoleReturnsFalseWhenUserIsNotInRole() {\n\t\tload((context) -> {\n\t\t\tthis.authenticatedContextCustomizer.accept(context);\n\t\t\tcontext.register(UserInRoleEndpointConfiguration.class);\n\t\t}, (client) -> client.get()\n\t\t\t.uri(\"/userinrole?role=ADMIN\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"ADMIN: false\"));\n\t}\n\n\t@Test\n\tvoid userInRoleReturnsTrueWhenUserIsInRole() {\n\t\tload((context) -> {\n\t\t\tthis.authenticatedContextCustomizer.accept(context);\n\t\t\tcontext.register(UserInRoleEndpointConfiguration.class);\n\t\t}, (client) -> client.get()\n\t\t\t.uri(\"/userinrole?role=ACTUATOR\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"ACTUATOR: true\"));\n\t}\n\n\t@Test\n\tvoid endpointCanProduceAResponseWithACustomStatus() {\n\t\tload((context) -> context.register(CustomResponseStatusEndpointConfiguration.class),\n\t\t\t\t(client) -> client.get().uri(\"/customstatus\").exchange().expectStatus().isEqualTo(234));\n\t}\n\n\tprotected abstract int getPort(T context);\n\n\tprotected void validateErrorBody(WebTestClient.BodyContentSpec body, HttpStatus status, String path,\n\t\t\tString message) {\n\t\tbody.jsonPath(\"status\")\n\t\t\t.isEqualTo(status.value())\n\t\t\t.jsonPath(\"error\")\n\t\t\t.isEqualTo(status.getReasonPhrase())\n\t\t\t.jsonPath(\"path\")\n\t\t\t.isEqualTo(path)\n\t\t\t.jsonPath(\"message\")\n\t\t\t.isEqualTo(message);\n\t}\n\n\tprivate void load(Class<?> configuration, BiConsumer<ApplicationContext, WebTestClient> consumer) {\n\t\tload((context) -> context.register(configuration), \"/endpoints\", consumer);\n\t}\n\n\tprotected void load(Class<?> configuration, Consumer<WebTestClient> clientConsumer) {\n\t\tload((context) -> context.register(configuration), \"/endpoints\",\n\t\t\t\t(context, client) -> clientConsumer.accept(client));\n\t}\n\n\tprotected void load(Consumer<T> contextCustomizer, Consumer<WebTestClient> clientConsumer) {\n\t\tload(contextCustomizer, \"/endpoints\", (context, client) -> clientConsumer.accept(client));\n\t}\n\n\tprotected void load(Class<?> configuration, String endpointPath, Consumer<WebTestClient> clientConsumer) {\n\t\tload((context) -> context.register(configuration), endpointPath,\n\t\t\t\t(context, client) -> clientConsumer.accept(client));\n\t}\n\n\tprivate void load(Consumer<T> contextCustomizer, String endpointPath,\n\t\t\tBiConsumer<ApplicationContext, WebTestClient> consumer) {\n\t\tT applicationContext = this.applicationContextSupplier.get();\n\t\tcontextCustomizer.accept(applicationContext);\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"endpointPath\", endpointPath);\n\t\tproperties.put(\"spring.web.error.include-message\", \"always\");\n\t\tapplicationContext.getEnvironment().getPropertySources().addLast(new MapPropertySource(\"test\", properties));\n\t\tapplicationContext.refresh();\n\t\ttry {\n\t\t\tInetSocketAddress address = new InetSocketAddress(getPort(applicationContext));\n\t\t\tString url = \"http://\" + address.getHostString() + \":\" + address.getPort() + endpointPath;\n\t\t\tconsumer.accept(applicationContext,\n\t\t\t\t\tWebTestClient.bindToServer().baseUrl(url).responseTimeout(TIMEOUT).build());\n\t\t}\n\t\tfinally {\n\t\t\tapplicationContext.close();\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tprotected static class TestEndpointConfiguration {\n\n\t\t@Bean\n\t\tpublic TestEndpoint testEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\treturn new TestEndpoint(endpointDelegate);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestEndpointConfiguration.class)\n\tprotected static class EndpointPathMappedToRootConfiguration {\n\n\t\t@Bean\n\t\tPathMapper pathMapper() {\n\t\t\treturn (endpointId) -> \"/\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class MatchAllRemainingEndpointConfiguration {\n\n\t\t@Bean\n\t\tMatchAllRemainingEndpoint matchAllRemainingEndpoint() {\n\t\t\treturn new MatchAllRemainingEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class QueryEndpointConfiguration {\n\n\t\t@Bean\n\t\tQueryEndpoint queryEndpoint() {\n\t\t\treturn new QueryEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class QueryWithListEndpointConfiguration {\n\n\t\t@Bean\n\t\tQueryWithListEndpoint queryEndpoint() {\n\t\t\treturn new QueryWithListEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class ReactiveQueryEndpointConfiguration {\n\n\t\t@Bean\n\t\tReactiveQueryEndpoint reactiveQueryEndpoint() {\n\t\t\treturn new ReactiveQueryEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class VoidWriteResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tVoidWriteResponseEndpoint voidWriteResponseEndpoint(EndpointDelegate delegate) {\n\t\t\treturn new VoidWriteResponseEndpoint(delegate);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class VoidDeleteResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tVoidDeleteResponseEndpoint voidDeleteResponseEndpoint(EndpointDelegate delegate) {\n\t\t\treturn new VoidDeleteResponseEndpoint(delegate);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class NullWriteResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tNullWriteResponseEndpoint nullWriteResponseEndpoint(EndpointDelegate delegate) {\n\t\t\treturn new NullWriteResponseEndpoint(delegate);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class NullReadResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tNullReadResponseEndpoint nullResponseEndpoint() {\n\t\t\treturn new NullReadResponseEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class NullDeleteResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tNullDeleteResponseEndpoint nullDeleteResponseEndpoint() {\n\t\t\treturn new NullDeleteResponseEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tprotected static class ResourceEndpointConfiguration {\n\n\t\t@Bean\n\t\tpublic ResourceEndpoint resourceEndpoint() {\n\t\t\treturn new ResourceEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class ResourceWebEndpointResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tResourceWebEndpointResponseEndpoint resourceEndpoint() {\n\t\t\treturn new ResourceWebEndpointResponseEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class MonoResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tMonoResponseEndpoint testEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\treturn new MonoResponseEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class FluxResponseEndpointConfiguration {\n\n\t\t@Bean\n\t\tFluxResponseEndpoint testEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\treturn new FluxResponseEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomMediaTypesEndpointConfiguration {\n\n\t\t@Bean\n\t\tCustomMediaTypesEndpoint customMediaTypesEndpoint() {\n\t\t\treturn new CustomMediaTypesEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class RequiredParameterEndpointConfiguration {\n\n\t\t@Bean\n\t\tRequiredParametersEndpoint requiredParametersEndpoint() {\n\t\t\treturn new RequiredParametersEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class PrincipalEndpointConfiguration {\n\n\t\t@Bean\n\t\tPrincipalEndpoint principalEndpoint() {\n\t\t\treturn new PrincipalEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class PrincipalQueryEndpointConfiguration {\n\n\t\t@Bean\n\t\tPrincipalQueryEndpoint principalQueryEndpoint() {\n\t\t\treturn new PrincipalQueryEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class SecurityContextEndpointConfiguration {\n\n\t\t@Bean\n\t\tSecurityContextEndpoint securityContextEndpoint() {\n\t\t\treturn new SecurityContextEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class UserInRoleEndpointConfiguration {\n\n\t\t@Bean\n\t\tUserInRoleEndpoint userInRoleEndpoint() {\n\t\t\treturn new UserInRoleEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomResponseStatusEndpointConfiguration {\n\n\t\t@Bean\n\t\tCustomResponseStatusEndpoint customResponseStatusEndpoint() {\n\t\t\treturn new CustomResponseStatusEndpoint();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\tprivate final EndpointDelegate endpointDelegate;\n\n\t\tTestEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\tthis.endpointDelegate = endpointDelegate;\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readPart(@Selector String part) {\n\t\t\treturn Collections.singletonMap(\"part\", part);\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid write(@Nullable String foo, @Nullable String bar) {\n\t\t\tthis.endpointDelegate.write(foo, bar);\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid writeGeneric(@Selector String part, Object generic) {\n\t\t\tthis.endpointDelegate.write(generic.toString(), generic.toString());\n\t\t}\n\n\t\t@DeleteOperation\n\t\tMap<String, Object> deletePart(@Selector String part) {\n\t\t\treturn Collections.singletonMap(\"part\", part);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"matchallremaining\")\n\tstatic class MatchAllRemainingEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, String> select(@Selector(match = Match.ALL_REMAINING) String... selection) {\n\t\t\treturn Collections.singletonMap(\"selection\", StringUtils.arrayToDelimitedString(selection, \"|\"));\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"query\")\n\tstatic class QueryEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, String> query(String one, Integer two) {\n\t\t\treturn Collections.singletonMap(\"query\", one + \" \" + two);\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, String> queryWithParameterList(@Selector String list, String one, List<String> two) {\n\t\t\treturn Collections.singletonMap(\"query\", list + \" \" + one + \" \" + two);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"query\")\n\tstatic class QueryWithListEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, String> queryWithParameterList(String one, List<String> two) {\n\t\t\treturn Collections.singletonMap(\"query\", one + \" \" + two);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"query\")\n\tstatic class ReactiveQueryEndpoint {\n\n\t\t@ReadOperation\n\t\tMono<Map<String, String>> query(String param) {\n\t\t\treturn Mono.just(Collections.singletonMap(\"query\", param));\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"voidwrite\")\n\tstatic class VoidWriteResponseEndpoint {\n\n\t\tprivate final EndpointDelegate delegate;\n\n\t\tVoidWriteResponseEndpoint(EndpointDelegate delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid write() {\n\t\t\tthis.delegate.write();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"voiddelete\")\n\tstatic class VoidDeleteResponseEndpoint {\n\n\t\tprivate final EndpointDelegate delegate;\n\n\t\tVoidDeleteResponseEndpoint(EndpointDelegate delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@DeleteOperation\n\t\tvoid delete() {\n\t\t\tthis.delegate.delete();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"nullwrite\")\n\tstatic class NullWriteResponseEndpoint {\n\n\t\tprivate final EndpointDelegate delegate;\n\n\t\tNullWriteResponseEndpoint(EndpointDelegate delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@WriteOperation\n\t\tObject write() {\n\t\t\tthis.delegate.write();\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"nullread\")\n\tstatic class NullReadResponseEndpoint {\n\n\t\t@ReadOperation\n\t\tString readReturningNull() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"nulldelete\")\n\tstatic class NullDeleteResponseEndpoint {\n\n\t\t@DeleteOperation\n\t\tString deleteReturningNull() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"resource\")\n\tstatic class ResourceEndpoint {\n\n\t\t@ReadOperation\n\t\tResource read() {\n\t\t\treturn new ByteArrayResource(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"resource\")\n\tstatic class ResourceWebEndpointResponseEndpoint {\n\n\t\t@ReadOperation\n\t\tWebEndpointResponse<Resource> read() {\n\t\t\treturn new WebEndpointResponse<>(new ByteArrayResource(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }), 200);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"mono\")\n\tstatic class MonoResponseEndpoint {\n\n\t\t@ReadOperation\n\t\tMono<Map<String, String>> operation() {\n\t\t\treturn Mono.just(Collections.singletonMap(\"a\", \"alpha\"));\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"flux\")\n\tstatic class FluxResponseEndpoint {\n\n\t\t@ReadOperation\n\t\tFlux<Map<String, String>> operation() {\n\t\t\treturn Flux.just(Collections.singletonMap(\"a\", \"alpha\"), Collections.singletonMap(\"b\", \"bravo\"),\n\t\t\t\t\tCollections.singletonMap(\"c\", \"charlie\"));\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"custommediatypes\")\n\tstatic class CustomMediaTypesEndpoint {\n\n\t\t@ReadOperation(produces = \"text/plain\")\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"requiredparameters\")\n\tstatic class RequiredParametersEndpoint {\n\n\t\t@ReadOperation\n\t\tString read(String foo, @Nullable String bar) {\n\t\t\treturn foo;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"principal\")\n\tstatic class PrincipalEndpoint {\n\n\t\t@ReadOperation\n\t\tString read(@Nullable Principal principal) {\n\t\t\treturn (principal != null) ? principal.getName() : \"None\";\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"principalquery\")\n\tstatic class PrincipalQueryEndpoint {\n\n\t\t@ReadOperation\n\t\tString read(String principal) {\n\t\t\treturn principal;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"securitycontext\")\n\tstatic class SecurityContextEndpoint {\n\n\t\t@ReadOperation\n\t\tString read(SecurityContext securityContext) {\n\t\t\tPrincipal principal = securityContext.getPrincipal();\n\t\t\treturn (principal != null) ? principal.getName() : \"None\";\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"userinrole\")\n\tstatic class UserInRoleEndpoint {\n\n\t\t@ReadOperation\n\t\tString read(SecurityContext securityContext, String role) {\n\t\t\treturn role + \": \" + securityContext.isUserInRole(role);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"customstatus\")\n\tstatic class CustomResponseStatusEndpoint {\n\n\t\t@ReadOperation\n\t\tWebEndpointResponse<String> read() {\n\t\t\treturn new WebEndpointResponse<>(\"Custom status\", 234);\n\t\t}\n\n\t}\n\n\tinterface EndpointDelegate {\n\n\t\tvoid write();\n\n\t\tvoid write(String foo, String bar);\n\n\t\tvoid delete();\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/BaseConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.tomcat.TomcatEmbeddedWebappClassLoader;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.convert.support.DefaultConversionService;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Base configuration shared by tests.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\nclass BaseConfiguration {\n\n\t@Bean\n\tAbstractWebEndpointIntegrationTests.EndpointDelegate endpointDelegate() {\n\t\tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n\t\tif (classLoader instanceof TomcatEmbeddedWebappClassLoader) {\n\t\t\tThread.currentThread().setContextClassLoader(classLoader.getParent());\n\t\t}\n\t\ttry {\n\t\t\treturn mock(AbstractWebEndpointIntegrationTests.EndpointDelegate.class);\n\t\t}\n\t\tfinally {\n\t\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\t}\n\t}\n\n\t@Bean\n\tEndpointMediaTypes endpointMediaTypes() {\n\t\tList<String> mediaTypes = Arrays.asList(\"application/vnd.test+json\", \"application/json\");\n\t\treturn new EndpointMediaTypes(mediaTypes, mediaTypes);\n\t}\n\n\t@Bean\n\tWebEndpointDiscoverer webEndpointDiscoverer(EndpointMediaTypes endpointMediaTypes,\n\t\t\tApplicationContext applicationContext, ObjectProvider<PathMapper> pathMappers) {\n\t\tParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\treturn new WebEndpointDiscoverer(applicationContext, parameterMapper, endpointMediaTypes,\n\t\t\t\tpathMappers.orderedStream().toList(), Collections.emptyList(), Collections.emptyList(),\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t}\n\n\t@Bean\n\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/jersey/JerseyWebEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.jersey;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.ws.rs.ext.ContextResolver;\nimport org.glassfish.jersey.jackson.JacksonFeature;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.server.model.Resource;\nimport org.glassfish.jersey.servlet.ServletContainer;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.context.SecurityContext;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\n/**\n * Integration tests for web endpoints exposed using Jersey.\n *\n * @author Andy Wilkinson\n * @see JerseyEndpointResourceFactory\n */\nclass JerseyWebEndpointIntegrationTests\n\t\textends AbstractWebEndpointIntegrationTests<AnnotationConfigServletWebServerApplicationContext> {\n\n\tJerseyWebEndpointIntegrationTests() {\n\t\tsuper(JerseyWebEndpointIntegrationTests::createApplicationContext,\n\t\t\t\tJerseyWebEndpointIntegrationTests::applyAuthenticatedConfiguration);\n\t}\n\n\tprivate static AnnotationConfigServletWebServerApplicationContext createApplicationContext() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tcontext.register(JerseyConfiguration.class);\n\t\treturn context;\n\t}\n\n\tprivate static void applyAuthenticatedConfiguration(AnnotationConfigServletWebServerApplicationContext context) {\n\t\tcontext.register(AuthenticatedConfiguration.class);\n\t}\n\n\t@Override\n\tprotected int getPort(AnnotationConfigServletWebServerApplicationContext context) {\n\t\treturn context.getWebServer().getPort();\n\t}\n\n\t@Override\n\tprotected void validateErrorBody(WebTestClient.BodyContentSpec body, HttpStatus status, String path,\n\t\t\tString message) {\n\t\t// Jersey doesn't support the general error page handling\n\t}\n\n\t@Override\n\t@Test\n\t@Disabled(\"Jersey does not distinguish between /example and /example/\")\n\tprotected void operationWithTrailingSlashShouldNotMatch() {\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JerseyConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<ServletContainer> servletContainer(ResourceConfig resourceConfig) {\n\t\t\treturn new ServletRegistrationBean<>(new ServletContainer(resourceConfig), \"/*\");\n\t\t}\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig(Environment environment, WebEndpointDiscoverer endpointDiscoverer,\n\t\t\t\tEndpointMediaTypes endpointMediaTypes) {\n\t\t\tResourceConfig resourceConfig = new ResourceConfig();\n\t\t\tString endpointPath = environment.getProperty(\"endpointPath\");\n\t\t\tCollection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(\n\t\t\t\t\tnew EndpointMapping(endpointPath), endpointDiscoverer.getEndpoints(), endpointMediaTypes,\n\t\t\t\t\tnew EndpointLinksResolver(endpointDiscoverer.getEndpoints()), StringUtils.hasText(endpointPath));\n\t\t\tresourceConfig.registerResources(new HashSet<>(resources));\n\t\t\tresourceConfig.register(JacksonFeature.class);\n\t\t\tresourceConfig.register(new ObjectMapperContextResolver(new ObjectMapper()), ContextResolver.class);\n\t\t\treturn resourceConfig;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuthenticatedConfiguration {\n\n\t\t@Bean\n\t\tFilter securityFilter() {\n\t\t\treturn new OncePerRequestFilter() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\t\t\tFilterChain filterChain) throws ServletException, IOException {\n\t\t\t\t\tSecurityContext context = SecurityContextHolder.createEmptyContext();\n\t\t\t\t\tcontext.setAuthentication(new UsernamePasswordAuthenticationToken(\"Alice\", \"secret\",\n\t\t\t\t\t\t\tArrays.asList(new SimpleGrantedAuthority(\"ROLE_ACTUATOR\"))));\n\t\t\t\t\tSecurityContextHolder.setContext(context);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfilterChain.doFilter(new SecurityContextHolderAwareRequestWrapper(request, \"ROLE_\"), response);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\tSecurityContextHolder.clearContext();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tprivate static final class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {\n\n\t\tprivate final ObjectMapper objectMapper;\n\n\t\tprivate ObjectMapperContextResolver(ObjectMapper objectMapper) {\n\t\t\tthis.objectMapper = objectMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic ObjectMapper getContext(Class<?> type) {\n\t\t\treturn this.objectMapper;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/ControllerEndpointHandlerMappingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.reactive;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\n/**\n * Integration tests for {@link ControllerEndpointHandlerMapping}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@SuppressWarnings(\"removal\")\n@Deprecated(since = \"3.3.5\", forRemoval = true)\nclass ControllerEndpointHandlerMappingIntegrationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(\n\t\t\tAnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t.withUserConfiguration(EndpointConfiguration.class, ExampleWebFluxEndpoint.class);\n\n\t@Test\n\tvoid getMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t.uri(\"/actuator/example/one\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"One\")));\n\t}\n\n\t@Test\n\tvoid getWithUnacceptableContentType() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t.uri(\"/actuator/example/one\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.NOT_ACCEPTABLE)));\n\t}\n\n\t@Test\n\tvoid postMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t.uri(\"/actuator/example/two\")\n\t\t\t.bodyValue(Collections.singletonMap(\"id\", \"test\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isCreated()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(HttpHeaders.LOCATION, \"/example/test\")));\n\t}\n\n\t@Test\n\tvoid postMappingWithReadOnlyAccessRespondsWith404() {\n\t\tthis.contextRunner.withPropertyValues(\"endpoint-access=READ_ONLY\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t\t.uri(\"/actuator/example/two\")\n\t\t\t\t.bodyValue(Collections.singletonMap(\"id\", \"test\"))\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound()));\n\t}\n\n\t@Test\n\tvoid getToRequestMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Three\")));\n\t}\n\n\t@Test\n\tvoid getToRequestMappingWithReadOnlyAccess() {\n\t\tthis.contextRunner.withPropertyValues(\"endpoint-access=READ_ONLY\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t\t.expectBody(String.class)\n\t\t\t\t.isEqualTo(\"Three\")));\n\t}\n\n\t@Test\n\tvoid postToRequestMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Three\")));\n\t}\n\n\t@Test\n\tvoid postToRequestMappingWithReadOnlyAccessRespondsWith405() {\n\t\tthis.contextRunner.withPropertyValues(\"endpoint-access=READ_ONLY\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.METHOD_NOT_ALLOWED)));\n\t}\n\n\tprivate ContextConsumer<AssertableReactiveWebApplicationContext> withWebTestClient(\n\t\t\tConsumer<WebTestClient> webClient) {\n\t\treturn (context) -> {\n\t\t\tint port = ((AnnotationConfigReactiveWebServerApplicationContext) context.getSourceApplicationContext())\n\t\t\t\t.getWebServer()\n\t\t\t\t.getPort();\n\t\t\tWebTestClient webTestClient = createWebTestClient(port);\n\t\t\twebClient.accept(webTestClient);\n\t\t};\n\t}\n\n\tprivate WebTestClient createWebTestClient(int port) {\n\t\tDefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(\"http://localhost:\" + port);\n\t\turiBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.uriBuilderFactory(uriBuilderFactory)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tWebFluxAutoConfiguration.class })\n\tstatic class EndpointConfiguration {\n\n\t\t@Bean\n\t\tNettyReactiveWebServerFactory netty() {\n\t\t\treturn new NettyReactiveWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ApplicationContext applicationContext) {\n\t\t\treturn WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t\t}\n\n\t\t@Bean\n\t\tControllerEndpointDiscoverer webEndpointDiscoverer(ApplicationContext applicationContext) {\n\t\t\treturn new ControllerEndpointDiscoverer(applicationContext, null, Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tControllerEndpointHandlerMapping webEndpointHandlerMapping(ControllerEndpointsSupplier endpointsSupplier,\n\t\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\t\treturn new ControllerEndpointHandlerMapping(new EndpointMapping(\"actuator\"),\n\t\t\t\t\tendpointsSupplier.getEndpoints(), null, endpointAccessResolver);\n\t\t}\n\n\t\t@Bean\n\t\tEndpointAccessResolver endpointAccessResolver(Environment environment) {\n\t\t\treturn (id, defaultAccess) -> environment.getProperty(\"endpoint-access\", Access.class, Access.UNRESTRICTED);\n\t\t}\n\n\t}\n\n\t@RestControllerEndpoint(id = \"example\")\n\tstatic class ExampleWebFluxEndpoint {\n\n\t\t@GetMapping(path = \"one\", produces = MediaType.TEXT_PLAIN_VALUE)\n\t\tString one() {\n\t\t\treturn \"One\";\n\t\t}\n\n\t\t@PostMapping(\"/two\")\n\t\tResponseEntity<String> two(@RequestBody Map<String, Object> content) {\n\t\t\treturn ResponseEntity.created(URI.create(\"/example/\" + content.get(\"id\"))).build();\n\t\t}\n\n\t\t@RequestMapping(path = \"/three\", produces = MediaType.TEXT_PLAIN_VALUE)\n\t\tString three() {\n\t\t\treturn \"Three\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.reactive;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.reactive.context.ReactiveWebServerInitializedEvent;\nimport org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;\nimport org.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.context.ReactiveSecurityContextHolder;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.server.WebFilter;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for web endpoints exposed using WebFlux.\n *\n * @author Andy Wilkinson\n * @see WebFluxEndpointHandlerMapping\n */\nclass WebFluxEndpointIntegrationTests\n\t\textends AbstractWebEndpointIntegrationTests<AnnotationConfigReactiveWebServerApplicationContext> {\n\n\tWebFluxEndpointIntegrationTests() {\n\t\tsuper(WebFluxEndpointIntegrationTests::createApplicationContext,\n\t\t\t\tWebFluxEndpointIntegrationTests::applyAuthenticatedConfiguration);\n\n\t}\n\n\tprivate static AnnotationConfigReactiveWebServerApplicationContext createApplicationContext() {\n\t\tAnnotationConfigReactiveWebServerApplicationContext context = new AnnotationConfigReactiveWebServerApplicationContext();\n\t\tcontext.register(ReactiveConfiguration.class);\n\t\treturn context;\n\t}\n\n\tprivate static void applyAuthenticatedConfiguration(AnnotationConfigReactiveWebServerApplicationContext context) {\n\t\tcontext.register(AuthenticatedConfiguration.class);\n\t}\n\n\t@Test\n\tvoid responseToOptionsRequestIncludesCorsHeaders() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.options()\n\t\t\t\t\t.uri(\"/test\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Access-Control-Request-Method\", \"POST\")\n\t\t\t\t\t.header(\"Origin\", \"https://example.com\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueEquals(\"Access-Control-Allow-Origin\", \"https://example.com\")\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueEquals(\"Access-Control-Allow-Methods\", \"GET,POST\"));\n\t}\n\n\t@Test\n\tvoid readOperationsThatReturnAResourceSupportRangeRequests() {\n\t\tload(ResourceEndpointConfiguration.class, (client) -> {\n\t\t\tbyte[] responseBody = client.get()\n\t\t\t\t.uri(\"/resource\")\n\t\t\t\t.header(\"Range\", \"bytes=0-3\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.PARTIAL_CONTENT)\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(MediaType.APPLICATION_OCTET_STREAM)\n\t\t\t\t.returnResult(byte[].class)\n\t\t\t\t.getResponseBodyContent();\n\t\t\tassertThat(responseBody).containsExactly(0, 1, 2, 3);\n\t\t});\n\t}\n\n\t@Override\n\tprotected int getPort(AnnotationConfigReactiveWebServerApplicationContext context) {\n\t\treturn context.getBean(ReactiveConfiguration.class).port;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\t@ImportAutoConfiguration(ErrorWebFluxAutoConfiguration.class)\n\tstatic class ReactiveConfiguration {\n\n\t\tprivate int port;\n\n\t\t@Bean\n\t\tNettyReactiveWebServerFactory netty() {\n\t\t\treturn new NettyReactiveWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ApplicationContext applicationContext) {\n\t\t\treturn WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t\t}\n\n\t\t@Bean\n\t\tWebFluxEndpointHandlerMapping webEndpointHandlerMapping(Environment environment,\n\t\t\t\tWebEndpointDiscoverer endpointDiscoverer, EndpointMediaTypes endpointMediaTypes) {\n\t\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\t\tcorsConfiguration.setAllowedOrigins(Arrays.asList(\"https://example.com\"));\n\t\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(\"GET\", \"POST\"));\n\t\t\tString endpointPath = environment.getProperty(\"endpointPath\");\n\t\t\treturn new WebFluxEndpointHandlerMapping(new EndpointMapping(endpointPath),\n\t\t\t\t\tendpointDiscoverer.getEndpoints(), endpointMediaTypes, corsConfiguration,\n\t\t\t\t\tnew EndpointLinksResolver(endpointDiscoverer.getEndpoints()), StringUtils.hasText(endpointPath));\n\t\t}\n\n\t\t@Bean\n\t\tApplicationListener<ReactiveWebServerInitializedEvent> serverInitializedListener() {\n\t\t\treturn (event) -> this.port = event.getWebServer().getPort();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuthenticatedConfiguration {\n\n\t\t@Bean\n\t\tWebFilter webFilter() {\n\t\t\treturn (exchange, chain) -> chain.filter(exchange)\n\t\t\t\t.contextWrite(ReactiveSecurityContextHolder.withAuthentication(new UsernamePasswordAuthenticationToken(\n\t\t\t\t\t\t\"Alice\", \"secret\", Arrays.asList(new SimpleGrantedAuthority(\"ROLE_ACTUATOR\")))));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/ControllerEndpointHandlerMappingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.servlet;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.ControllerEndpointHandlerMapping;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\n/**\n * Integration tests for {@link ControllerEndpointHandlerMapping}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.5\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass ControllerEndpointHandlerMappingIntegrationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withUserConfiguration(EndpointConfiguration.class, ExampleMvcEndpoint.class);\n\n\t@Test\n\tvoid getMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t.uri(\"/actuator/example/one\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"One\")));\n\t}\n\n\t@Test\n\tvoid getWithUnacceptableContentType() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t.uri(\"/actuator/example/one\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.NOT_ACCEPTABLE)));\n\t}\n\n\t@Test\n\tvoid postMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t.uri(\"/actuator/example/two\")\n\t\t\t.bodyValue(Collections.singletonMap(\"id\", \"test\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isCreated()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(HttpHeaders.LOCATION, \"/example/test\")));\n\t}\n\n\t@Test\n\tvoid postMappingWithReadOnlyAccessRespondsWith404() {\n\t\tthis.contextRunner.withPropertyValues(\"endpoint-access=READ_ONLY\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t\t.uri(\"/actuator/example/two\")\n\t\t\t\t.bodyValue(Collections.singletonMap(\"id\", \"test\"))\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound()));\n\t}\n\n\t@Test\n\tvoid getToRequestMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Three\")));\n\t}\n\n\t@Test\n\tvoid getToRequestMappingWithReadOnlyAccess() {\n\t\tthis.contextRunner.withPropertyValues(\"endpoint-access=READ_ONLY\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.get()\n\t\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t\t.expectBody(String.class)\n\t\t\t\t.isEqualTo(\"Three\")));\n\t}\n\n\t@Test\n\tvoid postToRequestMapping() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Three\")));\n\t}\n\n\t@Test\n\tvoid postToRequestMappingWithReadOnlyAccessRespondsWith405() {\n\t\tthis.contextRunner.withPropertyValues(\"endpoint-access=READ_ONLY\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.post()\n\t\t\t\t.uri(\"/actuator/example/three\")\n\t\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.METHOD_NOT_ALLOWED)));\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> withWebTestClient(Consumer<WebTestClient> webClient) {\n\t\treturn (context) -> {\n\t\t\tint port = ((AnnotationConfigServletWebServerApplicationContext) context.getSourceApplicationContext())\n\t\t\t\t.getWebServer()\n\t\t\t\t.getPort();\n\t\t\tWebTestClient webTestClient = createWebTestClient(port);\n\t\t\twebClient.accept(webTestClient);\n\t\t};\n\t}\n\n\tprivate WebTestClient createWebTestClient(int port) {\n\t\tDefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(\"http://localhost:\" + port);\n\t\turiBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.uriBuilderFactory(uriBuilderFactory)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class })\n\tstatic class EndpointConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tControllerEndpointDiscoverer webEndpointDiscoverer(ApplicationContext applicationContext) {\n\t\t\treturn new ControllerEndpointDiscoverer(applicationContext, null, Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tControllerEndpointHandlerMapping webEndpointHandlerMapping(ControllerEndpointsSupplier endpointsSupplier,\n\t\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\t\treturn new ControllerEndpointHandlerMapping(new EndpointMapping(\"actuator\"),\n\t\t\t\t\tendpointsSupplier.getEndpoints(), null, endpointAccessResolver);\n\t\t}\n\n\t\t@Bean\n\t\tEndpointAccessResolver endpointAccessResolver(Environment environment) {\n\t\t\treturn (id, defaultAccess) -> environment.getProperty(\"endpoint-access\", Access.class, Access.UNRESTRICTED);\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t}\n\n\t@RestControllerEndpoint(id = \"example\")\n\tstatic class ExampleMvcEndpoint {\n\n\t\t@GetMapping(path = \"one\", produces = MediaType.TEXT_PLAIN_VALUE)\n\t\tString one() {\n\t\t\treturn \"One\";\n\t\t}\n\n\t\t@PostMapping(\"/two\")\n\t\tResponseEntity<String> two(@RequestBody Map<String, Object> content) {\n\t\t\treturn ResponseEntity.created(URI.create(\"/example/\" + content.get(\"id\"))).build();\n\t\t}\n\n\t\t@RequestMapping(path = \"/three\", produces = MediaType.TEXT_PLAIN_VALUE)\n\t\tString three() {\n\t\t\treturn \"Three\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/MvcWebEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.servlet;\n\nimport java.io.IOException;\nimport java.util.Arrays;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.annotation.AbstractWebEndpointIntegrationTests;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.context.SecurityContext;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for web endpoints exposed using Spring MVC.\n *\n * @author Andy Wilkinson\n * @see WebMvcEndpointHandlerMapping\n */\nclass MvcWebEndpointIntegrationTests\n\t\textends AbstractWebEndpointIntegrationTests<AnnotationConfigServletWebServerApplicationContext> {\n\n\tMvcWebEndpointIntegrationTests() {\n\t\tsuper(MvcWebEndpointIntegrationTests::createApplicationContext,\n\t\t\t\tMvcWebEndpointIntegrationTests::applyAuthenticatedConfiguration);\n\t}\n\n\tprivate static AnnotationConfigServletWebServerApplicationContext createApplicationContext() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tcontext.register(WebMvcConfiguration.class);\n\t\treturn context;\n\t}\n\n\tprivate static void applyAuthenticatedConfiguration(AnnotationConfigServletWebServerApplicationContext context) {\n\t\tcontext.register(AuthenticatedConfiguration.class);\n\t}\n\n\t@Test\n\tvoid responseToOptionsRequestIncludesCorsHeaders() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.options()\n\t\t\t\t\t.uri(\"/test\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Access-Control-Request-Method\", \"POST\")\n\t\t\t\t\t.header(\"Origin\", \"https://example.com\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueEquals(\"Access-Control-Allow-Origin\", \"https://example.com\")\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueEquals(\"Access-Control-Allow-Methods\", \"GET,POST\"));\n\t}\n\n\t@Test\n\tvoid readOperationsThatReturnAResourceSupportRangeRequests() {\n\t\tload(ResourceEndpointConfiguration.class, (client) -> {\n\t\t\tbyte[] responseBody = client.get()\n\t\t\t\t.uri(\"/resource\")\n\t\t\t\t.header(\"Range\", \"bytes=0-3\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.PARTIAL_CONTENT)\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(MediaType.APPLICATION_OCTET_STREAM)\n\t\t\t\t.returnResult(byte[].class)\n\t\t\t\t.getResponseBodyContent();\n\t\t\tassertThat(responseBody).containsExactly(0, 1, 2, 3);\n\t\t});\n\t}\n\n\t@Test\n\tvoid requestWithSuffixShouldNotMatch() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.options()\n\t\t\t\t\t.uri(\"/test.do\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isNotFound());\n\t}\n\n\t@Override\n\tprotected int getPort(AnnotationConfigServletWebServerApplicationContext context) {\n\t\treturn context.getWebServer().getPort();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tTomcatServletWebServerAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tDispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class })\n\tstatic class WebMvcConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tWebMvcEndpointHandlerMapping webEndpointHandlerMapping(Environment environment,\n\t\t\t\tWebEndpointDiscoverer endpointDiscoverer, EndpointMediaTypes endpointMediaTypes) {\n\t\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\t\tcorsConfiguration.setAllowedOrigins(Arrays.asList(\"https://example.com\"));\n\t\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(\"GET\", \"POST\"));\n\t\t\tString endpointPath = environment.getProperty(\"endpointPath\");\n\t\t\treturn new WebMvcEndpointHandlerMapping(new EndpointMapping(endpointPath),\n\t\t\t\t\tendpointDiscoverer.getEndpoints(), endpointMediaTypes, corsConfiguration,\n\t\t\t\t\tnew EndpointLinksResolver(endpointDiscoverer.getEndpoints()), StringUtils.hasText(endpointPath));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tTomcatServletWebServerAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tDispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class })\n\tstatic class PathMatcherWebMvcConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tWebMvcEndpointHandlerMapping webEndpointHandlerMapping(Environment environment,\n\t\t\t\tWebEndpointDiscoverer endpointDiscoverer, EndpointMediaTypes endpointMediaTypes) {\n\t\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\t\tcorsConfiguration.setAllowedOrigins(Arrays.asList(\"https://example.com\"));\n\t\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(\"GET\", \"POST\"));\n\t\t\tString endpointPath = environment.getProperty(\"endpointPath\");\n\t\t\tWebMvcEndpointHandlerMapping handlerMapping = new WebMvcEndpointHandlerMapping(\n\t\t\t\t\tnew EndpointMapping(endpointPath), endpointDiscoverer.getEndpoints(), endpointMediaTypes,\n\t\t\t\t\tcorsConfiguration, new EndpointLinksResolver(endpointDiscoverer.getEndpoints()),\n\t\t\t\t\tStringUtils.hasText(endpointPath));\n\t\t\treturn handlerMapping;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuthenticatedConfiguration {\n\n\t\t@Bean\n\t\tFilter securityFilter() {\n\t\t\treturn new OncePerRequestFilter() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\t\t\tFilterChain filterChain) throws ServletException, IOException {\n\t\t\t\t\tSecurityContext context = SecurityContextHolder.createEmptyContext();\n\t\t\t\t\tcontext.setAuthentication(new UsernamePasswordAuthenticationToken(\"Alice\", \"secret\",\n\t\t\t\t\t\t\tArrays.asList(new SimpleGrantedAuthority(\"ROLE_ACTUATOR\"))));\n\t\t\t\t\tSecurityContextHolder.setContext(context);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfilterChain.doFilter(new SecurityContextHolderAwareRequestWrapper(request, \"ROLE_\"), response);\n\t\t\t\t\t}\n\t\t\t\t\tfinally {\n\t\t\t\t\t\tSecurityContextHolder.clearContext();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.env;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nclass EnvironmentEndpointWebIntegrationTests {\n\n\tprivate ConfigurableApplicationContext context;\n\n\tprivate WebTestClient client;\n\n\t@BeforeEach\n\tvoid prepareEnvironment(ConfigurableApplicationContext context, WebTestClient client) {\n\t\tTestPropertyValues.of(\"foo:bar\", \"fool:baz\").applyTo(context);\n\t\tthis.client = client;\n\t\tthis.context = context;\n\t}\n\n\t@WebEndpointTest\n\tvoid home() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/env\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"propertySources[?(@.name=='systemProperties')]\")\n\t\t\t.exists();\n\t}\n\n\t@WebEndpointTest\n\tvoid sub() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/env/foo\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"property.source\")\n\t\t\t.isEqualTo(\"test\")\n\t\t\t.jsonPath(\"property.value\")\n\t\t\t.isEqualTo(\"bar\");\n\t}\n\n\t@WebEndpointTest\n\tvoid regex() {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tmap.put(\"food\", null);\n\t\tthis.context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(\"null-value\", map));\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/env?pattern=foo.*\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(forProperty(\"test\", \"foo\"))\n\t\t\t.isEqualTo(\"bar\")\n\t\t\t.jsonPath(forProperty(\"test\", \"fool\"))\n\t\t\t.isEqualTo(\"baz\");\n\t}\n\n\t@WebEndpointTest\n\tvoid nestedPathWhenPlaceholderCannotBeResolvedShouldReturnUnresolvedProperty() {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tmap.put(\"my.foo\", \"${my.bar}\");\n\t\tthis.context.getEnvironment()\n\t\t\t.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"unresolved-placeholder\", map));\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/env/my.foo\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"property.value\")\n\t\t\t.isEqualTo(\"${my.bar}\")\n\t\t\t.jsonPath(forPropertyEntry(\"unresolved-placeholder\"))\n\t\t\t.isEqualTo(\"${my.bar}\");\n\t}\n\n\t@WebEndpointTest\n\tvoid nestedPathForUnknownKeyShouldReturn404() {\n\t\tthis.client.get().uri(\"/actuator/env/this.does.not.exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid nestedPathMatchedByRegexWhenPlaceholderCannotBeResolvedShouldReturnUnresolvedProperty() {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tmap.put(\"my.foo\", \"${my.bar}\");\n\t\tthis.context.getEnvironment()\n\t\t\t.getPropertySources()\n\t\t\t.addFirst(new MapPropertySource(\"unresolved-placeholder\", map));\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/env?pattern=my.*\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"propertySources[?(@.name=='unresolved-placeholder')].properties.['my.foo'].value\")\n\t\t\t.isEqualTo(\"${my.bar}\");\n\t}\n\n\tprivate String forProperty(String source, String name) {\n\t\treturn \"propertySources[?(@.name=='\" + source + \"')].properties.['\" + name + \"'].value\";\n\t}\n\n\tprivate String forPropertyEntry(String source) {\n\t\treturn \"propertySources[?(@.name=='\" + source + \"')].property.value\";\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tEnvironmentEndpoint endpoint(Environment environment) {\n\t\t\treturn new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\tEnvironmentEndpointWebExtension environmentEndpointWebExtension(EnvironmentEndpoint endpoint) {\n\t\t\treturn new EnvironmentEndpointWebExtension(endpoint, Show.ALWAYS, Collections.emptySet());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.health;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.assertj.core.api.ThrowableAssert.ThrowingCallable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorNameGenerator;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Integration tests for {@link HealthEndpoint} and {@link HealthEndpointWebExtension}\n * exposed by Jersey, Spring MVC, and WebFlux.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass HealthEndpointWebIntegrationTests {\n\n\tprivate static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\t@WebEndpointTest\n\tvoid whenHealthIsUp200ResponseIsReturned(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.alpha.status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.bravo.status\")\n\t\t\t.isEqualTo(\"UP\");\n\t}\n\n\t@WebEndpointTest\n\tvoid whenHealthIsUpAndAcceptsV3Request200ResponseIsReturned(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.headers((headers) -> headers.set(HttpHeaders.ACCEPT, V3_JSON))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.alpha.status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.bravo.status\")\n\t\t\t.isEqualTo(\"UP\");\n\t}\n\n\t@WebEndpointTest\n\tvoid whenHealthIsUpAndAcceptsAllRequest200ResponseIsReturned(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.headers((headers) -> headers.set(HttpHeaders.ACCEPT, \"*/*\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.alpha.status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.bravo.status\")\n\t\t\t.isEqualTo(\"UP\");\n\t}\n\n\t@WebEndpointTest\n\tvoid whenHealthIsUpAndV2Request200ResponseIsReturnedInV2Format(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.headers((headers) -> headers.set(HttpHeaders.ACCEPT, V2_JSON))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"details.alpha.status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"details.bravo.status\")\n\t\t\t.isEqualTo(\"UP\");\n\t}\n\n\t@WebEndpointTest\n\tvoid whenHealthIsDown503ResponseIsReturned(ApplicationContext context, WebTestClient client) {\n\t\tHealthIndicator healthIndicator = () -> Health.down().build();\n\t\tReactiveHealthIndicator reactiveHealthIndicator = () -> Mono.just(Health.down().build());\n\t\twithHealthContributor(context, \"charlie\", healthIndicator, reactiveHealthIndicator,\n\t\t\t\t() -> client.get()\n\t\t\t\t\t.uri(\"/actuator/health\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"DOWN\")\n\t\t\t\t\t.jsonPath(\"components.alpha.status\")\n\t\t\t\t\t.isEqualTo(\"UP\")\n\t\t\t\t\t.jsonPath(\"components.bravo.status\")\n\t\t\t\t\t.isEqualTo(\"UP\")\n\t\t\t\t\t.jsonPath(\"components.charlie.status\")\n\t\t\t\t\t.isEqualTo(\"DOWN\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid whenComponentHealthIsDown503ResponseIsReturned(ApplicationContext context, WebTestClient client) {\n\t\tHealthIndicator healthIndicator = () -> Health.down().build();\n\t\tReactiveHealthIndicator reactiveHealthIndicator = () -> Mono.just(Health.down().build());\n\t\twithHealthContributor(context, \"charlie\", healthIndicator, reactiveHealthIndicator,\n\t\t\t\t() -> client.get()\n\t\t\t\t\t.uri(\"/actuator/health/charlie\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"DOWN\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid whenComponentInstanceHealthIsDown503ResponseIsReturned(ApplicationContext context, WebTestClient client) {\n\t\tHealthIndicator healthIndicator = () -> Health.down().build();\n\t\tCompositeHealthContributor composite = CompositeHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"one\", healthIndicator));\n\t\tReactiveHealthIndicator reactiveHealthIndicator = () -> Mono.just(Health.down().build());\n\t\tCompositeReactiveHealthContributor reactiveComposite = CompositeReactiveHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"one\", reactiveHealthIndicator));\n\t\twithHealthContributor(context, \"charlie\", composite, reactiveComposite,\n\t\t\t\t() -> client.get()\n\t\t\t\t\t.uri(\"/actuator/health/charlie/one\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"DOWN\"));\n\t}\n\n\tprivate void withHealthContributor(ApplicationContext context, String name, HealthContributor healthContributor,\n\t\t\tReactiveHealthContributor reactiveHealthContributor, ThrowingCallable callable) {\n\t\tHealthContributorRegistry healthContributorRegistry = getContributorRegistry(context,\n\t\t\t\tHealthContributorRegistry.class);\n\t\thealthContributorRegistry.registerContributor(name, healthContributor);\n\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry = getContributorRegistry(context,\n\t\t\t\tReactiveHealthContributorRegistry.class);\n\t\tif (reactiveHealthContributorRegistry != null) {\n\t\t\treactiveHealthContributorRegistry.registerContributor(name, reactiveHealthContributor);\n\t\t}\n\t\ttry {\n\t\t\tcallable.call();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tReflectionUtils.rethrowRuntimeException(ex);\n\t\t}\n\t\tfinally {\n\t\t\thealthContributorRegistry.unregisterContributor(name);\n\t\t\tif (reactiveHealthContributorRegistry != null) {\n\t\t\t\treactiveHealthContributorRegistry.unregisterContributor(name);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate <R> R getContributorRegistry(ApplicationContext context, Class<R> registryType) {\n\t\treturn context.getBeanProvider(registryType).getIfAvailable();\n\t}\n\n\t@WebEndpointTest\n\tvoid whenHealthIndicatorIsRemovedResponseIsAltered(WebTestClient client, ApplicationContext context) {\n\t\tString name = \"bravo\";\n\t\tHealthContributorRegistry healthContributorRegistry = getContributorRegistry(context,\n\t\t\t\tHealthContributorRegistry.class);\n\t\tHealthContributor bravo = healthContributorRegistry.unregisterContributor(name);\n\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry = getContributorRegistry(context,\n\t\t\t\tReactiveHealthContributorRegistry.class);\n\t\tReactiveHealthContributor reactiveBravo = (reactiveHealthContributorRegistry != null)\n\t\t\t\t? reactiveHealthContributorRegistry.unregisterContributor(name) : null;\n\t\ttry {\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/actuator/health\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"UP\")\n\t\t\t\t.jsonPath(\"components.alpha.status\")\n\t\t\t\t.isEqualTo(\"UP\")\n\t\t\t\t.jsonPath(\"components.bravo.status\")\n\t\t\t\t.doesNotExist();\n\t\t}\n\t\tfinally {\n\t\t\thealthContributorRegistry.registerContributor(name, bravo);\n\t\t\tif (reactiveHealthContributorRegistry != null && reactiveBravo != null) {\n\t\t\t\treactiveHealthContributorRegistry.registerContributor(name, reactiveBravo);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tHealthContributorRegistry healthContributorRegistry(Map<String, HealthContributor> contributorBeans) {\n\t\t\treturn new DefaultHealthContributorRegistry(null,\n\t\t\t\t\tHealthContributorNameGenerator.withoutStandardSuffixes().registrar(contributorBeans));\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry(\n\t\t\t\tMap<String, ReactiveHealthContributor> contributorBeans) {\n\t\t\treturn new DefaultReactiveHealthContributorRegistry(null,\n\t\t\t\t\tHealthContributorNameGenerator.withoutStandardSuffixes().registrar(contributorBeans));\n\t\t}\n\n\t\t@Bean\n\t\tHealthEndpoint healthEndpoint(HealthContributorRegistry healthContributorRegistry,\n\t\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,\n\t\t\t\tHealthEndpointGroups healthEndpointGroups) {\n\t\t\treturn new HealthEndpoint(healthContributorRegistry, reactiveHealthContributorRegistry.getIfAvailable(),\n\t\t\t\t\thealthEndpointGroups, null);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\t\tHealthEndpointWebExtension healthWebEndpointExtension(HealthContributorRegistry healthContributorRegistry,\n\t\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,\n\t\t\t\tHealthEndpointGroups healthEndpointGroups) {\n\t\t\treturn new HealthEndpointWebExtension(healthContributorRegistry,\n\t\t\t\t\treactiveHealthContributorRegistry.getIfAvailable(), healthEndpointGroups, null);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t\tReactiveHealthEndpointWebExtension reactiveHealthWebEndpointExtension(\n\t\t\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry,\n\t\t\t\tObjectProvider<HealthContributorRegistry> healthContributorRegistry,\n\t\t\t\tHealthEndpointGroups healthEndpointGroups) {\n\t\t\treturn new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry,\n\t\t\t\t\thealthContributorRegistry.getIfAvailable(), healthEndpointGroups, null);\n\t\t}\n\n\t\t@Bean\n\t\tHealthEndpointGroups healthEndpointGroups() {\n\t\t\tTestHealthEndpointGroup primary = new TestHealthEndpointGroup();\n\t\t\tTestHealthEndpointGroup allTheAs = new TestHealthEndpointGroup((name) -> name.startsWith(\"a\"));\n\t\t\treturn HealthEndpointGroups.of(primary, Collections.singletonMap(\"alltheas\", allTheAs));\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator alphaHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator bravoHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/health/TestHealthEndpointGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.health;\n\nimport java.util.function.Predicate;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\n\n/**\n * Test implementation of {@link HealthEndpointGroups}.\n *\n * @author Phillip Webb\n */\nclass TestHealthEndpointGroup implements HealthEndpointGroup {\n\n\tprivate final StatusAggregator statusAggregator = StatusAggregator.getDefault();\n\n\tprivate final HttpCodeStatusMapper httpCodeStatusMapper = HttpCodeStatusMapper.getDefault();\n\n\tprivate final Predicate<String> memberPredicate;\n\n\tprivate Boolean showComponents;\n\n\tprivate boolean showDetails = true;\n\n\tprivate AdditionalHealthEndpointPath additionalPath;\n\n\tTestHealthEndpointGroup() {\n\t\tthis((name) -> true);\n\t}\n\n\tTestHealthEndpointGroup(Predicate<String> memberPredicate) {\n\t\tthis.memberPredicate = memberPredicate;\n\t}\n\n\t@Override\n\tpublic boolean isMember(String name) {\n\t\treturn this.memberPredicate.test(name);\n\t}\n\n\t@Override\n\tpublic boolean showComponents(SecurityContext securityContext) {\n\t\treturn (this.showComponents != null) ? this.showComponents : this.showDetails;\n\t}\n\n\tvoid setShowComponents(Boolean showComponents) {\n\t\tthis.showComponents = showComponents;\n\t}\n\n\t@Override\n\tpublic boolean showDetails(SecurityContext securityContext) {\n\t\treturn this.showDetails;\n\t}\n\n\tvoid setShowDetails(boolean includeDetails) {\n\t\tthis.showDetails = includeDetails;\n\t}\n\n\t@Override\n\tpublic StatusAggregator getStatusAggregator() {\n\t\treturn this.statusAggregator;\n\t}\n\n\t@Override\n\tpublic HttpCodeStatusMapper getHttpCodeStatusMapper() {\n\t\treturn this.httpCodeStatusMapper;\n\t}\n\n\t@Override\n\tpublic AdditionalHealthEndpointPath getAdditionalPath() {\n\t\treturn this.additionalPath;\n\t}\n\n\tvoid setAdditionalPath(AdditionalHealthEndpointPath additionalPath) {\n\t\tthis.additionalPath = additionalPath;\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/info/InfoEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link InfoEndpoint} exposed by Jersey, Spring MVC, and WebFlux.\n *\n * @author Meang Akira Tanaka\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = { \"info.app.name=MyService\" })\nclass InfoEndpointWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid info(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/info\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"beanName1.key11\")\n\t\t\t.isEqualTo(\"value11\")\n\t\t\t.jsonPath(\"beanName1.key12\")\n\t\t\t.isEqualTo(\"value12\")\n\t\t\t.jsonPath(\"beanName2.key21\")\n\t\t\t.isEqualTo(\"value21\")\n\t\t\t.jsonPath(\"beanName2.key22\")\n\t\t\t.isEqualTo(\"value22\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tInfoEndpoint endpoint(ObjectProvider<InfoContributor> infoContributors) {\n\t\t\treturn new InfoEndpoint(infoContributors.orderedStream().toList());\n\t\t}\n\n\t\t@Bean\n\t\tInfoContributor beanName1() {\n\t\t\treturn (builder) -> {\n\t\t\t\tMap<String, Object> content = new LinkedHashMap<>();\n\t\t\t\tcontent.put(\"key11\", \"value11\");\n\t\t\t\tcontent.put(\"key12\", \"value12\");\n\t\t\t\tbuilder.withDetail(\"beanName1\", content);\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tInfoContributor beanName2() {\n\t\t\treturn (builder) -> {\n\t\t\t\tMap<String, Object> content = new LinkedHashMap<>();\n\t\t\t\tcontent.put(\"key21\", \"value21\");\n\t\t\t\tcontent.put(\"key22\", \"value22\");\n\t\t\t\tbuilder.withDetail(\"beanName2\", content);\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/logging/LogFileWebEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.logging;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * Integration tests for {@link LogFileWebEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Andy Wilkinson\n */\nclass LogFileWebEndpointWebIntegrationTests {\n\n\tprivate WebTestClient client;\n\n\tprivate static File tempFile;\n\n\t@BeforeEach\n\tvoid setUp(WebTestClient client) {\n\t\tthis.client = client;\n\t}\n\n\t@BeforeAll\n\tstatic void setup(@TempDir File temp) {\n\t\ttempFile = temp;\n\t}\n\n\t@WebEndpointTest\n\tvoid getRequestProducesResponseWithLogFile() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/logfile\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(\"text/plain; charset=UTF-8\")\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"--TEST--\");\n\t}\n\n\t@WebEndpointTest\n\tvoid getRequestThatAcceptsTextPlainProducesResponseWithLogFile() {\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/logfile\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(\"text/plain; charset=UTF-8\")\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"--TEST--\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tLogFileWebEndpoint logFileEndpoint() throws IOException {\n\t\t\tFile logFile = new File(tempFile, \"test.log\");\n\t\t\tFileCopyUtils.copy(\"--TEST--\".getBytes(), logFile);\n\t\t\tMockEnvironment environment = new MockEnvironment();\n\t\t\tenvironment.setProperty(\"logging.file.name\", logFile.getAbsolutePath());\n\t\t\treturn new LogFileWebEndpoint(LogFile.get(environment), null);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/logging/LoggersEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.logging;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport net.minidev.json.JSONArray;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.mockito.Mockito;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link LoggersEndpoint} when exposed over Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Ben Hale\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author HaiTao Zhang\n * @author Madhura Bhave\n */\nclass LoggersEndpointWebIntegrationTests {\n\n\tprivate static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\tprivate static final ParameterizedTypeReference<List<String>> STRING_LIST = new ParameterizedTypeReference<>() {\n\t};\n\n\tprivate WebTestClient client;\n\n\tprivate LoggingSystem loggingSystem;\n\n\tprivate LoggerGroups loggerGroups;\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid resetMocks(ConfigurableApplicationContext context, WebTestClient client) {\n\t\tthis.client = client;\n\t\tthis.loggingSystem = context.getBean(LoggingSystem.class);\n\t\tthis.loggerGroups = context.getBean(LoggerGroups.class);\n\t\tMockito.reset(this.loggingSystem);\n\t\tgiven(this.loggingSystem.getSupportedLogLevels()).willReturn(EnumSet.allOf(LogLevel.class));\n\t}\n\n\t@WebEndpointTest\n\tvoid getLoggerShouldReturnAllLoggerConfigurationsWithLoggerGroups() {\n\t\tsetLogLevelToDebug(\"test\");\n\t\tgiven(this.loggingSystem.getLoggerConfigurations())\n\t\t\t.willReturn(Collections.singletonList(new LoggerConfiguration(\"ROOT\", null, LogLevel.DEBUG)));\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/loggers\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.length()\")\n\t\t\t.isEqualTo(3)\n\t\t\t.jsonPath(\"levels\")\n\t\t\t.isEqualTo(jsonArrayOf(\"OFF\", \"FATAL\", \"ERROR\", \"WARN\", \"INFO\", \"DEBUG\", \"TRACE\"))\n\t\t\t.jsonPath(\"loggers.length()\")\n\t\t\t.isEqualTo(1)\n\t\t\t.jsonPath(\"loggers.ROOT.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"loggers.ROOT.configuredLevel\")\n\t\t\t.isEqualTo(null)\n\t\t\t.jsonPath(\"loggers.ROOT.effectiveLevel\")\n\t\t\t.isEqualTo(\"DEBUG\")\n\t\t\t.jsonPath(\"groups.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"groups.test.configuredLevel\")\n\t\t\t.isEqualTo(\"DEBUG\");\n\t}\n\n\t@WebEndpointTest\n\tvoid getLoggerShouldReturnLogLevels() {\n\t\tsetLogLevelToDebug(\"test\");\n\t\tgiven(this.loggingSystem.getLoggerConfiguration(\"ROOT\"))\n\t\t\t.willReturn(new LoggerConfiguration(\"ROOT\", null, LogLevel.DEBUG));\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"configuredLevel\")\n\t\t\t.isEqualTo(null)\n\t\t\t.jsonPath(\"effectiveLevel\")\n\t\t\t.isEqualTo(\"DEBUG\");\n\t}\n\n\t@WebEndpointTest\n\tvoid getLoggersWhenLoggerAndLoggerGroupNotFoundShouldReturnNotFound() {\n\t\tthis.client.get().uri(\"/actuator/loggers/com.does.not.exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid getLoggerGroupShouldReturnConfiguredLogLevelAndMembers() {\n\t\tsetLogLevelToDebug(\"test\");\n\t\tthis.client.get()\n\t\t\t.uri(\"actuator/loggers/test\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"members\")\n\t\t\t.value(STRING_LIST,\n\t\t\t\t\t(members) -> assertThat(members).containsExactlyInAnyOrder(\"test.member1\", \"test.member2\"))\n\t\t\t.jsonPath(\"configuredLevel\")\n\t\t\t.isEqualTo(\"DEBUG\");\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerUsingApplicationJsonShouldSetLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", \"debug\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", LogLevel.DEBUG);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerUsingActuatorV2JsonShouldSetLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.contentType(MediaType.parseMediaType(V2_JSON))\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", \"debug\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", LogLevel.DEBUG);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerUsingActuatorV3JsonShouldSetLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.contentType(MediaType.parseMediaType(V3_JSON))\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", \"debug\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", LogLevel.DEBUG);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerGroupUsingActuatorV2JsonShouldSetLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/test\")\n\t\t\t.contentType(MediaType.parseMediaType(V2_JSON))\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", \"debug\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member1\", LogLevel.DEBUG);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member2\", LogLevel.DEBUG);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerGroupUsingApplicationJsonShouldSetLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/test\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", \"debug\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member1\", LogLevel.DEBUG);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member2\", LogLevel.DEBUG);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerOrLoggerGroupWithWrongLogLevelResultInBadRequestResponse() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", \"other\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isBadRequest();\n\t\tthen(this.loggingSystem).shouldHaveNoInteractions();\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerWithNullLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.contentType(MediaType.parseMediaType(V3_JSON))\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", null))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", null);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerWithNoLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/ROOT\")\n\t\t\t.contentType(MediaType.parseMediaType(V3_JSON))\n\t\t\t.bodyValue(Collections.emptyMap())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", null);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerGroupWithNullLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/test\")\n\t\t\t.contentType(MediaType.parseMediaType(V3_JSON))\n\t\t\t.bodyValue(Collections.singletonMap(\"configuredLevel\", null))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member1\", null);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member2\", null);\n\t}\n\n\t@WebEndpointTest\n\tvoid setLoggerGroupWithNoLogLevel() {\n\t\tthis.client.post()\n\t\t\t.uri(\"/actuator/loggers/test\")\n\t\t\t.contentType(MediaType.parseMediaType(V3_JSON))\n\t\t\t.bodyValue(Collections.emptyMap())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member1\", null);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member2\", null);\n\t}\n\n\t@WebEndpointTest\n\tvoid logLevelForLoggerWithNameThatCouldBeMistakenForAPathExtension() {\n\t\tgiven(this.loggingSystem.getLoggerConfiguration(\"com.png\"))\n\t\t\t.willReturn(new LoggerConfiguration(\"com.png\", null, LogLevel.DEBUG));\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/loggers/com.png\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"configuredLevel\")\n\t\t\t.isEqualTo(null)\n\t\t\t.jsonPath(\"effectiveLevel\")\n\t\t\t.isEqualTo(\"DEBUG\");\n\t}\n\n\t@WebEndpointTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid logLevelForLoggerGroupWithNameThatCouldBeMistakenForAPathExtension() {\n\t\tsetLogLevelToDebug(\"group.png\");\n\t\tthis.client.get()\n\t\t\t.uri(\"/actuator/loggers/group.png\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"configuredLevel\")\n\t\t\t.isEqualTo(\"DEBUG\")\n\t\t\t.jsonPath(\"members\")\n\t\t\t.value(STRING_LIST,\n\t\t\t\t\t(members) -> assertThat(members).containsExactlyInAnyOrder(\"png.member1\", \"png.member2\"));\n\t}\n\n\tprivate void setLogLevelToDebug(String name) {\n\t\tthis.loggerGroups.get(name).configureLogLevel(LogLevel.DEBUG, (a, b) -> {\n\t\t});\n\t}\n\n\tprivate JSONArray jsonArrayOf(Object... entries) {\n\t\tJSONArray array = new JSONArray();\n\t\tarray.addAll(Arrays.asList(entries));\n\t\treturn array;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tLoggingSystem loggingSystem() {\n\t\t\treturn mock(LoggingSystem.class);\n\t\t}\n\n\t\t@Bean\n\t\tLoggerGroups loggingGroups() {\n\t\t\treturn getLoggerGroups();\n\t\t}\n\n\t\tprivate LoggerGroups getLoggerGroups() {\n\t\t\tMap<String, List<String>> groups = new LinkedHashMap<>();\n\t\t\tgroups.put(\"test\", Arrays.asList(\"test.member1\", \"test.member2\"));\n\t\t\tgroups.put(\"group.png\", Arrays.asList(\"png.member1\", \"png.member2\"));\n\t\t\treturn new LoggerGroups(groups);\n\t\t}\n\n\t\t@Bean\n\t\tLoggersEndpoint endpoint(LoggingSystem loggingSystem,\n\t\t\t\tObjectProvider<LoggerGroups> loggingGroupsObjectProvider) {\n\t\t\treturn new LoggersEndpoint(loggingSystem, loggingGroupsObjectProvider.getIfAvailable());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/management/HeapDumpWebEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.BeforeEach;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.hamcrest.Matchers.is;\n\n/**\n * Integration tests for {@link HeapDumpWebEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass HeapDumpWebEndpointWebIntegrationTests {\n\n\tprivate TestHeapDumpWebEndpoint endpoint;\n\n\t@BeforeEach\n\tvoid configureEndpoint(ApplicationContext context) {\n\t\tthis.endpoint = context.getBean(TestHeapDumpWebEndpoint.class);\n\t\tthis.endpoint.setAvailable(true);\n\t}\n\n\t@WebEndpointTest\n\tvoid invokeWhenNotAvailableShouldReturnServiceUnavailableStatus(WebTestClient client) {\n\t\tthis.endpoint.setAvailable(false);\n\t\tclient.get().uri(\"/actuator/heapdump\").exchange().expectStatus().isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);\n\t}\n\n\t@WebEndpointTest\n\tvoid getRequestShouldReturnHeapDumpInResponseBody(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/heapdump\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.APPLICATION_OCTET_STREAM)\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"HEAPDUMP\");\n\t\tassertHeapDumpFileIsDeleted();\n\t}\n\n\tprivate void assertHeapDumpFileIsDeleted() {\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(5)).until(this.endpoint.file::exists, is(false));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tHeapDumpWebEndpoint endpoint() {\n\t\t\treturn new TestHeapDumpWebEndpoint();\n\t\t}\n\n\t}\n\n\tstatic class TestHeapDumpWebEndpoint extends HeapDumpWebEndpoint {\n\n\t\tprivate boolean available;\n\n\t\tprivate final String heapDump = \"HEAPDUMP\";\n\n\t\tprivate File file;\n\n\t\tTestHeapDumpWebEndpoint() {\n\t\t\tsuper(TimeUnit.SECONDS.toMillis(1));\n\t\t\treset();\n\t\t}\n\n\t\tvoid reset() {\n\t\t\tthis.available = true;\n\t\t}\n\n\t\t@Override\n\t\tprotected HeapDumper createHeapDumper() {\n\t\t\treturn (live) -> {\n\t\t\t\tthis.file = Files.createTempFile(\"heap-\", \".dump\").toFile();\n\t\t\t\tif (!TestHeapDumpWebEndpoint.this.available) {\n\t\t\t\t\tthrow new HeapDumperUnavailableException(\"Not available\", null);\n\t\t\t\t}\n\t\t\t\tFileCopyUtils.copy(TestHeapDumpWebEndpoint.this.heapDump.getBytes(), this.file);\n\t\t\t\treturn this.file;\n\t\t\t};\n\t\t}\n\n\t\tvoid setAvailable(boolean available) {\n\t\t\tthis.available = available;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/management/ThreadDumpEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ThreadDumpEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Andy Wilkinson\n */\nclass ThreadDumpEndpointWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid getRequestWithJsonAcceptHeaderShouldProduceJsonThreadDumpResponse(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/threaddump\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.APPLICATION_JSON);\n\t}\n\n\t@WebEndpointTest\n\tvoid getRequestWithTextPlainAcceptHeaderShouldProduceTextPlainResponse(WebTestClient client) {\n\t\tString response = client.get()\n\t\t\t.uri(\"/actuator/threaddump\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(\"text/plain;charset=UTF-8\")\n\t\t\t.expectBody(String.class)\n\t\t\t.returnResult()\n\t\t\t.getResponseBody();\n\t\tassertThat(response).contains(\"Full thread dump\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class TestConfiguration {\n\n\t\t@Bean\n\t\tpublic ThreadDumpEndpoint endpoint() {\n\t\t\treturn new ThreadDumpEndpoint();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/metrics/MetricsEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.metrics;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.MockClock;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Web integration tests for {@link MetricsEndpoint}.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n */\nclass MetricsEndpointWebIntegrationTests {\n\n\tprivate static final MeterRegistry registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock());\n\n\tprivate final JsonMapper mapper = new JsonMapper();\n\n\t@WebEndpointTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid listNames(WebTestClient client) {\n\t\tString responseBody = client.get()\n\t\t\t.uri(\"/actuator/metrics\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.returnResult()\n\t\t\t.getResponseBody();\n\t\tMap<String, List<String>> names = this.mapper.readValue(responseBody, Map.class);\n\t\tassertThat(names.get(\"names\")).containsOnlyOnce(\"jvm.memory.used\");\n\t}\n\n\t@WebEndpointTest\n\tvoid selectByName(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/metrics/jvm.memory.used\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.name\")\n\t\t\t.isEqualTo(\"jvm.memory.used\");\n\t}\n\n\t@WebEndpointTest\n\tvoid selectByTag(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/metrics/jvm.memory.used?tag=id:Compressed%20Class%20Space\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.name\")\n\t\t\t.isEqualTo(\"jvm.memory.used\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tMeterRegistry registry() {\n\t\t\treturn registry;\n\t\t}\n\n\t\t@Bean\n\t\tMetricsEndpoint metricsEndpoint(MeterRegistry meterRegistry) {\n\t\t\treturn new MetricsEndpoint(meterRegistry);\n\t\t}\n\n\t\t@Bean\n\t\tJvmMemoryMetrics jvmMemoryMetrics(MeterRegistry meterRegistry) {\n\t\t\tJvmMemoryMetrics memoryMetrics = new JvmMemoryMetrics();\n\t\t\tmemoryMetrics.bindTo(meterRegistry);\n\t\t\treturn memoryMetrics;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/metrics/export/prometheus/PrometheusScrapeEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.metrics.export.prometheus;\n\nimport java.util.Properties;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Counter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;\nimport io.prometheus.metrics.expositionformats.PrometheusProtobufWriter;\nimport io.prometheus.metrics.expositionformats.PrometheusTextFormatWriter;\nimport io.prometheus.metrics.model.registry.PrometheusRegistry;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus.PrometheusScrapeEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PrometheusScrapeEndpoint}.\n *\n * @author Jon Schneider\n * @author Johnny Lim\n */\nclass PrometheusScrapeEndpointIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid scrapeHasContentTypeText004ByDefault(WebTestClient client) {\n\t\tString expectedContentType = PrometheusTextFormatWriter.CONTENT_TYPE;\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/prometheus\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(expectedContentType))\n\t\t\t.expectBody(String.class)\n\t\t\t.value((body) -> assertThat(body).contains(\"counter1_total\")\n\t\t\t\t.contains(\"counter2_total\")\n\t\t\t\t.contains(\"counter3_total\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid scrapeHasContentTypeText004ByDefaultWhenClientAcceptsWildcardWithParameter(WebTestClient client) {\n\t\tString expectedContentType = PrometheusTextFormatWriter.CONTENT_TYPE;\n\t\tString accept = \"*/*;q=0.8\";\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/prometheus\")\n\t\t\t.accept(MediaType.parseMediaType(accept))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(expectedContentType))\n\t\t\t.expectBody(String.class)\n\t\t\t.value((body) -> assertThat(body).contains(\"counter1_total\")\n\t\t\t\t.contains(\"counter2_total\")\n\t\t\t\t.contains(\"counter3_total\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid scrapeCanProduceOpenMetrics100(WebTestClient client) {\n\t\tMediaType openMetrics = MediaType.parseMediaType(OpenMetricsTextFormatWriter.CONTENT_TYPE);\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/prometheus\")\n\t\t\t.accept(openMetrics)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(openMetrics)\n\t\t\t.expectBody(String.class)\n\t\t\t.value((body) -> assertThat(body).contains(\"counter1_total\")\n\t\t\t\t.contains(\"counter2_total\")\n\t\t\t\t.contains(\"counter3_total\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid scrapePrefersToProduceOpenMetrics100(WebTestClient client) {\n\t\tMediaType openMetrics = MediaType.parseMediaType(OpenMetricsTextFormatWriter.CONTENT_TYPE);\n\t\tMediaType textPlain = MediaType.parseMediaType(PrometheusTextFormatWriter.CONTENT_TYPE);\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/prometheus\")\n\t\t\t.accept(openMetrics, textPlain)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(openMetrics);\n\t}\n\n\t@WebEndpointTest\n\tvoid scrapeWithIncludedNames(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/prometheus?includedNames=counter1,counter2\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(PrometheusTextFormatWriter.CONTENT_TYPE))\n\t\t\t.expectBody(String.class)\n\t\t\t.value((body) -> assertThat(body).contains(\"counter1_total\")\n\t\t\t\t.contains(\"counter2_total\")\n\t\t\t\t.doesNotContain(\"counter3_total\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid scrapeCanProducePrometheusProtobuf(WebTestClient client) {\n\t\tMediaType prometheusProtobuf = MediaType.parseMediaType(PrometheusProtobufWriter.CONTENT_TYPE);\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/prometheus\")\n\t\t\t.accept(prometheusProtobuf)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(prometheusProtobuf)\n\t\t\t.expectBody(byte[].class)\n\t\t\t.value((body) -> assertThat(body).isNotEmpty());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tPrometheusScrapeEndpoint prometheusScrapeEndpoint(PrometheusRegistry prometheusRegistry) {\n\t\t\treturn new PrometheusScrapeEndpoint(prometheusRegistry, new Properties());\n\t\t}\n\n\t\t@Bean\n\t\tPrometheusRegistry prometheusRegistry() {\n\t\t\treturn new PrometheusRegistry();\n\t\t}\n\n\t\t@Bean\n\t\tMeterRegistry registry(PrometheusRegistry prometheusRegistry) {\n\t\t\tPrometheusMeterRegistry meterRegistry = new PrometheusMeterRegistry((k) -> null, prometheusRegistry,\n\t\t\t\t\tClock.SYSTEM);\n\t\t\tCounter.builder(\"counter1\").register(meterRegistry);\n\t\t\tCounter.builder(\"counter2\").register(meterRegistry);\n\t\t\tCounter.builder(\"counter3\").register(meterRegistry);\n\t\t\treturn meterRegistry;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointCycloneDxWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link SbomEndpoint} exposed by Jersey, Spring MVC, and WebFlux\n * in CycloneDX format.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointCycloneDxWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid shouldReturnSbomContent(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/sbom/application\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(\"application/vnd.cyclonedx+json\"))\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.bomFormat\")\n\t\t\t.isEqualTo(\"CycloneDX\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSbomProperties sbomProperties() {\n\t\t\tSbomProperties properties = new SbomProperties();\n\t\t\tproperties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\t\treturn properties;\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpoint sbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader) {\n\t\t\treturn new SbomEndpoint(properties, resourceLoader);\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpointWebExtension sbomEndpointWebExtension(SbomEndpoint sbomEndpoint, SbomProperties properties) {\n\t\t\treturn new SbomEndpointWebExtension(sbomEndpoint, properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointSpdxWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link SbomEndpoint} exposed by Jersey, Spring MVC, and WebFlux\n * in SPDX format.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointSpdxWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid shouldReturnSbomContent(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/sbom/application\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(\"application/spdx+json\"))\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.spdxVersion\")\n\t\t\t.isEqualTo(\"SPDX-2.3\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSbomProperties sbomProperties() {\n\t\t\tSbomProperties properties = new SbomProperties();\n\t\t\tproperties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/spdx.json\");\n\t\t\treturn properties;\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpoint sbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader) {\n\t\t\treturn new SbomEndpoint(properties, resourceLoader);\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpointWebExtension sbomEndpointWebExtension(SbomEndpoint sbomEndpoint, SbomProperties properties) {\n\t\t\treturn new SbomEndpointWebExtension(sbomEndpoint, properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointSyftWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link SbomEndpoint} exposed by Jersey, Spring MVC, and WebFlux\n * in Syft format.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointSyftWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid shouldReturnSbomContent(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/sbom/application\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(\"application/vnd.syft+json\"))\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.descriptor.name\")\n\t\t\t.isEqualTo(\"syft\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSbomProperties sbomProperties() {\n\t\t\tSbomProperties properties = new SbomProperties();\n\t\t\tproperties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/syft.json\");\n\t\t\treturn properties;\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpoint sbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader) {\n\t\t\treturn new SbomEndpoint(properties, resourceLoader);\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpointWebExtension sbomEndpointWebExtension(SbomEndpoint sbomEndpoint, SbomProperties properties) {\n\t\t\treturn new SbomEndpointWebExtension(sbomEndpoint, properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport net.minidev.json.JSONArray;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SbomEndpoint} exposed by Jersey, Spring MVC, and WebFlux.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid shouldReturnSboms(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/sbom\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.parseMediaType(\"application/vnd.spring-boot.actuator.v3+json\"))\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$.ids\")\n\t\t\t.value((value) -> assertThat(value).isEqualTo(new JSONArray().appendElement(\"application\")));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSbomProperties sbomProperties() {\n\t\t\tSbomProperties properties = new SbomProperties();\n\t\t\tproperties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\t\treturn properties;\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpoint sbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader) {\n\t\t\treturn new SbomEndpoint(properties, resourceLoader);\n\t\t}\n\n\t\t@Bean\n\t\tSbomEndpointWebExtension sbomEndpointWebExtension(SbomEndpoint sbomEndpoint, SbomProperties properties) {\n\t\t\treturn new SbomEndpointWebExtension(sbomEndpoint, properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/java/org/springframework/boot/actuate/web/mappings/MappingsEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.mappings;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.FilterRegistration;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint.ApplicationMappingsDescriptor;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint.ContextMappingsDescriptor;\nimport org.springframework.boot.servlet.actuate.web.mappings.FilterRegistrationMappingDescription;\nimport org.springframework.boot.servlet.actuate.web.mappings.FiltersMappingDescriptionProvider;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletRegistrationMappingDescription;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletsMappingDescriptionProvider;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlerMappingDescription;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlersMappingDescriptionProvider;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletMappingDescription;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletsMappingDescriptionProvider;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.web.MockServletConfig;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.config.annotation.PathMatchConfigurer;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.function.RequestPredicates;\nimport org.springframework.web.servlet.function.RouterFunctions;\nimport org.springframework.web.util.pattern.PathPatternParser;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.GET;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.POST;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n/**\n * Integration tests for {@link MappingsEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Xiong Tang\n */\nclass MappingsEndpointIntegrationTests {\n\n\t@Test\n\tvoid servletWebMappings() {\n\t\tSupplier<ConfigurableWebApplicationContext> contextSupplier = prepareContextSupplier();\n\t\tnew WebApplicationContextRunner(contextSupplier)\n\t\t\t.withUserConfiguration(EndpointConfiguration.class, ServletWebConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tContextMappingsDescriptor contextMappings = contextMappings(context);\n\t\t\t\tassertThat(contextMappings.getParentId()).isNull();\n\t\t\t\tassertThat(contextMappings.getMappings()).containsOnlyKeys(\"dispatcherServlets\", \"servletFilters\",\n\t\t\t\t\t\t\"servlets\");\n\t\t\t\tMap<String, List<DispatcherServletMappingDescription>> dispatcherServlets = mappings(contextMappings,\n\t\t\t\t\t\t\"dispatcherServlets\");\n\t\t\t\tassertThat(dispatcherServlets).containsOnlyKeys(\"dispatcherServlet\");\n\t\t\t\tList<DispatcherServletMappingDescription> handlerMappings = dispatcherServlets.get(\"dispatcherServlet\");\n\t\t\t\tassertThat(handlerMappings).hasSize(4);\n\t\t\t\tList<ServletRegistrationMappingDescription> servlets = mappings(contextMappings, \"servlets\");\n\t\t\t\tassertThat(servlets).hasSize(1);\n\t\t\t\tList<FilterRegistrationMappingDescription> filters = mappings(contextMappings, \"servletFilters\");\n\t\t\t\tassertThat(filters).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid servletWebMappingsWithPathPatternParser() {\n\t\tSupplier<ConfigurableWebApplicationContext> contextSupplier = prepareContextSupplier();\n\t\tnew WebApplicationContextRunner(contextSupplier)\n\t\t\t.withUserConfiguration(EndpointConfiguration.class, ServletWebConfiguration.class,\n\t\t\t\t\tPathPatternParserConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tContextMappingsDescriptor contextMappings = contextMappings(context);\n\t\t\t\tassertThat(contextMappings.getParentId()).isNull();\n\t\t\t\tassertThat(contextMappings.getMappings()).containsOnlyKeys(\"dispatcherServlets\", \"servletFilters\",\n\t\t\t\t\t\t\"servlets\");\n\t\t\t\tMap<String, List<DispatcherServletMappingDescription>> dispatcherServlets = mappings(contextMappings,\n\t\t\t\t\t\t\"dispatcherServlets\");\n\t\t\t\tassertThat(dispatcherServlets).containsOnlyKeys(\"dispatcherServlet\");\n\t\t\t\tList<DispatcherServletMappingDescription> handlerMappings = dispatcherServlets.get(\"dispatcherServlet\");\n\t\t\t\tassertThat(handlerMappings).hasSize(4);\n\t\t\t\tList<ServletRegistrationMappingDescription> servlets = mappings(contextMappings, \"servlets\");\n\t\t\t\tassertThat(servlets).hasSize(1);\n\t\t\t\tList<FilterRegistrationMappingDescription> filters = mappings(contextMappings, \"servletFilters\");\n\t\t\t\tassertThat(filters).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid servletWebMappingsWithAdditionalDispatcherServlets() {\n\t\tSupplier<ConfigurableWebApplicationContext> contextSupplier = prepareContextSupplier();\n\t\tnew WebApplicationContextRunner(contextSupplier)\n\t\t\t.withUserConfiguration(EndpointConfiguration.class, ServletWebConfiguration.class,\n\t\t\t\t\tCustomDispatcherServletConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tContextMappingsDescriptor contextMappings = contextMappings(context);\n\t\t\t\tMap<String, List<DispatcherServletMappingDescription>> dispatcherServlets = mappings(contextMappings,\n\t\t\t\t\t\t\"dispatcherServlets\");\n\t\t\t\tassertThat(dispatcherServlets).containsOnlyKeys(\"dispatcherServlet\",\n\t\t\t\t\t\t\"customDispatcherServletRegistration\", \"anotherDispatcherServletRegistration\");\n\t\t\t\tassertThat(dispatcherServlets.get(\"dispatcherServlet\")).hasSize(4);\n\t\t\t\tassertThat(dispatcherServlets.get(\"customDispatcherServletRegistration\")).hasSize(4);\n\t\t\t\tassertThat(dispatcherServlets.get(\"anotherDispatcherServletRegistration\")).hasSize(4);\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Supplier<ConfigurableWebApplicationContext> prepareContextSupplier() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(Collections.emptyEnumeration());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\tFilterRegistration filterRegistration = mock(FilterRegistration.class);\n\t\tgiven((Map<String, FilterRegistration>) servletContext.getFilterRegistrations())\n\t\t\t.willReturn(Collections.singletonMap(\"testFilter\", filterRegistration));\n\t\tServletRegistration servletRegistration = mock(ServletRegistration.class);\n\t\tgiven((Map<String, ServletRegistration>) servletContext.getServletRegistrations())\n\t\t\t.willReturn(Collections.singletonMap(\"testServlet\", servletRegistration));\n\t\treturn () -> {\n\t\t\tAnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\t\t\tcontext.setServletContext(servletContext);\n\t\t\treturn context;\n\t\t};\n\t}\n\n\t@Test\n\tvoid reactiveWebMappings() {\n\t\tnew ReactiveWebApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfiguration.class, ReactiveWebConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tContextMappingsDescriptor contextMappings = contextMappings(context);\n\t\t\t\tassertThat(contextMappings.getParentId()).isNull();\n\t\t\t\tassertThat(contextMappings.getMappings()).containsOnlyKeys(\"dispatcherHandlers\");\n\t\t\t\tMap<String, List<DispatcherHandlerMappingDescription>> dispatcherHandlers = mappings(contextMappings,\n\t\t\t\t\t\t\"dispatcherHandlers\");\n\t\t\t\tassertThat(dispatcherHandlers).containsOnlyKeys(\"webHandler\");\n\t\t\t\tList<DispatcherHandlerMappingDescription> handlerMappings = dispatcherHandlers.get(\"webHandler\");\n\t\t\t\tassertThat(handlerMappings).hasSize(4);\n\t\t\t});\n\t}\n\n\tprivate ContextMappingsDescriptor contextMappings(ApplicationContext context) {\n\t\tApplicationMappingsDescriptor applicationMappings = context.getBean(MappingsEndpoint.class).mappings();\n\t\tassertThat(applicationMappings.getContexts()).containsOnlyKeys(context.getId());\n\t\treturn applicationMappings.getContexts().get(context.getId());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> T mappings(ContextMappingsDescriptor contextMappings, String key) {\n\t\treturn (T) contextMappings.getMappings().get(key);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfiguration {\n\n\t\t@Bean\n\t\tMappingsEndpoint mappingsEndpoint(Collection<MappingDescriptionProvider> descriptionProviders,\n\t\t\t\tApplicationContext context) {\n\t\t\treturn new MappingsEndpoint(descriptionProviders, context);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\t@Controller\n\tstatic class ReactiveWebConfiguration {\n\n\t\t@Bean\n\t\tDispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {\n\t\t\treturn new DispatcherHandlersMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> routerFunction() {\n\t\t\treturn route(GET(\"/one\"), (request) -> ServerResponse.ok().build()).andRoute(POST(\"/two\"),\n\t\t\t\t\t(request) -> ServerResponse.ok().build());\n\t\t}\n\n\t\t@RequestMapping(\"/three\")\n\t\tvoid three() {\n\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> routerFunctionWithAttributes() {\n\t\t\treturn route(GET(\"/four\"), (request) -> ServerResponse.ok().build()).withAttribute(\"test\", \"test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@Controller\n\tstatic class ServletWebConfiguration {\n\n\t\t@Bean\n\t\tDispatcherServletsMappingDescriptionProvider dispatcherServletsMappingDescriptionProvider() {\n\t\t\treturn new DispatcherServletsMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tServletsMappingDescriptionProvider servletsMappingDescriptionProvider() {\n\t\t\treturn new ServletsMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tFiltersMappingDescriptionProvider filtersMappingDescriptionProvider() {\n\t\t\treturn new FiltersMappingDescriptionProvider();\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet(WebApplicationContext context) throws ServletException {\n\t\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet(context);\n\t\t\tdispatcherServlet.init(new MockServletConfig());\n\t\t\treturn dispatcherServlet;\n\t\t}\n\n\t\t@Bean\n\t\torg.springframework.web.servlet.function.RouterFunction<org.springframework.web.servlet.function.ServerResponse> routerFunction() {\n\t\t\treturn RouterFunctions\n\t\t\t\t.route(RequestPredicates.GET(\"/one\"),\n\t\t\t\t\t\t(request) -> org.springframework.web.servlet.function.ServerResponse.ok().build())\n\t\t\t\t.andRoute(RequestPredicates.POST(\"/two\"),\n\t\t\t\t\t\t(request) -> org.springframework.web.servlet.function.ServerResponse.ok().build());\n\t\t}\n\n\t\t@RequestMapping(\"/three\")\n\t\tvoid three() {\n\n\t\t}\n\n\t\t@Bean\n\t\torg.springframework.web.servlet.function.RouterFunction<org.springframework.web.servlet.function.ServerResponse> routerFunctionWithAttributes() {\n\t\t\treturn RouterFunctions\n\t\t\t\t.route(RequestPredicates.GET(\"/four\"),\n\t\t\t\t\t\t(request) -> org.springframework.web.servlet.function.ServerResponse.ok().build())\n\t\t\t\t.withAttribute(\"test\", \"test\");\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CustomDispatcherServletConfiguration {\n\n\t\t@Bean\n\t\tServletRegistrationBean<DispatcherServlet> customDispatcherServletRegistration(WebApplicationContext context) {\n\t\t\tServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(\n\t\t\t\t\tcreateTestDispatcherServlet(context));\n\t\t\tregistration.setName(\"customDispatcherServletRegistration\");\n\t\t\treturn registration;\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet anotherDispatcherServlet(WebApplicationContext context) {\n\t\t\treturn createTestDispatcherServlet(context);\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<DispatcherServlet> anotherDispatcherServletRegistration(\n\t\t\t\tDispatcherServlet dispatcherServlet, WebApplicationContext context) {\n\t\t\tServletRegistrationBean<DispatcherServlet> registrationBean = new ServletRegistrationBean<>(\n\t\t\t\t\tanotherDispatcherServlet(context));\n\t\t\tregistrationBean.setName(\"anotherDispatcherServletRegistration\");\n\t\t\treturn registrationBean;\n\t\t}\n\n\t\tprivate DispatcherServlet createTestDispatcherServlet(WebApplicationContext context) {\n\t\t\ttry {\n\t\t\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet(context);\n\t\t\t\tdispatcherServlet.init(new MockServletConfig());\n\t\t\t\treturn dispatcherServlet;\n\t\t\t}\n\t\t\tcatch (ServletException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class PathPatternParserConfiguration {\n\n\t\t@Bean\n\t\tWebMvcConfigurer pathPatternParserConfigurer() {\n\t\t\treturn new WebMvcConfigurer() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void configurePathMatch(PathMatchConfigurer configurer) {\n\t\t\t\t\tconfigurer.setPatternParser(new PathPatternParser());\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/resources/org/springframework/boot/actuate/sbom/cyclonedx.json",
    "content": "{\n  \"bomFormat\" : \"CycloneDX\",\n  \"specVersion\" : \"1.5\",\n  \"serialNumber\" : \"urn:uuid:13862013-3360-43e5-8055-3645aa43c548\",\n  \"version\" : 1,\n  \"metadata\" : {\n    \"timestamp\" : \"2024-01-12T11:10:49Z\",\n    \"tools\" : [\n      {\n        \"vendor\" : \"CycloneDX\",\n        \"name\" : \"cyclonedx-gradle-plugin\",\n        \"version\" : \"1.8.1\"\n      }\n    ],\n    \"component\" : {\n      \"group\" : \"org.example\",\n      \"name\" : \"cyclonedx\",\n      \"version\" : \"0.0.1-SNAPSHOT\",\n      \"purl\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\"\n    }\n  },\n  \"components\" : [\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-aop\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring AOP\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c9b8757051ed6c1cc9fda0e379283348\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a247bd81df8fa9c6a002b95969692bfd146a70b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e47b66833ebec281374d55b4e36352b80fe3fa64c94252481a8a7e8d31d9d601\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1cb69feb2931bd4af48b2329614f8e2a0d1afe77267af5f5ea9717ab24c83fd524c8bc7aa8d357a6ccbc497535c4fd282ddfb6d78364a349895a14825af8b9c\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"09c3c2711a054993922d28b76357c376649a942bf0d7410915e540339c3fa42d5a498211b02e0b09493e68fac7a0d833\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b30a6ea50e454373bd74779d983fc941bb1775368ea67ff0464edbdf0dd3d1c137760bee64a620bd51daf5b65281f15e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"291404410acd2cfbcc804bd91a9777276f622fb3b82788298254c0bf1856b49f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8101ef2cc88af43b2bfc6126547de4e4a4cc29bf49bffd83aa9d299cab9e9cdb6a5246d46c00119dd88ca02dbf7959c3076dbd32d23e8e1366144ccbbda13316\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jdk8\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support JDK 8 data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3b6579ff944e128c4eccb34e76ff67e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"80158cb020c7bd4e4ba94d8d752a65729dc943b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"29995d3677f72dde74bf32bbf268b96beb952492b742d93f4c70af6c44b2156e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1b13d4f0a955af18a2c68ca45deca79c38d7f9f065d7053bddf2a3dc2fafe729b3355676f7442012451e363aa0da0cd8a0b7a44ded7057cf513df98a475cbbf6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a29961097a15d3aeabc1ab870699dce827511df9902fc66fe9f836d294c8cea68617498d52fe7dbe920bb5c745f2789\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"55570097f9979197eafda91156db909f25dd1b37387656893564060a673dcbc6d85c1f5dc6fd5c8b379b48a4974e6757\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"362c3a494e16016f7adc3f512ebe8c8f8da4dbdfc1ca285d05ac085a9198258f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1aebbe19a11236b7dbf85fd4c457e1a9b5a60fad9c818cc9fd462d7eb489dd5d3a378b4c7c42c6e3777e0b70263968c964cf1aaf8247fc97ec445481af2418a8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apiguardian\",\n      \"name\" : \"apiguardian-api\",\n      \"version\" : \"1.1.2\",\n      \"description\" : \"@API Guardian\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8c7de3f82037fa4a2e8be2a2f13092af\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a231e0d844d2721b0fa1b238006d15c6ded6842a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d7ccd0e7019f1a997de39d66dc0ad4efe150428fdd7f4c743c93884f1602a3e90135ad34baea96d5b6d925ad6c0c8487c8e78304f0a089a12383d4a62e2c9a61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ae11cfedcee7da43a506a67946ddc8a7a2622284a924ba78f74541e9a22db6868a15f5d84edb91a541e38afded734ea\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c146116b3dfd969200b2ce52d96b92dd02d6f5a45a86e7e85edf35600ddbc2f3c6e8a1ad7e2db4dcd2c398c09fad0927\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b4b436d7f615fc0b820204e69f83c517d1c1ccc5f6b99e459209ede4482268de\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7b95b7ac68a6891b8901b5507acd2c24a0c1e20effa63cd513764f513eab4eb55f8de5178edbe0a400c11f3a18d3f56243569d6d663100f06dd98288504c09c5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/apiguardian-team/apiguardian\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.annotation\",\n      \"name\" : \"jakarta.annotation-api\",\n      \"version\" : \"2.1.1\",\n      \"description\" : \"Jakarta Annotations API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5dac2f68e8288d0add4dc92cb161711d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5f65fdaf424eee2b55e1d882ba9bb376be93fb09b37b808be6e22e8851c909fe\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eabe8b855b735663684052ec4cc357cc737936fa57cebf144eb09f70b3b6c600db7fa6f1c93a4f36c5994b1b37dad2dfcec87a41448872e69552accfd7f52af6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"798597a6b80b423844d70609c54b00d725a357031888da7e5c3efd3914d1770be69aa7135de13ddb89a4420a5550e35b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9629b8ca82f61674f5573723bbb3c137060e1442062eb52fa9c90fc8f57ea7d836eb2fb765d160ec8bf300bcb6b820be\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f71ffc2a2c2bd1a00dfc00c4be67dbe5f374078bd50d5b24c0b29fbcc6634ecb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa4e29025a55878db6edb0d984bd3a0633f3af03fa69e1d26c97c87c6d29339714003c96e29ff0a977132ce9c2729d0e27e36e9e245a7488266138239bdba15e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"GPL-2.0-with-classpath-exception\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://dev.eclipse.org/mhonarc/lists/ca-dev\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-annotations\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core annotations used for value types, used by Jackson data binding package.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f478f693731e4a2f0f0d3c7bba119b32\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"79baf4e605eb3bbb60b1c475d44a7aecceea1d60\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"aae865c3d88256d61b11523cb1e88bd48d5b9ad5855fa1fc859504fd2204708a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c496afd736fa8acbf8126887e2ff375f162212f451326451fbb4b9194231d814e25bccacbaead9db98beec454f6b8d9ed706c5c88e2145bf7e1a37e13fd81af0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"13b4d153cc113a69008147974d8887f868f2f3f0a551ef0bacaccf0add17a3168465a94a471e075913f9c6649980a3cb\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"dcf8ed73f748eb32e1ab25eba3c294344cc0ddb2cc7bb4376814f1866df42c3093f1336291ce9ed9e1c8730663e0017c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"59f42bc85ee3a8a5b422085b0462aed2a770cf52d7a3660f2cd6dd257ec6e694\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1d1a6fd0e6851d419e79f82170f4060981c233ec8dc61656b84ce7988e9b71bbeecd7364cdadac066ddaf0b3de4dc8aa5acc411ebd1641f549a3af5ba214667b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-annotations\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-jcl\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Commons Logging Bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1638acc7030a001c37f803185dbd6eaf\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"285eb725861c9eacf2a3e4965d4e897932e335ea\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"eb9ebadb1581f0fe598216f7cf032a3b44a84c96de06ffa8d6f41bcc47305134\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2e80d7485b7ad4de6cc372d86ed73db9808be6a5a33e3c9fabccc7915fe57b73011bed75b4567c44456fedad5ae2186658a7f5cc331b4aad64e2a7cc78acdcfa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a6a6422a6c2654eff951af0d6dfb6e93501bdcb4e38ec353d515ca8de919a34b9e1fe37c562106f3f33f844cf071e010\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71098eb263af3ab42d93b8e7a96ceb90fb2069f2ecca85754e702b82f9876255abf5e3f9b48beb4a200f2d9e13599794\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"7f49ddd5db9841bb2d7ca8cb5ce52fa1e8982c7c37bc0c6e987eca8f5fc70d38\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4a417d058ecd3619a9716c5d47ecc506f4cb9c3684ee589c443c7b7996b630949932295186135cb3ce5fb0154c29436de4b6c1dbf7f135563449050973510200\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-webmvc\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web MVC\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0fcf00ac160e0d42ad9cd242c796e47a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"906ee995372076e22ef9666d8628845c75bf5c42\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de42748c3c94c06131c3fe97d81f5c685e4492b9e986baa88af768bb12ea7738\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8e7ad7afa2a605d8dbb6cb36c11caf0e626a5ca5849c06f0b35524e5ad6a13eec1ddff8625e1cc278b3082555a940ec3865657828458ab8d60d1c99d513aba0f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ec328ff12f857baf85ce6f44c849f8818658aaabb4e4d0940ea6b5ad2b009ce3c7717b6b02843f641f8125d0cec4291\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"75605b286d839df688bbfb9594dbb83d1eb22f2cae52a6f4b35d485e91ab94a55e94158086684ef3b059f1346af6dc85\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2e67bcc31eede462f5105a09dbf5b40a3e0ccc52d637c6e2720b43412da01525\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d7c5330069c3c0f5eda1417a52384a4b5adc4451c405315a992ed147f26466a19487ffc5e39b90a1ec4cb0df3f804a4d26203f9aaf4e74cf906d1e811abfbf3b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-websocket\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cfc1778713fba9b5bc33d3db64071dff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ee2f34b51144b75878c9b42768e17de8fbdc74b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"00b16e507bea58c6e8a7cb64f129cd2ffd62da092a67a693a8a6af1efdc7dd6d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"72da073d4ec4f7473c9a91b4d11607d02a3d18ca8af10348f9130a280f898814625a5865cb44244e6be6d6ab915099805bf06a60f80fd9b8ff2c47840d5266e9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f4c1d108ca60a7a658839b8ac45eba94354ad20e641d36d2ecf777bac252d371df1e8806a5460ccaf9da222f72a4a9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2d0703de58338d38fbae7f4a38390a766d66e3875e3a6a7f2620ae478c838c8f306a39cdac8652890e1116a3859e56e1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e594abbc4cb6dc0896c08a89cb3fa376980587d5995bace2b3c0798d99c1e454\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3a35964398627fc8bcd323dd9fb6d4e51ea183b704074320822906c074aeb50a0f8732e42b98bdad9c5f0aa4eb421da96dde7e97f094ccdbcb70f668c6d4ff6e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"Byte Buddy is a Java library for creating Java classes at run time. This artifact is a build of Byte Buddy with all ASM dependencies repackaged into its own name space.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4e5bd83559bf8533b51f92dcd911d16c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8117daf4a612122eb4f517f66adff778cb8b4737\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"30e6e0446437a67db37e2b7f7d33f50787ddfd970359319dfd05469daa2dcbce\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"583512f3c47513cf17735aad4e600be44c97e9978c9f6a45227de8a160a879960b1fe01672751e7583176935e0db5477aba581bf68ef5c94f52436a0683a306e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"efcce5a139f498de410e182a52e5b2465823a2ebf845001c9a733d87418118342c3854d00a0fae7945ae8dcb1916ba90\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cace3217b1c2c77a4bc194ecc602a28886d9e448efa26b1985e9fd09d90c92bc2e1b50ed70475106ddf266f8c2d14160\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"71647273afb1561b70d2cfa519f707a98711f9ae5b891249ae5803c00c25a788\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4aba6f5dcac177c8f8aed902307c62916c32be61841adcf12b9c9885de2de9795a965c0b939729ed67ee7d49b0fbfaf0dfd922be1bf1cdbfbe7b1f09e083831b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d6f93aa42df4cb27a58835750597d835\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bfc34c523b3ab295fb01f46373e903f9729cdd43\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"86c51c743babfc591be09af7fedcd778410706e567e9ed27218448ccd2297ef4\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"701b6ee27c87081e4a65ba76fe721f74e917a655575b19b9205b314f4a561889564e09ceadaa880aaf30f70cd8b48dc70fc5e32f511204b1ea031a12349fd9be\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"74d4cf202399e946789a5572007aa4fbf1daf26cfac27f83a3d8550711f99700083029b1f900037b8f263543ac9824a1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ac0b64ec94b558b4f806c09f68247eff80bcc8e33b97f5d09f5517a2339187e4b11c8e2287400a173cb128e3fdb4ab06\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5ca85cd0c052076d625c262cf445e4e8fb255b13323ba4ab08cbfcf32ec236b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"04ce88c724852938057c723a7ec637af2f8e601879a592a6fe135eaa26940f8fd9d9ac8f6917e761cb0ff31547bb849ff88a66e1f6e93c1032a4009fe1fdef1d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-json\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for reading and writing json\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"bea54cf408b022894c0b1b013c58c0a9\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ecda50de20ab6d3c49ea30df4c1982048f5d31ac\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"572f1a4171dff33b5a9260bbd704473442adf24f890386abe33ecc18c047836a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c611e0d07093d99dbcded7a00e7c00355a7c13c24a69d33105ca88ec63cc68ba76339b5a96b84f2b666bb883849980776e1e24ee2df9c7dd07b2dde0992289b5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed40ffb527cf8442dbe3eb7b542970317e4827ed00196387d78f123490a77b08b3bc2fd5f53b83f6bee1d4eed29215bf\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"26d5852f479f1c72f501569a8ea0c0e4c93f9049676921dca94b467e68f221214e4485c41647e6a92005e5090a6a7c80\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"dc69eefb2f1441bbec58c219ccedd895b863b1e1d25cc3805936f0c9b072f2e6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bf6fce60937e78550fb3d411c19aad2200d8129138fade809e9d0abc307c7f06b54732f1e94fa86ebb82d4da0293f7bce43345416b3fdae1b3c2edbac6706310\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jsr310\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module to support JSR-310 (Java 8 Date & Time API) data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"acd8ae6da000eb831a69b4acdc182b7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4a20a0e104931bfa72f24ef358c2eb63f1ef2aaf\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bea1d78009ebc4e5d54918a3f7aec5da9fbd09f662c191a217ffcf37e8527c5e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1c5bde6c91a2a89f3c1f231f4e17c435063d9012babbfcba509a3b25363b1fd99f0dcd4234f1e00559e43d3dc8e6c71834282c72f2ebf15484ae900754c5d757\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cc72f54d89bc0f7ffae9af36dfba38e5a61ac83db2f0d8de3c74e405a0bfd77b6d463217ece19c64eeb16291d80a69f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"096944bac7583e5c97e8afcfbc928ca4a87a7d3e5eb74cc77394a19ca8bc6f26185da7fdf5d6bd2179582bf51940edc5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"0301cf719fd327643b3228b91c36688aaea3fccf3487c3e09bae3de636340dc7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b9a4a8c9785e8ec2786690bfede18c76e08d81fc9c77bb2dad88e1a034f97f7d20020531ac1cb9b0b6e61645b08ea441aba35fc0732edc2fc1dc4b36d6f1695c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.hdrhistogram\",\n      \"name\" : \"HdrHistogram\",\n      \"version\" : \"2.1.12\",\n      \"description\" : \"HdrHistogram supports the recording and analyzing sampled data value counts across a configurable integer value range with configurable value precision within the range. Value precision is expressed as the number of significant digits in the value recording, and provides control over value quantization behavior across the value range and the subsequent value resolution at any given level.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4b1acf3448b750cb485da7e37384fcd8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9b47fbae444feaac4b7e04f0ea294569e4bc282bc69d8c2ce2ac3f23577281e2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b03b7270eb7962c88324858f94313adb3a53876f1e11568a78a5b7e00a9419e4d7ab8774747427bff6974b971b6dfc47a127fca11cb30eaf7d83b716e09b1a0d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"06977d680dafd803d32441994474e598384a584411a67c95ab4a64698c9e4cbd613e0119b54685cea275b507a0a6f362\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b5ccb4d39bf7cc8ccc33f0f8fcbab0a63c99a94feda840b5d80fc3ae061127f1475cfb869b060933783a1f2eafb103a1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ef2113f27862af1d24d90c2028fc566902720248468d3c0f2f1807cc86918882\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4fca2f75bdfd3f2ac40dc227ae2ef0272142802b1546d4f5edf9155eaeed84eff07b0c3a978291a1df096ec94724b0defb045365e6a51acfdd5da68d72c5a8eb\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"BSD-2-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-2-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/HdrHistogram/HdrHistogram/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/HdrHistogram/HdrHistogram.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-commons\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing common code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2518ae277e56aea5e37e3fc2f578dfa4\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abcc6b294e60582afdfae6c559c94ad1d412ce2d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"295785b04cd4de7711bb16730da5e9829bac55a8879d52120625dac6c89904ed\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"25d65699a25fe3b90de17a0539233fdad37df864f6d493475976e9a513bd7767520a882cbf6bbd98714a1fe94acdb77a160cd68f549475d2b93624ffe8672a00\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8523ae45ce6dd4a068cce108cd31da24629839d3d293fca92353cf45db9eae88107744c9e66b82ed14abb96782c562da\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9af1fc3aad2d0131c337b843c38b05510d31e7931a48841a4bdb618257f185286ed393f8a4418ae4c5f91da7f9c76cbf\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d5dbeadc5f629430202c81a6736dff2efbfbf3ea2c09844b1194f316772a93f7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c7b1dd1727000936bf51c02f9bf9b262a412e2b815531df4a9f7aad675ef0f728d4492327a404b37b1ef36d41a240b83dbfeea3367b3b4faa22cdc2decc5bac9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-core\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito mock objects library core API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4df8dd230071bc192161d0e54a76f6b5\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a1c258331ab91d66863c983aff7136357e9de056\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dbad5e746654910a11a59ecb4d01e38461f3e5d16161689dc2588d5554432521\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5a2f00df2b1b2dbca06686f88806b86990f1eea6f7c25281c0e7ec7cf7904a0a9227477279b11630d80f8e88d6b6e9dbdb40ad094a4077cc6a44cd2072d12662\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f2caa05fe4a5d5b385654ce60d0655724200fdd333652459b86848c3b895a9ad0b0daca8a014851d6b5c744cd0e9372\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"06ba4583220a4aaa47d79ccab11783d48900d8850a346e4a1efc61c057630fcf0bb9c95cec74833ab5e6ee08e55625ec\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f1f9899edf629fffaf8b4483ac04430945996393f4fdcedc38eba22a9a5c715d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d6f479d52534b382088012e3d1a83fa267dfb046322a72e84438d21973165617d1d710bb42f1cb2d2d3d7f891969320232031be33f4abb2ea1526217e16e8c63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3afea56b25f872cee2c929c761b0790d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0fe81034352a15731322fba326447ba70bfa3962\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3850d85c0f6074fe9286dece9b44f8bded5e194e9b816860735e0fc728173d65\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7197158ef14a580edc836ab7af10a9f5f567ba60e21267b624fc4143debd2638c7b8bd8e2e5973fdd5c5d512be73df96500fb0a4273f20a21b42161e9f7add75\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4a35eb1f124d8d7812d32f87b16a24dd56d4cb43278ce66f216f4a4af34db357e7481fc1b26de9bde7c2dd6847687721\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8369a8b49cae80b92abbfcc0218d55b9cecd86778735c66b9b0cc6fbc7251784725249392e716c314e3ec08c995557bb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ee742160e4951e1f6145d575f6c6ebb908a46f38a8b3b81b7d61aac7c111a87f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"dcb1b214577203c9b3e2e5dcb3aaef8e46aec5f75a40a606f42e230c6e1af39c37250d58de6bf694c5a62d70fb1a6dcba436d696f71d7aa1a52b9f4dea5aa9a9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-tomcat\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"db4df0f653e84bfd545894c4567b19ff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d8efc48034015522958cb3fea5831b4cbcd4fcfb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bf93da73a8fb4caf9fa68e4f3b97adcc9dbb8c79220a828b3d70ecf12d410117\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d2bce5bb0271525766283e17160513de530c20e0452cecc3c9d5be3890986cc071c1423a3c11c54a36d2f83bd3a238b0fcbcc6218976a5633f0753a313418f6f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1f9ae7504b1345595377a4d35163315824dcf25f29ac9d522385e6e1672b813719655989708eb03b419e808f1f102be9\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9d890c3314b5ec30f39de30bf70471aef5f19e64d6d2f60b6fe66b3c57978bbda0a981cf92e42f18f27b72ed2ddb3574\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"43d38219fbe556c2bac8670fa0aa4f89e2ac273fda77d8bceac8d9d34d7b27c2\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"6a4e9a2ff89293c60c8a05cb79a65695dbe9823978be93f1b309d702338f87f108aabeaeafe8ff0ebf08bcd5483efbbb4a85c566e1357acd1d2fab565c910a80\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-to-slf4j\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j binding between Log4j 2 API and SLF4J.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"00b957af4a40bea6a7bf61400b6ccf63\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d77b2ba81711ed596cd797cc2b5b5bd7409d841c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de143c565ba78b0f2c0be58f132c7aec75e6e1a10845ebda5a4f17c2a35d9990\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8a7a682dc5ae6a123c8de6002f1470ad2682795c65b47b06397d9ad9a31729e588c406013bfa989f9c2a51750c353cd7a147bc036f2d66b0f8f0b3f13798a637\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8f3e4f1eea069f47b2c6111f1233448ea9ccc723b7c8a8bd308b7317a6ec1f47008d2952c1cb274152a38d3e21da750b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"822f93c3bba450b89a7f64b4d81aab48a7f5c2f693b53a4dcc83eba3a8300ff90c9e7727223f3491c782c80bee9dc707\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1f3f3aace32b45e9a6271c7b4ac76ddf86eb4f32e28e147a3e054dc8c836def1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bb61c16d22aeed2d6b18972f68a6c4670fb8a07eeb79407748a7d499bc64e8ad8eb9774d372d9286227665686fe90878f2ef7e7f8595b74cd448d0f847aec02e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.xml.bind\",\n      \"name\" : \"jakarta.xml.bind-api\",\n      \"version\" : \"4.0.1\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e62084f1afb23eccde6645bf3a9eb06f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca2330866cbc624c7e5ce982e121db1125d23e15\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"287f3b6d0600082e0b60265d7de32be403ee7d7269369c9718d9424305b89d95\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dcc70e8301a7f274bbb6d6b3fe84ad8c9e5beda318699c05aeac0c42b9e1e210fc6953911be2cb1a2ef49ac5159c331608365b1b83a14a8e86f89f630830dd28\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ff377d0cfd7d8f23f45417e1e0df72de7f77780832ae78a1d2c51d77c4b2f8d270bd9ce4b73d07b70b060a9c39c56e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"773fd2d1e1a647bea7a5365490483fd56e7a49d9b731298d3202b4f93602c9a1a7add0eee868bc5a7ac961da7dda8c8e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"26214bba5cee45014859be8018dc631c14146e0a5959bb88e05d98472c88de8b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"32bdc043b7d616d73bbc26e0b36308126b15658cd032a354770760c5b5656429a4240dd3ddcea835556e813b6ae8618307ebeb96e2e46ba8ab16f6a485fa4d32\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.yaml\",\n      \"name\" : \"snakeyaml\",\n      \"version\" : \"2.2\",\n      \"description\" : \"YAML 1.1 parser and emitter for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d78aacf5f2de5b52f1a327470efd1ad7\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"11547e75cc80bee26f532e2598bc6e4ffa802941496dc0d8ce017f1b15e01ebbb80e91ed17d1047916e32bf2fc58da532bc71a1dfe93afccc277a296d86634ba\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"dae0cb1a7ab9ccc75413f46f18ae160e12e91dfef0c17a07ea547a365e9fb422c071aa01579f2a320f15ce6ee4c29038\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"654b418f330fa02f1111a20c27395ec5c7f463907ae44f60057c94da04f81e815cf1c3959f005026381ef79030049694\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2c4deb8d79876b80b210ef72dc5de2b19607e50fbe3abf09a4324576ca0881fc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0d9be5610b2bcb6bb7562ee8bcc0d68f81d3771958ce9299c5e57e8ec952c96906d711587b7f72936328c72fb41687b4f908c4de3070b78cc1f3e257cf4b715e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/src\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-commons\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-commons\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cd430f3f7345c0888f8408ce8795c751\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2bfcd4a4e38b10c671b6916d7e543c20afe25579\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7d9855ee3f3f71f015eb1479559bf923783243c24fbfbd8b29bed8e8099b5672\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4aa83350e7a6df21feb9ba8756bb4a68986f33f8c6e384720d1daa448444016c0def1781729788e3e884664abd6703b1e3c0ec6b79893a9d5645c3a4809c0ad2\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"d264f2c8ceaff384b0f22ee77890195ed3d918b01f338e35fc2ee12f82df15e59533918509f535883b4f4befed28595e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d1fa76d6b2567e831b37ff7843df6d7d65028d4e53c570c6f580cbbf13269d2aa2afedfedfe5a3f2cf92d7de6d3c89b2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"eef0f968f2d2fc31f8b4a4ed43bafeb46977de1ac3d59477ab6e2b014f97e070\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"93340cc2c378c830c755b25006bc4f73ec77ad10661f05625b23efa0854d456da8e62bdbe7e7edf3418dda864e6e0d7a6b9d34cea23d525b8991258f3d75fc9c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-web\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"a39761bc7a706c70f6ca3ab805a97b34\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0f26b98778376cc39afb04fbb6fdd7543bef89f2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3f2012a24c6213f155b6bc69aa3ecafe2a373c1e92a26dbecc62ff575c3a1fb3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"f07f054feaf53c2a97b82150882281035824cf0b815f317a22ba1954afa721bc5d57cb07faa19bad99fc235373b62edd7013f7ac2cd0a3d0db91faf49f216741\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"57418cf2a9b3256201c0874e7721966b09929030c64f5e5a85007bd645294dfbf1a14d4632a5aa5fcf70af5bf733d542\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"83daa608abc0124ec237f65231d5f1dd1a5d751e459d3ea255a3d12a56e92ac83037fb72c5793f497fbecb9e389eb299\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1a17acdfa8920b1849a16e4260bb4b960f60da07732148a5281cfcba21d1e4a8\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3e5e020cb1068250eb0e58e9bc0368c44db96d59022047ecffe286a51b0896e4320d9696f2f9136b4c0aed547d8dd1af1bbc2b4b053aa994246bb43bd7397f05\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.objenesis\",\n      \"name\" : \"objenesis\",\n      \"version\" : \"3.3\",\n      \"description\" : \"A library for instantiating Java objects\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab0e0b2ab81affdd7f38bcc60fd85571\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1049c09f1de4331e8193e579448d0916d75b7631\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fa990d15bd179f07ffbc460d580a6fd0562e45dee8bd4a9405917536b78f45c0d6f644b67f85d781c758aa56eff90aef23eedcc9bd7f5ff887a67b716083e61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"2f6878f91a12db32c244afcee619d57c3ad6ff0297f4e41c2247e737c1ccc5fcc1ce03256b479b0f9b87900410bc4502\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"a3dd9f6908fe732900d50eb209988183ffcf511afb4e401ef95b75c51777709d2d10e1dc9ee386b7357c5c2cbcf8c00e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"fd2b66d174ed68cbfcda41d5cbd29db766c5676866d6b2324b446a87afab3a9f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ef509e8bcea73bc282287205ffc7625508080be44c16948137274f189459624891dcf109118c9feff109e1aa99becf176f8db837ac4fd586201510c3ae2ea30a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\"\n    },\n    {\n      \"group\" : \"com.vaadin.external.google\",\n      \"name\" : \"android-json\",\n      \"version\" : \"0.0.20131108.vaadin1\",\n      \"description\" : \"  JSON (JavaScript Object Notation) is a lightweight data-interchange format. This is the org.json compatible Android implementation extracted from the Android SDK  \",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10612241a9cc269501a7a2b8a984b949\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fa26d351fe62a6a17f5cda1287c1c6110dec413f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c4a06a0a3ce7bdbee702c06944265c050a4c8d2fbd21c248936e2edfdab63acea30f2cf3568d3c21a559940d939985a8b10d30aff972a3e8cbeb392c0b02da3a\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"60d1044b5439cdf5eb621118cb0581365ab4f023a30998b238b87854236f03d8395d45b0262fb812335ff904cb77f25f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b80ebdbec2127279ca402ca52e50374d3ca773376258f6aa588b442822ee7362de8cca206db71b79862bde84018cf450\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6285b1ac8ec5fd339c7232affd9c08e6daf91dfa18ef8ae7855f52281d76627e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"de7ed83f73670213b4eeacfd7b3ceb7fec7d88ac877f41aeaacf43351d04b34572f2edc9a8f623af5b3fccab3dac2cc048f5c8803c1d4dcd1ff975cd6005124d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"http://oss.sonatype.org/content/repositories/vaadin-releases/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"http://developer.android.com/sdk/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-logging\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for logging using Logback. Default logging starter\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7ac01b9dee045285c365cf6a3d8d8451\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0df8ec78dc87885298998ca3c9bd603ee7bfe5b8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0b7e411cfc44a15fc63a36cd05a73b34c3558f1b06e4f297b1919361b8a351a7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"23baf0a59d56809db43101fbddb712b515012c64530362665cebe84c53bbd716218d3602024315f3250dea923138845c09d5c56dd9c7fb26a53d5e21a325e52e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f5ff55d346828eaec7b535bdd1d6096acc3819e81f6fa0a3d2396d523616e2e356d58115de8b8c49adf035216fa6ea83\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e5bd5c09d127a2984a55bbfc296cc515e399f35ee2ca949b10639c5ef583bee58dc9eeb60f6bec1f05904f8b91b4a26\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"99b21628e6efb820b4955e0e17bb54345a6974dc785b79abb7af8186a261159e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"91625907d0200fb80f025aa6ed098372955053bfb277db124d95ce2dd5049c20e9e7f2b97cffd6f247d9ae8da1bc26c004b688687056a87ccb3033d57a7c20f3\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d5ede97972b567fe75db1d2bbfc035d8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9089b9fff0c17eae54aabc466b78e010eac3a04f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b870c0a601dc0d6d98b33a6b59d41799285848de267f7cfb466a6f167f30c4d2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9577f4ba268b688ad100d4038f6dba97139a29b82127f6a581b948f0ee08fc8159f51fa5f7deb200e5a61559fd321559d2255af75c3e28cf293e815b8b1bb8ac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"96adde3cd5a4f729a6d382566800e62e89c93d1c3b9120ffefcd9a666d755fc5d6dc3dd12577f927bcaf03b7f1b0922b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c3f71bfae2d560ec46f76e833aee6964b5ad57639cb4ded937cd6d1e39b213a4c255d9b83ba59882d22dd31a4ef7b5f5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a251040e99b14a5d926f86bdcb1fcf505518d31cb421e6aaf32d59d8f7f2eb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3b642b5433989ba548cffebd7c155d5ada680b96996eac432895de56a27d7529c795d7263e8419854c9d118cddc0492d142d260a2e5434058134c9bc17ab8253\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-core\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-core module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7367629d307fa3d0b82d76b9d3f1d09a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f8c2f05f42530b1852739507c1792f0080167850ed8f396444c6913d6617a293\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d18159d4b378973e49182c4711b3d5b1f3600674ddd7bde26793247854bbd3a7233df7f74c356ecc86e4160ac6f866e0b32c109df6e1b428a10cddd4bc7f44e8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"afe21cf21e8804d069514a1f0d57c92b4caf56f8b010bd681d19fff67f237fcf0bbe1e1c9bfc4cedcfe602a3ea859b57\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"38cc28c8a578f4053412440d88b41938fa029a8ee3d350fe7474b34afa0f17889298d00f3c2cec4510d72d3342d29a77\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6c7d3be575969be97a49e90a97a8dc1bb25380b1b302073e00d2e21cb266e6a6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8e9ce45d599bffac71e35a0d59c4dcff067f628157a75e9e28c1930f31537fb1dd058ddd9906322c1154f29436252a36bc50595578bfee9bcad4a9705c85726a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5c793b3b61ba2637840a6c865aa2901e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"142fbe3cfe3370c57d0ed55cca0d8d96e1d6f26e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fb27aeb59ab757e60c48f9810d0ab54dc858a4c1cd9cc75b4ad07456c9c3e7c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"975428c3f753ec1375f9c0ca2c47756a22896cc510193b53f7a8501255634a2e0d2165e699055667f4127cbaa8e79c9c128aef6de0854fccd4e158dce4422939\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"c3abb4c4a9961cab0fde6119d5b86755ea0c43fdd266b51d369a8544818463ce1876df2b13b0a2478f36b1e5282a305d\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"641f9090f373f299d61bf54dd06e7ea15217c5b06424e970ddaed1f64e2a25aae74bdc10e04c9c4e934f2a3a5ab95c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"45d05dd704757c997b11f13961762e371309bec11292b32af3f244ca3b49642c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"53001dd1610347d6cf92f737067271fe3c638828a0b1e0b6aca62429e97a85018daf6ab3e10f065acd79ed7c93dc3a4c57f89eda3e2feb48ab548ca7e906b414\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-jakarta9\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module for Jakarta 9+ based instrumentations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0e247019d91d3c357b440436e1af2fba\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2dc7257970669fa45e342b0b36902d868af2dbed\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e8c66d7aee8fbc8a9d2e15c6c53df92bd7ecbf94f1ca8562d62d9a2693aa4633\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3a481de081b216d42bd9b741b3a830c93d917c5ae8a11f670785b53b55cff601e1cdfd037b12d8b95cd8557c4493d6e04e51980860e421f444f2b4a953070969\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cdbca1958c2502bcdad18446401f7f21ec2bc2c4055fd2fafa8fdad30cb8c8fd9aa9863de5ddd9cb852cafda487d29b0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"13f29eca056350277ee80d786945386abdd1c8b7c04dc35a94c7ac8146e7b6cafa617652fca15e79b8376341ae5576d0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f095b2247aa3ada3c824121b4720dcceb3b65f7a2b9e880acdedc613a62d9be6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"773cd6f711b68a27d958ecb01f85d8480835014d23d3484e69e1c63bc736f50697bd6cf7d5e7776a13ae946ed10621334cb84ba8357b26d45cb6c9990826f993\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.module\",\n      \"name\" : \"jackson-module-parameter-names\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support introspection of method/constructor parameter names, without having to add explicit property name annotation.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"495868f770056602bfe13ea781656f03\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8d251b90c5358677e7d8161e0c2488e6f84f49da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baf1a3156a23cb407e05374161a07ed8560f78a7ae249955de04a9a2fa2d0f2b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"497b08f55f601b7ff6294e0b8307e015e60ad45c7949bd80ed3f5ee19daa93fad7f0b5a93abb8082ec46480667ab8539337633213d0fd5992e4a10c710f0a7aa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1a50ca6c0e0b4e3ecf83e3f327670a3b36f2b847b46ab5e193e9bccc36fee3bd41c1aa937dda88c4936339eafc73fc93\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"30d05f1dd78a796ba4abb79be93dae2d7e4e5269de18d85a9d89b1c92f6ff8fe09ac1953a48a0b2b51906bbaadb56fca\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e50d137efbe3de957a64fa4b90532cbb67efc2b09ba11824362315d1f57b812\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9418c5c18e429e201d7f6a4d5f05a52a433dbe4bf72a82e3ea69010c1d4b9ec99fc651804f2f8339a53841f88416318e3ab7fb1a07391cde5ea745ebbfcf98bc\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-engine\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4d571057589cd109f3f4bedf7bbf5e7a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"f32ae4af74fde68414b8a3d2b7cf1fb43824a83a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baa48e470d6dee7369a0a8820c51da89c1463279eda6e13a304d11f45922c760\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"52ea2f11ec2ef0457384335d1b09263f4efecf63d9df99c5f8396f74d972722c51f8f766370e85e030f4476e805dac72603296942593c5bbe56993454b9d8e30\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7c520e04c995a47c19c94fdcbbcba9bb117696191e6a989a82d9f960e0e315e5cf87d28022ac5cb2701c85d5f38eefde\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"79d4f2fb987d6a44174dda99b1bd827e8dfd0399495c3e994371d4f69631212768dee8b891313aac89045388a1bed9db\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5c3fcec688368188688cb6949c1230c2822211e53f3a65b7b3abf4a38051798b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"30a0834e88bbc62287e5f49302c4a07b6da1bf4d9774faddbe7e606fb296c0dcd71c7e90ef8fff3e18dd050e5a19f7b903c91674ff4806cdb97111e4f0cfc199\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"29fb14fe1d383588e87a73da4508604d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b100d2d21d45dddd740d496357ca6f3813d777d0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"371f0f36d226a8db972c37c73f0a0896ee4d3e77c29b54dbce8a64af731a6e53\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"42bc3a99f9c9ffc9fd08447303a946fce1c81e3a869a5788c7d3b669536455eedc8009428ae4660d66b0d74ab170968b6aad905455b53342d7c521e7ec4c262f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f47603c4009bb767f9d5cb0bf3fcba69167daab53cbfafd217450977464073e8b814c76aa545b1eccee587201fe93eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"bbd77376c9a46de290522662f327a8e6b0221a6c0105632e73b527799bec8a162d98948d0d05b32509650b4f47a6465e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e9549dda419ad6f482e3b376c595c69ccb93cebf365c1b18a59bf226c3264db\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1473f0de013447eb40d0b6d2a30013d2a7d262ce1e0259d4a27f88e421e5538234a46704f88b27c227aab7ae2261995a73f4075a6a43124e39c7234c6d164fe2\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-engine\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"71d86cd027062c4da0796c2493ae94fe\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6c9ff773f9aa842b91d1f2fe4658973252ce2428\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02930dfe495f93fe70b26550ace3a28f7e1b900c84426c2e4626ce020c7282d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fcc9406d1e0301e27538757c9649545d784e83743a8800932971881cfd78a14a264ad13c0b92fad9ae1be50963c540427a19cb2d1fee06888ef48105aad4c8b\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6657ac1bb11d7a40bbcb020add01e57edbbc521645116908d857074d9ea319eab3e7b7f2e9fa1ff8df08b5db3774f4dc\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"607313914c11274c577b0aaaae6c68aa6ecf25d8302f55d4e334aa6b58df2e543d2399785e2019a56b85aac7716c9623\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"be3560971111d3f548bef24aa6660ec2a126fd17b3bd68b7deeb1ab48735a9d1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4ba6cb70f8fc1918dcedc874340488909c48e0f976d1834ec433f4b5c6cff55b16a996a0443a1b68a0d0ad84a37bf51386633905628728bde08b5820ee67dfaa\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-observation\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing Observation related code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b55c9caac5c8f778996937c3f6cf4101\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fbd0e0e9b6a36effd53e0eee35b050ed1f548ae5\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48f6607b248e8b77ee9f7b3934f70124471daf947b30480c1b9c0e9d9f996c83\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3e12e101b161715e5c30eb166578de7ae76749a2c4d22435bc57395be14d1313073d5fa76dcc883ed807d4982d343addfa24540e283cd0432f1428ff00962d98\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"791f99b503d7fa16733a74d92ebd02e72dfce4d648245f149f5363019beabe7e317e7ef0df0bcb67832dbab03943ff53\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ccb83eb15cd8004295bdb40b948cb9d3efaa4281b0d02a97b49970a2699822d7cd15b83206c236c3a41e49063caa5ded\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"773e3647329d707d79efcb92c88cbe0719b4dcd820f06983e6e283e666875acc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"922f6c81c3a7b8e8c1296eb3359723161e91bac646d4bef954904c70a40ccfd9dc95c783715fcedc788f67ef06ea5514a918c7cc6811f2bdd39eb011a36698e7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.awaitility\",\n      \"name\" : \"awaitility\",\n      \"version\" : \"4.2.0\",\n      \"description\" : \"A Java DSL for synchronizing asynchronous operations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8f3644827b9e3037de42068c57006260\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2c39784846001a9cffd6c6b89c78de62c0d80fb8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2d23b79211fdd19036f6940cc783543779320aaf86f38d6e385a2ff26da41272\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4c422b4aef3dfceb040898f45cd1b2efb7bbf213ef9487334a0d0e674e494e120fef61348f8a81ce726f2f66dc426e133917de20c52b5d39d792e2dca7bc82d8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"11d15d6efb32707cae528eefb8fa4ab7820649ed528c3447660efd984518ee2906421af5ee76ea8181c904d594e8e719\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71eff4441379fb1d13bec42264d48dd1ed4817c7a226a4ef1e5255e5afcc8e5e61aa92677ae98fdce2bf4824b4dbe4fc\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4fc8b38b34625336be520d2be1edcab4c8dd8e0667fecb2aa6aea83b9bad7f28\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"074f8629ab499c28155e505513e0a25c83ce722747d196966eac6327de604853503ca5f54b84effe8e2e3ab78d9ce285bdba82bf738ff8bff0f1009549230521\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.hamcrest\",\n      \"name\" : \"hamcrest\",\n      \"version\" : \"2.2\",\n      \"description\" : \"Core API and libraries of hamcrest matcher framework.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10b47e837f271d0662f28780e60388e8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1820c0968dba3a11a1b30669bb1f01978a91dedc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"6b1141329b83224f69f074cb913dbff6921d6b8693ede8d2599acb626481255dae63de42eb123cbd5f59a261ac32faae012be64e8e90406ae9215543fbca5546\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"89bdcfdb28da13eaa09a40f5e3fd5667c3cf789cf43e237b8581d1cd814fee392ada66a79cbe77295950e996f485f887\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0d011b75ed22fe456ff683b420875636c4c05b3b837d8819f3f38fd33ec52b3ce2f854acfb7bebffc6659046af8fa204\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"92d05019d2aec2c45f0464df5bf29a2e41c1af1ee3de05ec9d8ca82e0ee4f0b0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4c5cbbe0dcaa9878e1dc6d3caa523c795a96280cb53843577164e5af458572cde0e82310cf5b52c1ea370c434d5631f02e06980d63126843d9b16e357a5f7483\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/hamcrest/JavaHamcrest\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-api\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-api\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c6b8b04f2910f6cef6ac10846f43a92d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"eb90c7d8bfaae8fdc97b225733fcb595ddd72843\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"60d5c398c32dc7039b99282514ad6064061d8417cf959a1f6bd2038cc907c913\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1fef44d4aa781bb119ab723c3c2a6f0d27efc4493a1fa26b603c7c7a8884c4d6274bccec6536f120d55f876f8d052aaf6cc003074c27cc704deb2c4bc08b6f0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fd81f893be859a50766bfbf3bd74bd7d359c6d481b7fe3099e220402f585d3d46b6ad42a36b1d88eefbb6fd27a3cefa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5e13ba92f757499ca52d719869d318cade9bde9c948ee9c68d753a21ec273f7b56ad68ff8cb281614efeef1d4c479db0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"997c9e0cc57d61a85a8eec568d0f014d47af5bf655602a2c3518b6530b089905\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97c3e2c1faa1f77b174ef6ce7b24a2339e547f5976a4e40348653e84498e0c3bb96068447facef6df6b54d4af34b807f19b4d2bb1d31e26f97d6dae07843bf6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.skyscreamer\",\n      \"name\" : \"jsonassert\",\n      \"version\" : \"1.5.1\",\n      \"description\" : \"A library to develop RESTful but flexible APIs\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"60a7d3d352b233487d735f4b86802717\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6d842d0faf4cf6725c509a5e5347d319ee0431c3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1e9a7c443d0dd579906646d767f3701918a78cb88a93112f528305fc9095d261\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"51221bbeb30ed47840494d31128e605e29a96249f3e4b9c00985a865f8ed58b73e045772e3b0af74a35018a9dd004b5cc2182344b9154d9a50604ad1a073f2dd\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"941cec8d4ce1fab19f32b36f0afd2c7de27325659c5f85ab90948182098de4afe327b49cea57b946f18671af8037aefd\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3fb46460472c82901ec6fa5deab84eea18369e74aad920e3ee9e0fb8a859e8397a287428d0bf1c2b137368b6579c5c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"24b6c0f73ee51c19d5fdae62588dff9d0bf172da7e6ad1595e275920c8de829c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"686fb7b0ee0849bc78b6eeb74a941795252cec9a62ea153e6bd1e77d51fb6ee14f64970cb52cc13f581d21b166c6f1b28b8fbc4c7ae0c3b225df385a92635f0c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-junit-jupiter\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito JUnit 5 support\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab44b412aa650651eedf323e945fe367\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ac2d6a3431747a7986b8f4abef465f72bf3a21ae\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e2416a260c3a45ba77d674cfe27d49428e57efe21a7b2ddeae733ebb5c5d85bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"39cccb119c0767f4e443567873af78d882c4a1e99c553ad39d4efae2698933de602d9c0046a70a05be552793569d4b43e75c2a798fd1f7f0a8c5ab34db8b9c94\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f02eeae7fe867ff8580164b4d20d269efbad2a18ba2ffc8ba9744c603c589fb5155399361b14ab2a6549d605d26a4694\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6b95b5f5efcc97a2531c9c108e53fe5465ae0249d46988fe7fd47df7ad4d154de40a66471a996ae7abd75bd0c1f6c9b4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"30978340a8749b094a5b0f42dffbb91e72f7d7eaea6924efce13f47a44048fdf\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"80601cb4de8850a0255b7c28cb7993be667a238d961fd281c7152b7ba40eec399240a2ab9d686cd1463872652876e88ef221d699acb61a2acf041c9f187053ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-api\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b5e9bf76dd128b37666ecd9a252b50ec\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"74c65e87b9ce1694a01524e192d7be989ba70486\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1db48e180881bef1deb502022006a025a248d8f6a26186789b0c7ce487c602d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4cbf72fbea7009ec2fc363aae2ccfe11ea2023967d65be39335eedd1d8917b7402eeb2219efd5a1f11d03833dd1f57eecab428616b03124ef2266c6cca06ac56\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"edd8429f2f88476afbfa63314f7846d1341a4cfc58d3abe55b3cda236613feb6859f711e0ae60bd7821b74e488fb0666\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b67292ff0c7ca988a4b40b6ec14582ef579990d275a37944ac9572ecdfd4bf6e9fff2ab982b21d159a1135c21a32495f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b2641c2db75d3c676e451a53b5f60dfaf030a84e0230747bd50d00414f8a27b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"f1f4d9c48a9d088460e1ad3d71126b243069e522588cdc5534ac8f201ec0574287e8f1fba182f8925ee75b78726269487cc0160f7f8bd1aa21cc8e587fdb5c4a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.assertj\",\n      \"name\" : \"assertj-core\",\n      \"version\" : \"3.24.2\",\n      \"description\" : \"Rich and fluent assertions for testing in Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b596a91049e6ce526bc5595c1bebea2c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ebbf338e33f893139459ce5df023115971c2786f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"df3d0b348f1fe806bdddcb10fa4ae63c6679e9888d4bc7055f09848517976aa3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d8e3159effc7954258f2398e26c34eab6c243675408c7b5fcd7ed04a7b7dc06006514510ad15be9e7725f724cbf6e5c534cb22cbfb7c0aed71b81d4ed5755220\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4f06196b5329e215282476d8e3aa5065092924bccb91da4eb0aa2e8fcd2509f249369654f0c17b59c38f11b878a305e3\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3029ae58aef975843e9205f130dcdd8f8e7da5ff1bfad62b7d918ffe52b74a3c34a859af13393abe122124a9132f3feb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2db6965251a03be26f5baa83792a002444b4de34aaaefb0e6cf3cccf0a20939e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"fa3ffb87bc40c3f881fb477d41c8565cbc1ce46ead2030442674bb86a425c722b75fce5bb3c22425b21cc3122ac46e0f28b2eaba2bcf5d5ddcb31f47d967b890\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-web\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8a6aea9e1fbdbabbd00e35038739200f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e27e36d4222fd4d589e634e1c7f5f09f0316147c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2f14d3a4a0ae3ad634bcfa07117542001c1789c0bdce3504baee8f2bc45ef006\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2fcfc8d9abfcd0518b6755737c6e520544600b3c26b42b60d1ab3fcfceb31582d5dbcd5d86a98ec312442d335e49f0db0ecf21d8e99089ef41d962ece42d97ae\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e3c8cb02b18ea5b7aa2a7c9c97c62385fcaa8fc53f41d7bf0b98d262a10473e9674924ad287964f6e58fb9c5915da8d1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"713c9200480f14fd4bcd073d43ac7900771c9d36b4e72b50ddf80733670948ad57700ea37336de5078d16557e426de79\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3346906c7b4b455c00226fd9804a237d3a667523800e0c2083413fde4592b7c3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"99ba750d8e1c97636eb47122ce259b1bc9b91c51fecc50d13604f7ae7096a20f1fa38562d83786c1d4c3ba07ff94b286d869d671a5f0d00fd6c378f032332f63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f808bed72032367a1170477e74e57f7e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e6a20062864e3a9a0bba0ac3b0c5a819453045b9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2e0a11d69fed912dd6f5a6b0f492ce1530e2ac932de9588d4b7df0ab548eea0a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"83c1f7e7b404be7b9f603a386ca2d0c84c7e0b73190ffb19ef2b0dff5cbc1ebd57ce73be663ee01ed28f1c4f41d91db7f070d7b37a3f2ae6b9b6814dd930a089\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3a5159cad10587b250f0a1f7cf6ebea9f2cbda539c008094fec1dff47eeced5b2119be3ad007eab0598445b9282164f4\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9303b808eed6e0425d5c7e968601960d9ff2e0c2fd840ffd041b01f0499b1f86ae05c50e968e925374a54b26e9298410\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"a18f18bd0a077a38ea0b3aeae85730b9f104d65d4d48f88210f2954c45739eae\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e021bfc51b8d6b8cdc1b44cf5042778c208db09b349250e33630b28ace2ed97d52bd89750ab70e14b650578f379a7e6172838c83bbb2c974394132cb80381f27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.activation\",\n      \"name\" : \"jakarta.activation-api\",\n      \"version\" : \"2.1.2\",\n      \"description\" : \"${project.name} ${spec.version} Specification\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1af11450fafc7ee26c633d940286bc16\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"640c0d5aff45dbff1e1a1bc09673ff3a02b1ba12\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f53f578dd0eb4170c195a4e215c59a38abfb4123dcb95dd902fef92876499fbb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"383283f469aba01a274591e29f1aa398fefa273bca180162d9d11c87509ffb55cb2dde51783bd6cae6f2c4347e0ac7358cf11f4c85787d5d2857354b9e29d877\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e34ac294c104cb67ac06f7fc60752e54a881c04f68271b758899739a5df5be2d2d0e707face2705b95fa5a26cedf9313\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ffd74b0335a4bfdd9a0c733c77ecdfa967d5280500c7d2f01e2be8499d39a9f0cd29c9063ae634223347bb00f4e60c33\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c97236eaebb15b8aefa034b23834eaeed848dacf119746c6d87832c47581e74d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"147dfa2bf46bb47c81462c36ac6612f9f807169ffb785e2bbd45538205c5713f33af4373f3324a2063350c2367baff37e9c2cf085c38c96870ad88c60a7fbea4\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api/issues/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-core\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Core module of Micrometer containing instrumentation API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"30dcc7ea6a0e99663e5908bce7371206\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b72e9a2f26355ecb8ababa0148a5c3c4ac648f14\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"97d0a5309e9c584f4dec6f549a383ae25d8727abff43cff8e0b90580ee797b67\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2acd080a1b40cb5a1ca0b7266af829392e318291dab57e6239ca97d15112cc206992b78316f4c02400454124519a084341e4de55dd729c96805b3fb196707a64\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a3998a9a219fc049ace5731fde94944948332eccbe589dbc34456057a2df173ef17e3b0642233e513d3118bcfba565f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"22c97b3fb49d299ebc36674a6e32d9fd05726d88109ede3323e3e97e82100d1ed6d7010e86749a2b07ffe994fb3b7833\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3b272686c89e274b5944715db002871e072f0f8c7099228f6d6909656b6ba3f4\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b1d82086950a2e61ed3e016fa962af2e9c3b2d543c4c311d40d9f7fc402b9beb3e5d09261d336cb1634b186f723bf584874f3fb8a29c38198d5ddd2b386c4413\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-params\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-params\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5e8e17f6f2a5dedb42d9846a3352dd31\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c8f15d4e99940c4564098af78c10809c00fdca06\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c8cf62debcbb354deefe1ffd0671eff785514907567d22a615ff8a8de4522b21\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dbd8a3bca0a03b6eef54de2b489685c8125e0c6f23cbdb633174b21e07cc7b97a24b55dcb5b60ec1a496683a918bfdf1ea0459950689e3755aa965ea9e106ee9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"882b3106163d7c195867e08db9948a0997e1469a23c847bff523efa30a9b274c0588f8228fca98c78abf9b61709a7ff2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e4e9a7dbb32cc3f16f21a14fe036aa13488c5b94e3cb6cc53b417c4588b90b5ae118caa3eb9f4bc9c513d06e2c1f408\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"171a08027b527e3be1ad66082405eacf4a55746dd983c46d9ff7ee5552276615\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c435b4a17208b67f6fa35ebe74872c3d2c3557b290437bb682ac86701402bbe17d0e53446c674bb94c7feaae4bbfa99d888c7bf7181707e27fe08ff7934c00f6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-databind\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"General data-binding functionality for Jackson: works on core streaming API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5f453c55f127690fa8491ce347aa055c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a734bc2c47a9453c4efa772461a3aeb273c010d9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c3c53333a2172a80678bda1803e39cff45bec6ae3e9c7d4f44a81ec4e2ab18dc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"490ccc99a9c28238fe28455bae08196b83df034cae8a1947d27ff89e500a5d812cf4be36c61942e647c62ad540d8eb4428f49855f0cc8db0ee9e7a5b12ba2454\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"b53f4a6fddbf677a8d02c65e9f0a96372140c68286d68740987fb462f946de878abaeea421d3e4716751f04d88c16ad1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5a407605544e303abf8a212651bf5e5594fa313804a399bf03401f449c0baf26ef965def518b05c275b2f38f18457739\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d0880002ac261d181e663499627fcce5763f3a9120bb76e758adfb9939d17c98\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97bfe0e9117dad82e0799cb2c105c4553c6aa5ce9abdefee4fd5b584876555309aafa9a19ca586e928e292e32f23452849a10da7364966e11e4f7afcc6aec78\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-databind\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"jul-to-slf4j\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"JUL to SLF4J bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"24f86e89ee3f71ea91f644150c507740\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"09ef7c70b248185845f013f49a33ff9ca65b7975\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"69b4e5f8d3bd3f6f54367d19f2c1ee95dd5877802f12d868282e218dd76b00bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c1cdfbc0c867917d65ab58e039b01c5b119368aef82abcb406d91646da208a4bfad91831a5a425eacfa8253ccd5713a9d4325d45665288483929cce7a6a56eb7\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a8d45375ec27c0833a441f28055ba2c07b601fb7a9bc54945672fc2f7b957d8ada5d574ab607ef3f9a279c32c0a7b0a5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d65edaa8f6ad8bbea84617e414ede438ec4aafffa3734f2d38e6dd0a01c1f42f9397acaf6291a73489fb252d7369c71e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"69416188261a8af7cb686a6d68a809f4e7cab668f6b12d4456ce8fd9df7a1c25\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"52d54c80e3934913a184efc091978201934b0ee47a6b4f9c8555a4d549becd26957e17592aff46dfdcfcbcb2313bfad09699ee84cfd7112ed2a00422c87399e8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"6f7384977eae04c804b1062df9217959\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"faa2ce019bee68a8d17529d0a08ebc427f927e13\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"6fde604399114e77b12519b3d117117c607cb73b89a88800856fb0e0cc82ea7a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8619959d143ef38f5c846591b8b10b0c50906a3301a5e9ed3e3df44124bdfbe3197cd4ecfb214c3250f40a0c1b11138b7a3f6865755445879f0685d2e88a6846\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e237fdf6fdb8d21f2fc19fc15a370901c368266ae8d2b157f41b5eeed50b211a871fabc352dda10bb3aec60975d233f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cd6240fc102daf1efcd9fdd6532ce21297d5477e9bde3f5651cc9ec9505d526f63ea2284e484c2aee2a8e63841137839\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3959b52aebe7405a95f82d8990b8122cf21b89967f691dad851b85191973f9cb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1b4ef33997158ddb97ccbcec7011cd55f0e019428d25410b01a83ca58c9420f2f8805be955cf704605145abe582522db0c8afb9698ae4efac141a3807a457ae5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.latencyutils\",\n      \"name\" : \"LatencyUtils\",\n      \"version\" : \"2.0.3\",\n      \"description\" : \"LatencyUtils is a package that provides latency recording and reporting utilities.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2ad12e1ef7614cecfb0483fa9ac6da73\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a32a9ffa06b2f4e01c5360f8f9df7bc5d9454a5d373cd8f361347fa5a57165ec\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"bb81a42498c65389366205f4e07cee336920e2f05cc0daae213f2784b1d0ce9a908b038daec20478f23eb00b2bf704f96c5b00f63c99615193ab2a3cc4a9f890\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ca4640dc9d848e6c6d15441897e1b5a9f27f34207b0bb456dd54d8f267b73b348092e548e78634144de44ba3515205\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"406c2b5c6f64b0c090568e479b5e6136a04a4e77f8eea65d32b4e2b01deebcdf6a0a851240cdb740c25b5a5e61e6c179\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"50ae828358301033542fd7c412e86ee318d5451f89a182e2a679aaf18099d26d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"456c337b9fb385579aae707409ed6a04d08e5fc87b1a46733dca617c22c625bf253dc4747e0cdbf5e7d8b48102d2938cb482b6b688a79aab645a7459c592258f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/LatencyUtils/LatencyUtils/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/LatencyUtils/LatencyUtils.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-el\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f9171a84574782d1d68acd8b07177172\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ad7312421535d7d3aabe0f541e852baccb59726\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bac12b9c993a9181ffc88ea8ba085491a482729e64ae105750a7475a7b85e549\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77cf7be4536d7f1f4761fec33562134150c0ebc74d582160ff913c8be37b1502ed63e90bce81bc8617cfcd76c774903c2dca4209a972146f4c976f786456c596\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"62b14b49de8ee6efb41831ff172114af56a18379a797de732915ac356bce3e5582764253852c9831a3c3b6c1e52dea65\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"05cb21cbf8b221332d7ad588cc6aa2087c60e8ce92c5ff2bddcd16465ef2a0198f74d4595dc3313d1acc68ea945c8672\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c18e9b240138c21a23b0bf2f502d1d667084c5a50d7b3340a4a08799a3175de9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"663d02ece35a989d8da1cdbdea002974f0115ae8c727dd71f0505f299c63f04c0e83b718e4c3e65412bea1c79d872e9ca7d9431c7deb63a312d3191d419620ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-context\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Context\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ca23d3013c2afc6d3b30b993f3c5cd69\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"15df19852991220556b4462a366269b8e15278eb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"af22a435469956415bbee873de6c05995ef12f2d29622abf510a94581ea52de2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eca3cb14e8c0fb65d27bc21a8041aab3baea14f278fb546356fcec9874d0dcd10353fe697e94ebc35a78abb3387d5a41b67c1cbc9341eb05359c1b535147a9c9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"374207d989f7f27ded5468f35867d0aace78927cdaf98c31b2b6345210fbbe960ae5e5143bb0308347b7ef386159fa04\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"236c1d366734b231ef4a334da4220b311dd58b1707ae854b2a50ff89b6b348913458fecdab14d196128b695de6dc9832\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1e1e87df37dbc064315d7afaa59480c830a0f445ed0df2ff5968931f96e9e86\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a600b2720ed8e5c6ecbb2a68b6a5fb5320811818e2128016b9888df705901a8d0f38dfa99b8d458724a85e769b4da2ce14d461133e085f8aab23f59e9e520c11\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.opentest4j\",\n      \"name\" : \"opentest4j\",\n      \"version\" : \"1.3.0\",\n      \"description\" : \"Open Test Alliance for the JVM\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"03c404f727531f3fd3b4c73997899327\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"152ea56b3a72f655d4fd677fc0ef2596c3dd5e6e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"78fc698a7871bb50305e3657893c10500595f043348d875f57bc39ca4a6a51eda3967b7c8c8a7ec3e8f85f2171bca4aa98823e912e416e87e81c6ba5b70a37c3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"10398b6998c9202a0731e2e19ae1c3f9d8a83582c2663fe7bdda15794ee6fa816727dbd8f7c7164bd5395ee1cfe7c97e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3abe706fd78509c25a402c7bbf6f9ddf71ffb5b35054864ba0fdf7902207115f888a0ba728fd71d2e87a9360d2498121\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d961907a1bfa1dcda329dca494ffbc251b31fabcaca5ab7095661a8ce3c1d654\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0ad661617bcac51bcd26f7ad4611c69b1fd9811b50dbf734e041a3243ab1f845e7796620e8a7c40c4a2df3946864598b1251396c7d9bd813203d82710788cce0\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/ota4j-team/opentest4j\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-core\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Core\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"98bedebd5de314d344ed3a7dcad01c66\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e43c71a9eaca454654621f7d272f15b53c68d583\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e3f7378e98c26500bdb5ecd6865778f57a22787eb2f11b9bd5fb8e438a0c631\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9654f2d77899116d66dbf5808815c866da0bc7a965532da059c7819bde3928e8d3692f0dc97e06f94c44e5452b785b50eb364a1cb7e46385653ba0e2c7195306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3b63b4a26c5706ef2e379ff7bce89df983e7ae449a927905ce23ecf26e22bbcf8e91dc53cc75f4f7cd72bc09d7e7bb20\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ca29e88f0764a6a9279fc93d5cb9284a04c6ccca6a8a5beaa404079b90674286fc6458d14b0b0a727d31e00b8009e4f9\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"861fc1147deae5a55165bd32c3fd4e18687afcc37876205c10bf1feede582ff9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"659a0d2e5ba153be219e1ebbafb28f9b48c44a2acd78d695e7479551a1c1641b7893d7df071a3cc7436de03735b0c8024b2f758bd0286711eae64ab005f6e929\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.jayway.jsonpath\",\n      \"name\" : \"json-path\",\n      \"version\" : \"2.8.0\",\n      \"description\" : \"A library to query and verify JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"501b9f34e6a05c20dd74e6b40e066617\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b4ab3b7a9e425655a0ca65487bbbd6d7ddb75160\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8d1521092a2acb13a2667774b8b81debc1f2a0e937007e27e5bd28bb222910774b64d6e269f33473f765c810c03a34e715d16065dc9a4be8d8d081436282ba7e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"aeea493be7c23574a77df50a0652776b768d52e4238efd504b8ef3b142bbe6caf0dae8955b30c2173a54f70243d36a36\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c11c80614c007f350fa2fe758c0f4505e7ed7d25590622f133abc59ccffeb4e0b2abfd393b83e58dff4668307f28704f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a7d1d7845dde343617ec009dd0d76e6bf012f182324e3b9d0f23c52bb7f67f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"da023255dfa2271a0b6b35b7d35980c3c502f3f63b3d515714f7dea54046f527bd6cbd903fec9492aad88ad03a1b85dc2b05fca4b34ded3c3b427c4cbfab02fe\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/jayway/JsonPath.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"slf4j-api\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"The slf4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"45630e54b0f0ac2b3c80462515ad8fda\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"7cf2726fdcfbc8610f9a71fb3ed639871f315340\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"069e6ddce79617e37d61758120c7e68348ee62f255781948937f7bec3058e46244026d7f6a11e90fbc15cd4288c4bb1acee4f242af521c721a9e68a05e64d526\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"fd6f7ad85d02ac63cd1a586c8bb158c1fc000495f512f097731ea9f749b5da2637615b821294962805ba312c738f40aa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"17cd61f59a162250b52a89c7c56eb60da253b776210500313c7b82744483ff84717946f969251fb4d76f9bb12a2458fe\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9dcb04582c64c79e788f9191195834ec75bb3457133d22a176a0ccb069b97103\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"990faffa454598a3fa82affe30f1323db769d2e1fff20d9c7163ef6fd95ac7a0874c06a634207a2eaed9e5afbdee68b225138fc75018717ba97efe3ffe92c88a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-classic\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-classic module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"204b49a7fa041b2b2c455193079dc1d2\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e832f7263ca606ae36dabb2d8b24c2f43d82cf634e81dad9d1640fa6ee3c596\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b535f2cf5a2fdb807017cb6fe456c40dcb11491e743ff86f99df2714a1b12bb9182ac193d37c8a6dd7eb2bf4c7d24390a6d551d02a280083673516eecdabc4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"606400251082b8193a57bb20f1774ee2d6e439fab2ddb0207643fe9cee66cf61edba5e5c80d4b3bc9785a7bab910f8df\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d9d9b1412d2fea3eeb5d110a0e7d44c9bc13459fd2b2f5cbb30b95174081f0184758abe43b5e6b6197a716c3ba7b310f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1b0d59a9a91fd7878c92b3680cde8c34896823612a2f04715c05e977c09db82\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e0a39dacbb91b7d9f00bdf78829918079f6f2e749c28f31a359064bac9ac7eb65c87e581795946814460f787e33b8829a9cf0e933a0f87dd7d48f288d45f5064\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"accessors-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"Java reflect give poor performance on getter setter an constructor calls, accessors-smart use ASM to speed up those calls.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fc814b28882dd9f2552eda21add0698f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"aca011492dfe9c26f4e0659028a4fe0970829dd8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"12314fc6881d66a413fd66370787adba16e504fbf7e138690b0f3952e3fbd321\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b21fdd3401a0557d2d04a14c27563897afe9e001fc520398e22083bc18afee5e48dd9f5fc6561d0f327a30a9303bf5cc20f0a2ce741d80b3792e258276faac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7464bf3917d11712b235c7e1af339766d01cb4b41ec98941c3c69bc4ab9a4d0e6c832cbf01482425100dc8f1611ce3a0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"be26dc2bfc5fdc1a45e14f1c2fcfe224994e66d39049e235ea83c714fb90bb685d3f2209c0d550528e2cd9b2d9d95a6e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6a914eb757ec313842f13c837eeb628e606323cc63dc24127e7a9804e2746d12\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"edbddef0538aac87bf6af714e12c4078fd6ada069b6fd0e1e5c1038b060999764e06c28b3ca38b8d540d0f60c72f7321ddc22d2537156999bad5098c89b6975a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-core\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core Jackson processing abstractions (aka Streaming API), implementation for JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c86c75392bf138d54d2a219bb1d0cbcd\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"60d600567c1862840397bf9ff5a92398edc5797b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"51fab7aad51ed588482edc507fd542747936c5094d1ab76ed21ddb63b96b610d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"112de40a31dc7d011f256f1d2fe0d9e2afc301a1f31974318f8d070c3e362b2ba96005167384244f630b915451db6694bd3cf6a9b793872351bc18f21c9de5e4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9daaf08467525e462234c53ddbf7287bcef15d8df7fbc64bcd558a91d11e8335b3a79368d194b126d3c8fb846800025b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0b4fdc8d11fc060461e74e773fce2e64d1a98bed7db6edf51784bb1b801da4bae744a2958e81c2e24cb992fec892fb6c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"751ad4f10a78cb36fccbbe1dfe208816f17619edd5adeabc86b7509201e03c3d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa5807b7d92d150fada6a4ecdbfce998bbea825a09af8381127ba3736de029ae9923f54d770b2e5c3f5c85d9b4bcf21e6893a5a3089db2d02f1432b85dfa0fe7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-core\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.xmlunit\",\n      \"name\" : \"xmlunit-core\",\n      \"version\" : \"2.9.1\",\n      \"description\" : \"XMLUnit for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"011288450a3905a7d97e3957b69e713e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e5833662d9a1279a37da3ef6f62a1da29fcd68c4\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7e70f23d4f75e05f0ee79f0f6b9e13b6cf51d34f36c5fc3a6b839429dde1efef\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1d07dc1582a1930664ab3cffd1443e85c83fec138c663f3070a9d3b283f818157b2cdd1589595867281a96d3b444b18c22c1ee3249a75c857c6ee9682785e8a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f54a506a08b66776d92d4379712ae9f7658cc89bd7b780eb629bd37143ff68e28cb2314539dc3c1ff13dc9cccba394f2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"7fd679371624f72417612491bac721a49f229744df3fc7455e5fd3983bd2de452a4eaabb707be7bac328f3beeea88d99\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c517aa9c543a4a3df361c30ba6609082a1dd5dc2abc351643ad5b733a1282773\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3797bade2087f791697f6736296381f8b158a2a93f50faeabcd96b4c9f48ad26fd78af56cc1036c449c35e624181961d54acdd7623b84c23c81c72d5d0fa57f1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"OW2\",\n      \"group\" : \"org.ow2.asm\",\n      \"name\" : \"asm\",\n      \"version\" : \"9.3\",\n      \"description\" : \"ASM, a very small and fast Java bytecode manipulation framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e1c3b96035117ab516ffe0de9bd696e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8e6300ef51c1d801a7ed62d07cd221aca3a90640\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1263369b59e29c943918de11d6d6152e2ec6085ce63e5710516f8c67d368e4bc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"04362f50a2b66934c2635196bf8e6bd2adbe4435f312d1d97f4733c911e070f5693941a70f586928437043d01d58994325e63744e71886ae53a62c824927a4d4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"304aa6673d587a68a06dd8601c6db0dc4d387f89a058b7600459522d94780e9e8d87a2778604fc41b81c43a57bf49ad6\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9744884ed03ced46ed36c68c7bb1f523678bcbb4f32ebeaa220157b8631e862d6573066dfc2092ed77dc7826ad17aef2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2be2d22fdbafe87b7cdda0498fc4f45db8d77a720b63ec1f7ffe8351e173b77b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a3ff403dd3eefbb7511d2360ab1ca3d1bf33b2f9d1c5738284be9d132eb6ad869f2d97e790ed0969132af30271e544d3725c02252267fe55e0339f89f3669ce1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"http://www.ow2.org/\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://mail.ow2.org/wws/arc/asm/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Core starter, including auto-configuration support, logging and YAML\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d9eb815815944bcdaeed5e63f32e5d7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bc03d7075fb9d9d4877218db48d5dae3dd72a65d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a25f2f4172c34f46b73fff03293370c3daf231a1db2883ef8032aa471779fb8b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"35cc80f9b10e81624324083a024c97e247e12f54762cfaadf40504903b0ebdc76d0226af1e4646bca445211b039913709ff48289dd57e27ecab18fd6e427d306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9acae9f3f77733a83d37641d3bd32d762225a08dcb20d61ff33a9038e8a4fe2dd39026bb08026cdb618437f68fc11382\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"1e605937a46c8371423b7876d5dae4363f718f70200a1276056bd6466d03096aa580708c7abc76618a141a542df29b24\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"331b3c120493fb5d9dd628beb8aa10382772a08d0a687103a2e87a4516fffde6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9f2612fbecec4664979896868e4766b1f66aaebc914e46a07a7ef7e5ff76786e5a73ae9ca5f364d23ae41f8bea2fb44e5034014950423fdc3a438ae1dc275820\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-core\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"81d2d784780b1fe54275ab4f3d0c3830\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"5b9185ee002f9e194d2cb21ddcf8bc5f3d4a69da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5d70fa6ae0548f89fb4c070423ecc2db050cebf248b0d5f3f2294375a6762382\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9fb1726f3a10f5e0bdd1cafcdc9532536679d04e5cdde9e54bdf18819ea2651bcaac0efddd6a8b5dbf3cfb8dfcd7ab0453f2ff3fa4e21a0f3796d4dd6d630433\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e644a094c17574fc9334772913aeabd6de0be8eacb0718981dbd97ee197a21f43ff3efe2c073f8863a4ff111f4ccb303\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2e8d5d4b1e202e19529270adc7992e9d187ad34bdd62ab7633359f3394059cdade69c88dddd3879dea40487cb17702da\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"25826af7f0a6fd192e83cd14481055b0c5477c325e51d17355d9ff97963380a0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0b2513e578a484562ad47a8a1a4d1fe8253a9a276fac49ea9732877d976a2d1827037caa5a6401d5659c765317acb94127e62f99373a4efea63b44ab4a1824be\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy-agent\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"The Byte Buddy agent offers convenience for attaching an agent to the local or a remote VM.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"389b6aca1ee862684592f6f041f81724\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"90ed94ac044ea8953b224304c762316e91fd6b31\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"67993a89d47ca58ff868802a4448ddd150e5fe4e5a5645ded990d7b4d557a6b9\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7f1a1310b1a0f60d6ff07dee8d9b7e404e8fb9a25a5c0c186e00cafc834e5a026a7694fb65279367dabfa1789c1f16192d0ea794b7f511f0bb3414b8d519e9a5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed1e1d594a7c2837311accf3f718cbc7c6e2034afcab13c63d72313ee1ffd18a53863f1ccd194b85b7e0ffed78bafc9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b3baeae67826ec4e4f71b2870220c362f153d2a126b04557302b5b8e24a58b9741bef7afa9c4e4f0fa1ea9371cbcb1df\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"01ccb9e430868deef5b51124073643eaf6dd2c8c7e4d6e70b59042c9d28e3361\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b621fa443ade355b10cc45329a5e0f700942dd39e633a8f2343ece00446cd42f5c1217b041a67b3143df86397c363f8dcad226f1e70b8755126512a74f878262\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-test\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring TestContext Framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fadfe62dd198a4acce4416acb28e2869\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c393079051398e02c20d8b24e02822f365123719\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2155779c3e461df55f3b093f0e6e4bda398664e3452efe599690bc9a3f1932f0\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5e6e4f76edbf17a321302bf6257c09ed7893e32c50fb3cace37b2271f3c488d397c67b5315ef3019ee6d28544f52cf593e0475bf00927cd67f0c668d6b3909a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"151df7daac9a3e3e74732405bd4feb17ad9ff3e4de196e767f39da675d4480994ed8da13e3b1b27c7b4ee9ebc17feef8\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9069193468f2ae4c65c94d3950541efe37498a4e19245ddc67909181e83e14019f956baba54da0b9d2e8a262db13abd0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"8ccf71564f5ee7e6a578031c7c8530a5ddf136cc1dce483818ebd30d53c851df\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"31049da217d1115b589780ffaa3ddfbf676cc58e70bd4cbc1f24c0cb2aea6b155539f8f9b3f6757f19719fed0a6102110f195b34cdd464b5e375132c25e7bb51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"32fd55a03f648868767c1bebedd198df\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6e5c7dd668d6349cb99e52ab8321e73479a309bc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c1a386e901fae28e493185a47c8cea988fb1a37422b353a0f8b4df2e6c5d6037\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c97a2f9eefa6f34441fc0c97744873040bbe49d335954edab43bab25876a33f4b3f11347459420569ef660449728aa093bbae5d42c0fa733a0b624706b57a65d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"873dfccaf8366ce5b14dc0b5498205debecd90ecba20b1f1c924721764d546b5b9629dd57c486e5a5a2bc38954bf3824\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"67f09e3174ae3fac6ddea13b56dcf078165e715cb18afd73d86bb980357e365cef6e62083231f09ae2accddfe62f5bcb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1c2a60003b13025c959e7728b3f4469b67bad8649d2080c0871418fb52b1c078\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7c03cfaeabed9c57b26e083bcb0ca9a114c491216fc7e9652a39a5468579175e575ace315493610fdc7711c6557eff11933fbd28f5433c237d2277bee102c5a6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"json-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"af9b7eda9c435acaf22e840991c7b10f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"57a64f421b472849c40e77d2e7cce3a141b41e99\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"432b9e545848c4141b80717b26e367f83bf33f19250a228ce75da6e967da2bc7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"56284bb3cee2bcc3684cdcc610115c7eacafdbd70aa852cb0209616b0503dfd448c5110b50e11a71b1c61a6e7ea27594ff63cc968230374555cc6f652d69d372\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fbbd6899d344c3158007f2f033165284323f1ecdfa49e17730d9d2bed8b3d77bbdc209a72a388e9e15a5bed9d9c8eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0f18f178117f8c640e7e1ac2ed4c2b28e331f658f40eac2f5974e891f7130b760e4f057859a537caaa046ba9c086a24a\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4c91eaa12f7c0ee08264ad95d016cfa41af08c963055b7f9076771da402e93e0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0c5fad6395cf3fd25c04fd1e2c915351da4849475b463e017b760ef97800addb170d11f89791dd29ab867e343c35fd1f3ea7935622ba728d789c9f2e7fd1da51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-expression\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Expression Language (SpEL)\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2f56216dc7ee08cbeafa54ccf18cad35\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"98786397734b27b7c8843a6b01a7fa34d40d6806\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fef5fb19f375a8632d2a117f4b3aed059b959e9693e90c3b7f57b7cad2f9e0b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"a28e984d9ff1d4078d57f139ff28065ffba7f325c891c74c0774cd3ccfe50a9462cd93483c28c8ca4674b581ab723687c37c5c88e7cb080823d5629fa684e7f8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a84fb64144a67b56ce322fc9f4948a9491f6f5876d198eb57c99f38540971a0779a2949b93cc5f32662f97a83823ea87\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b099ce06de6a5543e52a2d43c97c4ed6567e82263db29849ff09cf37bf48e3e9974308698c2f272187508e242f756576\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"efa3768de47e3b1ff9257f8367a528e38b3eec9c972eb7ba3dd8f60da626fb17\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"95d7011482520e797a25f9d9b8db1b1bf6c24b3ddb3ca4b70fe5a1a58ed04ea870f86f8393f884dad8b893a6fc53ad8da1b21fdc01d9169564c3dc0229824b27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Spring Boot's Actuator which provides production ready features to help you monitor and manage your application\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"59713236dc4fc4b1562a3ea9788bde1e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca17ff67e80a230f04d40d73321d623b769e361d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"31c28021755feab49cc9310a8353382b3ca35d0adf02926b83e4c44ea4942898\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"ed618c7f1e3337c90919551ad4f14996bb2a78f773ba00c1e02d5a991d1c578e940d9b73f5e01045115c7b5d3f096f8de6720ba0d28992a586ef834948f17766\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"45956cbd019f099f96f36391c98fd23ea32698035f90f6e4e4df0d9a43dc03ef6db2954c2871da76a038511280591b43\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3a08b673deb39ab5db9561281245b76e9f57410601e5ce4040cefedb02e2a19abb45a98d2de170fbbac7b7f0b93eceb3\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"12151432b32e26bab903572023ea022757a31177e4a6315d8fcd15bbbf34731c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"911f109b63d07f20de51f8a2de8799e32fdff05a52def36d408cb1da72a3bb63ff0878f850a7ad1cc9e85393f24ac58c6b8dd4068f11d9e70bc1e130974db00f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-beans\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Beans\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5ee147f2234968eeab4b469af4d3b5f1\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abf52f2254975a3b1e95b2b63fb8b01d891cdc51\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"742baa41c1b0282ef01b3d542dc1b1de71db2578bd9ddd9a7d57fb191234b194\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"efd0eb5a073c899515ae144a4fcb4fc97cc53cbd4236d0e6a30df8fa8873fcd9bc509bc3fa88d1bff86a94dc3dbc5106374d0117f64ec8df9e6affe8f98aaa07\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6214558d1024fa3b5545079268b0b2fbeda93768a0665d617612ddf4e42e11b770c38c05cb86e3ae558025afa67beea5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8170ccea30165f25c533e27c0de38b590ca72f285cfc365c60e97745e78532213d6c93bdbea56f561dd180297a8c5ab4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2761e0814e167de13ed08ce748880006407eda2fa744a347f57684c2bc9bb6fe\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ecdeb4cd558af513ed381942f35bd2d8dfa9b0db446dbc8c5326656ade960682283c71fcaae5578ca431f705f1a86041b0764bd453f30e738be65c4f0bbf37d1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\"\n    }\n  ],\n  \"dependencies\" : [\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n        \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n        \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n        \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n        \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n        \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n        \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n        \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n        \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n        \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n        \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n        \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"dependsOn\" : [ ]\n    }\n  ]\n}"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/resources/org/springframework/boot/actuate/sbom/spdx.json",
    "content": "{\n  \"spdxVersion\": \"SPDX-2.3\",\n  \"dataLicense\": \"CC0-1.0\",\n  \"SPDXID\": \"SPDXRef-DOCUMENT\",\n  \"name\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n  \"documentNamespace\": \"https://anchore.com/syft/file/sbom-test-gradle-0.0.1-SNAPSHOT.jar-d1583014-0f58-4476-8f5f-dbbcd2df5102\",\n  \"creationInfo\": {\n    \"licenseListVersion\": \"3.23\",\n    \"creators\": [\n      \"Organization: Anchore, Inc\",\n      \"Tool: syft-0.105.0\"\n    ],\n    \"created\": \"2024-02-15T12:39:33Z\"\n  },\n  \"packages\": [\n    {\n      \"name\": \"HdrHistogram\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-HdrHistogram-2c7953c2c68ec3bc\",\n      \"versionInfo\": \"2.1.12\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-d509473237fa971bc0a8ad7708f3cd561fcf86ef2e611701ed8eec621fd6575e\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:HdrHistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:hdrhistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12\"\n        }\n      ]\n    },\n    {\n      \"name\": \"LatencyUtils\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-LatencyUtils-f9418986cc24a153\",\n      \"versionInfo\": \"2.0.3\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-Public-Domain--per-Creative-Commons-CC0\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:LatencyUtils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:latencyutils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-annotations\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-annotations-c1e7975b6f55f7e8\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"fd441d574a71e7d10a4f73de6609f881d8cdfeec\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-annotations:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_annotations:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-core-0408f25059f495c5\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"9456bb3cdd0f79f91a5f730a1b1bb041a380c91f\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-databind\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-databind-9ad3756f611d1ed2\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"02a16efeb840c45af1e2f31753dfe76795278b73\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-databind:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_databind:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-datatype-jdk8\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-datatype-jdk8-846731ed2e85561c\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"695d9b8639cfc7a42a0507708cef2366fe492a44\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-datatype-jsr310\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-datatype-jsr310-1347581c05f302c0\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"36a418325c618e440e5ccb80b75c705d894f50bd\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-module-parameter-names\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-module-parameter-names-f5bca9d628ab321f\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"9e167afd1596e6a6aa6fe4e1af17f4ce8be0676f\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter-names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter-names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter_names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter_names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter-names:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter_names:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:module:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jakarta.annotation-api\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jakarta.annotation-api-77a5bf527533d628\",\n      \"versionInfo\": \"2.1.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-85a9a90b97292e5203565dd71a1a086ca3fe4d8ccea74453294fee37d5b0c7ae\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:glassfish:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:glassfish:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jul-to-slf4j\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jul-to-slf4j-598311f4a5b2a501\",\n      \"versionInfo\": \"2.0.11\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"279356f8e873b1a26badd8bbb3284b5c3b22c770\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.opensource.org-licenses-mit-license.php\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to-slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to-slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to_slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to_slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.11\"\n        }\n      ]\n    },\n    {\n      \"name\": \"log4j-api\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-log4j-api-c404b33d3a8ce0d8\",\n      \"versionInfo\": \"2.22.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"bea6fede6328fabafd7e68363161a7ea6605abd1\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-bc2074dd7e94ae9ffbcea3c53de6625b1b651c330895f46cf72d207c3025b98b\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j-api:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j_api:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:api:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.logging.log4j/log4j-api@2.22.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"log4j-to-slf4j\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-log4j-to-slf4j-860f45be6a175d16\",\n      \"versionInfo\": \"2.22.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"b5e67b6acac768bfec1d1d6991504f45453abcad\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-bc2074dd7e94ae9ffbcea3c53de6625b1b651c330895f46cf72d207c3025b98b\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j-to-slf4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j_to_slf4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:slf4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.22.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"logback-classic\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-logback-classic-d91fe3ae6bb15cad\",\n      \"versionInfo\": \"1.4.14\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-b997c307e688e15a53c7603c100d346cb7dc9726146cb5644d66bddc7ed1c8ca\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-classic:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-classic:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_classic:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_classic:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/ch.qos.logback/logback-classic@1.4.14\"\n        }\n      ]\n    },\n    {\n      \"name\": \"logback-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-logback-core-3748310e1aac44ea\",\n      \"versionInfo\": \"1.4.14\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-b997c307e688e15a53c7603c100d346cb7dc9726146cb5644d66bddc7ed1c8ca\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-core:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-core:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_core:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_core:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/ch.qos.logback/logback-core@1.4.14\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-commons\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-commons-c46f369578c77c43\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"e738daf6678eedf8e0c40a782bdb0df064a391e5\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-commons@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-core-3c0d8567351e2ae4\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"49d54a8ed6d3266b4f2691027d95144e946bbe36\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-core@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-jakarta9\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-jakarta9-f4ea2c844b65a026\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"74087b670cad9f9883228ee2aa871f51b53f827a\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-jakarta9@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-observation\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-observation-26b8a84479010ca8\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"c06e5e0f9b6edc9c0c0ac3dd46a2117ce6f16a9d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-observation@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"sbom-test-gradle\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-sbom-test-gradle-93ed082a147d9796\",\n      \"versionInfo\": \"0.0.1-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"8ccd6688e9d8e15d18e0f10967867e5e30729a4c\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot.loader.launch.JarLauncher/sbom-test-gradle@0.0.1-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"slf4j-api\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-slf4j-api-44752cfa6770756d\",\n      \"versionInfo\": \"2.0.11\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"ad96c3f8cf895e696dd35c2bc8e8ebe710be9e6d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.opensource.org-licenses-mit-license.php\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j-api:slf4j-api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j-api:slf4j_api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j_api:slf4j-api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j_api:slf4j_api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:slf4j-api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:slf4j_api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.slf4j/slf4j-api@2.0.11\"\n        }\n      ]\n    },\n    {\n      \"name\": \"snakeyaml\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-snakeyaml-f4585c65c0a5b26a\",\n      \"versionInfo\": \"2.2\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:snakeyaml:snakeyaml:2.2:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:yaml:snakeyaml:2.2:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.yaml/snakeyaml@2.2\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-aop\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-aop-1e7758a78bbc15ee\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"b02165904562fc487cde57ca75e063561d905f74\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-aop@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-beans\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-beans-bb7e773a923726bb\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"fa8be0f856958fdd33eef9e718b3a65f7130bbd2\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-beans@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-a11948291446c2f5\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d882660ea3deafe921faba8b17e7d94ef9556c47\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-actuator\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-actuator-f83d629168e25cce\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d0d018780795da57afa8edae7436646bccd55722\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-actuator-autoconfigure\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-actuator-autoconfigure-b8eb893518786bb8\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"8b8f74be822e6f2ab120ea0687acf629ef114399\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-autoconfigure\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-autoconfigure-b40bdc90eb8832a3\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"31a960bb63af836f35760077af8ef58d24b548e3\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-jarmode-layertools\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-jarmode-layertools-8069f3f866b2e657\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d86f1782ad3d9ee047863a5023aaa22f858cd9a4\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode-layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode_layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-jarmode-layertools@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-context\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-context-3d5d71e0e85398af\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"75440f70a649ca15948af5923ebdef345848a856\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-context@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-core-519fe54307d2d43d\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"27d0900a14e240a7311c979e7b30cf65f9de9074\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-core@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-expression\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-expression-546794e924e39088\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"a5d7041ca11fd188e9d17ac8a795eabed8be55e4\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-expression@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-jcl\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-jcl-173ea637a5756944\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"604cea28d23d8027a31c35f372d2b8d0fdec211d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-jcl@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-web\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-web-adc63cefcede34fc\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"c0600dcd73db226c3d121af16d6a155ecee08d30\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-web@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-webmvc\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-webmvc-940aed7082581b67\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"34a510cf565bec1c2f74f049b1730b22f877bd37\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-webmvc@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"tomcat-embed-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-tomcat-embed-core-a753aca6ee68c738\",\n      \"versionInfo\": \"10.1.18\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"bff6c34649d1dd7b509e819794d73ba795947dcf\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat-embed-core:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat_embed_core:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.18\"\n        }\n      ]\n    },\n    {\n      \"name\": \"tomcat-embed-el\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-tomcat-embed-el-7a59d22722f7701b\",\n      \"versionInfo\": \"10.1.18\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"b2c4dc05abd363c63b245523bb071727aa2f1046\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat-embed-el:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat_embed_el:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.18\"\n        }\n      ]\n    },\n    {\n      \"name\": \"tomcat-embed-websocket\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-tomcat-embed-websocket-6c04f8ee22f9157e\",\n      \"versionInfo\": \"10.1.18\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"83a3bc6898f2ceed2357ba231a5e83dc2016d454\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat-embed-websocket:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat_embed_websocket:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.18\"\n        }\n      ]\n    },\n    {\n      \"name\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"SPDXID\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"versionInfo\": \"sha256:f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA256\",\n          \"checksumValue\": \"f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\"\n        }\n      ],\n      \"primaryPackagePurpose\": \"FILE\"\n    }\n  ],\n  \"files\": [\n    {\n      \"fileName\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"SPDXID\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"0000000000000000000000000000000000000000\"\n        }\n      ],\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"copyrightText\": \"\"\n    }\n  ],\n  \"hasExtractedLicensingInfos\": [\n    {\n      \"licenseId\": \"LicenseRef-85a9a90b97292e5203565dd71a1a086ca3fe4d8ccea74453294fee37d5b0c7ae\",\n      \"extractedText\": \"http://www.eclipse.org/legal/epl-2.0, https://www.gnu.org/software/classpath/license.html\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-Public-Domain--per-Creative-Commons-CC0\",\n      \"extractedText\": \"Public Domain, per Creative Commons CC0\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-b997c307e688e15a53c7603c100d346cb7dc9726146cb5644d66bddc7ed1c8ca\",\n      \"extractedText\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-bc2074dd7e94ae9ffbcea3c53de6625b1b651c330895f46cf72d207c3025b98b\",\n      \"extractedText\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-d509473237fa971bc0a8ad7708f3cd561fcf86ef2e611701ed8eec621fd6575e\",\n      \"extractedText\": \"http://creativecommons.org/publicdomain/zero/1.0/, https://opensource.org/licenses/BSD-2-Clause\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"extractedText\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-http---www.opensource.org-licenses-mit-license.php\",\n      \"extractedText\": \"http://www.opensource.org/licenses/mit-license.php\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"extractedText\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n    }\n  ],\n  \"relationships\": [\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-core-0408f25059f495c5\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-datatype-jsr310-1347581c05f302c0\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-jcl-173ea637a5756944\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-aop-1e7758a78bbc15ee\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-observation-26b8a84479010ca8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-HdrHistogram-2c7953c2c68ec3bc\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-logback-core-3748310e1aac44ea\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-core-3c0d8567351e2ae4\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-context-3d5d71e0e85398af\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-slf4j-api-44752cfa6770756d\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-core-519fe54307d2d43d\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-expression-546794e924e39088\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jul-to-slf4j-598311f4a5b2a501\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-tomcat-embed-websocket-6c04f8ee22f9157e\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jakarta.annotation-api-77a5bf527533d628\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-tomcat-embed-el-7a59d22722f7701b\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-jarmode-layertools-8069f3f866b2e657\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-datatype-jdk8-846731ed2e85561c\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-log4j-to-slf4j-860f45be6a175d16\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-sbom-test-gradle-93ed082a147d9796\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-webmvc-940aed7082581b67\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-databind-9ad3756f611d1ed2\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-a11948291446c2f5\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-tomcat-embed-core-a753aca6ee68c738\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-web-adc63cefcede34fc\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-autoconfigure-b40bdc90eb8832a3\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-actuator-autoconfigure-b8eb893518786bb8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-beans-bb7e773a923726bb\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-annotations-c1e7975b6f55f7e8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-log4j-api-c404b33d3a8ce0d8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-commons-c46f369578c77c43\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-logback-classic-d91fe3ae6bb15cad\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-snakeyaml-f4585c65c0a5b26a\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-jakarta9-f4ea2c844b65a026\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-module-parameter-names-f5bca9d628ab321f\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-actuator-f83d629168e25cce\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-LatencyUtils-f9418986cc24a153\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-HdrHistogram-2c7953c2c68ec3bc\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-LatencyUtils-f9418986cc24a153\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-annotations-c1e7975b6f55f7e8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-core-0408f25059f495c5\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-databind-9ad3756f611d1ed2\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-datatype-jdk8-846731ed2e85561c\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-datatype-jsr310-1347581c05f302c0\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-module-parameter-names-f5bca9d628ab321f\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jakarta.annotation-api-77a5bf527533d628\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jul-to-slf4j-598311f4a5b2a501\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-log4j-api-c404b33d3a8ce0d8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-log4j-to-slf4j-860f45be6a175d16\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-logback-classic-d91fe3ae6bb15cad\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-logback-core-3748310e1aac44ea\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-commons-c46f369578c77c43\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-core-3c0d8567351e2ae4\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-jakarta9-f4ea2c844b65a026\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-observation-26b8a84479010ca8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-sbom-test-gradle-93ed082a147d9796\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-slf4j-api-44752cfa6770756d\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-snakeyaml-f4585c65c0a5b26a\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-aop-1e7758a78bbc15ee\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-beans-bb7e773a923726bb\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-a11948291446c2f5\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-actuator-f83d629168e25cce\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-actuator-autoconfigure-b8eb893518786bb8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-autoconfigure-b40bdc90eb8832a3\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-jarmode-layertools-8069f3f866b2e657\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-context-3d5d71e0e85398af\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-core-519fe54307d2d43d\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-expression-546794e924e39088\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-jcl-173ea637a5756944\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-web-adc63cefcede34fc\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-webmvc-940aed7082581b67\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-tomcat-embed-core-a753aca6ee68c738\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-tomcat-embed-el-7a59d22722f7701b\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-tomcat-embed-websocket-6c04f8ee22f9157e\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DOCUMENT\",\n      \"relatedSpdxElement\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relationshipType\": \"DESCRIBES\"\n    }\n  ]\n}\n"
  },
  {
    "path": "integration-test/spring-boot-actuator-integration-tests/src/test/resources/org/springframework/boot/actuate/sbom/syft.json",
    "content": "{\n  \"artifacts\": [\n    {\n      \"id\": \"2c7953c2c68ec3bc\",\n      \"name\": \"HdrHistogram\",\n      \"version\": \"2.1.12\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/HdrHistogram-2.1.12.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://creativecommons.org/publicdomain/zero/1.0/, https://opensource.org/licenses/BSD-2-Clause\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/HdrHistogram-2.1.12.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:HdrHistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:hdrhistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/HdrHistogram-2.1.12.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1575980548657\"\n            },\n            {\n              \"key\": \"Build-Jdk\",\n              \"value\": \"1.8.0_232\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"gil\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"HdrHistogram supports the recording and analyzing sampled data value        counts across a configurable integer value range with configurable value        precision within the range. Value precision is expressed as the number of        significant digits in the value recording, and provides control over value        quantization behavior across the value range and the subsequent value        resolutionat any given level.\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://creativecommons.org/publicdomain/zero/1.0/, https://opensource.org/licenses/BSD-2-Clause\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"HdrHistogram\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.hdrhistogram.HdrHistogram\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.1.12\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.HdrHistogram;version=\\\"2.1.12\\\",org.HdrHistogram.packedarray;version=\\\"2.1.12\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"HdrHistogram\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"org.hdrhistogram\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.1.12\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.7))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"HdrHistogram\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.1.12\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-2.3.0.201405100607\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.hdrhistogram/HdrHistogram/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.hdrhistogram\",\n          \"artifactId\": \"HdrHistogram\",\n          \"version\": \"2.1.12\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f9418986cc24a153\",\n      \"name\": \"LatencyUtils\",\n      \"version\": \"2.0.3\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/LatencyUtils-2.0.3.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Public Domain, per Creative Commons CC0\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [\n            \"http://creativecommons.org/publicdomain/zero/1.0/\"\n          ],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/LatencyUtils-2.0.3.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:LatencyUtils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:latencyutils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/LatencyUtils-2.0.3.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Archiver-Version\",\n              \"value\": \"Plexus Archiver\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"gil\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven 3.2.3\"\n            },\n            {\n              \"key\": \"Build-Jdk\",\n              \"value\": \"1.8.0_45\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.latencyutils/LatencyUtils/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.latencyutils\",\n          \"artifactId\": \"LatencyUtils\",\n          \"version\": \"2.0.3\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"c1e7975b6f55f7e8\",\n      \"name\": \"jackson-annotations\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-annotations-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-annotations-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-annotations:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_annotations:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-annotations-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Core annotations used for value types, used by Jackson data binding package.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson-annotations\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.core.jackson-annotations\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.core\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson-annotations\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.6))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"2.16.1\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson-annotations\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.6\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.6\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.core/jackson-annotations/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.core\",\n          \"artifactId\": \"jackson-annotations\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"fd441d574a71e7d10a4f73de6609f881d8cdfeec\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"0408f25059f495c5\",\n      \"name\": \"jackson-core\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-core-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-core-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-core-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.core.jackson-core\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.core\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson-core\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-core\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.async;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.base;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.exc;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.format;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io.schubfach;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.json;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.json.async;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.sym;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.core;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core.async,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.format,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.json,com.fasterxml.jackson.core.sym,com.fasterxml.jackson.core.type,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.async;version=\\\"2.16.1\\\",com.fasterxml.jackson.core.base;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.json,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.exc;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.filter;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.format;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core\\\",com.fasterxml.jackson.core.io;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.io.schubfach;version=\\\"2.16.1\\\",com.fasterxml.jackson.core.json;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.format,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.sym,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.json.async;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.async,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.sym,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.sym;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.type;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core\\\",com.fasterxml.jackson.core.util;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.async,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.io\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson-core\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Core Jackson processing abstractions (aka Streaming API), implementation for JSON\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson-core\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.core/jackson-core/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.core\",\n          \"artifactId\": \"jackson-core\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"9456bb3cdd0f79f91a5f730a1b1bb041a380c91f\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"9ad3756f611d1ed2\",\n      \"name\": \"jackson-databind\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-databind-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-databind-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-databind:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_databind:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-databind-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.core.jackson-databind\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.core\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"jackson-databind\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.base;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.exc;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.filter;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.format;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.json;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.exc;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ext;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.introspect;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jdk14;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.json;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonschema;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.node;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util.internal;version=\\\"[2.16,3)\\\",javax.xml.datatype,javax.xml.namespace,javax.xml.parsers,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.w3c.dom,org.xml.sax,org.w3c.dom.bootstrap;resolution:=optional\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.databind;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.filter,com.fasterxml.jackson.core.format,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.type,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.impl,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsonschema,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.jsontype.impl,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.annotation;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.cfg;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.deser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.format,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser.impl,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.deser.impl;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.impl,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.exc;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.introspect\\\",com.fasterxml.jackson.databind.ext;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.std,javax.xml.datatype,javax.xml.parsers,javax.xml.transform,org.w3c.dom\\\",com.fasterxml.jackson.databind.introspect;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.jsontype.impl,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.jdk14;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect\\\",com.fasterxml.jackson.databind.json;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.json,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind\\\",com.fasterxml.jackson.databind.jsonschema;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.node\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect\\\",com.fasterxml.jackson.databind.jsontype.impl;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.module;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.type\\\",com.fasterxml.jackson.databind.node;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.ser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.io,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsonschema,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.ser.impl;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.io,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsonschema,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.type;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.util;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.json,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util.internal\\\",com.fasterxml.jackson.databind.util.internal;version=\\\"2.16.1\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"jackson-databind\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"General data-binding functionality for Jackson: works on core streaming API\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"jackson-databind\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.core/jackson-databind/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.core\",\n          \"artifactId\": \"jackson-databind\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"02a16efeb840c45af1e2f31753dfe76795278b73\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"846731ed2e85561c\",\n      \"name\": \"jackson-datatype-jdk8\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.datatype.jackson-datatype-jdk8\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.datatype\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson datatype: jdk8\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.datatype.jdk8;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.io,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson datatype: jdk8\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Add-on module for Jackson (http://jackson.codehaus.org) to supportJDK 8 data types.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson datatype: jdk8\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.datatype\",\n          \"artifactId\": \"jackson-datatype-jdk8\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"695d9b8639cfc7a42a0507708cef2366fe492a44\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"1347581c05f302c0\",\n      \"name\": \"jackson-datatype-jsr310\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.datatype.jackson-datatype-jsr310\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.datatype\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson datatype: JSR310\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.introspect;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.module;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.node;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.deser.key;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.ser.key;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.util;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.datatype.jsr310;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.module\\\",com.fasterxml.jackson.datatype.jsr310.deser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.datatype.jsr310,com.fasterxml.jackson.datatype.jsr310.util\\\",com.fasterxml.jackson.datatype.jsr310.deser.key;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.databind\\\",com.fasterxml.jackson.datatype.jsr310.ser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.datatype.jsr310.util\\\",com.fasterxml.jackson.datatype.jsr310.ser.key;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind\\\",com.fasterxml.jackson.datatype.jsr310.util;version=\\\"2.16.1\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson datatype: JSR310\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Add-on module to support JSR-310 (Java 8 Date & Time API) data types.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson datatype: JSR310\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.datatype\",\n          \"artifactId\": \"jackson-datatype-jsr310\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"36a418325c618e440e5ccb80b75c705d894f50bd\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f5bca9d628ab321f\",\n      \"name\": \"jackson-module-parameter-names\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter-names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter-names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter_names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter_names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter-names:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter_names:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:module:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.module.jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.module\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.introspect;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.module;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.module.paramnames;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.module\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Add-on module for Jackson (http://jackson.codehaus.org) to supportintrospection of method/constructor parameter names,without having to add explicit property name annotation.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.module/jackson-module-parameter-names/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.module\",\n          \"artifactId\": \"jackson-module-parameter-names\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"9e167afd1596e6a6aa6fe4e1af17f4ce8be0676f\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"77a5bf527533d628\",\n      \"name\": \"jakarta.annotation-api\",\n      \"version\": \"2.1.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.eclipse.org/legal/epl-2.0, https://www.gnu.org/software/classpath/license.html\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:glassfish:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:glassfish:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Jakarta Annotations API\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://www.eclipse.org\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.eclipse.org/legal/epl-2.0, https://www.gnu.org/software/classpath/license.html\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jakarta Annotations API\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"jakarta.annotation-api\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"Eclipse Foundation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.1.1\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.annotation;version=\\\"2.1.1\\\",jakarta.annotation.security;version=\\\"2.1.1\\\",jakarta.annotation.sql;version=\\\"2.1.1\\\"\"\n            },\n            {\n              \"key\": \"Extension-Name\",\n              \"value\": \"jakarta.annotation\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Eclipse Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"org.glassfish\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.1.1\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Eclipse Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/jakarta.annotation/jakarta.annotation-api/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"jakarta.annotation\",\n          \"artifactId\": \"jakarta.annotation-api\",\n          \"version\": \"2.1.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"598311f4a5b2a501\",\n      \"name\": \"jul-to-slf4j\",\n      \"version\": \"2.0.11\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jul-to-slf4j-2.0.11.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.opensource.org/licenses/mit-license.php\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jul-to-slf4j-2.0.11.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to-slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to-slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to_slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to_slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.11\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jul-to-slf4j-2.0.11.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"JUL to SLF4J bridge\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.slf4j.org\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.opensource.org/licenses/mit-license.php\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"JUL to SLF4J bridge\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"jul.to.slf4j\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"SLF4J.ORG\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.slf4j.bridge;uses:=\\\"org.slf4j,org.slf4j.spi\\\";version=\\\"2.0.11\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"jul-to-slf4j\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.slf4j;version=\\\"[2.0,3)\\\",org.slf4j.spi;version=\\\"[2.0,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"8\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.slf4j/jul-to-slf4j/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.slf4j\",\n          \"artifactId\": \"jul-to-slf4j\",\n          \"version\": \"2.0.11\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"279356f8e873b1a26badd8bbb3284b5c3b22c770\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"c404b33d3a8ce0d8\",\n      \"name\": \"log4j-api\",\n      \"version\": \"2.22.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-api-2.22.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-api-2.22.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j-api:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j_api:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:api:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.logging.log4j/log4j-api@2.22.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-api-2.22.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Maven JAR Plugin 3.3.0\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Log4j API\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.22\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Log4j API\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-ActivationPolicy\",\n              \"value\": \"lazy\"\n            },\n            {\n              \"key\": \"Bundle-Activator\",\n              \"value\": \"org.apache.logging.log4j.util.Activator\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"The Apache Log4j API\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Apache Log4j API\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.logging.log4j.api\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.apache.logging.log4j;version=\\\"2.20.2\\\";uses:=\\\"org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.apache.logging.log4j.util\\\",org.apache.logging.log4j.message;version=\\\"2.22.0\\\";uses:=\\\"org.apache.logging.log4j.util\\\",org.apache.logging.log4j.simple;version=\\\"2.20.2\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.apache.logging.log4j.util\\\",org.apache.logging.log4j.spi;version=\\\"2.20.1\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.util\\\",org.apache.logging.log4j.status;version=\\\"2.20.2\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.spi\\\",org.apache.logging.log4j.util;version=\\\"2.22.0\\\";uses:=\\\"org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.osgi.framework\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.apache.logging.log4j.simple;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.status;version=\\\"[2.20,3)\\\",org.osgi.framework;version=\\\"[1.8,2)\\\",org.osgi.framework.wiring;version=\\\"[1.2,2)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.logging.log4j.internal,org.apache.logging.log4j.util.internal\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.service;objectClass:List<String>=\\\"org.apache.logging.log4j.util.PropertySource\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"org.apache.logging.log4j.util.PropertySource\\\";register:=\\\"org.apache.logging.log4j.util.EnvironmentPropertySource\\\",osgi.serviceloader;osgi.serviceloader=\\\"org.apache.logging.log4j.util.PropertySource\\\";register:=\\\"org.apache.logging.log4j.util.SystemPropertiesPropertySource\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.logging.log4j.message.ThreadDumpMessage$ThreadInfoFactory)\\\";osgi.serviceloader=\\\"org.apache.logging.log4j.message.ThreadDumpMessage$ThreadInfoFactory\\\";cardinality:=single;resolution:=optional,osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.logging.log4j.spi.Provider)\\\";osgi.serviceloader=\\\"org.apache.logging.log4j.spi.Provider\\\";cardinality:=multiple;resolution:=optional,osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.logging.log4j.util.PropertySource)\\\";osgi.serviceloader=\\\"org.apache.logging.log4j.util.PropertySource\\\";cardinality:=multiple;resolution:=optional,osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.apache.logging.log4j/log4j-api/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.apache.logging.log4j\",\n          \"artifactId\": \"log4j-api\",\n          \"version\": \"2.22.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"bea6fede6328fabafd7e68363161a7ea6605abd1\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"860f45be6a175d16\",\n      \"name\": \"log4j-to-slf4j\",\n      \"version\": \"2.22.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-to-slf4j-2.22.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-to-slf4j-2.22.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j-to-slf4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j_to_slf4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:slf4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.22.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-to-slf4j-2.22.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Maven JAR Plugin 3.3.0\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Log4j to SLF4J Adapter\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.22\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Log4j to SLF4J Adapter\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-ActivationPolicy\",\n              \"value\": \"lazy\"\n            },\n            {\n              \"key\": \"Bundle-Activator\",\n              \"value\": \"org.apache.logging.slf4j.Activator\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"The Apache Log4j binding between Log4j 2 API and SLF4J.\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Apache Log4j to SLF4J Adapter\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.logging.log4j.to.slf4j\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.apache.logging.slf4j;version=\\\"2.20.1\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.apache.logging.log4j.util,org.slf4j\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.slf4j;version=\\\"[1.7,3)\\\",org.slf4j.spi;version=\\\"[1.7,3)\\\",org.apache.logging.log4j;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.message;version=\\\"[2.22,3)\\\",org.apache.logging.log4j.spi;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.status;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.util;version=\\\"[2.22,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"false\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.service;objectClass:List<String>=\\\"org.apache.logging.log4j.spi.Provider\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"org.apache.logging.log4j.spi.Provider\\\";register:=\\\"org.apache.logging.slf4j.SLF4JProvider\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.apache.logging.log4j/log4j-to-slf4j/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.apache.logging.log4j\",\n          \"artifactId\": \"log4j-to-slf4j\",\n          \"version\": \"2.22.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"b5e67b6acac768bfec1d1d6991504f45453abcad\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"d91fe3ae6bb15cad\",\n      \"name\": \"logback-classic\",\n      \"version\": \"1.4.14\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-classic-1.4.14.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-classic-1.4.14.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:logback-classic:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback-classic:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_classic:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_classic:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/ch.qos.logback/logback-classic@1.4.14\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-classic-1.4.14.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Logback Classic Module\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"1.4\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Logback Classic Module\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"logback-classic module\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.qos.ch\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Logback Classic Module\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"ch.qos.logback.classic\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"ch.qos.logback.classic;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.classic.turbo,ch.qos.logback.core,ch.qos.logback.core.pattern,ch.qos.logback.core.spi,ch.qos.logback.core.status,jakarta.servlet.http,org.slf4j,org.slf4j.event,org.slf4j.spi\\\",ch.qos.logback.classic.boolex;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.boolex\\\",ch.qos.logback.classic.db.script;version=\\\"1.4.14\\\",ch.qos.logback.classic.encoder;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.encoder,ch.qos.logback.core.pattern\\\",ch.qos.logback.classic.filter;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core.filter,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.helpers;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core,jakarta.servlet\\\",ch.qos.logback.classic.html;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.html,ch.qos.logback.core.pattern\\\",ch.qos.logback.classic.joran;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core,ch.qos.logback.core.joran,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.joran.action;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,org.xml.sax\\\",ch.qos.logback.classic.joran.sanity;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.sanity,ch.qos.logback.core.model,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.joran.serializedModel;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.net\\\",ch.qos.logback.classic.jul;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.layout;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core\\\",ch.qos.logback.classic.log4j;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core\\\",ch.qos.logback.classic.model;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model,ch.qos.logback.core.model.processor\\\",ch.qos.logback.classic.model.processor;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.model,ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util,ch.qos.logback.core.model,ch.qos.logback.core.model.processor\\\",ch.qos.logback.classic.model.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model\\\",ch.qos.logback.classic.net;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core,ch.qos.logback.core.boolex,ch.qos.logback.core.helpers,ch.qos.logback.core.joran.spi,ch.qos.logback.core.net,ch.qos.logback.core.net.ssl,ch.qos.logback.core.pattern,ch.qos.logback.core.spi,javax.net,javax.net.ssl\\\",ch.qos.logback.classic.net.server;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.net,ch.qos.logback.classic.spi,ch.qos.logback.core.net,ch.qos.logback.core.net.server,ch.qos.logback.core.net.ssl,ch.qos.logback.core.spi,javax.net\\\",ch.qos.logback.classic.pattern;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core,ch.qos.logback.core.pattern,org.slf4j\\\",ch.qos.logback.classic.pattern.color;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.pattern.color\\\",ch.qos.logback.classic.selector;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic\\\",ch.qos.logback.classic.selector.servlet;version=\\\"1.4.14\\\";uses:=\\\"jakarta.servlet\\\",ch.qos.logback.classic.servlet;version=\\\"1.4.14\\\";uses:=\\\"jakarta.servlet\\\",ch.qos.logback.classic.sift;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.joran.spi,ch.qos.logback.core.sift\\\",ch.qos.logback.classic.spi;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.turbo,ch.qos.logback.core,ch.qos.logback.core.spi,org.slf4j,org.slf4j.event,org.slf4j.spi\\\",ch.qos.logback.classic.turbo;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.core.spi,org.slf4j\\\",ch.qos.logback.classic.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.selector,ch.qos.logback.classic.spi,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.slf4j.spi\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"ch.qos.logback.classic;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.boolex;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.encoder;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran.action;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran.sanity;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran.serializedModel;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.layout;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.model;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.model.processor;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.net;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.net.server;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.pattern;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.pattern.color;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.selector;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.turbo;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.util;version=\\\"[1.4,2)\\\",jakarta.servlet;resolution:=optional;version=\\\"[5.0,6)\\\",jakarta.servlet.http;resolution:=optional;version=\\\"[5.0,6)\\\",org.xml.sax;resolution:=optional,ch.qos.logback.core;version=\\\"[1.4,2)\\\",ch.qos.logback.core.boolex;version=\\\"[1.4,2)\\\",ch.qos.logback.core.encoder;version=\\\"[1.4,2)\\\",ch.qos.logback.core.filter;version=\\\"[1.4,2)\\\",ch.qos.logback.core.helpers;version=\\\"[1.4,2)\\\",ch.qos.logback.core.html;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.action;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.sanity;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.processor;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net.server;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net.ssl;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.color;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.parser;version=\\\"[1.4,2)\\\",ch.qos.logback.core.sift;version=\\\"[1.4,2)\\\",ch.qos.logback.core.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.status;version=\\\"[1.4,2)\\\",ch.qos.logback.core.util;version=\\\"[1.4,2)\\\",java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.reflect,java.net,java.nio.charset,java.security,java.text,java.time,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.function,java.util.logging,java.util.regex,javax.management,javax.naming,javax.net,javax.net.ssl,org.slf4j;version=\\\"[2.0,3)\\\",org.slf4j.event;version=\\\"[2.0,3)\\\",org.slf4j.helpers;version=\\\"[2.0,3)\\\",org.slf4j.spi;version=\\\"[2.0,3)\\\",sun.reflect;resolution:=optional,ch.qos.logback.core.rolling;version=\\\"[1.4,2)\\\",ch.qos.logback.core.rolling.helper;version=\\\"[1.4,2)\\\",ch.qos.logback.core.read;version=\\\"[1.4,2)\\\"\"\n            },\n            {\n              \"key\": \"Originally-Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.service;objectClass:List<String>=\\\"jakarta.servlet.ServletContainerInitializer\\\";effective:=active,osgi.service;objectClass:List<String>=\\\"org.slf4j.spi.SLF4JServiceProvider\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"jakarta.servlet.ServletContainerInitializer\\\";register:=\\\"ch.qos.logback.classic.servlet.LogbackServletContainerInitializer\\\",osgi.serviceloader;osgi.serviceloader=\\\"org.slf4j.spi.SLF4JServiceProvider\\\";register:=\\\"ch.qos.logback.classic.spi.LogbackServiceProvider\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=ch.qos.logback.classic.spi.Configurator)\\\";osgi.serviceloader=\\\"ch.qos.logback.classic.spi.Configurator\\\";resolution:=optional;cardinality:=multiple,osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=11))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/ch.qos.logback/logback-classic/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"ch.qos.logback\",\n          \"artifactId\": \"logback-classic\",\n          \"version\": \"1.4.14\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"3748310e1aac44ea\",\n      \"name\": \"logback-core\",\n      \"version\": \"1.4.14\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-core-1.4.14.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-core-1.4.14.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:logback-core:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback-core:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_core:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_core:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/ch.qos.logback/logback-core@1.4.14\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-core-1.4.14.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Logback Core Module\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"1.4\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Logback Core Module\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"logback-core module\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.qos.ch\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Logback Core Module\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"ch.qos.logback.core\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"ch.qos.logback.core;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.encoder,ch.qos.logback.core.filter,ch.qos.logback.core.helpers,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,ch.qos.logback.core.status,ch.qos.logback.core.util\\\",ch.qos.logback.core.boolex;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.spi\\\",ch.qos.logback.core.encoder;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.spi\\\",ch.qos.logback.core.filter;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.boolex,ch.qos.logback.core.spi\\\",ch.qos.logback.core.helpers;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.hook;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.html;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.pattern\\\",ch.qos.logback.core.joran;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.event,ch.qos.logback.core.joran.sanity,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util.beans,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,org.xml.sax\\\",ch.qos.logback.core.joran.action;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,ch.qos.logback.core.util,org.xml.sax\\\",ch.qos.logback.core.joran.conditional;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,ch.qos.logback.core.spi,org.codehaus.commons.compiler,org.xml.sax\\\",ch.qos.logback.core.joran.event;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.xml.sax,org.xml.sax.helpers\\\",ch.qos.logback.core.joran.event.stax;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,javax.xml.stream,javax.xml.stream.events\\\",ch.qos.logback.core.joran.node;version=\\\"1.4.14\\\",ch.qos.logback.core.joran.sanity;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model,ch.qos.logback.core.spi\\\",ch.qos.logback.core.joran.spi;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.event,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.xml.sax\\\",ch.qos.logback.core.joran.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util.beans,ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.joran.util.beans;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.spi\\\",ch.qos.logback.core.layout;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.model;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.action,ch.qos.logback.core.model.processor\\\",ch.qos.logback.core.model.conditional;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model\\\",ch.qos.logback.core.model.processor;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util.beans,ch.qos.logback.core.model,ch.qos.logback.core.spi\\\",ch.qos.logback.core.model.processor.conditional;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.model,ch.qos.logback.core.model.conditional,ch.qos.logback.core.model.processor\\\",ch.qos.logback.core.model.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model\\\",ch.qos.logback.core.net;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.boolex,ch.qos.logback.core.helpers,ch.qos.logback.core.net.ssl,ch.qos.logback.core.pattern,ch.qos.logback.core.sift,ch.qos.logback.core.spi,ch.qos.logback.core.util,jakarta.mail,jakarta.mail.internet,javax.net\\\",ch.qos.logback.core.net.server;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.net.ssl,ch.qos.logback.core.spi,javax.net\\\",ch.qos.logback.core.net.ssl;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,javax.net,javax.net.ssl\\\",ch.qos.logback.core.pattern;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.encoder,ch.qos.logback.core.spi,ch.qos.logback.core.status\\\",ch.qos.logback.core.pattern.color;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.pattern\\\",ch.qos.logback.core.pattern.parser;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.pattern,ch.qos.logback.core.pattern.util,ch.qos.logback.core.spi\\\",ch.qos.logback.core.pattern.util;version=\\\"1.4.14\\\",ch.qos.logback.core.property;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.read;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.recovery;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.status\\\",ch.qos.logback.core.rolling;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.rolling.helper,ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.rolling.helper;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.pattern,ch.qos.logback.core.rolling,ch.qos.logback.core.spi\\\",ch.qos.logback.core.sift;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.spi;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.filter,ch.qos.logback.core.helpers,ch.qos.logback.core.status\\\",ch.qos.logback.core.status;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.spi,jakarta.servlet,jakarta.servlet.http\\\",ch.qos.logback.core.subst;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.spi\\\",ch.qos.logback.core.testUtil;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.encoder,ch.qos.logback.core.read,ch.qos.logback.core.spi,ch.qos.logback.core.status,javax.naming,javax.naming.spi\\\",ch.qos.logback.core.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.rolling,ch.qos.logback.core.rolling.helper,ch.qos.logback.core.spi,ch.qos.logback.core.status,javax.naming\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"ch.qos.logback.core;version=\\\"[1.4,2)\\\",ch.qos.logback.core.boolex;version=\\\"[1.4,2)\\\",ch.qos.logback.core.encoder;version=\\\"[1.4,2)\\\",ch.qos.logback.core.filter;version=\\\"[1.4,2)\\\",ch.qos.logback.core.helpers;version=\\\"[1.4,2)\\\",ch.qos.logback.core.hook;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.action;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.event;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.sanity;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.util.beans;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.processor;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.processor.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net.ssl;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.parser;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.read;version=\\\"[1.4,2)\\\",ch.qos.logback.core.recovery;version=\\\"[1.4,2)\\\",ch.qos.logback.core.rolling;version=\\\"[1.4,2)\\\",ch.qos.logback.core.rolling.helper;version=\\\"[1.4,2)\\\",ch.qos.logback.core.sift;version=\\\"[1.4,2)\\\",ch.qos.logback.core.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.status;version=\\\"[1.4,2)\\\",ch.qos.logback.core.subst;version=\\\"[1.4,2)\\\",ch.qos.logback.core.util;version=\\\"[1.4,2)\\\",jakarta.mail;resolution:=optional;version=\\\"[2.1,3)\\\",jakarta.mail.internet;resolution:=optional;version=\\\"[2.1,3)\\\",jakarta.servlet;resolution:=optional;version=\\\"[5.0,6)\\\",jakarta.servlet.http;resolution:=optional;version=\\\"[5.0,6)\\\",org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,org.codehaus.janino;resolution:=optional;version=\\\"[3.1,4)\\\",org.codehaus.commons.compiler;resolution:=optional;version=\\\"[3.1,4)\\\",java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.module,java.lang.reflect,java.math,java.net,java.nio,java.nio.channels,java.nio.charset,java.nio.file,java.security,java.security.cert,java.text,java.time,java.time.format,java.time.temporal,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,java.util.function,java.util.regex,java.util.stream,java.util.zip,javax.naming,javax.naming.spi,javax.net,javax.net.ssl,javax.xml.namespace,javax.xml.parsers,javax.xml.stream,javax.xml.stream.events,org.fusesource.jansi;resolution:=optional;version=\\\"[2.4,3)\\\"\"\n            },\n            {\n              \"key\": \"Originally-Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=11))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/ch.qos.logback/logback-core/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"ch.qos.logback\",\n          \"artifactId\": \"logback-core\",\n          \"version\": \"1.4.14\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"c46f369578c77c43\",\n      \"name\": \"micrometer-commons\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-commons@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.commons\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769856136\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.169807141Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-commons\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-commons\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"DynamicImport-Package\",\n              \"value\": \"org.aspectj.lang,org.aspectj.lang.reflect\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.common;uses:=\\\"io.micrometer.common.docs,io.micrometer.common.lang\\\";version=\\\"1.13.0\\\",io.micrometer.common.annotation;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,org.aspectj.lang\\\";version=\\\"1.13.0\\\",io.micrometer.common.docs;uses:=\\\"io.micrometer.common\\\";version=\\\"1.13.0\\\",io.micrometer.common.lang;uses:=\\\"javax.annotation,javax.annotation.meta\\\";version=\\\"1.13.0\\\",io.micrometer.common.util;uses:=\\\"io.micrometer.common.lang\\\";version=\\\"1.13.0\\\",io.micrometer.common.util.internal.logging;version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-commons;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"io.micrometer.common,io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.common.util.internal.logging,javax.annotation;version=\\\"[3.0,4)\\\",javax.annotation.meta;version=\\\"[3.0,4)\\\",org.slf4j;version=\\\"[1.7,2)\\\",org.slf4j.helpers;version=\\\"[1.7,2)\\\",org.slf4j.spi;version=\\\"[1.7,2)\\\"\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-commons\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"e738daf6678eedf8e0c40a782bdb0df064a391e5\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"3c0d8567351e2ae4\",\n      \"name\": \"micrometer-core\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-core-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-core-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-core@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-core-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.core\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769876578\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.236904273Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-core\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-core\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"DynamicImport-Package\",\n              \"value\": \"org.aspectj.lang,org.aspectj.lang.annotation,org.aspectj.lang.reflect,com.github.benmanes.caffeine.cache;version=\\\"2.9.3\\\",com.github.benmanes.caffeine.cache.stats;version=\\\"2.9.3\\\",net.sf.ehcache;version=\\\"2.10.9\\\",net.sf.ehcache.statistics;version=\\\"2.10.9\\\",javax.cache;version=\\\"1.1.1\\\",org.hibernate;version=\\\"5.6.15.Final\\\",org.hibernate.engine.spi;version=\\\"5.6.15.Final\\\",org.hibernate.event.service.spi;version=\\\"5.6.15.Final\\\",org.hibernate.event.spi;version=\\\"5.6.15.Final\\\",org.hibernate.service;version=\\\"5.6.15.Final\\\",org.hibernate.service.spi;version=\\\"5.6.15.Final\\\",org.hibernate.stat;version=\\\"5.6.15.Final\\\",org.hibernate.stat.spi;version=\\\"5.6.15.Final\\\",org.eclipse.jetty.client.api;version=\\\"9.4.53\\\",org.eclipse.jetty.http;version=\\\"9.4.53\\\",org.eclipse.jetty.io;version=\\\"9.4.53\\\",org.eclipse.jetty.io.ssl;version=\\\"9.4.53\\\",org.eclipse.jetty.server;version=\\\"9.4.53\\\",org.eclipse.jetty.server.handler;version=\\\"9.4.53\\\",org.eclipse.jetty.util;version=\\\"9.4.53\\\",org.eclipse.jetty.util.component;version=\\\"9.4.53\\\",org.eclipse.jetty.util.thread;version=\\\"9.4.53\\\",org.glassfish.jersey.server;version=\\\"2.41\\\",org.glassfish.jersey.server.model;version=\\\"2.41\\\",org.glassfish.jersey.server.monitoring;version=\\\"2.41\\\",org.glassfish.jersey.uri;version=\\\"2.41\\\",io.grpc,io.grpc.kotlin,org.apache.hc.client5.http,org.apache.hc.client5.http.async,org.apache.hc.client5.http.classic,org.apache.hc.client5.http.protocol,org.apache.hc.core5.concurrent,org.apache.hc.core5.http,org.apache.hc.core5.http.impl,org.apache.hc.core5.http.impl.io,org.apache.hc.core5.http.io,org.apache.hc.core5.http.nio,org.apache.hc.core5.http.protocol,org.apache.hc.core5.pool,org.apache.hc.core5.util,org.apache.http,org.apache.http.conn.routing,org.apache.http.pool,org.apache.http.protocol,com.netflix.hystrix;version=\\\"1.5.12\\\",com.netflix.hystrix.metric;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.concurrency;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.eventnotifier;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.executionhook;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.metrics;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.properties;version=\\\"1.5.12\\\",ch.qos.logback.classic;version=\\\"1.2.13\\\",ch.qos.logback.classic.spi;version=\\\"1.2.13\\\",ch.qos.logback.classic.turbo;version=\\\"1.2.13\\\",ch.qos.logback.core.spi;version=\\\"1.2.13\\\",org.apache.logging.log4j;version=\\\"2.20.2\\\",org.apache.logging.log4j.core;version=\\\"2.20.2\\\",org.apache.logging.log4j.core.config;version=\\\"2.21.0\\\",org.apache.logging.log4j.core.filter;version=\\\"2.21.0\\\",org.apache.logging.log4j.spi;version=\\\"2.20.1\\\",okhttp3,com.mongodb;version=\\\"4.11.1\\\",com.mongodb.connection;version=\\\"4.11.1\\\",com.mongodb.event;version=\\\"4.11.1\\\",org.jooq;version=\\\"3.14.16\\\",org.jooq.exception;version=\\\"3.14.16\\\",org.jooq.impl;version=\\\"3.14.16\\\",org.apache.kafka.clients.admin,org.apache.kafka.clients.consumer,org.apache.kafka.clients.producer,org.apache.kafka.common,org.apache.kafka.common.metrics,org.apache.kafka.streams,com.codahale.metrics;version=\\\"4.2.25\\\",com.google.common.cache;version=\\\"32.1.2\\\",jakarta.servlet.http;version=\\\"5.0.0\\\",javax.servlet;version=\\\"4.0.0\\\",javax.servlet.http;version=\\\"4.0.0\\\",io.micrometer.context,io.micrometer.observation;version=\\\"1.13.0\\\",io.micrometer.observation.docs;version=\\\"1.13.0\\\",io.micrometer.observation.transport;version=\\\"1.13.0\\\",kotlin,kotlin.coroutines,kotlin.jvm.functions,kotlin.jvm.internal,kotlinx.coroutines,org.LatencyUtils,org.HdrHistogram;version=\\\"2.1.12\\\",org.apache.catalina,org.bson;version=\\\"4.11.1\\\",rx;version=\\\"1.2.0\\\",rx.functions;version=\\\"1.2.0\\\",javax.persistence;version=\\\"2.2.0\\\",io.netty.buffer;version=\\\"4.1.106\\\",io.netty.util.concurrent;version=\\\"4.1.106\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.core.annotation;version=\\\"1.13.0\\\",io.micrometer.core.aop;uses:=\\\"io.micrometer.common.annotation,io.micrometer.common.lang,io.micrometer.core.annotation,io.micrometer.core.instrument,org.aspectj.lang,org.aspectj.lang.annotation\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.annotation,io.micrometer.core.instrument.composite,io.micrometer.core.instrument.config,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.search\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.cache;uses:=\\\"com.github.benmanes.caffeine.cache,com.github.benmanes.caffeine.cache.stats,com.google.common.cache,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.cache,net.sf.ehcache\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.commonspool2;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.management\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.db;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.sql,org.jooq,org.jooq.impl\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.grpc;uses:=\\\"io.grpc,io.micrometer.common,io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.http;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,jakarta.servlet.http,javax.servlet.http\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.httpcomponents;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,org.apache.http,org.apache.http.conn.routing,org.apache.http.pool,org.apache.http.protocol\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.httpcomponents.hc5;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,org.apache.hc.client5.http,org.apache.hc.client5.http.async,org.apache.hc.client5.http.classic,org.apache.hc.client5.http.protocol,org.apache.hc.core5.http,org.apache.hc.core5.http.impl.io,org.apache.hc.core5.http.io,org.apache.hc.core5.http.nio,org.apache.hc.core5.http.protocol,org.apache.hc.core5.pool,org.apache.hc.core5.util\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.hystrix;uses:=\\\"com.netflix.hystrix,com.netflix.hystrix.strategy.metrics,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jersey.server;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,org.glassfish.jersey.server,org.glassfish.jersey.server.monitoring\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jetty;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.core.instrument.binder.http,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,javax.servlet,javax.servlet.http,org.eclipse.jetty.client.api,org.eclipse.jetty.io,org.eclipse.jetty.io.ssl,org.eclipse.jetty.server,org.eclipse.jetty.server.handler,org.eclipse.jetty.util.component,org.eclipse.jetty.util.thread\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jpa;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.persistence,org.hibernate\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jvm;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.kafka;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.management,org.apache.kafka.clients.admin,org.apache.kafka.clients.consumer,org.apache.kafka.clients.producer,org.apache.kafka.streams\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.logging;uses:=\\\"ch.qos.logback.classic,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,org.apache.logging.log4j.core\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.mongodb;uses:=\\\"com.mongodb.event,io.micrometer.common.lang,io.micrometer.core.instrument,org.bson\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.netty4;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.core.instrument.docs,io.netty.buffer,io.netty.util.concurrent\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.okhttp3;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,okhttp3\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.system;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.tomcat;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.management,org.apache.catalina\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.composite;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.config;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.config.validate;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument.config\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.cumulative;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.distribution;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.internal,io.micrometer.core.instrument.step,org.HdrHistogram\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.distribution.pause;version=\\\"1.13.0\\\",io.micrometer.core.instrument.docs;uses:=\\\"io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.core.instrument\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.dropwizard;uses:=\\\"com.codahale.metrics,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.util\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.internal;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.distribution\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.kotlin;uses:=\\\"io.grpc,io.grpc.kotlin,io.micrometer.observation,kotlin,kotlin.coroutines\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.logging;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.step\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.noop;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.distribution\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.observation;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.observation\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.push;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.search;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.simple;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.step;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.push\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.util;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config\\\";version=\\\"1.13.0\\\",io.micrometer.core.ipc.http;uses:=\\\"io.micrometer.common.lang,okhttp3\\\";version=\\\"1.13.0\\\",io.micrometer.core.lang;uses:=\\\"javax.annotation,javax.annotation.meta\\\";version=\\\"1.13.0\\\",io.micrometer.core.util.internal.logging;version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-core;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.sun.management,io.micrometer.common;version=\\\"[1.13,2)\\\",io.micrometer.common.annotation;version=\\\"[1.13,2)\\\",io.micrometer.common.docs;version=\\\"[1.13,2)\\\",io.micrometer.common.lang;version=\\\"[1.13,2)\\\",io.micrometer.common.util;version=\\\"[1.13,2)\\\",io.micrometer.common.util.internal.logging;version=\\\"[1.13,2)\\\",io.micrometer.core.annotation,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.core.instrument.binder.http,io.micrometer.core.instrument.composite,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.cumulative,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.docs,io.micrometer.core.instrument.internal,io.micrometer.core.instrument.noop,io.micrometer.core.instrument.observation,io.micrometer.core.instrument.push,io.micrometer.core.instrument.search,io.micrometer.core.instrument.step,io.micrometer.core.instrument.util,javax.annotation;version=\\\"[3.0,4)\\\",javax.annotation.meta;version=\\\"[3.0,4)\\\",javax.management,javax.management.openmbean,javax.net.ssl,javax.sql,org.slf4j;version=\\\"[1.7,2)\\\",org.slf4j.helpers;version=\\\"[1.7,2)\\\",org.slf4j.spi;version=\\\"[1.7,2)\\\"\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-core\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"49d54a8ed6d3266b4f2691027d95144e946bbe36\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f4ea2c844b65a026\",\n      \"name\": \"micrometer-jakarta9\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-jakarta9-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-jakarta9-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-jakarta9@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-jakarta9-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.jakarta9\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769878958\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.305566010Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-jakarta9\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-jakarta9\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"DynamicImport-Package\",\n              \"value\": \"jakarta.jms;version=\\\"3.0.0\\\",io.micrometer.observation;version=\\\"1.13.0\\\",io.micrometer.observation.docs;version=\\\"1.13.0\\\",io.micrometer.observation.transport;version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.jakarta9.instrument.jms;uses:=\\\"io.micrometer.common,io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,jakarta.jms\\\";version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-jakarta9;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"io.micrometer.common;version=\\\"[1.13,2)\\\",io.micrometer.common.docs;version=\\\"[1.13,2)\\\",io.micrometer.common.lang;version=\\\"[1.13,2)\\\"\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-jakarta9\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"74087b670cad9f9883228ee2aa871f51b53f827a\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"26b8a84479010ca8\",\n      \"name\": \"micrometer-observation\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-observation@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.observation\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769856490\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.426326246Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-observation\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-observation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.observation;uses:=\\\"io.micrometer.common,io.micrometer.common.lang\\\";version=\\\"1.13.0\\\",io.micrometer.observation.annotation;version=\\\"1.13.0\\\",io.micrometer.observation.aop;uses:=\\\"io.micrometer.common.lang,io.micrometer.observation,org.aspectj.lang,org.aspectj.lang.annotation\\\";version=\\\"1.13.0\\\",io.micrometer.observation.contextpropagation;uses:=\\\"io.micrometer.context,io.micrometer.observation\\\";version=\\\"1.13.0\\\",io.micrometer.observation.docs;uses:=\\\"io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.observation\\\";version=\\\"1.13.0\\\",io.micrometer.observation.transport;uses:=\\\"io.micrometer.common.lang,io.micrometer.observation\\\";version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-observation;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"io.micrometer.context;resolution:=optional,org.aspectj.lang;resolution:=optional,org.aspectj.lang.annotation;resolution:=optional,org.aspectj.lang.reflect;resolution:=optional,io.micrometer.common;version=\\\"[1.13,2)\\\",io.micrometer.common.docs;version=\\\"[1.13,2)\\\",io.micrometer.common.lang;version=\\\"[1.13,2)\\\",io.micrometer.common.util;version=\\\"[1.13,2)\\\",io.micrometer.common.util.internal.logging;version=\\\"[1.13,2)\\\",io.micrometer.observation,io.micrometer.observation.annotation,io.micrometer.observation.docs\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-observation\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"c06e5e0f9b6edc9c0c0ac3dd46a2117ce6f16a9d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"93ed082a147d9796\",\n      \"name\": \"sbom-test-gradle\",\n      \"version\": \"0.0.1-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot.loader.launch.JarLauncher/sbom-test-gradle@0.0.1-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Main-Class\",\n              \"value\": \"org.springframework.boot.loader.launch.JarLauncher\"\n            },\n            {\n              \"key\": \"Start-Class\",\n              \"value\": \"com.example.sbomtestgradle.SbomTestGradleApplication\"\n            },\n            {\n              \"key\": \"Spring-Boot-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Spring-Boot-Classes\",\n              \"value\": \"BOOT-INF/classes/\"\n            },\n            {\n              \"key\": \"Spring-Boot-Lib\",\n              \"value\": \"BOOT-INF/lib/\"\n            },\n            {\n              \"key\": \"Spring-Boot-Classpath-Index\",\n              \"value\": \"BOOT-INF/classpath.idx\"\n            },\n            {\n              \"key\": \"Spring-Boot-Layers-Index\",\n              \"value\": \"BOOT-INF/layers.idx\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"sbom-test-gradle\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"0.0.1-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Sbom-Location\",\n              \"value\": \"META-INF/sbom/bom.json\"\n            },\n            {\n              \"key\": \"Sbom-Format\",\n              \"value\": \"CycloneDX\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"8ccd6688e9d8e15d18e0f10967867e5e30729a4c\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"44752cfa6770756d\",\n      \"name\": \"slf4j-api\",\n      \"version\": \"2.0.11\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/slf4j-api-2.0.11.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.opensource.org/licenses/mit-license.php\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/slf4j-api-2.0.11.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j-api:slf4j-api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j-api:slf4j_api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j_api:slf4j-api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j_api:slf4j_api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:slf4j-api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:slf4j_api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.slf4j/slf4j-api@2.0.11\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/slf4j-api-2.0.11.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"The slf4j API\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.slf4j.org\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.opensource.org/licenses/mit-license.php\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"SLF4J API Module\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"slf4j.api\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"SLF4J.ORG\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.slf4j;uses:=\\\"org.slf4j.event,org.slf4j.helpers,org.slf4j.spi\\\";version=\\\"2.0.11\\\",org.slf4j.event;uses:=\\\"org.slf4j,org.slf4j.helpers\\\";version=\\\"2.0.11\\\",org.slf4j.helpers;uses:=\\\"org.slf4j,org.slf4j.event,org.slf4j.spi\\\";version=\\\"2.0.11\\\",org.slf4j.spi;uses:=\\\"org.slf4j,org.slf4j.event,org.slf4j.helpers\\\";version=\\\"2.0.11\\\",org.slf4j;version=\\\"1.7.36\\\",org.slf4j.helpers;version=\\\"1.7.36\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"slf4j-api\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.slf4j.spi;version=\\\"[2.0.11,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.slf4j.spi.SLF4JServiceProvider)\\\";osgi.serviceloader=\\\"org.slf4j.spi.SLF4JServiceProvider\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"8\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.slf4j/slf4j-api/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.slf4j\",\n          \"artifactId\": \"slf4j-api\",\n          \"version\": \"2.0.11\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"ad96c3f8cf895e696dd35c2bc8e8ebe710be9e6d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f4585c65c0a5b26a\",\n      \"name\": \"snakeyaml\",\n      \"version\": \"2.2\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/snakeyaml-2.2.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/snakeyaml-2.2.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:snakeyaml:snakeyaml:2.2:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:yaml:snakeyaml:2.2:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.yaml/snakeyaml@2.2\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/snakeyaml-2.2.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1693124775469\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"YAML 1.1 parser and emitter for Java\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"SnakeYAML\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.yaml.snakeyaml\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.2.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.yaml.snakeyaml;version=\\\"2.2\\\",org.yaml.snakeyaml.comments;version=\\\"2.2\\\",org.yaml.snakeyaml.composer;version=\\\"2.2\\\",org.yaml.snakeyaml.constructor;version=\\\"2.2\\\",org.yaml.snakeyaml.emitter;version=\\\"2.2\\\",org.yaml.snakeyaml.env;version=\\\"2.2\\\",org.yaml.snakeyaml.error;version=\\\"2.2\\\",org.yaml.snakeyaml.events;version=\\\"2.2\\\",org.yaml.snakeyaml.extensions.compactnotation;version=\\\"2.2\\\",org.yaml.snakeyaml.inspector;version=\\\"2.2\\\",org.yaml.snakeyaml.internal;version=\\\"2.2\\\",org.yaml.snakeyaml.introspector;version=\\\"2.2\\\",org.yaml.snakeyaml.nodes;version=\\\"2.2\\\",org.yaml.snakeyaml.parser;version=\\\"2.2\\\",org.yaml.snakeyaml.reader;version=\\\"2.2\\\",org.yaml.snakeyaml.representer;version=\\\"2.2\\\",org.yaml.snakeyaml.resolver;version=\\\"2.2\\\",org.yaml.snakeyaml.scanner;version=\\\"2.2\\\",org.yaml.snakeyaml.serializer;version=\\\"2.2\\\",org.yaml.snakeyaml.tokens;version=\\\"2.2\\\",org.yaml.snakeyaml.util;version=\\\"2.2\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.yaml.snakeyaml;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.comments;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.composer;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.emitter;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.error;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.events;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.inspector;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.internal;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.introspector;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.nodes;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.parser;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.reader;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.resolver;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.scanner;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.serializer;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.tokens;version=\\\"[2.2,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.7))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.yaml/snakeyaml/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.yaml\",\n          \"artifactId\": \"snakeyaml\",\n          \"version\": \"2.2\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"1e7758a78bbc15ee\",\n      \"name\": \"spring-aop\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-aop@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-aop\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.aop\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"b02165904562fc487cde57ca75e063561d905f74\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"bb7e773a923726bb\",\n      \"name\": \"spring-beans\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-beans@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-beans\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.beans\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"fa8be0f856958fdd33eef9e718b3a65f7130bbd2\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"a11948291446c2f5\",\n      \"name\": \"spring-boot\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d882660ea3deafe921faba8b17e7d94ef9556c47\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f83d629168e25cce\",\n      \"name\": \"spring-boot-actuator\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.actuator\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot Actuator\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d0d018780795da57afa8edae7436646bccd55722\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"b8eb893518786bb8\",\n      \"name\": \"spring-boot-actuator-autoconfigure\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-autoconfigure-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-autoconfigure-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-autoconfigure-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.actuator.autoconfigure\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot Actuator AutoConfigure\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"8b8f74be822e6f2ab120ea0687acf629ef114399\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"b40bdc90eb8832a3\",\n      \"name\": \"spring-boot-autoconfigure\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.autoconfigure\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot AutoConfigure\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"31a960bb63af836f35760077af8ef58d24b548e3\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"8069f3f866b2e657\",\n      \"name\": \"spring-boot-jarmode-layertools\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-jarmode-layertools-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-jarmode-layertools-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode-layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode_layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-jarmode-layertools@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-jarmode-layertools-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.jarmode.layertools\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot Layers Tools\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d86f1782ad3d9ee047863a5023aaa22f858cd9a4\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"3d5d71e0e85398af\",\n      \"name\": \"spring-context\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-context@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-context\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.context\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"75440f70a649ca15948af5923ebdef345848a856\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"519fe54307d2d43d\",\n      \"name\": \"spring-core\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-core@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-core\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.core\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Dependencies\",\n              \"value\": \"jdk.unsupported,org.jboss.vfs\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"27d0900a14e240a7311c979e7b30cf65f9de9074\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"546794e924e39088\",\n      \"name\": \"spring-expression\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-expression@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-expression\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.expression\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"a5d7041ca11fd188e9d17ac8a795eabed8be55e4\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"173ea637a5756944\",\n      \"name\": \"spring-jcl\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-jcl@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-jcl\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.jcl\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"604cea28d23d8027a31c35f372d2b8d0fdec211d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"adc63cefcede34fc\",\n      \"name\": \"spring-web\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-web@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-web\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.web\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"c0600dcd73db226c3d121af16d6a155ecee08d30\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"940aed7082581b67\",\n      \"name\": \"spring-webmvc\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-webmvc@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-webmvc\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.webmvc\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"34a510cf565bec1c2f74f049b1730b22f877bd37\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"a753aca6ee68c738\",\n      \"name\": \"tomcat-embed-core\",\n      \"version\": \"10.1.18\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-core-10.1.18.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-core-10.1.18.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat-embed-core:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat_embed_core:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.18\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-core-10.1.18.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"tomcat-embed-core\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.tomcat-embed-core\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.security.auth.message;version=\\\"3.0\\\";uses:=\\\"javax.security.auth,javax.security.auth.login\\\",jakarta.security.auth.message.callback;version=\\\"3.0\\\";uses:=\\\"javax.crypto,javax.security.auth,javax.security.auth.callback,javax.security.auth.x500\\\",jakarta.security.auth.message.config;version=\\\"3.0\\\";uses:=\\\"jakarta.security.auth.message,jakarta.security.auth.message.module,javax.security.auth,javax.security.auth.callback\\\",jakarta.security.auth.message.module;version=\\\"3.0\\\";uses:=\\\"jakarta.security.auth.message,javax.security.auth.callback\\\",jakarta.servlet;version=\\\"6.0\\\";uses:=\\\"jakarta.servlet.annotation,jakarta.servlet.descriptor\\\",jakarta.servlet.annotation;version=\\\"6.0\\\";uses:=\\\"jakarta.servlet\\\",jakarta.servlet.descriptor;version=\\\"6.0\\\",jakarta.servlet.http;version=\\\"6.0\\\";uses:=\\\"jakarta.servlet\\\",jakarta.servlet.resources;version=\\\"6.0\\\",org.apache.catalina;uses:=\\\"jakarta.servlet,jakarta.servlet.descriptor,jakarta.servlet.http,javax.management,javax.naming,org.apache.catalina.connector,org.apache.catalina.deploy,org.apache.catalina.mapper,org.apache.catalina.startup,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.file,org.apache.tomcat.util.http,org.ietf.jgss\\\";version=\\\"10.1.18\\\",org.apache.catalina.authenticator;uses:=\\\"jakarta.security.auth.message.config,jakarta.servlet,jakarta.servlet.http,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.util,org.apache.catalina.valves,org.apache.tomcat.util.buf,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.res,org.ietf.jgss\\\";version=\\\"10.1.18\\\",org.apache.catalina.authenticator.jaspic;uses:=\\\"jakarta.security.auth.message,jakarta.security.auth.message.config,jakarta.security.auth.message.module,jakarta.servlet.http,javax.security.auth,javax.security.auth.callback,org.apache.catalina,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.connector;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.security.auth,org.apache.catalina,org.apache.catalina.core,org.apache.catalina.mapper,org.apache.catalina.util,org.apache.coyote,org.apache.tomcat.util.buf,org.apache.tomcat.util.http,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.core;uses:=\\\"jakarta.servlet,jakarta.servlet.descriptor,jakarta.servlet.http,javax.management,javax.naming,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.deploy,org.apache.catalina.mapper,org.apache.catalina.startup,org.apache.catalina.util,org.apache.coyote,org.apache.juli.logging,org.apache.naming,org.apache.tomcat,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.http,org.apache.tomcat.util.http.fileupload,org.apache.tomcat.util.res,org.apache.tomcat.util.threads\\\";version=\\\"10.1.18\\\",org.apache.catalina.deploy;uses:=\\\"org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.descriptor.web\\\";version=\\\"10.1.18\\\",org.apache.catalina.filters;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.juli.logging,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.loader;uses:=\\\"org.apache.catalina,org.apache.catalina.util,org.apache.juli,org.apache.tomcat,org.apache.tomcat.util.res,org.apache.tomcat.util.security\\\";version=\\\"10.1.18\\\",org.apache.catalina.manager;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.management,javax.naming,org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.modeler,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.manager.host;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.catalina,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.manager.util;uses:=\\\"jakarta.servlet.http,org.apache.catalina\\\";version=\\\"10.1.18\\\",org.apache.catalina.mapper;uses:=\\\"jakarta.servlet.http,org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.buf\\\";version=\\\"10.1.18\\\",org.apache.catalina.mbeans;uses:=\\\"javax.management,javax.naming,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.core,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.modeler,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.realm;uses:=\\\"javax.management,javax.naming,javax.naming.directory,javax.net.ssl,javax.security.auth,javax.security.auth.callback,javax.security.auth.login,javax.security.auth.spi,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat.util.collections,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.digester,org.apache.tomcat.util.res,org.ietf.jgss\\\";version=\\\"10.1.18\\\",org.apache.catalina.security;uses:=\\\"jakarta.servlet,org.apache.catalina\\\";version=\\\"10.1.18\\\",org.apache.catalina.servlets;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.xml.parsers,javax.xml.transform,org.apache.catalina,org.apache.tomcat.util.http,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.session;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.sql,org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.startup;uses:=\\\"jakarta.annotation,jakarta.servlet,jakarta.servlet.descriptor,javax.management,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.core,org.apache.catalina.deploy,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.bcel.classfile,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.digester,org.apache.tomcat.util.file,org.apache.tomcat.util.http,org.apache.tomcat.util.res,org.xml.sax\\\";version=\\\"10.1.18\\\",org.apache.catalina.users;uses:=\\\"javax.naming,javax.naming.spi,javax.sql,org.apache.catalina\\\";version=\\\"10.1.18\\\",org.apache.catalina.util;uses:=\\\"jakarta.servlet.http,javax.management,org.apache.catalina,org.apache.juli.logging,org.apache.tomcat.util.descriptor.web,org.w3c.dom\\\";version=\\\"10.1.18\\\",org.apache.catalina.valves;uses:=\\\"jakarta.servlet,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.valves.rewrite;uses:=\\\"jakarta.servlet,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.valves,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.webresources;uses:=\\\"org.apache.catalina,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.webresources.war;version=\\\"10.1.18\\\",org.apache.coyote;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.management,org.apache.coyote.http11,org.apache.coyote.http11.upgrade,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.buf,org.apache.tomcat.util.collections,org.apache.tomcat.util.http,org.apache.tomcat.util.log,org.apache.tomcat.util.modeler,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.coyote.ajp;uses:=\\\"jakarta.servlet,org.apache.coyote,org.apache.juli.logging,org.apache.tomcat.util.buf,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.coyote.http11;uses:=\\\"jakarta.servlet,javax.management,org.apache.coyote,org.apache.coyote.http11.upgrade,org.apache.juli.logging,org.apache.tomcat.util.buf,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.coyote.http11.filters;uses:=\\\"org.apache.coyote,org.apache.coyote.http11,org.apache.juli.logging,org.apache.tomcat.util.buf,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.coyote.http11.upgrade;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.coyote,org.apache.juli.logging,org.apache.tomcat.util.modeler,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.coyote.http2;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.coyote,org.apache.coyote.http11,org.apache.coyote.http11.upgrade,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.juli;version=\\\"10.1.18\\\",org.apache.juli.logging;version=\\\"10.1.18\\\",org.apache.naming;uses:=\\\"javax.naming\\\";version=\\\"10.1.18\\\",org.apache.naming.factory;uses:=\\\"javax.naming,javax.naming.spi,javax.sql,org.apache.naming\\\";version=\\\"10.1.18\\\",org.apache.naming.java;uses:=\\\"javax.naming,javax.naming.spi\\\";version=\\\"10.1.18\\\",org.apache.tomcat;uses:=\\\"jakarta.servlet,javax.naming\\\";version=\\\"10.1.18\\\",org.apache.tomcat.jni;version=\\\"10.1.18\\\",org.apache.tomcat.util;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.bcel.classfile;version=\\\"10.1.18\\\",org.apache.tomcat.util.buf;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.codec.binary;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.collections;version=\\\"10.1.18\\\",org.apache.tomcat.util.compat;version=\\\"10.1.18\\\",org.apache.tomcat.util.descriptor;uses:=\\\"org.apache.juli.logging,org.apache.tomcat.util.digester,org.xml.sax,org.xml.sax.ext\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.descriptor.tagplugin;uses:=\\\"jakarta.servlet,org.xml.sax\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.descriptor.web;uses:=\\\"jakarta.servlet,jakarta.servlet.descriptor,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.digester,org.apache.tomcat.util.res,org.xml.sax\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.digester;uses:=\\\"javax.xml.parsers,org.apache.juli.logging,org.apache.tomcat.util,org.apache.tomcat.util.res,org.xml.sax,org.xml.sax.ext\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.file;version=\\\"10.1.18\\\",org.apache.tomcat.util.http;uses:=\\\"jakarta.servlet.http,org.apache.tomcat.util.buf\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload;uses:=\\\"org.apache.tomcat.util.http.fileupload.impl,org.apache.tomcat.util.http.fileupload.util\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.disk;uses:=\\\"org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.impl;uses:=\\\"org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.servlet;uses:=\\\"jakarta.servlet.http,org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.util;uses:=\\\"org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.parser;uses:=\\\"org.apache.tomcat.util.buf,org.apache.tomcat.util.http\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.log;uses:=\\\"org.apache.juli.logging\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.modeler;uses:=\\\"javax.management,javax.management.modelmbean\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.modeler.modules;uses:=\\\"javax.management,org.apache.tomcat.util.modeler,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.net;uses:=\\\"jakarta.servlet,javax.management,javax.net.ssl,org.apache.juli.logging,org.apache.tomcat.util.collections,org.apache.tomcat.util.net.openssl,org.apache.tomcat.util.net.openssl.ciphers,org.apache.tomcat.util.res,org.apache.tomcat.util.threads\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.net.openssl;uses:=\\\"javax.net.ssl,org.apache.juli.logging,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.net.openssl.ciphers;version=\\\"10.1.18\\\",org.apache.tomcat.util.res;version=\\\"10.1.18\\\",org.apache.tomcat.util.scan;uses:=\\\"jakarta.servlet,org.apache.tomcat\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.security;version=\\\"10.1.18\\\",org.apache.tomcat.util.threads;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.ssi;version=\\\"10.1.18\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"jakarta.annotation,jakarta.annotation.security,jakarta.ejb,jakarta.mail,jakarta.mail.internet,jakarta.persistence,jakarta.security.auth.message;version=\\\"[3.0,4)\\\",jakarta.security.auth.message.callback;version=\\\"[3.0,4)\\\",jakarta.security.auth.message.config;version=\\\"[3.0,4)\\\",jakarta.security.auth.message.module;version=\\\"[3.0,4)\\\",jakarta.servlet;version=\\\"[6.0,7)\\\",jakarta.servlet.annotation;version=\\\"[6.0,7)\\\",jakarta.servlet.descriptor;version=\\\"[6.0,7)\\\",jakarta.servlet.http;version=\\\"[6.0,7)\\\",jakarta.xml.ws,java.beans,java.io,java.lang,java.lang.annotation,java.lang.instrument,java.lang.invoke,java.lang.management,java.lang.module,java.lang.ref,java.lang.reflect,java.math,java.net,java.nio,java.nio.channels,java.nio.charset,java.nio.file,java.nio.file.attribute,java.rmi,java.security,java.security.cert,java.security.spec,java.sql,java.text,java.time,java.time.chrono,java.time.format,java.time.temporal,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,java.util.function,java.util.jar,java.util.logging,java.util.regex,java.util.stream,java.util.zip,javax.crypto,javax.crypto.spec,javax.imageio,javax.management,javax.management.loading,javax.management.modelmbean,javax.management.openmbean,javax.naming,javax.naming.directory,javax.naming.ldap,javax.naming.spi,javax.net.ssl,javax.security.auth,javax.security.auth.callback,javax.security.auth.login,javax.security.auth.spi,javax.security.auth.x500,javax.security.cert,javax.sql,javax.wsdl,javax.wsdl.extensions,javax.wsdl.extensions.soap,javax.wsdl.factory,javax.wsdl.xml,javax.xml.namespace,javax.xml.parsers,javax.xml.rpc,javax.xml.rpc.handler,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.apache.catalina,org.apache.catalina.authenticator,org.apache.catalina.authenticator.jaspic,org.apache.catalina.connector,org.apache.catalina.core,org.apache.catalina.deploy,org.apache.catalina.filters,org.apache.catalina.loader,org.apache.catalina.manager.util,org.apache.catalina.mapper,org.apache.catalina.mbeans,org.apache.catalina.realm,org.apache.catalina.security,org.apache.catalina.session,org.apache.catalina.startup,org.apache.catalina.util,org.apache.catalina.webresources,org.apache.catalina.webresources.war,org.apache.coyote,org.apache.coyote.ajp,org.apache.coyote.http11,org.apache.coyote.http11.filters,org.apache.coyote.http11.upgrade,org.apache.juli,org.apache.juli.logging,org.apache.naming,org.apache.naming.factory,org.apache.tomcat,org.apache.tomcat.jakartaee,org.apache.tomcat.jni,org.apache.tomcat.util,org.apache.tomcat.util.buf,org.apache.tomcat.util.codec.binary,org.apache.tomcat.util.collections,org.apache.tomcat.util.compat,org.apache.tomcat.util.descriptor,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.digester,org.apache.tomcat.util.file,org.apache.tomcat.util.http,org.apache.tomcat.util.http.fileupload.disk,org.apache.tomcat.util.http.fileupload.impl,org.apache.tomcat.util.http.fileupload.servlet,org.apache.tomcat.util.http.fileupload.util,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.log,org.apache.tomcat.util.modeler,org.apache.tomcat.util.modeler.modules,org.apache.tomcat.util.net.openssl.ciphers,org.apache.tomcat.util.res,org.apache.tomcat.util.scan,org.apache.tomcat.util.security,org.apache.tomcat.util.threads,org.ietf.jgss,org.w3c.dom,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.naming.factory.webservices,org.apache.tomcat.util.bcel,org.apache.tomcat.util.http.fileupload.util.mime,org.apache.tomcat.util.json,org.apache.tomcat.util.net.jsse\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.contract;osgi.contract=JavaJASPIC;version:Version=\\\"3.0\\\";uses:=\\\"jakarta.security.auth.message,jakarta.security.auth.message.callback,jakarta.security.auth.message.config,jakarta.security.auth.message.module\\\",osgi.contract;osgi.contract=JavaServlet;version:Version=\\\"6.0\\\";uses:=\\\"jakarta.servlet,jakarta.servlet.annotation,jakarta.servlet.descriptor,jakarta.servlet.http,jakarta.servlet.resources\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.juli.logging.Log)\\\";osgi.serviceloader=\\\"org.apache.juli.logging.Log\\\",osgi.contract;osgi.contract=JakartaAnnotations;filter:=\\\"(&(osgi.contract=JakartaAnnotations)(version=2.1.0))\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=11))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"10.1\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"11\"\n            }\n          ],\n          \"sections\": [\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/callback/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/config/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/module/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/annotation/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/descriptor/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/http/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/resources/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ]\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"bff6c34649d1dd7b509e819794d73ba795947dcf\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"7a59d22722f7701b\",\n      \"name\": \"tomcat-embed-el\",\n      \"version\": \"10.1.18\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-el-10.1.18.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-el-10.1.18.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat-embed-el:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat_embed_el:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.18\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-el-10.1.18.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"tomcat-embed-jasper-el\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.tomcat-embed-jasper-el\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.el;version=\\\"5.0\\\",org.apache.el;uses:=\\\"jakarta.el,org.apache.el.parser\\\";version=\\\"10.1.18\\\",org.apache.el.lang;uses:=\\\"jakarta.el,org.apache.el.parser\\\";version=\\\"10.1.18\\\",org.apache.el.parser;uses:=\\\"jakarta.el,org.apache.el.lang\\\";version=\\\"10.1.18\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"jakarta.el;version=\\\"[5.0,6)\\\",java.beans,java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.ref,java.lang.reflect,java.math,java.security,java.text,java.util,java.util.concurrent,java.util.concurrent.locks,java.util.function\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.el.stream,org.apache.el.util\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.contract;osgi.contract=JakartaExpressionLanguage;version:Version=\\\"5.0\\\";uses:=\\\"jakarta.el\\\",osgi.service;objectClass:List<String>=\\\"jakarta.el.ExpressionFactory\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"jakarta.el.ExpressionFactory\\\";register:=\\\"org.apache.el.ExpressionFactoryImpl\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=jakarta.el.ExpressionFactory)\\\";osgi.serviceloader=\\\"jakarta.el.ExpressionFactory\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\",osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"10.1\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"11\"\n            }\n          ],\n          \"sections\": [\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/el/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.annotation\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"5.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Expression Language\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"5.0\"\n              }\n            ]\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"b2c4dc05abd363c63b245523bb071727aa2f1046\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"6c04f8ee22f9157e\",\n      \"name\": \"tomcat-embed-websocket\",\n      \"version\": \"10.1.18\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-websocket-10.1.18.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-websocket-10.1.18.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat-embed-websocket:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat_embed_websocket:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.18\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-websocket-10.1.18.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"tomcat-embed-websocket\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.tomcat-embed-websocket\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.websocket;version=\\\"2.1\\\";uses:=\\\"javax.net.ssl\\\",jakarta.websocket.server;version=\\\"2.1\\\";uses:=\\\"jakarta.websocket\\\",org.apache.tomcat.websocket;uses:=\\\"jakarta.websocket,jakarta.websocket.server,javax.net.ssl,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.websocket.server;uses:=\\\"jakarta.servlet,jakarta.servlet.annotation,jakarta.servlet.http,jakarta.websocket,jakarta.websocket.server,org.apache.coyote.http11.upgrade,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.net,org.apache.tomcat.websocket\\\";version=\\\"10.1.18\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"jakarta.servlet,jakarta.servlet.annotation,jakarta.servlet.http,jakarta.websocket;version=\\\"[2.1,3)\\\",jakarta.websocket.server;version=\\\"[2.1,3)\\\",java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.reflect,java.net,java.nio,java.nio.channels,java.nio.charset,java.security,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,java.util.function,java.util.regex,java.util.zip,javax.naming,javax.net.ssl,org.apache.coyote.http11.upgrade;version=\\\"[10.1,11)\\\",org.apache.juli.logging;version=\\\"[10.1,11)\\\",org.apache.tomcat;version=\\\"[10.1,11)\\\",org.apache.tomcat.util;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.buf;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.codec.binary;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.collections;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.net;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.res;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.security;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.threads;version=\\\"[10.1,11)\\\"\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.tomcat.websocket.pojo\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.contract;osgi.contract=JavaWebSockets;version:Version=\\\"2.1\\\";uses:=\\\"jakarta.websocket,jakarta.websocket.server\\\",osgi.service;objectClass:List<String>=\\\"jakarta.websocket.ContainerProvider\\\";effective:=active,osgi.service;objectClass:List<String>=\\\"jakarta.websocket.server.ServerEndpointConfig$Configurator\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"jakarta.websocket.ContainerProvider\\\";register:=\\\"org.apache.tomcat.websocket.WsContainerProvider\\\",osgi.serviceloader;osgi.serviceloader=\\\"jakarta.websocket.server.ServerEndpointConfig$Configurator\\\";register:=\\\"org.apache.tomcat.websocket.server.DefaultServerEndpointConfigurator\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=jakarta.websocket.ContainerProvider)\\\";osgi.serviceloader=\\\"jakarta.websocket.ContainerProvider\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=jakarta.websocket.server.ServerEndpointConfig$Configurator)\\\";osgi.serviceloader=\\\"jakarta.websocket.server.ServerEndpointConfig$Configurator\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\",osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.contract;osgi.contract=JavaServlet;filter:=\\\"(&(osgi.contract=JavaServlet)(version=6.0.0))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"10.1\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"11\"\n            }\n          ],\n          \"sections\": [\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/websocket/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.websocket\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"2.1\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta WebSocket\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"2.1\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/websocket/server/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.websocket\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"2.1\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta WebSocket\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"2.1\"\n              }\n            ]\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"83a3bc6898f2ceed2357ba231a5e83dc2016d454\"\n          }\n        ]\n      }\n    }\n  ],\n  \"artifactRelationships\": [\n    {\n      \"parent\": \"0408f25059f495c5\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"1347581c05f302c0\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"173ea637a5756944\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"1e7758a78bbc15ee\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"26b8a84479010ca8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"2c7953c2c68ec3bc\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"3748310e1aac44ea\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"3c0d8567351e2ae4\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"3d5d71e0e85398af\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"44752cfa6770756d\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"519fe54307d2d43d\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"546794e924e39088\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"598311f4a5b2a501\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"6c04f8ee22f9157e\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"77a5bf527533d628\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"7a59d22722f7701b\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"8069f3f866b2e657\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"846731ed2e85561c\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"860f45be6a175d16\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"93ed082a147d9796\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"940aed7082581b67\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"9ad3756f611d1ed2\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"a11948291446c2f5\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"a753aca6ee68c738\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"adc63cefcede34fc\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"b40bdc90eb8832a3\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"b8eb893518786bb8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"bb7e773a923726bb\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"c1e7975b6f55f7e8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"c404b33d3a8ce0d8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"c46f369578c77c43\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"0408f25059f495c5\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"1347581c05f302c0\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"173ea637a5756944\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"1e7758a78bbc15ee\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"26b8a84479010ca8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"2c7953c2c68ec3bc\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"3748310e1aac44ea\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"3c0d8567351e2ae4\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"3d5d71e0e85398af\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"44752cfa6770756d\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"519fe54307d2d43d\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"546794e924e39088\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"598311f4a5b2a501\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"6c04f8ee22f9157e\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"77a5bf527533d628\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"7a59d22722f7701b\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"8069f3f866b2e657\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"846731ed2e85561c\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"860f45be6a175d16\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"93ed082a147d9796\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"940aed7082581b67\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"9ad3756f611d1ed2\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"a11948291446c2f5\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"a753aca6ee68c738\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"adc63cefcede34fc\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"b40bdc90eb8832a3\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"b8eb893518786bb8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"bb7e773a923726bb\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"c1e7975b6f55f7e8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"c404b33d3a8ce0d8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"c46f369578c77c43\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"d91fe3ae6bb15cad\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f4585c65c0a5b26a\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f4ea2c844b65a026\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f5bca9d628ab321f\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f83d629168e25cce\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f9418986cc24a153\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d91fe3ae6bb15cad\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f4585c65c0a5b26a\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f4ea2c844b65a026\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f5bca9d628ab321f\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f83d629168e25cce\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f9418986cc24a153\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    }\n  ],\n  \"files\": [\n    {\n      \"id\": \"af7261c65fbd5345\",\n      \"location\": {\n        \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\"\n      }\n    }\n  ],\n  \"source\": {\n    \"id\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n    \"name\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n    \"version\": \"sha256:f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\",\n    \"type\": \"file\",\n    \"metadata\": {\n      \"path\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"digests\": [\n        {\n          \"algorithm\": \"sha256\",\n          \"value\": \"f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\"\n        }\n      ],\n      \"mimeType\": \"application/jar\"\n    }\n  },\n  \"distro\": {},\n  \"descriptor\": {\n    \"name\": \"syft\",\n    \"version\": \"0.105.0\",\n    \"configuration\": {\n      \"catalogers\": {\n        \"requested\": {\n          \"default\": [\n            \"directory\"\n          ]\n        },\n        \"used\": [\n          \"alpm-db-cataloger\",\n          \"apk-db-cataloger\",\n          \"binary-cataloger\",\n          \"cocoapods-cataloger\",\n          \"conan-cataloger\",\n          \"dart-pubspec-lock-cataloger\",\n          \"dotnet-deps-cataloger\",\n          \"dotnet-portable-executable-cataloger\",\n          \"dpkg-db-cataloger\",\n          \"elixir-mix-lock-cataloger\",\n          \"erlang-otp-application-cataloger\",\n          \"erlang-rebar-lock-cataloger\",\n          \"github-action-workflow-usage-cataloger\",\n          \"github-actions-usage-cataloger\",\n          \"go-module-binary-cataloger\",\n          \"go-module-file-cataloger\",\n          \"graalvm-native-image-cataloger\",\n          \"haskell-cataloger\",\n          \"java-archive-cataloger\",\n          \"java-gradle-lockfile-cataloger\",\n          \"java-pom-cataloger\",\n          \"javascript-lock-cataloger\",\n          \"linux-kernel-cataloger\",\n          \"nix-store-cataloger\",\n          \"php-composer-lock-cataloger\",\n          \"portage-cataloger\",\n          \"python-installed-package-cataloger\",\n          \"python-package-cataloger\",\n          \"rpm-archive-cataloger\",\n          \"rpm-db-cataloger\",\n          \"ruby-gemfile-cataloger\",\n          \"ruby-gemspec-cataloger\",\n          \"rust-cargo-lock-cataloger\",\n          \"swift-package-manager-cataloger\",\n          \"wordpress-plugins-cataloger\"\n        ]\n      },\n      \"data-generation\": {\n        \"generate-cpes\": true\n      },\n      \"files\": {\n        \"content\": {\n          \"globs\": null,\n          \"skip-files-above-size\": 0\n        },\n        \"hashers\": [\n          \"sha-1\",\n          \"sha-256\"\n        ],\n        \"selection\": \"owned-by-package\"\n      },\n      \"packages\": {\n        \"binary\": [\n          \"python-binary\",\n          \"python-binary-lib\",\n          \"pypy-binary-lib\",\n          \"go-binary\",\n          \"julia-binary\",\n          \"helm\",\n          \"redis-binary\",\n          \"java-binary-openjdk\",\n          \"java-binary-ibm\",\n          \"java-binary-oracle\",\n          \"nodejs-binary\",\n          \"go-binary-hint\",\n          \"busybox-binary\",\n          \"haproxy-binary\",\n          \"perl-binary\",\n          \"php-cli-binary\",\n          \"php-fpm-binary\",\n          \"php-apache-binary\",\n          \"php-composer-binary\",\n          \"httpd-binary\",\n          \"memcached-binary\",\n          \"traefik-binary\",\n          \"postgresql-binary\",\n          \"mysql-binary\",\n          \"mysql-binary\",\n          \"mysql-binary\",\n          \"xtrabackup-binary\",\n          \"mariadb-binary\",\n          \"rust-standard-library-linux\",\n          \"rust-standard-library-macos\",\n          \"ruby-binary\",\n          \"erlang-binary\",\n          \"consul-binary\",\n          \"nginx-binary\",\n          \"bash-binary\",\n          \"openssl-binary\",\n          \"gcc-binary\",\n          \"wordpress-cli-binary\"\n        ],\n        \"golang\": {\n          \"local-mod-cache-dir\": \"/home/user/go/pkg/mod\",\n          \"main-module-version\": {\n            \"from-build-settings\": true,\n            \"from-contents\": true,\n            \"from-ld-flags\": true\n          },\n          \"proxies\": [\n            \"https://proxy.golang.org\",\n            \"direct\"\n          ],\n          \"search-local-mod-cache-licenses\": false,\n          \"search-remote-licenses\": false\n        },\n        \"java-archive\": {\n          \"include-indexed-archives\": true,\n          \"include-unindexed-archives\": false,\n          \"maven-base-url\": \"https://repo1.maven.org/maven2\",\n          \"max-parent-recursive-depth\": 5,\n          \"use-network\": false\n        },\n        \"javascript\": {\n          \"npm-base-url\": \"https://registry.npmjs.org\",\n          \"search-remote-licenses\": false\n        },\n        \"linux-kernel\": {\n          \"catalog-modules\": true\n        },\n        \"python\": {\n          \"guess-unpinned-requirements\": false\n        }\n      },\n      \"relationships\": {\n        \"exclude-binary-packages-with-file-ownership-overlap\": true,\n        \"package-file-ownership\": true,\n        \"package-file-ownership-overlap\": true\n      },\n      \"search\": {\n        \"scope\": \"squashed\"\n      }\n    }\n  },\n  \"schema\": {\n    \"version\": \"16.0.4\",\n    \"url\": \"https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-16.0.4.json\"\n  }\n}\n"
  },
  {
    "path": "integration-test/spring-boot-configuration-processor-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Configuration Processor Integration Tests\"\n\ndependencies {\n\tannotationProcessor(project(\":configuration-metadata:spring-boot-configuration-processor\"))\n\n\timplementation(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\timplementation(project(\":core:spring-boot\"))\n\timplementation(\"jakarta.validation:jakarta.validation-api\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n\ttestImplementation(project(\":configuration-metadata:spring-boot-configuration-metadata\"))\n}"
  },
  {
    "path": "integration-test/spring-boot-configuration-processor-integration-tests/src/main/java/sample/AnnotatedSample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample;\n\nimport jakarta.validation.Valid;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Test that a valid type is generated if an annotation is present.\n *\n * @author Stephane Nicoll\n * @since 1.5.10\n */\n@ConfigurationProperties(\"annotated\")\npublic class AnnotatedSample {\n\n\t/**\n\t * A valid name.\n\t */\n\tprivate @Nullable String name;\n\n\t@Valid\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-configuration-processor-integration-tests/src/main/java/sample/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sample used for testing.\n */\n@NullMarked\npackage sample;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "integration-test/spring-boot-configuration-processor-integration-tests/src/test/java/org/springframework/boot/configurationprocessor/tests/ConfigurationProcessorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.configurationprocessor.tests;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;\nimport org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;\nimport org.springframework.util.CollectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the configuration metadata annotation processor.\n *\n * @author Stephane Nicoll\n */\nclass ConfigurationProcessorIntegrationTests {\n\n\tprivate static ConfigurationMetadataRepository repository;\n\n\t@BeforeAll\n\tstatic void readMetadata() throws IOException {\n\t\trepository = ConfigurationMetadataRepositoryJsonBuilder.create(getResource().openStream()).build();\n\t}\n\n\tprivate static URL getResource() throws IOException {\n\t\tClassLoader classLoader = ConfigurationProcessorIntegrationTests.class.getClassLoader();\n\t\tList<URL> urls = new ArrayList<>();\n\t\tCollectionUtils.toIterator(classLoader.getResources(\"META-INF/spring-configuration-metadata.json\"))\n\t\t\t.forEachRemaining(urls::add);\n\t\tfor (URL url : urls) {\n\t\t\tif (url.toString().contains(\"spring-boot-configuration-processor-integration-tests\")) {\n\t\t\t\treturn url;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Unable to find correct configuration-metadata resource from \" + urls);\n\t}\n\n\t@Test\n\tvoid extractTypeFromAnnotatedGetter() {\n\t\tConfigurationMetadataProperty property = repository.getAllProperties().get(\"annotated.name\");\n\t\tassertThat(property).isNotNull();\n\t\tassertThat(property.getType()).isEqualTo(\"java.lang.String\");\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Integration Tests\"\n\ndependencies {\n\ttestImplementation(project(\":core:spring-boot\"))\n\ttestImplementation(project(\":module:spring-boot-jetty\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\ttestImplementation(\"org.apache.httpcomponents.core5:httpcore5-reactive\")\n\ttestImplementation(\"org.eclipse.jetty:jetty-client\")\n\ttestImplementation(\"org.eclipse.jetty:jetty-reactive-httpclient\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.ee11:jetty-ee11-servlets\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.ee11:jetty-ee11-webapp\")\n}\n\ntest {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n"
  },
  {
    "path": "integration-test/spring-boot-integration-tests/src/test/java/org/springframework/boot/web/servlet/support/ErrorPageFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.support;\n\nimport java.net.URI;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.support.ErrorPageFilterIntegrationTests.EmbeddedWebContextLoader;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.context.support.AbstractContextLoader;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ErrorPageFilter}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@DirtiesContext\n@ContextConfiguration(classes = ErrorPageFilterIntegrationTests.TomcatConfig.class,\n\t\tloader = EmbeddedWebContextLoader.class)\nclass ErrorPageFilterIntegrationTests {\n\n\t@Autowired\n\tprivate HelloWorldController controller;\n\n\t@Autowired\n\tprivate AnnotationConfigServletWebServerApplicationContext context;\n\n\t@AfterEach\n\tvoid init() {\n\t\tthis.controller.reset();\n\t}\n\n\t@Test\n\tvoid created() throws Exception {\n\t\tdoTest(this.context, \"/create\", HttpStatus.CREATED);\n\t\tassertThat(this.controller.getStatus()).isEqualTo(201);\n\t}\n\n\t@Test\n\tvoid ok() throws Exception {\n\t\tdoTest(this.context, \"/hello\", HttpStatus.OK);\n\t\tassertThat(this.controller.getStatus()).isEqualTo(200);\n\t}\n\n\tprivate void doTest(AnnotationConfigServletWebServerApplicationContext context, String resourcePath,\n\t\t\tHttpStatus status) throws Exception {\n\t\tint port = context.getWebServer().getPort();\n\t\tRestTemplate template = new RestTemplate();\n\t\tResponseEntity<String> entity = template.getForEntity(new URI(\"http://localhost:\" + port + resourcePath),\n\t\t\t\tString.class);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t\tassertThat(entity.getStatusCode()).isEqualTo(status);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class TomcatConfig {\n\n\t\t@Bean\n\t\tServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tErrorPageFilter errorPageFilter() {\n\t\t\treturn new ErrorPageFilter();\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t\t@Bean\n\t\tHelloWorldController helloWorldController() {\n\t\t\treturn new HelloWorldController();\n\t\t}\n\n\t}\n\n\t@Controller\n\tstatic class HelloWorldController implements WebMvcConfigurer {\n\n\t\tprivate int status;\n\n\t\tprivate CountDownLatch latch = new CountDownLatch(1);\n\n\t\tint getStatus() throws InterruptedException {\n\t\t\tassertThat(this.latch.await(1, TimeUnit.SECONDS)).as(\"Timed out waiting for latch\").isTrue();\n\t\t\treturn this.status;\n\t\t}\n\n\t\tvoid setStatus(int status) {\n\t\t\tthis.status = status;\n\t\t}\n\n\t\tvoid reset() {\n\t\t\tthis.status = 0;\n\t\t\tthis.latch = new CountDownLatch(1);\n\t\t}\n\n\t\t@Override\n\t\tpublic void addInterceptors(InterceptorRegistry registry) {\n\t\t\tregistry.addInterceptor(new HandlerInterceptor() {\n\t\t\t\t@Override\n\t\t\t\tpublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,\n\t\t\t\t\t\tModelAndView modelAndView) {\n\t\t\t\t\tHelloWorldController.this.setStatus(response.getStatus());\n\t\t\t\t\tHelloWorldController.this.latch.countDown();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t@RequestMapping(\"/hello\")\n\t\t@ResponseBody\n\t\tString sayHello() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t\t@RequestMapping(\"/create\")\n\t\t@ResponseBody\n\t\t@ResponseStatus(HttpStatus.CREATED)\n\t\tString created() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n\tstatic class EmbeddedWebContextLoader extends AbstractContextLoader {\n\n\t\tprivate static final String[] EMPTY_RESOURCE_SUFFIXES = {};\n\n\t\t@Override\n\t\tpublic ApplicationContext loadContext(MergedContextConfiguration config) {\n\t\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\t\tconfig.getClasses());\n\t\t\tcontext.registerShutdownHook();\n\t\t\treturn context;\n\t\t}\n\n\t\t@Override\n\t\tprotected String[] getResourceSuffixes() {\n\t\t\treturn EMPTY_RESOURCE_SUFFIXES;\n\t\t}\n\n\t\t@Override\n\t\tprotected String getResourceSuffix() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"de.undercouch.download\"\n}\n\ndescription = \"Spring Boot Loader Integration Tests\"\n\ndef oracleJdkVersion = \"17.0.12\"\ndef oracleJdkArch = \"aarch64\".equalsIgnoreCase(System.getProperty(\"os.arch\")) ? \"aarch64\" : \"x64\"\n\nconfigurations {\n\tapp\n}\n\ndependencies {\n\tapp project(path: \":platform:spring-boot-dependencies\", configuration: \"mavenRepository\")\n\tapp project(path: \":build-plugin:spring-boot-gradle-plugin\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter-webmvc\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter\", configuration: \"mavenRepository\")\n\tapp(\"org.bouncycastle:bcprov-jdk18on:1.78.1\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.register(\"syncMavenRepository\", Sync) {\n\tfrom configurations.app\n\tinto layout.buildDirectory.dir(\"docker-test-maven-repository\")\n}\n\ntasks.register(\"syncAppSource\", org.springframework.boot.build.SyncAppSource) {\n\tsourceDirectory = file(\"spring-boot-loader-tests-app\")\n\tdestinationDirectory = file(layout.buildDirectory.dir(\"spring-boot-loader-tests-app\"))\n}\n\ntasks.register(\"buildApp\", GradleBuild) {\n\tdependsOn syncAppSource, syncMavenRepository\n\tdir = layout.buildDirectory.dir(\"spring-boot-loader-tests-app\")\n\tstartParameter.buildCacheEnabled = false\n\ttasks  = [\"build\"]\n}\n\ntasks.register(\"syncSignedJarAppSource\", org.springframework.boot.build.SyncAppSource) {\n\tsourceDirectory = file(\"spring-boot-loader-tests-signed-jar\")\n\tdestinationDirectory = file(layout.buildDirectory.dir(\"spring-boot-loader-tests-signed-jar\"))\n}\n\ntasks.register(\"buildSignedJarApp\", GradleBuild) {\n\tdependsOn syncSignedJarAppSource, syncMavenRepository\n\tdir = layout.buildDirectory.dir(\"spring-boot-loader-tests-signed-jar\")\n\tstartParameter.buildCacheEnabled = false\n\ttasks  = [\"build\"]\n}\n\ntasks.register(\"downloadJdk\", Download) {\n\tdef destFolder = new File(project.gradle.gradleUserHomeDir, \"caches/springboot/downloads/jdk/oracle\")\n\tdestFolder.mkdirs()\n\tsrc \"https://download.oracle.com/java/17/archive/jdk-${oracleJdkVersion}_linux-${oracleJdkArch}_bin.tar.gz\"\n\tdest destFolder\n\ttempAndMove true\n\toverwrite false\n\tretries 3\n}\n\ntasks.register(\"syncJdkDownloads\", Sync) {\n\tdependsOn downloadJdk\n\tfrom \"${project.gradle.gradleUserHomeDir}/caches/springboot/downloads/jdk/oracle/\"\n\tinclude \"jdk-${oracleJdkVersion}_linux-${oracleJdkArch}_bin.tar.gz\"\n\tinto layout.buildDirectory.dir(\"downloads/jdk/oracle/\")\n}\n\ntasks.named(\"processDockerTestResources\").configure {\n\tdependsOn syncJdkDownloads\n}\n\ntasks.named(\"dockerTest\").configure {\n\tdependsOn buildApp, buildSignedJarApp\n}\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-app/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot\"\n}\n\njava {\n\tsourceCompatibility = '17'\n\ttargetCompatibility = '17'\n}\n\nrepositories {\n\tmaven { url = layout.projectDirectory.dir(\"../docker-test-maven-repository\") }\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc\")\n\timplementation(\"org.webjars:jquery:3.5.0\")\n}\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-app/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${gradle.parent.rootProject.rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmaven { url = layout.settingsDirectory.dir(\"../docker-test-maven-repository\") }\n\t\tmavenCentral()\n\t\tspring.mavenRepositories()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.springframework.boot\") {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-app/src/main/java/org/springframework/boot/loaderapp/LoaderTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loaderapp;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\n\nimport jakarta.servlet.ServletContext;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\n\n@SpringBootApplication\npublic class LoaderTestApplication {\n\n\t@Bean\n\tpublic CommandLineRunner commandLineRunner(ServletContext servletContext) {\n\t\treturn (args) -> {\n\t\t\tFile temp = new File(System.getProperty(\"java.io.tmpdir\"));\n\t\t\tURL resourceUrl = servletContext.getResource(\"webjars/jquery/3.5.0/jquery.js\");\n\t\t\tJarURLConnection connection = (JarURLConnection) resourceUrl.openConnection();\n\t\t\tString jarName = connection.getJarFile().getName();\n\t\t\tSystem.out.println(\">>>>> jar file \" + jarName);\n\t\t\tif(jarName.contains(temp.getAbsolutePath())) {\n\t\t\t\tSystem.out.println(\">>>>> jar written to temp\");\n\t\t\t}\n\t\t\tbyte[] resourceContent = FileCopyUtils.copyToByteArray(resourceUrl.openStream());\n\t\t\tURL directUrl = new URL(resourceUrl.toExternalForm());\n\t\t\tbyte[] directContent = FileCopyUtils.copyToByteArray(directUrl.openStream());\n\t\t\tString message = (!Arrays.equals(resourceContent, directContent)) ? \"NO MATCH\"\n\t\t\t\t\t: directContent.length + \" BYTES\";\n\t\t\tSystem.out.println(\">>>>> \" + message + \" from \" + resourceUrl);\n\t\t\ttestGh7161();\n\t\t};\n\t}\n\n\tprivate void testGh7161() {\n\t\ttry {\n\t\t\tResource resource = new ClassPathResource(\"gh-7161\");\n\t\t\tPath path = Paths.get(resource.getURI());\n\t\t\tSystem.out.println(\">>>>> gh-7161 \" + Files.list(path).toList());\n\t\t} catch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(LoaderTestApplication.class, args).close();\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-app/src/main/resources/gh-7161/example.txt",
    "content": ""
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-signed-jar/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot\"\n}\n\njava {\n\tsourceCompatibility = '17'\n\ttargetCompatibility = '17'\n}\n\nrepositories {\n\tmaven { url = layout.projectDirectory.dir(\"../docker-test-maven-repository\") }\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.springframework.boot:spring-boot-starter\")\n\timplementation(\"org.bouncycastle:bcprov-jdk18on:1.78.1\")\n}\n\ntasks.register(\"bootJarUnpack\", BootJar.class) {\n\tmainClass = \"org.springframework.boot.loaderapp.LoaderSignedJarTestApplication\"\n\tclasspath = bootJar.classpath\n\trequiresUnpack '**/bcprov-jdk18on-*.jar'\n\tarchiveClassifier.set(\"unpack\")\n\ttargetJavaVersion = java.targetCompatibility\n}\n\nbuild.dependsOn bootJarUnpack\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-signed-jar/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${gradle.parent.rootProject.rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmaven { url = layout.settingsDirectory.dir(\"../docker-test-maven-repository\") }\n\t\tmavenCentral()\n\t\tspring.mavenRepositories()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.springframework.boot\") {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/spring-boot-loader-tests-signed-jar/src/main/java/org/springframework/boot/loaderapp/LoaderSignedJarTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loaderapp;\n\nimport java.security.Security;\nimport javax.crypto.Cipher;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class LoaderSignedJarTestApplication {\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tSecurity.addProvider(new BouncyCastleProvider());\n\t\tCipher.getInstance(\"AES/CBC/PKCS5Padding\",\"BC\");\n\t\tSystem.out.println(\"Legion of the Bouncy Castle\");\n\t\tSpringApplication.run(LoaderSignedJarTestApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/src/dockerTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.output.ToStringConsumer;\nimport org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy;\nimport org.testcontainers.images.builder.ImageFromDockerfile;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\nimport org.springframework.boot.system.JavaVersion;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests loader that supports fat jars.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@DisabledIfDockerUnavailable\nclass LoaderIntegrationTests {\n\n\tprivate final ToStringConsumer output = new ToStringConsumer();\n\n\t@ParameterizedTest\n\t@MethodSource(\"javaRuntimes\")\n\tvoid runJar(JavaRuntime javaRuntime) {\n\t\ttry (GenericContainer<?> container = createContainer(javaRuntime, \"spring-boot-loader-tests-app\", null)) {\n\t\t\tcontainer.start();\n\t\t\tSystem.out.println(this.output.toUtf8String());\n\t\t\tassertThat(this.output.toUtf8String()).contains(\">>>>> 287649 BYTES from\")\n\t\t\t\t.contains(\">>>>> gh-7161 [/gh-7161/example.txt]\")\n\t\t\t\t.doesNotContain(\"WARNING:\")\n\t\t\t\t.doesNotContain(\"illegal\")\n\t\t\t\t.doesNotContain(\"jar written to temp\");\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"javaRuntimes\")\n\tvoid runSignedJar(JavaRuntime javaRuntime) {\n\t\ttry (GenericContainer<?> container = createContainer(javaRuntime, \"spring-boot-loader-tests-signed-jar\",\n\t\t\t\tnull)) {\n\t\t\tcontainer.start();\n\t\t\tSystem.out.println(this.output.toUtf8String());\n\t\t\tassertThat(this.output.toUtf8String()).contains(\"Legion of the Bouncy Castle\");\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"javaRuntimes\")\n\tvoid runSignedJarWhenUnpack(JavaRuntime javaRuntime) {\n\t\ttry (GenericContainer<?> container = createContainer(javaRuntime, \"spring-boot-loader-tests-signed-jar\",\n\t\t\t\t\"unpack\")) {\n\t\t\tcontainer.start();\n\t\t\tSystem.out.println(this.output.toUtf8String());\n\t\t\tassertThat(this.output.toUtf8String()).contains(\"Legion of the Bouncy Castle\");\n\t\t}\n\t}\n\n\tprivate GenericContainer<?> createContainer(JavaRuntime javaRuntime, String name, String classifier) {\n\t\treturn javaRuntime.getContainer()\n\t\t\t.withLogConsumer(this.output)\n\t\t\t.withCopyFileToContainer(findApplication(name, classifier), \"/app.jar\")\n\t\t\t.withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(5)))\n\t\t\t.withCommand(command());\n\t}\n\n\tprivate String[] command() {\n\t\tList<String> command = new ArrayList<>();\n\t\tcommand.add(\"java\");\n\t\tcommand.add(\"-jar\");\n\t\tcommand.add(\"app.jar\");\n\t\treturn command.toArray(new String[0]);\n\t}\n\n\tprivate MountableFile findApplication(String name, String classifier) {\n\t\treturn MountableFile.forHostPath(findJarFile(name, classifier).toPath());\n\t}\n\n\tprivate File findJarFile(String name, String classifier) {\n\t\tclassifier = (classifier != null) ? \"-\" + classifier : \"\";\n\t\tString path = String.format(\"build/%1$s/build/libs/%1$s%2$s.jar\", name, classifier);\n\t\tFile jar = new File(path);\n\t\tAssert.state(jar.isFile(), () -> \"Could not find \" + path + \". Have you built it?\");\n\t\treturn jar;\n\t}\n\n\tstatic Stream<JavaRuntime> javaRuntimes() {\n\t\tList<JavaRuntime> javaRuntimes = new ArrayList<>();\n\t\tjavaRuntimes.add(JavaRuntime.openJdk(JavaVersion.SEVENTEEN));\n\t\tjavaRuntimes.add(JavaRuntime.openJdk(JavaVersion.TWENTY_ONE));\n\t\tjavaRuntimes.add(JavaRuntime.oracleJdk17());\n\t\tjavaRuntimes.add(JavaRuntime.openJdk(JavaVersion.TWENTY_TWO));\n\t\tjavaRuntimes.add(JavaRuntime.openJdk(JavaVersion.TWENTY_THREE));\n\t\tjavaRuntimes.add(JavaRuntime.openJdk(JavaVersion.TWENTY_FOUR));\n\t\tjavaRuntimes.add(JavaRuntime.openJdk(JavaVersion.TWENTY_FIVE));\n\t\tjavaRuntimes.add(JavaRuntime.openJdkEarlyAccess(JavaVersion.TWENTY_SIX));\n\t\treturn javaRuntimes.stream().filter(JavaRuntime::isCompatible);\n\t}\n\n\tstatic final class JavaRuntime {\n\n\t\tprivate final String name;\n\n\t\tprivate final JavaVersion version;\n\n\t\tprivate final Supplier<GenericContainer<?>> container;\n\n\t\tprivate JavaRuntime(String name, JavaVersion version, Supplier<GenericContainer<?>> container) {\n\t\t\tthis.name = name;\n\t\t\tthis.version = version;\n\t\t\tthis.container = container;\n\t\t}\n\n\t\tprivate boolean isCompatible() {\n\t\t\treturn this.version.isEqualOrNewerThan(JavaVersion.getJavaVersion());\n\t\t}\n\n\t\tGenericContainer<?> getContainer() {\n\t\t\treturn this.container.get();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tstatic JavaRuntime openJdkEarlyAccess(JavaVersion version) {\n\t\t\tString imageVersion = version.toString();\n\t\t\tDockerImageName image = DockerImageName.parse(\"openjdk:%s-ea-jdk\".formatted(imageVersion));\n\t\t\treturn new JavaRuntime(\"OpenJDK Early Access \" + imageVersion, version,\n\t\t\t\t\t() -> new GenericContainer<>(image));\n\t\t}\n\n\t\tstatic JavaRuntime openJdk(JavaVersion version) {\n\t\t\tString imageVersion = version.toString();\n\t\t\tDockerImageName image = DockerImageName.parse(\"bellsoft/liberica-openjdk-debian:\" + imageVersion);\n\t\t\treturn new JavaRuntime(\"OpenJDK \" + imageVersion, version, () -> new GenericContainer<>(image));\n\t\t}\n\n\t\tstatic JavaRuntime oracleJdk17() {\n\t\t\tImageFromDockerfile image = new ImageFromDockerfile(\"spring-boot-loader/oracle-jdk\");\n\t\t\timage.withFileFromFile(\"Dockerfile\", new File(\"src/dockerTest/resources/conf/oracle-jdk-17/Dockerfile\"));\n\t\t\tfor (File file : new File(\"build/downloads/jdk/oracle\").listFiles()) {\n\t\t\t\timage.withFileFromFile(\"downloads/\" + file.getName(), file);\n\t\t\t}\n\t\t\treturn new JavaRuntime(\"Oracle JDK 17\", JavaVersion.SEVENTEEN, () -> new GenericContainer<>(image));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/src/dockerTest/resources/conf/oracle-jdk-17/Dockerfile",
    "content": "FROM ubuntu:noble-20250404 as prepare\nCOPY downloads/* /opt/download/\nRUN mkdir -p /opt/jdk && \\\n    cd /opt/jdk && \\\n    tar xzf  /opt/download/* --strip-components=1\n\nFROM ubuntu:noble-20250404\nCOPY --from=prepare /opt/jdk /opt/jdk\nENV JAVA_HOME /opt/jdk\nENV PATH $JAVA_HOME/bin:$PATH\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/src/dockerTest/resources/conf/oracle-jdk-17/README.adoc",
    "content": "This folder contains a Dockerfile that will create an Oracle JDK instance for use in integration tests.\nThe resulting Docker image should not be published.\n\nOracle JDK is subject to the https://www.oracle.com/downloads/licenses/no-fee-license.html[\"Oracle No-Fee Terms and Conditions\" License (NFTC)] license.\nWe are specifically using the unmodified JDK for the purposes of developing and testing.\n"
  },
  {
    "path": "integration-test/spring-boot-loader-integration-tests/src/dockerTest/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.integration-test\"\n}\n\ndescription = \"Spring Boot Server Integration Tests\"\n\nconfigurations {\n\ttestRepository\n}\n\ndependencies {\n\tintTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tintTestImplementation(project(\":test-support:spring-boot-test-support\"))\n\tintTestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\tintTestImplementation(\"org.springframework:spring-web\")\n\n\ttestRepository(project(path: \":platform:spring-boot-dependencies\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":build-plugin:spring-boot-gradle-plugin\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":starter:spring-boot-starter\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":starter:spring-boot-starter-jetty\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":starter:spring-boot-starter-jackson\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":starter:spring-boot-starter-parent\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":starter:spring-boot-starter-tomcat\", configuration: \"mavenRepository\"))\n\n\ttestRuntimeOnly(project(\":starter:spring-boot-starter-logging\"))\n}\n\ntasks.register(\"syncTestRepository\", Sync) {\n\tdestinationDir = file(layout.buildDirectory.dir(\"test-repository\"))\n\tfrom {\n\t\tconfigurations.testRepository\n\t}\n}\n\ntasks.register(\"syncAppSource\", org.springframework.boot.build.SyncAppSource) {\n\tsourceDirectory = file(\"spring-boot-server-tests-app\")\n\tdestinationDirectory = file(layout.buildDirectory.dir(\"spring-boot-server-tests-app\"))\n}\n\ntasks.register(\"buildApps\", GradleBuild) {\n\tdependsOn syncAppSource, syncTestRepository\n\tdir = layout.buildDirectory.dir(\"spring-boot-server-tests-app\")\n\tstartParameter.buildCacheEnabled = false\n\ttasks = [\n\t\t\"jettyBootJar\",\n\t\t\"jettyBootWar\",\n\t\t\"tomcatBootJar\",\n\t\t\"tomcatBootWar\"\n\t]\n}\n\nintTest {\n\tinputs.files(\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-jetty.jar\"),\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-jetty.war\"),\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-resources.jar\"),\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat.jar\"),\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat.war\")\n\t)\n\t\t.withPropertyName(\"applicationArchives\")\n\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t.withNormalizer(ClasspathNormalizer)\n\tdependsOn buildApps\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar\nimport org.springframework.boot.gradle.tasks.bundling.BootWar\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot\"\n\tid \"war\"\n}\n\njava {\n\tsourceCompatibility = '17'\n\ttargetCompatibility = '17'\n}\n\nrepositories {\n\tmaven { url = layout.projectDirectory.dir(\"../test-repository\") }\n\tmavenCentral()\n\tspring.mavenRepositoriesExcludingBootGroup()\n}\n\nconfigurations {\n\tapp {\n\t\textendsFrom(configurations.runtimeClasspath)\n\t}\n\tjetty {\n\t\textendsFrom(app)\n\t}\n\ttomcat {\n\t\textendsFrom(app)\n\t}\n}\n\ntasks.register(\"resourcesJar\", Jar) { jar ->\n\tdef nested = project.resources.text.fromString(\"nested\")\n\tfrom(nested) {\n\t\tinto \"META-INF/resources/\"\n\t\trename (\".*\", \"nested-meta-inf-resource.txt\")\n\t}\n\tif (!isWindows()) {\n\t\tdef encodedName = project.resources.text.fromString(\"encoded-name\")\n\t\tfrom(encodedName) {\n\t\t\tinto \"META-INF/resources/\"\n\t\t\trename (\".*\", 'nested-reserved-!#\\\\$%&()*+,:=?@[]-meta-inf-resource.txt')\n\t\t}\n\t}\n\tarchiveClassifier = 'resources'\n}\n\ndependencies {\n\tcompileOnly(\"org.springframework:spring-web\")\n\tcompileOnly(\"org.springframework.boot:spring-boot-jetty\")\n\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.springframework.boot:spring-boot-starter\")\n\n\tapp(files(resourcesJar))\n\tapp(files(sourceSets.main.output))\n\tapp(\"org.springframework:spring-web\")\n\tjetty(\"org.springframework.boot:spring-boot-starter-jetty\")\n\ttomcat(\"org.springframework.boot:spring-boot-starter-tomcat\")\n}\n\nstatic boolean isWindows() {\n\treturn File.separatorChar == '\\\\'\n}\n\n[\"jetty\", \"tomcat\"].each { webServer ->\n\tdef configurer = { task ->\n\t\ttask.dependsOn resourcesJar\n\t\ttask.mainClass = \"com.example.ResourceHandlingApplication\"\n\t\ttask.classpath = configurations.getByName(webServer)\n\t\ttask.archiveClassifier = webServer\n\t\ttask.targetJavaVersion = java.targetCompatibility\n\t}\n\ttasks.register(\"${webServer}BootJar\", BootJar, configurer)\n\ttasks.register(\"${webServer}BootWar\", BootWar, configurer)\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${gradle.parent.rootProject.rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmaven { url = layout.settingsDirectory.dir(\"../test-repository\") }\n\t\tmavenCentral()\n\t\tspring.mavenRepositoriesExcludingBootGroup()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.springframework.boot\") {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/src/main/java/com/autoconfig/ExampleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.autoconfig;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWarDeployment;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\n\n@AutoConfiguration\npublic final class ExampleAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnWarDeployment\n\tServletRegistrationBean<TestServlet> onWarTestServlet() {\n\t\tServletRegistrationBean<TestServlet> registration = new ServletRegistrationBean<>(new TestServlet());\n\t\tregistration.addUrlMappings(\"/conditionalOnWar\");\n\t\treturn registration;\n\t}\n\n\t@Bean\n\tServletRegistrationBean<TestServlet> testServlet() {\n\t\tServletRegistrationBean<TestServlet> registration = new ServletRegistrationBean<>(new TestServlet());\n\t\tregistration.addUrlMappings(\"/always\");\n\t\treturn registration;\n\t}\n\n\tstatic class TestServlet extends HttpServlet {\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t\tresp.setContentType(MediaType.APPLICATION_JSON_VALUE);\n\t\t\tresp.getWriter().println(\"{\\\"hello\\\":\\\"world\\\"}\");\n\t\t\tresp.flushBuffer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/src/main/java/com/example/JettyServerCustomizerConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example;\n\nimport org.eclipse.jetty.http.UriCompliance;\nimport org.eclipse.jetty.server.AllowedResourceAliasChecker;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.HttpConnectionFactory;\nimport org.eclipse.jetty.server.handler.ContextHandler;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link JettyServerCustomizer} that:\n * <ul>\n * <li>Approves all aliases to allow access to unusually named static resources\n * <li>Relaxes URI compliance to allow access to static resources with {@code %} in their file name.\n * </ul>\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\n@ConditionalOnClass(name = {\"org.eclipse.jetty.server.handler.ContextHandler\"})\n@Configuration(proxyBeanMethods = false)\npublic class JettyServerCustomizerConfig {\n\n\t@Bean\n\tpublic JettyServerCustomizer jettyServerCustomizer() {\n\t\treturn (server) -> {\n\t\t\tContextHandler handler = (ContextHandler) server.getHandler();\n\t\t\thandler.addAliasCheck((path, resource) -> true);\n\n\t\t\tfor (Connector connector : server.getConnectors()) {\n\t\t\t\tconnector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration()\n\t\t\t\t\t\t.setUriCompliance(UriCompliance.LEGACY);\n\t\t\t}\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/src/main/java/com/example/ResourceHandlingApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.server.context.WebServerPortFileWriter;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Test application for verifying an embedded container's static resource handling.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class ResourceHandlingApplication {\n\n\t@Bean\n\tpublic ServletRegistrationBean<?> resourceServletRegistration() {\n\t\tServletRegistrationBean<?> registration = new ServletRegistrationBean<HttpServlet>(new GetResourceServlet());\n\t\tregistration.addUrlMappings(\"/servletContext\");\n\t\treturn registration;\n\t}\n\n\t@Bean\n\tpublic ServletRegistrationBean<?> resourcePathsServletRegistration() {\n\t\tServletRegistrationBean<?> registration = new ServletRegistrationBean<HttpServlet>(\n\t\t\t\tnew GetResourcePathsServlet());\n\t\tregistration.addUrlMappings(\"/resourcePaths\");\n\t\treturn registration;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\ttry {\n\t\t\tClass.forName(\"org.springframework.web.servlet.DispatcherServlet\");\n\t\t\tSystem.err.println(\"Spring MVC must not be present, otherwise its static resource handling \"\n\t\t\t\t\t+ \"will be used rather than the embedded containers'\");\n\t\t\tSystem.exit(1);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tnew SpringApplicationBuilder(ResourceHandlingApplication.class).properties(\"server.port:0\")\n\t\t\t\t\t.listeners(new WebServerPortFileWriter(args[0])).run(args);\n\t\t}\n\t}\n\n\tprivate static final class GetResourcePathsServlet extends HttpServlet {\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t\tcollectResourcePaths(\"/\").forEach(resp.getWriter()::println);\n\t\t\tresp.getWriter().flush();\n\t\t}\n\n\t\tprivate Set<String> collectResourcePaths(String path) {\n\t\t\tSet<String> allResourcePaths = new LinkedHashSet<>();\n\t\t\tSet<String> pathsForPath = getServletContext().getResourcePaths(path);\n\t\t\tif (pathsForPath != null) {\n\t\t\t\tfor (String resourcePath : pathsForPath) {\n\t\t\t\t\tallResourcePaths.add(resourcePath);\n\t\t\t\t\tallResourcePaths.addAll(collectResourcePaths(resourcePath));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn allResourcePaths;\n\t\t}\n\n\t}\n\n\tprivate static final class GetResourceServlet extends HttpServlet {\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t\tURL resource = getServletContext().getResource(req.getQueryString());\n\t\t\tif (resource == null) {\n\t\t\t\tresp.sendError(404);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresp.getWriter().println(resource);\n\t\t\t\tresp.getWriter().flush();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "com.autoconfig.ExampleAutoConfiguration"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/spring-boot-server-tests-app/src/main/webapp/webapp-resource.txt",
    "content": "webapp resource"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/AbstractApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintStream;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for launching a Spring Boot application as part of a JUnit test.\n *\n * @author Andy Wilkinson\n */\nabstract class AbstractApplicationLauncher implements BeforeEachCallback {\n\n\tprivate final Application application;\n\n\tprivate final File outputLocation;\n\n\tprivate Process process;\n\n\tprivate int httpPort;\n\n\tprotected AbstractApplicationLauncher(Application application, File outputLocation) {\n\t\tthis.application = application;\n\t\tthis.outputLocation = outputLocation;\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tif (this.process == null) {\n\t\t\tthis.process = startApplication();\n\t\t}\n\t}\n\n\tvoid destroyProcess() {\n\t\tif (this.process != null) {\n\t\t\tthis.process.destroy();\n\t\t\ttry {\n\t\t\t\tthis.process.waitFor();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t\tFileSystemUtils.deleteRecursively(this.outputLocation);\n\t}\n\n\tfinal int getHttpPort() {\n\t\treturn this.httpPort;\n\t}\n\n\tprotected abstract List<String> getArguments(File archive, File serverPortFile);\n\n\tprotected abstract File getWorkingDirectory();\n\n\tprotected abstract String getDescription(String packaging);\n\n\tprivate Process startApplication() throws Exception {\n\t\tFile workingDirectory = getWorkingDirectory();\n\t\tFile serverPortFile = new File(this.outputLocation, \"server.port\");\n\t\tserverPortFile.delete();\n\t\tFile archive = new File(\"build/spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-\"\n\t\t\t\t+ this.application.getContainer() + \".\" + this.application.getPackaging());\n\t\tList<String> arguments = new ArrayList<>();\n\t\targuments.add(System.getProperty(\"java.home\") + \"/bin/java\");\n\t\targuments.addAll(getArguments(archive, serverPortFile));\n\t\targuments.add(\"--server.servlet.register-default-servlet=true\");\n\t\tProcessBuilder processBuilder = new ProcessBuilder(StringUtils.toStringArray(arguments));\n\t\tif (workingDirectory != null) {\n\t\t\tprocessBuilder.directory(workingDirectory);\n\t\t}\n\t\tProcess process = processBuilder.start();\n\t\tnew ConsoleCopy(process.getInputStream(), System.out).start();\n\t\tnew ConsoleCopy(process.getErrorStream(), System.err).start();\n\t\tthis.httpPort = awaitServerPort(process, serverPortFile);\n\t\treturn process;\n\t}\n\n\tprivate int awaitServerPort(Process process, File serverPortFile) throws Exception {\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(180)).until(serverPortFile::length, (length) -> {\n\t\t\tif (!process.isAlive()) {\n\t\t\t\tthrow new IllegalStateException(\"Application failed to start\");\n\t\t\t}\n\t\t\treturn length > 0;\n\t\t});\n\t\treturn Integer.parseInt(FileCopyUtils.copyToString(new FileReader(serverPortFile)));\n\t}\n\n\tprivate static class ConsoleCopy extends Thread {\n\n\t\tprivate final InputStream input;\n\n\t\tprivate final PrintStream output;\n\n\t\tConsoleCopy(InputStream input, PrintStream output) {\n\t\t\tthis.input = input;\n\t\t\tthis.output = output;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\ttry {\n\t\t\t\tStreamUtils.copy(this.input, this.output);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/Application.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\n\n/**\n * A pre-built application that can be launched.\n *\n * @author Andy Wilkinson\n */\nclass Application {\n\n\tprivate final String packaging;\n\n\tprivate final String container;\n\n\tApplication(String packaging, String container) {\n\t\tthis.packaging = packaging;\n\t\tthis.container = container;\n\t}\n\n\tString getPackaging() {\n\t\treturn this.packaging;\n\t}\n\n\tString getContainer() {\n\t\treturn this.container;\n\t}\n\n\tFile getArchive() {\n\t\treturn new File(\"build/spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-\" + this.container\n\t\t\t\t+ \".\" + this.packaging);\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/BootRunApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link AbstractApplicationLauncher} that launches a Spring Boot application with a\n * classpath similar to that used when run with Maven or Gradle.\n *\n * @author Andy Wilkinson\n */\nclass BootRunApplicationLauncher extends AbstractApplicationLauncher {\n\n\tprivate final File exploded;\n\n\tBootRunApplicationLauncher(Application application, File outputLocation) {\n\t\tsuper(application, outputLocation);\n\t\tthis.exploded = new File(outputLocation, \"run\");\n\t}\n\n\t@Override\n\tprotected List<String> getArguments(File archive, File serverPortFile) {\n\t\ttry {\n\t\t\texplodeArchive(archive);\n\t\t\tdeleteLauncherClasses();\n\t\t\tFile targetClasses = populateTargetClasses(archive);\n\t\t\tFile dependencies = populateDependencies(archive);\n\t\t\tif (archive.getName().endsWith(\".war\")) {\n\t\t\t\tpopulateSrcMainWebapp();\n\t\t\t}\n\t\t\tList<String> classpath = new ArrayList<>();\n\t\t\tclasspath.add(targetClasses.getAbsolutePath());\n\t\t\tfor (File dependency : dependencies.listFiles()) {\n\t\t\t\tclasspath.add(dependency.getAbsolutePath());\n\t\t\t}\n\t\t\treturn Arrays.asList(\"-cp\", StringUtils.collectionToDelimitedString(classpath, File.pathSeparator),\n\t\t\t\t\t\"com.example.ResourceHandlingApplication\", serverPortFile.getAbsolutePath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void deleteLauncherClasses() {\n\t\tFileSystemUtils.deleteRecursively(new File(this.exploded, \"org\"));\n\t}\n\n\tprivate File populateTargetClasses(File archive) throws IOException {\n\t\tFile builtClasses = new File(this.exploded, \"built/classes\");\n\t\tbuiltClasses.mkdirs();\n\t\tFile source = new File(this.exploded, getClassesPath(archive));\n\t\tFileSystemUtils.copyRecursively(source, builtClasses);\n\t\tFileSystemUtils.deleteRecursively(source);\n\t\treturn builtClasses;\n\t}\n\n\tprivate File populateDependencies(File archive) throws IOException {\n\t\tFile dependencies = new File(this.exploded, \"dependencies\");\n\t\tdependencies.mkdirs();\n\t\tList<String> libPaths = getLibPaths(archive);\n\t\tfor (String libPath : libPaths) {\n\t\t\tFile libDirectory = new File(this.exploded, libPath);\n\t\t\tfor (File jar : libDirectory.listFiles()) {\n\t\t\t\tFileCopyUtils.copy(jar, new File(dependencies, jar.getName()));\n\t\t\t}\n\t\t\tFileSystemUtils.deleteRecursively(libDirectory);\n\t\t}\n\t\treturn dependencies;\n\t}\n\n\tprivate void populateSrcMainWebapp() throws IOException {\n\t\tFile srcMainWebapp = new File(this.exploded, \"src/main/webapp\");\n\t\tsrcMainWebapp.mkdirs();\n\t\tFile source = new File(this.exploded, \"webapp-resource.txt\");\n\t\tFileCopyUtils.copy(source, new File(srcMainWebapp, \"webapp-resource.txt\"));\n\t\tsource.delete();\n\t}\n\n\tprivate String getClassesPath(File archive) {\n\t\treturn (archive.getName().endsWith(\".jar\") ? \"BOOT-INF/classes\" : \"WEB-INF/classes\");\n\t}\n\n\tprivate List<String> getLibPaths(File archive) {\n\t\treturn (archive.getName().endsWith(\".jar\") ? Collections.singletonList(\"BOOT-INF/lib\")\n\t\t\t\t: Arrays.asList(\"WEB-INF/lib\"));\n\t}\n\n\tprivate void explodeArchive(File archive) throws IOException {\n\t\tFileSystemUtils.deleteRecursively(this.exploded);\n\t\tJarFile jarFile = new JarFile(archive);\n\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\twhile (entries.hasMoreElements()) {\n\t\t\tJarEntry jarEntry = entries.nextElement();\n\t\t\tFile extracted = new File(this.exploded, jarEntry.getName());\n\t\t\tif (jarEntry.isDirectory()) {\n\t\t\t\textracted.mkdirs();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tFileOutputStream extractedOutputStream = new FileOutputStream(extracted);\n\t\t\t\tStreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);\n\t\t\t\textractedOutputStream.close();\n\t\t\t}\n\t\t}\n\t\tjarFile.close();\n\t}\n\n\t@Override\n\tprotected File getWorkingDirectory() {\n\t\treturn this.exploded;\n\t}\n\n\t@Override\n\tprotected String getDescription(String packaging) {\n\t\treturn \"build system run \" + packaging + \" project\";\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServerContainerInvocationContextProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.net.URI;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Stream;\n\nimport org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.core5.util.TimeValue;\nimport org.junit.jupiter.api.extension.AfterAllCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolver;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.client.NoOpResponseErrorHandler;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * {@link TestTemplateInvocationContextProvider} for templated\n * {@link EmbeddedServletContainerTest embedded servlet container tests}.\n *\n * @author Andy Wilkinson\n */\nclass EmbeddedServerContainerInvocationContextProvider\n\t\timplements TestTemplateInvocationContextProvider, AfterAllCallback {\n\n\tprivate static final Set<String> CONTAINERS = new HashSet<>(Arrays.asList(\"jetty\", \"tomcat\"));\n\n\tprivate static final BuildOutput buildOutput = new BuildOutput(\n\t\t\tEmbeddedServerContainerInvocationContextProvider.class);\n\n\tprivate final Map<String, AbstractApplicationLauncher> launcherCache = new HashMap<>();\n\n\tprivate final Path tempDir;\n\n\tEmbeddedServerContainerInvocationContextProvider() throws IOException {\n\t\tthis.tempDir = Files.createTempDirectory(\"embedded-servlet-container-tests\");\n\t}\n\n\t@Override\n\tpublic boolean supportsTestTemplate(ExtensionContext context) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {\n\t\tEmbeddedServletContainerTest annotation = context.getRequiredTestClass()\n\t\t\t.getAnnotation(EmbeddedServletContainerTest.class);\n\t\treturn CONTAINERS.stream()\n\t\t\t.map((container) -> getApplication(annotation, container))\n\t\t\t.flatMap((builder) -> provideTestTemplateInvocationContexts(annotation, builder));\n\t}\n\n\tprivate Stream<EmbeddedServletContainerInvocationContext> provideTestTemplateInvocationContexts(\n\t\t\tEmbeddedServletContainerTest annotation, Application application) {\n\t\treturn Stream.of(annotation.launchers())\n\t\t\t.map((launcherClass) -> getAbstractApplicationLauncher(application, launcherClass))\n\t\t\t.map((launcher) -> provideTestTemplateInvocationContext(application, launcher));\n\t}\n\n\tprivate EmbeddedServletContainerInvocationContext provideTestTemplateInvocationContext(Application application,\n\t\t\tAbstractApplicationLauncher launcher) {\n\t\tString name = StringUtils.capitalize(application.getContainer()) + \": \"\n\t\t\t\t+ launcher.getDescription(application.getPackaging());\n\t\treturn new EmbeddedServletContainerInvocationContext(name, launcher);\n\t}\n\n\t@Override\n\tpublic void afterAll(ExtensionContext context) throws Exception {\n\t\tcleanupCaches();\n\t\tFileSystemUtils.deleteRecursively(this.tempDir);\n\t}\n\n\tprivate void cleanupCaches() {\n\t\tthis.launcherCache.values().forEach(AbstractApplicationLauncher::destroyProcess);\n\t\tthis.launcherCache.clear();\n\t}\n\n\tprivate AbstractApplicationLauncher getAbstractApplicationLauncher(Application application,\n\t\t\tClass<? extends AbstractApplicationLauncher> launcherClass) {\n\t\tString cacheKey = application.getContainer() + \":\" + application.getPackaging() + \":\" + launcherClass.getName();\n\t\tAbstractApplicationLauncher cachedLauncher = this.launcherCache.get(cacheKey);\n\t\tif (cachedLauncher != null) {\n\t\t\treturn cachedLauncher;\n\t\t}\n\t\ttry {\n\t\t\tConstructor<? extends AbstractApplicationLauncher> constructor = ReflectionUtils\n\t\t\t\t.accessibleConstructor(launcherClass, Application.class, File.class);\n\t\t\tAbstractApplicationLauncher launcher = BeanUtils.instantiateClass(constructor, application,\n\t\t\t\t\tnew File(buildOutput.getRootLocation(), \"app-launcher-\" + UUID.randomUUID()));\n\t\t\tthis.launcherCache.put(cacheKey, launcher);\n\t\t\treturn launcher;\n\t\t}\n\t\tcatch (NoSuchMethodException ex) {\n\t\t\tthrow new IllegalStateException(String\n\t\t\t\t.format(\"Launcher class %s does not have an (Application, File) constructor\", launcherClass.getName()));\n\t\t}\n\t}\n\n\tprivate Application getApplication(EmbeddedServletContainerTest annotation, String container) {\n\t\treturn new Application(annotation.packaging(), container);\n\t}\n\n\tstatic class EmbeddedServletContainerInvocationContext implements TestTemplateInvocationContext, ParameterResolver {\n\n\t\tprivate final String name;\n\n\t\tprivate final AbstractApplicationLauncher launcher;\n\n\t\tEmbeddedServletContainerInvocationContext(String name, AbstractApplicationLauncher launcher) {\n\t\t\tthis.name = name;\n\t\t\tthis.launcher = launcher;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Extension> getAdditionalExtensions() {\n\t\t\treturn Arrays.asList(this.launcher, new RestTemplateParameterResolver(this.launcher));\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDisplayName(int invocationIndex) {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\tif (parameterContext.getParameter().getType().equals(AbstractApplicationLauncher.class)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn parameterContext.getParameter().getType().equals(RestTemplate.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\tif (parameterContext.getParameter().getType().equals(AbstractApplicationLauncher.class)) {\n\t\t\t\treturn this.launcher;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate static final class RestTemplateParameterResolver implements ParameterResolver {\n\n\t\tprivate final AbstractApplicationLauncher launcher;\n\n\t\tprivate RestTemplateParameterResolver(AbstractApplicationLauncher launcher) {\n\t\t\tthis.launcher = launcher;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\treturn parameterContext.getParameter().getType().equals(RestTemplate.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\tRestTemplate rest = new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClients.custom()\n\t\t\t\t.setRetryStrategy(new DefaultHttpRequestRetryStrategy(10, TimeValue.of(1, TimeUnit.SECONDS)))\n\t\t\t\t.build()));\n\t\t\trest.setErrorHandler(new NoOpResponseErrorHandler());\n\t\t\trest.setUriTemplateHandler(new UriTemplateHandler() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic URI expand(String uriTemplate, Object... uriVariables) {\n\t\t\t\t\treturn URI.create(\"http://localhost:\" + RestTemplateParameterResolver.this.launcher.getHttpPort()\n\t\t\t\t\t\t\t+ uriTemplate);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic URI expand(String uriTemplate, Map<String, ?> uriVariables) {\n\t\t\t\t\treturn URI.create(\"http://localhost:\" + RestTemplateParameterResolver.this.launcher.getHttpPort()\n\t\t\t\t\t\t\t+ uriTemplate);\n\t\t\t\t}\n\n\t\t\t});\n\t\t\treturn rest;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServletContainerJarDevelopmentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring Boot's embedded servlet container support when developing\n * a jar application.\n *\n * @author Andy Wilkinson\n */\n@EmbeddedServletContainerTest(packaging = \"jar\",\n\t\tlaunchers = { BootRunApplicationLauncher.class, IdeApplicationLauncher.class })\nclass EmbeddedServletContainerJarDevelopmentIntegrationTests {\n\n\t@TestTemplate\n\tvoid metaInfResourceFromDependencyIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/nested-meta-inf-resource.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid metaInfResourceFromDependencyWithNameThatContainsReservedCharactersIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\n\t\t\t\t\"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"encoded-name\");\n\t}\n\n\t@TestTemplate\n\tvoid metaInfResourceFromDependencyIsAvailableViaServletContext(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/servletContext?/nested-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServletContainerJarPackagingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring Boot's embedded servlet container support using jar\n * packaging.\n *\n * @author Andy Wilkinson\n */\n@EmbeddedServletContainerTest(packaging = \"jar\",\n\t\tlaunchers = { PackagedApplicationLauncher.class, ExplodedApplicationLauncher.class })\nclass EmbeddedServletContainerJarPackagingIntegrationTests {\n\n\t@TestTemplate\n\tvoid nestedMetaInfResourceIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/nested-meta-inf-resource.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid nestedMetaInfResourceWithNameThatContainsReservedCharactersIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\n\t\t\t\t\"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"encoded-name\");\n\t}\n\n\t@TestTemplate\n\tvoid nestedMetaInfResourceIsAvailableViaServletContext(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/servletContext?/nested-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\tvoid nestedJarIsNotAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/BOOT-INF/lib/resources-1.0.jar\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestTemplate\n\tvoid applicationClassesAreNotAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest\n\t\t\t.getForEntity(\"/BOOT-INF/classes/com/example/ResourceHandlingApplication.class\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestTemplate\n\tvoid launcherIsNotAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/org/springframework/boot/loader/Launcher.class\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestTemplate\n\tvoid conditionalOnWarDeploymentBeanIsNotAvailableForEmbeddedServer(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/war\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServletContainerTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Annotation used to configure servlet container tests.\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\n@ExtendWith(EmbeddedServerContainerInvocationContextProvider.class)\npublic @interface EmbeddedServletContainerTest {\n\n\tString packaging();\n\n\tClass<? extends AbstractApplicationLauncher>[] launchers();\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarDevelopmentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring Boot's embedded servlet container support when developing\n * a war application.\n *\n * @author Andy Wilkinson\n */\n@EmbeddedServletContainerTest(packaging = \"war\",\n\t\tlaunchers = { BootRunApplicationLauncher.class, IdeApplicationLauncher.class })\nclass EmbeddedServletContainerWarDevelopmentIntegrationTests {\n\n\t@TestTemplate\n\tvoid metaInfResourceFromDependencyIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/nested-meta-inf-resource.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid metaInfResourceFromDependencyWithNameThatContainsReservedCharactersIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\n\t\t\t\t\"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"encoded-name\");\n\t}\n\n\t@TestTemplate\n\tvoid metaInfResourceFromDependencyIsAvailableViaServletContext(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/servletContext?/nested-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\tvoid webappResourcesAreAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/webapp-resource.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\tvoid loaderClassesAreNotAvailableViaResourcePaths(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/resourcePaths\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(readLines(entity.getBody()))\n\t\t\t.noneMatch((resourcePath) -> resourcePath.startsWith(\"/org/springframework/boot/loader\"));\n\t}\n\n\tprivate List<String> readLines(String input) {\n\t\tif (input == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\ttry (BufferedReader reader = new BufferedReader(new StringReader(input))) {\n\t\t\treturn reader.lines().toList();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to read lines from input '\" + input + \"'\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/EmbeddedServletContainerWarPackagingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring Boot's embedded servlet container support using war\n * packaging.\n *\n * @author Andy Wilkinson\n */\n@EmbeddedServletContainerTest(packaging = \"war\",\n\t\tlaunchers = { PackagedApplicationLauncher.class, ExplodedApplicationLauncher.class })\nclass EmbeddedServletContainerWarPackagingIntegrationTests {\n\n\t@TestTemplate\n\tvoid nestedMetaInfResourceIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/nested-meta-inf-resource.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\t@DisabledOnOs(OS.WINDOWS)\n\tvoid nestedMetaInfResourceWithNameThatContainsReservedCharactersIsAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\n\t\t\t\t\"/nested-reserved-%21%23%24%25%26%28%29%2A%2B%2C%3A%3D%3F%40%5B%5D-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"encoded-name\");\n\t}\n\n\t@TestTemplate\n\tvoid nestedMetaInfResourceIsAvailableViaServletContext(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/servletContext?/nested-meta-inf-resource.txt\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\tvoid nestedJarIsNotAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/WEB-INF/lib/resources-1.0.jar\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestTemplate\n\tvoid applicationClassesAreNotAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest\n\t\t\t.getForEntity(\"/WEB-INF/classes/com/example/ResourceHandlingApplication.class\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestTemplate\n\tvoid webappResourcesAreAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/webapp-resource.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@TestTemplate\n\tvoid loaderClassesAreNotAvailableViaHttp(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/org/springframework/boot/loader/Launcher.class\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tentity = rest.getForEntity(\"/org/springframework/../springframework/boot/loader/Launcher.class\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestTemplate\n\tvoid loaderClassesAreNotAvailableViaResourcePaths(RestTemplate rest) {\n\t\tResponseEntity<String> entity = rest.getForEntity(\"/resourcePaths\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(readLines(entity.getBody()))\n\t\t\t.noneMatch((resourcePath) -> resourcePath.startsWith(\"/org/springframework/boot/loader\"));\n\t}\n\n\t@TestTemplate\n\tvoid conditionalOnWarDeploymentBeanIsNotAvailableForEmbeddedServer(RestTemplate rest) {\n\t\tassertThat(rest.getForEntity(\"/always\", String.class).getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(rest.getForEntity(\"/conditionalOnWar\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\tprivate List<String> readLines(String input) {\n\t\tif (input == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\ttry (BufferedReader reader = new BufferedReader(new StringReader(input))) {\n\t\t\treturn reader.lines().toList();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to read lines from input '\" + input + \"'\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/ExplodedApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StreamUtils;\n\n/**\n * {@link AbstractApplicationLauncher} that launches a Spring Boot application using\n * {@code JarLauncher} or {@code WarLauncher} and an exploded archive.\n *\n * @author Andy Wilkinson\n */\nclass ExplodedApplicationLauncher extends AbstractApplicationLauncher {\n\n\tprivate final File exploded;\n\n\tExplodedApplicationLauncher(Application application, File outputLocation) {\n\t\tsuper(application, outputLocation);\n\t\tthis.exploded = new File(outputLocation, \"exploded\");\n\t}\n\n\t@Override\n\tprotected File getWorkingDirectory() {\n\t\treturn this.exploded;\n\t}\n\n\t@Override\n\tprotected String getDescription(String packaging) {\n\t\treturn \"exploded \" + packaging;\n\t}\n\n\t@Override\n\tprotected List<String> getArguments(File archive, File serverPortFile) {\n\t\tString mainClass = (archive.getName().endsWith(\".war\") ? \"org.springframework.boot.loader.launch.WarLauncher\"\n\t\t\t\t: \"org.springframework.boot.loader.launch.JarLauncher\");\n\t\ttry {\n\t\t\texplodeArchive(archive);\n\t\t\treturn Arrays.asList(\"-cp\", this.exploded.getAbsolutePath(), mainClass, serverPortFile.getAbsolutePath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate void explodeArchive(File archive) throws IOException {\n\t\tFileSystemUtils.deleteRecursively(this.exploded);\n\t\tJarFile jarFile = new JarFile(archive);\n\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\twhile (entries.hasMoreElements()) {\n\t\t\tJarEntry jarEntry = entries.nextElement();\n\t\t\tFile extracted = new File(this.exploded, jarEntry.getName());\n\t\t\tif (jarEntry.isDirectory()) {\n\t\t\t\textracted.mkdirs();\n\t\t\t}\n\t\t\telse {\n\t\t\t\textracted.getParentFile().mkdirs();\n\t\t\t\tFileOutputStream extractedOutputStream = new FileOutputStream(extracted);\n\t\t\t\tStreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);\n\t\t\t\textractedOutputStream.close();\n\t\t\t}\n\t\t}\n\t\tjarFile.close();\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/IdeApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link AbstractApplicationLauncher} that launches a Spring Boot application with a\n * classpath similar to that used when run in an IDE.\n *\n * @author Andy Wilkinson\n */\nclass IdeApplicationLauncher extends AbstractApplicationLauncher {\n\n\tprivate final File exploded;\n\n\tIdeApplicationLauncher(Application application, File outputLocation) {\n\t\tsuper(application, outputLocation);\n\t\tthis.exploded = new File(outputLocation, \"the+ide application\");\n\t}\n\n\t@Override\n\tprotected File getWorkingDirectory() {\n\t\treturn this.exploded;\n\t}\n\n\t@Override\n\tprotected String getDescription(String packaging) {\n\t\treturn \"IDE run \" + packaging + \" project\";\n\t}\n\n\t@Override\n\tprotected List<String> getArguments(File archive, File serverPortFile) {\n\t\ttry {\n\t\t\texplodeArchive(archive, this.exploded);\n\t\t\tdeleteLauncherClasses();\n\t\t\tFile builtClasses = populateBuiltClasses(archive);\n\t\t\tFile dependencies = populateDependencies(archive);\n\t\t\tFile resourcesProject = explodedResourcesProject(dependencies);\n\t\t\tif (archive.getName().endsWith(\".war\")) {\n\t\t\t\tpopulateSrcMainWebapp();\n\t\t\t}\n\t\t\tList<String> classpath = new ArrayList<>();\n\t\t\tclasspath.add(builtClasses.getAbsolutePath());\n\t\t\tfor (File dependency : dependencies.listFiles()) {\n\t\t\t\tclasspath.add(dependency.getAbsolutePath());\n\t\t\t}\n\t\t\tclasspath.add(resourcesProject.getAbsolutePath());\n\t\t\treturn Arrays.asList(\"-cp\", StringUtils.collectionToDelimitedString(classpath, File.pathSeparator),\n\t\t\t\t\t\"com.example.ResourceHandlingApplication\", serverPortFile.getAbsolutePath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate File populateBuiltClasses(File archive) throws IOException {\n\t\tFile builtClasses = new File(this.exploded, \"built/classes\");\n\t\tbuiltClasses.mkdirs();\n\t\tFile source = new File(this.exploded, getClassesPath(archive));\n\t\tFileSystemUtils.copyRecursively(source, builtClasses);\n\t\tFileSystemUtils.deleteRecursively(source);\n\t\treturn builtClasses;\n\t}\n\n\tprivate File populateDependencies(File archive) throws IOException {\n\t\tFile dependencies = new File(this.exploded, \"dependencies\");\n\t\tdependencies.mkdirs();\n\t\tList<String> libPaths = getLibPaths(archive);\n\t\tfor (String libPath : libPaths) {\n\t\t\tFile libDirectory = new File(this.exploded, libPath);\n\t\t\tfor (File jar : libDirectory.listFiles()) {\n\t\t\t\tFileCopyUtils.copy(jar, new File(dependencies, jar.getName()));\n\t\t\t}\n\t\t\tFileSystemUtils.deleteRecursively(libDirectory);\n\t\t}\n\t\treturn dependencies;\n\t}\n\n\tprivate File explodedResourcesProject(File dependencies) throws IOException {\n\t\tFile resourcesProject = new File(this.exploded, \"resources-project/built/classes\");\n\t\tFile resourcesJar = new File(dependencies, \"spring-boot-server-tests-app-resources.jar\");\n\t\texplodeArchive(resourcesJar, resourcesProject);\n\t\tresourcesJar.delete();\n\t\treturn resourcesProject;\n\t}\n\n\tprivate void populateSrcMainWebapp() throws IOException {\n\t\tFile srcMainWebapp = new File(this.exploded, \"src/main/webapp\");\n\t\tsrcMainWebapp.mkdirs();\n\t\tFile source = new File(this.exploded, \"webapp-resource.txt\");\n\t\tFileCopyUtils.copy(source, new File(srcMainWebapp, \"webapp-resource.txt\"));\n\t\tsource.delete();\n\t}\n\n\tprivate void deleteLauncherClasses() {\n\t\tFileSystemUtils.deleteRecursively(new File(this.exploded, \"org\"));\n\t}\n\n\tprivate String getClassesPath(File archive) {\n\t\treturn (archive.getName().endsWith(\".jar\") ? \"BOOT-INF/classes\" : \"WEB-INF/classes\");\n\t}\n\n\tprivate List<String> getLibPaths(File archive) {\n\t\treturn (archive.getName().endsWith(\".jar\") ? Collections.singletonList(\"BOOT-INF/lib\")\n\t\t\t\t: Arrays.asList(\"WEB-INF/lib\"));\n\t}\n\n\tprivate void explodeArchive(File archive, File destination) throws IOException {\n\t\tFileSystemUtils.deleteRecursively(destination);\n\t\tJarFile jarFile = new JarFile(archive);\n\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\twhile (entries.hasMoreElements()) {\n\t\t\tJarEntry jarEntry = entries.nextElement();\n\t\t\tFile extracted = new File(destination, jarEntry.getName());\n\t\t\tif (jarEntry.isDirectory()) {\n\t\t\t\textracted.mkdirs();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tFileOutputStream extractedOutputStream = new FileOutputStream(extracted);\n\t\t\t\tStreamUtils.copy(jarFile.getInputStream(jarEntry), extractedOutputStream);\n\t\t\t\textractedOutputStream.close();\n\t\t\t}\n\t\t}\n\t\tjarFile.close();\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-server-integration-tests/src/intTest/java/org/springframework/boot/context/embedded/PackagedApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.context.embedded;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * {@link AbstractApplicationLauncher} that launches a packaged Spring Boot application\n * using {@code java -jar}.\n *\n * @author Andy Wilkinson\n */\nclass PackagedApplicationLauncher extends AbstractApplicationLauncher {\n\n\tPackagedApplicationLauncher(Application application, File outputLocation) {\n\t\tsuper(application, outputLocation);\n\t}\n\n\t@Override\n\tprotected File getWorkingDirectory() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected String getDescription(String packaging) {\n\t\treturn \"packaged \" + packaging;\n\t}\n\n\t@Override\n\tprotected List<String> getArguments(File archive, File serverPortFile) {\n\t\treturn Arrays.asList(\"-jar\", archive.getAbsolutePath(), serverPortFile.getAbsolutePath());\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.integration-test\"\n}\n\ndescription = \"Spring Boot SNI Integration Tests\"\n\nconfigurations {\n\tapp\n}\n\ndependencies {\n\tapp project(path: \":platform:spring-boot-dependencies\", configuration: \"mavenRepository\")\n\tapp project(path: \":module:spring-boot-restclient\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter-actuator\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter-tomcat\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter-webmvc\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter-webflux\", configuration: \"mavenRepository\")\n\tapp project(path: \":build-plugin:spring-boot-gradle-plugin\", configuration: \"mavenRepository\")\n\tapp project(path: \":module:spring-boot-webflux\", configuration: \"mavenRepository\")\n\n\tintTestImplementation(enforcedPlatform(project(\":platform:spring-boot-internal-dependencies\")))\n\tintTestImplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\tintTestImplementation(project(\":test-support:spring-boot-test-support\"))\n\tintTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tintTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.register(\"syncMavenRepository\", Sync) {\n\tfrom configurations.app\n\tinto layout.buildDirectory.dir(\"int-test-maven-repository\")\n}\n\ntasks.register(\"syncReactiveServerAppSource\", org.springframework.boot.build.SyncAppSource) {\n\tsourceDirectory = file(\"spring-boot-sni-reactive-app\")\n\tdestinationDirectory = file(layout.buildDirectory.dir(\"spring-boot-sni-reactive-app\"))\n}\n\ntasks.register(\"buildReactiveServerApps\", GradleBuild) {\n\tdependsOn syncReactiveServerAppSource, syncMavenRepository\n\tdir = layout.buildDirectory.dir(\"spring-boot-sni-reactive-app\")\n\tstartParameter.buildCacheEnabled = false\n\ttasks = [\n\t\t\t\"nettyServerApp\",\n\t\t\t\"tomcatServerApp\"\n\t]\n}\n\ntasks.register(\"syncServletServerAppSource\", org.springframework.boot.build.SyncAppSource) {\n\tsourceDirectory = file(\"spring-boot-sni-servlet-app\")\n\tdestinationDirectory = file(layout.buildDirectory.dir(\"spring-boot-sni-servlet-app\"))\n}\n\ntasks.register(\"buildServletServerApps\", GradleBuild) {\n\tdependsOn syncServletServerAppSource, syncMavenRepository\n\tdir = layout.buildDirectory.dir(\"spring-boot-sni-servlet-app\")\n\tstartParameter.buildCacheEnabled = false\n\ttasks = [\n\t\t\t\"tomcatServerApp\"\n\t]\n}\n\ntasks.register(\"syncClientAppSource\", org.springframework.boot.build.SyncAppSource) {\n\tsourceDirectory = file(\"spring-boot-sni-client-app\")\n\tdestinationDirectory = file(layout.buildDirectory.dir(\"spring-boot-sni-client-app\"))\n}\n\ntasks.register(\"buildClientApp\", GradleBuild) {\n\tdependsOn syncClientAppSource, syncMavenRepository\n\tdir = layout.buildDirectory.dir(\"spring-boot-sni-client-app\")\n\tstartParameter.buildCacheEnabled = false\n\ttasks = [\"build\"]\n}\n\nintTest {\n\tinputs.files(\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-netty-reactive.jar\"),\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat-reactive.jar\"),\n\t\t\tlayout.buildDirectory.file(\"spring-boot-server-tests-app/build/libs/spring-boot-server-tests-app-tomcat-servlet.jar\")\n\t)\n\t\t\t.withPropertyName(\"applicationArchives\")\n\t\t\t.withPathSensitivity(PathSensitivity.RELATIVE)\n\t\t\t.withNormalizer(ClasspathNormalizer)\n\tdependsOn buildReactiveServerApps, buildServletServerApps, buildClientApp\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/create-certs.sh",
    "content": "#!/bin/bash\n\ncreate_ssl_config() {\n    cat > openssl.cnf <<_END_\n    subjectAltName = @alt_names\n    [alt_names]\n    DNS.1 = example.com\n    DNS.2 = localhost\n    [ server_cert ]\n    keyUsage = digitalSignature, keyEncipherment\n    nsCertType = server\n    [ client_cert ]\n    keyUsage = digitalSignature, keyEncipherment\n    nsCertType = client\n_END_\n\n}\n\ngenerate_ca_cert() {\n    local location=$1\n\n    mkdir -p ${location}\n\n    openssl genrsa -out ${location}/test-ca.key 4096\n    openssl req -key ${location}/test-ca.key -out ${location}/test-ca.crt \\\n        -x509 -new -nodes -sha256 -days 3650 \\\n        -subj \"/O=Spring Boot Test/CN=Certificate Authority\" \\\n        -addext \"subjectAltName=DNS:hello.example.com,DNS:hello-alt.example.com\"\n}\n\ngenerate_cert() {\n    local location=$1\n    local caLocation=$2\n    local hostname=$3\n\n    local keyfile=${location}/test-${hostname}-server.key\n    local certfile=${location}/test-${hostname}-server.crt\n\n    mkdir -p ${location}\n\n    openssl genrsa -out ${keyfile} 2048\n    openssl req -key ${keyfile} \\\n        -new -sha256 \\\n        -subj \"/O=Spring Boot Test/CN=${hostname}.example.com\" \\\n        -addext \"subjectAltName=DNS:${hostname}.example.com\" | \\\n    openssl x509 -req -out ${certfile} \\\n        -CA ${caLocation}/test-ca.crt -CAkey ${caLocation}/test-ca.key -CAserial ${caLocation}/test-ca.txt -CAcreateserial \\\n        -sha256 -days 3650 \\\n        -extfile openssl.cnf \\\n        -extensions server_cert\n}\n\nif ! command -v openssl &> /dev/null; then\n    echo \"openssl is required\"\n    exit\nfi\n\nmkdir -p certs\n\ncreate_ssl_config\ngenerate_ca_cert certs/ca\ngenerate_cert certs/default certs/ca hello\ngenerate_cert certs/alt certs/ca hello-alt\n\nrm -f openssl.cnf\nrm -f certs/ca/test-ca.key certs/ca/test-ca.txt\n\ncp -r certs/* spring-boot-sni-reactive-app/src/main/resources\ncp -r certs/* spring-boot-sni-servlet-app/src/main/resources\ncp -r certs/ca/* spring-boot-sni-client-app/src/main/resources/ca\n\nrm -rf certs\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-client-app/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot\"\n}\n\njava {\n\tsourceCompatibility = '17'\n\ttargetCompatibility = '17'\n}\n\nrepositories {\n\tmaven { url = layout.projectDirectory.dir(\"../int-test-maven-repository\") }\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.springframework.boot:spring-boot-restclient\")\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc\")\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-client-app/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${gradle.parent.rootProject.rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmaven { url = layout.settingsDirectory.dir(\"../int-test-maven-repository\") }\n\t\tmavenCentral()\n\t\tspring.mavenRepositories()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.springframework.boot\") {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-client-app/src/main/java/org/springframework/boot/sni/client/SniClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sni.server;\n\nimport java.util.Arrays;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.restclient.autoconfigure.RestClientSsl;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.boot.ssl.SslBundles;\n\n@SpringBootApplication\npublic class SniClientApplication {\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(SniClientApplication.class)\n\t\t\t\t.web(WebApplicationType.NONE).run(args);\n\t}\n\n\t@Bean\n\tpublic RestClient restClient(RestClient.Builder restClientBuilder, RestClientSsl ssl) {\n\t\treturn restClientBuilder.apply(ssl.fromBundle(\"server\")).build();\n\t}\n\n\t@Bean\n\tpublic CommandLineRunner commandLineRunner(RestClient client) {\n\t\treturn ((args) -> {\n\t\t\tfor (String hostname : args) {\n\t\t\t\tcallServer(client, hostname);\n\t\t\t\tcallActuator(client, hostname);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static void callServer(RestClient client, String hostname) {\n\t\tString url = \"https://\" + hostname + \":8443/\";\n\t\tSystem.out.println(\">>>>>> Calling server at '\" + url + \"'\");\n\t\ttry {\n\t\t\tResponseEntity<String> response = client.get().uri(url).retrieve().toEntity(String.class);\n\t\t\tSystem.out.println(\">>>>>> Server response status code is '\" + response.getStatusCode() + \"'\");\n\t\t\tSystem.out.println(\">>>>>> Server response body is '\" + response + \"'\");\n\t\t} catch (Exception ex) {\n\t\t\tSystem.out.println(\">>>>>> Exception thrown calling server at '\" + url + \"': \" + ex.getMessage());\n\t\t\tex.printStackTrace();\n\t\t}\n\t}\n\n\tprivate static void callActuator(RestClient client, String hostname) {\n\t\tString url = \"https://\" + hostname + \":8444/actuator/health\";\n\t\tSystem.out.println(\">>>>>> Calling server actuator at '\" + url + \"'\");\n\t\ttry {\n\t\t\tResponseEntity<String> response = client.get().uri(url).retrieve().toEntity(String.class);\n\t\t\tSystem.out.println(\">>>>>> Server actuator response status code is '\" + response.getStatusCode() + \"'\");\n\t\t\tSystem.out.println(\">>>>>> Server actuator response body is '\" + response + \"'\");\n\t\t} catch (Exception ex) {\n\t\t\tSystem.out.println(\">>>>>> Exception thrown calling server actuator at '\" + url + \"': \" + ex.getMessage());\n\t\t\tex.printStackTrace();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-client-app/src/main/resources/application.yml",
    "content": "spring:\n  ssl:\n    bundle:\n      pem:\n        server:\n          truststore:\n            certificate: \"classpath:ca/test-ca.crt\"\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-client-app/src/main/resources/ca/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFjjCCA3agAwIBAgIUNY3OEEWlqJb8zOi8R0OwsmWyhd0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt1v6\nV2wZ4VcJL1BRHWwoinv16dqjouPi4Gzp4UPKtE1BBdqYCSmFpgV0KyDEd1ZFxdAl\n0WDzvuUxeMLlcxGT+c0vLIGVeWtnwowiIaQ32g3Zfcz5jTkLtRL6jLf9pglRzyeH\n80vRKjXnpWMpiYxlIK2AivjsuWMo1kBImGtWAkL/ojNY7wxjJlIy8WgkHSpg7IH/\nWcBjoV3WfMiNxI8pAxq17hMKvduN6EQeLuaGIkhSkCVeJP5wWQGEAfGiyCOugm0q\nC6BEWwkMUN1VuZ4ZMpC5ZIfZxDBqGLczCbq5LTS+6a+O/HmPnI5m83rcR9jKTv2/\neP2rRhrvzmfwngzw0k9l8jglruyKuvio94dcS+ChfLVXQMnhZ/U6j+QjCLNq1PMX\nUuTO9Z5g+2OQYxzUMCEzbzJZ9ofyuX6xbrOTGobXMTIlrKwj+FFG1ortplc8dikp\n8wYOYknZFU8Bj6tMQLfqJ0psF85IHr2NJI+69+YvP4+UTZZ9v+VdoaLL9U/in/wo\nVJ5ohnm0iWt8HmiVhfeIav+WLmSNCMjsukcFCpoosXzbgFFYqQa47USwjjLPFHxa\nrWcDviXhWuTFmKgmG3hnusTg/tKQJzq+4EIDZVIjApw2eAltozPw/bfqD63XV1Yd\n7XuHhIeP2rDH5/7ysw5CIz7ggiy4rwo1KLtZB0UCAwEAAaOBiTCBhjAdBgNVHQ4E\nFgQUSr3isk0cFN0oDQv4c/j3kwPpp/MwHwYDVR0jBBgwFoAUSr3isk0cFN0oDQv4\nc/j3kwPpp/MwDwYDVR0TAQH/BAUwAwEB/zAzBgNVHREELDAqghFoZWxsby5leGFt\ncGxlLmNvbYIVaGVsbG8tYWx0LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IC\nAQBRlUKOILQqJImVMNv8WpcWAdfUFW5G+eUvSSkxqk7abewONdwK5NXEledLHVuA\npOejsjdd4Vj1MMoY3SmaEVa3pKe38hFDhXRGnQGRWzTsu081+oZQjnINNw53exbx\nxjrV0qFVJR5MmbhkJaGuIFTJyONwVc9y7mpVAbJ/VcXXkK8qJ7lbcFGC9KuNFOtl\n6Me710vBm3QxNXuBHzmc/ac1ZeXYTokvRmRoRjBi4wSfCisKXmJqrHuqw22lZ4Sc\ncdoEwELSQssCj8EHbj5CYbyQIOqclZqkgThLfp04uwfO1THx7CMiXnZKBntmbjuo\nRnrAqvYaAdL9DDLsVZaibqhmYp3nAioZiA08jNUAcIXCIsomqawsBciYO/7SoFz5\nqAX/UKJ13jRGVKfRJEVXy3XnqpoGpv8z2m4X5IYhCBbTm4Q3X0iPSlpgQZyAUyTx\ntfRJ1mycAKvG/0fdVohT5we1URjiYGcqpfQ8BF43hXI7hJY2nUfydQVnnAZkFMo8\na6yYJ/xh+oRu3pSADN5UtTcJvEdfIGDVC+PcbAC5tgQEZq55EXYxt31X51oO8mb2\nK1V6GDJHd3/khEY4nUbYfdfI1hKoUbWTBqiW9CjuSsHeD8cw2D7xM8gXeIhRpZTG\nSGsQlVlCFtJcIh/0/DcCG/UgGvPhyXhntvQe/+iOK2tdIQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot\"\n}\n\njava {\n\tsourceCompatibility = '17'\n\ttargetCompatibility = '17'\n}\n\nrepositories {\n\tmaven { url = layout.projectDirectory.dir(\"../int-test-maven-repository\") }\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\nconfigurations {\n\tapp {\n\t\textendsFrom(configurations.runtimeClasspath)\n\t}\n\tnetty {\n\t\textendsFrom(app)\n\t}\n\ttomcat {\n\t\textendsFrom(app)\n\t}\n}\n\ndependencies {\n\tcompileOnly(\"org.springframework:spring-webflux\")\n\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.springframework.boot:spring-boot-starter\")\n\timplementation(\"org.springframework.boot:spring-boot-starter-actuator\")\n\timplementation(\"org.springframework.boot:spring-boot-starter-jackson\")\n\n\tapp(files(sourceSets.main.output))\n\tapp(\"org.springframework.boot:spring-boot-webflux\")\n\tnetty(\"org.springframework.boot:spring-boot-starter-webflux\")\n\ttomcat(\"org.springframework.boot:spring-boot-starter-tomcat\")\n}\n\n[\"netty\", \"tomcat\"].each { webServer ->\n\tdef configurer = { task ->\n\t\ttask.mainClass = \"org.springframework.boot.sni.server.SniServerApplication\"\n\t\ttask.classpath = configurations.getByName(webServer)\n\t\ttask.archiveClassifier = webServer\n\t\ttask.targetJavaVersion = project.java.targetCompatibility\n\t}\n\ttasks.register(\"${webServer}ServerApp\", BootJar, configurer)\n}"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${gradle.parent.rootProject.rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmaven { url = layout.settingsDirectory.dir(\"../int-test-maven-repository\") }\n\t\tmavenCentral()\n\t\tspring.mavenRepositories()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.springframework.boot\") {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/java/org/springframework/boot/sni/server/HelloController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sni.server;\n\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class HelloController {\n\n\t@GetMapping\n\tpublic String hello(ServerHttpRequest request) {\n\t\treturn \"Hello from \" + request.getURI();\n\t}\n\n}"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/java/org/springframework/boot/sni/server/SniServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sni.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SniServerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SniServerApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/resources/alt/test-hello-alt-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEZjCCAk6gAwIBAgIUWUyiO2/3ZShhRKAs+4QrJjDe9wUwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVaGVsbG8tYWx0\nLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApNnu\ntWe0OqqubKtaNnObfJ3QB9zXK2Y7o3zsHghdq5pasvDaup9/k34rwy+O0yVvLQsK\nuCKj6o/hSKTvbiL01yQ7oJt/hWVbkh2NeZ1NMg2xHw9Mt6Kw7eIvSB+SL04j4xU+\ngny/WKPknQ2wd/hCgRb2vej7rSyHCQvkmIWPgujbqK0bq6M+HddOoRsFKCBiItjM\nC2ZBKvyuR7ZpHR777DzTkAnMIlHuU0EkvM3pze5gPJdH20G0MxbOth7WV2jJM1sU\nXeSIfdR2MIfoWmeMRJtNQ9MwrPpD0GV9fe7vnlBkGQEHh2BaUlgWyuQRw4/Qw0G/\n3mNgCTdVB6MFT13IXwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEB\nBAQDAgZAMB0GA1UdDgQWBBQs7Rj8AEuEYbQx43jnQWctOfkbKDAfBgNVHSMEGDAW\ngBRKveKyTRwU3SgNC/hz+PeTA+mn8zANBgkqhkiG9w0BAQsFAAOCAgEACt/7KupM\nYvdSVkHXcth7U9d3y9ph/nFwjaEqloXK8XK6v3bzLzCcWrk59HotYrtpSoxy1UD1\nJYDlUm3Jh+snzBcOi2GZK0tQN5/Vb27DeCL4UVse3jAAK/3ppD787nG3Nf4B1+BW\ncBMHr4+U1xwYmkoWYVH0hHRB7Y4JBWxwt4MpehkZWnxSgLg5956BomyhmYYBQUPR\n31YP4TnD+hdUm+YsLSGF1hW6Dp8OW/p/hScE6wPMht9XhAW58VRIJwrye/kgEulW\nwkfIMF9UdXXibnIIvAppW88Qwv/PiGDMyWIhvQRXdmsc9rvJXqn8aZXR34hVE4Kw\nOhvMjxABFGlWCDvPXs8lawdvLWn08xodzRXFBOsnE3oHs68GgMT5CcmGUJA1jjl8\nWdv4O42BWlluTuqBz0Eea8lTjt6vMxidBbBDf98Fsvgtgk8DHppHhjoM1d4LAhCt\n4ZaWrUmoRjlMQKvo/J67a/7BKtemM61FvGu76JMB2UAGT6AP9EFQ8067nx7B+421\nfyCpJPuz/jgl4wtIjVNamo/Y52snfu8BSEL4S2wxNJS47OuwhaoPSCfkPPKUfOTo\nbcOo9mYC1R3CvjigeqXd1hnq3C9Y+0+X7QpYBHsTmsX2b0vhIOfJZexZHNK0/h4Y\nd6b1XmDwcZCdNnBfeedGeG5LD7pd19Q3YL0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/resources/alt/test-hello-alt-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCk2e61Z7Q6qq5s\nq1o2c5t8ndAH3NcrZjujfOweCF2rmlqy8Nq6n3+TfivDL47TJW8tCwq4IqPqj+FI\npO9uIvTXJDugm3+FZVuSHY15nU0yDbEfD0y3orDt4i9IH5IvTiPjFT6CfL9Yo+Sd\nDbB3+EKBFva96PutLIcJC+SYhY+C6NuorRuroz4d106hGwUoIGIi2MwLZkEq/K5H\ntmkdHvvsPNOQCcwiUe5TQSS8zenN7mA8l0fbQbQzFs62HtZXaMkzWxRd5Ih91HYw\nh+haZ4xEm01D0zCs+kPQZX197u+eUGQZAQeHYFpSWBbK5BHDj9DDQb/eY2AJN1UH\nowVPXchfAgMBAAECggEAEmYabNe6t1OGbS2Av5QOlg19Auukfj0GSfxu0/lGDxmG\npvMXzn1vvTP3SW0c6TcD3gid9Sg0mEDfuX5jFK1FG1/5YbcJOAe0fS3cNOcYDw6V\nJqzL+LDpQ1ubwFZ5t9rmSXl9BQ5MQuXj5Z16BSHJtmOsPUzsDgtqtNlFdbpuZoNN\n3YfAMW8yNCVOrJpf9vwMFSDGRSqtnBrr/uWLIrfjLGUaCGkRwsv/zOza5b9+DuXg\nbL+fShaUAGtULemhyCxWBQcoJPEsrIifel9uK3O4ZvyKr5SqrVV7kTsWm48f1ugz\nZ3bsLxu3oudD8dyukQ4Nv8dLMkvDRH1an/WxGYtmhQKBgQDW9D/g7XdtvzONpOuO\nVcIALIAiekE5sXx6PjRtqK/BRp31Nco1KlDEkHPOZ/j3goQTcEOTlN5oCJzwrPOe\n2M/PIBflEU83Rofua0M9BzjIfziACnw7VjZCj4WOWh2Hb87GFvockIXVR1g2CjTJ\ncgMO99lT5jyi2MLp1XlB6/4HQwKBgQDEVHkRnNItPrhf4jJrT9/k3qyuVDIb8Gig\nwBQaEdvsFPXO/NCni6N8JrODoknVEwRERYJfvryKsRIOkilR7PH49cUGYcOU8wFs\nEayY4nRvbwuhdBcy3fqE7flmy9cHIN9wRqYJFG5hvgXQyecJ0dEd6vDC2eVpRTjv\nGJpRXulitQKBgDCpElzk5QhfJFiIYRrTpxtK96bWbjWVTEyQEGZSrZbfWZrNFn16\nmtYkrVKojt/ZF/UekO2z4bVDXePOA0iOZFzLMx2UEY691L/QYGRMYjphMnUp6n20\nQoxG2UEkfVLPqMuHIA+fV+y0Pe/d151SxgZ5bSVlFYz37QfqX4zg05zpAoGAAgsG\n/4HsRgBDFuxZrfg00kLm9SF3LAdCb3nQO7031qsZK8BBw5yWZPJaJ+KGdisufi9i\n/fAUMjVJhNFMkMewdPDJzhkyWdh1iVRdwXGJ2KcFLfbxTtw0gTGgyMsSP8a9zINP\nswR9aZL6qIORXe7LCE6rlruBwaiwwPw2juY384kCgYBBcbCWC1CC4crJZj+F2b4N\nXqSIwsTqjsc9sdhladw/g9A6pPBKcvNUIi6T0q//QAWyyeD6FvbZazNjvIG+ZCBw\ng/cg+uRPRL7pU8KSQZYBCTQfxniO1p+52idNZAPYOyjPTRzEui59DCLfyrwzIOKe\nkWzF5xJPOw9252QH7XKaqQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/resources/application.yml",
    "content": "spring:\n  ssl:\n    bundle:\n      pem:\n        default:\n          keystore:\n            certificate: \"classpath:default/test-hello-server.crt\"\n            private-key: \"classpath:default/test-hello-server.key\"\n          truststore:\n            certificate: \"classpath:ca/test-ca.crt\"\n        alt:\n          keystore:\n            certificate: \"classpath:alt/test-hello-alt-server.crt\"\n            private-key: \"classpath:alt/test-hello-alt-server.key\"\n          truststore:\n            certificate: \"classpath:ca/test-ca.crt\"\n\nserver:\n  port: 8443\n  ssl:\n    bundle: \"default\"\n    server-name-bundles:\n      - server-name: \"hello.example.com\"\n        bundle: \"default\"\n      - server-name: \"hello-alt.example.com\"\n        bundle: \"alt\"\n\nmanagement:\n  server:\n    port: 8444\n    ssl:\n      bundle: \"default\"\n      server-name-bundles:\n        - server-name: \"hello.example.com\"\n          bundle: \"default\"\n        - server-name: \"hello-alt.example.com\"\n          bundle: \"alt\"\n  endpoints:\n    web:\n      exposure:\n        include:\n          - \"*\"\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/resources/ca/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFjjCCA3agAwIBAgIUNY3OEEWlqJb8zOi8R0OwsmWyhd0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt1v6\nV2wZ4VcJL1BRHWwoinv16dqjouPi4Gzp4UPKtE1BBdqYCSmFpgV0KyDEd1ZFxdAl\n0WDzvuUxeMLlcxGT+c0vLIGVeWtnwowiIaQ32g3Zfcz5jTkLtRL6jLf9pglRzyeH\n80vRKjXnpWMpiYxlIK2AivjsuWMo1kBImGtWAkL/ojNY7wxjJlIy8WgkHSpg7IH/\nWcBjoV3WfMiNxI8pAxq17hMKvduN6EQeLuaGIkhSkCVeJP5wWQGEAfGiyCOugm0q\nC6BEWwkMUN1VuZ4ZMpC5ZIfZxDBqGLczCbq5LTS+6a+O/HmPnI5m83rcR9jKTv2/\neP2rRhrvzmfwngzw0k9l8jglruyKuvio94dcS+ChfLVXQMnhZ/U6j+QjCLNq1PMX\nUuTO9Z5g+2OQYxzUMCEzbzJZ9ofyuX6xbrOTGobXMTIlrKwj+FFG1ortplc8dikp\n8wYOYknZFU8Bj6tMQLfqJ0psF85IHr2NJI+69+YvP4+UTZZ9v+VdoaLL9U/in/wo\nVJ5ohnm0iWt8HmiVhfeIav+WLmSNCMjsukcFCpoosXzbgFFYqQa47USwjjLPFHxa\nrWcDviXhWuTFmKgmG3hnusTg/tKQJzq+4EIDZVIjApw2eAltozPw/bfqD63XV1Yd\n7XuHhIeP2rDH5/7ysw5CIz7ggiy4rwo1KLtZB0UCAwEAAaOBiTCBhjAdBgNVHQ4E\nFgQUSr3isk0cFN0oDQv4c/j3kwPpp/MwHwYDVR0jBBgwFoAUSr3isk0cFN0oDQv4\nc/j3kwPpp/MwDwYDVR0TAQH/BAUwAwEB/zAzBgNVHREELDAqghFoZWxsby5leGFt\ncGxlLmNvbYIVaGVsbG8tYWx0LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IC\nAQBRlUKOILQqJImVMNv8WpcWAdfUFW5G+eUvSSkxqk7abewONdwK5NXEledLHVuA\npOejsjdd4Vj1MMoY3SmaEVa3pKe38hFDhXRGnQGRWzTsu081+oZQjnINNw53exbx\nxjrV0qFVJR5MmbhkJaGuIFTJyONwVc9y7mpVAbJ/VcXXkK8qJ7lbcFGC9KuNFOtl\n6Me710vBm3QxNXuBHzmc/ac1ZeXYTokvRmRoRjBi4wSfCisKXmJqrHuqw22lZ4Sc\ncdoEwELSQssCj8EHbj5CYbyQIOqclZqkgThLfp04uwfO1THx7CMiXnZKBntmbjuo\nRnrAqvYaAdL9DDLsVZaibqhmYp3nAioZiA08jNUAcIXCIsomqawsBciYO/7SoFz5\nqAX/UKJ13jRGVKfRJEVXy3XnqpoGpv8z2m4X5IYhCBbTm4Q3X0iPSlpgQZyAUyTx\ntfRJ1mycAKvG/0fdVohT5we1URjiYGcqpfQ8BF43hXI7hJY2nUfydQVnnAZkFMo8\na6yYJ/xh+oRu3pSADN5UtTcJvEdfIGDVC+PcbAC5tgQEZq55EXYxt31X51oO8mb2\nK1V6GDJHd3/khEY4nUbYfdfI1hKoUbWTBqiW9CjuSsHeD8cw2D7xM8gXeIhRpZTG\nSGsQlVlCFtJcIh/0/DcCG/UgGvPhyXhntvQe/+iOK2tdIQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/resources/default/test-hello-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEYjCCAkqgAwIBAgIUWUyiO2/3ZShhRKAs+4QrJjDe9wQwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nNzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEaMBgGA1UEAwwRaGVsbG8uZXhh\nbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7F/5wLby8\nMm9WFAQAXTLkZUI4fjnAinwmkfvOMihQLBAcpRJM4Ox8CfCp9sa3+EVevfwMqyLT\naXefBjBAamXCMLk76a2Sl8XqUWBYg6a/j1zZKmEZOzxNnzCfWRVh6gCbqO6OT5DH\nCs/4hLgyNt3jTKlIijyQyp3XxmAOqECsr3y6Cp++WyVgcOGU1m+em0Cs3nxOE1xs\nFWfm8Ycw8kMymYOdUpejgk+naIeWj7SBCd6QJ33xWBhcrBxEhQjnQeM8+ROMT4qB\naRYvJ3OtLfOHrd7eETQbpL3z2Q1GC+vQdQuKBj2/xJ9BXI40TpCq05oFu1Ffg22g\nQHJwCeFskOlZAgMBAAGjYjBgMAsGA1UdDwQEAwIFoDARBglghkgBhvhCAQEEBAMC\nBkAwHQYDVR0OBBYEFKum2hVx8Wf691lwK2uVJWOB6sC6MB8GA1UdIwQYMBaAFEq9\n4rJNHBTdKA0L+HP495MD6afzMA0GCSqGSIb3DQEBCwUAA4ICAQB8pZvrA2RKPdnp\nLEE/uD00ykJF7ZEV1bPADCsKqKR8Q9Z6xU+hLmJkzL2XbKxD+7OHeJJevTB1+yBT\nDaYKIIqQcjudWOEwjyUeat78MdoJJMukLQGTYD59NxLIVApUsLtVVIFUKdf7Ct7y\nLQulHKKS05SmKMwL8E580espG8fl+VJfakxcQdvsxBPrfAfza81EHmQ0GBM9gIwu\nO/QBv0oU+pvSwdOw5uHRd8tvmOFOcaqQii2MhVo1KW7tVfvDaLNJrt4fBoT5hAEe\nfvKbaaKouHDQLlAKhGhvNcqwK+KogAOWF4QH002qvjfGBtQh/zixEZegGodxZeN4\nNGH6n4xvgvvm+Ke1GWBBeUf8xMjV93KeVSZliC2Ugnc8nfqszkUIgv7gMU5yC1ty\natOsc8Zob/QLAhLsBToCuZ4S1rzFxzHA+qVtF9OZPhoKoGJHsA3R/ZvRJgIg66Hh\naA6b9TxdzuZuXclAg3cKJffQnukYHmy7OgNoxz/Su10/dcdRwg3AZYd0+ZX75v+B\n+W1jMfiokA+CknakPU6ct9F+WDIj6NVzeckwejLk9DmMT92bFvFr7r8OnMXO3Se9\nrdqQUXrbXSQHoIUOF5U4ghbWgkiEh7wAIiRaa7gExiaUaRcNTHBNymjfYmETjnIx\nOlYhXImujQBiAcdbLYQFBlrzCu16Fw==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-reactive-app/src/main/resources/default/test-hello-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC7F/5wLby8Mm9W\nFAQAXTLkZUI4fjnAinwmkfvOMihQLBAcpRJM4Ox8CfCp9sa3+EVevfwMqyLTaXef\nBjBAamXCMLk76a2Sl8XqUWBYg6a/j1zZKmEZOzxNnzCfWRVh6gCbqO6OT5DHCs/4\nhLgyNt3jTKlIijyQyp3XxmAOqECsr3y6Cp++WyVgcOGU1m+em0Cs3nxOE1xsFWfm\n8Ycw8kMymYOdUpejgk+naIeWj7SBCd6QJ33xWBhcrBxEhQjnQeM8+ROMT4qBaRYv\nJ3OtLfOHrd7eETQbpL3z2Q1GC+vQdQuKBj2/xJ9BXI40TpCq05oFu1Ffg22gQHJw\nCeFskOlZAgMBAAECggEABSLvQBatXhBXaKpTgswMO+OAyirC/KOArZFn850CaNMQ\n3Sx2AGjTbUNbmVr2UTIue1+lZhajteCpIVNK61XQdeCfEUNE2eezTg/OYJe6sfsm\nXirw7/+lk+75J4LLWL0TJ7LfW8ZY7/H+zDCemvhRJq6h3iU3bPU3GKewVu6tGeCK\nfCBB4dD2FnBkKjX9SGeDpBcqZusRvzBkrzSgcCjsjKYhKXxuGQh4yEv7qD4KD7e+\nJWpW6wTEpHtSZ896q7p+tNdRJl5iQhSLWjx3lWe3iX7vqzEbglwfl8x7dNabVA9+\nryqrt3xPIt7m4t09F12DLb+UvZhP2GEbEbw9wsdYQQKBgQDeV3d3q0+FVNByoGxz\n4lW40/3aTkI/ljnAFwjXuyCFwsdcj9+UFpl/pQ5L9OJbwBx35cJSLwAMngUC+bgp\nX4cNYml6u8rQi+7ogl15mhkXKYC5+dK0uZ+M7o95/ej24cDtl+nArr2KpkSDAB4H\n7jcVRcYHUwbaWlf5mApox13y+QKBgQDXaoswCBytU81O9mJNEH7dGC9HrJYT8Qyn\naCQ1spfWU1/taX4HXJhOtU4J8XgXFvbh0sUFbzmcO0vgd6vCgsMPtuqEHyjmtieO\n2VAsiBC1EWI6LhWiWmzHdXc2HOjYvKVI7WarW122bOsL14LQkvqz4QmHxh72aoRZ\nR6UNSoPhYQKBgD8aQ+XK0P7eW2qs7RrWmc2jHODgZRz23d0OrIvNqCVOapZyntnA\nsD/x8GTOU5AGrg25P7VjcXgjQPjfNs1HN2UtERKsSZt2m4+RsEXa3lQci1Q8+vgf\n1pCBBGdzELNAzyiffNAax+CZ38fuOJe3nBqFevaJMeC201EbPZkPPDLBAoGAI9jt\nFK8k5osdjVhe/2gRVIWjyI+l4eepLWqdK/puXhI90mpNuLfl+KMfO3Rdgaomp2nF\ns6PQuHj9pXsEsDfGciUEXbw5uDrz1ke/mcmCzj74U6o7m2rk00Ru9ChXb0nlT3+C\nKF3p+GOjsbLJaCAtbCW0yk1j9anAIINVqiKOU8ECgYAU4N4f0+FSsWooiaC9qRzR\nkju2ASqalK0NPr3aFowRHL32jdeNd/Gb6DiNcK2oB7jMq54kv1g2Z+e5UN0lmr5A\nSTsgEzodIvapmGtJ27NeolUOjPqv/vAYjAUPdzDUjLIslOIT7tRR32kx8xgslOj/\nkzkHCV1ZuJ60Ukxv6mwj3g==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport org.springframework.boot.gradle.tasks.bundling.BootJar\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot\"\n}\n\njava {\n\tsourceCompatibility = '17'\n\ttargetCompatibility = '17'\n}\n\nrepositories {\n\tmaven { url = layout.projectDirectory.dir(\"../int-test-maven-repository\") }\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\nconfigurations {\n\tapp {\n\t\textendsFrom(configurations.runtimeClasspath)\n\t}\n\ttomcat {\n\t\textendsFrom(app)\n\t}\n}\n\ndependencies {\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api:6.0.0\")\n\n\timplementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc\") {\n\t\texclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'\n\t}\n\timplementation(\"org.springframework.boot:spring-boot-starter-actuator\")\n\n\tapp(files(sourceSets.main.output))\n\tapp('org.springframework.boot:spring-boot-starter-webmvc') {\n\t\texclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'\n\t}\n\ttomcat(\"org.springframework.boot:spring-boot-starter-tomcat\")\n}\n\n[\"tomcat\"].each { webServer ->\n\tdef configurer = { task ->\n\t\ttask.mainClass = \"org.springframework.boot.sni.server.SniServerApplication\"\n\t\ttask.classpath = configurations.getByName(webServer)\n\t\ttask.archiveClassifier = webServer\n\t\ttask.targetJavaVersion = project.java.targetCompatibility\n\t}\n\ttasks.register(\"${webServer}ServerApp\", BootJar, configurer)\n}"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${gradle.parent.rootProject.rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmaven { url = layout.settingsDirectory.dir(\"../int-test-maven-repository\") }\n\t\tmavenCentral()\n\t\tspring.mavenRepositories()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.springframework.boot\") {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/java/org/springframework/boot/sni/server/HelloController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sni.server;\n\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class HelloController {\n\n\t@GetMapping\n\tpublic String hello(HttpServletRequest request) {\n\t\treturn \"Hello from \" + request.getRequestURL();\n\t}\n\n}"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/java/org/springframework/boot/sni/server/SniServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sni.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SniServerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SniServerApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/resources/alt/test-hello-alt-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEZjCCAk6gAwIBAgIUWUyiO2/3ZShhRKAs+4QrJjDe9wUwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVaGVsbG8tYWx0\nLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApNnu\ntWe0OqqubKtaNnObfJ3QB9zXK2Y7o3zsHghdq5pasvDaup9/k34rwy+O0yVvLQsK\nuCKj6o/hSKTvbiL01yQ7oJt/hWVbkh2NeZ1NMg2xHw9Mt6Kw7eIvSB+SL04j4xU+\ngny/WKPknQ2wd/hCgRb2vej7rSyHCQvkmIWPgujbqK0bq6M+HddOoRsFKCBiItjM\nC2ZBKvyuR7ZpHR777DzTkAnMIlHuU0EkvM3pze5gPJdH20G0MxbOth7WV2jJM1sU\nXeSIfdR2MIfoWmeMRJtNQ9MwrPpD0GV9fe7vnlBkGQEHh2BaUlgWyuQRw4/Qw0G/\n3mNgCTdVB6MFT13IXwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEB\nBAQDAgZAMB0GA1UdDgQWBBQs7Rj8AEuEYbQx43jnQWctOfkbKDAfBgNVHSMEGDAW\ngBRKveKyTRwU3SgNC/hz+PeTA+mn8zANBgkqhkiG9w0BAQsFAAOCAgEACt/7KupM\nYvdSVkHXcth7U9d3y9ph/nFwjaEqloXK8XK6v3bzLzCcWrk59HotYrtpSoxy1UD1\nJYDlUm3Jh+snzBcOi2GZK0tQN5/Vb27DeCL4UVse3jAAK/3ppD787nG3Nf4B1+BW\ncBMHr4+U1xwYmkoWYVH0hHRB7Y4JBWxwt4MpehkZWnxSgLg5956BomyhmYYBQUPR\n31YP4TnD+hdUm+YsLSGF1hW6Dp8OW/p/hScE6wPMht9XhAW58VRIJwrye/kgEulW\nwkfIMF9UdXXibnIIvAppW88Qwv/PiGDMyWIhvQRXdmsc9rvJXqn8aZXR34hVE4Kw\nOhvMjxABFGlWCDvPXs8lawdvLWn08xodzRXFBOsnE3oHs68GgMT5CcmGUJA1jjl8\nWdv4O42BWlluTuqBz0Eea8lTjt6vMxidBbBDf98Fsvgtgk8DHppHhjoM1d4LAhCt\n4ZaWrUmoRjlMQKvo/J67a/7BKtemM61FvGu76JMB2UAGT6AP9EFQ8067nx7B+421\nfyCpJPuz/jgl4wtIjVNamo/Y52snfu8BSEL4S2wxNJS47OuwhaoPSCfkPPKUfOTo\nbcOo9mYC1R3CvjigeqXd1hnq3C9Y+0+X7QpYBHsTmsX2b0vhIOfJZexZHNK0/h4Y\nd6b1XmDwcZCdNnBfeedGeG5LD7pd19Q3YL0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/resources/alt/test-hello-alt-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCk2e61Z7Q6qq5s\nq1o2c5t8ndAH3NcrZjujfOweCF2rmlqy8Nq6n3+TfivDL47TJW8tCwq4IqPqj+FI\npO9uIvTXJDugm3+FZVuSHY15nU0yDbEfD0y3orDt4i9IH5IvTiPjFT6CfL9Yo+Sd\nDbB3+EKBFva96PutLIcJC+SYhY+C6NuorRuroz4d106hGwUoIGIi2MwLZkEq/K5H\ntmkdHvvsPNOQCcwiUe5TQSS8zenN7mA8l0fbQbQzFs62HtZXaMkzWxRd5Ih91HYw\nh+haZ4xEm01D0zCs+kPQZX197u+eUGQZAQeHYFpSWBbK5BHDj9DDQb/eY2AJN1UH\nowVPXchfAgMBAAECggEAEmYabNe6t1OGbS2Av5QOlg19Auukfj0GSfxu0/lGDxmG\npvMXzn1vvTP3SW0c6TcD3gid9Sg0mEDfuX5jFK1FG1/5YbcJOAe0fS3cNOcYDw6V\nJqzL+LDpQ1ubwFZ5t9rmSXl9BQ5MQuXj5Z16BSHJtmOsPUzsDgtqtNlFdbpuZoNN\n3YfAMW8yNCVOrJpf9vwMFSDGRSqtnBrr/uWLIrfjLGUaCGkRwsv/zOza5b9+DuXg\nbL+fShaUAGtULemhyCxWBQcoJPEsrIifel9uK3O4ZvyKr5SqrVV7kTsWm48f1ugz\nZ3bsLxu3oudD8dyukQ4Nv8dLMkvDRH1an/WxGYtmhQKBgQDW9D/g7XdtvzONpOuO\nVcIALIAiekE5sXx6PjRtqK/BRp31Nco1KlDEkHPOZ/j3goQTcEOTlN5oCJzwrPOe\n2M/PIBflEU83Rofua0M9BzjIfziACnw7VjZCj4WOWh2Hb87GFvockIXVR1g2CjTJ\ncgMO99lT5jyi2MLp1XlB6/4HQwKBgQDEVHkRnNItPrhf4jJrT9/k3qyuVDIb8Gig\nwBQaEdvsFPXO/NCni6N8JrODoknVEwRERYJfvryKsRIOkilR7PH49cUGYcOU8wFs\nEayY4nRvbwuhdBcy3fqE7flmy9cHIN9wRqYJFG5hvgXQyecJ0dEd6vDC2eVpRTjv\nGJpRXulitQKBgDCpElzk5QhfJFiIYRrTpxtK96bWbjWVTEyQEGZSrZbfWZrNFn16\nmtYkrVKojt/ZF/UekO2z4bVDXePOA0iOZFzLMx2UEY691L/QYGRMYjphMnUp6n20\nQoxG2UEkfVLPqMuHIA+fV+y0Pe/d151SxgZ5bSVlFYz37QfqX4zg05zpAoGAAgsG\n/4HsRgBDFuxZrfg00kLm9SF3LAdCb3nQO7031qsZK8BBw5yWZPJaJ+KGdisufi9i\n/fAUMjVJhNFMkMewdPDJzhkyWdh1iVRdwXGJ2KcFLfbxTtw0gTGgyMsSP8a9zINP\nswR9aZL6qIORXe7LCE6rlruBwaiwwPw2juY384kCgYBBcbCWC1CC4crJZj+F2b4N\nXqSIwsTqjsc9sdhladw/g9A6pPBKcvNUIi6T0q//QAWyyeD6FvbZazNjvIG+ZCBw\ng/cg+uRPRL7pU8KSQZYBCTQfxniO1p+52idNZAPYOyjPTRzEui59DCLfyrwzIOKe\nkWzF5xJPOw9252QH7XKaqQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/resources/application.yml",
    "content": "spring:\n  ssl:\n    bundle:\n      pem:\n        default:\n          keystore:\n            certificate: \"classpath:default/test-hello-server.crt\"\n            private-key: \"classpath:default/test-hello-server.key\"\n          truststore:\n            certificate: \"classpath:ca/test-ca.crt\"\n        alt:\n          keystore:\n            certificate: \"classpath:alt/test-hello-alt-server.crt\"\n            private-key: \"classpath:alt/test-hello-alt-server.key\"\n          truststore:\n            certificate: \"classpath:ca/test-ca.crt\"\n\nserver:\n  port: 8443\n  ssl:\n    bundle: \"default\"\n    server-name-bundles:\n      - server-name: \"hello.example.com\"\n        bundle: \"default\"\n      - server-name: \"hello-alt.example.com\"\n        bundle: \"alt\"\n\nmanagement:\n  server:\n    port: 8444\n    ssl:\n      bundle: \"default\"\n      server-name-bundles:\n        - server-name: \"hello.example.com\"\n          bundle: \"default\"\n        - server-name: \"hello-alt.example.com\"\n          bundle: \"alt\"\n  endpoints:\n    web:\n      exposure:\n        include:\n          - \"*\"\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/resources/ca/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFjjCCA3agAwIBAgIUNY3OEEWlqJb8zOi8R0OwsmWyhd0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt1v6\nV2wZ4VcJL1BRHWwoinv16dqjouPi4Gzp4UPKtE1BBdqYCSmFpgV0KyDEd1ZFxdAl\n0WDzvuUxeMLlcxGT+c0vLIGVeWtnwowiIaQ32g3Zfcz5jTkLtRL6jLf9pglRzyeH\n80vRKjXnpWMpiYxlIK2AivjsuWMo1kBImGtWAkL/ojNY7wxjJlIy8WgkHSpg7IH/\nWcBjoV3WfMiNxI8pAxq17hMKvduN6EQeLuaGIkhSkCVeJP5wWQGEAfGiyCOugm0q\nC6BEWwkMUN1VuZ4ZMpC5ZIfZxDBqGLczCbq5LTS+6a+O/HmPnI5m83rcR9jKTv2/\neP2rRhrvzmfwngzw0k9l8jglruyKuvio94dcS+ChfLVXQMnhZ/U6j+QjCLNq1PMX\nUuTO9Z5g+2OQYxzUMCEzbzJZ9ofyuX6xbrOTGobXMTIlrKwj+FFG1ortplc8dikp\n8wYOYknZFU8Bj6tMQLfqJ0psF85IHr2NJI+69+YvP4+UTZZ9v+VdoaLL9U/in/wo\nVJ5ohnm0iWt8HmiVhfeIav+WLmSNCMjsukcFCpoosXzbgFFYqQa47USwjjLPFHxa\nrWcDviXhWuTFmKgmG3hnusTg/tKQJzq+4EIDZVIjApw2eAltozPw/bfqD63XV1Yd\n7XuHhIeP2rDH5/7ysw5CIz7ggiy4rwo1KLtZB0UCAwEAAaOBiTCBhjAdBgNVHQ4E\nFgQUSr3isk0cFN0oDQv4c/j3kwPpp/MwHwYDVR0jBBgwFoAUSr3isk0cFN0oDQv4\nc/j3kwPpp/MwDwYDVR0TAQH/BAUwAwEB/zAzBgNVHREELDAqghFoZWxsby5leGFt\ncGxlLmNvbYIVaGVsbG8tYWx0LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IC\nAQBRlUKOILQqJImVMNv8WpcWAdfUFW5G+eUvSSkxqk7abewONdwK5NXEledLHVuA\npOejsjdd4Vj1MMoY3SmaEVa3pKe38hFDhXRGnQGRWzTsu081+oZQjnINNw53exbx\nxjrV0qFVJR5MmbhkJaGuIFTJyONwVc9y7mpVAbJ/VcXXkK8qJ7lbcFGC9KuNFOtl\n6Me710vBm3QxNXuBHzmc/ac1ZeXYTokvRmRoRjBi4wSfCisKXmJqrHuqw22lZ4Sc\ncdoEwELSQssCj8EHbj5CYbyQIOqclZqkgThLfp04uwfO1THx7CMiXnZKBntmbjuo\nRnrAqvYaAdL9DDLsVZaibqhmYp3nAioZiA08jNUAcIXCIsomqawsBciYO/7SoFz5\nqAX/UKJ13jRGVKfRJEVXy3XnqpoGpv8z2m4X5IYhCBbTm4Q3X0iPSlpgQZyAUyTx\ntfRJ1mycAKvG/0fdVohT5we1URjiYGcqpfQ8BF43hXI7hJY2nUfydQVnnAZkFMo8\na6yYJ/xh+oRu3pSADN5UtTcJvEdfIGDVC+PcbAC5tgQEZq55EXYxt31X51oO8mb2\nK1V6GDJHd3/khEY4nUbYfdfI1hKoUbWTBqiW9CjuSsHeD8cw2D7xM8gXeIhRpZTG\nSGsQlVlCFtJcIh/0/DcCG/UgGvPhyXhntvQe/+iOK2tdIQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/resources/default/test-hello-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEYjCCAkqgAwIBAgIUWUyiO2/3ZShhRKAs+4QrJjDe9wQwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMjE0MzY0MVoXDTM0MDQzMDE0MzY0MVow\nNzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEaMBgGA1UEAwwRaGVsbG8uZXhh\nbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7F/5wLby8\nMm9WFAQAXTLkZUI4fjnAinwmkfvOMihQLBAcpRJM4Ox8CfCp9sa3+EVevfwMqyLT\naXefBjBAamXCMLk76a2Sl8XqUWBYg6a/j1zZKmEZOzxNnzCfWRVh6gCbqO6OT5DH\nCs/4hLgyNt3jTKlIijyQyp3XxmAOqECsr3y6Cp++WyVgcOGU1m+em0Cs3nxOE1xs\nFWfm8Ycw8kMymYOdUpejgk+naIeWj7SBCd6QJ33xWBhcrBxEhQjnQeM8+ROMT4qB\naRYvJ3OtLfOHrd7eETQbpL3z2Q1GC+vQdQuKBj2/xJ9BXI40TpCq05oFu1Ffg22g\nQHJwCeFskOlZAgMBAAGjYjBgMAsGA1UdDwQEAwIFoDARBglghkgBhvhCAQEEBAMC\nBkAwHQYDVR0OBBYEFKum2hVx8Wf691lwK2uVJWOB6sC6MB8GA1UdIwQYMBaAFEq9\n4rJNHBTdKA0L+HP495MD6afzMA0GCSqGSIb3DQEBCwUAA4ICAQB8pZvrA2RKPdnp\nLEE/uD00ykJF7ZEV1bPADCsKqKR8Q9Z6xU+hLmJkzL2XbKxD+7OHeJJevTB1+yBT\nDaYKIIqQcjudWOEwjyUeat78MdoJJMukLQGTYD59NxLIVApUsLtVVIFUKdf7Ct7y\nLQulHKKS05SmKMwL8E580espG8fl+VJfakxcQdvsxBPrfAfza81EHmQ0GBM9gIwu\nO/QBv0oU+pvSwdOw5uHRd8tvmOFOcaqQii2MhVo1KW7tVfvDaLNJrt4fBoT5hAEe\nfvKbaaKouHDQLlAKhGhvNcqwK+KogAOWF4QH002qvjfGBtQh/zixEZegGodxZeN4\nNGH6n4xvgvvm+Ke1GWBBeUf8xMjV93KeVSZliC2Ugnc8nfqszkUIgv7gMU5yC1ty\natOsc8Zob/QLAhLsBToCuZ4S1rzFxzHA+qVtF9OZPhoKoGJHsA3R/ZvRJgIg66Hh\naA6b9TxdzuZuXclAg3cKJffQnukYHmy7OgNoxz/Su10/dcdRwg3AZYd0+ZX75v+B\n+W1jMfiokA+CknakPU6ct9F+WDIj6NVzeckwejLk9DmMT92bFvFr7r8OnMXO3Se9\nrdqQUXrbXSQHoIUOF5U4ghbWgkiEh7wAIiRaa7gExiaUaRcNTHBNymjfYmETjnIx\nOlYhXImujQBiAcdbLYQFBlrzCu16Fw==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/spring-boot-sni-servlet-app/src/main/resources/default/test-hello-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC7F/5wLby8Mm9W\nFAQAXTLkZUI4fjnAinwmkfvOMihQLBAcpRJM4Ox8CfCp9sa3+EVevfwMqyLTaXef\nBjBAamXCMLk76a2Sl8XqUWBYg6a/j1zZKmEZOzxNnzCfWRVh6gCbqO6OT5DHCs/4\nhLgyNt3jTKlIijyQyp3XxmAOqECsr3y6Cp++WyVgcOGU1m+em0Cs3nxOE1xsFWfm\n8Ycw8kMymYOdUpejgk+naIeWj7SBCd6QJ33xWBhcrBxEhQjnQeM8+ROMT4qBaRYv\nJ3OtLfOHrd7eETQbpL3z2Q1GC+vQdQuKBj2/xJ9BXI40TpCq05oFu1Ffg22gQHJw\nCeFskOlZAgMBAAECggEABSLvQBatXhBXaKpTgswMO+OAyirC/KOArZFn850CaNMQ\n3Sx2AGjTbUNbmVr2UTIue1+lZhajteCpIVNK61XQdeCfEUNE2eezTg/OYJe6sfsm\nXirw7/+lk+75J4LLWL0TJ7LfW8ZY7/H+zDCemvhRJq6h3iU3bPU3GKewVu6tGeCK\nfCBB4dD2FnBkKjX9SGeDpBcqZusRvzBkrzSgcCjsjKYhKXxuGQh4yEv7qD4KD7e+\nJWpW6wTEpHtSZ896q7p+tNdRJl5iQhSLWjx3lWe3iX7vqzEbglwfl8x7dNabVA9+\nryqrt3xPIt7m4t09F12DLb+UvZhP2GEbEbw9wsdYQQKBgQDeV3d3q0+FVNByoGxz\n4lW40/3aTkI/ljnAFwjXuyCFwsdcj9+UFpl/pQ5L9OJbwBx35cJSLwAMngUC+bgp\nX4cNYml6u8rQi+7ogl15mhkXKYC5+dK0uZ+M7o95/ej24cDtl+nArr2KpkSDAB4H\n7jcVRcYHUwbaWlf5mApox13y+QKBgQDXaoswCBytU81O9mJNEH7dGC9HrJYT8Qyn\naCQ1spfWU1/taX4HXJhOtU4J8XgXFvbh0sUFbzmcO0vgd6vCgsMPtuqEHyjmtieO\n2VAsiBC1EWI6LhWiWmzHdXc2HOjYvKVI7WarW122bOsL14LQkvqz4QmHxh72aoRZ\nR6UNSoPhYQKBgD8aQ+XK0P7eW2qs7RrWmc2jHODgZRz23d0OrIvNqCVOapZyntnA\nsD/x8GTOU5AGrg25P7VjcXgjQPjfNs1HN2UtERKsSZt2m4+RsEXa3lQci1Q8+vgf\n1pCBBGdzELNAzyiffNAax+CZ38fuOJe3nBqFevaJMeC201EbPZkPPDLBAoGAI9jt\nFK8k5osdjVhe/2gRVIWjyI+l4eepLWqdK/puXhI90mpNuLfl+KMfO3Rdgaomp2nF\ns6PQuHj9pXsEsDfGciUEXbw5uDrz1ke/mcmCzj74U6o7m2rk00Ru9ChXb0nlT3+C\nKF3p+GOjsbLJaCAtbCW0yk1j9anAIINVqiKOU8ECgYAU4N4f0+FSsWooiaC9qRzR\nkju2ASqalK0NPr3aFowRHL32jdeNd/Gb6DiNcK2oB7jMq54kv1g2Z+e5UN0lmr5A\nSTsgEzodIvapmGtJ27NeolUOjPqv/vAYjAUPdzDUjLIslOIT7tRR32kx8xgslOj/\nkzkHCV1ZuJ60Ukxv6mwj3g==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "integration-test/spring-boot-sni-integration-tests/src/intTest/java/org/springframework/boot/sni/SniIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sni;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.Map;\n\nimport org.awaitility.Awaitility;\nimport org.awaitility.core.ConditionTimeoutException;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.CsvSource;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.Network;\nimport org.testcontainers.images.builder.ImageFromDockerfile;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for SSL configuration with SNI.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass SniIntegrationTests {\n\n\tprivate static final Map<String, String> SERVER_START_MESSAGES = Map.ofEntries(Map.entry(\"netty\", \"Netty started\"),\n\t\t\tMap.entry(\"tomcat\", \"Tomcat initialized\"));\n\n\tpublic static final String PRIMARY_SERVER_NAME = \"hello.example.com\";\n\n\tpublic static final String ALT_SERVER_NAME = \"hello-alt.example.com\";\n\n\tprivate static final Integer SERVER_PORT = 8443;\n\n\tprivate static final Network SHARED_NETWORK = Network.newNetwork();\n\n\t@ParameterizedTest\n\t@CsvSource({ \"reactive,netty\", \"reactive,tomcat\", \"servlet,tomcat\" })\n\tvoid home(String webStack, String server) {\n\t\ttry (ApplicationContainer serverContainer = new ServerApplicationContainer(webStack, server)) {\n\t\t\tserverContainer.start();\n\t\t\ttry {\n\t\t\t\tAwaitility.await().atMost(Duration.ofSeconds(60)).until(serverContainer::isRunning);\n\t\t\t}\n\t\t\tcatch (ConditionTimeoutException ex) {\n\t\t\t\tSystem.out.println(serverContainer.getLogs());\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tString serverLogs = serverContainer.getLogs();\n\t\t\tassertThat(serverLogs).contains(SERVER_START_MESSAGES.get(server));\n\t\t\ttry (ApplicationContainer clientContainer = new ClientApplicationContainer()) {\n\t\t\t\tclientContainer.start();\n\t\t\t\tAwaitility.await().atMost(Duration.ofSeconds(60)).until(() -> !clientContainer.isRunning());\n\t\t\t\tString clientLogs = clientContainer.getLogs();\n\t\t\t\tassertServerCalledWithName(clientLogs, PRIMARY_SERVER_NAME);\n\t\t\t\tassertServerCalledWithName(clientLogs, ALT_SERVER_NAME);\n\t\t\t\tclientContainer.stop();\n\t\t\t}\n\t\t\tserverContainer.stop();\n\t\t}\n\t}\n\n\tprivate void assertServerCalledWithName(String clientLogs, String serverName) {\n\t\tassertThat(clientLogs).contains(\"Calling server at 'https://\" + serverName + \":8443/'\")\n\t\t\t.contains(\"Hello from https://\" + serverName + \":8443/\");\n\t\tassertThat(clientLogs).contains(\"Calling server actuator at 'https://\" + serverName + \":8444/actuator/health'\")\n\t\t\t.contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\tstatic final class ClientApplicationContainer extends ApplicationContainer {\n\n\t\tClientApplicationContainer() {\n\t\t\tsuper(\"spring-boot-sni-client-app\", \"\", PRIMARY_SERVER_NAME, ALT_SERVER_NAME);\n\t\t}\n\n\t}\n\n\tstatic final class ServerApplicationContainer extends ApplicationContainer {\n\n\t\tServerApplicationContainer(String webStack, String server) {\n\t\t\tsuper(\"spring-boot-sni-\" + webStack + \"-app\", \"-\" + server);\n\t\t\twithNetworkAliases(PRIMARY_SERVER_NAME, ALT_SERVER_NAME);\n\t\t}\n\n\t}\n\n\tstatic class ApplicationContainer extends GenericContainer<ApplicationContainer> {\n\n\t\tprotected ApplicationContainer(String appName, String fileSuffix, String... entryPointArgs) {\n\t\t\tsuper(new ImageFromDockerfile().withFileFromFile(\"spring-boot.jar\", findJarFile(appName, fileSuffix))\n\t\t\t\t.withDockerfileFromBuilder((builder) -> builder.from(\"eclipse-temurin:17-jre-noble\")\n\t\t\t\t\t.add(\"spring-boot.jar\", \"/spring-boot.jar\")\n\t\t\t\t\t.entryPoint(buildEntryPoint(entryPointArgs))));\n\t\t\twithExposedPorts(SERVER_PORT);\n\t\t\twithStartupTimeout(Duration.ofMinutes(2));\n\t\t\twithStartupAttempts(3);\n\t\t\twithNetwork(SHARED_NETWORK);\n\t\t\twithNetworkMode(SHARED_NETWORK.getId());\n\t\t}\n\n\t\tprivate static File findJarFile(String appName, String fileSuffix) {\n\t\t\tString path = String.format(\"build/%1$s/build/libs/%1$s%2$s.jar\", appName, fileSuffix);\n\t\t\tFile jar = new File(path);\n\t\t\tAssert.state(jar.isFile(), () -> \"Could not find \" + path);\n\t\t\treturn jar;\n\t\t}\n\n\t\tprivate static String buildEntryPoint(String... args) {\n\t\t\tStringBuilder builder = new StringBuilder().append(\"java\").append(\" -jar\").append(\" /spring-boot.jar\");\n\t\t\tfor (String arg : args) {\n\t\t\t\tbuilder.append(\" \").append(arg);\n\t\t\t}\n\t\t\treturn builder.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nplugins {\n\tid \"java-library\"\n}\n\ndescription = \"Spring Boot Test Integration Tests\"\n\ndependencies {\n\ttestImplementation(project(\":core:spring-boot-autoconfigure\"))\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-http-codec\"))\n\ttestImplementation(project(\":module:spring-boot-restclient-test\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":module:spring-boot-webflux-test\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-webtestclient\"))\n\ttestImplementation(project(\":module:spring-boot-web-server\"))\n\ttestImplementation(project(\":module:spring-boot-web-server-test\"))\n\ttestImplementation(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for {@link SpringBootTest @SpringBootTest} tests configured to start an\n * embedded reactive container.\n *\n * @author Stephane Nicoll\n */\n@AutoConfigureWebTestClient\n@AutoConfigureTestRestTemplate\nabstract class AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Value(\"${value}\")\n\tprivate int value;\n\n\t@Autowired\n\tprivate ReactiveWebApplicationContext context;\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\tReactiveWebApplicationContext getContext() {\n\t\treturn this.context;\n\t}\n\n\t@Test\n\tvoid runAndTestHttpEndpoint() {\n\t\tassertThat(this.port).isNotEqualTo(8080).isNotZero();\n\t\tWebTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://localhost:\" + this.port)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build()\n\t\t\t.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid injectWebTestClient() {\n\t\tthis.webClient.get().uri(\"/\").exchange().expectBody(String.class).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid injectTestRestTemplate() {\n\t\tString body = this.restTemplate.getForObject(\"/\", String.class);\n\t\tassertThat(body).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid annotationAttributesOverridePropertiesFile() {\n\t\tassertThat(this.value).isEqualTo(123);\n\t}\n\n\tstatic class AbstractConfig {\n\n\t\t@Value(\"${server.port:8080}\")\n\t\tprivate int port = 8080;\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ApplicationContext applicationContext) {\n\t\t\treturn WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t\t}\n\n\t\t@Bean\n\t\tReactiveWebServerFactory webServerFactory() {\n\t\t\tTomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();\n\t\t\tfactory.setPort(this.port);\n\t\t\treturn factory;\n\t\t}\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertyPlaceholder() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t\t@RequestMapping(\"/\")\n\t\tMono<String> home() {\n\t\t\treturn Mono.just(\"Hello World\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/AbstractSpringBootTestWebServerWebEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for {@link SpringBootTest @SpringBootTest} tests configured to start an\n * embedded web server.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@AutoConfigureRestTestClient\n@AutoConfigureTestRestTemplate\nabstract class AbstractSpringBootTestWebServerWebEnvironmentTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Value(\"${value}\")\n\tprivate int value;\n\n\t@Autowired\n\tprivate WebApplicationContext context;\n\n\t@Autowired\n\tprivate ServletContext servletContext;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate RestTestClient restClient;\n\n\tWebApplicationContext getContext() {\n\t\treturn this.context;\n\t}\n\n\tTestRestTemplate getRestTemplate() {\n\t\treturn this.restTemplate;\n\t}\n\n\t@Test\n\tvoid runAndTestHttpEndpoint() {\n\t\tassertThat(this.port).isNotEqualTo(8080).isNotZero();\n\t\tString body = new RestTemplate().getForObject(\"http://localhost:\" + this.port + \"/\", String.class);\n\t\tassertThat(body).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid injectTestRestTemplate() {\n\t\tString body = this.restTemplate.getForObject(\"/\", String.class);\n\t\tassertThat(body).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid injectRestTestClient() {\n\t\tResponseSpec spec = this.restClient.get().uri(\"/\").exchange();\n\t\tassertThat(RestTestClientResponse.from(spec)).bodyText().isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid annotationAttributesOverridePropertiesFile() {\n\t\tassertThat(this.value).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid validateWebApplicationContextIsSet() {\n\t\tassertThat(this.context).isSameAs(WebApplicationContextUtils.getWebApplicationContext(this.servletContext));\n\t}\n\n\tstatic class AbstractConfig {\n\n\t\t@Value(\"${server.port:8080}\")\n\t\tprivate int port = 8080;\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t\t@Bean\n\t\tServletWebServerFactory webServerFactory() {\n\t\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();\n\t\t\tfactory.setPort(this.port);\n\t\t\treturn factory;\n\t\t}\n\n\t\t@Bean\n\t\tstatic PropertySourcesPlaceholderConfigurer propertyPlaceholder() {\n\t\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t\t}\n\n\t\t@RequestMapping(\"/\")\n\t\tString home() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/AutoConfigureWebServerWebMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServerWebMvcIntegrationTests.TestController;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigureWebServer @AutoConfigureWebServer} and Spring\n * MVC.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(classes = TestController.class, webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebServer\n@AutoConfigureWebMvc\n@AutoConfigureRestTestClient\nclass AutoConfigureWebServerWebMvcIntegrationTests {\n\n\t@Test\n\tvoid embeddedWebServerWithSpringMvcIsAvailable(@Autowired RestTestClient restClient) {\n\t\tassertThat(RestTestClientResponse.from(restClient.get().uri(\"/hello\").exchange())).hasStatusOk()\n\t\t\t.bodyText()\n\t\t\t.isEqualTo(\"hello\");\n\t}\n\n\t@RestController\n\tstatic class TestController {\n\n\t\t@RequestMapping(\"/hello\")\n\t\tString hello() {\n\t\t\treturn \"hello\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestReactiveWebEnvironmentDefinedPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.reactive.config.EnableWebFlux;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} in a reactive environment configured\n * with {@link WebEnvironment#DEFINED_PORT}.\n *\n * @author Stephane Nicoll\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT,\n\t\tproperties = { \"spring.main.web-application-type=reactive\", \"server.port=0\", \"value=123\" })\npublic class SpringBootTestReactiveWebEnvironmentDefinedPortTests\n\t\textends AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\t@RestController\n\tstatic class Config extends AbstractConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestReactiveWebEnvironmentRandomPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.reactive.config.EnableWebFlux;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} in a reactive environment configured\n * with {@link WebEnvironment#RANDOM_PORT}.\n *\n * @author Stephane Nicoll\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.main.webApplicationType=reactive\", \"value=123\" })\npublic class SpringBootTestReactiveWebEnvironmentRandomPortTests\n\t\textends AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\t@RestController\n\tstatic class Config extends AbstractConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestReactiveWebEnvironmentUserDefinedTestRestTemplateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.reactive.config.EnableWebFlux;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} in a reactive environment configured\n * with a user-defined {@link RestTemplate} that is named {@code testRestTemplate}.\n *\n * @author Madhura Bhave\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.main.web-application-type=reactive\", \"value=123\" })\nclass SpringBootTestReactiveWebEnvironmentUserDefinedTestRestTemplateTests\n\t\textends AbstractSpringBootTestEmbeddedReactiveWebEnvironmentTests {\n\n\t@Test\n\tvoid restTemplateIsUserDefined() {\n\t\tassertThat(getContext().getBean(\"testRestTemplate\")).isInstanceOf(RestTemplate.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\t@RestController\n\tstatic class Config extends AbstractConfig {\n\n\t\t@Bean\n\t\tRestTemplate testRestTemplate() {\n\t\t\treturn new RestTemplate();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestUserDefinedTestRestTemplateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with a user-defined\n * {@link RestTemplate} that is named {@code testRestTemplate}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"value=123\" })\nclass SpringBootTestUserDefinedTestRestTemplateTests extends AbstractSpringBootTestWebServerWebEnvironmentTests {\n\n\t@Test\n\tvoid restTemplateIsUserDefined() {\n\t\tassertThat(getContext().getBean(\"testRestTemplate\")).isInstanceOf(RestTemplate.class);\n\t}\n\n\t// gh-7711\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@RestController\n\tstatic class Config extends AbstractConfig {\n\n\t\t@Bean\n\t\tRestTemplate testRestTemplate() {\n\t\t\treturn new RestTemplate();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestWebEnvironmentContextHierarchyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.web.server.test.AbstractSpringBootTestWebServerWebEnvironmentTests.AbstractConfig;\nimport org.springframework.boot.web.server.test.SpringBootTestWebEnvironmentContextHierarchyTests.ChildConfiguration;\nimport org.springframework.boot.web.server.test.SpringBootTestWebEnvironmentContextHierarchyTests.ParentConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.ContextHierarchy;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with\n * {@link WebEnvironment#DEFINED_PORT}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = { \"server.port=0\", \"value=123\" })\n@ContextHierarchy({ @ContextConfiguration(classes = ParentConfiguration.class),\n\t\t@ContextConfiguration(classes = ChildConfiguration.class) })\nclass SpringBootTestWebEnvironmentContextHierarchyTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid testShouldOnlyStartSingleServer() {\n\t\tApplicationContext parent = this.context.getParent();\n\t\tassertThat(this.context).isInstanceOf(WebApplicationContext.class);\n\t\tassertThat(parent).isNotInstanceOf(WebApplicationContext.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParentConfiguration extends AbstractConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@RestController\n\tstatic class ChildConfiguration extends AbstractConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestWebEnvironmentDefinedPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with\n * {@link WebEnvironment#DEFINED_PORT}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, properties = { \"server.port=0\", \"value=123\" })\nclass SpringBootTestWebEnvironmentDefinedPortTests extends AbstractSpringBootTestWebServerWebEnvironmentTests {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@RestController\n\tstatic class Config extends AbstractConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestWebEnvironmentRandomPortCustomPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.web.server.test.AbstractSpringBootTestWebServerWebEnvironmentTests.AbstractConfig;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link SpringBootTest @SpringBootTest} with a custom inline server.port in an\n * embedded web environment.\n *\n * @author Stephane Nicoll\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"server.port=12345\" })\nclass SpringBootTestWebEnvironmentRandomPortCustomPortTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid validatePortIsNotOverwritten() {\n\t\tString port = this.environment.getProperty(\"server.port\");\n\t\tassertThat(port).isEqualTo(\"0\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class Config extends AbstractConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/web/server/test/SpringBootTestWebEnvironmentRandomPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} configured with\n * {@link WebEnvironment#RANDOM_PORT}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"value=123\" })\nclass SpringBootTestWebEnvironmentRandomPortTests extends AbstractSpringBootTestWebServerWebEnvironmentTests {\n\n\t@Test\n\tvoid testRestTemplateShouldUseBuilder() {\n\t\tassertThat(getRestTemplate().getRestTemplate().getMessageConverters())\n\t\t\t.hasAtLeastOneElementOfType(MyConverter.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@RestController\n\tstatic class Config extends AbstractConfig {\n\n\t\t@Bean\n\t\tRestTemplateBuilder restTemplateBuilder() {\n\t\t\treturn new RestTemplateBuilder().additionalMessageConverters(new MyConverter());\n\t\t}\n\n\t}\n\n\tstatic class MyConverter extends StringHttpMessageConverter {\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Jarmode Tools\"\n\ndependencies {\n\timplementation(project(\":loader:spring-boot-loader\"))\n\timplementation(\"org.springframework:spring-core\")\n\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.mockito:mockito-core\")\n\ttestImplementation(\"org.mockito:mockito-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Command.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A command that can be launched.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nabstract class Command {\n\n\tprivate final String name;\n\n\tprivate final String description;\n\n\tprivate final Options options;\n\n\tprivate final Parameters parameters;\n\n\t/**\n\t * Create a new {@link Command} instance.\n\t * @param name the name of the command\n\t * @param description a description of the command\n\t * @param options the command options\n\t * @param parameters the command parameters\n\t */\n\tCommand(String name, String description, Options options, Parameters parameters) {\n\t\tthis.name = name;\n\t\tthis.description = description;\n\t\tthis.options = options;\n\t\tthis.parameters = parameters;\n\t}\n\n\t/**\n\t * Return the name of this command.\n\t * @return the command name\n\t */\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the description of this command.\n\t * @return the command description\n\t */\n\tString getDescription() {\n\t\treturn this.description;\n\t}\n\n\t/**\n\t * Return options that this command accepts.\n\t * @return the command options\n\t */\n\tOptions getOptions() {\n\t\treturn this.options;\n\t}\n\n\t/**\n\t * Return parameters that this command accepts.\n\t * @return the command parameters\n\t */\n\tParameters getParameters() {\n\t\treturn this.parameters;\n\t}\n\n\t/**\n\t * Run the command by processing the remaining arguments.\n\t * @param out stream for command output\n\t * @param args a mutable deque of the remaining arguments\n\t */\n\tfinal void run(PrintStream out, Deque<String> args) {\n\t\tList<String> parameters = new ArrayList<>();\n\t\tMap<Option, @Nullable String> options = new HashMap<>();\n\t\twhile (!args.isEmpty()) {\n\t\t\tString arg = args.removeFirst();\n\t\t\tOption option = this.options.find(arg);\n\t\t\tif (option != null) {\n\t\t\t\toptions.put(option, option.claimArg(args));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tparameters.add(arg);\n\t\t\t}\n\t\t}\n\t\trun(out, options, parameters);\n\t}\n\n\t/**\n\t * Run the actual command.\n\t * @param out stream for command output\n\t * @param options any options extracted from the arguments\n\t * @param parameters any parameters extracted from the arguments\n\t */\n\tabstract void run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters);\n\n\t/**\n\t * Whether the command is deprecated.\n\t * @return whether the command is deprecated\n\t */\n\tboolean isDeprecated() {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns the deprecation message.\n\t * @return the deprecation message\n\t */\n\t@Nullable String getDeprecationMessage() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Static method that can be used to find a single command from a collection.\n\t * @param commands the commands to search\n\t * @param name the name of the command to find\n\t * @return a {@link Command} instance or {@code null}.\n\t */\n\tstatic @Nullable Command find(Collection<? extends Command> commands, String name) {\n\t\tfor (Command command : commands) {\n\t\t\tif (command.getName().equals(name)) {\n\t\t\t\treturn command;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Parameters that the command accepts.\n\t */\n\tstatic final class Parameters {\n\n\t\tprivate final List<String> descriptions;\n\n\t\tprivate Parameters(String[] descriptions) {\n\t\t\tthis.descriptions = Collections.unmodifiableList(Arrays.asList(descriptions));\n\t\t}\n\n\t\t/**\n\t\t * Return the parameter descriptions.\n\t\t * @return the descriptions\n\t\t */\n\t\tList<String> getDescriptions() {\n\t\t\treturn this.descriptions;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.descriptions.toString();\n\t\t}\n\n\t\t/**\n\t\t * Factory method used if there are no expected parameters.\n\t\t * @return a new {@link Parameters} instance\n\t\t */\n\t\tstatic Parameters none() {\n\t\t\treturn of();\n\t\t}\n\n\t\t/**\n\t\t * Factory method used to create a new {@link Parameters} instance with specific\n\t\t * descriptions.\n\t\t * @param descriptions the parameter descriptions\n\t\t * @return a new {@link Parameters} instance with the given descriptions\n\t\t */\n\t\tstatic Parameters of(String... descriptions) {\n\t\t\treturn new Parameters(descriptions);\n\t\t}\n\n\t}\n\n\t/**\n\t * Options that the command accepts.\n\t */\n\tstatic final class Options {\n\n\t\tprivate final Option[] values;\n\n\t\tprivate Options(Option[] values) {\n\t\t\tthis.values = values;\n\t\t}\n\n\t\tprivate @Nullable Option find(String arg) {\n\t\t\tif (arg.startsWith(\"--\")) {\n\t\t\t\tString name = arg.substring(2);\n\t\t\t\tfor (Option candidate : this.values) {\n\t\t\t\t\tif (candidate.getName().equals(name)) {\n\t\t\t\t\t\treturn candidate;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow new UnknownOptionException(name);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t/**\n\t\t * Return if this options collection is empty.\n\t\t * @return if there are no options\n\t\t */\n\t\tboolean isEmpty() {\n\t\t\treturn this.values.length == 0;\n\t\t}\n\n\t\t/**\n\t\t * Return a stream of each option.\n\t\t * @return a stream of the options\n\t\t */\n\t\tStream<Option> stream() {\n\t\t\treturn Arrays.stream(this.values);\n\t\t}\n\n\t\t/**\n\t\t * Factory method used if there are no expected options.\n\t\t * @return a new {@link Options} instance\n\t\t */\n\t\tstatic Options none() {\n\t\t\treturn of();\n\t\t}\n\n\t\t/**\n\t\t * Factory method used to create a new {@link Options} instance with specific\n\t\t * values.\n\t\t * @param values the option values\n\t\t * @return a new {@link Options} instance with the given values\n\t\t */\n\t\tstatic Options of(Option... values) {\n\t\t\treturn new Options(values);\n\t\t}\n\n\t}\n\n\t/**\n\t * An individual option that the command can accepts. Can either be an option with a\n\t * value (e.g. {@literal --log debug}) or a flag (e.g. {@literal\n\t * --verbose}). It also can be both if the value is marked as optional.\n\t */\n\tstatic final class Option {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable String valueDescription;\n\n\t\tprivate final String description;\n\n\t\tprivate final boolean optionalValue;\n\n\t\tprivate Option(String name, @Nullable String valueDescription, String description, boolean optionalValue) {\n\t\t\tthis.name = name;\n\t\t\tthis.description = description;\n\t\t\tthis.valueDescription = valueDescription;\n\t\t\tthis.optionalValue = optionalValue;\n\t\t}\n\n\t\t/**\n\t\t * Return the name of the option.\n\t\t * @return the options name\n\t\t */\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t/**\n\t\t * Return the description of the expected argument value or {@code null} if this\n\t\t * option is a flag/switch.\n\t\t * @return the option value description\n\t\t */\n\t\t@Nullable String getValueDescription() {\n\t\t\treturn this.valueDescription;\n\t\t}\n\n\t\t/**\n\t\t * Return the name and the value description combined.\n\t\t * @return the name and value description\n\t\t */\n\t\tString getNameAndValueDescription() {\n\t\t\treturn this.name + ((this.valueDescription != null) ? \" \" + this.valueDescription : \"\");\n\t\t}\n\n\t\t/**\n\t\t * Return a description of the option.\n\t\t * @return the option description\n\t\t */\n\t\tString getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tprivate @Nullable String claimArg(Deque<String> args) {\n\t\t\tif (this.valueDescription == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (this.optionalValue) {\n\t\t\t\tString nextArg = args.peek();\n\t\t\t\treturn (nextArg != null && !nextArg.startsWith(\"--\")) ? args.removeFirst() : null;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn args.removeFirst();\n\t\t\t}\n\t\t\tcatch (NoSuchElementException ex) {\n\t\t\t\tthrow new MissingValueException(this.name);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.name.equals(((Option) obj).name);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.name.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t/**\n\t\t * Factory method to create a flag/switch option.\n\t\t * @param name the name of the option\n\t\t * @param description a description of the option\n\t\t * @return a new {@link Option} instance\n\t\t */\n\t\tstatic Option flag(String name, String description) {\n\t\t\treturn new Option(name, null, description, false);\n\t\t}\n\n\t\t/**\n\t\t * Factory method to create value option.\n\t\t * @param name the name of the option\n\t\t * @param valueDescription a description of the expected value\n\t\t * @param description a description of the option\n\t\t * @return a new {@link Option} instance\n\t\t */\n\t\tstatic Option of(String name, String valueDescription, String description) {\n\t\t\treturn new Option(name, valueDescription, description, false);\n\t\t}\n\n\t\t/**\n\t\t * Factory method to create value option.\n\t\t * @param name the name of the option\n\t\t * @param valueDescription a description of the expected value\n\t\t * @param description a description of the option\n\t\t * @param optionalValue whether the value is optional\n\t\t * @return a new {@link Option} instance\n\t\t */\n\t\tstatic Option of(String name, String valueDescription, String description, boolean optionalValue) {\n\t\t\treturn new Option(name, valueDescription, description, optionalValue);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Context.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.JarURLConnection;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.nio.file.Paths;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.Locale;\nimport java.util.jar.JarFile;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Context for use by commands.\n *\n * @author Phillip Webb\n */\nclass Context {\n\n\tprivate final File archiveFile;\n\n\tprivate final File workingDir;\n\n\tprivate final @Nullable String relativeDir;\n\n\t/**\n\t * Create a new {@link Context} instance.\n\t */\n\tContext() {\n\t\tthis(getSourceArchiveFile(), Paths.get(\".\").toAbsolutePath().normalize().toFile());\n\t}\n\n\t/**\n\t * Create a new {@link Context} instance with the specified value.\n\t * @param archiveFile the source archive file\n\t * @param workingDir the working directory\n\t */\n\tContext(File archiveFile, File workingDir) {\n\t\tAssert.state(isExistingFile(archiveFile), \"Unable to find source archive\");\n\t\tAssert.state(isJarOrWar(archiveFile), \"Source archive \" + archiveFile + \" must end with .jar or .war\");\n\t\tthis.archiveFile = archiveFile;\n\t\tthis.workingDir = workingDir;\n\t\tthis.relativeDir = deduceRelativeDir(archiveFile.getParentFile(), this.workingDir);\n\t}\n\n\tprivate boolean isExistingFile(@Nullable File archiveFile) {\n\t\treturn archiveFile != null && archiveFile.isFile() && archiveFile.exists();\n\t}\n\n\tprivate boolean isJarOrWar(File jarFile) {\n\t\tString name = jarFile.getName().toLowerCase(Locale.ROOT);\n\t\treturn name.endsWith(\".jar\") || name.endsWith(\".war\");\n\t}\n\n\tprivate static File getSourceArchiveFile() {\n\t\ttry {\n\t\t\tProtectionDomain domain = Context.class.getProtectionDomain();\n\t\t\tCodeSource codeSource = (domain != null) ? domain.getCodeSource() : null;\n\t\t\tURL location = (codeSource != null) ? codeSource.getLocation() : null;\n\t\t\tFile source = (location != null) ? findSource(location) : null;\n\t\t\tif (source != null && source.exists()) {\n\t\t\t\treturn source.getAbsoluteFile();\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unable to find source archive\");\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to find source archive\", ex);\n\t\t}\n\t}\n\n\tprivate static File findSource(URL location) throws IOException, URISyntaxException {\n\t\tURLConnection connection = location.openConnection();\n\t\tif (connection instanceof JarURLConnection jarURLConnection) {\n\t\t\treturn getRootJarFile(jarURLConnection.getJarFile());\n\t\t}\n\t\treturn new File(location.toURI());\n\t}\n\n\tprivate static File getRootJarFile(JarFile jarFile) {\n\t\tString name = jarFile.getName();\n\t\tint separator = name.indexOf(\"!/\");\n\t\tif (separator > 0) {\n\t\t\tname = name.substring(0, separator);\n\t\t}\n\t\treturn new File(name);\n\t}\n\n\tprivate @Nullable String deduceRelativeDir(File sourceDirectory, File workingDir) {\n\t\tString sourcePath = sourceDirectory.getAbsolutePath();\n\t\tString workingPath = workingDir.getAbsolutePath();\n\t\tif (sourcePath.equals(workingPath) || !sourcePath.startsWith(workingPath)) {\n\t\t\treturn null;\n\t\t}\n\t\tString relativePath = sourcePath.substring(workingPath.length() + 1);\n\t\treturn !relativePath.isEmpty() ? relativePath : null;\n\t}\n\n\t/**\n\t * Return the source archive file that is running in tools mode.\n\t * @return the archive file\n\t */\n\tFile getArchiveFile() {\n\t\treturn this.archiveFile;\n\t}\n\n\t/**\n\t * Return the current working directory.\n\t * @return the working dir\n\t */\n\tFile getWorkingDir() {\n\t\treturn this.workingDir;\n\t}\n\n\t/**\n\t * Return the directory relative to {@link #getWorkingDir()} that contains the archive\n\t * or {@code null} if none relative directory can be deduced.\n\t * @return the relative dir ending in {@code /} or {@code null}\n\t */\n\t@Nullable String getRelativeArchiveDir() {\n\t\treturn this.relativeDir;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ExtractCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.io.UncheckedIOException;\nimport java.nio.file.Files;\nimport java.nio.file.attribute.BasicFileAttributeView;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.nio.file.attribute.FileTime;\nimport java.util.EnumSet;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jarmode.tools.JarStructure.Entry;\nimport org.springframework.boot.jarmode.tools.JarStructure.Entry.Type;\nimport org.springframework.boot.loader.jarmode.JarModeErrorException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * The {@code 'extract'} tools command.\n *\n * @author Moritz Halbritter\n */\nclass ExtractCommand extends Command {\n\n\t/**\n\t * Option to create a launcher.\n\t */\n\tstatic final Option LAUNCHER_OPTION = Option.flag(\"launcher\", \"Whether to extract the Spring Boot launcher\");\n\n\t/**\n\t * Option to extract layers.\n\t */\n\tstatic final Option LAYERS_OPTION = Option.of(\"layers\", \"string list\", \"Layers to extract\", true);\n\n\t/**\n\t * Option to specify the destination to write to.\n\t */\n\tstatic final Option DESTINATION_OPTION = Option.of(\"destination\", \"string\",\n\t\t\t\"Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)\");\n\n\t/**\n\t * Option to ignore non-empty directory error.\n\t */\n\tstatic final Option FORCE_OPTION = Option.flag(\"force\", \"Whether to ignore non-empty directories, extract anyway\");\n\n\tprivate static final Option LIBRARIES_DIRECTORY_OPTION = Option.of(\"libraries\", \"string\",\n\t\t\t\"Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/\");\n\n\tprivate static final Option APPLICATION_FILENAME_OPTION = Option.of(\"application-filename\", \"string\",\n\t\t\t\"Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename\");\n\n\tprivate final Context context;\n\n\tprivate final @Nullable Layers layers;\n\n\tExtractCommand(Context context) {\n\t\tthis(context, null);\n\t}\n\n\tExtractCommand(Context context, @Nullable Layers layers) {\n\t\tsuper(\"extract\", \"Extract the contents from the jar\", Options.of(LAUNCHER_OPTION, LAYERS_OPTION,\n\t\t\t\tDESTINATION_OPTION, LIBRARIES_DIRECTORY_OPTION, APPLICATION_FILENAME_OPTION, FORCE_OPTION),\n\t\t\t\tParameters.none());\n\t\tthis.context = context;\n\t\tthis.layers = layers;\n\t}\n\n\t@Override\n\tvoid run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\t\ttry {\n\t\t\tcheckJarCompatibility();\n\t\t\tFile destination = getDestination(options);\n\t\t\tcheckDirectoryIsEmpty(options, destination);\n\t\t\tFileResolver fileResolver = getFileResolver(destination, options);\n\t\t\tfileResolver.createDirectories();\n\t\t\tif (options.containsKey(LAUNCHER_OPTION)) {\n\t\t\t\textractArchive(fileResolver);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tJarStructure jarStructure = getJarStructure();\n\t\t\t\textractLibraries(fileResolver, jarStructure, options);\n\t\t\t\tcreateApplication(jarStructure, fileResolver, options);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate static void checkDirectoryIsEmpty(Map<Option, @Nullable String> options, File destination) {\n\t\tif (options.containsKey(FORCE_OPTION)) {\n\t\t\treturn;\n\t\t}\n\t\tif (!destination.exists()) {\n\t\t\treturn;\n\t\t}\n\t\tif (!destination.isDirectory()) {\n\t\t\tthrow new JarModeErrorException(destination.getAbsoluteFile() + \" already exists and is not a directory\");\n\t\t}\n\t\tFile[] files = destination.listFiles();\n\t\tif (files != null && files.length > 0) {\n\t\t\tthrow new JarModeErrorException(destination.getAbsoluteFile() + \" already exists and is not empty\");\n\t\t}\n\t}\n\n\tprivate void checkJarCompatibility() throws IOException {\n\t\tFile file = this.context.getArchiveFile();\n\t\ttry (ZipInputStream stream = new ZipInputStream(new FileInputStream(file))) {\n\t\t\tZipEntry entry = stream.getNextEntry();\n\t\t\tif (entry == null) {\n\t\t\t\tthrow new JarModeErrorException(\n\t\t\t\t\t\t\"File '%s' is not compatible; ensure jar file is valid and launch script is not enabled\"\n\t\t\t\t\t\t\t.formatted(file));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void extractLibraries(FileResolver fileResolver, JarStructure jarStructure,\n\t\t\tMap<Option, @Nullable String> options) throws IOException {\n\t\tString librariesDirectory = getLibrariesDirectory(options);\n\t\textractArchive(fileResolver, (jarEntry) -> {\n\t\t\tEntry entry = jarStructure.resolve(jarEntry);\n\t\t\tif (entry != null && entry.type() == Type.LIBRARY) {\n\t\t\t\treturn librariesDirectory + entry.location();\n\t\t\t}\n\t\t\treturn null;\n\t\t});\n\t}\n\n\tprivate static String getLibrariesDirectory(Map<Option, @Nullable String> options) {\n\t\tString libraryDirectory = options.get(LIBRARIES_DIRECTORY_OPTION);\n\t\tif (libraryDirectory != null) {\n\t\t\tif (libraryDirectory.endsWith(\"/\")) {\n\t\t\t\treturn libraryDirectory;\n\t\t\t}\n\t\t\treturn libraryDirectory + \"/\";\n\t\t}\n\t\treturn \"lib/\";\n\t}\n\n\tprivate FileResolver getFileResolver(File destination, Map<Option, @Nullable String> options) {\n\t\tString applicationFilename = getApplicationFilename(options);\n\t\tif (!options.containsKey(LAYERS_OPTION)) {\n\t\t\treturn new NoLayersFileResolver(destination, applicationFilename);\n\t\t}\n\t\tLayers layers = getLayers();\n\t\tSet<String> layersToExtract = StringUtils.commaDelimitedListToSet(options.get(LAYERS_OPTION));\n\t\treturn new LayersFileResolver(destination, layers, layersToExtract, applicationFilename);\n\t}\n\n\tprivate File getDestination(Map<Option, @Nullable String> options) {\n\t\tString value = options.get(DESTINATION_OPTION);\n\t\tif (value != null) {\n\t\t\tFile destination = new File(value);\n\t\t\tif (destination.isAbsolute()) {\n\t\t\t\treturn destination;\n\t\t\t}\n\t\t\treturn new File(this.context.getWorkingDir(), destination.getPath());\n\t\t}\n\t\treturn new File(this.context.getWorkingDir(), stripExtension(this.context.getArchiveFile().getName()));\n\t}\n\n\tprivate static String stripExtension(String name) {\n\t\tif (name.toLowerCase(Locale.ROOT).endsWith(\".jar\") || name.toLowerCase(Locale.ROOT).endsWith(\".war\")) {\n\t\t\treturn name.substring(0, name.length() - 4);\n\t\t}\n\t\treturn name;\n\t}\n\n\tprivate JarStructure getJarStructure() {\n\t\tIndexedJarStructure jarStructure = IndexedJarStructure.get(this.context.getArchiveFile());\n\t\tAssert.state(jarStructure != null, \"Couldn't read classpath index\");\n\t\treturn jarStructure;\n\t}\n\n\tprivate void extractArchive(FileResolver fileResolver) throws IOException {\n\t\textractArchive(fileResolver, JarEntry::getName);\n\t}\n\n\tprivate void extractArchive(FileResolver fileResolver, EntryNameTransformer entryNameTransformer)\n\t\t\tthrows IOException {\n\t\twithJarEntries(this.context.getArchiveFile(), (stream, jarEntry) -> {\n\t\t\tif (jarEntry.isDirectory()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tString name = entryNameTransformer.getName(jarEntry);\n\t\t\tif (name == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tFile file = fileResolver.resolve(jarEntry, name);\n\t\t\tif (file != null) {\n\t\t\t\textractEntry(stream, jarEntry, file);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate Layers getLayers() {\n\t\treturn (this.layers != null) ? this.layers : Layers.get(this.context);\n\t}\n\n\tprivate void createApplication(JarStructure jarStructure, FileResolver fileResolver,\n\t\t\tMap<Option, @Nullable String> options) throws IOException {\n\t\tFile file = fileResolver.resolveApplication();\n\t\tif (file == null) {\n\t\t\treturn;\n\t\t}\n\t\tString librariesDirectory = getLibrariesDirectory(options);\n\t\tManifest manifest = jarStructure.createLauncherManifest((library) -> librariesDirectory + library);\n\t\tmkdirs(file.getParentFile());\n\t\ttry (JarOutputStream output = new JarOutputStream(new FileOutputStream(file))) {\n\t\t\tManfiestWriter manfiestWriter = (sourceJarFile) -> {\n\t\t\t\tJarEntry entry = createJarEntry(JarFile.MANIFEST_NAME,\n\t\t\t\t\t\tsourceJarFile.getJarEntry(JarFile.MANIFEST_NAME));\n\t\t\t\toutput.putNextEntry(entry);\n\t\t\t\tmanifest.write(new BufferedOutputStream(output));\n\t\t\t\toutput.closeEntry();\n\t\t\t};\n\t\t\tEnumSet<Type> allowedTypes = EnumSet.of(Type.APPLICATION_CLASS_OR_RESOURCE, Type.META_INF);\n\t\t\tSet<String> writtenEntries = new HashSet<>();\n\t\t\twithJarEntries(this.context.getArchiveFile(), manfiestWriter, ((stream, jarEntry) -> {\n\t\t\t\tEntry entry = jarStructure.resolve(jarEntry);\n\t\t\t\tif (entry != null && allowedTypes.contains(entry.type()) && StringUtils.hasLength(entry.location())) {\n\t\t\t\t\tJarEntry newJarEntry = createJarEntry(entry.location(), jarEntry);\n\t\t\t\t\tif (writtenEntries.add(newJarEntry.getName())) {\n\t\t\t\t\t\toutput.putNextEntry(newJarEntry);\n\t\t\t\t\t\tStreamUtils.copy(stream, output);\n\t\t\t\t\t\toutput.closeEntry();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (!newJarEntry.isDirectory()) {\n\t\t\t\t\t\t\tthrow new IllegalStateException(\"Duplicate jar entry '%s' from original location '%s'\"\n\t\t\t\t\t\t\t\t.formatted(newJarEntry.getName(), entry.originalLocation()));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\tcopyTimestamps(this.context.getArchiveFile(), file);\n\t}\n\n\tprivate void copyTimestamps(File source, File destination) throws IOException {\n\t\tBasicFileAttributes sourceAttributes = Files.getFileAttributeView(source.toPath(), BasicFileAttributeView.class)\n\t\t\t.readAttributes();\n\t\tFiles.getFileAttributeView(destination.toPath(), BasicFileAttributeView.class)\n\t\t\t.setTimes(sourceAttributes.lastModifiedTime(), sourceAttributes.lastAccessTime(),\n\t\t\t\t\tsourceAttributes.creationTime());\n\t}\n\n\tprivate String getApplicationFilename(Map<Option, @Nullable String> options) {\n\t\tString value = options.get(APPLICATION_FILENAME_OPTION);\n\t\tif (value != null) {\n\t\t\treturn value;\n\t\t}\n\t\treturn this.context.getArchiveFile().getName();\n\t}\n\n\tprivate static void extractEntry(InputStream stream, JarEntry entry, File file) throws IOException {\n\t\tmkdirs(file.getParentFile());\n\t\ttry (OutputStream out = new FileOutputStream(file)) {\n\t\t\tStreamUtils.copy(stream, out);\n\t\t}\n\t\ttry {\n\t\t\tFiles.getFileAttributeView(file.toPath(), BasicFileAttributeView.class)\n\t\t\t\t.setTimes(getLastModifiedTime(entry), getLastAccessTime(entry), getCreationTime(entry));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// File system does not support setting time attributes. Continue.\n\t\t}\n\t}\n\n\tprivate static void mkdirs(File file) throws IOException {\n\t\tif (!file.exists() && !file.mkdirs()) {\n\t\t\tthrow new IOException(\"Unable to create directory \" + file);\n\t\t}\n\t}\n\n\tprivate static JarEntry createJarEntry(String location, JarEntry originalEntry) {\n\t\tJarEntry entry = new JarEntry(location);\n\t\tif (originalEntry != null) {\n\t\t\tcopyFileTime(getLastModifiedTime(originalEntry), entry::setLastModifiedTime);\n\t\t\tcopyFileTime(getLastAccessTime(originalEntry), entry::setLastAccessTime);\n\t\t\tcopyFileTime(getCreationTime(originalEntry), entry::setCreationTime);\n\t\t}\n\t\treturn entry;\n\t}\n\n\tprivate static void copyFileTime(@Nullable FileTime fileTime, Consumer<FileTime> setter) {\n\t\tif (fileTime != null) {\n\t\t\tsetter.accept(fileTime);\n\t\t}\n\t}\n\n\tprivate static @Nullable FileTime getCreationTime(JarEntry entry) {\n\t\treturn (entry.getCreationTime() != null) ? entry.getCreationTime() : entry.getLastModifiedTime();\n\t}\n\n\tprivate static @Nullable FileTime getLastAccessTime(JarEntry entry) {\n\t\treturn (entry.getLastAccessTime() != null) ? entry.getLastAccessTime() : getLastModifiedTime(entry);\n\t}\n\n\tprivate static @Nullable FileTime getLastModifiedTime(JarEntry entry) {\n\t\treturn (entry.getLastModifiedTime() != null) ? entry.getLastModifiedTime() : entry.getCreationTime();\n\t}\n\n\tprivate static void withJarEntries(File file, ThrowingConsumer callback) throws IOException {\n\t\twithJarEntries(file, null, callback);\n\t}\n\n\tprivate static void withJarEntries(File file, @Nullable ManfiestWriter manfiestWriter, ThrowingConsumer callback)\n\t\t\tthrows IOException {\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\tif (manfiestWriter != null) {\n\t\t\t\tmanfiestWriter.writeManifest(jarFile);\n\t\t\t}\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tJarEntry entry = entries.nextElement();\n\t\t\t\tif (StringUtils.hasLength(entry.getName())) {\n\t\t\t\t\ttry (InputStream stream = jarFile.getInputStream(entry)) {\n\t\t\t\t\t\tcallback.accept(stream, entry);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static File assertFileIsContainedInDirectory(File directory, File file, String name) throws IOException {\n\t\tString canonicalOutputPath = directory.getCanonicalPath() + File.separator;\n\t\tString canonicalEntryPath = file.getCanonicalPath();\n\t\tAssert.state(canonicalEntryPath.startsWith(canonicalOutputPath),\n\t\t\t\t() -> \"Entry '%s' would be written to '%s'. This is outside the output location of '%s'. Verify the contents of your archive.\"\n\t\t\t\t\t.formatted(name, canonicalEntryPath, canonicalOutputPath));\n\t\treturn file;\n\t}\n\n\t@FunctionalInterface\n\tprivate interface EntryNameTransformer {\n\n\t\t@Nullable String getName(JarEntry entry);\n\n\t}\n\n\t@FunctionalInterface\n\tprivate interface ManfiestWriter {\n\n\t\tvoid writeManifest(JarFile sourceJarFile) throws IOException;\n\n\t}\n\n\t@FunctionalInterface\n\tprivate interface ThrowingConsumer {\n\n\t\tvoid accept(InputStream stream, JarEntry entry) throws IOException;\n\n\t}\n\n\tprivate interface FileResolver {\n\n\t\t/**\n\t\t * Creates needed directories.\n\t\t * @throws IOException if something went wrong\n\t\t */\n\t\tvoid createDirectories() throws IOException;\n\n\t\t/**\n\t\t * Resolves the given {@link JarEntry} to a file.\n\t\t * @param entry the jar entry\n\t\t * @param newName the new name of the file\n\t\t * @return file where the contents should be written or {@code null} if this entry\n\t\t * should be skipped\n\t\t * @throws IOException if something went wrong\n\t\t */\n\t\tdefault @Nullable File resolve(JarEntry entry, String newName) throws IOException {\n\t\t\treturn resolve(entry.getName(), newName);\n\t\t}\n\n\t\t/**\n\t\t * Resolves the given name to a file.\n\t\t * @param originalName the original name of the file\n\t\t * @param newName the new name of the file\n\t\t * @return file where the contents should be written or {@code null} if this name\n\t\t * should be skipped\n\t\t * @throws IOException if something went wrong\n\t\t */\n\t\t@Nullable File resolve(String originalName, String newName) throws IOException;\n\n\t\t/**\n\t\t * Resolves the file for the application.\n\t\t * @return the file for the application or {@code null} if the application should\n\t\t * be skipped\n\t\t * @throws IOException if something went wrong\n\t\t */\n\t\t@Nullable File resolveApplication() throws IOException;\n\n\t}\n\n\tprivate static final class NoLayersFileResolver implements FileResolver {\n\n\t\tprivate final File directory;\n\n\t\tprivate final String applicationFilename;\n\n\t\tprivate NoLayersFileResolver(File directory, String applicationFilename) {\n\t\t\tthis.directory = directory;\n\t\t\tthis.applicationFilename = applicationFilename;\n\t\t}\n\n\t\t@Override\n\t\tpublic void createDirectories() {\n\t\t}\n\n\t\t@Override\n\t\tpublic File resolve(String originalName, String newName) throws IOException {\n\t\t\treturn assertFileIsContainedInDirectory(this.directory, new File(this.directory, newName), newName);\n\t\t}\n\n\t\t@Override\n\t\tpublic File resolveApplication() throws IOException {\n\t\t\treturn resolve(this.applicationFilename, this.applicationFilename);\n\t\t}\n\n\t}\n\n\tprivate static final class LayersFileResolver implements FileResolver {\n\n\t\tprivate final Layers layers;\n\n\t\tprivate final Set<String> layersToExtract;\n\n\t\tprivate final File directory;\n\n\t\tprivate final String applicationFilename;\n\n\t\tLayersFileResolver(File directory, Layers layers, Set<String> layersToExtract, String applicationFilename) {\n\t\t\tthis.layers = layers;\n\t\t\tthis.layersToExtract = layersToExtract;\n\t\t\tthis.directory = directory;\n\t\t\tthis.applicationFilename = applicationFilename;\n\t\t}\n\n\t\t@Override\n\t\tpublic void createDirectories() throws IOException {\n\t\t\tfor (String layer : this.layers) {\n\t\t\t\tif (shouldExtractLayer(layer)) {\n\t\t\t\t\tmkdirs(getLayerDirectory(layer));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable File resolve(String originalName, String newName) throws IOException {\n\t\t\tString layer = this.layers.getLayer(originalName);\n\t\t\tif (shouldExtractLayer(layer)) {\n\t\t\t\tFile directory = getLayerDirectory(layer);\n\t\t\t\treturn assertFileIsContainedInDirectory(directory, new File(directory, newName), newName);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable File resolveApplication() throws IOException {\n\t\t\tString layer = this.layers.getApplicationLayerName();\n\t\t\tif (shouldExtractLayer(layer)) {\n\t\t\t\tFile directory = getLayerDirectory(layer);\n\t\t\t\treturn assertFileIsContainedInDirectory(directory, new File(directory, this.applicationFilename),\n\t\t\t\t\t\tthis.applicationFilename);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate File getLayerDirectory(String layer) {\n\t\t\treturn new File(this.directory, layer);\n\t\t}\n\n\t\tprivate boolean shouldExtractLayer(String layer) {\n\t\t\treturn this.layersToExtract.isEmpty() || this.layersToExtract.contains(layer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ExtractLayersCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * The {@code 'extract'} tools command.\n *\n * @author Phillip Webb\n */\nclass ExtractLayersCommand extends Command {\n\n\tstatic final Option DESTINATION_OPTION = Option.of(\"destination\", \"string\", \"The destination to extract files to\");\n\n\tprivate final ExtractCommand delegate;\n\n\tExtractLayersCommand(Context context) {\n\t\tthis(context, null);\n\t}\n\n\tExtractLayersCommand(Context context, @Nullable Layers layers) {\n\t\tsuper(\"extract\", \"Extracts layers from the jar for image creation\", Options.of(DESTINATION_OPTION),\n\t\t\t\tParameters.of(\"[<layer>...]\"));\n\t\tthis.delegate = new ExtractCommand(context, layers);\n\t}\n\n\t@Override\n\tboolean isDeprecated() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tString getDeprecationMessage() {\n\t\treturn \"Use '-Djarmode=tools extract --layers --launcher' instead.\";\n\t}\n\n\t@Override\n\tvoid run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\t\tMap<Option, @Nullable String> rewrittenOptions = new HashMap<>();\n\t\trewrittenOptions.put(ExtractCommand.DESTINATION_OPTION, options.getOrDefault(DESTINATION_OPTION, \".\"));\n\t\trewrittenOptions.put(ExtractCommand.LAYERS_OPTION, StringUtils.collectionToCommaDelimitedString(parameters));\n\t\trewrittenOptions.put(ExtractCommand.LAUNCHER_OPTION, null);\n\t\trewrittenOptions.put(ExtractCommand.FORCE_OPTION, null);\n\t\tthis.delegate.run(out, rewrittenOptions, Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/HelpCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Implicit {@code 'help'} command.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass HelpCommand extends Command {\n\n\tprivate final Context context;\n\n\tprivate final List<Command> commands;\n\n\tprivate final String jarMode;\n\n\tHelpCommand(Context context, List<Command> commands) {\n\t\tthis(context, commands, System.getProperty(\"jarmode\"));\n\t}\n\n\tHelpCommand(Context context, List<Command> commands, @Nullable String jarMode) {\n\t\tsuper(\"help\", \"Help about any command\", Options.none(), Parameters.of(\"[<command>]\"));\n\t\tthis.context = context;\n\t\tthis.commands = commands;\n\t\tthis.jarMode = (jarMode != null) ? jarMode : \"tools\";\n\t}\n\n\t@Override\n\tvoid run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\t\trun(out, parameters);\n\t}\n\n\tvoid run(PrintStream out, List<String> parameters) {\n\t\tString commandName = (parameters.isEmpty()) ? null : parameters.get(0);\n\t\tif (commandName == null) {\n\t\t\tprintUsageAndCommands(out);\n\t\t\treturn;\n\t\t}\n\t\tif (getName().equals(commandName)) {\n\t\t\tprintCommandHelp(out, this, true);\n\t\t\treturn;\n\t\t}\n\t\tCommand command = Command.find(this.commands, commandName);\n\t\tif (command == null) {\n\t\t\tprintError(out, \"Unknown command \\\"%s\\\"\".formatted(commandName));\n\t\t\tprintUsageAndCommands(out);\n\t\t\treturn;\n\t\t}\n\t\tprintCommandHelp(out, command, true);\n\t}\n\n\tvoid printCommandHelp(PrintStream out, Command command, boolean printDeprecationWarning) {\n\t\tif (command.isDeprecated() && printDeprecationWarning) {\n\t\t\tprintWarning(out, \"This command is deprecated. \" + command.getDeprecationMessage());\n\t\t}\n\t\tout.println(command.getDescription());\n\t\tout.println();\n\t\tout.println(\"Usage:\");\n\t\tout.println(\"  \" + getJavaCommand() + \" \" + getUsage(command));\n\t\tif (!command.getOptions().isEmpty()) {\n\t\t\tout.println();\n\t\t\tout.println(\"Options:\");\n\t\t\tint maxNameLength = getMaxLength(0, command.getOptions().stream().map(Option::getNameAndValueDescription));\n\t\t\tcommand.getOptions().stream().forEach((option) -> printOptionSummary(out, option, maxNameLength));\n\t\t}\n\t}\n\n\tprivate void printOptionSummary(PrintStream out, Option option, int padding) {\n\t\tout.printf(\"  --%-\" + padding + \"s  %s%n\", option.getNameAndValueDescription(), option.getDescription());\n\t}\n\n\tprivate String getUsage(Command command) {\n\t\tStringBuilder usage = new StringBuilder();\n\t\tusage.append(command.getName());\n\t\tif (!command.getOptions().isEmpty()) {\n\t\t\tusage.append(\" [options]\");\n\t\t}\n\t\tcommand.getParameters().getDescriptions().forEach((param) -> usage.append(\" \").append(param));\n\t\treturn usage.toString();\n\t}\n\n\tprivate void printUsageAndCommands(PrintStream out) {\n\t\tout.println(\"Usage:\");\n\t\tout.println(\"  \" + getJavaCommand());\n\t\tout.println();\n\t\tout.println(\"Available commands:\");\n\t\tint maxNameLength = getMaxLength(getName().length(), this.commands.stream().map(Command::getName));\n\t\tthis.commands.stream()\n\t\t\t.filter((command) -> !command.isDeprecated())\n\t\t\t.forEach((command) -> printCommandSummary(out, command, maxNameLength));\n\t\tprintCommandSummary(out, this, maxNameLength);\n\t\tList<Command> deprecatedCommands = this.commands.stream().filter(Command::isDeprecated).toList();\n\t\tif (!deprecatedCommands.isEmpty()) {\n\t\t\tout.println(\"Deprecated commands:\");\n\t\t\tfor (Command command : deprecatedCommands) {\n\t\t\t\tprintCommandSummary(out, command, maxNameLength);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate int getMaxLength(int minimum, Stream<String> strings) {\n\t\treturn Math.max(minimum, strings.mapToInt(String::length).max().orElse(0));\n\t}\n\n\tprivate void printCommandSummary(PrintStream out, Command command, int padding) {\n\t\tout.printf(\"  %-\" + padding + \"s  %s%n\", command.getName(), command.getDescription());\n\t}\n\n\tprivate String getJavaCommand() {\n\t\treturn \"java -Djarmode=\" + this.jarMode + \" -jar \" + this.context.getArchiveFile().getName();\n\t}\n\n\tprivate void printError(PrintStream out, String errorMessage) {\n\t\tout.println(\"Error: \" + errorMessage);\n\t\tout.println();\n\t}\n\n\tprivate void printWarning(PrintStream out, String errorMessage) {\n\t\tout.println(\"Warning: \" + errorMessage);\n\t\tout.println();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/IndexedJarStructure.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.NoSuchFileException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.UnaryOperator;\nimport java.util.jar.Attributes;\nimport java.util.jar.Attributes.Name;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Collectors;\nimport java.util.zip.ZipEntry;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jarmode.tools.JarStructure.Entry.Type;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link JarStructure} implementation backed by a {@code classpath.idx} file.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass IndexedJarStructure implements JarStructure {\n\n\tprivate static final List<String> MANIFEST_DENY_LIST = List.of(\"Start-Class\", \"Spring-Boot-Classes\",\n\t\t\t\"Spring-Boot-Lib\", \"Spring-Boot-Classpath-Index\", \"Spring-Boot-Layers-Index\");\n\n\tprivate static final Set<String> ENTRY_IGNORE_LIST = Set.of(\"META-INF/\", \"META-INF/MANIFEST.MF\",\n\t\t\t\"META-INF/services/java.nio.file.spi.FileSystemProvider\");\n\n\tprivate final Manifest originalManifest;\n\n\tprivate final String libLocation;\n\n\tprivate final String classesLocation;\n\n\tprivate final List<String> classpathEntries;\n\n\tIndexedJarStructure(Manifest originalManifest, String indexFile) {\n\t\tthis.originalManifest = originalManifest;\n\t\tthis.libLocation = getLocation(originalManifest, \"Spring-Boot-Lib\");\n\t\tthis.classesLocation = getLocation(originalManifest, \"Spring-Boot-Classes\");\n\t\tthis.classpathEntries = readIndexFile(indexFile);\n\t}\n\n\tprivate static String getLocation(Manifest manifest, String attribute) {\n\t\tString location = getMandatoryAttribute(manifest, attribute);\n\t\treturn (!location.endsWith(\"/\")) ? location + \"/\" : location;\n\t}\n\n\tprivate static List<String> readIndexFile(String indexFile) {\n\t\tString[] lines = Arrays.stream(indexFile.split(\"\\n\"))\n\t\t\t.map((line) -> line.replace(\"\\r\", \"\"))\n\t\t\t.filter(StringUtils::hasText)\n\t\t\t.toArray(String[]::new);\n\t\tList<String> classpathEntries = new ArrayList<>();\n\t\tfor (String line : lines) {\n\t\t\tAssert.state(line.startsWith(\"- \"), \"Classpath index file is malformed\");\n\t\t\tclasspathEntries.add(line.substring(3, line.length() - 1));\n\t\t}\n\t\tAssert.state(!classpathEntries.isEmpty(), \"Empty classpath index file loaded\");\n\t\treturn classpathEntries;\n\t}\n\n\t@Override\n\tpublic String getClassesLocation() {\n\t\treturn this.classesLocation;\n\t}\n\n\t@Override\n\tpublic @Nullable Entry resolve(String name) {\n\t\tif (ENTRY_IGNORE_LIST.contains(name)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this.classpathEntries.contains(name)) {\n\t\t\treturn new Entry(name, toStructureDependency(name), Type.LIBRARY);\n\t\t}\n\t\tif (name.startsWith(this.classesLocation)) {\n\t\t\treturn new Entry(name, name.substring(this.classesLocation.length()), Type.APPLICATION_CLASS_OR_RESOURCE);\n\t\t}\n\t\tif (name.startsWith(\"org/springframework/boot/loader\")) {\n\t\t\treturn new Entry(name, name, Type.LOADER);\n\t\t}\n\t\tif (name.startsWith(\"META-INF/\")) {\n\t\t\treturn new Entry(name, name, Type.META_INF);\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Manifest createLauncherManifest(UnaryOperator<String> libraryTransformer) {\n\t\tManifest manifest = new Manifest(this.originalManifest);\n\t\tAttributes attributes = manifest.getMainAttributes();\n\t\tfor (String denied : MANIFEST_DENY_LIST) {\n\t\t\tattributes.remove(new Name(denied));\n\t\t}\n\t\tattributes.put(Name.MAIN_CLASS, getMandatoryAttribute(this.originalManifest, \"Start-Class\"));\n\t\tattributes.put(Name.CLASS_PATH,\n\t\t\t\tthis.classpathEntries.stream()\n\t\t\t\t\t.map(this::toStructureDependency)\n\t\t\t\t\t.map(libraryTransformer)\n\t\t\t\t\t.collect(Collectors.joining(\" \")));\n\t\treturn manifest;\n\t}\n\n\tprivate String toStructureDependency(String libEntryName) {\n\t\tAssert.state(libEntryName.startsWith(this.libLocation), () -> \"Invalid library location \" + libEntryName);\n\t\treturn libEntryName.substring(this.libLocation.length());\n\t}\n\n\tprivate static String getMandatoryAttribute(Manifest manifest, String attribute) {\n\t\tString value = manifest.getMainAttributes().getValue(attribute);\n\t\tAssert.state(value != null, () -> \"Manifest attribute '\" + attribute + \"' is mandatory\");\n\t\treturn value;\n\t}\n\n\tstatic @Nullable IndexedJarStructure get(File file) {\n\t\ttry {\n\t\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\t\tManifest manifest = jarFile.getManifest();\n\t\t\t\tString location = getMandatoryAttribute(manifest, \"Spring-Boot-Classpath-Index\");\n\t\t\t\tZipEntry entry = jarFile.getEntry(location);\n\t\t\t\tif (entry != null) {\n\t\t\t\t\tString indexFile = StreamUtils.copyToString(jarFile.getInputStream(entry), StandardCharsets.UTF_8);\n\t\t\t\t\treturn new IndexedJarStructure(manifest, indexFile);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\tcatch (FileNotFoundException | NoSuchFileException ex) {\n\t\t\treturn null;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/IndexedLayers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.NoSuchFileException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Layers} implementation backed by a {@code layers.idx} file.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\nclass IndexedLayers implements Layers {\n\n\tprivate final Map<String, List<String>> layers = new LinkedHashMap<>();\n\n\tprivate final String indexFileLocation;\n\n\tIndexedLayers(String indexFile, String indexFileLocation) {\n\t\tthis.indexFileLocation = indexFileLocation;\n\t\tString[] lines = Arrays.stream(indexFile.split(\"\\n\"))\n\t\t\t.map((line) -> line.replace(\"\\r\", \"\"))\n\t\t\t.filter(StringUtils::hasText)\n\t\t\t.toArray(String[]::new);\n\t\tList<String> contents = null;\n\t\tfor (String line : lines) {\n\t\t\tif (line.startsWith(\"- \")) {\n\t\t\t\tcontents = new ArrayList<>();\n\t\t\t\tthis.layers.put(line.substring(3, line.length() - 2), contents);\n\t\t\t}\n\t\t\telse if (line.startsWith(\"  - \")) {\n\t\t\t\tAssert.state(contents != null, \"Contents must not be null. Check if the index file is malformed!\");\n\t\t\t\tcontents.add(line.substring(5, line.length() - 1));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalStateException(\"Layer index file is malformed\");\n\t\t\t}\n\t\t}\n\t\tAssert.state(!this.layers.isEmpty(), \"Empty layer index file loaded\");\n\t}\n\n\t@Override\n\tpublic String getApplicationLayerName() {\n\t\treturn getLayer(this.indexFileLocation);\n\t}\n\n\t@Override\n\tpublic Iterator<String> iterator() {\n\t\treturn this.layers.keySet().iterator();\n\t}\n\n\t@Override\n\tpublic String getLayer(String name) {\n\t\tfor (Map.Entry<String, List<String>> entry : this.layers.entrySet()) {\n\t\t\tfor (String candidate : entry.getValue()) {\n\t\t\t\tif (candidate.equals(name) || (candidate.endsWith(\"/\") && name.startsWith(candidate))) {\n\t\t\t\t\treturn entry.getKey();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"No layer defined in index for file '\" + name + \"'\");\n\t}\n\n\t/**\n\t * Get an {@link IndexedLayers} instance of possible.\n\t * @param context the context\n\t * @return an {@link IndexedLayers} instance or {@code null} if this not a layered\n\t * jar.\n\t */\n\tstatic @Nullable IndexedLayers get(Context context) {\n\t\ttry (JarFile jarFile = new JarFile(context.getArchiveFile())) {\n\t\t\tManifest manifest = jarFile.getManifest();\n\t\t\tif (manifest == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tString indexFileLocation = manifest.getMainAttributes().getValue(\"Spring-Boot-Layers-Index\");\n\t\t\tif (indexFileLocation == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tZipEntry entry = jarFile.getEntry(indexFileLocation);\n\t\t\tif (entry == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tString indexFile = StreamUtils.copyToString(jarFile.getInputStream(entry), StandardCharsets.UTF_8);\n\t\t\treturn new IndexedLayers(indexFile, indexFileLocation);\n\t\t}\n\t\tcatch (FileNotFoundException | NoSuchFileException ex) {\n\t\t\treturn null;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/JarStructure.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.util.function.UnaryOperator;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provide information about a fat jar structure that is meant to be extracted.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\ninterface JarStructure {\n\n\t/**\n\t * Resolve the specified {@link ZipEntry}, return {@code null} if the entry should not\n\t * be handled.\n\t * @param entry the entry to handle\n\t * @return the resolved {@link Entry}\n\t */\n\tdefault @Nullable Entry resolve(ZipEntry entry) {\n\t\treturn resolve(entry.getName());\n\t}\n\n\t/**\n\t * Resolve the entry with the specified name, return {@code null} if the entry should\n\t * not be handled.\n\t * @param name the name of the entry to handle\n\t * @return the resolved {@link Entry}\n\t */\n\t@Nullable Entry resolve(String name);\n\n\t/**\n\t * Create the {@link Manifest} for the launcher jar, applying the specified operator\n\t * on each classpath entry.\n\t * @param libraryTransformer the operator to apply on each classpath entry\n\t * @return the manifest to use for the launcher jar\n\t */\n\tManifest createLauncherManifest(UnaryOperator<String> libraryTransformer);\n\n\t/**\n\t * Return the location of the application classes.\n\t * @return the location of the application classes\n\t */\n\tString getClassesLocation();\n\n\t/**\n\t * An entry to handle in the exploded structure.\n\t *\n\t * @param originalLocation the original location\n\t * @param location the relative location\n\t * @param type of the entry\n\t */\n\trecord Entry(String originalLocation, String location, Type type) {\n\n\t\tenum Type {\n\n\t\t\tLIBRARY, APPLICATION_CLASS_OR_RESOURCE, LOADER, META_INF\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Layers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.util.Iterator;\nimport java.util.zip.ZipEntry;\n\nimport org.springframework.boot.loader.jarmode.JarModeErrorException;\n\n/**\n * Provides information about the jar layers.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @see ExtractCommand\n * @see ListCommand\n */\ninterface Layers extends Iterable<String> {\n\n\t/**\n\t * Return the jar layers in the order that they should be added (starting with the\n\t * least frequently changed layer).\n\t */\n\t@Override\n\tIterator<String> iterator();\n\n\t/**\n\t * Return the layer that a given entry is in.\n\t * @param entry the entry to check\n\t * @return the layer that the entry is in\n\t */\n\tdefault String getLayer(ZipEntry entry) {\n\t\treturn getLayer(entry.getName());\n\t}\n\n\t/**\n\t * Return the layer that the entry with the given name is in.\n\t * @param entryName the name of the entry to check\n\t * @return the layer that the entry is in\n\t */\n\tString getLayer(String entryName);\n\n\t/**\n\t * Return the name of the application layer.\n\t * @return the name of the application layer\n\t */\n\tString getApplicationLayerName();\n\n\t/**\n\t * Return a {@link Layers} instance for the currently running application.\n\t * @param context the command context\n\t * @return a new layers instance\n\t */\n\tstatic Layers get(Context context) {\n\t\tIndexedLayers indexedLayers = IndexedLayers.get(context);\n\t\tif (indexedLayers == null) {\n\t\t\tthrow new JarModeErrorException(\"Layers are not enabled\");\n\t\t}\n\t\treturn indexedLayers;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ListCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * The {@code 'list'} tools command.\n *\n * Delegates the actual work to {@link ListLayersCommand}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass ListCommand extends Command {\n\n\tprivate final ListLayersCommand delegate;\n\n\tListCommand(Context context) {\n\t\tsuper(\"list\", \"List layers from the jar that can be extracted\", Options.none(), Parameters.none());\n\t\tthis.delegate = new ListLayersCommand(context);\n\t}\n\n\t@Override\n\tboolean isDeprecated() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tString getDeprecationMessage() {\n\t\treturn \"Use '-Djarmode=tools list-layers' instead.\";\n\t}\n\n\t@Override\n\tvoid run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\t\tthis.delegate.run(out, options, parameters);\n\t}\n\n\tvoid printLayers(Layers layers, PrintStream out) {\n\t\tthis.delegate.printLayers(out, layers);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ListLayersCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * The {@code 'list-layers'} tools command.\n *\n * @author Moritz Halbritter\n */\nclass ListLayersCommand extends Command {\n\n\tprivate final Context context;\n\n\tListLayersCommand(Context context) {\n\t\tsuper(\"list-layers\", \"List layers from the jar that can be extracted\", Options.none(), Parameters.none());\n\t\tthis.context = context;\n\t}\n\n\t@Override\n\tvoid run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\t\tLayers layers = Layers.get(this.context);\n\t\tprintLayers(out, layers);\n\t}\n\n\tvoid printLayers(PrintStream out, Layers layers) {\n\t\tlayers.forEach(out::println);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/MissingValueException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\n/**\n * Exception thrown when a required value is not provided for an option.\n *\n * @author Scott Frederick\n */\nclass MissingValueException extends RuntimeException {\n\n\tprivate final String optionName;\n\n\tMissingValueException(String optionName) {\n\t\tthis.optionName = optionName;\n\t}\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn \"--\" + this.optionName;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/Runner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Deque;\nimport java.util.List;\n\n/**\n * Runs commands.\n *\n * @author Moritz Halbritter\n */\nclass Runner {\n\n\tprivate final PrintStream out;\n\n\tprivate final List<Command> commands = new ArrayList<>();\n\n\tprivate final HelpCommand help;\n\n\tRunner(PrintStream out, Context context, List<Command> commands) {\n\t\tthis.out = out;\n\t\tthis.commands.addAll(commands);\n\t\tthis.help = new HelpCommand(context, commands);\n\t\tthis.commands.add(this.help);\n\t}\n\n\tvoid run(String... args) {\n\t\trun(dequeOf(args));\n\t}\n\n\tprivate void run(Deque<String> args) {\n\t\tif (!args.isEmpty()) {\n\t\t\tString commandName = args.removeFirst();\n\t\t\tCommand command = Command.find(this.commands, commandName);\n\t\t\tif (command != null) {\n\t\t\t\trunCommand(command, args);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprintError(\"Unknown command \\\"\" + commandName + \"\\\"\");\n\t\t}\n\t\tthis.help.run(this.out, args);\n\t}\n\n\tprivate void runCommand(Command command, Deque<String> args) {\n\t\tif (command.isDeprecated()) {\n\t\t\tprintWarning(\"This command is deprecated. \" + command.getDeprecationMessage());\n\t\t}\n\t\ttry {\n\t\t\tcommand.run(this.out, args);\n\t\t}\n\t\tcatch (UnknownOptionException ex) {\n\t\t\tprintError(\"Unknown option \\\"\" + ex.getMessage() + \"\\\" for the \" + command.getName() + \" command\");\n\t\t\tthis.help.printCommandHelp(this.out, command, false);\n\t\t}\n\t\tcatch (MissingValueException ex) {\n\t\t\tprintError(\"Option \\\"\" + ex.getMessage() + \"\\\" for the \" + command.getName() + \" command requires a value\");\n\t\t\tthis.help.printCommandHelp(this.out, command, false);\n\t\t}\n\t}\n\n\tprivate void printWarning(String message) {\n\t\tthis.out.println(\"Warning: \" + message);\n\t\tthis.out.println();\n\t}\n\n\tprivate void printError(String message) {\n\t\tthis.out.println(\"Error: \" + message);\n\t\tthis.out.println();\n\t}\n\n\tprivate Deque<String> dequeOf(String... args) {\n\t\treturn new ArrayDeque<>(Arrays.asList(args));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/ToolsJarMode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.jarmode.JarMode;\n\n/**\n * {@link JarMode} providing {@code \"tools\"} support.\n *\n * @author Moritz Halbritter\n * @since 3.3.0\n */\npublic class ToolsJarMode implements JarMode {\n\n\tprivate final Context context;\n\n\tprivate final PrintStream out;\n\n\tpublic ToolsJarMode() {\n\t\tthis(null, null);\n\t}\n\n\tpublic ToolsJarMode(@Nullable Context context, @Nullable PrintStream out) {\n\t\tthis.context = (context != null) ? context : new Context();\n\t\tthis.out = (out != null) ? out : System.out;\n\t}\n\n\t@Override\n\tpublic boolean accepts(String mode) {\n\t\treturn \"tools\".equalsIgnoreCase(mode);\n\t}\n\n\t@Override\n\tpublic void run(String mode, String[] args) {\n\t\ttry {\n\t\t\tnew Runner(this.out, this.context, getCommands(this.context)).run(args);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tstatic List<Command> getCommands(Context context) {\n\t\treturn List.of(new ExtractCommand(context), new ListLayersCommand(context));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/UnknownOptionException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\n/**\n * Exception thrown when an unrecognized option is encountered.\n *\n * @author Scott Frederick\n */\nclass UnknownOptionException extends RuntimeException {\n\n\tprivate final String optionName;\n\n\tUnknownOptionException(String optionName) {\n\t\tthis.optionName = optionName;\n\t}\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn \"--\" + this.optionName;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/java/org/springframework/boot/jarmode/tools/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * JarMode support for application tools.\n */\n@NullMarked\npackage org.springframework.boot.jarmode.tools;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/main/resources/META-INF/spring.factories",
    "content": "# Jar Modes\norg.springframework.boot.loader.jarmode.JarMode=\\\norg.springframework.boot.jarmode.tools.ToolsJarMode\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/AbstractJarModeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.BasicFileAttributeView;\nimport java.nio.file.attribute.FileTime;\nimport java.time.Instant;\nimport java.util.ArrayDeque;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.stream.Stream;\nimport java.util.zip.ZipEntry;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for jar mode tests.\n *\n * @author Moritz Halbritter\n */\nabstract class AbstractJarModeTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\tManifest createManifest(String... entries) {\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(\"Manifest-Version\", \"1.0\");\n\t\tfor (String entry : entries) {\n\t\t\tint colon = entry.indexOf(':');\n\t\t\tAssert.state(colon > -1, () -> \"Colon not found in %s\".formatted(entry));\n\t\t\tString key = entry.substring(0, colon).trim();\n\t\t\tString value = entry.substring(colon + 1).trim();\n\t\t\tmanifest.getMainAttributes().putValue(key, value);\n\t\t}\n\t\treturn manifest;\n\t}\n\n\tFile createArchive(String... entries) throws IOException {\n\t\treturn createArchive(createManifest(), entries);\n\t}\n\n\tFile createArchive(Manifest manifest, String... entries) throws IOException {\n\t\treturn createArchive(manifest, null, null, null, entries);\n\t}\n\n\tFile createArchive(Manifest manifest, @Nullable Instant creationTime, @Nullable Instant lastModifiedTime,\n\t\t\t@Nullable Instant lastAccessTime, String... entries) throws IOException {\n\t\tAssert.state(entries.length % 2 == 0, \"Entries must be key value pairs\");\n\t\tFile file = new File(this.tempDir, \"test.jar\");\n\t\ttry (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {\n\t\t\tZipEntry manifestEntry = createEntry(JarFile.MANIFEST_NAME, creationTime, lastModifiedTime, lastAccessTime);\n\t\t\tjar.putNextEntry(manifestEntry);\n\t\t\tmanifest.write(new BufferedOutputStream(jar));\n\t\t\tjar.closeEntry();\n\t\t\tfor (int i = 0; i < entries.length; i += 2) {\n\t\t\t\tZipEntry entry = createEntry(entries[i], creationTime, lastModifiedTime, lastAccessTime);\n\t\t\t\tjar.putNextEntry(entry);\n\t\t\t\tString resource = entries[i + 1];\n\t\t\t\tif (resource != null) {\n\t\t\t\t\ttry (InputStream content = ListLayersCommandTests.class.getResourceAsStream(resource)) {\n\t\t\t\t\t\tassertThat(content).as(\"Resource \" + resource).isNotNull();\n\t\t\t\t\t\tStreamUtils.copy(content, jar);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tjar.closeEntry();\n\t\t\t}\n\t\t}\n\t\tFiles.getFileAttributeView(file.toPath(), BasicFileAttributeView.class)\n\t\t\t.setTimes(asFileTime(lastModifiedTime), asFileTime(lastAccessTime), asFileTime(creationTime));\n\t\treturn file;\n\t}\n\n\tprivate @Nullable FileTime asFileTime(@Nullable Instant instant) {\n\t\treturn (instant != null) ? FileTime.from(instant) : null;\n\t}\n\n\tprivate ZipEntry createEntry(String name, @Nullable Instant creationTime, @Nullable Instant lastModifiedTime,\n\t\t\t@Nullable Instant lastAccessTime) {\n\t\tZipEntry entry = new ZipEntry(name);\n\t\tif (creationTime != null) {\n\t\t\tentry.setCreationTime(FileTime.from(creationTime));\n\t\t}\n\t\tif (lastModifiedTime != null) {\n\t\t\tentry.setLastModifiedTime(FileTime.from(lastModifiedTime));\n\t\t}\n\t\tif (lastAccessTime != null) {\n\t\t\tentry.setLastAccessTime(FileTime.from(lastAccessTime));\n\t\t}\n\t\treturn entry;\n\t}\n\n\tTestPrintStream runCommand(CommandFactory<?> commandFactory, File archive, String... arguments) {\n\t\tContext context = new Context(archive, this.tempDir);\n\t\tCommand command = commandFactory.create(context);\n\t\tTestPrintStream out = new TestPrintStream(this);\n\t\tcommand.run(out, new ArrayDeque<>(Arrays.asList(arguments)));\n\t\treturn out;\n\t}\n\n\tManifest getJarManifest(File jar) throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(jar)) {\n\t\t\treturn jarFile.getManifest();\n\t\t}\n\t}\n\n\tMap<String, String> getJarManifestAttributes(File jar) throws IOException {\n\t\tassertThat(jar).exists();\n\t\tManifest manifest = getJarManifest(jar);\n\t\tMap<String, String> result = new HashMap<>();\n\t\tmanifest.getMainAttributes().forEach((key, value) -> result.put(key.toString(), value.toString()));\n\t\treturn result;\n\t}\n\n\tList<String> getJarEntryNames(File jar) throws IOException {\n\t\tassertThat(jar).exists();\n\t\ttry (JarFile jarFile = new JarFile(jar)) {\n\t\t\treturn jarFile.stream().map(ZipEntry::getName).toList();\n\t\t}\n\t}\n\n\tList<String> listFilenames() throws IOException {\n\t\treturn listFilenames(this.tempDir);\n\t}\n\n\tList<String> listFilenames(File directory) throws IOException {\n\t\ttry (Stream<Path> stream = Files.walk(directory.toPath())) {\n\t\t\tint substring = directory.getAbsolutePath().length() + 1;\n\t\t\treturn stream.map((file) -> file.toAbsolutePath().toString())\n\t\t\t\t.map((file) -> (file.length() >= substring) ? file.substring(substring) : \"\")\n\t\t\t\t.filter(StringUtils::hasLength)\n\t\t\t\t.map((file) -> file.replace(File.separatorChar, '/'))\n\t\t\t\t.toList();\n\t\t}\n\t}\n\n\tinterface CommandFactory<T extends Command> {\n\n\t\tT create(Context context);\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/CommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.ArrayDeque;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jarmode.tools.Command.Option;\nimport org.springframework.boot.jarmode.tools.Command.Options;\nimport org.springframework.boot.jarmode.tools.Command.Parameters;\n\nimport static org.assertj.core.api.Assertions.as;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link Command}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass CommandTests {\n\n\tprivate static final Option VERBOSE_FLAG = Option.flag(\"verbose\", \"Verbose output\");\n\n\tprivate static final Option LOG_LEVEL_OPTION = Option.of(\"log-level\", \"Logging level (debug or info)\", \"string\");\n\n\tprivate static final Option LAYERS_OPTION = Option.of(\"layers\", \"Layers (leave empty for all)\", \"string list\",\n\t\t\ttrue);\n\n\t@Test\n\tvoid getNameReturnsName() {\n\t\tTestCommand command = new TestCommand(\"test\");\n\t\tassertThat(command.getName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getDescriptionReturnsDescription() {\n\t\tTestCommand command = new TestCommand(\"test\", \"Test description\", Options.none(), Parameters.none());\n\t\tassertThat(command.getDescription()).isEqualTo(\"Test description\");\n\t}\n\n\t@Test\n\tvoid getOptionsReturnsOptions() {\n\t\tOptions options = Options.of(LOG_LEVEL_OPTION);\n\t\tTestCommand command = new TestCommand(\"test\", \"test\", options, Parameters.none());\n\t\tassertThat(command.getOptions()).isEqualTo(options);\n\t}\n\n\t@Test\n\tvoid getParametersReturnsParameters() {\n\t\tParameters parameters = Parameters.of(\"[<param>]\");\n\t\tTestCommand command = new TestCommand(\"test\", \"test\", Options.none(), parameters);\n\t\tassertThat(command.getParameters()).isEqualTo(parameters);\n\t}\n\n\t@Test\n\tvoid runWithOptionsAndParametersParsesOptionsAndParameters() {\n\t\tTestCommand command = new TestCommand(\"test\", VERBOSE_FLAG, LOG_LEVEL_OPTION);\n\t\trun(command, \"--verbose\", \"--log-level\", \"test1\", \"test2\", \"test3\");\n\t\tassertThat(command.getRunOptions()).containsEntry(VERBOSE_FLAG, null);\n\t\tassertThat(command.getRunOptions()).containsEntry(LOG_LEVEL_OPTION, \"test1\");\n\t\tassertThat(command.getRunParameters()).containsExactly(\"test2\", \"test3\");\n\t}\n\n\t@Test\n\tvoid runWithUnknownOptionThrowsException() {\n\t\tTestCommand command = new TestCommand(\"test\", VERBOSE_FLAG, LOG_LEVEL_OPTION);\n\t\tassertThatExceptionOfType(UnknownOptionException.class).isThrownBy(() -> run(command, \"--invalid\"))\n\t\t\t.withMessage(\"--invalid\");\n\t}\n\n\t@Test\n\tvoid runWithOptionMissingRequiredValueThrowsException() {\n\t\tTestCommand command = new TestCommand(\"test\", VERBOSE_FLAG, LOG_LEVEL_OPTION);\n\t\tassertThatExceptionOfType(MissingValueException.class)\n\t\t\t.isThrownBy(() -> run(command, \"--verbose\", \"--log-level\"))\n\t\t\t.withMessage(\"--log-level\");\n\t}\n\n\t@Test\n\tvoid findWhenNameMatchesReturnsCommand() {\n\t\tTestCommand test1 = new TestCommand(\"test1\");\n\t\tTestCommand test2 = new TestCommand(\"test2\");\n\t\tList<Command> commands = Arrays.asList(test1, test2);\n\t\tassertThat(Command.find(commands, \"test1\")).isEqualTo(test1);\n\t\tassertThat(Command.find(commands, \"test2\")).isEqualTo(test2);\n\t}\n\n\t@Test\n\tvoid findWhenNameDoesNotMatchReturnsNull() {\n\t\tTestCommand test1 = new TestCommand(\"test1\");\n\t\tTestCommand test2 = new TestCommand(\"test2\");\n\t\tList<Command> commands = Arrays.asList(test1, test2);\n\t\tassertThat(Command.find(commands, \"test3\")).isNull();\n\t}\n\n\t@Test\n\tvoid parametersOfCreatesParametersInstance() {\n\t\tParameters parameters = Parameters.of(\"test1\", \"test2\");\n\t\tassertThat(parameters.getDescriptions()).containsExactly(\"test1\", \"test2\");\n\t}\n\n\t@Test\n\tvoid optionsNoneReturnsEmptyOptions() {\n\t\tOptions options = Options.none();\n\t\tassertThat(options).extracting(\"values\", as(InstanceOfAssertFactories.ARRAY)).isEmpty();\n\t}\n\n\t@Test\n\tvoid optionsOfReturnsOptions() {\n\t\tOption option = Option.of(\"test\", \"value description\", \"description\");\n\t\tOptions options = Options.of(option);\n\t\tassertThat(options).extracting(\"values\", as(InstanceOfAssertFactories.ARRAY)).containsExactly(option);\n\t}\n\n\t@Test\n\tvoid optionFlagCreatesFlagOption() {\n\t\tOption option = Option.flag(\"test\", \"description\");\n\t\tassertThat(option.getName()).isEqualTo(\"test\");\n\t\tassertThat(option.getDescription()).isEqualTo(\"description\");\n\t\tassertThat(option.getValueDescription()).isNull();\n\t}\n\n\t@Test\n\tvoid optionOfCreatesValueOption() {\n\t\tOption option = Option.of(\"test\", \"value description\", \"description\");\n\t\tassertThat(option.getName()).isEqualTo(\"test\");\n\t\tassertThat(option.getDescription()).isEqualTo(\"description\");\n\t\tassertThat(option.getValueDescription()).isEqualTo(\"value description\");\n\t}\n\n\t@Test\n\tvoid shouldNotParseFollowingOptionAsValue() {\n\t\tTestCommand command = new TestCommand(\"test\", LAYERS_OPTION, LOG_LEVEL_OPTION);\n\t\trun(command, \"--layers\", \"--log-level\", \"debug\");\n\t\tassertThat(command.getRunOptions()).containsEntry(LAYERS_OPTION, null);\n\t\tassertThat(command.getRunOptions()).containsEntry(LOG_LEVEL_OPTION, \"debug\");\n\t}\n\n\tprivate void run(TestCommand command, String... args) {\n\t\tcommand.run(System.out, new ArrayDeque<>(Arrays.asList(args)));\n\t}\n\n\tstatic class TestCommand extends Command {\n\n\t\tprivate @Nullable Map<Option, @Nullable String> runOptions;\n\n\t\tprivate @Nullable List<String> runParameters;\n\n\t\tTestCommand(String name, Option... options) {\n\t\t\tthis(name, \"test\", Options.of(options), Parameters.none());\n\t\t}\n\n\t\tTestCommand(String name, String description, Options options, Parameters parameters) {\n\t\t\tsuper(name, description, options, parameters);\n\t\t}\n\n\t\t@Override\n\t\tprotected void run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\t\t\tthis.runOptions = options;\n\t\t\tthis.runParameters = parameters;\n\t\t}\n\n\t\t@Nullable Map<Option, @Nullable String> getRunOptions() {\n\t\t\treturn this.runOptions;\n\t\t}\n\n\t\t@Nullable List<String> getRunParameters() {\n\t\t\treturn this.runParameters;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Context}.\n *\n * @author Phillip Webb\n */\nclass ContextTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSourceIsNullThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new Context(null, this.temp))\n\t\t\t.withMessage(\"Unable to find source archive\");\n\t}\n\n\t@Test\n\tvoid createWhenSourceIsDirectoryThrowsException() {\n\t\tFile directory = new File(this.temp, \"test\");\n\t\tdirectory.mkdir();\n\t\tassertThatIllegalStateException().isThrownBy(() -> new Context(directory, this.temp))\n\t\t\t.withMessage(\"Unable to find source archive\");\n\t}\n\n\t@Test\n\tvoid createWhenSourceIsNotJarOrWarThrowsException() throws Exception {\n\t\tFile zip = new File(this.temp, \"test.zip\");\n\t\tFiles.createFile(zip.toPath());\n\t\tassertThatIllegalStateException().isThrownBy(() -> new Context(zip, this.temp))\n\t\t\t.withMessageContaining(\"test.zip must end with .jar or .war\");\n\t}\n\n\t@Test\n\tvoid getJarFileReturnsJar() throws Exception {\n\t\tFile jar = new File(this.temp, \"test.jar\");\n\t\tFiles.createFile(jar.toPath());\n\t\tContext context = new Context(jar, this.temp);\n\t\tassertThat(context.getArchiveFile()).isEqualTo(jar);\n\t}\n\n\t@Test\n\tvoid getWorkingDirectoryReturnsWorkingDir() throws IOException {\n\t\tFile jar = new File(this.temp, \"test.jar\");\n\t\tFiles.createFile(jar.toPath());\n\t\tContext context = new Context(jar, this.temp);\n\t\tassertThat(context.getWorkingDir()).isEqualTo(this.temp);\n\n\t}\n\n\t@Test\n\tvoid getRelativePathReturnsRelativePath() throws Exception {\n\t\tFile target = new File(this.temp, \"target\");\n\t\ttarget.mkdir();\n\t\tFile jar = new File(target, \"test.jar\");\n\t\tFiles.createFile(jar.toPath());\n\t\tContext context = new Context(jar, this.temp);\n\t\tassertThat(context.getRelativeArchiveDir()).isEqualTo(\"target\");\n\t}\n\n\t@Test\n\tvoid getRelativePathWhenWorkingDirReturnsNull() throws Exception {\n\t\tFile jar = new File(this.temp, \"test.jar\");\n\t\tFiles.createFile(jar.toPath());\n\t\tContext context = new Context(jar, this.temp);\n\t\tassertThat(context.getRelativeArchiveDir()).isNull();\n\t}\n\n\t@Test\n\tvoid getRelativePathWhenCannotBeDeducedReturnsNull() throws Exception {\n\t\tFile directory1 = new File(this.temp, \"directory1\");\n\t\tdirectory1.mkdir();\n\t\tFile directory2 = new File(this.temp, \"directory2\");\n\t\tdirectory2.mkdir();\n\t\tFile jar = new File(directory1, \"test.jar\");\n\t\tFiles.createFile(jar.toPath());\n\t\tContext context = new Context(jar, directory2);\n\t\tassertThat(context.getRelativeArchiveDir()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.attribute.BasicFileAttributeView;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.jarmode.JarModeErrorException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ExtractCommand}.\n *\n * @author Moritz Halbritter\n */\nclass ExtractCommandTests extends AbstractJarModeTests {\n\n\tprivate static final Instant CREATION_TIME = Instant.parse(\"2020-01-01T00:00:00Z\");\n\n\tprivate static final Instant LAST_MODIFIED_TIME = Instant.parse(\"2021-01-01T00:00:00Z\");\n\n\tprivate static final Instant LAST_ACCESS_TIME = Instant.parse(\"2022-01-01T00:00:00Z\");\n\n\tprivate Manifest manifest;\n\n\tprivate File archive;\n\n\t@BeforeEach\n\tvoid setUp() throws IOException {\n\t\tthis.manifest = createManifest(\"Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx\",\n\t\t\t\t\"Spring-Boot-Lib: BOOT-INF/lib/\", \"Spring-Boot-Classes: BOOT-INF/classes/\",\n\t\t\t\t\"Start-Class: org.example.Main\", \"Spring-Boot-Layers-Index: BOOT-INF/layers.idx\",\n\t\t\t\t\"Some-Attribute: Some-Value\");\n\t\tthis.archive = createArchive(this.manifest, CREATION_TIME, LAST_MODIFIED_TIME, LAST_ACCESS_TIME,\n\t\t\t\t\"BOOT-INF/classpath.idx\", \"/jar-contents/classpath.idx\", \"BOOT-INF/layers.idx\",\n\t\t\t\t\"/jar-contents/layers.idx\", \"BOOT-INF/lib/dependency-1.jar\", \"/jar-contents/dependency-1\",\n\t\t\t\t\"BOOT-INF/lib/dependency-2.jar\", \"/jar-contents/dependency-2\", \"BOOT-INF/lib/dependency-3-SNAPSHOT.jar\",\n\t\t\t\t\"/jar-contents/dependency-3-SNAPSHOT\", \"org/springframework/boot/loader/launch/JarLauncher.class\",\n\t\t\t\t\"/jar-contents/JarLauncher\", \"BOOT-INF/classes/application.properties\",\n\t\t\t\t\"/jar-contents/application.properties\", \"META-INF/build-info.properties\",\n\t\t\t\t\"/jar-contents/build-info.properties\");\n\t}\n\n\tprivate File file(String name) {\n\t\treturn new File(this.tempDir, name);\n\t}\n\n\tprivate TestPrintStream run(File archive, String... args) {\n\t\treturn runCommand(ExtractCommand::new, archive, args);\n\t}\n\n\t@Nested\n\tclass Extract {\n\n\t\t@Test\n\t\tvoid extractLibrariesAndCreatesApplication() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive);\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"test/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"test/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"test/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"test/test.jar\")\n\t\t\t\t.doesNotContain(\"test/org/springframework/boot/loader/launch/JarLauncher.class\");\n\t\t}\n\n\t\t@Test\n\t\tvoid extractLibrariesAndCreatesApplicationInDestination() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--destination\", file(\"out\").getAbsolutePath());\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"out/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"out/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"out/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"out/test.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid applicationNameAndLibrariesDirectoriesCanBeCustomized() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--application-filename\", \"application-customized.jar\", \"--libraries\",\n\t\t\t\t\t\"dependencies\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"test/dependencies/dependency-1.jar\")\n\t\t\t\t.contains(\"test/dependencies/dependency-2.jar\")\n\t\t\t\t.contains(\"test/dependencies/dependency-3-SNAPSHOT.jar\");\n\t\t\tFile application = file(\"test/application-customized.jar\");\n\t\t\tassertThat(application).exists();\n\t\t\tMap<String, String> attributes = getJarManifestAttributes(application);\n\t\t\tassertThat(attributes).containsEntry(\"Class-Path\",\n\t\t\t\t\t\"dependencies/dependency-1.jar dependencies/dependency-2.jar dependencies/dependency-3-SNAPSHOT.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid applicationContainsManifestEntries() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive);\n\t\t\tFile application = file(\"test/test.jar\");\n\t\t\tMap<String, String> attributes = getJarManifestAttributes(application);\n\t\t\tassertThat(attributes).containsEntry(\"Main-Class\", \"org.example.Main\")\n\t\t\t\t.containsEntry(\"Class-Path\", \"lib/dependency-1.jar lib/dependency-2.jar lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.containsEntry(\"Some-Attribute\", \"Some-Value\")\n\t\t\t\t.doesNotContainKeys(\"Start-Class\", \"Spring-Boot-Classes\", \"Spring-Boot-Lib\",\n\t\t\t\t\t\t\"Spring-Boot-Classpath-Index\", \"Spring-Boot-Layers-Index\");\n\t\t}\n\n\t\t@Test\n\t\tvoid applicationContainsApplicationClassesAndResources() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive);\n\t\t\tFile application = file(\"test/test.jar\");\n\t\t\tList<String> entryNames = getJarEntryNames(application);\n\t\t\tassertThat(entryNames).contains(\"application.properties\");\n\t\t}\n\n\t\t@Test\n\t\tvoid appliesFileTimes() {\n\t\t\trun(ExtractCommandTests.this.archive);\n\t\t\tassertThat(file(\"test/lib/dependency-1.jar\")).exists().satisfies(this::fileTimeAttributes);\n\t\t\tassertThat(file(\"test/lib/dependency-2.jar\")).exists().satisfies(this::fileTimeAttributes);\n\t\t\tassertThat(file(\"test/lib/dependency-3-SNAPSHOT.jar\")).exists().satisfies(this::fileTimeAttributes);\n\t\t\tassertThat(file(\"test/test.jar\")).exists()\n\t\t\t\t.satisfies(this::fileTimeAttributes)\n\t\t\t\t.satisfies(this::entryTimeAttributes);\n\t\t}\n\n\t\tprivate void fileTimeAttributes(File file) {\n\t\t\ttry {\n\t\t\t\tBasicFileAttributes basicAttributes = Files\n\t\t\t\t\t.getFileAttributeView(file.toPath(), BasicFileAttributeView.class)\n\t\t\t\t\t.readAttributes();\n\t\t\t\tassertThat(basicAttributes.lastModifiedTime().toInstant().truncatedTo(ChronoUnit.SECONDS))\n\t\t\t\t\t.as(\"last modified time\")\n\t\t\t\t\t.isEqualTo(LAST_MODIFIED_TIME.truncatedTo(ChronoUnit.SECONDS));\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate void entryTimeAttributes(File file) {\n\t\t\ttry {\n\t\t\t\ttry (ZipFile archiveZipFile = new ZipFile(ExtractCommandTests.this.archive)) {\n\t\t\t\t\ttry (ZipFile zipFile = new ZipFile(file)) {\n\t\t\t\t\t\tEnumeration<? extends ZipEntry> entries = zipFile.entries();\n\t\t\t\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\t\t\t\tZipEntry entry = entries.nextElement();\n\t\t\t\t\t\t\tZipEntry archiveEntry = archiveZipFile.getEntry(entry.getName());\n\t\t\t\t\t\t\tif (archiveEntry != null) {\n\t\t\t\t\t\t\t\tassertThat(entry.getLastModifiedTime()).isEqualTo(archiveEntry.getLastModifiedTime());\n\t\t\t\t\t\t\t\tassertThat(entry.getLastAccessTime()).isEqualTo(archiveEntry.getLastAccessTime());\n\t\t\t\t\t\t\t\tassertThat(entry.getCreationTime()).isEqualTo(archiveEntry.getCreationTime());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Test\n\t\tvoid applicationDoesntContainLibraries() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive);\n\t\t\tFile application = file(\"test/test.jar\");\n\t\t\tList<String> entryNames = getJarEntryNames(application);\n\t\t\tassertThat(entryNames).doesNotContain(\"BOOT-INF/lib/dependency-1.jar\", \"BOOT-INF/lib/dependency-2.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid failsOnIncompatibleJar() throws IOException {\n\t\t\tFile file = file(\"empty.jar\");\n\t\t\ttry (FileWriter writer = new FileWriter(file)) {\n\t\t\t\twriter.write(\"text\");\n\t\t\t}\n\t\t\tassertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(file))\n\t\t\t\t.withMessageContaining(\"is not compatible; ensure jar file is valid and launch script is not enabled\");\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldFailIfDirectoryIsNotEmpty() throws IOException {\n\t\t\tFile destination = file(\"out\");\n\t\t\tFiles.createDirectories(destination.toPath());\n\t\t\tFiles.createFile(new File(destination, \"file.txt\").toPath());\n\t\t\tassertThatExceptionOfType(JarModeErrorException.class)\n\t\t\t\t.isThrownBy(() -> run(ExtractCommandTests.this.archive, \"--destination\", destination.getAbsolutePath()))\n\t\t\t\t.withMessageContaining(\"already exists and is not empty\");\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldNotFailIfDirectoryExistsButIsEmpty() throws IOException {\n\t\t\tFile destination = file(\"out\");\n\t\t\tFiles.createDirectories(destination.toPath());\n\t\t\trun(ExtractCommandTests.this.archive, \"--destination\", destination.getAbsolutePath());\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"out/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"out/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"out/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"out/test.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldNotFailIfDirectoryIsNotEmptyButForceIsPassed() throws IOException {\n\t\t\tFile destination = file(\"out\");\n\t\t\tFiles.createDirectories(destination.toPath());\n\t\t\tFiles.createFile(new File(destination, \"file.txt\").toPath());\n\t\t\trun(ExtractCommandTests.this.archive, \"--destination\", destination.getAbsolutePath(), \"--force\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"out/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"out/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"out/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"out/test.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldExtractFilesUnderMetaInf() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive);\n\t\t\tFile application = file(\"test/test.jar\");\n\t\t\tList<String> entryNames = getJarEntryNames(application);\n\t\t\tassertThat(entryNames).contains(\"META-INF/build-info.properties\");\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldNotFailOnDuplicateDirectories() throws IOException {\n\t\t\tFile file = createArchive(ExtractCommandTests.this.manifest, \"BOOT-INF/classpath.idx\",\n\t\t\t\t\t\"/jar-contents/classpath.idx\", \"META-INF/native-image/\", \"/jar-contents/empty-file\",\n\t\t\t\t\t\"BOOT-INF/classes/META-INF/native-image/\", \"/jar-contents/empty-file\");\n\t\t\trun(file);\n\t\t\tFile application = file(\"test/test.jar\");\n\t\t\tList<String> entryNames = getJarEntryNames(application);\n\t\t\tassertThat(entryNames).containsExactlyInAnyOrder(\"META-INF/native-image/\", \"META-INF/MANIFEST.MF\");\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldFailOnDuplicateFiles() throws IOException {\n\t\t\tFile file = createArchive(ExtractCommandTests.this.manifest, \"BOOT-INF/classpath.idx\",\n\t\t\t\t\t\"/jar-contents/classpath.idx\", \"META-INF/native-image/native-image.properties\",\n\t\t\t\t\t\"/jar-contents/empty-file\", \"BOOT-INF/classes/META-INF/native-image/native-image.properties\",\n\t\t\t\t\t\"/jar-contents/empty-file\");\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> run(file))\n\t\t\t\t.withMessage(\n\t\t\t\t\t\t\"Duplicate jar entry 'META-INF/native-image/native-image.properties' from original location 'BOOT-INF/classes/META-INF/native-image/native-image.properties'\");\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ExtractWithLayers {\n\n\t\t@Test\n\t\tvoid extractLibrariesAndCreatesApplication() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--layers\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"test/dependencies/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"test/dependencies/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"test/snapshot-dependencies/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"test/application/test.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid extractsOnlySelectedLayers() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--layers\", \"dependencies\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"test/dependencies/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"test/dependencies/lib/dependency-2.jar\")\n\t\t\t\t.doesNotContain(\"test/snapshot-dependencies/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.doesNotContain(\"test/application/test.jar\");\n\t\t}\n\n\t\t@Test\n\t\tvoid failsIfLayersAreNotEnabled() throws IOException {\n\t\t\tFile archive = createArchive();\n\t\t\tassertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(archive, \"--layers\"))\n\t\t\t\t.withMessage(\"Layers are not enabled\");\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ExtractLauncher {\n\n\t\t@Test\n\t\tvoid extract() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--launcher\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"test/META-INF/MANIFEST.MF\")\n\t\t\t\t.contains(\"test/BOOT-INF/classpath.idx\")\n\t\t\t\t.contains(\"test/BOOT-INF/layers.idx\")\n\t\t\t\t.contains(\"test/BOOT-INF/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"test/BOOT-INF/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"test/BOOT-INF/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"test/BOOT-INF/classes/application.properties\")\n\t\t\t\t.contains(\"test/org/springframework/boot/loader/launch/JarLauncher.class\");\n\t\t}\n\n\t\t@Test\n\t\tvoid runWithJarFileThatWouldWriteEntriesOutsideDestinationFails() throws Exception {\n\t\t\tFile file = createArchive(\"e/../../e.jar\", \"\");\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> run(file, \"--launcher\"))\n\t\t\t\t.withMessageContaining(\"Entry 'e/../../e.jar' would be written\");\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ExtractLauncherWithLayers {\n\n\t\t@Test\n\t\tvoid extract() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--launcher\", \"--layers\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).contains(\"test/application/META-INF/MANIFEST.MF\")\n\t\t\t\t.contains(\"test/application/BOOT-INF/classpath.idx\")\n\t\t\t\t.contains(\"test/application/BOOT-INF/layers.idx\")\n\t\t\t\t.contains(\"test/dependencies/BOOT-INF/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"test/dependencies/BOOT-INF/lib/dependency-2.jar\")\n\t\t\t\t.contains(\"test/snapshot-dependencies/BOOT-INF/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.contains(\"test/application/BOOT-INF/classes/application.properties\")\n\t\t\t\t.contains(\"test/spring-boot-loader/org/springframework/boot/loader/launch/JarLauncher.class\");\n\t\t}\n\n\t\t@Test\n\t\tvoid failsIfLayersAreNotEnabled() throws IOException {\n\t\t\tFile archive = createArchive();\n\t\t\tassertThatExceptionOfType(JarModeErrorException.class)\n\t\t\t\t.isThrownBy(() -> run(archive, \"--launcher\", \"--layers\"))\n\t\t\t\t.withMessage(\"Layers are not enabled\");\n\t\t}\n\n\t\t@Test\n\t\tvoid extractsOnlySelectedLayers() throws IOException {\n\t\t\trun(ExtractCommandTests.this.archive, \"--launcher\", \"--layers\", \"dependencies\");\n\t\t\tList<String> filenames = listFilenames();\n\t\t\tassertThat(filenames).doesNotContain(\"test/application/META-INF/MANIFEST.MF\")\n\t\t\t\t.doesNotContain(\"test/application/BOOT-INF/classpath.idx\")\n\t\t\t\t.doesNotContain(\"test/application/BOOT-INF/layers.idx\")\n\t\t\t\t.contains(\"test/dependencies/BOOT-INF/lib/dependency-1.jar\")\n\t\t\t\t.contains(\"test/dependencies/BOOT-INF/lib/dependency-2.jar\")\n\t\t\t\t.doesNotContain(\"test/snapshot-dependencies/BOOT-INF/lib/dependency-3-SNAPSHOT.jar\")\n\t\t\t\t.doesNotContain(\"test/application/BOOT-INF/classes/application.properties\")\n\t\t\t\t.doesNotContain(\"test/spring-boot-loader/org/springframework/boot/loader/launch/JarLauncher.class\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ExtractLayersCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.nio.file.Files;\nimport java.nio.file.attribute.BasicFileAttributeView;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.nio.file.attribute.FileTime;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.loader.jarmode.JarModeErrorException;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link ExtractLayersCommand}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(MockitoExtension.class)\nclass ExtractLayersCommandTests {\n\n\tprivate static final Instant NOW = Instant.now();\n\n\tprivate static final FileTime CREATION_TIME = FileTime.from(NOW.minus(3, ChronoUnit.DAYS));\n\n\tprivate static final FileTime LAST_MODIFIED_TIME = FileTime.from(NOW.minus(2, ChronoUnit.DAYS));\n\n\tprivate static final FileTime LAST_ACCESS_TIME = FileTime.from(NOW.minus(1, ChronoUnit.DAYS));\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Context context;\n\n\tprivate File jarFile;\n\n\tprivate File extract;\n\n\tprivate final Layers layers = new TestLayers();\n\n\tprivate ExtractLayersCommand command;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.jarFile = createJarFile(\"test.jar\");\n\t\tthis.extract = new File(this.temp, \"extract\");\n\t\tthis.extract.mkdir();\n\t\tthis.command = new ExtractLayersCommand(this.context, this.layers);\n\t}\n\n\t@Test\n\tvoid runExtractsLayers() {\n\t\tgiven(this.context.getArchiveFile()).willReturn(this.jarFile);\n\t\tgiven(this.context.getWorkingDir()).willReturn(this.extract);\n\t\tthis.command.run(System.out, Collections.emptyMap(), Collections.emptyList());\n\t\tassertThat(this.extract.list()).containsOnly(\"a\", \"b\", \"c\", \"d\");\n\t\tassertThat(new File(this.extract, \"a/a/a.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract, \"b/b/b.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract, \"c/c/c.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract, \"d\")).isDirectory();\n\t\tassertThat(new File(this.extract.getParentFile(), \"e.jar\")).doesNotExist();\n\t}\n\n\tprivate void timeAttributes(File file) {\n\t\ttry {\n\t\t\tBasicFileAttributes basicAttributes = Files\n\t\t\t\t.getFileAttributeView(file.toPath(), BasicFileAttributeView.class)\n\t\t\t\t.readAttributes();\n\t\t\tassertThat(basicAttributes.lastModifiedTime().to(TimeUnit.SECONDS))\n\t\t\t\t.isEqualTo(LAST_MODIFIED_TIME.to(TimeUnit.SECONDS));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Test\n\tvoid runWhenHasDestinationOptionExtractsLayers() {\n\t\tgiven(this.context.getArchiveFile()).willReturn(this.jarFile);\n\t\tFile out = new File(this.extract, \"out\");\n\t\tthis.command.run(System.out,\n\t\t\t\tCollections.singletonMap(ExtractLayersCommand.DESTINATION_OPTION, out.getAbsolutePath()),\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(this.extract.list()).containsOnly(\"out\");\n\t\tassertThat(new File(this.extract, \"out/a/a/a.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract, \"out/b/b/b.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract, \"out/c/c/c.jar\")).exists().satisfies(this::timeAttributes);\n\t}\n\n\t@Test\n\tvoid runWhenHasLayerParamsExtractsLimitedLayers() {\n\t\tgiven(this.context.getArchiveFile()).willReturn(this.jarFile);\n\t\tgiven(this.context.getWorkingDir()).willReturn(this.extract);\n\t\tthis.command.run(System.out, Collections.emptyMap(), Arrays.asList(\"a\", \"c\"));\n\t\tassertThat(this.extract.list()).containsOnly(\"a\", \"c\");\n\t\tassertThat(new File(this.extract, \"a/a/a.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract, \"c/c/c.jar\")).exists().satisfies(this::timeAttributes);\n\t\tassertThat(new File(this.extract.getParentFile(), \"e.jar\")).doesNotExist();\n\t}\n\n\t@Test\n\tvoid runWithJarFileContainingNoEntriesFails() throws IOException {\n\t\tFile file = new File(this.temp, \"empty.jar\");\n\t\ttry (FileWriter writer = new FileWriter(file)) {\n\t\t\twriter.write(\"text\");\n\t\t}\n\t\tgiven(this.context.getArchiveFile()).willReturn(file);\n\t\ttry (TestPrintStream out = new TestPrintStream(this)) {\n\t\t\tassertThatExceptionOfType(JarModeErrorException.class)\n\t\t\t\t.isThrownBy(() -> this.command.run(out, Collections.emptyMap(), Collections.emptyList()))\n\t\t\t\t.withMessageContaining(\"is not compatible\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid runWithJarFileThatWouldWriteEntriesOutsideDestinationFails() throws Exception {\n\t\tthis.jarFile = createJarFile(\"test.jar\", (out) -> {\n\t\t\ttry {\n\t\t\t\tout.putNextEntry(new ZipEntry(\"e/../../e.jar\"));\n\t\t\t\tout.closeEntry();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t});\n\t\tgiven(this.context.getArchiveFile()).willReturn(this.jarFile);\n\t\tgiven(this.context.getWorkingDir()).willReturn(this.extract);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.command.run(System.out, Collections.emptyMap(), Collections.emptyList()))\n\t\t\t.withMessageContaining(\"Entry 'e/../../e.jar' would be written\");\n\t}\n\n\tprivate File createJarFile(String name) throws Exception {\n\t\treturn createJarFile(name, (out) -> {\n\t\t});\n\t}\n\n\tprivate File createJarFile(String name, Consumer<ZipOutputStream> streamHandler) throws Exception {\n\t\tFile file = new File(this.temp, name);\n\t\ttry (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file))) {\n\t\t\tout.putNextEntry(entry(\"a/\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"a/a.jar\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"b/\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"b/b.jar\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"c/\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"c/c.jar\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"d/\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(entry(\"META-INF/MANIFEST.MF\"));\n\t\t\tout.write(getFile(\"test-manifest.MF\").getBytes());\n\t\t\tout.closeEntry();\n\t\t\tstreamHandler.accept(out);\n\t\t}\n\t\treturn file;\n\t}\n\n\tprivate ZipEntry entry(String path) {\n\t\tZipEntry entry = new ZipEntry(path);\n\t\tentry.setCreationTime(CREATION_TIME);\n\t\tentry.setLastModifiedTime(LAST_MODIFIED_TIME);\n\t\tentry.setLastAccessTime(LAST_ACCESS_TIME);\n\t\treturn entry;\n\t}\n\n\tprivate String getFile(String fileName) throws Exception {\n\t\tClassPathResource resource = new ClassPathResource(fileName, getClass());\n\t\tInputStreamReader reader = new InputStreamReader(resource.getInputStream());\n\t\treturn FileCopyUtils.copyToString(reader);\n\t}\n\n\tprivate static final class TestLayers implements Layers {\n\n\t\t@Override\n\t\tpublic Iterator<String> iterator() {\n\t\t\treturn Arrays.asList(\"a\", \"b\", \"c\", \"d\").iterator();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLayer(String entryName) {\n\t\t\tif (entryName.startsWith(\"a\")) {\n\t\t\t\treturn \"a\";\n\t\t\t}\n\t\t\tif (entryName.startsWith(\"b\")) {\n\t\t\t\treturn \"b\";\n\t\t\t}\n\t\t\treturn \"c\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getApplicationLayerName() {\n\t\t\treturn \"application\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/HelpCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mockito;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link HelpCommand}.\n *\n * @author Phillip Webb\n */\nclass HelpCommandTests {\n\n\tprivate HelpCommand command;\n\n\tprivate TestPrintStream out;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath temp;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tContext context = Mockito.mock(Context.class);\n\t\tgiven(context.getArchiveFile()).willReturn(this.temp.resolve(\"test.jar\").toFile());\n\t\tthis.command = new HelpCommand(context, List.of(new TestCommand()), \"tools\");\n\t\tthis.out = new TestPrintStream(this);\n\t}\n\n\t@Test\n\tvoid shouldPrintAllCommands() {\n\t\tthis.command.run(this.out, Collections.emptyList());\n\t\tassertThat(this.out).hasSameContentAsResource(\"help-output.txt\");\n\t}\n\n\t@Test\n\tvoid shouldPrintCommandSpecificHelp() {\n\t\tthis.command.run(this.out, List.of(\"test\"));\n\t\tSystem.out.println(this.out);\n\t\tassertThat(this.out).hasSameContentAsResource(\"help-test-output.txt\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/IndexedJarStructureTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.UnaryOperator;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.jarmode.tools.JarStructure.Entry;\nimport org.springframework.boot.jarmode.tools.JarStructure.Entry.Type;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IndexedJarStructure}.\n *\n * @author Moritz Halbritter\n */\nclass IndexedJarStructureTests {\n\n\t@Test\n\tvoid shouldResolveLibraryEntry() throws IOException {\n\t\tIndexedJarStructure structure = createStructure();\n\t\tEntry entry = structure.resolve(\"BOOT-INF/lib/spring-webmvc-6.1.4.jar\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.location()).isEqualTo(\"spring-webmvc-6.1.4.jar\");\n\t\tassertThat(entry.originalLocation()).isEqualTo(\"BOOT-INF/lib/spring-webmvc-6.1.4.jar\");\n\t\tassertThat(entry.type()).isEqualTo(Type.LIBRARY);\n\t}\n\n\t@Test\n\tvoid shouldResolveApplicationEntry() throws IOException {\n\t\tIndexedJarStructure structure = createStructure();\n\t\tEntry entry = structure.resolve(\"BOOT-INF/classes/application.properties\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.location()).isEqualTo(\"application.properties\");\n\t\tassertThat(entry.originalLocation()).isEqualTo(\"BOOT-INF/classes/application.properties\");\n\t\tassertThat(entry.type()).isEqualTo(Type.APPLICATION_CLASS_OR_RESOURCE);\n\t}\n\n\t@Test\n\tvoid shouldResolveLoaderEntry() throws IOException {\n\t\tIndexedJarStructure structure = createStructure();\n\t\tEntry entry = structure.resolve(\"org/springframework/boot/loader/launch/JarLauncher\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.location()).isEqualTo(\"org/springframework/boot/loader/launch/JarLauncher\");\n\t\tassertThat(entry.originalLocation()).isEqualTo(\"org/springframework/boot/loader/launch/JarLauncher\");\n\t\tassertThat(entry.type()).isEqualTo(Type.LOADER);\n\t}\n\n\t@Test\n\tvoid shouldNotResolveNonExistingLibs() throws IOException {\n\t\tIndexedJarStructure structure = createStructure();\n\t\tEntry entry = structure.resolve(\"BOOT-INF/lib/doesnt-exists.jar\");\n\t\tassertThat(entry).isNull();\n\t}\n\n\t@Test\n\tvoid shouldCreateLauncherManifest() throws IOException {\n\t\tIndexedJarStructure structure = createStructure();\n\t\tManifest manifest = structure.createLauncherManifest(UnaryOperator.identity());\n\t\tMap<String, String> attributes = getAttributes(manifest);\n\t\tassertThat(attributes).containsEntry(\"Manifest-Version\", \"1.0\")\n\t\t\t.containsEntry(\"Implementation-Title\", \"IndexedJarStructureTests\")\n\t\t\t.containsEntry(\"Spring-Boot-Version\", \"3.3.0-SNAPSHOT\")\n\t\t\t.containsEntry(\"Implementation-Version\", \"0.0.1-SNAPSHOT\")\n\t\t\t.containsEntry(\"Build-Jdk-Spec\", \"17\")\n\t\t\t.containsEntry(\"Class-Path\",\n\t\t\t\t\t\"spring-webmvc-6.1.4.jar spring-web-6.1.4.jar spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar spring-boot-3.3.0-SNAPSHOT.jar jakarta.annotation-api-2.1.1.jar spring-context-6.1.4.jar spring-aop-6.1.4.jar spring-beans-6.1.4.jar spring-expression-6.1.4.jar spring-core-6.1.4.jar snakeyaml-2.2.jar jackson-datatype-jdk8-2.16.1.jar jackson-datatype-jsr310-2.16.1.jar jackson-module-parameter-names-2.16.1.jar jackson-databind-2.16.1.jar tomcat-embed-websocket-10.1.19.jar tomcat-embed-core-10.1.19.jar tomcat-embed-el-10.1.19.jar micrometer-observation-1.13.0-M1.jar logback-classic-1.4.14.jar log4j-to-slf4j-2.23.0.jar jul-to-slf4j-2.0.12.jar spring-jcl-6.1.4.jar jackson-annotations-2.16.1.jar jackson-core-2.16.1.jar micrometer-commons-1.13.0-M1.jar logback-core-1.4.14.jar slf4j-api-2.0.12.jar log4j-api-2.23.0.jar\")\n\t\t\t.containsEntry(\"Main-Class\", \"org.springframework.boot.jarmode.tools.IndexedJarStructureTests\")\n\t\t\t.doesNotContainKeys(\"Start-Class\", \"Spring-Boot-Classes\", \"Spring-Boot-Lib\", \"Spring-Boot-Classpath-Index\",\n\t\t\t\t\t\"Spring-Boot-Layers-Index\");\n\t}\n\n\t@Test\n\tvoid shouldLoadFromFile(@TempDir File tempDir) throws IOException {\n\t\tFile jarFile = new File(tempDir, \"test.jar\");\n\t\ttry (JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(jarFile), createManifest())) {\n\t\t\toutputStream.putNextEntry(new ZipEntry(\"BOOT-INF/classpath.idx\"));\n\t\t\toutputStream.write(createIndexFile().getBytes(StandardCharsets.UTF_8));\n\t\t\toutputStream.closeEntry();\n\t\t}\n\t\tIndexedJarStructure structure = IndexedJarStructure.get(jarFile);\n\t\tassertThat(structure).isNotNull();\n\t\tassertThat(structure.resolve(\"BOOT-INF/lib/spring-webmvc-6.1.4.jar\")).extracting(Entry::type)\n\t\t\t.isEqualTo(Type.LIBRARY);\n\t\tassertThat(structure.resolve(\"BOOT-INF/classes/application.properties\")).extracting(Entry::type)\n\t\t\t.isEqualTo(Type.APPLICATION_CLASS_OR_RESOURCE);\n\t}\n\n\tprivate Map<String, String> getAttributes(Manifest manifest) {\n\t\tMap<String, String> result = new HashMap<>();\n\t\tmanifest.getMainAttributes().forEach((key, value) -> result.put(key.toString(), value.toString()));\n\t\treturn result;\n\t}\n\n\tprivate IndexedJarStructure createStructure() throws IOException {\n\t\treturn new IndexedJarStructure(createManifest(), createIndexFile());\n\t}\n\n\tprivate String createIndexFile() {\n\t\treturn \"\"\"\n\t\t\t\t- \"BOOT-INF/lib/spring-webmvc-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-web-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-context-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-aop-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-beans-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-expression-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-core-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/snakeyaml-2.2.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jackson-databind-2.16.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/tomcat-embed-websocket-10.1.19.jar\"\n\t\t\t\t- \"BOOT-INF/lib/tomcat-embed-core-10.1.19.jar\"\n\t\t\t\t- \"BOOT-INF/lib/tomcat-embed-el-10.1.19.jar\"\n\t\t\t\t- \"BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/logback-classic-1.4.14.jar\"\n\t\t\t\t- \"BOOT-INF/lib/log4j-to-slf4j-2.23.0.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jul-to-slf4j-2.0.12.jar\"\n\t\t\t\t- \"BOOT-INF/lib/spring-jcl-6.1.4.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jackson-annotations-2.16.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/jackson-core-2.16.1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\"\n\t\t\t\t- \"BOOT-INF/lib/logback-core-1.4.14.jar\"\n\t\t\t\t- \"BOOT-INF/lib/slf4j-api-2.0.12.jar\"\n\t\t\t\t- \"BOOT-INF/lib/log4j-api-2.23.0.jar\"\n\t\t\t\t\"\"\";\n\t}\n\n\tprivate Manifest createManifest() throws IOException {\n\t\treturn new Manifest(new ByteArrayInputStream(\"\"\"\n\t\t\t\tManifest-Version: 1.0\n\t\t\t\tMain-Class: org.springframework.boot.loader.launch.JarLauncher\n\t\t\t\tStart-Class: org.springframework.boot.jarmode.tools.IndexedJarStructureTests\n\t\t\t\tSpring-Boot-Version: 3.3.0-SNAPSHOT\n\t\t\t\tSpring-Boot-Classes: BOOT-INF/classes/\n\t\t\t\tSpring-Boot-Lib: BOOT-INF/lib/\n\t\t\t\tSpring-Boot-Classpath-Index: BOOT-INF/classpath.idx\n\t\t\t\tSpring-Boot-Layers-Index: BOOT-INF/layers.idx\n\t\t\t\tBuild-Jdk-Spec: 17\n\t\t\t\tImplementation-Title: IndexedJarStructureTests\n\t\t\t\tImplementation-Version: 0.0.1-SNAPSHOT\n\t\t\t\t\"\"\".getBytes(StandardCharsets.UTF_8)));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/IndexedLayersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStreamReader;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link IndexedLayers}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass IndexedLayersTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Test\n\tvoid createWhenIndexFileIsEmptyThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new IndexedLayers(\" \\n \", \"BOOT-INF/classes\"))\n\t\t\t.withMessage(\"Empty layer index file loaded\");\n\t}\n\n\t@Test\n\tvoid createWhenIndexFileIsMalformedThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new IndexedLayers(\"test\", \"BOOT-INF/classes\"))\n\t\t\t.withMessage(\"Layer index file is malformed\");\n\t}\n\n\t@Test\n\tvoid iteratorReturnsLayers() throws Exception {\n\t\tIndexedLayers layers = new IndexedLayers(getIndex(), \"BOOT-INF/classes\");\n\t\tassertThat(layers).containsExactly(\"test\", \"empty\", \"application\");\n\t}\n\n\t@Test\n\tvoid getLayerWhenMatchesNameReturnsLayer() throws Exception {\n\t\tIndexedLayers layers = new IndexedLayers(getIndex(), \"BOOT-INF/classes\");\n\t\tassertThat(layers.getLayer(mockEntry(\"BOOT-INF/lib/a.jar\"))).isEqualTo(\"test\");\n\t\tassertThat(layers.getLayer(mockEntry(\"BOOT-INF/classes/Demo.class\"))).isEqualTo(\"application\");\n\t}\n\n\t@Test\n\tvoid getLayerWhenMatchesNameForMissingLayerThrowsException() throws Exception {\n\t\tIndexedLayers layers = new IndexedLayers(getIndex(), \"BOOT-INF/classes\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> layers.getLayer(mockEntry(\"file.jar\")))\n\t\t\t.withMessage(\"No layer defined in index for file \" + \"'file.jar'\");\n\t}\n\n\t@Test\n\tvoid getLayerWhenMatchesDirectoryReturnsLayer() throws Exception {\n\t\tIndexedLayers layers = new IndexedLayers(getIndex(), \"BOOT-INF/classes\");\n\t\tassertThat(layers.getLayer(mockEntry(\"META-INF/MANIFEST.MF\"))).isEqualTo(\"application\");\n\t\tassertThat(layers.getLayer(mockEntry(\"META-INF/a/sub/directory/and/a/file\"))).isEqualTo(\"application\");\n\t}\n\n\t@Test\n\tvoid getLayerWhenFileHasSpaceReturnsLayer() throws Exception {\n\t\tIndexedLayers layers = new IndexedLayers(getIndex(), \"BOOT-INF/classes\");\n\t\tassertThat(layers.getLayer(mockEntry(\"a b/c d\"))).isEqualTo(\"application\");\n\t}\n\n\t@Test\n\tvoid getShouldReturnIndexedLayersFromContext() throws Exception {\n\t\tContext context = mock(Context.class);\n\t\tgiven(context.getArchiveFile()).willReturn(createWarFile(\"test.war\"));\n\t\tIndexedLayers layers = IndexedLayers.get(context);\n\t\tassertThat(layers).isNotNull();\n\t\tassertThat(layers.getLayer(mockEntry(\"WEB-INF/lib/a.jar\"))).isEqualTo(\"test\");\n\t}\n\n\tprivate String getIndex() throws Exception {\n\t\treturn getFile(\"test-layers.idx\");\n\t}\n\n\tprivate String getFile(String fileName) throws Exception {\n\t\tClassPathResource resource = new ClassPathResource(fileName, getClass());\n\t\tInputStreamReader reader = new InputStreamReader(resource.getInputStream());\n\t\treturn FileCopyUtils.copyToString(reader);\n\t}\n\n\tprivate ZipEntry mockEntry(String name) {\n\t\tZipEntry entry = mock(ZipEntry.class);\n\t\tgiven(entry.getName()).willReturn(name);\n\t\treturn entry;\n\t}\n\n\tprivate File createWarFile(String name) throws Exception {\n\t\tFile file = new File(this.temp, name);\n\t\ttry (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"WEB-INF/lib/a/\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(new ZipEntry(\"WEB-INF/lib/a/a.jar\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(new ZipEntry(\"WEB-INF/classes/Demo.class\"));\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(new ZipEntry(\"META-INF/MANIFEST.MF\"));\n\t\t\tout.write(getFile(\"test-war-manifest.MF\").getBytes());\n\t\t\tout.closeEntry();\n\t\t\tout.putNextEntry(new ZipEntry(\"WEB-INF/layers.idx\"));\n\t\t\tout.write(getFile(\"test-war-layers.idx\").getBytes());\n\t\t\tout.closeEntry();\n\t\t}\n\t\treturn file;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ListCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.jar.JarEntry;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link ListCommand}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass ListCommandTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Context context;\n\n\tprivate ListCommand command;\n\n\tprivate TestPrintStream out;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tFile jarFile = createJarFile(\"test.jar\");\n\t\tgiven(this.context.getArchiveFile()).willReturn(jarFile);\n\t\tthis.command = new ListCommand(this.context);\n\t\tthis.out = new TestPrintStream(this);\n\t}\n\n\t@Test\n\tvoid listLayersShouldListLayers() {\n\t\tLayers layers = IndexedLayers.get(this.context);\n\t\tassertThat(layers).isNotNull();\n\t\tthis.command.printLayers(layers, this.out);\n\t\tassertThat(this.out).hasSameContentAsResource(\"list-output-without-deprecation.txt\");\n\t}\n\n\tprivate File createJarFile(String name) throws Exception {\n\t\tFile file = new File(this.temp, name);\n\t\ttry (ZipOutputStream jarOutputStream = new ZipOutputStream(new FileOutputStream(file))) {\n\t\t\twriteLayersIndex(jarOutputStream);\n\t\t\tString entryPrefix = \"BOOT-INF/lib/\";\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"a/\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"a/a.jar\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"b/\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"b/b.jar\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"c/\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"c/c.jar\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new ZipEntry(entryPrefix + \"d/\"));\n\t\t\tjarOutputStream.closeEntry();\n\t\t\tjarOutputStream.putNextEntry(new JarEntry(\"META-INF/MANIFEST.MF\"));\n\t\t\tjarOutputStream.write(getFile(\"test-manifest.MF\").getBytes());\n\t\t\tjarOutputStream.closeEntry();\n\t\t}\n\t\treturn file;\n\t}\n\n\tprivate void writeLayersIndex(ZipOutputStream out) throws IOException {\n\t\tJarEntry indexEntry = new JarEntry(\"BOOT-INF/layers.idx\");\n\t\tout.putNextEntry(indexEntry);\n\t\tWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);\n\t\twriter.write(\"- \\\"0001\\\":\\n\");\n\t\twriter.write(\"  - \\\"BOOT-INF/lib/a.jar\\\"\\n\");\n\t\twriter.write(\"  - \\\"BOOT-INF/lib/b.jar\\\"\\n\");\n\t\twriter.write(\"- \\\"0002\\\":\\n\");\n\t\twriter.write(\"  - \\\"BOOT-INF/lib/c.jar\\\"\\n\");\n\t\twriter.write(\"- \\\"0003\\\":\\n\");\n\t\twriter.write(\"  - \\\"BOOT-INF/lib/d.jar\\\"\\n\");\n\t\twriter.flush();\n\t}\n\n\tprivate String getFile(String fileName) throws Exception {\n\t\treturn new ClassPathResource(fileName, getClass()).getContentAsString(StandardCharsets.UTF_8);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ListLayersCommandTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.Manifest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.jarmode.JarModeErrorException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ListLayersCommand}.\n *\n * @author Moritz Halbritter\n */\nclass ListLayersCommandTests extends AbstractJarModeTests {\n\n\t@Test\n\tvoid shouldListLayers() throws IOException {\n\t\tManifest manifest = createManifest(\"Spring-Boot-Layers-Index: META-INF/layers.idx\");\n\t\tTestPrintStream out = run(createArchive(manifest, \"META-INF/layers.idx\", \"/jar-contents/layers.idx\"));\n\t\tassertThat(out).hasSameContentAsResource(\"list-layers-output.txt\");\n\t}\n\n\t@Test\n\tvoid shouldFailWhenLayersAreNotEnabled() {\n\t\tassertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(createArchive()))\n\t\t\t.withMessage(\"Layers are not enabled\");\n\t}\n\n\tprivate TestPrintStream run(File archive) {\n\t\treturn runCommand(ListLayersCommand::new, archive);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/TestCommand.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.PrintStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * @author Moritz Halbritter\n */\nclass TestCommand extends Command {\n\n\tTestCommand() {\n\t\tsuper(\"test\", \"Description of test\",\n\t\t\t\tOptions.of(Option.of(\"option1\", \"value1\", \"Description of option1\"),\n\t\t\t\t\t\tOption.of(\"option2\", \"value2\", \"Description of option2\")),\n\t\t\t\tParameters.of(\"parameter1\", \"parameter2\"));\n\t}\n\n\t@Override\n\tprotected void run(PrintStream out, Map<Option, @Nullable String> options, List<String> parameters) {\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/TestPrintStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.PrintStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AssertProvider;\nimport org.assertj.core.api.Assertions;\n\nimport org.springframework.boot.jarmode.tools.TestPrintStream.PrintStreamAssert;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * {@link PrintStream} that can be used for testing.\n *\n * @author Phillip Webb\n */\nclass TestPrintStream extends PrintStream implements AssertProvider<PrintStreamAssert> {\n\n\tprivate final Class<?> testClass;\n\n\tTestPrintStream(Object testInstance) {\n\t\tsuper(new ByteArrayOutputStream());\n\t\tthis.testClass = testInstance.getClass();\n\t}\n\n\t@Override\n\tpublic PrintStreamAssert assertThat() {\n\t\treturn new PrintStreamAssert(this);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.out.toString();\n\t}\n\n\tstatic final class PrintStreamAssert extends AbstractAssert<PrintStreamAssert, TestPrintStream> {\n\n\t\tprivate PrintStreamAssert(TestPrintStream actual) {\n\t\t\tsuper(actual, PrintStreamAssert.class);\n\t\t}\n\n\t\tvoid hasSameContentAsResource(String resource) {\n\t\t\ttry {\n\t\t\t\ttry (InputStream stream = this.actual.testClass.getResourceAsStream(resource)) {\n\t\t\t\t\tAssertions.assertThat(stream).as(\"Resource '%s'\", resource).isNotNull();\n\t\t\t\t\tString content = FileCopyUtils.copyToString(new InputStreamReader(stream, StandardCharsets.UTF_8));\n\t\t\t\t\thasSameContent(content);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\tvoid hasSameContent(String content) {\n\t\t\tAssertions.assertThat(this.actual).hasToString(content);\n\t\t}\n\n\t\tvoid contains(String text) {\n\t\t\tAssertions.assertThat(this.actual.toString()).contains(text);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/java/org/springframework/boot/jarmode/tools/ToolsJarModeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jarmode.tools;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ToolsJarMode}.\n *\n * @author Moritz Halbritter\n */\nclass ToolsJarModeTests extends AbstractJarModeTests {\n\n\tprivate ToolsJarMode mode;\n\n\tprivate TestPrintStream out;\n\n\t@BeforeEach\n\tvoid setUp() throws IOException {\n\t\tthis.out = new TestPrintStream(this);\n\t\tContext context = new Context(createArchive(), this.tempDir);\n\t\tthis.mode = new ToolsJarMode(context, this.out);\n\t}\n\n\t@Test\n\tvoid shouldAcceptToolsMode() {\n\t\tassertThat(this.mode.accepts(\"tools\")).isTrue();\n\t\tassertThat(this.mode.accepts(\"something-else\")).isFalse();\n\t}\n\n\t@Test\n\tvoid noParametersShowsHelp() {\n\t\trun();\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-help-output.txt\");\n\t}\n\n\t@Test\n\tvoid helpForExtract() {\n\t\trun(\"help\", \"extract\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-help-extract-output.txt\");\n\t}\n\n\t@Test\n\tvoid helpForListLayers() {\n\t\trun(\"help\", \"list-layers\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-help-list-layers-output.txt\");\n\t}\n\n\t@Test\n\tvoid helpForHelp() {\n\t\trun(\"help\", \"help\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-help-help-output.txt\");\n\t}\n\n\t@Test\n\tvoid helpForUnknownCommand() {\n\t\trun(\"help\", \"unknown-command\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-help-unknown-command-output.txt\");\n\t}\n\n\t@Test\n\tvoid unknownCommandShowsErrorAndHelp() {\n\t\trun(\"something-invalid\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-error-command-unknown-output.txt\");\n\t}\n\n\t@Test\n\tvoid unknownOptionShowsErrorAndCommandHelp() {\n\t\trun(\"extract\", \"--something-invalid\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-error-option-unknown-output.txt\");\n\t}\n\n\t@Test\n\tvoid optionMissingRequiredValueShowsErrorAndCommandHelp() {\n\t\trun(\"extract\", \"--destination\");\n\t\tassertThat(this.out).hasSameContentAsResource(\"tools-error-option-missing-value-output.txt\");\n\t}\n\n\tprivate void run(String... args) {\n\t\tthis.mode.run(\"tools\", args);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/JarLauncher",
    "content": ""
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/application.properties",
    "content": "spring.application.name=test\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/build-info.properties",
    "content": "build.artifact=test\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/classpath.idx",
    "content": "- \"BOOT-INF/lib/dependency-1.jar\"\n- \"BOOT-INF/lib/dependency-2.jar\"\n- \"BOOT-INF/lib/dependency-3-SNAPSHOT.jar\"\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/dependency-1",
    "content": ""
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/dependency-2",
    "content": ""
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/dependency-3-SNAPSHOT",
    "content": ""
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/empty-file",
    "content": ""
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/jar-contents/layers.idx",
    "content": "- \"dependencies\":\n  - \"BOOT-INF/lib/dependency-1.jar\"\n  - \"BOOT-INF/lib/dependency-2.jar\"\n- \"spring-boot-loader\":\n  - \"org/\"\n- \"snapshot-dependencies\":\n  - \"BOOT-INF/lib/dependency-3-SNAPSHOT.jar\"\n- \"application\":\n  - \"BOOT-INF/classes/\"\n  - \"BOOT-INF/classpath.idx\"\n  - \"BOOT-INF/layers.idx\"\n  - \"META-INF/\"\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/help-output.txt",
    "content": "Usage:\n  java -Djarmode=tools -jar test.jar\n\nAvailable commands:\n  test  Description of test\n  help  Help about any command\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/help-test-output.txt",
    "content": "Description of test\n\nUsage:\n  java -Djarmode=tools -jar test.jar test [options] parameter1 parameter2\n\nOptions:\n  --option1 value1  Description of option1\n  --option2 value2  Description of option2\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/list-layers-output.txt",
    "content": "dependencies\nspring-boot-loader\nsnapshot-dependencies\napplication\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/list-output-without-deprecation.txt",
    "content": "0001\n0002\n0003\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/test-layers.idx",
    "content": "- \"test\":\n  - \"BOOT-INF/lib/a.jar\"\n  - \"BOOT-INF/lib/b.jar\"\n- \"empty\":\n- \"application\":\n  - \"BOOT-INF/classes/Demo.class\"\n  - \"META-INF/\"\n  - \"a b/c d\"\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/test-manifest.MF",
    "content": "Manifest-Version: 1.0\nCreated-By: Maven JAR Plugin\nBuild-Jdk-Spec: 11\nImplementation-Title: demo\nImplementation-Version: 0.0.1-SNAPSHOT\nMain-Class: org.springframework.boot.loader.WarLauncher\nStart-Class: com.example.DemoApplication\nSpring-Boot-Version: 2.5.0-SNAPSHOT\nSpring-Boot-Classes: BOOT-INF/classes/\nSpring-Boot-Lib: BOOT-INF/lib/\nSpring-Boot-Classpath-Index: BOOT-INF/classpath.idx\nSpring-Boot-Layers-Index: BOOT-INF/layers.idx\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/test-war-layers.idx",
    "content": "- \"test\":\n  - \"WEB-INF/lib/a.jar\"\n  - \"WEB-INF/lib/b.jar\"\n- \"empty\":\n- \"application\":\n  - \"WEB-INF/classes/Demo.class\"\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/test-war-manifest.MF",
    "content": "Manifest-Version: 1.0\nCreated-By: Maven WAR Plugin 3.3.1\nBuild-Jdk-Spec: 11\nImplementation-Title: demo\nImplementation-Version: 0.0.1-SNAPSHOT\nMain-Class: org.springframework.boot.loader.WarLauncher\nStart-Class: com.example.DemoApplication\nSpring-Boot-Version: 2.5.0-SNAPSHOT\nSpring-Boot-Classes: WEB-INF/classes/\nSpring-Boot-Lib: WEB-INF/lib/\nSpring-Boot-Classpath-Index: WEB-INF/classpath.idx\nSpring-Boot-Layers-Index: WEB-INF/layers.idx\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-error-command-unknown-output.txt",
    "content": "Error: Unknown command \"something-invalid\"\n\nUsage:\n  java -Djarmode=tools -jar test.jar\n\nAvailable commands:\n  extract      Extract the contents from the jar\n  list-layers  List layers from the jar that can be extracted\n  help         Help about any command\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-error-option-missing-value-output.txt",
    "content": "Error: Option \"--destination\" for the extract command requires a value\n\nExtract the contents from the jar\n\nUsage:\n  java -Djarmode=tools -jar test.jar extract [options]\n\nOptions:\n  --launcher                     Whether to extract the Spring Boot launcher\n  --layers string list           Layers to extract\n  --destination string           Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)\n  --libraries string             Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/\n  --application-filename string  Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename\n  --force                        Whether to ignore non-empty directories, extract anyway\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-error-option-unknown-output.txt",
    "content": "Error: Unknown option \"--something-invalid\" for the extract command\n\nExtract the contents from the jar\n\nUsage:\n  java -Djarmode=tools -jar test.jar extract [options]\n\nOptions:\n  --launcher                     Whether to extract the Spring Boot launcher\n  --layers string list           Layers to extract\n  --destination string           Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)\n  --libraries string             Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/\n  --application-filename string  Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename\n  --force                        Whether to ignore non-empty directories, extract anyway\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-help-extract-output.txt",
    "content": "Extract the contents from the jar\n\nUsage:\n  java -Djarmode=tools -jar test.jar extract [options]\n\nOptions:\n  --launcher                     Whether to extract the Spring Boot launcher\n  --layers string list           Layers to extract\n  --destination string           Directory to extract files to. Defaults to a directory named after the uber JAR (without the file extension)\n  --libraries string             Name of the libraries directory. Only applicable when not using --launcher. Defaults to lib/\n  --application-filename string  Name of the application JAR file. Only applicable when not using --launcher. Defaults to the uber JAR filename\n  --force                        Whether to ignore non-empty directories, extract anyway\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-help-help-output.txt",
    "content": "Help about any command\n\nUsage:\n  java -Djarmode=tools -jar test.jar help [<command>]\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-help-list-layers-output.txt",
    "content": "List layers from the jar that can be extracted\n\nUsage:\n  java -Djarmode=tools -jar test.jar list-layers\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-help-output.txt",
    "content": "Usage:\n  java -Djarmode=tools -jar test.jar\n\nAvailable commands:\n  extract      Extract the contents from the jar\n  list-layers  List layers from the jar that can be extracted\n  help         Help about any command\n"
  },
  {
    "path": "loader/spring-boot-jarmode-tools/src/test/resources/org/springframework/boot/jarmode/tools/tools-help-unknown-command-output.txt",
    "content": "Error: Unknown command \"unknown-command\"\n\nUsage:\n  java -Djarmode=tools -jar test.jar\n\nAvailable commands:\n  extract      Extract the contents from the jar\n  list-layers  List layers from the jar that can be extracted\n  help         Help about any command\n"
  },
  {
    "path": "loader/spring-boot-loader/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Loader\"\n\ndependencies {\n\tcompileOnly(\"org.springframework:spring-core\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.bouncycastle:bcprov-jdk18on:1.78.1\")\n\ttestRuntimeOnly(\"org.springframework:spring-webmvc\")\n}\n\ntasks.configureEach {\n\tif (\"checkArchitectureMainJava\".equals(it.name)) {\n\t\tprohibitObjectsRequireNonNull = false\n\t}\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarEntriesStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.Closeable;\nimport java.io.DataInputStream;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarInputStream;\nimport java.util.zip.Inflater;\nimport java.util.zip.ZipEntry;\n\n/**\n * Helper class to iterate entries in a jar file and check that content matches a related\n * entry.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass JarEntriesStream implements Closeable {\n\n\tprivate static final int BUFFER_SIZE = 4 * 1024;\n\n\tprivate final JarInputStream in;\n\n\tprivate final byte[] inBuffer = new byte[BUFFER_SIZE];\n\n\tprivate final byte[] compareBuffer = new byte[BUFFER_SIZE];\n\n\tprivate final Inflater inflater = new Inflater(true);\n\n\tprivate JarEntry entry;\n\n\tJarEntriesStream(InputStream in) throws IOException {\n\t\tthis.in = new JarInputStream(in);\n\t}\n\n\tJarEntry getNextEntry() throws IOException {\n\t\tthis.entry = this.in.getNextJarEntry();\n\t\tthis.inflater.reset();\n\t\treturn this.entry;\n\t}\n\n\tboolean matches(boolean directory, int size, int compressionMethod, InputStreamSupplier streamSupplier)\n\t\t\tthrows IOException {\n\t\tif (this.entry.isDirectory() != directory) {\n\t\t\tfail(\"directory\");\n\t\t}\n\t\tif (this.entry.getMethod() != compressionMethod) {\n\t\t\tfail(\"compression method\");\n\t\t}\n\t\tif (this.entry.isDirectory()) {\n\t\t\tthis.in.closeEntry();\n\t\t\treturn true;\n\t\t}\n\t\ttry (DataInputStream expected = new DataInputStream(getInputStream(size, streamSupplier))) {\n\t\t\tassertSameContent(expected);\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate InputStream getInputStream(int size, InputStreamSupplier streamSupplier) throws IOException {\n\t\tInputStream inputStream = streamSupplier.get();\n\t\treturn (this.entry.getMethod() != ZipEntry.DEFLATED) ? inputStream\n\t\t\t\t: new ZipInflaterInputStream(inputStream, this.inflater, size);\n\t}\n\n\tprivate void assertSameContent(DataInputStream expected) throws IOException {\n\t\tint len;\n\t\twhile ((len = this.in.read(this.inBuffer)) > 0) {\n\t\t\ttry {\n\t\t\t\texpected.readFully(this.compareBuffer, 0, len);\n\t\t\t\tif (Arrays.equals(this.inBuffer, 0, len, this.compareBuffer, 0, len)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (EOFException ex) {\n\t\t\t\t// Continue and throw exception due to mismatched content length.\n\t\t\t}\n\t\t\tfail(\"content\");\n\t\t}\n\t\tif (expected.read() != -1) {\n\t\t\tfail(\"content\");\n\t\t}\n\t}\n\n\tprivate void fail(String check) {\n\t\tthrow new IllegalStateException(\"Content mismatch when reading security info for entry '%s' (%s check)\"\n\t\t\t.formatted(this.entry.getName(), check));\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.inflater.end();\n\t\tthis.in.close();\n\t}\n\n\t@FunctionalInterface\n\tinterface InputStreamSupplier {\n\n\t\tInputStream get() throws IOException;\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/ManifestInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.util.jar.Attributes;\nimport java.util.jar.Attributes.Name;\nimport java.util.jar.Manifest;\n\nimport org.springframework.boot.loader.zip.ZipContent;\n\n/**\n * Info obtained from a {@link ZipContent} instance relating to the {@link Manifest}.\n *\n * @author Phillip Webb\n */\nclass ManifestInfo {\n\n\tprivate static final Name MULTI_RELEASE = new Name(\"Multi-Release\");\n\n\tstatic final ManifestInfo NONE = new ManifestInfo(null, false);\n\n\tprivate final Manifest manifest;\n\n\tprivate volatile Boolean multiRelease;\n\n\t/**\n\t * Create a new {@link ManifestInfo} instance.\n\t * @param manifest the jar manifest\n\t */\n\tManifestInfo(Manifest manifest) {\n\t\tthis(manifest, null);\n\t}\n\n\tprivate ManifestInfo(Manifest manifest, Boolean multiRelease) {\n\t\tthis.manifest = manifest;\n\t\tthis.multiRelease = multiRelease;\n\t}\n\n\t/**\n\t * Return the manifest, if any.\n\t * @return the manifest or {@code null}\n\t */\n\tManifest getManifest() {\n\t\treturn this.manifest;\n\t}\n\n\t/**\n\t * Return if this is a multi-release jar.\n\t * @return if the jar is multi-release\n\t */\n\tboolean isMultiRelease() {\n\t\tif (this.manifest == null) {\n\t\t\treturn false;\n\t\t}\n\t\tBoolean multiRelease = this.multiRelease;\n\t\tif (multiRelease != null) {\n\t\t\treturn multiRelease;\n\t\t}\n\t\tAttributes attributes = this.manifest.getMainAttributes();\n\t\tmultiRelease = attributes.containsKey(MULTI_RELEASE);\n\t\tthis.multiRelease = multiRelease;\n\t\treturn multiRelease;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/MetaInfVersionsInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.IntFunction;\n\nimport org.springframework.boot.loader.zip.ZipContent;\n\n/**\n * Info obtained from a {@link ZipContent} instance relating to the directories listed\n * under {@code META-INF/versions/}.\n *\n * @author Phillip Webb\n */\nfinal class MetaInfVersionsInfo {\n\n\tstatic final MetaInfVersionsInfo NONE = new MetaInfVersionsInfo(Collections.emptySet());\n\n\tprivate static final String META_INF_VERSIONS = NestedJarFile.META_INF_VERSIONS;\n\n\tprivate final int[] versions;\n\n\tprivate final String[] directories;\n\n\tprivate MetaInfVersionsInfo(Set<Integer> versions) {\n\t\tthis.versions = versions.stream().mapToInt(Integer::intValue).toArray();\n\t\tthis.directories = versions.stream().map((version) -> META_INF_VERSIONS + version + \"/\").toArray(String[]::new);\n\t}\n\n\t/**\n\t * Return the versions listed under {@code META-INF/versions/} in ascending order.\n\t * @return the versions\n\t */\n\tint[] versions() {\n\t\treturn this.versions;\n\t}\n\n\t/**\n\t * Return the version directories in the same order as {@link #versions()}.\n\t * @return the version directories\n\t */\n\tString[] directories() {\n\t\treturn this.directories;\n\t}\n\n\t/**\n\t * Get {@link MetaInfVersionsInfo} for the given {@link ZipContent}.\n\t * @param zipContent the zip content\n\t * @return the {@link MetaInfVersionsInfo}.\n\t */\n\tstatic MetaInfVersionsInfo get(ZipContent zipContent) {\n\t\treturn get(zipContent.size(), zipContent::getEntry);\n\t}\n\n\t/**\n\t * Get {@link MetaInfVersionsInfo} for the given details.\n\t * @param size the number of entries\n\t * @param entries a function to get an entry from an index\n\t * @return the {@link MetaInfVersionsInfo}.\n\t */\n\tstatic MetaInfVersionsInfo get(int size, IntFunction<ZipContent.Entry> entries) {\n\t\tSet<Integer> versions = new TreeSet<>();\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\tZipContent.Entry contentEntry = entries.apply(i);\n\t\t\tif (contentEntry.hasNameStartingWith(META_INF_VERSIONS) && !contentEntry.isDirectory()) {\n\t\t\t\tString name = contentEntry.getName();\n\t\t\t\tint slash = name.indexOf('/', META_INF_VERSIONS.length());\n\t\t\t\tif (slash > -1) {\n\t\t\t\t\tString version = name.substring(META_INF_VERSIONS.length(), slash);\n\t\t\t\t\ttry {\n\t\t\t\t\t\tint versionNumber = Integer.parseInt(version);\n\t\t\t\t\t\tif (versionNumber >= NestedJarFile.BASE_VERSION) {\n\t\t\t\t\t\t\tversions.add(versionNumber);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t\t\t// Ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn (!versions.isEmpty()) ? new MetaInfVersionsInfo(versions) : NONE;\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/NestedJarFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.File;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.nio.ByteBuffer;\nimport java.nio.file.attribute.FileTime;\nimport java.security.CodeSigner;\nimport java.security.cert.Certificate;\nimport java.time.LocalDateTime;\nimport java.util.Enumeration;\nimport java.util.NoSuchElementException;\nimport java.util.Objects;\nimport java.util.Spliterator;\nimport java.util.Spliterators.AbstractSpliterator;\nimport java.util.function.Consumer;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\nimport java.util.zip.Inflater;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipException;\n\nimport org.springframework.boot.loader.log.DebugLogger;\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.zip.CloseableDataBlock;\nimport org.springframework.boot.loader.zip.ZipContent;\nimport org.springframework.boot.loader.zip.ZipContent.Entry;\n\n/**\n * Extended variant of {@link JarFile} that behaves in the same way but can open nested\n * jars.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 3.2.0\n */\npublic class NestedJarFile extends JarFile {\n\n\tprivate static final int DECIMAL = 10;\n\n\tprivate static final String META_INF = \"META-INF/\";\n\n\tstatic final String META_INF_VERSIONS = META_INF + \"versions/\";\n\n\tstatic final int BASE_VERSION = baseVersion().feature();\n\n\tprivate static final DebugLogger debug = DebugLogger.get(NestedJarFile.class);\n\n\tprivate final Cleaner cleaner;\n\n\tprivate final NestedJarFileResources resources;\n\n\tprivate final Cleanable cleanup;\n\n\tprivate final String name;\n\n\tprivate final int version;\n\n\tprivate volatile NestedJarEntry lastEntry;\n\n\tprivate volatile boolean closed;\n\n\tprivate volatile ManifestInfo manifestInfo;\n\n\tprivate volatile MetaInfVersionsInfo metaInfVersionsInfo;\n\n\t/**\n\t * Creates a new {@link NestedJarFile} instance to read from the specific\n\t * {@code File}.\n\t * @param file the jar file to be opened for reading\n\t * @throws IOException on I/O error\n\t */\n\tNestedJarFile(File file) throws IOException {\n\t\tthis(file, null, null, false, Cleaner.instance);\n\t}\n\n\t/**\n\t * Creates a new {@link NestedJarFile} instance to read from the specific\n\t * {@code File}.\n\t * @param file the jar file to be opened for reading\n\t * @param nestedEntryName the nested entry name to open\n\t * @throws IOException on I/O error\n\t * @throws IllegalArgumentException if {@code nestedEntryName} is {@code null} or\n\t * empty\n\t */\n\tpublic NestedJarFile(File file, String nestedEntryName) throws IOException {\n\t\tthis(file, nestedEntryName, null, true, Cleaner.instance);\n\t}\n\n\t/**\n\t * Creates a new {@link NestedJarFile} instance to read from the specific\n\t * {@code File}.\n\t * @param file the jar file to be opened for reading\n\t * @param nestedEntryName the nested entry name to open\n\t * @param version the release version to use when opening a multi-release jar\n\t * @throws IOException on I/O error\n\t * @throws IllegalArgumentException if {@code nestedEntryName} is {@code null} or\n\t * empty\n\t */\n\tpublic NestedJarFile(File file, String nestedEntryName, Runtime.Version version) throws IOException {\n\t\tthis(file, nestedEntryName, version, true, Cleaner.instance);\n\t}\n\n\t/**\n\t * Creates a new {@link NestedJarFile} instance to read from the specific\n\t * {@code File}.\n\t * @param file the jar file to be opened for reading\n\t * @param nestedEntryName the nested entry name to open\n\t * @param version the release version to use when opening a multi-release jar\n\t * @param onlyNestedJars if <em>only</em> nested jars should be opened\n\t * @param cleaner the cleaner used to release resources\n\t * @throws IOException on I/O error\n\t * @throws IllegalArgumentException if {@code nestedEntryName} is {@code null} or\n\t * empty\n\t */\n\tNestedJarFile(File file, String nestedEntryName, Runtime.Version version, boolean onlyNestedJars, Cleaner cleaner)\n\t\t\tthrows IOException {\n\t\tsuper(file);\n\t\tif (onlyNestedJars && (nestedEntryName == null || nestedEntryName.isEmpty())) {\n\t\t\tthrow new IllegalArgumentException(\"nestedEntryName must not be empty\");\n\t\t}\n\t\tdebug.log(\"Created nested jar file (%s, %s, %s)\", file, nestedEntryName, version);\n\t\tthis.cleaner = cleaner;\n\t\tthis.resources = new NestedJarFileResources(file, nestedEntryName);\n\t\tthis.cleanup = cleaner.register(this, this.resources);\n\t\tthis.name = file.getPath() + ((nestedEntryName != null) ? \"!/\" + nestedEntryName : \"\");\n\t\tthis.version = (version != null) ? version.feature() : baseVersion().feature();\n\t}\n\n\tpublic InputStream getRawZipDataInputStream() throws IOException {\n\t\tRawZipDataInputStream inputStream = new RawZipDataInputStream(\n\t\t\t\tthis.resources.zipContent().openRawZipData().asInputStream());\n\t\tthis.resources.addInputStream(inputStream);\n\t\treturn inputStream;\n\t}\n\n\t@Override\n\tpublic Manifest getManifest() throws IOException {\n\t\ttry {\n\t\t\treturn this.resources.zipContentForManifest()\n\t\t\t\t.getInfo(ManifestInfo.class, this::getManifestInfo)\n\t\t\t\t.getManifest();\n\t\t}\n\t\tcatch (UncheckedIOException ex) {\n\t\t\tthrow ex.getCause();\n\t\t}\n\t}\n\n\t@Override\n\tpublic Enumeration<JarEntry> entries() {\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn new JarEntriesEnumeration(this.resources.zipContent());\n\t\t}\n\t}\n\n\t@Override\n\tpublic Stream<JarEntry> stream() {\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn streamContentEntries().map(NestedJarEntry::new);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Stream<JarEntry> versionedStream() {\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn streamContentEntries().map(this::getBaseName)\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.distinct()\n\t\t\t\t.map(this::getJarEntry)\n\t\t\t\t.filter(Objects::nonNull);\n\t\t}\n\t}\n\n\tprivate Stream<ZipContent.Entry> streamContentEntries() {\n\t\tZipContentEntriesSpliterator spliterator = new ZipContentEntriesSpliterator(this.resources.zipContent());\n\t\treturn StreamSupport.stream(spliterator, false);\n\t}\n\n\tprivate String getBaseName(ZipContent.Entry contentEntry) {\n\t\tString name = contentEntry.getName();\n\t\tif (!name.startsWith(META_INF_VERSIONS)) {\n\t\t\treturn name;\n\t\t}\n\t\tint versionNumberStartIndex = META_INF_VERSIONS.length();\n\t\tint versionNumberEndIndex = (versionNumberStartIndex != -1) ? name.indexOf('/', versionNumberStartIndex) : -1;\n\t\tif (versionNumberEndIndex == -1 || versionNumberEndIndex == (name.length() - 1)) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tint versionNumber = Integer.parseInt(name, versionNumberStartIndex, versionNumberEndIndex, DECIMAL);\n\t\t\tif (versionNumber > this.version) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\treturn null;\n\t\t}\n\t\treturn name.substring(versionNumberEndIndex + 1);\n\t}\n\n\t@Override\n\tpublic JarEntry getJarEntry(String name) {\n\t\treturn getNestedJarEntry(name);\n\t}\n\n\t@Override\n\tpublic JarEntry getEntry(String name) {\n\t\treturn getNestedJarEntry(name);\n\t}\n\n\t/**\n\t * Return if an entry with the given name exists.\n\t * @param name the name to check\n\t * @return if the entry exists\n\t */\n\tpublic boolean hasEntry(String name) {\n\t\tNestedJarEntry lastEntry = this.lastEntry;\n\t\tif (lastEntry != null && name.equals(lastEntry.getName())) {\n\t\t\treturn true;\n\t\t}\n\t\tZipContent.Entry entry = getVersionedContentEntry(name);\n\t\tif (entry != null) {\n\t\t\treturn true;\n\t\t}\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn this.resources.zipContent().hasEntry(null, name);\n\t\t}\n\t}\n\n\tprivate NestedJarEntry getNestedJarEntry(String name) {\n\t\tObjects.requireNonNull(name, \"name\");\n\t\tNestedJarEntry lastEntry = this.lastEntry;\n\t\tif (lastEntry != null && name.equals(lastEntry.getName())) {\n\t\t\treturn lastEntry;\n\t\t}\n\t\tZipContent.Entry entry = getVersionedContentEntry(name);\n\t\tentry = (entry != null) ? entry : getContentEntry(null, name);\n\t\tif (entry == null) {\n\t\t\treturn null;\n\t\t}\n\t\tNestedJarEntry nestedJarEntry = new NestedJarEntry(entry, name);\n\t\tthis.lastEntry = nestedJarEntry;\n\t\treturn nestedJarEntry;\n\t}\n\n\tprivate ZipContent.Entry getVersionedContentEntry(String name) {\n\t\t// NOTE: we can't call isMultiRelease() directly because it's a final method and\n\t\t// it inspects the container jar. We use ManifestInfo instead.\n\t\tif (BASE_VERSION >= this.version || name.startsWith(META_INF) || !getManifestInfo().isMultiRelease()) {\n\t\t\treturn null;\n\t\t}\n\t\tMetaInfVersionsInfo metaInfVersionsInfo = getMetaInfVersionsInfo();\n\t\tint[] versions = metaInfVersionsInfo.versions();\n\t\tString[] directories = metaInfVersionsInfo.directories();\n\t\tfor (int i = versions.length - 1; i >= 0; i--) {\n\t\t\tif (versions[i] <= this.version) {\n\t\t\t\tZipContent.Entry entry = getContentEntry(directories[i], name);\n\t\t\t\tif (entry != null) {\n\t\t\t\t\treturn entry;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate ZipContent.Entry getContentEntry(String namePrefix, String name) {\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn this.resources.zipContent().getEntry(namePrefix, name);\n\t\t}\n\t}\n\n\tprivate ManifestInfo getManifestInfo() {\n\t\tManifestInfo manifestInfo = this.manifestInfo;\n\t\tif (manifestInfo != null) {\n\t\t\treturn manifestInfo;\n\t\t}\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\tmanifestInfo = this.resources.zipContent().getInfo(ManifestInfo.class, this::getManifestInfo);\n\t\t}\n\t\tthis.manifestInfo = manifestInfo;\n\t\treturn manifestInfo;\n\t}\n\n\tprivate ManifestInfo getManifestInfo(ZipContent zipContent) {\n\t\tZipContent.Entry contentEntry = zipContent.getEntry(MANIFEST_NAME);\n\t\tif (contentEntry == null) {\n\t\t\treturn ManifestInfo.NONE;\n\t\t}\n\t\ttry {\n\t\t\ttry (InputStream inputStream = getInputStream(contentEntry)) {\n\t\t\t\tManifest manifest = new Manifest(inputStream);\n\t\t\t\treturn new ManifestInfo(manifest);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate MetaInfVersionsInfo getMetaInfVersionsInfo() {\n\t\tMetaInfVersionsInfo metaInfVersionsInfo = this.metaInfVersionsInfo;\n\t\tif (metaInfVersionsInfo != null) {\n\t\t\treturn metaInfVersionsInfo;\n\t\t}\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\tmetaInfVersionsInfo = this.resources.zipContent()\n\t\t\t\t.getInfo(MetaInfVersionsInfo.class, MetaInfVersionsInfo::get);\n\t\t}\n\t\tthis.metaInfVersionsInfo = metaInfVersionsInfo;\n\t\treturn metaInfVersionsInfo;\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream(ZipEntry entry) throws IOException {\n\t\tObjects.requireNonNull(entry, \"entry\");\n\t\tif (entry instanceof NestedJarEntry nestedJarEntry && nestedJarEntry.isOwnedBy(this)) {\n\t\t\treturn getInputStream(nestedJarEntry.contentEntry());\n\t\t}\n\t\treturn getInputStream(getNestedJarEntry(entry.getName()).contentEntry());\n\t}\n\n\tprivate InputStream getInputStream(ZipContent.Entry contentEntry) throws IOException {\n\t\tint compression = contentEntry.getCompressionMethod();\n\t\tif (compression != ZipEntry.STORED && compression != ZipEntry.DEFLATED) {\n\t\t\tthrow new ZipException(\"invalid compression method\");\n\t\t}\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\tInputStream inputStream = new JarEntryInputStream(contentEntry);\n\t\t\ttry {\n\t\t\t\tif (compression == ZipEntry.DEFLATED) {\n\t\t\t\t\tinputStream = new JarEntryInflaterInputStream((JarEntryInputStream) inputStream, this.resources);\n\t\t\t\t}\n\t\t\t\tthis.resources.addInputStream(inputStream);\n\t\t\t\treturn inputStream;\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\tinputStream.close();\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getComment() {\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn this.resources.zipContent().getComment();\n\t\t}\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\tsynchronized (this) {\n\t\t\tensureOpen();\n\t\t\treturn this.resources.zipContent().size();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tsuper.close();\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = true;\n\t\tsynchronized (this) {\n\t\t\ttry {\n\t\t\t\tthis.cleanup.clean();\n\t\t\t}\n\t\t\tcatch (UncheckedIOException ex) {\n\t\t\t\tthrow ex.getCause();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tprivate void ensureOpen() {\n\t\tif (this.closed) {\n\t\t\tthrow new IllegalStateException(\"Zip file closed\");\n\t\t}\n\t\tif (this.resources.zipContent() == null) {\n\t\t\tthrow new IllegalStateException(\"The object is not initialized.\");\n\t\t}\n\t}\n\n\t/**\n\t * Clear any internal caches.\n\t */\n\tpublic void clearCache() {\n\t\tsynchronized (this) {\n\t\t\tthis.lastEntry = null;\n\t\t}\n\t}\n\n\t/**\n\t * An individual entry from a {@link NestedJarFile}.\n\t */\n\tprivate class NestedJarEntry extends java.util.jar.JarEntry {\n\n\t\tprivate static final IllegalStateException CANNOT_BE_MODIFIED_EXCEPTION = new IllegalStateException(\n\t\t\t\t\"Neste jar entries cannot be modified\");\n\n\t\tprivate final ZipContent.Entry contentEntry;\n\n\t\tprivate final String name;\n\n\t\tprivate volatile boolean populated;\n\n\t\tNestedJarEntry(Entry contentEntry) {\n\t\t\tthis(contentEntry, contentEntry.getName());\n\t\t}\n\n\t\tNestedJarEntry(ZipContent.Entry contentEntry, String name) {\n\t\t\tsuper(contentEntry.getName());\n\t\t\tthis.contentEntry = contentEntry;\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getTime() {\n\t\t\tpopulate();\n\t\t\treturn super.getTime();\n\t\t}\n\n\t\t@Override\n\t\tpublic LocalDateTime getTimeLocal() {\n\t\t\tpopulate();\n\t\t\treturn super.getTimeLocal();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setTime(long time) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setTimeLocal(LocalDateTime time) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic FileTime getLastModifiedTime() {\n\t\t\tpopulate();\n\t\t\treturn super.getLastModifiedTime();\n\t\t}\n\n\t\t@Override\n\t\tpublic ZipEntry setLastModifiedTime(FileTime time) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic FileTime getLastAccessTime() {\n\t\t\tpopulate();\n\t\t\treturn super.getLastAccessTime();\n\t\t}\n\n\t\t@Override\n\t\tpublic ZipEntry setLastAccessTime(FileTime time) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic FileTime getCreationTime() {\n\t\t\tpopulate();\n\t\t\treturn super.getCreationTime();\n\t\t}\n\n\t\t@Override\n\t\tpublic ZipEntry setCreationTime(FileTime time) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getSize() {\n\t\t\treturn this.contentEntry.getUncompressedSize() & 0xFFFFFFFFL;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setSize(long size) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getCompressedSize() {\n\t\t\tpopulate();\n\t\t\treturn super.getCompressedSize();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setCompressedSize(long csize) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic long getCrc() {\n\t\t\tpopulate();\n\t\t\treturn super.getCrc();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setCrc(long crc) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getMethod() {\n\t\t\tpopulate();\n\t\t\treturn super.getMethod();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setMethod(int method) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic byte[] getExtra() {\n\t\t\tpopulate();\n\t\t\treturn super.getExtra();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setExtra(byte[] extra) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getComment() {\n\t\t\tpopulate();\n\t\t\treturn super.getComment();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setComment(String comment) {\n\t\t\tthrow CANNOT_BE_MODIFIED_EXCEPTION;\n\t\t}\n\n\t\tboolean isOwnedBy(NestedJarFile nestedJarFile) {\n\t\t\treturn NestedJarFile.this == nestedJarFile;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getRealName() {\n\t\t\treturn super.getName();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t@Override\n\t\tpublic Attributes getAttributes() throws IOException {\n\t\t\tManifest manifest = getManifest();\n\t\t\treturn (manifest != null) ? manifest.getAttributes(getName()) : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic Certificate[] getCertificates() {\n\t\t\treturn getSecurityInfo().getCertificates(contentEntry());\n\t\t}\n\n\t\t@Override\n\t\tpublic CodeSigner[] getCodeSigners() {\n\t\t\treturn getSecurityInfo().getCodeSigners(contentEntry());\n\t\t}\n\n\t\tprivate SecurityInfo getSecurityInfo() {\n\t\t\treturn NestedJarFile.this.resources.zipContent().getInfo(SecurityInfo.class, SecurityInfo::get);\n\t\t}\n\n\t\tZipContent.Entry contentEntry() {\n\t\t\treturn this.contentEntry;\n\t\t}\n\n\t\tprivate void populate() {\n\t\t\tboolean populated = this.populated;\n\t\t\tif (!populated) {\n\t\t\t\tZipEntry entry = this.contentEntry.as(ZipEntry::new);\n\t\t\t\tsuper.setMethod(entry.getMethod());\n\t\t\t\tsuper.setTime(entry.getTime());\n\t\t\t\tsuper.setCrc(entry.getCrc());\n\t\t\t\tsuper.setCompressedSize(entry.getCompressedSize());\n\t\t\t\tsuper.setSize(entry.getSize());\n\t\t\t\tsuper.setExtra(entry.getExtra());\n\t\t\t\tsuper.setComment(entry.getComment());\n\t\t\t\tthis.populated = true;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Enumeration} of {@link NestedJarEntry} instances.\n\t */\n\tprivate class JarEntriesEnumeration implements Enumeration<JarEntry> {\n\n\t\tprivate final ZipContent zipContent;\n\n\t\tprivate int cursor;\n\n\t\tJarEntriesEnumeration(ZipContent zipContent) {\n\t\t\tthis.zipContent = zipContent;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasMoreElements() {\n\t\t\treturn this.cursor < this.zipContent.size();\n\t\t}\n\n\t\t@Override\n\t\tpublic NestedJarEntry nextElement() {\n\t\t\tif (!hasMoreElements()) {\n\t\t\t\tthrow new NoSuchElementException();\n\t\t\t}\n\t\t\tsynchronized (NestedJarFile.this) {\n\t\t\t\tensureOpen();\n\t\t\t\treturn new NestedJarEntry(this.zipContent.getEntry(this.cursor++));\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Spliterator} for {@link ZipContent.Entry} instances.\n\t */\n\tprivate class ZipContentEntriesSpliterator extends AbstractSpliterator<ZipContent.Entry> {\n\n\t\tprivate static final int ADDITIONAL_CHARACTERISTICS = Spliterator.ORDERED | Spliterator.DISTINCT\n\t\t\t\t| Spliterator.IMMUTABLE | Spliterator.NONNULL;\n\n\t\tprivate final ZipContent zipContent;\n\n\t\tprivate int cursor;\n\n\t\tZipContentEntriesSpliterator(ZipContent zipContent) {\n\t\t\tsuper(zipContent.size(), ADDITIONAL_CHARACTERISTICS);\n\t\t\tthis.zipContent = zipContent;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean tryAdvance(Consumer<? super ZipContent.Entry> action) {\n\t\t\tif (this.cursor < this.zipContent.size()) {\n\t\t\t\tsynchronized (NestedJarFile.this) {\n\t\t\t\t\tensureOpen();\n\t\t\t\t\taction.accept(this.zipContent.getEntry(this.cursor++));\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link InputStream} to read jar entry content.\n\t */\n\tprivate class JarEntryInputStream extends InputStream {\n\n\t\tprivate final int uncompressedSize;\n\n\t\tprivate final CloseableDataBlock content;\n\n\t\tprivate long pos;\n\n\t\tprivate long remaining;\n\n\t\tprivate volatile boolean closed;\n\n\t\tJarEntryInputStream(ZipContent.Entry entry) throws IOException {\n\t\t\tthis.uncompressedSize = entry.getUncompressedSize();\n\t\t\tthis.content = entry.openContent();\n\t\t\tthis.remaining = this.uncompressedSize;\n\t\t}\n\n\t\t@Override\n\t\tpublic int read() throws IOException {\n\t\t\tbyte[] b = new byte[1];\n\t\t\treturn (read(b, 0, 1) == 1) ? b[0] & 0xFF : -1;\n\t\t}\n\n\t\t@Override\n\t\tpublic int read(byte[] b, int off, int len) throws IOException {\n\t\t\tint result;\n\t\t\tsynchronized (NestedJarFile.this) {\n\t\t\t\tensureOpen();\n\t\t\t\tByteBuffer dst = ByteBuffer.wrap(b, off, len);\n\t\t\t\tint count = this.content.read(dst, this.pos);\n\t\t\t\tif (count > 0) {\n\t\t\t\t\tthis.pos += count;\n\t\t\t\t\tthis.remaining -= count;\n\t\t\t\t}\n\t\t\t\tresult = count;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\t@Override\n\t\tpublic long skip(long n) throws IOException {\n\t\t\tlong result;\n\t\t\tsynchronized (NestedJarFile.this) {\n\t\t\t\tresult = (n > 0) ? maxForwardSkip(n) : maxBackwardSkip(n);\n\t\t\t\tthis.pos += result;\n\t\t\t\tthis.remaining -= result;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate long maxForwardSkip(long n) {\n\t\t\tboolean willCauseOverflow = (this.pos + n) < 0;\n\t\t\treturn (willCauseOverflow || n > this.remaining) ? this.remaining : n;\n\t\t}\n\n\t\tprivate long maxBackwardSkip(long n) {\n\t\t\treturn Math.max(-this.pos, n);\n\t\t}\n\n\t\t@Override\n\t\tpublic int available() {\n\t\t\treturn (this.remaining < Integer.MAX_VALUE) ? (int) this.remaining : Integer.MAX_VALUE;\n\t\t}\n\n\t\tprivate void ensureOpen() throws ZipException {\n\t\t\tif (NestedJarFile.this.closed || this.closed) {\n\t\t\t\tthrow new ZipException(\"ZipFile closed\");\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tif (this.closed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.closed = true;\n\t\t\tthis.content.close();\n\t\t\tNestedJarFile.this.resources.removeInputStream(this);\n\t\t}\n\n\t\tint getUncompressedSize() {\n\t\t\treturn this.uncompressedSize;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ZipInflaterInputStream} to read and inflate jar entry content.\n\t */\n\tprivate class JarEntryInflaterInputStream extends ZipInflaterInputStream {\n\n\t\tprivate final Cleanable cleanup;\n\n\t\tprivate volatile boolean closed;\n\n\t\tJarEntryInflaterInputStream(JarEntryInputStream inputStream, NestedJarFileResources resources) {\n\t\t\tthis(inputStream, resources, resources.getOrCreateInflater());\n\t\t}\n\n\t\tprivate JarEntryInflaterInputStream(JarEntryInputStream inputStream, NestedJarFileResources resources,\n\t\t\t\tInflater inflater) {\n\t\t\tsuper(inputStream, inflater, inputStream.getUncompressedSize());\n\t\t\tthis.cleanup = NestedJarFile.this.cleaner.register(this, resources.createInflatorCleanupAction(inflater));\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tif (this.closed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.closed = true;\n\t\t\tsuper.close();\n\t\t\tNestedJarFile.this.resources.removeInputStream(this);\n\t\t\tthis.cleanup.clean();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link InputStream} for raw zip data.\n\t */\n\tprivate class RawZipDataInputStream extends FilterInputStream {\n\n\t\tprivate volatile boolean closed;\n\n\t\tRawZipDataInputStream(InputStream in) {\n\t\t\tsuper(in);\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tif (this.closed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.closed = true;\n\t\t\tsuper.close();\n\t\t\tNestedJarFile.this.resources.removeInputStream(this);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/NestedJarFileResources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.util.ArrayDeque;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.WeakHashMap;\nimport java.util.zip.Inflater;\n\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.zip.ZipContent;\nimport org.springframework.boot.loader.zip.ZipContent.Kind;\n\n/**\n * Resources created managed and cleaned by a {@link NestedJarFile} instance and suitable\n * for registration with a {@link Cleaner}.\n *\n * @author Phillip Webb\n */\nclass NestedJarFileResources implements Runnable {\n\n\tprivate static final int INFLATER_CACHE_LIMIT = 20;\n\n\tprivate ZipContent zipContent;\n\n\tprivate ZipContent zipContentForManifest;\n\n\tprivate final Set<InputStream> inputStreams = Collections.newSetFromMap(new WeakHashMap<>());\n\n\tprivate Deque<Inflater> inflaterCache = new ArrayDeque<>();\n\n\t/**\n\t * Create a new {@link NestedJarFileResources} instance.\n\t * @param file the source zip file\n\t * @param nestedEntryName the nested entry or {@code null}\n\t * @throws IOException on I/O error\n\t */\n\tNestedJarFileResources(File file, String nestedEntryName) throws IOException {\n\t\tthis.zipContent = ZipContent.open(file.toPath(), nestedEntryName);\n\t\tthis.zipContentForManifest = (this.zipContent.getKind() != Kind.NESTED_DIRECTORY) ? null\n\t\t\t\t: ZipContent.open(file.toPath());\n\t}\n\n\t/**\n\t * Return the underling {@link ZipContent}.\n\t * @return the zip content\n\t */\n\tZipContent zipContent() {\n\t\treturn this.zipContent;\n\t}\n\n\t/**\n\t * Return the underlying {@link ZipContent} that should be used to load manifest\n\t * content.\n\t * @return the zip content to use when loading the manifest\n\t */\n\tZipContent zipContentForManifest() {\n\t\treturn (this.zipContentForManifest != null) ? this.zipContentForManifest : this.zipContent;\n\t}\n\n\t/**\n\t * Add a managed input stream resource.\n\t * @param inputStream the input stream\n\t */\n\tvoid addInputStream(InputStream inputStream) {\n\t\tsynchronized (this.inputStreams) {\n\t\t\tthis.inputStreams.add(inputStream);\n\t\t}\n\t}\n\n\t/**\n\t * Remove a managed input stream resource.\n\t * @param inputStream the input stream\n\t */\n\tvoid removeInputStream(InputStream inputStream) {\n\t\tsynchronized (this.inputStreams) {\n\t\t\tthis.inputStreams.remove(inputStream);\n\t\t}\n\t}\n\n\t/**\n\t * Create a {@link Runnable} action to cleanup the given inflater.\n\t * @param inflater the inflater to cleanup\n\t * @return the cleanup action\n\t */\n\tRunnable createInflatorCleanupAction(Inflater inflater) {\n\t\treturn () -> endOrCacheInflater(inflater);\n\t}\n\n\t/**\n\t * Get previously used {@link Inflater} from the cache, or create a new one.\n\t * @return a usable {@link Inflater}\n\t */\n\tInflater getOrCreateInflater() {\n\t\tDeque<Inflater> inflaterCache = this.inflaterCache;\n\t\tif (inflaterCache != null) {\n\t\t\tsynchronized (inflaterCache) {\n\t\t\t\tInflater inflater = this.inflaterCache.poll();\n\t\t\t\tif (inflater != null) {\n\t\t\t\t\treturn inflater;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new Inflater(true);\n\t}\n\n\t/**\n\t * Either release the given {@link Inflater} by calling {@link Inflater#end()} or add\n\t * it to the cache for later reuse.\n\t * @param inflater the inflater to end or cache\n\t */\n\tprivate void endOrCacheInflater(Inflater inflater) {\n\t\tDeque<Inflater> inflaterCache = this.inflaterCache;\n\t\tif (inflaterCache != null) {\n\t\t\tsynchronized (inflaterCache) {\n\t\t\t\tif (this.inflaterCache == inflaterCache && inflaterCache.size() < INFLATER_CACHE_LIMIT) {\n\t\t\t\t\tinflater.reset();\n\t\t\t\t\tthis.inflaterCache.add(inflater);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tinflater.end();\n\t}\n\n\t/**\n\t * Called by the {@link Cleaner} to free resources.\n\t * @see java.lang.Runnable#run()\n\t */\n\t@Override\n\tpublic void run() {\n\t\treleaseAll();\n\t}\n\n\tprivate void releaseAll() {\n\t\tIOException exceptionChain = null;\n\t\texceptionChain = releaseInflators(exceptionChain);\n\t\texceptionChain = releaseInputStreams(exceptionChain);\n\t\texceptionChain = releaseZipContent(exceptionChain);\n\t\texceptionChain = releaseZipContentForManifest(exceptionChain);\n\t\tif (exceptionChain != null) {\n\t\t\tthrow new UncheckedIOException(exceptionChain);\n\t\t}\n\t}\n\n\tprivate IOException releaseInflators(IOException exceptionChain) {\n\t\tDeque<Inflater> inflaterCache = this.inflaterCache;\n\t\tif (inflaterCache != null) {\n\t\t\ttry {\n\t\t\t\tsynchronized (inflaterCache) {\n\t\t\t\t\tinflaterCache.forEach(Inflater::end);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.inflaterCache = null;\n\t\t\t}\n\t\t}\n\t\treturn exceptionChain;\n\t}\n\n\tprivate IOException releaseInputStreams(IOException exceptionChain) {\n\t\tsynchronized (this.inputStreams) {\n\t\t\tfor (InputStream inputStream : List.copyOf(this.inputStreams)) {\n\t\t\t\ttry {\n\t\t\t\t\tinputStream.close();\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\texceptionChain = addToExceptionChain(exceptionChain, ex);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.inputStreams.clear();\n\t\t}\n\t\treturn exceptionChain;\n\t}\n\n\tprivate IOException releaseZipContent(IOException exceptionChain) {\n\t\tZipContent zipContent = this.zipContent;\n\t\tif (zipContent != null) {\n\t\t\ttry {\n\t\t\t\tzipContent.close();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\texceptionChain = addToExceptionChain(exceptionChain, ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.zipContent = null;\n\t\t\t}\n\t\t}\n\t\treturn exceptionChain;\n\t}\n\n\tprivate IOException releaseZipContentForManifest(IOException exceptionChain) {\n\t\tZipContent zipContentForManifest = this.zipContentForManifest;\n\t\tif (zipContentForManifest != null) {\n\t\t\ttry {\n\t\t\t\tzipContentForManifest.close();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\texceptionChain = addToExceptionChain(exceptionChain, ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.zipContentForManifest = null;\n\t\t\t}\n\t\t}\n\t\treturn exceptionChain;\n\t}\n\n\tprivate IOException addToExceptionChain(IOException exceptionChain, IOException ex) {\n\t\tif (exceptionChain != null) {\n\t\t\texceptionChain.addSuppressed(ex);\n\t\t\treturn exceptionChain;\n\t\t}\n\t\treturn ex;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/SecurityInfo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.security.CodeSigner;\nimport java.security.cert.Certificate;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarInputStream;\n\nimport org.springframework.boot.loader.zip.ZipContent;\n\n/**\n * Security information ({@link Certificate} and {@link CodeSigner} details) for entries\n * in the jar.\n *\n * @author Phillip Webb\n */\nfinal class SecurityInfo {\n\n\tstatic final SecurityInfo NONE = new SecurityInfo(null, null);\n\n\tprivate final Certificate[][] certificateLookups;\n\n\tprivate final CodeSigner[][] codeSignerLookups;\n\n\tprivate SecurityInfo(Certificate[][] entryCertificates, CodeSigner[][] entryCodeSigners) {\n\t\tthis.certificateLookups = entryCertificates;\n\t\tthis.codeSignerLookups = entryCodeSigners;\n\t}\n\n\tCertificate[] getCertificates(ZipContent.Entry contentEntry) {\n\t\treturn (this.certificateLookups != null) ? clone(this.certificateLookups[contentEntry.getLookupIndex()]) : null;\n\t}\n\n\tCodeSigner[] getCodeSigners(ZipContent.Entry contentEntry) {\n\t\treturn (this.codeSignerLookups != null) ? clone(this.codeSignerLookups[contentEntry.getLookupIndex()]) : null;\n\t}\n\n\tprivate <T> T[] clone(T[] array) {\n\t\treturn (array != null) ? array.clone() : null;\n\t}\n\n\t/**\n\t * Get the {@link SecurityInfo} for the given {@link ZipContent}.\n\t * @param content the zip content\n\t * @return the security info\n\t */\n\tstatic SecurityInfo get(ZipContent content) {\n\t\tif (!content.hasJarSignatureFile()) {\n\t\t\treturn NONE;\n\t\t}\n\t\ttry {\n\t\t\treturn load(content);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Load security info from the jar file. We need to use {@link JarInputStream} to\n\t * obtain the security info since we don't have an actual real file to read. This\n\t * isn't that fast, but hopefully doesn't happen too often and the result is cached.\n\t * @param content the zip content\n\t * @return the security info\n\t * @throws IOException on I/O error\n\t */\n\t@SuppressWarnings(\"resource\")\n\tprivate static SecurityInfo load(ZipContent content) throws IOException {\n\t\tint size = content.size();\n\t\tboolean hasSecurityInfo = false;\n\t\tCertificate[][] entryCertificates = new Certificate[size][];\n\t\tCodeSigner[][] entryCodeSigners = new CodeSigner[size][];\n\t\ttry (JarEntriesStream entries = new JarEntriesStream(content.openRawZipData().asInputStream())) {\n\t\t\tJarEntry entry = entries.getNextEntry();\n\t\t\twhile (entry != null) {\n\t\t\t\tZipContent.Entry relatedEntry = content.getEntry(entry.getName());\n\t\t\t\tif (relatedEntry != null && entries.matches(relatedEntry.isDirectory(),\n\t\t\t\t\t\trelatedEntry.getUncompressedSize(), relatedEntry.getCompressionMethod(),\n\t\t\t\t\t\t() -> relatedEntry.openContent().asInputStream())) {\n\t\t\t\t\tCertificate[] certificates = entry.getCertificates();\n\t\t\t\t\tCodeSigner[] codeSigners = entry.getCodeSigners();\n\t\t\t\t\tif (certificates != null || codeSigners != null) {\n\t\t\t\t\t\thasSecurityInfo = true;\n\t\t\t\t\t\tentryCertificates[relatedEntry.getLookupIndex()] = certificates;\n\t\t\t\t\t\tentryCodeSigners[relatedEntry.getLookupIndex()] = codeSigners;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tentry = entries.getNextEntry();\n\t\t\t}\n\t\t}\n\t\treturn (!hasSecurityInfo) ? NONE : new SecurityInfo(entryCertificates, entryCodeSigners);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/ZipInflaterInputStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.zip.Inflater;\nimport java.util.zip.InflaterInputStream;\n\n/**\n * {@link InflaterInputStream} that supports the writing of an extra \"dummy\" byte (which\n * is required when using an {@link Inflater} with {@code nowrap}) and returns accurate\n * available() results.\n *\n * @author Phillip Webb\n */\nclass ZipInflaterInputStream extends InflaterInputStream {\n\n\tprivate int available;\n\n\tprivate boolean extraBytesWritten;\n\n\tZipInflaterInputStream(InputStream inputStream, Inflater inflater, int size) {\n\t\tsuper(inputStream, inflater, getInflaterBufferSize(size));\n\t\tthis.available = size;\n\t}\n\n\tprivate static int getInflaterBufferSize(long size) {\n\t\tsize += 2; // inflater likes some space\n\t\tsize = (size > 65536) ? 8192 : size;\n\t\tsize = (size <= 0) ? 4096 : size;\n\t\treturn (int) size;\n\t}\n\n\t@Override\n\tpublic int available() throws IOException {\n\t\treturn (this.available >= 0) ? this.available : super.available();\n\t}\n\n\t@Override\n\tpublic int read(byte[] b, int off, int len) throws IOException {\n\t\tint result = super.read(b, off, len);\n\t\tif (result != -1) {\n\t\t\tthis.available -= result;\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tprotected void fill() throws IOException {\n\t\ttry {\n\t\t\tsuper.fill();\n\t\t}\n\t\tcatch (EOFException ex) {\n\t\t\tif (this.extraBytesWritten) {\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tthis.len = 1;\n\t\t\tthis.buf[0] = 0x0;\n\t\t\tthis.extraBytesWritten = true;\n\t\t\tthis.inf.setInput(this.buf, 0, this.len);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Alternative {@link java.util.jar.JarFile} implementation with support for nested jars.\n * @see org.springframework.boot.loader.jar.NestedJarFile\n */\npackage org.springframework.boot.loader.jar;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarMode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jarmode;\n\n/**\n * Interface registered in {@code spring.factories} to provides extended 'jarmode'\n * support.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface JarMode {\n\n\t/**\n\t * Returns if this accepts and can run the given mode.\n\t * @param mode the mode to check\n\t * @return if this instance accepts the mode\n\t */\n\tboolean accepts(String mode);\n\n\t/**\n\t * Run the jar in the given mode.\n\t * @param mode the mode to use\n\t * @param args any program arguments\n\t * @throws JarModeErrorException on an error that should print a simple error message\n\t */\n\tvoid run(String mode, String[] args) throws JarModeErrorException;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/JarModeErrorException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jarmode;\n\n/**\n * Simple {@link RuntimeException} used to fail the jar mode with a simple printed error\n * message.\n *\n * @author Phillip Webb\n * @since 3.3.7\n */\npublic class JarModeErrorException extends RuntimeException {\n\n\tpublic JarModeErrorException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic JarModeErrorException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/jarmode/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for launching the JAR using jarmode.\n */\npackage org.springframework.boot.loader.jarmode;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/Archive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.file.Path;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.jar.Manifest;\n\n/**\n * An archive that can be launched by the {@link Launcher}.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic interface Archive extends AutoCloseable {\n\n\t/**\n\t * Predicate that accepts all entries.\n\t */\n\tPredicate<Entry> ALL_ENTRIES = (entry) -> true;\n\n\t/**\n\t * Returns the manifest of the archive.\n\t * @return the manifest or {@code null}\n\t * @throws IOException if the manifest cannot be read\n\t */\n\tManifest getManifest() throws IOException;\n\n\t/**\n\t * Returns classpath URLs for the archive that match the specified filter.\n\t * @param includeFilter filter used to determine which entries should be included.\n\t * @return the classpath URLs\n\t * @throws IOException on IO error\n\t */\n\tdefault Set<URL> getClassPathUrls(Predicate<Entry> includeFilter) throws IOException {\n\t\treturn getClassPathUrls(includeFilter, ALL_ENTRIES);\n\n\t}\n\n\t/**\n\t * Returns classpath URLs for the archive that match the specified filters.\n\t * @param includeFilter filter used to determine which entries should be included\n\t * @param directorySearchFilter filter used to optimize tree walking for exploded\n\t * archives by determining if a directory needs to be searched or not\n\t * @return the classpath URLs\n\t * @throws IOException on IO error\n\t */\n\tSet<URL> getClassPathUrls(Predicate<Entry> includeFilter, Predicate<Entry> directorySearchFilter)\n\t\t\tthrows IOException;\n\n\t/**\n\t * Returns if this archive is backed by an exploded archive directory.\n\t * @return if the archive is exploded\n\t */\n\tdefault boolean isExploded() {\n\t\treturn getRootDirectory() != null;\n\t}\n\n\t/**\n\t * Returns the root directory of this archive or {@code null} if the archive is not\n\t * backed by a directory.\n\t * @return the root directory\n\t */\n\tdefault File getRootDirectory() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Closes the {@code Archive}, releasing any open resources.\n\t * @throws Exception if an error occurs during close processing\n\t */\n\t@Override\n\tdefault void close() throws Exception {\n\t}\n\n\t/**\n\t * Factory method to create an appropriate {@link Archive} from the given\n\t * {@link Class} target.\n\t * @param target a target class that will be used to find the archive code source\n\t * @return a new {@link Archive} instance\n\t * @throws Exception if the archive cannot be created\n\t */\n\tstatic Archive create(Class<?> target) throws Exception {\n\t\treturn create(target.getProtectionDomain());\n\t}\n\n\tstatic Archive create(ProtectionDomain protectionDomain) throws Exception {\n\t\tCodeSource codeSource = protectionDomain.getCodeSource();\n\t\tURI location = (codeSource != null) ? codeSource.getLocation().toURI() : null;\n\t\tif (location == null) {\n\t\t\tthrow new IllegalStateException(\"Unable to determine code source archive\");\n\t\t}\n\t\treturn create(Path.of(location).toFile());\n\t}\n\n\t/**\n\t * Factory method to create an {@link Archive} from the given {@link File} target.\n\t * @param target a target {@link File} used to create the archive. May be a directory\n\t * or a jar file.\n\t * @return a new {@link Archive} instance.\n\t * @throws Exception if the archive cannot be created\n\t */\n\tstatic Archive create(File target) throws Exception {\n\t\tif (!target.exists()) {\n\t\t\tthrow new IllegalStateException(\"Unable to determine code source archive from \" + target);\n\t\t}\n\t\treturn (target.isDirectory() ? new ExplodedArchive(target) : new JarFileArchive(target));\n\t}\n\n\t/**\n\t * Represents a single entry in the archive.\n\t */\n\tinterface Entry {\n\n\t\t/**\n\t\t * Returns the name of the entry.\n\t\t * @return the name of the entry\n\t\t */\n\t\tString name();\n\n\t\t/**\n\t\t * Returns {@code true} if the entry represents a directory.\n\t\t * @return if the entry is a directory\n\t\t */\n\t\tboolean isDirectory();\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/ClassPathIndexFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * A class path index file that provides an ordered classpath for exploded JARs.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nfinal class ClassPathIndexFile {\n\n\tprivate final File root;\n\n\tprivate final Set<String> lines;\n\n\tprivate ClassPathIndexFile(File root, List<String> lines) {\n\t\tthis.root = root;\n\t\tthis.lines = lines.stream().map(this::extractName).collect(Collectors.toCollection(LinkedHashSet::new));\n\t}\n\n\tprivate String extractName(String line) {\n\t\tif (line.startsWith(\"- \\\"\") && line.endsWith(\"\\\"\")) {\n\t\t\treturn line.substring(3, line.length() - 1);\n\t\t}\n\t\tthrow new IllegalStateException(\"Malformed classpath index line [\" + line + \"]\");\n\t}\n\n\tint size() {\n\t\treturn this.lines.size();\n\t}\n\n\tboolean containsEntry(String name) {\n\t\tif (name == null || name.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.lines.contains(name);\n\t}\n\n\tList<URL> getUrls() {\n\t\treturn this.lines.stream().map(this::asUrl).toList();\n\t}\n\n\tprivate URL asUrl(String line) {\n\t\ttry {\n\t\t\treturn new File(this.root, line).toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tstatic ClassPathIndexFile loadIfPossible(File root, String location) throws IOException {\n\t\treturn loadIfPossible(root, new File(root, location));\n\t}\n\n\tprivate static ClassPathIndexFile loadIfPossible(File root, File indexFile) throws IOException {\n\t\tif (indexFile.exists() && indexFile.isFile()) {\n\t\t\tList<String> lines = Files.readAllLines(indexFile.toPath())\n\t\t\t\t.stream()\n\t\t\t\t.filter(ClassPathIndexFile::lineHasText)\n\t\t\t\t.toList();\n\t\t\treturn new ClassPathIndexFile(root, lines);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static boolean lineHasText(String line) {\n\t\treturn !line.trim().isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/ExecutableArchiveLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Set;\nimport java.util.jar.Manifest;\n\n/**\n * Base class for a {@link Launcher} backed by an executable archive.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 3.2.0\n * @see JarLauncher\n * @see WarLauncher\n */\npublic abstract class ExecutableArchiveLauncher extends Launcher {\n\n\tprivate static final String START_CLASS_ATTRIBUTE = \"Start-Class\";\n\n\tprivate final Archive archive;\n\n\tpublic ExecutableArchiveLauncher() throws Exception {\n\t\tthis(Archive.create(Launcher.class));\n\t}\n\n\tprotected ExecutableArchiveLauncher(Archive archive) throws Exception {\n\t\tthis.archive = archive;\n\t\tthis.classPathIndex = getClassPathIndex(this.archive);\n\t}\n\n\t@Override\n\tprotected ClassLoader createClassLoader(Collection<URL> urls) throws Exception {\n\t\tif (this.classPathIndex != null) {\n\t\t\turls = new ArrayList<>(urls);\n\t\t\turls.addAll(this.classPathIndex.getUrls());\n\t\t}\n\t\treturn super.createClassLoader(urls);\n\t}\n\n\t@Override\n\tprotected final Archive getArchive() {\n\t\treturn this.archive;\n\t}\n\n\t@Override\n\tprotected String getMainClass() throws Exception {\n\t\tManifest manifest = this.archive.getManifest();\n\t\tString mainClass = (manifest != null) ? manifest.getMainAttributes().getValue(START_CLASS_ATTRIBUTE) : null;\n\t\tif (mainClass == null) {\n\t\t\tthrow new IllegalStateException(\"No 'Start-Class' manifest entry specified in \" + this);\n\t\t}\n\t\treturn mainClass;\n\t}\n\n\t@Override\n\tprotected Set<URL> getClassPathUrls() throws Exception {\n\t\treturn this.archive.getClassPathUrls(this::isIncludedOnClassPathAndNotIndexed, this::isSearchedDirectory);\n\t}\n\n\t/**\n\t * Determine if the specified directory entry is a candidate for further searching.\n\t * @param entry the entry to check\n\t * @return {@code true} if the entry is a candidate for further searching\n\t */\n\tprotected boolean isSearchedDirectory(Archive.Entry entry) {\n\t\treturn ((getEntryPathPrefix() == null) || entry.name().startsWith(getEntryPathPrefix()))\n\t\t\t\t&& !isIncludedOnClassPath(entry);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/ExplodedArchive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.jar.Manifest;\n\n/**\n * {@link Archive} implementation backed by an exploded archive directory.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass ExplodedArchive implements Archive {\n\n\tprivate static final Object NO_MANIFEST = new Object();\n\n\tprivate static final Set<String> SKIPPED_NAMES = Set.of(\".\", \"..\");\n\n\tprivate static final Comparator<File> entryComparator = Comparator.comparing(File::getAbsolutePath);\n\n\tprivate final File rootDirectory;\n\n\tprivate final String rootUriPath;\n\n\tprivate volatile Object manifest;\n\n\t/**\n\t * Create a new {@link ExplodedArchive} instance.\n\t * @param rootDirectory the root directory\n\t */\n\tExplodedArchive(File rootDirectory) {\n\t\tif (!rootDirectory.exists() || !rootDirectory.isDirectory()) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid source directory \" + rootDirectory);\n\t\t}\n\t\tthis.rootDirectory = rootDirectory;\n\t\tthis.rootUriPath = ExplodedArchive.this.rootDirectory.toURI().getPath();\n\t}\n\n\t@Override\n\tpublic Manifest getManifest() throws IOException {\n\t\tObject manifest = this.manifest;\n\t\tif (manifest == null) {\n\t\t\tmanifest = loadManifest();\n\t\t\tthis.manifest = manifest;\n\t\t}\n\t\treturn (manifest != NO_MANIFEST) ? (Manifest) manifest : null;\n\t}\n\n\tprivate Object loadManifest() throws IOException {\n\t\tFile file = new File(this.rootDirectory, \"META-INF/MANIFEST.MF\");\n\t\tif (!file.exists()) {\n\t\t\treturn NO_MANIFEST;\n\t\t}\n\t\ttry (FileInputStream inputStream = new FileInputStream(file)) {\n\t\t\treturn new Manifest(inputStream);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Set<URL> getClassPathUrls(Predicate<Entry> includeFilter, Predicate<Entry> directorySearchFilter)\n\t\t\tthrows IOException {\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tLinkedList<File> files = new LinkedList<>(listFiles(this.rootDirectory));\n\t\twhile (!files.isEmpty()) {\n\t\t\tFile file = files.poll();\n\t\t\tif (SKIPPED_NAMES.contains(file.getName())) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tString entryName = file.toURI().getPath().substring(this.rootUriPath.length());\n\t\t\tEntry entry = new FileArchiveEntry(entryName, file);\n\t\t\tif (entry.isDirectory() && directorySearchFilter.test(entry)) {\n\t\t\t\tfiles.addAll(0, listFiles(file));\n\t\t\t}\n\t\t\tif (includeFilter.test(entry)) {\n\t\t\t\turls.add(file.toURI().toURL());\n\t\t\t}\n\t\t}\n\t\treturn urls;\n\t}\n\n\tprivate List<File> listFiles(File file) {\n\t\tFile[] files = file.listFiles();\n\t\tif (files == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tArrays.sort(files, entryComparator);\n\t\treturn Arrays.asList(files);\n\t}\n\n\t@Override\n\tpublic File getRootDirectory() {\n\t\treturn this.rootDirectory;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.rootDirectory.toString();\n\t}\n\n\t/**\n\t * {@link Entry} backed by a File.\n\t */\n\tprivate record FileArchiveEntry(String name, File file) implements Entry {\n\n\t\t@Override\n\t\tpublic boolean isDirectory() {\n\t\t\treturn this.file.isDirectory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarFileArchive.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.net.URL;\nimport java.nio.file.FileSystem;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\nimport java.nio.file.attribute.FileAttribute;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.function.Predicate;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\n\n/**\n * {@link Archive} implementation backed by a {@link JarFile}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass JarFileArchive implements Archive {\n\n\tprivate static final String UNPACK_MARKER = \"UNPACK\";\n\n\tprivate static final FileAttribute<?>[] NO_FILE_ATTRIBUTES = {};\n\n\tprivate static final FileAttribute<?>[] DIRECTORY_PERMISSION_ATTRIBUTES = asFileAttributes(\n\t\t\tPosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);\n\n\tprivate static final FileAttribute<?>[] FILE_PERMISSION_ATTRIBUTES = asFileAttributes(\n\t\t\tPosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE);\n\n\tprivate static final Path TEMP = Paths.get(System.getProperty(\"java.io.tmpdir\"));\n\n\tprivate final File file;\n\n\tprivate final JarFile jarFile;\n\n\tprivate volatile Path tempUnpackDirectory;\n\n\tJarFileArchive(File file) throws IOException {\n\t\tthis(file, new JarFile(file));\n\t}\n\n\tprivate JarFileArchive(File file, JarFile jarFile) {\n\t\tthis.file = file;\n\t\tthis.jarFile = jarFile;\n\t}\n\n\t@Override\n\tpublic Manifest getManifest() throws IOException {\n\t\treturn this.jarFile.getManifest();\n\t}\n\n\t@Override\n\tpublic Set<URL> getClassPathUrls(Predicate<Entry> includeFilter, Predicate<Entry> directorySearchFilter)\n\t\t\tthrows IOException {\n\t\treturn this.jarFile.stream()\n\t\t\t.map(JarArchiveEntry::new)\n\t\t\t.filter(includeFilter)\n\t\t\t.map(this::getNestedJarUrl)\n\t\t\t.collect(Collectors.toCollection(LinkedHashSet::new));\n\t}\n\n\tprivate URL getNestedJarUrl(JarArchiveEntry archiveEntry) {\n\t\ttry {\n\t\t\tJarEntry jarEntry = archiveEntry.jarEntry();\n\t\t\tString comment = jarEntry.getComment();\n\t\t\tif (comment != null && comment.startsWith(UNPACK_MARKER)) {\n\t\t\t\treturn getUnpackedNestedJarUrl(jarEntry);\n\t\t\t}\n\t\t\treturn JarUrl.create(this.file, jarEntry);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate URL getUnpackedNestedJarUrl(JarEntry jarEntry) throws IOException {\n\t\tString name = jarEntry.getName();\n\t\tif (name.lastIndexOf('/') != -1) {\n\t\t\tname = name.substring(name.lastIndexOf('/') + 1);\n\t\t}\n\t\tPath path = getTempUnpackDirectory().resolve(name);\n\t\tif (!Files.exists(path) || Files.size(path) != jarEntry.getSize()) {\n\t\t\tunpack(jarEntry, path);\n\t\t}\n\t\treturn path.toUri().toURL();\n\t}\n\n\tprivate Path getTempUnpackDirectory() {\n\t\tPath tempUnpackDirectory = this.tempUnpackDirectory;\n\t\tif (tempUnpackDirectory != null) {\n\t\t\treturn tempUnpackDirectory;\n\t\t}\n\t\tsynchronized (TEMP) {\n\t\t\ttempUnpackDirectory = this.tempUnpackDirectory;\n\t\t\tif (tempUnpackDirectory == null) {\n\t\t\t\ttempUnpackDirectory = createUnpackDirectory(TEMP);\n\t\t\t\tthis.tempUnpackDirectory = tempUnpackDirectory;\n\t\t\t}\n\t\t}\n\t\treturn tempUnpackDirectory;\n\t}\n\n\tprivate Path createUnpackDirectory(Path parent) {\n\t\tint attempts = 0;\n\t\tString fileName = Paths.get(this.jarFile.getName()).getFileName().toString();\n\t\twhile (attempts++ < 100) {\n\t\t\tPath unpackDirectory = parent.resolve(fileName + \"-spring-boot-libs-\" + UUID.randomUUID());\n\t\t\ttry {\n\t\t\t\tcreateDirectory(unpackDirectory);\n\t\t\t\treturn unpackDirectory;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Failed to create unpack directory in directory '\" + parent + \"'\");\n\t}\n\n\tprivate void createDirectory(Path path) throws IOException {\n\t\tFiles.createDirectory(path, getFileAttributes(path, DIRECTORY_PERMISSION_ATTRIBUTES));\n\t}\n\n\tprivate void unpack(JarEntry entry, Path path) throws IOException {\n\t\tcreateFile(path);\n\t\tpath.toFile().deleteOnExit();\n\t\ttry (InputStream in = this.jarFile.getInputStream(entry)) {\n\t\t\tFiles.copy(in, path, StandardCopyOption.REPLACE_EXISTING);\n\t\t}\n\t}\n\n\tprivate void createFile(Path path) throws IOException {\n\t\tFiles.createFile(path, getFileAttributes(path, FILE_PERMISSION_ATTRIBUTES));\n\t}\n\n\tprivate FileAttribute<?>[] getFileAttributes(Path path, FileAttribute<?>[] permissionAttributes) {\n\t\treturn (!supportsPosix(path.getFileSystem())) ? NO_FILE_ATTRIBUTES : permissionAttributes;\n\t}\n\n\tprivate boolean supportsPosix(FileSystem fileSystem) {\n\t\treturn fileSystem.supportedFileAttributeViews().contains(\"posix\");\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.jarFile.close();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.file.toString();\n\t}\n\n\tprivate static FileAttribute<?>[] asFileAttributes(PosixFilePermission... permissions) {\n\t\treturn new FileAttribute<?>[] { PosixFilePermissions.asFileAttribute(Set.of(permissions)) };\n\t}\n\n\t/**\n\t * {@link Entry} implementation backed by a {@link JarEntry}.\n\t */\n\tprivate record JarArchiveEntry(JarEntry jarEntry) implements Entry {\n\n\t\t@Override\n\t\tpublic String name() {\n\t\t\treturn this.jarEntry.getName();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isDirectory() {\n\t\t\treturn this.jarEntry.isDirectory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\n/**\n * {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are\n * included inside a {@code /BOOT-INF/lib} directory and that application classes are\n * included inside a {@code /BOOT-INF/classes} directory.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 3.2.0\n */\npublic class JarLauncher extends ExecutableArchiveLauncher {\n\n\tpublic JarLauncher() throws Exception {\n\t}\n\n\tprotected JarLauncher(Archive archive) throws Exception {\n\t\tsuper(archive);\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tnew JarLauncher().launch(args);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/JarModeRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.util.List;\n\nimport org.springframework.boot.loader.jarmode.JarMode;\nimport org.springframework.boot.loader.jarmode.JarModeErrorException;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Delegate class used to run the nested jar in a specific mode.\n *\n * @author Phillip Webb\n */\nfinal class JarModeRunner {\n\n\tstatic final String DISABLE_SYSTEM_EXIT = JarModeRunner.class.getName() + \".DISABLE_SYSTEM_EXIT\";\n\n\tstatic final String SUPPRESSED_SYSTEM_EXIT_CODE = JarModeRunner.class.getName() + \".SUPPRESSED_SYSTEM_EXIT_CODE\";\n\n\tprivate JarModeRunner() {\n\t}\n\n\tstatic void main(String[] args) {\n\t\tString mode = System.getProperty(\"jarmode\");\n\t\tboolean disableSystemExit = Boolean.getBoolean(DISABLE_SYSTEM_EXIT);\n\t\ttry {\n\t\t\trunJarMode(mode, args);\n\t\t\tif (disableSystemExit) {\n\t\t\t\tSystem.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, \"0\");\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tprintError(ex);\n\t\t\tif (disableSystemExit) {\n\t\t\t\tSystem.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, \"1\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tSystem.exit(1);\n\t\t}\n\t}\n\n\tprivate static void runJarMode(String mode, String[] args) {\n\t\tList<JarMode> candidates = SpringFactoriesLoader.loadFactories(JarMode.class,\n\t\t\t\tClassUtils.getDefaultClassLoader());\n\t\tfor (JarMode candidate : candidates) {\n\t\t\tif (candidate.accepts(mode)) {\n\t\t\t\tcandidate.run(mode, args);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthrow new JarModeErrorException(\"Unsupported jarmode '\" + mode + \"'\");\n\t}\n\n\tprivate static void printError(Throwable ex) {\n\t\tif (ex instanceof JarModeErrorException) {\n\t\t\tString message = ex.getMessage();\n\t\t\tSystem.err.println(\"Error: \" + message);\n\t\t\tSystem.err.println();\n\t\t\treturn;\n\t\t}\n\t\tex.printStackTrace();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/LaunchedClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.function.Supplier;\nimport java.util.jar.Manifest;\n\nimport org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader;\n\n/**\n * {@link ClassLoader} used by the {@link Launcher}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 3.2.0\n */\npublic class LaunchedClassLoader extends JarUrlClassLoader {\n\n\tprivate static final String JAR_MODE_PACKAGE_PREFIX = \"org.springframework.boot.loader.jarmode.\";\n\n\tprivate static final String JAR_MODE_RUNNER_CLASS_NAME = JarModeRunner.class.getName();\n\n\tstatic {\n\t\tClassLoader.registerAsParallelCapable();\n\t}\n\n\tprivate final boolean exploded;\n\n\tprivate final Archive rootArchive;\n\n\tprivate final Object definePackageLock = new Object();\n\n\tprivate volatile DefinePackageCallType definePackageCallType;\n\n\t/**\n\t * Create a new {@link LaunchedClassLoader} instance.\n\t * @param exploded if the underlying archive is exploded\n\t * @param urls the URLs from which to load classes and resources\n\t * @param parent the parent class loader for delegation\n\t */\n\tpublic LaunchedClassLoader(boolean exploded, URL[] urls, ClassLoader parent) {\n\t\tthis(exploded, null, urls, parent);\n\t}\n\n\t/**\n\t * Create a new {@link LaunchedClassLoader} instance.\n\t * @param exploded if the underlying archive is exploded\n\t * @param rootArchive the root archive or {@code null}\n\t * @param urls the URLs from which to load classes and resources\n\t * @param parent the parent class loader for delegation\n\t */\n\tpublic LaunchedClassLoader(boolean exploded, Archive rootArchive, URL[] urls, ClassLoader parent) {\n\t\tsuper(urls, parent);\n\t\tthis.exploded = exploded;\n\t\tthis.rootArchive = rootArchive;\n\t}\n\n\t@Override\n\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\tif (name.startsWith(JAR_MODE_PACKAGE_PREFIX) || name.equals(JAR_MODE_RUNNER_CLASS_NAME)) {\n\t\t\ttry {\n\t\t\t\tClass<?> result = loadClassInLaunchedClassLoader(name);\n\t\t\t\tif (resolve) {\n\t\t\t\t\tresolveClass(result);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn super.loadClass(name, resolve);\n\t}\n\n\tprivate Class<?> loadClassInLaunchedClassLoader(String name) throws ClassNotFoundException {\n\t\ttry {\n\t\t\tString internalName = name.replace('.', '/') + \".class\";\n\t\t\ttry (InputStream inputStream = getParent().getResourceAsStream(internalName);\n\t\t\t\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {\n\t\t\t\tif (inputStream == null) {\n\t\t\t\t\tthrow new ClassNotFoundException(name);\n\t\t\t\t}\n\t\t\t\tinputStream.transferTo(outputStream);\n\t\t\t\tbyte[] bytes = outputStream.toByteArray();\n\t\t\t\tClass<?> definedClass = defineClass(name, bytes, 0, bytes.length);\n\t\t\t\tdefinePackageIfNecessary(name);\n\t\t\t\treturn definedClass;\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new ClassNotFoundException(\"Cannot load resource for class [\" + name + \"]\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected Package definePackage(String name, Manifest man, URL url) throws IllegalArgumentException {\n\t\treturn (!this.exploded) ? super.definePackage(name, man, url) : definePackageForExploded(name, man, url);\n\t}\n\n\tprivate Package definePackageForExploded(String name, Manifest man, URL url) {\n\t\tsynchronized (this.definePackageLock) {\n\t\t\treturn definePackage(DefinePackageCallType.MANIFEST, () -> super.definePackage(name, man, url));\n\t\t}\n\t}\n\n\t@Override\n\tprotected Package definePackage(String name, String specTitle, String specVersion, String specVendor,\n\t\t\tString implTitle, String implVersion, String implVendor, URL sealBase) throws IllegalArgumentException {\n\t\tif (!this.exploded) {\n\t\t\treturn super.definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor,\n\t\t\t\t\tsealBase);\n\t\t}\n\t\treturn definePackageForExploded(name, sealBase, () -> super.definePackage(name, specTitle, specVersion,\n\t\t\t\tspecVendor, implTitle, implVersion, implVendor, sealBase));\n\t}\n\n\tprivate Package definePackageForExploded(String name, URL sealBase, Supplier<Package> call) {\n\t\tsynchronized (this.definePackageLock) {\n\t\t\tif (this.definePackageCallType == null) {\n\t\t\t\t// We're not part of a call chain which means that the URLClassLoader\n\t\t\t\t// is trying to define a package for our exploded JAR. We use the\n\t\t\t\t// manifest version to ensure package attributes are set\n\t\t\t\tManifest manifest = getManifest(this.rootArchive);\n\t\t\t\tif (manifest != null) {\n\t\t\t\t\treturn definePackage(name, manifest, sealBase);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn definePackage(DefinePackageCallType.ATTRIBUTES, call);\n\t\t}\n\t}\n\n\tprivate <T> T definePackage(DefinePackageCallType type, Supplier<T> call) {\n\t\tDefinePackageCallType existingType = this.definePackageCallType;\n\t\ttry {\n\t\t\tthis.definePackageCallType = type;\n\t\t\treturn call.get();\n\t\t}\n\t\tfinally {\n\t\t\tthis.definePackageCallType = existingType;\n\t\t}\n\t}\n\n\tprivate Manifest getManifest(Archive archive) {\n\t\ttry {\n\t\t\treturn (archive != null) ? archive.getManifest() : null;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * The different types of call made to define a package. We track these for exploded\n\t * jars so that we can detect packages that should have manifest attributes applied.\n\t */\n\tprivate enum DefinePackageCallType {\n\n\t\t/**\n\t\t * A define package call from a resource that has a manifest.\n\t\t */\n\t\tMANIFEST,\n\n\t\t/**\n\t\t * A define package call with a direct set of attributes.\n\t\t */\n\t\tATTRIBUTES\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/Launcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.lang.reflect.Method;\nimport java.net.URL;\nimport java.util.Collection;\nimport java.util.Set;\nimport java.util.jar.Attributes;\nimport java.util.jar.Manifest;\n\nimport org.springframework.boot.loader.launch.Archive.Entry;\nimport org.springframework.boot.loader.net.protocol.Handlers;\n\n/**\n * Base class for launchers that can start an application with a fully configured\n * classpath.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Scott Frederick\n * @since 3.2.0\n */\npublic abstract class Launcher {\n\n\tprivate static final String JAR_MODE_RUNNER_CLASS_NAME = JarModeRunner.class.getName();\n\n\tprotected static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = \"Spring-Boot-Classpath-Index\";\n\n\tprotected static final String DEFAULT_CLASSPATH_INDEX_FILE_NAME = \"classpath.idx\";\n\n\tprotected ClassPathIndexFile classPathIndex;\n\n\t/**\n\t * Launch the application. This method is the initial entry point that should be\n\t * called by a subclass {@code public static void main(String[] args)} method.\n\t * @param args the incoming arguments\n\t * @throws Exception if the application fails to launch\n\t */\n\tprotected void launch(String[] args) throws Exception {\n\t\tif (!isExploded()) {\n\t\t\tHandlers.register();\n\t\t}\n\t\ttry {\n\t\t\tClassLoader classLoader = createClassLoader(getClassPathUrls());\n\t\t\tString jarMode = System.getProperty(\"jarmode\");\n\t\t\tString mainClassName = hasLength(jarMode) ? JAR_MODE_RUNNER_CLASS_NAME : getMainClass();\n\t\t\tlaunch(classLoader, mainClassName, args);\n\t\t}\n\t\tcatch (UncheckedIOException ex) {\n\t\t\tthrow ex.getCause();\n\t\t}\n\t}\n\n\tprivate boolean hasLength(String jarMode) {\n\t\treturn (jarMode != null) && !jarMode.isEmpty();\n\t}\n\n\t/**\n\t * Create a classloader for the specified archives.\n\t * @param urls the classpath URLs\n\t * @return the classloader\n\t * @throws Exception if the classloader cannot be created\n\t */\n\tprotected ClassLoader createClassLoader(Collection<URL> urls) throws Exception {\n\t\treturn createClassLoader(urls.toArray(new URL[0]));\n\t}\n\n\tprivate ClassLoader createClassLoader(URL[] urls) {\n\t\tClassLoader parent = getClass().getClassLoader();\n\t\treturn new LaunchedClassLoader(isExploded(), getArchive(), urls, parent);\n\t}\n\n\t/**\n\t * Launch the application given the archive file and a fully configured classloader.\n\t * @param classLoader the classloader\n\t * @param mainClassName the main class to run\n\t * @param args the incoming arguments\n\t * @throws Exception if the launch fails\n\t */\n\tprotected void launch(ClassLoader classLoader, String mainClassName, String[] args) throws Exception {\n\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\tClass<?> mainClass = Class.forName(mainClassName, false, classLoader);\n\t\tMethod mainMethod = getMainMethod(mainClass);\n\t\tmainMethod.setAccessible(true);\n\t\tif (mainMethod.getParameterCount() == 0) {\n\t\t\tmainMethod.invoke(null);\n\t\t}\n\t\telse {\n\t\t\tmainMethod.invoke(null, new Object[] { args });\n\t\t}\n\t}\n\n\tprivate Method getMainMethod(Class<?> mainClass) throws Exception {\n\t\ttry {\n\t\t\treturn mainClass.getDeclaredMethod(\"main\", String[].class);\n\t\t}\n\t\tcatch (NoSuchMethodException ex) {\n\t\t\treturn mainClass.getDeclaredMethod(\"main\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns if the launcher is running in an exploded mode. If this method returns\n\t * {@code true} then only regular JARs are supported and the additional URL and\n\t * ClassLoader support infrastructure can be optimized.\n\t * @return if the jar is exploded.\n\t */\n\tprotected boolean isExploded() {\n\t\tArchive archive = getArchive();\n\t\treturn (archive != null) && archive.isExploded();\n\t}\n\n\tClassPathIndexFile getClassPathIndex(Archive archive) throws IOException {\n\t\tif (!archive.isExploded()) {\n\t\t\treturn null; // Regular archives already have a defined order\n\t\t}\n\t\tString location = getClassPathIndexFileLocation(archive);\n\t\treturn ClassPathIndexFile.loadIfPossible(archive.getRootDirectory(), location);\n\t}\n\n\tprivate String getClassPathIndexFileLocation(Archive archive) throws IOException {\n\t\tManifest manifest = archive.getManifest();\n\t\tAttributes attributes = (manifest != null) ? manifest.getMainAttributes() : null;\n\t\tString location = (attributes != null) ? attributes.getValue(BOOT_CLASSPATH_INDEX_ATTRIBUTE) : null;\n\t\treturn (location != null) ? location : getEntryPathPrefix() + DEFAULT_CLASSPATH_INDEX_FILE_NAME;\n\t}\n\n\t/**\n\t * Return the archive being launched or {@code null} if there is no archive.\n\t * @return the launched archive\n\t */\n\tprotected abstract Archive getArchive();\n\n\t/**\n\t * Returns the main class that should be launched.\n\t * @return the name of the main class\n\t * @throws Exception if the main class cannot be obtained\n\t */\n\tprotected abstract String getMainClass() throws Exception;\n\n\t/**\n\t * Returns the archives that will be used to construct the class path.\n\t * @return the class path archives\n\t * @throws Exception if the class path archives cannot be obtained\n\t */\n\tprotected abstract Set<URL> getClassPathUrls() throws Exception;\n\n\t/**\n\t * Return the path prefix for relevant entries in the archive.\n\t * @return the entry path prefix\n\t */\n\tprotected String getEntryPathPrefix() {\n\t\treturn \"BOOT-INF/\";\n\t}\n\n\t/**\n\t * Determine if the specified entry is a nested item that should be added to the\n\t * classpath.\n\t * @param entry the entry to check\n\t * @return {@code true} if the entry is a nested item (jar or directory)\n\t */\n\tprotected boolean isIncludedOnClassPath(Archive.Entry entry) {\n\t\treturn isLibraryFileOrClassesDirectory(entry);\n\t}\n\n\tprotected boolean isLibraryFileOrClassesDirectory(Archive.Entry entry) {\n\t\tString name = entry.name();\n\t\tif (entry.isDirectory()) {\n\t\t\treturn name.equals(\"BOOT-INF/classes/\");\n\t\t}\n\t\treturn name.startsWith(\"BOOT-INF/lib/\");\n\t}\n\n\tprotected boolean isIncludedOnClassPathAndNotIndexed(Entry entry) {\n\t\tif (!isIncludedOnClassPath(entry)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (this.classPathIndex == null) || !this.classPathIndex.containsEntry(entry.name());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/PropertiesLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Constructor;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.Predicate;\nimport java.util.jar.Manifest;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.springframework.boot.loader.launch.Archive.Entry;\nimport org.springframework.boot.loader.log.DebugLogger;\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\n\n/**\n * {@link Launcher} for archives with user-configured classpath and main class through a\n * properties file.\n * <p>\n * Looks in various places for a properties file to extract loader settings, defaulting to\n * {@code loader.properties} either on the current classpath or in the current working\n * directory. The name of the properties file can be changed by setting a System property\n * {@code loader.config.name} (e.g. {@code -Dloader.config.name=my} will look for\n * {@code my.properties}. If that file doesn't exist then tries\n * {@code loader.config.location} (with allowed prefixes {@code classpath:} and\n * {@code file:} or any valid URL). Once that file is located turns it into Properties and\n * extracts optional values (which can also be provided overridden as System properties in\n * case the file doesn't exist):\n * <ul>\n * <li>{@code loader.path}: a comma-separated list of directories (containing file\n * resources and/or nested archives in *.jar or *.zip or archives) or archives to append\n * to the classpath. {@code BOOT-INF/classes,BOOT-INF/lib} in the application archive are\n * always used</li>\n * <li>{@code loader.main}: the main method to delegate execution to once the class loader\n * is set up. No default, but will fall back to looking for a {@code Start-Class} in a\n * {@code MANIFEST.MF}, if there is one in <code>${loader.home}/META-INF</code>.</li>\n * </ul>\n *\n * @author Dave Syer\n * @author Janne Valkealahti\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 3.2.0\n */\npublic class PropertiesLauncher extends Launcher {\n\n\t/**\n\t * Properties key for main class. As a manifest entry can also be specified as\n\t * {@code Start-Class}.\n\t */\n\tpublic static final String MAIN = \"loader.main\";\n\n\t/**\n\t * Properties key for classpath entries (directories possibly containing jars or\n\t * jars). Multiple entries can be specified using a comma-separated list. {@code\n\t * BOOT-INF/classes,BOOT-INF/lib} in the application archive are always used.\n\t */\n\tpublic static final String PATH = \"loader.path\";\n\n\t/**\n\t * Properties key for home directory. This is the location of external configuration\n\t * if not on classpath, and also the base path for any relative paths in the\n\t * {@link #PATH loader path}. Defaults to current working directory (\n\t * <code>${user.dir}</code>).\n\t */\n\tpublic static final String HOME = \"loader.home\";\n\n\t/**\n\t * Properties key for default command line arguments. These arguments (if present) are\n\t * prepended to the main method arguments before launching.\n\t */\n\tpublic static final String ARGS = \"loader.args\";\n\n\t/**\n\t * Properties key for name of external configuration file (excluding suffix). Defaults\n\t * to \"application\". Ignored if {@link #CONFIG_LOCATION loader config location} is\n\t * provided instead.\n\t */\n\tpublic static final String CONFIG_NAME = \"loader.config.name\";\n\n\t/**\n\t * Properties key for config file location (including optional classpath:, file: or\n\t * URL prefix).\n\t */\n\tpublic static final String CONFIG_LOCATION = \"loader.config.location\";\n\n\t/**\n\t * Properties key for boolean flag (default false) which, if set, will cause the\n\t * external configuration properties to be copied to System properties (assuming that\n\t * is allowed by Java security).\n\t */\n\tpublic static final String SET_SYSTEM_PROPERTIES = \"loader.system\";\n\n\tprivate static final URL[] NO_URLS = new URL[0];\n\n\tprivate static final Pattern WORD_SEPARATOR = Pattern.compile(\"\\\\W+\");\n\n\tprivate static final String NESTED_ARCHIVE_SEPARATOR = \"!\" + File.separator;\n\n\tprivate static final String JAR_FILE_PREFIX = \"jar:file:\";\n\n\tprivate static final DebugLogger debug = DebugLogger.get(PropertiesLauncher.class);\n\n\tprivate final Archive archive;\n\n\tprivate final File homeDirectory;\n\n\tprivate final List<String> paths;\n\n\tprivate final Properties properties = new Properties();\n\n\tpublic PropertiesLauncher() throws Exception {\n\t\tthis(Archive.create(Launcher.class));\n\t}\n\n\tPropertiesLauncher(Archive archive) throws Exception {\n\t\tthis.archive = archive;\n\t\tthis.homeDirectory = getHomeDirectory();\n\t\tinitializeProperties();\n\t\tthis.paths = getPaths();\n\t\tthis.classPathIndex = getClassPathIndex(this.archive);\n\t}\n\n\tprotected File getHomeDirectory() throws Exception {\n\t\treturn new File(getPropertyWithDefault(HOME, \"${user.dir}\"));\n\t}\n\n\tprivate void initializeProperties() throws Exception {\n\t\tList<String> configs = new ArrayList<>();\n\t\tif (getProperty(CONFIG_LOCATION) != null) {\n\t\t\tconfigs.add(getProperty(CONFIG_LOCATION));\n\t\t}\n\t\telse {\n\t\t\tString[] names = getPropertyWithDefault(CONFIG_NAME, \"loader\").split(\",\");\n\t\t\tfor (String name : names) {\n\t\t\t\tString propertiesFile = name + \".properties\";\n\t\t\t\tconfigs.add(\"file:\" + this.homeDirectory + \"/\" + propertiesFile);\n\t\t\t\tconfigs.add(\"classpath:\" + propertiesFile);\n\t\t\t\tconfigs.add(\"classpath:BOOT-INF/classes/\" + propertiesFile);\n\t\t\t}\n\t\t}\n\t\tfor (String config : configs) {\n\t\t\ttry (InputStream resource = getResource(config)) {\n\t\t\t\tif (resource == null) {\n\t\t\t\t\tdebug.log(\"Not found: %s\", config);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tdebug.log(\"Found: %s\", config);\n\t\t\t\tloadResource(resource);\n\t\t\t\treturn; // Load the first one we find\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate InputStream getResource(String config) throws Exception {\n\t\tif (config.startsWith(\"classpath:\")) {\n\t\t\treturn getClasspathResource(config.substring(\"classpath:\".length()));\n\t\t}\n\t\tconfig = handleUrl(config);\n\t\tif (isUrl(config)) {\n\t\t\treturn getURLResource(config);\n\t\t}\n\t\treturn getFileResource(config);\n\t}\n\n\tprivate InputStream getClasspathResource(String config) {\n\t\tconfig = stripLeadingSlashes(config);\n\t\tconfig = \"/\" + config;\n\t\tdebug.log(\"Trying classpath: %s\", config);\n\t\treturn getClass().getResourceAsStream(config);\n\t}\n\n\tprivate String handleUrl(String path) {\n\t\tif (path.startsWith(\"jar:file:\") || path.startsWith(\"file:\")) {\n\t\t\tpath = URLDecoder.decode(path, StandardCharsets.UTF_8);\n\t\t\tif (path.startsWith(\"file:\")) {\n\t\t\t\tpath = path.substring(\"file:\".length());\n\t\t\t\tif (path.startsWith(\"//\")) {\n\t\t\t\t\tpath = path.substring(2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn path;\n\t}\n\n\tprivate boolean isUrl(String config) {\n\t\treturn config.contains(\"://\");\n\t}\n\n\tprivate InputStream getURLResource(String config) throws Exception {\n\t\tURL url = new URL(config);\n\t\tif (exists(url)) {\n\t\t\tURLConnection connection = url.openConnection();\n\t\t\ttry {\n\t\t\t\treturn connection.getInputStream();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tdisconnect(connection);\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean exists(URL url) throws IOException {\n\t\tURLConnection connection = url.openConnection();\n\t\ttry {\n\t\t\tconnection.setUseCaches(connection.getClass().getSimpleName().startsWith(\"JNLP\"));\n\t\t\tif (connection instanceof HttpURLConnection httpConnection) {\n\t\t\t\thttpConnection.setRequestMethod(\"HEAD\");\n\t\t\t\tint responseCode = httpConnection.getResponseCode();\n\t\t\t\tif (responseCode == HttpURLConnection.HTTP_OK) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn (connection.getContentLength() >= 0);\n\t\t}\n\t\tfinally {\n\t\t\tdisconnect(connection);\n\t\t}\n\t}\n\n\tprivate void disconnect(URLConnection connection) {\n\t\tif (connection instanceof HttpURLConnection httpConnection) {\n\t\t\thttpConnection.disconnect();\n\t\t}\n\t}\n\n\tprivate InputStream getFileResource(String config) throws Exception {\n\t\tFile file = new File(config);\n\t\tdebug.log(\"Trying file: %s\", config);\n\t\treturn (!file.canRead()) ? null : new FileInputStream(file);\n\t}\n\n\tprivate void loadResource(InputStream resource) throws Exception {\n\t\tthis.properties.load(resource);\n\t\tresolvePropertyPlaceholders();\n\t\tif (\"true\".equalsIgnoreCase(getProperty(SET_SYSTEM_PROPERTIES))) {\n\t\t\taddToSystemProperties();\n\t\t}\n\t}\n\n\tprivate void resolvePropertyPlaceholders() {\n\t\tfor (String name : this.properties.stringPropertyNames()) {\n\t\t\tString value = this.properties.getProperty(name);\n\t\t\tString resolved = SystemPropertyUtils.resolvePlaceholders(this.properties, value);\n\t\t\tif (resolved != null) {\n\t\t\t\tthis.properties.put(name, resolved);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addToSystemProperties() {\n\t\tdebug.log(\"Adding resolved properties to System properties\");\n\t\tfor (String name : this.properties.stringPropertyNames()) {\n\t\t\tString value = this.properties.getProperty(name);\n\t\t\tSystem.setProperty(name, value);\n\t\t}\n\t}\n\n\tprivate List<String> getPaths() throws Exception {\n\t\tString path = getProperty(PATH);\n\t\tList<String> paths = (path != null) ? parsePathsProperty(path) : Collections.emptyList();\n\t\tdebug.log(\"Nested archive paths: %s\", this.paths);\n\t\treturn paths;\n\t}\n\n\tprivate List<String> parsePathsProperty(String commaSeparatedPaths) {\n\t\tList<String> paths = new ArrayList<>();\n\t\tfor (String path : commaSeparatedPaths.split(\",\")) {\n\t\t\tpath = cleanupPath(path);\n\t\t\t// \"\" means the user wants root of archive but not current directory\n\t\t\tpath = (path.isEmpty()) ? \"/\" : path;\n\t\t\tpaths.add(path);\n\t\t}\n\t\tif (paths.isEmpty()) {\n\t\t\tpaths.add(\"lib\");\n\t\t}\n\t\treturn paths;\n\t}\n\n\tprivate String cleanupPath(String path) {\n\t\tpath = path.trim();\n\t\t// No need for current dir path\n\t\tif (path.startsWith(\"./\")) {\n\t\t\tpath = path.substring(2);\n\t\t}\n\t\tif (isArchive(path)) {\n\t\t\treturn path;\n\t\t}\n\t\tif (path.endsWith(\"/*\")) {\n\t\t\treturn path.substring(0, path.length() - 1);\n\t\t}\n\t\t// It's a directory\n\t\treturn (!path.endsWith(\"/\") && !path.equals(\".\")) ? path + \"/\" : path;\n\t}\n\n\t@Override\n\tprotected ClassLoader createClassLoader(Collection<URL> urls) throws Exception {\n\t\tString loaderClassName = getProperty(\"loader.classLoader\");\n\t\tif (this.classPathIndex != null) {\n\t\t\turls = new ArrayList<>(urls);\n\t\t\turls.addAll(this.classPathIndex.getUrls());\n\t\t}\n\t\tif (loaderClassName == null) {\n\t\t\treturn super.createClassLoader(urls);\n\t\t}\n\t\tClassLoader parent = getClass().getClassLoader();\n\t\tClassLoader classLoader = new LaunchedClassLoader(false, urls.toArray(new URL[0]), parent);\n\t\tdebug.log(\"Classpath for custom loader: %s\", urls);\n\t\tclassLoader = wrapWithCustomClassLoader(classLoader, loaderClassName);\n\t\tdebug.log(\"Using custom class loader: %s\", loaderClassName);\n\t\treturn classLoader;\n\t}\n\n\tprivate ClassLoader wrapWithCustomClassLoader(ClassLoader parent, String loaderClassName) throws Exception {\n\t\tInstantiator<ClassLoader> instantiator = new Instantiator<>(parent, loaderClassName);\n\t\tClassLoader loader = instantiator.declaredConstructor(ClassLoader.class).newInstance(parent);\n\t\tloader = (loader != null) ? loader\n\t\t\t\t: instantiator.declaredConstructor(URL[].class, ClassLoader.class).newInstance(NO_URLS, parent);\n\t\tloader = (loader != null) ? loader : instantiator.constructWithoutParameters();\n\t\tif (loader != null) {\n\t\t\treturn loader;\n\t\t}\n\t\tthrow new IllegalStateException(\"Unable to create class loader for \" + loaderClassName);\n\t}\n\n\t@Override\n\tprotected Archive getArchive() {\n\t\treturn null; // We don't have a single archive and are not exploded.\n\t}\n\n\t@Override\n\tprotected String getMainClass() throws Exception {\n\t\tString mainClass = getProperty(MAIN, \"Start-Class\");\n\t\tif (mainClass == null) {\n\t\t\tthrow new IllegalStateException(\"No '%s' or 'Start-Class' specified\".formatted(MAIN));\n\t\t}\n\t\treturn mainClass;\n\t}\n\n\tprotected String[] getArgs(String... args) throws Exception {\n\t\tString loaderArgs = getProperty(ARGS);\n\t\treturn (loaderArgs != null) ? merge(loaderArgs.split(\"\\\\s+\"), args) : args;\n\t}\n\n\tprivate String[] merge(String[] a1, String[] a2) {\n\t\tString[] result = new String[a1.length + a2.length];\n\t\tSystem.arraycopy(a1, 0, result, 0, a1.length);\n\t\tSystem.arraycopy(a2, 0, result, a1.length, a2.length);\n\t\treturn result;\n\t}\n\n\tprivate String getProperty(String name) throws Exception {\n\t\treturn getProperty(name, null, null);\n\t}\n\n\tprivate String getProperty(String name, String manifestKey) throws Exception {\n\t\treturn getProperty(name, manifestKey, null);\n\t}\n\n\tprivate String getPropertyWithDefault(String name, String defaultValue) throws Exception {\n\t\treturn getProperty(name, null, defaultValue);\n\t}\n\n\tprivate String getProperty(String name, String manifestKey, String defaultValue) throws Exception {\n\t\tmanifestKey = (manifestKey != null) ? manifestKey : toCamelCase(name.replace('.', '-'));\n\t\tString value = SystemPropertyUtils.getProperty(name);\n\t\tif (value != null) {\n\t\t\treturn getResolvedProperty(name, manifestKey, value, \"environment\");\n\t\t}\n\t\tif (this.properties.containsKey(name)) {\n\t\t\tvalue = this.properties.getProperty(name);\n\t\t\treturn getResolvedProperty(name, manifestKey, value, \"properties\");\n\t\t}\n\t\t// Prefer home dir for MANIFEST if there is one\n\t\tif (this.homeDirectory != null) {\n\t\t\ttry {\n\t\t\t\ttry (ExplodedArchive explodedArchive = new ExplodedArchive(this.homeDirectory)) {\n\t\t\t\t\tvalue = getManifestValue(explodedArchive, manifestKey);\n\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\treturn getResolvedProperty(name, manifestKey, value, \"home directory manifest\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\t// Otherwise try the root archive\n\t\tvalue = getManifestValue(this.archive, manifestKey);\n\t\tif (value != null) {\n\t\t\treturn getResolvedProperty(name, manifestKey, value, \"manifest\");\n\t\t}\n\t\treturn SystemPropertyUtils.resolvePlaceholders(this.properties, defaultValue);\n\t}\n\n\tString getManifestValue(Archive archive, String manifestKey) throws Exception {\n\t\tManifest manifest = archive.getManifest();\n\t\treturn (manifest != null) ? manifest.getMainAttributes().getValue(manifestKey) : null;\n\t}\n\n\tprivate String getResolvedProperty(String name, String manifestKey, String value, String from) {\n\t\tvalue = SystemPropertyUtils.resolvePlaceholders(this.properties, value);\n\t\tString altName = (manifestKey != null && !manifestKey.equals(name)) ? \"[%s] \".formatted(manifestKey) : \"\";\n\t\tdebug.log(\"Property '%s'%s from %s: %s\", name, altName, from, value);\n\t\treturn value;\n\n\t}\n\n\tvoid close() throws Exception {\n\t\tif (this.archive != null) {\n\t\t\tthis.archive.close();\n\t\t}\n\t}\n\n\tpublic static String toCamelCase(CharSequence string) {\n\t\tif (string == null) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuilder result = new StringBuilder();\n\t\tMatcher matcher = WORD_SEPARATOR.matcher(string);\n\t\tint pos = 0;\n\t\twhile (matcher.find()) {\n\t\t\tresult.append(capitalize(string.subSequence(pos, matcher.end()).toString()));\n\t\t\tpos = matcher.end();\n\t\t}\n\t\tresult.append(capitalize(string.subSequence(pos, string.length()).toString()));\n\t\treturn result.toString();\n\t}\n\n\tprivate static String capitalize(String str) {\n\t\treturn Character.toUpperCase(str.charAt(0)) + str.substring(1);\n\t}\n\n\t@Override\n\tprotected Set<URL> getClassPathUrls() throws Exception {\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tfor (String path : getPaths()) {\n\t\t\tpath = cleanupPath(handleUrl(path));\n\t\t\turls.addAll(getClassPathUrlsForPath(path));\n\t\t}\n\t\turls.addAll(getClassPathUrlsForRoot());\n\t\tdebug.log(\"Using class path URLs %s\", urls);\n\t\treturn urls;\n\t}\n\n\tprivate Set<URL> getClassPathUrlsForPath(String path) throws Exception {\n\t\tFile file = (!isAbsolutePath(path)) ? new File(this.homeDirectory, path) : new File(path);\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tif (!\"/\".equals(path)) {\n\t\t\tif (file.isDirectory()) {\n\t\t\t\ttry (ExplodedArchive explodedArchive = new ExplodedArchive(file)) {\n\t\t\t\t\tdebug.log(\"Adding classpath entries from directory %s\", file);\n\t\t\t\t\turls.add(file.toURI().toURL());\n\t\t\t\t\turls.addAll(explodedArchive.getClassPathUrls(this::isArchive));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!file.getPath().contains(NESTED_ARCHIVE_SEPARATOR) && isArchive(file.getName())) {\n\t\t\tdebug.log(\"Adding classpath entries from jar/zip archive %s\", path);\n\t\t\turls.add(file.toURI().toURL());\n\t\t}\n\t\tSet<URL> nested = getClassPathUrlsForNested(path);\n\t\tif (!nested.isEmpty()) {\n\t\t\tdebug.log(\"Adding classpath entries from nested %s\", path);\n\t\t\turls.addAll(nested);\n\t\t}\n\t\treturn urls;\n\t}\n\n\tprivate Set<URL> getClassPathUrlsForNested(String path) throws Exception {\n\t\tboolean isJustArchive = isArchive(path);\n\t\tif (!path.equals(\"/\") && path.startsWith(\"/\")\n\t\t\t\t|| (this.archive.isExploded() && this.archive.getRootDirectory().equals(this.homeDirectory))) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t\tFile file = null;\n\t\tif (isJustArchive) {\n\t\t\tFile candidate = new File(this.homeDirectory, path);\n\t\t\tif (candidate.exists()) {\n\t\t\t\tfile = candidate;\n\t\t\t\tpath = \"\";\n\t\t\t}\n\t\t}\n\t\tint separatorIndex = path.indexOf('!');\n\t\tif (separatorIndex != -1) {\n\t\t\tfile = (!path.startsWith(JAR_FILE_PREFIX)) ? new File(this.homeDirectory, path.substring(0, separatorIndex))\n\t\t\t\t\t: new File(path.substring(JAR_FILE_PREFIX.length(), separatorIndex));\n\t\t\tpath = path.substring(separatorIndex + 1);\n\t\t\tpath = stripLeadingSlashes(path);\n\t\t}\n\t\tif (path.equals(\"/\") || path.equals(\"./\") || path.equals(\".\")) {\n\t\t\t// The prefix for nested jars is actually empty if it's at the root\n\t\t\tpath = \"\";\n\t\t}\n\t\tArchive archive = (file != null) ? new JarFileArchive(file) : this.archive;\n\t\ttry {\n\t\t\tSet<URL> urls = new LinkedHashSet<>(archive.getClassPathUrls(includeByPrefix(path)));\n\t\t\tif (!isJustArchive && file != null && path.isEmpty()) {\n\t\t\t\turls.add(JarUrl.create(file));\n\t\t\t}\n\t\t\treturn urls;\n\t\t}\n\t\tfinally {\n\t\t\tif (archive != this.archive) {\n\t\t\t\tarchive.close();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Set<URL> getClassPathUrlsForRoot() throws Exception {\n\t\tdebug.log(\"Adding classpath entries from root archive %s\", this.archive);\n\t\treturn this.archive.getClassPathUrls(this::isIncludedOnClassPathAndNotIndexed, Archive.ALL_ENTRIES);\n\t}\n\n\tprivate Predicate<Entry> includeByPrefix(String prefix) {\n\t\treturn (entry) -> (entry.isDirectory() && entry.name().equals(prefix))\n\t\t\t\t|| (isArchive(entry) && entry.name().startsWith(prefix));\n\t}\n\n\tprivate boolean isArchive(Entry entry) {\n\t\treturn isArchive(entry.name());\n\t}\n\n\tprivate boolean isArchive(String name) {\n\t\tname = name.toLowerCase(Locale.ENGLISH);\n\t\treturn name.endsWith(\".jar\") || name.endsWith(\".zip\");\n\t}\n\n\tprivate boolean isAbsolutePath(String root) {\n\t\t// Windows contains \":\" others start with \"/\"\n\t\treturn root.contains(\":\") || root.startsWith(\"/\");\n\t}\n\n\tprivate String stripLeadingSlashes(String string) {\n\t\twhile (string.startsWith(\"/\")) {\n\t\t\tstring = string.substring(1);\n\t\t}\n\t\treturn string;\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tPropertiesLauncher launcher = new PropertiesLauncher();\n\t\targs = launcher.getArgs(args);\n\t\tlauncher.launch(args);\n\t}\n\n\t/**\n\t * Utility to help instantiate objects.\n\t */\n\tprivate record Instantiator<T>(ClassLoader parent, Class<?> type) {\n\n\t\tInstantiator(ClassLoader parent, String className) throws ClassNotFoundException {\n\t\t\tthis(parent, Class.forName(className, true, parent));\n\t\t}\n\n\t\tT constructWithoutParameters() throws Exception {\n\t\t\treturn declaredConstructor().newInstance();\n\t\t}\n\n\t\tUsing<T> declaredConstructor(Class<?>... parameterTypes) {\n\t\t\treturn new Using<>(this, parameterTypes);\n\t\t}\n\n\t\tprivate record Using<T>(Instantiator<T> instantiator, Class<?>... parameterTypes) {\n\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tT newInstance(Object... initargs) throws Exception {\n\t\t\t\ttry {\n\t\t\t\t\tConstructor<?> constructor = this.instantiator.type().getDeclaredConstructor(this.parameterTypes);\n\t\t\t\t\tconstructor.setAccessible(true);\n\t\t\t\t\treturn (T) constructor.newInstance(initargs);\n\t\t\t\t}\n\t\t\t\tcatch (NoSuchMethodException ex) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/SystemPropertyUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Properties;\nimport java.util.Set;\n\n/**\n * Internal helper class adapted from Spring Framework for resolving placeholders in\n * texts.\n *\n * @author Juergen Hoeller\n * @author Rob Harrop\n * @author Dave Syer\n * @author Phillip Webb\n */\nfinal class SystemPropertyUtils {\n\n\tprivate static final String PLACEHOLDER_PREFIX = \"${\";\n\n\tprivate static final String PLACEHOLDER_SUFFIX = \"}\";\n\n\tprivate static final String VALUE_SEPARATOR = \":\";\n\n\tprivate static final String SIMPLE_PREFIX = PLACEHOLDER_PREFIX.substring(1);\n\n\tprivate SystemPropertyUtils() {\n\t}\n\n\tstatic String resolvePlaceholders(Properties properties, String text) {\n\t\treturn (text != null) ? parseStringValue(properties, text, text, new HashSet<>()) : null;\n\t}\n\n\tprivate static String parseStringValue(Properties properties, String value, String current,\n\t\t\tSet<String> visitedPlaceholders) {\n\t\tStringBuilder result = new StringBuilder(current);\n\t\tint startIndex = current.indexOf(PLACEHOLDER_PREFIX);\n\t\twhile (startIndex != -1) {\n\t\t\tint endIndex = findPlaceholderEndIndex(result, startIndex);\n\t\t\tif (endIndex == -1) {\n\t\t\t\tstartIndex = -1;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tString placeholder = result.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex);\n\t\t\tString originalPlaceholder = placeholder;\n\t\t\tif (!visitedPlaceholders.add(originalPlaceholder)) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Circular placeholder reference '\" + originalPlaceholder + \"' in property definitions\");\n\t\t\t}\n\t\t\tplaceholder = parseStringValue(properties, value, placeholder, visitedPlaceholders);\n\t\t\tString propertyValue = resolvePlaceholder(properties, value, placeholder);\n\t\t\tif (propertyValue == null) {\n\t\t\t\tint separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);\n\t\t\t\tif (separatorIndex != -1) {\n\t\t\t\t\tString actualPlaceholder = placeholder.substring(0, separatorIndex);\n\t\t\t\t\tString defaultValue = placeholder.substring(separatorIndex + VALUE_SEPARATOR.length());\n\t\t\t\t\tpropertyValue = resolvePlaceholder(properties, value, actualPlaceholder);\n\t\t\t\t\tpropertyValue = (propertyValue != null) ? propertyValue : defaultValue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (propertyValue != null) {\n\t\t\t\tpropertyValue = parseStringValue(properties, value, propertyValue, visitedPlaceholders);\n\t\t\t\tresult.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propertyValue);\n\t\t\t\tstartIndex = result.indexOf(PLACEHOLDER_PREFIX, startIndex + propertyValue.length());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstartIndex = result.indexOf(PLACEHOLDER_PREFIX, endIndex + PLACEHOLDER_SUFFIX.length());\n\t\t\t}\n\t\t\tvisitedPlaceholders.remove(originalPlaceholder);\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\tprivate static String resolvePlaceholder(Properties properties, String text, String placeholderName) {\n\t\tString propertyValue = getProperty(placeholderName, null, text);\n\t\tif (propertyValue != null) {\n\t\t\treturn propertyValue;\n\t\t}\n\t\treturn (properties != null) ? properties.getProperty(placeholderName) : null;\n\t}\n\n\tstatic String getProperty(String key) {\n\t\treturn getProperty(key, null, \"\");\n\t}\n\n\tprivate static String getProperty(String key, String defaultValue, String text) {\n\t\ttry {\n\t\t\tString value = System.getProperty(key);\n\t\t\tvalue = (value != null) ? value : System.getenv(key);\n\t\t\tvalue = (value != null) ? value : System.getenv(key.replace('.', '_'));\n\t\t\tvalue = (value != null) ? value : System.getenv(key.toUpperCase(Locale.ENGLISH).replace('.', '_'));\n\t\t\treturn (value != null) ? value : defaultValue;\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tSystem.err.println(\"Could not resolve key '\" + key + \"' in '\" + text\n\t\t\t\t\t+ \"' as system property or in environment: \" + ex);\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\tprivate static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {\n\t\tint index = startIndex + PLACEHOLDER_PREFIX.length();\n\t\tint withinNestedPlaceholder = 0;\n\t\twhile (index < buf.length()) {\n\t\t\tif (substringMatch(buf, index, PLACEHOLDER_SUFFIX)) {\n\t\t\t\tif (withinNestedPlaceholder > 0) {\n\t\t\t\t\twithinNestedPlaceholder--;\n\t\t\t\t\tindex = index + PLACEHOLDER_SUFFIX.length();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn index;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (substringMatch(buf, index, SIMPLE_PREFIX)) {\n\t\t\t\twithinNestedPlaceholder++;\n\t\t\t\tindex = index + SIMPLE_PREFIX.length();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tindex++;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\tprivate static boolean substringMatch(CharSequence str, int index, CharSequence substring) {\n\t\tfor (int j = 0; j < substring.length(); j++) {\n\t\t\tint i = index + j;\n\t\t\tif (i >= str.length() || str.charAt(i) != substring.charAt(j)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/WarLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\n/**\n * {@link Launcher} for WAR based archives. This launcher for standard WAR archives.\n * Supports dependencies in {@code WEB-INF/lib} as well as {@code WEB-INF/lib-provided},\n * classes are loaded from {@code WEB-INF/classes}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.2.0\n */\npublic class WarLauncher extends ExecutableArchiveLauncher {\n\n\tpublic WarLauncher() throws Exception {\n\t}\n\n\tprotected WarLauncher(Archive archive) throws Exception {\n\t\tsuper(archive);\n\t}\n\n\t@Override\n\tprotected String getEntryPathPrefix() {\n\t\treturn \"WEB-INF/\";\n\t}\n\n\t@Override\n\tprotected boolean isLibraryFileOrClassesDirectory(Archive.Entry entry) {\n\t\tString name = entry.name();\n\t\tif (entry.isDirectory()) {\n\t\t\treturn name.equals(\"WEB-INF/classes/\");\n\t\t}\n\t\treturn name.startsWith(\"WEB-INF/lib/\") || name.startsWith(\"WEB-INF/lib-provided/\");\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tnew WarLauncher().launch(args);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/launch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * System that allows self-contained JAR/WAR archives to be launched using\n * {@code java -jar}. Archives can include nested packaged dependency JARs (there is no\n * need to create shade style jars) and are executed without unpacking. The only\n * constraint is that nested JARs must be stored in the archive uncompressed.\n *\n * @see org.springframework.boot.loader.launch.JarLauncher\n * @see org.springframework.boot.loader.launch.WarLauncher\n */\npackage org.springframework.boot.loader.launch;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/log/DebugLogger.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.log;\n\n/**\n * Simple logger class used for {@link System#err} debugging.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic abstract sealed class DebugLogger {\n\n\tprivate static final String ENABLED_PROPERTY = \"loader.debug\";\n\n\tprivate static final DebugLogger disabled;\n\tstatic {\n\t\tdisabled = Boolean.getBoolean(ENABLED_PROPERTY) ? null : new DisabledDebugLogger();\n\t}\n\n\t/**\n\t * Log a message.\n\t * @param message the message to log\n\t */\n\tpublic abstract void log(String message);\n\n\t/**\n\t * Log a formatted message.\n\t * @param message the message to log\n\t * @param arg1 the first format argument\n\t */\n\tpublic abstract void log(String message, Object arg1);\n\n\t/**\n\t * Log a formatted message.\n\t * @param message the message to log\n\t * @param arg1 the first format argument\n\t * @param arg2 the second format argument\n\t */\n\tpublic abstract void log(String message, Object arg1, Object arg2);\n\n\t/**\n\t * Log a formatted message.\n\t * @param message the message to log\n\t * @param arg1 the first format argument\n\t * @param arg2 the second format argument\n\t * @param arg3 the third format argument\n\t */\n\tpublic abstract void log(String message, Object arg1, Object arg2, Object arg3);\n\n\t/**\n\t * Log a formatted message.\n\t * @param message the message to log\n\t * @param arg1 the first format argument\n\t * @param arg2 the second format argument\n\t * @param arg3 the third format argument\n\t * @param arg4 the fourth format argument\n\t */\n\tpublic abstract void log(String message, Object arg1, Object arg2, Object arg3, Object arg4);\n\n\t/**\n\t * Get a {@link DebugLogger} to log messages for the given source class.\n\t * @param sourceClass the source class\n\t * @return a {@link DebugLogger} instance\n\t */\n\tpublic static DebugLogger get(Class<?> sourceClass) {\n\t\treturn (disabled != null) ? disabled : new SystemErrDebugLogger(sourceClass);\n\t}\n\n\t/**\n\t * {@link DebugLogger} used for disabled logging that does nothing.\n\t */\n\tprivate static final class DisabledDebugLogger extends DebugLogger {\n\n\t\t@Override\n\t\tpublic void log(String message) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1, Object arg2) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1, Object arg2, Object arg3) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1, Object arg2, Object arg3, Object arg4) {\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DebugLogger} that prints messages to {@link System#err}.\n\t */\n\tprivate static final class SystemErrDebugLogger extends DebugLogger {\n\n\t\tprivate final String prefix;\n\n\t\tSystemErrDebugLogger(Class<?> sourceClass) {\n\t\t\tthis.prefix = \"LOADER: \" + sourceClass + \" : \";\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message) {\n\t\t\tprint(message);\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1) {\n\t\t\tprint(message.formatted(arg1));\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1, Object arg2) {\n\t\t\tprint(message.formatted(arg1, arg2));\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1, Object arg2, Object arg3) {\n\t\t\tprint(message.formatted(arg1, arg2, arg3));\n\t\t}\n\n\t\t@Override\n\t\tpublic void log(String message, Object arg1, Object arg2, Object arg3, Object arg4) {\n\t\t\tprint(message.formatted(arg1, arg2, arg3, arg4));\n\t\t}\n\n\t\tprivate void print(String message) {\n\t\t\tSystem.err.println(this.prefix + message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/log/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Debug {@link java.lang.System#err} logging support.\n */\npackage org.springframework.boot.loader.log;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/Handlers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol;\n\nimport java.net.URL;\nimport java.net.URLStreamHandler;\nimport java.net.URLStreamHandlerFactory;\n\n/**\n * Utility used to register loader {@link URLStreamHandler URL handlers}.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic final class Handlers {\n\n\tprivate static final String PROTOCOL_HANDLER_PACKAGES = \"java.protocol.handler.pkgs\";\n\n\tprivate static final String PACKAGE = Handlers.class.getPackageName();\n\n\tprivate Handlers() {\n\t}\n\n\t/**\n\t * Register a {@literal 'java.protocol.handler.pkgs'} property so that a\n\t * {@link URLStreamHandler} will be located to deal with jar URLs.\n\t */\n\tpublic static void register() {\n\t\tString packages = System.getProperty(PROTOCOL_HANDLER_PACKAGES, \"\");\n\t\tpackages = (!packages.isEmpty() && !packages.contains(PACKAGE)) ? packages + \"|\" + PACKAGE : PACKAGE;\n\t\tSystem.setProperty(PROTOCOL_HANDLER_PACKAGES, packages);\n\t\tresetCachedUrlHandlers();\n\t}\n\n\t/**\n\t * Reset any cached handlers just in case a jar protocol has already been used. We\n\t * reset the handler by trying to set a null {@link URLStreamHandlerFactory} which\n\t * should have no effect other than clearing the handlers cache.\n\t */\n\tprivate static void resetCachedUrlHandlers() {\n\t\ttry {\n\t\t\tURL.setURLStreamHandlerFactory(null);\n\t\t}\n\t\tcatch (Error ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/Canonicalizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\n/**\n * Internal utility used by the {@link Handler} to canonicalize paths. This implementation\n * should behave the same as the canonicalization functions in\n * {@code sun.net.www.protocol.jar.Handler}.\n *\n * @author Phillip Webb\n */\nfinal class Canonicalizer {\n\n\tprivate Canonicalizer() {\n\t}\n\n\tstatic String canonicalizeAfter(String path, int pos) {\n\t\tint pathLength = path.length();\n\t\tboolean noDotSlash = path.indexOf(\"./\", pos) == -1;\n\t\tif (pos >= pathLength || (noDotSlash && path.charAt(pathLength - 1) != '.')) {\n\t\t\treturn path;\n\t\t}\n\t\tString before = path.substring(0, pos);\n\t\tString after = path.substring(pos);\n\t\treturn before + canonicalize(after);\n\t}\n\n\tstatic String canonicalize(String path) {\n\t\tpath = removeEmbeddedSlashDotDotSlash(path);\n\t\tpath = removeEmbeddedSlashDotSlash(path);\n\t\tpath = removeTrailingSlashDotDot(path);\n\t\tpath = removeTrailingSlashDot(path);\n\t\treturn path;\n\t}\n\n\tprivate static String removeEmbeddedSlashDotDotSlash(String path) {\n\t\tint index;\n\t\twhile ((index = path.indexOf(\"/../\")) >= 0) {\n\t\t\tint priorSlash = path.lastIndexOf('/', index - 1);\n\t\t\tString after = path.substring(index + 3);\n\t\t\tpath = (priorSlash >= 0) ? path.substring(0, priorSlash) + after : after;\n\t\t}\n\t\treturn path;\n\t}\n\n\tprivate static String removeEmbeddedSlashDotSlash(String path) {\n\t\tint index;\n\t\twhile ((index = path.indexOf(\"/./\")) >= 0) {\n\t\t\tString before = path.substring(0, index);\n\t\t\tString after = path.substring(index + 2);\n\t\t\tpath = before + after;\n\t\t}\n\t\treturn path;\n\t}\n\n\tprivate static String removeTrailingSlashDot(String path) {\n\t\treturn (!path.endsWith(\"/.\")) ? path : path.substring(0, path.length() - 1);\n\t}\n\n\tprivate static String removeTrailingSlashDotDot(String path) {\n\t\tint index;\n\t\twhile (path.endsWith(\"/..\")) {\n\t\t\tindex = path.indexOf(\"/..\");\n\t\t\tint priorSlash = path.lastIndexOf('/', index - 1);\n\t\t\tpath = (priorSlash >= 0) ? path.substring(0, priorSlash + 1) : path.substring(0, index);\n\t\t}\n\t\treturn path;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/Handler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLStreamHandler;\n\n/**\n * {@link URLStreamHandler} alternative to {@code sun.net.www.protocol.jar.Handler} with\n * optimized support for nested jars.\n *\n * @author Phillip Webb\n * @since 3.2.0\n * @see org.springframework.boot.loader.net.protocol.Handlers\n */\npublic class Handler extends URLStreamHandler {\n\n\t// NOTE: in order to be found as a URL protocol handler, this class must be public,\n\t// must be named Handler and must be in a package ending '.jar'\n\n\tprivate static final String PROTOCOL = \"jar\";\n\n\tprivate static final String SEPARATOR = \"!/\";\n\n\tstatic final Handler INSTANCE = new Handler();\n\n\t@Override\n\tprotected URLConnection openConnection(URL url) throws IOException {\n\t\treturn JarUrlConnection.open(url);\n\t}\n\n\t@Override\n\tprotected void parseURL(URL url, String spec, int start, int limit) {\n\t\tif (spec.regionMatches(true, start, \"jar:\", 0, 4)) {\n\t\t\tthrow new IllegalStateException(\"Nested JAR URLs are not supported\");\n\t\t}\n\t\tint anchorIndex = spec.indexOf('#', limit);\n\t\tString path = extractPath(url, spec, start, limit, anchorIndex);\n\t\tString ref = (anchorIndex != -1) ? spec.substring(anchorIndex + 1) : null;\n\t\tsetURL(url, PROTOCOL, \"\", -1, null, null, path, null, ref);\n\t}\n\n\tprivate String extractPath(URL url, String spec, int start, int limit, int anchorIndex) {\n\t\tif (anchorIndex == start) {\n\t\t\treturn extractAnchorOnlyPath(url);\n\t\t}\n\t\tif (spec.length() >= 4 && spec.regionMatches(true, 0, \"jar:\", 0, 4)) {\n\t\t\treturn extractAbsolutePath(spec, start, limit);\n\t\t}\n\t\treturn extractRelativePath(url, spec, start, limit);\n\t}\n\n\tprivate String extractAnchorOnlyPath(URL url) {\n\t\treturn url.getPath();\n\t}\n\n\tprivate String extractAbsolutePath(String spec, int start, int limit) {\n\t\tint indexOfSeparator = indexOfSeparator(spec, start, limit);\n\t\tif (indexOfSeparator == -1) {\n\t\t\tthrow new IllegalStateException(\"no !/ in spec\");\n\t\t}\n\t\tString innerUrl = spec.substring(start, indexOfSeparator);\n\t\tassertInnerUrlIsNotMalformed(spec, innerUrl);\n\t\treturn spec.substring(start, limit);\n\t}\n\n\tprivate String extractRelativePath(URL url, String spec, int start, int limit) {\n\t\tString contextPath = extractContextPath(url, spec, start);\n\t\tString path = contextPath + spec.substring(start, limit);\n\t\treturn Canonicalizer.canonicalizeAfter(path, indexOfSeparator(path) + 1);\n\t}\n\n\tprivate String extractContextPath(URL url, String spec, int start) {\n\t\tString contextPath = url.getPath();\n\t\tif (spec.regionMatches(false, start, \"/\", 0, 1)) {\n\t\t\tint indexOfContextPathSeparator = indexOfSeparator(contextPath);\n\t\t\tif (indexOfContextPathSeparator == -1) {\n\t\t\t\tthrow new IllegalStateException(\"malformed context url:%s: no !/\".formatted(url));\n\t\t\t}\n\t\t\treturn contextPath.substring(0, indexOfContextPathSeparator + 1);\n\t\t}\n\t\tint lastSlash = contextPath.lastIndexOf('/');\n\t\tif (lastSlash == -1) {\n\t\t\tthrow new IllegalStateException(\"malformed context url:%s\".formatted(url));\n\t\t}\n\t\treturn contextPath.substring(0, lastSlash + 1);\n\t}\n\n\tprivate void assertInnerUrlIsNotMalformed(String spec, String innerUrl) {\n\t\tif (innerUrl.startsWith(\"nested:\")) {\n\t\t\torg.springframework.boot.loader.net.protocol.nested.Handler.assertUrlIsNotMalformed(innerUrl);\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tnew URL(innerUrl);\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(\"invalid url: %s (%s)\".formatted(spec, ex));\n\t\t}\n\t}\n\n\t@Override\n\tprotected int hashCode(URL url) {\n\t\tString protocol = url.getProtocol();\n\t\tint hash = (protocol != null) ? protocol.hashCode() : 0;\n\t\tString file = url.getFile();\n\t\tint indexOfSeparator = file.indexOf(SEPARATOR);\n\t\tif (indexOfSeparator == -1) {\n\t\t\treturn hash + file.hashCode();\n\t\t}\n\t\tString fileWithoutEntry = file.substring(0, indexOfSeparator);\n\t\ttry {\n\t\t\thash += new URL(fileWithoutEntry).hashCode();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\thash += fileWithoutEntry.hashCode();\n\t\t}\n\t\tString entry = file.substring(indexOfSeparator + 2);\n\t\treturn hash + entry.hashCode();\n\t}\n\n\t@Override\n\tprotected boolean sameFile(URL url1, URL url2) {\n\t\tif (!url1.getProtocol().equals(PROTOCOL) || !url2.getProtocol().equals(PROTOCOL)) {\n\t\t\treturn false;\n\t\t}\n\t\tString file1 = url1.getFile();\n\t\tString file2 = url2.getFile();\n\t\tint indexOfSeparator1 = file1.indexOf(SEPARATOR);\n\t\tint indexOfSeparator2 = file2.indexOf(SEPARATOR);\n\t\tif (indexOfSeparator1 == -1 || indexOfSeparator2 == -1) {\n\t\t\treturn super.sameFile(url1, url2);\n\t\t}\n\t\tString entry1 = file1.substring(indexOfSeparator1 + 2);\n\t\tString entry2 = file2.substring(indexOfSeparator2 + 2);\n\t\tif (!entry1.equals(entry2)) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tURL innerUrl1 = new URL(file1.substring(0, indexOfSeparator1));\n\t\t\tURL innerUrl2 = new URL(file2.substring(0, indexOfSeparator2));\n\t\t\tif (!super.sameFile(innerUrl1, innerUrl2)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tcatch (MalformedURLException unused) {\n\t\t\treturn super.sameFile(url1, url2);\n\t\t}\n\t\treturn true;\n\t}\n\n\tstatic int indexOfSeparator(String spec) {\n\t\treturn indexOfSeparator(spec, 0, spec.length());\n\t}\n\n\tstatic int indexOfSeparator(String spec, int start, int limit) {\n\t\tfor (int i = limit - 1; i >= start; i--) {\n\t\t\tif (spec.charAt(i) == '!' && (i + 1) < limit && spec.charAt(i + 1) == '/') {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Clear any internal caches.\n\t */\n\tpublic static void clearCache() {\n\t\tJarUrlConnection.clearCache();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarFileUrlKey.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.net.URL;\nimport java.util.Objects;\n\n/**\n * A fast cache key for a jar file {@link URL} that doesn't trigger DNS lookups.\n *\n * @author Phillip Webb\n */\nfinal class JarFileUrlKey {\n\n\tprivate final String protocol;\n\n\tprivate final String host;\n\n\tprivate final int port;\n\n\tprivate final String file;\n\n\tprivate final boolean runtimeRef;\n\n\tJarFileUrlKey(URL url) {\n\t\tthis.protocol = url.getProtocol();\n\t\tthis.host = url.getHost();\n\t\tthis.port = (url.getPort() != -1) ? url.getPort() : url.getDefaultPort();\n\t\tthis.file = url.getFile();\n\t\tthis.runtimeRef = \"runtime\".equals(url.getRef());\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tJarFileUrlKey other = (JarFileUrlKey) obj;\n\t\t// We check file first as case sensitive and the most likely item to be different\n\t\treturn Objects.equals(this.file, other.file) && equalsIgnoringCase(this.protocol, other.protocol)\n\t\t\t\t&& equalsIgnoringCase(this.host, other.host) && (this.port == other.port)\n\t\t\t\t&& (this.runtimeRef == other.runtimeRef);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hashCode(this.file);\n\t}\n\n\tprivate boolean equalsIgnoringCase(String s1, String s2) {\n\t\treturn (s1 == s2) || (s1 != null && s1.equalsIgnoreCase(s2));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarUrl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.jar.JarEntry;\n\n/**\n * Utility class with factory methods that can be used to create JAR URLs.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic final class JarUrl {\n\n\tprivate JarUrl() {\n\t}\n\n\t/**\n\t * Create a new jar URL.\n\t * @param file the jar file\n\t * @return a jar file URL\n\t */\n\tpublic static URL create(File file) {\n\t\treturn create(file, (String) null);\n\t}\n\n\t/**\n\t * Create a new jar URL.\n\t * @param file the jar file\n\t * @param nestedEntry the nested entry or {@code null}\n\t * @return a jar file URL\n\t */\n\tpublic static URL create(File file, JarEntry nestedEntry) {\n\t\treturn create(file, (nestedEntry != null) ? nestedEntry.getName() : null);\n\t}\n\n\t/**\n\t * Create a new jar URL.\n\t * @param file the jar file\n\t * @param nestedEntryName the nested entry name or {@code null}\n\t * @return a jar file URL\n\t */\n\tpublic static URL create(File file, String nestedEntryName) {\n\t\treturn create(file, nestedEntryName, null);\n\t}\n\n\t/**\n\t * Create a new jar URL.\n\t * @param file the jar file\n\t * @param nestedEntryName the nested entry name or {@code null}\n\t * @param path the path within the jar or nested jar\n\t * @return a jar file URL\n\t */\n\tpublic static URL create(File file, String nestedEntryName, String path) {\n\t\ttry {\n\t\t\tpath = (path != null) ? path : \"\";\n\t\t\treturn new URL(null, \"jar:\" + getJarReference(file, nestedEntryName) + \"!/\" + path, Handler.INSTANCE);\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create JarFileArchive URL\", ex);\n\t\t}\n\t}\n\n\tprivate static String getJarReference(File file, String nestedEntryName) {\n\t\tString jarFilePath = file.toURI().getRawPath().replace(\"!\", \"%21\");\n\t\treturn (nestedEntryName != null) ? \"nested:\" + jarFilePath + \"/!\" + nestedEntryName : \"file:\" + jarFilePath;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarUrlClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.net.URLConnection;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.jar.JarFile;\n\nimport org.springframework.boot.loader.jar.NestedJarFile;\nimport org.springframework.boot.loader.launch.LaunchedClassLoader;\n\n/**\n * {@link URLClassLoader} with optimized support for Jar URLs.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 3.2.0\n */\npublic abstract class JarUrlClassLoader extends URLClassLoader {\n\n\tstatic {\n\t\tClassLoader.registerAsParallelCapable();\n\t}\n\n\tprivate final URL[] urls;\n\n\tprivate final boolean hasJarUrls;\n\n\tprivate final Map<URL, JarFile> jarFiles = new ConcurrentHashMap<>();\n\n\tprivate final Set<String> undefinablePackages = ConcurrentHashMap.newKeySet();\n\n\t/**\n\t * Create a new {@link LaunchedClassLoader} instance.\n\t * @param urls the URLs from which to load classes and resources\n\t * @param parent the parent class loader for delegation\n\t */\n\tpublic JarUrlClassLoader(URL[] urls, ClassLoader parent) {\n\t\tsuper(urls, parent);\n\t\tthis.urls = urls;\n\t\tthis.hasJarUrls = Arrays.stream(urls).anyMatch(this::isJarUrl);\n\t}\n\n\t@Override\n\tpublic URL findResource(String name) {\n\t\tif (!this.hasJarUrls) {\n\t\t\treturn super.findResource(name);\n\t\t}\n\t\tOptimizations.enable(false);\n\t\ttry {\n\t\t\treturn super.findResource(name);\n\t\t}\n\t\tfinally {\n\t\t\tOptimizations.disable();\n\t\t}\n\t}\n\n\t@Override\n\tpublic Enumeration<URL> findResources(String name) throws IOException {\n\t\tif (!this.hasJarUrls) {\n\t\t\treturn super.findResources(name);\n\t\t}\n\t\tOptimizations.enable(false);\n\t\ttry {\n\t\t\treturn new OptimizedEnumeration(super.findResources(name));\n\t\t}\n\t\tfinally {\n\t\t\tOptimizations.disable();\n\t\t}\n\t}\n\n\t@Override\n\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\tif (!this.hasJarUrls) {\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\t\tOptimizations.enable(true);\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tdefinePackageIfNecessary(name);\n\t\t\t}\n\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\ttolerateRaceConditionDueToBeingParallelCapable(ex, name);\n\t\t\t}\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\t\tfinally {\n\t\t\tOptimizations.disable();\n\t\t}\n\t}\n\n\t/**\n\t * Define a package before a {@code findClass} call is made. This is necessary to\n\t * ensure that the appropriate manifest for nested JARs is associated with the\n\t * package.\n\t * @param className the class name being found\n\t */\n\tprotected final void definePackageIfNecessary(String className) {\n\t\tif (className.startsWith(\"java.\")) {\n\t\t\treturn;\n\t\t}\n\t\tint lastDot = className.lastIndexOf('.');\n\t\tif (lastDot >= 0) {\n\t\t\tString packageName = className.substring(0, lastDot);\n\t\t\tif (getDefinedPackage(packageName) == null) {\n\t\t\t\ttry {\n\t\t\t\t\tdefinePackage(className, packageName);\n\t\t\t\t}\n\t\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\t\ttolerateRaceConditionDueToBeingParallelCapable(ex, packageName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void definePackage(String className, String packageName) {\n\t\tif (this.undefinablePackages.contains(packageName)) {\n\t\t\treturn;\n\t\t}\n\t\tString packageEntryName = packageName.replace('.', '/') + \"/\";\n\t\tString classEntryName = className.replace('.', '/') + \".class\";\n\t\tfor (URL url : this.urls) {\n\t\t\ttry {\n\t\t\t\tJarFile jarFile = getJarFile(url);\n\t\t\t\tif (jarFile != null) {\n\t\t\t\t\tif (hasEntry(jarFile, classEntryName) && hasEntry(jarFile, packageEntryName)\n\t\t\t\t\t\t\t&& jarFile.getManifest() != null) {\n\t\t\t\t\t\tdefinePackage(packageName, jarFile.getManifest(), url);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tthis.undefinablePackages.add(packageName);\n\t}\n\n\tprivate void tolerateRaceConditionDueToBeingParallelCapable(IllegalArgumentException ex, String packageName)\n\t\t\tthrows AssertionError {\n\t\tif (getDefinedPackage(packageName) == null) {\n\t\t\t// This should never happen as the IllegalArgumentException indicates that the\n\t\t\t// package has already been defined and, therefore, getDefinedPackage(name)\n\t\t\t// should not have returned null.\n\t\t\tthrow new AssertionError(\n\t\t\t\t\t\"Package %s has already been defined but it could not be found\".formatted(packageName), ex);\n\t\t}\n\t}\n\n\tprivate boolean hasEntry(JarFile jarFile, String name) {\n\t\treturn (jarFile instanceof NestedJarFile nestedJarFile) ? nestedJarFile.hasEntry(name)\n\t\t\t\t: jarFile.getEntry(name) != null;\n\t}\n\n\tprivate JarFile getJarFile(URL url) throws IOException {\n\t\tJarFile jarFile = this.jarFiles.get(url);\n\t\tif (jarFile != null) {\n\t\t\treturn jarFile;\n\t\t}\n\t\tURLConnection connection = url.openConnection();\n\t\tif (!(connection instanceof JarURLConnection)) {\n\t\t\treturn null;\n\t\t}\n\t\tconnection.setUseCaches(false);\n\t\tjarFile = ((JarURLConnection) connection).getJarFile();\n\t\tsynchronized (this.jarFiles) {\n\t\t\tJarFile previous = this.jarFiles.putIfAbsent(url, jarFile);\n\t\t\tif (previous != null) {\n\t\t\t\tjarFile.close();\n\t\t\t\tjarFile = previous;\n\t\t\t}\n\t\t}\n\t\treturn jarFile;\n\t}\n\n\t/**\n\t * Clear any caches. This method is called reflectively by\n\t * {@code ClearCachesApplicationListener}.\n\t */\n\tpublic void clearCache() {\n\t\tHandler.clearCache();\n\t\torg.springframework.boot.loader.net.protocol.nested.Handler.clearCache();\n\t\ttry {\n\t\t\tclearJarFiles();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\tfor (URL url : this.urls) {\n\t\t\tif (isJarUrl(url)) {\n\t\t\t\tclearCache(url);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void clearCache(URL url) {\n\t\ttry {\n\t\t\tURLConnection connection = url.openConnection();\n\t\t\tif (connection instanceof JarURLConnection jarUrlConnection) {\n\t\t\t\tclearCache(jarUrlConnection);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate void clearCache(JarURLConnection connection) throws IOException {\n\t\tJarFile jarFile = connection.getJarFile();\n\t\tif (jarFile instanceof NestedJarFile nestedJarFile) {\n\t\t\tnestedJarFile.clearCache();\n\t\t}\n\t}\n\n\tprivate boolean isJarUrl(URL url) {\n\t\treturn \"jar\".equals(url.getProtocol());\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tsuper.close();\n\t\tclearJarFiles();\n\t}\n\n\tprivate void clearJarFiles() throws IOException {\n\t\tsynchronized (this.jarFiles) {\n\t\t\tfor (JarFile jarFile : this.jarFiles.values()) {\n\t\t\t\tjarFile.close();\n\t\t\t}\n\t\t\tthis.jarFiles.clear();\n\t\t}\n\t}\n\n\t/**\n\t * {@link Enumeration} that uses fast connections.\n\t */\n\tprivate static class OptimizedEnumeration implements Enumeration<URL> {\n\n\t\tprivate final Enumeration<URL> delegate;\n\n\t\tOptimizedEnumeration(Enumeration<URL> delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasMoreElements() {\n\t\t\tOptimizations.enable(false);\n\t\t\ttry {\n\t\t\t\treturn this.delegate.hasMoreElements();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tOptimizations.disable();\n\t\t\t}\n\n\t\t}\n\n\t\t@Override\n\t\tpublic URL nextElement() {\n\t\t\tOptimizations.enable(false);\n\t\t\ttry {\n\t\t\t\treturn this.delegate.nextElement();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tOptimizations.disable();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/JarUrlConnection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.net.URLConnection;\nimport java.net.URLStreamHandler;\nimport java.security.Permission;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.springframework.boot.loader.jar.NestedJarFile;\nimport org.springframework.boot.loader.net.util.UrlDecoder;\n\n/**\n * {@link java.net.JarURLConnection} alternative to\n * {@code sun.net.www.protocol.jar.JarURLConnection} with optimized support for nested\n * jars.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Rostyslav Dudka\n */\nfinal class JarUrlConnection extends java.net.JarURLConnection {\n\n\tstatic final UrlJarFiles jarFiles = new UrlJarFiles();\n\n\tstatic final InputStream emptyInputStream = new ByteArrayInputStream(new byte[0]);\n\n\tstatic final FileNotFoundException FILE_NOT_FOUND_EXCEPTION = new FileNotFoundException(\n\t\t\t\"Jar file or entry not found\");\n\n\tprivate static final URL NOT_FOUND_URL;\n\n\tstatic final JarUrlConnection NOT_FOUND_CONNECTION;\n\tstatic {\n\t\ttry {\n\t\t\tNOT_FOUND_URL = new URL(\"jar:\", null, 0, \"nested:!/\", new EmptyUrlStreamHandler());\n\t\t\tNOT_FOUND_CONNECTION = new JarUrlConnection(() -> FILE_NOT_FOUND_EXCEPTION);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate final String entryName;\n\n\tprivate final Supplier<FileNotFoundException> notFound;\n\n\tprivate JarFile jarFile;\n\n\tprivate URLConnection jarFileConnection;\n\n\tprivate JarEntry jarEntry;\n\n\tprivate String contentType;\n\n\tprivate JarUrlConnection(URL url) throws IOException {\n\t\tsuper(url);\n\t\tthis.entryName = getEntryName();\n\t\tthis.notFound = null;\n\t\tthis.jarFileConnection = getJarFileURL().openConnection();\n\t\tthis.jarFileConnection.setUseCaches(this.useCaches);\n\t}\n\n\tprivate JarUrlConnection(Supplier<FileNotFoundException> notFound) throws IOException {\n\t\tsuper(NOT_FOUND_URL);\n\t\tthis.entryName = null;\n\t\tthis.notFound = notFound;\n\t}\n\n\t@Override\n\tpublic JarFile getJarFile() throws IOException {\n\t\tconnect();\n\t\treturn this.jarFile;\n\t}\n\n\t@Override\n\tpublic JarEntry getJarEntry() throws IOException {\n\t\tconnect();\n\t\treturn this.jarEntry;\n\t}\n\n\t@Override\n\tpublic int getContentLength() {\n\t\tlong contentLength = getContentLengthLong();\n\t\treturn (contentLength <= Integer.MAX_VALUE) ? (int) contentLength : -1;\n\t}\n\n\t@Override\n\tpublic long getContentLengthLong() {\n\t\ttry {\n\t\t\tconnect();\n\t\t\treturn (this.jarEntry != null) ? this.jarEntry.getSize() : this.jarFileConnection.getContentLengthLong();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getContentType() {\n\t\tif (this.contentType == null) {\n\t\t\tthis.contentType = deduceContentType();\n\t\t}\n\t\treturn this.contentType;\n\t}\n\n\tprivate String deduceContentType() {\n\t\tString type = (this.entryName != null) ? null : \"x-java/jar\";\n\t\ttype = (type != null) ? type : deduceContentTypeFromStream();\n\t\ttype = (type != null) ? type : deduceContentTypeFromEntryName();\n\t\treturn (type != null) ? type : \"content/unknown\";\n\t}\n\n\tprivate String deduceContentTypeFromStream() {\n\t\ttry {\n\t\t\tconnect();\n\t\t\ttry (InputStream in = this.jarFile.getInputStream(this.jarEntry)) {\n\t\t\t\treturn guessContentTypeFromStream(new BufferedInputStream(in));\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate String deduceContentTypeFromEntryName() {\n\t\treturn guessContentTypeFromName(this.entryName);\n\t}\n\n\t@Override\n\tpublic long getLastModified() {\n\t\treturn (this.jarFileConnection != null) ? this.jarFileConnection.getLastModified() : super.getLastModified();\n\t}\n\n\t@Override\n\tpublic String getHeaderField(String name) {\n\t\treturn (this.jarFileConnection != null) ? this.jarFileConnection.getHeaderField(name) : null;\n\t}\n\n\t@Override\n\tpublic Object getContent() throws IOException {\n\t\tconnect();\n\t\treturn (this.entryName != null) ? super.getContent() : this.jarFile;\n\t}\n\n\t@Override\n\tpublic Permission getPermission() throws IOException {\n\t\treturn (this.jarFileConnection != null) ? this.jarFileConnection.getPermission() : null;\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream() throws IOException {\n\t\tif (this.notFound != null) {\n\t\t\tthrowFileNotFound();\n\t\t}\n\t\tURL jarFileURL = getJarFileURL();\n\t\tif (this.entryName == null && !UrlJarFileFactory.isNestedUrl(jarFileURL)) {\n\t\t\tthrow new IOException(\"no entry name specified\");\n\t\t}\n\t\tif (!getUseCaches() && Optimizations.isEnabled(false) && this.entryName != null) {\n\t\t\tJarFile cached = jarFiles.getCached(jarFileURL);\n\t\t\tif (cached != null) {\n\t\t\t\tif (cached.getEntry(this.entryName) != null) {\n\t\t\t\t\treturn emptyInputStream;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconnect();\n\t\tif (this.jarEntry == null) {\n\t\t\tif (this.jarFile instanceof NestedJarFile nestedJarFile) {\n\t\t\t\t// In order to work with Tomcat's TLD scanning and WarURLConnection we\n\t\t\t\t// return the raw zip data rather than failing because there is no entry.\n\t\t\t\t// See gh-38047 for details.\n\t\t\t\treturn nestedJarFile.getRawZipDataInputStream();\n\t\t\t}\n\t\t\tthrowFileNotFound();\n\t\t}\n\t\treturn new ConnectionInputStream();\n\t}\n\n\t@Override\n\tpublic boolean getAllowUserInteraction() {\n\t\treturn (this.jarFileConnection != null) && this.jarFileConnection.getAllowUserInteraction();\n\t}\n\n\t@Override\n\tpublic void setAllowUserInteraction(boolean allowUserInteraction) {\n\t\tif (this.jarFileConnection != null) {\n\t\t\tthis.jarFileConnection.setAllowUserInteraction(allowUserInteraction);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean getUseCaches() {\n\t\treturn (this.jarFileConnection == null) || this.jarFileConnection.getUseCaches();\n\t}\n\n\t@Override\n\tpublic void setUseCaches(boolean useCaches) {\n\t\tif (this.jarFileConnection != null) {\n\t\t\tthis.jarFileConnection.setUseCaches(useCaches);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean getDefaultUseCaches() {\n\t\treturn (this.jarFileConnection == null) || this.jarFileConnection.getDefaultUseCaches();\n\t}\n\n\t@Override\n\tpublic void setDefaultUseCaches(boolean defaultUseCaches) {\n\t\tif (this.jarFileConnection != null) {\n\t\t\tthis.jarFileConnection.setDefaultUseCaches(defaultUseCaches);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void setIfModifiedSince(long ifModifiedSince) {\n\t\tif (this.jarFileConnection != null) {\n\t\t\tthis.jarFileConnection.setIfModifiedSince(ifModifiedSince);\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getRequestProperty(String key) {\n\t\treturn (this.jarFileConnection != null) ? this.jarFileConnection.getRequestProperty(key) : null;\n\t}\n\n\t@Override\n\tpublic void setRequestProperty(String key, String value) {\n\t\tif (this.jarFileConnection != null) {\n\t\t\tthis.jarFileConnection.setRequestProperty(key, value);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void addRequestProperty(String key, String value) {\n\t\tif (this.jarFileConnection != null) {\n\t\t\tthis.jarFileConnection.addRequestProperty(key, value);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Map<String, List<String>> getRequestProperties() {\n\t\treturn (this.jarFileConnection != null) ? this.jarFileConnection.getRequestProperties()\n\t\t\t\t: Collections.emptyMap();\n\t}\n\n\t@Override\n\tpublic void connect() throws IOException {\n\t\tif (this.connected) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.notFound != null) {\n\t\t\tthrowFileNotFound();\n\t\t}\n\t\tboolean useCaches = getUseCaches();\n\t\tURL jarFileURL = getJarFileURL();\n\t\tif (this.entryName != null && Optimizations.isEnabled()) {\n\t\t\tassertCachedJarFileHasEntry(jarFileURL, this.entryName);\n\t\t}\n\t\tthis.jarFile = jarFiles.getOrCreate(useCaches, jarFileURL);\n\t\tthis.jarEntry = getJarEntry(jarFileURL);\n\t\tboolean addedToCache = jarFiles.cacheIfAbsent(useCaches, jarFileURL, this.jarFile);\n\t\tif (addedToCache) {\n\t\t\tthis.jarFileConnection = jarFiles.reconnect(this.jarFile, this.jarFileConnection);\n\t\t}\n\t\tthis.connected = true;\n\t}\n\n\t/**\n\t * The {@link URLClassLoader} connects often to check if a resource exists, we can\n\t * save some object allocations by using the cached copy if we have one.\n\t * @param jarFileURL the jar file to check\n\t * @param entryName the entry name to check\n\t * @throws FileNotFoundException on a missing entry\n\t */\n\tprivate void assertCachedJarFileHasEntry(URL jarFileURL, String entryName) throws FileNotFoundException {\n\t\tJarFile cachedJarFile = jarFiles.getCached(jarFileURL);\n\t\tif (cachedJarFile != null && cachedJarFile.getJarEntry(entryName) == null) {\n\t\t\tthrow FILE_NOT_FOUND_EXCEPTION;\n\t\t}\n\t}\n\n\tprivate JarEntry getJarEntry(URL jarFileUrl) throws IOException {\n\t\tif (this.entryName == null) {\n\t\t\treturn null;\n\t\t}\n\t\tJarEntry jarEntry = this.jarFile.getJarEntry(this.entryName);\n\t\tif (jarEntry == null) {\n\t\t\tjarFiles.closeIfNotCached(jarFileUrl, this.jarFile);\n\t\t\tthrowFileNotFound();\n\t\t}\n\t\treturn jarEntry;\n\t}\n\n\tprivate void throwFileNotFound() throws FileNotFoundException {\n\t\tif (Optimizations.isEnabled()) {\n\t\t\tthrow FILE_NOT_FOUND_EXCEPTION;\n\t\t}\n\t\tif (this.notFound != null) {\n\t\t\tthrow this.notFound.get();\n\t\t}\n\t\tthrow new FileNotFoundException(\"JAR entry \" + this.entryName + \" not found in \" + this.jarFile.getName());\n\t}\n\n\tstatic JarUrlConnection open(URL url) throws IOException {\n\t\tString spec = url.getFile();\n\t\tif (spec.startsWith(\"nested:\")) {\n\t\t\tint separator = spec.indexOf(\"!/\");\n\t\t\tboolean specHasEntry = (separator != -1) && (separator + 2 != spec.length());\n\t\t\tif (specHasEntry) {\n\t\t\t\tURL jarFileUrl = new URL(spec.substring(0, separator));\n\t\t\t\tif (\"runtime\".equals(url.getRef())) {\n\t\t\t\t\tjarFileUrl = new URL(jarFileUrl, \"#runtime\");\n\t\t\t\t}\n\t\t\t\tString entryName = UrlDecoder.decode(spec.substring(separator + 2));\n\t\t\t\tJarFile jarFile = jarFiles.getOrCreate(true, jarFileUrl);\n\t\t\t\tjarFiles.cacheIfAbsent(true, jarFileUrl, jarFile);\n\t\t\t\tif (!hasEntry(jarFile, entryName)) {\n\t\t\t\t\treturn notFoundConnection(jarFile.getName(), entryName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new JarUrlConnection(url);\n\t}\n\n\tprivate static boolean hasEntry(JarFile jarFile, String name) {\n\t\treturn (jarFile instanceof NestedJarFile nestedJarFile) ? nestedJarFile.hasEntry(name)\n\t\t\t\t: jarFile.getEntry(name) != null;\n\t}\n\n\tprivate static JarUrlConnection notFoundConnection(String jarFileName, String entryName) throws IOException {\n\t\tif (Optimizations.isEnabled()) {\n\t\t\treturn NOT_FOUND_CONNECTION;\n\t\t}\n\t\treturn new JarUrlConnection(\n\t\t\t\t() -> new FileNotFoundException(\"JAR entry \" + entryName + \" not found in \" + jarFileName));\n\t}\n\n\tstatic void clearCache() {\n\t\tjarFiles.clearCache();\n\t}\n\n\t/**\n\t * Connection {@link InputStream}. This is not a {@link FilterInputStream} since\n\t * {@link URLClassLoader} often creates streams that it doesn't call and we want to be\n\t * lazy about getting the underlying {@link InputStream}.\n\t */\n\tclass ConnectionInputStream extends LazyDelegatingInputStream {\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\ttry {\n\t\t\t\tsuper.close();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tif (!getUseCaches()) {\n\t\t\t\t\tJarUrlConnection.this.jarFile.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected InputStream getDelegateInputStream() throws IOException {\n\t\t\treturn JarUrlConnection.this.jarFile.getInputStream(JarUrlConnection.this.jarEntry);\n\t\t}\n\n\t}\n\n\t/**\n\t * Empty {@link URLStreamHandler} used to prevent the wrong JAR Handler from being\n\t * Instantiated and cached.\n\t */\n\tprivate static final class EmptyUrlStreamHandler extends URLStreamHandler {\n\n\t\t@Override\n\t\tprotected URLConnection openConnection(URL url) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/LazyDelegatingInputStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * {@link InputStream} that delegates lazily to another {@link InputStream}.\n *\n * @author Phillip Webb\n */\nabstract class LazyDelegatingInputStream extends InputStream {\n\n\tprivate volatile InputStream in;\n\n\t@Override\n\tpublic int read() throws IOException {\n\t\treturn in().read();\n\t}\n\n\t@Override\n\tpublic int read(byte[] b) throws IOException {\n\t\treturn in().read(b);\n\t}\n\n\t@Override\n\tpublic int read(byte[] b, int off, int len) throws IOException {\n\t\treturn in().read(b, off, len);\n\t}\n\n\t@Override\n\tpublic long skip(long n) throws IOException {\n\t\treturn in().skip(n);\n\t}\n\n\t@Override\n\tpublic int available() throws IOException {\n\t\treturn in().available();\n\t}\n\n\t@Override\n\tpublic boolean markSupported() {\n\t\ttry {\n\t\t\treturn in().markSupported();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic synchronized void mark(int readLimit) {\n\t\ttry {\n\t\t\tin().mark(readLimit);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t@Override\n\tpublic synchronized void reset() throws IOException {\n\t\tin().reset();\n\t}\n\n\tprivate InputStream in() throws IOException {\n\t\tInputStream in = this.in;\n\t\tif (in == null) {\n\t\t\tsynchronized (this) {\n\t\t\t\tin = this.in;\n\t\t\t\tif (in == null) {\n\t\t\t\t\tin = getDelegateInputStream();\n\t\t\t\t\tthis.in = in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn in;\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tInputStream in = this.in;\n\t\tif (in != null) {\n\t\t\tsynchronized (this) {\n\t\t\t\tin = this.in;\n\t\t\t\tif (in != null) {\n\t\t\t\t\tin.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected abstract InputStream getDelegateInputStream() throws IOException;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/Optimizations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\n/**\n * {@link ThreadLocal} state for {@link Handler} optimizations.\n *\n * @author Phillip Webb\n */\nfinal class Optimizations {\n\n\tprivate static final ThreadLocal<Boolean> status = new ThreadLocal<>();\n\n\tprivate Optimizations() {\n\t}\n\n\tstatic void enable(boolean readContents) {\n\t\tstatus.set(readContents);\n\t}\n\n\tstatic void disable() {\n\t\tstatus.remove();\n\t}\n\n\tstatic boolean isEnabled() {\n\t\treturn status.get() != null;\n\t}\n\n\tstatic boolean isEnabled(boolean readContents) {\n\t\treturn Boolean.valueOf(readContents).equals(status.get());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/UrlJarEntry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.zip.ZipEntry;\n\n/**\n * A {@link JarEntry} returned from a {@link UrlJarFile} or {@link UrlNestedJarFile}.\n *\n * @author Phillip Webb\n */\nfinal class UrlJarEntry extends JarEntry {\n\n\tprivate final UrlJarManifest manifest;\n\n\tprivate UrlJarEntry(JarEntry entry, UrlJarManifest manifest) {\n\t\tsuper(entry);\n\t\tthis.manifest = manifest;\n\t}\n\n\t@Override\n\tpublic Attributes getAttributes() throws IOException {\n\t\treturn this.manifest.getEntryAttributes(this);\n\t}\n\n\tstatic UrlJarEntry of(ZipEntry entry, UrlJarManifest manifest) {\n\t\treturn (entry != null) ? new UrlJarEntry((JarEntry) entry, manifest) : null;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/UrlJarFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.function.Consumer;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport org.springframework.boot.loader.ref.Cleaner;\n\n/**\n * A {@link JarFile} subclass returned from a {@link JarUrlConnection}.\n *\n * @author Phillip Webb\n */\nclass UrlJarFile extends JarFile {\n\n\tprivate final UrlJarManifest manifest;\n\n\tprivate final Consumer<JarFile> closeAction;\n\n\tUrlJarFile(File file, Runtime.Version version, Consumer<JarFile> closeAction) throws IOException {\n\t\tsuper(file, true, ZipFile.OPEN_READ, version);\n\t\t// Registered only for test cleanup since parent class is JarFile\n\t\tCleaner.instance.register(this, null);\n\t\tthis.manifest = new UrlJarManifest(super::getManifest);\n\t\tthis.closeAction = closeAction;\n\t}\n\n\t@Override\n\tpublic ZipEntry getEntry(String name) {\n\t\treturn UrlJarEntry.of(super.getEntry(name), this.manifest);\n\t}\n\n\t@Override\n\tpublic Manifest getManifest() throws IOException {\n\t\treturn this.manifest.get();\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tif (this.closeAction != null) {\n\t\t\tthis.closeAction.accept(this);\n\t\t}\n\t\tsuper.close();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/UrlJarFileFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.Runtime.Version;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.util.function.Consumer;\nimport java.util.jar.JarFile;\n\nimport org.springframework.boot.loader.net.protocol.nested.NestedLocation;\nimport org.springframework.boot.loader.net.util.UrlDecoder;\n\n/**\n * Factory used by {@link UrlJarFiles} to create {@link JarFile} instances.\n *\n * @author Phillip Webb\n * @see UrlJarFile\n * @see UrlNestedJarFile\n */\nclass UrlJarFileFactory {\n\n\t/**\n\t * Create a new {@link UrlJarFile} or {@link UrlNestedJarFile} instance.\n\t * @param jarFileUrl the jar file URL\n\t * @param closeAction the action to call when the file is closed\n\t * @return a new {@link JarFile} instance\n\t * @throws IOException on I/O error\n\t */\n\tJarFile createJarFile(URL jarFileUrl, Consumer<JarFile> closeAction) throws IOException {\n\t\tRuntime.Version version = getVersion(jarFileUrl);\n\t\tif (isLocalFileUrl(jarFileUrl)) {\n\t\t\treturn createJarFileForLocalFile(jarFileUrl, version, closeAction);\n\t\t}\n\t\tif (isNestedUrl(jarFileUrl)) {\n\t\t\treturn createJarFileForNested(jarFileUrl, version, closeAction);\n\t\t}\n\t\treturn createJarFileForStream(jarFileUrl, version, closeAction);\n\t}\n\n\tprivate Runtime.Version getVersion(URL url) {\n\t\t// The standard JDK handler uses #runtime to indicate that the runtime version\n\t\t// should be used. This unfortunately doesn't work for us as\n\t\t// jdk.internal.loader.URLClassPath only adds the runtime fragment when the URL\n\t\t// is using the internal JDK handler. We need to flip the default to use\n\t\t// the runtime version. See gh-38050\n\t\treturn \"base\".equals(url.getRef()) ? JarFile.baseVersion() : JarFile.runtimeVersion();\n\t}\n\n\tprivate boolean isLocalFileUrl(URL url) {\n\t\treturn url.getProtocol().equalsIgnoreCase(\"file\") && isLocal(url.getHost());\n\t}\n\n\tprivate boolean isLocal(String host) {\n\t\treturn host == null || host.isEmpty() || host.equals(\"~\") || host.equalsIgnoreCase(\"localhost\");\n\t}\n\n\tprivate JarFile createJarFileForLocalFile(URL url, Runtime.Version version, Consumer<JarFile> closeAction)\n\t\t\tthrows IOException {\n\t\tString path = UrlDecoder.decode(url.getPath());\n\t\treturn new UrlJarFile(new File(path), version, closeAction);\n\t}\n\n\tprivate JarFile createJarFileForNested(URL url, Runtime.Version version, Consumer<JarFile> closeAction)\n\t\t\tthrows IOException {\n\t\tNestedLocation location = NestedLocation.fromUrl(url);\n\t\treturn new UrlNestedJarFile(location.path().toFile(), location.nestedEntryName(), version, closeAction);\n\t}\n\n\tprivate JarFile createJarFileForStream(URL url, Version version, Consumer<JarFile> closeAction) throws IOException {\n\t\ttry (InputStream in = url.openStream()) {\n\t\t\treturn createJarFileForStream(in, version, closeAction);\n\t\t}\n\t}\n\n\tprivate JarFile createJarFileForStream(InputStream in, Version version, Consumer<JarFile> closeAction)\n\t\t\tthrows IOException {\n\t\tPath local = Files.createTempFile(\"jar_cache\", null);\n\t\ttry {\n\t\t\tFiles.copy(in, local, StandardCopyOption.REPLACE_EXISTING);\n\t\t\tJarFile jarFile = new UrlJarFile(local.toFile(), version, closeAction);\n\t\t\tlocal.toFile().deleteOnExit();\n\t\t\treturn jarFile;\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tdeleteIfPossible(local, ex);\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate void deleteIfPossible(Path local, Throwable cause) {\n\t\ttry {\n\t\t\tFiles.delete(local);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tcause.addSuppressed(ex);\n\t\t}\n\t}\n\n\tstatic boolean isNestedUrl(URL url) {\n\t\treturn url.getProtocol().equalsIgnoreCase(\"nested\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/UrlJarFiles.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.jar.JarFile;\n\n/**\n * Provides access to {@link UrlJarFile} and {@link UrlNestedJarFile} instances taking\n * care of caching concerns when necessary.\n * <p>\n * This class is thread-safe and designed to be shared by all {@link JarUrlConnection}\n * instances.\n *\n * @author Phillip Webb\n */\nclass UrlJarFiles {\n\n\tprivate final UrlJarFileFactory factory;\n\n\tprivate final Cache cache = new Cache();\n\n\t/**\n\t * Create a new {@link UrlJarFiles} instance.\n\t */\n\tUrlJarFiles() {\n\t\tthis(new UrlJarFileFactory());\n\t}\n\n\t/**\n\t * Create a new {@link UrlJarFiles} instance.\n\t * @param factory the {@link UrlJarFileFactory} to use.\n\t */\n\tUrlJarFiles(UrlJarFileFactory factory) {\n\t\tthis.factory = factory;\n\t}\n\n\t/**\n\t * Get an existing {@link JarFile} instance from the cache, or create a new\n\t * {@link JarFile} instance that can be {@link #cacheIfAbsent(boolean, URL, JarFile)\n\t * cached later}.\n\t * @param useCaches if caches can be used\n\t * @param jarFileUrl the jar file URL\n\t * @return a new or existing {@link JarFile} instance\n\t * @throws IOException on I/O error\n\t */\n\tJarFile getOrCreate(boolean useCaches, URL jarFileUrl) throws IOException {\n\t\tif (useCaches) {\n\t\t\tJarFile cached = getCached(jarFileUrl);\n\t\t\tif (cached != null) {\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t}\n\t\treturn this.factory.createJarFile(jarFileUrl, this::onClose);\n\t}\n\n\t/**\n\t * Return the cached {@link JarFile} if available.\n\t * @param jarFileUrl the jar file URL\n\t * @return the cached jar or {@code null}\n\t */\n\tJarFile getCached(URL jarFileUrl) {\n\t\treturn this.cache.get(jarFileUrl);\n\t}\n\n\t/**\n\t * Cache the given {@link JarFile} if caching can be used and there is no existing\n\t * entry.\n\t * @param useCaches if caches can be used\n\t * @param jarFileUrl the jar file URL\n\t * @param jarFile the jar file\n\t * @return {@code true} if that file was added to the cache\n\t */\n\tboolean cacheIfAbsent(boolean useCaches, URL jarFileUrl, JarFile jarFile) {\n\t\tif (!useCaches) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.cache.putIfAbsent(jarFileUrl, jarFile);\n\t}\n\n\t/**\n\t * Close the given {@link JarFile} only if it is not contained in the cache.\n\t * @param jarFileUrl the jar file URL\n\t * @param jarFile the jar file\n\t * @throws IOException on I/O error\n\t */\n\tvoid closeIfNotCached(URL jarFileUrl, JarFile jarFile) throws IOException {\n\t\tJarFile cached = getCached(jarFileUrl);\n\t\tif (cached != jarFile) {\n\t\t\tjarFile.close();\n\t\t}\n\t}\n\n\t/**\n\t * Reconnect to the {@link JarFile}, returning a replacement {@link URLConnection}.\n\t * @param jarFile the jar file\n\t * @param existingConnection the existing connection\n\t * @return a newly opened connection inhering the same {@code useCaches} value as the\n\t * existing connection\n\t * @throws IOException on I/O error\n\t */\n\tURLConnection reconnect(JarFile jarFile, URLConnection existingConnection) throws IOException {\n\t\tBoolean useCaches = (existingConnection != null) ? existingConnection.getUseCaches() : null;\n\t\tURLConnection connection = openConnection(jarFile);\n\t\tif (useCaches != null && connection != null) {\n\t\t\tconnection.setUseCaches(useCaches);\n\t\t}\n\t\treturn connection;\n\t}\n\n\tprivate URLConnection openConnection(JarFile jarFile) throws IOException {\n\t\tURL url = this.cache.get(jarFile);\n\t\treturn (url != null) ? url.openConnection() : null;\n\t}\n\n\tprivate void onClose(JarFile jarFile) {\n\t\tthis.cache.remove(jarFile);\n\t}\n\n\tvoid clearCache() {\n\t\tthis.cache.clear();\n\t}\n\n\t/**\n\t * Internal cache.\n\t */\n\tprivate static final class Cache {\n\n\t\tprivate final Map<JarFileUrlKey, JarFile> jarFileUrlToJarFile = new HashMap<>();\n\n\t\tprivate final Map<JarFile, URL> jarFileToJarFileUrl = new HashMap<>();\n\n\t\t/**\n\t\t * Get a {@link JarFile} from the cache given a jar file URL.\n\t\t * @param jarFileUrl the jar file URL\n\t\t * @return the cached {@link JarFile} or {@code null}\n\t\t */\n\t\tJarFile get(URL jarFileUrl) {\n\t\t\tJarFileUrlKey urlKey = new JarFileUrlKey(jarFileUrl);\n\t\t\tsynchronized (this) {\n\t\t\t\treturn this.jarFileUrlToJarFile.get(urlKey);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Get a jar file URL from the cache given a jar file.\n\t\t * @param jarFile the jar file\n\t\t * @return the cached {@link URL} or {@code null}\n\t\t */\n\t\tURL get(JarFile jarFile) {\n\t\t\tsynchronized (this) {\n\t\t\t\treturn this.jarFileToJarFileUrl.get(jarFile);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Put the given jar file URL and jar file into the cache if they aren't already\n\t\t * there.\n\t\t * @param jarFileUrl the jar file URL\n\t\t * @param jarFile the jar file\n\t\t * @return {@code true} if the items were added to the cache or {@code false} if\n\t\t * they were already there\n\t\t */\n\t\tboolean putIfAbsent(URL jarFileUrl, JarFile jarFile) {\n\t\t\tJarFileUrlKey urlKey = new JarFileUrlKey(jarFileUrl);\n\t\t\tsynchronized (this) {\n\t\t\t\tJarFile cached = this.jarFileUrlToJarFile.get(urlKey);\n\t\t\t\tif (cached == null) {\n\t\t\t\t\tthis.jarFileUrlToJarFile.put(urlKey, jarFile);\n\t\t\t\t\tthis.jarFileToJarFileUrl.put(jarFile, jarFileUrl);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Remove the given jar and any related URL file from the cache.\n\t\t * @param jarFile the jar file to remove\n\t\t */\n\t\tvoid remove(JarFile jarFile) {\n\t\t\tsynchronized (this) {\n\t\t\t\tURL removedUrl = this.jarFileToJarFileUrl.remove(jarFile);\n\t\t\t\tif (removedUrl != null) {\n\t\t\t\t\tthis.jarFileUrlToJarFile.remove(new JarFileUrlKey(removedUrl));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid clear() {\n\t\t\tsynchronized (this) {\n\t\t\t\tthis.jarFileToJarFileUrl.clear();\n\t\t\t\tthis.jarFileUrlToJarFile.clear();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/UrlJarManifest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.Manifest;\n\n/**\n * Provides access {@link Manifest} content that can be safely returned from\n * {@link UrlJarFile} or {@link UrlNestedJarFile}.\n *\n * @author Phillip Webb\n */\nclass UrlJarManifest {\n\n\tprivate static final Object NONE = new Object();\n\n\tprivate final ManifestSupplier supplier;\n\n\tprivate volatile Object supplied;\n\n\tUrlJarManifest(ManifestSupplier supplier) {\n\t\tthis.supplier = supplier;\n\t}\n\n\tManifest get() throws IOException {\n\t\tManifest manifest = supply();\n\t\tif (manifest == null) {\n\t\t\treturn null;\n\t\t}\n\t\tManifest copy = new Manifest();\n\t\tcopy.getMainAttributes().putAll((Map<?, ?>) manifest.getMainAttributes().clone());\n\t\tmanifest.getEntries().forEach((key, value) -> copy.getEntries().put(key, cloneAttributes(value)));\n\t\treturn copy;\n\t}\n\n\tAttributes getEntryAttributes(JarEntry entry) throws IOException {\n\t\tManifest manifest = supply();\n\t\tif (manifest == null) {\n\t\t\treturn null;\n\t\t}\n\t\tAttributes attributes = manifest.getEntries().get(entry.getName());\n\t\treturn cloneAttributes(attributes);\n\t}\n\n\tprivate Attributes cloneAttributes(Attributes attributes) {\n\t\treturn (attributes != null) ? (Attributes) attributes.clone() : null;\n\t}\n\n\tprivate Manifest supply() throws IOException {\n\t\tObject supplied = this.supplied;\n\t\tif (supplied == null) {\n\t\t\tsupplied = this.supplier.getManifest();\n\t\t\tthis.supplied = (supplied != null) ? supplied : NONE;\n\t\t}\n\t\treturn (supplied != NONE) ? (Manifest) supplied : null;\n\t}\n\n\t/**\n\t * Interface used to supply the actual manifest.\n\t */\n\t@FunctionalInterface\n\tinterface ManifestSupplier {\n\n\t\tManifest getManifest() throws IOException;\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/UrlNestedJarFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.Runtime.Version;\nimport java.util.function.Consumer;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.springframework.boot.loader.jar.NestedJarFile;\n\n/**\n * {@link NestedJarFile} subclass returned from a {@link JarUrlConnection}.\n *\n * @author Phillip Webb\n */\nclass UrlNestedJarFile extends NestedJarFile {\n\n\tprivate final UrlJarManifest manifest;\n\n\tprivate final Consumer<JarFile> closeAction;\n\n\tUrlNestedJarFile(File file, String nestedEntryName, Version version, Consumer<JarFile> closeAction)\n\t\t\tthrows IOException {\n\t\tsuper(file, nestedEntryName, version);\n\t\tthis.manifest = new UrlJarManifest(super::getManifest);\n\t\tthis.closeAction = closeAction;\n\t}\n\n\t@Override\n\tpublic Manifest getManifest() throws IOException {\n\t\treturn this.manifest.get();\n\t}\n\n\t@Override\n\tpublic JarEntry getEntry(String name) {\n\t\treturn UrlJarEntry.of(super.getEntry(name), this.manifest);\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tif (this.closeAction != null) {\n\t\t\tthis.closeAction.accept(this);\n\t\t}\n\t\tsuper.close();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/jar/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * JAR URL support, including support for nested jars.\n *\n * @see org.springframework.boot.loader.net.protocol.jar.JarUrl\n * @see org.springframework.boot.loader.net.protocol.jar.Handler\n */\npackage org.springframework.boot.loader.net.protocol.jar;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/Handler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLStreamHandler;\n\n/**\n * {@link URLStreamHandler} to support {@code nested:} URLs. See {@link NestedLocation}\n * for details of the URL format.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic class Handler extends URLStreamHandler {\n\n\t// NOTE: in order to be found as a URL protocol handler, this class must be public,\n\t// must be named Handler and must be in a package ending '.nested'\n\n\tprivate static final String PREFIX = \"nested:\";\n\n\t@Override\n\tprotected InetAddress getHostAddress(URL url) {\n\t\t// Some Windows users have reported that calls to java.net.URL.getHostAddress()\n\t\t// can be slow. Since we only deal with local files we always return null here.\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected URLConnection openConnection(URL url) throws IOException {\n\t\treturn new NestedUrlConnection(url);\n\t}\n\n\t/**\n\t * Assert that the specified URL is a valid \"nested\" URL.\n\t * @param url the URL to check\n\t */\n\tpublic static void assertUrlIsNotMalformed(String url) {\n\t\tif (url == null || !url.startsWith(PREFIX)) {\n\t\t\tthrow new IllegalArgumentException(\"'url' must not be null and must use 'nested' protocol\");\n\t\t}\n\t\tNestedLocation.parse(url.substring(PREFIX.length()));\n\t}\n\n\t/**\n\t * Clear any internal caches.\n\t */\n\tpublic static void clearCache() {\n\t\tNestedLocation.clearCache();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedLocation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.file.Path;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.springframework.boot.loader.net.util.UrlDecoder;\n\n/**\n * A location obtained from a {@code nested:} {@link URL} consisting of a jar file and an\n * optional nested entry.\n * <p>\n * The syntax of a nested JAR URL is: <pre>\n * nestedjar:&lt;path&gt;/!{entry}\n * </pre>\n * <p>\n * for example:\n * <p>\n * {@code nested:/home/example/my.jar/!BOOT-INF/lib/my-nested.jar}\n * <p>\n * or:\n * <p>\n * {@code nested:/home/example/my.jar/!BOOT-INF/classes/}\n * <p>\n * The path must refer to a jar file on the file system. The entry refers to either an\n * uncompressed entry that contains the nested jar, or a directory entry. The entry must\n * not start with a {@code '/'}.\n *\n * @param path the path to the zip that contains the nested entry\n * @param nestedEntryName the nested entry name\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 3.2.0\n */\npublic record NestedLocation(Path path, String nestedEntryName) {\n\n\tprivate static final Map<String, NestedLocation> locationCache = new ConcurrentHashMap<>();\n\n\tprivate static final Map<String, Path> pathCache = new ConcurrentHashMap<>();\n\n\tpublic NestedLocation(Path path, String nestedEntryName) {\n\t\tif (path == null) {\n\t\t\tthrow new IllegalArgumentException(\"'path' must not be null\");\n\t\t}\n\t\tthis.path = path;\n\t\tthis.nestedEntryName = (nestedEntryName != null && !nestedEntryName.isEmpty()) ? nestedEntryName : null;\n\t}\n\n\t/**\n\t * Create a new {@link NestedLocation} from the given URL.\n\t * @param url the nested URL\n\t * @return a new {@link NestedLocation} instance\n\t * @throws IllegalArgumentException if the URL is not valid\n\t */\n\tpublic static NestedLocation fromUrl(URL url) {\n\t\tif (url == null || !\"nested\".equalsIgnoreCase(url.getProtocol())) {\n\t\t\tthrow new IllegalArgumentException(\"'url' must not be null and must use 'nested' protocol\");\n\t\t}\n\t\treturn parse(UrlDecoder.decode(url.toString().substring(7)));\n\t}\n\n\t/**\n\t * Create a new {@link NestedLocation} from the given URI.\n\t * @param uri the nested URI\n\t * @return a new {@link NestedLocation} instance\n\t * @throws IllegalArgumentException if the URI is not valid\n\t */\n\tpublic static NestedLocation fromUri(URI uri) {\n\t\tif (uri == null || !\"nested\".equalsIgnoreCase(uri.getScheme())) {\n\t\t\tthrow new IllegalArgumentException(\"'uri' must not be null and must use 'nested' scheme\");\n\t\t}\n\t\treturn parse(uri.getSchemeSpecificPart());\n\t}\n\n\tstatic NestedLocation parse(String location) {\n\t\tif (location == null || location.isEmpty()) {\n\t\t\tthrow new IllegalArgumentException(\"'location' must not be empty\");\n\t\t}\n\t\treturn locationCache.computeIfAbsent(location, (key) -> create(location));\n\t}\n\n\tprivate static NestedLocation create(String location) {\n\t\tint index = location.lastIndexOf(\"/!\");\n\t\tString locationPath = (index != -1) ? location.substring(0, index) : location;\n\t\tString nestedEntryName = (index != -1) ? location.substring(index + 2) : null;\n\t\treturn new NestedLocation((!locationPath.isEmpty()) ? asPath(locationPath) : null, nestedEntryName);\n\t}\n\n\tprivate static Path asPath(String locationPath) {\n\t\treturn pathCache.computeIfAbsent(locationPath,\n\t\t\t\t(key) -> Path.of((!isWindows()) ? locationPath : fixWindowsLocationPath(locationPath)));\n\t}\n\n\tprivate static boolean isWindows() {\n\t\treturn File.separatorChar == '\\\\';\n\t}\n\n\tprivate static String fixWindowsLocationPath(String locationPath) {\n\t\t// Same logic as Java's internal WindowsUriSupport class\n\t\tif (locationPath.length() > 2 && locationPath.charAt(2) == ':') {\n\t\t\treturn locationPath.substring(1);\n\t\t}\n\t\t// Deal with Jetty's org.eclipse.jetty.util.URIUtil#correctURI(URI)\n\t\tif (locationPath.startsWith(\"///\") && locationPath.charAt(4) == ':') {\n\t\t\treturn locationPath.substring(3);\n\t\t}\n\t\treturn locationPath;\n\t}\n\n\tstatic void clearCache() {\n\t\tlocationCache.clear();\n\t\tpathCache.clear();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedUrlConnection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.File;\nimport java.io.FilePermission;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.nio.file.Files;\nimport java.security.Permission;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.springframework.boot.loader.ref.Cleaner;\n\n/**\n * {@link URLConnection} to support {@code nested:} URLs. See {@link NestedLocation} for\n * details of the URL format.\n *\n * @author Phillip Webb\n */\nclass NestedUrlConnection extends URLConnection {\n\n\tprivate static final DateTimeFormatter RFC_1123_DATE_TIME = DateTimeFormatter.RFC_1123_DATE_TIME\n\t\t.withZone(ZoneId.of(\"GMT\"));\n\n\tprivate static final String CONTENT_TYPE = \"x-java/jar\";\n\n\tprivate final NestedUrlConnectionResources resources;\n\n\tprivate final Cleanable cleanup;\n\n\tprivate long lastModified = -1;\n\n\tprivate FilePermission permission;\n\n\tprivate Map<String, List<String>> headerFields;\n\n\tNestedUrlConnection(URL url) throws MalformedURLException {\n\t\tthis(url, Cleaner.instance);\n\t}\n\n\tNestedUrlConnection(URL url, Cleaner cleaner) throws MalformedURLException {\n\t\tsuper(url);\n\t\tNestedLocation location = parseNestedLocation(url);\n\t\tthis.resources = new NestedUrlConnectionResources(location);\n\t\tthis.cleanup = cleaner.register(this, this.resources);\n\t}\n\n\tprivate NestedLocation parseNestedLocation(URL url) throws MalformedURLException {\n\t\ttry {\n\t\t\treturn NestedLocation.fromUrl(url);\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\tthrow new MalformedURLException(ex.getMessage());\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getHeaderField(String name) {\n\t\tList<String> values = getHeaderFields().get(name);\n\t\treturn (values != null && !values.isEmpty()) ? values.get(0) : null;\n\t}\n\n\t@Override\n\tpublic String getHeaderField(int n) {\n\t\tEntry<String, List<String>> entry = getHeaderEntry(n);\n\t\tList<String> values = (entry != null) ? entry.getValue() : null;\n\t\treturn (values != null && !values.isEmpty()) ? values.get(0) : null;\n\t}\n\n\t@Override\n\tpublic String getHeaderFieldKey(int n) {\n\t\tEntry<String, List<String>> entry = getHeaderEntry(n);\n\t\treturn (entry != null) ? entry.getKey() : null;\n\t}\n\n\tprivate Entry<String, List<String>> getHeaderEntry(int n) {\n\t\tIterator<Entry<String, List<String>>> iterator = getHeaderFields().entrySet().iterator();\n\t\tEntry<String, List<String>> entry = null;\n\t\tfor (int i = 0; i < n; i++) {\n\t\t\tentry = (!iterator.hasNext()) ? null : iterator.next();\n\t\t}\n\t\treturn entry;\n\t}\n\n\t@Override\n\tpublic Map<String, List<String>> getHeaderFields() {\n\t\ttry {\n\t\t\tconnect();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<String, List<String>> headerFields = this.headerFields;\n\t\tif (headerFields == null) {\n\t\t\theaderFields = new LinkedHashMap<>();\n\t\t\tlong contentLength = getContentLengthLong();\n\t\t\tlong lastModified = getLastModified();\n\t\t\tif (contentLength > 0) {\n\t\t\t\theaderFields.put(\"content-length\", List.of(String.valueOf(contentLength)));\n\t\t\t}\n\t\t\tif (getLastModified() > 0) {\n\t\t\t\theaderFields.put(\"last-modified\",\n\t\t\t\t\t\tList.of(RFC_1123_DATE_TIME.format(Instant.ofEpochMilli(lastModified))));\n\t\t\t}\n\t\t\theaderFields = Collections.unmodifiableMap(headerFields);\n\t\t\tthis.headerFields = headerFields;\n\t\t}\n\t\treturn headerFields;\n\t}\n\n\t@Override\n\tpublic int getContentLength() {\n\t\tlong contentLength = getContentLengthLong();\n\t\treturn (contentLength <= Integer.MAX_VALUE) ? (int) contentLength : -1;\n\t}\n\n\t@Override\n\tpublic long getContentLengthLong() {\n\t\ttry {\n\t\t\tconnect();\n\t\t\treturn this.resources.getContentLength();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\t@Override\n\tpublic String getContentType() {\n\t\treturn CONTENT_TYPE;\n\t}\n\n\t@Override\n\tpublic long getLastModified() {\n\t\tif (this.lastModified == -1) {\n\t\t\ttry {\n\t\t\t\tthis.lastModified = Files.getLastModifiedTime(this.resources.getLocation().path()).toMillis();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthis.lastModified = 0;\n\t\t\t}\n\t\t}\n\t\treturn this.lastModified;\n\t}\n\n\t@Override\n\tpublic Permission getPermission() throws IOException {\n\t\tif (this.permission == null) {\n\t\t\tFile file = this.resources.getLocation().path().toFile();\n\t\t\tthis.permission = new FilePermission(file.getCanonicalPath(), \"read\");\n\t\t}\n\t\treturn this.permission;\n\t}\n\n\t@Override\n\tpublic InputStream getInputStream() throws IOException {\n\t\tconnect();\n\t\treturn new ConnectionInputStream(this.resources.getInputStream());\n\t}\n\n\t@Override\n\tpublic void connect() throws IOException {\n\t\tif (this.connected) {\n\t\t\treturn;\n\t\t}\n\t\tthis.resources.connect();\n\t\tthis.connected = true;\n\t}\n\n\t/**\n\t * Connection {@link InputStream}.\n\t */\n\tclass ConnectionInputStream extends FilterInputStream {\n\n\t\tprivate volatile boolean closing;\n\n\t\tConnectionInputStream(InputStream in) {\n\t\t\tsuper(in);\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tif (this.closing) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.closing = true;\n\t\t\ttry {\n\t\t\t\tsuper.close();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\ttry {\n\t\t\t\t\tNestedUrlConnection.this.cleanup.clean();\n\t\t\t\t}\n\t\t\t\tcatch (UncheckedIOException ex) {\n\t\t\t\t\tthrow ex.getCause();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/NestedUrlConnectionResources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\n\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.zip.CloseableDataBlock;\nimport org.springframework.boot.loader.zip.ZipContent;\n\n/**\n * Resources created managed and cleaned by a {@link NestedUrlConnection} instance and\n * suitable for registration with a {@link Cleaner}.\n *\n * @author Phillip Webb\n */\nclass NestedUrlConnectionResources implements Runnable {\n\n\tprivate final NestedLocation location;\n\n\tprivate volatile ZipContent zipContent;\n\n\tprivate volatile long size = -1;\n\n\tprivate volatile InputStream inputStream;\n\n\tNestedUrlConnectionResources(NestedLocation location) {\n\t\tthis.location = location;\n\t}\n\n\tNestedLocation getLocation() {\n\t\treturn this.location;\n\t}\n\n\tvoid connect() throws IOException {\n\t\tsynchronized (this) {\n\t\t\tif (this.zipContent == null) {\n\t\t\t\tthis.zipContent = ZipContent.open(this.location.path(), this.location.nestedEntryName());\n\t\t\t\ttry {\n\t\t\t\t\tconnectData();\n\t\t\t\t}\n\t\t\t\tcatch (IOException | RuntimeException ex) {\n\t\t\t\t\tthis.zipContent.close();\n\t\t\t\t\tthis.zipContent = null;\n\t\t\t\t\tthrow ex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void connectData() throws IOException {\n\t\tCloseableDataBlock data = this.zipContent.openRawZipData();\n\t\ttry {\n\t\t\tthis.size = data.size();\n\t\t\tthis.inputStream = data.asInputStream();\n\t\t}\n\t\tcatch (IOException | RuntimeException ex) {\n\t\t\tdata.close();\n\t\t}\n\t}\n\n\tInputStream getInputStream() throws IOException {\n\t\tsynchronized (this) {\n\t\t\tif (this.inputStream == null) {\n\t\t\t\tthrow new IOException(\"Nested location not found \" + this.location);\n\t\t\t}\n\t\t\treturn this.inputStream;\n\t\t}\n\t}\n\n\tlong getContentLength() {\n\t\treturn this.size;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\treleaseAll();\n\t}\n\n\tprivate void releaseAll() {\n\t\tsynchronized (this) {\n\t\t\tif (this.zipContent != null) {\n\t\t\t\tIOException exceptionChain = null;\n\t\t\t\ttry {\n\t\t\t\t\tthis.inputStream.close();\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\texceptionChain = addToExceptionChain(exceptionChain, ex);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tthis.zipContent.close();\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\texceptionChain = addToExceptionChain(exceptionChain, ex);\n\t\t\t\t}\n\t\t\t\tthis.size = -1;\n\t\t\t\tif (exceptionChain != null) {\n\t\t\t\t\tthrow new UncheckedIOException(exceptionChain);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate IOException addToExceptionChain(IOException exceptionChain, IOException ex) {\n\t\tif (exceptionChain != null) {\n\t\t\texceptionChain.addSuppressed(ex);\n\t\t\treturn exceptionChain;\n\t\t}\n\t\treturn ex;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/nested/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Nested URL support.\n *\n * @see org.springframework.boot.loader.net.protocol.nested.NestedLocation\n * @see org.springframework.boot.loader.net.protocol.nested.Handler\n */\npackage org.springframework.boot.loader.net.protocol.nested;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/protocol/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * {@link java.net.URL} protocol support.\n */\npackage org.springframework.boot.loader.net.protocol;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/util/UrlDecoder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.util;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HexFormat;\n\n/**\n * Utility to decode URL strings. Copied from Spring Framework's {@code StringUtils} as we\n * cannot depend on it in the loader.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 3.2.0\n */\npublic final class UrlDecoder {\n\n\tprivate UrlDecoder() {\n\t}\n\n\t/**\n\t * Decode the given encoded URI component value by replacing each \"<i>{@code %xy}</i>\"\n\t * sequence with a hexadecimal representation of the character in\n\t * {@link StandardCharsets#UTF_8 UTF-8}, leaving other characters unmodified.\n\t * @param source the encoded URI component value\n\t * @return the decoded value\n\t */\n\tpublic static String decode(String source) {\n\t\treturn decode(source, StandardCharsets.UTF_8);\n\t}\n\n\t/**\n\t * Decode the given encoded URI component value by replacing each \"<i>{@code %xy}</i>\"\n\t * sequence with a hexadecimal representation of the character in the specified\n\t * character encoding, leaving other characters unmodified.\n\t * @param source the encoded URI component value\n\t * @param charset the character encoding to use to decode the \"<i>{@code %xy}</i>\"\n\t * sequences\n\t * @return the decoded value\n\t * @since 4.0.0\n\t */\n\tpublic static String decode(String source, Charset charset) {\n\t\tint length = source.length();\n\t\tint firstPercentIndex = source.indexOf('%');\n\t\tif (length == 0 || firstPercentIndex < 0) {\n\t\t\treturn source;\n\t\t}\n\n\t\tStringBuilder output = new StringBuilder(length);\n\t\toutput.append(source, 0, firstPercentIndex);\n\t\tbyte[] bytes = null;\n\t\tint i = firstPercentIndex;\n\t\twhile (i < length) {\n\t\t\tchar ch = source.charAt(i);\n\t\t\tif (ch == '%') {\n\t\t\t\ttry {\n\t\t\t\t\tif (bytes == null) {\n\t\t\t\t\t\tbytes = new byte[(length - i) / 3];\n\t\t\t\t\t}\n\n\t\t\t\t\tint pos = 0;\n\t\t\t\t\twhile (i + 2 < length && ch == '%') {\n\t\t\t\t\t\tbytes[pos++] = (byte) HexFormat.fromHexDigits(source, i + 1, i + 3);\n\t\t\t\t\t\ti += 3;\n\t\t\t\t\t\tif (i < length) {\n\t\t\t\t\t\t\tch = source.charAt(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (i < length && ch == '%') {\n\t\t\t\t\t\tthrow new IllegalArgumentException(\"Incomplete trailing escape (%) pattern\");\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.append(new String(bytes, 0, pos, charset));\n\t\t\t\t}\n\t\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"Invalid encoded sequence \\\"\" + source.substring(i) + \"\\\"\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\toutput.append(ch);\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t\treturn output.toString();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/net/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Net utilities.\n */\npackage org.springframework.boot.loader.net.util;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedByteChannel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.channels.NonWritableChannelException;\nimport java.nio.channels.SeekableByteChannel;\nimport java.nio.file.Path;\n\nimport org.springframework.boot.loader.net.protocol.nested.NestedLocation;\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.zip.CloseableDataBlock;\nimport org.springframework.boot.loader.zip.DataBlock;\nimport org.springframework.boot.loader.zip.ZipContent;\n\n/**\n * {@link SeekableByteChannel} implementation for {@link NestedLocation nested} jar files.\n *\n * @author Phillip Webb\n * @see NestedFileSystemProvider\n */\nclass NestedByteChannel implements SeekableByteChannel {\n\n\tprivate long position;\n\n\tprivate final Resources resources;\n\n\tprivate final Cleanable cleanup;\n\n\tprivate final long size;\n\n\tprivate volatile boolean closed;\n\n\tNestedByteChannel(Path path, String nestedEntryName) throws IOException {\n\t\tthis(path, nestedEntryName, Cleaner.instance);\n\t}\n\n\tNestedByteChannel(Path path, String nestedEntryName, Cleaner cleaner) throws IOException {\n\t\tthis.resources = new Resources(path, nestedEntryName);\n\t\tthis.cleanup = cleaner.register(this, this.resources);\n\t\tthis.size = this.resources.getData().size();\n\t}\n\n\t@Override\n\tpublic boolean isOpen() {\n\t\treturn !this.closed;\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = true;\n\t\ttry {\n\t\t\tthis.cleanup.clean();\n\t\t}\n\t\tcatch (UncheckedIOException ex) {\n\t\t\tthrow ex.getCause();\n\t\t}\n\t}\n\n\t@Override\n\tpublic int read(ByteBuffer dst) throws IOException {\n\t\tassertNotClosed();\n\t\tint total = 0;\n\t\twhile (dst.remaining() > 0) {\n\t\t\tint count = this.resources.getData().read(dst, this.position);\n\t\t\tif (count <= 0) {\n\t\t\t\treturn (total != 0) ? 0 : count;\n\t\t\t}\n\t\t\ttotal += count;\n\t\t\tthis.position += count;\n\t\t}\n\t\treturn total;\n\t}\n\n\t@Override\n\tpublic int write(ByteBuffer src) throws IOException {\n\t\tthrow new NonWritableChannelException();\n\t}\n\n\t@Override\n\tpublic long position() throws IOException {\n\t\tassertNotClosed();\n\t\treturn this.position;\n\t}\n\n\t@Override\n\tpublic SeekableByteChannel position(long position) throws IOException {\n\t\tassertNotClosed();\n\t\tif (position < 0 || position >= this.size) {\n\t\t\tthrow new IllegalArgumentException(\"Position must be in bounds\");\n\t\t}\n\t\tthis.position = position;\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic long size() throws IOException {\n\t\tassertNotClosed();\n\t\treturn this.size;\n\t}\n\n\t@Override\n\tpublic SeekableByteChannel truncate(long size) throws IOException {\n\t\tthrow new NonWritableChannelException();\n\t}\n\n\tprivate void assertNotClosed() throws ClosedChannelException {\n\t\tif (this.closed) {\n\t\t\tthrow new ClosedChannelException();\n\t\t}\n\t}\n\n\t/**\n\t * Resources used by the channel and suitable for registration with a {@link Cleaner}.\n\t */\n\tstatic class Resources implements Runnable {\n\n\t\tprivate final ZipContent zipContent;\n\n\t\tprivate final CloseableDataBlock data;\n\n\t\tResources(Path path, String nestedEntryName) throws IOException {\n\t\t\tthis.zipContent = ZipContent.open(path, nestedEntryName);\n\t\t\tthis.data = this.zipContent.openRawZipData();\n\t\t}\n\n\t\tDataBlock getData() {\n\t\t\treturn this.data;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\treleaseAll();\n\t\t}\n\n\t\tprivate void releaseAll() {\n\t\t\tIOException exception = null;\n\t\t\ttry {\n\t\t\t\tthis.data.close();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\texception = ex;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis.zipContent.close();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tif (exception != null) {\n\t\t\t\t\tex.addSuppressed(exception);\n\t\t\t\t}\n\t\t\t\texception = ex;\n\t\t\t}\n\t\t\tif (exception != null) {\n\t\t\t\tthrow new UncheckedIOException(exception);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileStore.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.file.FileStore;\nimport java.nio.file.Files;\nimport java.nio.file.attribute.FileAttributeView;\nimport java.nio.file.attribute.FileStoreAttributeView;\n\nimport org.springframework.boot.loader.net.protocol.nested.NestedLocation;\n\n/**\n * {@link FileStore} implementation for {@link NestedLocation nested} jar files.\n *\n * @author Phillip Webb\n * @see NestedFileSystemProvider\n */\nclass NestedFileStore extends FileStore {\n\n\tprivate final NestedFileSystem fileSystem;\n\n\tNestedFileStore(NestedFileSystem fileSystem) {\n\t\tthis.fileSystem = fileSystem;\n\t}\n\n\t@Override\n\tpublic String name() {\n\t\treturn this.fileSystem.toString();\n\t}\n\n\t@Override\n\tpublic String type() {\n\t\treturn \"nestedfs\";\n\t}\n\n\t@Override\n\tpublic boolean isReadOnly() {\n\t\treturn this.fileSystem.isReadOnly();\n\t}\n\n\t@Override\n\tpublic long getTotalSpace() throws IOException {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic long getUsableSpace() throws IOException {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic long getUnallocatedSpace() throws IOException {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {\n\t\treturn getJarPathFileStore().supportsFileAttributeView(type);\n\t}\n\n\t@Override\n\tpublic boolean supportsFileAttributeView(String name) {\n\t\treturn getJarPathFileStore().supportsFileAttributeView(name);\n\t}\n\n\t@Override\n\tpublic <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {\n\t\treturn getJarPathFileStore().getFileStoreAttributeView(type);\n\t}\n\n\t@Override\n\tpublic Object getAttribute(String attribute) throws IOException {\n\t\ttry {\n\t\t\treturn getJarPathFileStore().getAttribute(attribute);\n\t\t}\n\t\tcatch (UncheckedIOException ex) {\n\t\t\tthrow ex.getCause();\n\t\t}\n\t}\n\n\tprotected FileStore getJarPathFileStore() {\n\t\ttry {\n\t\t\treturn Files.getFileStore(this.fileSystem.getJarPath());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileSystem.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.nio.file.ClosedFileSystemException;\nimport java.nio.file.FileStore;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystemNotFoundException;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Path;\nimport java.nio.file.PathMatcher;\nimport java.nio.file.WatchService;\nimport java.nio.file.attribute.UserPrincipalLookupService;\nimport java.nio.file.spi.FileSystemProvider;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.boot.loader.net.protocol.nested.NestedLocation;\n\n/**\n * {@link FileSystem} implementation for {@link NestedLocation nested} jar files.\n *\n * @author Phillip Webb\n * @see NestedFileSystemProvider\n */\nclass NestedFileSystem extends FileSystem {\n\n\tprivate static final Set<String> SUPPORTED_FILE_ATTRIBUTE_VIEWS = Set.of(\"basic\");\n\n\tprivate static final String FILE_SYSTEMS_CLASS_NAME = FileSystems.class.getName();\n\n\tprivate static final Object EXISTING_FILE_SYSTEM = new Object();\n\n\tprivate final NestedFileSystemProvider provider;\n\n\tprivate final Path jarPath;\n\n\tprivate volatile boolean closed;\n\n\tprivate final Map<String, Object> zipFileSystems = new HashMap<>();\n\n\tNestedFileSystem(NestedFileSystemProvider provider, Path jarPath) {\n\t\tif (provider == null || jarPath == null) {\n\t\t\tthrow new IllegalArgumentException(\"Provider and JarPath must not be null\");\n\t\t}\n\t\tthis.provider = provider;\n\t\tthis.jarPath = jarPath;\n\t}\n\n\tvoid installZipFileSystemIfNecessary(String nestedEntryName) {\n\t\ttry {\n\t\t\tboolean seen;\n\t\t\tsynchronized (this.zipFileSystems) {\n\t\t\t\tseen = this.zipFileSystems.putIfAbsent(nestedEntryName, EXISTING_FILE_SYSTEM) != null;\n\t\t\t}\n\t\t\tif (!seen) {\n\t\t\t\tURI uri = new URI(\"jar:nested:\" + this.jarPath.toUri().getPath() + \"/!\" + nestedEntryName);\n\t\t\t\tif (!hasFileSystem(uri)) {\n\t\t\t\t\tFileSystem zipFileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());\n\t\t\t\t\tsynchronized (this.zipFileSystems) {\n\t\t\t\t\t\tthis.zipFileSystems.put(nestedEntryName, zipFileSystem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate boolean hasFileSystem(URI uri) {\n\t\ttry {\n\t\t\tFileSystems.getFileSystem(uri);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (FileSystemNotFoundException ex) {\n\t\t\treturn isCreatingNewFileSystem();\n\t\t}\n\t}\n\n\tprivate boolean isCreatingNewFileSystem() {\n\t\tStackTraceElement[] stack = Thread.currentThread().getStackTrace();\n\t\tfor (StackTraceElement element : stack) {\n\t\t\tif (FILE_SYSTEMS_CLASS_NAME.equals(element.getClassName())) {\n\t\t\t\treturn \"newFileSystem\".equals(element.getMethodName());\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic FileSystemProvider provider() {\n\t\treturn this.provider;\n\t}\n\n\tPath getJarPath() {\n\t\treturn this.jarPath;\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = true;\n\t\tsynchronized (this.zipFileSystems) {\n\t\t\tthis.zipFileSystems.values()\n\t\t\t\t.stream()\n\t\t\t\t.filter(FileSystem.class::isInstance)\n\t\t\t\t.map(FileSystem.class::cast)\n\t\t\t\t.forEach(this::closeZipFileSystem);\n\t\t}\n\t\tthis.provider.removeFileSystem(this);\n\t}\n\n\tprivate void closeZipFileSystem(FileSystem zipFileSystem) {\n\t\ttry {\n\t\t\tzipFileSystem.close();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isOpen() {\n\t\treturn !this.closed;\n\t}\n\n\t@Override\n\tpublic boolean isReadOnly() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic String getSeparator() {\n\t\treturn \"/!\";\n\t}\n\n\t@Override\n\tpublic Iterable<Path> getRootDirectories() {\n\t\tassertNotClosed();\n\t\treturn Collections.emptySet();\n\t}\n\n\t@Override\n\tpublic Iterable<FileStore> getFileStores() {\n\t\tassertNotClosed();\n\t\treturn Collections.emptySet();\n\t}\n\n\t@Override\n\tpublic Set<String> supportedFileAttributeViews() {\n\t\tassertNotClosed();\n\t\treturn SUPPORTED_FILE_ATTRIBUTE_VIEWS;\n\t}\n\n\t@Override\n\tpublic Path getPath(String first, String... more) {\n\t\tassertNotClosed();\n\t\tif (more.length != 0) {\n\t\t\tthrow new IllegalArgumentException(\"Nested paths must contain a single element\");\n\t\t}\n\t\treturn new NestedPath(this, first);\n\t}\n\n\t@Override\n\tpublic PathMatcher getPathMatcher(String syntaxAndPattern) {\n\t\tthrow new UnsupportedOperationException(\"Nested paths do not support path matchers\");\n\t}\n\n\t@Override\n\tpublic UserPrincipalLookupService getUserPrincipalLookupService() {\n\t\tthrow new UnsupportedOperationException(\"Nested paths do not have a user principal lookup service\");\n\t}\n\n\t@Override\n\tpublic WatchService newWatchService() throws IOException {\n\t\tthrow new UnsupportedOperationException(\"Nested paths do not support the WatchService\");\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tNestedFileSystem other = (NestedFileSystem) obj;\n\t\treturn this.jarPath.equals(other.jarPath);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.jarPath.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.jarPath.toAbsolutePath().toString();\n\t}\n\n\tprivate void assertNotClosed() {\n\t\tif (this.closed) {\n\t\t\tthrow new ClosedFileSystemException();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedFileSystemProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.nio.channels.SeekableByteChannel;\nimport java.nio.file.AccessMode;\nimport java.nio.file.CopyOption;\nimport java.nio.file.DirectoryStream;\nimport java.nio.file.DirectoryStream.Filter;\nimport java.nio.file.FileStore;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystemAlreadyExistsException;\nimport java.nio.file.FileSystemNotFoundException;\nimport java.nio.file.LinkOption;\nimport java.nio.file.NotDirectoryException;\nimport java.nio.file.OpenOption;\nimport java.nio.file.Path;\nimport java.nio.file.ReadOnlyFileSystemException;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.nio.file.attribute.FileAttribute;\nimport java.nio.file.attribute.FileAttributeView;\nimport java.nio.file.spi.FileSystemProvider;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.boot.loader.net.protocol.nested.NestedLocation;\n\n/**\n * {@link FileSystemProvider} implementation for {@link NestedLocation nested} jar files.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic class NestedFileSystemProvider extends FileSystemProvider {\n\n\tprivate final Map<Path, NestedFileSystem> fileSystems = new HashMap<>();\n\n\t@Override\n\tpublic String getScheme() {\n\t\treturn \"nested\";\n\t}\n\n\t@Override\n\tpublic FileSystem newFileSystem(URI uri, Map<String, ?> env) throws IOException {\n\t\tNestedLocation location = NestedLocation.fromUri(uri);\n\t\tPath jarPath = location.path();\n\t\tsynchronized (this.fileSystems) {\n\t\t\tif (this.fileSystems.containsKey(jarPath)) {\n\t\t\t\tthrow new FileSystemAlreadyExistsException();\n\t\t\t}\n\t\t\tNestedFileSystem fileSystem = new NestedFileSystem(this, location.path());\n\t\t\tthis.fileSystems.put(location.path(), fileSystem);\n\t\t\treturn fileSystem;\n\t\t}\n\t}\n\n\t@Override\n\tpublic FileSystem getFileSystem(URI uri) {\n\t\tNestedLocation location = NestedLocation.fromUri(uri);\n\t\tsynchronized (this.fileSystems) {\n\t\t\tNestedFileSystem fileSystem = this.fileSystems.get(location.path());\n\t\t\tif (fileSystem == null) {\n\t\t\t\tthrow new FileSystemNotFoundException();\n\t\t\t}\n\t\t\treturn fileSystem;\n\t\t}\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"resource\")\n\tpublic Path getPath(URI uri) {\n\t\tNestedLocation location = NestedLocation.fromUri(uri);\n\t\tsynchronized (this.fileSystems) {\n\t\t\tNestedFileSystem fileSystem = this.fileSystems.computeIfAbsent(location.path(),\n\t\t\t\t\t(path) -> new NestedFileSystem(this, path));\n\t\t\tfileSystem.installZipFileSystemIfNecessary(location.nestedEntryName());\n\t\t\treturn fileSystem.getPath(location.nestedEntryName());\n\t\t}\n\t}\n\n\tvoid removeFileSystem(NestedFileSystem fileSystem) {\n\t\tsynchronized (this.fileSystems) {\n\t\t\tthis.fileSystems.remove(fileSystem.getJarPath());\n\t\t}\n\t}\n\n\t@Override\n\tpublic SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs)\n\t\t\tthrows IOException {\n\t\tNestedPath nestedPath = NestedPath.cast(path);\n\t\treturn new NestedByteChannel(nestedPath.getJarPath(), nestedPath.getNestedEntryName());\n\t}\n\n\t@Override\n\tpublic DirectoryStream<Path> newDirectoryStream(Path dir, Filter<? super Path> filter) throws IOException {\n\t\tthrow new NotDirectoryException(NestedPath.cast(dir).toString());\n\t}\n\n\t@Override\n\tpublic void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {\n\t\tthrow new ReadOnlyFileSystemException();\n\t}\n\n\t@Override\n\tpublic void delete(Path path) throws IOException {\n\t\tthrow new ReadOnlyFileSystemException();\n\t}\n\n\t@Override\n\tpublic void copy(Path source, Path target, CopyOption... options) throws IOException {\n\t\tthrow new ReadOnlyFileSystemException();\n\t}\n\n\t@Override\n\tpublic void move(Path source, Path target, CopyOption... options) throws IOException {\n\t\tthrow new ReadOnlyFileSystemException();\n\t}\n\n\t@Override\n\tpublic boolean isSameFile(Path path, Path path2) throws IOException {\n\t\treturn path.equals(path2);\n\t}\n\n\t@Override\n\tpublic boolean isHidden(Path path) throws IOException {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic FileStore getFileStore(Path path) throws IOException {\n\t\tNestedPath nestedPath = NestedPath.cast(path);\n\t\tnestedPath.assertExists();\n\t\treturn new NestedFileStore(nestedPath.getFileSystem());\n\t}\n\n\t@Override\n\tpublic void checkAccess(Path path, AccessMode... modes) throws IOException {\n\t\tPath jarPath = getJarPath(path);\n\t\tjarPath.getFileSystem().provider().checkAccess(jarPath, modes);\n\t}\n\n\t@Override\n\tpublic <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) {\n\t\tPath jarPath = getJarPath(path);\n\t\treturn jarPath.getFileSystem().provider().getFileAttributeView(jarPath, type, options);\n\t}\n\n\t@Override\n\tpublic <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options)\n\t\t\tthrows IOException {\n\t\tPath jarPath = getJarPath(path);\n\t\treturn jarPath.getFileSystem().provider().readAttributes(jarPath, type, options);\n\t}\n\n\t@Override\n\tpublic Map<String, Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {\n\t\tPath jarPath = getJarPath(path);\n\t\treturn jarPath.getFileSystem().provider().readAttributes(jarPath, attributes, options);\n\t}\n\n\tprotected Path getJarPath(Path path) {\n\t\treturn NestedPath.cast(path).getJarPath();\n\t}\n\n\t@Override\n\tpublic void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {\n\t\tthrow new ReadOnlyFileSystemException();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/NestedPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.IOError;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.file.Files;\nimport java.nio.file.LinkOption;\nimport java.nio.file.NoSuchFileException;\nimport java.nio.file.Path;\nimport java.nio.file.ProviderMismatchException;\nimport java.nio.file.WatchEvent.Kind;\nimport java.nio.file.WatchEvent.Modifier;\nimport java.nio.file.WatchKey;\nimport java.nio.file.WatchService;\nimport java.util.Objects;\n\nimport org.springframework.boot.loader.net.protocol.nested.NestedLocation;\nimport org.springframework.boot.loader.zip.ZipContent;\n\n/**\n * {@link Path} implementation for {@link NestedLocation nested} jar files.\n *\n * @author Phillip Webb\n * @see NestedFileSystemProvider\n */\nfinal class NestedPath implements Path {\n\n\tprivate final NestedFileSystem fileSystem;\n\n\tprivate final String nestedEntryName;\n\n\tprivate volatile Boolean entryExists;\n\n\tNestedPath(NestedFileSystem fileSystem, String nestedEntryName) {\n\t\tif (fileSystem == null) {\n\t\t\tthrow new IllegalArgumentException(\"'filesSystem' must not be null\");\n\t\t}\n\t\tthis.fileSystem = fileSystem;\n\t\tthis.nestedEntryName = (nestedEntryName != null && !nestedEntryName.isBlank()) ? nestedEntryName : null;\n\t}\n\n\tPath getJarPath() {\n\t\treturn this.fileSystem.getJarPath();\n\t}\n\n\tString getNestedEntryName() {\n\t\treturn this.nestedEntryName;\n\t}\n\n\t@Override\n\tpublic NestedFileSystem getFileSystem() {\n\t\treturn this.fileSystem;\n\t}\n\n\t@Override\n\tpublic boolean isAbsolute() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Path getRoot() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Path getFileName() {\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic Path getParent() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic int getNameCount() {\n\t\treturn 1;\n\t}\n\n\t@Override\n\tpublic Path getName(int index) {\n\t\tif (index != 0) {\n\t\t\tthrow new IllegalArgumentException(\"Nested paths only have a single element\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic Path subpath(int beginIndex, int endIndex) {\n\t\tif (beginIndex != 0 || endIndex != 1) {\n\t\t\tthrow new IllegalArgumentException(\"Nested paths only have a single element\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic boolean startsWith(Path other) {\n\t\treturn equals(other);\n\t}\n\n\t@Override\n\tpublic boolean endsWith(Path other) {\n\t\treturn equals(other);\n\t}\n\n\t@Override\n\tpublic Path normalize() {\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic Path resolve(Path other) {\n\t\tthrow new UnsupportedOperationException(\"Unable to resolve nested path\");\n\t}\n\n\t@Override\n\tpublic Path relativize(Path other) {\n\t\tthrow new UnsupportedOperationException(\"Unable to relativize nested path\");\n\t}\n\n\t@Override\n\tpublic URI toUri() {\n\t\ttry {\n\t\t\tString uri = \"nested:\" + this.fileSystem.getJarPath().toUri().getRawPath();\n\t\t\tif (this.nestedEntryName != null) {\n\t\t\t\turi += \"/!\" + UriPathEncoder.encode(this.nestedEntryName);\n\t\t\t}\n\t\t\treturn new URI(uri);\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IOError(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Path toAbsolutePath() {\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic Path toRealPath(LinkOption... options) throws IOException {\n\t\treturn this;\n\t}\n\n\t@Override\n\tpublic WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException {\n\t\tthrow new UnsupportedOperationException(\"Nested paths cannot be watched\");\n\t}\n\n\t@Override\n\tpublic int compareTo(Path other) {\n\t\tNestedPath otherNestedPath = cast(other);\n\t\treturn this.nestedEntryName.compareTo(otherNestedPath.nestedEntryName);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tNestedPath other = (NestedPath) obj;\n\t\treturn Objects.equals(this.fileSystem, other.fileSystem)\n\t\t\t\t&& Objects.equals(this.nestedEntryName, other.nestedEntryName);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.fileSystem, this.nestedEntryName);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tString string = this.fileSystem.getJarPath().toString();\n\t\tif (this.nestedEntryName != null) {\n\t\t\tstring += this.fileSystem.getSeparator() + this.nestedEntryName;\n\t\t}\n\t\treturn string;\n\t}\n\n\tvoid assertExists() throws NoSuchFileException {\n\t\tif (!Files.isRegularFile(getJarPath())) {\n\t\t\tthrow new NoSuchFileException(toString());\n\t\t}\n\t\tBoolean entryExists = this.entryExists;\n\t\tif (entryExists == null) {\n\t\t\ttry {\n\t\t\t\ttry (ZipContent content = ZipContent.open(getJarPath(), this.nestedEntryName)) {\n\t\t\t\t\tentryExists = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tentryExists = false;\n\t\t\t}\n\t\t\tthis.entryExists = entryExists;\n\t\t}\n\t\tif (!entryExists) {\n\t\t\tthrow new NoSuchFileException(toString());\n\t\t}\n\t}\n\n\tstatic NestedPath cast(Path path) {\n\t\tif (path instanceof NestedPath nestedPath) {\n\t\t\treturn nestedPath;\n\t\t}\n\t\tthrow new ProviderMismatchException();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/UriPathEncoder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.ByteArrayOutputStream;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * URL Path Encoder based.\n *\n * @author Phillip Webb\n */\nfinal class UriPathEncoder {\n\n\t// Based on org.springframework.web.util.UriUtils\n\n\tprivate static final char[] ALLOWED = \"/:@-._~!$&\\'()*+,;=\".toCharArray();\n\n\tprivate UriPathEncoder() {\n\t}\n\n\tstatic String encode(String path) {\n\t\tbyte[] bytes = path.getBytes(StandardCharsets.UTF_8);\n\t\tfor (byte b : bytes) {\n\t\t\tif (!isAllowed(b)) {\n\t\t\t\treturn encode(bytes);\n\t\t\t}\n\t\t}\n\t\treturn path;\n\t}\n\n\tprivate static String encode(byte[] bytes) {\n\t\tByteArrayOutputStream result = new ByteArrayOutputStream(bytes.length);\n\t\tfor (byte b : bytes) {\n\t\t\tif (isAllowed(b)) {\n\t\t\t\tresult.write(b);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.write('%');\n\t\t\t\tresult.write(Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, 16)));\n\t\t\t\tresult.write(Character.toUpperCase(Character.forDigit(b & 0xF, 16)));\n\t\t\t}\n\t\t}\n\t\treturn result.toString(StandardCharsets.UTF_8);\n\t}\n\n\tprivate static boolean isAllowed(int ch) {\n\t\tfor (char allowed : ALLOWED) {\n\t\t\tif (ch == allowed) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn isAlpha(ch) || isDigit(ch);\n\t}\n\n\tprivate static boolean isAlpha(int ch) {\n\t\treturn (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z');\n\t}\n\n\tprivate static boolean isDigit(int ch) {\n\t\treturn (ch >= '0' && ch <= '9');\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/nio/file/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Non-blocking IO {@link java.nio.file.FileSystem} implementation for nested support.\n */\npackage org.springframework.boot.loader.nio.file;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/ref/Cleaner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.ref;\n\nimport java.lang.ref.Cleaner.Cleanable;\n\n/**\n * Wrapper for {@link java.lang.ref.Cleaner} providing registration support.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic interface Cleaner {\n\n\t/**\n\t * Provides access to the default clean instance which delegates to\n\t * {@link java.lang.ref.Cleaner}.\n\t */\n\tCleaner instance = DefaultCleaner.instance;\n\n\t/**\n\t * Registers an object and the clean action to run when the object becomes phantom\n\t * reachable.\n\t * @param obj the object to monitor\n\t * @param action the cleanup action to run\n\t * @return a {@link Cleanable} instance\n\t * @see java.lang.ref.Cleaner#register(Object, Runnable)\n\t */\n\tCleanable register(Object obj, Runnable action);\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/ref/DefaultCleaner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.ref;\n\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.util.function.BiConsumer;\n\n/**\n * Default {@link Cleaner} implementation that delegates to {@link java.lang.ref.Cleaner}.\n *\n * @author Phillip Webb\n */\nclass DefaultCleaner implements Cleaner {\n\n\tstatic final DefaultCleaner instance = new DefaultCleaner();\n\n\tstatic BiConsumer<Object, Cleanable> tracker;\n\n\tprivate final java.lang.ref.Cleaner cleaner = java.lang.ref.Cleaner.create();\n\n\t@Override\n\tpublic Cleanable register(Object obj, Runnable action) {\n\t\tCleanable cleanable = (action != null) ? this.cleaner.register(obj, action) : null;\n\t\tif (tracker != null) {\n\t\t\ttracker.accept(obj, cleanable);\n\t\t}\n\t\treturn cleanable;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/ref/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for {@link java.lang.ref.Cleaner}.\n */\npackage org.springframework.boot.loader.ref;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ByteArrayDataBlock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\n/**\n * {@link DataBlock} backed by a byte array .\n *\n * @author Phillip Webb\n */\nclass ByteArrayDataBlock implements CloseableDataBlock {\n\n\tprivate final byte[] bytes;\n\n\tprivate final int maxReadSize;\n\n\t/**\n\t * Create a new {@link ByteArrayDataBlock} backed by the given bytes.\n\t * @param bytes the bytes to use\n\t */\n\tByteArrayDataBlock(byte... bytes) {\n\t\tthis(bytes, -1);\n\t}\n\n\tByteArrayDataBlock(byte[] bytes, int maxReadSize) {\n\t\tthis.bytes = bytes;\n\t\tthis.maxReadSize = maxReadSize;\n\t}\n\n\t@Override\n\tpublic long size() throws IOException {\n\t\treturn this.bytes.length;\n\t}\n\n\t@Override\n\tpublic int read(ByteBuffer dst, long pos) throws IOException {\n\t\treturn read(dst, (int) pos);\n\t}\n\n\tprivate int read(ByteBuffer dst, int pos) {\n\t\tint remaining = dst.remaining();\n\t\tint length = Math.min(this.bytes.length - pos, remaining);\n\t\tif (this.maxReadSize > 0 && length > this.maxReadSize) {\n\t\t\tlength = this.maxReadSize;\n\t\t}\n\t\tdst.put(this.bytes, pos, length);\n\t\treturn length;\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/CloseableDataBlock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.Closeable;\n\n/**\n * A {@link Closeable} {@link DataBlock}.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic interface CloseableDataBlock extends DataBlock, Closeable {\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/DataBlock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\n\n/**\n * Provides read access to a block of data contained somewhere in a zip file.\n *\n * @author Phillip Webb\n * @since 3.2.0\n */\npublic interface DataBlock {\n\n\t/**\n\t * Return the size of this block.\n\t * @return the block size\n\t * @throws IOException on I/O error\n\t */\n\tlong size() throws IOException;\n\n\t/**\n\t * Read a sequence of bytes from this channel into the given buffer, starting at the\n\t * given block position.\n\t * @param dst the buffer into which bytes are to be transferred\n\t * @param pos the position within the block at which the transfer is to begin\n\t * @return the number of bytes read, possibly zero, or {@code -1} if the given\n\t * position is greater than or equal to the block size\n\t * @throws IOException on I/O error\n\t * @see #readFully(ByteBuffer, long)\n\t * @see FileChannel#read(ByteBuffer, long)\n\t */\n\tint read(ByteBuffer dst, long pos) throws IOException;\n\n\t/**\n\t * Fully read a sequence of bytes from this channel into the given buffer, starting at\n\t * the given block position and filling {@link ByteBuffer#remaining() remaining} bytes\n\t * in the buffer.\n\t * @param dst the buffer into which bytes are to be transferred\n\t * @param pos the position within the block at which the transfer is to begin\n\t * @throws EOFException if an attempt is made to read past the end of the block\n\t * @throws IOException on I/O error\n\t */\n\tdefault void readFully(ByteBuffer dst, long pos) throws IOException {\n\t\tdo {\n\t\t\tint count = read(dst, pos);\n\t\t\tif (count <= 0) {\n\t\t\t\tthrow new EOFException();\n\t\t\t}\n\t\t\tpos += count;\n\t\t}\n\t\twhile (dst.hasRemaining());\n\t}\n\n\t/**\n\t * Return this {@link DataBlock} as an {@link InputStream}.\n\t * @return an {@link InputStream} to read the data block content\n\t * @throws IOException on IO error\n\t */\n\tdefault InputStream asInputStream() throws IOException {\n\t\treturn new DataBlockInputStream(this);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/DataBlockInputStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\n\n/**\n * {@link InputStream} backed by a {@link DataBlock}.\n *\n * @author Phillip Webb\n */\nclass DataBlockInputStream extends InputStream {\n\n\tprivate final DataBlock dataBlock;\n\n\tprivate long pos;\n\n\tprivate long remaining;\n\n\tprivate volatile boolean closed;\n\n\tDataBlockInputStream(DataBlock dataBlock) throws IOException {\n\t\tthis.dataBlock = dataBlock;\n\t\tthis.remaining = dataBlock.size();\n\t}\n\n\t@Override\n\tpublic int read() throws IOException {\n\t\tbyte[] b = new byte[1];\n\t\treturn (read(b, 0, 1) == 1) ? b[0] & 0xFF : -1;\n\t}\n\n\t@Override\n\tpublic int read(byte[] b, int off, int len) throws IOException {\n\t\tensureOpen();\n\t\tByteBuffer dst = ByteBuffer.wrap(b, off, len);\n\t\tint count = this.dataBlock.read(dst, this.pos);\n\t\tif (count > 0) {\n\t\t\tthis.pos += count;\n\t\t\tthis.remaining -= count;\n\t\t}\n\t\treturn count;\n\t}\n\n\t@Override\n\tpublic long skip(long n) throws IOException {\n\t\tlong count = (n > 0) ? maxForwardSkip(n) : maxBackwardSkip(n);\n\t\tthis.pos += count;\n\t\tthis.remaining -= count;\n\t\treturn count;\n\t}\n\n\tprivate long maxForwardSkip(long n) {\n\t\tboolean willCauseOverflow = (this.pos + n) < 0;\n\t\treturn (willCauseOverflow || n > this.remaining) ? this.remaining : n;\n\t}\n\n\tprivate long maxBackwardSkip(long n) {\n\t\treturn Math.max(-this.pos, n);\n\t}\n\n\t@Override\n\tpublic int available() {\n\t\tif (this.closed) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn (this.remaining < Integer.MAX_VALUE) ? (int) this.remaining : Integer.MAX_VALUE;\n\t}\n\n\tprivate void ensureOpen() throws IOException {\n\t\tif (this.closed) {\n\t\t\tthrow new IOException(\"InputStream closed\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tif (this.closed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.closed = true;\n\t\tif (this.dataBlock instanceof Closeable closeable) {\n\t\t\tcloseable.close();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/FileDataBlock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ClosedByInterruptException;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * Reference counted {@link DataBlock} implementation backed by a {@link File} with\n * support for slicing.\n *\n * @author Phillip Webb\n */\nclass FileDataBlock implements CloseableDataBlock {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(FileDataBlock.class);\n\n\tstatic Tracker tracker = Tracker.NONE;\n\n\tprivate final FileAccess fileAccess;\n\n\tprivate final long offset;\n\n\tprivate final long size;\n\n\tFileDataBlock(Path path) throws IOException {\n\t\tthis.fileAccess = new FileAccess(path);\n\t\tthis.offset = 0;\n\t\tthis.size = Files.size(path);\n\t}\n\n\tFileDataBlock(FileAccess fileAccess, long offset, long size) {\n\t\tthis.fileAccess = fileAccess;\n\t\tthis.offset = offset;\n\t\tthis.size = size;\n\t}\n\n\t@Override\n\tpublic long size() throws IOException {\n\t\treturn this.size;\n\t}\n\n\t@Override\n\tpublic int read(ByteBuffer dst, long pos) throws IOException {\n\t\tif (pos < 0) {\n\t\t\tthrow new IllegalArgumentException(\"Position must not be negative\");\n\t\t}\n\t\tensureOpen(ClosedChannelException::new);\n\t\tlong remaining = this.size - pos;\n\t\tif (remaining <= 0) {\n\t\t\treturn -1;\n\t\t}\n\t\tint originalDestinationLimit = -1;\n\t\tif (dst.remaining() > remaining) {\n\t\t\toriginalDestinationLimit = dst.limit();\n\t\t\tlong updatedLimit = dst.position() + remaining;\n\t\t\tdst.limit((updatedLimit > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) updatedLimit);\n\t\t}\n\t\tint result = this.fileAccess.read(dst, this.offset + pos);\n\t\tif (originalDestinationLimit != -1) {\n\t\t\tdst.limit(originalDestinationLimit);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Open a connection to this block, increasing the reference count and re-opening the\n\t * underlying file channel if necessary.\n\t * @throws IOException on I/O error\n\t */\n\tvoid open() throws IOException {\n\t\tthis.fileAccess.open();\n\t}\n\n\t/**\n\t * Close a connection to this block, decreasing the reference count and closing the\n\t * underlying file channel if necessary.\n\t * @throws IOException on I/O error\n\t */\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.fileAccess.close();\n\t}\n\n\t/**\n\t * Ensure that the underlying file channel is currently open.\n\t * @param exceptionSupplier a supplier providing the exception to throw\n\t * @param <E> the exception type\n\t * @throws E if the channel is closed\n\t */\n\t<E extends Exception> void ensureOpen(Supplier<E> exceptionSupplier) throws E {\n\t\tthis.fileAccess.ensureOpen(exceptionSupplier);\n\t}\n\n\t/**\n\t * Return a new {@link FileDataBlock} slice providing access to a subset of the data.\n\t * The caller is responsible for calling {@link #open()} and {@link #close()} on the\n\t * returned block.\n\t * @param offset the start offset for the slice relative to this block\n\t * @return a new {@link FileDataBlock} instance\n\t * @throws IOException on I/O error\n\t */\n\tFileDataBlock slice(long offset) throws IOException {\n\t\treturn slice(offset, this.size - offset);\n\t}\n\n\t/**\n\t * Return a new {@link FileDataBlock} slice providing access to a subset of the data.\n\t * The caller is responsible for calling {@link #open()} and {@link #close()} on the\n\t * returned block.\n\t * @param offset the start offset for the slice relative to this block\n\t * @param size the size of the new slice\n\t * @return a new {@link FileDataBlock} instance\n\t */\n\tFileDataBlock slice(long offset, long size) {\n\t\tif (offset == 0 && size == this.size) {\n\t\t\treturn this;\n\t\t}\n\t\tif (offset < 0) {\n\t\t\tthrow new IllegalArgumentException(\"Offset must not be negative\");\n\t\t}\n\t\tif (size < 0 || offset + size > this.size) {\n\t\t\tthrow new IllegalArgumentException(\"Size must not be negative and must be within bounds\");\n\t\t}\n\t\tdebug.log(\"Slicing %s at %s with size %s\", this.fileAccess, offset, size);\n\t\treturn new FileDataBlock(this.fileAccess, this.offset + offset, size);\n\t}\n\n\t/**\n\t * Manages access to underlying {@link FileChannel}.\n\t */\n\tstatic class FileAccess {\n\n\t\tstatic final int BUFFER_SIZE = 1024 * 10;\n\n\t\tprivate final Path path;\n\n\t\tprivate int referenceCount;\n\n\t\tprivate FileChannel fileChannel;\n\n\t\tprivate boolean fileChannelInterrupted;\n\n\t\tprivate RandomAccessFile randomAccessFile;\n\n\t\tprivate ByteBuffer buffer;\n\n\t\tprivate long bufferPosition = -1;\n\n\t\tprivate int bufferSize;\n\n\t\tprivate final Object lock = new Object();\n\n\t\tFileAccess(Path path) {\n\t\t\tif (!Files.isRegularFile(path)) {\n\t\t\t\tthrow new IllegalArgumentException(path + \" must be a regular file\");\n\t\t\t}\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tint read(ByteBuffer dst, long position) throws IOException {\n\t\t\tsynchronized (this.lock) {\n\t\t\t\tif (position < this.bufferPosition || position >= this.bufferPosition + this.bufferSize) {\n\t\t\t\t\tfillBuffer(position);\n\t\t\t\t}\n\t\t\t\tif (this.bufferSize <= 0) {\n\t\t\t\t\treturn this.bufferSize;\n\t\t\t\t}\n\t\t\t\tint offset = (int) (position - this.bufferPosition);\n\t\t\t\tint length = Math.min(this.bufferSize - offset, dst.remaining());\n\t\t\t\tdst.put(dst.position(), this.buffer, offset, length);\n\t\t\t\tdst.position(dst.position() + length);\n\t\t\t\treturn length;\n\t\t\t}\n\t\t}\n\n\t\tprivate void fillBuffer(long position) throws IOException {\n\t\t\tif (Thread.currentThread().isInterrupted()) {\n\t\t\t\tfillBufferUsingRandomAccessFile(position);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (this.fileChannelInterrupted) {\n\t\t\t\t\trepairFileChannel();\n\t\t\t\t\tthis.fileChannelInterrupted = false;\n\t\t\t\t}\n\t\t\t\tthis.buffer.clear();\n\t\t\t\tthis.bufferSize = this.fileChannel.read(this.buffer, position);\n\t\t\t\tthis.bufferPosition = position;\n\t\t\t}\n\t\t\tcatch (ClosedByInterruptException ex) {\n\t\t\t\tthis.fileChannelInterrupted = true;\n\t\t\t\tfillBufferUsingRandomAccessFile(position);\n\t\t\t}\n\t\t}\n\n\t\tprivate void fillBufferUsingRandomAccessFile(long position) throws IOException {\n\t\t\tif (this.randomAccessFile == null) {\n\t\t\t\tthis.randomAccessFile = new RandomAccessFile(this.path.toFile(), \"r\");\n\t\t\t\ttracker.openedFileChannel(this.path);\n\t\t\t}\n\t\t\tbyte[] bytes = new byte[BUFFER_SIZE];\n\t\t\tthis.randomAccessFile.seek(position);\n\t\t\tint len = this.randomAccessFile.read(bytes);\n\t\t\tthis.buffer.clear();\n\t\t\tif (len > 0) {\n\t\t\t\tthis.buffer.put(bytes, 0, len);\n\t\t\t}\n\t\t\tthis.bufferSize = len;\n\t\t\tthis.bufferPosition = position;\n\t\t}\n\n\t\tprivate void repairFileChannel() throws IOException {\n\t\t\ttracker.closedFileChannel(this.path);\n\t\t\tthis.fileChannel = FileChannel.open(this.path, StandardOpenOption.READ);\n\t\t\ttracker.openedFileChannel(this.path);\n\t\t}\n\n\t\tvoid open() throws IOException {\n\t\t\tsynchronized (this.lock) {\n\t\t\t\tif (this.referenceCount == 0) {\n\t\t\t\t\tdebug.log(\"Opening '%s'\", this.path);\n\t\t\t\t\tthis.fileChannel = FileChannel.open(this.path, StandardOpenOption.READ);\n\t\t\t\t\tthis.buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);\n\t\t\t\t\ttracker.openedFileChannel(this.path);\n\t\t\t\t}\n\t\t\t\tthis.referenceCount++;\n\t\t\t\tdebug.log(\"Reference count for '%s' incremented to %s\", this.path, this.referenceCount);\n\t\t\t}\n\t\t}\n\n\t\tvoid close() throws IOException {\n\t\t\tsynchronized (this.lock) {\n\t\t\t\tif (this.referenceCount == 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.referenceCount--;\n\t\t\t\tif (this.referenceCount == 0) {\n\t\t\t\t\tdebug.log(\"Closing '%s'\", this.path);\n\t\t\t\t\tthis.buffer = null;\n\t\t\t\t\tthis.bufferPosition = -1;\n\t\t\t\t\tthis.bufferSize = 0;\n\t\t\t\t\tthis.fileChannel.close();\n\t\t\t\t\ttracker.closedFileChannel(this.path);\n\t\t\t\t\tthis.fileChannel = null;\n\t\t\t\t\tif (this.randomAccessFile != null) {\n\t\t\t\t\t\tthis.randomAccessFile.close();\n\t\t\t\t\t\ttracker.closedFileChannel(this.path);\n\t\t\t\t\t\tthis.randomAccessFile = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdebug.log(\"Reference count for '%s' decremented to %s\", this.path, this.referenceCount);\n\t\t\t}\n\t\t}\n\n\t\t<E extends Exception> void ensureOpen(Supplier<E> exceptionSupplier) throws E {\n\t\t\tsynchronized (this.lock) {\n\t\t\t\tif (this.referenceCount == 0) {\n\t\t\t\t\tthrow exceptionSupplier.get();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.path.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * Internal tracker used to check open and closing of files in tests.\n\t */\n\tinterface Tracker {\n\n\t\tTracker NONE = new Tracker() {\n\n\t\t\t@Override\n\t\t\tpublic void openedFileChannel(Path path) {\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void closedFileChannel(Path path) {\n\t\t\t}\n\n\t\t};\n\n\t\tvoid openedFileChannel(Path path);\n\n\t\tvoid closedFileChannel(Path path);\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/NameOffsetLookups.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.util.BitSet;\n\n/**\n * Tracks entries that have a name that should be offset by a specific amount. This class\n * is used with nested directory zip files so that entries under the directory are offset\n * correctly. META-INF entries are copied directly and have no offset.\n *\n * @author Phillip Webb\n */\nclass NameOffsetLookups {\n\n\tpublic static final NameOffsetLookups NONE = new NameOffsetLookups(0, 0);\n\n\tprivate final int offset;\n\n\tprivate final BitSet enabled;\n\n\tNameOffsetLookups(int offset, int size) {\n\t\tthis.offset = offset;\n\t\tthis.enabled = (size != 0) ? new BitSet(size) : null;\n\t}\n\n\tvoid swap(int i, int j) {\n\t\tif (this.enabled != null) {\n\t\t\tboolean temp = this.enabled.get(i);\n\t\t\tthis.enabled.set(i, this.enabled.get(j));\n\t\t\tthis.enabled.set(j, temp);\n\t\t}\n\t}\n\n\tint get(int index) {\n\t\treturn isEnabled(index) ? this.offset : 0;\n\t}\n\n\tint enable(int index, boolean enable) {\n\t\tif (this.enabled != null) {\n\t\t\tthis.enabled.set(index, enable);\n\t\t}\n\t\treturn (!enable) ? 0 : this.offset;\n\t}\n\n\tboolean isEnabled(int index) {\n\t\treturn (this.enabled != null && this.enabled.get(index));\n\t}\n\n\tboolean hasAnyEnabled() {\n\t\treturn this.enabled != null && this.enabled.cardinality() > 0;\n\t}\n\n\tNameOffsetLookups emptyCopy() {\n\t\treturn new NameOffsetLookups(this.offset, this.enabled.size());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/VirtualDataBlock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.Collection;\n\n/**\n * A virtual {@link DataBlock} build from a collection of other {@link DataBlock}\n * instances.\n *\n * @author Phillip Webb\n */\nclass VirtualDataBlock implements DataBlock {\n\n\tprivate DataBlock[] parts;\n\n\tprivate long[] offsets;\n\n\tprivate long size;\n\n\tprivate volatile int lastReadPart;\n\n\t/**\n\t * Create a new {@link VirtualDataBlock} instance. The {@link #setParts(Collection)}\n\t * method must be called before the data block can be used.\n\t */\n\tprotected VirtualDataBlock() {\n\t}\n\n\t/**\n\t * Create a new {@link VirtualDataBlock} backed by the given parts.\n\t * @param parts the parts that make up the virtual data block\n\t * @throws IOException in I/O error\n\t */\n\tVirtualDataBlock(Collection<? extends DataBlock> parts) throws IOException {\n\t\tsetParts(parts);\n\t}\n\n\t/**\n\t * Set the parts that make up the virtual data block.\n\t * @param parts the data block parts\n\t * @throws IOException on I/O error\n\t */\n\tprotected void setParts(Collection<? extends DataBlock> parts) throws IOException {\n\t\tthis.parts = parts.toArray(DataBlock[]::new);\n\t\tthis.offsets = new long[parts.size()];\n\t\tlong size = 0;\n\t\tint i = 0;\n\t\tfor (DataBlock part : parts) {\n\t\t\tthis.offsets[i++] = size;\n\t\t\tsize += part.size();\n\t\t}\n\t\tthis.size = size;\n\n\t}\n\n\t@Override\n\tpublic long size() throws IOException {\n\t\treturn this.size;\n\t}\n\n\t@Override\n\tpublic int read(ByteBuffer dst, long pos) throws IOException {\n\t\tif (pos < 0 || pos >= this.size) {\n\t\t\treturn -1;\n\t\t}\n\t\tint lastReadPart = this.lastReadPart;\n\t\tint partIndex = 0;\n\t\tlong offset = 0;\n\t\tint result = 0;\n\t\tif (pos >= this.offsets[lastReadPart]) {\n\t\t\tpartIndex = lastReadPart;\n\t\t\toffset = this.offsets[lastReadPart];\n\t\t}\n\t\twhile (partIndex < this.parts.length) {\n\t\t\tDataBlock part = this.parts[partIndex];\n\t\t\twhile (pos >= offset && pos < offset + part.size()) {\n\t\t\t\tint count = part.read(dst, pos - offset);\n\t\t\t\tresult += Math.max(count, 0);\n\t\t\t\tif (count <= 0 || !dst.hasRemaining()) {\n\t\t\t\t\tthis.lastReadPart = partIndex;\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\tpos += count;\n\t\t\t}\n\t\t\toffset += part.size();\n\t\t\tpartIndex++;\n\t\t}\n\t\treturn result;\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/VirtualZipDataBlock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.file.FileSystem;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * {@link DataBlock} that creates a virtual zip. This class allows us to create virtual\n * zip files that can be parsed by regular JDK classes such as the zip {@link FileSystem}.\n *\n * @author Phillip Webb\n */\nclass VirtualZipDataBlock extends VirtualDataBlock implements CloseableDataBlock {\n\n\tprivate final CloseableDataBlock data;\n\n\t/**\n\t * Create a new {@link VirtualZipDataBlock} for the given entries.\n\t * @param data the source zip data\n\t * @param nameOffsetLookups the name offsets to apply\n\t * @param centralRecords the records that should be copied to the virtual zip\n\t * @param centralRecordPositions the record positions in the data block.\n\t * @throws IOException on I/O error\n\t */\n\tVirtualZipDataBlock(CloseableDataBlock data, NameOffsetLookups nameOffsetLookups,\n\t\t\tZipCentralDirectoryFileHeaderRecord[] centralRecords, long[] centralRecordPositions) throws IOException {\n\t\tthis.data = data;\n\t\tList<DataBlock> parts = new ArrayList<>();\n\t\tList<DataBlock> centralParts = new ArrayList<>();\n\t\tlong offset = 0;\n\t\tlong sizeOfCentralDirectory = 0;\n\t\tfor (int i = 0; i < centralRecords.length; i++) {\n\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = centralRecords[i];\n\t\t\tint nameOffset = nameOffsetLookups.get(i);\n\t\t\tlong centralRecordPos = centralRecordPositions[i];\n\t\t\tDataBlock name = new DataPart(\n\t\t\t\t\tcentralRecordPos + ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET + nameOffset,\n\t\t\t\t\tShort.toUnsignedLong(centralRecord.fileNameLength()) - nameOffset);\n\t\t\tlong localRecordPos = Integer.toUnsignedLong(centralRecord.offsetToLocalHeader());\n\t\t\tZipLocalFileHeaderRecord localRecord = ZipLocalFileHeaderRecord.load(this.data, localRecordPos);\n\t\t\tDataBlock content = new DataPart(localRecordPos + localRecord.size(), centralRecord.compressedSize());\n\t\t\tboolean hasDescriptorRecord = ZipDataDescriptorRecord.isPresentBasedOnFlag(centralRecord);\n\t\t\tZipDataDescriptorRecord dataDescriptorRecord = (!hasDescriptorRecord) ? null\n\t\t\t\t\t: ZipDataDescriptorRecord.load(data, localRecordPos + localRecord.size() + content.size());\n\t\t\tsizeOfCentralDirectory += addToCentral(centralParts, centralRecord, centralRecordPos, name, (int) offset);\n\t\t\toffset += addToLocal(parts, centralRecord, localRecord, dataDescriptorRecord, name, content);\n\t\t}\n\t\tparts.addAll(centralParts);\n\t\tZipEndOfCentralDirectoryRecord eocd = new ZipEndOfCentralDirectoryRecord((short) centralRecords.length,\n\t\t\t\t(int) sizeOfCentralDirectory, (int) offset);\n\t\tparts.add(new ByteArrayDataBlock(eocd.asByteArray()));\n\t\tsetParts(parts);\n\t}\n\n\tprivate long addToCentral(List<DataBlock> parts, ZipCentralDirectoryFileHeaderRecord originalRecord,\n\t\t\tlong originalRecordPos, DataBlock name, int offsetToLocalHeader) throws IOException {\n\t\tZipCentralDirectoryFileHeaderRecord record = originalRecord.withFileNameLength((short) (name.size() & 0xFFFF))\n\t\t\t.withOffsetToLocalHeader(offsetToLocalHeader);\n\t\tint originalExtraFieldLength = Short.toUnsignedInt(originalRecord.extraFieldLength());\n\t\tint originalFileCommentLength = Short.toUnsignedInt(originalRecord.fileCommentLength());\n\t\tint extraFieldAndCommentSize = originalExtraFieldLength + originalFileCommentLength;\n\t\tparts.add(new ByteArrayDataBlock(record.asByteArray()));\n\t\tparts.add(name);\n\t\tif (extraFieldAndCommentSize > 0) {\n\t\t\tparts.add(new DataPart(originalRecordPos + originalRecord.size() - extraFieldAndCommentSize,\n\t\t\t\t\textraFieldAndCommentSize));\n\t\t}\n\t\treturn record.size();\n\t}\n\n\tprivate long addToLocal(List<DataBlock> parts, ZipCentralDirectoryFileHeaderRecord centralRecord,\n\t\t\tZipLocalFileHeaderRecord originalRecord, ZipDataDescriptorRecord dataDescriptorRecord, DataBlock name,\n\t\t\tDataBlock content) throws IOException {\n\t\tZipLocalFileHeaderRecord record = originalRecord.withFileNameLength((short) (name.size() & 0xFFFF));\n\t\tlong originalRecordPos = Integer.toUnsignedLong(centralRecord.offsetToLocalHeader());\n\t\tint extraFieldLength = Short.toUnsignedInt(originalRecord.extraFieldLength());\n\t\tparts.add(new ByteArrayDataBlock(record.asByteArray()));\n\t\tparts.add(name);\n\t\tif (extraFieldLength > 0) {\n\t\t\tparts.add(new DataPart(originalRecordPos + originalRecord.size() - extraFieldLength, extraFieldLength));\n\t\t}\n\t\tparts.add(content);\n\t\tif (dataDescriptorRecord != null) {\n\t\t\tparts.add(new ByteArrayDataBlock(dataDescriptorRecord.asByteArray()));\n\t\t}\n\t\treturn record.size() + content.size() + ((dataDescriptorRecord != null) ? dataDescriptorRecord.size() : 0);\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.data.close();\n\t}\n\n\t/**\n\t * {@link DataBlock} that points to part of the original data block.\n\t */\n\tfinal class DataPart implements DataBlock {\n\n\t\tprivate final long offset;\n\n\t\tprivate final long size;\n\n\t\tDataPart(long offset, long size) {\n\t\t\tthis.offset = offset;\n\t\t\tthis.size = size;\n\t\t}\n\n\t\t@Override\n\t\tpublic long size() throws IOException {\n\t\t\treturn this.size;\n\t\t}\n\n\t\t@Override\n\t\tpublic int read(ByteBuffer dst, long pos) throws IOException {\n\t\t\tint remaining = (int) (this.size - pos);\n\t\t\tif (remaining <= 0) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tint originalLimit = -1;\n\t\t\tif (dst.remaining() > remaining) {\n\t\t\t\toriginalLimit = dst.limit();\n\t\t\t\tdst.limit(dst.position() + remaining);\n\t\t\t}\n\t\t\tint result = VirtualZipDataBlock.this.data.read(dst, this.offset + pos);\n\t\t\tif (originalLimit != -1) {\n\t\t\t\tdst.limit(originalLimit);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/Zip64EndOfCentralDirectoryLocator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * A Zip64 end of central directory locator.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @param pos the position where this record begins in the source {@link DataBlock}\n * @param numberOfThisDisk the number of the disk with the start of the zip64 end of\n * central directory\n * @param offsetToZip64EndOfCentralDirectoryRecord the relative offset of the zip64 end of\n * central directory record\n * @param totalNumberOfDisks the total number of disks\n * @see <a href=\"https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\">Chapter\n * 4.3.15 of the Zip File Format Specification</a>\n */\nrecord Zip64EndOfCentralDirectoryLocator(long pos, int numberOfThisDisk, long offsetToZip64EndOfCentralDirectoryRecord,\n\t\tint totalNumberOfDisks) {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(Zip64EndOfCentralDirectoryLocator.class);\n\n\tprivate static final int SIGNATURE = 0x07064b50;\n\n\t/**\n\t * The size of this record.\n\t */\n\tstatic final int SIZE = 20;\n\n\t/**\n\t * Return the {@link Zip64EndOfCentralDirectoryLocator} or {@code null} if this is not\n\t * a Zip64 file.\n\t * @param dataBlock the source data block\n\t * @param endOfCentralDirectoryPos the {@link ZipEndOfCentralDirectoryRecord} position\n\t * @return a {@link Zip64EndOfCentralDirectoryLocator} instance or null\n\t * @throws IOException on I/O error\n\t */\n\tstatic Zip64EndOfCentralDirectoryLocator find(DataBlock dataBlock, long endOfCentralDirectoryPos)\n\t\t\tthrows IOException {\n\t\tdebug.log(\"Finding Zip64EndOfCentralDirectoryLocator from EOCD at %s\", endOfCentralDirectoryPos);\n\t\tlong pos = endOfCentralDirectoryPos - SIZE;\n\t\tif (pos < 0) {\n\t\t\tdebug.log(\"No Zip64EndOfCentralDirectoryLocator due to negative position %s\", pos);\n\t\t\treturn null;\n\t\t}\n\t\tByteBuffer buffer = ByteBuffer.allocate(SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tdataBlock.read(buffer, pos);\n\t\tbuffer.rewind();\n\t\tint signature = buffer.getInt();\n\t\tif (signature != SIGNATURE) {\n\t\t\tdebug.log(\"Found incorrect Zip64EndOfCentralDirectoryLocator signature %s at position %s\", signature, pos);\n\t\t\treturn null;\n\t\t}\n\t\tdebug.log(\"Found Zip64EndOfCentralDirectoryLocator at position %s\", pos);\n\t\treturn new Zip64EndOfCentralDirectoryLocator(pos, buffer.getInt(), buffer.getLong(), buffer.getInt());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/Zip64EndOfCentralDirectoryRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * A Zip64 end of central directory record.\n *\n * @author Phillip Webb\n * @param size the size of this record\n * @param sizeOfZip64EndOfCentralDirectoryRecord the size of zip64 end of central\n * directory record\n * @param versionMadeBy the version that made the zip\n * @param versionNeededToExtract the version needed to extract the zip\n * @param numberOfThisDisk the number of this disk\n * @param diskWhereCentralDirectoryStarts the disk where central directory starts\n * @param numberOfCentralDirectoryEntriesOnThisDisk the number of central directory\n * entries on this disk\n * @param totalNumberOfCentralDirectoryEntries the total number of central directory\n * entries\n * @param sizeOfCentralDirectory the size of central directory (bytes)\n * @param offsetToStartOfCentralDirectory the offset of start of central directory,\n * relative to start of archive\n * @see <a href=\"https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\">Chapter\n * 4.3.14 of the Zip File Format Specification</a>\n */\nrecord Zip64EndOfCentralDirectoryRecord(long size, long sizeOfZip64EndOfCentralDirectoryRecord, short versionMadeBy,\n\t\tshort versionNeededToExtract, int numberOfThisDisk, int diskWhereCentralDirectoryStarts,\n\t\tlong numberOfCentralDirectoryEntriesOnThisDisk, long totalNumberOfCentralDirectoryEntries,\n\t\tlong sizeOfCentralDirectory, long offsetToStartOfCentralDirectory) {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(Zip64EndOfCentralDirectoryRecord.class);\n\n\tprivate static final int SIGNATURE = 0x06064b50;\n\n\tprivate static final int MINIMUM_SIZE = 56;\n\n\t/**\n\t * Load the {@link Zip64EndOfCentralDirectoryRecord} from the given data block based\n\t * on the offset given in the locator.\n\t * @param dataBlock the source data block\n\t * @param locator the {@link Zip64EndOfCentralDirectoryLocator} or {@code null}\n\t * @return a new {@link ZipCentralDirectoryFileHeaderRecord} instance or {@code null}\n\t * if the locator is {@code null}\n\t * @throws IOException on I/O error\n\t */\n\tstatic Zip64EndOfCentralDirectoryRecord load(DataBlock dataBlock, Zip64EndOfCentralDirectoryLocator locator)\n\t\t\tthrows IOException {\n\t\tif (locator == null) {\n\t\t\treturn null;\n\t\t}\n\t\tByteBuffer buffer = ByteBuffer.allocate(MINIMUM_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tlong size = locator.pos() - locator.offsetToZip64EndOfCentralDirectoryRecord();\n\t\tlong pos = locator.pos() - size;\n\t\tdebug.log(\"Loading Zip64EndOfCentralDirectoryRecord from position %s size %s\", pos, size);\n\t\tdataBlock.readFully(buffer, pos);\n\t\tbuffer.rewind();\n\t\tint signature = buffer.getInt();\n\t\tif (signature != SIGNATURE) {\n\t\t\tdebug.log(\"Found incorrect Zip64EndOfCentralDirectoryRecord signature %s at position %s\", signature, pos);\n\t\t\tthrow new IOException(\"Zip64 'End Of Central Directory Record' not found at position \" + pos\n\t\t\t\t\t+ \". Zip file is corrupt or includes prefixed bytes which are not supported with Zip64 files\");\n\t\t}\n\t\treturn new Zip64EndOfCentralDirectoryRecord(size, buffer.getLong(), buffer.getShort(), buffer.getShort(),\n\t\t\t\tbuffer.getInt(), buffer.getInt(), buffer.getLong(), buffer.getLong(), buffer.getLong(),\n\t\t\t\tbuffer.getLong());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ZipCentralDirectoryFileHeaderRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.temporal.ChronoField;\nimport java.time.temporal.ChronoUnit;\nimport java.time.temporal.ValueRange;\nimport java.util.zip.ZipEntry;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * A ZIP File \"Central directory file header record\" (CDFH).\n *\n * @author Phillip Webb\n * @param versionMadeBy the version that made the zip\n * @param versionNeededToExtract the version needed to extract the zip\n * @param generalPurposeBitFlag the general purpose bit flag\n * @param compressionMethod the compression method used for this entry\n * @param lastModFileTime the last modified file time\n * @param lastModFileDate the last modified file date\n * @param crc32 the CRC32 checksum\n * @param compressedSize the size of the entry when compressed\n * @param uncompressedSize the size of the entry when uncompressed\n * @param fileNameLength the file name length\n * @param extraFieldLength the extra field length\n * @param fileCommentLength the comment length\n * @param diskNumberStart the disk number where the entry starts\n * @param internalFileAttributes the internal file attributes\n * @param externalFileAttributes the external file attributes\n * @param offsetToLocalHeader the relative offset to the local file header\n * @see <a href=\"https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\">Chapter\n * 4.3.12 of the Zip File Format Specification</a>\n */\nrecord ZipCentralDirectoryFileHeaderRecord(short versionMadeBy, short versionNeededToExtract,\n\t\tshort generalPurposeBitFlag, short compressionMethod, short lastModFileTime, short lastModFileDate, int crc32,\n\t\tint compressedSize, int uncompressedSize, short fileNameLength, short extraFieldLength, short fileCommentLength,\n\t\tshort diskNumberStart, short internalFileAttributes, int externalFileAttributes, int offsetToLocalHeader) {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(ZipCentralDirectoryFileHeaderRecord.class);\n\n\tprivate static final int SIGNATURE = 0x02014b50;\n\n\tprivate static final int MINIMUM_SIZE = 46;\n\n\t/**\n\t * The offset of the file name relative to the record start position.\n\t */\n\tstatic final int FILE_NAME_OFFSET = MINIMUM_SIZE;\n\n\t/**\n\t * Return the size of this record.\n\t * @return the record size\n\t */\n\tlong size() {\n\t\treturn MINIMUM_SIZE + fileNameLength() + extraFieldLength() + fileCommentLength();\n\t}\n\n\t/**\n\t * Copy values from this block to the given {@link ZipEntry}.\n\t * @param dataBlock the source data block\n\t * @param pos the position of this {@link ZipCentralDirectoryFileHeaderRecord}\n\t * @param zipEntry the destination zip entry\n\t * @throws IOException on I/O error\n\t */\n\tvoid copyTo(DataBlock dataBlock, long pos, ZipEntry zipEntry) throws IOException {\n\t\tint fileNameLength = Short.toUnsignedInt(fileNameLength());\n\t\tint extraLength = Short.toUnsignedInt(extraFieldLength());\n\t\tint commentLength = Short.toUnsignedInt(fileCommentLength());\n\t\tzipEntry.setMethod(Short.toUnsignedInt(compressionMethod()));\n\t\tzipEntry.setTime(decodeMsDosFormatDateTime(lastModFileDate(), lastModFileTime()));\n\t\tzipEntry.setCrc(Integer.toUnsignedLong(crc32()));\n\t\tzipEntry.setCompressedSize(Integer.toUnsignedLong(compressedSize()));\n\t\tzipEntry.setSize(Integer.toUnsignedLong(uncompressedSize()));\n\t\tif (extraLength > 0) {\n\t\t\tlong extraPos = pos + MINIMUM_SIZE + fileNameLength;\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(extraLength);\n\t\t\tdataBlock.readFully(buffer, extraPos);\n\t\t\tzipEntry.setExtra(buffer.array());\n\t\t}\n\t\tif (commentLength > 0) {\n\t\t\tlong commentPos = pos + MINIMUM_SIZE + fileNameLength + extraLength;\n\t\t\tzipEntry.setComment(ZipString.readString(dataBlock, commentPos, commentLength));\n\t\t}\n\t}\n\n\t/**\n\t * Decode MS-DOS Date Time details. See <a href=\n\t * \"https://docs.microsoft.com/en-gb/windows/desktop/api/winbase/nf-winbase-dosdatetimetofiletime\">\n\t * Microsoft's documentation</a> for more details of the format.\n\t * @param date the date\n\t * @param time the time\n\t * @return the date and time as milliseconds since the epoch\n\t */\n\tprivate long decodeMsDosFormatDateTime(short date, short time) {\n\t\tint year = getChronoValue(((date >> 9) & 0x7f) + 1980, ChronoField.YEAR);\n\t\tint month = getChronoValue((date >> 5) & 0x0f, ChronoField.MONTH_OF_YEAR);\n\t\tint day = getChronoValue(date & 0x1f, ChronoField.DAY_OF_MONTH);\n\t\tint hour = getChronoValue((time >> 11) & 0x1f, ChronoField.HOUR_OF_DAY);\n\t\tint minute = getChronoValue((time >> 5) & 0x3f, ChronoField.MINUTE_OF_HOUR);\n\t\tint second = getChronoValue((time << 1) & 0x3e, ChronoField.SECOND_OF_MINUTE);\n\t\treturn ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.systemDefault())\n\t\t\t.toInstant()\n\t\t\t.truncatedTo(ChronoUnit.SECONDS)\n\t\t\t.toEpochMilli();\n\t}\n\n\tprivate static int getChronoValue(long value, ChronoField field) {\n\t\tValueRange range = field.range();\n\t\treturn Math.toIntExact(Math.min(Math.max(value, range.getMinimum()), range.getMaximum()));\n\t}\n\n\t/**\n\t * Return a new {@link ZipCentralDirectoryFileHeaderRecord} with a new\n\t * {@link #fileNameLength()}.\n\t * @param fileNameLength the new file name length\n\t * @return a new {@link ZipCentralDirectoryFileHeaderRecord} instance\n\t */\n\tZipCentralDirectoryFileHeaderRecord withFileNameLength(short fileNameLength) {\n\t\treturn (this.fileNameLength != fileNameLength) ? new ZipCentralDirectoryFileHeaderRecord(this.versionMadeBy,\n\t\t\t\tthis.versionNeededToExtract, this.generalPurposeBitFlag, this.compressionMethod, this.lastModFileTime,\n\t\t\t\tthis.lastModFileDate, this.crc32, this.compressedSize, this.uncompressedSize, fileNameLength,\n\t\t\t\tthis.extraFieldLength, this.fileCommentLength, this.diskNumberStart, this.internalFileAttributes,\n\t\t\t\tthis.externalFileAttributes, this.offsetToLocalHeader) : this;\n\t}\n\n\t/**\n\t * Return a new {@link ZipCentralDirectoryFileHeaderRecord} with a new\n\t * {@link #offsetToLocalHeader()}.\n\t * @param offsetToLocalHeader the new offset to local header\n\t * @return a new {@link ZipCentralDirectoryFileHeaderRecord} instance\n\t */\n\tZipCentralDirectoryFileHeaderRecord withOffsetToLocalHeader(int offsetToLocalHeader) {\n\t\treturn (this.offsetToLocalHeader != offsetToLocalHeader) ? new ZipCentralDirectoryFileHeaderRecord(\n\t\t\t\tthis.versionMadeBy, this.versionNeededToExtract, this.generalPurposeBitFlag, this.compressionMethod,\n\t\t\t\tthis.lastModFileTime, this.lastModFileDate, this.crc32, this.compressedSize, this.uncompressedSize,\n\t\t\t\tthis.fileNameLength, this.extraFieldLength, this.fileCommentLength, this.diskNumberStart,\n\t\t\t\tthis.internalFileAttributes, this.externalFileAttributes, offsetToLocalHeader) : this;\n\t}\n\n\t/**\n\t * Return the contents of this record as a byte array suitable for writing to a zip.\n\t * @return the record as a byte array\n\t */\n\tbyte[] asByteArray() {\n\t\tByteBuffer buffer = ByteBuffer.allocate(MINIMUM_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tbuffer.putInt(SIGNATURE);\n\t\tbuffer.putShort(this.versionMadeBy);\n\t\tbuffer.putShort(this.versionNeededToExtract);\n\t\tbuffer.putShort(this.generalPurposeBitFlag);\n\t\tbuffer.putShort(this.compressionMethod);\n\t\tbuffer.putShort(this.lastModFileTime);\n\t\tbuffer.putShort(this.lastModFileDate);\n\t\tbuffer.putInt(this.crc32);\n\t\tbuffer.putInt(this.compressedSize);\n\t\tbuffer.putInt(this.uncompressedSize);\n\t\tbuffer.putShort(this.fileNameLength);\n\t\tbuffer.putShort(this.extraFieldLength);\n\t\tbuffer.putShort(this.fileCommentLength);\n\t\tbuffer.putShort(this.diskNumberStart);\n\t\tbuffer.putShort(this.internalFileAttributes);\n\t\tbuffer.putInt(this.externalFileAttributes);\n\t\tbuffer.putInt(this.offsetToLocalHeader);\n\t\treturn buffer.array();\n\t}\n\n\t/**\n\t * Load the {@link ZipCentralDirectoryFileHeaderRecord} from the given data block.\n\t * @param dataBlock the source data block\n\t * @param pos the position of the record\n\t * @return a new {@link ZipCentralDirectoryFileHeaderRecord} instance\n\t * @throws IOException on I/O error\n\t */\n\tstatic ZipCentralDirectoryFileHeaderRecord load(DataBlock dataBlock, long pos) throws IOException {\n\t\tdebug.log(\"Loading CentralDirectoryFileHeaderRecord from position %s\", pos);\n\t\tByteBuffer buffer = ByteBuffer.allocate(MINIMUM_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tdataBlock.readFully(buffer, pos);\n\t\tbuffer.rewind();\n\t\tint signature = buffer.getInt();\n\t\tif (signature != SIGNATURE) {\n\t\t\tdebug.log(\"Found incorrect CentralDirectoryFileHeaderRecord signature %s at position %s\", signature, pos);\n\t\t\tthrow new IOException(\"Zip 'Central Directory File Header Record' not found at position \" + pos);\n\t\t}\n\t\treturn new ZipCentralDirectoryFileHeaderRecord(buffer.getShort(), buffer.getShort(), buffer.getShort(),\n\t\t\t\tbuffer.getShort(), buffer.getShort(), buffer.getShort(), buffer.getInt(), buffer.getInt(),\n\t\t\t\tbuffer.getInt(), buffer.getShort(), buffer.getShort(), buffer.getShort(), buffer.getShort(),\n\t\t\t\tbuffer.getShort(), buffer.getInt(), buffer.getInt());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ZipContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.lang.ref.SoftReference;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\nimport java.util.zip.ZipEntry;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * Provides raw access to content from a regular or nested zip file. This class performs\n * the low level parsing of a zip file and provide access to raw entry data that it\n * contains. Unlike {@link java.util.zip.ZipFile}, this implementation can load content\n * from a zip file nested inside another file as long as the entry is not compressed.\n * <p>\n * In order to reduce memory consumption, this implementation stores only the hash of the\n * entry names, the central directory offsets and the original positions. Entries are\n * stored internally in {@code hashCode} order so that a binary search can be used to\n * quickly find an entry by name or determine if the zip file doesn't have a given entry.\n * <p>\n * {@link ZipContent} for a typical Spring Boot application JAR will have somewhere in the\n * region of 10,500 entries which should consume about 122K.\n * <p>\n * {@link ZipContent} results are cached and it is assumed that zip content will not\n * change once loaded. Entries and Strings are not cached and will be recreated on each\n * access which may produce a lot of garbage.\n * <p>\n * This implementation does not use {@link Cleanable} so care must be taken to release\n * {@link ZipContent} resources. The {@link #close()} method should be called explicitly\n * or by try-with-resources. Care must be take to only call close once.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 3.2.0\n */\npublic final class ZipContent implements Closeable {\n\n\tprivate static final String META_INF = \"META-INF/\";\n\n\tprivate static final byte[] SIGNATURE_SUFFIX = \".DSA\".getBytes(StandardCharsets.UTF_8);\n\n\tprivate static final DebugLogger debug = DebugLogger.get(ZipContent.class);\n\n\tprivate static final Map<Source, ZipContent> cache = new ConcurrentHashMap<>();\n\n\tprivate final Source source;\n\n\tprivate final Kind kind;\n\n\tprivate final FileDataBlock data;\n\n\tprivate final long centralDirectoryPos;\n\n\tprivate final long commentPos;\n\n\tprivate final long commentLength;\n\n\tprivate final int[] lookupIndexes;\n\n\tprivate final int[] nameHashLookups;\n\n\tprivate final int[] relativeCentralDirectoryOffsetLookups;\n\n\tprivate final NameOffsetLookups nameOffsetLookups;\n\n\tprivate final boolean hasJarSignatureFile;\n\n\tprivate SoftReference<CloseableDataBlock> virtualData;\n\n\tprivate SoftReference<Map<Class<?>, Object>> info;\n\n\tprivate ZipContent(Source source, Kind kind, FileDataBlock data, long centralDirectoryPos, long commentPos,\n\t\t\tlong commentLength, int[] lookupIndexes, int[] nameHashLookups, int[] relativeCentralDirectoryOffsetLookups,\n\t\t\tNameOffsetLookups nameOffsetLookups, boolean hasJarSignatureFile) {\n\t\tthis.source = source;\n\t\tthis.kind = kind;\n\t\tthis.data = data;\n\t\tthis.centralDirectoryPos = centralDirectoryPos;\n\t\tthis.commentPos = commentPos;\n\t\tthis.commentLength = commentLength;\n\t\tthis.lookupIndexes = lookupIndexes;\n\t\tthis.nameHashLookups = nameHashLookups;\n\t\tthis.relativeCentralDirectoryOffsetLookups = relativeCentralDirectoryOffsetLookups;\n\t\tthis.nameOffsetLookups = nameOffsetLookups;\n\t\tthis.hasJarSignatureFile = hasJarSignatureFile;\n\t}\n\n\t/**\n\t * Return the kind of content that was loaded.\n\t * @return the content kind\n\t * @since 3.2.2\n\t */\n\tpublic Kind getKind() {\n\t\treturn this.kind;\n\t}\n\n\t/**\n\t * Open a {@link DataBlock} containing the raw zip data. For container zip files, this\n\t * may be smaller than the original file since additional bytes are permitted at the\n\t * front of a zip file. For nested zip files, this will be only the contents of the\n\t * nest zip.\n\t * <p>\n\t * For nested directory zip files, a virtual data block will be created containing\n\t * only the relevant content.\n\t * <p>\n\t * To release resources, the {@link #close()} method of the data block should be\n\t * called explicitly or by try-with-resources.\n\t * <p>\n\t * The returned data block should not be accessed once {@link #close()} has been\n\t * called.\n\t * @return the zip data\n\t * @throws IOException on I/O error\n\t */\n\tpublic CloseableDataBlock openRawZipData() throws IOException {\n\t\tthis.data.open();\n\t\treturn (!this.nameOffsetLookups.hasAnyEnabled()) ? this.data : getVirtualData();\n\t}\n\n\tprivate CloseableDataBlock getVirtualData() throws IOException {\n\t\tCloseableDataBlock virtualData = (this.virtualData != null) ? this.virtualData.get() : null;\n\t\tif (virtualData != null) {\n\t\t\treturn virtualData;\n\t\t}\n\t\tvirtualData = createVirtualData();\n\t\tthis.virtualData = new SoftReference<>(virtualData);\n\t\treturn virtualData;\n\t}\n\n\tprivate CloseableDataBlock createVirtualData() throws IOException {\n\t\tint size = size();\n\t\tNameOffsetLookups nameOffsetLookups = this.nameOffsetLookups.emptyCopy();\n\t\tZipCentralDirectoryFileHeaderRecord[] centralRecords = new ZipCentralDirectoryFileHeaderRecord[size];\n\t\tlong[] centralRecordPositions = new long[size];\n\t\tfor (int i = 0; i < size; i++) {\n\t\t\tint lookupIndex = ZipContent.this.lookupIndexes[i];\n\t\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(lookupIndex);\n\t\t\tnameOffsetLookups.enable(i, this.nameOffsetLookups.isEnabled(lookupIndex));\n\t\t\tcentralRecords[i] = ZipCentralDirectoryFileHeaderRecord.load(this.data, pos);\n\t\t\tcentralRecordPositions[i] = pos;\n\t\t}\n\t\treturn new VirtualZipDataBlock(this.data, nameOffsetLookups, centralRecords, centralRecordPositions);\n\t}\n\n\t/**\n\t * Returns the number of entries in the ZIP file.\n\t * @return the number of entries\n\t */\n\tpublic int size() {\n\t\treturn this.lookupIndexes.length;\n\t}\n\n\t/**\n\t * Return the zip comment, if any.\n\t * @return the comment or {@code null}\n\t */\n\tpublic String getComment() {\n\t\ttry {\n\t\t\treturn ZipString.readString(this.data, this.commentPos, this.commentLength);\n\t\t}\n\t\tcatch (UncheckedIOException ex) {\n\t\t\tif (ex.getCause() instanceof ClosedChannelException) {\n\t\t\t\tthrow new IllegalStateException(\"Zip content closed\", ex);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t/**\n\t * Return the entry with the given name, if any.\n\t * @param name the name of the entry to find\n\t * @return the entry or {@code null}\n\t */\n\tpublic Entry getEntry(CharSequence name) {\n\t\treturn getEntry(null, name);\n\t}\n\n\t/**\n\t * Return the entry with the given name, if any.\n\t * @param namePrefix an optional prefix for the name\n\t * @param name the name of the entry to find\n\t * @return the entry or {@code null}\n\t */\n\tpublic Entry getEntry(CharSequence namePrefix, CharSequence name) {\n\t\tint nameHash = nameHash(namePrefix, name);\n\t\tint lookupIndex = getFirstLookupIndex(nameHash);\n\t\tint size = size();\n\t\twhile (lookupIndex >= 0 && lookupIndex < size && this.nameHashLookups[lookupIndex] == nameHash) {\n\t\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(lookupIndex);\n\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = loadZipCentralDirectoryFileHeaderRecord(pos);\n\t\t\tif (hasName(lookupIndex, centralRecord, pos, namePrefix, name)) {\n\t\t\t\treturn new Entry(lookupIndex, centralRecord);\n\t\t\t}\n\t\t\tlookupIndex++;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return if an entry with the given name exists.\n\t * @param namePrefix an optional prefix for the name\n\t * @param name the name of the entry to find\n\t * @return the entry or {@code null}\n\t */\n\tpublic boolean hasEntry(CharSequence namePrefix, CharSequence name) {\n\t\tint nameHash = nameHash(namePrefix, name);\n\t\tint lookupIndex = getFirstLookupIndex(nameHash);\n\t\tint size = size();\n\t\twhile (lookupIndex >= 0 && lookupIndex < size && this.nameHashLookups[lookupIndex] == nameHash) {\n\t\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(lookupIndex);\n\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = loadZipCentralDirectoryFileHeaderRecord(pos);\n\t\t\tif (hasName(lookupIndex, centralRecord, pos, namePrefix, name)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tlookupIndex++;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Return the entry at the specified index.\n\t * @param index the entry index\n\t * @return the entry\n\t * @throws IndexOutOfBoundsException if the index is out of bounds\n\t */\n\tpublic Entry getEntry(int index) {\n\t\tint lookupIndex = ZipContent.this.lookupIndexes[index];\n\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(lookupIndex);\n\t\tZipCentralDirectoryFileHeaderRecord centralRecord = loadZipCentralDirectoryFileHeaderRecord(pos);\n\t\treturn new Entry(lookupIndex, centralRecord);\n\t}\n\n\tprivate ZipCentralDirectoryFileHeaderRecord loadZipCentralDirectoryFileHeaderRecord(long pos) {\n\t\ttry {\n\t\t\treturn ZipCentralDirectoryFileHeaderRecord.load(this.data, pos);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tif (ex instanceof ClosedChannelException) {\n\t\t\t\tthrow new IllegalStateException(\"Zip content closed\", ex);\n\t\t\t}\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate int nameHash(CharSequence namePrefix, CharSequence name) {\n\t\tint nameHash = 0;\n\t\tnameHash = (namePrefix != null) ? ZipString.hash(nameHash, namePrefix, false) : nameHash;\n\t\tnameHash = ZipString.hash(nameHash, name, true);\n\t\treturn nameHash;\n\t}\n\n\tprivate int getFirstLookupIndex(int nameHash) {\n\t\tint lookupIndex = Arrays.binarySearch(this.nameHashLookups, 0, this.nameHashLookups.length, nameHash);\n\t\tif (lookupIndex < 0) {\n\t\t\treturn -1;\n\t\t}\n\t\twhile (lookupIndex > 0 && this.nameHashLookups[lookupIndex - 1] == nameHash) {\n\t\t\tlookupIndex--;\n\t\t}\n\t\treturn lookupIndex;\n\t}\n\n\tprivate long getCentralDirectoryFileHeaderRecordPos(int lookupIndex) {\n\t\treturn this.centralDirectoryPos + this.relativeCentralDirectoryOffsetLookups[lookupIndex];\n\t}\n\n\tprivate boolean hasName(int lookupIndex, ZipCentralDirectoryFileHeaderRecord centralRecord, long pos,\n\t\t\tCharSequence namePrefix, CharSequence name) {\n\t\tint offset = this.nameOffsetLookups.get(lookupIndex);\n\t\tpos += ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET + offset;\n\t\tint len = centralRecord.fileNameLength() - offset;\n\t\tByteBuffer buffer = ByteBuffer.allocate(ZipString.BUFFER_SIZE);\n\t\tif (namePrefix != null) {\n\t\t\tint startsWithNamePrefix = ZipString.startsWith(buffer, this.data, pos, len, namePrefix);\n\t\t\tif (startsWithNamePrefix == -1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tpos += startsWithNamePrefix;\n\t\t\tlen -= startsWithNamePrefix;\n\t\t}\n\t\treturn ZipString.matches(buffer, this.data, pos, len, name, true);\n\t}\n\n\t/**\n\t * Get or compute information based on the {@link ZipContent}.\n\t * @param <I> the info type to get or compute\n\t * @param type the info type to get or compute\n\t * @param function the function used to compute the information\n\t * @return the computed or existing information\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <I> I getInfo(Class<I> type, Function<ZipContent, I> function) {\n\t\tMap<Class<?>, Object> info = (this.info != null) ? this.info.get() : null;\n\t\tif (info == null) {\n\t\t\tinfo = new ConcurrentHashMap<>();\n\t\t\tthis.info = new SoftReference<>(info);\n\t\t}\n\t\treturn (I) info.computeIfAbsent(type, (key) -> {\n\t\t\tdebug.log(\"Getting %s info from zip '%s'\", type.getName(), this);\n\t\t\treturn function.apply(this);\n\t\t});\n\t}\n\n\t/**\n\t * Returns {@code true} if this zip contains a jar signature file\n\t * ({@code META-INF/*.DSA}).\n\t * @return if the zip contains a jar signature file\n\t */\n\tpublic boolean hasJarSignatureFile() {\n\t\treturn this.hasJarSignatureFile;\n\t}\n\n\t/**\n\t * Close this jar file, releasing the underlying file if this was the last reference.\n\t * @see java.io.Closeable#close()\n\t */\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.data.close();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.source.toString();\n\t}\n\n\t/**\n\t * Open {@link ZipContent} from the specified path. The resulting {@link ZipContent}\n\t * <em>must</em> be {@link #close() closed} by the caller.\n\t * @param path the zip path\n\t * @return a {@link ZipContent} instance\n\t * @throws IOException on I/O error\n\t */\n\tpublic static ZipContent open(Path path) throws IOException {\n\t\treturn open(new Source(path.toAbsolutePath(), null));\n\t}\n\n\t/**\n\t * Open nested {@link ZipContent} from the specified path. The resulting\n\t * {@link ZipContent} <em>must</em> be {@link #close() closed} by the caller.\n\t * @param path the zip path\n\t * @param nestedEntryName the nested entry name to open\n\t * @return a {@link ZipContent} instance\n\t * @throws IOException on I/O error\n\t */\n\tpublic static ZipContent open(Path path, String nestedEntryName) throws IOException {\n\t\treturn open(new Source(path.toAbsolutePath(), nestedEntryName));\n\t}\n\n\tprivate static ZipContent open(Source source) throws IOException {\n\t\tZipContent zipContent = cache.get(source);\n\t\tif (zipContent != null) {\n\t\t\tdebug.log(\"Opening existing cached zip content for %s\", zipContent);\n\t\t\tzipContent.data.open();\n\t\t\treturn zipContent;\n\t\t}\n\t\tdebug.log(\"Loading zip content from %s\", source);\n\t\tzipContent = Loader.load(source);\n\t\tZipContent previouslyCached = cache.putIfAbsent(source, zipContent);\n\t\tif (previouslyCached != null) {\n\t\t\tdebug.log(\"Closing zip content from %s since cache was populated from another thread\", source);\n\t\t\tzipContent.close();\n\t\t\tpreviouslyCached.data.open();\n\t\t\treturn previouslyCached;\n\t\t}\n\t\treturn zipContent;\n\t}\n\n\t/**\n\t * Zip content kinds.\n\t *\n\t * @since 3.2.2\n\t */\n\tpublic enum Kind {\n\n\t\t/**\n\t\t * Content from a standard zip file.\n\t\t */\n\t\tZIP,\n\n\t\t/**\n\t\t * Content from nested zip content.\n\t\t */\n\t\tNESTED_ZIP,\n\n\t\t/**\n\t\t * Content from a nested zip directory.\n\t\t */\n\t\tNESTED_DIRECTORY\n\n\t}\n\n\t/**\n\t * The source of {@link ZipContent}. Used as a cache key.\n\t *\n\t * @param path the path of the zip or container zip\n\t * @param nestedEntryName the name of the nested entry to use or {@code null}\n\t */\n\tprivate record Source(Path path, String nestedEntryName) {\n\n\t\t/**\n\t\t * Return if this is the source of a nested zip.\n\t\t * @return if this is for a nested zip\n\t\t */\n\t\tboolean isNested() {\n\t\t\treturn this.nestedEntryName != null;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn (!isNested()) ? path().toString() : path() + \"[\" + nestedEntryName() + \"]\";\n\t\t}\n\n\t}\n\n\t/**\n\t * Internal class used to load the zip content create a new {@link ZipContent}\n\t * instance.\n\t */\n\tprivate static final class Loader {\n\n\t\tprivate final ByteBuffer buffer = ByteBuffer.allocate(ZipString.BUFFER_SIZE);\n\n\t\tprivate final Source source;\n\n\t\tprivate final FileDataBlock data;\n\n\t\tprivate final long centralDirectoryPos;\n\n\t\tprivate final int[] index;\n\n\t\tprivate int[] nameHashLookups;\n\n\t\tprivate int[] relativeCentralDirectoryOffsetLookups;\n\n\t\tprivate final NameOffsetLookups nameOffsetLookups;\n\n\t\tprivate int cursor;\n\n\t\tprivate Loader(Source source, Entry directoryEntry, FileDataBlock data, long centralDirectoryPos, int maxSize) {\n\t\t\tthis.source = source;\n\t\t\tthis.data = data;\n\t\t\tthis.centralDirectoryPos = centralDirectoryPos;\n\t\t\tthis.index = new int[maxSize];\n\t\t\tthis.nameHashLookups = new int[maxSize];\n\t\t\tthis.relativeCentralDirectoryOffsetLookups = new int[maxSize];\n\t\t\tthis.nameOffsetLookups = (directoryEntry != null)\n\t\t\t\t\t? new NameOffsetLookups(directoryEntry.getName().length(), maxSize) : NameOffsetLookups.NONE;\n\t\t}\n\n\t\tprivate void add(ZipCentralDirectoryFileHeaderRecord centralRecord, long pos, boolean enableNameOffset)\n\t\t\t\tthrows IOException {\n\t\t\tint nameOffset = this.nameOffsetLookups.enable(this.cursor, enableNameOffset);\n\t\t\tint hash = ZipString.hash(this.buffer, this.data,\n\t\t\t\t\tpos + ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET + nameOffset,\n\t\t\t\t\tcentralRecord.fileNameLength() - nameOffset, true);\n\t\t\tthis.nameHashLookups[this.cursor] = hash;\n\t\t\tthis.relativeCentralDirectoryOffsetLookups[this.cursor] = (int) ((pos - this.centralDirectoryPos));\n\t\t\tthis.index[this.cursor] = this.cursor;\n\t\t\tthis.cursor++;\n\t\t}\n\n\t\tprivate ZipContent finish(Kind kind, long commentPos, long commentLength, boolean hasJarSignatureFile) {\n\t\t\tif (this.cursor != this.nameHashLookups.length) {\n\t\t\t\tthis.nameHashLookups = Arrays.copyOf(this.nameHashLookups, this.cursor);\n\t\t\t\tthis.relativeCentralDirectoryOffsetLookups = Arrays.copyOf(this.relativeCentralDirectoryOffsetLookups,\n\t\t\t\t\t\tthis.cursor);\n\t\t\t}\n\t\t\tint size = this.nameHashLookups.length;\n\t\t\tsort(0, size - 1);\n\t\t\tint[] lookupIndexes = new int[size];\n\t\t\tfor (int i = 0; i < size; i++) {\n\t\t\t\tlookupIndexes[this.index[i]] = i;\n\t\t\t}\n\t\t\treturn new ZipContent(this.source, kind, this.data, this.centralDirectoryPos, commentPos, commentLength,\n\t\t\t\t\tlookupIndexes, this.nameHashLookups, this.relativeCentralDirectoryOffsetLookups,\n\t\t\t\t\tthis.nameOffsetLookups, hasJarSignatureFile);\n\t\t}\n\n\t\tprivate void sort(int left, int right) {\n\t\t\t// Quick sort algorithm, uses nameHashCode as the source but sorts all arrays\n\t\t\tif (left < right) {\n\t\t\t\tint pivot = this.nameHashLookups[left + (right - left) / 2];\n\t\t\t\tint i = left;\n\t\t\t\tint j = right;\n\t\t\t\twhile (i <= j) {\n\t\t\t\t\twhile (this.nameHashLookups[i] < pivot) {\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t\twhile (this.nameHashLookups[j] > pivot) {\n\t\t\t\t\t\tj--;\n\t\t\t\t\t}\n\t\t\t\t\tif (i <= j) {\n\t\t\t\t\t\tswap(i, j);\n\t\t\t\t\t\ti++;\n\t\t\t\t\t\tj--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (left < j) {\n\t\t\t\t\tsort(left, j);\n\t\t\t\t}\n\t\t\t\tif (right > i) {\n\t\t\t\t\tsort(i, right);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void swap(int i, int j) {\n\t\t\tswap(this.index, i, j);\n\t\t\tswap(this.nameHashLookups, i, j);\n\t\t\tswap(this.relativeCentralDirectoryOffsetLookups, i, j);\n\t\t\tthis.nameOffsetLookups.swap(i, j);\n\t\t}\n\n\t\tprivate static void swap(int[] array, int i, int j) {\n\t\t\tint temp = array[i];\n\t\t\tarray[i] = array[j];\n\t\t\tarray[j] = temp;\n\t\t}\n\n\t\tstatic ZipContent load(Source source) throws IOException {\n\t\t\tif (!source.isNested()) {\n\t\t\t\treturn loadNonNested(source);\n\t\t\t}\n\t\t\ttry (ZipContent zip = open(source.path())) {\n\t\t\t\tEntry entry = zip.getEntry(source.nestedEntryName());\n\t\t\t\tif (entry == null) {\n\t\t\t\t\tthrow new IOException(\"Nested entry '%s' not found in container zip '%s'\"\n\t\t\t\t\t\t.formatted(source.nestedEntryName(), source.path()));\n\t\t\t\t}\n\t\t\t\treturn (!entry.isDirectory()) ? loadNestedZip(source, entry) : loadNestedDirectory(source, zip, entry);\n\t\t\t}\n\t\t}\n\n\t\tprivate static ZipContent loadNonNested(Source source) throws IOException {\n\t\t\tdebug.log(\"Loading non-nested zip '%s'\", source.path());\n\t\t\treturn openAndLoad(source, Kind.ZIP, new FileDataBlock(source.path()));\n\t\t}\n\n\t\tprivate static ZipContent loadNestedZip(Source source, Entry entry) throws IOException {\n\t\t\tif (entry.centralRecord.compressionMethod() != ZipEntry.STORED) {\n\t\t\t\tthrow new IOException(\"Nested entry '%s' in container zip '%s' must not be compressed\"\n\t\t\t\t\t.formatted(source.nestedEntryName(), source.path()));\n\t\t\t}\n\t\t\tdebug.log(\"Loading nested zip entry '%s' from '%s'\", source.nestedEntryName(), source.path());\n\t\t\treturn openAndLoad(source, Kind.NESTED_ZIP, entry.getContent());\n\t\t}\n\n\t\tprivate static ZipContent openAndLoad(Source source, Kind kind, FileDataBlock data) throws IOException {\n\t\t\ttry {\n\t\t\t\tdata.open();\n\t\t\t\treturn loadContent(source, kind, data);\n\t\t\t}\n\t\t\tcatch (IOException | RuntimeException ex) {\n\t\t\t\tdata.close();\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate static ZipContent loadContent(Source source, Kind kind, FileDataBlock data) throws IOException {\n\t\t\tZipEndOfCentralDirectoryRecord.Located locatedEocd = ZipEndOfCentralDirectoryRecord.load(data);\n\t\t\tZipEndOfCentralDirectoryRecord eocd = locatedEocd.endOfCentralDirectoryRecord();\n\t\t\tlong eocdPos = locatedEocd.pos();\n\t\t\tZip64EndOfCentralDirectoryLocator zip64Locator = Zip64EndOfCentralDirectoryLocator.find(data, eocdPos);\n\t\t\tZip64EndOfCentralDirectoryRecord zip64Eocd = Zip64EndOfCentralDirectoryRecord.load(data, zip64Locator);\n\t\t\tdata = data.slice(getStartOfZipContent(data, eocd, zip64Eocd));\n\t\t\tlong centralDirectoryPos = (zip64Eocd != null) ? zip64Eocd.offsetToStartOfCentralDirectory()\n\t\t\t\t\t: Integer.toUnsignedLong(eocd.offsetToStartOfCentralDirectory());\n\t\t\tlong numberOfEntries = (zip64Eocd != null) ? zip64Eocd.totalNumberOfCentralDirectoryEntries()\n\t\t\t\t\t: Short.toUnsignedInt(eocd.totalNumberOfCentralDirectoryEntries());\n\t\t\tif (numberOfEntries < 0) {\n\t\t\t\tthrow new IllegalStateException(\"Invalid number of zip entries in \" + source);\n\t\t\t}\n\t\t\tif (numberOfEntries > Integer.MAX_VALUE) {\n\t\t\t\tthrow new IllegalStateException(\"Too many zip entries in \" + source);\n\t\t\t}\n\t\t\tLoader loader = new Loader(source, null, data, centralDirectoryPos, (int) numberOfEntries);\n\t\t\tByteBuffer signatureNameSuffixBuffer = ByteBuffer.allocate(SIGNATURE_SUFFIX.length);\n\t\t\tboolean hasJarSignatureFile = false;\n\t\t\tlong pos = centralDirectoryPos;\n\t\t\tfor (int i = 0; i < numberOfEntries; i++) {\n\t\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = ZipCentralDirectoryFileHeaderRecord.load(data, pos);\n\t\t\t\tif (!hasJarSignatureFile) {\n\t\t\t\t\tlong filenamePos = pos + ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET;\n\t\t\t\t\tif (centralRecord.fileNameLength() > SIGNATURE_SUFFIX.length && ZipString.startsWith(loader.buffer,\n\t\t\t\t\t\t\tdata, filenamePos, centralRecord.fileNameLength(), META_INF) >= 0) {\n\t\t\t\t\t\tsignatureNameSuffixBuffer.clear();\n\t\t\t\t\t\tdata.readFully(signatureNameSuffixBuffer,\n\t\t\t\t\t\t\t\tfilenamePos + centralRecord.fileNameLength() - SIGNATURE_SUFFIX.length);\n\t\t\t\t\t\thasJarSignatureFile = Arrays.equals(SIGNATURE_SUFFIX, signatureNameSuffixBuffer.array());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tloader.add(centralRecord, pos, false);\n\t\t\t\tpos += centralRecord.size();\n\t\t\t}\n\t\t\tlong commentPos = locatedEocd.pos() + ZipEndOfCentralDirectoryRecord.COMMENT_OFFSET;\n\t\t\treturn loader.finish(kind, commentPos, eocd.commentLength(), hasJarSignatureFile);\n\t\t}\n\n\t\t/**\n\t\t * Returns the location in the data that the archive actually starts. For most\n\t\t * files the archive data will start at 0, however, it is possible to have\n\t\t * prefixed bytes (often used for startup scripts) at the beginning of the data.\n\t\t * @param data the source data\n\t\t * @param eocd the end of central directory record\n\t\t * @param zip64Eocd the zip64 end of central directory record or {@code null}\n\t\t * @return the offset within the data where the archive begins\n\t\t * @throws IOException on I/O error\n\t\t */\n\t\tprivate static long getStartOfZipContent(FileDataBlock data, ZipEndOfCentralDirectoryRecord eocd,\n\t\t\t\tZip64EndOfCentralDirectoryRecord zip64Eocd) throws IOException {\n\t\t\tlong specifiedOffsetToStartOfCentralDirectory = (zip64Eocd != null)\n\t\t\t\t\t? zip64Eocd.offsetToStartOfCentralDirectory()\n\t\t\t\t\t: Integer.toUnsignedLong(eocd.offsetToStartOfCentralDirectory());\n\t\t\tlong sizeOfCentralDirectoryAndEndRecords = getSizeOfCentralDirectoryAndEndRecords(eocd, zip64Eocd);\n\t\t\tlong actualOffsetToStartOfCentralDirectory = data.size() - sizeOfCentralDirectoryAndEndRecords;\n\t\t\treturn actualOffsetToStartOfCentralDirectory - specifiedOffsetToStartOfCentralDirectory;\n\t\t}\n\n\t\tprivate static long getSizeOfCentralDirectoryAndEndRecords(ZipEndOfCentralDirectoryRecord eocd,\n\t\t\t\tZip64EndOfCentralDirectoryRecord zip64Eocd) {\n\t\t\tlong result = 0;\n\t\t\tresult += eocd.size();\n\t\t\tif (zip64Eocd != null) {\n\t\t\t\tresult += Zip64EndOfCentralDirectoryLocator.SIZE;\n\t\t\t\tresult += zip64Eocd.size();\n\t\t\t}\n\t\t\tresult += (zip64Eocd != null) ? zip64Eocd.sizeOfCentralDirectory()\n\t\t\t\t\t: Integer.toUnsignedLong(eocd.sizeOfCentralDirectory());\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate static ZipContent loadNestedDirectory(Source source, ZipContent zip, Entry directoryEntry)\n\t\t\t\tthrows IOException {\n\t\t\tdebug.log(\"Loading nested directory entry '%s' from '%s'\", source.nestedEntryName(), source.path());\n\t\t\tif (!source.nestedEntryName().endsWith(\"/\")) {\n\t\t\t\tthrow new IllegalArgumentException(\"Nested entry name must end with '/'\");\n\t\t\t}\n\t\t\tString directoryName = directoryEntry.getName();\n\t\t\tzip.data.open();\n\t\t\ttry {\n\t\t\t\tLoader loader = new Loader(source, directoryEntry, zip.data, zip.centralDirectoryPos, zip.size());\n\t\t\t\tfor (int cursor = 0; cursor < zip.size(); cursor++) {\n\t\t\t\t\tint index = zip.lookupIndexes[cursor];\n\t\t\t\t\tif (index != directoryEntry.getLookupIndex()) {\n\t\t\t\t\t\tlong pos = zip.getCentralDirectoryFileHeaderRecordPos(index);\n\t\t\t\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = ZipCentralDirectoryFileHeaderRecord\n\t\t\t\t\t\t\t.load(zip.data, pos);\n\t\t\t\t\t\tlong namePos = pos + ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET;\n\t\t\t\t\t\tshort nameLen = centralRecord.fileNameLength();\n\t\t\t\t\t\tif (ZipString.startsWith(loader.buffer, zip.data, namePos, nameLen, directoryName) != -1) {\n\t\t\t\t\t\t\tloader.add(centralRecord, pos, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn loader.finish(Kind.NESTED_DIRECTORY, zip.commentPos, zip.commentLength, zip.hasJarSignatureFile);\n\t\t\t}\n\t\t\tcatch (IOException | RuntimeException ex) {\n\t\t\t\tzip.data.close();\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * A single zip content entry.\n\t */\n\tpublic class Entry {\n\n\t\tprivate final int lookupIndex;\n\n\t\tprivate final ZipCentralDirectoryFileHeaderRecord centralRecord;\n\n\t\tprivate volatile String name;\n\n\t\tprivate volatile FileDataBlock content;\n\n\t\t/**\n\t\t * Create a new {@link Entry} instance.\n\t\t * @param lookupIndex the lookup index of the entry\n\t\t * @param centralRecord the {@link ZipCentralDirectoryFileHeaderRecord} for the\n\t\t * entry\n\t\t */\n\t\tEntry(int lookupIndex, ZipCentralDirectoryFileHeaderRecord centralRecord) {\n\t\t\tthis.lookupIndex = lookupIndex;\n\t\t\tthis.centralRecord = centralRecord;\n\t\t}\n\n\t\t/**\n\t\t * Return the lookup index of the entry. Each entry has a unique lookup index but\n\t\t * they aren't the same as the order that the entry was loaded.\n\t\t * @return the entry lookup index\n\t\t */\n\t\tpublic int getLookupIndex() {\n\t\t\treturn this.lookupIndex;\n\t\t}\n\n\t\t/**\n\t\t * Return {@code true} if this is a directory entry.\n\t\t * @return if the entry is a directory\n\t\t */\n\t\tpublic boolean isDirectory() {\n\t\t\treturn getName().endsWith(\"/\");\n\t\t}\n\n\t\t/**\n\t\t * Returns {@code true} if this entry has a name starting with the given prefix.\n\t\t * @param prefix the required prefix\n\t\t * @return if the entry name starts with the prefix\n\t\t */\n\t\tpublic boolean hasNameStartingWith(CharSequence prefix) {\n\t\t\tString name = this.name;\n\t\t\tif (name != null) {\n\t\t\t\treturn name.startsWith(prefix.toString());\n\t\t\t}\n\t\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(this.lookupIndex)\n\t\t\t\t\t+ ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET;\n\t\t\treturn ZipString.startsWith(null, ZipContent.this.data, pos, this.centralRecord.fileNameLength(),\n\t\t\t\t\tprefix) != -1;\n\t\t}\n\n\t\t/**\n\t\t * Return the name of this entry.\n\t\t * @return the entry name\n\t\t */\n\t\tpublic String getName() {\n\t\t\tString name = this.name;\n\t\t\tif (name == null) {\n\t\t\t\tint offset = ZipContent.this.nameOffsetLookups.get(this.lookupIndex);\n\t\t\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(this.lookupIndex)\n\t\t\t\t\t\t+ ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET + offset;\n\t\t\t\tname = ZipString.readString(ZipContent.this.data, pos, this.centralRecord.fileNameLength() - offset);\n\t\t\t\tthis.name = name;\n\t\t\t}\n\t\t\treturn name;\n\t\t}\n\n\t\t/**\n\t\t * Return the compression method for this entry.\n\t\t * @return the compression method\n\t\t * @see ZipEntry#STORED\n\t\t * @see ZipEntry#DEFLATED\n\t\t */\n\t\tpublic int getCompressionMethod() {\n\t\t\treturn this.centralRecord.compressionMethod();\n\t\t}\n\n\t\t/**\n\t\t * Return the uncompressed size of this entry.\n\t\t * @return the uncompressed size\n\t\t */\n\t\tpublic int getUncompressedSize() {\n\t\t\treturn this.centralRecord.uncompressedSize();\n\t\t}\n\n\t\t/**\n\t\t * Open a {@link DataBlock} providing access to raw contents of the entry (not\n\t\t * including the local file header).\n\t\t * <p>\n\t\t * To release resources, the {@link #close()} method of the data block should be\n\t\t * called explicitly or by try-with-resources.\n\t\t * @return the contents of the entry\n\t\t * @throws IOException on I/O error\n\t\t */\n\t\tpublic CloseableDataBlock openContent() throws IOException {\n\t\t\tFileDataBlock content = getContent();\n\t\t\tcontent.open();\n\t\t\treturn content;\n\t\t}\n\n\t\tprivate FileDataBlock getContent() throws IOException {\n\t\t\tFileDataBlock content = this.content;\n\t\t\tif (content == null) {\n\t\t\t\tlong pos = Integer.toUnsignedLong(this.centralRecord.offsetToLocalHeader());\n\t\t\t\tcheckNotZip64Extended(pos);\n\t\t\t\tZipLocalFileHeaderRecord localHeader = ZipLocalFileHeaderRecord.load(ZipContent.this.data, pos);\n\t\t\t\tlong size = Integer.toUnsignedLong(this.centralRecord.compressedSize());\n\t\t\t\tcheckNotZip64Extended(size);\n\t\t\t\tcontent = ZipContent.this.data.slice(pos + localHeader.size(), size);\n\t\t\t\tthis.content = content;\n\t\t\t}\n\t\t\treturn content;\n\t\t}\n\n\t\tprivate void checkNotZip64Extended(long value) throws IOException {\n\t\t\tif (value == 0xFFFFFFFF) {\n\t\t\t\tthrow new IOException(\"Zip64 extended information extra fields are not supported\");\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Adapt the raw entry into a {@link ZipEntry} or {@link ZipEntry} subclass.\n\t\t * @param <E> the entry type\n\t\t * @param factory the factory used to create the {@link ZipEntry}\n\t\t * @return a fully populated zip entry\n\t\t */\n\t\tpublic <E extends ZipEntry> E as(Function<String, E> factory) {\n\t\t\treturn as((entry, name) -> factory.apply(name));\n\t\t}\n\n\t\t/**\n\t\t * Adapt the raw entry into a {@link ZipEntry} or {@link ZipEntry} subclass.\n\t\t * @param <E> the entry type\n\t\t * @param factory the factory used to create the {@link ZipEntry}\n\t\t * @return a fully populated zip entry\n\t\t */\n\t\tpublic <E extends ZipEntry> E as(BiFunction<Entry, String, E> factory) {\n\t\t\ttry {\n\t\t\t\tE result = factory.apply(this, getName());\n\t\t\t\tlong pos = getCentralDirectoryFileHeaderRecordPos(this.lookupIndex);\n\t\t\t\tthis.centralRecord.copyTo(ZipContent.this.data, pos, result);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ZipDataDescriptorRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * A ZIP File \"Data Descriptor\" record.\n *\n * @param includeSignature if the signature bytes are written or not (see note in spec)\n * @param crc32 the CRC32 checksum\n * @param compressedSize the size of the entry when compressed\n * @param uncompressedSize the size of the entry when uncompressed\n * @author Phillip Webb\n * @see <a href=\"https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\">Chapter\n * 4.3.9 of the Zip File Format Specification</a>\n */\nrecord ZipDataDescriptorRecord(boolean includeSignature, int crc32, int compressedSize, int uncompressedSize) {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(ZipDataDescriptorRecord.class);\n\n\tprivate static final int SIGNATURE = 0x08074b50;\n\n\tprivate static final int DATA_SIZE = 12;\n\n\tprivate static final int SIGNATURE_SIZE = 4;\n\n\tlong size() {\n\t\treturn (!includeSignature()) ? DATA_SIZE : DATA_SIZE + SIGNATURE_SIZE;\n\t}\n\n\t/**\n\t * Return the contents of this record as a byte array suitable for writing to a zip.\n\t * @return the record as a byte array\n\t */\n\tbyte[] asByteArray() {\n\t\tByteBuffer buffer = ByteBuffer.allocate((int) size());\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tif (this.includeSignature) {\n\t\t\tbuffer.putInt(SIGNATURE);\n\t\t}\n\t\tbuffer.putInt(this.crc32);\n\t\tbuffer.putInt(this.compressedSize);\n\t\tbuffer.putInt(this.uncompressedSize);\n\t\treturn buffer.array();\n\t}\n\n\t/**\n\t * Load the {@link ZipDataDescriptorRecord} from the given data block.\n\t * @param dataBlock the source data block\n\t * @param pos the position of the record\n\t * @return a new {@link ZipLocalFileHeaderRecord} instance\n\t * @throws IOException on I/O error\n\t */\n\tstatic ZipDataDescriptorRecord load(DataBlock dataBlock, long pos) throws IOException {\n\t\tdebug.log(\"Loading ZipDataDescriptorRecord from position %s\", pos);\n\t\tByteBuffer buffer = ByteBuffer.allocate(SIGNATURE_SIZE + DATA_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tbuffer.limit(SIGNATURE_SIZE);\n\t\tdataBlock.readFully(buffer, pos);\n\t\tbuffer.rewind();\n\t\tint signatureOrCrc = buffer.getInt();\n\t\tboolean hasSignature = (signatureOrCrc == SIGNATURE);\n\t\tbuffer.rewind();\n\t\tbuffer.limit((!hasSignature) ? DATA_SIZE - SIGNATURE_SIZE : DATA_SIZE);\n\t\tdataBlock.readFully(buffer, pos + SIGNATURE_SIZE);\n\t\tbuffer.rewind();\n\t\treturn new ZipDataDescriptorRecord(hasSignature, (!hasSignature) ? signatureOrCrc : buffer.getInt(),\n\t\t\t\tbuffer.getInt(), buffer.getInt());\n\t}\n\n\t/**\n\t * Return if the {@link ZipDataDescriptorRecord} is present based on the general\n\t * purpose bit flag in the given {@link ZipLocalFileHeaderRecord}.\n\t * @param localRecord the local record to check\n\t * @return if the bit flag is set\n\t */\n\tstatic boolean isPresentBasedOnFlag(ZipLocalFileHeaderRecord localRecord) {\n\t\treturn isPresentBasedOnFlag(localRecord.generalPurposeBitFlag());\n\t}\n\n\t/**\n\t * Return if the {@link ZipDataDescriptorRecord} is present based on the general\n\t * purpose bit flag in the given {@link ZipCentralDirectoryFileHeaderRecord}.\n\t * @param centralRecord the central record to check\n\t * @return if the bit flag is set\n\t */\n\tstatic boolean isPresentBasedOnFlag(ZipCentralDirectoryFileHeaderRecord centralRecord) {\n\t\treturn isPresentBasedOnFlag(centralRecord.generalPurposeBitFlag());\n\t}\n\n\t/**\n\t * Return if the {@link ZipDataDescriptorRecord} is present based on the given general\n\t * purpose bit flag.\n\t * @param generalPurposeBitFlag the general purpose bit flag to check\n\t * @return if the bit flag is set\n\t */\n\tstatic boolean isPresentBasedOnFlag(int generalPurposeBitFlag) {\n\t\treturn (generalPurposeBitFlag & 0b0000_1000) != 0;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ZipEndOfCentralDirectoryRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * A ZIP File \"End of central directory record\" (EOCD).\n *\n * @author Phillip Webb\n * @param numberOfThisDisk the number of this disk (or 0xffff for Zip64)\n * @param diskWhereCentralDirectoryStarts the disk where central directory starts (or\n * 0xffff for Zip64)\n * @param numberOfCentralDirectoryEntriesOnThisDisk the number of central directory\n * entries on this disk (or 0xffff for Zip64)\n * @param totalNumberOfCentralDirectoryEntries the total number of central directory\n * entries (or 0xffff for Zip64)\n * @param sizeOfCentralDirectory the size of central directory (bytes) (or 0xffffffff for\n * Zip64)\n * @param offsetToStartOfCentralDirectory the offset of start of central directory,\n * relative to start of archive (or 0xffffffff for Zip64)\n * @param commentLength the length of the comment field\n * @see <a href=\"https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\">Chapter\n * 4.3.16 of the Zip File Format Specification</a>\n */\nrecord ZipEndOfCentralDirectoryRecord(short numberOfThisDisk, short diskWhereCentralDirectoryStarts,\n\t\tshort numberOfCentralDirectoryEntriesOnThisDisk, short totalNumberOfCentralDirectoryEntries,\n\t\tint sizeOfCentralDirectory, int offsetToStartOfCentralDirectory, short commentLength) {\n\n\tZipEndOfCentralDirectoryRecord(short totalNumberOfCentralDirectoryEntries, int sizeOfCentralDirectory,\n\t\t\tint offsetToStartOfCentralDirectory) {\n\t\tthis((short) 0, (short) 0, totalNumberOfCentralDirectoryEntries, totalNumberOfCentralDirectoryEntries,\n\t\t\t\tsizeOfCentralDirectory, offsetToStartOfCentralDirectory, (short) 0);\n\t}\n\n\tprivate static final DebugLogger debug = DebugLogger.get(ZipEndOfCentralDirectoryRecord.class);\n\n\tprivate static final int SIGNATURE = 0x06054b50;\n\n\tprivate static final int MAXIMUM_COMMENT_LENGTH = 0xFFFF;\n\n\tprivate static final int MINIMUM_SIZE = 22;\n\n\tprivate static final int MAXIMUM_SIZE = MINIMUM_SIZE + MAXIMUM_COMMENT_LENGTH;\n\n\tstatic final int BUFFER_SIZE = 256;\n\n\t/**\n\t * The offset of the file comment relative to the record start position.\n\t */\n\tstatic final int COMMENT_OFFSET = MINIMUM_SIZE;\n\n\t/**\n\t * Return the size of this record.\n\t * @return the record size\n\t */\n\tlong size() {\n\t\treturn MINIMUM_SIZE + this.commentLength;\n\t}\n\n\t/**\n\t * Return the contents of this record as a byte array suitable for writing to a zip.\n\t * @return the record as a byte array\n\t */\n\tbyte[] asByteArray() {\n\t\tByteBuffer buffer = ByteBuffer.allocate(MINIMUM_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tbuffer.putInt(SIGNATURE);\n\t\tbuffer.putShort(this.numberOfThisDisk);\n\t\tbuffer.putShort(this.diskWhereCentralDirectoryStarts);\n\t\tbuffer.putShort(this.numberOfCentralDirectoryEntriesOnThisDisk);\n\t\tbuffer.putShort(this.totalNumberOfCentralDirectoryEntries);\n\t\tbuffer.putInt(this.sizeOfCentralDirectory);\n\t\tbuffer.putInt(this.offsetToStartOfCentralDirectory);\n\t\tbuffer.putShort(this.commentLength);\n\t\treturn buffer.array();\n\t}\n\n\t/**\n\t * Create a new {@link ZipEndOfCentralDirectoryRecord} instance from the specified\n\t * {@link DataBlock} by searching backwards from the end until a valid record is\n\t * located.\n\t * @param dataBlock the source data block\n\t * @return the {@link Located located} {@link ZipEndOfCentralDirectoryRecord}\n\t * @throws IOException if the {@link ZipEndOfCentralDirectoryRecord} cannot be read\n\t */\n\tstatic Located load(DataBlock dataBlock) throws IOException {\n\t\tByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tlong pos = locate(dataBlock, buffer);\n\t\treturn new Located(pos, new ZipEndOfCentralDirectoryRecord(buffer.getShort(), buffer.getShort(),\n\t\t\t\tbuffer.getShort(), buffer.getShort(), buffer.getInt(), buffer.getInt(), buffer.getShort()));\n\t}\n\n\tprivate static long locate(DataBlock dataBlock, ByteBuffer buffer) throws IOException {\n\t\tlong endPos = dataBlock.size();\n\t\tdebug.log(\"Finding EndOfCentralDirectoryRecord starting at end position %s\", endPos);\n\t\twhile (endPos > 0) {\n\t\t\tbuffer.clear();\n\t\t\tlong totalRead = dataBlock.size() - endPos;\n\t\t\tif (totalRead > MAXIMUM_SIZE) {\n\t\t\t\tthrow new IOException(\n\t\t\t\t\t\t\"Zip 'End Of Central Directory Record' not found after reading \" + totalRead + \" bytes\");\n\t\t\t}\n\t\t\tlong startPos = endPos - buffer.limit();\n\t\t\tif (startPos < 0) {\n\t\t\t\tbuffer.limit((int) startPos + buffer.limit());\n\t\t\t\tstartPos = 0;\n\t\t\t}\n\t\t\tdebug.log(\"Finding EndOfCentralDirectoryRecord from %s with limit %s\", startPos, buffer.limit());\n\t\t\tdataBlock.readFully(buffer, startPos);\n\t\t\tint offset = findInBuffer(buffer);\n\t\t\tif (offset >= 0) {\n\t\t\t\tdebug.log(\"Found EndOfCentralDirectoryRecord at %s + %s\", startPos, offset);\n\t\t\t\treturn startPos + offset;\n\t\t\t}\n\t\t\tendPos = endPos - BUFFER_SIZE + MINIMUM_SIZE;\n\t\t}\n\t\tthrow new IOException(\"Zip 'End Of Central Directory Record' not found after reading entire data block\");\n\t}\n\n\tprivate static int findInBuffer(ByteBuffer buffer) {\n\t\tfor (int pos = buffer.limit() - 4; pos >= 0; pos--) {\n\t\t\tbuffer.position(pos);\n\t\t\tif (buffer.getInt() == SIGNATURE) {\n\t\t\t\treturn pos;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * A located {@link ZipEndOfCentralDirectoryRecord}.\n\t *\n\t * @param pos the position of the record\n\t * @param endOfCentralDirectoryRecord the located end of central directory record\n\t */\n\trecord Located(long pos, ZipEndOfCentralDirectoryRecord endOfCentralDirectoryRecord) {\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ZipLocalFileHeaderRecord.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * A ZIP File \"Local file header record\" (LFH).\n *\n * @param versionNeededToExtract the version needed to extract the zip\n * @param generalPurposeBitFlag the general purpose bit flag\n * @param compressionMethod the compression method used for this entry\n * @param lastModFileTime the last modified file time\n * @param lastModFileDate the last modified file date\n * @param crc32 the CRC32 checksum\n * @param compressedSize the size of the entry when compressed\n * @param uncompressedSize the size of the entry when uncompressed\n * @param fileNameLength the file name length\n * @param extraFieldLength the extra field length\n * @author Phillip Webb\n * @see <a href=\"https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT\">Chapter\n * 4.3.7 of the Zip File Format Specification</a>\n */\nrecord ZipLocalFileHeaderRecord(short versionNeededToExtract, short generalPurposeBitFlag, short compressionMethod,\n\t\tshort lastModFileTime, short lastModFileDate, int crc32, int compressedSize, int uncompressedSize,\n\t\tshort fileNameLength, short extraFieldLength) {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(ZipLocalFileHeaderRecord.class);\n\n\tprivate static final int SIGNATURE = 0x04034b50;\n\n\tprivate static final int MINIMUM_SIZE = 30;\n\n\t/**\n\t * Return the size of this record.\n\t * @return the record size\n\t */\n\tlong size() {\n\t\treturn MINIMUM_SIZE + fileNameLength() + extraFieldLength();\n\t}\n\n\t/**\n\t * Return a new {@link ZipLocalFileHeaderRecord} with a new\n\t * {@link #extraFieldLength()}.\n\t * @param extraFieldLength the new extra field length\n\t * @return a new {@link ZipLocalFileHeaderRecord} instance\n\t */\n\tZipLocalFileHeaderRecord withExtraFieldLength(short extraFieldLength) {\n\t\treturn new ZipLocalFileHeaderRecord(this.versionNeededToExtract, this.generalPurposeBitFlag,\n\t\t\t\tthis.compressionMethod, this.lastModFileTime, this.lastModFileDate, this.crc32, this.compressedSize,\n\t\t\t\tthis.uncompressedSize, this.fileNameLength, extraFieldLength);\n\t}\n\n\t/**\n\t * Return a new {@link ZipLocalFileHeaderRecord} with a new {@link #fileNameLength()}.\n\t * @param fileNameLength the new file name length\n\t * @return a new {@link ZipLocalFileHeaderRecord} instance\n\t */\n\tZipLocalFileHeaderRecord withFileNameLength(short fileNameLength) {\n\t\treturn new ZipLocalFileHeaderRecord(this.versionNeededToExtract, this.generalPurposeBitFlag,\n\t\t\t\tthis.compressionMethod, this.lastModFileTime, this.lastModFileDate, this.crc32, this.compressedSize,\n\t\t\t\tthis.uncompressedSize, fileNameLength, this.extraFieldLength);\n\t}\n\n\t/**\n\t * Return the contents of this record as a byte array suitable for writing to a zip.\n\t * @return the record as a byte array\n\t */\n\tbyte[] asByteArray() {\n\t\tByteBuffer buffer = ByteBuffer.allocate(MINIMUM_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tbuffer.putInt(SIGNATURE);\n\t\tbuffer.putShort(this.versionNeededToExtract);\n\t\tbuffer.putShort(this.generalPurposeBitFlag);\n\t\tbuffer.putShort(this.compressionMethod);\n\t\tbuffer.putShort(this.lastModFileTime);\n\t\tbuffer.putShort(this.lastModFileDate);\n\t\tbuffer.putInt(this.crc32);\n\t\tbuffer.putInt(this.compressedSize);\n\t\tbuffer.putInt(this.uncompressedSize);\n\t\tbuffer.putShort(this.fileNameLength);\n\t\tbuffer.putShort(this.extraFieldLength);\n\t\treturn buffer.array();\n\t}\n\n\t/**\n\t * Load the {@link ZipLocalFileHeaderRecord} from the given data block.\n\t * @param dataBlock the source data block\n\t * @param pos the position of the record\n\t * @return a new {@link ZipLocalFileHeaderRecord} instance\n\t * @throws IOException on I/O error\n\t */\n\tstatic ZipLocalFileHeaderRecord load(DataBlock dataBlock, long pos) throws IOException {\n\t\tdebug.log(\"Loading LocalFileHeaderRecord from position %s\", pos);\n\t\tByteBuffer buffer = ByteBuffer.allocate(MINIMUM_SIZE);\n\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\tdataBlock.readFully(buffer, pos);\n\t\tbuffer.rewind();\n\t\tif (buffer.getInt() != SIGNATURE) {\n\t\t\tthrow new IOException(\"Zip 'Local File Header Record' not found at position \" + pos);\n\t\t}\n\t\treturn new ZipLocalFileHeaderRecord(buffer.getShort(), buffer.getShort(), buffer.getShort(), buffer.getShort(),\n\t\t\t\tbuffer.getShort(), buffer.getInt(), buffer.getInt(), buffer.getInt(), buffer.getShort(),\n\t\t\t\tbuffer.getShort());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/ZipString.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.boot.loader.log.DebugLogger;\n\n/**\n * Internal utility class for working with the string content of zip records. Provides\n * methods that work with raw bytes to save creating temporary strings.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nfinal class ZipString {\n\n\tprivate static final DebugLogger debug = DebugLogger.get(ZipString.class);\n\n\tstatic final int BUFFER_SIZE = 256;\n\n\tprivate static final int[] INITIAL_BYTE_BITMASK = { 0x7F, 0x1F, 0x0F, 0x07 };\n\n\tprivate static final int SUBSEQUENT_BYTE_BITMASK = 0x3F;\n\n\tprivate static final int EMPTY_HASH = \"\".hashCode();\n\n\tprivate static final int EMPTY_SLASH_HASH = \"/\".hashCode();\n\n\tprivate ZipString() {\n\t}\n\n\t/**\n\t * Return a hash for a char sequence, optionally appending '/'.\n\t * @param charSequence the source char sequence\n\t * @param addEndSlash if slash should be added to the string if it's not already\n\t * present\n\t * @return the hash\n\t */\n\tstatic int hash(CharSequence charSequence, boolean addEndSlash) {\n\t\treturn hash(0, charSequence, addEndSlash);\n\t}\n\n\t/**\n\t * Return a hash for a char sequence, optionally appending '/'.\n\t * @param initialHash the initial hash value\n\t * @param charSequence the source char sequence\n\t * @param addEndSlash if slash should be added to the string if it's not already\n\t * present\n\t * @return the hash\n\t */\n\tstatic int hash(int initialHash, CharSequence charSequence, boolean addEndSlash) {\n\t\tif (charSequence == null || charSequence.isEmpty()) {\n\t\t\treturn (!addEndSlash) ? EMPTY_HASH : EMPTY_SLASH_HASH;\n\t\t}\n\t\tboolean endsWithSlash = charSequence.charAt(charSequence.length() - 1) == '/';\n\t\tint hash = initialHash;\n\t\tif (charSequence instanceof String && initialHash == 0) {\n\t\t\t// We're compatible with String.hashCode and it might be already calculated\n\t\t\thash = charSequence.hashCode();\n\t\t}\n\t\telse {\n\t\t\tfor (int i = 0; i < charSequence.length(); i++) {\n\t\t\t\tchar ch = charSequence.charAt(i);\n\t\t\t\thash = 31 * hash + ch;\n\t\t\t}\n\t\t}\n\t\thash = (addEndSlash && !endsWithSlash) ? 31 * hash + '/' : hash;\n\t\tdebug.log(\"%s calculated for charsequence '%s' (addEndSlash=%s)\", hash, charSequence, endsWithSlash);\n\t\treturn hash;\n\t}\n\n\t/**\n\t * Return a hash for bytes read from a {@link DataBlock}, optionally appending '/'.\n\t * @param buffer the buffer to use or {@code null}\n\t * @param dataBlock the source data block\n\t * @param pos the position in the data block where the string starts\n\t * @param len the number of bytes to read from the block\n\t * @param addEndSlash if slash should be added to the string if it's not already\n\t * present\n\t * @return the hash\n\t * @throws IOException on I/O error\n\t */\n\tstatic int hash(ByteBuffer buffer, DataBlock dataBlock, long pos, int len, boolean addEndSlash) throws IOException {\n\t\tif (len == 0) {\n\t\t\treturn (!addEndSlash) ? EMPTY_HASH : EMPTY_SLASH_HASH;\n\t\t}\n\t\tbuffer = (buffer != null) ? buffer : ByteBuffer.allocate(BUFFER_SIZE);\n\t\tbyte[] bytes = buffer.array();\n\t\tint hash = 0;\n\t\tchar lastChar = 0;\n\t\tint codePointSize = 1;\n\t\twhile (len > 0) {\n\t\t\tint count = readInBuffer(dataBlock, pos, buffer, len, codePointSize);\n\t\t\tfor (int byteIndex = 0; byteIndex < count;) {\n\t\t\t\tcodePointSize = getCodePointSize(bytes, byteIndex);\n\t\t\t\tif (!hasEnoughBytes(byteIndex, codePointSize, count)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tint codePoint = getCodePoint(bytes, byteIndex, codePointSize);\n\t\t\t\tif (codePoint <= 0xFFFF) {\n\t\t\t\t\tlastChar = (char) (codePoint & 0xFFFF);\n\t\t\t\t\thash = 31 * hash + lastChar;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlastChar = 0;\n\t\t\t\t\thash = 31 * hash + Character.highSurrogate(codePoint);\n\t\t\t\t\thash = 31 * hash + Character.lowSurrogate(codePoint);\n\t\t\t\t}\n\t\t\t\tbyteIndex += codePointSize;\n\t\t\t\tpos += codePointSize;\n\t\t\t\tlen -= codePointSize;\n\t\t\t\tcodePointSize = 1;\n\t\t\t}\n\t\t}\n\t\thash = (addEndSlash && lastChar != '/') ? 31 * hash + '/' : hash;\n\t\tdebug.log(\"%08X calculated for datablock position %s size %s (addEndSlash=%s)\", hash, pos, len, addEndSlash);\n\t\treturn hash;\n\t}\n\n\t/**\n\t * Return if the bytes read from a {@link DataBlock} matches the give\n\t * {@link CharSequence}.\n\t * @param buffer the buffer to use or {@code null}\n\t * @param dataBlock the source data block\n\t * @param pos the position in the data block where the string starts\n\t * @param len the number of bytes to read from the block\n\t * @param charSequence the char sequence with which to compare\n\t * @param addSlash also accept {@code charSequence + '/'} when it doesn't already end\n\t * with one\n\t * @return true if the contents are considered equal\n\t */\n\tstatic boolean matches(ByteBuffer buffer, DataBlock dataBlock, long pos, int len, CharSequence charSequence,\n\t\t\tboolean addSlash) {\n\t\tif (charSequence.isEmpty()) {\n\t\t\treturn true;\n\t\t}\n\t\tbuffer = (buffer != null) ? buffer : ByteBuffer.allocate(BUFFER_SIZE);\n\t\ttry {\n\t\t\treturn compare(buffer, dataBlock, pos, len, charSequence,\n\t\t\t\t\t(!addSlash) ? CompareType.MATCHES : CompareType.MATCHES_ADDING_SLASH) != -1;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Returns if the bytes read from a {@link DataBlock} starts with the given\n\t * {@link CharSequence}.\n\t * @param buffer the buffer to use or {@code null}\n\t * @param dataBlock the source data block\n\t * @param pos the position in the data block where the string starts\n\t * @param len the number of bytes to read from the block\n\t * @param charSequence the required starting chars\n\t * @return {@code -1} if the data block does not start with the char sequence, or a\n\t * positive number indicating the number of bytes that contain the starting chars\n\t */\n\tstatic int startsWith(ByteBuffer buffer, DataBlock dataBlock, long pos, int len, CharSequence charSequence) {\n\t\tif (charSequence.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\t\tbuffer = (buffer != null) ? buffer : ByteBuffer.allocate(BUFFER_SIZE);\n\t\ttry {\n\t\t\treturn compare(buffer, dataBlock, pos, len, charSequence, CompareType.STARTS_WITH);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate static int compare(ByteBuffer buffer, DataBlock dataBlock, long pos, int len, CharSequence charSequence,\n\t\t\tCompareType compareType) throws IOException {\n\t\tif (charSequence.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\t\tboolean addSlash = compareType == CompareType.MATCHES_ADDING_SLASH && !endsWith(charSequence, '/');\n\t\tint charSequenceIndex = 0;\n\t\tint maxCharSequenceLength = (!addSlash) ? charSequence.length() : charSequence.length() + 1;\n\t\tint result = 0;\n\t\tbyte[] bytes = buffer.array();\n\t\tint codePointSize = 1;\n\t\twhile (len > 0) {\n\t\t\tint count = readInBuffer(dataBlock, pos, buffer, len, codePointSize);\n\t\t\tfor (int byteIndex = 0; byteIndex < count;) {\n\t\t\t\tcodePointSize = getCodePointSize(bytes, byteIndex);\n\t\t\t\tif (!hasEnoughBytes(byteIndex, codePointSize, count)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tint codePoint = getCodePoint(bytes, byteIndex, codePointSize);\n\t\t\t\tif (codePoint <= 0xFFFF) {\n\t\t\t\t\tchar ch = (char) (codePoint & 0xFFFF);\n\t\t\t\t\tif (charSequenceIndex >= maxCharSequenceLength\n\t\t\t\t\t\t\t|| getChar(charSequence, charSequenceIndex++) != ch) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tchar ch = Character.highSurrogate(codePoint);\n\t\t\t\t\tif (charSequenceIndex >= maxCharSequenceLength\n\t\t\t\t\t\t\t|| getChar(charSequence, charSequenceIndex++) != ch) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t\tch = Character.lowSurrogate(codePoint);\n\t\t\t\t\tif (charSequenceIndex >= charSequence.length()\n\t\t\t\t\t\t\t|| getChar(charSequence, charSequenceIndex++) != ch) {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbyteIndex += codePointSize;\n\t\t\t\tpos += codePointSize;\n\t\t\t\tlen -= codePointSize;\n\t\t\t\tresult += codePointSize;\n\t\t\t\tcodePointSize = 1;\n\t\t\t\tif (compareType == CompareType.STARTS_WITH && charSequenceIndex >= charSequence.length()) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn (charSequenceIndex >= charSequence.length()) ? result : -1;\n\t}\n\n\tprivate static boolean hasEnoughBytes(int byteIndex, int codePointSize, int count) {\n\t\treturn (byteIndex + codePointSize - 1) < count;\n\t}\n\n\tprivate static boolean endsWith(CharSequence charSequence, char ch) {\n\t\treturn !charSequence.isEmpty() && charSequence.charAt(charSequence.length() - 1) == ch;\n\t}\n\n\tprivate static char getChar(CharSequence charSequence, int index) {\n\t\treturn (index != charSequence.length()) ? charSequence.charAt(index) : '/';\n\t}\n\n\t/**\n\t * Read a string value from the given data block.\n\t * @param data the source data\n\t * @param pos the position to read from\n\t * @param len the number of bytes to read\n\t * @return the contents as a string\n\t */\n\tstatic String readString(DataBlock data, long pos, long len) {\n\t\ttry {\n\t\t\tif (len > Integer.MAX_VALUE) {\n\t\t\t\tthrow new IllegalStateException(\"String is too long to read\");\n\t\t\t}\n\t\t\tByteBuffer buffer = ByteBuffer.allocate((int) len);\n\t\t\tbuffer.order(ByteOrder.LITTLE_ENDIAN);\n\t\t\tdata.readFully(buffer, pos);\n\t\t\treturn new String(buffer.array(), StandardCharsets.UTF_8);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tprivate static int readInBuffer(DataBlock dataBlock, long pos, ByteBuffer buffer, int maxLen, int minLen)\n\t\t\tthrows IOException {\n\t\tbuffer.clear();\n\t\tif (buffer.remaining() > maxLen) {\n\t\t\tbuffer.limit(maxLen);\n\t\t}\n\t\tint result = 0;\n\t\twhile (result < minLen) {\n\t\t\tint count = dataBlock.read(buffer, pos);\n\t\t\tif (count <= 0) {\n\t\t\t\tthrow new EOFException();\n\t\t\t}\n\t\t\tresult += count;\n\t\t\tpos += count;\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static int getCodePointSize(byte[] bytes, int i) {\n\t\tint b = Byte.toUnsignedInt(bytes[i]);\n\t\tif ((b & 0b1_0000000) == 0b0_0000000) {\n\t\t\treturn 1;\n\t\t}\n\t\tif ((b & 0b111_00000) == 0b110_00000) {\n\t\t\treturn 2;\n\t\t}\n\t\tif ((b & 0b1111_0000) == 0b1110_0000) {\n\t\t\treturn 3;\n\t\t}\n\t\treturn 4;\n\t}\n\n\tprivate static int getCodePoint(byte[] bytes, int i, int codePointSize) {\n\t\tint codePoint = Byte.toUnsignedInt(bytes[i]);\n\t\tcodePoint &= INITIAL_BYTE_BITMASK[codePointSize - 1];\n\t\tfor (int j = 1; j < codePointSize; j++) {\n\t\t\tcodePoint = (codePoint << 6) + (bytes[i + j] & SUBSEQUENT_BYTE_BITMASK);\n\t\t}\n\t\treturn codePoint;\n\t}\n\n\t/**\n\t * Supported compare types.\n\t */\n\tprivate enum CompareType {\n\n\t\tMATCHES, MATCHES_ADDING_SLASH, STARTS_WITH\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/java/org/springframework/boot/loader/zip/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Provides low-level support for handling zip content, including support for nested and\n * virtual zip files.\n */\npackage org.springframework.boot.loader.zip;\n"
  },
  {
    "path": "loader/spring-boot-loader/src/main/resources/META-INF/services/java.nio.file.spi.FileSystemProvider",
    "content": "org.springframework.boot.loader.nio.file.NestedFileSystemProvider\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/ManifestInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.util.jar.Attributes.Name;\nimport java.util.jar.Manifest;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ManifestInfo}.\n *\n * @author Phillip Webb\n */\nclass ManifestInfoTests {\n\n\t@Test\n\tvoid noneReturnsNoDetails() {\n\t\tassertThat(ManifestInfo.NONE.getManifest()).isNull();\n\t\tassertThat(ManifestInfo.NONE.isMultiRelease()).isFalse();\n\t}\n\n\t@Test\n\tvoid getManifestReturnsManifest() {\n\t\tManifest manifest = new Manifest();\n\t\tManifestInfo info = new ManifestInfo(manifest);\n\t\tassertThat(info.getManifest()).isSameAs(manifest);\n\t}\n\n\t@Test\n\tvoid isMultiReleaseWhenHasMultiReleaseAttributeReturnsTrue() {\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().put(new Name(\"Multi-Release\"), \"true\");\n\t\tManifestInfo info = new ManifestInfo(manifest);\n\t\tassertThat(info.isMultiRelease()).isTrue();\n\t}\n\n\t@Test\n\tvoid isMultiReleaseWhenHasNoMultiReleaseAttributeReturnsFalse() {\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().put(new Name(\"Random-Release\"), \"true\");\n\t\tManifestInfo info = new ManifestInfo(manifest);\n\t\tassertThat(info.isMultiRelease()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/MetaInfVersionsInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.zip.ZipContent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetaInfVersionsInfo}.\n *\n * @author Phillip Webb\n */\nclass MetaInfVersionsInfoTests {\n\n\t@Test\n\tvoid getParsesVersionsAndEntries() {\n\t\tList<ZipContent.Entry> entries = new ArrayList<>();\n\t\tentries.add(mockEntry(\"META-INF/\"));\n\t\tentries.add(mockEntry(\"META-INF/MANIFEST.MF\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/9/\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/9/Foo.class\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/11/\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/11/Foo.class\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/10/\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/10/Foo.class\"));\n\t\tMetaInfVersionsInfo info = MetaInfVersionsInfo.get(entries.size(), entries::get);\n\t\tassertThat(info.versions()).containsExactly(9, 10, 11);\n\t\tassertThat(info.directories()).containsExactly(\"META-INF/versions/9/\", \"META-INF/versions/10/\",\n\t\t\t\t\"META-INF/versions/11/\");\n\t}\n\n\t@Test\n\tvoid getWhenHasBadEntryParsesGoodVersionsAndEntries() {\n\t\tList<ZipContent.Entry> entries = new ArrayList<>();\n\t\tentries.add(mockEntry(\"META-INF/versions/9/Foo.class\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/0x11/Foo.class\"));\n\t\tMetaInfVersionsInfo info = MetaInfVersionsInfo.get(entries.size(), entries::get);\n\t\tassertThat(info.versions()).containsExactly(9);\n\t\tassertThat(info.directories()).containsExactly(\"META-INF/versions/9/\");\n\t}\n\n\t@Test\n\tvoid getWhenHasNoEntriesReturnsNone() {\n\t\tList<ZipContent.Entry> entries = new ArrayList<>();\n\t\tMetaInfVersionsInfo info = MetaInfVersionsInfo.get(entries.size(), entries::get);\n\t\tassertThat(info.versions()).isEmpty();\n\t\tassertThat(info.directories()).isEmpty();\n\t\tassertThat(info).isSameAs(MetaInfVersionsInfo.NONE);\n\t}\n\n\t@Test\n\tvoid toleratesUnexpectedFileEntryInMetaInfVersions() {\n\t\tList<ZipContent.Entry> entries = new ArrayList<>();\n\t\tentries.add(mockEntry(\"META-INF/\"));\n\t\tentries.add(mockEntry(\"META-INF/MANIFEST.MF\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/unexpected\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/9/\"));\n\t\tentries.add(mockEntry(\"META-INF/versions/9/Foo.class\"));\n\t\tMetaInfVersionsInfo info = MetaInfVersionsInfo.get(entries.size(), entries::get);\n\t\tassertThat(info.versions()).containsExactly(9);\n\t\tassertThat(info.directories()).containsExactly(\"META-INF/versions/9/\");\n\t}\n\n\tprivate ZipContent.Entry mockEntry(String name) {\n\t\tZipContent.Entry entry = mock(ZipContent.Entry.class);\n\t\tgiven(entry.getName()).willReturn(name);\n\t\tgiven(entry.hasNameStartingWith(any()))\n\t\t\t.willAnswer((invocation) -> name.startsWith(invocation.getArgument(0, CharSequence.class).toString()));\n\t\tgiven(entry.isDirectory()).willAnswer((invocation) -> name.endsWith(\"/\"));\n\t\treturn entry;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/NestedJarFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport org.assertj.core.extractor.Extractors;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.loader.zip.ZipContent;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StopWatch;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atMostOnce;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NestedJarFile}.\n *\n * @author Phillip Webb\n * @author Martin Lau\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\n@AssertFileChannelDataBlocksClosed\nclass NestedJarFileTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprivate File file;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.tempDir, \"test.jar\");\n\t\tTestJar.create(this.file);\n\t}\n\n\t@Test\n\tvoid createOpensJar() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\ttry (JarFile jdkJar = new JarFile(this.file)) {\n\t\t\t\tassertThat(jar.size()).isEqualTo(jdkJar.size());\n\t\t\t\tassertThat(jar.getComment()).isEqualTo(jdkJar.getComment());\n\t\t\t\tEnumeration<JarEntry> entries = jar.entries();\n\t\t\t\tEnumeration<JarEntry> jdkEntries = jdkJar.entries();\n\t\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\t\tassertThat(entries.nextElement().getName()).isEqualTo(jdkEntries.nextElement().getName());\n\t\t\t\t}\n\t\t\t\tassertThat(jdkEntries.hasMoreElements()).isFalse();\n\t\t\t\ttry (InputStream in = jar.getInputStream(jar.getEntry(\"1.dat\"))) {\n\t\t\t\t\tassertThat(in.readAllBytes()).containsExactly(new byte[] { 1 });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid createWhenNestedJarFileOpensJar() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"nested.jar\")) {\n\t\t\tassertThat(jar.size()).isEqualTo(5);\n\t\t\tassertThat(jar.stream().map(JarEntry::getName)).containsExactly(\"META-INF/\", \"META-INF/MANIFEST.MF\",\n\t\t\t\t\t\"3.dat\", \"4.dat\", \"\\u00E4.dat\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid createWhenNestedJarDirectoryOpensJar() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"d/\")) {\n\t\t\tassertThat(jar.getName()).isEqualTo(this.file.getAbsolutePath() + \"!/d/\");\n\t\t\tassertThat(jar.size()).isEqualTo(1);\n\t\t\tassertThat(jar.stream().map(JarEntry::getName)).containsExactly(\"9.dat\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getManifestWhenNestedJarReturnsManifestOfNestedJar() throws Exception {\n\t\ttry (JarFile jar = new JarFile(this.file)) {\n\t\t\ttry (NestedJarFile nestedJar = new NestedJarFile(this.file, \"nested.jar\")) {\n\t\t\t\tManifest manifest = nestedJar.getManifest();\n\t\t\t\tassertThat(manifest).isNotEqualTo(jar.getManifest());\n\t\t\t\tassertThat(manifest.getMainAttributes().getValue(\"Built-By\")).isEqualTo(\"j2\");\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getManifestWhenNestedJarDirectoryReturnsManifestOfParent() throws Exception {\n\t\ttry (JarFile jar = new JarFile(this.file)) {\n\t\t\ttry (NestedJarFile nestedJar = new NestedJarFile(this.file, \"d/\")) {\n\t\t\t\tassertThat(nestedJar.getManifest()).isEqualTo(jar.getManifest());\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid createWhenJarHasFrontMatterOpensJar() throws IOException {\n\t\tFile file = new File(this.tempDir, \"frontmatter.jar\");\n\t\tInputStream sourceJarContent = new FileInputStream(this.file);\n\t\tFileOutputStream outputStream = new FileOutputStream(file);\n\t\tStreamUtils.copy(\"#/bin/bash\", Charset.defaultCharset(), outputStream);\n\t\tFileCopyUtils.copy(sourceJarContent, outputStream);\n\t\ttry (NestedJarFile jar = new NestedJarFile(file)) {\n\t\t\tassertThat(jar.size()).isEqualTo(12);\n\t\t}\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"nested.jar\")) {\n\t\t\tassertThat(jar.size()).isEqualTo(5);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getEntryReturnsEntry() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jar.getEntry(\"1.dat\");\n\t\t\tassertEntryOne(entry);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getEntryWhenClosedThrowsException() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tjar.close();\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> jar.getEntry(\"1.dat\")).withMessage(\"Zip file closed\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getJarEntryReturnsEntry() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jar.getJarEntry(\"1.dat\");\n\t\t\tassertEntryOne(entry);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getJarEntryWhenClosedThrowsException() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tjar.close();\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> jar.getJarEntry(\"1.dat\")).withMessage(\"Zip file closed\");\n\t\t}\n\t}\n\n\tprivate void assertEntryOne(JarEntry entry) {\n\t\tassertThat(entry.getName()).isEqualTo(\"1.dat\");\n\t\tassertThat(entry.getRealName()).isEqualTo(\"1.dat\");\n\t\tassertThat(entry.getSize()).isEqualTo(1);\n\t\tassertThat(entry.getCompressedSize()).isEqualTo(3);\n\t\tassertThat(entry.getCrc()).isEqualTo(2768625435L);\n\t\tassertThat(entry.getMethod()).isEqualTo(8);\n\t}\n\n\t@Test\n\tvoid getEntryWhenMultiReleaseEntryReturnsEntry() throws IOException {\n\t\tFile multiReleaseFile = new File(this.tempDir, \"mutli.zip\");\n\t\ttry (ZipContent zip = ZipContent.open(this.file.toPath(), \"multi-release.jar\")) {\n\t\t\ttry (InputStream in = zip.openRawZipData().asInputStream()) {\n\t\t\t\ttry (FileOutputStream out = new FileOutputStream(multiReleaseFile)) {\n\t\t\t\t\tin.transferTo(out);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"multi-release.jar\", JarFile.runtimeVersion())) {\n\t\t\ttry (JarFile jdkJar = new JarFile(multiReleaseFile, true, ZipFile.OPEN_READ, JarFile.runtimeVersion())) {\n\t\t\t\tJarEntry entry = jar.getJarEntry(\"multi-release.dat\");\n\t\t\t\tJarEntry jdkEntry = jdkJar.getJarEntry(\"multi-release.dat\");\n\t\t\t\tassertThat(entry.getName()).isEqualTo(jdkEntry.getName());\n\t\t\t\tassertThat(entry.getRealName()).isEqualTo(jdkEntry.getRealName());\n\t\t\t\ttry (InputStream inputStream = jdkJar.getInputStream(entry)) {\n\t\t\t\t\tassertThat(inputStream.available()).isOne();\n\t\t\t\t\tassertThat(inputStream.read()).isEqualTo(Runtime.version().feature());\n\t\t\t\t}\n\t\t\t\ttry (InputStream inputStream = jar.getInputStream(entry)) {\n\t\t\t\t\tassertThat(inputStream.available()).isOne();\n\t\t\t\t\tassertThat(inputStream.read()).isEqualTo(Runtime.version().feature());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getManifestReturnsManifest() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tManifest manifest = jar.getManifest();\n\t\t\tassertThat(manifest).isNotNull();\n\t\t\tassertThat(manifest.getEntries()).isEmpty();\n\t\t\tassertThat(manifest.getMainAttributes().getValue(\"Manifest-Version\")).isEqualTo(\"1.0\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getCommentReturnsComment() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tassertThat(jar.getComment()).isEqualTo(\"outer\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getCommentWhenClosedThrowsException() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tjar.close();\n\t\t\tassertThatIllegalStateException().isThrownBy(jar::getComment).withMessage(\"Zip file closed\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getNameReturnsName() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tassertThat(jar.getName()).isEqualTo(this.file.getAbsolutePath());\n\t\t}\n\t}\n\n\t@Test\n\tvoid getNameWhenNestedReturnsName() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"nested.jar\")) {\n\t\t\tassertThat(jar.getName()).isEqualTo(this.file.getAbsolutePath() + \"!/nested.jar\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid sizeReturnsSize() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tassertThat(jar.size()).isEqualByComparingTo(12);\n\t\t}\n\t}\n\n\t@Test\n\tvoid sizeWhenClosedThrowsException() throws Exception {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tjar.close();\n\t\t\tassertThatIllegalStateException().isThrownBy(jar::size).withMessage(\"Zip file closed\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getEntryTime() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\ttry (JarFile jdkJar = new JarFile(this.file)) {\n\t\t\t\tassertThat(jar.getEntry(\"META-INF/MANIFEST.MF\").getTime())\n\t\t\t\t\t.isEqualTo(jar.getEntry(\"META-INF/MANIFEST.MF\").getTime());\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid closeTriggersCleanupOnlyOnce() throws IOException {\n\t\tCleaner cleaner = mock(Cleaner.class);\n\t\tArgumentCaptor<Runnable> action = ArgumentCaptor.forClass(Runnable.class);\n\t\tCleanable cleanable = mock(Cleanable.class);\n\t\tgiven(cleaner.register(any(), action.capture())).willReturn(cleanable);\n\t\tNestedJarFile jar = new NestedJarFile(this.file, null, null, false, cleaner);\n\t\tjar.close();\n\t\tjar.close();\n\t\tthen(cleanable).should(atMostOnce()).clean();\n\t\taction.getValue().run();\n\t}\n\n\t@Test\n\tvoid cleanupFromReleasesResources() throws IOException {\n\t\tCleaner cleaner = mock(Cleaner.class);\n\t\tArgumentCaptor<Runnable> action = ArgumentCaptor.forClass(Runnable.class);\n\t\tCleanable cleanable = mock(Cleanable.class);\n\t\tgiven(cleaner.register(any(), action.capture())).willReturn(cleanable);\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, null, null, false, cleaner)) {\n\t\t\tObject channel = Extractors.byName(\"resources.zipContent.data.fileAccess\").apply(jar);\n\t\t\tassertThat(channel).extracting(\"referenceCount\").isEqualTo(1);\n\t\t\taction.getValue().run();\n\t\t\tassertThat(channel).extracting(\"referenceCount\").isEqualTo(0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getInputStreamReturnsInputStream() throws IOException {\n\t\ttry (NestedJarFile jarFile = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jarFile.getJarEntry(\"2.dat\");\n\t\t\ttry (InputStream in = jarFile.getInputStream(entry)) {\n\t\t\t\tassertThat(in).hasBinaryContent(new byte[] { 0x02 });\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenIsDirectory() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\ttry (InputStream inputStream = jar.getInputStream(jar.getEntry(\"d/\"))) {\n\t\t\t\tassertThat(inputStream).isNotNull();\n\t\t\t\tassertThat(inputStream.read()).isEqualTo(-1);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenNameWithoutSlashAndIsDirectory() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\ttry (InputStream inputStream = jar.getInputStream(jar.getEntry(\"d\"))) {\n\t\t\t\tassertThat(inputStream).isNotNull();\n\t\t\t\tassertThat(inputStream.read()).isEqualTo(-1);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid verifySignedJar() throws Exception {\n\t\tFile signedJarFile = TestJar.getSigned();\n\t\tassertThat(signedJarFile).exists();\n\t\ttry (JarFile expected = new JarFile(signedJarFile)) {\n\t\t\ttry (NestedJarFile actual = new NestedJarFile(signedJarFile)) {\n\t\t\t\tStopWatch stopWatch = new StopWatch();\n\t\t\t\tEnumeration<JarEntry> actualEntries = actual.entries();\n\t\t\t\twhile (actualEntries.hasMoreElements()) {\n\t\t\t\t\tJarEntry actualEntry = actualEntries.nextElement();\n\t\t\t\t\tJarEntry expectedEntry = expected.getJarEntry(actualEntry.getName());\n\t\t\t\t\tStreamUtils.drain(expected.getInputStream(expectedEntry));\n\t\t\t\t\tif (!actualEntry.getName().equals(\"META-INF/MANIFEST.MF\")) {\n\t\t\t\t\t\tassertThat(actualEntry.getCertificates()).as(actualEntry.getName())\n\t\t\t\t\t\t\t.isEqualTo(expectedEntry.getCertificates());\n\t\t\t\t\t\tassertThat(actualEntry.getCodeSigners()).as(actualEntry.getName())\n\t\t\t\t\t\t\t.isEqualTo(expectedEntry.getCodeSigners());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tassertThat(stopWatch.getTotalTimeSeconds()).isLessThan(3.0);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid closeAllowsFileToBeDeleted() throws Exception {\n\t\tnew NestedJarFile(this.file).close();\n\t\tassertThat(this.file.delete()).isTrue();\n\t}\n\n\t@Test\n\tvoid streamStreamsEntries() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"multi-release.jar\")) {\n\t\t\tassertThat(jar.stream().map((entry) -> entry.getName() + \":\" + entry.getRealName())).containsExactly(\n\t\t\t\t\t\"META-INF/:META-INF/\", \"META-INF/MANIFEST.MF:META-INF/MANIFEST.MF\",\n\t\t\t\t\t\"multi-release.dat:multi-release.dat\",\n\t\t\t\t\t\"META-INF/versions/%1$d/multi-release.dat:META-INF/versions/%1$d/multi-release.dat\"\n\t\t\t\t\t\t.formatted(TestJar.MULTI_JAR_VERSION));\n\t\t}\n\t}\n\n\t@Test\n\tvoid versionedStreamStreamsEntries() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file, \"multi-release.jar\", Runtime.version())) {\n\t\t\tassertThat(jar.versionedStream().map((entry) -> entry.getName() + \":\" + entry.getRealName()))\n\t\t\t\t.containsExactly(\"META-INF/:META-INF/\", \"META-INF/MANIFEST.MF:META-INF/MANIFEST.MF\",\n\t\t\t\t\t\t\"multi-release.dat:META-INF/versions/%1$d/multi-release.dat\"\n\t\t\t\t\t\t\t.formatted(TestJar.MULTI_JAR_VERSION));\n\t\t}\n\t}\n\n\t@Test // gh-39166\n\tvoid getCommentAlignsWithJdkJar() throws Exception {\n\t\tFile file = new File(this.tempDir, \"testcomments.jar\");\n\t\ttry (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {\n\t\t\tjar.putNextEntry(new ZipEntry(\"BOOT-INF/\"));\n\t\t\tjar.closeEntry();\n\t\t\tjar.putNextEntry(new ZipEntry(\"BOOT-INF/classes/\"));\n\t\t\tjar.closeEntry();\n\t\t\tfor (int i = 0; i < 5; i++) {\n\t\t\t\tZipEntry entry = new ZipEntry(\"BOOT-INF/classes/T\" + i + \".class\");\n\t\t\t\tentry.setComment(\"T\" + i);\n\t\t\t\tjar.putNextEntry(entry);\n\t\t\t\tjar.write(UUID.randomUUID().toString().getBytes());\n\t\t\t\tjar.closeEntry();\n\t\t\t}\n\t\t}\n\t\tList<String> jdk = collectComments(new JarFile(file));\n\t\tList<String> nested = collectComments(new NestedJarFile(file, \"BOOT-INF/classes/\"));\n\t\tassertThat(nested).isEqualTo(jdk);\n\t}\n\n\t@Test\n\tvoid mismatchedStreamEntriesThrowsException() throws IOException {\n\t\tFile mismatchJar = new File(\"src/test/resources/jars/mismatch.jar\");\n\t\tIllegalStateException failure = null;\n\t\ttry (NestedJarFile innerJar = new NestedJarFile(mismatchJar, \"inner.jar\")) {\n\t\t\tEnumeration<JarEntry> entries = innerJar.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\ttry {\n\t\t\t\t\tentries.nextElement().getCodeSigners();\n\t\t\t\t}\n\t\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\t\tfailure = (failure != null) ? failure : ex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tassertThat(failure)\n\t\t\t.hasMessage(\"Content mismatch when reading security info for entry 'content' (content check)\");\n\t}\n\n\t@Test\n\tvoid readingToEndOfStoredContentCausesAvailableToReachZero() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jar.getEntry(\"nested.jar\");\n\t\t\ttry (InputStream input = jar.getInputStream(entry)) {\n\t\t\t\tassertThat(input.available()).isGreaterThan(0);\n\t\t\t\tStreamUtils.copyToByteArray(input);\n\t\t\t\tassertThat(input.available()).isZero();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid readingToEndOfDeflatedContentCausesAvailableToReachZero() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jar.getEntry(\"d/9.dat\");\n\t\t\ttry (InputStream input = jar.getInputStream(entry)) {\n\t\t\t\tassertThat(input.available()).isGreaterThan(0);\n\t\t\t\tStreamUtils.copyToByteArray(input);\n\t\t\t\tassertThat(input.available()).isZero();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid skippingBeyondEndOfStoredContentCausesAvailableToReachZero() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jar.getEntry(\"nested.jar\");\n\t\t\ttry (InputStream input = jar.getInputStream(entry)) {\n\t\t\t\tassertThat(input.available()).isGreaterThan(0);\n\t\t\t\tlong skipped = input.skip(1000);\n\t\t\t\tassertThat(skipped).isLessThan(1000);\n\t\t\t\tassertThat(input.available()).isZero();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid skippingBeyondEndOfDeflatedContentCausesAvailableToReachZero() throws IOException {\n\t\ttry (NestedJarFile jar = new NestedJarFile(this.file)) {\n\t\t\tJarEntry entry = jar.getEntry(\"d/9.dat\");\n\t\t\ttry (InputStream input = jar.getInputStream(entry)) {\n\t\t\t\tassertThat(input.available()).isGreaterThan(0);\n\t\t\t\tlong skipped = input.skip(1000);\n\t\t\t\tassertThat(skipped).isLessThan(1000);\n\t\t\t\tassertThat(input.available()).isZero();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate List<String> collectComments(JarFile jarFile) throws IOException {\n\t\ttry (jarFile) {\n\t\t\tList<String> comments = new ArrayList<>();\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tString comment = entries.nextElement().getComment();\n\t\t\t\tif (comment != null) {\n\t\t\t\t\tcomments.add(comment);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn comments;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/SecurityInfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jar;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.loader.zip.ZipContent;\nimport org.springframework.boot.loader.zip.ZipContent.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SecurityInfo}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass SecurityInfoTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid getWhenNoSignatureFileReturnsNone() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\ttry (ZipContent content = ZipContent.open(file.toPath())) {\n\t\t\tSecurityInfo info = SecurityInfo.get(content);\n\t\t\tassertThat(info).isSameAs(SecurityInfo.NONE);\n\t\t\tfor (int i = 0; i < content.size(); i++) {\n\t\t\t\tEntry entry = content.getEntry(i);\n\t\t\t\tassertThat(info.getCertificates(entry)).isNull();\n\t\t\t\tassertThat(info.getCodeSigners(entry)).isNull();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getWhenHasSignatureFileButNoSecurityMaterialReturnsNone() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file, false, true);\n\t\ttry (ZipContent content = ZipContent.open(file.toPath())) {\n\t\t\tassertThat(content.hasJarSignatureFile()).isTrue();\n\t\t\tSecurityInfo info = SecurityInfo.get(content);\n\t\t\tassertThat(info).isSameAs(SecurityInfo.NONE);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getWhenJarIsSigned() throws Exception {\n\t\tFile file = TestJar.getSigned();\n\t\ttry (ZipContent content = ZipContent.open(file.toPath())) {\n\t\t\tassertThat(content.hasJarSignatureFile()).isTrue();\n\t\t\tSecurityInfo info = SecurityInfo.get(content);\n\t\t\tfor (int i = 0; i < content.size(); i++) {\n\t\t\t\tEntry entry = content.getEntry(i);\n\t\t\t\tif (entry.getName().endsWith(\".class\")) {\n\t\t\t\t\tassertThat(info.getCertificates(entry)).isNotNull();\n\t\t\t\t\tassertThat(info.getCodeSigners(entry)).isNotNull();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/jarmode/TestJarMode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.jarmode;\n\nimport java.util.Arrays;\n\n/**\n * {@link JarMode} for testing.\n *\n * @author Phillip Webb\n */\nclass TestJarMode implements JarMode {\n\n\t@Override\n\tpublic boolean accepts(String mode) {\n\t\treturn \"test\".equals(mode);\n\t}\n\n\t@Override\n\tpublic void run(String mode, String[] args) {\n\t\tSystem.out.println(\"running in \" + mode + \" jar mode \" + Arrays.asList(args));\n\t\tif (args.length > 0 && \"error\".equals(args[0])) {\n\t\t\tthrow new JarModeErrorException(\"error message\");\n\t\t}\n\t\tif (args.length > 0 && \"fail\".equals(args[0])) {\n\t\t\tthrow new IllegalStateException(\"bad\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/AbstractLauncherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.io.Writer;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.CRC32;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * Base class for testing {@link Launcher} implementations.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nabstract class AbstractLauncherTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprotected File createJarArchive(String name, String entryPrefix) throws IOException {\n\t\treturn createJarArchive(name, entryPrefix, false, Collections.emptyList());\n\t}\n\n\tprotected File createJarArchive(String name, String entryPrefix, boolean indexed, List<String> extraLibs)\n\t\t\tthrows IOException {\n\t\treturn createJarArchive(name, null, entryPrefix, indexed, extraLibs);\n\t}\n\n\tprotected File createJarArchive(String name, Manifest manifest, String entryPrefix, boolean indexed,\n\t\t\tList<String> extraLibs) throws IOException {\n\t\tFile archive = new File(this.tempDir, name);\n\t\tJarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(archive));\n\t\tif (manifest != null) {\n\t\t\tjarOutputStream.putNextEntry(new JarEntry(\"META-INF/\"));\n\t\t\tjarOutputStream.putNextEntry(new JarEntry(\"META-INF/MANIFEST.MF\"));\n\t\t\tmanifest.write(jarOutputStream);\n\t\t\tjarOutputStream.closeEntry();\n\t\t}\n\t\tjarOutputStream.putNextEntry(new JarEntry(entryPrefix + \"/\"));\n\t\tjarOutputStream.putNextEntry(new JarEntry(entryPrefix + \"/classes/\"));\n\t\tjarOutputStream.putNextEntry(new JarEntry(entryPrefix + \"/lib/\"));\n\t\tif (indexed) {\n\t\t\tjarOutputStream.putNextEntry(new JarEntry(entryPrefix + \"/classpath.idx\"));\n\t\t\tWriter writer = new OutputStreamWriter(jarOutputStream, StandardCharsets.UTF_8);\n\t\t\twriter.write(\"- \\\"\" + entryPrefix + \"/lib/foo.jar\\\"\\n\");\n\t\t\twriter.write(\"- \\\"\" + entryPrefix + \"/lib/bar.jar\\\"\\n\");\n\t\t\twriter.write(\"- \\\"\" + entryPrefix + \"/lib/baz.jar\\\"\\n\");\n\t\t\twriter.flush();\n\t\t\tjarOutputStream.closeEntry();\n\t\t}\n\t\taddNestedJars(entryPrefix, \"/lib/foo.jar\", jarOutputStream);\n\t\taddNestedJars(entryPrefix, \"/lib/bar.jar\", jarOutputStream);\n\t\taddNestedJars(entryPrefix, \"/lib/baz.jar\", jarOutputStream);\n\t\tfor (String lib : extraLibs) {\n\t\t\taddNestedJars(entryPrefix, \"/lib/\" + lib, jarOutputStream);\n\t\t}\n\t\tjarOutputStream.close();\n\t\treturn archive;\n\t}\n\n\tprivate void addNestedJars(String entryPrefix, String lib, JarOutputStream jarOutputStream) throws IOException {\n\t\tJarEntry libFoo = new JarEntry(entryPrefix + lib);\n\t\tlibFoo.setMethod(ZipEntry.STORED);\n\t\tByteArrayOutputStream fooJarStream = new ByteArrayOutputStream();\n\t\tnew JarOutputStream(fooJarStream).close();\n\t\tlibFoo.setSize(fooJarStream.size());\n\t\tCRC32 crc32 = new CRC32();\n\t\tcrc32.update(fooJarStream.toByteArray());\n\t\tlibFoo.setCrc(crc32.getValue());\n\t\tjarOutputStream.putNextEntry(libFoo);\n\t\tjarOutputStream.write(fooJarStream.toByteArray());\n\t}\n\n\tprotected File explode(File archive) throws IOException {\n\t\tFile exploded = new File(this.tempDir, \"exploded\");\n\t\texploded.mkdirs();\n\t\tJarFile jarFile = new JarFile(archive);\n\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\twhile (entries.hasMoreElements()) {\n\t\t\tJarEntry entry = entries.nextElement();\n\t\t\tFile entryFile = new File(exploded, entry.getName());\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tentryFile.mkdirs();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tFileCopyUtils.copy(jarFile.getInputStream(entry), new FileOutputStream(entryFile));\n\t\t\t}\n\t\t}\n\t\tjarFile.close();\n\t\treturn exploded;\n\t}\n\n\tprotected final URL toUrl(File file) {\n\t\ttry {\n\t\t\treturn file.toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprotected URLClassLoader createClassLoader(Launcher launcher) throws Exception {\n\t\treturn (URLClassLoader) launcher.createClassLoader(launcher.getClassPathUrls());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/ArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.function.Predicate;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.launch.Archive.Entry;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.CALLS_REAL_METHODS;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link Archive}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass ArchiveTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid getClassPathUrlsWithOnlyIncludeFilterSearchesAllDirectories() throws Exception {\n\t\tArchive archive = mock(Archive.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));\n\t\tPredicate<Entry> includeFilter = (entry) -> false;\n\t\tarchive.getClassPathUrls(includeFilter);\n\t\tthen(archive).should().getClassPathUrls(includeFilter, Archive.ALL_ENTRIES);\n\t}\n\n\t@Test\n\tvoid isExplodedWhenHasRootDirectoryReturnsTrue() {\n\t\tArchive archive = mock(Archive.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));\n\t\tgiven(archive.getRootDirectory()).willReturn(this.temp);\n\t\tassertThat(archive.isExploded()).isTrue();\n\t}\n\n\t@Test\n\tvoid isExplodedWhenHasNoRootDirectoryReturnsFalse() {\n\t\tArchive archive = mock(Archive.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));\n\t\tgiven(archive.getRootDirectory()).willReturn(null);\n\t\tassertThat(archive.isExploded()).isFalse();\n\t}\n\n\t@Test\n\tvoid createFromProtectionDomainCreatesJarArchive() throws Exception {\n\t\tFile jarFile = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(jarFile);\n\t\tProtectionDomain protectionDomain = mock(ProtectionDomain.class);\n\t\tCodeSource codeSource = mock(CodeSource.class);\n\t\tgiven(protectionDomain.getCodeSource()).willReturn(codeSource);\n\t\tgiven(codeSource.getLocation()).willReturn(jarFile.toURI().toURL());\n\t\ttry (Archive archive = Archive.create(protectionDomain)) {\n\t\t\tassertThat(archive).isInstanceOf(JarFileArchive.class);\n\t\t}\n\t}\n\n\t@Test\n\tvoid createFromProtectionDomainWhenNoLocationThrowsException() throws Exception {\n\t\tFile jarFile = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(jarFile);\n\t\tProtectionDomain protectionDomain = mock(ProtectionDomain.class);\n\t\tassertThatIllegalStateException().isThrownBy(() -> Archive.create(protectionDomain))\n\t\t\t.withMessage(\"Unable to determine code source archive\");\n\t}\n\n\t@Test\n\tvoid createFromFileWhenFileDoesNotExistThrowsException() {\n\t\tFile target = new File(this.temp, \"missing\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> Archive.create(target))\n\t\t\t.withMessageContaining(\"Unable to determine code source archive\");\n\t}\n\n\t@Test\n\tvoid createFromFileWhenJarFileReturnsJarFileArchive() throws Exception {\n\t\tFile target = new File(this.temp, \"missing\");\n\t\tTestJar.create(target);\n\t\ttry (Archive archive = Archive.create(target)) {\n\t\t\tassertThat(archive).isInstanceOf(JarFileArchive.class);\n\t\t}\n\t}\n\n\t@Test\n\tvoid createFromFileWhenDirectoryReturnsExplodedFileArchive() throws Exception {\n\t\tFile target = this.temp;\n\t\ttry (Archive archive = Archive.create(target)) {\n\t\t\tassertThat(archive).isInstanceOf(ExplodedArchive.class);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/ClassPathIndexFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ClassPathIndexFile}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ClassPathIndexFileTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid loadIfPossibleWhenRootDoesNotExistReturnsNull() throws Exception {\n\t\tFile root = new File(this.temp, \"missing\");\n\t\tassertThat(ClassPathIndexFile.loadIfPossible(root, \"test.idx\")).isNull();\n\t}\n\n\t@Test\n\tvoid loadIfPossibleWhenRootIsDirectoryThrowsException() throws Exception {\n\t\tFile root = new File(this.temp, \"directory\");\n\t\troot.mkdirs();\n\t\tassertThat(ClassPathIndexFile.loadIfPossible(root, \"test.idx\")).isNull();\n\t}\n\n\t@Test\n\tvoid loadIfPossibleReturnsInstance() throws Exception {\n\t\tClassPathIndexFile indexFile = copyAndLoadTestIndexFile();\n\t\tassertThat(indexFile).isNotNull();\n\t}\n\n\t@Test\n\tvoid sizeReturnsNumberOfLines() throws Exception {\n\t\tClassPathIndexFile indexFile = copyAndLoadTestIndexFile();\n\t\tassertThat(indexFile.size()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid getUrlsReturnsUrls() throws Exception {\n\t\tClassPathIndexFile indexFile = copyAndLoadTestIndexFile();\n\t\tList<URL> urls = indexFile.getUrls();\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(this.temp, \"BOOT-INF/layers/one/lib/a.jar\"));\n\t\texpected.add(new File(this.temp, \"BOOT-INF/layers/one/lib/b.jar\"));\n\t\texpected.add(new File(this.temp, \"BOOT-INF/layers/one/lib/c.jar\"));\n\t\texpected.add(new File(this.temp, \"BOOT-INF/layers/two/lib/d.jar\"));\n\t\texpected.add(new File(this.temp, \"BOOT-INF/layers/two/lib/e.jar\"));\n\t\tassertThat(urls).containsExactly(expected.stream().map(this::toUrl).toArray(URL[]::new));\n\t}\n\n\tprivate URL toUrl(File file) {\n\t\ttry {\n\t\t\treturn file.toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate ClassPathIndexFile copyAndLoadTestIndexFile() throws IOException {\n\t\tcopyTestIndexFile();\n\t\tClassPathIndexFile indexFile = ClassPathIndexFile.loadIfPossible(this.temp, \"test.idx\");\n\t\treturn indexFile;\n\t}\n\n\tprivate void copyTestIndexFile() throws IOException {\n\t\tFiles.copy(getClass().getResourceAsStream(\"classpath-index-file.idx\"),\n\t\t\t\tnew File(this.temp, \"test.idx\").toPath());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/ExplodedArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.Enumeration;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.launch.Archive.Entry;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ExplodedArchive}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n */\n@AssertFileChannelDataBlocksClosed\nclass ExplodedArchiveTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprivate File rootDirectory;\n\n\tprivate ExplodedArchive archive;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tcreateArchive();\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws Exception {\n\t\tif (this.archive != null) {\n\t\t\tthis.archive.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid isExplodedReturnsTrue() {\n\t\tassertThat(this.archive.isExploded()).isTrue();\n\t}\n\n\t@Test\n\tvoid getRootDirectoryReturnsRootDirectory() {\n\t\tassertThat(this.archive.getRootDirectory()).isEqualTo(this.rootDirectory);\n\t}\n\n\t@Test\n\tvoid getManifestReturnsManifest() throws Exception {\n\t\tassertThat(this.archive.getManifest().getMainAttributes().getValue(\"Built-By\")).isEqualTo(\"j1\");\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenNoPredicatesReturnsUrls() throws Exception {\n\t\tSet<URL> urls = this.archive.getClassPathUrls(Archive.ALL_ENTRIES);\n\t\tURL[] expectedUrls = TestJar.expectedEntries().stream().map(this::toUrl).toArray(URL[]::new);\n\t\tassertThat(urls).containsExactlyInAnyOrder(expectedUrls);\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasIncludeFilterReturnsUrls() throws Exception {\n\t\tSet<URL> urls = this.archive.getClassPathUrls(this::entryNameIsNestedJar);\n\t\tassertThat(urls).containsOnly(toUrl(\"nested.jar\"));\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasIncludeFilterAndSpaceInRootNameReturnsUrls() throws Exception {\n\t\tcreateArchive(\"spaces in the name\");\n\t\tSet<URL> urls = this.archive.getClassPathUrls(this::entryNameIsNestedJar);\n\t\tassertThat(urls).containsOnly(toUrl(\"nested.jar\"));\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasSearchFilterReturnsUrls() throws Exception {\n\t\tSet<URL> urls = this.archive.getClassPathUrls(Archive.ALL_ENTRIES, (entry) -> !entry.name().equals(\"d/\"));\n\t\tassertThat(urls).contains(toUrl(\"nested.jar\")).doesNotContain(toUrl(\"d/9.dat\"));\n\t}\n\n\tprivate void createArchive() throws Exception {\n\t\tcreateArchive(null);\n\t}\n\n\tprivate void createArchive(String directoryName) throws Exception {\n\t\tFile file = new File(this.tempDir, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tthis.rootDirectory = (StringUtils.hasText(directoryName) ? new File(this.tempDir, directoryName)\n\t\t\t\t: new File(this.tempDir, UUID.randomUUID().toString()));\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tJarEntry entry = entries.nextElement();\n\t\t\t\tFile destination = new File(this.rootDirectory, entry.getName());\n\t\t\t\tdestination.getParentFile().mkdirs();\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tdestination.mkdir();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttry (InputStream in = jarFile.getInputStream(entry);\n\t\t\t\t\t\t\tOutputStream out = new FileOutputStream(destination)) {\n\t\t\t\t\t\tin.transferTo(out);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.archive = new ExplodedArchive(this.rootDirectory);\n\t\t}\n\t}\n\n\tprivate URL toUrl(String name) {\n\t\treturn toUrl(new File(this.rootDirectory, name));\n\t}\n\n\tprivate URL toUrl(File file) {\n\t\ttry {\n\t\t\treturn file.toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate boolean entryNameIsNestedJar(Entry entry) {\n\t\treturn entry.name().equals(\"nested.jar\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/JarFileArchiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Set;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.launch.Archive.Entry;\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JarFileArchive}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Camille Vienot\n */\n@AssertFileChannelDataBlocksClosed\nclass JarFileArchiveTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprivate File file;\n\n\tprivate JarFileArchive archive;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tcreateTestJarArchive(false);\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws Exception {\n\t\tthis.archive.close();\n\t}\n\n\t@Test\n\tvoid isExplodedReturnsFalse() {\n\t\tassertThat(this.archive.isExploded()).isFalse();\n\t}\n\n\t@Test\n\tvoid getRootDirectoryReturnsNull() {\n\t\tassertThat(this.archive.getRootDirectory()).isNull();\n\t}\n\n\t@Test\n\tvoid getManifestReturnsManifest() throws Exception {\n\t\tassertThat(this.archive.getManifest().getMainAttributes().getValue(\"Built-By\")).isEqualTo(\"j1\");\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenNoPredicatesReturnsUrls() throws Exception {\n\t\tSet<URL> urls = this.archive.getClassPathUrls(Archive.ALL_ENTRIES);\n\t\tURL[] expected = TestJar.expectedEntries()\n\t\t\t.stream()\n\t\t\t.map((name) -> JarUrl.create(this.file, name))\n\t\t\t.toArray(URL[]::new);\n\t\tassertThat(urls).containsExactly(expected);\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasIncludeFilterReturnsUrls() throws Exception {\n\t\tSet<URL> urls = this.archive.getClassPathUrls(this::entryNameIsNestedJar);\n\t\tassertThat(urls).containsOnly(JarUrl.create(this.file, \"nested.jar\"));\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasSearchFilterAllUrlsSinceSearchFilterIsNotUsed() throws Exception {\n\t\tSet<URL> urls = this.archive.getClassPathUrls(Archive.ALL_ENTRIES, (entry) -> false);\n\t\tURL[] expected = TestJar.expectedEntries()\n\t\t\t.stream()\n\t\t\t.map((name) -> JarUrl.create(this.file, name))\n\t\t\t.toArray(URL[]::new);\n\t\tassertThat(urls).containsExactly(expected);\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasUnpackCommentUnpacksAndReturnsUrls() throws Exception {\n\t\tcreateTestJarArchive(true);\n\t\tSet<URL> urls = this.archive.getClassPathUrls(this::entryNameIsNestedJar);\n\t\tassertThat(urls).hasSize(1);\n\t\tURL url = urls.iterator().next();\n\t\tassertThat(url).isNotEqualTo(JarUrl.create(this.file, \"nested.jar\"));\n\t\t// The unpack URL must be a raw file URL (see gh-38833)\n\t\tassertThat(url.toString()).startsWith(\"file:\").endsWith(\"/nested.jar\");\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasUnpackCommentUnpacksToUniqueLocationsPerArchive() throws Exception {\n\t\tcreateTestJarArchive(true);\n\t\tURL firstNestedUrl = this.archive.getClassPathUrls(this::entryNameIsNestedJar).iterator().next();\n\t\tcreateTestJarArchive(true);\n\t\tURL secondNestedUrl = this.archive.getClassPathUrls(this::entryNameIsNestedJar).iterator().next();\n\t\tassertThat(secondNestedUrl).isNotEqualTo(firstNestedUrl);\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenHasUnpackCommentUnpacksAndShareSameParent() throws Exception {\n\t\tcreateTestJarArchive(true);\n\t\tURL nestedUrl = this.archive.getClassPathUrls(this::entryNameIsNestedJar).iterator().next();\n\t\tURL anotherNestedUrl = this.archive.getClassPathUrls((entry) -> entry.name().equals(\"another-nested.jar\"))\n\t\t\t.iterator()\n\t\t\t.next();\n\t\tassertThat(nestedUrl.toString())\n\t\t\t.isEqualTo(anotherNestedUrl.toString().replace(\"another-nested.jar\", \"nested.jar\"));\n\t}\n\n\t@Test\n\tvoid getClassPathUrlsWhenZip64ListsAllEntries() throws Exception {\n\t\tFile file = new File(this.tempDir, \"test.jar\");\n\t\tFileCopyUtils.copy(writeZip64Jar(), file);\n\t\ttry (Archive jarArchive = new JarFileArchive(file)) {\n\t\t\tSet<URL> urls = jarArchive.getClassPathUrls(Archive.ALL_ENTRIES);\n\t\t\tassertThat(urls).hasSize(65537);\n\t\t}\n\t}\n\n\tprivate byte[] writeZip64Jar() throws IOException {\n\t\tByteArrayOutputStream bytes = new ByteArrayOutputStream();\n\t\ttry (JarOutputStream jarOutput = new JarOutputStream(bytes)) {\n\t\t\tfor (int i = 0; i < 65537; i++) {\n\t\t\t\tjarOutput.putNextEntry(new JarEntry(i + \".dat\"));\n\t\t\t\tjarOutput.closeEntry();\n\t\t\t}\n\t\t}\n\t\treturn bytes.toByteArray();\n\t}\n\n\tprivate void createTestJarArchive(boolean unpackNested) throws Exception {\n\t\tif (this.archive != null) {\n\t\t\tthis.archive.close();\n\t\t}\n\t\tthis.file = new File(this.tempDir, \"root.jar\");\n\t\tTestJar.create(this.file, unpackNested);\n\t\tthis.archive = new JarFileArchive(this.file);\n\t}\n\n\tprivate boolean entryNameIsNestedJar(Entry entry) {\n\t\treturn entry.name().equals(\"nested.jar\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/JarLauncherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.jar.Attributes;\nimport java.util.jar.Attributes.Name;\nimport java.util.jar.Manifest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.test.tools.SourceFile;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JarLauncher}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass JarLauncherTests extends AbstractLauncherTests {\n\n\t@Test\n\tvoid explodedJarHasOnlyBootInfClassesAndContentsOfBootInfLibOnClasspath() throws Exception {\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.jar\", \"BOOT-INF\"));\n\t\tJarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot));\n\t\tSet<URL> urls = launcher.getClassPathUrls();\n\t\tassertThat(urls).containsExactlyInAnyOrder(getExpectedFileUrls(explodedRoot));\n\t}\n\n\t@Test\n\tvoid archivedJarHasOnlyBootInfClassesAndContentsOfBootInfLibOnClasspath() throws Exception {\n\t\tFile jarRoot = createJarArchive(\"archive.jar\", \"BOOT-INF\");\n\t\ttry (JarFileArchive archive = new JarFileArchive(jarRoot)) {\n\t\t\tJarLauncher launcher = new JarLauncher(archive);\n\t\t\tSet<URL> urls = launcher.getClassPathUrls();\n\t\t\tList<URL> expectedUrls = new ArrayList<>();\n\t\t\texpectedUrls.add(JarUrl.create(jarRoot, \"BOOT-INF/classes/\"));\n\t\t\texpectedUrls.add(JarUrl.create(jarRoot, \"BOOT-INF/lib/foo.jar\"));\n\t\t\texpectedUrls.add(JarUrl.create(jarRoot, \"BOOT-INF/lib/bar.jar\"));\n\t\t\texpectedUrls.add(JarUrl.create(jarRoot, \"BOOT-INF/lib/baz.jar\"));\n\t\t\tassertThat(urls).containsOnlyOnceElementsOf(expectedUrls);\n\t\t}\n\t}\n\n\t@Test\n\tvoid explodedJarShouldPreserveClasspathOrderWhenIndexPresent() throws Exception {\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.jar\", \"BOOT-INF\", true, Collections.emptyList()));\n\t\tJarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tassertThat(classLoader.getURLs()).containsExactly(getExpectedFileUrls(explodedRoot));\n\t}\n\n\t@Test\n\tvoid jarFilesPresentInBootInfLibsAndNotInClasspathIndexShouldBeAddedAfterBootInfClasses() throws Exception {\n\t\tArrayList<String> extraLibs = new ArrayList<>(Arrays.asList(\"extra-1.jar\", \"extra-2.jar\"));\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.jar\", \"BOOT-INF\", true, extraLibs));\n\t\tJarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tList<File> expectedFiles = getExpectedFilesWithExtraLibs(explodedRoot);\n\t\tURL[] expectedFileUrls = expectedFiles.stream().map(this::toUrl).toArray(URL[]::new);\n\t\tassertThat(classLoader.getURLs()).containsExactly(expectedFileUrls);\n\t}\n\n\t@Test\n\tvoid explodedJarDefinedPackagesIncludeManifestAttributes() {\n\t\tManifest manifest = new Manifest();\n\t\tAttributes attributes = manifest.getMainAttributes();\n\t\tattributes.put(Name.MANIFEST_VERSION, \"1.0\");\n\t\tattributes.put(Name.IMPLEMENTATION_TITLE, \"test\");\n\t\tSourceFile sourceFile = SourceFile.of(\"explodedsample/ExampleClass.java\",\n\t\t\t\tnew ClassPathResource(\"explodedsample/ExampleClass.txt\"));\n\t\tTestCompiler.forSystem().compile(sourceFile, ThrowingConsumer.of((compiled) -> {\n\t\t\tFile explodedRoot = explode(\n\t\t\t\t\tcreateJarArchive(\"archive.jar\", manifest, \"BOOT-INF\", true, Collections.emptyList()));\n\t\t\tFile target = new File(explodedRoot, \"BOOT-INF/classes/explodedsample/ExampleClass.class\");\n\t\t\ttarget.getParentFile().mkdirs();\n\t\t\tFileCopyUtils.copy(compiled.getClassLoader().getResourceAsStream(\"explodedsample/ExampleClass.class\"),\n\t\t\t\t\tnew FileOutputStream(target));\n\t\t\tJarLauncher launcher = new JarLauncher(new ExplodedArchive(explodedRoot));\n\t\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\t\tClass<?> loaded = classLoader.loadClass(\"explodedsample.ExampleClass\");\n\t\t\tassertThat(loaded.getPackage().getImplementationTitle()).isEqualTo(\"test\");\n\t\t}));\n\t}\n\n\tprivate URL[] getExpectedFileUrls(File explodedRoot) {\n\t\treturn getExpectedFiles(explodedRoot).stream().map(this::toUrl).toArray(URL[]::new);\n\t}\n\n\tprivate List<File> getExpectedFiles(File parent) {\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(parent, \"BOOT-INF/classes\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/foo.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/bar.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/baz.jar\"));\n\t\treturn expected;\n\t}\n\n\tprivate List<File> getExpectedFilesWithExtraLibs(File parent) {\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(parent, \"BOOT-INF/classes\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/extra-1.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/extra-2.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/foo.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/bar.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/baz.jar\"));\n\t\treturn expected;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/LaunchedClassLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.net.URL;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.jarmode.JarMode;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LaunchedClassLoader}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@AssertFileChannelDataBlocksClosed\nclass LaunchedClassLoaderTests {\n\n\t@Test\n\tvoid loadClassWhenJarModeClassLoadsInLaunchedClassLoader() throws Exception {\n\t\ttry (LaunchedClassLoader classLoader = new LaunchedClassLoader(false, new URL[] {},\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\tClass<?> jarModeClass = classLoader.loadClass(JarMode.class.getName());\n\t\t\tClass<?> jarModeRunnerClass = classLoader.loadClass(JarModeRunner.class.getName());\n\t\t\tassertThat(jarModeClass.getClassLoader()).isSameAs(classLoader);\n\t\t\tassertThat(jarModeRunnerClass.getClassLoader()).isSameAs(classLoader);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/LauncherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Launcher}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\n@AssertFileChannelDataBlocksClosed\nclass LauncherTests {\n\n\t/**\n\t * Main method tests.\n\t *\n\t */\n\t@Nested\n\t@ExtendWith(OutputCaptureExtension.class)\n\tclass MainMethod {\n\n\t\t@Test\n\t\tvoid publicMainMethod(CapturedOutput output) throws Exception {\n\t\t\tnew MainMethodTestLauncher(PublicMainMethod.class).launch(new String[0]);\n\t\t\tassertThat(output).contains(\"Launched public static void main(String[] args)\");\n\t\t}\n\n\t\t@Test\n\t\tvoid packagePrivateMainMethod(CapturedOutput output) throws Exception {\n\t\t\tnew MainMethodTestLauncher(PackagePrivateMainMethod.class).launch(new String[0]);\n\t\t\tassertThat(output).contains(\"Launched static void main(String[] args)\");\n\t\t}\n\n\t\t@Test\n\t\tvoid publicParameterlessMainMethod(CapturedOutput output) throws Exception {\n\t\t\tnew MainMethodTestLauncher(PublicParameterlessMainMethod.class).launch(new String[0]);\n\t\t\tassertThat(output).contains(\"Launched public static void main()\");\n\t\t}\n\n\t\t@Test\n\t\tvoid packagePrivateParameterlessMainMethod(CapturedOutput output) throws Exception {\n\t\t\tnew MainMethodTestLauncher(PackagePrivateParameterlessMainMethod.class).launch(new String[0]);\n\t\t\tassertThat(output).contains(\"Launched static void main()\");\n\t\t}\n\n\t\t@Test\n\t\tvoid prefersSingleParameterMainMethod(CapturedOutput output) throws Exception {\n\t\t\tnew MainMethodTestLauncher(MultipleMainMethods.class).launch(new String[0]);\n\t\t\tassertThat(output).contains(\"Launched static void main(String[] args)\");\n\t\t}\n\n\t\tstatic class MainMethodTestLauncher extends Launcher {\n\n\t\t\tprivate final Class<?> mainClass;\n\n\t\t\tMainMethodTestLauncher(Class<?> mainClass) {\n\t\t\t\tthis.mainClass = mainClass;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected Archive getArchive() {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected String getMainClass() throws Exception {\n\t\t\t\treturn this.mainClass.getName();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected Set<URL> getClassPathUrls() throws Exception {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class PublicMainMethod {\n\n\t\t\tpublic static void main(String[] args) {\n\t\t\t\tSystem.out.println(\"Launched public static void main(String[] args)\");\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class PackagePrivateMainMethod {\n\n\t\t\tpublic static void main(String[] args) {\n\t\t\t\tSystem.out.println(\"Launched static void main(String[] args)\");\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class PublicParameterlessMainMethod {\n\n\t\t\tpublic static void main() {\n\t\t\t\tSystem.out.println(\"Launched public static void main()\");\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class PackagePrivateParameterlessMainMethod {\n\n\t\t\tstatic void main() {\n\t\t\t\tSystem.out.println(\"Launched static void main()\");\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class MultipleMainMethods {\n\n\t\t\tstatic void main(String[] args) {\n\t\t\t\tSystem.out.println(\"Launched static void main(String[] args)\");\n\t\t\t}\n\n\t\t\tstatic void main() {\n\t\t\t\tSystem.out.println(\"Launched static void main()\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Jar Mode tests.\n\t */\n\t@Nested\n\tclass JarMode {\n\n\t\t@BeforeEach\n\t\tvoid setup() {\n\t\t\tSystem.setProperty(JarModeRunner.DISABLE_SYSTEM_EXIT, \"true\");\n\t\t}\n\n\t\t@AfterEach\n\t\tvoid cleanup() {\n\t\t\tSystem.clearProperty(\"jarmode\");\n\t\t\tSystem.clearProperty(JarModeRunner.DISABLE_SYSTEM_EXIT);\n\t\t}\n\n\t\t@Test\n\t\tvoid launchWhenJarModePropertyIsSetLaunchesJarMode(CapturedOutput out) throws Exception {\n\t\t\tSystem.setProperty(\"jarmode\", \"test\");\n\t\t\tnew JarModeTestLauncher().launch(new String[] { \"boot\" });\n\t\t\tassertThat(out).contains(\"running in test jar mode [boot]\");\n\t\t\tassertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo(\"0\");\n\t\t}\n\n\t\t@Test\n\t\tvoid launchWhenJarModePropertyIsNotAcceptedThrowsException(CapturedOutput out) throws Exception {\n\t\t\tSystem.setProperty(\"jarmode\", \"idontexist\");\n\t\t\tnew JarModeTestLauncher().launch(new String[] { \"boot\" });\n\t\t\tassertThat(out).contains(\"Unsupported jarmode 'idontexist'\");\n\t\t\tassertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo(\"1\");\n\t\t}\n\n\t\t@Test\n\t\tvoid launchWhenJarModeRunFailsWithErrorExceptionPrintsSimpleMessage(CapturedOutput out) throws Exception {\n\t\t\tSystem.setProperty(\"jarmode\", \"test\");\n\t\t\tnew JarModeTestLauncher().launch(new String[] { \"error\" });\n\t\t\tassertThat(out).contains(\"running in test jar mode [error]\");\n\t\t\tassertThat(out).contains(\"Error: error message\");\n\t\t\tassertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo(\"1\");\n\t\t}\n\n\t\t@Test\n\t\tvoid launchWhenJarModeRunFailsWithErrorExceptionPrintsStackTrace(CapturedOutput out) throws Exception {\n\t\t\tSystem.setProperty(\"jarmode\", \"test\");\n\t\t\tnew JarModeTestLauncher().launch(new String[] { \"fail\" });\n\t\t\tassertThat(out).contains(\"running in test jar mode [fail]\");\n\t\t\tassertThat(out).contains(\"java.lang.IllegalStateException: bad\");\n\t\t\tassertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo(\"1\");\n\t\t}\n\n\t\tprivate static final class JarModeTestLauncher extends Launcher {\n\n\t\t\t@Override\n\t\t\tprotected String getMainClass() throws Exception {\n\t\t\t\tthrow new IllegalStateException(\"Should not be called\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected Archive getArchive() {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected Set<URL> getClassPathUrls() throws Exception {\n\t\t\t\treturn Collections.emptySet();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected void launch(String[] args) throws Exception {\n\t\t\t\tsuper.launch(args);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/PropertiesLauncherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.assertj.core.api.Condition;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.hamcrest.Matchers.containsString;\n\n/**\n * Tests for {@link PropertiesLauncher}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@ExtendWith(OutputCaptureExtension.class)\n@AssertFileChannelDataBlocksClosed\nclass PropertiesLauncherTests extends AbstractLauncherTests {\n\n\tprivate PropertiesLauncher launcher;\n\n\tprivate ClassLoader contextClassLoader;\n\n\tprivate CapturedOutput output;\n\n\t@BeforeEach\n\tvoid setup(CapturedOutput capturedOutput) {\n\t\tthis.contextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tSystem.setProperty(\"loader.home\", new File(\"src/test/resources\").getAbsolutePath());\n\t\tthis.output = capturedOutput;\n\t}\n\n\t@AfterEach\n\tvoid close() throws Exception {\n\t\tThread.currentThread().setContextClassLoader(this.contextClassLoader);\n\t\tSystem.clearProperty(\"loader.home\");\n\t\tSystem.clearProperty(\"loader.path\");\n\t\tSystem.clearProperty(\"loader.main\");\n\t\tSystem.clearProperty(\"loader.config.name\");\n\t\tSystem.clearProperty(\"loader.config.location\");\n\t\tSystem.clearProperty(\"loader.system\");\n\t\tSystem.clearProperty(\"loader.classLoader\");\n\t\tif (this.launcher != null) {\n\t\t\tthis.launcher.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultHome() throws Exception {\n\t\tSystem.clearProperty(\"loader.home\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getHomeDirectory()).isEqualTo(new File(System.getProperty(\"user.dir\")));\n\t}\n\n\t@Test\n\tvoid testAlternateHome() throws Exception {\n\t\tSystem.setProperty(\"loader.home\", \"src/test/resources/home\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getHomeDirectory()).isEqualTo(new File(System.getProperty(\"loader.home\")));\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"demo.HomeApplication\");\n\t}\n\n\t@Test\n\tvoid testNonExistentHome() {\n\t\tSystem.setProperty(\"loader.home\", \"src/test/resources/nonexistent\");\n\t\tassertThatIllegalArgumentException().isThrownBy(PropertiesLauncher::new)\n\t\t\t.withMessageContaining(\"Invalid source directory\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedMain() throws Exception {\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"demo.Application\");\n\t\tassertThat(System.getProperty(\"loader.main\")).isNull();\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedConfigName() throws Exception {\n\t\tSystem.setProperty(\"loader.config.name\", \"foo\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"my.Application\");\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[etc/]\");\n\t}\n\n\t@Test\n\tvoid testRootOfClasspathFirst() throws Exception {\n\t\tSystem.setProperty(\"loader.config.name\", \"bar\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"my.BarApplication\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedDotPath() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \".\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[.]\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedSlashPath() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"jars/\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[jars/]\");\n\t\tSet<URL> urls = this.launcher.getClassPathUrls();\n\t\tassertThat(urls).areExactly(1, endingWith(\"app.jar\"));\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedWildcardPath() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"jars/*\");\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[jars/]\");\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedJarPath() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"jars/app.jar\");\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[jars/app.jar]\");\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedRootOfJarPath() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"jar:file:./src/test/resources/nested-jars/app.jar!/\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\"))\n\t\t\t.hasToString(\"[jar:file:./src/test/resources/nested-jars/app.jar!/]\");\n\t\tSet<URL> urls = this.launcher.getClassPathUrls();\n\t\tassertThat(urls).areExactly(1, endingWith(\"foo.jar!/\"));\n\t\tassertThat(urls).areExactly(1, endingWith(\"app.jar!/\"));\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedRootOfJarPathWithDot() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"nested-jars/app.jar!/./\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tSet<URL> urls = this.launcher.getClassPathUrls();\n\t\tassertThat(urls).areExactly(1, endingWith(\"foo.jar!/\"));\n\t\tassertThat(urls).areExactly(1, endingWith(\"app.jar!/\"));\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedRootOfJarPathWithDotAndJarPrefix() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"jar:file:./src/test/resources/nested-jars/app.jar!/./\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tSet<URL> urls = this.launcher.getClassPathUrls();\n\t\tassertThat(urls).areExactly(1, endingWith(\"foo.jar!/\"));\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedJarFileWithNestedArchives() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"nested-jars/app.jar\");\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tSet<URL> urls = this.launcher.getClassPathUrls();\n\t\tassertThat(urls).areExactly(1, endingWith(\"foo.jar!/\"));\n\t\tassertThat(urls).areExactly(1, endingWith(\"app.jar\"));\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedNestedJarPath() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"nested-jars/nested-jar-app.jar!/BOOT-INF/classes/\");\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\"))\n\t\t\t.hasToString(\"[nested-jars/nested-jar-app.jar!/BOOT-INF/classes/]\");\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedDirectoryContainingJarFileWithNestedArchives() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"nested-jars\");\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedJarPathWithDot() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"./jars/app.jar\");\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[jars/app.jar]\");\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedClassLoader() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"jars/app.jar\");\n\t\tSystem.setProperty(\"loader.classLoader\", URLClassLoader.class.getName());\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\")).hasToString(\"[jars/app.jar]\");\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedClassPathOrder() throws Exception {\n\t\tSystem.setProperty(\"loader.path\", \"more-jars/app.jar,jars/app.jar\");\n\t\tSystem.setProperty(\"loader.classLoader\", URLClassLoader.class.getName());\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(ReflectionTestUtils.getField(this.launcher, \"paths\"))\n\t\t\t.hasToString(\"[more-jars/app.jar, jars/app.jar]\");\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello Other World\");\n\t}\n\n\t@Test\n\tvoid testCustomClassLoaderCreation() throws Exception {\n\t\tSystem.setProperty(\"loader.classLoader\", TestLoader.class.getName());\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tClassLoader loader = this.launcher.createClassLoader(classPathUrls());\n\t\tassertThat(loader).isNotNull();\n\t\tassertThat(loader.getClass().getName()).isEqualTo(TestLoader.class.getName());\n\t}\n\n\tprivate Set<URL> classPathUrls() throws Exception {\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tString classPath = System.getProperty(\"java.class.path\");\n\t\tfor (String path : classPath.split(File.pathSeparator)) {\n\t\t\tFile file = new FileSystemResource(path).getFile();\n\t\t\tif (file.exists()) {\n\t\t\t\turls.add(file.toURI().toURL());\n\t\t\t}\n\t\t}\n\t\treturn urls;\n\t}\n\n\t@Test\n\tvoid testUserSpecifiedConfigPathWins() throws Exception {\n\t\tSystem.setProperty(\"loader.config.name\", \"foo\");\n\t\tSystem.setProperty(\"loader.config.location\", \"classpath:bar.properties\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"my.BarApplication\");\n\t}\n\n\t@Test\n\tvoid testSystemPropertySpecifiedMain() throws Exception {\n\t\tSystem.setProperty(\"loader.main\", \"foo.Bar\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"foo.Bar\");\n\t}\n\n\t@Test\n\tvoid testSystemPropertiesSet() throws Exception {\n\t\tSystem.setProperty(\"loader.system\", \"true\");\n\t\tnew PropertiesLauncher();\n\t\tassertThat(System.getProperty(\"loader.main\")).isEqualTo(\"demo.Application\");\n\t}\n\n\t@Test\n\tvoid testArgsEnhanced() throws Exception {\n\t\tSystem.setProperty(\"loader.args\", \"foo\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(Arrays.asList(this.launcher.getArgs(\"bar\"))).hasToString(\"[foo, bar]\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testLoadPathCustomizedUsingManifest() throws Exception {\n\t\tSystem.setProperty(\"loader.home\", this.tempDir.getAbsolutePath());\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\t\tmanifest.getMainAttributes().putValue(\"Loader-Path\", \"/foo.jar, /bar\");\n\t\tFile manifestFile = new File(this.tempDir, \"META-INF/MANIFEST.MF\");\n\t\tmanifestFile.getParentFile().mkdirs();\n\t\ttry (FileOutputStream manifestStream = new FileOutputStream(manifestFile)) {\n\t\t\tmanifest.write(manifestStream);\n\t\t}\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat((List<String>) ReflectionTestUtils.getField(this.launcher, \"paths\")).containsExactly(\"/foo.jar\",\n\t\t\t\t\"/bar/\");\n\t}\n\n\t@Test\n\tvoid testManifestWithPlaceholders() throws Exception {\n\t\tSystem.setProperty(\"loader.home\", \"src/test/resources/placeholders\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tassertThat(this.launcher.getMainClass()).isEqualTo(\"demo.FooApplication\");\n\t}\n\n\t@Test\n\tvoid encodedFileUrlLoaderPathIsHandledCorrectly() throws Exception {\n\t\tFile loaderPath = new File(this.tempDir, \"loader path\");\n\t\tloaderPath.mkdir();\n\t\tSystem.setProperty(\"loader.path\", loaderPath.toURI().toURL().toString());\n\t\tthis.launcher = new PropertiesLauncher();\n\t\tSet<URL> urls = this.launcher.getClassPathUrls();\n\t\tassertThat(urls).hasSize(1);\n\t\tassertThat(urls.iterator().next()).isEqualTo(loaderPath.toURI().toURL());\n\t}\n\n\t@Test // gh-21575\n\tvoid loadResourceFromJarFile() throws Exception {\n\t\tFile file = new File(this.tempDir, \"app.jar\");\n\t\tTestJar.create(file);\n\t\tSystem.setProperty(\"loader.home\", this.tempDir.getAbsolutePath());\n\t\tSystem.setProperty(\"loader.path\", \"app.jar\");\n\t\tthis.launcher = new PropertiesLauncher();\n\t\ttry {\n\t\t\tthis.launcher.launch(new String[0]);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Expected ClassNotFoundException\n\t\t\tLaunchedClassLoader classLoader = (LaunchedClassLoader) Thread.currentThread().getContextClassLoader();\n\t\t\tclassLoader.close();\n\t\t}\n\t\tURL resource = JarUrl.create(file, \"nested.jar\", \"3.dat\");\n\t\tbyte[] bytes = FileCopyUtils.copyToByteArray(resource.openStream());\n\t\tassertThat(bytes).isNotEmpty();\n\t}\n\n\t@Test // gh-37992\n\tvoid classPathWithoutLoaderPathDefaultsToJarLauncherIncludes() throws Exception {\n\t\tFile file = new File(this.tempDir, \"test.jar\");\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(file))) {\n\t\t\ttry (JarFile in = new JarFile(new File(\"src/test/resources/jars/app.jar\"))) {\n\t\t\t\tout.putNextEntry(new ZipEntry(\"BOOT-INF/\"));\n\t\t\t\tout.putNextEntry(new ZipEntry(\"BOOT-INF/classes/\"));\n\t\t\t\tout.putNextEntry(new ZipEntry(\"BOOT-INF/classes/demo/\"));\n\t\t\t\tout.putNextEntry(new ZipEntry(\"BOOT-INF/classes/demo/Application.class\"));\n\t\t\t\ttry (InputStream classIn = in.getInputStream(in.getEntry(\"demo/Application.class\"))) {\n\t\t\t\t\tclassIn.transferTo(out);\n\t\t\t\t}\n\t\t\t\tout.closeEntry();\n\t\t\t}\n\t\t}\n\t\tArchive archive = new JarFileArchive(file);\n\t\tSystem.setProperty(\"loader.main\", \"demo.Application\");\n\t\tthis.launcher = new PropertiesLauncher(archive);\n\t\tthis.launcher.launch(new String[0]);\n\t\twaitFor(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid explodedJarShouldPreserveClasspathOrderWhenIndexPresent() throws Exception {\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.jar\", \"BOOT-INF\", true, Collections.emptyList()));\n\t\tPropertiesLauncher launcher = new PropertiesLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tassertThat(classLoader.getURLs()).containsExactly(getExpectedFileUrls(explodedRoot));\n\t}\n\n\t@Test\n\tvoid customClassLoaderAndExplodedJarAndShouldPreserveClasspathOrderWhenIndexPresent() throws Exception {\n\t\tSystem.setProperty(\"loader.classLoader\", URLClassLoader.class.getName());\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.jar\", \"BOOT-INF\", true, Collections.emptyList()));\n\t\tPropertiesLauncher launcher = new PropertiesLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tassertThat(classLoader.getParent()).isInstanceOf(URLClassLoader.class);\n\t\tassertThat(((URLClassLoader) classLoader.getParent()).getURLs())\n\t\t\t.containsExactly(getExpectedFileUrls(explodedRoot));\n\t}\n\n\t@Test\n\tvoid jarFilesPresentInBootInfLibsAndNotInClasspathIndexShouldBeAddedAfterBootInfClasses() throws Exception {\n\t\tArrayList<String> extraLibs = new ArrayList<>(Arrays.asList(\"extra-1.jar\", \"extra-2.jar\"));\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.jar\", \"BOOT-INF\", true, extraLibs));\n\t\tPropertiesLauncher launcher = new PropertiesLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tList<File> expectedFiles = getExpectedFilesWithExtraLibs(explodedRoot);\n\t\tURL[] expectedFileUrls = expectedFiles.stream().map(this::toUrl).toArray(URL[]::new);\n\t\tassertThat(classLoader.getURLs()).containsExactly(expectedFileUrls);\n\t}\n\n\tprivate void waitFor(String value) {\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(5)).until(this.output::toString, containsString(value));\n\t}\n\n\tprivate URL[] getExpectedFileUrls(File explodedRoot) {\n\t\treturn getExpectedFiles(explodedRoot).stream().map(this::toUrl).toArray(URL[]::new);\n\t}\n\n\tprivate List<File> getExpectedFiles(File parent) {\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(parent, \"BOOT-INF/classes\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/foo.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/bar.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/baz.jar\"));\n\t\treturn expected;\n\t}\n\n\tprivate List<File> getExpectedFilesWithExtraLibs(File parent) {\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(parent, \"BOOT-INF/classes\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/extra-1.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/extra-2.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/foo.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/bar.jar\"));\n\t\texpected.add(new File(parent, \"BOOT-INF/lib/baz.jar\"));\n\t\treturn expected;\n\t}\n\n\tprivate Condition<URL> endingWith(String value) {\n\t\treturn new Condition<>() {\n\n\t\t\t@Override\n\t\t\tpublic boolean matches(URL archive) {\n\t\t\t\treturn archive.toString().endsWith(value);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tstatic class TestLoader extends URLClassLoader {\n\n\t\tTestLoader(ClassLoader parent) {\n\t\t\tsuper(new URL[0], parent);\n\t\t}\n\n\t\t@Override\n\t\tprotected Class<?> findClass(String name) throws ClassNotFoundException {\n\t\t\treturn super.findClass(name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/launch/WarLauncherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WarLauncher}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass WarLauncherTests extends AbstractLauncherTests {\n\n\t@Test\n\tvoid explodedWarHasOnlyWebInfClassesAndContentsOfWebInfLibOnClasspath() throws Exception {\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.war\", \"WEB-INF\"));\n\t\tWarLauncher launcher = new WarLauncher(new ExplodedArchive(explodedRoot));\n\t\tSet<URL> urls = launcher.getClassPathUrls();\n\t\tassertThat(urls).containsExactlyInAnyOrder(getExpectedFileUrls(explodedRoot));\n\t}\n\n\t@Test\n\tvoid archivedWarHasOnlyWebInfClassesAndContentsOfWebInfLibOnClasspath() throws Exception {\n\t\tFile file = createJarArchive(\"archive.war\", \"WEB-INF\");\n\t\ttry (JarFileArchive archive = new JarFileArchive(file)) {\n\t\t\tWarLauncher launcher = new WarLauncher(archive);\n\t\t\tSet<URL> urls = launcher.getClassPathUrls();\n\t\t\tList<URL> expected = new ArrayList<>();\n\t\t\texpected.add(JarUrl.create(file, \"WEB-INF/classes/\"));\n\t\t\texpected.add(JarUrl.create(file, \"WEB-INF/lib/foo.jar\"));\n\t\t\texpected.add(JarUrl.create(file, \"WEB-INF/lib/bar.jar\"));\n\t\t\texpected.add(JarUrl.create(file, \"WEB-INF/lib/baz.jar\"));\n\t\t\tassertThat(urls).containsOnly(expected.toArray(URL[]::new));\n\t\t}\n\t}\n\n\t@Test\n\tvoid explodedWarShouldPreserveClasspathOrderWhenIndexPresent() throws Exception {\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.war\", \"WEB-INF\", true, Collections.emptyList()));\n\t\tWarLauncher launcher = new WarLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tURL[] urls = classLoader.getURLs();\n\t\tassertThat(urls).containsExactly(getExpectedFileUrls(explodedRoot));\n\t}\n\n\t@Test\n\tvoid warFilesPresentInWebInfLibsAndNotInClasspathIndexShouldBeAddedAfterWebInfClasses() throws Exception {\n\t\tArrayList<String> extraLibs = new ArrayList<>(Arrays.asList(\"extra-1.jar\", \"extra-2.jar\"));\n\t\tFile explodedRoot = explode(createJarArchive(\"archive.war\", \"WEB-INF\", true, extraLibs));\n\t\tWarLauncher launcher = new WarLauncher(new ExplodedArchive(explodedRoot));\n\t\tURLClassLoader classLoader = createClassLoader(launcher);\n\t\tURL[] urls = classLoader.getURLs();\n\t\tList<File> expectedFiles = getExpectedFilesWithExtraLibs(explodedRoot);\n\t\tURL[] expectedFileUrls = expectedFiles.stream().map(this::toUrl).toArray(URL[]::new);\n\t\tassertThat(urls).containsExactly(expectedFileUrls);\n\t}\n\n\tprivate URL[] getExpectedFileUrls(File explodedRoot) {\n\t\treturn getExpectedFiles(explodedRoot).stream().map(this::toUrl).toArray(URL[]::new);\n\t}\n\n\tprivate List<File> getExpectedFiles(File parent) {\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(parent, \"WEB-INF/classes\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/foo.jar\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/bar.jar\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/baz.jar\"));\n\t\treturn expected;\n\t}\n\n\tprivate List<File> getExpectedFilesWithExtraLibs(File parent) {\n\t\tList<File> expected = new ArrayList<>();\n\t\texpected.add(new File(parent, \"WEB-INF/classes\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/extra-1.jar\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/extra-2.jar\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/foo.jar\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/bar.jar\"));\n\t\texpected.add(new File(parent, \"WEB-INF/lib/baz.jar\"));\n\t\treturn expected;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/CanonicalizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Canonicalizer}.\n *\n * @author Phillip Webb\n */\nclass CanonicalizerTests {\n\n\t@Test\n\tvoid canonicalizeAfterOnlyChangesAfterPos() {\n\t\tString prefix = \"/foo/.././bar/.!/foo/.././bar/.\";\n\t\tString canonicalized = Canonicalizer.canonicalizeAfter(prefix, prefix.indexOf(\"!/\"));\n\t\tassertThat(canonicalized).isEqualTo(\"/foo/.././bar/.!/bar/\");\n\t}\n\n\t@Test\n\tvoid canonicalizeWhenHasEmbeddedSlashDotDotSlash() {\n\t\tassertThat(Canonicalizer.canonicalize(\"/foo/../bar/bif/bam/../../baz\")).isEqualTo(\"/bar/baz\");\n\t}\n\n\t@Test\n\tvoid canonicalizeWhenHasEmbeddedSlashDotSlash() {\n\t\tassertThat(Canonicalizer.canonicalize(\"/foo/./bar/bif/bam/././baz\")).isEqualTo(\"/foo/bar/bif/bam/baz\");\n\t}\n\n\t@Test\n\tvoid canonicalizeWhenHasTrailingSlashDotDot() {\n\t\tassertThat(Canonicalizer.canonicalize(\"/foo/bar/baz/../..\")).isEqualTo(\"/foo/\");\n\t}\n\n\t@Test\n\tvoid canonicalizeWhenHasTrailingSlashDot() {\n\t\tassertThat(Canonicalizer.canonicalize(\"/foo/bar/baz/./.\")).isEqualTo(\"/foo/bar/baz/\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/HandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Handler}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass HandlerTests {\n\n\tprivate final Handler handler = new Handler();\n\n\t@Test\n\tvoid indexOfSeparator() {\n\t\tString spec = \"jar:nested:foo!bar!/some/entry#foo\";\n\t\tassertThat(Handler.indexOfSeparator(spec, 0, spec.indexOf('#'))).isEqualTo(spec.lastIndexOf(\"!/\"));\n\t}\n\n\t@Test\n\tvoid indexOfSeparatorWhenHasStartAndLimit() {\n\t\tString spec = \"a!/jar:nested:foo!bar!/some/entry#foo!/b\";\n\t\tint beginIndex = 3;\n\t\tint endIndex = spec.length() - 4;\n\t\tString substring = spec.substring(beginIndex, endIndex);\n\t\tassertThat(Handler.indexOfSeparator(spec, 0, spec.indexOf('#')))\n\t\t\t.isEqualTo(substring.lastIndexOf(\"!/\") + beginIndex);\n\t}\n\n\t@Test\n\tvoid parseUrlWhenAbsoluteParses() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"\");\n\t\tString spec = \"jar:file:example.jar!/entry.txt\";\n\t\tthis.handler.parseURL(url, spec, 4, spec.length());\n\t\tassertThat(url.toExternalForm()).isEqualTo(spec);\n\t}\n\n\t@Test\n\tvoid parseUrlWhenAbsoluteWithAnchorParses() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"\");\n\t\tString spec = \"jar:file:example.jar!/entry.txt\";\n\t\tthis.handler.parseURL(url, spec + \"#foo\", 4, spec.length());\n\t\tassertThat(url.toExternalForm()).isEqualTo(spec + \"#foo\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenAbsoluteWithNoSeparatorThrowsException() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"\");\n\t\tString spec = \"jar:file:example.jar!\\\\entry.txt\";\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.handler.parseURL(url, spec, 4, spec.length()))\n\t\t\t.withMessage(\"no !/ in spec\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenAbsoluteWithMalformedInnerUrlThrowsException() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"\");\n\t\tString spec = \"jar:example.jar!/entry.txt\";\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.handler.parseURL(url, spec, 4, spec.length()))\n\t\t\t.withMessage(\n\t\t\t\t\t\"invalid url: jar:example.jar!/entry.txt (java.net.MalformedURLException: no protocol: example.jar)\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenRelativeWithLeadingSlashParses() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tString spec = \"/other.txt\";\n\t\tthis.handler.parseURL(url, spec, 0, spec.length());\n\t\tassertThat(url.toExternalForm()).isEqualTo(\"jar:file:example.jar!/other.txt\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenRelativeWithLeadingSlashAndAnchorParses() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tString spec = \"/other.txt\";\n\t\tthis.handler.parseURL(url, spec + \"#relative\", 0, spec.length());\n\t\tassertThat(url.toExternalForm()).isEqualTo(\"jar:file:example.jar!/other.txt#relative\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenRelativeWithLeadingSlashAndNoSeparator() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar/entry.txt\");\n\t\tString spec = \"/other.txt\";\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.handler.parseURL(url, spec, 0, spec.length()))\n\t\t\t.withMessage(\"malformed context url:jar:file:example.jar/entry.txt: no !/\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenRelativeWithoutLeadingSlashParses() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar!/foo/\");\n\t\tString spec = \"bar.txt\";\n\t\tthis.handler.parseURL(url, spec, 0, spec.length());\n\t\tassertThat(url.toExternalForm()).isEqualTo(\"jar:file:example.jar!/foo/bar.txt\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenRelativeWithoutLeadingSlashAndWithoutTrailingSlashParses() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar!/foo/baz\");\n\t\tString spec = \"bar.txt\";\n\t\tthis.handler.parseURL(url, spec, 0, spec.length());\n\t\tassertThat(url.toExternalForm()).isEqualTo(\"jar:file:example.jar!/foo/bar.txt\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenRelativeWithoutLeadingSlashAndWithoutContextSlashThrowsException() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar\");\n\t\tString spec = \"bar.txt\";\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.handler.parseURL(url, spec, 0, spec.length()))\n\t\t\t.withMessage(\"malformed context url:jar:file:example.jar\");\n\t}\n\n\t@Test\n\tvoid parseUrlWhenAnchorOnly() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tString spec = \"#runtime\";\n\t\tthis.handler.parseURL(url, spec, 0, 0);\n\t\tassertThat(url.toExternalForm()).isEqualTo(\"jar:file:example.jar!/entry.txt#runtime\");\n\t}\n\n\t@Test // gh-38524\n\tvoid parseUrlWhenSpecIsEmpty() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"nested:gh-38524.jar/!BOOT-INF/classes/!/\");\n\t\tString spec = \"\";\n\t\tthis.handler.parseURL(url, spec, 0, 0);\n\t\tassertThat(url.toExternalForm()).isEqualTo(\"jar:nested:gh-38524.jar/!BOOT-INF/classes/!/\");\n\n\t}\n\n\t@Test\n\tvoid hashCodeGeneratesHashCode() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tassertThat(this.handler.hashCode(url)).isEqualTo(1873709601);\n\t}\n\n\t@Test\n\tvoid hashCodeWhenMalformedInnerUrlGeneratesHashCode() throws MalformedURLException {\n\t\tURL url = createJarUrl(\"example.jar!/entry.txt\");\n\t\tassertThat(this.handler.hashCode(url)).isEqualTo(1870566566);\n\t}\n\n\t@Test\n\tvoid sameFileWhenSameReturnsTrue() throws MalformedURLException {\n\t\tURL url1 = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tURL url2 = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tassertThat(this.handler.sameFile(url1, url2)).isTrue();\n\t}\n\n\t@Test\n\tvoid sameFileWhenMissingSeparatorReturnsFalse() throws MalformedURLException {\n\t\tURL url1 = createJarUrl(\"file:example.jar!/entry.txt\");\n\t\tURL url2 = createJarUrl(\"file:example.jar/entry.txt\");\n\t\tassertThat(this.handler.sameFile(url1, url2)).isFalse();\n\t}\n\n\t@Test\n\tvoid sameFileWhenDifferentEntryReturnsFalse() throws MalformedURLException {\n\t\tURL url1 = createJarUrl(\"file:example.jar!/entry1.txt\");\n\t\tURL url2 = createJarUrl(\"file:example.jar!/entry2.txt\");\n\t\tassertThat(this.handler.sameFile(url1, url2)).isFalse();\n\t}\n\n\t@Test\n\tvoid sameFileWhenDifferentInnerUrlReturnsFalse() throws MalformedURLException {\n\t\tURL url1 = createJarUrl(\"file:example1.jar!/entry.txt\");\n\t\tURL url2 = createJarUrl(\"file:example2.jar!/entry.txt\");\n\t\tassertThat(this.handler.sameFile(url1, url2)).isFalse();\n\t}\n\n\t@Test\n\tvoid sameFileWhenSameMalformedInnerUrlReturnsTrue() throws MalformedURLException {\n\t\tURL url1 = createJarUrl(\"example.jar!/entry.txt\");\n\t\tURL url2 = createJarUrl(\"example.jar!/entry.txt\");\n\t\tassertThat(this.handler.sameFile(url1, url2)).isTrue();\n\t}\n\n\t@Test\n\tvoid sameFileWhenDifferentMalformedInnerUrlReturnsFalse() throws MalformedURLException {\n\t\tURL url1 = createJarUrl(\"example1.jar!/entry.txt\");\n\t\tURL url2 = createJarUrl(\"example2.jar!/entry.txt\");\n\t\tassertThat(this.handler.sameFile(url1, url2)).isFalse();\n\t}\n\n\tprivate URL createJarUrl(String file) throws MalformedURLException {\n\t\treturn new URL(\"jar\", null, -1, file, this.handler);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/JarFileUrlKeyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JarFileUrlKey}.\n *\n * @author Phillip Webb\n */\nclass JarFileUrlKeyTests {\n\n\t@BeforeAll\n\tstatic void setup() {\n\t\tHandlers.register();\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path\");\n\t\tJarFileUrlKey k2 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path\");\n\t\tJarFileUrlKey k3 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path2\");\n\t\tassertThat(k1.hashCode()).isEqualTo(k2.hashCode())\n\t\t\t.isEqualTo(\"nested:/my.jar/!mynested.jar!/my/path\".hashCode());\n\t\tassertThat(k1).isEqualTo(k1).isEqualTo(k2).isNotEqualTo(k3);\n\t}\n\n\t@Test\n\tvoid equalsWhenUppercaseAndLowercaseProtocol() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"JAR:nested:/my.jar/!mynested.jar!/my/path\");\n\t\tJarFileUrlKey k2 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\t@Test\n\tvoid equalsWhenHasHostAndPort() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"https://example.com:1234/test\");\n\t\tJarFileUrlKey k2 = key(\"https://example.com:1234/test\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\t@Test\n\tvoid equalsWhenHasUppercaseAndLowercaseHost() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"https://EXAMPLE.com:1234/test\");\n\t\tJarFileUrlKey k2 = key(\"https://example.com:1234/test\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\t@Test\n\tvoid equalsWhenHasNoPortUsesDefaultPort() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"https://EXAMPLE.com/test\");\n\t\tJarFileUrlKey k2 = key(\"https://example.com:443/test\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\t@Test\n\tvoid equalsWhenHasNoFile() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"https://EXAMPLE.com\");\n\t\tJarFileUrlKey k2 = key(\"https://example.com:443\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\t@Test\n\tvoid equalsWhenHasRuntimeRef() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path#runtime\");\n\t\tJarFileUrlKey k2 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path#runtime\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\t@Test\n\tvoid equalsWhenHasOtherRefIgnoresRefs() throws Exception {\n\t\tJarFileUrlKey k1 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path#example\");\n\t\tJarFileUrlKey k2 = key(\"jar:nested:/my.jar/!mynested.jar!/my/path\");\n\t\tassertThat(k1).isEqualTo(k2);\n\t}\n\n\tprivate JarFileUrlKey key(String spec) throws MalformedURLException {\n\t\treturn new JarFileUrlKey(new URL(spec));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/JarUrlClassLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.CRC32;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JarUrlClassLoader}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass JarUrlClassLoaderTests {\n\n\tprivate static final URL APP_JAR;\n\tstatic {\n\t\ttry {\n\t\t\tAPP_JAR = new URL(\"jar:file:src/test/resources/jars/app.jar!/\");\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t@TempDir\n\tFile tempDir;\n\n\t@BeforeAll\n\tstatic void setup() {\n\t\tHandlers.register();\n\t}\n\n\t@Test\n\tvoid resolveResourceFromArchive() throws Exception {\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(APP_JAR)) {\n\t\t\tassertThat(loader.getResource(\"demo/Application.java\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid resolveResourcesFromArchive() throws Exception {\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(APP_JAR)) {\n\t\t\tassertThat(loader.getResources(\"demo/Application.java\").hasMoreElements()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid resolveRootPathFromArchive() throws Exception {\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(APP_JAR)) {\n\t\t\tassertThat(loader.getResource(\"\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid resolveRootResourcesFromArchive() throws Exception {\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(APP_JAR)) {\n\t\t\tassertThat(loader.getResources(\"\").hasMoreElements()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid resolveFromNested() throws Exception {\n\t\tFile jarFile = new File(this.tempDir, \"test.jar\");\n\t\tTestJar.create(jarFile);\n\t\tURL url = JarUrl.create(jarFile, \"nested.jar\");\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(url)) {\n\t\t\tURL resource = loader.getResource(\"3.dat\");\n\t\t\tassertThat(resource).hasToString(url + \"3.dat\");\n\t\t\ttry (InputStream input = resource.openConnection().getInputStream()) {\n\t\t\t\tassertThat(input.read()).isEqualTo(3);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadClass() throws Exception {\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(APP_JAR)) {\n\t\t\tassertThat(loader.loadClass(\"demo.Application\")).isNotNull().hasToString(\"class demo.Application\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadClassFromNested() throws Exception {\n\t\tFile appJar = new File(\"src/test/resources/jars/app.jar\");\n\t\tFile jarFile = new File(this.tempDir, \"test.jar\");\n\t\tFileOutputStream fileOutputStream = new FileOutputStream(jarFile);\n\t\ttry (JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream)) {\n\t\t\tJarEntry nestedEntry = new JarEntry(\"app.jar\");\n\t\t\tbyte[] nestedJarData = Files.readAllBytes(appJar.toPath());\n\t\t\tnestedEntry.setSize(nestedJarData.length);\n\t\t\tnestedEntry.setCompressedSize(nestedJarData.length);\n\t\t\tCRC32 crc32 = new CRC32();\n\t\t\tcrc32.update(nestedJarData);\n\t\t\tnestedEntry.setCrc(crc32.getValue());\n\t\t\tnestedEntry.setMethod(ZipEntry.STORED);\n\t\t\tjarOutputStream.putNextEntry(nestedEntry);\n\t\t\tjarOutputStream.write(nestedJarData);\n\t\t\tjarOutputStream.closeEntry();\n\t\t}\n\t\tURL url = JarUrl.create(jarFile, \"app.jar\");\n\t\ttry (JarUrlClassLoader loader = new TestJarUrlClassLoader(url)) {\n\t\t\tassertThat(loader.loadClass(\"demo.Application\")).isNotNull().hasToString(\"class demo.Application\");\n\t\t}\n\t}\n\n\tstatic class TestJarUrlClassLoader extends JarUrlClassLoader {\n\n\t\tTestJarUrlClassLoader(URL... urls) {\n\t\t\tsuper(urls, JarUrlClassLoaderTests.class.getClassLoader());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/JarUrlConnectionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.nio.charset.StandardCharsets;\nimport java.security.Permission;\nimport java.time.Instant;\nimport java.time.temporal.ChronoField;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.loader.zip.ZipContent;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link JarUrlConnection}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass JarUrlConnectionTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate File file;\n\n\tprivate URL url;\n\n\t@BeforeAll\n\tstatic void registerHandlers() {\n\t\tHandlers.register();\n\t}\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid reset() {\n\t\tJarUrlConnection.clearCache();\n\t\tOptimizations.disable();\n\t}\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(this.file);\n\t\tthis.url = JarUrl.create(this.file, \"nested.jar\");\n\t}\n\n\t@Test\n\tvoid getJarFileReturnsJarFile() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tJarFile jarFile = connection.getJarFile();\n\t\tassertThat(jarFile).isNotNull();\n\t\tassertThat(jarFile.getEntry(\"3.dat\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid getJarEntryReturnsJarEntry() throws Exception {\n\t\tURL url = JarUrl.create(this.file, \"nested.jar\", \"3.dat\");\n\t\tJarUrlConnection connection = JarUrlConnection.open(url);\n\t\tJarEntry entry = connection.getJarEntry();\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getName()).isEqualTo(\"3.dat\");\n\t}\n\n\t@Test\n\tvoid getJarEntryWhenHasNoEntryNameReturnsNull() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tJarEntry entry = connection.getJarEntry();\n\t\tassertThat(entry).isNull();\n\t}\n\n\t@Test\n\tvoid getContentLengthReturnsContentLength() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\ttry (ZipContent content = ZipContent.open(this.file.toPath())) {\n\t\t\tint expected = content.getEntry(\"nested.jar\").getUncompressedSize();\n\t\t\tassertThat(connection.getContentLength()).isEqualTo(expected);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getContentLengthWhenLengthIsLargerThanMaxIntReturnsMinusOne() {\n\t\tJarUrlConnection connection = mock(JarUrlConnection.class);\n\t\tgiven(connection.getContentLength()).willCallRealMethod();\n\t\tgiven(connection.getContentLengthLong()).willReturn((long) Integer.MAX_VALUE + 1);\n\t\tassertThat(connection.getContentLength()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid getContentLengthLongWhenHasNoEntryReturnsSizeOfJar() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\ttry (ZipContent content = ZipContent.open(this.file.toPath())) {\n\t\t\tint expected = content.getEntry(\"nested.jar\").getUncompressedSize();\n\t\t\tassertThat(connection.getContentLengthLong()).isEqualTo(expected);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getContentLengthLongWhenHasEntryReturnsEntrySize() throws Exception {\n\t\tURL url = JarUrl.create(this.file, \"nested.jar\", \"3.dat\");\n\t\tJarUrlConnection connection = JarUrlConnection.open(url);\n\t\tassertThat(connection.getContentLengthLong()).isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid getContentLengthLongWhenCannotConnectReturnsMinusOne() throws IOException {\n\t\tJarUrlConnection connection = mock(JarUrlConnection.class);\n\t\twillThrow(IOException.class).given(connection).connect();\n\t\tgiven(connection.getContentLengthLong()).willCallRealMethod();\n\t\tassertThat(connection.getContentLengthLong()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid getContentTypeWhenHasNoEntryReturnsJavaJar() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tassertThat(connection.getContentType()).isEqualTo(\"x-java/jar\");\n\t}\n\n\t@Test\n\tvoid getContentTypeWhenHasKnownStreamReturnsDeducedType() throws Exception {\n\t\tString content = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><ok></ok>\";\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(this.file))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"test.dat\"));\n\t\t\tout.write(content.getBytes(StandardCharsets.UTF_8));\n\t\t\tout.closeEntry();\n\t\t}\n\t\tJarUrlConnection connection = JarUrlConnection\n\t\t\t.open(new URL(\"jar:file:\" + this.file.getAbsolutePath() + \"!/test.dat\"));\n\t\tassertThat(connection.getContentType()).isEqualTo(\"application/xml\");\n\t}\n\n\t@Test\n\tvoid getContentTypeWhenNotKnownInStreamButKnownNameReturnsDeducedType() throws Exception {\n\t\tString content = \"nothinguseful\";\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(this.file))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"test.xml\"));\n\t\t\tout.write(content.getBytes(StandardCharsets.UTF_8));\n\t\t\tout.closeEntry();\n\t\t}\n\t\tJarUrlConnection connection = JarUrlConnection\n\t\t\t.open(new URL(\"jar:file:\" + this.file.getAbsolutePath() + \"!/test.xml\"));\n\t\tassertThat(connection.getContentType()).isEqualTo(\"application/xml\");\n\t}\n\n\t@Test\n\tvoid getContentTypeWhenCannotBeDeducedReturnsContentUnknown() throws Exception {\n\t\tString content = \"nothinguseful\";\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(this.file))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"test.dat\"));\n\t\t\tout.write(content.getBytes(StandardCharsets.UTF_8));\n\t\t\tout.closeEntry();\n\t\t}\n\t\tJarUrlConnection connection = JarUrlConnection\n\t\t\t.open(new URL(\"jar:file:\" + this.file.getAbsolutePath() + \"!/test.dat\"));\n\t\tassertThat(connection.getContentType()).isEqualTo(\"content/unknown\");\n\t}\n\n\t@Test\n\tvoid getHeaderFieldDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tgiven(jarFileConnection.getHeaderField(\"test\")).willReturn(\"test\");\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tassertThat(connection.getHeaderField(\"test\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getContentWhenHasEntryReturnsContentFromEntry() throws Exception {\n\t\tString content = \"hello\";\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(this.file))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"test.txt\"));\n\t\t\tout.write(content.getBytes(StandardCharsets.UTF_8));\n\t\t\tout.closeEntry();\n\t\t}\n\t\tJarUrlConnection connection = JarUrlConnection\n\t\t\t.open(new URL(\"jar:file:\" + this.file.getAbsolutePath() + \"!/test.txt\"));\n\t\tassertThat(connection.getContent()).isInstanceOf(FilterInputStream.class);\n\t}\n\n\t@Test\n\tvoid getContentWhenHasNoEntryReturnsJarFile() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tassertThat(connection.getContent()).isInstanceOf(JarFile.class);\n\t}\n\n\t@Test\n\tvoid getPermissionReturnJarConnectionPermission() throws IOException {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tPermission permission = mock(Permission.class);\n\t\tgiven(jarFileConnection.getPermission()).willReturn(permission);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tassertThat(connection.getPermission()).isSameAs(permission);\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenNotNestedAndHasNoEntryThrowsException() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file));\n\t\tassertThatIOException().isThrownBy(connection::getInputStream).withMessage(\"no entry name specified\");\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenOptimizedWithoutReadAndHasCachedJarWithEntryReturnsEmptyInputStream() throws Exception {\n\t\tJarUrlConnection setupConnection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\"));\n\t\tsetupConnection.connect();\n\t\tassertThat(JarUrlConnection.jarFiles.getCached(setupConnection.getJarFileURL())).isNotNull();\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"3.dat\"));\n\t\tconnection.setUseCaches(false);\n\t\tOptimizations.enable(false);\n\t\tassertThat(connection.getInputStream()).isSameAs(JarUrlConnection.emptyInputStream);\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenNoEntryAndOptimizedThrowsException() throws Exception {\n\t\tJarUrlConnection setupConnection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\"));\n\t\tsetupConnection.connect();\n\t\tassertThat(JarUrlConnection.jarFiles.getCached(setupConnection.getJarFileURL())).isNotNull();\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tOptimizations.enable(false);\n\t\tassertThatExceptionOfType(FileNotFoundException.class).isThrownBy(connection::getInputStream)\n\t\t\t.isSameAs(JarUrlConnection.FILE_NOT_FOUND_EXCEPTION);\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenNoEntryAndNotOptimizedThrowsException() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tassertThatExceptionOfType(FileNotFoundException.class).isThrownBy(connection::getInputStream)\n\t\t\t.withMessageContaining(\"JAR entry missing.dat not found in\");\n\t}\n\n\t@Test // gh-38047\n\tvoid getInputStreamWhenNoEntryAndNestedReturnsFullJarInputStream() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\"));\n\t\tFile outFile = new File(this.temp, \"out.zip\");\n\t\ttry (OutputStream out = new FileOutputStream(outFile)) {\n\t\t\tconnection.getInputStream().transferTo(out);\n\t\t}\n\t\ttry (JarFile outJar = new JarFile(outFile)) {\n\t\t\tassertThat(outJar.getEntry(\"3.dat\")).isNotNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getInputStreamReturnsInputStream() throws IOException {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"3.dat\"));\n\t\ttry (InputStream in = connection.getInputStream()) {\n\t\t\tassertThat(in).hasBinaryContent(new byte[] { 3 });\n\t\t}\n\t}\n\n\t@Test\n\tvoid getInputStreamWhenNoCachedClosesJarFileOnClose() throws IOException {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"3.dat\"));\n\t\tconnection.setUseCaches(false);\n\t\tInputStream in = connection.getInputStream();\n\t\tJarFile jarFile = (JarFile) ReflectionTestUtils.getField(connection, \"jarFile\");\n\t\tjarFile = spy(jarFile);\n\t\tReflectionTestUtils.setField(connection, \"jarFile\", jarFile);\n\t\tin.close();\n\t\tthen(jarFile).should().close();\n\t}\n\n\t@Test\n\tvoid getAllowUserInteractionDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tgiven(jarFileConnection.getAllowUserInteraction()).willReturn(true);\n\t\tassertThat(connection.getAllowUserInteraction()).isTrue();\n\t\tthen(jarFileConnection).should().getAllowUserInteraction();\n\t}\n\n\t@Test\n\tvoid setAllowUserInteractionDelegatesToJarFileConnection() throws IOException {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tconnection.setAllowUserInteraction(true);\n\t\tthen(jarFileConnection).should().setAllowUserInteraction(true);\n\t}\n\n\t@Test\n\tvoid getUseCachesDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tgiven(jarFileConnection.getUseCaches()).willReturn(true);\n\t\tassertThat(connection.getUseCaches()).isTrue();\n\t\tthen(jarFileConnection).should().getUseCaches();\n\t}\n\n\t@Test\n\tvoid setUseCachesDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tconnection.setUseCaches(true);\n\t\tthen(jarFileConnection).should().setUseCaches(true);\n\t}\n\n\t@Test\n\tvoid getDefaultUseCachesDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tgiven(jarFileConnection.getDefaultUseCaches()).willReturn(true);\n\t\tassertThat(connection.getDefaultUseCaches()).isTrue();\n\t\tthen(jarFileConnection).should().getDefaultUseCaches();\n\t}\n\n\t@Test\n\tvoid setDefaultUseCachesDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tconnection.setDefaultUseCaches(true);\n\t\tthen(jarFileConnection).should().setDefaultUseCaches(true);\n\t}\n\n\t@Test\n\tvoid setIfModifiedSinceDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tconnection.setIfModifiedSince(123L);\n\t\tthen(jarFileConnection).should().setIfModifiedSince(123L);\n\t}\n\n\t@Test\n\tvoid getRequestPropertyDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tgiven(jarFileConnection.getRequestProperty(\"test\")).willReturn(\"test\");\n\t\tassertThat(connection.getRequestProperty(\"test\")).isEqualTo(\"test\");\n\t\tthen(jarFileConnection).should().getRequestProperty(\"test\");\n\t}\n\n\t@Test\n\tvoid setRequestPropertyDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tconnection.setRequestProperty(\"test\", \"testvalue\");\n\t\tthen(jarFileConnection).should().setRequestProperty(\"test\", \"testvalue\");\n\t}\n\n\t@Test\n\tvoid addRequestPropertyDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tconnection.addRequestProperty(\"test\", \"testvalue\");\n\t\tthen(jarFileConnection).should().addRequestProperty(\"test\", \"testvalue\");\n\t}\n\n\t@Test\n\tvoid getRequestPropertiesDelegatesToJarFileConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection jarFileConnection = mock(URLConnection.class);\n\t\tReflectionTestUtils.setField(connection, \"jarFileConnection\", jarFileConnection);\n\t\tMap<String, List<String>> properties = Map.of(\"test\", List.of(\"testvalue\"));\n\t\tgiven(jarFileConnection.getRequestProperties()).willReturn(properties);\n\t\tassertThat(connection.getRequestProperties()).isEqualTo(properties);\n\t\tthen(jarFileConnection).should().getRequestProperties();\n\t}\n\n\t@Test\n\tvoid connectWhenConnectedDoesNotReconnect() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tconnection.connect();\n\t\tReflectionTestUtils.setField(connection, \"jarFile\", null);\n\t\tconnection.connect();\n\t\tassertThat(ReflectionTestUtils.getField(connection, \"jarFile\")).isNull();\n\t}\n\n\t@Test\n\tvoid connectWhenHasNotFoundSupplierThrowsException() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tassertThat(connection).extracting(\"notFound\").isNotNull();\n\t\tassertThatExceptionOfType(FileNotFoundException.class).isThrownBy(connection::connect)\n\t\t\t.withMessageContaining(\"JAR entry missing.dat not found in\");\n\t}\n\n\t@Test\n\tvoid connectWhenOptimizationsEnabledAndHasCachedJarWithoutEntryThrowsException() throws Exception {\n\t\tJarUrlConnection setupConnection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\"));\n\t\tsetupConnection.connect();\n\t\tassertThat(JarUrlConnection.jarFiles.getCached(setupConnection.getJarFileURL())).isNotNull();\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tOptimizations.enable(true);\n\t\tassertThatExceptionOfType(FileNotFoundException.class).isThrownBy(connection::connect)\n\t\t\t.isSameAs(JarUrlConnection.FILE_NOT_FOUND_EXCEPTION);\n\t}\n\n\t@Test\n\tvoid connectWhenHasNoEntryConnects() throws Exception {\n\t\tJarUrlConnection setupConnection = JarUrlConnection.open(this.url);\n\t\tsetupConnection.connect();\n\t\tassertThat(setupConnection.getJarFile()).isNotNull();\n\t}\n\n\t@Test\n\tvoid connectWhenEntryDoesNotExistAndOptimizationsEnabledThrowsException() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tOptimizations.enable(true);\n\t\tassertThatExceptionOfType(FileNotFoundException.class).isThrownBy(connection::connect)\n\t\t\t.isSameAs(JarUrlConnection.FILE_NOT_FOUND_EXCEPTION);\n\t}\n\n\t@Test\n\tvoid connectWhenEntryDoesNotExistAndNoOptimizationsEnabledThrowsException() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tassertThatExceptionOfType(FileNotFoundException.class).isThrownBy(connection::connect)\n\t\t\t.withMessageContaining(\"JAR entry missing.dat not found in\");\n\t}\n\n\t@Test\n\tvoid connectWhenEntryExists() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"3.dat\"));\n\t\tconnection.connect();\n\t\tassertThat(connection.getJarEntry()).isNotNull();\n\t}\n\n\t@Test\n\tvoid connectWhenAddedToCacheReconnects() throws IOException {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tObject originalConnection = ReflectionTestUtils.getField(connection, \"jarFileConnection\");\n\t\tconnection.connect();\n\t\tassertThat(connection).extracting(\"jarFileConnection\").isNotSameAs(originalConnection);\n\t}\n\n\t@Test\n\tvoid openWhenNestedAndInCachedWithoutEntryAndOptimizationsEnabledReturnsNoFoundConnection() throws Exception {\n\t\tJarUrlConnection setupConnection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\"));\n\t\tsetupConnection.connect();\n\t\tassertThat(JarUrlConnection.jarFiles.getCached(setupConnection.getJarFileURL())).isNotNull();\n\t\tOptimizations.enable(true);\n\t\tJarUrlConnection connection = JarUrlConnection.open(JarUrl.create(this.file, \"nested.jar\", \"missing.dat\"));\n\t\tassertThat(connection).isSameAs(JarUrlConnection.NOT_FOUND_CONNECTION);\n\t}\n\n\t@Test\n\tvoid openReturnsConnection() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tassertThat(connection).isNotNull();\n\t}\n\n\t@Test // gh-38204\n\tvoid getLastModifiedReturnsFileModifiedTime() throws Exception {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tassertThat(connection.getLastModified()).isEqualTo(this.file.lastModified());\n\t}\n\n\t@Test // gh-38204\n\tvoid getLastModifiedHeaderReturnsFileModifiedTime() throws IOException {\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tURLConnection fileConnection = this.file.toURI().toURL().openConnection();\n\t\ttry {\n\t\t\tassertThat(connection.getHeaderFieldDate(\"last-modified\", 0))\n\t\t\t\t.isEqualTo(withoutNanos(this.file.lastModified()))\n\t\t\t\t.isEqualTo(fileConnection.getHeaderFieldDate(\"last-modified\", 0));\n\t\t}\n\t\tfinally {\n\t\t\tfileConnection.getInputStream().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getJarFileWhenInFolderWithEncodedCharsReturnsJarFile() throws Exception {\n\t\tthis.temp = new File(this.temp, \"te#st\");\n\t\tthis.temp.mkdirs();\n\t\tthis.file = new File(this.temp, \"test.jar\");\n\t\tthis.url = JarUrl.create(this.file, \"nested.jar\");\n\t\tassertThat(this.url.toString()).contains(\"te%23st\");\n\t\tTestJar.create(this.file);\n\t\tJarUrlConnection connection = JarUrlConnection.open(this.url);\n\t\tJarFile jarFile = connection.getJarFile();\n\t\tassertThat(jarFile).isNotNull();\n\t\tassertThat(jarFile.getEntry(\"3.dat\")).isNotNull();\n\t}\n\n\tprivate long withoutNanos(long epochMilli) {\n\t\treturn Instant.ofEpochMilli(epochMilli).with(ChronoField.NANO_OF_SECOND, 0).toEpochMilli();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/JarUrlTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.jar.JarEntry;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.util.UrlDecoder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JarUrl}.\n *\n * @author Phillip Webb\n */\nclass JarUrlTests {\n\n\t@TempDir\n\tFile temp;\n\n\tFile jarFile;\n\n\tString jarFileUrlPath;\n\n\t@BeforeEach\n\tvoid setup() throws MalformedURLException {\n\t\tthis.jarFile = new File(this.temp, \"my.jar\");\n\t\tthis.jarFileUrlPath = this.jarFile.toURI().toURL().toString().substring(\"file:\".length()).replace(\"!\", \"%21\");\n\t}\n\n\t@Test\n\tvoid createWithFileReturnsUrl() {\n\t\tURL url = JarUrl.create(this.jarFile);\n\t\tassertThat(url).hasToString(\"jar:file:%s!/\".formatted(this.jarFileUrlPath));\n\t}\n\n\t@Test\n\tvoid createWithFileAndEntryReturnsUrl() {\n\t\tJarEntry entry = new JarEntry(\"lib.jar\");\n\t\tURL url = JarUrl.create(this.jarFile, entry);\n\t\tassertThat(url).hasToString(\"jar:nested:%s/!lib.jar!/\".formatted(this.jarFileUrlPath));\n\t}\n\n\t@Test\n\tvoid createWithFileAndNullEntryReturnsUrl() {\n\t\tURL url = JarUrl.create(this.jarFile, (JarEntry) null);\n\t\tassertThat(url).hasToString(\"jar:file:%s!/\".formatted(this.jarFileUrlPath));\n\t}\n\n\t@Test\n\tvoid createWithFileAndNameReturnsUrl() {\n\t\tURL url = JarUrl.create(this.jarFile, \"lib.jar\");\n\t\tassertThat(url).hasToString(\"jar:nested:%s/!lib.jar!/\".formatted(this.jarFileUrlPath));\n\t}\n\n\t@Test\n\tvoid createWithFileAndNullNameReturnsUrl() {\n\t\tURL url = JarUrl.create(this.jarFile, (String) null);\n\t\tassertThat(url).hasToString(\"jar:file:%s!/\".formatted(this.jarFileUrlPath));\n\t}\n\n\t@Test\n\tvoid createWithFileNameAndPathReturnsUrl() {\n\t\tURL url = JarUrl.create(this.jarFile, \"lib.jar\", \"com/example/My.class\");\n\t\tassertThat(url).hasToString(\"jar:nested:%s/!lib.jar!/com/example/My.class\".formatted(this.jarFileUrlPath));\n\t}\n\n\t@Test\n\tvoid createWithReservedCharsInName() throws Exception {\n\t\tString badFolderName = \"foo#bar!/baz/!oof\";\n\t\tthis.temp = new File(this.temp, badFolderName);\n\t\tsetup();\n\t\tURL url = JarUrl.create(this.jarFile, \"lib.jar\", \"com/example/My.class\");\n\t\tassertThat(url).hasToString(\"jar:nested:%s/!lib.jar!/com/example/My.class\".formatted(this.jarFileUrlPath));\n\t\tassertThat(UrlDecoder.decode(url.toString())).contains(badFolderName);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/LazyDelegatingInputStreamTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LazyDelegatingInputStream}.\n *\n * @author Phillip Webb\n */\nclass LazyDelegatingInputStreamTests {\n\n\tprivate InputStream delegate = mock(InputStream.class);\n\n\tprivate TestLazyDelegatingInputStream inputStream = new TestLazyDelegatingInputStream();\n\n\t@Test\n\tvoid noOperationsDoesNotGetDelegateInputStream() {\n\t\tthen(this.delegate).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid readDelegatesToInputStream() throws Exception {\n\t\tthis.inputStream.read();\n\t\tthen(this.delegate).should().read();\n\t}\n\n\t@Test\n\tvoid readWithByteArrayDelegatesToInputStream() throws Exception {\n\t\tbyte[] bytes = new byte[1];\n\t\tthis.inputStream.read(bytes);\n\t\tthen(this.delegate).should().read(bytes);\n\t}\n\n\t@Test\n\tvoid readWithByteArrayAndOffsetAndLenDelegatesToInputStream() throws Exception {\n\t\tbyte[] bytes = new byte[1];\n\t\tthis.inputStream.read(bytes, 0, 1);\n\t\tthen(this.delegate).should().read(bytes, 0, 1);\n\t}\n\n\t@Test\n\tvoid skipDelegatesToInputStream() throws Exception {\n\t\tthis.inputStream.skip(10);\n\t\tthen(this.delegate).should().skip(10);\n\t}\n\n\t@Test\n\tvoid availableDelegatesToInputStream() throws Exception {\n\t\tthis.inputStream.available();\n\t\tthen(this.delegate).should().available();\n\t}\n\n\t@Test\n\tvoid markSupportedDelegatesToInputStream() {\n\t\tthis.inputStream.markSupported();\n\t\tthen(this.delegate).should().markSupported();\n\t}\n\n\t@Test\n\tvoid markDelegatesToInputStream() {\n\t\tthis.inputStream.mark(10);\n\t\tthen(this.delegate).should().mark(10);\n\t}\n\n\t@Test\n\tvoid resetDelegatesToInputStream() throws Exception {\n\t\tthis.inputStream.reset();\n\t\tthen(this.delegate).should().reset();\n\t}\n\n\t@Test\n\tvoid closeWhenDelegateNotCreatedDoesNothing() throws Exception {\n\t\tthis.inputStream.close();\n\t\tthen(this.delegate).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid closeDelegatesToInputStream() throws Exception {\n\t\tthis.inputStream.available();\n\t\tthis.inputStream.close();\n\t\tthen(this.delegate).should().close();\n\t}\n\n\t@Test\n\tvoid getDelegateInputStreamIsOnlyCalledOnce() throws Exception {\n\t\tthis.inputStream.available();\n\t\tthis.inputStream.mark(10);\n\t\tthis.inputStream.read();\n\t\tassertThat(this.inputStream.count).isOne();\n\t}\n\n\tprivate final class TestLazyDelegatingInputStream extends LazyDelegatingInputStream {\n\n\t\tprivate int count;\n\n\t\t@Override\n\t\tprotected InputStream getDelegateInputStream() throws IOException {\n\t\t\tthis.count++;\n\t\t\treturn LazyDelegatingInputStreamTests.this.delegate;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/OptimizationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Optimizations}.\n *\n * @author Phillip Webb\n */\nclass OptimizationsTests {\n\n\t@AfterEach\n\tvoid reset() {\n\t\tOptimizations.disable();\n\t}\n\n\t@Test\n\tvoid defaultIsNotEnabled() {\n\t\tassertThat(Optimizations.isEnabled()).isFalse();\n\t\tassertThat(Optimizations.isEnabled(true)).isFalse();\n\t\tassertThat(Optimizations.isEnabled(false)).isFalse();\n\t}\n\n\t@Test\n\tvoid enableWithReadContentsEnables() {\n\t\tOptimizations.enable(true);\n\t\tassertThat(Optimizations.isEnabled()).isTrue();\n\t\tassertThat(Optimizations.isEnabled(true)).isTrue();\n\t\tassertThat(Optimizations.isEnabled(false)).isFalse();\n\t}\n\n\t@Test\n\tvoid enableWithoutReadContentsEnables() {\n\t\tOptimizations.enable(false);\n\t\tassertThat(Optimizations.isEnabled()).isTrue();\n\t\tassertThat(Optimizations.isEnabled(true)).isFalse();\n\t\tassertThat(Optimizations.isEnabled(false)).isTrue();\n\t}\n\n\t@Test\n\tvoid enableIsByThread() throws InterruptedException {\n\t\tOptimizations.enable(true);\n\t\tboolean[] enabled = new boolean[1];\n\t\tThread thread = new Thread(() -> enabled[0] = Optimizations.isEnabled());\n\t\tthread.start();\n\t\tthread.join();\n\t\tassertThat(enabled[0]).isFalse();\n\t}\n\n\t@Test\n\tvoid disableDisables() {\n\t\tOptimizations.enable(true);\n\t\tOptimizations.disable();\n\t\tassertThat(Optimizations.isEnabled()).isFalse();\n\t\tassertThat(Optimizations.isEnabled(true)).isFalse();\n\t\tassertThat(Optimizations.isEnabled(false)).isFalse();\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/UrlJarEntryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link UrlJarEntry}.\n *\n * @author Phillip Webb\n */\nclass UrlJarEntryTests {\n\n\t@Test\n\tvoid ofWhenEntryIsNullReturnsNull() {\n\t\tassertThat(UrlJarEntry.of(null, null)).isNull();\n\t}\n\n\t@Test\n\tvoid ofReturnsUrlJarEntry() {\n\t\tJarEntry entry = new JarEntry(\"test\");\n\t\tassertThat(UrlJarEntry.of(entry, null)).isNotNull();\n\n\t}\n\n\t@Test\n\tvoid getAttributesDelegatesToUrlJarManifest() throws Exception {\n\t\tJarEntry entry = new JarEntry(\"test\");\n\t\tUrlJarManifest manifest = mock(UrlJarManifest.class);\n\t\tAttributes attributes = mock(Attributes.class);\n\t\tgiven(manifest.getEntryAttributes(any())).willReturn(attributes);\n\t\tassertThat(UrlJarEntry.of(entry, manifest).getAttributes()).isSameAs(attributes);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/UrlJarFileFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.net.InetSocketAddress;\nimport java.net.URL;\nimport java.util.function.Consumer;\nimport java.util.jar.JarFile;\n\nimport com.sun.net.httpserver.HttpServer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UrlJarFileFactory}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass UrlJarFileFactoryTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate final UrlJarFileFactory factory = new UrlJarFileFactory();\n\n\t@Mock\n\tprivate Consumer<JarFile> closeAction;\n\n\t@BeforeAll\n\tstatic void registerHandlers() {\n\t\tHandlers.register();\n\t}\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockitoAnnotations.openMocks(this);\n\t}\n\n\t@Test\n\tvoid createJarFileWhenLocalFile() throws Throwable {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tURL url = file.toURI().toURL();\n\t\tJarFile jarFile = this.factory.createJarFile(url, this.closeAction);\n\t\tassertThat(jarFile).isInstanceOf(UrlJarFile.class);\n\t\tassertThat(jarFile).hasFieldOrPropertyWithValue(\"closeAction\", this.closeAction);\n\t}\n\n\t@Test\n\tvoid createJarFileWhenNested() throws Throwable {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tURL url = new URL(\"nested:\" + file.getPath() + \"/!nested.jar\");\n\t\tJarFile jarFile = this.factory.createJarFile(url, this.closeAction);\n\t\tassertThat(jarFile).isInstanceOf(UrlNestedJarFile.class);\n\t\tassertThat(jarFile).hasFieldOrPropertyWithValue(\"closeAction\", this.closeAction);\n\t}\n\n\t@Test\n\tvoid createJarFileWhenStream() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tHttpServer server = HttpServer.create(new InetSocketAddress(0), 0);\n\t\tserver.createContext(\"/test\", (exchange) -> {\n\t\t\texchange.sendResponseHeaders(200, file.length());\n\t\t\ttry (InputStream in = new FileInputStream(file)) {\n\t\t\t\tin.transferTo(exchange.getResponseBody());\n\t\t\t}\n\t\t\texchange.close();\n\t\t});\n\t\tserver.start();\n\t\ttry {\n\t\t\tURL url = new URL(\"http://localhost:\" + server.getAddress().getPort() + \"/test\");\n\t\t\tJarFile jarFile = this.factory.createJarFile(url, this.closeAction);\n\t\t\tassertThat(jarFile).isInstanceOf(UrlJarFile.class);\n\t\t\tassertThat(jarFile).hasFieldOrPropertyWithValue(\"closeAction\", this.closeAction);\n\t\t}\n\t\tfinally {\n\t\t\tserver.stop(0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid createWhenHasRuntimeRef() {\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/UrlJarFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.util.function.Consumer;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link UrlJarFile}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass UrlJarFileTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate UrlJarFile jarFile;\n\n\t@Mock\n\tprivate Consumer<JarFile> closeAction;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tMockitoAnnotations.openMocks(this);\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tthis.jarFile = new UrlJarFile(file, Runtime.version(), this.closeAction);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() throws Exception {\n\t\tthis.jarFile.close();\n\t}\n\n\t@Test\n\tvoid getEntryWhenNotfoundReturnsNull() {\n\t\tassertThat(this.jarFile.getEntry(\"missing\")).isNull();\n\t}\n\n\t@Test\n\tvoid getEntryWhenFoundReturnsUrlJarEntry() {\n\t\tassertThat(this.jarFile.getEntry(\"1.dat\")).isInstanceOf(UrlJarEntry.class);\n\t}\n\n\t@Test\n\tvoid getManifestReturnsNewCopy() throws Exception {\n\t\tManifest manifest1 = this.jarFile.getManifest();\n\t\tManifest manifest2 = this.jarFile.getManifest();\n\t\tassertThat(manifest1).isNotSameAs(manifest2);\n\t}\n\n\t@Test\n\tvoid closeCallsCloseAction() throws Exception {\n\t\tthis.jarFile.close();\n\t\tthen(this.closeAction).should().accept(this.jarFile);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/UrlJarFilesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.jar.JarFile;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link UrlJarFiles}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass UrlJarFilesTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate UrlJarFileFactory factory = mock(UrlJarFileFactory.class);\n\n\tprivate final UrlJarFiles jarFiles = new UrlJarFiles(this.factory);\n\n\tprivate File file;\n\n\tprivate URL url;\n\n\t@BeforeAll\n\tstatic void registerHandlers() {\n\t\tHandlers.register();\n\t}\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.temp, \"test.jar\");\n\t\tthis.url = new URL(\"nested:\" + this.file.getAbsolutePath() + \"/!nested.jar\");\n\t\tTestJar.create(this.file);\n\t}\n\n\t@Test\n\tvoid getOrCreateWhenNotUsingCachesAlwaysCreatesNewJarFile() throws Exception {\n\t\tgiven(this.factory.createJarFile(any(), any())).willCallRealMethod();\n\t\tJarFile jarFile1 = this.jarFiles.getOrCreate(false, this.url);\n\t\tJarFile jarFile2 = this.jarFiles.getOrCreate(false, this.url);\n\t\tJarFile jarFile3 = this.jarFiles.getOrCreate(false, this.url);\n\t\tassertThat(jarFile1).isNotSameAs(jarFile2).isNotSameAs(jarFile3);\n\t}\n\n\t@Test\n\tvoid getOrCreateWhenUsingCachingReturnsCachedWhenAvailable() throws Exception {\n\t\tgiven(this.factory.createJarFile(any(), any())).willCallRealMethod();\n\t\tJarFile jarFile1 = this.jarFiles.getOrCreate(true, this.url);\n\t\tthis.jarFiles.cacheIfAbsent(true, this.url, jarFile1);\n\t\tJarFile jarFile2 = this.jarFiles.getOrCreate(true, this.url);\n\t\tJarFile jarFile3 = this.jarFiles.getOrCreate(true, this.url);\n\t\tassertThat(jarFile1).isSameAs(jarFile2).isSameAs(jarFile3);\n\t}\n\n\t@Test\n\tvoid getCachedWhenNotCachedReturnsNull() {\n\t\tassertThat(this.jarFiles.getCached(this.url)).isNull();\n\t}\n\n\t@Test\n\tvoid getCachedWhenCachedReturnsCachedJar() throws Exception {\n\t\tgiven(this.factory.createJarFile(any(), any())).willCallRealMethod();\n\t\tJarFile jarFile = this.factory.createJarFile(this.url, null);\n\t\tthis.jarFiles.cacheIfAbsent(true, this.url, jarFile);\n\t\tassertThat(this.jarFiles.getCached(this.url)).isSameAs(jarFile);\n\t}\n\n\t@Test\n\tvoid cacheIfAbsentWhenNotUsingCachesDoesNotCacheAndReturnsFalse() throws Exception {\n\t\tgiven(this.factory.createJarFile(any(), any())).willCallRealMethod();\n\t\tJarFile jarFile = this.factory.createJarFile(this.url, null);\n\t\tthis.jarFiles.cacheIfAbsent(false, this.url, jarFile);\n\t\tassertThat(this.jarFiles.getCached(this.url)).isNull();\n\t}\n\n\t@Test\n\tvoid cacheIfAbsentWhenUsingCachingAndNotAlreadyCachedCachesAndReturnsTrue() throws Exception {\n\t\tgiven(this.factory.createJarFile(any(), any())).willCallRealMethod();\n\t\tJarFile jarFile = this.factory.createJarFile(this.url, null);\n\t\tassertThat(this.jarFiles.cacheIfAbsent(true, this.url, jarFile)).isTrue();\n\t\tassertThat(this.jarFiles.getCached(this.url)).isSameAs(jarFile);\n\t}\n\n\t@Test\n\tvoid cacheIfAbsentWhenUsingCachingAndAlreadyCachedLeavesCacheAndReturnsFalse() throws Exception {\n\t\tgiven(this.factory.createJarFile(any(), any())).willCallRealMethod();\n\t\tJarFile jarFile1 = this.factory.createJarFile(this.url, null);\n\t\tJarFile jarFile2 = this.factory.createJarFile(this.url, null);\n\t\tassertThat(this.jarFiles.cacheIfAbsent(true, this.url, jarFile1)).isTrue();\n\t\tassertThat(this.jarFiles.cacheIfAbsent(true, this.url, jarFile2)).isFalse();\n\t\tassertThat(this.jarFiles.getCached(this.url)).isSameAs(jarFile1);\n\t}\n\n\t@Test\n\tvoid closeIfNotCachedWhenNotCachedClosesJarFile() throws Exception {\n\t\tJarFile jarFile = mock(JarFile.class);\n\t\tthis.jarFiles.closeIfNotCached(this.url, jarFile);\n\t\tthen(jarFile).should().close();\n\t}\n\n\t@Test\n\tvoid closeIfNotCachedWhenCachedDoesNotCloseJarFile() throws Exception {\n\t\tJarFile jarFile = mock(JarFile.class);\n\t\tthis.jarFiles.cacheIfAbsent(true, this.url, jarFile);\n\t\tthis.jarFiles.closeIfNotCached(this.url, jarFile);\n\t\tthen(jarFile).should(never()).close();\n\t}\n\n\t@Test\n\tvoid reconnectReconnectsAndAppliesUseCaches() throws Exception {\n\t\tJarFile jarFile = mock(JarFile.class);\n\t\tthis.jarFiles.cacheIfAbsent(true, this.url, jarFile);\n\t\tURLConnection existingConnection = mock(URLConnection.class);\n\t\tgiven(existingConnection.getUseCaches()).willReturn(true);\n\t\tURLConnection connection = this.jarFiles.reconnect(jarFile, existingConnection);\n\t\tassertThat(connection).isNotSameAs(existingConnection);\n\t\tassertThat(connection.getUseCaches()).isTrue();\n\t}\n\n\t@Test\n\tvoid reconnectWhenExistingConnectionIsNullReconnects() throws Exception {\n\t\tJarFile jarFile = mock(JarFile.class);\n\t\tthis.jarFiles.cacheIfAbsent(true, this.url, jarFile);\n\t\tURLConnection connection = this.jarFiles.reconnect(jarFile, null);\n\t\tassertThat(connection).isNotNull();\n\t\tassertThat(connection.getUseCaches()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/UrlJarManifestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.IOException;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.Manifest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.net.protocol.jar.UrlJarManifest.ManifestSupplier;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link UrlJarManifest}.\n *\n * @author Phillip Webb\n */\nclass UrlJarManifestTests {\n\n\t@Test\n\tvoid getWhenSuppliedManifestIsNullReturnsNull() throws Exception {\n\t\tUrlJarManifest urlJarManifest = new UrlJarManifest(() -> null);\n\t\tassertThat(urlJarManifest.get()).isNull();\n\t}\n\n\t@Test\n\tvoid getAlwaysReturnsDeepCopy() throws Exception {\n\t\tManifest manifest = new Manifest();\n\t\tUrlJarManifest urlJarManifest = new UrlJarManifest(() -> manifest);\n\t\tmanifest.getMainAttributes().putValue(\"test\", \"one\");\n\t\tmanifest.getEntries().put(\"spring\", new Attributes());\n\t\tManifest copy = urlJarManifest.get();\n\t\tassertThat(copy).isNotSameAs(manifest);\n\t\tmanifest.getMainAttributes().clear();\n\t\tmanifest.getEntries().clear();\n\t\tassertThat(copy.getMainAttributes()).isNotEmpty();\n\t\tassertThat(copy.getAttributes(\"spring\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid getEntryAttributesWhenSuppliedManifestIsNullReturnsNull() throws Exception {\n\t\tUrlJarManifest urlJarManifest = new UrlJarManifest(() -> null);\n\t\tassertThat(urlJarManifest.getEntryAttributes(new JarEntry(\"test\"))).isNull();\n\t}\n\n\t@Test\n\tvoid getEntryAttributesReturnsDeepCopy() throws Exception {\n\t\tManifest manifest = new Manifest();\n\t\tUrlJarManifest urlJarManifest = new UrlJarManifest(() -> manifest);\n\t\tAttributes attributes = new Attributes();\n\t\tattributes.putValue(\"test\", \"test\");\n\t\tmanifest.getEntries().put(\"spring\", attributes);\n\t\tAttributes copy = urlJarManifest.getEntryAttributes(new JarEntry(\"spring\"));\n\t\tassertThat(copy).isNotSameAs(attributes);\n\t\tattributes.clear();\n\t\tassertThat(copy.getValue(\"test\")).isNotNull();\n\n\t}\n\n\t@Test\n\tvoid supplierIsOnlyCalledOnce() throws IOException {\n\t\tManifestSupplier supplier = mock(ManifestSupplier.class);\n\t\tUrlJarManifest urlJarManifest = new UrlJarManifest(supplier);\n\t\turlJarManifest.get();\n\t\turlJarManifest.get();\n\t\tthen(supplier).should(times(1)).getManifest();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/jar/UrlNestedJarFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.jar;\n\nimport java.io.File;\nimport java.util.function.Consumer;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link UrlNestedJarFile}.\n *\n * @author Phillip Webb\n */\nclass UrlNestedJarFileTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate UrlNestedJarFile jarFile;\n\n\t@Mock\n\tprivate Consumer<JarFile> closeAction;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tMockitoAnnotations.openMocks(this);\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tthis.jarFile = new UrlNestedJarFile(file, \"multi-release.jar\", Runtime.version(), this.closeAction);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() throws Exception {\n\t\tthis.jarFile.close();\n\t}\n\n\t@Test\n\tvoid getEntryWhenNotfoundReturnsNull() {\n\t\tassertThat(this.jarFile.getEntry(\"missing\")).isNull();\n\t}\n\n\t@Test\n\tvoid getEntryWhenFoundReturnsUrlJarEntry() {\n\t\tassertThat(this.jarFile.getEntry(\"multi-release.dat\")).isInstanceOf(UrlJarEntry.class);\n\t}\n\n\t@Test\n\tvoid getManifestReturnsNewCopy() throws Exception {\n\t\tManifest manifest1 = this.jarFile.getManifest();\n\t\tManifest manifest2 = this.jarFile.getManifest();\n\t\tassertThat(manifest1).isNotSameAs(manifest2);\n\t}\n\n\t@Test\n\tvoid closeCallsCloseAction() throws Exception {\n\t\tthis.jarFile.close();\n\t\tthen(this.closeAction).should().accept(this.jarFile);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/HandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.File;\nimport java.net.URL;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link Handler}.\n *\n * @author Phillip Webb\n */\nclass HandlerTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@BeforeAll\n\tstatic void registerHandlers() {\n\t\tHandlers.register();\n\t}\n\n\t@Test\n\tvoid openConnectionReturnsNestedUrlConnection() throws Exception {\n\t\tURL url = new URL(\"nested:\" + this.temp.getAbsolutePath() + \"/!nested.jar\");\n\t\tassertThat(url.openConnection()).isInstanceOf(NestedUrlConnection.class);\n\t}\n\n\t@Test\n\tvoid assertUrlIsNotMalformedWhenUrlIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Handler.assertUrlIsNotMalformed(null))\n\t\t\t.withMessageContaining(\"'url' must not be null\");\n\t}\n\n\t@Test\n\tvoid assertUrlIsNotMalformedWhenUrlIsNotNestedThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Handler.assertUrlIsNotMalformed(\"file:\"))\n\t\t\t.withMessageContaining(\"must use 'nested'\");\n\t}\n\n\t@Test\n\tvoid assertUrlIsNotMalformedWhenUrlIsValidDoesNotThrowException() {\n\t\tString url = \"nested:\" + this.temp.getAbsolutePath() + \"/!nested.jar\";\n\t\tassertThatNoException().isThrownBy(() -> Handler.assertUrlIsNotMalformed(url));\n\t}\n\n\t@Test\n\tvoid getHostAddressIsNull() throws Exception {\n\t\t// gh-46063\n\t\tString url = \"nested:\" + this.temp.getAbsolutePath() + \"/!nested.jar\";\n\t\tassertThat(new Handler().getHostAddress(new URL(url))).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/NestedLocationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URI;\nimport java.net.URL;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link NestedLocation}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass NestedLocationTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@BeforeAll\n\tstatic void registerHandlers() {\n\t\tHandlers.register();\n\t}\n\n\t@Test\n\tvoid createWhenPathIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new NestedLocation(null, \"nested.jar\"))\n\t\t\t.withMessageContaining(\"'path' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenNestedEntryNameIsNull() {\n\t\tNestedLocation location = new NestedLocation(Path.of(\"test.jar\"), null);\n\t\tassertThat(location.path().toString()).contains(\"test.jar\");\n\t\tassertThat(location.nestedEntryName()).isNull();\n\t}\n\n\t@Test\n\tvoid createWhenNestedEntryNameIsEmpty() {\n\t\tNestedLocation location = new NestedLocation(Path.of(\"test.jar\"), \"\");\n\t\tassertThat(location.path().toString()).contains(\"test.jar\");\n\t\tassertThat(location.nestedEntryName()).isNull();\n\t}\n\n\t@Test\n\tvoid fromUrlWhenUrlIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> NestedLocation.fromUrl(null))\n\t\t\t.withMessageContaining(\"'url' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromUrlWhenNotNestedProtocolThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> NestedLocation.fromUrl(new URL(\"file://test.jar\")))\n\t\t\t.withMessageContaining(\"must use 'nested' protocol\");\n\t}\n\n\t@Test\n\tvoid fromUrlWhenNoPathThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> NestedLocation.fromUrl(new URL(\"nested:\")))\n\t\t\t.withMessageContaining(\"'location' must not be empty\");\n\t}\n\n\t@Test\n\tvoid fromUrlWhenNoSeparator() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tNestedLocation location = NestedLocation.fromUrl(new URL(\"nested:\" + file.getAbsolutePath() + \"/\"));\n\t\tassertThat(location.path()).isEqualTo(file.toPath());\n\t\tassertThat(location.nestedEntryName()).isNull();\n\t}\n\n\t@Test\n\tvoid fromUrlReturnsNestedLocation() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tNestedLocation location = NestedLocation\n\t\t\t.fromUrl(new URL(\"nested:\" + file.getAbsolutePath() + \"/!lib/nested.jar\"));\n\t\tassertThat(location.path()).isEqualTo(file.toPath());\n\t\tassertThat(location.nestedEntryName()).isEqualTo(\"lib/nested.jar\");\n\t}\n\n\t@Test\n\tvoid fromUriWhenUrlIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> NestedLocation.fromUri(null))\n\t\t\t.withMessageContaining(\"'uri' must not be null\");\n\t}\n\n\t@Test\n\tvoid fromUriWhenNotNestedProtocolThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> NestedLocation.fromUri(new URI(\"file://test.jar\")))\n\t\t\t.withMessageContaining(\"must use 'nested' scheme\");\n\t}\n\n\t@Test\n\t@Disabled\n\tvoid fromUriWhenNoSeparator() throws Exception {\n\t\tNestedLocation location = NestedLocation.fromUri(new URI(\"nested:test.jar!nested.jar\"));\n\t\tassertThat(location.path().toString()).contains(\"test.jar!nested.jar\");\n\t\tassertThat(location.nestedEntryName()).isNull();\n\t}\n\n\t@Test\n\tvoid fromUriReturnsNestedLocation() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tNestedLocation location = NestedLocation\n\t\t\t.fromUri(new URI(\"nested:\" + file.getAbsoluteFile().toURI().getPath() + \"/!lib/nested.jar\"));\n\t\tassertThat(location.path()).isEqualTo(file.toPath());\n\t\tassertThat(location.nestedEntryName()).isEqualTo(\"lib/nested.jar\");\n\t}\n\n\t@Test\n\t@EnabledOnOs(OS.WINDOWS)\n\tvoid windowsUncPathIsHandledCorrectly() throws MalformedURLException {\n\t\tNestedLocation location = NestedLocation.fromUrl(\n\t\t\t\tnew URL(\"nested://localhost/c$/dev/temp/demo/build/libs/demo-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/\"));\n\t\tassertThat(location.path()).asString()\n\t\t\t.isEqualTo(\"\\\\\\\\localhost\\\\c$\\\\dev\\\\temp\\\\demo\\\\build\\\\libs\\\\demo-0.0.1-SNAPSHOT.jar\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/protocol/nested/NestedUrlConnectionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.protocol.nested;\n\nimport java.io.File;\nimport java.io.FilePermission;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.security.Permission;\nimport java.time.Instant;\nimport java.time.temporal.ChronoField;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.loader.net.protocol.Handlers;\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.loader.zip.ZipContent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NestedUrlConnection}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass NestedUrlConnectionTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate File jarFile;\n\n\tprivate URL url;\n\n\t@BeforeAll\n\tstatic void registerHandlers() {\n\t\tHandlers.register();\n\t}\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.jarFile = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(this.jarFile);\n\t\tthis.url = new URL(\"nested:\" + this.jarFile.getAbsolutePath() + \"/!nested.jar\");\n\t}\n\n\t@Test\n\tvoid getContentLengthWhenContentLengthMoreThanMaxIntReturnsMinusOne() {\n\t\tNestedUrlConnection connection = mock(NestedUrlConnection.class);\n\t\tgiven(connection.getContentLength()).willCallRealMethod();\n\t\tgiven(connection.getContentLengthLong()).willReturn((long) Integer.MAX_VALUE + 1);\n\t\tassertThat(connection.getContentLength()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid getContentLengthGetsContentLength() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\ttry (ZipContent zipContent = ZipContent.open(this.jarFile.toPath())) {\n\t\t\tint expectedSize = zipContent.getEntry(\"nested.jar\").getUncompressedSize();\n\t\t\tassertThat(connection.getContentLength()).isEqualTo(expectedSize);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getContentLengthLongReturnsContentLength() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\ttry (ZipContent zipContent = ZipContent.open(this.jarFile.toPath())) {\n\t\t\tint expectedSize = zipContent.getEntry(\"nested.jar\").getUncompressedSize();\n\t\t\tassertThat(connection.getContentLengthLong()).isEqualTo(expectedSize);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getContentTypeReturnsJavaJar() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tassertThat(connection.getContentType()).isEqualTo(\"x-java/jar\");\n\t}\n\n\t@Test\n\tvoid getLastModifiedReturnsFileLastModified() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tassertThat(connection.getLastModified()).isEqualTo(this.jarFile.lastModified());\n\t}\n\n\t@Test\n\tvoid getPermissionReturnsFilePermission() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tPermission permission = connection.getPermission();\n\t\tassertThat(permission).isInstanceOf(FilePermission.class);\n\t\tassertThat(permission.getName()).isEqualTo(this.jarFile.getCanonicalPath());\n\t}\n\n\t@Test\n\tvoid getInputStreamReturnsContentOfNestedJar() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tassertHasSameContentAsNestedJar(connection);\n\t}\n\n\t@Test\n\tvoid inputStreamCloseCleansResource() throws Exception {\n\t\tCleaner cleaner = mock(Cleaner.class);\n\t\tCleanable cleanable = mock(Cleanable.class);\n\t\tgiven(cleaner.register(any(), any())).willReturn(cleanable);\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url, cleaner);\n\t\tconnection.getInputStream().close();\n\t\tthen(cleanable).should().clean();\n\t\tArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);\n\t\tthen(cleaner).should().register(any(), actionCaptor.capture());\n\t\tactionCaptor.getValue().run();\n\t}\n\n\t@Test // gh-38204\n\tvoid getLastModifiedReturnsFileModifiedTime() throws Exception {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tassertThat(connection.getLastModified()).isEqualTo(this.jarFile.lastModified());\n\t}\n\n\t@Test // gh-38204\n\tvoid getLastModifiedHeaderReturnsFileModifiedTime() throws IOException {\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tURLConnection fileConnection = this.jarFile.toURI().toURL().openConnection();\n\t\ttry {\n\t\t\tassertThat(connection.getHeaderFieldDate(\"last-modified\", 0))\n\t\t\t\t.isEqualTo(withoutNanos(this.jarFile.lastModified()))\n\t\t\t\t.isEqualTo(fileConnection.getHeaderFieldDate(\"last-modified\", 0));\n\t\t}\n\t\tfinally {\n\t\t\tfileConnection.getInputStream().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid createDecodesUrlPath() throws Exception {\n\t\tFile withSpace = new File(this.temp, \"te st\");\n\t\twithSpace.mkdirs();\n\t\tthis.jarFile = new File(withSpace, \"test.jar\");\n\t\tTestJar.create(this.jarFile);\n\t\tthis.url = new URL(\"nested:\" + this.jarFile.toURI().getRawPath() + \"/!nested.jar\");\n\t\tassertThat(this.url.toString()).contains(\"%20\");\n\t\tNestedUrlConnection connection = new NestedUrlConnection(this.url);\n\t\tassertHasSameContentAsNestedJar(connection);\n\t\tassertThat(connection.getLastModified()).isEqualTo(this.jarFile.lastModified());\n\t}\n\n\tprivate void assertHasSameContentAsNestedJar(NestedUrlConnection connection) throws IOException {\n\t\ttry (InputStream actual = connection.getInputStream()) {\n\t\t\ttry (ZipContent zipContent = ZipContent.open(this.jarFile.toPath())) {\n\t\t\t\ttry (InputStream expected = zipContent.getEntry(\"nested.jar\").openContent().asInputStream()) {\n\t\t\t\t\tassertThat(actual).hasSameContentAs(expected);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate long withoutNanos(long epochMilli) {\n\t\treturn Instant.ofEpochMilli(epochMilli).with(ChronoField.NANO_OF_SECOND, 0).toEpochMilli();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/net/util/UrlDecoderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.net.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UrlDecoder}.\n *\n * @author Phillip Webb\n */\nclass UrlDecoderTests {\n\n\t@Test\n\tvoid decodeWhenBasicString() {\n\t\tassertThat(UrlDecoder.decode(\"a/b/C.class\")).isEqualTo(\"a/b/C.class\");\n\t}\n\n\t@Test\n\tvoid decodeWhenHasSingleByteEncodedCharacters() {\n\t\tassertThat(UrlDecoder.decode(\"%61/%62/%43.class\")).isEqualTo(\"a/b/C.class\");\n\t}\n\n\t@Test\n\tvoid decodeWhenHasDoubleByteEncodedCharacters() {\n\t\tassertThat(UrlDecoder.decode(\"%c3%a1/b/C.class\")).isEqualTo(\"\\u00e1/b/C.class\");\n\t}\n\n\t@Test\n\tvoid decodeWhenHasMixtureOfEncodedAndUnencodedDoubleByteCharacters() {\n\t\tassertThat(UrlDecoder.decode(\"%c3%a1/b/\\u00c7.class\")).isEqualTo(\"\\u00e1/b/\\u00c7.class\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/NestedByteChannelTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.channels.NonWritableChannelException;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.CRC32;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.loader.ref.Cleaner;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\nimport org.springframework.boot.loader.zip.FileChannelDataBlockManagedFileChannel;\nimport org.springframework.boot.loader.zip.ZipContent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NestedByteChannel}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass NestedByteChannelTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate File file;\n\n\tprivate NestedByteChannel channel;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(this.file);\n\t\tthis.channel = new NestedByteChannel(this.file.toPath(), \"nested.jar\");\n\t}\n\n\t@AfterEach\n\tvoid cleanup() throws Exception {\n\t\tthis.channel.close();\n\t}\n\n\t@Test\n\tvoid isOpenWhenOpenReturnsTrue() {\n\t\tassertThat(this.channel.isOpen()).isTrue();\n\t}\n\n\t@Test\n\tvoid isOpenWhenClosedReturnsFalse() throws Exception {\n\t\tthis.channel.close();\n\t\tassertThat(this.channel.isOpen()).isFalse();\n\t}\n\n\t@Test\n\tvoid closeCleansResources() throws Exception {\n\t\tCleaner cleaner = mock(Cleaner.class);\n\t\tCleanable cleanable = mock(Cleanable.class);\n\t\tgiven(cleaner.register(any(), any())).willReturn(cleanable);\n\t\tNestedByteChannel channel = new NestedByteChannel(this.file.toPath(), \"nested.jar\", cleaner);\n\t\tchannel.close();\n\t\tthen(cleanable).should().clean();\n\t\tArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);\n\t\tthen(cleaner).should().register(any(), actionCaptor.capture());\n\t\tactionCaptor.getValue().run();\n\t}\n\n\t@Test\n\tvoid closeWhenAlreadyClosedDoesNothing() throws IOException {\n\t\tCleaner cleaner = mock(Cleaner.class);\n\t\tCleanable cleanable = mock(Cleanable.class);\n\t\tgiven(cleaner.register(any(), any())).willReturn(cleanable);\n\t\tNestedByteChannel channel = new NestedByteChannel(this.file.toPath(), \"nested.jar\", cleaner);\n\t\tchannel.close();\n\t\tthen(cleanable).should().clean();\n\t\tArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);\n\t\tthen(cleaner).should().register(any(), actionCaptor.capture());\n\t\tactionCaptor.getValue().run();\n\t\tchannel.close();\n\t\tthen(cleaner).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid readReadsBytesAndIncrementsPosition() throws IOException {\n\t\tByteBuffer dst = ByteBuffer.allocate(10);\n\t\tassertThat(this.channel.position()).isZero();\n\t\tthis.channel.read(dst);\n\t\tassertThat(this.channel.position()).isEqualTo(10L);\n\t\tassertThat(dst.array()).isNotEqualTo(ByteBuffer.allocate(10).array());\n\t}\n\n\t@Test // gh-38592\n\tvoid readReadsAsManyBytesAsPossible() throws Exception {\n\t\t// ZipFileSystem checks that the number of bytes read matches an expected value\n\t\t// ...if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR)\n\t\t// but the readFullyAt assumes that all remaining bytes are attempted to be read\n\t\t// This doesn't seem to exactly match the contract of ReadableByteChannel.read\n\t\t// which states \"A read operation might not fill the buffer, and in fact it might\n\t\t// not read any bytes at all\", but we need to match ZipFileSystem's expectations\n\t\tint size = FileChannelDataBlockManagedFileChannel.BUFFER_SIZE * 2;\n\t\tbyte[] data = new byte[size];\n\t\tthis.file = new File(this.temp, \"testread.jar\");\n\t\tFileOutputStream fileOutputStream = new FileOutputStream(this.file);\n\t\ttry (JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream)) {\n\t\t\tJarEntry nestedEntry = new JarEntry(\"data\");\n\t\t\tnestedEntry.setSize(size);\n\t\t\tnestedEntry.setCompressedSize(size);\n\t\t\tCRC32 crc32 = new CRC32();\n\t\t\tcrc32.update(data);\n\t\t\tnestedEntry.setCrc(crc32.getValue());\n\t\t\tnestedEntry.setMethod(ZipEntry.STORED);\n\t\t\tjarOutputStream.putNextEntry(nestedEntry);\n\t\t\tjarOutputStream.write(data);\n\t\t\tjarOutputStream.closeEntry();\n\t\t}\n\t\tthis.channel = new NestedByteChannel(this.file.toPath(), null);\n\t\tByteBuffer buffer = ByteBuffer.allocate((int) this.file.length());\n\t\tassertThat(this.channel.read(buffer)).isEqualTo(buffer.capacity());\n\t\tassertThat(this.file).binaryContent().isEqualTo(buffer.array());\n\t}\n\n\t@Test\n\tvoid writeThrowsException() {\n\t\tassertThatExceptionOfType(NonWritableChannelException.class)\n\t\t\t.isThrownBy(() -> this.channel.write(ByteBuffer.allocate(10)));\n\t}\n\n\t@Test\n\tvoid positionWhenClosedThrowsException() throws Exception {\n\t\tthis.channel.close();\n\t\tassertThatExceptionOfType(ClosedChannelException.class).isThrownBy(() -> this.channel.position());\n\t}\n\n\t@Test\n\tvoid positionWhenOpenReturnsPosition() throws Exception {\n\t\tassertThat(this.channel.position()).isEqualTo(0L);\n\t}\n\n\t@Test\n\tvoid positionWithLongWhenClosedThrowsException() throws Exception {\n\t\tthis.channel.close();\n\t\tassertThatExceptionOfType(ClosedChannelException.class).isThrownBy(() -> this.channel.position(0L));\n\t}\n\n\t@Test\n\tvoid positionWithLongWhenLessThanZeroThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.channel.position(-1));\n\t}\n\n\t@Test\n\tvoid positionWithLongWhenEqualToSizeThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.channel.position(this.channel.size()));\n\t}\n\n\t@Test\n\tvoid positionWithLongWhenOpenUpdatesPosition() throws Exception {\n\t\tByteBuffer dst1 = ByteBuffer.allocate(10);\n\t\tByteBuffer dst2 = ByteBuffer.allocate(10);\n\t\tdst2.position(1);\n\t\tthis.channel.read(dst1);\n\t\tthis.channel.position(1);\n\t\tthis.channel.read(dst2);\n\t\tdst2.array()[0] = dst1.array()[0];\n\t\tassertThat(dst1.array()).isEqualTo(dst2.array());\n\t}\n\n\t@Test\n\tvoid sizeWhenClosedThrowsException() throws Exception {\n\t\tthis.channel.close();\n\t\tassertThatExceptionOfType(ClosedChannelException.class).isThrownBy(() -> this.channel.size());\n\t}\n\n\t@Test\n\tvoid sizeWhenOpenReturnsSize() throws IOException {\n\t\ttry (ZipContent content = ZipContent.open(this.file.toPath())) {\n\t\t\tassertThat(this.channel.size()).isEqualTo(content.getEntry(\"nested.jar\").getUncompressedSize());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/NestedFileStoreTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.File;\nimport java.nio.file.FileStore;\nimport java.nio.file.Path;\nimport java.nio.file.attribute.BasicFileAttributeView;\nimport java.nio.file.attribute.FileStoreAttributeView;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NestedFileStore}.\n *\n * @author Phillip Webb\n */\nclass NestedFileStoreTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate NestedFileSystemProvider provider;\n\n\tprivate Path jarPath;\n\n\tprivate NestedFileSystem fileSystem;\n\n\tprivate TestNestedFileStore fileStore;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.provider = new NestedFileSystemProvider();\n\t\tthis.jarPath = new File(this.temp, \"test.jar\").toPath();\n\t\tthis.fileSystem = new NestedFileSystem(this.provider, this.jarPath);\n\t\tthis.fileStore = new TestNestedFileStore(this.fileSystem);\n\t}\n\n\t@Test\n\tvoid nameReturnsName() {\n\t\tassertThat(this.fileStore.name()).isEqualTo(this.jarPath.toAbsolutePath().toString());\n\t}\n\n\t@Test\n\tvoid typeReturnsNestedFs() {\n\t\tassertThat(this.fileStore.type()).isEqualTo(\"nestedfs\");\n\t}\n\n\t@Test\n\tvoid isReadOnlyReturnsTrue() {\n\t\tassertThat(this.fileStore.isReadOnly()).isTrue();\n\t}\n\n\t@Test\n\tvoid getTotalSpaceReturnsZero() throws Exception {\n\t\tassertThat(this.fileStore.getTotalSpace()).isZero();\n\t}\n\n\t@Test\n\tvoid getUsableSpaceReturnsZero() throws Exception {\n\t\tassertThat(this.fileStore.getUsableSpace()).isZero();\n\t}\n\n\t@Test\n\tvoid getUnallocatedSpaceReturnsZero() throws Exception {\n\t\tassertThat(this.fileStore.getUnallocatedSpace()).isZero();\n\t}\n\n\t@Test\n\tvoid supportsFileAttributeViewWithClassDelegatesToJarPathFileStore() {\n\t\tFileStore jarFileStore = mock(FileStore.class);\n\t\tgiven(jarFileStore.supportsFileAttributeView(BasicFileAttributeView.class)).willReturn(true);\n\t\tthis.fileStore.setJarPathFileStore(jarFileStore);\n\t\tassertThat(this.fileStore.supportsFileAttributeView(BasicFileAttributeView.class)).isTrue();\n\t\tthen(jarFileStore).should().supportsFileAttributeView(BasicFileAttributeView.class);\n\t}\n\n\t@Test\n\tvoid supportsFileAttributeViewWithStringDelegatesToJarPathFileStore() {\n\t\tFileStore jarFileStore = mock(FileStore.class);\n\t\tgiven(jarFileStore.supportsFileAttributeView(\"basic\")).willReturn(true);\n\t\tthis.fileStore.setJarPathFileStore(jarFileStore);\n\t\tassertThat(this.fileStore.supportsFileAttributeView(\"basic\")).isTrue();\n\t\tthen(jarFileStore).should().supportsFileAttributeView(\"basic\");\n\t}\n\n\t@Test\n\tvoid getFileStoreAttributeViewDelegatesToJarPathFileStore() {\n\t\tFileStore jarFileStore = mock(FileStore.class);\n\t\tTestFileStoreAttributeView attributeView = mock(TestFileStoreAttributeView.class);\n\t\tgiven(jarFileStore.getFileStoreAttributeView(TestFileStoreAttributeView.class)).willReturn(attributeView);\n\t\tthis.fileStore.setJarPathFileStore(jarFileStore);\n\t\tassertThat(this.fileStore.getFileStoreAttributeView(TestFileStoreAttributeView.class)).isEqualTo(attributeView);\n\t\tthen(jarFileStore).should().getFileStoreAttributeView(TestFileStoreAttributeView.class);\n\t}\n\n\t@Test\n\tvoid getAttributeDelegatesToJarPathFileStore() throws Exception {\n\t\tFileStore jarFileStore = mock(FileStore.class);\n\t\tgiven(jarFileStore.getAttribute(\"test\")).willReturn(\"spring\");\n\t\tthis.fileStore.setJarPathFileStore(jarFileStore);\n\t\tassertThat(this.fileStore.getAttribute(\"test\")).isEqualTo(\"spring\");\n\t\tthen(jarFileStore).should().getAttribute(\"test\");\n\t}\n\n\tstatic class TestNestedFileStore extends NestedFileStore {\n\n\t\tTestNestedFileStore(NestedFileSystem fileSystem) {\n\t\t\tsuper(fileSystem);\n\t\t}\n\n\t\tprivate FileStore jarPathFileStore;\n\n\t\tvoid setJarPathFileStore(FileStore jarPathFileStore) {\n\t\t\tthis.jarPathFileStore = jarPathFileStore;\n\t\t}\n\n\t\t@Override\n\t\tprotected FileStore getJarPathFileStore() {\n\t\t\treturn (this.jarPathFileStore != null) ? this.jarPathFileStore : super.getJarPathFileStore();\n\t\t}\n\n\t}\n\n\tabstract static class TestFileStoreAttributeView implements FileStoreAttributeView {\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/NestedFileSystemProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.nio.channels.SeekableByteChannel;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystemAlreadyExistsException;\nimport java.nio.file.FileSystemNotFoundException;\nimport java.nio.file.NoSuchFileException;\nimport java.nio.file.NotDirectoryException;\nimport java.nio.file.Path;\nimport java.nio.file.ReadOnlyFileSystemException;\nimport java.nio.file.StandardOpenOption;\nimport java.nio.file.attribute.BasicFileAttributeView;\nimport java.nio.file.attribute.BasicFileAttributes;\nimport java.nio.file.spi.FileSystemProvider;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NestedFileSystemProvider}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass NestedFileSystemProviderTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate File file;\n\n\tprivate TestNestedFileSystemProvider provider = new TestNestedFileSystemProvider();\n\n\tprivate String uriPrefix;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(this.file);\n\t\tthis.uriPrefix = \"nested:\" + this.file.toURI().getPath() + \"/!\";\n\t}\n\n\t@Test\n\tvoid getSchemeReturnsScheme() {\n\t\tassertThat(this.provider.getScheme()).isEqualTo(\"nested\");\n\t}\n\n\t@Test\n\tvoid newFilesSystemWhenBadUrlThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.provider.newFileSystem(new URI(\"bad:notreal\"), Collections.emptyMap()))\n\t\t\t.withMessageContaining(\"must use 'nested' scheme\");\n\t}\n\n\t@Test\n\tvoid newFileSystemWhenAlreadyExistsThrowsException() throws Exception {\n\t\tthis.provider.newFileSystem(new URI(this.uriPrefix + \"nested.jar\"), null);\n\t\tassertThatExceptionOfType(FileSystemAlreadyExistsException.class)\n\t\t\t.isThrownBy(() -> this.provider.newFileSystem(new URI(this.uriPrefix + \"other.jar\"), null));\n\t}\n\n\t@Test\n\tvoid newFileSystemReturnsFileSystem() throws Exception {\n\t\tFileSystem fileSystem = this.provider.newFileSystem(new URI(this.uriPrefix + \"nested.jar\"), null);\n\t\tassertThat(fileSystem).isInstanceOf(NestedFileSystem.class);\n\t}\n\n\t@Test\n\tvoid getFileSystemWhenBadUrlThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.provider.getFileSystem(new URI(\"bad:notreal\")))\n\t\t\t.withMessageContaining(\"must use 'nested' scheme\");\n\t}\n\n\t@Test\n\tvoid getFileSystemWhenNotCreatedThrowsException() {\n\t\tassertThatExceptionOfType(FileSystemNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.provider.getFileSystem(new URI(this.uriPrefix + \"nested.jar\")));\n\t}\n\n\t@Test\n\tvoid getFileSystemReturnsFileSystem() throws Exception {\n\t\tFileSystem expected = this.provider.newFileSystem(new URI(this.uriPrefix + \"nested.jar\"), null);\n\t\tassertThat(this.provider.getFileSystem(new URI(this.uriPrefix + \"nested.jar\"))).isSameAs(expected);\n\t}\n\n\t@Test\n\tvoid getPathWhenFileSystemExistsReturnsPath() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tthis.provider.newFileSystem(uri, null);\n\t\tassertThat(this.provider.getPath(uri)).isInstanceOf(NestedPath.class);\n\t}\n\n\t@Test\n\tvoid getPathWhenFileSystemDoesNtExistReturnsPath() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tassertThat(this.provider.getPath(uri)).isInstanceOf(NestedPath.class);\n\t}\n\n\t@Test\n\tvoid newByteChannelReturnsByteChannel() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tPath path = this.provider.getPath(uri);\n\t\ttry (SeekableByteChannel byteChannel = this.provider.newByteChannel(path, Set.of(StandardOpenOption.READ))) {\n\t\t\tassertThat(byteChannel).isInstanceOf(NestedByteChannel.class);\n\t\t}\n\t}\n\n\t@Test\n\tvoid newDirectoryStreamThrowsException() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tPath path = this.provider.getPath(uri);\n\t\tassertThatExceptionOfType(NotDirectoryException.class)\n\t\t\t.isThrownBy(() -> this.provider.newDirectoryStream(path, null));\n\t}\n\n\t@Test\n\tvoid createDirectoryThrowsException() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tPath path = this.provider.getPath(uri);\n\t\tassertThatExceptionOfType(ReadOnlyFileSystemException.class)\n\t\t\t.isThrownBy(() -> this.provider.createDirectory(path));\n\t}\n\n\t@Test\n\tvoid deleteThrowsException() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tPath path = this.provider.getPath(uri);\n\t\tassertThatExceptionOfType(ReadOnlyFileSystemException.class).isThrownBy(() -> this.provider.delete(path));\n\t}\n\n\t@Test\n\tvoid copyThrowsException() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tPath path = this.provider.getPath(uri);\n\t\tassertThatExceptionOfType(ReadOnlyFileSystemException.class).isThrownBy(() -> this.provider.copy(path, path));\n\t}\n\n\t@Test\n\tvoid moveThrowsException() throws Exception {\n\t\tURI uri = new URI(this.uriPrefix + \"nested.jar\");\n\t\tPath path = this.provider.getPath(uri);\n\t\tassertThatExceptionOfType(ReadOnlyFileSystemException.class).isThrownBy(() -> this.provider.move(path, path));\n\t}\n\n\t@Test\n\tvoid isSameFileWhenSameReturnsTrue() throws Exception {\n\t\tPath p1 = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tPath p2 = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tassertThat(this.provider.isSameFile(p1, p1)).isTrue();\n\t\tassertThat(this.provider.isSameFile(p1, p2)).isTrue();\n\t}\n\n\t@Test\n\tvoid isSameFileWhenDifferentReturnsFalse() throws Exception {\n\t\tPath p1 = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tPath p2 = this.provider.getPath(new URI(this.uriPrefix + \"other.jar\"));\n\t\tassertThat(this.provider.isSameFile(p1, p2)).isFalse();\n\t}\n\n\t@Test\n\tvoid isHiddenReturnsFalse() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tassertThat(this.provider.isHidden(path)).isFalse();\n\t}\n\n\t@Test\n\tvoid getFileStoreWhenFileDoesNotExistThrowsException() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"missing.jar\"));\n\t\tassertThatExceptionOfType(NoSuchFileException.class).isThrownBy(() -> this.provider.getFileStore(path));\n\t}\n\n\t@Test\n\tvoid getFileStoreReturnsFileStore() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tassertThat(this.provider.getFileStore(path)).isInstanceOf(NestedFileStore.class);\n\t}\n\n\t@Test\n\tvoid checkAccessDelegatesToJarPath() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tPath jarPath = mockJarPath();\n\t\tthis.provider.setMockJarPath(jarPath);\n\t\tthis.provider.checkAccess(path);\n\t\tthen(jarPath.getFileSystem().provider()).should().checkAccess(jarPath);\n\t}\n\n\t@Test\n\tvoid getFileAttributeViewDelegatesToJarPath() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tPath jarPath = mockJarPath();\n\t\tthis.provider.setMockJarPath(jarPath);\n\t\tthis.provider.getFileAttributeView(path, BasicFileAttributeView.class);\n\t\tthen(jarPath.getFileSystem().provider()).should().getFileAttributeView(jarPath, BasicFileAttributeView.class);\n\t}\n\n\t@Test\n\tvoid readAttributesWithTypeDelegatesToJarPath() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tPath jarPath = mockJarPath();\n\t\tthis.provider.setMockJarPath(jarPath);\n\t\tthis.provider.readAttributes(path, BasicFileAttributes.class);\n\t\tthen(jarPath.getFileSystem().provider()).should().readAttributes(jarPath, BasicFileAttributes.class);\n\t}\n\n\t@Test\n\tvoid readAttributesWithNameDelegatesToJarPath() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tPath jarPath = mockJarPath();\n\t\tthis.provider.setMockJarPath(jarPath);\n\t\tthis.provider.readAttributes(path, \"basic\");\n\t\tthen(jarPath.getFileSystem().provider()).should().readAttributes(jarPath, \"basic\");\n\t}\n\n\t@Test\n\tvoid setAttributeThrowsException() throws Exception {\n\t\tPath path = this.provider.getPath(new URI(this.uriPrefix + \"nested.jar\"));\n\t\tassertThatExceptionOfType(ReadOnlyFileSystemException.class)\n\t\t\t.isThrownBy(() -> this.provider.setAttribute(path, \"test\", \"test\"));\n\t}\n\n\tprivate Path mockJarPath() {\n\t\tPath path = mock(Path.class);\n\t\tFileSystem fileSystem = mock(FileSystem.class);\n\t\tgiven(path.getFileSystem()).willReturn(fileSystem);\n\t\tFileSystemProvider provider = mock(FileSystemProvider.class);\n\t\tgiven(fileSystem.provider()).willReturn(provider);\n\t\treturn path;\n\t}\n\n\tstatic class TestNestedFileSystemProvider extends NestedFileSystemProvider {\n\n\t\tprivate Path mockJarPath;\n\n\t\t@Override\n\t\tprotected Path getJarPath(Path path) {\n\t\t\treturn (this.mockJarPath != null) ? this.mockJarPath : super.getJarPath(path);\n\t\t}\n\n\t\tvoid setMockJarPath(Path mockJarPath) {\n\t\t\tthis.mockJarPath = mockJarPath;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/NestedFileSystemTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.File;\nimport java.nio.file.ClosedFileSystemException;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link NestedFileSystem}.\n *\n * @author Phillip Webb\n */\nclass NestedFileSystemTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate NestedFileSystemProvider provider;\n\n\tprivate Path jarPath;\n\n\tprivate NestedFileSystem fileSystem;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.provider = new NestedFileSystemProvider();\n\t\tthis.jarPath = new File(this.temp, \"test.jar\").toPath();\n\t\tthis.fileSystem = new NestedFileSystem(this.provider, this.jarPath);\n\t}\n\n\t@Test\n\tvoid providerReturnsProvider() {\n\t\tassertThat(this.fileSystem.provider()).isSameAs(this.provider);\n\t}\n\n\t@Test\n\tvoid getJarPathReturnsJarPath() {\n\t\tassertThat(this.fileSystem.getJarPath()).isSameAs(this.jarPath);\n\t}\n\n\t@Test\n\tvoid closeClosesFileSystem() throws Exception {\n\t\tthis.fileSystem.close();\n\t\tassertThat(this.fileSystem.isOpen()).isFalse();\n\t}\n\n\t@Test\n\tvoid closeWhenAlreadyClosedDoesNothing() throws Exception {\n\t\tthis.fileSystem.close();\n\t\tthis.fileSystem.close();\n\t\tassertThat(this.fileSystem.isOpen()).isFalse();\n\t}\n\n\t@Test\n\tvoid isOpenWhenOpenReturnsTrue() {\n\t\tassertThat(this.fileSystem.isOpen()).isTrue();\n\t}\n\n\t@Test\n\tvoid isOpenWhenClosedReturnsFalse() throws Exception {\n\t\tthis.fileSystem.close();\n\t\tassertThat(this.fileSystem.isOpen()).isFalse();\n\t}\n\n\t@Test\n\tvoid isReadOnlyReturnsTrue() {\n\t\tassertThat(this.fileSystem.isReadOnly()).isTrue();\n\t}\n\n\t@Test\n\tvoid getSeparatorReturnsSeparator() {\n\t\tassertThat(this.fileSystem.getSeparator()).isEqualTo(\"/!\");\n\t}\n\n\t@Test\n\tvoid getRootDirectoryWhenOpenReturnsEmptyIterable() {\n\t\tassertThat(this.fileSystem.getRootDirectories()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getRootDirectoryWhenClosedThrowsException() throws Exception {\n\t\tthis.fileSystem.close();\n\t\tassertThatExceptionOfType(ClosedFileSystemException.class)\n\t\t\t.isThrownBy(() -> this.fileSystem.getRootDirectories());\n\t}\n\n\t@Test\n\tvoid supportedFileAttributeViewsWhenOpenReturnsBasic() {\n\t\tassertThat(this.fileSystem.supportedFileAttributeViews()).containsExactly(\"basic\");\n\t}\n\n\t@Test\n\tvoid supportedFileAttributeViewsWhenClosedThrowsException() throws Exception {\n\t\tthis.fileSystem.close();\n\t\tassertThatExceptionOfType(ClosedFileSystemException.class)\n\t\t\t.isThrownBy(() -> this.fileSystem.supportedFileAttributeViews());\n\t}\n\n\t@Test\n\tvoid getPathWhenClosedThrowsException() throws Exception {\n\t\tthis.fileSystem.close();\n\t\tassertThatExceptionOfType(ClosedFileSystemException.class)\n\t\t\t.isThrownBy(() -> this.fileSystem.getPath(\"nested.jar\"));\n\t}\n\n\t@Test\n\tvoid getPathWhenFirstIsNull() {\n\t\tPath path = this.fileSystem.getPath(null);\n\t\tassertThat(path.toString()).endsWith(File.separator + \"test.jar\");\n\t}\n\n\t@Test\n\tvoid getPathWhenFirstIsBlank() {\n\t\tPath path = this.fileSystem.getPath(\"\");\n\t\tassertThat(path.toString()).endsWith(File.separator + \"test.jar\");\n\t}\n\n\t@Test\n\tvoid getPathWhenMoreIsNotEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.fileSystem.getPath(\"nested.jar\", \"another.jar\"))\n\t\t\t.withMessage(\"Nested paths must contain a single element\");\n\t}\n\n\t@Test\n\tvoid getPathReturnsPath() {\n\t\tassertThat(this.fileSystem.getPath(\"nested.jar\")).isInstanceOf(NestedPath.class);\n\t}\n\n\t@Test\n\tvoid getPathMatchThrowsException() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> this.fileSystem.getPathMatcher(\"*\"))\n\t\t\t.withMessage(\"Nested paths do not support path matchers\");\n\t}\n\n\t@Test\n\tvoid getUserPrincipalLookupServiceThrowsException() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> this.fileSystem.getUserPrincipalLookupService())\n\t\t\t.withMessage(\"Nested paths do not have a user principal lookup service\");\n\t}\n\n\t@Test\n\tvoid newWatchServiceThrowsException() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> this.fileSystem.newWatchService())\n\t\t\t.withMessage(\"Nested paths do not support the WatchService\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tassertThat(this.fileSystem).hasToString(this.jarPath.toAbsolutePath().toString());\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tPath jp1 = new File(this.temp, \"test1.jar\").toPath();\n\t\tPath jp2 = new File(this.temp, \"test1.jar\").toPath();\n\t\tPath jp3 = new File(this.temp, \"test2.jar\").toPath();\n\t\tNestedFileSystem f1 = new NestedFileSystem(this.provider, jp1);\n\t\tNestedFileSystem f2 = new NestedFileSystem(this.provider, jp1);\n\t\tNestedFileSystem f3 = new NestedFileSystem(this.provider, jp2);\n\t\tNestedFileSystem f4 = new NestedFileSystem(this.provider, jp3);\n\t\tassertThat(f1).isEqualTo(f1).isEqualTo(f2).isEqualTo(f3).isNotEqualTo(f4);\n\t\tassertThat(f1).hasSameHashCodeAs(f2);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/NestedFileSystemZipFileSystemIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.net.protocol.jar.JarUrl;\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.AssertFileChannelDataBlocksClosed;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link NestedFileSystem} in combination with\n * {@code ZipFileSystem}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass NestedFileSystemZipFileSystemIntegrationTests {\n\n\t@TempDir\n\tFile temp;\n\n\t@Test\n\tvoid zip() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tURI uri = JarUrl.create(file).toURI();\n\t\ttry (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {\n\t\t\tassertThat(Files.readAllBytes(fs.getPath(\"1.dat\"))).containsExactly(0x1);\n\t\t}\n\t}\n\n\t@Test\n\tvoid nestedZip() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tURI uri = JarUrl.create(file, \"nested.jar\").toURI();\n\t\ttry (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {\n\t\t\tassertThat(Files.readAllBytes(fs.getPath(\"3.dat\"))).containsExactly(0x3);\n\t\t}\n\t}\n\n\t@Test\n\tvoid nestedZipWithoutNewFileSystem() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tURI uri = JarUrl.create(file, \"nested.jar\", \"3.dat\").toURI();\n\t\tPath path = Path.of(uri);\n\t\tassertThat(Files.readAllBytes(path)).containsExactly(0x3);\n\t}\n\n\t@Test // gh-38592\n\tvoid nestedZipSplitAndRestore() throws Exception {\n\t\tFile file = new File(this.temp, \"test.jar\");\n\t\tTestJar.create(file);\n\t\tURI uri = JarUrl.create(file, \"nested.jar\", \"3.dat\").toURI();\n\t\tString[] components = uri.toString().split(\"!\");\n\t\tSystem.out.println(List.of(components));\n\t\ttry (FileSystem rootFs = FileSystems.newFileSystem(URI.create(components[0]), Collections.emptyMap())) {\n\t\t\tPath childPath = rootFs.getPath(components[1]);\n\t\t\ttry (FileSystem childFs = FileSystems.newFileSystem(childPath)) {\n\t\t\t\tPath nestedRoot = childFs.getPath(\"/\");\n\t\t\t\tassertThat(Files.list(nestedRoot)).hasSize(4);\n\t\t\t\tPath path = childFs.getPath(components[2]);\n\t\t\t\tassertThat(Files.readAllBytes(path)).containsExactly(0x3);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/NestedPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.nio.file.NoSuchFileException;\nimport java.nio.file.Path;\nimport java.nio.file.ProviderMismatchException;\nimport java.nio.file.WatchService;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NestedPath}.\n *\n * @author Phillip Webb\n */\nclass NestedPathTests {\n\n\t@TempDir\n\tFile temp;\n\n\tprivate NestedFileSystem fileSystem;\n\n\tprivate NestedFileSystemProvider provider;\n\n\tprivate Path jarPath;\n\n\tprivate NestedPath path;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.jarPath = new File(this.temp, \"test.jar\").toPath();\n\t\tthis.provider = new NestedFileSystemProvider();\n\t\tthis.fileSystem = new NestedFileSystem(this.provider, this.jarPath);\n\t\tthis.path = new NestedPath(this.fileSystem, \"nested.jar\");\n\t}\n\n\t@Test\n\tvoid getJarPathReturnsJarPath() {\n\t\tassertThat(this.path.getJarPath()).isEqualTo(this.jarPath);\n\t}\n\n\t@Test\n\tvoid getNestedEntryNameReturnsNestedEntryName() {\n\t\tassertThat(this.path.getNestedEntryName()).isEqualTo(\"nested.jar\");\n\t}\n\n\t@Test\n\tvoid getFileSystemReturnsFileSystem() {\n\t\tassertThat(this.path.getFileSystem()).isSameAs(this.fileSystem);\n\t}\n\n\t@Test\n\tvoid isAbsoluteReturnsTrue() {\n\t\tassertThat(this.path.isAbsolute()).isTrue();\n\t}\n\n\t@Test\n\tvoid getRootReturnsNull() {\n\t\tassertThat(this.path.getRoot()).isNull();\n\t}\n\n\t@Test\n\tvoid getFileNameReturnsPath() {\n\t\tassertThat(this.path.getFileName()).isSameAs(this.path);\n\t}\n\n\t@Test\n\tvoid getParentReturnsNull() {\n\t\tassertThat(this.path.getParent()).isNull();\n\t}\n\n\t@Test\n\tvoid getNameCountReturnsOne() {\n\t\tassertThat(this.path.getNameCount()).isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid subPathWhenBeginZeroEndOneReturnsPath() {\n\t\tassertThat(this.path.subpath(0, 1)).isSameAs(this.path);\n\t}\n\n\t@Test\n\tvoid subPathWhenBeginIndexNotZeroThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.path.subpath(1, 1))\n\t\t\t.withMessage(\"Nested paths only have a single element\");\n\t}\n\n\t@Test\n\tvoid subPathThenEndIndexNotOneThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.path.subpath(0, 2))\n\t\t\t.withMessage(\"Nested paths only have a single element\");\n\t}\n\n\t@Test\n\tvoid startsWithWhenStartsWithReturnsTrue() {\n\t\tNestedPath otherPath = new NestedPath(this.fileSystem, \"nested.jar\");\n\t\tassertThat(this.path.startsWith(otherPath)).isTrue();\n\t}\n\n\t@Test\n\tvoid startsWithWhenNotStartsWithReturnsFalse() {\n\t\tNestedPath otherPath = new NestedPath(this.fileSystem, \"other.jar\");\n\t\tassertThat(this.path.startsWith(otherPath)).isFalse();\n\t}\n\n\t@Test\n\tvoid endsWithWhenEndsWithReturnsTrue() {\n\t\tNestedPath otherPath = new NestedPath(this.fileSystem, \"nested.jar\");\n\t\tassertThat(this.path.endsWith(otherPath)).isTrue();\n\t}\n\n\t@Test\n\tvoid endsWithWhenNotEndsWithReturnsFalse() {\n\t\tNestedPath otherPath = new NestedPath(this.fileSystem, \"other.jar\");\n\t\tassertThat(this.path.endsWith(otherPath)).isFalse();\n\t}\n\n\t@Test\n\tvoid normalizeReturnsPath() {\n\t\tassertThat(this.path.normalize()).isSameAs(this.path);\n\t}\n\n\t@Test\n\tvoid resolveThrowsException() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> this.path.resolve(this.path))\n\t\t\t.withMessage(\"Unable to resolve nested path\");\n\t}\n\n\t@Test\n\tvoid relativizeThrowsException() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> this.path.relativize(this.path))\n\t\t\t.withMessage(\"Unable to relativize nested path\");\n\t}\n\n\t@Test\n\tvoid toUriReturnsUri() throws Exception {\n\t\tassertThat(this.path.toUri())\n\t\t\t.isEqualTo(new URI(\"nested:\" + this.jarPath.toUri().getRawPath() + \"/!nested.jar\"));\n\t}\n\n\t@Test\n\tvoid toUriWhenHasSpecialCharsReturnsEncodedUri() throws Exception {\n\t\tthis.jarPath = new File(this.temp, \"te st.jar\").toPath();\n\t\tthis.provider = new NestedFileSystemProvider();\n\t\tthis.fileSystem = new NestedFileSystem(this.provider, this.jarPath);\n\t\tthis.path = new NestedPath(this.fileSystem, \"ne sted.jar\");\n\t\tassertThat(this.path.toUri())\n\t\t\t.isEqualTo(new URI(\"nested:\" + this.jarPath.toUri().getRawPath() + \"/!ne%20sted.jar\"));\n\t}\n\n\t@Test\n\tvoid toAbsolutePathReturnsPath() {\n\t\tassertThat(this.path.toAbsolutePath()).isSameAs(this.path);\n\t}\n\n\t@Test\n\tvoid toRealPathReturnsPath() throws Exception {\n\t\tassertThat(this.path.toRealPath()).isSameAs(this.path);\n\t}\n\n\t@Test\n\tvoid registerThrowsException() {\n\t\tWatchService watcher = mock(WatchService.class);\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> this.path.register(watcher))\n\t\t\t.withMessage(\"Nested paths cannot be watched\");\n\t}\n\n\t@Test\n\tvoid compareToComparesOnNestedEntryName() {\n\t\tNestedPath a = new NestedPath(this.fileSystem, \"a.jar\");\n\t\tNestedPath b = new NestedPath(this.fileSystem, \"b.jar\");\n\t\tNestedPath c = new NestedPath(this.fileSystem, \"c.jar\");\n\t\tassertThat(new TreeSet<>(Set.of(c, a, b))).containsExactly(a, b, c);\n\t}\n\n\t@Test\n\tvoid hashCodeAndEquals() {\n\t\tNestedFileSystem fs2 = new NestedFileSystem(this.provider, new File(this.temp, \"test2.jar\").toPath());\n\t\tNestedPath p1 = new NestedPath(this.fileSystem, \"a.jar\");\n\t\tNestedPath p2 = new NestedPath(this.fileSystem, \"a.jar\");\n\t\tNestedPath p3 = new NestedPath(this.fileSystem, \"c.jar\");\n\t\tNestedPath p4 = new NestedPath(fs2, \"c.jar\");\n\t\tassertThat(p1).hasSameHashCodeAs(p2);\n\t\tassertThat(p1).isEqualTo(p1).isEqualTo(p2).isNotEqualTo(p3).isNotEqualTo(p4);\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tassertThat(this.path).hasToString(this.jarPath.toString() + \"/!nested.jar\");\n\t}\n\n\t@Test\n\tvoid assertExistsWhenExists() throws Exception {\n\t\tTestJar.create(this.jarPath.toFile());\n\t\tthis.path.assertExists();\n\t}\n\n\t@Test\n\tvoid assertExistsWhenDoesNotExistThrowsException() {\n\t\tassertThatExceptionOfType(NoSuchFileException.class).isThrownBy(this.path::assertExists);\n\t}\n\n\t@Test\n\tvoid castWhenNestedPathReturnsNestedPath() {\n\t\tassertThat(NestedPath.cast(this.path)).isSameAs(this.path);\n\t}\n\n\t@Test\n\tvoid castWhenNullThrowsException() {\n\t\tassertThatExceptionOfType(ProviderMismatchException.class).isThrownBy(() -> NestedPath.cast(null));\n\t}\n\n\t@Test\n\tvoid castWhenNotNestedPathThrowsException() {\n\t\tassertThatExceptionOfType(ProviderMismatchException.class).isThrownBy(() -> NestedPath.cast(this.jarPath));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/nio/file/UriPathEncoderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.nio.file;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UriPathEncoder}.\n *\n * @author Phillip Webb\n */\nclass UriPathEncoderTests {\n\n\t@Test\n\tvoid encodePath() {\n\t\tassertThat(UriPathEncoder.encode(\"/foo/bar\")).isEqualTo(\"/foo/bar\");\n\t\tassertThat(UriPathEncoder.encode(\"/foo bar\")).isEqualTo(\"/foo%20bar\");\n\t\tassertThat(UriPathEncoder.encode(\"/Z\\u00fcrich\")).isEqualTo(\"/Z%C3%BCrich\");\n\t}\n\n\t@Test\n\tvoid encodePathWhenNoEncodingIsRequiredReturnsSameInstance() {\n\t\tString path = \"/foo/bar\";\n\t\tassertThat(UriPathEncoder.encode(path)).isSameAs(path);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/ref/DefaultCleanerTracking.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.ref;\n\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.util.function.BiConsumer;\n\n/**\n * Utility that allows tests to set a tracker on {@link DefaultCleaner}.\n *\n * @author Phillip Webb\n */\npublic final class DefaultCleanerTracking {\n\n\tprivate DefaultCleanerTracking() {\n\t}\n\n\tpublic static void set(BiConsumer<Object, Cleanable> tracker) {\n\t\tDefaultCleaner.tracker = tracker;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/testsupport/TestJar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.testsupport;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.CRC32;\nimport java.util.zip.ZipEntry;\n\n/**\n * Support class to create or get test jars.\n *\n * @author Phillip Webb\n */\npublic abstract class TestJar {\n\n\tpublic static final int MULTI_JAR_VERSION = Runtime.version().feature();\n\n\tprivate static final int BASE_VERSION = 8;\n\n\tpublic static void create(File file) throws Exception {\n\t\tcreate(file, false);\n\t}\n\n\tpublic static void create(File file, boolean unpackNested) throws Exception {\n\t\tcreate(file, unpackNested, false);\n\t}\n\n\tpublic static void create(File file, boolean unpackNested, boolean addSignatureFile) throws Exception {\n\t\tFileOutputStream fileOutputStream = new FileOutputStream(file);\n\t\ttry (JarOutputStream jarOutputStream = new JarOutputStream(fileOutputStream)) {\n\t\t\tjarOutputStream.setComment(\"outer\");\n\t\t\twriteManifest(jarOutputStream, \"j1\");\n\t\t\tif (addSignatureFile) {\n\t\t\t\twriteEntry(jarOutputStream, \"META-INF/some.DSA\", 0);\n\t\t\t}\n\t\t\twriteEntry(jarOutputStream, \"1.dat\", 1);\n\t\t\twriteEntry(jarOutputStream, \"2.dat\", 2);\n\t\t\twriteDirEntry(jarOutputStream, \"d/\");\n\t\t\twriteEntry(jarOutputStream, \"d/9.dat\", 9);\n\t\t\twriteDirEntry(jarOutputStream, \"special/\");\n\t\t\twriteEntry(jarOutputStream, \"special/\\u00EB.dat\", '\\u00EB');\n\t\t\twriteNestedEntry(\"nested.jar\", unpackNested, jarOutputStream);\n\t\t\twriteNestedEntry(\"another-nested.jar\", unpackNested, jarOutputStream);\n\t\t\twriteNestedEntry(\"space nested.jar\", unpackNested, jarOutputStream);\n\t\t\twriteNestedMultiReleaseEntry(\"multi-release.jar\", unpackNested, jarOutputStream);\n\t\t}\n\t}\n\n\tpublic static List<String> expectedEntries() {\n\t\treturn List.of(\"META-INF/\", \"META-INF/MANIFEST.MF\", \"1.dat\", \"2.dat\", \"d/\", \"d/9.dat\", \"special/\",\n\t\t\t\t\"special/\\u00EB.dat\", \"nested.jar\", \"another-nested.jar\", \"space nested.jar\", \"multi-release.jar\");\n\t}\n\n\tprivate static void writeNestedEntry(String name, boolean unpackNested, JarOutputStream jarOutputStream)\n\t\t\tthrows Exception {\n\t\twriteNestedEntry(name, unpackNested, jarOutputStream, false);\n\t}\n\n\tprivate static void writeNestedMultiReleaseEntry(String name, boolean unpackNested, JarOutputStream jarOutputStream)\n\t\t\tthrows Exception {\n\t\twriteNestedEntry(name, unpackNested, jarOutputStream, true);\n\t}\n\n\tprivate static void writeNestedEntry(String name, boolean unpackNested, JarOutputStream jarOutputStream,\n\t\t\tboolean multiRelease) throws Exception {\n\t\tJarEntry nestedEntry = new JarEntry(name);\n\t\tbyte[] nestedJarData = getNestedJarData(multiRelease);\n\t\tnestedEntry.setSize(nestedJarData.length);\n\t\tnestedEntry.setCompressedSize(nestedJarData.length);\n\t\tif (unpackNested) {\n\t\t\tnestedEntry.setComment(\"UNPACK\");\n\t\t}\n\t\tCRC32 crc32 = new CRC32();\n\t\tcrc32.update(nestedJarData);\n\t\tnestedEntry.setCrc(crc32.getValue());\n\t\tnestedEntry.setMethod(ZipEntry.STORED);\n\t\tjarOutputStream.putNextEntry(nestedEntry);\n\t\tjarOutputStream.write(nestedJarData);\n\t\tjarOutputStream.closeEntry();\n\t}\n\n\tprivate static byte[] getNestedJarData(boolean multiRelease) throws Exception {\n\t\tByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n\t\tJarOutputStream jarOutputStream = new JarOutputStream(byteArrayOutputStream);\n\t\tjarOutputStream.setComment(\"nested\");\n\t\twriteManifest(jarOutputStream, \"j2\", multiRelease);\n\t\tif (multiRelease) {\n\t\t\twriteEntry(jarOutputStream, \"multi-release.dat\", BASE_VERSION);\n\t\t\twriteEntry(jarOutputStream, String.format(\"META-INF/versions/%d/multi-release.dat\", MULTI_JAR_VERSION),\n\t\t\t\t\tMULTI_JAR_VERSION);\n\t\t}\n\t\telse {\n\t\t\twriteEntry(jarOutputStream, \"3.dat\", 3);\n\t\t\twriteEntry(jarOutputStream, \"4.dat\", 4);\n\t\t\twriteEntry(jarOutputStream, \"\\u00E4.dat\", '\\u00E4');\n\t\t}\n\t\tjarOutputStream.close();\n\t\treturn byteArrayOutputStream.toByteArray();\n\t}\n\n\tprivate static void writeManifest(JarOutputStream jarOutputStream, String name) throws Exception {\n\t\twriteManifest(jarOutputStream, name, false);\n\t}\n\n\tprivate static void writeManifest(JarOutputStream jarOutputStream, String name, boolean multiRelease)\n\t\t\tthrows Exception {\n\t\twriteDirEntry(jarOutputStream, \"META-INF/\");\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(\"Built-By\", name);\n\t\tmanifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\t\tif (multiRelease) {\n\t\t\tmanifest.getMainAttributes().putValue(\"Multi-Release\", Boolean.toString(true));\n\t\t}\n\t\tjarOutputStream.putNextEntry(new ZipEntry(\"META-INF/MANIFEST.MF\"));\n\t\tmanifest.write(jarOutputStream);\n\t\tjarOutputStream.closeEntry();\n\t}\n\n\tprivate static void writeDirEntry(JarOutputStream jarOutputStream, String name) throws IOException {\n\t\tjarOutputStream.putNextEntry(new JarEntry(name));\n\t\tjarOutputStream.closeEntry();\n\t}\n\n\tprivate static void writeEntry(JarOutputStream jarOutputStream, String name, int data) throws IOException {\n\t\tjarOutputStream.putNextEntry(new JarEntry(name));\n\t\tjarOutputStream.write(new byte[] { (byte) data });\n\t\tjarOutputStream.closeEntry();\n\t}\n\n\tpublic static File getSigned() {\n\t\tString[] entries = System.getProperty(\"java.class.path\").split(System.getProperty(\"path.separator\"));\n\t\tfor (String entry : entries) {\n\t\t\tif (entry.contains(\"bcprov\")) {\n\t\t\t\treturn new File(entry);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/AssertFileChannelDataBlocksClosed.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Annotation that can be added to tests to assert that {@link FileDataBlock} files are\n * not left open.\n *\n * @author Phillip Webb\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ExtendWith(AssertFileChannelDataBlocksClosedExtension.class)\npublic @interface AssertFileChannelDataBlocksClosed {\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/AssertFileChannelDataBlocksClosedExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.lang.ref.Cleaner.Cleanable;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.boot.loader.ref.DefaultCleanerTracking;\nimport org.springframework.boot.loader.zip.FileDataBlock.Tracker;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Extension for {@link AssertFileChannelDataBlocksClosed @TrackFileChannelDataBlock}.\n */\nclass AssertFileChannelDataBlocksClosedExtension implements BeforeEachCallback, AfterEachCallback {\n\n\tprivate static OpenFilesTracker tracker = new OpenFilesTracker();\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\ttracker.clear();\n\t\tFileDataBlock.tracker = tracker;\n\t\tDefaultCleanerTracking.set(tracker::addedCleanable);\n\t}\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\ttracker.assertAllClosed();\n\t\tFileDataBlock.tracker = Tracker.NONE;\n\t}\n\n\tprivate static final class OpenFilesTracker implements Tracker {\n\n\t\tprivate final Set<Path> paths = new LinkedHashSet<>();\n\n\t\tprivate final List<Cleanable> clean = new ArrayList<>();\n\n\t\tprivate final List<Closeable> close = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic void openedFileChannel(Path path) {\n\t\t\tthis.paths.add(path);\n\t\t}\n\n\t\t@Override\n\t\tpublic void closedFileChannel(Path path) {\n\t\t\tthis.paths.remove(path);\n\t\t}\n\n\t\tvoid clear() {\n\t\t\tthis.paths.clear();\n\t\t\tthis.clean.clear();\n\t\t}\n\n\t\tvoid assertAllClosed() throws IOException {\n\t\t\tfor (Closeable closeable : this.close) {\n\t\t\t\tcloseable.close();\n\t\t\t}\n\t\t\tthis.clean.forEach(Cleanable::clean);\n\t\t\tassertThat(this.paths).as(\"open paths\").isEmpty();\n\t\t}\n\n\t\tprivate void addedCleanable(Object obj, Cleanable cleanable) {\n\t\t\tif (cleanable != null) {\n\t\t\t\tthis.clean.add(cleanable);\n\t\t\t}\n\t\t\tif (obj instanceof Closeable closeable) {\n\t\t\t\tthis.close.add(closeable);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ByteArrayDataBlockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.nio.ByteBuffer;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ByteArrayDataBlock}.\n *\n * @author Phillip Webb\n */\nclass ByteArrayDataBlockTests {\n\n\tprivate final byte[] BYTES = { 0, 1, 2, 3, 4, 5, 6, 7 };\n\n\t@Test\n\tvoid sizeReturnsByteArrayLength() throws Exception {\n\t\ttry (ByteArrayDataBlock dataBlock = new ByteArrayDataBlock(this.BYTES)) {\n\t\t\tassertThat(dataBlock.size()).isEqualTo(this.BYTES.length);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readPutsBytes() throws Exception {\n\t\ttry (ByteArrayDataBlock dataBlock = new ByteArrayDataBlock(this.BYTES)) {\n\t\t\tByteBuffer dst = ByteBuffer.allocate(8);\n\t\t\tint result = dataBlock.read(dst, 0);\n\t\t\tassertThat(result).isEqualTo(8);\n\t\t\tassertThat(dst.array()).containsExactly(this.BYTES);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readWhenLessBytesThanRemainingInBufferPutsBytes() throws Exception {\n\t\ttry (ByteArrayDataBlock dataBlock = new ByteArrayDataBlock(this.BYTES)) {\n\t\t\tByteBuffer dst = ByteBuffer.allocate(9);\n\t\t\tint result = dataBlock.read(dst, 0);\n\t\t\tassertThat(result).isEqualTo(8);\n\t\t\tassertThat(dst.array()).containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readWhenLessRemainingInBufferThanLengthPutsBytes() throws Exception {\n\t\ttry (ByteArrayDataBlock dataBlock = new ByteArrayDataBlock(this.BYTES)) {\n\t\t\tByteBuffer dst = ByteBuffer.allocate(7);\n\t\t\tint result = dataBlock.read(dst, 0);\n\t\t\tassertThat(result).isEqualTo(7);\n\t\t\tassertThat(dst.array()).containsExactly(0, 1, 2, 3, 4, 5, 6);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readWhenHasPosOffsetReadsBytes() throws Exception {\n\t\ttry (ByteArrayDataBlock dataBlock = new ByteArrayDataBlock(this.BYTES)) {\n\t\t\tByteBuffer dst = ByteBuffer.allocate(3);\n\t\t\tint result = dataBlock.read(dst, 4);\n\t\t\tassertThat(result).isEqualTo(3);\n\t\t\tassertThat(dst.array()).containsExactly(4, 5, 6);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/DataBlockInputStreamTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link DataBlockInputStream}.\n *\n * @author Phillip Webb\n */\nclass DataBlockInputStreamTests {\n\n\tprivate ByteArrayDataBlock dataBlock;\n\n\tprivate InputStream inputStream;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.dataBlock = new ByteArrayDataBlock(new byte[] { 0, 1, 2 });\n\t\tthis.inputStream = this.dataBlock.asInputStream();\n\t}\n\n\t@Test\n\tvoid readSingleByteReadsByte() throws Exception {\n\t\tassertThat(this.inputStream.read()).isEqualTo(0);\n\t\tassertThat(this.inputStream.read()).isEqualTo(1);\n\t\tassertThat(this.inputStream.read()).isEqualTo(2);\n\t\tassertThat(this.inputStream.read()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid readByteArrayWhenNotOpenThrowsException() throws Exception {\n\t\tbyte[] bytes = new byte[10];\n\t\tthis.inputStream.close();\n\t\tassertThatIOException().isThrownBy(() -> this.inputStream.read(bytes)).withMessage(\"InputStream closed\");\n\t}\n\n\t@Test\n\tvoid readByteArrayWhenReadingMultipleTimesReadsBytes() throws Exception {\n\t\tbyte[] bytes = new byte[3];\n\t\tassertThat(this.inputStream.read(bytes, 0, 2)).isEqualTo(2);\n\t\tassertThat(this.inputStream.read(bytes, 2, 1)).isEqualTo(1);\n\t\tassertThat(bytes).containsExactly(0, 1, 2);\n\t}\n\n\t@Test\n\tvoid readByteArrayWhenReadingMoreThanAvailableReadsRemainingBytes() throws Exception {\n\t\tbyte[] bytes = new byte[5];\n\t\tassertThat(this.inputStream.read(bytes, 0, 5)).isEqualTo(3);\n\t\tassertThat(bytes).containsExactly(0, 1, 2, 0, 0);\n\t}\n\n\t@Test\n\tvoid skipSkipsBytes() throws Exception {\n\t\tassertThat(this.inputStream.skip(2)).isEqualTo(2);\n\t\tassertThat(this.inputStream.read()).isEqualTo(2);\n\t\tassertThat(this.inputStream.read()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid skipWhenSkippingMoreThanRemainingSkipsBytes() throws Exception {\n\t\tassertThat(this.inputStream.skip(100)).isEqualTo(3);\n\t\tassertThat(this.inputStream.read()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid skipBackwardsSkipsBytes() throws IOException {\n\t\tassertThat(this.inputStream.skip(2)).isEqualTo(2);\n\t\tassertThat(this.inputStream.skip(-1)).isEqualTo(-1);\n\t\tassertThat(this.inputStream.read()).isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid skipBackwardsPastBeginningSkipsBytes() throws Exception {\n\t\tassertThat(this.inputStream.skip(1)).isEqualTo(1);\n\t\tassertThat(this.inputStream.skip(-100)).isEqualTo(-1);\n\t\tassertThat(this.inputStream.read()).isEqualTo(0);\n\t}\n\n\t@Test\n\tvoid availableReturnsRemainingBytes() throws IOException {\n\t\tassertThat(this.inputStream.available()).isEqualTo(3);\n\t\tthis.inputStream.read();\n\t\tassertThat(this.inputStream.available()).isEqualTo(2);\n\t\tthis.inputStream.skip(1);\n\t\tassertThat(this.inputStream.available()).isEqualTo(1);\n\t}\n\n\t@Test\n\tvoid availableWhenClosedReturnsZero() throws IOException {\n\t\tthis.inputStream.close();\n\t\tassertThat(this.inputStream.available()).isZero();\n\t}\n\n\t@Test\n\tvoid closeClosesDataBlock() throws Exception {\n\t\tthis.dataBlock = spy(new ByteArrayDataBlock(new byte[] { 0, 1, 2 }));\n\t\tthis.inputStream = this.dataBlock.asInputStream();\n\t\tthis.inputStream.close();\n\t\tthen(this.dataBlock).should().close();\n\t}\n\n\t@Test\n\tvoid closeMultipleTimesClosesDataBlockOnce() throws Exception {\n\t\tthis.dataBlock = spy(new ByteArrayDataBlock(new byte[] { 0, 1, 2 }));\n\t\tthis.inputStream = this.dataBlock.asInputStream();\n\t\tthis.inputStream.close();\n\t\tthis.inputStream.close();\n\t\tthen(this.dataBlock).should(times(1)).close();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/DataBlockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.stubbing.Answer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyLong;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.CALLS_REAL_METHODS;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link DataBlock}.\n *\n * @author Phillip Webb\n */\nclass DataBlockTests {\n\n\t@Test\n\tvoid readFullyReadsAllBytesByCallingReadMultipleTimes() throws IOException {\n\t\tDataBlock dataBlock = mock(DataBlock.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));\n\t\tgiven(dataBlock.read(any(), anyLong()))\n\t\t\t.will(putBytes(new byte[] { 0, 1 }, new byte[] { 2 }, new byte[] { 3, 4, 5 }));\n\t\tByteBuffer dst = ByteBuffer.allocate(6);\n\t\tdataBlock.readFully(dst, 0);\n\t\tassertThat(dst.array()).containsExactly(0, 1, 2, 3, 4, 5);\n\t}\n\n\tprivate Answer<?> putBytes(byte[]... bytes) {\n\t\tAtomicInteger count = new AtomicInteger();\n\t\treturn (invocation) -> {\n\t\t\tint index = count.getAndIncrement();\n\t\t\tinvocation.getArgument(0, ByteBuffer.class).put(bytes[index]);\n\t\t\treturn bytes.length;\n\t\t};\n\t}\n\n\t@Test\n\tvoid readFullyWhenReadReturnsNegativeResultThrowsException() throws Exception {\n\t\tDataBlock dataBlock = mock(DataBlock.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));\n\t\tgiven(dataBlock.read(any(), anyLong())).willReturn(-1);\n\t\tByteBuffer dst = ByteBuffer.allocate(8);\n\t\tassertThatExceptionOfType(EOFException.class).isThrownBy(() -> dataBlock.readFully(dst, 0));\n\t}\n\n\t@Test\n\tvoid asInputStreamReturnsDataBlockInputStream() throws Exception {\n\t\tDataBlock dataBlock = mock(DataBlock.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));\n\t\tassertThat(dataBlock.asInputStream()).isInstanceOf(DataBlockInputStream.class);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/FileChannelDataBlockManagedFileChannel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport org.springframework.boot.loader.zip.FileDataBlock.FileAccess;\n\n/**\n * Test access to {@link FileAccess} details.\n *\n * @author Phillip Webb\n */\npublic final class FileChannelDataBlockManagedFileChannel {\n\n\tprivate FileChannelDataBlockManagedFileChannel() {\n\t}\n\n\tpublic static int BUFFER_SIZE = FileDataBlock.FileAccess.BUFFER_SIZE;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/FileDataBlockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.zip.FileDataBlock.Tracker;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link FileDataBlock}.\n *\n * @author Phillip Webb\n */\nclass FileDataBlockTests {\n\n\tprivate static final byte[] CONTENT = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };\n\n\t@TempDir\n\tFile tempDir;\n\n\tFile tempFile;\n\n\t@BeforeEach\n\tvoid writeTempFile() throws IOException {\n\t\tthis.tempFile = new File(this.tempDir, \"content\");\n\t\tFiles.write(this.tempFile.toPath(), CONTENT);\n\t}\n\n\t@AfterEach\n\tvoid resetTracker() {\n\t\tFileDataBlock.tracker = Tracker.NONE;\n\t}\n\n\t@Test\n\tvoid sizeReturnsFileSize() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tassertThat(block.size()).isEqualTo(CONTENT.length);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readReadsFile() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);\n\t\t\tassertThat(block.read(buffer, 0)).isEqualTo(6);\n\t\t\tassertThat(buffer.array()).containsExactly(CONTENT);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readReadsFileWhenThreadHasBeenInterrupted() throws IOException {\n\t\tFiles.write(this.tempFile.toPath(), CONTENT);\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);\n\t\t\tThread.currentThread().interrupt();\n\t\t\tassertThat(block.read(buffer, 0)).isEqualTo(6);\n\t\t\tassertThat(buffer.array()).containsExactly(CONTENT);\n\t\t}\n\t\tfinally {\n\t\t\tThread.interrupted();\n\t\t}\n\t}\n\n\t@Test\n\tvoid readDoesNotReadPastEndOfFile() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);\n\t\t\tassertThat(block.read(buffer, 2)).isEqualTo(4);\n\t\t\tassertThat(buffer.array()).containsExactly(0x02, 0x03, 0x04, 0x05, 0x0, 0x0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readWhenPosAtSizeReturnsMinusOne() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);\n\t\t\tassertThat(block.read(buffer, 6)).isEqualTo(-1);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readWhenPosOverSizeReturnsMinusOne() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);\n\t\t\tassertThat(block.read(buffer, 7)).isEqualTo(-1);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readWhenPosIsNegativeThrowsException() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(CONTENT.length);\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> block.read(buffer, -1));\n\t\t}\n\t}\n\n\t@Test\n\tvoid sliceWhenOffsetIsNegativeThrowsException() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> block.slice(-1, 0))\n\t\t\t\t.withMessage(\"Offset must not be negative\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid sliceWhenSizeIsNegativeThrowsException() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> block.slice(0, -1))\n\t\t\t\t.withMessage(\"Size must not be negative and must be within bounds\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid sliceWhenSizeIsOutOfBoundsThrowsException() throws IOException {\n\t\ttry (FileDataBlock block = createAndOpenBlock()) {\n\t\t\tassertThatIllegalArgumentException().isThrownBy(() -> block.slice(2, 5))\n\t\t\t\t.withMessage(\"Size must not be negative and must be within bounds\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid sliceReturnsSlice() throws IOException {\n\t\ttry (FileDataBlock slice = createAndOpenBlock().slice(1, 4)) {\n\t\t\tassertThat(slice.size()).isEqualTo(4);\n\t\t\tByteBuffer buffer = ByteBuffer.allocate(4);\n\t\t\tassertThat(slice.read(buffer, 0)).isEqualTo(4);\n\t\t\tassertThat(buffer.array()).containsExactly(0x01, 0x02, 0x03, 0x04);\n\t\t}\n\t}\n\n\t@Test\n\tvoid openAndCloseHandleReferenceCounting() throws IOException {\n\t\tTestTracker tracker = new TestTracker();\n\t\tFileDataBlock.tracker = tracker;\n\t\tFileDataBlock block = createBlock();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(0);\n\t\ttracker.assertOpenCloseCounts(0, 0);\n\t\tblock.open();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(1);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tblock.open();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(2);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tblock.close();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(1);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tblock.close();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(0);\n\t\ttracker.assertOpenCloseCounts(1, 1);\n\t\tblock.open();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(1);\n\t\ttracker.assertOpenCloseCounts(2, 1);\n\t\tblock.close();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(0);\n\t\ttracker.assertOpenCloseCounts(2, 2);\n\t}\n\n\t@Test\n\tvoid openAndCloseSliceHandleReferenceCounting() throws IOException {\n\t\tTestTracker tracker = new TestTracker();\n\t\tFileDataBlock.tracker = tracker;\n\t\tFileDataBlock block = createBlock();\n\t\tFileDataBlock slice = block.slice(1, 4);\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(0);\n\t\ttracker.assertOpenCloseCounts(0, 0);\n\t\tblock.open();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(1);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tslice.open();\n\t\tassertThat(slice).extracting(\"fileAccess.referenceCount\").isEqualTo(2);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tslice.open();\n\t\tassertThat(slice).extracting(\"fileAccess.referenceCount\").isEqualTo(3);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tslice.close();\n\t\tassertThat(slice).extracting(\"fileAccess.referenceCount\").isEqualTo(2);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tslice.close();\n\t\tassertThat(slice).extracting(\"fileAccess.referenceCount\").isEqualTo(1);\n\t\ttracker.assertOpenCloseCounts(1, 0);\n\t\tblock.close();\n\t\tassertThat(block).extracting(\"fileAccess.referenceCount\").isEqualTo(0);\n\t\ttracker.assertOpenCloseCounts(1, 1);\n\t\tslice.open();\n\t\tassertThat(slice).extracting(\"fileAccess.referenceCount\").isEqualTo(1);\n\t\ttracker.assertOpenCloseCounts(2, 1);\n\t\tslice.close();\n\t\tassertThat(slice).extracting(\"fileAccess.referenceCount\").isEqualTo(0);\n\t\ttracker.assertOpenCloseCounts(2, 2);\n\t}\n\n\tprivate FileDataBlock createAndOpenBlock() throws IOException {\n\t\tFileDataBlock block = createBlock();\n\t\tblock.open();\n\t\treturn block;\n\t}\n\n\tprivate FileDataBlock createBlock() throws IOException {\n\t\treturn new FileDataBlock(this.tempFile.toPath());\n\t}\n\n\tstatic class TestTracker implements Tracker {\n\n\t\tprivate int openCount;\n\n\t\tprivate int closeCount;\n\n\t\t@Override\n\t\tpublic void openedFileChannel(Path path) {\n\t\t\tthis.openCount++;\n\t\t}\n\n\t\t@Override\n\t\tpublic void closedFileChannel(Path path) {\n\t\t\tthis.closeCount++;\n\t\t}\n\n\t\tvoid assertOpenCloseCounts(int expectedOpenCount, int expectedCloseCount) {\n\t\t\tassertThat(this.openCount).as(\"openCount\").isEqualTo(expectedOpenCount);\n\t\t\tassertThat(this.closeCount).as(\"closeCount\").isEqualTo(expectedCloseCount);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/VirtualDataBlockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link VirtualDataBlock}.\n *\n * @author Phillip Webb\n */\nclass VirtualDataBlockTests {\n\n\tprivate VirtualDataBlock virtualDataBlock;\n\n\t@BeforeEach\n\tvoid setup() throws IOException {\n\t\tList<DataBlock> subsections = new ArrayList<>();\n\t\tsubsections.add(new ByteArrayDataBlock(\"abc\".getBytes(StandardCharsets.UTF_8)));\n\t\tsubsections.add(new ByteArrayDataBlock(\"defg\".getBytes(StandardCharsets.UTF_8)));\n\t\tsubsections.add(new ByteArrayDataBlock(\"h\".getBytes(StandardCharsets.UTF_8)));\n\t\tthis.virtualDataBlock = new VirtualDataBlock(subsections);\n\t}\n\n\t@Test\n\tvoid sizeReturnsSize() throws IOException {\n\t\tassertThat(this.virtualDataBlock.size()).isEqualTo(8);\n\t}\n\n\t@Test\n\tvoid readFullyReadsAllBlocks() throws IOException {\n\t\tByteBuffer dst = ByteBuffer.allocate((int) this.virtualDataBlock.size());\n\t\tthis.virtualDataBlock.readFully(dst, 0);\n\t\tassertThat(dst.array()).containsExactly(\"abcdefgh\".getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t@Test\n\tvoid readWithShortBlock() throws IOException {\n\t\tByteBuffer dst = ByteBuffer.allocate(2);\n\t\tassertThat(this.virtualDataBlock.read(dst, 1)).isEqualTo(2);\n\t\tassertThat(dst.array()).containsExactly(\"bc\".getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t@Test\n\tvoid readWithShortBlockAcrossSubsections() throws IOException {\n\t\tByteBuffer dst = ByteBuffer.allocate(3);\n\t\tassertThat(this.virtualDataBlock.read(dst, 2)).isEqualTo(3);\n\t\tassertThat(dst.array()).containsExactly(\"cde\".getBytes(StandardCharsets.UTF_8));\n\t}\n\n\t@Test\n\tvoid readWithBigBlock() throws IOException {\n\t\tByteBuffer dst = ByteBuffer.allocate(16);\n\t\tassertThat(this.virtualDataBlock.read(dst, 1)).isEqualTo(7);\n\t\tassertThat(dst.array()).startsWith(\"bcdefgh\".getBytes(StandardCharsets.UTF_8));\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/VirtualZipDataBlockTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.NoSuchFileException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link VirtualZipDataBlock}.\n *\n * @author Phillip Webb\n */\n@AssertFileChannelDataBlocksClosed\nclass VirtualZipDataBlockTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprivate File file;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.tempDir, \"test.jar\");\n\t\tTestJar.create(this.file);\n\t}\n\n\t@Test\n\tvoid createContainsValidZipContent() throws IOException {\n\t\tFileDataBlock data = new FileDataBlock(this.file.toPath());\n\t\tdata.open();\n\t\tList<ZipCentralDirectoryFileHeaderRecord> centralRecords = new ArrayList<>();\n\t\tList<Long> centralRecordPositions = new ArrayList<>();\n\t\tZipEndOfCentralDirectoryRecord eocd = ZipEndOfCentralDirectoryRecord.load(data).endOfCentralDirectoryRecord();\n\t\tlong pos = eocd.offsetToStartOfCentralDirectory();\n\t\tfor (int i = 0; i < eocd.totalNumberOfCentralDirectoryEntries(); i++) {\n\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = ZipCentralDirectoryFileHeaderRecord.load(data, pos);\n\t\t\tString name = ZipString.readString(data, pos + ZipCentralDirectoryFileHeaderRecord.FILE_NAME_OFFSET,\n\t\t\t\t\tcentralRecord.fileNameLength());\n\t\t\tif (name.endsWith(\".jar\")) {\n\t\t\t\tcentralRecords.add(centralRecord);\n\t\t\t\tcentralRecordPositions.add(pos);\n\t\t\t}\n\t\t\tpos += centralRecord.size();\n\t\t}\n\t\tNameOffsetLookups nameOffsetLookups = new NameOffsetLookups(2, centralRecords.size());\n\t\tfor (int i = 0; i < centralRecords.size(); i++) {\n\t\t\tnameOffsetLookups.enable(i, true);\n\t\t}\n\t\tnameOffsetLookups.enable(0, true);\n\t\tFile outputFile = new File(this.tempDir, \"out.jar\");\n\t\ttry (VirtualZipDataBlock block = new VirtualZipDataBlock(data, nameOffsetLookups,\n\t\t\t\tcentralRecords.toArray(ZipCentralDirectoryFileHeaderRecord[]::new),\n\t\t\t\tcentralRecordPositions.stream().mapToLong(Long::longValue).toArray())) {\n\t\t\ttry (FileOutputStream out = new FileOutputStream(outputFile)) {\n\t\t\t\tblock.asInputStream().transferTo(out);\n\t\t\t}\n\t\t}\n\t\ttry (FileSystem fileSystem = FileSystems.newFileSystem(outputFile.toPath())) {\n\t\t\tassertThatExceptionOfType(NoSuchFileException.class)\n\t\t\t\t.isThrownBy(() -> Files.size(fileSystem.getPath(\"nessted.jar\")));\n\t\t\tassertThat(Files.size(fileSystem.getPath(\"sted.jar\"))).isGreaterThan(0);\n\t\t\tassertThat(Files.size(fileSystem.getPath(\"other-nested.jar\"))).isGreaterThan(0);\n\t\t\tassertThat(Files.size(fileSystem.getPath(\"ace nested.jar\"))).isGreaterThan(0);\n\t\t\tassertThat(Files.size(fileSystem.getPath(\"lti-release.jar\"))).isGreaterThan(0);\n\t\t}\n\t}\n\n\t@Test // gh-38063\n\tvoid createWithDescriptorRecordContainsValidZipContent() throws Exception {\n\t\ttry (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(this.file))) {\n\t\t\tZipEntry entry = new ZipEntry(\"META-INF/\");\n\t\t\tentry.setMethod(ZipEntry.DEFLATED);\n\t\t\tzip.putNextEntry(entry);\n\t\t\tzip.write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 });\n\t\t\tzip.closeEntry();\n\t\t}\n\t\tbyte[] bytes = Files.readAllBytes(this.file.toPath());\n\t\tCloseableDataBlock data = new ByteArrayDataBlock(bytes);\n\t\tList<ZipCentralDirectoryFileHeaderRecord> centralRecords = new ArrayList<>();\n\t\tList<Long> centralRecordPositions = new ArrayList<>();\n\t\tZipEndOfCentralDirectoryRecord eocd = ZipEndOfCentralDirectoryRecord.load(data).endOfCentralDirectoryRecord();\n\t\tlong pos = eocd.offsetToStartOfCentralDirectory();\n\t\tfor (int i = 0; i < eocd.totalNumberOfCentralDirectoryEntries(); i++) {\n\t\t\tZipCentralDirectoryFileHeaderRecord centralRecord = ZipCentralDirectoryFileHeaderRecord.load(data, pos);\n\t\t\tcentralRecords.add(centralRecord);\n\t\t\tcentralRecordPositions.add(pos);\n\t\t\tpos += centralRecord.size();\n\t\t}\n\t\tNameOffsetLookups nameOffsetLookups = new NameOffsetLookups(0, centralRecords.size());\n\t\tfor (int i = 0; i < centralRecords.size(); i++) {\n\t\t\tnameOffsetLookups.enable(i, true);\n\t\t}\n\t\tnameOffsetLookups.enable(0, true);\n\t\tFile outputFile = new File(this.tempDir, \"out.jar\");\n\t\ttry (VirtualZipDataBlock block = new VirtualZipDataBlock(data, nameOffsetLookups,\n\t\t\t\tcentralRecords.toArray(ZipCentralDirectoryFileHeaderRecord[]::new),\n\t\t\t\tcentralRecordPositions.stream().mapToLong(Long::longValue).toArray())) {\n\t\t\ttry (FileOutputStream out = new FileOutputStream(outputFile)) {\n\t\t\t\tblock.asInputStream().transferTo(out);\n\t\t\t}\n\t\t}\n\t\tbyte[] virtualBytes = Files.readAllBytes(outputFile.toPath());\n\t\tassertThat(bytes).isEqualTo(virtualBytes);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/VirtualZipPerformanceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\nimport java.util.Random;\nimport java.util.concurrent.TimeUnit;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\n/**\n * Performance tests for {@link ZipContent} that creates a {@link VirtualZipDataBlock}.\n *\n * @author Phillip Webb\n */\n@Disabled(\"Only used for manual testing\")\nclass VirtualZipPerformanceTests {\n\n\t@TempDir\n\tPath temp;\n\n\t@Test\n\tvoid sequentialReadPerformance() throws IOException {\n\t\tFile file = createZipWithLargeEntries();\n\t\tlong start = System.nanoTime();\n\t\ttry (ZipContent zipContent = ZipContent.open(file.toPath(), \"test/\")) {\n\t\t\ttry (InputStream in = zipContent.openRawZipData().asInputStream()) {\n\t\t\t\tZipInputStream zip = new ZipInputStream(in);\n\t\t\t\tZipEntry entry = zip.getNextEntry();\n\t\t\t\twhile (entry != null) {\n\t\t\t\t\tentry = zip.getNextEntry();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tSystem.out.println(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start));\n\t}\n\n\tprivate File createZipWithLargeEntries() throws IOException {\n\t\tbyte[] bytes = new byte[1024 * 1024];\n\t\tnew Random().nextBytes(bytes);\n\t\tFile file = this.temp.resolve(\"test.zip\").toFile();\n\t\ttry (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"test/\"));\n\t\t\tout.closeEntry();\n\t\t\tfor (int i = 0; i < 50; i++) {\n\t\t\t\tout.putNextEntry(new ZipEntry(\"test/\" + i + \".dat\"));\n\t\t\t\tout.write(bytes);\n\t\t\t\tout.closeEntry();\n\t\t\t}\n\t\t}\n\t\treturn file;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/Zip64EndOfCentralDirectoryLocatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Zip64EndOfCentralDirectoryLocator}.\n *\n * @author Phillip Webb\n */\nclass Zip64EndOfCentralDirectoryLocatorTests {\n\n\t@Test\n\tvoid findReturnsRecord() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x06, 0x07, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x03, 0x00, 0x00, 0x00 }); //\n\t\tZip64EndOfCentralDirectoryLocator eocd = Zip64EndOfCentralDirectoryLocator.find(dataBlock, 20);\n\t\tassertThat(eocd.pos()).isEqualTo(0);\n\t\tassertThat(eocd.numberOfThisDisk()).isEqualTo(1);\n\t\tassertThat(eocd.offsetToZip64EndOfCentralDirectoryRecord()).isEqualTo(2);\n\t\tassertThat(eocd.totalNumberOfDisks()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid findWhenSignatureDoesNotMatchReturnsNull() throws IOException {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x51, 0x4b, 0x06, 0x07, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x03, 0x00, 0x00, 0x00 }); //\n\t\tZip64EndOfCentralDirectoryLocator eocd = Zip64EndOfCentralDirectoryLocator.find(dataBlock, 20);\n\t\tassertThat(eocd).isNull();\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/Zip64EndOfCentralDirectoryRecordTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link Zip64EndOfCentralDirectoryRecord}.\n *\n * @author Phillip Webb\n */\nclass Zip64EndOfCentralDirectoryRecordTests {\n\n\t@Test\n\tvoid loadLoadsData() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x06, 0x06, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, 0x00, 0x00, //\n\t\t\t\t0x05, 0x00, 0x00, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //\n\t\tZip64EndOfCentralDirectoryLocator locator = new Zip64EndOfCentralDirectoryLocator(56, 0, 0, 0);\n\t\tZip64EndOfCentralDirectoryRecord eocd = Zip64EndOfCentralDirectoryRecord.load(dataBlock, locator);\n\t\tassertThat(eocd.size()).isEqualTo(56);\n\t\tassertThat(eocd.sizeOfZip64EndOfCentralDirectoryRecord()).isEqualTo(1);\n\t\tassertThat(eocd.versionMadeBy()).isEqualTo((short) 2);\n\t\tassertThat(eocd.versionNeededToExtract()).isEqualTo((short) 3);\n\t\tassertThat(eocd.numberOfThisDisk()).isEqualTo(4);\n\t\tassertThat(eocd.diskWhereCentralDirectoryStarts()).isEqualTo(5);\n\t\tassertThat(eocd.numberOfCentralDirectoryEntriesOnThisDisk()).isEqualTo(6);\n\t\tassertThat(eocd.totalNumberOfCentralDirectoryEntries()).isEqualTo(7);\n\t\tassertThat(eocd.sizeOfCentralDirectory()).isEqualTo(8);\n\t\tassertThat(eocd.offsetToStartOfCentralDirectory());\n\t}\n\n\t@Test\n\tvoid loadWhenSignatureDoesNotMatchThrowsException() {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x51, 0x4b, 0x06, 0x06, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, 0x00, 0x00, //\n\t\t\t\t0x05, 0x00, 0x00, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); //\n\t\tZip64EndOfCentralDirectoryLocator locator = new Zip64EndOfCentralDirectoryLocator(56, 0, 0, 0);\n\t\tassertThatIOException().isThrownBy(() -> Zip64EndOfCentralDirectoryRecord.load(dataBlock, locator))\n\t\t\t.withMessageContaining(\"Zip64 'End Of Central Directory Record' not found at position\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ZipCentralDirectoryFileHeaderRecordTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link ZipCentralDirectoryFileHeaderRecord}.\n *\n * @author Phillip Webb\n */\nclass ZipCentralDirectoryFileHeaderRecordTests {\n\n\t@Test\n\tvoid loadLoadsData() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x01, 0x02, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, //\n\t\t\t\t0x06, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, 0x00, 0x00, //\n\t\t\t\t0x0A, 0x00, //\n\t\t\t\t0x0B, 0x00, //\n\t\t\t\t0x0C, 0x00, //\n\t\t\t\t0x0D, 0x00, //\n\t\t\t\t0x0E, 0x00, //\n\t\t\t\t0x0F, 0x00, 0x00, 0x00, //\n\t\t\t\t0x10, 0x00, 0x00, 0x00 }); //\n\t\tZipCentralDirectoryFileHeaderRecord record = ZipCentralDirectoryFileHeaderRecord.load(dataBlock, 0);\n\t\tassertThat(record.versionMadeBy()).isEqualTo((short) 1);\n\t\tassertThat(record.versionNeededToExtract()).isEqualTo((short) 2);\n\t\tassertThat(record.generalPurposeBitFlag()).isEqualTo((short) 3);\n\t\tassertThat(record.compressionMethod()).isEqualTo((short) 4);\n\t\tassertThat(record.lastModFileTime()).isEqualTo((short) 5);\n\t\tassertThat(record.lastModFileDate()).isEqualTo((short) 6);\n\t\tassertThat(record.crc32()).isEqualTo(7);\n\t\tassertThat(record.compressedSize()).isEqualTo(8);\n\t\tassertThat(record.uncompressedSize()).isEqualTo(9);\n\t\tassertThat(record.fileNameLength()).isEqualTo((short) 10);\n\t\tassertThat(record.extraFieldLength()).isEqualTo((short) 11);\n\t\tassertThat(record.fileCommentLength()).isEqualTo((short) 12);\n\t\tassertThat(record.diskNumberStart()).isEqualTo((short) 13);\n\t\tassertThat(record.internalFileAttributes()).isEqualTo((short) 14);\n\t\tassertThat(record.externalFileAttributes()).isEqualTo(15);\n\t\tassertThat(record.offsetToLocalHeader()).isEqualTo(16);\n\t}\n\n\t@Test\n\tvoid loadWhenSignatureDoesNotMatchThrowsException() {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x51, 0x4b, 0x01, 0x02, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, //\n\t\t\t\t0x06, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, 0x00, 0x00, //\n\t\t\t\t0x0A, 0x00, //\n\t\t\t\t0x0B, 0x00, //\n\t\t\t\t0x0C, 0x00, //\n\t\t\t\t0x0D, 0x00, //\n\t\t\t\t0x0E, 0x00, //\n\t\t\t\t0x0F, 0x00, 0x00, 0x00, //\n\t\t\t\t0x10, 0x00, 0x00, 0x00 }); //\n\t\tassertThatIOException().isThrownBy(() -> ZipCentralDirectoryFileHeaderRecord.load(dataBlock, 0))\n\t\t\t.withMessageContaining(\"'Central Directory File Header Record' not found\");\n\t}\n\n\t@Test\n\tvoid sizeReturnsSize() {\n\t\tZipCentralDirectoryFileHeaderRecord record = new ZipCentralDirectoryFileHeaderRecord((short) 1, (short) 2,\n\t\t\t\t(short) 3, (short) 4, (short) 5, (short) 6, 7, 8, 9, (short) 10, (short) 11, (short) 12, (short) 13,\n\t\t\t\t(short) 14, 15, 16);\n\t\tassertThat(record.size()).isEqualTo(79L);\n\t}\n\n\t@Test\n\tvoid copyToCopiesDataToZipEntry() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x01, 0x02, //\n\t\t\t\t0x00, 0x00, //\n\t\t\t\t0x00, 0x00, //\n\t\t\t\t0x00, 0x00, //\n\t\t\t\t0x08, 0x00, //\n\t\t\t\t0x23, 0x74, //\n\t\t\t\t0x58, 0x36, //\n\t\t\t\t(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x00, 0x00, //\n\t\t\t\t0x00, 0x00, //\n\t\t\t\t0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x00, 0x00, 0x00, 0x00, //\n\t\t\t\t0x61, //\n\t\t\t\t0x62, //\n\t\t\t\t0x63 }); //\n\t\tZipCentralDirectoryFileHeaderRecord record = ZipCentralDirectoryFileHeaderRecord.load(dataBlock, 0);\n\t\tZipEntry entry = new ZipEntry(\"\");\n\t\trecord.copyTo(dataBlock, 0, entry);\n\t\tassertThat(entry.getMethod()).isEqualTo(ZipEntry.DEFLATED);\n\t\tassertThat(entry.getTimeLocal()).hasYear(2007);\n\t\tZonedDateTime expectedTime = ZonedDateTime.of(2007, 02, 24, 14, 33, 06, 0, ZoneId.systemDefault());\n\t\tassertThat(entry.getTime()).isEqualTo(expectedTime.toEpochSecond() * 1000);\n\t\tassertThat(entry.getCrc()).isEqualTo(0xFFFFFFFFL);\n\t\tassertThat(entry.getCompressedSize()).isEqualTo(1);\n\t\tassertThat(entry.getSize()).isEqualTo(2);\n\t\tassertThat(entry.getExtra()).containsExactly(0x62);\n\t\tassertThat(entry.getComment()).isEqualTo(\"c\");\n\t}\n\n\t@Test\n\tvoid withFileNameLengthReturnsUpdatedInstance() {\n\t\tZipCentralDirectoryFileHeaderRecord record = new ZipCentralDirectoryFileHeaderRecord((short) 1, (short) 2,\n\t\t\t\t(short) 3, (short) 4, (short) 5, (short) 6, 7, 8, 9, (short) 10, (short) 11, (short) 12, (short) 13,\n\t\t\t\t(short) 14, 15, 16)\n\t\t\t.withFileNameLength((short) 100);\n\t\tassertThat(record.versionMadeBy()).isEqualTo((short) 1);\n\t\tassertThat(record.versionNeededToExtract()).isEqualTo((short) 2);\n\t\tassertThat(record.generalPurposeBitFlag()).isEqualTo((short) 3);\n\t\tassertThat(record.compressionMethod()).isEqualTo((short) 4);\n\t\tassertThat(record.lastModFileTime()).isEqualTo((short) 5);\n\t\tassertThat(record.lastModFileDate()).isEqualTo((short) 6);\n\t\tassertThat(record.crc32()).isEqualTo(7);\n\t\tassertThat(record.compressedSize()).isEqualTo(8);\n\t\tassertThat(record.uncompressedSize()).isEqualTo(9);\n\t\tassertThat(record.fileNameLength()).isEqualTo((short) 100);\n\t\tassertThat(record.extraFieldLength()).isEqualTo((short) 11);\n\t\tassertThat(record.fileCommentLength()).isEqualTo((short) 12);\n\t\tassertThat(record.diskNumberStart()).isEqualTo((short) 13);\n\t\tassertThat(record.internalFileAttributes()).isEqualTo((short) 14);\n\t\tassertThat(record.externalFileAttributes()).isEqualTo(15);\n\t\tassertThat(record.offsetToLocalHeader()).isEqualTo(16);\n\t}\n\n\t@Test\n\tvoid withOffsetToLocalHeaderReturnsUpdatedInstance() {\n\t\tZipCentralDirectoryFileHeaderRecord record = new ZipCentralDirectoryFileHeaderRecord((short) 1, (short) 2,\n\t\t\t\t(short) 3, (short) 4, (short) 5, (short) 6, 7, 8, 9, (short) 10, (short) 11, (short) 12, (short) 13,\n\t\t\t\t(short) 14, 15, 16)\n\t\t\t.withOffsetToLocalHeader(100);\n\t\tassertThat(record.versionMadeBy()).isEqualTo((short) 1);\n\t\tassertThat(record.versionNeededToExtract()).isEqualTo((short) 2);\n\t\tassertThat(record.generalPurposeBitFlag()).isEqualTo((short) 3);\n\t\tassertThat(record.compressionMethod()).isEqualTo((short) 4);\n\t\tassertThat(record.lastModFileTime()).isEqualTo((short) 5);\n\t\tassertThat(record.lastModFileDate()).isEqualTo((short) 6);\n\t\tassertThat(record.crc32()).isEqualTo(7);\n\t\tassertThat(record.compressedSize()).isEqualTo(8);\n\t\tassertThat(record.uncompressedSize()).isEqualTo(9);\n\t\tassertThat(record.fileNameLength()).isEqualTo((short) 10);\n\t\tassertThat(record.extraFieldLength()).isEqualTo((short) 11);\n\t\tassertThat(record.fileCommentLength()).isEqualTo((short) 12);\n\t\tassertThat(record.diskNumberStart()).isEqualTo((short) 13);\n\t\tassertThat(record.internalFileAttributes()).isEqualTo((short) 14);\n\t\tassertThat(record.externalFileAttributes()).isEqualTo(15);\n\t\tassertThat(record.offsetToLocalHeader()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid asByteArrayReturnsByteArray() throws Exception {\n\t\tbyte[] bytes = new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x01, 0x02, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, //\n\t\t\t\t0x06, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, 0x00, 0x00, //\n\t\t\t\t0x0A, 0x00, //\n\t\t\t\t0x0B, 0x00, //\n\t\t\t\t0x0C, 0x00, //\n\t\t\t\t0x0D, 0x00, //\n\t\t\t\t0x0E, 0x00, //\n\t\t\t\t0x0F, 0x00, 0x00, 0x00, //\n\t\t\t\t0x10, 0x00, 0x00, 0x00 };\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(bytes);\n\t\tZipCentralDirectoryFileHeaderRecord record = ZipCentralDirectoryFileHeaderRecord.load(dataBlock, 0);\n\t\tassertThat(record.asByteArray()).containsExactly(bytes);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ZipContentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.attribute.FileTime;\nimport java.time.Instant;\nimport java.util.Iterator;\nimport java.util.Random;\nimport java.util.jar.Manifest;\nimport java.util.zip.CRC32;\nimport java.util.zip.Inflater;\nimport java.util.zip.InflaterInputStream;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assumptions;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.testsupport.TestJar;\nimport org.springframework.boot.loader.zip.ZipContent.Entry;\nimport org.springframework.boot.loader.zip.ZipContent.Kind;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ZipContent}.\n *\n * @author Phillip Webb\n * @author Martin Lau\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass ZipContentTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\tprivate File file;\n\n\tprivate ZipContent zipContent;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.file = new File(this.tempDir, \"test.jar\");\n\t\tTestJar.create(this.file);\n\t\tthis.zipContent = ZipContent.open(this.file.toPath());\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws Exception {\n\t\tif (this.zipContent != null) {\n\t\t\ttry {\n\t\t\t\tthis.zipContent.close();\n\t\t\t}\n\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getCommentReturnsComment() {\n\t\tassertThat(this.zipContent.getComment()).isEqualTo(\"outer\");\n\t}\n\n\t@Test\n\tvoid getCommentWhenClosedThrowsException() throws IOException {\n\t\tthis.zipContent.close();\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.zipContent.getComment())\n\t\t\t.withMessage(\"Zip content closed\");\n\t}\n\n\t@Test\n\tvoid getEntryWhenPresentReturnsEntry() {\n\t\tEntry entry = this.zipContent.getEntry(\"1.dat\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getName()).isEqualTo(\"1.dat\");\n\t}\n\n\t@Test\n\tvoid getEntryWhenMissingReturnsNull() {\n\t\tassertThat(this.zipContent.getEntry(\"missing.dat\")).isNull();\n\t}\n\n\t@Test\n\tvoid getEntryWithPrefixWhenPresentReturnsEntry() {\n\t\tEntry entry = this.zipContent.getEntry(\"1\", \".dat\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getName()).isEqualTo(\"1.dat\");\n\t}\n\n\t@Test\n\tvoid getEntryWithLongPrefixWhenNameIsShorterReturnsNull() {\n\t\tEntry entry = this.zipContent.getEntry(\"iamaverylongprefixandiwontfindanything\", \"1.dat\");\n\t\tassertThat(entry).isNull();\n\t}\n\n\t@Test\n\tvoid getEntryWithPrefixWhenMissingReturnsNull() {\n\t\tassertThat(this.zipContent.getEntry(\"miss\", \"ing.dat\")).isNull();\n\t}\n\n\t@Test\n\tvoid getEntryWhenUsingSlashesIsCompatibleWithZipFile() throws IOException {\n\t\ttry (ZipFile zipFile = new ZipFile(this.file)) {\n\t\t\tassertThat(zipFile.getEntry(\"META-INF\").getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(this.zipContent.getEntry(\"META-INF\").getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(zipFile.getEntry(\"META-INF/\").getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(this.zipContent.getEntry(\"META-INF/\").getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(zipFile.getEntry(\"d/9.dat\").getName()).isEqualTo(\"d/9.dat\");\n\t\t\tassertThat(this.zipContent.getEntry(\"d/9.dat\").getName()).isEqualTo(\"d/9.dat\");\n\t\t\tassertThat(zipFile.getEntry(\"d/9.dat/\")).isNull();\n\t\t\tassertThat(this.zipContent.getEntry(\"d/9.dat/\")).isNull();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getManifestEntry() throws Exception {\n\t\tEntry entry = this.zipContent.getEntry(\"META-INF/MANIFEST.MF\");\n\t\ttry (CloseableDataBlock dataBlock = entry.openContent()) {\n\t\t\tManifest manifest = new Manifest(asInflaterInputStream(dataBlock));\n\t\t\tassertThat(manifest.getMainAttributes().getValue(\"Built-By\")).isEqualTo(\"j1\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid getEntryAsCreatesCompatibleEntries() throws IOException {\n\t\ttry (ZipFile zipFile = new ZipFile(this.file)) {\n\t\t\tIterator<? extends ZipEntry> expected = zipFile.entries().asIterator();\n\t\t\tint i = 0;\n\t\t\twhile (expected.hasNext()) {\n\t\t\t\tEntry actual = this.zipContent.getEntry(i++);\n\t\t\t\tassertThatFieldsAreEqual(actual.as(ZipEntry::new), expected.next());\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid getKindWhenZipReturnsZip() {\n\t\tassertThat(this.zipContent.getKind()).isEqualTo(Kind.ZIP);\n\t}\n\n\t@Test\n\tvoid getKindWhenNestedZipReturnsNestedZip() throws IOException {\n\t\ttry (ZipContent nested = ZipContent.open(this.file.toPath(), \"nested.jar\")) {\n\t\t\tassertThat(nested.getKind()).isEqualTo(Kind.NESTED_ZIP);\n\t\t}\n\t}\n\n\t@Test\n\tvoid getKindWhenNestedDirectoryReturnsNestedDirectory() throws IOException {\n\t\ttry (ZipContent nested = ZipContent.open(this.file.toPath(), \"d/\")) {\n\t\t\tassertThat(nested.getKind()).isEqualTo(Kind.NESTED_DIRECTORY);\n\t\t}\n\t}\n\n\tprivate void assertThatFieldsAreEqual(ZipEntry actual, ZipEntry expected) {\n\t\tassertThat(actual.getName()).isEqualTo(expected.getName());\n\t\tassertThat(actual.getTime()).isEqualTo(expected.getTime());\n\t\tassertThat(actual.getLastModifiedTime()).isEqualTo(expected.getLastModifiedTime());\n\t\tassertThat(actual.getLastAccessTime()).isEqualTo(expected.getLastAccessTime());\n\t\tassertThat(actual.getCreationTime()).isEqualTo(expected.getCreationTime());\n\t\tassertThat(actual.getSize()).isEqualTo(expected.getSize());\n\t\tassertThat(actual.getCompressedSize()).isEqualTo(expected.getCompressedSize());\n\t\tassertThat(actual.getCrc()).isEqualTo(expected.getCrc());\n\t\tassertThat(actual.getMethod()).isEqualTo(expected.getMethod());\n\t\tassertThat(actual.getExtra()).isEqualTo(expected.getExtra());\n\t\tassertThat(actual.getComment()).isEqualTo(expected.getComment());\n\t}\n\n\t@Test\n\tvoid sizeReturnsNumberOfEntries() {\n\t\tassertThat(this.zipContent.size()).isEqualTo(12);\n\t}\n\n\t@Test\n\tvoid nestedJarFileReturnsNestedJar() throws IOException {\n\t\ttry (ZipContent nested = ZipContent.open(this.file.toPath(), \"nested.jar\")) {\n\t\t\tassertThat(nested.size()).isEqualTo(5);\n\t\t\tassertThat(nested.getComment()).isEqualTo(\"nested\");\n\t\t\tassertThat(nested.size()).isEqualTo(5);\n\t\t\tassertThat(nested.getEntry(0).getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(nested.getEntry(1).getName()).isEqualTo(\"META-INF/MANIFEST.MF\");\n\t\t\tassertThat(nested.getEntry(2).getName()).isEqualTo(\"3.dat\");\n\t\t\tassertThat(nested.getEntry(3).getName()).isEqualTo(\"4.dat\");\n\t\t\tassertThat(nested.getEntry(4).getName()).isEqualTo(\"\\u00E4.dat\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid nestedJarFileWhenNameEndsInSlashThrowsException() {\n\t\tassertThatIOException().isThrownBy(() -> ZipContent.open(this.file.toPath(), \"nested.jar/\"))\n\t\t\t.withMessageStartingWith(\"Nested entry 'nested.jar/' not found in container zip\");\n\t}\n\n\t@Test\n\tvoid nestedDirectoryReturnsNestedJar() throws IOException {\n\t\ttry (ZipContent nested = ZipContent.open(this.file.toPath(), \"d/\")) {\n\t\t\tassertThat(nested.size()).isEqualTo(1);\n\t\t\tassertThat(nested.getEntry(\"9.dat\")).isNotNull();\n\t\t\tassertThat(nested.getEntry(0).getName()).isEqualTo(\"9.dat\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid nestedDirectoryWhenNotEndingInSlashThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ZipContent.open(this.file.toPath(), \"d\"))\n\t\t\t.withMessage(\"Nested entry name must end with '/'\");\n\t}\n\n\t@Test\n\tvoid getDataWhenNestedDirectoryReturnsVirtualZipDataBlock() throws IOException {\n\t\ttry (ZipContent nested = ZipContent.open(this.file.toPath(), \"d/\")) {\n\t\t\tFile file = new File(this.tempDir, \"included.zip\");\n\t\t\twrite(file, nested.openRawZipData());\n\t\t\ttry (ZipFile loadedZipFile = new ZipFile(file)) {\n\t\t\t\tassertThat(loadedZipFile.size()).isEqualTo(1);\n\t\t\t\tassertThat(loadedZipFile.stream().map(ZipEntry::getName)).containsExactly(\"9.dat\");\n\t\t\t\tassertThat(loadedZipFile.getEntry(\"9.dat\")).isNotNull();\n\t\t\t\ttry (InputStream in = loadedZipFile.getInputStream(loadedZipFile.getEntry(\"9.dat\"))) {\n\t\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\t\tin.transferTo(out);\n\t\t\t\t\tassertThat(out.toByteArray()).containsExactly(0x09);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid loadWhenHasFrontMatterOpensZip() throws IOException {\n\t\tFile fileWithFrontMatter = new File(this.tempDir, \"withfrontmatter.jar\");\n\t\tFileOutputStream outputStream = new FileOutputStream(fileWithFrontMatter);\n\t\tStreamUtils.copy(\"#/bin/bash\", Charset.defaultCharset(), outputStream);\n\t\tFileCopyUtils.copy(new FileInputStream(this.file), outputStream);\n\t\ttry (ZipContent zip = ZipContent.open(fileWithFrontMatter.toPath())) {\n\t\t\tassertThat(zip.size()).isEqualTo(12);\n\t\t\tassertThat(zip.getEntry(0).getName()).isEqualTo(\"META-INF/\");\n\t\t\tassertThat(zip.getEntry(1).getName()).isEqualTo(\"META-INF/MANIFEST.MF\");\n\t\t\tassertThat(zip.getEntry(2).getName()).isEqualTo(\"1.dat\");\n\t\t\tassertThat(zip.getEntry(3).getName()).isEqualTo(\"2.dat\");\n\t\t\tassertThat(zip.getEntry(4).getName()).isEqualTo(\"d/\");\n\t\t\tassertThat(zip.getEntry(5).getName()).isEqualTo(\"d/9.dat\");\n\t\t\tassertThat(zip.getEntry(6).getName()).isEqualTo(\"special/\");\n\t\t\tassertThat(zip.getEntry(7).getName()).isEqualTo(\"special/\\u00EB.dat\");\n\t\t\tassertThat(zip.getEntry(8).getName()).isEqualTo(\"nested.jar\");\n\t\t\tassertThat(zip.getEntry(9).getName()).isEqualTo(\"another-nested.jar\");\n\t\t\tassertThat(zip.getEntry(10).getName()).isEqualTo(\"space nested.jar\");\n\t\t\tassertThat(zip.getEntry(11).getName()).isEqualTo(\"multi-release.jar\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid openWhenZip64ThatExceedsZipEntryLimitOpensZip() throws Exception {\n\t\tFile zip64File = new File(this.tempDir, \"zip64.zip\");\n\t\tFileCopyUtils.copy(zip64Bytes(), zip64File);\n\t\ttry (ZipContent zip64Content = ZipContent.open(zip64File.toPath())) {\n\t\t\tassertThat(zip64Content.size()).isEqualTo(65537);\n\t\t\tfor (int i = 0; i < zip64Content.size(); i++) {\n\t\t\t\tEntry entry = zip64Content.getEntry(i);\n\t\t\t\ttry (CloseableDataBlock dataBlock = entry.openContent()) {\n\t\t\t\t\tassertThat(asInflaterInputStream(dataBlock)).hasContent(\"Entry \" + (i + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid openWhenZip64ThatExceedsZipSizeLimitOpensZip() throws Exception {\n\t\tAssumptions.assumeTrue(this.tempDir.getFreeSpace() > 6L * 1024 * 1024 * 1024, \"Insufficient disk space\");\n\t\tFile zip64File = new File(this.tempDir, \"zip64.zip\");\n\t\tFile entryFile = new File(this.tempDir, \"entry.dat\");\n\t\tCRC32 crc32 = new CRC32();\n\t\ttry (FileOutputStream entryOut = new FileOutputStream(entryFile)) {\n\t\t\tbyte[] data = new byte[1024 * 1024];\n\t\t\tnew Random().nextBytes(data);\n\t\t\tfor (int i = 0; i < 1024; i++) {\n\t\t\t\tentryOut.write(data);\n\t\t\t\tcrc32.update(data);\n\t\t\t}\n\t\t}\n\t\ttry (ZipOutputStream zipOutput = new ZipOutputStream(new FileOutputStream(zip64File))) {\n\t\t\tfor (int i = 0; i < 6; i++) {\n\t\t\t\tZipEntry storedEntry = new ZipEntry(\"huge-\" + i);\n\t\t\t\tstoredEntry.setSize(entryFile.length());\n\t\t\t\tstoredEntry.setCompressedSize(entryFile.length());\n\t\t\t\tstoredEntry.setCrc(crc32.getValue());\n\t\t\t\tstoredEntry.setMethod(ZipEntry.STORED);\n\t\t\t\tzipOutput.putNextEntry(storedEntry);\n\t\t\t\ttry (FileInputStream entryIn = new FileInputStream(entryFile)) {\n\t\t\t\t\tStreamUtils.copy(entryIn, zipOutput);\n\t\t\t\t}\n\t\t\t\tzipOutput.closeEntry();\n\t\t\t}\n\t\t}\n\t\ttry (ZipContent zip64Content = ZipContent.open(zip64File.toPath())) {\n\t\t\tassertThat(zip64Content.size()).isEqualTo(6);\n\t\t}\n\t}\n\n\t@Test\n\tvoid nestedZip64CanBeRead() throws Exception {\n\t\tFile containerFile = new File(this.tempDir, \"outer.zip\");\n\t\ttry (ZipOutputStream jarOutput = new ZipOutputStream(new FileOutputStream(containerFile))) {\n\t\t\tZipEntry nestedEntry = new ZipEntry(\"nested-zip64.zip\");\n\t\t\tbyte[] contents = zip64Bytes();\n\t\t\tnestedEntry.setSize(contents.length);\n\t\t\tnestedEntry.setCompressedSize(contents.length);\n\t\t\tCRC32 crc32 = new CRC32();\n\t\t\tcrc32.update(contents);\n\t\t\tnestedEntry.setCrc(crc32.getValue());\n\t\t\tnestedEntry.setMethod(ZipEntry.STORED);\n\t\t\tjarOutput.putNextEntry(nestedEntry);\n\t\t\tjarOutput.write(contents);\n\t\t\tjarOutput.closeEntry();\n\t\t}\n\t\ttry (ZipContent nestedZip = ZipContent.open(containerFile.toPath(), \"nested-zip64.zip\")) {\n\t\t\tassertThat(nestedZip.size()).isEqualTo(65537);\n\t\t\tfor (int i = 0; i < nestedZip.size(); i++) {\n\t\t\t\tEntry entry = nestedZip.getEntry(i);\n\t\t\t\ttry (CloseableDataBlock content = entry.openContent()) {\n\t\t\t\t\tassertThat(asInflaterInputStream(content)).hasContent(\"Entry \" + (i + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate byte[] zip64Bytes() throws IOException {\n\t\tByteArrayOutputStream bytes = new ByteArrayOutputStream();\n\t\tZipOutputStream zipOutput = new ZipOutputStream(bytes);\n\t\tfor (int i = 0; i < 65537; i++) {\n\t\t\tzipOutput.putNextEntry(new ZipEntry(i + \".dat\"));\n\t\t\tzipOutput.write((\"Entry \" + (i + 1)).getBytes(StandardCharsets.UTF_8));\n\t\t\tzipOutput.closeEntry();\n\t\t}\n\t\tzipOutput.close();\n\t\treturn bytes.toByteArray();\n\t}\n\n\t@Test\n\tvoid entryWithEpochTimeOfZeroShouldNotFail() throws Exception {\n\t\tFile file = createZipFileWithEpochTimeOfZero();\n\t\ttry (ZipContent zip = ZipContent.open(file.toPath())) {\n\t\t\tZipEntry entry = zip.getEntry(0).as(ZipEntry::new);\n\t\t\tassertThat(entry.getLastModifiedTime().toInstant()).isEqualTo(Instant.EPOCH);\n\t\t\tassertThat(entry.getName()).isEqualTo(\"1.dat\");\n\t\t}\n\t}\n\n\tprivate File createZipFileWithEpochTimeOfZero() throws Exception {\n\t\tFile file = new File(this.tempDir, \"temp.zip\");\n\t\tString comment = \"outer\";\n\t\ttry (ZipOutputStream zipOutput = new ZipOutputStream(new FileOutputStream(file))) {\n\t\t\tzipOutput.setComment(comment);\n\t\t\tZipEntry entry = new ZipEntry(\"1.dat\");\n\t\t\tentry.setLastModifiedTime(FileTime.from(Instant.EPOCH));\n\t\t\tzipOutput.putNextEntry(entry);\n\t\t\tzipOutput.write(new byte[] { (byte) 1 });\n\t\t\tzipOutput.closeEntry();\n\t\t}\n\t\tByteBuffer data = ByteBuffer.wrap(Files.readAllBytes(file.toPath()));\n\t\tdata.order(ByteOrder.LITTLE_ENDIAN);\n\t\tint endOfCentralDirectoryRecordPos = data.remaining() - ZipFile.ENDHDR - comment.getBytes().length;\n\t\tdata.position(endOfCentralDirectoryRecordPos + ZipFile.ENDOFF);\n\t\tint startOfCentralDirectoryOffset = data.getInt();\n\t\tdata.position(startOfCentralDirectoryOffset + ZipFile.CENOFF);\n\t\tint localHeaderPosition = data.getInt();\n\t\twriteTimeBlock(data.array(), startOfCentralDirectoryOffset + ZipFile.CENTIM, 0);\n\t\twriteTimeBlock(data.array(), localHeaderPosition + ZipFile.LOCTIM, 0);\n\t\tFile zerotimedFile = new File(this.tempDir, \"zerotimed.zip\");\n\t\tFiles.write(zerotimedFile.toPath(), data.array());\n\t\treturn zerotimedFile;\n\t}\n\n\t@Test\n\tvoid getInfoReturnsComputedInfo() {\n\t\tZipInfo info = this.zipContent.getInfo(ZipInfo.class, ZipInfo::get);\n\t\tassertThat(info.size()).isEqualTo(12);\n\t}\n\n\tprivate static void writeTimeBlock(byte[] data, int pos, int value) {\n\t\tdata[pos] = (byte) (value & 0xff);\n\t\tdata[pos + 1] = (byte) ((value >> 8) & 0xff);\n\t\tdata[pos + 2] = (byte) ((value >> 16) & 0xff);\n\t\tdata[pos + 3] = (byte) ((value >> 24) & 0xff);\n\t}\n\n\tprivate InputStream asInflaterInputStream(DataBlock dataBlock) throws IOException {\n\t\tByteBuffer buffer = ByteBuffer.allocate((int) dataBlock.size() + 1);\n\t\tbuffer.limit(buffer.limit() - 1);\n\t\tdataBlock.readFully(buffer, 0);\n\t\tByteArrayInputStream in = new ByteArrayInputStream(buffer.array());\n\t\treturn new InflaterInputStream(in, new Inflater(true));\n\t}\n\n\tprivate void write(File file, CloseableDataBlock dataBlock) throws IOException {\n\t\tByteBuffer buffer = ByteBuffer.allocate((int) dataBlock.size());\n\t\tdataBlock.readFully(buffer, 0);\n\t\tFiles.write(file.toPath(), buffer.array());\n\t\tdataBlock.close();\n\t}\n\n\tprivate static class ZipInfo {\n\n\t\tprivate int size;\n\n\t\tZipInfo(int size) {\n\t\t\tthis.size = size;\n\t\t}\n\n\t\tint size() {\n\t\t\treturn this.size;\n\t\t}\n\n\t\tstatic ZipInfo get(ZipContent content) {\n\t\t\treturn new ZipInfo(content.size());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ZipDataDescriptorRecordTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipDataDescriptorRecord}.\n *\n * @author Phillip Webb\n */\nclass ZipDataDescriptorRecordTests {\n\n\tprivate static final short S0 = 0;\n\n\t@Test\n\tvoid loadWhenHasSignatureLoadsData() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x07, 0x08, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, //\n\t\t\t\t0x03, 0x00, 0x00, 0x00 }); //\n\t\tZipDataDescriptorRecord record = ZipDataDescriptorRecord.load(dataBlock, 0);\n\t\tassertThat(record.includeSignature()).isTrue();\n\t\tassertThat(record.crc32()).isEqualTo(1);\n\t\tassertThat(record.compressedSize()).isEqualTo(2);\n\t\tassertThat(record.uncompressedSize()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid loadWhenHasNoSignatureLoadsData() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, //\n\t\t\t\t0x03, 0x00, 0x00, 0x00 }); //\n\t\tZipDataDescriptorRecord record = ZipDataDescriptorRecord.load(dataBlock, 0);\n\t\tassertThat(record.includeSignature()).isFalse();\n\t\tassertThat(record.crc32()).isEqualTo(1);\n\t\tassertThat(record.compressedSize()).isEqualTo(2);\n\t\tassertThat(record.uncompressedSize()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid sizeWhenIncludeSignatureReturnsSize() {\n\t\tZipDataDescriptorRecord record = new ZipDataDescriptorRecord(true, 0, 0, 0);\n\t\tassertThat(record.size()).isEqualTo(16);\n\t}\n\n\t@Test\n\tvoid sizeWhenNotIncludeSignatureReturnsSize() {\n\t\tZipDataDescriptorRecord record = new ZipDataDescriptorRecord(false, 0, 0, 0);\n\t\tassertThat(record.size()).isEqualTo(12);\n\t}\n\n\t@Test\n\tvoid asByteArrayWhenIncludeSignatureReturnsByteArray() throws Exception {\n\t\tbyte[] bytes = new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x07, 0x08, //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, //\n\t\t\t\t0x03, 0x00, 0x00, 0x00 }; //\n\t\tZipDataDescriptorRecord record = ZipDataDescriptorRecord.load(new ByteArrayDataBlock(bytes), 0);\n\t\tassertThat(record.asByteArray()).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid asByteArrayWhenNotIncludeSignatureReturnsByteArray() throws Exception {\n\t\tbyte[] bytes = new byte[] { //\n\t\t\t\t0x01, 0x00, 0x00, 0x00, //\n\t\t\t\t0x02, 0x00, 0x00, 0x00, //\n\t\t\t\t0x03, 0x00, 0x00, 0x00 }; //\n\t\tZipDataDescriptorRecord record = ZipDataDescriptorRecord.load(new ByteArrayDataBlock(bytes), 0);\n\t\tassertThat(record.asByteArray()).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid isPresentBasedOnFlagWhenPresentReturnsTrue() {\n\t\ttestIsPresentBasedOnFlag((short) 0x8, true);\n\t}\n\n\t@Test\n\tvoid isPresentBasedOnFlagWhenNotPresentReturnsFalse() {\n\t\ttestIsPresentBasedOnFlag((short) 0x0, false);\n\t}\n\n\tprivate void testIsPresentBasedOnFlag(short flag, boolean expected) {\n\t\tZipCentralDirectoryFileHeaderRecord centralRecord = new ZipCentralDirectoryFileHeaderRecord(S0, S0, flag, S0,\n\t\t\t\tS0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0, S0);\n\t\tZipLocalFileHeaderRecord localRecord = new ZipLocalFileHeaderRecord(S0, flag, S0, S0, S0, S0, S0, S0, S0, S0);\n\t\tassertThat(ZipDataDescriptorRecord.isPresentBasedOnFlag(flag)).isEqualTo(expected);\n\t\tassertThat(ZipDataDescriptorRecord.isPresentBasedOnFlag(centralRecord)).isEqualTo(expected);\n\t\tassertThat(ZipDataDescriptorRecord.isPresentBasedOnFlag(localRecord)).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ZipEndOfCentralDirectoryRecordTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link ZipEndOfCentralDirectoryRecord}.\n *\n * @author Phillip Webb\n */\nclass ZipEndOfCentralDirectoryRecordTests {\n\n\t@Test\n\tvoid loadLocatesAndLoadsData() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x05, 0x06, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, 0x00, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00 }); //\n\t\tZipEndOfCentralDirectoryRecord.Located located = ZipEndOfCentralDirectoryRecord.load(dataBlock);\n\t\tassertThat(located.pos()).isEqualTo(0L);\n\t\tZipEndOfCentralDirectoryRecord record = located.endOfCentralDirectoryRecord();\n\t\tassertThat(record.numberOfThisDisk()).isEqualTo((short) 1);\n\t\tassertThat(record.diskWhereCentralDirectoryStarts()).isEqualTo((short) 2);\n\t\tassertThat(record.numberOfCentralDirectoryEntriesOnThisDisk()).isEqualTo((short) 3);\n\t\tassertThat(record.totalNumberOfCentralDirectoryEntries()).isEqualTo((short) 4);\n\t\tassertThat(record.sizeOfCentralDirectory()).isEqualTo(5);\n\t\tassertThat(record.offsetToStartOfCentralDirectory()).isEqualTo(6);\n\t\tassertThat(record.commentLength()).isEqualTo((short) 7);\n\t}\n\n\t@Test\n\tvoid loadWhenMultipleBuffersBackLoadsData() throws Exception {\n\t\tbyte[] bytes = new byte[ZipEndOfCentralDirectoryRecord.BUFFER_SIZE * 4];\n\t\tbyte[] data = new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x05, 0x06, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, 0x00, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00 }; //\n\t\tSystem.arraycopy(data, 0, bytes, 4, data.length);\n\t\tZipEndOfCentralDirectoryRecord.Located located = ZipEndOfCentralDirectoryRecord\n\t\t\t.load(new ByteArrayDataBlock(bytes));\n\t\tassertThat(located.pos()).isEqualTo(4L);\n\t}\n\n\t@Test\n\tvoid loadWhenSignatureDoesNotMatchThrowsException() {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x51, 0x4b, 0x05, 0x06, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, 0x00, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00 }); //\n\t\tassertThatIOException().isThrownBy(() -> ZipEndOfCentralDirectoryRecord.load(dataBlock))\n\t\t\t.withMessageContaining(\"'End Of Central Directory Record' not found\");\n\t}\n\n\t@Test\n\tvoid asByteArrayReturnsByteArray() throws Exception {\n\t\tbyte[] bytes = new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x05, 0x06, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, 0x00, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00 }; //\n\t\tZipEndOfCentralDirectoryRecord.Located located = ZipEndOfCentralDirectoryRecord\n\t\t\t.load(new ByteArrayDataBlock(bytes));\n\t\tassertThat(located.endOfCentralDirectoryRecord().asByteArray()).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid sizeReturnsSize() {\n\t\tZipEndOfCentralDirectoryRecord record = new ZipEndOfCentralDirectoryRecord((short) 1, (short) 2, (short) 3,\n\t\t\t\t(short) 4, 5, 6, (short) 7);\n\t\tassertThat(record.size()).isEqualTo(29L);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ZipLocalFileHeaderRecordTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link ZipLocalFileHeaderRecord}.\n *\n * @author Phillip Webb\n */\nclass ZipLocalFileHeaderRecordTests {\n\n\t@Test\n\tvoid loadLoadsData() throws Exception {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x03, 0x04, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, //\n\t\t\t\t0x0A, 0x00 }); //\n\t\tZipLocalFileHeaderRecord record = ZipLocalFileHeaderRecord.load(dataBlock, 0);\n\t\tassertThat(record.versionNeededToExtract()).isEqualTo((short) 1);\n\t\tassertThat(record.generalPurposeBitFlag()).isEqualTo((short) 2);\n\t\tassertThat(record.compressionMethod()).isEqualTo((short) 3);\n\t\tassertThat(record.lastModFileTime()).isEqualTo((short) 4);\n\t\tassertThat(record.lastModFileDate()).isEqualTo((short) 5);\n\t\tassertThat(record.crc32()).isEqualTo(6);\n\t\tassertThat(record.compressedSize()).isEqualTo(7);\n\t\tassertThat(record.uncompressedSize()).isEqualTo(8);\n\t\tassertThat(record.fileNameLength()).isEqualTo((short) 9);\n\t\tassertThat(record.extraFieldLength()).isEqualTo((short) 10);\n\t}\n\n\t@Test\n\tvoid loadWhenSignatureDoesNotMatchThrowsException() {\n\t\tDataBlock dataBlock = new ByteArrayDataBlock(new byte[] { //\n\t\t\t\t0x51, 0x4b, 0x03, 0x04, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, //\n\t\t\t\t0x0A, 0x00 }); //\n\t\tassertThatIOException().isThrownBy(() -> ZipLocalFileHeaderRecord.load(dataBlock, 0))\n\t\t\t.withMessageContaining(\"'Local File Header Record' not found\");\n\t}\n\n\t@Test\n\tvoid sizeReturnsSize() {\n\t\tZipLocalFileHeaderRecord record = new ZipLocalFileHeaderRecord((short) 1, (short) 2, (short) 3, (short) 4,\n\t\t\t\t(short) 5, 6, 7, 8, (short) 9, (short) 10);\n\t\tassertThat(record.size()).isEqualTo(49L);\n\t}\n\n\t@Test\n\tvoid withExtraFieldLengthReturnsUpdatedInstance() {\n\t\tZipLocalFileHeaderRecord record = new ZipLocalFileHeaderRecord((short) 1, (short) 2, (short) 3, (short) 4,\n\t\t\t\t(short) 5, 6, 7, 8, (short) 9, (short) 10)\n\t\t\t.withExtraFieldLength((short) 100);\n\t\tassertThat(record.extraFieldLength()).isEqualTo((short) 100);\n\t}\n\n\t@Test\n\tvoid withFileNameLengthReturnsUpdatedInstance() {\n\t\tZipLocalFileHeaderRecord record = new ZipLocalFileHeaderRecord((short) 1, (short) 2, (short) 3, (short) 4,\n\t\t\t\t(short) 5, 6, 7, 8, (short) 9, (short) 10)\n\t\t\t.withFileNameLength((short) 100);\n\t\tassertThat(record.fileNameLength()).isEqualTo((short) 100);\n\t}\n\n\t@Test\n\tvoid asByteArrayReturnsByteArray() throws Exception {\n\t\tbyte[] bytes = new byte[] { //\n\t\t\t\t0x50, 0x4b, 0x03, 0x04, //\n\t\t\t\t0x01, 0x00, //\n\t\t\t\t0x02, 0x00, //\n\t\t\t\t0x03, 0x00, //\n\t\t\t\t0x04, 0x00, //\n\t\t\t\t0x05, 0x00, //\n\t\t\t\t0x06, 0x00, 0x00, 0x00, //\n\t\t\t\t0x07, 0x00, 0x00, 0x00, //\n\t\t\t\t0x08, 0x00, 0x00, 0x00, //\n\t\t\t\t0x09, 0x00, //\n\t\t\t\t0x0A, 0x00 }; //\n\t\tZipLocalFileHeaderRecord record = ZipLocalFileHeaderRecord.load(new ByteArrayDataBlock(bytes), 0);\n\t\tassertThat(record.asByteArray()).isEqualTo(bytes);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/java/org/springframework/boot/loader/zip/ZipStringTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.zip;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.assertj.core.api.AbstractBooleanAssert;\nimport org.assertj.core.api.AbstractIntegerAssert;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipString}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ZipStringTests {\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid hashGeneratesCorrectHashCode(HashSourceType sourceType) throws Exception {\n\t\ttestHash(sourceType, true, \"abcABC123xyz!\");\n\t\ttestHash(sourceType, false, \"abcABC123xyz!\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid hashWhenHasSpecialCharsGeneratesCorrectHashCode(HashSourceType sourceType) throws Exception {\n\t\ttestHash(sourceType, true, \"special/\\u00EB.dat\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid hashWhenHasCyrillicCharsGeneratesCorrectHashCode(HashSourceType sourceType) throws Exception {\n\t\ttestHash(sourceType, true, \"\\u0432\\u0435\\u0441\\u043D\\u0430\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid hashWhenHasEmojiGeneratesCorrectHashCode(HashSourceType sourceType) throws Exception {\n\t\ttestHash(sourceType, true, \"\\ud83d\\udca9\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid hashWhenOnlyDifferenceIsEndSlashGeneratesSameHashCode(HashSourceType sourceType) throws Exception {\n\t\ttestHash(sourceType, \"\", true, \"/\".hashCode());\n\t\ttestHash(sourceType, \"/\", true, \"/\".hashCode());\n\t\ttestHash(sourceType, \"a/b\", true, \"a/b/\".hashCode());\n\t\ttestHash(sourceType, \"a/b/\", true, \"a/b/\".hashCode());\n\t}\n\n\tvoid testHash(HashSourceType sourceType, boolean addSlash, String source) throws Exception {\n\t\tString expected = (addSlash && !source.endsWith(\"/\")) ? source + \"/\" : source;\n\t\ttestHash(sourceType, source, addSlash, expected.hashCode());\n\t}\n\n\tvoid testHash(HashSourceType sourceType, String source, boolean addEndSlash, int expected) throws Exception {\n\t\tswitch (sourceType) {\n\t\t\tcase STRING -> {\n\t\t\t\tassertThat(ZipString.hash(source, addEndSlash)).isEqualTo(expected);\n\t\t\t}\n\t\t\tcase CHAR_SEQUENCE -> {\n\t\t\t\tCharSequence charSequence = new StringBuilder(source);\n\t\t\t\tassertThat(ZipString.hash(charSequence, addEndSlash)).isEqualTo(expected);\n\t\t\t}\n\t\t\tcase DATA_BLOCK -> {\n\t\t\t\tByteArrayDataBlock dataBlock = new ByteArrayDataBlock(source.getBytes(StandardCharsets.UTF_8));\n\t\t\t\tassertThat(ZipString.hash(null, dataBlock, 0, (int) dataBlock.size(), addEndSlash)).isEqualTo(expected);\n\t\t\t}\n\t\t\tcase SINGLE_BYTE_READ_DATA_BLOCK -> {\n\t\t\t\tByteArrayDataBlock dataBlock = new ByteArrayDataBlock(source.getBytes(StandardCharsets.UTF_8), 1);\n\t\t\t\tassertThat(ZipString.hash(null, dataBlock, 0, (int) dataBlock.size(), addEndSlash)).isEqualTo(expected);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid matchesWhenExactMatchReturnsTrue() throws Exception {\n\t\tassertMatches(\"one/two/three\", \"one/two/three\", false).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenNotMatchWithSameLengthReturnsFalse() throws Exception {\n\t\tassertMatches(\"one/two/three\", \"one/too/three\", false).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenExactMatchWithSpecialCharsReturnsTrue() throws Exception {\n\t\tassertMatches(\"special/\\u00EB.dat\", \"special/\\u00EB.dat\", false).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenExactMatchWithCyrillicCharsReturnsTrue() throws Exception {\n\t\tassertMatches(\"\\u0432\\u0435\\u0441\\u043D\\u0430\", \"\\u0432\\u0435\\u0441\\u043D\\u0430\", false).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenNoMatchWithCyrillicCharsReturnsFalse() throws Exception {\n\t\tassertMatches(\"\\u0432\\u0435\\u0441\\u043D\\u0430\", \"\\u0432\\u0435\\u0441\\u043D\\u043D\", false).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenExactMatchWithEmojiCharsReturnsTrue() throws Exception {\n\t\tassertMatches(\"\\ud83d\\udca9\", \"\\ud83d\\udca9\", false).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWithAddSlash() throws Exception {\n\t\tassertMatches(\"META-INF/MANFIFEST.MF\", \"META-INF/MANFIFEST.MF\", true).isTrue();\n\t\tassertMatches(\"one/two/three/\", \"one/two/three\", true).isTrue();\n\t\tassertMatches(\"one/two/three\", \"one/two/three/\", true).isFalse();\n\t\tassertMatches(\"one/two/three/\", \"one/too/three\", true).isFalse();\n\t\tassertMatches(\"one/two/three\", \"one/too/three/\", true).isFalse();\n\t\tassertMatches(\"one/two/three//\", \"one/two/three\", true).isFalse();\n\t\tassertMatches(\"one/two/three\", \"one/two/three//\", true).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenDataBlockShorterThenCharSequenceReturnsFalse() throws Exception {\n\t\tassertMatches(\"one/two/thre\", \"one/two/three\", false).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenCharSequenceShorterThanDataBlockReturnsFalse() throws Exception {\n\t\tassertMatches(\"one/two/three\", \"one/two/thre\", false).isFalse();\n\t}\n\n\t@Test\n\tvoid startsWithWhenStartsWith() throws Exception {\n\t\tassertStartsWith(\"one/two\", \"one/\").isEqualTo(4);\n\t}\n\n\t@Test\n\tvoid startsWithWhenExact() throws Exception {\n\t\tassertStartsWith(\"one/\", \"one/\").isEqualTo(4);\n\t}\n\n\t@Test\n\tvoid startsWithWhenTooShort() throws Exception {\n\t\tassertStartsWith(\"one/two\", \"one/two/three/\").isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid startsWithWhenDoesNotStartWith() throws Exception {\n\t\tassertStartsWith(\"one/three/\", \"one/two/\").isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid zipStringWhenMultiCodePointAtBufferBoundary() throws Exception {\n\t\tStringBuilder source = new StringBuilder();\n\t\tsource.append(\"A\".repeat(ZipString.BUFFER_SIZE - 1));\n\t\tsource.append(\"\\u1EFF\");\n\t\tString charSequence = source.toString();\n\t\tsource.append(\"suffix\");\n\t\tassertStartsWith(source.toString(), charSequence);\n\t}\n\n\tprivate AbstractBooleanAssert<?> assertMatches(String source, CharSequence charSequence, boolean addSlash)\n\t\t\tthrows Exception {\n\t\tByteArrayDataBlock dataBlock = new ByteArrayDataBlock(source.getBytes(StandardCharsets.UTF_8));\n\t\treturn assertThat(ZipString.matches(null, dataBlock, 0, (int) dataBlock.size(), charSequence, addSlash));\n\t}\n\n\tprivate AbstractIntegerAssert<?> assertStartsWith(String source, CharSequence charSequence) throws IOException {\n\t\tByteArrayDataBlock dataBlock = new ByteArrayDataBlock(source.getBytes(StandardCharsets.UTF_8));\n\t\treturn assertThat(ZipString.startsWith(null, dataBlock, 0, (int) dataBlock.size(), charSequence));\n\t}\n\n\tenum HashSourceType {\n\n\t\tSTRING, CHAR_SEQUENCE, DATA_BLOCK, SINGLE_BYTE_READ_DATA_BLOCK\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties",
    "content": "loader.main: demo.Application\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/BOOT-INF/classes/bar.properties",
    "content": "loader.main: my.BootInfBarApplication\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/BOOT-INF/classes/foo.properties",
    "content": "foo: Application\nloader.main: my.${foo}\nloader.path: etc\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/BOOT-INF/classes/loader.properties",
    "content": "loader.main: demo.Application\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/META-INF/spring.factories",
    "content": "# Jar Modes\norg.springframework.boot.loader.jarmode.JarMode=\\\norg.springframework.boot.loader.jarmode.TestJarMode"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/bar.properties",
    "content": "loader.main: my.BarApplication\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/explodedsample/ExampleClass.txt",
    "content": "/*\n * Copyright 2012-2020 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage explodedsample;\n\n/**\n * Example class used to test class loading.\n *\n * @author Phillip Webb\n */\npublic class ExampleClass {\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/home/loader.properties",
    "content": "loader.main: demo.HomeApplication\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/org/springframework/boot/loader/launch/classpath-index-file.idx",
    "content": "- \"BOOT-INF/layers/one/lib/a.jar\"\n- \"BOOT-INF/layers/one/lib/b.jar\"\n- \"BOOT-INF/layers/one/lib/c.jar\"\n- \"BOOT-INF/layers/two/lib/d.jar\"\n- \"BOOT-INF/layers/two/lib/e.jar\"\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/placeholders/loader.properties",
    "content": "foo.main: demo.FooApplication\n"
  },
  {
    "path": "loader/spring-boot-loader/src/test/resources/root/META-INF/spring/application.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n</beans>\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Loader Tools\"\n\nProvider<Directory> generatedResources = layout.buildDirectory.dir(\"generated-resources/main\")\n\nconfigurations {\n\tloader {\n\t\textendsFrom dependencyManagement\n\t\ttransitive = false\n\t}\n\tjarmode {\n\t\textendsFrom dependencyManagement\n\t\ttransitive = false\n\t}\n}\n\ndependencies {\n\tapi(\"org.apache.commons:commons-compress\")\n\tapi(\"org.springframework:spring-core\")\n\n\tcompileOnly(\"ch.qos.logback:logback-classic\")\n\n\tloader(project(\":loader:spring-boot-loader\"))\n\n\tjarmode(project(\":loader:spring-boot-jarmode-tools\"))\n\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.mockito:mockito-core\")\n\ttestImplementation(\"org.zeroturnaround:zt-zip:1.13\")\n}\n\ntasks.register(\"loaderJar\", Jar) {\n\tdependsOn configurations.loader\n\tfrom {\n\t\tzipTree(configurations.loader.incoming.files.singleFile).matching {\n\t\t\texclude \"META-INF/LICENSE.txt\"\n\t\t\texclude \"META-INF/NOTICE.txt\"\n\t\t\texclude \"META-INF/spring-boot.properties\"\n\t\t}\n\t}\n\tarchiveFileName = \"spring-boot-loader.jar\"\n\tdestinationDirectory = file(generatedResources.map {it.dir(\"META-INF/loader\") })\n}\n\ntasks.register(\"toolsJar\", Sync) {\n\tdependsOn configurations.jarmode\n\tfrom {\n\t\tfile(configurations.jarmode.incoming.files.singleFile)\n\t}\n\trename({ \"spring-boot-jarmode-tools.jar\" })\n\tinto(file(generatedResources.map { it.dir(\"META-INF/jarmode\") }))\n}\n\nsourceSets {\n\tmain {\n\t\toutput.dir(generatedResources, builtBy: [toolsJar, loaderJar])\n\t}\n}\n\ntasks.named(\"compileJava\") {\n\toptions.compilerArgs -= ['-Werror']\n}\n\nplugins.withType(EclipsePlugin) {\n\teclipse {\n\t\tclasspath.file { merger ->\n\t\t\tmerger.beforeMerged { content ->\n\t\t\t\tif (content instanceof org.gradle.plugins.ide.eclipse.model.Classpath) {\n\t\t\t\t\tcontent.entries.add(new org.gradle.plugins.ide.eclipse.model.SourceFolder(\"build/generated-resources/main\", \"bin/main\"))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collection;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.JarInputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.CRC32;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.commons.compress.archivers.jar.JarArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.UnixStat;\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Abstract base class for JAR writers.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 2.3.0\n */\npublic abstract class AbstractJarWriter implements LoaderClassesWriter {\n\n\tprivate static final int BUFFER_SIZE = 32 * 1024;\n\n\tprivate static final int UNIX_FILE_MODE = UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM;\n\n\tprivate static final int UNIX_DIR_MODE = UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM;\n\n\tprivate final Set<String> writtenEntries = new HashSet<>();\n\n\tprivate @Nullable Layers layers;\n\n\tprivate @Nullable LayersIndex layersIndex;\n\n\t/**\n\t * Update this writer to use specific layers.\n\t * @param layers the layers to use\n\t * @param layersIndex the layers index to update\n\t */\n\tvoid useLayers(@Nullable Layers layers, @Nullable LayersIndex layersIndex) {\n\t\tthis.layers = layers;\n\t\tthis.layersIndex = layersIndex;\n\t}\n\n\t/**\n\t * Write the specified manifest.\n\t * @param manifest the manifest to write\n\t * @throws IOException of the manifest cannot be written\n\t */\n\tpublic void writeManifest(Manifest manifest) throws IOException {\n\t\tJarArchiveEntry entry = new JarArchiveEntry(\"META-INF/MANIFEST.MF\");\n\t\twriteEntry(entry, manifest::write);\n\t}\n\n\tfinal void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,\n\t\t\tFunction<JarEntry, @Nullable Library> libraryLookup) throws IOException {\n\t\tEnumeration<JarEntry> entries = jarFile.entries();\n\t\twhile (entries.hasMoreElements()) {\n\t\t\tJarEntry entry = entries.nextElement();\n\t\t\tLibrary library = libraryLookup.apply(entry);\n\t\t\tif (library == null || library.isIncluded()) {\n\t\t\t\twriteEntry(jarFile, entryTransformer, unpackHandler, new JarArchiveEntry(entry), library);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void writeEntry(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,\n\t\t\tJarArchiveEntry entry, @Nullable Library library) throws IOException {\n\t\tsetUpEntry(jarFile, entry, unpackHandler);\n\t\ttry (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {\n\t\t\tEntryWriter entryWriter = new InputStreamEntryWriter(inputStream);\n\t\t\tJarArchiveEntry transformedEntry = entryTransformer.transform(entry);\n\t\t\tif (transformedEntry != null) {\n\t\t\t\twriteEntry(transformedEntry, library, entryWriter);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void setUpEntry(JarFile jarFile, JarArchiveEntry entry, UnpackHandler unpackHandler) throws IOException {\n\t\ttry (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {\n\t\t\tif (inputStream.hasZipHeader() && entry.getMethod() != ZipEntry.STORED) {\n\t\t\t\tnew StoredEntryPreparator(inputStream, unpackHandler.requiresUnpack(entry.getName()))\n\t\t\t\t\t.prepareStoredEntry(entry);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tentry.setCompressedSize(-1);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Writes an entry. The {@code inputStream} is closed once the entry has been written\n\t * @param entryName the name of the entry\n\t * @param inputStream the stream from which the entry's data can be read\n\t * @throws IOException if the write fails\n\t */\n\t@Override\n\tpublic void writeEntry(String entryName, InputStream inputStream) throws IOException {\n\t\ttry (inputStream) {\n\t\t\twriteEntry(entryName, new InputStreamEntryWriter(inputStream));\n\t\t}\n\t}\n\n\t/**\n\t * Writes an entry. The {@code inputStream} is closed once the entry has been written\n\t * @param entryName the name of the entry\n\t * @param entryWriter the entry writer\n\t * @throws IOException if the write fails\n\t */\n\tpublic void writeEntry(String entryName, EntryWriter entryWriter) throws IOException {\n\t\tJarArchiveEntry entry = new JarArchiveEntry(entryName);\n\t\twriteEntry(entry, entryWriter);\n\t}\n\n\t/**\n\t * Write a nested library.\n\t * @param location the destination of the library\n\t * @param library the library\n\t * @throws IOException if the write fails\n\t */\n\tpublic void writeNestedLibrary(String location, Library library) throws IOException {\n\t\tJarArchiveEntry entry = new JarArchiveEntry(location + library.getName());\n\t\tentry.setTime(getNestedLibraryTime(library));\n\t\tnew StoredEntryPreparator(library.openStream(), new LibraryUnpackHandler(library).requiresUnpack(location))\n\t\t\t.prepareStoredEntry(entry);\n\t\ttry (InputStream inputStream = library.openStream()) {\n\t\t\twriteEntry(entry, library, new InputStreamEntryWriter(inputStream));\n\t\t}\n\t}\n\n\t/**\n\t * Write a simple index file containing the specified UTF-8 lines.\n\t * @param location the location of the index file\n\t * @param lines the lines to write\n\t * @throws IOException if the write fails\n\t */\n\tpublic void writeIndexFile(@Nullable String location, Collection<String> lines) throws IOException {\n\t\tif (location != null) {\n\t\t\tJarArchiveEntry entry = new JarArchiveEntry(location);\n\t\t\twriteEntry(entry, (outputStream) -> {\n\t\t\t\tBufferedWriter writer = new BufferedWriter(\n\t\t\t\t\t\tnew OutputStreamWriter(outputStream, StandardCharsets.UTF_8));\n\t\t\t\tfor (String line : lines) {\n\t\t\t\t\twriter.write(line);\n\t\t\t\t\twriter.write(\"\\n\");\n\t\t\t\t}\n\t\t\t\twriter.flush();\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate long getNestedLibraryTime(Library library) {\n\t\ttry {\n\t\t\ttry (JarInputStream jarStream = new JarInputStream(library.openStream())) {\n\t\t\t\tJarEntry entry = jarStream.getNextJarEntry();\n\t\t\t\twhile (entry != null) {\n\t\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\t\treturn entry.getTime();\n\t\t\t\t\t}\n\t\t\t\t\tentry = jarStream.getNextJarEntry();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore and just use the library timestamp\n\t\t}\n\t\treturn library.getLastModified();\n\t}\n\n\t@Override\n\tpublic void writeLoaderClasses() throws IOException {\n\t\twriteLoaderClasses(\"META-INF/loader/spring-boot-loader.jar\");\n\t}\n\n\t/**\n\t * Write the required spring-boot-loader classes to the JAR.\n\t * @param loaderJarResourceName the name of the resource containing the loader classes\n\t * to be written\n\t * @throws IOException if the classes cannot be written\n\t */\n\t@Override\n\tpublic void writeLoaderClasses(String loaderJarResourceName) throws IOException {\n\t\tURL loaderJar = getClass().getClassLoader().getResource(loaderJarResourceName);\n\t\tAssert.state(loaderJar != null, \"Unable to load resource '%s'\".formatted(loaderJarResourceName));\n\t\ttry (JarInputStream inputStream = new JarInputStream(new BufferedInputStream(loaderJar.openStream()))) {\n\t\t\tJarEntry entry;\n\t\t\twhile ((entry = inputStream.getNextJarEntry()) != null) {\n\t\t\t\tif (isDirectoryEntry(entry) || isClassEntry(entry) || isServicesEntry(entry)) {\n\t\t\t\t\twriteEntry(new JarArchiveEntry(entry), new InputStreamEntryWriter(inputStream));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isDirectoryEntry(JarEntry entry) {\n\t\treturn entry.isDirectory() && !entry.getName().equals(\"META-INF/\");\n\t}\n\n\tprivate boolean isClassEntry(JarEntry entry) {\n\t\treturn entry.getName().endsWith(\".class\");\n\t}\n\n\tprivate boolean isServicesEntry(JarEntry entry) {\n\t\treturn !entry.isDirectory() && entry.getName().startsWith(\"META-INF/services/\");\n\t}\n\n\tprivate void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws IOException {\n\t\twriteEntry(entry, null, entryWriter);\n\t}\n\n\t/**\n\t * Perform the actual write of a {@link JarEntry}. All other write methods delegate to\n\t * this one.\n\t * @param entry the entry to write\n\t * @param library the library for the entry or {@code null}\n\t * @param entryWriter the entry writer or {@code null} if there is no content\n\t * @throws IOException in case of I/O errors\n\t */\n\tprivate void writeEntry(JarArchiveEntry entry, @Nullable Library library, @Nullable EntryWriter entryWriter)\n\t\t\tthrows IOException {\n\t\tString name = entry.getName();\n\t\tif (this.writtenEntries.add(name)) {\n\t\t\twriteParentDirectoryEntries(name);\n\t\t\tentry.setUnixMode(name.endsWith(\"/\") ? UNIX_DIR_MODE : UNIX_FILE_MODE);\n\t\t\tentry.getGeneralPurposeBit().useUTF8ForNames(true);\n\t\t\tif (!entry.isDirectory() && entry.getSize() == -1) {\n\t\t\t\tentryWriter = SizeCalculatingEntryWriter.get(entryWriter);\n\t\t\t\tAssert.state(entryWriter != null, \"'entryWriter' must not be null\");\n\t\t\t\tentry.setSize(entryWriter.size());\n\t\t\t}\n\t\t\tupdateLayerIndex(entry, library);\n\t\t\twriteToArchive(entry, entryWriter);\n\t\t}\n\t}\n\n\tprivate void updateLayerIndex(JarArchiveEntry entry, @Nullable Library library) {\n\t\tif (this.layers != null && this.layersIndex != null && !entry.getName().endsWith(\"/\")) {\n\t\t\tLayer layer = (library != null) ? this.layers.getLayer(library) : this.layers.getLayer(entry.getName());\n\t\t\tthis.layersIndex.add(layer, entry.getName());\n\t\t}\n\t}\n\n\tprotected abstract void writeToArchive(ZipEntry entry, @Nullable EntryWriter entryWriter) throws IOException;\n\n\tprivate void writeParentDirectoryEntries(String name) throws IOException {\n\t\tString parent = name.endsWith(\"/\") ? name.substring(0, name.length() - 1) : name;\n\t\twhile (parent.lastIndexOf('/') != -1) {\n\t\t\tparent = parent.substring(0, parent.lastIndexOf('/'));\n\t\t\tif (!parent.isEmpty()) {\n\t\t\t\twriteEntry(new JarArchiveEntry(parent + \"/\"), null, null);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * {@link EntryWriter} that writes content from an {@link InputStream}.\n\t */\n\tprivate static class InputStreamEntryWriter implements EntryWriter {\n\n\t\tprivate final InputStream inputStream;\n\n\t\tInputStreamEntryWriter(InputStream inputStream) {\n\t\t\tthis.inputStream = inputStream;\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(OutputStream outputStream) throws IOException {\n\t\t\tbyte[] buffer = new byte[BUFFER_SIZE];\n\t\t\tint bytesRead;\n\t\t\twhile ((bytesRead = this.inputStream.read(buffer)) != -1) {\n\t\t\t\toutputStream.write(buffer, 0, bytesRead);\n\t\t\t}\n\t\t\toutputStream.flush();\n\t\t}\n\n\t}\n\n\t/**\n\t * Prepares a {@link ZipEntry#STORED stored} {@link ZipArchiveEntry entry} with CRC\n\t * and size information. Also adds an {@code UNPACK} comment, if needed.\n\t */\n\tprivate static class StoredEntryPreparator {\n\n\t\tprivate static final int BUFFER_SIZE = 32 * 1024;\n\n\t\tprivate final boolean unpack;\n\n\t\tprivate final CRC32 crc = new CRC32();\n\n\t\tprivate long size;\n\n\t\tStoredEntryPreparator(InputStream inputStream, boolean unpack) throws IOException {\n\t\t\tthis.unpack = unpack;\n\t\t\ttry (inputStream) {\n\t\t\t\tload(inputStream);\n\t\t\t}\n\t\t}\n\n\t\tprivate void load(InputStream inputStream) throws IOException {\n\t\t\tbyte[] buffer = new byte[BUFFER_SIZE];\n\t\t\tint bytesRead;\n\t\t\twhile ((bytesRead = inputStream.read(buffer)) != -1) {\n\t\t\t\tthis.crc.update(buffer, 0, bytesRead);\n\t\t\t\tthis.size += bytesRead;\n\t\t\t}\n\t\t}\n\n\t\tvoid prepareStoredEntry(ZipArchiveEntry entry) {\n\t\t\tentry.setSize(this.size);\n\t\t\tentry.setCompressedSize(this.size);\n\t\t\tentry.setCrc(this.crc.getValue());\n\t\t\tentry.setMethod(ZipEntry.STORED);\n\t\t\tif (this.unpack) {\n\t\t\t\tentry.setComment(\"UNPACK\");\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * An {@code EntryTransformer} enables the transformation of {@link JarEntry jar\n\t * entries} during the writing process.\n\t */\n\t@FunctionalInterface\n\tinterface EntryTransformer {\n\n\t\t/**\n\t\t * No-op entity transformer.\n\t\t */\n\t\tEntryTransformer NONE = (jarEntry) -> jarEntry;\n\n\t\t@Nullable JarArchiveEntry transform(JarArchiveEntry jarEntry);\n\n\t}\n\n\t/**\n\t * An {@code UnpackHandler} determines whether unpacking is required and provides a\n\t * SHA-1 hash if required.\n\t */\n\tinterface UnpackHandler {\n\n\t\tUnpackHandler NEVER = (name) -> false;\n\n\t\tboolean requiresUnpack(String name);\n\n\t}\n\n\t/**\n\t * {@link UnpackHandler} backed by a {@link Library}.\n\t */\n\tprivate static final class LibraryUnpackHandler implements UnpackHandler {\n\n\t\tprivate final Library library;\n\n\t\tprivate LibraryUnpackHandler(Library library) {\n\t\t\tthis.library = library;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean requiresUnpack(String name) {\n\t\t\treturn this.library.isUnpackRequired();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/BuildPropertiesWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.CollectionFactory;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@code BuildPropertiesWriter} writes the {@code build-info.properties} for\n * consumption by the Actuator.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 1.0.0\n */\npublic final class BuildPropertiesWriter {\n\n\tprivate final File outputFile;\n\n\t/**\n\t * Creates a new {@code BuildPropertiesWriter} that will write to the given\n\t * {@code outputFile}.\n\t * @param outputFile the output file\n\t */\n\tpublic BuildPropertiesWriter(File outputFile) {\n\t\tthis.outputFile = outputFile;\n\t}\n\n\tpublic void writeBuildProperties(ProjectDetails projectDetails) throws IOException {\n\t\tProperties properties = createBuildInfo(projectDetails);\n\t\tcreateFileIfNecessary(this.outputFile);\n\t\ttry (FileOutputStream outputStream = new FileOutputStream(this.outputFile)) {\n\t\t\tproperties.store(outputStream, \"Properties\");\n\t\t}\n\t}\n\n\tprivate void createFileIfNecessary(File file) throws IOException {\n\t\tif (file.exists()) {\n\t\t\treturn;\n\t\t}\n\t\tFile parent = file.getParentFile();\n\t\tif (!parent.isDirectory() && !parent.mkdirs()) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Cannot create parent directory for '\" + this.outputFile.getAbsolutePath() + \"'\");\n\t\t}\n\t\tif (!file.createNewFile()) {\n\t\t\tthrow new IllegalStateException(\"Cannot create target file '\" + this.outputFile.getAbsolutePath() + \"'\");\n\t\t}\n\t}\n\n\tprivate Properties createBuildInfo(ProjectDetails project) {\n\t\tProperties properties = CollectionFactory.createSortedProperties(true);\n\t\taddIfHasValue(properties, \"build.group\", project.getGroup());\n\t\taddIfHasValue(properties, \"build.artifact\", project.getArtifact());\n\t\taddIfHasValue(properties, \"build.name\", project.getName());\n\t\taddIfHasValue(properties, \"build.version\", project.getVersion());\n\t\tif (project.getTime() != null) {\n\t\t\tproperties.put(\"build.time\", DateTimeFormatter.ISO_INSTANT.format(project.getTime()));\n\t\t}\n\t\tif (project.getAdditionalProperties() != null) {\n\t\t\tproject.getAdditionalProperties().forEach((name, value) -> properties.put(\"build.\" + name, value));\n\t\t}\n\t\treturn properties;\n\t}\n\n\tprivate void addIfHasValue(Properties properties, String name, @Nullable String value) {\n\t\tif (StringUtils.hasText(value)) {\n\t\t\tproperties.put(name, value);\n\t\t}\n\t}\n\n\t/**\n\t * Build-system agnostic details of a project.\n\t */\n\tpublic static final class ProjectDetails {\n\n\t\tprivate final @Nullable String group;\n\n\t\tprivate final @Nullable String artifact;\n\n\t\tprivate final @Nullable String name;\n\n\t\tprivate final @Nullable String version;\n\n\t\tprivate final @Nullable Instant time;\n\n\t\tprivate final @Nullable Map<String, String> additionalProperties;\n\n\t\tpublic ProjectDetails(@Nullable String group, @Nullable String artifact, @Nullable String version,\n\t\t\t\t@Nullable String name, @Nullable Instant time, @Nullable Map<String, String> additionalProperties) {\n\t\t\tthis.group = group;\n\t\t\tthis.artifact = artifact;\n\t\t\tthis.name = name;\n\t\t\tthis.version = version;\n\t\t\tthis.time = time;\n\t\t\tvalidateAdditionalProperties(additionalProperties);\n\t\t\tthis.additionalProperties = additionalProperties;\n\t\t}\n\n\t\tprivate static void validateAdditionalProperties(@Nullable Map<String, String> additionalProperties) {\n\t\t\tif (additionalProperties != null) {\n\t\t\t\tadditionalProperties.forEach((name, value) -> {\n\t\t\t\t\tif (value == null) {\n\t\t\t\t\t\tthrow new NullAdditionalPropertyValueException(name);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tpublic @Nullable String getGroup() {\n\t\t\treturn this.group;\n\t\t}\n\n\t\tpublic @Nullable String getArtifact() {\n\t\t\treturn this.artifact;\n\t\t}\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic @Nullable String getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\tpublic @Nullable Instant getTime() {\n\t\t\treturn this.time;\n\t\t}\n\n\t\tpublic @Nullable Map<String, String> getAdditionalProperties() {\n\t\t\treturn this.additionalProperties;\n\t\t}\n\n\t}\n\n\t/**\n\t * Exception thrown when an additional property with a null value is encountered.\n\t */\n\tpublic static class NullAdditionalPropertyValueException extends IllegalArgumentException {\n\n\t\tpublic NullAdditionalPropertyValueException(String name) {\n\t\t\tsuper(\"Additional property '\" + name + \"' is illegal as its value is null\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/CustomLoaderLayout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.IOException;\n\n/**\n * Additional interface that can be implemented by {@link Layout Layouts} that write their\n * own loader classes.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\n@FunctionalInterface\npublic interface CustomLoaderLayout {\n\n\t/**\n\t * Write the required loader classes into the JAR.\n\t * @param writer the writer used to write the classes\n\t * @throws IOException if the classes cannot be written\n\t */\n\tvoid writeLoadedClasses(LoaderClassesWriter writer) throws IOException;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLayoutFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\n\n/**\n * Default implementation of {@link LayoutFactory}.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic class DefaultLayoutFactory implements LayoutFactory {\n\n\t@Override\n\tpublic Layout getLayout(File source) {\n\t\treturn Layouts.forFile(source);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultLibraryCoordinates.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Encapsulates information about the artifact coordinates of a library.\n *\n * @author Scott Frederick\n */\nclass DefaultLibraryCoordinates implements LibraryCoordinates {\n\n\tprivate final @Nullable String groupId;\n\n\tprivate final @Nullable String artifactId;\n\n\tprivate final @Nullable String version;\n\n\t/**\n\t * Create a new instance from discrete elements.\n\t * @param groupId the group ID\n\t * @param artifactId the artifact ID\n\t * @param version the version\n\t */\n\tDefaultLibraryCoordinates(@Nullable String groupId, @Nullable String artifactId, @Nullable String version) {\n\t\tthis.groupId = groupId;\n\t\tthis.artifactId = artifactId;\n\t\tthis.version = version;\n\t}\n\n\t/**\n\t * Return the group ID of the coordinates.\n\t * @return the group ID\n\t */\n\t@Override\n\tpublic @Nullable String getGroupId() {\n\t\treturn this.groupId;\n\t}\n\n\t/**\n\t * Return the artifact ID of the coordinates.\n\t * @return the artifact ID\n\t */\n\t@Override\n\tpublic @Nullable String getArtifactId() {\n\t\treturn this.artifactId;\n\t}\n\n\t/**\n\t * Return the version of the coordinates.\n\t * @return the version\n\t */\n\t@Override\n\tpublic @Nullable String getVersion() {\n\t\treturn this.version;\n\t}\n\n\t/**\n\t * Return the coordinates in the form {@code groupId:artifactId:version}.\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn LibraryCoordinates.toStandardNotationString(this);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/DefaultTimeZoneOffset.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.nio.file.attribute.FileTime;\nimport java.util.TimeZone;\nimport java.util.zip.ZipEntry;\n\n/**\n * Utility class that can be used to change a UTC time based on the\n * {@link java.util.TimeZone#getDefault() default TimeZone}. This is required because\n * {@link ZipEntry#setTime(long)} expects times in the default timezone and not UTC.\n *\n * @author Phillip Webb\n */\nclass DefaultTimeZoneOffset {\n\n\tstatic final DefaultTimeZoneOffset INSTANCE = new DefaultTimeZoneOffset(TimeZone.getDefault());\n\n\tprivate final TimeZone defaultTimeZone;\n\n\tDefaultTimeZoneOffset(TimeZone defaultTimeZone) {\n\t\tthis.defaultTimeZone = defaultTimeZone;\n\t}\n\n\t/**\n\t * Remove the default offset from the given time.\n\t * @param time the time to remove the default offset from\n\t * @return the time with the default offset removed\n\t */\n\tFileTime removeFrom(FileTime time) {\n\t\treturn FileTime.fromMillis(removeFrom(time.toMillis()));\n\t}\n\n\t/**\n\t * Remove the default offset from the given time.\n\t * @param time the time to remove the default offset from\n\t * @return the time with the default offset removed\n\t */\n\tlong removeFrom(long time) {\n\t\treturn time - this.defaultTimeZone.getOffset(time);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/EntryWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Interface used to write jar entry data.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface EntryWriter {\n\n\t/**\n\t * Write entry data to the specified output stream.\n\t * @param outputStream the destination for the data\n\t * @throws IOException in case of I/O errors\n\t */\n\tvoid write(OutputStream outputStream) throws IOException;\n\n\t/**\n\t * Return the size of the content that will be written, or {@code -1} if the size is\n\t * not known.\n\t * @return the size of the content\n\t */\n\tdefault int size() {\n\t\treturn -1;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/FileUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Locale;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Utilities for manipulating files and directories in Spring Boot tooling.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic abstract class FileUtils {\n\n\t/**\n\t * Utility to remove duplicate files from an \"output\" directory if they already exist\n\t * in an \"origin\". Recursively scans the origin directory looking for files (not\n\t * directories) that exist in both places and deleting the copy.\n\t * @param outputDirectory the output directory\n\t * @param originDirectory the origin directory\n\t */\n\tpublic static void removeDuplicatesFromOutputDirectory(File outputDirectory, File originDirectory) {\n\t\tif (originDirectory.isDirectory()) {\n\t\t\tString[] files = originDirectory.list();\n\t\t\tAssert.state(files != null, \"'files' must not be null\");\n\t\t\tfor (String name : files) {\n\t\t\t\tFile targetFile = new File(outputDirectory, name);\n\t\t\t\tif (targetFile.exists() && targetFile.canWrite()) {\n\t\t\t\t\tif (!targetFile.isDirectory()) {\n\t\t\t\t\t\ttargetFile.delete();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tFileUtils.removeDuplicatesFromOutputDirectory(targetFile, new File(originDirectory, name));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns {@code true} if the given jar file has been signed.\n\t * @param file the file to check\n\t * @return if the file has been signed\n\t * @throws IOException on IO error\n\t */\n\tpublic static boolean isSignedJarFile(@Nullable File file) throws IOException {\n\t\tif (file == null) {\n\t\t\treturn false;\n\t\t}\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\tif (hasDigestEntry(jarFile.getManifest())) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static boolean hasDigestEntry(@Nullable Manifest manifest) {\n\t\treturn (manifest != null) && manifest.getEntries().values().stream().anyMatch(FileUtils::hasDigestName);\n\t}\n\n\tprivate static boolean hasDigestName(Attributes attributes) {\n\t\treturn attributes.keySet().stream().anyMatch(FileUtils::isDigestName);\n\t}\n\n\tprivate static boolean isDigestName(Object name) {\n\t\treturn String.valueOf(name).toUpperCase(Locale.ROOT).endsWith(\"-DIGEST\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ImagePackager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.function.BiConsumer;\nimport java.util.jar.JarFile;\nimport java.util.zip.ZipEntry;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Utility class that can be used to export a fully packaged archive to an OCI image.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic class ImagePackager extends Packager {\n\n\t/**\n\t * Create a new {@link ImagePackager} instance.\n\t * @param source the source file to package\n\t * @param backupFile the backup of the source file to package\n\t */\n\tpublic ImagePackager(File source, @Nullable File backupFile) {\n\t\tsuper(source);\n\t\tsetBackupFile(backupFile);\n\t\tif (isAlreadyPackaged()) {\n\t\t\tAssert.isTrue(getBackupFile().exists() && getBackupFile().isFile(),\n\t\t\t\t\t\"Original source '\" + getBackupFile() + \"' is required for building an image\");\n\t\t\tAssert.state(!isAlreadyPackaged(getBackupFile()),\n\t\t\t\t\t() -> \"Repackaged archive file \" + source + \" cannot be used to build an image\");\n\t\t}\n\t}\n\n\t/**\n\t * Create a packaged image.\n\t * @param libraries the contained libraries\n\t * @param exporter the exporter used to write the image\n\t * @throws IOException on IO error\n\t */\n\tpublic void packageImage(Libraries libraries, BiConsumer<ZipEntry, @Nullable EntryWriter> exporter)\n\t\t\tthrows IOException {\n\t\tpackageImage(libraries, new DelegatingJarWriter(exporter));\n\t}\n\n\tprivate void packageImage(Libraries libraries, AbstractJarWriter writer) throws IOException {\n\t\tFile source = isAlreadyPackaged() ? getBackupFile() : getSource();\n\t\ttry (JarFile sourceJar = new JarFile(source)) {\n\t\t\twrite(sourceJar, libraries, writer);\n\t\t}\n\t}\n\n\t/**\n\t * {@link AbstractJarWriter} that delegates to a {@link BiConsumer}.\n\t */\n\tprivate static class DelegatingJarWriter extends AbstractJarWriter {\n\n\t\tprivate final BiConsumer<ZipEntry, @Nullable EntryWriter> exporter;\n\n\t\tDelegatingJarWriter(BiConsumer<ZipEntry, @Nullable EntryWriter> exporter) {\n\t\t\tthis.exporter = exporter;\n\t\t}\n\n\t\t@Override\n\t\tprotected void writeToArchive(ZipEntry entry, @Nullable EntryWriter entryWriter) throws IOException {\n\t\t\tthis.exporter.accept(entry, entryWriter);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ImplicitLayerResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\n/**\n * Implementation of {@link Layers} that uses implicit rules.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ImplicitLayerResolver extends StandardLayers {\n\n\tprivate static final String SPRING_BOOT_LOADER_PREFIX = \"org/springframework/boot/loader/\";\n\n\t@Override\n\tpublic Layer getLayer(String name) {\n\t\tif (name.startsWith(SPRING_BOOT_LOADER_PREFIX)) {\n\t\t\treturn SPRING_BOOT_LOADER;\n\t\t}\n\t\treturn APPLICATION;\n\t}\n\n\t@Override\n\tpublic Layer getLayer(Library library) {\n\t\tif (library.isLocal()) {\n\t\t\treturn APPLICATION;\n\t\t}\n\t\tif (library.getName().contains(\"SNAPSHOT.\")) {\n\t\t\treturn SNAPSHOT_DEPENDENCIES;\n\t\t}\n\t\treturn DEPENDENCIES;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/InputStreamSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Supplier to provide an {@link InputStream}.\n *\n * @author Phillip Webb\n */\n@FunctionalInterface\ninterface InputStreamSupplier {\n\n\t/**\n\t * Returns a new open {@link InputStream} at the beginning of the content.\n\t * @return a new {@link InputStream}\n\t * @throws IOException on IO error\n\t */\n\tInputStream openStream() throws IOException;\n\n\t/**\n\t * Factory method to create an {@link InputStreamSupplier} for the given {@link File}.\n\t * @param file the source file\n\t * @return a new {@link InputStreamSupplier} instance\n\t */\n\tstatic InputStreamSupplier forFile(File file) {\n\t\treturn () -> new FileInputStream(file);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarModeLibrary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Library} implementation for internal jarmode jars.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class JarModeLibrary extends Library {\n\n\t/**\n\t * {@link JarModeLibrary} for layer tools.\n\t */\n\tpublic static final JarModeLibrary TOOLS = new JarModeLibrary(\"spring-boot-jarmode-tools\");\n\n\tJarModeLibrary(String artifactId) {\n\t\tthis(createCoordinates(artifactId));\n\t}\n\n\tpublic JarModeLibrary(LibraryCoordinates coordinates) {\n\t\tsuper(getJarName(coordinates), null, LibraryScope.RUNTIME, coordinates, false, false, true);\n\t}\n\n\tprivate static LibraryCoordinates createCoordinates(String artifactId) {\n\t\tString version = JarModeLibrary.class.getPackage().getImplementationVersion();\n\t\treturn LibraryCoordinates.of(\"org.springframework.boot\", artifactId, version);\n\t}\n\n\tprivate static String getJarName(LibraryCoordinates coordinates) {\n\t\tString version = coordinates.getVersion();\n\t\tStringBuilder jarName = new StringBuilder(coordinates.getArtifactId());\n\t\tif (StringUtils.hasText(version)) {\n\t\t\tjarName.append('-');\n\t\t\tjarName.append(version);\n\t\t}\n\t\tjarName.append(\".jar\");\n\t\treturn jarName.toString();\n\t}\n\n\t@Override\n\tpublic InputStream openStream() throws IOException {\n\t\tLibraryCoordinates coordinates = getCoordinates();\n\t\tAssert.state(coordinates != null, \"'coordinates' must not be null\");\n\t\tString path = \"META-INF/jarmode/\" + coordinates.getArtifactId() + \".jar\";\n\t\tURL resource = getClass().getClassLoader().getResource(path);\n\t\tAssert.state(resource != null, () -> \"Unable to find resource \" + path);\n\t\treturn resource.openStream();\n\t}\n\n\t@Override\n\tlong getLastModified() {\n\t\treturn 0L;\n\t}\n\n\t@Override\n\tpublic File getFile() {\n\t\tthrow new UnsupportedOperationException(\"Unable to access jar mode library file\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.file.attribute.FileTime;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipException;\n\nimport org.apache.commons.compress.archivers.jar.JarArchiveEntry;\nimport org.apache.commons.compress.archivers.jar.JarArchiveOutputStream;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Writes JAR content, ensuring valid directory entries are always created and duplicate\n * items are ignored.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 1.0.0\n */\npublic class JarWriter extends AbstractJarWriter implements AutoCloseable {\n\n\tprivate final JarArchiveOutputStream jarOutputStream;\n\n\tprivate final @Nullable FileTime lastModifiedTime;\n\n\t/**\n\t * Create a new {@link JarWriter} instance.\n\t * @param file the file to write\n\t * @throws IOException if the file cannot be opened\n\t * @throws FileNotFoundException if the file cannot be found\n\t */\n\tpublic JarWriter(File file) throws FileNotFoundException, IOException {\n\t\tthis(file, null);\n\t}\n\n\t/**\n\t * Create a new {@link JarWriter} instance.\n\t * @param file the file to write\n\t * @param lastModifiedTime an optional last modified time to apply to the written\n\t * entries\n\t * @throws IOException if the file cannot be opened\n\t * @throws FileNotFoundException if the file cannot be found\n\t * @since 4.0.0\n\t */\n\tpublic JarWriter(File file, @Nullable FileTime lastModifiedTime) throws FileNotFoundException, IOException {\n\t\tthis.jarOutputStream = new JarArchiveOutputStream(new FileOutputStream(file));\n\t\tthis.jarOutputStream.setEncoding(\"UTF-8\");\n\t\tthis.lastModifiedTime = lastModifiedTime;\n\t}\n\n\t@Override\n\tprotected void writeToArchive(ZipEntry entry, @Nullable EntryWriter entryWriter) throws IOException {\n\t\tJarArchiveEntry jarEntry = asJarArchiveEntry(entry);\n\t\tif (this.lastModifiedTime != null) {\n\t\t\tjarEntry.setTime(DefaultTimeZoneOffset.INSTANCE.removeFrom(this.lastModifiedTime).toMillis());\n\t\t}\n\t\tthis.jarOutputStream.putArchiveEntry(jarEntry);\n\t\tif (entryWriter != null) {\n\t\t\tentryWriter.write(this.jarOutputStream);\n\t\t}\n\t\tthis.jarOutputStream.closeArchiveEntry();\n\t}\n\n\tprivate JarArchiveEntry asJarArchiveEntry(ZipEntry entry) throws ZipException {\n\t\tif (entry instanceof JarArchiveEntry jarArchiveEntry) {\n\t\t\treturn jarArchiveEntry;\n\t\t}\n\t\treturn new JarArchiveEntry(entry);\n\t}\n\n\t/**\n\t * Close the writer.\n\t * @throws IOException if the file cannot be closed\n\t */\n\t@Override\n\tpublic void close() throws IOException {\n\t\tthis.jarOutputStream.close();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JavaExecutable.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provides access to the java binary executable, regardless of OS.\n *\n * @author Phillip Webb\n * @since 1.1.0\n */\npublic class JavaExecutable {\n\n\tprivate final File file;\n\n\tpublic JavaExecutable() {\n\t\tString javaHome = System.getProperty(\"java.home\");\n\t\tAssert.state(StringUtils.hasLength(javaHome), \"Unable to find java executable due to missing 'java.home'\");\n\t\tthis.file = findInJavaHome(javaHome);\n\t}\n\n\tprivate File findInJavaHome(String javaHome) {\n\t\tFile bin = new File(new File(javaHome), \"bin\");\n\t\tFile command = new File(bin, \"java.exe\");\n\t\tcommand = command.exists() ? command : new File(bin, \"java\");\n\t\tAssert.state(command.exists(), () -> \"Unable to find java in \" + javaHome);\n\t\treturn command;\n\t}\n\n\t/**\n\t * Create a new {@link ProcessBuilder} that will run with the Java executable.\n\t * @param arguments the command arguments\n\t * @return a {@link ProcessBuilder}\n\t */\n\tpublic ProcessBuilder processBuilder(String... arguments) {\n\t\tProcessBuilder processBuilder = new ProcessBuilder(toString());\n\t\tprocessBuilder.command().addAll(Arrays.asList(arguments));\n\t\treturn processBuilder;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\ttry {\n\t\t\treturn this.file.getCanonicalPath();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.util.Locale;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A named layer used to separate the jar when creating a Docker image.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n * @see Layers\n */\npublic class Layer {\n\n\tprivate static final Pattern PATTERN = Pattern.compile(\"^[a-zA-Z0-9-]+$\");\n\n\tprivate final String name;\n\n\t/**\n\t * Create a new {@link Layer} instance with the specified name.\n\t * @param name the name of the layer.\n\t */\n\tpublic Layer(String name) {\n\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\tAssert.isTrue(PATTERN.matcher(name).matches(), () -> \"Malformed layer name '\" + name + \"'\");\n\t\tAssert.isTrue(!name.equalsIgnoreCase(\"ext\") && !name.toLowerCase(Locale.ROOT).startsWith(\"springboot\"),\n\t\t\t\t() -> \"Layer name '\" + name + \"' is reserved\");\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.name.equals(((Layer) obj).name);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.name.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.util.Iterator;\nimport java.util.stream.Stream;\n\n/**\n * Interface to provide information about layers to the {@link Repackager}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n * @see Layer\n */\npublic interface Layers extends Iterable<Layer> {\n\n\t/**\n\t * The default layer resolver.\n\t */\n\tLayers IMPLICIT = new ImplicitLayerResolver();\n\n\t/**\n\t * Return the jar layers in the order that they should be added (starting with the\n\t * least frequently changed layer).\n\t * @return the layers iterator\n\t */\n\t@Override\n\tIterator<Layer> iterator();\n\n\t/**\n\t * Return a stream of the jar layers in the order that they should be added (starting\n\t * with the least frequently changed layer).\n\t * @return the layers stream\n\t */\n\tStream<Layer> stream();\n\n\t/**\n\t * Return the layer that contains the given resource name.\n\t * @param applicationResource the name of an application resource (for example a\n\t * {@code .class} file).\n\t * @return the layer that contains the resource (must never be {@code null})\n\t */\n\tLayer getLayer(String applicationResource);\n\n\t/**\n\t * Return the layer that contains the given library.\n\t * @param library the library to consider\n\t * @return the layer that contains the resource (must never be {@code null})\n\t */\n\tLayer getLayer(Library library);\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayersIndex.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * Index describing the layer to which each entry in a jar belongs. Index files are simple\n * text files that should be read from top to bottom. Each file defines the layers and\n * their content. Layer names are written as quoted strings prefixed by a dash space\n * ({@code \"- \"}) and with a colon ({@code \":\"}) suffix. Layer content is either a file or\n * directory name written as a quoted string prefixed by space space dash space\n * ({@code \"  - \"}). A directory name ends with {@code /}, a file name does not. When a\n * directory name is used it means that all files inside that directory are in the same\n * layer.\n * <p>\n * Index files are designed to be compatible with YAML and may be read into a list of\n * {@code Map<String, List<String>>} instances.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class LayersIndex {\n\n\tprivate final Iterable<Layer> layers;\n\n\tprivate final Node root = new Node();\n\n\t/**\n\t * Create a new {@link LayersIndex} backed by the given layers.\n\t * @param layers the layers in the index\n\t */\n\tpublic LayersIndex(Layer... layers) {\n\t\tthis(Arrays.asList(layers));\n\t}\n\n\t/**\n\t * Create a new {@link LayersIndex} backed by the given layers.\n\t * @param layers the layers in the index\n\t */\n\tpublic LayersIndex(Iterable<Layer> layers) {\n\t\tthis.layers = layers;\n\t}\n\n\t/**\n\t * Add an item to the index.\n\t * @param layer the layer of the item\n\t * @param name the name of the item\n\t */\n\tpublic void add(Layer layer, String name) {\n\t\tString[] segments = name.split(\"/\");\n\t\tNode node = this.root;\n\t\tfor (int i = 0; i < segments.length; i++) {\n\t\t\tboolean isDirectory = i < (segments.length - 1);\n\t\t\tnode = node.updateOrAddNode(segments[i], isDirectory, layer);\n\t\t}\n\t}\n\n\t/**\n\t * Write the layer index to an output stream.\n\t * @param out the destination stream\n\t * @throws IOException on IO error\n\t */\n\tpublic void writeTo(OutputStream out) throws IOException {\n\t\tMultiValueMap<Layer, String> index = new LinkedMultiValueMap<>();\n\t\tthis.root.buildIndex(\"\", index);\n\t\tindex.values().forEach(Collections::sort);\n\t\tBufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));\n\t\tfor (Layer layer : this.layers) {\n\t\t\tList<String> names = index.get(layer);\n\t\t\twriter.write(\"- \\\"\" + layer + \"\\\":\\n\");\n\t\t\tif (names != null) {\n\t\t\t\tfor (String name : names) {\n\t\t\t\t\twriter.write(\"  - \\\"\" + name + \"\\\"\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twriter.flush();\n\t}\n\n\t/**\n\t * A node within the index representing a single path segment.\n\t */\n\tprivate static class Node {\n\n\t\tprivate final String name;\n\n\t\tprivate final Set<Layer> layers;\n\n\t\tprivate final List<Node> children = new ArrayList<>();\n\n\t\tNode() {\n\t\t\tthis.name = \"\";\n\t\t\tthis.layers = new HashSet<>();\n\t\t}\n\n\t\tNode(String name, Layer layer) {\n\t\t\tthis.name = name;\n\t\t\tthis.layers = new HashSet<>(Collections.singleton(layer));\n\t\t}\n\n\t\tNode updateOrAddNode(String segment, boolean isDirectory, Layer layer) {\n\t\t\tString name = segment + (isDirectory ? \"/\" : \"\");\n\t\t\tfor (Node child : this.children) {\n\t\t\t\tif (name.equals(child.name)) {\n\t\t\t\t\tchild.layers.add(layer);\n\t\t\t\t\treturn child;\n\t\t\t\t}\n\t\t\t}\n\t\t\tNode child = new Node(name, layer);\n\t\t\tthis.children.add(child);\n\t\t\treturn child;\n\t\t}\n\n\t\tvoid buildIndex(String path, MultiValueMap<Layer, String> index) {\n\t\t\tString name = path + this.name;\n\t\t\tif (this.layers.size() == 1) {\n\t\t\t\tindex.add(this.layers.iterator().next(), name);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (Node child : this.children) {\n\t\t\t\t\tchild.buildIndex(name, index);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Strategy interface used to determine the layout for a particular type of archive.\n * Layouts may additionally implement {@link CustomLoaderLayout} if they wish to write\n * custom loader classes.\n *\n * @author Phillip Webb\n * @since 1.0.0\n * @see Layouts\n * @see RepackagingLayout\n * @see CustomLoaderLayout\n */\npublic interface Layout {\n\n\t/**\n\t * Returns the launcher class name for this layout.\n\t * @return the launcher class name\n\t */\n\t@Nullable String getLauncherClassName();\n\n\t/**\n\t * Returns the destination path for a given library.\n\t * @param libraryName the name of the library (excluding any path)\n\t * @param scope the scope of the library\n\t * @return the location of the library relative to the root of the archive (should end\n\t * with '/') or {@code null} if the library should not be included.\n\t */\n\t@Nullable String getLibraryLocation(String libraryName, @Nullable LibraryScope scope);\n\n\t/**\n\t * Returns the location of classes within the archive.\n\t * @return the classes location\n\t */\n\tString getClassesLocation();\n\n\t/**\n\t * Returns the location of the classpath index file that should be written or\n\t * {@code null} if not index is required. The result should include the filename and\n\t * is relative to the root of the jar.\n\t * @return the classpath index file location\n\t * @since 2.5.0\n\t */\n\tdefault @Nullable String getClasspathIndexFileLocation() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the location of the layer index file that should be written or {@code null}\n\t * if not index is required. The result should include the filename and is relative to\n\t * the root of the jar.\n\t * @return the layer index file location\n\t * @since 2.5.0\n\t */\n\tdefault @Nullable String getLayersIndexFileLocation() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns if loader classes should be included to make the archive executable.\n\t * @return if the layout is executable\n\t */\n\tboolean isExecutable();\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\n\n/**\n * Factory interface used to create a {@link Layout}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 1.0.0\n */\n@FunctionalInterface\npublic interface LayoutFactory {\n\n\t/**\n\t * Return a {@link Layout} for the specified source file.\n\t * @param source the source file\n\t * @return the layout to use for the file\n\t */\n\tLayout getLayout(File source);\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Common {@link Layout layouts}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 1.0.0\n */\npublic final class Layouts {\n\n\tprivate Layouts() {\n\t}\n\n\t/**\n\t * Return a layout for the given source file.\n\t * @param file the source file\n\t * @return a {@link Layout}\n\t */\n\tpublic static Layout forFile(File file) {\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tString lowerCaseFileName = file.getName().toLowerCase(Locale.ENGLISH);\n\t\tif (lowerCaseFileName.endsWith(\".jar\")) {\n\t\t\treturn new Jar();\n\t\t}\n\t\tif (lowerCaseFileName.endsWith(\".war\")) {\n\t\t\treturn new War();\n\t\t}\n\t\tif (file.isDirectory() || lowerCaseFileName.endsWith(\".zip\")) {\n\t\t\treturn new Expanded();\n\t\t}\n\t\tthrow new IllegalStateException(\"Unable to deduce layout for '\" + file + \"'\");\n\t}\n\n\t/**\n\t * Executable JAR layout.\n\t */\n\tpublic static class Jar implements RepackagingLayout {\n\n\t\t@Override\n\t\tpublic @Nullable String getLauncherClassName() {\n\t\t\treturn \"org.springframework.boot.loader.launch.JarLauncher\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLibraryLocation(String libraryName, @Nullable LibraryScope scope) {\n\t\t\treturn \"BOOT-INF/lib/\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getClassesLocation() {\n\t\t\treturn \"\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getRepackagedClassesLocation() {\n\t\t\treturn \"BOOT-INF/classes/\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getClasspathIndexFileLocation() {\n\t\t\treturn \"BOOT-INF/classpath.idx\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLayersIndexFileLocation() {\n\t\t\treturn \"BOOT-INF/layers.idx\";\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isExecutable() {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n\t/**\n\t * Executable expanded archive layout.\n\t */\n\tpublic static class Expanded extends Jar {\n\n\t\t@Override\n\t\tpublic String getLauncherClassName() {\n\t\t\treturn \"org.springframework.boot.loader.launch.PropertiesLauncher\";\n\t\t}\n\n\t}\n\n\t/**\n\t * No layout.\n\t */\n\tpublic static class None extends Jar {\n\n\t\t@Override\n\t\tpublic @Nullable String getLauncherClassName() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isExecutable() {\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t/**\n\t * Executable WAR layout.\n\t */\n\tpublic static class War implements Layout {\n\n\t\tprivate static final Map<LibraryScope, String> SCOPE_LOCATION;\n\n\t\tstatic {\n\t\t\tMap<LibraryScope, String> locations = new HashMap<>();\n\t\t\tlocations.put(LibraryScope.COMPILE, \"WEB-INF/lib/\");\n\t\t\tlocations.put(LibraryScope.CUSTOM, \"WEB-INF/lib/\");\n\t\t\tlocations.put(LibraryScope.RUNTIME, \"WEB-INF/lib/\");\n\t\t\tlocations.put(LibraryScope.PROVIDED, \"WEB-INF/lib-provided/\");\n\t\t\tSCOPE_LOCATION = Collections.unmodifiableMap(locations);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLauncherClassName() {\n\t\t\treturn \"org.springframework.boot.loader.launch.WarLauncher\";\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getLibraryLocation(String libraryName, @Nullable LibraryScope scope) {\n\t\t\treturn SCOPE_LOCATION.get(scope);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getClassesLocation() {\n\t\t\treturn \"WEB-INF/classes/\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getClasspathIndexFileLocation() {\n\t\t\treturn \"WEB-INF/classpath.idx\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLayersIndexFileLocation() {\n\t\t\treturn \"WEB-INF/layers.idx\";\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isExecutable() {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Libraries.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.IOException;\n\n/**\n * Encapsulates information about libraries that may be packed into the archive.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@FunctionalInterface\npublic interface Libraries {\n\n\t/**\n\t * Represents no libraries.\n\t */\n\tLibraries NONE = (callback) -> {\n\t};\n\n\t/**\n\t * Iterate all relevant libraries.\n\t * @param callback a callback for each relevant library.\n\t * @throws IOException if the operation fails\n\t */\n\tvoid doWithLibraries(LibraryCallback callback) throws IOException;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Encapsulates information about a single library that may be packed into the archive.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 1.1.2\n * @see Libraries\n */\npublic class Library {\n\n\tprivate final String name;\n\n\tprivate final @Nullable File file;\n\n\tprivate final @Nullable LibraryScope scope;\n\n\tprivate final @Nullable LibraryCoordinates coordinates;\n\n\tprivate final boolean unpackRequired;\n\n\tprivate final boolean local;\n\n\tprivate final boolean included;\n\n\t/**\n\t * Create a new {@link Library}.\n\t * @param file the source file\n\t * @param scope the scope of the library\n\t */\n\tpublic Library(File file, LibraryScope scope) {\n\t\tthis(null, file, scope, null, false, false, true);\n\t}\n\n\t/**\n\t * Create a new {@link Library}.\n\t * @param name the name of the library as it should be written or {@code null} to use\n\t * the file name\n\t * @param file the source file\n\t * @param scope the scope of the library\n\t * @param coordinates the library coordinates or {@code null}\n\t * @param unpackRequired if the library needs to be unpacked before it can be used\n\t * @param local if the library is local (part of the same build) to the application\n\t * that is being packaged\n\t * @param included if the library is included in the uber jar\n\t * @since 2.4.8\n\t */\n\tpublic Library(@Nullable String name, @Nullable File file, @Nullable LibraryScope scope,\n\t\t\t@Nullable LibraryCoordinates coordinates, boolean unpackRequired, boolean local, boolean included) {\n\t\tthis.name = (name != null) ? name : getFileName(file);\n\t\tthis.file = file;\n\t\tthis.scope = scope;\n\t\tthis.coordinates = coordinates;\n\t\tthis.unpackRequired = unpackRequired;\n\t\tthis.local = local;\n\t\tthis.included = included;\n\t}\n\n\tprivate static String getFileName(@Nullable File file) {\n\t\tAssert.state(file != null, \"'file' must not be null\");\n\t\treturn file.getName();\n\t}\n\n\t/**\n\t * Return the name of file as it should be written.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Return the library file.\n\t * @return the file\n\t */\n\tpublic @Nullable File getFile() {\n\t\treturn this.file;\n\t}\n\n\t/**\n\t * Open a stream that provides the content of the source file.\n\t * @return the file content\n\t * @throws IOException on error\n\t */\n\tInputStream openStream() throws IOException {\n\t\tAssert.state(this.file != null, \"'file' must not be null\");\n\t\treturn new FileInputStream(this.file);\n\t}\n\n\t/**\n\t * Return the scope of the library.\n\t * @return the scope\n\t */\n\tpublic @Nullable LibraryScope getScope() {\n\t\treturn this.scope;\n\t}\n\n\t/**\n\t * Return the {@linkplain LibraryCoordinates coordinates} of the library.\n\t * @return the coordinates\n\t */\n\tpublic @Nullable LibraryCoordinates getCoordinates() {\n\t\treturn this.coordinates;\n\t}\n\n\t/**\n\t * Return if the file cannot be used directly as a nested jar and needs to be\n\t * unpacked.\n\t * @return if unpack is required\n\t */\n\tpublic boolean isUnpackRequired() {\n\t\treturn this.unpackRequired;\n\t}\n\n\tlong getLastModified() {\n\t\tAssert.state(this.file != null, \"'file' must not be null\");\n\t\treturn this.file.lastModified();\n\t}\n\n\t/**\n\t * Return if the library is local (part of the same build) to the application that is\n\t * being packaged.\n\t * @return if the library is local\n\t */\n\tpublic boolean isLocal() {\n\t\treturn this.local;\n\t}\n\n\t/**\n\t * Return if the library is included in the uber jar.\n\t * @return if the library is included\n\t */\n\tpublic boolean isIncluded() {\n\t\treturn this.included;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LibraryCallback.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * Callback interface used to iterate {@link Libraries}.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\n@FunctionalInterface\npublic interface LibraryCallback {\n\n\t/**\n\t * Callback for a single library backed by a {@link File}.\n\t * @param library the library\n\t * @throws IOException if the operation fails\n\t */\n\tvoid library(Library library) throws IOException;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LibraryCoordinates.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Encapsulates information about the artifact coordinates of a library.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic interface LibraryCoordinates {\n\n\t/**\n\t * Return the group ID of the coordinates.\n\t * @return the group ID\n\t */\n\t@Nullable String getGroupId();\n\n\t/**\n\t * Return the artifact ID of the coordinates.\n\t * @return the artifact ID\n\t */\n\t@Nullable String getArtifactId();\n\n\t/**\n\t * Return the version of the coordinates.\n\t * @return the version\n\t */\n\t@Nullable String getVersion();\n\n\t/**\n\t * Factory method to create {@link LibraryCoordinates} with the specified values.\n\t * @param groupId the group ID\n\t * @param artifactId the artifact ID\n\t * @param version the version\n\t * @return a new {@link LibraryCoordinates} instance\n\t */\n\tstatic LibraryCoordinates of(@Nullable String groupId, @Nullable String artifactId, @Nullable String version) {\n\t\treturn new DefaultLibraryCoordinates(groupId, artifactId, version);\n\t}\n\n\t/**\n\t * Utility method that returns the given coordinates using the standard\n\t * {@code group:artifact:version} form.\n\t * @param coordinates the coordinates to convert (may be {@code null})\n\t * @return the standard notation form or {@code \"::\"} when the coordinates are null\n\t */\n\tstatic String toStandardNotationString(@Nullable LibraryCoordinates coordinates) {\n\t\tif (coordinates == null) {\n\t\t\treturn \"::\";\n\t\t}\n\t\tStringBuilder builder = new StringBuilder();\n\t\tbuilder.append((coordinates.getGroupId() != null) ? coordinates.getGroupId() : \"\");\n\t\tbuilder.append(\":\");\n\t\tbuilder.append((coordinates.getArtifactId() != null) ? coordinates.getArtifactId() : \"\");\n\t\tbuilder.append(\":\");\n\t\tbuilder.append((coordinates.getVersion() != null) ? coordinates.getVersion() : \"\");\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LibraryScope.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\n/**\n * The scope of a library. The common {@link #COMPILE}, {@link #RUNTIME} and\n * {@link #PROVIDED} scopes are defined here and supported by the common {@link Layouts}.\n * A custom {@link Layout} can handle additional scopes as required.\n *\n * @author Phillip Webb\n * @since 1.0.0\n */\npublic interface LibraryScope {\n\n\t@Override\n\tString toString();\n\n\t/**\n\t * The library is used at compile time and runtime.\n\t */\n\tLibraryScope COMPILE = new LibraryScope() {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"compile\";\n\t\t}\n\n\t};\n\n\t/**\n\t * The library is used at runtime but not needed for compile.\n\t */\n\tLibraryScope RUNTIME = new LibraryScope() {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"runtime\";\n\t\t}\n\n\t};\n\n\t/**\n\t * The library is needed for compile but is usually provided when running.\n\t */\n\tLibraryScope PROVIDED = new LibraryScope() {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"provided\";\n\t\t}\n\n\t};\n\n\t/**\n\t * Marker for custom scope when custom configuration is used.\n\t */\n\tLibraryScope CUSTOM = new LibraryScope() {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"custom\";\n\t\t}\n\n\t};\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LoaderClassesWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Writer used by {@link CustomLoaderLayout CustomLoaderLayouts} to write classes into a\n * repackaged JAR.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic interface LoaderClassesWriter {\n\n\t/**\n\t * Write the default required spring-boot-loader classes to the JAR.\n\t * @throws IOException if the classes cannot be written\n\t */\n\tvoid writeLoaderClasses() throws IOException;\n\n\t/**\n\t * Write custom required spring-boot-loader classes to the JAR.\n\t * @param loaderJarResourceName the name of the resource containing the loader classes\n\t * to be written\n\t * @throws IOException if the classes cannot be written\n\t */\n\tvoid writeLoaderClasses(String loaderJarResourceName) throws IOException;\n\n\t/**\n\t * Write a single entry to the JAR.\n\t * @param name the name of the entry\n\t * @param inputStream the input stream content\n\t * @throws IOException if the entry cannot be written\n\t */\n\tvoid writeEntry(String name, InputStream inputStream) throws IOException;\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LogbackInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport ch.qos.logback.classic.Level;\nimport org.slf4j.ILoggerFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.util.ClassUtils;\n\n/**\n * Utility to initialize logback (when present) to use INFO level logging.\n *\n * @author Dave Syer\n * @since 1.1.0\n */\npublic abstract class LogbackInitializer {\n\n\tpublic static void initialize() {\n\t\tif (ClassUtils.isPresent(\"org.slf4j.LoggerFactory\", null)\n\t\t\t\t&& ClassUtils.isPresent(\"ch.qos.logback.classic.Logger\", null)) {\n\t\t\tnew Initializer().setRootLogLevel();\n\t\t}\n\t}\n\n\tprivate static final class Initializer {\n\n\t\tvoid setRootLogLevel() {\n\t\t\tILoggerFactory factory = LoggerFactory.getILoggerFactory();\n\t\t\tLogger logger = factory.getLogger(Logger.ROOT_LOGGER_NAME);\n\t\t\t((ch.qos.logback.classic.Logger) logger).setLevel(Level.INFO);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/MainClassFinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Deque;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.asm.AnnotationVisitor;\nimport org.springframework.asm.ClassReader;\nimport org.springframework.asm.ClassVisitor;\nimport org.springframework.asm.MethodVisitor;\nimport org.springframework.asm.Opcodes;\nimport org.springframework.asm.SpringAsmInfo;\nimport org.springframework.asm.Type;\n\n/**\n * Finds any class with a {@code public static main} method by performing a breadth first\n * search.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.0.0\n */\npublic abstract class MainClassFinder {\n\n\tprivate static final String DOT_CLASS = \".class\";\n\n\tprivate static final Type STRING_ARRAY_TYPE = Type.getType(String[].class);\n\n\tprivate static final Type MAIN_METHOD_TYPE = Type.getMethodType(Type.VOID_TYPE, STRING_ARRAY_TYPE);\n\n\tprivate static final Type PARAMETERLESS_MAIN_METHOD_TYPE = Type.getMethodType(Type.VOID_TYPE);\n\n\tprivate static final String MAIN_METHOD_NAME = \"main\";\n\n\tprivate static final FileFilter CLASS_FILE_FILTER = MainClassFinder::isClassFile;\n\n\tprivate static final FileFilter PACKAGE_DIRECTORY_FILTER = MainClassFinder::isPackageDirectory;\n\n\tprivate static boolean isClassFile(File file) {\n\t\treturn file.isFile() && file.getName().endsWith(DOT_CLASS);\n\t}\n\n\tprivate static boolean isPackageDirectory(File file) {\n\t\treturn file.isDirectory() && !file.getName().startsWith(\".\");\n\t}\n\n\t/**\n\t * Find the main class from a given directory.\n\t * @param rootDirectory the root directory to search\n\t * @return the main class or {@code null}\n\t * @throws IOException if the directory cannot be read\n\t */\n\tpublic static @Nullable String findMainClass(File rootDirectory) throws IOException {\n\t\treturn doWithMainClasses(rootDirectory, MainClass::getName);\n\t}\n\n\t/**\n\t * Find a single main class from the given {@code rootDirectory}.\n\t * @param rootDirectory the root directory to search\n\t * @return the main class or {@code null}\n\t * @throws IOException if the directory cannot be read\n\t */\n\tpublic static @Nullable String findSingleMainClass(File rootDirectory) throws IOException {\n\t\treturn findSingleMainClass(rootDirectory, null);\n\t}\n\n\t/**\n\t * Find a single main class from the given {@code rootDirectory}. A main class\n\t * annotated with an annotation with the given {@code annotationName} will be\n\t * preferred over a main class with no such annotation.\n\t * @param rootDirectory the root directory to search\n\t * @param annotationName the name of the annotation that may be present on the main\n\t * class\n\t * @return the main class or {@code null}\n\t * @throws IOException if the directory cannot be read\n\t */\n\tpublic static @Nullable String findSingleMainClass(File rootDirectory, @Nullable String annotationName)\n\t\t\tthrows IOException {\n\t\tSingleMainClassCallback callback = new SingleMainClassCallback(annotationName);\n\t\tMainClassFinder.doWithMainClasses(rootDirectory, callback);\n\t\treturn callback.getMainClassName();\n\t}\n\n\t/**\n\t * Perform the given callback operation on all main classes from the given root\n\t * directory.\n\t * @param <T> the result type\n\t * @param rootDirectory the root directory\n\t * @param callback the callback\n\t * @return the first callback result or {@code null}\n\t * @throws IOException in case of I/O errors\n\t */\n\tstatic <T> @Nullable T doWithMainClasses(File rootDirectory, MainClassCallback<T> callback) throws IOException {\n\t\tif (!rootDirectory.exists()) {\n\t\t\treturn null; // nothing to do\n\t\t}\n\t\tif (!rootDirectory.isDirectory()) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid root directory '\" + rootDirectory + \"'\");\n\t\t}\n\t\tString prefix = rootDirectory.getAbsolutePath() + \"/\";\n\t\tDeque<File> stack = new ArrayDeque<>();\n\t\tstack.push(rootDirectory);\n\t\twhile (!stack.isEmpty()) {\n\t\t\tFile file = stack.pop();\n\t\t\tif (file.isFile()) {\n\t\t\t\ttry (InputStream inputStream = new FileInputStream(file)) {\n\t\t\t\t\tClassDescriptor classDescriptor = createClassDescriptor(inputStream);\n\t\t\t\t\tif (classDescriptor != null && classDescriptor.isMainMethodFound()) {\n\t\t\t\t\t\tString className = convertToClassName(file.getAbsolutePath(), prefix);\n\t\t\t\t\t\tT result = callback.doWith(new MainClass(className, classDescriptor.getAnnotationNames()));\n\t\t\t\t\t\tif (result != null) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (file.isDirectory()) {\n\t\t\t\tpushAllSorted(stack, file.listFiles(PACKAGE_DIRECTORY_FILTER));\n\t\t\t\tpushAllSorted(stack, file.listFiles(CLASS_FILE_FILTER));\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static void pushAllSorted(Deque<File> stack, File @Nullable [] files) {\n\t\tif (files == null) {\n\t\t\treturn;\n\t\t}\n\t\tArrays.sort(files, Comparator.comparing(File::getName));\n\t\tfor (File file : files) {\n\t\t\tstack.push(file);\n\t\t}\n\t}\n\n\t/**\n\t * Find the main class in a given jar file.\n\t * @param jarFile the jar file to search\n\t * @param classesLocation the location within the jar containing classes\n\t * @return the main class or {@code null}\n\t * @throws IOException if the jar file cannot be read\n\t */\n\tpublic static @Nullable String findMainClass(JarFile jarFile, @Nullable String classesLocation) throws IOException {\n\t\treturn doWithMainClasses(jarFile, classesLocation, MainClass::getName);\n\t}\n\n\t/**\n\t * Find a single main class in a given jar file.\n\t * @param jarFile the jar file to search\n\t * @param classesLocation the location within the jar containing classes\n\t * @return the main class or {@code null}\n\t * @throws IOException if the jar file cannot be read\n\t */\n\tpublic static @Nullable String findSingleMainClass(JarFile jarFile, @Nullable String classesLocation)\n\t\t\tthrows IOException {\n\t\treturn findSingleMainClass(jarFile, classesLocation, null);\n\t}\n\n\t/**\n\t * Find a single main class in a given jar file. A main class annotated with an\n\t * annotation with the given {@code annotationName} will be preferred over a main\n\t * class with no such annotation.\n\t * @param jarFile the jar file to search\n\t * @param classesLocation the location within the jar containing classes\n\t * @param annotationName the name of the annotation that may be present on the main\n\t * class\n\t * @return the main class or {@code null}\n\t * @throws IOException if the jar file cannot be read\n\t */\n\tpublic static @Nullable String findSingleMainClass(JarFile jarFile, @Nullable String classesLocation,\n\t\t\t@Nullable String annotationName) throws IOException {\n\t\tSingleMainClassCallback callback = new SingleMainClassCallback(annotationName);\n\t\tMainClassFinder.doWithMainClasses(jarFile, classesLocation, callback);\n\t\treturn callback.getMainClassName();\n\t}\n\n\t/**\n\t * Perform the given callback operation on all main classes from the given jar.\n\t * @param <T> the result type\n\t * @param jarFile the jar file to search\n\t * @param classesLocation the location within the jar containing classes\n\t * @param callback the callback\n\t * @return the first callback result or {@code null}\n\t * @throws IOException in case of I/O errors\n\t */\n\tstatic <T> @Nullable T doWithMainClasses(JarFile jarFile, @Nullable String classesLocation,\n\t\t\tMainClassCallback<T> callback) throws IOException {\n\t\tList<JarEntry> classEntries = getClassEntries(jarFile, classesLocation);\n\t\tclassEntries.sort(new ClassEntryComparator());\n\t\tfor (JarEntry entry : classEntries) {\n\t\t\ttry (InputStream inputStream = new BufferedInputStream(jarFile.getInputStream(entry))) {\n\t\t\t\tClassDescriptor classDescriptor = createClassDescriptor(inputStream);\n\t\t\t\tif (classDescriptor != null && classDescriptor.isMainMethodFound()) {\n\t\t\t\t\tString className = convertToClassName(entry.getName(), classesLocation);\n\t\t\t\t\tT result = callback.doWith(new MainClass(className, classDescriptor.getAnnotationNames()));\n\t\t\t\t\tif (result != null) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static String convertToClassName(String name, @Nullable String prefix) {\n\t\tname = name.replace('/', '.');\n\t\tname = name.replace('\\\\', '.');\n\t\tname = name.substring(0, name.length() - DOT_CLASS.length());\n\t\tif (prefix != null) {\n\t\t\tname = name.substring(prefix.length());\n\t\t}\n\t\treturn name;\n\t}\n\n\tprivate static List<JarEntry> getClassEntries(JarFile source, @Nullable String classesLocation) {\n\t\tclassesLocation = (classesLocation != null) ? classesLocation : \"\";\n\t\tEnumeration<JarEntry> sourceEntries = source.entries();\n\t\tList<JarEntry> classEntries = new ArrayList<>();\n\t\twhile (sourceEntries.hasMoreElements()) {\n\t\t\tJarEntry entry = sourceEntries.nextElement();\n\t\t\tif (entry.getName().startsWith(classesLocation) && entry.getName().endsWith(DOT_CLASS)) {\n\t\t\t\tclassEntries.add(entry);\n\t\t\t}\n\t\t}\n\t\treturn classEntries;\n\t}\n\n\tprivate static @Nullable ClassDescriptor createClassDescriptor(InputStream inputStream) {\n\t\ttry {\n\t\t\tClassReader classReader = new ClassReader(inputStream);\n\t\t\tClassDescriptor classDescriptor = new ClassDescriptor();\n\t\t\tclassReader.accept(classDescriptor, ClassReader.SKIP_CODE);\n\t\t\treturn classDescriptor;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static final class ClassEntryComparator implements Comparator<JarEntry> {\n\n\t\t@Override\n\t\tpublic int compare(JarEntry o1, JarEntry o2) {\n\t\t\tInteger d1 = getDepth(o1);\n\t\t\tInteger d2 = getDepth(o2);\n\t\t\tint depthCompare = d1.compareTo(d2);\n\t\t\tif (depthCompare != 0) {\n\t\t\t\treturn depthCompare;\n\t\t\t}\n\t\t\treturn o1.getName().compareTo(o2.getName());\n\t\t}\n\n\t\tprivate int getDepth(JarEntry entry) {\n\t\t\treturn entry.getName().split(\"/\").length;\n\t\t}\n\n\t}\n\n\tprivate static class ClassDescriptor extends ClassVisitor {\n\n\t\tprivate final Set<String> annotationNames = new LinkedHashSet<>();\n\n\t\tprivate boolean mainMethodFound;\n\n\t\tprivate boolean java25OrLater;\n\n\t\tClassDescriptor() {\n\t\t\tsuper(SpringAsmInfo.ASM_VERSION);\n\t\t}\n\n\t\t@Override\n\t\tpublic void visit(int version, int access, String name, String signature, String superName,\n\t\t\t\tString[] interfaces) {\n\t\t\tif (version >= 69) {\n\t\t\t\tthis.java25OrLater = true;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable AnnotationVisitor visitAnnotation(String desc, boolean visible) {\n\t\t\tthis.annotationNames.add(Type.getType(desc).getClassName());\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable MethodVisitor visitMethod(int access, String name, String desc, String signature,\n\t\t\t\tString[] exceptions) {\n\t\t\tif (hasRequiredAccess(access) && MAIN_METHOD_NAME.equals(name)) {\n\t\t\t\tif (MAIN_METHOD_TYPE.getDescriptor().equals(desc)\n\t\t\t\t\t\t|| (this.java25OrLater && PARAMETERLESS_MAIN_METHOD_TYPE.getDescriptor().equals(desc))) {\n\t\t\t\t\tthis.mainMethodFound = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate boolean hasRequiredAccess(int access) {\n\t\t\tif (this.java25OrLater) {\n\t\t\t\treturn !isAccess(access, Opcodes.ACC_PRIVATE) && isAccess(access, Opcodes.ACC_STATIC);\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn isAccess(access, Opcodes.ACC_PUBLIC, Opcodes.ACC_STATIC);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isAccess(int access, int... requiredOpsCodes) {\n\t\t\tfor (int requiredOpsCode : requiredOpsCodes) {\n\t\t\t\tif ((access & requiredOpsCode) == 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tboolean isMainMethodFound() {\n\t\t\treturn this.mainMethodFound;\n\t\t}\n\n\t\tSet<String> getAnnotationNames() {\n\t\t\treturn this.annotationNames;\n\t\t}\n\n\t}\n\n\t/**\n\t * Callback for handling {@link MainClass MainClasses}.\n\t *\n\t * @param <T> the callback's return type\n\t */\n\tinterface MainClassCallback<T> {\n\n\t\t/**\n\t\t * Handle the specified main class.\n\t\t * @param mainClass the main class\n\t\t * @return a non-null value if processing should end or {@code null} to continue\n\t\t */\n\t\t@Nullable T doWith(MainClass mainClass);\n\n\t}\n\n\t/**\n\t * A class with a {@code main} method.\n\t */\n\tstatic final class MainClass {\n\n\t\tprivate final String name;\n\n\t\tprivate final Set<String> annotationNames;\n\n\t\t/**\n\t\t * Creates a new {@code MainClass} rather represents the main class with the given\n\t\t * {@code name}. The class is annotated with the annotations with the given\n\t\t * {@code annotationNames}.\n\t\t * @param name the name of the class\n\t\t * @param annotationNames the names of the annotations on the class\n\t\t */\n\t\tMainClass(String name, Set<String> annotationNames) {\n\t\t\tthis.name = name;\n\t\t\tthis.annotationNames = Collections.unmodifiableSet(new HashSet<>(annotationNames));\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tSet<String> getAnnotationNames() {\n\t\t\treturn this.annotationNames;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tMainClass other = (MainClass) obj;\n\t\t\treturn this.name.equals(other.name);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.name.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\t/**\n\t * Find a single main class, throwing an {@link IllegalStateException} if multiple\n\t * candidates exist.\n\t */\n\tprivate static final class SingleMainClassCallback implements MainClassCallback<Object> {\n\n\t\tprivate final Set<MainClass> mainClasses = new LinkedHashSet<>();\n\n\t\tprivate final @Nullable String annotationName;\n\n\t\tprivate SingleMainClassCallback(@Nullable String annotationName) {\n\t\t\tthis.annotationName = annotationName;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object doWith(MainClass mainClass) {\n\t\t\tthis.mainClasses.add(mainClass);\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable String getMainClassName() {\n\t\t\tSet<MainClass> matchingMainClasses = new LinkedHashSet<>();\n\t\t\tif (this.annotationName != null) {\n\t\t\t\tfor (MainClass mainClass : this.mainClasses) {\n\t\t\t\t\tif (mainClass.getAnnotationNames().contains(this.annotationName)) {\n\t\t\t\t\t\tmatchingMainClasses.add(mainClass);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (matchingMainClasses.isEmpty()) {\n\t\t\t\tmatchingMainClasses.addAll(this.mainClasses);\n\t\t\t}\n\t\t\tif (matchingMainClasses.size() > 1) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Unable to find a single main class from the following candidates \" + matchingMainClasses);\n\t\t\t}\n\t\t\treturn (matchingMainClasses.isEmpty() ? null : matchingMainClasses.iterator().next().getName());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/NativeImageArgFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * Class to work with the native-image argfile.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 3.0.0\n */\npublic final class NativeImageArgFile {\n\n\t/**\n\t * Location of the argfile.\n\t */\n\tpublic static final String LOCATION = \"META-INF/native-image/argfile\";\n\n\tprivate final List<String> excludes;\n\n\t/**\n\t * Constructs a new instance with the given excludes.\n\t * @param excludes dependencies for which the reachability metadata should be excluded\n\t */\n\tpublic NativeImageArgFile(Collection<String> excludes) {\n\t\tthis.excludes = List.copyOf(excludes);\n\t}\n\n\t/**\n\t * Write the arguments file if it is necessary.\n\t * @param writer consumer that should write the contents\n\t */\n\tpublic void writeIfNecessary(ThrowingConsumer<List<String>> writer) {\n\t\tif (this.excludes.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tList<String> lines = new ArrayList<>();\n\t\tfor (String exclude : this.excludes) {\n\t\t\tint lastSlash = exclude.lastIndexOf('/');\n\t\t\tString jar = (lastSlash != -1) ? exclude.substring(lastSlash + 1) : exclude;\n\t\t\tlines.add(\"--exclude-config\");\n\t\t\tlines.add(Pattern.quote(jar));\n\t\t\tlines.add(\"^/META-INF/native-image/.*\");\n\t\t}\n\t\twriter.accept(lines);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.commons.compress.archivers.jar.JarArchiveEntry;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.AbstractJarWriter.EntryTransformer;\nimport org.springframework.boot.loader.tools.AbstractJarWriter.UnpackHandler;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Abstract base class for packagers.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 2.3.0\n */\npublic abstract class Packager {\n\n\tprivate static final String MAIN_CLASS_ATTRIBUTE = \"Main-Class\";\n\n\tprivate static final String START_CLASS_ATTRIBUTE = \"Start-Class\";\n\n\tprivate static final String BOOT_VERSION_ATTRIBUTE = \"Spring-Boot-Version\";\n\n\tprivate static final String BOOT_CLASSES_ATTRIBUTE = \"Spring-Boot-Classes\";\n\n\tprivate static final String BOOT_LIB_ATTRIBUTE = \"Spring-Boot-Lib\";\n\n\tprivate static final String BOOT_CLASSPATH_INDEX_ATTRIBUTE = \"Spring-Boot-Classpath-Index\";\n\n\tprivate static final String BOOT_LAYERS_INDEX_ATTRIBUTE = \"Spring-Boot-Layers-Index\";\n\n\tprivate static final String SBOM_LOCATION_ATTRIBUTE = \"Sbom-Location\";\n\n\tprivate static final String SBOM_FORMAT_ATTRIBUTE = \"Sbom-Format\";\n\n\tprivate static final byte[] ZIP_FILE_HEADER = new byte[] { 'P', 'K', 3, 4 };\n\n\tprivate static final long FIND_WARNING_TIMEOUT = TimeUnit.SECONDS.toMillis(10);\n\n\tprivate static final String SPRING_BOOT_APPLICATION_CLASS_NAME = \"org.springframework.boot.autoconfigure.SpringBootApplication\";\n\n\tprivate final List<MainClassTimeoutWarningListener> mainClassTimeoutListeners = new ArrayList<>();\n\n\tprivate @Nullable String mainClass;\n\n\tprivate final File source;\n\n\tprivate @Nullable File backupFile;\n\n\tprivate @Nullable Layout layout;\n\n\tprivate @Nullable LayoutFactory layoutFactory;\n\n\tprivate @Nullable Layers layers;\n\n\tprivate @Nullable LayersIndex layersIndex;\n\n\tprivate boolean includeRelevantJarModeJars = true;\n\n\t/**\n\t * Create a new {@link Packager} instance.\n\t * @param source the source archive file to package\n\t */\n\tprotected Packager(File source) {\n\t\tAssert.notNull(source, \"'source' file must not be null\");\n\t\tAssert.isTrue(source.exists() && source.isFile(),\n\t\t\t\t() -> \"'source' must refer to an existing file, got \" + source.getAbsolutePath());\n\t\tthis.source = source.getAbsoluteFile();\n\t}\n\n\t/**\n\t * Add a listener that will be triggered to display a warning if searching for the\n\t * main class takes too long.\n\t * @param listener the listener to add\n\t */\n\tpublic void addMainClassTimeoutWarningListener(MainClassTimeoutWarningListener listener) {\n\t\tthis.mainClassTimeoutListeners.add(listener);\n\t}\n\n\t/**\n\t * Sets the main class that should be run. If not specified the value from the\n\t * MANIFEST will be used, or if no manifest entry is found the archive will be\n\t * searched for a suitable class.\n\t * @param mainClass the main class name\n\t */\n\tpublic void setMainClass(@Nullable String mainClass) {\n\t\tthis.mainClass = mainClass;\n\t}\n\n\t/**\n\t * Sets the layout to use for the jar. Defaults to {@link Layouts#forFile(File)}.\n\t * @param layout the layout\n\t */\n\tpublic void setLayout(Layout layout) {\n\t\tAssert.notNull(layout, \"Layout must not be null\");\n\t\tthis.layout = layout;\n\t}\n\n\t/**\n\t * Sets the layout factory for the jar. The factory can be used when no specific\n\t * layout is specified.\n\t * @param layoutFactory the layout factory to set\n\t */\n\tpublic void setLayoutFactory(@Nullable LayoutFactory layoutFactory) {\n\t\tthis.layoutFactory = layoutFactory;\n\t}\n\n\t/**\n\t * Sets the layers that should be used in the jar.\n\t * @param layers the jar layers\n\t */\n\tpublic void setLayers(Layers layers) {\n\t\tAssert.notNull(layers, \"'layers' must not be null\");\n\t\tthis.layers = layers;\n\t\tthis.layersIndex = new LayersIndex(layers);\n\t}\n\n\t/**\n\t * Sets the {@link File} to use to back up the original source.\n\t * @param backupFile the file to use to back up the original source\n\t */\n\tprotected void setBackupFile(@Nullable File backupFile) {\n\t\tthis.backupFile = backupFile;\n\t}\n\n\t/**\n\t * Sets if jarmode jars relevant for the packaging should be automatically included.\n\t * @param includeRelevantJarModeJars if relevant jars are included\n\t */\n\tpublic void setIncludeRelevantJarModeJars(boolean includeRelevantJarModeJars) {\n\t\tthis.includeRelevantJarModeJars = includeRelevantJarModeJars;\n\t}\n\n\tprotected final boolean isAlreadyPackaged() {\n\t\treturn isAlreadyPackaged(this.source);\n\t}\n\n\tprotected final boolean isAlreadyPackaged(File file) {\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\tManifest manifest = jarFile.getManifest();\n\t\t\treturn (manifest != null && manifest.getMainAttributes().getValue(BOOT_VERSION_ATTRIBUTE) != null);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Error reading archive file\", ex);\n\t\t}\n\t}\n\n\tprotected final void write(JarFile sourceJar, Libraries libraries, AbstractJarWriter writer) throws IOException {\n\t\twrite(sourceJar, libraries, writer, false);\n\t}\n\n\tprotected final void write(JarFile sourceJar, Libraries libraries, AbstractJarWriter writer,\n\t\t\tboolean ensureReproducibleBuild) throws IOException {\n\t\tAssert.notNull(libraries, \"'libraries' must not be null\");\n\t\twrite(sourceJar, writer, new PackagedLibraries(libraries, ensureReproducibleBuild));\n\t}\n\n\tprivate void write(JarFile sourceJar, AbstractJarWriter writer, PackagedLibraries libraries) throws IOException {\n\t\tif (isLayered()) {\n\t\t\twriter.useLayers(this.layers, this.layersIndex);\n\t\t}\n\t\twriter.writeManifest(buildManifest(sourceJar));\n\t\twriteLoaderClasses(writer);\n\t\twriter.writeEntries(sourceJar, getEntityTransformer(), libraries.getUnpackHandler(),\n\t\t\t\tlibraries.getLibraryLookup());\n\t\tMap<String, Library> writtenLibraries = libraries.write(writer);\n\t\twriteNativeImageArgFile(writer, sourceJar, writtenLibraries);\n\t\tif (isLayered()) {\n\t\t\twriteLayerIndex(writer);\n\t\t}\n\t\twriteSignatureFileIfNecessary(writtenLibraries, writer);\n\t}\n\n\tprivate void writeLoaderClasses(AbstractJarWriter writer) throws IOException {\n\t\tLayout layout = getLayout();\n\t\tif (layout instanceof CustomLoaderLayout customLoaderLayout) {\n\t\t\tcustomLoaderLayout.writeLoadedClasses(writer);\n\t\t}\n\t\telse if (layout.isExecutable()) {\n\t\t\twriter.writeLoaderClasses();\n\t\t}\n\t}\n\n\tprivate void writeNativeImageArgFile(AbstractJarWriter writer, JarFile sourceJar,\n\t\t\tMap<String, Library> writtenLibraries) throws IOException {\n\t\tSet<String> excludes = new LinkedHashSet<>();\n\t\tfor (Map.Entry<String, Library> entry : writtenLibraries.entrySet()) {\n\t\t\tLibraryCoordinates coordinates = entry.getValue().getCoordinates();\n\t\t\tZipEntry zipEntry = (coordinates != null)\n\t\t\t\t\t? sourceJar.getEntry(ReachabilityMetadataProperties.getLocation(coordinates)) : null;\n\t\t\tif (zipEntry != null) {\n\t\t\t\ttry (InputStream inputStream = sourceJar.getInputStream(zipEntry)) {\n\t\t\t\t\tReachabilityMetadataProperties properties = ReachabilityMetadataProperties\n\t\t\t\t\t\t.fromInputStream(inputStream);\n\t\t\t\t\tif (properties.isOverridden()) {\n\t\t\t\t\t\texcludes.add(entry.getKey());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tNativeImageArgFile argFile = new NativeImageArgFile(excludes);\n\t\targFile.writeIfNecessary((lines) -> {\n\t\t\tString contents = String.join(\"\\n\", lines) + \"\\n\";\n\t\t\twriter.writeEntry(NativeImageArgFile.LOCATION,\n\t\t\t\t\tnew ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8)));\n\t\t});\n\t}\n\n\tprivate void writeLayerIndex(AbstractJarWriter writer) throws IOException {\n\t\tAssert.state(this.layout != null, \"'layout' must not be null\");\n\t\tString name = this.layout.getLayersIndexFileLocation();\n\t\tif (StringUtils.hasLength(name)) {\n\t\t\tAssert.state(this.layers != null, \"'layers' must not be null\");\n\t\t\tAssert.state(this.layersIndex != null, \"'layersIndex' must not be null\");\n\t\t\tLayer layer = this.layers.getLayer(name);\n\t\t\tthis.layersIndex.add(layer, name);\n\t\t\twriter.writeEntry(name, this.layersIndex::writeTo);\n\t\t}\n\t}\n\n\t/**\n\t * Writes a signature file if necessary for the given {@code writtenLibraries}.\n\t * @param writtenLibraries the libraries\n\t * @param writer the writer to use to write the signature file if necessary\n\t * @throws IOException if a failure occurs when writing the signature file\n\t */\n\tprotected void writeSignatureFileIfNecessary(Map<String, Library> writtenLibraries, AbstractJarWriter writer)\n\t\t\tthrows IOException {\n\t}\n\n\tprivate EntryTransformer getEntityTransformer() {\n\t\tif (getLayout() instanceof RepackagingLayout repackagingLayout) {\n\t\t\treturn new RepackagingEntryTransformer(repackagingLayout);\n\t\t}\n\t\treturn EntryTransformer.NONE;\n\t}\n\n\tprivate boolean isZip(InputStreamSupplier supplier) {\n\t\ttry {\n\t\t\ttry (InputStream inputStream = supplier.openStream()) {\n\t\t\t\treturn isZip(inputStream);\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean isZip(InputStream inputStream) throws IOException {\n\t\tfor (byte magicByte : ZIP_FILE_HEADER) {\n\t\t\tif (inputStream.read() != magicByte) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate Manifest buildManifest(JarFile source) throws IOException {\n\t\tManifest manifest = createInitialManifest(source);\n\t\taddMainAndStartAttributes(source, manifest);\n\t\taddBootAttributes(manifest.getMainAttributes());\n\t\taddSbomAttributes(source, manifest.getMainAttributes());\n\t\treturn manifest;\n\t}\n\n\tprivate Manifest createInitialManifest(JarFile source) throws IOException {\n\t\tif (source.getManifest() != null) {\n\t\t\treturn new Manifest(source.getManifest());\n\t\t}\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(\"Manifest-Version\", \"1.0\");\n\t\treturn manifest;\n\t}\n\n\tprivate void addMainAndStartAttributes(JarFile source, Manifest manifest) throws IOException {\n\t\tString mainClass = getMainClass(source, manifest);\n\t\tString launcherClass = getLayout().getLauncherClassName();\n\t\tif (launcherClass != null) {\n\t\t\tAssert.state(mainClass != null, \"Unable to find main class\");\n\t\t\tmanifest.getMainAttributes().putValue(MAIN_CLASS_ATTRIBUTE, launcherClass);\n\t\t\tmanifest.getMainAttributes().putValue(START_CLASS_ATTRIBUTE, mainClass);\n\t\t}\n\t\telse if (mainClass != null) {\n\t\t\tmanifest.getMainAttributes().putValue(MAIN_CLASS_ATTRIBUTE, mainClass);\n\t\t}\n\t}\n\n\tprivate @Nullable String getMainClass(JarFile source, Manifest manifest) throws IOException {\n\t\tif (this.mainClass != null) {\n\t\t\treturn this.mainClass;\n\t\t}\n\t\tString attributeValue = manifest.getMainAttributes().getValue(MAIN_CLASS_ATTRIBUTE);\n\t\tif (attributeValue != null) {\n\t\t\treturn attributeValue;\n\t\t}\n\t\treturn findMainMethodWithTimeoutWarning(source);\n\t}\n\n\tprivate @Nullable String findMainMethodWithTimeoutWarning(JarFile source) throws IOException {\n\t\tlong startTime = System.currentTimeMillis();\n\t\tString mainMethod = findMainMethod(source);\n\t\tlong duration = System.currentTimeMillis() - startTime;\n\t\tif (duration > FIND_WARNING_TIMEOUT) {\n\t\t\tfor (MainClassTimeoutWarningListener listener : this.mainClassTimeoutListeners) {\n\t\t\t\tlistener.handleTimeoutWarning(duration, mainMethod);\n\t\t\t}\n\t\t}\n\t\treturn mainMethod;\n\t}\n\n\tprotected @Nullable String findMainMethod(JarFile source) throws IOException {\n\t\treturn MainClassFinder.findSingleMainClass(source, getLayout().getClassesLocation(),\n\t\t\t\tSPRING_BOOT_APPLICATION_CLASS_NAME);\n\t}\n\n\t/**\n\t * Return the {@link File} to use to back up the original source.\n\t * @return the file to use to back up the original source\n\t */\n\tpublic final File getBackupFile() {\n\t\tif (this.backupFile != null) {\n\t\t\treturn this.backupFile;\n\t\t}\n\t\treturn new File(this.source.getParentFile(), this.source.getName() + \".original\");\n\t}\n\n\tprotected final File getSource() {\n\t\treturn this.source;\n\t}\n\n\tprotected final Layout getLayout() {\n\t\tif (this.layout == null) {\n\t\t\tLayout createdLayout = getLayoutFactory().getLayout(this.source);\n\t\t\tAssert.state(createdLayout != null, \"Unable to detect layout\");\n\t\t\tthis.layout = createdLayout;\n\t\t}\n\t\treturn this.layout;\n\t}\n\n\tprivate LayoutFactory getLayoutFactory() {\n\t\tif (this.layoutFactory != null) {\n\t\t\treturn this.layoutFactory;\n\t\t}\n\t\tList<LayoutFactory> factories = SpringFactoriesLoader.loadFactories(LayoutFactory.class, null);\n\t\tif (factories.isEmpty()) {\n\t\t\treturn new DefaultLayoutFactory();\n\t\t}\n\t\tAssert.state(factories.size() == 1, \"No unique LayoutFactory found\");\n\t\treturn factories.get(0);\n\t}\n\n\tprivate void addBootAttributes(Attributes attributes) {\n\t\tattributes.putValue(BOOT_VERSION_ATTRIBUTE, getClass().getPackage().getImplementationVersion());\n\t\taddBootAttributesForLayout(attributes);\n\t}\n\n\tprivate void addBootAttributesForLayout(Attributes attributes) {\n\t\tLayout layout = getLayout();\n\t\tif (layout instanceof RepackagingLayout repackagingLayout) {\n\t\t\tattributes.putValue(BOOT_CLASSES_ATTRIBUTE, repackagingLayout.getRepackagedClassesLocation());\n\t\t}\n\t\telse {\n\t\t\tattributes.putValue(BOOT_CLASSES_ATTRIBUTE, layout.getClassesLocation());\n\t\t}\n\t\tputIfHasLength(attributes, BOOT_LIB_ATTRIBUTE, getLayout().getLibraryLocation(\"\", LibraryScope.COMPILE));\n\t\tputIfHasLength(attributes, BOOT_CLASSPATH_INDEX_ATTRIBUTE, layout.getClasspathIndexFileLocation());\n\t\tif (isLayered()) {\n\t\t\tputIfHasLength(attributes, BOOT_LAYERS_INDEX_ATTRIBUTE, layout.getLayersIndexFileLocation());\n\t\t}\n\t}\n\n\tprivate void addSbomAttributes(JarFile source, Attributes attributes) {\n\t\tJarEntry sbomEntry = source.stream().filter(this::isCycloneDxBom).findAny().orElse(null);\n\t\tif (sbomEntry != null) {\n\t\t\tattributes.putValue(SBOM_LOCATION_ATTRIBUTE, sbomEntry.getName());\n\t\t\tattributes.putValue(SBOM_FORMAT_ATTRIBUTE, \"CycloneDX\");\n\t\t}\n\t}\n\n\tprivate boolean isCycloneDxBom(JarEntry entry) {\n\t\tif (!entry.getName().startsWith(\"META-INF/sbom/\")) {\n\t\t\treturn false;\n\t\t}\n\t\treturn entry.getName().endsWith(\".cdx.json\") || entry.getName().endsWith(\"/bom.json\");\n\t}\n\n\tprivate void putIfHasLength(Attributes attributes, String name, @Nullable String value) {\n\t\tif (StringUtils.hasLength(value)) {\n\t\t\tattributes.putValue(name, value);\n\t\t}\n\t}\n\n\tprivate boolean isLayered() {\n\t\treturn this.layers != null;\n\t}\n\n\t/**\n\t * Callback interface used to present a warning when finding the main class takes too\n\t * long.\n\t */\n\t@FunctionalInterface\n\tpublic interface MainClassTimeoutWarningListener {\n\n\t\t/**\n\t\t * Handle a timeout warning.\n\t\t * @param duration the amount of time it took to find the main method\n\t\t * @param mainMethod the main method that was actually found\n\t\t */\n\t\tvoid handleTimeoutWarning(long duration, @Nullable String mainMethod);\n\n\t}\n\n\t/**\n\t * An {@code EntryTransformer} that renames entries by applying a prefix.\n\t */\n\tprivate static final class RepackagingEntryTransformer implements EntryTransformer {\n\n\t\tprivate final RepackagingLayout layout;\n\n\t\tprivate RepackagingEntryTransformer(RepackagingLayout layout) {\n\t\t\tthis.layout = layout;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable JarArchiveEntry transform(JarArchiveEntry entry) {\n\t\t\tif (entry.getName().equals(\"META-INF/INDEX.LIST\")) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!isTransformable(entry)) {\n\t\t\t\treturn entry;\n\t\t\t}\n\t\t\tString transformedName = transformName(entry.getName());\n\t\t\tJarArchiveEntry transformedEntry = new JarArchiveEntry(transformedName);\n\t\t\ttransformedEntry.setTime(entry.getTime());\n\t\t\ttransformedEntry.setSize(entry.getSize());\n\t\t\ttransformedEntry.setMethod(entry.getMethod());\n\t\t\tif (entry.getComment() != null) {\n\t\t\t\ttransformedEntry.setComment(entry.getComment());\n\t\t\t}\n\t\t\ttransformedEntry.setCompressedSize(entry.getCompressedSize());\n\t\t\ttransformedEntry.setCrc(entry.getCrc());\n\t\t\tif (entry.getCreationTime() != null) {\n\t\t\t\ttransformedEntry.setCreationTime(entry.getCreationTime());\n\t\t\t}\n\t\t\tif (entry.getExtra() != null) {\n\t\t\t\ttransformedEntry.setExtra(entry.getExtra());\n\t\t\t}\n\t\t\tif (entry.getLastAccessTime() != null) {\n\t\t\t\ttransformedEntry.setLastAccessTime(entry.getLastAccessTime());\n\t\t\t}\n\t\t\tif (entry.getLastModifiedTime() != null) {\n\t\t\t\ttransformedEntry.setLastModifiedTime(entry.getLastModifiedTime());\n\t\t\t}\n\t\t\treturn transformedEntry;\n\t\t}\n\n\t\tprivate String transformName(String name) {\n\t\t\treturn this.layout.getRepackagedClassesLocation() + name;\n\t\t}\n\n\t\tprivate boolean isTransformable(JarArchiveEntry entry) {\n\t\t\tString name = entry.getName();\n\t\t\tif (name.startsWith(\"META-INF/\")) {\n\t\t\t\treturn name.equals(\"META-INF/aop.xml\") || name.endsWith(\".kotlin_module\")\n\t\t\t\t\t\t|| name.startsWith(\"META-INF/services/\");\n\t\t\t}\n\t\t\treturn !name.startsWith(\"BOOT-INF/\") && !name.equals(\"module-info.class\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Libraries that should be packaged into the archive.\n\t */\n\tprivate final class PackagedLibraries {\n\n\t\tprivate final Map<String, Library> libraries;\n\n\t\tprivate final UnpackHandler unpackHandler;\n\n\t\tprivate final Function<JarEntry, @Nullable Library> libraryLookup;\n\n\t\tPackagedLibraries(Libraries libraries, boolean ensureReproducibleBuild) throws IOException {\n\t\t\tthis.libraries = (ensureReproducibleBuild) ? new TreeMap<>() : new LinkedHashMap<>();\n\t\t\tlibraries.doWithLibraries((library) -> {\n\t\t\t\tif (isZip(library::openStream)) {\n\t\t\t\t\taddLibrary(library);\n\t\t\t\t}\n\t\t\t});\n\t\t\tif (Packager.this.includeRelevantJarModeJars) {\n\t\t\t\taddLibrary(JarModeLibrary.TOOLS);\n\t\t\t}\n\t\t\tthis.unpackHandler = new PackagedLibrariesUnpackHandler();\n\t\t\tthis.libraryLookup = this::lookup;\n\t\t}\n\n\t\tprivate void addLibrary(Library library) {\n\t\t\tString location = getLayout().getLibraryLocation(library.getName(), library.getScope());\n\t\t\tif (location != null) {\n\t\t\t\tString path = location + library.getName();\n\t\t\t\tLibrary existing = this.libraries.putIfAbsent(path, library);\n\t\t\t\tAssert.state(existing == null, () -> \"Duplicate library \" + library.getName());\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable Library lookup(JarEntry entry) {\n\t\t\treturn this.libraries.get(entry.getName());\n\t\t}\n\n\t\tUnpackHandler getUnpackHandler() {\n\t\t\treturn this.unpackHandler;\n\t\t}\n\n\t\tFunction<JarEntry, @Nullable Library> getLibraryLookup() {\n\t\t\treturn this.libraryLookup;\n\t\t}\n\n\t\tMap<String, Library> write(AbstractJarWriter writer) throws IOException {\n\t\t\tMap<String, Library> writtenLibraries = new LinkedHashMap<>();\n\t\t\tfor (Entry<String, Library> entry : this.libraries.entrySet()) {\n\t\t\t\tString path = entry.getKey();\n\t\t\t\tLibrary library = entry.getValue();\n\t\t\t\tif (library.isIncluded()) {\n\t\t\t\t\tString location = path.substring(0, path.lastIndexOf('/') + 1);\n\t\t\t\t\twriter.writeNestedLibrary(location, library);\n\t\t\t\t\twrittenLibraries.put(path, library);\n\t\t\t\t}\n\t\t\t}\n\t\t\twriteClasspathIndexIfNecessary(writtenLibraries.keySet(), getLayout(), writer);\n\t\t\treturn writtenLibraries;\n\t\t}\n\n\t\tprivate void writeClasspathIndexIfNecessary(Collection<String> paths, Layout layout, AbstractJarWriter writer)\n\t\t\t\tthrows IOException {\n\t\t\tif (layout.getClasspathIndexFileLocation() != null) {\n\t\t\t\tList<String> names = paths.stream().map((path) -> \"- \\\"\" + path + \"\\\"\").toList();\n\t\t\t\twriter.writeIndexFile(layout.getClasspathIndexFileLocation(), names);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * An {@link UnpackHandler} that determines that an entry needs to be unpacked if\n\t\t * a library that requires unpacking has a matching entry name.\n\t\t */\n\t\tprivate final class PackagedLibrariesUnpackHandler implements UnpackHandler {\n\n\t\t\t@Override\n\t\t\tpublic boolean requiresUnpack(String name) {\n\t\t\t\tLibrary library = PackagedLibraries.this.libraries.get(name);\n\t\t\t\treturn library != null && library.isUnpackRequired();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ReachabilityMetadataProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * Class to work with {@code reachability-metadata.properties}.\n *\n * @author Moritz Halbritter\n * @since 3.0.0\n */\npublic final class ReachabilityMetadataProperties {\n\n\t/**\n\t * Location of the properties file. Must be formatted using\n\t * {@link String#format(String, Object...)} with the group id, artifact id and version\n\t * of the dependency.\n\t */\n\tpublic static final String REACHABILITY_METADATA_PROPERTIES_LOCATION_TEMPLATE = \"META-INF/native-image/%s/%s/%s/reachability-metadata.properties\";\n\n\tprivate final Properties properties;\n\n\tprivate ReachabilityMetadataProperties(Properties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t/**\n\t * Returns if the dependency has been overridden.\n\t * @return true if the dependency has been overridden\n\t */\n\tpublic boolean isOverridden() {\n\t\treturn Boolean.parseBoolean(this.properties.getProperty(\"override\"));\n\t}\n\n\t/**\n\t * Constructs a new instance from the given {@code InputStream}.\n\t * @param inputStream {@code InputStream} to load the properties from\n\t * @return loaded properties\n\t * @throws IOException if loading from the {@code InputStream} went wrong\n\t */\n\tpublic static ReachabilityMetadataProperties fromInputStream(InputStream inputStream) throws IOException {\n\t\tProperties properties = new Properties();\n\t\tproperties.load(inputStream);\n\t\treturn new ReachabilityMetadataProperties(properties);\n\t}\n\n\t/**\n\t * Returns the location of the properties for the given coordinates.\n\t * @param coordinates library coordinates for which the property file location should\n\t * be returned\n\t * @return location of the properties\n\t */\n\tpublic static String getLocation(LibraryCoordinates coordinates) {\n\t\treturn REACHABILITY_METADATA_PROPERTIES_LOCATION_TEMPLATE.formatted(coordinates.getGroupId(),\n\t\t\t\tcoordinates.getArtifactId(), coordinates.getVersion());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.attribute.FileTime;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.jar.JarFile;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Utility class that can be used to repackage an archive so that it can be executed using\n * '{@literal java -jar}'.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Scott Frederick\n * @since 1.0.0\n */\npublic class Repackager extends Packager {\n\n\tprivate boolean backupSource = true;\n\n\t/**\n\t * Create a new {@link Repackager} instance.\n\t * @param source the source archive file to package\n\t */\n\tpublic Repackager(File source) {\n\t\tsuper(source);\n\t}\n\n\t@Override\n\tprotected void writeSignatureFileIfNecessary(Map<String, Library> writtenLibraries, AbstractJarWriter writer)\n\t\t\tthrows IOException {\n\t\tString sourceName = getSource().getName().toLowerCase(Locale.ROOT);\n\t\tif ((sourceName.endsWith(\".jar\") || sourceName.endsWith(\".war\")) && hasSignedLibrary(writtenLibraries)) {\n\t\t\twriter.writeEntry(\"META-INF/BOOT.SF\", (entryWriter) -> {\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate boolean hasSignedLibrary(Map<String, Library> writtenLibraries) throws IOException {\n\t\tfor (Library library : writtenLibraries.values()) {\n\t\t\tif (!(library instanceof JarModeLibrary) && FileUtils.isSignedJarFile(library.getFile())) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Sets if source files should be backed up when they would be overwritten.\n\t * @param backupSource if source files should be backed up\n\t */\n\tpublic void setBackupSource(boolean backupSource) {\n\t\tthis.backupSource = backupSource;\n\t}\n\n\t/**\n\t * Repackage the source file so that it can be run using '{@literal java -jar}'.\n\t * @param libraries the libraries required to run the archive\n\t * @throws IOException if the file cannot be repackaged\n\t */\n\tpublic void repackage(Libraries libraries) throws IOException {\n\t\trepackage(getSource(), libraries);\n\t}\n\n\t/**\n\t * Repackage to the given destination so that it can be launched using '\n\t * {@literal java -jar}'.\n\t * @param destination the destination file (may be the same as the source)\n\t * @param libraries the libraries required to run the archive\n\t * @throws IOException if the file cannot be repackaged\n\t */\n\tpublic void repackage(File destination, Libraries libraries) throws IOException {\n\t\trepackage(destination, libraries, null);\n\t}\n\n\t/**\n\t * Repackage to the given destination so that it can be launched using '\n\t * {@literal java -jar}'.\n\t * @param destination the destination file (may be the same as the source)\n\t * @param libraries the libraries required to run the archive\n\t * @param lastModifiedTime an optional last modified time to apply to the archive and\n\t * its contents\n\t * @throws IOException if the file cannot be repackaged\n\t * @since 4.0.0\n\t */\n\tpublic void repackage(File destination, Libraries libraries, @Nullable FileTime lastModifiedTime)\n\t\t\tthrows IOException {\n\t\tAssert.isTrue(destination != null && !destination.isDirectory(), \"Invalid destination\");\n\t\tgetLayout(); // get layout early\n\t\tdestination = destination.getAbsoluteFile();\n\t\tFile source = getSource();\n\t\tif (isAlreadyPackaged() && source.equals(destination)) {\n\t\t\treturn;\n\t\t}\n\t\tFile workingSource = source;\n\t\tif (source.equals(destination)) {\n\t\t\tworkingSource = getBackupFile();\n\t\t\tworkingSource.delete();\n\t\t\trenameFile(source, workingSource);\n\t\t}\n\t\tdestination.delete();\n\t\ttry {\n\t\t\ttry (JarFile sourceJar = new JarFile(workingSource)) {\n\t\t\t\trepackage(sourceJar, destination, libraries, lastModifiedTime);\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tif (!this.backupSource && !source.equals(workingSource)) {\n\t\t\t\tdeleteFile(workingSource);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void repackage(JarFile sourceJar, File destination, Libraries libraries,\n\t\t\t@Nullable FileTime lastModifiedTime) throws IOException {\n\t\ttry (JarWriter writer = new JarWriter(destination, lastModifiedTime)) {\n\t\t\twrite(sourceJar, libraries, writer, lastModifiedTime != null);\n\t\t}\n\t\tif (lastModifiedTime != null) {\n\t\t\tdestination.setLastModified(lastModifiedTime.toMillis());\n\t\t}\n\t}\n\n\tprivate void renameFile(File file, File dest) {\n\t\tif (!file.renameTo(dest)) {\n\t\t\tthrow new IllegalStateException(\"Unable to rename '\" + file + \"' to '\" + dest + \"'\");\n\t\t}\n\t}\n\n\tprivate void deleteFile(File file) {\n\t\tif (!file.delete()) {\n\t\t\tthrow new IllegalStateException(\"Unable to delete '\" + file + \"'\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RepackagingLayout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\n/**\n * A specialization of {@link Layout} that repackages an existing archive by moving its\n * content to a new location.\n *\n * @author Andy Wilkinson\n * @since 1.4.0\n */\npublic interface RepackagingLayout extends Layout {\n\n\t/**\n\t * Returns the location to which classes should be moved.\n\t * @return the repackaged classes location\n\t */\n\tString getRepackagedClassesLocation();\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/RunProcess.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Utility used to run a process.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Dmytro Nosan\n * @since 1.1.0\n */\npublic class RunProcess {\n\n\tprivate static final long JUST_ENDED_LIMIT = 500;\n\n\tprivate final @Nullable File workingDirectory;\n\n\tprivate final String[] command;\n\n\tprivate volatile @Nullable Process process;\n\n\tprivate volatile long endTime;\n\n\t/**\n\t * Creates new {@link RunProcess} instance for the specified command.\n\t * @param command the program to execute and its arguments\n\t */\n\tpublic RunProcess(String... command) {\n\t\tthis(null, command);\n\t}\n\n\t/**\n\t * Creates new {@link RunProcess} instance for the specified working directory and\n\t * command.\n\t * @param workingDirectory the working directory of the child process or {@code null}\n\t * to run in the working directory of the current Java process\n\t * @param command the program to execute and its arguments\n\t */\n\tpublic RunProcess(@Nullable File workingDirectory, String... command) {\n\t\tthis.workingDirectory = workingDirectory;\n\t\tthis.command = command;\n\t}\n\n\tpublic int run(boolean waitForProcess, String... args) throws IOException {\n\t\treturn run(waitForProcess, Arrays.asList(args), Collections.emptyMap());\n\t}\n\n\tpublic int run(boolean waitForProcess, Collection<String> args, Map<String, String> environmentVariables)\n\t\t\tthrows IOException {\n\t\tProcessBuilder builder = new ProcessBuilder(this.command);\n\t\tbuilder.directory(this.workingDirectory);\n\t\tbuilder.command().addAll(args);\n\t\tbuilder.environment().putAll(environmentVariables);\n\t\tbuilder.redirectErrorStream(true);\n\t\tbuilder.inheritIO();\n\t\ttry {\n\t\t\tProcess process = builder.start();\n\t\t\tthis.process = process;\n\t\t\tSignalUtils.attachSignalHandler(this::handleSigInt);\n\t\t\tif (waitForProcess) {\n\t\t\t\ttry {\n\t\t\t\t\treturn process.waitFor();\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 5;\n\t\t}\n\t\tfinally {\n\t\t\tif (waitForProcess) {\n\t\t\t\tthis.endTime = System.currentTimeMillis();\n\t\t\t\tthis.process = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Return the running process.\n\t * @return the process or {@code null}\n\t */\n\tpublic @Nullable Process getRunningProcess() {\n\t\treturn this.process;\n\t}\n\n\t/**\n\t * Return if the process was stopped.\n\t * @return {@code true} if stopped\n\t */\n\tpublic boolean handleSigInt() {\n\t\tif (allowChildToHandleSigInt()) {\n\t\t\treturn true;\n\t\t}\n\t\treturn doKill();\n\t}\n\n\tprivate boolean allowChildToHandleSigInt() {\n\t\tProcess process = this.process;\n\t\tif (process == null) {\n\t\t\treturn true;\n\t\t}\n\t\tlong end = System.currentTimeMillis() + 5000;\n\t\twhile (System.currentTimeMillis() < end) {\n\t\t\tif (!process.isAlive()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tThread.sleep(500);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Kill this process.\n\t */\n\tpublic void kill() {\n\t\tdoKill();\n\t}\n\n\tprivate boolean doKill() {\n\t\t// destroy the running process\n\t\tProcess process = this.process;\n\t\tif (process != null) {\n\t\t\ttry {\n\t\t\t\tprocess.destroy();\n\t\t\t\tprocess.waitFor();\n\t\t\t\tthis.process = null;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic boolean hasJustEnded() {\n\t\treturn System.currentTimeMillis() < (this.endTime + JUST_ENDED_LIMIT);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/SignalUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport sun.misc.Signal;\n\n/**\n * Utilities for working with signal handling.\n *\n * @author Dave Syer\n * @since 1.1.0\n */\npublic final class SignalUtils {\n\n\tprivate static final Signal SIG_INT = new Signal(\"INT\");\n\n\tprivate SignalUtils() {\n\t}\n\n\t/**\n\t * Handle {@literal INT} signals by calling the specified {@link Runnable}.\n\t * @param runnable the runnable to call on SIGINT.\n\t */\n\tpublic static void attachSignalHandler(Runnable runnable) {\n\t\tSignal.handle(SIG_INT, (signal) -> runnable.run());\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/SizeCalculatingEntryWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\n/**\n * {@link EntryWriter} that always provides size information.\n *\n * @author Phillip Webb\n */\nfinal class SizeCalculatingEntryWriter implements EntryWriter {\n\n\tstatic final int THRESHOLD = 1024 * 20;\n\n\tprivate final Object content;\n\n\tprivate final int size;\n\n\tprivate SizeCalculatingEntryWriter(EntryWriter entryWriter) throws IOException {\n\t\tSizeCalculatingOutputStream outputStream = new SizeCalculatingOutputStream();\n\t\ttry (outputStream) {\n\t\t\tentryWriter.write(outputStream);\n\t\t}\n\t\tthis.content = outputStream.getContent();\n\t\tthis.size = outputStream.getSize();\n\t}\n\n\t@Override\n\tpublic void write(OutputStream outputStream) throws IOException {\n\t\tInputStream inputStream = getContentInputStream();\n\t\tcopy(inputStream, outputStream);\n\t}\n\n\tprivate InputStream getContentInputStream() throws FileNotFoundException {\n\t\tif (this.content instanceof File file) {\n\t\t\treturn new FileInputStream(file);\n\t\t}\n\t\treturn new ByteArrayInputStream((byte[]) this.content);\n\t}\n\n\tprivate void copy(InputStream inputStream, OutputStream outputStream) throws IOException {\n\t\ttry (inputStream) {\n\t\t\tStreamUtils.copy(inputStream, outputStream);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int size() {\n\t\treturn this.size;\n\t}\n\n\tstatic @Nullable EntryWriter get(@Nullable EntryWriter entryWriter) throws IOException {\n\t\tif (entryWriter == null || entryWriter.size() != -1) {\n\t\t\treturn entryWriter;\n\t\t}\n\t\treturn new SizeCalculatingEntryWriter(entryWriter);\n\t}\n\n\t/**\n\t * {@link OutputStream} to calculate the size and allow content to be written again.\n\t */\n\tprivate static class SizeCalculatingOutputStream extends OutputStream {\n\n\t\tprivate int size;\n\n\t\tprivate @Nullable File tempFile;\n\n\t\tprivate OutputStream outputStream;\n\n\t\tSizeCalculatingOutputStream() {\n\t\t\tthis.outputStream = new ByteArrayOutputStream();\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(int b) throws IOException {\n\t\t\twrite(new byte[] { (byte) b }, 0, 1);\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(byte[] b, int off, int len) throws IOException {\n\t\t\tint updatedSize = this.size + len;\n\t\t\tif (updatedSize > THRESHOLD && this.outputStream instanceof ByteArrayOutputStream byteArrayOutputStream) {\n\t\t\t\tthis.outputStream = convertToFileOutputStream(byteArrayOutputStream);\n\t\t\t}\n\t\t\tthis.outputStream.write(b, off, len);\n\t\t\tthis.size = updatedSize;\n\t\t}\n\n\t\tprivate OutputStream convertToFileOutputStream(ByteArrayOutputStream byteArrayOutputStream) throws IOException {\n\t\t\tFile tempFile = initializeTempFile();\n\t\t\tFileOutputStream fileOutputStream = new FileOutputStream(tempFile);\n\t\t\tStreamUtils.copy(byteArrayOutputStream.toByteArray(), fileOutputStream);\n\t\t\treturn fileOutputStream;\n\t\t}\n\n\t\tprivate File initializeTempFile() throws IOException {\n\t\t\tif (this.tempFile == null) {\n\t\t\t\tthis.tempFile = File.createTempFile(\"springboot-\", \"-entrycontent\");\n\t\t\t\tthis.tempFile.deleteOnExit();\n\t\t\t}\n\t\t\treturn this.tempFile;\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() throws IOException {\n\t\t\tthis.outputStream.close();\n\t\t}\n\n\t\tObject getContent() {\n\t\t\tObject result = (this.outputStream instanceof ByteArrayOutputStream byteArrayOutputStream)\n\t\t\t\t\t? byteArrayOutputStream.toByteArray() : this.tempFile;\n\t\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\t\treturn result;\n\t\t}\n\n\t\tint getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/StandardLayers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.stream.Stream;\n\n/**\n * Base class for the standard set of {@link Layers}. Defines the following layers:\n * <ol>\n * <li>\"dependencies\" - For non snapshot dependencies</li>\n * <li>\"spring-boot-loader\" - For classes from {@code spring-boot-loader} used to launch a\n * uber jar</li>\n * <li>\"snapshot-dependencies\" - For snapshot dependencies</li>\n * <li>\"application\" - For application classes and resources</li>\n * </ol>\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic abstract class StandardLayers implements Layers {\n\n\t/**\n\t * The dependencies layer.\n\t */\n\tpublic static final Layer DEPENDENCIES = new Layer(\"dependencies\");\n\n\t/**\n\t * The spring boot loader layer.\n\t */\n\tpublic static final Layer SPRING_BOOT_LOADER = new Layer(\"spring-boot-loader\");\n\n\t/**\n\t * The snapshot dependencies layer.\n\t */\n\tpublic static final Layer SNAPSHOT_DEPENDENCIES = new Layer(\"snapshot-dependencies\");\n\n\t/**\n\t * The application layer.\n\t */\n\tpublic static final Layer APPLICATION = new Layer(\"application\");\n\n\tprivate static final List<Layer> LAYERS;\n\tstatic {\n\t\tList<Layer> layers = new ArrayList<>();\n\t\tlayers.add(DEPENDENCIES);\n\t\tlayers.add(SPRING_BOOT_LOADER);\n\t\tlayers.add(SNAPSHOT_DEPENDENCIES);\n\t\tlayers.add(APPLICATION);\n\t\tLAYERS = Collections.unmodifiableList(layers);\n\t}\n\n\t@Override\n\tpublic Iterator<Layer> iterator() {\n\t\treturn LAYERS.iterator();\n\t}\n\n\t@Override\n\tpublic Stream<Layer> stream() {\n\t\treturn LAYERS.stream();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/ZipHeaderPeekInputStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Arrays;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link InputStream} that can peek ahead at zip header bytes.\n *\n * @author Phillip Webb\n */\nclass ZipHeaderPeekInputStream extends FilterInputStream {\n\n\tprivate static final byte[] ZIP_HEADER = new byte[] { 0x50, 0x4b, 0x03, 0x04 };\n\n\tprivate final byte[] header;\n\n\tprivate final int headerLength;\n\n\tprivate int position;\n\n\tprivate @Nullable ByteArrayInputStream headerStream;\n\n\tprotected ZipHeaderPeekInputStream(InputStream in) throws IOException {\n\t\tsuper(in);\n\t\tthis.header = new byte[4];\n\t\tthis.headerLength = in.read(this.header);\n\t\tthis.headerStream = new ByteArrayInputStream(this.header, 0, this.headerLength);\n\t}\n\n\t@Override\n\tpublic int read() throws IOException {\n\t\tint read = (this.headerStream != null) ? this.headerStream.read() : -1;\n\t\tif (read != -1) {\n\t\t\tthis.position++;\n\t\t\tif (this.position >= this.headerLength) {\n\t\t\t\tthis.headerStream = null;\n\t\t\t}\n\t\t\treturn read;\n\t\t}\n\t\treturn super.read();\n\t}\n\n\t@Override\n\tpublic int read(byte[] b) throws IOException {\n\t\treturn read(b, 0, b.length);\n\t}\n\n\t@Override\n\tpublic int read(byte[] b, int off, int len) throws IOException {\n\t\tint read = (this.headerStream != null) ? this.headerStream.read(b, off, len) : -1;\n\t\tif (read <= 0) {\n\t\t\treturn readRemainder(b, off, len);\n\t\t}\n\t\tthis.position += read;\n\t\tif (read < len) {\n\t\t\tint remainderRead = readRemainder(b, off + read, len - read);\n\t\t\tif (remainderRead > 0) {\n\t\t\t\tread += remainderRead;\n\t\t\t}\n\t\t}\n\t\tif (this.position >= this.headerLength) {\n\t\t\tthis.headerStream = null;\n\t\t}\n\t\treturn read;\n\t}\n\n\tboolean hasZipHeader() {\n\t\treturn Arrays.equals(this.header, ZIP_HEADER);\n\t}\n\n\tprivate int readRemainder(byte[] b, int off, int len) throws IOException {\n\t\tint read = super.read(b, off, len);\n\t\tif (read > 0) {\n\t\t\tthis.position += read;\n\t\t}\n\t\treturn read;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/ApplicationContentFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ContentFilter} that matches application items based on an Ant-style path\n * pattern.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class ApplicationContentFilter implements ContentFilter<String> {\n\n\tprivate static final AntPathMatcher MATCHER = new AntPathMatcher();\n\n\tprivate final String pattern;\n\n\tpublic ApplicationContentFilter(String pattern) {\n\t\tAssert.hasText(pattern, \"'pattern' must not be empty\");\n\t\tthis.pattern = pattern;\n\t}\n\n\t@Override\n\tpublic boolean matches(String path) {\n\t\treturn MATCHER.match(this.pattern, path);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/ContentFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\n/**\n * Callback interface that can be used to filter layer contents.\n *\n * @param <T> the content type\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n */\n@FunctionalInterface\npublic interface ContentFilter<T> {\n\n\t/**\n\t * Return if the filter matches the specified item.\n\t * @param item the item to test\n\t * @return if the filter matches\n\t */\n\tboolean matches(T item);\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/ContentSelector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport org.springframework.boot.loader.tools.Layer;\n\n/**\n * Strategy used by {@link CustomLayers} to select the layer of an item.\n *\n * @param <T> the content type\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n * @see IncludeExcludeContentSelector\n */\npublic interface ContentSelector<T> {\n\n\t/**\n\t * Return the {@link Layer} that the selector represents.\n\t * @return the named layer\n\t */\n\tLayer getLayer();\n\n\t/**\n\t * Returns {@code true} if the specified item is contained in this selection.\n\t * @param item the item to test\n\t * @return if the item is contained\n\t */\n\tboolean contains(T item);\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/CustomLayers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.springframework.boot.loader.tools.Layer;\nimport org.springframework.boot.loader.tools.Layers;\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.util.Assert;\n\n/**\n * Custom {@link Layers} implementation where layer content is selected by the user.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class CustomLayers implements Layers {\n\n\tprivate final List<Layer> layers;\n\n\tprivate final List<ContentSelector<String>> applicationSelectors;\n\n\tprivate final List<ContentSelector<Library>> librarySelectors;\n\n\tpublic CustomLayers(List<Layer> layers, List<ContentSelector<String>> applicationSelectors,\n\t\t\tList<ContentSelector<Library>> librarySelectors) {\n\t\tAssert.notNull(layers, \"'layers' must not be null\");\n\t\tAssert.notNull(applicationSelectors, \"'applicationSelectors' must not be null\");\n\t\tvalidateSelectorLayers(applicationSelectors, layers);\n\t\tAssert.notNull(librarySelectors, \"'librarySelectors' must not be null\");\n\t\tvalidateSelectorLayers(librarySelectors, layers);\n\t\tthis.layers = new ArrayList<>(layers);\n\t\tthis.applicationSelectors = new ArrayList<>(applicationSelectors);\n\t\tthis.librarySelectors = new ArrayList<>(librarySelectors);\n\t}\n\n\tprivate static <T> void validateSelectorLayers(List<ContentSelector<T>> selectors, List<Layer> layers) {\n\t\tfor (ContentSelector<?> selector : selectors) {\n\t\t\tvalidateSelectorLayers(selector, layers);\n\t\t}\n\t}\n\n\tprivate static void validateSelectorLayers(ContentSelector<?> selector, List<Layer> layers) {\n\t\tLayer layer = selector.getLayer();\n\t\tAssert.state(layer != null, \"Missing content selector layer\");\n\t\tAssert.state(layers.contains(layer),\n\t\t\t\t() -> \"Content selector layer '\" + selector.getLayer() + \"' not found in \" + layers);\n\t}\n\n\t@Override\n\tpublic Iterator<Layer> iterator() {\n\t\treturn this.layers.iterator();\n\t}\n\n\t@Override\n\tpublic Stream<Layer> stream() {\n\t\treturn this.layers.stream();\n\t}\n\n\t@Override\n\tpublic Layer getLayer(String resourceName) {\n\t\treturn selectLayer(resourceName, this.applicationSelectors, () -> \"Resource '\" + resourceName + \"'\");\n\t}\n\n\t@Override\n\tpublic Layer getLayer(Library library) {\n\t\treturn selectLayer(library, this.librarySelectors, () -> \"Library '\" + library.getName() + \"'\");\n\t}\n\n\tprivate <T> Layer selectLayer(T item, List<ContentSelector<T>> selectors, Supplier<String> name) {\n\t\tfor (ContentSelector<T> selector : selectors) {\n\t\t\tif (selector.contains(item)) {\n\t\t\t\treturn selector.getLayer();\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(name.get() + \" did not match any layer\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/IncludeExcludeContentSelector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.loader.tools.Layer;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ContentSelector} backed by {@code include}/{@code exclude} {@link ContentFilter\n * filters}.\n *\n * @param <T> the content type\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class IncludeExcludeContentSelector<T> implements ContentSelector<T> {\n\n\tprivate final Layer layer;\n\n\tprivate final List<ContentFilter<T>> includes;\n\n\tprivate final List<ContentFilter<T>> excludes;\n\n\tpublic IncludeExcludeContentSelector(Layer layer, @Nullable List<ContentFilter<T>> includes,\n\t\t\t@Nullable List<ContentFilter<T>> excludes) {\n\t\tthis(layer, includes, excludes, Function.identity());\n\t}\n\n\tpublic <S> IncludeExcludeContentSelector(Layer layer, @Nullable List<S> includes, @Nullable List<S> excludes,\n\t\t\tFunction<S, ContentFilter<T>> filterFactory) {\n\t\tAssert.notNull(layer, \"'layer' must not be null\");\n\t\tAssert.notNull(filterFactory, \"'filterFactory' must not be null\");\n\t\tthis.layer = layer;\n\t\tthis.includes = (includes != null) ? adapt(includes, filterFactory) : Collections.emptyList();\n\t\tthis.excludes = (excludes != null) ? adapt(excludes, filterFactory) : Collections.emptyList();\n\t}\n\n\tprivate <S> List<ContentFilter<T>> adapt(List<S> list, Function<S, ContentFilter<T>> mapper) {\n\t\treturn list.stream().map(mapper).toList();\n\t}\n\n\t@Override\n\tpublic Layer getLayer() {\n\t\treturn this.layer;\n\t}\n\n\t@Override\n\tpublic boolean contains(T item) {\n\t\treturn isIncluded(item) && !isExcluded(item);\n\t}\n\n\tprivate boolean isIncluded(T item) {\n\t\tif (this.includes.isEmpty()) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (ContentFilter<T> include : this.includes) {\n\t\t\tif (include.matches(item)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isExcluded(T item) {\n\t\tif (this.excludes.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (ContentFilter<T> exclude : this.excludes) {\n\t\t\tif (exclude.matches(item)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/LibraryContentFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport java.util.regex.Pattern;\n\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ContentFilter} that matches {@link Library} items based on a coordinates\n * pattern.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class LibraryContentFilter implements ContentFilter<Library> {\n\n\tprivate final Pattern pattern;\n\n\tpublic LibraryContentFilter(String coordinatesPattern) {\n\t\tAssert.hasText(coordinatesPattern, \"'coordinatesPattern' must not be empty\");\n\t\tStringBuilder regex = new StringBuilder();\n\t\tfor (int i = 0; i < coordinatesPattern.length(); i++) {\n\t\t\tchar c = coordinatesPattern.charAt(i);\n\t\t\tif (c == '.') {\n\t\t\t\tregex.append(\"\\\\.\");\n\t\t\t}\n\t\t\telse if (c == '*') {\n\t\t\t\tregex.append(\".*\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tregex.append(c);\n\t\t\t}\n\t\t}\n\t\tthis.pattern = Pattern.compile(regex.toString());\n\t}\n\n\t@Override\n\tpublic boolean matches(Library library) {\n\t\treturn this.pattern.matcher(LibraryCoordinates.toStandardNotationString(library.getCoordinates())).matches();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/layer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes used to support layer customization.\n */\n@NullMarked\npackage org.springframework.boot.loader.tools.layer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Tools for generating executable JAR/WAR files.\n */\n@NullMarked\npackage org.springframework.boot.loader.tools;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/AbstractPackagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Calendar;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.jar.Attributes;\nimport java.util.jar.Manifest;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport java.util.zip.Deflater;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.zeroturnaround.zip.ZipUtil;\n\nimport org.springframework.boot.loader.tools.sample.ClassWithMainMethod;\nimport org.springframework.boot.loader.tools.sample.ClassWithoutMainMethod;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Abstract class for {@link Packager} based tests.\n *\n * @param <P> The packager type\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nabstract class AbstractPackagerTests<P extends Packager> {\n\n\tprotected static final Libraries NO_LIBRARIES = (callback) -> {\n\t};\n\n\tprivate static final long JAN_1_1980;\n\tstatic {\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.set(1980, 0, 1, 0, 0, 0);\n\t\tcalendar.set(Calendar.MILLISECOND, 0);\n\t\tJAN_1_1980 = calendar.getTime().getTime();\n\t}\n\n\tprivate static final long JAN_1_1985;\n\tstatic {\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.set(1985, 0, 1, 0, 0, 0);\n\t\tcalendar.set(Calendar.MILLISECOND, 0);\n\t\tJAN_1_1985 = calendar.getTime().getTime();\n\t}\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\tprotected TestJarFile testJarFile;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.testJarFile = new TestJarFile(this.tempDir);\n\t}\n\n\t@Test\n\tvoid specificMainClass() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tP packager = createPackager();\n\t\tpackager.setMainClass(\"a.b.C\");\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Main-Class\"))\n\t\t\t.isEqualTo(\"org.springframework.boot.loader.launch.JarLauncher\");\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Start-Class\")).isEqualTo(\"a.b.C\");\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\tvoid mainClassFromManifest() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(\"Manifest-Version\", \"1.0\");\n\t\tmanifest.getMainAttributes().putValue(\"Main-Class\", \"a.b.C\");\n\t\tthis.testJarFile.addManifest(manifest);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Main-Class\"))\n\t\t\t.isEqualTo(\"org.springframework.boot.loader.launch.JarLauncher\");\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Start-Class\")).isEqualTo(\"a.b.C\");\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\tvoid mainClassFound() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Main-Class\"))\n\t\t\t.isEqualTo(\"org.springframework.boot.loader.launch.JarLauncher\");\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Start-Class\")).isEqualTo(\"a.b.C\");\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\tvoid multipleMainClassFound() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/D.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tassertThatIllegalStateException().isThrownBy(() -> execute(packager, NO_LIBRARIES))\n\t\t\t.withMessageContaining(\"Unable to find a single main class from the following candidates [a.b.C, a.b.D]\");\n\t}\n\n\t@Test\n\tvoid noMainClass() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tP packager = createPackager(this.testJarFile.getFile());\n\t\tassertThatIllegalStateException().isThrownBy(() -> execute(packager, NO_LIBRARIES))\n\t\t\t.withMessageContaining(\"Unable to find main class\");\n\t}\n\n\t@Test\n\tvoid noMainClassAndLayoutIsNone() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tpackager.setLayout(new Layouts.None());\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Main-Class\")).isEqualTo(\"a.b.C\");\n\t\tassertThat(hasPackagedLauncherClasses()).isFalse();\n\t}\n\n\t@Test\n\tvoid noMainClassAndLayoutIsNoneWithNoMain() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tP packager = createPackager();\n\t\tpackager.setLayout(new Layouts.None());\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Main-Class\")).isNull();\n\t\tassertThat(hasPackagedLauncherClasses()).isFalse();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullLibraries() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> execute(packager, null))\n\t\t\t.withMessageContaining(\"'libraries' must not be null\");\n\t}\n\n\t@Test\n\tvoid libraries() throws Exception {\n\t\tTestJarFile libJar = new TestJarFile(this.tempDir);\n\t\tlibJar.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile = libJar.getFile();\n\t\tFile libJarFileToUnpack = libJar.getFile();\n\t\tFile libNonJarFile = new File(this.tempDir, \"non-lib.jar\");\n\t\tFileCopyUtils.copy(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, libNonJarFile);\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addFile(\"BOOT-INF/lib/\" + libJarFileToUnpack.getName(), libJarFileToUnpack);\n\t\tlibJarFile.setLastModified(JAN_1_1980);\n\t\tP packager = createPackager();\n\t\texecute(packager, (callback) -> {\n\t\t\tcallback.library(newLibrary(libJarFile, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libJarFileToUnpack, LibraryScope.COMPILE, true));\n\t\t\tcallback.library(newLibrary(libNonJarFile, LibraryScope.COMPILE, false));\n\t\t});\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/lib/\" + libJarFile.getName())).isTrue();\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/lib/\" + libJarFileToUnpack.getName())).isTrue();\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/lib/\" + libNonJarFile.getName())).isFalse();\n\t\tZipEntry entry = getPackagedEntry(\"BOOT-INF/lib/\" + libJarFile.getName());\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getTime()).isEqualTo(JAN_1_1985);\n\t\tentry = getPackagedEntry(\"BOOT-INF/lib/\" + libJarFileToUnpack.getName());\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getComment()).isEqualTo(\"UNPACK\");\n\t}\n\n\t@Test\n\tvoid classPathIndex() throws Exception {\n\t\tTestJarFile libJar1 = new TestJarFile(this.tempDir);\n\t\tlibJar1.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile1 = libJar1.getFile();\n\t\tTestJarFile libJar2 = new TestJarFile(this.tempDir);\n\t\tlibJar2.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile2 = libJar2.getFile();\n\t\tTestJarFile libJar3 = new TestJarFile(this.tempDir);\n\t\tlibJar3.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile3 = libJar3.getFile();\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tFile file = this.testJarFile.getFile();\n\t\tP packager = createPackager(file);\n\t\tpackager.setIncludeRelevantJarModeJars(false);\n\t\texecute(packager, (callback) -> {\n\t\t\tcallback.library(newLibrary(libJarFile1, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libJarFile2, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libJarFile3, LibraryScope.COMPILE, false));\n\t\t});\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/classpath.idx\")).isTrue();\n\t\tString index = getPackagedEntryContent(\"BOOT-INF/classpath.idx\");\n\t\tassertThat(index).isNotNull();\n\t\tString[] libraries = index.split(\"\\\\r?\\\\n\");\n\t\tList<String> expected = Stream.of(libJarFile1, libJarFile2, libJarFile3)\n\t\t\t.map((jar) -> \"- \\\"BOOT-INF/lib/\" + jar.getName() + \"\\\"\")\n\t\t\t.toList();\n\t\tassertThat(Arrays.asList(libraries)).containsExactlyElementsOf(expected);\n\t}\n\n\t@Test\n\tvoid layersIndex() throws Exception {\n\t\tTestJarFile libJar1 = new TestJarFile(this.tempDir);\n\t\tlibJar1.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile1 = libJar1.getFile();\n\t\tTestJarFile libJar2 = new TestJarFile(this.tempDir);\n\t\tlibJar2.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile2 = libJar2.getFile();\n\t\tTestJarFile libJar3 = new TestJarFile(this.tempDir);\n\t\tlibJar3.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class, JAN_1_1985);\n\t\tFile libJarFile3 = libJar3.getFile();\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tTestLayers layers = new TestLayers();\n\t\tlayers.addLibrary(libJarFile1, \"0001\");\n\t\tlayers.addLibrary(libJarFile2, \"0002\");\n\t\tlayers.addLibrary(libJarFile3, \"0003\");\n\t\tpackager.setLayers(layers);\n\t\tpackager.setIncludeRelevantJarModeJars(false);\n\t\texecute(packager, (callback) -> {\n\t\t\tcallback.library(newLibrary(libJarFile1, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libJarFile2, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libJarFile3, LibraryScope.COMPILE, false));\n\t\t});\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/classpath.idx\")).isTrue();\n\t\tString classpathIndex = getPackagedEntryContent(\"BOOT-INF/classpath.idx\");\n\t\tassertThat(classpathIndex).isNotNull();\n\t\tList<String> expectedClasspathIndex = Stream.of(libJarFile1, libJarFile2, libJarFile3)\n\t\t\t.map((file) -> \"- \\\"BOOT-INF/lib/\" + file.getName() + \"\\\"\")\n\t\t\t.toList();\n\t\tassertThat(Arrays.asList(classpathIndex.split(\"\\\\n\"))).containsExactlyElementsOf(expectedClasspathIndex);\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/layers.idx\")).isTrue();\n\t\tString layersIndex = getPackagedEntryContent(\"BOOT-INF/layers.idx\");\n\t\tassertThat(layersIndex).isNotNull();\n\t\tList<String> expectedLayers = new ArrayList<>();\n\t\texpectedLayers.add(\"- 'default':\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/classes/'\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/classpath.idx'\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/layers.idx'\");\n\t\texpectedLayers.add(\"  - 'META-INF/'\");\n\t\texpectedLayers.add(\"  - 'org/'\");\n\t\texpectedLayers.add(\"- '0001':\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/lib/\" + libJarFile1.getName() + \"'\");\n\t\texpectedLayers.add(\"- '0002':\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/lib/\" + libJarFile2.getName() + \"'\");\n\t\texpectedLayers.add(\"- '0003':\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/lib/\" + libJarFile3.getName() + \"'\");\n\t\tassertThat(layersIndex.split(\"\\\\n\"))\n\t\t\t.containsExactly(expectedLayers.stream().map((s) -> s.replace('\\'', '\"')).toArray(String[]::new));\n\t}\n\n\t@Test\n\tvoid layersEnabledAddJarModeJar() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tTestLayers layers = new TestLayers();\n\t\tpackager.setLayers(layers);\n\t\texecute(packager, Libraries.NONE);\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/classpath.idx\")).isTrue();\n\t\tString classpathIndex = getPackagedEntryContent(\"BOOT-INF/classpath.idx\");\n\t\tassertThat(classpathIndex).isNotNull();\n\t\tassertThat(Arrays.asList(classpathIndex.split(\"\\\\n\")))\n\t\t\t.containsExactly(\"- \\\"BOOT-INF/lib/spring-boot-jarmode-tools.jar\\\"\");\n\t\tassertThat(hasPackagedEntry(\"BOOT-INF/layers.idx\")).isTrue();\n\t\tString layersIndex = getPackagedEntryContent(\"BOOT-INF/layers.idx\");\n\t\tassertThat(layersIndex).isNotNull();\n\t\tList<String> expectedLayers = new ArrayList<>();\n\t\texpectedLayers.add(\"- 'default':\");\n\t\texpectedLayers.add(\"  - 'BOOT-INF/'\");\n\t\texpectedLayers.add(\"  - 'META-INF/'\");\n\t\texpectedLayers.add(\"  - 'org/'\");\n\t\tassertThat(layersIndex.split(\"\\\\n\"))\n\t\t\t.containsExactly(expectedLayers.stream().map((s) -> s.replace('\\'', '\"')).toArray(String[]::new));\n\t}\n\n\t@Test\n\tvoid duplicateLibraries() throws Exception {\n\t\tTestJarFile libJar = new TestJarFile(this.tempDir);\n\t\tlibJar.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile libJarFile = libJar.getFile();\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tassertThatIllegalStateException().isThrownBy(() -> execute(packager, (callback) -> {\n\t\t\tcallback.library(newLibrary(libJarFile, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libJarFile, LibraryScope.COMPILE, false));\n\t\t})).withMessageContaining(\"Duplicate library\");\n\t}\n\n\t@Test\n\tvoid customLayout() throws Exception {\n\t\tTestJarFile libJar = new TestJarFile(this.tempDir);\n\t\tlibJar.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile libJarFile = libJar.getFile();\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tLayout layout = mock(Layout.class);\n\t\tLibraryScope scope = mock(LibraryScope.class);\n\t\tgiven(layout.getLauncherClassName()).willReturn(\"testLauncher\");\n\t\tgiven(layout.getLibraryLocation(anyString(), eq(scope))).willReturn(\"test/\");\n\t\tgiven(layout.getLibraryLocation(anyString(), eq(LibraryScope.COMPILE))).willReturn(\"test-lib/\");\n\t\tpackager.setLayout(layout);\n\t\texecute(packager, (callback) -> callback.library(newLibrary(libJarFile, scope, false)));\n\t\tassertThat(hasPackagedEntry(\"test/\" + libJarFile.getName())).isTrue();\n\t\tManifest manifest = getPackagedManifest();\n\t\tassertThat(manifest).isNotNull();\n\t\tassertThat(manifest.getMainAttributes().getValue(\"Spring-Boot-Lib\")).isEqualTo(\"test-lib/\");\n\t\tassertThat(manifest.getMainAttributes().getValue(\"Main-Class\")).isEqualTo(\"testLauncher\");\n\t}\n\n\t@Test\n\tvoid customLayoutNoBootLib() throws Exception {\n\t\tTestJarFile libJar = new TestJarFile(this.tempDir);\n\t\tlibJar.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile libJarFile = libJar.getFile();\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tLayout layout = mock(Layout.class);\n\t\tLibraryScope scope = mock(LibraryScope.class);\n\t\tgiven(layout.getLauncherClassName()).willReturn(\"testLauncher\");\n\t\tpackager.setLayout(layout);\n\t\texecute(packager, (callback) -> callback.library(newLibrary(libJarFile, scope, false)));\n\t\tManifest manifest = getPackagedManifest();\n\t\tassertThat(manifest).isNotNull();\n\t\tassertThat(manifest.getMainAttributes().getValue(\"Spring-Boot-Lib\")).isNull();\n\t\tassertThat(manifest.getMainAttributes().getValue(\"Main-Class\")).isEqualTo(\"testLauncher\");\n\t}\n\n\t@Test\n\tvoid springBootVersion() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes()).containsKey(new Attributes.Name(\"Spring-Boot-Version\"));\n\t}\n\n\t@Test\n\tvoid executableJarLayoutAttributes() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes()).containsEntry(new Attributes.Name(\"Spring-Boot-Lib\"),\n\t\t\t\t\"BOOT-INF/lib/\");\n\t\tassertThat(actualManifest.getMainAttributes()).containsEntry(new Attributes.Name(\"Spring-Boot-Classes\"),\n\t\t\t\t\"BOOT-INF/classes/\");\n\t}\n\n\t@Test\n\tvoid executableWarLayoutAttributes() throws Exception {\n\t\tthis.testJarFile.addClass(\"WEB-INF/classes/a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager(this.testJarFile.getFile(\"war\"));\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest).isNotNull();\n\t\tassertThat(actualManifest.getMainAttributes()).containsEntry(new Attributes.Name(\"Spring-Boot-Lib\"),\n\t\t\t\t\"WEB-INF/lib/\");\n\t\tassertThat(actualManifest.getMainAttributes()).containsEntry(new Attributes.Name(\"Spring-Boot-Classes\"),\n\t\t\t\t\"WEB-INF/classes/\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullCustomLayout() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tPackager packager = createPackager();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> packager.setLayout(null))\n\t\t\t.withMessageContaining(\"Layout must not be null\");\n\t}\n\n\t@Test\n\tvoid dontRecompressZips() throws Exception {\n\t\tTestJarFile nested = new TestJarFile(this.tempDir);\n\t\tnested.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile nestedFile = nested.getFile();\n\t\tthis.testJarFile.addFile(\"test/nested.jar\", nestedFile);\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, (callback) -> callback.library(newLibrary(nestedFile, LibraryScope.COMPILE, false)));\n\t\tZipEntry entry = getPackagedEntry(\"BOOT-INF/lib/\" + nestedFile.getName());\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getMethod()).isZero();\n\t\tentry = getPackagedEntry(\"BOOT-INF/classes/test/nested.jar\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getMethod()).isZero();\n\t}\n\n\t@Test\n\tvoid unpackLibrariesTakePrecedenceOverExistingSourceEntries() throws Exception {\n\t\tTestJarFile nested = new TestJarFile(this.tempDir);\n\t\tnested.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile nestedFile = nested.getFile();\n\t\tString name = \"BOOT-INF/lib/\" + nestedFile.getName();\n\t\tthis.testJarFile.addFile(name, nested.getFile());\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, (callback) -> callback.library(newLibrary(nestedFile, LibraryScope.COMPILE, true)));\n\t\tZipEntry entry = getPackagedEntry(name);\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getComment()).isEqualTo(\"UNPACK\");\n\t}\n\n\t@Test\n\tvoid existingSourceEntriesTakePrecedenceOverStandardLibraries() throws Exception {\n\t\tTestJarFile nested = new TestJarFile(this.tempDir);\n\t\tnested.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile nestedFile = nested.getFile();\n\t\tthis.testJarFile.addFile(\"BOOT-INF/lib/\" + nestedFile.getName(), nested.getFile());\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tlong sourceLength = nestedFile.length();\n\t\texecute(packager, (callback) -> {\n\t\t\tnestedFile.delete();\n\t\t\tFile toZip = new File(this.tempDir, \"to-zip\");\n\t\t\ttoZip.createNewFile();\n\t\t\tZipUtil.packEntry(toZip, nestedFile);\n\t\t\tcallback.library(newLibrary(nestedFile, LibraryScope.COMPILE, false));\n\t\t});\n\t\tZipEntry entry = getPackagedEntry(\"BOOT-INF/lib/\" + nestedFile.getName());\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getSize()).isEqualTo(sourceLength);\n\t}\n\n\t@Test\n\tvoid metaInfIndexListIsRemovedFromRepackagedJar() throws Exception {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tFile indexList = new File(this.tempDir, \"INDEX.LIST\");\n\t\tindexList.createNewFile();\n\t\tthis.testJarFile.addFile(\"META-INF/INDEX.LIST\", indexList);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"META-INF/INDEX.LIST\")).isNull();\n\t}\n\n\t@Test\n\tvoid customLayoutFactoryWithoutLayout() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tpackager.setLayoutFactory(new TestLayoutFactory());\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"test\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid customLayoutFactoryWithLayout() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tpackager.setLayoutFactory(new TestLayoutFactory());\n\t\tpackager.setLayout(new Layouts.Jar());\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"test\")).isNull();\n\t}\n\n\t@Test\n\tvoid metaInfAopXmlIsMovedBeneathBootInfClassesWhenRepackaged() throws Exception {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tFile aopXml = new File(this.tempDir, \"aop.xml\");\n\t\taopXml.createNewFile();\n\t\tthis.testJarFile.addFile(\"META-INF/aop.xml\", aopXml);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"META-INF/aop.xml\")).isNull();\n\t\tassertThat(getPackagedEntry(\"BOOT-INF/classes/META-INF/aop.xml\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid metaInfServicesFilesAreMovedBeneathBootInfClassesWhenRepackaged() throws Exception {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tFile service = new File(this.tempDir, \"com.example.Service\");\n\t\tservice.createNewFile();\n\t\tthis.testJarFile.addFile(\"META-INF/services/com.example.Service\", service);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"META-INF/services/com.example.Service\")).isNull();\n\t\tassertThat(getPackagedEntry(\"BOOT-INF/classes/META-INF/services/com.example.Service\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid allEntriesUseUnixPlatformAndUtf8NameEncoding() throws IOException {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tfor (ZipArchiveEntry entry : getAllPackagedEntries()) {\n\t\t\tassertThat(entry.getPlatform()).isEqualTo(ZipArchiveEntry.PLATFORM_UNIX);\n\t\t\tassertThat(entry.getGeneralPurposeBit().usesUTF8ForNames()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid loaderIsWrittenFirstThenApplicationClassesThenLibraries() throws IOException {\n\t\tthis.testJarFile.addClass(\"com/example/Application.class\", ClassWithMainMethod.class);\n\t\tFile libraryOne = createLibraryJar();\n\t\tFile libraryTwo = createLibraryJar();\n\t\tFile libraryThree = createLibraryJar();\n\t\tP packager = createPackager();\n\t\texecute(packager, (callback) -> {\n\t\t\tcallback.library(newLibrary(libraryOne, LibraryScope.COMPILE, false));\n\t\t\tcallback.library(newLibrary(libraryTwo, LibraryScope.COMPILE, true));\n\t\t\tcallback.library(newLibrary(libraryThree, LibraryScope.COMPILE, false));\n\t\t});\n\t\tassertThat(getPackagedEntryNames()).containsSubsequence(\"org/springframework/boot/loader/\",\n\t\t\t\t\"BOOT-INF/classes/com/example/Application.class\", \"BOOT-INF/lib/\" + libraryOne.getName(),\n\t\t\t\t\"BOOT-INF/lib/\" + libraryTwo.getName(), \"BOOT-INF/lib/\" + libraryThree.getName());\n\t}\n\n\t@Test\n\tvoid existingEntryThatMatchesUnpackLibraryIsMarkedForUnpack() throws IOException {\n\t\tFile library = createLibraryJar();\n\t\tthis.testJarFile.addClass(\"WEB-INF/classes/com/example/Application.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addFile(\"WEB-INF/lib/\" + library.getName(), library);\n\t\tP packager = createPackager(this.testJarFile.getFile(\"war\"));\n\t\tpackager.setLayout(new Layouts.War());\n\t\texecute(packager, (callback) -> callback.library(newLibrary(library, LibraryScope.COMPILE, true)));\n\t\tassertThat(getPackagedEntryNames()).containsSubsequence(\"org/springframework/boot/loader/\",\n\t\t\t\t\"WEB-INF/classes/com/example/Application.class\", \"WEB-INF/lib/\" + library.getName());\n\t\tZipEntry unpackLibrary = getPackagedEntry(\"WEB-INF/lib/\" + library.getName());\n\t\tassertThat(unpackLibrary).isNotNull();\n\t\tassertThat(unpackLibrary.getComment()).isEqualTo(\"UNPACK\");\n\t}\n\n\t@Test\n\tvoid layoutCanOmitLibraries() throws IOException {\n\t\tTestJarFile libJar = new TestJarFile(this.tempDir);\n\t\tlibJar.addClass(\"a/b/C.class\", ClassWithoutMainMethod.class);\n\t\tFile libJarFile = libJar.getFile();\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tP packager = createPackager();\n\t\tLayout layout = mock(Layout.class);\n\t\tLibraryScope scope = mock(LibraryScope.class);\n\t\tpackager.setLayout(layout);\n\t\texecute(packager, (callback) -> callback.library(newLibrary(libJarFile, scope, false)));\n\t\tassertThat(getPackagedEntryNames()).containsExactly(\"META-INF/\", \"META-INF/MANIFEST.MF\", \"a/\", \"a/b/\",\n\t\t\t\t\"a/b/C.class\");\n\t}\n\n\t@Test\n\tvoid jarThatUsesCustomCompressionConfigurationCanBeRepackaged() throws IOException {\n\t\tFile source = new File(this.tempDir, \"source.jar\");\n\t\tZipOutputStream output = new ZipOutputStream(new FileOutputStream(source)) {\n\t\t\t{\n\t\t\t\tthis.def = new Deflater(Deflater.NO_COMPRESSION, true);\n\t\t\t}\n\t\t};\n\t\tbyte[] data = new byte[1024 * 1024];\n\t\tnew Random().nextBytes(data);\n\t\tZipEntry entry = new ZipEntry(\"entry.dat\");\n\t\toutput.putNextEntry(entry);\n\t\toutput.write(data);\n\t\toutput.closeEntry();\n\t\toutput.close();\n\t\tP packager = createPackager(source);\n\t\tpackager.setMainClass(\"com.example.Main\");\n\t\texecute(packager, NO_LIBRARIES);\n\t}\n\n\t@Test\n\tvoid moduleInfoClassRemainsInRootOfJarWhenRepackaged() throws Exception {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"module-info.class\", ClassWithoutMainMethod.class);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"module-info.class\")).isNotNull();\n\t\tassertThat(getPackagedEntry(\"BOOT-INF/classes/module-info.class\")).isNull();\n\t}\n\n\t@Test\n\tvoid kotlinModuleMetadataMovesBeneathBootInfClassesWhenRepackaged() throws Exception {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tFile kotlinModule = new File(this.tempDir, \"test.kotlin_module\");\n\t\tkotlinModule.createNewFile();\n\t\tthis.testJarFile.addFile(\"META-INF/test.kotlin_module\", kotlinModule);\n\t\tP packager = createPackager();\n\t\texecute(packager, NO_LIBRARIES);\n\t\tassertThat(getPackagedEntry(\"META-INF/test.kotlin_module\")).isNull();\n\t\tassertThat(getPackagedEntry(\"BOOT-INF/classes/META-INF/test.kotlin_module\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid entryFiltering() throws Exception {\n\t\tFile webLibrary = createLibraryJar();\n\t\tFile libraryOne = createLibraryJar();\n\t\tFile libraryTwo = createLibraryJar();\n\t\tthis.testJarFile.addClass(\"WEB-INF/classes/com/example/Application.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addFile(\"WEB-INF/lib/\" + webLibrary.getName(), webLibrary);\n\t\tP packager = createPackager(this.testJarFile.getFile(\"war\"));\n\t\tpackager.setIncludeRelevantJarModeJars(false);\n\t\tpackager.setLayout(new Layouts.War());\n\t\texecute(packager, (callback) -> {\n\t\t\tcallback.library(newLibrary(webLibrary, LibraryScope.COMPILE, false, false));\n\t\t\tcallback.library(newLibrary(libraryOne, LibraryScope.COMPILE, false, false));\n\t\t\tcallback.library(newLibrary(libraryTwo, LibraryScope.COMPILE, false, true));\n\t\t});\n\t\tCollection<String> packagedEntryNames = getPackagedEntryNames();\n\t\tpackagedEntryNames.removeIf((name) -> !name.endsWith(\".jar\"));\n\t\tassertThat(packagedEntryNames).containsExactly(\"WEB-INF/lib/\" + libraryTwo.getName());\n\t}\n\n\t@Test\n\tvoid nativeImageArgFileWithExcludesIsWritten() throws Exception {\n\t\tthis.testJarFile.addClass(\"com/example/Application.class\", ClassWithMainMethod.class);\n\t\tFile libraryOne = createLibraryJar();\n\t\tFile libraryTwo = createLibraryJar();\n\t\tFile libraryThree = createLibraryJar();\n\t\tFile libraryFour = createLibraryJar();\n\t\tthis.testJarFile.addFile(\"META-INF/native-image/com.example.one/lib-one/123/reachability-metadata.properties\",\n\t\t\t\tnew ByteArrayInputStream(\"override=true\\n\".getBytes(StandardCharsets.ISO_8859_1)));\n\t\tthis.testJarFile.addFile(\"META-INF/native-image/com.example.two/lib-two/123/reachability-metadata.properties\",\n\t\t\t\tnew ByteArrayInputStream(\"override=true\\n\".getBytes(StandardCharsets.ISO_8859_1)));\n\t\tthis.testJarFile.addFile(\n\t\t\t\t\"META-INF/native-image/com.example.three/lib-three/123/reachability-metadata.properties\",\n\t\t\t\tnew ByteArrayInputStream(\"other=test\\n\".getBytes(StandardCharsets.ISO_8859_1)));\n\t\tP packager = createPackager(this.testJarFile.getFile());\n\t\texecute(packager, (callback) -> {\n\t\t\tcallback.library(new Library(null, libraryOne, LibraryScope.COMPILE,\n\t\t\t\t\tLibraryCoordinates.of(\"com.example.one\", \"lib-one\", \"123\"), false, false, true));\n\t\t\tcallback.library(new Library(null, libraryTwo, LibraryScope.COMPILE,\n\t\t\t\t\tLibraryCoordinates.of(\"com.example.two\", \"lib-two\", \"123\"), false, false, true));\n\t\t\tcallback.library(new Library(null, libraryThree, LibraryScope.COMPILE,\n\t\t\t\t\tLibraryCoordinates.of(\"com.example.three\", \"lib-three\", \"123\"), false, false, true));\n\t\t\tcallback.library(new Library(null, libraryFour, LibraryScope.COMPILE,\n\t\t\t\t\tLibraryCoordinates.of(\"com.example.four\", \"lib-four\", \"123\"), false, false, true));\n\t\t});\n\n\t\tList<String> expected = new ArrayList<>();\n\t\texpected.add(\"--exclude-config\");\n\t\texpected.add(\"\\\\Q\" + libraryOne.getName() + \"\\\\E\");\n\t\texpected.add(\"^/META-INF/native-image/.*\");\n\t\texpected.add(\"--exclude-config\");\n\t\texpected.add(\"\\\\Q\" + libraryTwo.getName() + \"\\\\E\");\n\t\texpected.add(\"^/META-INF/native-image/.*\");\n\t\tassertThat(getPackagedEntryContent(\"META-INF/native-image/argfile\"))\n\t\t\t.isEqualTo(String.join(\"\\n\", expected) + \"\\n\");\n\t}\n\n\t@Test\n\tvoid sbomManifestEntriesAreWritten() throws IOException {\n\t\tthis.testJarFile.addClass(\"com/example/Application.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addFile(\"META-INF/sbom/application.cdx.json\", new ByteArrayInputStream(new byte[0]));\n\t\tP packager = createPackager(this.testJarFile.getFile());\n\t\texecute(packager, NO_LIBRARIES);\n\t\tManifest manifest = getPackagedManifest();\n\t\tassertThat(manifest).isNotNull();\n\t\tassertThat(manifest.getMainAttributes().getValue(\"Sbom-Format\")).isEqualTo(\"CycloneDX\");\n\t\tassertThat(manifest.getMainAttributes().getValue(\"Sbom-Location\"))\n\t\t\t.isEqualTo(\"META-INF/sbom/application.cdx.json\");\n\t}\n\n\tprivate File createLibraryJar() throws IOException {\n\t\tTestJarFile library = new TestJarFile(this.tempDir);\n\t\tlibrary.addClass(\"com/example/library/Library.class\", ClassWithoutMainMethod.class);\n\t\treturn library.getFile();\n\t}\n\n\tprotected Library newLibrary(File file, LibraryScope scope, boolean unpackRequired) {\n\t\treturn new Library(null, file, scope, null, unpackRequired, false, true);\n\t}\n\n\tprivate Library newLibrary(File file, LibraryScope scope, boolean unpackRequired, boolean included) {\n\t\treturn new Library(null, file, scope, null, unpackRequired, false, included);\n\t}\n\n\tprotected final P createPackager() {\n\t\treturn createPackager(this.testJarFile.getFile());\n\t}\n\n\tprotected abstract P createPackager(File source);\n\n\tprotected abstract void execute(P packager, Libraries libraries) throws IOException;\n\n\tprotected Collection<String> getPackagedEntryNames() throws IOException {\n\t\treturn getAllPackagedEntries().stream()\n\t\t\t.map(ZipArchiveEntry::getName)\n\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t}\n\n\tprotected boolean hasPackagedLauncherClasses() throws IOException {\n\t\treturn hasPackagedEntry(\"org/springframework/boot/\")\n\t\t\t\t&& hasPackagedEntry(\"org/springframework/boot/loader/launch/JarLauncher.class\");\n\t}\n\n\tprotected boolean hasPackagedEntry(String name) throws IOException {\n\t\treturn getPackagedEntry(name) != null;\n\t}\n\n\tprotected @Nullable ZipEntry getPackagedEntry(String name) throws IOException {\n\t\treturn getAllPackagedEntries().stream()\n\t\t\t.filter((entry) -> name.equals(entry.getName()))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\n\t}\n\n\tprotected abstract Collection<ZipArchiveEntry> getAllPackagedEntries() throws IOException;\n\n\tprotected abstract @Nullable Manifest getPackagedManifest() throws IOException;\n\n\tprotected abstract @Nullable String getPackagedEntryContent(String name) throws IOException;\n\n\tstatic class TestLayoutFactory implements LayoutFactory {\n\n\t\t@Override\n\t\tpublic Layout getLayout(File source) {\n\t\t\treturn new TestLayout();\n\t\t}\n\n\t}\n\n\tstatic class TestLayout extends Layouts.Jar implements CustomLoaderLayout {\n\n\t\t@Override\n\t\tpublic void writeLoadedClasses(LoaderClassesWriter writer) throws IOException {\n\t\t\twriter.writeEntry(\"test\", new ByteArrayInputStream(\"test\".getBytes()));\n\t\t}\n\n\t}\n\n\tstatic class TestLayers implements Layers {\n\n\t\tprivate static final Layer DEFAULT_LAYER = new Layer(\"default\");\n\n\t\tprivate final Set<Layer> layers = new LinkedHashSet<>();\n\n\t\tprivate final Map<String, Layer> libraries = new HashMap<>();\n\n\t\tTestLayers() {\n\t\t\tthis.layers.add(DEFAULT_LAYER);\n\t\t}\n\n\t\tvoid addLibrary(File jarFile, String layerName) {\n\t\t\tLayer layer = new Layer(layerName);\n\t\t\tthis.layers.add(layer);\n\t\t\tthis.libraries.put(jarFile.getName(), layer);\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<Layer> iterator() {\n\t\t\treturn this.layers.iterator();\n\t\t}\n\n\t\t@Override\n\t\tpublic Stream<Layer> stream() {\n\t\t\treturn this.layers.stream();\n\t\t}\n\n\t\t@Override\n\t\tpublic Layer getLayer(String name) {\n\t\t\treturn DEFAULT_LAYER;\n\t\t}\n\n\t\t@Override\n\t\tpublic Layer getLayer(Library library) {\n\t\t\tString name = new File(library.getName()).getName();\n\t\t\treturn this.libraries.getOrDefault(name, DEFAULT_LAYER);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/DefaultTimeZoneOffsetTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.util.Calendar;\nimport java.util.TimeZone;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DefaultTimeZoneOffset}\n *\n * @author Phillip Webb\n */\nclass DefaultTimeZoneOffsetTests {\n\n\t// gh-34424\n\n\t@Test\n\tvoid removeFromWithLongInDifferentTimeZonesReturnsSameValue() {\n\t\tlong time = OffsetDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();\n\t\tTimeZone timeZone1 = TimeZone.getTimeZone(\"GMT\");\n\t\tTimeZone timeZone2 = TimeZone.getTimeZone(\"GMT+8\");\n\t\tTimeZone timeZone3 = TimeZone.getTimeZone(\"GMT-8\");\n\t\tlong result1 = new DefaultTimeZoneOffset(timeZone1).removeFrom(time);\n\t\tlong result2 = new DefaultTimeZoneOffset(timeZone2).removeFrom(time);\n\t\tlong result3 = new DefaultTimeZoneOffset(timeZone3).removeFrom(time);\n\t\tlong dosTime1 = toDosTime(Calendar.getInstance(timeZone1), result1);\n\t\tlong dosTime2 = toDosTime(Calendar.getInstance(timeZone2), result2);\n\t\tlong dosTime3 = toDosTime(Calendar.getInstance(timeZone3), result3);\n\t\tassertThat(dosTime1).isEqualTo(dosTime2).isEqualTo(dosTime3);\n\t}\n\n\t@Test\n\tvoid removeFromWithFileTimeReturnsFileTime() {\n\t\tlong time = OffsetDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();\n\t\tlong result = new DefaultTimeZoneOffset(TimeZone.getTimeZone(\"GMT+8\")).removeFrom(time);\n\t\tassertThat(result).isNotEqualTo(time).isEqualTo(946656000000L);\n\t}\n\n\t/**\n\t * Identical functionality to package-private\n\t * org.apache.commons.compress.archivers.zip.ZipUtil.toDosTime(Calendar, long, byte[],\n\t * int) method used by {@link ZipArchiveOutputStream} to convert times.\n\t * @param calendar the source calendar\n\t * @param time the time to convert\n\t * @return the DOS time\n\t */\n\tprivate long toDosTime(Calendar calendar, long time) {\n\t\tcalendar.setTimeInMillis(time);\n\t\tfinal int year = calendar.get(Calendar.YEAR);\n\t\tfinal int month = calendar.get(Calendar.MONTH) + 1;\n\t\treturn ((year - 1980) << 25) | (month << 21) | (calendar.get(Calendar.DAY_OF_MONTH) << 16)\n\t\t\t\t| (calendar.get(Calendar.HOUR_OF_DAY) << 11) | (calendar.get(Calendar.MINUTE) << 5)\n\t\t\t\t| (calendar.get(Calendar.SECOND) >> 1);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/FileUtilsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FileUtils}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\nclass FileUtilsTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\tprivate File outputDirectory;\n\n\tprivate File originDirectory;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.outputDirectory = new File(this.tempDir, \"remove\");\n\t\tthis.originDirectory = new File(this.tempDir, \"keep\");\n\t\tthis.outputDirectory.mkdirs();\n\t\tthis.originDirectory.mkdirs();\n\t}\n\n\t@Test\n\tvoid simpleDuplicateFile() throws IOException {\n\t\tFile file = new File(this.outputDirectory, \"logback.xml\");\n\t\tfile.createNewFile();\n\t\tnew File(this.originDirectory, \"logback.xml\").createNewFile();\n\t\tFileUtils.removeDuplicatesFromOutputDirectory(this.outputDirectory, this.originDirectory);\n\t\tassertThat(file).doesNotExist();\n\t}\n\n\t@Test\n\tvoid nestedDuplicateFile() throws IOException {\n\t\tassertThat(new File(this.outputDirectory, \"sub\").mkdirs()).isTrue();\n\t\tassertThat(new File(this.originDirectory, \"sub\").mkdirs()).isTrue();\n\t\tFile file = new File(this.outputDirectory, \"sub/logback.xml\");\n\t\tfile.createNewFile();\n\t\tnew File(this.originDirectory, \"sub/logback.xml\").createNewFile();\n\t\tFileUtils.removeDuplicatesFromOutputDirectory(this.outputDirectory, this.originDirectory);\n\t\tassertThat(file).doesNotExist();\n\t}\n\n\t@Test\n\tvoid nestedNonDuplicateFile() throws IOException {\n\t\tassertThat(new File(this.outputDirectory, \"sub\").mkdirs()).isTrue();\n\t\tassertThat(new File(this.originDirectory, \"sub\").mkdirs()).isTrue();\n\t\tFile file = new File(this.outputDirectory, \"sub/logback.xml\");\n\t\tfile.createNewFile();\n\t\tnew File(this.originDirectory, \"sub/different.xml\").createNewFile();\n\t\tFileUtils.removeDuplicatesFromOutputDirectory(this.outputDirectory, this.originDirectory);\n\t\tassertThat(file).exists();\n\t}\n\n\t@Test\n\tvoid nonDuplicateFile() throws IOException {\n\t\tFile file = new File(this.outputDirectory, \"logback.xml\");\n\t\tfile.createNewFile();\n\t\tnew File(this.originDirectory, \"different.xml\").createNewFile();\n\t\tFileUtils.removeDuplicatesFromOutputDirectory(this.outputDirectory, this.originDirectory);\n\t\tassertThat(file).exists();\n\t}\n\n\t@Test\n\tvoid isSignedJarFileWhenSignedReturnsTrue() throws IOException {\n\t\tManifest manifest = new Manifest(getClass().getResourceAsStream(\"signed-manifest.mf\"));\n\t\tFile jarFile = new File(this.tempDir, \"test.jar\");\n\t\twriteTestJar(manifest, jarFile);\n\t\tassertThat(FileUtils.isSignedJarFile(jarFile)).isTrue();\n\t}\n\n\t@Test\n\tvoid isSignedJarFileWhenNotSignedReturnsFalse() throws IOException {\n\t\tManifest manifest = new Manifest();\n\t\tFile jarFile = new File(this.tempDir, \"test.jar\");\n\t\twriteTestJar(manifest, jarFile);\n\t\tassertThat(FileUtils.isSignedJarFile(jarFile)).isFalse();\n\t}\n\n\tprivate void writeTestJar(Manifest manifest, File jarFile) throws IOException, FileNotFoundException {\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(jarFile))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"META-INF/MANIFEST.MF\"));\n\t\t\tmanifest.write(out);\n\t\t\tout.closeEntry();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ImagePackagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.jspecify.annotations.Nullable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImagePackager}\n *\n * @author Phillip Webb\n */\nclass ImagePackagerTests extends AbstractPackagerTests<ImagePackager> {\n\n\tprivate @Nullable Map<ZipArchiveEntry, byte[]> entries;\n\n\t@Override\n\tprotected ImagePackager createPackager(File source) {\n\t\treturn new ImagePackager(source, null);\n\t}\n\n\t@Override\n\tprotected void execute(ImagePackager packager, Libraries libraries) throws IOException {\n\t\tthis.entries = new LinkedHashMap<>();\n\t\tpackager.packageImage(libraries, this::save);\n\t}\n\n\tprivate void save(ZipEntry entry, EntryWriter writer) {\n\t\ttry {\n\t\t\tassertThat(this.entries).isNotNull();\n\t\t\tthis.entries.put((ZipArchiveEntry) entry, getContent(writer));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate byte @Nullable [] getContent(@Nullable EntryWriter writer) throws IOException {\n\t\tif (writer == null) {\n\t\t\treturn null;\n\t\t}\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\twriter.write(outputStream);\n\t\treturn outputStream.toByteArray();\n\t}\n\n\t@Override\n\tprotected Collection<ZipArchiveEntry> getAllPackagedEntries() throws IOException {\n\t\tassertThat(this.entries).isNotNull();\n\t\treturn this.entries.keySet();\n\t}\n\n\t@Override\n\tprotected @Nullable Manifest getPackagedManifest() throws IOException {\n\t\tbyte[] bytes = getEntryBytes(\"META-INF/MANIFEST.MF\");\n\t\treturn (bytes != null) ? new Manifest(new ByteArrayInputStream(bytes)) : null;\n\t}\n\n\t@Override\n\tprotected @Nullable String getPackagedEntryContent(String name) throws IOException {\n\t\tbyte[] bytes = getEntryBytes(name);\n\t\treturn (bytes != null) ? new String(bytes, StandardCharsets.UTF_8) : null;\n\t}\n\n\tprivate byte @Nullable [] getEntryBytes(String name) throws IOException {\n\t\tZipEntry entry = getPackagedEntry(name);\n\t\tif (entry == null) {\n\t\t\treturn null;\n\t\t}\n\t\tassertThat(this.entries).isNotNull();\n\t\treturn this.entries.get(entry);\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ImplicitLayerResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ImplicitLayerResolver}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ImplicitLayerResolverTests {\n\n\tprivate final Layers layers = Layers.IMPLICIT;\n\n\t@Test\n\tvoid iteratorReturnsLayers() {\n\t\tassertThat(this.layers).containsExactly(StandardLayers.DEPENDENCIES, StandardLayers.SPRING_BOOT_LOADER,\n\t\t\t\tStandardLayers.SNAPSHOT_DEPENDENCIES, StandardLayers.APPLICATION);\n\t}\n\n\t@Test\n\tvoid getLayerWhenNameInResourceLocationReturnsApplicationLayer() {\n\t\tassertThat(this.layers.getLayer(\"META-INF/resources/logo.gif\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"resources/logo.gif\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"static/logo.gif\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"public/logo.gif\")).isEqualTo(StandardLayers.APPLICATION);\n\t}\n\n\t@Test\n\tvoid getLayerWhenNameIsClassInResourceLocationReturnsApplicationLayer() {\n\t\tassertThat(this.layers.getLayer(\"META-INF/resources/Logo.class\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"resources/Logo.class\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"static/Logo.class\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"public/Logo.class\")).isEqualTo(StandardLayers.APPLICATION);\n\t}\n\n\t@Test\n\tvoid getLayerWhenNameNotInResourceLocationReturnsApplicationLayer() {\n\t\tassertThat(this.layers.getLayer(\"com/example/Application.class\")).isEqualTo(StandardLayers.APPLICATION);\n\t\tassertThat(this.layers.getLayer(\"com/example/application.properties\")).isEqualTo(StandardLayers.APPLICATION);\n\t}\n\n\t@Test\n\tvoid getLayerWhenLoaderClassReturnsLoaderLayer() {\n\t\tassertThat(this.layers.getLayer(\"org/springframework/boot/loader/Launcher.class\"))\n\t\t\t.isEqualTo(StandardLayers.SPRING_BOOT_LOADER);\n\t\tassertThat(this.layers.getLayer(\"org/springframework/boot/loader/Utils.class\"))\n\t\t\t.isEqualTo(StandardLayers.SPRING_BOOT_LOADER);\n\t}\n\n\t@Test\n\tvoid getLayerWhenLibraryIsSnapshotReturnsSnapshotLayer() {\n\t\tassertThat(this.layers.getLayer(mockLibrary(\"spring-boot.2.0.0.BUILD-SNAPSHOT.jar\")))\n\t\t\t.isEqualTo(StandardLayers.SNAPSHOT_DEPENDENCIES);\n\t\tassertThat(this.layers.getLayer(mockLibrary(\"spring-boot.2.0.0-SNAPSHOT.jar\")))\n\t\t\t.isEqualTo(StandardLayers.SNAPSHOT_DEPENDENCIES);\n\t\tassertThat(this.layers.getLayer(mockLibrary(\"spring-boot.2.0.0.SNAPSHOT.jar\")))\n\t\t\t.isEqualTo(StandardLayers.SNAPSHOT_DEPENDENCIES);\n\t}\n\n\t@Test\n\tvoid getLayerWhenLibraryIsNotSnapshotReturnsDependenciesLayer() {\n\t\tassertThat(this.layers.getLayer(mockLibrary(\"spring-boot.2.0.0.jar\"))).isEqualTo(StandardLayers.DEPENDENCIES);\n\t\tassertThat(this.layers.getLayer(mockLibrary(\"spring-boot.2.0.0-classified.jar\")))\n\t\t\t.isEqualTo(StandardLayers.DEPENDENCIES);\n\t}\n\n\tprivate Library mockLibrary(String name) {\n\t\tLibrary library = mock(Library.class);\n\t\tgiven(library.getName()).willReturn(name);\n\t\treturn library;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Layer}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass LayerTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Layer(null)).withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenNameIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Layer(\"\")).withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenNameContainsBadCharsThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Layer(\"bad!name\"))\n\t\t\t.withMessage(\"Malformed layer name 'bad!name'\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tLayer layer1 = new Layer(\"testa\");\n\t\tLayer layer2 = new Layer(\"testa\");\n\t\tLayer layer3 = new Layer(\"testb\");\n\t\tassertThat(layer1).hasSameHashCodeAs(layer2);\n\t\tassertThat(layer1).isEqualTo(layer1).isEqualTo(layer2).isNotEqualTo(layer3);\n\t}\n\n\t@Test\n\tvoid toStringReturnsName() {\n\t\tassertThat(new Layer(\"test\")).hasToString(\"test\");\n\t}\n\n\t@Test\n\tvoid createWhenUsingReservedNameThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Layer(\"ext\"))\n\t\t\t.withMessage(\"Layer name 'ext' is reserved\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Layer(\"ExT\"))\n\t\t\t.withMessage(\"Layer name 'ExT' is reserved\");\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Layer(\"springbootloader\"))\n\t\t\t.withMessage(\"Layer name 'springbootloader' is reserved\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayersIndexTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.assertj.core.api.AbstractObjectAssert;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestInfo;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LayersIndex}.\n *\n * @author Phillip Webb\n */\nclass LayersIndexTests {\n\n\tprivate static final Layer LAYER_A = new Layer(\"a\");\n\n\tprivate static final Layer LAYER_B = new Layer(\"b\");\n\n\tprivate static final Layer LAYER_C = new Layer(\"c\");\n\n\tprivate String testMethodName;\n\n\t@BeforeEach\n\tvoid setup(TestInfo testInfo) {\n\t\tthis.testMethodName = testInfo.getTestMethod().get().getName();\n\t}\n\n\t@Test\n\tvoid writeToWhenSimpleNamesSortsAlphabetically() {\n\t\tLayersIndex index = new LayersIndex(LAYER_A);\n\t\tindex.add(LAYER_A, \"cat\");\n\t\tindex.add(LAYER_A, \"dog\");\n\t\tindex.add(LAYER_A, \"aardvark\");\n\t\tindex.add(LAYER_A, \"zerbra\");\n\t\tindex.add(LAYER_A, \"hamster\");\n\t\tassertThatIndex(index).writesExpectedContent();\n\t}\n\n\t@Test\n\tvoid writeToWritesLayersInIteratorOrder() {\n\t\tLayersIndex index = new LayersIndex(LAYER_B, LAYER_A, LAYER_C);\n\t\tindex.add(LAYER_A, \"a1\");\n\t\tindex.add(LAYER_A, \"a2\");\n\t\tindex.add(LAYER_B, \"b1\");\n\t\tindex.add(LAYER_B, \"b2\");\n\t\tindex.add(LAYER_C, \"c1\");\n\t\tindex.add(LAYER_C, \"c2\");\n\t\tassertThatIndex(index).writesExpectedContent();\n\t}\n\n\t@Test\n\tvoid writeToWhenLayerNotUsedDoesNotSkipLayer() {\n\t\tLayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C);\n\t\tindex.add(LAYER_A, \"a1\");\n\t\tindex.add(LAYER_A, \"a2\");\n\t\tindex.add(LAYER_C, \"c1\");\n\t\tindex.add(LAYER_C, \"c2\");\n\t\tassertThatIndex(index).writesExpectedContent();\n\t}\n\n\t@Test\n\tvoid writeToWhenAllFilesInDirectoryAreInSameLayerUsesDirectory() {\n\t\tLayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C);\n\t\tindex.add(LAYER_A, \"a1/b1/c1\");\n\t\tindex.add(LAYER_A, \"a1/b1/c2\");\n\t\tindex.add(LAYER_A, \"a1/b2/c1\");\n\t\tindex.add(LAYER_B, \"a2/b1\");\n\t\tindex.add(LAYER_B, \"a2/b2\");\n\t\tassertThatIndex(index).writesExpectedContent();\n\t}\n\n\t@Test\n\tvoid writeToWhenAllFilesInDirectoryAreInNotInSameLayerUsesFiles() {\n\t\tLayersIndex index = new LayersIndex(LAYER_A, LAYER_B, LAYER_C);\n\t\tindex.add(LAYER_A, \"a1/b1/c1\");\n\t\tindex.add(LAYER_B, \"a1/b1/c2\");\n\t\tindex.add(LAYER_C, \"a1/b2/c1\");\n\t\tindex.add(LAYER_A, \"a2/b1\");\n\t\tindex.add(LAYER_B, \"a2/b2\");\n\t\tassertThatIndex(index).writesExpectedContent();\n\t}\n\n\t@Test\n\tvoid writeToWhenSpaceInFileName() {\n\t\tLayersIndex index = new LayersIndex(LAYER_A);\n\t\tindex.add(LAYER_A, \"a b\");\n\t\tindex.add(LAYER_A, \"a b/c\");\n\t\tindex.add(LAYER_A, \"a b/d\");\n\t\tassertThatIndex(index).writesExpectedContent();\n\t}\n\n\tprivate LayersIndexAssert assertThatIndex(LayersIndex index) {\n\t\treturn new LayersIndexAssert(index);\n\t}\n\n\tprivate class LayersIndexAssert extends AbstractObjectAssert<LayersIndexAssert, LayersIndex> {\n\n\t\tLayersIndexAssert(LayersIndex actual) {\n\t\t\tsuper(actual, LayersIndexAssert.class);\n\t\t}\n\n\t\tvoid writesExpectedContent() {\n\t\t\ttry {\n\t\t\t\tString actualContent = getContent();\n\t\t\t\tString name = \"LayersIndexTests-\" + LayersIndexTests.this.testMethodName + \".txt\";\n\t\t\t\tInputStream in = LayersIndexTests.class.getResourceAsStream(name);\n\t\t\t\tAssert.state(in != null, () -> \"Can't read \" + name);\n\t\t\t\tString expectedContent = new String(FileCopyUtils.copyToByteArray(in), StandardCharsets.UTF_8);\n\t\t\t\texpectedContent = expectedContent.replace(\"\\r\", \"\");\n\t\t\t\tassertThat(actualContent).isEqualTo(expectedContent);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\n\t\t}\n\n\t\tprivate String getContent() throws IOException {\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tthis.actual.writeTo(out);\n\t\t\treturn out.toString(StandardCharsets.UTF_8);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Layouts}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass LayoutsTests {\n\n\t@Test\n\tvoid jarFile() {\n\t\tassertThat(Layouts.forFile(new File(\"test.jar\"))).isInstanceOf(Layouts.Jar.class);\n\t\tassertThat(Layouts.forFile(new File(\"test.JAR\"))).isInstanceOf(Layouts.Jar.class);\n\t\tassertThat(Layouts.forFile(new File(\"test.jAr\"))).isInstanceOf(Layouts.Jar.class);\n\t\tassertThat(Layouts.forFile(new File(\"te.st.jar\"))).isInstanceOf(Layouts.Jar.class);\n\t}\n\n\t@Test\n\tvoid warFile() {\n\t\tassertThat(Layouts.forFile(new File(\"test.war\"))).isInstanceOf(Layouts.War.class);\n\t\tassertThat(Layouts.forFile(new File(\"test.WAR\"))).isInstanceOf(Layouts.War.class);\n\t\tassertThat(Layouts.forFile(new File(\"test.wAr\"))).isInstanceOf(Layouts.War.class);\n\t\tassertThat(Layouts.forFile(new File(\"te.st.war\"))).isInstanceOf(Layouts.War.class);\n\t}\n\n\t@Test\n\tvoid unknownFile() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> Layouts.forFile(new File(\"test.txt\")))\n\t\t\t.withMessageContaining(\"Unable to deduce layout for 'test.txt'\");\n\t}\n\n\t@Test\n\tvoid jarLayout() {\n\t\tLayout layout = new Layouts.Jar();\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.COMPILE)).isEqualTo(\"BOOT-INF/lib/\");\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.CUSTOM)).isEqualTo(\"BOOT-INF/lib/\");\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.PROVIDED)).isEqualTo(\"BOOT-INF/lib/\");\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.RUNTIME)).isEqualTo(\"BOOT-INF/lib/\");\n\t}\n\n\t@Test\n\tvoid warLayout() {\n\t\tLayout layout = new Layouts.War();\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.COMPILE)).isEqualTo(\"WEB-INF/lib/\");\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.CUSTOM)).isEqualTo(\"WEB-INF/lib/\");\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.PROVIDED)).isEqualTo(\"WEB-INF/lib-provided/\");\n\t\tassertThat(layout.getLibraryLocation(\"lib.jar\", LibraryScope.RUNTIME)).isEqualTo(\"WEB-INF/lib/\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LibraryCoordinatesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LibraryCoordinates}.\n *\n * @author Phillip Webb\n */\nclass LibraryCoordinatesTests {\n\n\t@Test\n\tvoid ofCreateLibraryCoordinates() {\n\t\tLibraryCoordinates coordinates = LibraryCoordinates.of(\"g\", \"a\", \"v\");\n\t\tassertThat(coordinates.getGroupId()).isEqualTo(\"g\");\n\t\tassertThat(coordinates.getArtifactId()).isEqualTo(\"a\");\n\t\tassertThat(coordinates.getVersion()).isEqualTo(\"v\");\n\t\tassertThat(coordinates).hasToString(\"g:a:v\");\n\t}\n\n\t@Test\n\tvoid toStandardNotationStringWhenCoordinatesAreNull() {\n\t\tassertThat(LibraryCoordinates.toStandardNotationString(null)).isEqualTo(\"::\");\n\t}\n\n\t@Test\n\tvoid toStandardNotationStringWhenCoordinatesElementsNull() {\n\t\tassertThat(LibraryCoordinates.toStandardNotationString(mock(LibraryCoordinates.class))).isEqualTo(\"::\");\n\t}\n\n\t@Test\n\tvoid toStandardNotationString() {\n\t\tLibraryCoordinates coordinates = mock(LibraryCoordinates.class);\n\t\tgiven(coordinates.getGroupId()).willReturn(\"a\");\n\t\tgiven(coordinates.getArtifactId()).willReturn(\"b\");\n\t\tgiven(coordinates.getVersion()).willReturn(\"c\");\n\t\tassertThat(LibraryCoordinates.toStandardNotationString(coordinates)).isEqualTo(\"a:b:c\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/MainClassFinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.jar.JarFile;\n\nimport net.bytebuddy.ByteBuddy;\nimport net.bytebuddy.ClassFileVersion;\nimport net.bytebuddy.description.method.MethodDescription;\nimport net.bytebuddy.dynamic.scaffold.InstrumentedType;\nimport net.bytebuddy.implementation.Implementation;\nimport net.bytebuddy.implementation.bytecode.ByteCodeAppender;\nimport net.bytebuddy.jar.asm.MethodVisitor;\nimport net.bytebuddy.jar.asm.Opcodes;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.loader.tools.MainClassFinder.MainClass;\nimport org.springframework.boot.loader.tools.MainClassFinder.MainClassCallback;\nimport org.springframework.boot.loader.tools.sample.AnnotatedClassWithMainMethod;\nimport org.springframework.boot.loader.tools.sample.ClassWithMainMethod;\nimport org.springframework.boot.loader.tools.sample.ClassWithoutMainMethod;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MainClassFinder}.\n *\n * @author Phillip Webb\n */\nclass MainClassFinderTests {\n\n\tprivate TestJarFile testJarFile;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File tempDir) {\n\t\tthis.testJarFile = new TestJarFile(tempDir);\n\t}\n\n\t@Test\n\tvoid findMainClassInJar() throws Exception {\n\t\tthis.testJarFile.addClass(\"B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithoutMainMethod.class);\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tString actual = MainClassFinder.findMainClass(jarFile, \"\");\n\t\t\tassertThat(actual).isEqualTo(\"B\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid findMainClassInJarSubDirectory() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/c/D.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithoutMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/F.class\", ClassWithoutMainMethod.class);\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tString actual = MainClassFinder.findMainClass(jarFile, \"\");\n\t\t\tassertThat(actual).isEqualTo(\"a.b.c.D\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid usesBreadthFirstJarSearch() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithMainMethod.class);\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tString actual = MainClassFinder.findMainClass(jarFile, \"\");\n\t\t\tassertThat(actual).isEqualTo(\"a.B\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid findSingleJarSearch() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithMainMethod.class);\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tassertThatIllegalStateException().isThrownBy(() -> MainClassFinder.findSingleMainClass(jarFile, \"\"))\n\t\t\t\t.withMessageContaining(\n\t\t\t\t\t\t\"Unable to find a single main class from the following candidates [a.B, a.b.c.E]\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid findSingleJarSearchPrefersAnnotatedMainClass() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", AnnotatedClassWithMainMethod.class);\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tString mainClass = MainClassFinder.findSingleMainClass(jarFile, \"\",\n\t\t\t\t\t\"org.springframework.boot.loader.tools.sample.SomeApplication\");\n\t\t\tassertThat(mainClass).isEqualTo(\"a.b.c.E\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid findMainClassInJarSubLocation() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithMainMethod.class);\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tString actual = MainClassFinder.findMainClass(jarFile, \"a/\");\n\t\t\tassertThat(actual).isEqualTo(\"B\");\n\t\t}\n\n\t}\n\n\t@Test\n\tvoid findMainClassInDirectory() throws Exception {\n\t\tthis.testJarFile.addClass(\"B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithoutMainMethod.class);\n\t\tString actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource());\n\t\tassertThat(actual).isEqualTo(\"B\");\n\t}\n\n\t@Test\n\tvoid findMainClassInSubDirectory() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/c/D.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithoutMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/F.class\", ClassWithoutMainMethod.class);\n\t\tString actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource());\n\t\tassertThat(actual).isEqualTo(\"a.b.c.D\");\n\t}\n\n\t@Test\n\tvoid usesBreadthFirstDirectorySearch() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithMainMethod.class);\n\t\tString actual = MainClassFinder.findMainClass(this.testJarFile.getJarSource());\n\t\tassertThat(actual).isEqualTo(\"a.B\");\n\t}\n\n\t@Test\n\tvoid findSingleDirectorySearch() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithMainMethod.class);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> MainClassFinder.findSingleMainClass(this.testJarFile.getJarSource()))\n\t\t\t.withMessageContaining(\"Unable to find a single main class from the following candidates [a.B, a.b.c.E]\");\n\t}\n\n\t@Test\n\tvoid findSingleDirectorySearchPrefersAnnotatedMainClass() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/B.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", AnnotatedClassWithMainMethod.class);\n\t\tString mainClass = MainClassFinder.findSingleMainClass(this.testJarFile.getJarSource(),\n\t\t\t\t\"org.springframework.boot.loader.tools.sample.SomeApplication\");\n\t\tassertThat(mainClass).isEqualTo(\"a.b.c.E\");\n\t}\n\n\t@Test\n\tvoid doWithDirectoryMainMethods() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/c/D.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithoutMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/F.class\", ClassWithoutMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/G.class\", ClassWithMainMethod.class);\n\t\tClassNameCollector callback = new ClassNameCollector();\n\t\tMainClassFinder.doWithMainClasses(this.testJarFile.getJarSource(), callback);\n\t\tassertThat(callback.getClassNames()).hasToString(\"[a.b.G, a.b.c.D]\");\n\t}\n\n\t@Test\n\tvoid doWithJarMainMethods() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/c/D.class\", ClassWithMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/c/E.class\", ClassWithoutMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/F.class\", ClassWithoutMainMethod.class);\n\t\tthis.testJarFile.addClass(\"a/b/G.class\", ClassWithMainMethod.class);\n\t\tClassNameCollector callback = new ClassNameCollector();\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tMainClassFinder.doWithMainClasses(jarFile, null, callback);\n\t\t\tassertThat(callback.getClassNames()).hasToString(\"[a.b.G, a.b.c.D]\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid packagePrivateMainMethod() throws Exception {\n\t\tthis.testJarFile.addFile(\"a/b/c/D.class\", packagePrivateMainMethod(ClassFileVersion.JAVA_V25));\n\t\tClassNameCollector callback = new ClassNameCollector();\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tMainClassFinder.doWithMainClasses(jarFile, null, callback);\n\t\t\tassertThat(callback.getClassNames()).hasToString(\"[a.b.c.D]\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid packagePrivateMainMethodBeforeJava25() throws Exception {\n\t\tthis.testJarFile.addFile(\"a/b/c/D.class\", packagePrivateMainMethod(ClassFileVersion.JAVA_V24));\n\t\tClassNameCollector callback = new ClassNameCollector();\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tMainClassFinder.doWithMainClasses(jarFile, null, callback);\n\t\t\tassertThat(callback.getClassNames()).isEmpty();\n\t\t}\n\t}\n\n\t@Test\n\tvoid parameterlessMainMethod() throws Exception {\n\t\tthis.testJarFile.addFile(\"a/b/c/D.class\", parameterlessMainMethod(ClassFileVersion.JAVA_V25));\n\t\tClassNameCollector callback = new ClassNameCollector();\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tMainClassFinder.doWithMainClasses(jarFile, null, callback);\n\t\t\tassertThat(callback.getClassNames()).hasToString(\"[a.b.c.D]\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid parameterlessMainMethodBeforeJava25() throws Exception {\n\t\tthis.testJarFile.addFile(\"a/b/c/D.class\", parameterlessMainMethod(ClassFileVersion.JAVA_V24));\n\t\tClassNameCollector callback = new ClassNameCollector();\n\t\ttry (JarFile jarFile = this.testJarFile.getJarFile()) {\n\t\t\tMainClassFinder.doWithMainClasses(jarFile, null, callback);\n\t\t\tassertThat(callback.getClassNames()).isEmpty();\n\t\t}\n\t}\n\n\tprivate ByteArrayInputStream packagePrivateMainMethod(ClassFileVersion classFileVersion) {\n\t\tbyte[] bytecode = new ByteBuddy(classFileVersion).subclass(Object.class)\n\t\t\t.defineMethod(\"main\", void.class, Modifier.STATIC)\n\t\t\t.withParameter(String[].class)\n\t\t\t.intercept(new EmptyBodyImplementation())\n\t\t\t.make()\n\t\t\t.getBytes();\n\t\treturn new ByteArrayInputStream(bytecode);\n\t}\n\n\tprivate ByteArrayInputStream parameterlessMainMethod(ClassFileVersion classFileVersion) {\n\t\tbyte[] bytecode = new ByteBuddy(classFileVersion).subclass(Object.class)\n\t\t\t.defineMethod(\"main\", void.class, Modifier.STATIC | Modifier.PUBLIC)\n\t\t\t.intercept(new EmptyBodyImplementation())\n\t\t\t.make()\n\t\t\t.getBytes();\n\t\treturn new ByteArrayInputStream(bytecode);\n\t}\n\n\tstatic class EmptyBodyImplementation implements Implementation {\n\n\t\t@Override\n\t\tpublic InstrumentedType prepare(InstrumentedType instrumentedType) {\n\t\t\treturn instrumentedType;\n\t\t}\n\n\t\t@Override\n\t\tpublic ByteCodeAppender appender(Target implementationTarget) {\n\t\t\treturn new ByteCodeAppender() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Size apply(MethodVisitor methodVisitor, Context implementationContext,\n\t\t\t\t\t\tMethodDescription instrumentedMethod) {\n\t\t\t\t\tmethodVisitor.visitInsn(Opcodes.RETURN);\n\t\t\t\t\treturn Size.ZERO;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class ClassNameCollector implements MainClassCallback<Object> {\n\n\t\tprivate final List<String> classNames = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic @Nullable Object doWith(MainClass mainClass) {\n\t\t\tthis.classNames.add(mainClass.getName());\n\t\t\treturn null;\n\t\t}\n\n\t\tList<String> getClassNames() {\n\t\t\treturn this.classNames;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/NativeImageArgFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for @{link NativeImageArgFile}.\n *\n * @author Moritz Halbritter\n */\nclass NativeImageArgFileTests {\n\n\t@Test\n\tvoid writeIfNecessaryWhenHasExcludesWritesLines() {\n\t\tNativeImageArgFile argFile = new NativeImageArgFile(List.of(\"path/to/dependency-1.jar\", \"dependency-2.jar\"));\n\t\tList<String> lines = new ArrayList<>();\n\t\targFile.writeIfNecessary(lines::addAll);\n\t\tassertThat(lines).containsExactly(\"--exclude-config\", \"\\\\Qdependency-1.jar\\\\E\", \"^/META-INF/native-image/.*\",\n\t\t\t\t\"--exclude-config\", \"\\\\Qdependency-2.jar\\\\E\", \"^/META-INF/native-image/.*\");\n\t}\n\n\t@Test\n\tvoid writeIfNecessaryWhenHasNothingDoesNotCallConsumer() {\n\t\tNativeImageArgFile argFile = new NativeImageArgFile(Collections.emptyList());\n\t\targFile.writeIfNecessary((lines) -> fail(\"Should not be called\"));\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ReachabilityMetadataPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReachabilityMetadataProperties}.\n *\n * @author Moritz Halbritter\n */\nclass ReachabilityMetadataPropertiesTests {\n\n\t@Test\n\tvoid shouldReadFromInputStream() throws IOException {\n\t\tString propertiesContent = \"override=true\\n\";\n\t\tReachabilityMetadataProperties properties = ReachabilityMetadataProperties\n\t\t\t.fromInputStream(new ByteArrayInputStream(propertiesContent.getBytes(StandardCharsets.UTF_8)));\n\t\tassertThat(properties.isOverridden()).isTrue();\n\t}\n\n\t@Test\n\tvoid shouldFormatLocation() {\n\t\tString location = ReachabilityMetadataProperties\n\t\t\t.getLocation(LibraryCoordinates.of(\"group-id\", \"artifact-id\", \"1.0.0\"));\n\t\tassertThat(location)\n\t\t\t.isEqualTo(\"META-INF/native-image/group-id/artifact-id/1.0.0/reachability-metadata.properties\");\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/RepackagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.attribute.FileTime;\nimport java.time.OffsetDateTime;\nimport java.time.ZoneOffset;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.apache.commons.compress.archivers.zip.ZipArchiveEntry;\nimport org.apache.commons.compress.archivers.zip.ZipFile;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.tools.sample.ClassWithMainMethod;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StopWatch;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Repackager}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass RepackagerTests extends AbstractPackagerTests<Repackager> {\n\n\tprivate @Nullable File destination;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullSource() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Repackager(null));\n\t}\n\n\t@Test\n\tvoid missingSource() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Repackager(new File(\"missing\")));\n\t}\n\n\t@Test\n\tvoid directorySource() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Repackager(this.tempDir));\n\t}\n\n\t@Test\n\tvoid jarIsOnlyRepackagedOnce() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), false);\n\t\trepackager.repackage(NO_LIBRARIES);\n\t\trepackager.repackage(NO_LIBRARIES);\n\t\tManifest actualManifest = getPackagedManifest();\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Main-Class\"))\n\t\t\t.isEqualTo(\"org.springframework.boot.loader.launch.JarLauncher\");\n\t\tassertThat(actualManifest.getMainAttributes().getValue(\"Start-Class\")).isEqualTo(\"a.b.C\");\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\tvoid sameSourceAndDestinationWithoutBackup() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tFile file = this.testJarFile.getFile();\n\t\tRepackager repackager = createRepackager(file, false);\n\t\trepackager.setBackupSource(false);\n\t\trepackager.repackage(NO_LIBRARIES);\n\t\tassertThat(new File(file.getParent(), file.getName() + \".original\")).doesNotExist();\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\tvoid sameSourceAndDestinationWithBackup() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tFile file = this.testJarFile.getFile();\n\t\tRepackager repackager = createRepackager(file, false);\n\t\trepackager.repackage(NO_LIBRARIES);\n\t\tassertThat(new File(file.getParent(), file.getName() + \".original\")).exists();\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\tvoid differentDestination() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tFile source = this.testJarFile.getFile();\n\t\tRepackager repackager = createRepackager(source, true);\n\t\texecute(repackager, NO_LIBRARIES);\n\t\tassertThat(new File(source.getParent(), source.getName() + \".original\")).doesNotExist();\n\t\tassertThat(hasLauncherClasses(source)).isFalse();\n\t\tassertThat(hasPackagedLauncherClasses()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullDestination() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), true);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> repackager.repackage(null, NO_LIBRARIES))\n\t\t\t.withMessageContaining(\"Invalid destination\");\n\t}\n\n\t@Test\n\tvoid destinationIsDirectory() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), true);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> repackager.repackage(this.tempDir, NO_LIBRARIES))\n\t\t\t.withMessageContaining(\"Invalid destination\");\n\t}\n\n\t@Test\n\tvoid overwriteDestination() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), true);\n\t\tassertThat(this.destination).isNotNull();\n\t\tthis.destination.createNewFile();\n\t\trepackager.repackage(this.destination, NO_LIBRARIES);\n\t\tassertThat(hasLauncherClasses(this.destination)).isTrue();\n\t}\n\n\t@Test\n\tvoid layoutFactoryGetsOriginalFile() throws Exception {\n\t\tthis.testJarFile.addClass(\"a/b/C.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), false);\n\t\trepackager.setLayoutFactory(new TestLayoutFactory());\n\t\tassertThat(this.destination).isNotNull();\n\t\trepackager.repackage(this.destination, NO_LIBRARIES);\n\t\tassertThat(hasLauncherClasses(this.destination)).isTrue();\n\t}\n\n\t@Test\n\tvoid allLoaderDirectoriesAndFilesUseSameTimestamp() throws IOException {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), true);\n\t\tLong timestamp = null;\n\t\tassertThat(this.destination).isNotNull();\n\t\trepackager.repackage(this.destination, NO_LIBRARIES);\n\t\tfor (ZipArchiveEntry entry : getAllPackagedEntries()) {\n\t\t\tif (entry.getName().startsWith(\"org/springframework/boot/loader\")) {\n\t\t\t\tif (timestamp == null) {\n\t\t\t\t\ttimestamp = entry.getTime();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tassertThat(entry.getTime())\n\t\t\t\t\t\t.withFailMessage(\"Expected time %d to be equal to %d for entry %s\", entry.getTime(), timestamp,\n\t\t\t\t\t\t\t\tentry.getName())\n\t\t\t\t\t\t.isEqualTo(timestamp);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid allEntriesUseProvidedTimestamp() throws IOException {\n\t\tthis.testJarFile.addClass(\"A.class\", ClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), true);\n\t\tlong timestamp = OffsetDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();\n\t\tassertThat(this.destination).isNotNull();\n\t\trepackager.repackage(this.destination, NO_LIBRARIES, FileTime.fromMillis(timestamp));\n\t\tlong offsetTimestamp = DefaultTimeZoneOffset.INSTANCE.removeFrom(timestamp);\n\t\tfor (ZipArchiveEntry entry : getAllPackagedEntries()) {\n\t\t\tassertThat(entry.getTime()).isEqualTo(offsetTimestamp);\n\t\t}\n\t}\n\n\t@Test\n\tvoid repackagingDeeplyNestedPackageIsNotProhibitivelySlow() throws IOException {\n\t\tStopWatch stopWatch = new StopWatch();\n\t\tstopWatch.start();\n\t\tthis.testJarFile.addClass(\"a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/Some.class\",\n\t\t\t\tClassWithMainMethod.class);\n\t\tRepackager repackager = createRepackager(this.testJarFile.getFile(), true);\n\t\tassertThat(this.destination).isNotNull();\n\t\trepackager.repackage(this.destination, NO_LIBRARIES, null);\n\t\tstopWatch.stop();\n\t\tassertThat(stopWatch.getTotalTimeMillis()).isLessThan(5000);\n\t}\n\n\t@Test\n\tvoid signedJar() throws Exception {\n\t\tRepackager packager = createPackager();\n\t\tpackager.setMainClass(\"a.b.C\");\n\t\tManifest manifest = new Manifest();\n\t\tAttributes attributes = new Attributes();\n\t\tattributes.putValue(\"SHA1-Digest\", \"0000\");\n\t\tmanifest.getEntries().put(\"a/b/C.class\", attributes);\n\t\tTestJarFile libJar = new TestJarFile(this.tempDir);\n\t\tlibJar.addManifest(manifest);\n\t\texecute(packager, (callback) -> callback.library(newLibrary(libJar.getFile(), LibraryScope.COMPILE, false)));\n\t\tassertThat(hasPackagedEntry(\"META-INF/BOOT.SF\")).isTrue();\n\t}\n\n\tprivate boolean hasLauncherClasses(File file) throws IOException {\n\t\treturn hasEntry(file, \"org/springframework/boot/\")\n\t\t\t\t&& hasEntry(file, \"org/springframework/boot/loader/launch/JarLauncher.class\");\n\t}\n\n\tprivate boolean hasEntry(File file, String name) throws IOException {\n\t\treturn getEntry(file, name) != null;\n\t}\n\n\tprivate JarEntry getEntry(File file, String name) throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\treturn jarFile.getJarEntry(name);\n\t\t}\n\t}\n\n\t@Override\n\tprotected Repackager createPackager(File source) {\n\t\treturn createRepackager(source, true);\n\t}\n\n\tprivate Repackager createRepackager(File source, boolean differentDest) {\n\t\tString ext = StringUtils.getFilenameExtension(source.getName());\n\t\tthis.destination = differentDest ? new File(this.tempDir, \"dest.\" + ext) : source;\n\t\treturn new Repackager(source);\n\t}\n\n\t@Override\n\tprotected void execute(Repackager packager, Libraries libraries) throws IOException {\n\t\tassertThat(this.destination).isNotNull();\n\t\tpackager.repackage(this.destination, libraries);\n\t}\n\n\t@Override\n\tprotected Collection<ZipArchiveEntry> getAllPackagedEntries() throws IOException {\n\t\tList<ZipArchiveEntry> result = new ArrayList<>();\n\t\ttry (ZipFile zip = ZipFile.builder().setFile(this.destination).get()) {\n\t\t\tEnumeration<ZipArchiveEntry> entries = zip.getEntries();\n\t\t\twhile (entries.hasMoreElements()) {\n\t\t\t\tresult.add(entries.nextElement());\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t@Override\n\tprotected Manifest getPackagedManifest() throws IOException {\n\t\tassertThat(this.destination).isNotNull();\n\t\ttry (JarFile jarFile = new JarFile(this.destination)) {\n\t\t\treturn jarFile.getManifest();\n\t\t}\n\t}\n\n\t@Override\n\tprotected @Nullable String getPackagedEntryContent(String name) throws IOException {\n\t\ttry (ZipFile zip = ZipFile.builder().setFile(this.destination).get()) {\n\t\t\tZipArchiveEntry entry = zip.getEntry(name);\n\t\t\tif (entry == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tbyte[] bytes = FileCopyUtils.copyToByteArray(zip.getInputStream(entry));\n\t\t\treturn new String(bytes, StandardCharsets.UTF_8);\n\t\t}\n\t}\n\n\tstatic class TestLayoutFactory implements LayoutFactory {\n\n\t\t@Override\n\t\tpublic Layout getLayout(File source) {\n\t\t\tassertThat(source.length()).isGreaterThan(0);\n\t\t\treturn new DefaultLayoutFactory().getLayout(source);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/SizeCalculatingEntryWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Random;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SizeCalculatingEntryWriter}.\n *\n * @author Phillip Webb\n */\nclass SizeCalculatingEntryWriterTests {\n\n\t@Test\n\tvoid getWhenWithinThreshold() throws Exception {\n\t\tTestEntryWriter original = new TestEntryWriter(SizeCalculatingEntryWriter.THRESHOLD - 1);\n\t\tEntryWriter writer = SizeCalculatingEntryWriter.get(original);\n\t\tassertThat(writer).isNotNull();\n\t\tassertThat(writer.size()).isEqualTo(original.getBytes().length);\n\t\tassertThat(writeBytes(writer)).isEqualTo(original.getBytes());\n\t\tassertThat(writer).extracting(\"content\").isNotInstanceOf(File.class);\n\t}\n\n\t@Test\n\tvoid getWhenExceedingThreshold() throws Exception {\n\t\tTestEntryWriter original = new TestEntryWriter(SizeCalculatingEntryWriter.THRESHOLD + 1);\n\t\tEntryWriter writer = SizeCalculatingEntryWriter.get(original);\n\t\tassertThat(writer).isNotNull();\n\t\tassertThat(writer.size()).isEqualTo(original.getBytes().length);\n\t\tassertThat(writeBytes(writer)).isEqualTo(original.getBytes());\n\t\tassertThat(writer).extracting(\"content\").isInstanceOf(File.class);\n\t}\n\n\tprivate byte[] writeBytes(EntryWriter writer) throws IOException {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\twriter.write(outputStream);\n\t\toutputStream.close();\n\t\treturn outputStream.toByteArray();\n\t}\n\n\tprivate static class TestEntryWriter implements EntryWriter {\n\n\t\tprivate final byte[] bytes;\n\n\t\tTestEntryWriter(int size) {\n\t\t\tthis.bytes = new byte[size];\n\t\t\tnew Random().nextBytes(this.bytes);\n\t\t}\n\n\t\tbyte[] getBytes() {\n\t\t\treturn this.bytes;\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(OutputStream outputStream) throws IOException {\n\t\t\toutputStream.write(this.bytes);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/TestJarFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.jspecify.annotations.Nullable;\nimport org.zeroturnaround.zip.FileSource;\nimport org.zeroturnaround.zip.ZipEntrySource;\nimport org.zeroturnaround.zip.ZipUtil;\n\n/**\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic class TestJarFile {\n\n\tprivate final byte[] buffer = new byte[4096];\n\n\tprivate final File temporaryDirectory;\n\n\tprivate final File jarSource;\n\n\tprivate final List<ZipEntrySource> entries = new ArrayList<>();\n\n\tpublic TestJarFile(File temporaryDirectory) {\n\t\tthis.temporaryDirectory = temporaryDirectory;\n\t\tthis.jarSource = new File(temporaryDirectory, \"jar-source\");\n\t}\n\n\tpublic void addClass(String filename, Class<?> classToCopy) throws IOException {\n\t\taddClass(filename, classToCopy, null);\n\t}\n\n\tpublic void addClass(String filename, Class<?> classToCopy, @Nullable Long time) throws IOException {\n\t\tFile file = getFilePath(filename);\n\t\tfile.getParentFile().mkdirs();\n\t\tInputStream inputStream = getClass()\n\t\t\t.getResourceAsStream(\"/\" + classToCopy.getName().replace('.', '/') + \".class\");\n\t\tcopyToFile(inputStream, file);\n\t\tif (time != null) {\n\t\t\tfile.setLastModified(time);\n\t\t}\n\t\tthis.entries.add(new FileSource(filename, file));\n\t}\n\n\tpublic void addFile(String filename, File fileToCopy) throws IOException {\n\t\ttry (InputStream inputStream = new FileInputStream(fileToCopy)) {\n\t\t\taddFile(filename, inputStream);\n\t\t}\n\t}\n\n\tpublic void addFile(String filename, InputStream inputStream) throws IOException {\n\t\tFile file = getFilePath(filename);\n\t\tfile.getParentFile().mkdirs();\n\t\tcopyToFile(inputStream, file);\n\t\tthis.entries.add(new FileSource(filename, file));\n\t}\n\n\tpublic void addManifest(Manifest manifest) throws IOException {\n\t\tFile manifestFile = new File(this.jarSource, \"META-INF/MANIFEST.MF\");\n\t\tmanifestFile.getParentFile().mkdirs();\n\t\ttry (OutputStream outputStream = new FileOutputStream(manifestFile)) {\n\t\t\tmanifest.write(outputStream);\n\t\t}\n\t\tthis.entries.add(new FileSource(\"META-INF/MANIFEST.MF\", manifestFile));\n\t}\n\n\tprivate File getFilePath(String filename) {\n\t\tString[] paths = filename.split(\"/\");\n\t\tFile file = this.jarSource;\n\t\tfor (String path : paths) {\n\t\t\tfile = new File(file, path);\n\t\t}\n\t\treturn file;\n\t}\n\n\tprivate void copyToFile(InputStream inputStream, File file) throws IOException {\n\t\ttry (OutputStream outputStream = new FileOutputStream(file)) {\n\t\t\tcopy(inputStream, outputStream);\n\t\t}\n\t}\n\n\tprivate void copy(InputStream in, OutputStream out) throws IOException {\n\t\tint bytesRead;\n\t\twhile ((bytesRead = in.read(this.buffer)) != -1) {\n\t\t\tout.write(this.buffer, 0, bytesRead);\n\t\t}\n\t}\n\n\tpublic JarFile getJarFile() throws IOException {\n\t\treturn new JarFile(getFile());\n\t}\n\n\tpublic File getJarSource() {\n\t\treturn this.jarSource;\n\t}\n\n\tpublic File getFile() {\n\t\treturn getFile(\"jar\");\n\t}\n\n\tpublic File getFile(String extension) {\n\t\tFile file = new File(this.temporaryDirectory, UUID.randomUUID() + \".\" + extension);\n\t\tZipUtil.pack(this.entries.toArray(new ZipEntrySource[0]), file);\n\t\treturn file;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/ZipHeaderPeekInputStreamTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipHeaderPeekInputStream}.\n *\n * @author Andy Wilkinson\n */\nclass ZipHeaderPeekInputStreamTests {\n\n\t@Test\n\tvoid hasZipHeaderReturnsTrueWhenStreamStartsWithZipHeader() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 0x50, 0x4b, 0x03, 0x04, 5, 6 }))) {\n\t\t\tassertThat(in.hasZipHeader()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tvoid hasZipHeaderReturnsFalseWhenStreamDoesNotStartWithZipHeader() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5 }))) {\n\t\t\tassertThat(in.hasZipHeader()).isFalse();\n\t\t}\n\t}\n\n\t@Test\n\tvoid readIndividualBytes() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5 }))) {\n\t\t\tassertThat(in.read()).isZero();\n\t\t\tassertThat(in.read()).isOne();\n\t\t\tassertThat(in.read()).isEqualTo(2);\n\t\t\tassertThat(in.read()).isEqualTo(3);\n\t\t\tassertThat(in.read()).isEqualTo(4);\n\t\t\tassertThat(in.read()).isEqualTo(5);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readMultipleBytes() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5 }))) {\n\t\t\tbyte[] bytes = new byte[3];\n\t\t\tassertThat(in.read(bytes)).isEqualTo(3);\n\t\t\tassertThat(bytes).containsExactly(0, 1, 2);\n\t\t\tassertThat(in.read(bytes)).isEqualTo(3);\n\t\t\tassertThat(bytes).containsExactly(3, 4, 5);\n\t\t\tassertThat(in.read(bytes)).isEqualTo(-1);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readingMoreThanEntireStreamReadsToEndOfStream() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5 }))) {\n\t\t\tbyte[] bytes = new byte[8];\n\t\t\tassertThat(in.read(bytes)).isEqualTo(6);\n\t\t\tassertThat(bytes).containsExactly(0, 1, 2, 3, 4, 5, 0, 0);\n\t\t\tassertThat(in.read(bytes)).isEqualTo(-1);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readOfSomeOfTheHeaderThenMoreThanEntireStreamReadsToEndOfStream() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5 }))) {\n\t\t\tbyte[] bytes = new byte[8];\n\t\t\tassertThat(in.read(bytes, 0, 3)).isEqualTo(3);\n\t\t\tassertThat(bytes).containsExactly(0, 1, 2, 0, 0, 0, 0, 0);\n\t\t\tassertThat(in.read(bytes, 3, 5)).isEqualTo(3);\n\t\t\tassertThat(bytes).containsExactly(0, 1, 2, 3, 4, 5, 0, 0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readMoreThanEntireStreamWhenStreamLengthIsLessThanZipHeaderLength() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(new ByteArrayInputStream(new byte[] { 10 }))) {\n\t\t\tbyte[] bytes = new byte[8];\n\t\t\tassertThat(in.read(bytes)).isOne();\n\t\t\tassertThat(bytes).containsExactly(10, 0, 0, 0, 0, 0, 0, 0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readMoreThanEntireStreamWhenStreamLengthIsSameAsHeaderLength() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(\n\t\t\t\tnew ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }))) {\n\t\t\tbyte[] bytes = new byte[8];\n\t\t\tassertThat(in.read(bytes)).isEqualTo(4);\n\t\t\tassertThat(bytes).containsExactly(1, 2, 3, 4, 0, 0, 0, 0);\n\t\t}\n\t}\n\n\t@Test\n\tvoid readMoreThanEntireStreamWhenStreamLengthIsZero() throws IOException {\n\t\ttry (ZipHeaderPeekInputStream in = new ZipHeaderPeekInputStream(new ByteArrayInputStream(new byte[0]))) {\n\t\t\tbyte[] bytes = new byte[8];\n\t\t\tassertThat(in.read(bytes)).isEqualTo(-1);\n\t\t\tassertThat(bytes).containsExactly(0, 0, 0, 0, 0, 0, 0, 0);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/layer/ApplicationContentFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ApplicationContentFilter}.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ApplicationContentFilterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPatternIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ApplicationContentFilter(null))\n\t\t\t.withMessage(\"'pattern' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenPatternIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ApplicationContentFilter(\"\"))\n\t\t\t.withMessage(\"'pattern' must not be empty\");\n\t}\n\n\t@Test\n\tvoid matchesWhenWildcardPatternMatchesReturnsTrue() {\n\t\tApplicationContentFilter filter = new ApplicationContentFilter(\"META-INF/**\");\n\t\tassertThat(filter.matches(\"META-INF/resources/application.yml\")).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenWildcardPatternDoesNotMatchReturnsFalse() {\n\t\tApplicationContentFilter filter = new ApplicationContentFilter(\"META-INF/**\");\n\t\tassertThat(filter.matches(\"src/main/resources/application.yml\")).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/layer/IncludeExcludeContentSelectorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.tools.Layer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link IncludeExcludeContentSelector}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass IncludeExcludeContentSelectorTests {\n\n\tprivate static final Layer LAYER = new Layer(\"test\");\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenLayerIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new IncludeExcludeContentSelector<>(null, Collections.emptyList(), Collections.emptyList()))\n\t\t\t.withMessage(\"'layer' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenFactoryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new IncludeExcludeContentSelector<>(LAYER, null, null, null))\n\t\t\t.withMessage(\"'filterFactory' must not be null\");\n\t}\n\n\t@Test\n\tvoid getLayerReturnsLayer() {\n\t\tIncludeExcludeContentSelector<?> selector = new IncludeExcludeContentSelector<>(LAYER, null, null);\n\t\tassertThat(selector.getLayer()).isEqualTo(LAYER);\n\t}\n\n\t@Test\n\tvoid containsWhenEmptyIncludesAndEmptyExcludesReturnsTrue() {\n\t\tList<String> includes = Arrays.asList();\n\t\tList<String> excludes = Arrays.asList();\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"A\")).isTrue();\n\t}\n\n\t@Test\n\tvoid containsWhenNullIncludesAndEmptyExcludesReturnsTrue() {\n\t\tList<String> includes = null;\n\t\tList<String> excludes = null;\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"A\")).isTrue();\n\t}\n\n\t@Test\n\tvoid containsWhenEmptyIncludesAndNotExcludedReturnsTrue() {\n\t\tList<String> includes = Arrays.asList();\n\t\tList<String> excludes = Arrays.asList(\"B\");\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"A\")).isTrue();\n\t}\n\n\t@Test\n\tvoid containsWhenEmptyIncludesAndExcludedReturnsFalse() {\n\t\tList<String> includes = Arrays.asList();\n\t\tList<String> excludes = Arrays.asList(\"A\");\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"A\")).isFalse();\n\t}\n\n\t@Test\n\tvoid containsWhenIncludedAndEmptyExcludesReturnsTrue() {\n\t\tList<String> includes = Arrays.asList(\"A\", \"B\");\n\t\tList<String> excludes = Arrays.asList();\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"B\")).isTrue();\n\t}\n\n\t@Test\n\tvoid containsWhenIncludedAndNotExcludedReturnsTrue() {\n\t\tList<String> includes = Arrays.asList(\"A\", \"B\");\n\t\tList<String> excludes = Arrays.asList(\"C\", \"D\");\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"B\")).isTrue();\n\t}\n\n\t@Test\n\tvoid containsWhenIncludedAndExcludedReturnsFalse() {\n\t\tList<String> includes = Arrays.asList(\"A\", \"B\");\n\t\tList<String> excludes = Arrays.asList(\"C\", \"D\");\n\t\tIncludeExcludeContentSelector<String> selector = new IncludeExcludeContentSelector<>(LAYER, includes, excludes,\n\t\t\t\tTestContentsFilter::new);\n\t\tassertThat(selector.contains(\"C\")).isFalse();\n\t}\n\n\t/**\n\t * {@link ContentFilter} used for testing.\n\t */\n\tstatic class TestContentsFilter implements ContentFilter<String> {\n\n\t\tprivate final String match;\n\n\t\tTestContentsFilter(String match) {\n\t\t\tthis.match = match;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matches(String item) {\n\t\t\treturn this.match.equals(item);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/layer/LibraryContentFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.layer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.tools.Library;\nimport org.springframework.boot.loader.tools.LibraryCoordinates;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LibraryContentFilter}.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Phillip Webb\n */\nclass LibraryContentFilterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenCoordinatesPatternIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new LibraryContentFilter(null))\n\t\t\t.withMessage(\"'coordinatesPattern' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenCoordinatesPatternIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new LibraryContentFilter(\"\"))\n\t\t\t.withMessage(\"'coordinatesPattern' must not be empty\");\n\t}\n\n\t@Test\n\tvoid matchesWhenGroupIdIsNullAndToMatchHasWildcardReturnsTrue() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"*:*\");\n\t\tassertThat(filter.matches(mockLibrary(null, null, null))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenArtifactIdIsNullAndToMatchHasWildcardReturnsTrue() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:*\");\n\t\tassertThat(filter.matches(mockLibrary(\"org.acme\", null, null))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenVersionIsNullAndToMatchHasWildcardReturnsTrue() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:something:*\");\n\t\tassertThat(filter.matches(mockLibrary(\"org.acme\", \"something\", null))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenGroupIdDoesNotMatchReturnsFalse() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:*\");\n\t\tassertThat(filter.matches(mockLibrary(\"other.foo\", null, null))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenWhenArtifactIdDoesNotMatchReturnsFalse() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:test:*\");\n\t\tassertThat(filter.matches(mockLibrary(\"org.acme\", \"other\", null))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenArtifactIdMatchesReturnsTrue() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:test:*\");\n\t\tassertThat(filter.matches(mockLibrary(\"org.acme\", \"test\", null))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchesWhenVersionDoesNotMatchReturnsFalse() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:test:*SNAPSHOT\");\n\t\tassertThat(filter.matches(mockLibrary(\"org.acme\", \"test\", \"1.0.0\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchesWhenVersionMatchesReturnsTrue() {\n\t\tLibraryContentFilter filter = new LibraryContentFilter(\"org.acme:test:*SNAPSHOT\");\n\t\tassertThat(filter.matches(mockLibrary(\"org.acme\", \"test\", \"1.0.0-SNAPSHOT\"))).isTrue();\n\t}\n\n\tprivate Library mockLibrary(@Nullable String groupId, @Nullable String artifactId, @Nullable String version) {\n\t\treturn mockLibrary(LibraryCoordinates.of(groupId, artifactId, version));\n\t}\n\n\tprivate Library mockLibrary(LibraryCoordinates coordinates) {\n\t\tLibrary library = mock(Library.class);\n\t\tgiven(library.getCoordinates()).willReturn(coordinates);\n\t\treturn library;\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/sample/AnnotatedClassWithMainMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.sample;\n\n/**\n * Sample annotated class with a main method.\n *\n * @author Andy Wilkinson\n */\n@SomeApplication\npublic class AnnotatedClassWithMainMethod {\n\n\tpublic void run() {\n\t\tSystem.out.println(\"Hello World\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew AnnotatedClassWithMainMethod().run();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/sample/ClassWithMainMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.sample;\n\n/**\n * Sample class with a main method.\n *\n * @author Phillip Webb\n */\npublic class ClassWithMainMethod {\n\n\tpublic void run() {\n\t\tSystem.out.println(\"Hello World\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew ClassWithMainMethod().run();\n\t}\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/sample/ClassWithoutMainMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.sample;\n\n/**\n * Sample class without a main method.\n *\n * @author Phillip Webb\n */\npublic class ClassWithoutMainMethod {\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/sample/SomeApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.tools.sample;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Test annotation for a main application class.\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@interface SomeApplication {\n\n}\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/sample/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sample code for testing Spring Boot's loader tools.\n */\n@NullMarked\npackage org.springframework.boot.loader.tools.sample;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/example.script",
    "content": "FOO=BAR\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-.txt",
    "content": "- \"a\"\n  - \"aardvark\"\n  - \"cat\"\n  - \"dog\"\n  - \"hamster\"\n  - \"zerbra\"\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-writeToWhenAllFilesInDirectoryAreInNotInSameLayerUsesFiles.txt",
    "content": "- \"a\":\n  - \"a1/b1/c1\"\n  - \"a2/b1\"\n- \"b\":\n  - \"a1/b1/c2\"\n  - \"a2/b2\"\n- \"c\":\n  - \"a1/b2/\"\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-writeToWhenAllFilesInDirectoryAreInSameLayerUsesDirectory.txt",
    "content": "- \"a\":\n  - \"a1/\"\n- \"b\":\n  - \"a2/\"\n- \"c\":\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-writeToWhenLayerNotUsedDoesNotSkipLayer.txt",
    "content": "- \"a\":\n  - \"a1\"\n  - \"a2\"\n- \"b\":\n- \"c\":\n  - \"c1\"\n  - \"c2\"\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-writeToWhenSimpleNamesSortsAlphabetically.txt",
    "content": "- \"a\":\n  - \"aardvark\"\n  - \"cat\"\n  - \"dog\"\n  - \"hamster\"\n  - \"zerbra\"\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-writeToWhenSpaceInFileName.txt",
    "content": "- \"a\":\n  - \"a b\"\n  - \"a b/\"\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/LayersIndexTests-writeToWritesLayersInIteratorOrder.txt",
    "content": "- \"b\":\n  - \"b1\"\n  - \"b2\"\n- \"a\":\n  - \"a1\"\n  - \"a2\"\n- \"c\":\n  - \"c1\"\n  - \"c2\"\n"
  },
  {
    "path": "loader/spring-boot-loader-tools/src/test/resources/org/springframework/boot/loader/tools/signed-manifest.mf",
    "content": "Manifest-Version: 1.0\nCreated-By: 1.5.0_08 (Sun Microsystems Inc.)\nSpecification-Version: 1.1\n\nName: org/bouncycastle/pqc/legacy/math/linearalgebra/GoppaCode.class\nSHA-256-Digest: wNhEfeTvNG9ggqKfLjQDDoFoDqeWwGUc47JiL7VqxqU=\n\nName: org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.class\nSHA-256-Digest: nqljr9DNx4nNie4sbkZajVenvd3LdMF3X5s5dmSMToM=\n"
  },
  {
    "path": "module/spring-boot-activemq/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot ActiveMQ\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-jms\"))\n\tapi(\"org.apache.activemq:activemq-client\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-transaction\"))\n\toptional(\"jakarta.transaction:jakarta.transaction-api\")\n\toptional(\"org.apache.activemq:activemq-broker\")\n\toptional(\"org.messaginghub:pooled-jms\") {\n\t\texclude group: \"org.apache.geronimo.specs\", module: \"geronimo-jms_2.0_spec\"\n\t}\n\toptional(\"org.testcontainers:testcontainers-activemq\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/java/org/springframework/boot/activemq/docker/compose/ActiveMQClassicDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ActiveMQClassicDockerComposeConnectionDetailsFactory}.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ActiveMQClassicDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"activemq-classic-compose.yaml\", image = TestImage.ACTIVE_MQ_CLASSIC)\n\tvoid runCreatesConnectionDetails(ActiveMQConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getBrokerUrl()).isNotNull().startsWith(\"tcp://\");\n\t\tassertThat(connectionDetails.getUser()).isEqualTo(\"root\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/java/org/springframework/boot/activemq/docker/compose/ActiveMQDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ActiveMQDockerComposeConnectionDetailsFactory}.\n *\n * @author Stephane Nicoll\n */\nclass ActiveMQDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"activemq-compose.yaml\", image = TestImage.ACTIVE_MQ)\n\tvoid runCreatesConnectionDetails(ActiveMQConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getBrokerUrl()).isNotNull().startsWith(\"tcp://\");\n\t\tassertThat(connectionDetails.getUser()).isEqualTo(\"root\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/java/org/springframework/boot/activemq/testcontainers/ActiveMQClassicContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.activemq.ActiveMQContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ActiveMQClassicContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass ActiveMQClassicContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ActiveMQContainer activemq = TestImage.container(ActiveMQContainer.class);\n\n\t@Autowired\n\tprivate JmsClient jmsClient;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToActiveMQContainer() {\n\t\tthis.jmsClient.destination(\"sample.queue\").send(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@JmsListener(destination = \"sample.queue\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/java/org/springframework/boot/activemq/testcontainers/ActiveMQContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.SymptomaActiveMQContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ActiveMQContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass ActiveMQContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final SymptomaActiveMQContainer activemq = TestImage.container(SymptomaActiveMQContainer.class);\n\n\t@Autowired\n\tprivate JmsClient jmsClient;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToActiveMQContainer() {\n\t\tthis.jmsClient.destination(\"sample.queue\").send(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@JmsListener(destination = \"sample.queue\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/resources/org/springframework/boot/activemq/docker/compose/activemq-classic-compose.yaml",
    "content": "services:\n  activemq:\n    image: '{imageName}'\n    ports:\n      - '61616'\n    environment:\n      ACTIVEMQ_CONNECTION_USER: 'root'\n      ACTIVEMQ_CONNECTION_PASSWORD: 'secret'\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/resources/org/springframework/boot/activemq/docker/compose/activemq-compose.yaml",
    "content": "services:\n  activemq:\n    image: '{imageName}'\n    ports:\n      - '61616'\n    environment:\n      ACTIVEMQ_USERNAME: 'root'\n      ACTIVEMQ_PASSWORD: 'secret'\n"
  },
  {
    "path": "module/spring-boot-activemq/src/dockerTest/resources/org/springframework/boot/activemq/docker/compose/artemis-compose.yaml",
    "content": "services:\n  artemis:\n    image: '{imageName}'\n    ports:\n      - '61616'\n    environment:\n      ARTEMIS_USER: 'root'\n      ARTEMIS_PASSWORD: 'secret'\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties;\nimport org.springframework.boot.jms.autoconfigure.JndiConnectionFactoryAutoConfiguration;\nimport org.springframework.boot.transaction.jta.autoconfigure.JtaAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to integrate with an ActiveMQ\n * broker.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration(before = JmsAutoConfiguration.class,\n\t\tafter = { JndiConnectionFactoryAutoConfiguration.class, JtaAutoConfiguration.class })\n@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })\n@ConditionalOnMissingBean(ConnectionFactory.class)\n@EnableConfigurationProperties({ ActiveMQProperties.class, JmsProperties.class })\n@Import({ ActiveMQXAConnectionFactoryConfiguration.class, ActiveMQConnectionFactoryConfiguration.class })\npublic final class ActiveMQAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tActiveMQConnectionDetails activemqConnectionDetails(ActiveMQProperties properties) {\n\t\treturn new PropertiesActiveMQConnectionDetails(properties);\n\t}\n\n\t/**\n\t * Adapts {@link ActiveMQProperties} to {@link ActiveMQConnectionDetails}.\n\t */\n\tstatic class PropertiesActiveMQConnectionDetails implements ActiveMQConnectionDetails {\n\n\t\tprivate final ActiveMQProperties properties;\n\n\t\tPropertiesActiveMQConnectionDetails(ActiveMQProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn this.properties.determineBrokerUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn this.properties.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to an ActiveMQ service.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic interface ActiveMQConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Broker URL to use.\n\t * @return the url of the broker\n\t */\n\tString getBrokerUrl();\n\n\t/**\n\t * Login user to authenticate to the broker.\n\t * @return the login user to authenticate to the broker or {@code null}\n\t */\n\t@Nullable String getUser();\n\n\t/**\n\t * Login to authenticate against the broker.\n\t * @return the login to authenticate against the broker or {@code null}\n\t */\n\t@Nullable String getPassword();\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQConnectionFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.apache.commons.pool2.PooledObject;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryFactory;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.connection.CachingConnectionFactory;\n\n/**\n * Configuration for ActiveMQ {@link ConnectionFactory}.\n *\n * @author Greg Turnquist\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Aurélien Leboulanger\n * @author Eddú Meléndez\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(ConnectionFactory.class)\nclass ActiveMQConnectionFactoryConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.activemq.pool.enabled\", havingValue = false, matchIfMissing = true)\n\tstatic class SimpleConnectionFactoryConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBooleanProperty(name = \"spring.jms.cache.enabled\", havingValue = false)\n\t\tActiveMQConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,\n\t\t\t\tObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers,\n\t\t\t\tActiveMQConnectionDetails connectionDetails) {\n\t\t\treturn createJmsConnectionFactory(properties, factoryCustomizers, connectionDetails);\n\t\t}\n\n\t\tprivate static ActiveMQConnectionFactory createJmsConnectionFactory(ActiveMQProperties properties,\n\t\t\t\tObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers,\n\t\t\t\tActiveMQConnectionDetails connectionDetails) {\n\t\t\tActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionDetails.getUser(),\n\t\t\t\t\tconnectionDetails.getPassword(), connectionDetails.getBrokerUrl());\n\t\t\tnew ActiveMQConnectionFactoryConfigurer(properties, factoryCustomizers.orderedStream().toList())\n\t\t\t\t.configure(connectionFactory);\n\t\t\treturn connectionFactory;\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(CachingConnectionFactory.class)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.jms.cache.enabled\", matchIfMissing = true)\n\t\tstatic class CachingConnectionFactoryConfiguration {\n\n\t\t\t@Bean\n\t\t\tCachingConnectionFactory jmsConnectionFactory(JmsProperties jmsProperties, ActiveMQProperties properties,\n\t\t\t\t\tObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers,\n\t\t\t\t\tActiveMQConnectionDetails connectionDetails) {\n\t\t\t\tJmsProperties.Cache cacheProperties = jmsProperties.getCache();\n\t\t\t\tCachingConnectionFactory connectionFactory = new CachingConnectionFactory(\n\t\t\t\t\t\tcreateJmsConnectionFactory(properties, factoryCustomizers, connectionDetails));\n\t\t\t\tconnectionFactory.setCacheConsumers(cacheProperties.isConsumers());\n\t\t\t\tconnectionFactory.setCacheProducers(cacheProperties.isProducers());\n\t\t\t\tconnectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());\n\t\t\t\treturn connectionFactory;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class })\n\tstatic class PooledConnectionFactoryConfiguration {\n\n\t\t@Bean(destroyMethod = \"stop\")\n\t\t@ConditionalOnBooleanProperty(\"spring.activemq.pool.enabled\")\n\t\tJmsPoolConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,\n\t\t\t\tObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers,\n\t\t\t\tActiveMQConnectionDetails connectionDetails) {\n\t\t\tActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionDetails.getUser(),\n\t\t\t\t\tconnectionDetails.getPassword(), connectionDetails.getBrokerUrl());\n\t\t\tnew ActiveMQConnectionFactoryConfigurer(properties, factoryCustomizers.orderedStream().toList())\n\t\t\t\t.configure(connectionFactory);\n\t\t\treturn new JmsPoolConnectionFactoryFactory(properties.getPool())\n\t\t\t\t.createPooledConnectionFactory(connectionFactory);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQConnectionFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQProperties.Packages;\nimport org.springframework.util.Assert;\n\n/**\n * Class to configure an {@link ActiveMQConnectionFactory} instance from properties\n * defined in {@link ActiveMQProperties} and any\n * {@link ActiveMQConnectionFactoryCustomizer customizers}.\n *\n * @author Phillip Webb\n * @author Venil Noronha\n * @author Eddú Meléndez\n */\nclass ActiveMQConnectionFactoryConfigurer {\n\n\tprivate final ActiveMQProperties properties;\n\n\tprivate final List<ActiveMQConnectionFactoryCustomizer> factoryCustomizers;\n\n\tActiveMQConnectionFactoryConfigurer(ActiveMQProperties properties,\n\t\t\t@Nullable List<ActiveMQConnectionFactoryCustomizer> factoryCustomizers) {\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tthis.properties = properties;\n\t\tthis.factoryCustomizers = (factoryCustomizers != null) ? factoryCustomizers : Collections.emptyList();\n\t}\n\n\tvoid configure(ActiveMQConnectionFactory factory) {\n\t\tif (this.properties.getCloseTimeout() != null) {\n\t\t\tfactory.setCloseTimeout((int) this.properties.getCloseTimeout().toMillis());\n\t\t}\n\t\tfactory.setNonBlockingRedelivery(this.properties.isNonBlockingRedelivery());\n\t\tif (this.properties.getSendTimeout() != null) {\n\t\t\tfactory.setSendTimeout((int) this.properties.getSendTimeout().toMillis());\n\t\t}\n\t\tPackages packages = this.properties.getPackages();\n\t\tif (packages.getTrustAll() != null) {\n\t\t\tfactory.setTrustAllPackages(packages.getTrustAll());\n\t\t}\n\t\tif (!packages.getTrusted().isEmpty()) {\n\t\t\tfactory.setTrustedPackages(packages.getTrusted());\n\t\t}\n\t\tcustomize(factory);\n\t}\n\n\tprivate void customize(ActiveMQConnectionFactory connectionFactory) {\n\t\tfor (ActiveMQConnectionFactoryCustomizer factoryCustomizer : this.factoryCustomizers) {\n\t\t\tfactoryCustomizer.customize(connectionFactory);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQConnectionFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport org.apache.activemq.ActiveMQConnectionFactory;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link ActiveMQConnectionFactory} to fine-tune its auto-configuration.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ActiveMQConnectionFactoryCustomizer {\n\n\t/**\n\t * Customize the {@link ActiveMQConnectionFactory}.\n\t * @param factory the factory to customize\n\t */\n\tvoid customize(ActiveMQConnectionFactory factory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties;\n\n/**\n * Configuration properties for ActiveMQ.\n *\n * @author Greg Turnquist\n * @author Stephane Nicoll\n * @author Aurélien Leboulanger\n * @author Venil Noronha\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.activemq\")\npublic class ActiveMQProperties {\n\n\tprivate static final String DEFAULT_EMBEDDED_BROKER_URL = \"vm://localhost?broker.persistent=false\";\n\n\tprivate static final String DEFAULT_NETWORK_BROKER_URL = \"tcp://localhost:61616\";\n\n\t/**\n\t * URL of the ActiveMQ broker. Auto-generated by default.\n\t */\n\tprivate @Nullable String brokerUrl;\n\n\t/**\n\t * Login user of the broker.\n\t */\n\tprivate @Nullable String user;\n\n\t/**\n\t * Login password of the broker.\n\t */\n\tprivate @Nullable String password;\n\n\tprivate final Embedded embedded = new Embedded();\n\n\t/**\n\t * Time to wait before considering a close complete.\n\t */\n\tprivate Duration closeTimeout = Duration.ofSeconds(15);\n\n\t/**\n\t * Whether to stop message delivery before re-delivering messages from a rolled back\n\t * transaction. This implies that message order is not preserved when this is enabled.\n\t */\n\tprivate boolean nonBlockingRedelivery;\n\n\t/**\n\t * Time to wait on message sends for a response. Set it to 0 to wait forever.\n\t */\n\tprivate Duration sendTimeout = Duration.ofMillis(0);\n\n\t@NestedConfigurationProperty\n\tprivate final JmsPoolConnectionFactoryProperties pool = new JmsPoolConnectionFactoryProperties();\n\n\tprivate final Packages packages = new Packages();\n\n\tpublic @Nullable String getBrokerUrl() {\n\t\treturn this.brokerUrl;\n\t}\n\n\tpublic void setBrokerUrl(@Nullable String brokerUrl) {\n\t\tthis.brokerUrl = brokerUrl;\n\t}\n\n\tpublic @Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\tpublic void setUser(@Nullable String user) {\n\t\tthis.user = user;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Embedded getEmbedded() {\n\t\treturn this.embedded;\n\t}\n\n\tpublic Duration getCloseTimeout() {\n\t\treturn this.closeTimeout;\n\t}\n\n\tpublic void setCloseTimeout(Duration closeTimeout) {\n\t\tthis.closeTimeout = closeTimeout;\n\t}\n\n\tpublic boolean isNonBlockingRedelivery() {\n\t\treturn this.nonBlockingRedelivery;\n\t}\n\n\tpublic void setNonBlockingRedelivery(boolean nonBlockingRedelivery) {\n\t\tthis.nonBlockingRedelivery = nonBlockingRedelivery;\n\t}\n\n\tpublic Duration getSendTimeout() {\n\t\treturn this.sendTimeout;\n\t}\n\n\tpublic void setSendTimeout(Duration sendTimeout) {\n\t\tthis.sendTimeout = sendTimeout;\n\t}\n\n\tpublic JmsPoolConnectionFactoryProperties getPool() {\n\t\treturn this.pool;\n\t}\n\n\tpublic Packages getPackages() {\n\t\treturn this.packages;\n\t}\n\n\tString determineBrokerUrl() {\n\t\tif (this.brokerUrl != null) {\n\t\t\treturn this.brokerUrl;\n\t\t}\n\t\tif (this.embedded.isEnabled()) {\n\t\t\treturn DEFAULT_EMBEDDED_BROKER_URL;\n\t\t}\n\t\treturn DEFAULT_NETWORK_BROKER_URL;\n\t}\n\n\t/**\n\t * Configuration for an embedded ActiveMQ broker.\n\t */\n\tpublic static class Embedded {\n\n\t\t/**\n\t\t * Whether to enable embedded mode if the ActiveMQ Broker is available.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\tpublic static class Packages {\n\n\t\t/**\n\t\t * Whether to trust all packages.\n\t\t */\n\t\tprivate @Nullable Boolean trustAll;\n\n\t\t/**\n\t\t * List of specific packages to trust (when not trusting all packages).\n\t\t */\n\t\tprivate List<String> trusted = new ArrayList<>();\n\n\t\tpublic @Nullable Boolean getTrustAll() {\n\t\t\treturn this.trustAll;\n\t\t}\n\n\t\tpublic void setTrustAll(@Nullable Boolean trustAll) {\n\t\t\tthis.trustAll = trustAll;\n\t\t}\n\n\t\tpublic List<String> getTrusted() {\n\t\t\treturn this.trusted;\n\t\t}\n\n\t\tpublic void setTrusted(List<String> trusted) {\n\t\t\tthis.trusted = trusted;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/ActiveMQXAConnectionFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.transaction.TransactionManager;\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.apache.activemq.ActiveMQXAConnectionFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.jms.XAConnectionFactoryWrapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Configuration for ActiveMQ XA {@link ConnectionFactory}.\n *\n * @author Phillip Webb\n * @author Aurélien Leboulanger\n * @author Eddú Meléndez\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(TransactionManager.class)\n@ConditionalOnBean(XAConnectionFactoryWrapper.class)\n@ConditionalOnMissingBean(ConnectionFactory.class)\nclass ActiveMQXAConnectionFactoryConfiguration {\n\n\t@Primary\n\t@Bean(name = { \"jmsConnectionFactory\", \"xaJmsConnectionFactory\" })\n\tConnectionFactory jmsConnectionFactory(ActiveMQProperties properties,\n\t\t\tObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers, XAConnectionFactoryWrapper wrapper,\n\t\t\tActiveMQConnectionDetails connectionDetails) throws Exception {\n\t\tActiveMQXAConnectionFactory connectionFactory = new ActiveMQXAConnectionFactory(connectionDetails.getUser(),\n\t\t\t\tconnectionDetails.getPassword(), connectionDetails.getBrokerUrl());\n\t\tnew ActiveMQConnectionFactoryConfigurer(properties, factoryCustomizers.orderedStream().toList())\n\t\t\t.configure(connectionFactory);\n\t\treturn wrapper.wrapConnectionFactory(connectionFactory);\n\t}\n\n\t@Bean\n\t@ConditionalOnBooleanProperty(name = \"spring.activemq.pool.enabled\", havingValue = false, matchIfMissing = true)\n\tActiveMQConnectionFactory nonXaJmsConnectionFactory(ActiveMQProperties properties,\n\t\t\tObjectProvider<ActiveMQConnectionFactoryCustomizer> factoryCustomizers,\n\t\t\tActiveMQConnectionDetails connectionDetails) {\n\t\tActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(connectionDetails.getUser(),\n\t\t\t\tconnectionDetails.getPassword(), connectionDetails.getBrokerUrl());\n\t\tnew ActiveMQConnectionFactoryConfigurer(properties, factoryCustomizers.orderedStream().toList())\n\t\t\t.configure(connectionFactory);\n\t\treturn connectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for ActiveMQ.\n */\n@NullMarked\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/docker/compose/ActiveMQClassicDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link ActiveMQConnectionDetails} for an {@code activemq} service.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ActiveMQClassicDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<ActiveMQConnectionDetails> {\n\n\tprivate static final int ACTIVEMQ_PORT = 61616;\n\n\tprotected ActiveMQClassicDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"apache/activemq-classic\");\n\t}\n\n\t@Override\n\tprotected ActiveMQConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ActiveMQDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link ActiveMQConnectionDetails} backed by an {@code activemq}\n\t * {@link RunningService}.\n\t */\n\tstatic class ActiveMQDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements ActiveMQConnectionDetails {\n\n\t\tprivate final ActiveMQClassicEnvironment environment;\n\n\t\tprivate final String brokerUrl;\n\n\t\tprotected ActiveMQDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new ActiveMQClassicEnvironment(service.env());\n\t\t\tthis.brokerUrl = \"tcp://\" + service.host() + \":\" + service.ports().get(ACTIVEMQ_PORT);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn this.brokerUrl;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn this.environment.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/docker/compose/ActiveMQClassicEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * ActiveMQ environment details.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ActiveMQClassicEnvironment {\n\n\tprivate final @Nullable String user;\n\n\tprivate final @Nullable String password;\n\n\tActiveMQClassicEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.user = env.get(\"ACTIVEMQ_CONNECTION_USER\");\n\t\tthis.password = env.get(\"ACTIVEMQ_CONNECTION_PASSWORD\");\n\t}\n\n\t@Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/docker/compose/ActiveMQDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link ActiveMQConnectionDetails} for an {@code activemq} service.\n *\n * @author Stephane Nicoll\n */\nclass ActiveMQDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<ActiveMQConnectionDetails> {\n\n\tprivate static final int ACTIVEMQ_PORT = 61616;\n\n\tprotected ActiveMQDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"symptoma/activemq\");\n\t}\n\n\t@Override\n\tprotected ActiveMQConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ActiveMQDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link ActiveMQConnectionDetails} backed by an {@code activemq}\n\t * {@link RunningService}.\n\t */\n\tstatic class ActiveMQDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements ActiveMQConnectionDetails {\n\n\t\tprivate final ActiveMQEnvironment environment;\n\n\t\tprivate final String brokerUrl;\n\n\t\tprotected ActiveMQDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new ActiveMQEnvironment(service.env());\n\t\t\tthis.brokerUrl = \"tcp://\" + service.host() + \":\" + service.ports().get(ACTIVEMQ_PORT);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn this.brokerUrl;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn this.environment.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/docker/compose/ActiveMQEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * ActiveMQ environment details.\n *\n * @author Stephane Nicoll\n */\nclass ActiveMQEnvironment {\n\n\tprivate final @Nullable String user;\n\n\tprivate final @Nullable String password;\n\n\tActiveMQEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.user = env.get(\"ACTIVEMQ_USERNAME\");\n\t\tthis.password = env.get(\"ACTIVEMQ_PASSWORD\");\n\t}\n\n\t@Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose ActiveMQ service connections.\n */\n@NullMarked\npackage org.springframework.boot.activemq.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/testcontainers/ActiveMQClassicContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.testcontainers;\n\nimport org.testcontainers.activemq.ActiveMQContainer;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link ActiveMQConnectionDetails} *\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link ActiveMQContainer}.\n *\n * @author Eddú Meléndez\n */\nclass ActiveMQClassicContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<ActiveMQContainer, ActiveMQConnectionDetails> {\n\n\t@Override\n\tprotected ActiveMQConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<ActiveMQContainer> source) {\n\t\treturn new ActiveMQContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class ActiveMQContainerConnectionDetails extends ContainerConnectionDetails<ActiveMQContainer>\n\t\t\timplements ActiveMQConnectionDetails {\n\n\t\tprivate ActiveMQContainerConnectionDetails(ContainerConnectionSource<ActiveMQContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn getContainer().getBrokerUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUser() {\n\t\t\treturn getContainer().getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/testcontainers/ActiveMQContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.testcontainers;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.activemq.autoconfigure.ActiveMQConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link ActiveMQConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer}\n * using the {@code \"symptoma/activemq\"} image.\n *\n * @author Eddú Meléndez\n */\nclass ActiveMQContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, ActiveMQConnectionDetails> {\n\n\tActiveMQContainerConnectionDetailsFactory() {\n\t\tsuper(\"symptoma/activemq\");\n\t}\n\n\t@Override\n\tprotected ActiveMQConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\treturn new ActiveMQContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class ActiveMQContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>\n\t\t\timplements ActiveMQConnectionDetails {\n\n\t\tprivate ActiveMQContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn \"tcp://\" + getContainer().getHost() + \":\" + getContainer().getFirstMappedPort();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn getContainer().getEnvMap().get(\"ACTIVEMQ_USERNAME\");\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn getContainer().getEnvMap().get(\"ACTIVEMQ_PASSWORD\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/java/org/springframework/boot/activemq/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers ActiveMQ service connections.\n */\n@NullMarked\npackage org.springframework.boot.activemq.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.activemq.pool.block-if-full\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to block when a connection is requested and the pool is full. Set it to false to throw a \\\"JMSException\\\" instead.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.activemq.pool.block-if-full-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Blocking period before throwing an exception if the pool is still full.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": \"-1ms\"\n    },\n    {\n      \"name\": \"spring.activemq.pool.create-connection-on-startup\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to create a connection on startup. Can be used to warm up the pool on startup.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.activemq.pool.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether a JmsPoolConnectionFactory should be created, instead of a regular ConnectionFactory.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.activemq.pool.expiry-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Connection expiration timeout.\",\n      \"defaultValue\": \"0ms\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.activemq.pool.idle-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Connection idle timeout.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": \"30s\"\n    },\n    {\n      \"name\": \"spring.activemq.pool.max-connections\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of pooled connections.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": 1\n    },\n    {\n      \"name\": \"spring.activemq.pool.max-sessions-per-connection\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of pooled sessions per connection in the pool.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": 500\n    },\n    {\n      \"name\": \"spring.activemq.pool.maximum-active-session-per-connection\",\n      \"deprecation\": {\n        \"replacement\": \"spring.activemq.pool.max-sessions-per-connection\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.activemq.pool.reconnect-on-exception\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Reset the connection when a \\\"JMSException\\\" occurs.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.activemq.pool.time-between-expiration-check\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Time to sleep between runs of the idle connection eviction thread. When negative, no idle connection eviction thread runs.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": \"-1ms\"\n    },\n    {\n      \"name\": \"spring.activemq.pool.use-anonymous-producers\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use only one anonymous \\\"MessageProducer\\\" instance. Set it to false to create one \\\"MessageProducer\\\" every time one is required.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": true\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-activemq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.activemq.autoconfigure.ActiveMQAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-activemq/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.activemq.docker.compose.ActiveMQClassicDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.activemq.docker.compose.ActiveMQDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.activemq.testcontainers.ActiveMQClassicContainerConnectionDetailsFactory,\\\norg.springframework.boot.activemq.testcontainers.ActiveMQContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-activemq/src/test/java/org/springframework/boot/activemq/autoconfigure/ActiveMQAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.junit.jupiter.api.Test;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.connection.CachingConnectionFactory;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.mockingDetails;\n\n/**\n * Tests for {@link ActiveMQAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Aurélien Leboulanger\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ActiveMQAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class));\n\n\t@Test\n\tvoid brokerIsEmbeddedByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CachingConnectionFactory.class).hasBean(\"jmsConnectionFactory\");\n\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\tConnectionFactory targetConnectionFactory = connectionFactory.getTargetConnectionFactory();\n\t\t\tassertThat(targetConnectionFactory).isInstanceOf(ActiveMQConnectionFactory.class);\n\t\t\tassertThat(((ActiveMQConnectionFactory) targetConnectionFactory).getBrokerURL())\n\t\t\t\t.isEqualTo(\"vm://localhost?broker.persistent=false\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configurationBacksOffWhenCustomConnectionFactoryExists() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConnectionFactoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(mockingDetails(context.getBean(ConnectionFactory.class)).isMock()).isTrue());\n\t}\n\n\t@Test\n\tvoid connectionFactoryIsCachedByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t.hasSingleBean(CachingConnectionFactory.class)\n\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\tassertThat(connectionFactory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);\n\t\t\tassertThat(connectionFactory.isCacheConsumers()).isFalse();\n\t\t\tassertThat(connectionFactory.isCacheProducers()).isTrue();\n\t\t\tassertThat(connectionFactory.getSessionCacheSize()).isEqualTo(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid connectionFactoryCachingCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.cache.consumers=true\", \"spring.jms.cache.producers=false\",\n\t\t\t\t\t\"spring.jms.cache.session-cache-size=10\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(CachingConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t\tassertThat(connectionFactory.isCacheConsumers()).isTrue();\n\t\t\t\tassertThat(connectionFactory.isCacheProducers()).isFalse();\n\t\t\t\tassertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionFactoryCachingCanBeDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.cache.enabled=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(ActiveMQConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tActiveMQConnectionFactory connectionFactory = context.getBean(ActiveMQConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t\tActiveMQConnectionFactory defaultFactory = new ActiveMQConnectionFactory(\n\t\t\t\t\t\t\"vm://localhost?broker.persistent=false\");\n\t\t\t\tassertThat(connectionFactory.getUserName()).isEqualTo(defaultFactory.getUserName());\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(defaultFactory.getPassword());\n\t\t\t\tassertThat(connectionFactory.getCloseTimeout()).isEqualTo(defaultFactory.getCloseTimeout());\n\t\t\t\tassertThat(connectionFactory.isNonBlockingRedelivery())\n\t\t\t\t\t.isEqualTo(defaultFactory.isNonBlockingRedelivery());\n\t\t\t\tassertThat(connectionFactory.getSendTimeout()).isEqualTo(defaultFactory.getSendTimeout());\n\t\t\t\tassertThat(connectionFactory.isTrustAllPackages()).isEqualTo(defaultFactory.isTrustAllPackages());\n\t\t\t\tassertThat(connectionFactory.getTrustedPackages())\n\t\t\t\t\t.containsExactly(StringUtils.toStringArray(defaultFactory.getTrustedPackages()));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customConnectionFactoryIsApplied() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.cache.enabled=false\",\n\t\t\t\t\t\"spring.activemq.brokerUrl=vm://localhost?useJmx=false&broker.persistent=false\",\n\t\t\t\t\t\"spring.activemq.user=foo\", \"spring.activemq.password=bar\", \"spring.activemq.closeTimeout=500\",\n\t\t\t\t\t\"spring.activemq.nonBlockingRedelivery=true\", \"spring.activemq.sendTimeout=1000\",\n\t\t\t\t\t\"spring.activemq.packages.trust-all=false\", \"spring.activemq.packages.trusted=com.example.acme\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(ActiveMQConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tActiveMQConnectionFactory connectionFactory = context.getBean(ActiveMQConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t\tassertThat(connectionFactory.getUserName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(\"bar\");\n\t\t\t\tassertThat(connectionFactory.getCloseTimeout()).isEqualTo(500);\n\t\t\t\tassertThat(connectionFactory.isNonBlockingRedelivery()).isTrue();\n\t\t\t\tassertThat(connectionFactory.getSendTimeout()).isEqualTo(1000);\n\t\t\t\tassertThat(connectionFactory.isTrustAllPackages()).isFalse();\n\t\t\t\tassertThat(connectionFactory.getTrustedPackages()).containsExactly(\"com.example.acme\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultPoolConnectionFactoryIsApplied() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.activemq.pool.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(JmsPoolConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tJmsPoolConnectionFactory connectionFactory = context.getBean(JmsPoolConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t\tJmsPoolConnectionFactory defaultFactory = new JmsPoolConnectionFactory();\n\t\t\t\tassertThat(connectionFactory.isBlockIfSessionPoolIsFull())\n\t\t\t\t\t.isEqualTo(defaultFactory.isBlockIfSessionPoolIsFull());\n\t\t\t\tassertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout())\n\t\t\t\t\t.isEqualTo(defaultFactory.getBlockIfSessionPoolIsFullTimeout());\n\t\t\t\tassertThat(connectionFactory.getConnectionIdleTimeout())\n\t\t\t\t\t.isEqualTo(defaultFactory.getConnectionIdleTimeout());\n\t\t\t\tassertThat(connectionFactory.getMaxConnections()).isEqualTo(defaultFactory.getMaxConnections());\n\t\t\t\tassertThat(connectionFactory.getMaxSessionsPerConnection())\n\t\t\t\t\t.isEqualTo(defaultFactory.getMaxSessionsPerConnection());\n\t\t\t\tassertThat(connectionFactory.getConnectionCheckInterval())\n\t\t\t\t\t.isEqualTo(defaultFactory.getConnectionCheckInterval());\n\t\t\t\tassertThat(connectionFactory.isUseAnonymousProducers())\n\t\t\t\t\t.isEqualTo(defaultFactory.isUseAnonymousProducers());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customPoolConnectionFactoryIsApplied() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.activemq.pool.enabled=true\", \"spring.activemq.pool.blockIfFull=false\",\n\t\t\t\t\t\"spring.activemq.pool.blockIfFullTimeout=64\", \"spring.activemq.pool.idleTimeout=512\",\n\t\t\t\t\t\"spring.activemq.pool.maxConnections=256\", \"spring.activemq.pool.maxSessionsPerConnection=1024\",\n\t\t\t\t\t\"spring.activemq.pool.timeBetweenExpirationCheck=2048\",\n\t\t\t\t\t\"spring.activemq.pool.useAnonymousProducers=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(JmsPoolConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tJmsPoolConnectionFactory connectionFactory = context.getBean(JmsPoolConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t\tassertThat(connectionFactory.isBlockIfSessionPoolIsFull()).isFalse();\n\t\t\t\tassertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()).isEqualTo(64);\n\t\t\t\tassertThat(connectionFactory.getConnectionIdleTimeout()).isEqualTo(512);\n\t\t\t\tassertThat(connectionFactory.getMaxConnections()).isEqualTo(256);\n\t\t\t\tassertThat(connectionFactory.getMaxSessionsPerConnection()).isEqualTo(1024);\n\t\t\t\tassertThat(connectionFactory.getConnectionCheckInterval()).isEqualTo(2048);\n\t\t\t\tassertThat(connectionFactory.isUseAnonymousProducers()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid poolConnectionFactoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.activemq.pool.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(JmsPoolConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tConnectionFactory factory = context.getBean(ConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(factory);\n\t\t\t\tassertThat(factory).isInstanceOf(JmsPoolConnectionFactory.class);\n\t\t\t\tcontext.getSourceApplicationContext().close();\n\t\t\t\tassertThat(factory.createConnection()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cachingConnectionFactoryNotOnTheClasspathThenSimpleConnectionFactoryAutoConfigured() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(CachingConnectionFactory.class))\n\t\t\t.withPropertyValues(\"spring.activemq.pool.enabled=false\", \"spring.jms.cache.enabled=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(ActiveMQConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tActiveMQConnectionFactory connectionFactory = context.getBean(ActiveMQConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cachingConnectionFactoryNotOnTheClasspathAndCacheEnabledThenSimpleConnectionFactoryNotConfigured() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(CachingConnectionFactory.class))\n\t\t\t.withPropertyValues(\"spring.activemq.pool.enabled=false\", \"spring.jms.cache.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactory.class)\n\t\t\t\t.doesNotHaveBean(ActiveMQConnectionFactory.class)\n\t\t\t\t.doesNotHaveBean(\"jmsConnectionFactory\"));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context)\n\t\t\t.hasSingleBean(ActiveMQAutoConfiguration.PropertiesActiveMQConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(CachingConnectionFactory.class))\n\t\t\t.withPropertyValues(\"spring.activemq.pool.enabled=false\", \"spring.jms.cache.enabled=false\")\n\t\t\t.withUserConfiguration(TestConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ActiveMQConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(ActiveMQAutoConfiguration.PropertiesActiveMQConnectionDetails.class);\n\t\t\t\tActiveMQConnectionFactory connectionFactory = context.getBean(ActiveMQConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getBrokerURL()).isEqualTo(\"tcp://localhost:12345\");\n\t\t\t\tassertThat(connectionFactory.getUserName()).isEqualTo(\"springuser\");\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(\"spring\");\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConnectionFactoryConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactory() {\n\t\t\treturn mock(ConnectionFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tActiveMQConnectionFactoryCustomizer activeMQConnectionFactoryCustomizer() {\n\t\t\treturn (factory) -> {\n\t\t\t\tfactory.setBrokerURL(\"vm://localhost?useJmx=false&broker.persistent=false\");\n\t\t\t\tfactory.setUserName(\"foobar\");\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tActiveMQConnectionDetails activemqConnectionDetails() {\n\t\t\treturn new ActiveMQConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getBrokerUrl() {\n\t\t\t\t\treturn \"tcp://localhost:12345\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUser() {\n\t\t\t\t\treturn \"springuser\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"spring\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/test/java/org/springframework/boot/activemq/autoconfigure/ActiveMQPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.autoconfigure;\n\nimport org.apache.activemq.ActiveMQConnectionFactory;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ActiveMQProperties} and {@link ActiveMQConnectionFactoryConfigurer}.\n *\n * @author Stephane Nicoll\n * @author Aurélien Leboulanger\n * @author Venil Noronha\n * @author Eddú Meléndez\n */\nclass ActiveMQPropertiesTests {\n\n\tprivate static final String DEFAULT_EMBEDDED_BROKER_URL = \"vm://localhost?broker.persistent=false\";\n\n\tprivate static final String DEFAULT_NETWORK_BROKER_URL = \"tcp://localhost:61616\";\n\n\tprivate final ActiveMQProperties properties = new ActiveMQProperties();\n\n\t@Test\n\tvoid getBrokerUrlIsEmbeddedByDefault() {\n\t\tassertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_EMBEDDED_BROKER_URL);\n\t}\n\n\t@Test\n\tvoid getBrokerUrlUseExplicitBrokerUrl() {\n\t\tthis.properties.setBrokerUrl(\"tcp://activemq.example.com:71717\");\n\t\tassertThat(this.properties.determineBrokerUrl()).isEqualTo(\"tcp://activemq.example.com:71717\");\n\t}\n\n\t@Test\n\tvoid getBrokerUrlWithEmbeddedSetToFalse() {\n\t\tthis.properties.getEmbedded().setEnabled(false);\n\t\tassertThat(this.properties.determineBrokerUrl()).isEqualTo(DEFAULT_NETWORK_BROKER_URL);\n\t}\n\n\t@Test\n\tvoid getExplicitBrokerUrlAlwaysWins() {\n\t\tthis.properties.setBrokerUrl(\"tcp://activemq.example.com:71717\");\n\t\tthis.properties.getEmbedded().setEnabled(false);\n\t\tassertThat(this.properties.determineBrokerUrl()).isEqualTo(\"tcp://activemq.example.com:71717\");\n\t}\n\n\t@Test\n\tvoid setTrustAllPackages() {\n\t\tActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();\n\t\tthis.properties.getPackages().setTrustAll(true);\n\t\tnew ActiveMQConnectionFactoryConfigurer(this.properties, null).configure(factory);\n\t\tassertThat(factory.isTrustAllPackages()).isTrue();\n\t}\n\n\t@Test\n\tvoid setTrustedPackages() {\n\t\tActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();\n\t\tthis.properties.getPackages().setTrustAll(false);\n\t\tthis.properties.getPackages().getTrusted().add(\"trusted.package\");\n\t\tnew ActiveMQConnectionFactoryConfigurer(this.properties, null).configure(factory);\n\t\tassertThat(factory.isTrustAllPackages()).isFalse();\n\t\tassertThat(factory.getTrustedPackages()).hasSize(1);\n\t\tassertThat(factory.getTrustedPackages().get(0)).isEqualTo(\"trusted.package\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/test/java/org/springframework/boot/activemq/docker/compose/ActiveMQClassicEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ActiveMQClassicEnvironment}.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass ActiveMQClassicEnvironmentTests {\n\n\t@Test\n\tvoid getUserWhenHasNoActiveMqUser() {\n\t\tActiveMQClassicEnvironment environment = new ActiveMQClassicEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getUser()).isNull();\n\t}\n\n\t@Test\n\tvoid getUserWhenHasActiveMqUser() {\n\t\tActiveMQClassicEnvironment environment = new ActiveMQClassicEnvironment(\n\t\t\t\tMap.of(\"ACTIVEMQ_CONNECTION_USER\", \"me\"));\n\t\tassertThat(environment.getUser()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoActiveMqPassword() {\n\t\tActiveMQClassicEnvironment environment = new ActiveMQClassicEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasActiveMqPassword() {\n\t\tActiveMQClassicEnvironment environment = new ActiveMQClassicEnvironment(\n\t\t\t\tMap.of(\"ACTIVEMQ_CONNECTION_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/test/java/org/springframework/boot/activemq/docker/compose/ActiveMQEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.activemq.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ActiveMQEnvironment}.\n *\n * @author Stephane Nicoll\n */\nclass ActiveMQEnvironmentTests {\n\n\t@Test\n\tvoid getUserWhenHasNoActiveMqUser() {\n\t\tActiveMQEnvironment environment = new ActiveMQEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getUser()).isNull();\n\t}\n\n\t@Test\n\tvoid getUserWhenHasActiveMqUser() {\n\t\tActiveMQEnvironment environment = new ActiveMQEnvironment(Map.of(\"ACTIVEMQ_USERNAME\", \"me\"));\n\t\tassertThat(environment.getUser()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoActiveMqPassword() {\n\t\tActiveMQEnvironment environment = new ActiveMQEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasActiveMqPassword() {\n\t\tActiveMQEnvironment environment = new ActiveMQEnvironment(Map.of(\"ACTIVEMQ_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-activemq/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-actuator/README.adoc",
    "content": "= Spring Boot - Actuator\n\nSpring Boot Actuator includes a number of additional features to help you monitor and\nmanage your application when it's pushed to production. You can choose to manage and\nmonitor your application using HTTP or JMX endpoints. Auditing, health and metrics\ngathering can be automatically applied to your application. The\nhttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready[user guide]\ncovers the features in more detail.\n\n\n\n== Enabling the Actuator\n\nThe recommended way to enable the features is to add a dependency to the\n`spring-boot-starter-actuator` '`Starter`'. To add the actuator to a Maven-based project,\nadd the following '`Starter`' dependency:\n\n[source,xml]\n----\n<dependencies>\n\t<dependency>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-actuator</artifactId>\n\t</dependency>\n</dependencies>\n----\n\nFor Gradle, use the following declaration:\n\n[source]\n----\ndependencies {\n\timplementation 'org.springframework.boot:spring-boot-starter-actuator'\n}\n----\n\n\n\n== Features\n\n* **Endpoints** Actuator endpoints allow you to monitor and interact with your\n  application. Spring Boot includes a number of built-in endpoints and you can also add\n  your own. For example the `health` endpoint provides basic application health\n  information. Run up a basic application and look at `/actuator/health`.\n* **Metrics** Spring Boot Actuator provides dimensional metrics by integrating with\n  https://micrometer.io[Micrometer].\n* **Audit** Spring Boot Actuator has a flexible audit framework that will publish events\n  to an `AuditEventRepository`. Once Spring Security is in play it automatically publishes\n  authentication events by default. This can be very useful for reporting, and also to\n  implement a lock-out policy based on authentication failures.\n"
  },
  {
    "path": "module/spring-boot-actuator/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Actuator\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\")\n\toptional(\"com.github.ben-manes.caffeine:caffeine\")\n\toptional(\"com.google.code.findbugs:jsr305\")\n\toptional(\"com.zaxxer:HikariCP\")\n\toptional(\"io.lettuce:lettuce-core\")\n\toptional(\"io.micrometer:micrometer-observation\")\n\toptional(\"io.micrometer:micrometer-jakarta9\")\n\toptional(\"io.micrometer:micrometer-tracing\")\n\toptional(\"io.micrometer:micrometer-registry-prometheus\")\n\toptional(\"io.micrometer:micrometer-registry-prometheus-simpleclient\")\n\toptional(\"io.prometheus:prometheus-metrics-exposition-formats\")\n\toptional(\"io.prometheus:prometheus-metrics-exporter-pushgateway\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"javax.cache:cache-api\")\n\toptional(\"org.aspectj:aspectjweaver\")\n\toptional(\"org.eclipse.angus:angus-mail\")\n\toptional(\"org.hibernate.validator:hibernate-validator\")\n\toptional(\"org.influxdb:influxdb-java\")\n\toptional(\"org.springframework:spring-context-support\")\n\toptional(\"org.springframework:spring-jdbc\")\n\toptional(\"org.springframework:spring-messaging\")\n\toptional(\"org.springframework.graphql:spring-graphql\")\n\toptional(\"org.springframework.security:spring-security-core\")\n\toptional(\"org.springframework.security:spring-security-web\")\n\toptional(\"tools.jackson.core:jackson-databind\")\n\n\ttestFixturesImplementation(project(\":module:spring-boot-web-server\"))\n\ttestFixturesImplementation(\"org.junit.jupiter:junit-jupiter-api\")\n\ttestFixturesImplementation(\"org.springframework:spring-test\")\n\ttestFixturesImplementation(\"org.springframework:spring-webflux\")\n\n\ttestImplementation(project(\":core:spring-boot-autoconfigure\"))\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-jsonb\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"net.minidev:json-smart\")\n\ttestImplementation(\"org.apache.logging.log4j:log4j-to-slf4j\")\n\n\ttestRuntimeOnly(project(\":module:spring-boot-http-codec\"))\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestRuntimeOnly(\"jakarta.xml.bind:jakarta.xml.bind-api\")\n\ttestRuntimeOnly(\"org.apache.tomcat.embed:tomcat-embed-el\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/AuditEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.io.Serializable;\nimport java.time.Instant;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\nimport org.springframework.util.Assert;\n\n/**\n * A value object representing an audit event: at a particular time, a particular user or\n * agent carried out an action of a particular type. This object records the details of\n * such an event.\n * <p>\n * Users can inject a {@link AuditEventRepository} to publish their own events or\n * alternatively use Spring's {@link ApplicationEventPublisher} (usually obtained by\n * implementing {@link ApplicationEventPublisherAware}) to publish AuditApplicationEvents\n * (wrappers for AuditEvent).\n *\n * @author Dave Syer\n * @since 1.0.0\n * @see AuditEventRepository\n */\n@JsonInclude(Include.NON_EMPTY)\npublic class AuditEvent implements Serializable {\n\n\tprivate final Instant timestamp;\n\n\tprivate final String principal;\n\n\tprivate final String type;\n\n\tprivate final Map<String, @Nullable Object> data;\n\n\t/**\n\t * Create a new audit event for the current time.\n\t * @param principal the user principal responsible\n\t * @param type the event type\n\t * @param data the event data\n\t */\n\tpublic AuditEvent(@Nullable String principal, String type, Map<String, @Nullable Object> data) {\n\t\tthis(Instant.now(), principal, type, data);\n\t}\n\n\t/**\n\t * Create a new audit event for the current time from data provided as name-value\n\t * pairs.\n\t * @param principal the user principal responsible\n\t * @param type the event type\n\t * @param data the event data in the form 'key=value' or simply 'key'\n\t */\n\tpublic AuditEvent(@Nullable String principal, String type, String... data) {\n\t\tthis(Instant.now(), principal, type, convert(data));\n\t}\n\n\t/**\n\t * Create a new audit event.\n\t * @param timestamp the date/time of the event\n\t * @param principal the user principal responsible\n\t * @param type the event type\n\t * @param data the event data\n\t */\n\tpublic AuditEvent(Instant timestamp, @Nullable String principal, String type, Map<String, @Nullable Object> data) {\n\t\tAssert.notNull(timestamp, \"'timestamp' must not be null\");\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tthis.timestamp = timestamp;\n\t\tthis.principal = (principal != null) ? principal : \"\";\n\t\tthis.type = type;\n\t\tthis.data = Collections.unmodifiableMap(data);\n\t}\n\n\tprivate static Map<String, @Nullable Object> convert(String[] data) {\n\t\tMap<String, @Nullable Object> result = new HashMap<>();\n\t\tfor (String entry : data) {\n\t\t\tint index = entry.indexOf('=');\n\t\t\tif (index != -1) {\n\t\t\t\tresult.put(entry.substring(0, index), entry.substring(index + 1));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresult.put(entry, null);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns the date/time that the event was logged.\n\t * @return the timestamp\n\t */\n\tpublic Instant getTimestamp() {\n\t\treturn this.timestamp;\n\t}\n\n\t/**\n\t * Returns the user principal responsible for the event or an empty String if the\n\t * principal is not available.\n\t * @return the principal\n\t */\n\tpublic String getPrincipal() {\n\t\treturn this.principal;\n\t}\n\n\t/**\n\t * Returns the type of event.\n\t * @return the event type\n\t */\n\tpublic String getType() {\n\t\treturn this.type;\n\t}\n\n\t/**\n\t * Returns the event data.\n\t * @return the event data\n\t */\n\tpublic Map<String, @Nullable Object> getData() {\n\t\treturn this.data;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"AuditEvent [timestamp=\" + this.timestamp + \", principal=\" + this.principal + \", type=\" + this.type\n\t\t\t\t+ \", data=\" + this.data + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/AuditEventRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.time.Instant;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Repository for {@link AuditEvent}s.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @since 1.0.0\n */\npublic interface AuditEventRepository {\n\n\t/**\n\t * Log an event.\n\t * @param event the audit event to log\n\t */\n\tvoid add(AuditEvent event);\n\n\t/**\n\t * Find audit events of specified type relating to the specified principal that\n\t * occurred {@link Instant#isAfter(Instant) after} the time provided.\n\t * @param principal the principal name to search for (or {@code null} if unrestricted)\n\t * @param after time after which an event must have occurred (or {@code null} if\n\t * unrestricted)\n\t * @param type the event type to search for (or {@code null} if unrestricted)\n\t * @return audit events of specified type relating to the principal\n\t * @since 1.4.0\n\t */\n\tList<AuditEvent> find(@Nullable String principal, @Nullable Instant after, @Nullable String type);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/AuditEventsEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.time.Instant;\nimport java.time.OffsetDateTime;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose audit events.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Endpoint(id = \"auditevents\")\npublic class AuditEventsEndpoint {\n\n\tprivate final AuditEventRepository auditEventRepository;\n\n\tpublic AuditEventsEndpoint(AuditEventRepository auditEventRepository) {\n\t\tAssert.notNull(auditEventRepository, \"'auditEventRepository' must not be null\");\n\t\tthis.auditEventRepository = auditEventRepository;\n\t}\n\n\t@ReadOperation\n\tpublic AuditEventsDescriptor events(@Nullable String principal, @Nullable OffsetDateTime after,\n\t\t\t@Nullable String type) {\n\t\tList<AuditEvent> events = this.auditEventRepository.find(principal, getInstant(after), type);\n\t\treturn new AuditEventsDescriptor(events);\n\t}\n\n\tprivate @Nullable Instant getInstant(@Nullable OffsetDateTime offsetDateTime) {\n\t\treturn (offsetDateTime != null) ? offsetDateTime.toInstant() : null;\n\t}\n\n\t/**\n\t * Description of an application's {@link AuditEvent audit events}.\n\t */\n\tpublic static final class AuditEventsDescriptor implements OperationResponseBody {\n\n\t\tprivate final List<AuditEvent> events;\n\n\t\tprivate AuditEventsDescriptor(List<AuditEvent> events) {\n\t\t\tthis.events = events;\n\t\t}\n\n\t\tpublic List<AuditEvent> getEvents() {\n\t\t\treturn this.events;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/InMemoryAuditEventRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.time.Instant;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * In-memory {@link AuditEventRepository} implementation.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Vedran Pavic\n * @since 1.0.0\n */\npublic class InMemoryAuditEventRepository implements AuditEventRepository {\n\n\tprivate static final int DEFAULT_CAPACITY = 1000;\n\n\tprivate final Object monitor = new Object();\n\n\t/**\n\t * Circular buffer of the event with tail pointing to the last element.\n\t */\n\tprivate AuditEvent[] events;\n\n\tprivate volatile int tail = -1;\n\n\tpublic InMemoryAuditEventRepository() {\n\t\tthis(DEFAULT_CAPACITY);\n\t}\n\n\tpublic InMemoryAuditEventRepository(int capacity) {\n\t\tthis.events = new AuditEvent[capacity];\n\t}\n\n\t/**\n\t * Set the capacity of this event repository.\n\t * @param capacity the capacity\n\t */\n\tpublic void setCapacity(int capacity) {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.events = new AuditEvent[capacity];\n\t\t}\n\t}\n\n\t@Override\n\tpublic void add(AuditEvent event) {\n\t\tAssert.notNull(event, \"'event' must not be null\");\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.tail = (this.tail + 1) % this.events.length;\n\t\t\tthis.events[this.tail] = event;\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<AuditEvent> find(@Nullable String principal, @Nullable Instant after, @Nullable String type) {\n\t\tLinkedList<AuditEvent> events = new LinkedList<>();\n\t\tsynchronized (this.monitor) {\n\t\t\tfor (int i = 0; i < this.events.length; i++) {\n\t\t\t\tAuditEvent event = resolveTailEvent(i);\n\t\t\t\tif (event != null && isMatch(principal, after, type, event)) {\n\t\t\t\t\tevents.addFirst(event);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn events;\n\t}\n\n\tprivate boolean isMatch(@Nullable String principal, @Nullable Instant after, @Nullable String type,\n\t\t\tAuditEvent event) {\n\t\tboolean match = true;\n\t\tmatch = match && (principal == null || event.getPrincipal().equals(principal));\n\t\tmatch = match && (after == null || event.getTimestamp().isAfter(after));\n\t\tmatch = match && (type == null || event.getType().equals(type));\n\t\treturn match;\n\t}\n\n\tprivate AuditEvent resolveTailEvent(int offset) {\n\t\tint index = ((this.tail + this.events.length - offset) % this.events.length);\n\t\treturn this.events[index];\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/listener/AbstractAuditListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit.listener;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.context.ApplicationListener;\n\n/**\n * Abstract {@link ApplicationListener} to handle {@link AuditApplicationEvent}s.\n *\n * @author Vedran Pavic\n * @since 1.4.0\n */\npublic abstract class AbstractAuditListener implements ApplicationListener<AuditApplicationEvent> {\n\n\t@Override\n\tpublic void onApplicationEvent(AuditApplicationEvent event) {\n\t\tonAuditEvent(event.getAuditEvent());\n\t}\n\n\tprotected abstract void onAuditEvent(AuditEvent event);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/listener/AuditApplicationEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit.listener;\n\nimport java.time.Instant;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.util.Assert;\n\n/**\n * Spring {@link ApplicationEvent} to encapsulate {@link AuditEvent}s.\n *\n * @author Dave Syer\n * @since 1.0.0\n */\npublic class AuditApplicationEvent extends ApplicationEvent {\n\n\tprivate final AuditEvent auditEvent;\n\n\t/**\n\t * Create a new {@link AuditApplicationEvent} that wraps a newly created\n\t * {@link AuditEvent}.\n\t * @param principal the principal\n\t * @param type the event type\n\t * @param data the event data\n\t * @see AuditEvent#AuditEvent(String, String, Map)\n\t */\n\tpublic AuditApplicationEvent(String principal, String type, Map<String, @Nullable Object> data) {\n\t\tthis(new AuditEvent(principal, type, data));\n\t}\n\n\t/**\n\t * Create a new {@link AuditApplicationEvent} that wraps a newly created\n\t * {@link AuditEvent}.\n\t * @param principal the principal\n\t * @param type the event type\n\t * @param data the event data\n\t * @see AuditEvent#AuditEvent(String, String, String...)\n\t */\n\tpublic AuditApplicationEvent(String principal, String type, String... data) {\n\t\tthis(new AuditEvent(principal, type, data));\n\t}\n\n\t/**\n\t * Create a new {@link AuditApplicationEvent} that wraps a newly created\n\t * {@link AuditEvent}.\n\t * @param timestamp the timestamp\n\t * @param principal the principal\n\t * @param type the event type\n\t * @param data the event data\n\t * @see AuditEvent#AuditEvent(Instant, String, String, Map)\n\t */\n\tpublic AuditApplicationEvent(Instant timestamp, String principal, String type, Map<String, @Nullable Object> data) {\n\t\tthis(new AuditEvent(timestamp, principal, type, data));\n\t}\n\n\t/**\n\t * Create a new {@link AuditApplicationEvent} that wraps the specified\n\t * {@link AuditEvent}.\n\t * @param auditEvent the source of this event\n\t */\n\tpublic AuditApplicationEvent(AuditEvent auditEvent) {\n\t\tsuper(auditEvent);\n\t\tAssert.notNull(auditEvent, \"'auditEvent' must not be null\");\n\t\tthis.auditEvent = auditEvent;\n\t}\n\n\t/**\n\t * Get the audit event.\n\t * @return the audit event\n\t */\n\tpublic AuditEvent getAuditEvent() {\n\t\treturn this.auditEvent;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/listener/AuditListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit.listener;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.AuditEventRepository;\n\n/**\n * The default {@link AbstractAuditListener} implementation. Listens for\n * {@link AuditApplicationEvent}s and stores them in a {@link AuditEventRepository}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 1.0.0\n */\npublic class AuditListener extends AbstractAuditListener {\n\n\tprivate static final Log logger = LogFactory.getLog(AuditListener.class);\n\n\tprivate final AuditEventRepository auditEventRepository;\n\n\tpublic AuditListener(AuditEventRepository auditEventRepository) {\n\t\tthis.auditEventRepository = auditEventRepository;\n\t}\n\n\t@Override\n\tprotected void onAuditEvent(AuditEvent event) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(event);\n\t\t}\n\t\tthis.auditEventRepository.add(event);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/listener/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator auditing listeners.\n */\n@NullMarked\npackage org.springframework.boot.actuate.audit.listener;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/audit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core actuator auditing classes.\n */\n@NullMarked\npackage org.springframework.boot.actuate.audit;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/beans/BeansEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.beans;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Endpoint @Endpoint} to expose details of an application's beans, grouped by\n * application context.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Endpoint(id = \"beans\")\npublic class BeansEndpoint {\n\n\tprivate final ConfigurableApplicationContext context;\n\n\t/**\n\t * Creates a new {@code BeansEndpoint} that will describe the beans in the given\n\t * {@code context} and all of its ancestors.\n\t * @param context the application context\n\t * @see ConfigurableApplicationContext#getParent()\n\t */\n\tpublic BeansEndpoint(ConfigurableApplicationContext context) {\n\t\tthis.context = context;\n\t}\n\n\t@ReadOperation\n\tpublic BeansDescriptor beans() {\n\t\tMap<@Nullable String, ContextBeansDescriptor> contexts = new HashMap<>();\n\t\tConfigurableApplicationContext context = this.context;\n\t\twhile (context != null) {\n\t\t\tcontexts.put(context.getId(), ContextBeansDescriptor.describing(context));\n\t\t\tcontext = getConfigurableParent(context);\n\t\t}\n\t\treturn new BeansDescriptor(contexts);\n\t}\n\n\tprivate static @Nullable ConfigurableApplicationContext getConfigurableParent(\n\t\t\tConfigurableApplicationContext context) {\n\t\tApplicationContext parent = context.getParent();\n\t\tif (parent instanceof ConfigurableApplicationContext configurableParent) {\n\t\t\treturn configurableParent;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Description of an application's beans.\n\t */\n\tpublic static final class BeansDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<@Nullable String, ContextBeansDescriptor> contexts;\n\n\t\tprivate BeansDescriptor(Map<@Nullable String, ContextBeansDescriptor> contexts) {\n\t\t\tthis.contexts = contexts;\n\t\t}\n\n\t\tpublic Map<@Nullable String, ContextBeansDescriptor> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an application context beans.\n\t */\n\tpublic static final class ContextBeansDescriptor {\n\n\t\tprivate final Map<String, BeanDescriptor> beans;\n\n\t\tprivate final @Nullable String parentId;\n\n\t\tprivate ContextBeansDescriptor(Map<String, BeanDescriptor> beans, @Nullable String parentId) {\n\t\t\tthis.beans = beans;\n\t\t\tthis.parentId = parentId;\n\t\t}\n\n\t\tpublic @Nullable String getParentId() {\n\t\t\treturn this.parentId;\n\t\t}\n\n\t\tpublic Map<String, BeanDescriptor> getBeans() {\n\t\t\treturn this.beans;\n\t\t}\n\n\t\t@Contract(\"!null -> !null\")\n\t\tprivate static @Nullable ContextBeansDescriptor describing(@Nullable ConfigurableApplicationContext context) {\n\t\t\tif (context == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tConfigurableApplicationContext parent = getConfigurableParent(context);\n\t\t\treturn new ContextBeansDescriptor(describeBeans(context.getBeanFactory()),\n\t\t\t\t\t(parent != null) ? parent.getId() : null);\n\t\t}\n\n\t\tprivate static Map<String, BeanDescriptor> describeBeans(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tMap<String, BeanDescriptor> beans = new HashMap<>();\n\t\t\tfor (String beanName : beanFactory.getBeanDefinitionNames()) {\n\t\t\t\tBeanDefinition definition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\tif (isBeanEligible(beanName, definition, beanFactory)) {\n\t\t\t\t\tbeans.put(beanName, describeBean(beanName, definition, beanFactory));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn beans;\n\t\t}\n\n\t\tprivate static BeanDescriptor describeBean(String name, BeanDefinition definition,\n\t\t\t\tConfigurableListableBeanFactory factory) {\n\t\t\treturn new BeanDescriptor(factory.getAliases(name), definition.getScope(), factory.getType(name),\n\t\t\t\t\tdefinition.getResourceDescription(), factory.getDependenciesForBean(name));\n\t\t}\n\n\t\tprivate static boolean isBeanEligible(String beanName, BeanDefinition bd, ConfigurableBeanFactory bf) {\n\t\t\treturn (bd.getRole() != BeanDefinition.ROLE_INFRASTRUCTURE\n\t\t\t\t\t&& (!bd.isLazyInit() || bf.containsSingleton(beanName)));\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a bean.\n\t */\n\tpublic static final class BeanDescriptor {\n\n\t\tprivate final String[] aliases;\n\n\t\tprivate final @Nullable String scope;\n\n\t\tprivate final @Nullable Class<?> type;\n\n\t\tprivate final @Nullable String resource;\n\n\t\tprivate final String[] dependencies;\n\n\t\tprivate BeanDescriptor(String[] aliases, @Nullable String scope, @Nullable Class<?> type,\n\t\t\t\t@Nullable String resource, String[] dependencies) {\n\t\t\tthis.aliases = aliases;\n\t\t\tthis.scope = (StringUtils.hasText(scope) ? scope : ConfigurableBeanFactory.SCOPE_SINGLETON);\n\t\t\tthis.type = type;\n\t\t\tthis.resource = resource;\n\t\t\tthis.dependencies = dependencies;\n\t\t}\n\n\t\tpublic String[] getAliases() {\n\t\t\treturn this.aliases;\n\t\t}\n\n\t\tpublic @Nullable String getScope() {\n\t\t\treturn this.scope;\n\t\t}\n\n\t\tpublic @Nullable Class<?> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic @Nullable String getResource() {\n\t\t\treturn this.resource;\n\t\t}\n\n\t\tpublic String[] getDependencies() {\n\t\t\treturn this.dependencies;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/beans/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support relating to Spring Beans.\n */\n@NullMarked\npackage org.springframework.boot.actuate.beans;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/ShutdownEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to shutdown the {@link ApplicationContext}.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Endpoint(id = \"shutdown\", defaultAccess = Access.NONE)\npublic class ShutdownEndpoint implements ApplicationContextAware {\n\n\t@Nullable private ConfigurableApplicationContext context;\n\n\t@WriteOperation\n\tpublic ShutdownDescriptor shutdown() {\n\t\tif (this.context == null) {\n\t\t\treturn ShutdownDescriptor.NO_CONTEXT;\n\t\t}\n\t\ttry {\n\t\t\treturn ShutdownDescriptor.DEFAULT;\n\t\t}\n\t\tfinally {\n\t\t\tThread thread = new Thread(this::performShutdown);\n\t\t\tthread.setContextClassLoader(getClass().getClassLoader());\n\t\t\tthread.start();\n\t\t}\n\t}\n\n\tprivate void performShutdown() {\n\t\ttry {\n\t\t\tThread.sleep(500L);\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t\tAssert.state(this.context != null, \"'context' must not be null\");\n\t\tthis.context.close();\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext context) throws BeansException {\n\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\tthis.context = configurableContext;\n\t\t}\n\t}\n\n\t/**\n\t * Description of the shutdown.\n\t */\n\tpublic static class ShutdownDescriptor implements OperationResponseBody {\n\n\t\tprivate static final ShutdownDescriptor DEFAULT = new ShutdownDescriptor(\"Shutting down, bye...\");\n\n\t\tprivate static final ShutdownDescriptor NO_CONTEXT = new ShutdownDescriptor(\"No context to shutdown.\");\n\n\t\tprivate final String message;\n\n\t\tShutdownDescriptor(String message) {\n\t\t\tthis.message = message;\n\t\t}\n\n\t\tpublic String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support relating to Spring Context.\n */\n@NullMarked\npackage org.springframework.boot.actuate.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/BeanSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Strategy used by {@link ConfigurationPropertiesReportEndpoint} to serialize beans into\n * a {@link Map}.\n *\n * @author Phillip Webb\n */\n@FunctionalInterface\ninterface BeanSerializer {\n\n\tMap<String, @Nullable Object> serialize(@Nullable Object bean);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.SanitizableData;\nimport org.springframework.boot.actuate.endpoint.Sanitizer;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.context.properties.BoundConfigurationProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBean;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link Endpoint @Endpoint} to expose application properties from\n * {@link ConfigurationProperties @ConfigurationProperties} annotated beans.\n *\n * <p>\n * To protect sensitive information from being exposed, all property values are masked by\n * default. To configure when property values should be shown, use\n * {@code management.endpoint.configprops.show-values} and\n * {@code management.endpoint.configprops.roles} in your Spring Boot application\n * configuration.\n *\n * @author Christian Dupuis\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @author Chris Bono\n * @since 2.0.0\n */\n@Endpoint(id = \"configprops\")\npublic class ConfigurationPropertiesReportEndpoint implements ApplicationContextAware {\n\n\tprivate final Sanitizer sanitizer;\n\n\tprivate final Show showValues;\n\n\tprivate final BeanSerializer serializer;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext context;\n\n\tpublic ConfigurationPropertiesReportEndpoint(Iterable<SanitizingFunction> sanitizingFunctions, Show showValues) {\n\t\tthis.sanitizer = new Sanitizer(sanitizingFunctions);\n\t\tthis.showValues = showValues;\n\t\tthis.serializer = getBeanSerializer();\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext context) throws BeansException {\n\t\tthis.context = context;\n\t}\n\n\t@ReadOperation\n\tpublic ConfigurationPropertiesDescriptor configurationProperties() {\n\t\tboolean showUnsanitized = this.showValues.isShown(true);\n\t\treturn getConfigurationProperties(showUnsanitized);\n\t}\n\n\tConfigurationPropertiesDescriptor getConfigurationProperties(boolean showUnsanitized) {\n\t\treturn getConfigurationProperties(this.context, (bean) -> true, showUnsanitized);\n\t}\n\n\t@ReadOperation\n\tpublic ConfigurationPropertiesDescriptor configurationPropertiesWithPrefix(@Selector String prefix) {\n\t\tboolean showUnsanitized = this.showValues.isShown(true);\n\t\treturn getConfigurationProperties(prefix, showUnsanitized);\n\t}\n\n\tConfigurationPropertiesDescriptor getConfigurationProperties(String prefix, boolean showUnsanitized) {\n\t\treturn getConfigurationProperties(this.context, (bean) -> bean.getAnnotation().prefix().startsWith(prefix),\n\t\t\t\tshowUnsanitized);\n\t}\n\n\tprivate ConfigurationPropertiesDescriptor getConfigurationProperties(ApplicationContext context,\n\t\t\tPredicate<ConfigurationPropertiesBean> beanFilterPredicate, boolean showUnsanitized) {\n\t\tMap<@Nullable String, ContextConfigurationPropertiesDescriptor> contexts = new HashMap<>();\n\t\tApplicationContext target = context;\n\n\t\twhile (target != null) {\n\t\t\tcontexts.put(target.getId(), describeBeans(target, beanFilterPredicate, showUnsanitized));\n\t\t\ttarget = target.getParent();\n\t\t}\n\t\treturn new ConfigurationPropertiesDescriptor(contexts);\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate static BeanSerializer getBeanSerializer() {\n\t\tClassLoader classLoader = ConfigurationPropertiesReportEndpoint.class.getClassLoader();\n\t\tif (ClassUtils.isPresent(\"tools.jackson.databind.json.JsonMapper\", classLoader)) {\n\t\t\treturn new JacksonBeanSerializer();\n\t\t}\n\t\tif (ClassUtils.isPresent(\"com.fasterxml.jackson.databind.ObjectMapper\", classLoader)) {\n\t\t\treturn new Jackson2BeanSerializer();\n\t\t}\n\t\treturn (bean) -> {\n\t\t\tthrow new IllegalStateException(\"Jackson is required for the 'configprops' endpoint\");\n\t\t};\n\t}\n\n\tprivate ContextConfigurationPropertiesDescriptor describeBeans(ApplicationContext context,\n\t\t\tPredicate<ConfigurationPropertiesBean> beanFilterPredicate, boolean showUnsanitized) {\n\t\tMap<String, ConfigurationPropertiesBean> beans = ConfigurationPropertiesBean.getAll(context);\n\t\tMap<String, ConfigurationPropertiesBeanDescriptor> descriptors = beans.values()\n\t\t\t.stream()\n\t\t\t.filter(beanFilterPredicate)\n\t\t\t.collect(Collectors.toMap(ConfigurationPropertiesBean::getName,\n\t\t\t\t\t(bean) -> describeBean(bean, showUnsanitized)));\n\t\treturn new ContextConfigurationPropertiesDescriptor(descriptors,\n\t\t\t\t(context.getParent() != null) ? context.getParent().getId() : null);\n\t}\n\n\tprivate ConfigurationPropertiesBeanDescriptor describeBean(ConfigurationPropertiesBean bean,\n\t\t\tboolean showUnsanitized) {\n\t\tString prefix = bean.getAnnotation().prefix();\n\t\tMap<String, @Nullable Object> serialized = safeSerialize(bean.getInstance(), prefix);\n\t\tMap<String, @Nullable Object> properties = sanitize(prefix, serialized, showUnsanitized);\n\t\tMap<String, Object> inputs = getInputs(prefix, serialized, showUnsanitized);\n\t\treturn new ConfigurationPropertiesBeanDescriptor(prefix, properties, inputs);\n\t}\n\n\t/**\n\t * Cautiously serialize the bean to a map (returning a map with an error message\n\t * instead of throwing an exception if there is a problem).\n\t * @param bean the source bean\n\t * @param prefix the prefix\n\t * @return the serialized instance\n\t */\n\tprivate Map<String, @Nullable Object> safeSerialize(@Nullable Object bean, String prefix) {\n\t\ttry {\n\t\t\treturn new HashMap<>(this.serializer.serialize(bean));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn new HashMap<>(Collections.singletonMap(\"error\", \"Cannot serialize '\" + prefix + \"'\"));\n\t\t}\n\t}\n\n\t/**\n\t * Sanitize all unwanted configuration properties to avoid leaking of sensitive\n\t * information.\n\t * @param prefix the property prefix\n\t * @param map the source map\n\t * @param showUnsanitized whether to show the unsanitized values\n\t * @return the sanitized map\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, @Nullable Object> sanitize(String prefix, Map<String, @Nullable Object> map,\n\t\t\tboolean showUnsanitized) {\n\t\tmap.forEach((key, value) -> {\n\t\t\tString qualifiedKey = getQualifiedKey(prefix, key);\n\t\t\tif (value instanceof Map) {\n\t\t\t\tmap.put(key, sanitize(qualifiedKey, (Map<String, @Nullable Object>) value, showUnsanitized));\n\t\t\t}\n\t\t\telse if (value instanceof List) {\n\t\t\t\tmap.put(key, sanitize(qualifiedKey, (List<Object>) value, showUnsanitized));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmap.put(key, sanitizeWithPropertySourceIfPresent(qualifiedKey, value, showUnsanitized));\n\t\t\t}\n\t\t});\n\t\treturn map;\n\t}\n\n\tprivate @Nullable Object sanitizeWithPropertySourceIfPresent(String qualifiedKey, @Nullable Object value,\n\t\t\tboolean showUnsanitized) {\n\t\tConfigurationPropertyName currentName = getCurrentName(qualifiedKey);\n\t\tConfigurationProperty candidate = getCandidate(currentName);\n\t\tPropertySource<?> propertySource = getPropertySource(candidate);\n\t\tif (propertySource != null) {\n\t\t\tSanitizableData data = new SanitizableData(propertySource, qualifiedKey, value);\n\t\t\treturn this.sanitizer.sanitize(data, showUnsanitized);\n\t\t}\n\t\tSanitizableData data = new SanitizableData(null, qualifiedKey, value);\n\t\treturn this.sanitizer.sanitize(data, showUnsanitized);\n\t}\n\n\tprivate @Nullable PropertySource<?> getPropertySource(@Nullable ConfigurationProperty configurationProperty) {\n\t\tif (configurationProperty == null) {\n\t\t\treturn null;\n\t\t}\n\t\tConfigurationPropertySource source = configurationProperty.getSource();\n\t\tObject underlyingSource = (source != null) ? source.getUnderlyingSource() : null;\n\t\treturn (underlyingSource instanceof PropertySource<?>) ? (PropertySource<?>) underlyingSource : null;\n\t}\n\n\tprivate ConfigurationPropertyName getCurrentName(String qualifiedKey) {\n\t\treturn ConfigurationPropertyName.adapt(qualifiedKey, '.');\n\t}\n\n\tprivate @Nullable ConfigurationProperty getCandidate(ConfigurationPropertyName currentName) {\n\t\tBoundConfigurationProperties bound = BoundConfigurationProperties.get(this.context);\n\t\tif (bound == null) {\n\t\t\treturn null;\n\t\t}\n\t\tConfigurationProperty candidate = bound.get(currentName);\n\t\tif (candidate == null && currentName.isLastElementIndexed()) {\n\t\t\tcandidate = bound.get(currentName.chop(currentName.getNumberOfElements() - 1));\n\t\t}\n\t\treturn candidate;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate List<@Nullable Object> sanitize(String prefix, List<Object> list, boolean showUnsanitized) {\n\t\tList<@Nullable Object> sanitized = new ArrayList<>();\n\t\tint index = 0;\n\t\tfor (Object item : list) {\n\t\t\tString name = prefix + \"[\" + index++ + \"]\";\n\t\t\tif (item instanceof Map) {\n\t\t\t\tsanitized.add(sanitize(name, (Map<String, @Nullable Object>) item, showUnsanitized));\n\t\t\t}\n\t\t\telse if (item instanceof List) {\n\t\t\t\tsanitized.add(sanitize(name, (List<Object>) item, showUnsanitized));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsanitized.add(sanitizeWithPropertySourceIfPresent(name, item, showUnsanitized));\n\t\t\t}\n\t\t}\n\t\treturn sanitized;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, Object> getInputs(String prefix, Map<String, @Nullable Object> map, boolean showUnsanitized) {\n\t\tMap<String, Object> augmented = new LinkedHashMap<>(map);\n\t\tmap.forEach((key, value) -> {\n\t\t\tString qualifiedKey = getQualifiedKey(prefix, key);\n\t\t\tif (value instanceof Map) {\n\t\t\t\taugmented.put(key, getInputs(qualifiedKey, (Map<String, @Nullable Object>) value, showUnsanitized));\n\t\t\t}\n\t\t\telse if (value instanceof List) {\n\t\t\t\taugmented.put(key, getInputs(qualifiedKey, (List<Object>) value, showUnsanitized));\n\t\t\t}\n\t\t\telse {\n\t\t\t\taugmented.put(key, applyInput(qualifiedKey, showUnsanitized));\n\t\t\t}\n\t\t});\n\t\treturn augmented;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate List<Object> getInputs(String prefix, List<Object> list, boolean showUnsanitized) {\n\t\tList<Object> augmented = new ArrayList<>();\n\t\tint index = 0;\n\t\tfor (Object item : list) {\n\t\t\tString name = prefix + \"[\" + index++ + \"]\";\n\t\t\tif (item instanceof Map) {\n\t\t\t\taugmented.add(getInputs(name, (Map<String, @Nullable Object>) item, showUnsanitized));\n\t\t\t}\n\t\t\telse if (item instanceof List) {\n\t\t\t\taugmented.add(getInputs(name, (List<Object>) item, showUnsanitized));\n\t\t\t}\n\t\t\telse {\n\t\t\t\taugmented.add(applyInput(name, showUnsanitized));\n\t\t\t}\n\t\t}\n\t\treturn augmented;\n\t}\n\n\tprivate Map<String, @Nullable Object> applyInput(String qualifiedKey, boolean showUnsanitized) {\n\t\tConfigurationPropertyName currentName = getCurrentName(qualifiedKey);\n\t\tConfigurationProperty candidate = getCandidate(currentName);\n\t\tPropertySource<?> propertySource = getPropertySource(candidate);\n\t\tif (propertySource != null) {\n\t\t\tAssert.state(candidate != null, \"'candidate' must not be null\");\n\t\t\tObject value = stringifyIfNecessary(candidate.getValue());\n\t\t\tSanitizableData data = new SanitizableData(propertySource, currentName.toString(), value);\n\t\t\treturn getInput(candidate, this.sanitizer.sanitize(data, showUnsanitized));\n\t\t}\n\t\treturn Collections.emptyMap();\n\t}\n\n\tprivate Map<String, @Nullable Object> getInput(ConfigurationProperty candidate, @Nullable Object sanitizedValue) {\n\t\tMap<String, @Nullable Object> input = new LinkedHashMap<>();\n\t\tOrigin origin = Origin.from(candidate);\n\t\tList<Origin> originParents = Origin.parentsFrom(candidate);\n\t\tinput.put(\"value\", sanitizedValue);\n\t\tinput.put(\"origin\", (origin != null) ? origin.toString() : \"none\");\n\t\tif (!originParents.isEmpty()) {\n\t\t\tinput.put(\"originParents\", originParents.stream().map(Object::toString).toArray(String[]::new));\n\t\t}\n\t\treturn input;\n\t}\n\n\tprivate @Nullable Object stringifyIfNecessary(@Nullable Object value) {\n\t\tif (value == null || ClassUtils.isPrimitiveOrWrapper(value.getClass()) || value instanceof String) {\n\t\t\treturn value;\n\t\t}\n\t\tif (CharSequence.class.isAssignableFrom(value.getClass())) {\n\t\t\treturn value.toString();\n\t\t}\n\t\treturn \"Complex property value \" + value.getClass().getName();\n\t}\n\n\tprivate String getQualifiedKey(String prefix, String key) {\n\t\treturn (prefix.isEmpty() ? prefix : prefix + \".\") + key;\n\t}\n\n\t/**\n\t * Description of an application's\n\t * {@link ConfigurationProperties @ConfigurationProperties} beans.\n\t */\n\tpublic static final class ConfigurationPropertiesDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<@Nullable String, ContextConfigurationPropertiesDescriptor> contexts;\n\n\t\tConfigurationPropertiesDescriptor(Map<@Nullable String, ContextConfigurationPropertiesDescriptor> contexts) {\n\t\t\tthis.contexts = contexts;\n\t\t}\n\n\t\tpublic Map<@Nullable String, ContextConfigurationPropertiesDescriptor> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an application context's\n\t * {@link ConfigurationProperties @ConfigurationProperties} beans.\n\t */\n\tpublic static final class ContextConfigurationPropertiesDescriptor {\n\n\t\tprivate final Map<String, ConfigurationPropertiesBeanDescriptor> beans;\n\n\t\tprivate final @Nullable String parentId;\n\n\t\tprivate ContextConfigurationPropertiesDescriptor(Map<String, ConfigurationPropertiesBeanDescriptor> beans,\n\t\t\t\t@Nullable String parentId) {\n\t\t\tthis.beans = beans;\n\t\t\tthis.parentId = parentId;\n\t\t}\n\n\t\tpublic Map<String, ConfigurationPropertiesBeanDescriptor> getBeans() {\n\t\t\treturn this.beans;\n\t\t}\n\n\t\tpublic @Nullable String getParentId() {\n\t\t\treturn this.parentId;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link ConfigurationProperties @ConfigurationProperties} bean.\n\t */\n\tpublic static final class ConfigurationPropertiesBeanDescriptor {\n\n\t\tprivate final String prefix;\n\n\t\tprivate final Map<String, @Nullable Object> properties;\n\n\t\tprivate final Map<String, Object> inputs;\n\n\t\tprivate ConfigurationPropertiesBeanDescriptor(String prefix, Map<String, @Nullable Object> properties,\n\t\t\t\tMap<String, Object> inputs) {\n\t\t\tthis.prefix = prefix;\n\t\t\tthis.properties = properties;\n\t\t\tthis.inputs = inputs;\n\t\t}\n\n\t\tpublic String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic Map<String, @Nullable Object> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tpublic Map<String, Object> getInputs() {\n\t\t\treturn this.inputs;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\n\n/**\n * {@link EndpointWebExtension @EndpointWebExtension} for the\n * {@link ConfigurationPropertiesReportEndpoint}.\n *\n * @author Chris Bono\n * @since 2.5.0\n */\n@EndpointWebExtension(endpoint = ConfigurationPropertiesReportEndpoint.class)\npublic class ConfigurationPropertiesReportEndpointWebExtension {\n\n\tprivate final ConfigurationPropertiesReportEndpoint delegate;\n\n\tprivate final Show showValues;\n\n\tprivate final Set<String> roles;\n\n\tpublic ConfigurationPropertiesReportEndpointWebExtension(ConfigurationPropertiesReportEndpoint delegate,\n\t\t\tShow showValues, Set<String> roles) {\n\t\tthis.delegate = delegate;\n\t\tthis.showValues = showValues;\n\t\tthis.roles = roles;\n\t}\n\n\t@ReadOperation\n\tpublic ConfigurationPropertiesDescriptor configurationProperties(SecurityContext securityContext) {\n\t\tboolean showUnsanitized = this.showValues.isShown(securityContext, this.roles);\n\t\treturn this.delegate.getConfigurationProperties(showUnsanitized);\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<ConfigurationPropertiesDescriptor> configurationPropertiesWithPrefix(\n\t\t\tSecurityContext securityContext, @Selector String prefix) {\n\t\tboolean showUnsanitized = this.showValues.isShown(securityContext, this.roles);\n\t\tConfigurationPropertiesDescriptor configurationProperties = this.delegate.getConfigurationProperties(prefix,\n\t\t\t\tshowUnsanitized);\n\t\tboolean foundMatchingBeans = configurationProperties.getContexts()\n\t\t\t.values()\n\t\t\t.stream()\n\t\t\t.anyMatch((context) -> !context.getBeans().isEmpty());\n\t\treturn (foundMatchingBeans) ? new WebEndpointResponse<>(configurationProperties, WebEndpointResponse.STATUS_OK)\n\t\t\t\t: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/Jackson2BeanSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.BeanDescription;\nimport com.fasterxml.jackson.databind.MapperFeature;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializationConfig;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.SerializerProvider;\nimport com.fasterxml.jackson.databind.introspect.Annotated;\nimport com.fasterxml.jackson.databind.introspect.AnnotatedMethod;\nimport com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;\nimport com.fasterxml.jackson.databind.json.JsonMapper;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport com.fasterxml.jackson.databind.ser.BeanPropertyWriter;\nimport com.fasterxml.jackson.databind.ser.BeanSerializerFactory;\nimport com.fasterxml.jackson.databind.ser.BeanSerializerModifier;\nimport com.fasterxml.jackson.databind.ser.PropertyWriter;\nimport com.fasterxml.jackson.databind.ser.SerializerFactory;\nimport com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;\nimport com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;\nimport com.fasterxml.jackson.databind.ser.std.ToStringSerializer;\nimport com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.BindConstructorProvider;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link BeanSerializer} backed by Jackson 2.\n *\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass Jackson2BeanSerializer implements BeanSerializer {\n\n\tprivate static final String CONFIGURATION_PROPERTIES_FILTER_ID = \"configurationPropertiesFilter\";\n\n\tprivate final ObjectMapper mapper;\n\n\tJackson2BeanSerializer() {\n\t\tJsonMapper.Builder builder = JsonMapper.builder();\n\t\tconfigureMapper(builder);\n\t\tthis.mapper = builder.build();\n\t}\n\n\tprivate void configureMapper(JsonMapper.Builder builder) {\n\t\tbuilder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);\n\t\tbuilder.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);\n\t\tbuilder.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);\n\t\tbuilder.configure(MapperFeature.USE_STD_BEAN_NAMING, true);\n\t\tbuilder.serializationInclusion(Include.NON_NULL);\n\t\tapplyConfigurationPropertiesFilter(builder);\n\t\tapplySerializationModifier(builder);\n\t\tif (ClassUtils.isPresent(\"com.fasterxml.jackson.datatype.jsr310.JavaTimeModule\",\n\t\t\t\tbuilder.getClass().getClassLoader())) {\n\t\t\tbuilder.addModule(new JavaTimeModule());\n\t\t}\n\t\tbuilder.addModule(new ConfigurationPropertiesModule());\n\t}\n\n\tprivate void applyConfigurationPropertiesFilter(JsonMapper.Builder builder) {\n\t\tbuilder.annotationIntrospector(new ConfigurationPropertiesAnnotationIntrospector());\n\t\tConfigurationPropertiesPropertyFilter filter = new ConfigurationPropertiesPropertyFilter();\n\t\tbuilder.filterProvider(new SimpleFilterProvider().setDefaultFilter(filter));\n\t}\n\n\t/**\n\t * Ensure only bindable and non-cyclic bean properties are reported.\n\t * @param builder the JsonMapper builder\n\t */\n\tprivate void applySerializationModifier(JsonMapper.Builder builder) {\n\t\tSerializerFactory factory = BeanSerializerFactory.instance\n\t\t\t.withSerializerModifier(new GenericSerializerModifier());\n\t\tbuilder.serializerFactory(factory);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, @Nullable Object> serialize(@Nullable Object bean) {\n\t\treturn this.mapper.convertValue(bean, Map.class);\n\t}\n\n\t/**\n\t * Extension to {@link JacksonAnnotationIntrospector} to suppress CGLIB generated bean\n\t * properties.\n\t */\n\tprivate static final class ConfigurationPropertiesAnnotationIntrospector extends JacksonAnnotationIntrospector {\n\n\t\t@Override\n\t\tpublic Object findFilterId(Annotated a) {\n\t\t\tObject id = super.findFilterId(a);\n\t\t\treturn (id != null) ? id : CONFIGURATION_PROPERTIES_FILTER_ID;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SimpleBeanPropertyFilter} for serialization of\n\t * {@link ConfigurationProperties @ConfigurationProperties} beans. The filter hides:\n\t *\n\t * <ul>\n\t * <li>Properties that have a name starting with '$$'.\n\t * <li>Properties that are self-referential.\n\t * <li>Properties that throw an exception when retrieving their value.\n\t * </ul>\n\t */\n\tprivate static final class ConfigurationPropertiesPropertyFilter extends SimpleBeanPropertyFilter {\n\n\t\tprivate static final Log logger = LogFactory.getLog(ConfigurationPropertiesPropertyFilter.class);\n\n\t\t@Override\n\t\tprotected boolean include(BeanPropertyWriter writer) {\n\t\t\treturn include(writer.getFullName().getSimpleName());\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean include(PropertyWriter writer) {\n\t\t\treturn include(writer.getFullName().getSimpleName());\n\t\t}\n\n\t\tprivate boolean include(String name) {\n\t\t\treturn !name.startsWith(\"$$\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider,\n\t\t\t\tPropertyWriter writer) throws Exception {\n\t\t\tif (writer instanceof BeanPropertyWriter beanPropertyWriter) {\n\t\t\t\ttry {\n\t\t\t\t\tif (pojo == beanPropertyWriter.get(pojo)) {\n\t\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\t\tlogger.debug(\"Skipping '\" + writer.getFullName() + \"' on '\" + pojo.getClass().getName()\n\t\t\t\t\t\t\t\t\t+ \"' as it is self-referential\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\tlogger.debug(\"Skipping '\" + writer.getFullName() + \"' on '\" + pojo.getClass().getName()\n\t\t\t\t\t\t\t\t+ \"' as an exception was thrown when retrieving its value\", ex);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsuper.serializeAsField(pojo, jgen, provider, writer);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SimpleModule} for configuring the serializer.\n\t */\n\tprivate static final class ConfigurationPropertiesModule extends SimpleModule {\n\n\t\tprivate ConfigurationPropertiesModule() {\n\t\t\taddSerializer(DataSize.class, ToStringSerializer.instance);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link BeanSerializerModifier} to return only relevant configuration properties.\n\t */\n\tprotected static class GenericSerializerModifier extends BeanSerializerModifier {\n\n\t\tprivate static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();\n\n\t\t@Override\n\t\tpublic List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,\n\t\t\t\tList<BeanPropertyWriter> beanProperties) {\n\t\t\tList<BeanPropertyWriter> result = new ArrayList<>();\n\t\t\tClass<?> beanClass = beanDesc.getType().getRawClass();\n\t\t\tBindable<?> bindable = Bindable.of(ClassUtils.getUserClass(beanClass));\n\t\t\tConstructor<?> bindConstructor = BindConstructorProvider.DEFAULT.getBindConstructor(bindable, false);\n\t\t\tfor (BeanPropertyWriter writer : beanProperties) {\n\t\t\t\tif (isCandidate(beanDesc, writer, bindConstructor)) {\n\t\t\t\t\tresult.add(writer);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate boolean isCandidate(BeanDescription beanDesc, BeanPropertyWriter writer,\n\t\t\t\t@Nullable Constructor<?> constructor) {\n\t\t\tif (constructor != null) {\n\t\t\t\tParameter[] parameters = constructor.getParameters();\n\t\t\t\t@Nullable String @Nullable [] names = parameterNameDiscoverer.getParameterNames(constructor);\n\t\t\t\tif (names == null) {\n\t\t\t\t\tnames = new String[parameters.length];\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < parameters.length; i++) {\n\t\t\t\t\tString name = MergedAnnotations.from(parameters[i])\n\t\t\t\t\t\t.get(Name.class)\n\t\t\t\t\t\t.getValue(MergedAnnotation.VALUE, String.class)\n\t\t\t\t\t\t.orElse((names[i] != null) ? names[i] : parameters[i].getName());\n\t\t\t\t\tif (name.equals(writer.getName())) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isReadable(beanDesc, writer);\n\t\t}\n\n\t\tprivate boolean isReadable(BeanDescription beanDesc, BeanPropertyWriter writer) {\n\t\t\tClass<?> parentType = beanDesc.getType().getRawClass();\n\t\t\tClass<?> type = writer.getType().getRawClass();\n\t\t\tAnnotatedMethod setter = findSetter(beanDesc, writer);\n\t\t\t// If there's a setter, we assume it's OK to report on the value,\n\t\t\t// similarly, if there's no setter but the package names match, we assume\n\t\t\t// that it is a nested class used solely for binding to config props, so it\n\t\t\t// should be kosher. Lists and Maps are also auto-detected by default since\n\t\t\t// that's what the metadata generator does. This filter is not used if there\n\t\t\t// is JSON metadata for the property, so it's mainly for user-defined beans.\n\t\t\treturn (setter != null) || ClassUtils.getPackageName(parentType).equals(ClassUtils.getPackageName(type))\n\t\t\t\t\t|| Map.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type);\n\t\t}\n\n\t\tprivate @Nullable AnnotatedMethod findSetter(BeanDescription beanDesc, BeanPropertyWriter writer) {\n\t\t\tString name = \"set\" + determineAccessorSuffix(writer.getName());\n\t\t\tClass<?> type = writer.getType().getRawClass();\n\t\t\tAnnotatedMethod setter = beanDesc.findMethod(name, new Class<?>[] { type });\n\t\t\t// The enabled property of endpoints returns a boolean primitive but is set\n\t\t\t// using a Boolean class\n\t\t\tif (setter == null && type.equals(Boolean.TYPE)) {\n\t\t\t\tsetter = beanDesc.findMethod(name, new Class<?>[] { Boolean.class });\n\t\t\t}\n\t\t\treturn setter;\n\t\t}\n\n\t\t/**\n\t\t * Determine the accessor suffix of the specified {@code propertyName}, see\n\t\t * section 8.8 \"Capitalization of inferred names\" of the JavaBean specs for more\n\t\t * details.\n\t\t * @param propertyName the property name to turn into an accessor suffix\n\t\t * @return the accessor suffix for {@code propertyName}\n\t\t */\n\t\tprivate String determineAccessorSuffix(String propertyName) {\n\t\t\tif (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) {\n\t\t\t\treturn propertyName;\n\t\t\t}\n\t\t\treturn StringUtils.capitalize(propertyName);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/JacksonBeanSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.BeanDescription;\nimport tools.jackson.databind.SerializationConfig;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.cfg.MapperConfig;\nimport tools.jackson.databind.introspect.Annotated;\nimport tools.jackson.databind.introspect.AnnotatedMethod;\nimport tools.jackson.databind.introspect.DefaultAccessorNamingStrategy;\nimport tools.jackson.databind.introspect.JacksonAnnotationIntrospector;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.module.SimpleModule;\nimport tools.jackson.databind.ser.BeanPropertyWriter;\nimport tools.jackson.databind.ser.BeanSerializerFactory;\nimport tools.jackson.databind.ser.PropertyWriter;\nimport tools.jackson.databind.ser.SerializerFactory;\nimport tools.jackson.databind.ser.ValueSerializerModifier;\nimport tools.jackson.databind.ser.std.SimpleBeanPropertyFilter;\nimport tools.jackson.databind.ser.std.SimpleFilterProvider;\nimport tools.jackson.databind.ser.std.ToStringSerializer;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.BindConstructorProvider;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link BeanSerializer} backed by Jackson.\n *\n * @author Phillip Webb\n */\nclass JacksonBeanSerializer implements BeanSerializer {\n\n\tprivate static final String CONFIGURATION_PROPERTIES_FILTER_ID = \"configurationPropertiesFilter\";\n\n\tprivate final JsonMapper mapper;\n\n\tJacksonBeanSerializer() {\n\t\tJsonMapper.Builder builder = JsonMapper.builder();\n\t\tconfigureMapper(builder);\n\t\tthis.mapper = builder.build();\n\t}\n\n\tprivate void configureMapper(JsonMapper.Builder builder) {\n\t\tbuilder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);\n\t\tbuilder.changeDefaultPropertyInclusion((value) -> value.withValueInclusion(Include.NON_NULL));\n\t\tbuilder.accessorNaming(new DefaultAccessorNamingStrategy.Provider().withFirstCharAcceptance(true, false));\n\t\tapplyConfigurationPropertiesFilter(builder);\n\t\tapplySerializationModifier(builder);\n\t\tbuilder.addModule(new ConfigurationPropertiesModule());\n\t}\n\n\tprivate void applyConfigurationPropertiesFilter(JsonMapper.Builder builder) {\n\t\tbuilder.annotationIntrospector(new ConfigurationPropertiesAnnotationIntrospector());\n\t\tConfigurationPropertiesPropertyFilter filter = new ConfigurationPropertiesPropertyFilter();\n\t\tbuilder.filterProvider(new SimpleFilterProvider().setDefaultFilter(filter));\n\t}\n\n\t/**\n\t * Ensure only bindable and non-cyclic bean properties are reported.\n\t * @param builder the JsonMapper builder\n\t */\n\tprivate void applySerializationModifier(JsonMapper.Builder builder) {\n\t\tSerializerFactory factory = BeanSerializerFactory.instance\n\t\t\t.withSerializerModifier(new GenericSerializerModifier());\n\t\tbuilder.serializerFactory(factory);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Map<String, @Nullable Object> serialize(@Nullable Object bean) {\n\t\treturn this.mapper.convertValue(bean, Map.class);\n\t}\n\n\t/**\n\t * Extension to {@link JacksonAnnotationIntrospector} to suppress CGLIB generated bean\n\t * properties.\n\t */\n\tprivate static final class ConfigurationPropertiesAnnotationIntrospector extends JacksonAnnotationIntrospector {\n\n\t\t@Override\n\t\tpublic Object findFilterId(MapperConfig<?> config, Annotated a) {\n\t\t\tObject id = super.findFilterId(config, a);\n\t\t\treturn (id != null) ? id : CONFIGURATION_PROPERTIES_FILTER_ID;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SimpleBeanPropertyFilter} for serialization of\n\t * {@link ConfigurationProperties @ConfigurationProperties} beans. The filter hides:\n\t *\n\t * <ul>\n\t * <li>Properties that have a name starting with '$$'.\n\t * <li>Properties that are self-referential.\n\t * <li>Properties that throw an exception when retrieving their value.\n\t * </ul>\n\t */\n\tprivate static final class ConfigurationPropertiesPropertyFilter extends SimpleBeanPropertyFilter {\n\n\t\tprivate static final Log logger = LogFactory.getLog(ConfigurationPropertiesPropertyFilter.class);\n\n\t\t@Override\n\t\tprotected boolean include(BeanPropertyWriter writer) {\n\t\t\treturn include(writer.getFullName().getSimpleName());\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean include(PropertyWriter writer) {\n\t\t\treturn include(writer.getFullName().getSimpleName());\n\t\t}\n\n\t\tprivate boolean include(String name) {\n\t\t\treturn !name.startsWith(\"$$\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void serializeAsProperty(Object pojo, JsonGenerator jgen, SerializationContext context,\n\t\t\t\tPropertyWriter writer) throws Exception {\n\t\t\tif (writer instanceof BeanPropertyWriter beanPropertyWriter) {\n\t\t\t\ttry {\n\t\t\t\t\tif (pojo == beanPropertyWriter.get(pojo)) {\n\t\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\t\tlogger.debug(\"Skipping '\" + writer.getFullName() + \"' on '\" + pojo.getClass().getName()\n\t\t\t\t\t\t\t\t\t+ \"' as it is self-referential\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\tlogger.debug(\"Skipping '\" + writer.getFullName() + \"' on '\" + pojo.getClass().getName()\n\t\t\t\t\t\t\t\t+ \"' as an exception was thrown when retrieving its value\", ex);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsuper.serializeAsProperty(pojo, jgen, context, writer);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SimpleModule} for configuring the serializer.\n\t */\n\tprivate static final class ConfigurationPropertiesModule extends SimpleModule {\n\n\t\tprivate ConfigurationPropertiesModule() {\n\t\t\taddSerializer(DataSize.class, ToStringSerializer.instance);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ValueSerializerModifier} to return only relevant configuration properties.\n\t */\n\tprotected static class GenericSerializerModifier extends ValueSerializerModifier {\n\n\t\tprivate static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();\n\n\t\t@Override\n\t\tpublic List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription.Supplier beanDesc,\n\t\t\t\tList<BeanPropertyWriter> beanProperties) {\n\t\t\tList<BeanPropertyWriter> result = new ArrayList<>();\n\t\t\tClass<?> beanClass = beanDesc.getType().getRawClass();\n\t\t\tBindable<?> bindable = Bindable.of(ClassUtils.getUserClass(beanClass));\n\t\t\tConstructor<?> bindConstructor = BindConstructorProvider.DEFAULT.getBindConstructor(bindable, false);\n\t\t\tfor (BeanPropertyWriter writer : beanProperties) {\n\t\t\t\tif (isCandidate(beanDesc, writer, bindConstructor)) {\n\t\t\t\t\tresult.add(writer);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate boolean isCandidate(BeanDescription.Supplier beanDesc, BeanPropertyWriter writer,\n\t\t\t\t@Nullable Constructor<?> constructor) {\n\t\t\tif (constructor != null) {\n\t\t\t\tParameter[] parameters = constructor.getParameters();\n\t\t\t\t@Nullable String @Nullable [] names = parameterNameDiscoverer.getParameterNames(constructor);\n\t\t\t\tif (names == null) {\n\t\t\t\t\tnames = new String[parameters.length];\n\t\t\t\t}\n\t\t\t\tfor (int i = 0; i < parameters.length; i++) {\n\t\t\t\t\tString name = MergedAnnotations.from(parameters[i])\n\t\t\t\t\t\t.get(Name.class)\n\t\t\t\t\t\t.getValue(MergedAnnotation.VALUE, String.class)\n\t\t\t\t\t\t.orElse((names[i] != null) ? names[i] : parameters[i].getName());\n\t\t\t\t\tif (name != null && name.equals(writer.getName())) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn isReadable(beanDesc, writer);\n\t\t}\n\n\t\tprivate boolean isReadable(BeanDescription.Supplier beanDesc, BeanPropertyWriter writer) {\n\t\t\tClass<?> parentType = beanDesc.get().getType().getRawClass();\n\t\t\tClass<?> type = writer.getType().getRawClass();\n\t\t\tAnnotatedMethod setter = findSetter(beanDesc.get(), writer);\n\t\t\t// If there's a setter, we assume it's OK to report on the value,\n\t\t\t// similarly, if there's no setter but the package names match, we assume\n\t\t\t// that it is a nested class used solely for binding to config props, so it\n\t\t\t// should be kosher. Lists and Maps are also auto-detected by default since\n\t\t\t// that's what the metadata generator does. This filter is not used if there\n\t\t\t// is JSON metadata for the property, so it's mainly for user-defined beans.\n\t\t\treturn (setter != null) || ClassUtils.getPackageName(parentType).equals(ClassUtils.getPackageName(type))\n\t\t\t\t\t|| Map.class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type);\n\t\t}\n\n\t\tprivate @Nullable AnnotatedMethod findSetter(BeanDescription beanDesc, BeanPropertyWriter writer) {\n\t\t\tString name = \"set\" + determineAccessorSuffix(writer.getName());\n\t\t\tClass<?> type = writer.getType().getRawClass();\n\t\t\tAnnotatedMethod setter = beanDesc.findMethod(name, new Class<?>[] { type });\n\t\t\t// The enabled property of endpoints returns a boolean primitive but is set\n\t\t\t// using a Boolean class\n\t\t\tif (setter == null && type.equals(Boolean.TYPE)) {\n\t\t\t\tsetter = beanDesc.findMethod(name, new Class<?>[] { Boolean.class });\n\t\t\t}\n\t\t\treturn setter;\n\t\t}\n\n\t\t/**\n\t\t * Determine the accessor suffix of the specified {@code propertyName}, see\n\t\t * section 8.8 \"Capitalization of inferred names\" of the JavaBean specs for more\n\t\t * details.\n\t\t * @param propertyName the property name to turn into an accessor suffix\n\t\t * @return the accessor suffix for {@code propertyName}\n\t\t */\n\t\tprivate String determineAccessorSuffix(String propertyName) {\n\t\t\tif (propertyName.length() > 1 && Character.isUpperCase(propertyName.charAt(1))) {\n\t\t\t\treturn propertyName;\n\t\t\t}\n\t\t\treturn StringUtils.capitalize(propertyName);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/context/properties/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support relating to external configuration properties.\n */\n@NullMarked\npackage org.springframework.boot.actuate.context.properties;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AbstractExposableEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.springframework.util.Assert;\n\n/**\n * Abstract base class for {@link ExposableEndpoint} implementations.\n *\n * @param <O> the operation type.\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic abstract class AbstractExposableEndpoint<O extends Operation> implements ExposableEndpoint<O> {\n\n\tprivate final EndpointId id;\n\n\tprivate final Access defaultAccess;\n\n\tprivate final List<O> operations;\n\n\t/**\n\t * Create a new {@link AbstractExposableEndpoint} instance.\n\t * @param id the endpoint id\n\t * @param defaultAccess access to the endpoint that is permitted by default\n\t * @param operations the endpoint operations\n\t * @since 3.4.0\n\t */\n\tpublic AbstractExposableEndpoint(EndpointId id, Access defaultAccess, Collection<? extends O> operations) {\n\t\tAssert.notNull(id, \"'id' must not be null\");\n\t\tAssert.notNull(operations, \"'operations' must not be null\");\n\t\tthis.id = id;\n\t\tthis.defaultAccess = defaultAccess;\n\t\tthis.operations = List.copyOf(operations);\n\t}\n\n\t@Override\n\tpublic EndpointId getEndpointId() {\n\t\treturn this.id;\n\t}\n\n\t@Override\n\tpublic Access getDefaultAccess() {\n\t\treturn this.defaultAccess;\n\t}\n\n\t@Override\n\tpublic Collection<O> getOperations() {\n\t\treturn this.operations;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Access.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.springframework.util.Assert;\n\n/**\n * Permitted level of access to an endpoint and its operations.\n *\n * @author Andy Wilkinson\n * @since 3.4.0\n */\npublic enum Access {\n\n\t/**\n\t * No access to the endpoint is permitted.\n\t */\n\tNONE,\n\n\t/**\n\t * Read-only access to the endpoint is permitted.\n\t */\n\tREAD_ONLY,\n\n\t/**\n\t * Unrestricted access to the endpoint is permitted.\n\t */\n\tUNRESTRICTED;\n\n\t/**\n\t * Cap access to a maximum permitted.\n\t * @param maxPermitted the maximum permitted access\n\t * @return this access if less than the maximum or the maximum permitted\n\t */\n\tpublic Access cap(Access maxPermitted) {\n\t\tAssert.notNull(maxPermitted, \"'maxPermitted' must not be null\");\n\t\treturn (ordinal() <= maxPermitted.ordinal()) ? this : maxPermitted;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ApiVersion.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.springframework.util.MimeType;\nimport org.springframework.util.MimeTypeUtils;\n\n/**\n * API versions supported for the actuator API. This enum may be injected into actuator\n * endpoints in order to return a response compatible with the requested version.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic enum ApiVersion implements Producible<ApiVersion> {\n\n\t/**\n\t * Version 2 (supported by Spring Boot 2.0+).\n\t */\n\tV2(\"application/vnd.spring-boot.actuator.v2+json\"),\n\n\t/**\n\t * Version 3 (supported by Spring Boot 2.2+).\n\t */\n\tV3(\"application/vnd.spring-boot.actuator.v3+json\");\n\n\t/**\n\t * The latest API version.\n\t */\n\tpublic static final ApiVersion LATEST = ApiVersion.V3;\n\n\tprivate final MimeType mimeType;\n\n\tApiVersion(String mimeType) {\n\t\tthis.mimeType = MimeTypeUtils.parseMimeType(mimeType);\n\t}\n\n\t@Override\n\tpublic MimeType getProducedMimeType() {\n\t\treturn this.mimeType;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointAccessResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\n/**\n * Resolver for the permitted level of {@link Access access} to an endpoint.\n *\n * @author Andy Wilkinson\n * @since 3.4.0\n */\npublic interface EndpointAccessResolver {\n\n\t/**\n\t * Resolves the permitted level of access for the endpoint with the given\n\t * {@code endpointId} and {@code defaultAccess}.\n\t * @param endpointId the ID of the endpoint\n\t * @param defaultAccess the default access level of the endpoint\n\t * @return the permitted level of access, never {@code null}\n\t */\n\tAccess accessFor(EndpointId endpointId, Access defaultAccess);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\n/**\n * Strategy class that can be used to filter {@link ExposableEndpoint endpoints}.\n *\n * @param <E> the endpoint type\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface EndpointFilter<E extends ExposableEndpoint<?>> {\n\n\t/**\n\t * Return {@code true} if the filter matches.\n\t * @param endpoint the endpoint to check\n\t * @return {@code true} if the filter matches\n\t */\n\tboolean match(E endpoint);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointId.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * An identifier for an actuator endpoint. Endpoint IDs may contain only letters and\n * numbers. They must begin with a lower-case letter. Case and syntax characters are\n * ignored when comparing endpoint IDs.\n *\n * @author Phillip Webb\n * @since 2.0.6\n */\npublic final class EndpointId {\n\n\tprivate static final Log logger = LogFactory.getLog(EndpointId.class);\n\n\tprivate static final Set<String> loggedWarnings = new HashSet<>();\n\n\tprivate static final Pattern VALID_PATTERN = Pattern.compile(\"[a-zA-Z0-9.-]+\");\n\n\tprivate static final Pattern WARNING_PATTERN = Pattern.compile(\"[.-]+\");\n\n\tprivate static final String MIGRATE_LEGACY_NAMES_PROPERTY = \"management.endpoints.migrate-legacy-ids\";\n\n\tprivate final String value;\n\n\tprivate final String lowerCaseValue;\n\n\tprivate final String lowerCaseAlphaNumeric;\n\n\tprivate EndpointId(String value) {\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tAssert.isTrue(VALID_PATTERN.matcher(value).matches(), \"'value' must only contain valid chars\");\n\t\tAssert.isTrue(!Character.isDigit(value.charAt(0)), \"'value' must not start with a number\");\n\t\tAssert.isTrue(!Character.isUpperCase(value.charAt(0)), \"'value' must not start with an uppercase letter\");\n\t\tif (WARNING_PATTERN.matcher(value).find()) {\n\t\t\tlogWarning(value);\n\t\t}\n\t\tthis.value = value;\n\t\tthis.lowerCaseValue = value.toLowerCase(Locale.ENGLISH);\n\t\tthis.lowerCaseAlphaNumeric = getAlphaNumerics(this.lowerCaseValue);\n\t}\n\n\tprivate String getAlphaNumerics(String value) {\n\t\tStringBuilder result = new StringBuilder(value.length());\n\t\tfor (int i = 0; i < value.length(); i++) {\n\t\t\tchar ch = value.charAt(i);\n\t\t\tif (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') {\n\t\t\t\tresult.append(ch);\n\t\t\t}\n\t\t}\n\t\treturn result.toString();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.lowerCaseAlphaNumeric.equals(((EndpointId) obj).lowerCaseAlphaNumeric);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.lowerCaseAlphaNumeric.hashCode();\n\t}\n\n\t/**\n\t * Return a lower-case version of the endpoint ID.\n\t * @return the lower-case endpoint ID\n\t */\n\tpublic String toLowerCaseString() {\n\t\treturn this.lowerCaseValue;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link EndpointId} of the specified value.\n\t * @param value the endpoint ID value\n\t * @return an {@link EndpointId} instance\n\t */\n\tpublic static EndpointId of(String value) {\n\t\treturn new EndpointId(value);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link EndpointId} of the specified value. This\n\t * variant will respect the {@code management.endpoints.migrate-legacy-names} property\n\t * if it has been set in the {@link Environment}.\n\t * @param environment the Spring environment\n\t * @param value the endpoint ID value\n\t * @return an {@link EndpointId} instance\n\t * @since 2.2.0\n\t */\n\tpublic static EndpointId of(Environment environment, String value) {\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\treturn new EndpointId(migrateLegacyId(environment, value));\n\t}\n\n\tprivate static String migrateLegacyId(Environment environment, String value) {\n\t\tif (environment.getProperty(MIGRATE_LEGACY_NAMES_PROPERTY, Boolean.class, false)) {\n\t\t\treturn value.replaceAll(\"[-.]+\", \"\");\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link EndpointId} from a property value. More\n\t * lenient than {@link #of(String)} to allow for common \"relaxed\" property variants.\n\t * @param value the property value to convert\n\t * @return an {@link EndpointId} instance\n\t */\n\tpublic static EndpointId fromPropertyValue(String value) {\n\t\treturn new EndpointId(value.replace(\"-\", \"\"));\n\t}\n\n\tstatic void resetLoggedWarnings() {\n\t\tloggedWarnings.clear();\n\t}\n\n\tprivate static void logWarning(String value) {\n\t\tif (logger.isWarnEnabled() && loggedWarnings.add(value)) {\n\t\t\tlogger.warn(\"Endpoint ID '\" + value + \"' contains invalid characters, please migrate to a valid format.\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/EndpointsSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Collection;\n\n/**\n * Provides access to a collection of {@link ExposableEndpoint endpoints}.\n *\n * @param <E> the endpoint type\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface EndpointsSupplier<E extends ExposableEndpoint<?>> {\n\n\t/**\n\t * Return the provided endpoints.\n\t * @return the endpoints\n\t */\n\tCollection<E> getEndpoints();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ExposableEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Collection;\n\n/**\n * Information describing an endpoint that can be exposed in some technology specific way.\n *\n * @param <O> the type of the endpoint's operations\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface ExposableEndpoint<O extends Operation> {\n\n\t/**\n\t * Return the endpoint ID.\n\t * @return the endpoint ID\n\t */\n\tEndpointId getEndpointId();\n\n\t/**\n\t * Returns the access to the endpoint that is permitted by default.\n\t * @return access that is permitted by default\n\t * @since 3.4.0\n\t */\n\tAccess getDefaultAccess();\n\n\t/**\n\t * Returns the operations of the endpoint.\n\t * @return the operations\n\t */\n\tCollection<O> getOperations();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InvalidEndpointRequestException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Indicate that an endpoint request is invalid.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class InvalidEndpointRequestException extends RuntimeException {\n\n\tprivate final @Nullable String reason;\n\n\tpublic InvalidEndpointRequestException(String message, @Nullable String reason) {\n\t\tsuper(message);\n\t\tthis.reason = reason;\n\t}\n\n\tpublic InvalidEndpointRequestException(String message, @Nullable String reason, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.reason = reason;\n\t}\n\n\t/**\n\t * Return the reason explaining why the request is invalid, potentially {@code null}.\n\t * @return the reason for the failure\n\t */\n\tpublic @Nullable String getReason() {\n\t\treturn this.reason;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/InvocationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.security.Principal;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.util.Assert;\n\n/**\n * The context for the {@link OperationInvoker invocation of an operation}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class InvocationContext {\n\n\tprivate final Map<String, Object> arguments;\n\n\tprivate final List<OperationArgumentResolver> argumentResolvers;\n\n\t/**\n\t * Creates a new context for an operation being invoked by the given\n\t * {@code securityContext} with the given available {@code arguments}.\n\t * @param securityContext the current security context. Never {@code null}\n\t * @param arguments the arguments available to the operation. Never {@code null}\n\t * @param argumentResolvers resolvers for additional arguments should be available to\n\t * the operation.\n\t */\n\tpublic InvocationContext(SecurityContext securityContext, Map<String, Object> arguments,\n\t\t\tOperationArgumentResolver @Nullable ... argumentResolvers) {\n\t\tAssert.notNull(securityContext, \"'securityContext' must not be null\");\n\t\tAssert.notNull(arguments, \"'arguments' must not be null\");\n\t\tthis.arguments = arguments;\n\t\tthis.argumentResolvers = new ArrayList<>();\n\t\tif (argumentResolvers != null) {\n\t\t\tthis.argumentResolvers.addAll(Arrays.asList(argumentResolvers));\n\t\t}\n\t\tthis.argumentResolvers.add(OperationArgumentResolver.of(SecurityContext.class, () -> securityContext));\n\t\tthis.argumentResolvers.add(OperationArgumentResolver.of(Principal.class, securityContext::getPrincipal));\n\t\tthis.argumentResolvers.add(OperationArgumentResolver.of(ApiVersion.class, () -> ApiVersion.LATEST));\n\t}\n\n\t/**\n\t * Return the invocation arguments.\n\t * @return the arguments\n\t */\n\tpublic Map<String, Object> getArguments() {\n\t\treturn this.arguments;\n\t}\n\n\t/**\n\t * Resolves an argument with the given {@code argumentType}.\n\t * @param <T> type of the argument\n\t * @param argumentType type of the argument\n\t * @return resolved argument of the required type or {@code null}\n\t * @since 2.5.0\n\t * @see #canResolve(Class)\n\t */\n\tpublic <T> @Nullable T resolveArgument(Class<T> argumentType) {\n\t\tfor (OperationArgumentResolver argumentResolver : this.argumentResolvers) {\n\t\t\tif (argumentResolver.canResolve(argumentType)) {\n\t\t\t\tT result = argumentResolver.resolve(argumentType);\n\t\t\t\tif (result != null) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns whether the context is capable of resolving an argument of the given\n\t * {@code type}. Note that, even when {@code true} is returned,\n\t * {@link #resolveArgument argument resolution} will return {@code null} if no\n\t * argument of the required type is available.\n\t * @param type argument type\n\t * @return {@code true} if resolution of arguments of the given type is possible,\n\t * otherwise {@code false}.\n\t * @since 2.5.0\n\t * @see #resolveArgument(Class)\n\t */\n\tpublic boolean canResolve(Class<?> type) {\n\t\tfor (OperationArgumentResolver argumentResolver : this.argumentResolvers) {\n\t\t\tif (argumentResolver.canResolve(type)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Operation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * An operation on an {@link ExposableEndpoint endpoint}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface Operation {\n\n\t/**\n\t * Returns the {@link OperationType type} of the operation.\n\t * @return the type\n\t */\n\tOperationType getType();\n\n\t/**\n\t * Invoke the underlying operation using the given {@code context}. Results intended\n\t * to be returned in the body of the response should additionally implement\n\t * {@link OperationResponseBody}.\n\t * @param context the context to use when invoking the operation\n\t * @return the result of the operation, may be {@code null}\n\t */\n\t@Nullable Object invoke(InvocationContext context);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/OperationArgumentResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Resolver for an argument of an {@link Operation}.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic interface OperationArgumentResolver {\n\n\t/**\n\t * Return whether an argument of the given {@code type} can be resolved.\n\t * @param type argument type\n\t * @return {@code true} if an argument of the required type can be resolved, otherwise\n\t * {@code false}\n\t */\n\tboolean canResolve(Class<?> type);\n\n\t/**\n\t * Resolves an argument of the given {@code type}.\n\t * @param <T> required type of the argument\n\t * @param type argument type\n\t * @return an argument of the required type, or {@code null}\n\t */\n\t<T> @Nullable T resolve(Class<T> type);\n\n\t/**\n\t * Factory method that creates an {@link OperationArgumentResolver} for a specific\n\t * type using a {@link Supplier}.\n\t * @param <T> the resolvable type\n\t * @param type the resolvable type\n\t * @param supplier the value supplier\n\t * @return an {@link OperationArgumentResolver} instance\n\t */\n\tstatic <T> OperationArgumentResolver of(Class<T> type, Supplier<? extends @Nullable T> supplier) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tAssert.notNull(supplier, \"'supplier' must not be null\");\n\t\treturn new OperationArgumentResolver() {\n\n\t\t\t@Override\n\t\t\tpublic boolean canResolve(Class<?> actualType) {\n\t\t\t\treturn actualType.equals(type);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tpublic <R> @Nullable R resolve(Class<R> argumentType) {\n\t\t\t\treturn (R) supplier.get();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/OperationFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\n/**\n * Strategy class that can be used to filter {@link Operation operations}.\n *\n * @param <O> the operation type\n * @author Andy Wilkinson\n * @since 3.4.0\n */\n@FunctionalInterface\npublic interface OperationFilter<O extends Operation> {\n\n\t/**\n\t * Return {@code true} if the filter matches.\n\t * @param endpointId the ID of the endpoint to which the operation belongs\n\t * @param operation the operation to check\n\t * @param defaultAccess the default permitted level of access to the endpoint\n\t * @return {@code true} if the filter matches\n\t */\n\tboolean match(O operation, EndpointId endpointId, Access defaultAccess);\n\n\t/**\n\t * Return an {@link OperationFilter} that filters based on the allowed {@link Access\n\t * access} as determined by an {@link EndpointAccessResolver access resolver}.\n\t * @param <O> the operation type\n\t * @param accessResolver the access resolver\n\t * @return a new {@link OperationFilter}\n\t */\n\tstatic <O extends Operation> OperationFilter<O> byAccess(EndpointAccessResolver accessResolver) {\n\t\treturn (operation, endpointId, defaultAccess) -> {\n\t\t\tAccess access = accessResolver.accessFor(endpointId, defaultAccess);\n\t\t\treturn switch (access) {\n\t\t\t\tcase NONE -> false;\n\t\t\t\tcase READ_ONLY -> operation.getType() == OperationType.READ;\n\t\t\t\tcase UNRESTRICTED -> true;\n\t\t\t};\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/OperationResponseBody.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Tagging interface used to indicate that an operation result is intended to be returned\n * in the body of the response. Primarily intended to support JSON serialization using an\n * endpoint specific {@link JsonMapper}.\n *\n * @author Phillip Webb\n * @since 3.0.0\n */\npublic interface OperationResponseBody {\n\n\t/**\n\t * Return a {@link OperationResponseBody} {@link Map} instance containing entries from\n\t * the given {@code map}.\n\t * @param <K> the key type\n\t * @param <V> the value type\n\t * @param map the source map or {@code null}\n\t * @return a {@link OperationResponseBody} version of the map or {@code null}\n\t */\n\t@Contract(\"!null -> !null\")\n\tstatic <K, V> @Nullable Map<K, V> of(@Nullable Map<K, V> map) {\n\t\treturn (map != null) ? new OperationResponseBodyMap<>(map) : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/OperationResponseBodyMap.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * {@link LinkedHashMap} to support {@link OperationResponseBody#of(java.util.Map)}.\n *\n * @param <K> the key type\n * @param <V> the value type\n * @author Phillip Webb\n */\nclass OperationResponseBodyMap<K, V> extends LinkedHashMap<K, V> implements OperationResponseBody {\n\n\tOperationResponseBodyMap(Map<? extends K, ? extends V> map) {\n\t\tsuper(map);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/OperationType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\n/**\n * An enumeration of the different types of operation supported by an endpoint.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n * @see Operation\n */\npublic enum OperationType {\n\n\t/**\n\t * A read operation.\n\t */\n\tREAD,\n\n\t/**\n\t * A write operation.\n\t */\n\tWRITE,\n\n\t/**\n\t * A delete operation.\n\t */\n\tDELETE\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Producible.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.util.MimeType;\n\n/**\n * Interface that can be implemented by any {@link Enum} that represents a finite set of\n * producible mime-types.\n * <p>\n * Can be used with {@link ReadOperation @ReadOperation},\n * {@link WriteOperation @WriteOperation} and {@link DeleteOperation @DeleteOperation}\n * annotations to quickly define a list of {@code produces} values.\n * <p>\n * {@link Producible} types can also be injected into operations when the underlying\n * technology supports content negotiation. For example, with web based endpoints, the\n * value of the {@code Producible} enum is resolved using the {@code Accept} header of the\n * request. When multiple values are equally acceptable, the value with the highest\n * {@link Enum#ordinal() ordinal} is used.\n *\n * @param <E> enum type that implements this interface\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic interface Producible<E extends Enum<E> & Producible<E>> {\n\n\t/**\n\t * Mime type that can be produced.\n\t * @return the producible mime type\n\t */\n\tMimeType getProducedMimeType();\n\n\t/**\n\t * Return if this enum value should be used as the default value when an accept header\n\t * of &#42;&#47;&#42; is provided, or if the {@code Accept} header is missing. Only\n\t * one value can be marked as default. If no value is marked, then the value with the\n\t * highest {@link Enum#ordinal() ordinal} is used as the default.\n\t * @return if this value should be used as the default value\n\t * @since 2.5.6\n\t */\n\tdefault boolean isDefault() {\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ProducibleOperationArgumentResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.MimeTypeUtils;\n\n/**\n * An {@link OperationArgumentResolver} for {@link Producible producible enums}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.5.0\n */\npublic class ProducibleOperationArgumentResolver implements OperationArgumentResolver {\n\n\tprivate final Supplier<@Nullable List<String>> accepts;\n\n\t/**\n\t * Create a new {@link ProducibleOperationArgumentResolver} instance.\n\t * @param accepts supplier that returns accepted mime types\n\t */\n\tpublic ProducibleOperationArgumentResolver(Supplier<@Nullable List<String>> accepts) {\n\t\tthis.accepts = accepts;\n\t}\n\n\t@Override\n\tpublic boolean canResolve(Class<?> type) {\n\t\treturn Producible.class.isAssignableFrom(type) && Enum.class.isAssignableFrom(type);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Override\n\tpublic <T> @Nullable T resolve(Class<T> type) {\n\t\treturn (T) resolveProducible((Class<Enum<? extends Producible<?>>>) type);\n\t}\n\n\tprivate @Nullable Enum<? extends Producible<?>> resolveProducible(Class<Enum<? extends Producible<?>>> type) {\n\t\tList<String> accepts = this.accepts.get();\n\t\tList<Enum<? extends Producible<?>>> values = getValues(type);\n\t\tif (CollectionUtils.isEmpty(accepts)) {\n\t\t\treturn getDefaultValue(values);\n\t\t}\n\t\tEnum<? extends Producible<?>> result = null;\n\t\tfor (String accept : accepts) {\n\t\t\tfor (String mimeType : MimeTypeUtils.tokenize(accept)) {\n\t\t\t\tresult = mostRecent(result, forMimeType(values, MimeTypeUtils.parseMimeType(mimeType)));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate @Nullable Enum<? extends Producible<?>> mostRecent(@Nullable Enum<? extends Producible<?>> existing,\n\t\t\t@Nullable Enum<? extends Producible<?>> candidate) {\n\t\tint existingOrdinal = (existing != null) ? existing.ordinal() : -1;\n\t\tint candidateOrdinal = (candidate != null) ? candidate.ordinal() : -1;\n\t\treturn (candidateOrdinal > existingOrdinal) ? candidate : existing;\n\t}\n\n\tprivate @Nullable Enum<? extends Producible<?>> forMimeType(List<Enum<? extends Producible<?>>> values,\n\t\t\tMimeType mimeType) {\n\t\tif (mimeType.isWildcardType() && mimeType.isWildcardSubtype()) {\n\t\t\treturn getDefaultValue(values);\n\t\t}\n\t\tfor (Enum<? extends Producible<?>> candidate : values) {\n\t\t\tif (mimeType.isCompatibleWith(((Producible<?>) candidate).getProducedMimeType())) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<Enum<? extends Producible<?>>> getValues(Class<Enum<? extends Producible<?>>> type) {\n\t\tList<Enum<? extends Producible<?>>> values = Arrays.asList(type.getEnumConstants());\n\t\tCollections.reverse(values);\n\t\tAssert.state(values.stream().filter(this::isDefault).count() <= 1,\n\t\t\t\t\"Multiple default values declared in \" + type.getName());\n\t\treturn values;\n\t}\n\n\tprivate Enum<? extends Producible<?>> getDefaultValue(List<Enum<? extends Producible<?>>> values) {\n\t\treturn values.stream().filter(this::isDefault).findFirst().orElseGet(() -> values.get(0));\n\t}\n\n\tprivate boolean isDefault(Enum<? extends Producible<?>> value) {\n\t\treturn ((Producible<?>) value).isDefault();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/SanitizableData.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * Value object that represents the data that can be used by a {@link SanitizingFunction}.\n *\n * @author Madhura Bhave\n * @author Rohan Goyal\n * @since 2.6.0\n **/\npublic final class SanitizableData {\n\n\t/**\n\t * Represents a sanitized value.\n\t */\n\tpublic static final String SANITIZED_VALUE = \"******\";\n\n\tprivate final @Nullable PropertySource<?> propertySource;\n\n\tprivate final String key;\n\n\tprivate @Nullable String lowerCaseKey;\n\n\tprivate final @Nullable Object value;\n\n\t/**\n\t * Create a new {@link SanitizableData} instance.\n\t * @param propertySource the property source that provided the data or {@code null}.\n\t * @param key the data key\n\t * @param value the data value\n\t */\n\tpublic SanitizableData(@Nullable PropertySource<?> propertySource, String key, @Nullable Object value) {\n\t\tAssert.notNull(key, \"'key' must not be null\");\n\t\tthis.propertySource = propertySource;\n\t\tthis.key = key;\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Return the property source that provided the data or {@code null} If the data was\n\t * not from a {@link PropertySource}.\n\t * @return the property source that provided the data\n\t */\n\tpublic @Nullable PropertySource<?> getPropertySource() {\n\t\treturn this.propertySource;\n\t}\n\n\t/**\n\t * Return the key of the data.\n\t * @return the data key\n\t */\n\tpublic String getKey() {\n\t\treturn this.key;\n\t}\n\n\t/**\n\t * Return the key as a lowercase value.\n\t * @return the key as a lowercase value\n\t * @since 3.5.0\n\t */\n\tpublic String getLowerCaseKey() {\n\t\tString result = this.lowerCaseKey;\n\t\tif (result == null) {\n\t\t\tresult = this.key.toLowerCase(Locale.getDefault());\n\t\t\tthis.lowerCaseKey = result;\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the value of the data.\n\t * @return the data value\n\t */\n\tpublic @Nullable Object getValue() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Return a new {@link SanitizableData} instance with sanitized value.\n\t * @return a new sanitizable data instance.\n\t * @since 3.1.0\n\t */\n\tpublic SanitizableData withSanitizedValue() {\n\t\treturn withValue(SANITIZED_VALUE);\n\t}\n\n\t/**\n\t * Return a new {@link SanitizableData} instance with a different value.\n\t * @param value the new value (often {@link #SANITIZED_VALUE}\n\t * @return a new sanitizable data instance\n\t */\n\tpublic SanitizableData withValue(@Nullable Object value) {\n\t\treturn new SanitizableData(this.propertySource, this.key, value);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Sanitizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Strategy that should be used by endpoint implementations to sanitize potentially\n * sensitive keys.\n *\n * @author Christian Dupuis\n * @author Toshiaki Maki\n * @author Phillip Webb\n * @author Nicolas Lejeune\n * @author Stephane Nicoll\n * @author HaiTao Zhang\n * @author Chris Bono\n * @author David Good\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic class Sanitizer {\n\n\tprivate final List<SanitizingFunction> sanitizingFunctions = new ArrayList<>();\n\n\t/**\n\t * Create a new {@link Sanitizer} instance.\n\t */\n\tpublic Sanitizer() {\n\t\tthis(Collections.emptyList());\n\t}\n\n\t/**\n\t * Create a new {@link Sanitizer} instance with sanitizing functions.\n\t * @param sanitizingFunctions the sanitizing functions to apply\n\t * @since 2.6.0\n\t */\n\tpublic Sanitizer(Iterable<SanitizingFunction> sanitizingFunctions) {\n\t\tsanitizingFunctions.forEach(this.sanitizingFunctions::add);\n\t}\n\n\t/**\n\t * Sanitize the value from the given {@link SanitizableData} using the available\n\t * {@link SanitizingFunction}s.\n\t * @param data the sanitizable data\n\t * @param showUnsanitized whether to show the unsanitized values or not\n\t * @return the potentially updated data\n\t * @since 3.0.0\n\t */\n\tpublic @Nullable Object sanitize(SanitizableData data, boolean showUnsanitized) {\n\t\tObject value = data.getValue();\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (!showUnsanitized) {\n\t\t\treturn SanitizableData.SANITIZED_VALUE;\n\t\t}\n\t\tfor (SanitizingFunction sanitizingFunction : this.sanitizingFunctions) {\n\t\t\tdata = sanitizingFunction.applyUnlessFiltered(data);\n\t\t\tObject sanitizedValue = data.getValue();\n\t\t\tif (!value.equals(sanitizedValue)) {\n\t\t\t\treturn sanitizedValue;\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/SanitizingFunction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.function.BiPredicate;\nimport java.util.function.Predicate;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Function that takes a {@link SanitizableData} and applies sanitization to the value, if\n * necessary. Can be used by a {@link Sanitizer} to determine the sanitized value.\n * <p>\n * This interface also provides convenience methods that can help build a\n * {@link SanitizingFunction} instances, for example to return from a {@code @Bean}\n * method. See {@link #sanitizeValue()} for an example.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.6.0\n * @see Sanitizer\n */\n@FunctionalInterface\npublic interface SanitizingFunction {\n\n\t/**\n\t * Apply the sanitizing function to the given data.\n\t * @param data the data to sanitize\n\t * @return the sanitized data or the original instance is no sanitization is applied\n\t */\n\tSanitizableData apply(SanitizableData data);\n\n\t/**\n\t * Return an optional filter that determines if the sanitizing function applies.\n\t * @return a predicate used to filter functions or {@code null} if no filter is\n\t * declared\n\t * @since 3.5.0\n\t * @see #applyUnlessFiltered(SanitizableData)\n\t */\n\tdefault @Nullable Predicate<SanitizableData> filter() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Apply the sanitizing function as long as the filter passes or there is no filter.\n\t * @param data the data to sanitize\n\t * @return the sanitized data or the original instance is no sanitization is applied\n\t * @since 3.5.0\n\t */\n\tdefault SanitizableData applyUnlessFiltered(SanitizableData data) {\n\t\tPredicate<SanitizableData> filter = filter();\n\t\treturn (filter == null || filter.test(data)) ? apply(data) : data;\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data is\n\t * likely to contain a sensitive value. This method can help construct a useful\n\t * sanitizing function, but may not catch all sensitive data so care should be taken\n\t * to test the results for your specific environment.\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifLikelySensitive() {\n\t\treturn ifLikelyCredential().ifLikelyUri().ifLikelySensitiveProperty().ifVcapServices();\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data is\n\t * likely to contain a credential. This method can help construct a useful sanitizing\n\t * function, but may not catch all sensitive data so care should be taken to test the\n\t * results for your specific environment.\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifLikelyCredential() {\n\t\treturn ifKeyEndsWith(\"password\", \"secret\", \"key\", \"token\").ifKeyContains(\"credentials\");\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data is\n\t * likely to contain a URI. This method can help construct a useful sanitizing\n\t * function, but may not catch all sensitive data so care should be taken to test the\n\t * results for your specific environment.\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifLikelyUri() {\n\t\treturn ifKeyEndsWith(\"uri\", \"uris\", \"url\", \"urls\", \"address\", \"addresses\");\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data is\n\t * likely to contain a sensitive property value. This method can help construct a\n\t * useful sanitizing function, but may not catch all sensitive data so care should be\n\t * taken to test the results for your specific environment.\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifLikelySensitiveProperty() {\n\t\treturn ifKeyMatches(\"sun.java.command\", \"^spring[._]application[._]json$\");\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data is for\n\t * VCAP services.\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\n\tdefault SanitizingFunction ifVcapServices() {\n\t\treturn ifKeyEquals(\"vcap_services\").ifKeyMatches(\"^vcap\\\\.services.*$\");\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key is\n\t * equal to any of the given values (ignoring case).\n\t * @param values the case insensitive values that the key can equal\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyEquals(String... values) {\n\t\tAssert.notNull(values, \"'values' must not be null\");\n\t\treturn ifKeyMatchesIgnoringCase(String::equals, values);\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key ends\n\t * with any of the given values (ignoring case).\n\t * @param suffixes the case insensitive suffixes that they key can end with\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyEndsWith(String... suffixes) {\n\t\tAssert.notNull(suffixes, \"'suffixes' must not be null\");\n\t\treturn ifKeyMatchesIgnoringCase(String::endsWith, suffixes);\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key\n\t * contains any of the given values (ignoring case).\n\t * @param values the case insensitive values that the key can contain\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyContains(String... values) {\n\t\tAssert.notNull(values, \"'values' must not be null\");\n\t\treturn ifKeyMatchesIgnoringCase(String::contains, values);\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key and\n\t * any of the values match the given predicate. The predicate is only called with\n\t * lower case values.\n\t * @param predicate the predicate used to check the key against a value. The key is\n\t * the first argument and the value is the second. Both are converted to lower case\n\t * @param values the case insensitive values that the key can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyMatchesIgnoringCase(BiPredicate<String, String> predicate, String... values) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\tAssert.notNull(values, \"'values' must not be null\");\n\t\treturn ifMatches(Arrays.stream(values).map((value) -> onKeyIgnoringCase(predicate, value)).toList());\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key\n\t * matches any of the given regex patterns (ignoring case).\n\t * @param regexes the case insensitive regexes that the key can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyMatches(String... regexes) {\n\t\tAssert.notNull(regexes, \"'regexes' must not be null\");\n\t\treturn ifKeyMatches(Arrays.stream(regexes).map(this::caseInsensitivePattern).toArray(Pattern[]::new));\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key\n\t * matches any of the given patterns.\n\t * @param patterns the patterns that the key can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyMatches(Pattern... patterns) {\n\t\tAssert.notNull(patterns, \"'patterns' must not be null\");\n\t\treturn ifKeyMatches(Arrays.stream(patterns).map(Pattern::asMatchPredicate).toList());\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key\n\t * matches any of the given predicates.\n\t * @param predicates the predicates that the key can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyMatches(List<Predicate<String>> predicates) {\n\t\tAssert.notNull(predicates, \"'predicates' must not be null\");\n\t\treturn ifMatches(predicates.stream().map(this::onKey).toList());\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data key\n\t * matches any of the given predicate.\n\t * @param predicate the predicate that the key can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifKeyMatches(Predicate<String> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn ifMatches(onKey(predicate));\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data string\n\t * value matches any of the given regex patterns (ignoring case).\n\t * @param regexes the case insensitive regexes that the values string can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifValueStringMatches(String... regexes) {\n\t\tAssert.notNull(regexes, \"'regexes' must not be null\");\n\t\treturn ifValueStringMatches(Arrays.stream(regexes).map(this::caseInsensitivePattern).toArray(Pattern[]::new));\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data string\n\t * value matches any of the given patterns.\n\t * @param patterns the patterns that the value string can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifValueStringMatches(Pattern... patterns) {\n\t\tAssert.notNull(patterns, \"'patterns' must not be null\");\n\t\treturn ifValueStringMatches(Arrays.stream(patterns).map(Pattern::asMatchPredicate).toList());\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data string\n\t * value matches any of the given predicates.\n\t * @param predicates the predicates that the value string can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\n\tdefault SanitizingFunction ifValueStringMatches(List<Predicate<String>> predicates) {\n\t\tAssert.notNull(predicates, \"'predicates' must not be null\");\n\t\treturn ifMatches(predicates.stream().map(this::onValueString).toList());\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data value\n\t * matches any of the given predicates.\n\t * @param predicates the predicates that the value can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifValueMatches(List<Predicate<Object>> predicates) {\n\t\tAssert.notNull(predicates, \"'predicates' must not be null\");\n\t\treturn ifMatches(predicates.stream().map(this::onValue).toList());\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data string\n\t * value matches the given predicate.\n\t * @param predicate the predicate that the value string can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\n\tdefault SanitizingFunction ifValueStringMatches(Predicate<String> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn ifMatches(onValueString(predicate));\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data value\n\t * matches the given predicate.\n\t * @param predicate the predicate that the value can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifValueMatches(Predicate<@Nullable Object> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn ifMatches((data) -> predicate.test(data.getValue()));\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data matches\n\t * any of the given predicates.\n\t * @param predicates the predicates that the data can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifMatches(List<Predicate<SanitizableData>> predicates) {\n\t\tAssert.notNull(predicates, \"'predicates' must not be null\");\n\t\tPredicate<SanitizableData> combined = null;\n\t\tfor (Predicate<SanitizableData> predicate : predicates) {\n\t\t\tcombined = (combined != null) ? combined.or(predicate) : predicate;\n\t\t}\n\t\tAssert.state(combined != null, \"'combined' must not be null\");\n\t\treturn ifMatches(combined);\n\t}\n\n\t/**\n\t * Return a new function with a filter that <em>also</em> applies if the data matches\n\t * the given predicate.\n\t * @param predicate the predicate that the data can match\n\t * @return a new sanitizing function with an updated {@link #filter()}\n\t * @since 3.5.0\n\t * @see #filter()\n\t * @see #sanitizeValue()\n\t */\n\tdefault SanitizingFunction ifMatches(Predicate<SanitizableData> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\tPredicate<SanitizableData> filter = filter();\n\t\tPredicate<SanitizableData> newFilter = (filter != null) ? filter.or(predicate) : predicate;\n\t\treturn new SanitizingFunction() {\n\n\t\t\t@Override\n\t\t\tpublic Predicate<SanitizableData> filter() {\n\t\t\t\treturn newFilter;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic SanitizableData apply(SanitizableData data) {\n\t\t\t\treturn SanitizingFunction.this.apply(data);\n\t\t\t}\n\n\t\t};\n\t}\n\n\tprivate Pattern caseInsensitivePattern(String regex) {\n\t\tAssert.notNull(regex, \"'regex' must not be null\");\n\t\treturn Pattern.compile(regex, Pattern.CASE_INSENSITIVE);\n\t}\n\n\tprivate Predicate<SanitizableData> onKeyIgnoringCase(BiPredicate<String, String> predicate, String value) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\tString lowerCaseValue = value.toLowerCase(Locale.getDefault());\n\t\treturn (data) -> predicate.test(data.getLowerCaseKey(), lowerCaseValue);\n\t}\n\n\tprivate Predicate<SanitizableData> onKey(Predicate<String> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn (data) -> predicate.test(data.getKey());\n\t}\n\n\tprivate Predicate<SanitizableData> onValue(Predicate<Object> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn (data) -> nullSafeTest(data.getValue(), predicate);\n\t}\n\n\tprivate Predicate<SanitizableData> onValueString(Predicate<String> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn (data) -> nullSafeTest((data.getValue() != null) ? data.getValue().toString() : null, predicate);\n\t}\n\n\tprivate <T> boolean nullSafeTest(@Nullable T value, Predicate<T> predicate) {\n\t\treturn value != null && predicate.test(value);\n\t}\n\n\t/**\n\t * Factory method to return a {@link SanitizingFunction} that sanitizes the value.\n\t * This method is often chained with one or more {@code if...} methods. For example:\n\t * <pre class=\"code\">\n\t * return SanitizingFunction.sanitizeValue()\n\t * \t.ifKeyContains(\"password\", \"secret\")\n\t * \t.ifValueStringMatches(\"^gh._[a-zA-Z0-9]{36}$\");\n\t * </pre>\n\t * @return a {@link SanitizingFunction} that sanitizes values.\n\t */\n\tstatic SanitizingFunction sanitizeValue() {\n\t\treturn SanitizableData::withSanitizedValue;\n\t}\n\n\t/**\n\t * Helper method that can be used working with a sanitizingFunction as a lambda. For\n\t * example: <pre class=\"code\">\n\t * SanitizingFunction.of((data) -> data.withValue(\"----\")).ifKeyContains(\"password\");\n\t * </pre>\n\t * @param sanitizingFunction the sanitizing function lambda\n\t * @return a {@link SanitizingFunction} for further method calls\n\t * @since 3.5.0\n\t */\n\tstatic SanitizingFunction of(SanitizingFunction sanitizingFunction) {\n\t\tAssert.notNull(sanitizingFunction, \"'sanitizingFunction' must not be null\");\n\t\treturn sanitizingFunction;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/SecurityContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.security.Principal;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Security context in which an endpoint is being invoked.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic interface SecurityContext {\n\n\t/**\n\t * Empty security context.\n\t */\n\tSecurityContext NONE = new SecurityContext() {\n\n\t\t@Override\n\t\tpublic @Nullable Principal getPrincipal() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isUserInRole(String role) {\n\t\t\treturn false;\n\t\t}\n\n\t};\n\n\t/**\n\t * Return the currently authenticated {@link Principal} or {@code null}.\n\t * @return the principal or {@code null}\n\t */\n\t@Nullable Principal getPrincipal();\n\n\t/**\n\t * Returns {@code true} if the currently authenticated user is in the given\n\t * {@code role}, or false otherwise.\n\t * @param role name of the role\n\t * @return {@code true} if the user is in the given role\n\t */\n\tboolean isUserInRole(String role);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/Show.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.security.Principal;\nimport java.util.Collection;\n\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Options for showing data in endpoint responses.\n *\n * @author Madhura Bhave\n * @since 3.0.0\n */\npublic enum Show {\n\n\t/**\n\t * Never show the item in the response.\n\t */\n\tNEVER,\n\n\t/**\n\t * Show the item in the response when accessed by an authorized user.\n\t */\n\tWHEN_AUTHORIZED,\n\n\t/**\n\t * Always show the item in the response.\n\t */\n\tALWAYS;\n\n\t/**\n\t * Return if data should be shown when no {@link SecurityContext} is available.\n\t * @param unauthorizedResult the result to used for an unauthorized user\n\t * @return if data should be shown\n\t */\n\tpublic boolean isShown(boolean unauthorizedResult) {\n\t\treturn switch (this) {\n\t\t\tcase NEVER -> false;\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase WHEN_AUTHORIZED -> unauthorizedResult;\n\t\t};\n\t}\n\n\t/**\n\t * Return if data should be shown.\n\t * @param securityContext the security context\n\t * @param roles the required roles\n\t * @return if data should be shown\n\t */\n\tpublic boolean isShown(SecurityContext securityContext, Collection<String> roles) {\n\t\treturn switch (this) {\n\t\t\tcase NEVER -> false;\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase WHEN_AUTHORIZED -> isAuthorized(securityContext, roles);\n\t\t};\n\t}\n\n\tprivate boolean isAuthorized(SecurityContext securityContext, Collection<String> roles) {\n\t\tPrincipal principal = securityContext.getPrincipal();\n\t\tif (principal == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (CollectionUtils.isEmpty(roles)) {\n\t\t\treturn true;\n\t\t}\n\t\tboolean checkAuthorities = isSpringSecurityAuthentication(principal);\n\t\tfor (String role : roles) {\n\t\t\tif (securityContext.isUserInRole(role)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (checkAuthorities) {\n\t\t\t\tAuthentication authentication = (Authentication) principal;\n\t\t\t\tfor (GrantedAuthority authority : authentication.getAuthorities()) {\n\t\t\t\t\tString name = authority.getAuthority();\n\t\t\t\t\tif (role.equals(name)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isSpringSecurityAuthentication(Principal principal) {\n\t\treturn ClassUtils.isPresent(\"org.springframework.security.core.Authentication\", null)\n\t\t\t\t&& (principal instanceof Authentication);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/AbstractDiscoveredEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.actuate.endpoint.AbstractExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\n\n/**\n * Abstract base class for {@link ExposableEndpoint endpoints} discovered by a\n * {@link EndpointDiscoverer}.\n *\n * @param <O> the operation type\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic abstract class AbstractDiscoveredEndpoint<O extends Operation> extends AbstractExposableEndpoint<O>\n\t\timplements DiscoveredEndpoint<O> {\n\n\tprivate final EndpointDiscoverer<?, ?> discoverer;\n\n\tprivate final Object endpointBean;\n\n\t/**\n\t * Create a new {@link AbstractDiscoveredEndpoint} instance.\n\t * @param discoverer the discoverer that discovered the endpoint\n\t * @param endpointBean the primary source bean\n\t * @param id the ID of the endpoint\n\t * @param defaultAccess access to the endpoint that is permitted by default\n\t * @param operations the endpoint operations\n\t * @since 3.4.0\n\t */\n\tpublic AbstractDiscoveredEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id,\n\t\t\tAccess defaultAccess, Collection<? extends O> operations) {\n\t\tsuper(id, defaultAccess, operations);\n\t\tAssert.notNull(discoverer, \"'discoverer' must not be null\");\n\t\tAssert.notNull(endpointBean, \"'endpointBean' must not be null\");\n\t\tthis.discoverer = discoverer;\n\t\tthis.endpointBean = endpointBean;\n\t}\n\n\t@Override\n\tpublic Object getEndpointBean() {\n\t\treturn this.endpointBean;\n\t}\n\n\t@Override\n\tpublic boolean wasDiscoveredBy(Class<? extends EndpointDiscoverer<?, ?>> discoverer) {\n\t\treturn discoverer.isInstance(this.discoverer);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this).append(\"discoverer\", this.discoverer.getClass().getName())\n\t\t\t.append(\"endpointBean\", this.endpointBean.getClass().getName());\n\t\tappendFields(creator);\n\t\treturn creator.toString();\n\t}\n\n\tprotected void appendFields(ToStringCreator creator) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/AbstractDiscoveredOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.core.style.ToStringCreator;\n\n/**\n * Abstract base class for {@link Operation endpoints operations} discovered by a\n * {@link EndpointDiscoverer}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic abstract class AbstractDiscoveredOperation implements Operation {\n\n\tprivate final OperationMethod operationMethod;\n\n\tprivate final OperationInvoker invoker;\n\n\t/**\n\t * Create a new {@link AbstractDiscoveredOperation} instance.\n\t * @param operationMethod the method backing the operation\n\t * @param invoker the operation invoker to use\n\t */\n\tpublic AbstractDiscoveredOperation(DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {\n\t\tthis.operationMethod = operationMethod;\n\t\tthis.invoker = invoker;\n\t}\n\n\tpublic OperationMethod getOperationMethod() {\n\t\treturn this.operationMethod;\n\t}\n\n\t@Override\n\tpublic OperationType getType() {\n\t\treturn this.operationMethod.getOperationType();\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(InvocationContext context) {\n\t\treturn this.invoker.invoke(context);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this).append(\"operationMethod\", this.operationMethod)\n\t\t\t.append(\"invoker\", this.invoker);\n\t\tappendFields(creator);\n\t\treturn creator.toString();\n\t}\n\n\tprotected void appendFields(ToStringCreator creator) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DeleteOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.boot.actuate.endpoint.Producible;\n\n/**\n * Identifies a method on an {@link Endpoint @Endpoint} as being a delete operation.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective(OperationReflectiveProcessor.class)\npublic @interface DeleteOperation {\n\n\t/**\n\t * The media type of the result of the operation.\n\t * @return the media type\n\t */\n\tString[] produces() default {};\n\n\t/**\n\t * The media types of the result of the operation.\n\t * @return the media types\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tClass<? extends Producible> producesFrom() default Producible.class;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\n\n/**\n * An {@link ExposableEndpoint endpoint} discovered by an {@link EndpointDiscoverer}.\n *\n * @param <O> the operation type\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface DiscoveredEndpoint<O extends Operation> extends ExposableEndpoint<O> {\n\n\t/**\n\t * Return {@code true} if the endpoint was discovered by the specified discoverer.\n\t * @param discoverer the discoverer type\n\t * @return {@code true} if discovered using the specified discoverer\n\t */\n\tboolean wasDiscoveredBy(Class<? extends EndpointDiscoverer<?, ?>> discoverer);\n\n\t/**\n\t * Return the source bean that was used to construct the {@link DiscoveredEndpoint}.\n\t * @return the source endpoint bean\n\t */\n\tObject getEndpointBean();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.Producible;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.util.Assert;\n\n/**\n * An {@link OperationMethod} discovered by an {@link EndpointDiscoverer}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class DiscoveredOperationMethod extends OperationMethod {\n\n\tprivate final List<String> producesMediaTypes;\n\n\tpublic DiscoveredOperationMethod(Method method, OperationType operationType,\n\t\t\tAnnotationAttributes annotationAttributes) {\n\t\tsuper(method, operationType);\n\t\tAssert.notNull(annotationAttributes, \"'annotationAttributes' must not be null\");\n\t\tList<String> producesMediaTypes = new ArrayList<>();\n\t\tproducesMediaTypes.addAll(Arrays.asList(annotationAttributes.getStringArray(\"produces\")));\n\t\tproducesMediaTypes.addAll(getProducesFromProducible(annotationAttributes));\n\t\tthis.producesMediaTypes = Collections.unmodifiableList(producesMediaTypes);\n\t}\n\n\tprivate <E extends Enum<E> & Producible<E>> List<String> getProducesFromProducible(\n\t\t\tAnnotationAttributes annotationAttributes) {\n\t\tClass<?> type = getProducesFrom(annotationAttributes);\n\t\tif (type == Producible.class) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<String> produces = new ArrayList<>();\n\t\tfor (Object value : type.getEnumConstants()) {\n\t\t\tproduces.add(((Producible<?>) value).getProducedMimeType().toString());\n\t\t}\n\t\treturn produces;\n\t}\n\n\tprivate Class<?> getProducesFrom(AnnotationAttributes annotationAttributes) {\n\t\ttry {\n\t\t\treturn annotationAttributes.getClass(\"producesFrom\");\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\treturn Producible.class;\n\t\t}\n\t}\n\n\tpublic List<String> getProducesMediaTypes() {\n\t\treturn this.producesMediaTypes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker;\nimport org.springframework.core.MethodIntrospector;\nimport org.springframework.core.MethodIntrospector.MetadataLookup;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\n\n/**\n * Factory to create an {@link Operation} for annotated methods on an\n * {@link Endpoint @Endpoint} or {@link EndpointExtension @EndpointExtension}.\n *\n * @param <O> the operation type\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nabstract class DiscoveredOperationsFactory<O extends Operation> {\n\n\tprivate static final Map<OperationType, Class<? extends Annotation>> OPERATION_TYPES;\n\n\tstatic {\n\t\tMap<OperationType, Class<? extends Annotation>> operationTypes = new EnumMap<>(OperationType.class);\n\t\toperationTypes.put(OperationType.READ, ReadOperation.class);\n\t\toperationTypes.put(OperationType.WRITE, WriteOperation.class);\n\t\toperationTypes.put(OperationType.DELETE, DeleteOperation.class);\n\t\tOPERATION_TYPES = Collections.unmodifiableMap(operationTypes);\n\t}\n\n\tprivate final ParameterValueMapper parameterValueMapper;\n\n\tprivate final @Nullable Collection<OperationInvokerAdvisor> invokerAdvisors;\n\n\tDiscoveredOperationsFactory(ParameterValueMapper parameterValueMapper,\n\t\t\t@Nullable Collection<OperationInvokerAdvisor> invokerAdvisors) {\n\t\tthis.parameterValueMapper = parameterValueMapper;\n\t\tthis.invokerAdvisors = invokerAdvisors;\n\t}\n\n\tCollection<O> createOperations(EndpointId id, Object target) {\n\t\treturn MethodIntrospector\n\t\t\t.selectMethods(target.getClass(), (MetadataLookup<O>) (method) -> createOperation(id, target, method))\n\t\t\t.values();\n\t}\n\n\tprivate @Nullable O createOperation(EndpointId endpointId, Object target, Method method) {\n\t\treturn OPERATION_TYPES.entrySet()\n\t\t\t.stream()\n\t\t\t.map((entry) -> createOperation(endpointId, target, method, entry.getKey(), entry.getValue()))\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprivate @Nullable O createOperation(EndpointId endpointId, Object target, Method method,\n\t\t\tOperationType operationType, Class<? extends Annotation> annotationType) {\n\t\tMergedAnnotation<?> annotation = MergedAnnotations.from(method).get(annotationType);\n\t\tif (!annotation.isPresent()) {\n\t\t\treturn null;\n\t\t}\n\t\tDiscoveredOperationMethod operationMethod = new DiscoveredOperationMethod(method, operationType,\n\t\t\t\tannotation.asAnnotationAttributes());\n\t\tOperationInvoker invoker = new ReflectiveOperationInvoker(target, operationMethod, this.parameterValueMapper);\n\t\tinvoker = applyAdvisors(endpointId, operationMethod, invoker);\n\t\treturn createOperation(endpointId, operationMethod, invoker);\n\t}\n\n\tprivate OperationInvoker applyAdvisors(EndpointId endpointId, OperationMethod operationMethod,\n\t\t\tOperationInvoker invoker) {\n\t\tif (this.invokerAdvisors != null) {\n\t\t\tfor (OperationInvokerAdvisor advisor : this.invokerAdvisors) {\n\t\t\t\tinvoker = advisor.apply(endpointId, operationMethod.getOperationType(), operationMethod.getParameters(),\n\t\t\t\t\t\tinvoker);\n\t\t\t}\n\t\t}\n\t\treturn invoker;\n\t}\n\n\tprotected abstract O createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\tOperationInvoker invoker);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/DiscovererEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EndpointFilter} the matches based on the {@link EndpointDiscoverer} the created\n * the endpoint.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic abstract class DiscovererEndpointFilter implements EndpointFilter<DiscoveredEndpoint<?>> {\n\n\tprivate final Class<? extends EndpointDiscoverer<?, ?>> discoverer;\n\n\t/**\n\t * Create a new {@link DiscovererEndpointFilter} instance.\n\t * @param discoverer the required discoverer\n\t */\n\tprotected DiscovererEndpointFilter(Class<? extends EndpointDiscoverer<?, ?>> discoverer) {\n\t\tAssert.notNull(discoverer, \"'discoverer' must not be null\");\n\t\tthis.discoverer = discoverer;\n\t}\n\n\t@Override\n\tpublic boolean match(DiscoveredEndpoint<?> endpoint) {\n\t\treturn endpoint.wasDiscoveredBy(this.discoverer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Endpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\n\n/**\n * Identifies a type as being an actuator endpoint that provides information about the\n * running application. Endpoints can be exposed over a variety of technologies including\n * JMX and HTTP.\n * <p>\n * Most {@code @Endpoint} classes will declare one or more\n * {@link ReadOperation @ReadOperation}, {@link WriteOperation @WriteOperation},\n * {@link DeleteOperation @DeleteOperation} annotated methods which will be automatically\n * adapted to the exposing technology (JMX, Spring MVC, Spring WebFlux, Jersey etc.).\n * <p>\n * {@code @Endpoint} represents the lowest common denominator for endpoints and\n * intentionally limits the sorts of operation methods that may be defined in order to\n * support the broadest possible range of exposure technologies. If you need deeper\n * support for a specific technology you can either write an endpoint that is\n * {@link FilteredEndpoint filtered} to a certain technology, or provide\n * {@link EndpointExtension extension} for the broader endpoint.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n * @see EndpointExtension\n * @see FilteredEndpoint\n * @see EndpointDiscoverer\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective\npublic @interface Endpoint {\n\n\t/**\n\t * The id of the endpoint (must follow {@link EndpointId} rules).\n\t * @return the id\n\t * @see EndpointId\n\t */\n\tString id() default \"\";\n\n\t/**\n\t * Level of access to the endpoint that is permitted by default.\n\t * @return the default level of access\n\t * @since 3.4.0\n\t */\n\tAccess defaultAccess() default Access.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\n/**\n * Qualifier for beans that are needed to convert {@link Endpoint @Endpoint} input\n * parameters.\n *\n * @author Chao Chang\n * @since 2.2.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface EndpointConverter {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscoverer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * A Base for {@link EndpointsSupplier} implementations that discover\n * {@link Endpoint @Endpoint} beans and {@link EndpointExtension @EndpointExtension} beans\n * in an application context.\n *\n * @param <E> the endpoint type\n * @param <O> the operation type\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic abstract class EndpointDiscoverer<E extends ExposableEndpoint<O>, O extends Operation>\n\t\timplements EndpointsSupplier<E> {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final Collection<EndpointFilter<E>> endpointFilters;\n\n\tprivate final Collection<OperationFilter<O>> operationFilters;\n\n\tprivate final DiscoveredOperationsFactory<O> operationsFactory;\n\n\tprivate final Map<EndpointBean, E> filterEndpoints = new ConcurrentHashMap<>();\n\n\tprivate volatile @Nullable Collection<E> endpoints;\n\n\t/**\n\t * Create a new {@link EndpointDiscoverer} instance.\n\t * @param applicationContext the source application context\n\t * @param parameterValueMapper the parameter value mapper\n\t * @param invokerAdvisors invoker advisors to apply\n\t * @param endpointFilters endpoint filters to apply\n\t * @param operationFilters operation filters to apply\n\t * @since 3.4.0\n\t */\n\tpublic EndpointDiscoverer(ApplicationContext applicationContext, ParameterValueMapper parameterValueMapper,\n\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors, Collection<EndpointFilter<E>> endpointFilters,\n\t\t\tCollection<OperationFilter<O>> operationFilters) {\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tAssert.notNull(parameterValueMapper, \"'parameterValueMapper' must not be null\");\n\t\tAssert.notNull(invokerAdvisors, \"'invokerAdvisors' must not be null\");\n\t\tAssert.notNull(endpointFilters, \"'endpointFilters' must not be null\");\n\t\tAssert.notNull(operationFilters, \"'operationFilters' must not be null\");\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.endpointFilters = Collections.unmodifiableCollection(endpointFilters);\n\t\tthis.operationFilters = Collections.unmodifiableCollection(operationFilters);\n\t\tthis.operationsFactory = getOperationsFactory(parameterValueMapper, invokerAdvisors);\n\t}\n\n\tprivate DiscoveredOperationsFactory<O> getOperationsFactory(ParameterValueMapper parameterValueMapper,\n\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors) {\n\t\treturn new DiscoveredOperationsFactory<>(parameterValueMapper, invokerAdvisors) {\n\n\t\t\t@Override\n\t\t\tCollection<O> createOperations(EndpointId id, Object target) {\n\t\t\t\treturn super.createOperations(id, target);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected O createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\t\t\tOperationInvoker invoker) {\n\t\t\t\treturn EndpointDiscoverer.this.createOperation(endpointId, operationMethod, invoker);\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Override\n\tpublic final Collection<E> getEndpoints() {\n\t\tCollection<E> endpoints = this.endpoints;\n\t\tif (endpoints == null) {\n\t\t\tendpoints = discoverEndpoints();\n\t\t\tthis.endpoints = endpoints;\n\t\t}\n\t\treturn endpoints;\n\t}\n\n\tprivate Collection<E> discoverEndpoints() {\n\t\tCollection<EndpointBean> endpointBeans = createEndpointBeans();\n\t\taddExtensionBeans(endpointBeans);\n\t\treturn convertToEndpoints(endpointBeans);\n\t}\n\n\tprivate Collection<EndpointBean> createEndpointBeans() {\n\t\tMap<EndpointId, EndpointBean> byId = new LinkedHashMap<>();\n\t\tString[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.applicationContext,\n\t\t\t\tEndpoint.class);\n\t\tfor (String beanName : beanNames) {\n\t\t\tif (!ScopedProxyUtils.isScopedTarget(beanName)) {\n\t\t\t\tEndpointBean endpointBean = createEndpointBean(beanName);\n\t\t\t\tEndpointBean previous = byId.putIfAbsent(endpointBean.getId(), endpointBean);\n\t\t\t\tif (previous != null) {\n\t\t\t\t\tthrow new IllegalStateException(\"Found two endpoints with the id '\" + endpointBean.getId() + \"': '\"\n\t\t\t\t\t\t\t+ endpointBean.getBeanName() + \"' and '\" + previous.getBeanName() + \"'\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn byId.values();\n\t}\n\n\tprivate EndpointBean createEndpointBean(String beanName) {\n\t\tClass<?> type = this.applicationContext.getType(beanName, false);\n\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\tClass<?> beanType = ClassUtils.getUserClass(type);\n\t\tSupplier<Object> beanSupplier = () -> this.applicationContext.getBean(beanName);\n\t\treturn new EndpointBean(this.applicationContext.getEnvironment(), beanName, beanType, beanSupplier);\n\t}\n\n\tprivate void addExtensionBeans(Collection<EndpointBean> endpointBeans) {\n\t\tMap<EndpointId, EndpointBean> byId = endpointBeans.stream()\n\t\t\t.collect(Collectors.toMap(EndpointBean::getId, Function.identity()));\n\t\tString[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(this.applicationContext,\n\t\t\t\tEndpointExtension.class);\n\t\tfor (String beanName : beanNames) {\n\t\t\tExtensionBean extensionBean = createExtensionBean(beanName);\n\t\t\tEndpointBean endpointBean = byId.get(extensionBean.getEndpointId());\n\t\t\tAssert.state(endpointBean != null, () -> (\"Invalid extension '\" + extensionBean.getBeanName()\n\t\t\t\t\t+ \"': no endpoint found with id '\" + extensionBean.getEndpointId() + \"'\"));\n\t\t\taddExtensionBean(endpointBean, extensionBean);\n\t\t}\n\t}\n\n\tprivate ExtensionBean createExtensionBean(String beanName) {\n\t\tClass<?> type = this.applicationContext.getType(beanName);\n\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\tClass<?> beanType = ClassUtils.getUserClass(type);\n\t\tSupplier<Object> beanSupplier = () -> this.applicationContext.getBean(beanName);\n\t\treturn new ExtensionBean(this.applicationContext.getEnvironment(), beanName, beanType, beanSupplier);\n\t}\n\n\tprivate void addExtensionBean(EndpointBean endpointBean, ExtensionBean extensionBean) {\n\t\tif (isExtensionExposed(endpointBean, extensionBean)) {\n\t\t\tAssert.state(isEndpointExposed(endpointBean) || isEndpointFiltered(endpointBean),\n\t\t\t\t\t() -> \"Endpoint bean '\" + endpointBean.getBeanName() + \"' cannot support the extension bean '\"\n\t\t\t\t\t\t\t+ extensionBean.getBeanName() + \"'\");\n\t\t\tendpointBean.addExtension(extensionBean);\n\t\t}\n\t}\n\n\tprivate Collection<E> convertToEndpoints(Collection<EndpointBean> endpointBeans) {\n\t\tSet<E> endpoints = new LinkedHashSet<>();\n\t\tfor (EndpointBean endpointBean : endpointBeans) {\n\t\t\tif (isEndpointExposed(endpointBean)) {\n\t\t\t\tE endpoint = convertToEndpoint(endpointBean);\n\t\t\t\tif (isInvocable(endpoint)) {\n\t\t\t\t\tendpoints.add(endpoint);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn Collections.unmodifiableSet(endpoints);\n\t}\n\n\t/**\n\t * Returns whether the endpoint is invocable and should be included in the discovered\n\t * endpoints. The default implementation returns {@code true} if the endpoint has any\n\t * operations, otherwise {@code false}.\n\t * @param endpoint the endpoint to assess\n\t * @return {@code true} if the endpoint is invocable, otherwise {@code false}.\n\t * @since 3.4.0\n\t */\n\tprotected boolean isInvocable(E endpoint) {\n\t\treturn !endpoint.getOperations().isEmpty();\n\t}\n\n\tprivate E convertToEndpoint(EndpointBean endpointBean) {\n\t\tMultiValueMap<OperationKey, O> indexed = new LinkedMultiValueMap<>();\n\t\tEndpointId id = endpointBean.getId();\n\t\taddOperations(indexed, id, endpointBean.getDefaultAccess(), endpointBean.getBean(), false);\n\t\tif (endpointBean.getExtensions().size() > 1) {\n\t\t\tString extensionBeans = endpointBean.getExtensions()\n\t\t\t\t.stream()\n\t\t\t\t.map(ExtensionBean::getBeanName)\n\t\t\t\t.collect(Collectors.joining(\", \"));\n\t\t\tthrow new IllegalStateException(\"Found multiple extensions for the endpoint bean \"\n\t\t\t\t\t+ endpointBean.getBeanName() + \" (\" + extensionBeans + \")\");\n\t\t}\n\t\tfor (ExtensionBean extensionBean : endpointBean.getExtensions()) {\n\t\t\taddOperations(indexed, id, endpointBean.getDefaultAccess(), extensionBean.getBean(), true);\n\t\t}\n\t\tassertNoDuplicateOperations(endpointBean, indexed);\n\t\tList<O> operations = indexed.values().stream().map(this::getLast).filter(Objects::nonNull).toList();\n\t\treturn createEndpoint(endpointBean.getBean(), id, endpointBean.getDefaultAccess(), operations);\n\t}\n\n\tprivate void addOperations(MultiValueMap<OperationKey, O> indexed, EndpointId id, Access defaultAccess,\n\t\t\tObject target, boolean replaceLast) {\n\t\tSet<OperationKey> replacedLast = new HashSet<>();\n\t\tCollection<O> operations = this.operationsFactory.createOperations(id, target);\n\t\tfor (O operation : operations) {\n\t\t\tif (!isOperationFiltered(operation, id, defaultAccess)) {\n\t\t\t\tOperationKey key = createOperationKey(operation);\n\t\t\t\tO last = getLast(indexed.get(key));\n\t\t\t\tif (replaceLast && replacedLast.add(key) && last != null) {\n\t\t\t\t\tList<O> os = indexed.get(key);\n\t\t\t\t\tAssert.state(os != null, \"'os' must not be null\");\n\t\t\t\t\tos.remove(last);\n\t\t\t\t}\n\t\t\t\tindexed.add(key, operation);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate <T> @Nullable T getLast(@Nullable List<T> list) {\n\t\treturn CollectionUtils.isEmpty(list) ? null : list.get(list.size() - 1);\n\t}\n\n\tprivate void assertNoDuplicateOperations(EndpointBean endpointBean, MultiValueMap<OperationKey, O> indexed) {\n\t\tList<OperationKey> duplicates = indexed.entrySet()\n\t\t\t.stream()\n\t\t\t.filter((entry) -> entry.getValue().size() > 1)\n\t\t\t.map(Map.Entry::getKey)\n\t\t\t.toList();\n\t\tif (!duplicates.isEmpty()) {\n\t\t\tSet<ExtensionBean> extensions = endpointBean.getExtensions();\n\t\t\tString extensionBeanNames = extensions.stream()\n\t\t\t\t.map(ExtensionBean::getBeanName)\n\t\t\t\t.collect(Collectors.joining(\", \"));\n\t\t\tthrow new IllegalStateException(\"Unable to map duplicate endpoint operations: \" + duplicates + \" to \"\n\t\t\t\t\t+ endpointBean.getBeanName() + (extensions.isEmpty() ? \"\" : \" (\" + extensionBeanNames + \")\"));\n\t\t}\n\t}\n\n\tprivate boolean isExtensionExposed(EndpointBean endpointBean, ExtensionBean extensionBean) {\n\t\treturn isFilterMatch(extensionBean.getFilter(), endpointBean)\n\t\t\t\t&& isExtensionTypeExposed(extensionBean.getBeanType());\n\t}\n\n\t/**\n\t * Determine if an extension bean should be exposed. Subclasses can override this\n\t * method to provide additional logic.\n\t * @param extensionBeanType the extension bean type\n\t * @return {@code true} if the extension is exposed\n\t */\n\tprotected boolean isExtensionTypeExposed(Class<?> extensionBeanType) {\n\t\treturn true;\n\t}\n\n\tprivate boolean isEndpointExposed(EndpointBean endpointBean) {\n\t\treturn isFilterMatch(endpointBean.getFilter(), endpointBean) && !isEndpointFiltered(endpointBean)\n\t\t\t\t&& isEndpointTypeExposed(endpointBean.getBeanType());\n\t}\n\n\t/**\n\t * Determine if an endpoint bean should be exposed. Subclasses can override this\n\t * method to provide additional logic.\n\t * @param beanType the endpoint bean type\n\t * @return {@code true} if the endpoint is exposed\n\t */\n\tprotected boolean isEndpointTypeExposed(Class<?> beanType) {\n\t\treturn true;\n\t}\n\n\tprivate boolean isEndpointFiltered(EndpointBean endpointBean) {\n\t\tfor (EndpointFilter<E> filter : this.endpointFilters) {\n\t\t\tif (!isFilterMatch(filter, endpointBean)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate boolean isFilterMatch(@Nullable Class<?> filter, EndpointBean endpointBean) {\n\t\tif (!isEndpointTypeExposed(endpointBean.getBeanType())) {\n\t\t\treturn false;\n\t\t}\n\t\tif (filter == null) {\n\t\t\treturn true;\n\t\t}\n\t\tE endpoint = getFilterEndpoint(endpointBean);\n\t\tClass<?> generic = ResolvableType.forClass(EndpointFilter.class, filter).resolveGeneric(0);\n\t\tif (generic == null || generic.isInstance(endpoint)) {\n\t\t\tEndpointFilter<E> instance = (EndpointFilter<E>) BeanUtils.instantiateClass(filter);\n\t\t\treturn isFilterMatch(instance, endpoint);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isFilterMatch(EndpointFilter<E> filter, EndpointBean endpointBean) {\n\t\treturn isFilterMatch(filter, getFilterEndpoint(endpointBean));\n\t}\n\n\t// Doesn't detect lambda with correct nullability\n\t@SuppressWarnings({ \"unchecked\", \"NullAway\" })\n\tprivate boolean isFilterMatch(EndpointFilter<E> filter, E endpoint) {\n\t\tBoolean result = LambdaSafe.callback(EndpointFilter.class, filter, endpoint)\n\t\t\t.withLogger(EndpointDiscoverer.class)\n\t\t\t.invokeAnd((f) -> f.match(endpoint))\n\t\t\t.get();\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate boolean isOperationFiltered(Operation operation, EndpointId endpointId, Access defaultAccess) {\n\t\tfor (OperationFilter<O> filter : this.operationFilters) {\n\t\t\tif (!isFilterMatch(filter, operation, endpointId, defaultAccess)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t// Doesn't detect lambda with correct nullability\n\t@SuppressWarnings({ \"unchecked\", \"NullAway\" })\n\tprivate boolean isFilterMatch(OperationFilter<O> filter, Operation operation, EndpointId endpointId,\n\t\t\tAccess defaultAccess) {\n\t\tBoolean result = LambdaSafe.callback(OperationFilter.class, filter, operation)\n\t\t\t.withLogger(EndpointDiscoverer.class)\n\t\t\t.invokeAnd((f) -> f.match(operation, endpointId, defaultAccess))\n\t\t\t.get();\n\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\treturn result;\n\t}\n\n\tprivate E getFilterEndpoint(EndpointBean endpointBean) {\n\t\treturn this.filterEndpoints.computeIfAbsent(endpointBean, (key) -> createEndpoint(endpointBean.getBean(),\n\t\t\t\tendpointBean.getId(), endpointBean.getDefaultAccess(), Collections.emptySet()));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected Class<? extends E> getEndpointType() {\n\t\tClass<?> generic = ResolvableType.forClass(EndpointDiscoverer.class, getClass()).resolveGeneric(0);\n\t\tAssert.state(generic != null, \"'generic' must not be null\");\n\t\treturn (Class<? extends E>) generic;\n\t}\n\n\t/**\n\t * Factory method called to create the {@link ExposableEndpoint endpoint}.\n\t * @param endpointBean the source endpoint bean\n\t * @param id the ID of the endpoint\n\t * @param defaultAccess access to the endpoint that is permitted by default\n\t * @param operations the endpoint operations\n\t * @return a created endpoint (a {@link DiscoveredEndpoint} is recommended)\n\t */\n\tprotected abstract E createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\tCollection<O> operations);\n\n\t/**\n\t * Factory method to create an {@link Operation endpoint operation}.\n\t * @param endpointId the endpoint id\n\t * @param operationMethod the operation method\n\t * @param invoker the invoker to use\n\t * @return a created operation\n\t */\n\tprotected abstract O createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\tOperationInvoker invoker);\n\n\t/**\n\t * Create an {@link OperationKey} for the given operation.\n\t * @param operation the source operation\n\t * @return the operation key\n\t */\n\tprotected abstract OperationKey createOperationKey(O operation);\n\n\t/**\n\t * A key generated for an {@link Operation} based on specific criteria from the actual\n\t * operation implementation.\n\t */\n\tprotected static final class OperationKey {\n\n\t\tprivate final Object key;\n\n\t\tprivate final Supplier<String> description;\n\n\t\t/**\n\t\t * Create a new {@link OperationKey} instance.\n\t\t * @param key the underlying key for the operation\n\t\t * @param description a human-readable description of the key\n\t\t */\n\t\tpublic OperationKey(Object key, Supplier<String> description) {\n\t\t\tAssert.notNull(key, \"'key' must not be null\");\n\t\t\tAssert.notNull(description, \"'description' must not be null\");\n\t\t\tthis.key = key;\n\t\t\tthis.description = description;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (obj == this) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn this.key.equals(((OperationKey) obj).key);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.key.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.description.get();\n\t\t}\n\n\t}\n\n\t/**\n\t * Information about an {@link Endpoint @Endpoint} bean.\n\t */\n\tprivate static class EndpointBean {\n\n\t\tprivate final String beanName;\n\n\t\tprivate final Class<?> beanType;\n\n\t\tprivate final Supplier<Object> beanSupplier;\n\n\t\tprivate final EndpointId id;\n\n\t\tprivate final Access defaultAccess;\n\n\t\tprivate final @Nullable Class<?> filter;\n\n\t\tprivate final Set<ExtensionBean> extensions = new LinkedHashSet<>();\n\n\t\tEndpointBean(Environment environment, String beanName, Class<?> beanType, Supplier<Object> beanSupplier) {\n\t\t\tMergedAnnotation<Endpoint> annotation = MergedAnnotations.from(beanType, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.get(Endpoint.class);\n\t\t\tString id = annotation.getString(\"id\");\n\t\t\tAssert.state(StringUtils.hasText(id),\n\t\t\t\t\t() -> \"No @Endpoint id attribute specified for \" + beanType.getName());\n\t\t\tthis.beanName = beanName;\n\t\t\tthis.beanType = beanType;\n\t\t\tthis.beanSupplier = beanSupplier;\n\t\t\tthis.id = EndpointId.of(environment, id);\n\t\t\tthis.defaultAccess = annotation.getEnum(\"defaultAccess\", Access.class);\n\t\t\tthis.filter = getFilter(beanType);\n\t\t}\n\n\t\tvoid addExtension(ExtensionBean extensionBean) {\n\t\t\tthis.extensions.add(extensionBean);\n\t\t}\n\n\t\tSet<ExtensionBean> getExtensions() {\n\t\t\treturn this.extensions;\n\t\t}\n\n\t\tprivate @Nullable Class<?> getFilter(Class<?> type) {\n\t\t\treturn MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.get(FilteredEndpoint.class)\n\t\t\t\t.getValue(MergedAnnotation.VALUE, Class.class)\n\t\t\t\t.orElse(null);\n\t\t}\n\n\t\tString getBeanName() {\n\t\t\treturn this.beanName;\n\t\t}\n\n\t\tClass<?> getBeanType() {\n\t\t\treturn this.beanType;\n\t\t}\n\n\t\tObject getBean() {\n\t\t\treturn this.beanSupplier.get();\n\t\t}\n\n\t\tEndpointId getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t\tAccess getDefaultAccess() {\n\t\t\treturn this.defaultAccess;\n\t\t}\n\n\t\t@Nullable Class<?> getFilter() {\n\t\t\treturn this.filter;\n\t\t}\n\n\t}\n\n\t/**\n\t * Information about an {@link EndpointExtension @EndpointExtension} bean.\n\t */\n\tprivate static class ExtensionBean {\n\n\t\tprivate final String beanName;\n\n\t\tprivate final Class<?> beanType;\n\n\t\tprivate final Supplier<Object> beanSupplier;\n\n\t\tprivate final EndpointId endpointId;\n\n\t\tprivate final Class<?> filter;\n\n\t\tExtensionBean(Environment environment, String beanName, Class<?> beanType, Supplier<Object> beanSupplier) {\n\t\t\tthis.beanName = beanName;\n\t\t\tthis.beanType = beanType;\n\t\t\tthis.beanSupplier = beanSupplier;\n\t\t\tMergedAnnotation<EndpointExtension> extensionAnnotation = MergedAnnotations\n\t\t\t\t.from(beanType, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.get(EndpointExtension.class);\n\t\t\tClass<?> endpointType = extensionAnnotation.getClass(\"endpoint\");\n\t\t\tMergedAnnotation<Endpoint> endpointAnnotation = MergedAnnotations\n\t\t\t\t.from(endpointType, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t\t.get(Endpoint.class);\n\t\t\tAssert.state(endpointAnnotation.isPresent(),\n\t\t\t\t\t() -> \"Extension \" + endpointType.getName() + \" does not specify an endpoint\");\n\t\t\tthis.endpointId = EndpointId.of(environment, endpointAnnotation.getString(\"id\"));\n\t\t\tthis.filter = extensionAnnotation.getClass(\"filter\");\n\t\t}\n\n\t\tString getBeanName() {\n\t\t\treturn this.beanName;\n\t\t}\n\n\t\tClass<?> getBeanType() {\n\t\t\treturn this.beanType;\n\t\t}\n\n\t\tObject getBean() {\n\t\t\treturn this.beanSupplier.get();\n\t\t}\n\n\t\tEndpointId getEndpointId() {\n\t\t\treturn this.endpointId;\n\t\t}\n\n\t\tClass<?> getFilter() {\n\t\t\treturn this.filter;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/EndpointExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Annotation primarily used as a meta-annotation to indicate that an annotation provides\n * extension support for an endpoint. Extensions allow additional technology specific\n * {@link Operation operations} to be added to an existing endpoint. For example, a web\n * extension may offer variations of a read operation to support filtering based on a\n * query parameter.\n * <p>\n * Extension annotations must provide an {@link EndpointFilter} to restrict when the\n * extension applies. The {@code endpoint} attribute is usually re-declared using\n * {@link AliasFor @AliasFor}. For example: <pre class=\"code\">\n * &#64;EndpointExtension(filter = WebEndpointFilter.class)\n * public &#64;interface EndpointWebExtension {\n *\n *   &#64;AliasFor(annotation = EndpointExtension.class, attribute = \"endpoint\")\n *   Class&lt;?&gt; endpoint();\n *\n * }\n * </pre>\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective\npublic @interface EndpointExtension {\n\n\t/**\n\t * The filter class used to determine when the extension applies.\n\t * @return the filter class\n\t */\n\tClass<? extends EndpointFilter<?>> filter();\n\n\t/**\n\t * The class of the endpoint to extend.\n\t * @return the class endpoint to extend\n\t */\n\tClass<?> endpoint() default Void.class;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/FilteredEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\n\n/**\n * Annotation that can be used on an {@link Endpoint @Endpoint} to implement implicit\n * filtering. Often used as a meta-annotation on technology specific endpoint annotations,\n * for example:<pre class=\"code\">\n * &#64;Endpoint\n * &#64;FilteredEndpoint(WebEndpointFilter.class)\n * public &#64;interface WebEndpoint {\n *\n *     &#64;AliasFor(annotation = Endpoint.class, attribute = \"id\")\n *     String id();\n *\n *     &#64;AliasFor(annotation = Endpoint.class, attribute = \"enableByDefault\")\n *     boolean enableByDefault() default true;\n *\n * } </pre>\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see DiscovererEndpointFilter\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface FilteredEndpoint {\n\n\t/**\n\t * The filter class to use.\n\t * @return the filter class\n\t */\n\tClass<? extends EndpointFilter<?>> value();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Type;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.annotation.ReflectiveProcessor;\nimport org.springframework.aot.hint.annotation.SimpleReflectiveProcessor;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link ReflectiveProcessor} that registers the annotated operation method and its\n * return type for reflection.\n *\n * @author Moritz Halbritter\n * @author Stephane Nicoll\n */\nclass OperationReflectiveProcessor extends SimpleReflectiveProcessor {\n\n\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t@Override\n\tprotected void registerMethodHint(ReflectionHints hints, Method method) {\n\t\tsuper.registerMethodHint(hints, method);\n\t\tType returnType = extractReturnType(method);\n\t\tif (returnType != null) {\n\t\t\tregisterReflectionHints(hints, returnType);\n\t\t}\n\t}\n\n\tprivate Type extractReturnType(Method method) {\n\t\tResolvableType returnType = ResolvableType.forMethodReturnType(method);\n\t\tif (!WebEndpointResponse.class.isAssignableFrom(method.getReturnType())) {\n\t\t\treturn returnType.getType();\n\t\t}\n\t\treturn returnType.as(WebEndpointResponse.class).getGeneric(0).getType();\n\t}\n\n\tprivate void registerReflectionHints(ReflectionHints hints, Type type) {\n\t\tif (!type.equals(Resource.class)) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints, type);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/ReadOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.boot.actuate.endpoint.Producible;\n\n/**\n * Identifies a method on an {@link Endpoint @Endpoint} as being a read operation.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective(OperationReflectiveProcessor.class)\npublic @interface ReadOperation {\n\n\t/**\n\t * The media type of the result of the operation.\n\t * @return the media type\n\t */\n\tString[] produces() default {};\n\n\t/**\n\t * The media types of the result of the operation.\n\t * @return the media types\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tClass<? extends Producible> producesFrom() default Producible.class;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/Selector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * A {@code @Selector} can be used on a parameter of an {@link Endpoint @Endpoint} method\n * to indicate that the parameter is used to select a subset of the endpoint's data.\n * <p>\n * A {@code @Selector} may change the way that the endpoint is exposed to the user. For\n * example, HTTP mapped endpoints will map select parameters to path variables.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Target(ElementType.PARAMETER)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface Selector {\n\n\t/**\n\t * The match type that should be used for the selection.\n\t * @return the match type\n\t * @since 2.2.0\n\t */\n\tMatch match() default Match.SINGLE;\n\n\t/**\n\t * Match types that can be used with the {@code @Selector}.\n\t */\n\tenum Match {\n\n\t\t/**\n\t\t * Capture a single item. For example, in the case of a web application a single\n\t\t * path segment. The parameter value be converted from a {@code String} source.\n\t\t */\n\t\tSINGLE,\n\n\t\t/**\n\t\t * Capture all remaining times. For example, in the case of a web application all\n\t\t * remaining path segments. The parameter value be converted from a\n\t\t * {@code String[]} source.\n\t\t */\n\t\tALL_REMAINING\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/WriteOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.boot.actuate.endpoint.Producible;\n\n/**\n * Identifies a method on an {@link Endpoint @Endpoint} as being a write operation.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective(OperationReflectiveProcessor.class)\npublic @interface WriteOperation {\n\n\t/**\n\t * The media type of the result of the operation.\n\t * @return the media type\n\t */\n\tString[] produces() default {};\n\n\t/**\n\t * The media types of the result of the operation.\n\t * @return the media types\n\t */\n\t@SuppressWarnings(\"rawtypes\")\n\tClass<? extends Producible> producesFrom() default Producible.class;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/annotation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Annotation support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/MissingParametersException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link RuntimeException} thrown when an endpoint invocation does not contain required\n * parameters.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic final class MissingParametersException extends InvalidEndpointRequestException {\n\n\tprivate final Set<OperationParameter> missingParameters;\n\n\tpublic MissingParametersException(Set<OperationParameter> missingParameters) {\n\t\tsuper(\"Failed to invoke operation because the following required parameters were missing: \"\n\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(missingParameters),\n\t\t\t\t\"Missing parameters: \"\n\t\t\t\t\t\t+ missingParameters.stream().map(OperationParameter::getName).collect(Collectors.joining(\",\")));\n\t\tthis.missingParameters = missingParameters;\n\t}\n\n\t/**\n\t * Returns the parameters that were missing.\n\t * @return the parameters\n\t */\n\tpublic Set<OperationParameter> getMissingParameters() {\n\t\treturn this.missingParameters;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationInvoker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\n\n/**\n * Interface to perform an operation invocation.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface OperationInvoker {\n\n\t/**\n\t * Invoke the underlying operation using the given {@code context}.\n\t * @param context the context to use to invoke the operation\n\t * @return the result of the operation, may be {@code null}\n\t * @throws MissingParametersException if parameters are missing\n\t */\n\t@Nullable Object invoke(InvocationContext context) throws MissingParametersException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationInvokerAdvisor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationType;\n\n/**\n * Allows additional functionality to be applied to an {@link OperationInvoker}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface OperationInvokerAdvisor {\n\n\t/**\n\t * Apply additional functionality to the given invoker.\n\t * @param endpointId the endpoint ID\n\t * @param operationType the operation type\n\t * @param parameters the operation parameters\n\t * @param invoker the invoker to advise\n\t * @return a potentially new operation invoker with support for additional features\n\t */\n\tOperationInvoker apply(EndpointId endpointId, OperationType operationType, OperationParameters parameters,\n\t\t\tOperationInvoker invoker);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationParameter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport java.lang.annotation.Annotation;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A single operation parameter.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @since 2.0.0\n */\npublic interface OperationParameter {\n\n\t/**\n\t * Returns the parameter name.\n\t * @return the name\n\t */\n\tString getName();\n\n\t/**\n\t * Returns the parameter type.\n\t * @return the type\n\t */\n\tClass<?> getType();\n\n\t/**\n\t * Return if the parameter is mandatory (does not accept null values).\n\t * @return if the parameter is mandatory\n\t */\n\tboolean isMandatory();\n\n\t/**\n\t * Returns this element's annotation for the specified type if such an annotation is\n\t * present, else null.\n\t * @param annotation class of the annotation\n\t * @return annotation value\n\t * @param <T> type of the annotation\n\t * @since 2.7.8\n\t */\n\t<T extends Annotation> @Nullable T getAnnotation(Class<T> annotation);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/OperationParameters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport java.util.stream.Stream;\n\n/**\n * A collection of {@link OperationParameter operation parameters}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface OperationParameters extends Iterable<OperationParameter> {\n\n\t/**\n\t * Return {@code true} if there is at least one parameter.\n\t * @return if there are parameters\n\t */\n\tdefault boolean hasParameters() {\n\t\treturn getParameterCount() > 0;\n\t}\n\n\t/**\n\t * Return the total number of parameters.\n\t * @return the total number of parameters\n\t */\n\tint getParameterCount();\n\n\t/**\n\t * Return if any of the contained parameters are\n\t * {@link OperationParameter#isMandatory() mandatory}.\n\t * @return if any parameters are mandatory\n\t */\n\tdefault boolean hasMandatoryParameter() {\n\t\treturn stream().anyMatch(OperationParameter::isMandatory);\n\t}\n\n\t/**\n\t * Return the parameter at the specified index.\n\t * @param index the parameter index\n\t * @return the parameter\n\t */\n\tOperationParameter get(int index);\n\n\t/**\n\t * Return a stream of the contained parameters.\n\t * @return a stream of the parameters\n\t */\n\tStream<OperationParameter> stream();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/ParameterMappingException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\n\n/**\n * A {@code ParameterMappingException} is thrown when a failure occurs during\n * {@link ParameterValueMapper#mapParameterValue operation parameter mapping}.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic final class ParameterMappingException extends InvalidEndpointRequestException {\n\n\tprivate final OperationParameter parameter;\n\n\tprivate final @Nullable Object value;\n\n\t/**\n\t * Creates a new {@code ParameterMappingException} for a failure that occurred when\n\t * trying to map the given {@code input} to the given {@code type}.\n\t * @param parameter the parameter being mapping\n\t * @param value the value being mapped\n\t * @param cause the cause of the mapping failure\n\t */\n\tpublic ParameterMappingException(OperationParameter parameter, @Nullable Object value, Throwable cause) {\n\t\tsuper(\"Failed to map \" + value + \" of type \" + ((value != null) ? value.getClass() : null) + \" to \" + parameter,\n\t\t\t\t\"Parameter mapping failure\", cause);\n\t\tthis.parameter = parameter;\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Return the parameter being mapped.\n\t * @return the parameter\n\t */\n\tpublic OperationParameter getParameter() {\n\t\treturn this.parameter;\n\t}\n\n\t/**\n\t * Return the value being mapped.\n\t * @return the value\n\t */\n\tpublic @Nullable Object getValue() {\n\t\treturn this.value;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/ParameterValueMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Maps parameter values to the required type when invoking an endpoint.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface ParameterValueMapper {\n\n\t/**\n\t * A {@link ParameterValueMapper} that does nothing.\n\t */\n\tParameterValueMapper NONE = (parameter, value) -> value;\n\n\t/**\n\t * Map the specified {@code input} parameter to the given {@code parameterType}.\n\t * @param parameter the parameter to map\n\t * @param value a parameter value\n\t * @return a value suitable for that parameter\n\t * @throws ParameterMappingException when a mapping failure occurs\n\t */\n\t@Nullable Object mapParameterValue(OperationParameter parameter, @Nullable Object value) throws ParameterMappingException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/convert/ConversionServiceParameterValueMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.convert;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterMappingException;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ParameterValueMapper} backed by a {@link ConversionService}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class ConversionServiceParameterValueMapper implements ParameterValueMapper {\n\n\tprivate final ConversionService conversionService;\n\n\t/**\n\t * Create a new {@link ConversionServiceParameterValueMapper} instance.\n\t */\n\tpublic ConversionServiceParameterValueMapper() {\n\t\tthis(ApplicationConversionService.getSharedInstance());\n\t}\n\n\t/**\n\t * Create a new {@link ConversionServiceParameterValueMapper} instance backed by a\n\t * specific conversion service.\n\t * @param conversionService the conversion service\n\t */\n\tpublic ConversionServiceParameterValueMapper(ConversionService conversionService) {\n\t\tAssert.notNull(conversionService, \"'conversionService' must not be null\");\n\t\tthis.conversionService = conversionService;\n\t}\n\n\t@Override\n\tpublic @Nullable Object mapParameterValue(OperationParameter parameter, @Nullable Object value)\n\t\t\tthrows ParameterMappingException {\n\t\ttry {\n\t\t\treturn this.conversionService.convert(value, parameter.getType());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new ParameterMappingException(parameter, value, ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/convert/IsoOffsetDateTimeConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.convert;\n\nimport java.time.OffsetDateTime;\nimport java.time.format.DateTimeFormatter;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.ConverterRegistry;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link String} to {@link OffsetDateTime} {@link Converter} that uses\n * {@link DateTimeFormatter#ISO_OFFSET_DATE_TIME ISO offset} parsing.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class IsoOffsetDateTimeConverter implements Converter<String, @Nullable OffsetDateTime> {\n\n\t@Override\n\tpublic @Nullable OffsetDateTime convert(String source) {\n\t\tif (StringUtils.hasLength(source)) {\n\t\t\treturn OffsetDateTime.parse(source, DateTimeFormatter.ISO_OFFSET_DATE_TIME);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static void registerConverter(ConverterRegistry registry) {\n\t\tregistry.addConverter(new IsoOffsetDateTimeConverter());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/convert/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Converter support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.invoke.convert;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interfaces and classes relating to invoking operation methods.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.invoke;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\nimport java.util.Locale;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.util.Assert;\n\n/**\n * Information describing an operation method on an endpoint method.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see ReflectiveOperationInvoker\n */\npublic class OperationMethod {\n\n\tprivate static final ParameterNameDiscoverer DEFAULT_PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();\n\n\tprivate final Method method;\n\n\tprivate final OperationType operationType;\n\n\tprivate final OperationParameters operationParameters;\n\n\t/**\n\t * Create a new {@link OperationMethod} instance.\n\t * @param method the source method\n\t * @param operationType the operation type\n\t */\n\tpublic OperationMethod(Method method, OperationType operationType) {\n\t\tAssert.notNull(method, \"'method' must not be null\");\n\t\tAssert.notNull(operationType, \"'operationType' must not be null\");\n\t\tthis.method = method;\n\t\tthis.operationType = operationType;\n\t\tthis.operationParameters = new OperationMethodParameters(method, DEFAULT_PARAMETER_NAME_DISCOVERER);\n\t}\n\n\t/**\n\t * Return the source Java method.\n\t * @return the method\n\t */\n\tpublic Method getMethod() {\n\t\treturn this.method;\n\t}\n\n\t/**\n\t * Return the operation type.\n\t * @return the operation type\n\t */\n\tpublic OperationType getOperationType() {\n\t\treturn this.operationType;\n\t}\n\n\t/**\n\t * Return the operation parameters.\n\t * @return the operation parameters\n\t */\n\tpublic OperationParameters getParameters() {\n\t\treturn this.operationParameters;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Operation \" + this.operationType.name().toLowerCase(Locale.ENGLISH) + \" method \" + this.method;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Parameter;\n\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.core.Nullness;\n\n/**\n * {@link OperationParameter} created from an {@link OperationMethod}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass OperationMethodParameter implements OperationParameter {\n\n\tprivate final String name;\n\n\tprivate final Parameter parameter;\n\n\t/**\n\t * Create a new {@link OperationMethodParameter} instance.\n\t * @param name the parameter name\n\t * @param parameter the parameter\n\t */\n\tOperationMethodParameter(String name, Parameter parameter) {\n\t\tthis.name = name;\n\t\tthis.parameter = parameter;\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic Class<?> getType() {\n\t\treturn this.parameter.getType();\n\t}\n\n\t@Override\n\tpublic boolean isMandatory() {\n\t\treturn Nullness.NULLABLE != Nullness.forParameter(this.parameter);\n\t}\n\n\t@Override\n\tpublic <T extends Annotation> T getAnnotation(Class<T> annotation) {\n\t\treturn this.parameter.getAnnotation(annotation);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.name + \" of type \" + this.parameter.getType().getName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.util.Assert;\n\n/**\n * {@link OperationParameters} created from an {@link OperationMethod}.\n *\n * @author Phillip Webb\n */\nclass OperationMethodParameters implements OperationParameters {\n\n\tprivate final List<OperationParameter> operationParameters;\n\n\t/**\n\t * Create a new {@link OperationMethodParameters} instance.\n\t * @param method the source method\n\t * @param parameterNameDiscoverer the parameter name discoverer\n\t */\n\tOperationMethodParameters(Method method, ParameterNameDiscoverer parameterNameDiscoverer) {\n\t\tAssert.notNull(method, \"'method' must not be null\");\n\t\tAssert.notNull(parameterNameDiscoverer, \"'parameterNameDiscoverer' must not be null\");\n\t\t@Nullable String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);\n\t\tParameter[] parameters = method.getParameters();\n\t\tAssert.state(parameterNames != null, () -> \"Failed to extract parameter names for \" + method);\n\t\tthis.operationParameters = getOperationParameters(parameters, parameterNames);\n\t}\n\n\tprivate List<OperationParameter> getOperationParameters(Parameter[] parameters, @Nullable String[] names) {\n\t\tList<OperationParameter> operationParameters = new ArrayList<>(parameters.length);\n\t\tfor (int i = 0; i < names.length; i++) {\n\t\t\tString name = names[i];\n\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\toperationParameters.add(new OperationMethodParameter(name, parameters[i]));\n\t\t}\n\t\treturn Collections.unmodifiableList(operationParameters);\n\t}\n\n\t@Override\n\tpublic int getParameterCount() {\n\t\treturn this.operationParameters.size();\n\t}\n\n\t@Override\n\tpublic OperationParameter get(int index) {\n\t\treturn this.operationParameters.get(index);\n\t}\n\n\t@Override\n\tpublic Iterator<OperationParameter> iterator() {\n\t\treturn this.operationParameters.iterator();\n\t}\n\n\t@Override\n\tpublic Stream<OperationParameter> stream() {\n\t\treturn this.operationParameters.stream();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/ReflectiveOperationInvoker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.invoke.MissingParametersException;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * An {@code OperationInvoker} that invokes an operation using reflection.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class ReflectiveOperationInvoker implements OperationInvoker {\n\n\tprivate final Object target;\n\n\tprivate final OperationMethod operationMethod;\n\n\tprivate final ParameterValueMapper parameterValueMapper;\n\n\t/**\n\t * Creates a new {@code ReflectiveOperationInvoker} that will invoke the given\n\t * {@code method} on the given {@code target}. The given {@code parameterMapper} will\n\t * be used to map parameters to the required types and the given\n\t * {@code parameterNameMapper} will be used map parameters by name.\n\t * @param target the target of the reflective call\n\t * @param operationMethod the method info\n\t * @param parameterValueMapper the parameter mapper\n\t */\n\tpublic ReflectiveOperationInvoker(Object target, OperationMethod operationMethod,\n\t\t\tParameterValueMapper parameterValueMapper) {\n\t\tAssert.notNull(target, \"'target' must not be null\");\n\t\tAssert.notNull(operationMethod, \"'operationMethod' must not be null\");\n\t\tAssert.notNull(parameterValueMapper, \"'parameterValueMapper' must not be null\");\n\t\tReflectionUtils.makeAccessible(operationMethod.getMethod());\n\t\tthis.target = target;\n\t\tthis.operationMethod = operationMethod;\n\t\tthis.parameterValueMapper = parameterValueMapper;\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(InvocationContext context) {\n\t\tvalidateRequiredParameters(context);\n\t\tMethod method = this.operationMethod.getMethod();\n\t\t@Nullable Object[] resolvedArguments = resolveArguments(context);\n\t\tReflectionUtils.makeAccessible(method);\n\t\treturn ReflectionUtils.invokeMethod(method, this.target, resolvedArguments);\n\t}\n\n\tprivate void validateRequiredParameters(InvocationContext context) {\n\t\tSet<OperationParameter> missing = this.operationMethod.getParameters()\n\t\t\t.stream()\n\t\t\t.filter((parameter) -> isMissing(context, parameter))\n\t\t\t.collect(Collectors.toSet());\n\t\tif (!missing.isEmpty()) {\n\t\t\tthrow new MissingParametersException(missing);\n\t\t}\n\t}\n\n\tprivate boolean isMissing(InvocationContext context, OperationParameter parameter) {\n\t\tif (!parameter.isMandatory()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (context.canResolve(parameter.getType())) {\n\t\t\treturn false;\n\t\t}\n\t\treturn context.getArguments().get(parameter.getName()) == null;\n\t}\n\n\tprivate @Nullable Object[] resolveArguments(InvocationContext context) {\n\t\treturn this.operationMethod.getParameters()\n\t\t\t.stream()\n\t\t\t.map((parameter) -> resolveArgument(parameter, context))\n\t\t\t.toArray();\n\t}\n\n\tprivate @Nullable Object resolveArgument(OperationParameter parameter, InvocationContext context) {\n\t\tObject resolvedByType = context.resolveArgument(parameter.getType());\n\t\tif (resolvedByType != null) {\n\t\t\treturn resolvedByType;\n\t\t}\n\t\tObject value = context.getArguments().get(parameter.getName());\n\t\treturn this.parameterValueMapper.mapParameterValue(parameter, value);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new ToStringCreator(this).append(\"target\", this.target)\n\t\t\t.append(\"method\", this.operationMethod)\n\t\t\t.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoke/reflect/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Endpoint reflection support.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvoker.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoker.cache;\n\nimport java.security.Principal;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ConcurrentReferenceHashMap;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * An {@link OperationInvoker} that caches the response of an operation with a\n * configurable time to live.\n *\n * @author Stephane Nicoll\n * @author Christoph Dreis\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class CachingOperationInvoker implements OperationInvoker {\n\n\tprivate static final boolean IS_REACTOR_PRESENT = ClassUtils.isPresent(\"reactor.core.publisher.Mono\", null);\n\n\tprivate static final int CACHE_CLEANUP_THRESHOLD = 40;\n\n\tprivate final OperationInvoker invoker;\n\n\tprivate final long timeToLive;\n\n\tprivate final Map<CacheKey, CachedResponse> cachedResponses;\n\n\t/**\n\t * Create a new instance with the target {@link OperationInvoker} to use to compute\n\t * the response and the time to live for the cache.\n\t * @param invoker the {@link OperationInvoker} this instance wraps\n\t * @param timeToLive the maximum time in milliseconds that a response can be cached\n\t */\n\tCachingOperationInvoker(OperationInvoker invoker, long timeToLive) {\n\t\tAssert.isTrue(timeToLive > 0, \"'timeToLive' must be greater than zero\");\n\t\tthis.invoker = invoker;\n\t\tthis.timeToLive = timeToLive;\n\t\tthis.cachedResponses = new ConcurrentReferenceHashMap<>();\n\t}\n\n\t/**\n\t * Return the maximum time in milliseconds that a response can be cached.\n\t * @return the time to live of a response\n\t */\n\tpublic long getTimeToLive() {\n\t\treturn this.timeToLive;\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(InvocationContext context) {\n\t\tif (hasInput(context)) {\n\t\t\treturn this.invoker.invoke(context);\n\t\t}\n\t\tlong accessTime = System.currentTimeMillis();\n\t\tif (this.cachedResponses.size() > CACHE_CLEANUP_THRESHOLD) {\n\t\t\tcleanExpiredCachedResponses(accessTime);\n\t\t}\n\t\tCacheKey cacheKey = getCacheKey(context);\n\t\tCachedResponse cached = this.cachedResponses.get(cacheKey);\n\t\tif (cached == null || cached.isStale(accessTime, this.timeToLive)) {\n\t\t\tObject response = this.invoker.invoke(context);\n\t\t\tcached = createCachedResponse(response, accessTime);\n\t\t\tthis.cachedResponses.put(cacheKey, cached);\n\t\t}\n\t\treturn cached.getResponse();\n\t}\n\n\tprivate CacheKey getCacheKey(InvocationContext context) {\n\t\tApiVersion contextApiVersion = context.resolveArgument(ApiVersion.class);\n\t\tPrincipal principal = context.resolveArgument(Principal.class);\n\t\tWebServerNamespace serverNamespace = context.resolveArgument(WebServerNamespace.class);\n\t\tAssert.state(contextApiVersion != null, \"'contextApiVersion' must not be null\");\n\t\treturn new CacheKey(contextApiVersion, principal, serverNamespace);\n\t}\n\n\tprivate void cleanExpiredCachedResponses(long accessTime) {\n\t\ttry {\n\t\t\tthis.cachedResponses.entrySet().removeIf((entry) -> entry.getValue().isStale(accessTime, this.timeToLive));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate boolean hasInput(InvocationContext context) {\n\t\tMap<String, Object> arguments = context.getArguments();\n\t\tif (!ObjectUtils.isEmpty(arguments)) {\n\t\t\treturn arguments.values().stream().anyMatch(Objects::nonNull);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate CachedResponse createCachedResponse(@Nullable Object response, long accessTime) {\n\t\tif (IS_REACTOR_PRESENT) {\n\t\t\treturn new ReactiveCachedResponse(response, accessTime, this.timeToLive);\n\t\t}\n\t\treturn new CachedResponse(response, accessTime);\n\t}\n\n\tstatic boolean isApplicable(OperationParameters parameters) {\n\t\tfor (OperationParameter parameter : parameters) {\n\t\t\tif (parameter.isMandatory() && !CacheKey.containsType(parameter.getType())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * A cached response that encapsulates the response itself and the time at which it\n\t * was created.\n\t */\n\tstatic class CachedResponse {\n\n\t\tprivate final @Nullable Object response;\n\n\t\tprivate final long creationTime;\n\n\t\tCachedResponse(@Nullable Object response, long creationTime) {\n\t\t\tthis.response = response;\n\t\t\tthis.creationTime = creationTime;\n\t\t}\n\n\t\tboolean isStale(long accessTime, long timeToLive) {\n\t\t\treturn (accessTime - this.creationTime) >= timeToLive;\n\t\t}\n\n\t\t@Nullable Object getResponse() {\n\t\t\treturn this.response;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link CachedResponse} variant used when Reactor is present.\n\t */\n\tstatic class ReactiveCachedResponse extends CachedResponse {\n\n\t\tReactiveCachedResponse(@Nullable Object response, long creationTime, long timeToLive) {\n\t\t\tsuper(applyCaching(response, timeToLive), creationTime);\n\t\t}\n\n\t\tprivate static @Nullable Object applyCaching(@Nullable Object response, long timeToLive) {\n\t\t\tif (response instanceof Mono) {\n\t\t\t\treturn ((Mono<?>) response).cache(Duration.ofMillis(timeToLive));\n\t\t\t}\n\t\t\tif (response instanceof Flux) {\n\t\t\t\treturn ((Flux<?>) response).cache(Duration.ofMillis(timeToLive));\n\t\t\t}\n\t\t\treturn response;\n\t\t}\n\n\t}\n\n\tprivate static final class CacheKey {\n\n\t\tprivate static final Class<?>[] CACHEABLE_TYPES = new Class<?>[] { ApiVersion.class, SecurityContext.class,\n\t\t\t\tWebServerNamespace.class };\n\n\t\tprivate final ApiVersion apiVersion;\n\n\t\tprivate final @Nullable Principal principal;\n\n\t\tprivate final @Nullable WebServerNamespace serverNamespace;\n\n\t\tprivate CacheKey(ApiVersion apiVersion, @Nullable Principal principal,\n\t\t\t\t@Nullable WebServerNamespace serverNamespace) {\n\t\t\tthis.principal = principal;\n\t\t\tthis.apiVersion = apiVersion;\n\t\t\tthis.serverNamespace = serverNamespace;\n\t\t}\n\n\t\tstatic boolean containsType(Class<?> type) {\n\t\t\treturn Arrays.stream(CacheKey.CACHEABLE_TYPES).anyMatch((c) -> c.isAssignableFrom(type));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (this == obj) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tCacheKey other = (CacheKey) obj;\n\t\t\treturn this.apiVersion.equals(other.apiVersion)\n\t\t\t\t\t&& ObjectUtils.nullSafeEquals(this.principal, other.principal)\n\t\t\t\t\t&& ObjectUtils.nullSafeEquals(this.serverNamespace, other.serverNamespace);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\tfinal int prime = 31;\n\t\t\tint result = 1;\n\t\t\tresult = prime * result + this.apiVersion.hashCode();\n\t\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.principal);\n\t\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.serverNamespace);\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoker.cache;\n\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\n\n/**\n * {@link OperationInvokerAdvisor} to optionally provide result caching support.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor {\n\n\tprivate final Function<EndpointId, @Nullable Long> endpointIdTimeToLive;\n\n\tpublic CachingOperationInvokerAdvisor(Function<EndpointId, @Nullable Long> endpointIdTimeToLive) {\n\t\tthis.endpointIdTimeToLive = endpointIdTimeToLive;\n\t}\n\n\t@Override\n\tpublic OperationInvoker apply(EndpointId endpointId, OperationType operationType, OperationParameters parameters,\n\t\t\tOperationInvoker invoker) {\n\t\tif (operationType == OperationType.READ && CachingOperationInvoker.isApplicable(parameters)) {\n\t\t\tLong timeToLive = this.endpointIdTimeToLive.apply(endpointId);\n\t\t\tif (timeToLive != null && timeToLive > 0) {\n\t\t\t\treturn new CachingOperationInvoker(invoker, timeToLive);\n\t\t\t}\n\t\t}\n\t\treturn invoker;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/invoker/cache/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Caching support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.invoker.cache;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jackson/EndpointJackson2ObjectMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jackson;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\n\n/**\n * Interface used to supply the Jackson 2 {@link ObjectMapper} that should be used when\n * serializing endpoint results.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see OperationResponseBody\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@FunctionalInterface\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic interface EndpointJackson2ObjectMapper {\n\n\t/**\n\t * Return the {@link JsonMapper} that should be used to serialize\n\t * {@link OperationResponseBody} endpoint results.\n\t * @return the object mapper\n\t */\n\tObjectMapper get();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jackson/EndpointJsonMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jackson;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\n\n/**\n * Interface used to supply the {@link JsonMapper} that should be used when serializing\n * endpoint results.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see OperationResponseBody\n */\n@FunctionalInterface\npublic interface EndpointJsonMapper {\n\n\t/**\n\t * Return the {@link JsonMapper} that should be used to serialize\n\t * {@link OperationResponseBody} endpoint results.\n\t * @return the object mapper\n\t */\n\tJsonMapper get();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jackson/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Jackson support classes for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.jackson;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.management.Attribute;\nimport javax.management.AttributeList;\nimport javax.management.AttributeNotFoundException;\nimport javax.management.DynamicMBean;\nimport javax.management.InvalidAttributeValueException;\nimport javax.management.MBeanException;\nimport javax.management.MBeanInfo;\nimport javax.management.ReflectionException;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Adapter to expose a {@link ExposableJmxEndpoint JMX endpoint} as a\n * {@link DynamicMBean}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class EndpointMBean implements DynamicMBean {\n\n\tprivate static final boolean REACTOR_PRESENT = ClassUtils.isPresent(\"reactor.core.publisher.Mono\",\n\t\t\tEndpointMBean.class.getClassLoader());\n\n\tprivate final JmxOperationResponseMapper responseMapper;\n\n\tprivate final @Nullable ClassLoader classLoader;\n\n\tprivate final ExposableJmxEndpoint endpoint;\n\n\tprivate final MBeanInfo info;\n\n\tprivate final Map<String, JmxOperation> operations;\n\n\tEndpointMBean(JmxOperationResponseMapper responseMapper, @Nullable ClassLoader classLoader,\n\t\t\tExposableJmxEndpoint endpoint) {\n\t\tAssert.notNull(responseMapper, \"'responseMapper' must not be null\");\n\t\tAssert.notNull(endpoint, \"'endpoint' must not be null\");\n\t\tthis.responseMapper = responseMapper;\n\t\tthis.classLoader = classLoader;\n\t\tthis.endpoint = endpoint;\n\t\tthis.info = new MBeanInfoFactory(responseMapper).getMBeanInfo(endpoint);\n\t\tthis.operations = getOperations(endpoint);\n\t}\n\n\tprivate Map<String, JmxOperation> getOperations(ExposableJmxEndpoint endpoint) {\n\t\tMap<String, JmxOperation> operations = new HashMap<>();\n\t\tendpoint.getOperations().forEach((operation) -> operations.put(operation.getName(), operation));\n\t\treturn Collections.unmodifiableMap(operations);\n\t}\n\n\t@Override\n\tpublic MBeanInfo getMBeanInfo() {\n\t\treturn this.info;\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(String actionName, Object[] params, String[] signature)\n\t\t\tthrows MBeanException, ReflectionException {\n\t\tJmxOperation operation = this.operations.get(actionName);\n\t\tif (operation == null) {\n\t\t\tString message = \"Endpoint with id '\" + this.endpoint.getEndpointId() + \"' has no operation named \"\n\t\t\t\t\t+ actionName;\n\t\t\tthrow new ReflectionException(new IllegalArgumentException(message), message);\n\t\t}\n\t\tClassLoader previousClassLoader = overrideThreadContextClassLoader(this.classLoader);\n\t\ttry {\n\t\t\treturn invoke(operation, params);\n\t\t}\n\t\tfinally {\n\t\t\toverrideThreadContextClassLoader(previousClassLoader);\n\t\t}\n\t}\n\n\tprivate @Nullable ClassLoader overrideThreadContextClassLoader(@Nullable ClassLoader classLoader) {\n\t\tif (classLoader != null) {\n\t\t\ttry {\n\t\t\t\treturn ClassUtils.overrideThreadContextClassLoader(classLoader);\n\t\t\t}\n\t\t\tcatch (SecurityException ex) {\n\t\t\t\t// can't set class loader, ignore it and proceed\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable Object invoke(JmxOperation operation, Object[] params)\n\t\t\tthrows MBeanException, ReflectionException {\n\t\ttry {\n\t\t\tString[] parameterNames = operation.getParameters()\n\t\t\t\t.stream()\n\t\t\t\t.map(JmxOperationParameter::getName)\n\t\t\t\t.toArray(String[]::new);\n\t\t\tMap<String, Object> arguments = getArguments(parameterNames, params);\n\t\t\tInvocationContext context = new InvocationContext(SecurityContext.NONE, arguments);\n\t\t\tObject result = operation.invoke(context);\n\t\t\tif (REACTOR_PRESENT) {\n\t\t\t\tresult = ReactiveHandler.handle(result);\n\t\t\t}\n\t\t\treturn this.responseMapper.mapResponse(result);\n\t\t}\n\t\tcatch (InvalidEndpointRequestException ex) {\n\t\t\tthrow new ReflectionException(new IllegalArgumentException(ex.getMessage()), ex.getMessage());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MBeanException(translateIfNecessary(ex), ex.getMessage());\n\t\t}\n\t}\n\n\tprivate Exception translateIfNecessary(Exception exception) {\n\t\tif (exception.getClass().getName().startsWith(\"java.\")) {\n\t\t\treturn exception;\n\t\t}\n\t\treturn new IllegalStateException(exception.getMessage());\n\t}\n\n\tprivate Map<String, Object> getArguments(String[] parameterNames, Object[] params) {\n\t\tMap<String, Object> arguments = new HashMap<>();\n\t\tfor (int i = 0; i < params.length; i++) {\n\t\t\targuments.put(parameterNames[i], params[i]);\n\t\t}\n\t\treturn arguments;\n\t}\n\n\t@Override\n\tpublic Object getAttribute(String attribute)\n\t\t\tthrows AttributeNotFoundException, MBeanException, ReflectionException {\n\t\tthrow new AttributeNotFoundException(\"EndpointMBeans do not support attributes\");\n\t}\n\n\t@Override\n\tpublic void setAttribute(Attribute attribute)\n\t\t\tthrows AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {\n\t\tthrow new AttributeNotFoundException(\"EndpointMBeans do not support attributes\");\n\t}\n\n\t@Override\n\tpublic AttributeList getAttributes(String[] attributes) {\n\t\treturn new AttributeList();\n\t}\n\n\t@Override\n\tpublic AttributeList setAttributes(AttributeList attributes) {\n\t\treturn new AttributeList();\n\t}\n\n\tprivate static final class ReactiveHandler {\n\n\t\tstatic @Nullable Object handle(@Nullable Object result) {\n\t\t\tif (result instanceof Flux) {\n\t\t\t\tresult = ((Flux<?>) result).collectList();\n\t\t\t}\n\t\t\tif (result instanceof Mono) {\n\t\t\t\treturn ((Mono<?>) result).block();\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/EndpointObjectNameFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\n/**\n * A factory to create an {@link ObjectName} for an {@link EndpointMBean}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface EndpointObjectNameFactory {\n\n\t/**\n\t * Generate an {@link ObjectName} for the specified {@link ExposableJmxEndpoint\n\t * endpoint}.\n\t * @param endpoint the endpoint MBean to handle\n\t * @return the {@link ObjectName} to use for the endpoint\n\t * @throws MalformedObjectNameException if the object name is invalid\n\t */\n\tObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/ExposableJmxEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\n\n/**\n * Information describing an endpoint that can be exposed over JMX.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface ExposableJmxEndpoint extends ExposableEndpoint<JmxOperation> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/Jackson2JmxOperationResponseMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.databind.JavaType;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\n\n/**\n * {@link JmxOperationResponseMapper} that delegates to a Jackson 2 {@link ObjectMapper}\n * to return a JSON response.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link JacksonJmxOperationResponseMapper}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic class Jackson2JmxOperationResponseMapper implements JmxOperationResponseMapper {\n\n\tprivate final ObjectMapper objectMapper;\n\n\tprivate final JavaType listType;\n\n\tprivate final JavaType mapType;\n\n\tpublic Jackson2JmxOperationResponseMapper(@Nullable ObjectMapper objectMapper) {\n\t\tthis.objectMapper = (objectMapper != null) ? objectMapper : new ObjectMapper();\n\t\tthis.listType = this.objectMapper.getTypeFactory().constructParametricType(List.class, Object.class);\n\t\tthis.mapType = this.objectMapper.getTypeFactory()\n\t\t\t.constructParametricType(Map.class, String.class, Object.class);\n\t}\n\n\t@Override\n\tpublic Class<?> mapResponseType(Class<?> responseType) {\n\t\tif (CharSequence.class.isAssignableFrom(responseType)) {\n\t\t\treturn String.class;\n\t\t}\n\t\tif (responseType.isArray() || Collection.class.isAssignableFrom(responseType)) {\n\t\t\treturn List.class;\n\t\t}\n\t\treturn Map.class;\n\t}\n\n\t@Override\n\t@Contract(\"!null -> !null\")\n\tpublic @Nullable Object mapResponse(@Nullable Object response) {\n\t\tif (response == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (response instanceof CharSequence) {\n\t\t\treturn response.toString();\n\t\t}\n\t\tif (response.getClass().isArray() || response instanceof Collection) {\n\t\t\treturn this.objectMapper.convertValue(response, this.listType);\n\t\t}\n\t\treturn this.objectMapper.convertValue(response, this.mapType);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JacksonJmxOperationResponseMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JavaType;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.lang.Contract;\n\n/**\n * {@link JmxOperationResponseMapper} that delegates to a Jackson {@link JsonMapper} to\n * return a JSON response.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class JacksonJmxOperationResponseMapper implements JmxOperationResponseMapper {\n\n\tprivate final JsonMapper jsonMapper;\n\n\tprivate final JavaType listType;\n\n\tprivate final JavaType mapType;\n\n\tpublic JacksonJmxOperationResponseMapper(@Nullable JsonMapper jsonMapper) {\n\t\tthis.jsonMapper = (jsonMapper != null) ? jsonMapper : new JsonMapper();\n\t\tthis.listType = this.jsonMapper.getTypeFactory().constructParametricType(List.class, Object.class);\n\t\tthis.mapType = this.jsonMapper.getTypeFactory().constructParametricType(Map.class, String.class, Object.class);\n\t}\n\n\t@Override\n\tpublic Class<?> mapResponseType(Class<?> responseType) {\n\t\tif (CharSequence.class.isAssignableFrom(responseType)) {\n\t\t\treturn String.class;\n\t\t}\n\t\tif (responseType.isArray() || Collection.class.isAssignableFrom(responseType)) {\n\t\t\treturn List.class;\n\t\t}\n\t\treturn Map.class;\n\t}\n\n\t@Override\n\t@Contract(\"!null -> !null\")\n\tpublic @Nullable Object mapResponse(@Nullable Object response) {\n\t\tif (response == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (response instanceof CharSequence) {\n\t\t\treturn response.toString();\n\t\t}\n\t\tif (response.getClass().isArray() || response instanceof Collection) {\n\t\t\treturn this.jsonMapper.convertValue(response, this.listType);\n\t\t}\n\t\treturn this.jsonMapper.convertValue(response, this.mapType);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport javax.management.InstanceNotFoundException;\nimport javax.management.MBeanRegistrationException;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.jmx.JmxException;\nimport org.springframework.jmx.export.MBeanExportException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Exports {@link ExposableJmxEndpoint JMX endpoints} to a {@link MBeanServer}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class JmxEndpointExporter implements InitializingBean, DisposableBean, BeanClassLoaderAware {\n\n\tprivate static final Log logger = LogFactory.getLog(JmxEndpointExporter.class);\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader classLoader;\n\n\tprivate final MBeanServer mBeanServer;\n\n\tprivate final EndpointObjectNameFactory objectNameFactory;\n\n\tprivate final JmxOperationResponseMapper responseMapper;\n\n\tprivate final Collection<ExposableJmxEndpoint> endpoints;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Collection<ObjectName> registered;\n\n\tpublic JmxEndpointExporter(MBeanServer mBeanServer, EndpointObjectNameFactory objectNameFactory,\n\t\t\tJmxOperationResponseMapper responseMapper, Collection<? extends ExposableJmxEndpoint> endpoints) {\n\t\tAssert.notNull(mBeanServer, \"'mBeanServer' must not be null\");\n\t\tAssert.notNull(objectNameFactory, \"'objectNameFactory' must not be null\");\n\t\tAssert.notNull(responseMapper, \"'responseMapper' must not be null\");\n\t\tAssert.notNull(endpoints, \"'endpoints' must not be null\");\n\t\tthis.mBeanServer = mBeanServer;\n\t\tthis.objectNameFactory = objectNameFactory;\n\t\tthis.responseMapper = responseMapper;\n\t\tthis.endpoints = Collections.unmodifiableCollection(endpoints);\n\t}\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tthis.registered = register();\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tunregister(this.registered);\n\t}\n\n\tprivate Collection<ObjectName> register() {\n\t\treturn this.endpoints.stream().filter(this::hasOperations).map(this::register).toList();\n\t}\n\n\tprivate boolean hasOperations(ExposableJmxEndpoint endpoint) {\n\t\treturn !CollectionUtils.isEmpty(endpoint.getOperations());\n\t}\n\n\tprivate ObjectName register(ExposableJmxEndpoint endpoint) {\n\t\tAssert.notNull(endpoint, \"'endpoint' must not be null\");\n\t\ttry {\n\t\t\tObjectName name = this.objectNameFactory.getObjectName(endpoint);\n\t\t\tEndpointMBean mbean = new EndpointMBean(this.responseMapper, this.classLoader, endpoint);\n\t\t\tthis.mBeanServer.registerMBean(mbean, name);\n\t\t\treturn name;\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid ObjectName for \" + getEndpointDescription(endpoint), ex);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new MBeanExportException(\"Failed to register MBean for \" + getEndpointDescription(endpoint), ex);\n\t\t}\n\t}\n\n\tprivate void unregister(Collection<ObjectName> objectNames) {\n\t\tobjectNames.forEach(this::unregister);\n\t}\n\n\tprivate void unregister(ObjectName objectName) {\n\t\ttry {\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"Unregister endpoint with ObjectName '\" + objectName + \"' from the JMX domain\");\n\t\t\t}\n\t\t\tthis.mBeanServer.unregisterMBean(objectName);\n\t\t}\n\t\tcatch (InstanceNotFoundException ex) {\n\t\t\t// Ignore and continue\n\t\t}\n\t\tcatch (MBeanRegistrationException ex) {\n\t\t\tthrow new JmxException(\"Failed to unregister MBean with ObjectName '\" + objectName + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate String getEndpointDescription(ExposableJmxEndpoint endpoint) {\n\t\treturn \"endpoint '\" + endpoint.getEndpointId() + \"'\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointsSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\n\n/**\n * {@link EndpointsSupplier} for {@link ExposableJmxEndpoint JMX endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface JmxEndpointsSupplier extends EndpointsSupplier<ExposableJmxEndpoint> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.Operation;\n\n/**\n * An operation on a JMX endpoint.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface JmxOperation extends Operation {\n\n\t/**\n\t * Returns the name of the operation.\n\t * @return the operation name\n\t */\n\tString getName();\n\n\t/**\n\t * Returns the type of the output of the operation.\n\t * @return the output type\n\t */\n\tClass<?> getOutputType();\n\n\t/**\n\t * Returns the description of the operation.\n\t * @return the operation description\n\t */\n\tString getDescription();\n\n\t/**\n\t * Returns the parameters the operation expects in the order that they should be\n\t * provided.\n\t * @return the operation parameter names\n\t */\n\tList<JmxOperationParameter> getParameters();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxOperationParameter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Describes the parameters of an operation on a JMX endpoint.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface JmxOperationParameter {\n\n\t/**\n\t * Return the name of the operation parameter.\n\t * @return the name of the parameter\n\t */\n\tString getName();\n\n\t/**\n\t * Return the type of the operation parameter.\n\t * @return the type\n\t */\n\tClass<?> getType();\n\n\t/**\n\t * Return the description of the parameter or {@code null} if none is available.\n\t * @return the description or {@code null}\n\t */\n\t@Nullable String getDescription();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/JmxOperationResponseMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Maps an operation's response to a JMX-friendly form.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic interface JmxOperationResponseMapper {\n\n\t/**\n\t * Map the response type to its JMX compliant counterpart.\n\t * @param responseType the operation's response type\n\t * @return the JMX compliant type\n\t */\n\tClass<?> mapResponseType(Class<?> responseType);\n\n\t/**\n\t * Map the operation's response so that it can be consumed by a JMX compliant client.\n\t * @param response the operation's response\n\t * @return the {@code response}, in a JMX compliant format\n\t */\n\t@Nullable Object mapResponse(@Nullable Object response);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/MBeanInfoFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.List;\n\nimport javax.management.MBeanInfo;\nimport javax.management.MBeanOperationInfo;\nimport javax.management.MBeanParameterInfo;\nimport javax.management.modelmbean.ModelMBeanAttributeInfo;\nimport javax.management.modelmbean.ModelMBeanConstructorInfo;\nimport javax.management.modelmbean.ModelMBeanInfoSupport;\nimport javax.management.modelmbean.ModelMBeanNotificationInfo;\nimport javax.management.modelmbean.ModelMBeanOperationInfo;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\n\n/**\n * Factory to create {@link MBeanInfo} from an {@link ExposableJmxEndpoint}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass MBeanInfoFactory {\n\n\tprivate static final ModelMBeanAttributeInfo[] NO_ATTRIBUTES = new ModelMBeanAttributeInfo[0];\n\n\tprivate static final ModelMBeanConstructorInfo[] NO_CONSTRUCTORS = new ModelMBeanConstructorInfo[0];\n\n\tprivate static final ModelMBeanNotificationInfo[] NO_NOTIFICATIONS = new ModelMBeanNotificationInfo[0];\n\n\tprivate final JmxOperationResponseMapper responseMapper;\n\n\tMBeanInfoFactory(JmxOperationResponseMapper responseMapper) {\n\t\tthis.responseMapper = responseMapper;\n\t}\n\n\tMBeanInfo getMBeanInfo(ExposableJmxEndpoint endpoint) {\n\t\tString className = EndpointMBean.class.getName();\n\t\tString description = getDescription(endpoint);\n\t\tModelMBeanOperationInfo[] operations = getMBeanOperations(endpoint);\n\t\treturn new ModelMBeanInfoSupport(className, description, NO_ATTRIBUTES, NO_CONSTRUCTORS, operations,\n\t\t\t\tNO_NOTIFICATIONS);\n\t}\n\n\tprivate String getDescription(ExposableJmxEndpoint endpoint) {\n\t\treturn \"MBean operations for endpoint \" + endpoint.getEndpointId();\n\t}\n\n\tprivate ModelMBeanOperationInfo[] getMBeanOperations(ExposableJmxEndpoint endpoint) {\n\t\treturn endpoint.getOperations().stream().map(this::getMBeanOperation).toArray(ModelMBeanOperationInfo[]::new);\n\t}\n\n\tprivate ModelMBeanOperationInfo getMBeanOperation(JmxOperation operation) {\n\t\tString name = operation.getName();\n\t\tString description = operation.getDescription();\n\t\tMBeanParameterInfo[] signature = getSignature(operation.getParameters());\n\t\tString type = getType(operation.getOutputType());\n\t\tint impact = getImpact(operation.getType());\n\t\treturn new ModelMBeanOperationInfo(name, description, signature, type, impact);\n\t}\n\n\tprivate MBeanParameterInfo[] getSignature(List<JmxOperationParameter> parameters) {\n\t\treturn parameters.stream().map(this::getMBeanParameter).toArray(MBeanParameterInfo[]::new);\n\t}\n\n\tprivate MBeanParameterInfo getMBeanParameter(JmxOperationParameter parameter) {\n\t\treturn new MBeanParameterInfo(parameter.getName(), parameter.getType().getName(), parameter.getDescription());\n\t}\n\n\tprivate int getImpact(OperationType operationType) {\n\t\tif (operationType == OperationType.READ) {\n\t\t\treturn MBeanOperationInfo.INFO;\n\t\t}\n\t\tif (operationType == OperationType.WRITE || operationType == OperationType.DELETE) {\n\t\t\treturn MBeanOperationInfo.ACTION;\n\t\t}\n\t\treturn MBeanOperationInfo.UNKNOWN;\n\t}\n\n\tprivate String getType(Class<?> outputType) {\n\t\treturn this.responseMapper.mapResponseType(outputType).getName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperation;\n\n/**\n * A discovered {@link ExposableJmxEndpoint JMX endpoint}.\n *\n * @author Phillip Webb\n */\nclass DiscoveredJmxEndpoint extends AbstractDiscoveredEndpoint<JmxOperation> implements ExposableJmxEndpoint {\n\n\t@SuppressWarnings(\"removal\")\n\tDiscoveredJmxEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\tCollection<JmxOperation> operations) {\n\t\tsuper(discoverer, endpointBean, id, defaultAccess, operations);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.lang.reflect.Method;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperation;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperationParameter;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource;\nimport org.springframework.jmx.export.metadata.JmxAttributeSource;\nimport org.springframework.jmx.export.metadata.ManagedOperation;\nimport org.springframework.jmx.export.metadata.ManagedOperationParameter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A discovered {@link JmxOperation JMX operation}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass DiscoveredJmxOperation extends AbstractDiscoveredOperation implements JmxOperation {\n\n\tprivate static final JmxAttributeSource jmxAttributeSource = new AnnotationJmxAttributeSource();\n\n\tprivate final String name;\n\n\tprivate final Class<?> outputType;\n\n\tprivate final String description;\n\n\tprivate final List<JmxOperationParameter> parameters;\n\n\tDiscoveredJmxOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {\n\t\tsuper(operationMethod, invoker);\n\t\tMethod method = operationMethod.getMethod();\n\t\tthis.name = method.getName();\n\t\tthis.outputType = JmxType.get(method.getReturnType());\n\t\tthis.description = getDescription(method, () -> \"Invoke \" + this.name + \" for endpoint \" + endpointId);\n\t\tthis.parameters = getParameters(operationMethod);\n\t}\n\n\tprivate String getDescription(Method method, Supplier<String> fallback) {\n\t\tManagedOperation managed = jmxAttributeSource.getManagedOperation(method);\n\t\tif (managed != null && StringUtils.hasText(managed.getDescription())) {\n\t\t\treturn managed.getDescription();\n\t\t}\n\t\treturn fallback.get();\n\t}\n\n\tprivate List<JmxOperationParameter> getParameters(OperationMethod operationMethod) {\n\t\tif (!operationMethod.getParameters().hasParameters()) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tMethod method = operationMethod.getMethod();\n\t\t@Nullable ManagedOperationParameter[] managed = jmxAttributeSource.getManagedOperationParameters(method);\n\t\tif (managed.length == 0) {\n\t\t\tStream<JmxOperationParameter> parameters = operationMethod.getParameters()\n\t\t\t\t.stream()\n\t\t\t\t.map(DiscoveredJmxOperationParameter::new);\n\t\t\treturn parameters.toList();\n\t\t}\n\t\treturn mergeParameters(operationMethod.getParameters(), managed);\n\t}\n\n\tprivate List<JmxOperationParameter> mergeParameters(OperationParameters operationParameters,\n\t\t\t@Nullable ManagedOperationParameter[] managedParameters) {\n\t\tList<JmxOperationParameter> merged = new ArrayList<>(managedParameters.length);\n\t\tfor (int i = 0; i < managedParameters.length; i++) {\n\t\t\tManagedOperationParameter managedParameter = managedParameters[i];\n\t\t\tAssert.state(managedParameter != null, \"'managedParameter' must not be null\");\n\t\t\tmerged.add(new DiscoveredJmxOperationParameter(managedParameter, operationParameters.get(i)));\n\t\t}\n\t\treturn Collections.unmodifiableList(merged);\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic Class<?> getOutputType() {\n\t\treturn this.outputType;\n\t}\n\n\t@Override\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\t@Override\n\tpublic List<JmxOperationParameter> getParameters() {\n\t\treturn this.parameters;\n\t}\n\n\t@Override\n\tprotected void appendFields(ToStringCreator creator) {\n\t\tcreator.append(\"name\", this.name)\n\t\t\t.append(\"outputType\", this.outputType)\n\t\t\t.append(\"description\", this.description)\n\t\t\t.append(\"parameters\", this.parameters);\n\t}\n\n\t/**\n\t * A discovered {@link JmxOperationParameter}.\n\t */\n\tprivate static class DiscoveredJmxOperationParameter implements JmxOperationParameter {\n\n\t\tprivate final String name;\n\n\t\tprivate final Class<?> type;\n\n\t\tprivate final @Nullable String description;\n\n\t\tDiscoveredJmxOperationParameter(OperationParameter operationParameter) {\n\t\t\tthis.name = operationParameter.getName();\n\t\t\tthis.type = JmxType.get(operationParameter.getType());\n\t\t\tthis.description = null;\n\t\t}\n\n\t\tDiscoveredJmxOperationParameter(ManagedOperationParameter managedParameter,\n\t\t\t\tOperationParameter operationParameter) {\n\t\t\tthis.name = managedParameter.getName();\n\t\t\tthis.type = JmxType.get(operationParameter.getType());\n\t\t\tthis.description = managedParameter.getDescription();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tStringBuilder result = new StringBuilder(this.name);\n\t\t\tif (this.description != null) {\n\t\t\t\tresult.append(\" (\").append(this.description).append(\")\");\n\t\t\t}\n\t\t\tresult.append(\":\").append(this.type);\n\t\t\treturn result.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * Utility to convert to JMX supported types.\n\t */\n\tprivate static final class JmxType {\n\n\t\tstatic Class<?> get(Class<?> source) {\n\t\t\tif (source.isEnum()) {\n\t\t\t\treturn String.class;\n\t\t\t}\n\t\t\tif (Date.class.isAssignableFrom(source) || Instant.class.isAssignableFrom(source)) {\n\t\t\t\treturn String.class;\n\t\t\t}\n\t\t\tif (source.getName().startsWith(\"java.\")) {\n\t\t\t\treturn source;\n\t\t\t}\n\t\t\tif (source.equals(Void.TYPE)) {\n\t\t\t\treturn source;\n\t\t\t}\n\t\t\treturn Object.class;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/EndpointJmxExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Identifies a type as being a JMX-specific extension of an {@link Endpoint @Endpoint}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n * @see Endpoint\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@EndpointExtension(filter = JmxEndpointFilter.class)\npublic @interface EndpointJmxExtension {\n\n\t/**\n\t * The {@link Endpoint endpoint} class to which this JMX extension relates.\n\t * @return the endpoint class\n\t */\n\t@AliasFor(annotation = EndpointExtension.class)\n\tClass<?> endpoint();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Identifies a type as being an endpoint that is only exposed over JMX.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Endpoint\n@FilteredEndpoint(JmxEndpointFilter.class)\npublic @interface JmxEndpoint {\n\n\t/**\n\t * The id of the endpoint.\n\t * @return the id\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tString id() default \"\";\n\n\t/**\n\t * Level of access to the endpoint that is permitted by default.\n\t * @return the default level of access\n\t * @since 3.4.0\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tAccess defaultAccess() default Access.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscoverer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperation;\nimport org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer.JmxEndpointDiscovererRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * {@link EndpointDiscoverer} for {@link ExposableJmxEndpoint JMX endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@ImportRuntimeHints(JmxEndpointDiscovererRuntimeHints.class)\npublic class JmxEndpointDiscoverer extends EndpointDiscoverer<ExposableJmxEndpoint, JmxOperation>\n\t\timplements JmxEndpointsSupplier {\n\n\t/**\n\t * Create a new {@link JmxEndpointDiscoverer} instance.\n\t * @param applicationContext the source application context\n\t * @param parameterValueMapper the parameter value mapper\n\t * @param invokerAdvisors invoker advisors to apply\n\t * @param endpointFilters endpoint filters to apply\n\t * @param operationFilters operation filters to apply\n\t * @since 3.4.0\n\t */\n\tpublic JmxEndpointDiscoverer(ApplicationContext applicationContext, ParameterValueMapper parameterValueMapper,\n\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\tCollection<EndpointFilter<ExposableJmxEndpoint>> endpointFilters,\n\t\t\tCollection<OperationFilter<JmxOperation>> operationFilters) {\n\t\tsuper(applicationContext, parameterValueMapper, invokerAdvisors, endpointFilters, operationFilters);\n\t}\n\n\t@Override\n\tprotected ExposableJmxEndpoint createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\tCollection<JmxOperation> operations) {\n\t\treturn new DiscoveredJmxEndpoint(this, endpointBean, id, defaultAccess, operations);\n\t}\n\n\t@Override\n\tprotected JmxOperation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\tOperationInvoker invoker) {\n\t\treturn new DiscoveredJmxOperation(endpointId, operationMethod, invoker);\n\t}\n\n\t@Override\n\tprotected OperationKey createOperationKey(JmxOperation operation) {\n\t\treturn new OperationKey(operation.getName(), () -> \"MBean call '\" + operation.getName() + \"'\");\n\t}\n\n\tstatic class JmxEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(JmxEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;\n\n/**\n * {@link EndpointFilter} for endpoints discovered by {@link JmxEndpointDiscoverer}.\n *\n * @author Phillip Webb\n */\nclass JmxEndpointFilter extends DiscovererEndpointFilter {\n\n\tJmxEndpointFilter() {\n\t\tsuper(JmxEndpointDiscoverer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/annotation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Annotation support for actuator JMX endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/jmx/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * JMX support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Endpoint support.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/AdditionalPathsMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\n\n/**\n * Strategy interface used to provide a mapping between an endpoint ID and any additional\n * paths where it will be exposed.\n *\n * @author Phillip Webb\n * @since 3.4.0\n */\n@FunctionalInterface\npublic interface AdditionalPathsMapper {\n\n\t/**\n\t * Resolve the additional paths for the specified {@code endpointId} and web server\n\t * namespace.\n\t * @param endpointId the id of an endpoint\n\t * @param webServerNamespace the web server namespace\n\t * @return the additional paths of the endpoint or {@code null} if this mapper doesn't\n\t * support the given endpoint ID.\n\t */\n\t@Nullable List<String> getAdditionalPaths(EndpointId endpointId, WebServerNamespace webServerNamespace);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\n\n/**\n * A resolver for {@link Link links} to web endpoints.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class EndpointLinksResolver {\n\n\tprivate static final Log logger = LogFactory.getLog(EndpointLinksResolver.class);\n\n\tprivate final Collection<? extends ExposableEndpoint<?>> endpoints;\n\n\t/**\n\t * Creates a new {@code EndpointLinksResolver} that will resolve links to the given\n\t * {@code endpoints}.\n\t * @param endpoints the endpoints\n\t */\n\tpublic EndpointLinksResolver(Collection<? extends ExposableEndpoint<?>> endpoints) {\n\t\tthis.endpoints = endpoints;\n\t}\n\n\t/**\n\t * Creates a new {@code EndpointLinksResolver} that will resolve links to the given\n\t * {@code endpoints} that are exposed beneath the given {@code basePath}.\n\t * @param endpoints the endpoints\n\t * @param basePath the basePath\n\t */\n\tpublic EndpointLinksResolver(Collection<? extends ExposableEndpoint<?>> endpoints, String basePath) {\n\t\tthis.endpoints = endpoints;\n\t\tif (logger.isInfoEnabled()) {\n\t\t\tString suffix = (endpoints.size() == 1) ? \"\" : \"s\";\n\t\t\tlogger\n\t\t\t\t.info(\"Exposing \" + endpoints.size() + \" endpoint\" + suffix + \" beneath base path '\" + basePath + \"'\");\n\t\t}\n\t}\n\n\t/**\n\t * Resolves links to the known endpoints based on a request with the given\n\t * {@code requestUrl}.\n\t * @param requestUrl the url of the request for the endpoint links\n\t * @return the links\n\t */\n\tpublic Map<String, Link> resolveLinks(String requestUrl) {\n\t\tString normalizedUrl = normalizeRequestUrl(requestUrl);\n\t\tMap<String, Link> links = new LinkedHashMap<>();\n\t\tlinks.put(\"self\", new Link(normalizedUrl));\n\t\tfor (ExposableEndpoint<?> endpoint : this.endpoints) {\n\t\t\tif (endpoint instanceof ExposableWebEndpoint exposableWebEndpoint) {\n\t\t\t\tcollectLinks(links, exposableWebEndpoint, normalizedUrl);\n\t\t\t}\n\t\t\telse if (endpoint instanceof PathMappedEndpoint pathMappedEndpoint) {\n\t\t\t\tString rootPath = pathMappedEndpoint.getRootPath();\n\t\t\t\tLink link = createLink(normalizedUrl, rootPath);\n\t\t\t\tlinks.put(endpoint.getEndpointId().toLowerCaseString(), link);\n\t\t\t}\n\t\t}\n\t\treturn links;\n\t}\n\n\tprivate String normalizeRequestUrl(String requestUrl) {\n\t\tif (requestUrl.endsWith(\"/\")) {\n\t\t\treturn requestUrl.substring(0, requestUrl.length() - 1);\n\t\t}\n\t\treturn requestUrl;\n\t}\n\n\tprivate void collectLinks(Map<String, Link> links, ExposableWebEndpoint endpoint, String normalizedUrl) {\n\t\tfor (WebOperation operation : endpoint.getOperations()) {\n\t\t\tlinks.put(operation.getId(), createLink(normalizedUrl, operation));\n\t\t}\n\t}\n\n\tprivate Link createLink(String requestUrl, WebOperation operation) {\n\t\treturn createLink(requestUrl, operation.getRequestPredicate().getPath());\n\t}\n\n\tprivate Link createLink(String requestUrl, String path) {\n\t\treturn new Link(requestUrl + (path.startsWith(\"/\") ? path : \"/\" + path));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * A value object for the base mapping for endpoints.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class EndpointMapping {\n\n\tprivate final String path;\n\n\t/**\n\t * Creates a new {@code EndpointMapping} using the given {@code path}.\n\t * @param path the path\n\t */\n\tpublic EndpointMapping(String path) {\n\t\tthis.path = normalizePath(path);\n\t}\n\n\t/**\n\t * Returns the path to which endpoints should be mapped.\n\t * @return the path\n\t */\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\tpublic String createSubPath(String path) {\n\t\treturn this.path + normalizePath(path);\n\t}\n\n\tprivate static String normalizePath(String path) {\n\t\tif (!StringUtils.hasText(path)) {\n\t\t\treturn path;\n\t\t}\n\t\tString normalizedPath = path;\n\t\tif (!normalizedPath.startsWith(\"/\")) {\n\t\t\tnormalizedPath = \"/\" + normalizedPath;\n\t\t}\n\t\tif (normalizedPath.endsWith(\"/\")) {\n\t\t\tnormalizedPath = normalizedPath.substring(0, normalizedPath.length() - 1);\n\t\t}\n\t\treturn normalizedPath;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointMediaTypes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.util.Assert;\n\n/**\n * Media types that are, by default, produced and consumed by an endpoint.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class EndpointMediaTypes {\n\n\t/**\n\t * Default {@link EndpointMediaTypes} for this version of Spring Boot.\n\t */\n\tpublic static final EndpointMediaTypes DEFAULT = new EndpointMediaTypes(\n\t\t\tApiVersion.V3.getProducedMimeType().toString(), ApiVersion.V2.getProducedMimeType().toString(),\n\t\t\t\"application/json\");\n\n\tprivate final List<String> produced;\n\n\tprivate final List<String> consumed;\n\n\t/**\n\t * Creates a new {@link EndpointMediaTypes} with the given {@code produced} and\n\t * {@code consumed} media types.\n\t * @param producedAndConsumed the default media types that are produced and consumed\n\t * by an endpoint. Must not be {@code null}.\n\t * @since 2.2.0\n\t */\n\tpublic EndpointMediaTypes(String... producedAndConsumed) {\n\t\tthis(toList(producedAndConsumed));\n\t}\n\n\tprivate static List<String> toList(String[] producedAndConsumed) {\n\t\tAssert.notNull(producedAndConsumed, \"'producedAndConsumed' must not be null\");\n\t\treturn Arrays.asList(producedAndConsumed);\n\t}\n\n\t/**\n\t * Creates a new {@link EndpointMediaTypes} with the given {@code produced} and\n\t * {@code consumed} media types.\n\t * @param producedAndConsumed the default media types that are produced and consumed\n\t * by an endpoint. Must not be {@code null}.\n\t * @since 2.2.0\n\t */\n\tpublic EndpointMediaTypes(List<String> producedAndConsumed) {\n\t\tthis(producedAndConsumed, producedAndConsumed);\n\t}\n\n\t/**\n\t * Creates a new {@link EndpointMediaTypes} with the given {@code produced} and\n\t * {@code consumed} media types.\n\t * @param produced the default media types that are produced by an endpoint. Must not\n\t * be {@code null}.\n\t * @param consumed the default media types that are consumed by an endpoint. Must not\n\t */\n\tpublic EndpointMediaTypes(List<String> produced, List<String> consumed) {\n\t\tAssert.notNull(produced, \"'produced' must not be null\");\n\t\tAssert.notNull(consumed, \"'consumed' must not be null\");\n\t\tthis.produced = Collections.unmodifiableList(produced);\n\t\tthis.consumed = Collections.unmodifiableList(consumed);\n\t}\n\n\t/**\n\t * Returns the media types produced by an endpoint.\n\t * @return the produced media types\n\t */\n\tpublic List<String> getProduced() {\n\t\treturn this.produced;\n\t}\n\n\t/**\n\t * Returns the media types consumed by an endpoint.\n\t * @return the consumed media types\n\t */\n\tpublic List<String> getConsumed() {\n\t\treturn this.consumed;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/EndpointServlet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletRegistration.Dynamic;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Contains details of a servlet that is exposed as an actuator endpoint.\n *\n * @author Phillip Webb\n * @author Julio José Gómez Díaz\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@Deprecated(since = \"3.3.0\", forRemoval = true)\npublic final class EndpointServlet {\n\n\tprivate final Servlet servlet;\n\n\tprivate final Map<String, String> initParameters;\n\n\tprivate final int loadOnStartup;\n\n\tpublic EndpointServlet(Class<? extends Servlet> servlet) {\n\t\tthis(instantiateClass(servlet));\n\t}\n\n\tprivate static Servlet instantiateClass(Class<? extends Servlet> servlet) {\n\t\tAssert.notNull(servlet, \"'servlet' must not be null\");\n\t\treturn BeanUtils.instantiateClass(servlet);\n\t}\n\n\tpublic EndpointServlet(Servlet servlet) {\n\t\tthis(servlet, Collections.emptyMap(), -1);\n\t}\n\n\tprivate EndpointServlet(Servlet servlet, Map<String, String> initParameters, int loadOnStartup) {\n\t\tAssert.notNull(servlet, \"'servlet' must not be null\");\n\t\tthis.servlet = servlet;\n\t\tthis.initParameters = Collections.unmodifiableMap(initParameters);\n\t\tthis.loadOnStartup = loadOnStartup;\n\t}\n\n\tpublic EndpointServlet withInitParameter(String name, String value) {\n\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\treturn withInitParameters(Collections.singletonMap(name, value));\n\t}\n\n\tpublic EndpointServlet withInitParameters(Map<String, String> initParameters) {\n\t\tAssert.notNull(initParameters, \"'initParameters' must not be null\");\n\t\tboolean hasEmptyName = initParameters.keySet().stream().anyMatch((name) -> !StringUtils.hasText(name));\n\t\tAssert.isTrue(!hasEmptyName, \"'initParameters' must not contain empty names\");\n\t\tMap<String, String> mergedInitParameters = new LinkedHashMap<>(this.initParameters);\n\t\tmergedInitParameters.putAll(initParameters);\n\t\treturn new EndpointServlet(this.servlet, mergedInitParameters, this.loadOnStartup);\n\t}\n\n\t/**\n\t * Sets the {@code loadOnStartup} priority that will be set on Servlet registration.\n\t * The default value for {@code loadOnStartup} is {@code -1}.\n\t * @param loadOnStartup the initialization priority of the Servlet\n\t * @return a new instance of {@link EndpointServlet} with the provided\n\t * {@code loadOnStartup} value set\n\t * @since 2.2.0\n\t * @see Dynamic#setLoadOnStartup(int)\n\t */\n\tpublic EndpointServlet withLoadOnStartup(int loadOnStartup) {\n\t\treturn new EndpointServlet(this.servlet, this.initParameters, loadOnStartup);\n\t}\n\n\tServlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tMap<String, String> getInitParameters() {\n\t\treturn this.initParameters;\n\t}\n\n\tint getLoadOnStartup() {\n\t\treturn this.loadOnStartup;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ExposableServletEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\n\n/**\n * Information describing an endpoint that can be exposed by registering a servlet.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@Deprecated(since = \"3.3.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic interface ExposableServletEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {\n\n\t/**\n\t * Return details of the servlet that should be registered.\n\t * @return the endpoint servlet\n\t */\n\tEndpointServlet getEndpointServlet();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ExposableWebEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\n\n/**\n * Information describing an endpoint that can be exposed over the web.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface ExposableWebEndpoint extends ExposableEndpoint<WebOperation>, PathMappedEndpoint {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/Link.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\n\n/**\n * Details for a link in a\n * <a href=\"https://tools.ietf.org/html/draft-kelly-json-hal-08\">HAL</a>-formatted\n * response.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class Link {\n\n\tprivate final String href;\n\n\tprivate final boolean templated;\n\n\t/**\n\t * Creates a new {@link Link} with the given {@code href}.\n\t * @param href the href\n\t */\n\tpublic Link(String href) {\n\t\tAssert.notNull(href, \"'href' must not be null\");\n\t\tthis.href = href;\n\t\tthis.templated = href.contains(\"{\");\n\t}\n\n\t/**\n\t * Returns the href of the link.\n\t * @return the href\n\t */\n\tpublic String getHref() {\n\t\treturn this.href;\n\t}\n\n\t/**\n\t * Returns whether the {@link #getHref() href} is templated.\n\t * @return {@code true} if the href is templated, otherwise {@code false}\n\t */\n\tpublic boolean isTemplated() {\n\t\treturn this.templated;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new ToStringCreator(this).append(\"href\", this.href).toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\n\n/**\n * Interface that can be implemented by an {@link ExposableEndpoint} that is mapped to a\n * root web path.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see PathMapper\n */\n@FunctionalInterface\npublic interface PathMappedEndpoint {\n\n\t/**\n\t * Return the root path of the endpoint (relative to the context and base path) that\n\t * exposes it. For example, a root path of {@code example} would be exposed under the\n\t * URL \"/{actuator-context}/example\".\n\t * @return the root path for the endpoint\n\t * @see PathMappedEndpoints#getBasePath\n\t */\n\tString getRootPath();\n\n\t/**\n\t * Return any additional paths (relative to the context) for the given\n\t * {@link WebServerNamespace}.\n\t * @param webServerNamespace the web server namespace\n\t * @return a list of additional paths\n\t * @since 3.4.0\n\t */\n\tdefault List<String> getAdditionalPaths(WebServerNamespace webServerNamespace) {\n\t\treturn Collections.emptyList();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpoints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * A collection of {@link PathMappedEndpoint path mapped endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class PathMappedEndpoints implements Iterable<PathMappedEndpoint> {\n\n\tprivate final String basePath;\n\n\tprivate final Map<EndpointId, PathMappedEndpoint> endpoints;\n\n\t/**\n\t * Create a new {@link PathMappedEndpoints} instance for the given supplier.\n\t * @param basePath the base path of the endpoints\n\t * @param supplier the endpoint supplier\n\t */\n\tpublic PathMappedEndpoints(@Nullable String basePath, EndpointsSupplier<?> supplier) {\n\t\tAssert.notNull(supplier, \"'supplier' must not be null\");\n\t\tthis.basePath = (basePath != null) ? basePath : \"\";\n\t\tthis.endpoints = getEndpoints(Collections.singleton(supplier));\n\t}\n\n\t/**\n\t * Create a new {@link PathMappedEndpoints} instance for the given suppliers.\n\t * @param basePath the base path of the endpoints\n\t * @param suppliers the endpoint suppliers\n\t */\n\tpublic PathMappedEndpoints(@Nullable String basePath, Collection<EndpointsSupplier<?>> suppliers) {\n\t\tAssert.notNull(suppliers, \"'suppliers' must not be null\");\n\t\tthis.basePath = (basePath != null) ? basePath : \"\";\n\t\tthis.endpoints = getEndpoints(suppliers);\n\t}\n\n\tprivate Map<EndpointId, PathMappedEndpoint> getEndpoints(Collection<EndpointsSupplier<?>> suppliers) {\n\t\tMap<EndpointId, PathMappedEndpoint> endpoints = new LinkedHashMap<>();\n\t\tsuppliers.forEach((supplier) -> supplier.getEndpoints().forEach((endpoint) -> {\n\t\t\tif (endpoint instanceof PathMappedEndpoint pathMappedEndpoint) {\n\t\t\t\tendpoints.put(endpoint.getEndpointId(), pathMappedEndpoint);\n\t\t\t}\n\t\t}));\n\t\treturn Collections.unmodifiableMap(endpoints);\n\t}\n\n\t/**\n\t * Return the base path for the endpoints.\n\t * @return the base path\n\t */\n\tpublic String getBasePath() {\n\t\treturn this.basePath;\n\t}\n\n\t/**\n\t * Return the root path for the endpoint with the given ID or {@code null} if the\n\t * endpoint cannot be found.\n\t * @param endpointId the endpoint ID\n\t * @return the root path or {@code null}\n\t */\n\tpublic @Nullable String getRootPath(EndpointId endpointId) {\n\t\tPathMappedEndpoint endpoint = getEndpoint(endpointId);\n\t\treturn (endpoint != null) ? endpoint.getRootPath() : null;\n\t}\n\n\t/**\n\t * Return the full path for the endpoint with the given ID or {@code null} if the\n\t * endpoint cannot be found.\n\t * @param endpointId the endpoint ID\n\t * @return the full path or {@code null}\n\t */\n\tpublic @Nullable String getPath(EndpointId endpointId) {\n\t\treturn getPath(getEndpoint(endpointId));\n\t}\n\n\t/**\n\t * Return the root paths for each mapped endpoint (excluding additional paths).\n\t * @return all root paths\n\t */\n\tpublic Collection<String> getAllRootPaths() {\n\t\treturn stream().map(PathMappedEndpoint::getRootPath).toList();\n\t}\n\n\t/**\n\t * Return the full paths for each mapped endpoint (excluding additional paths).\n\t * @return all root paths\n\t */\n\tpublic Collection<String> getAllPaths() {\n\t\treturn stream().map(this::getPath).toList();\n\t}\n\n\t/**\n\t * Return the additional paths for each mapped endpoint.\n\t * @param webServerNamespace the web server namespace\n\t * @param endpointId the endpoint ID\n\t * @return all additional paths\n\t * @since 3.4.0\n\t */\n\tpublic Collection<String> getAdditionalPaths(WebServerNamespace webServerNamespace, EndpointId endpointId) {\n\t\treturn getAdditionalPaths(webServerNamespace, getEndpoint(endpointId)).toList();\n\t}\n\n\tprivate Stream<String> getAdditionalPaths(WebServerNamespace webServerNamespace,\n\t\t\t@Nullable PathMappedEndpoint endpoint) {\n\t\tList<String> additionalPaths = (endpoint != null) ? endpoint.getAdditionalPaths(webServerNamespace) : null;\n\t\tif (CollectionUtils.isEmpty(additionalPaths)) {\n\t\t\treturn Stream.empty();\n\t\t}\n\t\treturn additionalPaths.stream().map(this::getAdditionalPath);\n\t}\n\n\tprivate String getAdditionalPath(String path) {\n\t\treturn path.startsWith(\"/\") ? path : \"/\" + path;\n\t}\n\n\t/**\n\t * Return the {@link PathMappedEndpoint} with the given ID or {@code null} if the\n\t * endpoint cannot be found.\n\t * @param endpointId the endpoint ID\n\t * @return the path mapped endpoint or {@code null}\n\t */\n\tpublic @Nullable PathMappedEndpoint getEndpoint(EndpointId endpointId) {\n\t\treturn this.endpoints.get(endpointId);\n\t}\n\n\t/**\n\t * Stream all {@link PathMappedEndpoint path mapped endpoints}.\n\t * @return a stream of endpoints\n\t */\n\tpublic Stream<PathMappedEndpoint> stream() {\n\t\treturn this.endpoints.values().stream();\n\t}\n\n\t@Override\n\tpublic Iterator<PathMappedEndpoint> iterator() {\n\t\treturn this.endpoints.values().iterator();\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate @Nullable String getPath(@Nullable PathMappedEndpoint endpoint) {\n\t\tif (endpoint == null) {\n\t\t\treturn null;\n\t\t}\n\t\tStringBuilder path = new StringBuilder(this.basePath);\n\t\tif (!this.basePath.equals(\"/\")) {\n\t\t\tpath.append(\"/\");\n\t\t}\n\t\tif (!endpoint.getRootPath().equals(\"/\")) {\n\t\t\tpath.append(endpoint.getRootPath());\n\t\t}\n\t\treturn path.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/PathMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Strategy interface used to provide a mapping between an endpoint ID and the root path\n * where it will be exposed.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface PathMapper {\n\n\t/**\n\t * Resolve the root path for the specified {@code endpointId}.\n\t * @param endpointId the id of an endpoint\n\t * @return the path of the endpoint or {@code null} if this mapper doesn't support the\n\t * given endpoint ID\n\t */\n\t@Nullable String getRootPath(EndpointId endpointId);\n\n\t/**\n\t * Resolve the root path for the specified {@code endpointId} from the given path\n\t * mappers. If no mapper matches then the ID itself is returned.\n\t * @param pathMappers the path mappers (may be {@code null})\n\t * @param endpointId the id of an endpoint\n\t * @return the path of the endpoint\n\t */\n\tstatic String getRootPath(@Nullable List<PathMapper> pathMappers, EndpointId endpointId) {\n\t\tAssert.notNull(endpointId, \"'endpointId' must not be null\");\n\t\tif (pathMappers != null) {\n\t\t\tfor (PathMapper mapper : pathMappers) {\n\t\t\t\tString path = mapper.getRootPath(endpointId);\n\t\t\t\tif (StringUtils.hasText(path)) {\n\t\t\t\t\treturn path;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn endpointId.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.EnumSet;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration.Dynamic;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ServletContextInitializer} to register {@link ExposableServletEndpoint servlet\n * endpoints}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ServletEndpointRegistrar implements ServletContextInitializer {\n\n\tprivate static final Set<String> READ_ONLY_ACCESS_REQUEST_METHODS = Set.of(\"GET\", \"HEAD\");\n\n\tprivate static final Log logger = LogFactory.getLog(ServletEndpointRegistrar.class);\n\n\tprivate final String basePath;\n\n\tprivate final Collection<ExposableServletEndpoint> servletEndpoints;\n\n\tprivate final EndpointAccessResolver endpointAccessResolver;\n\n\tpublic ServletEndpointRegistrar(@Nullable String basePath, Collection<ExposableServletEndpoint> servletEndpoints) {\n\t\tthis(basePath, servletEndpoints, (endpointId, defaultAccess) -> Access.NONE);\n\t}\n\n\tpublic ServletEndpointRegistrar(@Nullable String basePath, Collection<ExposableServletEndpoint> servletEndpoints,\n\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\tAssert.notNull(servletEndpoints, \"'servletEndpoints' must not be null\");\n\t\tthis.basePath = cleanBasePath(basePath);\n\t\tthis.servletEndpoints = servletEndpoints;\n\t\tthis.endpointAccessResolver = endpointAccessResolver;\n\t}\n\n\tprivate static String cleanBasePath(@Nullable String basePath) {\n\t\tif (StringUtils.hasText(basePath) && basePath.endsWith(\"/\")) {\n\t\t\treturn basePath.substring(0, basePath.length() - 1);\n\t\t}\n\t\treturn (basePath != null) ? basePath : \"\";\n\t}\n\n\t@Override\n\tpublic void onStartup(ServletContext servletContext) throws ServletException {\n\t\tthis.servletEndpoints.forEach((servletEndpoint) -> register(servletContext, servletEndpoint));\n\t}\n\n\tprivate void register(ServletContext servletContext, ExposableServletEndpoint endpoint) {\n\t\tAccess access = this.endpointAccessResolver.accessFor(endpoint.getEndpointId(), endpoint.getDefaultAccess());\n\t\tif (access == Access.NONE) {\n\t\t\treturn;\n\t\t}\n\t\tString name = endpoint.getEndpointId().toLowerCaseString() + \"-actuator-endpoint\";\n\t\tString path = this.basePath + \"/\" + endpoint.getRootPath();\n\t\tString urlMapping = path.endsWith(\"/\") ? path + \"*\" : path + \"/*\";\n\t\tEndpointServlet endpointServlet = endpoint.getEndpointServlet();\n\t\tDynamic registration = servletContext.addServlet(name, endpointServlet.getServlet());\n\t\tregistration.addMapping(urlMapping);\n\t\tregistration.setInitParameters(endpointServlet.getInitParameters());\n\t\tregistration.setLoadOnStartup(endpointServlet.getLoadOnStartup());\n\t\tif (access == Access.READ_ONLY) {\n\t\t\tservletContext.addFilter(name + \"-access-filter\", new ReadOnlyAccessFilter())\n\t\t\t\t.addMappingForServletNames(EnumSet.allOf(DispatcherType.class), false, name);\n\t\t}\n\t\tlogger.info(\"Registered '\" + path + \"' to \" + name);\n\t}\n\n\tstatic class ReadOnlyAccessFilter implements Filter {\n\n\t\tprivate static final int METHOD_NOT_ALLOWED = 405;\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\tthrows IOException, ServletException {\n\t\t\tif (request instanceof HttpServletRequest httpRequest\n\t\t\t\t\t&& response instanceof HttpServletResponse httpResponse) {\n\t\t\t\tdoFilter(httpRequest, httpResponse, chain);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new ServletException();\n\t\t\t}\n\t\t}\n\n\t\tprivate void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)\n\t\t\t\tthrows IOException, ServletException {\n\t\t\tif (isReadOnlyAccessMethod(request)) {\n\t\t\t\tchain.doFilter(request, response);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tresponse.sendError(METHOD_NOT_ALLOWED);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isReadOnlyAccessMethod(HttpServletRequest request) {\n\t\t\treturn READ_ONLY_ACCESS_REQUEST_METHODS.contains(request.getMethod().toUpperCase(Locale.ROOT));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointHttpMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\n/**\n * An enumeration of HTTP methods supported by web endpoint operations.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic enum WebEndpointHttpMethod {\n\n\t/**\n\t * An HTTP GET request.\n\t */\n\tGET,\n\n\t/**\n\t * An HTTP POST request.\n\t */\n\tPOST,\n\n\t/**\n\t * An HTTP DELETE request.\n\t */\n\tDELETE\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Producible;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.util.MimeType;\n\n/**\n * A {@code WebEndpointResponse} can be returned by an operation on a\n * {@link EndpointWebExtension @EndpointWebExtension} to provide additional, web-specific\n * information such as the HTTP status code.\n *\n * @param <T> the type of the response body\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @since 2.0.0\n */\npublic final class WebEndpointResponse<T> {\n\n\t/**\n\t * {@code 200 OK}.\n\t */\n\tpublic static final int STATUS_OK = 200;\n\n\t/**\n\t * {@code 204 No Content}.\n\t */\n\tpublic static final int STATUS_NO_CONTENT = 204;\n\n\t/**\n\t * {@code 400 Bad Request}.\n\t */\n\tpublic static final int STATUS_BAD_REQUEST = 400;\n\n\t/**\n\t * {@code 404 Not Found}.\n\t */\n\tpublic static final int STATUS_NOT_FOUND = 404;\n\n\t/**\n\t * {@code 429 Too Many Requests}.\n\t */\n\tpublic static final int STATUS_TOO_MANY_REQUESTS = 429;\n\n\t/**\n\t * {@code 500 Internal Server Error}.\n\t */\n\tpublic static final int STATUS_INTERNAL_SERVER_ERROR = 500;\n\n\t/**\n\t * {@code 503 Service Unavailable}.\n\t */\n\tpublic static final int STATUS_SERVICE_UNAVAILABLE = 503;\n\n\tprivate final @Nullable T body;\n\n\tprivate final int status;\n\n\tprivate final @Nullable MimeType contentType;\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with no body and a 200 (OK) status.\n\t */\n\tpublic WebEndpointResponse() {\n\t\tthis(null);\n\t}\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with no body and the given\n\t * {@code status}.\n\t * @param status the HTTP status\n\t */\n\tpublic WebEndpointResponse(int status) {\n\t\tthis(null, status);\n\t}\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with the given body and a 200 (OK)\n\t * status.\n\t * @param body the body\n\t */\n\tpublic WebEndpointResponse(@Nullable T body) {\n\t\tthis(body, STATUS_OK);\n\t}\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with the given body and content type and\n\t * a 200 (OK) status.\n\t * @param body the body\n\t * @param producible the producible providing the content type\n\t * @since 2.5.0\n\t */\n\tpublic WebEndpointResponse(@Nullable T body, Producible<?> producible) {\n\t\tthis(body, STATUS_OK, producible.getProducedMimeType());\n\t}\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with the given body and content type and\n\t * a 200 (OK) status.\n\t * @param body the body\n\t * @param contentType the content type of the response\n\t * @since 2.5.0\n\t */\n\tpublic WebEndpointResponse(@Nullable T body, MimeType contentType) {\n\t\tthis(body, STATUS_OK, contentType);\n\t}\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with the given body and status.\n\t * @param body the body\n\t * @param status the HTTP status\n\t */\n\tpublic WebEndpointResponse(@Nullable T body, int status) {\n\t\tthis(body, status, null);\n\t}\n\n\t/**\n\t * Creates a new {@code WebEndpointResponse} with the given body and status.\n\t * @param body the body\n\t * @param status the HTTP status\n\t * @param contentType the content type of the response\n\t * @since 2.5.0\n\t */\n\tpublic WebEndpointResponse(@Nullable T body, int status, @Nullable MimeType contentType) {\n\t\tthis.body = body;\n\t\tthis.status = status;\n\t\tthis.contentType = contentType;\n\t}\n\n\t/**\n\t * Returns the content type of the response.\n\t * @return the content type;\n\t */\n\tpublic @Nullable MimeType getContentType() {\n\t\treturn this.contentType;\n\t}\n\n\t/**\n\t * Returns the body for the response.\n\t * @return the body\n\t */\n\tpublic @Nullable T getBody() {\n\t\treturn this.body;\n\t}\n\n\t/**\n\t * Returns the status for the response.\n\t * @return the status\n\t */\n\tpublic int getStatus() {\n\t\treturn this.status;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebEndpointsSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\n\n/**\n * {@link EndpointsSupplier} for {@link ExposableWebEndpoint web endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface WebEndpointsSupplier extends EndpointsSupplier<ExposableWebEndpoint> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.springframework.boot.actuate.endpoint.Operation;\n\n/**\n * An operation on a web endpoint.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic interface WebOperation extends Operation {\n\n\t/**\n\t * Returns the ID of the operation that uniquely identifies it within its endpoint.\n\t * @return the ID\n\t */\n\tString getId();\n\n\t/**\n\t * Returns if the underlying operation is blocking.\n\t * @return {@code true} if the operation is blocking\n\t */\n\tboolean isBlocking();\n\n\t/**\n\t * Returns the predicate for requests that can be handled by this operation.\n\t * @return the predicate\n\t */\n\tWebOperationRequestPredicate getRequestPredicate();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebOperationRequestPredicate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A predicate for a request to an operation on a web endpoint.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic final class WebOperationRequestPredicate {\n\n\tprivate static final Pattern PATH_VAR_PATTERN = Pattern.compile(\"(\\\\{\\\\*?).+?}\");\n\n\tprivate static final Pattern ALL_REMAINING_PATH_SEGMENTS_VAR_PATTERN = Pattern.compile(\"^.*\\\\{\\\\*(.+?)}$\");\n\n\tprivate final String path;\n\n\tprivate final @Nullable String matchAllRemainingPathSegmentsVariable;\n\n\tprivate final String canonicalPath;\n\n\tprivate final WebEndpointHttpMethod httpMethod;\n\n\tprivate final Collection<String> consumes;\n\n\tprivate final Collection<String> produces;\n\n\t/**\n\t * Creates a new {@code OperationRequestPredicate}.\n\t * @param path the path for the operation\n\t * @param httpMethod the HTTP method that the operation supports\n\t * @param produces the media types that the operation produces\n\t * @param consumes the media types that the operation consumes\n\t */\n\tpublic WebOperationRequestPredicate(String path, WebEndpointHttpMethod httpMethod, Collection<String> consumes,\n\t\t\tCollection<String> produces) {\n\t\tthis.path = path;\n\t\tthis.canonicalPath = extractCanonicalPath(path);\n\t\tthis.matchAllRemainingPathSegmentsVariable = extractMatchAllRemainingPathSegmentsVariable(path);\n\t\tthis.httpMethod = httpMethod;\n\t\tthis.consumes = consumes;\n\t\tthis.produces = produces;\n\t}\n\n\tprivate String extractCanonicalPath(String path) {\n\t\tMatcher matcher = PATH_VAR_PATTERN.matcher(path);\n\t\treturn matcher.replaceAll(\"$1*}\");\n\t}\n\n\tprivate @Nullable String extractMatchAllRemainingPathSegmentsVariable(String path) {\n\t\tMatcher matcher = ALL_REMAINING_PATH_SEGMENTS_VAR_PATTERN.matcher(path);\n\t\treturn matcher.matches() ? matcher.group(1) : null;\n\t}\n\n\t/**\n\t * Returns the path for the operation.\n\t * @return the path\n\t */\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\t/**\n\t * Returns the name of the variable used to catch all remaining path segments or\n\t * {@code null}.\n\t * @return the variable name\n\t * @since 2.2.0\n\t */\n\tpublic @Nullable String getMatchAllRemainingPathSegmentsVariable() {\n\t\treturn this.matchAllRemainingPathSegmentsVariable;\n\t}\n\n\t/**\n\t * Returns the HTTP method for the operation.\n\t * @return the HTTP method\n\t */\n\tpublic WebEndpointHttpMethod getHttpMethod() {\n\t\treturn this.httpMethod;\n\t}\n\n\t/**\n\t * Returns the media types that the operation consumes.\n\t * @return the consumed media types\n\t */\n\tpublic Collection<String> getConsumes() {\n\t\treturn Collections.unmodifiableCollection(this.consumes);\n\t}\n\n\t/**\n\t * Returns the media types that the operation produces.\n\t * @return the produced media types\n\t */\n\tpublic Collection<String> getProduces() {\n\t\treturn Collections.unmodifiableCollection(this.produces);\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tWebOperationRequestPredicate other = (WebOperationRequestPredicate) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.consumes.equals(other.consumes);\n\t\tresult = result && this.httpMethod == other.httpMethod;\n\t\tresult = result && this.canonicalPath.equals(other.canonicalPath);\n\t\tresult = result && this.produces.equals(other.produces);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.consumes.hashCode();\n\t\tresult = prime * result + this.httpMethod.hashCode();\n\t\tresult = prime * result + this.canonicalPath.hashCode();\n\t\tresult = prime * result + this.produces.hashCode();\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tStringBuilder result = new StringBuilder(this.httpMethod + \" to path '\" + this.path + \"'\");\n\t\tif (!CollectionUtils.isEmpty(this.consumes)) {\n\t\t\tresult.append(\" consumes: \").append(StringUtils.collectionToCommaDelimitedString(this.consumes));\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.produces)) {\n\t\t\tresult.append(\" produces: \").append(StringUtils.collectionToCommaDelimitedString(this.produces));\n\t\t}\n\t\treturn result.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/WebServerNamespace.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A web server namespace used for disambiguation when multiple web servers are running in\n * the same application (for example a management context running on a different port).\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 2.6.0\n */\npublic final class WebServerNamespace {\n\n\tprivate static final String WEB_SERVER_CONTEXT_CLASS = \"org.springframework.boot.web.server.context.WebServerApplicationContext\";\n\n\t/**\n\t * {@link WebServerNamespace} that represents the main server.\n\t */\n\tpublic static final WebServerNamespace SERVER = new WebServerNamespace(\"server\");\n\n\t/**\n\t * {@link WebServerNamespace} that represents the management server.\n\t */\n\tpublic static final WebServerNamespace MANAGEMENT = new WebServerNamespace(\"management\");\n\n\tprivate final String value;\n\n\tprivate WebServerNamespace(String value) {\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Return the value of the namespace.\n\t * @return the value\n\t */\n\tpublic String getValue() {\n\t\treturn this.value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tWebServerNamespace other = (WebServerNamespace) obj;\n\t\treturn this.value.equals(other.value);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.value.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link WebServerNamespace} from a value. If the\n\t * context is {@code null} or not a web server context then {@link #SERVER} is\n\t * returned.\n\t * @param context the application context\n\t * @return the web server namespace\n\t * @since 4.0.1\n\t */\n\tpublic static WebServerNamespace from(@Nullable ApplicationContext context) {\n\t\tif (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {\n\t\t\treturn SERVER;\n\t\t}\n\t\treturn from(WebServerApplicationContext.getServerNamespace(context));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link WebServerNamespace} from a value. If the\n\t * value is empty or {@code null} then {@link #SERVER} is returned.\n\t * @param value the namespace value or {@code null}\n\t * @return the web server namespace\n\t */\n\tpublic static WebServerNamespace from(@Nullable String value) {\n\t\tif (StringUtils.hasText(value)) {\n\t\t\treturn new WebServerNamespace(value);\n\t\t}\n\t\treturn SERVER;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\n\n/**\n * Identifies a type as being an endpoint that is only exposed over Spring MVC or Spring\n * WebFlux. Mapped methods must be annotated with {@link GetMapping @GetMapping},\n * {@link PostMapping @PostMapping}, {@link DeleteMapping @DeleteMapping}, etc.\n * annotations rather than {@link ReadOperation @ReadOperation},\n * {@link WriteOperation @WriteOperation}, {@link DeleteOperation @DeleteOperation}.\n * <p>\n * This annotation can be used when deeper Spring integration is required, but at the\n * expense of portability. Most users should prefer the {@link Endpoint @Endpoint} or\n * {@link WebEndpoint @WebEndpoint} annotation whenever possible.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see WebEndpoint\n * @see RestControllerEndpoint\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Endpoint\n@FilteredEndpoint(ControllerEndpointFilter.class)\n@Deprecated(since = \"3.3.0\", forRemoval = true)\npublic @interface ControllerEndpoint {\n\n\t/**\n\t * The id of the endpoint.\n\t * @return the id\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tString id();\n\n\t/**\n\t * Level of access to the endpoint that is permitted by default.\n\t * @return the default level of access\n\t * @since 3.4.0\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tAccess defaultAccess() default Access.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscoverer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\n\n/**\n * {@link EndpointDiscoverer} for {@link ExposableControllerEndpoint controller\n * endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@ImportRuntimeHints(ControllerEndpointDiscoverer.ControllerEndpointDiscovererRuntimeHints.class)\n@Deprecated(since = \"3.3.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ControllerEndpointDiscoverer extends EndpointDiscoverer<ExposableControllerEndpoint, Operation>\n\t\timplements ControllerEndpointsSupplier {\n\n\tprivate final @Nullable List<PathMapper> endpointPathMappers;\n\n\t/**\n\t * Create a new {@link ControllerEndpointDiscoverer} instance.\n\t * @param applicationContext the source application context\n\t * @param endpointPathMappers the endpoint path mappers\n\t * @param filters filters to apply\n\t */\n\tpublic ControllerEndpointDiscoverer(ApplicationContext applicationContext,\n\t\t\t@Nullable List<PathMapper> endpointPathMappers,\n\t\t\tCollection<EndpointFilter<ExposableControllerEndpoint>> filters) {\n\t\tsuper(applicationContext, ParameterValueMapper.NONE, Collections.emptyList(), filters, Collections.emptyList());\n\t\tthis.endpointPathMappers = endpointPathMappers;\n\t}\n\n\t@Override\n\tprotected boolean isEndpointTypeExposed(Class<?> beanType) {\n\t\tMergedAnnotations annotations = MergedAnnotations.from(beanType, SearchStrategy.SUPERCLASS);\n\t\treturn annotations.isPresent(ControllerEndpoint.class) || annotations.isPresent(RestControllerEndpoint.class);\n\t}\n\n\t@Override\n\tprotected ExposableControllerEndpoint createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\tCollection<Operation> operations) {\n\t\tString rootPath = PathMapper.getRootPath(this.endpointPathMappers, id);\n\t\treturn new DiscoveredControllerEndpoint(this, endpointBean, id, rootPath, defaultAccess);\n\t}\n\n\t@Override\n\tprotected Operation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\tOperationInvoker invoker) {\n\t\tthrow new IllegalStateException(\"ControllerEndpoints must not declare operations\");\n\t}\n\n\t@Override\n\tprotected OperationKey createOperationKey(Operation operation) {\n\t\tthrow new IllegalStateException(\"ControllerEndpoints must not declare operations\");\n\t}\n\n\t@Override\n\tprotected boolean isInvocable(ExposableControllerEndpoint endpoint) {\n\t\treturn true;\n\t}\n\n\tstatic class ControllerEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerType(ControllerEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;\n\n/**\n * {@link EndpointFilter} for endpoints discovered by\n * {@link ControllerEndpointDiscoverer}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass ControllerEndpointFilter extends DiscovererEndpointFilter {\n\n\tControllerEndpointFilter() {\n\t\tsuper(ControllerEndpointDiscoverer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointsSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\n\n/**\n * {@link EndpointsSupplier} for {@link ExposableControllerEndpoint controller endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.3 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@FunctionalInterface\n@Deprecated(since = \"3.3.3\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic interface ControllerEndpointsSupplier extends EndpointsSupplier<ExposableControllerEndpoint> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collections;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\n\n/**\n * A discovered {@link ExposableControllerEndpoint controller endpoint}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass DiscoveredControllerEndpoint extends AbstractDiscoveredEndpoint<Operation>\n\t\timplements ExposableControllerEndpoint {\n\n\tprivate final String rootPath;\n\n\tDiscoveredControllerEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id,\n\t\t\tString rootPath, Access defaultAccess) {\n\t\tsuper(discoverer, endpointBean, id, defaultAccess, Collections.emptyList());\n\t\tthis.rootPath = rootPath;\n\t}\n\n\t@Override\n\tpublic Object getController() {\n\t\treturn getEndpointBean();\n\t}\n\n\t@Override\n\tpublic String getRootPath() {\n\t\treturn this.rootPath;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredServletEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collections;\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.web.EndpointServlet;\nimport org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;\nimport org.springframework.util.Assert;\n\n/**\n * A discovered {@link ExposableServletEndpoint servlet endpoint}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass DiscoveredServletEndpoint extends AbstractDiscoveredEndpoint<Operation> implements ExposableServletEndpoint {\n\n\tprivate final String rootPath;\n\n\tprivate final EndpointServlet endpointServlet;\n\n\tDiscoveredServletEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id, String rootPath,\n\t\t\tAccess defaultAccess) {\n\t\tsuper(discoverer, endpointBean, id, defaultAccess, Collections.emptyList());\n\t\tString beanType = endpointBean.getClass().getName();\n\t\tAssert.state(endpointBean instanceof Supplier,\n\t\t\t\t() -> \"ServletEndpoint bean \" + beanType + \" must be a supplier\");\n\t\tObject supplied = ((Supplier<?>) endpointBean).get();\n\t\tAssert.state(supplied != null, () -> \"ServletEndpoint bean \" + beanType + \" must not supply null\");\n\t\tAssert.state(supplied instanceof EndpointServlet,\n\t\t\t\t() -> \"ServletEndpoint bean \" + beanType + \" must supply an EndpointServlet\");\n\t\tthis.endpointServlet = (EndpointServlet) supplied;\n\t\tthis.rootPath = rootPath;\n\t}\n\n\t@Override\n\tpublic String getRootPath() {\n\t\treturn this.rootPath;\n\t}\n\n\t@Override\n\tpublic EndpointServlet getEndpointServlet() {\n\t\treturn this.endpointServlet;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\n\n/**\n * A discovered {@link ExposableWebEndpoint web endpoint}.\n *\n * @author Phillip Webb\n */\nclass DiscoveredWebEndpoint extends AbstractDiscoveredEndpoint<WebOperation> implements ExposableWebEndpoint {\n\n\tprivate final String rootPath;\n\n\tprivate Collection<AdditionalPathsMapper> additionalPathsMappers;\n\n\tDiscoveredWebEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id, String rootPath,\n\t\t\tAccess defaultAccess, Collection<WebOperation> operations,\n\t\t\tCollection<AdditionalPathsMapper> additionalPathsMappers) {\n\t\tsuper(discoverer, endpointBean, id, defaultAccess, operations);\n\t\tthis.rootPath = rootPath;\n\t\tthis.additionalPathsMappers = additionalPathsMappers;\n\t}\n\n\t@Override\n\tpublic String getRootPath() {\n\t\treturn this.rootPath;\n\t}\n\n\t@Override\n\tpublic List<String> getAdditionalPaths(WebServerNamespace webServerNamespace) {\n\t\treturn this.additionalPathsMappers.stream()\n\t\t\t.flatMap((mapper) -> getAdditionalPaths(webServerNamespace, mapper))\n\t\t\t.toList();\n\t}\n\n\tprivate Stream<String> getAdditionalPaths(WebServerNamespace webServerNamespace, AdditionalPathsMapper mapper) {\n\t\tList<String> additionalPaths = mapper.getAdditionalPaths(getEndpointId(), webServerNamespace);\n\t\treturn (additionalPaths != null) ? additionalPaths.stream() : Stream.empty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/DiscoveredWebOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.stream.Collectors;\n\nimport org.reactivestreams.Publisher;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.ClassUtils;\n\n/**\n * A discovered {@link WebOperation web operation}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass DiscoveredWebOperation extends AbstractDiscoveredOperation implements WebOperation {\n\n\tprivate static final boolean REACTIVE_STREAMS_PRESENT = ClassUtils.isPresent(\"org.reactivestreams.Publisher\",\n\t\t\tDiscoveredWebOperation.class.getClassLoader());\n\n\tprivate final String id;\n\n\tprivate final boolean blocking;\n\n\tprivate final WebOperationRequestPredicate requestPredicate;\n\n\tDiscoveredWebOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker,\n\t\t\tWebOperationRequestPredicate requestPredicate) {\n\t\tsuper(operationMethod, invoker);\n\t\tthis.id = getId(endpointId, operationMethod);\n\t\tthis.blocking = getBlocking(operationMethod);\n\t\tthis.requestPredicate = requestPredicate;\n\t}\n\n\tprivate String getId(EndpointId endpointId, OperationMethod method) {\n\t\treturn endpointId + method.getParameters()\n\t\t\t.stream()\n\t\t\t.filter(this::hasSelector)\n\t\t\t.map(this::dashName)\n\t\t\t.collect(Collectors.joining());\n\t}\n\n\tprivate boolean hasSelector(OperationParameter parameter) {\n\t\treturn parameter.getAnnotation(Selector.class) != null;\n\t}\n\n\tprivate String dashName(OperationParameter parameter) {\n\t\treturn \"-\" + parameter.getName();\n\t}\n\n\tprivate boolean getBlocking(OperationMethod method) {\n\t\treturn !REACTIVE_STREAMS_PRESENT || !Publisher.class.isAssignableFrom(method.getMethod().getReturnType());\n\t}\n\n\t@Override\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\t@Override\n\tpublic boolean isBlocking() {\n\t\treturn this.blocking;\n\t}\n\n\t@Override\n\tpublic WebOperationRequestPredicate getRequestPredicate() {\n\t\treturn this.requestPredicate;\n\t}\n\n\t@Override\n\tprotected void appendFields(ToStringCreator creator) {\n\t\tcreator.append(\"id\", this.id)\n\t\t\t.append(\"blocking\", this.blocking)\n\t\t\t.append(\"requestPredicate\", this.requestPredicate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/EndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Identifies a type as being a Web-specific extension of an {@link Endpoint @Endpoint}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 2.0.0\n * @see Endpoint\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@EndpointExtension(filter = WebEndpointFilter.class)\npublic @interface EndpointWebExtension {\n\n\t/**\n\t * The {@link Endpoint endpoint} class to which this Web extension relates.\n\t * @return the endpoint class\n\t */\n\t@AliasFor(annotation = EndpointExtension.class)\n\tClass<?> endpoint();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ExposableControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n/**\n * Information describing an endpoint that can be exposed over Spring MVC or Spring\n * WebFlux. Mappings should be discovered directly from {@link #getController()} and\n * {@link #getOperations()} should always return an empty collection.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.3 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.3\", forRemoval = true)\npublic interface ExposableControllerEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {\n\n\t/**\n\t * Return the source controller that contains {@link RequestMapping @RequestMapping}\n\t * methods.\n\t * @return the source controller\n\t */\n\tObject getController();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/RequestPredicateFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * Factory to create a {@link WebOperationRequestPredicate}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass RequestPredicateFactory {\n\n\tprivate final EndpointMediaTypes endpointMediaTypes;\n\n\tRequestPredicateFactory(EndpointMediaTypes endpointMediaTypes) {\n\t\tAssert.notNull(endpointMediaTypes, \"'endpointMediaTypes' must not be null\");\n\t\tthis.endpointMediaTypes = endpointMediaTypes;\n\t}\n\n\tWebOperationRequestPredicate getRequestPredicate(String rootPath, DiscoveredOperationMethod operationMethod) {\n\t\tMethod method = operationMethod.getMethod();\n\t\tOperationParameter[] selectorParameters = operationMethod.getParameters()\n\t\t\t.stream()\n\t\t\t.filter(this::hasSelector)\n\t\t\t.toArray(OperationParameter[]::new);\n\t\tOperationParameter allRemainingPathSegmentsParameter = getAllRemainingPathSegmentsParameter(selectorParameters);\n\t\tString path = getPath(rootPath, selectorParameters, allRemainingPathSegmentsParameter != null);\n\t\tWebEndpointHttpMethod httpMethod = determineHttpMethod(operationMethod.getOperationType());\n\t\tCollection<String> consumes = getConsumes(httpMethod, method);\n\t\tCollection<String> produces = getProduces(operationMethod, method);\n\t\treturn new WebOperationRequestPredicate(path, httpMethod, consumes, produces);\n\t}\n\n\tprivate @Nullable OperationParameter getAllRemainingPathSegmentsParameter(OperationParameter[] selectorParameters) {\n\t\tOperationParameter trailingPathsParameter = null;\n\t\tfor (OperationParameter selectorParameter : selectorParameters) {\n\t\t\tSelector selector = selectorParameter.getAnnotation(Selector.class);\n\t\t\tAssert.state(selector != null, \"'selector' must not be null\");\n\t\t\tif (selector.match() == Match.ALL_REMAINING) {\n\t\t\t\tAssert.state(trailingPathsParameter == null,\n\t\t\t\t\t\t\"@Selector annotation with Match.ALL_REMAINING must be unique\");\n\t\t\t\ttrailingPathsParameter = selectorParameter;\n\t\t\t}\n\t\t}\n\t\tif (trailingPathsParameter != null) {\n\t\t\tAssert.state(trailingPathsParameter == selectorParameters[selectorParameters.length - 1],\n\t\t\t\t\t\"@Selector annotation with Match.ALL_REMAINING must be the last parameter\");\n\t\t}\n\t\treturn trailingPathsParameter;\n\t}\n\n\tprivate String getPath(String rootPath, OperationParameter[] selectorParameters,\n\t\t\tboolean matchRemainingPathSegments) {\n\t\tStringBuilder path = new StringBuilder(rootPath);\n\t\tfor (int i = 0; i < selectorParameters.length; i++) {\n\t\t\tpath.append((i != 0 || !rootPath.endsWith(\"/\")) ? \"/{\" : \"{\");\n\t\t\tif (i == selectorParameters.length - 1 && matchRemainingPathSegments) {\n\t\t\t\tpath.append(\"*\");\n\t\t\t}\n\t\t\tpath.append(selectorParameters[i].getName());\n\t\t\tpath.append(\"}\");\n\t\t}\n\t\treturn path.toString();\n\t}\n\n\tprivate boolean hasSelector(OperationParameter parameter) {\n\t\treturn parameter.getAnnotation(Selector.class) != null;\n\t}\n\n\tprivate Collection<String> getConsumes(WebEndpointHttpMethod httpMethod, Method method) {\n\t\tif (WebEndpointHttpMethod.POST == httpMethod && consumesRequestBody(method)) {\n\t\t\treturn this.endpointMediaTypes.getConsumed();\n\t\t}\n\t\treturn Collections.emptyList();\n\t}\n\n\tprivate Collection<String> getProduces(DiscoveredOperationMethod operationMethod, Method method) {\n\t\tif (!operationMethod.getProducesMediaTypes().isEmpty()) {\n\t\t\treturn operationMethod.getProducesMediaTypes();\n\t\t}\n\t\tif (Void.class.equals(method.getReturnType()) || void.class.equals(method.getReturnType())) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tif (producesResource(method)) {\n\t\t\treturn Collections.singletonList(\"application/octet-stream\");\n\t\t}\n\t\treturn this.endpointMediaTypes.getProduced();\n\t}\n\n\tprivate boolean producesResource(Method method) {\n\t\tif (Resource.class.equals(method.getReturnType())) {\n\t\t\treturn true;\n\t\t}\n\t\tif (WebEndpointResponse.class.isAssignableFrom(method.getReturnType())) {\n\t\t\tResolvableType returnType = ResolvableType.forMethodReturnType(method);\n\t\t\treturn ResolvableType.forClass(Resource.class).isAssignableFrom(returnType.getGeneric(0));\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean consumesRequestBody(Method method) {\n\t\treturn Stream.of(method.getParameters())\n\t\t\t.anyMatch((parameter) -> parameter.getAnnotation(Selector.class) == null);\n\t}\n\n\tprivate WebEndpointHttpMethod determineHttpMethod(OperationType operationType) {\n\t\tif (operationType == OperationType.WRITE) {\n\t\t\treturn WebEndpointHttpMethod.POST;\n\t\t}\n\t\tif (operationType == OperationType.DELETE) {\n\t\t\treturn WebEndpointHttpMethod.DELETE;\n\t\t}\n\t\treturn WebEndpointHttpMethod.GET;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/RestControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.web.bind.annotation.DeleteMapping;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Identifies a type as being a REST endpoint that is only exposed over Spring MVC or\n * Spring WebFlux. Mapped methods must be annotated with {@link GetMapping @GetMapping},\n * {@link PostMapping @PostMapping}, {@link DeleteMapping @DeleteMapping}, etc.\n * annotations rather than {@link ReadOperation @ReadOperation},\n * {@link WriteOperation @WriteOperation}, {@link DeleteOperation @DeleteOperation}.\n * <p>\n * This annotation can be used when deeper Spring integration is required, but at the\n * expense of portability. Most users should prefer the {@link Endpoint @Endpoint} or\n * {@link WebEndpoint @WebEndpoint} annotations whenever possible.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see WebEndpoint\n * @see ControllerEndpoint\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Endpoint\n@FilteredEndpoint(ControllerEndpointFilter.class)\n@ResponseBody\n@Deprecated(since = \"3.3.0\", forRemoval = true)\npublic @interface RestControllerEndpoint {\n\n\t/**\n\t * The id of the endpoint.\n\t * @return the id\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tString id();\n\n\t/**\n\t * Level of access to the endpoint that is permitted by default.\n\t * @return the default level of access\n\t * @since 3.4.0\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tAccess defaultAccess() default Access.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.function.Supplier;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.EndpointServlet;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Identifies a type as being an endpoint that supplies a servlet to expose.\n * Implementations must also implement {@link Supplier Supplier&lt;EndpointServlet&gt;}\n * and return a valid {@link EndpointServlet}.\n * <p>\n * This annotation can be used when existing servlets need to be exposed as actuator\n * endpoints, but it is at the expense of portability. Most users should prefer the\n * {@link Endpoint @Endpoint} or {@link WebEndpoint @WebEndpoint} annotations whenever\n * possible.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Endpoint\n@FilteredEndpoint(ServletEndpointFilter.class)\n@Deprecated(since = \"3.3.0\", forRemoval = true)\npublic @interface ServletEndpoint {\n\n\t/**\n\t * The id of the endpoint.\n\t * @return the id\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tString id();\n\n\t/**\n\t * Level of access to the endpoint that is permitted by default.\n\t * @return the default level of access\n\t * @since 3.4.0\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tAccess defaultAccess() default Access.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscoverer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\n\n/**\n * {@link EndpointDiscoverer} for {@link ExposableServletEndpoint servlet endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@ImportRuntimeHints(ServletEndpointDiscoverer.ServletEndpointDiscovererRuntimeHints.class)\n@Deprecated(since = \"3.3.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ServletEndpointDiscoverer extends EndpointDiscoverer<ExposableServletEndpoint, Operation>\n\t\timplements ServletEndpointsSupplier {\n\n\tprivate final @Nullable List<PathMapper> endpointPathMappers;\n\n\t/**\n\t * Create a new {@link ServletEndpointDiscoverer} instance.\n\t * @param applicationContext the source application context\n\t * @param endpointPathMappers the endpoint path mappers\n\t * @param filters filters to apply\n\t */\n\tpublic ServletEndpointDiscoverer(ApplicationContext applicationContext,\n\t\t\t@Nullable List<PathMapper> endpointPathMappers,\n\t\t\tCollection<EndpointFilter<ExposableServletEndpoint>> filters) {\n\t\tsuper(applicationContext, ParameterValueMapper.NONE, Collections.emptyList(), filters, Collections.emptyList());\n\t\tthis.endpointPathMappers = endpointPathMappers;\n\t}\n\n\t@Override\n\tprotected boolean isEndpointTypeExposed(Class<?> beanType) {\n\t\treturn MergedAnnotations.from(beanType, SearchStrategy.SUPERCLASS).isPresent(ServletEndpoint.class);\n\t}\n\n\t@Override\n\tprotected ExposableServletEndpoint createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\tCollection<Operation> operations) {\n\t\tString rootPath = PathMapper.getRootPath(this.endpointPathMappers, id);\n\t\treturn new DiscoveredServletEndpoint(this, endpointBean, id, rootPath, defaultAccess);\n\t}\n\n\t@Override\n\tprotected Operation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\tOperationInvoker invoker) {\n\t\tthrow new IllegalStateException(\"ServletEndpoints must not declare operations\");\n\t}\n\n\t@Override\n\tprotected OperationKey createOperationKey(Operation operation) {\n\t\tthrow new IllegalStateException(\"ServletEndpoints must not declare operations\");\n\t}\n\n\t@Override\n\tprotected boolean isInvocable(ExposableServletEndpoint endpoint) {\n\t\treturn true;\n\t}\n\n\tstatic class ServletEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(ServletEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;\n\n/**\n * {@link EndpointFilter} for endpoints discovered by {@link ServletEndpointDiscoverer}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass ServletEndpointFilter extends DiscovererEndpointFilter {\n\n\tServletEndpointFilter() {\n\t\tsuper(ServletEndpointDiscoverer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointsSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;\n\n/**\n * {@link EndpointsSupplier} for {@link ExposableServletEndpoint servlet endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @deprecated since 3.3.0 in favor of {@code @Endpoint} and {@code @WebEndpoint}\n */\n@FunctionalInterface\n@Deprecated(since = \"3.3.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic interface ServletEndpointsSupplier extends EndpointsSupplier<ExposableServletEndpoint> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.FilteredEndpoint;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Identifies a type as being an endpoint that is only exposed over HTTP.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Endpoint\n@FilteredEndpoint(WebEndpointFilter.class)\npublic @interface WebEndpoint {\n\n\t/**\n\t * The id of the endpoint.\n\t * @return the id\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tString id();\n\n\t/**\n\t * Level of access to the endpoint that is permitted by default.\n\t * @return the default level of access\n\t * @since 3.4.0\n\t */\n\t@AliasFor(annotation = Endpoint.class)\n\tAccess defaultAccess() default Access.UNRESTRICTED;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscoverer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointDiscoverer;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer.WebEndpointDiscovererRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * {@link EndpointDiscoverer} for {@link ExposableWebEndpoint web endpoints}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@ImportRuntimeHints(WebEndpointDiscovererRuntimeHints.class)\npublic class WebEndpointDiscoverer extends EndpointDiscoverer<ExposableWebEndpoint, WebOperation>\n\t\timplements WebEndpointsSupplier {\n\n\tprivate final List<PathMapper> endpointPathMappers;\n\n\tprivate final List<AdditionalPathsMapper> additionalPathsMappers;\n\n\tprivate final RequestPredicateFactory requestPredicateFactory;\n\n\t/**\n\t * Create a new {@link WebEndpointDiscoverer} instance.\n\t * @param applicationContext the source application context\n\t * @param parameterValueMapper the parameter value mapper\n\t * @param endpointMediaTypes the endpoint media types\n\t * @param endpointPathMappers the endpoint path mappers\n\t * @param additionalPathsMappers the\n\t * @param invokerAdvisors invoker advisors to apply\n\t * @param endpointFilters endpoint filters to apply\n\t * @param operationFilters operation filters to apply\n\t * @since 3.4.0\n\t */\n\tpublic WebEndpointDiscoverer(ApplicationContext applicationContext, ParameterValueMapper parameterValueMapper,\n\t\t\tEndpointMediaTypes endpointMediaTypes, @Nullable List<PathMapper> endpointPathMappers,\n\t\t\t@Nullable List<AdditionalPathsMapper> additionalPathsMappers,\n\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\tCollection<EndpointFilter<ExposableWebEndpoint>> endpointFilters,\n\t\t\tCollection<OperationFilter<WebOperation>> operationFilters) {\n\t\tsuper(applicationContext, parameterValueMapper, invokerAdvisors, endpointFilters, operationFilters);\n\t\tthis.endpointPathMappers = (endpointPathMappers != null) ? endpointPathMappers : Collections.emptyList();\n\t\tthis.additionalPathsMappers = (additionalPathsMappers != null) ? additionalPathsMappers\n\t\t\t\t: Collections.emptyList();\n\t\tthis.requestPredicateFactory = new RequestPredicateFactory(endpointMediaTypes);\n\t}\n\n\t@Override\n\tprotected ExposableWebEndpoint createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\tCollection<WebOperation> operations) {\n\t\tString rootPath = PathMapper.getRootPath(this.endpointPathMappers, id);\n\t\treturn new DiscoveredWebEndpoint(this, endpointBean, id, rootPath, defaultAccess, operations,\n\t\t\t\tthis.additionalPathsMappers);\n\t}\n\n\t@Override\n\tprotected WebOperation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\tOperationInvoker invoker) {\n\t\tString rootPath = PathMapper.getRootPath(this.endpointPathMappers, endpointId);\n\t\tWebOperationRequestPredicate requestPredicate = this.requestPredicateFactory.getRequestPredicate(rootPath,\n\t\t\t\toperationMethod);\n\t\treturn new DiscoveredWebOperation(endpointId, operationMethod, invoker, requestPredicate);\n\t}\n\n\t@Override\n\tprotected OperationKey createOperationKey(WebOperation operation) {\n\t\treturn new OperationKey(operation.getRequestPredicate(),\n\t\t\t\t() -> \"web request predicate \" + operation.getRequestPredicate());\n\t}\n\n\tstatic class WebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(WebEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;\n\n/**\n * {@link EndpointFilter} for endpoints discovered by {@link WebEndpointDiscoverer}.\n *\n * @author Phillip Webb\n */\nclass WebEndpointFilter extends DiscovererEndpointFilter {\n\n\tWebEndpointFilter() {\n\t\tsuper(WebEndpointDiscoverer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/annotation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Annotation support for actuator web endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Web support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.env;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Predicate;\nimport java.util.regex.Pattern;\nimport java.util.stream.Stream;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.SanitizableData;\nimport org.springframework.boot.actuate.endpoint.Sanitizer;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.context.properties.bind.PlaceholdersResolver;\nimport org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Endpoint @Endpoint} to expose {@link ConfigurableEnvironment environment}\n * information.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Christian Dupuis\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 2.0.0\n */\n@Endpoint(id = \"env\")\npublic class EnvironmentEndpoint {\n\n\tprivate final Sanitizer sanitizer;\n\n\tprivate final Environment environment;\n\n\tprivate final Show showValues;\n\n\tpublic EnvironmentEndpoint(Environment environment, Iterable<SanitizingFunction> sanitizingFunctions,\n\t\t\tShow showValues) {\n\t\tthis.environment = environment;\n\t\tthis.sanitizer = new Sanitizer(sanitizingFunctions);\n\t\tthis.showValues = showValues;\n\t}\n\n\t@ReadOperation\n\tpublic EnvironmentDescriptor environment(@Nullable String pattern) {\n\t\tboolean showUnsanitized = this.showValues.isShown(true);\n\t\treturn getEnvironmentDescriptor(pattern, showUnsanitized);\n\t}\n\n\tEnvironmentDescriptor getEnvironmentDescriptor(@Nullable String pattern, boolean showUnsanitized) {\n\t\tif (StringUtils.hasText(pattern)) {\n\t\t\treturn getEnvironmentDescriptor(Pattern.compile(pattern).asPredicate(), showUnsanitized);\n\t\t}\n\t\treturn getEnvironmentDescriptor((name) -> true, showUnsanitized);\n\t}\n\n\tprivate EnvironmentDescriptor getEnvironmentDescriptor(Predicate<String> propertyNamePredicate,\n\t\t\tboolean showUnsanitized) {\n\t\tList<PropertySourceDescriptor> propertySources = new ArrayList<>();\n\t\tgetPropertySourcesAsMap().forEach((sourceName, source) -> {\n\t\t\tif (source instanceof EnumerablePropertySource) {\n\t\t\t\tpropertySources.add(describeSource(sourceName, (EnumerablePropertySource<?>) source,\n\t\t\t\t\t\tpropertyNamePredicate, showUnsanitized));\n\t\t\t}\n\t\t});\n\t\treturn new EnvironmentDescriptor(Arrays.asList(this.environment.getActiveProfiles()),\n\t\t\t\tArrays.asList(this.environment.getDefaultProfiles()), propertySources);\n\t}\n\n\t@ReadOperation\n\tpublic EnvironmentEntryDescriptor environmentEntry(@Selector String toMatch) {\n\t\tboolean showUnsanitized = this.showValues.isShown(true);\n\t\treturn getEnvironmentEntryDescriptor(toMatch, showUnsanitized);\n\t}\n\n\tEnvironmentEntryDescriptor getEnvironmentEntryDescriptor(String propertyName, boolean showUnsanitized) {\n\t\tMap<String, @Nullable PropertyValueDescriptor> descriptors = getPropertySourceDescriptors(propertyName,\n\t\t\t\tshowUnsanitized);\n\t\tPropertySummaryDescriptor summary = getPropertySummaryDescriptor(descriptors);\n\t\treturn new EnvironmentEntryDescriptor(summary, Arrays.asList(this.environment.getActiveProfiles()),\n\t\t\t\tArrays.asList(this.environment.getDefaultProfiles()), toPropertySourceDescriptors(descriptors));\n\t}\n\n\tprivate List<PropertySourceEntryDescriptor> toPropertySourceDescriptors(\n\t\t\tMap<String, @Nullable PropertyValueDescriptor> descriptors) {\n\t\tList<PropertySourceEntryDescriptor> result = new ArrayList<>();\n\t\tdescriptors.forEach((name, property) -> result.add(new PropertySourceEntryDescriptor(name, property)));\n\t\treturn result;\n\t}\n\n\tprivate @Nullable PropertySummaryDescriptor getPropertySummaryDescriptor(\n\t\t\tMap<String, @Nullable PropertyValueDescriptor> descriptors) {\n\t\tfor (Map.Entry<String, @Nullable PropertyValueDescriptor> entry : descriptors.entrySet()) {\n\t\t\tif (entry.getValue() != null) {\n\t\t\t\treturn new PropertySummaryDescriptor(entry.getKey(), entry.getValue().getValue());\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Map<String, @Nullable PropertyValueDescriptor> getPropertySourceDescriptors(String propertyName,\n\t\t\tboolean showUnsanitized) {\n\t\tMap<String, @Nullable PropertyValueDescriptor> propertySources = new LinkedHashMap<>();\n\t\tgetPropertySourcesAsMap().forEach((sourceName, source) -> propertySources.put(sourceName,\n\t\t\t\tsource.containsProperty(propertyName) ? describeValueOf(propertyName, source, showUnsanitized) : null));\n\t\treturn propertySources;\n\t}\n\n\tprivate PropertySourceDescriptor describeSource(String sourceName, EnumerablePropertySource<?> source,\n\t\t\tPredicate<String> namePredicate, boolean showUnsanitized) {\n\t\tMap<String, PropertyValueDescriptor> properties = new LinkedHashMap<>();\n\t\tStream.of(source.getPropertyNames())\n\t\t\t.filter(namePredicate)\n\t\t\t.forEach((name) -> properties.put(name, describeValueOf(name, source, showUnsanitized)));\n\t\treturn new PropertySourceDescriptor(sourceName, properties);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate PropertyValueDescriptor describeValueOf(String name, PropertySource<?> source, boolean showUnsanitized) {\n\t\tPlaceholdersResolver resolver = new PropertySourcesPlaceholdersResolver(getPropertySources());\n\t\tObject resolved = resolver.resolvePlaceholders(source.getProperty(name));\n\t\tOrigin origin = ((source instanceof OriginLookup) ? ((OriginLookup<Object>) source).getOrigin(name) : null);\n\t\tObject sanitizedValue = sanitize(source, name, resolved, showUnsanitized);\n\t\treturn new PropertyValueDescriptor(stringifyIfNecessary(sanitizedValue), origin);\n\t}\n\n\tprivate Map<String, PropertySource<?>> getPropertySourcesAsMap() {\n\t\tMap<String, PropertySource<?>> map = new LinkedHashMap<>();\n\t\tfor (PropertySource<?> source : getPropertySources()) {\n\t\t\tif (!ConfigurationPropertySources.isAttachedConfigurationPropertySource(source)) {\n\t\t\t\textract(\"\", map, source);\n\t\t\t}\n\t\t}\n\t\treturn map;\n\t}\n\n\tprivate MutablePropertySources getPropertySources() {\n\t\tif (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\treturn configurableEnvironment.getPropertySources();\n\t\t}\n\t\treturn new StandardEnvironment().getPropertySources();\n\t}\n\n\tprivate void extract(String root, Map<String, PropertySource<?>> map, PropertySource<?> source) {\n\t\tif (source instanceof CompositePropertySource compositePropertySource) {\n\t\t\tfor (PropertySource<?> nest : compositePropertySource.getPropertySources()) {\n\t\t\t\textract(source.getName() + \":\", map, nest);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tmap.put(root + source.getName(), source);\n\t\t}\n\t}\n\n\tprivate @Nullable Object sanitize(PropertySource<?> source, String name, @Nullable Object value,\n\t\t\tboolean showUnsanitized) {\n\t\treturn this.sanitizer.sanitize(new SanitizableData(source, name, value), showUnsanitized);\n\t}\n\n\tprotected @Nullable Object stringifyIfNecessary(@Nullable Object value) {\n\t\tif (value == null || ClassUtils.isPrimitiveOrWrapper(value.getClass())\n\t\t\t\t|| Number.class.isAssignableFrom(value.getClass())) {\n\t\t\treturn value;\n\t\t}\n\t\tif (CharSequence.class.isAssignableFrom(value.getClass())) {\n\t\t\treturn value.toString();\n\t\t}\n\t\treturn \"Complex property type \" + value.getClass().getName();\n\t}\n\n\t/**\n\t * Description of an {@link Environment}.\n\t */\n\tpublic static final class EnvironmentDescriptor implements OperationResponseBody {\n\n\t\tprivate final List<String> activeProfiles;\n\n\t\tprivate final List<String> defaultProfiles;\n\n\t\tprivate final List<PropertySourceDescriptor> propertySources;\n\n\t\tprivate EnvironmentDescriptor(List<String> activeProfiles, List<String> defaultProfiles,\n\t\t\t\tList<PropertySourceDescriptor> propertySources) {\n\t\t\tthis.activeProfiles = activeProfiles;\n\t\t\tthis.defaultProfiles = defaultProfiles;\n\t\t\tthis.propertySources = propertySources;\n\t\t}\n\n\t\tpublic List<String> getActiveProfiles() {\n\t\t\treturn this.activeProfiles;\n\t\t}\n\n\t\tpublic List<String> getDefaultProfiles() {\n\t\t\treturn this.defaultProfiles;\n\t\t}\n\n\t\tpublic List<PropertySourceDescriptor> getPropertySources() {\n\t\t\treturn this.propertySources;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an entry of the {@link Environment}.\n\t */\n\t@JsonInclude(JsonInclude.Include.NON_NULL)\n\tpublic static final class EnvironmentEntryDescriptor {\n\n\t\tprivate final @Nullable PropertySummaryDescriptor property;\n\n\t\tprivate final List<String> activeProfiles;\n\n\t\tprivate final List<String> defaultProfiles;\n\n\t\tprivate final List<PropertySourceEntryDescriptor> propertySources;\n\n\t\tEnvironmentEntryDescriptor(@Nullable PropertySummaryDescriptor property, List<String> activeProfiles,\n\t\t\t\tList<String> defaultProfiles, List<PropertySourceEntryDescriptor> propertySources) {\n\t\t\tthis.property = property;\n\t\t\tthis.activeProfiles = activeProfiles;\n\t\t\tthis.defaultProfiles = defaultProfiles;\n\t\t\tthis.propertySources = propertySources;\n\t\t}\n\n\t\tpublic @Nullable PropertySummaryDescriptor getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t\tpublic List<String> getActiveProfiles() {\n\t\t\treturn this.activeProfiles;\n\t\t}\n\n\t\tpublic List<String> getDefaultProfiles() {\n\t\t\treturn this.defaultProfiles;\n\t\t}\n\n\t\tpublic List<PropertySourceEntryDescriptor> getPropertySources() {\n\t\t\treturn this.propertySources;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a particular entry of the {@link Environment}.\n\t */\n\t@JsonInclude(JsonInclude.Include.NON_NULL)\n\tpublic static final class PropertySummaryDescriptor {\n\n\t\tprivate final String source;\n\n\t\tprivate final @Nullable Object value;\n\n\t\tpublic PropertySummaryDescriptor(String source, @Nullable Object value) {\n\t\t\tthis.source = source;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String getSource() {\n\t\t\treturn this.source;\n\t\t}\n\n\t\tpublic @Nullable Object getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link PropertySource}.\n\t */\n\tpublic static final class PropertySourceDescriptor {\n\n\t\tprivate final String name;\n\n\t\tprivate final Map<String, PropertyValueDescriptor> properties;\n\n\t\tprivate PropertySourceDescriptor(String name, Map<String, PropertyValueDescriptor> properties) {\n\t\t\tthis.name = name;\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic Map<String, PropertyValueDescriptor> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a particular entry of {@link PropertySource}.\n\t */\n\t@JsonInclude(JsonInclude.Include.NON_NULL)\n\tpublic static final class PropertySourceEntryDescriptor {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable PropertyValueDescriptor property;\n\n\t\tprivate PropertySourceEntryDescriptor(String name, @Nullable PropertyValueDescriptor property) {\n\t\t\tthis.name = name;\n\t\t\tthis.property = property;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic @Nullable PropertyValueDescriptor getProperty() {\n\t\t\treturn this.property;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a property's value, including its origin if available.\n\t */\n\t@JsonInclude(JsonInclude.Include.NON_NULL)\n\tpublic static final class PropertyValueDescriptor {\n\n\t\tprivate final @Nullable Object value;\n\n\t\tprivate final @Nullable String origin;\n\n\t\tprivate final String @Nullable [] originParents;\n\n\t\tprivate PropertyValueDescriptor(@Nullable Object value, @Nullable Origin origin) {\n\t\t\tthis.value = value;\n\t\t\tthis.origin = (origin != null) ? origin.toString() : null;\n\t\t\tList<Origin> originParents = Origin.parentsFrom(origin);\n\t\t\tthis.originParents = originParents.isEmpty() ? null\n\t\t\t\t\t: originParents.stream().map(Object::toString).toArray(String[]::new);\n\t\t}\n\n\t\tpublic @Nullable Object getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tpublic @Nullable String getOrigin() {\n\t\t\treturn this.origin;\n\t\t}\n\n\t\tpublic String @Nullable [] getOriginParents() {\n\t\t\treturn this.originParents;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/EnvironmentEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.env;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentEntryDescriptor;\n\n/**\n * {@link EndpointWebExtension @EndpointWebExtension} for the {@link EnvironmentEndpoint}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 2.0.0\n */\n@EndpointWebExtension(endpoint = EnvironmentEndpoint.class)\npublic class EnvironmentEndpointWebExtension {\n\n\tprivate final EnvironmentEndpoint delegate;\n\n\tprivate final Show showValues;\n\n\tprivate final Set<String> roles;\n\n\tpublic EnvironmentEndpointWebExtension(EnvironmentEndpoint delegate, Show showValues, Set<String> roles) {\n\t\tthis.delegate = delegate;\n\t\tthis.showValues = showValues;\n\t\tthis.roles = roles;\n\t}\n\n\t@ReadOperation\n\tpublic EnvironmentDescriptor environment(SecurityContext securityContext, @Nullable String pattern) {\n\t\tboolean showUnsanitized = this.showValues.isShown(securityContext, this.roles);\n\t\treturn this.delegate.getEnvironmentDescriptor(pattern, showUnsanitized);\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<EnvironmentEntryDescriptor> environmentEntry(SecurityContext securityContext,\n\t\t\t@Selector String toMatch) {\n\t\tboolean showUnsanitized = this.showValues.isShown(securityContext, this.roles);\n\t\tEnvironmentEntryDescriptor descriptor = this.delegate.getEnvironmentEntryDescriptor(toMatch, showUnsanitized);\n\t\treturn (descriptor.getProperty() != null) ? new WebEndpointResponse<>(descriptor, WebEndpointResponse.STATUS_OK)\n\t\t\t\t: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/env/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for Spring Framework's\n * {@link org.springframework.core.env.Environment}.\n */\n@NullMarked\npackage org.springframework.boot.actuate.env;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/BuildInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.info.BuildInfoContributor.BuildInfoContributorRuntimeHints;\nimport org.springframework.boot.info.BuildProperties;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.env.PropertiesPropertySource;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * An {@link InfoContributor} that exposes {@link BuildProperties}.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@ImportRuntimeHints(BuildInfoContributorRuntimeHints.class)\npublic class BuildInfoContributor extends InfoPropertiesInfoContributor<BuildProperties> {\n\n\tpublic BuildInfoContributor(BuildProperties properties) {\n\t\tsuper(properties, Mode.FULL);\n\t}\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tbuilder.withDetail(\"build\", generateContent());\n\t}\n\n\t@Override\n\tprotected PropertySource<?> toSimplePropertySource() {\n\t\tProperties props = new Properties();\n\t\tcopyIfSet(props, \"group\");\n\t\tcopyIfSet(props, \"artifact\");\n\t\tcopyIfSet(props, \"name\");\n\t\tcopyIfSet(props, \"version\");\n\t\tcopyIfSet(props, \"time\");\n\t\treturn new PropertiesPropertySource(\"build\", props);\n\t}\n\n\t@Override\n\tprotected void postProcessContent(Map<String, Object> content) {\n\t\treplaceValue(content, \"time\", getProperties().getTime());\n\t}\n\n\tstatic class BuildInfoContributorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), BuildProperties.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * An {@link InfoContributor} that provides all environment entries prefixed with info.\n *\n * @author Meang Akira Tanaka\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 1.4.0\n */\npublic class EnvironmentInfoContributor implements InfoContributor {\n\n\tprivate static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable.mapOf(String.class, Object.class);\n\n\tprivate final ConfigurableEnvironment environment;\n\n\tpublic EnvironmentInfoContributor(ConfigurableEnvironment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tBinder binder = Binder.get(this.environment);\n\t\tbinder.bind(\"info\", STRING_OBJECT_MAP).ifBound(builder::withDetails);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/GitInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.time.Instant;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.info.GitInfoContributor.GitInfoContributorRuntimeHints;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.env.PropertiesPropertySource;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * An {@link InfoContributor} that exposes {@link GitProperties}.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@ImportRuntimeHints(GitInfoContributorRuntimeHints.class)\npublic class GitInfoContributor extends InfoPropertiesInfoContributor<GitProperties> {\n\n\tpublic GitInfoContributor(GitProperties properties) {\n\t\tthis(properties, Mode.SIMPLE);\n\t}\n\n\tpublic GitInfoContributor(GitProperties properties, Mode mode) {\n\t\tsuper(properties, mode);\n\t}\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tbuilder.withDetail(\"git\", generateContent());\n\t}\n\n\t@Override\n\tprotected PropertySource<?> toSimplePropertySource() {\n\t\tProperties props = new Properties();\n\t\tcopyIfSet(props, \"branch\");\n\t\tString commitId = getProperties().getShortCommitId();\n\t\tif (commitId != null) {\n\t\t\tprops.put(\"commit.id\", commitId);\n\t\t}\n\t\tcopyIfSet(props, \"commit.time\");\n\t\treturn new PropertiesPropertySource(\"git\", props);\n\t}\n\n\t/**\n\t * Post-process the content to expose. By default, well known keys representing dates\n\t * are converted to {@link Instant} instances.\n\t * @param content the content to expose\n\t */\n\t@Override\n\tprotected void postProcessContent(Map<String, Object> content) {\n\t\treplaceValue(getNestedMap(content, \"commit\"), \"time\", getProperties().getCommitTime());\n\t\treplaceValue(getNestedMap(content, \"build\"), \"time\", getProperties().getInstant(\"build.time\"));\n\t}\n\n\tstatic class GitInfoContributorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), GitProperties.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/Info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Carries information of the application.\n * <p>\n * Each detail element can be singular or a hierarchical object such as a POJO or a nested\n * Map.\n *\n * @author Meang Akira Tanaka\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@JsonInclude(Include.NON_EMPTY)\npublic final class Info {\n\n\tprivate final Map<String, Object> details;\n\n\tprivate Info(Builder builder) {\n\t\tMap<String, Object> content = new LinkedHashMap<>(builder.content);\n\t\tthis.details = Collections.unmodifiableMap(content);\n\t}\n\n\t/**\n\t * Return the content.\n\t * @return the details of the info or an empty map.\n\t */\n\t@JsonAnyGetter\n\tpublic Map<String, Object> getDetails() {\n\t\treturn this.details;\n\t}\n\n\tpublic @Nullable Object get(String id) {\n\t\treturn this.details.get(id);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> @Nullable T get(String id, @Nullable Class<T> type) {\n\t\tObject value = get(id);\n\t\tif (value != null && type != null && !type.isInstance(value)) {\n\t\t\tthrow new IllegalStateException(\"Info entry is not of required type [\" + type.getName() + \"]: \" + value);\n\t\t}\n\t\treturn (T) value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof Info other) {\n\t\t\treturn this.details.equals(other.details);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.details.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getDetails().toString();\n\t}\n\n\t/**\n\t * Builder for creating immutable {@link Info} instances.\n\t */\n\tpublic static class Builder {\n\n\t\tprivate final Map<String, @Nullable Object> content;\n\n\t\tpublic Builder() {\n\t\t\tthis.content = new LinkedHashMap<>();\n\t\t}\n\n\t\t/**\n\t\t * Record detail using given {@code key} and {@code value}.\n\t\t * @param key the detail key\n\t\t * @param value the detail value\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder withDetail(String key, @Nullable Object value) {\n\t\t\tthis.content.put(key, value);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Record several details.\n\t\t * @param details the details\n\t\t * @return this {@link Builder} instance\n\t\t * @see #withDetail(String, Object)\n\t\t */\n\t\tpublic Builder withDetails(Map<String, @Nullable Object> details) {\n\t\t\tthis.content.putAll(details);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link Info} instance based on the state of this builder.\n\t\t * @return a new {@link Info} instance\n\t\t */\n\t\tpublic Info build() {\n\t\t\treturn new Info(this);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\n/**\n * Contributes additional info details.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\n@FunctionalInterface\npublic interface InfoContributor {\n\n\t/**\n\t * Contributes additional details using the specified {@link Info.Builder Builder}.\n\t * @param builder the builder to use\n\t */\n\tvoid contribute(Info.Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose arbitrary application information.\n *\n * @author Dave Syer\n * @author Meang Akira Tanaka\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@Endpoint(id = \"info\")\npublic class InfoEndpoint {\n\n\tprivate final List<InfoContributor> infoContributors;\n\n\t/**\n\t * Create a new {@link InfoEndpoint} instance.\n\t * @param infoContributors the info contributors to use\n\t */\n\tpublic InfoEndpoint(List<InfoContributor> infoContributors) {\n\t\tAssert.notNull(infoContributors, \"'infoContributors' must not be null\");\n\t\tthis.infoContributors = infoContributors;\n\t}\n\n\t@ReadOperation\n\tpublic Map<String, Object> info() {\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tfor (InfoContributor contributor : this.infoContributors) {\n\t\t\tcontributor.contribute(builder);\n\t\t}\n\t\treturn OperationResponseBody.of(builder.build().getDetails());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoPropertiesInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.info.InfoProperties;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A base {@link InfoContributor} to expose an {@link InfoProperties}.\n *\n * @param <T> the type of the {@link InfoProperties} to expose\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 1.4.0\n */\npublic abstract class InfoPropertiesInfoContributor<T extends InfoProperties> implements InfoContributor {\n\n\tprivate static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable.mapOf(String.class, Object.class);\n\n\tprivate final T properties;\n\n\tprivate final Mode mode;\n\n\tprotected InfoPropertiesInfoContributor(T properties, Mode mode) {\n\t\tthis.properties = properties;\n\t\tthis.mode = mode;\n\t}\n\n\t/**\n\t * Return the properties that this instance manages.\n\t * @return the info properties\n\t */\n\tprotected final T getProperties() {\n\t\treturn this.properties;\n\t}\n\n\t/**\n\t * Return the mode that should be used to expose the content.\n\t * @return the mode\n\t */\n\tprotected final Mode getMode() {\n\t\treturn this.mode;\n\t}\n\n\t/**\n\t * Return a {@link PropertySource} for the {@link Mode#SIMPLE SIMPLE} mode.\n\t * @return the property source for the simple model\n\t * @see #toPropertySource()\n\t */\n\tprotected abstract PropertySource<?> toSimplePropertySource();\n\n\t/**\n\t * Extract the content to contribute to the info endpoint.\n\t * @return the content to expose\n\t * @see #extractContent(PropertySource)\n\t * @see #postProcessContent(Map)\n\t */\n\tprotected Map<String, Object> generateContent() {\n\t\tMap<String, Object> content = extractContent(toPropertySource());\n\t\tpostProcessContent(content);\n\t\treturn content;\n\t}\n\n\t/**\n\t * Extract the raw content based on the specified {@link PropertySource}.\n\t * @param propertySource the property source to use\n\t * @return the raw content\n\t */\n\tprotected Map<String, Object> extractContent(PropertySource<?> propertySource) {\n\t\tIterable<@Nullable ConfigurationPropertySource> adapted = ConfigurationPropertySources.from(propertySource);\n\t\treturn new Binder(ensureNonNullContent(adapted)).bind(\"\", STRING_OBJECT_MAP).orElseGet(LinkedHashMap::new);\n\t}\n\n\tprivate Iterable<ConfigurationPropertySource> ensureNonNullContent(\n\t\t\tIterable<@Nullable ConfigurationPropertySource> sources) {\n\t\tList<ConfigurationPropertySource> nonNullSources = new ArrayList<>(1);\n\t\tfor (ConfigurationPropertySource source : sources) {\n\t\t\tAssert.notNull(source, \"'source' must not be null\");\n\t\t\tnonNullSources.add(source);\n\t\t}\n\t\treturn nonNullSources;\n\t}\n\n\t/**\n\t * Post-process the content to expose. Elements can be added, changed or removed.\n\t * @param content the content to expose\n\t */\n\tprotected void postProcessContent(Map<String, Object> content) {\n\n\t}\n\n\t/**\n\t * Return the {@link PropertySource} to use based on the chosen {@link Mode}.\n\t * @return the property source\n\t */\n\tprotected PropertySource<?> toPropertySource() {\n\t\tif (this.mode.equals(Mode.FULL)) {\n\t\t\treturn this.properties.toPropertySource();\n\t\t}\n\t\treturn toSimplePropertySource();\n\t}\n\n\t/**\n\t * Copy the specified key to the target {@link Properties} if it is set.\n\t * @param target the target properties to update\n\t * @param key the key\n\t */\n\tprotected void copyIfSet(Properties target, String key) {\n\t\tString value = this.properties.get(key);\n\t\tif (StringUtils.hasText(value)) {\n\t\t\ttarget.put(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * Replace the {@code value} for the specified key if the value is not {@code null}.\n\t * @param content the content to expose\n\t * @param key the property to replace\n\t * @param value the new value\n\t */\n\tprotected void replaceValue(Map<String, Object> content, String key, @Nullable Object value) {\n\t\tif (content.containsKey(key) && value != null) {\n\t\t\tcontent.put(key, value);\n\t\t}\n\t}\n\n\t/**\n\t * Return the nested map with the specified key or empty map if the specified map\n\t * contains no mapping for the key.\n\t * @param map the content\n\t * @param key the key of a nested map\n\t * @return the nested map\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprotected Map<String, Object> getNestedMap(Map<String, Object> map, String key) {\n\t\tObject value = map.get(key);\n\t\tif (value == null) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\treturn (Map<String, Object>) value;\n\t}\n\n\t/**\n\t * Defines how properties should be exposed.\n\t */\n\tpublic enum Mode {\n\n\t\t/**\n\t\t * Expose all available data, including custom properties.\n\t\t */\n\t\tFULL,\n\n\t\t/**\n\t\t * Expose a pre-defined set of core settings only.\n\t\t */\n\t\tSIMPLE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/JavaInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.info.Info.Builder;\nimport org.springframework.boot.actuate.info.JavaInfoContributor.JavaInfoContributorRuntimeHints;\nimport org.springframework.boot.info.JavaInfo;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * An {@link InfoContributor} that exposes {@link JavaInfo}.\n *\n * @author Jonatan Ivanov\n * @since 2.6.0\n */\n@ImportRuntimeHints(JavaInfoContributorRuntimeHints.class)\npublic class JavaInfoContributor implements InfoContributor {\n\n\tprivate final JavaInfo javaInfo;\n\n\tpublic JavaInfoContributor() {\n\t\tthis.javaInfo = new JavaInfo();\n\t}\n\n\t@Override\n\tpublic void contribute(Builder builder) {\n\t\tbuilder.withDetail(\"java\", this.javaInfo);\n\t}\n\n\tstatic class JavaInfoContributorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), JavaInfo.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/MapInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A simple {@link InfoContributor} that exposes a map.\n *\n * @author Dave Syer\n * @since 1.4.0\n */\npublic class MapInfoContributor implements InfoContributor {\n\n\tprivate final Map<String, @Nullable Object> info;\n\n\tpublic MapInfoContributor(Map<String, Object> info) {\n\t\tthis.info = new LinkedHashMap<>(info);\n\t}\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tbuilder.withDetails(this.info);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/OsInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.info.OsInfoContributor.OsInfoContributorRuntimeHints;\nimport org.springframework.boot.info.OsInfo;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * An {@link InfoContributor} that exposes {@link OsInfo}.\n *\n * @author Jonatan Ivanov\n * @since 2.7.0\n */\n@ImportRuntimeHints(OsInfoContributorRuntimeHints.class)\npublic class OsInfoContributor implements InfoContributor {\n\n\tprivate final OsInfo osInfo;\n\n\tpublic OsInfoContributor() {\n\t\tthis.osInfo = new OsInfo();\n\t}\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tbuilder.withDetail(\"os\", this.osInfo);\n\t}\n\n\tstatic class OsInfoContributorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), OsInfo.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/ProcessInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.info.Info.Builder;\nimport org.springframework.boot.actuate.info.ProcessInfoContributor.ProcessInfoContributorRuntimeHints;\nimport org.springframework.boot.info.ProcessInfo;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * An {@link InfoContributor} that exposes {@link ProcessInfo}.\n *\n * @author Jonatan Ivanov\n * @since 3.3.0\n */\n@ImportRuntimeHints(ProcessInfoContributorRuntimeHints.class)\npublic class ProcessInfoContributor implements InfoContributor {\n\n\tprivate final ProcessInfo processInfo;\n\n\tpublic ProcessInfoContributor() {\n\t\tthis.processInfo = new ProcessInfo();\n\t}\n\n\t@Override\n\tpublic void contribute(Builder builder) {\n\t\tbuilder.withDetail(\"process\", this.processInfo);\n\t}\n\n\tstatic class ProcessInfoContributorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), ProcessInfo.class);\n\t\t\thints.reflection()\n\t\t\t\t.registerTypeIfPresent(classLoader, \"jdk.management.VirtualThreadSchedulerMXBean\",\n\t\t\t\t\t\tMemberCategory.INVOKE_PUBLIC_METHODS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SimpleInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A simple {@link InfoContributor} that exposes a single detail.\n *\n * @author Stephane Nicoll\n * @since 1.4.0\n */\npublic class SimpleInfoContributor implements InfoContributor {\n\n\tprivate final String prefix;\n\n\tprivate final @Nullable Object detail;\n\n\tpublic SimpleInfoContributor(String prefix, @Nullable Object detail) {\n\t\tAssert.notNull(prefix, \"'prefix' must not be null\");\n\t\tthis.prefix = prefix;\n\t\tthis.detail = detail;\n\t}\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tif (this.detail != null) {\n\t\t\tbuilder.withDetail(this.prefix, this.detail);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/SslInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.info.Info.Builder;\nimport org.springframework.boot.actuate.info.SslInfoContributor.SslInfoContributorRuntimeHints;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * An {@link InfoContributor} that exposes {@link SslInfo}.\n *\n * @author Jonatan Ivanov\n * @since 3.4.0\n */\n@ImportRuntimeHints(SslInfoContributorRuntimeHints.class)\npublic class SslInfoContributor implements InfoContributor {\n\n\tprivate final SslInfo sslInfo;\n\n\tpublic SslInfoContributor(SslInfo sslInfo) {\n\t\tthis.sslInfo = sslInfo;\n\t}\n\n\t@Override\n\tpublic void contribute(Builder builder) {\n\t\tbuilder.withDetail(\"ssl\", this.sslInfo);\n\t}\n\n\tstatic class SslInfoContributorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), SslInfo.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for application info.\n */\n@NullMarked\npackage org.springframework.boot.actuate.info;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/logging/LogFileWebEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.logging;\n\nimport java.io.File;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\n\n/**\n * Web {@link Endpoint @Endpoint} that provides access to an application's log file.\n *\n * @author Johannes Edmeier\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@WebEndpoint(id = \"logfile\")\npublic class LogFileWebEndpoint {\n\n\tprivate static final Log logger = LogFactory.getLog(LogFileWebEndpoint.class);\n\n\tprivate final @Nullable LogFile logFile;\n\n\tprivate final @Nullable File externalFile;\n\n\tpublic LogFileWebEndpoint(@Nullable LogFile logFile, @Nullable File externalFile) {\n\t\tthis.logFile = logFile;\n\t\tthis.externalFile = externalFile;\n\t}\n\n\t@ReadOperation(produces = \"text/plain; charset=UTF-8\")\n\tpublic @Nullable Resource logFile() {\n\t\tResource logFileResource = getLogFileResource();\n\t\tif (logFileResource == null || !logFileResource.isReadable()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn logFileResource;\n\t}\n\n\tprivate @Nullable Resource getLogFileResource() {\n\t\tif (this.externalFile != null) {\n\t\t\treturn new FileSystemResource(this.externalFile);\n\t\t}\n\t\tif (this.logFile == null) {\n\t\t\tlogger.debug(\"Missing 'logging.file.name' or 'logging.file.path' properties\");\n\t\t\treturn null;\n\t\t}\n\t\treturn new FileSystemResource(this.logFile.toString());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/logging/LoggersEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.logging;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.NavigableSet;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.annotation.RegisterReflectionForBinding;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint.GroupLoggerLevelsDescriptor;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint.SingleLoggerLevelsDescriptor;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggerConfiguration.ConfigurationScope;\nimport org.springframework.boot.logging.LoggerConfiguration.LevelConfiguration;\nimport org.springframework.boot.logging.LoggerGroup;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose a collection of {@link LoggerConfiguration}s.\n *\n * @author Ben Hale\n * @author Phillip Webb\n * @author HaiTao Zhang\n * @since 2.0.0\n */\n@Endpoint(id = \"loggers\")\n@RegisterReflectionForBinding({ GroupLoggerLevelsDescriptor.class, SingleLoggerLevelsDescriptor.class })\npublic class LoggersEndpoint {\n\n\tprivate final LoggingSystem loggingSystem;\n\n\tprivate final LoggerGroups loggerGroups;\n\n\t/**\n\t * Create a new {@link LoggersEndpoint} instance.\n\t * @param loggingSystem the logging system to expose\n\t * @param loggerGroups the logger group to expose\n\t */\n\tpublic LoggersEndpoint(LoggingSystem loggingSystem, LoggerGroups loggerGroups) {\n\t\tAssert.notNull(loggingSystem, \"'loggingSystem' must not be null\");\n\t\tAssert.notNull(loggerGroups, \"'loggerGroups' must not be null\");\n\t\tthis.loggingSystem = loggingSystem;\n\t\tthis.loggerGroups = loggerGroups;\n\t}\n\n\t@ReadOperation\n\tpublic LoggersDescriptor loggers() {\n\t\tCollection<LoggerConfiguration> configurations = this.loggingSystem.getLoggerConfigurations();\n\t\tif (configurations == null) {\n\t\t\treturn LoggersDescriptor.NONE;\n\t\t}\n\t\treturn new LoggersDescriptor(getLevels(), getLoggers(configurations), getGroups());\n\t}\n\n\tprivate Map<String, GroupLoggerLevelsDescriptor> getGroups() {\n\t\tMap<String, GroupLoggerLevelsDescriptor> groups = new LinkedHashMap<>();\n\t\tthis.loggerGroups.forEach((group) -> groups.put(group.getName(),\n\t\t\t\tnew GroupLoggerLevelsDescriptor(group.getConfiguredLevel(), group.getMembers())));\n\t\treturn groups;\n\t}\n\n\t@ReadOperation\n\tpublic @Nullable LoggerLevelsDescriptor loggerLevels(@Selector String name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tLoggerGroup group = this.loggerGroups.get(name);\n\t\tif (group != null) {\n\t\t\treturn new GroupLoggerLevelsDescriptor(group.getConfiguredLevel(), group.getMembers());\n\t\t}\n\t\tLoggerConfiguration configuration = this.loggingSystem.getLoggerConfiguration(name);\n\t\treturn (configuration != null) ? new SingleLoggerLevelsDescriptor(configuration) : null;\n\t}\n\n\t@WriteOperation\n\tpublic void configureLogLevel(@Selector String name, @Nullable LogLevel configuredLevel) {\n\t\tAssert.notNull(name, \"'name' must not be empty\");\n\t\tLoggerGroup group = this.loggerGroups.get(name);\n\t\tif (group != null && group.hasMembers()) {\n\t\t\tgroup.configureLogLevel(configuredLevel, this.loggingSystem::setLogLevel);\n\t\t\treturn;\n\t\t}\n\t\tthis.loggingSystem.setLogLevel(name, configuredLevel);\n\t}\n\n\tprivate NavigableSet<LogLevel> getLevels() {\n\t\tSet<LogLevel> levels = this.loggingSystem.getSupportedLogLevels();\n\t\treturn new TreeSet<>(levels).descendingSet();\n\t}\n\n\tprivate Map<String, LoggerLevelsDescriptor> getLoggers(Collection<LoggerConfiguration> configurations) {\n\t\tMap<String, LoggerLevelsDescriptor> loggers = new LinkedHashMap<>(configurations.size());\n\t\tfor (LoggerConfiguration configuration : configurations) {\n\t\t\tloggers.put(configuration.getName(), new SingleLoggerLevelsDescriptor(configuration));\n\t\t}\n\t\treturn loggers;\n\t}\n\n\t/**\n\t * Description of loggers.\n\t */\n\tpublic static class LoggersDescriptor implements OperationResponseBody {\n\n\t\t/**\n\t\t * Empty description.\n\t\t */\n\t\tpublic static final LoggersDescriptor NONE = new LoggersDescriptor(null, null, null);\n\n\t\tprivate final @Nullable NavigableSet<LogLevel> levels;\n\n\t\tprivate final @Nullable Map<String, LoggerLevelsDescriptor> loggers;\n\n\t\tprivate final @Nullable Map<String, GroupLoggerLevelsDescriptor> groups;\n\n\t\tpublic LoggersDescriptor(@Nullable NavigableSet<LogLevel> levels,\n\t\t\t\t@Nullable Map<String, LoggerLevelsDescriptor> loggers,\n\t\t\t\t@Nullable Map<String, GroupLoggerLevelsDescriptor> groups) {\n\t\t\tthis.levels = levels;\n\t\t\tthis.loggers = loggers;\n\t\t\tthis.groups = groups;\n\t\t}\n\n\t\tpublic @Nullable NavigableSet<LogLevel> getLevels() {\n\t\t\treturn this.levels;\n\t\t}\n\n\t\tpublic @Nullable Map<String, LoggerLevelsDescriptor> getLoggers() {\n\t\t\treturn this.loggers;\n\t\t}\n\n\t\tpublic @Nullable Map<String, GroupLoggerLevelsDescriptor> getGroups() {\n\t\t\treturn this.groups;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of levels configured for a given logger.\n\t */\n\tpublic static class LoggerLevelsDescriptor implements OperationResponseBody {\n\n\t\tprivate final @Nullable String configuredLevel;\n\n\t\tpublic LoggerLevelsDescriptor(@Nullable LogLevel configuredLevel) {\n\t\t\tthis.configuredLevel = (configuredLevel != null) ? configuredLevel.name() : null;\n\t\t}\n\n\t\tLoggerLevelsDescriptor(@Nullable LevelConfiguration directConfiguration) {\n\t\t\tthis.configuredLevel = (directConfiguration != null) ? directConfiguration.getName() : null;\n\t\t}\n\n\t\tprotected final @Nullable String getName(@Nullable LogLevel level) {\n\t\t\treturn (level != null) ? level.name() : null;\n\t\t}\n\n\t\tpublic @Nullable String getConfiguredLevel() {\n\t\t\treturn this.configuredLevel;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of levels configured for a given group logger.\n\t */\n\tpublic static class GroupLoggerLevelsDescriptor extends LoggerLevelsDescriptor {\n\n\t\tprivate final List<String> members;\n\n\t\tpublic GroupLoggerLevelsDescriptor(@Nullable LogLevel configuredLevel, List<String> members) {\n\t\t\tsuper(configuredLevel);\n\t\t\tthis.members = members;\n\t\t}\n\n\t\tpublic List<String> getMembers() {\n\t\t\treturn this.members;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of levels configured for a given single logger.\n\t */\n\tpublic static class SingleLoggerLevelsDescriptor extends LoggerLevelsDescriptor {\n\n\t\tprivate final String effectiveLevel;\n\n\t\tpublic SingleLoggerLevelsDescriptor(LoggerConfiguration configuration) {\n\t\t\tsuper(configuration.getLevelConfiguration(ConfigurationScope.DIRECT));\n\t\t\tthis.effectiveLevel = configuration.getLevelConfiguration().getName();\n\t\t}\n\n\t\tpublic String getEffectiveLevel() {\n\t\t\treturn this.effectiveLevel;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for logging.\n */\n@NullMarked\npackage org.springframework.boot.actuate.logging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/HeapDumpWebEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.PlatformManagedObject;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ReadableByteChannel;\nimport java.nio.file.Files;\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.Locale;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Web {@link Endpoint @Endpoint} to expose heap dumps.\n *\n * @author Lari Hotari\n * @author Phillip Webb\n * @author Raja Kolli\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@WebEndpoint(id = \"heapdump\", defaultAccess = Access.NONE)\npublic class HeapDumpWebEndpoint {\n\n\tprivate final long timeout;\n\n\tprivate final Lock lock = new ReentrantLock();\n\n\tprivate @Nullable HeapDumper heapDumper;\n\n\tpublic HeapDumpWebEndpoint() {\n\t\tthis(TimeUnit.SECONDS.toMillis(10));\n\t}\n\n\tprotected HeapDumpWebEndpoint(long timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<Resource> heapDump(@Nullable Boolean live) {\n\t\ttry {\n\t\t\tif (this.lock.tryLock(this.timeout, TimeUnit.MILLISECONDS)) {\n\t\t\t\ttry {\n\t\t\t\t\treturn new WebEndpointResponse<>(dumpHeap(live));\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.lock.unlock();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_INTERNAL_SERVER_ERROR);\n\t\t}\n\t\tcatch (HeapDumperUnavailableException ex) {\n\t\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t\t}\n\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_TOO_MANY_REQUESTS);\n\t}\n\n\tprivate Resource dumpHeap(@Nullable Boolean live) throws IOException, InterruptedException {\n\t\tif (this.heapDumper == null) {\n\t\t\tthis.heapDumper = createHeapDumper();\n\t\t}\n\t\tFile file = this.heapDumper.dumpHeap(live);\n\t\treturn new TemporaryFileSystemResource(file);\n\t}\n\n\t/**\n\t * Factory method used to create the {@link HeapDumper}.\n\t * @return the heap dumper to use\n\t * @throws HeapDumperUnavailableException if the heap dumper cannot be created\n\t */\n\tprotected HeapDumper createHeapDumper() throws HeapDumperUnavailableException {\n\t\tif (isRunningOnOpenJ9()) {\n\t\t\treturn new OpenJ9DiagnosticsMXBeanHeapDumper();\n\t\t}\n\t\treturn new HotSpotDiagnosticMXBeanHeapDumper();\n\t}\n\n\tprivate boolean isRunningOnOpenJ9() {\n\t\tString vmName = System.getProperty(\"java.vm.name\");\n\t\tif (StringUtils.hasLength(vmName) && vmName.toLowerCase(Locale.ROOT).contains(\"openj9\")) {\n\t\t\treturn true;\n\t\t}\n\t\tString vmVendor = System.getProperty(\"java.vm.vendor\");\n\t\treturn StringUtils.hasLength(vmVendor) && vmVendor.toLowerCase(Locale.ROOT).contains(\"openj9\");\n\t}\n\n\t/**\n\t * Strategy interface used to dump the heap to a file.\n\t */\n\t@FunctionalInterface\n\tprotected interface HeapDumper {\n\n\t\t/**\n\t\t * Dump the current heap to a file.\n\t\t * @param live if only <em>live</em> objects (i.e. objects that are reachable from\n\t\t * others) should be dumped. May be {@code null} to use a JVM-specific default.\n\t\t * @return the file containing the heap dump\n\t\t * @throws IOException on IO error\n\t\t * @throws InterruptedException on thread interruption\n\t\t * @throws IllegalArgumentException if live is non-null and is not supported by\n\t\t * the JVM\n\t\t * @since 3.0.0\n\t\t */\n\t\tFile dumpHeap(@Nullable Boolean live) throws IOException, InterruptedException;\n\n\t}\n\n\t/**\n\t * {@link HeapDumper} that uses {@code com.sun.management.HotSpotDiagnosticMXBean},\n\t * available on Oracle and OpenJDK, to dump the heap to a file.\n\t */\n\tprotected static class HotSpotDiagnosticMXBeanHeapDumper implements HeapDumper {\n\n\t\tprivate final Object diagnosticMXBean;\n\n\t\tprivate final Method dumpHeapMethod;\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprotected HotSpotDiagnosticMXBeanHeapDumper() {\n\t\t\ttry {\n\t\t\t\tClass<?> diagnosticMXBeanClass = ClassUtils\n\t\t\t\t\t.resolveClassName(\"com.sun.management.HotSpotDiagnosticMXBean\", null);\n\t\t\t\tthis.diagnosticMXBean = ManagementFactory\n\t\t\t\t\t.getPlatformMXBean((Class<PlatformManagedObject>) diagnosticMXBeanClass);\n\t\t\t\tthis.dumpHeapMethod = getDumpHeapMethod(diagnosticMXBeanClass);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new HeapDumperUnavailableException(\"Unable to locate HotSpotDiagnosticMXBean\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate static Method getDumpHeapMethod(Class<?> clazz) {\n\t\t\tMethod method = ReflectionUtils.findMethod(clazz, \"dumpHeap\", String.class, Boolean.TYPE);\n\t\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\t\treturn method;\n\t\t}\n\n\t\t@Override\n\t\tpublic File dumpHeap(@Nullable Boolean live) throws IOException {\n\t\t\tFile file = createTempFile();\n\t\t\tReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, file.getAbsolutePath(),\n\t\t\t\t\t(live != null) ? live : true);\n\t\t\treturn file;\n\t\t}\n\n\t\tprivate File createTempFile() throws IOException {\n\t\t\tString date = DateTimeFormatter.ofPattern(\"yyyy-MM-dd-HH-mm\").format(LocalDateTime.now());\n\t\t\tFile file = File.createTempFile(\"heap-\" + date, \".hprof\");\n\t\t\tfile.delete();\n\t\t\treturn file;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link HeapDumper} that uses\n\t * {@code openj9.lang.management.OpenJ9DiagnosticsMXBean}, available on OpenJ9, to\n\t * dump the heap to a file.\n\t */\n\tprivate static final class OpenJ9DiagnosticsMXBeanHeapDumper implements HeapDumper {\n\n\t\tprivate final Object diagnosticMXBean;\n\n\t\tprivate final Method dumpHeapMethod;\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate OpenJ9DiagnosticsMXBeanHeapDumper() {\n\t\t\ttry {\n\t\t\t\tClass<?> mxBeanClass = ClassUtils.resolveClassName(\"openj9.lang.management.OpenJ9DiagnosticsMXBean\",\n\t\t\t\t\t\tnull);\n\t\t\t\tthis.diagnosticMXBean = ManagementFactory.getPlatformMXBean((Class<PlatformManagedObject>) mxBeanClass);\n\t\t\t\tthis.dumpHeapMethod = getDumpHeapMethod(mxBeanClass);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tthrow new HeapDumperUnavailableException(\"Unable to locate OpenJ9DiagnosticsMXBean\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate static Method getDumpHeapMethod(Class<?> mxBeanClass) {\n\t\t\tMethod method = ReflectionUtils.findMethod(mxBeanClass, \"triggerDumpToFile\", String.class, String.class);\n\t\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\t\treturn method;\n\t\t}\n\n\t\t@Override\n\t\tpublic File dumpHeap(@Nullable Boolean live) throws IOException, InterruptedException {\n\t\t\tAssert.state(live == null, \"OpenJ9DiagnosticsMXBean does not support live parameter when dumping the heap\");\n\t\t\tString file = (String) ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, \"heap\",\n\t\t\t\t\tnull);\n\t\t\tAssert.state(file != null, \"'file' must not be null\");\n\t\t\treturn new File(file);\n\t\t}\n\n\t}\n\n\t/**\n\t * Exception to be thrown if the {@link HeapDumper} cannot be created.\n\t */\n\tprotected static class HeapDumperUnavailableException extends RuntimeException {\n\n\t\tpublic HeapDumperUnavailableException(String message, Throwable cause) {\n\t\t\tsuper(message, cause);\n\t\t}\n\n\t}\n\n\tprivate static final class TemporaryFileSystemResource extends FileSystemResource {\n\n\t\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\t\tprivate TemporaryFileSystemResource(File file) {\n\t\t\tsuper(file);\n\t\t}\n\n\t\t@Override\n\t\tpublic ReadableByteChannel readableChannel() throws IOException {\n\t\t\tReadableByteChannel readableChannel = super.readableChannel();\n\t\t\treturn new ReadableByteChannel() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic boolean isOpen() {\n\t\t\t\t\treturn readableChannel.isOpen();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void close() throws IOException {\n\t\t\t\t\tcloseThenDeleteFile(readableChannel);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic int read(ByteBuffer dst) throws IOException {\n\t\t\t\t\treturn readableChannel.read(dst);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\treturn new FilterInputStream(super.getInputStream()) {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void close() throws IOException {\n\t\t\t\t\tcloseThenDeleteFile(this.in);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\tprivate void closeThenDeleteFile(Closeable closeable) throws IOException {\n\t\t\ttry {\n\t\t\t\tcloseable.close();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tdeleteFile();\n\t\t\t}\n\t\t}\n\n\t\tprivate void deleteFile() {\n\t\t\ttry {\n\t\t\t\tFiles.delete(getFile().toPath());\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tTemporaryFileSystemResource.this.logger\n\t\t\t\t\t.warn(\"Failed to delete temporary heap dump file '\" + getFile() + \"'\", ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isFile() {\n\t\t\t// Prevent zero-copy so we can delete the file on close\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/PlainTextThreadDumpFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.management.LockInfo;\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.MonitorInfo;\nimport java.lang.management.RuntimeMXBean;\nimport java.lang.management.ThreadInfo;\nimport java.time.LocalDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.util.List;\nimport java.util.stream.Stream;\n\n/**\n * Formats a thread dump as plain text.\n *\n * @author Andy Wilkinson\n */\nclass PlainTextThreadDumpFormatter {\n\n\tString format(ThreadInfo[] threads) {\n\t\tStringWriter dump = new StringWriter();\n\t\tPrintWriter writer = new PrintWriter(dump);\n\t\twritePreamble(writer);\n\t\tfor (ThreadInfo info : threads) {\n\t\t\twriteThread(writer, info);\n\t\t}\n\t\treturn dump.toString();\n\t}\n\n\tprivate void writePreamble(PrintWriter writer) {\n\t\tDateTimeFormatter dateFormat = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\");\n\t\twriter.println(dateFormat.format(LocalDateTime.now()));\n\t\tRuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();\n\t\twriter.printf(\"Full thread dump %s (%s %s):%n\", runtime.getVmName(), runtime.getVmVersion(),\n\t\t\t\tSystem.getProperty(\"java.vm.info\"));\n\t\twriter.println();\n\t}\n\n\tprivate void writeThread(PrintWriter writer, ThreadInfo info) {\n\t\twriter.printf(\"\\\"%s\\\" - Thread t@%d%n\", info.getThreadName(), info.getThreadId());\n\t\twriter.printf(\"   %s: %s%n\", Thread.State.class.getCanonicalName(), info.getThreadState());\n\t\twriteStackTrace(writer, info, info.getLockedMonitors());\n\t\twriter.println();\n\t\twriteLockedOwnableSynchronizers(writer, info);\n\t\twriter.println();\n\t}\n\n\tprivate void writeStackTrace(PrintWriter writer, ThreadInfo info, MonitorInfo[] lockedMonitors) {\n\t\tint depth = 0;\n\t\tfor (StackTraceElement element : info.getStackTrace()) {\n\t\t\twriteStackTraceElement(writer, element, info, lockedMonitorsForDepth(lockedMonitors, depth), depth == 0);\n\t\t\tdepth++;\n\t\t}\n\t}\n\n\tprivate List<MonitorInfo> lockedMonitorsForDepth(MonitorInfo[] lockedMonitors, int depth) {\n\t\treturn Stream.of(lockedMonitors).filter((candidate) -> candidate.getLockedStackDepth() == depth).toList();\n\t}\n\n\tprivate void writeStackTraceElement(PrintWriter writer, StackTraceElement element, ThreadInfo info,\n\t\t\tList<MonitorInfo> lockedMonitors, boolean firstElement) {\n\t\twriter.printf(\"\\tat %s%n\", element.toString());\n\t\tLockInfo lockInfo = info.getLockInfo();\n\t\tif (firstElement && lockInfo != null) {\n\t\t\tif (element.getClassName().equals(Object.class.getName()) && element.getMethodName().equals(\"wait\")) {\n\t\t\t\twriter.printf(\"\\t- waiting on %s%n\", format(lockInfo));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tString lockOwner = info.getLockOwnerName();\n\t\t\t\tif (lockOwner != null) {\n\t\t\t\t\twriter.printf(\"\\t- waiting to lock %s owned by \\\"%s\\\" t@%d%n\", format(lockInfo), lockOwner,\n\t\t\t\t\t\t\tinfo.getLockOwnerId());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twriter.printf(\"\\t- parking to wait for %s%n\", format(lockInfo));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twriteMonitors(writer, lockedMonitors);\n\t}\n\n\tprivate String format(LockInfo lockInfo) {\n\t\treturn String.format(\"<%x> (a %s)\", lockInfo.getIdentityHashCode(), lockInfo.getClassName());\n\t}\n\n\tprivate void writeMonitors(PrintWriter writer, List<MonitorInfo> lockedMonitorsAtCurrentDepth) {\n\t\tfor (MonitorInfo lockedMonitor : lockedMonitorsAtCurrentDepth) {\n\t\t\twriter.printf(\"\\t- locked %s%n\", format(lockedMonitor));\n\t\t}\n\t}\n\n\tprivate void writeLockedOwnableSynchronizers(PrintWriter writer, ThreadInfo info) {\n\t\twriter.println(\"   Locked ownable synchronizers:\");\n\t\tLockInfo[] lockedSynchronizers = info.getLockedSynchronizers();\n\t\tif (lockedSynchronizers == null || lockedSynchronizers.length == 0) {\n\t\t\twriter.println(\"\\t- None\");\n\t\t}\n\t\telse {\n\t\t\tfor (LockInfo lockedSynchronizer : lockedSynchronizers) {\n\t\t\t\twriter.printf(\"\\t- Locked %s%n\", format(lockedSynchronizer));\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/ThreadDumpEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.ThreadInfo;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\n\n/**\n * {@link Endpoint @Endpoint} to expose thread info.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Endpoint(id = \"threaddump\")\npublic class ThreadDumpEndpoint {\n\n\tprivate final PlainTextThreadDumpFormatter plainTextFormatter = new PlainTextThreadDumpFormatter();\n\n\t@ReadOperation\n\tpublic ThreadDumpDescriptor threadDump() {\n\t\treturn getFormattedThreadDump(ThreadDumpDescriptor::new);\n\t}\n\n\t@ReadOperation(produces = \"text/plain;charset=UTF-8\")\n\tpublic String textThreadDump() {\n\t\treturn getFormattedThreadDump(this.plainTextFormatter::format);\n\t}\n\n\tprivate <T> T getFormattedThreadDump(Function<ThreadInfo[], T> formatter) {\n\t\treturn formatter.apply(ManagementFactory.getThreadMXBean().dumpAllThreads(true, true));\n\t}\n\n\t/**\n\t * Description of a thread dump.\n\t */\n\tpublic static final class ThreadDumpDescriptor implements OperationResponseBody {\n\n\t\tprivate final List<ThreadInfo> threads;\n\n\t\tprivate ThreadDumpDescriptor(ThreadInfo[] threads) {\n\t\t\tthis.threads = Arrays.asList(threads);\n\t\t}\n\n\t\tpublic List<ThreadInfo> getThreads() {\n\t\t\treturn this.threads;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/management/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for JVM management.\n */\n@NullMarked\npackage org.springframework.boot.actuate.management;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/sbom/SbomEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeSet;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.sbom.SbomEndpoint.SbomEndpointRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Endpoint @Endpoint} to expose an SBOM.\n *\n * @author Moritz Halbritter\n * @since 3.3.0\n */\n@Endpoint(id = \"sbom\")\n@ImportRuntimeHints(SbomEndpointRuntimeHints.class)\npublic class SbomEndpoint {\n\n\tstatic final String APPLICATION_SBOM_ID = \"application\";\n\n\tprivate static final List<AutodetectedSbom> AUTODETECTED_SBOMS = List.of(\n\t\t\tnew AutodetectedSbom(APPLICATION_SBOM_ID, \"classpath:META-INF/sbom/bom.json\", true),\n\t\t\tnew AutodetectedSbom(APPLICATION_SBOM_ID, \"classpath:META-INF/sbom/application.cdx.json\", true),\n\t\t\tnew AutodetectedSbom(\"native-image\", \"classpath:META-INF/native-image/sbom.json\", false));\n\n\tprivate final SbomProperties properties;\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final Map<String, Resource> sboms;\n\n\tpublic SbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader) {\n\t\tthis.properties = properties;\n\t\tthis.resourceLoader = resourceLoader;\n\t\tthis.sboms = loadSboms();\n\t}\n\n\tprivate Map<String, Resource> loadSboms() {\n\t\tMap<String, Resource> sboms = new HashMap<>();\n\t\taddConfiguredApplicationSbom(sboms);\n\t\taddAdditionalSboms(sboms);\n\t\taddAutodetectedSboms(sboms);\n\t\treturn Collections.unmodifiableMap(sboms);\n\t}\n\n\tprivate void addConfiguredApplicationSbom(Map<String, Resource> sboms) {\n\t\tString location = this.properties.getApplication().getLocation();\n\t\tif (!StringUtils.hasLength(location)) {\n\t\t\treturn;\n\t\t}\n\t\tResource resource = loadResource(location);\n\t\tif (resource != null) {\n\t\t\tsboms.put(APPLICATION_SBOM_ID, resource);\n\t\t}\n\t}\n\n\tprivate void addAdditionalSboms(Map<String, Resource> result) {\n\t\tthis.properties.getAdditional().forEach((id, sbom) -> {\n\t\t\tResource resource = loadResource(sbom.getLocation());\n\t\t\tif (resource != null) {\n\t\t\t\tif (result.putIfAbsent(id, resource) != null) {\n\t\t\t\t\tthrow new IllegalStateException(\"Duplicate SBOM registration with id '%s'\".formatted(id));\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void addAutodetectedSboms(Map<String, Resource> sboms) {\n\t\tfor (AutodetectedSbom sbom : AUTODETECTED_SBOMS) {\n\t\t\tif (sboms.containsKey(sbom.id())) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tResource resource = this.resourceLoader.getResource(sbom.resource());\n\t\t\tif (resource.exists()) {\n\t\t\t\tsboms.put(sbom.id(), resource);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate @Nullable Resource loadResource(@Nullable String location) {\n\t\tif (location == null) {\n\t\t\treturn null;\n\t\t}\n\t\tLocation parsedLocation = Location.of(location);\n\t\tResource resource = this.resourceLoader.getResource(parsedLocation.location());\n\t\tif (resource.exists()) {\n\t\t\treturn resource;\n\t\t}\n\t\tif (parsedLocation.optional()) {\n\t\t\treturn null;\n\t\t}\n\t\tthrow new IllegalStateException(\"Resource '%s' doesn't exist and it's not marked optional\".formatted(location));\n\t}\n\n\t@ReadOperation\n\tSboms sboms() {\n\t\treturn new Sboms(new TreeSet<>(this.sboms.keySet()));\n\t}\n\n\t@ReadOperation\n\t@Nullable Resource sbom(@Selector String id) {\n\t\treturn this.sboms.get(id);\n\t}\n\n\trecord Sboms(Collection<String> ids) implements OperationResponseBody {\n\t}\n\n\tprivate record Location(String location, boolean optional) {\n\n\t\tprivate static final String OPTIONAL_PREFIX = \"optional:\";\n\n\t\tstatic Location of(String location) {\n\t\t\tboolean optional = isOptional(location);\n\t\t\treturn new Location(optional ? stripOptionalPrefix(location) : location, optional);\n\t\t}\n\n\t\tprivate static boolean isOptional(String location) {\n\t\t\treturn location.startsWith(OPTIONAL_PREFIX);\n\t\t}\n\n\t\tprivate static String stripOptionalPrefix(String location) {\n\t\t\treturn location.substring(OPTIONAL_PREFIX.length());\n\t\t}\n\t}\n\n\tprivate record AutodetectedSbom(String id, String resource, boolean needsHints) {\n\t\tvoid registerHintsIfNeeded(RuntimeHints hints) {\n\t\t\tif (this.needsHints) {\n\t\t\t\thints.resources().registerPattern(stripClasspathPrefix(this.resource));\n\t\t\t}\n\t\t}\n\n\t\tprivate String stripClasspathPrefix(String location) {\n\t\t\treturn location.substring(\"classpath:\".length());\n\t\t}\n\t}\n\n\tstatic class SbomEndpointRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tfor (AutodetectedSbom sbom : AUTODETECTED_SBOMS) {\n\t\t\t\tsbom.registerHintsIfNeeded(hints);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/sbom/SbomEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.actuate.sbom.SbomProperties.Sbom;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.MimeType;\n\n/**\n * {@link EndpointWebExtension @EndpointWebExtension} for the {@link SbomEndpoint}.\n *\n * @author Moritz Halbritter\n * @since 3.3.0\n */\n@EndpointWebExtension(endpoint = SbomEndpoint.class)\npublic class SbomEndpointWebExtension {\n\n\tprivate final SbomEndpoint sbomEndpoint;\n\n\tprivate final SbomProperties properties;\n\n\tprivate final Map<String, SbomType> detectedMediaTypeCache = new ConcurrentHashMap<>();\n\n\tpublic SbomEndpointWebExtension(SbomEndpoint sbomEndpoint, SbomProperties properties) {\n\t\tthis.sbomEndpoint = sbomEndpoint;\n\t\tthis.properties = properties;\n\t}\n\n\t@ReadOperation\n\tWebEndpointResponse<Resource> sbom(@Selector String id) {\n\t\tResource resource = this.sbomEndpoint.sbom(id);\n\t\tif (resource == null) {\n\t\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);\n\t\t}\n\t\tMimeType type = getMediaType(id, resource);\n\t\treturn (type != null) ? new WebEndpointResponse<>(resource, type) : new WebEndpointResponse<>(resource);\n\t}\n\n\tprivate @Nullable MimeType getMediaType(String id, Resource resource) {\n\t\tif (SbomEndpoint.APPLICATION_SBOM_ID.equals(id) && this.properties.getApplication().getMediaType() != null) {\n\t\t\treturn this.properties.getApplication().getMediaType();\n\t\t}\n\t\tSbom sbomProperties = this.properties.getAdditional().get(id);\n\t\tif (sbomProperties != null && sbomProperties.getMediaType() != null) {\n\t\t\treturn sbomProperties.getMediaType();\n\t\t}\n\t\treturn this.detectedMediaTypeCache.computeIfAbsent(id, (ignored) -> {\n\t\t\ttry {\n\t\t\t\treturn detectSbomType(resource);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(\"Failed to detect type of resource '%s'\".formatted(resource), ex);\n\t\t\t}\n\t\t}).getMediaType();\n\t}\n\n\tprivate SbomType detectSbomType(Resource resource) throws IOException {\n\t\tString content = resource.getContentAsString(StandardCharsets.UTF_8);\n\t\tfor (SbomType candidate : SbomType.values()) {\n\t\t\tif (candidate.matches(content)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn SbomType.UNKNOWN;\n\t}\n\n\tenum SbomType {\n\n\t\tCYCLONE_DX(MimeType.valueOf(\"application/vnd.cyclonedx+json\")) {\n\t\t\t@Override\n\t\t\tboolean matches(String content) {\n\t\t\t\treturn content.replaceAll(\"\\\\s\", \"\").contains(\"\\\"bomFormat\\\":\\\"CycloneDX\\\"\");\n\t\t\t}\n\t\t},\n\t\tSPDX(MimeType.valueOf(\"application/spdx+json\")) {\n\t\t\t@Override\n\t\t\tboolean matches(String content) {\n\t\t\t\treturn content.contains(\"\\\"spdxVersion\\\"\");\n\t\t\t}\n\t\t},\n\t\tSYFT(MimeType.valueOf(\"application/vnd.syft+json\")) {\n\t\t\t@Override\n\t\t\tboolean matches(String content) {\n\t\t\t\treturn content.contains(\"\\\"FoundBy\\\"\") || content.contains(\"\\\"foundBy\\\"\");\n\t\t\t}\n\t\t},\n\t\tUNKNOWN(null) {\n\t\t\t@Override\n\t\t\tboolean matches(String content) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\tprivate final @Nullable MimeType mediaType;\n\n\t\tSbomType(@Nullable MimeType mediaType) {\n\t\t\tthis.mediaType = mediaType;\n\t\t}\n\n\t\t@Nullable MimeType getMediaType() {\n\t\t\treturn this.mediaType;\n\t\t}\n\n\t\tabstract boolean matches(String content);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/sbom/SbomProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.MimeType;\n\n/**\n * Configuration properties for the SBOM endpoint.\n *\n * @author Moritz Halbritter\n * @since 3.3.0\n */\n@ConfigurationProperties(\"management.endpoint.sbom\")\npublic class SbomProperties {\n\n\t/**\n\t * Application SBOM configuration.\n\t */\n\tprivate final Sbom application = new Sbom();\n\n\t/**\n\t * Additional SBOMs.\n\t */\n\tprivate Map<String, Sbom> additional = new HashMap<>();\n\n\tpublic Sbom getApplication() {\n\t\treturn this.application;\n\t}\n\n\tpublic Map<String, Sbom> getAdditional() {\n\t\treturn this.additional;\n\t}\n\n\tpublic void setAdditional(Map<String, Sbom> additional) {\n\t\tthis.additional = additional;\n\t}\n\n\tpublic static class Sbom {\n\n\t\t/**\n\t\t * Location to the SBOM. If null, the location will be auto-detected.\n\t\t */\n\t\tprivate @Nullable String location;\n\n\t\t/**\n\t\t * Media type of the SBOM. If null, the media type will be auto-detected.\n\t\t */\n\t\tprivate @Nullable MimeType mediaType;\n\n\t\tpublic @Nullable String getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\tpublic void setLocation(@Nullable String location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tpublic @Nullable MimeType getMediaType() {\n\t\t\treturn this.mediaType;\n\t\t}\n\n\t\tpublic void setMediaType(@Nullable MimeType mediaType) {\n\t\t\tthis.mediaType = mediaType;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/sbom/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for SBOMs.\n */\n@NullMarked\npackage org.springframework.boot.actuate.sbom;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.scheduling;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksEndpointRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.scheduling.Trigger;\nimport org.springframework.scheduling.config.CronTask;\nimport org.springframework.scheduling.config.FixedDelayTask;\nimport org.springframework.scheduling.config.FixedRateTask;\nimport org.springframework.scheduling.config.IntervalTask;\nimport org.springframework.scheduling.config.ScheduledTask;\nimport org.springframework.scheduling.config.ScheduledTaskHolder;\nimport org.springframework.scheduling.config.Task;\nimport org.springframework.scheduling.config.TaskExecutionOutcome;\nimport org.springframework.scheduling.config.TaskExecutionOutcome.Status;\nimport org.springframework.scheduling.config.TriggerTask;\nimport org.springframework.scheduling.support.CronTrigger;\nimport org.springframework.scheduling.support.PeriodicTrigger;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * {@link Endpoint @Endpoint} to expose information about an application's scheduled\n * tasks.\n *\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @since 2.0.0\n */\n@Endpoint(id = \"scheduledtasks\")\n@ImportRuntimeHints(ScheduledTasksEndpointRuntimeHints.class)\npublic class ScheduledTasksEndpoint {\n\n\tprivate final Collection<ScheduledTaskHolder> scheduledTaskHolders;\n\n\tpublic ScheduledTasksEndpoint(Collection<ScheduledTaskHolder> scheduledTaskHolders) {\n\t\tthis.scheduledTaskHolders = scheduledTaskHolders;\n\t}\n\n\t@ReadOperation\n\tpublic ScheduledTasksDescriptor scheduledTasks() {\n\t\tMultiValueMap<TaskType, TaskDescriptor> descriptionsByType = new LinkedMultiValueMap<>();\n\t\tfor (ScheduledTaskHolder holder : this.scheduledTaskHolders) {\n\t\t\tfor (ScheduledTask scheduledTask : holder.getScheduledTasks()) {\n\t\t\t\tTaskType taskType = TaskType.forTask(scheduledTask);\n\t\t\t\tif (taskType != null) {\n\t\t\t\t\tTaskDescriptor descriptor = taskType.createDescriptor(scheduledTask);\n\t\t\t\t\tdescriptionsByType.add(descriptor.getType(), descriptor);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new ScheduledTasksDescriptor(descriptionsByType);\n\t}\n\n\t/**\n\t * Description of an application's scheduled {@link Task Tasks}.\n\t */\n\tpublic static final class ScheduledTasksDescriptor implements OperationResponseBody {\n\n\t\tprivate final List<TaskDescriptor> cron;\n\n\t\tprivate final List<TaskDescriptor> fixedDelay;\n\n\t\tprivate final List<TaskDescriptor> fixedRate;\n\n\t\tprivate final List<TaskDescriptor> custom;\n\n\t\tprivate ScheduledTasksDescriptor(Map<TaskType, List<TaskDescriptor>> descriptionsByType) {\n\t\t\tthis.cron = descriptionsByType.getOrDefault(TaskType.CRON, Collections.emptyList());\n\t\t\tthis.fixedDelay = descriptionsByType.getOrDefault(TaskType.FIXED_DELAY, Collections.emptyList());\n\t\t\tthis.fixedRate = descriptionsByType.getOrDefault(TaskType.FIXED_RATE, Collections.emptyList());\n\t\t\tthis.custom = descriptionsByType.getOrDefault(TaskType.CUSTOM_TRIGGER, Collections.emptyList());\n\t\t}\n\n\t\tpublic List<TaskDescriptor> getCron() {\n\t\t\treturn this.cron;\n\t\t}\n\n\t\tpublic List<TaskDescriptor> getFixedDelay() {\n\t\t\treturn this.fixedDelay;\n\t\t}\n\n\t\tpublic List<TaskDescriptor> getFixedRate() {\n\t\t\treturn this.fixedRate;\n\t\t}\n\n\t\tpublic List<TaskDescriptor> getCustom() {\n\t\t\treturn this.custom;\n\t\t}\n\n\t}\n\n\t/**\n\t * Base class for descriptions of a {@link Task}.\n\t */\n\tpublic abstract static class TaskDescriptor {\n\n\t\tprivate final TaskType type;\n\n\t\tprivate final ScheduledTask scheduledTask;\n\n\t\tprivate final RunnableDescriptor runnable;\n\n\t\tprotected TaskDescriptor(ScheduledTask scheduledTask, TaskType type) {\n\t\t\tthis.scheduledTask = scheduledTask;\n\t\t\tthis.type = type;\n\t\t\tthis.runnable = new RunnableDescriptor(scheduledTask.getTask().getRunnable());\n\t\t}\n\n\t\tprivate TaskType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic final RunnableDescriptor getRunnable() {\n\t\t\treturn this.runnable;\n\t\t}\n\n\t\tpublic final @Nullable NextExecution getNextExecution() {\n\t\t\tInstant nextExecution = this.scheduledTask.nextExecution();\n\t\t\tif (nextExecution != null) {\n\t\t\t\treturn new NextExecution(nextExecution);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic final @Nullable LastExecution getLastExecution() {\n\t\t\tTaskExecutionOutcome lastExecutionOutcome = this.scheduledTask.getTask().getLastExecutionOutcome();\n\t\t\tif (lastExecutionOutcome.status() != Status.NONE) {\n\t\t\t\treturn new LastExecution(lastExecutionOutcome);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tpublic static final class NextExecution {\n\n\t\tprivate final Instant time;\n\n\t\tpublic NextExecution(Instant time) {\n\t\t\tthis.time = time;\n\t\t}\n\n\t\tpublic Instant getTime() {\n\t\t\treturn this.time;\n\t\t}\n\n\t}\n\n\tpublic static final class LastExecution {\n\n\t\tprivate final TaskExecutionOutcome lastExecutionOutcome;\n\n\t\tprivate LastExecution(TaskExecutionOutcome lastExecutionOutcome) {\n\t\t\tthis.lastExecutionOutcome = lastExecutionOutcome;\n\t\t}\n\n\t\tpublic Status getStatus() {\n\t\t\treturn this.lastExecutionOutcome.status();\n\t\t}\n\n\t\tpublic @Nullable Instant getTime() {\n\t\t\treturn this.lastExecutionOutcome.executionTime();\n\t\t}\n\n\t\tpublic @Nullable ExceptionInfo getException() {\n\t\t\tThrowable throwable = this.lastExecutionOutcome.throwable();\n\t\t\tif (throwable != null) {\n\t\t\t\treturn new ExceptionInfo(throwable);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tpublic static final class ExceptionInfo {\n\n\t\tprivate final Throwable throwable;\n\n\t\tprivate ExceptionInfo(Throwable throwable) {\n\t\t\tthis.throwable = throwable;\n\t\t}\n\n\t\tpublic String getType() {\n\t\t\treturn this.throwable.getClass().getName();\n\t\t}\n\n\t\tpublic @Nullable String getMessage() {\n\t\t\treturn this.throwable.getMessage();\n\t\t}\n\n\t}\n\n\tprivate enum TaskType {\n\n\t\tCRON(CronTask.class,\n\t\t\t\t(scheduledTask) -> new CronTaskDescriptor(scheduledTask, (CronTask) scheduledTask.getTask())),\n\t\tFIXED_DELAY(FixedDelayTask.class,\n\t\t\t\t(scheduledTask) -> new FixedDelayTaskDescriptor(scheduledTask,\n\t\t\t\t\t\t(FixedDelayTask) scheduledTask.getTask())),\n\t\tFIXED_RATE(FixedRateTask.class,\n\t\t\t\t(scheduledTask) -> new FixedRateTaskDescriptor(scheduledTask, (FixedRateTask) scheduledTask.getTask())),\n\t\tCUSTOM_TRIGGER(TriggerTask.class, TaskType::describeTriggerTask);\n\n\t\tfinal Class<?> taskClass;\n\n\t\tfinal Function<ScheduledTask, TaskDescriptor> describer;\n\n\t\tTaskType(Class<?> taskClass, Function<ScheduledTask, TaskDescriptor> describer) {\n\t\t\tthis.taskClass = taskClass;\n\t\t\tthis.describer = describer;\n\t\t}\n\n\t\tstatic @Nullable TaskType forTask(ScheduledTask scheduledTask) {\n\t\t\tfor (TaskType taskType : TaskType.values()) {\n\t\t\t\tif (taskType.taskClass.isInstance(scheduledTask.getTask())) {\n\t\t\t\t\treturn taskType;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tTaskDescriptor createDescriptor(ScheduledTask scheduledTask) {\n\t\t\treturn this.describer.apply(scheduledTask);\n\t\t}\n\n\t\tprivate static TaskDescriptor describeTriggerTask(ScheduledTask scheduledTask) {\n\t\t\tTriggerTask triggerTask = (TriggerTask) scheduledTask.getTask();\n\t\t\tTrigger trigger = triggerTask.getTrigger();\n\t\t\tif (trigger instanceof CronTrigger cronTrigger) {\n\t\t\t\treturn new CronTaskDescriptor(scheduledTask, triggerTask, cronTrigger);\n\t\t\t}\n\t\t\tif (trigger instanceof PeriodicTrigger periodicTrigger) {\n\t\t\t\tif (periodicTrigger.isFixedRate()) {\n\t\t\t\t\treturn new FixedRateTaskDescriptor(scheduledTask, triggerTask, periodicTrigger);\n\t\t\t\t}\n\t\t\t\treturn new FixedDelayTaskDescriptor(scheduledTask, triggerTask, periodicTrigger);\n\t\t\t}\n\t\t\treturn new CustomTriggerTaskDescriptor(scheduledTask);\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an {@link IntervalTask}.\n\t */\n\tpublic static class IntervalTaskDescriptor extends TaskDescriptor {\n\n\t\tprivate final long initialDelay;\n\n\t\tprivate final long interval;\n\n\t\tprotected IntervalTaskDescriptor(ScheduledTask scheduledTask, TaskType type, IntervalTask intervalTask) {\n\t\t\tsuper(scheduledTask, type);\n\t\t\tthis.initialDelay = intervalTask.getInitialDelayDuration().toMillis();\n\t\t\tthis.interval = intervalTask.getIntervalDuration().toMillis();\n\t\t}\n\n\t\tprotected IntervalTaskDescriptor(ScheduledTask scheduledTask, TaskType type, TriggerTask task,\n\t\t\t\tPeriodicTrigger trigger) {\n\t\t\tsuper(scheduledTask, type);\n\t\t\tDuration initialDelayDuration = trigger.getInitialDelayDuration();\n\t\t\tthis.initialDelay = (initialDelayDuration != null) ? initialDelayDuration.toMillis() : 0;\n\t\t\tthis.interval = trigger.getPeriodDuration().toMillis();\n\t\t}\n\n\t\tpublic long getInitialDelay() {\n\t\t\treturn this.initialDelay;\n\t\t}\n\n\t\tpublic long getInterval() {\n\t\t\treturn this.interval;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link FixedDelayTask} or a {@link TriggerTask} with a fixed-delay\n\t * {@link PeriodicTrigger}.\n\t */\n\tpublic static final class FixedDelayTaskDescriptor extends IntervalTaskDescriptor {\n\n\t\tprivate FixedDelayTaskDescriptor(ScheduledTask scheduledTask, FixedDelayTask task) {\n\t\t\tsuper(scheduledTask, TaskType.FIXED_DELAY, task);\n\t\t}\n\n\t\tprivate FixedDelayTaskDescriptor(ScheduledTask scheduledTask, TriggerTask task, PeriodicTrigger trigger) {\n\t\t\tsuper(scheduledTask, TaskType.FIXED_DELAY, task, trigger);\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link FixedRateTask} or a {@link TriggerTask} with a fixed-rate\n\t * {@link PeriodicTrigger}.\n\t */\n\tpublic static final class FixedRateTaskDescriptor extends IntervalTaskDescriptor {\n\n\t\tprivate FixedRateTaskDescriptor(ScheduledTask scheduledTask, FixedRateTask task) {\n\t\t\tsuper(scheduledTask, TaskType.FIXED_RATE, task);\n\t\t}\n\n\t\tprivate FixedRateTaskDescriptor(ScheduledTask scheduledTask, TriggerTask task, PeriodicTrigger trigger) {\n\t\t\tsuper(scheduledTask, TaskType.FIXED_RATE, task, trigger);\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link CronTask} or a {@link TriggerTask} with a\n\t * {@link CronTrigger}.\n\t */\n\tpublic static final class CronTaskDescriptor extends TaskDescriptor {\n\n\t\tprivate final String expression;\n\n\t\tprivate CronTaskDescriptor(ScheduledTask scheduledTask, CronTask cronTask) {\n\t\t\tsuper(scheduledTask, TaskType.CRON);\n\t\t\tthis.expression = cronTask.getExpression();\n\t\t}\n\n\t\tprivate CronTaskDescriptor(ScheduledTask scheduledTask, TriggerTask triggerTask, CronTrigger trigger) {\n\t\t\tsuper(scheduledTask, TaskType.CRON);\n\t\t\tthis.expression = trigger.getExpression();\n\t\t}\n\n\t\tpublic String getExpression() {\n\t\t\treturn this.expression;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link TriggerTask} with a custom {@link Trigger}.\n\t */\n\tpublic static final class CustomTriggerTaskDescriptor extends TaskDescriptor {\n\n\t\tprivate final String trigger;\n\n\t\tprivate CustomTriggerTaskDescriptor(ScheduledTask scheduledTask) {\n\t\t\tsuper(scheduledTask, TaskType.CUSTOM_TRIGGER);\n\t\t\tTriggerTask triggerTask = (TriggerTask) scheduledTask.getTask();\n\t\t\tthis.trigger = triggerTask.getTrigger().toString();\n\t\t}\n\n\t\tpublic String getTrigger() {\n\t\t\treturn this.trigger;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link Task Task's} {@link Runnable}.\n\t */\n\tpublic static final class RunnableDescriptor {\n\n\t\tprivate final String target;\n\n\t\tprivate RunnableDescriptor(Runnable runnable) {\n\t\t\tthis.target = runnable.toString();\n\t\t}\n\n\t\tpublic String getTarget() {\n\t\t\treturn this.target;\n\t\t}\n\n\t}\n\n\tstatic class ScheduledTasksEndpointRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), FixedRateTaskDescriptor.class,\n\t\t\t\t\tFixedDelayTaskDescriptor.class, CronTaskDescriptor.class, CustomTriggerTaskDescriptor.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/scheduling/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator scheduling support.\n */\n@NullMarked\npackage org.springframework.boot.actuate.scheduling;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AbstractAuthenticationAuditListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.security;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.security.authentication.event.AbstractAuthenticationEvent;\n\n/**\n * Abstract {@link ApplicationListener} to expose Spring Security\n * {@link AbstractAuthenticationEvent authentication events} as {@link AuditEvent}s.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @since 1.3.0\n */\npublic abstract class AbstractAuthenticationAuditListener\n\t\timplements ApplicationListener<AbstractAuthenticationEvent>, ApplicationEventPublisherAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationEventPublisher publisher;\n\n\t@Override\n\tpublic void setApplicationEventPublisher(ApplicationEventPublisher publisher) {\n\t\tthis.publisher = publisher;\n\t}\n\n\tprotected ApplicationEventPublisher getPublisher() {\n\t\treturn this.publisher;\n\t}\n\n\tprotected void publish(AuditEvent event) {\n\t\tif (getPublisher() != null) {\n\t\t\tgetPublisher().publishEvent(new AuditApplicationEvent(event));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AbstractAuthorizationAuditListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.security;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.security.authorization.event.AuthorizationDeniedEvent;\nimport org.springframework.security.authorization.event.AuthorizationEvent;\nimport org.springframework.security.authorization.event.AuthorizationGrantedEvent;\n\n/**\n * Abstract {@link ApplicationListener} to expose Spring Security\n * {@link AuthorizationDeniedEvent authorization denied} and\n * {@link AuthorizationGrantedEvent authorization granted} events as {@link AuditEvent}s.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @since 1.3.0\n */\npublic abstract class AbstractAuthorizationAuditListener\n\t\timplements ApplicationListener<AuthorizationEvent>, ApplicationEventPublisherAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationEventPublisher publisher;\n\n\t@Override\n\tpublic void setApplicationEventPublisher(ApplicationEventPublisher publisher) {\n\t\tthis.publisher = publisher;\n\t}\n\n\tprotected ApplicationEventPublisher getPublisher() {\n\t\treturn this.publisher;\n\t}\n\n\tprotected void publish(AuditEvent event) {\n\t\tif (getPublisher() != null) {\n\t\t\tgetPublisher().publishEvent(new AuditApplicationEvent(event));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthenticationAuditListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.security;\n\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.security.authentication.event.AbstractAuthenticationEvent;\nimport org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;\nimport org.springframework.security.authentication.event.AuthenticationSuccessEvent;\nimport org.springframework.security.authentication.event.LogoutSuccessEvent;\nimport org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Default implementation of {@link AbstractAuthenticationAuditListener}.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @since 1.0.0\n */\npublic class AuthenticationAuditListener extends AbstractAuthenticationAuditListener {\n\n\t/**\n\t * Authentication success event type.\n\t */\n\tpublic static final String AUTHENTICATION_SUCCESS = \"AUTHENTICATION_SUCCESS\";\n\n\t/**\n\t * Authentication failure event type.\n\t */\n\tpublic static final String AUTHENTICATION_FAILURE = \"AUTHENTICATION_FAILURE\";\n\n\t/**\n\t * Authentication switch event type.\n\t */\n\tpublic static final String AUTHENTICATION_SWITCH = \"AUTHENTICATION_SWITCH\";\n\n\t/**\n\t * Logout success event type.\n\t *\n\t * @since 3.4.0\n\t */\n\tpublic static final String LOGOUT_SUCCESS = \"LOGOUT_SUCCESS\";\n\n\tprivate static final String WEB_LISTENER_CHECK_CLASS = \"org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent\";\n\n\tprivate final @Nullable WebAuditListener webListener = maybeCreateWebListener();\n\n\tprivate static @Nullable WebAuditListener maybeCreateWebListener() {\n\t\tif (ClassUtils.isPresent(WEB_LISTENER_CHECK_CLASS, null)) {\n\t\t\treturn new WebAuditListener();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(AbstractAuthenticationEvent event) {\n\t\tif (event instanceof AbstractAuthenticationFailureEvent failureEvent) {\n\t\t\tonAuthenticationFailureEvent(failureEvent);\n\t\t}\n\t\telse if (this.webListener != null && this.webListener.accepts(event)) {\n\t\t\tthis.webListener.process(this, event);\n\t\t}\n\t\telse if (event instanceof AuthenticationSuccessEvent successEvent) {\n\t\t\tonAuthenticationSuccessEvent(successEvent);\n\t\t}\n\t\telse if (event instanceof LogoutSuccessEvent logoutSuccessEvent) {\n\t\t\tonLogoutSuccessEvent(logoutSuccessEvent);\n\t\t}\n\t}\n\n\tprivate void onAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) {\n\t\tMap<String, @Nullable Object> data = new LinkedHashMap<>();\n\t\tdata.put(\"type\", event.getException().getClass().getName());\n\t\tdata.put(\"message\", event.getException().getMessage());\n\t\tif (event.getAuthentication().getDetails() != null) {\n\t\t\tdata.put(\"details\", event.getAuthentication().getDetails());\n\t\t}\n\t\tpublish(new AuditEvent(event.getAuthentication().getName(), AUTHENTICATION_FAILURE, data));\n\t}\n\n\tprivate void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) {\n\t\tMap<String, @Nullable Object> data = new LinkedHashMap<>();\n\t\tif (event.getAuthentication().getDetails() != null) {\n\t\t\tdata.put(\"details\", event.getAuthentication().getDetails());\n\t\t}\n\t\tpublish(new AuditEvent(event.getAuthentication().getName(), AUTHENTICATION_SUCCESS, data));\n\t}\n\n\tprivate void onLogoutSuccessEvent(LogoutSuccessEvent event) {\n\t\tMap<String, @Nullable Object> data = new LinkedHashMap<>();\n\t\tif (event.getAuthentication().getDetails() != null) {\n\t\t\tdata.put(\"details\", event.getAuthentication().getDetails());\n\t\t}\n\t\tpublish(new AuditEvent(event.getAuthentication().getName(), LOGOUT_SUCCESS, data));\n\t}\n\n\tprivate static final class WebAuditListener {\n\n\t\tvoid process(@Nullable AuthenticationAuditListener listener, AbstractAuthenticationEvent input) {\n\t\t\tif (listener != null) {\n\t\t\t\tAuthenticationSwitchUserEvent event = (AuthenticationSwitchUserEvent) input;\n\t\t\t\tMap<String, @Nullable Object> data = new HashMap<>();\n\t\t\t\tif (event.getAuthentication().getDetails() != null) {\n\t\t\t\t\tdata.put(\"details\", event.getAuthentication().getDetails());\n\t\t\t\t}\n\t\t\t\tif (event.getTargetUser() != null) {\n\t\t\t\t\tdata.put(\"target\", event.getTargetUser().getUsername());\n\t\t\t\t}\n\t\t\t\tlistener.publish(new AuditEvent(event.getAuthentication().getName(), AUTHENTICATION_SWITCH, data));\n\t\t\t}\n\n\t\t}\n\n\t\tboolean accepts(AbstractAuthenticationEvent event) {\n\t\t\treturn event instanceof AuthenticationSwitchUserEvent;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/AuthorizationAuditListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.security;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.security.authorization.event.AuthorizationDeniedEvent;\nimport org.springframework.security.authorization.event.AuthorizationEvent;\nimport org.springframework.security.core.Authentication;\n\n/**\n * Default implementation of {@link AbstractAuthorizationAuditListener}.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @since 1.0.0\n */\npublic class AuthorizationAuditListener extends AbstractAuthorizationAuditListener {\n\n\t/**\n\t * Authorization failure event type.\n\t */\n\tpublic static final String AUTHORIZATION_FAILURE = \"AUTHORIZATION_FAILURE\";\n\n\t@Override\n\tpublic void onApplicationEvent(AuthorizationEvent event) {\n\t\tif (event instanceof AuthorizationDeniedEvent<?> authorizationDeniedEvent) {\n\t\t\tonAuthorizationDeniedEvent(authorizationDeniedEvent);\n\t\t}\n\t}\n\n\tprivate void onAuthorizationDeniedEvent(AuthorizationDeniedEvent<?> event) {\n\t\tString name = getName(event.getAuthentication());\n\t\tMap<String, @Nullable Object> data = new LinkedHashMap<>();\n\t\tObject details = getDetails(event.getAuthentication());\n\t\tif (details != null) {\n\t\t\tdata.put(\"details\", details);\n\t\t}\n\t\tpublish(new AuditEvent(name, AUTHORIZATION_FAILURE, data));\n\t}\n\n\tprivate String getName(Supplier<Authentication> authentication) {\n\t\ttry {\n\t\t\treturn authentication.get().getName();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn \"<unknown>\";\n\t\t}\n\t}\n\n\tprivate @Nullable Object getDetails(Supplier<Authentication> authentication) {\n\t\ttry {\n\t\t\treturn authentication.get().getDetails();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/security/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for security.\n *\n */\n@NullMarked\npackage org.springframework.boot.actuate.security;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/startup/StartupEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.startup;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.boot.SpringBootVersion;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.startup.StartupEndpoint.StartupEndpointRuntimeHints;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.context.metrics.buffering.StartupTimeline;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * {@link Endpoint @Endpoint} to expose the timeline of the\n * {@link org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup\n * application startup}.\n *\n * @author Brian Clozel\n * @author Chris Bono\n * @since 2.4.0\n */\n@Endpoint(id = \"startup\")\n@ImportRuntimeHints(StartupEndpointRuntimeHints.class)\npublic class StartupEndpoint {\n\n\tprivate final BufferingApplicationStartup applicationStartup;\n\n\t/**\n\t * Creates a new {@code StartupEndpoint} that will describe the timeline of buffered\n\t * application startup events.\n\t * @param applicationStartup the application startup\n\t */\n\tpublic StartupEndpoint(BufferingApplicationStartup applicationStartup) {\n\t\tthis.applicationStartup = applicationStartup;\n\t}\n\n\t@ReadOperation\n\tpublic StartupDescriptor startupSnapshot() {\n\t\tStartupTimeline startupTimeline = this.applicationStartup.getBufferedTimeline();\n\t\treturn new StartupDescriptor(startupTimeline);\n\t}\n\n\t@WriteOperation\n\tpublic StartupDescriptor startup() {\n\t\tStartupTimeline startupTimeline = this.applicationStartup.drainBufferedTimeline();\n\t\treturn new StartupDescriptor(startupTimeline);\n\t}\n\n\t/**\n\t * Description of an application startup.\n\t */\n\tpublic static final class StartupDescriptor implements OperationResponseBody {\n\n\t\tprivate final String springBootVersion;\n\n\t\tprivate final StartupTimeline timeline;\n\n\t\tprivate StartupDescriptor(StartupTimeline timeline) {\n\t\t\tthis.timeline = timeline;\n\t\t\tthis.springBootVersion = SpringBootVersion.getVersion();\n\t\t}\n\n\t\tpublic String getSpringBootVersion() {\n\t\t\treturn this.springBootVersion;\n\t\t}\n\n\t\tpublic StartupTimeline getTimeline() {\n\t\t\treturn this.timeline;\n\t\t}\n\n\t}\n\n\tstatic class StartupEndpointRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate static final TypeReference DEFAULT_TAG = TypeReference\n\t\t\t.of(\"org.springframework.boot.context.metrics.buffering.BufferedStartupStep$DefaultTag\");\n\n\t\tprivate static final TypeReference BUFFERED_STARTUP_STEP = TypeReference\n\t\t\t.of(\"org.springframework.boot.context.metrics.buffering.BufferedStartupStep\");\n\n\t\tprivate static final TypeReference FLIGHT_RECORDER_TAG = TypeReference\n\t\t\t.of(\"org.springframework.core.metrics.jfr.FlightRecorderStartupStep$FlightRecorderTag\");\n\n\t\tprivate static final TypeReference FLIGHT_RECORDER_STARTUP_STEP = TypeReference\n\t\t\t.of(\"org.springframework.core.metrics.jfr.FlightRecorderStartupStep\");\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerType(DEFAULT_TAG, (typeHint) -> typeHint.onReachableType(BUFFERED_STARTUP_STEP)\n\t\t\t\t\t.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));\n\t\t\thints.reflection()\n\t\t\t\t.registerType(FLIGHT_RECORDER_TAG, (typeHint) -> typeHint.onReachableType(FLIGHT_RECORDER_STARTUP_STEP)\n\t\t\t\t\t.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/startup/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for {@link org.springframework.core.metrics.ApplicationStartup}.\n */\n@NullMarked\npackage org.springframework.boot.actuate.startup;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchange.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.net.URI;\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpHeaders;\n\n/**\n * An HTTP request and response exchange. Can be used for analyzing contextual information\n * such as HTTP headers. Data from this class will be exposed by the\n * {@link HttpExchangesEndpoint}, usually as JSON.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.0.0\n */\npublic final class HttpExchange {\n\n\tprivate final Instant timestamp;\n\n\tprivate final Request request;\n\n\tprivate final Response response;\n\n\tprivate final @Nullable Principal principal;\n\n\tprivate final @Nullable Session session;\n\n\tprivate final @Nullable Duration timeTaken;\n\n\t/**\n\t * Primarily for use by {@link HttpExchangeRepository} implementations when recreating\n\t * an exchange from a persistent store.\n\t * @param timestamp the instant that the exchange started\n\t * @param request the request\n\t * @param response the response\n\t * @param principal the principal\n\t * @param session the session\n\t * @param timeTaken the total time taken\n\t */\n\tpublic HttpExchange(Instant timestamp, Request request, Response response, @Nullable Principal principal,\n\t\t\t@Nullable Session session, @Nullable Duration timeTaken) {\n\t\tthis.timestamp = timestamp;\n\t\tthis.request = request;\n\t\tthis.response = response;\n\t\tthis.principal = principal;\n\t\tthis.session = session;\n\t\tthis.timeTaken = timeTaken;\n\t}\n\n\t/**\n\t * Returns the instant that the exchange started.\n\t * @return the start timestamp\n\t */\n\tpublic Instant getTimestamp() {\n\t\treturn this.timestamp;\n\t}\n\n\t/**\n\t * Returns the request that started the exchange.\n\t * @return the request.\n\t */\n\tpublic Request getRequest() {\n\t\treturn this.request;\n\t}\n\n\t/**\n\t * Returns the response that completed the exchange.\n\t * @return the response.\n\t */\n\tpublic Response getResponse() {\n\t\treturn this.response;\n\t}\n\n\t/**\n\t * Returns the principal.\n\t * @return the request\n\t */\n\tpublic @Nullable Principal getPrincipal() {\n\t\treturn this.principal;\n\t}\n\n\t/**\n\t * Returns the session details.\n\t * @return the session\n\t */\n\tpublic @Nullable Session getSession() {\n\t\treturn this.session;\n\t}\n\n\t/**\n\t * Returns the total time taken for the exchange.\n\t * @return the total time taken\n\t */\n\tpublic @Nullable Duration getTimeTaken() {\n\t\treturn this.timeTaken;\n\t}\n\n\t/**\n\t * Start a new {@link Started} from the given source request.\n\t * @param request the recordable HTTP request\n\t * @return an in-progress request\n\t */\n\tpublic static Started start(RecordableHttpRequest request) {\n\t\treturn start(Clock.systemUTC(), request);\n\t}\n\n\t/**\n\t * Start a new {@link Started} from the given source request.\n\t * @param clock the clock to use\n\t * @param request the recordable HTTP request\n\t * @return an in-progress request\n\t */\n\tpublic static Started start(Clock clock, RecordableHttpRequest request) {\n\t\treturn new Started(clock, request);\n\t}\n\n\t/**\n\t * A started request that when {@link #finish finished} will return a new\n\t * {@link HttpExchange} instance.\n\t */\n\tpublic static final class Started {\n\n\t\tprivate final Instant timestamp;\n\n\t\tprivate final RecordableHttpRequest request;\n\n\t\tprivate Started(Clock clock, RecordableHttpRequest request) {\n\t\t\tthis.timestamp = Instant.now(clock);\n\t\t\tthis.request = request;\n\t\t}\n\n\t\t/**\n\t\t * Finish the request and return a new {@link HttpExchange} instance.\n\t\t * @param response the recordable HTTP response\n\t\t * @param principalSupplier a supplier to provide the principal\n\t\t * @param sessionIdSupplier a supplier to provide the session ID\n\t\t * @param includes the options to include\n\t\t * @return a new {@link HttpExchange} instance\n\t\t */\n\t\tpublic HttpExchange finish(RecordableHttpResponse response,\n\t\t\t\tSupplier<java.security.@Nullable Principal> principalSupplier,\n\t\t\t\tSupplier<@Nullable String> sessionIdSupplier, Include... includes) {\n\t\t\treturn finish(Clock.systemUTC(), response, principalSupplier, sessionIdSupplier, includes);\n\t\t}\n\n\t\t/**\n\t\t * Finish the request and return a new {@link HttpExchange} instance.\n\t\t * @param clock the clock to use\n\t\t * @param response the recordable HTTP response\n\t\t * @param principalSupplier a supplier to provide the principal\n\t\t * @param sessionIdSupplier a supplier to provide the session ID\n\t\t * @param includes the options to include\n\t\t * @return a new {@link HttpExchange} instance\n\t\t */\n\t\tpublic HttpExchange finish(Clock clock, RecordableHttpResponse response,\n\t\t\t\tSupplier<java.security.@Nullable Principal> principalSupplier,\n\t\t\t\tSupplier<@Nullable String> sessionIdSupplier, Include... includes) {\n\t\t\treturn finish(clock, response, principalSupplier, sessionIdSupplier,\n\t\t\t\t\tnew HashSet<>(Arrays.asList(includes)));\n\t\t}\n\n\t\t/**\n\t\t * Finish the request and return a new {@link HttpExchange} instance.\n\t\t * @param response the recordable HTTP response\n\t\t * @param principalSupplier a supplier to provide the principal\n\t\t * @param sessionIdSupplier a supplier to provide the session ID\n\t\t * @param includes the options to include\n\t\t * @return a new {@link HttpExchange} instance\n\t\t */\n\t\tpublic HttpExchange finish(RecordableHttpResponse response,\n\t\t\t\tSupplier<java.security.@Nullable Principal> principalSupplier,\n\t\t\t\tSupplier<@Nullable String> sessionIdSupplier, Set<Include> includes) {\n\t\t\treturn finish(Clock.systemUTC(), response, principalSupplier, sessionIdSupplier, includes);\n\t\t}\n\n\t\t/**\n\t\t * Finish the request and return a new {@link HttpExchange} instance.\n\t\t * @param clock the clock to use\n\t\t * @param response the recordable HTTP response\n\t\t * @param principalSupplier a supplier to provide the principal\n\t\t * @param sessionIdSupplier a supplier to provide the session ID\n\t\t * @param includes the options to include\n\t\t * @return a new {@link HttpExchange} instance\n\t\t */\n\t\tpublic HttpExchange finish(Clock clock, RecordableHttpResponse response,\n\t\t\t\tSupplier<java.security.@Nullable Principal> principalSupplier,\n\t\t\t\tSupplier<@Nullable String> sessionIdSupplier, Set<Include> includes) {\n\t\t\tRequest exchangeRequest = new Request(this.request, includes);\n\t\t\tResponse exchangeResponse = new Response(response, includes);\n\t\t\tPrincipal principal = (includes.contains(Include.PRINCIPAL)) ? Principal.from(principalSupplier) : null;\n\t\t\tSession session = (includes.contains(Include.SESSION_ID)) ? Session.from(sessionIdSupplier) : null;\n\t\t\tDuration duration = (includes.contains(Include.TIME_TAKEN))\n\t\t\t\t\t? Duration.between(this.timestamp, Instant.now(clock)) : null;\n\t\t\treturn new HttpExchange(this.timestamp, exchangeRequest, exchangeResponse, principal, session, duration);\n\t\t}\n\n\t}\n\n\t/**\n\t * The request that started the exchange.\n\t */\n\tpublic static final class Request {\n\n\t\tprivate final URI uri;\n\n\t\tprivate final @Nullable String remoteAddress;\n\n\t\tprivate final String method;\n\n\t\tprivate final Map<String, List<String>> headers;\n\n\t\tprivate Request(RecordableHttpRequest request, Set<Include> includes) {\n\t\t\tthis.uri = request.getUri();\n\t\t\tthis.remoteAddress = (includes.contains(Include.REMOTE_ADDRESS)) ? request.getRemoteAddress() : null;\n\t\t\tthis.method = request.getMethod();\n\t\t\tthis.headers = Collections.unmodifiableMap(filterHeaders(request.getHeaders(), includes));\n\t\t}\n\n\t\t/**\n\t\t * Creates a fully-configured {@code Request} instance. Primarily for use by\n\t\t * {@link HttpExchangeRepository} implementations when recreating a request from a\n\t\t * persistent store.\n\t\t * @param uri the URI of the request\n\t\t * @param remoteAddress remote address from which the request was sent, if known\n\t\t * @param method the HTTP method of the request\n\t\t * @param headers the request headers\n\t\t */\n\t\tpublic Request(URI uri, String remoteAddress, String method, Map<String, List<String>> headers) {\n\t\t\tthis.uri = uri;\n\t\t\tthis.remoteAddress = remoteAddress;\n\t\t\tthis.method = method;\n\t\t\tthis.headers = Collections.unmodifiableMap(new LinkedHashMap<>(headers));\n\t\t}\n\n\t\tprivate Map<String, List<String>> filterHeaders(Map<String, List<String>> headers, Set<Include> includes) {\n\t\t\tHeadersFilter filter = new HeadersFilter(includes, Include.REQUEST_HEADERS);\n\t\t\tfilter.excludeUnless(HttpHeaders.COOKIE, Include.COOKIE_HEADERS);\n\t\t\tfilter.excludeUnless(HttpHeaders.AUTHORIZATION, Include.AUTHORIZATION_HEADER);\n\t\t\treturn filter.apply(headers);\n\t\t}\n\n\t\t/**\n\t\t * Return the HTTP method requested.\n\t\t * @return the HTTP method\n\t\t */\n\t\tpublic String getMethod() {\n\t\t\treturn this.method;\n\t\t}\n\n\t\t/**\n\t\t * Return the URI requested.\n\t\t * @return the URI\n\t\t */\n\t\tpublic URI getUri() {\n\t\t\treturn this.uri;\n\t\t}\n\n\t\t/**\n\t\t * Return the request headers.\n\t\t * @return the request headers\n\t\t */\n\t\tpublic Map<String, List<String>> getHeaders() {\n\t\t\treturn this.headers;\n\t\t}\n\n\t\t/**\n\t\t * Return the remote address that made the request.\n\t\t * @return the remote address\n\t\t */\n\t\tpublic @Nullable String getRemoteAddress() {\n\t\t\treturn this.remoteAddress;\n\t\t}\n\n\t}\n\n\t/**\n\t * The response that finished the exchange.\n\t */\n\tpublic static final class Response {\n\n\t\tprivate final int status;\n\n\t\tprivate final Map<String, List<String>> headers;\n\n\t\tprivate Response(RecordableHttpResponse request, Set<Include> includes) {\n\t\t\tthis.status = request.getStatus();\n\t\t\tthis.headers = Collections.unmodifiableMap(filterHeaders(request.getHeaders(), includes));\n\t\t}\n\n\t\t/**\n\t\t * Creates a fully-configured {@code Response} instance. Primarily for use by\n\t\t * {@link HttpExchangeRepository} implementations when recreating a response from\n\t\t * a persistent store.\n\t\t * @param status the status of the response\n\t\t * @param headers the response headers\n\t\t */\n\t\tpublic Response(int status, Map<String, List<String>> headers) {\n\t\t\tthis.status = status;\n\t\t\tthis.headers = Collections.unmodifiableMap(new LinkedHashMap<>(headers));\n\t\t}\n\n\t\tprivate Map<String, List<String>> filterHeaders(Map<String, List<String>> headers, Set<Include> includes) {\n\t\t\tHeadersFilter filter = new HeadersFilter(includes, Include.RESPONSE_HEADERS);\n\t\t\tfilter.excludeUnless(HttpHeaders.SET_COOKIE, Include.COOKIE_HEADERS);\n\t\t\treturn filter.apply(headers);\n\t\t}\n\n\t\t/**\n\t\t * Return the status code of the response.\n\t\t * @return the response status code\n\t\t */\n\t\tpublic int getStatus() {\n\t\t\treturn this.status;\n\t\t}\n\n\t\t/**\n\t\t * Return the response headers.\n\t\t * @return the headers\n\t\t */\n\t\tpublic Map<String, List<String>> getHeaders() {\n\t\t\treturn this.headers;\n\t\t}\n\n\t}\n\n\t/**\n\t * The session associated with the exchange.\n\t */\n\tpublic static final class Session {\n\n\t\tprivate final String id;\n\n\t\t/**\n\t\t * Creates a {@code Session}. Primarily for use by {@link HttpExchangeRepository}\n\t\t * implementations when recreating a session from a persistent store.\n\t\t * @param id the session id\n\t\t */\n\t\tpublic Session(String id) {\n\t\t\tthis.id = id;\n\t\t}\n\n\t\t/**\n\t\t * Return the ID of the session.\n\t\t * @return the session ID\n\t\t */\n\t\tpublic String getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t\tstatic @Nullable Session from(Supplier<@Nullable String> sessionIdSupplier) {\n\t\t\tString id = sessionIdSupplier.get();\n\t\t\treturn (id != null) ? new Session(id) : null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Principal associated with an HTTP request-response exchange.\n\t */\n\tpublic static final class Principal {\n\n\t\tprivate final String name;\n\n\t\t/**\n\t\t * Creates a {@code Principal}. Primarily for use by {@link Principal}\n\t\t * implementations when recreating a response from a persistent store.\n\t\t * @param name the name of the principal\n\t\t */\n\t\tpublic Principal(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t/**\n\t\t * Return the name of the principal.\n\t\t * @return the principal name\n\t\t */\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tstatic @Nullable Principal from(Supplier<java.security.@Nullable Principal> principalSupplier) {\n\t\t\tjava.security.Principal principal = principalSupplier.get();\n\t\t\treturn (principal != null) ? new Principal(principal.getName()) : null;\n\t\t}\n\n\t}\n\n\t/**\n\t * Utility class used to filter headers.\n\t */\n\tprivate static class HeadersFilter {\n\n\t\tprivate final Set<Include> includes;\n\n\t\tprivate final Include requiredInclude;\n\n\t\tprivate final Set<String> filteredHeaderNames;\n\n\t\tHeadersFilter(Set<Include> includes, Include requiredInclude) {\n\t\t\tthis.includes = includes;\n\t\t\tthis.requiredInclude = requiredInclude;\n\t\t\tthis.filteredHeaderNames = new HashSet<>();\n\t\t}\n\n\t\tvoid excludeUnless(String header, Include exception) {\n\t\t\tif (!this.includes.contains(exception)) {\n\t\t\t\tthis.filteredHeaderNames.add(header.toLowerCase(Locale.ROOT));\n\t\t\t}\n\t\t}\n\n\t\tMap<String, List<String>> apply(Map<String, List<String>> headers) {\n\t\t\tif (!this.includes.contains(this.requiredInclude)) {\n\t\t\t\treturn Collections.emptyMap();\n\t\t\t}\n\t\t\tMap<String, List<String>> filtered = new LinkedHashMap<>();\n\t\t\theaders.forEach((name, value) -> {\n\t\t\t\tif (!this.filteredHeaderNames.contains(name.toLowerCase(Locale.ROOT))) {\n\t\t\t\t\tfiltered.put(name, value);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn filtered;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchangeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.util.List;\n\n/**\n * A repository for {@link HttpExchange} instances.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 3.0.0\n */\npublic interface HttpExchangeRepository {\n\n\t/**\n\t * Find all {@link HttpExchange} instances contained in the repository.\n\t * @return all contained HTTP exchanges\n\t */\n\tList<HttpExchange> findAll();\n\n\t/**\n\t * Adds an {@link HttpExchange} instance to the repository.\n\t * @param httpExchange the HTTP exchange to add\n\t */\n\tvoid add(HttpExchange httpExchange);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/HttpExchangesEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose {@link HttpExchange} information.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 3.0.0\n */\n@Endpoint(id = \"httpexchanges\")\npublic class HttpExchangesEndpoint {\n\n\tprivate final HttpExchangeRepository repository;\n\n\t/**\n\t * Create a new {@link HttpExchangesEndpoint} instance.\n\t * @param repository the exchange repository\n\t */\n\tpublic HttpExchangesEndpoint(HttpExchangeRepository repository) {\n\t\tAssert.notNull(repository, \"'repository' must not be null\");\n\t\tthis.repository = repository;\n\t}\n\n\t@ReadOperation\n\tpublic HttpExchangesDescriptor httpExchanges() {\n\t\treturn new HttpExchangesDescriptor(this.repository.findAll());\n\t}\n\n\t/**\n\t * Description of an application's {@link HttpExchange} entries.\n\t */\n\tpublic static final class HttpExchangesDescriptor implements OperationResponseBody {\n\n\t\tprivate final List<HttpExchange> exchanges;\n\n\t\tprivate HttpExchangesDescriptor(List<HttpExchange> exchanges) {\n\t\t\tthis.exchanges = exchanges;\n\t\t}\n\n\t\tpublic List<HttpExchange> getExchanges() {\n\t\t\treturn this.exchanges;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/InMemoryHttpExchangeRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * In-memory implementation of {@link HttpExchangeRepository}.\n *\n * @author Dave Syer\n * @author Olivier Bourgain\n * @since 3.0.0\n */\npublic class InMemoryHttpExchangeRepository implements HttpExchangeRepository {\n\n\tprivate int capacity = 100;\n\n\tprivate boolean reverse = true;\n\n\tprivate final List<HttpExchange> httpExchanges = new LinkedList<>();\n\n\t/**\n\t * Flag to say that the repository lists exchanges in reverse order.\n\t * @param reverse flag value (default true)\n\t */\n\tpublic void setReverse(boolean reverse) {\n\t\tsynchronized (this.httpExchanges) {\n\t\t\tthis.reverse = reverse;\n\t\t}\n\t}\n\n\t/**\n\t * Set the capacity of the in-memory repository.\n\t * @param capacity the capacity\n\t */\n\tpublic void setCapacity(int capacity) {\n\t\tsynchronized (this.httpExchanges) {\n\t\t\tthis.capacity = capacity;\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<HttpExchange> findAll() {\n\t\tsynchronized (this.httpExchanges) {\n\t\t\treturn List.copyOf(this.httpExchanges);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void add(HttpExchange exchange) {\n\t\tsynchronized (this.httpExchanges) {\n\t\t\twhile (this.httpExchanges.size() >= this.capacity) {\n\t\t\t\tthis.httpExchanges.remove(this.reverse ? this.capacity - 1 : 0);\n\t\t\t}\n\t\t\tif (this.reverse) {\n\t\t\t\tthis.httpExchanges.add(0, exchange);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.httpExchanges.add(exchange);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/Include.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\n/**\n * Include options for HTTP exchanges.\n *\n * @author Wallace Wadge\n * @author Emily Tsanova\n * @author Joseph Beeton\n * @since 3.0.0\n */\npublic enum Include {\n\n\t/**\n\t * Include request headers.\n\t */\n\tREQUEST_HEADERS,\n\n\t/**\n\t * Include the remote address from the request.\n\t */\n\tREMOTE_ADDRESS,\n\n\t/**\n\t * Include \"Cookie\" header (if any) in request headers and \"Set-Cookie\" (if any) in\n\t * response headers.\n\t */\n\tCOOKIE_HEADERS,\n\n\t/**\n\t * Include authorization header (if any).\n\t */\n\tAUTHORIZATION_HEADER,\n\n\t/**\n\t * Include response headers.\n\t */\n\tRESPONSE_HEADERS,\n\n\t/**\n\t * Include the principal.\n\t */\n\tPRINCIPAL,\n\n\t/**\n\t * Include the session ID.\n\t */\n\tSESSION_ID,\n\n\t/**\n\t * Include the time taken to service the request.\n\t */\n\tTIME_TAKEN;\n\n\tprivate static final Set<Include> DEFAULT_INCLUDES;\n\n\tstatic {\n\t\tSet<Include> defaultIncludes = new LinkedHashSet<>();\n\t\tdefaultIncludes.add(Include.TIME_TAKEN);\n\t\tdefaultIncludes.add(Include.REQUEST_HEADERS);\n\t\tdefaultIncludes.add(Include.RESPONSE_HEADERS);\n\t\tDEFAULT_INCLUDES = Collections.unmodifiableSet(defaultIncludes);\n\t}\n\n\t/**\n\t * Return the default {@link Include}.\n\t * @return the default include.\n\t */\n\tpublic static Set<Include> defaultIncludes() {\n\t\treturn DEFAULT_INCLUDES;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/RecordableHttpRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.net.URI;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * The recordable parts of an HTTP request used when creating an {@link HttpExchange}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.0.0\n * @see RecordableHttpResponse\n */\npublic interface RecordableHttpRequest {\n\n\t/**\n\t * Returns the URI of the request.\n\t * @return the URI\n\t */\n\tURI getUri();\n\n\t/**\n\t * Returns the remote address from which the request was sent, if available.\n\t * @return the remote address or {@code null}\n\t */\n\t@Nullable String getRemoteAddress();\n\n\t/**\n\t * Returns the method (GET, POST, etc.) of the request.\n\t * @return the method\n\t */\n\tString getMethod();\n\n\t/**\n\t * Returns a modifiable copy of the headers of the request.\n\t * @return the headers\n\t */\n\tMap<String, List<String>> getHeaders();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/RecordableHttpResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * The recordable parts of an HTTP response used when creating an {@link HttpExchange}.\n *\n * @author Andy Wilkinson\n * @since 3.0.0\n * @see RecordableHttpRequest\n */\npublic interface RecordableHttpResponse {\n\n\t/**\n\t * The status of the response.\n\t * @return the status\n\t */\n\tint getStatus();\n\n\t/**\n\t * Returns a modifiable copy of the headers of the response.\n\t * @return the headers\n\t */\n\tMap<String, List<String>> getHeaders();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/exchanges/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator HTTP exchanges support.\n *\n * @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository\n */\n@NullMarked\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/HandlerMethodDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.mappings;\n\nimport org.springframework.asm.Type;\nimport org.springframework.web.method.HandlerMethod;\n\n/**\n * A description of a {@link HandlerMethod}.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class HandlerMethodDescription {\n\n\tprivate final String className;\n\n\tprivate final String name;\n\n\tprivate final String descriptor;\n\n\tpublic HandlerMethodDescription(HandlerMethod handlerMethod) {\n\t\tthis.name = handlerMethod.getMethod().getName();\n\t\tthis.className = handlerMethod.getMethod().getDeclaringClass().getCanonicalName();\n\t\tthis.descriptor = Type.getMethodDescriptor(handlerMethod.getMethod());\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getDescriptor() {\n\t\treturn this.descriptor;\n\t}\n\n\tpublic String getClassName() {\n\t\treturn this.className;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/MappingDescriptionProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.mappings;\n\nimport java.util.List;\n\nimport org.springframework.context.ApplicationContext;\n\n/**\n * A {@link MappingDescriptionProvider} provides a {@link List} of mapping descriptions\n * through implementation-specific introspection of an application context.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic interface MappingDescriptionProvider {\n\n\t/**\n\t * Returns the name of the mappings described by this provider.\n\t * @return the name of the mappings\n\t */\n\tString getMappingName();\n\n\t/**\n\t * Produce the descriptions of the mappings identified by this provider in the given\n\t * {@code context}.\n\t * @param context the application context to introspect\n\t * @return the mapping descriptions\n\t */\n\tObject describeMappings(ApplicationContext context);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/MappingsEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.mappings;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * {@link Endpoint @Endpoint} to expose HTTP request mappings.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Endpoint(id = \"mappings\")\npublic class MappingsEndpoint {\n\n\tprivate final Collection<MappingDescriptionProvider> descriptionProviders;\n\n\tprivate final ApplicationContext context;\n\n\tpublic MappingsEndpoint(Collection<MappingDescriptionProvider> descriptionProviders, ApplicationContext context) {\n\t\tthis.descriptionProviders = descriptionProviders;\n\t\tthis.context = context;\n\t}\n\n\t@ReadOperation\n\tpublic ApplicationMappingsDescriptor mappings() {\n\t\tApplicationContext target = this.context;\n\t\tMap<@Nullable String, ContextMappingsDescriptor> contextMappings = new HashMap<>();\n\t\twhile (target != null) {\n\t\t\tcontextMappings.put(target.getId(), mappingsForContext(target));\n\t\t\ttarget = target.getParent();\n\t\t}\n\t\treturn new ApplicationMappingsDescriptor(contextMappings);\n\t}\n\n\tprivate ContextMappingsDescriptor mappingsForContext(ApplicationContext applicationContext) {\n\t\tMap<String, Object> mappings = new HashMap<>();\n\t\tthis.descriptionProviders.forEach(\n\t\t\t\t(provider) -> mappings.put(provider.getMappingName(), provider.describeMappings(applicationContext)));\n\t\treturn new ContextMappingsDescriptor(mappings,\n\t\t\t\t(applicationContext.getParent() != null) ? applicationContext.getId() : null);\n\t}\n\n\t/**\n\t * Description of an application's request mappings.\n\t */\n\tpublic static final class ApplicationMappingsDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<@Nullable String, ContextMappingsDescriptor> contextMappings;\n\n\t\tprivate ApplicationMappingsDescriptor(Map<@Nullable String, ContextMappingsDescriptor> contextMappings) {\n\t\t\tthis.contextMappings = contextMappings;\n\t\t}\n\n\t\tpublic Map<@Nullable String, ContextMappingsDescriptor> getContexts() {\n\t\t\treturn this.contextMappings;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an application context's request mappings.\n\t */\n\tpublic static final class ContextMappingsDescriptor {\n\n\t\tprivate final Map<String, Object> mappings;\n\n\t\tprivate final @Nullable String parentId;\n\n\t\tprivate ContextMappingsDescriptor(Map<String, Object> mappings, @Nullable String parentId) {\n\t\t\tthis.mappings = mappings;\n\t\t\tthis.parentId = parentId;\n\t\t}\n\n\t\tpublic @Nullable String getParentId() {\n\t\t\treturn this.parentId;\n\t\t}\n\n\t\tpublic Map<String, Object> getMappings() {\n\t\t\treturn this.mappings;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator web request mappings support.\n */\n@NullMarked\npackage org.springframework.boot.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.endpoints.migrate-legacy-ids\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to transparently migrate legacy endpoint IDs.\",\n      \"defaultValue\": false\n    }\n  ],\n  \"hints\": []\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/audit/AuditEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.util.Collections;\n\nimport org.json.JSONObject;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AuditEvent}.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n */\nclass AuditEventTests {\n\n\t@Test\n\tvoid nowEvent() {\n\t\tAuditEvent event = new AuditEvent(\"phil\", \"UNKNOWN\", Collections.singletonMap(\"a\", \"b\"));\n\t\tassertThat(event.getData()).containsEntry(\"a\", \"b\");\n\t\tassertThat(event.getType()).isEqualTo(\"UNKNOWN\");\n\t\tassertThat(event.getPrincipal()).isEqualTo(\"phil\");\n\t\tassertThat(event.getTimestamp()).isNotNull();\n\t}\n\n\t@Test\n\tvoid convertStringsToData() {\n\t\tAuditEvent event = new AuditEvent(\"phil\", \"UNKNOWN\", \"a=b\", \"c=d\");\n\t\tassertThat(event.getData()).containsEntry(\"a\", \"b\");\n\t\tassertThat(event.getData()).containsEntry(\"c\", \"d\");\n\t}\n\n\t@Test\n\tvoid nullPrincipalIsMappedToEmptyString() {\n\t\tAuditEvent auditEvent = new AuditEvent(null, \"UNKNOWN\", Collections.singletonMap(\"a\", \"b\"));\n\t\tassertThat(auditEvent.getPrincipal()).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullTimestamp() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new AuditEvent(null, \"phil\", \"UNKNOWN\", Collections.singletonMap(\"a\", \"b\")))\n\t\t\t.withMessageContaining(\"'timestamp' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nullType() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new AuditEvent(\"phil\", null, Collections.singletonMap(\"a\", \"b\")))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid jsonFormat() throws Exception {\n\t\tAuditEvent event = new AuditEvent(\"johannes\", \"UNKNOWN\",\n\t\t\t\tCollections.singletonMap(\"type\", (Object) \"BadCredentials\"));\n\t\tString json = new JsonMapper().writeValueAsString(event);\n\t\tJSONObject jsonObject = new JSONObject(json);\n\t\tassertThat(jsonObject.getString(\"type\")).isEqualTo(\"UNKNOWN\");\n\t\tassertThat(jsonObject.getJSONObject(\"data\").getString(\"type\")).isEqualTo(\"BadCredentials\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/audit/AuditEventsEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.time.OffsetDateTime;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AuditEventsEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass AuditEventsEndpointTests {\n\n\tprivate final AuditEventRepository repository = mock(AuditEventRepository.class);\n\n\tprivate final AuditEventsEndpoint endpoint = new AuditEventsEndpoint(this.repository);\n\n\tprivate final AuditEvent event = new AuditEvent(\"principal\", \"type\", Collections.singletonMap(\"a\", \"alpha\"));\n\n\t@Test\n\tvoid eventsWithType() {\n\t\tgiven(this.repository.find(null, null, \"type\")).willReturn(Collections.singletonList(this.event));\n\t\tList<AuditEvent> result = this.endpoint.events(null, null, \"type\").getEvents();\n\t\tassertThat(result).isEqualTo(Collections.singletonList(this.event));\n\t}\n\n\t@Test\n\tvoid eventsCreatedAfter() {\n\t\tOffsetDateTime now = OffsetDateTime.now();\n\t\tgiven(this.repository.find(null, now.toInstant(), null)).willReturn(Collections.singletonList(this.event));\n\t\tList<AuditEvent> result = this.endpoint.events(null, now, null).getEvents();\n\t\tassertThat(result).isEqualTo(Collections.singletonList(this.event));\n\t}\n\n\t@Test\n\tvoid eventsWithPrincipal() {\n\t\tgiven(this.repository.find(\"Joan\", null, null)).willReturn(Collections.singletonList(this.event));\n\t\tList<AuditEvent> result = this.endpoint.events(\"Joan\", null, null).getEvents();\n\t\tassertThat(result).isEqualTo(Collections.singletonList(this.event));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/audit/InMemoryAuditEventRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit;\n\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link InMemoryAuditEventRepository}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Vedran Pavic\n */\nclass InMemoryAuditEventRepositoryTests {\n\n\t@Test\n\tvoid lessThanCapacity() {\n\t\tInMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();\n\t\trepository.add(new AuditEvent(\"dave\", \"a\"));\n\t\trepository.add(new AuditEvent(\"dave\", \"b\"));\n\t\tList<AuditEvent> events = repository.find(\"dave\", null, null);\n\t\tassertThat(events).hasSize(2);\n\t\tassertThat(events.get(0).getType()).isEqualTo(\"a\");\n\t\tassertThat(events.get(1).getType()).isEqualTo(\"b\");\n\t}\n\n\t@Test\n\tvoid capacity() {\n\t\tInMemoryAuditEventRepository repository = new InMemoryAuditEventRepository(2);\n\t\trepository.add(new AuditEvent(\"dave\", \"a\"));\n\t\trepository.add(new AuditEvent(\"dave\", \"b\"));\n\t\trepository.add(new AuditEvent(\"dave\", \"c\"));\n\t\tList<AuditEvent> events = repository.find(\"dave\", null, null);\n\t\tassertThat(events).hasSize(2);\n\t\tassertThat(events.get(0).getType()).isEqualTo(\"b\");\n\t\tassertThat(events.get(1).getType()).isEqualTo(\"c\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullAuditEvent() {\n\t\tInMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> repository.add(null))\n\t\t\t.withMessageContaining(\"'event' must not be null\");\n\t}\n\n\t@Test\n\tvoid findByPrincipal() {\n\t\tInMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();\n\t\trepository.add(new AuditEvent(\"dave\", \"a\"));\n\t\trepository.add(new AuditEvent(\"phil\", \"b\"));\n\t\trepository.add(new AuditEvent(\"dave\", \"c\"));\n\t\trepository.add(new AuditEvent(\"phil\", \"d\"));\n\t\tList<AuditEvent> events = repository.find(\"dave\", null, null);\n\t\tassertThat(events).hasSize(2);\n\t\tassertThat(events.get(0).getType()).isEqualTo(\"a\");\n\t\tassertThat(events.get(1).getType()).isEqualTo(\"c\");\n\t}\n\n\t@Test\n\tvoid findByPrincipalAndType() {\n\t\tInMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();\n\t\trepository.add(new AuditEvent(\"dave\", \"a\"));\n\t\trepository.add(new AuditEvent(\"phil\", \"b\"));\n\t\trepository.add(new AuditEvent(\"dave\", \"c\"));\n\t\trepository.add(new AuditEvent(\"phil\", \"d\"));\n\t\tList<AuditEvent> events = repository.find(\"dave\", null, \"a\");\n\t\tassertThat(events).hasSize(1);\n\t\tassertThat(events.get(0).getPrincipal()).isEqualTo(\"dave\");\n\t\tassertThat(events.get(0).getType()).isEqualTo(\"a\");\n\t}\n\n\t@Test\n\tvoid findByDate() {\n\t\tInstant instant = Instant.now();\n\t\tMap<String, @Nullable Object> data = new HashMap<>();\n\t\tInMemoryAuditEventRepository repository = new InMemoryAuditEventRepository();\n\t\trepository.add(new AuditEvent(instant, \"dave\", \"a\", data));\n\t\trepository.add(new AuditEvent(instant.plus(1, ChronoUnit.DAYS), \"phil\", \"b\", data));\n\t\trepository.add(new AuditEvent(instant.plus(2, ChronoUnit.DAYS), \"dave\", \"c\", data));\n\t\trepository.add(new AuditEvent(instant.plus(3, ChronoUnit.DAYS), \"phil\", \"d\", data));\n\t\tInstant after = instant.plus(1, ChronoUnit.DAYS);\n\t\tList<AuditEvent> events = repository.find(null, after, null);\n\t\tassertThat(events).hasSize(2);\n\t\tassertThat(events.get(0).getType()).isEqualTo(\"c\");\n\t\tassertThat(events.get(1).getType()).isEqualTo(\"d\");\n\t\tevents = repository.find(\"dave\", after, null);\n\t\tassertThat(events).hasSize(1);\n\t\tassertThat(events.get(0).getType()).isEqualTo(\"c\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/audit/listener/AuditListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.audit.listener;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.AuditEventRepository;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AuditListener}.\n *\n * @author Phillip Webb\n */\nclass AuditListenerTests {\n\n\t@Test\n\tvoid testStoredEvents() {\n\t\tAuditEventRepository repository = mock(AuditEventRepository.class);\n\t\tAuditEvent event = new AuditEvent(\"principal\", \"type\", Collections.emptyMap());\n\t\tAuditListener listener = new AuditListener(repository);\n\t\tlistener.onApplicationEvent(new AuditApplicationEvent(event));\n\t\tthen(repository).should().add(event);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/beans/BeansEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.beans;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.actuate.beans.BeansEndpoint.BeanDescriptor;\nimport org.springframework.boot.actuate.beans.BeansEndpoint.BeansDescriptor;\nimport org.springframework.boot.actuate.beans.BeansEndpoint.ContextBeansDescriptor;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Lazy;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BeansEndpoint}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass BeansEndpointTests {\n\n\t@Test\n\tvoid beansAreFound() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfiguration.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tBeansDescriptor result = context.getBean(BeansEndpoint.class).beans();\n\t\t\tContextBeansDescriptor descriptor = result.getContexts().get(context.getId());\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getParentId()).isNull();\n\t\t\tMap<String, BeanDescriptor> beans = descriptor.getBeans();\n\t\t\tassertThat(beans).hasSizeLessThanOrEqualTo(context.getBeanDefinitionCount());\n\t\t\tassertThat(beans).containsKey(\"endpoint\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid infrastructureBeansAreOmitted() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfiguration.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) context\n\t\t\t\t.getAutowireCapableBeanFactory();\n\t\t\tList<String> infrastructureBeans = Stream.of(context.getBeanDefinitionNames())\n\t\t\t\t.filter((name) -> BeanDefinition.ROLE_INFRASTRUCTURE == factory.getBeanDefinition(name).getRole())\n\t\t\t\t.toList();\n\t\t\tBeansDescriptor result = context.getBean(BeansEndpoint.class).beans();\n\t\t\tContextBeansDescriptor contextDescriptor = result.getContexts().get(context.getId());\n\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\tMap<String, BeanDescriptor> beans = contextDescriptor.getBeans();\n\t\t\tfor (String infrastructureBean : infrastructureBeans) {\n\t\t\t\tassertThat(beans).doesNotContainKey(infrastructureBean);\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid lazyBeansAreOmitted() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfiguration.class, LazyBeanConfiguration.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tBeansDescriptor result = context.getBean(BeansEndpoint.class).beans();\n\t\t\tassertThat(context).hasBean(\"lazyBean\");\n\t\t\tContextBeansDescriptor contextDescriptor = result.getContexts().get(context.getId());\n\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\tassertThat(contextDescriptor.getBeans()).doesNotContainKey(\"lazyBean\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid beansInParentContextAreFound() {\n\t\tApplicationContextRunner parentRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(BeanConfiguration.class);\n\t\tparentRunner.run((parent) -> {\n\t\t\tnew ApplicationContextRunner().withUserConfiguration(EndpointConfiguration.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tBeansDescriptor result = child.getBean(BeansEndpoint.class).beans();\n\t\t\t\t\tContextBeansDescriptor parentContext = result.getContexts().get(parent.getId());\n\t\t\t\t\tassertThat(parentContext).isNotNull();\n\t\t\t\t\tassertThat(parentContext.getBeans()).containsKey(\"bean\");\n\t\t\t\t\tContextBeansDescriptor childContext = result.getContexts().get(child.getId());\n\t\t\t\t\tassertThat(childContext).isNotNull();\n\t\t\t\t\tassertThat(childContext.getBeans()).containsKey(\"endpoint\");\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfiguration {\n\n\t\t@Bean\n\t\tBeansEndpoint endpoint(ConfigurableApplicationContext context) {\n\t\t\treturn new BeansEndpoint(context);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BeanConfiguration {\n\n\t\t@Bean\n\t\tString bean() {\n\t\t\treturn \"bean\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LazyBeanConfiguration {\n\n\t\t@Lazy\n\t\t@Bean\n\t\tString lazyBean() {\n\t\t\treturn \"lazyBean\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/ShutdownEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.context.ShutdownEndpoint.ShutdownDescriptor;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.ContextClosedEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ShutdownEndpoint}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass ShutdownEndpointTests {\n\n\t@Test\n\tvoid shutdown() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfig.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tEndpointConfig config = context.getBean(EndpointConfig.class);\n\t\t\tClassLoader previousTccl = Thread.currentThread().getContextClassLoader();\n\t\t\tShutdownDescriptor result;\n\t\t\tThread.currentThread().setContextClassLoader(new URLClassLoader(new URL[0], getClass().getClassLoader()));\n\t\t\ttry {\n\t\t\t\tresult = context.getBean(ShutdownEndpoint.class).shutdown();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tThread.currentThread().setContextClassLoader(previousTccl);\n\t\t\t}\n\t\t\tassertThat(result.getMessage()).startsWith(\"Shutting down\");\n\t\t\tassertThat(context.isActive()).isTrue();\n\t\t\tassertThat(config.latch.await(10, TimeUnit.SECONDS)).isTrue();\n\t\t\tassertThat(config.threadContextClassLoader).isEqualTo(getClass().getClassLoader());\n\t\t});\n\t}\n\n\t@Test\n\tvoid shutdownChild() throws Exception {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(EmptyConfig.class)\n\t\t\t.child(EndpointConfig.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.run();\n\t\tCountDownLatch latch = context.getBean(EndpointConfig.class).latch;\n\t\tassertThat(context.getBean(ShutdownEndpoint.class).shutdown().getMessage()).startsWith(\"Shutting down\");\n\t\tassertThat(context.isActive()).isTrue();\n\t\tassertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();\n\t}\n\n\t@Test\n\tvoid shutdownParent() throws Exception {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(EndpointConfig.class)\n\t\t\t.child(EmptyConfig.class)\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.run();\n\t\tCountDownLatch parentLatch = context.getBean(EndpointConfig.class).latch;\n\t\tCountDownLatch childLatch = context.getBean(EmptyConfig.class).latch;\n\t\tassertThat(context.getBean(ShutdownEndpoint.class).shutdown().getMessage()).startsWith(\"Shutting down\");\n\t\tassertThat(context.isActive()).isTrue();\n\t\tassertThat(parentLatch.await(10, TimeUnit.SECONDS)).isTrue();\n\t\tassertThat(childLatch.await(10, TimeUnit.SECONDS)).isTrue();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfig {\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate volatile @Nullable ClassLoader threadContextClassLoader;\n\n\t\t@Bean\n\t\tShutdownEndpoint endpoint() {\n\t\t\treturn new ShutdownEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tApplicationListener<ContextClosedEvent> listener() {\n\t\t\treturn (event) -> {\n\t\t\t\tEndpointConfig.this.threadContextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\t\t\tEndpointConfig.this.latch.countDown();\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfig {\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\t@Bean\n\t\tApplicationListener<ContextClosedEvent> listener() {\n\t\t\treturn (event) -> EmptyConfig.this.latch.countDown();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointFilteringTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Collections;\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpoint} when filtering by prefix.\n *\n * @author Chris Bono\n */\nclass ConfigurationPropertiesReportEndpointFilteringTests {\n\n\t@Test\n\tvoid filterByPrefixSingleMatch() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"foo.primary.name:foo1\", \"foo.secondary.name:foo2\", \"only.bar.name:solo1\");\n\t\tassertProperties(contextRunner, \"solo1\");\n\t}\n\n\t@Test\n\tvoid filterByPrefixMultipleMatches() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"foo.primary.name:foo1\", \"foo.secondary.name:foo2\", \"only.bar.name:solo1\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint\n\t\t\t\t.configurationPropertiesWithPrefix(\"foo.\");\n\t\t\tassertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());\n\t\t\tContextConfigurationPropertiesDescriptor contextProperties = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextProperties).isNotNull();\n\t\t\tassertThat(contextProperties.getBeans()).containsOnlyKeys(\"primaryFoo\", \"secondaryFoo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid filterByPrefixNoMatches() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"foo.primary.name:foo1\", \"foo.secondary.name:foo2\", \"only.bar.name:solo1\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint\n\t\t\t\t.configurationPropertiesWithPrefix(\"foo.third\");\n\t\t\tassertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());\n\t\t\tContextConfigurationPropertiesDescriptor contextProperties = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextProperties).isNotNull();\n\t\t\tassertThat(contextProperties.getBeans()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid noSanitizationWhenShowAlways() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(ConfigWithAlways.class)\n\t\t\t.withPropertyValues(\"foo.primary.name:foo1\", \"foo.secondary.name:foo2\", \"only.bar.name:solo1\");\n\t\tassertProperties(contextRunner, \"solo1\");\n\t}\n\n\t@Test\n\tvoid sanitizationWhenShowNever() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(ConfigWithNever.class)\n\t\t\t.withPropertyValues(\"foo.primary.name:foo1\", \"foo.secondary.name:foo2\", \"only.bar.name:solo1\");\n\t\tassertProperties(contextRunner, \"******\");\n\t}\n\n\tprivate void assertProperties(ApplicationContextRunner contextRunner, String value) {\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint\n\t\t\t\t.configurationPropertiesWithPrefix(\"only.bar\");\n\t\t\tassertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());\n\t\t\tContextConfigurationPropertiesDescriptor contextProperties = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextProperties).isNotNull();\n\t\t\tOptional<String> key = contextProperties.getBeans()\n\t\t\t\t.keySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((id) -> findIdFromPrefix(\"only.bar\", id))\n\t\t\t\t.findAny();\n\t\t\tConfigurationPropertiesBeanDescriptor descriptor = contextProperties.getBeans().get(key.get());\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getPrefix()).isEqualTo(\"only.bar\");\n\t\t\tassertThat(descriptor.getProperties()).containsEntry(\"name\", value);\n\t\t});\n\t}\n\n\tprivate boolean findIdFromPrefix(String prefix, String id) {\n\t\tint separator = id.indexOf(\"-\");\n\t\tString candidate = (separator != -1) ? id.substring(0, separator) : id;\n\t\treturn prefix.equals(candidate);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\t@EnableConfigurationProperties(Bar.class)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.WHEN_AUTHORIZED);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\t@EnableConfigurationProperties(Bar.class)\n\tstatic class ConfigWithNever {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.NEVER);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\t@EnableConfigurationProperties(Bar.class)\n\tstatic class ConfigWithAlways {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(Bar.class)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo.primary\")\n\t\tFoo primaryFoo() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo.secondary\")\n\t\tFoo secondaryFoo() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name = \"5150\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"only.bar\")\n\tpublic static class Bar {\n\n\t\tprivate String name = \"123456\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointMethodAnnotationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpoint} when used with bean methods.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesReportEndpointMethodAnnotationsTests {\n\n\t@Test\n\tvoid testNaming() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"other.name:foo\", \"first.name:bar\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tassertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());\n\t\t\tContextConfigurationPropertiesDescriptor contextProperties = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextProperties).isNotNull();\n\t\t\tConfigurationPropertiesBeanDescriptor other = contextProperties.getBeans().get(\"other\");\n\t\t\tassertThat(other).isNotNull();\n\t\t\tassertThat(other.getPrefix()).isEqualTo(\"other\");\n\t\t\tassertThat(other.getProperties()).isNotNull();\n\t\t\tassertThat(other.getProperties()).isNotEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid prefixFromBeanMethodConfigurationPropertiesCanOverridePrefixOnClass() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(OverriddenPrefix.class)\n\t\t\t.withPropertyValues(\"other.name:foo\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tassertThat(applicationProperties.getContexts()).containsOnlyKeys(context.getId());\n\t\t\tContextConfigurationPropertiesDescriptor contextProperties = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextProperties).isNotNull();\n\t\t\tConfigurationPropertiesBeanDescriptor bar = contextProperties.getBeans().get(\"bar\");\n\t\t\tassertThat(bar).isNotNull();\n\t\t\tassertThat(bar.getPrefix()).isEqualTo(\"other\");\n\t\t\tassertThat(bar.getProperties()).isNotNull();\n\t\t\tassertThat(bar.getProperties()).isNotEmpty();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class Config {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"first\")\n\t\tFoo foo() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"other\")\n\t\tFoo other() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class OverriddenPrefix {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"other\")\n\t\tBar bar() {\n\t\t\treturn new Bar();\n\t\t}\n\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name = \"654321\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tpublic static class Bar {\n\n\t\tprivate String name = \"654321\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointParentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpoint} when used with a parent\n * context.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesReportEndpointParentTests {\n\n\t@Test\n\tvoid configurationPropertiesClass() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(Parent.class).run((parent) -> {\n\t\t\tnew ApplicationContextRunner().withUserConfiguration(ClassConfigurationProperties.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tConfigurationPropertiesReportEndpoint endpoint = child\n\t\t\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\t\t\tassertThat(applicationProperties.getContexts()).containsOnlyKeys(child.getId(), parent.getId());\n\t\t\t\t\tContextConfigurationPropertiesDescriptor childContext = applicationProperties.getContexts()\n\t\t\t\t\t\t.get(child.getId());\n\t\t\t\t\tassertThat(childContext).isNotNull();\n\t\t\t\t\tassertThat(childContext.getBeans().keySet()).containsExactly(\"someProperties\");\n\t\t\t\t\tContextConfigurationPropertiesDescriptor parentContext = applicationProperties.getContexts()\n\t\t\t\t\t\t.get(parent.getId());\n\t\t\t\t\tassertThat(parentContext).isNotNull();\n\t\t\t\t\tassertThat((parentContext.getBeans().keySet())).containsExactly(\"testProperties\");\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid configurationPropertiesBeanMethod() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(Parent.class).run((parent) -> {\n\t\t\tnew ApplicationContextRunner().withUserConfiguration(BeanMethodConfigurationProperties.class)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tConfigurationPropertiesReportEndpoint endpoint = child\n\t\t\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\t\t\tContextConfigurationPropertiesDescriptor childContext = applicationProperties.getContexts()\n\t\t\t\t\t\t.get(child.getId());\n\t\t\t\t\tassertThat(childContext).isNotNull();\n\t\t\t\t\tassertThat(childContext.getBeans().keySet()).containsExactlyInAnyOrder(\"otherProperties\");\n\t\t\t\t\tContextConfigurationPropertiesDescriptor parentContext = applicationProperties.getContexts()\n\t\t\t\t\t\t.get(parent.getId());\n\t\t\t\t\tassertThat(parentContext).isNotNull();\n\t\t\t\t\tassertThat((parentContext.getBeans().keySet())).containsExactly(\"testProperties\");\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class Parent {\n\n\t\t@Bean\n\t\tTestProperties testProperties() {\n\t\t\treturn new TestProperties();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class ClassConfigurationProperties {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\tTestProperties someProperties() {\n\t\t\treturn new TestProperties();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class BeanMethodConfigurationProperties {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"other\")\n\t\tOtherProperties otherProperties() {\n\t\t\treturn new OtherProperties();\n\t\t}\n\n\t}\n\n\tstatic class OtherProperties {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tstatic class TestProperties {\n\n\t\tprivate String myTestProperty = \"654321\";\n\n\t\tString getMyTestProperty() {\n\t\t\treturn this.myTestProperty;\n\t\t}\n\n\t\tvoid setMyTestProperty(String myTestProperty) {\n\t\t\tthis.myTestProperty = myTestProperty;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointProxyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpoint} when used against a proxy\n * class.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass ConfigurationPropertiesReportEndpointProxyTests {\n\n\t@Test\n\tvoid testWithProxyClass() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(Config.class,\n\t\t\t\tSqlExecutor.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class)\n\t\t\t\t.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor contextDescriptor = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\tassertThat(contextDescriptor.getBeans()\n\t\t\t\t.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(ConfigurationPropertiesBeanDescriptor::getPrefix)\n\t\t\t\t.filter(\"executor.sql\"::equals)\n\t\t\t\t.findFirst()).isNotEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid proxiedConstructorBoundPropertiesShouldBeAvailableInReport() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(ValidatedConfiguration.class)\n\t\t\t.withPropertyValues(\"validated.name=baz\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class)\n\t\t\t\t.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor contextDescriptor = applicationProperties.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\tMap<String, @Nullable Object> properties = contextDescriptor.getBeans()\n\t\t\t\t.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(ConfigurationPropertiesBeanDescriptor::getProperties)\n\t\t\t\t.findFirst()\n\t\t\t\t.get();\n\t\t\tassertThat(properties).containsEntry(\"name\", \"baz\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableTransactionManagement(proxyTargetClass = false)\n\t@EnableConfigurationProperties\n\tstatic class Config {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager(DataSource dataSource) {\n\t\t\treturn new DataSourceTransactionManager(dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tstatic MethodValidationPostProcessor testPostProcessor() {\n\t\t\treturn new MethodValidationPostProcessor();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build();\n\t\t}\n\n\t}\n\n\tinterface Executor {\n\n\t\tvoid execute();\n\n\t}\n\n\tabstract static class AbstractExecutor implements Executor {\n\n\t}\n\n\t@Component\n\t@ConfigurationProperties(\"executor.sql\")\n\tstatic class SqlExecutor extends AbstractExecutor {\n\n\t\t@Override\n\t\t@Transactional(propagation = Propagation.REQUIRES_NEW)\n\t\tpublic void execute() {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ValidatedConstructorBindingProperties.class)\n\t@Import(Config.class)\n\tstatic class ValidatedConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointSerializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.InetAddress;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBinding;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.io.InputStreamSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpoint} serialization.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass ConfigurationPropertiesReportEndpointSerializationTests {\n\n\t@Test\n\tvoid testNaming() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(FooConfig.class)\n\t\t\t.withPropertyValues(\"foo.name:foo\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor foo = getContextDescriptor(context, applicationProperties).getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tassertThat(foo.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> map = foo.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).hasSize(2);\n\t\t\tassertThat(map).containsEntry(\"name\", \"foo\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testNestedNaming() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(FooConfig.class)\n\t\t\t.withPropertyValues(\"foo.bar.name:foo\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor contextDescriptor = getContextDescriptor(context,\n\t\t\t\t\tapplicationProperties);\n\t\t\tConfigurationPropertiesBeanDescriptor foo = contextDescriptor.getBeans().get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tMap<String, @Nullable Object> map = foo.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).hasSize(2);\n\t\t\tassertThat(((Map<String, Object>) map.get(\"bar\"))).containsEntry(\"name\", \"foo\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testSelfReferentialProperty() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(SelfReferentialConfig.class)\n\t\t\t.withPropertyValues(\"foo.name:foo\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor contextDescriptor = getContextDescriptor(context,\n\t\t\t\t\tapplicationProperties);\n\t\t\tConfigurationPropertiesBeanDescriptor foo = contextDescriptor.getBeans().get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tassertThat(foo.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> map = foo.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).containsOnlyKeys(\"bar\", \"name\");\n\t\t\tassertThat(map).containsEntry(\"name\", \"foo\");\n\t\t\tMap<String, Object> bar = (Map<String, Object>) map.get(\"bar\");\n\t\t\tassertThat(bar).containsOnlyKeys(\"name\");\n\t\t\tassertThat(bar).containsEntry(\"name\", \"123456\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testCycle() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CycleConfig.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor contextDescriptor = getContextDescriptor(context,\n\t\t\t\t\tapplicationProperties);\n\t\t\tConfigurationPropertiesBeanDescriptor cycle = contextDescriptor.getBeans().get(\"cycle\");\n\t\t\tassertThat(cycle).isNotNull();\n\t\t\tassertThat(cycle.getPrefix()).isEqualTo(\"cycle\");\n\t\t\tMap<String, @Nullable Object> map = cycle.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).containsOnlyKeys(\"error\");\n\t\t\tassertThat(map).containsEntry(\"error\", \"Cannot serialize 'cycle'\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testMap() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(MapConfig.class)\n\t\t\t.withPropertyValues(\"foo.map.name:foo\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor fooProperties = getContextDescriptor(context, applicationProperties)\n\t\t\t\t.getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(fooProperties).isNotNull();\n\t\t\tassertThat(fooProperties.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> map = fooProperties.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).hasSize(3);\n\t\t\tassertThat(((Map<String, Object>) map.get(\"map\"))).containsEntry(\"name\", \"foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testEmptyMapIsNotAdded() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(MapConfig.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor foo = getContextDescriptor(context, applicationProperties).getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tassertThat(foo.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> map = foo.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).hasSize(2);\n\t\t\tassertThat(map).doesNotContainKey(\"map\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testList() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withUserConfiguration(ListConfig.class)\n\t\t\t.withPropertyValues(\"foo.list[0]:foo\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor foo = getContextDescriptor(context, applicationProperties).getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tassertThat(foo.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> map = foo.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).hasSize(3);\n\t\t\tList<String> list = (List<String>) map.get(\"list\");\n\t\t\tassertThat(list).first().isEqualTo(\"foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testInetAddress() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(AddressedConfig.class)\n\t\t\t.withPropertyValues(\"foo.address:192.168.1.10\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor foo = getContextDescriptor(context, applicationProperties).getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tassertThat(foo.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> map = foo.getProperties();\n\t\t\tassertThat(map).isNotNull();\n\t\t\tassertThat(map).hasSize(3);\n\t\t\tassertThat(map).containsEntry(\"address\", \"192.168.1.10\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testInitializedMapAndList() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(InitializedMapAndListPropertiesConfig.class)\n\t\t\t.withPropertyValues(\"foo.map.entryOne:true\", \"foo.list[0]:abc\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor foo = getContextDescriptor(context, applicationProperties).getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(foo).isNotNull();\n\t\t\tassertThat(foo.getPrefix()).isEqualTo(\"foo\");\n\t\t\tMap<String, @Nullable Object> propertiesMap = foo.getProperties();\n\t\t\tassertThat(propertiesMap).containsOnlyKeys(\"bar\", \"name\", \"map\", \"list\");\n\t\t\tMap<String, Object> map = (Map<String, Object>) propertiesMap.get(\"map\");\n\t\t\tassertThat(map).containsOnly(entry(\"entryOne\", true));\n\t\t\tList<String> list = (List<String>) propertiesMap.get(\"list\");\n\t\t\tassertThat(list).containsExactly(\"abc\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid hikariDataSourceConfigurationPropertiesBeanCanBeSerialized() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(HikariDataSourceConfig.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor hikariDataSource = getContextDescriptor(context,\n\t\t\t\t\tapplicationProperties)\n\t\t\t\t.getBeans()\n\t\t\t\t.get(\"hikariDataSource\");\n\t\t\tassertThat(hikariDataSource).isNotNull();\n\t\t\tMap<String, @Nullable Object> nestedProperties = hikariDataSource.getProperties();\n\t\t\tassertThat(nestedProperties).doesNotContainKey(\"error\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid endpointResponseUsesToStringOfCharSequenceAsPropertyValue() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withInitializer((context) -> {\n\t\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\t\tenvironment.getPropertySources()\n\t\t\t\t.addFirst(new MapPropertySource(\"test\",\n\t\t\t\t\t\tCollections.singletonMap(\"foo.name\", new CharSequenceProperty(\"Spring Boot\"))));\n\t\t}).withUserConfiguration(FooConfig.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor descriptor = getContextDescriptor(context, applicationProperties)\n\t\t\t\t.getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat((Map<String, Object>) descriptor.getInputs().get(\"name\")).containsEntry(\"value\", \"Spring Boot\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid endpointResponseUsesPlaceholderForComplexValueAsPropertyValue() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner().withInitializer((context) -> {\n\t\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\t\tenvironment.getPropertySources()\n\t\t\t\t.addFirst(new MapPropertySource(\"test\",\n\t\t\t\t\t\tCollections.singletonMap(\"foo.name\", new ComplexProperty(\"Spring Boot\"))));\n\t\t}).withUserConfiguration(ComplexPropertyToStringConverter.class, FooConfig.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor applicationProperties = endpoint.configurationProperties();\n\t\t\tConfigurationPropertiesBeanDescriptor descriptor = getContextDescriptor(context, applicationProperties)\n\t\t\t\t.getBeans()\n\t\t\t\t.get(\"foo\");\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat((Map<String, Object>) descriptor.getInputs().get(\"name\")).containsEntry(\"value\",\n\t\t\t\t\t\"Complex property value \" + ComplexProperty.class.getName());\n\t\t});\n\t}\n\n\tprivate ContextConfigurationPropertiesDescriptor getContextDescriptor(AssertableApplicationContext context,\n\t\t\tConfigurationPropertiesDescriptor applicationProperties) {\n\t\tContextConfigurationPropertiesDescriptor contextDescriptor = applicationProperties.getContexts()\n\t\t\t.get(context.getId());\n\t\tassertThat(contextDescriptor).isNotNull();\n\t\treturn contextDescriptor;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class Base {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class FooConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tFoo foo() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class SelfReferentialConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tSelfReferential foo() {\n\t\t\treturn new SelfReferential();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class MetadataCycleConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"bar\")\n\t\tSelfReferential foo() {\n\t\t\treturn new SelfReferential();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class MapConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tMapHolder foo() {\n\t\t\treturn new MapHolder();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class ListConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tListHolder foo() {\n\t\t\treturn new ListHolder();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class MetadataMapConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spam\")\n\t\tMapHolder foo() {\n\t\t\treturn new MapHolder();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class AddressedConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tAddressed foo() {\n\t\t\treturn new Addressed();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class InitializedMapAndListPropertiesConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"foo\")\n\t\tInitializedMapAndListProperties foo() {\n\t\t\treturn new InitializedMapAndListProperties();\n\t\t}\n\n\t}\n\n\tpublic static class Foo {\n\n\t\tprivate String name = \"654321\";\n\n\t\tprivate Bar bar = new Bar();\n\n\t\tpublic Bar getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t\tpublic void setBar(Bar bar) {\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t// No setter so it doesn't appear in the report\n\t\tpublic String getSummary() {\n\t\t\treturn \"Name: \" + this.name;\n\t\t}\n\n\t\tpublic static class Bar {\n\n\t\t\tprivate String name = \"123456\";\n\n\t\t\tpublic String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic void setName(String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class SelfReferential extends Foo {\n\n\t\tprivate Foo self;\n\n\t\tSelfReferential() {\n\t\t\tthis.self = this;\n\t\t}\n\n\t\tpublic Foo getSelf() {\n\t\t\treturn this.self;\n\t\t}\n\n\t\tpublic void setSelf(Foo self) {\n\t\t\tthis.self = self;\n\t\t}\n\n\t}\n\n\tpublic static class MapHolder extends Foo {\n\n\t\tprivate @Nullable Map<String, Object> map;\n\n\t\tpublic @Nullable Map<String, Object> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tpublic void setMap(@Nullable Map<String, Object> map) {\n\t\t\tthis.map = map;\n\t\t}\n\n\t}\n\n\tpublic static class ListHolder extends Foo {\n\n\t\tprivate @Nullable List<String> list;\n\n\t\tpublic @Nullable List<String> getList() {\n\t\t\treturn this.list;\n\t\t}\n\n\t\tpublic void setList(@Nullable List<String> list) {\n\t\t\tthis.list = list;\n\t\t}\n\n\t}\n\n\tpublic static class Addressed extends Foo {\n\n\t\tprivate @Nullable InetAddress address;\n\n\t\tpublic @Nullable InetAddress getAddress() {\n\t\t\treturn this.address;\n\t\t}\n\n\t\tpublic void setAddress(@Nullable InetAddress address) {\n\t\t\tthis.address = address;\n\t\t}\n\n\t}\n\n\tpublic static class InitializedMapAndListProperties extends Foo {\n\n\t\tprivate final Map<String, Boolean> map = new HashMap<>();\n\n\t\tprivate final List<String> list = new ArrayList<>();\n\n\t\tpublic Map<String, Boolean> getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\tpublic List<String> getList() {\n\t\t\treturn this.list;\n\t\t}\n\n\t}\n\n\tpublic static class Cycle {\n\n\t\tprivate final Alpha alpha = new Alpha(this);\n\n\t\tpublic Alpha getAlpha() {\n\t\t\treturn this.alpha;\n\t\t}\n\n\t\tpublic static class Alpha {\n\n\t\t\tprivate final Cycle cycle;\n\n\t\t\tAlpha(Cycle cycle) {\n\t\t\t\tthis.cycle = cycle;\n\t\t\t}\n\n\t\t\tpublic Cycle getCycle() {\n\t\t\t\treturn this.cycle;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Base.class)\n\tstatic class CycleConfig {\n\n\t\t@Bean\n\t\t// gh-11037\n\t\t@ConfigurationProperties(\"cycle\")\n\t\tCycle cycle() {\n\t\t\treturn new Cycle();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class HikariDataSourceConfig {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\treturn new ConfigurationPropertiesReportEndpoint(Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"test.datasource\")\n\t\tHikariDataSource hikariDataSource() {\n\t\t\treturn new HikariDataSource();\n\t\t}\n\n\t}\n\n\tstatic class CharSequenceProperty implements CharSequence, InputStreamSource {\n\n\t\tprivate final String value;\n\n\t\tCharSequenceProperty(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic int length() {\n\t\t\treturn this.value.length();\n\t\t}\n\n\t\t@Override\n\t\tpublic char charAt(int index) {\n\t\t\treturn this.value.charAt(index);\n\t\t}\n\n\t\t@Override\n\t\tpublic CharSequence subSequence(int start, int end) {\n\t\t\treturn this.value.subSequence(start, end);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\treturn new ByteArrayInputStream(this.value.getBytes());\n\t\t}\n\n\t}\n\n\tstatic class ComplexProperty {\n\n\t\tprivate final String value;\n\n\t\tComplexProperty(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n\t@ConfigurationPropertiesBinding\n\tstatic class ComplexPropertyToStringConverter implements Converter<ComplexProperty, String> {\n\n\t\t@Override\n\t\tpublic String convert(ComplexProperty source) {\n\t\t\treturn source.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.mock.env.MockPropertySource;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpoint}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author HaiTao Zhang\n * @author Chris Bono\n * @author Madhura Bhave\n */\n@SuppressWarnings(\"unchecked\")\nclass ConfigurationPropertiesReportEndpointTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(EndpointConfig.class);\n\n\t@Test\n\tvoid descriptorWithJavaBeanBindMethodDetectsRelevantProperties() {\n\t\tthis.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"test\", (properties) -> assertThat(properties).containsOnlyKeys(\"dbPassword\",\n\t\t\t\t\t\"myTestProperty\", \"duration\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithAutowiredConstructorBindMethodDetectsRelevantProperties() {\n\t\tthis.contextRunner.withUserConfiguration(AutowiredPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"autowired\", (properties) -> assertThat(properties).containsOnlyKeys(\"counter\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithValueObjectBindMethodDetectsRelevantProperties() {\n\t\tthis.contextRunner.withUserConfiguration(ImmutablePropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"immutable\",\n\t\t\t\t\t(properties) -> assertThat(properties).containsOnlyKeys(\"dbPassword\", \"myTestProperty\", \"for\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithValueObjectBindMethodUseDedicatedConstructor() {\n\t\tthis.contextRunner.withUserConfiguration(MultiConstructorPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"multiconstructor\",\n\t\t\t\t\t(properties) -> assertThat(properties).containsOnly(entry(\"name\", \"test\"))));\n\t}\n\n\t@Test\n\tvoid descriptorWithValueObjectBindMethodHandleNestedType() {\n\t\tthis.contextRunner.withPropertyValues(\"immutablenested.nested.name=nested\", \"immutablenested.nested.counter=42\")\n\t\t\t.withUserConfiguration(ImmutableNestedPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"immutablenested\", (properties) -> {\n\t\t\t\tassertThat(properties).containsOnlyKeys(\"name\", \"nested\");\n\t\t\t\tMap<String, Object> nested = (Map<String, Object>) properties.get(\"nested\");\n\t\t\t\tassertThat(nested).containsOnly(entry(\"name\", \"nested\"), entry(\"counter\", 42));\n\t\t\t}, (inputs) -> {\n\t\t\t\tMap<String, Object> nested = (Map<String, Object>) inputs.get(\"nested\");\n\t\t\t\tassertThat(nested).isNotNull();\n\t\t\t\tMap<String, Object> name = (Map<String, Object>) nested.get(\"name\");\n\t\t\t\tMap<String, Object> counter = (Map<String, Object>) nested.get(\"counter\");\n\t\t\t\tassertThat(name).containsEntry(\"value\", \"nested\");\n\t\t\t\tassertThat(name).containsEntry(\"origin\",\n\t\t\t\t\t\t\"\\\"immutablenested.nested.name\\\" from property source \\\"test\\\"\");\n\t\t\t\tassertThat(counter).containsEntry(\"origin\",\n\t\t\t\t\t\t\"\\\"immutablenested.nested.counter\\\" from property source \\\"test\\\"\");\n\t\t\t\tassertThat(counter).containsEntry(\"value\", \"42\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid descriptorWithSimpleList() {\n\t\tthis.contextRunner.withUserConfiguration(SensiblePropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"sensible.simpleList=a,b\")\n\t\t\t.run(assertProperties(\"sensible\", (properties) -> {\n\t\t\t\tassertThat(properties.get(\"simpleList\")).isInstanceOf(List.class);\n\t\t\t\tList<String> list = (List<String>) properties.get(\"simpleList\");\n\t\t\t\tassertThat(list).hasSize(2);\n\t\t\t\tassertThat(list.get(0)).isEqualTo(\"a\");\n\t\t\t\tassertThat(list.get(1)).isEqualTo(\"b\");\n\t\t\t}, (inputs) -> {\n\t\t\t\tList<Object> list = (List<Object>) inputs.get(\"simpleList\");\n\t\t\t\tassertThat(list).hasSize(2);\n\t\t\t\tMap<String, String> item = (Map<String, String>) list.get(0);\n\t\t\t\tString origin = item.get(\"origin\");\n\t\t\t\tString value = item.get(\"value\");\n\t\t\t\tassertThat(value).isEqualTo(\"a,b\");\n\t\t\t\tassertThat(origin).isEqualTo(\"\\\"sensible.simpleList\\\" from property source \\\"test\\\"\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid descriptorDoesNotIncludePropertyWithNullValue() {\n\t\tthis.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"test\", (properties) -> assertThat(properties).doesNotContainKey(\"nullValue\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithDurationProperty() {\n\t\tthis.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"test\", (properties) -> assertThat(properties.get(\"duration\"))\n\t\t\t\t.isEqualTo(Duration.ofSeconds(10).toString())));\n\t}\n\n\t@Test // gh-36076\n\tvoid descriptorWithWrapperProperty() {\n\t\tthis.contextRunner.withUserConfiguration(TestPropertiesConfiguration.class).withInitializer((context) -> {\n\t\t\tConfigurableEnvironment environment = context.getEnvironment();\n\t\t\tMap<String, Object> map = Collections.singletonMap(\"test.wrapper\", 10);\n\t\t\tPropertySource<?> propertySource = new MapPropertySource(\"test\", map);\n\t\t\tenvironment.getPropertySources().addLast(propertySource);\n\t\t})\n\t\t\t.run(assertProperties(\"test\", (properties) -> assertThat(properties.get(\"wrapper\")).isEqualTo(10),\n\t\t\t\t\t(inputs) -> {\n\t\t\t\t\t\tMap<String, Object> wrapper = (Map<String, Object>) inputs.get(\"wrapper\");\n\t\t\t\t\t\tassertThat(wrapper).containsEntry(\"value\", 10);\n\t\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid descriptorWithNonCamelCaseProperty() {\n\t\tthis.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"mixedcase\",\n\t\t\t\t\t(properties) -> assertThat(properties.get(\"myURL\")).isEqualTo(\"https://example.com\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithMixedCaseProperty() {\n\t\tthis.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"mixedcase\",\n\t\t\t\t\t(properties) -> assertThat(properties).containsEntry(\"mIxedCase\", \"mixed\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithSingleLetterProperty() {\n\t\tthis.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"mixedcase\", (properties) -> assertThat(properties.get(\"z\")).isEqualTo(\"zzz\")));\n\t}\n\n\t@Test\n\tvoid descriptorWithSimpleBooleanProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BooleanPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"boolean\",\n\t\t\t\t\t(properties) -> assertThat(properties.get(\"simpleBoolean\")).isEqualTo(true)));\n\t}\n\n\t@Test\n\tvoid descriptorWithMixedBooleanProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BooleanPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"boolean\",\n\t\t\t\t\t(properties) -> assertThat(properties.get(\"mixedBoolean\")).isEqualTo(true)));\n\t}\n\n\t@Test\n\tvoid descriptorWithDataSizeProperty() {\n\t\tString configSize = \"1MB\";\n\t\tString stringifySize = DataSize.parse(configSize).toString();\n\t\tthis.contextRunner.withUserConfiguration(DataSizePropertiesConfiguration.class)\n\t\t\t.withPropertyValues(String.format(\"data.size=%s\", configSize))\n\t\t\t.run(assertProperties(\"data\", (properties) -> assertThat(properties.get(\"size\")).isEqualTo(stringifySize),\n\t\t\t\t\t(inputs) -> {\n\t\t\t\t\t\tMap<String, Object> size = (Map<String, Object>) inputs.get(\"size\");\n\t\t\t\t\t\tassertThat(size).containsEntry(\"value\", configSize);\n\t\t\t\t\t\tassertThat(size).containsEntry(\"origin\", \"\\\"data.size\\\" from property source \\\"test\\\"\");\n\t\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid sanitizeLists() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfigWithShowNever.class, SensiblePropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"sensible.listItems[0].some-password=password\")\n\t\t\t.run(assertProperties(\"sensible\", (properties) -> {\n\t\t\t\tassertThat(properties.get(\"listItems\")).isInstanceOf(List.class);\n\t\t\t\tList<Object> list = (List<Object>) properties.get(\"listItems\");\n\t\t\t\tassertThat(list).hasSize(1);\n\t\t\t\tMap<String, Object> item = (Map<String, Object>) list.get(0);\n\t\t\t\tassertThat(item).containsEntry(\"somePassword\", \"******\");\n\t\t\t}, (inputs) -> {\n\t\t\t\tList<Object> list = (List<Object>) inputs.get(\"listItems\");\n\t\t\t\tassertThat(list).hasSize(1);\n\t\t\t\tMap<String, Object> item = (Map<String, Object>) list.get(0);\n\t\t\t\tMap<String, Object> somePassword = (Map<String, Object>) item.get(\"somePassword\");\n\t\t\t\tassertThat(somePassword).containsEntry(\"value\", \"******\");\n\t\t\t\tassertThat(somePassword).containsEntry(\"origin\",\n\t\t\t\t\t\t\"\\\"sensible.listItems[0].some-password\\\" from property source \\\"test\\\"\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid listsOfListsAreSanitized() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfigWithShowNever.class, SensiblePropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"sensible.listOfListItems[0][0].some-password=password\")\n\t\t\t.run(assertProperties(\"sensible\", (properties) -> {\n\t\t\t\tassertThat(properties.get(\"listOfListItems\")).isInstanceOf(List.class);\n\t\t\t\tList<List<Object>> listOfLists = (List<List<Object>>) properties.get(\"listOfListItems\");\n\t\t\t\tassertThat(listOfLists).hasSize(1);\n\t\t\t\tList<Object> list = listOfLists.get(0);\n\t\t\t\tassertThat(list).hasSize(1);\n\t\t\t\tMap<String, Object> item = (Map<String, Object>) list.get(0);\n\t\t\t\tassertThat(item).containsEntry(\"somePassword\", \"******\");\n\t\t\t}, (inputs) -> {\n\t\t\t\tassertThat(inputs.get(\"listOfListItems\")).isInstanceOf(List.class);\n\t\t\t\tList<List<Object>> listOfLists = (List<List<Object>>) inputs.get(\"listOfListItems\");\n\t\t\t\tassertThat(listOfLists).hasSize(1);\n\t\t\t\tList<Object> list = listOfLists.get(0);\n\t\t\t\tassertThat(list).hasSize(1);\n\t\t\t\tMap<String, Object> item = (Map<String, Object>) list.get(0);\n\t\t\t\tMap<String, Object> somePassword = (Map<String, Object>) item.get(\"somePassword\");\n\t\t\t\tassertThat(somePassword).containsEntry(\"value\", \"******\");\n\t\t\t\tassertThat(somePassword).containsEntry(\"origin\",\n\t\t\t\t\t\t\"\\\"sensible.listOfListItems[0][0].some-password\\\" from property source \\\"test\\\"\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid sanitizeWithCustomSanitizingFunction() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomSanitizingEndpointConfig.class, SanitizingFunctionConfiguration.class,\n\t\t\t\t\tTestPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"test\", (properties) -> {\n\t\t\t\tassertThat(properties).containsEntry(\"dbPassword\", \"$$$\");\n\t\t\t\tassertThat(properties).containsEntry(\"myTestProperty\", \"$$$\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid sanitizeWithCustomPropertySourceBasedSanitizingFunction() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomSanitizingEndpointConfig.class,\n\t\t\t\t\tPropertySourceBasedSanitizingFunctionConfiguration.class, TestPropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"test.my-test-property=abcde\")\n\t\t\t.run(assertProperties(\"test\", (properties) -> {\n\t\t\t\tassertThat(properties).containsEntry(\"dbPassword\", \"123456\");\n\t\t\t\tassertThat(properties).containsEntry(\"myTestProperty\", \"$$$\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid sanitizeListsWithCustomSanitizingFunction() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomSanitizingEndpointConfig.class, SanitizingFunctionConfiguration.class,\n\t\t\t\t\tSensiblePropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"sensible.listItems[0].custom=my-value\")\n\t\t\t.run(assertProperties(\"sensible\", (properties) -> {\n\t\t\t\tassertThat(properties.get(\"listItems\")).isInstanceOf(List.class);\n\t\t\t\tList<Object> list = (List<Object>) properties.get(\"listItems\");\n\t\t\t\tassertThat(list).hasSize(1);\n\t\t\t\tMap<String, Object> item = (Map<String, Object>) list.get(0);\n\t\t\t\tassertThat(item).containsEntry(\"custom\", \"$$$\");\n\t\t\t}, (inputs) -> {\n\t\t\t\tList<Object> list = (List<Object>) inputs.get(\"listItems\");\n\t\t\t\tassertThat(list).hasSize(1);\n\t\t\t\tMap<String, Object> item = (Map<String, Object>) list.get(0);\n\t\t\t\tMap<String, Object> somePassword = (Map<String, Object>) item.get(\"custom\");\n\t\t\t\tassertThat(somePassword).containsEntry(\"value\", \"$$$\");\n\t\t\t\tassertThat(somePassword).containsEntry(\"origin\",\n\t\t\t\t\t\t\"\\\"sensible.listItems[0].custom\\\" from property source \\\"test\\\"\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid noSanitizationWhenShowAlways() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfigWithShowAlways.class, TestPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"test\", (properties) -> {\n\t\t\t\tassertThat(properties).containsEntry(\"dbPassword\", \"123456\");\n\t\t\t\tassertThat(properties).containsEntry(\"myTestProperty\", \"654321\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid sanitizationWhenShowNever() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(EndpointConfigWithShowNever.class, TestPropertiesConfiguration.class)\n\t\t\t.run(assertProperties(\"test\", (properties) -> {\n\t\t\t\tassertThat(properties).containsEntry(\"dbPassword\", \"******\");\n\t\t\t\tassertThat(properties).containsEntry(\"myTestProperty\", \"******\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid originParents() {\n\t\tthis.contextRunner.withUserConfiguration(SensiblePropertiesConfiguration.class)\n\t\t\t.withInitializer(this::initializeOriginParents)\n\t\t\t.run(assertProperties(\"sensible\", (properties) -> {\n\t\t\t}, (inputs) -> {\n\t\t\t\tMap<String, Object> stringInputs = (Map<String, Object>) inputs.get(\"string\");\n\t\t\t\tassertThat(stringInputs).isNotNull();\n\t\t\t\tString[] originParents = (String[]) stringInputs.get(\"originParents\");\n\t\t\t\tassertThat(originParents).containsExactly(\"spring\", \"boot\");\n\t\t\t}));\n\t}\n\n\tprivate void initializeOriginParents(ConfigurableApplicationContext context) {\n\t\tMockPropertySource propertySource = new OriginParentMockPropertySource();\n\t\tpropertySource.setProperty(\"sensible.string\", \"spring\");\n\t\tcontext.getEnvironment().getPropertySources().addFirst(propertySource);\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertProperties(String prefix,\n\t\t\tConsumer<Map<String, Object>> properties) {\n\t\treturn assertProperties(prefix, properties, (inputs) -> {\n\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertProperties(String prefix,\n\t\t\tConsumer<Map<String, Object>> properties, Consumer<Map<String, Object>> inputs) {\n\t\treturn (context) -> {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor configurationProperties = endpoint\n\t\t\t\t.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor allProperties = getContextDescriptor(context,\n\t\t\t\t\tconfigurationProperties);\n\t\t\tOptional<String> key = allProperties.getBeans()\n\t\t\t\t.keySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((id) -> findIdFromPrefix(prefix, id))\n\t\t\t\t.findAny();\n\t\t\tassertThat(key).describedAs(\"No configuration properties with prefix '%s' found\", prefix).isPresent();\n\t\t\tConfigurationPropertiesBeanDescriptor descriptor = allProperties.getBeans().get(key.get());\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getPrefix()).isEqualTo(prefix);\n\t\t\tproperties.accept(descriptor.getProperties());\n\t\t\tinputs.accept(descriptor.getInputs());\n\t\t};\n\t}\n\n\tprivate ContextConfigurationPropertiesDescriptor getContextDescriptor(AssertableApplicationContext context,\n\t\t\tConfigurationPropertiesDescriptor configurationProperties) {\n\t\tContextConfigurationPropertiesDescriptor contextDescriptor = configurationProperties.getContexts()\n\t\t\t.get(context.getId());\n\t\tassertThat(contextDescriptor).isNotNull();\n\t\treturn contextDescriptor;\n\t}\n\n\tprivate boolean findIdFromPrefix(String prefix, String id) {\n\t\tint separator = id.indexOf(\"-\");\n\t\tString candidate = (separator != -1) ? id.substring(0, separator) : id;\n\t\treturn prefix.equals(candidate);\n\t}\n\n\tstatic class OriginParentMockPropertySource extends MockPropertySource implements OriginLookup<String> {\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String key) {\n\t\t\treturn new MockOrigin(key, new MockOrigin(\"spring\", new MockOrigin(\"boot\", null)));\n\t\t}\n\n\t}\n\n\tstatic class MockOrigin implements Origin {\n\n\t\tprivate final String value;\n\n\t\tprivate final @Nullable MockOrigin parent;\n\n\t\tMockOrigin(String value, @Nullable MockOrigin parent) {\n\t\t\tthis.value = value;\n\t\t\tthis.parent = parent;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getParent() {\n\t\t\treturn this.parent;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfig {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(\n\t\t\t\t\tCollections.emptyList(), Show.WHEN_AUTHORIZED);\n\t\t\treturn endpoint;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfigWithShowAlways {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(\n\t\t\t\t\tCollections.emptyList(), Show.ALWAYS);\n\t\t\treturn endpoint;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfigWithShowNever {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint() {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(\n\t\t\t\t\tCollections.emptyList(), Show.NEVER);\n\t\t\treturn endpoint;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(TestProperties.class)\n\tstatic class TestPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tpublic static class TestProperties {\n\n\t\tprivate String dbPassword = \"123456\";\n\n\t\tprivate String myTestProperty = \"654321\";\n\n\t\tprivate @Nullable String nullValue;\n\n\t\tprivate Duration duration = Duration.ofSeconds(10);\n\n\t\tprivate final String ignored = \"dummy\";\n\n\t\tprivate @Nullable Integer wrapper;\n\n\t\tpublic String getDbPassword() {\n\t\t\treturn this.dbPassword;\n\t\t}\n\n\t\tpublic void setDbPassword(String dbPassword) {\n\t\t\tthis.dbPassword = dbPassword;\n\t\t}\n\n\t\tpublic String getMyTestProperty() {\n\t\t\treturn this.myTestProperty;\n\t\t}\n\n\t\tpublic void setMyTestProperty(String myTestProperty) {\n\t\t\tthis.myTestProperty = myTestProperty;\n\t\t}\n\n\t\tpublic @Nullable String getNullValue() {\n\t\t\treturn this.nullValue;\n\t\t}\n\n\t\tpublic void setNullValue(@Nullable String nullValue) {\n\t\t\tthis.nullValue = nullValue;\n\t\t}\n\n\t\tpublic Duration getDuration() {\n\t\t\treturn this.duration;\n\t\t}\n\n\t\tpublic void setDuration(Duration duration) {\n\t\t\tthis.duration = duration;\n\t\t}\n\n\t\tpublic String getIgnored() {\n\t\t\treturn this.ignored;\n\t\t}\n\n\t\tpublic @Nullable Integer getWrapper() {\n\t\t\treturn this.wrapper;\n\t\t}\n\n\t\tpublic void setWrapper(@Nullable Integer wrapper) {\n\t\t\tthis.wrapper = wrapper;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ImmutableProperties.class)\n\tstatic class ImmutablePropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"immutable\")\n\tpublic static class ImmutableProperties {\n\n\t\tprivate final String dbPassword;\n\n\t\tprivate final String myTestProperty;\n\n\t\tprivate final String nullValue;\n\n\t\tprivate final Duration forDuration;\n\n\t\tprivate final String ignored;\n\n\t\tImmutableProperties(@DefaultValue(\"123456\") String dbPassword, @DefaultValue(\"654321\") String myTestProperty,\n\t\t\t\tString nullValue, @DefaultValue(\"10s\") @Name(\"for\") Duration forDuration) {\n\t\t\tthis.dbPassword = dbPassword;\n\t\t\tthis.myTestProperty = myTestProperty;\n\t\t\tthis.nullValue = nullValue;\n\t\t\tthis.forDuration = forDuration;\n\t\t\tthis.ignored = \"dummy\";\n\t\t}\n\n\t\tpublic String getDbPassword() {\n\t\t\treturn this.dbPassword;\n\t\t}\n\n\t\tpublic String getMyTestProperty() {\n\t\t\treturn this.myTestProperty;\n\t\t}\n\n\t\tpublic String getNullValue() {\n\t\t\treturn this.nullValue;\n\t\t}\n\n\t\tpublic Duration getFor() {\n\t\t\treturn this.forDuration;\n\t\t}\n\n\t\tpublic String getIgnored() {\n\t\t\treturn this.ignored;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(MultiConstructorProperties.class)\n\tstatic class MultiConstructorPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"multiconstructor\")\n\tpublic static class MultiConstructorProperties {\n\n\t\tprivate final String name;\n\n\t\tprivate final int counter;\n\n\t\tMultiConstructorProperties(String name, int counter) {\n\t\t\tthis.name = name;\n\t\t\tthis.counter = counter;\n\t\t}\n\n\t\t@ConstructorBinding\n\t\tMultiConstructorProperties(@DefaultValue(\"test\") String name) {\n\t\t\tthis.name = name;\n\t\t\tthis.counter = 42;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic int getCounter() {\n\t\t\treturn this.counter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(AutowiredProperties.class)\n\tstatic class AutowiredPropertiesConfiguration {\n\n\t\t@Bean\n\t\tString hello() {\n\t\t\treturn \"hello\";\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"autowired\")\n\tpublic static class AutowiredProperties {\n\n\t\tprivate final String name;\n\n\t\tprivate int counter;\n\n\t\t@Autowired\n\t\tAutowiredProperties(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic int getCounter() {\n\t\t\treturn this.counter;\n\t\t}\n\n\t\tpublic void setCounter(int counter) {\n\t\t\tthis.counter = counter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ImmutableNestedProperties.class)\n\tstatic class ImmutableNestedPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"immutablenested\")\n\tpublic static class ImmutableNestedProperties {\n\n\t\tprivate final String name;\n\n\t\tprivate final Nested nested;\n\n\t\tImmutableNestedProperties(@DefaultValue(\"parent\") String name, Nested nested) {\n\t\t\tthis.name = name;\n\t\t\tthis.nested = nested;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic Nested getNested() {\n\t\t\treturn this.nested;\n\t\t}\n\n\t\tpublic static class Nested {\n\n\t\t\tprivate final String name;\n\n\t\t\tprivate final int counter;\n\n\t\t\tNested(String name, int counter) {\n\t\t\t\tthis.name = name;\n\t\t\t\tthis.counter = counter;\n\t\t\t}\n\n\t\t\tpublic String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic int getCounter() {\n\t\t\t\treturn this.counter;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(MixedCaseProperties.class)\n\tstatic class MixedCasePropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"mixedcase\")\n\tpublic static class MixedCaseProperties {\n\n\t\tprivate String myURL = \"https://example.com\";\n\n\t\tprivate String mIxedCase = \"mixed\";\n\n\t\tprivate String z = \"zzz\";\n\n\t\tpublic String getMyURL() {\n\t\t\treturn this.myURL;\n\t\t}\n\n\t\tpublic void setMyURL(String myURL) {\n\t\t\tthis.myURL = myURL;\n\t\t}\n\n\t\tpublic String getmIxedCase() {\n\t\t\treturn this.mIxedCase;\n\t\t}\n\n\t\tpublic void setmIxedCase(String mIxedCase) {\n\t\t\tthis.mIxedCase = mIxedCase;\n\t\t}\n\n\t\tpublic String getZ() {\n\t\t\treturn this.z;\n\t\t}\n\n\t\tpublic void setZ(String z) {\n\t\t\tthis.z = z;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(BooleanProperties.class)\n\tstatic class BooleanPropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"boolean\")\n\tpublic static class BooleanProperties {\n\n\t\tprivate boolean simpleBoolean = true;\n\n\t\tprivate Boolean mixedBoolean = true;\n\n\t\tpublic boolean isSimpleBoolean() {\n\t\t\treturn this.simpleBoolean;\n\t\t}\n\n\t\tpublic void setSimpleBoolean(boolean simpleBoolean) {\n\t\t\tthis.simpleBoolean = simpleBoolean;\n\t\t}\n\n\t\tpublic boolean isMixedBoolean() {\n\t\t\treturn (this.mixedBoolean != null) ? this.mixedBoolean : false;\n\t\t}\n\n\t\tpublic void setMixedBoolean(Boolean mixedBoolean) {\n\t\t\tthis.mixedBoolean = mixedBoolean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(DataSizeProperties.class)\n\tstatic class DataSizePropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"data\")\n\tpublic static class DataSizeProperties {\n\n\t\tprivate @Nullable DataSize size;\n\n\t\tpublic @Nullable DataSize getSize() {\n\t\t\treturn this.size;\n\t\t}\n\n\t\tpublic void setSize(@Nullable DataSize size) {\n\t\t\tthis.size = size;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(Gh4415Properties.class)\n\tstatic class Gh4415PropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"gh4415\")\n\tpublic static class Gh4415Properties {\n\n\t\tprivate Hidden hidden = new Hidden();\n\n\t\tprivate Map<String, Object> secrets = new HashMap<>();\n\n\t\tGh4415Properties() {\n\t\t\tthis.secrets.put(\"mine\", \"myPrivateThing\");\n\t\t\tthis.secrets.put(\"yours\", \"yourPrivateThing\");\n\t\t}\n\n\t\tpublic Hidden getHidden() {\n\t\t\treturn this.hidden;\n\t\t}\n\n\t\tpublic void setHidden(Hidden hidden) {\n\t\t\tthis.hidden = hidden;\n\t\t}\n\n\t\tpublic Map<String, Object> getSecrets() {\n\t\t\treturn this.secrets;\n\t\t}\n\n\t\tpublic void setSecrets(Map<String, Object> secrets) {\n\t\t\tthis.secrets = secrets;\n\t\t}\n\n\t\tpublic static class Hidden {\n\n\t\t\tprivate String mine = \"mySecret\";\n\n\t\t\tpublic String getMine() {\n\t\t\t\treturn this.mine;\n\t\t\t}\n\n\t\t\tpublic void setMine(String mine) {\n\t\t\t\tthis.mine = mine;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(SensibleProperties.class)\n\tstatic class SensiblePropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"sensible\")\n\tpublic static class SensibleProperties {\n\n\t\tprivate @Nullable String string;\n\n\t\tprivate URI sensitiveUri = URI.create(\"http://user:password@localhost:8080\");\n\n\t\tprivate URI noPasswordUri = URI.create(\"http://user:@localhost:8080\");\n\n\t\tprivate final List<String> simpleList = new ArrayList<>();\n\n\t\tprivate String rawSensitiveAddresses = \"http://user:password@localhost:8080,http://user2:password2@localhost:8082\";\n\n\t\tprivate List<ListItem> listItems = new ArrayList<>();\n\n\t\tprivate List<List<ListItem>> listOfListItems = new ArrayList<>();\n\n\t\tSensibleProperties() {\n\t\t\tthis.listItems.add(new ListItem());\n\t\t\tthis.listOfListItems.add(Collections.singletonList(new ListItem()));\n\t\t}\n\n\t\tpublic void setString(@Nullable String string) {\n\t\t\tthis.string = string;\n\t\t}\n\n\t\tpublic @Nullable String getString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t\tpublic void setSensitiveUri(URI sensitiveUri) {\n\t\t\tthis.sensitiveUri = sensitiveUri;\n\t\t}\n\n\t\tpublic URI getSensitiveUri() {\n\t\t\treturn this.sensitiveUri;\n\t\t}\n\n\t\tpublic void setNoPasswordUri(URI noPasswordUri) {\n\t\t\tthis.noPasswordUri = noPasswordUri;\n\t\t}\n\n\t\tpublic URI getNoPasswordUri() {\n\t\t\treturn this.noPasswordUri;\n\t\t}\n\n\t\tpublic String getRawSensitiveAddresses() {\n\t\t\treturn this.rawSensitiveAddresses;\n\t\t}\n\n\t\tpublic void setRawSensitiveAddresses(final String rawSensitiveAddresses) {\n\t\t\tthis.rawSensitiveAddresses = rawSensitiveAddresses;\n\t\t}\n\n\t\tpublic List<ListItem> getListItems() {\n\t\t\treturn this.listItems;\n\t\t}\n\n\t\tpublic void setListItems(List<ListItem> listItems) {\n\t\t\tthis.listItems = listItems;\n\t\t}\n\n\t\tpublic List<List<ListItem>> getListOfListItems() {\n\t\t\treturn this.listOfListItems;\n\t\t}\n\n\t\tpublic void setListOfListItems(List<List<ListItem>> listOfListItems) {\n\t\t\tthis.listOfListItems = listOfListItems;\n\t\t}\n\n\t\tpublic List<String> getSimpleList() {\n\t\t\treturn this.simpleList;\n\t\t}\n\n\t\tpublic static class ListItem {\n\n\t\t\tprivate String somePassword = \"secret\";\n\n\t\t\tprivate @Nullable String custom;\n\n\t\t\tpublic String getSomePassword() {\n\t\t\t\treturn this.somePassword;\n\t\t\t}\n\n\t\t\tpublic void setSomePassword(String somePassword) {\n\t\t\t\tthis.somePassword = somePassword;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getCustom() {\n\t\t\t\treturn this.custom;\n\t\t\t}\n\n\t\t\tpublic void setCustom(@Nullable String custom) {\n\t\t\t\tthis.custom = custom;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSanitizingEndpointConfig {\n\n\t\t@Bean\n\t\tConfigurationPropertiesReportEndpoint endpoint(SanitizingFunction sanitizingFunction) {\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = new ConfigurationPropertiesReportEndpoint(\n\t\t\t\t\tCollections.singletonList(sanitizingFunction), Show.ALWAYS);\n\t\t\treturn endpoint;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SanitizingFunctionConfiguration {\n\n\t\t@Bean\n\t\tSanitizingFunction testSanitizingFunction() {\n\t\t\treturn (data) -> {\n\t\t\t\tif (data.getKey().contains(\"custom\") || data.getKey().contains(\"test\")) {\n\t\t\t\t\treturn data.withValue(\"$$$\");\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PropertySourceBasedSanitizingFunctionConfiguration {\n\n\t\t@Bean\n\t\tSanitizingFunction testSanitizingFunction() {\n\t\t\treturn (data) -> {\n\t\t\t\tif (data.getPropertySource() != null && data.getPropertySource().getName().startsWith(\"test\")) {\n\t\t\t\t\treturn data.withValue(\"$$$\");\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ConfigurationPropertiesReportEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport java.security.Principal;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpointWebExtension}.\n *\n * @author Madhura Bhave\n */\nclass ConfigurationPropertiesReportEndpointWebExtensionTests {\n\n\tprivate @Nullable ConfigurationPropertiesReportEndpointWebExtension webExtension;\n\n\tprivate ConfigurationPropertiesReportEndpoint delegate;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.delegate = mock(ConfigurationPropertiesReportEndpoint.class);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsNever() {\n\t\tthis.webExtension = new ConfigurationPropertiesReportEndpointWebExtension(this.delegate, Show.NEVER,\n\t\t\t\tCollections.emptySet());\n\t\tthis.webExtension.configurationProperties(SecurityContext.NONE);\n\t\tthen(this.delegate).should().getConfigurationProperties(false);\n\t\tverifyPrefixed(SecurityContext.NONE, false);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsAlways() {\n\t\tthis.webExtension = new ConfigurationPropertiesReportEndpointWebExtension(this.delegate, Show.ALWAYS,\n\t\t\t\tCollections.emptySet());\n\t\tthis.webExtension.configurationProperties(SecurityContext.NONE);\n\t\tthen(this.delegate).should().getConfigurationProperties(true);\n\t\tverifyPrefixed(SecurityContext.NONE, true);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsWhenAuthorizedAndSecurityContextIsAuthorized() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class));\n\t\tthis.webExtension = new ConfigurationPropertiesReportEndpointWebExtension(this.delegate, Show.WHEN_AUTHORIZED,\n\t\t\t\tCollections.emptySet());\n\t\tthis.webExtension.configurationProperties(securityContext);\n\t\tthen(this.delegate).should().getConfigurationProperties(true);\n\t\tverifyPrefixed(securityContext, true);\n\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsWhenAuthorizedAndSecurityContextIsNotAuthorized() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tthis.webExtension = new ConfigurationPropertiesReportEndpointWebExtension(this.delegate, Show.WHEN_AUTHORIZED,\n\t\t\t\tCollections.emptySet());\n\t\tthis.webExtension.configurationProperties(securityContext);\n\t\tthen(this.delegate).should().getConfigurationProperties(false);\n\t\tverifyPrefixed(securityContext, false);\n\t}\n\n\tprivate void verifyPrefixed(SecurityContext securityContext, boolean showUnsanitized) {\n\t\tgiven(this.delegate.getConfigurationProperties(\"test\", showUnsanitized))\n\t\t\t.willReturn(new ConfigurationPropertiesDescriptor(Collections.emptyMap()));\n\t\tassertThat(this.webExtension).isNotNull();\n\t\tthis.webExtension.configurationPropertiesWithPrefix(securityContext, \"test\");\n\t\tthen(this.delegate).should().getConfigurationProperties(\"test\", showUnsanitized);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/context/properties/ValidatedConstructorBindingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.context.properties;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.validation.annotation.Validated;\n\n/**\n * Used for testing the {@link ConfigurationPropertiesReportEndpoint} endpoint with\n * validated {@link ConfigurationProperties @ConfigurationProperties}.\n *\n * @author Madhura Bhave\n */\n@Validated\n@ConfigurationProperties(\"validated\")\npublic class ValidatedConstructorBindingProperties {\n\n\tprivate final String name;\n\n\tValidatedConstructorBindingProperties(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AccessTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Access}.\n *\n * @author Phillip Webb\n */\nclass AccessTests {\n\n\t@Test\n\tvoid capWhenAboveMaximum() {\n\t\tassertThat(Access.UNRESTRICTED.cap(Access.READ_ONLY)).isEqualTo(Access.READ_ONLY);\n\t}\n\n\t@Test\n\tvoid capWhenAtMaximum() {\n\t\tassertThat(Access.READ_ONLY.cap(Access.READ_ONLY)).isEqualTo(Access.READ_ONLY);\n\t}\n\n\t@Test\n\tvoid capWhenBelowMaximum() {\n\t\tassertThat(Access.NONE.cap(Access.READ_ONLY)).isEqualTo(Access.NONE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/EndpointIdTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link EndpointId}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass EndpointIdTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(null))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(\"\"))\n\t\t\t.withMessage(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsSlashThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(\"foo/bar\"))\n\t\t\t.withMessage(\"'value' must only contain valid chars\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsBackslashThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(\"foo\\\\bar\"))\n\t\t\t.withMessage(\"'value' must only contain valid chars\");\n\t}\n\n\t@Test\n\tvoid ofWhenHasBadCharThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(\"foo!bar\"))\n\t\t\t.withMessage(\"'value' must only contain valid chars\");\n\t}\n\n\t@Test\n\tvoid ofWhenStartsWithNumberThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(\"1foo\"))\n\t\t\t.withMessage(\"'value' must not start with a number\");\n\t}\n\n\t@Test\n\tvoid ofWhenStartsWithUppercaseLetterThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EndpointId.of(\"Foo\"))\n\t\t\t.withMessage(\"'value' must not start with an uppercase letter\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsDotIsValid() {\n\t\t// Ideally we wouldn't support this but there are existing endpoints using the\n\t\t// pattern. See gh-14773\n\t\tEndpointId endpointId = EndpointId.of(\"foo.bar\");\n\t\tassertThat(endpointId).hasToString(\"foo.bar\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsDashIsValid() {\n\t\t// Ideally we wouldn't support this but there are existing endpoints using the\n\t\t// pattern. See gh-14773\n\t\tEndpointId endpointId = EndpointId.of(\"foo-bar\");\n\t\tassertThat(endpointId).hasToString(\"foo-bar\");\n\t}\n\n\t@Test\n\tvoid ofWhenContainsDeprecatedCharsLogsWarning(CapturedOutput output) {\n\t\tEndpointId.resetLoggedWarnings();\n\t\tEndpointId.of(\"foo-bar\");\n\t\tassertThat(output)\n\t\t\t.contains(\"Endpoint ID 'foo-bar' contains invalid characters, please migrate to a valid format\");\n\t}\n\n\t@Test\n\tvoid ofWhenMigratingLegacyNameRemovesDots(CapturedOutput output) {\n\t\tEndpointId endpointId = migrateLegacyName(\"one.two.three\");\n\t\tassertThat(endpointId).hasToString(\"onetwothree\");\n\t\tassertThat(output).doesNotContain(\"contains invalid characters\");\n\t}\n\n\t@Test\n\tvoid ofWhenMigratingLegacyNameRemovesHyphens(CapturedOutput output) {\n\t\tEndpointId endpointId = migrateLegacyName(\"one-two-three\");\n\t\tassertThat(endpointId).hasToString(\"onetwothree\");\n\t\tassertThat(output).doesNotContain(\"contains invalid characters\");\n\t}\n\n\t@Test\n\tvoid ofWhenMigratingLegacyNameRemovesMixOfDashAndDot(CapturedOutput output) {\n\t\tEndpointId endpointId = migrateLegacyName(\"one.two-three\");\n\t\tassertThat(endpointId).hasToString(\"onetwothree\");\n\t\tassertThat(output).doesNotContain(\"contains invalid characters\");\n\t}\n\n\tprivate EndpointId migrateLegacyName(String name) {\n\t\tEndpointId.resetLoggedWarnings();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"management.endpoints.migrate-legacy-ids\", \"true\");\n\t\treturn EndpointId.of(environment, name);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tEndpointId one = EndpointId.of(\"foobar1\");\n\t\tEndpointId two = EndpointId.of(\"fooBar1\");\n\t\tEndpointId three = EndpointId.of(\"foo-bar1\");\n\t\tEndpointId four = EndpointId.of(\"foo.bar1\");\n\t\tEndpointId five = EndpointId.of(\"barfoo1\");\n\t\tEndpointId six = EndpointId.of(\"foobar2\");\n\t\tassertThat(one).hasSameHashCodeAs(two);\n\t\tassertThat(one).isEqualTo(one)\n\t\t\t.isEqualTo(two)\n\t\t\t.isEqualTo(three)\n\t\t\t.isEqualTo(four)\n\t\t\t.isNotEqualTo(five)\n\t\t\t.isNotEqualTo(six);\n\t}\n\n\t@Test\n\tvoid toLowerCaseStringReturnsLowercase() {\n\t\tassertThat(EndpointId.of(\"fooBar\").toLowerCaseString()).isEqualTo(\"foobar\");\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tassertThat(EndpointId.of(\"fooBar\")).hasToString(\"fooBar\");\n\t}\n\n\t@Test\n\tvoid fromPropertyValueStripsDashes() {\n\t\tEndpointId fromPropertyValue = EndpointId.fromPropertyValue(\"foo-bar\");\n\t\tassertThat(fromPropertyValue).isEqualTo(EndpointId.of(\"fooBar\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/InvocationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link InvocationContext}.\n *\n * @author Phillip Webb\n */\nclass InvocationContextTests {\n\n\tprivate final SecurityContext securityContext = mock(SecurityContext.class);\n\n\tprivate final Map<String, Object> arguments = Collections.singletonMap(\"test\", \"value\");\n\n\t@Test\n\tvoid whenCreatedWithoutApiVersionThenResolveApiVersionReturnsLatestVersion() {\n\t\tInvocationContext context = new InvocationContext(this.securityContext, this.arguments);\n\t\tassertThat(context.resolveArgument(ApiVersion.class)).isEqualTo(ApiVersion.LATEST);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSecurityContextIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new InvocationContext(null, this.arguments))\n\t\t\t.withMessage(\"'securityContext' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenArgumentsIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new InvocationContext(this.securityContext, null))\n\t\t\t.withMessage(\"'arguments' must not be null\");\n\t}\n\n\t@Test\n\tvoid resolveSecurityContextReturnsSecurityContext() {\n\t\tInvocationContext context = new InvocationContext(this.securityContext, this.arguments);\n\t\tassertThat(context.resolveArgument(SecurityContext.class)).isEqualTo(this.securityContext);\n\t}\n\n\t@Test\n\tvoid getArgumentsReturnsArguments() {\n\t\tInvocationContext context = new InvocationContext(this.securityContext, this.arguments);\n\t\tassertThat(context.getArguments()).isEqualTo(this.arguments);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/OperationFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OperationFilter}.\n *\n * @author Andy Wilkinson\n */\nclass OperationFilterTests {\n\n\tprivate final EndpointAccessResolver accessResolver = mock(EndpointAccessResolver.class);\n\n\tprivate final Operation operation = mock(Operation.class);\n\n\tprivate final OperationFilter<Operation> filter = OperationFilter.byAccess(this.accessResolver);\n\n\t@Test\n\tvoid whenAccessIsUnrestrictedThenMatchReturnsTrue() {\n\t\tEndpointId endpointId = EndpointId.of(\"test\");\n\t\tAccess defaultAccess = Access.READ_ONLY;\n\t\tgiven(this.accessResolver.accessFor(endpointId, defaultAccess)).willReturn(Access.UNRESTRICTED);\n\t\tassertThat(this.filter.match(this.operation, endpointId, defaultAccess)).isTrue();\n\t}\n\n\t@Test\n\tvoid whenAccessIsNoneThenMatchReturnsFalse() {\n\t\tEndpointId endpointId = EndpointId.of(\"test\");\n\t\tAccess defaultAccess = Access.READ_ONLY;\n\t\tgiven(this.accessResolver.accessFor(endpointId, defaultAccess)).willReturn(Access.NONE);\n\t\tassertThat(this.filter.match(this.operation, endpointId, defaultAccess)).isFalse();\n\t}\n\n\t@Test\n\tvoid whenAccessIsReadOnlyAndOperationTypeIsReadThenMatchReturnsTrue() {\n\t\tEndpointId endpointId = EndpointId.of(\"test\");\n\t\tAccess defaultAccess = Access.READ_ONLY;\n\t\tgiven(this.accessResolver.accessFor(endpointId, defaultAccess)).willReturn(Access.READ_ONLY);\n\t\tgiven(this.operation.getType()).willReturn(OperationType.READ);\n\t\tassertThat(this.filter.match(this.operation, endpointId, defaultAccess)).isTrue();\n\t}\n\n\t@Test\n\tvoid whenAccessIsReadOnlyAndOperationTypeIsWriteThenMatchReturnsFalse() {\n\t\tEndpointId endpointId = EndpointId.of(\"test\");\n\t\tAccess defaultAccess = Access.READ_ONLY;\n\t\tgiven(this.accessResolver.accessFor(endpointId, defaultAccess)).willReturn(Access.READ_ONLY);\n\t\tgiven(this.operation.getType()).willReturn(OperationType.WRITE);\n\t\tassertThat(this.filter.match(this.operation, endpointId, defaultAccess)).isFalse();\n\t}\n\n\t@Test\n\tvoid whenAccessIsReadOnlyAndOperationTypeIsDeleteThenMatchReturnsFalse() {\n\t\tEndpointId endpointId = EndpointId.of(\"test\");\n\t\tAccess defaultAccess = Access.READ_ONLY;\n\t\tgiven(this.accessResolver.accessFor(endpointId, defaultAccess)).willReturn(Access.READ_ONLY);\n\t\tgiven(this.operation.getType()).willReturn(OperationType.DELETE);\n\t\tassertThat(this.filter.match(this.operation, endpointId, defaultAccess)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/OperationResponseBodyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link OperationResponseBody}.\n *\n * @author Phillip Webb\n */\nclass OperationResponseBodyTests {\n\n\t@Test\n\tvoid ofMapReturnsOperationResponseBody() {\n\t\tLinkedHashMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"one\", \"1\");\n\t\tmap.put(\"two\", \"2\");\n\t\tMap<String, String> mapDescriptor = OperationResponseBody.of(map);\n\t\tassertThat(mapDescriptor).containsExactly(entry(\"one\", \"1\"), entry(\"two\", \"2\"));\n\t\tassertThat(mapDescriptor).isInstanceOf(OperationResponseBody.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ProducibleOperationArgumentResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.MimeType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Test for {@link ProducibleOperationArgumentResolver}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ProducibleOperationArgumentResolverTests {\n\n\tprivate static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\t@Test\n\tvoid whenAcceptHeaderIsEmptyThenHighestOrdinalIsReturned() {\n\t\tassertThat(resolve(acceptHeader())).isEqualTo(ApiVersion.V3);\n\t}\n\n\t@Test\n\tvoid whenAcceptHeaderIsEmptyAndWithDefaultThenDefaultIsReturned() {\n\t\tassertThat(resolve(acceptHeader(), WithDefault.class)).isEqualTo(WithDefault.TWO);\n\t}\n\n\t@Test\n\tvoid whenEverythingIsAcceptableThenHighestOrdinalIsReturned() {\n\t\tassertThat(resolve(acceptHeader(\"*/*\"))).isEqualTo(ApiVersion.V3);\n\t}\n\n\t@Test\n\tvoid whenEverythingIsAcceptableWithDefaultThenDefaultIsReturned() {\n\t\tassertThat(resolve(acceptHeader(\"*/*\"), WithDefault.class)).isEqualTo(WithDefault.TWO);\n\t}\n\n\t@Test\n\tvoid whenNothingIsAcceptableThenNullIsReturned() {\n\t\tassertThat(resolve(acceptHeader(\"image/png\"))).isNull();\n\t}\n\n\t@Test\n\tvoid whenSingleValueIsAcceptableThenMatchingEnumValueIsReturned() {\n\t\tassertThat(new ProducibleOperationArgumentResolver(acceptHeader(V2_JSON)).resolve(ApiVersion.class))\n\t\t\t.isEqualTo(ApiVersion.V2);\n\t\tassertThat(new ProducibleOperationArgumentResolver(acceptHeader(V3_JSON)).resolve(ApiVersion.class))\n\t\t\t.isEqualTo(ApiVersion.V3);\n\t}\n\n\t@Test\n\tvoid whenMultipleValuesAreAcceptableThenHighestOrdinalIsReturned() {\n\t\tassertThat(resolve(acceptHeader(V2_JSON, V3_JSON))).isEqualTo(ApiVersion.V3);\n\t}\n\n\t@Test\n\tvoid whenMultipleValuesAreAcceptableAsSingleHeaderThenHighestOrdinalIsReturned() {\n\t\tassertThat(resolve(acceptHeader(V2_JSON + \",\" + V3_JSON))).isEqualTo(ApiVersion.V3);\n\t}\n\n\t@Test\n\tvoid withMultipleValuesOneOfWhichIsAllReturnsDefault() {\n\t\tassertThat(resolve(acceptHeader(\"one/one\", \"*/*\"), WithDefault.class)).isEqualTo(WithDefault.TWO);\n\t}\n\n\t@Test\n\tvoid whenMultipleDefaultsThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> resolve(acceptHeader(\"one/one\"), WithMultipleDefaults.class))\n\t\t\t.withMessageContaining(\"Multiple default values\");\n\t}\n\n\tprivate Supplier<@Nullable List<String>> acceptHeader(String... types) {\n\t\tList<String> value = Arrays.asList(types);\n\t\treturn () -> (value.isEmpty() ? null : value);\n\t}\n\n\tprivate @Nullable ApiVersion resolve(Supplier<@Nullable List<String>> accepts) {\n\t\treturn resolve(accepts, ApiVersion.class);\n\t}\n\n\tprivate <T> @Nullable T resolve(Supplier<@Nullable List<String>> accepts, Class<T> type) {\n\t\treturn new ProducibleOperationArgumentResolver(accepts).resolve(type);\n\t}\n\n\tenum WithDefault implements Producible<WithDefault> {\n\n\t\tONE(\"one/one\"),\n\n\t\tTWO(\"two/two\") {\n\n\t\t\t@Override\n\t\t\tpublic boolean isDefault() {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t},\n\n\t\tTHREE(\"three/three\");\n\n\t\tprivate final MimeType mimeType;\n\n\t\tWithDefault(String mimeType) {\n\t\t\tthis.mimeType = MimeType.valueOf(mimeType);\n\t\t}\n\n\t\t@Override\n\t\tpublic MimeType getProducedMimeType() {\n\t\t\treturn this.mimeType;\n\t\t}\n\n\t}\n\n\tenum WithMultipleDefaults implements Producible<WithMultipleDefaults> {\n\n\t\tONE, TWO, THREE;\n\n\t\t@Override\n\t\tpublic boolean isDefault() {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic MimeType getProducedMimeType() {\n\t\t\treturn MimeType.valueOf(\"image/jpeg\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizableDataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SanitizableData}.\n *\n * @author Phillip Webb\n */\nclass SanitizableDataTests {\n\n\tprivate final PropertySource<?> propertySource = new MapPropertySource(\"test\", Map.of(\"key\", \"value\"));\n\n\t@Test\n\tvoid getPropertySourceReturnsPropertySource() {\n\t\tSanitizableData data = new SanitizableData(this.propertySource, \"key\", \"value\");\n\t\tassertThat(data.getPropertySource()).isSameAs(this.propertySource);\n\t}\n\n\t@Test\n\tvoid getKeyReturnsKey() {\n\t\tSanitizableData data = new SanitizableData(this.propertySource, \"key\", \"value\");\n\t\tassertThat(data.getKey()).isEqualTo(\"key\");\n\t}\n\n\t@Test\n\tvoid getValueReturnsValue() {\n\t\tSanitizableData data = new SanitizableData(this.propertySource, \"key\", \"value\");\n\t\tassertThat(data.getValue()).isEqualTo(\"value\");\n\t}\n\n\t@Test\n\tvoid withSanitizedValueReturnsNewInstanceWithSanitizedValue() {\n\t\tSanitizableData data = new SanitizableData(this.propertySource, \"key\", \"value\");\n\t\tSanitizableData sanitized = data.withSanitizedValue();\n\t\tassertThat(data.getValue()).isEqualTo(\"value\");\n\t\tassertThat(sanitized.getValue()).isEqualTo(\"******\");\n\t}\n\n\t@Test\n\tvoid withValueReturnsNewInstanceWithNewValue() {\n\t\tSanitizableData data = new SanitizableData(this.propertySource, \"key\", \"value\");\n\t\tSanitizableData sanitized = data.withValue(\"eulav\");\n\t\tassertThat(data.getValue()).isEqualTo(\"value\");\n\t\tassertThat(sanitized.getValue()).isEqualTo(\"eulav\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Sanitizer}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Chris Bono\n * @author David Good\n * @author Madhura Bhave\n */\nclass SanitizerTests {\n\n\t@Test\n\tvoid whenNoSanitizationFunctionAndShowUnsanitizedIsFalse() {\n\t\tSanitizer sanitizer = new Sanitizer();\n\t\tassertThat(sanitizer.sanitize(new SanitizableData(null, \"password\", \"secret\"), false)).isEqualTo(\"******\");\n\t\tassertThat(sanitizer.sanitize(new SanitizableData(null, \"other\", \"something\"), false)).isEqualTo(\"******\");\n\t}\n\n\t@Test\n\tvoid whenNoSanitizationFunctionAndShowUnsanitizedIsTrue() {\n\t\tSanitizer sanitizer = new Sanitizer();\n\t\tassertThat(sanitizer.sanitize(new SanitizableData(null, \"password\", \"secret\"), true)).isEqualTo(\"secret\");\n\t\tassertThat(sanitizer.sanitize(new SanitizableData(null, \"other\", \"something\"), true)).isEqualTo(\"something\");\n\t}\n\n\t@Test\n\tvoid whenCustomSanitizationFunctionAndShowUnsanitizedIsFalse() {\n\t\tSanitizer sanitizer = new Sanitizer(Collections.singletonList((data) -> {\n\t\t\tif (data.getKey().equals(\"custom\")) {\n\t\t\t\treturn data.withValue(\"$$$$$$\");\n\t\t\t}\n\t\t\treturn data;\n\t\t}));\n\t\tSanitizableData secret = new SanitizableData(null, \"secret\", \"xyz\");\n\t\tassertThat(sanitizer.sanitize(secret, false)).isEqualTo(\"******\");\n\t\tSanitizableData custom = new SanitizableData(null, \"custom\", \"abcde\");\n\t\tassertThat(sanitizer.sanitize(custom, false)).isEqualTo(\"******\");\n\t\tSanitizableData hello = new SanitizableData(null, \"hello\", \"abc\");\n\t\tassertThat(sanitizer.sanitize(hello, false)).isEqualTo(\"******\");\n\t}\n\n\t@Test\n\tvoid whenCustomSanitizationFunctionAndShowUnsanitizedIsTrue() {\n\t\tSanitizer sanitizer = new Sanitizer(Collections.singletonList((data) -> {\n\t\t\tif (data.getKey().equals(\"custom\")) {\n\t\t\t\treturn data.withValue(\"$$$$$$\");\n\t\t\t}\n\t\t\treturn data;\n\t\t}));\n\t\tSanitizableData secret = new SanitizableData(null, \"secret\", \"xyz\");\n\t\tassertThat(sanitizer.sanitize(secret, true)).isEqualTo(\"xyz\");\n\t\tSanitizableData custom = new SanitizableData(null, \"custom\", \"abcde\");\n\t\tassertThat(sanitizer.sanitize(custom, true)).isEqualTo(\"$$$$$$\");\n\t\tSanitizableData hello = new SanitizableData(null, \"hello\", \"abc\");\n\t\tassertThat(sanitizer.sanitize(hello, true)).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid overridingDefaultSanitizingFunction() {\n\t\tSanitizer sanitizer = new Sanitizer(Collections.singletonList((data) -> {\n\t\t\tif (data.getKey().equals(\"password\")) {\n\t\t\t\treturn data.withValue(\"------\");\n\t\t\t}\n\t\t\treturn data;\n\t\t}));\n\t\tSanitizableData password = new SanitizableData(null, \"password\", \"123456\");\n\t\tassertThat(sanitizer.sanitize(password, true)).isEqualTo(\"------\");\n\t}\n\n\t@Test\n\tvoid overridingDefaultSanitizingFunctionWithFiltered() {\n\t\tSanitizer sanitizer = new Sanitizer(List.of(SanitizingFunction.sanitizeValue().ifLikelySensitive()));\n\t\tSanitizableData other = new SanitizableData(null, \"other\", \"123456\");\n\t\tSanitizableData password = new SanitizableData(null, \"password\", \"123456\");\n\t\tassertThat(sanitizer.sanitize(other, true)).isEqualTo(\"123456\");\n\t\tassertThat(sanitizer.sanitize(password, true)).isEqualTo(SanitizableData.SANITIZED_VALUE);\n\t}\n\n\t@Test\n\tvoid whenValueSanitizedLaterSanitizingFunctionsShouldBeSkipped() {\n\t\tfinal String sameKey = \"custom\";\n\t\tList<SanitizingFunction> sanitizingFunctions = new ArrayList<>();\n\t\tsanitizingFunctions.add((data) -> {\n\t\t\tif (data.getKey().equals(sameKey)) {\n\t\t\t\treturn data.withValue(\"------\");\n\t\t\t}\n\t\t\treturn data;\n\t\t});\n\t\tsanitizingFunctions.add((data) -> {\n\t\t\tif (data.getKey().equals(sameKey)) {\n\t\t\t\treturn data.withValue(\"******\");\n\t\t\t}\n\t\t\treturn data;\n\t\t});\n\t\tSanitizer sanitizer = new Sanitizer(sanitizingFunctions);\n\t\tSanitizableData custom = new SanitizableData(null, sameKey, \"123456\");\n\t\tassertThat(sanitizer.sanitize(custom, true)).isEqualTo(\"------\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/SanitizingFunctionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\n\nimport org.assertj.core.api.Condition;\nimport org.assertj.core.api.ObjectAssert;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SanitizingFunction}.\n *\n * @author Phillip Webb\n */\nclass SanitizingFunctionTests {\n\n\tprivate static final SanitizableData data = data(\"key\");\n\n\t@Test\n\tvoid applyUnlessFilteredWhenHasNoFilterReturnsFiltered() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue();\n\t\tassertThat(function.apply(data)).has(sanitizedValue());\n\t\tassertThat(function.applyUnlessFiltered(data)).has(sanitizedValue());\n\t}\n\n\t@Test\n\tvoid applyUnlessFilteredWhenHasFilterTestingTrueReturnsFiltered() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifMatches((data) -> true);\n\t\tassertThat(function.apply(data)).has(sanitizedValue());\n\t\tassertThat(function.applyUnlessFiltered(data)).has(sanitizedValue());\n\t}\n\n\t@Test\n\tvoid applyUnlessFilteredWhenHasFilterTestingFalseReturnsUnfiltered() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifMatches((data) -> false);\n\t\tassertThat(function.apply(data)).has(sanitizedValue());\n\t\tassertThat(function.applyUnlessFiltered(data)).has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifLikelySensitiveFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifLikelySensitive();\n\t\tassertThat(function).satisfies(this::likelyCredentialChecks, this::likelyUriChecks,\n\t\t\t\tthis::likelySensitivePropertyChecks, this::vcapServicesChecks);\n\t}\n\n\t@Test\n\tvoid ifLikelyCredentialFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifLikelyCredential();\n\t\tassertThat(function).satisfies(this::likelyCredentialChecks);\n\t}\n\n\tprivate void likelyCredentialChecks(SanitizingFunction function) {\n\t\tassertThatApplyingToKey(function, \"password\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"database.password\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"PASSWORD\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"secret\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"key\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"token\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"credentials\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"thecredentialssecret\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"some.credentials.here\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"test\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifLikelyUriFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifLikelyUri();\n\t\tassertThat(function).satisfies(this::likelyUriChecks);\n\t}\n\n\tprivate void likelyUriChecks(SanitizingFunction function) {\n\t\tassertThatApplyingToKey(function, \"uri\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"URI\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"database.uri\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"uris\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"url\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"urls\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"address\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"addresses\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"test\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifLikelySensitivePropertyFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifLikelySensitiveProperty();\n\t\tassertThat(function).satisfies(this::likelySensitivePropertyChecks);\n\t}\n\n\tprivate void likelySensitivePropertyChecks(SanitizingFunction function) {\n\t\tassertThatApplyingToKey(function, \"sun.java.command\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"spring.application.json\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SPRING_APPLICATION_JSON\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"some.other.json\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifVcapServicesFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifVcapServices();\n\t\tassertThat(function).satisfies(this::vcapServicesChecks);\n\t}\n\n\tprivate void vcapServicesChecks(SanitizingFunction function) {\n\t\tassertThatApplyingToKey(function, \"vcap_services\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"vcap.services\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"vcap.services.whatever\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"notvcap.services\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyEqualsFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifKeyEquals(\"spring\", \"test\");\n\t\tassertThatApplyingToKey(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SPRING\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SpRiNg\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"test\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"boot\").has(unsanitizedValue());\n\t\tassertThatApplyingToKey(function, \"xspring\").has(unsanitizedValue());\n\t\tassertThatApplyingToKey(function, \"springx\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyEndsWithFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifKeyEndsWith(\"boot\", \"test\");\n\t\tassertThatApplyingToKey(function, \"springboot\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SPRINGboot\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"springBOOT\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"boot\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"atest\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"bootx\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyContainsFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifKeyContains(\"oo\", \"ee\");\n\t\tassertThatApplyingToKey(function, \"oo\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"OO\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"bOOt\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"boot\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"beet\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"spring\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyMatchesIgnoringCaseFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifKeyMatchesIgnoringCase((key, value) -> key.startsWith(value) && key.endsWith(value), \"x\", \"y\");\n\t\tassertThatApplyingToKey(function, \"xtestx\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"XtestX\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"YY\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"xy\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyMatchesWithRegexFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifKeyMatches(\"^sp.*$\", \"^bo.*$\");\n\t\tassertThatApplyingToKey(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SPRING\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"BOOT\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"xspring\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyMatchesWithPatternFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifKeyMatches(Pattern.compile(\"^sp.*$\"));\n\t\tassertThatApplyingToKey(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SPRING\").has(unsanitizedValue());\n\t\tassertThatApplyingToKey(function, \"xspring\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyMatchesWithPredicatesFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifKeyMatches(List.of((key) -> key.startsWith(\"sp\"), (key) -> key.startsWith(\"BO\")));\n\t\tassertThatApplyingToKey(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"BO\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"SPRING\").has(unsanitizedValue());\n\t\tassertThatApplyingToKey(function, \"boot\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifKeyMatchesWithPredicateFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifKeyMatches((key) -> key.startsWith(\"sp\"));\n\t\tassertThatApplyingToKey(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToKey(function, \"boot\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifValueStringMatchesWithRegexesFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue().ifValueStringMatches(\"^sp.*$\", \"^bo.*$\");\n\t\tassertThatApplyingToValue(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"SPRING\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"boot\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"other\").has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifValueStringMatchesWithPatternsFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifValueStringMatches(Pattern.compile(\"^sp.*$\"));\n\t\tassertThatApplyingToValue(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"SPRING\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, \"xspring\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, null).has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifValueStringStringMatchesWithPredicatesFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifValueStringMatches(List.of((value) -> value.startsWith(\"sp\"), (value) -> value.startsWith(\"BO\")));\n\t\tassertThatApplyingToValue(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"BO\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"SPRING\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, \"boot\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, null).has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifValueStringMatchesWithPredicateFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifValueStringMatches((value) -> value.startsWith(\"sp\"));\n\t\tassertThatApplyingToValue(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"boot\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, null).has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifValueMatchesWithPredicatesFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifValueMatches(List.of((value) -> value instanceof String string && string.startsWith(\"sp\"),\n\t\t\t\t\t(value) -> value instanceof String string && string.startsWith(\"BO\")));\n\t\tassertThatApplyingToValue(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"BO\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"SPRING\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, \"boot\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, 123).has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, null).has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifValueMatchesWithPredicateFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifValueMatches((value) -> value instanceof String string && string.startsWith(\"sp\"));\n\t\tassertThatApplyingToValue(function, \"spring\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"spin\").has(sanitizedValue());\n\t\tassertThatApplyingToValue(function, \"boot\").has(unsanitizedValue());\n\t\tassertThatApplyingToValue(function, 123).has(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifMatchesPredicatesFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifMatches(List.of((data) -> data.getKey().startsWith(\"sp\") && \"boot\".equals(data.getValue()),\n\t\t\t\t\t(data) -> data.getKey().startsWith(\"sp\") && \"framework\".equals(data.getValue())));\n\t\tassertThatApplying(function, data(\"spring\", \"boot\")).is(sanitizedValue());\n\t\tassertThatApplying(function, data(\"spring\", \"framework\")).is(sanitizedValue());\n\t\tassertThatApplying(function, data(\"spring\", \"data\")).is(unsanitizedValue());\n\t\tassertThatApplying(function, data(\"spring\", null)).is(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ifMatchesPredicateFiltersExpected() {\n\t\tSanitizingFunction function = SanitizingFunction.sanitizeValue()\n\t\t\t.ifMatches((data) -> data.getKey().startsWith(\"sp\") && \"boot\".equals(data.getValue()));\n\t\tassertThatApplying(function, data(\"spring\", \"boot\")).is(sanitizedValue());\n\t\tassertThatApplying(function, data(\"spring\", \"framework\")).is(unsanitizedValue());\n\t\tassertThatApplying(function, data(\"spring\", \"data\")).is(unsanitizedValue());\n\t\tassertThatApplying(function, data(\"spring\", null)).is(unsanitizedValue());\n\t}\n\n\t@Test\n\tvoid ofAllowsChainingFromLambda() {\n\t\tSanitizingFunction function = SanitizingFunction.of((data) -> data.withValue(\"----\")).ifKeyContains(\"password\");\n\t\tassertThat(function.applyUnlessFiltered(data(\"username\", \"spring\")).getValue()).isEqualTo(\"spring\");\n\t\tassertThat(function.applyUnlessFiltered(data(\"password\", \"boot\")).getValue()).isEqualTo(\"----\");\n\t}\n\n\tprivate ObjectAssert<SanitizableData> assertThatApplyingToKey(SanitizingFunction function, String key) {\n\t\treturn assertThatApplying(function, data(key));\n\t}\n\n\tprivate ObjectAssert<SanitizableData> assertThatApplyingToValue(SanitizingFunction function,\n\t\t\t@Nullable Object value) {\n\t\treturn assertThatApplying(function, data(\"key\", value));\n\t}\n\n\tprivate ObjectAssert<SanitizableData> assertThatApplying(SanitizingFunction function, SanitizableData data) {\n\t\treturn assertThat(function.applyUnlessFiltered(data)).as(\"%s:%s\", data.getKey(), data.getValue());\n\t}\n\n\tprivate Condition<SanitizableData> sanitizedValue() {\n\t\treturn new Condition<>((data) -> Objects.equals(data.getValue(), SanitizableData.SANITIZED_VALUE),\n\t\t\t\t\"sanitized value\");\n\t}\n\n\tprivate Condition<SanitizableData> unsanitizedValue() {\n\t\treturn new Condition<>((data) -> !Objects.equals(data.getValue(), SanitizableData.SANITIZED_VALUE),\n\t\t\t\t\"unsanitized value\");\n\t}\n\n\tprivate static SanitizableData data(String key) {\n\t\treturn data(key, \"value\");\n\t}\n\n\tprivate static SanitizableData data(String key, @Nullable Object value) {\n\t\treturn new SanitizableData(null, key, value);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ShowTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint;\n\nimport java.security.Principal;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Show}.\n *\n * @author Madhura Bhave\n */\nclass ShowTests {\n\n\t@Test\n\tvoid isShownWhenNever() {\n\t\tassertThat(Show.NEVER.isShown(SecurityContext.NONE, Collections.emptySet())).isFalse();\n\t\tassertThat(Show.NEVER.isShown(true)).isFalse();\n\t\tassertThat(Show.NEVER.isShown(false)).isFalse();\n\t}\n\n\t@Test\n\tvoid isShownWhenAlways() {\n\t\tassertThat(Show.ALWAYS.isShown(SecurityContext.NONE, Collections.emptySet())).isTrue();\n\t\tassertThat(Show.ALWAYS.isShown(true)).isTrue();\n\t\tassertThat(Show.ALWAYS.isShown(true)).isTrue();\n\t}\n\n\t@Test\n\tvoid isShownWithUnauthorizedResult() {\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(true)).isTrue();\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(false)).isFalse();\n\t}\n\n\t@Test\n\tvoid isShownWhenUserNotInRole() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class));\n\t\tgiven(securityContext.isUserInRole(\"admin\")).willReturn(false);\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(securityContext, Collections.singleton(\"admin\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isShownWhenUserInRole() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class));\n\t\tgiven(securityContext.isUserInRole(\"admin\")).willReturn(true);\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(securityContext, Collections.singleton(\"admin\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid isShownWhenPrincipalNull() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.isUserInRole(\"admin\")).willReturn(true);\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(securityContext, Collections.singleton(\"admin\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isShownWhenRolesEmpty() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class));\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(securityContext, Collections.emptySet())).isTrue();\n\t}\n\n\t@Test\n\tvoid isShownWhenSpringSecurityAuthenticationAndUnauthorized() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tAuthentication authentication = mock(Authentication.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(authentication);\n\t\tgiven(authentication.getAuthorities())\n\t\t\t.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(\"other\")));\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(securityContext, Collections.singleton(\"admin\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isShownWhenSpringSecurityAuthenticationAndAuthorized() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tAuthentication authentication = mock(Authentication.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(authentication);\n\t\tgiven(authentication.getAuthorities())\n\t\t\t.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(\"admin\")));\n\t\tassertThat(Show.WHEN_AUTHORIZED.isShown(securityContext, Collections.singleton(\"admin\"))).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationMethodTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.reflect.Method;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.Producible;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DiscoveredOperationMethod}.\n *\n * @author Phillip Webb\n */\nclass DiscoveredOperationMethodTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenAnnotationAttributesIsNullShouldThrowException() {\n\t\tMethod method = getMethod();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DiscoveredOperationMethod(method, OperationType.READ, null))\n\t\t\t.withMessageContaining(\"'annotationAttributes' must not be null\");\n\t}\n\n\t@Test\n\tvoid getProducesMediaTypesShouldReturnMediaTypes() {\n\t\tMethod method = getMethod();\n\t\tAnnotationAttributes annotationAttributes = new AnnotationAttributes();\n\t\tString[] produces = new String[] { \"application/json\" };\n\t\tannotationAttributes.put(\"produces\", produces);\n\t\tannotationAttributes.put(\"producesFrom\", Producible.class);\n\t\tDiscoveredOperationMethod discovered = new DiscoveredOperationMethod(method, OperationType.READ,\n\t\t\t\tannotationAttributes);\n\t\tassertThat(discovered.getProducesMediaTypes()).containsExactly(\"application/json\");\n\t}\n\n\t@Test\n\tvoid getProducesMediaTypesWhenProducesFromShouldReturnMediaTypes() {\n\t\tMethod method = getMethod();\n\t\tAnnotationAttributes annotationAttributes = new AnnotationAttributes();\n\t\tannotationAttributes.put(\"produces\", new String[0]);\n\t\tannotationAttributes.put(\"producesFrom\", ExampleProducible.class);\n\t\tDiscoveredOperationMethod discovered = new DiscoveredOperationMethod(method, OperationType.READ,\n\t\t\t\tannotationAttributes);\n\t\tassertThat(discovered.getProducesMediaTypes()).containsExactly(\"one/*\", \"two/*\", \"three/*\");\n\t}\n\n\tprivate Method getMethod() {\n\t\tMethod method = ReflectionUtils.findMethod(getClass(), \"example\");\n\t\tassertThat(method).isNotNull();\n\t\treturn method;\n\t}\n\n\tvoid example() {\n\t}\n\n\tenum ExampleProducible implements Producible<ExampleProducible> {\n\n\t\tONE, TWO, THREE;\n\n\t\t@Override\n\t\tpublic MimeType getProducedMimeType() {\n\t\t\treturn new MimeType(toString().toLowerCase(Locale.ROOT));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscoveredOperationsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.Producible;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.util.MimeType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DiscoveredOperationsFactory}.\n *\n * @author Phillip Webb\n */\nclass DiscoveredOperationsFactoryTests {\n\n\tprivate TestDiscoveredOperationsFactory factory;\n\n\tprivate List<OperationInvokerAdvisor> invokerAdvisors;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tParameterValueMapper parameterValueMapper = (parameter, value) -> (value != null) ? value.toString() : null;\n\t\tthis.invokerAdvisors = new ArrayList<>();\n\t\tthis.factory = new TestDiscoveredOperationsFactory(parameterValueMapper, this.invokerAdvisors);\n\t}\n\n\t@Test\n\tvoid createOperationsWhenHasReadMethodShouldCreateOperation() {\n\t\tCollection<TestOperation> operations = this.factory.createOperations(EndpointId.of(\"test\"), new ExampleRead());\n\t\tassertThat(operations).hasSize(1);\n\t\tTestOperation operation = getFirst(operations);\n\t\tassertThat(operation.getType()).isEqualTo(OperationType.READ);\n\t}\n\n\t@Test\n\tvoid createOperationsWhenHasWriteMethodShouldCreateOperation() {\n\t\tCollection<TestOperation> operations = this.factory.createOperations(EndpointId.of(\"test\"), new ExampleWrite());\n\t\tassertThat(operations).hasSize(1);\n\t\tTestOperation operation = getFirst(operations);\n\t\tassertThat(operation.getType()).isEqualTo(OperationType.WRITE);\n\t}\n\n\t@Test\n\tvoid createOperationsWhenHasDeleteMethodShouldCreateOperation() {\n\t\tCollection<TestOperation> operations = this.factory.createOperations(EndpointId.of(\"test\"),\n\t\t\t\tnew ExampleDelete());\n\t\tassertThat(operations).hasSize(1);\n\t\tTestOperation operation = getFirst(operations);\n\t\tassertThat(operation.getType()).isEqualTo(OperationType.DELETE);\n\t}\n\n\t@Test\n\tvoid createOperationsWhenMultipleShouldReturnMultiple() {\n\t\tCollection<TestOperation> operations = this.factory.createOperations(EndpointId.of(\"test\"),\n\t\t\t\tnew ExampleMultiple());\n\t\tassertThat(operations).hasSize(2);\n\t\tassertThat(operations.stream().map(TestOperation::getType)).containsOnly(OperationType.READ,\n\t\t\t\tOperationType.WRITE);\n\t}\n\n\t@Test\n\tvoid createOperationsShouldProvideOperationMethod() {\n\t\tTestOperation operation = getFirst(\n\t\t\t\tthis.factory.createOperations(EndpointId.of(\"test\"), new ExampleWithParams()));\n\t\tOperationMethod operationMethod = operation.getOperationMethod();\n\t\tassertThat(operationMethod.getMethod().getName()).isEqualTo(\"read\");\n\t\tassertThat(operationMethod.getParameters().hasParameters()).isTrue();\n\t}\n\n\t@Test\n\tvoid createOperationsShouldProviderInvoker() {\n\t\tTestOperation operation = getFirst(\n\t\t\t\tthis.factory.createOperations(EndpointId.of(\"test\"), new ExampleWithParams()));\n\t\tMap<String, Object> params = Collections.singletonMap(\"name\", 123);\n\t\tObject result = operation.invoke(new InvocationContext(mock(SecurityContext.class), params));\n\t\tassertThat(result).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid createOperationShouldApplyAdvisors() {\n\t\tTestOperationInvokerAdvisor advisor = new TestOperationInvokerAdvisor();\n\t\tthis.invokerAdvisors.add(advisor);\n\t\tTestOperation operation = getFirst(this.factory.createOperations(EndpointId.of(\"test\"), new ExampleRead()));\n\t\toperation.invoke(new InvocationContext(mock(SecurityContext.class), Collections.emptyMap()));\n\t\tassertThat(advisor.getEndpointId()).isEqualTo(EndpointId.of(\"test\"));\n\t\tassertThat(advisor.getOperationType()).isEqualTo(OperationType.READ);\n\t\tassertThat(advisor.getParameters()).isEmpty();\n\t}\n\n\t@Test\n\tvoid createOperationShouldApplyProducesFrom() {\n\t\tTestOperation operation = getFirst(\n\t\t\t\tthis.factory.createOperations(EndpointId.of(\"test\"), new ExampleWithProducesFrom()));\n\t\tDiscoveredOperationMethod method = (DiscoveredOperationMethod) operation.getOperationMethod();\n\t\tassertThat(method.getProducesMediaTypes()).containsExactly(\"one/*\", \"two/*\", \"three/*\");\n\t}\n\n\tprivate <T> T getFirst(Iterable<T> iterable) {\n\t\treturn iterable.iterator().next();\n\t}\n\n\tstatic class ExampleRead {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t}\n\n\tstatic class ExampleWrite {\n\n\t\t@WriteOperation\n\t\tString write() {\n\t\t\treturn \"write\";\n\t\t}\n\n\t}\n\n\tstatic class ExampleDelete {\n\n\t\t@DeleteOperation\n\t\tString delete() {\n\t\t\treturn \"delete\";\n\t\t}\n\n\t}\n\n\tstatic class ExampleMultiple {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t\t@WriteOperation\n\t\tString write() {\n\t\t\treturn \"write\";\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithParams {\n\n\t\t@ReadOperation\n\t\tString read(String name) {\n\t\t\treturn name;\n\t\t}\n\n\t}\n\n\tstatic class ExampleWithProducesFrom {\n\n\t\t@ReadOperation(producesFrom = ExampleProducible.class)\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t}\n\n\tstatic class TestDiscoveredOperationsFactory extends DiscoveredOperationsFactory<TestOperation> {\n\n\t\tTestDiscoveredOperationsFactory(ParameterValueMapper parameterValueMapper,\n\t\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors) {\n\t\t\tsuper(parameterValueMapper, invokerAdvisors);\n\t\t}\n\n\t\t@Override\n\t\tprotected TestOperation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\t\tOperationInvoker invoker) {\n\t\t\treturn new TestOperation(endpointId, operationMethod, invoker);\n\t\t}\n\n\t}\n\n\tstatic class TestOperation extends AbstractDiscoveredOperation {\n\n\t\tTestOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {\n\t\t\tsuper(operationMethod, invoker);\n\t\t}\n\n\t}\n\n\tstatic class TestOperationInvokerAdvisor implements OperationInvokerAdvisor {\n\n\t\tprivate @Nullable EndpointId endpointId;\n\n\t\tprivate @Nullable OperationType operationType;\n\n\t\tprivate @Nullable OperationParameters parameters;\n\n\t\t@Override\n\t\tpublic OperationInvoker apply(EndpointId endpointId, OperationType operationType,\n\t\t\t\tOperationParameters parameters, OperationInvoker invoker) {\n\t\t\tthis.endpointId = endpointId;\n\t\t\tthis.operationType = operationType;\n\t\t\tthis.parameters = parameters;\n\t\t\treturn invoker;\n\t\t}\n\n\t\t@Nullable EndpointId getEndpointId() {\n\t\t\treturn this.endpointId;\n\t\t}\n\n\t\t@Nullable OperationType getOperationType() {\n\t\t\treturn this.operationType;\n\t\t}\n\n\t\t@Nullable OperationParameters getParameters() {\n\t\t\treturn this.parameters;\n\t\t}\n\n\t}\n\n\tenum ExampleProducible implements Producible<ExampleProducible> {\n\n\t\tONE, TWO, THREE;\n\n\t\t@Override\n\t\tpublic MimeType getProducedMimeType() {\n\t\t\treturn new MimeType(toString().toLowerCase(Locale.ROOT));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/DiscovererEndpointFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DiscovererEndpointFilter}.\n *\n * @author Phillip Webb\n */\nclass DiscovererEndpointFilterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenDiscovererIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TestDiscovererEndpointFilter(null))\n\t\t\t.withMessageContaining(\"'discoverer' must not be null\");\n\t}\n\n\t@Test\n\tvoid matchWhenDiscoveredByDiscovererShouldReturnTrue() {\n\t\tDiscovererEndpointFilter filter = new TestDiscovererEndpointFilter(TestDiscovererA.class);\n\t\tDiscoveredEndpoint<?> endpoint = mockDiscoveredEndpoint(TestDiscovererA.class);\n\t\tassertThat(filter.match(endpoint)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenNotDiscoveredByDiscovererShouldReturnFalse() {\n\t\tDiscovererEndpointFilter filter = new TestDiscovererEndpointFilter(TestDiscovererA.class);\n\t\tDiscoveredEndpoint<?> endpoint = mockDiscoveredEndpoint(TestDiscovererB.class);\n\t\tassertThat(filter.match(endpoint)).isFalse();\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate DiscoveredEndpoint<?> mockDiscoveredEndpoint(Class<?> discoverer) {\n\t\tDiscoveredEndpoint endpoint = mock(DiscoveredEndpoint.class);\n\t\tgiven(endpoint.wasDiscoveredBy(discoverer)).willReturn(true);\n\t\treturn endpoint;\n\t}\n\n\tstatic class TestDiscovererEndpointFilter extends DiscovererEndpointFilter {\n\n\t\tTestDiscovererEndpointFilter(Class<? extends EndpointDiscoverer<?, ?>> discoverer) {\n\t\t\tsuper(discoverer);\n\t\t}\n\n\t}\n\n\tabstract static class TestDiscovererA extends EndpointDiscoverer<ExposableEndpoint<Operation>, Operation> {\n\n\t\tTestDiscovererA(ApplicationContext applicationContext, ParameterValueMapper parameterValueMapper,\n\t\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\t\tCollection<EndpointFilter<ExposableEndpoint<Operation>>> filters) {\n\t\t\tsuper(applicationContext, parameterValueMapper, invokerAdvisors, filters, Collections.emptyList());\n\t\t}\n\n\t}\n\n\tabstract static class TestDiscovererB extends EndpointDiscoverer<ExposableEndpoint<Operation>, Operation> {\n\n\t\tTestDiscovererB(ApplicationContext applicationContext, ParameterValueMapper parameterValueMapper,\n\t\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\t\tCollection<EndpointFilter<ExposableEndpoint<Operation>>> filters) {\n\t\t\tsuper(applicationContext, parameterValueMapper, invokerAdvisors, filters, Collections.emptyList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/EndpointDiscovererTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;\nimport org.springframework.cglib.proxy.Enhancer;\nimport org.springframework.cglib.proxy.FixedValue;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EndpointDiscoverer}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass EndpointDiscovererTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenApplicationContextIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestEndpointDiscoverer(null, mock(ParameterValueMapper.class),\n\t\t\t\t\tCollections.emptyList(), Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'applicationContext' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenParameterValueMapperIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestEndpointDiscoverer(mock(ApplicationContext.class), null, Collections.emptyList(),\n\t\t\t\t\tCollections.emptyList()))\n\t\t\t.withMessageContaining(\"'parameterValueMapper' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenInvokerAdvisorsIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestEndpointDiscoverer(mock(ApplicationContext.class),\n\t\t\t\t\tmock(ParameterValueMapper.class), null, Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'invokerAdvisors' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenFiltersIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestEndpointDiscoverer(mock(ApplicationContext.class),\n\t\t\t\t\tmock(ParameterValueMapper.class), Collections.emptyList(), null))\n\t\t\t.withMessageContaining(\"'endpointFilters' must not be null\");\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {\n\t\tload(EmptyConfiguration.class, (context) -> {\n\t\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context);\n\t\t\tCollection<TestExposableEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\tassertThat(endpoints).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasEndpointShouldReturnEndpoint() {\n\t\tload(TestEndpointConfiguration.class, this::hasTestEndpoint);\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasEndpointInParentContextShouldReturnEndpoint() {\n\t\tAnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(\n\t\t\t\tTestEndpointConfiguration.class);\n\t\tloadWithParent(parent, EmptyConfiguration.class, this::hasTestEndpoint);\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasSubclassedEndpointShouldReturnEndpoint() {\n\t\tload(TestEndpointSubclassConfiguration.class, (context) -> {\n\t\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context);\n\t\t\tMap<EndpointId, TestExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tTestExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tMap<Method, TestOperation> operations = mapOperations(endpoint);\n\t\t\tassertThat(operations).hasSize(5);\n\t\t\tassertThat(operations).containsKeys(testEndpointMethods());\n\t\t\tassertThat(operations).containsKeys(ReflectionUtils.findMethod(TestEndpointSubclass.class,\n\t\t\t\t\t\"updateWithMoreArguments\", String.class, String.class, String.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTwoEndpointsHaveTheSameIdShouldThrowException() {\n\t\tload(ClashingEndpointConfiguration.class,\n\t\t\t\t(context) -> assertThatIllegalStateException()\n\t\t\t\t\t.isThrownBy(new TestEndpointDiscoverer(context)::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Found two endpoints with the id 'test': \"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenEndpointsArePrefixedWithScopedTargetShouldRegisterOnlyOneEndpoint() {\n\t\tload(ScopedTargetEndpointConfiguration.class, (context) -> {\n\t\t\tTestEndpoint expectedEndpoint = context.getBean(\"testEndpoint\", TestEndpoint.class);\n\t\t\tCollection<TestExposableEndpoint> endpoints = new TestEndpointDiscoverer(context).getEndpoints();\n\t\t\tassertThat(endpoints).flatExtracting(TestExposableEndpoint::getEndpointBean).containsOnly(expectedEndpoint);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTtlSetToZeroShouldNotCacheInvokeCalls() {\n\t\tload(TestEndpointConfiguration.class, (context) -> {\n\t\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context, (endpointId) -> 0L);\n\t\t\tMap<EndpointId, TestExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tTestExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tMap<Method, TestOperation> operations = mapOperations(endpoint);\n\t\t\toperations.values()\n\t\t\t\t.forEach((operation) -> assertThat(operation.getInvoker())\n\t\t\t\t\t.isNotInstanceOf(CachingOperationInvoker.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTtlSetByIdAndIdDoesNotMatchShouldNotCacheInvokeCalls() {\n\t\tload(TestEndpointConfiguration.class, (context) -> {\n\t\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context,\n\t\t\t\t\t(endpointId) -> (endpointId.equals(EndpointId.of(\"foo\")) ? 500L : 0L));\n\t\t\tMap<EndpointId, TestExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tTestExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tMap<Method, TestOperation> operations = mapOperations(endpoint);\n\t\t\toperations.values()\n\t\t\t\t.forEach((operation) -> assertThat(operation.getInvoker())\n\t\t\t\t\t.isNotInstanceOf(CachingOperationInvoker.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTtlSetByIdAndIdMatchesShouldCacheInvokeCalls() {\n\t\tload(TestEndpointConfiguration.class, (context) -> {\n\t\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context,\n\t\t\t\t\t(endpointId) -> (endpointId.equals(EndpointId.of(\"test\")) ? 500L : 0L));\n\t\t\tMap<EndpointId, TestExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tTestExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tMap<Method, TestOperation> operations = mapOperations(endpoint);\n\t\t\tTestOperation getAll = operations.get(findTestEndpointMethod(\"getAll\"));\n\t\t\tassertThat(getAll).isNotNull();\n\t\t\tTestOperation getOne = operations.get(findTestEndpointMethod(\"getOne\", String.class));\n\t\t\tassertThat(getOne).isNotNull();\n\t\t\tTestOperation update = operations\n\t\t\t\t.get(ReflectionUtils.findMethod(TestEndpoint.class, \"update\", String.class, String.class));\n\t\t\tassertThat(update).isNotNull();\n\t\t\tassertThat(((CachingOperationInvoker) getAll.getInvoker()).getTimeToLive()).isEqualTo(500);\n\t\t\tassertThat(getOne.getInvoker()).isNotInstanceOf(CachingOperationInvoker.class);\n\t\t\tassertThat(update.getInvoker()).isNotInstanceOf(CachingOperationInvoker.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasSpecializedFiltersInNonSpecializedDiscovererShouldFilterEndpoints() {\n\t\tload(SpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context);\n\t\t\tMap<EndpointId, TestExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasSpecializedFiltersInSpecializedDiscovererShouldNotFilterEndpoints() {\n\t\tload(SpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tSpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer(context);\n\t\t\tMap<EndpointId, SpecializedExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"), EndpointId.of(\"specialized\"),\n\t\t\t\t\tEndpointId.of(\"specialized-superclass\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldApplyExtensions() {\n\t\tload(SpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tSpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer(context);\n\t\t\tMap<EndpointId, SpecializedExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tSpecializedExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"specialized\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tMap<Method, SpecializedOperation> operations = mapOperations(endpoint);\n\t\t\tassertThat(operations).containsKeys(ReflectionUtils.findMethod(SpecializedExtension.class, \"getSpecial\"));\n\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointShouldFindParentExtension() {\n\t\tload(SubSpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tSpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer(context);\n\t\t\tMap<EndpointId, SpecializedExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tSpecializedExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"specialized\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tMap<Method, SpecializedOperation> operations = mapOperations(endpoint);\n\t\t\tassertThat(operations).containsKeys(ReflectionUtils.findMethod(SpecializedTestEndpoint.class, \"getAll\"));\n\t\t\tassertThat(operations).containsKeys(\n\t\t\t\t\tReflectionUtils.findMethod(SubSpecializedTestEndpoint.class, \"getSpecialOne\", String.class));\n\t\t\tassertThat(operations).containsKeys(ReflectionUtils.findMethod(SpecializedExtension.class, \"getSpecial\"));\n\t\t\tassertThat(operations).hasSize(3);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasProxiedEndpointShouldReturnEndpoint() {\n\t\tload(ProxiedSpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tSpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer(context);\n\t\t\tMap<EndpointId, SpecializedExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"), EndpointId.of(\"specialized\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldApplyEndpointFilters() {\n\t\tload(SpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tEndpointFilter<SpecializedExposableEndpoint> filter = (endpoint) -> {\n\t\t\t\tEndpointId id = endpoint.getEndpointId();\n\t\t\t\treturn !id.equals(EndpointId.of(\"specialized\")) && !id.equals(EndpointId.of(\"specialized-superclass\"));\n\t\t\t};\n\t\t\tSpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer(context,\n\t\t\t\t\tCollections.singleton(filter), Collections.emptyList());\n\t\t\tMap<EndpointId, SpecializedExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldApplyOperationFilters() {\n\t\tload(SpecializedEndpointsConfiguration.class, (context) -> {\n\t\t\tOperationFilter<SpecializedOperation> operationFilter = (operation, endpointId,\n\t\t\t\t\tdefaultAccess) -> operation.getType() == OperationType.READ;\n\t\t\tSpecializedEndpointDiscoverer discoverer = new SpecializedEndpointDiscoverer(context,\n\t\t\t\t\tCollections.emptyList(), List.of(operationFilter));\n\t\t\tMap<EndpointId, SpecializedExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints.values())\n\t\t\t\t.allSatisfy((endpoint) -> assertThat(endpoint.getOperations()).extracting(SpecializedOperation::getType)\n\t\t\t\t\t.containsOnly(OperationType.READ));\n\t\t});\n\t}\n\n\tprivate void hasTestEndpoint(AnnotationConfigApplicationContext context) {\n\t\tTestEndpointDiscoverer discoverer = new TestEndpointDiscoverer(context);\n\t\tMap<EndpointId, TestExposableEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\tTestExposableEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\tassertThat(endpoint).isNotNull();\n\t\tMap<Method, TestOperation> operations = mapOperations(endpoint);\n\t\tassertThat(operations).containsOnlyKeys(testEndpointMethods());\n\t}\n\n\tprivate Method[] testEndpointMethods() {\n\t\tList<Method> methods = new ArrayList<>();\n\t\tmethods.add(findTestEndpointMethod(\"getAll\"));\n\t\tmethods.add(findTestEndpointMethod(\"getOne\", String.class));\n\t\tmethods.add(findTestEndpointMethod(\"update\", String.class, String.class));\n\t\tmethods.add(findTestEndpointMethod(\"deleteOne\", String.class));\n\t\treturn methods.toArray(new Method[0]);\n\t}\n\n\tprivate Method findTestEndpointMethod(String name, Class<?>... paramTypes) {\n\t\tMethod method = ReflectionUtils.findMethod(TestEndpoint.class, name, paramTypes);\n\t\tassertThat(method).isNotNull();\n\t\treturn method;\n\t}\n\n\tprivate <E extends ExposableEndpoint<?>> Map<EndpointId, E> mapEndpoints(Collection<E> endpoints) {\n\t\tMap<EndpointId, E> byId = new LinkedHashMap<>();\n\t\tendpoints.forEach((endpoint) -> {\n\t\t\tE existing = byId.put(endpoint.getEndpointId(), endpoint);\n\t\t\tif (existing != null) {\n\t\t\t\tthrow new AssertionError(\n\t\t\t\t\t\tString.format(\"Found endpoints with duplicate id '%s'\", endpoint.getEndpointId()));\n\t\t\t}\n\t\t});\n\t\treturn byId;\n\t}\n\n\tprivate <O extends Operation> Map<Method, O> mapOperations(ExposableEndpoint<O> endpoint) {\n\t\tMap<Method, O> byMethod = new HashMap<>();\n\t\tendpoint.getOperations().forEach((operation) -> {\n\t\t\tAbstractDiscoveredOperation discoveredOperation = (AbstractDiscoveredOperation) operation;\n\t\t\tMethod method = discoveredOperation.getOperationMethod().getMethod();\n\t\t\tO existing = byMethod.put(method, operation);\n\t\t\tif (existing != null) {\n\t\t\t\tthrow new AssertionError(String.format(\"Found endpoint with duplicate operation method '%s'\", method));\n\t\t\t}\n\t\t});\n\t\treturn byMethod;\n\t}\n\n\tprivate void load(Class<?> configuration, Consumer<AnnotationConfigApplicationContext> consumer) {\n\t\tload(null, configuration, consumer);\n\t}\n\n\tprivate void loadWithParent(@Nullable ApplicationContext parent, Class<?> configuration,\n\t\t\tConsumer<AnnotationConfigApplicationContext> consumer) {\n\t\tload(parent, configuration, consumer);\n\t}\n\n\tprivate void load(@Nullable ApplicationContext parent, Class<?> configuration,\n\t\t\tConsumer<AnnotationConfigApplicationContext> consumer) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\ttry (context) {\n\t\t\tif (parent != null) {\n\t\t\t\tcontext.setParent(parent);\n\t\t\t}\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tconsumer.accept(context);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ProxiedSpecializedTestEndpointConfiguration {\n\n\t\t@Bean\n\t\tSpecializedExtension specializedExtension() {\n\t\t\tEnhancer enhancer = new Enhancer();\n\t\t\tenhancer.setSuperclass(SpecializedExtension.class);\n\t\t\tenhancer.setCallback((FixedValue) () -> null);\n\t\t\treturn (SpecializedExtension) enhancer.create();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestEndpointSubclassConfiguration {\n\n\t\t@Bean\n\t\tTestEndpointSubclass testEndpointSubclass() {\n\t\t\treturn new TestEndpointSubclass();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpointTwo() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint testEndpointOne() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ScopedTargetEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean(name = \"scopedTarget.testEndpoint\")\n\t\tTestEndpoint scopedTargetTestEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t}\n\n\t@Import({ TestEndpoint.class, SpecializedTestEndpoint.class, SpecializedSuperclassTestEndpoint.class,\n\t\t\tSpecializedExtension.class })\n\tstatic class SpecializedEndpointsConfiguration {\n\n\t}\n\n\t@Import({ TestEndpoint.class, SubSpecializedTestEndpoint.class, SpecializedExtension.class })\n\tstatic class SubSpecializedEndpointsConfiguration {\n\n\t}\n\n\t@Import({ TestEndpoint.class, SpecializedTestEndpoint.class, ProxiedSpecializedTestEndpointConfiguration.class })\n\tstatic class ProxiedSpecializedEndpointsConfiguration {\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object getOne(@Selector String id) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid update(String foo, String bar) {\n\n\t\t}\n\n\t\t@DeleteOperation\n\t\tvoid deleteOne(@Selector String id) {\n\n\t\t}\n\n\t\tvoid someOtherMethod() {\n\n\t\t}\n\n\t}\n\n\tstatic class TestEndpointSubclass extends TestEndpoint {\n\n\t\t@WriteOperation\n\t\tvoid updateWithMoreArguments(String foo, String bar, String baz) {\n\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Endpoint\n\t@FilteredEndpoint(SpecializedEndpointFilter.class)\n\t@interface SpecializedEndpoint {\n\n\t\t@AliasFor(annotation = Endpoint.class)\n\t\tString id();\n\n\t}\n\n\t@EndpointExtension(endpoint = SpecializedTestEndpoint.class, filter = SpecializedEndpointFilter.class)\n\tstatic class SpecializedExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getSpecial() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class SpecializedEndpointFilter extends DiscovererEndpointFilter {\n\n\t\tSpecializedEndpointFilter() {\n\t\t\tsuper(SpecializedEndpointDiscoverer.class);\n\t\t}\n\n\t}\n\n\t@SpecializedEndpoint(id = \"specialized\")\n\tstatic class SpecializedTestEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@SpecializedEndpoint(id = \"specialized-superclass\")\n\tstatic class AbstractFilteredEndpoint {\n\n\t}\n\n\tstatic class SpecializedSuperclassTestEndpoint extends AbstractFilteredEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class SubSpecializedTestEndpoint extends SpecializedTestEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getSpecialOne(@Selector String id) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class TestEndpointDiscoverer extends EndpointDiscoverer<TestExposableEndpoint, TestOperation> {\n\n\t\tTestEndpointDiscoverer(ApplicationContext applicationContext) {\n\t\t\tthis(applicationContext, (id) -> null);\n\t\t}\n\n\t\tTestEndpointDiscoverer(ApplicationContext applicationContext, Function<EndpointId, @Nullable Long> timeToLive) {\n\t\t\tthis(applicationContext, timeToLive, Collections.emptyList());\n\t\t}\n\n\t\tTestEndpointDiscoverer(ApplicationContext applicationContext, Function<EndpointId, @Nullable Long> timeToLive,\n\t\t\t\tCollection<EndpointFilter<TestExposableEndpoint>> filters) {\n\t\t\tthis(applicationContext, new ConversionServiceParameterValueMapper(),\n\t\t\t\t\tCollections.singleton(new CachingOperationInvokerAdvisor(timeToLive)), filters);\n\t\t}\n\n\t\tTestEndpointDiscoverer(ApplicationContext applicationContext, ParameterValueMapper parameterValueMapper,\n\t\t\t\tCollection<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\t\tCollection<EndpointFilter<TestExposableEndpoint>> filters) {\n\t\t\tsuper(applicationContext, parameterValueMapper, invokerAdvisors, filters, Collections.emptyList());\n\t\t}\n\n\t\t@Override\n\t\tprotected TestExposableEndpoint createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\t\tCollection<TestOperation> operations) {\n\t\t\treturn new TestExposableEndpoint(this, endpointBean, id, defaultAccess, operations);\n\t\t}\n\n\t\t@Override\n\t\tprotected TestOperation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\t\tOperationInvoker invoker) {\n\t\t\treturn new TestOperation(operationMethod, invoker);\n\t\t}\n\n\t\t@Override\n\t\tprotected OperationKey createOperationKey(TestOperation operation) {\n\t\t\treturn new OperationKey(operation.getOperationMethod(),\n\t\t\t\t\t() -> \"TestOperation \" + operation.getOperationMethod());\n\t\t}\n\n\t}\n\n\tstatic class SpecializedEndpointDiscoverer\n\t\t\textends EndpointDiscoverer<SpecializedExposableEndpoint, SpecializedOperation> {\n\n\t\tSpecializedEndpointDiscoverer(ApplicationContext applicationContext) {\n\t\t\tthis(applicationContext, Collections.emptyList(), Collections.emptyList());\n\t\t}\n\n\t\tSpecializedEndpointDiscoverer(ApplicationContext applicationContext,\n\t\t\t\tCollection<EndpointFilter<SpecializedExposableEndpoint>> filters,\n\t\t\t\tCollection<OperationFilter<SpecializedOperation>> operationFilters) {\n\t\t\tsuper(applicationContext, new ConversionServiceParameterValueMapper(), Collections.emptyList(), filters,\n\t\t\t\t\toperationFilters);\n\t\t}\n\n\t\t@Override\n\t\tprotected SpecializedExposableEndpoint createEndpoint(Object endpointBean, EndpointId id, Access defaultAccess,\n\t\t\t\tCollection<SpecializedOperation> operations) {\n\t\t\treturn new SpecializedExposableEndpoint(this, endpointBean, id, defaultAccess, operations);\n\t\t}\n\n\t\t@Override\n\t\tprotected SpecializedOperation createOperation(EndpointId endpointId, DiscoveredOperationMethod operationMethod,\n\t\t\t\tOperationInvoker invoker) {\n\t\t\treturn new SpecializedOperation(operationMethod, invoker);\n\t\t}\n\n\t\t@Override\n\t\tprotected OperationKey createOperationKey(SpecializedOperation operation) {\n\t\t\treturn new OperationKey(operation.getOperationMethod(),\n\t\t\t\t\t() -> \"TestOperation \" + operation.getOperationMethod());\n\t\t}\n\n\t}\n\n\tstatic class TestExposableEndpoint extends AbstractDiscoveredEndpoint<TestOperation> {\n\n\t\tTestExposableEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id,\n\t\t\t\tAccess defaultAccess, Collection<? extends TestOperation> operations) {\n\t\t\tsuper(discoverer, endpointBean, id, defaultAccess, operations);\n\t\t}\n\n\t}\n\n\tstatic class SpecializedExposableEndpoint extends AbstractDiscoveredEndpoint<SpecializedOperation> {\n\n\t\t@SuppressWarnings(\"removal\")\n\t\tSpecializedExposableEndpoint(EndpointDiscoverer<?, ?> discoverer, Object endpointBean, EndpointId id,\n\t\t\t\tAccess defaultAccess, Collection<? extends SpecializedOperation> operations) {\n\t\t\tsuper(discoverer, endpointBean, id, defaultAccess, operations);\n\t\t}\n\n\t}\n\n\tstatic class TestOperation extends AbstractDiscoveredOperation {\n\n\t\tprivate final OperationInvoker invoker;\n\n\t\tTestOperation(DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {\n\t\t\tsuper(operationMethod, invoker);\n\t\t\tthis.invoker = invoker;\n\t\t}\n\n\t\tOperationInvoker getInvoker() {\n\t\t\treturn this.invoker;\n\t\t}\n\n\t}\n\n\tstatic class SpecializedOperation extends TestOperation {\n\n\t\tSpecializedOperation(DiscoveredOperationMethod operationMethod, OperationInvoker invoker) {\n\t\t\tsuper(operationMethod, invoker);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/annotation/OperationReflectiveProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.annotation;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OperationReflectiveProcessor}.\n *\n * @author Moritz Halbritter\n * @author Stephane Nicoll\n */\nclass OperationReflectiveProcessorTests {\n\n\tprivate final OperationReflectiveProcessor processor = new OperationReflectiveProcessor();\n\n\tprivate final RuntimeHints runtimeHints = new RuntimeHints();\n\n\t@Test\n\tvoid shouldRegisterMethodAsInvokable() {\n\t\tMethod method = ReflectionUtils.findMethod(Methods.class, \"string\");\n\t\tassertThat(method).isNotNull();\n\t\trunProcessor(method);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(method)).accepts(this.runtimeHints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterReturnType() {\n\t\tMethod method = ReflectionUtils.findMethod(Methods.class, \"dto\");\n\t\tassertThat(method).isNotNull();\n\t\trunProcessor(method);\n\t\tassertHintsForDto();\n\t}\n\n\t@Test\n\tvoid shouldRegisterMapValueFromReturnType() {\n\t\tMethod method = ReflectionUtils.findMethod(Methods.class, \"dtos\");\n\t\tassertThat(method).isNotNull();\n\t\trunProcessor(method);\n\t\tassertHintsForDto();\n\t}\n\n\t@Test\n\tvoid shouldRegisterWebEndpointResponseReturnType() {\n\t\tMethod method = ReflectionUtils.findMethod(Methods.class, \"webEndpointResponse\");\n\t\tassertThat(method).isNotNull();\n\t\trunProcessor(method);\n\t\tassertHintsForDto();\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(WebEndpointResponse.class)).rejects(this.runtimeHints);\n\t}\n\n\t@Test\n\tvoid shouldNotRegisterResourceReturnType() {\n\t\tMethod method = ReflectionUtils.findMethod(Methods.class, \"resource\");\n\t\tassertThat(method).isNotNull();\n\t\trunProcessor(method);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Resource.class)).rejects(this.runtimeHints);\n\t}\n\n\tprivate void assertHintsForDto() {\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(Dto.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(NestedDto.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(this.runtimeHints);\n\t}\n\n\tprivate void runProcessor(Method method) {\n\t\tthis.processor.registerReflectionHints(this.runtimeHints.reflection(), method);\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tprivate static final class Methods {\n\n\t\tprivate @Nullable String string() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable Map<String, List<Dto>> dtos() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable Dto dto() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable WebEndpointResponse<Dto> webEndpointResponse() {\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable Resource resource() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tpublic static class Dto {\n\n\t\tprivate final NestedDto nestedDto = new NestedDto();\n\n\t\tpublic NestedDto getNestedDto() {\n\t\t\treturn this.nestedDto;\n\t\t}\n\n\t}\n\n\tpublic static class NestedDto {\n\n\t\tprivate final String string = \"some-string\";\n\n\t\tpublic String getString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/convert/ConversionServiceParameterValueMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.convert;\n\nimport java.lang.annotation.Annotation;\nimport java.time.OffsetDateTime;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterMappingException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.format.support.DefaultFormattingConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ConversionServiceParameterValueMapper}.\n *\n * @author Phillip Webb\n */\nclass ConversionServiceParameterValueMapperTests {\n\n\t@Test\n\tvoid mapParameterShouldDelegateToConversionService() {\n\t\tDefaultFormattingConversionService conversionService = spy(new DefaultFormattingConversionService());\n\t\tConversionServiceParameterValueMapper mapper = new ConversionServiceParameterValueMapper(conversionService);\n\t\tObject mapped = mapper.mapParameterValue(new TestOperationParameter(Integer.class), \"123\");\n\t\tassertThat(mapped).isEqualTo(123);\n\t\tthen(conversionService).should().convert(\"123\", Integer.class);\n\t}\n\n\t@Test\n\tvoid mapParameterWhenConversionServiceFailsShouldThrowParameterMappingException() {\n\t\tConversionService conversionService = mock(ConversionService.class);\n\t\tRuntimeException error = new RuntimeException();\n\t\tgiven(conversionService.convert(any(Object.class), eq(Integer.class))).willThrow(error);\n\t\tConversionServiceParameterValueMapper mapper = new ConversionServiceParameterValueMapper(conversionService);\n\t\tassertThatExceptionOfType(ParameterMappingException.class)\n\t\t\t.isThrownBy(() -> mapper.mapParameterValue(new TestOperationParameter(Integer.class), \"123\"))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(ex.getValue()).isEqualTo(\"123\");\n\t\t\t\tassertThat(ex.getParameter().getType()).isEqualTo(Integer.class);\n\t\t\t\tassertThat(ex.getCause()).isEqualTo(error);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createShouldRegisterIsoOffsetDateTimeConverter() {\n\t\tConversionServiceParameterValueMapper mapper = new ConversionServiceParameterValueMapper();\n\t\tObject mapped = mapper.mapParameterValue(new TestOperationParameter(OffsetDateTime.class),\n\t\t\t\t\"2011-12-03T10:15:30+01:00\");\n\t\tassertThat(mapped).isNotNull();\n\t}\n\n\t@Test\n\tvoid createWithConversionServiceShouldNotRegisterIsoOffsetDateTimeConverter() {\n\t\tConversionService conversionService = new DefaultConversionService();\n\t\tConversionServiceParameterValueMapper mapper = new ConversionServiceParameterValueMapper(conversionService);\n\t\tassertThatExceptionOfType(ParameterMappingException.class).isThrownBy(() -> mapper\n\t\t\t.mapParameterValue(new TestOperationParameter(OffsetDateTime.class), \"2011-12-03T10:15:30+01:00\"));\n\t}\n\n\tstatic class TestOperationParameter implements OperationParameter {\n\n\t\tprivate final Class<?> type;\n\n\t\tTestOperationParameter(Class<?> type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getName() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isMandatory() {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic <T extends Annotation> @Nullable T getAnnotation(Class<T> annotation) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/convert/IsoOffsetDateTimeConverterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.convert;\n\nimport java.time.OffsetDateTime;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.convert.support.DefaultConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IsoOffsetDateTimeConverter}.\n *\n * @author Phillip Webb\n */\nclass IsoOffsetDateTimeConverterTests {\n\n\t@Test\n\tvoid convertShouldConvertIsoDate() {\n\t\tIsoOffsetDateTimeConverter converter = new IsoOffsetDateTimeConverter();\n\t\tOffsetDateTime time = converter.convert(\"2011-12-03T10:15:30+01:00\");\n\t\tassertThat(time).isNotNull();\n\t}\n\n\t@Test\n\tvoid registerConverterShouldRegister() {\n\t\tDefaultConversionService service = new DefaultConversionService();\n\t\tIsoOffsetDateTimeConverter.registerConverter(service);\n\t\tOffsetDateTime time = service.convert(\"2011-12-03T10:15:30+01:00\", OffsetDateTime.class);\n\t\tassertThat(time).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParameterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OperationMethodParameter}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass OperationMethodParameterTests {\n\n\tprivate final Method example = findMethod(\"example\", String.class, String.class);\n\n\tprivate final Method exampleSpringNullable = findMethod(\"exampleSpringNullable\", String.class, String.class);\n\n\tprivate final Method exampleAnnotation = findMethod(\"exampleAnnotation\", String.class);\n\n\t@Test\n\tvoid getNameShouldReturnName() {\n\t\tOperationMethodParameter parameter = new OperationMethodParameter(\"name\", this.example.getParameters()[0]);\n\t\tassertThat(parameter.getName()).isEqualTo(\"name\");\n\t}\n\n\t@Test\n\tvoid getTypeShouldReturnType() {\n\t\tOperationMethodParameter parameter = new OperationMethodParameter(\"name\", this.example.getParameters()[0]);\n\t\tassertThat(parameter.getType()).isEqualTo(String.class);\n\t}\n\n\t@Test\n\tvoid isMandatoryWhenNoAnnotationShouldReturnTrue() {\n\t\tOperationMethodParameter parameter = new OperationMethodParameter(\"name\", this.example.getParameters()[0]);\n\t\tassertThat(parameter.isMandatory()).isTrue();\n\t}\n\n\t@Test\n\tvoid isMandatoryWhenNullableAnnotationShouldReturnFalse() {\n\t\tOperationMethodParameter parameter = new OperationMethodParameter(\"name\", this.example.getParameters()[1]);\n\t\tassertThat(parameter.isMandatory()).isFalse();\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\")\n\tvoid isMandatoryWhenSpringNullableAnnotationShouldReturnFalse() {\n\t\tOperationMethodParameter parameter = new OperationMethodParameter(\"name\",\n\t\t\t\tthis.exampleSpringNullable.getParameters()[1]);\n\t\tassertThat(parameter.isMandatory()).isFalse();\n\t}\n\n\t@Test\n\tvoid getAnnotationShouldReturnAnnotation() {\n\t\tOperationMethodParameter parameter = new OperationMethodParameter(\"name\",\n\t\t\t\tthis.exampleAnnotation.getParameters()[0]);\n\t\tSelector annotation = parameter.getAnnotation(Selector.class);\n\t\tassertThat(annotation).isNotNull();\n\t\tassertThat(annotation.match()).isEqualTo(Match.ALL_REMAINING);\n\t}\n\n\tprivate Method findMethod(String name, Class<?>... parameters) {\n\t\tMethod method = ReflectionUtils.findMethod(getClass(), name, parameters);\n\t\tassertThat(method).as(\"Method '%s'\", name).isNotNull();\n\t\treturn method;\n\t}\n\n\tvoid example(String one, @org.jspecify.annotations.Nullable String two) {\n\t}\n\n\t@Deprecated(since = \"4.0.0\")\n\tvoid exampleSpringNullable(String one, @org.springframework.lang.Nullable String two) {\n\t}\n\n\tvoid exampleAnnotation(@Selector(match = Match.ALL_REMAINING) String allRemaining) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodParametersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Spliterator;\nimport java.util.Spliterators;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.core.DefaultParameterNameDiscoverer;\nimport org.springframework.core.ParameterNameDiscoverer;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OperationMethodParameters}.\n *\n * @author Phillip Webb\n */\nclass OperationMethodParametersTests {\n\n\tprivate final Method exampleMethod = findMethod(\"example\", String.class);\n\n\tprivate final Method exampleNoParamsMethod = findMethod(\"exampleNoParams\");\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenMethodIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new OperationMethodParameters(null, mock(ParameterNameDiscoverer.class)))\n\t\t\t.withMessageContaining(\"'method' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenParameterNameDiscovererIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new OperationMethodParameters(this.exampleMethod, null))\n\t\t\t.withMessageContaining(\"'parameterNameDiscoverer' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenParameterNameDiscovererReturnsNullShouldThrowException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OperationMethodParameters(this.exampleMethod, mock(ParameterNameDiscoverer.class)))\n\t\t\t.withMessageContaining(\"Failed to extract parameter names\");\n\t}\n\n\t@Test\n\tvoid hasParametersWhenHasParametersShouldReturnTrue() {\n\t\tOperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,\n\t\t\t\tnew DefaultParameterNameDiscoverer());\n\t\tassertThat(parameters.hasParameters()).isTrue();\n\t}\n\n\t@Test\n\tvoid hasParametersWhenHasNoParametersShouldReturnFalse() {\n\t\tOperationMethodParameters parameters = new OperationMethodParameters(this.exampleNoParamsMethod,\n\t\t\t\tnew DefaultParameterNameDiscoverer());\n\t\tassertThat(parameters.hasParameters()).isFalse();\n\t}\n\n\t@Test\n\tvoid getParameterCountShouldReturnParameterCount() {\n\t\tOperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,\n\t\t\t\tnew DefaultParameterNameDiscoverer());\n\t\tassertThat(parameters.getParameterCount()).isOne();\n\t}\n\n\t@Test\n\tvoid iteratorShouldIterateOperationParameters() {\n\t\tOperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,\n\t\t\t\tnew DefaultParameterNameDiscoverer());\n\t\tIterator<OperationParameter> iterator = parameters.iterator();\n\t\tassertParameters(\n\t\t\t\tStreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false));\n\t}\n\n\t@Test\n\tvoid streamShouldStreamOperationParameters() {\n\t\tOperationMethodParameters parameters = new OperationMethodParameters(this.exampleMethod,\n\t\t\t\tnew DefaultParameterNameDiscoverer());\n\t\tassertParameters(parameters.stream());\n\t}\n\n\tprivate Method findMethod(String name, Class<?>... parameters) {\n\t\tMethod method = ReflectionUtils.findMethod(getClass(), name, parameters);\n\t\tassertThat(method).as(\"Method '%s'\", name).isNotNull();\n\t\treturn method;\n\t}\n\n\tprivate void assertParameters(Stream<OperationParameter> stream) {\n\t\tList<OperationParameter> parameters = stream.toList();\n\t\tassertThat(parameters).hasSize(1);\n\t\tOperationParameter parameter = parameters.get(0);\n\t\tassertThat(parameter.getName()).isEqualTo(\"name\");\n\t\tassertThat(parameter.getType()).isEqualTo(String.class);\n\t}\n\n\tString example(String name) {\n\t\treturn name;\n\t}\n\n\tString exampleNoParams() {\n\t\treturn \"example\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/OperationMethodTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link OperationMethod}.\n *\n * @author Phillip Webb\n */\nclass OperationMethodTests {\n\n\tprivate final Method exampleMethod = findMethod(\"example\", String.class);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenMethodIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new OperationMethod(null, OperationType.READ))\n\t\t\t.withMessageContaining(\"'method' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenOperationTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new OperationMethod(this.exampleMethod, null))\n\t\t\t.withMessageContaining(\"'operationType' must not be null\");\n\t}\n\n\t@Test\n\tvoid getMethodShouldReturnMethod() {\n\t\tOperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ);\n\t\tassertThat(operationMethod.getMethod()).isEqualTo(this.exampleMethod);\n\t}\n\n\t@Test\n\tvoid getOperationTypeShouldReturnOperationType() {\n\t\tOperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ);\n\t\tassertThat(operationMethod.getOperationType()).isEqualTo(OperationType.READ);\n\t}\n\n\t@Test\n\tvoid getParametersShouldReturnParameters() {\n\t\tOperationMethod operationMethod = new OperationMethod(this.exampleMethod, OperationType.READ);\n\t\tOperationParameters parameters = operationMethod.getParameters();\n\t\tassertThat(parameters.getParameterCount()).isOne();\n\t\tassertThat(parameters.iterator().next().getName()).isEqualTo(\"name\");\n\t}\n\n\tString example(String name) {\n\t\treturn name;\n\t}\n\n\tprivate Method findMethod(String name, Class<?>... parameters) {\n\t\tMethod method = ReflectionUtils.findMethod(getClass(), name, parameters);\n\t\tassertThat(method).as(\"Method '%s'\", name).isNotNull();\n\t\treturn method;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoke/reflect/ReflectiveOperationInvokerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoke.reflect;\n\nimport java.lang.reflect.Method;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.MissingParametersException;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReflectiveOperationInvoker}.\n *\n * @author Phillip Webb\n */\nclass ReflectiveOperationInvokerTests {\n\n\tprivate Example target;\n\n\tprivate OperationMethod operationMethod;\n\n\tprivate ParameterValueMapper parameterValueMapper;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.target = new Example();\n\t\tthis.operationMethod = new OperationMethod(\n\t\t\t\tfindMethod(\"reverse\", ApiVersion.class, SecurityContext.class, String.class), OperationType.READ);\n\t\tthis.parameterValueMapper = (parameter, value) -> (value != null) ? value.toString() : null;\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenTargetIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ReflectiveOperationInvoker(null, this.operationMethod, this.parameterValueMapper))\n\t\t\t.withMessageContaining(\"'target' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenOperationMethodIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ReflectiveOperationInvoker(this.target, null, this.parameterValueMapper))\n\t\t\t.withMessageContaining(\"'operationMethod' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenParameterValueMapperIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ReflectiveOperationInvoker(this.target, this.operationMethod, null))\n\t\t\t.withMessageContaining(\"'parameterValueMapper' must not be null\");\n\t}\n\n\t@Test\n\tvoid invokeShouldInvokeMethod() {\n\t\tReflectiveOperationInvoker invoker = new ReflectiveOperationInvoker(this.target, this.operationMethod,\n\t\t\t\tthis.parameterValueMapper);\n\t\tObject result = invoker\n\t\t\t.invoke(new InvocationContext(mock(SecurityContext.class), Collections.singletonMap(\"name\", \"boot\")));\n\t\tassertThat(result).isEqualTo(\"toob\");\n\t}\n\n\t@Test\n\tvoid invokeWhenMissingNonOptionalArgumentShouldThrowException() {\n\t\tReflectiveOperationInvoker invoker = new ReflectiveOperationInvoker(this.target, this.operationMethod,\n\t\t\t\tthis.parameterValueMapper);\n\t\tassertThatExceptionOfType(MissingParametersException.class).isThrownBy(() -> invoker\n\t\t\t.invoke(new InvocationContext(mock(SecurityContext.class), Collections.singletonMap(\"name\", null))));\n\t}\n\n\t@Test\n\tvoid invokeWhenMissingOptionalArgumentShouldInvoke() {\n\t\tOperationMethod operationMethod = new OperationMethod(\n\t\t\t\tfindMethod(\"reverseOptional\", ApiVersion.class, SecurityContext.class, String.class),\n\t\t\t\tOperationType.READ);\n\t\tReflectiveOperationInvoker invoker = new ReflectiveOperationInvoker(this.target, operationMethod,\n\t\t\t\tthis.parameterValueMapper);\n\t\tObject result = invoker\n\t\t\t.invoke(new InvocationContext(mock(SecurityContext.class), Collections.singletonMap(\"name\", null)));\n\t\tassertThat(result).isEqualTo(\"llun\");\n\t}\n\n\t@Test\n\tvoid invokeShouldResolveParameters() {\n\t\tReflectiveOperationInvoker invoker = new ReflectiveOperationInvoker(this.target, this.operationMethod,\n\t\t\t\tthis.parameterValueMapper);\n\t\tObject result = invoker\n\t\t\t.invoke(new InvocationContext(mock(SecurityContext.class), Collections.singletonMap(\"name\", 1234)));\n\t\tassertThat(result).isEqualTo(\"4321\");\n\t}\n\n\tprivate Method findMethod(String name, Class<?>... parameters) {\n\t\tMethod method = ReflectionUtils.findMethod(Example.class, name, parameters);\n\t\tassertThat(method).as(\"Method '%s'\", name).isNotNull();\n\t\treturn method;\n\t}\n\n\tstatic class Example {\n\n\t\tString reverse(ApiVersion apiVersion, SecurityContext securityContext, String name) {\n\t\t\tassertThat(apiVersion).isEqualTo(ApiVersion.LATEST);\n\t\t\tassertThat(securityContext).isNotNull();\n\t\t\treturn new StringBuilder(name).reverse().toString();\n\t\t}\n\n\t\tString reverseOptional(ApiVersion apiVersion, SecurityContext securityContext, @Nullable String name) {\n\t\t\tassertThat(apiVersion).isEqualTo(ApiVersion.LATEST);\n\t\t\tassertThat(securityContext).isNotNull();\n\t\t\treturn new StringBuilder(String.valueOf(name)).reverse().toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerAdvisorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoker.cache;\n\nimport java.lang.reflect.Method;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameters;\nimport org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link CachingOperationInvokerAdvisor}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@ExtendWith(MockitoExtension.class)\nclass CachingOperationInvokerAdvisorTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate OperationInvoker invoker;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Function<EndpointId, @Nullable Long> timeToLive;\n\n\tprivate CachingOperationInvokerAdvisor advisor;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.advisor = new CachingOperationInvokerAdvisor(this.timeToLive);\n\t}\n\n\t@Test\n\tvoid applyWhenOperationIsNotReadShouldNotAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"get\");\n\t\tOperationInvoker advised = this.advisor.apply(EndpointId.of(\"foo\"), OperationType.WRITE, parameters,\n\t\t\t\tthis.invoker);\n\t\tassertThat(advised).isSameAs(this.invoker);\n\t}\n\n\t@Test\n\tvoid applyWhenHasAtLeaseOneMandatoryParameterShouldNotAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"getWithParameters\", String.class, String.class);\n\t\tOperationInvoker advised = this.advisor.apply(EndpointId.of(\"foo\"), OperationType.READ, parameters,\n\t\t\t\tthis.invoker);\n\t\tassertThat(advised).isSameAs(this.invoker);\n\t}\n\n\t@Test\n\tvoid applyWhenTimeToLiveReturnsNullShouldNotAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"get\");\n\t\tgiven(this.timeToLive.apply(any())).willReturn(null);\n\t\tOperationInvoker advised = this.advisor.apply(EndpointId.of(\"foo\"), OperationType.READ, parameters,\n\t\t\t\tthis.invoker);\n\t\tassertThat(advised).isSameAs(this.invoker);\n\t\tthen(this.timeToLive).should().apply(EndpointId.of(\"foo\"));\n\t}\n\n\t@Test\n\tvoid applyWhenTimeToLiveIsZeroShouldNotAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"get\");\n\t\tgiven(this.timeToLive.apply(any())).willReturn(0L);\n\t\tOperationInvoker advised = this.advisor.apply(EndpointId.of(\"foo\"), OperationType.READ, parameters,\n\t\t\t\tthis.invoker);\n\t\tassertThat(advised).isSameAs(this.invoker);\n\t\tthen(this.timeToLive).should().apply(EndpointId.of(\"foo\"));\n\t}\n\n\t@Test\n\tvoid applyShouldAddCacheAdvise() {\n\t\tOperationParameters parameters = getParameters(\"get\");\n\t\tgiven(this.timeToLive.apply(any())).willReturn(100L);\n\t\tassertAdviseIsApplied(parameters);\n\t}\n\n\t@Test\n\tvoid applyWithAllOptionalParametersShouldAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"getWithAllOptionalParameters\", String.class, String.class);\n\t\tgiven(this.timeToLive.apply(any())).willReturn(100L);\n\t\tassertAdviseIsApplied(parameters);\n\t}\n\n\t@Test\n\tvoid applyWithSecurityContextShouldAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"getWithSecurityContext\", SecurityContext.class, String.class);\n\t\tgiven(this.timeToLive.apply(any())).willReturn(100L);\n\t\tassertAdviseIsApplied(parameters);\n\t}\n\n\t@Test\n\tvoid applyWithApiVersionShouldAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"getWithApiVersion\", ApiVersion.class, String.class);\n\t\tgiven(this.timeToLive.apply(any())).willReturn(100L);\n\t\tassertAdviseIsApplied(parameters);\n\t}\n\n\t@Test\n\tvoid applyWithWebServerNamespaceShouldAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"getWithServerNamespace\", WebServerNamespace.class,\n\t\t\t\tString.class);\n\t\tgiven(this.timeToLive.apply(any())).willReturn(100L);\n\t\tassertAdviseIsApplied(parameters);\n\t}\n\n\t@Test\n\tvoid applyWithMandatoryCachedAndNonCachedShouldAddAdvise() {\n\t\tOperationParameters parameters = getParameters(\"getWithServerNamespaceAndOtherMandatory\",\n\t\t\t\tWebServerNamespace.class, String.class);\n\t\tOperationInvoker advised = this.advisor.apply(EndpointId.of(\"foo\"), OperationType.READ, parameters,\n\t\t\t\tthis.invoker);\n\t\tassertThat(advised).isSameAs(this.invoker);\n\t}\n\n\tprivate void assertAdviseIsApplied(OperationParameters parameters) {\n\t\tOperationInvoker advised = this.advisor.apply(EndpointId.of(\"foo\"), OperationType.READ, parameters,\n\t\t\t\tthis.invoker);\n\t\tassertThat(advised).isInstanceOf(CachingOperationInvoker.class);\n\t\tassertThat(advised).hasFieldOrPropertyWithValue(\"invoker\", this.invoker);\n\t\tassertThat(advised).hasFieldOrPropertyWithValue(\"timeToLive\", 100L);\n\t}\n\n\tprivate OperationParameters getParameters(String methodName, Class<?>... parameterTypes) {\n\t\treturn getOperationMethod(methodName, parameterTypes).getParameters();\n\t}\n\n\tprivate OperationMethod getOperationMethod(String methodName, Class<?>... parameterTypes) {\n\t\tMethod method = ReflectionUtils.findMethod(TestOperations.class, methodName, parameterTypes);\n\t\tassertThat(method).as(\"Method '%s'\", method).isNotNull();\n\t\treturn new OperationMethod(method, OperationType.READ);\n\t}\n\n\tstatic class TestOperations {\n\n\t\tString get() {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString getWithParameters(@Nullable String foo, String bar) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString getWithAllOptionalParameters(@Nullable String foo, @Nullable String bar) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString getWithSecurityContext(SecurityContext securityContext, @Nullable String bar) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString getWithApiVersion(ApiVersion apiVersion, @Nullable String bar) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString getWithServerNamespace(WebServerNamespace serverNamespace, @Nullable String bar) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\tString getWithServerNamespaceAndOtherMandatory(WebServerNamespace serverNamespace, String bar) {\n\t\t\treturn \"\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/invoker/cache/CachingOperationInvokerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.invoker.cache;\n\nimport java.security.Principal;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\n\nimport static org.assertj.core.api.Assertions.as;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link CachingOperationInvoker}.\n *\n * @author Stephane Nicoll\n * @author Christoph Dreis\n * @author Phillip Webb\n */\nclass CachingOperationInvokerTests {\n\n\tprivate static final long CACHE_TTL = Duration.ofHours(1).toMillis();\n\n\t@Test\n\tvoid createInstanceWithTtlSetToZero() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new CachingOperationInvoker(mock(OperationInvoker.class), 0))\n\t\t\t.withMessage(\"'timeToLive' must be greater than zero\");\n\t}\n\n\t@Test\n\tvoid cacheInTtlRangeWithNoParameter() {\n\t\tassertCacheIsUsed(Collections.emptyMap());\n\t}\n\n\t@Test\n\tvoid cacheInTtlWithPrincipal() {\n\t\tassertCacheIsUsed(Collections.emptyMap(), mock(Principal.class));\n\t}\n\n\t@Test\n\tvoid cacheInTtlWithNullParameters() {\n\t\tMap<String, Object> parameters = new HashMap<>();\n\t\tparameters.put(\"first\", null);\n\t\tparameters.put(\"second\", null);\n\t\tassertCacheIsUsed(parameters);\n\t}\n\n\t@Test\n\tvoid cacheInTtlWithMonoResponse() {\n\t\tMonoOperationInvoker.invocations = new AtomicInteger();\n\t\tMonoOperationInvoker target = new MonoOperationInvoker();\n\t\tInvocationContext context = new InvocationContext(mock(SecurityContext.class), Collections.emptyMap());\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tObject response = invokeMono(invoker, context).block();\n\t\tObject cachedResponse = invokeMono(invoker, context).block();\n\t\tassertThat(MonoOperationInvoker.invocations).hasValue(1);\n\t\tassertThat(response).isSameAs(cachedResponse);\n\t}\n\n\t@Test\n\tvoid cacheInTtlWithFluxResponse() {\n\t\tFluxOperationInvoker.invocations = new AtomicInteger();\n\t\tFluxOperationInvoker target = new FluxOperationInvoker();\n\t\tInvocationContext context = new InvocationContext(mock(SecurityContext.class), Collections.emptyMap());\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tObject response = invokeFlux(invoker, context).blockLast();\n\t\tObject cachedResponse = invokeFlux(invoker, context).blockLast();\n\t\tassertThat(FluxOperationInvoker.invocations).hasValue(1);\n\t\tassertThat(response).isSameAs(cachedResponse);\n\t}\n\n\t@Test // gh-28313\n\tvoid cacheWhenEachPrincipalIsUniqueDoesNotConsumeTooMuchMemory() throws Exception {\n\t\tMonoOperationInvoker target = new MonoOperationInvoker();\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, 50L);\n\t\tint count = 1000;\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tinvokeWithUniquePrincipal(invoker);\n\t\t}\n\t\tlong expired = System.currentTimeMillis() + 50;\n\t\twhile (System.currentTimeMillis() < expired) {\n\t\t\tThread.sleep(10);\n\t\t}\n\t\tinvokeWithUniquePrincipal(invoker);\n\t\tassertThat(invoker).extracting(\"cachedResponses\", as(InstanceOfAssertFactories.MAP)).hasSizeLessThan(count);\n\t}\n\n\tprivate void invokeWithUniquePrincipal(CachingOperationInvoker invoker) {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tPrincipal principal = mock(Principal.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(principal);\n\t\tInvocationContext context = new InvocationContext(securityContext, Collections.emptyMap());\n\t\tinvokeMono(invoker, context).block();\n\t}\n\n\tprivate void assertCacheIsUsed(Map<String, Object> parameters) {\n\t\tassertCacheIsUsed(parameters, null);\n\t}\n\n\tprivate void assertCacheIsUsed(Map<String, Object> parameters, @Nullable Principal principal) {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tObject expected = new Object();\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tif (principal != null) {\n\t\t\tgiven(securityContext.getPrincipal()).willReturn(principal);\n\t\t}\n\t\tInvocationContext context = new InvocationContext(securityContext, parameters);\n\t\tgiven(target.invoke(context)).willReturn(expected);\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tObject response = invoker.invoke(context);\n\t\tassertThat(response).isSameAs(expected);\n\t\tthen(target).should().invoke(context);\n\t\tObject cachedResponse = invoker.invoke(context);\n\t\tassertThat(cachedResponse).isSameAs(response);\n\t\tthen(target).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid targetAlwaysInvokedWithParameters() {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tMap<String, Object> parameters = new HashMap<>();\n\t\tparameters.put(\"test\", \"value\");\n\t\tparameters.put(\"something\", null);\n\t\tInvocationContext context = new InvocationContext(mock(SecurityContext.class), parameters);\n\t\tgiven(target.invoke(context)).willReturn(new Object());\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tinvoker.invoke(context);\n\t\tinvoker.invoke(context);\n\t\tinvoker.invoke(context);\n\t\tthen(target).should(times(3)).invoke(context);\n\t}\n\n\t@Test\n\tvoid targetAlwaysInvokedWithDifferentPrincipals() {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tMap<String, Object> parameters = new HashMap<>();\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class), mock(Principal.class),\n\t\t\t\tmock(Principal.class));\n\t\tInvocationContext context = new InvocationContext(securityContext, parameters);\n\t\tObject result1 = new Object();\n\t\tObject result2 = new Object();\n\t\tObject result3 = new Object();\n\t\tgiven(target.invoke(context)).willReturn(result1, result2, result3);\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tassertThat(invoker.invoke(context)).isEqualTo(result1);\n\t\tassertThat(invoker.invoke(context)).isEqualTo(result2);\n\t\tassertThat(invoker.invoke(context)).isEqualTo(result3);\n\t\tthen(target).should(times(3)).invoke(context);\n\t}\n\n\t@Test\n\tvoid targetInvokedWhenCalledWithAndWithoutPrincipal() {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tMap<String, Object> parameters = new HashMap<>();\n\t\tSecurityContext anonymous = mock(SecurityContext.class);\n\t\tSecurityContext authenticated = mock(SecurityContext.class);\n\t\tgiven(authenticated.getPrincipal()).willReturn(mock(Principal.class));\n\t\tInvocationContext anonymousContext = new InvocationContext(anonymous, parameters);\n\t\tObject anonymousResult = new Object();\n\t\tgiven(target.invoke(anonymousContext)).willReturn(anonymousResult);\n\t\tInvocationContext authenticatedContext = new InvocationContext(authenticated, parameters);\n\t\tObject authenticatedResult = new Object();\n\t\tgiven(target.invoke(authenticatedContext)).willReturn(authenticatedResult);\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tassertThat(invoker.invoke(anonymousContext)).isEqualTo(anonymousResult);\n\t\tassertThat(invoker.invoke(authenticatedContext)).isEqualTo(authenticatedResult);\n\t\tassertThat(invoker.invoke(anonymousContext)).isEqualTo(anonymousResult);\n\t\tassertThat(invoker.invoke(authenticatedContext)).isEqualTo(authenticatedResult);\n\t\tthen(target).should().invoke(anonymousContext);\n\t\tthen(target).should().invoke(authenticatedContext);\n\t}\n\n\t@Test\n\tvoid targetInvokedWhenCacheExpires() throws InterruptedException {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tMap<String, Object> parameters = new HashMap<>();\n\t\tInvocationContext context = new InvocationContext(mock(SecurityContext.class), parameters);\n\t\tgiven(target.invoke(context)).willReturn(new Object());\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, 50L);\n\t\tinvoker.invoke(context);\n\t\tlong expired = System.currentTimeMillis() + 50;\n\t\twhile (System.currentTimeMillis() < expired) {\n\t\t\tThread.sleep(10);\n\t\t}\n\t\tinvoker.invoke(context);\n\t\tthen(target).should(times(2)).invoke(context);\n\t}\n\n\t@Test\n\tvoid targetInvokedWithDifferentApiVersion() {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tObject expectedV2 = new Object();\n\t\tObject expectedV3 = new Object();\n\t\tInvocationContext contextV2 = new InvocationContext(mock(SecurityContext.class), Collections.emptyMap(),\n\t\t\t\tnew ApiVersionArgumentResolver(ApiVersion.V2));\n\t\tInvocationContext contextV3 = new InvocationContext(mock(SecurityContext.class), Collections.emptyMap(),\n\t\t\t\tnew ApiVersionArgumentResolver(ApiVersion.V3));\n\t\tgiven(target.invoke(contextV2)).willReturn(expectedV2);\n\t\tgiven(target.invoke(contextV3)).willReturn(expectedV3);\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tObject responseV2 = invoker.invoke(contextV2);\n\t\tassertThat(responseV2).isSameAs(expectedV2);\n\t\tthen(target).should().invoke(contextV2);\n\t\tObject responseV3 = invoker.invoke(contextV3);\n\t\tassertThat(responseV3).isNotSameAs(responseV2);\n\t\tthen(target).should().invoke(contextV3);\n\t}\n\n\t@Test\n\tvoid targetInvokedWithDifferentWebServerNamespace() {\n\t\tOperationInvoker target = mock(OperationInvoker.class);\n\t\tObject expectedServer = new Object();\n\t\tObject expectedManagement = new Object();\n\t\tInvocationContext contextServer = new InvocationContext(mock(SecurityContext.class), Collections.emptyMap(),\n\t\t\t\tnew WebServerNamespaceArgumentResolver(WebServerNamespace.SERVER));\n\t\tInvocationContext contextManagement = new InvocationContext(mock(SecurityContext.class), Collections.emptyMap(),\n\t\t\t\tnew WebServerNamespaceArgumentResolver(WebServerNamespace.MANAGEMENT));\n\t\tgiven(target.invoke(contextServer)).willReturn(expectedServer);\n\t\tgiven(target.invoke(contextManagement)).willReturn(expectedManagement);\n\t\tCachingOperationInvoker invoker = new CachingOperationInvoker(target, CACHE_TTL);\n\t\tObject responseServer = invoker.invoke(contextServer);\n\t\tassertThat(responseServer).isSameAs(expectedServer);\n\t\tthen(target).should(times(1)).invoke(contextServer);\n\t\tObject responseManagement = invoker.invoke(contextManagement);\n\t\tassertThat(responseManagement).isNotSameAs(responseServer);\n\t\tthen(target).should(times(1)).invoke(contextManagement);\n\t}\n\n\tprivate Mono<?> invokeMono(CachingOperationInvoker invoker, InvocationContext context) {\n\t\tMono<?> result = (Mono<?>) invoker.invoke(context);\n\t\tassertThat(result).isNotNull();\n\t\treturn result;\n\t}\n\n\tprivate Flux<?> invokeFlux(CachingOperationInvoker invoker, InvocationContext context) {\n\t\tFlux<?> result = (Flux<?>) invoker.invoke(context);\n\t\tassertThat(result).isNotNull();\n\t\treturn result;\n\t}\n\n\tprivate static final class MonoOperationInvoker implements OperationInvoker {\n\n\t\tstatic AtomicInteger invocations = new AtomicInteger();\n\n\t\t@Override\n\t\tpublic Mono<String> invoke(InvocationContext context) {\n\t\t\treturn Mono.fromCallable(() -> {\n\t\t\t\tinvocations.incrementAndGet();\n\t\t\t\treturn \"test\";\n\t\t\t});\n\t\t}\n\n\t}\n\n\tprivate static final class FluxOperationInvoker implements OperationInvoker {\n\n\t\tstatic AtomicInteger invocations = new AtomicInteger();\n\n\t\t@Override\n\t\tpublic Flux<String> invoke(InvocationContext context) {\n\t\t\treturn Flux.just(\"spring\", \"boot\").hide().doFirst(invocations::incrementAndGet);\n\t\t}\n\n\t}\n\n\tprivate static final class ApiVersionArgumentResolver implements OperationArgumentResolver {\n\n\t\tprivate final ApiVersion apiVersion;\n\n\t\tprivate ApiVersionArgumentResolver(ApiVersion apiVersion) {\n\t\t\tthis.apiVersion = apiVersion;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\t@Override\n\t\tpublic <T> T resolve(Class<T> type) {\n\t\t\treturn (T) this.apiVersion;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canResolve(Class<?> type) {\n\t\t\treturn ApiVersion.class.equals(type);\n\t\t}\n\n\t}\n\n\tprivate static final class WebServerNamespaceArgumentResolver implements OperationArgumentResolver {\n\n\t\tprivate final WebServerNamespace webServerNamespace;\n\n\t\tprivate WebServerNamespaceArgumentResolver(WebServerNamespace webServerNamespace) {\n\t\t\tthis.webServerNamespace = webServerNamespace;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\t@Override\n\t\tpublic <T> T resolve(Class<T> type) {\n\t\t\treturn (T) this.webServerNamespace;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canResolve(Class<?> type) {\n\t\t\treturn WebServerNamespace.class.equals(type);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/EndpointMBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\n\nimport javax.management.Attribute;\nimport javax.management.AttributeList;\nimport javax.management.AttributeNotFoundException;\nimport javax.management.MBeanException;\nimport javax.management.MBeanInfo;\nimport javax.management.ReflectionException;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.FatalBeanException;\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link EndpointMBean}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass EndpointMBeanTests {\n\n\tprivate static final Object[] NO_PARAMS = {};\n\n\tprivate static final String[] NO_SIGNATURE = {};\n\n\tprivate final TestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(new TestJmxOperation());\n\n\tprivate final TestJmxOperationResponseMapper responseMapper = new TestJmxOperationResponseMapper();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResponseMapperIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new EndpointMBean(null, null, mock(ExposableJmxEndpoint.class)))\n\t\t\t.withMessageContaining(\"'responseMapper' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenEndpointIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new EndpointMBean(mock(JmxOperationResponseMapper.class), null, null))\n\t\t\t.withMessageContaining(\"'endpoint' must not be null\");\n\t}\n\n\t@Test\n\tvoid getMBeanInfoShouldReturnMBeanInfo() {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tMBeanInfo info = bean.getMBeanInfo();\n\t\tassertThat(info.getDescription()).isEqualTo(\"MBean operations for endpoint test\");\n\t}\n\n\t@Test\n\tvoid invokeShouldInvokeJmxOperation() throws MBeanException, ReflectionException {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tObject result = bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE);\n\t\tassertThat(result).isEqualTo(\"result\");\n\t}\n\n\t@Test\n\tvoid invokeWhenOperationFailedShouldTranslateException() {\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(new TestJmxOperation((arguments) -> {\n\t\t\tthrow new FatalBeanException(\"test failure\");\n\t\t}));\n\t\tEndpointMBean bean = new EndpointMBean(this.responseMapper, null, endpoint);\n\t\tassertThatExceptionOfType(MBeanException.class)\n\t\t\t.isThrownBy(() -> bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE))\n\t\t\t.withCauseInstanceOf(IllegalStateException.class)\n\t\t\t.withMessageContaining(\"test failure\");\n\n\t}\n\n\t@Test\n\tvoid invokeWhenOperationFailedWithJdkExceptionShouldReuseException() {\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(new TestJmxOperation((arguments) -> {\n\t\t\tthrow new UnsupportedOperationException(\"test failure\");\n\t\t}));\n\t\tEndpointMBean bean = new EndpointMBean(this.responseMapper, null, endpoint);\n\t\tassertThatExceptionOfType(MBeanException.class)\n\t\t\t.isThrownBy(() -> bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE))\n\t\t\t.withCauseInstanceOf(UnsupportedOperationException.class)\n\t\t\t.withMessageContaining(\"test failure\");\n\t}\n\n\t@Test\n\tvoid invokeWhenActionNameIsNotAnOperationShouldThrowException() {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tassertThatExceptionOfType(ReflectionException.class)\n\t\t\t.isThrownBy(() -> bean.invoke(\"missingOperation\", NO_PARAMS, NO_SIGNATURE))\n\t\t\t.withCauseInstanceOf(IllegalArgumentException.class)\n\t\t\t.withMessageContaining(\"no operation named missingOperation\");\n\t}\n\n\t@Test\n\tvoid invokeShouldInvokeJmxOperationWithBeanClassLoader() throws ReflectionException, MBeanException {\n\t\tClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(\n\t\t\t\tnew TestJmxOperation((arguments) -> ClassUtils.getDefaultClassLoader()));\n\t\tURLClassLoader beanClassLoader = new URLClassLoader(new URL[0], getClass().getClassLoader());\n\t\tEndpointMBean bean = new EndpointMBean(this.responseMapper, beanClassLoader, endpoint);\n\t\tObject result = bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE);\n\t\tassertThat(result).isEqualTo(beanClassLoader);\n\t\tassertThat(Thread.currentThread().getContextClassLoader()).isEqualTo(originalClassLoader);\n\t}\n\n\t@Test\n\tvoid invokeWhenOperationIsInvalidShouldThrowException() {\n\t\tTestJmxOperation operation = new TestJmxOperation() {\n\n\t\t\t@Override\n\t\t\tpublic Object invoke(InvocationContext context) {\n\t\t\t\tthrow new InvalidEndpointRequestException(\"test failure\", \"test\");\n\t\t\t}\n\n\t\t};\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(operation);\n\t\tEndpointMBean bean = new EndpointMBean(this.responseMapper, null, endpoint);\n\t\tassertThatExceptionOfType(ReflectionException.class)\n\t\t\t.isThrownBy(() -> bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE))\n\t\t\t.withRootCauseInstanceOf(IllegalArgumentException.class)\n\t\t\t.withMessageContaining(\"test failure\");\n\t}\n\n\t@Test\n\tvoid invokeWhenMonoResultShouldBlockOnMono() throws MBeanException, ReflectionException {\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(\n\t\t\t\tnew TestJmxOperation((arguments) -> Mono.just(\"monoResult\")));\n\t\tEndpointMBean bean = new EndpointMBean(this.responseMapper, null, endpoint);\n\t\tObject result = bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE);\n\t\tassertThat(result).isEqualTo(\"monoResult\");\n\t}\n\n\t@Test\n\tvoid invokeWhenFluxResultShouldCollectToMonoListAndBlockOnMono() throws MBeanException, ReflectionException {\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(\n\t\t\t\tnew TestJmxOperation((arguments) -> Flux.just(\"flux\", \"result\")));\n\t\tEndpointMBean bean = new EndpointMBean(this.responseMapper, null, endpoint);\n\t\tObject result = bean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE);\n\t\tassertThat(result).asInstanceOf(InstanceOfAssertFactories.LIST).containsExactly(\"flux\", \"result\");\n\t}\n\n\t@Test\n\tvoid invokeShouldCallResponseMapper() throws MBeanException, ReflectionException {\n\t\tTestJmxOperationResponseMapper responseMapper = spy(this.responseMapper);\n\t\tEndpointMBean bean = new EndpointMBean(responseMapper, null, this.endpoint);\n\t\tbean.invoke(\"testOperation\", NO_PARAMS, NO_SIGNATURE);\n\t\tthen(responseMapper).should().mapResponseType(String.class);\n\t\tthen(responseMapper).should().mapResponse(\"result\");\n\t}\n\n\t@Test\n\tvoid getAttributeShouldThrowException() {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tassertThatExceptionOfType(AttributeNotFoundException.class).isThrownBy(() -> bean.getAttribute(\"test\"))\n\t\t\t.withMessageContaining(\"EndpointMBeans do not support attributes\");\n\t}\n\n\t@Test\n\tvoid setAttributeShouldThrowException() {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tassertThatExceptionOfType(AttributeNotFoundException.class)\n\t\t\t.isThrownBy(() -> bean.setAttribute(new Attribute(\"test\", \"test\")))\n\t\t\t.withMessageContaining(\"EndpointMBeans do not support attributes\");\n\t}\n\n\t@Test\n\tvoid getAttributesShouldReturnEmptyAttributeList() {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tAttributeList attributes = bean.getAttributes(new String[] { \"test\" });\n\t\tassertThat(attributes).isEmpty();\n\t}\n\n\t@Test\n\tvoid setAttributesShouldReturnEmptyAttributeList() {\n\t\tEndpointMBean bean = createEndpointMBean();\n\t\tAttributeList sourceAttributes = new AttributeList();\n\t\tsourceAttributes.add(new Attribute(\"test\", \"test\"));\n\t\tAttributeList attributes = bean.setAttributes(sourceAttributes);\n\t\tassertThat(attributes).isEmpty();\n\t}\n\n\tprivate EndpointMBean createEndpointMBean() {\n\t\treturn new EndpointMBean(this.responseMapper, null, this.endpoint);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/JacksonJmxOperationResponseMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.JavaType;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.test.json.BasicJsonTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link JacksonJmxOperationResponseMapper}\n *\n * @author Phillip Webb\n */\nclass JacksonJmxOperationResponseMapperTests {\n\n\tprivate final JacksonJmxOperationResponseMapper mapper = new JacksonJmxOperationResponseMapper(null);\n\n\tprivate final BasicJsonTester json = new BasicJsonTester(getClass());\n\n\t@Test\n\tvoid createWhenObjectMapperIsNullShouldUseDefaultObjectMapper() {\n\t\tJacksonJmxOperationResponseMapper mapper = new JacksonJmxOperationResponseMapper(null);\n\t\tObject mapped = mapper.mapResponse(Collections.singleton(\"test\"));\n\t\tassertThat(this.json.from(mapped.toString())).isEqualToJson(\"[test]\");\n\t}\n\n\t@Test\n\tvoid createWhenObjectMapperIsSpecifiedShouldUseObjectMapper() {\n\t\tJsonMapper jsonMapper = spy(JsonMapper.class);\n\t\tJacksonJmxOperationResponseMapper mapper = new JacksonJmxOperationResponseMapper(jsonMapper);\n\t\tSet<String> response = Collections.singleton(\"test\");\n\t\tmapper.mapResponse(response);\n\t\tthen(jsonMapper).should().convertValue(eq(response), any(JavaType.class));\n\t}\n\n\t@Test\n\tvoid mapResponseTypeWhenCharSequenceShouldReturnString() {\n\t\tassertThat(this.mapper.mapResponseType(String.class)).isEqualTo(String.class);\n\t\tassertThat(this.mapper.mapResponseType(StringBuilder.class)).isEqualTo(String.class);\n\t}\n\n\t@Test\n\tvoid mapResponseTypeWhenArrayShouldReturnList() {\n\t\tassertThat(this.mapper.mapResponseType(String[].class)).isEqualTo(List.class);\n\t\tassertThat(this.mapper.mapResponseType(Object[].class)).isEqualTo(List.class);\n\t}\n\n\t@Test\n\tvoid mapResponseTypeWhenCollectionShouldReturnList() {\n\t\tassertThat(this.mapper.mapResponseType(Collection.class)).isEqualTo(List.class);\n\t\tassertThat(this.mapper.mapResponseType(Set.class)).isEqualTo(List.class);\n\t\tassertThat(this.mapper.mapResponseType(List.class)).isEqualTo(List.class);\n\t}\n\n\t@Test\n\tvoid mapResponseTypeWhenOtherShouldReturnMap() {\n\t\tassertThat(this.mapper.mapResponseType(ExampleBean.class)).isEqualTo(Map.class);\n\t}\n\n\t@Test\n\tvoid mapResponseWhenNullShouldReturnNull() {\n\t\tassertThat(this.mapper.mapResponse(null)).isNull();\n\t}\n\n\t@Test\n\tvoid mapResponseWhenCharSequenceShouldReturnString() {\n\t\tassertThat(this.mapper.mapResponse(new StringBuilder(\"test\"))).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid mapResponseWhenArrayShouldReturnJsonArray() {\n\t\tObject mapped = this.mapper.mapResponse(new int[] { 1, 2, 3 });\n\t\tassertThat(this.json.from(mapped.toString())).isEqualToJson(\"[1,2,3]\");\n\t}\n\n\t@Test\n\tvoid mapResponseWhenCollectionShouldReturnJsonArray() {\n\t\tObject mapped = this.mapper.mapResponse(Arrays.asList(\"a\", \"b\", \"c\"));\n\t\tassertThat(this.json.from(mapped.toString())).isEqualToJson(\"[a,b,c]\");\n\t}\n\n\t@Test\n\tvoid mapResponseWhenOtherShouldReturnMap() {\n\t\tExampleBean bean = new ExampleBean();\n\t\tbean.setName(\"boot\");\n\t\tObject mapped = this.mapper.mapResponse(bean);\n\t\tassertThat(this.json.from(mapped.toString())).isEqualToJson(\"{'name':'boot'}\");\n\t}\n\n\tpublic static class ExampleBean {\n\n\t\tprivate @Nullable String name;\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/JmxEndpointExporterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.management.InstanceNotFoundException;\nimport javax.management.MBeanRegistrationException;\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.Spy;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.jmx.JmxException;\nimport org.springframework.jmx.export.MBeanExportException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\n\n/**\n * Tests for {@link JmxEndpointExporter}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass JmxEndpointExporterTests {\n\n\tprivate final JmxOperationResponseMapper responseMapper = new TestJmxOperationResponseMapper();\n\n\tprivate final List<ExposableJmxEndpoint> endpoints = new ArrayList<>();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MBeanServer mBeanServer;\n\n\t@Spy\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate EndpointObjectNameFactory objectNameFactory = new TestEndpointObjectNameFactory();\n\n\tprivate JmxEndpointExporter exporter;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.exporter = new JmxEndpointExporter(this.mBeanServer, this.objectNameFactory, this.responseMapper,\n\t\t\t\tthis.endpoints);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenMBeanServerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new JmxEndpointExporter(null, this.objectNameFactory, this.responseMapper, this.endpoints))\n\t\t\t.withMessageContaining(\"'mBeanServer' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenObjectNameFactoryIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new JmxEndpointExporter(this.mBeanServer, null, this.responseMapper, this.endpoints))\n\t\t\t.withMessageContaining(\"'objectNameFactory' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResponseMapperIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new JmxEndpointExporter(this.mBeanServer, this.objectNameFactory, null, this.endpoints))\n\t\t\t.withMessageContaining(\"'responseMapper' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenEndpointsIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new JmxEndpointExporter(this.mBeanServer, this.objectNameFactory, this.responseMapper, null))\n\t\t\t.withMessageContaining(\"'endpoints' must not be null\");\n\t}\n\n\t@Test\n\tvoid afterPropertiesSetShouldRegisterMBeans() throws Exception {\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tthis.exporter.afterPropertiesSet();\n\t\tthen(this.mBeanServer).should()\n\t\t\t.registerMBean(assertArg((object) -> assertThat(object).isInstanceOf(EndpointMBean.class)),\n\t\t\t\t\tassertArg((objectName) -> assertThat(objectName.getKeyProperty(\"name\")).isEqualTo(\"test\")));\n\t}\n\n\t@Test\n\tvoid registerShouldUseObjectNameFactory() throws Exception {\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tthis.exporter.afterPropertiesSet();\n\t\tthen(this.objectNameFactory).should().getObjectName(any(ExposableJmxEndpoint.class));\n\t}\n\n\t@Test\n\tvoid registerWhenObjectNameIsMalformedShouldThrowException() throws Exception {\n\t\tTestExposableJmxEndpoint endpoint = new TestExposableJmxEndpoint(new TestJmxOperation());\n\t\tgiven(this.objectNameFactory.getObjectName(endpoint)).willThrow(MalformedObjectNameException.class);\n\t\tthis.endpoints.add(endpoint);\n\t\tassertThatIllegalStateException().isThrownBy(this.exporter::afterPropertiesSet)\n\t\t\t.withMessageContaining(\"Invalid ObjectName for endpoint 'test'\");\n\t}\n\n\t@Test\n\tvoid registerWhenRegistrationFailsShouldThrowException() throws Exception {\n\t\tgiven(this.mBeanServer.registerMBean(any(), any(ObjectName.class)))\n\t\t\t.willThrow(new MBeanRegistrationException(new RuntimeException()));\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tassertThatExceptionOfType(MBeanExportException.class).isThrownBy(this.exporter::afterPropertiesSet)\n\t\t\t.withMessageContaining(\"Failed to register MBean for endpoint 'test\");\n\t}\n\n\t@Test\n\tvoid registerWhenEndpointHasNoOperationsShouldNotCreateMBean() {\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint());\n\t\tthis.exporter.afterPropertiesSet();\n\t\tthen(this.mBeanServer).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid destroyShouldUnregisterMBeans() throws Exception {\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tthis.exporter.afterPropertiesSet();\n\t\tthis.exporter.destroy();\n\t\tthen(this.mBeanServer).should()\n\t\t\t.unregisterMBean(\n\t\t\t\t\tassertArg((objectName) -> assertThat(objectName.getKeyProperty(\"name\")).isEqualTo(\"test\")));\n\t}\n\n\t@Test\n\tvoid unregisterWhenInstanceNotFoundShouldContinue() throws Exception {\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tthis.exporter.afterPropertiesSet();\n\t\twillThrow(InstanceNotFoundException.class).given(this.mBeanServer).unregisterMBean(any(ObjectName.class));\n\t\tthis.exporter.destroy();\n\t}\n\n\t@Test\n\tvoid unregisterWhenUnregisterThrowsExceptionShouldThrowException() throws Exception {\n\t\tthis.endpoints.add(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tthis.exporter.afterPropertiesSet();\n\t\twillThrow(new MBeanRegistrationException(new RuntimeException())).given(this.mBeanServer)\n\t\t\t.unregisterMBean(any(ObjectName.class));\n\t\tassertThatExceptionOfType(JmxException.class).isThrownBy(() -> this.exporter.destroy())\n\t\t\t.withMessageContaining(\"Failed to unregister MBean with ObjectName 'boot\");\n\t}\n\n\t/**\n\t * Test {@link EndpointObjectNameFactory}.\n\t */\n\tstatic class TestEndpointObjectNameFactory implements EndpointObjectNameFactory {\n\n\t\t@Override\n\t\tpublic ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException {\n\t\t\treturn new ObjectName(\"boot:type=Endpoint,name=\" + endpoint.getEndpointId());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/MBeanInfoFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.management.MBeanInfo;\nimport javax.management.MBeanOperationInfo;\nimport javax.management.MBeanParameterInfo;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MBeanInfoFactory}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass MBeanInfoFactoryTests {\n\n\tprivate final MBeanInfoFactory factory = new MBeanInfoFactory(new TestJmxOperationResponseMapper());\n\n\t@Test\n\tvoid getMBeanInfoShouldReturnMBeanInfo() {\n\t\tMBeanInfo info = this.factory.getMBeanInfo(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tassertThat(info).isNotNull();\n\t\tassertThat(info.getClassName()).isEqualTo(EndpointMBean.class.getName());\n\t\tassertThat(info.getDescription()).isEqualTo(\"MBean operations for endpoint test\");\n\t\tassertThat(info.getAttributes()).isEmpty();\n\t\tassertThat(info.getNotifications()).isEmpty();\n\t\tassertThat(info.getConstructors()).isEmpty();\n\t\tassertThat(info.getOperations()).hasSize(1);\n\t\tMBeanOperationInfo operationInfo = info.getOperations()[0];\n\t\tassertThat(operationInfo.getName()).isEqualTo(\"testOperation\");\n\t\tassertThat(operationInfo.getReturnType()).isEqualTo(String.class.getName());\n\t\tassertThat(operationInfo.getImpact()).isZero();\n\t\tassertThat(operationInfo.getSignature()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getMBeanInfoWhenReadOperationShouldHaveInfoImpact() {\n\t\tMBeanInfo info = this.factory\n\t\t\t.getMBeanInfo(new TestExposableJmxEndpoint(new TestJmxOperation(OperationType.READ)));\n\t\tassertThat(info.getOperations()[0].getImpact()).isZero();\n\t}\n\n\t@Test\n\tvoid getMBeanInfoWhenWriteOperationShouldHaveActionImpact() {\n\t\tMBeanInfo info = this.factory\n\t\t\t.getMBeanInfo(new TestExposableJmxEndpoint(new TestJmxOperation(OperationType.WRITE)));\n\t\tassertThat(info.getOperations()[0].getImpact()).isOne();\n\t}\n\n\t@Test\n\tvoid getMBeanInfoWhenDeleteOperationShouldHaveActionImpact() {\n\t\tMBeanInfo info = this.factory\n\t\t\t.getMBeanInfo(new TestExposableJmxEndpoint(new TestJmxOperation(OperationType.DELETE)));\n\t\tassertThat(info.getOperations()[0].getImpact()).isOne();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid getMBeanInfoShouldUseJmxOperationResponseMapper() {\n\t\tJmxOperationResponseMapper mapper = mock(JmxOperationResponseMapper.class);\n\t\tgiven(mapper.mapResponseType(String.class)).willReturn((Class) Integer.class);\n\t\tMBeanInfoFactory factory = new MBeanInfoFactory(mapper);\n\t\tMBeanInfo info = factory.getMBeanInfo(new TestExposableJmxEndpoint(new TestJmxOperation()));\n\t\tMBeanOperationInfo operationInfo = info.getOperations()[0];\n\t\tassertThat(operationInfo.getReturnType()).isEqualTo(Integer.class.getName());\n\t}\n\n\t@Test\n\tvoid getMBeanShouldMapOperationParameters() {\n\t\tList<JmxOperationParameter> parameters = new ArrayList<>();\n\t\tparameters.add(mockParameter(\"one\", String.class, \"myone\"));\n\t\tparameters.add(mockParameter(\"two\", Object.class, null));\n\t\tTestJmxOperation operation = new TestJmxOperation(parameters);\n\t\tMBeanInfo info = this.factory.getMBeanInfo(new TestExposableJmxEndpoint(operation));\n\t\tMBeanOperationInfo operationInfo = info.getOperations()[0];\n\t\tMBeanParameterInfo[] signature = operationInfo.getSignature();\n\t\tassertThat(signature).hasSize(2);\n\t\tassertThat(signature[0].getName()).isEqualTo(\"one\");\n\t\tassertThat(signature[0].getType()).isEqualTo(String.class.getName());\n\t\tassertThat(signature[0].getDescription()).isEqualTo(\"myone\");\n\t\tassertThat(signature[1].getName()).isEqualTo(\"two\");\n\t\tassertThat(signature[1].getType()).isEqualTo(Object.class.getName());\n\t\tassertThat(signature[1].getDescription()).isNull();\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate JmxOperationParameter mockParameter(String name, Class<?> type, @Nullable String description) {\n\t\tJmxOperationParameter parameter = mock(JmxOperationParameter.class);\n\t\tgiven(parameter.getName()).willReturn(name);\n\t\tgiven(parameter.getType()).willReturn((Class) type);\n\t\tgiven(parameter.getDescription()).willReturn(description);\n\t\treturn parameter;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/TestExposableJmxEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\n\n/**\n * Test {@link ExposableJmxEndpoint} implementation.\n *\n * @author Phillip Webb\n */\npublic class TestExposableJmxEndpoint implements ExposableJmxEndpoint {\n\n\tprivate final Collection<JmxOperation> operations;\n\n\tpublic TestExposableJmxEndpoint(JmxOperation... operations) {\n\t\tthis(Arrays.asList(operations));\n\t}\n\n\tpublic TestExposableJmxEndpoint(Collection<JmxOperation> operations) {\n\t\tthis.operations = operations;\n\t}\n\n\t@Override\n\tpublic EndpointId getEndpointId() {\n\t\treturn EndpointId.of(\"test\");\n\t}\n\n\t@Override\n\tpublic Collection<JmxOperation> getOperations() {\n\t\treturn this.operations;\n\t}\n\n\t@Override\n\tpublic Access getDefaultAccess() {\n\t\treturn Access.UNRESTRICTED;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/TestJmxOperation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationType;\n\n/**\n * Test {@link JmxOperation} implementation.\n *\n * @author Phillip Webb\n */\npublic class TestJmxOperation implements JmxOperation {\n\n\tprivate final OperationType operationType;\n\n\tprivate final @Nullable Function<Map<String, Object>, @Nullable Object> invoke;\n\n\tprivate final List<JmxOperationParameter> parameters;\n\n\tpublic TestJmxOperation() {\n\t\tthis.operationType = OperationType.READ;\n\t\tthis.invoke = null;\n\t\tthis.parameters = Collections.emptyList();\n\t}\n\n\tpublic TestJmxOperation(OperationType operationType) {\n\t\tthis.operationType = operationType;\n\t\tthis.invoke = null;\n\t\tthis.parameters = Collections.emptyList();\n\t}\n\n\tpublic TestJmxOperation(Function<Map<String, Object>, @Nullable Object> invoke) {\n\t\tthis.operationType = OperationType.READ;\n\t\tthis.invoke = invoke;\n\t\tthis.parameters = Collections.emptyList();\n\t}\n\n\tpublic TestJmxOperation(List<JmxOperationParameter> parameters) {\n\t\tthis.operationType = OperationType.READ;\n\t\tthis.invoke = null;\n\t\tthis.parameters = parameters;\n\t}\n\n\t@Override\n\tpublic OperationType getType() {\n\t\treturn this.operationType;\n\t}\n\n\t@Override\n\tpublic @Nullable Object invoke(InvocationContext context) {\n\t\treturn (this.invoke != null) ? this.invoke.apply(context.getArguments()) : \"result\";\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn \"testOperation\";\n\t}\n\n\t@Override\n\tpublic Class<?> getOutputType() {\n\t\treturn String.class;\n\t}\n\n\t@Override\n\tpublic String getDescription() {\n\t\treturn \"Test JMX operation\";\n\t}\n\n\t@Override\n\tpublic List<JmxOperationParameter> getParameters() {\n\t\treturn this.parameters;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/TestJmxOperationResponseMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Test {@link JmxOperationResponseMapper} implementation.\n *\n * @author Stephane Nicoll\n */\nclass TestJmxOperationResponseMapper implements JmxOperationResponseMapper {\n\n\t@Override\n\tpublic @Nullable Object mapResponse(@Nullable Object response) {\n\t\treturn response;\n\t}\n\n\t@Override\n\tpublic Class<?> mapResponseType(Class<?> responseType) {\n\t\treturn responseType;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/DiscoveredJmxOperationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.lang.reflect.Method;\nimport java.time.Instant;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperationParameter;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.jmx.export.annotation.ManagedOperation;\nimport org.springframework.jmx.export.annotation.ManagedOperationParameter;\nimport org.springframework.jmx.export.annotation.ManagedOperationParameters;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DiscoveredJmxOperation}.\n *\n * @author Phillip Webb\n */\nclass DiscoveredJmxOperationTests {\n\n\t@Test\n\tvoid getNameShouldReturnMethodName() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"getEnum\");\n\t\tassertThat(operation.getName()).isEqualTo(\"getEnum\");\n\t}\n\n\t@Test\n\tvoid getOutputTypeShouldReturnJmxType() {\n\t\tassertThat(getOperation(\"getEnum\").getOutputType()).isEqualTo(String.class);\n\t\tassertThat(getOperation(\"getDate\").getOutputType()).isEqualTo(String.class);\n\t\tassertThat(getOperation(\"getInstant\").getOutputType()).isEqualTo(String.class);\n\t\tassertThat(getOperation(\"getInteger\").getOutputType()).isEqualTo(Integer.class);\n\t\tassertThat(getOperation(\"getVoid\").getOutputType()).isEqualTo(void.class);\n\t\tassertThat(getOperation(\"getApplicationContext\").getOutputType()).isEqualTo(Object.class);\n\t}\n\n\t@Test\n\tvoid getDescriptionWhenHasManagedOperationDescriptionShouldUseValueFromAnnotation() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"withManagedOperationDescription\");\n\t\tassertThat(operation.getDescription()).isEqualTo(\"fromannotation\");\n\t}\n\n\t@Test\n\tvoid getDescriptionWhenHasNoManagedOperationShouldGenerateDescription() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"getEnum\");\n\t\tassertThat(operation.getDescription()).isEqualTo(\"Invoke getEnum for endpoint test\");\n\t}\n\n\t@Test\n\tvoid getParametersWhenHasNoParametersShouldReturnEmptyList() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"getEnum\");\n\t\tassertThat(operation.getParameters()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getParametersShouldReturnJmxTypes() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"params\");\n\t\tList<JmxOperationParameter> parameters = operation.getParameters();\n\t\tassertThat(parameters.get(0).getType()).isEqualTo(String.class);\n\t\tassertThat(parameters.get(1).getType()).isEqualTo(String.class);\n\t\tassertThat(parameters.get(2).getType()).isEqualTo(String.class);\n\t\tassertThat(parameters.get(3).getType()).isEqualTo(Integer.class);\n\t\tassertThat(parameters.get(4).getType()).isEqualTo(Object.class);\n\t}\n\n\t@Test\n\tvoid getParametersWhenHasManagedOperationParameterShouldUseValuesFromAnnotation() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"withManagedOperationParameters\");\n\t\tList<JmxOperationParameter> parameters = operation.getParameters();\n\t\tassertThat(parameters.get(0).getName()).isEqualTo(\"a1\");\n\t\tassertThat(parameters.get(1).getName()).isEqualTo(\"a2\");\n\t\tassertThat(parameters.get(0).getDescription()).isEqualTo(\"d1\");\n\t\tassertThat(parameters.get(1).getDescription()).isEqualTo(\"d2\");\n\t}\n\n\t@Test\n\tvoid getParametersWhenHasNoManagedOperationParameterShouldDeducedValuesName() {\n\t\tDiscoveredJmxOperation operation = getOperation(\"params\");\n\t\tList<JmxOperationParameter> parameters = operation.getParameters();\n\t\tassertThat(parameters.get(0).getName()).isEqualTo(\"enumParam\");\n\t\tassertThat(parameters.get(1).getName()).isEqualTo(\"dateParam\");\n\t\tassertThat(parameters.get(2).getName()).isEqualTo(\"instantParam\");\n\t\tassertThat(parameters.get(3).getName()).isEqualTo(\"integerParam\");\n\t\tassertThat(parameters.get(4).getName()).isEqualTo(\"applicationContextParam\");\n\t\tassertThat(parameters.get(0).getDescription()).isNull();\n\t\tassertThat(parameters.get(1).getDescription()).isNull();\n\t\tassertThat(parameters.get(2).getDescription()).isNull();\n\t\tassertThat(parameters.get(3).getDescription()).isNull();\n\t\tassertThat(parameters.get(4).getDescription()).isNull();\n\t}\n\n\tprivate DiscoveredJmxOperation getOperation(String methodName) {\n\t\tMethod method = findMethod(methodName);\n\t\tAnnotationAttributes annotationAttributes = new AnnotationAttributes();\n\t\tannotationAttributes.put(\"produces\", \"application/xml\");\n\t\tassertThat(method).as(\"Method '%s'\", methodName).isNotNull();\n\t\tDiscoveredOperationMethod operationMethod = new DiscoveredOperationMethod(method, OperationType.READ,\n\t\t\t\tannotationAttributes);\n\t\treturn new DiscoveredJmxOperation(EndpointId.of(\"test\"), operationMethod, mock(OperationInvoker.class));\n\t}\n\n\tprivate @Nullable Method findMethod(String methodName) {\n\t\tMap<String, Method> methods = new HashMap<>();\n\t\tReflectionUtils.doWithMethods(Example.class, (method) -> methods.put(method.getName(), method));\n\t\treturn methods.get(methodName);\n\t}\n\n\tinterface Example {\n\n\t\tOperationType getEnum();\n\n\t\tDate getDate();\n\n\t\tInstant getInstant();\n\n\t\tInteger getInteger();\n\n\t\tvoid getVoid();\n\n\t\tApplicationContext getApplicationContext();\n\n\t\tObject params(OperationType enumParam, Date dateParam, Instant instantParam, Integer integerParam,\n\t\t\t\tApplicationContext applicationContextParam);\n\n\t\t@ManagedOperation(description = \"fromannotation\")\n\t\tObject withManagedOperationDescription();\n\n\t\t@ManagedOperationParameters({ @ManagedOperationParameter(name = \"a1\", description = \"d1\"),\n\t\t\t\t@ManagedOperationParameter(name = \"a2\", description = \"d2\") })\n\t\tObject withManagedOperationParameters(Object one, Object two);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/jmx/annotation/JmxEndpointDiscovererTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.jmx.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperation;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperationParameter;\nimport org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer.JmxEndpointDiscovererRuntimeHints;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.jmx.export.annotation.ManagedOperation;\nimport org.springframework.jmx.export.annotation.ManagedOperationParameter;\nimport org.springframework.jmx.export.annotation.ManagedOperationParameters;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link JmxEndpointDiscoverer}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass JmxEndpointDiscovererTests {\n\n\t@Test\n\tvoid getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {\n\t\tload(EmptyConfiguration.class, (discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty());\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldDiscoverStandardEndpoints() {\n\t\tload(TestEndpoint.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableJmxEndpoint> endpoints = discover(discoverer);\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tMap<String, JmxOperation> operationByName = mapOperations(getJmxEndpoint(endpoints).getOperations());\n\t\t\tassertThat(operationByName).containsOnlyKeys(\"getAll\", \"getSomething\", \"update\", \"deleteSomething\");\n\t\t\tJmxOperation getAll = operationByName.get(\"getAll\");\n\t\t\tassertThat(getAll).isNotNull();\n\t\t\tassertThat(getAll.getDescription()).isEqualTo(\"Invoke getAll for endpoint test\");\n\t\t\tassertThat(getAll.getOutputType()).isEqualTo(Object.class);\n\t\t\tassertThat(getAll.getParameters()).isEmpty();\n\t\t\tJmxOperation getSomething = operationByName.get(\"getSomething\");\n\t\t\tassertThat(getSomething).isNotNull();\n\t\t\tassertThat(getSomething.getDescription()).isEqualTo(\"Invoke getSomething for endpoint test\");\n\t\t\tassertThat(getSomething.getOutputType()).isEqualTo(String.class);\n\t\t\tassertThat(getSomething.getParameters()).hasSize(1);\n\t\t\tassertThat(getSomething.getParameters().get(0).getType()).isEqualTo(String.class);\n\t\t\tJmxOperation update = operationByName.get(\"update\");\n\t\t\tassertThat(update).isNotNull();\n\t\t\tassertThat(update.getDescription()).isEqualTo(\"Invoke update for endpoint test\");\n\t\t\tassertThat(update.getOutputType()).isEqualTo(Void.TYPE);\n\t\t\tassertThat(update.getParameters()).hasSize(2);\n\t\t\tassertThat(update.getParameters().get(0).getType()).isEqualTo(String.class);\n\t\t\tassertThat(update.getParameters().get(1).getType()).isEqualTo(String.class);\n\t\t\tJmxOperation deleteSomething = operationByName.get(\"deleteSomething\");\n\t\t\tassertThat(deleteSomething).isNotNull();\n\t\t\tassertThat(deleteSomething.getDescription()).isEqualTo(\"Invoke deleteSomething for endpoint test\");\n\t\t\tassertThat(deleteSomething.getOutputType()).isEqualTo(Void.TYPE);\n\t\t\tassertThat(deleteSomething.getParameters()).hasSize(1);\n\t\t\tassertThat(deleteSomething.getParameters().get(0).getType()).isEqualTo(String.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasFilteredEndpointShouldOnlyDiscoverJmxEndpoints() {\n\t\tload(MultipleEndpointsConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableJmxEndpoint> endpoints = discover(discoverer);\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"), EndpointId.of(\"jmx\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenJmxExtensionIsMissingEndpointShouldThrowException() {\n\t\tload(TestJmxEndpointExtension.class, (discoverer) -> assertThatIllegalStateException()\n\t\t\t.isThrownBy(discoverer::getEndpoints)\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Invalid extension 'jmxEndpointDiscovererTests.TestJmxEndpointExtension': no endpoint found with id 'test'\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasJmxExtensionShouldOverrideStandardEndpoint() {\n\t\tload(OverriddenOperationJmxEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableJmxEndpoint> endpoints = discover(discoverer);\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tassertJmxTestEndpoint(getJmxEndpoint(endpoints));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasJmxExtensionWithNewOperationAddsExtraOperation() {\n\t\tload(AdditionalOperationJmxEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableJmxEndpoint> endpoints = discover(discoverer);\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tMap<String, JmxOperation> operationByName = mapOperations(getJmxEndpoint(endpoints).getOperations());\n\t\t\tassertThat(operationByName).containsOnlyKeys(\"getAll\", \"getSomething\", \"update\", \"deleteSomething\",\n\t\t\t\t\t\"getAnother\");\n\t\t\tJmxOperation getAnother = operationByName.get(\"getAnother\");\n\t\t\tassertThat(getAnother).isNotNull();\n\t\t\tassertThat(getAnother.getDescription()).isEqualTo(\"Get another thing\");\n\t\t\tassertThat(getAnother.getOutputType()).isEqualTo(Object.class);\n\t\t\tassertThat(getAnother.getParameters()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasCacheWithTtlShouldCacheReadOperationWithTtlValue() {\n\t\tload(TestEndpoint.class, (id) -> 500L, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableJmxEndpoint> endpoints = discover(discoverer);\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tMap<String, JmxOperation> operationByName = mapOperations(getJmxEndpoint(endpoints).getOperations());\n\t\t\tassertThat(operationByName).containsOnlyKeys(\"getAll\", \"getSomething\", \"update\", \"deleteSomething\");\n\t\t\tJmxOperation getAll = operationByName.get(\"getAll\");\n\t\t\tassertThat(getAll).isNotNull();\n\t\t\tassertThat(getInvoker(getAll)).isInstanceOf(CachingOperationInvoker.class);\n\t\t\tassertThat(((CachingOperationInvoker) getInvoker(getAll)).getTimeToLive()).isEqualTo(500);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldCacheReadOperations() {\n\t\tload(AdditionalOperationJmxEndpointConfiguration.class, (id) -> 500L, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableJmxEndpoint> endpoints = discover(discoverer);\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tMap<String, JmxOperation> operationByName = mapOperations(getJmxEndpoint(endpoints).getOperations());\n\t\t\tassertThat(operationByName).containsOnlyKeys(\"getAll\", \"getSomething\", \"update\", \"deleteSomething\",\n\t\t\t\t\t\"getAnother\");\n\t\t\tJmxOperation getAll = operationByName.get(\"getAll\");\n\t\t\tassertThat(getAll).isNotNull();\n\t\t\tassertThat(getInvoker(getAll)).isInstanceOf(CachingOperationInvoker.class);\n\t\t\tassertThat(((CachingOperationInvoker) getInvoker(getAll)).getTimeToLive()).isEqualTo(500);\n\t\t\tJmxOperation getAnother = operationByName.get(\"getAnother\");\n\t\t\tassertThat(getAnother).isNotNull();\n\t\t\tassertThat(getInvoker(getAnother)).isInstanceOf(CachingOperationInvoker.class);\n\t\t\tassertThat(((CachingOperationInvoker) getInvoker(getAnother)).getTimeToLive()).isEqualTo(500);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTwoExtensionsHaveTheSameEndpointTypeShouldThrowException() {\n\t\tload(ClashingJmxEndpointConfiguration.class, (discoverer) -> assertThatIllegalStateException()\n\t\t\t.isThrownBy(discoverer::getEndpoints)\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Found multiple extensions for the endpoint bean testEndpoint (testExtensionOne, testExtensionTwo)\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTwoStandardEndpointsHaveTheSameIdShouldThrowException() {\n\t\tload(ClashingStandardEndpointConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Found two endpoints with the id 'test': \"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenWhenEndpointHasTwoOperationsWithTheSameNameShouldThrowException() {\n\t\tload(ClashingOperationsEndpoint.class, (discoverer) -> assertThatIllegalStateException()\n\t\t\t.isThrownBy(discoverer::getEndpoints)\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Unable to map duplicate endpoint operations: [MBean call 'getAll'] to jmxEndpointDiscovererTests.ClashingOperationsEndpoint\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenWhenExtensionHasTwoOperationsWithTheSameNameShouldThrowException() {\n\t\tload(AdditionalClashingOperationsConfiguration.class, (discoverer) -> assertThatIllegalStateException()\n\t\t\t.isThrownBy(discoverer::getEndpoints)\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Unable to map duplicate endpoint operations: [MBean call 'getAll'] to testEndpoint (clashingOperationsJmxEndpointExtension)\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenExtensionIsNotCompatibleWithTheEndpointTypeShouldThrowException() {\n\t\tload(InvalidJmxExtensionConfiguration.class, (discoverer) -> assertThatIllegalStateException()\n\t\t\t.isThrownBy(discoverer::getEndpoints)\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Endpoint bean 'nonJmxEndpoint' cannot support the extension bean 'nonJmxJmxEndpointExtension'\"));\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew JmxEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(JmxEndpointFilter.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\tprivate Object getInvoker(JmxOperation operation) {\n\t\tObject invoker = ReflectionTestUtils.getField(operation, \"invoker\");\n\t\tassertThat(invoker).isNotNull();\n\t\treturn invoker;\n\t}\n\n\tprivate void assertJmxTestEndpoint(ExposableJmxEndpoint endpoint) {\n\t\tMap<String, JmxOperation> operationsByName = mapOperations(endpoint.getOperations());\n\t\tassertThat(operationsByName).containsOnlyKeys(\"getAll\", \"getSomething\", \"update\", \"deleteSomething\");\n\t\tJmxOperation getAll = operationsByName.get(\"getAll\");\n\t\tassertThat(getAll).isNotNull();\n\t\tassertThat(getAll.getDescription()).isEqualTo(\"Get all the things\");\n\t\tassertThat(getAll.getOutputType()).isEqualTo(Object.class);\n\t\tassertThat(getAll.getParameters()).isEmpty();\n\t\tJmxOperation getSomething = operationsByName.get(\"getSomething\");\n\t\tassertThat(getSomething).isNotNull();\n\t\tassertThat(getSomething.getDescription()).isEqualTo(\"Get something based on a timeUnit\");\n\t\tassertThat(getSomething.getOutputType()).isEqualTo(String.class);\n\t\tassertThat(getSomething.getParameters()).hasSize(1);\n\t\thasDocumentedParameter(getSomething, 0, \"unitMs\", Long.class, \"Number of milliseconds\");\n\t\tJmxOperation update = operationsByName.get(\"update\");\n\t\tassertThat(update).isNotNull();\n\t\tassertThat(update.getDescription()).isEqualTo(\"Update something based on bar\");\n\t\tassertThat(update.getOutputType()).isEqualTo(Void.TYPE);\n\t\tassertThat(update.getParameters()).hasSize(2);\n\t\thasDocumentedParameter(update, 0, \"foo\", String.class, \"Foo identifier\");\n\t\thasDocumentedParameter(update, 1, \"bar\", String.class, \"Bar value\");\n\t\tJmxOperation deleteSomething = operationsByName.get(\"deleteSomething\");\n\t\tassertThat(deleteSomething).isNotNull();\n\t\tassertThat(deleteSomething.getDescription()).isEqualTo(\"Delete something based on a timeUnit\");\n\t\tassertThat(deleteSomething.getOutputType()).isEqualTo(Void.TYPE);\n\t\tassertThat(deleteSomething.getParameters()).hasSize(1);\n\t\thasDocumentedParameter(deleteSomething, 0, \"unitMs\", Long.class, \"Number of milliseconds\");\n\t}\n\n\tprivate void hasDocumentedParameter(JmxOperation operation, int index, String name, Class<?> type,\n\t\t\tString description) {\n\t\tassertThat(index).isLessThan(operation.getParameters().size());\n\t\tJmxOperationParameter parameter = operation.getParameters().get(index);\n\t\tassertThat(parameter.getName()).isEqualTo(name);\n\t\tassertThat(parameter.getType()).isEqualTo(type);\n\t\tassertThat(parameter.getDescription()).isEqualTo(description);\n\t}\n\n\tprivate Map<EndpointId, ExposableJmxEndpoint> discover(JmxEndpointDiscoverer discoverer) {\n\t\tMap<EndpointId, ExposableJmxEndpoint> byId = new HashMap<>();\n\t\tdiscoverer.getEndpoints().forEach((endpoint) -> byId.put(endpoint.getEndpointId(), endpoint));\n\t\treturn byId;\n\t}\n\n\tprivate Map<String, JmxOperation> mapOperations(Collection<JmxOperation> operations) {\n\t\tMap<String, JmxOperation> byName = new HashMap<>();\n\t\toperations.forEach((operation) -> byName.put(operation.getName(), operation));\n\t\treturn byName;\n\t}\n\n\tprivate void load(Class<?> configuration, Consumer<JmxEndpointDiscoverer> consumer) {\n\t\tload(configuration, (id) -> null, consumer);\n\t}\n\n\tprivate void load(Class<?> configuration, Function<EndpointId, @Nullable Long> timeToLive,\n\t\t\tConsumer<JmxEndpointDiscoverer> consumer) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configuration)) {\n\t\t\tConversionServiceParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\t\tJmxEndpointDiscoverer discoverer = new JmxEndpointDiscoverer(context, parameterMapper,\n\t\t\t\t\tCollections.singleton(new CachingOperationInvokerAdvisor(timeToLive)), Collections.emptyList(),\n\t\t\t\t\tCollections.emptyList());\n\t\t\tconsumer.accept(discoverer);\n\t\t}\n\t}\n\n\tprivate ExposableJmxEndpoint getJmxEndpoint(Map<EndpointId, ExposableJmxEndpoint> endpoints) {\n\t\tExposableJmxEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\tassertThat(endpoint).isNotNull();\n\t\treturn endpoint;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleEndpointsConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestJmxEndpoint testJmxEndpoint() {\n\t\t\treturn new TestJmxEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tNonJmxEndpoint nonJmxEndpoint() {\n\t\t\treturn new NonJmxEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OverriddenOperationJmxEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestJmxEndpointExtension testJmxEndpointExtension() {\n\t\t\treturn new TestJmxEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AdditionalOperationJmxEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tAdditionalOperationJmxEndpointExtension additionalOperationJmxEndpointExtension() {\n\t\t\treturn new AdditionalOperationJmxEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AdditionalClashingOperationsConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tClashingOperationsJmxEndpointExtension clashingOperationsJmxEndpointExtension() {\n\t\t\treturn new ClashingOperationsJmxEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingJmxEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestJmxEndpointExtension testExtensionOne() {\n\t\t\treturn new TestJmxEndpointExtension();\n\t\t}\n\n\t\t@Bean\n\t\tTestJmxEndpointExtension testExtensionTwo() {\n\t\t\treturn new TestJmxEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingStandardEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpointTwo() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint testEndpointOne() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class InvalidJmxExtensionConfiguration {\n\n\t\t@Bean\n\t\tNonJmxEndpoint nonJmxEndpoint() {\n\t\t\treturn new NonJmxEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tNonJmxJmxEndpointExtension nonJmxJmxEndpointExtension() {\n\t\t\treturn new NonJmxJmxEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable String getSomething(TimeUnit timeUnit) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid update(String foo, String bar) {\n\n\t\t}\n\n\t\t@DeleteOperation\n\t\tvoid deleteSomething(TimeUnit timeUnit) {\n\n\t\t}\n\n\t}\n\n\t@JmxEndpoint(id = \"jmx\")\n\tstatic class TestJmxEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointJmxExtension(endpoint = TestEndpoint.class)\n\tstatic class TestJmxEndpointExtension {\n\n\t\t@ManagedOperation(description = \"Get all the things\")\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@ManagedOperation(description = \"Get something based on a timeUnit\")\n\t\t@ManagedOperationParameters({\n\t\t\t\t@ManagedOperationParameter(name = \"unitMs\", description = \"Number of milliseconds\") })\n\t\t@Nullable String getSomething(Long timeUnit) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@WriteOperation\n\t\t@ManagedOperation(description = \"Update something based on bar\")\n\t\t@ManagedOperationParameters({ @ManagedOperationParameter(name = \"foo\", description = \"Foo identifier\"),\n\t\t\t\t@ManagedOperationParameter(name = \"bar\", description = \"Bar value\") })\n\t\tvoid update(String foo, String bar) {\n\n\t\t}\n\n\t\t@DeleteOperation\n\t\t@ManagedOperation(description = \"Delete something based on a timeUnit\")\n\t\t@ManagedOperationParameters({\n\t\t\t\t@ManagedOperationParameter(name = \"unitMs\", description = \"Number of milliseconds\") })\n\t\tvoid deleteSomething(Long timeUnit) {\n\n\t\t}\n\n\t}\n\n\t@EndpointJmxExtension(endpoint = TestEndpoint.class)\n\tstatic class AdditionalOperationJmxEndpointExtension {\n\n\t\t@ManagedOperation(description = \"Get another thing\")\n\t\t@ReadOperation\n\t\t@Nullable Object getAnother() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class ClashingOperationsEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll(String param) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointJmxExtension(endpoint = TestEndpoint.class)\n\tstatic class ClashingOperationsJmxEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll(String param) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@WebEndpoint(id = \"nonjmx\")\n\tstatic class NonJmxEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getData() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointJmxExtension(endpoint = NonJmxEndpoint.class)\n\tstatic class NonJmxJmxEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getSomething() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointLinksResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.Condition;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EndpointLinksResolver}.\n *\n * @author Andy Wilkinson\n */\n@SuppressWarnings(\"removal\")\nclass EndpointLinksResolverTests {\n\n\t@Test\n\tvoid linkResolutionWithTrailingSlashStripsSlashOnSelfLink() {\n\t\tMap<String, Link> links = new EndpointLinksResolver(Collections.emptyList())\n\t\t\t.resolveLinks(\"https://api.example.com/actuator/\");\n\t\tassertThat(links).hasSize(1);\n\t\tassertThat(links).hasEntrySatisfying(\"self\", linkWithHref(\"https://api.example.com/actuator\"));\n\t}\n\n\t@Test\n\tvoid linkResolutionWithoutTrailingSlash() {\n\t\tMap<String, Link> links = new EndpointLinksResolver(Collections.emptyList())\n\t\t\t.resolveLinks(\"https://api.example.com/actuator\");\n\t\tassertThat(links).hasSize(1);\n\t\tassertThat(links).hasEntrySatisfying(\"self\", linkWithHref(\"https://api.example.com/actuator\"));\n\t}\n\n\t@Test\n\tvoid resolvedLinksContainsALinkForEachWebEndpointOperation() {\n\t\tList<WebOperation> operations = new ArrayList<>();\n\t\toperations.add(operationWithPath(\"/alpha\", \"alpha\"));\n\t\toperations.add(operationWithPath(\"/alpha/{name}\", \"alpha-name\"));\n\t\tExposableWebEndpoint endpoint = mock(ExposableWebEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(EndpointId.of(\"alpha\"));\n\t\tgiven(endpoint.getOperations()).willReturn(operations);\n\t\tString requestUrl = \"https://api.example.com/actuator\";\n\t\tMap<String, Link> links = new EndpointLinksResolver(Collections.singletonList(endpoint))\n\t\t\t.resolveLinks(requestUrl);\n\t\tassertThat(links).hasSize(3);\n\t\tassertThat(links).hasEntrySatisfying(\"self\", linkWithHref(\"https://api.example.com/actuator\"));\n\t\tassertThat(links).hasEntrySatisfying(\"alpha\", linkWithHref(\"https://api.example.com/actuator/alpha\"));\n\t\tassertThat(links).hasEntrySatisfying(\"alpha-name\",\n\t\t\t\tlinkWithHref(\"https://api.example.com/actuator/alpha/{name}\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid resolvedLinksContainsALinkForServletEndpoint() {\n\t\tExposableServletEndpoint servletEndpoint = mock(ExposableServletEndpoint.class);\n\t\tgiven(servletEndpoint.getEndpointId()).willReturn(EndpointId.of(\"alpha\"));\n\t\tgiven(servletEndpoint.getRootPath()).willReturn(\"alpha\");\n\t\tString requestUrl = \"https://api.example.com/actuator\";\n\t\tMap<String, Link> links = new EndpointLinksResolver(Collections.singletonList(servletEndpoint))\n\t\t\t.resolveLinks(requestUrl);\n\t\tassertThat(links).hasSize(2);\n\t\tassertThat(links).hasEntrySatisfying(\"self\", linkWithHref(\"https://api.example.com/actuator\"));\n\t\tassertThat(links).hasEntrySatisfying(\"alpha\", linkWithHref(\"https://api.example.com/actuator/alpha\"));\n\t}\n\n\t@Test\n\tvoid resolvedLinksContainsALinkForControllerEndpoint() {\n\t\tExposableControllerEndpoint controllerEndpoint = mock(ExposableControllerEndpoint.class);\n\t\tgiven(controllerEndpoint.getEndpointId()).willReturn(EndpointId.of(\"alpha\"));\n\t\tgiven(controllerEndpoint.getRootPath()).willReturn(\"alpha\");\n\t\tString requestUrl = \"https://api.example.com/actuator\";\n\t\tMap<String, Link> links = new EndpointLinksResolver(Collections.singletonList(controllerEndpoint))\n\t\t\t.resolveLinks(requestUrl);\n\t\tassertThat(links).hasSize(2);\n\t\tassertThat(links).hasEntrySatisfying(\"self\", linkWithHref(\"https://api.example.com/actuator\"));\n\t\tassertThat(links).hasEntrySatisfying(\"alpha\", linkWithHref(\"https://api.example.com/actuator/alpha\"));\n\t}\n\n\tprivate WebOperation operationWithPath(String path, String id) {\n\t\tWebOperationRequestPredicate predicate = new WebOperationRequestPredicate(path, WebEndpointHttpMethod.GET,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tWebOperation operation = mock(WebOperation.class);\n\t\tgiven(operation.getId()).willReturn(id);\n\t\tgiven(operation.getType()).willReturn(OperationType.READ);\n\t\tgiven(operation.getRequestPredicate()).willReturn(predicate);\n\t\treturn operation;\n\t}\n\n\tprivate Condition<Link> linkWithHref(String href) {\n\t\treturn new Condition<>((link) -> href.equals(link.getHref()), \"Link with href '%s'\", href);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EndpointMapping}.\n *\n * @author Andy Wilkinson\n */\nclass EndpointMappingTests {\n\n\t@Test\n\tvoid normalizationTurnsASlashIntoAnEmptyString() {\n\t\tassertThat(new EndpointMapping(\"/\").getPath()).isEmpty();\n\t}\n\n\t@Test\n\tvoid normalizationLeavesAnEmptyStringAsIs() {\n\t\tassertThat(new EndpointMapping(\"\").getPath()).isEmpty();\n\t}\n\n\t@Test\n\tvoid normalizationRemovesATrailingSlash() {\n\t\tassertThat(new EndpointMapping(\"/test/\").getPath()).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid normalizationAddsALeadingSlash() {\n\t\tassertThat(new EndpointMapping(\"test\").getPath()).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid normalizationAddsALeadingSlashAndRemovesATrailingSlash() {\n\t\tassertThat(new EndpointMapping(\"test/\").getPath()).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid normalizationLeavesAPathWithALeadingSlashAndNoTrailingSlashAsIs() {\n\t\tassertThat(new EndpointMapping(\"/test\").getPath()).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid subPathForAnEmptyStringReturnsBasePath() {\n\t\tassertThat(new EndpointMapping(\"/test\").createSubPath(\"\")).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid subPathWithALeadingSlashIsSeparatedFromBasePathBySingleSlash() {\n\t\tassertThat(new EndpointMapping(\"/test\").createSubPath(\"/one\")).isEqualTo(\"/test/one\");\n\t}\n\n\t@Test\n\tvoid subPathWithoutALeadingSlashIsSeparatedFromBasePathBySingleSlash() {\n\t\tassertThat(new EndpointMapping(\"/test\").createSubPath(\"one\")).isEqualTo(\"/test/one\");\n\t}\n\n\t@Test\n\tvoid trailingSlashIsRemovedFromASubPath() {\n\t\tassertThat(new EndpointMapping(\"/test\").createSubPath(\"one/\")).isEqualTo(\"/test/one\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointMediaTypesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link EndpointMediaTypes}.\n *\n * @author Phillip Webb\n */\nclass EndpointMediaTypesTests {\n\n\tprivate static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\t@Test\n\tvoid defaultReturnsExpectedProducedAndConsumedTypes() {\n\t\tassertThat(EndpointMediaTypes.DEFAULT.getProduced()).containsExactly(V3_JSON, V2_JSON, \"application/json\");\n\t\tassertThat(EndpointMediaTypes.DEFAULT.getConsumed()).containsExactly(V3_JSON, V2_JSON, \"application/json\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenProducedIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new EndpointMediaTypes(null, Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'produced' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenConsumedIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new EndpointMediaTypes(Collections.emptyList(), null))\n\t\t\t.withMessageContaining(\"'consumed' must not be null\");\n\t}\n\n\t@Test\n\tvoid createFromProducedAndConsumedUsesSameListForBoth() {\n\t\tEndpointMediaTypes types = new EndpointMediaTypes(\"spring/framework\", \"spring/boot\");\n\t\tassertThat(types.getProduced()).containsExactly(\"spring/framework\", \"spring/boot\");\n\t\tassertThat(types.getConsumed()).containsExactly(\"spring/framework\", \"spring/boot\");\n\t}\n\n\t@Test\n\tvoid getProducedShouldReturnProduced() {\n\t\tList<String> produced = Arrays.asList(\"a\", \"b\", \"c\");\n\t\tEndpointMediaTypes types = new EndpointMediaTypes(produced, Collections.emptyList());\n\t\tassertThat(types.getProduced()).isEqualTo(produced);\n\t}\n\n\t@Test\n\tvoid getConsumedShouldReturnConsumed() {\n\t\tList<String> consumed = Arrays.asList(\"a\", \"b\", \"c\");\n\t\tEndpointMediaTypes types = new EndpointMediaTypes(Collections.emptyList(), consumed);\n\t\tassertThat(types.getConsumed()).isEqualTo(consumed);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/EndpointServletTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link EndpointServlet}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@SuppressWarnings({ \"deprecation\", \"removal\" })\nclass EndpointServletTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenServletClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new EndpointServlet((Class<Servlet>) null))\n\t\t\t.withMessageContaining(\"'servlet' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenServletIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new EndpointServlet((Servlet) null))\n\t\t\t.withMessageContaining(\"'servlet' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithServletClassShouldCreateServletInstance() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThat(endpointServlet.getServlet()).isInstanceOf(TestServlet.class);\n\t}\n\n\t@Test\n\tvoid getServletShouldGetServlet() {\n\t\tTestServlet servlet = new TestServlet();\n\t\tEndpointServlet endpointServlet = new EndpointServlet(servlet);\n\t\tassertThat(endpointServlet.getServlet()).isEqualTo(servlet);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid withInitParameterNullName() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> endpointServlet.withInitParameter(null, \"value\"));\n\t}\n\n\t@Test\n\tvoid withInitParameterEmptyName() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> endpointServlet.withInitParameter(\" \", \"value\"));\n\t}\n\n\t@Test\n\tvoid withInitParameterShouldReturnNewInstance() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThat(endpointServlet.withInitParameter(\"spring\", \"boot\")).isNotSameAs(endpointServlet);\n\t}\n\n\t@Test\n\tvoid withInitParameterWhenHasExistingShouldMergeParameters() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class).withInitParameter(\"a\", \"b\")\n\t\t\t.withInitParameter(\"c\", \"d\");\n\t\tassertThat(endpointServlet.withInitParameter(\"a\", \"b1\").withInitParameter(\"e\", \"f\").getInitParameters())\n\t\t\t.containsExactly(entry(\"a\", \"b1\"), entry(\"c\", \"d\"), entry(\"e\", \"f\"));\n\t}\n\n\t@Test\n\tvoid withInitParametersNullName() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> endpointServlet.withInitParameters(Collections.singletonMap(null, \"value\")));\n\t}\n\n\t@Test\n\tvoid withInitParametersEmptyName() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> endpointServlet.withInitParameters(Collections.singletonMap(\" \", \"value\")));\n\t}\n\n\t@Test\n\tvoid withInitParametersShouldCreateNewInstance() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThat(endpointServlet.withInitParameters(Collections.singletonMap(\"spring\", \"boot\")))\n\t\t\t.isNotSameAs(endpointServlet);\n\t}\n\n\t@Test\n\tvoid withInitParametersWhenHasExistingShouldMergeParameters() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class).withInitParameter(\"a\", \"b\")\n\t\t\t.withInitParameter(\"c\", \"d\");\n\t\tMap<String, String> extra = new LinkedHashMap<>();\n\t\textra.put(\"a\", \"b1\");\n\t\textra.put(\"e\", \"f\");\n\t\tassertThat(endpointServlet.withInitParameters(extra).getInitParameters()).containsExactly(entry(\"a\", \"b1\"),\n\t\t\t\tentry(\"c\", \"d\"), entry(\"e\", \"f\"));\n\t}\n\n\t@Test\n\tvoid withLoadOnStartupNotSetShouldReturnDefaultValue() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class);\n\t\tassertThat(endpointServlet.getLoadOnStartup()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid withLoadOnStartupSetShouldReturnValue() {\n\t\tEndpointServlet endpointServlet = new EndpointServlet(TestServlet.class).withLoadOnStartup(3);\n\t\tassertThat(endpointServlet.getLoadOnStartup()).isEqualTo(3);\n\t}\n\n\tstatic class TestServlet extends GenericServlet {\n\n\t\t@Override\n\t\tpublic void service(ServletRequest req, ServletResponse res) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/LinkTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Link}.\n *\n * @author Phillip Webb\n */\nclass LinkTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenHrefIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Link(null))\n\t\t\t.withMessageContaining(\"'href' must not be null\");\n\t}\n\n\t@Test\n\tvoid getHrefShouldReturnHref() {\n\t\tString href = \"https://example.com\";\n\t\tLink link = new Link(href);\n\t\tassertThat(link.getHref()).isEqualTo(href);\n\t}\n\n\t@Test\n\tvoid isTemplatedWhenContainsPlaceholderShouldReturnTrue() {\n\t\tString href = \"https://example.com/{path}\";\n\t\tLink link = new Link(href);\n\t\tassertThat(link.isTemplated()).isTrue();\n\t}\n\n\t@Test\n\tvoid isTemplatedWhenContainsNoPlaceholderShouldReturnFalse() {\n\t\tString href = \"https://example.com/path\";\n\t\tLink link = new Link(href);\n\t\tassertThat(link.isTemplated()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/PathMappedEndpointsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PathMappedEndpoints}.\n *\n * @author Phillip Webb\n */\nclass PathMappedEndpointsTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSupplierIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PathMappedEndpoints(null, (WebEndpointsSupplier) null))\n\t\t\t.withMessageContaining(\"'supplier' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSuppliersIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PathMappedEndpoints(null, (Collection<EndpointsSupplier<?>>) null))\n\t\t\t.withMessageContaining(\"'suppliers' must not be null\");\n\t}\n\n\t@Test\n\tvoid iteratorShouldReturnPathMappedEndpoints() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped).hasSize(2);\n\t\tassertThat(mapped).extracting(\"endpointId\").containsExactly(EndpointId.of(\"e2\"), EndpointId.of(\"e3\"));\n\t}\n\n\t@Test\n\tvoid streamShouldReturnPathMappedEndpoints() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.stream()).hasSize(2);\n\t\tassertThat(mapped.stream()).extracting(\"endpointId\").containsExactly(EndpointId.of(\"e2\"), EndpointId.of(\"e3\"));\n\t}\n\n\t@Test\n\tvoid getRootPathWhenContainsIdShouldReturnRootPath() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.getRootPath(EndpointId.of(\"e2\"))).isEqualTo(\"p2\");\n\t}\n\n\t@Test\n\tvoid getRootPathWhenMissingIdShouldReturnNull() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.getRootPath(EndpointId.of(\"xx\"))).isNull();\n\t}\n\n\t@Test\n\tvoid getPathWhenContainsIdShouldReturnRootPath() {\n\t\tassertThat(createTestMapped(null).getPath(EndpointId.of(\"e2\"))).isEqualTo(\"/p2\");\n\t\tassertThat(createTestMapped(\"/x\").getPath(EndpointId.of(\"e2\"))).isEqualTo(\"/x/p2\");\n\t}\n\n\t@Test\n\tvoid getPathWhenMissingIdShouldReturnNull() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.getPath(EndpointId.of(\"xx\"))).isNull();\n\t}\n\n\t@Test\n\tvoid getPathWhenBasePathIsRootAndEndpointIsPathMappedToRootShouldReturnSingleSlash() {\n\t\tPathMappedEndpoints mapped = new PathMappedEndpoints(\"/\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"root\"), \"/\")));\n\t\tassertThat(mapped.getPath(EndpointId.of(\"root\"))).isEqualTo(\"/\");\n\t}\n\n\t@Test\n\tvoid getPathWhenBasePathIsRootAndEndpointIsPathMapped() {\n\t\tPathMappedEndpoints mapped = new PathMappedEndpoints(\"/\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"a\"), \"alpha\")));\n\t\tassertThat(mapped.getPath(EndpointId.of(\"a\"))).isEqualTo(\"/alpha\");\n\t}\n\n\t@Test\n\tvoid getAllRootPathsShouldReturnAllPaths() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.getAllRootPaths()).containsExactly(\"p2\", \"p3\");\n\t}\n\n\t@Test\n\tvoid getAllPathsShouldReturnAllPaths() {\n\t\tassertThat(createTestMapped(null).getAllPaths()).containsExactly(\"/p2\", \"/p3\");\n\t\tassertThat(createTestMapped(\"/x\").getAllPaths()).containsExactly(\"/x/p2\", \"/x/p3\");\n\t}\n\n\t@Test\n\tvoid getEndpointWhenContainsIdShouldReturnPathMappedEndpoint() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tPathMappedEndpoint endpoint = mapped.getEndpoint(EndpointId.of(\"e2\"));\n\t\tassertThat(endpoint).isNotNull();\n\t\tassertThat(endpoint.getRootPath()).isEqualTo(\"p2\");\n\t}\n\n\t@Test\n\tvoid getEndpointWhenMissingIdShouldReturnNull() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.getEndpoint(EndpointId.of(\"xx\"))).isNull();\n\t}\n\n\t@Test\n\tvoid getAdditionalPathsShouldReturnCanonicalAdditionalPaths() {\n\t\tPathMappedEndpoints mapped = createTestMapped(null);\n\t\tassertThat(mapped.getAdditionalPaths(WebServerNamespace.SERVER, EndpointId.of(\"e2\"))).containsExactly(\"/a2\",\n\t\t\t\t\"/A2\");\n\t\tassertThat(mapped.getAdditionalPaths(WebServerNamespace.MANAGEMENT, EndpointId.of(\"e2\"))).isEmpty();\n\t\tassertThat(mapped.getAdditionalPaths(WebServerNamespace.SERVER, EndpointId.of(\"e3\"))).isEmpty();\n\t}\n\n\tprivate PathMappedEndpoints createTestMapped(@Nullable String basePath) {\n\t\tList<ExposableEndpoint<?>> endpoints = new ArrayList<>();\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"e1\")));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"e2\"), \"p2\", WebServerNamespace.SERVER, List.of(\"/a2\", \"A2\")));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"e3\"), \"p3\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"e4\")));\n\t\treturn new PathMappedEndpoints(basePath, () -> endpoints);\n\t}\n\n\tprivate TestPathMappedEndpoint mockEndpoint(EndpointId id, String rootPath) {\n\t\treturn mockEndpoint(id, rootPath, null, null);\n\t}\n\n\tprivate TestPathMappedEndpoint mockEndpoint(EndpointId id, String rootPath,\n\t\t\t@Nullable WebServerNamespace webServerNamespace, @Nullable List<String> additionalPaths) {\n\t\tTestPathMappedEndpoint endpoint = mock(TestPathMappedEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\tgiven(endpoint.getRootPath()).willReturn(rootPath);\n\t\tif (webServerNamespace != null && additionalPaths != null) {\n\t\t\tgiven(endpoint.getAdditionalPaths(webServerNamespace)).willReturn(additionalPaths);\n\t\t}\n\t\treturn endpoint;\n\t}\n\n\tprivate TestEndpoint mockEndpoint(EndpointId id) {\n\t\tTestEndpoint endpoint = mock(TestEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\treturn endpoint;\n\t}\n\n\tpublic interface TestEndpoint extends ExposableEndpoint<Operation> {\n\n\t}\n\n\tpublic interface TestPathMappedEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/ServletEndpointRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterRegistration;\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ServletEndpointRegistrar}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@ExtendWith(MockitoExtension.class)\n@SuppressWarnings({ \"deprecation\", \"removal\" })\nclass ServletEndpointRegistrarTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletContext servletContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ServletRegistration.Dynamic servletDynamic;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate FilterRegistration.Dynamic filterDynamic;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenServletEndpointsIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ServletEndpointRegistrar(null, null))\n\t\t\t.withMessageContaining(\"'servletEndpoints' must not be null\");\n\t}\n\n\t@Test\n\tvoid onStartupShouldRegisterServlets() throws ServletException {\n\t\tassertBasePath(null, \"/test/*\");\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasBasePathShouldIncludeBasePath() throws ServletException {\n\t\tassertBasePath(\"/actuator\", \"/actuator/test/*\");\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasEmptyBasePathShouldPrefixWithSlash() throws ServletException {\n\t\tassertBasePath(\"\", \"/test/*\");\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasRootBasePathShouldNotAddDuplicateSlash() throws ServletException {\n\t\tassertBasePath(\"/\", \"/test/*\");\n\t}\n\n\tprivate void assertBasePath(@Nullable String basePath, String expectedMapping) throws ServletException {\n\t\tgiven(this.servletContext.addServlet(any(String.class), any(Servlet.class))).willReturn(this.servletDynamic);\n\t\tExposableServletEndpoint endpoint = mockEndpoint(new EndpointServlet(TestServlet.class));\n\t\tServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePath, Collections.singleton(endpoint),\n\t\t\t\t(endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\t\tregistrar.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should()\n\t\t\t.addServlet(eq(\"test-actuator-endpoint\"),\n\t\t\t\t\t(Servlet) assertArg((servlet) -> assertThat(servlet).isInstanceOf(TestServlet.class)));\n\t\tthen(this.servletDynamic).should().addMapping(expectedMapping);\n\t\tthen(this.servletContext).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasInitParametersShouldRegisterInitParameters() throws Exception {\n\t\tgiven(this.servletContext.addServlet(any(String.class), any(Servlet.class))).willReturn(this.servletDynamic);\n\t\tExposableServletEndpoint endpoint = mockEndpoint(\n\t\t\t\tnew EndpointServlet(TestServlet.class).withInitParameter(\"a\", \"b\"));\n\t\tServletEndpointRegistrar registrar = new ServletEndpointRegistrar(\"/actuator\", Collections.singleton(endpoint),\n\t\t\t\t(endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\t\tregistrar.onStartup(this.servletContext);\n\t\tthen(this.servletDynamic).should().setInitParameters(Collections.singletonMap(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasLoadOnStartupShouldRegisterLoadOnStartup() throws Exception {\n\t\tgiven(this.servletContext.addServlet(any(String.class), any(Servlet.class))).willReturn(this.servletDynamic);\n\t\tExposableServletEndpoint endpoint = mockEndpoint(new EndpointServlet(TestServlet.class).withLoadOnStartup(7));\n\t\tServletEndpointRegistrar registrar = new ServletEndpointRegistrar(\"/actuator\", Collections.singleton(endpoint),\n\t\t\t\t(endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\t\tregistrar.onStartup(this.servletContext);\n\t\tthen(this.servletDynamic).should().setLoadOnStartup(7);\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasNotLoadOnStartupShouldRegisterDefaultValue() throws Exception {\n\t\tgiven(this.servletContext.addServlet(any(String.class), any(Servlet.class))).willReturn(this.servletDynamic);\n\t\tExposableServletEndpoint endpoint = mockEndpoint(new EndpointServlet(TestServlet.class));\n\t\tServletEndpointRegistrar registrar = new ServletEndpointRegistrar(\"/actuator\", Collections.singleton(endpoint),\n\t\t\t\t(endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\t\tregistrar.onStartup(this.servletContext);\n\t\tthen(this.servletDynamic).should().setLoadOnStartup(-1);\n\t}\n\n\t@Test\n\tvoid onStartupWhenAccessIsDisabledShouldNotRegister() throws Exception {\n\t\tExposableServletEndpoint endpoint = mock(ExposableServletEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(EndpointId.of(\"test\"));\n\t\tServletEndpointRegistrar registrar = new ServletEndpointRegistrar(\"/actuator\", Collections.singleton(endpoint));\n\t\tregistrar.onStartup(this.servletContext);\n\t\tthen(this.servletContext).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid onStartupWhenAccessIsReadOnlyShouldRegisterServletWithFilter() throws Exception {\n\t\tExposableServletEndpoint endpoint = mockEndpoint(new EndpointServlet(TestServlet.class));\n\t\tgiven(endpoint.getEndpointId()).willReturn(EndpointId.of(\"test\"));\n\t\tgiven(this.servletContext.addServlet(any(String.class), any(Servlet.class))).willReturn(this.servletDynamic);\n\t\tgiven(this.servletContext.addFilter(any(String.class), any(Filter.class))).willReturn(this.filterDynamic);\n\t\tServletEndpointRegistrar registrar = new ServletEndpointRegistrar(\"/actuator\", Collections.singleton(endpoint),\n\t\t\t\t(endpointId, defaultAccess) -> Access.READ_ONLY);\n\t\tregistrar.onStartup(this.servletContext);\n\t\tthen(this.servletContext).should()\n\t\t\t.addServlet(eq(\"test-actuator-endpoint\"),\n\t\t\t\t\t(Servlet) assertArg((servlet) -> assertThat(servlet).isInstanceOf(TestServlet.class)));\n\t\tthen(this.servletDynamic).should().addMapping(\"/actuator/test/*\");\n\t\tthen(this.servletContext).should()\n\t\t\t.addFilter(eq(\"test-actuator-endpoint-access-filter\"), (Filter) assertArg((filter) -> assertThat(filter)\n\t\t\t\t.isInstanceOf(\n\t\t\t\t\t\torg.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar.ReadOnlyAccessFilter.class)));\n\t\tthen(this.filterDynamic).should()\n\t\t\t.addMappingForServletNames(EnumSet.allOf(DispatcherType.class), false, \"test-actuator-endpoint\");\n\t}\n\n\tprivate ExposableServletEndpoint mockEndpoint(EndpointServlet endpointServlet) {\n\t\tExposableServletEndpoint endpoint = mock(ExposableServletEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(EndpointId.of(\"test\"));\n\t\tgiven(endpoint.getEndpointServlet()).willReturn(endpointServlet);\n\t\tgiven(endpoint.getRootPath()).willReturn(\"test\");\n\t\treturn endpoint;\n\t}\n\n\tstatic class TestServlet extends GenericServlet {\n\n\t\t@Override\n\t\tpublic void service(ServletRequest req, ServletResponse res) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/WebEndpointResponseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebEndpointResponse}.\n *\n * @author Phillip Webb\n */\nclass WebEndpointResponseTests {\n\n\t@Test\n\tvoid createWithNoParamsShouldReturn200() {\n\t\tWebEndpointResponse<Object> response = new WebEndpointResponse<>();\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t\tassertThat(response.getBody()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithStatusShouldReturnStatus() {\n\t\tWebEndpointResponse<Object> response = new WebEndpointResponse<>(404);\n\t\tassertThat(response.getStatus()).isEqualTo(404);\n\t\tassertThat(response.getBody()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithBodyShouldReturnBody() {\n\t\tWebEndpointResponse<Object> response = new WebEndpointResponse<>(\"body\");\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t\tassertThat(response.getBody()).isEqualTo(\"body\");\n\t}\n\n\t@Test\n\tvoid createWithBodyAndStatusShouldReturnStatusAndBody() {\n\t\tWebEndpointResponse<Object> response = new WebEndpointResponse<>(\"body\", 500);\n\t\tassertThat(response.getStatus()).isEqualTo(500);\n\t\tassertThat(response.getBody()).isEqualTo(\"body\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/WebOperationRequestPredicateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebOperationRequestPredicate}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass WebOperationRequestPredicateTests {\n\n\t@Test\n\tvoid predicatesWithIdenticalPathsAreEqual() {\n\t\tassertThat(predicateWithPath(\"/path\")).isEqualTo(predicateWithPath(\"/path\"));\n\t}\n\n\t@Test\n\tvoid predicatesWithDifferentPathsAreNotEqual() {\n\t\tassertThat(predicateWithPath(\"/one\")).isNotEqualTo(predicateWithPath(\"/two\"));\n\t}\n\n\t@Test\n\tvoid predicatesWithIdenticalPathsWithVariablesAreEqual() {\n\t\tassertThat(predicateWithPath(\"/path/{foo}\")).isEqualTo(predicateWithPath(\"/path/{foo}\"));\n\t}\n\n\t@Test\n\tvoid predicatesWhereOneHasAPathAndTheOtherHasAVariableAreNotEqual() {\n\t\tassertThat(predicateWithPath(\"/path/{foo}\")).isNotEqualTo(predicateWithPath(\"/path/foo\"));\n\t}\n\n\t@Test\n\tvoid predicatesWithSinglePathVariablesInTheSamePlaceAreEqual() {\n\t\tassertThat(predicateWithPath(\"/path/{foo1}\")).isEqualTo(predicateWithPath(\"/path/{foo2}\"));\n\t}\n\n\t@Test\n\tvoid predicatesWithSingleWildcardPathVariablesInTheSamePlaceAreEqual() {\n\t\tassertThat(predicateWithPath(\"/path/{*foo1}\")).isEqualTo(predicateWithPath(\"/path/{*foo2}\"));\n\t}\n\n\t@Test\n\tvoid predicatesWithSingleWildcardPathVariableAndRegularVariableInTheSamePlaceAreNotEqual() {\n\t\tassertThat(predicateWithPath(\"/path/{*foo1}\")).isNotEqualTo(predicateWithPath(\"/path/{foo2}\"));\n\t}\n\n\t@Test\n\tvoid predicatesWithMultiplePathVariablesInTheSamePlaceAreEqual() {\n\t\tassertThat(predicateWithPath(\"/path/{foo1}/more/{bar1}\"))\n\t\t\t.isEqualTo(predicateWithPath(\"/path/{foo2}/more/{bar2}\"));\n\t}\n\n\t@Test\n\tvoid predicateWithWildcardPathVariableReturnsMatchAllRemainingPathSegmentsVariable() {\n\t\tassertThat(predicateWithPath(\"/path/{*foo1}\").getMatchAllRemainingPathSegmentsVariable()).isEqualTo(\"foo1\");\n\t}\n\n\t@Test\n\tvoid predicateWithRegularPathVariableDoesNotReturnMatchAllRemainingPathSegmentsVariable() {\n\t\tassertThat(predicateWithPath(\"/path/{foo1}\").getMatchAllRemainingPathSegmentsVariable()).isNull();\n\t}\n\n\t@Test\n\tvoid predicateWithNoPathVariableDoesNotReturnMatchAllRemainingPathSegmentsVariable() {\n\t\tassertThat(predicateWithPath(\"/path/foo1\").getMatchAllRemainingPathSegmentsVariable()).isNull();\n\t}\n\n\tprivate WebOperationRequestPredicate predicateWithPath(String path) {\n\t\treturn new WebOperationRequestPredicate(path, WebEndpointHttpMethod.GET, Collections.emptyList(),\n\t\t\t\tCollections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/WebServerNamespaceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebServerNamespace}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass WebServerNamespaceTests {\n\n\t@Test\n\tvoid fromWhenValueHasText() {\n\t\tassertThat(WebServerNamespace.from(\"management\")).isEqualTo(WebServerNamespace.MANAGEMENT);\n\t}\n\n\t@Test\n\tvoid fromWhenValueIsNull() {\n\t\tassertThat(WebServerNamespace.from((String) null)).isEqualTo(WebServerNamespace.SERVER);\n\t}\n\n\t@Test\n\tvoid fromWhenValueIsEmpty() {\n\t\tassertThat(WebServerNamespace.from(\"\")).isEqualTo(WebServerNamespace.SERVER);\n\t}\n\n\t@Test\n\tvoid namespaceWithSameValueAreEqual() {\n\t\tassertThat(WebServerNamespace.from(\"value\")).isEqualTo(WebServerNamespace.from(\"value\"));\n\t}\n\n\t@Test\n\tvoid namespaceWithDifferentValuesAreNotEqual() {\n\t\tassertThat(WebServerNamespace.from(\"value\")).isNotEqualTo(WebServerNamespace.from(\"other\"));\n\t}\n\n\t@Test\n\tvoid toStringReturnsString() {\n\t\tassertThat(WebServerNamespace.from(\"value\")).hasToString(\"value\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/BaseConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.convert.support.DefaultConversionService;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Base configuration shared by tests.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\nclass BaseConfiguration {\n\n\t@Bean\n\tEndpointDelegate endpointDelegate() {\n\t\treturn mock(EndpointDelegate.class);\n\t}\n\n\t@Bean\n\tEndpointMediaTypes endpointMediaTypes() {\n\t\tList<String> mediaTypes = Arrays.asList(\"application/vnd.test+json\", \"application/json\");\n\t\treturn new EndpointMediaTypes(mediaTypes, mediaTypes);\n\t}\n\n\t@Bean\n\tWebEndpointDiscoverer webEndpointDiscoverer(EndpointMediaTypes endpointMediaTypes,\n\t\t\tApplicationContext applicationContext, ObjectProvider<PathMapper> pathMappers) {\n\t\tParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\treturn new WebEndpointDiscoverer(applicationContext, parameterMapper, endpointMediaTypes,\n\t\t\t\tpathMappers.orderedStream().toList(), Collections.emptyList(), Collections.emptyList(),\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t}\n\n\t@Bean\n\tstatic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t}\n\n\tinterface EndpointDelegate {\n\n\t\tvoid write();\n\n\t\tvoid write(String foo, String bar);\n\n\t\tvoid delete();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ControllerEndpointDiscovererTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport jakarta.validation.Validator;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ControllerEndpointDiscoverer}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\n@SuppressWarnings({ \"deprecation\", \"removal\" })\nclass ControllerEndpointDiscovererTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty()));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldIncludeControllerEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(TestControllerEndpoint.class).run(assertDiscoverer((discoverer) -> {\n\t\t\tCollection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\tassertThat(endpoints).hasSize(1);\n\t\t\tExposableControllerEndpoint endpoint = endpoints.iterator().next();\n\t\t\tassertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of(\"testcontroller\"));\n\t\t\tassertThat(endpoint.getController()).isInstanceOf(TestControllerEndpoint.class);\n\t\t\tassertThat(ClassUtils.isCglibProxy(endpoint.getController())).isFalse();\n\t\t\tassertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldDiscoverProxyControllerEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(ProxyBeanConfiguration.class, TestProxyControllerEndpoint.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> {\n\t\t\t\tCollection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\t\tassertThat(endpoints).hasSize(1);\n\t\t\t\tExposableControllerEndpoint endpoint = endpoints.iterator().next();\n\t\t\t\tassertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of(\"testcontroller\"));\n\t\t\t\tassertThat(endpoint.getController()).isInstanceOf(TestProxyControllerEndpoint.class);\n\t\t\t\tassertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);\n\t\t\t\tassertThat(ClassUtils.isCglibProxy(endpoint.getController())).isTrue();\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldIncludeRestControllerEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(TestRestControllerEndpoint.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> {\n\t\t\t\tCollection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\t\tassertThat(endpoints).hasSize(1);\n\t\t\t\tExposableControllerEndpoint endpoint = endpoints.iterator().next();\n\t\t\t\tassertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of(\"testrestcontroller\"));\n\t\t\t\tassertThat(endpoint.getController()).isInstanceOf(TestRestControllerEndpoint.class);\n\t\t\t\tassertThat(ClassUtils.isCglibProxy(endpoint.getController())).isFalse();\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldDiscoverProxyRestControllerEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(ProxyBeanConfiguration.class, TestProxyRestControllerEndpoint.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> {\n\t\t\t\tCollection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\t\tassertThat(endpoints).hasSize(1);\n\t\t\t\tExposableControllerEndpoint endpoint = endpoints.iterator().next();\n\t\t\t\tassertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of(\"testrestcontroller\"));\n\t\t\t\tassertThat(endpoint.getController()).isInstanceOf(TestProxyRestControllerEndpoint.class);\n\t\t\t\tassertThat(ClassUtils.isCglibProxy(endpoint.getController())).isTrue();\n\t\t\t\tassertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldNotDiscoverRegularEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> {\n\t\t\t\tCollection<ExposableControllerEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\t\tList<EndpointId> ids = endpoints.stream().map(ExposableControllerEndpoint::getEndpointId).toList();\n\t\t\t\tassertThat(ids).containsOnly(EndpointId.of(\"testcontroller\"), EndpointId.of(\"testrestcontroller\"));\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointWhenEndpointHasOperationsShouldThrowException() {\n\t\tthis.contextRunner.withUserConfiguration(TestControllerWithOperation.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t.withMessageContaining(\"ControllerEndpoints must not declare operations\")));\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ControllerEndpointDiscoverer.ControllerEndpointDiscovererRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(ControllerEndpointFilter.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertDiscoverer(\n\t\t\tConsumer<ControllerEndpointDiscoverer> consumer) {\n\t\treturn (context) -> {\n\t\t\tControllerEndpointDiscoverer discoverer = new ControllerEndpointDiscoverer(context, null,\n\t\t\t\t\tCollections.emptyList());\n\t\t\tconsumer.accept(discoverer);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TestEndpoint.class, TestControllerEndpoint.class, TestRestControllerEndpoint.class })\n\tstatic class WithRegularEndpointConfiguration {\n\n\t}\n\n\t@ControllerEndpoint(id = \"testcontroller\")\n\tstatic class TestControllerEndpoint {\n\n\t}\n\n\t@ControllerEndpoint(id = \"testcontroller\")\n\t@Validated\n\tstatic class TestProxyControllerEndpoint {\n\n\t}\n\n\t@RestControllerEndpoint(id = \"testrestcontroller\")\n\tstatic class TestRestControllerEndpoint {\n\n\t}\n\n\t@RestControllerEndpoint(id = \"testrestcontroller\")\n\t@Validated\n\tstatic class TestProxyRestControllerEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t}\n\n\t@ControllerEndpoint(id = \"testcontroller\")\n\tstatic class TestControllerWithOperation {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"error\";\n\t\t}\n\n\t}\n\n\tstatic class ProxyBeanConfiguration {\n\n\t\t@Bean\n\t\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t\tstatic LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext) {\n\t\t\treturn new LocalValidatorFactoryBean();\n\t\t}\n\n\t\t@Bean\n\t\tstatic MethodValidationPostProcessor methodValidationPostProcessor(ObjectProvider<Validator> validator) {\n\t\t\tMethodValidationPostProcessor processor = new MethodValidationPostProcessor();\n\t\t\tprocessor.setProxyTargetClass(true);\n\t\t\tprocessor.setValidatorProvider(validator);\n\t\t\treturn processor;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/RequestPredicateFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.lang.reflect.Method;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredOperationMethod;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link RequestPredicateFactory}.\n *\n * @author Phillip Webb\n */\nclass RequestPredicateFactoryTests {\n\n\tprivate final RequestPredicateFactory factory = new RequestPredicateFactory(\n\t\t\tnew EndpointMediaTypes(Collections.emptyList(), Collections.emptyList()));\n\n\tprivate final String rootPath = \"/root\";\n\n\t@Test\n\tvoid getRequestPredicateWhenHasMoreThanOneMatchAllThrowsException() {\n\t\tDiscoveredOperationMethod operationMethod = getDiscoveredOperationMethod(MoreThanOneMatchAll.class);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.factory.getRequestPredicate(this.rootPath, operationMethod))\n\t\t\t.withMessage(\"@Selector annotation with Match.ALL_REMAINING must be unique\");\n\t}\n\n\t@Test\n\tvoid getRequestPredicateWhenMatchAllIsNotLastParameterThrowsException() {\n\t\tDiscoveredOperationMethod operationMethod = getDiscoveredOperationMethod(MatchAllIsNotLastParameter.class);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.factory.getRequestPredicate(this.rootPath, operationMethod))\n\t\t\t.withMessage(\"@Selector annotation with Match.ALL_REMAINING must be the last parameter\");\n\t}\n\n\t@Test\n\tvoid getRequestPredicateReturnsPredicateWithPath() {\n\t\tDiscoveredOperationMethod operationMethod = getDiscoveredOperationMethod(ValidSelectors.class);\n\t\tWebOperationRequestPredicate requestPredicate = this.factory.getRequestPredicate(this.rootPath,\n\t\t\t\toperationMethod);\n\t\tassertThat(requestPredicate.getPath()).isEqualTo(\"/root/{one}/{*two}\");\n\t}\n\n\t@Test\n\tvoid getRequestPredicateWithSlashRootReturnsPredicateWithPathWithoutDoubleSlash() {\n\t\tDiscoveredOperationMethod operationMethod = getDiscoveredOperationMethod(ValidSelectors.class);\n\t\tWebOperationRequestPredicate requestPredicate = this.factory.getRequestPredicate(\"/\", operationMethod);\n\t\tassertThat(requestPredicate.getPath()).isEqualTo(\"/{one}/{*two}\");\n\t}\n\n\tprivate DiscoveredOperationMethod getDiscoveredOperationMethod(Class<?> source) {\n\t\tMethod method = source.getDeclaredMethods()[0];\n\t\tAnnotationAttributes attributes = new AnnotationAttributes();\n\t\tattributes.put(\"produces\", \"application/json\");\n\t\treturn new DiscoveredOperationMethod(method, OperationType.READ, attributes);\n\t}\n\n\tstatic class MoreThanOneMatchAll {\n\n\t\tvoid test(@Selector(match = Match.ALL_REMAINING) String[] one,\n\t\t\t\t@Selector(match = Match.ALL_REMAINING) String[] two) {\n\t\t}\n\n\t}\n\n\tstatic class MatchAllIsNotLastParameter {\n\n\t\tvoid test(@Selector(match = Match.ALL_REMAINING) String[] one, @Selector String[] two) {\n\t\t}\n\n\t}\n\n\tstatic class ValidSelectors {\n\n\t\tvoid test(@Selector String[] one, @Selector(match = Match.ALL_REMAINING) String[] two) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/ServletEndpointDiscovererTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.validation.ValidatorFactory;\nimport org.assertj.core.extractor.Extractors;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.web.EndpointServlet;\nimport org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\nimport org.springframework.validation.beanvalidation.MethodValidationInterceptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ServletEndpointDiscoverer}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\n@SuppressWarnings({ \"deprecation\", \"removal\" })\nclass ServletEndpointDiscovererTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty()));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldIncludeServletEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(TestServletEndpoint.class).run(assertDiscoverer((discoverer) -> {\n\t\t\tCollection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\tassertThat(endpoints).hasSize(1);\n\t\t\tExposableServletEndpoint endpoint = endpoints.iterator().next();\n\t\t\tassertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of(\"testservlet\"));\n\t\t\tassertThat(endpoint.getEndpointServlet()).isNotNull();\n\t\t\tObject servlet = Extractors.byName(\"servlet\").apply(endpoint.getEndpointServlet());\n\t\t\tassertThat(ClassUtils.isCglibProxy(servlet)).isFalse();\n\t\t\tassertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldDiscoverProxyServletEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(TestProxyServletEndpoint.class).run(assertDiscoverer((discoverer) -> {\n\t\t\tCollection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\tassertThat(endpoints).hasSize(1);\n\t\t\tExposableServletEndpoint endpoint = endpoints.iterator().next();\n\t\t\tassertThat(endpoint.getEndpointId()).isEqualTo(EndpointId.of(\"testservlet\"));\n\t\t\tassertThat(endpoint.getEndpointServlet()).isNotNull();\n\t\t\tObject servlet = Extractors.byName(\"servlet\").apply(endpoint.getEndpointServlet());\n\t\t\tassertThat(ClassUtils.isCglibProxy(servlet)).isTrue();\n\t\t\tassertThat(endpoint).isInstanceOf(DiscoveredEndpoint.class);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointsShouldNotDiscoverRegularEndpoints() {\n\t\tthis.contextRunner.withUserConfiguration(WithRegularEndpointConfiguration.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> {\n\t\t\t\tCollection<ExposableServletEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\t\tList<EndpointId> ids = endpoints.stream().map(ExposableServletEndpoint::getEndpointId).toList();\n\t\t\t\tassertThat(ids).containsOnly(EndpointId.of(\"testservlet\"));\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid getEndpointWhenEndpointHasOperationsShouldThrowException() {\n\t\tthis.contextRunner.withUserConfiguration(TestServletEndpointWithOperation.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t.withMessageContaining(\"ServletEndpoints must not declare operations\")));\n\t}\n\n\t@Test\n\tvoid getEndpointWhenEndpointNotASupplierShouldThrowException() {\n\t\tthis.contextRunner.withUserConfiguration(TestServletEndpointNotASupplier.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t.withMessageContaining(\"must be a supplier\")));\n\t}\n\n\t@Test\n\tvoid getEndpointWhenEndpointSuppliesWrongTypeShouldThrowException() {\n\t\tthis.contextRunner.withUserConfiguration(TestServletEndpointSupplierOfWrongType.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t.withMessageContaining(\"must supply an EndpointServlet\")));\n\t}\n\n\t@Test\n\tvoid getEndpointWhenEndpointSuppliesNullShouldThrowException() {\n\t\tthis.contextRunner.withUserConfiguration(TestServletEndpointSupplierOfNull.class)\n\t\t\t.run(assertDiscoverer((discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t.withMessageContaining(\"must not supply null\")));\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ServletEndpointDiscoverer.ServletEndpointDiscovererRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(ServletEndpointFilter.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertDiscoverer(\n\t\t\tConsumer<ServletEndpointDiscoverer> consumer) {\n\t\treturn (context) -> {\n\t\t\tServletEndpointDiscoverer discoverer = new ServletEndpointDiscoverer(context, null,\n\t\t\t\t\tCollections.emptyList());\n\t\t\tconsumer.accept(discoverer);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TestEndpoint.class, TestServletEndpoint.class })\n\tstatic class WithRegularEndpointConfiguration {\n\n\t}\n\n\t@ServletEndpoint(id = \"testservlet\")\n\tstatic class TestServletEndpoint implements Supplier<EndpointServlet> {\n\n\t\t@Override\n\t\tpublic EndpointServlet get() {\n\t\t\treturn new EndpointServlet(TestServlet.class);\n\t\t}\n\n\t}\n\n\t@ServletEndpoint(id = \"testservlet\")\n\t@Validated\n\tstatic class TestProxyServletEndpoint implements Supplier<EndpointServlet> {\n\n\t\t@Override\n\t\tpublic EndpointServlet get() {\n\t\t\tValidatorFactory validator = new LocalValidatorFactoryBean();\n\t\t\tTestServlet target = new TestServlet();\n\t\t\tMethodValidationInterceptor interceptor = new MethodValidationInterceptor(validator);\n\t\t\tProxyFactory proxyFactory = new ProxyFactory();\n\t\t\tproxyFactory.setTargetClass(EndpointServlet.class);\n\t\t\tproxyFactory.setTarget(target);\n\t\t\tproxyFactory.setProxyTargetClass(true);\n\t\t\tproxyFactory.addAdvice(interceptor);\n\t\t\tproxyFactory.getProxy();\n\t\t\tTestServlet servlet = (TestServlet) proxyFactory.getProxy();\n\t\t\treturn new EndpointServlet(servlet);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t}\n\n\t@ServletEndpoint(id = \"testservlet\")\n\tstatic class TestServletEndpointWithOperation implements Supplier<EndpointServlet> {\n\n\t\t@Override\n\t\tpublic EndpointServlet get() {\n\t\t\treturn new EndpointServlet(TestServlet.class);\n\t\t}\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"error\";\n\t\t}\n\n\t}\n\n\tstatic class TestServlet extends GenericServlet {\n\n\t\t@Override\n\t\tpublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n\t\t}\n\n\t}\n\n\t@ServletEndpoint(id = \"testservlet\")\n\tstatic class TestServletEndpointNotASupplier {\n\n\t}\n\n\t@ServletEndpoint(id = \"testservlet\")\n\tstatic class TestServletEndpointSupplierOfWrongType implements Supplier<String> {\n\n\t\t@Override\n\t\tpublic String get() {\n\t\t\treturn \"error\";\n\t\t}\n\n\t}\n\n\t@ServletEndpoint(id = \"testservlet\")\n\tstatic class TestServletEndpointSupplierOfNull implements Supplier<EndpointServlet> {\n\n\t\t@Override\n\t\tpublic @Nullable EndpointServlet get() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/annotation/WebEndpointDiscovererTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.annotation;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.assertj.core.api.Condition;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvoker;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointHttpMethod;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer.WebEndpointDiscovererRuntimeHints;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link WebEndpointDiscoverer}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass WebEndpointDiscovererTests {\n\n\t@Test\n\tvoid getEndpointsWhenNoEndpointBeansShouldReturnEmptyCollection() {\n\t\tload(EmptyConfiguration.class, (discoverer) -> assertThat(discoverer.getEndpoints()).isEmpty());\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenWebExtensionIsMissingEndpointShouldThrowException() {\n\t\tload(TestWebEndpointExtensionConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Invalid extension 'endpointExtension': no endpoint found with id 'test'\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasFilteredEndpointShouldOnlyDiscoverWebEndpoints() {\n\t\tload(MultipleEndpointsConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasWebExtensionShouldOverrideStandardEndpoint() {\n\t\tload(OverriddenOperationWebEndpointExtensionConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(requestPredicates(endpoint)).has(requestPredicates(\n\t\t\t\t\tpath(\"test\").httpMethod(WebEndpointHttpMethod.GET).consumes().produces(\"application/json\")));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenExtensionAddsOperationShouldHaveBothOperations() {\n\t\tload(AdditionalOperationWebEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(requestPredicates(endpoint)).has(requestPredicates(\n\t\t\t\t\tpath(\"test\").httpMethod(WebEndpointHttpMethod.GET).consumes().produces(\"application/json\"),\n\t\t\t\t\tpath(\"test/{id}\").httpMethod(WebEndpointHttpMethod.GET).consumes().produces(\"application/json\")));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenPredicateForWriteOperationThatReturnsVoidShouldHaveNoProducedMediaTypes() {\n\t\tload(VoidWriteOperationEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"voidwrite\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"voidwrite\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(requestPredicates(endpoint)).has(requestPredicates(\n\t\t\t\t\tpath(\"voidwrite\").httpMethod(WebEndpointHttpMethod.POST).produces().consumes(\"application/json\")));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTwoExtensionsHaveTheSameEndpointTypeShouldThrowException() {\n\t\tload(ClashingWebEndpointConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Found multiple extensions for the endpoint bean \"\n\t\t\t\t\t\t\t+ \"testEndpoint (testExtensionOne, testExtensionTwo)\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenTwoStandardEndpointsHaveTheSameIdShouldThrowException() {\n\t\tload(ClashingStandardEndpointConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Found two endpoints with the id 'test': \"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenWhenEndpointHasTwoOperationsWithTheSameNameShouldThrowException() {\n\t\tload(ClashingOperationsEndpointConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Unable to map duplicate endpoint operations: \"\n\t\t\t\t\t\t\t+ \"[web request predicate GET to path 'test' \"\n\t\t\t\t\t\t\t+ \"produces: application/json] to clashingOperationsEndpoint\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenExtensionIsNotCompatibleWithTheEndpointTypeShouldThrowException() {\n\t\tload(InvalidWebExtensionConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Endpoint bean 'nonWebEndpoint' cannot support the \"\n\t\t\t\t\t\t\t+ \"extension bean 'nonWebWebEndpointExtension'\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenWhenExtensionHasTwoOperationsWithTheSameNameShouldThrowException() {\n\t\tload(ClashingSelectorsWebEndpointExtensionConfiguration.class,\n\t\t\t\t(discoverer) -> assertThatIllegalStateException().isThrownBy(discoverer::getEndpoints)\n\t\t\t\t\t.withMessageContaining(\"Unable to map duplicate endpoint operations\")\n\t\t\t\t\t.withMessageContaining(\"to testEndpoint (clashingSelectorsExtension)\"));\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasCacheWithTtlShouldCacheReadOperationWithTtlValue() {\n\t\tload((id) -> 500L, EndpointId::toString, TestEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(endpoint.getOperations()).hasSize(1);\n\t\t\tWebOperation operation = endpoint.getOperations().iterator().next();\n\t\t\tObject invoker = ReflectionTestUtils.getField(operation, \"invoker\");\n\t\t\tassertThat(invoker).isInstanceOf(CachingOperationInvoker.class);\n\t\t\tassertThat(((CachingOperationInvoker) invoker).getTimeToLive()).isEqualTo(500);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenOperationReturnsResourceShouldProduceApplicationOctetStream() {\n\t\tload(ResourceEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"resource\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"resource\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(requestPredicates(endpoint))\n\t\t\t\t.has(requestPredicates(path(\"resource\").httpMethod(WebEndpointHttpMethod.GET)\n\t\t\t\t\t.consumes()\n\t\t\t\t\t.produces(\"application/octet-stream\")));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasCustomMediaTypeShouldProduceCustomMediaType() {\n\t\tload(CustomMediaTypesEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"custommediatypes\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"custommediatypes\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(requestPredicates(endpoint)).has(requestPredicates(\n\t\t\t\t\tpath(\"custommediatypes\").httpMethod(WebEndpointHttpMethod.GET).consumes().produces(\"text/plain\"),\n\t\t\t\t\tpath(\"custommediatypes\").httpMethod(WebEndpointHttpMethod.POST).consumes().produces(\"a/b\", \"c/d\"),\n\t\t\t\t\tpath(\"custommediatypes\").httpMethod(WebEndpointHttpMethod.DELETE)\n\t\t\t\t\t\t.consumes()\n\t\t\t\t\t\t.produces(\"text/plain\")));\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasCustomPathShouldReturnCustomPath() {\n\t\tload((id) -> null, (id) -> \"custom/\" + id, AdditionalOperationWebEndpointConfiguration.class, (discoverer) -> {\n\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\tassertThat(endpoints).containsOnlyKeys(EndpointId.of(\"test\"));\n\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\tCondition<List<? extends WebOperationRequestPredicate>> expected = requestPredicates(\n\t\t\t\t\tpath(\"custom/test\").httpMethod(WebEndpointHttpMethod.GET).consumes().produces(\"application/json\"),\n\t\t\t\t\tpath(\"custom/test/{id}\").httpMethod(WebEndpointHttpMethod.GET)\n\t\t\t\t\t\t.consumes()\n\t\t\t\t\t\t.produces(\"application/json\"));\n\t\t\tassertThat(endpoint).isNotNull();\n\t\t\tassertThat(requestPredicates(endpoint)).has(expected);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getEndpointsWhenHasAdditionalPaths() {\n\t\tAdditionalPathsMapper additionalPathsMapper = (id, webServerNamespace) -> {\n\t\t\tif (!WebServerNamespace.SERVER.equals(webServerNamespace)) {\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\t\t\treturn List.of(\"/test\");\n\t\t};\n\t\tload((id) -> null, EndpointId::toString, additionalPathsMapper,\n\t\t\t\tAdditionalOperationWebEndpointConfiguration.class, (discoverer) -> {\n\t\t\t\t\tMap<EndpointId, ExposableWebEndpoint> endpoints = mapEndpoints(discoverer.getEndpoints());\n\t\t\t\t\tExposableWebEndpoint endpoint = endpoints.get(EndpointId.of(\"test\"));\n\t\t\t\t\tassertThat(endpoint).isNotNull();\n\t\t\t\t\tassertThat(endpoint.getAdditionalPaths(WebServerNamespace.SERVER)).containsExactly(\"/test\");\n\t\t\t\t\tassertThat(endpoint.getAdditionalPaths(WebServerNamespace.MANAGEMENT)).isEmpty();\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew WebEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(WebEndpointFilter.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\tprivate void load(Class<?> configuration, Consumer<WebEndpointDiscoverer> consumer) {\n\t\tload((id) -> null, EndpointId::toString, configuration, consumer);\n\t}\n\n\tprivate void load(Function<EndpointId, @Nullable Long> timeToLive, PathMapper endpointPathMapper,\n\t\t\tClass<?> configuration, Consumer<WebEndpointDiscoverer> consumer) {\n\t\tload(timeToLive, endpointPathMapper, null, configuration, consumer);\n\t}\n\n\tprivate void load(Function<EndpointId, @Nullable Long> timeToLive, PathMapper endpointPathMapper,\n\t\t\t@Nullable AdditionalPathsMapper additionalPathsMapper, Class<?> configuration,\n\t\t\tConsumer<WebEndpointDiscoverer> consumer) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configuration)) {\n\t\t\tConversionServiceParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\t\tEndpointMediaTypes mediaTypes = new EndpointMediaTypes(Collections.singletonList(\"application/json\"),\n\t\t\t\t\tCollections.singletonList(\"application/json\"));\n\t\t\tWebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(context, parameterMapper, mediaTypes,\n\t\t\t\t\tCollections.singletonList(endpointPathMapper),\n\t\t\t\t\t(additionalPathsMapper != null) ? Collections.singletonList(additionalPathsMapper) : null,\n\t\t\t\t\tCollections.singleton(new CachingOperationInvokerAdvisor(timeToLive)), Collections.emptyList(),\n\t\t\t\t\tCollections.emptyList());\n\t\t\tconsumer.accept(discoverer);\n\t\t}\n\t}\n\n\tprivate Map<EndpointId, ExposableWebEndpoint> mapEndpoints(Collection<ExposableWebEndpoint> endpoints) {\n\t\tMap<EndpointId, ExposableWebEndpoint> endpointById = new HashMap<>();\n\t\tendpoints.forEach((endpoint) -> endpointById.put(endpoint.getEndpointId(), endpoint));\n\t\treturn endpointById;\n\t}\n\n\tprivate List<WebOperationRequestPredicate> requestPredicates(ExposableWebEndpoint endpoint) {\n\t\treturn endpoint.getOperations().stream().map(WebOperation::getRequestPredicate).toList();\n\t}\n\n\tprivate Condition<List<? extends WebOperationRequestPredicate>> requestPredicates(\n\t\t\tRequestPredicateMatcher... matchers) {\n\t\treturn new Condition<>((predicates) -> {\n\t\t\tif (predicates.size() != matchers.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tMap<WebOperationRequestPredicate, Long> matchCounts = new HashMap<>();\n\t\t\tfor (WebOperationRequestPredicate predicate : predicates) {\n\t\t\t\tmatchCounts.put(predicate, Stream.of(matchers).filter((matcher) -> matcher.matches(predicate)).count());\n\t\t\t}\n\t\t\treturn matchCounts.values().stream().noneMatch((count) -> count != 1);\n\t\t}, Arrays.toString(matchers));\n\t}\n\n\tprivate RequestPredicateMatcher path(String path) {\n\t\treturn new RequestPredicateMatcher(path);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleEndpointsConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tNonWebEndpoint nonWebEndpoint() {\n\t\t\treturn new NonWebEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestWebEndpointExtensionConfiguration {\n\n\t\t@Bean\n\t\tTestWebEndpointExtension endpointExtension() {\n\t\t\treturn new TestWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingOperationsEndpointConfiguration {\n\n\t\t@Bean\n\t\tClashingOperationsEndpoint clashingOperationsEndpoint() {\n\t\t\treturn new ClashingOperationsEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingOperationsWebEndpointExtensionConfiguration {\n\n\t\t@Bean\n\t\tClashingOperationsWebEndpointExtension clashingOperationsExtension() {\n\t\t\treturn new ClashingOperationsWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestEndpointConfiguration.class)\n\tstatic class OverriddenOperationWebEndpointExtensionConfiguration {\n\n\t\t@Bean\n\t\tOverriddenOperationWebEndpointExtension overriddenOperationExtension() {\n\t\t\treturn new OverriddenOperationWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestEndpointConfiguration.class)\n\tstatic class AdditionalOperationWebEndpointConfiguration {\n\n\t\t@Bean\n\t\tAdditionalOperationWebEndpointExtension additionalOperationExtension() {\n\t\t\treturn new AdditionalOperationWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingWebEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestWebEndpointExtension testExtensionOne() {\n\t\t\treturn new TestWebEndpointExtension();\n\t\t}\n\n\t\t@Bean\n\t\tTestWebEndpointExtension testExtensionTwo() {\n\t\t\treturn new TestWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingStandardEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpointTwo() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint testEndpointOne() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClashingSelectorsWebEndpointExtensionConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tClashingSelectorsWebEndpointExtension clashingSelectorsExtension() {\n\t\t\treturn new ClashingSelectorsWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class InvalidWebExtensionConfiguration {\n\n\t\t@Bean\n\t\tNonWebEndpoint nonWebEndpoint() {\n\t\t\treturn new NonWebEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tNonWebWebEndpointExtension nonWebWebEndpointExtension() {\n\t\t\treturn new NonWebWebEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class VoidWriteOperationEndpointConfiguration {\n\n\t\t@Bean\n\t\tVoidWriteOperationEndpoint voidWriteOperationEndpoint() {\n\t\t\treturn new VoidWriteOperationEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class ResourceEndpointConfiguration {\n\n\t\t@Bean\n\t\tResourceEndpoint resourceEndpoint() {\n\t\t\treturn new ResourceEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomMediaTypesEndpointConfiguration {\n\n\t\t@Bean\n\t\tCustomMediaTypesEndpoint customMediaTypesEndpoint() {\n\t\t\treturn new CustomMediaTypesEndpoint();\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = TestEndpoint.class)\n\tstatic class TestWebEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object getOne(@Selector String id) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid update(String foo, String bar) {\n\n\t\t}\n\n\t\tvoid someOtherMethod() {\n\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = TestEndpoint.class)\n\tstatic class OverriddenOperationWebEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = TestEndpoint.class)\n\tstatic class AdditionalOperationWebEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getOne(@Selector String id) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class ClashingOperationsEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAgain() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = TestEndpoint.class)\n\tstatic class ClashingOperationsWebEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAgain() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = TestEndpoint.class)\n\tstatic class ClashingSelectorsWebEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object readOne(@Selector String oneA, @Selector String oneB) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@ReadOperation\n\t\t@Nullable Object readTwo(@Selector String twoA, @Selector String twoB) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@JmxEndpoint(id = \"nonweb\")\n\tstatic class NonWebEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getData() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = NonWebEndpoint.class)\n\tstatic class NonWebWebEndpointExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getSomething(@Selector String name) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"voidwrite\")\n\tstatic class VoidWriteOperationEndpoint {\n\n\t\t@WriteOperation\n\t\tvoid write(String foo, String bar) {\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"resource\")\n\tstatic class ResourceEndpoint {\n\n\t\t@ReadOperation\n\t\tResource read() {\n\t\t\treturn new ByteArrayResource(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"custommediatypes\")\n\tstatic class CustomMediaTypesEndpoint {\n\n\t\t@ReadOperation(produces = \"text/plain\")\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t\t@WriteOperation(produces = { \"a/b\", \"c/d\" })\n\t\tString write() {\n\t\t\treturn \"write\";\n\t\t}\n\n\t\t@DeleteOperation(produces = \"text/plain\")\n\t\tString delete() {\n\t\t\treturn \"delete\";\n\t\t}\n\n\t}\n\n\tprivate static final class RequestPredicateMatcher {\n\n\t\tprivate final String path;\n\n\t\tprivate @Nullable List<String> produces;\n\n\t\tprivate @Nullable List<String> consumes;\n\n\t\tprivate @Nullable WebEndpointHttpMethod httpMethod;\n\n\t\tprivate RequestPredicateMatcher(String path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tRequestPredicateMatcher produces(String... mediaTypes) {\n\t\t\tthis.produces = Arrays.asList(mediaTypes);\n\t\t\treturn this;\n\t\t}\n\n\t\tRequestPredicateMatcher consumes(String... mediaTypes) {\n\t\t\tthis.consumes = Arrays.asList(mediaTypes);\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate RequestPredicateMatcher httpMethod(WebEndpointHttpMethod httpMethod) {\n\t\t\tthis.httpMethod = httpMethod;\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate boolean matches(WebOperationRequestPredicate predicate) {\n\t\t\treturn (this.path == null || this.path.equals(predicate.getPath()))\n\t\t\t\t\t&& (this.httpMethod == null || this.httpMethod == predicate.getHttpMethod())\n\t\t\t\t\t&& (this.produces == null || this.produces.equals(new ArrayList<>(predicate.getProduces())))\n\t\t\t\t\t&& (this.consumes == null || this.consumes.equals(new ArrayList<>(predicate.getConsumes())));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Request predicate with path = '\" + this.path + \"', httpMethod = '\" + this.httpMethod\n\t\t\t\t\t+ \"', produces = '\" + this.produces + \"'\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.env;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigInteger;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentEntryDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceEntryDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertyValueDescriptor;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.CompositePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.mock.env.MockPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EnvironmentEndpoint}.\n *\n * @author Phillip Webb\n * @author Christian Dupuis\n * @author Nicolas Lejeune\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @author HaiTao Zhang\n * @author Chris Bono\n * @author Scott Frederick\n */\nclass EnvironmentEndpointTests {\n\n\t@AfterEach\n\tvoid close() {\n\t\tSystem.clearProperty(\"VCAP_SERVICES\");\n\t}\n\n\t@Test\n\tvoid basicResponse() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tenvironment.getPropertySources().addLast(singleKeyPropertySource(\"one\", \"my.key\", \"first\"));\n\t\tenvironment.getPropertySources().addLast(singleKeyPropertySource(\"two\", \"my.key\", \"second\"));\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tassertThat(descriptor.getActiveProfiles()).isEmpty();\n\t\tMap<String, PropertySourceDescriptor> sources = propertySources(descriptor);\n\t\tassertThat(sources.keySet()).containsExactly(\"one\", \"two\");\n\t\tPropertySourceDescriptor one = sources.get(\"one\");\n\t\tassertThat(one).isNotNull();\n\t\tassertThat(one.getProperties()).containsOnlyKeys(\"my.key\");\n\t\tPropertySourceDescriptor two = sources.get(\"two\");\n\t\tassertThat(two).isNotNull();\n\t\tassertThat(two.getProperties()).containsOnlyKeys(\"my.key\");\n\t}\n\n\t@Test\n\tvoid responseWhenShowNever() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tTestPropertyValues.of(\"other.service=abcde\").applyTo(environment);\n\t\tTestPropertyValues.of(\"system.service=123456\").applyToSystemProperties(() -> {\n\t\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.NEVER)\n\t\t\t\t.environment(null);\n\t\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\t\tassertThat(test).isNotNull();\n\t\t\tPropertyValueDescriptor otherService = test.getProperties().get(\"other.service\");\n\t\t\tassertThat(otherService).isNotNull();\n\t\t\tassertThat(otherService.getValue()).isEqualTo(\"******\");\n\t\t\tPropertySourceDescriptor systemPropertiesDescriptor = propertySources(descriptor).get(\"systemProperties\");\n\t\t\tassertThat(systemPropertiesDescriptor).isNotNull();\n\t\t\tMap<String, PropertyValueDescriptor> systemProperties = systemPropertiesDescriptor.getProperties();\n\t\t\tPropertyValueDescriptor systemService = systemProperties.get(\"system.service\");\n\t\t\tassertThat(systemService).isNotNull();\n\t\t\tassertThat(systemService.getValue()).isEqualTo(\"******\");\n\t\t\treturn null;\n\t\t});\n\t}\n\n\t@Test\n\tvoid responseWhenShowWhenAuthorized() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tTestPropertyValues.of(\"other.service=abcde\").applyTo(environment);\n\t\tTestPropertyValues.of(\"system.service=123456\").applyToSystemProperties(() -> {\n\t\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(),\n\t\t\t\t\tShow.WHEN_AUTHORIZED)\n\t\t\t\t.environment(null);\n\t\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\t\tassertThat(test).isNotNull();\n\t\t\tPropertyValueDescriptor otherService = test.getProperties().get(\"other.service\");\n\t\t\tassertThat(otherService).isNotNull();\n\t\t\tassertThat(otherService.getValue()).isEqualTo(\"abcde\");\n\t\t\tPropertySourceDescriptor systemPropertiesDescriptor = propertySources(descriptor).get(\"systemProperties\");\n\t\t\tassertThat(systemPropertiesDescriptor).isNotNull();\n\t\t\tMap<String, PropertyValueDescriptor> systemProperties = systemPropertiesDescriptor.getProperties();\n\t\t\tPropertyValueDescriptor systemServiceDescriptor = systemProperties.get(\"system.service\");\n\t\t\tassertThat(systemServiceDescriptor).isNotNull();\n\t\t\tassertThat(systemServiceDescriptor.getValue()).isEqualTo(\"123456\");\n\t\t\treturn null;\n\t\t});\n\t}\n\n\t@Test\n\tvoid compositeSourceIsHandledCorrectly() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tCompositePropertySource source = new CompositePropertySource(\"composite\");\n\t\tsource.addPropertySource(new MapPropertySource(\"one\", Collections.singletonMap(\"foo\", \"bar\")));\n\t\tsource.addPropertySource(new MapPropertySource(\"two\", Collections.singletonMap(\"foo\", \"spam\")));\n\t\tenvironment.getPropertySources().addFirst(source);\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tMap<String, PropertySourceDescriptor> sources = propertySources(descriptor);\n\t\tassertThat(sources.keySet()).containsExactly(\"composite:one\", \"composite:two\");\n\t\tPropertySourceDescriptor one = sources.get(\"composite:one\");\n\t\tassertThat(one).isNotNull();\n\t\tPropertyValueDescriptor oneFoo = one.getProperties().get(\"foo\");\n\t\tassertThat(oneFoo).isNotNull();\n\t\tassertThat(oneFoo.getValue()).isEqualTo(\"bar\");\n\t\tPropertySourceDescriptor two = sources.get(\"composite:two\");\n\t\tassertThat(two).isNotNull();\n\t\tPropertyValueDescriptor twoFoo = two.getProperties().get(\"foo\");\n\t\tassertThat(twoFoo).isNotNull();\n\t\tassertThat(twoFoo.getValue()).isEqualTo(\"spam\");\n\t}\n\n\t@Test\n\tvoid keysMatchingCustomSanitizingFunctionHaveTheirValuesSanitized() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tTestPropertyValues.of(\"other.service=abcde\").applyTo(environment);\n\t\tTestPropertyValues.of(\"system.service=123456\").applyToSystemProperties(() -> {\n\t\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment,\n\t\t\t\t\tCollections.singletonList((data) -> {\n\t\t\t\t\t\tPropertySource<?> propertySource = data.getPropertySource();\n\t\t\t\t\t\tassertThat(propertySource).isNotNull();\n\t\t\t\t\t\tString name = propertySource.getName();\n\t\t\t\t\t\tif (name.equals(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)) {\n\t\t\t\t\t\t\treturn data.withValue(\"******\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn data;\n\t\t\t\t\t}), Show.ALWAYS)\n\t\t\t\t.environment(null);\n\t\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\t\tassertThat(test).isNotNull();\n\t\t\tPropertyValueDescriptor otherService = test.getProperties().get(\"other.service\");\n\t\t\tassertThat(otherService).isNotNull();\n\t\t\tassertThat(otherService.getValue()).isEqualTo(\"abcde\");\n\t\t\tPropertySourceDescriptor systemPropertiesDescriptor = propertySources(descriptor).get(\"systemProperties\");\n\t\t\tassertThat(systemPropertiesDescriptor).isNotNull();\n\t\t\tMap<String, PropertyValueDescriptor> systemProperties = systemPropertiesDescriptor.getProperties();\n\t\t\tPropertyValueDescriptor systemService = systemProperties.get(\"system.service\");\n\t\t\tassertThat(systemService).isNotNull();\n\t\t\tassertThat(systemService.getValue()).isEqualTo(\"******\");\n\t\t\treturn null;\n\t\t});\n\t}\n\n\t@Test\n\tvoid propertyWithPlaceholderResolved() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tTestPropertyValues.of(\"my.foo: ${bar.blah}\", \"bar.blah: hello\").applyTo(environment);\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tPropertyValueDescriptor foo = test.getProperties().get(\"my.foo\");\n\t\tassertThat(foo).isNotNull();\n\t\tassertThat(foo.getValue()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid propertyWithPlaceholderNotResolved() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tTestPropertyValues.of(\"my.foo: ${bar.blah}\").applyTo(environment);\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tPropertyValueDescriptor foo = test.getProperties().get(\"my.foo\");\n\t\tassertThat(foo).isNotNull();\n\t\tassertThat(foo.getValue()).isEqualTo(\"${bar.blah}\");\n\t}\n\n\t@Test\n\tvoid propertyWithComplexTypeShouldNotFail() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(singleKeyPropertySource(\"test\", \"foo\", Collections.singletonMap(\"bar\", \"baz\")));\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tPropertyValueDescriptor foo = test.getProperties().get(\"foo\");\n\t\tassertThat(foo).isNotNull();\n\t\tString value = (String) foo.getValue();\n\t\tassertThat(value).isEqualTo(\"Complex property type java.util.Collections$SingletonMap\");\n\t}\n\n\t@Test\n\tvoid propertyWithPrimitiveOrWrapperTypeIsHandledCorrectly() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tmap.put(\"char\", 'a');\n\t\tmap.put(\"integer\", 100);\n\t\tmap.put(\"boolean\", true);\n\t\tmap.put(\"biginteger\", BigInteger.valueOf(200));\n\t\tenvironment.getPropertySources().addFirst(new MapPropertySource(\"test\", map));\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tMap<String, PropertyValueDescriptor> properties = test.getProperties();\n\t\tPropertyValueDescriptor aChar = properties.get(\"char\");\n\t\tassertThat(aChar).isNotNull();\n\t\tassertThat(aChar.getValue()).isEqualTo('a');\n\t\tPropertyValueDescriptor integer = properties.get(\"integer\");\n\t\tassertThat(integer).isNotNull();\n\t\tassertThat(integer.getValue()).isEqualTo(100);\n\t\tPropertyValueDescriptor aBoolean = properties.get(\"boolean\");\n\t\tassertThat(aBoolean).isNotNull();\n\t\tassertThat(aBoolean.getValue()).isEqualTo(true);\n\t\tPropertyValueDescriptor bigInteger = properties.get(\"biginteger\");\n\t\tassertThat(bigInteger).isNotNull();\n\t\tassertThat(bigInteger.getValue()).isEqualTo(BigInteger.valueOf(200));\n\t}\n\n\t@Test\n\tvoid propertyWithCharSequenceTypeIsConvertedToString() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tenvironment.getPropertySources().addFirst(singleKeyPropertySource(\"test\", \"foo\", new CharSequenceProperty()));\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tPropertySourceDescriptor test = propertySources(descriptor).get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tPropertyValueDescriptor foo = test.getProperties().get(\"foo\");\n\t\tassertThat(foo).isNotNull();\n\t\tString value = (String) foo.getValue();\n\t\tassertThat(value).isEqualTo(\"test value\");\n\t}\n\n\t@Test\n\tvoid propertyEntry() {\n\t\ttestPropertyEntry(Show.ALWAYS, \"bar\", \"another\");\n\t}\n\n\t@Test\n\tvoid propertyEntryWhenShowNever() {\n\t\ttestPropertyEntry(Show.NEVER, \"******\", \"******\");\n\t}\n\n\t@Test\n\tvoid propertyEntryWhenShowWhenAuthorized() {\n\t\ttestPropertyEntry(Show.ALWAYS, \"bar\", \"another\");\n\t}\n\n\tprivate void testPropertyEntry(Show always, String bar, String another) {\n\t\tTestPropertyValues.of(\"my.foo=another\").applyToSystemProperties(() -> {\n\t\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\t\tTestPropertyValues.of(\"my.foo=bar\", \"my.foo2=bar2\")\n\t\t\t\t.applyTo(environment, TestPropertyValues.Type.MAP, \"test\");\n\t\t\tEnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(),\n\t\t\t\t\talways)\n\t\t\t\t.environmentEntry(\"my.foo\");\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getProperty()).isNotNull();\n\t\t\tassertThat(descriptor.getProperty().getSource()).isEqualTo(\"test\");\n\t\t\tassertThat(descriptor.getProperty().getValue()).isEqualTo(bar);\n\t\t\tMap<String, PropertySourceEntryDescriptor> sources = propertySources(descriptor);\n\t\t\tassertThat(sources.keySet()).containsExactly(\"test\", \"systemProperties\", \"systemEnvironment\");\n\t\t\tassertPropertySourceEntryDescriptor(sources.get(\"test\"), bar, null);\n\t\t\tassertPropertySourceEntryDescriptor(sources.get(\"systemProperties\"), another, null);\n\t\t\tassertPropertySourceEntryDescriptor(sources.get(\"systemEnvironment\"), null, null);\n\t\t\treturn null;\n\t\t});\n\t}\n\n\t@Test\n\tvoid originAndOriginParents() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tOriginParentMockPropertySource propertySource = new OriginParentMockPropertySource();\n\t\tpropertySource.setProperty(\"name\", \"test\");\n\t\tenvironment.getPropertySources().addFirst(propertySource);\n\t\tEnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(),\n\t\t\t\tShow.ALWAYS)\n\t\t\t.environmentEntry(\"name\");\n\t\tPropertySourceEntryDescriptor entryDescriptor = propertySources(descriptor).get(\"mockProperties\");\n\t\tassertThat(entryDescriptor).isNotNull();\n\t\tPropertyValueDescriptor property = entryDescriptor.getProperty();\n\t\tassertThat(property).isNotNull();\n\t\tassertThat(property.getOrigin()).isEqualTo(\"name\");\n\t\tassertThat(property.getOriginParents()).containsExactly(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid propertyEntryNotFound() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tenvironment.getPropertySources().addFirst(singleKeyPropertySource(\"test\", \"foo\", \"bar\"));\n\t\tEnvironmentEntryDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(),\n\t\t\t\tShow.ALWAYS)\n\t\t\t.environmentEntry(\"does.not.exist\");\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getProperty()).isNull();\n\t\tMap<String, PropertySourceEntryDescriptor> sources = propertySources(descriptor);\n\t\tassertThat(sources.keySet()).containsExactly(\"test\");\n\t\tassertPropertySourceEntryDescriptor(sources.get(\"test\"), null, null);\n\t}\n\n\t@Test\n\tvoid multipleSourcesWithSameProperty() {\n\t\tConfigurableEnvironment environment = emptyEnvironment();\n\t\tenvironment.getPropertySources().addFirst(singleKeyPropertySource(\"one\", \"a\", \"alpha\"));\n\t\tenvironment.getPropertySources().addFirst(singleKeyPropertySource(\"two\", \"a\", \"apple\"));\n\t\tEnvironmentDescriptor descriptor = new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS)\n\t\t\t.environment(null);\n\t\tMap<String, PropertySourceDescriptor> sources = propertySources(descriptor);\n\t\tassertThat(sources.keySet()).containsExactly(\"two\", \"one\");\n\t\tPropertySourceDescriptor one = sources.get(\"one\");\n\t\tassertThat(one).isNotNull();\n\t\tPropertyValueDescriptor oneA = one.getProperties().get(\"a\");\n\t\tassertThat(oneA).isNotNull();\n\t\tassertThat(oneA.getValue()).isEqualTo(\"alpha\");\n\t\tPropertySourceDescriptor two = sources.get(\"two\");\n\t\tassertThat(two).isNotNull();\n\t\tPropertyValueDescriptor twoA = two.getProperties().get(\"a\");\n\t\tassertThat(twoA).isNotNull();\n\t\tassertThat(twoA.getValue()).isEqualTo(\"apple\");\n\t}\n\n\tprivate static ConfigurableEnvironment emptyEnvironment() {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources().remove(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);\n\t\tenvironment.getPropertySources().remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME);\n\t\treturn environment;\n\t}\n\n\tprivate MapPropertySource singleKeyPropertySource(String name, String key, Object value) {\n\t\treturn new MapPropertySource(name, Collections.singletonMap(key, value));\n\t}\n\n\tprivate Map<String, PropertySourceDescriptor> propertySources(EnvironmentDescriptor descriptor) {\n\t\tMap<String, PropertySourceDescriptor> sources = new LinkedHashMap<>();\n\t\tdescriptor.getPropertySources().forEach((d) -> sources.put(d.getName(), d));\n\t\treturn sources;\n\t}\n\n\tprivate Map<String, PropertySourceEntryDescriptor> propertySources(EnvironmentEntryDescriptor descriptor) {\n\t\tMap<String, PropertySourceEntryDescriptor> sources = new LinkedHashMap<>();\n\t\tdescriptor.getPropertySources().forEach((d) -> sources.put(d.getName(), d));\n\t\treturn sources;\n\t}\n\n\tprivate void assertPropertySourceEntryDescriptor(@Nullable PropertySourceEntryDescriptor actual,\n\t\t\t@Nullable Object value, @Nullable String origin) {\n\t\tassertThat(actual).isNotNull();\n\t\tif (value != null) {\n\t\t\tPropertyValueDescriptor property = actual.getProperty();\n\t\t\tassertThat(property).isNotNull();\n\t\t\tassertThat(property.getValue()).isEqualTo(value);\n\t\t\tassertThat(property.getOrigin()).isEqualTo(origin);\n\t\t}\n\t\telse {\n\t\t\tassertThat(actual.getProperty()).isNull();\n\t\t}\n\n\t}\n\n\tstatic class OriginParentMockPropertySource extends MockPropertySource implements OriginLookup<String> {\n\n\t\t@Override\n\t\tpublic Origin getOrigin(String key) {\n\t\t\treturn new MockOrigin(key, new MockOrigin(\"spring\", new MockOrigin(\"boot\", null)));\n\t\t}\n\n\t}\n\n\tstatic class MockOrigin implements Origin {\n\n\t\tprivate final String value;\n\n\t\tprivate final @Nullable MockOrigin parent;\n\n\t\tMockOrigin(String value, @Nullable MockOrigin parent) {\n\t\t\tthis.value = value;\n\t\t\tthis.parent = parent;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getParent() {\n\t\t\treturn this.parent;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class Config {\n\n\t\t@Bean\n\t\tEnvironmentEndpoint environmentEndpoint(Environment environment) {\n\t\t\treturn new EnvironmentEndpoint(environment, Collections.emptyList(), Show.ALWAYS);\n\t\t}\n\n\t}\n\n\tpublic static class CharSequenceProperty implements CharSequence, InputStreamSource {\n\n\t\tprivate final String value = \"test value\";\n\n\t\t@Override\n\t\tpublic int length() {\n\t\t\treturn this.value.length();\n\t\t}\n\n\t\t@Override\n\t\tpublic char charAt(int index) {\n\t\t\treturn this.value.charAt(index);\n\t\t}\n\n\t\t@Override\n\t\tpublic CharSequence subSequence(int start, int end) {\n\t\t\treturn this.value.subSequence(start, end);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\treturn new ByteArrayInputStream(this.value.getBytes());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/env/EnvironmentEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.env;\n\nimport java.security.Principal;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentEntryDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EnvironmentEndpointWebExtension}.\n *\n * @author Madhura Bhave\n */\nclass EnvironmentEndpointWebExtensionTests {\n\n\tprivate @Nullable EnvironmentEndpointWebExtension webExtension;\n\n\tprivate EnvironmentEndpoint delegate;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.delegate = mock(EnvironmentEndpoint.class);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsNever() {\n\t\tthis.webExtension = new EnvironmentEndpointWebExtension(this.delegate, Show.NEVER, Collections.emptySet());\n\t\tthis.webExtension.environment(SecurityContext.NONE, null);\n\t\tthen(this.delegate).should().getEnvironmentDescriptor(null, false);\n\t\tverifyPrefixed(SecurityContext.NONE, false);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsAlways() {\n\t\tthis.webExtension = new EnvironmentEndpointWebExtension(this.delegate, Show.ALWAYS, Collections.emptySet());\n\t\tthis.webExtension.environment(SecurityContext.NONE, null);\n\t\tthen(this.delegate).should().getEnvironmentDescriptor(null, true);\n\t\tverifyPrefixed(SecurityContext.NONE, true);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsWhenAuthorizedAndSecurityContextIsAuthorized() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class));\n\t\tthis.webExtension = new EnvironmentEndpointWebExtension(this.delegate, Show.WHEN_AUTHORIZED,\n\t\t\t\tCollections.emptySet());\n\t\tthis.webExtension.environment(securityContext, null);\n\t\tthen(this.delegate).should().getEnvironmentDescriptor(null, true);\n\t\tverifyPrefixed(securityContext, true);\n\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsWhenAuthorizedAndSecurityContextIsNotAuthorized() {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tthis.webExtension = new EnvironmentEndpointWebExtension(this.delegate, Show.WHEN_AUTHORIZED,\n\t\t\t\tCollections.emptySet());\n\t\tthis.webExtension.environment(securityContext, null);\n\t\tthen(this.delegate).should().getEnvironmentDescriptor(null, false);\n\t\tverifyPrefixed(securityContext, false);\n\t}\n\n\tprivate void verifyPrefixed(SecurityContext securityContext, boolean showUnsanitized) {\n\t\tgiven(this.delegate.getEnvironmentEntryDescriptor(\"test\", showUnsanitized))\n\t\t\t.willReturn(new EnvironmentEntryDescriptor(null, Collections.emptyList(), Collections.emptyList(),\n\t\t\t\t\tCollections.emptyList()));\n\t\tassertThat(this.webExtension).isNotNull();\n\t\tthis.webExtension.environmentEntry(securityContext, \"test\");\n\t\tthen(this.delegate).should().getEnvironmentEntryDescriptor(\"test\", showUnsanitized);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/BuildInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.info.BuildInfoContributor.BuildInfoContributorRuntimeHints;\nimport org.springframework.boot.info.BuildProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BuildInfoContributor}.\n *\n * @author Moritz Halbritter\n */\nclass BuildInfoContributorTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew BuildInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(BuildProperties.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/EnvironmentInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.test.util.TestPropertyValues.Type;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EnvironmentInfoContributor}.\n *\n * @author Stephane Nicoll\n */\nclass EnvironmentInfoContributorTests {\n\n\tprivate final StandardEnvironment environment = new StandardEnvironment();\n\n\t@Test\n\tvoid extractOnlyInfoProperty() {\n\t\tTestPropertyValues.of(\"info.app=my app\", \"info.version=1.0.0\", \"foo=bar\").applyTo(this.environment);\n\t\tInfo actual = contributeFrom(this.environment);\n\t\tassertThat(actual.get(\"app\", String.class)).isEqualTo(\"my app\");\n\t\tassertThat(actual.get(\"version\", String.class)).isEqualTo(\"1.0.0\");\n\t\tassertThat(actual.getDetails()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid extractNoEntry() {\n\t\tTestPropertyValues.of(\"foo=bar\").applyTo(this.environment);\n\t\tInfo actual = contributeFrom(this.environment);\n\t\tassertThat(actual.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid propertiesFromEnvironmentShouldBindCorrectly() {\n\t\tTestPropertyValues.of(\"INFO_ENVIRONMENT_FOO=green\").applyTo(this.environment, Type.SYSTEM_ENVIRONMENT);\n\t\tInfo actual = contributeFrom(this.environment);\n\t\tassertThat(actual.get(\"environment\", Map.class)).containsEntry(\"foo\", \"green\");\n\t}\n\n\tprivate static Info contributeFrom(ConfigurableEnvironment environment) {\n\t\tEnvironmentInfoContributor contributor = new EnvironmentInfoContributor(environment);\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tcontributor.contribute(builder);\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/GitInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.time.Instant;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.info.GitInfoContributor.GitInfoContributorRuntimeHints;\nimport org.springframework.boot.actuate.info.InfoPropertiesInfoContributor.Mode;\nimport org.springframework.boot.info.GitProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GitInfoContributor}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass GitInfoContributorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid coerceDate() {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"branch\", \"master\");\n\t\tproperties.put(\"commit.time\", \"2016-03-04T14:36:33+0100\");\n\t\tGitInfoContributor contributor = new GitInfoContributor(new GitProperties(properties));\n\t\tMap<String, Object> content = contributor.generateContent();\n\t\tassertThat(content.get(\"commit\")).isInstanceOf(Map.class);\n\t\tMap<String, Object> commit = (Map<String, Object>) content.get(\"commit\");\n\t\tObject commitTime = commit.get(\"time\");\n\t\tassertThat(commitTime).isInstanceOf(Instant.class);\n\t\tassertThat(((Instant) commitTime).toEpochMilli()).isEqualTo(1457098593000L);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shortenCommitId() {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"branch\", \"master\");\n\t\tproperties.put(\"commit.id\", \"8e29a0b0d423d2665c6ee5171947c101a5c15681\");\n\t\tGitInfoContributor contributor = new GitInfoContributor(new GitProperties(properties));\n\t\tMap<String, Object> content = contributor.generateContent();\n\t\tassertThat(content.get(\"commit\")).isInstanceOf(Map.class);\n\t\tMap<String, Object> commit = (Map<String, Object>) content.get(\"commit\");\n\t\tassertThat(commit).containsEntry(\"id\", \"8e29a0b\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid withGitIdAndAbbrev() {\n\t\t// gh-11892\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"branch\", \"master\");\n\t\tproperties.put(\"commit.id\", \"1b3cec34f7ca0a021244452f2cae07a80497a7c7\");\n\t\tproperties.put(\"commit.id.abbrev\", \"1b3cec3\");\n\t\tGitInfoContributor contributor = new GitInfoContributor(new GitProperties(properties), Mode.FULL);\n\t\tMap<String, Object> content = contributor.generateContent();\n\t\tMap<String, Object> commit = (Map<String, Object>) content.get(\"commit\");\n\t\tassertThat(commit).isNotNull();\n\t\tassertThat(commit.get(\"id\")).isInstanceOf(Map.class);\n\t\tMap<String, Object> id = (Map<String, Object>) commit.get(\"id\");\n\t\tassertThat(id).containsEntry(\"full\", \"1b3cec34f7ca0a021244452f2cae07a80497a7c7\");\n\t\tassertThat(id).containsEntry(\"abbrev\", \"1b3cec3\");\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew GitInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(GitProperties.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/InfoEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InfoEndpoint}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Meang Akira Tanaka\n * @author Andy Wilkinson\n */\nclass InfoEndpointTests {\n\n\t@Test\n\tvoid info() {\n\t\tInfoEndpoint endpoint = new InfoEndpoint(Arrays.asList((builder) -> builder.withDetail(\"key1\", \"value1\"),\n\t\t\t\t(builder) -> builder.withDetail(\"key2\", \"value2\")));\n\t\tMap<String, Object> info = endpoint.info();\n\t\tassertThat(info).hasSize(2);\n\t\tassertThat(info).containsEntry(\"key1\", \"value1\");\n\t\tassertThat(info).containsEntry(\"key2\", \"value2\");\n\t}\n\n\t@Test\n\tvoid infoWithNoContributorsProducesEmptyMap() {\n\t\tInfoEndpoint endpoint = new InfoEndpoint(Collections.emptyList());\n\t\tMap<String, Object> info = endpoint.info();\n\t\tassertThat(info).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/InfoTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link Info}.\n *\n * @author Stephane Nicoll\n */\nclass InfoTests {\n\n\t@Test\n\tvoid infoIsImmutable() {\n\t\tInfo info = new Info.Builder().withDetail(\"foo\", \"bar\").build();\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(info.getDetails()::clear);\n\t}\n\n\t@Test\n\tvoid infoTakesCopyOfMap() {\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tbuilder.withDetail(\"foo\", \"bar\");\n\t\tInfo build = builder.build();\n\t\tbuilder.withDetail(\"biz\", \"bar\");\n\t\tassertThat(build.getDetails()).containsOnly(entry(\"foo\", \"bar\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/JavaInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.info.JavaInfoContributor.JavaInfoContributorRuntimeHints;\nimport org.springframework.boot.info.JavaInfo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JavaInfoContributor}\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass JavaInfoContributorTests {\n\n\t@Test\n\tvoid javaInfoShouldBeAdded() {\n\t\tJavaInfoContributor javaInfoContributor = new JavaInfoContributor();\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tjavaInfoContributor.contribute(builder);\n\t\tInfo info = builder.build();\n\t\tassertThat(info.getDetails().get(\"java\")).isInstanceOf(JavaInfo.class);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew JavaInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(JavaInfo.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.info.OsInfoContributor.OsInfoContributorRuntimeHints;\nimport org.springframework.boot.info.OsInfo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OsInfoContributor}\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass OsInfoContributorTests {\n\n\t@Test\n\tvoid osInfoShouldBeAdded() {\n\t\tOsInfoContributor osInfoContributor = new OsInfoContributor();\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tosInfoContributor.contribute(builder);\n\t\tInfo info = builder.build();\n\t\tassertThat(info.getDetails().get(\"os\")).isInstanceOf(OsInfo.class);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew OsInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(OsInfo.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/ProcessInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.info.ProcessInfoContributor.ProcessInfoContributorRuntimeHints;\nimport org.springframework.boot.info.ProcessInfo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ProcessInfoContributor}.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass ProcessInfoContributorTests {\n\n\t@Test\n\tvoid processInfoShouldBeAdded() {\n\t\tProcessInfoContributor processInfoContributor = new ProcessInfoContributor();\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tprocessInfoContributor.contribute(builder);\n\t\tInfo info = builder.build();\n\t\tassertThat(info.get(\"process\")).isInstanceOf(ProcessInfo.class);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ProcessInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(ProcessInfo.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_24)\n\tvoid shouldRegisterRuntimeHintsForVirtualThreadSchedulerMXBean() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ProcessInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference.of(\"jdk.management.VirtualThreadSchedulerMXBean\"))\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_PUBLIC_METHODS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SimpleInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link SimpleInfoContributor}.\n *\n * @author Stephane Nicoll\n */\nclass SimpleInfoContributorTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid prefixIsMandatory() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new SimpleInfoContributor(null, new Object()));\n\t}\n\n\t@Test\n\tvoid mapSimpleObject() {\n\t\tObject o = new Object();\n\t\tInfo info = contributeFrom(\"test\", o);\n\t\tassertThat(info.get(\"test\")).isSameAs(o);\n\t}\n\n\tprivate static Info contributeFrom(String prefix, Object detail) {\n\t\tSimpleInfoContributor contributor = new SimpleInfoContributor(prefix, detail);\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tcontributor.contribute(builder);\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/SslInfoContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.info.SslInfoContributor.SslInfoContributorRuntimeHints;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SslInfoContributor}.\n *\n * @author Jonatan Ivanov\n */\nclass SslInfoContributorTests {\n\n\t@Test\n\tvoid sslInfoShouldBeAdded() {\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry(\"test\", mock(SslBundle.class));\n\t\tSslInfo sslInfo = new SslInfo(sslBundles);\n\t\tSslInfoContributor sslInfoContributor = new SslInfoContributor(sslInfo);\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tsslInfoContributor.contribute(builder);\n\t\tInfo info = builder.build();\n\t\tassertThat(info.getDetails().get(\"ssl\")).isInstanceOf(SslInfo.class);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew SslInfoContributorRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(SslInfo.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/logging/LogFileWebEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.logging;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.core.io.Resource;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Tests for {@link LogFileWebEndpoint}.\n *\n * @author Johannes Edmeier\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass LogFileWebEndpointTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate File logFile;\n\n\t@BeforeEach\n\tvoid before(@TempDir Path temp) throws IOException {\n\t\tthis.logFile = Files.createTempFile(temp, \"junit\", null).toFile();\n\t\tFileCopyUtils.copy(\"--TEST--\".getBytes(), this.logFile);\n\t}\n\n\t@Test\n\tvoid nullResponseWithoutLogFile() {\n\t\tLogFileWebEndpoint endpoint = new LogFileWebEndpoint(null, null);\n\t\tassertThat(endpoint.logFile()).isNull();\n\t}\n\n\t@Test\n\tvoid nullResponseWithMissingLogFile() {\n\t\tthis.environment.setProperty(\"logging.file.name\", \"no_test.log\");\n\t\tLogFileWebEndpoint endpoint = new LogFileWebEndpoint(LogFile.get(this.environment), null);\n\t\tassertThat(endpoint.logFile()).isNull();\n\t}\n\n\t@Test\n\tvoid resourceResponseWithLogFile() throws Exception {\n\t\tthis.environment.setProperty(\"logging.file.name\", this.logFile.getAbsolutePath());\n\t\tLogFileWebEndpoint endpoint = new LogFileWebEndpoint(LogFile.get(this.environment), null);\n\t\tResource resource = endpoint.logFile();\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(contentOf(resource.getFile())).isEqualTo(\"--TEST--\");\n\t}\n\n\t@Test\n\tvoid resourceResponseWithExternalLogFile() throws Exception {\n\t\tLogFileWebEndpoint endpoint = new LogFileWebEndpoint(null, this.logFile);\n\t\tResource resource = endpoint.logFile();\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(contentOf(resource.getFile())).isEqualTo(\"--TEST--\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/logging/LoggersEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.logging;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint.GroupLoggerLevelsDescriptor;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint.LoggerLevelsDescriptor;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint.LoggersDescriptor;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint.SingleLoggerLevelsDescriptor;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.logging.LoggerConfiguration;\nimport org.springframework.boot.logging.LoggerConfiguration.LevelConfiguration;\nimport org.springframework.boot.logging.LoggerGroup;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingSystem;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LoggersEndpoint}.\n *\n * @author Ben Hale\n * @author Andy Wilkinson\n * @author HaiTao Zhang\n * @author Madhura Bhave\n */\nclass LoggersEndpointTests {\n\n\tprivate final LoggingSystem loggingSystem = mock(LoggingSystem.class);\n\n\tprivate LoggerGroups loggerGroups;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMap<String, List<String>> groups = Collections.singletonMap(\"test\", Collections.singletonList(\"test.member\"));\n\t\tthis.loggerGroups = new LoggerGroups(groups);\n\t\tLoggerGroup test = this.loggerGroups.get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\ttest.configureLogLevel(LogLevel.DEBUG, (a, b) -> {\n\t\t});\n\t}\n\n\t@Test\n\tvoid loggersShouldReturnLoggerConfigurationsWithNoLoggerGroups() {\n\t\tgiven(this.loggingSystem.getLoggerConfigurations())\n\t\t\t.willReturn(Collections.singletonList(new LoggerConfiguration(\"ROOT\", null, LogLevel.DEBUG)));\n\t\tgiven(this.loggingSystem.getSupportedLogLevels()).willReturn(EnumSet.allOf(LogLevel.class));\n\t\tLoggersDescriptor result = new LoggersEndpoint(this.loggingSystem, new LoggerGroups()).loggers();\n\t\tMap<String, LoggerLevelsDescriptor> loggers = result.getLoggers();\n\t\tSet<LogLevel> levels = result.getLevels();\n\t\tassertThat(loggers).isNotNull();\n\t\tSingleLoggerLevelsDescriptor rootLevels = (SingleLoggerLevelsDescriptor) loggers.get(\"ROOT\");\n\t\tassertThat(rootLevels).isNotNull();\n\t\tassertThat(rootLevels.getConfiguredLevel()).isNull();\n\t\tassertThat(rootLevels.getEffectiveLevel()).isEqualTo(\"DEBUG\");\n\t\tassertThat(levels).containsExactly(LogLevel.OFF, LogLevel.FATAL, LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO,\n\t\t\t\tLogLevel.DEBUG, LogLevel.TRACE);\n\t\tMap<String, GroupLoggerLevelsDescriptor> groups = result.getGroups();\n\t\tassertThat(groups).isEmpty();\n\t}\n\n\t@Test\n\tvoid loggersShouldReturnLoggerConfigurationsWithLoggerGroups() {\n\t\tgiven(this.loggingSystem.getLoggerConfigurations())\n\t\t\t.willReturn(Collections.singletonList(new LoggerConfiguration(\"ROOT\", null, LogLevel.DEBUG)));\n\t\tgiven(this.loggingSystem.getSupportedLogLevels()).willReturn(EnumSet.allOf(LogLevel.class));\n\t\tLoggersDescriptor result = new LoggersEndpoint(this.loggingSystem, this.loggerGroups).loggers();\n\t\tMap<String, GroupLoggerLevelsDescriptor> loggerGroups = result.getGroups();\n\t\tassertThat(loggerGroups).isNotNull();\n\t\tGroupLoggerLevelsDescriptor groupLevel = loggerGroups.get(\"test\");\n\t\tMap<String, LoggerLevelsDescriptor> loggers = result.getLoggers();\n\t\tSet<LogLevel> levels = result.getLevels();\n\t\tassertThat(loggers).isNotNull();\n\t\tSingleLoggerLevelsDescriptor rootLevels = (SingleLoggerLevelsDescriptor) loggers.get(\"ROOT\");\n\t\tassertThat(rootLevels).isNotNull();\n\t\tassertThat(rootLevels.getConfiguredLevel()).isNull();\n\t\tassertThat(rootLevels.getEffectiveLevel()).isEqualTo(\"DEBUG\");\n\t\tassertThat(levels).containsExactly(LogLevel.OFF, LogLevel.FATAL, LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO,\n\t\t\t\tLogLevel.DEBUG, LogLevel.TRACE);\n\t\tassertThat(loggerGroups).isNotNull();\n\t\tassertThat(groupLevel).isNotNull();\n\t\tassertThat(groupLevel.getConfiguredLevel()).isEqualTo(\"DEBUG\");\n\t\tassertThat(groupLevel.getMembers()).containsExactly(\"test.member\");\n\t}\n\n\t@Test\n\tvoid loggerLevelsWhenNameSpecifiedShouldReturnLevels() {\n\t\tgiven(this.loggingSystem.getLoggerConfiguration(\"ROOT\"))\n\t\t\t.willReturn(new LoggerConfiguration(\"ROOT\", null, LogLevel.DEBUG));\n\t\tSingleLoggerLevelsDescriptor levels = (SingleLoggerLevelsDescriptor) new LoggersEndpoint(this.loggingSystem,\n\t\t\t\tthis.loggerGroups)\n\t\t\t.loggerLevels(\"ROOT\");\n\t\tassertThat(levels).isNotNull();\n\t\tassertThat(levels.getConfiguredLevel()).isNull();\n\t\tassertThat(levels.getEffectiveLevel()).isEqualTo(\"DEBUG\");\n\t}\n\n\t@Test // gh-35227\n\tvoid loggerLevelsWhenCustomLevelShouldReturnLevels() {\n\t\tgiven(this.loggingSystem.getLoggerConfiguration(\"ROOT\"))\n\t\t\t.willReturn(new LoggerConfiguration(\"ROOT\", null, LevelConfiguration.ofCustom(\"FINEST\")));\n\t\tSingleLoggerLevelsDescriptor levels = (SingleLoggerLevelsDescriptor) new LoggersEndpoint(this.loggingSystem,\n\t\t\t\tthis.loggerGroups)\n\t\t\t.loggerLevels(\"ROOT\");\n\t\tassertThat(levels).isNotNull();\n\t\tassertThat(levels.getConfiguredLevel()).isNull();\n\t\tassertThat(levels.getEffectiveLevel()).isEqualTo(\"FINEST\");\n\t}\n\n\t@Test\n\tvoid groupNameSpecifiedShouldReturnConfiguredLevelAndMembers() {\n\t\tGroupLoggerLevelsDescriptor levels = (GroupLoggerLevelsDescriptor) new LoggersEndpoint(this.loggingSystem,\n\t\t\t\tthis.loggerGroups)\n\t\t\t.loggerLevels(\"test\");\n\t\tassertThat(levels).isNotNull();\n\t\tassertThat(levels.getConfiguredLevel()).isEqualTo(\"DEBUG\");\n\t\tassertThat(levels.getMembers()).isEqualTo(Collections.singletonList(\"test.member\"));\n\t}\n\n\t@Test\n\tvoid configureLogLevelShouldSetLevelOnLoggingSystem() {\n\t\tnew LoggersEndpoint(this.loggingSystem, this.loggerGroups).configureLogLevel(\"ROOT\", LogLevel.DEBUG);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", LogLevel.DEBUG);\n\t}\n\n\t@Test\n\tvoid configureLogLevelWithNullSetsLevelOnLoggingSystemToNull() {\n\t\tnew LoggersEndpoint(this.loggingSystem, this.loggerGroups).configureLogLevel(\"ROOT\", null);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"ROOT\", null);\n\t}\n\n\t@Test\n\tvoid configureLogLevelInLoggerGroupShouldSetLevelOnLoggingSystem() {\n\t\tnew LoggersEndpoint(this.loggingSystem, this.loggerGroups).configureLogLevel(\"test\", LogLevel.DEBUG);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member\", LogLevel.DEBUG);\n\t}\n\n\t@Test\n\tvoid configureLogLevelWithNullInLoggerGroupShouldSetLevelOnLoggingSystem() {\n\t\tnew LoggersEndpoint(this.loggingSystem, this.loggerGroups).configureLogLevel(\"test\", null);\n\t\tthen(this.loggingSystem).should().setLogLevel(\"test.member\", null);\n\t}\n\n\t@Test\n\tvoid registersRuntimeHintsForClassesSerializedToJson() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ReflectiveRuntimeHintsRegistrar().registerRuntimeHints(runtimeHints, LoggersEndpoint.class);\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tassertThat(reflection.onType(LoggerLevelsDescriptor.class)).accepts(runtimeHints);\n\t\tassertThat(reflection.onMethodInvocation(LoggerLevelsDescriptor.class, \"getConfiguredLevel\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(reflection.onType(SingleLoggerLevelsDescriptor.class)).accepts(runtimeHints);\n\t\tassertThat(reflection.onMethodInvocation(SingleLoggerLevelsDescriptor.class, \"getEffectiveLevel\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(reflection.onMethodInvocation(SingleLoggerLevelsDescriptor.class, \"getConfiguredLevel\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(reflection.onType(GroupLoggerLevelsDescriptor.class)).accepts(runtimeHints);\n\t\tassertThat(reflection.onMethodInvocation(GroupLoggerLevelsDescriptor.class, \"getMembers\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(reflection.onMethodInvocation(GroupLoggerLevelsDescriptor.class, \"getConfiguredLevel\"))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/management/HeapDumpWebEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport java.nio.file.Files;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HeapDumpWebEndpoint}.\n *\n * @author Andy Wilkinson\n */\nclass HeapDumpWebEndpointTests {\n\n\t@Test\n\tvoid parallelRequestProducesTooManyRequestsResponse() throws InterruptedException {\n\t\tCountDownLatch dumpingLatch = new CountDownLatch(1);\n\t\tCountDownLatch blockingLatch = new CountDownLatch(1);\n\t\tHeapDumpWebEndpoint slowEndpoint = new HeapDumpWebEndpoint(2500) {\n\n\t\t\t@Override\n\t\t\tprotected HeapDumper createHeapDumper() {\n\t\t\t\treturn (live) -> {\n\t\t\t\t\tdumpingLatch.countDown();\n\t\t\t\t\tblockingLatch.await();\n\t\t\t\t\treturn Files.createTempFile(\"heap-\", \".dump\").toFile();\n\t\t\t\t};\n\t\t\t}\n\n\t\t};\n\t\tThread thread = new Thread(() -> slowEndpoint.heapDump(true));\n\t\tthread.start();\n\t\tdumpingLatch.await();\n\t\tassertThat(slowEndpoint.heapDump(true).getStatus()).isEqualTo(429);\n\t\tblockingLatch.countDown();\n\t\tthread.join();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/management/ThreadDumpEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.management;\n\nimport java.lang.Thread.State;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ThreadDumpEndpoint}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ThreadDumpEndpointTests {\n\n\t@Test\n\tvoid dumpThreads() {\n\t\tassertThat(new ThreadDumpEndpoint().threadDump().getThreads()).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid dumpThreadsAsText() throws InterruptedException {\n\t\tObject contendedMonitor = new Object();\n\t\tObject monitor = new Object();\n\t\tCountDownLatch latch = new CountDownLatch(1);\n\t\tThread awaitCountDownLatchThread = new Thread(() -> {\n\t\t\ttry {\n\t\t\t\tlatch.await();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}, \"Awaiting CountDownLatch\");\n\t\tawaitCountDownLatchThread.start();\n\t\tThread contendedMonitorThread = new Thread(() -> {\n\t\t\tsynchronized (contendedMonitor) {\n\t\t\t\t// Intentionally empty\n\t\t\t}\n\t\t}, \"Waiting for monitor\");\n\t\tThread waitOnMonitorThread = new Thread(() -> {\n\t\t\tsynchronized (monitor) {\n\t\t\t\ttry {\n\t\t\t\t\tmonitor.wait();\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t}\n\t\t}, \"Waiting on monitor\");\n\t\twaitOnMonitorThread.start();\n\t\tReadWriteLock readWriteLock = new ReentrantReadWriteLock();\n\t\tLock writeLock = readWriteLock.writeLock();\n\t\tnew Thread(() -> {\n\t\t\twriteLock.lock();\n\t\t\ttry {\n\t\t\t\tlatch.await();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\twriteLock.unlock();\n\t\t\t}\n\t\t}, \"Holding write lock\").start();\n\t\twhile (writeLock.tryLock()) {\n\t\t\twriteLock.unlock();\n\t\t}\n\t\tawaitState(waitOnMonitorThread, State.WAITING);\n\t\tawaitState(awaitCountDownLatchThread, State.WAITING);\n\t\tString threadDump;\n\t\tsynchronized (contendedMonitor) {\n\t\t\tcontendedMonitorThread.start();\n\t\t\tawaitState(contendedMonitorThread, State.BLOCKED);\n\t\t\tthreadDump = new ThreadDumpEndpoint().textThreadDump();\n\t\t}\n\t\tlatch.countDown();\n\t\tsynchronized (monitor) {\n\t\t\tmonitor.notifyAll();\n\t\t}\n\t\tassertThat(threadDump)\n\t\t\t.containsPattern(String.format(\"\\t- parking to wait for <[0-9a-z]+> \\\\(a %s\\\\$Sync\\\\)\",\n\t\t\t\t\tCountDownLatch.class.getName().replace(\".\", \"\\\\.\")))\n\t\t\t.contains(String.format(\"\\t- locked <%s> (a java.lang.Object)\", hexIdentityHashCode(contendedMonitor)))\n\t\t\t.contains(String.format(\"\\t- waiting to lock <%s> (a java.lang.Object) owned by \\\"%s\\\" t@%d\",\n\t\t\t\t\thexIdentityHashCode(contendedMonitor), Thread.currentThread().getName(),\n\t\t\t\t\tThread.currentThread().getId()))\n\t\t\t.satisfiesAnyOf(\n\t\t\t\t\t(dump) -> assertThat(dump).contains(\n\t\t\t\t\t\t\tString.format(\"\\t- waiting on <%s> (a java.lang.Object)\", hexIdentityHashCode(monitor))),\n\t\t\t\t\t(dump) -> assertThat(dump).contains(String\n\t\t\t\t\t\t.format(\"\\t- parking to wait for <%s> (a java.lang.Object)\", hexIdentityHashCode(monitor))))\n\t\t\t.containsPattern(\n\t\t\t\t\tString.format(\"Locked ownable synchronizers:%n\\t- Locked <[0-9a-z]+> \\\\(a %s\\\\$NonfairSync\\\\)\",\n\t\t\t\t\t\t\tReentrantReadWriteLock.class.getName().replace(\".\", \"\\\\.\")));\n\t}\n\n\tprivate String hexIdentityHashCode(Object object) {\n\t\treturn Integer.toHexString(System.identityHashCode(object));\n\t}\n\n\tprivate void awaitState(Thread thread, State state) throws InterruptedException {\n\t\twhile (thread.getState() != state) {\n\t\t\tThread.sleep(50);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.sbom.SbomEndpoint.SbomEndpointRuntimeHints;\nimport org.springframework.boot.actuate.sbom.SbomEndpoint.Sboms;\nimport org.springframework.boot.actuate.sbom.SbomProperties.Sbom;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SbomEndpoint}.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointTests {\n\n\tprivate SbomProperties properties;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new SbomProperties();\n\t}\n\n\t@Test\n\tvoid shouldListSboms() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\tthis.properties.getAdditional()\n\t\t\t.put(\"alpha\", sbom(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\"));\n\t\tthis.properties.getAdditional()\n\t\t\t.put(\"beta\", sbom(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\"));\n\t\tSboms sboms = createEndpoint().sboms();\n\t\tassertThat(sboms.ids()).containsExactly(\"alpha\", \"application\", \"beta\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfDuplicateSbomIdIsRegistered() {\n\t\t// This adds an SBOM with id 'application'\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\tthis.properties.getAdditional()\n\t\t\t.put(\"application\", sbom(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\"));\n\t\tassertThatIllegalStateException().isThrownBy(this::createEndpoint)\n\t\t\t.withMessage(\"Duplicate SBOM registration with id 'application'\");\n\t}\n\n\t@Test\n\tvoid shouldUseLocationFromProperties() throws IOException {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\tResource sbom = createEndpoint().sbom(\"application\");\n\t\tassertThat(sbom).isNotNull();\n\t\tString content = sbom.getContentAsString(StandardCharsets.UTF_8);\n\t\tassertThat(content).contains(\"\\\"bomFormat\\\" : \\\"CycloneDX\\\"\");\n\t}\n\n\t@Test\n\tvoid shouldFailIfNonExistingLocationIsGiven() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:does-not-exist.json\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> createEndpoint().sbom(\"application\"))\n\t\t\t.withMessageContaining(\"Resource 'classpath:does-not-exist.json' doesn't exist\");\n\t}\n\n\t@Test\n\tvoid shouldNotFailIfNonExistingOptionalLocationIsGiven() {\n\t\tthis.properties.getApplication().setLocation(\"optional:classpath:does-not-exist.json\");\n\t\tassertThat(createEndpoint().sbom(\"application\")).isNull();\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew SbomEndpointRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"META-INF/sbom/bom.json\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"META-INF/sbom/application.cdx.json\")).accepts(hints);\n\t}\n\n\tprivate Sbom sbom(String location) {\n\t\tSbom result = new Sbom();\n\t\tresult.setLocation(location);\n\t\treturn result;\n\t}\n\n\tprivate SbomEndpoint createEndpoint() {\n\t\treturn new SbomEndpoint(this.properties, new GenericApplicationContext());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/sbom/SbomEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.sbom;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport org.junit.jupiter.params.provider.EnumSource.Mode;\n\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.sbom.SbomEndpointWebExtension.SbomType;\nimport org.springframework.boot.actuate.sbom.SbomProperties.Sbom;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.MimeType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SbomEndpointWebExtension}.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointWebExtensionTests {\n\n\tprivate SbomProperties properties;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new SbomProperties();\n\t}\n\n\t@Test\n\tvoid shouldReturnHttpOk() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid shouldReturnNotFoundIfResourceDoesntExist() {\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getStatus()).isEqualTo(404);\n\t}\n\n\t@Test\n\tvoid shouldAutoDetectContentTypeForCycloneDx() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getContentType()).isEqualTo(MimeType.valueOf(\"application/vnd.cyclonedx+json\"));\n\t}\n\n\t@Test\n\tvoid shouldAutoDetectContentTypeForSpdx() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/spdx.json\");\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getContentType()).isEqualTo(MimeType.valueOf(\"application/spdx+json\"));\n\t}\n\n\t@Test\n\tvoid shouldAutoDetectContentTypeForSyft() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/syft.json\");\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getContentType()).isEqualTo(MimeType.valueOf(\"application/vnd.syft+json\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"git.properties\", content = \"git.commit.id.abbrev=e02a4f3\")\n\tvoid shouldSupportUnknownFiles() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:git.properties\");\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getContentType()).isNull();\n\t}\n\n\t@Test\n\tvoid shouldUseContentTypeIfSet() {\n\t\tthis.properties.getApplication().setLocation(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\");\n\t\tthis.properties.getApplication().setMediaType(MimeType.valueOf(\"text/plain\"));\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"application\");\n\t\tassertThat(response.getContentType()).isEqualTo(MimeType.valueOf(\"text/plain\"));\n\t}\n\n\t@Test\n\tvoid shouldUseContentTypeForAdditionalSbomsIfSet() {\n\t\tthis.properties.getAdditional()\n\t\t\t.put(\"alpha\", sbom(\"classpath:org/springframework/boot/actuate/sbom/cyclonedx.json\",\n\t\t\t\t\tMediaType.valueOf(\"text/plain\")));\n\t\tWebEndpointResponse<Resource> response = createWebExtension().sbom(\"alpha\");\n\t\tassertThat(response.getContentType()).isEqualTo(MimeType.valueOf(\"text/plain\"));\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(names = \"UNKNOWN\", mode = Mode.EXCLUDE)\n\tvoid shouldAutodetectFormats(SbomType type) throws IOException {\n\t\tString content = getSbomContent(type);\n\t\tassertThat(type.matches(content)).isTrue();\n\t\tArrays.stream(SbomType.values())\n\t\t\t.filter((candidate) -> candidate != type)\n\t\t\t.forEach((notType) -> assertThat(notType.matches(content)).isFalse());\n\t}\n\n\tprivate String getSbomContent(SbomType type) throws IOException {\n\t\treturn switch (type) {\n\t\t\tcase CYCLONE_DX -> readResource(\"cyclonedx.json\");\n\t\t\tcase SPDX -> readResource(\"spdx.json\");\n\t\t\tcase SYFT -> readResource(\"syft.json\");\n\t\t\tcase UNKNOWN -> throw new IllegalArgumentException(\"UNKNOWN is not supported\");\n\t\t};\n\t}\n\n\tprivate String readResource(String resource) throws IOException {\n\t\ttry (InputStream stream = getClass().getResourceAsStream(resource)) {\n\t\t\tassertThat(stream).as(\"Resource '%s'\", resource).isNotNull();\n\t\t\treturn new String(stream.readAllBytes(), StandardCharsets.UTF_8);\n\t\t}\n\t}\n\n\tprivate Sbom sbom(String location, MimeType mediaType) {\n\t\tSbom sbom = new Sbom();\n\t\tsbom.setLocation(location);\n\t\tsbom.setMediaType(mediaType);\n\t\treturn sbom;\n\t}\n\n\tprivate SbomEndpointWebExtension createWebExtension() {\n\t\tSbomEndpoint endpoint = new SbomEndpoint(this.properties, new GenericApplicationContext());\n\t\treturn new SbomEndpointWebExtension(endpoint, this.properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.scheduling;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Collection;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.CronTaskDescriptor;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.CustomTriggerTaskDescriptor;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.FixedDelayTaskDescriptor;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.FixedRateTaskDescriptor;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.LastExecution;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.NextExecution;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksDescriptor;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.ScheduledTasksEndpointRuntimeHints;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint.TaskDescriptor;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.Trigger;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.scheduling.annotation.SchedulingConfigurer;\nimport org.springframework.scheduling.config.ScheduledTaskHolder;\nimport org.springframework.scheduling.config.ScheduledTaskRegistrar;\nimport org.springframework.scheduling.config.TaskExecutionOutcome.Status;\nimport org.springframework.scheduling.support.CronTrigger;\nimport org.springframework.scheduling.support.PeriodicTrigger;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ScheduledTasksEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Brian Clozel\n */\nclass ScheduledTasksEndpointTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(BaseConfiguration.class);\n\n\t@Test\n\tvoid cronScheduledMethodIsReported() {\n\t\trun(CronScheduledMethod.class, (tasks) -> {\n\t\t\tassertThat(tasks.getFixedDelay()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getCron()).hasSize(1);\n\t\t\tCronTaskDescriptor description = (CronTaskDescriptor) tasks.getCron().get(0);\n\t\t\tassertThat(description.getExpression()).isEqualTo(\"0 0 0/3 1/1 * ?\");\n\t\t\tassertThat(description.getRunnable().getTarget()).isEqualTo(CronScheduledMethod.class.getName() + \".cron\");\n\t\t\tNextExecution nextExecution = description.getNextExecution();\n\t\t\tassertThat(nextExecution).isNotNull();\n\t\t\tassertThat(nextExecution.getTime()).isInTheFuture();\n\t\t\tassertThat(description.getLastExecution()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid cronTriggerIsReported() {\n\t\trun(CronTriggerTask.class, (tasks) -> {\n\t\t\tassertThat(tasks.getFixedRate()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getCron()).hasSize(1);\n\t\t\tCronTaskDescriptor description = (CronTaskDescriptor) tasks.getCron().get(0);\n\t\t\tassertThat(description.getExpression()).isEqualTo(\"0 0 0/6 1/1 * ?\");\n\t\t\tassertThat(description.getRunnable().getTarget()).contains(CronTriggerRunnable.class.getName());\n\t\t\tassertThat(description.getLastExecution()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid fixedDelayScheduledMethodIsReported() {\n\t\trun(FixedDelayScheduledMethod.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).hasSize(1);\n\t\t\tFixedDelayTaskDescriptor description = (FixedDelayTaskDescriptor) tasks.getFixedDelay().get(0);\n\t\t\tassertThat(description.getInitialDelay()).isEqualTo(2000);\n\t\t\tassertThat(description.getInterval()).isEqualTo(1000);\n\t\t\tassertThat(description.getRunnable().getTarget())\n\t\t\t\t.isEqualTo(FixedDelayScheduledMethod.class.getName() + \".fixedDelay\");\n\t\t\tassertThat(description.getLastExecution()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid fixedDelayTriggerIsReported() {\n\t\trun(FixedDelayTriggerTask.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).hasSize(1);\n\t\t\tFixedDelayTaskDescriptor description = (FixedDelayTaskDescriptor) tasks.getFixedDelay().get(0);\n\t\t\tassertThat(description.getInitialDelay()).isEqualTo(2000);\n\t\t\tassertThat(description.getInterval()).isEqualTo(1000);\n\t\t\tassertThat(description.getRunnable().getTarget()).contains(FixedDelayTriggerRunnable.class.getName());\n\t\t\tassertThat(description.getLastExecution()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid noInitialDelayFixedDelayTriggerIsReported() {\n\t\trun(NoInitialDelayFixedDelayTriggerTask.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).hasSize(1);\n\t\t\tFixedDelayTaskDescriptor description = (FixedDelayTaskDescriptor) tasks.getFixedDelay().get(0);\n\t\t\tassertThat(description.getInitialDelay()).isEqualTo(0);\n\t\t\tassertThat(description.getInterval()).isEqualTo(1000);\n\t\t\tassertThat(description.getRunnable().getTarget()).contains(FixedDelayTriggerRunnable.class.getName());\n\t\t\tassertThatTaskMayHaveBeenExecuted(description);\n\t\t});\n\t}\n\n\t@Test\n\tvoid fixedRateScheduledMethodIsReported() {\n\t\trun(FixedRateScheduledMethod.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).hasSize(1);\n\t\t\tFixedRateTaskDescriptor description = (FixedRateTaskDescriptor) tasks.getFixedRate().get(0);\n\t\t\tassertThat(description.getInitialDelay()).isEqualTo(4000);\n\t\t\tassertThat(description.getInterval()).isEqualTo(3000);\n\t\t\tassertThat(description.getRunnable().getTarget())\n\t\t\t\t.isEqualTo(FixedRateScheduledMethod.class.getName() + \".fixedRate\");\n\t\t\tassertThat(description.getLastExecution()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid fixedRateTriggerIsReported() {\n\t\trun(FixedRateTriggerTask.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).hasSize(1);\n\t\t\tFixedRateTaskDescriptor description = (FixedRateTaskDescriptor) tasks.getFixedRate().get(0);\n\t\t\tassertThat(description.getInitialDelay()).isEqualTo(3000);\n\t\t\tassertThat(description.getInterval()).isEqualTo(2000);\n\t\t\tassertThat(description.getRunnable().getTarget()).contains(FixedRateTriggerRunnable.class.getName());\n\t\t\tassertThat(description.getLastExecution()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid noInitialDelayFixedRateTriggerIsReported() {\n\t\trun(NoInitialDelayFixedRateTriggerTask.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).hasSize(1);\n\t\t\tFixedRateTaskDescriptor description = (FixedRateTaskDescriptor) tasks.getFixedRate().get(0);\n\t\t\tassertThat(description.getInitialDelay()).isEqualTo(0);\n\t\t\tassertThat(description.getInterval()).isEqualTo(2000);\n\t\t\tassertThat(description.getRunnable().getTarget()).contains(FixedRateTriggerRunnable.class.getName());\n\t\t\tassertThatTaskMayHaveBeenExecuted(description);\n\t\t});\n\t}\n\n\t@Test\n\tvoid taskWithCustomTriggerIsReported() {\n\t\trun(CustomTriggerTask.class, (tasks) -> {\n\t\t\tassertThat(tasks.getCron()).isEmpty();\n\t\t\tassertThat(tasks.getFixedDelay()).isEmpty();\n\t\t\tassertThat(tasks.getFixedRate()).isEmpty();\n\t\t\tassertThat(tasks.getCustom()).hasSize(1);\n\t\t\tCustomTriggerTaskDescriptor description = (CustomTriggerTaskDescriptor) tasks.getCustom().get(0);\n\t\t\tassertThat(description.getRunnable().getTarget()).contains(CustomTriggerRunnable.class.getName());\n\t\t\tassertThat(description.getTrigger()).isEqualTo(CustomTriggerTask.trigger.toString());\n\t\t\tassertThatTaskMayHaveBeenExecuted(description);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ScheduledTasksEndpointRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tSet<Class<?>> bindingTypes = Set.of(FixedRateTaskDescriptor.class, FixedDelayTaskDescriptor.class,\n\t\t\t\tCronTaskDescriptor.class, CustomTriggerTaskDescriptor.class);\n\t\tfor (Class<?> bindingType : bindingTypes) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(bindingType)\n\t\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t\t}\n\t}\n\n\tprivate void assertThatTaskMayHaveBeenExecuted(TaskDescriptor descriptor) {\n\t\tLastExecution lastExecution = descriptor.getLastExecution();\n\t\tif (lastExecution != null) {\n\t\t\tif (lastExecution.getStatus() == Status.SUCCESS) {\n\t\t\t\tassertThat(lastExecution.getTime()).isInThePast();\n\t\t\t\tassertThat(lastExecution.getException()).isNull();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void run(Class<?> configuration, Consumer<ScheduledTasksDescriptor> consumer) {\n\t\tthis.contextRunner.withUserConfiguration(configuration)\n\t\t\t.run((context) -> consumer.accept(context.getBean(ScheduledTasksEndpoint.class).scheduledTasks()));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableScheduling\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tScheduledTasksEndpoint endpoint(Collection<ScheduledTaskHolder> scheduledTaskHolders) {\n\t\t\treturn new ScheduledTasksEndpoint(scheduledTaskHolders);\n\t\t}\n\n\t}\n\n\tstatic class FixedDelayScheduledMethod {\n\n\t\t@Scheduled(fixedDelay = 1000, initialDelay = 2000)\n\t\tvoid fixedDelay() {\n\n\t\t}\n\n\t}\n\n\tstatic class FixedRateScheduledMethod {\n\n\t\t@Scheduled(fixedRate = 3000, initialDelay = 4000)\n\t\tvoid fixedRate() {\n\n\t\t}\n\n\t}\n\n\tstatic class CronScheduledMethod {\n\n\t\t@Scheduled(cron = \"0 0 0/3 1/1 * ?\")\n\t\tvoid cron() {\n\n\t\t}\n\n\t}\n\n\tstatic class FixedDelayTriggerTask implements SchedulingConfigurer {\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\tPeriodicTrigger trigger = new PeriodicTrigger(Duration.ofSeconds(1));\n\t\t\ttrigger.setInitialDelay(Duration.ofSeconds(2));\n\t\t\ttaskRegistrar.addTriggerTask(new FixedDelayTriggerRunnable(), trigger);\n\t\t}\n\n\t}\n\n\tstatic class NoInitialDelayFixedDelayTriggerTask implements SchedulingConfigurer {\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\tPeriodicTrigger trigger = new PeriodicTrigger(Duration.ofSeconds(1));\n\t\t\ttaskRegistrar.addTriggerTask(new FixedDelayTriggerRunnable(), trigger);\n\t\t}\n\n\t}\n\n\tstatic class FixedRateTriggerTask implements SchedulingConfigurer {\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\tPeriodicTrigger trigger = new PeriodicTrigger(Duration.ofSeconds(2));\n\t\t\ttrigger.setInitialDelay(Duration.ofSeconds(3));\n\t\t\ttrigger.setFixedRate(true);\n\t\t\ttaskRegistrar.addTriggerTask(new FixedRateTriggerRunnable(), trigger);\n\t\t}\n\n\t}\n\n\tstatic class NoInitialDelayFixedRateTriggerTask implements SchedulingConfigurer {\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\tPeriodicTrigger trigger = new PeriodicTrigger(Duration.ofSeconds(2));\n\t\t\ttrigger.setFixedRate(true);\n\t\t\ttaskRegistrar.addTriggerTask(new FixedRateTriggerRunnable(), trigger);\n\t\t}\n\n\t}\n\n\tstatic class CronTriggerTask implements SchedulingConfigurer {\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\ttaskRegistrar.addTriggerTask(new CronTriggerRunnable(), new CronTrigger(\"0 0 0/6 1/1 * ?\"));\n\t\t}\n\n\t}\n\n\tstatic class CustomTriggerTask implements SchedulingConfigurer {\n\n\t\tprivate static final Trigger trigger = (context) -> Instant.now();\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\ttaskRegistrar.addTriggerTask(new CustomTriggerRunnable(), trigger);\n\t\t}\n\n\t}\n\n\tstatic class CronTriggerRunnable implements Runnable {\n\n\t\t@Override\n\t\tpublic void run() {\n\n\t\t}\n\n\t}\n\n\tstatic class FixedDelayTriggerRunnable implements Runnable {\n\n\t\t@Override\n\t\tpublic void run() {\n\n\t\t}\n\n\t}\n\n\tstatic class FixedRateTriggerRunnable implements Runnable {\n\n\t\t@Override\n\t\tpublic void run() {\n\n\t\t}\n\n\t}\n\n\tstatic class CustomTriggerRunnable implements Runnable {\n\n\t\t@Override\n\t\tpublic void run() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthenticationAuditListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.security;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.authentication.event.AbstractAuthenticationEvent;\nimport org.springframework.security.authentication.event.AuthenticationFailureExpiredEvent;\nimport org.springframework.security.authentication.event.AuthenticationSuccessEvent;\nimport org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;\nimport org.springframework.security.authentication.event.LogoutSuccessEvent;\nimport org.springframework.security.core.authority.AuthorityUtils;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.web.authentication.switchuser.AuthenticationSwitchUserEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link AuthenticationAuditListener}.\n */\nclass AuthenticationAuditListenerTests {\n\n\tprivate final AuthenticationAuditListener listener = new AuthenticationAuditListener();\n\n\tprivate final ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class);\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.listener.setApplicationEventPublisher(this.publisher);\n\t}\n\n\t@Test\n\tvoid testAuthenticationSuccess() {\n\t\tAuditApplicationEvent event = handleAuthenticationEvent(\n\t\t\t\tnew AuthenticationSuccessEvent(new UsernamePasswordAuthenticationToken(\"user\", \"password\")));\n\t\tassertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SUCCESS);\n\t}\n\n\t@Test\n\tvoid testLogoutSuccess() {\n\t\tAuditApplicationEvent event = handleAuthenticationEvent(\n\t\t\t\tnew LogoutSuccessEvent(new UsernamePasswordAuthenticationToken(\"user\", \"password\")));\n\t\tassertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.LOGOUT_SUCCESS);\n\t}\n\n\t@Test\n\tvoid testOtherAuthenticationSuccess() {\n\t\tthis.listener.onApplicationEvent(new InteractiveAuthenticationSuccessEvent(\n\t\t\t\tnew UsernamePasswordAuthenticationToken(\"user\", \"password\"), getClass()));\n\t\t// No need to audit this one (it shadows a regular AuthenticationSuccessEvent)\n\t\tthen(this.publisher).should(never()).publishEvent(any(ApplicationEvent.class));\n\t}\n\n\t@Test\n\tvoid testAuthenticationFailed() {\n\t\tAuditApplicationEvent event = handleAuthenticationEvent(new AuthenticationFailureExpiredEvent(\n\t\t\t\tnew UsernamePasswordAuthenticationToken(\"user\", \"password\"), new BadCredentialsException(\"Bad user\")));\n\t\tassertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE);\n\t}\n\n\t@Test\n\tvoid testAuthenticationSwitch() {\n\t\tAuditApplicationEvent event = handleAuthenticationEvent(\n\t\t\t\tnew AuthenticationSwitchUserEvent(new UsernamePasswordAuthenticationToken(\"user\", \"password\"),\n\t\t\t\t\t\tnew User(\"user\", \"password\", AuthorityUtils.commaSeparatedStringToAuthorityList(\"USER\"))));\n\t\tassertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SWITCH);\n\t}\n\n\t@Test\n\tvoid testAuthenticationSwitchBackToAnonymous() {\n\t\tAuditApplicationEvent event = handleAuthenticationEvent(\n\t\t\t\tnew AuthenticationSwitchUserEvent(new UsernamePasswordAuthenticationToken(\"user\", \"password\"), null));\n\t\tassertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_SWITCH);\n\t}\n\n\t@Test\n\tvoid testDetailsAreIncludedInAuditEvent() {\n\t\tObject details = new Object();\n\t\tUsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(\"user\",\n\t\t\t\t\"password\");\n\t\tauthentication.setDetails(details);\n\t\tAuditApplicationEvent event = handleAuthenticationEvent(\n\t\t\t\tnew AuthenticationFailureExpiredEvent(authentication, new BadCredentialsException(\"Bad user\")));\n\t\tassertThat(event.getAuditEvent().getType()).isEqualTo(AuthenticationAuditListener.AUTHENTICATION_FAILURE);\n\t\tassertThat(event.getAuditEvent().getData()).containsEntry(\"details\", details);\n\t}\n\n\tprivate AuditApplicationEvent handleAuthenticationEvent(AbstractAuthenticationEvent event) {\n\t\tArgumentCaptor<AuditApplicationEvent> eventCaptor = ArgumentCaptor.forClass(AuditApplicationEvent.class);\n\t\tthis.listener.onApplicationEvent(event);\n\t\tthen(this.publisher).should().publishEvent(eventCaptor.capture());\n\t\treturn eventCaptor.getValue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/security/AuthorizationAuditListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.security;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.listener.AuditApplicationEvent;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.authorization.AuthorizationDecision;\nimport org.springframework.security.authorization.AuthorizationResult;\nimport org.springframework.security.authorization.event.AuthorizationDeniedEvent;\nimport org.springframework.security.authorization.event.AuthorizationEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AuthorizationAuditListener}.\n */\nclass AuthorizationAuditListenerTests {\n\n\tprivate final AuthorizationAuditListener listener = new AuthorizationAuditListener();\n\n\tprivate final ApplicationEventPublisher publisher = mock(ApplicationEventPublisher.class);\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.listener.setApplicationEventPublisher(this.publisher);\n\t}\n\n\t@Test\n\tvoid authorizationDeniedEvent() {\n\t\tAuthorizationResult decision = new AuthorizationDecision(false);\n\t\tUsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(\"spring\",\n\t\t\t\t\"password\");\n\t\tauthentication.setDetails(\"details\");\n\t\tAuthorizationDeniedEvent<?> authorizationEvent = new AuthorizationDeniedEvent<>(() -> authentication, \"\",\n\t\t\t\tdecision);\n\t\tAuditEvent auditEvent = handleAuthorizationEvent(authorizationEvent).getAuditEvent();\n\t\tassertThat(auditEvent.getPrincipal()).isEqualTo(\"spring\");\n\t\tassertThat(auditEvent.getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);\n\t\tassertThat(auditEvent.getData()).containsEntry(\"details\", \"details\");\n\t}\n\n\t@Test\n\tvoid authorizationDeniedEventWhenAuthenticationIsNotAvailable() {\n\t\tAuthorizationResult decision = new AuthorizationDecision(false);\n\t\tUsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(\"spring\",\n\t\t\t\t\"password\");\n\t\tauthentication.setDetails(\"details\");\n\t\tAuthorizationDeniedEvent<?> authorizationEvent = new AuthorizationDeniedEvent<>(() -> {\n\t\t\tthrow new RuntimeException(\"No authentication\");\n\t\t}, \"\", decision);\n\t\tAuditEvent auditEvent = handleAuthorizationEvent(authorizationEvent).getAuditEvent();\n\t\tassertThat(auditEvent.getPrincipal()).isEqualTo(\"<unknown>\");\n\t\tassertThat(auditEvent.getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);\n\t\tassertThat(auditEvent.getData()).doesNotContainKey(\"details\");\n\t}\n\n\t@Test\n\tvoid authorizationDeniedEventWhenAuthenticationDoesNotHaveDetails() {\n\t\tAuthorizationResult decision = new AuthorizationDecision(false);\n\t\tUsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(\"spring\",\n\t\t\t\t\"password\");\n\t\tAuthorizationDeniedEvent<?> authorizationEvent = new AuthorizationDeniedEvent<>(() -> authentication, \"\",\n\t\t\t\tdecision);\n\t\tAuditEvent auditEvent = handleAuthorizationEvent(authorizationEvent).getAuditEvent();\n\t\tassertThat(auditEvent.getPrincipal()).isEqualTo(\"spring\");\n\t\tassertThat(auditEvent.getType()).isEqualTo(AuthorizationAuditListener.AUTHORIZATION_FAILURE);\n\t\tassertThat(auditEvent.getData()).doesNotContainKey(\"details\");\n\t}\n\n\tprivate AuditApplicationEvent handleAuthorizationEvent(AuthorizationEvent event) {\n\t\tArgumentCaptor<AuditApplicationEvent> eventCaptor = ArgumentCaptor.forClass(AuditApplicationEvent.class);\n\t\tthis.listener.onApplicationEvent(event);\n\t\tthen(this.publisher).should().publishEvent(eventCaptor.capture());\n\t\treturn eventCaptor.getValue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/startup/StartupEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.startup;\n\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.SpringBootVersion;\nimport org.springframework.boot.actuate.startup.StartupEndpoint.StartupDescriptor;\nimport org.springframework.boot.actuate.startup.StartupEndpoint.StartupEndpointRuntimeHints;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.metrics.ApplicationStartup;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StartupEndpoint}.\n *\n * @author Brian Clozel\n * @author Chris Bono\n * @author Moritz Halbritter\n */\nclass StartupEndpointTests {\n\n\t@Test\n\tvoid startupEventsAreFound() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(256);\n\t\ttestStartupEndpoint(applicationStartup, (startupEndpoint) -> {\n\t\t\tStartupDescriptor startup = startupEndpoint.startup();\n\t\t\tassertThat(startup.getSpringBootVersion()).isEqualTo(SpringBootVersion.getVersion());\n\t\t\tassertThat(startup.getTimeline().getStartTime())\n\t\t\t\t.isEqualTo(applicationStartup.getBufferedTimeline().getStartTime());\n\t\t});\n\t}\n\n\t@Test\n\tvoid bufferWithGetIsNotDrained() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(256);\n\t\ttestStartupEndpoint(applicationStartup, (startupEndpoint) -> {\n\t\t\tStartupDescriptor startup = startupEndpoint.startupSnapshot();\n\t\t\tassertThat(startup.getTimeline().getEvents()).isNotEmpty();\n\t\t\tassertThat(applicationStartup.getBufferedTimeline().getEvents()).isNotEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid bufferWithPostIsDrained() {\n\t\tBufferingApplicationStartup applicationStartup = new BufferingApplicationStartup(256);\n\t\ttestStartupEndpoint(applicationStartup, (startupEndpoint) -> {\n\t\t\tStartupDescriptor startup = startupEndpoint.startup();\n\t\t\tassertThat(startup.getTimeline().getEvents()).isNotEmpty();\n\t\t\tassertThat(applicationStartup.getBufferedTimeline().getEvents()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew StartupEndpointRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tSet<TypeReference> bindingTypes = Set.of(\n\t\t\t\tTypeReference.of(\"org.springframework.boot.context.metrics.buffering.BufferedStartupStep$DefaultTag\"),\n\t\t\t\tTypeReference.of(\"org.springframework.core.metrics.jfr.FlightRecorderStartupStep$FlightRecorderTag\"));\n\t\tfor (TypeReference bindingType : bindingTypes) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(bindingType)\n\t\t\t\t.withMemberCategories(MemberCategory.INVOKE_PUBLIC_METHODS)).accepts(runtimeHints);\n\t\t}\n\t}\n\n\tprivate void testStartupEndpoint(ApplicationStartup applicationStartup, Consumer<StartupEndpoint> startupEndpoint) {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withInitializer((context) -> context.setApplicationStartup(applicationStartup))\n\t\t\t.withUserConfiguration(EndpointConfiguration.class);\n\t\tcontextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(StartupEndpoint.class);\n\t\t\tstartupEndpoint.accept(context.getBean(StartupEndpoint.class));\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointConfiguration {\n\n\t\t@Bean\n\t\tStartupEndpoint endpoint(BufferingApplicationStartup applicationStartup) {\n\t\t\treturn new StartupEndpoint(applicationStartup);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/exchanges/HttpExchangeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.net.URI;\nimport java.security.Principal;\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneId;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for {@link HttpExchange}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass HttpExchangeTests {\n\n\tprivate static final HttpHeaders AUTHORIZATION_HEADER = ofSingleHttpHeader(HttpHeaders.AUTHORIZATION, \"secret\");\n\n\tprivate static final HttpHeaders COOKIE_HEADER = ofSingleHttpHeader(HttpHeaders.COOKIE, \"test=test\");\n\n\tprivate static final HttpHeaders SET_COOKIE_HEADER = ofSingleHttpHeader(HttpHeaders.SET_COOKIE, \"test=test\");\n\n\tprivate static final Supplier<@Nullable Principal> NO_PRINCIPAL = () -> null;\n\n\tprivate static final Supplier<@Nullable String> NO_SESSION_ID = () -> null;\n\n\tprivate static final Supplier<@Nullable Principal> WITH_PRINCIPAL = () -> {\n\t\tPrincipal principal = mock(Principal.class);\n\t\tgiven(principal.getName()).willReturn(\"alice\");\n\t\treturn principal;\n\t};\n\n\tprivate static final Supplier<@Nullable String> WITH_SESSION_ID = () -> \"JSESSION_123\";\n\n\t@Test\n\tvoid getTimestampReturnsTimestamp() {\n\t\tInstant now = Instant.now();\n\t\tClock clock = Clock.fixed(now, ZoneId.systemDefault());\n\t\tHttpExchange exchange = HttpExchange.start(clock, createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getTimestamp()).isEqualTo(now);\n\t}\n\n\t@Test\n\tvoid getRequestUriReturnsUri() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getRequest().getUri()).isEqualTo(URI.create(\"https://api.example.com\"));\n\t}\n\n\t@Test\n\tvoid getRequestRemoteAddressWhenUsingDefaultIncludesReturnsNull() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getRequest().getRemoteAddress()).isNull();\n\t}\n\n\t@Test\n\tvoid getRequestRemoteAddressWhenIncludedReturnsRemoteAddress() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REMOTE_ADDRESS);\n\t\tassertThat(exchange.getRequest().getRemoteAddress()).isEqualTo(\"127.0.0.1\");\n\t}\n\n\t@Test\n\tvoid getRequestMethodReturnsHttpMethod() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getRequest().getMethod()).isEqualTo(\"GET\");\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenUsingDefaultIncludesReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(HttpHeaders.ACCEPT);\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenIncludedReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REQUEST_HEADERS);\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(HttpHeaders.ACCEPT);\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenNotIncludedReturnsEmptyHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID);\n\t\tassertThat(exchange.getRequest().getHeaders()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenUsingDefaultIncludesFiltersAuthorizeHeader() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(AUTHORIZATION_HEADER))\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getRequest().getHeaders()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenIncludesAuthorizationHeaderReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(AUTHORIZATION_HEADER))\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REQUEST_HEADERS,\n\t\t\t\t\tInclude.AUTHORIZATION_HEADER);\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(HttpHeaders.AUTHORIZATION);\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenIncludesAuthorizationHeaderAndInDifferentCaseReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(mixedCase(AUTHORIZATION_HEADER)))\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REQUEST_HEADERS,\n\t\t\t\t\tInclude.AUTHORIZATION_HEADER);\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(mixedCase(HttpHeaders.AUTHORIZATION));\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenUsingDefaultIncludesFiltersCookieHeader() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(COOKIE_HEADER))\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getRequest().getHeaders()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenIncludesCookieHeaderReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(COOKIE_HEADER))\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REQUEST_HEADERS, Include.COOKIE_HEADERS);\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(HttpHeaders.COOKIE);\n\t}\n\n\t@Test\n\tvoid getRequestHeadersWhenIncludesCookieHeaderAndInDifferentCaseReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(mixedCase(COOKIE_HEADER)))\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REQUEST_HEADERS, Include.COOKIE_HEADERS);\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(mixedCase(HttpHeaders.COOKIE));\n\t}\n\n\t@Test\n\tvoid getResponseStatusReturnsStatus() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.REMOTE_ADDRESS);\n\t\tassertThat(exchange.getResponse().getStatus()).isEqualTo(204);\n\t}\n\n\t@Test\n\tvoid getResponseHeadersWhenUsingDefaultIncludesReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getResponse().getHeaders()).containsOnlyKeys(HttpHeaders.CONTENT_TYPE);\n\t}\n\n\t@Test\n\tvoid getResponseHeadersWhenNotIncludedReturnsEmptyHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID);\n\t\tassertThat(exchange.getResponse().getHeaders()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getResponseHeadersIncludedReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.RESPONSE_HEADERS);\n\t\tassertThat(exchange.getResponse().getHeaders()).containsOnlyKeys(HttpHeaders.CONTENT_TYPE);\n\t}\n\n\t@Test\n\tvoid getResponseHeadersWhenUsingDefaultIncludesFiltersSetCookieHeader() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(SET_COOKIE_HEADER), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getResponse().getHeaders()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getResponseHeadersWhenIncludesCookieHeaderReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(SET_COOKIE_HEADER), NO_PRINCIPAL, NO_SESSION_ID, Include.RESPONSE_HEADERS,\n\t\t\t\t\tInclude.COOKIE_HEADERS);\n\t\tassertThat(exchange.getResponse().getHeaders()).containsKey(HttpHeaders.SET_COOKIE);\n\t}\n\n\t@Test\n\tvoid getResponseHeadersWhenIncludesCookieHeaderAndInDifferentCaseReturnsHeaders() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(mixedCase(SET_COOKIE_HEADER)), NO_PRINCIPAL, NO_SESSION_ID, Include.RESPONSE_HEADERS,\n\t\t\t\t\tInclude.COOKIE_HEADERS);\n\t\tassertThat(exchange.getResponse().getHeaders()).containsKey(mixedCase(HttpHeaders.SET_COOKIE));\n\t}\n\n\t@Test\n\tvoid getPrincipalWhenUsingDefaultIncludesReturnsNull() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), WITH_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getPrincipal()).isNull();\n\t}\n\n\t@Test\n\tvoid getPrincipalWhenIncludesPrincipalReturnsPrincipal() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), WITH_PRINCIPAL, NO_SESSION_ID, Include.PRINCIPAL);\n\t\tassertThat(exchange.getPrincipal()).isNotNull();\n\t\tassertThat(exchange.getPrincipal().getName()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid getSessionIdWhenUsingDefaultIncludesReturnsNull() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, WITH_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getSession()).isNull();\n\t}\n\n\t@Test\n\tvoid getSessionIdWhenIncludesSessionReturnsSessionId() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, WITH_SESSION_ID, Include.SESSION_ID);\n\t\tassertThat(exchange.getSession()).isNotNull();\n\t\tassertThat(exchange.getSession().getId()).isEqualTo(\"JSESSION_123\");\n\t}\n\n\t@Test\n\tvoid getTimeTakenWhenUsingDefaultIncludesReturnsTimeTaken() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getTimeTaken()).isNotNull();\n\t}\n\n\t@Test\n\tvoid getTimeTakenWhenNotIncludedReturnsNull() {\n\t\tHttpExchange exchange = HttpExchange.start(createRequest())\n\t\t\t.finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID);\n\t\tassertThat(exchange.getTimeTaken()).isNull();\n\t}\n\n\t@Test\n\tvoid getTimeTakenWhenIncludesTimeTakenReturnsTimeTaken() {\n\t\tDuration duration = Duration.ofSeconds(1);\n\t\tClock startClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());\n\t\tClock finishClock = Clock.offset(startClock, duration);\n\t\tHttpExchange exchange = HttpExchange.start(startClock, createRequest())\n\t\t\t.finish(finishClock, createResponse(), NO_PRINCIPAL, NO_SESSION_ID, Include.TIME_TAKEN);\n\t\tassertThat(exchange.getTimeTaken()).isEqualTo(duration);\n\t}\n\n\t@Test\n\tvoid defaultIncludes() {\n\t\tHttpHeaders requestHeaders = new HttpHeaders();\n\t\trequestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));\n\t\trequestHeaders.set(HttpHeaders.COOKIE, \"value\");\n\t\trequestHeaders.set(HttpHeaders.AUTHORIZATION, \"secret\");\n\t\tHttpHeaders responseHeaders = new HttpHeaders();\n\t\tresponseHeaders.set(HttpHeaders.SET_COOKIE, \"test=test\");\n\t\tresponseHeaders.setContentLength(0);\n\t\tHttpExchange exchange = HttpExchange.start(createRequest(requestHeaders))\n\t\t\t.finish(createResponse(responseHeaders), NO_PRINCIPAL, NO_SESSION_ID, Include.defaultIncludes());\n\t\tassertThat(exchange.getTimeTaken()).isNotNull();\n\t\tassertThat(exchange.getPrincipal()).isNull();\n\t\tassertThat(exchange.getSession()).isNull();\n\t\tassertThat(exchange.getTimestamp()).isNotNull();\n\t\tassertThat(exchange.getRequest().getMethod()).isEqualTo(\"GET\");\n\t\tassertThat(exchange.getRequest().getRemoteAddress()).isNull();\n\t\tassertThat(exchange.getResponse().getStatus()).isEqualTo(204);\n\t\tassertThat(exchange.getRequest().getHeaders()).containsOnlyKeys(HttpHeaders.ACCEPT);\n\t\tassertThat(exchange.getResponse().getHeaders()).containsOnlyKeys(HttpHeaders.CONTENT_LENGTH);\n\t}\n\n\tprivate RecordableHttpRequest createRequest() {\n\t\treturn createRequest(ofSingleHttpHeader(HttpHeaders.ACCEPT, \"application/json\"));\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate RecordableHttpRequest createRequest(HttpHeaders headers) {\n\t\tRecordableHttpRequest request = mock(RecordableHttpRequest.class);\n\t\tgiven(request.getMethod()).willReturn(\"GET\");\n\t\tgiven(request.getUri()).willReturn(URI.create(\"https://api.example.com\"));\n\t\tgiven(request.getHeaders()).willReturn(new HashMap<>(headers.asMultiValueMap()));\n\t\tgiven(request.getRemoteAddress()).willReturn(\"127.0.0.1\");\n\t\treturn request;\n\t}\n\n\tprivate RecordableHttpResponse createResponse() {\n\t\treturn createResponse(ofSingleHttpHeader(HttpHeaders.CONTENT_TYPE, \"application/json\"));\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate RecordableHttpResponse createResponse(HttpHeaders headers) {\n\t\tRecordableHttpResponse response = mock(RecordableHttpResponse.class);\n\t\tgiven(response.getStatus()).willReturn(204);\n\t\tgiven(response.getHeaders()).willReturn(new HashMap<>(headers.asMultiValueMap()));\n\t\treturn response;\n\t}\n\n\tprivate HttpHeaders mixedCase(HttpHeaders headers) {\n\t\tHttpHeaders result = new HttpHeaders();\n\t\theaders.forEach((key, value) -> result.put(mixedCase(key), value));\n\t\treturn result;\n\t}\n\n\tprivate String mixedCase(String input) {\n\t\tStringBuilder output = new StringBuilder();\n\t\tfor (int i = 0; i < input.length(); i++) {\n\t\t\tchar ch = input.charAt(i);\n\t\t\toutput.append((i % 2 != 0) ? Character.toUpperCase(ch) : Character.toLowerCase(ch));\n\t\t}\n\t\treturn output.toString();\n\t}\n\n\tprivate static HttpHeaders ofSingleHttpHeader(String header, String... values) {\n\t\tHttpHeaders httpHeaders = new HttpHeaders();\n\t\thttpHeaders.put(header, List.of(values));\n\t\treturn httpHeaders;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/exchanges/HttpExchangesEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.security.Principal;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpExchangesEndpoint}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass HttpExchangesEndpointTests {\n\n\tprivate static final Supplier<@Nullable Principal> NO_PRINCIPAL = () -> null;\n\n\tprivate static final Supplier<@Nullable String> NO_SESSION_ID = () -> null;\n\n\t@Test\n\tvoid httpExchanges() {\n\t\tHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();\n\t\trepository.add(HttpExchange.start(createRequest(\"GET\")).finish(createResponse(), NO_PRINCIPAL, NO_SESSION_ID));\n\t\tList<HttpExchange> httpExchanges = new HttpExchangesEndpoint(repository).httpExchanges().getExchanges();\n\t\tassertThat(httpExchanges).hasSize(1);\n\t\tHttpExchange exchange = httpExchanges.get(0);\n\t\tassertThat(exchange.getRequest().getMethod()).isEqualTo(\"GET\");\n\t}\n\n\tprivate RecordableHttpRequest createRequest(String method) {\n\t\tRecordableHttpRequest request = mock(RecordableHttpRequest.class);\n\t\tgiven(request.getMethod()).willReturn(method);\n\t\treturn request;\n\t}\n\n\tprivate RecordableHttpResponse createResponse() {\n\t\treturn mock(RecordableHttpResponse.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/web/exchanges/InMemoryHttpExchangeRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.web.exchanges;\n\nimport java.security.Principal;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link InMemoryHttpExchangeRepository}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass InMemoryHttpExchangeRepositoryTests {\n\n\tprivate static final Supplier<@Nullable Principal> NO_PRINCIPAL = () -> null;\n\n\tprivate static final Supplier<@Nullable String> NO_SESSION_ID = () -> null;\n\n\tprivate final InMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();\n\n\t@Test\n\tvoid adWhenHasLimitedCapacityRestrictsSize() {\n\t\tthis.repository.setCapacity(2);\n\t\tthis.repository.add(createHttpExchange(\"GET\"));\n\t\tthis.repository.add(createHttpExchange(\"POST\"));\n\t\tthis.repository.add(createHttpExchange(\"DELETE\"));\n\t\tList<HttpExchange> exchanges = this.repository.findAll();\n\t\tassertThat(exchanges).hasSize(2);\n\t\tassertThat(exchanges.get(0).getRequest().getMethod()).isEqualTo(\"DELETE\");\n\t\tassertThat(exchanges.get(1).getRequest().getMethod()).isEqualTo(\"POST\");\n\t}\n\n\t@Test\n\tvoid addWhenReverseFalseReturnsInCorrectOrder() {\n\t\tthis.repository.setReverse(false);\n\t\tthis.repository.setCapacity(2);\n\t\tthis.repository.add(createHttpExchange(\"GET\"));\n\t\tthis.repository.add(createHttpExchange(\"POST\"));\n\t\tthis.repository.add(createHttpExchange(\"DELETE\"));\n\t\tList<HttpExchange> exchanges = this.repository.findAll();\n\t\tassertThat(exchanges).hasSize(2);\n\t\tassertThat(exchanges.get(0).getRequest().getMethod()).isEqualTo(\"POST\");\n\t\tassertThat(exchanges.get(1).getRequest().getMethod()).isEqualTo(\"DELETE\");\n\t}\n\n\tprivate HttpExchange createHttpExchange(String method) {\n\t\tRecordableHttpRequest request = mock(RecordableHttpRequest.class);\n\t\tgiven(request.getMethod()).willReturn(method);\n\t\tRecordableHttpResponse response = mock(RecordableHttpResponse.class);\n\t\treturn HttpExchange.start(request).finish(response, NO_PRINCIPAL, NO_SESSION_ID);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/resources/org/springframework/boot/actuate/sbom/cyclonedx.json",
    "content": "{\n  \"bomFormat\" : \"CycloneDX\",\n  \"specVersion\" : \"1.5\",\n  \"serialNumber\" : \"urn:uuid:13862013-3360-43e5-8055-3645aa43c548\",\n  \"version\" : 1,\n  \"metadata\" : {\n    \"timestamp\" : \"2024-01-12T11:10:49Z\",\n    \"tools\" : [\n      {\n        \"vendor\" : \"CycloneDX\",\n        \"name\" : \"cyclonedx-gradle-plugin\",\n        \"version\" : \"1.8.1\"\n      }\n    ],\n    \"component\" : {\n      \"group\" : \"org.example\",\n      \"name\" : \"cyclonedx\",\n      \"version\" : \"0.0.1-SNAPSHOT\",\n      \"purl\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\"\n    }\n  },\n  \"components\" : [\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-aop\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring AOP\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c9b8757051ed6c1cc9fda0e379283348\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a247bd81df8fa9c6a002b95969692bfd146a70b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e47b66833ebec281374d55b4e36352b80fe3fa64c94252481a8a7e8d31d9d601\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1cb69feb2931bd4af48b2329614f8e2a0d1afe77267af5f5ea9717ab24c83fd524c8bc7aa8d357a6ccbc497535c4fd282ddfb6d78364a349895a14825af8b9c\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"09c3c2711a054993922d28b76357c376649a942bf0d7410915e540339c3fa42d5a498211b02e0b09493e68fac7a0d833\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b30a6ea50e454373bd74779d983fc941bb1775368ea67ff0464edbdf0dd3d1c137760bee64a620bd51daf5b65281f15e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"291404410acd2cfbcc804bd91a9777276f622fb3b82788298254c0bf1856b49f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8101ef2cc88af43b2bfc6126547de4e4a4cc29bf49bffd83aa9d299cab9e9cdb6a5246d46c00119dd88ca02dbf7959c3076dbd32d23e8e1366144ccbbda13316\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jdk8\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support JDK 8 data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3b6579ff944e128c4eccb34e76ff67e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"80158cb020c7bd4e4ba94d8d752a65729dc943b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"29995d3677f72dde74bf32bbf268b96beb952492b742d93f4c70af6c44b2156e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1b13d4f0a955af18a2c68ca45deca79c38d7f9f065d7053bddf2a3dc2fafe729b3355676f7442012451e363aa0da0cd8a0b7a44ded7057cf513df98a475cbbf6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a29961097a15d3aeabc1ab870699dce827511df9902fc66fe9f836d294c8cea68617498d52fe7dbe920bb5c745f2789\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"55570097f9979197eafda91156db909f25dd1b37387656893564060a673dcbc6d85c1f5dc6fd5c8b379b48a4974e6757\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"362c3a494e16016f7adc3f512ebe8c8f8da4dbdfc1ca285d05ac085a9198258f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1aebbe19a11236b7dbf85fd4c457e1a9b5a60fad9c818cc9fd462d7eb489dd5d3a378b4c7c42c6e3777e0b70263968c964cf1aaf8247fc97ec445481af2418a8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apiguardian\",\n      \"name\" : \"apiguardian-api\",\n      \"version\" : \"1.1.2\",\n      \"description\" : \"@API Guardian\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8c7de3f82037fa4a2e8be2a2f13092af\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a231e0d844d2721b0fa1b238006d15c6ded6842a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d7ccd0e7019f1a997de39d66dc0ad4efe150428fdd7f4c743c93884f1602a3e90135ad34baea96d5b6d925ad6c0c8487c8e78304f0a089a12383d4a62e2c9a61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ae11cfedcee7da43a506a67946ddc8a7a2622284a924ba78f74541e9a22db6868a15f5d84edb91a541e38afded734ea\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c146116b3dfd969200b2ce52d96b92dd02d6f5a45a86e7e85edf35600ddbc2f3c6e8a1ad7e2db4dcd2c398c09fad0927\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b4b436d7f615fc0b820204e69f83c517d1c1ccc5f6b99e459209ede4482268de\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7b95b7ac68a6891b8901b5507acd2c24a0c1e20effa63cd513764f513eab4eb55f8de5178edbe0a400c11f3a18d3f56243569d6d663100f06dd98288504c09c5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/apiguardian-team/apiguardian\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.annotation\",\n      \"name\" : \"jakarta.annotation-api\",\n      \"version\" : \"2.1.1\",\n      \"description\" : \"Jakarta Annotations API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5dac2f68e8288d0add4dc92cb161711d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5f65fdaf424eee2b55e1d882ba9bb376be93fb09b37b808be6e22e8851c909fe\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eabe8b855b735663684052ec4cc357cc737936fa57cebf144eb09f70b3b6c600db7fa6f1c93a4f36c5994b1b37dad2dfcec87a41448872e69552accfd7f52af6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"798597a6b80b423844d70609c54b00d725a357031888da7e5c3efd3914d1770be69aa7135de13ddb89a4420a5550e35b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9629b8ca82f61674f5573723bbb3c137060e1442062eb52fa9c90fc8f57ea7d836eb2fb765d160ec8bf300bcb6b820be\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f71ffc2a2c2bd1a00dfc00c4be67dbe5f374078bd50d5b24c0b29fbcc6634ecb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa4e29025a55878db6edb0d984bd3a0633f3af03fa69e1d26c97c87c6d29339714003c96e29ff0a977132ce9c2729d0e27e36e9e245a7488266138239bdba15e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"GPL-2.0-with-classpath-exception\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://dev.eclipse.org/mhonarc/lists/ca-dev\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-annotations\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core annotations used for value types, used by Jackson data binding package.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f478f693731e4a2f0f0d3c7bba119b32\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"79baf4e605eb3bbb60b1c475d44a7aecceea1d60\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"aae865c3d88256d61b11523cb1e88bd48d5b9ad5855fa1fc859504fd2204708a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c496afd736fa8acbf8126887e2ff375f162212f451326451fbb4b9194231d814e25bccacbaead9db98beec454f6b8d9ed706c5c88e2145bf7e1a37e13fd81af0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"13b4d153cc113a69008147974d8887f868f2f3f0a551ef0bacaccf0add17a3168465a94a471e075913f9c6649980a3cb\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"dcf8ed73f748eb32e1ab25eba3c294344cc0ddb2cc7bb4376814f1866df42c3093f1336291ce9ed9e1c8730663e0017c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"59f42bc85ee3a8a5b422085b0462aed2a770cf52d7a3660f2cd6dd257ec6e694\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1d1a6fd0e6851d419e79f82170f4060981c233ec8dc61656b84ce7988e9b71bbeecd7364cdadac066ddaf0b3de4dc8aa5acc411ebd1641f549a3af5ba214667b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-annotations\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-jcl\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Commons Logging Bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1638acc7030a001c37f803185dbd6eaf\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"285eb725861c9eacf2a3e4965d4e897932e335ea\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"eb9ebadb1581f0fe598216f7cf032a3b44a84c96de06ffa8d6f41bcc47305134\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2e80d7485b7ad4de6cc372d86ed73db9808be6a5a33e3c9fabccc7915fe57b73011bed75b4567c44456fedad5ae2186658a7f5cc331b4aad64e2a7cc78acdcfa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a6a6422a6c2654eff951af0d6dfb6e93501bdcb4e38ec353d515ca8de919a34b9e1fe37c562106f3f33f844cf071e010\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71098eb263af3ab42d93b8e7a96ceb90fb2069f2ecca85754e702b82f9876255abf5e3f9b48beb4a200f2d9e13599794\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"7f49ddd5db9841bb2d7ca8cb5ce52fa1e8982c7c37bc0c6e987eca8f5fc70d38\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4a417d058ecd3619a9716c5d47ecc506f4cb9c3684ee589c443c7b7996b630949932295186135cb3ce5fb0154c29436de4b6c1dbf7f135563449050973510200\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-webmvc\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web MVC\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0fcf00ac160e0d42ad9cd242c796e47a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"906ee995372076e22ef9666d8628845c75bf5c42\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de42748c3c94c06131c3fe97d81f5c685e4492b9e986baa88af768bb12ea7738\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8e7ad7afa2a605d8dbb6cb36c11caf0e626a5ca5849c06f0b35524e5ad6a13eec1ddff8625e1cc278b3082555a940ec3865657828458ab8d60d1c99d513aba0f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ec328ff12f857baf85ce6f44c849f8818658aaabb4e4d0940ea6b5ad2b009ce3c7717b6b02843f641f8125d0cec4291\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"75605b286d839df688bbfb9594dbb83d1eb22f2cae52a6f4b35d485e91ab94a55e94158086684ef3b059f1346af6dc85\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2e67bcc31eede462f5105a09dbf5b40a3e0ccc52d637c6e2720b43412da01525\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d7c5330069c3c0f5eda1417a52384a4b5adc4451c405315a992ed147f26466a19487ffc5e39b90a1ec4cb0df3f804a4d26203f9aaf4e74cf906d1e811abfbf3b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-websocket\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cfc1778713fba9b5bc33d3db64071dff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ee2f34b51144b75878c9b42768e17de8fbdc74b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"00b16e507bea58c6e8a7cb64f129cd2ffd62da092a67a693a8a6af1efdc7dd6d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"72da073d4ec4f7473c9a91b4d11607d02a3d18ca8af10348f9130a280f898814625a5865cb44244e6be6d6ab915099805bf06a60f80fd9b8ff2c47840d5266e9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f4c1d108ca60a7a658839b8ac45eba94354ad20e641d36d2ecf777bac252d371df1e8806a5460ccaf9da222f72a4a9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2d0703de58338d38fbae7f4a38390a766d66e3875e3a6a7f2620ae478c838c8f306a39cdac8652890e1116a3859e56e1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e594abbc4cb6dc0896c08a89cb3fa376980587d5995bace2b3c0798d99c1e454\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3a35964398627fc8bcd323dd9fb6d4e51ea183b704074320822906c074aeb50a0f8732e42b98bdad9c5f0aa4eb421da96dde7e97f094ccdbcb70f668c6d4ff6e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"Byte Buddy is a Java library for creating Java classes at run time. This artifact is a build of Byte Buddy with all ASM dependencies repackaged into its own name space.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4e5bd83559bf8533b51f92dcd911d16c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8117daf4a612122eb4f517f66adff778cb8b4737\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"30e6e0446437a67db37e2b7f7d33f50787ddfd970359319dfd05469daa2dcbce\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"583512f3c47513cf17735aad4e600be44c97e9978c9f6a45227de8a160a879960b1fe01672751e7583176935e0db5477aba581bf68ef5c94f52436a0683a306e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"efcce5a139f498de410e182a52e5b2465823a2ebf845001c9a733d87418118342c3854d00a0fae7945ae8dcb1916ba90\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cace3217b1c2c77a4bc194ecc602a28886d9e448efa26b1985e9fd09d90c92bc2e1b50ed70475106ddf266f8c2d14160\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"71647273afb1561b70d2cfa519f707a98711f9ae5b891249ae5803c00c25a788\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4aba6f5dcac177c8f8aed902307c62916c32be61841adcf12b9c9885de2de9795a965c0b939729ed67ee7d49b0fbfaf0dfd922be1bf1cdbfbe7b1f09e083831b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d6f93aa42df4cb27a58835750597d835\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bfc34c523b3ab295fb01f46373e903f9729cdd43\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"86c51c743babfc591be09af7fedcd778410706e567e9ed27218448ccd2297ef4\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"701b6ee27c87081e4a65ba76fe721f74e917a655575b19b9205b314f4a561889564e09ceadaa880aaf30f70cd8b48dc70fc5e32f511204b1ea031a12349fd9be\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"74d4cf202399e946789a5572007aa4fbf1daf26cfac27f83a3d8550711f99700083029b1f900037b8f263543ac9824a1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ac0b64ec94b558b4f806c09f68247eff80bcc8e33b97f5d09f5517a2339187e4b11c8e2287400a173cb128e3fdb4ab06\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5ca85cd0c052076d625c262cf445e4e8fb255b13323ba4ab08cbfcf32ec236b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"04ce88c724852938057c723a7ec637af2f8e601879a592a6fe135eaa26940f8fd9d9ac8f6917e761cb0ff31547bb849ff88a66e1f6e93c1032a4009fe1fdef1d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-json\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for reading and writing json\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"bea54cf408b022894c0b1b013c58c0a9\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ecda50de20ab6d3c49ea30df4c1982048f5d31ac\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"572f1a4171dff33b5a9260bbd704473442adf24f890386abe33ecc18c047836a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c611e0d07093d99dbcded7a00e7c00355a7c13c24a69d33105ca88ec63cc68ba76339b5a96b84f2b666bb883849980776e1e24ee2df9c7dd07b2dde0992289b5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed40ffb527cf8442dbe3eb7b542970317e4827ed00196387d78f123490a77b08b3bc2fd5f53b83f6bee1d4eed29215bf\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"26d5852f479f1c72f501569a8ea0c0e4c93f9049676921dca94b467e68f221214e4485c41647e6a92005e5090a6a7c80\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"dc69eefb2f1441bbec58c219ccedd895b863b1e1d25cc3805936f0c9b072f2e6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bf6fce60937e78550fb3d411c19aad2200d8129138fade809e9d0abc307c7f06b54732f1e94fa86ebb82d4da0293f7bce43345416b3fdae1b3c2edbac6706310\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jsr310\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module to support JSR-310 (Java 8 Date & Time API) data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"acd8ae6da000eb831a69b4acdc182b7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4a20a0e104931bfa72f24ef358c2eb63f1ef2aaf\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bea1d78009ebc4e5d54918a3f7aec5da9fbd09f662c191a217ffcf37e8527c5e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1c5bde6c91a2a89f3c1f231f4e17c435063d9012babbfcba509a3b25363b1fd99f0dcd4234f1e00559e43d3dc8e6c71834282c72f2ebf15484ae900754c5d757\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cc72f54d89bc0f7ffae9af36dfba38e5a61ac83db2f0d8de3c74e405a0bfd77b6d463217ece19c64eeb16291d80a69f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"096944bac7583e5c97e8afcfbc928ca4a87a7d3e5eb74cc77394a19ca8bc6f26185da7fdf5d6bd2179582bf51940edc5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"0301cf719fd327643b3228b91c36688aaea3fccf3487c3e09bae3de636340dc7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b9a4a8c9785e8ec2786690bfede18c76e08d81fc9c77bb2dad88e1a034f97f7d20020531ac1cb9b0b6e61645b08ea441aba35fc0732edc2fc1dc4b36d6f1695c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.hdrhistogram\",\n      \"name\" : \"HdrHistogram\",\n      \"version\" : \"2.1.12\",\n      \"description\" : \"HdrHistogram supports the recording and analyzing sampled data value counts across a configurable integer value range with configurable value precision within the range. Value precision is expressed as the number of significant digits in the value recording, and provides control over value quantization behavior across the value range and the subsequent value resolution at any given level.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4b1acf3448b750cb485da7e37384fcd8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9b47fbae444feaac4b7e04f0ea294569e4bc282bc69d8c2ce2ac3f23577281e2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b03b7270eb7962c88324858f94313adb3a53876f1e11568a78a5b7e00a9419e4d7ab8774747427bff6974b971b6dfc47a127fca11cb30eaf7d83b716e09b1a0d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"06977d680dafd803d32441994474e598384a584411a67c95ab4a64698c9e4cbd613e0119b54685cea275b507a0a6f362\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b5ccb4d39bf7cc8ccc33f0f8fcbab0a63c99a94feda840b5d80fc3ae061127f1475cfb869b060933783a1f2eafb103a1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ef2113f27862af1d24d90c2028fc566902720248468d3c0f2f1807cc86918882\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4fca2f75bdfd3f2ac40dc227ae2ef0272142802b1546d4f5edf9155eaeed84eff07b0c3a978291a1df096ec94724b0defb045365e6a51acfdd5da68d72c5a8eb\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"BSD-2-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-2-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/HdrHistogram/HdrHistogram/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/HdrHistogram/HdrHistogram.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-commons\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing common code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2518ae277e56aea5e37e3fc2f578dfa4\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abcc6b294e60582afdfae6c559c94ad1d412ce2d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"295785b04cd4de7711bb16730da5e9829bac55a8879d52120625dac6c89904ed\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"25d65699a25fe3b90de17a0539233fdad37df864f6d493475976e9a513bd7767520a882cbf6bbd98714a1fe94acdb77a160cd68f549475d2b93624ffe8672a00\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8523ae45ce6dd4a068cce108cd31da24629839d3d293fca92353cf45db9eae88107744c9e66b82ed14abb96782c562da\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9af1fc3aad2d0131c337b843c38b05510d31e7931a48841a4bdb618257f185286ed393f8a4418ae4c5f91da7f9c76cbf\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d5dbeadc5f629430202c81a6736dff2efbfbf3ea2c09844b1194f316772a93f7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c7b1dd1727000936bf51c02f9bf9b262a412e2b815531df4a9f7aad675ef0f728d4492327a404b37b1ef36d41a240b83dbfeea3367b3b4faa22cdc2decc5bac9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-core\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito mock objects library core API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4df8dd230071bc192161d0e54a76f6b5\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a1c258331ab91d66863c983aff7136357e9de056\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dbad5e746654910a11a59ecb4d01e38461f3e5d16161689dc2588d5554432521\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5a2f00df2b1b2dbca06686f88806b86990f1eea6f7c25281c0e7ec7cf7904a0a9227477279b11630d80f8e88d6b6e9dbdb40ad094a4077cc6a44cd2072d12662\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f2caa05fe4a5d5b385654ce60d0655724200fdd333652459b86848c3b895a9ad0b0daca8a014851d6b5c744cd0e9372\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"06ba4583220a4aaa47d79ccab11783d48900d8850a346e4a1efc61c057630fcf0bb9c95cec74833ab5e6ee08e55625ec\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f1f9899edf629fffaf8b4483ac04430945996393f4fdcedc38eba22a9a5c715d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d6f479d52534b382088012e3d1a83fa267dfb046322a72e84438d21973165617d1d710bb42f1cb2d2d3d7f891969320232031be33f4abb2ea1526217e16e8c63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3afea56b25f872cee2c929c761b0790d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0fe81034352a15731322fba326447ba70bfa3962\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3850d85c0f6074fe9286dece9b44f8bded5e194e9b816860735e0fc728173d65\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7197158ef14a580edc836ab7af10a9f5f567ba60e21267b624fc4143debd2638c7b8bd8e2e5973fdd5c5d512be73df96500fb0a4273f20a21b42161e9f7add75\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4a35eb1f124d8d7812d32f87b16a24dd56d4cb43278ce66f216f4a4af34db357e7481fc1b26de9bde7c2dd6847687721\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8369a8b49cae80b92abbfcc0218d55b9cecd86778735c66b9b0cc6fbc7251784725249392e716c314e3ec08c995557bb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ee742160e4951e1f6145d575f6c6ebb908a46f38a8b3b81b7d61aac7c111a87f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"dcb1b214577203c9b3e2e5dcb3aaef8e46aec5f75a40a606f42e230c6e1af39c37250d58de6bf694c5a62d70fb1a6dcba436d696f71d7aa1a52b9f4dea5aa9a9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-tomcat\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"db4df0f653e84bfd545894c4567b19ff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d8efc48034015522958cb3fea5831b4cbcd4fcfb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bf93da73a8fb4caf9fa68e4f3b97adcc9dbb8c79220a828b3d70ecf12d410117\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d2bce5bb0271525766283e17160513de530c20e0452cecc3c9d5be3890986cc071c1423a3c11c54a36d2f83bd3a238b0fcbcc6218976a5633f0753a313418f6f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1f9ae7504b1345595377a4d35163315824dcf25f29ac9d522385e6e1672b813719655989708eb03b419e808f1f102be9\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9d890c3314b5ec30f39de30bf70471aef5f19e64d6d2f60b6fe66b3c57978bbda0a981cf92e42f18f27b72ed2ddb3574\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"43d38219fbe556c2bac8670fa0aa4f89e2ac273fda77d8bceac8d9d34d7b27c2\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"6a4e9a2ff89293c60c8a05cb79a65695dbe9823978be93f1b309d702338f87f108aabeaeafe8ff0ebf08bcd5483efbbb4a85c566e1357acd1d2fab565c910a80\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-to-slf4j\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j binding between Log4j 2 API and SLF4J.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"00b957af4a40bea6a7bf61400b6ccf63\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d77b2ba81711ed596cd797cc2b5b5bd7409d841c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de143c565ba78b0f2c0be58f132c7aec75e6e1a10845ebda5a4f17c2a35d9990\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8a7a682dc5ae6a123c8de6002f1470ad2682795c65b47b06397d9ad9a31729e588c406013bfa989f9c2a51750c353cd7a147bc036f2d66b0f8f0b3f13798a637\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8f3e4f1eea069f47b2c6111f1233448ea9ccc723b7c8a8bd308b7317a6ec1f47008d2952c1cb274152a38d3e21da750b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"822f93c3bba450b89a7f64b4d81aab48a7f5c2f693b53a4dcc83eba3a8300ff90c9e7727223f3491c782c80bee9dc707\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1f3f3aace32b45e9a6271c7b4ac76ddf86eb4f32e28e147a3e054dc8c836def1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bb61c16d22aeed2d6b18972f68a6c4670fb8a07eeb79407748a7d499bc64e8ad8eb9774d372d9286227665686fe90878f2ef7e7f8595b74cd448d0f847aec02e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.xml.bind\",\n      \"name\" : \"jakarta.xml.bind-api\",\n      \"version\" : \"4.0.1\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e62084f1afb23eccde6645bf3a9eb06f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca2330866cbc624c7e5ce982e121db1125d23e15\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"287f3b6d0600082e0b60265d7de32be403ee7d7269369c9718d9424305b89d95\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dcc70e8301a7f274bbb6d6b3fe84ad8c9e5beda318699c05aeac0c42b9e1e210fc6953911be2cb1a2ef49ac5159c331608365b1b83a14a8e86f89f630830dd28\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ff377d0cfd7d8f23f45417e1e0df72de7f77780832ae78a1d2c51d77c4b2f8d270bd9ce4b73d07b70b060a9c39c56e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"773fd2d1e1a647bea7a5365490483fd56e7a49d9b731298d3202b4f93602c9a1a7add0eee868bc5a7ac961da7dda8c8e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"26214bba5cee45014859be8018dc631c14146e0a5959bb88e05d98472c88de8b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"32bdc043b7d616d73bbc26e0b36308126b15658cd032a354770760c5b5656429a4240dd3ddcea835556e813b6ae8618307ebeb96e2e46ba8ab16f6a485fa4d32\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.yaml\",\n      \"name\" : \"snakeyaml\",\n      \"version\" : \"2.2\",\n      \"description\" : \"YAML 1.1 parser and emitter for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d78aacf5f2de5b52f1a327470efd1ad7\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"11547e75cc80bee26f532e2598bc6e4ffa802941496dc0d8ce017f1b15e01ebbb80e91ed17d1047916e32bf2fc58da532bc71a1dfe93afccc277a296d86634ba\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"dae0cb1a7ab9ccc75413f46f18ae160e12e91dfef0c17a07ea547a365e9fb422c071aa01579f2a320f15ce6ee4c29038\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"654b418f330fa02f1111a20c27395ec5c7f463907ae44f60057c94da04f81e815cf1c3959f005026381ef79030049694\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2c4deb8d79876b80b210ef72dc5de2b19607e50fbe3abf09a4324576ca0881fc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0d9be5610b2bcb6bb7562ee8bcc0d68f81d3771958ce9299c5e57e8ec952c96906d711587b7f72936328c72fb41687b4f908c4de3070b78cc1f3e257cf4b715e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/src\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-commons\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-commons\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cd430f3f7345c0888f8408ce8795c751\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2bfcd4a4e38b10c671b6916d7e543c20afe25579\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7d9855ee3f3f71f015eb1479559bf923783243c24fbfbd8b29bed8e8099b5672\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4aa83350e7a6df21feb9ba8756bb4a68986f33f8c6e384720d1daa448444016c0def1781729788e3e884664abd6703b1e3c0ec6b79893a9d5645c3a4809c0ad2\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"d264f2c8ceaff384b0f22ee77890195ed3d918b01f338e35fc2ee12f82df15e59533918509f535883b4f4befed28595e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d1fa76d6b2567e831b37ff7843df6d7d65028d4e53c570c6f580cbbf13269d2aa2afedfedfe5a3f2cf92d7de6d3c89b2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"eef0f968f2d2fc31f8b4a4ed43bafeb46977de1ac3d59477ab6e2b014f97e070\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"93340cc2c378c830c755b25006bc4f73ec77ad10661f05625b23efa0854d456da8e62bdbe7e7edf3418dda864e6e0d7a6b9d34cea23d525b8991258f3d75fc9c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-web\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"a39761bc7a706c70f6ca3ab805a97b34\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0f26b98778376cc39afb04fbb6fdd7543bef89f2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3f2012a24c6213f155b6bc69aa3ecafe2a373c1e92a26dbecc62ff575c3a1fb3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"f07f054feaf53c2a97b82150882281035824cf0b815f317a22ba1954afa721bc5d57cb07faa19bad99fc235373b62edd7013f7ac2cd0a3d0db91faf49f216741\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"57418cf2a9b3256201c0874e7721966b09929030c64f5e5a85007bd645294dfbf1a14d4632a5aa5fcf70af5bf733d542\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"83daa608abc0124ec237f65231d5f1dd1a5d751e459d3ea255a3d12a56e92ac83037fb72c5793f497fbecb9e389eb299\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1a17acdfa8920b1849a16e4260bb4b960f60da07732148a5281cfcba21d1e4a8\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3e5e020cb1068250eb0e58e9bc0368c44db96d59022047ecffe286a51b0896e4320d9696f2f9136b4c0aed547d8dd1af1bbc2b4b053aa994246bb43bd7397f05\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.objenesis\",\n      \"name\" : \"objenesis\",\n      \"version\" : \"3.3\",\n      \"description\" : \"A library for instantiating Java objects\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab0e0b2ab81affdd7f38bcc60fd85571\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1049c09f1de4331e8193e579448d0916d75b7631\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fa990d15bd179f07ffbc460d580a6fd0562e45dee8bd4a9405917536b78f45c0d6f644b67f85d781c758aa56eff90aef23eedcc9bd7f5ff887a67b716083e61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"2f6878f91a12db32c244afcee619d57c3ad6ff0297f4e41c2247e737c1ccc5fcc1ce03256b479b0f9b87900410bc4502\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"a3dd9f6908fe732900d50eb209988183ffcf511afb4e401ef95b75c51777709d2d10e1dc9ee386b7357c5c2cbcf8c00e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"fd2b66d174ed68cbfcda41d5cbd29db766c5676866d6b2324b446a87afab3a9f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ef509e8bcea73bc282287205ffc7625508080be44c16948137274f189459624891dcf109118c9feff109e1aa99becf176f8db837ac4fd586201510c3ae2ea30a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\"\n    },\n    {\n      \"group\" : \"com.vaadin.external.google\",\n      \"name\" : \"android-json\",\n      \"version\" : \"0.0.20131108.vaadin1\",\n      \"description\" : \"  JSON (JavaScript Object Notation) is a lightweight data-interchange format. This is the org.json compatible Android implementation extracted from the Android SDK  \",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10612241a9cc269501a7a2b8a984b949\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fa26d351fe62a6a17f5cda1287c1c6110dec413f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c4a06a0a3ce7bdbee702c06944265c050a4c8d2fbd21c248936e2edfdab63acea30f2cf3568d3c21a559940d939985a8b10d30aff972a3e8cbeb392c0b02da3a\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"60d1044b5439cdf5eb621118cb0581365ab4f023a30998b238b87854236f03d8395d45b0262fb812335ff904cb77f25f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b80ebdbec2127279ca402ca52e50374d3ca773376258f6aa588b442822ee7362de8cca206db71b79862bde84018cf450\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6285b1ac8ec5fd339c7232affd9c08e6daf91dfa18ef8ae7855f52281d76627e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"de7ed83f73670213b4eeacfd7b3ceb7fec7d88ac877f41aeaacf43351d04b34572f2edc9a8f623af5b3fccab3dac2cc048f5c8803c1d4dcd1ff975cd6005124d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"http://oss.sonatype.org/content/repositories/vaadin-releases/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"http://developer.android.com/sdk/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-logging\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for logging using Logback. Default logging starter\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7ac01b9dee045285c365cf6a3d8d8451\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0df8ec78dc87885298998ca3c9bd603ee7bfe5b8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0b7e411cfc44a15fc63a36cd05a73b34c3558f1b06e4f297b1919361b8a351a7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"23baf0a59d56809db43101fbddb712b515012c64530362665cebe84c53bbd716218d3602024315f3250dea923138845c09d5c56dd9c7fb26a53d5e21a325e52e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f5ff55d346828eaec7b535bdd1d6096acc3819e81f6fa0a3d2396d523616e2e356d58115de8b8c49adf035216fa6ea83\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e5bd5c09d127a2984a55bbfc296cc515e399f35ee2ca949b10639c5ef583bee58dc9eeb60f6bec1f05904f8b91b4a26\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"99b21628e6efb820b4955e0e17bb54345a6974dc785b79abb7af8186a261159e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"91625907d0200fb80f025aa6ed098372955053bfb277db124d95ce2dd5049c20e9e7f2b97cffd6f247d9ae8da1bc26c004b688687056a87ccb3033d57a7c20f3\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d5ede97972b567fe75db1d2bbfc035d8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9089b9fff0c17eae54aabc466b78e010eac3a04f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b870c0a601dc0d6d98b33a6b59d41799285848de267f7cfb466a6f167f30c4d2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9577f4ba268b688ad100d4038f6dba97139a29b82127f6a581b948f0ee08fc8159f51fa5f7deb200e5a61559fd321559d2255af75c3e28cf293e815b8b1bb8ac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"96adde3cd5a4f729a6d382566800e62e89c93d1c3b9120ffefcd9a666d755fc5d6dc3dd12577f927bcaf03b7f1b0922b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c3f71bfae2d560ec46f76e833aee6964b5ad57639cb4ded937cd6d1e39b213a4c255d9b83ba59882d22dd31a4ef7b5f5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a251040e99b14a5d926f86bdcb1fcf505518d31cb421e6aaf32d59d8f7f2eb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3b642b5433989ba548cffebd7c155d5ada680b96996eac432895de56a27d7529c795d7263e8419854c9d118cddc0492d142d260a2e5434058134c9bc17ab8253\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-core\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-core module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7367629d307fa3d0b82d76b9d3f1d09a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f8c2f05f42530b1852739507c1792f0080167850ed8f396444c6913d6617a293\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d18159d4b378973e49182c4711b3d5b1f3600674ddd7bde26793247854bbd3a7233df7f74c356ecc86e4160ac6f866e0b32c109df6e1b428a10cddd4bc7f44e8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"afe21cf21e8804d069514a1f0d57c92b4caf56f8b010bd681d19fff67f237fcf0bbe1e1c9bfc4cedcfe602a3ea859b57\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"38cc28c8a578f4053412440d88b41938fa029a8ee3d350fe7474b34afa0f17889298d00f3c2cec4510d72d3342d29a77\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6c7d3be575969be97a49e90a97a8dc1bb25380b1b302073e00d2e21cb266e6a6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8e9ce45d599bffac71e35a0d59c4dcff067f628157a75e9e28c1930f31537fb1dd058ddd9906322c1154f29436252a36bc50595578bfee9bcad4a9705c85726a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5c793b3b61ba2637840a6c865aa2901e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"142fbe3cfe3370c57d0ed55cca0d8d96e1d6f26e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fb27aeb59ab757e60c48f9810d0ab54dc858a4c1cd9cc75b4ad07456c9c3e7c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"975428c3f753ec1375f9c0ca2c47756a22896cc510193b53f7a8501255634a2e0d2165e699055667f4127cbaa8e79c9c128aef6de0854fccd4e158dce4422939\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"c3abb4c4a9961cab0fde6119d5b86755ea0c43fdd266b51d369a8544818463ce1876df2b13b0a2478f36b1e5282a305d\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"641f9090f373f299d61bf54dd06e7ea15217c5b06424e970ddaed1f64e2a25aae74bdc10e04c9c4e934f2a3a5ab95c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"45d05dd704757c997b11f13961762e371309bec11292b32af3f244ca3b49642c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"53001dd1610347d6cf92f737067271fe3c638828a0b1e0b6aca62429e97a85018daf6ab3e10f065acd79ed7c93dc3a4c57f89eda3e2feb48ab548ca7e906b414\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-jakarta9\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module for Jakarta 9+ based instrumentations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0e247019d91d3c357b440436e1af2fba\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2dc7257970669fa45e342b0b36902d868af2dbed\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e8c66d7aee8fbc8a9d2e15c6c53df92bd7ecbf94f1ca8562d62d9a2693aa4633\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3a481de081b216d42bd9b741b3a830c93d917c5ae8a11f670785b53b55cff601e1cdfd037b12d8b95cd8557c4493d6e04e51980860e421f444f2b4a953070969\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cdbca1958c2502bcdad18446401f7f21ec2bc2c4055fd2fafa8fdad30cb8c8fd9aa9863de5ddd9cb852cafda487d29b0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"13f29eca056350277ee80d786945386abdd1c8b7c04dc35a94c7ac8146e7b6cafa617652fca15e79b8376341ae5576d0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f095b2247aa3ada3c824121b4720dcceb3b65f7a2b9e880acdedc613a62d9be6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"773cd6f711b68a27d958ecb01f85d8480835014d23d3484e69e1c63bc736f50697bd6cf7d5e7776a13ae946ed10621334cb84ba8357b26d45cb6c9990826f993\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.module\",\n      \"name\" : \"jackson-module-parameter-names\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support introspection of method/constructor parameter names, without having to add explicit property name annotation.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"495868f770056602bfe13ea781656f03\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8d251b90c5358677e7d8161e0c2488e6f84f49da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baf1a3156a23cb407e05374161a07ed8560f78a7ae249955de04a9a2fa2d0f2b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"497b08f55f601b7ff6294e0b8307e015e60ad45c7949bd80ed3f5ee19daa93fad7f0b5a93abb8082ec46480667ab8539337633213d0fd5992e4a10c710f0a7aa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1a50ca6c0e0b4e3ecf83e3f327670a3b36f2b847b46ab5e193e9bccc36fee3bd41c1aa937dda88c4936339eafc73fc93\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"30d05f1dd78a796ba4abb79be93dae2d7e4e5269de18d85a9d89b1c92f6ff8fe09ac1953a48a0b2b51906bbaadb56fca\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e50d137efbe3de957a64fa4b90532cbb67efc2b09ba11824362315d1f57b812\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9418c5c18e429e201d7f6a4d5f05a52a433dbe4bf72a82e3ea69010c1d4b9ec99fc651804f2f8339a53841f88416318e3ab7fb1a07391cde5ea745ebbfcf98bc\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-engine\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4d571057589cd109f3f4bedf7bbf5e7a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"f32ae4af74fde68414b8a3d2b7cf1fb43824a83a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baa48e470d6dee7369a0a8820c51da89c1463279eda6e13a304d11f45922c760\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"52ea2f11ec2ef0457384335d1b09263f4efecf63d9df99c5f8396f74d972722c51f8f766370e85e030f4476e805dac72603296942593c5bbe56993454b9d8e30\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7c520e04c995a47c19c94fdcbbcba9bb117696191e6a989a82d9f960e0e315e5cf87d28022ac5cb2701c85d5f38eefde\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"79d4f2fb987d6a44174dda99b1bd827e8dfd0399495c3e994371d4f69631212768dee8b891313aac89045388a1bed9db\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5c3fcec688368188688cb6949c1230c2822211e53f3a65b7b3abf4a38051798b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"30a0834e88bbc62287e5f49302c4a07b6da1bf4d9774faddbe7e606fb296c0dcd71c7e90ef8fff3e18dd050e5a19f7b903c91674ff4806cdb97111e4f0cfc199\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"29fb14fe1d383588e87a73da4508604d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b100d2d21d45dddd740d496357ca6f3813d777d0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"371f0f36d226a8db972c37c73f0a0896ee4d3e77c29b54dbce8a64af731a6e53\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"42bc3a99f9c9ffc9fd08447303a946fce1c81e3a869a5788c7d3b669536455eedc8009428ae4660d66b0d74ab170968b6aad905455b53342d7c521e7ec4c262f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f47603c4009bb767f9d5cb0bf3fcba69167daab53cbfafd217450977464073e8b814c76aa545b1eccee587201fe93eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"bbd77376c9a46de290522662f327a8e6b0221a6c0105632e73b527799bec8a162d98948d0d05b32509650b4f47a6465e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e9549dda419ad6f482e3b376c595c69ccb93cebf365c1b18a59bf226c3264db\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1473f0de013447eb40d0b6d2a30013d2a7d262ce1e0259d4a27f88e421e5538234a46704f88b27c227aab7ae2261995a73f4075a6a43124e39c7234c6d164fe2\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-engine\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"71d86cd027062c4da0796c2493ae94fe\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6c9ff773f9aa842b91d1f2fe4658973252ce2428\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02930dfe495f93fe70b26550ace3a28f7e1b900c84426c2e4626ce020c7282d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fcc9406d1e0301e27538757c9649545d784e83743a8800932971881cfd78a14a264ad13c0b92fad9ae1be50963c540427a19cb2d1fee06888ef48105aad4c8b\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6657ac1bb11d7a40bbcb020add01e57edbbc521645116908d857074d9ea319eab3e7b7f2e9fa1ff8df08b5db3774f4dc\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"607313914c11274c577b0aaaae6c68aa6ecf25d8302f55d4e334aa6b58df2e543d2399785e2019a56b85aac7716c9623\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"be3560971111d3f548bef24aa6660ec2a126fd17b3bd68b7deeb1ab48735a9d1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4ba6cb70f8fc1918dcedc874340488909c48e0f976d1834ec433f4b5c6cff55b16a996a0443a1b68a0d0ad84a37bf51386633905628728bde08b5820ee67dfaa\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-observation\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing Observation related code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b55c9caac5c8f778996937c3f6cf4101\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fbd0e0e9b6a36effd53e0eee35b050ed1f548ae5\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48f6607b248e8b77ee9f7b3934f70124471daf947b30480c1b9c0e9d9f996c83\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3e12e101b161715e5c30eb166578de7ae76749a2c4d22435bc57395be14d1313073d5fa76dcc883ed807d4982d343addfa24540e283cd0432f1428ff00962d98\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"791f99b503d7fa16733a74d92ebd02e72dfce4d648245f149f5363019beabe7e317e7ef0df0bcb67832dbab03943ff53\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ccb83eb15cd8004295bdb40b948cb9d3efaa4281b0d02a97b49970a2699822d7cd15b83206c236c3a41e49063caa5ded\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"773e3647329d707d79efcb92c88cbe0719b4dcd820f06983e6e283e666875acc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"922f6c81c3a7b8e8c1296eb3359723161e91bac646d4bef954904c70a40ccfd9dc95c783715fcedc788f67ef06ea5514a918c7cc6811f2bdd39eb011a36698e7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.awaitility\",\n      \"name\" : \"awaitility\",\n      \"version\" : \"4.2.0\",\n      \"description\" : \"A Java DSL for synchronizing asynchronous operations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8f3644827b9e3037de42068c57006260\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2c39784846001a9cffd6c6b89c78de62c0d80fb8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2d23b79211fdd19036f6940cc783543779320aaf86f38d6e385a2ff26da41272\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4c422b4aef3dfceb040898f45cd1b2efb7bbf213ef9487334a0d0e674e494e120fef61348f8a81ce726f2f66dc426e133917de20c52b5d39d792e2dca7bc82d8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"11d15d6efb32707cae528eefb8fa4ab7820649ed528c3447660efd984518ee2906421af5ee76ea8181c904d594e8e719\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71eff4441379fb1d13bec42264d48dd1ed4817c7a226a4ef1e5255e5afcc8e5e61aa92677ae98fdce2bf4824b4dbe4fc\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4fc8b38b34625336be520d2be1edcab4c8dd8e0667fecb2aa6aea83b9bad7f28\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"074f8629ab499c28155e505513e0a25c83ce722747d196966eac6327de604853503ca5f54b84effe8e2e3ab78d9ce285bdba82bf738ff8bff0f1009549230521\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.hamcrest\",\n      \"name\" : \"hamcrest\",\n      \"version\" : \"2.2\",\n      \"description\" : \"Core API and libraries of hamcrest matcher framework.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10b47e837f271d0662f28780e60388e8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1820c0968dba3a11a1b30669bb1f01978a91dedc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"6b1141329b83224f69f074cb913dbff6921d6b8693ede8d2599acb626481255dae63de42eb123cbd5f59a261ac32faae012be64e8e90406ae9215543fbca5546\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"89bdcfdb28da13eaa09a40f5e3fd5667c3cf789cf43e237b8581d1cd814fee392ada66a79cbe77295950e996f485f887\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0d011b75ed22fe456ff683b420875636c4c05b3b837d8819f3f38fd33ec52b3ce2f854acfb7bebffc6659046af8fa204\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"92d05019d2aec2c45f0464df5bf29a2e41c1af1ee3de05ec9d8ca82e0ee4f0b0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4c5cbbe0dcaa9878e1dc6d3caa523c795a96280cb53843577164e5af458572cde0e82310cf5b52c1ea370c434d5631f02e06980d63126843d9b16e357a5f7483\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/hamcrest/JavaHamcrest\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-api\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-api\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c6b8b04f2910f6cef6ac10846f43a92d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"eb90c7d8bfaae8fdc97b225733fcb595ddd72843\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"60d5c398c32dc7039b99282514ad6064061d8417cf959a1f6bd2038cc907c913\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1fef44d4aa781bb119ab723c3c2a6f0d27efc4493a1fa26b603c7c7a8884c4d6274bccec6536f120d55f876f8d052aaf6cc003074c27cc704deb2c4bc08b6f0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fd81f893be859a50766bfbf3bd74bd7d359c6d481b7fe3099e220402f585d3d46b6ad42a36b1d88eefbb6fd27a3cefa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5e13ba92f757499ca52d719869d318cade9bde9c948ee9c68d753a21ec273f7b56ad68ff8cb281614efeef1d4c479db0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"997c9e0cc57d61a85a8eec568d0f014d47af5bf655602a2c3518b6530b089905\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97c3e2c1faa1f77b174ef6ce7b24a2339e547f5976a4e40348653e84498e0c3bb96068447facef6df6b54d4af34b807f19b4d2bb1d31e26f97d6dae07843bf6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.skyscreamer\",\n      \"name\" : \"jsonassert\",\n      \"version\" : \"1.5.1\",\n      \"description\" : \"A library to develop RESTful but flexible APIs\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"60a7d3d352b233487d735f4b86802717\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6d842d0faf4cf6725c509a5e5347d319ee0431c3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1e9a7c443d0dd579906646d767f3701918a78cb88a93112f528305fc9095d261\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"51221bbeb30ed47840494d31128e605e29a96249f3e4b9c00985a865f8ed58b73e045772e3b0af74a35018a9dd004b5cc2182344b9154d9a50604ad1a073f2dd\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"941cec8d4ce1fab19f32b36f0afd2c7de27325659c5f85ab90948182098de4afe327b49cea57b946f18671af8037aefd\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3fb46460472c82901ec6fa5deab84eea18369e74aad920e3ee9e0fb8a859e8397a287428d0bf1c2b137368b6579c5c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"24b6c0f73ee51c19d5fdae62588dff9d0bf172da7e6ad1595e275920c8de829c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"686fb7b0ee0849bc78b6eeb74a941795252cec9a62ea153e6bd1e77d51fb6ee14f64970cb52cc13f581d21b166c6f1b28b8fbc4c7ae0c3b225df385a92635f0c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-junit-jupiter\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito JUnit 5 support\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab44b412aa650651eedf323e945fe367\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ac2d6a3431747a7986b8f4abef465f72bf3a21ae\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e2416a260c3a45ba77d674cfe27d49428e57efe21a7b2ddeae733ebb5c5d85bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"39cccb119c0767f4e443567873af78d882c4a1e99c553ad39d4efae2698933de602d9c0046a70a05be552793569d4b43e75c2a798fd1f7f0a8c5ab34db8b9c94\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f02eeae7fe867ff8580164b4d20d269efbad2a18ba2ffc8ba9744c603c589fb5155399361b14ab2a6549d605d26a4694\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6b95b5f5efcc97a2531c9c108e53fe5465ae0249d46988fe7fd47df7ad4d154de40a66471a996ae7abd75bd0c1f6c9b4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"30978340a8749b094a5b0f42dffbb91e72f7d7eaea6924efce13f47a44048fdf\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"80601cb4de8850a0255b7c28cb7993be667a238d961fd281c7152b7ba40eec399240a2ab9d686cd1463872652876e88ef221d699acb61a2acf041c9f187053ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-api\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b5e9bf76dd128b37666ecd9a252b50ec\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"74c65e87b9ce1694a01524e192d7be989ba70486\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1db48e180881bef1deb502022006a025a248d8f6a26186789b0c7ce487c602d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4cbf72fbea7009ec2fc363aae2ccfe11ea2023967d65be39335eedd1d8917b7402eeb2219efd5a1f11d03833dd1f57eecab428616b03124ef2266c6cca06ac56\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"edd8429f2f88476afbfa63314f7846d1341a4cfc58d3abe55b3cda236613feb6859f711e0ae60bd7821b74e488fb0666\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b67292ff0c7ca988a4b40b6ec14582ef579990d275a37944ac9572ecdfd4bf6e9fff2ab982b21d159a1135c21a32495f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b2641c2db75d3c676e451a53b5f60dfaf030a84e0230747bd50d00414f8a27b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"f1f4d9c48a9d088460e1ad3d71126b243069e522588cdc5534ac8f201ec0574287e8f1fba182f8925ee75b78726269487cc0160f7f8bd1aa21cc8e587fdb5c4a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.assertj\",\n      \"name\" : \"assertj-core\",\n      \"version\" : \"3.24.2\",\n      \"description\" : \"Rich and fluent assertions for testing in Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b596a91049e6ce526bc5595c1bebea2c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ebbf338e33f893139459ce5df023115971c2786f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"df3d0b348f1fe806bdddcb10fa4ae63c6679e9888d4bc7055f09848517976aa3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d8e3159effc7954258f2398e26c34eab6c243675408c7b5fcd7ed04a7b7dc06006514510ad15be9e7725f724cbf6e5c534cb22cbfb7c0aed71b81d4ed5755220\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4f06196b5329e215282476d8e3aa5065092924bccb91da4eb0aa2e8fcd2509f249369654f0c17b59c38f11b878a305e3\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3029ae58aef975843e9205f130dcdd8f8e7da5ff1bfad62b7d918ffe52b74a3c34a859af13393abe122124a9132f3feb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2db6965251a03be26f5baa83792a002444b4de34aaaefb0e6cf3cccf0a20939e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"fa3ffb87bc40c3f881fb477d41c8565cbc1ce46ead2030442674bb86a425c722b75fce5bb3c22425b21cc3122ac46e0f28b2eaba2bcf5d5ddcb31f47d967b890\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-web\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8a6aea9e1fbdbabbd00e35038739200f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e27e36d4222fd4d589e634e1c7f5f09f0316147c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2f14d3a4a0ae3ad634bcfa07117542001c1789c0bdce3504baee8f2bc45ef006\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2fcfc8d9abfcd0518b6755737c6e520544600b3c26b42b60d1ab3fcfceb31582d5dbcd5d86a98ec312442d335e49f0db0ecf21d8e99089ef41d962ece42d97ae\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e3c8cb02b18ea5b7aa2a7c9c97c62385fcaa8fc53f41d7bf0b98d262a10473e9674924ad287964f6e58fb9c5915da8d1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"713c9200480f14fd4bcd073d43ac7900771c9d36b4e72b50ddf80733670948ad57700ea37336de5078d16557e426de79\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3346906c7b4b455c00226fd9804a237d3a667523800e0c2083413fde4592b7c3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"99ba750d8e1c97636eb47122ce259b1bc9b91c51fecc50d13604f7ae7096a20f1fa38562d83786c1d4c3ba07ff94b286d869d671a5f0d00fd6c378f032332f63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f808bed72032367a1170477e74e57f7e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e6a20062864e3a9a0bba0ac3b0c5a819453045b9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2e0a11d69fed912dd6f5a6b0f492ce1530e2ac932de9588d4b7df0ab548eea0a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"83c1f7e7b404be7b9f603a386ca2d0c84c7e0b73190ffb19ef2b0dff5cbc1ebd57ce73be663ee01ed28f1c4f41d91db7f070d7b37a3f2ae6b9b6814dd930a089\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3a5159cad10587b250f0a1f7cf6ebea9f2cbda539c008094fec1dff47eeced5b2119be3ad007eab0598445b9282164f4\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9303b808eed6e0425d5c7e968601960d9ff2e0c2fd840ffd041b01f0499b1f86ae05c50e968e925374a54b26e9298410\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"a18f18bd0a077a38ea0b3aeae85730b9f104d65d4d48f88210f2954c45739eae\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e021bfc51b8d6b8cdc1b44cf5042778c208db09b349250e33630b28ace2ed97d52bd89750ab70e14b650578f379a7e6172838c83bbb2c974394132cb80381f27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.activation\",\n      \"name\" : \"jakarta.activation-api\",\n      \"version\" : \"2.1.2\",\n      \"description\" : \"${project.name} ${spec.version} Specification\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1af11450fafc7ee26c633d940286bc16\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"640c0d5aff45dbff1e1a1bc09673ff3a02b1ba12\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f53f578dd0eb4170c195a4e215c59a38abfb4123dcb95dd902fef92876499fbb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"383283f469aba01a274591e29f1aa398fefa273bca180162d9d11c87509ffb55cb2dde51783bd6cae6f2c4347e0ac7358cf11f4c85787d5d2857354b9e29d877\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e34ac294c104cb67ac06f7fc60752e54a881c04f68271b758899739a5df5be2d2d0e707face2705b95fa5a26cedf9313\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ffd74b0335a4bfdd9a0c733c77ecdfa967d5280500c7d2f01e2be8499d39a9f0cd29c9063ae634223347bb00f4e60c33\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c97236eaebb15b8aefa034b23834eaeed848dacf119746c6d87832c47581e74d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"147dfa2bf46bb47c81462c36ac6612f9f807169ffb785e2bbd45538205c5713f33af4373f3324a2063350c2367baff37e9c2cf085c38c96870ad88c60a7fbea4\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api/issues/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-core\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Core module of Micrometer containing instrumentation API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"30dcc7ea6a0e99663e5908bce7371206\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b72e9a2f26355ecb8ababa0148a5c3c4ac648f14\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"97d0a5309e9c584f4dec6f549a383ae25d8727abff43cff8e0b90580ee797b67\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2acd080a1b40cb5a1ca0b7266af829392e318291dab57e6239ca97d15112cc206992b78316f4c02400454124519a084341e4de55dd729c96805b3fb196707a64\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a3998a9a219fc049ace5731fde94944948332eccbe589dbc34456057a2df173ef17e3b0642233e513d3118bcfba565f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"22c97b3fb49d299ebc36674a6e32d9fd05726d88109ede3323e3e97e82100d1ed6d7010e86749a2b07ffe994fb3b7833\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3b272686c89e274b5944715db002871e072f0f8c7099228f6d6909656b6ba3f4\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b1d82086950a2e61ed3e016fa962af2e9c3b2d543c4c311d40d9f7fc402b9beb3e5d09261d336cb1634b186f723bf584874f3fb8a29c38198d5ddd2b386c4413\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-params\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-params\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5e8e17f6f2a5dedb42d9846a3352dd31\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c8f15d4e99940c4564098af78c10809c00fdca06\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c8cf62debcbb354deefe1ffd0671eff785514907567d22a615ff8a8de4522b21\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dbd8a3bca0a03b6eef54de2b489685c8125e0c6f23cbdb633174b21e07cc7b97a24b55dcb5b60ec1a496683a918bfdf1ea0459950689e3755aa965ea9e106ee9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"882b3106163d7c195867e08db9948a0997e1469a23c847bff523efa30a9b274c0588f8228fca98c78abf9b61709a7ff2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e4e9a7dbb32cc3f16f21a14fe036aa13488c5b94e3cb6cc53b417c4588b90b5ae118caa3eb9f4bc9c513d06e2c1f408\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"171a08027b527e3be1ad66082405eacf4a55746dd983c46d9ff7ee5552276615\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c435b4a17208b67f6fa35ebe74872c3d2c3557b290437bb682ac86701402bbe17d0e53446c674bb94c7feaae4bbfa99d888c7bf7181707e27fe08ff7934c00f6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-databind\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"General data-binding functionality for Jackson: works on core streaming API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5f453c55f127690fa8491ce347aa055c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a734bc2c47a9453c4efa772461a3aeb273c010d9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c3c53333a2172a80678bda1803e39cff45bec6ae3e9c7d4f44a81ec4e2ab18dc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"490ccc99a9c28238fe28455bae08196b83df034cae8a1947d27ff89e500a5d812cf4be36c61942e647c62ad540d8eb4428f49855f0cc8db0ee9e7a5b12ba2454\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"b53f4a6fddbf677a8d02c65e9f0a96372140c68286d68740987fb462f946de878abaeea421d3e4716751f04d88c16ad1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5a407605544e303abf8a212651bf5e5594fa313804a399bf03401f449c0baf26ef965def518b05c275b2f38f18457739\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d0880002ac261d181e663499627fcce5763f3a9120bb76e758adfb9939d17c98\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97bfe0e9117dad82e0799cb2c105c4553c6aa5ce9abdefee4fd5b584876555309aafa9a19ca586e928e292e32f23452849a10da7364966e11e4f7afcc6aec78\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-databind\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"jul-to-slf4j\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"JUL to SLF4J bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"24f86e89ee3f71ea91f644150c507740\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"09ef7c70b248185845f013f49a33ff9ca65b7975\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"69b4e5f8d3bd3f6f54367d19f2c1ee95dd5877802f12d868282e218dd76b00bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c1cdfbc0c867917d65ab58e039b01c5b119368aef82abcb406d91646da208a4bfad91831a5a425eacfa8253ccd5713a9d4325d45665288483929cce7a6a56eb7\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a8d45375ec27c0833a441f28055ba2c07b601fb7a9bc54945672fc2f7b957d8ada5d574ab607ef3f9a279c32c0a7b0a5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d65edaa8f6ad8bbea84617e414ede438ec4aafffa3734f2d38e6dd0a01c1f42f9397acaf6291a73489fb252d7369c71e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"69416188261a8af7cb686a6d68a809f4e7cab668f6b12d4456ce8fd9df7a1c25\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"52d54c80e3934913a184efc091978201934b0ee47a6b4f9c8555a4d549becd26957e17592aff46dfdcfcbcb2313bfad09699ee84cfd7112ed2a00422c87399e8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"6f7384977eae04c804b1062df9217959\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"faa2ce019bee68a8d17529d0a08ebc427f927e13\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"6fde604399114e77b12519b3d117117c607cb73b89a88800856fb0e0cc82ea7a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8619959d143ef38f5c846591b8b10b0c50906a3301a5e9ed3e3df44124bdfbe3197cd4ecfb214c3250f40a0c1b11138b7a3f6865755445879f0685d2e88a6846\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e237fdf6fdb8d21f2fc19fc15a370901c368266ae8d2b157f41b5eeed50b211a871fabc352dda10bb3aec60975d233f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cd6240fc102daf1efcd9fdd6532ce21297d5477e9bde3f5651cc9ec9505d526f63ea2284e484c2aee2a8e63841137839\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3959b52aebe7405a95f82d8990b8122cf21b89967f691dad851b85191973f9cb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1b4ef33997158ddb97ccbcec7011cd55f0e019428d25410b01a83ca58c9420f2f8805be955cf704605145abe582522db0c8afb9698ae4efac141a3807a457ae5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.latencyutils\",\n      \"name\" : \"LatencyUtils\",\n      \"version\" : \"2.0.3\",\n      \"description\" : \"LatencyUtils is a package that provides latency recording and reporting utilities.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2ad12e1ef7614cecfb0483fa9ac6da73\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a32a9ffa06b2f4e01c5360f8f9df7bc5d9454a5d373cd8f361347fa5a57165ec\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"bb81a42498c65389366205f4e07cee336920e2f05cc0daae213f2784b1d0ce9a908b038daec20478f23eb00b2bf704f96c5b00f63c99615193ab2a3cc4a9f890\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ca4640dc9d848e6c6d15441897e1b5a9f27f34207b0bb456dd54d8f267b73b348092e548e78634144de44ba3515205\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"406c2b5c6f64b0c090568e479b5e6136a04a4e77f8eea65d32b4e2b01deebcdf6a0a851240cdb740c25b5a5e61e6c179\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"50ae828358301033542fd7c412e86ee318d5451f89a182e2a679aaf18099d26d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"456c337b9fb385579aae707409ed6a04d08e5fc87b1a46733dca617c22c625bf253dc4747e0cdbf5e7d8b48102d2938cb482b6b688a79aab645a7459c592258f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/LatencyUtils/LatencyUtils/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/LatencyUtils/LatencyUtils.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-el\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f9171a84574782d1d68acd8b07177172\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ad7312421535d7d3aabe0f541e852baccb59726\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bac12b9c993a9181ffc88ea8ba085491a482729e64ae105750a7475a7b85e549\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77cf7be4536d7f1f4761fec33562134150c0ebc74d582160ff913c8be37b1502ed63e90bce81bc8617cfcd76c774903c2dca4209a972146f4c976f786456c596\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"62b14b49de8ee6efb41831ff172114af56a18379a797de732915ac356bce3e5582764253852c9831a3c3b6c1e52dea65\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"05cb21cbf8b221332d7ad588cc6aa2087c60e8ce92c5ff2bddcd16465ef2a0198f74d4595dc3313d1acc68ea945c8672\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c18e9b240138c21a23b0bf2f502d1d667084c5a50d7b3340a4a08799a3175de9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"663d02ece35a989d8da1cdbdea002974f0115ae8c727dd71f0505f299c63f04c0e83b718e4c3e65412bea1c79d872e9ca7d9431c7deb63a312d3191d419620ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-context\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Context\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ca23d3013c2afc6d3b30b993f3c5cd69\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"15df19852991220556b4462a366269b8e15278eb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"af22a435469956415bbee873de6c05995ef12f2d29622abf510a94581ea52de2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eca3cb14e8c0fb65d27bc21a8041aab3baea14f278fb546356fcec9874d0dcd10353fe697e94ebc35a78abb3387d5a41b67c1cbc9341eb05359c1b535147a9c9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"374207d989f7f27ded5468f35867d0aace78927cdaf98c31b2b6345210fbbe960ae5e5143bb0308347b7ef386159fa04\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"236c1d366734b231ef4a334da4220b311dd58b1707ae854b2a50ff89b6b348913458fecdab14d196128b695de6dc9832\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1e1e87df37dbc064315d7afaa59480c830a0f445ed0df2ff5968931f96e9e86\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a600b2720ed8e5c6ecbb2a68b6a5fb5320811818e2128016b9888df705901a8d0f38dfa99b8d458724a85e769b4da2ce14d461133e085f8aab23f59e9e520c11\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.opentest4j\",\n      \"name\" : \"opentest4j\",\n      \"version\" : \"1.3.0\",\n      \"description\" : \"Open Test Alliance for the JVM\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"03c404f727531f3fd3b4c73997899327\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"152ea56b3a72f655d4fd677fc0ef2596c3dd5e6e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"78fc698a7871bb50305e3657893c10500595f043348d875f57bc39ca4a6a51eda3967b7c8c8a7ec3e8f85f2171bca4aa98823e912e416e87e81c6ba5b70a37c3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"10398b6998c9202a0731e2e19ae1c3f9d8a83582c2663fe7bdda15794ee6fa816727dbd8f7c7164bd5395ee1cfe7c97e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3abe706fd78509c25a402c7bbf6f9ddf71ffb5b35054864ba0fdf7902207115f888a0ba728fd71d2e87a9360d2498121\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d961907a1bfa1dcda329dca494ffbc251b31fabcaca5ab7095661a8ce3c1d654\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0ad661617bcac51bcd26f7ad4611c69b1fd9811b50dbf734e041a3243ab1f845e7796620e8a7c40c4a2df3946864598b1251396c7d9bd813203d82710788cce0\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/ota4j-team/opentest4j\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-core\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Core\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"98bedebd5de314d344ed3a7dcad01c66\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e43c71a9eaca454654621f7d272f15b53c68d583\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e3f7378e98c26500bdb5ecd6865778f57a22787eb2f11b9bd5fb8e438a0c631\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9654f2d77899116d66dbf5808815c866da0bc7a965532da059c7819bde3928e8d3692f0dc97e06f94c44e5452b785b50eb364a1cb7e46385653ba0e2c7195306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3b63b4a26c5706ef2e379ff7bce89df983e7ae449a927905ce23ecf26e22bbcf8e91dc53cc75f4f7cd72bc09d7e7bb20\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ca29e88f0764a6a9279fc93d5cb9284a04c6ccca6a8a5beaa404079b90674286fc6458d14b0b0a727d31e00b8009e4f9\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"861fc1147deae5a55165bd32c3fd4e18687afcc37876205c10bf1feede582ff9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"659a0d2e5ba153be219e1ebbafb28f9b48c44a2acd78d695e7479551a1c1641b7893d7df071a3cc7436de03735b0c8024b2f758bd0286711eae64ab005f6e929\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.jayway.jsonpath\",\n      \"name\" : \"json-path\",\n      \"version\" : \"2.8.0\",\n      \"description\" : \"A library to query and verify JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"501b9f34e6a05c20dd74e6b40e066617\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b4ab3b7a9e425655a0ca65487bbbd6d7ddb75160\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8d1521092a2acb13a2667774b8b81debc1f2a0e937007e27e5bd28bb222910774b64d6e269f33473f765c810c03a34e715d16065dc9a4be8d8d081436282ba7e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"aeea493be7c23574a77df50a0652776b768d52e4238efd504b8ef3b142bbe6caf0dae8955b30c2173a54f70243d36a36\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c11c80614c007f350fa2fe758c0f4505e7ed7d25590622f133abc59ccffeb4e0b2abfd393b83e58dff4668307f28704f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a7d1d7845dde343617ec009dd0d76e6bf012f182324e3b9d0f23c52bb7f67f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"da023255dfa2271a0b6b35b7d35980c3c502f3f63b3d515714f7dea54046f527bd6cbd903fec9492aad88ad03a1b85dc2b05fca4b34ded3c3b427c4cbfab02fe\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/jayway/JsonPath.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"slf4j-api\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"The slf4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"45630e54b0f0ac2b3c80462515ad8fda\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"7cf2726fdcfbc8610f9a71fb3ed639871f315340\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"069e6ddce79617e37d61758120c7e68348ee62f255781948937f7bec3058e46244026d7f6a11e90fbc15cd4288c4bb1acee4f242af521c721a9e68a05e64d526\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"fd6f7ad85d02ac63cd1a586c8bb158c1fc000495f512f097731ea9f749b5da2637615b821294962805ba312c738f40aa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"17cd61f59a162250b52a89c7c56eb60da253b776210500313c7b82744483ff84717946f969251fb4d76f9bb12a2458fe\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9dcb04582c64c79e788f9191195834ec75bb3457133d22a176a0ccb069b97103\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"990faffa454598a3fa82affe30f1323db769d2e1fff20d9c7163ef6fd95ac7a0874c06a634207a2eaed9e5afbdee68b225138fc75018717ba97efe3ffe92c88a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-classic\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-classic module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"204b49a7fa041b2b2c455193079dc1d2\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e832f7263ca606ae36dabb2d8b24c2f43d82cf634e81dad9d1640fa6ee3c596\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b535f2cf5a2fdb807017cb6fe456c40dcb11491e743ff86f99df2714a1b12bb9182ac193d37c8a6dd7eb2bf4c7d24390a6d551d02a280083673516eecdabc4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"606400251082b8193a57bb20f1774ee2d6e439fab2ddb0207643fe9cee66cf61edba5e5c80d4b3bc9785a7bab910f8df\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d9d9b1412d2fea3eeb5d110a0e7d44c9bc13459fd2b2f5cbb30b95174081f0184758abe43b5e6b6197a716c3ba7b310f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1b0d59a9a91fd7878c92b3680cde8c34896823612a2f04715c05e977c09db82\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e0a39dacbb91b7d9f00bdf78829918079f6f2e749c28f31a359064bac9ac7eb65c87e581795946814460f787e33b8829a9cf0e933a0f87dd7d48f288d45f5064\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"accessors-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"Java reflect give poor performance on getter setter an constructor calls, accessors-smart use ASM to speed up those calls.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fc814b28882dd9f2552eda21add0698f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"aca011492dfe9c26f4e0659028a4fe0970829dd8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"12314fc6881d66a413fd66370787adba16e504fbf7e138690b0f3952e3fbd321\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b21fdd3401a0557d2d04a14c27563897afe9e001fc520398e22083bc18afee5e48dd9f5fc6561d0f327a30a9303bf5cc20f0a2ce741d80b3792e258276faac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7464bf3917d11712b235c7e1af339766d01cb4b41ec98941c3c69bc4ab9a4d0e6c832cbf01482425100dc8f1611ce3a0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"be26dc2bfc5fdc1a45e14f1c2fcfe224994e66d39049e235ea83c714fb90bb685d3f2209c0d550528e2cd9b2d9d95a6e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6a914eb757ec313842f13c837eeb628e606323cc63dc24127e7a9804e2746d12\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"edbddef0538aac87bf6af714e12c4078fd6ada069b6fd0e1e5c1038b060999764e06c28b3ca38b8d540d0f60c72f7321ddc22d2537156999bad5098c89b6975a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-core\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core Jackson processing abstractions (aka Streaming API), implementation for JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c86c75392bf138d54d2a219bb1d0cbcd\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"60d600567c1862840397bf9ff5a92398edc5797b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"51fab7aad51ed588482edc507fd542747936c5094d1ab76ed21ddb63b96b610d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"112de40a31dc7d011f256f1d2fe0d9e2afc301a1f31974318f8d070c3e362b2ba96005167384244f630b915451db6694bd3cf6a9b793872351bc18f21c9de5e4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9daaf08467525e462234c53ddbf7287bcef15d8df7fbc64bcd558a91d11e8335b3a79368d194b126d3c8fb846800025b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0b4fdc8d11fc060461e74e773fce2e64d1a98bed7db6edf51784bb1b801da4bae744a2958e81c2e24cb992fec892fb6c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"751ad4f10a78cb36fccbbe1dfe208816f17619edd5adeabc86b7509201e03c3d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa5807b7d92d150fada6a4ecdbfce998bbea825a09af8381127ba3736de029ae9923f54d770b2e5c3f5c85d9b4bcf21e6893a5a3089db2d02f1432b85dfa0fe7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-core\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.xmlunit\",\n      \"name\" : \"xmlunit-core\",\n      \"version\" : \"2.9.1\",\n      \"description\" : \"XMLUnit for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"011288450a3905a7d97e3957b69e713e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e5833662d9a1279a37da3ef6f62a1da29fcd68c4\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7e70f23d4f75e05f0ee79f0f6b9e13b6cf51d34f36c5fc3a6b839429dde1efef\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1d07dc1582a1930664ab3cffd1443e85c83fec138c663f3070a9d3b283f818157b2cdd1589595867281a96d3b444b18c22c1ee3249a75c857c6ee9682785e8a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f54a506a08b66776d92d4379712ae9f7658cc89bd7b780eb629bd37143ff68e28cb2314539dc3c1ff13dc9cccba394f2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"7fd679371624f72417612491bac721a49f229744df3fc7455e5fd3983bd2de452a4eaabb707be7bac328f3beeea88d99\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c517aa9c543a4a3df361c30ba6609082a1dd5dc2abc351643ad5b733a1282773\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3797bade2087f791697f6736296381f8b158a2a93f50faeabcd96b4c9f48ad26fd78af56cc1036c449c35e624181961d54acdd7623b84c23c81c72d5d0fa57f1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"OW2\",\n      \"group\" : \"org.ow2.asm\",\n      \"name\" : \"asm\",\n      \"version\" : \"9.3\",\n      \"description\" : \"ASM, a very small and fast Java bytecode manipulation framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e1c3b96035117ab516ffe0de9bd696e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8e6300ef51c1d801a7ed62d07cd221aca3a90640\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1263369b59e29c943918de11d6d6152e2ec6085ce63e5710516f8c67d368e4bc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"04362f50a2b66934c2635196bf8e6bd2adbe4435f312d1d97f4733c911e070f5693941a70f586928437043d01d58994325e63744e71886ae53a62c824927a4d4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"304aa6673d587a68a06dd8601c6db0dc4d387f89a058b7600459522d94780e9e8d87a2778604fc41b81c43a57bf49ad6\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9744884ed03ced46ed36c68c7bb1f523678bcbb4f32ebeaa220157b8631e862d6573066dfc2092ed77dc7826ad17aef2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2be2d22fdbafe87b7cdda0498fc4f45db8d77a720b63ec1f7ffe8351e173b77b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a3ff403dd3eefbb7511d2360ab1ca3d1bf33b2f9d1c5738284be9d132eb6ad869f2d97e790ed0969132af30271e544d3725c02252267fe55e0339f89f3669ce1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"http://www.ow2.org/\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://mail.ow2.org/wws/arc/asm/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Core starter, including auto-configuration support, logging and YAML\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d9eb815815944bcdaeed5e63f32e5d7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bc03d7075fb9d9d4877218db48d5dae3dd72a65d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a25f2f4172c34f46b73fff03293370c3daf231a1db2883ef8032aa471779fb8b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"35cc80f9b10e81624324083a024c97e247e12f54762cfaadf40504903b0ebdc76d0226af1e4646bca445211b039913709ff48289dd57e27ecab18fd6e427d306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9acae9f3f77733a83d37641d3bd32d762225a08dcb20d61ff33a9038e8a4fe2dd39026bb08026cdb618437f68fc11382\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"1e605937a46c8371423b7876d5dae4363f718f70200a1276056bd6466d03096aa580708c7abc76618a141a542df29b24\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"331b3c120493fb5d9dd628beb8aa10382772a08d0a687103a2e87a4516fffde6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9f2612fbecec4664979896868e4766b1f66aaebc914e46a07a7ef7e5ff76786e5a73ae9ca5f364d23ae41f8bea2fb44e5034014950423fdc3a438ae1dc275820\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-core\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"81d2d784780b1fe54275ab4f3d0c3830\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"5b9185ee002f9e194d2cb21ddcf8bc5f3d4a69da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5d70fa6ae0548f89fb4c070423ecc2db050cebf248b0d5f3f2294375a6762382\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9fb1726f3a10f5e0bdd1cafcdc9532536679d04e5cdde9e54bdf18819ea2651bcaac0efddd6a8b5dbf3cfb8dfcd7ab0453f2ff3fa4e21a0f3796d4dd6d630433\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e644a094c17574fc9334772913aeabd6de0be8eacb0718981dbd97ee197a21f43ff3efe2c073f8863a4ff111f4ccb303\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2e8d5d4b1e202e19529270adc7992e9d187ad34bdd62ab7633359f3394059cdade69c88dddd3879dea40487cb17702da\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"25826af7f0a6fd192e83cd14481055b0c5477c325e51d17355d9ff97963380a0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0b2513e578a484562ad47a8a1a4d1fe8253a9a276fac49ea9732877d976a2d1827037caa5a6401d5659c765317acb94127e62f99373a4efea63b44ab4a1824be\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy-agent\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"The Byte Buddy agent offers convenience for attaching an agent to the local or a remote VM.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"389b6aca1ee862684592f6f041f81724\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"90ed94ac044ea8953b224304c762316e91fd6b31\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"67993a89d47ca58ff868802a4448ddd150e5fe4e5a5645ded990d7b4d557a6b9\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7f1a1310b1a0f60d6ff07dee8d9b7e404e8fb9a25a5c0c186e00cafc834e5a026a7694fb65279367dabfa1789c1f16192d0ea794b7f511f0bb3414b8d519e9a5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed1e1d594a7c2837311accf3f718cbc7c6e2034afcab13c63d72313ee1ffd18a53863f1ccd194b85b7e0ffed78bafc9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b3baeae67826ec4e4f71b2870220c362f153d2a126b04557302b5b8e24a58b9741bef7afa9c4e4f0fa1ea9371cbcb1df\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"01ccb9e430868deef5b51124073643eaf6dd2c8c7e4d6e70b59042c9d28e3361\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b621fa443ade355b10cc45329a5e0f700942dd39e633a8f2343ece00446cd42f5c1217b041a67b3143df86397c363f8dcad226f1e70b8755126512a74f878262\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-test\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring TestContext Framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fadfe62dd198a4acce4416acb28e2869\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c393079051398e02c20d8b24e02822f365123719\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2155779c3e461df55f3b093f0e6e4bda398664e3452efe599690bc9a3f1932f0\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5e6e4f76edbf17a321302bf6257c09ed7893e32c50fb3cace37b2271f3c488d397c67b5315ef3019ee6d28544f52cf593e0475bf00927cd67f0c668d6b3909a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"151df7daac9a3e3e74732405bd4feb17ad9ff3e4de196e767f39da675d4480994ed8da13e3b1b27c7b4ee9ebc17feef8\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9069193468f2ae4c65c94d3950541efe37498a4e19245ddc67909181e83e14019f956baba54da0b9d2e8a262db13abd0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"8ccf71564f5ee7e6a578031c7c8530a5ddf136cc1dce483818ebd30d53c851df\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"31049da217d1115b589780ffaa3ddfbf676cc58e70bd4cbc1f24c0cb2aea6b155539f8f9b3f6757f19719fed0a6102110f195b34cdd464b5e375132c25e7bb51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"32fd55a03f648868767c1bebedd198df\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6e5c7dd668d6349cb99e52ab8321e73479a309bc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c1a386e901fae28e493185a47c8cea988fb1a37422b353a0f8b4df2e6c5d6037\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c97a2f9eefa6f34441fc0c97744873040bbe49d335954edab43bab25876a33f4b3f11347459420569ef660449728aa093bbae5d42c0fa733a0b624706b57a65d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"873dfccaf8366ce5b14dc0b5498205debecd90ecba20b1f1c924721764d546b5b9629dd57c486e5a5a2bc38954bf3824\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"67f09e3174ae3fac6ddea13b56dcf078165e715cb18afd73d86bb980357e365cef6e62083231f09ae2accddfe62f5bcb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1c2a60003b13025c959e7728b3f4469b67bad8649d2080c0871418fb52b1c078\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7c03cfaeabed9c57b26e083bcb0ca9a114c491216fc7e9652a39a5468579175e575ace315493610fdc7711c6557eff11933fbd28f5433c237d2277bee102c5a6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"json-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"af9b7eda9c435acaf22e840991c7b10f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"57a64f421b472849c40e77d2e7cce3a141b41e99\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"432b9e545848c4141b80717b26e367f83bf33f19250a228ce75da6e967da2bc7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"56284bb3cee2bcc3684cdcc610115c7eacafdbd70aa852cb0209616b0503dfd448c5110b50e11a71b1c61a6e7ea27594ff63cc968230374555cc6f652d69d372\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fbbd6899d344c3158007f2f033165284323f1ecdfa49e17730d9d2bed8b3d77bbdc209a72a388e9e15a5bed9d9c8eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0f18f178117f8c640e7e1ac2ed4c2b28e331f658f40eac2f5974e891f7130b760e4f057859a537caaa046ba9c086a24a\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4c91eaa12f7c0ee08264ad95d016cfa41af08c963055b7f9076771da402e93e0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0c5fad6395cf3fd25c04fd1e2c915351da4849475b463e017b760ef97800addb170d11f89791dd29ab867e343c35fd1f3ea7935622ba728d789c9f2e7fd1da51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-expression\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Expression Language (SpEL)\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2f56216dc7ee08cbeafa54ccf18cad35\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"98786397734b27b7c8843a6b01a7fa34d40d6806\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fef5fb19f375a8632d2a117f4b3aed059b959e9693e90c3b7f57b7cad2f9e0b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"a28e984d9ff1d4078d57f139ff28065ffba7f325c891c74c0774cd3ccfe50a9462cd93483c28c8ca4674b581ab723687c37c5c88e7cb080823d5629fa684e7f8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a84fb64144a67b56ce322fc9f4948a9491f6f5876d198eb57c99f38540971a0779a2949b93cc5f32662f97a83823ea87\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b099ce06de6a5543e52a2d43c97c4ed6567e82263db29849ff09cf37bf48e3e9974308698c2f272187508e242f756576\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"efa3768de47e3b1ff9257f8367a528e38b3eec9c972eb7ba3dd8f60da626fb17\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"95d7011482520e797a25f9d9b8db1b1bf6c24b3ddb3ca4b70fe5a1a58ed04ea870f86f8393f884dad8b893a6fc53ad8da1b21fdc01d9169564c3dc0229824b27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Spring Boot's Actuator which provides production ready features to help you monitor and manage your application\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"59713236dc4fc4b1562a3ea9788bde1e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca17ff67e80a230f04d40d73321d623b769e361d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"31c28021755feab49cc9310a8353382b3ca35d0adf02926b83e4c44ea4942898\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"ed618c7f1e3337c90919551ad4f14996bb2a78f773ba00c1e02d5a991d1c578e940d9b73f5e01045115c7b5d3f096f8de6720ba0d28992a586ef834948f17766\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"45956cbd019f099f96f36391c98fd23ea32698035f90f6e4e4df0d9a43dc03ef6db2954c2871da76a038511280591b43\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3a08b673deb39ab5db9561281245b76e9f57410601e5ce4040cefedb02e2a19abb45a98d2de170fbbac7b7f0b93eceb3\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"12151432b32e26bab903572023ea022757a31177e4a6315d8fcd15bbbf34731c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"911f109b63d07f20de51f8a2de8799e32fdff05a52def36d408cb1da72a3bb63ff0878f850a7ad1cc9e85393f24ac58c6b8dd4068f11d9e70bc1e130974db00f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-beans\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Beans\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5ee147f2234968eeab4b469af4d3b5f1\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abf52f2254975a3b1e95b2b63fb8b01d891cdc51\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"742baa41c1b0282ef01b3d542dc1b1de71db2578bd9ddd9a7d57fb191234b194\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"efd0eb5a073c899515ae144a4fcb4fc97cc53cbd4236d0e6a30df8fa8873fcd9bc509bc3fa88d1bff86a94dc3dbc5106374d0117f64ec8df9e6affe8f98aaa07\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6214558d1024fa3b5545079268b0b2fbeda93768a0665d617612ddf4e42e11b770c38c05cb86e3ae558025afa67beea5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8170ccea30165f25c533e27c0de38b590ca72f285cfc365c60e97745e78532213d6c93bdbea56f561dd180297a8c5ab4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2761e0814e167de13ed08ce748880006407eda2fa744a347f57684c2bc9bb6fe\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ecdeb4cd558af513ed381942f35bd2d8dfa9b0db446dbc8c5326656ade960682283c71fcaae5578ca431f705f1a86041b0764bd453f30e738be65c4f0bbf37d1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\"\n    }\n  ],\n  \"dependencies\" : [\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n        \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n        \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n        \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n        \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n        \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n        \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n        \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n        \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n        \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n        \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n        \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"dependsOn\" : [ ]\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-actuator/src/test/resources/org/springframework/boot/actuate/sbom/spdx.json",
    "content": "{\n  \"spdxVersion\": \"SPDX-2.3\",\n  \"dataLicense\": \"CC0-1.0\",\n  \"SPDXID\": \"SPDXRef-DOCUMENT\",\n  \"name\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n  \"documentNamespace\": \"https://anchore.com/syft/file/sbom-test-gradle-0.0.1-SNAPSHOT.jar-d1583014-0f58-4476-8f5f-dbbcd2df5102\",\n  \"creationInfo\": {\n    \"licenseListVersion\": \"3.23\",\n    \"creators\": [\n      \"Organization: Anchore, Inc\",\n      \"Tool: syft-0.105.0\"\n    ],\n    \"created\": \"2024-02-15T12:39:33Z\"\n  },\n  \"packages\": [\n    {\n      \"name\": \"HdrHistogram\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-HdrHistogram-2c7953c2c68ec3bc\",\n      \"versionInfo\": \"2.1.12\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-d509473237fa971bc0a8ad7708f3cd561fcf86ef2e611701ed8eec621fd6575e\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:HdrHistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:hdrhistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12\"\n        }\n      ]\n    },\n    {\n      \"name\": \"LatencyUtils\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-LatencyUtils-f9418986cc24a153\",\n      \"versionInfo\": \"2.0.3\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-Public-Domain--per-Creative-Commons-CC0\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:LatencyUtils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:latencyutils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-annotations\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-annotations-c1e7975b6f55f7e8\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"fd441d574a71e7d10a4f73de6609f881d8cdfeec\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-annotations:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_annotations:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson-annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson_annotations:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-core-0408f25059f495c5\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"9456bb3cdd0f79f91a5f730a1b1bb041a380c91f\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson-core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson_core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-core:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_core:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:core:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-databind\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-databind-9ad3756f611d1ed2\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"02a16efeb840c45af1e2f31753dfe76795278b73\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-databind:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_databind:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson-databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson_databind:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-datatype-jdk8\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-datatype-jdk8-846731ed2e85561c\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"695d9b8639cfc7a42a0507708cef2366fe492a44\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-datatype-jsr310\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-datatype-jsr310-1347581c05f302c0\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"36a418325c618e440e5ccb80b75c705d894f50bd\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jackson-module-parameter-names\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jackson-module-parameter-names-f5bca9d628ab321f\",\n      \"versionInfo\": \"2.16.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"9e167afd1596e6a6aa6fe4e1af17f4ce8be0676f\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter-names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter-names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter_names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter_names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter-names:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter_names:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module-parameter:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module_parameter:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson-module:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson_module:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:module:jackson:2.16.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.16.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jakarta.annotation-api\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jakarta.annotation-api-77a5bf527533d628\",\n      \"versionInfo\": \"2.1.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-85a9a90b97292e5203565dd71a1a086ca3fe4d8ccea74453294fee37d5b0c7ae\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:glassfish:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:glassfish:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"jul-to-slf4j\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-jul-to-slf4j-598311f4a5b2a501\",\n      \"versionInfo\": \"2.0.11\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"279356f8e873b1a26badd8bbb3284b5c3b22c770\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.opensource.org-licenses-mit-license.php\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to-slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to-slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to_slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to_slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul-to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul_to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:jul:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.11\"\n        }\n      ]\n    },\n    {\n      \"name\": \"log4j-api\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-log4j-api-c404b33d3a8ce0d8\",\n      \"versionInfo\": \"2.22.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"bea6fede6328fabafd7e68363161a7ea6605abd1\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-bc2074dd7e94ae9ffbcea3c53de6625b1b651c330895f46cf72d207c3025b98b\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j-api:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j_api:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:api:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.logging.log4j/log4j-api@2.22.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"log4j-to-slf4j\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-log4j-to-slf4j-860f45be6a175d16\",\n      \"versionInfo\": \"2.22.1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"b5e67b6acac768bfec1d1d6991504f45453abcad\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-bc2074dd7e94ae9ffbcea3c53de6625b1b651c330895f46cf72d207c3025b98b\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j-to-slf4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j_to_slf4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:slf4j:2.22.1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.22.1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"logback-classic\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-logback-classic-d91fe3ae6bb15cad\",\n      \"versionInfo\": \"1.4.14\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-b997c307e688e15a53c7603c100d346cb7dc9726146cb5644d66bddc7ed1c8ca\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-classic:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-classic:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_classic:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_classic:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback-classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback_classic:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/ch.qos.logback/logback-classic@1.4.14\"\n        }\n      ]\n    },\n    {\n      \"name\": \"logback-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-logback-core-3748310e1aac44ea\",\n      \"versionInfo\": \"1.4.14\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-b997c307e688e15a53c7603c100d346cb7dc9726146cb5644d66bddc7ed1c8ca\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-core:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback-core:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_core:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback_core:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:logback:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos-ch:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback-core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:qos_ch:logback_core:1.4.14:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/ch.qos.logback/logback-core@1.4.14\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-commons\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-commons-c46f369578c77c43\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"e738daf6678eedf8e0c40a782bdb0df064a391e5\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-commons@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-core-3c0d8567351e2ae4\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"49d54a8ed6d3266b4f2691027d95144e946bbe36\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-core@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-jakarta9\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-jakarta9-f4ea2c844b65a026\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"74087b670cad9f9883228ee2aa871f51b53f827a\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-jakarta9@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"micrometer-observation\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-micrometer-observation-26b8a84479010ca8\",\n      \"versionInfo\": \"1.13.0-M1\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"c06e5e0f9b6edc9c0c0ac3dd46a2117ce6f16a9d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer-observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer_observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:micrometer:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/io.micrometer/micrometer-observation@1.13.0-M1\"\n        }\n      ]\n    },\n    {\n      \"name\": \"sbom-test-gradle\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-sbom-test-gradle-93ed082a147d9796\",\n      \"versionInfo\": \"0.0.1-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"8ccd6688e9d8e15d18e0f10967867e5e30729a4c\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test-gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test_gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:JarLauncher:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom-test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom_test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:launch:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:loader:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:sbom:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot.loader.launch.JarLauncher/sbom-test-gradle@0.0.1-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"slf4j-api\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-slf4j-api-44752cfa6770756d\",\n      \"versionInfo\": \"2.0.11\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"ad96c3f8cf895e696dd35c2bc8e8ebe710be9e6d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.opensource.org-licenses-mit-license.php\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j-api:slf4j-api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j-api:slf4j_api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j_api:slf4j-api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j_api:slf4j_api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:slf4j-api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:slf4j:slf4j_api:2.0.11:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.slf4j/slf4j-api@2.0.11\"\n        }\n      ]\n    },\n    {\n      \"name\": \"snakeyaml\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-snakeyaml-f4585c65c0a5b26a\",\n      \"versionInfo\": \"2.2\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:snakeyaml:snakeyaml:2.2:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:yaml:snakeyaml:2.2:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.yaml/snakeyaml@2.2\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-aop\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-aop-1e7758a78bbc15ee\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"b02165904562fc487cde57ca75e063561d905f74\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-aop@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-beans\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-beans-bb7e773a923726bb\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"fa8be0f856958fdd33eef9e718b3a65f7130bbd2\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-beans@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-a11948291446c2f5\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d882660ea3deafe921faba8b17e7d94ef9556c47\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-actuator\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-actuator-f83d629168e25cce\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d0d018780795da57afa8edae7436646bccd55722\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-actuator-autoconfigure\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-actuator-autoconfigure-b8eb893518786bb8\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"8b8f74be822e6f2ab120ea0687acf629ef114399\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-autoconfigure\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-autoconfigure-b40bdc90eb8832a3\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"31a960bb63af836f35760077af8ef58d24b548e3\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-boot-jarmode-layertools\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-boot-jarmode-layertools-8069f3f866b2e657\",\n      \"versionInfo\": \"3.3.0-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"d86f1782ad3d9ee047863a5023aaa22f858cd9a4\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode-layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode_layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot-jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot_jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework.boot/spring-boot-jarmode-layertools@3.3.0-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-context\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-context-3d5d71e0e85398af\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"75440f70a649ca15948af5923ebdef345848a856\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-context@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-core-519fe54307d2d43d\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"27d0900a14e240a7311c979e7b30cf65f9de9074\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource-spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource_spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:pivotal_software:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springsource:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:vmware:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-core@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-expression\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-expression-546794e924e39088\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"a5d7041ca11fd188e9d17ac8a795eabed8be55e4\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-expression@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-jcl\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-jcl-173ea637a5756944\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"604cea28d23d8027a31c35f372d2b8d0fdec211d\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-jcl@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-web\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-web-adc63cefcede34fc\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"c0600dcd73db226c3d121af16d6a155ecee08d30\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-web@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring-webmvc\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-spring-webmvc-940aed7082581b67\",\n      \"versionInfo\": \"6.1.4-SNAPSHOT\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"34a510cf565bec1c2f74f049b1730b22f877bd37\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"Apache-2.0 AND BSD-3-Clause\",\n      \"licenseDeclared\": \"NOASSERTION\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:springframework:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring-webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring_webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:spring:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.springframework/spring-webmvc@6.1.4-SNAPSHOT\"\n        }\n      ]\n    },\n    {\n      \"name\": \"tomcat-embed-core\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-tomcat-embed-core-a753aca6ee68c738\",\n      \"versionInfo\": \"10.1.18\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"bff6c34649d1dd7b509e819794d73ba795947dcf\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat-embed-core:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat_embed_core:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.18\"\n        }\n      ]\n    },\n    {\n      \"name\": \"tomcat-embed-el\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-tomcat-embed-el-7a59d22722f7701b\",\n      \"versionInfo\": \"10.1.18\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"b2c4dc05abd363c63b245523bb071727aa2f1046\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat-embed-el:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat_embed_el:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.18\"\n        }\n      ]\n    },\n    {\n      \"name\": \"tomcat-embed-websocket\",\n      \"SPDXID\": \"SPDXRef-Package-java-archive-tomcat-embed-websocket-6c04f8ee22f9157e\",\n      \"versionInfo\": \"10.1.18\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"83a3bc6898f2ceed2357ba231a5e83dc2016d454\"\n        }\n      ],\n      \"sourceInfo\": \"acquired package info from installed java archive: /sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"licenseDeclared\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"copyrightText\": \"NOASSERTION\",\n      \"externalRefs\": [\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat-embed-websocket:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat_embed_websocket:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"SECURITY\",\n          \"referenceType\": \"cpe23Type\",\n          \"referenceLocator\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\"\n        },\n        {\n          \"referenceCategory\": \"PACKAGE-MANAGER\",\n          \"referenceType\": \"purl\",\n          \"referenceLocator\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.18\"\n        }\n      ]\n    },\n    {\n      \"name\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"SPDXID\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"versionInfo\": \"sha256:f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\",\n      \"supplier\": \"NOASSERTION\",\n      \"downloadLocation\": \"NOASSERTION\",\n      \"filesAnalyzed\": false,\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA256\",\n          \"checksumValue\": \"f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\"\n        }\n      ],\n      \"primaryPackagePurpose\": \"FILE\"\n    }\n  ],\n  \"files\": [\n    {\n      \"fileName\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"SPDXID\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"checksums\": [\n        {\n          \"algorithm\": \"SHA1\",\n          \"checksumValue\": \"0000000000000000000000000000000000000000\"\n        }\n      ],\n      \"licenseConcluded\": \"NOASSERTION\",\n      \"copyrightText\": \"\"\n    }\n  ],\n  \"hasExtractedLicensingInfos\": [\n    {\n      \"licenseId\": \"LicenseRef-85a9a90b97292e5203565dd71a1a086ca3fe4d8ccea74453294fee37d5b0c7ae\",\n      \"extractedText\": \"http://www.eclipse.org/legal/epl-2.0, https://www.gnu.org/software/classpath/license.html\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-Public-Domain--per-Creative-Commons-CC0\",\n      \"extractedText\": \"Public Domain, per Creative Commons CC0\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-b997c307e688e15a53c7603c100d346cb7dc9726146cb5644d66bddc7ed1c8ca\",\n      \"extractedText\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-bc2074dd7e94ae9ffbcea3c53de6625b1b651c330895f46cf72d207c3025b98b\",\n      \"extractedText\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-d509473237fa971bc0a8ad7708f3cd561fcf86ef2e611701ed8eec621fd6575e\",\n      \"extractedText\": \"http://creativecommons.org/publicdomain/zero/1.0/, https://opensource.org/licenses/BSD-2-Clause\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-http---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"extractedText\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-http---www.opensource.org-licenses-mit-license.php\",\n      \"extractedText\": \"http://www.opensource.org/licenses/mit-license.php\"\n    },\n    {\n      \"licenseId\": \"LicenseRef-https---www.apache.org-licenses-LICENSE-2.0.txt\",\n      \"extractedText\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n    }\n  ],\n  \"relationships\": [\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-core-0408f25059f495c5\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-datatype-jsr310-1347581c05f302c0\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-jcl-173ea637a5756944\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-aop-1e7758a78bbc15ee\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-observation-26b8a84479010ca8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-HdrHistogram-2c7953c2c68ec3bc\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-logback-core-3748310e1aac44ea\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-core-3c0d8567351e2ae4\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-context-3d5d71e0e85398af\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-slf4j-api-44752cfa6770756d\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-core-519fe54307d2d43d\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-expression-546794e924e39088\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jul-to-slf4j-598311f4a5b2a501\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-tomcat-embed-websocket-6c04f8ee22f9157e\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jakarta.annotation-api-77a5bf527533d628\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-tomcat-embed-el-7a59d22722f7701b\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-jarmode-layertools-8069f3f866b2e657\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-datatype-jdk8-846731ed2e85561c\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-log4j-to-slf4j-860f45be6a175d16\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-sbom-test-gradle-93ed082a147d9796\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-webmvc-940aed7082581b67\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-databind-9ad3756f611d1ed2\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-a11948291446c2f5\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-tomcat-embed-core-a753aca6ee68c738\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-web-adc63cefcede34fc\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-autoconfigure-b40bdc90eb8832a3\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-actuator-autoconfigure-b8eb893518786bb8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-beans-bb7e773a923726bb\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-annotations-c1e7975b6f55f7e8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-log4j-api-c404b33d3a8ce0d8\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-commons-c46f369578c77c43\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-logback-classic-d91fe3ae6bb15cad\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-snakeyaml-f4585c65c0a5b26a\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-micrometer-jakarta9-f4ea2c844b65a026\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-jackson-module-parameter-names-f5bca9d628ab321f\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-spring-boot-actuator-f83d629168e25cce\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-Package-java-archive-LatencyUtils-f9418986cc24a153\",\n      \"relatedSpdxElement\": \"SPDXRef-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar-af7261c65fbd5345\",\n      \"relationshipType\": \"OTHER\",\n      \"comment\": \"evident-by: indicates the package's existence is evident by the given file\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-HdrHistogram-2c7953c2c68ec3bc\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-LatencyUtils-f9418986cc24a153\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-annotations-c1e7975b6f55f7e8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-core-0408f25059f495c5\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-databind-9ad3756f611d1ed2\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-datatype-jdk8-846731ed2e85561c\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-datatype-jsr310-1347581c05f302c0\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jackson-module-parameter-names-f5bca9d628ab321f\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jakarta.annotation-api-77a5bf527533d628\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-jul-to-slf4j-598311f4a5b2a501\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-log4j-api-c404b33d3a8ce0d8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-log4j-to-slf4j-860f45be6a175d16\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-logback-classic-d91fe3ae6bb15cad\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-logback-core-3748310e1aac44ea\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-commons-c46f369578c77c43\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-core-3c0d8567351e2ae4\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-jakarta9-f4ea2c844b65a026\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-micrometer-observation-26b8a84479010ca8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-sbom-test-gradle-93ed082a147d9796\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-slf4j-api-44752cfa6770756d\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-snakeyaml-f4585c65c0a5b26a\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-aop-1e7758a78bbc15ee\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-beans-bb7e773a923726bb\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-a11948291446c2f5\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-actuator-f83d629168e25cce\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-actuator-autoconfigure-b8eb893518786bb8\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-autoconfigure-b40bdc90eb8832a3\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-boot-jarmode-layertools-8069f3f866b2e657\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-context-3d5d71e0e85398af\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-core-519fe54307d2d43d\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-expression-546794e924e39088\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-jcl-173ea637a5756944\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-web-adc63cefcede34fc\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-spring-webmvc-940aed7082581b67\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-tomcat-embed-core-a753aca6ee68c738\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-tomcat-embed-el-7a59d22722f7701b\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relatedSpdxElement\": \"SPDXRef-Package-java-archive-tomcat-embed-websocket-6c04f8ee22f9157e\",\n      \"relationshipType\": \"CONTAINS\"\n    },\n    {\n      \"spdxElementId\": \"SPDXRef-DOCUMENT\",\n      \"relatedSpdxElement\": \"SPDXRef-DocumentRoot-File-sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"relationshipType\": \"DESCRIBES\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/test/resources/org/springframework/boot/actuate/sbom/syft.json",
    "content": "{\n  \"artifacts\": [\n    {\n      \"id\": \"2c7953c2c68ec3bc\",\n      \"name\": \"HdrHistogram\",\n      \"version\": \"2.1.12\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/HdrHistogram-2.1.12.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://creativecommons.org/publicdomain/zero/1.0/, https://opensource.org/licenses/BSD-2-Clause\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/HdrHistogram-2.1.12.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:HdrHistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:hdrhistogram:HdrHistogram:2.1.12:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/HdrHistogram-2.1.12.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1575980548657\"\n            },\n            {\n              \"key\": \"Build-Jdk\",\n              \"value\": \"1.8.0_232\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"gil\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"HdrHistogram supports the recording and analyzing sampled data value        counts across a configurable integer value range with configurable value        precision within the range. Value precision is expressed as the number of        significant digits in the value recording, and provides control over value        quantization behavior across the value range and the subsequent value        resolutionat any given level.\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://creativecommons.org/publicdomain/zero/1.0/, https://opensource.org/licenses/BSD-2-Clause\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"HdrHistogram\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.hdrhistogram.HdrHistogram\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.1.12\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.HdrHistogram;version=\\\"2.1.12\\\",org.HdrHistogram.packedarray;version=\\\"2.1.12\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"HdrHistogram\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"org.hdrhistogram\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.1.12\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.7))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"HdrHistogram\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.1.12\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-2.3.0.201405100607\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.hdrhistogram/HdrHistogram/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.hdrhistogram\",\n          \"artifactId\": \"HdrHistogram\",\n          \"version\": \"2.1.12\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f9418986cc24a153\",\n      \"name\": \"LatencyUtils\",\n      \"version\": \"2.0.3\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/LatencyUtils-2.0.3.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Public Domain, per Creative Commons CC0\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [\n            \"http://creativecommons.org/publicdomain/zero/1.0/\"\n          ],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/LatencyUtils-2.0.3.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:LatencyUtils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:latencyutils:LatencyUtils:2.0.3:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/LatencyUtils-2.0.3.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Archiver-Version\",\n              \"value\": \"Plexus Archiver\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"gil\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven 3.2.3\"\n            },\n            {\n              \"key\": \"Build-Jdk\",\n              \"value\": \"1.8.0_45\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.latencyutils/LatencyUtils/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.latencyutils\",\n          \"artifactId\": \"LatencyUtils\",\n          \"version\": \"2.0.3\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"c1e7975b6f55f7e8\",\n      \"name\": \"jackson-annotations\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-annotations-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-annotations-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_annotations:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_annotations:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-annotations:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_annotations:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson-annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson_annotations:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-annotations-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Core annotations used for value types, used by Jackson data binding package.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson-annotations\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.core.jackson-annotations\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.core\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson-annotations\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.6))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"2.16.1\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson-annotations\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.6\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.6\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.core/jackson-annotations/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.core\",\n          \"artifactId\": \"jackson-annotations\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"fd441d574a71e7d10a4f73de6609f881d8cdfeec\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"0408f25059f495c5\",\n      \"name\": \"jackson-core\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-core-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-core-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson-core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson_core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-core:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_core:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:core:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-core-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.core.jackson-core\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.core\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson-core\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-core\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.async;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.base;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.exc;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.format;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io.schubfach;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.json;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.json.async;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.sym;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.core;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core.async,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.format,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.json,com.fasterxml.jackson.core.sym,com.fasterxml.jackson.core.type,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.async;version=\\\"2.16.1\\\",com.fasterxml.jackson.core.base;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.json,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.exc;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.filter;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.format;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core\\\",com.fasterxml.jackson.core.io;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.io.schubfach;version=\\\"2.16.1\\\",com.fasterxml.jackson.core.json;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.format,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.sym,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.json.async;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.async,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.sym,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.sym;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.util\\\",com.fasterxml.jackson.core.type;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core\\\",com.fasterxml.jackson.core.util;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.async,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.io\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson-core\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Core Jackson processing abstractions (aka Streaming API), implementation for JSON\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson-core\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.core/jackson-core/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.core\",\n          \"artifactId\": \"jackson-core\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"9456bb3cdd0f79f91a5f730a1b1bb041a380c91f\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"9ad3756f611d1ed2\",\n      \"name\": \"jackson-databind\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-databind-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-databind-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_databind:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_databind:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-databind:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_databind:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson-databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson_databind:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:core:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-databind-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.core.jackson-databind\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.core\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"jackson-databind\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.base;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.exc;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.filter;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.format;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.json;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.exc;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ext;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.introspect;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jdk14;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.json;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonschema;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.node;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util.internal;version=\\\"[2.16,3)\\\",javax.xml.datatype,javax.xml.namespace,javax.xml.parsers,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.w3c.dom,org.xml.sax,org.w3c.dom.bootstrap;resolution:=optional\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.databind;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.exc,com.fasterxml.jackson.core.filter,com.fasterxml.jackson.core.format,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.type,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.impl,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsonschema,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.jsontype.impl,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.annotation;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.cfg;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.deser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.format,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser.impl,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.deser.impl;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.impl,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.exc;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.introspect\\\",com.fasterxml.jackson.databind.ext;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.std,javax.xml.datatype,javax.xml.parsers,javax.xml.transform,org.w3c.dom\\\",com.fasterxml.jackson.databind.introspect;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.jsontype.impl,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.jdk14;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect\\\",com.fasterxml.jackson.databind.json;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.json,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind\\\",com.fasterxml.jackson.databind.jsonschema;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.node\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect\\\",com.fasterxml.jackson.databind.jsontype.impl;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.module;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.type\\\",com.fasterxml.jackson.databind.node;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.ser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.io,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsonschema,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.ser.impl;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.io,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.annotation,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsonschema,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.node,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.type;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.type,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.util\\\",com.fasterxml.jackson.databind.util;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.base,com.fasterxml.jackson.core.io,com.fasterxml.jackson.core.json,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util.internal\\\",com.fasterxml.jackson.databind.util.internal;version=\\\"2.16.1\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"jackson-databind\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"General data-binding functionality for Jackson: works on core streaming API\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"jackson-databind\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.core/jackson-databind/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.core\",\n          \"artifactId\": \"jackson-databind\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"02a16efeb840c45af1e2f31753dfe76795278b73\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"846731ed2e85561c\",\n      \"name\": \"jackson-datatype-jdk8\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jdk8:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-datatype-jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_datatype_jdk8:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jdk8:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jdk8-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.datatype.jackson-datatype-jdk8\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.datatype\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson datatype: jdk8\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.impl;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.datatype.jdk8;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.io,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.deser.std,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser,com.fasterxml.jackson.databind.ser.impl,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.databind.util\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson datatype: jdk8\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Add-on module for Jackson (http://jackson.codehaus.org) to supportJDK 8 data types.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson datatype: jdk8\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.datatype\",\n          \"artifactId\": \"jackson-datatype-jdk8\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"695d9b8639cfc7a42a0507708cef2366fe492a44\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"1347581c05f302c0\",\n      \"name\": \"jackson-datatype-jsr310\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype-jsr310:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-datatype-jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_datatype_jsr310:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype_jsr310:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:datatype:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-datatype-jsr310-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.datatype.jackson-datatype-jsr310\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.datatype\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson datatype: JSR310\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.io;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.deser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.introspect;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsonFormatVisitors;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.jsontype;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.module;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.node;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.ser.std;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.type;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.deser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.deser.key;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.ser;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.ser.key;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.datatype.jsr310.util;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.datatype.jsr310;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.module\\\",com.fasterxml.jackson.datatype.jsr310.deser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.core.util,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.deser,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.type,com.fasterxml.jackson.datatype.jsr310,com.fasterxml.jackson.datatype.jsr310.util\\\",com.fasterxml.jackson.datatype.jsr310.deser.key;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.databind\\\",com.fasterxml.jackson.datatype.jsr310.ser;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.jsonFormatVisitors,com.fasterxml.jackson.databind.jsontype,com.fasterxml.jackson.databind.ser.std,com.fasterxml.jackson.datatype.jsr310.util\\\",com.fasterxml.jackson.datatype.jsr310.ser.key;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.core,com.fasterxml.jackson.databind\\\",com.fasterxml.jackson.datatype.jsr310.util;version=\\\"2.16.1\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson datatype: JSR310\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Add-on module to support JSR-310 (Java 8 Date & Time API) data types.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson datatype: JSR310\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.datatype\",\n          \"artifactId\": \"jackson-datatype-jsr310\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"36a418325c618e440e5ccb80b75c705d894f50bd\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f5bca9d628ab321f\",\n      \"name\": \"jackson-module-parameter-names\",\n      \"version\": \"2.16.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter-names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter-names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter_names:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter_names:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter-names:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter_names:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:module:jackson-module-parameter-names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:module:jackson_module_parameter_names:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module-parameter:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module_parameter:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson-module:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson_module:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:fasterxml:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jackson:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:module:jackson:2.16.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.16.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jackson-module-parameter-names-2.16.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"com.fasterxml.jackson.module.jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"com.fasterxml.jackson.module\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.fasterxml.jackson.annotation;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.core.util;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.cfg;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.introspect;version=\\\"[2.16,3)\\\",com.fasterxml.jackson.databind.module;version=\\\"[2.16,3)\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"com.fasterxml.jackson.module.paramnames;version=\\\"2.16.1\\\";uses:=\\\"com.fasterxml.jackson.annotation,com.fasterxml.jackson.core,com.fasterxml.jackson.databind,com.fasterxml.jackson.databind.cfg,com.fasterxml.jackson.databind.introspect,com.fasterxml.jackson.databind.module\\\"\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Add-on module for Jackson (http://jackson.codehaus.org) to supportintrospection of method/constructor parameter names,without having to add explicit property name annotation.\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Jackson-module-parameter-names\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"FasterXML\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.16.1\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.16.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/com.fasterxml.jackson.module/jackson-module-parameter-names/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"com.fasterxml.jackson.module\",\n          \"artifactId\": \"jackson-module-parameter-names\",\n          \"version\": \"2.16.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"9e167afd1596e6a6aa6fe4e1af17f4ce8be0676f\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"77a5bf527533d628\",\n      \"name\": \"jakarta.annotation-api\",\n      \"version\": \"2.1.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.eclipse.org/legal/epl-2.0, https://www.gnu.org/software/classpath/license.html\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation-api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation_api:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse-foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:eclipse_foundation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jakarta.annotation:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:glassfish:jakarta.annotation-api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:glassfish:jakarta.annotation_api:2.1.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"Jakarta Annotations API\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"https://www.eclipse.org\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.eclipse.org/legal/epl-2.0, https://www.gnu.org/software/classpath/license.html\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Jakarta Annotations API\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"jakarta.annotation-api\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"Eclipse Foundation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.1.1\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.annotation;version=\\\"2.1.1\\\",jakarta.annotation.security;version=\\\"2.1.1\\\",jakarta.annotation.sql;version=\\\"2.1.1\\\"\"\n            },\n            {\n              \"key\": \"Extension-Name\",\n              \"value\": \"jakarta.annotation\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Eclipse Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Vendor-Id\",\n              \"value\": \"org.glassfish\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.1.1\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Eclipse Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.1\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/jakarta.annotation/jakarta.annotation-api/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"jakarta.annotation\",\n          \"artifactId\": \"jakarta.annotation-api\",\n          \"version\": \"2.1.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"598311f4a5b2a501\",\n      \"name\": \"jul-to-slf4j\",\n      \"version\": \"2.0.11\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jul-to-slf4j-2.0.11.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.opensource.org/licenses/mit-license.php\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jul-to-slf4j-2.0.11.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to-slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to-slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to_slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to_slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul-to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul_to:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul:jul-to-slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:jul:jul_to_slf4j:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.11\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/jul-to-slf4j-2.0.11.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"JUL to SLF4J bridge\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.slf4j.org\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.opensource.org/licenses/mit-license.php\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"JUL to SLF4J bridge\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"jul.to.slf4j\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"SLF4J.ORG\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.slf4j.bridge;uses:=\\\"org.slf4j,org.slf4j.spi\\\";version=\\\"2.0.11\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"jul-to-slf4j\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.slf4j;version=\\\"[2.0,3)\\\",org.slf4j.spi;version=\\\"[2.0,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"8\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.slf4j/jul-to-slf4j/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.slf4j\",\n          \"artifactId\": \"jul-to-slf4j\",\n          \"version\": \"2.0.11\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"279356f8e873b1a26badd8bbb3284b5c3b22c770\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"c404b33d3a8ce0d8\",\n      \"name\": \"log4j-api\",\n      \"version\": \"2.22.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-api-2.22.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-api-2.22.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j-api:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j_api:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:api:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.logging.log4j/log4j-api@2.22.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-api-2.22.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Maven JAR Plugin 3.3.0\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Log4j API\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.22\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Log4j API\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-ActivationPolicy\",\n              \"value\": \"lazy\"\n            },\n            {\n              \"key\": \"Bundle-Activator\",\n              \"value\": \"org.apache.logging.log4j.util.Activator\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"The Apache Log4j API\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Apache Log4j API\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.logging.log4j.api\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.apache.logging.log4j;version=\\\"2.20.2\\\";uses:=\\\"org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.apache.logging.log4j.util\\\",org.apache.logging.log4j.message;version=\\\"2.22.0\\\";uses:=\\\"org.apache.logging.log4j.util\\\",org.apache.logging.log4j.simple;version=\\\"2.20.2\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.apache.logging.log4j.util\\\",org.apache.logging.log4j.spi;version=\\\"2.20.1\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.util\\\",org.apache.logging.log4j.status;version=\\\"2.20.2\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.spi\\\",org.apache.logging.log4j.util;version=\\\"2.22.0\\\";uses:=\\\"org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.osgi.framework\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.apache.logging.log4j.simple;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.status;version=\\\"[2.20,3)\\\",org.osgi.framework;version=\\\"[1.8,2)\\\",org.osgi.framework.wiring;version=\\\"[1.2,2)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.logging.log4j.internal,org.apache.logging.log4j.util.internal\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.service;objectClass:List<String>=\\\"org.apache.logging.log4j.util.PropertySource\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"org.apache.logging.log4j.util.PropertySource\\\";register:=\\\"org.apache.logging.log4j.util.EnvironmentPropertySource\\\",osgi.serviceloader;osgi.serviceloader=\\\"org.apache.logging.log4j.util.PropertySource\\\";register:=\\\"org.apache.logging.log4j.util.SystemPropertiesPropertySource\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.logging.log4j.message.ThreadDumpMessage$ThreadInfoFactory)\\\";osgi.serviceloader=\\\"org.apache.logging.log4j.message.ThreadDumpMessage$ThreadInfoFactory\\\";cardinality:=single;resolution:=optional,osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.logging.log4j.spi.Provider)\\\";osgi.serviceloader=\\\"org.apache.logging.log4j.spi.Provider\\\";cardinality:=multiple;resolution:=optional,osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.logging.log4j.util.PropertySource)\\\";osgi.serviceloader=\\\"org.apache.logging.log4j.util.PropertySource\\\";cardinality:=multiple;resolution:=optional,osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.apache.logging.log4j/log4j-api/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.apache.logging.log4j\",\n          \"artifactId\": \"log4j-api\",\n          \"version\": \"2.22.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"bea6fede6328fabafd7e68363161a7ea6605abd1\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"860f45be6a175d16\",\n      \"name\": \"log4j-to-slf4j\",\n      \"version\": \"2.22.1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-to-slf4j-2.22.1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-to-slf4j-2.22.1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j-to-slf4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j_to_slf4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:log4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:slf4j:2.22.1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.22.1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/log4j-to-slf4j-2.22.1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Maven JAR Plugin 3.3.0\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Log4j to SLF4J Adapter\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"2.22\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Log4j to SLF4J Adapter\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-ActivationPolicy\",\n              \"value\": \"lazy\"\n            },\n            {\n              \"key\": \"Bundle-Activator\",\n              \"value\": \"org.apache.logging.slf4j.Activator\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"The Apache Log4j binding between Log4j 2 API and SLF4J.\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"\\\"Apache-2.0\\\";link=\\\"https://www.apache.org/licenses/LICENSE-2.0.txt\\\"\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Apache Log4j to SLF4J Adapter\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.logging.log4j.to.slf4j\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"The Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.22.1\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.apache.logging.slf4j;version=\\\"2.20.1\\\";uses:=\\\"org.apache.logging.log4j,org.apache.logging.log4j.message,org.apache.logging.log4j.spi,org.apache.logging.log4j.util,org.slf4j\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.slf4j;version=\\\"[1.7,3)\\\",org.slf4j.spi;version=\\\"[1.7,3)\\\",org.apache.logging.log4j;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.message;version=\\\"[2.22,3)\\\",org.apache.logging.log4j.spi;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.status;version=\\\"[2.20,3)\\\",org.apache.logging.log4j.util;version=\\\"[2.22,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"false\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.service;objectClass:List<String>=\\\"org.apache.logging.log4j.spi.Provider\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"org.apache.logging.log4j.spi.Provider\\\";register:=\\\"org.apache.logging.slf4j.SLF4JProvider\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.apache.logging.log4j/log4j-to-slf4j/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.apache.logging.log4j\",\n          \"artifactId\": \"log4j-to-slf4j\",\n          \"version\": \"2.22.1\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"b5e67b6acac768bfec1d1d6991504f45453abcad\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"d91fe3ae6bb15cad\",\n      \"name\": \"logback-classic\",\n      \"version\": \"1.4.14\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-classic-1.4.14.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-classic-1.4.14.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:logback-classic:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback-classic:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_classic:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_classic:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback-classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback_classic:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/ch.qos.logback/logback-classic@1.4.14\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-classic-1.4.14.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Logback Classic Module\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"1.4\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Logback Classic Module\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"logback-classic module\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.qos.ch\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Logback Classic Module\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"ch.qos.logback.classic\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"ch.qos.logback.classic;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.classic.turbo,ch.qos.logback.core,ch.qos.logback.core.pattern,ch.qos.logback.core.spi,ch.qos.logback.core.status,jakarta.servlet.http,org.slf4j,org.slf4j.event,org.slf4j.spi\\\",ch.qos.logback.classic.boolex;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.boolex\\\",ch.qos.logback.classic.db.script;version=\\\"1.4.14\\\",ch.qos.logback.classic.encoder;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.encoder,ch.qos.logback.core.pattern\\\",ch.qos.logback.classic.filter;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core.filter,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.helpers;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core,jakarta.servlet\\\",ch.qos.logback.classic.html;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.html,ch.qos.logback.core.pattern\\\",ch.qos.logback.classic.joran;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core,ch.qos.logback.core.joran,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.joran.action;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,org.xml.sax\\\",ch.qos.logback.classic.joran.sanity;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.sanity,ch.qos.logback.core.model,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.joran.serializedModel;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.net\\\",ch.qos.logback.classic.jul;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core.spi\\\",ch.qos.logback.classic.layout;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core\\\",ch.qos.logback.classic.log4j;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core\\\",ch.qos.logback.classic.model;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model,ch.qos.logback.core.model.processor\\\",ch.qos.logback.classic.model.processor;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.model,ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util,ch.qos.logback.core.model,ch.qos.logback.core.model.processor\\\",ch.qos.logback.classic.model.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model\\\",ch.qos.logback.classic.net;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.spi,ch.qos.logback.core,ch.qos.logback.core.boolex,ch.qos.logback.core.helpers,ch.qos.logback.core.joran.spi,ch.qos.logback.core.net,ch.qos.logback.core.net.ssl,ch.qos.logback.core.pattern,ch.qos.logback.core.spi,javax.net,javax.net.ssl\\\",ch.qos.logback.classic.net.server;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.net,ch.qos.logback.classic.spi,ch.qos.logback.core.net,ch.qos.logback.core.net.server,ch.qos.logback.core.net.ssl,ch.qos.logback.core.spi,javax.net\\\",ch.qos.logback.classic.pattern;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core,ch.qos.logback.core.pattern,org.slf4j\\\",ch.qos.logback.classic.pattern.color;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.pattern.color\\\",ch.qos.logback.classic.selector;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic\\\",ch.qos.logback.classic.selector.servlet;version=\\\"1.4.14\\\";uses:=\\\"jakarta.servlet\\\",ch.qos.logback.classic.servlet;version=\\\"1.4.14\\\";uses:=\\\"jakarta.servlet\\\",ch.qos.logback.classic.sift;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic.spi,ch.qos.logback.core.joran.spi,ch.qos.logback.core.sift\\\",ch.qos.logback.classic.spi;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.turbo,ch.qos.logback.core,ch.qos.logback.core.spi,org.slf4j,org.slf4j.event,org.slf4j.spi\\\",ch.qos.logback.classic.turbo;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.core.spi,org.slf4j\\\",ch.qos.logback.classic.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.classic,ch.qos.logback.classic.selector,ch.qos.logback.classic.spi,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.slf4j.spi\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"ch.qos.logback.classic;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.boolex;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.encoder;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran.action;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran.sanity;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.joran.serializedModel;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.layout;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.model;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.model.processor;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.net;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.net.server;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.pattern;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.pattern.color;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.selector;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.turbo;version=\\\"[1.4,2)\\\",ch.qos.logback.classic.util;version=\\\"[1.4,2)\\\",jakarta.servlet;resolution:=optional;version=\\\"[5.0,6)\\\",jakarta.servlet.http;resolution:=optional;version=\\\"[5.0,6)\\\",org.xml.sax;resolution:=optional,ch.qos.logback.core;version=\\\"[1.4,2)\\\",ch.qos.logback.core.boolex;version=\\\"[1.4,2)\\\",ch.qos.logback.core.encoder;version=\\\"[1.4,2)\\\",ch.qos.logback.core.filter;version=\\\"[1.4,2)\\\",ch.qos.logback.core.helpers;version=\\\"[1.4,2)\\\",ch.qos.logback.core.html;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.action;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.sanity;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.processor;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net.server;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net.ssl;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.color;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.parser;version=\\\"[1.4,2)\\\",ch.qos.logback.core.sift;version=\\\"[1.4,2)\\\",ch.qos.logback.core.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.status;version=\\\"[1.4,2)\\\",ch.qos.logback.core.util;version=\\\"[1.4,2)\\\",java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.reflect,java.net,java.nio.charset,java.security,java.text,java.time,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.function,java.util.logging,java.util.regex,javax.management,javax.naming,javax.net,javax.net.ssl,org.slf4j;version=\\\"[2.0,3)\\\",org.slf4j.event;version=\\\"[2.0,3)\\\",org.slf4j.helpers;version=\\\"[2.0,3)\\\",org.slf4j.spi;version=\\\"[2.0,3)\\\",sun.reflect;resolution:=optional,ch.qos.logback.core.rolling;version=\\\"[1.4,2)\\\",ch.qos.logback.core.rolling.helper;version=\\\"[1.4,2)\\\",ch.qos.logback.core.read;version=\\\"[1.4,2)\\\"\"\n            },\n            {\n              \"key\": \"Originally-Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.service;objectClass:List<String>=\\\"jakarta.servlet.ServletContainerInitializer\\\";effective:=active,osgi.service;objectClass:List<String>=\\\"org.slf4j.spi.SLF4JServiceProvider\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"jakarta.servlet.ServletContainerInitializer\\\";register:=\\\"ch.qos.logback.classic.servlet.LogbackServletContainerInitializer\\\",osgi.serviceloader;osgi.serviceloader=\\\"org.slf4j.spi.SLF4JServiceProvider\\\";register:=\\\"ch.qos.logback.classic.spi.LogbackServiceProvider\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\";resolution:=optional,osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=ch.qos.logback.classic.spi.Configurator)\\\";osgi.serviceloader=\\\"ch.qos.logback.classic.spi.Configurator\\\";resolution:=optional;cardinality:=multiple,osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=11))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/ch.qos.logback/logback-classic/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"ch.qos.logback\",\n          \"artifactId\": \"logback-classic\",\n          \"version\": \"1.4.14\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"3748310e1aac44ea\",\n      \"name\": \"logback-core\",\n      \"version\": \"1.4.14\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-core-1.4.14.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-core-1.4.14.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:logback-core:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback-core:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_core:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback_core:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:logback:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos-ch:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback-core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:qos_ch:logback_core:1.4.14:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/ch.qos.logback/logback-core@1.4.14\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/logback-core-1.4.14.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Logback Core Module\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"1.4\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Logback Core Module\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"logback-core module\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.qos.ch\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.eclipse.org/legal/epl-v10.html, http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"Logback Core Module\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"ch.qos.logback.core\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"QOS.ch\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.4.14\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"ch.qos.logback.core;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.encoder,ch.qos.logback.core.filter,ch.qos.logback.core.helpers,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,ch.qos.logback.core.status,ch.qos.logback.core.util\\\",ch.qos.logback.core.boolex;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.spi\\\",ch.qos.logback.core.encoder;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.spi\\\",ch.qos.logback.core.filter;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.boolex,ch.qos.logback.core.spi\\\",ch.qos.logback.core.helpers;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.hook;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.html;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.pattern\\\",ch.qos.logback.core.joran;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.event,ch.qos.logback.core.joran.sanity,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util.beans,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,org.xml.sax\\\",ch.qos.logback.core.joran.action;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,ch.qos.logback.core.util,org.xml.sax\\\",ch.qos.logback.core.joran.conditional;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,ch.qos.logback.core.spi,org.codehaus.commons.compiler,org.xml.sax\\\",ch.qos.logback.core.joran.event;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.xml.sax,org.xml.sax.helpers\\\",ch.qos.logback.core.joran.event.stax;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,javax.xml.stream,javax.xml.stream.events\\\",ch.qos.logback.core.joran.node;version=\\\"1.4.14\\\",ch.qos.logback.core.joran.sanity;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model,ch.qos.logback.core.spi\\\",ch.qos.logback.core.joran.spi;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.event,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,ch.qos.logback.core.status,org.xml.sax\\\",ch.qos.logback.core.joran.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util.beans,ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.joran.util.beans;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.spi\\\",ch.qos.logback.core.layout;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.model;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.action,ch.qos.logback.core.model.processor\\\",ch.qos.logback.core.model.conditional;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model\\\",ch.qos.logback.core.model.processor;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.action,ch.qos.logback.core.joran.spi,ch.qos.logback.core.joran.util.beans,ch.qos.logback.core.model,ch.qos.logback.core.spi\\\",ch.qos.logback.core.model.processor.conditional;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.model,ch.qos.logback.core.model.conditional,ch.qos.logback.core.model.processor\\\",ch.qos.logback.core.model.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.model\\\",ch.qos.logback.core.net;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.boolex,ch.qos.logback.core.helpers,ch.qos.logback.core.net.ssl,ch.qos.logback.core.pattern,ch.qos.logback.core.sift,ch.qos.logback.core.spi,ch.qos.logback.core.util,jakarta.mail,jakarta.mail.internet,javax.net\\\",ch.qos.logback.core.net.server;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.net.ssl,ch.qos.logback.core.spi,javax.net\\\",ch.qos.logback.core.net.ssl;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.joran.spi,ch.qos.logback.core.spi,javax.net,javax.net.ssl\\\",ch.qos.logback.core.pattern;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.encoder,ch.qos.logback.core.spi,ch.qos.logback.core.status\\\",ch.qos.logback.core.pattern.color;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.pattern\\\",ch.qos.logback.core.pattern.parser;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.pattern,ch.qos.logback.core.pattern.util,ch.qos.logback.core.spi\\\",ch.qos.logback.core.pattern.util;version=\\\"1.4.14\\\",ch.qos.logback.core.property;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.read;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core\\\",ch.qos.logback.core.recovery;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.status\\\",ch.qos.logback.core.rolling;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.rolling.helper,ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.rolling.helper;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.pattern,ch.qos.logback.core.rolling,ch.qos.logback.core.spi\\\",ch.qos.logback.core.sift;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.joran.spi,ch.qos.logback.core.model,ch.qos.logback.core.model.processor,ch.qos.logback.core.spi,ch.qos.logback.core.util\\\",ch.qos.logback.core.spi;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.filter,ch.qos.logback.core.helpers,ch.qos.logback.core.status\\\",ch.qos.logback.core.status;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.spi,jakarta.servlet,jakarta.servlet.http\\\",ch.qos.logback.core.subst;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core.spi\\\",ch.qos.logback.core.testUtil;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.encoder,ch.qos.logback.core.read,ch.qos.logback.core.spi,ch.qos.logback.core.status,javax.naming,javax.naming.spi\\\",ch.qos.logback.core.util;version=\\\"1.4.14\\\";uses:=\\\"ch.qos.logback.core,ch.qos.logback.core.rolling,ch.qos.logback.core.rolling.helper,ch.qos.logback.core.spi,ch.qos.logback.core.status,javax.naming\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"ch.qos.logback.core;version=\\\"[1.4,2)\\\",ch.qos.logback.core.boolex;version=\\\"[1.4,2)\\\",ch.qos.logback.core.encoder;version=\\\"[1.4,2)\\\",ch.qos.logback.core.filter;version=\\\"[1.4,2)\\\",ch.qos.logback.core.helpers;version=\\\"[1.4,2)\\\",ch.qos.logback.core.hook;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.action;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.event;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.sanity;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.joran.util.beans;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.processor;version=\\\"[1.4,2)\\\",ch.qos.logback.core.model.processor.conditional;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net;version=\\\"[1.4,2)\\\",ch.qos.logback.core.net.ssl;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.parser;version=\\\"[1.4,2)\\\",ch.qos.logback.core.pattern.util;version=\\\"[1.4,2)\\\",ch.qos.logback.core.read;version=\\\"[1.4,2)\\\",ch.qos.logback.core.recovery;version=\\\"[1.4,2)\\\",ch.qos.logback.core.rolling;version=\\\"[1.4,2)\\\",ch.qos.logback.core.rolling.helper;version=\\\"[1.4,2)\\\",ch.qos.logback.core.sift;version=\\\"[1.4,2)\\\",ch.qos.logback.core.spi;version=\\\"[1.4,2)\\\",ch.qos.logback.core.status;version=\\\"[1.4,2)\\\",ch.qos.logback.core.subst;version=\\\"[1.4,2)\\\",ch.qos.logback.core.util;version=\\\"[1.4,2)\\\",jakarta.mail;resolution:=optional;version=\\\"[2.1,3)\\\",jakarta.mail.internet;resolution:=optional;version=\\\"[2.1,3)\\\",jakarta.servlet;resolution:=optional;version=\\\"[5.0,6)\\\",jakarta.servlet.http;resolution:=optional;version=\\\"[5.0,6)\\\",org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,org.codehaus.janino;resolution:=optional;version=\\\"[3.1,4)\\\",org.codehaus.commons.compiler;resolution:=optional;version=\\\"[3.1,4)\\\",java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.module,java.lang.reflect,java.math,java.net,java.nio,java.nio.channels,java.nio.charset,java.nio.file,java.security,java.security.cert,java.text,java.time,java.time.format,java.time.temporal,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,java.util.function,java.util.regex,java.util.stream,java.util.zip,javax.naming,javax.naming.spi,javax.net,javax.net.ssl,javax.xml.namespace,javax.xml.parsers,javax.xml.stream,javax.xml.stream.events,org.fusesource.jansi;resolution:=optional;version=\\\"[2.4,3)\\\"\"\n            },\n            {\n              \"key\": \"Originally-Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=11))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/ch.qos.logback/logback-core/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"ch.qos.logback\",\n          \"artifactId\": \"logback-core\",\n          \"version\": \"1.4.14\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"c46f369578c77c43\",\n      \"name\": \"micrometer-commons\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_commons:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_commons:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_commons:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-commons@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-commons-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.commons\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769856136\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.169807141Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-commons\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-commons\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"DynamicImport-Package\",\n              \"value\": \"org.aspectj.lang,org.aspectj.lang.reflect\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.common;uses:=\\\"io.micrometer.common.docs,io.micrometer.common.lang\\\";version=\\\"1.13.0\\\",io.micrometer.common.annotation;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,org.aspectj.lang\\\";version=\\\"1.13.0\\\",io.micrometer.common.docs;uses:=\\\"io.micrometer.common\\\";version=\\\"1.13.0\\\",io.micrometer.common.lang;uses:=\\\"javax.annotation,javax.annotation.meta\\\";version=\\\"1.13.0\\\",io.micrometer.common.util;uses:=\\\"io.micrometer.common.lang\\\";version=\\\"1.13.0\\\",io.micrometer.common.util.internal.logging;version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-commons;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"io.micrometer.common,io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.common.util.internal.logging,javax.annotation;version=\\\"[3.0,4)\\\",javax.annotation.meta;version=\\\"[3.0,4)\\\",org.slf4j;version=\\\"[1.7,2)\\\",org.slf4j.helpers;version=\\\"[1.7,2)\\\",org.slf4j.spi;version=\\\"[1.7,2)\\\"\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-commons\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"e738daf6678eedf8e0c40a782bdb0df064a391e5\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"3c0d8567351e2ae4\",\n      \"name\": \"micrometer-core\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-core-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-core-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_core:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_core:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_core:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-core@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-core-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.core\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769876578\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.236904273Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-core\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-core\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"DynamicImport-Package\",\n              \"value\": \"org.aspectj.lang,org.aspectj.lang.annotation,org.aspectj.lang.reflect,com.github.benmanes.caffeine.cache;version=\\\"2.9.3\\\",com.github.benmanes.caffeine.cache.stats;version=\\\"2.9.3\\\",net.sf.ehcache;version=\\\"2.10.9\\\",net.sf.ehcache.statistics;version=\\\"2.10.9\\\",javax.cache;version=\\\"1.1.1\\\",org.hibernate;version=\\\"5.6.15.Final\\\",org.hibernate.engine.spi;version=\\\"5.6.15.Final\\\",org.hibernate.event.service.spi;version=\\\"5.6.15.Final\\\",org.hibernate.event.spi;version=\\\"5.6.15.Final\\\",org.hibernate.service;version=\\\"5.6.15.Final\\\",org.hibernate.service.spi;version=\\\"5.6.15.Final\\\",org.hibernate.stat;version=\\\"5.6.15.Final\\\",org.hibernate.stat.spi;version=\\\"5.6.15.Final\\\",org.eclipse.jetty.client.api;version=\\\"9.4.53\\\",org.eclipse.jetty.http;version=\\\"9.4.53\\\",org.eclipse.jetty.io;version=\\\"9.4.53\\\",org.eclipse.jetty.io.ssl;version=\\\"9.4.53\\\",org.eclipse.jetty.server;version=\\\"9.4.53\\\",org.eclipse.jetty.server.handler;version=\\\"9.4.53\\\",org.eclipse.jetty.util;version=\\\"9.4.53\\\",org.eclipse.jetty.util.component;version=\\\"9.4.53\\\",org.eclipse.jetty.util.thread;version=\\\"9.4.53\\\",org.glassfish.jersey.server;version=\\\"2.41\\\",org.glassfish.jersey.server.model;version=\\\"2.41\\\",org.glassfish.jersey.server.monitoring;version=\\\"2.41\\\",org.glassfish.jersey.uri;version=\\\"2.41\\\",io.grpc,io.grpc.kotlin,org.apache.hc.client5.http,org.apache.hc.client5.http.async,org.apache.hc.client5.http.classic,org.apache.hc.client5.http.protocol,org.apache.hc.core5.concurrent,org.apache.hc.core5.http,org.apache.hc.core5.http.impl,org.apache.hc.core5.http.impl.io,org.apache.hc.core5.http.io,org.apache.hc.core5.http.nio,org.apache.hc.core5.http.protocol,org.apache.hc.core5.pool,org.apache.hc.core5.util,org.apache.http,org.apache.http.conn.routing,org.apache.http.pool,org.apache.http.protocol,com.netflix.hystrix;version=\\\"1.5.12\\\",com.netflix.hystrix.metric;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.concurrency;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.eventnotifier;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.executionhook;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.metrics;version=\\\"1.5.12\\\",com.netflix.hystrix.strategy.properties;version=\\\"1.5.12\\\",ch.qos.logback.classic;version=\\\"1.2.13\\\",ch.qos.logback.classic.spi;version=\\\"1.2.13\\\",ch.qos.logback.classic.turbo;version=\\\"1.2.13\\\",ch.qos.logback.core.spi;version=\\\"1.2.13\\\",org.apache.logging.log4j;version=\\\"2.20.2\\\",org.apache.logging.log4j.core;version=\\\"2.20.2\\\",org.apache.logging.log4j.core.config;version=\\\"2.21.0\\\",org.apache.logging.log4j.core.filter;version=\\\"2.21.0\\\",org.apache.logging.log4j.spi;version=\\\"2.20.1\\\",okhttp3,com.mongodb;version=\\\"4.11.1\\\",com.mongodb.connection;version=\\\"4.11.1\\\",com.mongodb.event;version=\\\"4.11.1\\\",org.jooq;version=\\\"3.14.16\\\",org.jooq.exception;version=\\\"3.14.16\\\",org.jooq.impl;version=\\\"3.14.16\\\",org.apache.kafka.clients.admin,org.apache.kafka.clients.consumer,org.apache.kafka.clients.producer,org.apache.kafka.common,org.apache.kafka.common.metrics,org.apache.kafka.streams,com.codahale.metrics;version=\\\"4.2.25\\\",com.google.common.cache;version=\\\"32.1.2\\\",jakarta.servlet.http;version=\\\"5.0.0\\\",javax.servlet;version=\\\"4.0.0\\\",javax.servlet.http;version=\\\"4.0.0\\\",io.micrometer.context,io.micrometer.observation;version=\\\"1.13.0\\\",io.micrometer.observation.docs;version=\\\"1.13.0\\\",io.micrometer.observation.transport;version=\\\"1.13.0\\\",kotlin,kotlin.coroutines,kotlin.jvm.functions,kotlin.jvm.internal,kotlinx.coroutines,org.LatencyUtils,org.HdrHistogram;version=\\\"2.1.12\\\",org.apache.catalina,org.bson;version=\\\"4.11.1\\\",rx;version=\\\"1.2.0\\\",rx.functions;version=\\\"1.2.0\\\",javax.persistence;version=\\\"2.2.0\\\",io.netty.buffer;version=\\\"4.1.106\\\",io.netty.util.concurrent;version=\\\"4.1.106\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.core.annotation;version=\\\"1.13.0\\\",io.micrometer.core.aop;uses:=\\\"io.micrometer.common.annotation,io.micrometer.common.lang,io.micrometer.core.annotation,io.micrometer.core.instrument,org.aspectj.lang,org.aspectj.lang.annotation\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.annotation,io.micrometer.core.instrument.composite,io.micrometer.core.instrument.config,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.search\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.cache;uses:=\\\"com.github.benmanes.caffeine.cache,com.github.benmanes.caffeine.cache.stats,com.google.common.cache,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.cache,net.sf.ehcache\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.commonspool2;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.management\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.db;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.sql,org.jooq,org.jooq.impl\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.grpc;uses:=\\\"io.grpc,io.micrometer.common,io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.http;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,jakarta.servlet.http,javax.servlet.http\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.httpcomponents;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,org.apache.http,org.apache.http.conn.routing,org.apache.http.pool,org.apache.http.protocol\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.httpcomponents.hc5;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,org.apache.hc.client5.http,org.apache.hc.client5.http.async,org.apache.hc.client5.http.classic,org.apache.hc.client5.http.protocol,org.apache.hc.core5.http,org.apache.hc.core5.http.impl.io,org.apache.hc.core5.http.io,org.apache.hc.core5.http.nio,org.apache.hc.core5.http.protocol,org.apache.hc.core5.pool,org.apache.hc.core5.util\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.hystrix;uses:=\\\"com.netflix.hystrix,com.netflix.hystrix.strategy.metrics,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jersey.server;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,org.glassfish.jersey.server,org.glassfish.jersey.server.monitoring\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jetty;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.core.instrument.binder.http,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,javax.servlet,javax.servlet.http,org.eclipse.jetty.client.api,org.eclipse.jetty.io,org.eclipse.jetty.io.ssl,org.eclipse.jetty.server,org.eclipse.jetty.server.handler,org.eclipse.jetty.util.component,org.eclipse.jetty.util.thread\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jpa;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.persistence,org.hibernate\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.jvm;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.kafka;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.management,org.apache.kafka.clients.admin,org.apache.kafka.clients.consumer,org.apache.kafka.clients.producer,org.apache.kafka.streams\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.logging;uses:=\\\"ch.qos.logback.classic,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,org.apache.logging.log4j.core\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.mongodb;uses:=\\\"com.mongodb.event,io.micrometer.common.lang,io.micrometer.core.instrument,org.bson\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.netty4;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.core.instrument.docs,io.netty.buffer,io.netty.util.concurrent\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.okhttp3;uses:=\\\"io.micrometer.common,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,okhttp3\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.system;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.binder.tomcat;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,javax.management,org.apache.catalina\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.composite;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.config;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.config.validate;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument.config\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.cumulative;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.distribution;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.internal,io.micrometer.core.instrument.step,org.HdrHistogram\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.distribution.pause;version=\\\"1.13.0\\\",io.micrometer.core.instrument.docs;uses:=\\\"io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.core.instrument\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.dropwizard;uses:=\\\"com.codahale.metrics,io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.util\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.internal;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.distribution\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.kotlin;uses:=\\\"io.grpc,io.grpc.kotlin,io.micrometer.observation,kotlin,kotlin.coroutines\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.logging;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.step\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.noop;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.distribution\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.observation;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.observation\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.push;uses:=\\\"io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.search;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.simple;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.step;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.push\\\";version=\\\"1.13.0\\\",io.micrometer.core.instrument.util;uses:=\\\"io.micrometer.common.lang,io.micrometer.core.instrument,io.micrometer.core.instrument.config\\\";version=\\\"1.13.0\\\",io.micrometer.core.ipc.http;uses:=\\\"io.micrometer.common.lang,okhttp3\\\";version=\\\"1.13.0\\\",io.micrometer.core.lang;uses:=\\\"javax.annotation,javax.annotation.meta\\\";version=\\\"1.13.0\\\",io.micrometer.core.util.internal.logging;version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-core;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"com.sun.management,io.micrometer.common;version=\\\"[1.13,2)\\\",io.micrometer.common.annotation;version=\\\"[1.13,2)\\\",io.micrometer.common.docs;version=\\\"[1.13,2)\\\",io.micrometer.common.lang;version=\\\"[1.13,2)\\\",io.micrometer.common.util;version=\\\"[1.13,2)\\\",io.micrometer.common.util.internal.logging;version=\\\"[1.13,2)\\\",io.micrometer.core.annotation,io.micrometer.core.instrument,io.micrometer.core.instrument.binder,io.micrometer.core.instrument.binder.http,io.micrometer.core.instrument.composite,io.micrometer.core.instrument.config,io.micrometer.core.instrument.config.validate,io.micrometer.core.instrument.cumulative,io.micrometer.core.instrument.distribution,io.micrometer.core.instrument.distribution.pause,io.micrometer.core.instrument.docs,io.micrometer.core.instrument.internal,io.micrometer.core.instrument.noop,io.micrometer.core.instrument.observation,io.micrometer.core.instrument.push,io.micrometer.core.instrument.search,io.micrometer.core.instrument.step,io.micrometer.core.instrument.util,javax.annotation;version=\\\"[3.0,4)\\\",javax.annotation.meta;version=\\\"[3.0,4)\\\",javax.management,javax.management.openmbean,javax.net.ssl,javax.sql,org.slf4j;version=\\\"[1.7,2)\\\",org.slf4j.helpers;version=\\\"[1.7,2)\\\",org.slf4j.spi;version=\\\"[1.7,2)\\\"\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-core\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"49d54a8ed6d3266b4f2691027d95144e946bbe36\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f4ea2c844b65a026\",\n      \"name\": \"micrometer-jakarta9\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-jakarta9-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-jakarta9-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_jakarta9:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_jakarta9:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_jakarta9:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-jakarta9@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-jakarta9-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.jakarta9\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769878958\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.305566010Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-jakarta9\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-jakarta9\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"DynamicImport-Package\",\n              \"value\": \"jakarta.jms;version=\\\"3.0.0\\\",io.micrometer.observation;version=\\\"1.13.0\\\",io.micrometer.observation.docs;version=\\\"1.13.0\\\",io.micrometer.observation.transport;version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.jakarta9.instrument.jms;uses:=\\\"io.micrometer.common,io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.observation,io.micrometer.observation.docs,io.micrometer.observation.transport,jakarta.jms\\\";version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-jakarta9;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"io.micrometer.common;version=\\\"[1.13,2)\\\",io.micrometer.common.docs;version=\\\"[1.13,2)\\\",io.micrometer.common.lang;version=\\\"[1.13,2)\\\"\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-jakarta9\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"74087b670cad9f9883228ee2aa871f51b53f827a\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"26b8a84479010ca8\",\n      \"name\": \"micrometer-observation\",\n      \"version\": \"1.13.0-M1\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer-observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_observation:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer_observation:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer-observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:micrometer:micrometer_observation:1.13.0-M1:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/io.micrometer/micrometer-observation@1.13.0-M1\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/micrometer-observation-1.13.0-M1.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"micrometer.observation\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1707769856490\"\n            },\n            {\n              \"key\": \"Branch\",\n              \"value\": \"HEAD\"\n            },\n            {\n              \"key\": \"Build-Date\",\n              \"value\": \"2024-02-12_20:30:25\"\n            },\n            {\n              \"key\": \"Build-Date-UTC\",\n              \"value\": \"2024-02-12T20:30:25.426326246Z\"\n            },\n            {\n              \"key\": \"Build-Host\",\n              \"value\": \"bea640c5c9a6\"\n            },\n            {\n              \"key\": \"Build-Id\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Java-Version\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Build-Job\",\n              \"value\": \"deploy\"\n            },\n            {\n              \"key\": \"Build-Number\",\n              \"value\": \"30241\"\n            },\n            {\n              \"key\": \"Build-Timezone\",\n              \"value\": \"Etc/UTC\"\n            },\n            {\n              \"key\": \"Build-Url\",\n              \"value\": \"https://circleci.com/gh/micrometer-metrics/micrometer/30241\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"circleci\"\n            },\n            {\n              \"key\": \"Built-OS\",\n              \"value\": \"Linux\"\n            },\n            {\n              \"key\": \"Built-Status\",\n              \"value\": \"candidate\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"micrometer-observation\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"micrometer-observation\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"1.13.0.M1\"\n            },\n            {\n              \"key\": \"Change\",\n              \"value\": \"639c93a\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"21.0.2 (Eclipse Adoptium)\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"io.micrometer.observation;uses:=\\\"io.micrometer.common,io.micrometer.common.lang\\\";version=\\\"1.13.0\\\",io.micrometer.observation.annotation;version=\\\"1.13.0\\\",io.micrometer.observation.aop;uses:=\\\"io.micrometer.common.lang,io.micrometer.observation,org.aspectj.lang,org.aspectj.lang.annotation\\\";version=\\\"1.13.0\\\",io.micrometer.observation.contextpropagation;uses:=\\\"io.micrometer.context,io.micrometer.observation\\\";version=\\\"1.13.0\\\",io.micrometer.observation.docs;uses:=\\\"io.micrometer.common.docs,io.micrometer.common.lang,io.micrometer.observation\\\";version=\\\"1.13.0\\\",io.micrometer.observation.transport;uses:=\\\"io.micrometer.common.lang,io.micrometer.observation\\\";version=\\\"1.13.0\\\"\"\n            },\n            {\n              \"key\": \"Full-Change\",\n              \"value\": \"639c93af0d0507b4cfa0e0581146719863b691b1\"\n            },\n            {\n              \"key\": \"Gradle-Version\",\n              \"value\": \"8.6\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"io.micrometer#micrometer-observation;1.13.0-M1\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"1.13.0-M1\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"io.micrometer.context;resolution:=optional,org.aspectj.lang;resolution:=optional,org.aspectj.lang.annotation;resolution:=optional,org.aspectj.lang.reflect;resolution:=optional,io.micrometer.common;version=\\\"[1.13,2)\\\",io.micrometer.common.docs;version=\\\"[1.13,2)\\\",io.micrometer.common.lang;version=\\\"[1.13,2)\\\",io.micrometer.common.util;version=\\\"[1.13,2)\\\",io.micrometer.common.util.internal.logging;version=\\\"[1.13,2)\\\",io.micrometer.observation,io.micrometer.observation.annotation,io.micrometer.observation.docs\"\n            },\n            {\n              \"key\": \"Module-Email\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Origin\",\n              \"value\": \"git@github.com:micrometer-metrics/micrometer.git\"\n            },\n            {\n              \"key\": \"Module-Owner\",\n              \"value\": \"tludwig@vmware.com\"\n            },\n            {\n              \"key\": \"Module-Source\",\n              \"value\": \"/micrometer-observation\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.4.0.202211291949\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"1.8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"1.8\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"c06e5e0f9b6edc9c0c0ac3dd46a2117ce6f16a9d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"93ed082a147d9796\",\n      \"name\": \"sbom-test-gradle\",\n      \"version\": \"0.0.1-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test-gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:sbom-test-gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:sbom_test_gradle:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test_gradle:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:JarLauncher:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:JarLauncher:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom-test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom_test:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:launch:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:loader:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:launch:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:loader:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:sbom:boot:0.0.1-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot.loader.launch.JarLauncher/sbom-test-gradle@0.0.1-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Main-Class\",\n              \"value\": \"org.springframework.boot.loader.launch.JarLauncher\"\n            },\n            {\n              \"key\": \"Start-Class\",\n              \"value\": \"com.example.sbomtestgradle.SbomTestGradleApplication\"\n            },\n            {\n              \"key\": \"Spring-Boot-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Spring-Boot-Classes\",\n              \"value\": \"BOOT-INF/classes/\"\n            },\n            {\n              \"key\": \"Spring-Boot-Lib\",\n              \"value\": \"BOOT-INF/lib/\"\n            },\n            {\n              \"key\": \"Spring-Boot-Classpath-Index\",\n              \"value\": \"BOOT-INF/classpath.idx\"\n            },\n            {\n              \"key\": \"Spring-Boot-Layers-Index\",\n              \"value\": \"BOOT-INF/layers.idx\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"sbom-test-gradle\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"0.0.1-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Sbom-Location\",\n              \"value\": \"META-INF/sbom/bom.json\"\n            },\n            {\n              \"key\": \"Sbom-Format\",\n              \"value\": \"CycloneDX\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"8ccd6688e9d8e15d18e0f10967867e5e30729a4c\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"44752cfa6770756d\",\n      \"name\": \"slf4j-api\",\n      \"version\": \"2.0.11\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/slf4j-api-2.0.11.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.opensource.org/licenses/mit-license.php\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/slf4j-api-2.0.11.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j-api:slf4j-api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j-api:slf4j_api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j_api:slf4j-api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j_api:slf4j_api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:slf4j-api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:slf4j:slf4j_api:2.0.11:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.slf4j/slf4j-api@2.0.11\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/slf4j-api-2.0.11.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.9\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"21\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"The slf4j API\"\n            },\n            {\n              \"key\": \"Bundle-DocURL\",\n              \"value\": \"http://www.slf4j.org\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.opensource.org/licenses/mit-license.php\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"SLF4J API Module\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"slf4j.api\"\n            },\n            {\n              \"key\": \"Bundle-Vendor\",\n              \"value\": \"SLF4J.ORG\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.slf4j;uses:=\\\"org.slf4j.event,org.slf4j.helpers,org.slf4j.spi\\\";version=\\\"2.0.11\\\",org.slf4j.event;uses:=\\\"org.slf4j,org.slf4j.helpers\\\";version=\\\"2.0.11\\\",org.slf4j.helpers;uses:=\\\"org.slf4j,org.slf4j.event,org.slf4j.spi\\\";version=\\\"2.0.11\\\",org.slf4j.spi;uses:=\\\"org.slf4j,org.slf4j.event,org.slf4j.helpers\\\";version=\\\"2.0.11\\\",org.slf4j;version=\\\"1.7.36\\\",org.slf4j.helpers;version=\\\"1.7.36\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"slf4j-api\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"2.0.11\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.slf4j.spi;version=\\\"[2.0.11,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.slf4j.spi.SLF4JServiceProvider)\\\";osgi.serviceloader=\\\"org.slf4j.spi.SLF4JServiceProvider\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"8\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"8\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.slf4j/slf4j-api/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.slf4j\",\n          \"artifactId\": \"slf4j-api\",\n          \"version\": \"2.0.11\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"ad96c3f8cf895e696dd35c2bc8e8ebe710be9e6d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f4585c65c0a5b26a\",\n      \"name\": \"snakeyaml\",\n      \"version\": \"2.2\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/snakeyaml-2.2.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/snakeyaml-2.2.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:snakeyaml:snakeyaml:2.2:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:yaml:snakeyaml:2.2:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.yaml/snakeyaml@2.2\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/snakeyaml-2.2.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bnd-LastModified\",\n              \"value\": \"1693124775469\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"Bundle-Description\",\n              \"value\": \"YAML 1.1 parser and emitter for Java\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"http://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"SnakeYAML\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.yaml.snakeyaml\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"2.2.0\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"Apache Maven Bundle Plugin 5.1.8\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"org.yaml.snakeyaml;version=\\\"2.2\\\",org.yaml.snakeyaml.comments;version=\\\"2.2\\\",org.yaml.snakeyaml.composer;version=\\\"2.2\\\",org.yaml.snakeyaml.constructor;version=\\\"2.2\\\",org.yaml.snakeyaml.emitter;version=\\\"2.2\\\",org.yaml.snakeyaml.env;version=\\\"2.2\\\",org.yaml.snakeyaml.error;version=\\\"2.2\\\",org.yaml.snakeyaml.events;version=\\\"2.2\\\",org.yaml.snakeyaml.extensions.compactnotation;version=\\\"2.2\\\",org.yaml.snakeyaml.inspector;version=\\\"2.2\\\",org.yaml.snakeyaml.internal;version=\\\"2.2\\\",org.yaml.snakeyaml.introspector;version=\\\"2.2\\\",org.yaml.snakeyaml.nodes;version=\\\"2.2\\\",org.yaml.snakeyaml.parser;version=\\\"2.2\\\",org.yaml.snakeyaml.reader;version=\\\"2.2\\\",org.yaml.snakeyaml.representer;version=\\\"2.2\\\",org.yaml.snakeyaml.resolver;version=\\\"2.2\\\",org.yaml.snakeyaml.scanner;version=\\\"2.2\\\",org.yaml.snakeyaml.serializer;version=\\\"2.2\\\",org.yaml.snakeyaml.tokens;version=\\\"2.2\\\",org.yaml.snakeyaml.util;version=\\\"2.2\\\"\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"org.yaml.snakeyaml;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.comments;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.composer;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.emitter;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.error;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.events;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.inspector;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.internal;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.introspector;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.nodes;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.parser;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.reader;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.resolver;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.scanner;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.serializer;version=\\\"[2.2,3)\\\",org.yaml.snakeyaml.tokens;version=\\\"[2.2,3)\\\"\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.7))\\\"\"\n            },\n            {\n              \"key\": \"Tool\",\n              \"value\": \"Bnd-6.3.1.202206071316\"\n            }\n          ]\n        },\n        \"pomProperties\": {\n          \"path\": \"META-INF/maven/org.yaml/snakeyaml/pom.properties\",\n          \"name\": \"\",\n          \"groupId\": \"org.yaml\",\n          \"artifactId\": \"snakeyaml\",\n          \"version\": \"2.2\"\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"1e7758a78bbc15ee\",\n      \"name\": \"spring-aop\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_aop:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_aop:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_aop:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-aop@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-aop-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-aop\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.aop\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"b02165904562fc487cde57ca75e063561d905f74\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"bb7e773a923726bb\",\n      \"name\": \"spring-beans\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_beans:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_beans:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_beans:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-beans@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-beans-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-beans\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.beans\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"fa8be0f856958fdd33eef9e718b3a65f7130bbd2\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"a11948291446c2f5\",\n      \"name\": \"spring-boot\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d882660ea3deafe921faba8b17e7d94ef9556c47\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"f83d629168e25cce\",\n      \"name\": \"spring-boot-actuator\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_actuator:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.actuator\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot Actuator\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d0d018780795da57afa8edae7436646bccd55722\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"b8eb893518786bb8\",\n      \"name\": \"spring-boot-actuator-autoconfigure\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-autoconfigure-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-autoconfigure-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-actuator-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_actuator_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_actuator:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-actuator-autoconfigure-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.actuator.autoconfigure\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot Actuator AutoConfigure\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"8b8f74be822e6f2ab120ea0687acf629ef114399\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"b40bdc90eb8832a3\",\n      \"name\": \"spring-boot-autoconfigure\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_autoconfigure:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_autoconfigure:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_autoconfigure:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_autoconfigure:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-autoconfigure-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.autoconfigure\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot AutoConfigure\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"31a960bb63af836f35760077af8ef58d24b548e3\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"8069f3f866b2e657\",\n      \"name\": \"spring-boot-jarmode-layertools\",\n      \"version\": \"3.3.0-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-jarmode-layertools-3.3.0-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-jarmode-layertools-3.3.0-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode-layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode_layertools:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring-boot-jarmode-layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:spring_boot_jarmode_layertools:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode-layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode_layertools:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot-jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot_jarmode:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:boot:boot:3.3.0-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework.boot/spring-boot-jarmode-layertools@3.3.0-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-boot-jarmode-layertools-3.3.0-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.boot.jarmode.layertools\"\n            },\n            {\n              \"key\": \"Build-Jdk-Spec\",\n              \"value\": \"17\"\n            },\n            {\n              \"key\": \"Built-By\",\n              \"value\": \"Spring\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Spring Boot Layers Tools\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"3.3.0-SNAPSHOT\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"d86f1782ad3d9ee047863a5023aaa22f858cd9a4\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"3d5d71e0e85398af\",\n      \"name\": \"spring-context\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_context:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_context:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_context:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-context@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-context-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-context\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.context\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"75440f70a649ca15948af5923ebdef345848a856\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"519fe54307d2d43d\",\n      \"name\": \"spring-core\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:springsource_spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource-spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource_spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:pivotal_software:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_framework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springsource:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_core:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:spring_framework:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:spring-core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:vmware:spring_core:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-core@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-core-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-core\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.core\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            },\n            {\n              \"key\": \"Multi-Release\",\n              \"value\": \"true\"\n            },\n            {\n              \"key\": \"Dependencies\",\n              \"value\": \"jdk.unsupported,org.jboss.vfs\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"27d0900a14e240a7311c979e7b30cf65f9de9074\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"546794e924e39088\",\n      \"name\": \"spring-expression\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:spring-expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_expression:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_expression:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_expression:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-expression@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-expression-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-expression\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.expression\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"a5d7041ca11fd188e9d17ac8a795eabed8be55e4\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"173ea637a5756944\",\n      \"name\": \"spring-jcl\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_jcl:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_jcl:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_jcl:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-jcl@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-jcl-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-jcl\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.jcl\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"604cea28d23d8027a31c35f372d2b8d0fdec211d\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"adc63cefcede34fc\",\n      \"name\": \"spring-web\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_web:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_web:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_web:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-web@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-web-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-web\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.web\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"c0600dcd73db226c3d121af16d6a155ecee08d30\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"940aed7082581b67\",\n      \"name\": \"spring-webmvc\",\n      \"version\": \"6.1.4-SNAPSHOT\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"Apache-2.0\",\n          \"spdxExpression\": \"Apache-2.0\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        },\n        {\n          \"value\": \"BSD-3-Clause\",\n          \"spdxExpression\": \"BSD-3-Clause\",\n          \"type\": \"concluded\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:springframework:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring-webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_webmvc:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring_webmvc:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring-webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:spring:spring_webmvc:6.1.4-SNAPSHOT:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.springframework/spring-webmvc@6.1.4-SNAPSHOT\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/spring-webmvc-6.1.4-SNAPSHOT.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"spring-webmvc\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"6.1.4-SNAPSHOT\"\n            },\n            {\n              \"key\": \"Automatic-Module-Name\",\n              \"value\": \"spring.webmvc\"\n            },\n            {\n              \"key\": \"Created-By\",\n              \"value\": \"17.0.10 (Oracle Corporation)\"\n            }\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"34a510cf565bec1c2f74f049b1730b22f877bd37\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"a753aca6ee68c738\",\n      \"name\": \"tomcat-embed-core\",\n      \"version\": \"10.1.18\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-core-10.1.18.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-core-10.1.18.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat-embed-core:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat_embed_core:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.18\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-core-10.1.18.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"tomcat-embed-core\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.tomcat-embed-core\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.security.auth.message;version=\\\"3.0\\\";uses:=\\\"javax.security.auth,javax.security.auth.login\\\",jakarta.security.auth.message.callback;version=\\\"3.0\\\";uses:=\\\"javax.crypto,javax.security.auth,javax.security.auth.callback,javax.security.auth.x500\\\",jakarta.security.auth.message.config;version=\\\"3.0\\\";uses:=\\\"jakarta.security.auth.message,jakarta.security.auth.message.module,javax.security.auth,javax.security.auth.callback\\\",jakarta.security.auth.message.module;version=\\\"3.0\\\";uses:=\\\"jakarta.security.auth.message,javax.security.auth.callback\\\",jakarta.servlet;version=\\\"6.0\\\";uses:=\\\"jakarta.servlet.annotation,jakarta.servlet.descriptor\\\",jakarta.servlet.annotation;version=\\\"6.0\\\";uses:=\\\"jakarta.servlet\\\",jakarta.servlet.descriptor;version=\\\"6.0\\\",jakarta.servlet.http;version=\\\"6.0\\\";uses:=\\\"jakarta.servlet\\\",jakarta.servlet.resources;version=\\\"6.0\\\",org.apache.catalina;uses:=\\\"jakarta.servlet,jakarta.servlet.descriptor,jakarta.servlet.http,javax.management,javax.naming,org.apache.catalina.connector,org.apache.catalina.deploy,org.apache.catalina.mapper,org.apache.catalina.startup,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.file,org.apache.tomcat.util.http,org.ietf.jgss\\\";version=\\\"10.1.18\\\",org.apache.catalina.authenticator;uses:=\\\"jakarta.security.auth.message.config,jakarta.servlet,jakarta.servlet.http,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.util,org.apache.catalina.valves,org.apache.tomcat.util.buf,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.res,org.ietf.jgss\\\";version=\\\"10.1.18\\\",org.apache.catalina.authenticator.jaspic;uses:=\\\"jakarta.security.auth.message,jakarta.security.auth.message.config,jakarta.security.auth.message.module,jakarta.servlet.http,javax.security.auth,javax.security.auth.callback,org.apache.catalina,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.connector;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.security.auth,org.apache.catalina,org.apache.catalina.core,org.apache.catalina.mapper,org.apache.catalina.util,org.apache.coyote,org.apache.tomcat.util.buf,org.apache.tomcat.util.http,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.core;uses:=\\\"jakarta.servlet,jakarta.servlet.descriptor,jakarta.servlet.http,javax.management,javax.naming,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.deploy,org.apache.catalina.mapper,org.apache.catalina.startup,org.apache.catalina.util,org.apache.coyote,org.apache.juli.logging,org.apache.naming,org.apache.tomcat,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.http,org.apache.tomcat.util.http.fileupload,org.apache.tomcat.util.res,org.apache.tomcat.util.threads\\\";version=\\\"10.1.18\\\",org.apache.catalina.deploy;uses:=\\\"org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.descriptor.web\\\";version=\\\"10.1.18\\\",org.apache.catalina.filters;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.juli.logging,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.loader;uses:=\\\"org.apache.catalina,org.apache.catalina.util,org.apache.juli,org.apache.tomcat,org.apache.tomcat.util.res,org.apache.tomcat.util.security\\\";version=\\\"10.1.18\\\",org.apache.catalina.manager;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.management,javax.naming,org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.modeler,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.manager.host;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.catalina,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.manager.util;uses:=\\\"jakarta.servlet.http,org.apache.catalina\\\";version=\\\"10.1.18\\\",org.apache.catalina.mapper;uses:=\\\"jakarta.servlet.http,org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.buf\\\";version=\\\"10.1.18\\\",org.apache.catalina.mbeans;uses:=\\\"javax.management,javax.naming,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.core,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.modeler,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.realm;uses:=\\\"javax.management,javax.naming,javax.naming.directory,javax.net.ssl,javax.security.auth,javax.security.auth.callback,javax.security.auth.login,javax.security.auth.spi,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat.util.collections,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.digester,org.apache.tomcat.util.res,org.ietf.jgss\\\";version=\\\"10.1.18\\\",org.apache.catalina.security;uses:=\\\"jakarta.servlet,org.apache.catalina\\\";version=\\\"10.1.18\\\",org.apache.catalina.servlets;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.xml.parsers,javax.xml.transform,org.apache.catalina,org.apache.tomcat.util.http,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.session;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.sql,org.apache.catalina,org.apache.catalina.util,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.startup;uses:=\\\"jakarta.annotation,jakarta.servlet,jakarta.servlet.descriptor,javax.management,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.core,org.apache.catalina.deploy,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.bcel.classfile,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.digester,org.apache.tomcat.util.file,org.apache.tomcat.util.http,org.apache.tomcat.util.res,org.xml.sax\\\";version=\\\"10.1.18\\\",org.apache.catalina.users;uses:=\\\"javax.naming,javax.naming.spi,javax.sql,org.apache.catalina\\\";version=\\\"10.1.18\\\",org.apache.catalina.util;uses:=\\\"jakarta.servlet.http,javax.management,org.apache.catalina,org.apache.juli.logging,org.apache.tomcat.util.descriptor.web,org.w3c.dom\\\";version=\\\"10.1.18\\\",org.apache.catalina.valves;uses:=\\\"jakarta.servlet,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.valves.rewrite;uses:=\\\"jakarta.servlet,org.apache.catalina,org.apache.catalina.connector,org.apache.catalina.valves,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.webresources;uses:=\\\"org.apache.catalina,org.apache.catalina.util,org.apache.juli.logging,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.webresources.war;version=\\\"10.1.18\\\",org.apache.coyote;uses:=\\\"jakarta.servlet,jakarta.servlet.http,javax.management,org.apache.coyote.http11,org.apache.coyote.http11.upgrade,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.buf,org.apache.tomcat.util.collections,org.apache.tomcat.util.http,org.apache.tomcat.util.log,org.apache.tomcat.util.modeler,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.coyote.ajp;uses:=\\\"jakarta.servlet,org.apache.coyote,org.apache.juli.logging,org.apache.tomcat.util.buf,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.coyote.http11;uses:=\\\"jakarta.servlet,javax.management,org.apache.coyote,org.apache.coyote.http11.upgrade,org.apache.juli.logging,org.apache.tomcat.util.buf,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.coyote.http11.filters;uses:=\\\"org.apache.coyote,org.apache.coyote.http11,org.apache.juli.logging,org.apache.tomcat.util.buf,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.coyote.http11.upgrade;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.coyote,org.apache.juli.logging,org.apache.tomcat.util.modeler,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.coyote.http2;uses:=\\\"jakarta.servlet,jakarta.servlet.http,org.apache.coyote,org.apache.coyote.http11,org.apache.coyote.http11.upgrade,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.net,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.juli;version=\\\"10.1.18\\\",org.apache.juli.logging;version=\\\"10.1.18\\\",org.apache.naming;uses:=\\\"javax.naming\\\";version=\\\"10.1.18\\\",org.apache.naming.factory;uses:=\\\"javax.naming,javax.naming.spi,javax.sql,org.apache.naming\\\";version=\\\"10.1.18\\\",org.apache.naming.java;uses:=\\\"javax.naming,javax.naming.spi\\\";version=\\\"10.1.18\\\",org.apache.tomcat;uses:=\\\"jakarta.servlet,javax.naming\\\";version=\\\"10.1.18\\\",org.apache.tomcat.jni;version=\\\"10.1.18\\\",org.apache.tomcat.util;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.bcel.classfile;version=\\\"10.1.18\\\",org.apache.tomcat.util.buf;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.codec.binary;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.collections;version=\\\"10.1.18\\\",org.apache.tomcat.util.compat;version=\\\"10.1.18\\\",org.apache.tomcat.util.descriptor;uses:=\\\"org.apache.juli.logging,org.apache.tomcat.util.digester,org.xml.sax,org.xml.sax.ext\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.descriptor.tagplugin;uses:=\\\"jakarta.servlet,org.xml.sax\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.descriptor.web;uses:=\\\"jakarta.servlet,jakarta.servlet.descriptor,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.digester,org.apache.tomcat.util.res,org.xml.sax\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.digester;uses:=\\\"javax.xml.parsers,org.apache.juli.logging,org.apache.tomcat.util,org.apache.tomcat.util.res,org.xml.sax,org.xml.sax.ext\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.file;version=\\\"10.1.18\\\",org.apache.tomcat.util.http;uses:=\\\"jakarta.servlet.http,org.apache.tomcat.util.buf\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload;uses:=\\\"org.apache.tomcat.util.http.fileupload.impl,org.apache.tomcat.util.http.fileupload.util\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.disk;uses:=\\\"org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.impl;uses:=\\\"org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.servlet;uses:=\\\"jakarta.servlet.http,org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.fileupload.util;uses:=\\\"org.apache.tomcat.util.http.fileupload\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.http.parser;uses:=\\\"org.apache.tomcat.util.buf,org.apache.tomcat.util.http\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.log;uses:=\\\"org.apache.juli.logging\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.modeler;uses:=\\\"javax.management,javax.management.modelmbean\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.modeler.modules;uses:=\\\"javax.management,org.apache.tomcat.util.modeler,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.net;uses:=\\\"jakarta.servlet,javax.management,javax.net.ssl,org.apache.juli.logging,org.apache.tomcat.util.collections,org.apache.tomcat.util.net.openssl,org.apache.tomcat.util.net.openssl.ciphers,org.apache.tomcat.util.res,org.apache.tomcat.util.threads\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.net.openssl;uses:=\\\"javax.net.ssl,org.apache.juli.logging,org.apache.tomcat.util.net\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.net.openssl.ciphers;version=\\\"10.1.18\\\",org.apache.tomcat.util.res;version=\\\"10.1.18\\\",org.apache.tomcat.util.scan;uses:=\\\"jakarta.servlet,org.apache.tomcat\\\";version=\\\"10.1.18\\\",org.apache.tomcat.util.security;version=\\\"10.1.18\\\",org.apache.tomcat.util.threads;uses:=\\\"org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.catalina.ssi;version=\\\"10.1.18\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"jakarta.annotation,jakarta.annotation.security,jakarta.ejb,jakarta.mail,jakarta.mail.internet,jakarta.persistence,jakarta.security.auth.message;version=\\\"[3.0,4)\\\",jakarta.security.auth.message.callback;version=\\\"[3.0,4)\\\",jakarta.security.auth.message.config;version=\\\"[3.0,4)\\\",jakarta.security.auth.message.module;version=\\\"[3.0,4)\\\",jakarta.servlet;version=\\\"[6.0,7)\\\",jakarta.servlet.annotation;version=\\\"[6.0,7)\\\",jakarta.servlet.descriptor;version=\\\"[6.0,7)\\\",jakarta.servlet.http;version=\\\"[6.0,7)\\\",jakarta.xml.ws,java.beans,java.io,java.lang,java.lang.annotation,java.lang.instrument,java.lang.invoke,java.lang.management,java.lang.module,java.lang.ref,java.lang.reflect,java.math,java.net,java.nio,java.nio.channels,java.nio.charset,java.nio.file,java.nio.file.attribute,java.rmi,java.security,java.security.cert,java.security.spec,java.sql,java.text,java.time,java.time.chrono,java.time.format,java.time.temporal,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,java.util.function,java.util.jar,java.util.logging,java.util.regex,java.util.stream,java.util.zip,javax.crypto,javax.crypto.spec,javax.imageio,javax.management,javax.management.loading,javax.management.modelmbean,javax.management.openmbean,javax.naming,javax.naming.directory,javax.naming.ldap,javax.naming.spi,javax.net.ssl,javax.security.auth,javax.security.auth.callback,javax.security.auth.login,javax.security.auth.spi,javax.security.auth.x500,javax.security.cert,javax.sql,javax.wsdl,javax.wsdl.extensions,javax.wsdl.extensions.soap,javax.wsdl.factory,javax.wsdl.xml,javax.xml.namespace,javax.xml.parsers,javax.xml.rpc,javax.xml.rpc.handler,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.apache.catalina,org.apache.catalina.authenticator,org.apache.catalina.authenticator.jaspic,org.apache.catalina.connector,org.apache.catalina.core,org.apache.catalina.deploy,org.apache.catalina.filters,org.apache.catalina.loader,org.apache.catalina.manager.util,org.apache.catalina.mapper,org.apache.catalina.mbeans,org.apache.catalina.realm,org.apache.catalina.security,org.apache.catalina.session,org.apache.catalina.startup,org.apache.catalina.util,org.apache.catalina.webresources,org.apache.catalina.webresources.war,org.apache.coyote,org.apache.coyote.ajp,org.apache.coyote.http11,org.apache.coyote.http11.filters,org.apache.coyote.http11.upgrade,org.apache.juli,org.apache.juli.logging,org.apache.naming,org.apache.naming.factory,org.apache.tomcat,org.apache.tomcat.jakartaee,org.apache.tomcat.jni,org.apache.tomcat.util,org.apache.tomcat.util.buf,org.apache.tomcat.util.codec.binary,org.apache.tomcat.util.collections,org.apache.tomcat.util.compat,org.apache.tomcat.util.descriptor,org.apache.tomcat.util.descriptor.web,org.apache.tomcat.util.digester,org.apache.tomcat.util.file,org.apache.tomcat.util.http,org.apache.tomcat.util.http.fileupload.disk,org.apache.tomcat.util.http.fileupload.impl,org.apache.tomcat.util.http.fileupload.servlet,org.apache.tomcat.util.http.fileupload.util,org.apache.tomcat.util.http.parser,org.apache.tomcat.util.log,org.apache.tomcat.util.modeler,org.apache.tomcat.util.modeler.modules,org.apache.tomcat.util.net.openssl.ciphers,org.apache.tomcat.util.res,org.apache.tomcat.util.scan,org.apache.tomcat.util.security,org.apache.tomcat.util.threads,org.ietf.jgss,org.w3c.dom,org.xml.sax,org.xml.sax.ext,org.xml.sax.helpers\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.naming.factory.webservices,org.apache.tomcat.util.bcel,org.apache.tomcat.util.http.fileupload.util.mime,org.apache.tomcat.util.json,org.apache.tomcat.util.net.jsse\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.contract;osgi.contract=JavaJASPIC;version:Version=\\\"3.0\\\";uses:=\\\"jakarta.security.auth.message,jakarta.security.auth.message.callback,jakarta.security.auth.message.config,jakarta.security.auth.message.module\\\",osgi.contract;osgi.contract=JavaServlet;version:Version=\\\"6.0\\\";uses:=\\\"jakarta.servlet,jakarta.servlet.annotation,jakarta.servlet.descriptor,jakarta.servlet.http,jakarta.servlet.resources\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=org.apache.juli.logging.Log)\\\";osgi.serviceloader=\\\"org.apache.juli.logging.Log\\\",osgi.contract;osgi.contract=JakartaAnnotations;filter:=\\\"(&(osgi.contract=JakartaAnnotations)(version=2.1.0))\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=11))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"10.1\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"11\"\n            }\n          ],\n          \"sections\": [\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/callback/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/config/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/security/auth/message/module/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.security.auth.message\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"3.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Authentication SPI for Containers\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"3.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/annotation/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/descriptor/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/http/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/servlet/resources/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.servlet\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"6.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Servlet\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"6.0\"\n              }\n            ]\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"bff6c34649d1dd7b509e819794d73ba795947dcf\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"7a59d22722f7701b\",\n      \"name\": \"tomcat-embed-el\",\n      \"version\": \"10.1.18\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-el-10.1.18.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-el-10.1.18.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat-embed-el:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat_embed_el:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.18\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-el-10.1.18.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"tomcat-embed-jasper-el\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.tomcat-embed-jasper-el\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.el;version=\\\"5.0\\\",org.apache.el;uses:=\\\"jakarta.el,org.apache.el.parser\\\";version=\\\"10.1.18\\\",org.apache.el.lang;uses:=\\\"jakarta.el,org.apache.el.parser\\\";version=\\\"10.1.18\\\",org.apache.el.parser;uses:=\\\"jakarta.el,org.apache.el.lang\\\";version=\\\"10.1.18\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"jakarta.el;version=\\\"[5.0,6)\\\",java.beans,java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.ref,java.lang.reflect,java.math,java.security,java.text,java.util,java.util.concurrent,java.util.concurrent.locks,java.util.function\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.el.stream,org.apache.el.util\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.contract;osgi.contract=JakartaExpressionLanguage;version:Version=\\\"5.0\\\";uses:=\\\"jakarta.el\\\",osgi.service;objectClass:List<String>=\\\"jakarta.el.ExpressionFactory\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"jakarta.el.ExpressionFactory\\\";register:=\\\"org.apache.el.ExpressionFactoryImpl\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=jakarta.el.ExpressionFactory)\\\";osgi.serviceloader=\\\"jakarta.el.ExpressionFactory\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\",osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"10.1\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"11\"\n            }\n          ],\n          \"sections\": [\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/el/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.annotation\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"5.0\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta Expression Language\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"5.0\"\n              }\n            ]\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"b2c4dc05abd363c63b245523bb071727aa2f1046\"\n          }\n        ]\n      }\n    },\n    {\n      \"id\": \"6c04f8ee22f9157e\",\n      \"name\": \"tomcat-embed-websocket\",\n      \"version\": \"10.1.18\",\n      \"type\": \"java-archive\",\n      \"foundBy\": \"java-archive-cataloger\",\n      \"locations\": [\n        {\n          \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n          \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-websocket-10.1.18.jar\",\n          \"annotations\": {\n            \"evidence\": \"primary\"\n          }\n        }\n      ],\n      \"licenses\": [\n        {\n          \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\",\n          \"spdxExpression\": \"\",\n          \"type\": \"declared\",\n          \"urls\": [],\n          \"locations\": [\n            {\n              \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n              \"accessPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-websocket-10.1.18.jar\",\n              \"annotations\": {\n                \"evidence\": \"primary\"\n              }\n            }\n          ]\n        }\n      ],\n      \"language\": \"java\",\n      \"cpes\": [\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat-embed-websocket:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat_embed_websocket:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:tomcat:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        },\n        {\n          \"cpe\": \"cpe:2.3:a:apache:embed:10.1.18:*:*:*:*:*:*:*\",\n          \"source\": \"syft-generated\"\n        }\n      ],\n      \"purl\": \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.18\",\n      \"metadataType\": \"java-archive\",\n      \"metadata\": {\n        \"virtualPath\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar:BOOT-INF/lib/tomcat-embed-websocket-10.1.18.jar\",\n        \"manifest\": {\n          \"main\": [\n            {\n              \"key\": \"Manifest-Version\",\n              \"value\": \"1.0\"\n            },\n            {\n              \"key\": \"Bundle-License\",\n              \"value\": \"https://www.apache.org/licenses/LICENSE-2.0.txt\"\n            },\n            {\n              \"key\": \"Bundle-ManifestVersion\",\n              \"value\": \"2\"\n            },\n            {\n              \"key\": \"Bundle-Name\",\n              \"value\": \"tomcat-embed-websocket\"\n            },\n            {\n              \"key\": \"Bundle-SymbolicName\",\n              \"value\": \"org.apache.tomcat-embed-websocket\"\n            },\n            {\n              \"key\": \"Bundle-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Export-Package\",\n              \"value\": \"jakarta.websocket;version=\\\"2.1\\\";uses:=\\\"javax.net.ssl\\\",jakarta.websocket.server;version=\\\"2.1\\\";uses:=\\\"jakarta.websocket\\\",org.apache.tomcat.websocket;uses:=\\\"jakarta.websocket,jakarta.websocket.server,javax.net.ssl,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.res\\\";version=\\\"10.1.18\\\",org.apache.tomcat.websocket.server;uses:=\\\"jakarta.servlet,jakarta.servlet.annotation,jakarta.servlet.http,jakarta.websocket,jakarta.websocket.server,org.apache.coyote.http11.upgrade,org.apache.juli.logging,org.apache.tomcat,org.apache.tomcat.util.net,org.apache.tomcat.websocket\\\";version=\\\"10.1.18\\\"\"\n            },\n            {\n              \"key\": \"Implementation-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Implementation-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Implementation-Version\",\n              \"value\": \"10.1.18\"\n            },\n            {\n              \"key\": \"Import-Package\",\n              \"value\": \"jakarta.servlet,jakarta.servlet.annotation,jakarta.servlet.http,jakarta.websocket;version=\\\"[2.1,3)\\\",jakarta.websocket.server;version=\\\"[2.1,3)\\\",java.io,java.lang,java.lang.annotation,java.lang.invoke,java.lang.reflect,java.net,java.nio,java.nio.channels,java.nio.charset,java.security,java.util,java.util.concurrent,java.util.concurrent.atomic,java.util.concurrent.locks,java.util.function,java.util.regex,java.util.zip,javax.naming,javax.net.ssl,org.apache.coyote.http11.upgrade;version=\\\"[10.1,11)\\\",org.apache.juli.logging;version=\\\"[10.1,11)\\\",org.apache.tomcat;version=\\\"[10.1,11)\\\",org.apache.tomcat.util;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.buf;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.codec.binary;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.collections;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.net;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.res;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.security;version=\\\"[10.1,11)\\\",org.apache.tomcat.util.threads;version=\\\"[10.1,11)\\\"\"\n            },\n            {\n              \"key\": \"Private-Package\",\n              \"value\": \"org.apache.tomcat.websocket.pojo\"\n            },\n            {\n              \"key\": \"Provide-Capability\",\n              \"value\": \"osgi.contract;osgi.contract=JavaWebSockets;version:Version=\\\"2.1\\\";uses:=\\\"jakarta.websocket,jakarta.websocket.server\\\",osgi.service;objectClass:List<String>=\\\"jakarta.websocket.ContainerProvider\\\";effective:=active,osgi.service;objectClass:List<String>=\\\"jakarta.websocket.server.ServerEndpointConfig$Configurator\\\";effective:=active,osgi.serviceloader;osgi.serviceloader=\\\"jakarta.websocket.ContainerProvider\\\";register:=\\\"org.apache.tomcat.websocket.WsContainerProvider\\\",osgi.serviceloader;osgi.serviceloader=\\\"jakarta.websocket.server.ServerEndpointConfig$Configurator\\\";register:=\\\"org.apache.tomcat.websocket.server.DefaultServerEndpointConfigurator\\\"\"\n            },\n            {\n              \"key\": \"Require-Capability\",\n              \"value\": \"osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.processor)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=jakarta.websocket.ContainerProvider)\\\";osgi.serviceloader=\\\"jakarta.websocket.ContainerProvider\\\",osgi.serviceloader;filter:=\\\"(osgi.serviceloader=jakarta.websocket.server.ServerEndpointConfig$Configurator)\\\";osgi.serviceloader=\\\"jakarta.websocket.server.ServerEndpointConfig$Configurator\\\",osgi.ee;filter:=\\\"(&(osgi.ee=JavaSE)(version=1.8))\\\",osgi.extender;filter:=\\\"(&(osgi.extender=osgi.serviceloader.registrar)(version>=1.0.0)(!(version>=2.0.0)))\\\",osgi.contract;osgi.contract=JavaServlet;filter:=\\\"(&(osgi.contract=JavaServlet)(version=6.0.0))\\\"\"\n            },\n            {\n              \"key\": \"Specification-Title\",\n              \"value\": \"Apache Tomcat\"\n            },\n            {\n              \"key\": \"Specification-Vendor\",\n              \"value\": \"Apache Software Foundation\"\n            },\n            {\n              \"key\": \"Specification-Version\",\n              \"value\": \"10.1\"\n            },\n            {\n              \"key\": \"X-Compile-Source-JDK\",\n              \"value\": \"11\"\n            },\n            {\n              \"key\": \"X-Compile-Target-JDK\",\n              \"value\": \"11\"\n            }\n          ],\n          \"sections\": [\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/websocket/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.websocket\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"2.1\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta WebSocket\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"2.1\"\n              }\n            ],\n            [\n              {\n                \"key\": \"Name\",\n                \"value\": \"jakarta/websocket/server/\"\n              },\n              {\n                \"key\": \"Implementation-Title\",\n                \"value\": \"jakarta.websocket\"\n              },\n              {\n                \"key\": \"Implementation-Vendor\",\n                \"value\": \"Apache Software Foundation\"\n              },\n              {\n                \"key\": \"Implementation-Version\",\n                \"value\": \"2.1\"\n              },\n              {\n                \"key\": \"Specification-Title\",\n                \"value\": \"Jakarta WebSocket\"\n              },\n              {\n                \"key\": \"Specification-Vendor\",\n                \"value\": \"Eclipse Foundation\"\n              },\n              {\n                \"key\": \"Specification-Version\",\n                \"value\": \"2.1\"\n              }\n            ]\n          ]\n        },\n        \"digest\": [\n          {\n            \"algorithm\": \"sha1\",\n            \"value\": \"83a3bc6898f2ceed2357ba231a5e83dc2016d454\"\n          }\n        ]\n      }\n    }\n  ],\n  \"artifactRelationships\": [\n    {\n      \"parent\": \"0408f25059f495c5\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"1347581c05f302c0\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"173ea637a5756944\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"1e7758a78bbc15ee\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"26b8a84479010ca8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"2c7953c2c68ec3bc\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"3748310e1aac44ea\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"3c0d8567351e2ae4\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"3d5d71e0e85398af\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"44752cfa6770756d\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"519fe54307d2d43d\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"546794e924e39088\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"598311f4a5b2a501\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"6c04f8ee22f9157e\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"77a5bf527533d628\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"7a59d22722f7701b\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"8069f3f866b2e657\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"846731ed2e85561c\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"860f45be6a175d16\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"93ed082a147d9796\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"940aed7082581b67\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"9ad3756f611d1ed2\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"a11948291446c2f5\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"a753aca6ee68c738\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"adc63cefcede34fc\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"b40bdc90eb8832a3\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"b8eb893518786bb8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"bb7e773a923726bb\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"c1e7975b6f55f7e8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"c404b33d3a8ce0d8\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"c46f369578c77c43\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"0408f25059f495c5\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"1347581c05f302c0\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"173ea637a5756944\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"1e7758a78bbc15ee\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"26b8a84479010ca8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"2c7953c2c68ec3bc\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"3748310e1aac44ea\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"3c0d8567351e2ae4\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"3d5d71e0e85398af\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"44752cfa6770756d\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"519fe54307d2d43d\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"546794e924e39088\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"598311f4a5b2a501\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"6c04f8ee22f9157e\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"77a5bf527533d628\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"7a59d22722f7701b\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"8069f3f866b2e657\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"846731ed2e85561c\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"860f45be6a175d16\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"93ed082a147d9796\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"940aed7082581b67\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"9ad3756f611d1ed2\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"a11948291446c2f5\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"a753aca6ee68c738\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"adc63cefcede34fc\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"b40bdc90eb8832a3\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"b8eb893518786bb8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"bb7e773a923726bb\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"c1e7975b6f55f7e8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"c404b33d3a8ce0d8\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"c46f369578c77c43\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"d91fe3ae6bb15cad\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f4585c65c0a5b26a\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f4ea2c844b65a026\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f5bca9d628ab321f\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f83d629168e25cce\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n      \"child\": \"f9418986cc24a153\",\n      \"type\": \"contains\"\n    },\n    {\n      \"parent\": \"d91fe3ae6bb15cad\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f4585c65c0a5b26a\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f4ea2c844b65a026\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f5bca9d628ab321f\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f83d629168e25cce\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    },\n    {\n      \"parent\": \"f9418986cc24a153\",\n      \"child\": \"af7261c65fbd5345\",\n      \"type\": \"evident-by\"\n    }\n  ],\n  \"files\": [\n    {\n      \"id\": \"af7261c65fbd5345\",\n      \"location\": {\n        \"path\": \"/sbom-test-gradle-0.0.1-SNAPSHOT.jar\"\n      }\n    }\n  ],\n  \"source\": {\n    \"id\": \"d2ff433e51158ef9a80dae682491d6500e9070bb143038bc0756d49fda3ad416\",\n    \"name\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n    \"version\": \"sha256:f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\",\n    \"type\": \"file\",\n    \"metadata\": {\n      \"path\": \"sbom-test-gradle-0.0.1-SNAPSHOT.jar\",\n      \"digests\": [\n        {\n          \"algorithm\": \"sha256\",\n          \"value\": \"f1802eb27e84114cfd7213ec83534a4b3219da6c4b2dcc827e0130b69ffa63b9\"\n        }\n      ],\n      \"mimeType\": \"application/jar\"\n    }\n  },\n  \"distro\": {},\n  \"descriptor\": {\n    \"name\": \"syft\",\n    \"version\": \"0.105.0\",\n    \"configuration\": {\n      \"catalogers\": {\n        \"requested\": {\n          \"default\": [\n            \"directory\"\n          ]\n        },\n        \"used\": [\n          \"alpm-db-cataloger\",\n          \"apk-db-cataloger\",\n          \"binary-cataloger\",\n          \"cocoapods-cataloger\",\n          \"conan-cataloger\",\n          \"dart-pubspec-lock-cataloger\",\n          \"dotnet-deps-cataloger\",\n          \"dotnet-portable-executable-cataloger\",\n          \"dpkg-db-cataloger\",\n          \"elixir-mix-lock-cataloger\",\n          \"erlang-otp-application-cataloger\",\n          \"erlang-rebar-lock-cataloger\",\n          \"github-action-workflow-usage-cataloger\",\n          \"github-actions-usage-cataloger\",\n          \"go-module-binary-cataloger\",\n          \"go-module-file-cataloger\",\n          \"graalvm-native-image-cataloger\",\n          \"haskell-cataloger\",\n          \"java-archive-cataloger\",\n          \"java-gradle-lockfile-cataloger\",\n          \"java-pom-cataloger\",\n          \"javascript-lock-cataloger\",\n          \"linux-kernel-cataloger\",\n          \"nix-store-cataloger\",\n          \"php-composer-lock-cataloger\",\n          \"portage-cataloger\",\n          \"python-installed-package-cataloger\",\n          \"python-package-cataloger\",\n          \"rpm-archive-cataloger\",\n          \"rpm-db-cataloger\",\n          \"ruby-gemfile-cataloger\",\n          \"ruby-gemspec-cataloger\",\n          \"rust-cargo-lock-cataloger\",\n          \"swift-package-manager-cataloger\",\n          \"wordpress-plugins-cataloger\"\n        ]\n      },\n      \"data-generation\": {\n        \"generate-cpes\": true\n      },\n      \"files\": {\n        \"content\": {\n          \"globs\": null,\n          \"skip-files-above-size\": 0\n        },\n        \"hashers\": [\n          \"sha-1\",\n          \"sha-256\"\n        ],\n        \"selection\": \"owned-by-package\"\n      },\n      \"packages\": {\n        \"binary\": [\n          \"python-binary\",\n          \"python-binary-lib\",\n          \"pypy-binary-lib\",\n          \"go-binary\",\n          \"julia-binary\",\n          \"helm\",\n          \"redis-binary\",\n          \"java-binary-openjdk\",\n          \"java-binary-ibm\",\n          \"java-binary-oracle\",\n          \"nodejs-binary\",\n          \"go-binary-hint\",\n          \"busybox-binary\",\n          \"haproxy-binary\",\n          \"perl-binary\",\n          \"php-cli-binary\",\n          \"php-fpm-binary\",\n          \"php-apache-binary\",\n          \"php-composer-binary\",\n          \"httpd-binary\",\n          \"memcached-binary\",\n          \"traefik-binary\",\n          \"postgresql-binary\",\n          \"mysql-binary\",\n          \"mysql-binary\",\n          \"mysql-binary\",\n          \"xtrabackup-binary\",\n          \"mariadb-binary\",\n          \"rust-standard-library-linux\",\n          \"rust-standard-library-macos\",\n          \"ruby-binary\",\n          \"erlang-binary\",\n          \"consul-binary\",\n          \"nginx-binary\",\n          \"bash-binary\",\n          \"openssl-binary\",\n          \"gcc-binary\",\n          \"wordpress-cli-binary\"\n        ],\n        \"golang\": {\n          \"local-mod-cache-dir\": \"/home/user/go/pkg/mod\",\n          \"main-module-version\": {\n            \"from-build-settings\": true,\n            \"from-contents\": true,\n            \"from-ld-flags\": true\n          },\n          \"proxies\": [\n            \"https://proxy.golang.org\",\n            \"direct\"\n          ],\n          \"search-local-mod-cache-licenses\": false,\n          \"search-remote-licenses\": false\n        },\n        \"java-archive\": {\n          \"include-indexed-archives\": true,\n          \"include-unindexed-archives\": false,\n          \"maven-base-url\": \"https://repo1.maven.org/maven2\",\n          \"max-parent-recursive-depth\": 5,\n          \"use-network\": false\n        },\n        \"javascript\": {\n          \"npm-base-url\": \"https://registry.npmjs.org\",\n          \"search-remote-licenses\": false\n        },\n        \"linux-kernel\": {\n          \"catalog-modules\": true\n        },\n        \"python\": {\n          \"guess-unpinned-requirements\": false\n        }\n      },\n      \"relationships\": {\n        \"exclude-binary-packages-with-file-ownership-overlap\": true,\n        \"package-file-ownership\": true,\n        \"package-file-ownership-overlap\": true\n      },\n      \"search\": {\n        \"scope\": \"squashed\"\n      }\n    }\n  },\n  \"schema\": {\n    \"version\": \"16.0.4\",\n    \"url\": \"https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-16.0.4.json\"\n  }\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/testFixtures/java/org/springframework/boot/actuate/endpoint/web/test/WebEndpointInfrastructureProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.test;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\n\n/**\n * Strategy interface to provide the web endpoint configuration for a target\n * {@linkplain Infrastructure infrastructure}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic interface WebEndpointInfrastructureProvider {\n\n\t/**\n\t * Specify if the given {@link Infrastructure} is supported.\n\t * @param infrastructure the infrastructure to target\n\t * @return {@code true} if this instance can provide the configuration\n\t */\n\tboolean supports(Infrastructure infrastructure);\n\n\t/**\n\t * Return the configuration to use for the given {@code infrastructure}.\n\t * @param infrastructure the infrastructure to target\n\t * @return the configuration for that infrastructure\n\t */\n\tList<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/testFixtures/java/org/springframework/boot/actuate/endpoint/web/test/WebEndpointTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.test;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.junit.jupiter.api.TestTemplate;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTestInvocationContextProvider.WebEndpointsInvocationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Signals that a test should be run against one or more of the web endpoint\n * infrastructure implementations (Jersey, Web MVC, and WebFlux).\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\n@TestTemplate\n@ExtendWith(WebEndpointTestInvocationContextProvider.class)\npublic @interface WebEndpointTest {\n\n\t/**\n\t * The infrastructure against which the test should run.\n\t * @return the infrastructure to run the tests against\n\t */\n\tInfrastructure[] infrastructure() default { Infrastructure.JERSEY, Infrastructure.MVC, Infrastructure.WEBFLUX };\n\n\tenum Infrastructure {\n\n\t\t/**\n\t\t * Actuator running on the Jersey-based infrastructure.\n\t\t */\n\t\tJERSEY(\"Jersey\"),\n\n\t\t/**\n\t\t * Actuator running on the WebMVC-based infrastructure.\n\t\t */\n\t\tMVC(\"WebMvc\"),\n\n\t\t/**\n\t\t * Actuator running on the WebFlux-based infrastructure.\n\t\t */\n\t\tWEBFLUX(\"WebFlux\");\n\n\t\tprivate final String name;\n\n\t\tInfrastructure(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tWebEndpointsInvocationContext createInvocationContext(\n\t\t\t\tFunction<List<Class<?>>, ConfigurableApplicationContext> contextFactory) {\n\t\t\treturn new WebEndpointsInvocationContext(this.name, contextFactory);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/testFixtures/java/org/springframework/boot/actuate/endpoint/web/test/WebEndpointTestInvocationContextProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.endpoint.web.test;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolver;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContext;\nimport org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;\nimport org.junit.platform.commons.util.AnnotationUtils;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\nimport org.springframework.boot.web.server.context.WebServerInitializedEvent;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;\n\n/**\n * {@link TestTemplateInvocationContextProvider} for\n * {@link WebEndpointTest @WebEndpointTest}.\n *\n * @author Andy Wilkinson`\n * @author Stephane Nicoll\n */\nclass WebEndpointTestInvocationContextProvider implements TestTemplateInvocationContextProvider {\n\n\tprivate final Map<Infrastructure, List<Class<?>>> infrastructures;\n\n\tprivate final Map<Infrastructure, Function<List<Class<?>>, ConfigurableApplicationContext>> contextFactories;\n\n\tWebEndpointTestInvocationContextProvider() {\n\t\tthis.infrastructures = new HashMap<>();\n\t\tList<WebEndpointInfrastructureProvider> providers = SpringFactoriesLoader\n\t\t\t.loadFactories(WebEndpointInfrastructureProvider.class, getClass().getClassLoader());\n\t\tStream.of(Infrastructure.values())\n\t\t\t.forEach((infrastructure) -> providers.stream()\n\t\t\t\t.filter((provider) -> provider.supports(infrastructure))\n\t\t\t\t.findFirst()\n\t\t\t\t.ifPresent((provider) -> this.infrastructures.put(infrastructure,\n\t\t\t\t\t\tprovider.getInfrastructureConfiguration(infrastructure))));\n\t\tthis.contextFactories = Map.of(Infrastructure.JERSEY, this::createJerseyContext, Infrastructure.MVC,\n\t\t\t\tthis::createWebMvcContext, Infrastructure.WEBFLUX, this::createWebFluxContext);\n\t}\n\n\t@Override\n\tpublic boolean supportsTestTemplate(ExtensionContext context) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(\n\t\t\tExtensionContext extensionContext) {\n\t\tWebEndpointTest webEndpointTest = AnnotationUtils\n\t\t\t.findAnnotation(extensionContext.getRequiredTestMethod(), WebEndpointTest.class)\n\t\t\t.orElseThrow(() -> new IllegalStateException(\"Unable to find WebEndpointTest annotation on %s\"\n\t\t\t\t.formatted(extensionContext.getRequiredTestMethod())));\n\t\treturn Stream.of(webEndpointTest.infrastructure()).distinct().map(this::createInvocationContext);\n\t}\n\n\tprivate WebEndpointsInvocationContext createInvocationContext(Infrastructure infrastructure) {\n\t\treturn infrastructure.createInvocationContext(this.contextFactories.get(infrastructure));\n\t}\n\n\tprivate ConfigurableApplicationContext createJerseyContext(List<Class<?>> classes) {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tclasses.addAll(getEndpointInfrastructureConfiguration(Infrastructure.JERSEY));\n\t\tcontext.register(ClassUtils.toClassArray(classes));\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\tprivate ConfigurableApplicationContext createWebMvcContext(List<Class<?>> classes) {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tclasses.addAll(getEndpointInfrastructureConfiguration(Infrastructure.MVC));\n\t\tcontext.register(ClassUtils.toClassArray(classes));\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\tprivate ConfigurableApplicationContext createWebFluxContext(List<Class<?>> classes) {\n\t\tAnnotationConfigReactiveWebServerApplicationContext context = new AnnotationConfigReactiveWebServerApplicationContext();\n\t\tclasses.addAll(getEndpointInfrastructureConfiguration(Infrastructure.WEBFLUX));\n\t\tcontext.register(ClassUtils.toClassArray(classes));\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\tprivate List<Class<?>> getEndpointInfrastructureConfiguration(Infrastructure infrastructure) {\n\t\tList<Class<?>> configurationClasses = new ArrayList<>();\n\t\tconfigurationClasses.add(EndpointBaseConfiguration.class);\n\t\tList<Class<?>> endpointConfiguration = this.infrastructures.get(infrastructure);\n\t\tif (endpointConfiguration == null) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"No endpoint infrastructure configuration found for \" + infrastructure.name());\n\t\t}\n\t\tconfigurationClasses.addAll(endpointConfiguration);\n\t\treturn configurationClasses;\n\t}\n\n\tstatic class WebEndpointsInvocationContext\n\t\t\timplements TestTemplateInvocationContext, BeforeEachCallback, AfterEachCallback, ParameterResolver {\n\n\t\tprivate static final Duration TIMEOUT = Duration.ofMinutes(5);\n\n\t\tprivate final String name;\n\n\t\tprivate final Function<List<Class<?>>, ConfigurableApplicationContext> contextFactory;\n\n\t\tprivate ConfigurableApplicationContext context;\n\n\t\t<T extends ConfigurableApplicationContext & AnnotationConfigRegistry> WebEndpointsInvocationContext(String name,\n\t\t\t\tFunction<List<Class<?>>, ConfigurableApplicationContext> contextFactory) {\n\t\t\tthis.name = name;\n\t\t\tthis.contextFactory = contextFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic void beforeEach(ExtensionContext extensionContext) throws Exception {\n\t\t\tList<Class<?>> configurationClasses = Stream\n\t\t\t\t.of(extensionContext.getRequiredTestClass().getDeclaredClasses())\n\t\t\t\t.filter(this::isConfiguration)\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t\tthis.context = this.contextFactory.apply(configurationClasses);\n\t\t}\n\n\t\tprivate boolean isConfiguration(Class<?> candidate) {\n\t\t\treturn MergedAnnotations.from(candidate, SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\t\tif (this.context != null) {\n\t\t\t\tthis.context.close();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\tClass<?> type = parameterContext.getParameter().getType();\n\t\t\treturn type.equals(WebTestClient.class) || type.isAssignableFrom(ConfigurableApplicationContext.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\t\tClass<?> type = parameterContext.getParameter().getType();\n\t\t\tif (type.equals(WebTestClient.class)) {\n\t\t\t\treturn createWebTestClient();\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn this.context;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Extension> getAdditionalExtensions() {\n\t\t\treturn Collections.singletonList(this);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDisplayName(int invocationIndex) {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tprivate WebTestClient createWebTestClient() {\n\t\t\tDefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(\n\t\t\t\t\t\"http://localhost:\" + determinePort());\n\t\t\turiBuilderFactory.setEncodingMode(EncodingMode.NONE);\n\t\t\treturn WebTestClient.bindToServer()\n\t\t\t\t.uriBuilderFactory(uriBuilderFactory)\n\t\t\t\t.responseTimeout(TIMEOUT)\n\t\t\t\t.codecs((codecs) -> codecs.defaultCodecs().maxInMemorySize(-1))\n\t\t\t\t.filter((request, next) -> {\n\t\t\t\t\tif (HttpMethod.GET == request.method()) {\n\t\t\t\t\t\treturn next.exchange(request).retry(10);\n\t\t\t\t\t}\n\t\t\t\t\treturn next.exchange(request);\n\t\t\t\t})\n\t\t\t\t.build();\n\t\t}\n\n\t\tprivate int determinePort() {\n\t\t\treturn this.context.getBean(PortHolder.class).getPort();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointBaseConfiguration implements ApplicationListener<WebServerInitializedEvent> {\n\n\t\tprivate final PortHolder portHolder = new PortHolder();\n\n\t\t@Bean\n\t\tPortHolder portHolder() {\n\t\t\treturn this.portHolder;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(WebServerInitializedEvent event) {\n\t\t\tthis.portHolder.setPort(event.getWebServer().getPort());\n\t\t}\n\n\t}\n\n\tprivate static final class PortHolder {\n\n\t\tprivate int port;\n\n\t\tprivate int getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tprivate void setPort(int port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator/src/testFixtures/java/org/springframework/boot/actuate/endpoint/web/test/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testing endpoints against one or more of the web endpoint infrastructure\n * implementations.\n */\npackage org.springframework.boot.actuate.endpoint.web.test;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Actuator AutoConfigure\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-autoconfigure\"))\n\tapi(project(\":module:spring-boot-actuator\"))\n\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework.security:spring-security-config\")\n\toptional(\"tools.jackson.core:jackson-databind\")\n\n\ttestFixturesImplementation(project(\":core:spring-boot-test\"))\n\ttestFixturesImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/OnEndpointElementCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * Base endpoint element condition. An element can be disabled globally through the\n * {@code defaults} name or individually through the name of the element.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 2.0.0\n */\npublic abstract class OnEndpointElementCondition extends SpringBootCondition {\n\n\tprivate final String prefix;\n\n\tprivate final Class<? extends Annotation> annotationType;\n\n\tprotected OnEndpointElementCondition(String prefix, Class<? extends Annotation> annotationType) {\n\t\tthis.prefix = prefix;\n\t\tthis.annotationType = annotationType;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tAnnotationAttributes annotationAttributes = AnnotationAttributes\n\t\t\t.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName()));\n\t\tAssert.state(annotationAttributes != null, \"'annotationAttributes' must not be null\");\n\t\tString endpointName = annotationAttributes.getString(\"value\");\n\t\tConditionOutcome outcome = getEndpointOutcome(context, endpointName);\n\t\tif (outcome != null) {\n\t\t\treturn outcome;\n\t\t}\n\t\treturn getDefaultOutcome(context, annotationAttributes);\n\t}\n\n\tprotected @Nullable ConditionOutcome getEndpointOutcome(ConditionContext context, String endpointName) {\n\t\tEnvironment environment = context.getEnvironment();\n\t\tString enabledProperty = this.prefix + endpointName + \".enabled\";\n\t\tif (environment.containsProperty(enabledProperty)) {\n\t\t\tboolean match = environment.getProperty(enabledProperty, Boolean.class, true);\n\t\t\treturn new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)\n\t\t\t\t.because(this.prefix + endpointName + \".enabled is \" + match));\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the default outcome that should be used if property is not set. By default\n\t * this method will use the {@code <prefix>.defaults.enabled} property, matching if it\n\t * is {@code true} or if it is not configured.\n\t * @param context the condition context\n\t * @param annotationAttributes the annotation attributes\n\t * @return the default outcome\n\t * @since 2.6.0\n\t */\n\tprotected ConditionOutcome getDefaultOutcome(ConditionContext context, AnnotationAttributes annotationAttributes) {\n\t\tboolean match = Boolean\n\t\t\t.parseBoolean(context.getEnvironment().getProperty(this.prefix + \"defaults.enabled\", \"true\"));\n\t\treturn new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)\n\t\t\t.because(this.prefix + \"defaults.enabled is considered \" + match));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/audit/AuditAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.audit;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.AuditEventRepository;\nimport org.springframework.boot.actuate.audit.listener.AbstractAuditListener;\nimport org.springframework.boot.actuate.audit.listener.AuditListener;\nimport org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener;\nimport org.springframework.boot.actuate.security.AbstractAuthorizationAuditListener;\nimport org.springframework.boot.actuate.security.AuthenticationAuditListener;\nimport org.springframework.boot.actuate.security.AuthorizationAuditListener;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link AuditEvent}s.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnBean(AuditEventRepository.class)\n@ConditionalOnBooleanProperty(name = \"management.auditevents.enabled\", matchIfMissing = true)\npublic final class AuditAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(AbstractAuditListener.class)\n\tAuditListener auditListener(AuditEventRepository auditEventRepository) {\n\t\treturn new AuditListener(auditEventRepository);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(AbstractAuthenticationAuditListener.class)\n\tAuthenticationAuditListener authenticationAuditListener() {\n\t\treturn new AuthenticationAuditListener();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(AbstractAuthorizationAuditListener.class)\n\tAuthorizationAuditListener authorizationAuditListener() {\n\t\treturn new AuthorizationAuditListener();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/audit/AuditEventsEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.audit;\n\nimport org.springframework.boot.actuate.audit.AuditEventRepository;\nimport org.springframework.boot.actuate.audit.AuditEventsEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link AuditEventsEndpoint}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @since 2.0.0\n */\n@AutoConfiguration(after = AuditAutoConfiguration.class)\n@ConditionalOnAvailableEndpoint(AuditEventsEndpoint.class)\npublic final class AuditEventsEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(AuditEventRepository.class)\n\tAuditEventsEndpoint auditEventsEndpoint(AuditEventRepository auditEventRepository) {\n\t\treturn new AuditEventsEndpoint(auditEventRepository);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/audit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator audit concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.audit;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/beans/BeansEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.beans;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.beans.BeansEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link BeansEndpoint}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(BeansEndpoint.class)\npublic final class BeansEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tBeansEndpoint beansEndpoint(ConfigurableApplicationContext applicationContext) {\n\t\treturn new BeansEndpoint(applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/beans/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator Spring Bean concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.beans;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/condition/ConditionsReportEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.condition;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.annotation.JsonPropertyOrder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Endpoint @Endpoint} to expose the {@link ConditionEvaluationReport}.\n *\n * @author Greg Turnquist\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Endpoint(id = \"conditions\")\npublic class ConditionsReportEndpoint {\n\n\tprivate final ConfigurableApplicationContext context;\n\n\tpublic ConditionsReportEndpoint(ConfigurableApplicationContext context) {\n\t\tthis.context = context;\n\t}\n\n\t@ReadOperation\n\tpublic ConditionsDescriptor conditions() {\n\t\tMap<@Nullable String, ContextConditionsDescriptor> contextConditionEvaluations = new HashMap<>();\n\t\tConfigurableApplicationContext target = this.context;\n\t\twhile (target != null) {\n\t\t\tcontextConditionEvaluations.put(target.getId(), new ContextConditionsDescriptor(target));\n\t\t\ttarget = getConfigurableParent(target);\n\t\t}\n\t\treturn new ConditionsDescriptor(contextConditionEvaluations);\n\t}\n\n\tprivate @Nullable ConfigurableApplicationContext getConfigurableParent(ConfigurableApplicationContext context) {\n\t\tApplicationContext parent = context.getParent();\n\t\tif (parent instanceof ConfigurableApplicationContext configurableParent) {\n\t\t\treturn configurableParent;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * A description of an application's condition evaluation.\n\t */\n\tpublic static final class ConditionsDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<@Nullable String, ContextConditionsDescriptor> contexts;\n\n\t\tprivate ConditionsDescriptor(Map<@Nullable String, ContextConditionsDescriptor> contexts) {\n\t\t\tthis.contexts = contexts;\n\t\t}\n\n\t\tpublic Map<@Nullable String, ContextConditionsDescriptor> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t}\n\n\t/**\n\t * A description of an application context's condition evaluation, primarily intended\n\t * for serialization to JSON.\n\t */\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic static final class ContextConditionsDescriptor {\n\n\t\tprivate final MultiValueMap<String, MessageAndConditionDescriptor> positiveMatches;\n\n\t\tprivate final Map<String, MessageAndConditionsDescriptor> negativeMatches;\n\n\t\tprivate final List<String> exclusions;\n\n\t\tprivate final Set<String> unconditionalClasses;\n\n\t\tprivate final @Nullable String parentId;\n\n\t\tpublic ContextConditionsDescriptor(ConfigurableApplicationContext context) {\n\t\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory());\n\t\t\tthis.positiveMatches = new LinkedMultiValueMap<>();\n\t\t\tthis.negativeMatches = new LinkedHashMap<>();\n\t\t\tthis.exclusions = report.getExclusions();\n\t\t\tthis.unconditionalClasses = report.getUnconditionalClasses();\n\t\t\treport.getConditionAndOutcomesBySource().forEach(this::add);\n\t\t\tthis.parentId = (context.getParent() != null) ? context.getParent().getId() : null;\n\t\t}\n\n\t\tprivate void add(String source, ConditionAndOutcomes conditionAndOutcomes) {\n\t\t\tString name = ClassUtils.getShortName(source);\n\t\t\tif (conditionAndOutcomes.isFullMatch()) {\n\t\t\t\tconditionAndOutcomes.forEach((conditionAndOutcome) -> this.positiveMatches.add(name,\n\t\t\t\t\t\tnew MessageAndConditionDescriptor(conditionAndOutcome)));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.negativeMatches.put(name, new MessageAndConditionsDescriptor(conditionAndOutcomes));\n\t\t\t}\n\t\t}\n\n\t\tpublic Map<String, List<MessageAndConditionDescriptor>> getPositiveMatches() {\n\t\t\treturn this.positiveMatches;\n\t\t}\n\n\t\tpublic Map<String, MessageAndConditionsDescriptor> getNegativeMatches() {\n\t\t\treturn this.negativeMatches;\n\t\t}\n\n\t\tpublic List<String> getExclusions() {\n\t\t\treturn this.exclusions;\n\t\t}\n\n\t\tpublic Set<String> getUnconditionalClasses() {\n\t\t\treturn this.unconditionalClasses;\n\t\t}\n\n\t\tpublic @Nullable String getParentId() {\n\t\t\treturn this.parentId;\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link ConditionAndOutcomes} to a JSON friendly structure.\n\t */\n\t@JsonPropertyOrder({ \"notMatched\", \"matched\" })\n\tpublic static class MessageAndConditionsDescriptor {\n\n\t\tprivate final List<MessageAndConditionDescriptor> notMatched = new ArrayList<>();\n\n\t\tprivate final List<MessageAndConditionDescriptor> matched = new ArrayList<>();\n\n\t\tpublic MessageAndConditionsDescriptor(ConditionAndOutcomes conditionAndOutcomes) {\n\t\t\tfor (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {\n\t\t\t\tList<MessageAndConditionDescriptor> target = (conditionAndOutcome.getOutcome().isMatch() ? this.matched\n\t\t\t\t\t\t: this.notMatched);\n\t\t\t\ttarget.add(new MessageAndConditionDescriptor(conditionAndOutcome));\n\t\t\t}\n\t\t}\n\n\t\tpublic List<MessageAndConditionDescriptor> getNotMatched() {\n\t\t\treturn this.notMatched;\n\t\t}\n\n\t\tpublic List<MessageAndConditionDescriptor> getMatched() {\n\t\t\treturn this.matched;\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link ConditionAndOutcome} to a JSON friendly structure.\n\t */\n\t@JsonPropertyOrder({ \"condition\", \"message\" })\n\tpublic static class MessageAndConditionDescriptor {\n\n\t\tprivate final String condition;\n\n\t\tprivate final String message;\n\n\t\tpublic MessageAndConditionDescriptor(ConditionAndOutcome conditionAndOutcome) {\n\t\t\tCondition condition = conditionAndOutcome.getCondition();\n\t\t\tConditionOutcome outcome = conditionAndOutcome.getOutcome();\n\t\t\tthis.condition = ClassUtils.getShortName(condition.getClass());\n\t\t\tif (StringUtils.hasLength(outcome.getMessage())) {\n\t\t\t\tthis.message = outcome.getMessage();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.message = outcome.isMatch() ? \"matched\" : \"did not match\";\n\t\t\t}\n\t\t}\n\n\t\tpublic String getCondition() {\n\t\t\treturn this.condition;\n\t\t}\n\n\t\tpublic String getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/condition/ConditionsReportEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.condition;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the\n * {@link ConditionsReportEndpoint}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(ConditionsReportEndpoint.class)\npublic final class ConditionsReportEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)\n\tConditionsReportEndpoint conditionsReportEndpoint(ConfigurableApplicationContext context) {\n\t\treturn new ConditionsReportEndpoint(context);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/condition/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator condition concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.condition;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/context/ShutdownEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.context;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.context.ShutdownEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link ShutdownEndpoint}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(ShutdownEndpoint.class)\npublic final class ShutdownEndpointAutoConfiguration {\n\n\t@Bean(destroyMethod = \"\")\n\t@ConditionalOnMissingBean\n\tShutdownEndpoint shutdownEndpoint() {\n\t\treturn new ShutdownEndpoint();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator Spring Context concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/context/properties/ConfigurationPropertiesReportEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.context.properties;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpointWebExtension;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the\n * {@link ConfigurationPropertiesReportEndpoint}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Chris Bono\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(ConfigurationPropertiesReportEndpoint.class)\n@EnableConfigurationProperties(ConfigurationPropertiesReportEndpointProperties.class)\npublic final class ConfigurationPropertiesReportEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint(\n\t\t\tConfigurationPropertiesReportEndpointProperties properties,\n\t\t\tObjectProvider<SanitizingFunction> sanitizingFunctions) {\n\t\treturn new ConfigurationPropertiesReportEndpoint(sanitizingFunctions.orderedStream().toList(),\n\t\t\t\tproperties.getShowValues());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(ConfigurationPropertiesReportEndpoint.class)\n\t@ConditionalOnAvailableEndpoint(exposure = EndpointExposure.WEB)\n\tConfigurationPropertiesReportEndpointWebExtension configurationPropertiesReportEndpointWebExtension(\n\t\t\tConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint,\n\t\t\tConfigurationPropertiesReportEndpointProperties properties) {\n\t\treturn new ConfigurationPropertiesReportEndpointWebExtension(configurationPropertiesReportEndpoint,\n\t\t\t\tproperties.getShowValues(), properties.getRoles());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/context/properties/ConfigurationPropertiesReportEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.context.properties;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for {@link ConfigurationPropertiesReportEndpoint}.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.endpoint.configprops\")\npublic class ConfigurationPropertiesReportEndpointProperties {\n\n\t/**\n\t * When to show unsanitized values.\n\t */\n\tprivate Show showValues = Show.NEVER;\n\n\t/**\n\t * Roles used to determine whether a user is authorized to be shown unsanitized\n\t * values. When empty, all authenticated users are authorized.\n\t */\n\tprivate final Set<String> roles = new HashSet<>();\n\n\tpublic Show getShowValues() {\n\t\treturn this.showValues;\n\t}\n\n\tpublic void setShowValues(Show showValues) {\n\t\tthis.showValues = showValues;\n\t}\n\n\tpublic Set<String> getRoles() {\n\t\treturn this.roles;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/context/properties/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator property concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.context.properties;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointConverter;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link Endpoint @Endpoint}\n * support.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Chao Chang\n * @since 2.0.0\n */\n@AutoConfiguration\npublic final class EndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tParameterValueMapper endpointOperationParameterMapper(@EndpointConverter ObjectProvider<Converter<?, ?>> converters,\n\t\t\t@EndpointConverter ObjectProvider<GenericConverter> genericConverters) {\n\t\tConversionService conversionService = createConversionService(converters.orderedStream().toList(),\n\t\t\t\tgenericConverters.orderedStream().toList());\n\t\treturn new ConversionServiceParameterValueMapper(conversionService);\n\t}\n\n\tprivate ConversionService createConversionService(List<Converter<?, ?>> converters,\n\t\t\tList<GenericConverter> genericConverters) {\n\t\tif (genericConverters.isEmpty() && converters.isEmpty()) {\n\t\t\treturn ApplicationConversionService.getSharedInstance();\n\t\t}\n\t\tApplicationConversionService conversionService = new ApplicationConversionService();\n\t\tconverters.forEach(conversionService::addConverter);\n\t\tgenericConverters.forEach(conversionService::addConverter);\n\t\treturn conversionService;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCachingOperationInvokerAdvisor endpointCachingOperationInvokerAdvisor(Environment environment) {\n\t\treturn new CachingOperationInvokerAdvisor(new EndpointIdTimeToLivePropertyFunction(environment));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(EndpointAccessResolver.class)\n\tPropertiesEndpointAccessResolver propertiesEndpointAccessResolver(Environment environment) {\n\t\treturn new PropertiesEndpointAccessResolver(environment);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointIdTimeToLivePropertyFunction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport java.time.Duration;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertyResolver;\n\n/**\n * Function for use with {@link CachingOperationInvokerAdvisor} that extracts caching\n * time-to-live from a {@link PropertyResolver resolved property}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass EndpointIdTimeToLivePropertyFunction implements Function<EndpointId, @Nullable Long> {\n\n\tprivate static final Bindable<Duration> DURATION = Bindable.of(Duration.class);\n\n\tprivate final Environment environment;\n\n\t/**\n\t * Create a new instance with the {@link PropertyResolver} to use.\n\t * @param environment the environment\n\t */\n\tEndpointIdTimeToLivePropertyFunction(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic @Nullable Long apply(EndpointId endpointId) {\n\t\tString name = String.format(\"management.endpoint.%s.cache.time-to-live\", endpointId.toLowerCaseString());\n\t\tBindResult<Duration> duration = Binder.get(this.environment).bind(name, DURATION);\n\t\treturn duration.map(Duration::toMillis).orElse(null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.core.env.PropertyResolver;\n\n/**\n * {@link EndpointAccessResolver} that resolves the permitted level of access to an\n * endpoint using the following properties:\n * <ol>\n * <li>{@code management.endpoint.<id>.access} or {@code management.endpoint.<id>.enabled}\n * (deprecated)\n * <li>{@code management.endpoints.access.default} or\n * {@code management.endpoints.enabled-by-default} (deprecated)\n * </ol>\n * The resulting access is capped using {@code management.endpoints.access.max-permitted}.\n *\n * @author Andy Wilkinson\n * @since 3.4.0\n */\npublic class PropertiesEndpointAccessResolver implements EndpointAccessResolver {\n\n\tprivate static final String DEFAULT_ACCESS_KEY = \"management.endpoints.access.default\";\n\n\tprivate static final String ENABLED_BY_DEFAULT_KEY = \"management.endpoints.enabled-by-default\";\n\n\tprivate final PropertyResolver properties;\n\n\tprivate final @Nullable Access endpointsDefaultAccess;\n\n\tprivate final Access maxPermittedAccess;\n\n\tprivate final Map<EndpointId, Access> accessCache = new ConcurrentHashMap<>();\n\n\tpublic PropertiesEndpointAccessResolver(PropertyResolver properties) {\n\t\tthis.properties = properties;\n\t\tthis.endpointsDefaultAccess = determineDefaultAccess(properties);\n\t\tthis.maxPermittedAccess = properties.getProperty(\"management.endpoints.access.max-permitted\", Access.class,\n\t\t\t\tAccess.UNRESTRICTED);\n\t}\n\n\tprivate static @Nullable Access determineDefaultAccess(PropertyResolver properties) {\n\t\tAccess defaultAccess = properties.getProperty(DEFAULT_ACCESS_KEY, Access.class);\n\t\tBoolean endpointsEnabledByDefault = properties.getProperty(ENABLED_BY_DEFAULT_KEY, Boolean.class);\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\tentries.put(DEFAULT_ACCESS_KEY, defaultAccess);\n\t\t\tentries.put(ENABLED_BY_DEFAULT_KEY, endpointsEnabledByDefault);\n\t\t});\n\t\tif (defaultAccess != null) {\n\t\t\treturn defaultAccess;\n\t\t}\n\t\tif (endpointsEnabledByDefault != null) {\n\t\t\treturn endpointsEnabledByDefault ? org.springframework.boot.actuate.endpoint.Access.UNRESTRICTED\n\t\t\t\t\t: org.springframework.boot.actuate.endpoint.Access.NONE;\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Access accessFor(EndpointId endpointId, Access defaultAccess) {\n\t\treturn this.accessCache.computeIfAbsent(endpointId,\n\t\t\t\t(key) -> resolveAccess(endpointId.toLowerCaseString(), defaultAccess).cap(this.maxPermittedAccess));\n\t}\n\n\tprivate Access resolveAccess(String endpointId, Access defaultAccess) {\n\t\tString accessKey = \"management.endpoint.%s.access\".formatted(endpointId);\n\t\tString enabledKey = \"management.endpoint.%s.enabled\".formatted(endpointId);\n\t\tAccess access = this.properties.getProperty(accessKey, Access.class);\n\t\tBoolean enabled = this.properties.getProperty(enabledKey, Boolean.class);\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\tentries.put(accessKey, access);\n\t\t\tentries.put(enabledKey, enabled);\n\t\t});\n\t\tif (access != null) {\n\t\t\treturn access;\n\t\t}\n\t\tif (enabled != null) {\n\t\t\treturn (enabled) ? Access.UNRESTRICTED : Access.NONE;\n\t\t}\n\t\treturn (this.endpointsDefaultAccess != null) ? this.endpointsDefaultAccess : defaultAccess;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnAvailableEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.condition;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link Conditional @Conditional} that checks whether an endpoint is available. An\n * endpoint is considered available if it is both enabled and exposed on the specified\n * technologies.\n * <p>\n * Matches access according to the endpoint's specific {@link Environment} property,\n * falling back to {@code management.endpoints.default-access} or failing that\n * {@link Endpoint#defaultAccess()}.\n * <p>\n * Matches exposure according to any of the {@code management.endpoints.web.exposure.<id>}\n * or {@code management.endpoints.jmx.exposure.<id>} specific properties or failing that\n * to whether any {@link EndpointExposureOutcomeContributor} exposes the endpoint.\n * <p>\n * Both enablement and exposure conditions should match for the endpoint to be considered\n * available.\n * <p>\n * When placed on a {@code @Bean} method, the endpoint defaults to the return type of the\n * factory method:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * public class MyConfiguration {\n *\n *     &#064;ConditionalOnAvailableEndpoint\n *     &#064;Bean\n *     public MyEndpoint myEndpoint() {\n *         ...\n *     }\n *\n * }</pre>\n * <p>\n * It is also possible to use the same mechanism for extensions:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * public class MyConfiguration {\n *\n *     &#064;ConditionalOnAvailableEndpoint\n *     &#064;Bean\n *     public MyEndpointWebExtension myEndpointWebExtension() {\n *         ...\n *     }\n *\n * }</pre>\n * <p>\n * In the sample above, {@code MyEndpointWebExtension} will be created if the endpoint is\n * available as defined by the rules above. {@code MyEndpointWebExtension} must be a\n * regular extension that refers to an endpoint, something like:\n *\n * <pre class=\"code\">\n * &#064;EndpointWebExtension(endpoint = MyEndpoint.class)\n * public class MyEndpointWebExtension {\n *\n * }</pre>\n * <p>\n * Alternatively, the target endpoint can be manually specified for components that should\n * only be created when a given endpoint is available:\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * public class MyConfiguration {\n *\n *     &#064;ConditionalOnAvailableEndpoint(endpoint = MyEndpoint.class)\n *     &#064;Bean\n *     public MyComponent myComponent() {\n *         ...\n *     }\n *\n * }</pre>\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.2.0\n * @see Endpoint\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@Documented\n@Conditional(OnAvailableEndpointCondition.class)\npublic @interface ConditionalOnAvailableEndpoint {\n\n\t/**\n\t * Alias for {@link #endpoint()}.\n\t * @return the endpoint type to check\n\t * @since 3.4.0\n\t */\n\t@AliasFor(attribute = \"endpoint\")\n\tClass<?> value() default Void.class;\n\n\t/**\n\t * The endpoint type that should be checked. Inferred when the return type of the\n\t * {@code @Bean} method is either an {@link Endpoint @Endpoint} or an\n\t * {@link EndpointExtension @EndpointExtension}.\n\t * @return the endpoint type to check\n\t */\n\t@AliasFor(attribute = \"value\")\n\tClass<?> endpoint() default Void.class;\n\n\t/**\n\t * Technologies to check the exposure of the endpoint on while considering it to be\n\t * available.\n\t * @return the technologies to check\n\t * @since 2.6.0\n\t */\n\tEndpointExposure[] exposure() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/EndpointExposureOutcomeContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.condition;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.core.env.Environment;\n\n/**\n * Contributor loaded from the {@code spring.factories} file and used by\n * {@link ConditionalOnAvailableEndpoint @ConditionalOnAvailableEndpoint} to determine if\n * an endpoint is exposed. If any contributor returns a {@link ConditionOutcome#isMatch()\n * matching} {@link ConditionOutcome} then the endpoint is considered exposed.\n * <p>\n * Implementations may declare a constructor that accepts an {@link Environment} argument.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 3.4.0\n */\npublic interface EndpointExposureOutcomeContributor {\n\n\t/**\n\t * Return if the given endpoint is exposed for the given set of exposure technologies.\n\t * @param endpointId the endpoint ID\n\t * @param exposures the exposure technologies to check\n\t * @param message the condition message builder\n\t * @return a {@link ConditionOutcome#isMatch() matching} {@link ConditionOutcome} if\n\t * the endpoint is exposed or {@code null} if the contributor should not apply\n\t */\n\t@Nullable ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,\n\t\t\tConditionMessage.Builder message);\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/OnAvailableEndpointCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.condition;\n\nimport java.util.Arrays;\nimport java.util.EnumSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.PropertiesEndpointAccessResolver;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ConcurrentReferenceHashMap;\n\n/**\n * A condition that checks if an endpoint is available (i.e. accessible and exposed).\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @see ConditionalOnAvailableEndpoint\n */\nclass OnAvailableEndpointCondition extends SpringBootCondition {\n\n\tprivate static final String JMX_ENABLED_KEY = \"spring.jmx.enabled\";\n\n\tprivate static final Map<Environment, EndpointAccessResolver> accessResolversCache = new ConcurrentReferenceHashMap<>();\n\n\tprivate static final Map<Environment, Set<EndpointExposureOutcomeContributor>> exposureOutcomeContributorsCache = new ConcurrentReferenceHashMap<>();\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMergedAnnotation<ConditionalOnAvailableEndpoint> conditionAnnotation = metadata.getAnnotations()\n\t\t\t.get(ConditionalOnAvailableEndpoint.class);\n\t\tClass<?> target = getTarget(context, metadata, conditionAnnotation);\n\t\tMergedAnnotation<Endpoint> endpointAnnotation = getEndpointAnnotation(target);\n\t\treturn getMatchOutcome(context, conditionAnnotation, endpointAnnotation);\n\t}\n\n\tprivate Class<?> getTarget(ConditionContext context, AnnotatedTypeMetadata metadata,\n\t\t\tMergedAnnotation<ConditionalOnAvailableEndpoint> condition) {\n\t\tClass<?> target = condition.getClass(\"endpoint\");\n\t\tif (target != Void.class) {\n\t\t\treturn target;\n\t\t}\n\t\tAssert.state(metadata instanceof MethodMetadata && metadata.isAnnotated(Bean.class.getName()),\n\t\t\t\t\"EndpointCondition must be used on @Bean methods when the endpoint is not specified\");\n\t\tMethodMetadata methodMetadata = (MethodMetadata) metadata;\n\t\ttry {\n\t\t\treturn ClassUtils.forName(methodMetadata.getReturnTypeName(), context.getClassLoader());\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to extract endpoint id for \"\n\t\t\t\t\t+ methodMetadata.getDeclaringClassName() + \".\" + methodMetadata.getMethodName(), ex);\n\t\t}\n\t}\n\n\tprotected MergedAnnotation<Endpoint> getEndpointAnnotation(Class<?> target) {\n\t\tMergedAnnotations annotations = MergedAnnotations.from(target, SearchStrategy.TYPE_HIERARCHY);\n\t\tMergedAnnotation<Endpoint> endpoint = annotations.get(Endpoint.class);\n\t\tif (endpoint.isPresent()) {\n\t\t\treturn endpoint;\n\t\t}\n\t\tMergedAnnotation<EndpointExtension> extension = annotations.get(EndpointExtension.class);\n\t\tAssert.state(extension.isPresent(), \"No endpoint is specified and the return type of the @Bean method is \"\n\t\t\t\t+ \"neither an @Endpoint, nor an @EndpointExtension\");\n\t\treturn getEndpointAnnotation(extension.getClass(\"endpoint\"));\n\t}\n\n\tprivate ConditionOutcome getMatchOutcome(ConditionContext context,\n\t\t\tMergedAnnotation<ConditionalOnAvailableEndpoint> conditionAnnotation,\n\t\t\tMergedAnnotation<Endpoint> endpointAnnotation) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnAvailableEndpoint.class);\n\t\tEnvironment environment = context.getEnvironment();\n\t\tEndpointId endpointId = EndpointId.of(environment, endpointAnnotation.getString(\"id\"));\n\t\tConditionOutcome accessOutcome = getAccessOutcome(environment, endpointAnnotation, endpointId, message);\n\t\tif (!accessOutcome.isMatch()) {\n\t\t\treturn accessOutcome;\n\t\t}\n\t\tConditionOutcome exposureOutcome = getExposureOutcome(context, conditionAnnotation, endpointAnnotation,\n\t\t\t\tendpointId, message);\n\t\treturn (exposureOutcome != null) ? exposureOutcome : ConditionOutcome.noMatch(message.because(\"not exposed\"));\n\t}\n\n\tprivate ConditionOutcome getAccessOutcome(Environment environment, MergedAnnotation<Endpoint> endpointAnnotation,\n\t\t\tEndpointId endpointId, ConditionMessage.Builder message) {\n\t\tAccess defaultAccess = endpointAnnotation.getEnum(\"defaultAccess\", Access.class);\n\t\tAccess access = getAccess(environment, endpointId, defaultAccess);\n\t\treturn new ConditionOutcome(access != Access.NONE,\n\t\t\t\tmessage.because(\"the configured access for endpoint '%s' is %s\".formatted(endpointId, access)));\n\t}\n\n\tprivate Access getAccess(Environment environment, EndpointId endpointId, Access defaultAccess) {\n\t\treturn accessResolversCache.computeIfAbsent(environment, PropertiesEndpointAccessResolver::new)\n\t\t\t.accessFor(endpointId, defaultAccess);\n\t}\n\n\tprivate @Nullable ConditionOutcome getExposureOutcome(ConditionContext context,\n\t\t\tMergedAnnotation<ConditionalOnAvailableEndpoint> conditionAnnotation,\n\t\t\tMergedAnnotation<Endpoint> endpointAnnotation, EndpointId endpointId, Builder message) {\n\t\tSet<EndpointExposure> exposures = getExposures(conditionAnnotation);\n\t\tSet<EndpointExposureOutcomeContributor> outcomeContributors = getExposureOutcomeContributors(context);\n\t\tfor (EndpointExposureOutcomeContributor outcomeContributor : outcomeContributors) {\n\t\t\tConditionOutcome outcome = outcomeContributor.getExposureOutcome(endpointId, exposures, message);\n\t\t\tif (outcome != null && outcome.isMatch()) {\n\t\t\t\treturn outcome;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Set<EndpointExposure> getExposures(MergedAnnotation<ConditionalOnAvailableEndpoint> conditionAnnotation) {\n\t\tEndpointExposure[] exposures = conditionAnnotation.getEnumArray(\"exposure\", EndpointExposure.class);\n\t\treturn (exposures.length == 0) ? EnumSet.allOf(EndpointExposure.class)\n\t\t\t\t: EnumSet.copyOf(Arrays.asList(exposures));\n\t}\n\n\tprivate Set<EndpointExposureOutcomeContributor> getExposureOutcomeContributors(ConditionContext context) {\n\t\tEnvironment environment = context.getEnvironment();\n\t\tSet<EndpointExposureOutcomeContributor> contributors = exposureOutcomeContributorsCache.get(environment);\n\t\tif (contributors == null) {\n\t\t\tcontributors = new LinkedHashSet<>();\n\t\t\tcontributors.add(new StandardExposureOutcomeContributor(environment, EndpointExposure.WEB));\n\t\t\tif (environment.getProperty(JMX_ENABLED_KEY, Boolean.class, false)) {\n\t\t\t\tcontributors.add(new StandardExposureOutcomeContributor(environment, EndpointExposure.JMX));\n\t\t\t}\n\t\t\tcontributors.addAll(loadExposureOutcomeContributors(context.getClassLoader(), environment));\n\t\t\texposureOutcomeContributorsCache.put(environment, contributors);\n\t\t}\n\t\treturn contributors;\n\t}\n\n\tprivate List<EndpointExposureOutcomeContributor> loadExposureOutcomeContributors(@Nullable ClassLoader classLoader,\n\t\t\tEnvironment environment) {\n\t\tArgumentResolver argumentResolver = ArgumentResolver.of(Environment.class, environment);\n\t\treturn SpringFactoriesLoader.forDefaultResourceLocation(classLoader)\n\t\t\t.load(EndpointExposureOutcomeContributor.class, argumentResolver);\n\t}\n\n\t/**\n\t * Standard {@link EndpointExposureOutcomeContributor}.\n\t */\n\tprivate static class StandardExposureOutcomeContributor implements EndpointExposureOutcomeContributor {\n\n\t\tprivate final EndpointExposure exposure;\n\n\t\tprivate final String property;\n\n\t\tprivate final IncludeExcludeEndpointFilter<?> filter;\n\n\t\tStandardExposureOutcomeContributor(Environment environment, EndpointExposure exposure) {\n\t\t\tthis.exposure = exposure;\n\t\t\tString name = exposure.name().toLowerCase(Locale.ROOT).replace('_', '-');\n\t\t\tthis.property = \"management.endpoints.\" + name + \".exposure\";\n\t\t\tthis.filter = new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, environment, this.property,\n\t\t\t\t\texposure.getDefaultIncludes());\n\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,\n\t\t\t\tConditionMessage.Builder message) {\n\t\t\tif (exposures.contains(this.exposure) && this.filter.match(endpointId)) {\n\t\t\t\treturn ConditionOutcome\n\t\t\t\t\t.match(message.because(\"marked as exposed by a '\" + this.property + \"' property\"));\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint auto-configuration conditions.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.endpoint.condition;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/expose/EndpointExposure.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.expose;\n\n/**\n * Technologies that can be used to expose an endpoint.\n *\n * @author Phillip Webb\n * @since 2.6.0\n */\npublic enum EndpointExposure {\n\n\t/**\n\t * Exposed over a JMX endpoint.\n\t */\n\tJMX(\"health\"),\n\n\t/**\n\t * Exposed over a web endpoint.\n\t */\n\tWEB(\"health\");\n\n\tprivate final String[] defaultIncludes;\n\n\tEndpointExposure(String... defaultIncludes) {\n\t\tthis.defaultIncludes = defaultIncludes;\n\t}\n\n\t/**\n\t * Return the default set of include patterns.\n\t * @return the default includes\n\t */\n\tpublic String[] getDefaultIncludes() {\n\t\treturn this.defaultIncludes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/expose/IncludeExcludeEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.expose;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EndpointFilter} that will filter endpoints based on {@code include} and\n * {@code exclude} patterns.\n *\n * @param <E> the endpoint type\n * @author Phillip Webb\n * @since 2.2.7\n */\npublic class IncludeExcludeEndpointFilter<E extends ExposableEndpoint<?>> implements EndpointFilter<E> {\n\n\tprivate final Class<E> endpointType;\n\n\tprivate final EndpointPatterns include;\n\n\tprivate final EndpointPatterns defaultIncludes;\n\n\tprivate final EndpointPatterns exclude;\n\n\t/**\n\t * Create a new {@link IncludeExcludeEndpointFilter} with include/exclude rules bound\n\t * from the {@link Environment}.\n\t * @param endpointType the endpoint type that should be considered (other types always\n\t * match)\n\t * @param environment the environment containing the properties\n\t * @param prefix the property prefix to bind\n\t * @param defaultIncludes the default {@code includes} to use when none are specified.\n\t */\n\tpublic IncludeExcludeEndpointFilter(Class<E> endpointType, Environment environment, String prefix,\n\t\t\tString... defaultIncludes) {\n\t\tthis(endpointType, environment, prefix, new EndpointPatterns(defaultIncludes));\n\t}\n\n\t/**\n\t * Create a new {@link IncludeExcludeEndpointFilter} with specific include/exclude\n\t * rules.\n\t * @param endpointType the endpoint type that should be considered (other types always\n\t * match)\n\t * @param include the include patterns\n\t * @param exclude the exclude patterns\n\t * @param defaultIncludes the default {@code includes} to use when none are specified.\n\t */\n\tpublic IncludeExcludeEndpointFilter(Class<E> endpointType, Collection<String> include, Collection<String> exclude,\n\t\t\tString... defaultIncludes) {\n\t\tthis(endpointType, include, exclude, new EndpointPatterns(defaultIncludes));\n\t}\n\n\tprivate IncludeExcludeEndpointFilter(Class<E> endpointType, Environment environment, String prefix,\n\t\t\tEndpointPatterns defaultIncludes) {\n\t\tAssert.notNull(endpointType, \"'endpointType' must not be null\");\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tAssert.hasText(prefix, \"'prefix' must not be empty\");\n\t\tAssert.notNull(defaultIncludes, \"'defaultIncludes' must not be null\");\n\t\tBinder binder = Binder.get(environment);\n\t\tthis.endpointType = endpointType;\n\t\tthis.include = new EndpointPatterns(bind(binder, prefix + \".include\"));\n\t\tthis.defaultIncludes = defaultIncludes;\n\t\tthis.exclude = new EndpointPatterns(bind(binder, prefix + \".exclude\"));\n\t}\n\n\tprivate IncludeExcludeEndpointFilter(Class<E> endpointType, Collection<String> include, Collection<String> exclude,\n\t\t\tEndpointPatterns defaultIncludes) {\n\t\tAssert.notNull(endpointType, \"'endpointType' Type must not be null\");\n\t\tAssert.notNull(defaultIncludes, \"'defaultIncludes' must not be null\");\n\t\tthis.endpointType = endpointType;\n\t\tthis.include = new EndpointPatterns(include);\n\t\tthis.defaultIncludes = defaultIncludes;\n\t\tthis.exclude = new EndpointPatterns(exclude);\n\t}\n\n\tprivate List<String> bind(Binder binder, String name) {\n\t\treturn binder.bind(name, Bindable.listOf(String.class)).orElseGet(ArrayList::new);\n\t}\n\n\t@Override\n\tpublic boolean match(E endpoint) {\n\t\tif (!this.endpointType.isInstance(endpoint)) {\n\t\t\t// Leave non-matching types for other filters\n\t\t\treturn true;\n\t\t}\n\t\treturn match(endpoint.getEndpointId());\n\t}\n\n\t/**\n\t * Return {@code true} if the filter matches.\n\t * @param endpointId the endpoint ID to check\n\t * @return {@code true} if the filter matches\n\t * @since 2.6.0\n\t */\n\tpublic final boolean match(EndpointId endpointId) {\n\t\treturn isIncluded(endpointId) && !isExcluded(endpointId);\n\t}\n\n\tprivate boolean isIncluded(EndpointId endpointId) {\n\t\tif (this.include.isEmpty()) {\n\t\t\treturn this.defaultIncludes.matches(endpointId);\n\t\t}\n\t\treturn this.include.matches(endpointId);\n\t}\n\n\tprivate boolean isExcluded(EndpointId endpointId) {\n\t\tif (this.exclude.isEmpty()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.exclude.matches(endpointId);\n\t}\n\n\t/**\n\t * A set of endpoint patterns used to match IDs.\n\t */\n\tprivate static class EndpointPatterns {\n\n\t\tprivate final boolean empty;\n\n\t\tprivate final boolean matchesAll;\n\n\t\tprivate final Set<EndpointId> endpointIds;\n\n\t\tEndpointPatterns(String @Nullable [] patterns) {\n\t\t\tthis((patterns != null) ? Arrays.asList(patterns) : null);\n\t\t}\n\n\t\tEndpointPatterns(@Nullable Collection<String> patterns) {\n\t\t\tpatterns = (patterns != null) ? patterns : Collections.emptySet();\n\t\t\tboolean matchesAll = false;\n\t\t\tSet<EndpointId> endpointIds = new LinkedHashSet<>();\n\t\t\tfor (String pattern : patterns) {\n\t\t\t\tif (\"*\".equals(pattern)) {\n\t\t\t\t\tmatchesAll = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tendpointIds.add(EndpointId.fromPropertyValue(pattern));\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.empty = patterns.isEmpty();\n\t\t\tthis.matchesAll = matchesAll;\n\t\t\tthis.endpointIds = endpointIds;\n\t\t}\n\n\t\tboolean isEmpty() {\n\t\t\treturn this.empty;\n\t\t}\n\n\t\tboolean matches(EndpointId endpointId) {\n\t\t\treturn this.matchesAll || this.endpointIds.contains(endpointId);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/expose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Endpoint exposure logic used for auto-configuration and conditions.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.endpoint.expose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/Jackson2EndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jackson;\n\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializationFeature;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Endpoint Jackson 2 support.\n *\n * @author Phillip Webb\n * @since 3.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@AutoConfiguration\n@ConditionalOnClass({ ObjectMapper.class, org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class })\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic final class Jackson2EndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBooleanProperty(name = \"management.endpoints.jackson2.isolated-object-mapper\", matchIfMissing = true)\n\torg.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper jackson2EndpointJsonMapper() {\n\t\tObjectMapper objectMapper = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json()\n\t\t\t.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,\n\t\t\t\t\tSerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)\n\t\t\t.serializationInclusion(Include.NON_NULL)\n\t\t\t.build();\n\t\treturn () -> objectMapper;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jackson;\n\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Endpoint Jackson support.\n *\n * @author Phillip Webb\n * @since 3.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(JsonMapper.class)\npublic final class JacksonEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBooleanProperty(name = \"management.endpoints.jackson.isolated-json-mapper\", matchIfMissing = true)\n\tEndpointJsonMapper endpointJsonMapper() {\n\t\tJsonMapper jsonMapper = JsonMapper.builder()\n\t\t\t.changeDefaultPropertyInclusion(\n\t\t\t\t\t(value) -> value.withValueInclusion(Include.NON_NULL).withContentInclusion(Include.NON_NULL))\n\t\t\t.build();\n\t\treturn () -> jsonMapper;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator Jackson auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jackson;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory;\nimport org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;\nimport org.springframework.boot.autoconfigure.jmx.JmxProperties;\nimport org.springframework.jmx.support.ObjectNameManager;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link EndpointObjectNameFactory} that generates standard {@link ObjectName} for\n * Actuator's endpoints.\n *\n * @author Stephane Nicoll\n */\nclass DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {\n\n\tprivate final JmxEndpointProperties properties;\n\n\tprivate final JmxProperties jmxProperties;\n\n\tprivate final @Nullable MBeanServer mBeanServer;\n\n\tprivate final @Nullable String contextId;\n\n\tDefaultEndpointObjectNameFactory(JmxEndpointProperties properties, JmxProperties jmxProperties,\n\t\t\t@Nullable MBeanServer mBeanServer, @Nullable String contextId) {\n\t\tthis.properties = properties;\n\t\tthis.jmxProperties = jmxProperties;\n\t\tthis.mBeanServer = mBeanServer;\n\t\tthis.contextId = contextId;\n\t}\n\n\t@Override\n\tpublic ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException {\n\t\tStringBuilder builder = new StringBuilder(determineDomain());\n\t\tbuilder.append(\":type=Endpoint\");\n\t\tbuilder.append(\",name=\").append(StringUtils.capitalize(endpoint.getEndpointId().toString()));\n\t\tString baseName = builder.toString();\n\t\tif (this.mBeanServer != null && hasMBean(baseName)) {\n\t\t\tbuilder.append(\",context=\").append(this.contextId);\n\t\t}\n\t\tif (this.jmxProperties.isUniqueNames()) {\n\t\t\tString identity = ObjectUtils.getIdentityHexString(endpoint);\n\t\t\tbuilder.append(\",identity=\").append(identity);\n\t\t}\n\t\tbuilder.append(getStaticNames());\n\t\treturn ObjectNameManager.getInstance(builder.toString());\n\t}\n\n\tprivate String determineDomain() {\n\t\tif (StringUtils.hasText(this.properties.getDomain())) {\n\t\t\treturn this.properties.getDomain();\n\t\t}\n\t\tif (StringUtils.hasText(this.jmxProperties.getDefaultDomain())) {\n\t\t\treturn this.jmxProperties.getDefaultDomain();\n\t\t}\n\t\treturn \"org.springframework.boot\";\n\t}\n\n\tprivate boolean hasMBean(String baseObjectName) throws MalformedObjectNameException {\n\t\tObjectName query = new ObjectName(baseObjectName + \",*\");\n\t\tAssert.state(this.mBeanServer != null, \"'mBeanServer' must not be null\");\n\t\treturn !this.mBeanServer.queryNames(query, null).isEmpty();\n\t}\n\n\tprivate String getStaticNames() {\n\t\tif (this.properties.getStaticNames().isEmpty()) {\n\t\t\treturn \"\";\n\t\t}\n\t\tStringBuilder builder = new StringBuilder();\n\t\tthis.properties.getStaticNames()\n\t\t\t.forEach((name, value) -> builder.append(\",\").append(name).append(\"=\").append(value));\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport javax.management.MBeanServer;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory;\nimport org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;\nimport org.springframework.boot.actuate.endpoint.jmx.JacksonJmxOperationResponseMapper;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxEndpointExporter;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperation;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxOperationResponseMapper;\nimport org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.autoconfigure.jmx.JmxProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for JMX {@link Endpoint @Endpoint}\n * support.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration(after = { JmxAutoConfiguration.class, EndpointAutoConfiguration.class })\n@EnableConfigurationProperties({ JmxEndpointProperties.class, JmxProperties.class })\n@ConditionalOnBooleanProperty(\"spring.jmx.enabled\")\npublic final class JmxEndpointAutoConfiguration {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final JmxEndpointProperties properties;\n\n\tprivate final JmxProperties jmxProperties;\n\n\tJmxEndpointAutoConfiguration(ApplicationContext applicationContext, JmxEndpointProperties properties,\n\t\t\tJmxProperties jmxProperties) {\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.properties = properties;\n\t\tthis.jmxProperties = jmxProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(JmxEndpointsSupplier.class)\n\tJmxEndpointDiscoverer jmxAnnotationEndpointDiscoverer(ParameterValueMapper parameterValueMapper,\n\t\t\tObjectProvider<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\tObjectProvider<EndpointFilter<ExposableJmxEndpoint>> endpointFilters,\n\t\t\tObjectProvider<OperationFilter<JmxOperation>> operationFilters) {\n\t\treturn new JmxEndpointDiscoverer(this.applicationContext, parameterValueMapper,\n\t\t\t\tinvokerAdvisors.orderedStream().toList(), endpointFilters.orderedStream().toList(),\n\t\t\t\toperationFilters.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = EndpointObjectNameFactory.class, search = SearchStrategy.CURRENT)\n\tDefaultEndpointObjectNameFactory endpointObjectNameFactory(MBeanServer mBeanServer) {\n\t\tString contextId = ObjectUtils.getIdentityHexString(this.applicationContext);\n\t\treturn new DefaultEndpointObjectNameFactory(this.properties, this.jmxProperties, mBeanServer, contextId);\n\t}\n\n\t@Bean\n\tIncludeExcludeEndpointFilter<ExposableJmxEndpoint> jmxIncludeExcludePropertyEndpointFilter() {\n\t\tJmxEndpointProperties.Exposure exposure = this.properties.getExposure();\n\t\treturn new IncludeExcludeEndpointFilter<>(ExposableJmxEndpoint.class, exposure.getInclude(),\n\t\t\t\texposure.getExclude(), EndpointExposure.JMX.getDefaultIncludes());\n\t}\n\n\t@Bean\n\tstatic LazyInitializationExcludeFilter eagerlyInitializeJmxEndpointExporter() {\n\t\treturn LazyInitializationExcludeFilter.forBeanTypes(JmxEndpointExporter.class);\n\t}\n\n\t@Bean\n\tOperationFilter<JmxOperation> jmxAccessPropertiesOperationFilter(EndpointAccessResolver endpointAccessResolver) {\n\t\treturn OperationFilter.byAccess(endpointAccessResolver);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JsonMapper.class)\n\tstatic class JmxJacksonEndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(MBeanServer.class)\n\t\tJmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer,\n\t\t\t\tEndpointObjectNameFactory endpointObjectNameFactory, ObjectProvider<JsonMapper> jsonMapper,\n\t\t\t\tJmxEndpointsSupplier jmxEndpointsSupplier) {\n\t\t\tJmxOperationResponseMapper responseMapper = new JacksonJmxOperationResponseMapper(\n\t\t\t\t\tjsonMapper.getIfAvailable());\n\t\t\treturn new JmxEndpointExporter(mBeanServer, endpointObjectNameFactory, responseMapper,\n\t\t\t\t\tjmxEndpointsSupplier.getEndpoints());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ObjectMapper.class)\n\t@ConditionalOnMissingClass(\"tools.jackson.databind.json.JsonMapper\")\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tstatic class JmxJackson2EndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(MBeanServer.class)\n\t\tJmxEndpointExporter jmxMBeanExporter(MBeanServer mBeanServer,\n\t\t\t\tEndpointObjectNameFactory endpointObjectNameFactory, ObjectProvider<ObjectMapper> objectMapper,\n\t\t\t\tJmxEndpointsSupplier jmxEndpointsSupplier) {\n\t\t\tJmxOperationResponseMapper responseMapper = new org.springframework.boot.actuate.endpoint.jmx.Jackson2JmxOperationResponseMapper(\n\t\t\t\t\tobjectMapper.getIfAvailable());\n\t\t\treturn new JmxEndpointExporter(mBeanServer, endpointObjectNameFactory, responseMapper,\n\t\t\t\t\tjmxEndpointsSupplier.getEndpoints());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport java.util.LinkedHashSet;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for JMX export of endpoints.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.endpoints.jmx\")\npublic class JmxEndpointProperties {\n\n\tprivate final Exposure exposure = new Exposure();\n\n\t/**\n\t * Endpoints JMX domain name. Fallback to 'spring.jmx.default-domain' if set.\n\t */\n\tprivate @Nullable String domain;\n\n\t/**\n\t * Additional static properties to append to all ObjectNames of MBeans representing\n\t * Endpoints.\n\t */\n\tprivate final Properties staticNames = new Properties();\n\n\tpublic Exposure getExposure() {\n\t\treturn this.exposure;\n\t}\n\n\tpublic @Nullable String getDomain() {\n\t\treturn this.domain;\n\t}\n\n\tpublic void setDomain(@Nullable String domain) {\n\t\tthis.domain = domain;\n\t}\n\n\tpublic Properties getStaticNames() {\n\t\treturn this.staticNames;\n\t}\n\n\tpublic static class Exposure {\n\n\t\t/**\n\t\t * Endpoint IDs that should be included or '*' for all.\n\t\t */\n\t\tprivate Set<String> include = new LinkedHashSet<>();\n\n\t\t/**\n\t\t * Endpoint IDs that should be excluded or '*' for all.\n\t\t */\n\t\tprivate Set<String> exclude = new LinkedHashSet<>();\n\n\t\tpublic Set<String> getInclude() {\n\t\t\treturn this.include;\n\t\t}\n\n\t\tpublic void setInclude(Set<String> include) {\n\t\t\tthis.include = include;\n\t\t}\n\n\t\tpublic Set<String> getExclude() {\n\t\t\treturn this.exclude;\n\t\t}\n\n\t\tpublic void setExclude(Set<String> exclude) {\n\t\t\tthis.exclude = exclude;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator JMX endpoint auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core classes for actuator endpoint auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/CorsEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.cors.CorsConfiguration;\n\n/**\n * Configuration properties for web endpoints' CORS support.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.endpoints.web.cors\")\npublic class CorsEndpointProperties {\n\n\t/**\n\t * List of origins to allow. '*' allows all origins. When credentials are allowed, '*'\n\t * cannot be used and origin patterns should be configured instead. When no allowed\n\t * origins or allowed origin patterns are set, CORS support is disabled.\n\t */\n\tprivate List<String> allowedOrigins = new ArrayList<>();\n\n\t/**\n\t * List of origin patterns to allow. Unlike allowed origins which only supports '*',\n\t * origin patterns are more flexible (for example 'https://*.example.com') and can be\n\t * used when credentials are allowed. When no allowed origin patterns or allowed\n\t * origins are set, CORS support is disabled.\n\t */\n\tprivate List<String> allowedOriginPatterns = new ArrayList<>();\n\n\t/**\n\t * List of methods to allow. '*' allows all methods. When not set, defaults to GET.\n\t */\n\tprivate List<String> allowedMethods = new ArrayList<>();\n\n\t/**\n\t * List of headers to allow in a request. '*' allows all headers.\n\t */\n\tprivate List<String> allowedHeaders = new ArrayList<>();\n\n\t/**\n\t * List of headers to include in a response.\n\t */\n\tprivate List<String> exposedHeaders = new ArrayList<>();\n\n\t/**\n\t * Whether credentials are supported. When not set, credentials are not supported.\n\t */\n\tprivate @Nullable Boolean allowCredentials;\n\n\t/**\n\t * How long the response from a pre-flight request can be cached by clients. If a\n\t * duration suffix is not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate Duration maxAge = Duration.ofSeconds(1800);\n\n\tpublic List<String> getAllowedOrigins() {\n\t\treturn this.allowedOrigins;\n\t}\n\n\tpublic void setAllowedOrigins(List<String> allowedOrigins) {\n\t\tthis.allowedOrigins = allowedOrigins;\n\t}\n\n\tpublic List<String> getAllowedOriginPatterns() {\n\t\treturn this.allowedOriginPatterns;\n\t}\n\n\tpublic void setAllowedOriginPatterns(List<String> allowedOriginPatterns) {\n\t\tthis.allowedOriginPatterns = allowedOriginPatterns;\n\t}\n\n\tpublic List<String> getAllowedMethods() {\n\t\treturn this.allowedMethods;\n\t}\n\n\tpublic void setAllowedMethods(List<String> allowedMethods) {\n\t\tthis.allowedMethods = allowedMethods;\n\t}\n\n\tpublic List<String> getAllowedHeaders() {\n\t\treturn this.allowedHeaders;\n\t}\n\n\tpublic void setAllowedHeaders(List<String> allowedHeaders) {\n\t\tthis.allowedHeaders = allowedHeaders;\n\t}\n\n\tpublic List<String> getExposedHeaders() {\n\t\treturn this.exposedHeaders;\n\t}\n\n\tpublic void setExposedHeaders(List<String> exposedHeaders) {\n\t\tthis.exposedHeaders = exposedHeaders;\n\t}\n\n\tpublic @Nullable Boolean getAllowCredentials() {\n\t\treturn this.allowCredentials;\n\t}\n\n\tpublic void setAllowCredentials(@Nullable Boolean allowCredentials) {\n\t\tthis.allowCredentials = allowCredentials;\n\t}\n\n\tpublic Duration getMaxAge() {\n\t\treturn this.maxAge;\n\t}\n\n\tpublic void setMaxAge(Duration maxAge) {\n\t\tthis.maxAge = maxAge;\n\t}\n\n\tpublic @Nullable CorsConfiguration toCorsConfiguration() {\n\t\tif (CollectionUtils.isEmpty(this.allowedOrigins) && CollectionUtils.isEmpty(this.allowedOriginPatterns)) {\n\t\t\treturn null;\n\t\t}\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tCorsConfiguration configuration = new CorsConfiguration();\n\t\tmap.from(this::getAllowedOrigins).to(configuration::setAllowedOrigins);\n\t\tmap.from(this::getAllowedOriginPatterns).to(configuration::setAllowedOriginPatterns);\n\t\tmap.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedHeaders);\n\t\tmap.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedMethods);\n\t\tmap.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setExposedHeaders);\n\t\tmap.from(this::getMaxAge).as(Duration::getSeconds).to(configuration::setMaxAge);\n\t\tmap.from(this::getAllowCredentials).to(configuration::setAllowCredentials);\n\t\treturn configuration;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link PathMapper} implementation that uses a simple {@link Map} to determine the\n * endpoint path.\n *\n * @author Stephane Nicoll\n */\n@Order(Ordered.HIGHEST_PRECEDENCE)\nclass MappingWebEndpointPathMapper implements PathMapper {\n\n\tprivate final Map<EndpointId, String> pathMapping;\n\n\tMappingWebEndpointPathMapper(Map<String, String> pathMapping) {\n\t\tthis.pathMapping = new HashMap<>();\n\t\tpathMapping.forEach((id, path) -> this.pathMapping.put(EndpointId.fromPropertyValue(id), path));\n\t}\n\n\t@Override\n\tpublic @Nullable String getRootPath(EndpointId endpointId) {\n\t\tString path = this.pathMapping.get(endpointId);\n\t\treturn StringUtils.hasText(path) ? path : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for web {@link Endpoint @Endpoint}\n * support.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Yongjun Hong\n * @since 2.0.0\n */\n@AutoConfiguration(after = EndpointAutoConfiguration.class)\n@ConditionalOnWebApplication\n@EnableConfigurationProperties(WebEndpointProperties.class)\npublic final class WebEndpointAutoConfiguration {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final WebEndpointProperties properties;\n\n\tWebEndpointAutoConfiguration(ApplicationContext applicationContext, WebEndpointProperties properties) {\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\tPathMapper webEndpointPathMapper() {\n\t\treturn new MappingWebEndpointPathMapper(this.properties.getPathMapping());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tEndpointMediaTypes endpointMediaTypes() {\n\t\treturn EndpointMediaTypes.DEFAULT;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(WebEndpointsSupplier.class)\n\tWebEndpointDiscoverer webEndpointDiscoverer(ParameterValueMapper parameterValueMapper,\n\t\t\tEndpointMediaTypes endpointMediaTypes, ObjectProvider<PathMapper> endpointPathMappers,\n\t\t\tObjectProvider<AdditionalPathsMapper> additionalPathsMappers,\n\t\t\tObjectProvider<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\tObjectProvider<EndpointFilter<ExposableWebEndpoint>> endpointFilters,\n\t\t\tObjectProvider<OperationFilter<WebOperation>> operationFilters) {\n\t\treturn new WebEndpointDiscoverer(this.applicationContext, parameterValueMapper, endpointMediaTypes,\n\t\t\t\tendpointPathMappers.orderedStream().toList(), additionalPathsMappers.orderedStream().toList(),\n\t\t\t\tinvokerAdvisors.orderedStream().toList(), endpointFilters.orderedStream().toList(),\n\t\t\t\toperationFilters.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier.class)\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer controllerEndpointDiscoverer(\n\t\t\tObjectProvider<PathMapper> endpointPathMappers,\n\t\t\tObjectProvider<Collection<EndpointFilter<org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint>>> filters) {\n\t\treturn new org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer(\n\t\t\t\tthis.applicationContext, endpointPathMappers.orderedStream().toList(),\n\t\t\t\tfilters.getIfAvailable(Collections::emptyList));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPathMappedEndpoints pathMappedEndpoints(Collection<EndpointsSupplier<?>> endpointSuppliers) {\n\t\tString basePath = this.properties.getBasePath();\n\t\tPathMappedEndpoints pathMappedEndpoints = new PathMappedEndpoints(basePath, endpointSuppliers);\n\t\tif ((!StringUtils.hasText(basePath) || \"/\".equals(basePath))\n\t\t\t\t&& ManagementPortType.get(this.applicationContext.getEnvironment()) == ManagementPortType.SAME) {\n\t\t\tassertHasNoRootPaths(pathMappedEndpoints);\n\t\t}\n\t\treturn pathMappedEndpoints;\n\t}\n\n\tprivate void assertHasNoRootPaths(PathMappedEndpoints endpoints) {\n\t\tfor (PathMappedEndpoint endpoint : endpoints) {\n\t\t\tif (endpoint instanceof ExposableWebEndpoint webEndpoint) {\n\t\t\t\tAssert.state(!isMappedToRootPath(webEndpoint),\n\t\t\t\t\t\t() -> \"Management base path and the '\" + webEndpoint.getEndpointId()\n\t\t\t\t\t\t\t\t+ \"' actuator endpoint are both mapped to '/' \"\n\t\t\t\t\t\t\t\t+ \"on the server port which will block access to other endpoints. \"\n\t\t\t\t\t\t\t\t+ \"Please use a different path for management endpoints or map them to a \"\n\t\t\t\t\t\t\t\t+ \"dedicated management port.\");\n\t\t\t}\n\n\t\t}\n\t}\n\n\tprivate boolean isMappedToRootPath(PathMappedEndpoint endpoint) {\n\t\treturn endpoint.getRootPath().equals(\"/\")\n\t\t\t\t|| endpoint.getAdditionalPaths(WebServerNamespace.SERVER).contains(\"/\");\n\t}\n\n\t@Bean\n\tIncludeExcludeEndpointFilter<ExposableWebEndpoint> webExposeExcludePropertyEndpointFilter() {\n\t\tWebEndpointProperties.Exposure exposure = this.properties.getExposure();\n\t\treturn new IncludeExcludeEndpointFilter<>(ExposableWebEndpoint.class, exposure.getInclude(),\n\t\t\t\texposure.getExclude(), EndpointExposure.WEB.getDefaultIncludes());\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\tIncludeExcludeEndpointFilter<org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint> controllerExposeExcludePropertyEndpointFilter() {\n\t\tWebEndpointProperties.Exposure exposure = this.properties.getExposure();\n\t\treturn new IncludeExcludeEndpointFilter<>(\n\t\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint.class,\n\t\t\t\texposure.getInclude(), exposure.getExclude());\n\t}\n\n\t@Bean\n\tOperationFilter<WebOperation> webAccessPropertiesOperationFilter(EndpointAccessResolver endpointAccessResolver) {\n\t\treturn OperationFilter.byAccess(endpointAccessResolver);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\tstatic class WebEndpointServletConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\t\t@ConditionalOnMissingBean(org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier.class)\n\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer servletEndpointDiscoverer(\n\t\t\t\tApplicationContext applicationContext, ObjectProvider<PathMapper> endpointPathMappers,\n\t\t\t\tObjectProvider<EndpointFilter<org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint>> filters) {\n\t\t\treturn new org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer(\n\t\t\t\t\tapplicationContext, endpointPathMappers.orderedStream().toList(), filters.orderedStream().toList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration properties for web management endpoints.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.endpoints.web\")\npublic class WebEndpointProperties {\n\n\tprivate final Exposure exposure = new Exposure();\n\n\t/**\n\t * Base path for Web endpoints. Relative to the servlet context path\n\t * (server.servlet.context-path) or WebFlux base path (spring.webflux.base-path) when\n\t * the management server is sharing the main server port. Relative to the management\n\t * server base path (management.server.base-path) when a separate management server\n\t * port (management.server.port) is configured.\n\t */\n\tprivate String basePath = \"/actuator\";\n\n\t/**\n\t * Mapping between endpoint IDs and the path that should expose them.\n\t */\n\tprivate final Map<String, String> pathMapping = new LinkedHashMap<>();\n\n\tprivate final Discovery discovery = new Discovery();\n\n\tpublic Exposure getExposure() {\n\t\treturn this.exposure;\n\t}\n\n\tpublic String getBasePath() {\n\t\treturn this.basePath;\n\t}\n\n\tpublic void setBasePath(String basePath) {\n\t\tAssert.isTrue(basePath.isEmpty() || basePath.startsWith(\"/\"), \"'basePath' must start with '/' or be empty\");\n\t\tthis.basePath = cleanBasePath(basePath);\n\t}\n\n\tprivate String cleanBasePath(String basePath) {\n\t\tif (StringUtils.hasText(basePath) && basePath.endsWith(\"/\")) {\n\t\t\treturn basePath.substring(0, basePath.length() - 1);\n\t\t}\n\t\treturn basePath;\n\t}\n\n\tpublic Map<String, String> getPathMapping() {\n\t\treturn this.pathMapping;\n\t}\n\n\tpublic Discovery getDiscovery() {\n\t\treturn this.discovery;\n\t}\n\n\tpublic static class Exposure {\n\n\t\t/**\n\t\t * Endpoint IDs that should be included or '*' for all.\n\t\t */\n\t\tprivate Set<String> include = new LinkedHashSet<>();\n\n\t\t/**\n\t\t * Endpoint IDs that should be excluded or '*' for all.\n\t\t */\n\t\tprivate Set<String> exclude = new LinkedHashSet<>();\n\n\t\tpublic Set<String> getInclude() {\n\t\t\treturn this.include;\n\t\t}\n\n\t\tpublic void setInclude(Set<String> include) {\n\t\t\tthis.include = include;\n\t\t}\n\n\t\tpublic Set<String> getExclude() {\n\t\t\treturn this.exclude;\n\t\t}\n\n\t\tpublic void setExclude(Set<String> exclude) {\n\t\t\tthis.exclude = exclude;\n\t\t}\n\n\t}\n\n\tpublic static class Discovery {\n\n\t\t/**\n\t\t * Whether the discovery page is enabled.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for the Actuator's web endpoints.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/env/EnvironmentEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.env;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint;\nimport org.springframework.boot.actuate.env.EnvironmentEndpointWebExtension;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link EnvironmentEndpoint}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(EnvironmentEndpoint.class)\n@EnableConfigurationProperties(EnvironmentEndpointProperties.class)\npublic final class EnvironmentEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tEnvironmentEndpoint environmentEndpoint(Environment environment, EnvironmentEndpointProperties properties,\n\t\t\tObjectProvider<SanitizingFunction> sanitizingFunctions) {\n\t\treturn new EnvironmentEndpoint(environment, sanitizingFunctions.orderedStream().toList(),\n\t\t\t\tproperties.getShowValues());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(EnvironmentEndpoint.class)\n\t@ConditionalOnAvailableEndpoint(exposure = EndpointExposure.WEB)\n\tEnvironmentEndpointWebExtension environmentEndpointWebExtension(EnvironmentEndpoint environmentEndpoint,\n\t\t\tEnvironmentEndpointProperties properties) {\n\t\treturn new EnvironmentEndpointWebExtension(environmentEndpoint, properties.getShowValues(),\n\t\t\t\tproperties.getRoles());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/env/EnvironmentEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.env;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for {@link EnvironmentEndpoint}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.endpoint.env\")\npublic class EnvironmentEndpointProperties {\n\n\t/**\n\t * When to show unsanitized values.\n\t */\n\tprivate Show showValues = Show.NEVER;\n\n\t/**\n\t * Roles used to determine whether a user is authorized to be shown unsanitized\n\t * values. When empty, all authenticated users are authorized.\n\t */\n\tprivate final Set<String> roles = new HashSet<>();\n\n\tpublic Show getShowValues() {\n\t\treturn this.showValues;\n\t}\n\n\tpublic void setShowValues(Show showValues) {\n\t\tthis.showValues = showValues;\n\t}\n\n\tpublic Set<String> getRoles() {\n\t\treturn this.roles;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/env/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator Spring Environment concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.env;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/ConditionalOnEnabledInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether an info contributor is enabled.\n * Matches if the value of the {@code management.info.<name>.enabled} property is\n * {@code true}. Otherwise, use the specific {@link #fallback() fallback} method.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnEnabledInfoContributorCondition.class)\npublic @interface ConditionalOnEnabledInfoContributor {\n\n\t/**\n\t * The name of the info contributor.\n\t * @return the name of the info contributor\n\t */\n\tString value();\n\n\t/**\n\t * Fallback behavior when {@code management.info.<name>.enabled} has not been set.\n\t * @return the fallback behavior\n\t */\n\tInfoContributorFallback fallback() default InfoContributorFallback.USE_DEFAULTS_PROPERTY;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.springframework.boot.actuate.info.BuildInfoContributor;\nimport org.springframework.boot.actuate.info.EnvironmentInfoContributor;\nimport org.springframework.boot.actuate.info.GitInfoContributor;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.boot.actuate.info.JavaInfoContributor;\nimport org.springframework.boot.actuate.info.OsInfoContributor;\nimport org.springframework.boot.actuate.info.ProcessInfoContributor;\nimport org.springframework.boot.actuate.info.SslInfoContributor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.info.BuildProperties;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for standard\n * {@link InfoContributor}s.\n *\n * @author Meang Akira Tanaka\n * @author Stephane Nicoll\n * @author Jonatan Ivanov\n * @since 2.0.0\n */\n@AutoConfiguration(after = ProjectInfoAutoConfiguration.class)\n@EnableConfigurationProperties(InfoContributorProperties.class)\npublic final class InfoContributorAutoConfiguration {\n\n\t/**\n\t * The default order for the core {@link InfoContributor} beans.\n\t */\n\tpublic static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(value = \"env\", fallback = InfoContributorFallback.DISABLE)\n\t@Order(DEFAULT_ORDER)\n\tEnvironmentInfoContributor envInfoContributor(ConfigurableEnvironment environment) {\n\t\treturn new EnvironmentInfoContributor(environment);\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(\"git\")\n\t@ConditionalOnSingleCandidate(GitProperties.class)\n\t@ConditionalOnMissingBean\n\t@Order(DEFAULT_ORDER)\n\tGitInfoContributor gitInfoContributor(GitProperties gitProperties,\n\t\t\tInfoContributorProperties infoContributorProperties) {\n\t\treturn new GitInfoContributor(gitProperties, infoContributorProperties.getGit().getMode());\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(\"build\")\n\t@ConditionalOnSingleCandidate(BuildProperties.class)\n\t@Order(DEFAULT_ORDER)\n\tInfoContributor buildInfoContributor(BuildProperties buildProperties) {\n\t\treturn new BuildInfoContributor(buildProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(value = \"java\", fallback = InfoContributorFallback.DISABLE)\n\t@Order(DEFAULT_ORDER)\n\tJavaInfoContributor javaInfoContributor() {\n\t\treturn new JavaInfoContributor();\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(value = \"os\", fallback = InfoContributorFallback.DISABLE)\n\t@Order(DEFAULT_ORDER)\n\tOsInfoContributor osInfoContributor() {\n\t\treturn new OsInfoContributor();\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(value = \"process\", fallback = InfoContributorFallback.DISABLE)\n\t@Order(DEFAULT_ORDER)\n\tProcessInfoContributor processInfoContributor() {\n\t\treturn new ProcessInfoContributor();\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledInfoContributor(value = \"ssl\", fallback = InfoContributorFallback.DISABLE)\n\t@Order(DEFAULT_ORDER)\n\tSslInfoContributor sslInfoContributor(SslInfo sslInfo) {\n\t\treturn new SslInfoContributor(sslInfo);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledInfoContributor(value = \"ssl\", fallback = InfoContributorFallback.DISABLE)\n\tSslInfo sslInfo(SslBundles sslBundles) {\n\t\treturn new SslInfo(sslBundles);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorFallback.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.springframework.boot.actuate.autoconfigure.OnEndpointElementCondition;\n\n/**\n * Controls the fallback behavior when the primary property that controls whether an info\n * contributor is enabled is not set.\n *\n * @author Andy Wilkinson\n * @since 2.6.0\n * @see OnEndpointElementCondition\n */\npublic enum InfoContributorFallback {\n\n\t/**\n\t * Fall back to the {@code management.info.defaults.enabled} property, matching if it\n\t * is {@code true} or if it is not configured.\n\t */\n\tUSE_DEFAULTS_PROPERTY,\n\n\t/**\n\t * Do not fall back, thereby disabling the info contributor.\n\t */\n\tDISABLE\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.springframework.boot.actuate.info.GitInfoContributor;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for core info contributors.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.info\")\npublic class InfoContributorProperties {\n\n\tprivate final Git git = new Git();\n\n\tpublic Git getGit() {\n\t\treturn this.git;\n\t}\n\n\tpublic static class Git {\n\n\t\t/**\n\t\t * Mode to use to expose git information.\n\t\t */\n\t\tprivate GitInfoContributor.Mode mode = GitInfoContributor.Mode.SIMPLE;\n\n\t\tpublic GitInfoContributor.Mode getMode() {\n\t\t\treturn this.mode;\n\t\t}\n\n\t\tpublic void setMode(GitInfoContributor.Mode mode) {\n\t\t\tthis.mode = mode;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.boot.actuate.info.InfoEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link InfoEndpoint}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration(after = InfoContributorAutoConfiguration.class)\n@ConditionalOnAvailableEndpoint(InfoEndpoint.class)\npublic final class InfoEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tInfoEndpoint infoEndpoint(ObjectProvider<InfoContributor> infoContributors) {\n\t\treturn new InfoEndpoint(infoContributors.orderedStream().toList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/OnEnabledInfoContributorCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.springframework.boot.actuate.autoconfigure.OnEndpointElementCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\n/**\n * {@link Condition} that checks if an info indicator is enabled.\n *\n * @author Stephane Nicoll\n */\nclass OnEnabledInfoContributorCondition extends OnEndpointElementCondition {\n\n\tOnEnabledInfoContributorCondition() {\n\t\tsuper(\"management.info.\", ConditionalOnEnabledInfoContributor.class);\n\t}\n\n\t@Override\n\tprotected ConditionOutcome getDefaultOutcome(ConditionContext context, AnnotationAttributes annotationAttributes) {\n\t\tInfoContributorFallback fallback = annotationAttributes.getEnum(\"fallback\");\n\t\tif (fallback == InfoContributorFallback.DISABLE) {\n\t\t\treturn new ConditionOutcome(false, ConditionMessage.forCondition(ConditionalOnEnabledInfoContributor.class)\n\t\t\t\t.because(\"management.info.\" + annotationAttributes.getString(\"value\") + \".enabled is not true\"));\n\t\t}\n\t\treturn super.getDefaultOutcome(context, annotationAttributes);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator info concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/LogFileWebEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.logging;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.logging.LogFileWebEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.logging.LogFile;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link LogFileWebEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Christian Carriere-Tisseur\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(LogFileWebEndpoint.class)\n@EnableConfigurationProperties(LogFileWebEndpointProperties.class)\npublic final class LogFileWebEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Conditional(LogFileCondition.class)\n\tLogFileWebEndpoint logFileWebEndpoint(ObjectProvider<LogFile> logFile, LogFileWebEndpointProperties properties) {\n\t\treturn new LogFileWebEndpoint(logFile.getIfAvailable(), properties.getExternalFile());\n\t}\n\n\tprivate static final class LogFileCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tEnvironment environment = context.getEnvironment();\n\t\t\tString config = getLogFileConfig(environment, LogFile.FILE_NAME_PROPERTY);\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Log File\");\n\t\t\tif (StringUtils.hasText(config)) {\n\t\t\t\treturn ConditionOutcome.match(message.found(LogFile.FILE_NAME_PROPERTY).items(config));\n\t\t\t}\n\t\t\tconfig = getLogFileConfig(environment, LogFile.FILE_PATH_PROPERTY);\n\t\t\tif (StringUtils.hasText(config)) {\n\t\t\t\treturn ConditionOutcome.match(message.found(LogFile.FILE_PATH_PROPERTY).items(config));\n\t\t\t}\n\t\t\tconfig = environment.getProperty(\"management.endpoint.logfile.external-file\");\n\t\t\tif (StringUtils.hasText(config)) {\n\t\t\t\treturn ConditionOutcome.match(message.found(\"management.endpoint.logfile.external-file\").items(config));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"logging file\").atAll());\n\t\t}\n\n\t\tprivate String getLogFileConfig(Environment environment, String configName) {\n\t\t\treturn environment.resolvePlaceholders(\"${\" + configName + \":}\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/LogFileWebEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.logging;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.logging.LogFileWebEndpoint;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for {@link LogFileWebEndpoint}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.endpoint.logfile\")\npublic class LogFileWebEndpointProperties {\n\n\t/**\n\t * External Logfile to be accessed. Can be used if the logfile is written by output\n\t * redirect and not by the logging system itself.\n\t */\n\tprivate @Nullable File externalFile;\n\n\tpublic @Nullable File getExternalFile() {\n\t\treturn this.externalFile;\n\t}\n\n\tpublic void setExternalFile(@Nullable File externalFile) {\n\t\tthis.externalFile = externalFile;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/LoggersEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.logging;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.logging.LoggersEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.logging.LoggerGroups;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link LoggersEndpoint}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(LoggersEndpoint.class)\npublic final class LoggersEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(LoggingSystem.class)\n\t@Conditional(OnEnabledLoggingSystemCondition.class)\n\t@ConditionalOnMissingBean\n\tLoggersEndpoint loggersEndpoint(LoggingSystem loggingSystem, ObjectProvider<LoggerGroups> springBootLoggerGroups) {\n\t\treturn new LoggersEndpoint(loggingSystem, springBootLoggerGroups.getIfAvailable(LoggerGroups::new));\n\t}\n\n\tstatic class OnEnabledLoggingSystemCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Logging System\");\n\t\t\tString loggingSystem = System.getProperty(LoggingSystem.SYSTEM_PROPERTY);\n\t\t\tif (LoggingSystem.NONE.equals(loggingSystem)) {\n\t\t\t\treturn ConditionOutcome\n\t\t\t\t\t.noMatch(message.because(\"system property \" + LoggingSystem.SYSTEM_PROPERTY + \" is set to none\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.match(message.because(\"enabled\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator logging concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.logging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/HeapDumpWebEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.management;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.management.HeapDumpWebEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HeapDumpWebEndpoint}.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(HeapDumpWebEndpoint.class)\npublic final class HeapDumpWebEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHeapDumpWebEndpoint heapDumpWebEndpoint() {\n\t\treturn new HeapDumpWebEndpoint();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.management;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.management.ThreadDumpEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link ThreadDumpEndpoint}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(ThreadDumpEndpoint.class)\npublic final class ThreadDumpEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tThreadDumpEndpoint dumpEndpoint() {\n\t\treturn new ThreadDumpEndpoint();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/management/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator management concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.management;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for general actuator auto-configuration concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/sbom/SbomEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.sbom;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.sbom.SbomEndpoint;\nimport org.springframework.boot.actuate.sbom.SbomEndpointWebExtension;\nimport org.springframework.boot.actuate.sbom.SbomProperties;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link SbomEndpoint}.\n *\n * @author Moritz Halbritter\n * @since 3.3.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(SbomEndpoint.class)\n@EnableConfigurationProperties(SbomProperties.class)\npublic final class SbomEndpointAutoConfiguration {\n\n\tprivate final SbomProperties properties;\n\n\tSbomEndpointAutoConfiguration(SbomProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSbomEndpoint sbomEndpoint(ResourceLoader resourceLoader) {\n\t\treturn new SbomEndpoint(this.properties, resourceLoader);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(SbomEndpoint.class)\n\t@ConditionalOnAvailableEndpoint(exposure = EndpointExposure.WEB)\n\tSbomEndpointWebExtension sbomEndpointWebExtension(SbomEndpoint sbomEndpoint) {\n\t\treturn new SbomEndpointWebExtension(sbomEndpoint, this.properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/sbom/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator SBOM concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.sbom;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.scheduling;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.scheduling.config.ScheduledTaskHolder;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link ScheduledTasksEndpoint}.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(ScheduledTasksEndpoint.class)\npublic final class ScheduledTasksEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tScheduledTasksEndpoint scheduledTasksEndpoint(ObjectProvider<ScheduledTaskHolder> holders) {\n\t\treturn new ScheduledTasksEndpoint(holders.orderedStream().toList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/scheduling/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator scheduling concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.scheduling;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/startup/StartupEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.startup;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.startup.StartupEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.metrics.ApplicationStartup;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the {@link StartupEndpoint}.\n *\n * @author Brian Clozel\n * @since 2.4.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(StartupEndpoint.class)\n@Conditional(StartupEndpointAutoConfiguration.ApplicationStartupCondition.class)\npublic final class StartupEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStartupEndpoint startupEndpoint(BufferingApplicationStartup applicationStartup) {\n\t\treturn new StartupEndpoint(applicationStartup);\n\t}\n\n\t/**\n\t * {@link SpringBootCondition} checking the configured\n\t * {@link org.springframework.core.metrics.ApplicationStartup}.\n\t * <p>\n\t * Endpoint is enabled only if the configured implementation is\n\t * {@link BufferingApplicationStartup}.\n\t */\n\tstatic class ApplicationStartupCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"ApplicationStartup\");\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\t\tApplicationStartup applicationStartup = beanFactory.getApplicationStartup();\n\t\t\tif (applicationStartup instanceof BufferingApplicationStartup) {\n\t\t\t\treturn ConditionOutcome\n\t\t\t\t\t.match(message.because(\"configured applicationStartup is of type BufferingApplicationStartup.\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.because(\"configured applicationStartup is of type \"\n\t\t\t\t\t+ applicationStartup.getClass() + \", expected BufferingApplicationStartup.\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/startup/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator ApplicationStartup concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.startup;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Specialized {@link Configuration @Configuration} class that defines configuration\n * specific for the management context. Configurations should be registered in\n * {@code /META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports}.\n * <p>\n * {@code ManagementContextConfiguration} classes can be ordered using\n * {@link Order @Order}. Ordering by implementing {@link Ordered} is not supported and\n * will have no effect.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Configuration\npublic @interface ManagementContextConfiguration {\n\n\t/**\n\t * Specifies the type of management context that is required for this configuration to\n\t * be applied.\n\t * @return the required management context type\n\t */\n\tManagementContextType value() default ManagementContextType.ANY;\n\n\t/**\n\t * Specify whether {@link Bean @Bean} methods should get proxied in order to enforce\n\t * bean lifecycle behavior, e.g. to return shared singleton bean instances even in\n\t * case of direct {@code @Bean} method calls in user code. This feature requires\n\t * method interception, implemented through a runtime-generated CGLIB subclass which\n\t * comes with limitations such as the configuration class and its methods not being\n\t * allowed to declare {@code final}.\n\t * <p>\n\t * The default is {@code true}, allowing for 'inter-bean references' within the\n\t * configuration class as well as for external calls to this configuration's\n\t * {@code @Bean} methods, e.g. from another configuration class. If this is not needed\n\t * since each of this particular configuration's {@code @Bean} methods is\n\t * self-contained and designed as a plain factory method for container use, switch\n\t * this flag to {@code false} in order to avoid CGLIB subclass processing.\n\t * <p>\n\t * Turning off bean method interception effectively processes {@code @Bean} methods\n\t * individually like when declared on non-{@code @Configuration} classes, a.k.a.\n\t * \"@Bean Lite Mode\" (see {@link Bean @Bean's javadoc}). It is therefore behaviorally\n\t * equivalent to removing the {@code @Configuration} stereotype.\n\t * @return whether to proxy {@code @Bean} methods\n\t * @since 2.2.0\n\t */\n\t@AliasFor(annotation = Configuration.class)\n\tboolean proxyBeanMethods() default true;\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web;\n\n/**\n * Enumeration of management context types.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic enum ManagementContextType {\n\n\t/**\n\t * The management context is the same as the main application context.\n\t */\n\tSAME,\n\n\t/**\n\t * The management context is a separate context that is a child of the main\n\t * application context.\n\t */\n\tCHILD,\n\n\t/**\n\t * The management context can be either the same as the main application context or a\n\t * child of the main application context.\n\t */\n\tANY\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/exchanges/HttpExchangesEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.exchanges;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangesEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the\n * {@link HttpExchangesEndpoint}.\n *\n * @author Phillip Webb\n * @since 3.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(HttpExchangesEndpoint.class)\npublic final class HttpExchangesEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(HttpExchangeRepository.class)\n\t@ConditionalOnMissingBean\n\tHttpExchangesEndpoint httpExchangesEndpoint(HttpExchangeRepository exchangeRepository) {\n\t\treturn new HttpExchangesEndpoint(exchangeRepository);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/exchanges/HttpExchangesProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.exchanges;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for recording HTTP exchanges.\n *\n * @author Wallace Wadge\n * @author Phillip Webb\n * @author Venil Noronha\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@ConfigurationProperties(\"management.httpexchanges\")\npublic class HttpExchangesProperties {\n\n\tprivate final Recording recording = new Recording();\n\n\tpublic Recording getRecording() {\n\t\treturn this.recording;\n\t}\n\n\t/**\n\t * Recording properties.\n\t *\n\t * @since 3.0.0\n\t */\n\tpublic static class Recording {\n\n\t\t/**\n\t\t * Items to be included in the exchange recording. Defaults to request headers\n\t\t * (excluding Authorization and Cookie), response headers (excluding Set-Cookie),\n\t\t * and time taken.\n\t\t */\n\t\tprivate Set<Include> include = new HashSet<>(Include.defaultIncludes());\n\n\t\tpublic Set<Include> getInclude() {\n\t\t\treturn this.include;\n\t\t}\n\n\t\tpublic void setInclude(Set<Include> include) {\n\t\t\tthis.include = include;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/exchanges/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator HTTP exchanges.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.web.exchanges;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.mappings;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link MappingsEndpoint}.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@AutoConfiguration\n@ConditionalOnAvailableEndpoint(MappingsEndpoint.class)\npublic final class MappingsEndpointAutoConfiguration {\n\n\t@Bean\n\tMappingsEndpoint mappingsEndpoint(ApplicationContext applicationContext,\n\t\t\tObjectProvider<MappingDescriptionProvider> descriptionProviders) {\n\t\treturn new MappingsEndpoint(descriptionProviders.orderedStream().toList(), applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for auto-configuration of actuator web request mapping concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core classes for auto-configuration of actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/AccessLogCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.WebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.core.Ordered;\nimport org.springframework.lang.Contract;\n\n/**\n * Base class for a {@link WebServerFactoryCustomizer} that customizes the web server's\n * access log.\n *\n * @param <T> the {@link WebServerFactory} type that can be customized\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic abstract class AccessLogCustomizer<T extends WebServerFactory>\n\t\timplements WebServerFactoryCustomizer<T>, Ordered {\n\n\tprivate final @Nullable String prefix;\n\n\tprotected AccessLogCustomizer(@Nullable String prefix) {\n\t\tthis.prefix = prefix;\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprotected @Nullable String customizePrefix(@Nullable String existingPrefix) {\n\t\tif (this.prefix == null) {\n\t\t\treturn existingPrefix;\n\t\t}\n\t\tif (existingPrefix == null) {\n\t\t\treturn this.prefix;\n\t\t}\n\t\tif (existingPrefix.startsWith(this.prefix)) {\n\t\t\treturn existingPrefix;\n\t\t}\n\t\treturn this.prefix + existingPrefix;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ChildManagementContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.util.List;\n\nimport javax.lang.model.element.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GeneratedMethod;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.web.server.context.ConfigurableWebServerApplicationContext;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.util.Assert;\n\n/**\n * {@link SmartLifecycle} used to initialize the management context when it's running on a\n * different port.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ChildManagementContextInitializer implements BeanRegistrationAotProcessor, SmartLifecycle {\n\n\tprivate final ManagementContextFactory managementContextFactory;\n\n\tprivate final AbstractApplicationContext parentContext;\n\n\tprivate final @Nullable ApplicationContextInitializer<ConfigurableApplicationContext> applicationContextInitializer;\n\n\tprivate volatile @Nullable ConfigurableApplicationContext managementContext;\n\n\tChildManagementContextInitializer(ManagementContextFactory managementContextFactory,\n\t\t\tAbstractApplicationContext parentContext) {\n\t\tthis(managementContextFactory, parentContext, null);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ChildManagementContextInitializer(ManagementContextFactory managementContextFactory,\n\t\t\tAbstractApplicationContext parentContext,\n\t\t\t@Nullable ApplicationContextInitializer<? extends ConfigurableApplicationContext> applicationContextInitializer) {\n\t\tthis.managementContextFactory = managementContextFactory;\n\t\tthis.parentContext = parentContext;\n\t\tthis.applicationContextInitializer = (ApplicationContextInitializer<ConfigurableApplicationContext>) applicationContextInitializer;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tif (!(this.parentContext instanceof WebServerApplicationContext)) {\n\t\t\treturn;\n\t\t}\n\t\tConfigurableApplicationContext managementContext = this.managementContext;\n\t\tif (managementContext == null) {\n\t\t\tmanagementContext = createManagementContext();\n\t\t\tregisterBeans(managementContext);\n\t\t\tmanagementContext.refresh();\n\t\t\tthis.managementContext = managementContext;\n\t\t}\n\t\telse {\n\t\t\tmanagementContext.start();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tConfigurableApplicationContext managementContext = this.managementContext;\n\t\tif (managementContext != null) {\n\t\t\tif (this.parentContext.isClosed()) {\n\t\t\t\tmanagementContext.close();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tmanagementContext.stop();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\tConfigurableApplicationContext managementContext = this.managementContext;\n\t\treturn managementContext != null && managementContext.isRunning();\n\t}\n\n\t@Override\n\tpublic int getPhase() {\n\t\treturn WebServerApplicationContext.GRACEFUL_SHUTDOWN_PHASE - 512;\n\t}\n\n\t@Override\n\tpublic @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n\t\tAssert.isInstanceOf(ConfigurableApplicationContext.class, this.parentContext);\n\t\tBeanFactory parentBeanFactory = this.parentContext.getBeanFactory();\n\t\tif (registeredBean.getBeanClass().equals(getClass())\n\t\t\t\t&& registeredBean.getBeanFactory().equals(parentBeanFactory)) {\n\t\t\tConfigurableApplicationContext managementContext = createManagementContext();\n\t\t\tregisterBeans(managementContext);\n\t\t\treturn new AotContribution(managementContext);\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean isBeanExcludedFromAotProcessing() {\n\t\treturn false;\n\t}\n\n\t@Nullable ConfigurableApplicationContext getManagementContext() {\n\t\treturn this.managementContext;\n\t}\n\n\tprivate void registerBeans(ConfigurableApplicationContext managementContext) {\n\t\tif (this.applicationContextInitializer != null) {\n\t\t\tthis.applicationContextInitializer.initialize(managementContext);\n\t\t\treturn;\n\t\t}\n\t\tAssert.isInstanceOf(AnnotationConfigRegistry.class, managementContext);\n\t\tAnnotationConfigRegistry registry = (AnnotationConfigRegistry) managementContext;\n\t\tthis.managementContextFactory.registerWebServerFactoryBeans(this.parentContext, managementContext, registry);\n\t\tregistry.register(EnableChildManagementContextConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tif (isLazyInitialization()) {\n\t\t\tmanagementContext.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());\n\t\t}\n\t}\n\n\tprotected final ConfigurableApplicationContext createManagementContext() {\n\t\tConfigurableApplicationContext managementContext = this.managementContextFactory\n\t\t\t.createManagementContext(this.parentContext);\n\t\tmanagementContext.setId(this.parentContext.getId() + \":management\");\n\t\tif (managementContext instanceof ConfigurableWebServerApplicationContext webServerApplicationContext) {\n\t\t\twebServerApplicationContext.setServerNamespace(\"management\");\n\t\t}\n\t\tif (managementContext instanceof DefaultResourceLoader resourceLoader) {\n\t\t\tresourceLoader.setClassLoader(this.parentContext.getClassLoader());\n\t\t}\n\t\tCloseManagementContextListener.addIfPossible(this.parentContext, managementContext);\n\t\treturn managementContext;\n\t}\n\n\tprivate boolean isLazyInitialization() {\n\t\tList<BeanFactoryPostProcessor> postProcessors = this.parentContext.getBeanFactoryPostProcessors();\n\t\treturn postProcessors.stream().anyMatch(LazyInitializationBeanFactoryPostProcessor.class::isInstance);\n\t}\n\n\tChildManagementContextInitializer withApplicationContextInitializer(\n\t\t\tApplicationContextInitializer<? extends ConfigurableApplicationContext> applicationContextInitializer) {\n\t\treturn new ChildManagementContextInitializer(this.managementContextFactory, this.parentContext,\n\t\t\t\tapplicationContextInitializer);\n\t}\n\n\t/**\n\t * {@link BeanRegistrationAotContribution} for\n\t * {@link ChildManagementContextInitializer}.\n\t */\n\tprivate static class AotContribution implements BeanRegistrationAotContribution {\n\n\t\tprivate final GenericApplicationContext managementContext;\n\n\t\tAotContribution(ConfigurableApplicationContext managementContext) {\n\t\t\tAssert.isInstanceOf(GenericApplicationContext.class, managementContext);\n\t\t\tthis.managementContext = (GenericApplicationContext) managementContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {\n\t\t\tGenerationContext managementGenerationContext = generationContext.withName(\"Management\");\n\t\t\tClassName generatedInitializerClassName = new ApplicationContextAotGenerator()\n\t\t\t\t.processAheadOfTime(this.managementContext, managementGenerationContext);\n\t\t\tGeneratedMethod postProcessorMethod = beanRegistrationCode.getMethods()\n\t\t\t\t.add(\"addManagementInitializer\",\n\t\t\t\t\t\t(method) -> method.addJavadoc(\"Use AOT management context initialization\")\n\t\t\t\t\t\t\t.addModifiers(Modifier.PRIVATE, Modifier.STATIC)\n\t\t\t\t\t\t\t.addParameter(RegisteredBean.class, \"registeredBean\")\n\t\t\t\t\t\t\t.addParameter(ChildManagementContextInitializer.class, \"instance\")\n\t\t\t\t\t\t\t.returns(ChildManagementContextInitializer.class)\n\t\t\t\t\t\t\t.addStatement(\"return instance.withApplicationContextInitializer(new $L())\",\n\t\t\t\t\t\t\t\t\tgeneratedInitializerClassName));\n\t\t\tbeanRegistrationCode.addInstancePostProcessor(postProcessorMethod.toMethodReference());\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ApplicationListener} to propagate the {@link ApplicationFailedEvent} from a\n\t * parent to a child.\n\t */\n\tprivate static class CloseManagementContextListener implements ApplicationListener<ApplicationEvent> {\n\n\t\tprivate final ApplicationContext parentContext;\n\n\t\tprivate final ConfigurableApplicationContext childContext;\n\n\t\tCloseManagementContextListener(ApplicationContext parentContext, ConfigurableApplicationContext childContext) {\n\t\t\tthis.parentContext = parentContext;\n\t\t\tthis.childContext = childContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tif (event instanceof ApplicationFailedEvent applicationFailedEvent) {\n\t\t\t\tonApplicationFailedEvent(applicationFailedEvent);\n\t\t\t}\n\t\t}\n\n\t\tprivate void onApplicationFailedEvent(ApplicationFailedEvent event) {\n\t\t\tpropagateCloseIfNecessary(event.getApplicationContext());\n\t\t}\n\n\t\tprivate void propagateCloseIfNecessary(@Nullable ApplicationContext applicationContext) {\n\t\t\tif (applicationContext == this.parentContext) {\n\t\t\t\tthis.childContext.close();\n\t\t\t}\n\t\t}\n\n\t\tstatic void addIfPossible(ApplicationContext parentContext, ConfigurableApplicationContext childContext) {\n\t\t\tif (parentContext instanceof ConfigurableApplicationContext configurableApplicationContext) {\n\t\t\t\tadd(configurableApplicationContext, childContext);\n\t\t\t}\n\t\t}\n\n\t\tprivate static void add(ConfigurableApplicationContext parentContext,\n\t\t\t\tConfigurableApplicationContext childContext) {\n\t\t\tparentContext.addApplicationListener(new CloseManagementContextListener(parentContext, childContext));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ConditionalOnManagementPort.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches based on the configuration of the\n * management port.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnManagementPortCondition.class)\npublic @interface ConditionalOnManagementPort {\n\n\t/**\n\t * The {@link ManagementPortType} to match.\n\t * @return the port type\n\t */\n\tManagementPortType value();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/EnableChildManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration class used to enable configuration of a child management context.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@EnableManagementContext(ManagementContextType.CHILD)\nclass EnableChildManagementContextConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/EnableManagementContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Enables the management context.\n *\n * @author Andy Wilkinson\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(ManagementContextConfigurationImportSelector.class)\n@interface EnableManagementContext {\n\n\t/**\n\t * The management context type that should be enabled.\n\t * @return the management context type\n\t */\n\tManagementContextType value();\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the management context. If the\n * {@code management.server.port} is the same as the {@code server.port} the management\n * context will be the same as the main application context. If the\n * {@code management.server.port} is different to the {@code server.port} the management\n * context will be a separate context that has the main application context as its parent.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\n@AutoConfiguration\n@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)\npublic final class ManagementContextAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnManagementPort(ManagementPortType.SAME)\n\tstatic class SameManagementContextConfiguration implements SmartInitializingSingleton {\n\n\t\tprivate final Environment environment;\n\n\t\tSameManagementContextConfiguration(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterSingletonsInstantiated() {\n\t\t\tverifySslConfiguration();\n\t\t\tverifyAddressConfiguration();\n\t\t\tif (this.environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\t\taddLocalManagementPortPropertyAlias(configurableEnvironment);\n\t\t\t}\n\t\t}\n\n\t\tprivate void verifySslConfiguration() {\n\t\t\tBoolean enabled = this.environment.getProperty(\"management.server.ssl.enabled\", Boolean.class, false);\n\t\t\tAssert.state(!enabled, \"Management-specific SSL cannot be configured as the management \"\n\t\t\t\t\t+ \"server is not listening on a separate port\");\n\t\t}\n\n\t\tprivate void verifyAddressConfiguration() {\n\t\t\tObject address = this.environment.getProperty(\"management.server.address\");\n\t\t\tAssert.state(address == null, \"Management-specific server address cannot be configured as the management \"\n\t\t\t\t\t+ \"server is not listening on a separate port\");\n\t\t}\n\n\t\t/**\n\t\t * Add an alias for 'local.management.port' that actually resolves using\n\t\t * 'local.server.port'.\n\t\t * @param environment the environment\n\t\t */\n\t\tprivate void addLocalManagementPortPropertyAlias(ConfigurableEnvironment environment) {\n\t\t\tenvironment.getPropertySources().addLast(new LocalManagementPortPropertySource(environment));\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableManagementContext(ManagementContextType.SAME)\n\t\tstatic class EnableSameManagementContextConfiguration {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\n\t@EnableConfigurationProperties(ManagementServerProperties.class)\n\tstatic class DifferentManagementContextConfiguration {\n\n\t\t@Bean\n\t\tstatic ChildManagementContextInitializer childManagementContextInitializer(\n\t\t\t\tManagementContextFactory managementContextFactory, AbstractApplicationContext parentContext) {\n\t\t\treturn new ChildManagementContextInitializer(managementContextFactory, parentContext);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link EnumerablePropertySource} providing {@code local.management.port} support.\n\t */\n\tstatic class LocalManagementPortPropertySource extends EnumerablePropertySource<Object>\n\t\t\timplements PropertySourceInfo {\n\n\t\tprivate static final Map<String, String> PROPERTY_MAPPINGS = Map.of(\"local.management.port\",\n\t\t\t\t\"local.server.port\");\n\n\t\tprivate static final String[] PROPERTY_NAMES = PROPERTY_MAPPINGS.keySet().toArray(String[]::new);\n\n\t\tprivate final Environment environment;\n\n\t\tLocalManagementPortPropertySource(Environment environment) {\n\t\t\tsuper(\"Management Server\");\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getPropertyNames() {\n\t\t\treturn PROPERTY_NAMES;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\tString mapped = PROPERTY_MAPPINGS.get(name);\n\t\t\treturn (mapped != null) ? this.environment.getProperty(mapped) : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isImmutable() {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextConfigurationImportSelector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.context.annotation.DeferredImportSelector;\nimport org.springframework.core.OrderComparator;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Selects configuration classes for the management context configuration. Entries are\n * loaded from\n * {@code /META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @see ManagementContextConfiguration\n * @see ImportCandidates\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass ManagementContextConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware {\n\n\tprivate @Nullable ClassLoader classLoader;\n\n\t@Override\n\tpublic String[] selectImports(AnnotationMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(EnableManagementContext.class.getName());\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tManagementContextType contextType = (ManagementContextType) attributes.get(\"value\");\n\t\t// Find all management context configuration classes, filtering duplicates\n\t\tList<ManagementConfiguration> configurations = getConfigurations();\n\t\tOrderComparator.sort(configurations);\n\t\tList<String> names = new ArrayList<>();\n\t\tfor (ManagementConfiguration configuration : configurations) {\n\t\t\tif (configuration.getContextType() == ManagementContextType.ANY\n\t\t\t\t\t|| configuration.getContextType() == contextType) {\n\t\t\t\tnames.add(configuration.getClassName());\n\t\t\t}\n\t\t}\n\t\treturn StringUtils.toStringArray(names);\n\t}\n\n\tprivate List<ManagementConfiguration> getConfigurations() {\n\t\tSimpleMetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory(this.classLoader);\n\t\tList<ManagementConfiguration> configurations = new ArrayList<>();\n\t\tfor (String className : loadFactoryNames()) {\n\t\t\taddConfiguration(readerFactory, configurations, className);\n\t\t}\n\t\treturn configurations;\n\t}\n\n\tprivate void addConfiguration(SimpleMetadataReaderFactory readerFactory,\n\t\t\tList<ManagementConfiguration> configurations, String className) {\n\t\ttry {\n\t\t\tMetadataReader metadataReader = readerFactory.getMetadataReader(className);\n\t\t\tconfigurations.add(new ManagementConfiguration(metadataReader));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to read annotation metadata for '\" + className + \"'\", ex);\n\t\t}\n\t}\n\n\tprotected List<String> loadFactoryNames() {\n\t\treturn ImportCandidates.load(ManagementContextConfiguration.class, this.classLoader).getCandidates();\n\t}\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t/**\n\t * A management configuration class which can be sorted according to {@code @Order}.\n\t */\n\tprivate static final class ManagementConfiguration implements Ordered {\n\n\t\tprivate final String className;\n\n\t\tprivate final int order;\n\n\t\tprivate final ManagementContextType contextType;\n\n\t\tManagementConfiguration(MetadataReader metadataReader) {\n\t\t\tAnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();\n\t\t\tthis.order = readOrder(annotationMetadata);\n\t\t\tthis.className = metadataReader.getClassMetadata().getClassName();\n\t\t\tthis.contextType = readContextType(annotationMetadata);\n\t\t}\n\n\t\tprivate ManagementContextType readContextType(AnnotationMetadata annotationMetadata) {\n\t\t\tMap<String, @Nullable Object> annotationAttributes = annotationMetadata\n\t\t\t\t.getAnnotationAttributes(ManagementContextConfiguration.class.getName());\n\t\t\tif (annotationAttributes == null) {\n\t\t\t\treturn ManagementContextType.ANY;\n\t\t\t}\n\t\t\tManagementContextType value = (ManagementContextType) annotationAttributes.get(\"value\");\n\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\treturn value;\n\t\t}\n\n\t\tprivate int readOrder(AnnotationMetadata annotationMetadata) {\n\t\t\tMap<String, @Nullable Object> attributes = annotationMetadata\n\t\t\t\t.getAnnotationAttributes(Order.class.getName());\n\t\t\tInteger order = (attributes != null) ? (Integer) attributes.get(\"value\") : null;\n\t\t\treturn (order != null) ? order : Ordered.LOWEST_PRECEDENCE;\n\t\t}\n\n\t\tString getClassName() {\n\t\t\treturn this.className;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn this.order;\n\t\t}\n\n\t\tManagementContextType getContextType() {\n\t\t\treturn this.contextType;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.lang.reflect.Modifier;\n\nimport org.springframework.beans.FatalBeanException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.support.SystemEnvironmentPropertySourceEnvironmentPostProcessor;\nimport org.springframework.boot.web.server.WebServerFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\n\n/**\n * Factory for creating a separate management context when the management web server is\n * running on a different port to the main application.\n * <p>\n * <strong>For internal use only.</strong>\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class ManagementContextFactory {\n\n\tprivate final WebApplicationType webApplicationType;\n\n\tprivate final Class<? extends WebServerFactory> webServerFactoryClass;\n\n\tprivate final Class<?>[] autoConfigurationClasses;\n\n\tpublic ManagementContextFactory(WebApplicationType webApplicationType,\n\t\t\tClass<? extends WebServerFactory> webServerFactoryClass, Class<?>... autoConfigurationClasses) {\n\t\tthis.webApplicationType = webApplicationType;\n\t\tthis.webServerFactoryClass = webServerFactoryClass;\n\t\tthis.autoConfigurationClasses = autoConfigurationClasses;\n\t}\n\n\tpublic ConfigurableApplicationContext createManagementContext(ApplicationContext parentContext) {\n\t\tEnvironment parentEnvironment = parentContext.getEnvironment();\n\t\tConfigurableEnvironment childEnvironment = ApplicationContextFactory.DEFAULT\n\t\t\t.createEnvironment(this.webApplicationType);\n\t\tAssert.state(childEnvironment != null, \"'childEnvironment' must not be null\");\n\t\tif (parentEnvironment instanceof ConfigurableEnvironment configurableParentEnvironment) {\n\t\t\tpostProcessChildEnvironment(childEnvironment, configurableParentEnvironment);\n\t\t}\n\t\tConfigurableApplicationContext managementContext = ApplicationContextFactory.DEFAULT\n\t\t\t.create(this.webApplicationType);\n\t\tAssert.state(managementContext != null, \"'managementContext' must not be null\");\n\t\tmanagementContext.setEnvironment(childEnvironment);\n\t\tmanagementContext.setParent(parentContext);\n\t\treturn managementContext;\n\t}\n\n\tprivate void postProcessChildEnvironment(ConfigurableEnvironment childEnvironment,\n\t\t\tConfigurableEnvironment parentEnvironment) {\n\t\tchildEnvironment.setConversionService((parentEnvironment).getConversionService());\n\t\tSystemEnvironmentPropertySourceEnvironmentPostProcessor.postProcessEnvironment(childEnvironment,\n\t\t\t\tparentEnvironment);\n\t}\n\n\tpublic void registerWebServerFactoryBeans(ApplicationContext parentContext,\n\t\t\tConfigurableApplicationContext managementContext, AnnotationConfigRegistry registry) {\n\t\tif (this.autoConfigurationClasses != null && this.autoConfigurationClasses.length > 0) {\n\t\t\tregistry.register(this.autoConfigurationClasses);\n\t\t}\n\t\tregisterWebServerFactoryFromParent(parentContext, managementContext);\n\t}\n\n\tprivate void registerWebServerFactoryFromParent(ApplicationContext parentContext,\n\t\t\tConfigurableApplicationContext managementContext) {\n\t\ttry {\n\t\t\tif (managementContext.getBeanFactory() instanceof BeanDefinitionRegistry registry) {\n\t\t\t\tregistry.registerBeanDefinition(\"ManagementContextWebServerFactory\",\n\t\t\t\t\t\tnew RootBeanDefinition(determineWebServerFactoryClass(parentContext)));\n\t\t\t}\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t// Ignore and assume auto-configuration\n\t\t}\n\t}\n\n\tprivate Class<?> determineWebServerFactoryClass(ApplicationContext parent) throws NoSuchBeanDefinitionException {\n\t\tClass<?> factoryClass = parent.getBean(this.webServerFactoryClass).getClass();\n\t\tif (cannotBeInstantiated(factoryClass)) {\n\t\t\tthrow new FatalBeanException(\"ManagementContextWebServerFactory implementation \" + factoryClass.getName()\n\t\t\t\t\t+ \" cannot be instantiated. To allow a separate management port to be used, a top-level class \"\n\t\t\t\t\t+ \"or static inner class should be used instead\");\n\t\t}\n\t\treturn factoryClass;\n\t}\n\n\tprivate boolean cannotBeInstantiated(Class<?> factoryClass) {\n\t\treturn factoryClass.isLocalClass()\n\t\t\t\t|| (factoryClass.isMemberClass() && !Modifier.isStatic(factoryClass.getModifiers()))\n\t\t\t\t|| factoryClass.isAnonymousClass();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementPortType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\n\n/**\n * Port types that can be used to control how the management server is started.\n *\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic enum ManagementPortType {\n\n\t/**\n\t * The management port has been disabled.\n\t */\n\tDISABLED,\n\n\t/**\n\t * The management port is the same as the server port.\n\t */\n\tSAME,\n\n\t/**\n\t * The management port and server port are different.\n\t */\n\tDIFFERENT;\n\n\t/**\n\t * Look at the given environment to determine if the {@link ManagementPortType} is\n\t * {@link #DISABLED}, {@link #SAME} or {@link #DIFFERENT}.\n\t * @param environment the Spring environment\n\t * @return {@link #DISABLED} if {@code management.server.port} is set to a negative\n\t * value, {@link #SAME} if {@code management.server.port} is not specified or equal to\n\t * {@code server.port} and {@link #DIFFERENT} otherwise.\n\t * @since 2.1.4\n\t */\n\tpublic static ManagementPortType get(Environment environment) {\n\t\tInteger managementPort = getPortProperty(environment, \"management.server.\");\n\t\tif (managementPort != null && managementPort < 0) {\n\t\t\treturn DISABLED;\n\t\t}\n\t\tInteger serverPort = getPortProperty(environment, \"server.\");\n\t\treturn ((managementPort == null || (serverPort == null && managementPort.equals(8080))\n\t\t\t\t|| (managementPort != 0 && managementPort.equals(serverPort))) ? SAME : DIFFERENT);\n\t}\n\n\tprivate static @Nullable Integer getPortProperty(Environment environment, String prefix) {\n\t\treturn environment.getProperty(prefix + \"port\", Integer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.net.InetAddress;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.StringUtils;\n\n/**\n * Properties for the management server (e.g. port and path settings).\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Moritz Halbritter\n * @since 2.0.0\n * @see ServerProperties\n */\n@ConfigurationProperties(\"management.server\")\npublic class ManagementServerProperties {\n\n\t/**\n\t * Management endpoint HTTP port (uses the same port as the application by default).\n\t * Configure a different port to use management-specific SSL.\n\t */\n\tprivate @Nullable Integer port;\n\n\t/**\n\t * Network address to which the management endpoints should bind. Requires a custom\n\t * management.server.port.\n\t */\n\tprivate @Nullable InetAddress address;\n\n\t/**\n\t * Management endpoint base path (for instance, '/management'). Requires a custom\n\t * management.server.port.\n\t */\n\tprivate String basePath = \"\";\n\n\t@NestedConfigurationProperty\n\tprivate @Nullable Ssl ssl;\n\n\t/**\n\t * Returns the management port or {@code null} if the\n\t * {@link ServerProperties#getPort() server port} should be used.\n\t * @return the port\n\t * @see #setPort(Integer)\n\t */\n\tpublic @Nullable Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\t/**\n\t * Sets the port of the management server, use {@code null} if the\n\t * {@link ServerProperties#getPort() server port} should be used. Set to 0 to use a\n\t * random port or set to -1 to disable.\n\t * @param port the port\n\t */\n\tpublic void setPort(@Nullable Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable InetAddress getAddress() {\n\t\treturn this.address;\n\t}\n\n\tpublic void setAddress(@Nullable InetAddress address) {\n\t\tthis.address = address;\n\t}\n\n\tpublic String getBasePath() {\n\t\treturn this.basePath;\n\t}\n\n\tpublic void setBasePath(String basePath) {\n\t\tthis.basePath = cleanBasePath(basePath);\n\t}\n\n\tpublic @Nullable Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic void setSsl(@Nullable Ssl ssl) {\n\t\tthis.ssl = ssl;\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate @Nullable String cleanBasePath(@Nullable String basePath) {\n\t\tif (basePath == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString candidate = basePath.strip();\n\t\tif (StringUtils.hasText(candidate)) {\n\t\t\tif (!candidate.startsWith(\"/\")) {\n\t\t\t\tcandidate = \"/\" + candidate;\n\t\t\t}\n\t\t\tif (candidate.endsWith(\"/\")) {\n\t\t\t\tcandidate = candidate.substring(0, candidate.length() - 1);\n\t\t\t}\n\t\t}\n\t\treturn candidate;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * {@link WebServerFactoryCustomizer} that customizes the {@link WebServerFactory} used to\n * create the management context's web server.\n *\n * @param <T> the type of web server factory to customize\n * @author Andy Wilkinson\n * @since 2.0.0\n */\npublic class ManagementWebServerFactoryCustomizer<T extends ConfigurableWebServerFactory>\n\t\timplements WebServerFactoryCustomizer<T>, Ordered {\n\n\tprivate final ListableBeanFactory beanFactory;\n\n\tprivate final Class<? extends WebServerFactoryCustomizer<?>> @Nullable [] customizerClasses;\n\n\t/**\n\t * Creates a new customizer that will retrieve beans using the given\n\t * {@code beanFactory}.\n\t * @param beanFactory the bean factory to use\n\t * @since 3.5.0\n\t */\n\tpublic ManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t\tthis.customizerClasses = null;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic final void customize(T factory) {\n\t\tManagementServerProperties managementServerProperties = BeanFactoryUtils\n\t\t\t.beanOfTypeIncludingAncestors(this.beanFactory, ManagementServerProperties.class);\n\t\t// Customize as per the parent context first (so e.g. the access logs go to\n\t\t// the same place)\n\t\tif (this.customizerClasses != null) {\n\t\t\tcustomizeSameAsParentContext(factory);\n\t\t}\n\t\t// Then reset the error pages\n\t\tfactory.setErrorPages(Collections.emptySet());\n\t\t// and add the management-specific bits\n\t\tServerProperties serverProperties = BeanFactoryUtils.beanOfTypeIncludingAncestors(this.beanFactory,\n\t\t\t\tServerProperties.class);\n\t\tcustomize(factory, managementServerProperties, serverProperties);\n\t}\n\n\tprivate void customizeSameAsParentContext(T factory) {\n\t\tList<WebServerFactoryCustomizer<?>> customizers = new ArrayList<>();\n\t\tAssert.state(this.customizerClasses != null, \"'customizerClasses' must not be null\");\n\t\tfor (Class<? extends WebServerFactoryCustomizer<?>> customizerClass : this.customizerClasses) {\n\t\t\ttry {\n\t\t\t\tcustomizers.add(BeanFactoryUtils.beanOfTypeIncludingAncestors(this.beanFactory, customizerClass));\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tinvokeCustomizers(factory, customizers);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void invokeCustomizers(T factory, List<WebServerFactoryCustomizer<?>> customizers) {\n\t\tLambdaSafe.callbacks(WebServerFactoryCustomizer.class, customizers, factory)\n\t\t\t.invoke((customizer) -> customizer.customize(factory));\n\t}\n\n\tprotected void customize(T factory, ManagementServerProperties managementServerProperties,\n\t\t\tServerProperties serverProperties) {\n\t\tInteger port = managementServerProperties.getPort();\n\t\tAssert.state(port != null, \"'port' must not be null\");\n\t\tfactory.setPort(port);\n\t\tSsl ssl = managementServerProperties.getSsl();\n\t\tif (ssl != null) {\n\t\t\tfactory.setSsl(ssl);\n\t\t}\n\t\tfactory.setServerHeader(serverProperties.getServerHeader());\n\t\tfactory.setAddress(managementServerProperties.getAddress());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/OnManagementPortCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * {@link SpringBootCondition} that matches when the management server is running on a\n * different port.\n *\n * @author Andy Wilkinson\n */\nclass OnManagementPortCondition extends SpringBootCondition {\n\n\tprivate static final String CLASS_NAME_WEB_APPLICATION_CONTEXT = \"org.springframework.web.context.WebApplicationContext\";\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Management Port\");\n\t\tif (!isWebApplicationContext(context)) {\n\t\t\treturn ConditionOutcome.noMatch(message.because(\"non web application context\"));\n\t\t}\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnManagementPort.class.getName());\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tManagementPortType requiredType = (ManagementPortType) attributes.get(\"value\");\n\t\tManagementPortType actualType = ManagementPortType.get(context.getEnvironment());\n\t\tif (actualType == requiredType) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.match(message.because(\"actual port type (\" + actualType + \") matched required type\"));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message\n\t\t\t.because(\"actual port type (\" + actualType + \") did not match required type (\" + requiredType + \")\"));\n\t}\n\n\tprivate boolean isWebApplicationContext(ConditionContext context) {\n\t\tResourceLoader resourceLoader = context.getResourceLoader();\n\t\tif (resourceLoader instanceof ConfigurableReactiveWebApplicationContext) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!ClassUtils.isPresent(CLASS_NAME_WEB_APPLICATION_CONTEXT, context.getClassLoader())) {\n\t\t\treturn false;\n\t\t}\n\t\treturn resourceLoader instanceof WebApplicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/web/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator web server support.\n */\n@NullMarked\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"info\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.Object>\",\n      \"description\": \"Arbitrary properties to add to the info endpoint.\"\n    },\n    {\n      \"name\": \"management.auditevents.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable storage of audit events.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.cloudfoundry.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable extended Cloud Foundry actuator endpoints.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.cloudfoundry.skip-ssl-validation\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to skip SSL verification for Cloud Foundry actuator endpoint security calls.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.endpoints.access.default\",\n      \"type\": \"org.springframework.boot.actuate.endpoint.Access\",\n      \"description\": \"Default access level for all endpoints.\"\n    },\n    {\n      \"name\": \"management.endpoints.access.max-permitted\",\n      \"description\": \"Maximum level of endpoint access that is permitted. Caps an endpoint's individual access level (management.endpoint.<id>.access) and the default access (management.endpoints.access.default).'\",\n      \"defaultValue\": \"unrestricted\"\n    },\n    {\n      \"name\": \"management.endpoints.enabled-by-default\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable or disable all endpoints by default.\",\n      \"deprecation\": {\n        \"replacement\": \"management.endpoints.access.default\",\n        \"since\": \"3.4.0\"\n      }\n    },\n    {\n      \"name\": \"management.endpoints.jackson.isolated-json-mapper\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use an isolated JsonMapper to serialize endpoint JSON.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.endpoints.jackson2.isolated-object-mapper\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use an isolated object mapper to serialize endpoint JSON.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"reason\": \"Jackson 3 is preferred.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.endpoints.jmx.domain\",\n      \"defaultValue\": \"org.springframework.boot\"\n    },\n    {\n      \"name\": \"management.endpoints.jmx.exposure.include\",\n      \"defaultValue\": \"health\"\n    },\n    {\n      \"name\": \"management.endpoints.jmx.unique-names\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether unique runtime object names should be ensured.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.jmx.unique-names\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"management.endpoints.web.exposure.include\",\n      \"defaultValue\": [\n        \"health\"\n      ]\n    },\n    {\n      \"name\": \"management.httpexchanges.recording.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable HTTP request-response exchange recording.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.httpexchanges.recording.include\",\n      \"defaultValue\": [\n        \"request-headers\",\n        \"response-headers\",\n        \"errors\"\n      ]\n    },\n    {\n      \"name\": \"management.info.build.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable build info.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.info.defaults.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable default info contributors.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.info.env.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable environment info.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.info.git.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable git info.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.info.java.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Java info.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.info.os.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Operating System info.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.info.process.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable process info.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.info.ssl.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable SSL certificate info.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.logging.export.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether auto-configuration of logging is enabled to export logs.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.server.add-application-context-header\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Add the \\\"X-Application-Context\\\" HTTP header in each response.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.server.servlet.context-path\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"management.server.base-path\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.trace.http.enabled\",\n      \"deprecation\": {\n        \"replacement\": \"management.httpexchanges.recording.enabled\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.trace.http.include\",\n      \"deprecation\": {\n        \"replacement\": \"management.httpexchanges.recording.include\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.trace.include\",\n      \"deprecation\": {\n        \"replacement\": \"management.httpexchanges.recording.include\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.api-token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.api-token-type\",\n      \"type\": \"org.springframework.boot.actuate.autoconfigure.wavefront.WavefrontProperties$TokenType\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.application.cluster-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.application.custom-tags\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.application.name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.application.service-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.application.shard-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.global-prefix\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.report-day-distribution\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.report-hour-distribution\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.report-minute-distribution\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.metrics.export.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.sender.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.sender.flush-interval\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.sender.max-queue-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.sender.message-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.source\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.trace-derived-custom-tag-keys\",\n      \"type\": \"java.util.Set<java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.tracing.export.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.wavefront.uri\",\n      \"type\": \"java.net.URI\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Wavefront is end-of-life.\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"management.endpoints.web.cors.allowed-headers\",\n      \"values\": [\n        {\n          \"value\": \"*\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"management.endpoints.web.cors.allowed-methods\",\n      \"values\": [\n        {\n          \"value\": \"*\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"management.endpoints.web.cors.allowed-origins\",\n      \"values\": [\n        {\n          \"value\": \"*\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.endpoint.jackson.Jackson2EndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.logging.LoggersEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.management.HeapDumpWebEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.management.ThreadDumpEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.sbom.SbomEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.startup.StartupEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration\norg.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/audit/AuditAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.audit;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.audit.AuditEvent;\nimport org.springframework.boot.actuate.audit.AuditEventRepository;\nimport org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;\nimport org.springframework.boot.actuate.audit.listener.AbstractAuditListener;\nimport org.springframework.boot.actuate.audit.listener.AuditListener;\nimport org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener;\nimport org.springframework.boot.actuate.security.AbstractAuthorizationAuditListener;\nimport org.springframework.boot.actuate.security.AuthenticationAuditListener;\nimport org.springframework.boot.actuate.security.AuthorizationAuditListener;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.event.AbstractAuthenticationEvent;\nimport org.springframework.security.authorization.event.AuthorizationEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AuditAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @author Madhura Bhave\n */\nclass AuditAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AuditAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationIsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(AuditAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsEnabledWhenAuditEventRepositoryBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBean(AuditEventRepository.class)).isNotNull();\n\t\t\tassertThat(context.getBean(AuthenticationAuditListener.class)).isNotNull();\n\t\t\tassertThat(context.getBean(AuthorizationAuditListener.class)).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid ownAuthenticationAuditListener() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class)\n\t\t\t.withUserConfiguration(CustomAuthenticationAuditListenerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(AbstractAuthenticationAuditListener.class))\n\t\t\t\t.isInstanceOf(TestAuthenticationAuditListener.class));\n\t}\n\n\t@Test\n\tvoid ownAuthorizationAuditListener() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class)\n\t\t\t.withUserConfiguration(CustomAuthorizationAuditListenerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(AbstractAuthorizationAuditListener.class))\n\t\t\t\t.isInstanceOf(TestAuthorizationAuditListener.class));\n\t}\n\n\t@Test\n\tvoid ownAuditListener() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class)\n\t\t\t.withUserConfiguration(CustomAuditListenerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(AbstractAuditListener.class))\n\t\t\t\t.isInstanceOf(TestAuditListener.class));\n\t}\n\n\t@Test\n\tvoid backsOffWhenDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.auditevents.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AuditListener.class)\n\t\t\t\t.doesNotHaveBean(AuthenticationAuditListener.class)\n\t\t\t\t.doesNotHaveBean(AuthorizationAuditListener.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAuditEventRepositoryConfiguration {\n\n\t\t@Bean\n\t\tTestAuditEventRepository testAuditEventRepository() {\n\t\t\treturn new TestAuditEventRepository();\n\t\t}\n\n\t}\n\n\tstatic class TestAuditEventRepository extends InMemoryAuditEventRepository {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAuthenticationAuditListenerConfiguration {\n\n\t\t@Bean\n\t\tTestAuthenticationAuditListener authenticationAuditListener() {\n\t\t\treturn new TestAuthenticationAuditListener();\n\t\t}\n\n\t}\n\n\tstatic class TestAuthenticationAuditListener extends AbstractAuthenticationAuditListener {\n\n\t\t@Override\n\t\tpublic void setApplicationEventPublisher(ApplicationEventPublisher publisher) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(AbstractAuthenticationEvent event) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAuthorizationAuditListenerConfiguration {\n\n\t\t@Bean\n\t\tTestAuthorizationAuditListener authorizationAuditListener() {\n\t\t\treturn new TestAuthorizationAuditListener();\n\t\t}\n\n\t}\n\n\tstatic class TestAuthorizationAuditListener extends AbstractAuthorizationAuditListener {\n\n\t\t@Override\n\t\tpublic void setApplicationEventPublisher(ApplicationEventPublisher publisher) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(AuthorizationEvent event) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAuditListenerConfiguration {\n\n\t\t@Bean\n\t\tTestAuditListener testAuditListener() {\n\t\t\treturn new TestAuditListener();\n\t\t}\n\n\t}\n\n\tstatic class TestAuditListener extends AbstractAuditListener {\n\n\t\t@Override\n\t\tprotected void onAuditEvent(AuditEvent event) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/audit/AuditEventsEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.audit;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.audit.AuditEventsEndpoint;\nimport org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AuditEventsEndpointAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Vedran Pavic\n */\nclass AuditEventsEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(AuditAutoConfiguration.class, AuditEventsEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runWhenRepositoryBeanAvailableShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=auditevents\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AuditEventsEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointBacksOffWhenRepositoryNotAvailable() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=auditevents\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AuditEventsEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(AuditEventsEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpoint() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAuditEventRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.auditevents.enabled:false\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AuditEventsEndpoint.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAuditEventRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryAuditEventRepository testAuditEventRepository() {\n\t\t\treturn new InMemoryAuditEventRepository();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/beans/BeansEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.beans;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.beans.BeansEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BeansEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass BeansEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BeansEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=beans\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(BeansEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(BeansEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.beans.enabled:false\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BeansEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/condition/ConditionsReportEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionsReportEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass ConditionsReportEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ConditionsReportEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=conditions\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConditionsReportEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ConditionsReportEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.conditions.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConditionsReportEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/condition/ConditionsReportEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.condition;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpoint.ContextConditionsDescriptor;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConditionsReportEndpoint}.\n *\n * @author Greg Turnquist\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ConditionsReportEndpointTests {\n\n\t@Test\n\tvoid invoke() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(Config.class).run((context) -> {\n\t\t\tContextConditionsDescriptor report = context.getBean(ConditionsReportEndpoint.class)\n\t\t\t\t.conditions()\n\t\t\t\t.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(report).isNotNull();\n\t\t\tassertThat(report.getPositiveMatches()).isEmpty();\n\t\t\tassertThat(report.getNegativeMatches()).containsKey(\"a\");\n\t\t\tassertThat(report.getUnconditionalClasses()).contains(\"b\");\n\t\t\tassertThat(report.getExclusions()).contains(\"com.foo.Bar\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class Config {\n\n\t\tprivate final ConfigurableApplicationContext context;\n\n\t\tConfig(ConfigurableApplicationContext context) {\n\t\t\tthis.context = context;\n\t\t\tsetupAutoConfigurationReport();\n\t\t}\n\n\t\tprivate void setupAutoConfigurationReport() {\n\t\t\tConditionEvaluationReport report = ConditionEvaluationReport.get(this.context.getBeanFactory());\n\t\t\treport.recordEvaluationCandidates(Arrays.asList(\"a\", \"b\"));\n\t\t\treport.recordConditionEvaluation(\"a\", mock(Condition.class), mock(ConditionOutcome.class));\n\t\t\treport.recordExclusions(Collections.singletonList(\"com.foo.Bar\"));\n\t\t}\n\n\t\t@Bean\n\t\tConditionsReportEndpoint endpoint() {\n\t\t\treturn new ConditionsReportEndpoint(this.context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/context/ShutdownEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.context;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.actuate.context.ShutdownEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ShutdownEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass ShutdownEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ShutdownEndpointAutoConfiguration.class));\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid runShouldHaveEndpointBeanThatIsNotDisposable() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.shutdown.enabled:true\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=shutdown\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ShutdownEndpoint.class);\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tMap<String, Object> disposableBeans = (Map<String, Object>) ReflectionTestUtils.getField(beanFactory,\n\t\t\t\t\t\t\"disposableBeans\");\n\t\t\t\tassertThat(disposableBeans).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.shutdown.enabled:true\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ShutdownEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.shutdown.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ShutdownEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/context/properties/ConfigurationPropertiesReportEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.context.properties;\n\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesBeanDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpoint.ContextConfigurationPropertiesDescriptor;\nimport org.springframework.boot.actuate.context.properties.ConfigurationPropertiesReportEndpointWebExtension;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfigurationPropertiesReportEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass ConfigurationPropertiesReportEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ConfigurationPropertiesReportEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=configprops\")\n\t\t\t.run(validateTestProperties(\"******\", \"******\"));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.configprops.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConfigurationPropertiesReportEndpoint.class));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid rolesCanBeConfiguredViaTheEnvironment() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"management.endpoint.configprops.roles: test\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=configprops\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConfigurationPropertiesReportEndpointWebExtension.class);\n\t\t\t\tConfigurationPropertiesReportEndpointWebExtension endpoint = context\n\t\t\t\t\t.getBean(ConfigurationPropertiesReportEndpointWebExtension.class);\n\t\t\t\tSet<String> roles = (Set<String>) ReflectionTestUtils.getField(endpoint, \"roles\");\n\t\t\t\tassertThat(roles).contains(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid showValuesCanBeConfiguredViaTheEnvironment() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"management.endpoint.configprops.show-values: WHEN_AUTHORIZED\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=configprops\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\t\tassertThat(context).hasSingleBean(ConfigurationPropertiesReportEndpointWebExtension.class);\n\t\t\t\tConfigurationPropertiesReportEndpointWebExtension webExtension = context\n\t\t\t\t\t.getBean(ConfigurationPropertiesReportEndpointWebExtension.class);\n\t\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\t\tShow showValuesWebExtension = (Show) ReflectionTestUtils.getField(webExtension, \"showValues\");\n\t\t\t\tassertThat(showValuesWebExtension).isEqualTo(Show.WHEN_AUTHORIZED);\n\t\t\t\tShow showValues = (Show) ReflectionTestUtils.getField(endpoint, \"showValues\");\n\t\t\t\tassertThat(showValues).isEqualTo(Show.WHEN_AUTHORIZED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customSanitizingFunctionsAreAppliedInOrder() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.configprops.show-values: ALWAYS\")\n\t\t\t.withUserConfiguration(Config.class, SanitizingFunctionConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=configprops\", \"test.my-test-property=abc\")\n\t\t\t.run(validateTestProperties(\"$$$111$$$\", \"$$$222$$$\"));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConfigurationPropertiesReportEndpoint.class));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> validateTestProperties(String dbPassword,\n\t\t\tString myTestProperty) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesReportEndpoint endpoint = context\n\t\t\t\t.getBean(ConfigurationPropertiesReportEndpoint.class);\n\t\t\tConfigurationPropertiesDescriptor properties = endpoint.configurationProperties();\n\t\t\tContextConfigurationPropertiesDescriptor contextDescriptor = properties.getContexts().get(context.getId());\n\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\tConfigurationPropertiesBeanDescriptor testProperties = contextDescriptor.getBeans().get(\"testProperties\");\n\t\t\tassertThat(testProperties).isNotNull();\n\t\t\tMap<String, @Nullable Object> nestedProperties = testProperties.getProperties();\n\t\t\tassertThat(nestedProperties).isNotNull();\n\t\t\tassertThat(nestedProperties).containsEntry(\"dbPassword\", dbPassword);\n\t\t\tassertThat(nestedProperties).containsEntry(\"myTestProperty\", myTestProperty);\n\t\t};\n\t}\n\n\t@Test\n\tvoid runWhenOnlyExposedOverJmxShouldHaveEndpointBeanWithoutWebExtension() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info\", \"spring.jmx.enabled=true\",\n\t\t\t\t\t\"management.endpoints.jmx.exposure.include=configprops\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConfigurationPropertiesReportEndpoint.class)\n\t\t\t\t.doesNotHaveBean(ConfigurationPropertiesReportEndpointWebExtension.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class Config {\n\n\t\t@Bean\n\t\tTestProperties testProperties() {\n\t\t\treturn new TestProperties();\n\t\t}\n\n\t}\n\n\t@ConfigurationProperties(\"test\")\n\tpublic static class TestProperties {\n\n\t\tprivate String dbPassword = \"123456\";\n\n\t\tprivate String myTestProperty = \"654321\";\n\n\t\tpublic String getDbPassword() {\n\t\t\treturn this.dbPassword;\n\t\t}\n\n\t\tpublic void setDbPassword(String dbPassword) {\n\t\t\tthis.dbPassword = dbPassword;\n\t\t}\n\n\t\tpublic String getMyTestProperty() {\n\t\t\treturn this.myTestProperty;\n\t\t}\n\n\t\tpublic void setMyTestProperty(String myTestProperty) {\n\t\t\tthis.myTestProperty = myTestProperty;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SanitizingFunctionConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tSanitizingFunction firstSanitizingFunction() {\n\t\t\treturn (data) -> {\n\t\t\t\tif (data.getKey().contains(\"Password\")) {\n\t\t\t\t\treturn data.withValue(\"$$$111$$$\");\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSanitizingFunction secondSanitizingFunction() {\n\t\t\treturn (data) -> {\n\t\t\t\tif (data.getKey().contains(\"Password\") || data.getKey().contains(\"test\")) {\n\t\t\t\t\treturn data.withValue(\"$$$222$$$\");\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointConverter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationParameter;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterMappingException;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.ConverterNotFoundException;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link EndpointAutoConfiguration}.\n *\n * @author Chao Chang\n */\nclass EndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid mapShouldUseConfigurationConverter() {\n\t\tthis.contextRunner.withUserConfiguration(ConverterConfiguration.class).run((context) -> {\n\t\t\tParameterValueMapper parameterValueMapper = context.getBean(ParameterValueMapper.class);\n\t\t\tObject paramValue = parameterValueMapper.mapParameterValue(new TestOperationParameter(Person.class),\n\t\t\t\t\t\"John Smith\");\n\t\t\tassertThat(paramValue).isInstanceOf(Person.class);\n\t\t\tPerson person = (Person) paramValue;\n\t\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid mapWhenConfigurationConverterIsNotQualifiedShouldNotConvert() {\n\t\tassertThatExceptionOfType(ParameterMappingException.class).isThrownBy(() -> {\n\t\t\tthis.contextRunner.withUserConfiguration(NonQualifiedConverterConfiguration.class).run((context) -> {\n\t\t\t\tParameterValueMapper parameterValueMapper = context.getBean(ParameterValueMapper.class);\n\t\t\t\tparameterValueMapper.mapParameterValue(new TestOperationParameter(Person.class), \"John Smith\");\n\t\t\t});\n\n\t\t}).withCauseInstanceOf(ConverterNotFoundException.class);\n\t}\n\n\t@Test\n\tvoid mapShouldUseGenericConfigurationConverter() {\n\t\tthis.contextRunner.withUserConfiguration(GenericConverterConfiguration.class).run((context) -> {\n\t\t\tParameterValueMapper parameterValueMapper = context.getBean(ParameterValueMapper.class);\n\t\t\tObject paramValue = parameterValueMapper.mapParameterValue(new TestOperationParameter(Person.class),\n\t\t\t\t\t\"John Smith\");\n\t\t\tassertThat(paramValue).isInstanceOf(Person.class);\n\t\t\tPerson person = (Person) paramValue;\n\t\t\tassertThat(person.firstName).isEqualTo(\"John\");\n\t\t\tassertThat(person.lastName).isEqualTo(\"Smith\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid mapWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() {\n\t\tassertThatExceptionOfType(ParameterMappingException.class).isThrownBy(() -> {\n\t\t\tthis.contextRunner.withUserConfiguration(NonQualifiedGenericConverterConfiguration.class).run((context) -> {\n\t\t\t\tParameterValueMapper parameterValueMapper = context.getBean(ParameterValueMapper.class);\n\t\t\t\tparameterValueMapper.mapParameterValue(new TestOperationParameter(Person.class), \"John Smith\");\n\t\t\t});\n\n\t\t}).withCauseInstanceOf(ConverterNotFoundException.class);\n\n\t}\n\n\tstatic class PersonConverter implements Converter<String, Person> {\n\n\t\t@Override\n\t\tpublic Person convert(String source) {\n\t\t\tString[] content = StringUtils.split(source, \" \");\n\t\t\tassertThat(content).isNotNull();\n\t\t\treturn new Person(content[0], content[1]);\n\t\t}\n\n\t}\n\n\tstatic class GenericPersonConverter implements GenericConverter {\n\n\t\t@Override\n\t\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\t\treturn Collections.singleton(new ConvertiblePair(String.class, Person.class));\n\t\t}\n\n\t\t@Override\n\t\tpublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tString[] content = StringUtils.split((String) source, \" \");\n\t\t\tassertThat(content).isNotNull();\n\t\t\treturn new Person(content[0], content[1]);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConverterConfiguration {\n\n\t\t@Bean\n\t\t@EndpointConverter\n\t\tConverter<String, Person> personConverter() {\n\t\t\treturn new PersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonQualifiedConverterConfiguration {\n\n\t\t@Bean\n\t\tConverter<String, Person> personConverter() {\n\t\t\treturn new PersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GenericConverterConfiguration {\n\n\t\t@Bean\n\t\t@EndpointConverter\n\t\tGenericConverter genericPersonConverter() {\n\t\t\treturn new GenericPersonConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonQualifiedGenericConverterConfiguration {\n\n\t\t@Bean\n\t\tGenericConverter genericPersonConverter() {\n\t\t\treturn new GenericPersonConverter();\n\t\t}\n\n\t}\n\n\tstatic class Person {\n\n\t\tprivate final String firstName;\n\n\t\tprivate final String lastName;\n\n\t\tPerson(String firstName, String lastName) {\n\t\t\tthis.firstName = firstName;\n\t\t\tthis.lastName = lastName;\n\t\t}\n\n\t}\n\n\tprivate static class TestOperationParameter implements OperationParameter {\n\n\t\tprivate final Class<?> type;\n\n\t\tTestOperationParameter(Class<?> type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getName() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isMandatory() {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic <T extends Annotation> @Nullable T getAnnotation(Class<T> annotation) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/EndpointIdTimeToLivePropertyFunctionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EndpointIdTimeToLivePropertyFunction}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass EndpointIdTimeToLivePropertyFunctionTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final Function<EndpointId, @Nullable Long> timeToLive = new EndpointIdTimeToLivePropertyFunction(\n\t\t\tthis.environment);\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tLong result = this.timeToLive.apply(EndpointId.of(\"test\"));\n\t\tassertThat(result).isNull();\n\t}\n\n\t@Test\n\tvoid userConfiguration() {\n\t\tthis.environment.setProperty(\"management.endpoint.test.cache.time-to-live\", \"500\");\n\t\tLong result = this.timeToLive.apply(EndpointId.of(\"test\"));\n\t\tassertThat(result).isEqualTo(500L);\n\t}\n\n\t@Test\n\tvoid mixedCaseUserConfiguration() {\n\t\tthis.environment.setProperty(\"management.endpoint.another-test.cache.time-to-live\", \"500\");\n\t\tLong result = this.timeToLive.apply(EndpointId.of(\"anotherTest\"));\n\t\tassertThat(result).isEqualTo(500L);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link PropertiesEndpointAccessResolver}.\n *\n * @author Andy Wilkinson\n */\nclass PropertiesEndpointAccessResolverTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tPropertiesEndpointAccessResolverTests() {\n\t\tConfigurationPropertySources.attach(this.environment);\n\t}\n\n\t@Test\n\tvoid whenNoPropertiesAreConfiguredThenAccessForReturnsEndpointsDefaultAccess() {\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.READ_ONLY);\n\t}\n\n\t@Test\n\tvoid whenDefaultAccessForAllEndpointsIsConfiguredThenAccessForReturnsDefaultForAllEndpoints() {\n\t\tthis.environment.withProperty(\"management.endpoints.access.default\", Access.UNRESTRICTED.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED);\n\t}\n\n\t@Test\n\tvoid whenAccessForEndpointIsConfiguredThenAccessForReturnsIt() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.access\", Access.UNRESTRICTED.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED);\n\t}\n\n\t@Test\n\tvoid whenAccessForEndpointWithCamelCaseIdIsConfiguredThenAccessForReturnsIt() {\n\t\tthis.environment.withProperty(\"management.endpoint.alpha-bravo.access\", Access.UNRESTRICTED.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"alphaBravo\"), Access.READ_ONLY))\n\t\t\t.isEqualTo(Access.UNRESTRICTED);\n\t}\n\n\t@Test\n\tvoid whenAccessForEndpointAndDefaultAccessForAllEndpointsAreConfiguredAccessForReturnsAccessForEndpoint() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.access\", Access.NONE.name())\n\t\t\t.withProperty(\"management.endpoints.access.default\", Access.UNRESTRICTED.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.NONE);\n\t}\n\n\t@Test\n\tvoid whenAllEndpointsAreDisabledByDefaultAccessForReturnsNone() {\n\t\tthis.environment.withProperty(\"management.endpoints.enabled-by-default\", \"false\");\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.NONE);\n\t}\n\n\t@Test\n\tvoid whenAllEndpointsAreEnabledByDefaultAccessForReturnsUnrestricted() {\n\t\tthis.environment.withProperty(\"management.endpoints.enabled-by-default\", \"true\");\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED);\n\t}\n\n\t@Test\n\tvoid whenEndpointIsDisabledAccessForReturnsNone() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.enabled\", \"false\");\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.NONE);\n\t}\n\n\t@Test\n\tvoid whenEndpointIsEnabledAccessForReturnsUnrestricted() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.enabled\", \"true\");\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED);\n\t}\n\n\t@Test\n\tvoid whenEndpointWithCamelCaseIdIsEnabledAccessForReturnsUnrestricted() {\n\t\tthis.environment.withProperty(\"management.endpoint.alpha-bravo.enabled\", \"true\");\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"alphaBravo\"), Access.READ_ONLY))\n\t\t\t.isEqualTo(Access.UNRESTRICTED);\n\t}\n\n\t@Test\n\tvoid whenEnabledByDefaultAndDefaultAccessAreBothConfiguredResolverCreationThrows() {\n\t\tthis.environment.withProperty(\"management.endpoints.enabled-by-default\", \"true\")\n\t\t\t.withProperty(\"management.endpoints.access.default\", Access.READ_ONLY.name());\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(this::accessResolver);\n\t}\n\n\t@Test\n\tvoid whenEndpointEnabledAndAccessAreBothConfiguredAccessForThrows() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.enabled\", \"true\")\n\t\t\t.withProperty(\"management.endpoint.test.access\", Access.READ_ONLY.name());\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(() -> accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY));\n\t}\n\n\t@Test\n\tvoid whenAllEndpointsAreEnabledByDefaultAndAccessIsLimitedToReadOnlyAccessForReturnsReadOnly() {\n\t\tthis.environment.withProperty(\"management.endpoints.enabled-by-default\", \"true\")\n\t\t\t.withProperty(\"management.endpoints.access.max-permitted\", Access.READ_ONLY.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.READ_ONLY);\n\t}\n\n\t@Test\n\tvoid whenAllEndpointsHaveUnrestrictedDefaultAccessAndAccessIsLimitedToReadOnlyAccessForReturnsReadOnly() {\n\t\tthis.environment.withProperty(\"management.endpoints.access.default\", Access.UNRESTRICTED.name())\n\t\t\t.withProperty(\"management.endpoints.access.max-permitted\", Access.READ_ONLY.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.READ_ONLY);\n\t}\n\n\t@Test\n\tvoid whenEndpointsIsEnabledAndAccessIsLimitedToNoneAccessForReturnsNone() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.enabled\", \"true\")\n\t\t\t.withProperty(\"management.endpoints.access.max-permitted\", Access.NONE.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.NONE);\n\t}\n\n\t@Test\n\tvoid whenEndpointsHasUnrestrictedAccessAndAccessIsLimitedToNoneAccessForReturnsNone() {\n\t\tthis.environment.withProperty(\"management.endpoint.test.access\", Access.UNRESTRICTED.name())\n\t\t\t.withProperty(\"management.endpoints.access.max-permitted\", Access.NONE.name());\n\t\tassertThat(accessResolver().accessFor(EndpointId.of(\"test\"), Access.READ_ONLY)).isEqualTo(Access.NONE);\n\t}\n\n\tprivate PropertiesEndpointAccessResolver accessResolver() {\n\t\treturn new PropertiesEndpointAccessResolver(this.environment);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/ConditionalOnAvailableEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.condition;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnAvailableEndpoint @ConditionalOnAvailableEndpoint}.\n *\n * @author Brian Clozel\n */\nclass ConditionalOnAvailableEndpointTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(AllEndpointsConfiguration.class)\n\t\t.withInitializer(\n\t\t\t\t(context) -> context.getEnvironment().setConversionService(new ApplicationConversionService()));\n\n\t@Test\n\tvoid outcomeShouldMatchDefaults() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"health\")\n\t\t\t.doesNotHaveBean(\"spring\")\n\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWithEnabledByDefaultSetToFalseShouldNotMatchAnything() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.enabled-by-default=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllWebShouldMatchEnabledEndpoints() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"info\")\n\t\t\t\t.hasBean(\"health\")\n\t\t\t\t.hasBean(\"test\")\n\t\t\t\t.hasBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllWebAndDisablingEndpointShouldMatchEnabledEndpoints() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\", \"management.endpoint.test.enabled=false\",\n\t\t\t\t\t\"management.endpoint.health.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.hasBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllWebAndEnablingEndpointDisabledByDefaultShouldMatchAll() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoint.shutdown.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"info\")\n\t\t\t\t.hasBean(\"health\")\n\t\t\t\t.hasBean(\"test\")\n\t\t\t\t.hasBean(\"spring\")\n\t\t\t\t.hasBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllJmxButJmxDisabledShouldMatchDefaults() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllJmxAndJmxEnabledShouldMatchEnabledEndpoints() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\", \"spring.jmx.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"info\")\n\t\t\t\t.hasBean(\"health\")\n\t\t\t\t.hasBean(\"test\")\n\t\t\t\t.hasBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllJmxAndJmxEnabledAndEnablingEndpointDisabledByDefaultShouldMatchAll() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.jmx.exposure.include=*\", \"spring.jmx.enabled=true\",\n\t\t\t\t\t\"management.endpoint.shutdown.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"health\")\n\t\t\t\t.hasBean(\"test\")\n\t\t\t\t.hasBean(\"spring\")\n\t\t\t\t.hasBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeAllWebAndExcludeMatchesShouldNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.web.exposure.exclude=spring,info\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"health\")\n\t\t\t\t.hasBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchesAndExcludeMatchesShouldNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info,health,spring,test\",\n\t\t\t\t\t\"management.endpoints.web.exposure.exclude=spring,info\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"health\")\n\t\t\t\t.hasBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchesShouldMatchEnabledEndpoints() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=spring\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchOnDisabledEndpointShouldNotMatch() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=shutdown\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchOnEnabledEndpointShouldNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=shutdown\",\n\t\t\t\t\t\"management.endpoint.shutdown.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.hasBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchesWithCaseShouldMatch() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=sPRing\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchesAndExcludeAllShouldNotMatch() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info,health,spring,test\",\n\t\t\t\t\t\"management.endpoints.web.exposure.exclude=*\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"spring\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWhenIncludeMatchesShouldMatchWithExtensionsAndComponents() {\n\t\tthis.contextRunner.withUserConfiguration(ComponentEnabledIfEndpointIsExposedConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=spring\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"spring\")\n\t\t\t\t.hasBean(\"springComponent\")\n\t\t\t\t.hasBean(\"springExtension\")\n\t\t\t\t.doesNotHaveBean(\"info\")\n\t\t\t\t.doesNotHaveBean(\"health\")\n\t\t\t\t.doesNotHaveBean(\"test\")\n\t\t\t\t.doesNotHaveBean(\"shutdown\"));\n\t}\n\n\t@Test\n\tvoid outcomeWithNoEndpointReferenceShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(ComponentWithNoEndpointReferenceConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tThrowable startupFailure = context.getStartupFailure();\n\t\t\t\tassertThat(startupFailure).isNotNull();\n\t\t\t\tThrowable cause = startupFailure.getCause();\n\t\t\t\tassertThat(cause).isNotNull();\n\t\t\t\tassertThat(cause.getMessage())\n\t\t\t\t\t.contains(\"No endpoint is specified and the return type of the @Bean method \"\n\t\t\t\t\t\t\t+ \"is neither an @Endpoint, nor an @EndpointExtension\");\n\t\t\t});\n\t}\n\n\t@Test // gh-21044\n\tvoid outcomeWhenIncludeAllShouldMatchDashedEndpoint() {\n\t\tthis.contextRunner.withUserConfiguration(DashedEndpointConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DashedEndpoint.class));\n\t}\n\n\t@Test // gh-21044\n\tvoid outcomeWhenIncludeDashedShouldMatchDashedEndpoint() {\n\t\tthis.contextRunner.withUserConfiguration(DashedEndpointConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=test-dashed\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DashedEndpoint.class));\n\t}\n\n\t@Test\n\tvoid outcomeWhenEndpointNotExposedOnSpecifiedTechnology() {\n\t\tthis.contextRunner.withUserConfiguration(ExposureEndpointConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"management.endpoints.jmx.exposure.include=test\",\n\t\t\t\t\t\"management.endpoints.web.exposure.exclude=test\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"unexposed\"));\n\t}\n\n\t@Test\n\tvoid whenBothAccessAndEnabledAreConfiguredThenThrows() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoint.shutdown.enabled=true\", \"management.endpoint.shutdown.access=none\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Test\n\tvoid whenBothDefaultAccessAndDefaultEnabledAreConfiguredThenThrows() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.enabled-by-default=true\", \"management.endpoints.access.default=none\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Test\n\t@WithTestEndpointOutcomeExposureContributor\n\tvoid exposureOutcomeContributorCanMakeEndpointAvailable() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.test.exposure.include=test\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(TestEndpoint.class));\n\t}\n\n\t@Endpoint(id = \"health\")\n\tstatic class HealthEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"info\")\n\tstatic class InfoEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"spring\")\n\tstatic class SpringEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"shutdown\", defaultAccess = Access.NONE)\n\tstatic class ShutdownEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"test-dashed\")\n\tstatic class DashedEndpoint {\n\n\t}\n\n\t@EndpointExtension(endpoint = SpringEndpoint.class, filter = TestFilter.class)\n\tstatic class SpringEndpointExtension {\n\n\t}\n\n\tstatic class TestFilter implements EndpointFilter<ExposableEndpoint<?>> {\n\n\t\t@Override\n\t\tpublic boolean match(ExposableEndpoint<?> endpoint) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AllEndpointsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tHealthEndpoint health() {\n\t\t\treturn new HealthEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tInfoEndpoint info() {\n\t\t\treturn new InfoEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tSpringEndpoint spring() {\n\t\t\treturn new SpringEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tTestEndpoint test() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tShutdownEndpoint shutdown() {\n\t\t\treturn new ShutdownEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ComponentEnabledIfEndpointIsExposedConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint(SpringEndpoint.class)\n\t\tString springComponent() {\n\t\t\treturn \"springComponent\";\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tSpringEndpointExtension springExtension() {\n\t\t\treturn new SpringEndpointExtension();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ComponentWithNoEndpointReferenceConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tString springcomp() {\n\t\t\treturn \"springcomp\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DashedEndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tDashedEndpoint dashedEndpoint() {\n\t\t\treturn new DashedEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExposureEndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint(endpoint = TestEndpoint.class, exposure = EndpointExposure.WEB)\n\t\tString unexposed() {\n\t\t\treturn \"unexposed\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/expose/IncludeExcludeEndpointFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.expose;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link IncludeExcludeEndpointFilter}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass IncludeExcludeEndpointFilterTests {\n\n\tprivate @Nullable IncludeExcludeEndpointFilter<?> filter;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenEndpointTypeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new IncludeExcludeEndpointFilter<>(null, new MockEnvironment(), \"foo\"))\n\t\t\t.withMessageContaining(\"'endpointType' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenEnvironmentIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, null, \"foo\"))\n\t\t\t.withMessageContaining(\"'environment' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPrefixIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, new MockEnvironment(), null))\n\t\t\t.withMessageContaining(\"'prefix' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenPrefixIsEmptyShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, new MockEnvironment(), \"\"))\n\t\t\t.withMessageContaining(\"'prefix' must not be empty\");\n\t}\n\n\t@Test\n\tvoid matchWhenExposeIsEmptyAndExcludeIsEmptyAndInDefaultShouldMatch() {\n\t\tsetupFilter(\"\", \"\");\n\t\tassertThat(match(EndpointId.of(\"def\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenExposeIsEmptyAndExcludeIsEmptyAndNotInDefaultShouldNotMatch() {\n\t\tsetupFilter(\"\", \"\");\n\t\tassertThat(match(EndpointId.of(\"bar\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenExposeMatchesAndExcludeIsEmptyShouldMatch() {\n\t\tsetupFilter(\"bar\", \"\");\n\t\tassertThat(match(EndpointId.of(\"bar\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenExposeDoesNotMatchAndExcludeIsEmptyShouldNotMatch() {\n\t\tsetupFilter(\"bar\", \"\");\n\t\tassertThat(match(EndpointId.of(\"baz\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenExposeMatchesAndExcludeMatchesShouldNotMatch() {\n\t\tsetupFilter(\"bar,baz\", \"baz\");\n\t\tassertThat(match(EndpointId.of(\"baz\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenExposeMatchesAndExcludeDoesNotMatchShouldMatch() {\n\t\tsetupFilter(\"bar,baz\", \"buz\");\n\t\tassertThat(match(EndpointId.of(\"baz\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenExposeMatchesWithDifferentCaseShouldMatch() {\n\t\tsetupFilter(\"bar\", \"\");\n\t\tassertThat(match(EndpointId.of(\"bAr\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenDiscovererDoesNotMatchShouldMatch() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"foo.include\", \"bar\");\n\t\tenvironment.setProperty(\"foo.exclude\", \"\");\n\t\tthis.filter = new IncludeExcludeEndpointFilter<>(DifferentTestExposableWebEndpoint.class, environment, \"foo\");\n\t\tassertThat(match()).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenIncludeIsAsteriskShouldMatchAll() {\n\t\tsetupFilter(\"*\", \"buz\");\n\t\tassertThat(match(EndpointId.of(\"bar\"))).isTrue();\n\t\tassertThat(match(EndpointId.of(\"baz\"))).isTrue();\n\t\tassertThat(match(EndpointId.of(\"buz\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenExcludeIsAsteriskShouldMatchNone() {\n\t\tsetupFilter(\"bar,baz,buz\", \"*\");\n\t\tassertThat(match(EndpointId.of(\"bar\"))).isFalse();\n\t\tassertThat(match(EndpointId.of(\"baz\"))).isFalse();\n\t\tassertThat(match(EndpointId.of(\"buz\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenMixedCaseShouldMatch() {\n\t\tsetupFilter(\"foo-bar\", \"\");\n\t\tassertThat(match(EndpointId.of(\"fooBar\"))).isTrue();\n\t}\n\n\t@Test // gh-20997\n\tvoid matchWhenDashInName() {\n\t\tsetupFilter(\"bus-refresh\", \"\");\n\t\tassertThat(match(EndpointId.of(\"bus-refresh\"))).isTrue();\n\t}\n\n\tprivate void setupFilter(String include, String exclude) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"foo.include\", include);\n\t\tenvironment.setProperty(\"foo.exclude\", exclude);\n\t\tthis.filter = new IncludeExcludeEndpointFilter<>(TestExposableWebEndpoint.class, environment, \"foo\", \"def\");\n\t}\n\n\tprivate boolean match() {\n\t\treturn match(null);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate boolean match(@Nullable EndpointId id) {\n\t\tExposableEndpoint<?> endpoint = mock(TestExposableWebEndpoint.class);\n\t\tif (id != null) {\n\t\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\t}\n\t\tEndpointFilter filter = this.filter;\n\t\tassertThat(filter).isNotNull();\n\t\treturn filter.match(endpoint);\n\t}\n\n\tabstract static class TestExposableWebEndpoint implements ExposableWebEndpoint {\n\n\t}\n\n\tabstract static class DifferentTestExposableWebEndpoint implements ExposableWebEndpoint {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/Jackson2EndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jackson;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Jackson2EndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@SuppressWarnings(\"removal\")\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass Jackson2EndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(Jackson2EndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid endpointObjectMapperWhenNoProperty() {\n\t\tthis.runner.run((context) -> assertThat(context)\n\t\t\t.hasSingleBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperWhenPropertyTrue() {\n\t\tthis.runner.run((context) -> assertThat(context)\n\t\t\t.hasSingleBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperWhenPropertyFalse() {\n\t\tthis.runner.withPropertyValues(\"management.endpoints.jackson2.isolated-object-mapper=false\")\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperWhenSpringWebIsAbsent() {\n\t\tthis.runner.withClassLoader(new FilteredClassLoader(Jackson2ObjectMapperBuilder.class))\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperDoesNotSerializeDatesAsTimestamps() {\n\t\tthis.runner.run((context) -> {\n\t\t\tObjectMapper objectMapper = context\n\t\t\t\t.getBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)\n\t\t\t\t.get();\n\t\t\tInstant now = Instant.now();\n\t\t\tString json = objectMapper.writeValueAsString(Map.of(\"timestamp\", now));\n\t\t\tassertThat(json).contains(DateTimeFormatter.ISO_INSTANT.format(now));\n\t\t});\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperDoesNotSerializeDurationsAsTimestamps() {\n\t\tthis.runner.run((context) -> {\n\t\t\tObjectMapper objectMapper = context\n\t\t\t\t.getBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)\n\t\t\t\t.get();\n\t\t\tDuration duration = Duration.ofSeconds(42);\n\t\t\tString json = objectMapper.writeValueAsString(Map.of(\"duration\", duration));\n\t\t\tassertThat(json).contains(duration.toString());\n\t\t});\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperDoesNotSerializeNullValues() {\n\t\tthis.runner.run((context) -> {\n\t\t\tObjectMapper objectMapper = context\n\t\t\t\t.getBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)\n\t\t\t\t.get();\n\t\t\tHashMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"key\", null);\n\t\t\tString json = objectMapper.writeValueAsString(map);\n\t\t\tassertThat(json).isEqualTo(\"{}\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestEndpointMapperConfiguration {\n\n\t\t@Bean\n\t\tTestEndpointJsonMapper testEndpointJsonMapper() {\n\t\t\treturn new TestEndpointJsonMapper();\n\t\t}\n\n\t}\n\n\tstatic class TestEndpointJsonMapper implements EndpointJsonMapper {\n\n\t\t@Override\n\t\tpublic JsonMapper get() {\n\t\t\treturn new JsonMapper();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jackson/JacksonEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jackson;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.format.DateTimeFormatter;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JacksonEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass JacksonEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid endpointJsonMapperWhenNoProperty() {\n\t\tthis.runner.run((context) -> assertThat(context).hasSingleBean(EndpointJsonMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperWhenPropertyTrue() {\n\t\tthis.runner.withPropertyValues(\"management.endpoints.jackson.isolated-json-mapper=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(EndpointJsonMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperWhenPropertyFalse() {\n\t\tthis.runner.withPropertyValues(\"management.endpoints.jackson.isolated-json-mapper=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(EndpointJsonMapper.class));\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperDoesNotSerializeDatesAsTimestamps() {\n\t\tthis.runner.run((context) -> {\n\t\t\tJsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();\n\t\t\tInstant now = Instant.now();\n\t\t\tString json = jsonMapper.writeValueAsString(Map.of(\"timestamp\", now));\n\t\t\tassertThat(json).contains(DateTimeFormatter.ISO_INSTANT.format(now));\n\t\t});\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperDoesNotSerializeDurationsAsTimestamps() {\n\t\tthis.runner.run((context) -> {\n\t\t\tJsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();\n\t\t\tDuration duration = Duration.ofSeconds(42);\n\t\t\tString json = jsonMapper.writeValueAsString(Map.of(\"duration\", duration));\n\t\t\tassertThat(json).contains(duration.toString());\n\t\t});\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperDoesNotSerializeNullValues() {\n\t\tthis.runner.run((context) -> {\n\t\t\tJsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();\n\t\t\tHashMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"key\", null);\n\t\t\tString json = jsonMapper.writeValueAsString(map);\n\t\t\tassertThat(json).isEqualTo(\"{}\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestEndpointMapperConfiguration {\n\n\t\t@Bean\n\t\tTestEndpointJsonMapper testEndpointJsonMapper() {\n\t\t\treturn new TestEndpointJsonMapper();\n\t\t}\n\n\t}\n\n\tstatic class TestEndpointJsonMapper implements EndpointJsonMapper {\n\n\t\t@Override\n\t\tpublic JsonMapper get() {\n\t\t\treturn new JsonMapper();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/DefaultEndpointObjectNameFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport java.util.Collections;\n\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectName;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.jmx.ExposableJmxEndpoint;\nimport org.springframework.boot.autoconfigure.jmx.JmxProperties;\nimport org.springframework.util.ObjectUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultEndpointObjectNameFactory}.\n *\n * @author Stephane Nicoll\n */\nclass DefaultEndpointObjectNameFactoryTests {\n\n\tprivate final JmxEndpointProperties properties = new JmxEndpointProperties();\n\n\tprivate final JmxProperties jmxProperties = new JmxProperties();\n\n\tprivate final MBeanServer mBeanServer = mock(MBeanServer.class);\n\n\tprivate @Nullable String contextId;\n\n\t@Test\n\tvoid generateObjectName() {\n\t\tObjectName objectName = generateObjectName(endpoint(EndpointId.of(\"test\")));\n\t\tassertThat(objectName).hasToString(\"org.springframework.boot:type=Endpoint,name=Test\");\n\t}\n\n\t@Test\n\tvoid generateObjectNameWithCapitalizedId() {\n\t\tObjectName objectName = generateObjectName(endpoint(EndpointId.of(\"testEndpoint\")));\n\t\tassertThat(objectName).hasToString(\"org.springframework.boot:type=Endpoint,name=TestEndpoint\");\n\t}\n\n\t@Test\n\tvoid generateObjectNameWithCustomDomain() {\n\t\tthis.properties.setDomain(\"com.example.acme\");\n\t\tObjectName objectName = generateObjectName(endpoint(EndpointId.of(\"test\")));\n\t\tassertThat(objectName).hasToString(\"com.example.acme:type=Endpoint,name=Test\");\n\t}\n\n\t@Test\n\tvoid generateObjectNameWithUniqueNames() {\n\t\tthis.jmxProperties.setUniqueNames(true);\n\t\tassertUniqueObjectName();\n\t}\n\n\tprivate void assertUniqueObjectName() {\n\t\tExposableJmxEndpoint endpoint = endpoint(EndpointId.of(\"test\"));\n\t\tString id = ObjectUtils.getIdentityHexString(endpoint);\n\t\tObjectName objectName = generateObjectName(endpoint);\n\t\tassertThat(objectName).hasToString(\"org.springframework.boot:type=Endpoint,name=Test,identity=\" + id);\n\t}\n\n\t@Test\n\tvoid generateObjectNameWithStaticNames() {\n\t\tthis.properties.getStaticNames().setProperty(\"counter\", \"42\");\n\t\tthis.properties.getStaticNames().setProperty(\"foo\", \"bar\");\n\t\tObjectName objectName = generateObjectName(endpoint(EndpointId.of(\"test\")));\n\t\tassertThat(objectName.getKeyProperty(\"counter\")).isEqualTo(\"42\");\n\t\tassertThat(objectName.getKeyProperty(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(objectName.toString()).startsWith(\"org.springframework.boot:type=Endpoint,name=Test,\");\n\t}\n\n\t@Test\n\tvoid generateObjectNameWithDuplicate() throws MalformedObjectNameException {\n\t\tthis.contextId = \"testContext\";\n\t\tgiven(this.mBeanServer.queryNames(new ObjectName(\"org.springframework.boot:type=Endpoint,name=Test,*\"), null))\n\t\t\t.willReturn(Collections.singleton(new ObjectName(\"org.springframework.boot:type=Endpoint,name=Test\")));\n\t\tObjectName objectName = generateObjectName(endpoint(EndpointId.of(\"test\")));\n\t\tassertThat(objectName).hasToString(\"org.springframework.boot:type=Endpoint,name=Test,context=testContext\");\n\n\t}\n\n\tprivate ObjectName generateObjectName(ExposableJmxEndpoint endpoint) {\n\t\ttry {\n\t\t\treturn new DefaultEndpointObjectNameFactory(this.properties, this.jmxProperties, this.mBeanServer,\n\t\t\t\t\tthis.contextId)\n\t\t\t\t.getObjectName(endpoint);\n\t\t}\n\t\tcatch (MalformedObjectNameException ex) {\n\t\t\tthrow new AssertionError(\"Invalid object name\", ex);\n\t\t}\n\t}\n\n\tprivate ExposableJmxEndpoint endpoint(EndpointId id) {\n\t\tExposableJmxEndpoint endpoint = mock(ExposableJmxEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\treturn endpoint;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/jmx/JmxEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.jmx;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.jmx.EndpointObjectNameFactory;\nimport org.springframework.boot.actuate.endpoint.jmx.JmxEndpointExporter;\nimport org.springframework.boot.actuate.endpoint.jmx.annotation.JmxEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link JmxEndpointAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass JmxEndpointAutoConfigurationTests {\n\n\tprivate static final ContextConsumer<ConfigurableApplicationContext> NO_OPERATION = (context) -> {\n\t};\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class, JmxAutoConfiguration.class,\n\t\t\t\tJmxEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(TestEndpoint.class);\n\n\tprivate final MBeanServer mBeanServer = mock(MBeanServer.class);\n\n\t@Test\n\tvoid jmxEndpointWithoutJmxSupportNotAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(MBeanServer.class)\n\t\t\t.doesNotHaveBean(JmxEndpointDiscoverer.class)\n\t\t\t.doesNotHaveBean(JmxEndpointExporter.class));\n\t}\n\n\t@Test\n\tvoid jmxEndpointWithJmxSupportAutoConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jmx.enabled=true\")\n\t\t\t.with(mockMBeanServer())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JmxEndpointDiscoverer.class)\n\t\t\t\t.hasSingleBean(JmxEndpointExporter.class));\n\t}\n\n\t@Test\n\tvoid jmxEndpointWithCustomEndpointObjectNameFactory() {\n\t\tEndpointObjectNameFactory factory = mock(EndpointObjectNameFactory.class);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"management.endpoints.jmx.exposure.include=test\")\n\t\t\t.with(mockMBeanServer())\n\t\t\t.withBean(EndpointObjectNameFactory.class, () -> factory)\n\t\t\t.run((context) -> then(factory).should()\n\t\t\t\t.getObjectName(assertArg((jmxEndpoint) -> assertThat(jmxEndpoint.getEndpointId().toLowerCaseString())\n\t\t\t\t\t.isEqualTo(\"test\"))));\n\t}\n\n\t@Test\n\tvoid jmxEndpointWithContextHierarchyGeneratesUniqueNamesForEachEndpoint() throws Exception {\n\t\tgiven(this.mBeanServer.queryNames(any(), any()))\n\t\t\t.willReturn(new HashSet<>(Arrays.asList(new ObjectName(\"test:test=test\"))));\n\t\tArgumentCaptor<ObjectName> objectName = ArgumentCaptor.forClass(ObjectName.class);\n\t\tApplicationContextRunner jmxEnabledContextRunner = this.contextRunner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"management.endpoints.jmx.exposure.include=test\");\n\t\tjmxEnabledContextRunner.with(mockMBeanServer()).run((parent) -> {\n\t\t\tjmxEnabledContextRunner.withParent(parent).run(NO_OPERATION);\n\t\t\tjmxEnabledContextRunner.withParent(parent).run(NO_OPERATION);\n\t\t});\n\t\tthen(this.mBeanServer).should(times(3)).registerMBean(any(Object.class), objectName.capture());\n\t\tSet<ObjectName> uniqueValues = new HashSet<>(objectName.getAllValues());\n\t\tassertThat(uniqueValues).hasSize(3);\n\t\tassertThat(uniqueValues).allMatch((name) -> name.getDomain().equals(\"org.springframework.boot\"));\n\t\tassertThat(uniqueValues).allMatch((name) -> name.getKeyProperty(\"type\").equals(\"Endpoint\"));\n\t\tassertThat(uniqueValues).allMatch((name) -> name.getKeyProperty(\"name\").equals(\"Test\"));\n\t\tassertThat(uniqueValues).allMatch((name) -> name.getKeyProperty(\"context\") != null);\n\t}\n\n\tprivate Function<ApplicationContextRunner, ApplicationContextRunner> mockMBeanServer() {\n\t\treturn (ctxRunner) -> ctxRunner.withBean(\"mbeanServer\", MBeanServer.class, () -> this.mBeanServer);\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\tString hello() {\n\t\t\treturn \"hello world\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/MappingWebEndpointPathMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MappingWebEndpointPathMapper}.\n *\n * @author Stephane Nicoll\n */\nclass MappingWebEndpointPathMapperTests {\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tMappingWebEndpointPathMapper mapper = new MappingWebEndpointPathMapper(Collections.emptyMap());\n\t\tassertThat(PathMapper.getRootPath(Collections.singletonList(mapper), EndpointId.of(\"test\"))).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid userConfiguration() {\n\t\tMappingWebEndpointPathMapper mapper = new MappingWebEndpointPathMapper(\n\t\t\t\tCollections.singletonMap(\"test\", \"custom\"));\n\t\tassertThat(PathMapper.getRootPath(Collections.singletonList(mapper), EndpointId.of(\"test\")))\n\t\t\t.isEqualTo(\"custom\");\n\t}\n\n\t@Test\n\tvoid mixedCaseDefaultConfiguration() {\n\t\tMappingWebEndpointPathMapper mapper = new MappingWebEndpointPathMapper(Collections.emptyMap());\n\t\tassertThat(PathMapper.getRootPath(Collections.singletonList(mapper), EndpointId.of(\"testEndpoint\")))\n\t\t\t.isEqualTo(\"testEndpoint\");\n\t}\n\n\t@Test\n\tvoid mixedCaseUserConfiguration() {\n\t\tMappingWebEndpointPathMapper mapper = new MappingWebEndpointPathMapper(\n\t\t\t\tCollections.singletonMap(\"test-endpoint\", \"custom\"));\n\t\tassertThat(PathMapper.getRootPath(Collections.singletonList(mapper), EndpointId.of(\"testEndpoint\")))\n\t\t\t.isEqualTo(\"custom\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.stereotype.Component;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebEndpointAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Yunkun Huang\n * @author Phillip Webb\n */\nclass WebEndpointAutoConfigurationTests {\n\n\tprivate static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\tprivate static final AutoConfigurations CONFIGURATIONS = AutoConfigurations.of(EndpointAutoConfiguration.class,\n\t\t\tWebEndpointAutoConfiguration.class);\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(CONFIGURATIONS);\n\n\t@Test\n\tvoid webApplicationConfiguresEndpointMediaTypes() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tEndpointMediaTypes endpointMediaTypes = context.getBean(EndpointMediaTypes.class);\n\t\t\tassertThat(endpointMediaTypes.getConsumed()).containsExactly(V3_JSON, V2_JSON, \"application/json\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid webApplicationConfiguresPathMapper() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.path-mapping.health=healthcheck\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PathMapper.class);\n\t\t\t\tString pathMapping = context.getBean(PathMapper.class).getRootPath(EndpointId.of(\"health\"));\n\t\t\t\tassertThat(pathMapping).isEqualTo(\"healthcheck\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid webApplicationSupportCustomPathMatcher() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.web.path-mapping.testanotherone=foo\")\n\t\t\t.withUserConfiguration(TestPathMatcher.class, TestOneEndpoint.class, TestAnotherOneEndpoint.class,\n\t\t\t\t\tTestTwoEndpoint.class)\n\t\t\t.run((context) -> {\n\t\t\t\tWebEndpointDiscoverer discoverer = context.getBean(WebEndpointDiscoverer.class);\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\t\tExposableWebEndpoint[] webEndpoints = endpoints.toArray(new ExposableWebEndpoint[0]);\n\t\t\t\tList<String> paths = Arrays.stream(webEndpoints).map(PathMappedEndpoint::getRootPath).toList();\n\t\t\t\tassertThat(paths).containsOnly(\"1/testone\", \"foo\", \"testtwo\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid webApplicationConfiguresEndpointDiscoverer() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(\n\t\t\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointDiscoverer.class);\n\t\t\tassertThat(context).hasSingleBean(WebEndpointDiscoverer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid webApplicationConfiguresExposeExcludePropertyEndpointFilter() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBeans(IncludeExcludeEndpointFilter.class)\n\t\t\t.containsKeys(\"webExposeExcludePropertyEndpointFilter\", \"controllerExposeExcludePropertyEndpointFilter\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid contextShouldConfigureServletEndpointDiscoverer() {\n\t\tthis.contextRunner.run((context) -> assertThat(context)\n\t\t\t.hasSingleBean(org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer.class));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid contextWhenNotServletShouldNotConfigureServletEndpointDiscoverer() {\n\t\tnew ApplicationContextRunner().withConfiguration(CONFIGURATIONS)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\n\t\t\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointDiscoverer.class));\n\t}\n\n\t@Component\n\tstatic class TestPathMatcher implements PathMapper {\n\n\t\t@Override\n\t\tpublic @Nullable String getRootPath(EndpointId endpointId) {\n\t\t\tif (endpointId.toString().endsWith(\"one\")) {\n\t\t\t\treturn \"1/\" + endpointId;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Component\n\t@Endpoint(id = \"testone\")\n\tstatic class TestOneEndpoint {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t}\n\n\t@Component\n\t@Endpoint(id = \"testanotherone\")\n\tstatic class TestAnotherOneEndpoint {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t}\n\n\t@Component\n\t@Endpoint(id = \"testtwo\")\n\tstatic class TestTwoEndpoint {\n\n\t\t@ReadOperation\n\t\tString read() {\n\t\t\treturn \"read\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link WebEndpointProperties}.\n *\n * @author Madhura Bhave\n */\nclass WebEndpointPropertiesTests {\n\n\t@Test\n\tvoid defaultBasePathShouldBeApplication() {\n\t\tWebEndpointProperties properties = new WebEndpointProperties();\n\t\tassertThat(properties.getBasePath()).isEqualTo(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid basePathShouldBeCleaned() {\n\t\tWebEndpointProperties properties = new WebEndpointProperties();\n\t\tproperties.setBasePath(\"/\");\n\t\tassertThat(properties.getBasePath()).isEmpty();\n\t\tproperties.setBasePath(\"/actuator/\");\n\t\tassertThat(properties.getBasePath()).isEqualTo(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid basePathMustStartWithSlash() {\n\t\tWebEndpointProperties properties = new WebEndpointProperties();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> properties.setBasePath(\"admin\"))\n\t\t\t.withMessageContaining(\"'basePath' must start with '/' or be empty\");\n\t}\n\n\t@Test\n\tvoid basePathCanBeEmpty() {\n\t\tWebEndpointProperties properties = new WebEndpointProperties();\n\t\tproperties.setBasePath(\"\");\n\t\tassertThat(properties.getBasePath()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/env/EnvironmentEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.env;\n\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.EnvironmentDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertySourceDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpoint.PropertyValueDescriptor;\nimport org.springframework.boot.actuate.env.EnvironmentEndpointWebExtension;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EnvironmentEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass EnvironmentEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(EnvironmentEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=env\")\n\t\t\t.withSystemProperties(\"dbPassword=123456\", \"apiKey=123456\")\n\t\t\t.run(validateSystemProperties(\"******\", \"******\"));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.env.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(EnvironmentEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(EnvironmentEndpoint.class));\n\t}\n\n\t@Test\n\tvoid customSanitizingFunctionsAreAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(SanitizingFunctionConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.env.show-values: WHEN_AUTHORIZED\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=env\")\n\t\t\t.withSystemProperties(\"custom=123456\", \"password=123456\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(EnvironmentEndpoint.class);\n\t\t\t\tEnvironmentEndpoint endpoint = context.getBean(EnvironmentEndpoint.class);\n\t\t\t\tEnvironmentDescriptor env = endpoint.environment(null);\n\t\t\t\tMap<String, PropertyValueDescriptor> systemProperties = getSource(\"systemProperties\", env)\n\t\t\t\t\t.getProperties();\n\t\t\t\tPropertyValueDescriptor custom = systemProperties.get(\"custom\");\n\t\t\t\tassertThat(custom).isNotNull();\n\t\t\t\tassertThat(custom.getValue()).isEqualTo(\"$$$111$$$\");\n\t\t\t\tPropertyValueDescriptor password = systemProperties.get(\"password\");\n\t\t\t\tassertThat(password).isNotNull();\n\t\t\t\tassertThat(password.getValue()).isEqualTo(\"$$$222$$$\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid rolesCanBeConfiguredViaTheEnvironment() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.env.roles: test\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=env\")\n\t\t\t.withSystemProperties(\"dbPassword=123456\", \"apiKey=123456\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(EnvironmentEndpointWebExtension.class);\n\t\t\t\tEnvironmentEndpointWebExtension endpoint = context.getBean(EnvironmentEndpointWebExtension.class);\n\t\t\t\tSet<String> roles = (Set<String>) ReflectionTestUtils.getField(endpoint, \"roles\");\n\t\t\t\tassertThat(roles).contains(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid showValuesCanBeConfiguredViaTheEnvironment() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.env.show-values: WHEN_AUTHORIZED\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=env\")\n\t\t\t.withSystemProperties(\"dbPassword=123456\", \"apiKey=123456\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(EnvironmentEndpoint.class);\n\t\t\t\tassertThat(context).hasSingleBean(EnvironmentEndpointWebExtension.class);\n\t\t\t\tEnvironmentEndpointWebExtension webExtension = context.getBean(EnvironmentEndpointWebExtension.class);\n\t\t\t\tEnvironmentEndpoint endpoint = context.getBean(EnvironmentEndpoint.class);\n\t\t\t\tassertThat(webExtension).extracting(\"showValues\").isEqualTo(Show.WHEN_AUTHORIZED);\n\t\t\t\tassertThat(endpoint).extracting(\"showValues\").isEqualTo(Show.WHEN_AUTHORIZED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenOnlyExposedOverJmxShouldHaveEndpointBeanWithoutWebExtension() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info\", \"spring.jmx.enabled=true\",\n\t\t\t\t\t\"management.endpoints.jmx.exposure.include=env\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(EnvironmentEndpoint.class)\n\t\t\t\t.doesNotHaveBean(EnvironmentEndpointWebExtension.class));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> validateSystemProperties(String expectedPassword,\n\t\t\tString expectedApiKey) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(EnvironmentEndpoint.class);\n\t\t\tEnvironmentEndpoint endpoint = context.getBean(EnvironmentEndpoint.class);\n\t\t\tEnvironmentDescriptor env = endpoint.environment(null);\n\t\t\tMap<String, PropertyValueDescriptor> systemProperties = getSource(\"systemProperties\", env).getProperties();\n\t\t\tPropertyValueDescriptor dbPassword = systemProperties.get(\"dbPassword\");\n\t\t\tassertThat(dbPassword).isNotNull();\n\t\t\tassertThat(dbPassword.getValue()).isEqualTo(expectedPassword);\n\t\t\tPropertyValueDescriptor apiKey = systemProperties.get(\"apiKey\");\n\t\t\tassertThat(apiKey).isNotNull();\n\t\t\tassertThat(apiKey.getValue()).isEqualTo(expectedApiKey);\n\t\t};\n\t}\n\n\tprivate PropertySourceDescriptor getSource(String name, EnvironmentDescriptor descriptor) {\n\t\treturn descriptor.getPropertySources()\n\t\t\t.stream()\n\t\t\t.filter((source) -> name.equals(source.getName()))\n\t\t\t.findFirst()\n\t\t\t.get();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SanitizingFunctionConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tSanitizingFunction firstSanitizingFunction() {\n\t\t\treturn (data) -> {\n\t\t\t\tif (data.getKey().contains(\"custom\")) {\n\t\t\t\t\treturn data.withValue(\"$$$111$$$\");\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSanitizingFunction secondSanitizingFunction() {\n\t\t\treturn (data) -> {\n\t\t\t\tif (data.getKey().contains(\"custom\") || data.getKey().contains(\"password\")) {\n\t\t\t\t\treturn data.withValue(\"$$$222$$$\");\n\t\t\t\t}\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.info.BuildInfoContributor;\nimport org.springframework.boot.actuate.info.EnvironmentInfoContributor;\nimport org.springframework.boot.actuate.info.GitInfoContributor;\nimport org.springframework.boot.actuate.info.Info;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.boot.actuate.info.JavaInfoContributor;\nimport org.springframework.boot.actuate.info.OsInfoContributor;\nimport org.springframework.boot.actuate.info.ProcessInfoContributor;\nimport org.springframework.boot.actuate.info.SslInfoContributor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.info.BuildProperties;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.boot.info.JavaInfo;\nimport org.springframework.boot.info.OsInfo;\nimport org.springframework.boot.info.ProcessInfo;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InfoContributorAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Jonatan Ivanov\n */\nclass InfoContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(InfoContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid envContributor() {\n\t\tthis.contextRunner.withPropertyValues(\"management.info.env.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(EnvironmentInfoContributor.class));\n\t}\n\n\t@Test\n\tvoid defaultInfoContributorsEnabled() {\n\t\tthis.contextRunner.run(\n\t\t\t\t(context) -> assertThat(context).doesNotHaveBean(InfoContributor.class).doesNotHaveBean(SslInfo.class));\n\t}\n\n\t@Test\n\tvoid defaultInfoContributorsEnabledWithPrerequisitesInPlace() {\n\t\tthis.contextRunner.withUserConfiguration(GitPropertiesConfiguration.class, BuildPropertiesConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(InfoContributor.class)).hasSize(2)\n\t\t\t\t.satisfies((contributors) -> assertThat(contributors.values())\n\t\t\t\t\t.hasOnlyElementsOfTypes(BuildInfoContributor.class, GitInfoContributor.class)));\n\t}\n\n\t@Test\n\tvoid defaultInfoContributorsDisabledWithPrerequisitesInPlace() {\n\t\tthis.contextRunner.withUserConfiguration(GitPropertiesConfiguration.class, BuildPropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"management.info.defaults.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(InfoContributor.class));\n\t}\n\n\t@Test\n\tvoid defaultInfoContributorsDisabledWithCustomOne() {\n\t\tthis.contextRunner.withUserConfiguration(CustomInfoContributorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(InfoContributor.class);\n\t\t\tassertThat(context.getBean(InfoContributor.class)).isSameAs(context.getBean(\"customInfoContributor\"));\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid gitPropertiesDefaultMode() {\n\t\tthis.contextRunner.withUserConfiguration(GitPropertiesConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GitInfoContributor.class);\n\t\t\tMap<String, Object> content = invokeContributor(context.getBean(GitInfoContributor.class));\n\t\t\tObject git = content.get(\"git\");\n\t\t\tassertThat(git).isInstanceOf(Map.class);\n\t\t\tMap<String, Object> gitInfo = (Map<String, Object>) git;\n\t\t\tassertThat(gitInfo).containsOnlyKeys(\"branch\", \"commit\");\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid gitPropertiesFullMode() {\n\t\tthis.contextRunner.withPropertyValues(\"management.info.git.mode=full\")\n\t\t\t.withUserConfiguration(GitPropertiesConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GitInfoContributor.class);\n\t\t\t\tMap<String, Object> content = invokeContributor(context.getBean(GitInfoContributor.class));\n\t\t\t\tObject git = content.get(\"git\");\n\t\t\t\tassertThat(git).isInstanceOf(Map.class);\n\t\t\t\tMap<String, Object> gitInfo = (Map<String, Object>) git;\n\t\t\t\tassertThat(gitInfo).containsOnlyKeys(\"branch\", \"commit\", \"foo\");\n\t\t\t\tassertThat(gitInfo).containsEntry(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customGitInfoContributor() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGitInfoContributorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GitInfoContributor.class);\n\t\t\tassertThat(context.getBean(GitInfoContributor.class)).isSameAs(context.getBean(\"customGitInfoContributor\"));\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid buildProperties() {\n\t\tthis.contextRunner.withUserConfiguration(BuildPropertiesConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BuildInfoContributor.class);\n\t\t\tMap<String, Object> content = invokeContributor(context.getBean(BuildInfoContributor.class));\n\t\t\tObject build = content.get(\"build\");\n\t\t\tassertThat(build).isInstanceOf(Map.class);\n\t\t\tMap<String, Object> buildInfo = (Map<String, Object>) build;\n\t\t\tassertThat(buildInfo).containsOnlyKeys(\"group\", \"artifact\", \"foo\");\n\t\t\tassertThat(buildInfo).containsEntry(\"foo\", \"bar\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customBuildInfoContributor() {\n\t\tthis.contextRunner.withUserConfiguration(CustomBuildInfoContributorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BuildInfoContributor.class);\n\t\t\tassertThat(context.getBean(BuildInfoContributor.class))\n\t\t\t\t.isSameAs(context.getBean(\"customBuildInfoContributor\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid javaInfoContributor() {\n\t\tthis.contextRunner.withPropertyValues(\"management.info.java.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JavaInfoContributor.class);\n\t\t\tMap<String, Object> content = invokeContributor(context.getBean(JavaInfoContributor.class));\n\t\t\tassertThat(content).containsKey(\"java\");\n\t\t\tassertThat(content.get(\"java\")).isInstanceOf(JavaInfo.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid osInfoContributor() {\n\t\tthis.contextRunner.withPropertyValues(\"management.info.os.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OsInfoContributor.class);\n\t\t\tMap<String, Object> content = invokeContributor(context.getBean(OsInfoContributor.class));\n\t\t\tassertThat(content).containsKey(\"os\");\n\t\t\tassertThat(content.get(\"os\")).isInstanceOf(OsInfo.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid processInfoContributor() {\n\t\tthis.contextRunner.withPropertyValues(\"management.info.process.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ProcessInfoContributor.class);\n\t\t\tMap<String, Object> content = invokeContributor(context.getBean(ProcessInfoContributor.class));\n\t\t\tassertThat(content).containsKey(\"process\");\n\t\t\tassertThat(content.get(\"process\")).isInstanceOf(ProcessInfo.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid sslInfoContributor() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.info.ssl.enabled=true\", \"server.ssl.bundle=ssltest\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.ssltest.keystore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SslInfoContributor.class);\n\t\t\t\tassertThat(context).hasSingleBean(SslInfo.class);\n\t\t\t\tMap<String, Object> content = invokeContributor(context.getBean(SslInfoContributor.class));\n\t\t\t\tassertThat(content).containsKey(\"ssl\");\n\t\t\t\tassertThat(content.get(\"ssl\")).isInstanceOf(SslInfo.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customSslInfo() {\n\t\tthis.contextRunner.withUserConfiguration(CustomSslInfoConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.info.ssl.enabled=true\", \"server.ssl.bundle=ssltest\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.ssltest.keystore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SslInfoContributor.class);\n\t\t\t\tassertThat(context).hasSingleBean(SslInfo.class);\n\t\t\t\tassertThat(context.getBean(SslInfo.class)).isSameAs(context.getBean(\"customSslInfo\"));\n\t\t\t\tMap<String, Object> content = invokeContributor(context.getBean(SslInfoContributor.class));\n\t\t\t\tassertThat(content).containsKey(\"ssl\");\n\t\t\t\tassertThat(content.get(\"ssl\")).isInstanceOf(SslInfo.class);\n\t\t\t});\n\t}\n\n\tprivate Map<String, Object> invokeContributor(InfoContributor contributor) {\n\t\tInfo.Builder builder = new Info.Builder();\n\t\tcontributor.contribute(builder);\n\t\treturn builder.build().getDetails();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GitPropertiesConfiguration {\n\n\t\t@Bean\n\t\tGitProperties gitProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(\"branch\", \"master\");\n\t\t\tproperties.put(\"commit.id\", \"abcdefg\");\n\t\t\tproperties.put(\"foo\", \"bar\");\n\t\t\treturn new GitProperties(properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BuildPropertiesConfiguration {\n\n\t\t@Bean\n\t\tBuildProperties buildProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(\"group\", \"com.example\");\n\t\t\tproperties.put(\"artifact\", \"demo\");\n\t\t\tproperties.put(\"foo\", \"bar\");\n\t\t\treturn new BuildProperties(properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomInfoContributorConfiguration {\n\n\t\t@Bean\n\t\tInfoContributor customInfoContributor() {\n\t\t\treturn (builder) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomGitInfoContributorConfiguration {\n\n\t\t@Bean\n\t\tGitInfoContributor customGitInfoContributor() {\n\t\t\treturn new GitInfoContributor(new GitProperties(new Properties()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBuildInfoContributorConfiguration {\n\n\t\t@Bean\n\t\tBuildInfoContributor customBuildInfoContributor() {\n\t\t\treturn new BuildInfoContributor(new BuildProperties(new Properties()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSslInfoConfiguration {\n\n\t\t@Bean\n\t\tSslInfo customSslInfo(SslBundles sslBundles) {\n\t\t\treturn new SslInfo(sslBundles);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/info/InfoEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.info;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.info.InfoEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InfoEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass InfoEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(InfoEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=info\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(InfoEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(InfoEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.info.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(InfoEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/LogFileWebEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.logging;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.actuate.logging.LogFileWebEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Tests for {@link LogFileWebEndpointAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Christian Carriere-Tisseur\n */\nclass LogFileWebEndpointAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LogFileWebEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runWithOnlyExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=logfile\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenLoggingFileIsSetAndNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"logging.file.name:test.log\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenLoggingFileIsSetAndExposedShouldHaveEndpointBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"logging.file.name:test.log\", \"management.endpoints.web.exposure.include=logfile\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenLoggingPathIsSetAndNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"logging.file.path:test/logs\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenLoggingPathIsSetAndExposedShouldHaveEndpointBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"logging.file.path:test/logs\", \"management.endpoints.web.exposure.include=logfile\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid logFileWebEndpointIsAutoConfiguredWhenExternalFileIsSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.logfile.external-file:external.log\",\n\t\t\t\t\t\"management.endpoints.web.exposure.include=logfile\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid logFileWebEndpointCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"logging.file.name:test.log\", \"management.endpoint.logfile.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LogFileWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid logFileWebEndpointUsesConfiguredExternalFile(@TempDir Path temp) throws IOException {\n\t\tFile file = new File(temp.toFile(), \"logfile\");\n\t\tFileCopyUtils.copy(\"--TEST--\".getBytes(), file);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=logfile\",\n\t\t\t\t\t\"management.endpoint.logfile.external-file:\" + file.getAbsolutePath())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LogFileWebEndpoint.class);\n\t\t\t\tLogFileWebEndpoint endpoint = context.getBean(LogFileWebEndpoint.class);\n\t\t\t\tResource resource = endpoint.logFile();\n\t\t\t\tassertThat(resource).isNotNull();\n\t\t\t\tassertThat(contentOf(resource.getFile())).isEqualTo(\"--TEST--\");\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/logging/LoggersEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.logging;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.logging.LoggersEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LoggersEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass LoggersEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LoggersEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(LoggingConfiguration.class);\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=loggers\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(LoggersEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.loggers.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LoggersEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(LoggersEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWithNoneLoggingSystemShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withSystemProperties(\"org.springframework.boot.logging.LoggingSystem=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LoggersEndpoint.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LoggingConfiguration {\n\n\t\t@Bean\n\t\tLoggingSystem loggingSystem() {\n\t\t\treturn mock(LoggingSystem.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/management/HeapDumpWebEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.management;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.management.HeapDumpWebEndpoint;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HeapDumpWebEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass HeapDumpWebEndpointAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withPropertyValues(\"management.endpoints.web.exposure.include:*\")\n\t\t.withUserConfiguration(HeapDumpWebEndpointAutoConfiguration.class);\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.heapdump.access:UNRESTRICTED\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HeapDumpWebEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HeapDumpWebEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/management/ThreadDumpEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.management;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.management.ThreadDumpEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ThreadDumpEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass ThreadDumpEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ThreadDumpEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=threaddump\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ThreadDumpEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ThreadDumpEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.withPropertyValues(\"management.endpoint.threaddump.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ThreadDumpEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/sbom/SbomEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.sbom;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.sbom.SbomEndpoint;\nimport org.springframework.boot.actuate.sbom.SbomEndpointWebExtension;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SbomEndpointAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass SbomEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SbomEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runWhenWebExposedShouldHaveEndpointBeanAndWebExtension() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=sbom\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SbomEndpoint.class)\n\t\t\t\t.hasSingleBean(SbomEndpointWebExtension.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(SbomEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.sbom.enabled:false\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SbomEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenOnlyExposedOverJmxShouldHaveEndpointBeanWithoutWebExtension() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info\", \"spring.jmx.enabled=true\",\n\t\t\t\t\t\"management.endpoints.jmx.exposure.include=sbom\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SbomEndpoint.class)\n\t\t\t\t.doesNotHaveBean(SbomEndpointWebExtension.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.scheduling;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.scheduling.ScheduledTasksEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ScheduledTasksEndpointAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ScheduledTasksEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ScheduledTasksEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid endpointIsAutoConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=scheduledtasks\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ScheduledTasksEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointNotAutoConfiguredWhenNotExposed() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ScheduledTasksEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.scheduledtasks.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ScheduledTasksEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointBacksOffWhenUserProvidedEndpointIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomEndpointConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ScheduledTasksEndpoint.class)\n\t\t\t\t.hasBean(\"customEndpoint\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomEndpointConfiguration {\n\n\t\t@Bean\n\t\tCustomEndpoint customEndpoint() {\n\t\t\treturn new CustomEndpoint();\n\t\t}\n\n\t}\n\n\tprivate static final class CustomEndpoint extends ScheduledTasksEndpoint {\n\n\t\tprivate CustomEndpoint() {\n\t\t\tsuper(Collections.emptyList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/startup/StartupEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.startup;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.startup.StartupEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StartupEndpointAutoConfiguration}\n *\n * @author Brian Clozel\n */\nclass StartupEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(StartupEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldNotHaveStartupEndpoint() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(StartupEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenMissingAppStartupShouldNotHaveStartupEndpoint() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=startup\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(StartupEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runShouldHaveStartupEndpoint() {\n\t\tnew ApplicationContextRunner(() -> {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tcontext.setApplicationStartup(new BufferingApplicationStartup(1));\n\t\t\treturn context;\n\t\t}).withConfiguration(AutoConfigurations.of(StartupEndpointAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=startup\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StartupEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/ManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\nimport org.springframework.core.annotation.AnnotationAttributes;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ManagementContextConfiguration @ManagementContextConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ManagementContextConfigurationTests {\n\n\t@Test\n\tvoid proxyBeanMethodsIsEnabledByDefault() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils\n\t\t\t.getMergedAnnotationAttributes(DefaultManagementContextConfiguration.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", true);\n\t}\n\n\t@Test\n\tvoid proxyBeanMethodsCanBeDisabled() {\n\t\tAnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(\n\t\t\t\tNoBeanMethodProxyingManagementContextConfiguration.class, Configuration.class);\n\t\tassertThat(attributes).containsEntry(\"proxyBeanMethods\", false);\n\t}\n\n\t@ManagementContextConfiguration\n\tstatic class DefaultManagementContextConfiguration {\n\n\t}\n\n\t@ManagementContextConfiguration(proxyBeanMethods = false)\n\tstatic class NoBeanMethodProxyingManagementContextConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/exchanges/HttpExchangesEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.exchanges;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangesEndpoint;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpExchangesEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass HttpExchangesEndpointAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpExchangesEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runWhenRepositoryBeanAvailableShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withUserConfiguration(HttpExchangeRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=httpexchanges\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HttpExchangesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withUserConfiguration(HttpExchangeRepositoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withUserConfiguration(HttpExchangeRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=httpexchanges\")\n\t\t\t.withPropertyValues(\"management.endpoint.httpexchanges.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointBacksOffWhenRepositoryIsNotAvailable() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=httpexchanges\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesEndpoint.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpExchangeRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryHttpExchangeRepository customHttpExchangeRepository() {\n\t\t\treturn new InMemoryHttpExchangeRepository();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/mappings/MappingsEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.mappings;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MappingsEndpointAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass MappingsEndpointAutoConfigurationTests {\n\n\t@Test\n\tvoid whenEndpointIsUnavailableThenEndpointIsNotCreated() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(MappingsEndpointAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MappingsEndpoint.class));\n\t}\n\n\t@Test\n\tvoid whenEndpointIsAvailableThenEndpointIsCreated() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(MappingsEndpointAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=mappings\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MappingsEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ChildManagementContextInitializerAotTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.util.function.Consumer;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.MockServletWebServer;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.willAnswer;\n\n/**\n * AOT tests for {@link ChildManagementContextInitializer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ChildManagementContextInitializerAotTests {\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\t@SuppressWarnings(\"unchecked\")\n\tvoid aotContributedInitializerStartsManagementContext(CapturedOutput output) {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tcontext.register(ManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tEndpointAutoConfiguration.class);\n\t\tcontext.register(WebServerConfiguration.class, TestServletManagementContextConfiguration.class);\n\t\tcontext.setEnvironment(\n\t\t\t\tnew MockEnvironment().withProperty(\"server.port\", \"0\").withProperty(\"management.server.port\", \"0\"));\n\t\tTestGenerationContext generationContext = new TestGenerationContext(TestTarget.class);\n\t\tClassName className = new ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\tgenerationContext.writeGeneratedContent();\n\t\tTestCompiler compiler = TestCompiler.forSystem();\n\t\tcompiler.with(generationContext).compile((compiled) -> {\n\t\t\tServletWebServerApplicationContext freshApplicationContext = new ServletWebServerApplicationContext();\n\t\t\tTestPropertyValues.of(\"server.port=0\", \"management.server.port=0\").applyTo(freshApplicationContext);\n\t\t\tApplicationContextInitializer<GenericApplicationContext> initializer = compiled\n\t\t\t\t.getInstance(ApplicationContextInitializer.class, className.toString());\n\t\t\tinitializer.initialize(freshApplicationContext);\n\t\t\tassertThat(output).satisfies(numberOfOccurrences(\"WebServer started\", 0));\n\t\t\tTestPropertyValues.of(AotDetector.AOT_ENABLED + \"=true\")\n\t\t\t\t.applyToSystemProperties(freshApplicationContext::refresh);\n\t\t\tassertThat(output).satisfies(numberOfOccurrences(\"WebServer started\", 2));\n\t\t});\n\t}\n\n\tprivate <T extends CharSequence> Consumer<T> numberOfOccurrences(String substring, int expectedCount) {\n\t\treturn (charSequence) -> {\n\t\t\tint count = StringUtils.countOccurrencesOf(charSequence.toString(), substring);\n\t\t\tassertThat(count).isEqualTo(expectedCount);\n\t\t};\n\t}\n\n\tstatic class TestTarget {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestServletManagementContextConfiguration {\n\n\t\t@Bean\n\t\tManagementContextFactory managementContextFactory() {\n\t\t\treturn new ManagementContextFactory(WebApplicationType.SERVLET, LogOnStartServletWebServerFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerConfiguration {\n\n\t\t@Bean\n\t\tLogOnStartServletWebServerFactory servletWebServerFactory() {\n\t\t\treturn new LogOnStartServletWebServerFactory();\n\t\t}\n\n\t}\n\n\tstatic class LogOnStartServletWebServerFactory extends MockServletWebServerFactory {\n\n\t\tprivate static final Log log = LogFactory.getLog(LogOnStartServletWebServerFactory.class);\n\n\t\t@Override\n\t\tpublic MockServletWebServer getWebServer(ServletContextInitializer... initializers) {\n\t\t\tWebServer webServer = super.getWebServer(initializers);\n\t\t\twillAnswer((invocation) -> {\n\t\t\t\tlog.info(\"WebServer started\");\n\t\t\t\treturn null;\n\t\t\t}).given(webServer).start();\n\t\t\treturn (MockServletWebServer) webServer;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementContextConfigurationImportSelectorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotationMetadata;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ManagementContextConfigurationImportSelector}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ManagementContextConfigurationImportSelectorTests {\n\n\t@Test\n\tvoid selectImportsShouldOrderResult() {\n\t\tString[] imports = new TestManagementContextConfigurationsImportSelector(C.class, A.class, D.class, B.class)\n\t\t\t.selectImports(AnnotationMetadata.introspect(EnableChildContext.class));\n\t\tassertThat(imports).containsExactly(A.class.getName(), B.class.getName(), C.class.getName(), D.class.getName());\n\t}\n\n\t@Test\n\tvoid selectImportsFiltersChildOnlyConfigurationWhenUsingSameContext() {\n\t\tString[] imports = new TestManagementContextConfigurationsImportSelector(ChildOnly.class, SameOnly.class,\n\t\t\t\tA.class)\n\t\t\t.selectImports(AnnotationMetadata.introspect(EnableSameContext.class));\n\t\tassertThat(imports).containsExactlyInAnyOrder(SameOnly.class.getName(), A.class.getName());\n\t}\n\n\t@Test\n\tvoid selectImportsFiltersSameOnlyConfigurationWhenUsingChildContext() {\n\t\tString[] imports = new TestManagementContextConfigurationsImportSelector(ChildOnly.class, SameOnly.class,\n\t\t\t\tA.class)\n\t\t\t.selectImports(AnnotationMetadata.introspect(EnableChildContext.class));\n\t\tassertThat(imports).containsExactlyInAnyOrder(ChildOnly.class.getName(), A.class.getName());\n\t}\n\n\t@Test\n\tvoid selectImportsLoadsFromResources() {\n\t\tString[] imports = new ManagementContextConfigurationImportSelector()\n\t\t\t.selectImports(AnnotationMetadata.introspect(EnableChildContext.class));\n\t\tSet<String> expected = new HashSet<>();\n\t\tImportCandidates\n\t\t\t.load(ManagementContextConfiguration.class,\n\t\t\t\t\tManagementContextConfigurationImportSelectorTests.class.getClassLoader())\n\t\t\t.forEach(expected::add);\n\t\t// Remove JerseySameManagementContextConfiguration, as it specifies\n\t\t// ManagementContextType.SAME and we asked for ManagementContextType.CHILD\n\t\texpected.remove(\n\t\t\t\t\"org.springframework.boot.jersey.actuate.autoconfigure.web.JerseySameManagementContextConfiguration\");\n\t\tassertThat(imports).containsExactlyInAnyOrderElementsOf(expected);\n\t}\n\n\tprivate static final class TestManagementContextConfigurationsImportSelector\n\t\t\textends ManagementContextConfigurationImportSelector {\n\n\t\tprivate final List<String> factoryNames;\n\n\t\tprivate TestManagementContextConfigurationsImportSelector(Class<?>... classes) {\n\t\t\tthis.factoryNames = Stream.of(classes).map(Class::getName).toList();\n\t\t}\n\n\t\t@Override\n\t\tprotected List<String> loadFactoryNames() {\n\t\t\treturn this.factoryNames;\n\t\t}\n\n\t}\n\n\t@Order(1)\n\tstatic class A {\n\n\t}\n\n\t@Order(2)\n\tstatic class B {\n\n\t}\n\n\t@Order(3)\n\tstatic class C {\n\n\t}\n\n\tstatic class D {\n\n\t}\n\n\t@ManagementContextConfiguration(ManagementContextType.CHILD)\n\tstatic class ChildOnly {\n\n\t}\n\n\t@ManagementContextConfiguration(ManagementContextType.SAME)\n\tstatic class SameOnly {\n\n\t}\n\n\t@EnableManagementContext(ManagementContextType.CHILD)\n\tstatic class EnableChildContext {\n\n\t}\n\n\t@EnableManagementContext(ManagementContextType.SAME)\n\tstatic class EnableSameContext {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/server/ManagementServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.web.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ManagementServerProperties}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass ManagementServerPropertiesTests {\n\n\t@Test\n\tvoid defaultPortIsNull() {\n\t\tManagementServerProperties properties = new ManagementServerProperties();\n\t\tassertThat(properties.getPort()).isNull();\n\t}\n\n\t@Test\n\tvoid definedPort() {\n\t\tManagementServerProperties properties = new ManagementServerProperties();\n\t\tproperties.setPort(123);\n\t\tassertThat(properties.getPort()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid defaultBasePathIsEmptyString() {\n\t\tManagementServerProperties properties = new ManagementServerProperties();\n\t\tassertThat(properties.getBasePath()).isEmpty();\n\t}\n\n\t@Test\n\tvoid definedBasePath() {\n\t\tManagementServerProperties properties = new ManagementServerProperties();\n\t\tproperties.setBasePath(\"/foo\");\n\t\tassertThat(properties.getBasePath()).isEqualTo(\"/foo\");\n\t}\n\n\t@Test\n\tvoid trailingSlashOfBasePathIsRemoved() {\n\t\tManagementServerProperties properties = new ManagementServerProperties();\n\t\tproperties.setBasePath(\"/foo/\");\n\t\tassertThat(properties.getBasePath()).isEqualTo(\"/foo\");\n\t}\n\n\t@Test\n\tvoid slashOfBasePathIsDefaultValue() {\n\t\tManagementServerProperties properties = new ManagementServerProperties();\n\t\tproperties.setBasePath(\"/\");\n\t\tassertThat(properties.getBasePath()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/resources/org/springframework/boot/actuate/autoconfigure/env/application.properties",
    "content": "com.example.cache.max-size: 1000\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/test/resources/org/springframework/boot/actuate/autoconfigure/sbom/cyclonedx.json",
    "content": "{\n  \"bomFormat\" : \"CycloneDX\",\n  \"specVersion\" : \"1.5\",\n  \"serialNumber\" : \"urn:uuid:13862013-3360-43e5-8055-3645aa43c548\",\n  \"version\" : 1,\n  \"metadata\" : {\n    \"timestamp\" : \"2024-01-12T11:10:49Z\",\n    \"tools\" : [\n      {\n        \"vendor\" : \"CycloneDX\",\n        \"name\" : \"cyclonedx-gradle-plugin\",\n        \"version\" : \"1.8.1\"\n      }\n    ],\n    \"component\" : {\n      \"group\" : \"org.example\",\n      \"name\" : \"cyclonedx\",\n      \"version\" : \"0.0.1-SNAPSHOT\",\n      \"purl\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\"\n    }\n  },\n  \"components\" : [\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-aop\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring AOP\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c9b8757051ed6c1cc9fda0e379283348\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a247bd81df8fa9c6a002b95969692bfd146a70b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e47b66833ebec281374d55b4e36352b80fe3fa64c94252481a8a7e8d31d9d601\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1cb69feb2931bd4af48b2329614f8e2a0d1afe77267af5f5ea9717ab24c83fd524c8bc7aa8d357a6ccbc497535c4fd282ddfb6d78364a349895a14825af8b9c\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"09c3c2711a054993922d28b76357c376649a942bf0d7410915e540339c3fa42d5a498211b02e0b09493e68fac7a0d833\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b30a6ea50e454373bd74779d983fc941bb1775368ea67ff0464edbdf0dd3d1c137760bee64a620bd51daf5b65281f15e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"291404410acd2cfbcc804bd91a9777276f622fb3b82788298254c0bf1856b49f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8101ef2cc88af43b2bfc6126547de4e4a4cc29bf49bffd83aa9d299cab9e9cdb6a5246d46c00119dd88ca02dbf7959c3076dbd32d23e8e1366144ccbbda13316\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jdk8\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support JDK 8 data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3b6579ff944e128c4eccb34e76ff67e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"80158cb020c7bd4e4ba94d8d752a65729dc943b2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"29995d3677f72dde74bf32bbf268b96beb952492b742d93f4c70af6c44b2156e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1b13d4f0a955af18a2c68ca45deca79c38d7f9f065d7053bddf2a3dc2fafe729b3355676f7442012451e363aa0da0cd8a0b7a44ded7057cf513df98a475cbbf6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a29961097a15d3aeabc1ab870699dce827511df9902fc66fe9f836d294c8cea68617498d52fe7dbe920bb5c745f2789\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"55570097f9979197eafda91156db909f25dd1b37387656893564060a673dcbc6d85c1f5dc6fd5c8b379b48a4974e6757\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"362c3a494e16016f7adc3f512ebe8c8f8da4dbdfc1ca285d05ac085a9198258f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1aebbe19a11236b7dbf85fd4c457e1a9b5a60fad9c818cc9fd462d7eb489dd5d3a378b4c7c42c6e3777e0b70263968c964cf1aaf8247fc97ec445481af2418a8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apiguardian\",\n      \"name\" : \"apiguardian-api\",\n      \"version\" : \"1.1.2\",\n      \"description\" : \"@API Guardian\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8c7de3f82037fa4a2e8be2a2f13092af\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a231e0d844d2721b0fa1b238006d15c6ded6842a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b509448ac506d607319f182537f0b35d71007582ec741832a1f111e5b5b70b38\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d7ccd0e7019f1a997de39d66dc0ad4efe150428fdd7f4c743c93884f1602a3e90135ad34baea96d5b6d925ad6c0c8487c8e78304f0a089a12383d4a62e2c9a61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ae11cfedcee7da43a506a67946ddc8a7a2622284a924ba78f74541e9a22db6868a15f5d84edb91a541e38afded734ea\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c146116b3dfd969200b2ce52d96b92dd02d6f5a45a86e7e85edf35600ddbc2f3c6e8a1ad7e2db4dcd2c398c09fad0927\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b4b436d7f615fc0b820204e69f83c517d1c1ccc5f6b99e459209ede4482268de\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7b95b7ac68a6891b8901b5507acd2c24a0c1e20effa63cd513764f513eab4eb55f8de5178edbe0a400c11f3a18d3f56243569d6d663100f06dd98288504c09c5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/apiguardian-team/apiguardian\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.annotation\",\n      \"name\" : \"jakarta.annotation-api\",\n      \"version\" : \"2.1.1\",\n      \"description\" : \"Jakarta Annotations API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5dac2f68e8288d0add4dc92cb161711d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"48b9bda22b091b1f48b13af03fe36db3be6e1ae3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5f65fdaf424eee2b55e1d882ba9bb376be93fb09b37b808be6e22e8851c909fe\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eabe8b855b735663684052ec4cc357cc737936fa57cebf144eb09f70b3b6c600db7fa6f1c93a4f36c5994b1b37dad2dfcec87a41448872e69552accfd7f52af6\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"798597a6b80b423844d70609c54b00d725a357031888da7e5c3efd3914d1770be69aa7135de13ddb89a4420a5550e35b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9629b8ca82f61674f5573723bbb3c137060e1442062eb52fa9c90fc8f57ea7d836eb2fb765d160ec8bf300bcb6b820be\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f71ffc2a2c2bd1a00dfc00c4be67dbe5f374078bd50d5b24c0b29fbcc6634ecb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa4e29025a55878db6edb0d984bd3a0633f3af03fa69e1d26c97c87c6d29339714003c96e29ff0a977132ce9c2729d0e27e36e9e245a7488266138239bdba15e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"GPL-2.0-with-classpath-exception\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://dev.eclipse.org/mhonarc/lists/ca-dev\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/eclipse-ee4j/common-annotations-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-annotations\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core annotations used for value types, used by Jackson data binding package.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f478f693731e4a2f0f0d3c7bba119b32\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"79baf4e605eb3bbb60b1c475d44a7aecceea1d60\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"aae865c3d88256d61b11523cb1e88bd48d5b9ad5855fa1fc859504fd2204708a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c496afd736fa8acbf8126887e2ff375f162212f451326451fbb4b9194231d814e25bccacbaead9db98beec454f6b8d9ed706c5c88e2145bf7e1a37e13fd81af0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"13b4d153cc113a69008147974d8887f868f2f3f0a551ef0bacaccf0add17a3168465a94a471e075913f9c6649980a3cb\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"dcf8ed73f748eb32e1ab25eba3c294344cc0ddb2cc7bb4376814f1866df42c3093f1336291ce9ed9e1c8730663e0017c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"59f42bc85ee3a8a5b422085b0462aed2a770cf52d7a3660f2cd6dd257ec6e694\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1d1a6fd0e6851d419e79f82170f4060981c233ec8dc61656b84ce7988e9b71bbeecd7364cdadac066ddaf0b3de4dc8aa5acc411ebd1641f549a3af5ba214667b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-annotations\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-jcl\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Commons Logging Bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1638acc7030a001c37f803185dbd6eaf\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"285eb725861c9eacf2a3e4965d4e897932e335ea\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"eb9ebadb1581f0fe598216f7cf032a3b44a84c96de06ffa8d6f41bcc47305134\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2e80d7485b7ad4de6cc372d86ed73db9808be6a5a33e3c9fabccc7915fe57b73011bed75b4567c44456fedad5ae2186658a7f5cc331b4aad64e2a7cc78acdcfa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a6a6422a6c2654eff951af0d6dfb6e93501bdcb4e38ec353d515ca8de919a34b9e1fe37c562106f3f33f844cf071e010\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71098eb263af3ab42d93b8e7a96ceb90fb2069f2ecca85754e702b82f9876255abf5e3f9b48beb4a200f2d9e13599794\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"7f49ddd5db9841bb2d7ca8cb5ce52fa1e8982c7c37bc0c6e987eca8f5fc70d38\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4a417d058ecd3619a9716c5d47ecc506f4cb9c3684ee589c443c7b7996b630949932295186135cb3ce5fb0154c29436de4b6c1dbf7f135563449050973510200\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-webmvc\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web MVC\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0fcf00ac160e0d42ad9cd242c796e47a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"906ee995372076e22ef9666d8628845c75bf5c42\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de42748c3c94c06131c3fe97d81f5c685e4492b9e986baa88af768bb12ea7738\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8e7ad7afa2a605d8dbb6cb36c11caf0e626a5ca5849c06f0b35524e5ad6a13eec1ddff8625e1cc278b3082555a940ec3865657828458ab8d60d1c99d513aba0f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"5ec328ff12f857baf85ce6f44c849f8818658aaabb4e4d0940ea6b5ad2b009ce3c7717b6b02843f641f8125d0cec4291\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"75605b286d839df688bbfb9594dbb83d1eb22f2cae52a6f4b35d485e91ab94a55e94158086684ef3b059f1346af6dc85\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2e67bcc31eede462f5105a09dbf5b40a3e0ccc52d637c6e2720b43412da01525\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d7c5330069c3c0f5eda1417a52384a4b5adc4451c405315a992ed147f26466a19487ffc5e39b90a1ec4cb0df3f804a4d26203f9aaf4e74cf906d1e811abfbf3b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-websocket\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cfc1778713fba9b5bc33d3db64071dff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ee2f34b51144b75878c9b42768e17de8fbdc74b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"00b16e507bea58c6e8a7cb64f129cd2ffd62da092a67a693a8a6af1efdc7dd6d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"72da073d4ec4f7473c9a91b4d11607d02a3d18ca8af10348f9130a280f898814625a5865cb44244e6be6d6ab915099805bf06a60f80fd9b8ff2c47840d5266e9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f4c1d108ca60a7a658839b8ac45eba94354ad20e641d36d2ecf777bac252d371df1e8806a5460ccaf9da222f72a4a9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2d0703de58338d38fbae7f4a38390a766d66e3875e3a6a7f2620ae478c838c8f306a39cdac8652890e1116a3859e56e1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e594abbc4cb6dc0896c08a89cb3fa376980587d5995bace2b3c0798d99c1e454\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3a35964398627fc8bcd323dd9fb6d4e51ea183b704074320822906c074aeb50a0f8732e42b98bdad9c5f0aa4eb421da96dde7e97f094ccdbcb70f668c6d4ff6e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"Byte Buddy is a Java library for creating Java classes at run time. This artifact is a build of Byte Buddy with all ASM dependencies repackaged into its own name space.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4e5bd83559bf8533b51f92dcd911d16c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8117daf4a612122eb4f517f66adff778cb8b4737\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"30e6e0446437a67db37e2b7f7d33f50787ddfd970359319dfd05469daa2dcbce\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"583512f3c47513cf17735aad4e600be44c97e9978c9f6a45227de8a160a879960b1fe01672751e7583176935e0db5477aba581bf68ef5c94f52436a0683a306e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"efcce5a139f498de410e182a52e5b2465823a2ebf845001c9a733d87418118342c3854d00a0fae7945ae8dcb1916ba90\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cace3217b1c2c77a4bc194ecc602a28886d9e448efa26b1985e9fd09d90c92bc2e1b50ed70475106ddf266f8c2d14160\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"71647273afb1561b70d2cfa519f707a98711f9ae5b891249ae5803c00c25a788\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4aba6f5dcac177c8f8aed902307c62916c32be61841adcf12b9c9885de2de9795a965c0b939729ed67ee7d49b0fbfaf0dfd922be1bf1cdbfbe7b1f09e083831b\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d6f93aa42df4cb27a58835750597d835\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bfc34c523b3ab295fb01f46373e903f9729cdd43\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"86c51c743babfc591be09af7fedcd778410706e567e9ed27218448ccd2297ef4\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"701b6ee27c87081e4a65ba76fe721f74e917a655575b19b9205b314f4a561889564e09ceadaa880aaf30f70cd8b48dc70fc5e32f511204b1ea031a12349fd9be\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"74d4cf202399e946789a5572007aa4fbf1daf26cfac27f83a3d8550711f99700083029b1f900037b8f263543ac9824a1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ac0b64ec94b558b4f806c09f68247eff80bcc8e33b97f5d09f5517a2339187e4b11c8e2287400a173cb128e3fdb4ab06\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5ca85cd0c052076d625c262cf445e4e8fb255b13323ba4ab08cbfcf32ec236b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"04ce88c724852938057c723a7ec637af2f8e601879a592a6fe135eaa26940f8fd9d9ac8f6917e761cb0ff31547bb849ff88a66e1f6e93c1032a4009fe1fdef1d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-json\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for reading and writing json\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"bea54cf408b022894c0b1b013c58c0a9\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ecda50de20ab6d3c49ea30df4c1982048f5d31ac\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"572f1a4171dff33b5a9260bbd704473442adf24f890386abe33ecc18c047836a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c611e0d07093d99dbcded7a00e7c00355a7c13c24a69d33105ca88ec63cc68ba76339b5a96b84f2b666bb883849980776e1e24ee2df9c7dd07b2dde0992289b5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed40ffb527cf8442dbe3eb7b542970317e4827ed00196387d78f123490a77b08b3bc2fd5f53b83f6bee1d4eed29215bf\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"26d5852f479f1c72f501569a8ea0c0e4c93f9049676921dca94b467e68f221214e4485c41647e6a92005e5090a6a7c80\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"dc69eefb2f1441bbec58c219ccedd895b863b1e1d25cc3805936f0c9b072f2e6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bf6fce60937e78550fb3d411c19aad2200d8129138fade809e9d0abc307c7f06b54732f1e94fa86ebb82d4da0293f7bce43345416b3fdae1b3c2edbac6706310\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.datatype\",\n      \"name\" : \"jackson-datatype-jsr310\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module to support JSR-310 (Java 8 Date & Time API) data types.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"acd8ae6da000eb831a69b4acdc182b7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4a20a0e104931bfa72f24ef358c2eb63f1ef2aaf\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bea1d78009ebc4e5d54918a3f7aec5da9fbd09f662c191a217ffcf37e8527c5e\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1c5bde6c91a2a89f3c1f231f4e17c435063d9012babbfcba509a3b25363b1fd99f0dcd4234f1e00559e43d3dc8e6c71834282c72f2ebf15484ae900754c5d757\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cc72f54d89bc0f7ffae9af36dfba38e5a61ac83db2f0d8de3c74e405a0bfd77b6d463217ece19c64eeb16291d80a69f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"096944bac7583e5c97e8afcfbc928ca4a87a7d3e5eb74cc77394a19ca8bc6f26185da7fdf5d6bd2179582bf51940edc5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"0301cf719fd327643b3228b91c36688aaea3fccf3487c3e09bae3de636340dc7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b9a4a8c9785e8ec2786690bfede18c76e08d81fc9c77bb2dad88e1a034f97f7d20020531ac1cb9b0b6e61645b08ea441aba35fc0732edc2fc1dc4b36d6f1695c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.hdrhistogram\",\n      \"name\" : \"HdrHistogram\",\n      \"version\" : \"2.1.12\",\n      \"description\" : \"HdrHistogram supports the recording and analyzing sampled data value counts across a configurable integer value range with configurable value precision within the range. Value precision is expressed as the number of significant digits in the value recording, and provides control over value quantization behavior across the value range and the subsequent value resolution at any given level.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4b1acf3448b750cb485da7e37384fcd8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6eb7552156e0d517ae80cc2247be1427c8d90452\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9b47fbae444feaac4b7e04f0ea294569e4bc282bc69d8c2ce2ac3f23577281e2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b03b7270eb7962c88324858f94313adb3a53876f1e11568a78a5b7e00a9419e4d7ab8774747427bff6974b971b6dfc47a127fca11cb30eaf7d83b716e09b1a0d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"06977d680dafd803d32441994474e598384a584411a67c95ab4a64698c9e4cbd613e0119b54685cea275b507a0a6f362\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b5ccb4d39bf7cc8ccc33f0f8fcbab0a63c99a94feda840b5d80fc3ae061127f1475cfb869b060933783a1f2eafb103a1\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ef2113f27862af1d24d90c2028fc566902720248468d3c0f2f1807cc86918882\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4fca2f75bdfd3f2ac40dc227ae2ef0272142802b1546d4f5edf9155eaeed84eff07b0c3a978291a1df096ec94724b0defb045365e6a51acfdd5da68d72c5a8eb\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"id\" : \"BSD-2-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-2-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/HdrHistogram/HdrHistogram/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/HdrHistogram/HdrHistogram.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-commons\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing common code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2518ae277e56aea5e37e3fc2f578dfa4\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abcc6b294e60582afdfae6c559c94ad1d412ce2d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"295785b04cd4de7711bb16730da5e9829bac55a8879d52120625dac6c89904ed\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"25d65699a25fe3b90de17a0539233fdad37df864f6d493475976e9a513bd7767520a882cbf6bbd98714a1fe94acdb77a160cd68f549475d2b93624ffe8672a00\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8523ae45ce6dd4a068cce108cd31da24629839d3d293fca92353cf45db9eae88107744c9e66b82ed14abb96782c562da\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9af1fc3aad2d0131c337b843c38b05510d31e7931a48841a4bdb618257f185286ed393f8a4418ae4c5f91da7f9c76cbf\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d5dbeadc5f629430202c81a6736dff2efbfbf3ea2c09844b1194f316772a93f7\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c7b1dd1727000936bf51c02f9bf9b262a412e2b815531df4a9f7aad675ef0f728d4492327a404b37b1ef36d41a240b83dbfeea3367b3b4faa22cdc2decc5bac9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-core\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito mock objects library core API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4df8dd230071bc192161d0e54a76f6b5\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a1c258331ab91d66863c983aff7136357e9de056\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dbad5e746654910a11a59ecb4d01e38461f3e5d16161689dc2588d5554432521\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5a2f00df2b1b2dbca06686f88806b86990f1eea6f7c25281c0e7ec7cf7904a0a9227477279b11630d80f8e88d6b6e9dbdb40ad094a4077cc6a44cd2072d12662\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3f2caa05fe4a5d5b385654ce60d0655724200fdd333652459b86848c3b895a9ad0b0daca8a014851d6b5c744cd0e9372\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"06ba4583220a4aaa47d79ccab11783d48900d8850a346e4a1efc61c057630fcf0bb9c95cec74833ab5e6ee08e55625ec\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f1f9899edf629fffaf8b4483ac04430945996393f4fdcedc38eba22a9a5c715d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"d6f479d52534b382088012e3d1a83fa267dfb046322a72e84438d21973165617d1d710bb42f1cb2d2d3d7f891969320232031be33f4abb2ea1526217e16e8c63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"3afea56b25f872cee2c929c761b0790d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0fe81034352a15731322fba326447ba70bfa3962\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3850d85c0f6074fe9286dece9b44f8bded5e194e9b816860735e0fc728173d65\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7197158ef14a580edc836ab7af10a9f5f567ba60e21267b624fc4143debd2638c7b8bd8e2e5973fdd5c5d512be73df96500fb0a4273f20a21b42161e9f7add75\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4a35eb1f124d8d7812d32f87b16a24dd56d4cb43278ce66f216f4a4af34db357e7481fc1b26de9bde7c2dd6847687721\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8369a8b49cae80b92abbfcc0218d55b9cecd86778735c66b9b0cc6fbc7251784725249392e716c314e3ec08c995557bb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"ee742160e4951e1f6145d575f6c6ebb908a46f38a8b3b81b7d61aac7c111a87f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"dcb1b214577203c9b3e2e5dcb3aaef8e46aec5f75a40a606f42e230c6e1af39c37250d58de6bf694c5a62d70fb1a6dcba436d696f71d7aa1a52b9f4dea5aa9a9\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-tomcat\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Tomcat as the embedded servlet container. Default servlet container starter used by spring-boot-starter-web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"db4df0f653e84bfd545894c4567b19ff\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d8efc48034015522958cb3fea5831b4cbcd4fcfb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bf93da73a8fb4caf9fa68e4f3b97adcc9dbb8c79220a828b3d70ecf12d410117\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d2bce5bb0271525766283e17160513de530c20e0452cecc3c9d5be3890986cc071c1423a3c11c54a36d2f83bd3a238b0fcbcc6218976a5633f0753a313418f6f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1f9ae7504b1345595377a4d35163315824dcf25f29ac9d522385e6e1672b813719655989708eb03b419e808f1f102be9\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9d890c3314b5ec30f39de30bf70471aef5f19e64d6d2f60b6fe66b3c57978bbda0a981cf92e42f18f27b72ed2ddb3574\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"43d38219fbe556c2bac8670fa0aa4f89e2ac273fda77d8bceac8d9d34d7b27c2\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"6a4e9a2ff89293c60c8a05cb79a65695dbe9823978be93f1b309d702338f87f108aabeaeafe8ff0ebf08bcd5483efbbb4a85c566e1357acd1d2fab565c910a80\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-to-slf4j\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j binding between Log4j 2 API and SLF4J.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"00b957af4a40bea6a7bf61400b6ccf63\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d77b2ba81711ed596cd797cc2b5b5bd7409d841c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"de143c565ba78b0f2c0be58f132c7aec75e6e1a10845ebda5a4f17c2a35d9990\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8a7a682dc5ae6a123c8de6002f1470ad2682795c65b47b06397d9ad9a31729e588c406013bfa989f9c2a51750c353cd7a147bc036f2d66b0f8f0b3f13798a637\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"8f3e4f1eea069f47b2c6111f1233448ea9ccc723b7c8a8bd308b7317a6ec1f47008d2952c1cb274152a38d3e21da750b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"822f93c3bba450b89a7f64b4d81aab48a7f5c2f693b53a4dcc83eba3a8300ff90c9e7727223f3491c782c80bee9dc707\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1f3f3aace32b45e9a6271c7b4ac76ddf86eb4f32e28e147a3e054dc8c836def1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"bb61c16d22aeed2d6b18972f68a6c4670fb8a07eeb79407748a7d499bc64e8ad8eb9774d372d9286227665686fe90878f2ef7e7f8595b74cd448d0f847aec02e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.xml.bind\",\n      \"name\" : \"jakarta.xml.bind-api\",\n      \"version\" : \"4.0.1\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e62084f1afb23eccde6645bf3a9eb06f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca2330866cbc624c7e5ce982e121db1125d23e15\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"287f3b6d0600082e0b60265d7de32be403ee7d7269369c9718d9424305b89d95\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dcc70e8301a7f274bbb6d6b3fe84ad8c9e5beda318699c05aeac0c42b9e1e210fc6953911be2cb1a2ef49ac5159c331608365b1b83a14a8e86f89f630830dd28\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ff377d0cfd7d8f23f45417e1e0df72de7f77780832ae78a1d2c51d77c4b2f8d270bd9ce4b73d07b70b060a9c39c56e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"773fd2d1e1a647bea7a5365490483fd56e7a49d9b731298d3202b4f93602c9a1a7add0eee868bc5a7ac961da7dda8c8e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"26214bba5cee45014859be8018dc631c14146e0a5959bb88e05d98472c88de8b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"32bdc043b7d616d73bbc26e0b36308126b15658cd032a354770760c5b5656429a4240dd3ddcea835556e813b6ae8618307ebeb96e2e46ba8ab16f6a485fa4d32\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.yaml\",\n      \"name\" : \"snakeyaml\",\n      \"version\" : \"2.2\",\n      \"description\" : \"YAML 1.1 parser and emitter for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d78aacf5f2de5b52f1a327470efd1ad7\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"3af797a25458550a16bf89acc8e4ab2b7f2bfce0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1467931448a0817696ae2805b7b8b20bfb082652bf9c4efaed528930dc49389b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"11547e75cc80bee26f532e2598bc6e4ffa802941496dc0d8ce017f1b15e01ebbb80e91ed17d1047916e32bf2fc58da532bc71a1dfe93afccc277a296d86634ba\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"dae0cb1a7ab9ccc75413f46f18ae160e12e91dfef0c17a07ea547a365e9fb422c071aa01579f2a320f15ce6ee4c29038\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"654b418f330fa02f1111a20c27395ec5c7f463907ae44f60057c94da04f81e815cf1c3959f005026381ef79030049694\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2c4deb8d79876b80b210ef72dc5de2b19607e50fbe3abf09a4324576ca0881fc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0d9be5610b2bcb6bb7562ee8bcc0d68f81d3771958ce9299c5e57e8ec952c96906d711587b7f72936328c72fb41687b4f908c4de3070b78cc1f3e257cf4b715e\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://bitbucket.org/snakeyaml/snakeyaml/src\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-commons\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-commons\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"cd430f3f7345c0888f8408ce8795c751\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2bfcd4a4e38b10c671b6916d7e543c20afe25579\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7d9855ee3f3f71f015eb1479559bf923783243c24fbfbd8b29bed8e8099b5672\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4aa83350e7a6df21feb9ba8756bb4a68986f33f8c6e384720d1daa448444016c0def1781729788e3e884664abd6703b1e3c0ec6b79893a9d5645c3a4809c0ad2\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"d264f2c8ceaff384b0f22ee77890195ed3d918b01f338e35fc2ee12f82df15e59533918509f535883b4f4befed28595e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d1fa76d6b2567e831b37ff7843df6d7d65028d4e53c570c6f580cbbf13269d2aa2afedfedfe5a3f2cf92d7de6d3c89b2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"eef0f968f2d2fc31f8b4a4ed43bafeb46977de1ac3d59477ab6e2b014f97e070\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"93340cc2c378c830c755b25006bc4f73ec77ad10661f05625b23efa0854d456da8e62bdbe7e7edf3418dda864e6e0d7a6b9d34cea23d525b8991258f3d75fc9c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-web\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Web\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"a39761bc7a706c70f6ca3ab805a97b34\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0f26b98778376cc39afb04fbb6fdd7543bef89f2\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"3f2012a24c6213f155b6bc69aa3ecafe2a373c1e92a26dbecc62ff575c3a1fb3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"f07f054feaf53c2a97b82150882281035824cf0b815f317a22ba1954afa721bc5d57cb07faa19bad99fc235373b62edd7013f7ac2cd0a3d0db91faf49f216741\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"57418cf2a9b3256201c0874e7721966b09929030c64f5e5a85007bd645294dfbf1a14d4632a5aa5fcf70af5bf733d542\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"83daa608abc0124ec237f65231d5f1dd1a5d751e459d3ea255a3d12a56e92ac83037fb72c5793f497fbecb9e389eb299\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1a17acdfa8920b1849a16e4260bb4b960f60da07732148a5281cfcba21d1e4a8\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3e5e020cb1068250eb0e58e9bc0368c44db96d59022047ecffe286a51b0896e4320d9696f2f9136b4c0aed547d8dd1af1bbc2b4b053aa994246bb43bd7397f05\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.objenesis\",\n      \"name\" : \"objenesis\",\n      \"version\" : \"3.3\",\n      \"description\" : \"A library for instantiating Java objects\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab0e0b2ab81affdd7f38bcc60fd85571\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1049c09f1de4331e8193e579448d0916d75b7631\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02dfd0b0439a5591e35b708ed2f5474eb0948f53abf74637e959b8e4ef69bfeb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fa990d15bd179f07ffbc460d580a6fd0562e45dee8bd4a9405917536b78f45c0d6f644b67f85d781c758aa56eff90aef23eedcc9bd7f5ff887a67b716083e61\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"2f6878f91a12db32c244afcee619d57c3ad6ff0297f4e41c2247e737c1ccc5fcc1ce03256b479b0f9b87900410bc4502\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"a3dd9f6908fe732900d50eb209988183ffcf511afb4e401ef95b75c51777709d2d10e1dc9ee386b7357c5c2cbcf8c00e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"fd2b66d174ed68cbfcda41d5cbd29db766c5676866d6b2324b446a87afab3a9f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ef509e8bcea73bc282287205ffc7625508080be44c16948137274f189459624891dcf109118c9feff109e1aa99becf176f8db837ac4fd586201510c3ae2ea30a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.objenesis/objenesis@3.3?type=jar\"\n    },\n    {\n      \"group\" : \"com.vaadin.external.google\",\n      \"name\" : \"android-json\",\n      \"version\" : \"0.0.20131108.vaadin1\",\n      \"description\" : \"  JSON (JavaScript Object Notation) is a lightweight data-interchange format. This is the org.json compatible Android implementation extracted from the Android SDK  \",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10612241a9cc269501a7a2b8a984b949\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fa26d351fe62a6a17f5cda1287c1c6110dec413f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c4a06a0a3ce7bdbee702c06944265c050a4c8d2fbd21c248936e2edfdab63acea30f2cf3568d3c21a559940d939985a8b10d30aff972a3e8cbeb392c0b02da3a\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"60d1044b5439cdf5eb621118cb0581365ab4f023a30998b238b87854236f03d8395d45b0262fb812335ff904cb77f25f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b80ebdbec2127279ca402ca52e50374d3ca773376258f6aa588b442822ee7362de8cca206db71b79862bde84018cf450\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6285b1ac8ec5fd339c7232affd9c08e6daf91dfa18ef8ae7855f52281d76627e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"de7ed83f73670213b4eeacfd7b3ceb7fec7d88ac877f41aeaacf43351d04b34572f2edc9a8f623af5b3fccab3dac2cc048f5c8803c1d4dcd1ff975cd6005124d\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"http://oss.sonatype.org/content/repositories/vaadin-releases/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"http://developer.android.com/sdk/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-logging\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for logging using Logback. Default logging starter\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7ac01b9dee045285c365cf6a3d8d8451\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"0df8ec78dc87885298998ca3c9bd603ee7bfe5b8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0b7e411cfc44a15fc63a36cd05a73b34c3558f1b06e4f297b1919361b8a351a7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"23baf0a59d56809db43101fbddb712b515012c64530362665cebe84c53bbd716218d3602024315f3250dea923138845c09d5c56dd9c7fb26a53d5e21a325e52e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f5ff55d346828eaec7b535bdd1d6096acc3819e81f6fa0a3d2396d523616e2e356d58115de8b8c49adf035216fa6ea83\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e5bd5c09d127a2984a55bbfc296cc515e399f35ee2ca949b10639c5ef583bee58dc9eeb60f6bec1f05904f8b91b4a26\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"99b21628e6efb820b4955e0e17bb54345a6974dc785b79abb7af8186a261159e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"91625907d0200fb80f025aa6ed098372955053bfb277db124d95ce2dd5049c20e9e7f2b97cffd6f247d9ae8da1bc26c004b688687056a87ccb3033d57a7c20f3\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Actuator\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d5ede97972b567fe75db1d2bbfc035d8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9089b9fff0c17eae54aabc466b78e010eac3a04f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"b870c0a601dc0d6d98b33a6b59d41799285848de267f7cfb466a6f167f30c4d2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9577f4ba268b688ad100d4038f6dba97139a29b82127f6a581b948f0ee08fc8159f51fa5f7deb200e5a61559fd321559d2255af75c3e28cf293e815b8b1bb8ac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"96adde3cd5a4f729a6d382566800e62e89c93d1c3b9120ffefcd9a666d755fc5d6dc3dd12577f927bcaf03b7f1b0922b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c3f71bfae2d560ec46f76e833aee6964b5ad57639cb4ded937cd6d1e39b213a4c255d9b83ba59882d22dd31a4ef7b5f5\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a251040e99b14a5d926f86bdcb1fcf505518d31cb421e6aaf32d59d8f7f2eb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3b642b5433989ba548cffebd7c155d5ada680b96996eac432895de56a27d7529c795d7263e8419854c9d118cddc0492d142d260a2e5434058134c9bc17ab8253\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-core\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-core module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"7367629d307fa3d0b82d76b9d3f1d09a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"4d3c2248219ac0effeb380ed4c5280a80bf395e8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f8c2f05f42530b1852739507c1792f0080167850ed8f396444c6913d6617a293\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d18159d4b378973e49182c4711b3d5b1f3600674ddd7bde26793247854bbd3a7233df7f74c356ecc86e4160ac6f866e0b32c109df6e1b428a10cddd4bc7f44e8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"afe21cf21e8804d069514a1f0d57c92b4caf56f8b010bd681d19fff67f237fcf0bbe1e1c9bfc4cedcfe602a3ea859b57\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"38cc28c8a578f4053412440d88b41938fa029a8ee3d350fe7474b34afa0f17889298d00f3c2cec4510d72d3342d29a77\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6c7d3be575969be97a49e90a97a8dc1bb25380b1b302073e00d2e21cb266e6a6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"8e9ce45d599bffac71e35a0d59c4dcff067f628157a75e9e28c1930f31537fb1dd058ddd9906322c1154f29436252a36bc50595578bfee9bcad4a9705c85726a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot Test\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5c793b3b61ba2637840a6c865aa2901e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"142fbe3cfe3370c57d0ed55cca0d8d96e1d6f26e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fb27aeb59ab757e60c48f9810d0ab54dc858a4c1cd9cc75b4ad07456c9c3e7c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"975428c3f753ec1375f9c0ca2c47756a22896cc510193b53f7a8501255634a2e0d2165e699055667f4127cbaa8e79c9c128aef6de0854fccd4e158dce4422939\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"c3abb4c4a9961cab0fde6119d5b86755ea0c43fdd266b51d369a8544818463ce1876df2b13b0a2478f36b1e5282a305d\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"641f9090f373f299d61bf54dd06e7ea15217c5b06424e970ddaed1f64e2a25aae74bdc10e04c9c4e934f2a3a5ab95c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"45d05dd704757c997b11f13961762e371309bec11292b32af3f244ca3b49642c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"53001dd1610347d6cf92f737067271fe3c638828a0b1e0b6aca62429e97a85018daf6ab3e10f065acd79ed7c93dc3a4c57f89eda3e2feb48ab548ca7e906b414\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-jakarta9\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module for Jakarta 9+ based instrumentations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"0e247019d91d3c357b440436e1af2fba\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2dc7257970669fa45e342b0b36902d868af2dbed\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e8c66d7aee8fbc8a9d2e15c6c53df92bd7ecbf94f1ca8562d62d9a2693aa4633\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3a481de081b216d42bd9b741b3a830c93d917c5ae8a11f670785b53b55cff601e1cdfd037b12d8b95cd8557c4493d6e04e51980860e421f444f2b4a953070969\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"cdbca1958c2502bcdad18446401f7f21ec2bc2c4055fd2fafa8fdad30cb8c8fd9aa9863de5ddd9cb852cafda487d29b0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"13f29eca056350277ee80d786945386abdd1c8b7c04dc35a94c7ac8146e7b6cafa617652fca15e79b8376341ae5576d0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"f095b2247aa3ada3c824121b4720dcceb3b65f7a2b9e880acdedc613a62d9be6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"773cd6f711b68a27d958ecb01f85d8480835014d23d3484e69e1c63bc736f50697bd6cf7d5e7776a13ae946ed10621334cb84ba8357b26d45cb6c9990826f993\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.module\",\n      \"name\" : \"jackson-module-parameter-names\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Add-on module for Jackson (http://jackson.codehaus.org) to support introspection of method/constructor parameter names, without having to add explicit property name annotation.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"495868f770056602bfe13ea781656f03\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8d251b90c5358677e7d8161e0c2488e6f84f49da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baf1a3156a23cb407e05374161a07ed8560f78a7ae249955de04a9a2fa2d0f2b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"497b08f55f601b7ff6294e0b8307e015e60ad45c7949bd80ed3f5ee19daa93fad7f0b5a93abb8082ec46480667ab8539337633213d0fd5992e4a10c710f0a7aa\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"1a50ca6c0e0b4e3ecf83e3f327670a3b36f2b847b46ab5e193e9bccc36fee3bd41c1aa937dda88c4936339eafc73fc93\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"30d05f1dd78a796ba4abb79be93dae2d7e4e5269de18d85a9d89b1c92f6ff8fe09ac1953a48a0b2b51906bbaadb56fca\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e50d137efbe3de957a64fa4b90532cbb67efc2b09ba11824362315d1f57b812\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9418c5c18e429e201d7f6a4d5f05a52a433dbe4bf72a82e3ea69010c1d4b9ec99fc651804f2f8339a53841f88416318e3ab7fb1a07391cde5ea745ebbfcf98bc\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.platform\",\n      \"name\" : \"junit-platform-engine\",\n      \"version\" : \"1.10.1\",\n      \"description\" : \"Module \\\"junit-platform-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"4d571057589cd109f3f4bedf7bbf5e7a\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"f32ae4af74fde68414b8a3d2b7cf1fb43824a83a\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"baa48e470d6dee7369a0a8820c51da89c1463279eda6e13a304d11f45922c760\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"52ea2f11ec2ef0457384335d1b09263f4efecf63d9df99c5f8396f74d972722c51f8f766370e85e030f4476e805dac72603296942593c5bbe56993454b9d8e30\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7c520e04c995a47c19c94fdcbbcba9bb117696191e6a989a82d9f960e0e315e5cf87d28022ac5cb2701c85d5f38eefde\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"79d4f2fb987d6a44174dda99b1bd827e8dfd0399495c3e994371d4f69631212768dee8b891313aac89045388a1bed9db\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"5c3fcec688368188688cb6949c1230c2822211e53f3a65b7b3abf4a38051798b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"30a0834e88bbc62287e5f49302c4a07b6da1bf4d9774faddbe7e606fb296c0dcd71c7e90ef8fff3e18dd050e5a19f7b903c91674ff4806cdb97111e4f0cfc199\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.platform/junit-platform-engine@1.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-autoconfigure\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot AutoConfigure\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"29fb14fe1d383588e87a73da4508604d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b100d2d21d45dddd740d496357ca6f3813d777d0\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"371f0f36d226a8db972c37c73f0a0896ee4d3e77c29b54dbce8a64af731a6e53\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"42bc3a99f9c9ffc9fd08447303a946fce1c81e3a869a5788c7d3b669536455eedc8009428ae4660d66b0d74ab170968b6aad905455b53342d7c521e7ec4c262f\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f47603c4009bb767f9d5cb0bf3fcba69167daab53cbfafd217450977464073e8b814c76aa545b1eccee587201fe93eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"bbd77376c9a46de290522662f327a8e6b0221a6c0105632e73b527799bec8a162d98948d0d05b32509650b4f47a6465e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9e9549dda419ad6f482e3b376c595c69ccb93cebf365c1b18a59bf226c3264db\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1473f0de013447eb40d0b6d2a30013d2a7d262ce1e0259d4a27f88e421e5538234a46704f88b27c227aab7ae2261995a73f4075a6a43124e39c7234c6d164fe2\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-engine\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-engine\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"71d86cd027062c4da0796c2493ae94fe\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6c9ff773f9aa842b91d1f2fe4658973252ce2428\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"02930dfe495f93fe70b26550ace3a28f7e1b900c84426c2e4626ce020c7282d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1fcc9406d1e0301e27538757c9649545d784e83743a8800932971881cfd78a14a264ad13c0b92fad9ae1be50963c540427a19cb2d1fee06888ef48105aad4c8b\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6657ac1bb11d7a40bbcb020add01e57edbbc521645116908d857074d9ea319eab3e7b7f2e9fa1ff8df08b5db3774f4dc\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"607313914c11274c577b0aaaae6c68aa6ecf25d8302f55d4e334aa6b58df2e543d2399785e2019a56b85aac7716c9623\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"be3560971111d3f548bef24aa6660ec2a126fd17b3bd68b7deeb1ab48735a9d1\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4ba6cb70f8fc1918dcedc874340488909c48e0f976d1834ec433f4b5c6cff55b16a996a0443a1b68a0d0ad84a37bf51386633905628728bde08b5820ee67dfaa\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-observation\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Module containing Observation related code\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b55c9caac5c8f778996937c3f6cf4101\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"fbd0e0e9b6a36effd53e0eee35b050ed1f548ae5\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48f6607b248e8b77ee9f7b3934f70124471daf947b30480c1b9c0e9d9f996c83\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"3e12e101b161715e5c30eb166578de7ae76749a2c4d22435bc57395be14d1313073d5fa76dcc883ed807d4982d343addfa24540e283cd0432f1428ff00962d98\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"791f99b503d7fa16733a74d92ebd02e72dfce4d648245f149f5363019beabe7e317e7ef0df0bcb67832dbab03943ff53\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ccb83eb15cd8004295bdb40b948cb9d3efaa4281b0d02a97b49970a2699822d7cd15b83206c236c3a41e49063caa5ded\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"773e3647329d707d79efcb92c88cbe0719b4dcd820f06983e6e283e666875acc\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"922f6c81c3a7b8e8c1296eb3359723161e91bac646d4bef954904c70a40ccfd9dc95c783715fcedc788f67ef06ea5514a918c7cc6811f2bdd39eb011a36698e7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.awaitility\",\n      \"name\" : \"awaitility\",\n      \"version\" : \"4.2.0\",\n      \"description\" : \"A Java DSL for synchronizing asynchronous operations\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8f3644827b9e3037de42068c57006260\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"2c39784846001a9cffd6c6b89c78de62c0d80fb8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2d23b79211fdd19036f6940cc783543779320aaf86f38d6e385a2ff26da41272\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4c422b4aef3dfceb040898f45cd1b2efb7bbf213ef9487334a0d0e674e494e120fef61348f8a81ce726f2f66dc426e133917de20c52b5d39d792e2dca7bc82d8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"11d15d6efb32707cae528eefb8fa4ab7820649ed528c3447660efd984518ee2906421af5ee76ea8181c904d594e8e719\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"71eff4441379fb1d13bec42264d48dd1ed4817c7a226a4ef1e5255e5afcc8e5e61aa92677ae98fdce2bf4824b4dbe4fc\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4fc8b38b34625336be520d2be1edcab4c8dd8e0667fecb2aa6aea83b9bad7f28\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"074f8629ab499c28155e505513e0a25c83ce722747d196966eac6327de604853503ca5f54b84effe8e2e3ab78d9ce285bdba82bf738ff8bff0f1009549230521\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.hamcrest\",\n      \"name\" : \"hamcrest\",\n      \"version\" : \"2.2\",\n      \"description\" : \"Core API and libraries of hamcrest matcher framework.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"10b47e837f271d0662f28780e60388e8\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"1820c0968dba3a11a1b30669bb1f01978a91dedc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"6b1141329b83224f69f074cb913dbff6921d6b8693ede8d2599acb626481255dae63de42eb123cbd5f59a261ac32faae012be64e8e90406ae9215543fbca5546\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"89bdcfdb28da13eaa09a40f5e3fd5667c3cf789cf43e237b8581d1cd814fee392ada66a79cbe77295950e996f485f887\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0d011b75ed22fe456ff683b420875636c4c05b3b837d8819f3f38fd33ec52b3ce2f854acfb7bebffc6659046af8fa204\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"92d05019d2aec2c45f0464df5bf29a2e41c1af1ee3de05ec9d8ca82e0ee4f0b0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"4c5cbbe0dcaa9878e1dc6d3caa523c795a96280cb53843577164e5af458572cde0e82310cf5b52c1ea370c434d5631f02e06980d63126843d9b16e357a5f7483\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/hamcrest/JavaHamcrest\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-api\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-api\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c6b8b04f2910f6cef6ac10846f43a92d\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"eb90c7d8bfaae8fdc97b225733fcb595ddd72843\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"60d5c398c32dc7039b99282514ad6064061d8417cf959a1f6bd2038cc907c913\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"b1fef44d4aa781bb119ab723c3c2a6f0d27efc4493a1fa26b603c7c7a8884c4d6274bccec6536f120d55f876f8d052aaf6cc003074c27cc704deb2c4bc08b6f0\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fd81f893be859a50766bfbf3bd74bd7d359c6d481b7fe3099e220402f585d3d46b6ad42a36b1d88eefbb6fd27a3cefa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5e13ba92f757499ca52d719869d318cade9bde9c948ee9c68d753a21ec273f7b56ad68ff8cb281614efeef1d4c479db0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"997c9e0cc57d61a85a8eec568d0f014d47af5bf655602a2c3518b6530b089905\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97c3e2c1faa1f77b174ef6ce7b24a2339e547f5976a4e40348653e84498e0c3bb96068447facef6df6b54d4af34b807f19b4d2bb1d31e26f97d6dae07843bf6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.skyscreamer\",\n      \"name\" : \"jsonassert\",\n      \"version\" : \"1.5.1\",\n      \"description\" : \"A library to develop RESTful but flexible APIs\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"60a7d3d352b233487d735f4b86802717\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6d842d0faf4cf6725c509a5e5347d319ee0431c3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1e9a7c443d0dd579906646d767f3701918a78cb88a93112f528305fc9095d261\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"51221bbeb30ed47840494d31128e605e29a96249f3e4b9c00985a865f8ed58b73e045772e3b0af74a35018a9dd004b5cc2182344b9154d9a50604ad1a073f2dd\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"941cec8d4ce1fab19f32b36f0afd2c7de27325659c5f85ab90948182098de4afe327b49cea57b946f18671af8037aefd\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3fb46460472c82901ec6fa5deab84eea18369e74aad920e3ee9e0fb8a859e8397a287428d0bf1c2b137368b6579c5c4b\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"24b6c0f73ee51c19d5fdae62588dff9d0bf172da7e6ad1595e275920c8de829c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"686fb7b0ee0849bc78b6eeb74a941795252cec9a62ea153e6bd1e77d51fb6ee14f64970cb52cc13f581d21b166c6f1b28b8fbc4c7ae0c3b225df385a92635f0c\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.mockito\",\n      \"name\" : \"mockito-junit-jupiter\",\n      \"version\" : \"5.7.0\",\n      \"description\" : \"Mockito JUnit 5 support\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ab44b412aa650651eedf323e945fe367\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ac2d6a3431747a7986b8f4abef465f72bf3a21ae\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"e2416a260c3a45ba77d674cfe27d49428e57efe21a7b2ddeae733ebb5c5d85bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"39cccb119c0767f4e443567873af78d882c4a1e99c553ad39d4efae2698933de602d9c0046a70a05be552793569d4b43e75c2a798fd1f7f0a8c5ab34db8b9c94\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f02eeae7fe867ff8580164b4d20d269efbad2a18ba2ffc8ba9744c603c589fb5155399361b14ab2a6549d605d26a4694\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6b95b5f5efcc97a2531c9c108e53fe5465ae0249d46988fe7fd47df7ad4d154de40a66471a996ae7abd75bd0c1f6c9b4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"30978340a8749b094a5b0f42dffbb91e72f7d7eaea6924efce13f47a44048fdf\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"80601cb4de8850a0255b7c28cb7993be667a238d961fd281c7152b7ba40eec399240a2ab9d686cd1463872652876e88ef221d699acb61a2acf041c9f187053ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"build-system\",\n          \"url\" : \"https://github.com/mockito/mockito/actions\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/mockito/mockito/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/mockito/mockito.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.logging.log4j\",\n      \"name\" : \"log4j-api\",\n      \"version\" : \"2.21.1\",\n      \"description\" : \"The Apache Log4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b5e9bf76dd128b37666ecd9a252b50ec\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"74c65e87b9ce1694a01524e192d7be989ba70486\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1db48e180881bef1deb502022006a025a248d8f6a26186789b0c7ce487c602d6\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"4cbf72fbea7009ec2fc363aae2ccfe11ea2023967d65be39335eedd1d8917b7402eeb2219efd5a1f11d03833dd1f57eecab428616b03124ef2266c6cca06ac56\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"edd8429f2f88476afbfa63314f7846d1341a4cfc58d3abe55b3cda236613feb6859f711e0ae60bd7821b74e488fb0666\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b67292ff0c7ca988a4b40b6ec14582ef579990d275a37944ac9572ecdfd4bf6e9fff2ab982b21d159a1135c21a32495f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"b2641c2db75d3c676e451a53b5f60dfaf030a84e0230747bd50d00414f8a27b3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"f1f4d9c48a9d088460e1ad3d71126b243069e522588cdc5534ac8f201ec0574287e8f1fba182f8925ee75b78726269487cc0160f7f8bd1aa21cc8e587fdb5c4a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\",\n            \"url\" : \"https://www.apache.org/licenses/LICENSE-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.assertj\",\n      \"name\" : \"assertj-core\",\n      \"version\" : \"3.24.2\",\n      \"description\" : \"Rich and fluent assertions for testing in Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"b596a91049e6ce526bc5595c1bebea2c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ebbf338e33f893139459ce5df023115971c2786f\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"df3d0b348f1fe806bdddcb10fa4ae63c6679e9888d4bc7055f09848517976aa3\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"d8e3159effc7954258f2398e26c34eab6c243675408c7b5fcd7ed04a7b7dc06006514510ad15be9e7725f724cbf6e5c534cb22cbfb7c0aed71b81d4ed5755220\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"4f06196b5329e215282476d8e3aa5065092924bccb91da4eb0aa2e8fcd2509f249369654f0c17b59c38f11b878a305e3\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3029ae58aef975843e9205f130dcdd8f8e7da5ff1bfad62b7d918ffe52b74a3c34a859af13393abe122124a9132f3feb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2db6965251a03be26f5baa83792a002444b4de34aaaefb0e6cf3cccf0a20939e\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"fa3ffb87bc40c3f881fb477d41c8565cbc1ce46ead2030442674bb86a425c722b75fce5bb3c22425b21cc3122ac46e0f28b2eaba2bcf5d5ddcb31f47d967b890\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-web\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"8a6aea9e1fbdbabbd00e35038739200f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e27e36d4222fd4d589e634e1c7f5f09f0316147c\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2f14d3a4a0ae3ad634bcfa07117542001c1789c0bdce3504baee8f2bc45ef006\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2fcfc8d9abfcd0518b6755737c6e520544600b3c26b42b60d1ab3fcfceb31582d5dbcd5d86a98ec312442d335e49f0db0ecf21d8e99089ef41d962ece42d97ae\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e3c8cb02b18ea5b7aa2a7c9c97c62385fcaa8fc53f41d7bf0b98d262a10473e9674924ad287964f6e58fb9c5915da8d1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"713c9200480f14fd4bcd073d43ac7900771c9d36b4e72b50ddf80733670948ad57700ea37336de5078d16557e426de79\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3346906c7b4b455c00226fd9804a237d3a667523800e0c2083413fde4592b7c3\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"99ba750d8e1c97636eb47122ce259b1bc9b91c51fecc50d13604f7ae7096a20f1fa38562d83786c1d4c3ba07ff94b286d869d671a5f0d00fd6c378f032332f63\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-test\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f808bed72032367a1170477e74e57f7e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e6a20062864e3a9a0bba0ac3b0c5a819453045b9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2e0a11d69fed912dd6f5a6b0f492ce1530e2ac932de9588d4b7df0ab548eea0a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"83c1f7e7b404be7b9f603a386ca2d0c84c7e0b73190ffb19ef2b0dff5cbc1ebd57ce73be663ee01ed28f1c4f41d91db7f070d7b37a3f2ae6b9b6814dd930a089\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3a5159cad10587b250f0a1f7cf6ebea9f2cbda539c008094fec1dff47eeced5b2119be3ad007eab0598445b9282164f4\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9303b808eed6e0425d5c7e968601960d9ff2e0c2fd840ffd041b01f0499b1f86ae05c50e968e925374a54b26e9298410\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"a18f18bd0a077a38ea0b3aeae85730b9f104d65d4d48f88210f2954c45739eae\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e021bfc51b8d6b8cdc1b44cf5042778c208db09b349250e33630b28ace2ed97d52bd89750ab70e14b650578f379a7e6172838c83bbb2c974394132cb80381f27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"jakarta.activation\",\n      \"name\" : \"jakarta.activation-api\",\n      \"version\" : \"2.1.2\",\n      \"description\" : \"${project.name} ${spec.version} Specification\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"1af11450fafc7ee26c633d940286bc16\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"640c0d5aff45dbff1e1a1bc09673ff3a02b1ba12\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"f53f578dd0eb4170c195a4e215c59a38abfb4123dcb95dd902fef92876499fbb\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"383283f469aba01a274591e29f1aa398fefa273bca180162d9d11c87509ffb55cb2dde51783bd6cae6f2c4347e0ac7358cf11f4c85787d5d2857354b9e29d877\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e34ac294c104cb67ac06f7fc60752e54a881c04f68271b758899739a5df5be2d2d0e707face2705b95fa5a26cedf9313\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ffd74b0335a4bfdd9a0c733c77ecdfa967d5280500c7d2f01e2be8499d39a9f0cd29c9063ae634223347bb00f4e60c33\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c97236eaebb15b8aefa034b23834eaeed848dacf119746c6d87832c47581e74d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"147dfa2bf46bb47c81462c36ac6612f9f807169ffb785e2bbd45538205c5713f33af4373f3324a2063350c2367baff37e9c2cf085c38c96870ad88c60a7fbea4\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api/issues/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/jakartaee/jaf-api\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"io.micrometer\",\n      \"name\" : \"micrometer-core\",\n      \"version\" : \"1.12.1\",\n      \"description\" : \"Core module of Micrometer containing instrumentation API and implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"30dcc7ea6a0e99663e5908bce7371206\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b72e9a2f26355ecb8ababa0148a5c3c4ac648f14\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"97d0a5309e9c584f4dec6f549a383ae25d8727abff43cff8e0b90580ee797b67\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"2acd080a1b40cb5a1ca0b7266af829392e318291dab57e6239ca97d15112cc206992b78316f4c02400454124519a084341e4de55dd729c96805b3fb196707a64\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9a3998a9a219fc049ace5731fde94944948332eccbe589dbc34456057a2df173ef17e3b0642233e513d3118bcfba565f\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"22c97b3fb49d299ebc36674a6e32d9fd05726d88109ede3323e3e97e82100d1ed6d7010e86749a2b07ffe994fb3b7833\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3b272686c89e274b5944715db002871e072f0f8c7099228f6d6909656b6ba3f4\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b1d82086950a2e61ed3e016fa962af2e9c3b2d543c4c311d40d9f7fc402b9beb3e5d09261d336cb1634b186f723bf584874f3fb8a29c38198d5ddd2b386c4413\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter-params\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter-params\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5e8e17f6f2a5dedb42d9846a3352dd31\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c8f15d4e99940c4564098af78c10809c00fdca06\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c8cf62debcbb354deefe1ffd0671eff785514907567d22a615ff8a8de4522b21\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"dbd8a3bca0a03b6eef54de2b489685c8125e0c6f23cbdb633174b21e07cc7b97a24b55dcb5b60ec1a496683a918bfdf1ea0459950689e3755aa965ea9e106ee9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"882b3106163d7c195867e08db9948a0997e1469a23c847bff523efa30a9b274c0588f8228fca98c78abf9b61709a7ff2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"6e4e9a7dbb32cc3f16f21a14fe036aa13488c5b94e3cb6cc53b417c4588b90b5ae118caa3eb9f4bc9c513d06e2c1f408\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"171a08027b527e3be1ad66082405eacf4a55746dd983c46d9ff7ee5552276615\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"c435b4a17208b67f6fa35ebe74872c3d2c3557b290437bb682ac86701402bbe17d0e53446c674bb94c7feaae4bbfa99d888c7bf7181707e27fe08ff7934c00f6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-databind\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"General data-binding functionality for Jackson: works on core streaming API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5f453c55f127690fa8491ce347aa055c\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"a734bc2c47a9453c4efa772461a3aeb273c010d9\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c3c53333a2172a80678bda1803e39cff45bec6ae3e9c7d4f44a81ec4e2ab18dc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"490ccc99a9c28238fe28455bae08196b83df034cae8a1947d27ff89e500a5d812cf4be36c61942e647c62ad540d8eb4428f49855f0cc8db0ee9e7a5b12ba2454\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"b53f4a6fddbf677a8d02c65e9f0a96372140c68286d68740987fb462f946de878abaeea421d3e4716751f04d88c16ad1\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"5a407605544e303abf8a212651bf5e5594fa313804a399bf03401f449c0baf26ef965def518b05c275b2f38f18457739\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d0880002ac261d181e663499627fcce5763f3a9120bb76e758adfb9939d17c98\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e97bfe0e9117dad82e0799cb2c105c4553c6aa5ce9abdefee4fd5b584876555309aafa9a19ca586e928e292e32f23452849a10da7364966e11e4f7afcc6aec78\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-databind\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"jul-to-slf4j\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"JUL to SLF4J bridge\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"24f86e89ee3f71ea91f644150c507740\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"09ef7c70b248185845f013f49a33ff9ca65b7975\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"69b4e5f8d3bd3f6f54367d19f2c1ee95dd5877802f12d868282e218dd76b00bf\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c1cdfbc0c867917d65ab58e039b01c5b119368aef82abcb406d91646da208a4bfad91831a5a425eacfa8253ccd5713a9d4325d45665288483929cce7a6a56eb7\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a8d45375ec27c0833a441f28055ba2c07b601fb7a9bc54945672fc2f7b957d8ada5d574ab607ef3f9a279c32c0a7b0a5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d65edaa8f6ad8bbea84617e414ede438ec4aafffa3734f2d38e6dd0a01c1f42f9397acaf6291a73489fb252d7369c71e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"69416188261a8af7cb686a6d68a809f4e7cab668f6b12d4456ce8fd9df7a1c25\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"52d54c80e3934913a184efc091978201934b0ee47a6b4f9c8555a4d549becd26957e17592aff46dfdcfcbcb2313bfad09699ee84cfd7112ed2a00422c87399e8\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Spring Boot\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"6f7384977eae04c804b1062df9217959\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"faa2ce019bee68a8d17529d0a08ebc427f927e13\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"6fde604399114e77b12519b3d117117c607cb73b89a88800856fb0e0cc82ea7a\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8619959d143ef38f5c846591b8b10b0c50906a3301a5e9ed3e3df44124bdfbe3197cd4ecfb214c3250f40a0c1b11138b7a3f6865755445879f0685d2e88a6846\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e237fdf6fdb8d21f2fc19fc15a370901c368266ae8d2b157f41b5eeed50b211a871fabc352dda10bb3aec60975d233f5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"cd6240fc102daf1efcd9fdd6532ce21297d5477e9bde3f5651cc9ec9505d526f63ea2284e484c2aee2a8e63841137839\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"3959b52aebe7405a95f82d8990b8122cf21b89967f691dad851b85191973f9cb\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"1b4ef33997158ddb97ccbcec7011cd55f0e019428d25410b01a83ca58c9420f2f8805be955cf704605145abe582522db0c8afb9698ae4efac141a3807a457ae5\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.latencyutils\",\n      \"name\" : \"LatencyUtils\",\n      \"version\" : \"2.0.3\",\n      \"description\" : \"LatencyUtils is a package that provides latency recording and reporting utilities.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2ad12e1ef7614cecfb0483fa9ac6da73\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"769c0b82cb2421c8256300e907298a9410a2a3d3\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a32a9ffa06b2f4e01c5360f8f9df7bc5d9454a5d373cd8f361347fa5a57165ec\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"bb81a42498c65389366205f4e07cee336920e2f05cc0daae213f2784b1d0ce9a908b038daec20478f23eb00b2bf704f96c5b00f63c99615193ab2a3cc4a9f890\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"16ca4640dc9d848e6c6d15441897e1b5a9f27f34207b0bb456dd54d8f267b73b348092e548e78634144de44ba3515205\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"406c2b5c6f64b0c090568e479b5e6136a04a4e77f8eea65d32b4e2b01deebcdf6a0a851240cdb740c25b5a5e61e6c179\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"50ae828358301033542fd7c412e86ee318d5451f89a182e2a679aaf18099d26d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"456c337b9fb385579aae707409ed6a04d08e5fc87b1a46733dca617c22c625bf253dc4747e0cdbf5e7d8b48102d2938cb482b6b688a79aab645a7459c592258f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"CC0-1.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/LatencyUtils/LatencyUtils/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/LatencyUtils/LatencyUtils.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-el\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"f9171a84574782d1d68acd8b07177172\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"9ad7312421535d7d3aabe0f541e852baccb59726\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"bac12b9c993a9181ffc88ea8ba085491a482729e64ae105750a7475a7b85e549\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77cf7be4536d7f1f4761fec33562134150c0ebc74d582160ff913c8be37b1502ed63e90bce81bc8617cfcd76c774903c2dca4209a972146f4c976f786456c596\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"62b14b49de8ee6efb41831ff172114af56a18379a797de732915ac356bce3e5582764253852c9831a3c3b6c1e52dea65\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"05cb21cbf8b221332d7ad588cc6aa2087c60e8ce92c5ff2bddcd16465ef2a0198f74d4595dc3313d1acc68ea945c8672\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c18e9b240138c21a23b0bf2f502d1d667084c5a50d7b3340a4a08799a3175de9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"663d02ece35a989d8da1cdbdea002974f0115ae8c727dd71f0505f299c63f04c0e83b718e4c3e65412bea1c79d872e9ca7d9431c7deb63a312d3191d419620ab\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-context\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Context\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"ca23d3013c2afc6d3b30b993f3c5cd69\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"15df19852991220556b4462a366269b8e15278eb\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"af22a435469956415bbee873de6c05995ef12f2d29622abf510a94581ea52de2\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"eca3cb14e8c0fb65d27bc21a8041aab3baea14f278fb546356fcec9874d0dcd10353fe697e94ebc35a78abb3387d5a41b67c1cbc9341eb05359c1b535147a9c9\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"374207d989f7f27ded5468f35867d0aace78927cdaf98c31b2b6345210fbbe960ae5e5143bb0308347b7ef386159fa04\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"236c1d366734b231ef4a334da4220b311dd58b1707ae854b2a50ff89b6b348913458fecdab14d196128b695de6dc9832\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1e1e87df37dbc064315d7afaa59480c830a0f445ed0df2ff5968931f96e9e86\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a600b2720ed8e5c6ecbb2a68b6a5fb5320811818e2128016b9888df705901a8d0f38dfa99b8d458724a85e769b4da2ce14d461133e085f8aab23f59e9e520c11\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.opentest4j\",\n      \"name\" : \"opentest4j\",\n      \"version\" : \"1.3.0\",\n      \"description\" : \"Open Test Alliance for the JVM\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"03c404f727531f3fd3b4c73997899327\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"152ea56b3a72f655d4fd677fc0ef2596c3dd5e6e\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"78fc698a7871bb50305e3657893c10500595f043348d875f57bc39ca4a6a51eda3967b7c8c8a7ec3e8f85f2171bca4aa98823e912e416e87e81c6ba5b70a37c3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"10398b6998c9202a0731e2e19ae1c3f9d8a83582c2663fe7bdda15794ee6fa816727dbd8f7c7164bd5395ee1cfe7c97e\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3abe706fd78509c25a402c7bbf6f9ddf71ffb5b35054864ba0fdf7902207115f888a0ba728fd71d2e87a9360d2498121\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d961907a1bfa1dcda329dca494ffbc251b31fabcaca5ab7095661a8ce3c1d654\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0ad661617bcac51bcd26f7ad4611c69b1fd9811b50dbf734e041a3243ab1f845e7796620e8a7c40c4a2df3946864598b1251396c7d9bd813203d82710788cce0\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/ota4j-team/opentest4j\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-core\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Core\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"98bedebd5de314d344ed3a7dcad01c66\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e43c71a9eaca454654621f7d272f15b53c68d583\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e3f7378e98c26500bdb5ecd6865778f57a22787eb2f11b9bd5fb8e438a0c631\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9654f2d77899116d66dbf5808815c866da0bc7a965532da059c7819bde3928e8d3692f0dc97e06f94c44e5452b785b50eb364a1cb7e46385653ba0e2c7195306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"3b63b4a26c5706ef2e379ff7bce89df983e7ae449a927905ce23ecf26e22bbcf8e91dc53cc75f4f7cd72bc09d7e7bb20\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"ca29e88f0764a6a9279fc93d5cb9284a04c6ccca6a8a5beaa404079b90674286fc6458d14b0b0a727d31e00b8009e4f9\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"861fc1147deae5a55165bd32c3fd4e18687afcc37876205c10bf1feede582ff9\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"659a0d2e5ba153be219e1ebbafb28f9b48c44a2acd78d695e7479551a1c1641b7893d7df071a3cc7436de03735b0c8024b2f758bd0286711eae64ab005f6e929\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"com.jayway.jsonpath\",\n      \"name\" : \"json-path\",\n      \"version\" : \"2.8.0\",\n      \"description\" : \"A library to query and verify JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"501b9f34e6a05c20dd74e6b40e066617\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"b4ab3b7a9e425655a0ca65487bbbd6d7ddb75160\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"9601707e95cd79fb98570a01ea8cfb857b5cde948744d6e0edf733c11002c95b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"8d1521092a2acb13a2667774b8b81debc1f2a0e937007e27e5bd28bb222910774b64d6e269f33473f765c810c03a34e715d16065dc9a4be8d8d081436282ba7e\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"aeea493be7c23574a77df50a0652776b768d52e4238efd504b8ef3b142bbe6caf0dae8955b30c2173a54f70243d36a36\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"c11c80614c007f350fa2fe758c0f4505e7ed7d25590622f133abc59ccffeb4e0b2abfd393b83e58dff4668307f28704f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"d7a7d1d7845dde343617ec009dd0d76e6bf012f182324e3b9d0f23c52bb7f67f\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"da023255dfa2271a0b6b35b7d35980c3c502f3f63b3d515714f7dea54046f527bd6cbd903fec9492aad88ad03a1b85dc2b05fca4b34ded3c3b427c4cbfab02fe\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"scm:git:git://github.com/jayway/JsonPath.git\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\"\n    },\n    {\n      \"group\" : \"org.slf4j\",\n      \"name\" : \"slf4j-api\",\n      \"version\" : \"2.0.9\",\n      \"description\" : \"The slf4j API\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"45630e54b0f0ac2b3c80462515ad8fda\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"7cf2726fdcfbc8610f9a71fb3ed639871f315340\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0818930dc8d7debb403204611691da58e49d42c50b6ffcfdce02dadb7c3c2b6c\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"069e6ddce79617e37d61758120c7e68348ee62f255781948937f7bec3058e46244026d7f6a11e90fbc15cd4288c4bb1acee4f242af521c721a9e68a05e64d526\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"fd6f7ad85d02ac63cd1a586c8bb158c1fc000495f512f097731ea9f749b5da2637615b821294962805ba312c738f40aa\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"17cd61f59a162250b52a89c7c56eb60da253b776210500313c7b82744483ff84717946f969251fb4d76f9bb12a2458fe\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"9dcb04582c64c79e788f9191195834ec75bb3457133d22a176a0ccb069b97103\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"990faffa454598a3fa82affe30f1323db769d2e1fff20d9c7163ef6fd95ac7a0874c06a634207a2eaed9e5afbdee68b225138fc75018717ba97efe3ffe92c88a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"MIT\",\n            \"url\" : \"https://opensource.org/licenses/MIT\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n    },\n    {\n      \"group\" : \"ch.qos.logback\",\n      \"name\" : \"logback-classic\",\n      \"version\" : \"1.4.14\",\n      \"description\" : \"logback-classic module\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"204b49a7fa041b2b2c455193079dc1d2\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"d98bc162275134cdf1518774da4a2a17ef6fb94d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"8e832f7263ca606ae36dabb2d8b24c2f43d82cf634e81dad9d1640fa6ee3c596\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b535f2cf5a2fdb807017cb6fe456c40dcb11491e743ff86f99df2714a1b12bb9182ac193d37c8a6dd7eb2bf4c7d24390a6d551d02a280083673516eecdabc4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"606400251082b8193a57bb20f1774ee2d6e439fab2ddb0207643fe9cee66cf61edba5e5c80d4b3bc9785a7bab910f8df\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"d9d9b1412d2fea3eeb5d110a0e7d44c9bc13459fd2b2f5cbb30b95174081f0184758abe43b5e6b6197a716c3ba7b310f\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"e1b0d59a9a91fd7878c92b3680cde8c34896823612a2f04715c05e977c09db82\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"e0a39dacbb91b7d9f00bdf78829918079f6f2e749c28f31a359064bac9ac7eb65c87e581795946814460f787e33b8829a9cf0e933a0f87dd7d48f288d45f5064\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-1.0\"\n          }\n        },\n        {\n          \"license\" : {\n            \"name\" : \"GNU Lesser General Public License\",\n            \"url\" : \"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"accessors-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"Java reflect give poor performance on getter setter an constructor calls, accessors-smart use ASM to speed up those calls.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fc814b28882dd9f2552eda21add0698f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"aca011492dfe9c26f4e0659028a4fe0970829dd8\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"12314fc6881d66a413fd66370787adba16e504fbf7e138690b0f3952e3fbd321\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"77b21fdd3401a0557d2d04a14c27563897afe9e001fc520398e22083bc18afee5e48dd9f5fc6561d0f327a30a9303bf5cc20f0a2ce741d80b3792e258276faac\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"7464bf3917d11712b235c7e1af339766d01cb4b41ec98941c3c69bc4ab9a4d0e6c832cbf01482425100dc8f1611ce3a0\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"be26dc2bfc5fdc1a45e14f1c2fcfe224994e66d39049e235ea83c714fb90bb685d3f2209c0d550528e2cd9b2d9d95a6e\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"6a914eb757ec313842f13c837eeb628e606323cc63dc24127e7a9804e2746d12\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"edbddef0538aac87bf6af714e12c4078fd6ada069b6fd0e1e5c1038b060999764e06c28b3ca38b8d540d0f60c72f7321ddc22d2537156999bad5098c89b6975a\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n    },\n    {\n      \"group\" : \"com.fasterxml.jackson.core\",\n      \"name\" : \"jackson-core\",\n      \"version\" : \"2.15.3\",\n      \"description\" : \"Core Jackson processing abstractions (aka Streaming API), implementation for JSON\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"c86c75392bf138d54d2a219bb1d0cbcd\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"60d600567c1862840397bf9ff5a92398edc5797b\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"51fab7aad51ed588482edc507fd542747936c5094d1ab76ed21ddb63b96b610d\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"112de40a31dc7d011f256f1d2fe0d9e2afc301a1f31974318f8d070c3e362b2ba96005167384244f630b915451db6694bd3cf6a9b793872351bc18f21c9de5e4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9daaf08467525e462234c53ddbf7287bcef15d8df7fbc64bcd558a91d11e8335b3a79368d194b126d3c8fb846800025b\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0b4fdc8d11fc060461e74e773fce2e64d1a98bed7db6edf51784bb1b801da4bae744a2958e81c2e24cb992fec892fb6c\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"751ad4f10a78cb36fccbbe1dfe208816f17619edd5adeabc86b7509201e03c3d\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"aa5807b7d92d150fada6a4ecdbfce998bbea825a09af8381127ba3736de029ae9923f54d770b2e5c3f5c85d9b4bcf21e6893a5a3089db2d02f1432b85dfa0fe7\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/FasterXML/jackson-core\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n    },\n    {\n      \"group\" : \"org.xmlunit\",\n      \"name\" : \"xmlunit-core\",\n      \"version\" : \"2.9.1\",\n      \"description\" : \"XMLUnit for Java\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"011288450a3905a7d97e3957b69e713e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"e5833662d9a1279a37da3ef6f62a1da29fcd68c4\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"7e70f23d4f75e05f0ee79f0f6b9e13b6cf51d34f36c5fc3a6b839429dde1efef\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"1d07dc1582a1930664ab3cffd1443e85c83fec138c663f3070a9d3b283f818157b2cdd1589595867281a96d3b444b18c22c1ee3249a75c857c6ee9682785e8a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"f54a506a08b66776d92d4379712ae9f7658cc89bd7b780eb629bd37143ff68e28cb2314539dc3c1ff13dc9cccba394f2\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"7fd679371624f72417612491bac721a49f229744df3fc7455e5fd3983bd2de452a4eaabb707be7bac328f3beeea88d99\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"c517aa9c543a4a3df361c30ba6609082a1dd5dc2abc351643ad5b733a1282773\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"3797bade2087f791697f6736296381f8b158a2a93f50faeabcd96b4c9f48ad26fd78af56cc1036c449c35e624181961d54acdd7623b84c23c81c72d5d0fa57f1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"OW2\",\n      \"group\" : \"org.ow2.asm\",\n      \"name\" : \"asm\",\n      \"version\" : \"9.3\",\n      \"description\" : \"ASM, a very small and fast Java bytecode manipulation framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"e1c3b96035117ab516ffe0de9bd696e0\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"8e6300ef51c1d801a7ed62d07cd221aca3a90640\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"1263369b59e29c943918de11d6d6152e2ec6085ce63e5710516f8c67d368e4bc\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"04362f50a2b66934c2635196bf8e6bd2adbe4435f312d1d97f4733c911e070f5693941a70f586928437043d01d58994325e63744e71886ae53a62c824927a4d4\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"304aa6673d587a68a06dd8601c6db0dc4d387f89a058b7600459522d94780e9e8d87a2778604fc41b81c43a57bf49ad6\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9744884ed03ced46ed36c68c7bb1f523678bcbb4f32ebeaa220157b8631e862d6573066dfc2092ed77dc7826ad17aef2\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2be2d22fdbafe87b7cdda0498fc4f45db8d77a720b63ec1f7ffe8351e173b77b\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"a3ff403dd3eefbb7511d2360ab1ca3d1bf33b2f9d1c5738284be9d132eb6ad869f2d97e790ed0969132af30271e544d3725c02252267fe55e0339f89f3669ce1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"BSD-3-Clause\",\n            \"url\" : \"https://opensource.org/licenses/BSD-3-Clause\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"http://www.ow2.org/\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/issues\"\n        },\n        {\n          \"type\" : \"mailing-list\",\n          \"url\" : \"https://mail.ow2.org/wws/arc/asm/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://gitlab.ow2.org/asm/asm/\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Core starter, including auto-configuration support, logging and YAML\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"d9eb815815944bcdaeed5e63f32e5d7f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"bc03d7075fb9d9d4877218db48d5dae3dd72a65d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"a25f2f4172c34f46b73fff03293370c3daf231a1db2883ef8032aa471779fb8b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"35cc80f9b10e81624324083a024c97e247e12f54762cfaadf40504903b0ebdc76d0226af1e4646bca445211b039913709ff48289dd57e27ecab18fd6e427d306\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"9acae9f3f77733a83d37641d3bd32d762225a08dcb20d61ff33a9038e8a4fe2dd39026bb08026cdb618437f68fc11382\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"1e605937a46c8371423b7876d5dae4363f718f70200a1276056bd6466d03096aa580708c7abc76618a141a542df29b24\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"331b3c120493fb5d9dd628beb8aa10382772a08d0a687103a2e87a4516fffde6\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"9f2612fbecec4664979896868e4766b1f66aaebc914e46a07a7ef7e5ff76786e5a73ae9ca5f364d23ae41f8bea2fb44e5034014950423fdc3a438ae1dc275820\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\"\n    },\n    {\n      \"group\" : \"org.apache.tomcat.embed\",\n      \"name\" : \"tomcat-embed-core\",\n      \"version\" : \"10.1.17\",\n      \"description\" : \"Core Tomcat implementation\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"81d2d784780b1fe54275ab4f3d0c3830\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"5b9185ee002f9e194d2cb21ddcf8bc5f3d4a69da\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"5d70fa6ae0548f89fb4c070423ecc2db050cebf248b0d5f3f2294375a6762382\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"9fb1726f3a10f5e0bdd1cafcdc9532536679d04e5cdde9e54bdf18819ea2651bcaac0efddd6a8b5dbf3cfb8dfcd7ab0453f2ff3fa4e21a0f3796d4dd6d630433\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"e644a094c17574fc9334772913aeabd6de0be8eacb0718981dbd97ee197a21f43ff3efe2c073f8863a4ff111f4ccb303\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"2e8d5d4b1e202e19529270adc7992e9d187ad34bdd62ab7633359f3394059cdade69c88dddd3879dea40487cb17702da\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"25826af7f0a6fd192e83cd14481055b0c5477c325e51d17355d9ff97963380a0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0b2513e578a484562ad47a8a1a4d1fe8253a9a276fac49ea9732877d976a2d1827037caa5a6401d5659c765317acb94127e62f99373a4efea63b44ab4a1824be\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n    },\n    {\n      \"group\" : \"net.bytebuddy\",\n      \"name\" : \"byte-buddy-agent\",\n      \"version\" : \"1.14.10\",\n      \"description\" : \"The Byte Buddy agent offers convenience for attaching an agent to the local or a remote VM.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"389b6aca1ee862684592f6f041f81724\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"90ed94ac044ea8953b224304c762316e91fd6b31\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"67993a89d47ca58ff868802a4448ddd150e5fe4e5a5645ded990d7b4d557a6b9\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"7f1a1310b1a0f60d6ff07dee8d9b7e404e8fb9a25a5c0c186e00cafc834e5a026a7694fb65279367dabfa1789c1f16192d0ea794b7f511f0bb3414b8d519e9a5\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"ed1e1d594a7c2837311accf3f718cbc7c6e2034afcab13c63d72313ee1ffd18a53863f1ccd194b85b7e0ffed78bafc9c\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b3baeae67826ec4e4f71b2870220c362f153d2a126b04557302b5b8e24a58b9741bef7afa9c4e4f0fa1ea9371cbcb1df\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"01ccb9e430868deef5b51124073643eaf6dd2c8c7e4d6e70b59042c9d28e3361\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"b621fa443ade355b10cc45329a5e0f700942dd39e633a8f2343ece00446cd42f5c1217b041a67b3143df86397c363f8dcad226f1e70b8755126512a74f878262\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"modified\" : false,\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-test\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring TestContext Framework\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"fadfe62dd198a4acce4416acb28e2869\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"c393079051398e02c20d8b24e02822f365123719\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"2155779c3e461df55f3b093f0e6e4bda398664e3452efe599690bc9a3f1932f0\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"5e6e4f76edbf17a321302bf6257c09ed7893e32c50fb3cace37b2271f3c488d397c67b5315ef3019ee6d28544f52cf593e0475bf00927cd67f0c668d6b3909a3\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"151df7daac9a3e3e74732405bd4feb17ad9ff3e4de196e767f39da675d4480994ed8da13e3b1b27c7b4ee9ebc17feef8\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"9069193468f2ae4c65c94d3950541efe37498a4e19245ddc67909181e83e14019f956baba54da0b9d2e8a262db13abd0\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"8ccf71564f5ee7e6a578031c7c8530a5ddf136cc1dce483818ebd30d53c851df\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"31049da217d1115b589780ffaa3ddfbf676cc58e70bd4cbc1f24c0cb2aea6b155539f8f9b3f6757f19719fed0a6102110f195b34cdd464b5e375132c25e7bb51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\"\n    },\n    {\n      \"group\" : \"org.junit.jupiter\",\n      \"name\" : \"junit-jupiter\",\n      \"version\" : \"5.10.1\",\n      \"description\" : \"Module \\\"junit-jupiter\\\" of JUnit 5.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"32fd55a03f648868767c1bebedd198df\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"6e5c7dd668d6349cb99e52ab8321e73479a309bc\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"c1a386e901fae28e493185a47c8cea988fb1a37422b353a0f8b4df2e6c5d6037\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"c97a2f9eefa6f34441fc0c97744873040bbe49d335954edab43bab25876a33f4b3f11347459420569ef660449728aa093bbae5d42c0fa733a0b624706b57a65d\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"873dfccaf8366ce5b14dc0b5498205debecd90ecba20b1f1c924721764d546b5b9629dd57c486e5a5a2bc38954bf3824\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"67f09e3174ae3fac6ddea13b56dcf078165e715cb18afd73d86bb980357e365cef6e62083231f09ae2accddfe62f5bcb\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"1c2a60003b13025c959e7728b3f4469b67bad8649d2080c0871418fb52b1c078\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"7c03cfaeabed9c57b26e083bcb0ca9a114c491216fc7e9652a39a5468579175e575ace315493610fdc7711c6557eff11933fbd28f5433c237d2277bee102c5a6\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"EPL-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/junit-team/junit5\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Chemouni Uriel\",\n      \"group\" : \"net.minidev\",\n      \"name\" : \"json-smart\",\n      \"version\" : \"2.5.0\",\n      \"description\" : \"JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"af9b7eda9c435acaf22e840991c7b10f\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"57a64f421b472849c40e77d2e7cce3a141b41e99\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"432b9e545848c4141b80717b26e367f83bf33f19250a228ce75da6e967da2bc7\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"56284bb3cee2bcc3684cdcc610115c7eacafdbd70aa852cb0209616b0503dfd448c5110b50e11a71b1c61a6e7ea27594ff63cc968230374555cc6f652d69d372\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"0fbbd6899d344c3158007f2f033165284323f1ecdfa49e17730d9d2bed8b3d77bbdc209a72a388e9e15a5bed9d9c8eef\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"0f18f178117f8c640e7e1ac2ed4c2b28e331f658f40eac2f5974e891f7130b760e4f057859a537caaa046ba9c086a24a\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"4c91eaa12f7c0ee08264ad95d016cfa41af08c963055b7f9076771da402e93e0\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"0c5fad6395cf3fd25c04fd1e2c915351da4849475b463e017b760ef97800addb170d11f89791dd29ab867e343c35fd1f3ea7935622ba728d789c9f2e7fd1da51\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://urielch.github.io/\"\n        },\n        {\n          \"type\" : \"distribution\",\n          \"url\" : \"https://oss.sonatype.org/service/local/staging/deploy/maven2/\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/netplex/json-smart-v2\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-expression\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Expression Language (SpEL)\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"2f56216dc7ee08cbeafa54ccf18cad35\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"98786397734b27b7c8843a6b01a7fa34d40d6806\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"0fef5fb19f375a8632d2a117f4b3aed059b959e9693e90c3b7f57b7cad2f9e0b\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"a28e984d9ff1d4078d57f139ff28065ffba7f325c891c74c0774cd3ccfe50a9462cd93483c28c8ca4674b581ab723687c37c5c88e7cb080823d5629fa684e7f8\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"a84fb64144a67b56ce322fc9f4948a9491f6f5876d198eb57c99f38540971a0779a2949b93cc5f32662f97a83823ea87\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"b099ce06de6a5543e52a2d43c97c4ed6567e82263db29849ff09cf37bf48e3e9974308698c2f272187508e242f756576\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"efa3768de47e3b1ff9257f8367a528e38b3eec9c972eb7ba3dd8f60da626fb17\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"95d7011482520e797a25f9d9b8db1b1bf6c24b3ddb3ca4b70fe5a1a58ed04ea870f86f8393f884dad8b893a6fc53ad8da1b21fdc01d9169564c3dc0229824b27\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\"\n    },\n    {\n      \"publisher\" : \"VMware, Inc.\",\n      \"group\" : \"org.springframework.boot\",\n      \"name\" : \"spring-boot-starter-actuator\",\n      \"version\" : \"3.2.1\",\n      \"description\" : \"Starter for using Spring Boot's Actuator which provides production ready features to help you monitor and manage your application\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"59713236dc4fc4b1562a3ea9788bde1e\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"ca17ff67e80a230f04d40d73321d623b769e361d\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"31c28021755feab49cc9310a8353382b3ca35d0adf02926b83e4c44ea4942898\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"ed618c7f1e3337c90919551ad4f14996bb2a78f773ba00c1e02d5a991d1c578e940d9b73f5e01045115c7b5d3f096f8de6720ba0d28992a586ef834948f17766\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"45956cbd019f099f96f36391c98fd23ea32698035f90f6e4e4df0d9a43dc03ef6db2954c2871da76a038511280591b43\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"3a08b673deb39ab5db9561281245b76e9f57410601e5ce4040cefedb02e2a19abb45a98d2de170fbbac7b7f0b93eceb3\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"12151432b32e26bab903572023ea022757a31177e4a6315d8fcd15bbbf34731c\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"911f109b63d07f20de51f8a2de8799e32fdff05a52def36d408cb1da72a3bb63ff0878f850a7ad1cc9e85393f24ac58c6b8dd4068f11d9e70bc1e130974db00f\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-boot\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\"\n    },\n    {\n      \"publisher\" : \"Spring IO\",\n      \"group\" : \"org.springframework\",\n      \"name\" : \"spring-beans\",\n      \"version\" : \"6.1.2\",\n      \"description\" : \"Spring Beans\",\n      \"hashes\" : [\n        {\n          \"alg\" : \"MD5\",\n          \"content\" : \"5ee147f2234968eeab4b469af4d3b5f1\"\n        },\n        {\n          \"alg\" : \"SHA-1\",\n          \"content\" : \"abf52f2254975a3b1e95b2b63fb8b01d891cdc51\"\n        },\n        {\n          \"alg\" : \"SHA-256\",\n          \"content\" : \"742baa41c1b0282ef01b3d542dc1b1de71db2578bd9ddd9a7d57fb191234b194\"\n        },\n        {\n          \"alg\" : \"SHA-512\",\n          \"content\" : \"efd0eb5a073c899515ae144a4fcb4fc97cc53cbd4236d0e6a30df8fa8873fcd9bc509bc3fa88d1bff86a94dc3dbc5106374d0117f64ec8df9e6affe8f98aaa07\"\n        },\n        {\n          \"alg\" : \"SHA-384\",\n          \"content\" : \"6214558d1024fa3b5545079268b0b2fbeda93768a0665d617612ddf4e42e11b770c38c05cb86e3ae558025afa67beea5\"\n        },\n        {\n          \"alg\" : \"SHA3-384\",\n          \"content\" : \"8170ccea30165f25c533e27c0de38b590ca72f285cfc365c60e97745e78532213d6c93bdbea56f561dd180297a8c5ab4\"\n        },\n        {\n          \"alg\" : \"SHA3-256\",\n          \"content\" : \"2761e0814e167de13ed08ce748880006407eda2fa744a347f57684c2bc9bb6fe\"\n        },\n        {\n          \"alg\" : \"SHA3-512\",\n          \"content\" : \"ecdeb4cd558af513ed381942f35bd2d8dfa9b0db446dbc8c5326656ade960682283c71fcaae5578ca431f705f1a86041b0764bd453f30e738be65c4f0bbf37d1\"\n        }\n      ],\n      \"licenses\" : [\n        {\n          \"license\" : {\n            \"id\" : \"Apache-2.0\"\n          }\n        }\n      ],\n      \"purl\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"modified\" : false,\n      \"externalReferences\" : [\n        {\n          \"type\" : \"website\",\n          \"url\" : \"https://spring.io/projects/spring-framework\"\n        },\n        {\n          \"type\" : \"issue-tracker\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework/issues\"\n        },\n        {\n          \"type\" : \"vcs\",\n          \"url\" : \"https://github.com/spring-projects/spring-framework\"\n        }\n      ],\n      \"type\" : \"library\",\n      \"bom-ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\"\n    }\n  ],\n  \"dependencies\" : [\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n        \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n        \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n        \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n        \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n        \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n        \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n        \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n        \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-test@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.xmlunit/xmlunit-core@2.9.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-core@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n        \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n        \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hdrhistogram/HdrHistogram@2.1.12?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.minidev/json-smart@2.5.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.minidev/accessors-smart@2.5.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/ch.qos.logback/logback-classic@1.4.14?type=jar\",\n        \"pkg:maven/org.apache.logging.log4j/log4j-to-slf4j@2.21.1?type=jar\",\n        \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.skyscreamer/jsonassert@1.5.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/ch.qos.logback/logback-core@1.4.14?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-webmvc@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.assertj/assertj-core@3.24.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.jayway.jsonpath/json-path@2.8.0?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-expression@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.slf4j/jul-to-slf4j@2.0.9?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.slf4j/slf4j-api@2.0.9?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.apache.logging.log4j/log4j-api@2.21.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy-agent@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-params@5.10.1?type=jar\",\n        \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-tomcat@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-websocket@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@10.1.17?type=jar\",\n        \"pkg:maven/org.apache.tomcat.embed/tomcat-embed-el@10.1.17?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.awaitility/awaitility@4.2.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.hamcrest/hamcrest@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-context@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/io.micrometer/micrometer-commons@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-jcl@6.1.2?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-json@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-web@6.1.2?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jdk8@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.module/jackson-module-parameter-names@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.mockito/mockito-junit-jupiter@5.7.0?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.mockito/mockito-core@5.7.0?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/net.bytebuddy/byte-buddy@1.14.10?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.junit.jupiter/junit-jupiter-api@5.10.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.junit.platform/junit-platform-commons@1.10.1?type=jar\",\n        \"pkg:maven/org.opentest4j/opentest4j@1.3.0?type=jar\",\n        \"pkg:maven/org.apiguardian/apiguardian-api@1.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.datatype/jackson-datatype-jsr310@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.xml.bind/jakarta.xml.bind-api@4.0.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/jakarta.activation/jakarta.activation-api@2.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-logging@3.2.1?type=jar\",\n        \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\",\n        \"pkg:maven/org.yaml/snakeyaml@2.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.latencyutils/LatencyUtils@2.0.3?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.vaadin.external.google/android-json@0.0.20131108.vaadin1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-test@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework/spring-aop@6.1.2?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework/spring-beans@6.1.2?type=jar\",\n        \"pkg:maven/org.springframework/spring-core@6.1.2?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/jakarta.annotation/jakarta.annotation-api@2.1.1?type=jar\",\n      \"dependsOn\" : [ ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-actuator-autoconfigure@3.2.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-jakarta9@1.12.1?type=jar\",\n        \"pkg:maven/io.micrometer/micrometer-observation@1.12.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.15.3?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.15.3?type=jar\",\n        \"pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.3?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.example/cyclonedx@0.0.1-SNAPSHOT?type=jar\",\n      \"dependsOn\" : [\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-actuator@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-web@3.2.1?type=jar\",\n        \"pkg:maven/org.springframework.boot/spring-boot-starter-test@3.2.1?type=jar\"\n      ]\n    },\n    {\n      \"ref\" : \"pkg:maven/org.ow2.asm/asm@9.3?type=jar\",\n      \"dependsOn\" : [ ]\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/testFixtures/java/org/springframework/boot/actuate/autoconfigure/endpoint/condition/WithTestEndpointOutcomeExposureContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.endpoint.condition;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\n\n/**\n * Makes a test {@link EndpointExposureOutcomeContributor} available via\n * {@link SpringFactoriesLoader}.\n *\n * @author Andy Wilkinson\n */\n@Inherited\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\n@WithResource(name = \"META-INF/spring.factories\",\n\t\tcontent = \"\"\"\n\t\t\t\torg.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor=\\\n\t\t\t\torg.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor.TestEndpointExposureOutcomeContributor\n\t\t\t\t\"\"\")\npublic @interface WithTestEndpointOutcomeExposureContributor {\n\n\tclass TestEndpointExposureOutcomeContributor implements EndpointExposureOutcomeContributor {\n\n\t\tprivate final IncludeExcludeEndpointFilter<?> filter;\n\n\t\tTestEndpointExposureOutcomeContributor(Environment environment) {\n\t\t\tthis.filter = new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, environment,\n\t\t\t\t\t\"management.endpoints.test.exposure\");\n\t\t}\n\n\t\t@Override\n\t\tpublic ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,\n\t\t\t\tBuilder message) {\n\t\t\tif (this.filter.match(endpointId)) {\n\t\t\t\treturn ConditionOutcome.match();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-actuator-autoconfigure/src/testFixtures/java/org/springframework/boot/actuate/autoconfigure/integrationtest/AbstractHealthEndpointAdditionalPathIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.integrationtest;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;\nimport org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Abstract base class for health groups with an additional path.\n *\n * @param <T> the runner\n * @param <C> the application context type\n * @param <A> the assertions\n * @author Madhura Bhave\n */\npublic abstract class AbstractHealthEndpointAdditionalPathIntegrationTests<T extends AbstractApplicationContextRunner<T, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> {\n\n\tprivate final T runner;\n\n\tprotected AbstractHealthEndpointAdditionalPathIntegrationTests(T runner) {\n\t\tthis.runner = runner;\n\t}\n\n\t@Test\n\tvoid groupIsAvailableAtAdditionalPath() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.live.include=diskSpace\",\n\t\t\t\t\t\"management.endpoint.health.group.live.additional-path=server:/healthz\",\n\t\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient(this::testResponse, \"local.server.port\"));\n\t}\n\n\t@Test\n\tvoid multipleGroupsAreAvailableAtAdditionalPaths() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.one.include=diskSpace\",\n\t\t\t\t\t\"management.endpoint.health.group.two.include=diskSpace\",\n\t\t\t\t\t\"management.endpoint.health.group.one.additional-path=server:/alpha\",\n\t\t\t\t\t\"management.endpoint.health.group.two.additional-path=server:/bravo\",\n\t\t\t\t\t\"management.endpoint.health.group.one.show-components=always\",\n\t\t\t\t\t\"management.endpoint.health.group.two.show-components=always\")\n\t\t\t.run(withWebTestClient((client) -> testResponses(client, \"/alpha\", \"/bravo\"), \"local.server.port\"));\n\t}\n\n\t@Test\n\tvoid groupIsAvailableAtAdditionalPathWithoutSlash() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.live.include=diskSpace\",\n\t\t\t\t\t\"management.endpoint.health.group.live.additional-path=server:healthz\",\n\t\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient(this::testResponse, \"local.server.port\"));\n\t}\n\n\t@Test\n\tvoid groupIsAvailableAtAdditionalPathOnManagementPort() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.live.include=diskSpace\", \"management.server.port=0\",\n\t\t\t\t\t\"management.endpoint.health.group.live.additional-path=management:healthz\",\n\t\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient(this::testResponse, \"local.management.port\"));\n\t}\n\n\t@Test\n\tvoid groupIsAvailableAtAdditionalPathOnServerPortWithDifferentManagementPort() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.live.include=diskSpace\", \"management.server.port=0\",\n\t\t\t\t\t\"management.endpoint.health.group.live.additional-path=server:healthz\",\n\t\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient(this::testResponse, \"local.server.port\"));\n\t}\n\n\t@Test\n\tvoid groupsAreNotConfiguredWhenHealthEndpointIsNotExposed() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"management.endpoints.web.exposure.exclude=health\",\n\t\t\t\t\t\"management.server.port=0\", \"management.endpoint.health.group.live.include=diskSpace\",\n\t\t\t\t\t\"management.endpoint.health.group.live.additional-path=server:healthz\",\n\t\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient((client) -> client.get()\n\t\t\t\t.uri(\"/healthz\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound(), \"local.server.port\"));\n\t}\n\n\t@Test\n\tvoid groupsAreNotConfiguredWhenHealthEndpointIsNotExposedAndCloudFoundryPlatform() {\n\t\tthis.runner.withPropertyValues(\"spring.jmx.enabled=true\", \"management.endpoints.web.exposure.exclude=health\",\n\t\t\t\t\"spring.main.cloud-platform=cloud_foundry\", \"management.endpoint.health.group.live.include=diskSpace\",\n\t\t\t\t\"management.endpoint.health.group.live.additional-path=server:healthz\",\n\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient((client) -> client.get()\n\t\t\t\t.uri(\"/healthz\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound(), \"local.server.port\"));\n\t}\n\n\t@Test\n\tvoid groupsAreNotConfiguredWhenHealthEndpointIsNotExposedWithDifferentManagementPortAndCloudFoundryPlatform() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"management.endpoints.web.exposure.exclude=health\",\n\t\t\t\t\t\"spring.main.cloud-platform=cloud_foundry\", \"management.server.port=0\",\n\t\t\t\t\t\"management.endpoint.health.group.live.include=diskSpace\",\n\t\t\t\t\t\"management.endpoint.health.group.live.additional-path=server:healthz\",\n\t\t\t\t\t\"management.endpoint.health.group.live.show-components=always\")\n\t\t\t.run(withWebTestClient((client) -> client.get()\n\t\t\t\t.uri(\"/healthz\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound(), \"local.server.port\"));\n\t}\n\n\tprivate void testResponse(WebTestClient client) {\n\t\ttestResponses(client, \"/healthz\");\n\t}\n\n\tprivate void testResponses(WebTestClient client, String... paths) {\n\t\tfor (String path : paths) {\n\t\t\tassertThatNoException().as(path)\n\t\t\t\t.isThrownBy(() -> client.get()\n\t\t\t\t\t.uri(path)\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"UP\")\n\t\t\t\t\t.jsonPath(\"components.diskSpace\")\n\t\t\t\t\t.exists());\n\t\t}\n\t}\n\n\tprivate ContextConsumer<A> withWebTestClient(Consumer<WebTestClient> consumer, String property) {\n\t\treturn (context) -> {\n\t\t\tString port = context.getEnvironment().getProperty(property);\n\t\t\tWebTestClient client = WebTestClient.bindToServer().baseUrl(\"http://localhost:\" + port).build();\n\t\t\tconsumer.accept(client);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot AMQP\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-messaging\")\n\tapi(\"org.springframework.amqp:spring-rabbit\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\timplementation(project(\":module:spring-boot-transaction\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"org.springframework.amqp:spring-rabbit-stream\")\n\toptional(\"org.testcontainers:testcontainers-rabbitmq\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/docker/compose/RabbitAndRabbitStreamDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails.Address;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link RabbitDockerComposeConnectionDetailsFactory} and\n * {@link RabbitStreamDockerComposeConnectionDetailsFactory} when used in combination.\n *\n * @author Andy Wilkinson\n */\nclass RabbitAndRabbitStreamDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"rabbit-and-rabbit-stream-separate-services-compose.yaml\",\n\t\t\timage = TestImage.RABBITMQ)\n\tvoid runCreatesConnectionDetailsFromSeparateServices(RabbitConnectionDetails connectionDetails,\n\t\t\tRabbitStreamConnectionDetails streamConnectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertConnectionDetails(streamConnectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"rabbit-and-rabbit-stream-single-service-compose.yaml\", image = TestImage.RABBITMQ)\n\tvoid runCreatesConnectionDetailsFromSingleService(RabbitConnectionDetails connectionDetails,\n\t\t\tRabbitStreamConnectionDetails streamConnectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertConnectionDetails(streamConnectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(RabbitConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getVirtualHost()).isEqualTo(\"/\");\n\t\tassertThat(connectionDetails.getAddresses()).hasSize(1);\n\t\tAddress address = connectionDetails.getFirstAddress();\n\t\tassertThat(address.host()).isNotNull();\n\t\tassertThat(address.port()).isGreaterThan(0);\n\t}\n\n\tprivate void assertConnectionDetails(RabbitStreamConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getVirtualHost()).isEqualTo(\"/\");\n\t\tassertThat(connectionDetails.getHost()).isNotNull();\n\t\tassertThat(connectionDetails.getPort()).isGreaterThan(0);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/docker/compose/RabbitDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails.Address;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link RabbitDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass RabbitDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"rabbit-compose.yaml\", image = TestImage.RABBITMQ)\n\tvoid runCreatesConnectionDetails(RabbitConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"rabbit-ssl-compose.yaml\", image = TestImage.RABBITMQ,\n\t\t\tadditionalResources = { \"../../ca.crt\", \"../../server.crt\", \"../../server.key\", \"../../client.crt\",\n\t\t\t\t\t\"../../client.key\", \"rabbitmq-ssl.conf\" })\n\tvoid runWithSslCreatesConnectionDetails(RabbitConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\tprivate void assertConnectionDetails(RabbitConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getVirtualHost()).isEqualTo(\"/\");\n\t\tassertThat(connectionDetails.getAddresses()).hasSize(1);\n\t\tAddress address = connectionDetails.getFirstAddress();\n\t\tassertThat(address.host()).isNotNull();\n\t\tassertThat(address.port()).isGreaterThan(0);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/docker/compose/RabbitStreamDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link RabbitStreamDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass RabbitStreamDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"rabbit-stream-compose.yaml\", image = TestImage.RABBITMQ)\n\tvoid runCreatesConnectionDetails(RabbitStreamConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"rabbit-stream-ssl-compose.yaml\", image = TestImage.RABBITMQ,\n\t\t\tadditionalResources = { \"../../ca.crt\", \"../../server.crt\", \"../../server.key\", \"../../client.crt\",\n\t\t\t\t\t\"../../client.key\", \"rabbitmq-stream-ssl.conf\" })\n\tvoid runWithSslCreatesConnectionDetails(RabbitStreamConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\tprivate void assertConnectionDetails(RabbitStreamConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getVirtualHost()).isEqualTo(\"/\");\n\t\tassertThat(connectionDetails.getHost()).isNotNull();\n\t\tassertThat(connectionDetails.getPort()).isGreaterThan(0);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/docker/compose/SingleServiceRabbitAndRabbitStreamDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails.Address;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link RabbitDockerComposeConnectionDetailsFactory} and\n * {@link RabbitStreamDockerComposeConnectionDetailsFactory} when using a single service\n * for standard and stream-based messaging.\n *\n * @author Andy Wilkinson\n */\nclass SingleServiceRabbitAndRabbitStreamDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"rabbit-and-rabbit-stream-single-service-compose.yaml\", image = TestImage.RABBITMQ)\n\tvoid runCreatesConnectionDetails(RabbitConnectionDetails connectionDetails,\n\t\t\tRabbitStreamConnectionDetails streamConnectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertConnectionDetails(streamConnectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(RabbitConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getVirtualHost()).isEqualTo(\"/\");\n\t\tassertThat(connectionDetails.getAddresses()).hasSize(1);\n\t\tAddress address = connectionDetails.getFirstAddress();\n\t\tassertThat(address.host()).isNotNull();\n\t\tassertThat(address.port()).isGreaterThan(0);\n\t}\n\n\tprivate void assertConnectionDetails(RabbitStreamConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getVirtualHost()).isEqualTo(\"/\");\n\t\tassertThat(connectionDetails.getHost()).isNotNull();\n\t\tassertThat(connectionDetails.getPort()).isGreaterThan(0);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/testcontainers/DeprecatedRabbitContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.RabbitMQContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DeprecatedRabbitContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link RabbitContainerConnectionDetailsFactoryIntegrationTests}.\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedRabbitContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RabbitMQContainer rabbit = TestImage.container(RabbitMQContainer.class);\n\n\t@Autowired(required = false)\n\tprivate RabbitConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate RabbitTemplate rabbitTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToRabbitContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tthis.rabbitTemplate.convertAndSend(\"test\", \"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(RabbitAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@RabbitListener(queuesToDeclare = @Queue(\"test\"))\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/testcontainers/RabbitContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.amqp.rabbit.annotation.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass RabbitContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RabbitMQContainer rabbit = TestImage.container(RabbitMQContainer.class);\n\n\t@Autowired(required = false)\n\tprivate RabbitConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate RabbitTemplate rabbitTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToRabbitContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tthis.rabbitTemplate.convertAndSend(\"test\", \"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(RabbitAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@RabbitListener(queuesToDeclare = @Queue(\"test\"))\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/testcontainers/RabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.rabbitmq.stream.Address;\nimport com.rabbitmq.stream.Environment;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.images.builder.Transferable;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.EnvironmentBuilderCustomizer;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitContainerConnectionDetailsFactory.RabbitMqContainerConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitStreamContainerConnectionDetailsFactory.RabbitMqStreamContainerConnectionDetails;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.StreamAdmin;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitStreamContainerConnectionDetailsFactory} with a single container\n * that's only used for streams.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@TestPropertySource(\n\t\tproperties = { \"spring.rabbitmq.stream.name=stream.queue1\", \"spring.rabbitmq.listener.type=stream\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass RabbitStreamContainerConnectionDetailsFactoryIntegrationTests {\n\n\tprivate static final int RABBITMQ_STREAMS_PORT = 5552;\n\n\t@Container\n\t@ServiceConnection(type = RabbitStreamConnectionDetails.class)\n\tstatic final RabbitMQContainer rabbit = getRabbitMqStreamContainer();\n\n\tprivate static RabbitMQContainer getRabbitMqStreamContainer() {\n\t\tRabbitMQContainer container = TestImage.container(RabbitMQContainer.class);\n\t\tcontainer.addExposedPorts(RABBITMQ_STREAMS_PORT);\n\t\tString enabledPlugins = \"[rabbitmq_stream,rabbitmq_prometheus].\";\n\t\tcontainer.withCopyToContainer(Transferable.of(enabledPlugins), \"/etc/rabbitmq/enabled_plugins\");\n\t\treturn container;\n\t}\n\n\t@Autowired(required = false)\n\tprivate RabbitConnectionDetails connectionDetails;\n\n\t@Autowired(required = false)\n\tprivate RabbitStreamConnectionDetails streamConnectionDetails;\n\n\t@Autowired\n\tprivate RabbitStreamTemplate rabbitStreamTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToRabbitContainer() {\n\t\tassertThat(this.connectionDetails).isNotInstanceOf(RabbitMqContainerConnectionDetails.class);\n\t\tassertThat(this.streamConnectionDetails).isInstanceOf(RabbitMqStreamContainerConnectionDetails.class);\n\t\tthis.rabbitStreamTemplate.convertAndSend(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(RabbitAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tStreamAdmin streamAdmin(Environment env) {\n\t\t\treturn new StreamAdmin(env, (sc) -> sc.stream(\"stream.queue1\").create());\n\t\t}\n\n\t\t@Bean\n\t\tEnvironmentBuilderCustomizer environmentBuilderCustomizer() {\n\t\t\treturn (env) -> env.addressResolver(\n\t\t\t\t\t(address) -> new Address(rabbit.getHost(), rabbit.getMappedPort(RABBITMQ_STREAMS_PORT)));\n\t\t}\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@RabbitListener(queues = \"stream.queue1\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/testcontainers/RabbitStreamWithSslContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.rabbitmq.stream.Address;\nimport com.rabbitmq.stream.Environment;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.images.builder.Transferable;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\nimport org.testcontainers.utility.MountableFile;\n\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.EnvironmentBuilderCustomizer;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitContainerConnectionDetailsFactory.RabbitMqContainerConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitStreamContainerConnectionDetailsFactory.RabbitMqStreamContainerConnectionDetails;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.StreamAdmin;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitStreamContainerConnectionDetailsFactory} with SSL.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@TestPropertySource(\n\t\tproperties = { \"spring.rabbitmq.stream.name=stream.queue1\", \"spring.rabbitmq.listener.type=stream\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass RabbitStreamWithSslContainerConnectionDetailsFactoryIntegrationTests {\n\n\tprivate static final int RABBITMQ_STREAMS_TLS_PORT = 5551;\n\n\t@Container\n\t@ServiceConnection(type = RabbitStreamConnectionDetails.class)\n\t@PemTrustStore(certificate = \"classpath:org/springframework/boot/amqp/ca.crt\")\n\t@PemKeyStore(certificate = \"classpath:org/springframework/boot/amqp/client.crt\",\n\t\t\tprivateKey = \"classpath:org/springframework/boot/amqp/client.key\")\n\tstatic final RabbitMQContainer rabbit = getRabbitMqStreamContainer();\n\n\tprivate static RabbitMQContainer getRabbitMqStreamContainer() {\n\t\tRabbitMQContainer container = TestImage.container(RabbitMQContainer.class);\n\t\tcontainer.addExposedPorts(RABBITMQ_STREAMS_TLS_PORT);\n\t\tString enabledPlugins = \"[rabbitmq_stream,rabbitmq_prometheus].\";\n\t\tcontainer.withCopyToContainer(Transferable.of(enabledPlugins), \"/etc/rabbitmq/enabled_plugins\");\n\t\tcontainer.withCopyFileToContainer(\n\t\t\t\tMountableFile\n\t\t\t\t\t.forClasspathResource(\"org/springframework/boot/amqp/testcontainers/rabbitmq-stream-ssl.conf\"),\n\t\t\t\t\"/etc/rabbitmq/rabbitmq.conf\");\n\t\tcontainer.withCopyFileToContainer(MountableFile.forClasspathResource(\"org/springframework/boot/amqp/ca.crt\"),\n\t\t\t\t\"/etc/rabbitmq/ca.crt\");\n\t\tcontainer.withCopyFileToContainer(\n\t\t\t\tMountableFile.forClasspathResource(\"org/springframework/boot/amqp/server.key\"),\n\t\t\t\t\"/etc/rabbitmq/server.key\");\n\t\tcontainer.withCopyFileToContainer(\n\t\t\t\tMountableFile.forClasspathResource(\"org/springframework/boot/amqp/server.crt\"),\n\t\t\t\t\"/etc/rabbitmq/server.crt\");\n\t\treturn container;\n\t}\n\n\t@Autowired(required = false)\n\tprivate RabbitConnectionDetails connectionDetails;\n\n\t@Autowired(required = false)\n\tprivate RabbitStreamConnectionDetails streamConnectionDetails;\n\n\t@Autowired\n\tprivate RabbitStreamTemplate rabbitStreamTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToRabbitContainer() {\n\t\tassertThat(this.connectionDetails).isNotInstanceOf(RabbitMqContainerConnectionDetails.class);\n\t\tassertThat(this.streamConnectionDetails).isInstanceOf(RabbitMqStreamContainerConnectionDetails.class);\n\t\tassertThat(this.streamConnectionDetails.getSslBundle()).isNotNull();\n\t\tthis.rabbitStreamTemplate.convertAndSend(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(RabbitAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tStreamAdmin streamAdmin(Environment env) {\n\t\t\treturn new StreamAdmin(env, (sc) -> sc.stream(\"stream.queue1\").create());\n\t\t}\n\n\t\t@Bean\n\t\tEnvironmentBuilderCustomizer environmentBuilderCustomizer() {\n\t\t\treturn (env) -> env.addressResolver(\n\t\t\t\t\t(address) -> new Address(rabbit.getHost(), rabbit.getMappedPort(RABBITMQ_STREAMS_TLS_PORT)));\n\t\t}\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@RabbitListener(queues = \"stream.queue1\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/testcontainers/SeparateContainersRabbitAndRabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.rabbitmq.stream.Address;\nimport com.rabbitmq.stream.Environment;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.images.builder.Transferable;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.core.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.EnvironmentBuilderCustomizer;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitContainerConnectionDetailsFactory.RabbitMqContainerConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitStreamContainerConnectionDetailsFactory.RabbitMqStreamContainerConnectionDetails;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.StreamAdmin;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitStreamContainerConnectionDetailsFactory} with two containers,\n * one for streams and one for standard messaging.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@TestPropertySource(\n\t\tproperties = { \"spring.rabbitmq.stream.name=stream.queue1\", \"spring.rabbitmq.listener.type=stream\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass SeparateContainersRabbitAndRabbitStreamContainerConnectionDetailsFactoryIntegrationTests {\n\n\tprivate static final int RABBITMQ_STREAMS_PORT = 5552;\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RabbitMQContainer rabbit = TestImage.container(RabbitMQContainer.class);\n\n\t@Container\n\t@ServiceConnection(type = RabbitStreamConnectionDetails.class)\n\tstatic final RabbitMQContainer rabbitStream = getRabbitMqStreamContainer();\n\n\tprivate static RabbitMQContainer getRabbitMqStreamContainer() {\n\t\tRabbitMQContainer container = TestImage.container(RabbitMQContainer.class);\n\t\tcontainer.addExposedPorts(RABBITMQ_STREAMS_PORT);\n\t\tString enabledPlugins = \"[rabbitmq_stream,rabbitmq_prometheus].\";\n\t\tcontainer.withCopyToContainer(Transferable.of(enabledPlugins), \"/etc/rabbitmq/enabled_plugins\");\n\t\treturn container;\n\t}\n\n\t@Autowired(required = false)\n\tprivate RabbitConnectionDetails connectionDetails;\n\n\t@Autowired(required = false)\n\tprivate RabbitStreamConnectionDetails streamConnectionDetails;\n\n\t@Autowired\n\tprivate RabbitTemplate rabbitTemplate;\n\n\t@Autowired\n\tprivate RabbitStreamTemplate rabbitStreamTemplate;\n\n\t@Autowired\n\tprivate StreamTestListener streamListener;\n\n\t@Test\n\tvoid rabbitConnectionDetailsAreSourcedFromContainer() {\n\t\tassertThat(this.connectionDetails).isInstanceOf(RabbitMqContainerConnectionDetails.class);\n\t\tassertThat(this.connectionDetails.getFirstAddress().port()).isEqualTo(rabbit.getAmqpPort());\n\t}\n\n\t@Test\n\tvoid rabbitStreamConnectionDetailsAreSourcedFromContainer() {\n\t\tassertThat(this.streamConnectionDetails).isInstanceOf(RabbitMqStreamContainerConnectionDetails.class);\n\t\tassertThat(this.streamConnectionDetails.getPort()).isEqualTo(rabbitStream.getMappedPort(RABBITMQ_STREAMS_PORT));\n\t}\n\n\t@Test\n\tvoid connectionCanBeMadeToRabbitContainer() {\n\t\tthis.rabbitTemplate.convertAndSend(\"test\", \"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.rabbitTemplate.receive(\"test\"))\n\t\t\t\t.extracting((message) -> new String(message.getBody(), StandardCharsets.UTF_8))\n\t\t\t\t.isEqualTo(\"message\"));\n\t}\n\n\t@Test\n\tvoid streamConnectionCanBeMadeToRabbitContainer() {\n\t\tthis.rabbitStreamTemplate.convertAndSend(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.streamListener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(RabbitAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\tTestConfiguration(AmqpAdmin amqpAdmin) {\n\t\t\tamqpAdmin.declareQueue(new Queue(\"test\"));\n\t\t}\n\n\t\t@Bean\n\t\tStreamAdmin streamAdmin(Environment env) {\n\t\t\treturn new StreamAdmin(env, (sc) -> sc.stream(\"stream.queue1\").create());\n\t\t}\n\n\t\t@Bean\n\t\tEnvironmentBuilderCustomizer environmentBuilderCustomizer() {\n\t\t\treturn (env) -> env.addressResolver((address) -> new Address(rabbitStream.getHost(),\n\t\t\t\t\trabbitStream.getMappedPort(RABBITMQ_STREAMS_PORT)));\n\t\t}\n\n\t\t@Bean\n\t\tStreamTestListener streamTestListener() {\n\t\t\treturn new StreamTestListener();\n\t\t}\n\n\t}\n\n\tstatic class StreamTestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@RabbitListener(queues = \"stream.queue1\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/java/org/springframework/boot/amqp/testcontainers/SingleContainerRabbitAndRabbitStreamContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.rabbitmq.stream.Address;\nimport com.rabbitmq.stream.Environment;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.images.builder.Transferable;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.core.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.EnvironmentBuilderCustomizer;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitContainerConnectionDetailsFactory.RabbitMqContainerConnectionDetails;\nimport org.springframework.boot.amqp.testcontainers.RabbitStreamContainerConnectionDetailsFactory.RabbitMqStreamContainerConnectionDetails;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.StreamAdmin;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitStreamContainerConnectionDetailsFactory} with a single container\n * used for both streams and standard messaging.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@TestPropertySource(\n\t\tproperties = { \"spring.rabbitmq.stream.name=stream.queue1\", \"spring.rabbitmq.listener.type=stream\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass SingleContainerRabbitAndRabbitStreamContainerConnectionDetailsFactoryIntegrationTests {\n\n\tprivate static final int RABBITMQ_STREAMS_PORT = 5552;\n\n\t@Container\n\t@ServiceConnection(type = { RabbitConnectionDetails.class, RabbitStreamConnectionDetails.class })\n\tstatic final RabbitMQContainer rabbit = getRabbitMqStreamContainer();\n\n\tprivate static RabbitMQContainer getRabbitMqStreamContainer() {\n\t\tRabbitMQContainer container = TestImage.container(RabbitMQContainer.class);\n\t\tcontainer.addExposedPorts(RABBITMQ_STREAMS_PORT);\n\t\tString enabledPlugins = \"[rabbitmq_stream,rabbitmq_prometheus].\";\n\t\tcontainer.withCopyToContainer(Transferable.of(enabledPlugins), \"/etc/rabbitmq/enabled_plugins\");\n\t\treturn container;\n\t}\n\n\t@Autowired(required = false)\n\tprivate RabbitConnectionDetails connectionDetails;\n\n\t@Autowired(required = false)\n\tprivate RabbitStreamConnectionDetails streamConnectionDetails;\n\n\t@Autowired\n\tprivate RabbitStreamTemplate rabbitStreamTemplate;\n\n\t@Autowired\n\tprivate RabbitTemplate rabbitTemplate;\n\n\t@Autowired\n\tprivate StreamTestListener streamListener;\n\n\t@Test\n\tvoid rabbitConnectionDetailsAreSourcedFromContainer() {\n\t\tassertThat(this.connectionDetails).isInstanceOf(RabbitMqContainerConnectionDetails.class);\n\t}\n\n\t@Test\n\tvoid rabbitStreamConnectionDetailsAreSourcedFromContainer() {\n\t\tassertThat(this.streamConnectionDetails).isInstanceOf(RabbitMqStreamContainerConnectionDetails.class);\n\t}\n\n\t@Test\n\tvoid connectionCanBeMadeToRabbitContainer() {\n\t\tthis.rabbitTemplate.convertAndSend(\"test\", \"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.rabbitTemplate.receive(\"test\"))\n\t\t\t\t.extracting((message) -> new String(message.getBody(), StandardCharsets.UTF_8))\n\t\t\t\t.isEqualTo(\"message\"));\n\t}\n\n\t@Test\n\tvoid streamConnectionCanBeMadeToRabbitContainer() {\n\t\tthis.rabbitStreamTemplate.convertAndSend(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.streamListener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(RabbitAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\tTestConfiguration(AmqpAdmin amqpAdmin) {\n\t\t\tamqpAdmin.declareQueue(new Queue(\"test\"));\n\t\t}\n\n\t\t@Bean\n\t\tStreamAdmin streamAdmin(Environment env) {\n\t\t\treturn new StreamAdmin(env, (sc) -> sc.stream(\"stream.queue1\").create());\n\t\t}\n\n\t\t@Bean\n\t\tEnvironmentBuilderCustomizer environmentBuilderCustomizer() {\n\t\t\treturn (env) -> env.addressResolver(\n\t\t\t\t\t(address) -> new Address(rabbit.getHost(), rabbit.getMappedPort(RABBITMQ_STREAMS_PORT)));\n\t\t}\n\n\t\t@Bean\n\t\tStreamTestListener streamTestListener() {\n\t\t\treturn new StreamTestListener();\n\t\t}\n\n\t}\n\n\tstatic class StreamTestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@RabbitListener(queues = \"stream.queue1\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbit-and-rabbit-stream-separate-services-compose.yaml",
    "content": "services:\n  rabbitmq:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    ports:\n      - '5672'\n  rabbitmq_streams:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    configs:\n      - source: plugins\n        target: /etc/rabbitmq/enabled_plugins\n    ports:\n      - '5552'\nconfigs:\n  plugins:\n    content: \"[rabbitmq_stream].\"\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbit-and-rabbit-stream-single-service-compose.yaml",
    "content": "services:\n  rabbitmq:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    configs:\n      - source: plugins\n        target: /etc/rabbitmq/enabled_plugins\n    ports:\n      - '5552'\n      - '5672'\nconfigs:\n  plugins:\n    content: \"[rabbitmq_stream].\"\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbit-compose.yaml",
    "content": "services:\n  rabbitmq:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    ports:\n      - '5672'\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbit-ssl-compose.yaml",
    "content": "services:\n  rabbitmq:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    ports:\n      - '5672'\n      - '5671'\n    secrets:\n      - ssl-ca\n      - ssl-key\n      - ssl-cert\n    volumes:\n      - ./rabbitmq-ssl.conf:/etc/rabbitmq/rabbitmq.conf:ro\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'\n      - 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\nsecrets:\n  ssl-ca:\n    file: 'ca.crt'\n  ssl-key:\n    file: 'server.key'\n  ssl-cert:\n    file: 'server.crt'"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbit-stream-compose.yaml",
    "content": "services:\n  rabbitmq:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    configs:\n      - source: plugins\n        target: /etc/rabbitmq/enabled_plugins\n    ports:\n      - '5552'\nconfigs:\n  plugins:\n    content: \"[rabbitmq_stream].\"\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbit-stream-ssl-compose.yaml",
    "content": "services:\n  rabbitmq:\n    image: '{imageName}'\n    environment:\n      - 'RABBITMQ_DEFAULT_USER=myuser'\n      - 'RABBITMQ_DEFAULT_PASS=secret'\n    configs:\n      - source: plugins\n        target: /etc/rabbitmq/enabled_plugins\n    ports:\n      - '5551'\n      - '5552'\n    secrets:\n      - ssl-ca\n      - ssl-key\n      - ssl-cert\n    volumes:\n      - ./rabbitmq-stream-ssl.conf:/etc/rabbitmq/rabbitmq.conf:ro\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'\n      - 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\nsecrets:\n  ssl-ca:\n    file: 'ca.crt'\n  ssl-key:\n    file: 'server.key'\n  ssl-cert:\n    file: 'server.crt'\nconfigs:\n  plugins:\n    content: \"[rabbitmq_stream].\"\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbitmq-ssl.conf",
    "content": "listeners.ssl.default=5671\n\nssl_options.cacertfile=/run/secrets/ssl-ca\nssl_options.certfile=/run/secrets/ssl-cert\nssl_options.keyfile=/run/secrets/ssl-key\n\nssl_options.verify=verify_peer\nssl_options.fail_if_no_peer_cert=true\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/docker/compose/rabbitmq-stream-ssl.conf",
    "content": "stream.listeners.ssl.1 = 5551\n\nssl_options.cacertfile=/run/secrets/ssl-ca\nssl_options.certfile=/run/secrets/ssl-cert\nssl_options.keyfile=/run/secrets/ssl-key\n\nssl_options.verify=verify_peer\nssl_options.fail_if_no_peer_cert=true\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/org/springframework/boot/amqp/testcontainers/rabbitmq-stream-ssl.conf",
    "content": "stream.listeners.ssl.1 = 5551\n\nssl_options.cacertfile=/etc/rabbitmq/ca.crt\nssl_options.certfile=/etc/rabbitmq/server.crt\nssl_options.keyfile=/etc/rabbitmq/server.key\n\nssl_options.verify=verify_peer\nssl_options.fail_if_no_peer_cert=true\n"
  },
  {
    "path": "module/spring-boot-amqp/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/AbstractConnectionFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.connection.AbstractConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.util.Assert;\n\n/**\n * Base class for configurers of sub-classes of {@link AbstractConnectionFactory}.\n *\n * @param <T> the connection factory type.\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class AbstractConnectionFactoryConfigurer<T extends AbstractConnectionFactory> {\n\n\tprivate final RabbitProperties rabbitProperties;\n\n\tprivate @Nullable ConnectionNameStrategy connectionNameStrategy;\n\n\tprivate final RabbitConnectionDetails connectionDetails;\n\n\t/**\n\t * Creates a new configurer that will configure the connection factory using the given\n\t * {@code properties}.\n\t * @param properties the properties to use to configure the connection factory\n\t */\n\tprotected AbstractConnectionFactoryConfigurer(RabbitProperties properties) {\n\t\tthis(properties, new PropertiesRabbitConnectionDetails(properties, null));\n\t}\n\n\t/**\n\t * Creates a new configurer that will configure the connection factory using the given\n\t * {@code properties} and {@code connectionDetails}, with the latter taking priority.\n\t * @param properties the properties to use to configure the connection factory\n\t * @param connectionDetails the connection details to use to configure the connection\n\t * factory\n\t */\n\tprotected AbstractConnectionFactoryConfigurer(RabbitProperties properties,\n\t\t\tRabbitConnectionDetails connectionDetails) {\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tAssert.notNull(connectionDetails, \"'connectionDetails' must not be null\");\n\t\tthis.rabbitProperties = properties;\n\t\tthis.connectionDetails = connectionDetails;\n\t}\n\n\tprotected final @Nullable ConnectionNameStrategy getConnectionNameStrategy() {\n\t\treturn this.connectionNameStrategy;\n\t}\n\n\tpublic final void setConnectionNameStrategy(@Nullable ConnectionNameStrategy connectionNameStrategy) {\n\t\tthis.connectionNameStrategy = connectionNameStrategy;\n\t}\n\n\t/**\n\t * Configures the given {@code connectionFactory} with sensible defaults.\n\t * @param connectionFactory connection factory to configure\n\t */\n\tpublic final void configure(T connectionFactory) {\n\t\tAssert.notNull(connectionFactory, \"'connectionFactory' must not be null\");\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tString addresses = this.connectionDetails.getAddresses()\n\t\t\t.stream()\n\t\t\t.map((address) -> address.host() + \":\" + address.port())\n\t\t\t.collect(Collectors.joining(\",\"));\n\t\tmap.from(addresses).to(connectionFactory::setAddresses);\n\t\tmap.from(this.rabbitProperties::getAddressShuffleMode).to(connectionFactory::setAddressShuffleMode);\n\t\tmap.from(this.connectionNameStrategy).to(connectionFactory::setConnectionNameStrategy);\n\t\tconfigure(connectionFactory, this.rabbitProperties);\n\t}\n\n\t/**\n\t * Configures the given {@code connectionFactory} using the given\n\t * {@code rabbitProperties}.\n\t * @param connectionFactory connection factory to configure\n\t * @param rabbitProperties properties to use for the configuration\n\t */\n\tprotected abstract void configure(T connectionFactory, RabbitProperties rabbitProperties);\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/AbstractRabbitListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.config.RetryInterceptorBuilder;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.retry.MessageRecoverer;\nimport org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitListenerObservationConvention;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties.ListenerRetry;\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties.Retry;\nimport org.springframework.boot.retry.RetryPolicySettings;\nimport org.springframework.core.retry.RetryPolicy;\nimport org.springframework.util.Assert;\n\n/**\n * Base class for configurers of sub-classes of\n * {@link AbstractRabbitListenerContainerFactory}.\n *\n * @param <T> the container factory type.\n * @author Gary Russell\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic abstract class AbstractRabbitListenerContainerFactoryConfigurer<T extends AbstractRabbitListenerContainerFactory<?>> {\n\n\tprivate @Nullable MessageConverter messageConverter;\n\n\tprivate @Nullable MessageRecoverer messageRecoverer;\n\n\tprivate @Nullable List<RabbitListenerRetrySettingsCustomizer> retrySettingsCustomizers;\n\n\tprivate final RabbitProperties rabbitProperties;\n\n\tprivate @Nullable Executor taskExecutor;\n\n\tprivate @Nullable RabbitListenerObservationConvention observationConvention;\n\n\t/**\n\t * Creates a new configurer that will use the given {@code rabbitProperties}.\n\t * @param rabbitProperties properties to use\n\t */\n\tprotected AbstractRabbitListenerContainerFactoryConfigurer(RabbitProperties rabbitProperties) {\n\t\tthis.rabbitProperties = rabbitProperties;\n\t}\n\n\t/**\n\t * Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box\n\t * converter should be used.\n\t * @param messageConverter the {@link MessageConverter}\n\t */\n\tprotected void setMessageConverter(@Nullable MessageConverter messageConverter) {\n\t\tthis.messageConverter = messageConverter;\n\t}\n\n\t/**\n\t * Set the {@link MessageRecoverer} to use or {@code null} to rely on the default.\n\t * @param messageRecoverer the {@link MessageRecoverer}\n\t */\n\tprotected void setMessageRecoverer(@Nullable MessageRecoverer messageRecoverer) {\n\t\tthis.messageRecoverer = messageRecoverer;\n\t}\n\n\t/**\n\t * Set the {@link RabbitListenerRetrySettingsCustomizer} instances to use.\n\t * @param retrySettingsCustomizers the retry settings customizers\n\t */\n\tprotected void setRetrySettingsCustomizers(\n\t\t\t@Nullable List<RabbitListenerRetrySettingsCustomizer> retrySettingsCustomizers) {\n\t\tthis.retrySettingsCustomizers = retrySettingsCustomizers;\n\t}\n\n\t/**\n\t * Set the task executor to use.\n\t * @param taskExecutor the task executor\n\t */\n\tpublic void setTaskExecutor(@Nullable Executor taskExecutor) {\n\t\tthis.taskExecutor = taskExecutor;\n\t}\n\n\t/**\n\t * Sets the observation convention to use.\n\t * @param observationConvention the observation convention to use\n\t * @since 4.1.0\n\t */\n\tprotected void setObservationConvention(@Nullable RabbitListenerObservationConvention observationConvention) {\n\t\tthis.observationConvention = observationConvention;\n\t}\n\n\tprotected final RabbitProperties getRabbitProperties() {\n\t\treturn this.rabbitProperties;\n\t}\n\n\t/**\n\t * Configure the specified rabbit listener container factory. The factory can be\n\t * further tuned and default settings can be overridden.\n\t * @param factory the {@link AbstractRabbitListenerContainerFactory} instance to\n\t * configure\n\t * @param connectionFactory the {@link ConnectionFactory} to use\n\t */\n\tpublic abstract void configure(T factory, ConnectionFactory connectionFactory);\n\n\tprotected void configure(T factory, ConnectionFactory connectionFactory,\n\t\t\tRabbitProperties.AmqpContainer configuration) {\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\tAssert.notNull(connectionFactory, \"'connectionFactory' must not be null\");\n\t\tAssert.notNull(configuration, \"'configuration' must not be null\");\n\t\tfactory.setConnectionFactory(connectionFactory);\n\t\tif (this.messageConverter != null) {\n\t\t\tfactory.setMessageConverter(this.messageConverter);\n\t\t}\n\t\tfactory.setAutoStartup(configuration.isAutoStartup());\n\t\tif (configuration.getAcknowledgeMode() != null) {\n\t\t\tfactory.setAcknowledgeMode(configuration.getAcknowledgeMode());\n\t\t}\n\t\tif (configuration.getPrefetch() != null) {\n\t\t\tfactory.setPrefetchCount(configuration.getPrefetch());\n\t\t}\n\t\tif (configuration.getDefaultRequeueRejected() != null) {\n\t\t\tfactory.setDefaultRequeueRejected(configuration.getDefaultRequeueRejected());\n\t\t}\n\t\tif (configuration.getIdleEventInterval() != null) {\n\t\t\tfactory.setIdleEventInterval(configuration.getIdleEventInterval().toMillis());\n\t\t}\n\t\tfactory.setMissingQueuesFatal(configuration.isMissingQueuesFatal());\n\t\tfactory.setDeBatchingEnabled(configuration.isDeBatchingEnabled());\n\t\tfactory.setForceStop(configuration.isForceStop());\n\t\tif (this.taskExecutor != null) {\n\t\t\tfactory.setTaskExecutor(this.taskExecutor);\n\t\t}\n\t\tfactory.setObservationEnabled(configuration.isObservationEnabled());\n\t\tListenerRetry retryConfig = configuration.getRetry();\n\t\tif (retryConfig.isEnabled()) {\n\t\t\tRetryInterceptorBuilder<?, ?> builder = (retryConfig.isStateless()) ? RetryInterceptorBuilder.stateless()\n\t\t\t\t\t: RetryInterceptorBuilder.stateful();\n\t\t\tbuilder.retryPolicy(createRetryPolicy(retryConfig));\n\t\t\tMessageRecoverer recoverer = (this.messageRecoverer != null) ? this.messageRecoverer\n\t\t\t\t\t: new RejectAndDontRequeueRecoverer();\n\t\t\tbuilder.recoverer(recoverer);\n\t\t\tfactory.setAdviceChain(builder.build());\n\t\t}\n\t\tif (this.observationConvention != null) {\n\t\t\tfactory.setObservationConvention(this.observationConvention);\n\t\t}\n\t}\n\n\tprivate RetryPolicy createRetryPolicy(Retry retryProperties) {\n\t\tRetryPolicySettings retrySettings = retryProperties.initializeRetryPolicySettings();\n\t\tif (this.retrySettingsCustomizers != null) {\n\t\t\tfor (RabbitListenerRetrySettingsCustomizer customizer : this.retrySettingsCustomizers) {\n\t\t\t\tcustomizer.customize(retrySettings);\n\t\t\t}\n\t\t}\n\t\treturn retrySettings.createRetryPolicy();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/CachingConnectionFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory;\nimport org.springframework.boot.context.properties.PropertyMapper;\n\n/**\n * Configures Rabbit {@link CachingConnectionFactory} with sensible defaults tuned using\n * configuration properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code CachingConnectionFactory} whose configuration is based upon that produced by\n * auto-configuration.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class CachingConnectionFactoryConfigurer extends AbstractConnectionFactoryConfigurer<CachingConnectionFactory> {\n\n\t/**\n\t * Creates a new configurer that will configure the connection factory using the given\n\t * {@code properties}.\n\t * @param properties the properties to use to configure the connection factory\n\t */\n\tpublic CachingConnectionFactoryConfigurer(RabbitProperties properties) {\n\t\tthis(properties, new PropertiesRabbitConnectionDetails(properties, null));\n\t}\n\n\t/**\n\t * Creates a new configurer that will configure the connection factory using the given\n\t * {@code properties} and {@code connectionDetails}, with the latter taking priority.\n\t * @param properties the properties to use to configure the connection factory\n\t * @param connectionDetails the connection details to use to configure the connection\n\t * factory\n\t */\n\tpublic CachingConnectionFactoryConfigurer(RabbitProperties properties, RabbitConnectionDetails connectionDetails) {\n\t\tsuper(properties, connectionDetails);\n\t}\n\n\t@Override\n\tpublic void configure(CachingConnectionFactory connectionFactory, RabbitProperties rabbitProperties) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(rabbitProperties::isPublisherReturns).to(connectionFactory::setPublisherReturns);\n\t\tmap.from(rabbitProperties::getPublisherConfirmType).to(connectionFactory::setPublisherConfirmType);\n\t\tRabbitProperties.Cache.Channel channel = rabbitProperties.getCache().getChannel();\n\t\tmap.from(channel::getSize).to(connectionFactory::setChannelCacheSize);\n\t\tmap.from(channel::getCheckoutTimeout).as(Duration::toMillis).to(connectionFactory::setChannelCheckoutTimeout);\n\t\tRabbitProperties.Cache.Connection connection = rabbitProperties.getCache().getConnection();\n\t\tmap.from(connection::getMode).to(connectionFactory::setCacheMode);\n\t\tmap.from(connection::getSize).to(connectionFactory::setConnectionCacheSize);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/ConnectionFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport com.rabbitmq.client.ConnectionFactory;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the RabbitMQ\n * {@link ConnectionFactory} to fine-tune its auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ConnectionFactoryCustomizer {\n\n\t/**\n\t * Customize the {@link ConnectionFactory}.\n\t * @param factory the factory to customize\n\t */\n\tvoid customize(ConnectionFactory factory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/DirectRabbitListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.boot.context.properties.PropertyMapper;\n\n/**\n * Configure {@link DirectRabbitListenerContainerFactory} with sensible defaults tuned\n * using configuration properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code DirectRabbitListenerContainerFactory} whose configuration is based upon that\n * produced by auto-configuration.\n *\n * @author Gary Russell\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class DirectRabbitListenerContainerFactoryConfigurer\n\t\textends AbstractRabbitListenerContainerFactoryConfigurer<DirectRabbitListenerContainerFactory> {\n\n\t/**\n\t * Creates a new configurer that will use the given {@code rabbitProperties}.\n\t * @param rabbitProperties properties to use\n\t */\n\tpublic DirectRabbitListenerContainerFactoryConfigurer(RabbitProperties rabbitProperties) {\n\t\tsuper(rabbitProperties);\n\t}\n\n\t@Override\n\tpublic void configure(DirectRabbitListenerContainerFactory factory, ConnectionFactory connectionFactory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRabbitProperties.DirectContainer config = getRabbitProperties().getListener().getDirect();\n\t\tconfigure(factory, connectionFactory, config);\n\t\tmap.from(config::getConsumersPerQueue).to(factory::setConsumersPerQueue);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/EnvironmentBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport com.rabbitmq.stream.Environment;\nimport com.rabbitmq.stream.EnvironmentBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link EnvironmentBuilder} to fine-tune its auto-configuration before it creates an\n * {@link Environment}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface EnvironmentBuilderCustomizer {\n\n\t/**\n\t * Customize the {@code EnvironmentBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(EnvironmentBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/PropertiesRabbitConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Adapts {@link RabbitProperties} to {@link RabbitConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass PropertiesRabbitConnectionDetails implements RabbitConnectionDetails {\n\n\tprivate final RabbitProperties properties;\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\tPropertiesRabbitConnectionDetails(RabbitProperties properties, @Nullable SslBundles sslBundles) {\n\t\tthis.properties = properties;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic String getUsername() {\n\t\treturn this.properties.determineUsername();\n\t}\n\n\t@Override\n\tpublic @Nullable String getPassword() {\n\t\treturn this.properties.determinePassword();\n\t}\n\n\t@Override\n\tpublic @Nullable String getVirtualHost() {\n\t\treturn this.properties.determineVirtualHost();\n\t}\n\n\t@Override\n\tpublic List<Address> getAddresses() {\n\t\tList<Address> addresses = new ArrayList<>();\n\t\tfor (String address : this.properties.determineAddresses()) {\n\t\t\tint portSeparatorIndex = address.lastIndexOf(':');\n\t\t\tString host = address.substring(0, portSeparatorIndex);\n\t\t\tString port = address.substring(portSeparatorIndex + 1);\n\t\t\taddresses.add(new Address(host, Integer.parseInt(port)));\n\t\t}\n\t\treturn addresses;\n\t}\n\n\t@Override\n\tpublic @Nullable SslBundle getSslBundle() {\n\t\tSsl ssl = this.properties.getSsl();\n\t\tif (!ssl.determineEnabled()) {\n\t\t\treturn null;\n\t\t}\n\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitAnnotationDrivenConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.springframework.amqp.rabbit.annotation.EnableRabbit;\nimport org.springframework.amqp.rabbit.config.ContainerCustomizer;\nimport org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;\nimport org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;\nimport org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;\nimport org.springframework.amqp.rabbit.retry.MessageRecoverer;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitListenerObservationConvention;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\n\n/**\n * Configuration for Spring AMQP annotation driven endpoints.\n *\n * @author Stephane Nicoll\n * @author Josh Thornhill\n * @author Moritz Halbritter\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(EnableRabbit.class)\nclass RabbitAnnotationDrivenConfiguration {\n\n\tprivate final ObjectProvider<MessageConverter> messageConverter;\n\n\tprivate final ObjectProvider<MessageRecoverer> messageRecoverer;\n\n\tprivate final ObjectProvider<RabbitListenerRetrySettingsCustomizer> retrySettingsCustomizers;\n\n\tprivate final RabbitProperties properties;\n\n\tprivate final ObjectProvider<RabbitListenerObservationConvention> observationConvention;\n\n\tRabbitAnnotationDrivenConfiguration(ObjectProvider<MessageConverter> messageConverter,\n\t\t\tObjectProvider<MessageRecoverer> messageRecoverer,\n\t\t\tObjectProvider<RabbitListenerRetrySettingsCustomizer> retrySettingsCustomizers,\n\t\t\tObjectProvider<RabbitListenerObservationConvention> observationConvention, RabbitProperties properties) {\n\t\tthis.messageConverter = messageConverter;\n\t\tthis.messageRecoverer = messageRecoverer;\n\t\tthis.retrySettingsCustomizers = retrySettingsCustomizers;\n\t\tthis.observationConvention = observationConvention;\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tSimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContainerFactoryConfigurer() {\n\t\treturn simpleListenerConfigurer();\n\t}\n\n\t@Bean(name = \"simpleRabbitListenerContainerFactoryConfigurer\")\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tSimpleRabbitListenerContainerFactoryConfigurer simpleRabbitListenerContainerFactoryConfigurerVirtualThreads() {\n\t\tSimpleRabbitListenerContainerFactoryConfigurer configurer = simpleListenerConfigurer();\n\t\tconfigurer.setTaskExecutor(new VirtualThreadTaskExecutor(\"rabbit-simple-\"));\n\t\treturn configurer;\n\t}\n\n\t@Bean(name = \"rabbitListenerContainerFactory\")\n\t@ConditionalOnMissingBean(name = \"rabbitListenerContainerFactory\")\n\t@ConditionalOnProperty(name = \"spring.rabbitmq.listener.type\", havingValue = \"simple\", matchIfMissing = true)\n\tSimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(\n\t\t\tSimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,\n\t\t\tObjectProvider<ContainerCustomizer<SimpleMessageListenerContainer>> simpleContainerCustomizer) {\n\t\tSimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();\n\t\tconfigurer.configure(factory, connectionFactory);\n\t\tsimpleContainerCustomizer.ifUnique(factory::setContainerCustomizer);\n\t\treturn factory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tDirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContainerFactoryConfigurer() {\n\t\treturn directListenerConfigurer();\n\t}\n\n\t@Bean(name = \"directRabbitListenerContainerFactoryConfigurer\")\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tDirectRabbitListenerContainerFactoryConfigurer directRabbitListenerContainerFactoryConfigurerVirtualThreads() {\n\t\tDirectRabbitListenerContainerFactoryConfigurer configurer = directListenerConfigurer();\n\t\tconfigurer.setTaskExecutor(new VirtualThreadTaskExecutor(\"rabbit-direct-\"));\n\t\treturn configurer;\n\t}\n\n\t@Bean(name = \"rabbitListenerContainerFactory\")\n\t@ConditionalOnMissingBean(name = \"rabbitListenerContainerFactory\")\n\t@ConditionalOnProperty(name = \"spring.rabbitmq.listener.type\", havingValue = \"direct\")\n\tDirectRabbitListenerContainerFactory directRabbitListenerContainerFactory(\n\t\t\tDirectRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory,\n\t\t\tObjectProvider<ContainerCustomizer<DirectMessageListenerContainer>> directContainerCustomizer) {\n\t\tDirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();\n\t\tconfigurer.configure(factory, connectionFactory);\n\t\tdirectContainerCustomizer.ifUnique(factory::setContainerCustomizer);\n\t\treturn factory;\n\t}\n\n\tprivate SimpleRabbitListenerContainerFactoryConfigurer simpleListenerConfigurer() {\n\t\tSimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer(\n\t\t\t\tthis.properties);\n\t\tconfigurer.setMessageConverter(this.messageConverter.getIfUnique());\n\t\tconfigurer.setMessageRecoverer(this.messageRecoverer.getIfUnique());\n\t\tconfigurer.setObservationConvention(this.observationConvention.getIfUnique());\n\t\tconfigurer.setRetrySettingsCustomizers(this.retrySettingsCustomizers.orderedStream().toList());\n\t\treturn configurer;\n\t}\n\n\tprivate DirectRabbitListenerContainerFactoryConfigurer directListenerConfigurer() {\n\t\tDirectRabbitListenerContainerFactoryConfigurer configurer = new DirectRabbitListenerContainerFactoryConfigurer(\n\t\t\t\tthis.properties);\n\t\tconfigurer.setMessageConverter(this.messageConverter.getIfUnique());\n\t\tconfigurer.setMessageRecoverer(this.messageRecoverer.getIfUnique());\n\t\tconfigurer.setObservationConvention(this.observationConvention.getIfUnique());\n\t\tconfigurer.setRetrySettingsCustomizers(this.retrySettingsCustomizers.orderedStream().toList());\n\t\treturn configurer;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableRabbit\n\t@ConditionalOnMissingBean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)\n\tstatic class EnableRabbitConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.impl.CredentialsProvider;\nimport com.rabbitmq.client.impl.CredentialsRefreshService;\n\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;\nimport org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;\nimport org.springframework.amqp.rabbit.core.RabbitAdmin;\nimport org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;\nimport org.springframework.amqp.rabbit.core.RabbitOperations;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitTemplateObservationConvention;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitTemplate}.\n * <p>\n * This configuration class is active only when the RabbitMQ and Spring AMQP client\n * libraries are on the classpath.\n * <p>\n * Registers the following beans:\n * <ul>\n * <li>{@link org.springframework.amqp.rabbit.core.RabbitTemplate RabbitTemplate} if there\n * is no other bean of the same type in the context.</li>\n * <li>{@link org.springframework.amqp.rabbit.connection.CachingConnectionFactory\n * CachingConnectionFactory} instance if there is no other bean of the same type in the\n * context.</li>\n * <li>{@link org.springframework.amqp.core.AmqpAdmin } instance as long as\n * {@literal spring.rabbitmq.dynamic=true}.</li>\n * </ul>\n *\n * @author Greg Turnquist\n * @author Josh Long\n * @author Stephane Nicoll\n * @author Gary Russell\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ RabbitTemplate.class, Channel.class })\n@EnableConfigurationProperties(RabbitProperties.class)\n@Import({ RabbitAnnotationDrivenConfiguration.class, RabbitStreamConfiguration.class })\npublic final class RabbitAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class RabbitConnectionFactoryCreator {\n\n\t\tprivate final RabbitProperties properties;\n\n\t\tprotected RabbitConnectionFactoryCreator(RabbitProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tRabbitConnectionDetails rabbitConnectionDetails(ObjectProvider<SslBundles> sslBundles) {\n\t\t\treturn new PropertiesRabbitConnectionDetails(this.properties, sslBundles.getIfAvailable());\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tRabbitConnectionFactoryBeanConfigurer rabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader,\n\t\t\t\tRabbitConnectionDetails connectionDetails, ObjectProvider<CredentialsProvider> credentialsProvider,\n\t\t\t\tObjectProvider<CredentialsRefreshService> credentialsRefreshService) {\n\t\t\tRabbitConnectionFactoryBeanConfigurer configurer = new RabbitConnectionFactoryBeanConfigurer(resourceLoader,\n\t\t\t\t\tthis.properties, connectionDetails);\n\t\t\tconfigurer.setCredentialsProvider(credentialsProvider.getIfUnique());\n\t\t\tconfigurer.setCredentialsRefreshService(credentialsRefreshService.getIfUnique());\n\t\t\treturn configurer;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tCachingConnectionFactoryConfigurer rabbitConnectionFactoryConfigurer(RabbitConnectionDetails connectionDetails,\n\t\t\t\tObjectProvider<ConnectionNameStrategy> connectionNameStrategy) {\n\t\t\tCachingConnectionFactoryConfigurer configurer = new CachingConnectionFactoryConfigurer(this.properties,\n\t\t\t\t\tconnectionDetails);\n\t\t\tconfigurer.setConnectionNameStrategy(connectionNameStrategy.getIfUnique());\n\t\t\treturn configurer;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ConnectionFactory.class)\n\t\tCachingConnectionFactory rabbitConnectionFactory(\n\t\t\t\tRabbitConnectionFactoryBeanConfigurer rabbitConnectionFactoryBeanConfigurer,\n\t\t\t\tCachingConnectionFactoryConfigurer rabbitCachingConnectionFactoryConfigurer,\n\t\t\t\tObjectProvider<ConnectionFactoryCustomizer> connectionFactoryCustomizers) throws Exception {\n\t\t\tRabbitConnectionFactoryBean connectionFactoryBean = new SslBundleRabbitConnectionFactoryBean();\n\t\t\trabbitConnectionFactoryBeanConfigurer.configure(connectionFactoryBean);\n\t\t\tconnectionFactoryBean.afterPropertiesSet();\n\t\t\tcom.rabbitmq.client.ConnectionFactory connectionFactory = connectionFactoryBean.getObject();\n\t\t\tconnectionFactoryCustomizers.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(connectionFactory));\n\t\t\tCachingConnectionFactory factory = new CachingConnectionFactory(connectionFactory);\n\t\t\trabbitCachingConnectionFactoryConfigurer.configure(factory);\n\t\t\treturn factory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(RabbitConnectionFactoryCreator.class)\n\tprotected static class RabbitTemplateConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tRabbitTemplateConfigurer rabbitTemplateConfigurer(RabbitProperties properties,\n\t\t\t\tObjectProvider<MessageConverter> messageConverter,\n\t\t\t\tObjectProvider<RabbitTemplateRetrySettingsCustomizer> retrySettingsCustomizers,\n\t\t\t\tObjectProvider<RabbitTemplateObservationConvention> observationConvention) {\n\t\t\tRabbitTemplateConfigurer configurer = new RabbitTemplateConfigurer(properties);\n\t\t\tconfigurer.setMessageConverter(messageConverter.getIfUnique());\n\t\t\tconfigurer.setRetrySettingsCustomizers(retrySettingsCustomizers.orderedStream().toList());\n\t\t\tconfigurer.setObservationConvention(observationConvention.getIfUnique());\n\t\t\treturn configurer;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(ConnectionFactory.class)\n\t\t@ConditionalOnMissingBean(RabbitOperations.class)\n\t\tRabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory,\n\t\t\t\tObjectProvider<RabbitTemplateCustomizer> customizers) {\n\t\t\tRabbitTemplate template = new RabbitTemplate();\n\t\t\tconfigurer.configure(template, connectionFactory);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(template));\n\t\t\treturn template;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(ConnectionFactory.class)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.rabbitmq.dynamic\", matchIfMissing = true)\n\t\t@ConditionalOnMissingBean\n\t\tAmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {\n\t\t\treturn new RabbitAdmin(connectionFactory);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(RabbitMessagingTemplate.class)\n\t@ConditionalOnMissingBean(RabbitMessagingTemplate.class)\n\t@Import(RabbitTemplateConfiguration.class)\n\tprotected static class RabbitMessagingTemplateConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(RabbitTemplate.class)\n\t\tRabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {\n\t\t\treturn new RabbitMessagingTemplate(rabbitTemplate);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.util.Assert;\n\n/**\n * Details required to establish a connection to a RabbitMQ service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface RabbitConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Login user to authenticate to the broker.\n\t * @return the login user to authenticate to the broker or {@code null}\n\t */\n\tdefault @Nullable String getUsername() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Login to authenticate against the broker.\n\t * @return the login to authenticate against the broker or {@code null}\n\t */\n\tdefault @Nullable String getPassword() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Virtual host to use when connecting to the broker.\n\t * @return the virtual host to use when connecting to the broker or {@code null}\n\t */\n\tdefault @Nullable String getVirtualHost() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * List of addresses to which the client should connect. Must return at least one\n\t * address.\n\t * @return the list of addresses to which the client should connect\n\t */\n\tList<Address> getAddresses();\n\n\t/**\n\t * Returns the first address.\n\t * @return the first address\n\t * @throws IllegalStateException if the address list is empty\n\t */\n\tdefault Address getFirstAddress() {\n\t\tList<Address> addresses = getAddresses();\n\t\tAssert.state(!addresses.isEmpty(), \"Address list is empty\");\n\t\treturn addresses.get(0);\n\t}\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * A RabbitMQ address.\n\t *\n\t * @param host the host\n\t * @param port the port\n\t */\n\trecord Address(String host, int port) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitConnectionFactoryBeanConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.time.Duration;\n\nimport com.rabbitmq.client.impl.CredentialsProvider;\nimport com.rabbitmq.client.impl.CredentialsRefreshService;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails.Address;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Configures {@link RabbitConnectionFactoryBean} with sensible defaults tuned using\n * configuration properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code RabbitConnectionFactoryBean} whose configuration is based upon that produced by\n * auto-configuration.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class RabbitConnectionFactoryBeanConfigurer {\n\n\tprivate final RabbitProperties rabbitProperties;\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final RabbitConnectionDetails connectionDetails;\n\n\tprivate @Nullable CredentialsProvider credentialsProvider;\n\n\tprivate @Nullable CredentialsRefreshService credentialsRefreshService;\n\n\t/**\n\t * Creates a new configurer that will use the given {@code resourceLoader} and\n\t * {@code properties}.\n\t * @param resourceLoader the resource loader\n\t * @param properties the properties\n\t */\n\tpublic RabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader, RabbitProperties properties) {\n\t\tthis(resourceLoader, properties, new PropertiesRabbitConnectionDetails(properties, null));\n\t}\n\n\t/**\n\t * Creates a new configurer that will use the given {@code resourceLoader},\n\t * {@code properties}, and {@code connectionDetails}. The connection details have\n\t * priority over the properties.\n\t * @param resourceLoader the resource loader\n\t * @param properties the properties\n\t * @param connectionDetails the connection details\n\t */\n\tpublic RabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader, RabbitProperties properties,\n\t\t\tRabbitConnectionDetails connectionDetails) {\n\t\tthis(resourceLoader, properties, connectionDetails, null);\n\t}\n\n\t/**\n\t * Creates a new configurer that will use the given {@code resourceLoader},\n\t * {@code properties}, {@code connectionDetails}, and {@code sslBundles}. The\n\t * connection details have priority over the properties.\n\t * @param resourceLoader the resource loader\n\t * @param properties the properties\n\t * @param connectionDetails the connection details\n\t * @param sslBundles the SSL bundles\n\t */\n\tpublic RabbitConnectionFactoryBeanConfigurer(ResourceLoader resourceLoader, RabbitProperties properties,\n\t\t\tRabbitConnectionDetails connectionDetails, @Nullable SslBundles sslBundles) {\n\t\tAssert.notNull(resourceLoader, \"'resourceLoader' must not be null\");\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tAssert.notNull(connectionDetails, \"'connectionDetails' must not be null\");\n\t\tthis.resourceLoader = resourceLoader;\n\t\tthis.rabbitProperties = properties;\n\t\tthis.connectionDetails = connectionDetails;\n\t}\n\n\tpublic void setCredentialsProvider(@Nullable CredentialsProvider credentialsProvider) {\n\t\tthis.credentialsProvider = credentialsProvider;\n\t}\n\n\tpublic void setCredentialsRefreshService(@Nullable CredentialsRefreshService credentialsRefreshService) {\n\t\tthis.credentialsRefreshService = credentialsRefreshService;\n\t}\n\n\t/**\n\t * Configure the specified rabbit connection factory bean. The factory bean can be\n\t * further tuned and default settings can be overridden. It is the responsibility of\n\t * the caller to invoke {@link RabbitConnectionFactoryBean#afterPropertiesSet()}\n\t * though.\n\t * @param factory the {@link RabbitConnectionFactoryBean} instance to configure\n\t */\n\tpublic void configure(RabbitConnectionFactoryBean factory) {\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\tfactory.setResourceLoader(this.resourceLoader);\n\t\tAddress address = this.connectionDetails.getFirstAddress();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(address::host).to(factory::setHost);\n\t\tmap.from(address::port).to(factory::setPort);\n\t\tmap.from(this.connectionDetails::getUsername).to(factory::setUsername);\n\t\tmap.from(this.connectionDetails::getPassword).to(factory::setPassword);\n\t\tmap.from(this.connectionDetails::getVirtualHost).to(factory::setVirtualHost);\n\t\tmap.from(this.rabbitProperties::getRequestedHeartbeat)\n\t\t\t.asInt(Duration::getSeconds)\n\t\t\t.to(factory::setRequestedHeartbeat);\n\t\tmap.from(this.rabbitProperties::getRequestedChannelMax).to(factory::setRequestedChannelMax);\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tif (sslBundle != null) {\n\t\t\tapplySslBundle(factory, sslBundle);\n\t\t}\n\t\telse {\n\t\t\tRabbitProperties.Ssl ssl = this.rabbitProperties.getSsl();\n\t\t\tif (ssl.determineEnabled()) {\n\t\t\t\tfactory.setUseSSL(true);\n\t\t\t\tmap.from(ssl::getAlgorithm).to(factory::setSslAlgorithm);\n\t\t\t\tmap.from(ssl::getKeyStoreType).to(factory::setKeyStoreType);\n\t\t\t\tmap.from(ssl::getKeyStore).to(factory::setKeyStore);\n\t\t\t\tmap.from(ssl::getKeyStorePassword).to(factory::setKeyStorePassphrase);\n\t\t\t\tmap.from(ssl::getKeyStoreAlgorithm).to(factory::setKeyStoreAlgorithm);\n\t\t\t\tmap.from(ssl::getTrustStoreType).to(factory::setTrustStoreType);\n\t\t\t\tmap.from(ssl::getTrustStore).to(factory::setTrustStore);\n\t\t\t\tmap.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase);\n\t\t\t\tmap.from(ssl::getTrustStoreAlgorithm).to(factory::setTrustStoreAlgorithm);\n\t\t\t\tmap.from(ssl::isValidateServerCertificate)\n\t\t\t\t\t.to((validate) -> factory.setSkipServerCertificateValidation(!validate));\n\t\t\t\tmap.from(ssl::isVerifyHostname).to(factory::setEnableHostnameVerification);\n\t\t\t}\n\t\t}\n\t\tmap.from(this.rabbitProperties::getConnectionTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to(factory::setConnectionTimeout);\n\t\tmap.from(this.rabbitProperties::getChannelRpcTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to(factory::setChannelRpcTimeout);\n\t\tmap.from(this.credentialsProvider).to(factory::setCredentialsProvider);\n\t\tmap.from(this.credentialsRefreshService).to(factory::setCredentialsRefreshService);\n\t\tmap.from(this.rabbitProperties.getMaxInboundMessageBodySize())\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.to(factory::setMaxInboundMessageBodySize);\n\t}\n\n\tprivate static void applySslBundle(RabbitConnectionFactoryBean factory, SslBundle bundle) {\n\t\tfactory.setUseSSL(true);\n\t\tif (factory instanceof SslBundleRabbitConnectionFactoryBean sslFactory) {\n\t\t\tsslFactory.setSslBundle(bundle);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitListenerRetrySettingsCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.springframework.boot.retry.RetryPolicySettings;\nimport org.springframework.core.retry.RetryPolicy;\n\n/**\n * Callback interface that can be used to customize {@linkplain RetryPolicySettings retry\n * settings} used by message listeners.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see RetryPolicy\n */\n@FunctionalInterface\npublic interface RabbitListenerRetrySettingsCustomizer {\n\n\t/**\n\t * Callback to customize the {@link RetryPolicySettings} to create the\n\t * {@link RetryPolicy} used by message listeners.\n\t * @param retrySettings the settings to customize\n\t */\n\tvoid customize(RetryPolicySettings retrySettings);\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.core.AcknowledgeMode;\nimport org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.AddressShuffleMode;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory.CacheMode;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory.ConfirmType;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.boot.retry.RetryPolicySettings;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Configuration properties for Rabbit.\n *\n * @author Greg Turnquist\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Josh Thornhill\n * @author Gary Russell\n * @author Artsiom Yudovin\n * @author Franjo Zilic\n * @author Eddú Meléndez\n * @author Rafael Carvalho\n * @author Scott Frederick\n * @author Lasse Wulff\n * @author Yanming Zhou\n * @author Jay Choi\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.rabbitmq\")\npublic class RabbitProperties {\n\n\tprivate static final int DEFAULT_PORT = 5672;\n\n\tprivate static final int DEFAULT_PORT_SECURE = 5671;\n\n\tprivate static final int DEFAULT_STREAM_PORT = 5552;\n\n\t/**\n\t * RabbitMQ host. Ignored if an address is set.\n\t */\n\tprivate String host = \"localhost\";\n\n\t/**\n\t * RabbitMQ port. Ignored if an address is set. Default to 5672, or 5671 if SSL is\n\t * enabled.\n\t */\n\tprivate @Nullable Integer port;\n\n\t/**\n\t * Login user to authenticate to the broker.\n\t */\n\tprivate String username = \"guest\";\n\n\t/**\n\t * Login to authenticate against the broker.\n\t */\n\tprivate String password = \"guest\";\n\n\t/**\n\t * SSL configuration.\n\t */\n\tprivate final Ssl ssl = new Ssl();\n\n\t/**\n\t * Virtual host to use when connecting to the broker.\n\t */\n\tprivate @Nullable String virtualHost;\n\n\t/**\n\t * List of addresses to which the client should connect. When set, the host and port\n\t * are ignored.\n\t */\n\tprivate @Nullable List<String> addresses;\n\n\t/**\n\t * Mode used to shuffle configured addresses.\n\t */\n\tprivate AddressShuffleMode addressShuffleMode = AddressShuffleMode.NONE;\n\n\t/**\n\t * Requested heartbeat timeout; zero for none. If a duration suffix is not specified,\n\t * seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate @Nullable Duration requestedHeartbeat;\n\n\t/**\n\t * Number of channels per connection requested by the client. Use 0 for unlimited.\n\t */\n\tprivate int requestedChannelMax = 2047;\n\n\t/**\n\t * Whether to enable publisher returns.\n\t */\n\tprivate boolean publisherReturns;\n\n\t/**\n\t * Type of publisher confirms to use.\n\t */\n\tprivate @Nullable ConfirmType publisherConfirmType;\n\n\t/**\n\t * Connection timeout. Set it to zero to wait forever.\n\t */\n\tprivate @Nullable Duration connectionTimeout;\n\n\t/**\n\t * Continuation timeout for RPC calls in channels. Set it to zero to wait forever.\n\t */\n\tprivate Duration channelRpcTimeout = Duration.ofMinutes(10);\n\n\t/**\n\t * Maximum size of the body of inbound (received) messages.\n\t */\n\tprivate DataSize maxInboundMessageBodySize = DataSize.ofMegabytes(64);\n\n\t/**\n\t * Cache configuration.\n\t */\n\tprivate final Cache cache = new Cache();\n\n\t/**\n\t * Listener container configuration.\n\t */\n\tprivate final Listener listener = new Listener();\n\n\tprivate final Template template = new Template();\n\n\tprivate final Stream stream = new Stream();\n\n\tprivate @Nullable List<Address> parsedAddresses;\n\n\tpublic String getHost() {\n\t\treturn this.host;\n\t}\n\n\t/**\n\t * Returns the host from the first address, or the configured host if no addresses\n\t * have been set.\n\t * @return the host\n\t * @see #setAddresses(List)\n\t * @see #getHost()\n\t */\n\tpublic String determineHost() {\n\t\tif (CollectionUtils.isEmpty(this.parsedAddresses)) {\n\t\t\treturn getHost();\n\t\t}\n\t\treturn this.parsedAddresses.get(0).host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic @Nullable Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\t/**\n\t * Returns the port from the first address, or the configured port if no addresses\n\t * have been set.\n\t * @return the port\n\t * @see #setAddresses(List)\n\t * @see #getPort()\n\t */\n\tpublic int determinePort() {\n\t\tif (CollectionUtils.isEmpty(this.parsedAddresses)) {\n\t\t\tInteger port = getPort();\n\t\t\tif (port != null) {\n\t\t\t\treturn port;\n\t\t\t}\n\t\t\treturn Boolean.TRUE.equals(getSsl().getEnabled()) ? DEFAULT_PORT_SECURE : DEFAULT_PORT;\n\t\t}\n\t\treturn this.parsedAddresses.get(0).port;\n\t}\n\n\tpublic void setPort(@Nullable Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable List<String> getAddresses() {\n\t\treturn this.addresses;\n\t}\n\n\t/**\n\t * Returns the configured addresses or a single address ({@code host:port}) created\n\t * from the configured host and port if no addresses have been set.\n\t * @return the addresses\n\t */\n\tpublic List<String> determineAddresses() {\n\t\tif (CollectionUtils.isEmpty(this.parsedAddresses)) {\n\t\t\tif (this.host.contains(\",\")) {\n\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"spring.rabbitmq.host\", this.host,\n\t\t\t\t\t\t\"Invalid character ','. Value must be a single host. For multiple hosts, use property 'spring.rabbitmq.addresses' instead.\");\n\t\t\t}\n\t\t\treturn List.of(this.host + \":\" + determinePort());\n\t\t}\n\t\tList<String> addressStrings = new ArrayList<>();\n\t\tfor (Address parsedAddress : this.parsedAddresses) {\n\t\t\taddressStrings.add(parsedAddress.host + \":\" + parsedAddress.port);\n\t\t}\n\t\treturn addressStrings;\n\t}\n\n\tpublic void setAddresses(List<String> addresses) {\n\t\tthis.addresses = addresses;\n\t\tthis.parsedAddresses = parseAddresses(addresses);\n\t}\n\n\tprivate List<Address> parseAddresses(List<String> addresses) {\n\t\tList<Address> parsedAddresses = new ArrayList<>();\n\t\tfor (String address : addresses) {\n\t\t\tparsedAddresses.add(new Address(address, Boolean.TRUE.equals(getSsl().getEnabled())));\n\t\t}\n\t\treturn parsedAddresses;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn this.username;\n\t}\n\n\t/**\n\t * If addresses have been set and the first address has a username it is returned.\n\t * Otherwise returns the result of calling {@code getUsername()}.\n\t * @return the username\n\t * @see #setAddresses(List)\n\t * @see #getUsername()\n\t */\n\tpublic String determineUsername() {\n\t\tif (CollectionUtils.isEmpty(this.parsedAddresses)) {\n\t\t\treturn this.username;\n\t\t}\n\t\tAddress address = this.parsedAddresses.get(0);\n\t\treturn (address.username != null) ? address.username : this.username;\n\t}\n\n\tpublic void setUsername(String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic String getPassword() {\n\t\treturn this.password;\n\t}\n\n\t/**\n\t * If addresses have been set and the first address has a password it is returned.\n\t * Otherwise returns the result of calling {@code getPassword()}.\n\t * @return the password or {@code null}\n\t * @see #setAddresses(List)\n\t * @see #getPassword()\n\t */\n\tpublic @Nullable String determinePassword() {\n\t\tif (CollectionUtils.isEmpty(this.parsedAddresses)) {\n\t\t\treturn getPassword();\n\t\t}\n\t\tAddress address = this.parsedAddresses.get(0);\n\t\treturn (address.password != null) ? address.password : getPassword();\n\t}\n\n\tpublic void setPassword(String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic @Nullable String getVirtualHost() {\n\t\treturn this.virtualHost;\n\t}\n\n\t/**\n\t * If addresses have been set and the first address has a virtual host it is returned.\n\t * Otherwise returns the result of calling {@code getVirtualHost()}.\n\t * @return the virtual host or {@code null}\n\t * @see #setAddresses(List)\n\t * @see #getVirtualHost()\n\t */\n\tpublic @Nullable String determineVirtualHost() {\n\t\tif (CollectionUtils.isEmpty(this.parsedAddresses)) {\n\t\t\treturn getVirtualHost();\n\t\t}\n\t\tAddress address = this.parsedAddresses.get(0);\n\t\treturn (address.virtualHost != null) ? address.virtualHost : getVirtualHost();\n\t}\n\n\tpublic void setVirtualHost(@Nullable String virtualHost) {\n\t\tthis.virtualHost = StringUtils.hasText(virtualHost) ? virtualHost : \"/\";\n\t}\n\n\tpublic AddressShuffleMode getAddressShuffleMode() {\n\t\treturn this.addressShuffleMode;\n\t}\n\n\tpublic void setAddressShuffleMode(AddressShuffleMode addressShuffleMode) {\n\t\tthis.addressShuffleMode = addressShuffleMode;\n\t}\n\n\tpublic @Nullable Duration getRequestedHeartbeat() {\n\t\treturn this.requestedHeartbeat;\n\t}\n\n\tpublic void setRequestedHeartbeat(@Nullable Duration requestedHeartbeat) {\n\t\tthis.requestedHeartbeat = requestedHeartbeat;\n\t}\n\n\tpublic int getRequestedChannelMax() {\n\t\treturn this.requestedChannelMax;\n\t}\n\n\tpublic void setRequestedChannelMax(int requestedChannelMax) {\n\t\tthis.requestedChannelMax = requestedChannelMax;\n\t}\n\n\tpublic boolean isPublisherReturns() {\n\t\treturn this.publisherReturns;\n\t}\n\n\tpublic void setPublisherReturns(boolean publisherReturns) {\n\t\tthis.publisherReturns = publisherReturns;\n\t}\n\n\tpublic @Nullable Duration getConnectionTimeout() {\n\t\treturn this.connectionTimeout;\n\t}\n\n\tpublic void setPublisherConfirmType(@Nullable ConfirmType publisherConfirmType) {\n\t\tthis.publisherConfirmType = publisherConfirmType;\n\t}\n\n\tpublic @Nullable ConfirmType getPublisherConfirmType() {\n\t\treturn this.publisherConfirmType;\n\t}\n\n\tpublic void setConnectionTimeout(@Nullable Duration connectionTimeout) {\n\t\tthis.connectionTimeout = connectionTimeout;\n\t}\n\n\tpublic Duration getChannelRpcTimeout() {\n\t\treturn this.channelRpcTimeout;\n\t}\n\n\tpublic void setChannelRpcTimeout(Duration channelRpcTimeout) {\n\t\tthis.channelRpcTimeout = channelRpcTimeout;\n\t}\n\n\tpublic DataSize getMaxInboundMessageBodySize() {\n\t\treturn this.maxInboundMessageBodySize;\n\t}\n\n\tpublic void setMaxInboundMessageBodySize(DataSize maxInboundMessageBodySize) {\n\t\tthis.maxInboundMessageBodySize = maxInboundMessageBodySize;\n\t}\n\n\tpublic Cache getCache() {\n\t\treturn this.cache;\n\t}\n\n\tpublic Listener getListener() {\n\t\treturn this.listener;\n\t}\n\n\tpublic Template getTemplate() {\n\t\treturn this.template;\n\t}\n\n\tpublic Stream getStream() {\n\t\treturn this.stream;\n\t}\n\n\tpublic class Ssl {\n\n\t\tprivate static final String SUN_X509 = \"SunX509\";\n\n\t\t/**\n\t\t * Whether to enable SSL support. Determined automatically if an address is\n\t\t * provided with the protocol (amqp:// vs. amqps://).\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\t/**\n\t\t * Path to the key store that holds the SSL certificate.\n\t\t */\n\t\tprivate @Nullable String keyStore;\n\n\t\t/**\n\t\t * Key store type.\n\t\t */\n\t\tprivate String keyStoreType = \"PKCS12\";\n\n\t\t/**\n\t\t * Password used to access the key store.\n\t\t */\n\t\tprivate @Nullable String keyStorePassword;\n\n\t\t/**\n\t\t * Key store algorithm.\n\t\t */\n\t\tprivate String keyStoreAlgorithm = SUN_X509;\n\n\t\t/**\n\t\t * Trust store that holds SSL certificates.\n\t\t */\n\t\tprivate @Nullable String trustStore;\n\n\t\t/**\n\t\t * Trust store type.\n\t\t */\n\t\tprivate String trustStoreType = \"JKS\";\n\n\t\t/**\n\t\t * Password used to access the trust store.\n\t\t */\n\t\tprivate @Nullable String trustStorePassword;\n\n\t\t/**\n\t\t * Trust store algorithm.\n\t\t */\n\t\tprivate String trustStoreAlgorithm = SUN_X509;\n\n\t\t/**\n\t\t * SSL algorithm to use. By default, configured by the Rabbit client library.\n\t\t */\n\t\tprivate @Nullable String algorithm;\n\n\t\t/**\n\t\t * Whether to enable server side certificate validation.\n\t\t */\n\t\tprivate boolean validateServerCertificate = true;\n\n\t\t/**\n\t\t * Whether to enable hostname verification.\n\t\t */\n\t\tprivate boolean verifyHostname = true;\n\n\t\tpublic @Nullable Boolean getEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\t/**\n\t\t * Returns whether SSL is enabled from the first address, or the configured ssl\n\t\t * enabled flag if no addresses have been set.\n\t\t * @return whether ssl is enabled\n\t\t * @see #setAddresses(List)\n\t\t * @see #getEnabled() ()\n\t\t */\n\t\tpublic boolean determineEnabled() {\n\t\t\tboolean defaultEnabled = Boolean.TRUE.equals(getEnabled()) || this.bundle != null;\n\t\t\tif (CollectionUtils.isEmpty(RabbitProperties.this.parsedAddresses)) {\n\t\t\t\treturn defaultEnabled;\n\t\t\t}\n\t\t\tAddress address = RabbitProperties.this.parsedAddresses.get(0);\n\t\t\treturn address.determineSslEnabled(defaultEnabled);\n\t\t}\n\n\t\tpublic void setEnabled(@Nullable Boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t\tpublic @Nullable String getKeyStore() {\n\t\t\treturn this.keyStore;\n\t\t}\n\n\t\tpublic void setKeyStore(@Nullable String keyStore) {\n\t\t\tthis.keyStore = keyStore;\n\t\t}\n\n\t\tpublic String getKeyStoreType() {\n\t\t\treturn this.keyStoreType;\n\t\t}\n\n\t\tpublic void setKeyStoreType(String keyStoreType) {\n\t\t\tthis.keyStoreType = keyStoreType;\n\t\t}\n\n\t\tpublic @Nullable String getKeyStorePassword() {\n\t\t\treturn this.keyStorePassword;\n\t\t}\n\n\t\tpublic void setKeyStorePassword(@Nullable String keyStorePassword) {\n\t\t\tthis.keyStorePassword = keyStorePassword;\n\t\t}\n\n\t\tpublic String getKeyStoreAlgorithm() {\n\t\t\treturn this.keyStoreAlgorithm;\n\t\t}\n\n\t\tpublic void setKeyStoreAlgorithm(String keyStoreAlgorithm) {\n\t\t\tthis.keyStoreAlgorithm = keyStoreAlgorithm;\n\t\t}\n\n\t\tpublic @Nullable String getTrustStore() {\n\t\t\treturn this.trustStore;\n\t\t}\n\n\t\tpublic void setTrustStore(@Nullable String trustStore) {\n\t\t\tthis.trustStore = trustStore;\n\t\t}\n\n\t\tpublic String getTrustStoreType() {\n\t\t\treturn this.trustStoreType;\n\t\t}\n\n\t\tpublic void setTrustStoreType(String trustStoreType) {\n\t\t\tthis.trustStoreType = trustStoreType;\n\t\t}\n\n\t\tpublic @Nullable String getTrustStorePassword() {\n\t\t\treturn this.trustStorePassword;\n\t\t}\n\n\t\tpublic void setTrustStorePassword(@Nullable String trustStorePassword) {\n\t\t\tthis.trustStorePassword = trustStorePassword;\n\t\t}\n\n\t\tpublic String getTrustStoreAlgorithm() {\n\t\t\treturn this.trustStoreAlgorithm;\n\t\t}\n\n\t\tpublic void setTrustStoreAlgorithm(String trustStoreAlgorithm) {\n\t\t\tthis.trustStoreAlgorithm = trustStoreAlgorithm;\n\t\t}\n\n\t\tpublic @Nullable String getAlgorithm() {\n\t\t\treturn this.algorithm;\n\t\t}\n\n\t\tpublic void setAlgorithm(@Nullable String sslAlgorithm) {\n\t\t\tthis.algorithm = sslAlgorithm;\n\t\t}\n\n\t\tpublic boolean isValidateServerCertificate() {\n\t\t\treturn this.validateServerCertificate;\n\t\t}\n\n\t\tpublic void setValidateServerCertificate(boolean validateServerCertificate) {\n\t\t\tthis.validateServerCertificate = validateServerCertificate;\n\t\t}\n\n\t\tpublic boolean isVerifyHostname() {\n\t\t\treturn this.verifyHostname;\n\t\t}\n\n\t\tpublic void setVerifyHostname(boolean verifyHostname) {\n\t\t\tthis.verifyHostname = verifyHostname;\n\t\t}\n\n\t}\n\n\tpublic static class Cache {\n\n\t\tprivate final Channel channel = new Channel();\n\n\t\tprivate final Connection connection = new Connection();\n\n\t\tpublic Channel getChannel() {\n\t\t\treturn this.channel;\n\t\t}\n\n\t\tpublic Connection getConnection() {\n\t\t\treturn this.connection;\n\t\t}\n\n\t\tpublic static class Channel {\n\n\t\t\t/**\n\t\t\t * Number of channels to retain in the cache. When \"check-timeout\" > 0, max\n\t\t\t * channels per connection.\n\t\t\t */\n\t\t\tprivate @Nullable Integer size;\n\n\t\t\t/**\n\t\t\t * Duration to wait to obtain a channel if the cache size has been reached. If\n\t\t\t * 0, always create a new channel.\n\t\t\t */\n\t\t\tprivate @Nullable Duration checkoutTimeout;\n\n\t\t\tpublic @Nullable Integer getSize() {\n\t\t\t\treturn this.size;\n\t\t\t}\n\n\t\t\tpublic void setSize(@Nullable Integer size) {\n\t\t\t\tthis.size = size;\n\t\t\t}\n\n\t\t\tpublic @Nullable Duration getCheckoutTimeout() {\n\t\t\t\treturn this.checkoutTimeout;\n\t\t\t}\n\n\t\t\tpublic void setCheckoutTimeout(@Nullable Duration checkoutTimeout) {\n\t\t\t\tthis.checkoutTimeout = checkoutTimeout;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Connection {\n\n\t\t\t/**\n\t\t\t * Connection factory cache mode.\n\t\t\t */\n\t\t\tprivate CacheMode mode = CacheMode.CHANNEL;\n\n\t\t\t/**\n\t\t\t * Number of connections to cache. Only applies when mode is CONNECTION.\n\t\t\t */\n\t\t\tprivate @Nullable Integer size;\n\n\t\t\tpublic CacheMode getMode() {\n\t\t\t\treturn this.mode;\n\t\t\t}\n\n\t\t\tpublic void setMode(CacheMode mode) {\n\t\t\t\tthis.mode = mode;\n\t\t\t}\n\n\t\t\tpublic @Nullable Integer getSize() {\n\t\t\t\treturn this.size;\n\t\t\t}\n\n\t\t\tpublic void setSize(@Nullable Integer size) {\n\t\t\t\tthis.size = size;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic enum ContainerType {\n\n\t\t/**\n\t\t * Container where the RabbitMQ consumer dispatches messages to an invoker thread.\n\t\t */\n\t\tSIMPLE,\n\n\t\t/**\n\t\t * Container where the listener is invoked directly on the RabbitMQ consumer\n\t\t * thread.\n\t\t */\n\t\tDIRECT,\n\n\t\t/**\n\t\t * Container that uses the RabbitMQ Stream Client.\n\t\t */\n\t\tSTREAM\n\n\t}\n\n\tpublic static class Listener {\n\n\t\t/**\n\t\t * Listener container type.\n\t\t */\n\t\tprivate ContainerType type = ContainerType.SIMPLE;\n\n\t\tprivate final SimpleContainer simple = new SimpleContainer();\n\n\t\tprivate final DirectContainer direct = new DirectContainer();\n\n\t\tprivate final StreamContainer stream = new StreamContainer();\n\n\t\tpublic ContainerType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic void setType(ContainerType containerType) {\n\t\t\tthis.type = containerType;\n\t\t}\n\n\t\tpublic SimpleContainer getSimple() {\n\t\t\treturn this.simple;\n\t\t}\n\n\t\tpublic DirectContainer getDirect() {\n\t\t\treturn this.direct;\n\t\t}\n\n\t\tpublic StreamContainer getStream() {\n\t\t\treturn this.stream;\n\t\t}\n\n\t}\n\n\tpublic abstract static class BaseContainer {\n\n\t\t/**\n\t\t * Whether to enable observation.\n\t\t */\n\t\tprivate boolean observationEnabled;\n\n\t\tpublic boolean isObservationEnabled() {\n\t\t\treturn this.observationEnabled;\n\t\t}\n\n\t\tpublic void setObservationEnabled(boolean observationEnabled) {\n\t\t\tthis.observationEnabled = observationEnabled;\n\t\t}\n\n\t}\n\n\tpublic abstract static class AmqpContainer extends BaseContainer {\n\n\t\t/**\n\t\t * Whether to start the container automatically on startup.\n\t\t */\n\t\tprivate boolean autoStartup = true;\n\n\t\t/**\n\t\t * Acknowledge mode of container.\n\t\t */\n\t\tprivate @Nullable AcknowledgeMode acknowledgeMode;\n\n\t\t/**\n\t\t * Maximum number of unacknowledged messages that can be outstanding at each\n\t\t * consumer.\n\t\t */\n\t\tprivate @Nullable Integer prefetch;\n\n\t\t/**\n\t\t * Whether rejected deliveries are re-queued by default.\n\t\t */\n\t\tprivate @Nullable Boolean defaultRequeueRejected;\n\n\t\t/**\n\t\t * How often idle container events should be published.\n\t\t */\n\t\tprivate @Nullable Duration idleEventInterval;\n\n\t\t/**\n\t\t * Whether the container should present batched messages as discrete messages or\n\t\t * call the listener with the batch.\n\t\t */\n\t\tprivate boolean deBatchingEnabled = true;\n\n\t\t/**\n\t\t * Whether the container (when stopped) should stop immediately after processing\n\t\t * the current message or stop after processing all pre-fetched messages.\n\t\t */\n\t\tprivate boolean forceStop;\n\n\t\t/**\n\t\t * Optional properties for a retry interceptor.\n\t\t */\n\t\tprivate final ListenerRetry retry = new ListenerRetry();\n\n\t\tpublic boolean isAutoStartup() {\n\t\t\treturn this.autoStartup;\n\t\t}\n\n\t\tpublic void setAutoStartup(boolean autoStartup) {\n\t\t\tthis.autoStartup = autoStartup;\n\t\t}\n\n\t\tpublic @Nullable AcknowledgeMode getAcknowledgeMode() {\n\t\t\treturn this.acknowledgeMode;\n\t\t}\n\n\t\tpublic void setAcknowledgeMode(@Nullable AcknowledgeMode acknowledgeMode) {\n\t\t\tthis.acknowledgeMode = acknowledgeMode;\n\t\t}\n\n\t\tpublic @Nullable Integer getPrefetch() {\n\t\t\treturn this.prefetch;\n\t\t}\n\n\t\tpublic void setPrefetch(@Nullable Integer prefetch) {\n\t\t\tthis.prefetch = prefetch;\n\t\t}\n\n\t\tpublic @Nullable Boolean getDefaultRequeueRejected() {\n\t\t\treturn this.defaultRequeueRejected;\n\t\t}\n\n\t\tpublic void setDefaultRequeueRejected(@Nullable Boolean defaultRequeueRejected) {\n\t\t\tthis.defaultRequeueRejected = defaultRequeueRejected;\n\t\t}\n\n\t\tpublic @Nullable Duration getIdleEventInterval() {\n\t\t\treturn this.idleEventInterval;\n\t\t}\n\n\t\tpublic void setIdleEventInterval(@Nullable Duration idleEventInterval) {\n\t\t\tthis.idleEventInterval = idleEventInterval;\n\t\t}\n\n\t\tpublic abstract boolean isMissingQueuesFatal();\n\n\t\tpublic boolean isDeBatchingEnabled() {\n\t\t\treturn this.deBatchingEnabled;\n\t\t}\n\n\t\tpublic void setDeBatchingEnabled(boolean deBatchingEnabled) {\n\t\t\tthis.deBatchingEnabled = deBatchingEnabled;\n\t\t}\n\n\t\tpublic boolean isForceStop() {\n\t\t\treturn this.forceStop;\n\t\t}\n\n\t\tpublic void setForceStop(boolean forceStop) {\n\t\t\tthis.forceStop = forceStop;\n\t\t}\n\n\t\tpublic ListenerRetry getRetry() {\n\t\t\treturn this.retry;\n\t\t}\n\n\t}\n\n\t/**\n\t * Configuration properties for {@code SimpleMessageListenerContainer}.\n\t */\n\tpublic static class SimpleContainer extends AmqpContainer {\n\n\t\t/**\n\t\t * Minimum number of listener invoker threads.\n\t\t */\n\t\tprivate @Nullable Integer concurrency;\n\n\t\t/**\n\t\t * Maximum number of listener invoker threads.\n\t\t */\n\t\tprivate @Nullable Integer maxConcurrency;\n\n\t\t/**\n\t\t * Batch size, expressed as the number of physical messages, to be used by the\n\t\t * container.\n\t\t */\n\t\tprivate @Nullable Integer batchSize;\n\n\t\t/**\n\t\t * Whether to fail if the queues declared by the container are not available on\n\t\t * the broker and/or whether to stop the container if one or more queues are\n\t\t * deleted at runtime.\n\t\t */\n\t\tprivate boolean missingQueuesFatal = true;\n\n\t\t/**\n\t\t * Whether the container creates a batch of messages based on the\n\t\t * 'receive-timeout' and 'batch-size'. Coerces 'de-batching-enabled' to true to\n\t\t * include the contents of a producer created batch in the batch as discrete\n\t\t * records.\n\t\t */\n\t\tprivate boolean consumerBatchEnabled;\n\n\t\tpublic @Nullable Integer getConcurrency() {\n\t\t\treturn this.concurrency;\n\t\t}\n\n\t\tpublic void setConcurrency(@Nullable Integer concurrency) {\n\t\t\tthis.concurrency = concurrency;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxConcurrency() {\n\t\t\treturn this.maxConcurrency;\n\t\t}\n\n\t\tpublic void setMaxConcurrency(@Nullable Integer maxConcurrency) {\n\t\t\tthis.maxConcurrency = maxConcurrency;\n\t\t}\n\n\t\tpublic @Nullable Integer getBatchSize() {\n\t\t\treturn this.batchSize;\n\t\t}\n\n\t\tpublic void setBatchSize(@Nullable Integer batchSize) {\n\t\t\tthis.batchSize = batchSize;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isMissingQueuesFatal() {\n\t\t\treturn this.missingQueuesFatal;\n\t\t}\n\n\t\tpublic void setMissingQueuesFatal(boolean missingQueuesFatal) {\n\t\t\tthis.missingQueuesFatal = missingQueuesFatal;\n\t\t}\n\n\t\tpublic boolean isConsumerBatchEnabled() {\n\t\t\treturn this.consumerBatchEnabled;\n\t\t}\n\n\t\tpublic void setConsumerBatchEnabled(boolean consumerBatchEnabled) {\n\t\t\tthis.consumerBatchEnabled = consumerBatchEnabled;\n\t\t}\n\n\t}\n\n\t/**\n\t * Configuration properties for {@code DirectMessageListenerContainer}.\n\t */\n\tpublic static class DirectContainer extends AmqpContainer {\n\n\t\t/**\n\t\t * Number of consumers per queue.\n\t\t */\n\t\tprivate @Nullable Integer consumersPerQueue;\n\n\t\t/**\n\t\t * Whether to fail if the queues declared by the container are not available on\n\t\t * the broker.\n\t\t */\n\t\tprivate boolean missingQueuesFatal;\n\n\t\tpublic @Nullable Integer getConsumersPerQueue() {\n\t\t\treturn this.consumersPerQueue;\n\t\t}\n\n\t\tpublic void setConsumersPerQueue(@Nullable Integer consumersPerQueue) {\n\t\t\tthis.consumersPerQueue = consumersPerQueue;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isMissingQueuesFatal() {\n\t\t\treturn this.missingQueuesFatal;\n\t\t}\n\n\t\tpublic void setMissingQueuesFatal(boolean missingQueuesFatal) {\n\t\t\tthis.missingQueuesFatal = missingQueuesFatal;\n\t\t}\n\n\t}\n\n\tpublic static class StreamContainer extends BaseContainer {\n\n\t\t/**\n\t\t * Whether the container will support listeners that consume native stream\n\t\t * messages instead of Spring AMQP messages.\n\t\t */\n\t\tprivate boolean nativeListener;\n\n\t\tpublic boolean isNativeListener() {\n\t\t\treturn this.nativeListener;\n\t\t}\n\n\t\tpublic void setNativeListener(boolean nativeListener) {\n\t\t\tthis.nativeListener = nativeListener;\n\t\t}\n\n\t}\n\n\tpublic static class Template {\n\n\t\tprivate final Retry retry = new Retry();\n\n\t\t/**\n\t\t * Whether to enable mandatory messages.\n\t\t */\n\t\tprivate @Nullable Boolean mandatory;\n\n\t\t/**\n\t\t * Timeout for receive() operations.\n\t\t */\n\t\tprivate @Nullable Duration receiveTimeout;\n\n\t\t/**\n\t\t * Timeout for sendAndReceive() operations.\n\t\t */\n\t\tprivate @Nullable Duration replyTimeout;\n\n\t\t/**\n\t\t * Name of the default exchange to use for send operations.\n\t\t */\n\t\tprivate String exchange = \"\";\n\n\t\t/**\n\t\t * Value of a default routing key to use for send operations.\n\t\t */\n\t\tprivate String routingKey = \"\";\n\n\t\t/**\n\t\t * Name of the default queue to receive messages from when none is specified\n\t\t * explicitly.\n\t\t */\n\t\tprivate @Nullable String defaultReceiveQueue;\n\n\t\t/**\n\t\t * Whether to enable observation.\n\t\t */\n\t\tprivate boolean observationEnabled;\n\n\t\t/**\n\t\t * Simple patterns for allowable packages/classes for deserialization.\n\t\t */\n\t\tprivate @Nullable List<String> allowedListPatterns;\n\n\t\tpublic Retry getRetry() {\n\t\t\treturn this.retry;\n\t\t}\n\n\t\tpublic @Nullable Boolean getMandatory() {\n\t\t\treturn this.mandatory;\n\t\t}\n\n\t\tpublic void setMandatory(@Nullable Boolean mandatory) {\n\t\t\tthis.mandatory = mandatory;\n\t\t}\n\n\t\tpublic @Nullable Duration getReceiveTimeout() {\n\t\t\treturn this.receiveTimeout;\n\t\t}\n\n\t\tpublic void setReceiveTimeout(@Nullable Duration receiveTimeout) {\n\t\t\tthis.receiveTimeout = receiveTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getReplyTimeout() {\n\t\t\treturn this.replyTimeout;\n\t\t}\n\n\t\tpublic void setReplyTimeout(@Nullable Duration replyTimeout) {\n\t\t\tthis.replyTimeout = replyTimeout;\n\t\t}\n\n\t\tpublic String getExchange() {\n\t\t\treturn this.exchange;\n\t\t}\n\n\t\tpublic void setExchange(String exchange) {\n\t\t\tthis.exchange = exchange;\n\t\t}\n\n\t\tpublic String getRoutingKey() {\n\t\t\treturn this.routingKey;\n\t\t}\n\n\t\tpublic void setRoutingKey(String routingKey) {\n\t\t\tthis.routingKey = routingKey;\n\t\t}\n\n\t\tpublic @Nullable String getDefaultReceiveQueue() {\n\t\t\treturn this.defaultReceiveQueue;\n\t\t}\n\n\t\tpublic void setDefaultReceiveQueue(@Nullable String defaultReceiveQueue) {\n\t\t\tthis.defaultReceiveQueue = defaultReceiveQueue;\n\t\t}\n\n\t\tpublic boolean isObservationEnabled() {\n\t\t\treturn this.observationEnabled;\n\t\t}\n\n\t\tpublic void setObservationEnabled(boolean observationEnabled) {\n\t\t\tthis.observationEnabled = observationEnabled;\n\t\t}\n\n\t\tpublic @Nullable List<String> getAllowedListPatterns() {\n\t\t\treturn this.allowedListPatterns;\n\t\t}\n\n\t\tpublic void setAllowedListPatterns(@Nullable List<String> allowedListPatterns) {\n\t\t\tthis.allowedListPatterns = allowedListPatterns;\n\t\t}\n\n\t}\n\n\tpublic static class Retry {\n\n\t\t/**\n\t\t * Whether publishing retries are enabled.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Maximum number of retry attempts to deliver a message.\n\t\t */\n\t\tprivate long maxRetries = 3;\n\n\t\t/**\n\t\t * Duration between the first and second attempt to deliver a message.\n\t\t */\n\t\tprivate Duration initialInterval = Duration.ofMillis(1000);\n\n\t\t/**\n\t\t * Multiplier to apply to the previous retry interval.\n\t\t */\n\t\tprivate double multiplier = 1.0;\n\n\t\t/**\n\t\t * Maximum duration between attempts.\n\t\t */\n\t\tprivate Duration maxInterval = Duration.ofMillis(10000);\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic long getMaxRetries() {\n\t\t\treturn this.maxRetries;\n\t\t}\n\n\t\tpublic void setMaxRetries(long maxRetries) {\n\t\t\tthis.maxRetries = maxRetries;\n\t\t}\n\n\t\tpublic Duration getInitialInterval() {\n\t\t\treturn this.initialInterval;\n\t\t}\n\n\t\tpublic void setInitialInterval(Duration initialInterval) {\n\t\t\tthis.initialInterval = initialInterval;\n\t\t}\n\n\t\tpublic double getMultiplier() {\n\t\t\treturn this.multiplier;\n\t\t}\n\n\t\tpublic void setMultiplier(double multiplier) {\n\t\t\tthis.multiplier = multiplier;\n\t\t}\n\n\t\tpublic Duration getMaxInterval() {\n\t\t\treturn this.maxInterval;\n\t\t}\n\n\t\tpublic void setMaxInterval(Duration maxInterval) {\n\t\t\tthis.maxInterval = maxInterval;\n\t\t}\n\n\t\tRetryPolicySettings initializeRetryPolicySettings() {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tRetryPolicySettings settings = new RetryPolicySettings();\n\t\t\tmap.from(this::getMaxRetries).to(settings::setMaxRetries);\n\t\t\tmap.from(this::getInitialInterval).to(settings::setDelay);\n\t\t\tmap.from(this::getMultiplier).to(settings::setMultiplier);\n\t\t\tmap.from(this::getMaxInterval).to(settings::setMaxDelay);\n\t\t\treturn settings;\n\t\t}\n\n\t}\n\n\tpublic static class ListenerRetry extends Retry {\n\n\t\t/**\n\t\t * Whether retries are stateless or stateful.\n\t\t */\n\t\tprivate boolean stateless = true;\n\n\t\tpublic boolean isStateless() {\n\t\t\treturn this.stateless;\n\t\t}\n\n\t\tpublic void setStateless(boolean stateless) {\n\t\t\tthis.stateless = stateless;\n\t\t}\n\n\t}\n\n\tprivate static final class Address {\n\n\t\tprivate static final String PREFIX_AMQP = \"amqp://\";\n\n\t\tprivate static final String PREFIX_AMQP_SECURE = \"amqps://\";\n\n\t\tprivate String host;\n\n\t\tprivate int port;\n\n\t\tprivate @Nullable String username;\n\n\t\tprivate @Nullable String password;\n\n\t\tprivate @Nullable String virtualHost;\n\n\t\tprivate @Nullable Boolean secureConnection;\n\n\t\tprivate Address(String input, boolean sslEnabled) {\n\t\t\tinput = input.trim();\n\t\t\tinput = trimPrefix(input);\n\t\t\tinput = parseUsernameAndPassword(input);\n\t\t\tinput = parseVirtualHost(input);\n\t\t\tparseHostAndPort(input, sslEnabled);\n\t\t}\n\n\t\tprivate String trimPrefix(String input) {\n\t\t\tif (input.startsWith(PREFIX_AMQP_SECURE)) {\n\t\t\t\tthis.secureConnection = true;\n\t\t\t\treturn input.substring(PREFIX_AMQP_SECURE.length());\n\t\t\t}\n\t\t\tif (input.startsWith(PREFIX_AMQP)) {\n\t\t\t\tthis.secureConnection = false;\n\t\t\t\treturn input.substring(PREFIX_AMQP.length());\n\t\t\t}\n\t\t\treturn input;\n\t\t}\n\n\t\tprivate String parseUsernameAndPassword(String input) {\n\t\t\tString[] splitInput = StringUtils.split(input, \"@\");\n\t\t\tif (splitInput == null) {\n\t\t\t\treturn input;\n\t\t\t}\n\t\t\tString credentials = splitInput[0];\n\t\t\tString[] splitCredentials = StringUtils.split(credentials, \":\");\n\t\t\tif (splitCredentials == null) {\n\t\t\t\tthis.username = credentials;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.username = splitCredentials[0];\n\t\t\t\tthis.password = splitCredentials[1];\n\t\t\t}\n\t\t\treturn splitInput[1];\n\t\t}\n\n\t\tprivate String parseVirtualHost(String input) {\n\t\t\tint hostIndex = input.indexOf('/');\n\t\t\tif (hostIndex >= 0) {\n\t\t\t\tthis.virtualHost = input.substring(hostIndex + 1);\n\t\t\t\tif (this.virtualHost.isEmpty()) {\n\t\t\t\t\tthis.virtualHost = \"/\";\n\t\t\t\t}\n\t\t\t\tinput = input.substring(0, hostIndex);\n\t\t\t}\n\t\t\treturn input;\n\t\t}\n\n\t\tprivate void parseHostAndPort(String input, boolean sslEnabled) {\n\t\t\tint bracketIndex = input.lastIndexOf(']');\n\t\t\tint colonIndex = input.lastIndexOf(':');\n\t\t\tif (colonIndex == -1 || colonIndex < bracketIndex) {\n\t\t\t\tthis.host = input;\n\t\t\t\tthis.port = (determineSslEnabled(sslEnabled)) ? DEFAULT_PORT_SECURE : DEFAULT_PORT;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.host = input.substring(0, colonIndex);\n\t\t\t\tthis.port = Integer.parseInt(input.substring(colonIndex + 1));\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean determineSslEnabled(boolean sslEnabled) {\n\t\t\treturn (this.secureConnection != null) ? this.secureConnection : sslEnabled;\n\t\t}\n\n\t}\n\n\tpublic static final class Stream {\n\n\t\t/**\n\t\t * Host of a RabbitMQ instance with the Stream plugin enabled.\n\t\t */\n\t\tprivate String host = \"localhost\";\n\n\t\t/**\n\t\t * Stream port of a RabbitMQ instance with the Stream plugin enabled.\n\t\t */\n\t\tprivate int port = DEFAULT_STREAM_PORT;\n\n\t\t/**\n\t\t * Virtual host of a RabbitMQ instance with the Stream plugin enabled. When not\n\t\t * set, spring.rabbitmq.virtual-host is used.\n\t\t */\n\t\tprivate @Nullable String virtualHost;\n\n\t\t/**\n\t\t * Login user to authenticate to the broker. When not set,\n\t\t * spring.rabbitmq.username is used.\n\t\t */\n\t\tprivate @Nullable String username;\n\n\t\t/**\n\t\t * Login password to authenticate to the broker. When not set\n\t\t * spring.rabbitmq.password is used.\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\t/**\n\t\t * Name of the stream.\n\t\t */\n\t\tprivate @Nullable String name;\n\n\t\t/**\n\t\t * SSL configuration for RabbitMQ instance with the Stream plugin enabled.\n\t\t */\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tpublic String getHost() {\n\t\t\treturn this.host;\n\t\t}\n\n\t\tpublic void setHost(String host) {\n\t\t\tthis.host = host;\n\t\t}\n\n\t\tpublic int getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tpublic void setPort(int port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t\tpublic @Nullable String getVirtualHost() {\n\t\t\treturn this.virtualHost;\n\t\t}\n\n\t\tpublic void setVirtualHost(@Nullable String virtualHost) {\n\t\t\tthis.virtualHost = virtualHost;\n\t\t}\n\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic static class Ssl {\n\n\t\t\t/**\n\t\t\t * Whether to enable SSL support. Enabled automatically if \"bundle\" is\n\t\t\t * provided.\n\t\t\t */\n\t\t\tprivate @Nullable Boolean enabled;\n\n\t\t\t/**\n\t\t\t * SSL bundle name.\n\t\t\t */\n\t\t\tprivate @Nullable String bundle;\n\n\t\t\tpublic @Nullable Boolean getEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic boolean determineEnabled() {\n\t\t\t\treturn Boolean.TRUE.equals(getEnabled()) || this.bundle != null;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(@Nullable Boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getBundle() {\n\t\t\t\treturn this.bundle;\n\t\t\t}\n\n\t\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\t\tthis.bundle = bundle;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitRetryTemplateSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.LinkedList;\n\nimport org.springframework.boot.retry.RetryPolicySettings;\nimport org.springframework.core.retry.RetryListener;\nimport org.springframework.core.retry.RetryTemplate;\n\n/**\n * Define the settings of a {@link RetryTemplate}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class RabbitRetryTemplateSettings {\n\n\tprivate final RetryPolicySettings retryPolicySettings;\n\n\tprivate final LinkedList<RetryListener> retryListeners;\n\n\tRabbitRetryTemplateSettings(RetryPolicySettings retryPolicySettings) {\n\t\tthis.retryPolicySettings = retryPolicySettings;\n\t\tthis.retryListeners = new LinkedList<>();\n\t}\n\n\t/**\n\t * Return the {@link RetryPolicySettings} to use to customize the retry policy.\n\t * @return the retry policy settings\n\t */\n\tpublic RetryPolicySettings getRetryPolicySettings() {\n\t\treturn this.retryPolicySettings;\n\t}\n\n\t/**\n\t * Return the list of {@link RetryListener} instances. The returned list is mutable\n\t * and can be used to add listeners.\n\t * @return the retry listeners\n\t */\n\tpublic LinkedList<RetryListener> getRetryListeners() {\n\t\treturn this.retryListeners;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitStreamConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport javax.net.ssl.SSLException;\n\nimport com.rabbitmq.stream.Environment;\nimport com.rabbitmq.stream.EnvironmentBuilder;\nimport io.netty.handler.ssl.SslContext;\nimport io.netty.handler.ssl.SslContextBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.config.ContainerCustomizer;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties.Stream;\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties.Stream.Ssl;\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties.StreamContainer;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslManagerBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.rabbit.stream.config.StreamRabbitListenerContainerFactory;\nimport org.springframework.rabbit.stream.listener.ConsumerCustomizer;\nimport org.springframework.rabbit.stream.listener.StreamListenerContainer;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamListenerObservationConvention;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamTemplateObservationConvention;\nimport org.springframework.rabbit.stream.producer.ProducerCustomizer;\nimport org.springframework.rabbit.stream.producer.RabbitStreamOperations;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.converter.StreamMessageConverter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration for Spring RabbitMQ Stream plugin support.\n *\n * @author Gary Russell\n * @author Eddú Meléndez\n * @author Jay Choi\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(StreamRabbitListenerContainerFactory.class)\nclass RabbitStreamConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tRabbitStreamConnectionDetails rabbitStreamConnectionDetails(RabbitProperties rabbitProperties,\n\t\t\t@Nullable SslBundles sslBundles) {\n\t\treturn new PropertiesRabbitStreamConnectionDetails(rabbitProperties.getStream(), sslBundles);\n\t}\n\n\t@Bean(name = \"rabbitListenerContainerFactory\")\n\t@ConditionalOnMissingBean(name = \"rabbitListenerContainerFactory\")\n\t@ConditionalOnProperty(name = \"spring.rabbitmq.listener.type\", havingValue = \"stream\")\n\tStreamRabbitListenerContainerFactory streamRabbitListenerContainerFactory(Environment rabbitStreamEnvironment,\n\t\t\tRabbitProperties properties, ObjectProvider<ConsumerCustomizer> consumerCustomizer,\n\t\t\tObjectProvider<ContainerCustomizer<StreamListenerContainer>> containerCustomizer,\n\t\t\tObjectProvider<RabbitStreamListenerObservationConvention> observationConvention) {\n\t\tStreamRabbitListenerContainerFactory factory = new StreamRabbitListenerContainerFactory(\n\t\t\t\trabbitStreamEnvironment);\n\t\tStreamContainer stream = properties.getListener().getStream();\n\t\tfactory.setObservationEnabled(stream.isObservationEnabled());\n\t\tfactory.setNativeListener(stream.isNativeListener());\n\t\tobservationConvention.ifUnique(factory::setStreamListenerObservationConvention);\n\t\tconsumerCustomizer.ifUnique(factory::setConsumerCustomizer);\n\t\tcontainerCustomizer.ifUnique(factory::setContainerCustomizer);\n\t\treturn factory;\n\n\t}\n\n\t@Bean(name = \"rabbitStreamEnvironment\")\n\t@ConditionalOnMissingBean(name = \"rabbitStreamEnvironment\")\n\tEnvironment rabbitStreamEnvironment(RabbitProperties properties, RabbitConnectionDetails connectionDetails,\n\t\t\tRabbitStreamConnectionDetails streamConnectionDetails,\n\t\t\tObjectProvider<EnvironmentBuilderCustomizer> customizers) {\n\t\tEnvironmentBuilder builder = configure(Environment.builder(), properties, connectionDetails,\n\t\t\t\tstreamConnectionDetails);\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tRabbitStreamTemplateConfigurer rabbitStreamTemplateConfigurer(RabbitProperties properties,\n\t\t\tObjectProvider<MessageConverter> messageConverter,\n\t\t\tObjectProvider<StreamMessageConverter> streamMessageConverter,\n\t\t\tObjectProvider<ProducerCustomizer> producerCustomizer,\n\t\t\tObjectProvider<RabbitStreamTemplateObservationConvention> observationConvention) {\n\t\tRabbitStreamTemplateConfigurer configurer = new RabbitStreamTemplateConfigurer();\n\t\tconfigurer.setMessageConverter(messageConverter.getIfUnique());\n\t\tconfigurer.setStreamMessageConverter(streamMessageConverter.getIfUnique());\n\t\tconfigurer.setProducerCustomizer(producerCustomizer.getIfUnique());\n\t\tconfigurer.setObservationConvention(observationConvention.getIfUnique());\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(RabbitStreamOperations.class)\n\t@ConditionalOnProperty(name = \"spring.rabbitmq.stream.name\")\n\tRabbitStreamTemplate rabbitStreamTemplate(Environment rabbitStreamEnvironment, RabbitProperties properties,\n\t\t\tRabbitStreamTemplateConfigurer configurer) {\n\t\tString name = properties.getStream().getName();\n\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\tRabbitStreamTemplate template = new RabbitStreamTemplate(rabbitStreamEnvironment, name);\n\t\tconfigurer.configure(template);\n\t\treturn template;\n\t}\n\n\tstatic EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties properties,\n\t\t\tRabbitConnectionDetails connectionDetails, RabbitStreamConnectionDetails streamConnectionDetails) {\n\t\treturn configure(builder, properties.getStream(), connectionDetails, streamConnectionDetails);\n\t}\n\n\tprivate static EnvironmentBuilder configure(EnvironmentBuilder builder, RabbitProperties.Stream stream,\n\t\t\tRabbitConnectionDetails connectionDetails, RabbitStreamConnectionDetails streamConnectionDetails) {\n\t\tbuilder.lazyInitialization(true);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(streamConnectionDetails.getHost()).to(builder::host);\n\t\tmap.from(streamConnectionDetails.getPort()).to(builder::port);\n\t\tmap.from(streamConnectionDetails.getVirtualHost())\n\t\t\t.orFrom(connectionDetails::getVirtualHost)\n\t\t\t.to(builder::virtualHost);\n\t\tmap.from(streamConnectionDetails.getUsername()).orFrom(connectionDetails::getUsername).to(builder::username);\n\t\tmap.from(streamConnectionDetails.getPassword()).orFrom(connectionDetails::getPassword).to(builder::password);\n\t\tSslBundle sslBundle = streamConnectionDetails.getSslBundle();\n\t\tif (sslBundle != null) {\n\t\t\tbuilder.tls().sslContext(createSslContext(sslBundle));\n\t\t}\n\t\telse if (stream.getSsl().determineEnabled()) {\n\t\t\tbuilder.tls();\n\t\t}\n\t\treturn builder;\n\t}\n\n\tprivate static SslContext createSslContext(SslBundle sslBundle) {\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tSslManagerBundle managers = sslBundle.getManagers();\n\t\ttry {\n\t\t\treturn SslContextBuilder.forClient()\n\t\t\t\t.keyManager(managers.getKeyManagerFactory())\n\t\t\t\t.trustManager(managers.getTrustManagerFactory())\n\t\t\t\t.ciphers(SslOptions.asSet(options.getCiphers()))\n\t\t\t\t.protocols(options.getEnabledProtocols())\n\t\t\t\t.build();\n\t\t}\n\t\tcatch (SSLException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to create SSL context for RabbitMQ Stream\", ex);\n\t\t}\n\t}\n\n\tstatic class PropertiesRabbitStreamConnectionDetails implements RabbitStreamConnectionDetails {\n\n\t\tprivate final Stream streamProperties;\n\n\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\tPropertiesRabbitStreamConnectionDetails(Stream streamProperties, @Nullable SslBundles sslBundles) {\n\t\t\tthis.streamProperties = streamProperties;\n\t\t\tthis.sslBundles = sslBundles;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getHost() {\n\t\t\treturn this.streamProperties.getHost();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getPort() {\n\t\t\treturn this.streamProperties.getPort();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getVirtualHost() {\n\t\t\treturn this.streamProperties.getVirtualHost();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.streamProperties.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.streamProperties.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\tSsl ssl = this.streamProperties.getSsl();\n\t\t\tif (!ssl.determineEnabled()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitStreamConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to a RabbitMQ Stream service.\n *\n * @author Eddú Meléndez\n * @author Jay Choi\n * @since 4.1.0\n */\npublic interface RabbitStreamConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Rabbit Stream server host.\n\t * @return the Rabbit Stream server host\n\t */\n\tString getHost();\n\n\t/**\n\t * Rabbit Stream server port.\n\t * @return the Rabbit Stream server port\n\t */\n\tint getPort();\n\n\t/**\n\t * Username for authentication.\n\t * @return the username for authentication or {@code null}\n\t */\n\tdefault @Nullable String getUsername() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Password for authentication.\n\t * @return the password for authentication or {@code null}\n\t */\n\tdefault @Nullable String getPassword() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Virtual host to use when connecting to the broker.\n\t * @return the virtual host to use when connecting to the broker or {@code null}\n\t */\n\tdefault @Nullable String getVirtualHost() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use or {@code null}\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitStreamTemplateConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamTemplateObservationConvention;\nimport org.springframework.rabbit.stream.producer.ProducerCustomizer;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.converter.StreamMessageConverter;\n\n/**\n * Configure {@link RabbitStreamTemplate} with sensible defaults.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code RabbitStreamTemplate} whose configuration is based upon that produced by\n * auto-configuration.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\npublic class RabbitStreamTemplateConfigurer {\n\n\tprivate @Nullable MessageConverter messageConverter;\n\n\tprivate @Nullable StreamMessageConverter streamMessageConverter;\n\n\tprivate @Nullable ProducerCustomizer producerCustomizer;\n\n\tprivate @Nullable RabbitStreamTemplateObservationConvention observationConvention;\n\n\t/**\n\t * Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box\n\t * converter should be used.\n\t * @param messageConverter the {@link MessageConverter}\n\t */\n\tpublic void setMessageConverter(@Nullable MessageConverter messageConverter) {\n\t\tthis.messageConverter = messageConverter;\n\t}\n\n\t/**\n\t * Set the {@link StreamMessageConverter} to use or {@code null} if the out-of-the-box\n\t * stream message converter should be used.\n\t * @param streamMessageConverter the {@link StreamMessageConverter}\n\t */\n\tpublic void setStreamMessageConverter(@Nullable StreamMessageConverter streamMessageConverter) {\n\t\tthis.streamMessageConverter = streamMessageConverter;\n\t}\n\n\t/**\n\t * Set the {@link ProducerCustomizer} instances to use.\n\t * @param producerCustomizer the producer customizer\n\t */\n\tpublic void setProducerCustomizer(@Nullable ProducerCustomizer producerCustomizer) {\n\t\tthis.producerCustomizer = producerCustomizer;\n\t}\n\n\t/**\n\t * Set the observation convention to use.\n\t * @param observationConvention the observation convention to use\n\t * @since 4.1.0\n\t */\n\tpublic void setObservationConvention(@Nullable RabbitStreamTemplateObservationConvention observationConvention) {\n\t\tthis.observationConvention = observationConvention;\n\t}\n\n\t/**\n\t * Configure the specified {@link RabbitStreamTemplate}. The template can be further\n\t * tuned and default settings can be overridden.\n\t * @param template the {@link RabbitStreamTemplate} instance to configure\n\t */\n\tpublic void configure(RabbitStreamTemplate template) {\n\t\tif (this.messageConverter != null) {\n\t\t\ttemplate.setMessageConverter(this.messageConverter);\n\t\t}\n\t\tif (this.streamMessageConverter != null) {\n\t\t\ttemplate.setStreamConverter(this.streamMessageConverter);\n\t\t}\n\t\tif (this.producerCustomizer != null) {\n\t\t\ttemplate.setProducerCustomizer(this.producerCustomizer);\n\t\t}\n\t\tif (this.observationConvention != null) {\n\t\t\ttemplate.setObservationConvention(this.observationConvention);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitTemplateConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitTemplateObservationConvention;\nimport org.springframework.amqp.support.converter.AllowedListDeserializingMessageConverter;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.core.retry.RetryListener;\nimport org.springframework.core.retry.RetryPolicy;\nimport org.springframework.core.retry.RetryTemplate;\nimport org.springframework.core.retry.support.CompositeRetryListener;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Configure {@link RabbitTemplate} with sensible defaults tuned using configuration\n * properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code RabbitTemplate} whose configuration is based upon that produced by\n * auto-configuration.\n *\n * @author Stephane Nicoll\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class RabbitTemplateConfigurer {\n\n\tprivate @Nullable MessageConverter messageConverter;\n\n\tprivate @Nullable List<RabbitTemplateRetrySettingsCustomizer> retrySettingsCustomizers;\n\n\tprivate @Nullable RabbitTemplateObservationConvention observationConvention;\n\n\tprivate final RabbitProperties rabbitProperties;\n\n\t/**\n\t * Creates a new configurer that will use the given {@code rabbitProperties}.\n\t * @param rabbitProperties properties to use\n\t */\n\tpublic RabbitTemplateConfigurer(RabbitProperties rabbitProperties) {\n\t\tAssert.notNull(rabbitProperties, \"'rabbitProperties' must not be null\");\n\t\tthis.rabbitProperties = rabbitProperties;\n\t}\n\n\t/**\n\t * Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box\n\t * converter should be used.\n\t * @param messageConverter the {@link MessageConverter}\n\t */\n\tpublic void setMessageConverter(@Nullable MessageConverter messageConverter) {\n\t\tthis.messageConverter = messageConverter;\n\t}\n\n\t/**\n\t * Set the {@link RabbitTemplateRetrySettingsCustomizer} instances to use.\n\t * @param retrySettingsCustomizers the retry settings customizers\n\t */\n\tpublic void setRetrySettingsCustomizers(\n\t\t\t@Nullable List<RabbitTemplateRetrySettingsCustomizer> retrySettingsCustomizers) {\n\t\tthis.retrySettingsCustomizers = retrySettingsCustomizers;\n\t}\n\n\t/**\n\t * Sets the observation convention to use.\n\t * @param observationConvention the observation convention to use\n\t * @since 4.1.0\n\t */\n\tpublic void setObservationConvention(@Nullable RabbitTemplateObservationConvention observationConvention) {\n\t\tthis.observationConvention = observationConvention;\n\t}\n\n\tprotected final RabbitProperties getRabbitProperties() {\n\t\treturn this.rabbitProperties;\n\t}\n\n\t/**\n\t * Configure the specified {@link RabbitTemplate}. The template can be further tuned\n\t * and default settings can be overridden.\n\t * @param template the {@link RabbitTemplate} instance to configure\n\t * @param connectionFactory the {@link ConnectionFactory} to use\n\t */\n\tpublic void configure(RabbitTemplate template, ConnectionFactory connectionFactory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\ttemplate.setConnectionFactory(connectionFactory);\n\t\tif (this.messageConverter != null) {\n\t\t\ttemplate.setMessageConverter(this.messageConverter);\n\t\t}\n\t\ttemplate.setMandatory(determineMandatoryFlag());\n\t\tRabbitProperties.Template templateProperties = this.rabbitProperties.getTemplate();\n\t\tif (templateProperties.getRetry().isEnabled()) {\n\t\t\ttemplate.setRetryTemplate(createRetryTemplate(templateProperties.getRetry()));\n\t\t}\n\t\tmap.from(templateProperties::getReceiveTimeout).as(Duration::toMillis).to(template::setReceiveTimeout);\n\t\tmap.from(templateProperties::getReplyTimeout).as(Duration::toMillis).to(template::setReplyTimeout);\n\t\tmap.from(templateProperties::getExchange).to(template::setExchange);\n\t\tmap.from(templateProperties::getRoutingKey).to(template::setRoutingKey);\n\t\tmap.from(templateProperties::getDefaultReceiveQueue).to(template::setDefaultReceiveQueue);\n\t\tmap.from(templateProperties::isObservationEnabled).to(template::setObservationEnabled);\n\t\tmap.from(templateProperties::getAllowedListPatterns)\n\t\t\t.whenNot(CollectionUtils::isEmpty)\n\t\t\t.to((allowedListPatterns) -> setAllowedListPatterns(template.getMessageConverter(), allowedListPatterns));\n\t\tif (this.observationConvention != null) {\n\t\t\ttemplate.setObservationConvention(this.observationConvention);\n\t\t}\n\t}\n\n\tprotected RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) {\n\t\tRabbitRetryTemplateSettings retrySettings = new RabbitRetryTemplateSettings(\n\t\t\t\tproperties.initializeRetryPolicySettings());\n\t\tif (this.retrySettingsCustomizers != null) {\n\t\t\tfor (RabbitTemplateRetrySettingsCustomizer customizer : this.retrySettingsCustomizers) {\n\t\t\t\tcustomizer.customize(retrySettings);\n\t\t\t}\n\t\t}\n\t\tRetryPolicy retryPolicy = retrySettings.getRetryPolicySettings().createRetryPolicy();\n\t\tRetryListener retryListener = createRetryListener(retrySettings.getRetryListeners());\n\t\tRetryTemplate retryTemplate = new RetryTemplate(retryPolicy);\n\t\tif (retryListener != null) {\n\t\t\tretryTemplate.setRetryListener(retryListener);\n\t\t}\n\t\treturn retryTemplate;\n\t}\n\n\tprivate @Nullable RetryListener createRetryListener(List<RetryListener> configuredListeners) {\n\t\tif (configuredListeners.size() > 1) {\n\t\t\treturn new CompositeRetryListener(configuredListeners);\n\t\t}\n\t\tif (configuredListeners.size() == 1) {\n\t\t\treturn configuredListeners.get(0);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void setAllowedListPatterns(MessageConverter messageConverter, List<String> allowedListPatterns) {\n\t\tif (messageConverter instanceof AllowedListDeserializingMessageConverter allowedListDeserializingMessageConverter) {\n\t\t\tallowedListDeserializingMessageConverter.setAllowedListPatterns(allowedListPatterns);\n\t\t\treturn;\n\t\t}\n\t\tthrow new InvalidConfigurationPropertyValueException(\"spring.rabbitmq.template.allowed-list-patterns\",\n\t\t\t\tallowedListPatterns,\n\t\t\t\t\"Allowed list patterns can only be applied to an AllowedListDeserializingMessageConverter\");\n\t}\n\n\tprivate boolean determineMandatoryFlag() {\n\t\tBoolean mandatory = this.rabbitProperties.getTemplate().getMandatory();\n\t\treturn (mandatory != null) ? mandatory : this.rabbitProperties.isPublisherReturns();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\n\n/**\n * Callback interface that can be used to customize a {@link RabbitTemplate}.\n *\n * @author dang zhicairang\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RabbitTemplateCustomizer {\n\n\t/**\n\t * Callback to customize a {@link RabbitTemplate} instance.\n\t * @param rabbitTemplate the rabbitTemplate to customize\n\t */\n\tvoid customize(RabbitTemplate rabbitTemplate);\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/RabbitTemplateRetrySettingsCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.core.retry.RetryTemplate;\n\n/**\n * Callback interface that can be used to customize\n * {@linkplain RabbitRetryTemplateSettings retry settings} used by {@link RabbitTemplate}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see RabbitTemplateConfigurer\n * @see RetryTemplate\n */\n@FunctionalInterface\npublic interface RabbitTemplateRetrySettingsCustomizer {\n\n\t/**\n\t * Callback to customize the {@link RabbitRetryTemplateSettings} to create the\n\t * {@link RetryTemplate} used as part of {@link RabbitTemplate} operations.\n\t * @param retrySettings the settings to customize\n\t */\n\tvoid customize(RabbitRetryTemplateSettings retrySettings);\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/SimpleRabbitListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.boot.context.properties.PropertyMapper;\n\n/**\n * Configure {@link SimpleRabbitListenerContainerFactory} with sensible defaults tuned\n * using configuration properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code SimpleRabbitListenerContainerFactory} whose configuration is based upon that\n * produced by auto-configuration.\n *\n * @author Stephane Nicoll\n * @author Gary Russell\n * @since 4.0.0\n */\npublic final class SimpleRabbitListenerContainerFactoryConfigurer\n\t\textends AbstractRabbitListenerContainerFactoryConfigurer<SimpleRabbitListenerContainerFactory> {\n\n\t/**\n\t * Creates a new configurer that will use the given {@code rabbitProperties}.\n\t * @param rabbitProperties properties to use\n\t */\n\tpublic SimpleRabbitListenerContainerFactoryConfigurer(RabbitProperties rabbitProperties) {\n\t\tsuper(rabbitProperties);\n\t}\n\n\t@Override\n\tpublic void configure(SimpleRabbitListenerContainerFactory factory, ConnectionFactory connectionFactory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRabbitProperties.SimpleContainer config = getRabbitProperties().getListener().getSimple();\n\t\tconfigure(factory, connectionFactory, config);\n\t\tmap.from(config::getConcurrency).to(factory::setConcurrentConsumers);\n\t\tmap.from(config::getMaxConcurrency).to(factory::setMaxConcurrentConsumers);\n\t\tmap.from(config::getBatchSize).to(factory::setBatchSize);\n\t\tmap.from(config::isConsumerBatchEnabled).to(factory::setConsumerBatchEnabled);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/SslBundleRabbitConnectionFactoryBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * A {@link RabbitConnectionFactoryBean} that can be configured with custom SSL trust\n * material from an {@link SslBundle}.\n *\n * @author Scott Frederick\n */\nclass SslBundleRabbitConnectionFactoryBean extends RabbitConnectionFactoryBean {\n\n\tprivate @Nullable SslBundle sslBundle;\n\n\tprivate boolean enableHostnameVerification;\n\n\t@Override\n\tprotected void setUpSSL() {\n\t\tif (this.sslBundle != null) {\n\t\t\tthis.connectionFactory.useSslProtocol(this.sslBundle.createSslContext());\n\t\t\tif (this.enableHostnameVerification) {\n\t\t\t\tthis.connectionFactory.enableHostnameVerification();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tsuper.setUpSSL();\n\t\t}\n\t}\n\n\tvoid setSslBundle(@Nullable SslBundle sslBundle) {\n\t\tthis.sslBundle = sslBundle;\n\t}\n\n\t@Override\n\tpublic void setEnableHostnameVerification(boolean enable) {\n\t\tthis.enableHostnameVerification = enable;\n\t\tsuper.setEnableHostnameVerification(enable);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/health/RabbitHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure.health;\n\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.health.RabbitHealthIndicator;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link RabbitHealthIndicator}.\n *\n * @author Christian Dupuis\n * @since 4.0.0\n */\n@AutoConfiguration(after = RabbitAutoConfiguration.class)\n@ConditionalOnClass({ RabbitHealthIndicator.class, RabbitTemplate.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(RabbitTemplate.class)\n@ConditionalOnEnabledHealthIndicator(\"rabbit\")\npublic final class RabbitHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<RabbitHealthIndicator, RabbitTemplate> {\n\n\tRabbitHealthContributorAutoConfiguration() {\n\t\tsuper(RabbitHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"rabbitHealthIndicator\", \"rabbitHealthContributor\" })\n\tHealthContributor rabbitHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, RabbitTemplate.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RabbitMQ health.\n */\n@NullMarked\npackage org.springframework.boot.amqp.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/metrics/RabbitConnectionFactoryMetricsPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure.metrics;\n\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.MetricsCollector;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.connection.AbstractConnectionFactory;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.amqp.metrics.RabbitMetrics;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link BeanPostProcessor} that configures RabbitMQ metrics. Such arrangement is\n * necessary because a connection can be eagerly created and cached without a reference to\n * a proper {@link MetricsCollector}.\n *\n * @author Stephane Nicoll\n */\nclass RabbitConnectionFactoryMetricsPostProcessor implements BeanPostProcessor, Ordered {\n\n\tprivate static final String CONNECTION_FACTORY_SUFFIX = \"connectionFactory\";\n\n\tprivate final ApplicationContext context;\n\n\tprivate volatile @Nullable MeterRegistry meterRegistry;\n\n\tRabbitConnectionFactoryMetricsPostProcessor(ApplicationContext context) {\n\t\tthis.context = context;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\tif (bean instanceof AbstractConnectionFactory connectionFactory) {\n\t\t\tbindConnectionFactoryToRegistry(getMeterRegistry(), beanName, connectionFactory);\n\t\t}\n\t\treturn bean;\n\t}\n\n\tprivate void bindConnectionFactoryToRegistry(MeterRegistry registry, String beanName,\n\t\t\tAbstractConnectionFactory connectionFactory) {\n\t\tConnectionFactory rabbitConnectionFactory = connectionFactory.getRabbitConnectionFactory();\n\t\tString connectionFactoryName = getConnectionFactoryName(beanName);\n\t\tnew RabbitMetrics(rabbitConnectionFactory, Tags.of(\"name\", connectionFactoryName)).bindTo(registry);\n\t}\n\n\t/**\n\t * Get the name of a ConnectionFactory based on its {@code beanName}.\n\t * @param beanName the name of the connection factory bean\n\t * @return a name for the given connection factory\n\t */\n\tprivate String getConnectionFactoryName(String beanName) {\n\t\tif (beanName.length() > CONNECTION_FACTORY_SUFFIX.length()\n\t\t\t\t&& StringUtils.endsWithIgnoreCase(beanName, CONNECTION_FACTORY_SUFFIX)) {\n\t\t\treturn beanName.substring(0, beanName.length() - CONNECTION_FACTORY_SUFFIX.length());\n\t\t}\n\t\treturn beanName;\n\t}\n\n\tprivate MeterRegistry getMeterRegistry() {\n\t\tMeterRegistry meterRegistry = this.meterRegistry;\n\t\tif (meterRegistry == null) {\n\t\t\tmeterRegistry = this.context.getBean(MeterRegistry.class);\n\t\t\tthis.meterRegistry = meterRegistry;\n\t\t}\n\t\treturn meterRegistry;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/metrics/RabbitMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure.metrics;\n\nimport com.rabbitmq.client.ConnectionFactory;\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.amqp.rabbit.connection.AbstractConnectionFactory;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available\n * {@link ConnectionFactory connection factories}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\",\n\t\tafter = RabbitAutoConfiguration.class)\n@ConditionalOnClass({ ConnectionFactory.class, AbstractConnectionFactory.class, MeterRegistry.class })\n@ConditionalOnBean({ org.springframework.amqp.rabbit.connection.ConnectionFactory.class, MeterRegistry.class })\npublic final class RabbitMetricsAutoConfiguration {\n\n\t@Bean\n\tstatic RabbitConnectionFactoryMetricsPostProcessor rabbitConnectionFactoryMetricsPostProcessor(\n\t\t\tApplicationContext applicationContext) {\n\t\treturn new RabbitConnectionFactoryMetricsPostProcessor(applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RabbitMQ metrics.\n */\n@NullMarked\npackage org.springframework.boot.amqp.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RabbitMQ.\n */\n@NullMarked\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/docker/compose/RabbitDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link RabbitStreamConnectionDetails} for a {@code rabbitmq} service.\n *\n * @author Andy Wilkinson\n */\nclass RabbitDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<RabbitConnectionDetails> {\n\n\tprivate static final int RABBITMQ_PORT = 5672;\n\n\tprotected RabbitDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"rabbitmq\");\n\t}\n\n\t@Override\n\tprotected @Nullable RabbitConnectionDetails getDockerComposeConnectionDetails(\n\t\t\tDockerComposeConnectionSource source) {\n\t\ttry {\n\t\t\treturn new RabbitDockerComposeConnectionDetails(source.getRunningService());\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * {@link RabbitConnectionDetails} backed by a {@code rabbitmq}\n\t * {@link RunningService}.\n\t */\n\tstatic class RabbitDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements RabbitConnectionDetails {\n\n\t\tprivate final RabbitEnvironment environment;\n\n\t\tprivate final List<Address> addresses;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tprotected RabbitDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new RabbitEnvironment(service.env());\n\t\t\tthis.sslBundle = getSslBundle(service);\n\t\t\tthis.addresses = List.of(new Address(service.host(), service.ports().get(RABBITMQ_PORT)));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getVirtualHost() {\n\t\t\treturn \"/\";\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Address> getAddresses() {\n\t\t\treturn this.addresses;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/docker/compose/RabbitEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * RabbitMQ environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass RabbitEnvironment {\n\n\tprivate final @Nullable String username;\n\n\tprivate final @Nullable String password;\n\n\tRabbitEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = env.getOrDefault(\"RABBITMQ_DEFAULT_USER\", env.getOrDefault(\"RABBITMQ_USERNAME\", \"guest\"));\n\t\tthis.password = env.getOrDefault(\"RABBITMQ_DEFAULT_PASS\", env.getOrDefault(\"RABBITMQ_PASSWORD\", \"guest\"));\n\t}\n\n\t@Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/docker/compose/RabbitStreamDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link RabbitConnectionDetails}\n * for a {@code rabbitmq} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Jay Choi\n */\nclass RabbitStreamDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<RabbitStreamConnectionDetails> {\n\n\tprotected RabbitStreamDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"rabbitmq\");\n\t}\n\n\t@Override\n\tprotected @Nullable RabbitStreamConnectionDetails getDockerComposeConnectionDetails(\n\t\t\tDockerComposeConnectionSource source) {\n\t\ttry {\n\t\t\treturn new RabbitStreamDockerComposeConnectionDetails(source.getRunningService());\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * {@link RabbitStreamConnectionDetails} backed by a {@code rabbitmq}\n\t * {@link RunningService}.\n\t */\n\tstatic class RabbitStreamDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements RabbitStreamConnectionDetails {\n\n\t\tprivate static final int STREAMS_PORT = 5552;\n\n\t\tprivate static final int STREAMS_TLS_PORT = 5551;\n\n\t\tprivate final RabbitEnvironment environment;\n\n\t\tprivate final String host;\n\n\t\tprivate final int port;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tprotected RabbitStreamDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new RabbitEnvironment(service.env());\n\t\t\tthis.host = service.host();\n\t\t\tthis.sslBundle = getSslBundle(service);\n\t\t\tthis.port = service.ports().get((this.sslBundle != null) ? STREAMS_TLS_PORT : STREAMS_PORT);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getVirtualHost() {\n\t\t\treturn \"/\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getHost() {\n\t\t\treturn this.host;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose RabbitMQ service connections.\n */\n@NullMarked\npackage org.springframework.boot.amqp.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/health/RabbitHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.health;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.util.Assert;\n\n/**\n * Simple implementation of a {@link HealthIndicator} returning status information for the\n * RabbitMQ messaging system.\n *\n * @author Christian Dupuis\n * @since 4.0.0\n */\npublic class RabbitHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final RabbitTemplate rabbitTemplate;\n\n\tpublic RabbitHealthIndicator(RabbitTemplate rabbitTemplate) {\n\t\tsuper(\"Rabbit health check failed\");\n\t\tAssert.notNull(rabbitTemplate, \"'rabbitTemplate' must not be null\");\n\t\tthis.rabbitTemplate = rabbitTemplate;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tbuilder.up();\n\t\tString version = getVersion();\n\t\tif (version != null) {\n\t\t\tbuilder.withDetail(\"version\", version);\n\t\t}\n\t}\n\n\tprivate @Nullable String getVersion() {\n\t\treturn this.rabbitTemplate.execute((channel) -> {\n\t\t\tObject version = channel.getConnection().getServerProperties().getOrDefault(\"version\", \"unknown\");\n\t\t\tAssert.state(version != null, \"'version' must not be null\");\n\t\t\treturn version.toString();\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for AMQP and RabbitMQ.\n */\n@NullMarked\npackage org.springframework.boot.amqp.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/metrics/RabbitMetrics.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.metrics;\n\nimport java.util.Collections;\n\nimport com.rabbitmq.client.ConnectionFactory;\nimport com.rabbitmq.client.impl.MicrometerMetricsCollector;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A {@link MeterBinder} for RabbitMQ Java Client metrics.\n *\n * @author Arnaud Cogoluègnes\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class RabbitMetrics implements MeterBinder {\n\n\tprivate final Iterable<Tag> tags;\n\n\tprivate final ConnectionFactory connectionFactory;\n\n\t/**\n\t * Create a new meter binder recording the specified {@link ConnectionFactory}.\n\t * @param connectionFactory the {@link ConnectionFactory} to instrument\n\t * @param tags tags to apply to all recorded metrics\n\t */\n\tpublic RabbitMetrics(ConnectionFactory connectionFactory, @Nullable Iterable<Tag> tags) {\n\t\tAssert.notNull(connectionFactory, \"'connectionFactory' must not be null\");\n\t\tthis.connectionFactory = connectionFactory;\n\t\tthis.tags = (tags != null) ? tags : Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic void bindTo(MeterRegistry registry) {\n\t\tthis.connectionFactory.setMetricsCollector(new MicrometerMetricsCollector(registry, \"rabbitmq\", this.tags));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Metrics for AMQP and RabbitMQ.\n */\n@NullMarked\npackage org.springframework.boot.amqp.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/testcontainers/DeprecatedRabbitContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.net.URI;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.RabbitMQContainer;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link RabbitConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link RabbitMQContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link RabbitContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedRabbitContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<RabbitMQContainer, RabbitConnectionDetails> {\n\n\t@Override\n\tprotected RabbitConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<RabbitMQContainer> source) {\n\t\treturn new RabbitMqContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link RabbitConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class RabbitMqContainerConnectionDetails extends ContainerConnectionDetails<RabbitMQContainer>\n\t\t\timplements RabbitConnectionDetails {\n\n\t\tprivate RabbitMqContainerConnectionDetails(ContainerConnectionSource<RabbitMQContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getAdminUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getAdminPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Address> getAddresses() {\n\t\t\tURI uri = URI.create((getSslBundle() != null) ? getContainer().getAmqpsUrl() : getContainer().getAmqpUrl());\n\t\t\treturn List.of(new Address(uri.getHost(), uri.getPort()));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/testcontainers/RabbitContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport java.net.URI;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link RabbitConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link RabbitMQContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass RabbitContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<RabbitMQContainer, RabbitConnectionDetails> {\n\n\t@Override\n\tprotected RabbitConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<RabbitMQContainer> source) {\n\t\treturn new RabbitMqContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link RabbitConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tstatic final class RabbitMqContainerConnectionDetails extends ContainerConnectionDetails<RabbitMQContainer>\n\t\t\timplements RabbitConnectionDetails {\n\n\t\tprivate RabbitMqContainerConnectionDetails(ContainerConnectionSource<RabbitMQContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getAdminUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getAdminPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Address> getAddresses() {\n\t\t\tURI uri = URI.create((getSslBundle() != null) ? getContainer().getAmqpsUrl() : getContainer().getAmqpUrl());\n\t\t\treturn List.of(new Address(uri.getHost(), uri.getPort()));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/testcontainers/RabbitStreamContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.testcontainers;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link RabbitStreamConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link RabbitMQContainer}.\n *\n * @author Eddú Meléndez\n * @author Jay Choi\n */\nclass RabbitStreamContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<RabbitMQContainer, RabbitStreamConnectionDetails> {\n\n\tRabbitStreamContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"org.springframework.rabbit.stream.producer.RabbitStreamTemplate\");\n\t}\n\n\t@Override\n\tprotected boolean sourceAccepts(ContainerConnectionSource<RabbitMQContainer> source, Class<?> requiredContainerType,\n\t\t\tClass<?> requiredConnectionDetailsType) {\n\t\treturn source.getConnectionDetailsTypes().contains(requiredConnectionDetailsType)\n\t\t\t\t&& super.sourceAccepts(source, requiredContainerType, requiredConnectionDetailsType);\n\t}\n\n\t@Override\n\tprotected RabbitStreamConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<RabbitMQContainer> source) {\n\t\treturn new RabbitMqStreamContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link RabbitStreamConnectionDetails} backed by a\n\t * {@link ContainerConnectionSource}.\n\t */\n\tstatic final class RabbitMqStreamContainerConnectionDetails extends ContainerConnectionDetails<RabbitMQContainer>\n\t\t\timplements RabbitStreamConnectionDetails {\n\n\t\tprivate static final int STREAMS_PORT = 5552;\n\n\t\tprivate static final int STREAMS_TLS_PORT = 5551;\n\n\t\tprivate RabbitMqStreamContainerConnectionDetails(ContainerConnectionSource<RabbitMQContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getHost() {\n\t\t\treturn getContainer().getHost();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getPort() {\n\t\t\treturn getContainer().getMappedPort((getSslBundle() != null) ? STREAMS_TLS_PORT : STREAMS_PORT);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getAdminUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getAdminPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/java/org/springframework/boot/amqp/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers RabbitMQ service connections.\n */\n@NullMarked\npackage org.springframework.boot.amqp.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-amqp/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.rabbit.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable RabbitMQ health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.rabbitmq.dynamic\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to create an AmqpAdmin bean.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.rabbitmq.listener.direct.retry.max-attempts\",\n      \"type\": \"java.lang.Long\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.rabbitmq.listener.direct.retry.max-retries\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.rabbitmq.listener.simple.retry.max-attempts\",\n      \"type\": \"java.lang.Long\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.rabbitmq.listener.simple.retry.max-retries\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.rabbitmq.listener.simple.transaction-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.rabbitmq.publisher-confirms\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.rabbitmq.template.queue\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.rabbitmq.template.default-receive-queue\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.rabbitmq.template.retry.max-attempts\",\n      \"type\": \"java.lang.Long\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.rabbitmq.template.retry.max-retries\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-amqp/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration\norg.springframework.boot.amqp.autoconfigure.health.RabbitHealthContributorAutoConfiguration\norg.springframework.boot.amqp.autoconfigure.metrics.RabbitMetricsAutoConfiguration"
  },
  {
    "path": "module/spring-boot-amqp/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.amqp.docker.compose.RabbitDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.amqp.docker.compose.RabbitStreamDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.amqp.testcontainers.DeprecatedRabbitContainerConnectionDetailsFactory,\\\norg.springframework.boot.amqp.testcontainers.RabbitContainerConnectionDetailsFactory,\\\norg.springframework.boot.amqp.testcontainers.RabbitStreamContainerConnectionDetailsFactory\n\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/PropertiesRabbitConnectionDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitConnectionDetails.Address;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PropertiesRabbitConnectionDetails}.\n *\n * @author Jonas Fügedi\n */\nclass PropertiesRabbitConnectionDetailsTests {\n\n\tprivate static final int DEFAULT_PORT = 5672;\n\n\tprivate DefaultSslBundleRegistry sslBundleRegistry;\n\n\tprivate RabbitProperties properties;\n\n\tprivate PropertiesRabbitConnectionDetails propertiesRabbitConnectionDetails;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new RabbitProperties();\n\t\tthis.sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tthis.propertiesRabbitConnectionDetails = new PropertiesRabbitConnectionDetails(this.properties,\n\t\t\t\tthis.sslBundleRegistry);\n\t}\n\n\t@Test\n\tvoid getAddresses() {\n\t\tthis.properties.setAddresses(List.of(\"localhost\", \"localhost:1234\", \"[::1]\", \"[::1]:32863\"));\n\t\tList<Address> addresses = this.propertiesRabbitConnectionDetails.getAddresses();\n\t\tassertThat(addresses.size()).isEqualTo(4);\n\t\tassertThat(addresses.get(0).host()).isEqualTo(\"localhost\");\n\t\tassertThat(addresses.get(0).port()).isEqualTo(DEFAULT_PORT);\n\t\tassertThat(addresses.get(1).host()).isEqualTo(\"localhost\");\n\t\tassertThat(addresses.get(1).port()).isEqualTo(1234);\n\t\tassertThat(addresses.get(2).host()).isEqualTo(\"[::1]\");\n\t\tassertThat(addresses.get(2).port()).isEqualTo(DEFAULT_PORT);\n\t\tassertThat(addresses.get(3).host()).isEqualTo(\"[::1]\");\n\t\tassertThat(addresses.get(3).port()).isEqualTo(32863);\n\t}\n\n\t@Test\n\tvoid shouldReturnSslBundle() {\n\t\tSslBundle bundle1 = mock(SslBundle.class);\n\t\tthis.sslBundleRegistry.registerBundle(\"bundle-1\", bundle1);\n\t\tthis.properties.getSsl().setBundle(\"bundle-1\");\n\t\tSslBundle sslBundle = this.propertiesRabbitConnectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isSameAs(bundle1);\n\t}\n\n\t@Test\n\tvoid shouldReturnNullIfSslIsEnabledButBundleNotSet() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tSslBundle sslBundle = this.propertiesRabbitConnectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNull();\n\t}\n\n\t@Test\n\tvoid shouldReturnNullIfSslIsNotEnabled() {\n\t\tthis.properties.getSsl().setEnabled(false);\n\t\tSslBundle sslBundle = this.propertiesRabbitConnectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/RabbitAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.BiFunction;\n\nimport javax.net.ssl.SSLSocketFactory;\n\nimport com.rabbitmq.client.Address;\nimport com.rabbitmq.client.Connection;\nimport com.rabbitmq.client.JDKSaslConfig;\nimport com.rabbitmq.client.impl.CredentialsProvider;\nimport com.rabbitmq.client.impl.CredentialsRefreshService;\nimport com.rabbitmq.client.impl.DefaultCredentialsProvider;\nimport org.aopalliance.aop.Advice;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport org.mockito.InOrder;\n\nimport org.springframework.amqp.core.AcknowledgeMode;\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.core.Message;\nimport org.springframework.amqp.core.MessageProperties;\nimport org.springframework.amqp.rabbit.annotation.EnableRabbit;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.config.ContainerCustomizer;\nimport org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;\nimport org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.AddressShuffleMode;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory.CacheMode;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionNameStrategy;\nimport org.springframework.amqp.rabbit.core.RabbitAdmin;\nimport org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;\nimport org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;\nimport org.springframework.amqp.rabbit.retry.MessageRecoverer;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitListenerObservation.DefaultRabbitListenerObservationConvention;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitListenerObservationConvention;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitTemplateObservation.DefaultRabbitTemplateObservationConvention;\nimport org.springframework.amqp.rabbit.support.micrometer.RabbitTemplateObservationConvention;\nimport org.springframework.amqp.support.converter.MessageConversionException;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.amqp.support.converter.SerializerMessageConverter;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.retry.RetryPolicy;\nimport org.springframework.core.retry.RetryTemplate;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.backoff.ExponentialBackOff;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isNull;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RabbitAutoConfiguration}.\n *\n * @author Greg Turnquist\n * @author Stephane Nicoll\n * @author Gary Russell\n * @author HaiTao Zhang\n * @author Franjo Zilic\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Yanming Zhou\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass RabbitAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RabbitAutoConfiguration.class, SslAutoConfiguration.class))\n\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.rabbit.stream\")); // gh-38750\n\n\t@Test\n\tvoid testDefaultRabbitConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\tRabbitMessagingTemplate messagingTemplate = context.getBean(RabbitMessagingTemplate.class);\n\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\tRabbitAdmin amqpAdmin = context.getBean(RabbitAdmin.class);\n\t\t\tassertThat(rabbitTemplate.getConnectionFactory()).isEqualTo(connectionFactory);\n\t\t\tassertThat(getMandatory(rabbitTemplate)).isFalse();\n\t\t\tassertThat(messagingTemplate.getRabbitTemplate()).isEqualTo(rabbitTemplate);\n\t\t\tassertThat(amqpAdmin).isNotNull();\n\t\t\tassertThat(connectionFactory.getHost()).isEqualTo(\"localhost\");\n\t\t\tassertThat(getTargetConnectionFactory(context).getRequestedChannelMax())\n\t\t\t\t.isEqualTo(com.rabbitmq.client.ConnectionFactory.DEFAULT_CHANNEL_MAX);\n\t\t\tassertThat(connectionFactory.isPublisherConfirms()).isFalse();\n\t\t\tassertThat(connectionFactory.isPublisherReturns()).isFalse();\n\t\t\tassertThat(connectionFactory.getRabbitConnectionFactory().getChannelRpcTimeout())\n\t\t\t\t.isEqualTo(com.rabbitmq.client.ConnectionFactory.DEFAULT_CHANNEL_RPC_TIMEOUT);\n\t\t\tassertThat(context.containsBean(\"rabbitListenerContainerFactory\"))\n\t\t\t\t.as(\"Listener container factory should be created by default\")\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultRabbitTemplateConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\tRabbitTemplate defaultRabbitTemplate = new RabbitTemplate();\n\t\t\tassertThat(rabbitTemplate.getRoutingKey()).isEqualTo(defaultRabbitTemplate.getRoutingKey());\n\t\t\tassertThat(rabbitTemplate.getExchange()).isEqualTo(defaultRabbitTemplate.getExchange());\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultConnectionFactoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tRabbitProperties properties = new RabbitProperties();\n\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\tassertThat(rabbitConnectionFactory.getUsername()).isEqualTo(properties.getUsername());\n\t\t\tassertThat(rabbitConnectionFactory.getPassword()).isEqualTo(properties.getPassword());\n\t\t\tassertThat(rabbitConnectionFactory).extracting(\"maxInboundMessageBodySize\")\n\t\t\t\t.isEqualTo((int) properties.getMaxInboundMessageBodySize().toBytes());\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testConnectionFactoryWithOverrides() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.host:remote-server\", \"spring.rabbitmq.port:9000\",\n\t\t\t\t\t\"spring.rabbitmq.address-shuffle-mode=random\", \"spring.rabbitmq.username:alice\",\n\t\t\t\t\t\"spring.rabbitmq.password:secret\", \"spring.rabbitmq.virtual_host:/vhost\",\n\t\t\t\t\t\"spring.rabbitmq.connection-timeout:123\", \"spring.rabbitmq.channel-rpc-timeout:140\",\n\t\t\t\t\t\"spring.rabbitmq.max-inbound-message-body-size:128MB\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getHost()).isEqualTo(\"remote-server\");\n\t\t\t\tassertThat(connectionFactory.getPort()).isEqualTo(9000);\n\t\t\t\tassertThat(connectionFactory).hasFieldOrPropertyWithValue(\"addressShuffleMode\",\n\t\t\t\t\t\tAddressShuffleMode.RANDOM);\n\t\t\t\tassertThat(connectionFactory.getVirtualHost()).isEqualTo(\"/vhost\");\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rcf = connectionFactory.getRabbitConnectionFactory();\n\t\t\t\tassertThat(rcf.getConnectionTimeout()).isEqualTo(123);\n\t\t\t\tassertThat(rcf.getChannelRpcTimeout()).isEqualTo(140);\n\t\t\t\tassertThat((List<Address>) ReflectionTestUtils.getField(connectionFactory, \"addresses\")).hasSize(1);\n\t\t\t\tassertThat(rcf).hasFieldOrPropertyWithValue(\"maxInboundMessageBodySize\", 1024 * 1024 * 128);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesRabbitConnectionDetails.class));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class, ConnectionDetailsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.host:remote-server\", \"spring.rabbitmq.port:9000\",\n\t\t\t\t\t\"spring.rabbitmq.username:alice\", \"spring.rabbitmq.password:secret\",\n\t\t\t\t\t\"spring.rabbitmq.virtual_host:/vhost\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RabbitConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesRabbitConnectionDetails.class);\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getHost()).isEqualTo(\"rabbit.example.com\");\n\t\t\t\tassertThat(connectionFactory.getPort()).isEqualTo(12345);\n\t\t\t\tassertThat(connectionFactory.getVirtualHost()).isEqualTo(\"/vhost-1\");\n\t\t\t\tassertThat(connectionFactory.getUsername()).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(connectionFactory.getRabbitConnectionFactory().getPassword()).isEqualTo(\"password-1\");\n\t\t\t\tList<Address> addresses = (List<Address>) ReflectionTestUtils.getField(connectionFactory, \"addresses\");\n\t\t\t\tassertThat(addresses).containsExactly(new Address(\"rabbit.example.com\", 12345),\n\t\t\t\t\t\tnew Address(\"rabbit2.example.com\", 23456));\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testConnectionFactoryWithCustomConnectionNameStrategy() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionNameStrategyConfiguration.class).run((context) -> {\n\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\tList<Address> addresses = (List<Address>) ReflectionTestUtils.getField(connectionFactory, \"addresses\");\n\t\t\tassertThat(addresses).hasSize(1);\n\t\t\tcom.rabbitmq.client.ConnectionFactory rcf = mock(com.rabbitmq.client.ConnectionFactory.class);\n\t\t\tgiven(rcf.newConnection(isNull(), eq(addresses), anyString())).willReturn(mock(Connection.class));\n\t\t\tReflectionTestUtils.setField(connectionFactory, \"rabbitConnectionFactory\", rcf);\n\t\t\ttry (org.springframework.amqp.rabbit.connection.Connection connection = connectionFactory\n\t\t\t\t.createConnection()) {\n\t\t\t\tthen(rcf).should().newConnection(isNull(), eq(addresses), eq(\"test#0\"));\n\t\t\t}\n\t\t\tconnectionFactory.resetConnection();\n\t\t\ttry (org.springframework.amqp.rabbit.connection.Connection connection = connectionFactory\n\t\t\t\t.createConnection()) {\n\t\t\t\tthen(rcf).should().newConnection(isNull(), eq(addresses), eq(\"test#1\"));\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryEmptyVirtualHost() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.virtual_host:\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getVirtualHost()).isEqualTo(\"/\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryVirtualHostNoLeadingSlash() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.virtual_host:foo\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getVirtualHost()).isEqualTo(\"foo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryVirtualHostMultiLeadingSlashes() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.virtual_host:///foo\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getVirtualHost()).isEqualTo(\"///foo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryDefaultVirtualHost() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.virtual_host:/\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getVirtualHost()).isEqualTo(\"/\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryPublisherConfirmTypeCorrelated() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.publisher-confirm-type=correlated\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.isPublisherConfirms()).isTrue();\n\t\t\t\tassertThat(connectionFactory.isSimplePublisherConfirms()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryPublisherConfirmTypeSimple() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.publisher-confirm-type=simple\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.isPublisherConfirms()).isFalse();\n\t\t\t\tassertThat(connectionFactory.isSimplePublisherConfirms()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryPublisherReturns() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.publisher-returns=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(connectionFactory.isPublisherReturns()).isTrue();\n\t\t\t\tassertThat(getMandatory(rabbitTemplate)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateMessageConverters() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class).run((context) -> {\n\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\tassertThat(rabbitTemplate.getMessageConverter()).isSameAs(context.getBean(\"myMessageConverter\"));\n\t\t\tassertThat(rabbitTemplate).hasFieldOrPropertyWithValue(\"retryTemplate\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureRabbitTemplateObservationConvention() {\n\t\tRabbitTemplateObservationConvention convention = new DefaultRabbitTemplateObservationConvention();\n\t\tthis.contextRunner.withBean(RabbitTemplateObservationConvention.class, () -> convention).run((context) -> {\n\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\tassertThat(rabbitTemplate).hasFieldOrPropertyWithValue(\"observationConvention\", convention);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateRetry() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.retry.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.template.retry.max-retries:4\",\n\t\t\t\t\t\"spring.rabbitmq.template.retry.initial-interval:2000\",\n\t\t\t\t\t\"spring.rabbitmq.template.retry.multiplier:1.5\", \"spring.rabbitmq.template.retry.max-interval:5000\",\n\t\t\t\t\t\"spring.rabbitmq.template.receive-timeout:123\", \"spring.rabbitmq.template.reply-timeout:456\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(rabbitTemplate).hasFieldOrPropertyWithValue(\"receiveTimeout\", 123L);\n\t\t\t\tassertThat(rabbitTemplate).hasFieldOrPropertyWithValue(\"replyTimeout\", 456L);\n\t\t\t\tRetryTemplate retryTemplate = (RetryTemplate) ReflectionTestUtils.getField(rabbitTemplate,\n\t\t\t\t\t\t\"retryTemplate\");\n\t\t\t\tassertThat(retryTemplate).isNotNull();\n\t\t\t\tRetryPolicy retryPolicy = (RetryPolicy) ReflectionTestUtils.getField(retryTemplate, \"retryPolicy\");\n\t\t\t\tassertThat(retryPolicy).isNotNull();\n\t\t\t\tassertThat(retryPolicy.getBackOff()).isInstanceOfSatisfying(ExponentialBackOff.class, (backOff) -> {\n\t\t\t\t\tassertThat(backOff.getMaxAttempts()).isEqualTo(4);\n\t\t\t\t\tassertThat(backOff.getInitialInterval()).isEqualTo(2000);\n\t\t\t\t\tassertThat(backOff.getMultiplier()).isEqualTo(1.5);\n\t\t\t\t\tassertThat(backOff.getMaxInterval()).isEqualTo(5000);\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateRetryWithCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(RabbitRetryTemplateCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.retry.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.template.retry.initial-interval:2000\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tRetryTemplate retryTemplate = (RetryTemplate) ReflectionTestUtils.getField(rabbitTemplate,\n\t\t\t\t\t\t\"retryTemplate\");\n\t\t\t\tassertThat(retryTemplate).isNotNull();\n\t\t\t\tRetryPolicy retryPolicy = (RetryPolicy) ReflectionTestUtils.getField(retryTemplate, \"retryPolicy\");\n\t\t\t\tassertThat(retryPolicy).isNotNull();\n\t\t\t\tassertThat(retryPolicy.getBackOff()).isInstanceOfSatisfying(ExponentialBackOff.class, (backOff) -> {\n\t\t\t\t\tassertThat(backOff.getInitialInterval()).isEqualTo(2000);\n\t\t\t\t\tassertThat(backOff.getMultiplier()).isEqualTo(1.4);\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateExchangeAndRoutingKey() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.exchange:my-exchange\",\n\t\t\t\t\t\"spring.rabbitmq.template.routing-key:my-routing-key\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(rabbitTemplate.getExchange()).isEqualTo(\"my-exchange\");\n\t\t\t\tassertThat(rabbitTemplate.getRoutingKey()).isEqualTo(\"my-routing-key\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureObservationEnabledOnTemplate() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.observation-enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(rabbitTemplate).extracting(\"observationEnabled\", InstanceOfAssertFactories.BOOLEAN).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateDefaultReceiveQueue() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.default-receive-queue:default-queue\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(rabbitTemplate).hasFieldOrPropertyWithValue(\"defaultReceiveQueue\", \"default-queue\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateMandatory() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.mandatory:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(getMandatory(rabbitTemplate)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateMandatoryDisabledEvenIfPublisherReturnsIsSet() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.mandatory:false\", \"spring.rabbitmq.publisher-returns=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\t\tassertThat(getMandatory(rabbitTemplate)).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateConfigurersIsAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RabbitTemplateConfigurer.class));\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateConfigurerUsesConfig() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.exchange:my-exchange\",\n\t\t\t\t\t\"spring.rabbitmq.template.routing-key:my-routing-key\",\n\t\t\t\t\t\"spring.rabbitmq.template.default-receive-queue:default-queue\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplateConfigurer configurer = context.getBean(RabbitTemplateConfigurer.class);\n\t\t\t\tRabbitTemplate template = mock(RabbitTemplate.class);\n\t\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\t\tconfigurer.configure(template, connectionFactory);\n\t\t\t\tthen(template).should()\n\t\t\t\t\t.setMessageConverter(context.getBean(\"myMessageConverter\", MessageConverter.class));\n\t\t\t\tthen(template).should().setExchange(\"my-exchange\");\n\t\t\t\tthen(template).should().setRoutingKey(\"my-routing-key\");\n\t\t\t\tthen(template).should().setDefaultReceiveQueue(\"default-queue\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenMultipleRabbitTemplateCustomizersAreDefinedThenTheyAreCalledInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleRabbitTemplateCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitTemplateCustomizer firstCustomizer = context.getBean(\"firstCustomizer\",\n\t\t\t\t\t\tRabbitTemplateCustomizer.class);\n\t\t\t\tRabbitTemplateCustomizer secondCustomizer = context.getBean(\"secondCustomizer\",\n\t\t\t\t\t\tRabbitTemplateCustomizer.class);\n\t\t\t\tInOrder inOrder = inOrder(firstCustomizer, secondCustomizer);\n\t\t\t\tRabbitTemplate template = context.getBean(RabbitTemplate.class);\n\t\t\t\tthen(firstCustomizer).should(inOrder).customize(template);\n\t\t\t\tthen(secondCustomizer).should(inOrder).customize(template);\n\t\t\t\tinOrder.verifyNoMoreInteractions();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration2.class).run((context) -> {\n\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\tassertThat(connectionFactory).isEqualTo(rabbitTemplate.getConnectionFactory());\n\t\t\tassertThat(connectionFactory.getHost()).isEqualTo(\"otherserver\");\n\t\t\tassertThat(connectionFactory.getPort()).isEqualTo(8001);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryCacheSettings() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.cache.channel.size=23\",\n\t\t\t\t\t\"spring.rabbitmq.cache.channel.checkout-timeout=1000\",\n\t\t\t\t\t\"spring.rabbitmq.cache.connection.mode=CONNECTION\", \"spring.rabbitmq.cache.connection.size=2\")\n\t\t\t.run((context) -> {\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getChannelCacheSize()).isEqualTo(23);\n\t\t\t\tassertThat(connectionFactory.getCacheMode()).isEqualTo(CacheMode.CONNECTION);\n\t\t\t\tassertThat(connectionFactory.getConnectionCacheSize()).isEqualTo(2);\n\t\t\t\tassertThat(connectionFactory).hasFieldOrPropertyWithValue(\"channelCheckoutTimeout\", 1000L);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitTemplateBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration3.class).run((context) -> {\n\t\t\tRabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);\n\t\t\tassertThat(rabbitTemplate.getMessageConverter()).isEqualTo(context.getBean(\"testMessageConverter\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitMessagingTemplateBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration4.class).run((context) -> {\n\t\t\tRabbitMessagingTemplate messagingTemplate = context.getBean(RabbitMessagingTemplate.class);\n\t\t\tassertThat(messagingTemplate.getDefaultDestination()).isEqualTo(\"fooBar\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testStaticQueues() {\n\t\t// There should NOT be an AmqpAdmin bean when dynamic is switch to false\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.dynamic:false\")\n\t\t\t.run((context) -> assertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t\t.isThrownBy(() -> context.getBean(AmqpAdmin.class))\n\t\t\t\t.withMessageContaining(\"No qualifying bean of type '\" + AmqpAdmin.class.getName() + \"'\"));\n\t}\n\n\t@Test\n\tvoid testEnableRabbitCreateDefaultContainerFactory() {\n\t\tthis.contextRunner.withUserConfiguration(EnableRabbitConfiguration.class).run((context) -> {\n\t\t\tRabbitListenerContainerFactory<?> rabbitListenerContainerFactory = context\n\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", RabbitListenerContainerFactory.class);\n\t\t\tassertThat(rabbitListenerContainerFactory.getClass()).isEqualTo(SimpleRabbitListenerContainerFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitListenerContainerFactoryBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration5.class).run((context) -> {\n\t\t\tSimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context\n\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", SimpleRabbitListenerContainerFactory.class);\n\t\t\trabbitListenerContainerFactory.setBatchSize(10);\n\t\t\tthen(rabbitListenerContainerFactory).should().setBatchSize(10);\n\t\t\tassertThat(rabbitListenerContainerFactory.getAdviceChain()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testSimpleRabbitListenerContainerFactoryWithCustomSettings() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(MessageConvertersConfiguration.class, MessageRecoverersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.simple.retry.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.retry.max-retries:4\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.retry.initial-interval:2000\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.retry.multiplier:1.5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.retry.max-interval:5000\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.auto-startup:false\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.acknowledge-mode:manual\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.concurrency:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.max-concurrency:10\", \"spring.rabbitmq.listener.simple.prefetch:40\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.default-requeue-rejected:false\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.idle-event-interval:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.batch-size:20\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.missing-queues-fatal:false\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.force-stop:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.observation-enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context\n\t\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", SimpleRabbitListenerContainerFactory.class);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"concurrentConsumers\", 5);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"maxConcurrentConsumers\", 10);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"batchSize\", 20);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"missingQueuesFatal\", false);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"observationEnabled\", true);\n\t\t\t\tcheckCommonProps(context, rabbitListenerContainerFactory);\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldConfigureVirtualThreadsForSimpleListener() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tSimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context\n\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", SimpleRabbitListenerContainerFactory.class);\n\t\t\tassertThat(rabbitListenerContainerFactory).extracting(\"taskExecutor\")\n\t\t\t\t.isInstanceOf(VirtualThreadTaskExecutor.class);\n\t\t\tObject taskExecutor = ReflectionTestUtils.getField(rabbitListenerContainerFactory, \"taskExecutor\");\n\t\t\tassertThat(taskExecutor).isNotNull();\n\t\t\tObject virtualThread = ReflectionTestUtils.getField(taskExecutor, \"virtualThreadFactory\");\n\t\t\tassertThat(virtualThread).isNotNull();\n\t\t\tThread threadCreated = ((ThreadFactory) virtualThread).newThread(mock(Runnable.class));\n\t\t\tassertThat(threadCreated.getName()).containsPattern(\"rabbit-simple-[0-9]+\");\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldConfigureVirtualThreadsForDirectListener() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tDirectRabbitListenerContainerFactoryConfigurer rabbitListenerContainerFactory = context.getBean(\n\t\t\t\t\t\"directRabbitListenerContainerFactoryConfigurer\",\n\t\t\t\t\tDirectRabbitListenerContainerFactoryConfigurer.class);\n\t\t\tassertThat(rabbitListenerContainerFactory).extracting(\"taskExecutor\")\n\t\t\t\t.isInstanceOf(VirtualThreadTaskExecutor.class);\n\t\t\tObject taskExecutor = ReflectionTestUtils.getField(rabbitListenerContainerFactory, \"taskExecutor\");\n\t\t\tassertThat(taskExecutor).isNotNull();\n\t\t\tObject virtualThread = ReflectionTestUtils.getField(taskExecutor, \"virtualThreadFactory\");\n\t\t\tassertThat(virtualThread).isNotNull();\n\t\t\tThread threadCreated = ((ThreadFactory) virtualThread).newThread(mock(Runnable.class));\n\t\t\tassertThat(threadCreated.getName()).containsPattern(\"rabbit-direct-[0-9]+\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureRabbitListenerObservationConvention() {\n\t\tRabbitListenerObservationConvention convention = new DefaultRabbitListenerObservationConvention();\n\t\tthis.contextRunner.withBean(RabbitListenerObservationConvention.class, () -> convention).run((context) -> {\n\t\t\tSimpleRabbitListenerContainerFactory listenerFactory = context.getBean(\"rabbitListenerContainerFactory\",\n\t\t\t\t\tSimpleRabbitListenerContainerFactory.class);\n\t\t\tassertThat(listenerFactory).hasFieldOrPropertyWithValue(\"observationConvention\", convention);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testSimpleRabbitListenerContainerFactoryWithDefaultForceStop() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(MessageConvertersConfiguration.class, MessageRecoverersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleRabbitListenerContainerFactory containerFactory = context\n\t\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", SimpleRabbitListenerContainerFactory.class);\n\t\t\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"forceStop\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDirectRabbitListenerContainerFactoryWithCustomSettings() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(MessageConvertersConfiguration.class, MessageRecoverersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:direct\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.max-retries:4\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.initial-interval:2000\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.multiplier:1.5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.max-interval:5000\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.auto-startup:false\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.acknowledge-mode:manual\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.consumers-per-queue:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.prefetch:40\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.default-requeue-rejected:false\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.idle-event-interval:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.missing-queues-fatal:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.force-stop:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.observation-enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tDirectRabbitListenerContainerFactory rabbitListenerContainerFactory = context\n\t\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", DirectRabbitListenerContainerFactory.class);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"consumersPerQueue\", 5);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"missingQueuesFatal\", true);\n\t\t\t\tassertThat(rabbitListenerContainerFactory).hasFieldOrPropertyWithValue(\"observationEnabled\", true);\n\t\t\t\tcheckCommonProps(context, rabbitListenerContainerFactory);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDirectRabbitListenerContainerFactoryWithDefaultForceStop() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(MessageConvertersConfiguration.class, MessageRecoverersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:direct\")\n\t\t\t.run((context) -> {\n\t\t\t\tDirectRabbitListenerContainerFactory containerFactory = context\n\t\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", DirectRabbitListenerContainerFactory.class);\n\t\t\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"forceStop\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testSimpleRabbitListenerContainerFactoryRetryWithCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(RabbitRetryTemplateCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.simple.retry.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.retry.max-retries:4\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleRabbitListenerContainerFactory rabbitListenerContainerFactory = context\n\t\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", SimpleRabbitListenerContainerFactory.class);\n\t\t\t\tassertListenerRetryTemplate(rabbitListenerContainerFactory,\n\t\t\t\t\t\tcontext.getBean(RabbitRetryTemplateCustomizerConfiguration.class).retryPolicy);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDirectRabbitListenerContainerFactoryRetryWithCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(RabbitRetryTemplateCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:direct\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.retry.max-retries:4\")\n\t\t\t.run((context) -> {\n\t\t\t\tDirectRabbitListenerContainerFactory rabbitListenerContainerFactory = context\n\t\t\t\t\t.getBean(\"rabbitListenerContainerFactory\", DirectRabbitListenerContainerFactory.class);\n\t\t\t\tassertListenerRetryTemplate(rabbitListenerContainerFactory,\n\t\t\t\t\t\tcontext.getBean(RabbitRetryTemplateCustomizerConfiguration.class).retryPolicy);\n\t\t\t});\n\t}\n\n\tprivate void assertListenerRetryTemplate(AbstractRabbitListenerContainerFactory<?> rabbitListenerContainerFactory,\n\t\t\tRetryPolicy retryPolicy) {\n\t\tAdvice[] adviceChain = rabbitListenerContainerFactory.getAdviceChain();\n\t\tassertThat(adviceChain).isNotNull();\n\t\tassertThat(adviceChain).hasSize(1);\n\t\tAdvice advice = adviceChain[0];\n\t\tRetryTemplate retryTemplate = (RetryTemplate) ReflectionTestUtils.getField(advice, \"retryOperations\");\n\t\tassertThat(retryTemplate).hasFieldOrPropertyWithValue(\"retryPolicy\", retryPolicy);\n\t}\n\n\t@Test\n\tvoid testRabbitListenerContainerFactoryConfigurersAreAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.simple.concurrency:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.max-concurrency:10\", \"spring.rabbitmq.listener.simple.prefetch:40\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.consumers-per-queue:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.prefetch:40\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SimpleRabbitListenerContainerFactoryConfigurer.class);\n\t\t\t\tassertThat(context).hasSingleBean(DirectRabbitListenerContainerFactoryConfigurer.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testSimpleRabbitListenerContainerFactoryConfigurerUsesConfig() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.simple.concurrency:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.simple.max-concurrency:10\", \"spring.rabbitmq.listener.simple.prefetch:40\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleRabbitListenerContainerFactoryConfigurer configurer = context\n\t\t\t\t\t.getBean(SimpleRabbitListenerContainerFactoryConfigurer.class);\n\t\t\t\tSimpleRabbitListenerContainerFactory factory = mock(SimpleRabbitListenerContainerFactory.class);\n\t\t\t\tconfigurer.configure(factory, mock(ConnectionFactory.class));\n\t\t\t\tthen(factory).should().setConcurrentConsumers(5);\n\t\t\t\tthen(factory).should().setMaxConcurrentConsumers(10);\n\t\t\t\tthen(factory).should().setPrefetchCount(40);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testSimpleRabbitListenerContainerFactoryConfigurerEnableDeBatchingWithConsumerBatchEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.simple.consumer-batch-enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleRabbitListenerContainerFactoryConfigurer configurer = context\n\t\t\t\t\t.getBean(SimpleRabbitListenerContainerFactoryConfigurer.class);\n\t\t\t\tSimpleRabbitListenerContainerFactory factory = mock(SimpleRabbitListenerContainerFactory.class);\n\t\t\t\tconfigurer.configure(factory, mock(ConnectionFactory.class));\n\t\t\t\tthen(factory).should().setConsumerBatchEnabled(true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDirectRabbitListenerContainerFactoryConfigurerUsesConfig() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.direct.consumers-per-queue:5\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.prefetch:40\",\n\t\t\t\t\t\"spring.rabbitmq.listener.direct.de-batching-enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tDirectRabbitListenerContainerFactoryConfigurer configurer = context\n\t\t\t\t\t.getBean(DirectRabbitListenerContainerFactoryConfigurer.class);\n\t\t\t\tDirectRabbitListenerContainerFactory factory = mock(DirectRabbitListenerContainerFactory.class);\n\t\t\t\tconfigurer.configure(factory, mock(ConnectionFactory.class));\n\t\t\t\tthen(factory).should().setConsumersPerQueue(5);\n\t\t\t\tthen(factory).should().setPrefetchCount(40);\n\t\t\t\tthen(factory).should().setDeBatchingEnabled(false);\n\t\t\t});\n\t}\n\n\tprivate void checkCommonProps(AssertableApplicationContext context,\n\t\t\tAbstractRabbitListenerContainerFactory<?> containerFactory) {\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"autoStartup\", Boolean.FALSE);\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"acknowledgeMode\", AcknowledgeMode.MANUAL);\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"prefetchCount\", 40);\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"messageConverter\",\n\t\t\t\tcontext.getBean(\"myMessageConverter\"));\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"defaultRequeueRejected\", Boolean.FALSE);\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"idleEventInterval\", 5L);\n\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"forceStop\", true);\n\t\tAdvice[] adviceChain = containerFactory.getAdviceChain();\n\t\tassertThat(adviceChain).isNotNull();\n\t\tassertThat(adviceChain).hasSize(1);\n\t\tAdvice advice = adviceChain[0];\n\t\tMessageRecoverer messageRecoverer = context.getBean(\"myMessageRecoverer\", MessageRecoverer.class);\n\t\tMessage message = mock(Message.class);\n\t\tException cause = new Exception(\"test\");\n\t\tinvokeRecoverer(advice, new Object[] { \"foo\", message }, cause);\n\t\tthen(messageRecoverer).should().recover(message, cause);\n\t\tRetryTemplate retryTemplate = (RetryTemplate) ReflectionTestUtils.getField(advice, \"retryOperations\");\n\t\tassertThat(retryTemplate).isNotNull();\n\t\tRetryPolicy retryPolicy = (RetryPolicy) ReflectionTestUtils.getField(retryTemplate, \"retryPolicy\");\n\t\tassertThat(retryPolicy).isNotNull();\n\t\tassertThat(retryPolicy.getBackOff()).isInstanceOfSatisfying(ExponentialBackOff.class, (backOff) -> {\n\t\t\tassertThat(backOff.getMaxAttempts()).isEqualTo(4);\n\t\t\tassertThat(backOff.getInitialInterval()).isEqualTo(2000);\n\t\t\tassertThat(backOff.getMultiplier()).isEqualTo(1.5);\n\t\t\tassertThat(backOff.getMaxInterval()).isEqualTo(5000);\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Object invokeRecoverer(Advice advice, Object[] args, Throwable cause) {\n\t\tBiFunction<Object[], Throwable, Object> recoverer = (BiFunction<Object[], Throwable, Object>) ReflectionTestUtils\n\t\t\t.getField(advice, \"recoverer\");\n\t\tassertThat(recoverer).isNotNull();\n\t\treturn recoverer.apply(args, cause);\n\t}\n\n\t@Test\n\tvoid enableRabbitAutomatically() {\n\t\tthis.contextRunner.withUserConfiguration(NoEnableRabbitConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME);\n\t\t\tassertThat(context).hasBean(RabbitListenerConfigUtils.RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customizeRequestedHeartBeat() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.requested-heartbeat:20\")\n\t\t\t.run((context) -> {\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tassertThat(rabbitConnectionFactory.getRequestedHeartbeat()).isEqualTo(20);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizeRequestedChannelMax() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.requested-channel-max:12\")\n\t\t\t.run((context) -> {\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tassertThat(rabbitConnectionFactory.getRequestedChannelMax()).isEqualTo(12);\n\t\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(classes = { TestConfiguration.class, TestConfiguration6.class })\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeAllowedListPatterns(Class<?> configuration) {\n\t\tthis.contextRunner.withUserConfiguration(configuration)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.allowed-list-patterns:*\")\n\t\t\t.run((context) -> {\n\t\t\t\tMessageConverter messageConverter = context.getBean(RabbitTemplate.class).getMessageConverter();\n\t\t\t\tassertThat(messageConverter).extracting(\"allowedListPatterns\")\n\t\t\t\t\t.isInstanceOfSatisfying(Collection.class, (set) -> assertThat(set).contains(\"*\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizeAllowedListPatternsWhenHasNoAllowedListDeserializingMessageConverter() {\n\t\tthis.contextRunner.withUserConfiguration(CustomMessageConverterConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.template.allowed-list-patterns:*\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.hasRootCauseInstanceOf(InvalidConfigurationPropertyValueException.class));\n\t}\n\n\t@Test\n\tvoid noSslByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\tassertThat(rabbitConnectionFactory.getSocketFactory()).isNull();\n\t\t\tassertThat(rabbitConnectionFactory.isSSL()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableSsl() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tassertThat(rabbitConnectionFactory.isSSL()).isTrue();\n\t\t\t\tassertThat(rabbitConnectionFactory.getSocketFactory()).as(\"SocketFactory must use SSL\")\n\t\t\t\t\t.isInstanceOf(SSLSocketFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithInvalidSslBundleFails() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.bundle=invalid\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"SSL bundle name 'invalid' cannot be found\");\n\t\t\t});\n\t}\n\n\t@Test\n\t// Make sure that we at least attempt to load the store\n\tvoid enableSslWithNonExistingKeystoreShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\", \"spring.rabbitmq.ssl.key-store=foo\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"foo\");\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"does not exist\");\n\t\t\t});\n\t}\n\n\t@Test\n\t// Make sure that we at least attempt to load the store\n\tvoid enableSslWithNonExistingTrustStoreShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\", \"spring.rabbitmq.ssl.trust-store=bar\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"bar\");\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"does not exist\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithInvalidKeystoreTypeShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\", \"spring.rabbitmq.ssl.key-store=foo\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-type=fooType\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"fooType\");\n\t\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(NoSuchAlgorithmException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithInvalidTrustStoreTypeShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\", \"spring.rabbitmq.ssl.trust-store=bar\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-type=barType\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"barType\");\n\t\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(NoSuchAlgorithmException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithBundle() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.bundle=test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tassertThat(rabbitConnectionFactory.isSSL()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithKeystoreTypeAndTrustStoreTypeShouldWork() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store=/org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-type=jks\", \"spring.rabbitmq.ssl.key-store-password=secret\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store=/org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-type=jks\", \"spring.rabbitmq.ssl.trust-store-password=secret\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid enableSslWithValidateServerCertificateFalse(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.validate-server-certificate=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tassertThat(rabbitConnectionFactory.isSSL()).isTrue();\n\t\t\t\tassertThat(output).contains(\"TrustEverythingTrustManager\", \"SECURITY ALERT\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithValidateServerCertificateDefault(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tassertThat(rabbitConnectionFactory.isSSL()).isTrue();\n\t\t\t\tassertThat(output).doesNotContain(\"TrustEverythingTrustManager\", \"SECURITY ALERT\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithValidStoreAlgorithmShouldWork() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store=/org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-type=jks\", \"spring.rabbitmq.ssl.key-store-password=secret\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-algorithm=PKIX\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store=/org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-type=jks\", \"spring.rabbitmq.ssl.trust-store-password=secret\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-algorithm=PKIX\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid enableSslWithInvalidKeyStoreAlgorithmShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store=/org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-type=jks\", \"spring.rabbitmq.ssl.key-store-password=secret\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.key-store-algorithm=test-invalid-algo\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"test-invalid-algo\");\n\t\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(NoSuchAlgorithmException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSslWithInvalidTrustStoreAlgorithmShouldFail() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.ssl.enabled:true\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store=/org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-type=jks\", \"spring.rabbitmq.ssl.trust-store-password=secret\",\n\t\t\t\t\t\"spring.rabbitmq.ssl.trust-store-algorithm=test-invalid-algo\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"test-invalid-algo\");\n\t\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(NoSuchAlgorithmException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenACredentialsProviderIsAvailableThenConnectionFactoryIsConfiguredToUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(CredentialsProviderConfiguration.class)\n\t\t\t.run((context) -> assertThat(getTargetConnectionFactory(context).params(null).getCredentialsProvider())\n\t\t\t\t.isEqualTo(CredentialsProviderConfiguration.credentialsProvider));\n\t}\n\n\t@Test\n\tvoid whenAPrimaryCredentialsProviderIsAvailableThenConnectionFactoryIsConfiguredToUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(PrimaryCredentialsProviderConfiguration.class)\n\t\t\t.run((context) -> assertThat(getTargetConnectionFactory(context).params(null).getCredentialsProvider())\n\t\t\t\t.isEqualTo(PrimaryCredentialsProviderConfiguration.credentialsProvider));\n\t}\n\n\t@Test\n\tvoid whenMultipleCredentialsProvidersAreAvailableThenConnectionFactoryUsesDefaultProvider() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleCredentialsProvidersConfiguration.class)\n\t\t\t.run((context) -> assertThat(getTargetConnectionFactory(context).params(null).getCredentialsProvider())\n\t\t\t\t.isInstanceOf(DefaultCredentialsProvider.class));\n\t}\n\n\t@Test\n\tvoid whenACredentialsRefreshServiceIsAvailableThenConnectionFactoryIsConfiguredToUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(CredentialsRefreshServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tgetTargetConnectionFactory(context).params(null).getCredentialsRefreshService())\n\t\t\t\t.isEqualTo(CredentialsRefreshServiceConfiguration.credentialsRefreshService));\n\t}\n\n\t@Test\n\tvoid whenAPrimaryCredentialsRefreshServiceIsAvailableThenConnectionFactoryIsConfiguredToUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(PrimaryCredentialsRefreshServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tgetTargetConnectionFactory(context).params(null).getCredentialsRefreshService())\n\t\t\t\t.isEqualTo(PrimaryCredentialsRefreshServiceConfiguration.credentialsRefreshService));\n\t}\n\n\t@Test\n\tvoid whenMultipleCredentialsRefreshServiceAreAvailableThenConnectionFactoryHasNoCredentialsRefreshService() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleCredentialsRefreshServicesConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tgetTargetConnectionFactory(context).params(null).getCredentialsRefreshService())\n\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid whenAConnectionFactoryCustomizerIsDefinedThenItCustomizesTheConnectionFactory() {\n\t\tthis.contextRunner.withUserConfiguration(SaslConfigCustomizerConfiguration.class)\n\t\t\t.run((context) -> assertThat(getTargetConnectionFactory(context).getSaslConfig())\n\t\t\t\t.isInstanceOf(JDKSaslConfig.class));\n\t}\n\n\t@Test\n\tvoid whenMultipleConnectionFactoryCustomizersAreDefinedThenTheyAreCalledInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleConnectionFactoryCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConnectionFactoryCustomizer firstCustomizer = context.getBean(\"firstCustomizer\",\n\t\t\t\t\t\tConnectionFactoryCustomizer.class);\n\t\t\t\tConnectionFactoryCustomizer secondCustomizer = context.getBean(\"secondCustomizer\",\n\t\t\t\t\t\tConnectionFactoryCustomizer.class);\n\t\t\t\tInOrder inOrder = inOrder(firstCustomizer, secondCustomizer);\n\t\t\t\tcom.rabbitmq.client.ConnectionFactory targetConnectionFactory = getTargetConnectionFactory(context);\n\t\t\t\tthen(firstCustomizer).should(inOrder).customize(targetConnectionFactory);\n\t\t\t\tthen(secondCustomizer).should(inOrder).customize(targetConnectionFactory);\n\t\t\t\tinOrder.verifyNoMoreInteractions();\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid whenASimpleContainerCustomizerIsDefinedThenItIsCalledToConfigureTheContainer() {\n\t\tthis.contextRunner.withUserConfiguration(SimpleContainerCustomizerConfiguration.class)\n\t\t\t.run((context) -> then(context.getBean(ContainerCustomizer.class)).should()\n\t\t\t\t.configure(any(SimpleMessageListenerContainer.class)));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid whenADirectContainerCustomizerIsDefinedThenItIsCalledToConfigureTheContainer() {\n\t\tthis.contextRunner.withUserConfiguration(DirectContainerCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:direct\")\n\t\t\t.run((context) -> then(context.getBean(ContainerCustomizer.class)).should()\n\t\t\t\t.configure(any(DirectMessageListenerContainer.class)));\n\t}\n\n\tprivate com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory(AssertableApplicationContext context) {\n\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\treturn connectionFactory.getRabbitConnectionFactory();\n\t}\n\n\tprivate boolean getMandatory(RabbitTemplate rabbitTemplate) {\n\t\treturn rabbitTemplate.isMandatoryFor(mock(Message.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration2 {\n\n\t\t@Bean\n\t\tConnectionFactory aDifferentConnectionFactory() {\n\t\t\treturn new CachingConnectionFactory(\"otherserver\", 8001);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration3 {\n\n\t\t@Bean\n\t\tRabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {\n\t\t\tRabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);\n\t\t\trabbitTemplate.setMessageConverter(messageConverter);\n\t\t\treturn rabbitTemplate;\n\t\t}\n\n\t\t@Bean\n\t\tMessageConverter testMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration4 {\n\n\t\t@Bean\n\t\tRabbitMessagingTemplate messagingTemplate(RabbitTemplate rabbitTemplate) {\n\t\t\tRabbitMessagingTemplate messagingTemplate = new RabbitMessagingTemplate(rabbitTemplate);\n\t\t\tmessagingTemplate.setDefaultDestination(\"fooBar\");\n\t\t\treturn messagingTemplate;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration5 {\n\n\t\t@Bean\n\t\tRabbitListenerContainerFactory<?> rabbitListenerContainerFactory() {\n\t\t\treturn mock(SimpleRabbitListenerContainerFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration6 {\n\n\t\t@Bean\n\t\tMessageConverter messageConverter() {\n\t\t\treturn new SerializerMessageConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MessageConvertersConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tMessageConverter myMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t\t@Bean\n\t\tMessageConverter anotherMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MessageRecoverersConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tMessageRecoverer myMessageRecoverer() {\n\t\t\treturn mock(MessageRecoverer.class);\n\t\t}\n\n\t\t@Bean\n\t\tMessageRecoverer anotherMessageRecoverer() {\n\t\t\treturn mock(MessageRecoverer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleRabbitTemplateCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(Ordered.LOWEST_PRECEDENCE)\n\t\tRabbitTemplateCustomizer secondCustomizer() {\n\t\t\treturn mock(RabbitTemplateCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tRabbitTemplateCustomizer firstCustomizer() {\n\t\t\treturn mock(RabbitTemplateCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionNameStrategyConfiguration {\n\n\t\tprivate final AtomicInteger counter = new AtomicInteger();\n\n\t\t@Bean\n\t\tConnectionNameStrategy myConnectionNameStrategy() {\n\t\t\treturn (connectionFactory) -> \"test#\" + this.counter.getAndIncrement();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RabbitRetryTemplateCustomizerConfiguration {\n\n\t\tprivate final RetryPolicy retryPolicy = RetryPolicy.withMaxRetries(1);\n\n\t\t@Bean\n\t\tRabbitTemplateRetrySettingsCustomizer rabbitTemplateRetryTemplateCustomizer() {\n\t\t\treturn (settings) -> settings.getRetryPolicySettings()\n\t\t\t\t.setFactory((builder) -> builder.multiplier(1.4).build());\n\t\t}\n\n\t\t@Bean\n\t\tRabbitListenerRetrySettingsCustomizer rabbitListenerRetryPolicyCustomizer() {\n\t\t\treturn (settings) -> settings.setFactory((builder) -> this.retryPolicy);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableRabbit\n\tstatic class EnableRabbitConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NoEnableRabbitConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CredentialsProviderConfiguration {\n\n\t\tprivate static final CredentialsProvider credentialsProvider = mock(CredentialsProvider.class);\n\n\t\t@Bean\n\t\tCredentialsProvider credentialsProvider() {\n\t\t\treturn credentialsProvider;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrimaryCredentialsProviderConfiguration {\n\n\t\tprivate static final CredentialsProvider credentialsProvider = mock(CredentialsProvider.class);\n\n\t\t@Bean\n\t\t@Primary\n\t\tCredentialsProvider credentialsProvider() {\n\t\t\treturn credentialsProvider;\n\t\t}\n\n\t\t@Bean\n\t\tCredentialsProvider credentialsProvider1() {\n\t\t\treturn mock(CredentialsProvider.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleCredentialsProvidersConfiguration {\n\n\t\t@Bean\n\t\tCredentialsProvider credentialsProvider1() {\n\t\t\treturn mock(CredentialsProvider.class);\n\t\t}\n\n\t\t@Bean\n\t\tCredentialsProvider credentialsProvider2() {\n\t\t\treturn mock(CredentialsProvider.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CredentialsRefreshServiceConfiguration {\n\n\t\tprivate static final CredentialsRefreshService credentialsRefreshService = mock(\n\t\t\t\tCredentialsRefreshService.class);\n\n\t\t@Bean\n\t\tCredentialsRefreshService credentialsRefreshService() {\n\t\t\treturn credentialsRefreshService;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrimaryCredentialsRefreshServiceConfiguration {\n\n\t\tprivate static final CredentialsRefreshService credentialsRefreshService = mock(\n\t\t\t\tCredentialsRefreshService.class);\n\n\t\t@Bean\n\t\t@Primary\n\t\tCredentialsRefreshService credentialsRefreshService1() {\n\t\t\treturn credentialsRefreshService;\n\t\t}\n\n\t\t@Bean\n\t\tCredentialsRefreshService credentialsRefreshService2() {\n\t\t\treturn mock(CredentialsRefreshService.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleCredentialsRefreshServicesConfiguration {\n\n\t\t@Bean\n\t\tCredentialsRefreshService credentialsRefreshService1() {\n\t\t\treturn mock(CredentialsRefreshService.class);\n\t\t}\n\n\t\t@Bean\n\t\tCredentialsRefreshService credentialsRefreshService2() {\n\t\t\treturn mock(CredentialsRefreshService.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SaslConfigCustomizerConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactoryCustomizer connectionFactoryCustomizer() {\n\t\t\treturn (connectionFactory) -> connectionFactory.setSaslConfig(new JDKSaslConfig(connectionFactory));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleConnectionFactoryCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(Ordered.LOWEST_PRECEDENCE)\n\t\tConnectionFactoryCustomizer secondCustomizer() {\n\t\t\treturn mock(ConnectionFactoryCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tConnectionFactoryCustomizer firstCustomizer() {\n\t\t\treturn mock(ConnectionFactoryCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Import(TestListener.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleContainerCustomizerConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tContainerCustomizer<SimpleMessageListenerContainer> customizer() {\n\t\t\treturn mock(ContainerCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Import(TestListener.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DirectContainerCustomizerConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tContainerCustomizer<DirectMessageListenerContainer> customizer() {\n\t\t\treturn mock(ContainerCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tRabbitConnectionDetails rabbitConnectionDetails() {\n\t\t\treturn new RabbitConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"password-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getVirtualHost() {\n\t\t\t\t\treturn \"/vhost-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic List<Address> getAddresses() {\n\t\t\t\t\treturn List.of(new Address(\"rabbit.example.com\", 12345), new Address(\"rabbit2.example.com\", 23456));\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CustomMessageConverterConfiguration {\n\n\t\t@Bean\n\t\tMessageConverter messageConverter() {\n\t\t\treturn new MessageConverter() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Message toMessage(Object object, MessageProperties messageProperties)\n\t\t\t\t\t\tthrows MessageConversionException {\n\t\t\t\t\treturn new Message(object.toString().getBytes());\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Object fromMessage(Message message) throws MessageConversionException {\n\t\t\t\t\treturn new String(message.getBody());\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\t@RabbitListener(queues = \"test\", autoStartup = \"false\")\n\t\tvoid listen(String in) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/RabbitPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.util.List;\n\nimport com.rabbitmq.client.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer;\nimport org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link RabbitProperties}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Rafael Carvalho\n * @author Scott Frederick\n * @author Jay Choi\n */\nclass RabbitPropertiesTests {\n\n\tprivate final RabbitProperties properties = new RabbitProperties();\n\n\t@Test\n\tvoid hostDefaultsToLocalhost() {\n\t\tassertThat(this.properties.getHost()).isEqualTo(\"localhost\");\n\t}\n\n\t@Test\n\tvoid customHost() {\n\t\tthis.properties.setHost(\"rabbit.example.com\");\n\t\tassertThat(this.properties.getHost()).isEqualTo(\"rabbit.example.com\");\n\t}\n\n\t@Test\n\tvoid hostIsDeterminedFromFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"rabbit1.example.com:1234\", \"rabbit2.example.com:2345\"));\n\t\tassertThat(this.properties.determineHost()).isEqualTo(\"rabbit1.example.com\");\n\t}\n\n\t@Test\n\tvoid determineHostReturnsHostPropertyWhenNoAddresses() {\n\t\tthis.properties.setHost(\"rabbit.example.com\");\n\t\tassertThat(this.properties.determineHost()).isEqualTo(\"rabbit.example.com\");\n\t}\n\n\t@Test\n\tvoid portDefaultsToNull() {\n\t\tassertThat(this.properties.getPort()).isNull();\n\t}\n\n\t@Test\n\tvoid customPort() {\n\t\tthis.properties.setPort(1234);\n\t\tassertThat(this.properties.getPort()).isEqualTo(1234);\n\t}\n\n\t@Test\n\tvoid determinePortReturnsPortOfFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"rabbit1.example.com:1234\", \"rabbit2.example.com:2345\"));\n\t\tassertThat(this.properties.determinePort()).isEqualTo(1234);\n\t}\n\n\t@Test\n\tvoid determinePortReturnsDefaultPortWhenNoAddresses() {\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5672);\n\t}\n\n\t@Test\n\tvoid determinePortWithSslReturnsDefaultSslPortWhenNoAddresses() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5671);\n\t}\n\n\t@Test\n\tvoid determinePortReturnsPortPropertyWhenNoAddresses() {\n\t\tthis.properties.setPort(1234);\n\t\tassertThat(this.properties.determinePort()).isEqualTo(1234);\n\t}\n\n\t@Test\n\tvoid determinePortReturnsDefaultAmqpPortWhenFirstAddressHasNoExplicitPort() {\n\t\tthis.properties.setPort(1234);\n\t\tthis.properties.setAddresses(List.of(\"rabbit1.example.com\", \"rabbit2.example.com:2345\"));\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5672);\n\t}\n\n\t@Test\n\tvoid determinePortUsingAmqpReturnsPortOfFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"amqp://root:password@otherhost\", \"amqps://root:password2@otherhost2\"));\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5672);\n\t}\n\n\t@Test\n\tvoid determinePortUsingAmqpsReturnsPortOfFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"amqps://root:password@otherhost\", \"amqp://root:password2@otherhost2\"));\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5671);\n\t}\n\n\t@Test\n\tvoid determinePortReturnsDefaultAmqpsPortWhenFirstAddressHasNoExplicitPortButSslEnabled() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tthis.properties.setPort(1234);\n\t\tthis.properties.setAddresses(List.of(\"rabbit1.example.com\", \"rabbit2.example.com:2345\"));\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5671);\n\t}\n\n\t@Test\n\tvoid virtualHostDefaultsToNull() {\n\t\tassertThat(this.properties.getVirtualHost()).isNull();\n\t}\n\n\t@Test\n\tvoid customVirtualHost() {\n\t\tthis.properties.setVirtualHost(\"alpha\");\n\t\tassertThat(this.properties.getVirtualHost()).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid virtualHostRetainsALeadingSlash() {\n\t\tthis.properties.setVirtualHost(\"/alpha\");\n\t\tassertThat(this.properties.getVirtualHost()).isEqualTo(\"/alpha\");\n\t}\n\n\t@Test\n\tvoid determineVirtualHostReturnsVirtualHostOfFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"rabbit1.example.com:1234/alpha\", \"rabbit2.example.com:2345/bravo\"));\n\t\tassertThat(this.properties.determineVirtualHost()).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid determineVirtualHostReturnsPropertyWhenNoAddresses() {\n\t\tthis.properties.setVirtualHost(\"alpha\");\n\t\tassertThat(this.properties.determineVirtualHost()).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid determineVirtualHostReturnsPropertyWhenFirstAddressHasNoVirtualHost() {\n\t\tthis.properties.setVirtualHost(\"alpha\");\n\t\tthis.properties.setAddresses(List.of(\"rabbit1.example.com:1234\", \"rabbit2.example.com:2345/bravo\"));\n\t\tassertThat(this.properties.determineVirtualHost()).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid determineVirtualHostIsSlashWhenAddressHasTrailingSlash() {\n\t\tthis.properties.setAddresses(List.of(\"amqp://root:password@otherhost:1111/\"));\n\t\tassertThat(this.properties.determineVirtualHost()).isEqualTo(\"/\");\n\t}\n\n\t@Test\n\tvoid emptyVirtualHostIsCoercedToASlash() {\n\t\tthis.properties.setVirtualHost(\"\");\n\t\tassertThat(this.properties.getVirtualHost()).isEqualTo(\"/\");\n\t}\n\n\t@Test\n\tvoid usernameDefaultsToGuest() {\n\t\tassertThat(this.properties.getUsername()).isEqualTo(\"guest\");\n\t}\n\n\t@Test\n\tvoid customUsername() {\n\t\tthis.properties.setUsername(\"user\");\n\t\tassertThat(this.properties.getUsername()).isEqualTo(\"user\");\n\t}\n\n\t@Test\n\tvoid determineUsernameReturnsUsernameOfFirstAddress() {\n\t\tthis.properties\n\t\t\t.setAddresses(List.of(\"user:secret@rabbit1.example.com:1234/alpha\", \"rabbit2.example.com:2345/bravo\"));\n\t\tassertThat(this.properties.determineUsername()).isEqualTo(\"user\");\n\t}\n\n\t@Test\n\tvoid determineUsernameReturnsPropertyWhenNoAddresses() {\n\t\tthis.properties.setUsername(\"alice\");\n\t\tassertThat(this.properties.determineUsername()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid determineUsernameReturnsPropertyWhenFirstAddressHasNoUsername() {\n\t\tthis.properties.setUsername(\"alice\");\n\t\tthis.properties\n\t\t\t.setAddresses(List.of(\"rabbit1.example.com:1234/alpha\", \"user:secret@rabbit2.example.com:2345/bravo\"));\n\t\tassertThat(this.properties.determineUsername()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid passwordDefaultsToGuest() {\n\t\tassertThat(this.properties.getPassword()).isEqualTo(\"guest\");\n\t}\n\n\t@Test\n\tvoid customPassword() {\n\t\tthis.properties.setPassword(\"secret\");\n\t\tassertThat(this.properties.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid determinePasswordReturnsPasswordOfFirstAddress() {\n\t\tthis.properties\n\t\t\t.setAddresses(List.of(\"user:secret@rabbit1.example.com:1234/alpha\", \"rabbit2.example.com:2345/bravo\"));\n\t\tassertThat(this.properties.determinePassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid determinePasswordReturnsPropertyWhenNoAddresses() {\n\t\tthis.properties.setPassword(\"secret\");\n\t\tassertThat(this.properties.determinePassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid determinePasswordReturnsPropertyWhenFirstAddressHasNoPassword() {\n\t\tthis.properties.setPassword(\"12345678\");\n\t\tthis.properties\n\t\t\t.setAddresses(List.of(\"rabbit1.example.com:1234/alpha\", \"user:secret@rabbit2.example.com:2345/bravo\"));\n\t\tassertThat(this.properties.determinePassword()).isEqualTo(\"12345678\");\n\t}\n\n\t@Test\n\tvoid addressesDefaultsToNull() {\n\t\tassertThat(this.properties.getAddresses()).isNull();\n\t}\n\n\t@Test\n\tvoid customAddresses() {\n\t\tthis.properties.setAddresses(List.of(\"user:secret@rabbit1.example.com:1234/alpha\", \"rabbit2.example.com\"));\n\t\tassertThat(this.properties.getAddresses()).containsExactly(\"user:secret@rabbit1.example.com:1234/alpha\",\n\t\t\t\t\"rabbit2.example.com\");\n\t}\n\n\t@Test\n\tvoid ipv6Address() {\n\t\tthis.properties.setAddresses(List.of(\"amqp://foo:bar@[aaaa:bbbb:cccc::d]:1234\"));\n\t\tassertThat(this.properties.determineHost()).isEqualTo(\"[aaaa:bbbb:cccc::d]\");\n\t\tassertThat(this.properties.determinePort()).isEqualTo(1234);\n\t}\n\n\t@Test\n\tvoid ipv6AddressDefaultPort() {\n\t\tthis.properties.setAddresses(List.of(\"amqp://foo:bar@[aaaa:bbbb:cccc::d]\"));\n\t\tassertThat(this.properties.determineHost()).isEqualTo(\"[aaaa:bbbb:cccc::d]\");\n\t\tassertThat(this.properties.determinePort()).isEqualTo(5672);\n\t}\n\n\t@Test\n\tvoid determineAddressesReturnsAddressesWithJustHostAndPort() {\n\t\tthis.properties.setAddresses(List.of(\"user:secret@rabbit1.example.com:1234/alpha\", \"rabbit2.example.com\"));\n\t\tassertThat(this.properties.determineAddresses()).containsExactly(\"rabbit1.example.com:1234\",\n\t\t\t\t\"rabbit2.example.com:5672\");\n\t}\n\n\t@Test\n\tvoid determineAddressesUsesDefaultWhenNoAddressesSet() {\n\t\tassertThat(this.properties.determineAddresses()).containsExactly(\"localhost:5672\");\n\t}\n\n\t@Test\n\tvoid determineAddressesWithSslUsesDefaultWhenNoAddressesSet() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tassertThat(this.properties.determineAddresses()).containsExactly(\"localhost:5671\");\n\t}\n\n\t@Test\n\tvoid determineAddressesUsesHostAndPortPropertiesWhenNoAddressesSet() {\n\t\tthis.properties.setHost(\"rabbit.example.com\");\n\t\tthis.properties.setPort(1234);\n\t\tassertThat(this.properties.determineAddresses()).containsExactly(\"rabbit.example.com:1234\");\n\t}\n\n\t@Test\n\tvoid determineAddressesUsesIpv6HostAndPortPropertiesWhenNoAddressesSet() {\n\t\tthis.properties.setHost(\"[::1]\");\n\t\tthis.properties.setPort(32863);\n\t\tassertThat(this.properties.determineAddresses()).containsExactly(\"[::1]:32863\");\n\t}\n\n\t@Test\n\tvoid determineSslUsingAmqpsReturnsStateOfFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"amqps://root:password@otherhost\", \"amqp://root:password2@otherhost2\"));\n\t\tassertThat(this.properties.getSsl().determineEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid sslDetermineEnabledIsTrueWhenAddressHasNoProtocolAndSslIsEnabled() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tthis.properties.setAddresses(List.of(\"root:password@otherhost\"));\n\t\tassertThat(this.properties.getSsl().determineEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid sslDetermineEnabledIsFalseWhenAddressHasNoProtocolAndSslIsDisabled() {\n\t\tthis.properties.getSsl().setEnabled(false);\n\t\tthis.properties.setAddresses(List.of(\"root:password@otherhost\"));\n\t\tassertThat(this.properties.getSsl().determineEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid determineSslUsingAmqpReturnsStateOfFirstAddress() {\n\t\tthis.properties.setAddresses(List.of(\"amqp://root:password@otherhost\", \"amqps://root:password2@otherhost2\"));\n\t\tassertThat(this.properties.getSsl().determineEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid determineSslReturnFlagPropertyWhenNoAddresses() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tassertThat(this.properties.getSsl().determineEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid determineSslEnabledIsTrueWhenBundleIsSetAndNoAddresses() {\n\t\tthis.properties.getSsl().setBundle(\"test\");\n\t\tassertThat(this.properties.getSsl().determineEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid propertiesUseConsistentDefaultValues() {\n\t\tConnectionFactory connectionFactory = new ConnectionFactory();\n\t\tassertThat(connectionFactory).hasFieldOrPropertyWithValue(\"maxInboundMessageBodySize\",\n\t\t\t\t(int) this.properties.getMaxInboundMessageBodySize().toBytes());\n\t}\n\n\t@Test\n\tvoid simpleContainerUseConsistentDefaultValues() {\n\t\tSimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();\n\t\tSimpleMessageListenerContainer container = factory.createListenerContainer();\n\t\tRabbitProperties.SimpleContainer simple = this.properties.getListener().getSimple();\n\t\tassertThat(simple.isAutoStartup()).isEqualTo(container.isAutoStartup());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"missingQueuesFatal\", simple.isMissingQueuesFatal());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"deBatchingEnabled\", simple.isDeBatchingEnabled());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"consumerBatchEnabled\", simple.isConsumerBatchEnabled());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"forceStop\", simple.isForceStop());\n\t}\n\n\t@Test\n\tvoid directContainerUseConsistentDefaultValues() {\n\t\tDirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory();\n\t\tDirectMessageListenerContainer container = factory.createListenerContainer();\n\t\tRabbitProperties.DirectContainer direct = this.properties.getListener().getDirect();\n\t\tassertThat(direct.isAutoStartup()).isEqualTo(container.isAutoStartup());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"missingQueuesFatal\", direct.isMissingQueuesFatal());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"deBatchingEnabled\", direct.isDeBatchingEnabled());\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"forceStop\", direct.isForceStop());\n\t}\n\n\t@Test\n\tvoid determineUsernameWithoutPassword() {\n\t\tthis.properties.setAddresses(List.of(\"user@rabbit1.example.com:1234/alpha\"));\n\t\tassertThat(this.properties.determineUsername()).isEqualTo(\"user\");\n\t\tassertThat(this.properties.determinePassword()).isEqualTo(\"guest\");\n\t}\n\n\t@Test\n\tvoid hostPropertyMustBeSingleHost() {\n\t\tthis.properties.setHost(\"my-rmq-host.net,my-rmq-host-2.net\");\n\t\tassertThat(this.properties.getHost()).isEqualTo(\"my-rmq-host.net,my-rmq-host-2.net\");\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)\n\t\t\t.isThrownBy(this.properties::determineAddresses)\n\t\t\t.withMessageContaining(\"spring.rabbitmq.host\");\n\t}\n\n\t@Test\n\tvoid streamSslIsDisabledByDefault() {\n\t\tassertThat(this.properties.getStream().getSsl().determineEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid streamSslIsEnabledWhenEnabledIsTrue() {\n\t\tthis.properties.getStream().getSsl().setEnabled(true);\n\t\tassertThat(this.properties.getStream().getSsl().determineEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid streamSslIsEnabledWhenBundleIsSet() {\n\t\tthis.properties.getStream().getSsl().setBundle(\"test-bundle\");\n\t\tassertThat(this.properties.getStream().getSsl().determineEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid streamSslIsDisabledWhenEnabledIsFalseAndBundleIsNotSet() {\n\t\tthis.properties.getStream().getSsl().setEnabled(false);\n\t\tassertThat(this.properties.getStream().getSsl().determineEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid streamSslIsEnabledWhenBundleIsSetButEnabledIsFalse() {\n\t\tthis.properties.getStream().getSsl().setBundle(\"test-bundle\");\n\t\tthis.properties.getStream().getSsl().setEnabled(false);\n\t\tassertThat(this.properties.getStream().getSsl().determineEnabled()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/RabbitStreamConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport com.rabbitmq.stream.Address;\nimport com.rabbitmq.stream.BackOffDelayPolicy;\nimport com.rabbitmq.stream.Codec;\nimport com.rabbitmq.stream.Environment;\nimport com.rabbitmq.stream.EnvironmentBuilder;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.amqp.core.MessageListenerContainer;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.amqp.rabbit.config.ContainerCustomizer;\nimport org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;\nimport org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.boot.amqp.autoconfigure.RabbitStreamConfiguration.PropertiesRabbitStreamConnectionDetails;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.rabbit.stream.config.StreamRabbitListenerContainerFactory;\nimport org.springframework.rabbit.stream.listener.ConsumerCustomizer;\nimport org.springframework.rabbit.stream.listener.StreamListenerContainer;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamListenerObservation.DefaultRabbitStreamListenerObservationConvention;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamListenerObservationConvention;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamTemplateObservation.DefaultRabbitStreamTemplateObservationConvention;\nimport org.springframework.rabbit.stream.micrometer.RabbitStreamTemplateObservationConvention;\nimport org.springframework.rabbit.stream.producer.ProducerCustomizer;\nimport org.springframework.rabbit.stream.producer.RabbitStreamTemplate;\nimport org.springframework.rabbit.stream.support.converter.StreamMessageConverter;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link RabbitStreamConfiguration}.\n *\n * @author Gary Russell\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Jay Choi\n */\nclass RabbitStreamConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RabbitAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid whenListenerTypeIsStreamThenStreamListenerContainerAndEnvironmentAreAutoConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:stream\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitListenerEndpointRegistry registry = context.getBean(RabbitListenerEndpointRegistry.class);\n\t\t\t\tMessageListenerContainer listenerContainer = registry.getListenerContainer(\"test\");\n\t\t\t\tassertThat(listenerContainer).isInstanceOf(StreamListenerContainer.class);\n\t\t\t\tassertThat(listenerContainer).extracting(\"consumerCustomizer\").isNotNull();\n\t\t\t\tassertThat(context.getBean(StreamRabbitListenerContainerFactory.class))\n\t\t\t\t\t.extracting(\"nativeListener\", InstanceOfAssertFactories.BOOLEAN)\n\t\t\t\t\t.isFalse();\n\t\t\t\tthen(context.getBean(ContainerCustomizer.class)).should().configure(listenerContainer);\n\t\t\t\tassertThat(context).hasSingleBean(Environment.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenNativeListenerIsEnabledThenContainerFactoryIsConfiguredToUseNativeListeners() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:stream\",\n\t\t\t\t\t\"spring.rabbitmq.listener.stream.native-listener:true\")\n\t\t\t.run((context) -> assertThat(context.getBean(StreamRabbitListenerContainerFactory.class))\n\t\t\t\t.extracting(\"nativeListener\", InstanceOfAssertFactories.BOOLEAN)\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid shouldConfigureObservations() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:stream\",\n\t\t\t\t\t\"spring.rabbitmq.listener.stream.observation-enabled:true\")\n\t\t\t.run((context) -> assertThat(context.getBean(StreamRabbitListenerContainerFactory.class))\n\t\t\t\t.extracting(\"observationEnabled\", InstanceOfAssertFactories.BOOLEAN)\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid shouldConfigureRabbitStreamListenerObservationConvention() {\n\t\tRabbitStreamListenerObservationConvention convention = new DefaultRabbitStreamListenerObservationConvention();\n\t\tthis.contextRunner.withBean(RabbitStreamListenerObservationConvention.class, () -> convention)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.listener.type:stream\")\n\t\t\t.run((context) -> {\n\t\t\t\tStreamRabbitListenerContainerFactory containerFactory = context\n\t\t\t\t\t.getBean(StreamRabbitListenerContainerFactory.class);\n\t\t\t\tassertThat(containerFactory).hasFieldOrPropertyWithValue(\"streamListenerObservationConvention\",\n\t\t\t\t\t\tconvention);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid environmentIsAutoConfiguredByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(Environment.class));\n\t}\n\n\t@Test\n\tvoid whenCustomEnvironmentIsDefinedThenAutoConfiguredEnvironmentBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomEnvironmentConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Environment.class);\n\t\t\tassertThat(context.getBean(Environment.class))\n\t\t\t\t.isSameAs(context.getBean(CustomEnvironmentConfiguration.class).environment);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomMessageListenerContainerFactoryIsDefinedThenAutoConfiguredContainerFactoryBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomMessageListenerContainerFactoryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RabbitListenerContainerFactory.class);\n\t\t\t\tassertThat(context.getBean(RabbitListenerContainerFactory.class)).isSameAs(context\n\t\t\t\t\t.getBean(CustomMessageListenerContainerFactoryConfiguration.class).listenerContainerFactory);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid environmentUsesConnectionDetailsByDefault() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().port(5552);\n\t\tthen(builder).should().host(\"localhost\");\n\t\tthen(builder).should().virtualHost(\"vhost\");\n\t\tthen(builder).should().lazyInitialization(true);\n\t\tthen(builder).should().username(\"guest\");\n\t\tthen(builder).should().password(\"guest\");\n\t\tthen(builder).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid whenStreamPortIsSetThenEnvironmentUsesCustomPort() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().setPort(5553);\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().port(5553);\n\t}\n\n\t@Test\n\tvoid whenStreamHostIsSetThenEnvironmentUsesCustomHost() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().setHost(\"stream.rabbit.example.com\");\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().host(\"stream.rabbit.example.com\");\n\t}\n\n\t@Test\n\tvoid whenStreamVirtualHostIsSetThenEnvironmentUsesCustomVirtualHost() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().setVirtualHost(\"stream-virtual-host\");\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().virtualHost(\"stream-virtual-host\");\n\t}\n\n\t@Test\n\tvoid whenStreamVirtualHostIsNotSetButDefaultVirtualHostIsSetThenEnvironmentUsesDefaultVirtualHost() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.setVirtualHost(\"default-virtual-host\");\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"default-virtual-host\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().virtualHost(\"default-virtual-host\");\n\t}\n\n\t@Test\n\tvoid whenStreamCredentialsAreNotSetThenEnvironmentUsesConnectionDetailsCredentials() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.setUsername(\"alice\");\n\t\tproperties.setPassword(\"secret\");\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"bob\", \"password\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().username(\"bob\");\n\t\tthen(builder).should().password(\"password\");\n\t}\n\n\t@Test\n\tvoid whenStreamCredentialsAreSetThenEnvironmentUsesStreamCredentials() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.setUsername(\"alice\");\n\t\tproperties.setPassword(\"secret\");\n\t\tproperties.getStream().setUsername(\"bob\");\n\t\tproperties.getStream().setPassword(\"confidential\");\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().username(\"bob\");\n\t\tthen(builder).should().password(\"confidential\");\n\t}\n\n\t@Test\n\tvoid testDefaultRabbitStreamTemplateConfiguration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.rabbitmq.stream.name:stream-test\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RabbitStreamTemplate.class);\n\t\t\tassertThat(context.getBean(RabbitStreamTemplate.class)).hasFieldOrPropertyWithValue(\"streamName\",\n\t\t\t\t\t\"stream-test\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultRabbitStreamTemplateConfigurationWithoutStreamName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.rabbitmq.listener.type:stream\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RabbitStreamTemplate.class));\n\t}\n\n\t@Test\n\tvoid testRabbitStreamTemplateConfigurationWithCustomMessageConverter() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.stream.name:stream-test\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RabbitStreamTemplate.class);\n\t\t\t\tRabbitStreamTemplate streamTemplate = context.getBean(RabbitStreamTemplate.class);\n\t\t\t\tassertThat(streamTemplate).hasFieldOrPropertyWithValue(\"streamName\", \"stream-test\");\n\t\t\t\tassertThat(streamTemplate).extracting(\"messageConverter\")\n\t\t\t\t\t.isSameAs(context.getBean(MessageConverter.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitStreamTemplateConfigurationWithCustomStreamMessageConverter() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"myStreamMessageConverter\", StreamMessageConverter.class,\n\t\t\t\t\t() -> mock(StreamMessageConverter.class))\n\t\t\t.withPropertyValues(\"spring.rabbitmq.stream.name:stream-test\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RabbitStreamTemplate.class);\n\t\t\t\tassertThat(context.getBean(RabbitStreamTemplate.class)).extracting(\"messageConverter\")\n\t\t\t\t\t.isSameAs(context.getBean(\"myStreamMessageConverter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRabbitStreamTemplateConfigurationWithCustomProducerCustomizer() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"myProducerCustomizer\", ProducerCustomizer.class, () -> mock(ProducerCustomizer.class))\n\t\t\t.withPropertyValues(\"spring.rabbitmq.stream.name:stream-test\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RabbitStreamTemplate.class);\n\t\t\t\tassertThat(context.getBean(RabbitStreamTemplate.class)).extracting(\"producerCustomizer\")\n\t\t\t\t\t.isSameAs(context.getBean(\"myProducerCustomizer\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureRabbitStreamTemplateObservationConvention() {\n\t\tRabbitStreamTemplateObservationConvention convention = new DefaultRabbitStreamTemplateObservationConvention();\n\t\tthis.contextRunner.withBean(RabbitStreamTemplateObservationConvention.class, () -> convention)\n\t\t\t.withPropertyValues(\"spring.rabbitmq.stream.name:stream-test\")\n\t\t\t.run((context) -> {\n\t\t\t\tRabbitStreamTemplate rabbitStreamTemplate = context.getBean(RabbitStreamTemplate.class);\n\t\t\t\tassertThat(rabbitStreamTemplate).hasFieldOrPropertyWithValue(\"observationConvention\", convention);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid environmentCreatedByBuilderCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(EnvironmentBuilderCustomizers.class).run((context) -> {\n\t\t\tEnvironment environment = context.getBean(Environment.class);\n\t\t\tassertThat(environment).extracting(\"codec\")\n\t\t\t\t.isEqualTo(context.getBean(EnvironmentBuilderCustomizers.class).codec);\n\t\t\tassertThat(environment).extracting(\"recoveryBackOffDelayPolicy\")\n\t\t\t\t.isEqualTo(context.getBean(EnvironmentBuilderCustomizers.class).recoveryBackOffDelayPolicy);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid connectionDetailsAreApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.rabbitmq.stream.name:stream-test\")\n\t\t\t.withUserConfiguration(CustomConnectionDetails.class)\n\t\t\t.run((context) -> assertThat(context.getBean(Environment.class))\n\t\t\t\t.extracting((environment) -> (List<Address>) ReflectionTestUtils.getField(environment, \"addresses\"))\n\t\t\t\t.extracting((address) -> address.get(0))\n\t\t\t\t.extracting(\"host\", \"port\")\n\t\t\t\t.containsExactly(\"rabbitmq\", 5555));\n\t}\n\n\t@Test\n\tvoid whenStreamSslIsNotConfiguredThenTlsIsNotUsed() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should(never()).tls();\n\t}\n\n\t@Test\n\tvoid whenStreamSslIsEnabledThenTlsIsUsed() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().getSsl().setEnabled(true);\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should().tls();\n\t}\n\n\t@Test\n\tvoid whenStreamSslBundleIsConfiguredThenTlsIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.rabbitmq.stream.ssl.bundle=test-bundle\",\n\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).hasSingleBean(Environment.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenStreamSslIsDisabledThenTlsIsNotUsed() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().getSsl().setEnabled(false);\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, null));\n\t\tthen(builder).should(never()).tls();\n\t}\n\n\t@Test\n\tvoid whenStreamSslIsDisabledWithBundleThenTlsIsStillUsed() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tSslBundles sslBundles = mock(SslBundles.class);\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().getSsl().setEnabled(false);\n\t\tproperties.getStream().getSsl().setBundle(\"some-bundle\");\n\t\tRabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\tgetRabbitStreamConnectionDetails(properties, sslBundles));\n\t\tthen(builder).should().tls();\n\t}\n\n\t@Test\n\tvoid whenConnectionDetailsSslBundleIsProvidedThenTlsIsUsedWithoutProperties() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConnectionDetails.class)\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:org/springframework/boot/amqp/autoconfigure/test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).hasSingleBean(Environment.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenStreamSslBundleIsInvalidThenFails() {\n\t\tEnvironmentBuilder builder = mock(EnvironmentBuilder.class);\n\t\tSslBundles sslBundles = mock(SslBundles.class);\n\t\tgiven(sslBundles.getBundle(\"invalid-bundle\")).willThrow(\n\t\t\t\tnew NoSuchSslBundleException(\"invalid-bundle\", \"SSL bundle name 'invalid-bundle' cannot be found\"));\n\t\tRabbitProperties properties = new RabbitProperties();\n\t\tproperties.getStream().getSsl().setBundle(\"invalid-bundle\");\n\t\tassertThatExceptionOfType(NoSuchSslBundleException.class)\n\t\t\t.isThrownBy(() -> RabbitStreamConfiguration.configure(builder, properties,\n\t\t\t\t\tnew TestRabbitConnectionDetails(\"guest\", \"guest\", \"vhost\"),\n\t\t\t\t\tgetRabbitStreamConnectionDetails(properties, sslBundles)))\n\t\t\t.withMessageContaining(\"invalid-bundle\");\n\t}\n\n\tprivate RabbitStreamConnectionDetails getRabbitStreamConnectionDetails(RabbitProperties properties,\n\t\t\t@Nullable SslBundles sslBundles) {\n\t\treturn new PropertiesRabbitStreamConnectionDetails(properties.getStream(), sslBundles);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@RabbitListener(id = \"test\", queues = \"stream\", autoStartup = \"false\")\n\t\tvoid listen(String in) {\n\t\t}\n\n\t\t@Bean\n\t\tConsumerCustomizer consumerCustomizer() {\n\t\t\treturn mock(ConsumerCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tContainerCustomizer<StreamListenerContainer> containerCustomizer() {\n\t\t\treturn mock(ContainerCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomEnvironmentConfiguration {\n\n\t\tprivate final Environment environment = Environment.builder().lazyInitialization(true).build();\n\n\t\t@Bean\n\t\tEnvironment rabbitStreamEnvironment() {\n\t\t\treturn this.environment;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomMessageListenerContainerFactoryConfiguration {\n\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tprivate final RabbitListenerContainerFactory listenerContainerFactory = mock(\n\t\t\t\tRabbitListenerContainerFactory.class);\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tRabbitListenerContainerFactory<MessageListenerContainer> rabbitListenerContainerFactory() {\n\t\t\treturn this.listenerContainerFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MessageConvertersConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tMessageConverter myMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t\t@Bean\n\t\tMessageConverter anotherMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EnvironmentBuilderCustomizers {\n\n\t\tprivate final Codec codec = mock(Codec.class);\n\n\t\tprivate final BackOffDelayPolicy recoveryBackOffDelayPolicy = BackOffDelayPolicy.fixed(Duration.ofSeconds(5));\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tEnvironmentBuilderCustomizer customizerA() {\n\t\t\treturn (builder) -> builder.codec(this.codec);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tEnvironmentBuilderCustomizer customizerB() {\n\t\t\treturn (builder) -> builder.codec(mock(Codec.class))\n\t\t\t\t.recoveryBackOffDelayPolicy(this.recoveryBackOffDelayPolicy);\n\t\t}\n\n\t}\n\n\tprivate static final class TestRabbitConnectionDetails implements RabbitConnectionDetails {\n\n\t\tprivate final String username;\n\n\t\tprivate final String password;\n\n\t\tprivate final String virtualHost;\n\n\t\tprivate TestRabbitConnectionDetails(String username, String password, String virtualHost) {\n\t\t\tthis.username = username;\n\t\t\tthis.password = password;\n\t\t\tthis.virtualHost = virtualHost;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getVirtualHost() {\n\t\t\treturn this.virtualHost;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Address> getAddresses() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConnectionDetails {\n\n\t\t@Bean\n\t\tRabbitStreamConnectionDetails customRabbitMqStreamConnectionDetails(SslBundles sslBundles) {\n\t\t\treturn new RabbitStreamConnectionDetails() {\n\t\t\t\t@Override\n\t\t\t\tpublic String getHost() {\n\t\t\t\t\treturn \"rabbitmq\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic int getPort() {\n\t\t\t\t\treturn 5555;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\t\t\tif (sslBundles.getBundleNames().contains(\"test-bundle\")) {\n\t\t\t\t\t\treturn sslBundles.getBundle(\"test-bundle\");\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/health/RabbitHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.amqp.health.RabbitHealthIndicator;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass RabbitHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RabbitAutoConfiguration.class,\n\t\t\t\tRabbitHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(RabbitHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.rabbit.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RabbitHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/metrics/RabbitMetricsAutoConfigurationMeterBinderCycleIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to check that {@link RabbitMetricsAutoConfiguration} does not cause a\n * dependency cycle when used with {@link MeterBinder}.\n *\n * @author Phillip Webb\n * @see <a href=\"https://github.com/spring-projects/spring-boot/issues/30636\">gh-30636</a>\n */\nclass RabbitMetricsAutoConfigurationMeterBinderCycleIntegrationTests {\n\n\t@Test\n\tvoid doesNotFormCycle() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);\n\t\tTestService testService = context.getBean(TestService.class);\n\t\tcontext.close();\n\t\tassertThat(testService.bound).isTrue();\n\t}\n\n\t@Configuration\n\t@Import({ TestService.class, RabbitAutoConfiguration.class, MetricsAutoConfiguration.class,\n\t\t\tRabbitMetricsAutoConfiguration.class })\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tSimpleMeterRegistry meterRegistry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\tstatic class TestService implements MeterBinder {\n\n\t\tprivate boolean bound;\n\n\t\tTestService(RabbitTemplate rabbitTemplate) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void bindTo(MeterRegistry registry) {\n\t\t\tthis.bound = true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/autoconfigure/metrics/RabbitMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitMetricsAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass RabbitMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(AutoConfigurations.of(RabbitAutoConfiguration.class, RabbitMetricsAutoConfiguration.class,\n\t\t\t\tMetricsAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid autoConfiguredConnectionFactoryIsInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tregistry.get(\"rabbitmq.connections\").meter();\n\t\t});\n\t}\n\n\t@Test\n\tvoid abstractConnectionFactoryDefinedAsAConnectionFactoryIsInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionFactoryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customConnectionFactory\");\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tregistry.get(\"rabbitmq.connections\").meter();\n\t\t});\n\t}\n\n\t@Test\n\tvoid rabbitmqNativeConnectionFactoryInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.enable.rabbitmq=false\").run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.find(\"rabbitmq.connections\").meter()).isNull();\n\t\t});\n\t}\n\n\t@Configuration\n\tstatic class ConnectionFactoryConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory customConnectionFactory() {\n\t\t\treturn new CachingConnectionFactory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/docker/compose/RabbitEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RabbitEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass RabbitEnvironmentTests {\n\n\t@Test\n\tvoid getUsernameWhenNoRabbitmqDefaultUser() {\n\t\tRabbitEnvironment environment = new RabbitEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getUsername()).isEqualTo(\"guest\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasRabbitmqDefaultUser() {\n\t\tRabbitEnvironment environment = new RabbitEnvironment(Map.of(\"RABBITMQ_DEFAULT_USER\", \"me\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasRabbitmqUsername() {\n\t\tRabbitEnvironment environment = new RabbitEnvironment(Map.of(\"RABBITMQ_USERNAME\", \"me\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoRabbitmqDefaultPass() {\n\t\tRabbitEnvironment environment = new RabbitEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getPassword()).isEqualTo(\"guest\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasRabbitmqDefaultPass() {\n\t\tRabbitEnvironment environment = new RabbitEnvironment(Map.of(\"RABBITMQ_DEFAULT_PASS\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasRabbitmqPassword() {\n\t\tRabbitEnvironment environment = new RabbitEnvironment(Map.of(\"RABBITMQ_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/health/RabbitHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.health;\n\nimport java.util.Collections;\n\nimport com.rabbitmq.client.Channel;\nimport com.rabbitmq.client.Connection;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.amqp.rabbit.core.ChannelCallback;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RabbitHealthIndicator}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass RabbitHealthIndicatorTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate RabbitTemplate rabbitTemplate;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Channel channel;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenRabbitTemplateIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RabbitHealthIndicator(null))\n\t\t\t.withMessageContaining(\"'rabbitTemplate' must not be null\");\n\t}\n\n\t@Test\n\tvoid healthWhenConnectionSucceedsShouldReturnUpWithVersion() {\n\t\tgivenTemplateExecutionWillInvokeCallback();\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(this.channel.getConnection()).willReturn(connection);\n\t\tgiven(connection.getServerProperties()).willReturn(Collections.singletonMap(\"version\", \"123\"));\n\t\tHealth health = new RabbitHealthIndicator(this.rabbitTemplate).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"version\", \"123\");\n\t}\n\n\t@Test\n\tvoid healthWhenVersionIsMissingShouldReturnUpWithUnknownVersion() {\n\t\tgivenTemplateExecutionWillInvokeCallback();\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(this.channel.getConnection()).willReturn(connection);\n\t\tgiven(connection.getServerProperties()).willReturn(Collections.emptyMap());\n\t\tHealth health = new RabbitHealthIndicator(this.rabbitTemplate).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"version\", \"unknown\");\n\t}\n\n\t@Test\n\tvoid healthWhenConnectionFailsShouldReturnDown() {\n\t\tgivenTemplateExecutionWillInvokeCallback();\n\t\tgiven(this.channel.getConnection()).willThrow(new RuntimeException());\n\t\tHealth health = new RabbitHealthIndicator(this.rabbitTemplate).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n\tprivate void givenTemplateExecutionWillInvokeCallback() {\n\t\tgiven(this.rabbitTemplate.execute(any())).willAnswer((invocation) -> {\n\t\t\tChannelCallback<?> callback = invocation.getArgument(0);\n\t\t\treturn callback.doInRabbit(this.channel);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/java/org/springframework/boot/amqp/metrics/RabbitMetricsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.amqp.metrics;\n\nimport com.rabbitmq.client.ConnectionFactory;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RabbitMetrics}.\n *\n * @author Stephane Nicoll\n */\nclass RabbitMetricsTests {\n\n\t@Test\n\tvoid connectionFactoryIsInstrumented() {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tSimpleMeterRegistry registry = new SimpleMeterRegistry();\n\t\tnew RabbitMetrics(connectionFactory, null).bindTo(registry);\n\t\tregistry.get(\"rabbitmq.connections\");\n\t}\n\n\t@Test\n\tvoid connectionFactoryWithTagsIsInstrumented() {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tSimpleMeterRegistry registry = new SimpleMeterRegistry();\n\t\tnew RabbitMetrics(connectionFactory, Tags.of(\"env\", \"prod\")).bindTo(registry);\n\t\tassertThat(registry.get(\"rabbitmq.connections\").tags(\"env\", \"prod\").meter()).isNotNull();\n\t\tassertThat(registry.find(\"rabbitmq.connections\").tags(\"env\", \"dev\").meter()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-amqp/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-artemis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Artemis\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-jms\"))\n\tapi(\"org.apache.artemis:artemis-jakarta-client\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-transaction\"))\n\toptional(\"org.apache.artemis:artemis-jakarta-server\")\n\toptional(\"org.messaginghub:pooled-jms\") {\n\t\texclude group: \"org.apache.geronimo.specs\", module: \"geronimo-jms_2.0_spec\"\n\t}\n\toptional(\"org.testcontainers:testcontainers-activemq\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/dockerTest/java/org/springframework/boot/artemis/docker/compose/ArtemisDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.docker.compose;\n\nimport org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails;\nimport org.springframework.boot.artemis.autoconfigure.ArtemisMode;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ArtemisDockerComposeConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\nclass ArtemisDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"artemis-compose.yaml\", image = TestImage.ARTEMIS)\n\tvoid runCreatesConnectionDetails(ArtemisConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getMode()).isEqualTo(ArtemisMode.NATIVE);\n\t\tassertThat(connectionDetails.getBrokerUrl()).isNotNull().startsWith(\"tcp://\");\n\t\tassertThat(connectionDetails.getUser()).isEqualTo(\"root\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/dockerTest/java/org/springframework/boot/artemis/testcontainers/ArtemisContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.activemq.ArtemisContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.artemis.autoconfigure.ArtemisAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArtemisContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass ArtemisContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ArtemisContainer artemis = TestImage.container(ArtemisContainer.class);\n\n\t@Autowired\n\tprivate JmsClient jmsClient;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToActiveMQContainer() {\n\t\tthis.jmsClient.destination(\"sample.queue\").send(\"message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"message\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ ArtemisAutoConfiguration.class, JmsAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@JmsListener(destination = \"sample.queue\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/dockerTest/resources/org/springframework/boot/artemis/docker/compose/artemis-compose.yaml",
    "content": "services:\n  artemis:\n    image: '{imageName}'\n    ports:\n      - '61616'\n    environment:\n      ARTEMIS_USER: 'root'\n      ARTEMIS_PASSWORD: 'secret'\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties;\nimport org.springframework.boot.jms.autoconfigure.JndiConnectionFactoryAutoConfiguration;\nimport org.springframework.boot.transaction.jta.autoconfigure.JtaAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to integrate with an Artemis broker.\n * If the necessary classes are present, embed the broker in the application by default.\n * Otherwise, connect to a broker available on the local machine with the default\n * settings.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see ArtemisProperties\n */\n@AutoConfiguration(before = JmsAutoConfiguration.class,\n\t\tafter = { JndiConnectionFactoryAutoConfiguration.class, JtaAutoConfiguration.class })\n@ConditionalOnClass({ ConnectionFactory.class, ActiveMQConnectionFactory.class })\n@ConditionalOnMissingBean(ConnectionFactory.class)\n@EnableConfigurationProperties({ ArtemisProperties.class, JmsProperties.class })\n@Import({ ArtemisEmbeddedServerConfiguration.class, ArtemisXAConnectionFactoryConfiguration.class,\n\t\tArtemisConnectionFactoryConfiguration.class })\npublic final class ArtemisAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tArtemisConnectionDetails artemisConnectionDetails(ArtemisProperties properties) {\n\t\treturn new PropertiesArtemisConnectionDetails(properties);\n\t}\n\n\t/**\n\t * Adapts {@link ArtemisProperties} to {@link ArtemisConnectionDetails}.\n\t */\n\tstatic class PropertiesArtemisConnectionDetails implements ArtemisConnectionDetails {\n\n\t\tprivate final ArtemisProperties properties;\n\n\t\tPropertiesArtemisConnectionDetails(ArtemisProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ArtemisMode getMode() {\n\t\t\treturn this.properties.getMode();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getBrokerUrl() {\n\t\t\treturn this.properties.getBrokerUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn this.properties.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisConfigurationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport org.apache.activemq.artemis.core.config.Configuration;\nimport org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the Artemis\n * JMS server {@link Configuration} to fine-tune its auto-configuration before it is used\n * by the auto-configured {@link EmbeddedActiveMQ} instance.\n *\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @since 4.0.0\n * @see ArtemisAutoConfiguration\n */\n@FunctionalInterface\npublic interface ArtemisConfigurationCustomizer {\n\n\t/**\n\t * Customize the configuration.\n\t * @param configuration the configuration to customize\n\t */\n\tvoid customize(Configuration configuration);\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to an Artemis service.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\npublic interface ArtemisConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Artemis deployment mode, auto-detected by default.\n\t * @return the Artemis deployment mode, auto-detected by default\n\t */\n\t@Nullable ArtemisMode getMode();\n\n\t/**\n\t * Artemis broker url.\n\t * @return the Artemis broker url\n\t */\n\t@Nullable String getBrokerUrl();\n\n\t/**\n\t * Login user of the broker.\n\t * @return the login user of the broker\n\t */\n\t@Nullable String getUser();\n\n\t/**\n\t * Login password of the broker.\n\t * @return the login password of the broker\n\t */\n\t@Nullable String getPassword();\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisConnectionFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;\nimport org.apache.commons.pool2.PooledObject;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryFactory;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.connection.CachingConnectionFactory;\n\n/**\n * Configuration for Artemis {@link ConnectionFactory}.\n *\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(ConnectionFactory.class)\nclass ArtemisConnectionFactoryConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.artemis.pool.enabled\", havingValue = false, matchIfMissing = true)\n\tstatic class SimpleConnectionFactoryConfiguration {\n\n\t\t@Bean(name = \"jmsConnectionFactory\")\n\t\t@ConditionalOnBooleanProperty(name = \"spring.jms.cache.enabled\", havingValue = false)\n\t\tActiveMQConnectionFactory jmsConnectionFactory(ArtemisProperties properties, ListableBeanFactory beanFactory,\n\t\t\t\tArtemisConnectionDetails connectionDetails) {\n\t\t\treturn createJmsConnectionFactory(properties, connectionDetails, beanFactory);\n\t\t}\n\n\t\tprivate static ActiveMQConnectionFactory createJmsConnectionFactory(ArtemisProperties properties,\n\t\t\t\tArtemisConnectionDetails connectionDetails, ListableBeanFactory beanFactory) {\n\t\t\treturn new ArtemisConnectionFactoryFactory(beanFactory, properties, connectionDetails)\n\t\t\t\t.createConnectionFactory(ActiveMQConnectionFactory::new, ActiveMQConnectionFactory::new);\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(CachingConnectionFactory.class)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.jms.cache.enabled\", matchIfMissing = true)\n\t\tstatic class CachingConnectionFactoryConfiguration {\n\n\t\t\t@Bean(name = \"jmsConnectionFactory\")\n\t\t\tCachingConnectionFactory cachingJmsConnectionFactory(JmsProperties jmsProperties,\n\t\t\t\t\tArtemisProperties properties, ArtemisConnectionDetails connectionDetails,\n\t\t\t\t\tListableBeanFactory beanFactory) {\n\t\t\t\tJmsProperties.Cache cacheProperties = jmsProperties.getCache();\n\t\t\t\tCachingConnectionFactory connectionFactory = new CachingConnectionFactory(\n\t\t\t\t\t\tcreateJmsConnectionFactory(properties, connectionDetails, beanFactory));\n\t\t\t\tconnectionFactory.setCacheConsumers(cacheProperties.isConsumers());\n\t\t\t\tconnectionFactory.setCacheProducers(cacheProperties.isProducers());\n\t\t\t\tconnectionFactory.setSessionCacheSize(cacheProperties.getSessionCacheSize());\n\t\t\t\treturn connectionFactory;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class })\n\t@ConditionalOnBooleanProperty(\"spring.artemis.pool.enabled\")\n\tstatic class PooledConnectionFactoryConfiguration {\n\n\t\t@Bean(destroyMethod = \"stop\")\n\t\tJmsPoolConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, ArtemisProperties properties,\n\t\t\t\tArtemisConnectionDetails connectionDetails) {\n\t\t\tActiveMQConnectionFactory connectionFactory = new ArtemisConnectionFactoryFactory(beanFactory, properties,\n\t\t\t\t\tconnectionDetails)\n\t\t\t\t.createConnectionFactory(ActiveMQConnectionFactory::new, ActiveMQConnectionFactory::new);\n\t\t\treturn new JmsPoolConnectionFactoryFactory(properties.getPool())\n\t\t\t\t.createPooledConnectionFactory(connectionFactory);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisConnectionFactoryFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport java.util.function.Function;\n\nimport org.apache.activemq.artemis.api.core.TransportConfiguration;\nimport org.apache.activemq.artemis.api.core.client.ActiveMQClient;\nimport org.apache.activemq.artemis.api.core.client.ServerLocator;\nimport org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;\nimport org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Factory to create an Artemis {@link ActiveMQConnectionFactory} instance from properties\n * defined in {@link ArtemisProperties}.\n *\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Justin Bertram\n */\nclass ArtemisConnectionFactoryFactory {\n\n\tprivate static final String DEFAULT_BROKER_URL = \"tcp://localhost:61616\";\n\n\tstatic final String[] EMBEDDED_JMS_CLASSES = { \"org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS\",\n\t\t\t\"org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ\" };\n\n\tprivate final ArtemisProperties properties;\n\n\tprivate final ArtemisConnectionDetails connectionDetails;\n\n\tprivate final ListableBeanFactory beanFactory;\n\n\tArtemisConnectionFactoryFactory(ListableBeanFactory beanFactory, ArtemisProperties properties,\n\t\t\tArtemisConnectionDetails connectionDetails) {\n\t\tAssert.notNull(beanFactory, \"'beanFactory' must not be null\");\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tAssert.notNull(connectionDetails, \"'connectionDetails' must not be null\");\n\t\tthis.beanFactory = beanFactory;\n\t\tthis.properties = properties;\n\t\tthis.connectionDetails = connectionDetails;\n\t}\n\n\t<T extends ActiveMQConnectionFactory> T createConnectionFactory(Function<String, T> nativeFactoryCreator,\n\t\t\tFunction<ServerLocator, T> embeddedFactoryCreator) {\n\t\ttry {\n\t\t\tstartEmbeddedJms();\n\t\t\treturn doCreateConnectionFactory(nativeFactoryCreator, embeddedFactoryCreator);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create ActiveMQConnectionFactory\", ex);\n\t\t}\n\t}\n\n\tprivate void startEmbeddedJms() {\n\t\tfor (String embeddedJmsClass : EMBEDDED_JMS_CLASSES) {\n\t\t\tif (ClassUtils.isPresent(embeddedJmsClass, null)) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.beanFactory.getBeansOfType(Class.forName(embeddedJmsClass));\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate <T extends ActiveMQConnectionFactory> T doCreateConnectionFactory(Function<String, T> nativeFactoryCreator,\n\t\t\tFunction<ServerLocator, T> embeddedFactoryCreator) throws Exception {\n\t\tArtemisMode mode = this.connectionDetails.getMode();\n\t\tif (mode == null) {\n\t\t\tmode = deduceMode();\n\t\t}\n\t\tif (mode == ArtemisMode.EMBEDDED) {\n\t\t\treturn createEmbeddedConnectionFactory(embeddedFactoryCreator);\n\t\t}\n\t\treturn createNativeConnectionFactory(nativeFactoryCreator);\n\t}\n\n\t/**\n\t * Deduce the {@link ArtemisMode} to use if none has been set.\n\t * @return the mode\n\t */\n\tprivate ArtemisMode deduceMode() {\n\t\tif (this.properties.getEmbedded().isEnabled() && isEmbeddedJmsClassPresent()) {\n\t\t\treturn ArtemisMode.EMBEDDED;\n\t\t}\n\t\treturn ArtemisMode.NATIVE;\n\t}\n\n\tprivate boolean isEmbeddedJmsClassPresent() {\n\t\tfor (String embeddedJmsClass : EMBEDDED_JMS_CLASSES) {\n\t\t\tif (ClassUtils.isPresent(embeddedJmsClass, null)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate <T extends ActiveMQConnectionFactory> T createEmbeddedConnectionFactory(\n\t\t\tFunction<ServerLocator, T> factoryCreator) throws Exception {\n\t\ttry {\n\t\t\tTransportConfiguration transportConfiguration = new TransportConfiguration(\n\t\t\t\t\tInVMConnectorFactory.class.getName(), this.properties.getEmbedded().generateTransportParameters());\n\t\t\tServerLocator serverLocator = ActiveMQClient.createServerLocatorWithoutHA(transportConfiguration);\n\t\t\treturn factoryCreator.apply(serverLocator);\n\t\t}\n\t\tcatch (NoClassDefFoundError ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create InVM \"\n\t\t\t\t\t+ \"Artemis connection, ensure that artemis-jms-server.jar is in the classpath\", ex);\n\t\t}\n\t}\n\n\tprivate <T extends ActiveMQConnectionFactory> T createNativeConnectionFactory(Function<String, T> factoryCreator) {\n\t\tT connectionFactory = newNativeConnectionFactory(factoryCreator);\n\t\tString user = this.connectionDetails.getUser();\n\t\tif (StringUtils.hasText(user)) {\n\t\t\tconnectionFactory.setUser(user);\n\t\t\tconnectionFactory.setPassword(this.connectionDetails.getPassword());\n\t\t}\n\t\treturn connectionFactory;\n\t}\n\n\tprivate <T extends ActiveMQConnectionFactory> T newNativeConnectionFactory(Function<String, T> factoryCreator) {\n\t\tString brokerUrl = StringUtils.hasText(this.connectionDetails.getBrokerUrl())\n\t\t\t\t? this.connectionDetails.getBrokerUrl() : DEFAULT_BROKER_URL;\n\t\treturn factoryCreator.apply(brokerUrl);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisEmbeddedConfigurationFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport java.io.File;\n\nimport org.apache.activemq.artemis.api.core.QueueConfiguration;\nimport org.apache.activemq.artemis.api.core.RoutingType;\nimport org.apache.activemq.artemis.api.core.SimpleString;\nimport org.apache.activemq.artemis.api.core.TransportConfiguration;\nimport org.apache.activemq.artemis.core.config.Configuration;\nimport org.apache.activemq.artemis.core.config.CoreAddressConfiguration;\nimport org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;\nimport org.apache.activemq.artemis.core.remoting.impl.invm.InVMAcceptorFactory;\nimport org.apache.activemq.artemis.core.server.JournalType;\nimport org.apache.activemq.artemis.core.settings.impl.AddressSettings;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\n/**\n * Configuration used to create the embedded Artemis server.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ArtemisEmbeddedConfigurationFactory {\n\n\tprivate static final Log logger = LogFactory.getLog(ArtemisEmbeddedConfigurationFactory.class);\n\n\tprivate final ArtemisProperties.Embedded properties;\n\n\tArtemisEmbeddedConfigurationFactory(ArtemisProperties properties) {\n\t\tthis.properties = properties.getEmbedded();\n\t}\n\n\tConfiguration createConfiguration() {\n\t\tConfigurationImpl configuration = new ConfigurationImpl();\n\t\tconfiguration.setSecurityEnabled(false);\n\t\tconfiguration.setPersistenceEnabled(this.properties.isPersistent());\n\t\tString dataDir = getDataDir();\n\t\tconfiguration.setJournalDirectory(dataDir + \"/journal\");\n\t\tif (this.properties.isPersistent()) {\n\t\t\tconfiguration.setJournalType(JournalType.NIO);\n\t\t\tconfiguration.setLargeMessagesDirectory(dataDir + \"/largemessages\");\n\t\t\tconfiguration.setBindingsDirectory(dataDir + \"/bindings\");\n\t\t\tconfiguration.setPagingDirectory(dataDir + \"/paging\");\n\t\t}\n\t\tTransportConfiguration transportConfiguration = new TransportConfiguration(InVMAcceptorFactory.class.getName(),\n\t\t\t\tthis.properties.generateTransportParameters());\n\t\tconfiguration.getAcceptorConfigurations().add(transportConfiguration);\n\t\tif (this.properties.isDefaultClusterPassword() && logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Using default Artemis cluster password: \" + this.properties.getClusterPassword());\n\t\t}\n\t\tconfiguration.setClusterPassword(this.properties.getClusterPassword());\n\t\tconfiguration.addAddressConfiguration(createAddressConfiguration(\"DLQ\"));\n\t\tconfiguration.addAddressConfiguration(createAddressConfiguration(\"ExpiryQueue\"));\n\t\tconfiguration.addAddressSetting(\"#\", new AddressSettings().setDeadLetterAddress(SimpleString.of(\"DLQ\"))\n\t\t\t.setExpiryAddress(SimpleString.of(\"ExpiryQueue\")));\n\t\treturn configuration;\n\t}\n\n\tprivate CoreAddressConfiguration createAddressConfiguration(String name) {\n\t\treturn new CoreAddressConfiguration().setName(name)\n\t\t\t.addRoutingType(RoutingType.ANYCAST)\n\t\t\t.addQueueConfiguration(QueueConfiguration.of(name).setRoutingType(RoutingType.ANYCAST).setAddress(name));\n\t}\n\n\tprivate String getDataDir() {\n\t\tif (this.properties.getDataDirectory() != null) {\n\t\t\treturn this.properties.getDataDirectory();\n\t\t}\n\t\tString tempDirectory = System.getProperty(\"java.io.tmpdir\");\n\t\treturn new File(tempDirectory, \"artemis-data\").getAbsolutePath();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisEmbeddedServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport org.apache.activemq.artemis.api.core.QueueConfiguration;\nimport org.apache.activemq.artemis.api.core.RoutingType;\nimport org.apache.activemq.artemis.core.config.CoreAddressConfiguration;\nimport org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;\nimport org.apache.activemq.artemis.jms.server.config.JMSConfiguration;\nimport org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;\nimport org.apache.activemq.artemis.jms.server.config.TopicConfiguration;\nimport org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;\nimport org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;\nimport org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration used to create the embedded Artemis server.\n *\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(EmbeddedActiveMQ.class)\n@ConditionalOnBooleanProperty(name = \"spring.artemis.embedded.enabled\", matchIfMissing = true)\nclass ArtemisEmbeddedServerConfiguration {\n\n\tprivate final ArtemisProperties properties;\n\n\tArtemisEmbeddedServerConfiguration(ArtemisProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\torg.apache.activemq.artemis.core.config.Configuration artemisConfiguration() {\n\t\treturn new ArtemisEmbeddedConfigurationFactory(this.properties).createConfiguration();\n\t}\n\n\t@Bean(initMethod = \"start\", destroyMethod = \"stop\")\n\t@ConditionalOnMissingBean\n\tEmbeddedActiveMQ embeddedActiveMq(org.apache.activemq.artemis.core.config.Configuration configuration,\n\t\t\tJMSConfiguration jmsConfiguration,\n\t\t\tObjectProvider<ArtemisConfigurationCustomizer> configurationCustomizers) {\n\t\tfor (JMSQueueConfiguration queueConfiguration : jmsConfiguration.getQueueConfigurations()) {\n\t\t\tString queueName = queueConfiguration.getName();\n\t\t\tconfiguration.addAddressConfiguration(new CoreAddressConfiguration().setName(queueName)\n\t\t\t\t.addRoutingType(RoutingType.ANYCAST)\n\t\t\t\t.addQueueConfiguration(QueueConfiguration.of(queueName)\n\t\t\t\t\t.setAddress(queueName)\n\t\t\t\t\t.setFilterString(queueConfiguration.getSelector())\n\t\t\t\t\t.setDurable(queueConfiguration.isDurable())\n\t\t\t\t\t.setRoutingType(RoutingType.ANYCAST)));\n\t\t}\n\t\tfor (TopicConfiguration topicConfiguration : jmsConfiguration.getTopicConfigurations()) {\n\t\t\tconfiguration.addAddressConfiguration(new CoreAddressConfiguration().setName(topicConfiguration.getName())\n\t\t\t\t.addRoutingType(RoutingType.MULTICAST));\n\t\t}\n\t\tconfigurationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configuration));\n\t\tEmbeddedActiveMQ embeddedActiveMq = new EmbeddedActiveMQ();\n\t\tembeddedActiveMq.setConfiguration(configuration);\n\t\treturn embeddedActiveMq;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJMSConfiguration artemisJmsConfiguration(ObjectProvider<JMSQueueConfiguration> queuesConfiguration,\n\t\t\tObjectProvider<TopicConfiguration> topicsConfiguration) {\n\t\tJMSConfiguration configuration = new JMSConfigurationImpl();\n\t\tconfiguration.getQueueConfigurations().addAll(queuesConfiguration.orderedStream().toList());\n\t\tconfiguration.getTopicConfigurations().addAll(topicsConfiguration.orderedStream().toList());\n\t\taddQueues(configuration, this.properties.getEmbedded().getQueues());\n\t\taddTopics(configuration, this.properties.getEmbedded().getTopics());\n\t\treturn configuration;\n\t}\n\n\tprivate void addQueues(JMSConfiguration configuration, String[] queues) {\n\t\tboolean persistent = this.properties.getEmbedded().isPersistent();\n\t\tfor (String queue : queues) {\n\t\t\tJMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();\n\t\t\tjmsQueueConfiguration.setName(queue);\n\t\t\tjmsQueueConfiguration.setDurable(persistent);\n\t\t\tjmsQueueConfiguration.setBindings(\"/queue/\" + queue);\n\t\t\tconfiguration.getQueueConfigurations().add(jmsQueueConfiguration);\n\t\t}\n\t}\n\n\tprivate void addTopics(JMSConfiguration configuration, String[] topics) {\n\t\tfor (String topic : topics) {\n\t\t\tTopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();\n\t\t\ttopicConfiguration.setName(topic);\n\t\t\ttopicConfiguration.setBindings(\"/topic/\" + topic);\n\t\t\tconfiguration.getTopicConfigurations().add(topicConfiguration);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisMode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\n/**\n * Define the mode in which Artemis can operate.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic enum ArtemisMode {\n\n\t/**\n\t * Connect to a broker using the native Artemis protocol (i.e. netty).\n\t */\n\tNATIVE,\n\n\t/**\n\t * Embed (i.e. start) the broker in the application.\n\t */\n\tEMBEDDED\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisNoOpBindingRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport org.apache.activemq.artemis.spi.core.naming.BindingRegistry;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A no-op implementation of the {@link BindingRegistry}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class ArtemisNoOpBindingRegistry implements BindingRegistry {\n\n\t@Override\n\tpublic @Nullable Object lookup(String s) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean bind(String s, Object o) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic void unbind(String s) {\n\t}\n\n\t@Override\n\tpublic void close() {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.activemq.artemis.core.remoting.impl.invm.TransportConstants;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties;\n\n/**\n * Configuration properties for Artemis.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Justin Bertram\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.artemis\")\npublic class ArtemisProperties {\n\n\t/**\n\t * Artemis deployment mode, auto-detected by default.\n\t */\n\tprivate @Nullable ArtemisMode mode;\n\n\t/**\n\t * Artemis broker url.\n\t */\n\tprivate @Nullable String brokerUrl;\n\n\t/**\n\t * Login user of the broker.\n\t */\n\tprivate @Nullable String user;\n\n\t/**\n\t * Login password of the broker.\n\t */\n\tprivate @Nullable String password;\n\n\tprivate final Embedded embedded = new Embedded();\n\n\t@NestedConfigurationProperty\n\tprivate final JmsPoolConnectionFactoryProperties pool = new JmsPoolConnectionFactoryProperties();\n\n\tpublic @Nullable ArtemisMode getMode() {\n\t\treturn this.mode;\n\t}\n\n\tpublic void setMode(@Nullable ArtemisMode mode) {\n\t\tthis.mode = mode;\n\t}\n\n\tpublic @Nullable String getBrokerUrl() {\n\t\treturn this.brokerUrl;\n\t}\n\n\tpublic void setBrokerUrl(@Nullable String brokerUrl) {\n\t\tthis.brokerUrl = brokerUrl;\n\t}\n\n\tpublic @Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\tpublic void setUser(@Nullable String user) {\n\t\tthis.user = user;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Embedded getEmbedded() {\n\t\treturn this.embedded;\n\t}\n\n\tpublic JmsPoolConnectionFactoryProperties getPool() {\n\t\treturn this.pool;\n\t}\n\n\t/**\n\t * Configuration for an embedded Artemis server.\n\t */\n\tpublic static class Embedded {\n\n\t\tprivate static final AtomicInteger serverIdCounter = new AtomicInteger();\n\n\t\t/**\n\t\t * Server ID. By default, an auto-incremented counter is used.\n\t\t */\n\t\tprivate int serverId = serverIdCounter.getAndIncrement();\n\n\t\t/**\n\t\t * Whether to enable embedded mode if the Artemis server APIs are available.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\t/**\n\t\t * Whether to enable persistent store.\n\t\t */\n\t\tprivate boolean persistent;\n\n\t\t/**\n\t\t * Journal file directory. Not necessary if persistence is turned off.\n\t\t */\n\t\tprivate @Nullable String dataDirectory;\n\n\t\t/**\n\t\t * List of queues to create on startup.\n\t\t */\n\t\tprivate String[] queues = new String[0];\n\n\t\t/**\n\t\t * List of topics to create on startup.\n\t\t */\n\t\tprivate String[] topics = new String[0];\n\n\t\t/**\n\t\t * Cluster password. Randomly generated on startup by default.\n\t\t */\n\t\tprivate String clusterPassword = UUID.randomUUID().toString();\n\n\t\tprivate boolean defaultClusterPassword = true;\n\n\t\tpublic int getServerId() {\n\t\t\treturn this.serverId;\n\t\t}\n\n\t\tpublic void setServerId(int serverId) {\n\t\t\tthis.serverId = serverId;\n\t\t}\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic boolean isPersistent() {\n\t\t\treturn this.persistent;\n\t\t}\n\n\t\tpublic void setPersistent(boolean persistent) {\n\t\t\tthis.persistent = persistent;\n\t\t}\n\n\t\tpublic @Nullable String getDataDirectory() {\n\t\t\treturn this.dataDirectory;\n\t\t}\n\n\t\tpublic void setDataDirectory(@Nullable String dataDirectory) {\n\t\t\tthis.dataDirectory = dataDirectory;\n\t\t}\n\n\t\tpublic String[] getQueues() {\n\t\t\treturn this.queues;\n\t\t}\n\n\t\tpublic void setQueues(String[] queues) {\n\t\t\tthis.queues = queues;\n\t\t}\n\n\t\tpublic String[] getTopics() {\n\t\t\treturn this.topics;\n\t\t}\n\n\t\tpublic void setTopics(String[] topics) {\n\t\t\tthis.topics = topics;\n\t\t}\n\n\t\tpublic String getClusterPassword() {\n\t\t\treturn this.clusterPassword;\n\t\t}\n\n\t\tpublic void setClusterPassword(String clusterPassword) {\n\t\t\tthis.clusterPassword = clusterPassword;\n\t\t\tthis.defaultClusterPassword = false;\n\t\t}\n\n\t\tpublic boolean isDefaultClusterPassword() {\n\t\t\treturn this.defaultClusterPassword;\n\t\t}\n\n\t\t/**\n\t\t * Creates the minimal transport parameters for an embedded transport\n\t\t * configuration.\n\t\t * @return the transport parameters\n\t\t * @see TransportConstants#SERVER_ID_PROP_NAME\n\t\t */\n\t\tpublic Map<String, Object> generateTransportParameters() {\n\t\t\tMap<String, Object> parameters = new HashMap<>();\n\t\t\tparameters.put(TransportConstants.SERVER_ID_PROP_NAME, getServerId());\n\t\t\treturn parameters;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/ArtemisXAConnectionFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.transaction.TransactionManager;\nimport org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.jms.XAConnectionFactoryWrapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Configuration for Artemis XA {@link ConnectionFactory}.\n *\n * @author Eddú Meléndez\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(ConnectionFactory.class)\n@ConditionalOnClass(TransactionManager.class)\n@ConditionalOnBean(XAConnectionFactoryWrapper.class)\nclass ArtemisXAConnectionFactoryConfiguration {\n\n\t@Primary\n\t@Bean(name = { \"jmsConnectionFactory\", \"xaJmsConnectionFactory\" })\n\tConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, ArtemisProperties properties,\n\t\t\tArtemisConnectionDetails connectionDetails, XAConnectionFactoryWrapper wrapper) throws Exception {\n\t\treturn wrapper\n\t\t\t.wrapConnectionFactory(new ArtemisConnectionFactoryFactory(beanFactory, properties, connectionDetails)\n\t\t\t\t.createConnectionFactory(ActiveMQXAConnectionFactory::new, ActiveMQXAConnectionFactory::new));\n\t}\n\n\t@Bean\n\tActiveMQXAConnectionFactory nonXaJmsConnectionFactory(ListableBeanFactory beanFactory, ArtemisProperties properties,\n\t\t\tArtemisConnectionDetails connectionDetails) {\n\t\treturn new ArtemisConnectionFactoryFactory(beanFactory, properties, connectionDetails)\n\t\t\t.createConnectionFactory(ActiveMQXAConnectionFactory::new, ActiveMQXAConnectionFactory::new);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Artemis.\n *\n * @author Eddú Meléndez\n */\n@NullMarked\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/docker/compose/ArtemisDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails;\nimport org.springframework.boot.artemis.autoconfigure.ArtemisMode;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link ArtemisConnectionDetails} for an {@code artemis} service.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass ArtemisDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<ArtemisConnectionDetails> {\n\n\tprivate static final int ACTIVEMQ_PORT = 61616;\n\n\tprotected ArtemisDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"apache/activemq-artemis\");\n\t}\n\n\t@Override\n\tprotected ArtemisConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ArtemisDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link ArtemisConnectionDetails} backed by a {@code artemis}\n\t * {@link RunningService}.\n\t */\n\tstatic class ArtemisDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements ArtemisConnectionDetails {\n\n\t\tprivate final ArtemisEnvironment environment;\n\n\t\tprivate final String brokerUrl;\n\n\t\tprotected ArtemisDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new ArtemisEnvironment(service.env());\n\t\t\tthis.brokerUrl = \"tcp://\" + service.host() + \":\" + service.ports().get(ACTIVEMQ_PORT);\n\t\t}\n\n\t\t@Override\n\t\tpublic ArtemisMode getMode() {\n\t\t\treturn ArtemisMode.NATIVE;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn this.brokerUrl;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn this.environment.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/docker/compose/ArtemisEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Artemis environment details.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass ArtemisEnvironment {\n\n\tprivate final @Nullable String user;\n\n\tprivate final @Nullable String password;\n\n\tArtemisEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.user = env.get(\"ARTEMIS_USER\");\n\t\tthis.password = env.get(\"ARTEMIS_PASSWORD\");\n\t}\n\n\t@Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Artemis service connections.\n */\n@NullMarked\npackage org.springframework.boot.artemis.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/testcontainers/ArtemisContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.testcontainers;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.activemq.ArtemisContainer;\n\nimport org.springframework.boot.artemis.autoconfigure.ArtemisConnectionDetails;\nimport org.springframework.boot.artemis.autoconfigure.ArtemisMode;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link ArtemisConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link ArtemisContainer}.\n *\n * @author Eddú Meléndez\n */\nclass ArtemisContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<ArtemisContainer, ArtemisConnectionDetails> {\n\n\t@Override\n\tprotected ArtemisConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<ArtemisContainer> source) {\n\t\treturn new ArtemisContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class ArtemisContainerConnectionDetails extends ContainerConnectionDetails<ArtemisContainer>\n\t\t\timplements ArtemisConnectionDetails {\n\n\t\tprivate ArtemisContainerConnectionDetails(ContainerConnectionSource<ArtemisContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ArtemisMode getMode() {\n\t\t\treturn ArtemisMode.NATIVE;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn getContainer().getBrokerUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUser() {\n\t\t\treturn getContainer().getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/java/org/springframework/boot/artemis/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Artemis service connections.\n */\n@NullMarked\npackage org.springframework.boot.artemis.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.artemis.broker-url\",\n      \"defaultValue\": \"tcp://localhost:61616\"\n    },\n    {\n      \"name\": \"spring.artemis.host\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.artemis.broker-url\",\n        \"level\": \"error\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.artemis.pool.block-if-full\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to block when a connection is requested and the pool is full. Set it to false to throw a \\\"JMSException\\\" instead.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.artemis.pool.block-if-full-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Blocking period before throwing an exception if the pool is still full.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": \"-1ms\"\n    },\n    {\n      \"name\": \"spring.artemis.pool.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether a JmsPoolConnectionFactory should be created, instead of a regular ConnectionFactory.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.artemis.pool.idle-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Connection idle timeout.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": \"30s\"\n    },\n    {\n      \"name\": \"spring.artemis.pool.max-connections\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of pooled connections.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": 1\n    },\n    {\n      \"name\": \"spring.artemis.pool.max-sessions-per-connection\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of pooled sessions per connection in the pool.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": 500\n    },\n    {\n      \"name\": \"spring.artemis.pool.maximum-active-session-per-connection\",\n      \"deprecation\": {\n        \"replacement\": \"spring.artemis.pool.max-sessions-per-connection\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.artemis.pool.time-between-expiration-check\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Time to sleep between runs of the idle connection eviction thread. When negative, no idle connection eviction thread runs.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": \"-1ms\"\n    },\n    {\n      \"name\": \"spring.artemis.pool.use-anonymous-producers\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use only one anonymous \\\"MessageProducer\\\" instance. Set it to false to create one \\\"MessageProducer\\\" every time one is required.\",\n      \"sourceType\": \"org.springframework.boot.jms.autoconfigure.JmsPoolConnectionFactoryProperties\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.artemis.port\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.artemis.broker-url\",\n        \"level\": \"error\",\n        \"since\": \"2.5.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.artemis.autoconfigure.ArtemisAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-artemis/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.artemis.docker.compose.ArtemisDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.artemis.testcontainers.ArtemisContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-artemis/src/test/java/org/springframework/boot/artemis/autoconfigure/ArtemisAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.UUID;\n\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.Message;\nimport jakarta.jms.TextMessage;\nimport org.apache.activemq.artemis.api.core.RoutingType;\nimport org.apache.activemq.artemis.api.core.SimpleString;\nimport org.apache.activemq.artemis.api.core.TransportConfiguration;\nimport org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;\nimport org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;\nimport org.apache.activemq.artemis.core.server.ActiveMQServer;\nimport org.apache.activemq.artemis.core.server.BindingQueryResult;\nimport org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;\nimport org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;\nimport org.apache.activemq.artemis.jms.server.config.JMSConfiguration;\nimport org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;\nimport org.apache.activemq.artemis.jms.server.config.TopicConfiguration;\nimport org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;\nimport org.apache.activemq.artemis.jms.server.config.impl.JMSQueueConfigurationImpl;\nimport org.apache.activemq.artemis.jms.server.config.impl.TopicConfigurationImpl;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\nimport org.springframework.boot.artemis.autoconfigure.ArtemisAutoConfiguration.PropertiesArtemisConnectionDetails;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.connection.CachingConnectionFactory;\nimport org.springframework.jms.core.JmsTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArtemisAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\n@EnabledForJreRange(min = JRE.JAVA_17, max = JRE.JAVA_22,\n\t\tdisabledReason = \"https://issues.apache.org/jira/browse/ARTEMIS-4975\")\nclass ArtemisAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ArtemisAutoConfiguration.class, JmsAutoConfiguration.class));\n\n\t@Test\n\tvoid connectionFactoryIsCachedByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t.hasSingleBean(CachingConnectionFactory.class)\n\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\tassertThat(connectionFactory.getTargetConnectionFactory()).isInstanceOf(ActiveMQConnectionFactory.class);\n\t\t\tassertThat(connectionFactory.isCacheConsumers()).isFalse();\n\t\t\tassertThat(connectionFactory.isCacheProducers()).isTrue();\n\t\t\tassertThat(connectionFactory.getSessionCacheSize()).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid connectionFactoryCachingCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.cache.consumers=true\", \"spring.jms.cache.producers=false\",\n\t\t\t\t\t\"spring.jms.cache.session-cache-size=10\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(CachingConnectionFactory.class)\n\t\t\t\t\t.hasBean(\"jmsConnectionFactory\");\n\t\t\t\tCachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(\"jmsConnectionFactory\")).isSameAs(connectionFactory);\n\t\t\t\tassertThat(connectionFactory.isCacheConsumers()).isTrue();\n\t\t\t\tassertThat(connectionFactory.isCacheProducers()).isFalse();\n\t\t\t\tassertThat(connectionFactory.getSessionCacheSize()).isEqualTo(10);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionFactoryCachingCanBeDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.cache.enabled=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(CachingConnectionFactory.class);\n\t\t\t\tConnectionFactory connectionFactory = getConnectionFactory(context);\n\t\t\t\tassertThat(connectionFactory).isInstanceOf(ActiveMQConnectionFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid nativeConnectionFactory() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.mode:native\")\n\t\t\t.run((context) -> {\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tConnectionFactory connectionFactory = getConnectionFactory(context);\n\t\t\t\tassertThat(connectionFactory).isEqualTo(jmsTemplate.getConnectionFactory());\n\t\t\t\tActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(connectionFactory);\n\t\t\t\tassertNettyConnectionFactory(activeMQConnectionFactory, \"localhost\", 61616);\n\t\t\t\tassertThat(activeMQConnectionFactory.getUser()).isNull();\n\t\t\t\tassertThat(activeMQConnectionFactory.getPassword()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid nativeConnectionFactoryCustomBrokerUrl() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.mode:native\", \"spring.artemis.broker-url:tcp://192.168.1.144:9876\")\n\t\t\t.run((context) -> assertNettyConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)),\n\t\t\t\t\t\"192.168.1.144\", 9876));\n\t}\n\n\t@Test\n\tvoid nativeConnectionFactoryCredentials() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.mode:native\", \"spring.artemis.user:user\",\n\t\t\t\t\t\"spring.artemis.password:secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tConnectionFactory connectionFactory = getConnectionFactory(context);\n\t\t\t\tassertThat(connectionFactory).isEqualTo(jmsTemplate.getConnectionFactory());\n\t\t\t\tActiveMQConnectionFactory activeMQConnectionFactory = getActiveMQConnectionFactory(connectionFactory);\n\t\t\t\tassertNettyConnectionFactory(activeMQConnectionFactory, \"localhost\", 61616);\n\t\t\t\tassertThat(activeMQConnectionFactory.getUser()).isEqualTo(\"user\");\n\t\t\t\tassertThat(activeMQConnectionFactory.getPassword()).isEqualTo(\"secret\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedConnectionFactory() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.mode:embedded\")\n\t\t\t.run((context) -> {\n\t\t\t\tArtemisProperties properties = context.getBean(ArtemisProperties.class);\n\t\t\t\tassertThat(properties.getMode()).isEqualTo(ArtemisMode.EMBEDDED);\n\t\t\t\tassertThat(context).hasSingleBean(EmbeddedActiveMQ.class);\n\t\t\t\torg.apache.activemq.artemis.core.config.Configuration configuration = context\n\t\t\t\t\t.getBean(org.apache.activemq.artemis.core.config.Configuration.class);\n\t\t\t\tassertThat(configuration.isPersistenceEnabled()).isFalse();\n\t\t\t\tassertThat(configuration.isSecurityEnabled()).isFalse();\n\t\t\t\tassertInVmConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedConnectionFactoryByDefault() {\n\t\t// No mode is specified\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(EmbeddedActiveMQ.class);\n\t\t\torg.apache.activemq.artemis.core.config.Configuration configuration = context\n\t\t\t\t.getBean(org.apache.activemq.artemis.core.config.Configuration.class);\n\t\t\tassertThat(configuration.isPersistenceEnabled()).isFalse();\n\t\t\tassertThat(configuration.isSecurityEnabled()).isFalse();\n\t\t\tassertInVmConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)));\n\t\t});\n\t}\n\n\t@Test\n\tvoid nativeConnectionFactoryIfEmbeddedServiceDisabledExplicitly() {\n\t\t// No mode is specified\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.embedded.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(ActiveMQServer.class);\n\t\t\t\tassertNettyConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)), \"localhost\",\n\t\t\t\t\t\t61616);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedConnectionFactoryEvenIfEmbeddedServiceDisabled() {\n\t\t// No mode is specified\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.mode:embedded\", \"spring.artemis.embedded.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(ActiveMQServer.class)).isEmpty();\n\t\t\t\tassertInVmConnectionFactory(getActiveMQConnectionFactory(getConnectionFactory(context)));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedServerWithDestinations() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.embedded.queues=Queue1,Queue2\", \"spring.artemis.embedded.topics=Topic1\")\n\t\t\t.run((context) -> {\n\t\t\t\tDestinationChecker checker = new DestinationChecker(context);\n\t\t\t\tchecker.checkQueue(\"Queue1\", true);\n\t\t\t\tchecker.checkQueue(\"Queue2\", true);\n\t\t\t\tchecker.checkQueue(\"NonExistentQueue\", false);\n\t\t\t\tchecker.checkTopic(\"Topic1\", true);\n\t\t\t\tchecker.checkTopic(\"NonExistentTopic\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedServerWithDestinationConfig() {\n\t\tthis.contextRunner.withUserConfiguration(DestinationConfiguration.class).run((context) -> {\n\t\t\tDestinationChecker checker = new DestinationChecker(context);\n\t\t\tchecker.checkQueue(\"sampleQueue\", true);\n\t\t\tchecker.checkTopic(\"sampleTopic\", true);\n\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedServiceWithCustomJmsConfiguration() {\n\t\t// Ignored with custom config\n\t\tthis.contextRunner.withUserConfiguration(CustomJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.embedded.queues=Queue1,Queue2\")\n\t\t\t.run((context) -> {\n\t\t\t\tDestinationChecker checker = new DestinationChecker(context);\n\t\t\t\tchecker.checkQueue(\"custom\", true); // See CustomJmsConfiguration\n\t\t\t\tchecker.checkQueue(\"Queue1\", false);\n\t\t\t\tchecker.checkQueue(\"Queue2\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid embeddedServiceWithCustomArtemisConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomArtemisConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(org.apache.activemq.artemis.core.config.Configuration.class).getName())\n\t\t\t\t.isEqualTo(\"customFooBar\"));\n\t}\n\n\t@Test\n\tvoid embeddedWithPersistentMode(@TempDir Path temp) throws IOException {\n\t\tFile dataDirectory = Files.createTempDirectory(temp, null).toFile();\n\t\tfinal String messageId = UUID.randomUUID().toString();\n\t\t// Start the server and post a message to some queue\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.embedded.queues=TestQueue\", \"spring.artemis.embedded.persistent:true\",\n\t\t\t\t\t\"spring.artemis.embedded.dataDirectory:\" + dataDirectory.getAbsolutePath())\n\t\t\t.run((context) -> context.getBean(JmsTemplate.class)\n\t\t\t\t.send(\"TestQueue\", (session) -> session.createTextMessage(messageId)))\n\t\t\t.run((context) -> {\n\t\t\t\t// Start the server again and check if our message is still here\n\t\t\t\tJmsTemplate jmsTemplate2 = context.getBean(JmsTemplate.class);\n\t\t\t\tjmsTemplate2.setReceiveTimeout(1000L);\n\t\t\t\tMessage message = jmsTemplate2.receive(\"TestQueue\");\n\t\t\t\tassertThat(message).isNotNull();\n\t\t\t\tassertThat(((TextMessage) message).getText()).isEqualTo(messageId);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid severalEmbeddedBrokers() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.embedded.queues=Queue1\")\n\t\t\t.run((first) -> {\n\t\t\t\tthis.contextRunner.withPropertyValues(\"spring.artemis.embedded.queues=Queue2\").run((second) -> {\n\t\t\t\t\tArtemisProperties firstProperties = first.getBean(ArtemisProperties.class);\n\t\t\t\t\tArtemisProperties secondProperties = second.getBean(ArtemisProperties.class);\n\t\t\t\t\tassertThat(firstProperties.getEmbedded().getServerId())\n\t\t\t\t\t\t.isLessThan(secondProperties.getEmbedded().getServerId());\n\t\t\t\t\tDestinationChecker firstChecker = new DestinationChecker(first);\n\t\t\t\t\tfirstChecker.checkQueue(\"Queue1\", true);\n\t\t\t\t\tfirstChecker.checkQueue(\"Queue2\", false);\n\t\t\t\t\tDestinationChecker secondChecker = new DestinationChecker(second);\n\t\t\t\t\tsecondChecker.checkQueue(\"Queue1\", false);\n\t\t\t\t\tsecondChecker.checkQueue(\"Queue2\", true);\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectToASpecificEmbeddedBroker() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.artemis.embedded.serverId=93\", \"spring.artemis.embedded.queues=Queue1\")\n\t\t\t.run((first) -> {\n\t\t\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t\t\t.withPropertyValues(\"spring.artemis.mode=embedded\",\n\t\t\t\t\t\t\t// Connect to the \"main\" broker\n\t\t\t\t\t\t\t\"spring.artemis.embedded.serverId=93\",\n\t\t\t\t\t\t\t// Do not start a specific one\n\t\t\t\t\t\t\t\"spring.artemis.embedded.enabled=false\")\n\t\t\t\t\t.run((secondContext) -> {\n\t\t\t\t\t\tfirst.getBean(JmsTemplate.class).convertAndSend(\"Queue1\", \"test\");\n\t\t\t\t\t\tassertThat(secondContext.getBean(JmsTemplate.class).receiveAndConvert(\"Queue1\"))\n\t\t\t\t\t\t\t.isEqualTo(\"test\");\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultPoolConnectionFactoryIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.artemis.pool.enabled=true\").run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)).hasSize(1);\n\t\t\tJmsPoolConnectionFactory connectionFactory = context.getBean(JmsPoolConnectionFactory.class);\n\t\t\tJmsPoolConnectionFactory defaultFactory = new JmsPoolConnectionFactory();\n\t\t\tassertThat(connectionFactory.isBlockIfSessionPoolIsFull())\n\t\t\t\t.isEqualTo(defaultFactory.isBlockIfSessionPoolIsFull());\n\t\t\tassertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout())\n\t\t\t\t.isEqualTo(defaultFactory.getBlockIfSessionPoolIsFullTimeout());\n\t\t\tassertThat(connectionFactory.getConnectionIdleTimeout())\n\t\t\t\t.isEqualTo(defaultFactory.getConnectionIdleTimeout());\n\t\t\tassertThat(connectionFactory.getMaxConnections()).isEqualTo(defaultFactory.getMaxConnections());\n\t\t\tassertThat(connectionFactory.getMaxSessionsPerConnection())\n\t\t\t\t.isEqualTo(defaultFactory.getMaxSessionsPerConnection());\n\t\t\tassertThat(connectionFactory.getConnectionCheckInterval())\n\t\t\t\t.isEqualTo(defaultFactory.getConnectionCheckInterval());\n\t\t\tassertThat(connectionFactory.isUseAnonymousProducers()).isEqualTo(defaultFactory.isUseAnonymousProducers());\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPoolConnectionFactoryIsApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.artemis.pool.enabled=true\", \"spring.artemis.pool.blockIfFull=false\",\n\t\t\t\t\t\"spring.artemis.pool.blockIfFullTimeout=64\", \"spring.artemis.pool.idleTimeout=512\",\n\t\t\t\t\t\"spring.artemis.pool.maxConnections=256\", \"spring.artemis.pool.maxSessionsPerConnection=1024\",\n\t\t\t\t\t\"spring.artemis.pool.timeBetweenExpirationCheck=2048\",\n\t\t\t\t\t\"spring.artemis.pool.useAnonymousProducers=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(JmsPoolConnectionFactory.class)).hasSize(1);\n\t\t\t\tJmsPoolConnectionFactory connectionFactory = context.getBean(JmsPoolConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.isBlockIfSessionPoolIsFull()).isFalse();\n\t\t\t\tassertThat(connectionFactory.getBlockIfSessionPoolIsFullTimeout()).isEqualTo(64);\n\t\t\t\tassertThat(connectionFactory.getConnectionIdleTimeout()).isEqualTo(512);\n\t\t\t\tassertThat(connectionFactory.getMaxConnections()).isEqualTo(256);\n\t\t\t\tassertThat(connectionFactory.getMaxSessionsPerConnection()).isEqualTo(1024);\n\t\t\t\tassertThat(connectionFactory.getConnectionCheckInterval()).isEqualTo(2048);\n\t\t\t\tassertThat(connectionFactory.isUseAnonymousProducers()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid poolConnectionFactoryConfiguration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.artemis.pool.enabled:true\").run((context) -> {\n\t\t\tConnectionFactory factory = getConnectionFactory(context);\n\t\t\tassertThat(factory).isInstanceOf(JmsPoolConnectionFactory.class);\n\t\t\tcontext.getSourceApplicationContext().close();\n\t\t\tassertThat(factory.createConnection()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid cachingConnectionFactoryNotOnTheClasspathThenSimpleConnectionFactoryAutoConfigured() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(CachingConnectionFactory.class))\n\t\t\t.withPropertyValues(\"spring.artemis.pool.enabled=false\", \"spring.jms.cache.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ActiveMQConnectionFactory.class));\n\t}\n\n\t@Test\n\tvoid cachingConnectionFactoryNotOnTheClasspathAndCacheEnabledThenSimpleConnectionFactoryNotConfigured() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(CachingConnectionFactory.class))\n\t\t\t.withPropertyValues(\"spring.artemis.pool.enabled=false\", \"spring.jms.cache.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ActiveMQConnectionFactory.class));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesArtemisConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(CachingConnectionFactory.class))\n\t\t\t.withPropertyValues(\"spring.artemis.pool.enabled=false\", \"spring.jms.cache.enabled=false\")\n\t\t\t.withUserConfiguration(TestConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ArtemisConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesArtemisConnectionDetails.class);\n\t\t\t\tActiveMQConnectionFactory connectionFactory = context.getBean(ActiveMQConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.toURI().toString()).startsWith(\"tcp://localhost:12345\");\n\t\t\t\tassertThat(connectionFactory.getUser()).isEqualTo(\"springuser\");\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(\"spring\");\n\t\t\t});\n\t}\n\n\tprivate ConnectionFactory getConnectionFactory(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasBean(\"jmsConnectionFactory\");\n\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\tassertThat(connectionFactory).isSameAs(context.getBean(\"jmsConnectionFactory\"));\n\t\treturn connectionFactory;\n\t}\n\n\tprivate ActiveMQConnectionFactory getActiveMQConnectionFactory(ConnectionFactory connectionFactory) {\n\t\tassertThat(connectionFactory).isInstanceOf(CachingConnectionFactory.class);\n\t\tConnectionFactory targetConnectionFactory = ((CachingConnectionFactory) connectionFactory)\n\t\t\t.getTargetConnectionFactory();\n\t\tassertThat(targetConnectionFactory).isNotNull();\n\t\treturn (ActiveMQConnectionFactory) targetConnectionFactory;\n\t}\n\n\tprivate TransportConfiguration assertInVmConnectionFactory(ActiveMQConnectionFactory connectionFactory) {\n\t\tTransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);\n\t\tassertThat(transportConfig.getFactoryClassName()).isEqualTo(InVMConnectorFactory.class.getName());\n\t\treturn transportConfig;\n\t}\n\n\tprivate TransportConfiguration assertNettyConnectionFactory(ActiveMQConnectionFactory connectionFactory,\n\t\t\tString host, int port) {\n\t\tTransportConfiguration transportConfig = getSingleTransportConfiguration(connectionFactory);\n\t\tassertThat(transportConfig.getFactoryClassName()).isEqualTo(NettyConnectorFactory.class.getName());\n\t\tassertThat(transportConfig.getParams()).containsEntry(\"host\", host);\n\t\tObject transportConfigPort = transportConfig.getParams().get(\"port\");\n\t\tif (transportConfigPort instanceof String portString) {\n\t\t\ttransportConfigPort = Integer.parseInt(portString);\n\t\t}\n\t\tassertThat(transportConfigPort).isEqualTo(port);\n\t\treturn transportConfig;\n\t}\n\n\tprivate TransportConfiguration getSingleTransportConfiguration(ActiveMQConnectionFactory connectionFactory) {\n\t\tTransportConfiguration[] transportConfigurations = connectionFactory.getServerLocator()\n\t\t\t.getStaticTransportConfigurations();\n\t\tassertThat(transportConfigurations).hasSize(1);\n\t\treturn transportConfigurations[0];\n\t}\n\n\tprivate static final class DestinationChecker {\n\n\t\tprivate final ActiveMQServer server;\n\n\t\tprivate DestinationChecker(ApplicationContext applicationContext) {\n\t\t\tthis.server = applicationContext.getBean(EmbeddedActiveMQ.class).getActiveMQServer();\n\t\t}\n\n\t\tvoid checkQueue(String name, boolean shouldExist) {\n\t\t\tcheckDestination(name, RoutingType.ANYCAST, shouldExist);\n\t\t}\n\n\t\tvoid checkTopic(String name, boolean shouldExist) {\n\t\t\tcheckDestination(name, RoutingType.MULTICAST, shouldExist);\n\t\t}\n\n\t\tvoid checkDestination(String name, RoutingType routingType, boolean shouldExist) {\n\t\t\ttry {\n\t\t\t\tBindingQueryResult result = this.server.bindingQuery(SimpleString.of(name));\n\t\t\t\tassertThat(result.isExists()).isEqualTo(shouldExist);\n\t\t\t\tif (shouldExist) {\n\t\t\t\t\tassertThat(result.getAddressInfo().getRoutingType()).isEqualTo(routingType);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DestinationConfiguration {\n\n\t\t@Bean\n\t\tJMSQueueConfiguration sampleQueueConfiguration() {\n\t\t\tJMSQueueConfigurationImpl jmsQueueConfiguration = new JMSQueueConfigurationImpl();\n\t\t\tjmsQueueConfiguration.setName(\"sampleQueue\");\n\t\t\tjmsQueueConfiguration.setSelector(\"foo=bar\");\n\t\t\tjmsQueueConfiguration.setDurable(false);\n\t\t\tjmsQueueConfiguration.setBindings(\"/queue/1\");\n\t\t\treturn jmsQueueConfiguration;\n\t\t}\n\n\t\t@Bean\n\t\tTopicConfiguration sampleTopicConfiguration() {\n\t\t\tTopicConfigurationImpl topicConfiguration = new TopicConfigurationImpl();\n\t\t\ttopicConfiguration.setName(\"sampleTopic\");\n\t\t\ttopicConfiguration.setBindings(\"/topic/1\");\n\t\t\treturn topicConfiguration;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJmsConfiguration {\n\n\t\t@Bean\n\t\tJMSConfiguration myJmsConfiguration() {\n\t\t\tJMSConfiguration config = new JMSConfigurationImpl();\n\t\t\tJMSQueueConfiguration jmsQueueConfiguration = new JMSQueueConfigurationImpl();\n\t\t\tjmsQueueConfiguration.setName(\"custom\");\n\t\t\tjmsQueueConfiguration.setDurable(false);\n\t\t\tconfig.getQueueConfigurations().add(jmsQueueConfiguration);\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomArtemisConfiguration {\n\n\t\t@Bean\n\t\tArtemisConfigurationCustomizer myArtemisCustomize() {\n\t\t\treturn (configuration) -> {\n\t\t\t\tconfiguration.setClusterPassword(\"Foobar\");\n\t\t\t\tconfiguration.setName(\"customFooBar\");\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tArtemisConnectionDetails activemqConnectionDetails() {\n\t\t\treturn new ArtemisConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic ArtemisMode getMode() {\n\t\t\t\t\treturn ArtemisMode.NATIVE;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getBrokerUrl() {\n\t\t\t\t\treturn \"tcp://localhost:12345\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUser() {\n\t\t\t\t\treturn \"springuser\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"spring\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/test/java/org/springframework/boot/artemis/autoconfigure/ArtemisEmbeddedConfigurationFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.autoconfigure;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.activemq.artemis.api.core.SimpleString;\nimport org.apache.activemq.artemis.core.config.Configuration;\nimport org.apache.activemq.artemis.core.config.CoreAddressConfiguration;\nimport org.apache.activemq.artemis.core.server.JournalType;\nimport org.apache.activemq.artemis.core.settings.impl.AddressSettings;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArtemisEmbeddedConfigurationFactory}\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass ArtemisEmbeddedConfigurationFactoryTests {\n\n\t@Test\n\tvoid defaultDataDir() {\n\t\tArtemisProperties properties = new ArtemisProperties();\n\t\tproperties.getEmbedded().setPersistent(true);\n\t\tConfiguration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();\n\t\tassertThat(configuration.getJournalDirectory()).startsWith(System.getProperty(\"java.io.tmpdir\"))\n\t\t\t.endsWith(\"/journal\");\n\t}\n\n\t@Test\n\tvoid persistenceSetup() {\n\t\tArtemisProperties properties = new ArtemisProperties();\n\t\tproperties.getEmbedded().setPersistent(true);\n\t\tConfiguration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();\n\t\tassertThat(configuration.isPersistenceEnabled()).isTrue();\n\t\tassertThat(configuration.getJournalType()).isEqualTo(JournalType.NIO);\n\t}\n\n\t@Test\n\tvoid generatedClusterPassword() {\n\t\tArtemisProperties properties = new ArtemisProperties();\n\t\tConfiguration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();\n\t\tassertThat(configuration.getClusterPassword()).hasSize(36);\n\t}\n\n\t@Test\n\tvoid specificClusterPassword() {\n\t\tArtemisProperties properties = new ArtemisProperties();\n\t\tproperties.getEmbedded().setClusterPassword(\"password\");\n\t\tConfiguration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();\n\t\tassertThat(configuration.getClusterPassword()).isEqualTo(\"password\");\n\t}\n\n\t@Test\n\tvoid hasDlqExpiryQueueAddressSettingsConfigured() {\n\t\tArtemisProperties properties = new ArtemisProperties();\n\t\tConfiguration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();\n\t\tMap<String, AddressSettings> addressSettings = configuration.getAddressSettings();\n\t\tAddressSettings sharp = addressSettings.get(\"#\");\n\t\tassertThat(sharp).isNotNull();\n\t\tassertThat((Object) sharp.getDeadLetterAddress()).isEqualTo(SimpleString.of(\"DLQ\"));\n\t\tassertThat((Object) sharp.getExpiryAddress()).isEqualTo(SimpleString.of(\"ExpiryQueue\"));\n\t}\n\n\t@Test\n\tvoid hasDlqExpiryQueueConfigured() {\n\t\tArtemisProperties properties = new ArtemisProperties();\n\t\tConfiguration configuration = new ArtemisEmbeddedConfigurationFactory(properties).createConfiguration();\n\t\tList<CoreAddressConfiguration> addressConfigurations = configuration.getAddressConfigurations();\n\t\tassertThat(addressConfigurations).hasSize(2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/test/java/org/springframework/boot/artemis/docker/compose/ArtemisEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.artemis.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ArtemisEnvironment}.\n *\n * @author Eddú Meléndez\n */\nclass ArtemisEnvironmentTests {\n\n\t@Test\n\tvoid getUserWhenHasNoActiveMqUser() {\n\t\tArtemisEnvironment environment = new ArtemisEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getUser()).isNull();\n\t}\n\n\t@Test\n\tvoid getUserWhenHasActiveMqUser() {\n\t\tArtemisEnvironment environment = new ArtemisEnvironment(Map.of(\"ARTEMIS_USER\", \"me\"));\n\t\tassertThat(environment.getUser()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoActiveMqPassword() {\n\t\tArtemisEnvironment environment = new ArtemisEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasActiveMqPassword() {\n\t\tArtemisEnvironment environment = new ArtemisEnvironment(Map.of(\"ARTEMIS_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-artemis/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-autoconfigure-classic/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot AutoConfigure Classic\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-autoconfigure\"))\n\tapi(project(\":module:spring-boot-autoconfigure-classic-modules\"))\n}\n"
  },
  {
    "path": "module/spring-boot-autoconfigure-classic-modules/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot AutoConfigure Classic Modules\"\n\n// NOTE: This module is broken out so that direct starter dependencies are\n// closer and will be resolved by Maven without the exclusions\n\ndependencies {\n\tapi(project(\":module:spring-boot-activemq\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-amqp\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-artemis\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-batch\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-cache\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-cassandra\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-cloudfoundry\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-couchbase\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-cassandra\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-commons\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-couchbase\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-elasticsearch\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-jdbc\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-jpa\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-ldap\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-mongodb\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-neo4j\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-r2dbc\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-redis\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-rest\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-elasticsearch\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-flyway\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-freemarker\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-graphql\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-grpc-client\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-grpc-server\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-groovy-templates\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-gson\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-h2console\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-hateoas\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-hazelcast\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-health\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-hibernate\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-http-client\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-http-codec\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-http-converter\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-integration\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jackson\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jdbc\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jersey\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jetty\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jms\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jooq\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jpa\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jsonb\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-kafka\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-kotlinx-serialization-json\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-ldap\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-liquibase\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-mail\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-metrics\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-observation\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-tracing\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-tracing-brave\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-tracing-opentelemetry\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-mongodb\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-mustache\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-neo4j\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-netty\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-opentelemetry\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-pulsar\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-quartz\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-r2dbc\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-reactor\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-reactor-netty\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-restclient\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-rsocket\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-security\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-security-oauth2-authorization-server\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-security-oauth2-client\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-security-oauth2-resource-server\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-security-saml2\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-sendgrid\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-servlet\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-session\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-session-data-redis\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-session-jdbc\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-sql\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-thymeleaf\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-tomcat\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-transaction\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-validation\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webclient\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webflux\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webmvc\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webservices\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-websocket\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-web-server\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-zipkin\")) {\n\t\ttransitive = false\n\t}\n}\n"
  },
  {
    "path": "module/spring-boot-batch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Batch\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.batch:spring-batch-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"tools.jackson.core:jackson-databind\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/BatchAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;\nimport org.springframework.batch.core.converter.JobParametersConverter;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.TaskExecutor;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Batch using an in-memory\n * store.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(JobOperator.class)\n@ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class)\n@EnableConfigurationProperties(BatchProperties.class)\npublic final class BatchAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SpringBootBatchDefaultConfiguration extends DefaultBatchConfiguration {\n\n\t\tprivate final @Nullable TaskExecutor taskExecutor;\n\n\t\tprivate final @Nullable JobParametersConverter jobParametersConverter;\n\n\t\tSpringBootBatchDefaultConfiguration(@BatchTaskExecutor ObjectProvider<TaskExecutor> batchTaskExecutor,\n\t\t\t\tObjectProvider<JobParametersConverter> jobParametersConverter) {\n\t\t\tthis.taskExecutor = batchTaskExecutor.getIfAvailable();\n\t\t\tthis.jobParametersConverter = jobParametersConverter.getIfAvailable();\n\t\t}\n\n\t\t@Override\n\t\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t\t@SuppressWarnings(\"removal\")\n\t\tprotected JobParametersConverter getJobParametersConverter() {\n\t\t\treturn (this.jobParametersConverter != null) ? this.jobParametersConverter\n\t\t\t\t\t: super.getJobParametersConverter();\n\t\t}\n\n\t\t@Override\n\t\tprotected TaskExecutor getTaskExecutor() {\n\t\t\treturn (this.taskExecutor != null) ? this.taskExecutor : super.getTaskExecutor();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/BatchConversionServiceCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.springframework.core.convert.support.ConfigurableConversionService;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link ConfigurableConversionService} to fine-tune its auto-configuration. The\n * conversion service is used by the Spring Batch infrastructure.\n *\n * @author Claudio Nave\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface BatchConversionServiceCustomizer {\n\n\t/**\n\t * Customize the {@link ConfigurableConversionService}.\n\t * @param configurableConversionService the ConfigurableConversionService to customize\n\t */\n\tvoid customize(ConfigurableConversionService configurableConversionService);\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/BatchJobLauncherAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.boot.ExitCodeGenerator;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Batch. If a single job is\n * found in the context, it will be executed on startup.\n * <p>\n * Disable this behavior with {@literal spring.batch.job.enabled=false}).\n * <p>\n * If multiple jobs are found, a job name to execute on startup can be supplied by the\n * User with : {@literal spring.batch.job.name=job1}. In this case the Runner will first\n * find jobs registered as Beans, then those in the existing JobRegistry.\n *\n * @author Dave Syer\n * @author Eddú Meléndez\n * @author Kazuki Shimizu\n * @author Mahmoud Ben Hassine\n * @author Lars Uffmann\n * @author Lasse Wulff\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration(after = BatchAutoConfiguration.class)\n@ConditionalOnClass(JobOperator.class)\n@ConditionalOnBean(JobOperator.class)\n@EnableConfigurationProperties(BatchProperties.class)\npublic final class BatchJobLauncherAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBooleanProperty(name = \"spring.batch.job.enabled\", matchIfMissing = true)\n\tJobLauncherApplicationRunner jobLauncherApplicationRunner(JobOperator jobOperator, BatchProperties properties) {\n\t\tJobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobOperator);\n\t\tString jobName = properties.getJob().getName();\n\t\tif (StringUtils.hasText(jobName)) {\n\t\t\trunner.setJobName(jobName);\n\t\t}\n\t\treturn runner;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ExitCodeGenerator.class)\n\tJobExecutionExitCodeGenerator jobExecutionExitCodeGenerator() {\n\t\treturn new JobExecutionExitCodeGenerator();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/BatchProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Spring Batch.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Vedran Pavic\n * @author Mukul Kumar Chaundhyan\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.batch\")\npublic class BatchProperties {\n\n\tprivate final Job job = new Job();\n\n\tpublic Job getJob() {\n\t\treturn this.job;\n\t}\n\n\tpublic static class Job {\n\n\t\t/**\n\t\t * Job name to execute on startup. Must be specified if multiple Jobs are found in\n\t\t * the context.\n\t\t */\n\t\tprivate String name = \"\";\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/BatchTaskExecutor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.task.TaskExecutor;\n\n/**\n * Qualifier annotation for a {@link TaskExecutor} to be injected into Batch\n * auto-configuration. Can be used on a secondary task executor source, if there is\n * another one marked as {@link Primary @Primary}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface BatchTaskExecutor {\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/BatchTransactionManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * Qualifier annotation for a {@link PlatformTransactionManager} to be injected into Batch\n * auto-configuration. Can be used on a secondary {@link PlatformTransactionManager}, if\n * there is another one marked as {@link Primary @Primary}.\n *\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface BatchTransactionManager {\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/JobExecutionEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Spring {@link ApplicationEvent} encapsulating a {@link JobExecution}.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class JobExecutionEvent extends ApplicationEvent {\n\n\tprivate final JobExecution execution;\n\n\t/**\n\t * Create a new {@link JobExecutionEvent} instance.\n\t * @param execution the job execution\n\t */\n\tpublic JobExecutionEvent(JobExecution execution) {\n\t\tsuper(execution);\n\t\tthis.execution = execution;\n\t}\n\n\t/**\n\t * Return the job execution.\n\t * @return the job execution\n\t */\n\tpublic JobExecution getJobExecution() {\n\t\treturn this.execution;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/JobExecutionExitCodeGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.boot.ExitCodeGenerator;\nimport org.springframework.context.ApplicationListener;\n\n/**\n * {@link ExitCodeGenerator} for {@link JobExecutionEvent}s.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\npublic class JobExecutionExitCodeGenerator implements ApplicationListener<JobExecutionEvent>, ExitCodeGenerator {\n\n\tprivate final List<JobExecution> executions = new CopyOnWriteArrayList<>();\n\n\t@Override\n\tpublic void onApplicationEvent(JobExecutionEvent event) {\n\t\tthis.executions.add(event.getJobExecution());\n\t}\n\n\t@Override\n\tpublic int getExitCode() {\n\t\tfor (JobExecution execution : this.executions) {\n\t\t\tif (execution.getStatus().ordinal() > 0) {\n\t\t\t\treturn execution.getStatus().ordinal();\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/JobLauncherApplicationRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Properties;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.converter.DefaultJobParametersConverter;\nimport org.springframework.batch.core.converter.JobParametersConverter;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobExecutionException;\nimport org.springframework.batch.core.job.parameters.InvalidJobParametersException;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobExecutionAlreadyRunningException;\nimport org.springframework.batch.core.launch.JobInstanceAlreadyCompleteException;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.launch.JobRestartException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationRunner} to {@link JobOperator launch} Spring Batch jobs. If a single\n * job is found in the context, it will be executed by default. If multiple jobs are\n * found, launch a specific job by providing a jobName.\n *\n * @author Dave Syer\n * @author Jean-Pierre Bergamin\n * @author Mahmoud Ben Hassine\n * @author Stephane Nicoll\n * @author Akshay Dubey\n * @since 4.0.0\n */\npublic class JobLauncherApplicationRunner\n\t\timplements ApplicationRunner, InitializingBean, Ordered, ApplicationEventPublisherAware {\n\n\t/**\n\t * The default order for the command line runner.\n\t */\n\tpublic static final int DEFAULT_ORDER = 0;\n\n\tprivate static final Log logger = LogFactory.getLog(JobLauncherApplicationRunner.class);\n\n\tprivate JobParametersConverter converter = new DefaultJobParametersConverter();\n\n\tprivate final JobOperator jobOperator;\n\n\tprivate @Nullable JobRegistry jobRegistry;\n\n\tprivate @Nullable String jobName;\n\n\tprivate Collection<Job> jobs = Collections.emptySet();\n\n\tprivate int order = DEFAULT_ORDER;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationEventPublisher publisher;\n\n\t/**\n\t * Create a new {@link JobLauncherApplicationRunner}.\n\t * @param jobOperator to launch jobs\n\t */\n\tpublic JobLauncherApplicationRunner(JobOperator jobOperator) {\n\t\tAssert.notNull(jobOperator, \"'jobOperator' must not be null\");\n\t\tthis.jobOperator = jobOperator;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tAssert.state(this.jobs.size() <= 1 || StringUtils.hasText(this.jobName),\n\t\t\t\t\"Job name must be specified in case of multiple jobs\");\n\t\tif (StringUtils.hasText(this.jobName)) {\n\t\t\tAssert.state(isLocalJob(this.jobName) || isRegisteredJob(this.jobName),\n\t\t\t\t\t() -> \"No job found with name '\" + this.jobName + \"'\");\n\t\t}\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t@Override\n\tpublic void setApplicationEventPublisher(ApplicationEventPublisher publisher) {\n\t\tthis.publisher = publisher;\n\t}\n\n\t@Autowired(required = false)\n\tpublic void setJobRegistry(JobRegistry jobRegistry) {\n\t\tthis.jobRegistry = jobRegistry;\n\t}\n\n\tpublic void setJobName(String jobName) {\n\t\tthis.jobName = jobName;\n\t}\n\n\t@Autowired(required = false)\n\tpublic void setJobParametersConverter(JobParametersConverter converter) {\n\t\tthis.converter = converter;\n\t}\n\n\t@Autowired(required = false)\n\tpublic void setJobs(Collection<Job> jobs) {\n\t\tthis.jobs = jobs;\n\t}\n\n\t@Override\n\tpublic void run(ApplicationArguments args) throws Exception {\n\t\tString[] jobArguments = args.getNonOptionArgs().toArray(new String[0]);\n\t\trun(jobArguments);\n\t}\n\n\tpublic void run(String... args) throws JobExecutionException {\n\t\tlogger.info(\"Running default command line with: \" + Arrays.asList(args));\n\t\tProperties properties = StringUtils.splitArrayElementsIntoProperties(args, \"=\");\n\t\tlaunchJobFromProperties((properties != null) ? properties : new Properties());\n\t}\n\n\tprotected void launchJobFromProperties(Properties properties) throws JobExecutionException {\n\t\tJobParameters jobParameters = this.converter.getJobParameters(properties);\n\t\texecuteLocalJobs(jobParameters);\n\t\texecuteRegisteredJobs(jobParameters);\n\t}\n\n\tprivate boolean isLocalJob(String jobName) {\n\t\treturn this.jobs.stream().anyMatch((job) -> job.getName().equals(jobName));\n\t}\n\n\tprivate boolean isRegisteredJob(String jobName) {\n\t\treturn this.jobRegistry != null && this.jobRegistry.getJobNames().contains(jobName);\n\t}\n\n\tprivate void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException {\n\t\tfor (Job job : this.jobs) {\n\t\t\tif (StringUtils.hasText(this.jobName)) {\n\t\t\t\tif (!this.jobName.equals(job.getName())) {\n\t\t\t\t\tlogger.debug(LogMessage.format(\"Skipped job: %s\", job.getName()));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\texecute(job, jobParameters);\n\t\t}\n\t}\n\n\tprivate void executeRegisteredJobs(JobParameters jobParameters) throws JobExecutionException {\n\t\tif (this.jobRegistry != null && StringUtils.hasText(this.jobName)) {\n\t\t\tif (!isLocalJob(this.jobName)) {\n\t\t\t\tJob job = this.jobRegistry.getJob(this.jobName);\n\t\t\t\tAssert.notNull(job, () -> \"No job found with name '\" + this.jobName + \"'\");\n\t\t\t\texecute(job, jobParameters);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected void execute(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException,\n\t\t\tJobRestartException, JobInstanceAlreadyCompleteException, InvalidJobParametersException {\n\t\tJobExecution execution = this.jobOperator.start(job, jobParameters);\n\t\tif (this.publisher != null) {\n\t\t\tthis.publisher.publishEvent(new JobExecutionEvent(execution));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/observation/BatchObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.batch.core.configuration.annotation.BatchObservabilityBeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring Batch\n * Jobs.\n *\n * @author Mark Bonnekessel\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnBean(ObservationRegistry.class)\n@ConditionalOnClass({ ObservationRegistry.class, BatchObservabilityBeanPostProcessor.class })\npublic final class BatchObservationAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tstatic BatchObservabilityBeanPostProcessor batchObservabilityBeanPostProcessor() {\n\t\treturn new BatchObservabilityBeanPostProcessor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Batch observations.\n */\n@NullMarked\npackage org.springframework.boot.batch.autoconfigure.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/java/org/springframework/boot/batch/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Batch.\n */\n@NullMarked\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-batch/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.batch.job.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to execute a Spring Batch job on startup. When multiple jobs are present in the context, set spring.batch.job.name to identify the job to execute.\",\n      \"defaultValue\": true\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-batch/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration\norg.springframework.boot.batch.autoconfigure.BatchJobLauncherAutoConfiguration\norg.springframework.boot.batch.autoconfigure.observation.BatchObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-batch/src/test/java/org/springframework/boot/batch/autoconfigure/BatchAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;\nimport org.springframework.batch.core.converter.DefaultJobParametersConverter;\nimport org.springframework.batch.core.converter.JobParametersConverter;\nimport org.springframework.batch.core.converter.JsonJobParametersConverter;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration.SpringBootBatchDefaultConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.SyncTaskExecutor;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.jdbc.datasource.init.DatabasePopulator;\nimport org.springframework.test.util.AopTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BatchJobLauncherAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Kazuki Shimizu\n * @author Mahmoud Ben Hassine\n * @author Lars Uffmann\n * @author Lasse Wulff\n * @author Yanming Zhou\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass BatchAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BatchAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultContext() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JobRepository.class);\n\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWhenUserEnablesBatchProcessing() {\n\t\tthis.contextRunner.withUserConfiguration(EnableBatchProcessingConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringBootBatchDefaultConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWhenUserProvidesBatchConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomBatchConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(DatabasePopulator.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringBootBatchDefaultConfiguration.class));\n\t}\n\n\t@Test\n\tvoid testBatchTaskExecutor() {\n\t\tthis.contextRunner.withUserConfiguration(BatchTaskExecutorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpringBootBatchDefaultConfiguration.class).hasBean(\"batchTaskExecutor\");\n\t\t\tTaskExecutor batchTaskExecutor = context.getBean(\"batchTaskExecutor\", TaskExecutor.class);\n\t\t\tassertThat(batchTaskExecutor).isInstanceOf(AsyncTaskExecutor.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchDefaultConfiguration.class).getTaskExecutor())\n\t\t\t\t.isEqualTo(batchTaskExecutor);\n\t\t\tJobOperator jobOperator = AopTestUtils.getTargetObject(context.getBean(JobOperator.class));\n\t\t\tassertThat(jobOperator).hasFieldOrPropertyWithValue(\"taskExecutor\", batchTaskExecutor);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameAsJobInstanceValidates() {\n\t\tJobLauncherApplicationRunner runner = createInstance(\"another\");\n\t\trunner.setJobs(Collections.singletonList(mockJob(\"test\")));\n\t\trunner.setJobName(\"test\");\n\t\trunner.afterPropertiesSet();\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameAsRegisteredJobValidates() {\n\t\tJobLauncherApplicationRunner runner = createInstance(\"test\");\n\t\trunner.setJobName(\"test\");\n\t\trunner.afterPropertiesSet();\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameThatDoesNotExistWithJobInstancesFailsFast() {\n\t\tJobLauncherApplicationRunner runner = createInstance();\n\t\trunner.setJobs(Arrays.asList(mockJob(\"one\"), mockJob(\"two\")));\n\t\trunner.setJobName(\"three\");\n\t\tassertThatIllegalStateException().isThrownBy(runner::afterPropertiesSet)\n\t\t\t.withMessage(\"No job found with name 'three'\");\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameThatDoesNotExistWithRegisteredJobFailsFast() {\n\t\tJobLauncherApplicationRunner runner = createInstance(\"one\", \"two\");\n\t\trunner.setJobName(\"three\");\n\t\tassertThatIllegalStateException().isThrownBy(runner::afterPropertiesSet)\n\t\t\t.withMessage(\"No job found with name 'three'\");\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid customJobParametersConverterIsUsed() {\n\t\tthis.contextRunner.withBean(JobParametersConverter.class, JsonJobParametersConverter::new).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JsonJobParametersConverter.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchDefaultConfiguration.class).getJobParametersConverter())\n\t\t\t\t.isInstanceOf(JsonJobParametersConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid defaultJobParametersConverterIsUsed() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(JobParametersConverter.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchDefaultConfiguration.class).getJobParametersConverter())\n\t\t\t\t.isInstanceOf(DefaultJobParametersConverter.class);\n\t\t});\n\t}\n\n\tprivate JobLauncherApplicationRunner createInstance(String... registeredJobNames) {\n\t\tJobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(mock(JobOperator.class));\n\t\tJobRegistry jobRegistry = mock(JobRegistry.class);\n\t\tgiven(jobRegistry.getJobNames()).willReturn(Arrays.asList(registeredJobNames));\n\t\trunner.setJobRegistry(jobRegistry);\n\t\treturn runner;\n\t}\n\n\tprivate Job mockJob(String name) {\n\t\tJob job = mock(Job.class);\n\t\tgiven(job.getName()).willReturn(name);\n\t\treturn job;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchTaskExecutorConfiguration {\n\n\t\t@Bean\n\t\tTaskExecutor taskExecutor() {\n\t\t\treturn new SyncTaskExecutor();\n\t\t}\n\n\t\t@BatchTaskExecutor\n\t\t@Bean(defaultCandidate = false)\n\t\tTaskExecutor batchTaskExecutor() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBatchConfiguration extends DefaultBatchConfiguration {\n\n\t}\n\n\t@EnableBatchProcessing\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EnableBatchProcessingConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConversionServiceCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tBatchConversionServiceCustomizer batchConversionServiceCustomizer() {\n\t\t\treturn mock(BatchConversionServiceCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tBatchConversionServiceCustomizer anotherBatchConversionServiceCustomizer() {\n\t\t\treturn mock(BatchConversionServiceCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/test/java/org/springframework/boot/batch/autoconfigure/BatchJobLauncherAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.job.AbstractJob;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.job.parameters.JobParametersBuilder;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.DefaultApplicationArguments;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BatchJobLauncherAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass BatchJobLauncherAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(BatchAutoConfiguration.class, BatchJobLauncherAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefinesAndLaunchesJob() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run(new DefaultApplicationArguments(\"jobParam=test\"));\n\t\t\tJobParameters jobParameters = new JobParametersBuilder().addString(\"jobParam\", \"test\").toJobParameters();\n\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"job\", jobParameters)).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefinesAndLaunchesJobIgnoreOptionArguments() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\tcontext.getBean(JobLauncherApplicationRunner.class)\n\t\t\t\t.run(new DefaultApplicationArguments(\"--spring.property=value\", \"jobParam=test\"));\n\t\t\tJobParameters jobParameters = new JobParametersBuilder().addString(\"jobParam\", \"test\").toJobParameters();\n\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"job\", jobParameters)).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRegisteredAndLocalJob() {\n\t\tthis.contextRunner.withUserConfiguration(NamedJobConfigurationWithRegisteredAndLocalJob.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.name:discreteRegisteredJob\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run();\n\t\t\t\tJobExecution lastJobExecution = context.getBean(JobRepository.class)\n\t\t\t\t\t.getLastJobExecution(\"discreteRegisteredJob\", new JobParameters());\n\t\t\t\tassertThat(lastJobExecution).isNotNull();\n\t\t\t\tassertThat(lastJobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefinesAndLaunchesLocalJob() {\n\t\tthis.contextRunner.withUserConfiguration(NamedJobConfigurationWithLocalJob.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.name:discreteLocalJob\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run();\n\t\t\t\tassertThat(context.getBean(JobRepository.class)\n\t\t\t\t\t.getLastJobExecution(\"discreteLocalJob\", new JobParameters())).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testMultipleJobsAndNoJobName() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleJobConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tThrowable startupFailure = context.getStartupFailure();\n\t\t\tassertThat(startupFailure).isNotNull();\n\t\t\tThrowable cause = startupFailure.getCause();\n\t\t\tassertThat(cause).isNotNull();\n\t\t\tassertThat(cause.getMessage()).contains(\"Job name must be specified in case of multiple jobs\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testMultipleJobsAndJobName() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleJobConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.name:discreteLocalJob\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run();\n\t\t\t\tassertThat(context.getBean(JobRepository.class)\n\t\t\t\t\t.getLastJobExecution(\"discreteLocalJob\", new JobParameters())).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDisableLaunchesJob() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(CommandLineRunner.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NamedJobConfigurationWithRegisteredAndLocalJob {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob discreteJob() {\n\t\t\tAbstractJob job = new AbstractJob(\"discreteRegisteredJob\") {\n\n\t\t\t\tprivate static int count;\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\tif (count == 0) {\n\t\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\texecution.setStatus(BatchStatus.FAILED);\n\t\t\t\t\t}\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NamedJobConfigurationWithLocalJob {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob discreteJob() {\n\t\t\tAbstractJob job = new AbstractJob(\"discreteLocalJob\") {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleJobConfiguration {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob discreteJob() {\n\t\t\tAbstractJob job = new AbstractJob(\"discreteLocalJob\") {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t\t@Bean\n\t\tJob job2() {\n\t\t\treturn new Job() {\n\t\t\t\t@Override\n\t\t\t\tpublic String getName() {\n\t\t\t\t\treturn \"discreteLocalJob2\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void execute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JobConfiguration {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob job() {\n\t\t\tAbstractJob job = new AbstractJob() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/test/java/org/springframework/boot/batch/autoconfigure/JobExecutionExitCodeGeneratorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.parameters.JobParameters;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JobExecutionExitCodeGenerator}.\n *\n * @author Dave Syer\n */\nclass JobExecutionExitCodeGeneratorTests {\n\n\tprivate final JobExecutionExitCodeGenerator generator = new JobExecutionExitCodeGenerator();\n\n\t@Test\n\tvoid testExitCodeForRunning() {\n\t\tthis.generator.onApplicationEvent(new JobExecutionEvent(testJobExecution()));\n\t\tassertThat(this.generator.getExitCode()).isOne();\n\t}\n\n\t@Test\n\tvoid testExitCodeForCompleted() {\n\t\tJobExecution execution = testJobExecution();\n\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\tthis.generator.onApplicationEvent(new JobExecutionEvent(execution));\n\t\tassertThat(this.generator.getExitCode()).isZero();\n\t}\n\n\t@Test\n\tvoid testExitCodeForFailed() {\n\t\tJobExecution execution = testJobExecution();\n\t\texecution.setStatus(BatchStatus.FAILED);\n\t\tthis.generator.onApplicationEvent(new JobExecutionEvent(execution));\n\t\tassertThat(this.generator.getExitCode()).isEqualTo(5);\n\t}\n\n\tprivate static JobExecution testJobExecution() {\n\t\tJobInstance jobInstance = new JobInstance(1L, \"job\");\n\t\treturn new JobExecution(0L, jobInstance, new JobParameters());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/test/java/org/springframework/boot/batch/autoconfigure/JobLauncherApplicationRunnerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.ExitStatus;\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobExecutionException;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JobLauncherApplicationRunner}.\n *\n * @author Dave Syer\n * @author Jean-Pierre Bergamin\n * @author Mahmoud Ben Hassine\n * @author Stephane Nicoll\n */\nclass JobLauncherApplicationRunnerTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(PlatformTransactionManager.class, ResourcelessTransactionManager::new)\n\t\t.withUserConfiguration(BatchConfiguration.class);\n\n\t@Test\n\tvoid basicExecutionSuccess() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tjobLauncherContext.executeJob(new JobParameters());\n\t\t\tList<JobInstance> jobInstances = jobLauncherContext.jobInstances();\n\t\t\tassertThat(jobInstances).hasSize(1);\n\t\t\tList<JobExecution> jobExecutions = jobLauncherContext.jobExecutions(jobInstances.get(0));\n\t\t\tassertThat(jobExecutions).hasSize(1);\n\t\t\tassertThat(jobExecutions.get(0).getExitStatus().getExitCode())\n\t\t\t\t.isEqualTo(ExitStatus.COMPLETED.getExitCode());\n\t\t});\n\t}\n\n\t@Test\n\tvoid basicExecutionFailure() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tJob job = jobLauncherContext.jobBuilder()\n\t\t\t\t.start(jobLauncherContext.stepBuilder().tasklet(throwingTasklet(), transactionManager).build())\n\t\t\t\t.build();\n\t\t\tjobLauncherContext.runner.execute(job, new JobParameters());\n\t\t\tList<JobInstance> jobInstances = jobLauncherContext.jobInstances();\n\t\t\tassertThat(jobInstances).hasSize(1);\n\t\t\tList<JobExecution> jobExecutions = jobLauncherContext.jobExecutions(jobInstances.get(0));\n\t\t\tassertThat(jobExecutions).hasSize(1);\n\t\t\tassertThat(jobExecutions.get(0).getExitStatus().getExitCode()).isEqualTo(ExitStatus.FAILED.getExitCode());\n\t\t});\n\t}\n\n\tprivate Tasklet throwingTasklet() {\n\t\treturn (contribution, chunkContext) -> {\n\t\t\tthrow new RuntimeException(\"Planned\");\n\t\t};\n\t}\n\n\tstatic class JobLauncherApplicationRunnerContext {\n\n\t\tprivate final JobLauncherApplicationRunner runner;\n\n\t\tprivate final JobRepository jobRepository;\n\n\t\tprivate final JobBuilder jobBuilder;\n\n\t\tprivate final Job job;\n\n\t\tprivate final StepBuilder stepBuilder;\n\n\t\tJobLauncherApplicationRunnerContext(ApplicationContext context) {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tthis.stepBuilder = new StepBuilder(\"step\", jobRepository);\n\t\t\tStep step = this.stepBuilder.tasklet((contribution, chunkContext) -> null, transactionManager).build();\n\t\t\tthis.jobBuilder = new JobBuilder(\"job\", jobRepository);\n\t\t\tthis.job = this.jobBuilder.start(step).build();\n\t\t\tthis.jobRepository = context.getBean(JobRepository.class);\n\t\t\tthis.runner = new JobLauncherApplicationRunner(jobOperator);\n\t\t}\n\n\t\tList<JobInstance> jobInstances() {\n\t\t\treturn this.jobRepository.getJobInstances(\"job\", 0, 100);\n\t\t}\n\n\t\tList<JobExecution> jobExecutions(JobInstance jobInstance) {\n\t\t\treturn this.jobRepository.getJobExecutions(jobInstance);\n\t\t}\n\n\t\tvoid executeJob(JobParameters jobParameters) throws JobExecutionException {\n\t\t\tthis.runner.execute(this.job, jobParameters);\n\t\t}\n\n\t\tJobBuilder jobBuilder() {\n\t\t\treturn this.jobBuilder;\n\t\t}\n\n\t\tStepBuilder stepBuilder() {\n\t\t\treturn this.stepBuilder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableBatchProcessing\n\tstatic class BatchConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch/src/test/java/org/springframework/boot/batch/autoconfigure/observation/BatchObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.autoconfigure.observation;\n\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.configuration.annotation.BatchObservabilityBeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BatchObservationAutoConfiguration}.\n *\n * @author Mark Bonnekessel\n */\nclass BatchObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(TestObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(BatchObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWhenObservationRegistryIsMissing() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(BatchObservationAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BatchObservabilityBeanPostProcessor.class));\n\t}\n\n\t@Test\n\tvoid beanIsPresentWhenSpringBatchIsPresent() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(BatchObservabilityBeanPostProcessor.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Batch Data MongoDB\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-batch\"))\n\tapi(project(\":module:spring-boot-data-mongodb\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.mongodb:mongodb-driver-sync\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.mongodb:mongodb-driver-sync\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-mongodb\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/dockerTest/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchDataMongoAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport java.time.LocalDateTime;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.job.parameters.JobParametersBuilder;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.mongodb.autoconfigure.DataMongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.mongodb.core.MongoOperations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link BatchDataMongoAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass BatchDataMongoAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class).withReplicaSet();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(JobConfiguration.class)\n\t\t.withPropertyValues(\"spring.batch.data.mongodb.schema.initialize=true\",\n\t\t\t\t\"spring.mongodb.uri=\" + mongoDb.getReplicaSetUrl())\n\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, DataMongoAutoConfiguration.class,\n\t\t\t\tBatchDataMongoAutoConfiguration.class));\n\n\t@Test\n\tvoid runJob() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JobOperator.class)\n\t\t\t\t.hasSingleBean(JobRepository.class)\n\t\t\t\t.hasSingleBean(Job.class);\n\n\t\t\tJobParameters jobParameters = new JobParametersBuilder().addString(\"name\", \"foo\")\n\t\t\t\t.addLocalDateTime(\"runtime\", LocalDateTime.now())\n\t\t\t\t.toJobParameters();\n\t\t\tJobExecution jobExecution = context.getBean(JobOperator.class)\n\t\t\t\t.start(context.getBean(Job.class), jobParameters);\n\n\t\t\tassertThat(jobExecution).isNotNull();\n\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"job\", jobParameters)).isNotNull();\n\t\t\tassertThat(context.getBean(MongoOperations.class).getCollection(\"BATCH_JOB_EXECUTION\").countDocuments())\n\t\t\t\t.isPositive();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JobConfiguration {\n\n\t\t@Bean\n\t\tJob job(JobRepository jobRepository) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository)\n\t\t\t\t\t.tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)\n\t\t\t\t\t.build())\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchDataMongoAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport com.mongodb.client.MongoClient;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;\nimport org.springframework.batch.core.configuration.support.MongoDefaultBatchConfiguration;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchJobLauncherAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchTaskExecutor;\nimport org.springframework.boot.batch.autoconfigure.BatchTransactionManager;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.data.mongodb.autoconfigure.DataMongoAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.MongoTransactionManager;\nimport org.springframework.data.mongodb.core.MongoOperations;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.convert.MappingMongoConverter;\nimport org.springframework.transaction.annotation.Isolation;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Batch using Data MongoDB.\n *\n * @author Stephane Nicoll\n * @since 4.1.0\n */\n@AutoConfiguration(before = { BatchAutoConfiguration.class, BatchJobLauncherAutoConfiguration.class },\n\t\tafter = DataMongoAutoConfiguration.class)\n@ConditionalOnClass({ JobOperator.class, MongoClient.class, MongoOperations.class })\n@ConditionalOnBean(MongoDatabaseFactory.class)\n@ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class)\n@EnableConfigurationProperties(BatchDataMongoProperties.class)\npublic final class BatchDataMongoAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(\"spring.batch.data.mongodb.schema.initialize\")\n\t@ConditionalOnBean(MongoOperations.class)\n\t@Import(JobRepositoryDependsOnSchemaInitializationDetector.class)\n\tstatic class BatchMongoDatabaseInitializerConfiguration {\n\n\t\t@Bean(name = JobRepositoryDependsOnSchemaInitializationDetector.SCHEMA_INITIALIZATION_BEAN_NAME)\n\t\tInitializingBean batchMongoDataInitializingBean(MongoOperations mongoOperations,\n\t\t\t\tBatchDataMongoProperties properties) {\n\t\t\treturn () -> {\n\t\t\t\tBatchMongoSchemaInitializer initializer = new BatchMongoSchemaInitializer(mongoOperations);\n\t\t\t\tString schemaLocation = properties.getSchema().getLocation();\n\t\t\t\tResource resource = new ClassPathResource(schemaLocation);\n\t\t\t\tif (!resource.exists()) {\n\t\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"spring.batch.data.mongodb.schema.location\",\n\t\t\t\t\t\t\tschemaLocation, \"resource does not exist\");\n\t\t\t\t}\n\t\t\t\tinitializer.initialize(resource);\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SpringBootBatchMongoConfiguration extends MongoDefaultBatchConfiguration {\n\n\t\tprivate final MongoOperations mongoOperations;\n\n\t\tprivate final MongoTransactionManager transactionManager;\n\n\t\tprivate final @Nullable TaskExecutor taskExecutor;\n\n\t\tprivate final BatchDataMongoProperties properties;\n\n\t\tSpringBootBatchMongoConfiguration(MongoDatabaseFactory mongoDatabaseFactory,\n\t\t\t\tObjectProvider<MongoTransactionManager> transactionManager,\n\t\t\t\t@BatchTransactionManager ObjectProvider<MongoTransactionManager> batchTransactionManager,\n\t\t\t\t@BatchTaskExecutor ObjectProvider<TaskExecutor> batchTaskExecutor,\n\t\t\t\tBatchDataMongoProperties properties) {\n\t\t\tthis.mongoOperations = createMongoOperations(mongoDatabaseFactory);\n\t\t\tthis.transactionManager = batchTransactionManager.getIfAvailable(\n\t\t\t\t\t() -> transactionManager.getIfAvailable(() -> new MongoTransactionManager(mongoDatabaseFactory)));\n\t\t\tthis.taskExecutor = batchTaskExecutor.getIfAvailable();\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\tprivate static MongoTemplate createMongoOperations(MongoDatabaseFactory mongoDatabaseFactory) {\n\t\t\tMongoTemplate template = new MongoTemplate(mongoDatabaseFactory);\n\t\t\tMappingMongoConverter converter = (MappingMongoConverter) template.getConverter();\n\t\t\tconverter.setMapKeyDotReplacement(\".\");\n\t\t\treturn template;\n\t\t}\n\n\t\t@Override\n\t\tprotected MongoOperations getMongoOperations() {\n\t\t\treturn this.mongoOperations;\n\t\t}\n\n\t\t@Override\n\t\tprotected MongoTransactionManager getTransactionManager() {\n\t\t\treturn this.transactionManager;\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean getValidateTransactionState() {\n\t\t\treturn this.properties.isValidateTransactionState();\n\t\t}\n\n\t\t@Override\n\t\tprotected Isolation getIsolationLevelForCreate() {\n\t\t\tIsolation isolation = this.properties.getIsolationLevelForCreate();\n\t\t\treturn (isolation != null) ? isolation : super.getIsolationLevelForCreate();\n\t\t}\n\n\t\t@Override\n\t\tprotected TaskExecutor getTaskExecutor() {\n\t\t\treturn (this.taskExecutor != null) ? this.taskExecutor : super.getTaskExecutor();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchDataMongoProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.transaction.annotation.Isolation;\n\n/**\n * Configuration properties for Spring Batch using Data MongoDB.\n *\n * @author Stephane Nicoll\n * @since 4.1.0\n */\n@ConfigurationProperties(\"spring.batch.data.mongodb\")\npublic class BatchDataMongoProperties {\n\n\t/**\n\t * Whether to validate the transaction state.\n\t */\n\tprivate boolean validateTransactionState = true;\n\n\t/**\n\t * Transaction isolation level to use when creating job metadata for new jobs.\n\t */\n\tprivate @Nullable Isolation isolationLevelForCreate;\n\n\tprivate final Schema schema = new Schema();\n\n\tpublic boolean isValidateTransactionState() {\n\t\treturn this.validateTransactionState;\n\t}\n\n\tpublic void setValidateTransactionState(boolean validateTransactionState) {\n\t\tthis.validateTransactionState = validateTransactionState;\n\t}\n\n\tpublic @Nullable Isolation getIsolationLevelForCreate() {\n\t\treturn this.isolationLevelForCreate;\n\t}\n\n\tpublic void setIsolationLevelForCreate(@Nullable Isolation isolationLevelForCreate) {\n\t\tthis.isolationLevelForCreate = isolationLevelForCreate;\n\t}\n\n\tpublic Schema getSchema() {\n\t\treturn this.schema;\n\t}\n\n\tpublic static class Schema {\n\n\t\t/**\n\t\t * Path to the newline-delimited JSON script used to create the Spring Batch job\n\t\t * repository collections and indexes in MongoDB.\n\t\t */\n\t\tprivate String location = \"org/springframework/batch/core/schema-mongodb.jsonl\";\n\n\t\t/**\n\t\t * Whether to initialize the Spring Batch job repository schema in MongoDB.\n\t\t */\n\t\tprivate boolean initialize;\n\n\t\tpublic String getLocation() {\n\t\t\treturn this.location;\n\t\t}\n\n\t\tpublic void setLocation(String location) {\n\t\t\tthis.location = location;\n\t\t}\n\n\t\tpublic boolean isInitialize() {\n\t\t\treturn this.initialize;\n\t\t}\n\n\t\tpublic void setInitialize(boolean initialize) {\n\t\t\tthis.initialize = initialize;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchMongoSchemaInitializationException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.dao.DataAccessException;\n\n/**\n * Thrown when the Spring Batch repository schema cannot be initialized.\n *\n * @author Stephane Nicoll\n * @since 4.1.0\n */\npublic class BatchMongoSchemaInitializationException extends DataAccessException {\n\n\tpublic BatchMongoSchemaInitializationException(String msg, @Nullable Throwable cause) {\n\t\tsuper(msg, cause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchMongoSchemaInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.data.mongodb.core.MongoOperations;\nimport org.springframework.util.StreamUtils;\n\n/**\n * Initializes the Spring Batch job repository schema (collections and indexes) in MongoDB\n * by executing commands from a newline-delimited JSON script.\n *\n * @author Stephane Nicoll\n */\nclass BatchMongoSchemaInitializer {\n\n\tprivate static final Log logger = LogFactory.getLog(BatchMongoSchemaInitializer.class);\n\n\tprivate final MongoOperations mongoOperations;\n\n\tBatchMongoSchemaInitializer(MongoOperations mongoOperations) {\n\t\tthis.mongoOperations = mongoOperations;\n\t}\n\n\tvoid initialize(Resource schema) throws IOException {\n\t\tStreamUtils.copyToString(schema.getInputStream(), StandardCharsets.UTF_8)\n\t\t\t.lines()\n\t\t\t.filter((line) -> !line.isBlank())\n\t\t\t.forEach((command) -> {\n\t\t\t\ttry {\n\t\t\t\t\texecuteCommand(command);\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthrow new BatchMongoSchemaInitializationException(\n\t\t\t\t\t\t\t\"Failed to initialize Batch repository schema using '%s', command failed: %s\"\n\t\t\t\t\t\t\t\t.formatted(schema, command),\n\t\t\t\t\t\t\tex);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate void executeCommand(String command) {\n\t\tif (logger.isTraceEnabled()) {\n\t\t\tlogger.trace(\"Executing command: \" + command);\n\t\t}\n\t\tthis.mongoOperations.executeCommand(command);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb/autoconfigure/JobRepositoryDependsOnSchemaInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;\n\n/**\n * {@link AbstractDependsOnBeanFactoryPostProcessor} implementation that makes sure Spring\n * Batch's {@link JobRepository} depends on schema initialization.\n *\n * @author Stephane Nicoll\n */\nclass JobRepositoryDependsOnSchemaInitializationDetector extends AbstractDependsOnBeanFactoryPostProcessor {\n\n\t/**\n\t * Bean name responsible for schema initialization.\n\t */\n\tstatic final String SCHEMA_INITIALIZATION_BEAN_NAME = \"batchMongoDataInitializingBean\";\n\n\tJobRepositoryDependsOnSchemaInitializationDetector() {\n\t\tsuper(JobRepository.class, SCHEMA_INITIALIZATION_BEAN_NAME);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/java/org/springframework/boot/batch/mongodb/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Batch with Data MongoDB.\n */\n@NullMarked\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.batch.mongodb.autoconfigure.BatchDataMongoAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/test/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchDataMongoAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.batch.autoconfigure.BatchTransactionManager;\nimport org.springframework.boot.batch.mongodb.autoconfigure.BatchDataMongoAutoConfiguration.SpringBootBatchMongoConfiguration;\nimport org.springframework.boot.data.mongodb.autoconfigure.DataMongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.MongoTransactionManager;\nimport org.springframework.data.mongodb.core.MongoExceptionTranslator;\nimport org.springframework.data.mongodb.core.MongoOperations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link BatchDataMongoAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass BatchDataMongoAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BatchDataMongoAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationWithSpringDataMongoDb() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, DataMongoAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JobRepository.class).hasSingleBean(JobOperator.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationOnlyRequiresMongoDatabaseFactory() {\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JobRepository.class).hasSingleBean(JobOperator.class));\n\t}\n\n\t@Test\n\tvoid autConfigurationUsesMainTransactionManager() {\n\t\tMongoTransactionManager transactionManager = mock(MongoTransactionManager.class);\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withBean(MongoTransactionManager.class, () -> transactionManager)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(SpringBootBatchMongoConfiguration.class).getTransactionManager())\n\t\t\t\t.isSameAs(transactionManager));\n\t}\n\n\t@Test\n\tvoid autConfigurationFavorsBatchTransactionManager() {\n\t\tMongoTransactionManager transactionManager = mock(MongoTransactionManager.class);\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withBean(MongoTransactionManager.class, () -> transactionManager)\n\t\t\t.withUserConfiguration(BatchTransactionManagerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(MongoTransactionManager.class)).hasSize(2);\n\t\t\t\tassertThat(context.getBean(SpringBootBatchMongoConfiguration.class).getTransactionManager())\n\t\t\t\t\t.isSameAs(context.getBean(\"customTransactionManager\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autConfigurationCreatesBatchTransactionManagerIfNecessary() {\n\t\tMongoDatabaseFactory mongoDatabaseFactory = mockMongoDatabaseFactory();\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, () -> mongoDatabaseFactory).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(MongoTransactionManager.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchMongoConfiguration.class).getTransactionManager())\n\t\t\t\t.satisfies((mongoTransactionManager) -> assertThat(mongoTransactionManager.getDatabaseFactory())\n\t\t\t\t\t.isSameAs(mongoDatabaseFactory));\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoconfigurationBacksOffEntirelyIfSpringMongoDbAbsent() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, DataMongoAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(MongoOperations.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JobRepository.class)\n\t\t\t\t.doesNotHaveBean(JobOperator.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOfEntirelyIfSpringMongoDbIsNotConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(JobRepository.class)\n\t\t\t.doesNotHaveBean(JobOperator.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWhenUserEnablesBatchProcessing() {\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withUserConfiguration(EnableBatchProcessingConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringBootBatchMongoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWhenUserProvidesBatchConfiguration() {\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withUserConfiguration(CustomBatchConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringBootBatchMongoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid schemaInitializerBeanNotCreatedByDefault() {\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(JobRepositoryDependsOnSchemaInitializationDetector.SCHEMA_INITIALIZATION_BEAN_NAME));\n\t}\n\n\t@Test\n\tvoid schemaInitializerBeanCreatedWhenSchemaInitializeEnabled() {\n\t\tMongoOperations mongoOperations = mock(MongoOperations.class);\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withBean(MongoOperations.class, () -> mongoOperations)\n\t\t\t.withPropertyValues(\"spring.batch.data.mongodb.schema.initialize=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context)\n\t\t\t\t\t.hasBean(JobRepositoryDependsOnSchemaInitializationDetector.SCHEMA_INITIALIZATION_BEAN_NAME);\n\t\t\t\t// see org/springframework/batch/core/schema-mongodb.jsonl\n\t\t\t\tthen(mongoOperations).should(times(7)).executeCommand(anyString());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jobRepositoryDependsOnSchemaInitializerWhenSchemaInitializationEnabled() {\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withBean(MongoOperations.class, Mockito::mock)\n\t\t\t.withPropertyValues(\"spring.batch.data.mongodb.schema.initialize=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobRepository.class);\n\t\t\t\tBeanDefinition jobRepositoryDefinition = context.getBeanFactory().getBeanDefinition(\"jobRepository\");\n\t\t\t\tassertThat(jobRepositoryDefinition.getDependsOn())\n\t\t\t\t\t.contains(JobRepositoryDependsOnSchemaInitializationDetector.SCHEMA_INITIALIZATION_BEAN_NAME);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid schemaInitializationFailsWhenSchemaLocationDoesNotExist() {\n\t\tthis.contextRunner.withBean(MongoDatabaseFactory.class, this::mockMongoDatabaseFactory)\n\t\t\t.withBean(MongoOperations.class, Mockito::mock)\n\t\t\t.withPropertyValues(\"spring.batch.data.mongodb.schema.initialize=true\",\n\t\t\t\t\t\"spring.batch.data.mongodb.schema.location=classpath:does/not/exist.jsonl\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.hasRootCauseInstanceOf(\n\t\t\t\t\t\torg.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException.class)\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"spring.batch.data.mongodb.schema.location\")\n\t\t\t\t.hasMessageContaining(\"resource does not exist\"));\n\t}\n\n\tprivate MongoDatabaseFactory mockMongoDatabaseFactory() {\n\t\tMongoDatabaseFactory factory = mock(MongoDatabaseFactory.class);\n\t\tgiven(factory.getExceptionTranslator()).willReturn(MongoExceptionTranslator.DEFAULT_EXCEPTION_TRANSLATOR);\n\t\treturn factory;\n\t}\n\n\t@EnableBatchProcessing\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EnableBatchProcessingConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBatchConfiguration extends DefaultBatchConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\t@BatchTransactionManager\n\t\tMongoTransactionManager customTransactionManager() {\n\t\t\treturn mock(MongoTransactionManager.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-data-mongodb/src/test/java/org/springframework/boot/batch/mongodb/autoconfigure/BatchMongoSchemaInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.mongodb.autoconfigure;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.InputStreamResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.data.mongodb.core.MongoOperations;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BatchMongoSchemaInitializer}.\n *\n * @author Stephane Nicoll\n */\nclass BatchMongoSchemaInitializerTests {\n\n\t@Test\n\tvoid initializeExecutesEachNonBlankLine() throws IOException {\n\t\tMongoOperations mongoOperations = mock(MongoOperations.class);\n\t\tBatchMongoSchemaInitializer initializer = new BatchMongoSchemaInitializer(mongoOperations);\n\t\tResource schema = resource(\"{\\\"create\\\": \\\"batch_job_instance\\\"}\\n{\\\"create\\\": \\\"batch_job_execution\\\"}\");\n\n\t\tinitializer.initialize(schema);\n\n\t\tthen(mongoOperations).should().executeCommand(\"{\\\"create\\\": \\\"batch_job_instance\\\"}\");\n\t\tthen(mongoOperations).should().executeCommand(\"{\\\"create\\\": \\\"batch_job_execution\\\"}\");\n\t}\n\n\t@Test\n\tvoid initializeSkipsBlankLines() throws IOException {\n\t\tMongoOperations mongoOperations = mock(MongoOperations.class);\n\t\tBatchMongoSchemaInitializer initializer = new BatchMongoSchemaInitializer(mongoOperations);\n\t\tResource schema = resource(\"{\\\"create\\\": \\\"col1\\\"}\\n\\n  \\n{\\\"create\\\": \\\"col2\\\"}\");\n\n\t\tinitializer.initialize(schema);\n\n\t\tthen(mongoOperations).should().executeCommand(\"{\\\"create\\\": \\\"col1\\\"}\");\n\t\tthen(mongoOperations).should().executeCommand(\"{\\\"create\\\": \\\"col2\\\"}\");\n\t}\n\n\t@Test\n\tvoid initializeThrowsWhenCommandFails() {\n\t\tMongoOperations mongoOperations = mock(MongoOperations.class);\n\t\tgiven(mongoOperations.executeCommand(anyString())).willThrow(new RuntimeException(\"Command failed\"));\n\t\tBatchMongoSchemaInitializer initializer = new BatchMongoSchemaInitializer(mongoOperations);\n\t\tResource schema = resource(\"{\\\"create\\\": \\\"batch_job_instance\\\"}\");\n\n\t\tassertThatExceptionOfType(BatchMongoSchemaInitializationException.class)\n\t\t\t.isThrownBy(() -> initializer.initialize(schema))\n\t\t\t.withMessageContaining(\"Failed to initialize Batch repository schema\")\n\t\t\t.withMessageContaining(\"{\\\"create\\\": \\\"batch_job_instance\\\"}\")\n\t\t\t.withCauseInstanceOf(RuntimeException.class);\n\t}\n\n\tprivate static Resource resource(String content) {\n\t\treturn new InputStreamResource(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Batch JDBC\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-batch\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n\n\timplementation(project(\":module:spring-boot-transaction\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-hibernate\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-liquibase\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-sql\")))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\ttestRuntimeOnly(\"tools.jackson.core:jackson-databind\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Qualifier annotation for a DataSource to be injected into Batch auto-configuration. Can\n * be used on a secondary data source, if there is another one marked as\n * {@link Primary @Primary}.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface BatchDataSource {\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer;\n\n/**\n * {@link DataSourceScriptDatabaseInitializer} for the Spring Batch database. May be\n * registered as a bean to override auto-configuration.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class BatchDataSourceScriptDatabaseInitializer\n\t\textends PropertiesBasedDataSourceScriptDatabaseInitializer<BatchJdbcProperties> {\n\n\t/**\n\t * Create a new {@link BatchDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the Spring Batch data source\n\t * @param properties the Spring Batch JDBC properties\n\t */\n\tpublic BatchDataSourceScriptDatabaseInitializer(DataSource dataSource, BatchJdbcProperties properties) {\n\t\tsuper(dataSource, properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchJdbcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;\nimport org.springframework.batch.core.configuration.support.JdbcDefaultBatchConfiguration;\nimport org.springframework.batch.core.converter.JobParametersConverter;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.ExecutionContextSerializer;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchConversionServiceCustomizer;\nimport org.springframework.boot.batch.autoconfigure.BatchJobLauncherAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchTaskExecutor;\nimport org.springframework.boot.batch.autoconfigure.BatchTransactionManager;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.sql.autoconfigure.init.OnDatabaseInitializationCondition;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.jdbc.datasource.init.DatabasePopulator;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.Isolation;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Batch using a JDBC store.\n *\n * @author Dave Syer\n * @author Eddú Meléndez\n * @author Kazuki Shimizu\n * @author Mahmoud Ben Hassine\n * @author Lars Uffmann\n * @author Lasse Wulff\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration(before = { BatchAutoConfiguration.class, BatchJobLauncherAutoConfiguration.class },\n\t\tafter = { DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class },\n\t\tafterName = \"org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\")\n@ConditionalOnClass({ JobOperator.class, DataSource.class, DatabasePopulator.class })\n@ConditionalOnBean({ DataSource.class, PlatformTransactionManager.class })\n@ConditionalOnMissingBean(value = DefaultBatchConfiguration.class, annotation = EnableBatchProcessing.class)\n@EnableConfigurationProperties(BatchJdbcProperties.class)\n@Import(DatabaseInitializationDependencyConfigurer.class)\npublic final class BatchJdbcAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SpringBootBatchJdbcConfiguration extends JdbcDefaultBatchConfiguration {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprivate final PlatformTransactionManager transactionManager;\n\n\t\tprivate final @Nullable TaskExecutor taskExecutor;\n\n\t\tprivate final BatchJdbcProperties properties;\n\n\t\tprivate final List<BatchConversionServiceCustomizer> batchConversionServiceCustomizers;\n\n\t\tprivate final @Nullable ExecutionContextSerializer executionContextSerializer;\n\n\t\tprivate final @Nullable JobParametersConverter jobParametersConverter;\n\n\t\tSpringBootBatchJdbcConfiguration(DataSource dataSource,\n\t\t\t\t@BatchDataSource ObjectProvider<DataSource> batchDataSource,\n\t\t\t\tPlatformTransactionManager transactionManager,\n\t\t\t\t@BatchTransactionManager ObjectProvider<PlatformTransactionManager> batchTransactionManager,\n\t\t\t\t@BatchTaskExecutor ObjectProvider<TaskExecutor> batchTaskExecutor, BatchJdbcProperties properties,\n\t\t\t\tObjectProvider<BatchConversionServiceCustomizer> batchConversionServiceCustomizers,\n\t\t\t\tObjectProvider<ExecutionContextSerializer> executionContextSerializer,\n\t\t\t\tObjectProvider<JobParametersConverter> jobParametersConverter) {\n\t\t\tthis.dataSource = batchDataSource.getIfAvailable(() -> dataSource);\n\t\t\tthis.transactionManager = batchTransactionManager.getIfAvailable(() -> transactionManager);\n\t\t\tthis.taskExecutor = batchTaskExecutor.getIfAvailable();\n\t\t\tthis.properties = properties;\n\t\t\tthis.batchConversionServiceCustomizers = batchConversionServiceCustomizers.orderedStream().toList();\n\t\t\tthis.executionContextSerializer = executionContextSerializer.getIfAvailable();\n\t\t\tthis.jobParametersConverter = jobParametersConverter.getIfAvailable();\n\t\t}\n\n\t\t@Override\n\t\tprotected DataSource getDataSource() {\n\t\t\treturn this.dataSource;\n\t\t}\n\n\t\t@Override\n\t\tprotected PlatformTransactionManager getTransactionManager() {\n\t\t\treturn this.transactionManager;\n\t\t}\n\n\t\t@Override\n\t\tprotected String getTablePrefix() {\n\t\t\tString tablePrefix = this.properties.getTablePrefix();\n\t\t\treturn (tablePrefix != null) ? tablePrefix : super.getTablePrefix();\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean getValidateTransactionState() {\n\t\t\treturn this.properties.isValidateTransactionState();\n\t\t}\n\n\t\t@Override\n\t\tprotected Isolation getIsolationLevelForCreate() {\n\t\t\tIsolation isolation = this.properties.getIsolationLevelForCreate();\n\t\t\treturn (isolation != null) ? isolation : super.getIsolationLevelForCreate();\n\t\t}\n\n\t\t@Override\n\t\tprotected ConfigurableConversionService getConversionService() {\n\t\t\tConfigurableConversionService conversionService = super.getConversionService();\n\t\t\tfor (BatchConversionServiceCustomizer customizer : this.batchConversionServiceCustomizers) {\n\t\t\t\tcustomizer.customize(conversionService);\n\t\t\t}\n\t\t\treturn conversionService;\n\t\t}\n\n\t\t@Override\n\t\tprotected ExecutionContextSerializer getExecutionContextSerializer() {\n\t\t\treturn (this.executionContextSerializer != null) ? this.executionContextSerializer\n\t\t\t\t\t: super.getExecutionContextSerializer();\n\t\t}\n\n\t\t@Override\n\t\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t\t@SuppressWarnings(\"removal\")\n\t\tprotected JobParametersConverter getJobParametersConverter() {\n\t\t\treturn (this.jobParametersConverter != null) ? this.jobParametersConverter\n\t\t\t\t\t: super.getJobParametersConverter();\n\t\t}\n\n\t\t@Override\n\t\tprotected TaskExecutor getTaskExecutor() {\n\t\t\treturn (this.taskExecutor != null) ? this.taskExecutor : super.getTaskExecutor();\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@Conditional(OnBatchDatasourceInitializationCondition.class)\n\t\tstatic class DataSourceInitializerConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean\n\t\t\tBatchDataSourceScriptDatabaseInitializer batchDataSourceInitializer(DataSource dataSource,\n\t\t\t\t\t@BatchDataSource ObjectProvider<DataSource> batchDataSource, BatchJdbcProperties properties) {\n\t\t\t\treturn new BatchDataSourceScriptDatabaseInitializer(batchDataSource.getIfAvailable(() -> dataSource),\n\t\t\t\t\t\tproperties);\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class OnBatchDatasourceInitializationCondition extends OnDatabaseInitializationCondition {\n\n\t\t\tOnBatchDatasourceInitializationCondition() {\n\t\t\t\tsuper(\"Batch\", \"spring.batch.jdbc.initialize-schema\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchJdbcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.init.DatabaseInitializationProperties;\nimport org.springframework.transaction.annotation.Isolation;\n\n/**\n * Configuration properties for Spring Batch using a JDBC store.\n *\n * @author Stephane Nicoll\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.batch.jdbc\")\npublic class BatchJdbcProperties extends DatabaseInitializationProperties {\n\n\tprivate static final String DEFAULT_SCHEMA_LOCATION = \"classpath:org/springframework/\"\n\t\t\t+ \"batch/core/schema-@@platform@@.sql\";\n\n\t/**\n\t * Whether to validate the transaction state.\n\t */\n\tprivate boolean validateTransactionState = true;\n\n\t/**\n\t * Transaction isolation level to use when creating job meta-data for new jobs.\n\t */\n\tprivate @Nullable Isolation isolationLevelForCreate;\n\n\t/**\n\t * Table prefix for all the batch meta-data tables.\n\t */\n\tprivate @Nullable String tablePrefix;\n\n\tpublic boolean isValidateTransactionState() {\n\t\treturn this.validateTransactionState;\n\t}\n\n\tpublic void setValidateTransactionState(boolean validateTransactionState) {\n\t\tthis.validateTransactionState = validateTransactionState;\n\t}\n\n\tpublic @Nullable Isolation getIsolationLevelForCreate() {\n\t\treturn this.isolationLevelForCreate;\n\t}\n\n\tpublic void setIsolationLevelForCreate(@Nullable Isolation isolationLevelForCreate) {\n\t\tthis.isolationLevelForCreate = isolationLevelForCreate;\n\t}\n\n\tpublic @Nullable String getTablePrefix() {\n\t\treturn this.tablePrefix;\n\t}\n\n\tpublic void setTablePrefix(@Nullable String tablePrefix) {\n\t\tthis.tablePrefix = tablePrefix;\n\t}\n\n\t@Override\n\tpublic String getDefaultSchemaLocation() {\n\t\treturn DEFAULT_SCHEMA_LOCATION;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc/autoconfigure/JobRepositoryDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\n\n/**\n * {@link DependsOnDatabaseInitializationDetector} for Spring Batch's\n * {@link JobRepository}.\n *\n * @author Henning Pöttker\n */\nclass JobRepositoryDependsOnDatabaseInitializationDetector\n\t\textends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\treturn Collections.singleton(JobRepository.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/java/org/springframework/boot/batch/jdbc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Batch JDBC.\n */\n@NullMarked\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.batch.initialize-schema\",\n      \"type\": \"org.springframework.boot.sql.init.DatabaseInitializationMode\",\n      \"deprecation\": {\n        \"replacement\": \"spring.batch.jdbc.initialize-schema\",\n        \"level\": \"error\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.batch.initializer.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Create the required batch tables on startup if necessary. Enabled automatically\\n if no custom table prefix is set or if a custom schema is configured.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.batch.jdbc.initialize-schema\",\n        \"level\": \"error\",\n        \"since\": \"2.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.batch.schema\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.batch.jdbc.schema\",\n        \"level\": \"error\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.batch.table-prefix\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.batch.jdbc.table-prefix\",\n        \"level\": \"error\",\n        \"since\": \"2.5.0\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.batch.jdbc.autoconfigure.BatchJdbcAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/main/resources/META-INF/spring.factories",
    "content": "# Depends on Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.batch.jdbc.autoconfigure.JobRepositoryDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchDataSourceScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport org.junit.jupiter.params.provider.EnumSource.Mode;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.sql.init.ScriptDatabaseInitializerSettings;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BatchDataSourceScriptDatabaseInitializer}.\n *\n * @author Stephane Nicoll\n */\nclass BatchDataSourceScriptDatabaseInitializerTests {\n\n\t@Test\n\tvoid getSettingsWithPlatformDoesNotTouchDataSource() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tBatchJdbcProperties properties = new BatchJdbcProperties();\n\t\tproperties.setPlatform(\"test\");\n\t\tDatabaseInitializationSettings settings = ScriptDatabaseInitializerSettings\n\t\t\t.get(new BatchDataSourceScriptDatabaseInitializer(dataSource, properties));\n\t\tassertThat(settings.getSchemaLocations())\n\t\t\t.containsOnly(\"classpath:org/springframework/batch/core/schema-test.sql\");\n\t\tthen(dataSource).shouldHaveNoInteractions();\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(mode = Mode.EXCLUDE, names = { \"AWS_WRAPPER\", \"CLICKHOUSE\", \"FIREBIRD\", \"INFORMIX\", \"JTDS\", \"PHOENIX\",\n\t\t\t\"REDSHIFT\", \"TERADATA\", \"TESTCONTAINERS\", \"UNKNOWN\" })\n\tvoid batchSchemaCanBeLocated(DatabaseDriver driver) throws SQLException {\n\t\tDefaultResourceLoader resourceLoader = new DefaultResourceLoader();\n\t\tBatchJdbcProperties properties = new BatchJdbcProperties();\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(dataSource.getConnection()).willReturn(connection);\n\t\tDatabaseMetaData metadata = mock(DatabaseMetaData.class);\n\t\tgiven(connection.getMetaData()).willReturn(metadata);\n\t\tString productName = (String) ReflectionTestUtils.getField(driver, \"productName\");\n\t\tgiven(metadata.getDatabaseProductName()).willReturn(productName);\n\t\tDatabaseInitializationSettings settings = ScriptDatabaseInitializerSettings\n\t\t\t.get(new BatchDataSourceScriptDatabaseInitializer(dataSource, properties));\n\t\tList<String> schemaLocations = settings.getSchemaLocations();\n\t\tassertThat(schemaLocations).isNotEmpty()\n\t\t\t.allSatisfy((location) -> assertThat(resourceLoader.getResource(location).exists()).isTrue());\n\t}\n\n\t@Test\n\tvoid batchHasExpectedBuiltInSchemas() throws IOException {\n\t\tPathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();\n\t\tList<String> schemaNames = Stream\n\t\t\t.of(resolver.getResources(\"classpath:org/springframework/batch/core/schema-*.sql\"))\n\t\t\t.map(Resource::getFilename)\n\t\t\t.filter((resourceName) -> !resourceName.contains(\"-drop-\"))\n\t\t\t.toList();\n\t\tassertThat(schemaNames).containsExactlyInAnyOrder(\"schema-derby.sql\", \"schema-sqlserver.sql\",\n\t\t\t\t\"schema-mariadb.sql\", \"schema-mysql.sql\", \"schema-sqlite.sql\", \"schema-postgresql.sql\",\n\t\t\t\t\"schema-hana.sql\", \"schema-oracle.sql\", \"schema-db2.sql\", \"schema-hsqldb.sql\", \"schema-sybase.sql\",\n\t\t\t\t\"schema-h2.sql\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchJdbcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport javax.sql.DataSource;\n\nimport jakarta.persistence.EntityManagerFactory;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.Mockito;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;\nimport org.springframework.batch.core.converter.DefaultJobParametersConverter;\nimport org.springframework.batch.core.converter.JobParametersConverter;\nimport org.springframework.batch.core.converter.JsonJobParametersConverter;\nimport org.springframework.batch.core.job.AbstractJob;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.job.parameters.JobParametersBuilder;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.ExecutionContextSerializer;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.repository.dao.DefaultExecutionContextSerializer;\nimport org.springframework.batch.core.repository.dao.JacksonExecutionContextStringSerializer;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.DefaultApplicationArguments;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.batch.autoconfigure.BatchConversionServiceCustomizer;\nimport org.springframework.boot.batch.autoconfigure.BatchJobLauncherAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchTaskExecutor;\nimport org.springframework.boot.batch.autoconfigure.BatchTransactionManager;\nimport org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner;\nimport org.springframework.boot.batch.jdbc.autoconfigure.BatchJdbcAutoConfiguration.SpringBootBatchJdbcConfiguration;\nimport org.springframework.boot.batch.jdbc.autoconfigure.domain.City;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.SyncTaskExecutor;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.datasource.init.DatabasePopulator;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.test.util.AopTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.Isolation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BatchJdbcAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Kazuki Shimizu\n * @author Mahmoud Ben Hassine\n * @author Lars Uffmann\n * @author Lasse Wulff\n * @author Yanming Zhou\n */\nclass BatchJdbcAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BatchJobLauncherAutoConfiguration.class,\n\t\t\t\tBatchJdbcAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class,\n\t\t\t\tTransactionAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultContext() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JobRepository.class);\n\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\tassertThat(context.getBean(BatchJdbcProperties.class).getInitializeSchema())\n\t\t\t\t.isEqualTo(DatabaseInitializationMode.EMBEDDED);\n\t\t\tassertThat(new JdbcTemplate(context.getBean(DataSource.class))\n\t\t\t\t.queryForList(\"select * from BATCH_JOB_EXECUTION\")).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoconfigurationBacksOffEntirelyIfSpringJdbcAbsent() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(DatabasePopulator.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(JobLauncherApplicationRunner.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(BatchDataSourceScriptDatabaseInitializer.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWhenUserEnablesBatchProcessing() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EnableBatchProcessingConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(DatabasePopulator.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BatchJdbcAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWhenUserProvidesBatchConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomBatchConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(DatabasePopulator.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BatchJdbcAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid testDefinesAndLaunchesJob() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class)\n\t\t\t\t\t.run(new DefaultApplicationArguments(\"jobParam=test\"));\n\t\t\t\tJobParameters jobParameters = new JobParametersBuilder().addString(\"jobParam\", \"test\")\n\t\t\t\t\t.toJobParameters();\n\t\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"job\", jobParameters)).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefinesAndLaunchesJobIgnoreOptionArguments() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class)\n\t\t\t\t\t.run(new DefaultApplicationArguments(\"--spring.property=value\", \"jobParam=test\"));\n\t\t\t\tJobParameters jobParameters = new JobParametersBuilder().addString(\"jobParam\", \"test\")\n\t\t\t\t\t.toJobParameters();\n\t\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"job\", jobParameters)).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRegisteredAndLocalJob() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NamedJobConfigurationWithRegisteredAndLocalJob.class,\n\t\t\t\t\tEmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.name:discreteRegisteredJob\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run();\n\t\t\t\tJobExecution lastJobExecution = context.getBean(JobRepository.class)\n\t\t\t\t\t.getLastJobExecution(\"discreteRegisteredJob\", new JobParameters());\n\t\t\t\tassertThat(lastJobExecution).isNotNull();\n\t\t\t\tassertThat(lastJobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefinesAndLaunchesLocalJob() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(NamedJobConfigurationWithLocalJob.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.name:discreteLocalJob\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run();\n\t\t\t\tassertThat(context.getBean(JobRepository.class)\n\t\t\t\t\t.getLastJobExecution(\"discreteLocalJob\", new JobParameters())).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testMultipleJobsAndNoJobName() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleJobConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tThrowable startupFailure = context.getStartupFailure();\n\t\t\t\tassertThat(startupFailure).isNotNull();\n\t\t\t\tThrowable cause = startupFailure.getCause();\n\t\t\t\tassertThat(cause).isNotNull();\n\t\t\t\tassertThat(cause.getMessage()).contains(\"Job name must be specified in case of multiple jobs\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testMultipleJobsAndJobName() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleJobConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.name:discreteLocalJob\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tcontext.getBean(JobLauncherApplicationRunner.class).run();\n\t\t\t\tassertThat(context.getBean(JobRepository.class)\n\t\t\t\t\t.getLastJobExecution(\"discreteLocalJob\", new JobParameters())).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDisableLaunchesJob() {\n\t\tthis.contextRunner.withUserConfiguration(JobConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.job.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(CommandLineRunner.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDisableSchemaLoader() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.batch.jdbc.initialize-schema:never\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tassertThat(context.getBean(BatchJdbcProperties.class).getInitializeSchema())\n\t\t\t\t\t.isEqualTo(DatabaseInitializationMode.NEVER);\n\t\t\t\tassertThat(context).doesNotHaveBean(BatchDataSourceScriptDatabaseInitializer.class);\n\t\t\t\tassertThatExceptionOfType(BadSqlGrammarException.class)\n\t\t\t\t\t.isThrownBy(() -> new JdbcTemplate(context.getBean(DataSource.class))\n\t\t\t\t\t\t.queryForList(\"select * from BATCH_JOB_EXECUTION\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testUsingJpa() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(TestJpaConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tHibernateJpaAutoConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\t\t// It's a lazy proxy, but it does render its target if you ask for\n\t\t\t\t// toString():\n\t\t\t\tassertThat(transactionManager.toString()).contains(\"JpaTransactionManager\");\n\t\t\t\tassertThat(context).hasSingleBean(EntityManagerFactory.class);\n\t\t\t\t// Ensure the JobRepository can be used (no problem with isolation\n\t\t\t\t// level)\n\t\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"job\", new JobParameters()))\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"custom-schema.sql\")\n\tvoid testRenamePrefix() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.batch.jdbc.schema:classpath:custom-schema.sql\", \"spring.batch.jdbc.table-prefix:PREFIX_\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tassertThat(context.getBean(BatchJdbcProperties.class).getInitializeSchema())\n\t\t\t\t\t.isEqualTo(DatabaseInitializationMode.EMBEDDED);\n\t\t\t\tassertThat(new JdbcTemplate(context.getBean(DataSource.class))\n\t\t\t\t\t.queryForList(\"select * from PREFIX_JOB_EXECUTION\")).isEmpty();\n\t\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\t\t\t\tassertThat(jobRepository.findRunningJobExecutions(\"test\")).isEmpty();\n\t\t\t\tassertThat(jobRepository.getLastJobExecution(\"test\", new JobParameters())).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testCustomizeJpaTransactionManagerUsingProperties() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(TestJpaConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tHibernateJpaAutoConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.transaction.default-timeout:30\",\n\t\t\t\t\t\"spring.transaction.rollback-on-commit-failure:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(BatchJobLauncherAutoConfiguration.class);\n\t\t\t\tJpaTransactionManager transactionManager = JpaTransactionManager.class\n\t\t\t\t\t.cast(context.getBean(SpringBootBatchJdbcConfiguration.class).getTransactionManager());\n\t\t\t\tassertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);\n\t\t\t\tassertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testCustomizeDataSourceTransactionManagerUsingProperties() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.transaction.default-timeout:30\",\n\t\t\t\t\t\"spring.transaction.rollback-on-commit-failure:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(BatchJdbcAutoConfiguration.class);\n\t\t\t\tDataSourceTransactionManager transactionManager = DataSourceTransactionManager.class\n\t\t\t\t\t.cast(context.getBean(SpringBootBatchJdbcConfiguration.class).getTransactionManager());\n\t\t\t\tassertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);\n\t\t\t\tassertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testBatchDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(BatchDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchJdbcAutoConfiguration.class)\n\t\t\t\t.hasSingleBean(BatchDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"batchDataSource\");\n\t\t\tDataSource batchDataSource = context.getBean(\"batchDataSource\", DataSource.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getDataSource())\n\t\t\t\t.isEqualTo(batchDataSource);\n\t\t\tassertThat(context.getBean(BatchDataSourceScriptDatabaseInitializer.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"dataSource\", batchDataSource);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testBatchTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(BatchTransactionManagerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchJdbcAutoConfiguration.class);\n\t\t\tPlatformTransactionManager batchTransactionManager = context.getBean(\"batchTransactionManager\",\n\t\t\t\t\tPlatformTransactionManager.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getTransactionManager())\n\t\t\t\t.isEqualTo(batchTransactionManager);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testBatchTaskExecutor() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(BatchTaskExecutorConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(BatchJdbcAutoConfiguration.class).hasBean(\"batchTaskExecutor\");\n\t\t\t\tTaskExecutor batchTaskExecutor = context.getBean(\"batchTaskExecutor\", TaskExecutor.class);\n\t\t\t\tassertThat(batchTaskExecutor).isInstanceOf(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getTaskExecutor())\n\t\t\t\t\t.isEqualTo(batchTaskExecutor);\n\t\t\t\tJobOperator jobOperator = AopTestUtils.getTargetObject(context.getBean(JobOperator.class));\n\t\t\t\tassertThat(jobOperator).hasFieldOrPropertyWithValue(\"taskExecutor\", batchTaskExecutor);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jobRepositoryBeansDependOnBatchDataSourceInitializer() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tString[] jobRepositoryNames = beanFactory.getBeanNamesForType(JobRepository.class);\n\t\t\tassertThat(jobRepositoryNames).isNotEmpty();\n\t\t\tfor (String jobRepositoryName : jobRepositoryNames) {\n\t\t\t\tassertThat(beanFactory.getBeanDefinition(jobRepositoryName).getDependsOn())\n\t\t\t\t\t.contains(\"batchDataSourceInitializer\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid jobRepositoryBeansDependOnFlyway() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayAutoConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.jdbc.initialize-schema=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tString[] jobRepositoryNames = beanFactory.getBeanNamesForType(JobRepository.class);\n\t\t\t\tassertThat(jobRepositoryNames).isNotEmpty();\n\t\t\t\tfor (String jobRepositoryName : jobRepositoryNames) {\n\t\t\t\t\tassertThat(beanFactory.getBeanDefinition(jobRepositoryName).getDependsOn()).contains(\"flyway\",\n\t\t\t\t\t\t\t\"flywayInitializer\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-master.yaml\", content = \"databaseChangeLog:\")\n\tvoid jobRepositoryBeansDependOnLiquibase() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, LiquibaseAutoConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.jdbc.initialize-schema=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tString[] jobRepositoryNames = beanFactory.getBeanNamesForType(JobRepository.class);\n\t\t\t\tassertThat(jobRepositoryNames).isNotEmpty();\n\t\t\t\tfor (String jobRepositoryName : jobRepositoryNames) {\n\t\t\t\t\tassertThat(beanFactory.getBeanDefinition(jobRepositoryName).getDependsOn()).contains(\"liquibase\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnBatchDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomBatchDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(BatchDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.doesNotHaveBean(\"batchDataSourceScriptDatabaseInitializer\")\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredBatchInitializerRemains() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(BatchDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid conversionServiceCustomizersAreCalled() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tConversionServiceCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tBatchConversionServiceCustomizer customizer = context.getBean(\"batchConversionServiceCustomizer\",\n\t\t\t\t\t\tBatchConversionServiceCustomizer.class);\n\t\t\t\tBatchConversionServiceCustomizer anotherCustomizer = context\n\t\t\t\t\t.getBean(\"anotherBatchConversionServiceCustomizer\", BatchConversionServiceCustomizer.class);\n\t\t\t\tInOrder inOrder = Mockito.inOrder(customizer, anotherCustomizer);\n\t\t\t\tConfigurableConversionService configurableConversionService = context\n\t\t\t\t\t.getBean(SpringBootBatchJdbcConfiguration.class)\n\t\t\t\t\t.getConversionService();\n\t\t\t\tinOrder.verify(customizer).customize(configurableConversionService);\n\t\t\t\tinOrder.verify(anotherCustomizer).customize(configurableConversionService);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameAsJobInstanceValidates() {\n\t\tJobLauncherApplicationRunner runner = createInstance(\"another\");\n\t\trunner.setJobs(Collections.singletonList(mockJob(\"test\")));\n\t\trunner.setJobName(\"test\");\n\t\trunner.afterPropertiesSet();\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameAsRegisteredJobValidates() {\n\t\tJobLauncherApplicationRunner runner = createInstance(\"test\");\n\t\trunner.setJobName(\"test\");\n\t\trunner.afterPropertiesSet();\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameThatDoesNotExistWithJobInstancesFailsFast() {\n\t\tJobLauncherApplicationRunner runner = createInstance();\n\t\trunner.setJobs(Arrays.asList(mockJob(\"one\"), mockJob(\"two\")));\n\t\trunner.setJobName(\"three\");\n\t\tassertThatIllegalStateException().isThrownBy(runner::afterPropertiesSet)\n\t\t\t.withMessage(\"No job found with name 'three'\");\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesAJobNameThatDoesNotExistWithRegisteredJobFailsFast() {\n\t\tJobLauncherApplicationRunner runner = createInstance(\"one\", \"two\");\n\t\trunner.setJobName(\"three\");\n\t\tassertThatIllegalStateException().isThrownBy(runner::afterPropertiesSet)\n\t\t\t.withMessage(\"No job found with name 'three'\");\n\t}\n\n\t@Test\n\tvoid customExecutionContextSerializerIsUsed() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withBean(ExecutionContextSerializer.class, JacksonExecutionContextStringSerializer::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JacksonExecutionContextStringSerializer.class);\n\t\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getExecutionContextSerializer())\n\t\t\t\t\t.isInstanceOf(JacksonExecutionContextStringSerializer.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultExecutionContextSerializerIsUsed() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ExecutionContextSerializer.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getExecutionContextSerializer())\n\t\t\t\t.isInstanceOf(DefaultExecutionContextSerializer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customJdbcPropertiesIsUsed() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.batch.jdbc.validate-transaction-state:false\",\n\t\t\t\t\t\"spring.batch.jdbc.isolation-level-for-create:READ_COMMITTED\")\n\t\t\t.run((context) -> {\n\t\t\t\tSpringBootBatchJdbcConfiguration configuration = context\n\t\t\t\t\t.getBean(SpringBootBatchJdbcConfiguration.class);\n\t\t\t\tassertThat(configuration.getValidateTransactionState()).isEqualTo(false);\n\t\t\t\tassertThat(configuration.getIsolationLevelForCreate()).isEqualTo(Isolation.READ_COMMITTED);\n\t\t\t});\n\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid customJobParametersConverterIsUsed() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withBean(JobParametersConverter.class, JsonJobParametersConverter::new)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JsonJobParametersConverter.class);\n\t\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getJobParametersConverter())\n\t\t\t\t\t.isInstanceOf(JsonJobParametersConverter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid defaultJobParametersConverterIsUsed() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(JobParametersConverter.class);\n\t\t\tassertThat(context.getBean(SpringBootBatchJdbcConfiguration.class).getJobParametersConverter())\n\t\t\t\t.isInstanceOf(DefaultJobParametersConverter.class);\n\t\t});\n\t}\n\n\tprivate JobLauncherApplicationRunner createInstance(String... registeredJobNames) {\n\t\tJobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(mock(JobOperator.class));\n\t\tJobRegistry jobRegistry = mock(JobRegistry.class);\n\t\tgiven(jobRegistry.getJobNames()).willReturn(Arrays.asList(registeredJobNames));\n\t\trunner.setJobRegistry(jobRegistry);\n\t\treturn runner;\n\t}\n\n\tprivate Job mockJob(String name) {\n\t\tJob job = mock(Job.class);\n\t\tgiven(job.getName()).willReturn(name);\n\t\treturn job;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource normalDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:h2:mem:normal\").username(\"sa\").build();\n\t\t}\n\n\t\t@BatchDataSource\n\t\t@Bean(defaultCandidate = false)\n\t\tDataSource batchDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:h2:mem:batchdatasource\").username(\"sa\").build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:h2:mem:database\").username(\"sa\").build();\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tPlatformTransactionManager normalTransactionManager() {\n\t\t\treturn mock(PlatformTransactionManager.class);\n\t\t}\n\n\t\t@BatchTransactionManager\n\t\t@Bean(defaultCandidate = false)\n\t\tPlatformTransactionManager batchTransactionManager() {\n\t\t\treturn mock(PlatformTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchTaskExecutorConfiguration {\n\n\t\t@Bean\n\t\tTaskExecutor taskExecutor() {\n\t\t\treturn new SyncTaskExecutor();\n\t\t}\n\n\t\t@BatchTaskExecutor\n\t\t@Bean(defaultCandidate = false)\n\t\tTaskExecutor batchTaskExecutor() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestJpaConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EntityManagerFactoryConfiguration {\n\n\t\t@Bean\n\t\tEntityManagerFactory entityManagerFactory() {\n\t\t\treturn mock(EntityManagerFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NamedJobConfigurationWithRegisteredAndLocalJob {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob discreteJob() {\n\t\t\tAbstractJob job = new AbstractJob(\"discreteRegisteredJob\") {\n\n\t\t\t\tprivate static int count;\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\tif (count == 0) {\n\t\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\texecution.setStatus(BatchStatus.FAILED);\n\t\t\t\t\t}\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NamedJobConfigurationWithLocalJob {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob discreteJob() {\n\t\t\tAbstractJob job = new AbstractJob(\"discreteLocalJob\") {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleJobConfiguration {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob discreteJob() {\n\t\t\tAbstractJob job = new AbstractJob(\"discreteLocalJob\") {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t\t@Bean\n\t\tJob job2() {\n\t\t\treturn new Job() {\n\t\t\t\t@Override\n\t\t\t\tpublic String getName() {\n\t\t\t\t\treturn \"discreteLocalJob2\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void execute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JobConfiguration {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Bean\n\t\tJob job() {\n\t\t\tAbstractJob job = new AbstractJob() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Collection<String> getStepNames() {\n\t\t\t\t\treturn Collections.emptySet();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Step getStep(String stepName) {\n\t\t\t\t\treturn mock(Step.class);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doExecute(JobExecution execution) {\n\t\t\t\t\texecution.setStatus(BatchStatus.COMPLETED);\n\t\t\t\t}\n\t\t\t};\n\t\t\tjob.setJobRepository(this.jobRepository);\n\t\t\treturn job;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBatchDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tBatchDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource,\n\t\t\t\tBatchJdbcProperties properties) {\n\t\t\treturn new BatchDataSourceScriptDatabaseInitializer(dataSource, properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) {\n\t\t\treturn new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBatchConfiguration extends DefaultBatchConfiguration {\n\n\t}\n\n\t@EnableBatchProcessing\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EnableBatchProcessingConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConversionServiceCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tBatchConversionServiceCustomizer batchConversionServiceCustomizer() {\n\t\t\treturn mock(BatchConversionServiceCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tBatchConversionServiceCustomizer anotherBatchConversionServiceCustomizer() {\n\t\t\treturn mock(BatchConversionServiceCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchJdbcAutoConfigurationWithoutJpaTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.batch.jdbc.autoconfigure.BatchJdbcAutoConfiguration.SpringBootBatchJdbcConfiguration;\nimport org.springframework.boot.batch.jdbc.autoconfigure.domain.City;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.transaction.annotation.Isolation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BatchJdbcAutoConfiguration} when JPA is not on the classpath.\n *\n * @author Stephane Nicoll\n */\n@ClassPathExclusions(\"hibernate-jpa-*.jar\")\nclass BatchJdbcAutoConfigurationWithoutJpaTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BatchJdbcAutoConfiguration.class, TransactionAutoConfiguration.class,\n\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class));\n\n\t@Test\n\tvoid jdbcWithDefaultSettings() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JobOperator.class);\n\t\t\t\tassertThat(context).hasSingleBean(JobRepository.class);\n\t\t\t\tassertThat(context.getBean(BatchJdbcProperties.class).getInitializeSchema())\n\t\t\t\t\t.isEqualTo(DatabaseInitializationMode.EMBEDDED);\n\t\t\t\tassertThat(new JdbcTemplate(context.getBean(DataSource.class))\n\t\t\t\t\t.queryForList(\"select * from BATCH_JOB_EXECUTION\")).isEmpty();\n\t\t\t\tassertThat(context.getBean(JobRepository.class).findRunningJobExecutions(\"test\")).isEmpty();\n\t\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"test\", new JobParameters()))\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"custom-schema.sql\")\n\tvoid jdbcWithCustomPrefix() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.batch.jdbc.schema:classpath:custom-schema.sql\", \"spring.batch.jdbc.tablePrefix:PREFIX_\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(new JdbcTemplate(context.getBean(DataSource.class))\n\t\t\t\t\t.queryForList(\"select * from PREFIX_JOB_EXECUTION\")).isEmpty();\n\t\t\t\tassertThat(context.getBean(JobRepository.class).findRunningJobExecutions(\"test\")).isEmpty();\n\t\t\t\tassertThat(context.getBean(JobRepository.class).getLastJobExecution(\"test\", new JobParameters()))\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jdbcWithCustomIsolationLevel() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.batch.jdbc.isolation-level-for-create=read_committed\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(SpringBootBatchJdbcConfiguration.class).getIsolationLevelForCreate())\n\t\t\t\t.isEqualTo(Isolation.READ_COMMITTED));\n\t}\n\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class DefaultConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/BatchJdbcPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.configuration.support.JdbcDefaultBatchConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BatchJdbcProperties}.\n *\n * @author Andy Wilkinson\n */\nclass BatchJdbcPropertiesTests {\n\n\t@Test\n\tvoid validateTransactionStateDefaultMatchesSpringBatchDefault() {\n\t\tassertThat(new BatchJdbcProperties().isValidateTransactionState())\n\t\t\t.isEqualTo(new TestBatchConfiguration().getValidateTransactionState());\n\t}\n\n\tstatic class TestBatchConfiguration extends JdbcDefaultBatchConfiguration {\n\n\t\t@Override\n\t\tpublic boolean getValidateTransactionState() {\n\t\t\treturn super.getValidateTransactionState();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/domain/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.batch.jdbc.autoconfigure.domain;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n@Entity\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String state, String country, String map) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t\tthis.country = country;\n\t\tthis.map = map;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/java/org/springframework/boot/batch/jdbc/autoconfigure/domain/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.batch.jdbc.autoconfigure.domain;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-batch-jdbc/src/test/resources/org/springframework/boot/batch/jdbc/autoconfigure/custom-schema.sql",
    "content": "CREATE TABLE PREFIX_JOB_INSTANCE  (\n\tJOB_INSTANCE_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\tVERSION BIGINT,\n\tJOB_NAME VARCHAR(100) NOT NULL,\n\tJOB_KEY VARCHAR(32) NOT NULL,\n\tconstraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)\n) ;\n\nCREATE TABLE PREFIX_JOB_EXECUTION  (\n\tJOB_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\tVERSION BIGINT,\n\tJOB_INSTANCE_ID BIGINT NOT NULL,\n\tCREATE_TIME TIMESTAMP(9) NOT NULL,\n\tSTART_TIME TIMESTAMP(9) DEFAULT NULL,\n\tEND_TIME TIMESTAMP(9) DEFAULT NULL,\n\tSTATUS VARCHAR(10),\n\tEXIT_CODE VARCHAR(2500),\n\tEXIT_MESSAGE VARCHAR(2500),\n\tLAST_UPDATED TIMESTAMP(9),\n\tconstraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)\n\treferences PREFIX_JOB_INSTANCE(JOB_INSTANCE_ID)\n) ;\n\nCREATE TABLE PREFIX_JOB_EXECUTION_PARAMS  (\n\tJOB_EXECUTION_ID BIGINT NOT NULL,\n\tPARAMETER_NAME VARCHAR(100) NOT NULL,\n\tPARAMETER_TYPE VARCHAR(100) NOT NULL,\n\tPARAMETER_VALUE VARCHAR(2500),\n\tIDENTIFYING CHAR(1) NOT NULL,\n\tconstraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)\n\treferences PREFIX_JOB_EXECUTION(JOB_EXECUTION_ID)\n) ;\n\nCREATE TABLE PREFIX_STEP_EXECUTION  (\n\tSTEP_EXECUTION_ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\tVERSION BIGINT NOT NULL,\n\tSTEP_NAME VARCHAR(100) NOT NULL,\n\tJOB_EXECUTION_ID BIGINT NOT NULL,\n\tCREATE_TIME TIMESTAMP(9) NOT NULL,\n\tSTART_TIME TIMESTAMP(9) DEFAULT NULL,\n\tEND_TIME TIMESTAMP(9) DEFAULT NULL,\n\tSTATUS VARCHAR(10),\n\tCOMMIT_COUNT BIGINT,\n\tREAD_COUNT BIGINT,\n\tFILTER_COUNT BIGINT,\n\tWRITE_COUNT BIGINT,\n\tREAD_SKIP_COUNT BIGINT,\n\tWRITE_SKIP_COUNT BIGINT,\n\tPROCESS_SKIP_COUNT BIGINT,\n\tROLLBACK_COUNT BIGINT,\n\tEXIT_CODE VARCHAR(2500),\n\tEXIT_MESSAGE VARCHAR(2500),\n\tLAST_UPDATED TIMESTAMP(9),\n\tconstraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)\n\treferences PREFIX_JOB_EXECUTION(JOB_EXECUTION_ID)\n) ;\n\nCREATE TABLE PREFIX_STEP_EXECUTION_CONTEXT  (\n\tSTEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,\n\tSHORT_CONTEXT VARCHAR(2500) NOT NULL,\n\tSERIALIZED_CONTEXT LONGVARCHAR,\n\tconstraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)\n\treferences PREFIX_STEP_EXECUTION(STEP_EXECUTION_ID)\n) ;\n\nCREATE TABLE PREFIX_JOB_EXECUTION_CONTEXT  (\n\tJOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,\n\tSHORT_CONTEXT VARCHAR(2500) NOT NULL,\n\tSERIALIZED_CONTEXT LONGVARCHAR,\n\tconstraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)\n\treferences PREFIX_JOB_EXECUTION(JOB_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ;\nCREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ;\nCREATE SEQUENCE BATCH_JOB_INSTANCE_SEQ;\n"
  },
  {
    "path": "module/spring-boot-cache/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Cache\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-context-support\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-data-couchbase\"))\n\toptional(project(\":module:spring-boot-data-redis\"))\n\toptional(project(\":module:spring-boot-hazelcast\"))\n\toptional(project(\":module:spring-boot-hibernate\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"com.hazelcast:hazelcast-spring\")\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"javax.cache:cache-api\")\n\toptional(\"org.cache2k:cache2k-micrometer\")\n\toptional(\"org.cache2k:cache2k-spring\")\n\toptional(\"org.ehcache:ehcache\") {\n\t\tartifact {\n\t\t\tclassifier = 'jakarta'\n\t\t}\n\t}\n\toptional(\"org.hibernate.orm:hibernate-core\")\n\toptional(\"org.hibernate.orm:hibernate-jcache\")\n\toptional(\"org.infinispan:infinispan-commons\")\n\toptional(\"org.infinispan:infinispan-component-annotations\")\n\toptional(\"org.infinispan:infinispan-core\")\n\toptional(\"org.infinispan:infinispan-jcache\")\n\toptional(\"org.infinispan:infinispan-spring6-embedded\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-jersey\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webmvc\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webflux\")))\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/dockerTest/java/org/springframework/boot/cache/metrics/RedisCacheMetricsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.UUID;\nimport java.util.function.BiConsumer;\n\nimport com.redis.testcontainers.RedisContainer;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.cache.RedisCache;\nimport org.springframework.data.redis.cache.RedisCacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RedisCacheMetrics}.\n *\n * @author Stephane Nicoll\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass RedisCacheMetricsTests {\n\n\t@Container\n\tstatic final RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\tprivate static final Tags TAGS = Tags.of(\"app\", \"test\").and(\"cache\", \"test\");\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class, CacheAutoConfiguration.class))\n\t\t.withUserConfiguration(CachingConfiguration.class)\n\t\t.withPropertyValues(\"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort(), \"spring.cache.type=redis\",\n\t\t\t\t\"spring.cache.redis.enable-statistics=true\");\n\n\t@Test\n\tvoid cacheStatisticsAreExposed() {\n\t\tthis.contextRunner.run(withCacheMetrics((cache, meterRegistry) -> {\n\t\t\tassertThat(meterRegistry.find(\"cache.size\").tags(TAGS).functionCounter()).isNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.gets\").tags(TAGS.and(\"result\", \"hit\")).functionCounter()).isNotNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.gets\").tags(TAGS.and(\"result\", \"miss\")).functionCounter()).isNotNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.gets\").tags(TAGS.and(\"result\", \"pending\")).functionCounter())\n\t\t\t\t.isNotNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.evictions\").tags(TAGS).functionCounter()).isNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.puts\").tags(TAGS).functionCounter()).isNotNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.removals\").tags(TAGS).functionCounter()).isNotNull();\n\t\t\tassertThat(meterRegistry.find(\"cache.lock.duration\").tags(TAGS).timeGauge()).isNotNull();\n\t\t}));\n\t}\n\n\t@Test\n\tvoid cacheHitsAreExposed() {\n\t\tthis.contextRunner.run(withCacheMetrics((cache, meterRegistry) -> {\n\t\t\tString key = UUID.randomUUID().toString();\n\t\t\tcache.put(key, \"test\");\n\n\t\t\tcache.get(key);\n\t\t\tcache.get(key);\n\t\t\tassertThat(meterRegistry.get(\"cache.gets\").tags(TAGS.and(\"result\", \"hit\")).functionCounter().count())\n\t\t\t\t.isEqualTo(2.0d);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid cacheMissesAreExposed() {\n\t\tthis.contextRunner.run(withCacheMetrics((cache, meterRegistry) -> {\n\t\t\tString key = UUID.randomUUID().toString();\n\t\t\tcache.get(key);\n\t\t\tcache.get(key);\n\t\t\tcache.get(key);\n\t\t\tassertThat(meterRegistry.get(\"cache.gets\").tags(TAGS.and(\"result\", \"miss\")).functionCounter().count())\n\t\t\t\t.isEqualTo(3.0d);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid cacheMetricsMatchCacheStatistics() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRedisCache cache = getTestCache(context);\n\t\t\tRedisCacheMetrics cacheMetrics = new RedisCacheMetrics(cache, TAGS);\n\t\t\tassertThat(cacheMetrics.hitCount()).isEqualTo(cache.getStatistics().getHits());\n\t\t\tassertThat(cacheMetrics.missCount()).isEqualTo(cache.getStatistics().getMisses());\n\t\t\tassertThat(cacheMetrics.putCount()).isEqualTo(cache.getStatistics().getPuts());\n\t\t\tassertThat(cacheMetrics.size()).isNull();\n\t\t\tassertThat(cacheMetrics.evictionCount()).isNull();\n\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> withCacheMetrics(\n\t\t\tBiConsumer<RedisCache, MeterRegistry> stats) {\n\t\treturn (context) -> {\n\t\t\tRedisCache cache = getTestCache(context);\n\t\t\tSimpleMeterRegistry meterRegistry = new SimpleMeterRegistry();\n\t\t\tnew RedisCacheMetrics(cache, Tags.of(\"app\", \"test\")).bindTo(meterRegistry);\n\t\t\tstats.accept(cache, meterRegistry);\n\t\t};\n\t}\n\n\tprivate RedisCache getTestCache(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(RedisCacheManager.class);\n\t\tRedisCacheManager cacheManager = context.getBean(RedisCacheManager.class);\n\t\tRedisCache cache = (RedisCache) cacheManager.getCache(\"test\");\n\t\tassertThat(cache).isNotNull();\n\t\treturn cache;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CachingConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/actuate/endpoint/CachesEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.actuate.endpoint;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose available {@link Cache caches}.\n *\n * @author Johannes Edmeier\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Endpoint(id = \"caches\")\npublic class CachesEndpoint {\n\n\tprivate final Map<String, CacheManager> cacheManagers;\n\n\t/**\n\t * Create a new endpoint with the {@link CacheManager} instances to use.\n\t * @param cacheManagers the cache managers to use, indexed by name\n\t */\n\tpublic CachesEndpoint(Map<String, CacheManager> cacheManagers) {\n\t\tthis.cacheManagers = new LinkedHashMap<>(cacheManagers);\n\t}\n\n\t/**\n\t * Return a {@link CachesDescriptor} of all available {@link Cache caches}.\n\t * @return a caches reports\n\t */\n\t@ReadOperation\n\tpublic CachesDescriptor caches() {\n\t\tMap<String, Map<String, CacheDescriptor>> descriptors = new LinkedHashMap<>();\n\t\tgetCacheEntries(matchAll(), matchAll()).forEach((entry) -> {\n\t\t\tString cacheName = entry.getName();\n\t\t\tString cacheManager = entry.getCacheManager();\n\t\t\tMap<String, CacheDescriptor> cacheManagerDescriptors = descriptors.computeIfAbsent(cacheManager,\n\t\t\t\t\t(key) -> new LinkedHashMap<>());\n\t\t\tcacheManagerDescriptors.put(cacheName, new CacheDescriptor(entry.getTarget()));\n\t\t});\n\t\tMap<String, CacheManagerDescriptor> cacheManagerDescriptors = new LinkedHashMap<>();\n\t\tdescriptors.forEach((name, entries) -> cacheManagerDescriptors.put(name, new CacheManagerDescriptor(entries)));\n\t\treturn new CachesDescriptor(cacheManagerDescriptors);\n\t}\n\n\t/**\n\t * Return a {@link CacheDescriptor} for the specified cache.\n\t * @param cache the name of the cache\n\t * @param cacheManager the name of the cacheManager (can be {@code null}\n\t * @return the descriptor of the cache or {@code null} if no such cache exists\n\t * @throws NonUniqueCacheException if more than one cache with that name exists and no\n\t * {@code cacheManager} was provided to identify a unique candidate\n\t */\n\t@ReadOperation\n\tpublic @Nullable CacheEntryDescriptor cache(@Selector String cache, @Nullable String cacheManager) {\n\t\treturn extractUniqueCacheEntry(cache, getCacheEntries((name) -> name.equals(cache), isNameMatch(cacheManager)));\n\t}\n\n\t/**\n\t * Clear all the available {@link Cache caches}.\n\t */\n\t@DeleteOperation\n\tpublic void clearCaches() {\n\t\tgetCacheEntries(matchAll(), matchAll()).forEach(this::clearCache);\n\t}\n\n\t/**\n\t * Clear the specific {@link Cache}.\n\t * @param cache the name of the cache\n\t * @param cacheManager the name of the cacheManager (can be {@code null} to match all)\n\t * @return {@code true} if the cache was cleared or {@code false} if no such cache\n\t * exists\n\t * @throws NonUniqueCacheException if more than one cache with that name exists and no\n\t * {@code cacheManager} was provided to identify a unique candidate\n\t */\n\t@DeleteOperation\n\tpublic boolean clearCache(@Selector String cache, @Nullable String cacheManager) {\n\t\tCacheEntryDescriptor entry = extractUniqueCacheEntry(cache,\n\t\t\t\tgetCacheEntries((name) -> name.equals(cache), isNameMatch(cacheManager)));\n\t\treturn (entry != null && clearCache(entry));\n\t}\n\n\tprivate List<CacheEntryDescriptor> getCacheEntries(Predicate<String> cacheNamePredicate,\n\t\t\tPredicate<String> cacheManagerNamePredicate) {\n\t\treturn this.cacheManagers.keySet()\n\t\t\t.stream()\n\t\t\t.filter(cacheManagerNamePredicate)\n\t\t\t.flatMap((cacheManagerName) -> getCacheEntries(cacheManagerName, cacheNamePredicate).stream())\n\t\t\t.toList();\n\t}\n\n\tprivate List<CacheEntryDescriptor> getCacheEntries(String cacheManagerName, Predicate<String> cacheNamePredicate) {\n\t\tCacheManager cacheManager = this.cacheManagers.get(cacheManagerName);\n\t\tAssert.state(cacheManager != null, \"'cacheManager' must not be null\");\n\t\treturn cacheManager.getCacheNames()\n\t\t\t.stream()\n\t\t\t.filter(cacheNamePredicate)\n\t\t\t.map(cacheManager::getCache)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.map((cache) -> new CacheEntryDescriptor(cache, cacheManagerName))\n\t\t\t.toList();\n\t}\n\n\tprivate @Nullable CacheEntryDescriptor extractUniqueCacheEntry(String cache, List<CacheEntryDescriptor> entries) {\n\t\tif (entries.size() > 1) {\n\t\t\tthrow new NonUniqueCacheException(cache,\n\t\t\t\t\tentries.stream().map(CacheEntryDescriptor::getCacheManager).distinct().toList());\n\t\t}\n\t\treturn (!entries.isEmpty() ? entries.get(0) : null);\n\t}\n\n\tprivate boolean clearCache(CacheEntryDescriptor entry) {\n\t\tString cacheName = entry.getName();\n\t\tString cacheManagerName = entry.getCacheManager();\n\t\tCacheManager cacheManager = this.cacheManagers.get(cacheManagerName);\n\t\tAssert.state(cacheManager != null, \"'cacheManager' must not be null\");\n\t\tCache cache = cacheManager.getCache(cacheName);\n\t\tif (cache != null) {\n\t\t\tcache.clear();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Predicate<String> isNameMatch(@Nullable String name) {\n\t\treturn (name != null) ? ((requested) -> requested.equals(name)) : matchAll();\n\t}\n\n\tprivate Predicate<String> matchAll() {\n\t\treturn (name) -> true;\n\t}\n\n\t/**\n\t * Description of the caches.\n\t */\n\tpublic static final class CachesDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<String, CacheManagerDescriptor> cacheManagers;\n\n\t\tpublic CachesDescriptor(Map<String, CacheManagerDescriptor> cacheManagers) {\n\t\t\tthis.cacheManagers = cacheManagers;\n\t\t}\n\n\t\tpublic Map<String, CacheManagerDescriptor> getCacheManagers() {\n\t\t\treturn this.cacheManagers;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link CacheManager}.\n\t */\n\tpublic static final class CacheManagerDescriptor {\n\n\t\tprivate final Map<String, CacheDescriptor> caches;\n\n\t\tpublic CacheManagerDescriptor(Map<String, CacheDescriptor> caches) {\n\t\t\tthis.caches = caches;\n\t\t}\n\n\t\tpublic Map<String, CacheDescriptor> getCaches() {\n\t\t\treturn this.caches;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link Cache}.\n\t */\n\tpublic static class CacheDescriptor implements OperationResponseBody {\n\n\t\tprivate final String target;\n\n\t\tpublic CacheDescriptor(String target) {\n\t\t\tthis.target = target;\n\t\t}\n\n\t\t/**\n\t\t * Return the fully qualified name of the native cache.\n\t\t * @return the fully qualified name of the native cache\n\t\t */\n\t\tpublic String getTarget() {\n\t\t\treturn this.target;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link Cache} entry.\n\t */\n\tpublic static final class CacheEntryDescriptor extends CacheDescriptor {\n\n\t\tprivate final String name;\n\n\t\tprivate final String cacheManager;\n\n\t\tpublic CacheEntryDescriptor(Cache cache, String cacheManager) {\n\t\t\tsuper(cache.getNativeCache().getClass().getName());\n\t\t\tthis.name = cache.getName();\n\t\t\tthis.cacheManager = cacheManager;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getCacheManager() {\n\t\t\treturn this.cacheManager;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/actuate/endpoint/CachesEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint.CacheEntryDescriptor;\n\n/**\n * {@link EndpointWebExtension @EndpointWebExtension} for the {@link CachesEndpoint}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@EndpointWebExtension(endpoint = CachesEndpoint.class)\npublic class CachesEndpointWebExtension {\n\n\tprivate final CachesEndpoint delegate;\n\n\tpublic CachesEndpointWebExtension(CachesEndpoint delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<CacheEntryDescriptor> cache(@Selector String cache, @Nullable String cacheManager) {\n\t\ttry {\n\t\t\tCacheEntryDescriptor entry = this.delegate.cache(cache, cacheManager);\n\t\t\tint status = (entry != null) ? WebEndpointResponse.STATUS_OK : WebEndpointResponse.STATUS_NOT_FOUND;\n\t\t\treturn new WebEndpointResponse<>(entry, status);\n\t\t}\n\t\tcatch (NonUniqueCacheException ex) {\n\t\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_BAD_REQUEST);\n\t\t}\n\t}\n\n\t@DeleteOperation\n\tpublic WebEndpointResponse<Void> clearCache(@Selector String cache, @Nullable String cacheManager) {\n\t\ttry {\n\t\t\tboolean cleared = this.delegate.clearCache(cache, cacheManager);\n\t\t\tint status = (cleared ? WebEndpointResponse.STATUS_NO_CONTENT : WebEndpointResponse.STATUS_NOT_FOUND);\n\t\t\treturn new WebEndpointResponse<>(status);\n\t\t}\n\t\tcatch (NonUniqueCacheException ex) {\n\t\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_BAD_REQUEST);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/actuate/endpoint/NonUniqueCacheException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.actuate.endpoint;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\n/**\n * Exception thrown when multiple caches exist with the same name.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class NonUniqueCacheException extends RuntimeException {\n\n\tprivate final String cacheName;\n\n\tprivate final Collection<String> cacheManagerNames;\n\n\tpublic NonUniqueCacheException(String cacheName, Collection<String> cacheManagerNames) {\n\t\tsuper(String.format(\"Multiple caches named %s found, specify the 'cacheManager' to use: %s\", cacheName,\n\t\t\t\tcacheManagerNames));\n\t\tthis.cacheName = cacheName;\n\t\tthis.cacheManagerNames = Collections.unmodifiableCollection(cacheManagerNames);\n\t}\n\n\tpublic String getCacheName() {\n\t\treturn this.cacheName;\n\t}\n\n\tpublic Collection<String> getCacheManagerNames() {\n\t\treturn this.cacheManagerNames;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for caches.\n */\n@NullMarked\npackage org.springframework.boot.cache.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/Cache2kBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.cache2k.Cache2kBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the default\n * setup for caches added to the manager through addCaches and for dynamically created\n * caches.\n *\n * @author Jens Wilke\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic interface Cache2kBuilderCustomizer {\n\n\t/**\n\t * Customize the default cache settings.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(Cache2kBuilder<?, ?> builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/Cache2kCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.function.Function;\n\nimport org.cache2k.Cache2kBuilder;\nimport org.cache2k.extra.spring.SpringCache2kCacheManager;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Cache2k cache configuration.\n *\n * @author Jens Wilke\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ Cache2kBuilder.class, SpringCache2kCacheManager.class })\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\nclass Cache2kCacheConfiguration {\n\n\t@Bean\n\tSpringCache2kCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,\n\t\t\tObjectProvider<Cache2kBuilderCustomizer> cache2kBuilderCustomizers) {\n\t\tSpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager();\n\t\tcacheManager.defaultSetup(configureDefaults(cache2kBuilderCustomizers));\n\t\tCollection<String> cacheNames = cacheProperties.getCacheNames();\n\t\tif (!CollectionUtils.isEmpty(cacheNames)) {\n\t\t\tcacheManager.setDefaultCacheNames(cacheNames);\n\t\t}\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n\tprivate Function<Cache2kBuilder<?, ?>, Cache2kBuilder<?, ?>> configureDefaults(\n\t\t\tObjectProvider<Cache2kBuilderCustomizer> cache2kBuilderCustomizers) {\n\t\treturn (builder) -> {\n\t\t\tcache2kBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CacheAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.cache.CacheType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration.CacheConfigurationImportSelector;\nimport org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration.CacheManagerEntityManagerFactoryDependsOnConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.interceptor.CacheAspectSupport;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the cache abstraction. Creates a\n * {@link CacheManager} if necessary when caching is enabled via\n * {@link EnableCaching @EnableCaching}.\n * <p>\n * Cache store can be auto-detected or specified explicitly through configuration.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see EnableCaching\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseAutoConfiguration\",\n\t\t\"org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration\",\n\t\t\"org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration\",\n\t\t\"org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\" })\n@ConditionalOnClass(CacheManager.class)\n@ConditionalOnBean(CacheAspectSupport.class)\n@ConditionalOnMissingBean(value = CacheManager.class, name = \"cacheResolver\")\n@EnableConfigurationProperties(CacheProperties.class)\n@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnConfiguration.class })\npublic final class CacheAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {\n\t\treturn new CacheManagerCustomizers(customizers.orderedStream().toList());\n\t}\n\n\t@Bean\n\tCacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,\n\t\t\tObjectProvider<CacheManager> cacheManager) {\n\t\treturn new CacheManagerValidator(cacheProperties, cacheManager);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ EntityManagerFactoryDependsOnPostProcessor.class,\n\t\t\tLocalContainerEntityManagerFactoryBean.class })\n\t@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)\n\t@Import(CacheManagerEntityManagerFactoryDependsOnPostProcessor.class)\n\tstatic class CacheManagerEntityManagerFactoryDependsOnConfiguration {\n\n\t}\n\n\tstatic class CacheManagerEntityManagerFactoryDependsOnPostProcessor\n\t\t\textends EntityManagerFactoryDependsOnPostProcessor {\n\n\t\tCacheManagerEntityManagerFactoryDependsOnPostProcessor() {\n\t\t\tsuper(\"cacheManager\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Bean used to validate that a CacheManager exists and provide a more meaningful\n\t * exception.\n\t */\n\tstatic class CacheManagerValidator implements InitializingBean {\n\n\t\tprivate final CacheProperties cacheProperties;\n\n\t\tprivate final ObjectProvider<CacheManager> cacheManager;\n\n\t\tCacheManagerValidator(CacheProperties cacheProperties, ObjectProvider<CacheManager> cacheManager) {\n\t\t\tthis.cacheProperties = cacheProperties;\n\t\t\tthis.cacheManager = cacheManager;\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterPropertiesSet() {\n\t\t\tAssert.state(this.cacheManager.getIfAvailable() != null,\n\t\t\t\t\t() -> \"No cache manager could be auto-configured, check your configuration (caching type is '\"\n\t\t\t\t\t\t\t+ this.cacheProperties.getType() + \"')\");\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ImportSelector} to add {@link CacheType} configuration classes.\n\t */\n\tstatic class CacheConfigurationImportSelector implements ImportSelector {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\tCacheType[] types = CacheType.values();\n\t\t\tString[] imports = new String[types.length];\n\t\t\tfor (int i = 0; i < types.length; i++) {\n\t\t\t\timports[i] = CacheConfigurations.getConfigurationClass(types[i]);\n\t\t\t}\n\t\t\treturn imports;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CacheCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.cache.CacheType;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * General cache condition used with all cache configuration classes.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass CacheCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tAssert.isInstanceOf(AnnotationMetadata.class, metadata);\n\t\treturn getOutcome(context, (AnnotationMetadata) metadata);\n\t}\n\n\tprivate ConditionOutcome getOutcome(ConditionContext context, AnnotationMetadata metadata) {\n\t\tString sourceClass = metadata.getClassName();\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Cache\", sourceClass);\n\t\tEnvironment environment = context.getEnvironment();\n\t\ttry {\n\t\t\tBindResult<CacheType> specified = Binder.get(environment).bind(\"spring.cache.type\", CacheType.class);\n\t\t\tif (!specified.isBound()) {\n\t\t\t\treturn ConditionOutcome.match(message.because(\"automatic cache type\"));\n\t\t\t}\n\t\t\tCacheType required = CacheConfigurations.getType(sourceClass);\n\t\t\tif (specified.get() == required) {\n\t\t\t\treturn ConditionOutcome.match(message.because(specified.get() + \" cache type\"));\n\t\t\t}\n\t\t}\n\t\tcatch (BindException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.because(\"unknown cache type\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CacheConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\n\nimport org.springframework.boot.autoconfigure.cache.CacheType;\nimport org.springframework.util.Assert;\n\n/**\n * Mappings between {@link CacheType} and {@code @Configuration}.\n *\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Sebastien Deleuze\n */\nfinal class CacheConfigurations {\n\n\tprivate static final Map<CacheType, String> MAPPINGS;\n\n\tstatic {\n\t\tMap<CacheType, String> mappings = new EnumMap<>(CacheType.class);\n\t\tmappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.CACHE2K, Cache2kCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName());\n\t\tmappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName());\n\t\tMAPPINGS = Collections.unmodifiableMap(mappings);\n\t}\n\n\tprivate CacheConfigurations() {\n\t}\n\n\tstatic String getConfigurationClass(CacheType cacheType) {\n\t\tString configurationClassName = MAPPINGS.get(cacheType);\n\t\tAssert.state(configurationClassName != null, () -> \"Unknown cache type \" + cacheType);\n\t\treturn configurationClassName;\n\t}\n\n\tstatic CacheType getType(String configurationClassName) {\n\t\tfor (Map.Entry<CacheType, String> entry : MAPPINGS.entrySet()) {\n\t\t\tif (entry.getValue().equals(configurationClassName)) {\n\t\t\t\treturn entry.getKey();\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Unknown configuration class \" + configurationClassName);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CacheManagerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.cache.CacheManager;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the cache\n * manager before it is fully initialized, in particular to tune its configuration.\n *\n * @param <T> the type of the {@link CacheManager}\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface CacheManagerCustomizer<T extends CacheManager> {\n\n\t/**\n\t * Customize the cache manager.\n\t * @param cacheManager the {@code CacheManager} to customize\n\t */\n\tvoid customize(T cacheManager);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CacheManagerCustomizers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.cache.CacheManager;\n\n/**\n * Invokes the available {@link CacheManagerCustomizer} instances in the context for a\n * given {@link CacheManager}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class CacheManagerCustomizers {\n\n\tprivate final List<CacheManagerCustomizer<?>> customizers;\n\n\tpublic CacheManagerCustomizers(@Nullable List<? extends CacheManagerCustomizer<?>> customizers) {\n\t\tthis.customizers = (customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList();\n\t}\n\n\t/**\n\t * Customize the specified {@link CacheManager}. Locates all\n\t * {@link CacheManagerCustomizer} beans able to handle the specified instance and\n\t * invoke {@link CacheManagerCustomizer#customize(CacheManager)} on them.\n\t * @param <T> the type of cache manager\n\t * @param cacheManager the cache manager to customize\n\t * @return the cache manager\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T extends CacheManager> T customize(T cacheManager) {\n\t\tLambdaSafe.callbacks(CacheManagerCustomizer.class, this.customizers, cacheManager)\n\t\t\t.withLogger(CacheManagerCustomizers.class)\n\t\t\t.invoke((customizer) -> customizer.customize(cacheManager));\n\t\treturn cacheManager;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CacheProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.cache.CacheType;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration properties for the cache abstraction.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Ryon Day\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.cache\")\npublic class CacheProperties {\n\n\t/**\n\t * Cache type. By default, auto-detected according to the environment.\n\t */\n\tprivate @Nullable CacheType type;\n\n\t/**\n\t * List of cache names to create if supported by the underlying cache manager.\n\t * Usually, this disables the ability to create additional caches on-the-fly.\n\t */\n\tprivate List<String> cacheNames = new ArrayList<>();\n\n\tprivate final Caffeine caffeine = new Caffeine();\n\n\tprivate final Couchbase couchbase = new Couchbase();\n\n\tprivate final Infinispan infinispan = new Infinispan();\n\n\tprivate final JCache jcache = new JCache();\n\n\tprivate final Redis redis = new Redis();\n\n\tpublic @Nullable CacheType getType() {\n\t\treturn this.type;\n\t}\n\n\tpublic void setType(@Nullable CacheType mode) {\n\t\tthis.type = mode;\n\t}\n\n\tpublic List<String> getCacheNames() {\n\t\treturn this.cacheNames;\n\t}\n\n\tpublic void setCacheNames(List<String> cacheNames) {\n\t\tthis.cacheNames = cacheNames;\n\t}\n\n\tpublic Caffeine getCaffeine() {\n\t\treturn this.caffeine;\n\t}\n\n\tpublic Couchbase getCouchbase() {\n\t\treturn this.couchbase;\n\t}\n\n\tpublic Infinispan getInfinispan() {\n\t\treturn this.infinispan;\n\t}\n\n\tpublic JCache getJcache() {\n\t\treturn this.jcache;\n\t}\n\n\tpublic Redis getRedis() {\n\t\treturn this.redis;\n\t}\n\n\t/**\n\t * Resolve the config location if set.\n\t * @param config the config resource\n\t * @return the location or {@code null} if it is not set\n\t * @throws IllegalArgumentException if the config attribute is set to an unknown\n\t * location\n\t */\n\tpublic @Nullable Resource resolveConfigLocation(@Nullable Resource config) {\n\t\tif (config != null) {\n\t\t\tAssert.isTrue(config.exists(),\n\t\t\t\t\t() -> \"'config' resource [%s] must exist\".formatted(config.getDescription()));\n\t\t\treturn config;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Caffeine specific cache properties.\n\t */\n\tpublic static class Caffeine {\n\n\t\t/**\n\t\t * The spec to use to create caches. See CaffeineSpec for more details on the spec\n\t\t * format.\n\t\t */\n\t\tprivate @Nullable String spec;\n\n\t\tpublic @Nullable String getSpec() {\n\t\t\treturn this.spec;\n\t\t}\n\n\t\tpublic void setSpec(@Nullable String spec) {\n\t\t\tthis.spec = spec;\n\t\t}\n\n\t}\n\n\t/**\n\t * Couchbase specific cache properties.\n\t */\n\tpublic static class Couchbase {\n\n\t\t/**\n\t\t * Entry expiration. By default the entries never expire. Note that this value is\n\t\t * ultimately converted to seconds.\n\t\t */\n\t\tprivate @Nullable Duration expiration;\n\n\t\tpublic @Nullable Duration getExpiration() {\n\t\t\treturn this.expiration;\n\t\t}\n\n\t\tpublic void setExpiration(@Nullable Duration expiration) {\n\t\t\tthis.expiration = expiration;\n\t\t}\n\n\t}\n\n\t/**\n\t * Infinispan specific cache properties.\n\t */\n\tpublic static class Infinispan {\n\n\t\t/**\n\t\t * The location of the configuration file to use to initialize Infinispan.\n\t\t */\n\t\tprivate @Nullable Resource config;\n\n\t\tpublic @Nullable Resource getConfig() {\n\t\t\treturn this.config;\n\t\t}\n\n\t\tpublic void setConfig(@Nullable Resource config) {\n\t\t\tthis.config = config;\n\t\t}\n\n\t}\n\n\t/**\n\t * JCache (JSR-107) specific cache properties.\n\t */\n\tpublic static class JCache {\n\n\t\t/**\n\t\t * The location of the configuration file to use to initialize the cache manager.\n\t\t * The configuration file is dependent of the underlying cache implementation.\n\t\t */\n\t\tprivate @Nullable Resource config;\n\n\t\t/**\n\t\t * Fully qualified name of the CachingProvider implementation to use to retrieve\n\t\t * the JSR-107 compliant cache manager. Needed only if more than one JSR-107\n\t\t * implementation is available on the classpath.\n\t\t */\n\t\tprivate @Nullable String provider;\n\n\t\tpublic @Nullable String getProvider() {\n\t\t\treturn this.provider;\n\t\t}\n\n\t\tpublic void setProvider(@Nullable String provider) {\n\t\t\tthis.provider = provider;\n\t\t}\n\n\t\tpublic @Nullable Resource getConfig() {\n\t\t\treturn this.config;\n\t\t}\n\n\t\tpublic void setConfig(@Nullable Resource config) {\n\t\t\tthis.config = config;\n\t\t}\n\n\t}\n\n\t/**\n\t * Redis-specific cache properties.\n\t */\n\tpublic static class Redis {\n\n\t\t/**\n\t\t * Entry expiration. By default the entries never expire.\n\t\t */\n\t\tprivate @Nullable Duration timeToLive;\n\n\t\t/**\n\t\t * Allow caching null values.\n\t\t */\n\t\tprivate boolean cacheNullValues = true;\n\n\t\t/**\n\t\t * Key prefix.\n\t\t */\n\t\tprivate @Nullable String keyPrefix;\n\n\t\t/**\n\t\t * Whether to use the key prefix when writing to Redis.\n\t\t */\n\t\tprivate boolean useKeyPrefix = true;\n\n\t\t/**\n\t\t * Whether to enable cache statistics.\n\t\t */\n\t\tprivate boolean enableStatistics;\n\n\t\tpublic @Nullable Duration getTimeToLive() {\n\t\t\treturn this.timeToLive;\n\t\t}\n\n\t\tpublic void setTimeToLive(@Nullable Duration timeToLive) {\n\t\t\tthis.timeToLive = timeToLive;\n\t\t}\n\n\t\tpublic boolean isCacheNullValues() {\n\t\t\treturn this.cacheNullValues;\n\t\t}\n\n\t\tpublic void setCacheNullValues(boolean cacheNullValues) {\n\t\t\tthis.cacheNullValues = cacheNullValues;\n\t\t}\n\n\t\tpublic @Nullable String getKeyPrefix() {\n\t\t\treturn this.keyPrefix;\n\t\t}\n\n\t\tpublic void setKeyPrefix(@Nullable String keyPrefix) {\n\t\t\tthis.keyPrefix = keyPrefix;\n\t\t}\n\n\t\tpublic boolean isUseKeyPrefix() {\n\t\t\treturn this.useKeyPrefix;\n\t\t}\n\n\t\tpublic void setUseKeyPrefix(boolean useKeyPrefix) {\n\t\t\tthis.useKeyPrefix = useKeyPrefix;\n\t\t}\n\n\t\tpublic boolean isEnableStatistics() {\n\t\t\treturn this.enableStatistics;\n\t\t}\n\n\t\tpublic void setEnableStatistics(boolean enableStatistics) {\n\t\t\tthis.enableStatistics = enableStatistics;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CachesEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpointWebExtension;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link CachesEndpoint}.\n *\n * @author Johannes Edmeier\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = CacheAutoConfiguration.class)\n@ConditionalOnClass({ CacheManager.class, ConditionalOnAvailableEndpoint.class })\n@ConditionalOnAvailableEndpoint(CachesEndpoint.class)\npublic final class CachesEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCachesEndpoint cachesEndpoint(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn new CachesEndpoint(\n\t\t\t\tSimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, CacheManager.class));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(CachesEndpoint.class)\n\t@ConditionalOnAvailableEndpoint(exposure = EndpointExposure.WEB)\n\tCachesEndpointWebExtension cachesEndpointWebExtension(CachesEndpoint cachesEndpoint) {\n\t\treturn new CachesEndpointWebExtension(cachesEndpoint);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CaffeineCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.List;\n\nimport com.github.benmanes.caffeine.cache.CacheLoader;\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport com.github.benmanes.caffeine.cache.CaffeineSpec;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.caffeine.CaffeineCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Caffeine cache configuration.\n *\n * @author Eddú Meléndez\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class })\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional({ CacheCondition.class })\nclass CaffeineCacheConfiguration {\n\n\t@Bean\n\tCaffeineCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,\n\t\t\tObjectProvider<Caffeine<Object, Object>> caffeine, ObjectProvider<CaffeineSpec> caffeineSpec,\n\t\t\tObjectProvider<CacheLoader<Object, Object>> cacheLoader) {\n\t\tCaffeineCacheManager cacheManager = createCacheManager(cacheProperties, caffeine, caffeineSpec, cacheLoader);\n\t\tList<String> cacheNames = cacheProperties.getCacheNames();\n\t\tif (!CollectionUtils.isEmpty(cacheNames)) {\n\t\t\tcacheManager.setCacheNames(cacheNames);\n\t\t}\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n\tprivate CaffeineCacheManager createCacheManager(CacheProperties cacheProperties,\n\t\t\tObjectProvider<Caffeine<Object, Object>> caffeine, ObjectProvider<CaffeineSpec> caffeineSpec,\n\t\t\tObjectProvider<CacheLoader<Object, Object>> cacheLoader) {\n\t\tCaffeineCacheManager cacheManager = new CaffeineCacheManager();\n\t\tsetCacheBuilder(cacheProperties, caffeineSpec.getIfAvailable(), caffeine.getIfAvailable(), cacheManager);\n\t\tcacheLoader.ifAvailable(cacheManager::setCacheLoader);\n\t\treturn cacheManager;\n\t}\n\n\tprivate void setCacheBuilder(CacheProperties cacheProperties, @Nullable CaffeineSpec caffeineSpec,\n\t\t\t@Nullable Caffeine<Object, Object> caffeine, CaffeineCacheManager cacheManager) {\n\t\tString specification = cacheProperties.getCaffeine().getSpec();\n\t\tif (StringUtils.hasText(specification)) {\n\t\t\tcacheManager.setCacheSpecification(specification);\n\t\t}\n\t\telse if (caffeineSpec != null) {\n\t\t\tcacheManager.setCaffeineSpec(caffeineSpec);\n\t\t}\n\t\telse if (caffeine != null) {\n\t\t\tcacheManager.setCaffeine(caffeine);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CouchbaseCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\n\nimport com.couchbase.client.java.Cluster;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.cache.autoconfigure.CacheProperties.Couchbase;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.CouchbaseClientFactory;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheManager;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Couchbase cache configuration.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class })\n@ConditionalOnMissingBean(CacheManager.class)\n@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)\n@Conditional(CacheCondition.class)\nclass CouchbaseCacheConfiguration {\n\n\t@Bean\n\tCouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers,\n\t\t\tObjectProvider<CouchbaseCacheManagerBuilderCustomizer> couchbaseCacheManagerBuilderCustomizers,\n\t\t\tCouchbaseClientFactory clientFactory) {\n\t\tList<String> cacheNames = cacheProperties.getCacheNames();\n\t\tCouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory);\n\t\tCouchbase couchbase = cacheProperties.getCouchbase();\n\t\torg.springframework.data.couchbase.cache.CouchbaseCacheConfiguration config = org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration\n\t\t\t.defaultCacheConfig();\n\t\tif (couchbase.getExpiration() != null) {\n\t\t\tconfig = config.entryExpiry(couchbase.getExpiration());\n\t\t}\n\t\tbuilder.cacheDefaults(config);\n\t\tif (!ObjectUtils.isEmpty(cacheNames)) {\n\t\t\tbuilder.initialCacheNames(new LinkedHashSet<>(cacheNames));\n\t\t}\n\t\tcouchbaseCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\tCouchbaseCacheManager cacheManager = builder.build();\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/CouchbaseCacheManagerBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.data.couchbase.cache.CouchbaseCacheManager;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link CouchbaseCacheManagerBuilder} to fine-tune its auto-configuration before it is\n * used to build the auto-configured {@link CouchbaseCacheManager}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface CouchbaseCacheManagerBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link CouchbaseCacheManagerBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(CouchbaseCacheManagerBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/GenericCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.support.SimpleCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Generic cache configuration based on arbitrary {@link Cache} instances defined in the\n * context.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBean(Cache.class)\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\nclass GenericCacheConfiguration {\n\n\t@Bean\n\tSimpleCacheManager cacheManager(CacheManagerCustomizers customizers, Collection<Cache> caches) {\n\t\tSimpleCacheManager cacheManager = new SimpleCacheManager();\n\t\tcacheManager.setCaches(caches);\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/HazelcastCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.spring.cache.HazelcastCacheManager;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastConfigResourceCondition;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Hazelcast cache configuration. Can either reuse the {@link HazelcastInstance} that has\n * been configured by the general {@link HazelcastAutoConfiguration} or create a separate\n * one if the {@code spring.cache.hazelcast.config} property has been set.\n * <p>\n * If the {@link HazelcastAutoConfiguration} has been disabled, an attempt to configure a\n * default {@link HazelcastInstance} is still made, using the same defaults.\n *\n * @author Stephane Nicoll\n * @see HazelcastConfigResourceCondition\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ HazelcastInstance.class, HazelcastCacheManager.class })\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\n@ConditionalOnSingleCandidate(HazelcastInstance.class)\nclass HazelcastCacheConfiguration {\n\n\t@Bean\n\tHazelcastCacheManager cacheManager(CacheManagerCustomizers customizers,\n\t\t\tHazelcastInstance existingHazelcastInstance) {\n\t\tHazelcastCacheManager cacheManager = new HazelcastCacheManager(existingHazelcastInstance);\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/HazelcastJCacheCustomizationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.Properties;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.Resource;\n\n/**\n * JCache customization for Hazelcast.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(HazelcastInstance.class)\nclass HazelcastJCacheCustomizationConfiguration {\n\n\t@Bean\n\tHazelcastPropertiesCustomizer hazelcastPropertiesCustomizer(ObjectProvider<HazelcastInstance> hazelcastInstance,\n\t\t\tCacheProperties cacheProperties) {\n\t\treturn new HazelcastPropertiesCustomizer(hazelcastInstance.getIfUnique(), cacheProperties);\n\t}\n\n\tstatic class HazelcastPropertiesCustomizer implements JCachePropertiesCustomizer {\n\n\t\tprivate final @Nullable HazelcastInstance hazelcastInstance;\n\n\t\tprivate final CacheProperties cacheProperties;\n\n\t\tHazelcastPropertiesCustomizer(@Nullable HazelcastInstance hazelcastInstance, CacheProperties cacheProperties) {\n\t\t\tthis.hazelcastInstance = hazelcastInstance;\n\t\t\tthis.cacheProperties = cacheProperties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(Properties properties) {\n\t\t\tResource configLocation = this.cacheProperties\n\t\t\t\t.resolveConfigLocation(this.cacheProperties.getJcache().getConfig());\n\t\t\tif (configLocation != null) {\n\t\t\t\t// Hazelcast does not use the URI as a mean to specify a custom config.\n\t\t\t\tproperties.setProperty(\"hazelcast.config.location\", toUri(configLocation).toString());\n\t\t\t}\n\t\t\telse if (this.hazelcastInstance != null) {\n\t\t\t\tproperties.put(\"hazelcast.instance.itself\", this.hazelcastInstance);\n\t\t\t}\n\t\t}\n\n\t\tprivate static URI toUri(Resource config) {\n\t\t\ttry {\n\t\t\t\treturn config.getURI();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Could not get URI from \" + config, ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/InfinispanCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\n\nimport org.infinispan.configuration.cache.ConfigurationBuilder;\nimport org.infinispan.manager.DefaultCacheManager;\nimport org.infinispan.manager.EmbeddedCacheManager;\nimport org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Infinispan cache configuration.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Raja Kolli\n * @since 4.0.0\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(SpringEmbeddedCacheManager.class)\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\npublic class InfinispanCacheConfiguration {\n\n\t@Bean\n\tpublic SpringEmbeddedCacheManager cacheManager(CacheManagerCustomizers customizers,\n\t\t\tEmbeddedCacheManager embeddedCacheManager) {\n\t\tSpringEmbeddedCacheManager cacheManager = new SpringEmbeddedCacheManager(embeddedCacheManager);\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n\t@Bean(destroyMethod = \"stop\")\n\t@ConditionalOnMissingBean\n\tpublic EmbeddedCacheManager infinispanCacheManager(CacheProperties cacheProperties,\n\t\t\tObjectProvider<ConfigurationBuilder> defaultConfigurationBuilder) throws IOException {\n\t\tEmbeddedCacheManager cacheManager = createEmbeddedCacheManager(cacheProperties);\n\t\tList<String> cacheNames = cacheProperties.getCacheNames();\n\t\tif (!CollectionUtils.isEmpty(cacheNames)) {\n\t\t\tcacheNames.forEach((cacheName) -> cacheManager.defineConfiguration(cacheName,\n\t\t\t\t\tgetDefaultCacheConfiguration(defaultConfigurationBuilder.getIfAvailable())));\n\t\t}\n\t\treturn cacheManager;\n\t}\n\n\tprivate EmbeddedCacheManager createEmbeddedCacheManager(CacheProperties cacheProperties) throws IOException {\n\t\tResource location = cacheProperties.resolveConfigLocation(cacheProperties.getInfinispan().getConfig());\n\t\tif (location != null) {\n\t\t\ttry (InputStream in = location.getInputStream()) {\n\t\t\t\treturn new DefaultCacheManager(in);\n\t\t\t}\n\t\t}\n\t\treturn new DefaultCacheManager();\n\t}\n\n\tprivate org.infinispan.configuration.cache.Configuration getDefaultCacheConfiguration(\n\t\t\t@Nullable ConfigurationBuilder defaultConfigurationBuilder) {\n\t\tif (defaultConfigurationBuilder != null) {\n\t\t\treturn defaultConfigurationBuilder.build();\n\t\t}\n\t\treturn new ConfigurationBuilder().build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/JCacheCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.cache.CacheManager;\nimport javax.cache.Caching;\nimport javax.cache.configuration.MutableConfiguration;\nimport javax.cache.spi.CachingProvider;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.cache.jcache.JCacheCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Cache configuration for JSR-107 compliant providers.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ Caching.class, JCacheCacheManager.class })\n@ConditionalOnMissingBean(org.springframework.cache.CacheManager.class)\n@Conditional({ CacheCondition.class, JCacheCacheConfiguration.JCacheAvailableCondition.class })\n@Import(HazelcastJCacheCustomizationConfiguration.class)\nclass JCacheCacheConfiguration implements BeanClassLoaderAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader beanClassLoader;\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.beanClassLoader = classLoader;\n\t}\n\n\t@Bean\n\tJCacheCacheManager cacheManager(CacheManagerCustomizers customizers, CacheManager jCacheCacheManager) {\n\t\tJCacheCacheManager cacheManager = new JCacheCacheManager(jCacheCacheManager);\n\t\treturn customizers.customize(cacheManager);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCacheManager jCacheCacheManager(CacheProperties cacheProperties,\n\t\t\tObjectProvider<javax.cache.configuration.Configuration<?, ?>> defaultCacheConfiguration,\n\t\t\tObjectProvider<JCacheManagerCustomizer> cacheManagerCustomizers,\n\t\t\tObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {\n\t\tCacheManager jCacheCacheManager = createCacheManager(cacheProperties, cachePropertiesCustomizers);\n\t\tList<String> cacheNames = cacheProperties.getCacheNames();\n\t\tif (!CollectionUtils.isEmpty(cacheNames)) {\n\t\t\tfor (String cacheName : cacheNames) {\n\t\t\t\tjCacheCacheManager.createCache(cacheName,\n\t\t\t\t\t\tdefaultCacheConfiguration.getIfAvailable(MutableConfiguration::new));\n\t\t\t}\n\t\t}\n\t\tcacheManagerCustomizers.orderedStream().forEach((customizer) -> customizer.customize(jCacheCacheManager));\n\t\treturn jCacheCacheManager;\n\t}\n\n\tprivate CacheManager createCacheManager(CacheProperties cacheProperties,\n\t\t\tObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) throws IOException {\n\t\tCachingProvider cachingProvider = getCachingProvider(cacheProperties.getJcache().getProvider());\n\t\tProperties properties = createCacheManagerProperties(cachePropertiesCustomizers);\n\t\tResource configLocation = cacheProperties.resolveConfigLocation(cacheProperties.getJcache().getConfig());\n\t\tif (configLocation != null) {\n\t\t\treturn cachingProvider.getCacheManager(configLocation.getURI(), this.beanClassLoader, properties);\n\t\t}\n\t\treturn cachingProvider.getCacheManager(null, this.beanClassLoader, properties);\n\t}\n\n\tprivate CachingProvider getCachingProvider(@Nullable String cachingProviderFqn) {\n\t\tif (StringUtils.hasText(cachingProviderFqn)) {\n\t\t\treturn Caching.getCachingProvider(cachingProviderFqn);\n\t\t}\n\t\treturn Caching.getCachingProvider();\n\t}\n\n\tprivate Properties createCacheManagerProperties(\n\t\t\tObjectProvider<JCachePropertiesCustomizer> cachePropertiesCustomizers) {\n\t\tProperties properties = new Properties();\n\t\tcachePropertiesCustomizers.orderedStream().forEach((customizer) -> customizer.customize(properties));\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Determine if JCache is available. This either kicks in if a provider is available\n\t * as defined per {@link JCacheProviderAvailableCondition} or if a\n\t * {@link CacheManager} has already been defined.\n\t */\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class JCacheAvailableCondition extends AnyNestedCondition {\n\n\t\tJCacheAvailableCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@Conditional(JCacheProviderAvailableCondition.class)\n\t\tstatic class JCacheProvider {\n\n\t\t}\n\n\t\t@ConditionalOnSingleCandidate(CacheManager.class)\n\t\tstatic class CustomJCacheCacheManager {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Determine if a JCache provider is available. This either kicks in if a default\n\t * {@link CachingProvider} has been found or if the property referring to the provider\n\t * to use has been set.\n\t */\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class JCacheProviderAvailableCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"JCache\");\n\t\t\tString providerProperty = \"spring.cache.jcache.provider\";\n\t\t\tif (context.getEnvironment().containsProperty(providerProperty)) {\n\t\t\t\treturn ConditionOutcome.match(message.because(\"JCache provider specified\"));\n\t\t\t}\n\t\t\tIterator<CachingProvider> providers = Caching.getCachingProviders().iterator();\n\t\t\tif (!providers.hasNext()) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"JSR-107 provider\").atAll());\n\t\t\t}\n\t\t\tproviders.next();\n\t\t\tif (providers.hasNext()) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.foundExactly(\"multiple JSR-107 providers\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"single JSR-107 provider\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/JCacheManagerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport javax.cache.CacheManager;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the cache\n * manager before it is used, in particular to create additional caches.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface JCacheManagerCustomizer {\n\n\t/**\n\t * Customize the cache manager.\n\t * @param cacheManager the {@code javax.cache.CacheManager} to customize\n\t */\n\tvoid customize(CacheManager cacheManager);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/JCachePropertiesCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.Properties;\n\nimport javax.cache.CacheManager;\nimport javax.cache.spi.CachingProvider;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the properties\n * used by the {@link CachingProvider} to create the {@link CacheManager}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see CachingProvider#getCacheManager(java.net.URI, ClassLoader, Properties)\n */\npublic interface JCachePropertiesCustomizer {\n\n\t/**\n\t * Customize the properties.\n\t * @param properties the current properties\n\t */\n\tvoid customize(Properties properties);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/NoOpCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.support.NoOpCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * No-op cache configuration used to disable caching through configuration.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\nclass NoOpCacheConfiguration {\n\n\t@Bean\n\tNoOpCacheManager cacheManager() {\n\t\treturn new NoOpCacheManager();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/RedisCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cache.autoconfigure.CacheProperties.Redis;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;\nimport org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;\n\n/**\n * Redis cache configuration.\n *\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Ryon Day\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(RedisConnectionFactory.class)\n@AutoConfigureAfter(name = \"org.springframework.boot.data.redis.autoconfigure.RedisAutoConfiguration\")\n@ConditionalOnBean(RedisConnectionFactory.class)\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\nclass RedisCacheConfiguration {\n\n\t@Bean\n\tRedisCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers,\n\t\t\tObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,\n\t\t\tObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,\n\t\t\tRedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {\n\t\tRedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory)\n\t\t\t.cacheDefaults(\n\t\t\t\t\tdetermineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));\n\t\tList<String> cacheNames = cacheProperties.getCacheNames();\n\t\tif (!cacheNames.isEmpty()) {\n\t\t\tbuilder.initialCacheNames(new LinkedHashSet<>(cacheNames));\n\t\t}\n\t\tif (cacheProperties.getRedis().isEnableStatistics()) {\n\t\t\tbuilder.enableStatistics();\n\t\t}\n\t\tredisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn cacheManagerCustomizers.customize(builder.build());\n\t}\n\n\tprivate org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(\n\t\t\tCacheProperties cacheProperties,\n\t\t\tObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,\n\t\t\t@Nullable ClassLoader classLoader) {\n\t\treturn redisCacheConfiguration.getIfAvailable(() -> createConfiguration(cacheProperties, classLoader));\n\t}\n\n\tprivate org.springframework.data.redis.cache.RedisCacheConfiguration createConfiguration(\n\t\t\tCacheProperties cacheProperties, @Nullable ClassLoader classLoader) {\n\t\tRedis redisProperties = cacheProperties.getRedis();\n\t\torg.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration\n\t\t\t.defaultCacheConfig();\n\t\tconfig = config\n\t\t\t.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));\n\t\tif (redisProperties.getTimeToLive() != null) {\n\t\t\tconfig = config.entryTtl(redisProperties.getTimeToLive());\n\t\t}\n\t\tif (redisProperties.getKeyPrefix() != null) {\n\t\t\tconfig = config.prefixCacheNameWith(redisProperties.getKeyPrefix());\n\t\t}\n\t\tif (!redisProperties.isCacheNullValues()) {\n\t\t\tconfig = config.disableCachingNullValues();\n\t\t}\n\t\tif (!redisProperties.isUseKeyPrefix()) {\n\t\t\tconfig = config.disableKeyPrefix();\n\t\t}\n\t\treturn config;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/RedisCacheManagerBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.springframework.data.redis.cache.RedisCacheManager.RedisCacheManagerBuilder;\n\n/**\n * Callback interface that can be used to customize a {@link RedisCacheManagerBuilder}.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RedisCacheManagerBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link RedisCacheManagerBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(RedisCacheManagerBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/SimpleCacheConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Simplest cache configuration, usually used as a fallback.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(CacheManager.class)\n@Conditional(CacheCondition.class)\nclass SimpleCacheConfiguration {\n\n\t@Bean\n\tConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,\n\t\t\tCacheManagerCustomizers cacheManagerCustomizers) {\n\t\tConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();\n\t\tList<String> cacheNames = cacheProperties.getCacheNames();\n\t\tif (!cacheNames.isEmpty()) {\n\t\t\tcacheManager.setCacheNames(cacheNames);\n\t\t}\n\t\treturn cacheManagerCustomizers.customize(cacheManager);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/metrics/CacheMeterBinderProvidersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure.metrics;\n\nimport com.hazelcast.core.Hazelcast;\nimport com.hazelcast.spring.cache.HazelcastCache;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.cache2k.Cache2kBuilder;\nimport org.cache2k.extra.micrometer.Cache2kCacheMetrics;\nimport org.cache2k.extra.spring.SpringCache2kCache;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cache.metrics.Cache2kCacheMeterBinderProvider;\nimport org.springframework.boot.cache.metrics.CacheMeterBinderProvider;\nimport org.springframework.boot.cache.metrics.CaffeineCacheMeterBinderProvider;\nimport org.springframework.boot.cache.metrics.HazelcastCacheMeterBinderProvider;\nimport org.springframework.boot.cache.metrics.JCacheCacheMeterBinderProvider;\nimport org.springframework.boot.cache.metrics.RedisCacheMeterBinderProvider;\nimport org.springframework.cache.caffeine.CaffeineCache;\nimport org.springframework.cache.jcache.JCacheCache;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.cache.RedisCache;\n\n/**\n * Configure {@link CacheMeterBinderProvider} beans.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ MeterBinder.class, CacheMeterBinderProvider.class })\nclass CacheMeterBinderProvidersConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ Cache2kBuilder.class, SpringCache2kCache.class, Cache2kCacheMetrics.class })\n\tstatic class Cache2kCacheMeterBinderProviderConfiguration {\n\n\t\t@Bean\n\t\tCache2kCacheMeterBinderProvider cache2kCacheMeterBinderProvider() {\n\t\t\treturn new Cache2kCacheMeterBinderProvider();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ CaffeineCache.class, com.github.benmanes.caffeine.cache.Cache.class })\n\tstatic class CaffeineCacheMeterBinderProviderConfiguration {\n\n\t\t@Bean\n\t\tCaffeineCacheMeterBinderProvider caffeineCacheMeterBinderProvider() {\n\t\t\treturn new CaffeineCacheMeterBinderProvider();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ HazelcastCache.class, Hazelcast.class })\n\tstatic class HazelcastCacheMeterBinderProviderConfiguration {\n\n\t\t@Bean\n\t\tHazelcastCacheMeterBinderProvider hazelcastCacheMeterBinderProvider() {\n\t\t\treturn new HazelcastCacheMeterBinderProvider();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ JCacheCache.class, javax.cache.CacheManager.class })\n\t@ConditionalOnMissingBean(JCacheCacheMeterBinderProvider.class)\n\tstatic class JCacheCacheMeterBinderProviderConfiguration {\n\n\t\t@Bean\n\t\tJCacheCacheMeterBinderProvider jCacheCacheMeterBinderProvider() {\n\t\t\treturn new JCacheCacheMeterBinderProvider();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(RedisCache.class)\n\tstatic class RedisCacheMeterBinderProviderConfiguration {\n\n\t\t@Bean\n\t\tRedisCacheMeterBinderProvider redisCacheMeterBinderProvider() {\n\t\t\treturn new RedisCacheMeterBinderProvider();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/metrics/CacheMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available\n * {@link Cache caches}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = { CacheAutoConfiguration.class },\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnBean(CacheManager.class)\n@ConditionalOnClass(MeterRegistry.class)\n@Import({ CacheMeterBinderProvidersConfiguration.class, CacheMetricsRegistrarConfiguration.class })\npublic final class CacheMetricsAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/metrics/CacheMetricsRegistrarConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure.metrics;\n\nimport java.util.Collection;\nimport java.util.Map;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.cache.metrics.CacheMeterBinderProvider;\nimport org.springframework.boot.cache.metrics.CacheMetricsRegistrar;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configure a {@link CacheMetricsRegistrar} and register all available {@link Cache\n * caches}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBean({ CacheMeterBinderProvider.class, MeterRegistry.class })\nclass CacheMetricsRegistrarConfiguration {\n\n\tprivate static final String CACHE_MANAGER_SUFFIX = \"cacheManager\";\n\n\tprivate final MeterRegistry registry;\n\n\tprivate final CacheMetricsRegistrar cacheMetricsRegistrar;\n\n\tprivate final Map<String, CacheManager> cacheManagers;\n\n\tCacheMetricsRegistrarConfiguration(MeterRegistry registry, Collection<CacheMeterBinderProvider<?>> binderProviders,\n\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\tthis.registry = registry;\n\t\tthis.cacheManagers = SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, CacheManager.class);\n\t\tthis.cacheMetricsRegistrar = new CacheMetricsRegistrar(this.registry, binderProviders);\n\t\tbindCachesToRegistry();\n\t}\n\n\t@Bean\n\tCacheMetricsRegistrar cacheMetricsRegistrar() {\n\t\treturn this.cacheMetricsRegistrar;\n\t}\n\n\tprivate void bindCachesToRegistry() {\n\t\tthis.cacheManagers.forEach(this::bindCacheManagerToRegistry);\n\t}\n\n\tprivate void bindCacheManagerToRegistry(String beanName, CacheManager cacheManager) {\n\t\tcacheManager.getCacheNames().forEach((cacheName) -> {\n\t\t\tCache cache = cacheManager.getCache(cacheName);\n\t\t\tAssert.state(cache != null, () -> \"'cache' must not be null. 'cacheName' is '%s'\".formatted(cacheName));\n\t\t\tbindCacheToRegistry(beanName, cache);\n\t\t});\n\t}\n\n\tprivate void bindCacheToRegistry(String beanName, Cache cache) {\n\t\tTag cacheManagerTag = Tag.of(\"cache.manager\", getCacheManagerName(beanName));\n\t\tthis.cacheMetricsRegistrar.bindCacheToRegistry(cache, cacheManagerTag);\n\t}\n\n\t/**\n\t * Get the name of a {@link CacheManager} based on its {@code beanName}.\n\t * @param beanName the name of the {@link CacheManager} bean\n\t * @return a name for the given cache manager\n\t */\n\tprivate String getCacheManagerName(String beanName) {\n\t\tif (beanName.length() > CACHE_MANAGER_SUFFIX.length()\n\t\t\t\t&& StringUtils.endsWithIgnoreCase(beanName, CACHE_MANAGER_SUFFIX)) {\n\t\t\treturn beanName.substring(0, beanName.length() - CACHE_MANAGER_SUFFIX.length());\n\t\t}\n\t\treturn beanName;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for the cache abstraction metrics.\n */\n@NullMarked\npackage org.springframework.boot.cache.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for the cache abstraction.\n */\n@NullMarked\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/Cache2kCacheMeterBinderProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.cache2k.extra.micrometer.Cache2kCacheMetrics;\nimport org.cache2k.extra.spring.SpringCache2kCache;\n\n/**\n * {@link CacheMeterBinderProvider} implementation for cache2k.\n *\n * @author Jens Wilke\n * @since 4.0.0\n */\npublic class Cache2kCacheMeterBinderProvider implements CacheMeterBinderProvider<SpringCache2kCache> {\n\n\t@Override\n\tpublic MeterBinder getMeterBinder(SpringCache2kCache cache, Iterable<Tag> tags) {\n\t\treturn new Cache2kCacheMetrics(cache.getNativeCache(), tags);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/CacheMeterBinderProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.cache.Cache;\n\n/**\n * Provide a {@link MeterBinder} based on a {@link Cache}.\n *\n * @param <C> the cache type\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface CacheMeterBinderProvider<C extends Cache> {\n\n\t/**\n\t * Return the {@link MeterBinder} managing the specified {@link Cache} or {@code null}\n\t * if the specified {@link Cache} is not supported.\n\t * @param cache the cache to instrument\n\t * @param tags tags to apply to all recorded metrics\n\t * @return a {@link MeterBinder} handling the specified {@link Cache} or {@code null}\n\t */\n\t@Nullable MeterBinder getMeterBinder(C cache, Iterable<Tag> tags);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/CacheMetricsRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.Collection;\nimport java.util.Objects;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.transaction.TransactionAwareCacheDecorator;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Register supported {@link Cache} to a {@link MeterRegistry}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class CacheMetricsRegistrar {\n\n\tprivate final MeterRegistry registry;\n\n\tprivate final Collection<CacheMeterBinderProvider<?>> binderProviders;\n\n\t/**\n\t * Creates a new registrar.\n\t * @param registry the {@link MeterRegistry} to use\n\t * @param binderProviders the {@link CacheMeterBinderProvider} instances that should\n\t * be used to detect compatible caches\n\t */\n\tpublic CacheMetricsRegistrar(MeterRegistry registry, Collection<CacheMeterBinderProvider<?>> binderProviders) {\n\t\tthis.registry = registry;\n\t\tthis.binderProviders = binderProviders;\n\t}\n\n\t/**\n\t * Attempt to bind the specified {@link Cache} to the registry. Return {@code true} if\n\t * the cache is supported and was bound to the registry, {@code false} otherwise.\n\t * @param cache the cache to handle\n\t * @param tags the tags to associate with the metrics of that cache\n\t * @return {@code true} if the {@code cache} is supported and was registered\n\t */\n\tpublic boolean bindCacheToRegistry(Cache cache, Tag... tags) {\n\t\tMeterBinder meterBinder = getMeterBinder(unwrapIfNecessary(cache), Tags.of(tags));\n\t\tif (meterBinder != null) {\n\t\t\tmeterBinder.bindTo(this.registry);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// Lambda isn't detected with the correct nullability\n\t@SuppressWarnings({ \"unchecked\", \"NullAway\" })\n\tprivate @Nullable MeterBinder getMeterBinder(Cache cache, Tags tags) {\n\t\tTags cacheTags = tags.and(getAdditionalTags(cache));\n\t\treturn LambdaSafe.callbacks(CacheMeterBinderProvider.class, this.binderProviders, cache)\n\t\t\t.withLogger(CacheMetricsRegistrar.class)\n\t\t\t.invokeAnd((binderProvider) -> binderProvider.getMeterBinder(cache, cacheTags))\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t/**\n\t * Return additional {@link Tag tags} to be associated with the given {@link Cache}.\n\t * @param cache the cache\n\t * @return a list of additional tags to associate to that {@code cache}.\n\t */\n\tprotected Iterable<Tag> getAdditionalTags(Cache cache) {\n\t\treturn Tags.of(\"name\", cache.getName());\n\t}\n\n\tprivate Cache unwrapIfNecessary(Cache cache) {\n\t\tif (ClassUtils.isPresent(\"org.springframework.cache.transaction.TransactionAwareCacheDecorator\",\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\treturn TransactionAwareCacheDecoratorHandler.unwrapIfNecessary(cache);\n\t\t}\n\t\treturn cache;\n\t}\n\n\tprivate static final class TransactionAwareCacheDecoratorHandler {\n\n\t\tprivate static Cache unwrapIfNecessary(Cache cache) {\n\t\t\ttry {\n\t\t\t\tif (cache instanceof TransactionAwareCacheDecorator decorator) {\n\t\t\t\t\treturn decorator.getTargetCache();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (NoClassDefFoundError ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\treturn cache;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/CaffeineCacheMeterBinderProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.cache.CaffeineCacheMetrics;\n\nimport org.springframework.cache.caffeine.CaffeineCache;\n\n/**\n * {@link CacheMeterBinderProvider} implementation for Caffeine.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class CaffeineCacheMeterBinderProvider implements CacheMeterBinderProvider<CaffeineCache> {\n\n\t@Override\n\tpublic MeterBinder getMeterBinder(CaffeineCache cache, Iterable<Tag> tags) {\n\t\treturn new CaffeineCacheMetrics<>(cache.getNativeCache(), cache.getName(), tags);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/HazelcastCacheMeterBinderProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\n\nimport com.hazelcast.spring.cache.HazelcastCache;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.cache.metrics.HazelcastCacheMeterBinderProvider.HazelcastCacheMeterBinderProviderRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link CacheMeterBinderProvider} implementation for Hazelcast.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ImportRuntimeHints(HazelcastCacheMeterBinderProviderRuntimeHints.class)\npublic class HazelcastCacheMeterBinderProvider implements CacheMeterBinderProvider<HazelcastCache> {\n\n\t@Override\n\tpublic MeterBinder getMeterBinder(HazelcastCache cache, Iterable<Tag> tags) {\n\t\ttry {\n\t\t\treturn new HazelcastCacheMetrics(cache.getNativeCache(), tags);\n\t\t}\n\t\tcatch (NoSuchMethodError ex) {\n\t\t\t// Hazelcast 4\n\t\t\treturn createHazelcast4CacheMetrics(cache, tags);\n\t\t}\n\t}\n\n\tprivate MeterBinder createHazelcast4CacheMetrics(HazelcastCache cache, Iterable<Tag> tags) {\n\t\ttry {\n\t\t\tMethod nativeCacheAccessor = ReflectionUtils.findMethod(HazelcastCache.class, \"getNativeCache\");\n\t\t\tAssert.state(nativeCacheAccessor != null, \"'nativeCacheAccessor' must not be null\");\n\t\t\tObject nativeCache = ReflectionUtils.invokeMethod(nativeCacheAccessor, cache);\n\t\t\treturn HazelcastCacheMetrics.class.getConstructor(Object.class, Iterable.class)\n\t\t\t\t.newInstance(nativeCache, tags);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to create MeterBinder for Hazelcast\", ex);\n\t\t}\n\t}\n\n\tstatic class HazelcastCacheMeterBinderProviderRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\ttry {\n\t\t\t\tMethod getNativeCacheMethod = ReflectionUtils.findMethod(HazelcastCache.class, \"getNativeCache\");\n\t\t\t\tAssert.state(getNativeCacheMethod != null, \"Unable to find 'getNativeCache' method\");\n\t\t\t\tConstructor<?> constructor = HazelcastCacheMetrics.class.getConstructor(Object.class, Iterable.class);\n\t\t\t\thints.reflection()\n\t\t\t\t\t.registerMethod(getNativeCacheMethod, ExecutableMode.INVOKE)\n\t\t\t\t\t.registerConstructor(constructor, ExecutableMode.INVOKE);\n\t\t\t}\n\t\t\tcatch (NoSuchMethodException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/JCacheCacheMeterBinderProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport io.micrometer.core.instrument.FunctionCounter;\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.cache.JCacheMetrics;\n\nimport org.springframework.cache.jcache.JCacheCache;\n\n/**\n * {@link CacheMeterBinderProvider} implementation for JCache.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class JCacheCacheMeterBinderProvider implements CacheMeterBinderProvider<JCacheCache> {\n\n\tprivate final boolean registerCacheRemovalsAsFunctionCounter;\n\n\t/**\n\t * Creates a {@code JCacheCacheMeterBinderProvider} that registers cache removals as a\n\t * {@link Gauge}.\n\t */\n\tpublic JCacheCacheMeterBinderProvider() {\n\t\tthis(false);\n\t}\n\n\t/**\n\t * Creates a {@code JCacheCacheMeterBinderProvider} that registers cache removals with\n\t * a meter type that depends on the value of\n\t * {@code registerCacheRemovalsAsFunctionCounter}. When {@code false}, cache removals\n\t * are registered as a {@link Gauge}. When {@code true}, cache removals are registered\n\t * as a {@link FunctionCounter}.\n\t * @param registerCacheRemovalsAsFunctionCounter whether to register removals as a\n\t * gauge or a function counter\n\t * @since 3.4.12\n\t */\n\tpublic JCacheCacheMeterBinderProvider(boolean registerCacheRemovalsAsFunctionCounter) {\n\t\tthis.registerCacheRemovalsAsFunctionCounter = registerCacheRemovalsAsFunctionCounter;\n\t}\n\n\t@Override\n\tpublic MeterBinder getMeterBinder(JCacheCache cache, Iterable<Tag> tags) {\n\t\treturn new JCacheMetrics<>(cache.getNativeCache(), tags, this.registerCacheRemovalsAsFunctionCounter);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/RedisCacheMeterBinderProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\n\nimport org.springframework.data.redis.cache.RedisCache;\n\n/**\n * {@link CacheMeterBinderProvider} implementation for Redis.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class RedisCacheMeterBinderProvider implements CacheMeterBinderProvider<RedisCache> {\n\n\t@Override\n\tpublic MeterBinder getMeterBinder(RedisCache cache, Iterable<Tag> tags) {\n\t\treturn new RedisCacheMetrics(cache, tags);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/RedisCacheMetrics.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.FunctionCounter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.TimeGauge;\nimport io.micrometer.core.instrument.binder.cache.CacheMeterBinder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.redis.cache.RedisCache;\n\n/**\n * {@link CacheMeterBinder} for {@link RedisCache}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class RedisCacheMetrics extends CacheMeterBinder<RedisCache> {\n\n\tprivate final RedisCache cache;\n\n\tpublic RedisCacheMetrics(RedisCache cache, Iterable<Tag> tags) {\n\t\tsuper(cache, cache.getName(), tags);\n\t\tthis.cache = cache;\n\t}\n\n\t@Override\n\tprotected @Nullable Long size() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected long hitCount() {\n\t\treturn this.cache.getStatistics().getHits();\n\t}\n\n\t@Override\n\tprotected Long missCount() {\n\t\treturn this.cache.getStatistics().getMisses();\n\t}\n\n\t@Override\n\tprotected @Nullable Long evictionCount() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected long putCount() {\n\t\treturn this.cache.getStatistics().getPuts();\n\t}\n\n\t@Override\n\tprotected void bindImplementationSpecificMetrics(MeterRegistry registry) {\n\t\tFunctionCounter.builder(\"cache.removals\", this.cache, (cache) -> cache.getStatistics().getDeletes())\n\t\t\t.tags(getTagsWithCacheName())\n\t\t\t.description(\"Cache removals\")\n\t\t\t.register(registry);\n\t\tFunctionCounter.builder(\"cache.gets\", this.cache, (cache) -> cache.getStatistics().getPending())\n\t\t\t.tags(getTagsWithCacheName())\n\t\t\t.tag(\"result\", \"pending\")\n\t\t\t.description(\"The number of pending requests\")\n\t\t\t.register(registry);\n\t\tTimeGauge\n\t\t\t.builder(\"cache.lock.duration\", this.cache, TimeUnit.NANOSECONDS,\n\t\t\t\t\t(cache) -> cache.getStatistics().getLockWaitDuration(TimeUnit.NANOSECONDS))\n\t\t\t.tags(getTagsWithCacheName())\n\t\t\t.description(\"The time the cache has spent waiting on a lock\")\n\t\t\t.register(registry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/java/org/springframework/boot/cache/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Metrics for caches.\n */\n@NullMarked\npackage org.springframework.boot.cache.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [],\n  \"hints\": [\n    {\n      \"name\": \"spring.cache.jcache.provider\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"javax.cache.spi.CachingProvider\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration\norg.springframework.boot.cache.autoconfigure.CachesEndpointAutoConfiguration\norg.springframework.boot.cache.autoconfigure.metrics.CacheMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/actuate/endpoint/CachesEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint.CacheDescriptor;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint.CacheEntryDescriptor;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint.CacheManagerDescriptor;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.cache.support.SimpleCacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link CachesEndpoint}.\n *\n * @author Stephane Nicoll\n */\nclass CachesEndpointTests {\n\n\t@Test\n\tvoid allCachesWithSingleCacheManager() {\n\t\tCachesEndpoint endpoint = new CachesEndpoint(\n\t\t\t\tCollections.singletonMap(\"test\", new ConcurrentMapCacheManager(\"a\", \"b\")));\n\t\tMap<String, CacheManagerDescriptor> allDescriptors = endpoint.caches().getCacheManagers();\n\t\tassertThat(allDescriptors).containsOnlyKeys(\"test\");\n\t\tCacheManagerDescriptor descriptors = allDescriptors.get(\"test\");\n\t\tassertThat(descriptors).isNotNull();\n\t\tassertThat(descriptors.getCaches()).containsOnlyKeys(\"a\", \"b\");\n\t\tCacheDescriptor a = descriptors.getCaches().get(\"a\");\n\t\tassertThat(a).isNotNull();\n\t\tassertThat(a.getTarget()).isEqualTo(ConcurrentHashMap.class.getName());\n\t\tCacheDescriptor b = descriptors.getCaches().get(\"b\");\n\t\tassertThat(b).isNotNull();\n\t\tassertThat(b.getTarget()).isEqualTo(ConcurrentHashMap.class.getName());\n\t}\n\n\t@Test\n\tvoid allCachesWithSeveralCacheManagers() {\n\t\tMap<String, CacheManager> cacheManagers = new LinkedHashMap<>();\n\t\tcacheManagers.put(\"test\", new ConcurrentMapCacheManager(\"a\", \"b\"));\n\t\tcacheManagers.put(\"another\", new ConcurrentMapCacheManager(\"a\", \"c\"));\n\t\tCachesEndpoint endpoint = new CachesEndpoint(cacheManagers);\n\t\tMap<String, CacheManagerDescriptor> allDescriptors = endpoint.caches().getCacheManagers();\n\t\tassertThat(allDescriptors).containsOnlyKeys(\"test\", \"another\");\n\t\tCacheManagerDescriptor test = allDescriptors.get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tassertThat(test.getCaches()).containsOnlyKeys(\"a\", \"b\");\n\t\tCacheManagerDescriptor another = allDescriptors.get(\"another\");\n\t\tassertThat(another).isNotNull();\n\t\tassertThat(another.getCaches()).containsOnlyKeys(\"a\", \"c\");\n\t}\n\n\t@Test\n\tvoid namedCacheWithSingleCacheManager() {\n\t\tCachesEndpoint endpoint = new CachesEndpoint(\n\t\t\t\tCollections.singletonMap(\"test\", new ConcurrentMapCacheManager(\"b\", \"a\")));\n\t\tCacheEntryDescriptor entry = endpoint.cache(\"a\", null);\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getCacheManager()).isEqualTo(\"test\");\n\t\tassertThat(entry.getName()).isEqualTo(\"a\");\n\t\tassertThat(entry.getTarget()).isEqualTo(ConcurrentHashMap.class.getName());\n\t}\n\n\t@Test\n\tvoid namedCacheWithSeveralCacheManagers() {\n\t\tMap<String, CacheManager> cacheManagers = new LinkedHashMap<>();\n\t\tcacheManagers.put(\"test\", new ConcurrentMapCacheManager(\"b\", \"dupe-cache\"));\n\t\tcacheManagers.put(\"another\", new ConcurrentMapCacheManager(\"c\", \"dupe-cache\"));\n\t\tCachesEndpoint endpoint = new CachesEndpoint(cacheManagers);\n\t\tassertThatExceptionOfType(NonUniqueCacheException.class).isThrownBy(() -> endpoint.cache(\"dupe-cache\", null))\n\t\t\t.withMessageContaining(\"dupe-cache\")\n\t\t\t.withMessageContaining(\"test\")\n\t\t\t.withMessageContaining(\"another\");\n\t}\n\n\t@Test\n\tvoid namedCacheWithUnknownCache() {\n\t\tCachesEndpoint endpoint = new CachesEndpoint(\n\t\t\t\tCollections.singletonMap(\"test\", new ConcurrentMapCacheManager(\"b\", \"a\")));\n\t\tCacheEntryDescriptor entry = endpoint.cache(\"unknown\", null);\n\t\tassertThat(entry).isNull();\n\t}\n\n\t@Test\n\tvoid namedCacheWithWrongCacheManager() {\n\t\tMap<String, CacheManager> cacheManagers = new LinkedHashMap<>();\n\t\tcacheManagers.put(\"test\", new ConcurrentMapCacheManager(\"b\", \"a\"));\n\t\tcacheManagers.put(\"another\", new ConcurrentMapCacheManager(\"c\", \"a\"));\n\t\tCachesEndpoint endpoint = new CachesEndpoint(cacheManagers);\n\t\tCacheEntryDescriptor entry = endpoint.cache(\"c\", \"test\");\n\t\tassertThat(entry).isNull();\n\t}\n\n\t@Test\n\tvoid namedCacheWithSeveralCacheManagersWithCacheManagerFilter() {\n\t\tMap<String, CacheManager> cacheManagers = new LinkedHashMap<>();\n\t\tcacheManagers.put(\"test\", new ConcurrentMapCacheManager(\"b\", \"a\"));\n\t\tcacheManagers.put(\"another\", new ConcurrentMapCacheManager(\"c\", \"a\"));\n\t\tCachesEndpoint endpoint = new CachesEndpoint(cacheManagers);\n\t\tCacheEntryDescriptor entry = endpoint.cache(\"a\", \"test\");\n\t\tassertThat(entry).isNotNull();\n\t\tassertThat(entry.getCacheManager()).isEqualTo(\"test\");\n\t\tassertThat(entry.getName()).isEqualTo(\"a\");\n\t}\n\n\t@Test\n\tvoid clearAllCaches() {\n\t\tCache a = mockCache(\"a\");\n\t\tCache b = mockCache(\"b\");\n\t\tCachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap(\"test\", cacheManager(a, b)));\n\t\tendpoint.clearCaches();\n\t\tthen(a).should().clear();\n\t\tthen(b).should().clear();\n\t}\n\n\t@Test\n\tvoid clearCache() {\n\t\tCache a = mockCache(\"a\");\n\t\tCache b = mockCache(\"b\");\n\t\tCachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap(\"test\", cacheManager(a, b)));\n\t\tassertThat(endpoint.clearCache(\"a\", null)).isTrue();\n\t\tthen(a).should().clear();\n\t\tthen(b).should(never()).clear();\n\t}\n\n\t@Test\n\tvoid clearCacheWithSeveralCacheManagers() {\n\t\tMap<String, CacheManager> cacheManagers = new LinkedHashMap<>();\n\t\tcacheManagers.put(\"test\", cacheManager(mockCache(\"dupe-cache\"), mockCache(\"b\")));\n\t\tcacheManagers.put(\"another\", cacheManager(mockCache(\"dupe-cache\")));\n\t\tCachesEndpoint endpoint = new CachesEndpoint(cacheManagers);\n\t\tassertThatExceptionOfType(NonUniqueCacheException.class)\n\t\t\t.isThrownBy(() -> endpoint.clearCache(\"dupe-cache\", null))\n\t\t\t.withMessageContaining(\"dupe-cache\")\n\t\t\t.withMessageContaining(\"test\")\n\t\t\t.withMessageContaining(\"another\");\n\t}\n\n\t@Test\n\tvoid clearCacheWithSeveralCacheManagersWithCacheManagerFilter() {\n\t\tMap<String, CacheManager> cacheManagers = new LinkedHashMap<>();\n\t\tCache a = mockCache(\"a\");\n\t\tCache b = mockCache(\"b\");\n\t\tcacheManagers.put(\"test\", cacheManager(a, b));\n\t\tCache anotherA = mockCache(\"a\");\n\t\tcacheManagers.put(\"another\", cacheManager(anotherA));\n\t\tCachesEndpoint endpoint = new CachesEndpoint(cacheManagers);\n\t\tassertThat(endpoint.clearCache(\"a\", \"another\")).isTrue();\n\t\tthen(a).should(never()).clear();\n\t\tthen(anotherA).should().clear();\n\t\tthen(b).should(never()).clear();\n\t}\n\n\t@Test\n\tvoid clearCacheWithUnknownCache() {\n\t\tCache a = mockCache(\"a\");\n\t\tCachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap(\"test\", cacheManager(a)));\n\t\tassertThat(endpoint.clearCache(\"unknown\", null)).isFalse();\n\t\tthen(a).should(never()).clear();\n\t}\n\n\t@Test\n\tvoid clearCacheWithUnknownCacheManager() {\n\t\tCache a = mockCache(\"a\");\n\t\tCachesEndpoint endpoint = new CachesEndpoint(Collections.singletonMap(\"test\", cacheManager(a)));\n\t\tassertThat(endpoint.clearCache(\"a\", \"unknown\")).isFalse();\n\t\tthen(a).should(never()).clear();\n\t}\n\n\tprivate CacheManager cacheManager(Cache... caches) {\n\t\tSimpleCacheManager cacheManager = new SimpleCacheManager();\n\t\tcacheManager.setCaches(Arrays.asList(caches));\n\t\tcacheManager.afterPropertiesSet();\n\t\treturn cacheManager;\n\t}\n\n\tprivate Cache mockCache(String name) {\n\t\tCache cache = mock(Cache.class);\n\t\tgiven(cache.getName()).willReturn(name);\n\t\tgiven(cache.getNativeCache()).willReturn(new Object());\n\t\treturn cache;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/actuate/endpoint/CachesEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.actuate.endpoint;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CachesEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Stephane Nicoll\n */\nclass CachesEndpointWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid allCaches(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/caches\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"cacheManagers.one.caches.a.target\")\n\t\t\t.isEqualTo(ConcurrentHashMap.class.getName())\n\t\t\t.jsonPath(\"cacheManagers.one.caches.b.target\")\n\t\t\t.isEqualTo(ConcurrentHashMap.class.getName())\n\t\t\t.jsonPath(\"cacheManagers.two.caches.a.target\")\n\t\t\t.isEqualTo(ConcurrentHashMap.class.getName())\n\t\t\t.jsonPath(\"cacheManagers.two.caches.c.target\")\n\t\t\t.isEqualTo(ConcurrentHashMap.class.getName());\n\t}\n\n\t@WebEndpointTest\n\tvoid namedCache(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/caches/b\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"name\")\n\t\t\t.isEqualTo(\"b\")\n\t\t\t.jsonPath(\"cacheManager\")\n\t\t\t.isEqualTo(\"one\")\n\t\t\t.jsonPath(\"target\")\n\t\t\t.isEqualTo(ConcurrentHashMap.class.getName());\n\t}\n\n\t@WebEndpointTest\n\tvoid namedCacheWithUnknownName(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/caches/does-not-exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid namedCacheWithNonUniqueName(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/caches/a\").exchange().expectStatus().isBadRequest();\n\t}\n\n\t@WebEndpointTest\n\tvoid clearNamedCache(WebTestClient client, ApplicationContext context) {\n\t\tCache b = context.getBean(\"one\", CacheManager.class).getCache(\"b\");\n\t\tassertThat(b).isNotNull();\n\t\tb.put(\"test\", \"value\");\n\t\tclient.delete().uri(\"/actuator/caches/b\").exchange().expectStatus().isNoContent();\n\t\tassertThat(b.get(\"test\")).isNull();\n\t}\n\n\t@WebEndpointTest\n\tvoid cleanNamedCacheWithUnknownName(WebTestClient client) {\n\t\tclient.delete().uri(\"/actuator/caches/does-not-exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid clearNamedCacheWithNonUniqueName(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/caches/a\").exchange().expectStatus().isBadRequest();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tCacheManager one() {\n\t\t\treturn new ConcurrentMapCacheManager(\"a\", \"b\");\n\t\t}\n\n\t\t@Bean\n\t\tCacheManager two() {\n\t\t\treturn new ConcurrentMapCacheManager(\"a\", \"c\");\n\t\t}\n\n\t\t@Bean\n\t\tCachesEndpoint endpoint(Map<String, CacheManager> cacheManagers) {\n\t\t\treturn new CachesEndpoint(cacheManagers);\n\t\t}\n\n\t\t@Bean\n\t\tCachesEndpointWebExtension cachesEndpointWebExtension(CachesEndpoint endpoint) {\n\t\t\treturn new CachesEndpointWebExtension(endpoint);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/AbstractCacheAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.hazelcast.spring.cache.HazelcastCacheManager;\nimport org.cache2k.extra.spring.SpringCache2kCacheManager;\nimport org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.caffeine.CaffeineCacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.cache.support.SimpleCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheManager;\nimport org.springframework.data.redis.cache.RedisCacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for {@link CacheAutoConfiguration} tests.\n *\n * @author Andy Wilkinson\n */\nabstract class AbstractCacheAutoConfigurationTests {\n\n\tprotected final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class));\n\n\tprotected <T extends CacheManager> T getCacheManager(AssertableApplicationContext loaded, Class<T> type) {\n\t\tCacheManager cacheManager = loaded.getBean(CacheManager.class);\n\t\tassertThat(cacheManager).as(\"Wrong cache manager type\").isInstanceOf(type);\n\t\treturn type.cast(cacheManager);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprotected ContextConsumer<AssertableApplicationContext> verifyCustomizers(String... expectedCustomizerNames) {\n\t\treturn (context) -> {\n\t\t\tCacheManager cacheManager = getCacheManager(context, CacheManager.class);\n\t\t\tList<String> expected = new ArrayList<>(Arrays.asList(expectedCustomizerNames));\n\t\t\tMap<String, CacheManagerTestCustomizer> customizer = context\n\t\t\t\t.getBeansOfType(CacheManagerTestCustomizer.class);\n\t\t\tcustomizer.forEach((key, value) -> {\n\t\t\t\tif (expected.contains(key)) {\n\t\t\t\t\texpected.remove(key);\n\t\t\t\t\tassertThat(value.cacheManager).isSameAs(cacheManager);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tassertThat(value.cacheManager).isNull();\n\t\t\t\t}\n\t\t\t});\n\t\t\tassertThat(expected).isEmpty();\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CacheManagerCustomizersConfiguration {\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<CacheManager> allCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<ConcurrentMapCacheManager> simpleCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<SimpleCacheManager> genericCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<CouchbaseCacheManager> couchbaseCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<RedisCacheManager> redisCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<HazelcastCacheManager> hazelcastCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<SpringEmbeddedCacheManager> infinispanCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<SpringCache2kCacheManager> cache2kCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tCacheManagerCustomizer<CaffeineCacheManager> caffeineCacheManagerCustomizer() {\n\t\t\treturn new CacheManagerTestCustomizer<>() {\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tabstract static class CacheManagerTestCustomizer<T extends CacheManager> implements CacheManagerCustomizer<T> {\n\n\t\t@Nullable T cacheManager;\n\n\t\t@Override\n\t\tpublic void customize(T cacheManager) {\n\t\t\tif (this.cacheManager != null) {\n\t\t\t\tthrow new IllegalStateException(\"Customized invoked twice\");\n\t\t\t}\n\t\t\tthis.cacheManager = cacheManager;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/CacheAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.function.Consumer;\n\nimport javax.cache.Caching;\nimport javax.cache.configuration.CompleteConfiguration;\nimport javax.cache.configuration.MutableConfiguration;\nimport javax.cache.expiry.CreatedExpiryPolicy;\nimport javax.cache.expiry.Duration;\n\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport com.github.benmanes.caffeine.cache.CaffeineSpec;\nimport com.hazelcast.cache.impl.HazelcastServerCachingProvider;\nimport com.hazelcast.core.Hazelcast;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.spring.cache.HazelcastCacheManager;\nimport org.cache2k.extra.spring.SpringCache2kCacheManager;\nimport org.infinispan.configuration.cache.ConfigurationBuilder;\nimport org.infinispan.jcache.embedded.JCachingProvider;\nimport org.infinispan.spring.embedded.provider.SpringEmbeddedCacheManager;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cache.autoconfigure.MockCachingProvider.MockCacheManager;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.Cache.ValueWrapper;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.CachingConfigurer;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.caffeine.CaffeineCache;\nimport org.springframework.cache.caffeine.CaffeineCacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCache;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.cache.interceptor.CacheResolver;\nimport org.springframework.cache.jcache.JCacheCacheManager;\nimport org.springframework.cache.support.NoOpCacheManager;\nimport org.springframework.cache.support.SimpleCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.data.couchbase.CouchbaseClientFactory;\nimport org.springframework.data.couchbase.cache.CouchbaseCache;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;\nimport org.springframework.data.couchbase.cache.CouchbaseCacheManager;\nimport org.springframework.data.redis.cache.FixedDurationTtlFunction;\nimport org.springframework.data.redis.cache.RedisCacheConfiguration;\nimport org.springframework.data.redis.cache.RedisCacheManager;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link CacheAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Mark Paluch\n * @author Ryon Day\n */\nclass CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {\n\n\t@Test\n\tvoid noEnableCaching() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CacheManager.class));\n\t}\n\n\t@Test\n\tvoid cacheManagerBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomCacheManagerConfiguration.class)\n\t\t\t.run((context) -> assertThat(getCacheManager(context, ConcurrentMapCacheManager.class).getCacheNames())\n\t\t\t\t.containsOnly(\"custom1\"));\n\t}\n\n\t@Test\n\tvoid cacheManagerFromSupportBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomCacheManagerFromSupportConfiguration.class)\n\t\t\t.run((context) -> assertThat(getCacheManager(context, ConcurrentMapCacheManager.class).getCacheNames())\n\t\t\t\t.containsOnly(\"custom1\"));\n\t}\n\n\t@Test\n\tvoid cacheResolverFromSupportBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomCacheResolverFromSupportConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CacheManager.class));\n\t}\n\n\t@Test\n\tvoid customCacheResolverCanBeDefined() {\n\t\tthis.contextRunner.withUserConfiguration(SpecificCacheResolverConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=simple\")\n\t\t\t.run((context) -> {\n\t\t\t\tgetCacheManager(context, ConcurrentMapCacheManager.class);\n\t\t\t\tassertThat(context).hasSingleBean(CacheResolver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid notSupportedCachingMode() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=foobar\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"No enum constant\")\n\t\t\t\t.hasMessageContaining(\"foobar\"));\n\t}\n\n\t@Test\n\tvoid simpleCacheExplicit() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=simple\")\n\t\t\t.run((context) -> assertThat(getCacheManager(context, ConcurrentMapCacheManager.class).getCacheNames())\n\t\t\t\t.isEmpty());\n\t}\n\n\t@Test\n\tvoid simpleCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheAndCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=simple\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"simpleCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid simpleCacheExplicitWithCacheNames() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=simple\", \"spring.cache.cacheNames[0]=foo\",\n\t\t\t\t\t\"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tConcurrentMapCacheManager cacheManager = getCacheManager(context, ConcurrentMapCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid genericCacheWithCaches() {\n\t\tthis.contextRunner.withUserConfiguration(GenericCacheConfiguration.class).run((context) -> {\n\t\t\tSimpleCacheManager cacheManager = getCacheManager(context, SimpleCacheManager.class);\n\t\t\tassertThat(cacheManager.getCache(\"first\")).isEqualTo(context.getBean(\"firstCache\"));\n\t\t\tassertThat(cacheManager.getCache(\"second\")).isEqualTo(context.getBean(\"secondCache\"));\n\t\t\tassertThat(cacheManager.getCacheNames()).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid genericCacheExplicit() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=generic\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"No cache manager could be auto-configured\")\n\t\t\t\t.hasMessageContaining(\"GENERIC\"));\n\t}\n\n\t@Test\n\tvoid genericCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(GenericCacheAndCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=generic\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"genericCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid genericCacheExplicitWithCaches() {\n\t\tthis.contextRunner.withUserConfiguration(GenericCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=generic\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleCacheManager cacheManager = getCacheManager(context, SimpleCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCache(\"first\")).isEqualTo(context.getBean(\"firstCache\"));\n\t\t\t\tassertThat(cacheManager.getCache(\"second\")).isEqualTo(context.getBean(\"secondCache\"));\n\t\t\t\tassertThat(cacheManager.getCacheNames()).hasSize(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid couchbaseCacheExplicit() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=couchbase\")\n\t\t\t.run((context) -> {\n\t\t\t\tCouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid couchbaseCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseWithCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=couchbase\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"couchbaseCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid couchbaseCacheExplicitWithCaches() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=couchbase\", \"spring.cache.cacheNames[0]=foo\",\n\t\t\t\t\t\"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tCouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t\tCache cache = cacheManager.getCache(\"foo\");\n\t\t\t\tassertThat(cache).isInstanceOf(CouchbaseCache.class);\n\t\t\t\tassertThat(((CouchbaseCache) cache).getCacheConfiguration().getExpiry()).hasSeconds(0);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid couchbaseCacheExplicitWithTtl() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=couchbase\", \"spring.cache.cacheNames=foo,bar\",\n\t\t\t\t\t\"spring.cache.couchbase.expiration=2000\")\n\t\t\t.run((context) -> {\n\t\t\t\tCouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t\tCache cache = cacheManager.getCache(\"foo\");\n\t\t\t\tassertThat(cache).isInstanceOf(CouchbaseCache.class);\n\t\t\t\tassertThat(((CouchbaseCache) cache).getCacheConfiguration().getExpiry()).hasSeconds(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid couchbaseCacheWithCouchbaseCacheManagerBuilderCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=couchbase\", \"spring.cache.couchbase.expiration=15s\")\n\t\t\t.withBean(CouchbaseCacheManagerBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.cacheDefaults(CouchbaseCacheConfiguration.defaultCacheConfig()\n\t\t\t\t\t\t.entryExpiry(java.time.Duration.ofSeconds(10))))\n\t\t\t.run((context) -> {\n\t\t\t\tCouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class);\n\t\t\t\tCouchbaseCacheConfiguration couchbaseCacheConfiguration = getDefaultCouchbaseCacheConfiguration(\n\t\t\t\t\t\tcacheManager);\n\t\t\t\tassertThat(couchbaseCacheConfiguration.getExpiry()).isEqualTo(java.time.Duration.ofSeconds(10));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid redisCacheExplicit() {\n\t\tthis.contextRunner.withUserConfiguration(RedisConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=redis\", \"spring.cache.redis.time-to-live=15000\",\n\t\t\t\t\t\"spring.cache.redis.cacheNullValues=false\", \"spring.cache.redis.keyPrefix=prefix\",\n\t\t\t\t\t\"spring.cache.redis.useKeyPrefix=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tRedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).isEmpty();\n\t\t\t\tRedisCacheConfiguration redisCacheConfiguration = getDefaultRedisCacheConfiguration(cacheManager);\n\t\t\t\tassertThat(redisCacheConfiguration).extracting(RedisCacheConfiguration::getTtlFunction)\n\t\t\t\t\t.isInstanceOf(FixedDurationTtlFunction.class)\n\t\t\t\t\t.extracting(\"duration\")\n\t\t\t\t\t.isEqualTo(java.time.Duration.ofSeconds(15));\n\t\t\t\tassertThat(redisCacheConfiguration.getAllowCacheNullValues()).isFalse();\n\t\t\t\tassertThat(redisCacheConfiguration.getKeyPrefixFor(\"MyCache\")).isEqualTo(\"prefixMyCache::\");\n\t\t\t\tassertThat(redisCacheConfiguration.usePrefix()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid redisCacheWithRedisCacheConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(RedisWithCacheConfigurationConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=redis\", \"spring.cache.redis.time-to-live=15000\",\n\t\t\t\t\t\"spring.cache.redis.keyPrefix=foo\")\n\t\t\t.run((context) -> {\n\t\t\t\tRedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).isEmpty();\n\t\t\t\tRedisCacheConfiguration redisCacheConfiguration = getDefaultRedisCacheConfiguration(cacheManager);\n\t\t\t\tassertThat(redisCacheConfiguration).extracting(RedisCacheConfiguration::getTtlFunction)\n\t\t\t\t\t.isInstanceOf(FixedDurationTtlFunction.class)\n\t\t\t\t\t.extracting(\"duration\")\n\t\t\t\t\t.isEqualTo(java.time.Duration.ofSeconds(30));\n\t\t\t\tassertThat(redisCacheConfiguration.getKeyPrefixFor(\"\")).isEqualTo(\"bar::\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid redisCacheWithRedisCacheManagerBuilderCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(RedisWithRedisCacheManagerBuilderCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=redis\", \"spring.cache.redis.time-to-live=15000\")\n\t\t\t.run((context) -> {\n\t\t\t\tRedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class);\n\t\t\t\tRedisCacheConfiguration redisCacheConfiguration = getDefaultRedisCacheConfiguration(cacheManager);\n\t\t\t\tassertThat(redisCacheConfiguration).extracting(RedisCacheConfiguration::getTtlFunction)\n\t\t\t\t\t.isInstanceOf(FixedDurationTtlFunction.class)\n\t\t\t\t\t.extracting(\"duration\")\n\t\t\t\t\t.isEqualTo(java.time.Duration.ofSeconds(10));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid redisCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(RedisWithCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=redis\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"redisCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid redisCacheExplicitWithCaches() {\n\t\tthis.contextRunner.withUserConfiguration(RedisConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=redis\", \"spring.cache.cacheNames[0]=foo\",\n\t\t\t\t\t\"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tRedisCacheManager cacheManager = getCacheManager(context, RedisCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t\tRedisCacheConfiguration redisCacheConfiguration = getDefaultRedisCacheConfiguration(cacheManager);\n\t\t\t\tassertThat(redisCacheConfiguration).extracting(RedisCacheConfiguration::getTtlFunction)\n\t\t\t\t\t.isInstanceOf(FixedDurationTtlFunction.class)\n\t\t\t\t\t.extracting(\"duration\")\n\t\t\t\t\t.isEqualTo(java.time.Duration.ofSeconds(0));\n\t\t\t\tassertThat(redisCacheConfiguration.getAllowCacheNullValues()).isTrue();\n\t\t\t\tassertThat(redisCacheConfiguration.getKeyPrefixFor(\"test\")).isEqualTo(\"test::\");\n\t\t\t\tassertThat(redisCacheConfiguration.usePrefix()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid noOpCacheExplicit() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=none\")\n\t\t\t.run((context) -> {\n\t\t\t\tNoOpCacheManager cacheManager = getCacheManager(context, NoOpCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheNoProviderExplicit() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"No cache manager could be auto-configured\")\n\t\t\t\t.hasMessageContaining(\"JCACHE\"));\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithProvider() {\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn)\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).isEmpty();\n\t\t\t\tassertThat(context.getBean(javax.cache.CacheManager.class)).isEqualTo(cacheManager.getCacheManager());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithCaches() {\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.cache.cacheNames[0]=foo\", \"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithCachesAndCustomConfig() {\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(JCacheCustomConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.cache.cacheNames[0]=one\", \"spring.cache.cacheNames[1]=two\")\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"one\", \"two\");\n\t\t\t\tCompleteConfiguration<?, ?> defaultCacheConfiguration = context.getBean(CompleteConfiguration.class);\n\t\t\t\tMockCacheManager mockCacheManager = (MockCacheManager) cacheManager.getCacheManager();\n\t\t\t\tassertThat(mockCacheManager).isNotNull();\n\t\t\t\tassertThat(mockCacheManager.getConfigurations()).containsEntry(\"one\", defaultCacheConfiguration)\n\t\t\t\t\t.containsEntry(\"two\", defaultCacheConfiguration);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithExistingJCacheManager() {\n\t\tthis.contextRunner.withUserConfiguration(JCacheCustomCacheManager.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\")\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheManager()).isEqualTo(context.getBean(\"customJCacheCacheManager\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithUnknownProvider() {\n\t\tString wrongCachingProviderClassName = \"org.acme.FooBar\";\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\",\n\t\t\t\t\t\"spring.cache.jcache.provider=\" + wrongCachingProviderClassName)\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(wrongCachingProviderClassName));\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithConfig() {\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tString configLocation = \"org/springframework/boot/cache/autoconfigure/hazelcast-specific.xml\";\n\t\tthis.contextRunner.withUserConfiguration(JCacheCustomConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.cache.jcache.config=\" + configLocation)\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tResource configResource = new ClassPathResource(configLocation);\n\t\t\t\tjavax.cache.CacheManager jCache = cacheManager.getCacheManager();\n\t\t\t\tassertThat(jCache).isNotNull();\n\t\t\t\tassertThat(jCache.getURI()).isEqualTo(configResource.getURI());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithWrongConfig() {\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tString configLocation = \"org/springframework/boot/cache/autoconfigure/does-not-exist.xml\";\n\t\tthis.contextRunner.withUserConfiguration(JCacheCustomConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.cache.jcache.config=\" + configLocation)\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"must exist\")\n\t\t\t\t.hasMessageContaining(configLocation));\n\t}\n\n\t@Test\n\tvoid jCacheCacheUseBeanClassLoader() {\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn)\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tjavax.cache.CacheManager jCache = cacheManager.getCacheManager();\n\t\t\t\tassertThat(jCache).isNotNull();\n\t\t\t\tassertThat(jCache.getClassLoader()).isEqualTo(context.getClassLoader());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithPropertiesCustomizer() {\n\t\tJCachePropertiesCustomizer customizer = mock(JCachePropertiesCustomizer.class);\n\t\twillAnswer((invocation) -> {\n\t\t\tinvocation.getArgument(0, Properties.class).setProperty(\"customized\", \"true\");\n\t\t\treturn null;\n\t\t}).given(customizer).customize(any(Properties.class));\n\t\tString cachingProviderFqn = MockCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn)\n\t\t\t.withBean(JCachePropertiesCustomizer.class, () -> customizer)\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tjavax.cache.CacheManager jCache = cacheManager.getCacheManager();\n\t\t\t\tassertThat(jCache).isNotNull();\n\t\t\t\tassertThat(jCache.getProperties()).containsEntry(\"customized\", \"true\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid hazelcastCacheExplicit() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=hazelcast\")\n\t\t\t.run((context) -> {\n\t\t\t\tHazelcastCacheManager cacheManager = getCacheManager(context, HazelcastCacheManager.class);\n\t\t\t\t// NOTE: the hazelcast implementation knows about a cache in a lazy\n\t\t\t\t// manner.\n\t\t\t\tcacheManager.getCache(\"defaultCache\");\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"defaultCache\");\n\t\t\t\tassertThat(context.getBean(HazelcastInstance.class)).isEqualTo(cacheManager.getHazelcastInstance());\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid hazelcastCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastCacheAndCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=hazelcast\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"hazelcastCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid hazelcastCacheWithExistingHazelcastInstance() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastCustomHazelcastInstance.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=hazelcast\")\n\t\t\t.run((context) -> {\n\t\t\t\tHazelcastCacheManager cacheManager = getCacheManager(context, HazelcastCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getHazelcastInstance()).isEqualTo(context.getBean(\"customHazelcastInstance\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hazelcastCacheWithHazelcastAutoConfiguration() {\n\t\tString hazelcastConfig = \"org/springframework/boot/cache/autoconfigure/hazelcast-specific.xml\";\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=hazelcast\", \"spring.hazelcast.config=\" + hazelcastConfig)\n\t\t\t.run((context) -> {\n\t\t\t\tHazelcastCacheManager cacheManager = getCacheManager(context, HazelcastCacheManager.class);\n\t\t\t\tHazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);\n\t\t\t\tassertThat(cacheManager.getHazelcastInstance()).isSameAs(hazelcastInstance);\n\t\t\t\tassertThat(hazelcastInstance.getConfig().getConfigurationFile())\n\t\t\t\t\t.isEqualTo(new ClassPathResource(hazelcastConfig).getFile());\n\t\t\t\tassertThat(cacheManager.getCache(\"foobar\")).isNotNull();\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foobar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hazelcastAsJCacheWithCaches() {\n\t\tString cachingProviderFqn = HazelcastServerCachingProvider.class.getName();\n\t\ttry {\n\t\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\t\"spring.cache.cacheNames[0]=foo\", \"spring.cache.cacheNames[1]=bar\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t\t\tassertThat(Hazelcast.getAllHazelcastInstances()).hasSize(1);\n\t\t\t\t});\n\t\t}\n\t\tfinally {\n\t\t\tCaching.getCachingProvider(cachingProviderFqn).close();\n\t\t}\n\t}\n\n\t@Test\n\t@WithResource(name = \"hazelcast-specific.xml\", content = \"\"\"\n\t\t\t<hazelcast xsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t\t\t\t   xmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t\t\t\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n\t\t\t\t<queue name=\"foobar\"/>\n\n\t\t\t\t<map name=\"foobar\">\n\t\t\t\t\t<time-to-live-seconds>3600</time-to-live-seconds>\n\t\t\t\t\t<max-idle-seconds>600</max-idle-seconds>\n\t\t\t\t</map>\n\n\t\t\t\t<network>\n\t\t\t\t\t<join>\n\t\t\t\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t\t\t\t<multicast enabled=\"false\"/>\n\t\t\t\t\t</join>\n\t\t\t\t</network>\n\n\t\t\t</hazelcast>\n\t\t\t\"\"\")\n\tvoid hazelcastAsJCacheWithConfig() {\n\t\tString cachingProviderFqn = HazelcastServerCachingProvider.class.getName();\n\t\ttry {\n\t\t\tString configLocation = \"hazelcast-specific.xml\";\n\t\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\t\"spring.cache.jcache.config=\" + configLocation)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\t\tResource configResource = new ClassPathResource(configLocation);\n\t\t\t\t\tjavax.cache.CacheManager jCache = cacheManager.getCacheManager();\n\t\t\t\t\tassertThat(jCache).isNotNull();\n\t\t\t\t\tassertThat(jCache.getURI()).isEqualTo(configResource.getURI());\n\t\t\t\t\tassertThat(Hazelcast.getAllHazelcastInstances()).hasSize(1);\n\t\t\t\t});\n\t\t}\n\t\tfinally {\n\t\t\tCaching.getCachingProvider(cachingProviderFqn).close();\n\t\t}\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid hazelcastAsJCacheWithExistingHazelcastInstance() {\n\t\tString cachingProviderFqn = HazelcastServerCachingProvider.class.getName();\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn)\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tjavax.cache.CacheManager jCacheManager = cacheManager.getCacheManager();\n\t\t\t\tassertThat(jCacheManager).isInstanceOf(com.hazelcast.cache.HazelcastCacheManager.class);\n\t\t\t\tassertThat(context).hasSingleBean(HazelcastInstance.class);\n\t\t\t\tHazelcastInstance hazelcastInstance = context.getBean(HazelcastInstance.class);\n\t\t\t\tassertThat(((com.hazelcast.cache.HazelcastCacheManager) jCacheManager).getHazelcastInstance())\n\t\t\t\t\t.isSameAs(hazelcastInstance);\n\t\t\t\tassertThat(hazelcastInstance.getName()).isEqualTo(\"default-instance\");\n\t\t\t\tassertThat(Hazelcast.getAllHazelcastInstances()).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithInfinispanXmlResource\n\tvoid infinispanCacheWithConfig() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=infinispan\", \"spring.cache.infinispan.config=infinispan.xml\")\n\t\t\t.run((context) -> {\n\t\t\t\tSpringEmbeddedCacheManager cacheManager = getCacheManager(context, SpringEmbeddedCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).contains(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid infinispanCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheAndCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=infinispan\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"infinispanCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid infinispanCacheWithCaches() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=infinispan\", \"spring.cache.cacheNames[0]=foo\",\n\t\t\t\t\t\"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> assertThat(getCacheManager(context, SpringEmbeddedCacheManager.class).getCacheNames())\n\t\t\t\t.containsOnly(\"foo\", \"bar\"));\n\t}\n\n\t@Test\n\tvoid infinispanCacheWithCachesAndCustomConfig() {\n\t\tthis.contextRunner.withUserConfiguration(InfinispanCustomConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=infinispan\", \"spring.cache.cacheNames[0]=foo\",\n\t\t\t\t\t\"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getCacheManager(context, SpringEmbeddedCacheManager.class).getCacheNames())\n\t\t\t\t\t.containsOnly(\"foo\", \"bar\");\n\t\t\t\tthen(context.getBean(ConfigurationBuilder.class)).should(times(2)).build();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid infinispanAsJCacheWithCaches() {\n\t\tString cachingProviderClassName = JCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderClassName,\n\t\t\t\t\t\"spring.cache.cacheNames[0]=foo\", \"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> assertThat(getCacheManager(context, JCacheCacheManager.class).getCacheNames())\n\t\t\t\t.containsOnly(\"foo\", \"bar\"));\n\t}\n\n\t@Test\n\t@WithInfinispanXmlResource\n\tvoid infinispanAsJCacheWithConfig() {\n\t\tString cachingProviderClassName = JCachingProvider.class.getName();\n\t\tString configLocation = \"infinispan.xml\";\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderClassName,\n\t\t\t\t\t\"spring.cache.jcache.config=\" + configLocation)\n\t\t\t.run((context) -> {\n\t\t\t\tResource configResource = new ClassPathResource(configLocation);\n\t\t\t\tjavax.cache.CacheManager jCache = getCacheManager(context, JCacheCacheManager.class).getCacheManager();\n\t\t\t\tassertThat(jCache).isNotNull();\n\t\t\t\tassertThat(jCache.getURI()).isEqualTo(configResource.getURI());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jCacheCacheWithCachesAndCustomizer() {\n\t\tString cachingProviderFqn = HazelcastServerCachingProvider.class.getName();\n\t\ttry {\n\t\t\tthis.contextRunner.withUserConfiguration(JCacheWithCustomizerConfiguration.class)\n\t\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\t\"spring.cache.cacheNames[0]=foo\", \"spring.cache.cacheNames[1]=bar\")\n\t\t\t\t.run((context) ->\n\t\t\t\t// see customizer\n\t\t\t\tassertThat(getCacheManager(context, JCacheCacheManager.class).getCacheNames()).containsOnly(\"foo\",\n\t\t\t\t\t\t\"custom1\"));\n\t\t}\n\t\tfinally {\n\t\t\tCaching.getCachingProvider(cachingProviderFqn).close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid cache2kCacheWithExplicitCaches() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=cache2k\", \"spring.cache.cacheNames=foo,bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tSpringCache2kCacheManager manager = getCacheManager(context, SpringCache2kCacheManager.class);\n\t\t\t\tassertThat(manager.getCacheNames()).containsExactlyInAnyOrder(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cache2kCacheWithCustomizedDefaults() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=cache2k\")\n\t\t\t.withBean(Cache2kBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.valueType(String.class).loader((key) -> \"default\"))\n\t\t\t.run((context) -> {\n\t\t\t\tSpringCache2kCacheManager manager = getCacheManager(context, SpringCache2kCacheManager.class);\n\t\t\t\tassertThat(manager.getCacheNames()).isEmpty();\n\t\t\t\tCache dynamic = manager.getCache(\"dynamic\");\n\t\t\t\tassertThat(dynamic.get(\"1\")).satisfies(hasEntry(\"default\"));\n\t\t\t\tassertThat(dynamic.get(\"2\")).satisfies(hasEntry(\"default\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cache2kCacheWithCustomizedDefaultsAndExplicitCaches() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=cache2k\", \"spring.cache.cacheNames=foo,bar\")\n\t\t\t.withBean(Cache2kBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.valueType(String.class).loader((key) -> \"default\"))\n\t\t\t.run((context) -> {\n\t\t\t\tSpringCache2kCacheManager manager = getCacheManager(context, SpringCache2kCacheManager.class);\n\t\t\t\tassertThat(manager.getCacheNames()).containsExactlyInAnyOrder(\"foo\", \"bar\");\n\t\t\t\tassertThat(manager.getCache(\"foo\").get(\"1\")).satisfies(hasEntry(\"default\"));\n\t\t\t\tassertThat(manager.getCache(\"bar\").get(\"1\")).satisfies(hasEntry(\"default\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cache2kCacheWithCacheManagerCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=cache2k\")\n\t\t\t.withBean(CacheManagerCustomizer.class,\n\t\t\t\t\t() -> cache2kCacheManagerCustomizer((cacheManager) -> cacheManager.addCache(\"custom\",\n\t\t\t\t\t\t\t(builder) -> builder.valueType(String.class).loader((key) -> \"custom\"))))\n\t\t\t.run((context) -> {\n\t\t\t\tSpringCache2kCacheManager manager = getCacheManager(context, SpringCache2kCacheManager.class);\n\t\t\t\tassertThat(manager.getCacheNames()).containsExactlyInAnyOrder(\"custom\");\n\t\t\t\tassertThat(manager.getCache(\"custom\").get(\"1\")).satisfies(hasEntry(\"custom\"));\n\t\t\t});\n\t}\n\n\tprivate CacheManagerCustomizer<SpringCache2kCacheManager> cache2kCacheManagerCustomizer(\n\t\t\tConsumer<SpringCache2kCacheManager> cacheManager) {\n\t\treturn cacheManager::accept;\n\t}\n\n\t@Test\n\tvoid cache2kCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheAndCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=cache2k\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"cache2kCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid caffeineCacheWithExplicitCaches() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\", \"spring.cache.cacheNames=foo\")\n\t\t\t.run((context) -> {\n\t\t\t\tCaffeineCacheManager manager = getCacheManager(context, CaffeineCacheManager.class);\n\t\t\t\tassertThat(manager.getCacheNames()).containsOnly(\"foo\");\n\t\t\t\tCache foo = manager.getCache(\"foo\");\n\t\t\t\tassertThat(foo).isNotNull();\n\t\t\t\tfoo.get(\"1\");\n\t\t\t\t// See next tests: no spec given so stats should be disabled\n\t\t\t\tassertThat(((CaffeineCache) foo).getNativeCache().stats().missCount()).isZero();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid caffeineCacheWithCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheAndCustomizersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\")\n\t\t\t.run(verifyCustomizers(\"allCacheManagerCustomizer\", \"caffeineCacheManagerCustomizer\"));\n\t}\n\n\t@Test\n\tvoid caffeineCacheWithExplicitCacheBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(CaffeineCacheBuilderConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\", \"spring.cache.cacheNames=foo,bar\")\n\t\t\t.run(this::validateCaffeineCacheWithStats);\n\t}\n\n\t@Test\n\tvoid caffeineCacheExplicitWithSpec() {\n\t\tthis.contextRunner.withUserConfiguration(CaffeineCacheSpecConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\", \"spring.cache.cacheNames[0]=foo\",\n\t\t\t\t\t\"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run(this::validateCaffeineCacheWithStats);\n\t}\n\n\t@Test\n\tvoid caffeineCacheExplicitWithSpecString() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\", \"spring.cache.caffeine.spec=recordStats\",\n\t\t\t\t\t\"spring.cache.cacheNames[0]=foo\", \"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run(this::validateCaffeineCacheWithStats);\n\t}\n\n\t@Test\n\tvoid autoConfiguredCacheManagerCanBeSwapped() {\n\t\tthis.contextRunner.withUserConfiguration(CacheManagerPostProcessorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\")\n\t\t\t.run((context) -> {\n\t\t\t\tgetCacheManager(context, SimpleCacheManager.class);\n\t\t\t\tCacheManagerPostProcessor postProcessor = context.getBean(CacheManagerPostProcessor.class);\n\t\t\t\tassertThat(postProcessor.cacheManagers).hasSize(1);\n\t\t\t\tassertThat(postProcessor.cacheManagers.get(0)).isInstanceOf(CaffeineCacheManager.class);\n\t\t\t});\n\t}\n\n\tprivate Consumer<ValueWrapper> hasEntry(Object value) {\n\t\treturn (valueWrapper) -> assertThat(valueWrapper.get()).isEqualTo(value);\n\t}\n\n\tprivate void validateCaffeineCacheWithStats(AssertableApplicationContext context) {\n\t\tCaffeineCacheManager manager = getCacheManager(context, CaffeineCacheManager.class);\n\t\tassertThat(manager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\tCache foo = manager.getCache(\"foo\");\n\t\tassertThat(foo).isNotNull();\n\t\tfoo.get(\"1\");\n\t\tassertThat(((CaffeineCache) foo).getNativeCache().stats().missCount()).isOne();\n\t}\n\n\tprivate CouchbaseCacheConfiguration getDefaultCouchbaseCacheConfiguration(CouchbaseCacheManager cacheManager) {\n\t\tObject field = ReflectionTestUtils.getField(cacheManager, \"defaultCacheConfig\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (CouchbaseCacheConfiguration) field;\n\t}\n\n\tprivate RedisCacheConfiguration getDefaultRedisCacheConfiguration(RedisCacheManager cacheManager) {\n\t\tObject field = ReflectionTestUtils.getField(cacheManager, \"defaultCacheConfiguration\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (RedisCacheConfiguration) field;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class DefaultCacheConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\t@Import(CacheManagerCustomizersConfiguration.class)\n\tstatic class DefaultCacheAndCustomizersConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class GenericCacheConfiguration {\n\n\t\t@Bean\n\t\tCache firstCache() {\n\t\t\treturn new ConcurrentMapCache(\"first\");\n\t\t}\n\n\t\t@Bean\n\t\tCache secondCache() {\n\t\t\treturn new ConcurrentMapCache(\"second\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ GenericCacheConfiguration.class, CacheManagerCustomizersConfiguration.class })\n\tstatic class GenericCacheAndCustomizersConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\t@Import({ HazelcastAutoConfiguration.class, CacheManagerCustomizersConfiguration.class })\n\tstatic class HazelcastCacheAndCustomizersConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CouchbaseConfiguration {\n\n\t\t@Bean\n\t\tCouchbaseClientFactory couchbaseClientFactory() {\n\t\t\treturn mock(CouchbaseClientFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ CouchbaseConfiguration.class, CacheManagerCustomizersConfiguration.class })\n\tstatic class CouchbaseWithCustomizersConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class RedisConfiguration {\n\n\t\t@Bean\n\t\tRedisConnectionFactory redisConnectionFactory() {\n\t\t\treturn mock(RedisConnectionFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(RedisConfiguration.class)\n\tstatic class RedisWithCacheConfigurationConfiguration {\n\n\t\t@Bean\n\t\torg.springframework.data.redis.cache.RedisCacheConfiguration customRedisCacheConfiguration() {\n\t\t\treturn org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig()\n\t\t\t\t.entryTtl(java.time.Duration.ofSeconds(30))\n\t\t\t\t.prefixCacheNameWith(\"bar\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(RedisConfiguration.class)\n\tstatic class RedisWithRedisCacheManagerBuilderCustomizerConfiguration {\n\n\t\t@Bean\n\t\tRedisCacheManagerBuilderCustomizer ttlRedisCacheManagerBuilderCustomizer() {\n\t\t\treturn (builder) -> builder\n\t\t\t\t.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(java.time.Duration.ofSeconds(10)));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ RedisConfiguration.class, CacheManagerCustomizersConfiguration.class })\n\tstatic class RedisWithCustomizersConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class JCacheCustomConfiguration {\n\n\t\t@Bean\n\t\tCompleteConfiguration<?, ?> defaultCacheConfiguration() {\n\t\t\treturn mock(CompleteConfiguration.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class JCacheCustomCacheManager {\n\n\t\t@Bean\n\t\tjavax.cache.CacheManager customJCacheCacheManager() {\n\t\t\tjavax.cache.CacheManager cacheManager = mock(javax.cache.CacheManager.class);\n\t\t\tgiven(cacheManager.getCacheNames()).willReturn(Collections.emptyList());\n\t\t\treturn cacheManager;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class JCacheWithCustomizerConfiguration {\n\n\t\t@Bean\n\t\tJCacheManagerCustomizer myCustomizer() {\n\t\t\treturn (cacheManager) -> {\n\t\t\t\tMutableConfiguration<?, ?> config = new MutableConfiguration<>();\n\t\t\t\tconfig.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(Duration.TEN_MINUTES));\n\t\t\t\tconfig.setStatisticsEnabled(true);\n\t\t\t\tcacheManager.createCache(\"custom1\", config);\n\t\t\t\tcacheManager.destroyCache(\"bar\");\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class HazelcastCustomHazelcastInstance {\n\n\t\t@Bean\n\t\tHazelcastInstance customHazelcastInstance() {\n\t\t\treturn mock(HazelcastInstance.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class InfinispanCustomConfiguration {\n\n\t\t@Bean\n\t\tConfigurationBuilder configurationBuilder() {\n\t\t\tConfigurationBuilder builder = mock(ConfigurationBuilder.class);\n\t\t\tgiven(builder.build()).willReturn(new ConfigurationBuilder().build());\n\t\t\treturn builder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CustomCacheManagerConfiguration {\n\n\t\t@Bean\n\t\tCacheManager cacheManager() {\n\t\t\treturn new ConcurrentMapCacheManager(\"custom1\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CustomCacheManagerFromSupportConfiguration implements CachingConfigurer {\n\n\t\t@Override\n\t\t@Bean\n\t\tpublic CacheManager cacheManager() {\n\t\t\t// The @Bean annotation is important, see CachingConfigurerSupport Javadoc\n\t\t\treturn new ConcurrentMapCacheManager(\"custom1\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CustomCacheResolverFromSupportConfiguration implements CachingConfigurer {\n\n\t\t@Override\n\t\t@Bean\n\t\tpublic CacheResolver cacheResolver() {\n\t\t\t// The @Bean annotation is important, see CachingConfigurerSupport Javadoc\n\t\t\treturn (context) -> Collections.singleton(mock(Cache.class));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class SpecificCacheResolverConfiguration {\n\n\t\t@Bean\n\t\tCacheResolver myCacheResolver() {\n\t\t\treturn mock(CacheResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CaffeineCacheBuilderConfiguration {\n\n\t\t@Bean\n\t\tCaffeine<Object, Object> cacheBuilder() {\n\t\t\treturn Caffeine.newBuilder().recordStats();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CaffeineCacheSpecConfiguration {\n\n\t\t@Bean\n\t\tCaffeineSpec caffeineSpec() {\n\t\t\treturn CaffeineSpec.parse(\"recordStats\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CacheManagerPostProcessorConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor cacheManagerBeanPostProcessor() {\n\t\t\treturn new CacheManagerPostProcessor();\n\t\t}\n\n\t}\n\n\tstatic class CacheManagerPostProcessor implements BeanPostProcessor {\n\n\t\tprivate final List<CacheManager> cacheManagers = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) {\n\t\t\treturn bean;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\tif (bean instanceof CacheManager cacheManager) {\n\t\t\t\tthis.cacheManagers.add(cacheManager);\n\t\t\t\treturn new SimpleCacheManager();\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"infinispan.xml\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<infinispan>\n\n\t\t\t\t<!-- ************************************** -->\n\t\t\t\t<!-- Corresponds to @Cacheable(\"cache-name\") -->\n\t\t\t\t<!-- ************************************** -->\n\t\t\t\t<cache-container default-cache=\"default\">\n\t\t\t\t\t<local-cache name=\"default\"/>\n\t\t\t\t\t<local-cache name=\"foo\"/>\n\t\t\t\t\t<local-cache name=\"bar\" />\n\t\t\t\t</cache-container>\n\n\t\t\t</infinispan>\n\t\t\t\"\"\")\n\t@interface WithInfinispanXmlResource {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"hazelcast.xml\", content = \"\"\"\n\t\t\t<hazelcast\n\t\t\t\txsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t\t\txmlns=\"http://www.hazelcast.com/schema/config\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t\t\t\t<instance-name>default-instance</instance-name>\n\t\t\t\t<map name=\"defaultCache\" />\n\t\t\t\t<network>\n\t\t\t\t\t<join>\n\t\t\t\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t\t\t\t<multicast enabled=\"false\" />\n\t\t\t\t\t</join>\n\t\t\t\t</network>\n\t\t\t</hazelcast>\n\t\t\t\"\"\")\n\t@interface WithHazelcastXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/CacheManagerCustomizersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.caffeine.CaffeineCacheManager;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * @author Stephane Nicoll\n */\nclass CacheManagerCustomizersTests {\n\n\t@Test\n\tvoid customizeWithNullCustomizersShouldDoNothing() {\n\t\tnew CacheManagerCustomizers(null).customize(mock(CacheManager.class));\n\t}\n\n\t@Test\n\tvoid customizeSimpleCacheManager() {\n\t\tCacheManagerCustomizers customizers = new CacheManagerCustomizers(\n\t\t\t\tCollections.singletonList(new CacheNamesCacheManagerCustomizer()));\n\t\tConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();\n\t\tcustomizers.customize(cacheManager);\n\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"one\", \"two\");\n\t}\n\n\t@Test\n\tvoid customizeShouldCheckGeneric() {\n\t\tList<TestCustomizer<?>> list = new ArrayList<>();\n\t\tlist.add(new TestCustomizer<>());\n\t\tlist.add(new TestConcurrentMapCacheManagerCustomizer());\n\t\tCacheManagerCustomizers customizers = new CacheManagerCustomizers(list);\n\t\tcustomizers.customize(mock(CacheManager.class));\n\t\tassertThat(list.get(0).getCount()).isOne();\n\t\tassertThat(list.get(1).getCount()).isZero();\n\t\tcustomizers.customize(mock(ConcurrentMapCacheManager.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t\tcustomizers.customize(mock(CaffeineCacheManager.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(3);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t}\n\n\tstatic class CacheNamesCacheManagerCustomizer implements CacheManagerCustomizer<ConcurrentMapCacheManager> {\n\n\t\t@Override\n\t\tpublic void customize(ConcurrentMapCacheManager cacheManager) {\n\t\t\tcacheManager.setCacheNames(Arrays.asList(\"one\", \"two\"));\n\t\t}\n\n\t}\n\n\tstatic class TestCustomizer<T extends CacheManager> implements CacheManagerCustomizer<T> {\n\n\t\tprivate int count;\n\n\t\t@Override\n\t\tpublic void customize(T cacheManager) {\n\t\t\tthis.count++;\n\t\t}\n\n\t\tint getCount() {\n\t\t\treturn this.count;\n\t\t}\n\n\t}\n\n\tstatic class TestConcurrentMapCacheManagerCustomizer extends TestCustomizer<ConcurrentMapCacheManager> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/CachesEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpoint;\nimport org.springframework.boot.cache.actuate.endpoint.CachesEndpointWebExtension;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cache.CacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CachesEndpointAutoConfiguration}.\n *\n * @author Johannes Edmeier\n * @author Stephane Nicoll\n */\nclass CachesEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CachesEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withBean(CacheManager.class, () -> mock(CacheManager.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=caches\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CachesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWithoutCacheManagerShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=caches\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CachesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withBean(CacheManager.class, () -> mock(CacheManager.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CachesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.caches.enabled:false\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.withBean(CacheManager.class, () -> mock(CacheManager.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CachesEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenOnlyExposedOverJmxShouldHaveEndpointBeanWithoutWebExtension() {\n\t\tthis.contextRunner.withBean(CacheManager.class, () -> mock(CacheManager.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info\", \"spring.jmx.enabled=true\",\n\t\t\t\t\t\"management.endpoints.jmx.exposure.include=caches\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CachesEndpoint.class)\n\t\t\t\t.doesNotHaveBean(CachesEndpointWebExtension.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/EhCache3CacheAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport javax.cache.CacheManager;\n\nimport org.ehcache.jsr107.EhcacheCachingProvider;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cache.autoconfigure.CacheAutoConfigurationTests.DefaultCacheConfiguration;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.cache.jcache.JCacheCacheManager;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CacheAutoConfiguration} with EhCache 3.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"ehcache-2*.jar\")\nclass EhCache3CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests {\n\n\t@Test\n\tvoid ehcache3AsJCacheWithCaches() {\n\t\tString cachingProviderFqn = EhcacheCachingProvider.class.getName();\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.cache.cacheNames[0]=foo\", \"spring.cache.cacheNames[1]=bar\")\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"ehcache3.xml\", content = \"\"\"\n\t\t\t<config\n\t\t\t\t\txmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n\t\t\t\t\txmlns='http://www.ehcache.org/v3'\n\t\t\t\t\txmlns:jsr107='http://www.ehcache.org/v3/jsr107'\n\t\t\t\t\txsi:schemaLocation=\"\n\t\t\t        http://www.ehcache.org/v3 https://www.ehcache.org/schema/ehcache-core-3.10.xsd\n\t\t\t        http://www.ehcache.org/v3/jsr107 https://www.ehcache.org/schema/ehcache-107-ext-3.10.xsd\">\n\n\t\t\t\t<cache-template name=\"example\">\n\t\t\t\t\t<heap unit=\"entries\">200</heap>\n\t\t\t\t</cache-template>\n\n\t\t\t\t<cache alias=\"foo\" uses-template=\"example\">\n\t\t\t\t\t<expiry>\n\t\t\t\t\t\t<ttl unit=\"seconds\">600</ttl>\n\t\t\t\t\t</expiry>\n\t\t\t\t\t<jsr107:mbeans enable-statistics=\"true\"/>\n\t\t\t\t</cache>\n\n\t\t\t\t<cache alias=\"bar\" uses-template=\"example\">\n\t\t\t\t\t<expiry>\n\t\t\t\t\t\t<ttl unit=\"seconds\">400</ttl>\n\t\t\t\t\t</expiry>\n\t\t\t\t</cache>\n\n\t\t\t</config>\n\t\t\t\"\"\")\n\tvoid ehcache3AsJCacheWithConfig() {\n\t\tString cachingProviderFqn = EhcacheCachingProvider.class.getName();\n\t\tString configLocation = \"ehcache3.xml\";\n\t\tthis.contextRunner.withUserConfiguration(DefaultCacheConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.cache.jcache.config=\" + configLocation)\n\t\t\t.run((context) -> {\n\t\t\t\tJCacheCacheManager cacheManager = getCacheManager(context, JCacheCacheManager.class);\n\n\t\t\t\tResource configResource = new ClassPathResource(configLocation);\n\t\t\t\tCacheManager jCache = cacheManager.getCacheManager();\n\t\t\t\tassertThat(jCache).isNotNull();\n\t\t\t\tassertThat(jCache.getURI()).isEqualTo(configResource.getURI());\n\t\t\t\tassertThat(cacheManager.getCacheNames()).containsOnly(\"foo\", \"bar\");\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/MockCachingProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure;\n\nimport java.net.URI;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.cache.Cache;\nimport javax.cache.CacheManager;\nimport javax.cache.configuration.Configuration;\nimport javax.cache.configuration.OptionalFeature;\nimport javax.cache.spi.CachingProvider;\n\nimport org.jspecify.annotations.Nullable;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * A mock {@link CachingProvider} that exposes a JSR-107 cache manager for testing\n * purposes.\n *\n * @author Stephane Nicoll\n */\npublic class MockCachingProvider implements CachingProvider {\n\n\t@Override\n\tpublic CacheManager getCacheManager(@Nullable URI uri, ClassLoader classLoader, Properties properties) {\n\t\treturn new MockCacheManager(uri, classLoader, properties);\n\t}\n\n\t@Override\n\tpublic ClassLoader getDefaultClassLoader() {\n\t\treturn mock(ClassLoader.class);\n\t}\n\n\t@Override\n\tpublic @Nullable URI getDefaultURI() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Properties getDefaultProperties() {\n\t\treturn new Properties();\n\t}\n\n\t@Override\n\tpublic CacheManager getCacheManager(@Nullable URI uri, ClassLoader classLoader) {\n\t\treturn getCacheManager(uri, classLoader, getDefaultProperties());\n\t}\n\n\t@Override\n\tpublic CacheManager getCacheManager() {\n\t\treturn getCacheManager(getDefaultURI(), getDefaultClassLoader());\n\t}\n\n\t@Override\n\tpublic void close() {\n\t}\n\n\t@Override\n\tpublic void close(ClassLoader classLoader) {\n\t}\n\n\t@Override\n\tpublic void close(URI uri, ClassLoader classLoader) {\n\t}\n\n\t@Override\n\tpublic boolean isSupported(OptionalFeature optionalFeature) {\n\t\treturn false;\n\t}\n\n\tpublic static class MockCacheManager implements CacheManager {\n\n\t\tprivate final Map<String, Configuration<?, ?>> configurations = new HashMap<>();\n\n\t\tprivate final Map<String, Cache<?, ?>> caches = new HashMap<>();\n\n\t\tprivate final @Nullable URI uri;\n\n\t\tprivate final ClassLoader classLoader;\n\n\t\tprivate final Properties properties;\n\n\t\tprivate boolean closed;\n\n\t\tpublic MockCacheManager(@Nullable URI uri, ClassLoader classLoader, Properties properties) {\n\t\t\tthis.uri = uri;\n\t\t\tthis.classLoader = classLoader;\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic CachingProvider getCachingProvider() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable URI getURI() {\n\t\t\treturn this.uri;\n\t\t}\n\n\t\t@Override\n\t\tpublic ClassLoader getClassLoader() {\n\t\t\treturn this.classLoader;\n\t\t}\n\n\t\t@Override\n\t\tpublic Properties getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(String cacheName, C configuration) {\n\t\t\tthis.configurations.put(cacheName, configuration);\n\t\t\tCache<K, V> cache = mock(Cache.class);\n\t\t\tgiven(cache.getName()).willReturn(cacheName);\n\t\t\tthis.caches.put(cacheName, cache);\n\t\t\treturn cache;\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic <K, V> @Nullable Cache<K, V> getCache(String cacheName, Class<K> keyType, Class<V> valueType) {\n\t\t\treturn (Cache<K, V>) this.caches.get(cacheName);\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic <K, V> @Nullable Cache<K, V> getCache(String cacheName) {\n\t\t\treturn (Cache<K, V>) this.caches.get(cacheName);\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterable<String> getCacheNames() {\n\t\t\treturn this.caches.keySet();\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroyCache(String cacheName) {\n\t\t\tthis.caches.remove(cacheName);\n\t\t}\n\n\t\t@Override\n\t\tpublic void enableManagement(String cacheName, boolean enabled) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic void enableStatistics(String cacheName, boolean enabled) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t\tthis.closed = true;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isClosed() {\n\t\t\treturn this.closed;\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> T unwrap(Class<T> type) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\tpublic Map<String, Configuration<?, ?>> getConfigurations() {\n\t\t\treturn this.configurations;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/autoconfigure/metrics/CacheMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.autoconfigure.metrics;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.github.benmanes.caffeine.cache.CaffeineSpec;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration;\nimport org.springframework.boot.cache.metrics.JCacheCacheMeterBinderProvider;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.CachingConfigurer;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.caffeine.CaffeineCacheManager;\nimport org.springframework.cache.interceptor.CacheResolver;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CacheMetricsAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass CacheMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withUserConfiguration(CachingConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class, CacheMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguredCache2kIsInstrumented() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cache.type=cache2k\", \"spring.cache.cache-names=cache1,cache2\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"cache.gets\").tags(\"name\", \"cache1\").tags(\"cache.manager\", \"cacheManager\").meter();\n\t\t\t\tregistry.get(\"cache.gets\").tags(\"name\", \"cache2\").tags(\"cache.manager\", \"cacheManager\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredCacheManagerIsInstrumented() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\", \"spring.cache.cache-names=cache1,cache2\",\n\t\t\t\t\t\"spring.cache.caffeine.spec=recordStats\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"cache.gets\").tags(\"name\", \"cache1\").tags(\"cache.manager\", \"cacheManager\").meter();\n\t\t\t\tregistry.get(\"cache.gets\").tags(\"name\", \"cache2\").tags(\"cache.manager\", \"cacheManager\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredNonSupportedCacheManagerIsIgnored() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cache.type=simple\", \"spring.cache.cache-names=cache1,cache2\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"cache.gets\")\n\t\t\t\t\t.tags(\"name\", \"cache1\")\n\t\t\t\t\t.tags(\"cache.manager\", \"cacheManager\")\n\t\t\t\t\t.meter()).isNull();\n\t\t\t\tassertThat(registry.find(\"cache.gets\")\n\t\t\t\t\t.tags(\"name\", \"cache2\")\n\t\t\t\t\t.tags(\"cache.manager\", \"cacheManager\")\n\t\t\t\t\t.meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cacheInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.metrics.enable.cache=false\", \"spring.cache.type=caffeine\",\n\t\t\t\t\t\"spring.cache.cache-names=cache1\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"cache.requests\")\n\t\t\t\t\t.tags(\"name\", \"cache1\")\n\t\t\t\t\t.tags(\"cache.manager\", \"cacheManager\")\n\t\t\t\t\t.meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customCacheManagersAreInstrumented() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cache.type=caffeine\", \"spring.cache.cache-names=cache1,cache2\",\n\t\t\t\t\t\"spring.cache.caffeine.spec=recordStats\")\n\t\t\t.withUserConfiguration(CustomCacheManagersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"cache.gets\").meters()).map((meter) -> meter.getId().getTag(\"cache\"))\n\t\t\t\t\t.containsOnly(\"standard\", \"non-default\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jcacheCacheMeterBinderProviderIsAutoConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cache.type=simple\", \"spring.cache.cache-names=cache1,cache2\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JCacheCacheMeterBinderProvider.class)\n\t\t\t\t.hasBean(\"jCacheCacheMeterBinderProvider\"));\n\t}\n\n\t@Test\n\tvoid jcacheCacheMeterBinderProviderBacksOff() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cache.type=simple\", \"spring.cache.cache-names=cache1,cache2\")\n\t\t\t.withBean(\"customProvider\", JCacheCacheMeterBinderProvider.class,\n\t\t\t\t\t() -> new JCacheCacheMeterBinderProvider(true))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JCacheCacheMeterBinderProvider.class)\n\t\t\t\t.hasBean(\"customProvider\")\n\t\t\t\t.doesNotHaveBean(\"jCacheCacheMeterBinderProvider\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomCacheManagersConfiguration implements CachingConfigurer {\n\n\t\t@Bean\n\t\tCacheManager standardCacheManager() {\n\t\t\tCaffeineCacheManager cacheManager = new CaffeineCacheManager();\n\t\t\tcacheManager.setCaffeineSpec(CaffeineSpec.parse(\"recordStats\"));\n\t\t\tcacheManager.setCacheNames(List.of(\"standard\"));\n\t\t\treturn cacheManager;\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tCacheManager nonDefaultCacheManager() {\n\t\t\tCaffeineCacheManager cacheManager = new CaffeineCacheManager();\n\t\t\tcacheManager.setCaffeineSpec(CaffeineSpec.parse(\"recordStats\"));\n\t\t\tcacheManager.setCacheNames(List.of(\"non-default\"));\n\t\t\treturn cacheManager;\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tCacheManager nonAutowireCacheManager() {\n\t\t\tCaffeineCacheManager cacheManager = new CaffeineCacheManager();\n\t\t\tcacheManager.setCaffeineSpec(CaffeineSpec.parse(\"recordStats\"));\n\t\t\tcacheManager.setCacheNames(List.of(\"non-autowire\"));\n\t\t\treturn cacheManager;\n\t\t}\n\n\t\t@Bean\n\t\t@Override\n\t\tpublic CacheResolver cacheResolver() {\n\t\t\treturn (context) -> Collections.emptyList();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class CachingConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/metrics/Cache2kCacheMeterBinderProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.cache2k.extra.micrometer.Cache2kCacheMetrics;\nimport org.cache2k.extra.spring.SpringCache2kCacheManager;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Cache2kCacheMeterBinderProvider}.\n *\n * @author Stephane Nicoll\n */\nclass Cache2kCacheMeterBinderProviderTests {\n\n\t@Test\n\tvoid cache2kCacheProvider() {\n\t\tSpringCache2kCacheManager cacheManager = new SpringCache2kCacheManager()\n\t\t\t.addCaches((builder) -> builder.name(\"test\"));\n\t\tMeterBinder meterBinder = new Cache2kCacheMeterBinderProvider().getMeterBinder(cacheManager.getCache(\"test\"),\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(meterBinder).isInstanceOf(Cache2kCacheMetrics.class);\n\t\tcacheManager.destroy();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/metrics/CacheMetricsRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.Collections;\n\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cache.caffeine.CaffeineCache;\nimport org.springframework.cache.transaction.TransactionAwareCacheDecorator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CacheMetricsRegistrar}.\n *\n * @author Stephane Nicoll\n */\nclass CacheMetricsRegistrarTests {\n\n\tprivate final MeterRegistry meterRegistry = new SimpleMeterRegistry();\n\n\t@Test\n\tvoid bindToSupportedCache() {\n\t\tCacheMetricsRegistrar registrar = new CacheMetricsRegistrar(this.meterRegistry,\n\t\t\t\tCollections.singleton(new CaffeineCacheMeterBinderProvider()));\n\t\tassertThat(\n\t\t\t\tregistrar.bindCacheToRegistry(new CaffeineCache(\"test\", Caffeine.newBuilder().recordStats().build())))\n\t\t\t.isTrue();\n\t\tassertThat(this.meterRegistry.get(\"cache.gets\").tags(\"name\", \"test\").meter()).isNotNull();\n\t}\n\n\t@Test\n\tvoid bindToSupportedCacheWrappedInTransactionProxy() {\n\t\tCacheMetricsRegistrar registrar = new CacheMetricsRegistrar(this.meterRegistry,\n\t\t\t\tCollections.singleton(new CaffeineCacheMeterBinderProvider()));\n\t\tassertThat(registrar.bindCacheToRegistry(new TransactionAwareCacheDecorator(\n\t\t\t\tnew CaffeineCache(\"test\", Caffeine.newBuilder().recordStats().build()))))\n\t\t\t.isTrue();\n\t\tassertThat(this.meterRegistry.get(\"cache.gets\").tags(\"name\", \"test\").meter()).isNotNull();\n\t}\n\n\t@Test\n\tvoid bindToUnsupportedCache() {\n\t\tCacheMetricsRegistrar registrar = new CacheMetricsRegistrar(this.meterRegistry, Collections.emptyList());\n\t\tassertThat(\n\t\t\t\tregistrar.bindCacheToRegistry(new CaffeineCache(\"test\", Caffeine.newBuilder().recordStats().build())))\n\t\t\t.isFalse();\n\t\tassertThat(this.meterRegistry.find(\"cache.gets\").tags(\"name\", \"test\").meter()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/metrics/CaffeineCacheMeterBinderProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.Collections;\n\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.cache.CaffeineCacheMetrics;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cache.caffeine.CaffeineCache;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CaffeineCacheMeterBinderProvider}.\n *\n * @author Stephane Nicoll\n */\nclass CaffeineCacheMeterBinderProviderTests {\n\n\t@Test\n\tvoid caffeineCacheProvider() {\n\t\tCaffeineCache cache = new CaffeineCache(\"test\", Caffeine.newBuilder().build());\n\t\tMeterBinder meterBinder = new CaffeineCacheMeterBinderProvider().getMeterBinder(cache, Collections.emptyList());\n\t\tassertThat(meterBinder).isInstanceOf(CaffeineCacheMetrics.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/metrics/HazelcastCacheMeterBinderProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.Collections;\n\nimport com.hazelcast.map.IMap;\nimport com.hazelcast.spring.cache.HazelcastCache;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.cache.HazelcastCacheMetrics;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.cache.metrics.HazelcastCacheMeterBinderProvider.HazelcastCacheMeterBinderProviderRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HazelcastCacheMeterBinderProvider}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass HazelcastCacheMeterBinderProviderTests {\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid hazelcastCacheProvider() {\n\t\tIMap<Object, Object> nativeCache = mock(IMap.class);\n\t\tgiven(nativeCache.getName()).willReturn(\"test\");\n\t\tHazelcastCache cache = new HazelcastCache(nativeCache);\n\t\tMeterBinder meterBinder = new HazelcastCacheMeterBinderProvider().getMeterBinder(cache,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(meterBinder).isInstanceOf(HazelcastCacheMetrics.class);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew HazelcastCacheMeterBinderProviderRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(HazelcastCache.class, \"getNativeCache\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(HazelcastCacheMetrics.class)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/metrics/JCacheCacheMeterBinderProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.cache.JCacheMetrics;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.cache.jcache.JCacheCache;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JCacheCacheMeterBinderProvider}.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(MockitoExtension.class)\nclass JCacheCacheMeterBinderProviderTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate javax.cache.Cache<Object, Object> nativeCache;\n\n\t@Test\n\tvoid jCacheCacheProvider() throws URISyntaxException {\n\t\tjavax.cache.CacheManager cacheManager = mock(javax.cache.CacheManager.class);\n\t\tgiven(cacheManager.getURI()).willReturn(new URI(\"/test\"));\n\t\tgiven(this.nativeCache.getCacheManager()).willReturn(cacheManager);\n\t\tgiven(this.nativeCache.getName()).willReturn(\"test\");\n\t\tJCacheCache cache = new JCacheCache(this.nativeCache);\n\t\tMeterBinder meterBinder = new JCacheCacheMeterBinderProvider().getMeterBinder(cache, Collections.emptyList());\n\t\tassertThat(meterBinder).isInstanceOf(JCacheMetrics.class);\n\t\tassertThat(meterBinder).extracting(\"registerCacheRemovalsAsFunctionCounter\").isEqualTo(false);\n\t}\n\n\t@Test\n\tvoid jCacheCacheProviderRegisteringRemovalsAsAFunctionCounter() throws URISyntaxException {\n\t\tjavax.cache.CacheManager cacheManager = mock(javax.cache.CacheManager.class);\n\t\tgiven(cacheManager.getURI()).willReturn(new URI(\"/test\"));\n\t\tgiven(this.nativeCache.getCacheManager()).willReturn(cacheManager);\n\t\tgiven(this.nativeCache.getName()).willReturn(\"test\");\n\t\tJCacheCache cache = new JCacheCache(this.nativeCache);\n\t\tMeterBinder meterBinder = new JCacheCacheMeterBinderProvider(true).getMeterBinder(cache,\n\t\t\t\tCollections.emptyList());\n\t\tassertThat(meterBinder).isInstanceOf(JCacheMetrics.class);\n\t\tassertThat(meterBinder).extracting(\"registerCacheRemovalsAsFunctionCounter\").isEqualTo(true);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/java/org/springframework/boot/cache/metrics/RedisCacheMeterBinderProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.data.redis.cache.RedisCache;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RedisCacheMeterBinderProvider}.\n *\n * @author Stephane Nicoll\n */\nclass RedisCacheMeterBinderProviderTests {\n\n\t@Test\n\tvoid redisCacheProvider() {\n\t\tRedisCache cache = mock(RedisCache.class);\n\t\tgiven(cache.getName()).willReturn(\"test\");\n\t\tMeterBinder meterBinder = new RedisCacheMeterBinderProvider().getMeterBinder(cache, Collections.emptyList());\n\t\tassertThat(meterBinder).isInstanceOf(RedisCacheMetrics.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/resources/META-INF/services/javax.cache.spi.CachingProvider",
    "content": "#\n# Test JSR 107 provider for testing purposes only.\n#\norg.springframework.boot.cache.autoconfigure.MockCachingProvider\n"
  },
  {
    "path": "module/spring-boot-cache/src/test/resources/org/springframework/boot/cache/autoconfigure/hazelcast-specific.xml",
    "content": "<hazelcast xsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t   xmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n\t<queue name=\"foobar\"/>\n\n\t<map name=\"foobar\">\n\t\t<time-to-live-seconds>3600</time-to-live-seconds>\n\t\t<max-idle-seconds>600</max-idle-seconds>\n\t</map>\n\n\t<network>\n\t\t<join>\n\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t<multicast enabled=\"false\"/>\n\t\t</join>\n\t</network>\n\n</hazelcast>\n"
  },
  {
    "path": "module/spring-boot-cache-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-metadata\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Cache Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-cache\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-cache-test/src/main/java/org/springframework/boot/cache/test/autoconfigure/AutoConfigureCache.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.cache.CacheType;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.support.NoOpCacheManager;\n\n/**\n * Annotation that can be applied to a test class to customize the\n * {@linkplain #cacheProvider() cache provider}. By default, a {@link NoOpCacheManager} is\n * auto-configured\n * <p>\n * As for the regular auto-configuration, this has no effect if a custom\n * {@link CacheManager} is defined.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureCache {\n\n\t/**\n\t * The {@link CacheType} to configure, overriding the behavior for testing purposes.\n\t * @return the cache type to configure\n\t */\n\t@PropertyMapping(\"spring.cache.type\")\n\tCacheType cacheProvider() default CacheType.NONE;\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache-test/src/main/java/org/springframework/boot/cache/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for testing code that uses the cache abstraction.\n */\n@NullMarked\npackage org.springframework.boot.cache.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cache-test/src/main/resources/META-INF/spring/org.springframework.boot.cache.test.autoconfigure.AutoConfigureCache.imports",
    "content": "org.springframework.boot.cache.autoconfigure.CacheAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-cache-test/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-cache-test/src/test/java/org/springframework/boot/cache/test/autoconfigure/AutoConfigureCacheIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.support.NoOpCacheManager;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureCache @AutoConfigureCache}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@AutoConfigureCache\nclass AutoConfigureCacheIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid shouldConfigureNoOpCacheManager() {\n\t\tCacheManager bean = this.applicationContext.getBean(CacheManager.class);\n\t\tassertThat(bean).isInstanceOf(NoOpCacheManager.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cache-test/src/test/java/org/springframework/boot/cache/test/autoconfigure/AutoConfigureCacheWithExistingCacheManagerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cache.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.concurrent.ConcurrentMapCacheManager;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureCache @AutoConfigureCache} with an existing\n * {@link CacheManager}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@AutoConfigureCache\nclass AutoConfigureCacheWithExistingCacheManagerIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid shouldNotReplaceExistingCacheManager() {\n\t\tCacheManager bean = this.applicationContext.getBean(CacheManager.class);\n\t\tassertThat(bean).isInstanceOf(ConcurrentMapCacheManager.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class Config {\n\n\t\t@Bean\n\t\tConcurrentMapCacheManager existingCacheManager() {\n\t\t\treturn new ConcurrentMapCacheManager();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Cassandra\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.apache.cassandra:java-driver-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"org.testcontainers:testcontainers-cassandra\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-cassandra\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/java/org/springframework/boot/cassandra/autoconfigure/CassandraAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.config.DriverConfigLoader;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Integration tests for {@link CassandraAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass CassandraAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class))\n\t\t.withPropertyValues(\n\t\t\t\t\"spring.cassandra.contact-points:\" + cassandra.getHost() + \":\" + cassandra.getFirstMappedPort(),\n\t\t\t\t\"spring.cassandra.local-datacenter=datacenter1\", \"spring.cassandra.connection.connect-timeout=60s\",\n\t\t\t\t\"spring.cassandra.connection.init-query-timeout=60s\", \"spring.cassandra.request.timeout=60s\");\n\n\t@Test\n\tvoid whenTheContextIsClosedThenTheDriverConfigLoaderIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(DriverConfigLoaderSpyConfiguration.class).run((context) -> {\n\t\t\tassertThat(((BeanDefinitionRegistry) context.getSourceApplicationContext())\n\t\t\t\t.getBeanDefinition(\"cassandraDriverConfigLoader\")\n\t\t\t\t.getDestroyMethodName()).isEmpty();\n\t\t\t// Initialize lazy bean\n\t\t\tcontext.getBean(CqlSession.class);\n\t\t\tDriverConfigLoader driverConfigLoader = context.getBean(DriverConfigLoader.class);\n\t\t\tcontext.close();\n\t\t\tthen(driverConfigLoader).should().close();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DriverConfigLoaderSpyConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor driverConfigLoaderSpy() {\n\t\t\treturn new BeanPostProcessor() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\t\t\tif (bean instanceof DriverConfigLoader) {\n\t\t\t\t\t\treturn spy(bean);\n\t\t\t\t\t}\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/java/org/springframework/boot/cassandra/autoconfigure/CassandraAutoConfigurationWithPasswordAuthenticationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport java.net.InetSocketAddress;\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.TimeUnit;\n\nimport com.datastax.oss.driver.api.core.ConsistencyLevel;\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport com.datastax.oss.driver.api.core.cql.SimpleStatement;\nimport org.junit.jupiter.api.Test;\nimport org.rnorth.ducttape.TimeoutException;\nimport org.rnorth.ducttape.unreliables.Unreliables;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.containers.ContainerLaunchException;\nimport org.testcontainers.containers.wait.strategy.AbstractWaitStrategy;\nimport org.testcontainers.images.builder.Transferable;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link CassandraAutoConfiguration} that only uses password authentication.\n *\n * @author Stephane Nicoll\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass CassandraAutoConfigurationWithPasswordAuthenticationIntegrationTests {\n\n\t@Container\n\tstatic final CassandraContainer cassandra = TestImage.container(PasswordAuthenticatorCassandraContainer.class)\n\t\t.withStartupAttempts(5)\n\t\t.waitingFor(new CassandraWaitStrategy());\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class))\n\t\t.withPropertyValues(\n\t\t\t\t\"spring.cassandra.contact-points:\" + cassandra.getHost() + \":\" + cassandra.getFirstMappedPort(),\n\t\t\t\t\"spring.cassandra.local-datacenter=datacenter1\", \"spring.cassandra.connection.connect-timeout=60s\",\n\t\t\t\t\"spring.cassandra.connection.init-query-timeout=60s\", \"spring.cassandra.request.timeout=60s\");\n\n\t@Test\n\tvoid authenticationWithValidUsernameAndPassword() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.username=cassandra\", \"spring.cassandra.password=cassandra\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleStatement select = SimpleStatement.newInstance(\"SELECT release_version FROM system.local\")\n\t\t\t\t\t.setConsistencyLevel(ConsistencyLevel.LOCAL_ONE);\n\t\t\t\tassertThat(context.getBean(CqlSession.class).execute(select).one()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid authenticationWithInvalidCredentials() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.username=not-a-user\", \"spring.cassandra.password=invalid-password\")\n\t\t\t.run((context) -> assertThatExceptionOfType(BeanCreationException.class)\n\t\t\t\t.isThrownBy(() -> context.getBean(CqlSession.class))\n\t\t\t\t.withMessageContaining(\"Authentication error\"));\n\t}\n\n\tstatic final class PasswordAuthenticatorCassandraContainer extends CassandraContainer {\n\n\t\tPasswordAuthenticatorCassandraContainer(DockerImageName dockerImageName) {\n\t\t\tsuper(dockerImageName);\n\t\t}\n\n\t\t@Override\n\t\tprotected void containerIsCreated(String containerId) {\n\t\t\tString config = copyFileFromContainer(\"/etc/cassandra/cassandra.yaml\",\n\t\t\t\t\t(stream) -> StreamUtils.copyToString(stream, StandardCharsets.UTF_8));\n\t\t\tString updatedConfig = config.replace(\"authenticator: AllowAllAuthenticator\",\n\t\t\t\t\t\"authenticator: PasswordAuthenticator\");\n\t\t\tcopyFileToContainer(Transferable.of(updatedConfig.getBytes(StandardCharsets.UTF_8)),\n\t\t\t\t\t\"/etc/cassandra/cassandra.yaml\");\n\t\t}\n\n\t}\n\n\tstatic final class CassandraWaitStrategy extends AbstractWaitStrategy {\n\n\t\t@Override\n\t\tprotected void waitUntilReady() {\n\t\t\ttry {\n\t\t\t\tUnreliables.retryUntilSuccess((int) this.startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> {\n\t\t\t\t\tgetRateLimiter().doWhenReady(() -> cqlSessionBuilder().build());\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (TimeoutException ex) {\n\t\t\t\tthrow new ContainerLaunchException(\n\t\t\t\t\t\t\"Timed out waiting for Cassandra to be accessible for query execution\");\n\t\t\t}\n\t\t}\n\n\t\tprivate CqlSessionBuilder cqlSessionBuilder() {\n\t\t\treturn CqlSession.builder()\n\t\t\t\t.addContactPoint(new InetSocketAddress(this.waitStrategyTarget.getHost(),\n\t\t\t\t\t\tthis.waitStrategyTarget.getFirstMappedPort()))\n\t\t\t\t.withLocalDatacenter(\"datacenter1\")\n\t\t\t\t.withAuthCredentials(\"cassandra\", \"cassandra\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/java/org/springframework/boot/cassandra/docker/compose/CassandraDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.docker.compose;\n\nimport java.util.List;\n\nimport org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails.Node;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for {@link CassandraDockerComposeConnectionDetailsFactory}.\n *\n * @author Scott Frederick\n */\nclass CassandraDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"cassandra-compose.yaml\", image = TestImage.CASSANDRA)\n\tvoid runCreatesConnectionDetails(CassandraConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"cassandra-ssl-compose.yaml\", image = TestImage.CASSANDRA, additionalResources = {\n\t\t\t\"server-keystore.p12\", \"server-truststore.p12\", \"client-keystore.p12\", \"client-truststore.p12\" })\n\tvoid runWithSslCreatesConnectionDetails(CassandraConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\tprivate void assertConnectionDetails(CassandraConnectionDetails connectionDetails) {\n\t\tList<Node> contactPoints = connectionDetails.getContactPoints();\n\t\tassertThat(contactPoints).hasSize(1);\n\t\tNode node = contactPoints.get(0);\n\t\tassertThat(node.host()).isNotNull();\n\t\tassertThat(node.port()).isGreaterThan(0);\n\t\tassertThat(connectionDetails.getUsername()).isNull();\n\t\tassertThat(connectionDetails.getPassword()).isNull();\n\t\tassertThat(connectionDetails.getLocalDatacenter()).isEqualTo(\"testdc1\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/java/org/springframework/boot/cassandra/testcontainers/CassandraContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.testcontainers;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CassandraContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass CassandraContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);\n\n\t@Autowired(required = false)\n\tprivate CassandraConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate CqlSession cqlSession;\n\n\t@Test\n\tvoid connectionCanBeMadeToCassandraContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tassertThat(this.cqlSession.getMetadata().getNodes()).hasSize(1);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(CassandraAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/resources/org/springframework/boot/cassandra/docker/compose/cassandra-compose.yaml",
    "content": "services:\n  cassandra:\n    image: '{imageName}'\n    ports:\n      - '9042'\n    environment:\n      - 'CASSANDRA_SNITCH=GossipingPropertyFileSnitch'\n      - 'JVM_OPTS=-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0'\n      - 'HEAP_NEWSIZE=128M'\n      - 'MAX_HEAP_SIZE=1024M'\n      - 'CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch'\n      - 'CASSANDRA_DC=testdc1'\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/resources/org/springframework/boot/cassandra/docker/compose/cassandra-ssl-compose.yaml",
    "content": "services:\n  cassandra:\n    image: '{imageName}'\n    ports:\n      - '9042'\n    environment:\n      - 'CASSANDRA_SNITCH=GossipingPropertyFileSnitch'\n      - 'JVM_OPTS=-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0'\n      - 'HEAP_NEWSIZE=128M'\n      - 'MAX_HEAP_SIZE=1024M'\n      - 'CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch'\n      - 'CASSANDRA_DC=testdc1'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_ENABLED: true'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_REQUIRE_CLIENT_AUTH: true'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_KEYSTORE: /run/secrets/ssl/server-keystore.p12'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_KEYSTORE_PASSWORD: password'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_TRUSTSTORE: /run/secrets/server-truststore.p12'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_TRUSTSTORE_PASSWORD: password'\n      - 'CASSANDRA_CLIENT_ENCRYPTION_OPTIONS_STORE_TYPE: PKCS12'\n    labels:\n      - 'org.springframework.boot.sslbundle.jks.keystore.type:PKCS12'\n      - 'org.springframework.boot.sslbundle.jks.keystore.location=client-keystore.p12'\n      - 'org.springframework.boot.sslbundle.jks.keystore.password=password'\n      - 'org.springframework.boot.sslbundle.jks.truststore.type=PKCS12'\n      - 'org.springframework.boot.sslbundle.jks.truststore.location=client-truststore.p12'\n      - 'org.springframework.boot.sslbundle.jks.truststore.password=password'\n    secrets:\n      - server-keystore\n      - server-truststore\nsecrets:\n  server-keystore:\n    file: ./server-keystore.p12\n  server-truststore:\n    file: ./server-truststore.p12"
  },
  {
    "path": "module/spring-boot-cassandra/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/CassandraAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport com.datastax.oss.driver.api.core.config.DefaultDriverOption;\nimport com.datastax.oss.driver.api.core.config.DriverConfigLoader;\nimport com.datastax.oss.driver.api.core.config.DriverOption;\nimport com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;\nimport com.datastax.oss.driver.api.core.ssl.ProgrammaticSslEngineFactory;\nimport com.datastax.oss.driver.internal.core.config.typesafe.DefaultDriverConfigLoader;\nimport com.datastax.oss.driver.internal.core.config.typesafe.DefaultProgrammaticDriverConfigLoaderBuilder;\nimport com.typesafe.config.Config;\nimport com.typesafe.config.ConfigFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraProperties.Connection;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraProperties.Controlconnection;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraProperties.Request;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraProperties.Ssl;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraProperties.Throttler;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraProperties.ThrottlerType;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Cassandra.\n *\n * @author Julien Dubois\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Steffen F. Qvistgaard\n * @author Ittay Stern\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(CqlSession.class)\n@EnableConfigurationProperties(CassandraProperties.class)\npublic final class CassandraAutoConfiguration {\n\n\tprivate static final Config SPRING_BOOT_DEFAULTS;\n\tstatic {\n\t\tCassandraDriverOptions options = new CassandraDriverOptions();\n\t\toptions.add(DefaultDriverOption.CONTACT_POINTS, Collections.singletonList(\"127.0.0.1:9042\"));\n\t\toptions.add(DefaultDriverOption.PROTOCOL_COMPRESSION, \"none\");\n\t\toptions.add(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT, (int) Duration.ofSeconds(5).toMillis());\n\t\tSPRING_BOOT_DEFAULTS = options.build();\n\t}\n\n\tprivate final CassandraProperties properties;\n\n\tCassandraAutoConfiguration(CassandraProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(CassandraConnectionDetails.class)\n\tPropertiesCassandraConnectionDetails cassandraConnectionDetails(ObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesCassandraConnectionDetails(this.properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Lazy\n\tCqlSession cassandraSession(CqlSessionBuilder cqlSessionBuilder) {\n\t\treturn cqlSessionBuilder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\tCqlSessionBuilder cassandraSessionBuilder(DriverConfigLoader driverConfigLoader,\n\t\t\tCassandraConnectionDetails connectionDetails,\n\t\t\tObjectProvider<CqlSessionBuilderCustomizer> builderCustomizers) {\n\t\tCqlSessionBuilder builder = CqlSession.builder().withConfigLoader(driverConfigLoader);\n\t\tconfigureAuthentication(builder, connectionDetails);\n\t\tconfigureSsl(builder, connectionDetails);\n\t\tbuilder.withKeyspace(this.properties.getKeyspaceName());\n\t\tbuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder;\n\t}\n\n\tprivate void configureAuthentication(CqlSessionBuilder builder, CassandraConnectionDetails connectionDetails) {\n\t\tString username = connectionDetails.getUsername();\n\t\tString password = connectionDetails.getPassword();\n\t\tif (username != null && password != null) {\n\t\t\tbuilder.withAuthCredentials(username, password);\n\t\t}\n\t}\n\n\tprivate void configureSsl(CqlSessionBuilder builder, CassandraConnectionDetails connectionDetails) {\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tif (sslBundle == null) {\n\t\t\treturn;\n\t\t}\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tAssert.state(options.getEnabledProtocols() == null, \"SSL protocol options cannot be specified with Cassandra\");\n\t\tbuilder\n\t\t\t.withSslEngineFactory(new ProgrammaticSslEngineFactory(sslBundle.createSslContext(), options.getCiphers()));\n\t}\n\n\t@Bean(destroyMethod = \"\")\n\t@ConditionalOnMissingBean\n\tDriverConfigLoader cassandraDriverConfigLoader(CassandraConnectionDetails connectionDetails,\n\t\t\tObjectProvider<DriverConfigLoaderBuilderCustomizer> builderCustomizers) {\n\t\tProgrammaticDriverConfigLoaderBuilder builder = new DefaultProgrammaticDriverConfigLoaderBuilder(\n\t\t\t\t() -> cassandraConfiguration(connectionDetails), DefaultDriverConfigLoader.DEFAULT_ROOT_PATH);\n\t\tbuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate Config cassandraConfiguration(CassandraConnectionDetails connectionDetails) {\n\t\tConfigFactory.invalidateCaches();\n\t\tConfig config = ConfigFactory.defaultOverrides();\n\t\tconfig = config.withFallback(mapConfig(connectionDetails));\n\t\tif (this.properties.getConfig() != null) {\n\t\t\tconfig = config.withFallback(loadConfig(this.properties.getConfig()));\n\t\t}\n\t\tconfig = config.withFallback(SPRING_BOOT_DEFAULTS);\n\t\tconfig = config.withFallback(ConfigFactory.defaultReferenceUnresolved());\n\t\treturn config.resolve();\n\t}\n\n\tprivate Config loadConfig(Resource resource) {\n\t\ttry {\n\t\t\treturn ConfigFactory.parseURL(resource.getURL());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to load cassandra configuration from \" + resource, ex);\n\t\t}\n\t}\n\n\tprivate Config mapConfig(CassandraConnectionDetails connectionDetails) {\n\t\tCassandraDriverOptions options = new CassandraDriverOptions();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.properties.getSessionName())\n\t\t\t.whenHasText()\n\t\t\t.to((sessionName) -> options.add(DefaultDriverOption.SESSION_NAME, sessionName));\n\t\tmap.from(connectionDetails.getUsername())\n\t\t\t.to((value) -> options.add(DefaultDriverOption.AUTH_PROVIDER_USER_NAME, value)\n\t\t\t\t.add(DefaultDriverOption.AUTH_PROVIDER_PASSWORD, connectionDetails.getPassword()));\n\t\tmap.from(this.properties::getCompression)\n\t\t\t.to((compression) -> options.add(DefaultDriverOption.PROTOCOL_COMPRESSION, compression));\n\t\tmapConnectionOptions(options);\n\t\tmapPoolingOptions(options);\n\t\tmapRequestOptions(options);\n\t\tmapControlConnectionOptions(options);\n\t\tmap.from(mapContactPoints(connectionDetails))\n\t\t\t.to((contactPoints) -> options.add(DefaultDriverOption.CONTACT_POINTS, contactPoints));\n\t\tmap.from(connectionDetails.getLocalDatacenter())\n\t\t\t.whenHasText()\n\t\t\t.to((localDatacenter) -> options.add(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, localDatacenter));\n\t\treturn options.build();\n\t}\n\n\tprivate void mapConnectionOptions(CassandraDriverOptions options) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tConnection connectionProperties = this.properties.getConnection();\n\t\tmap.from(connectionProperties::getConnectTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((connectTimeout) -> options.add(DefaultDriverOption.CONNECTION_CONNECT_TIMEOUT, connectTimeout));\n\t\tmap.from(connectionProperties::getInitQueryTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((initQueryTimeout) -> options.add(DefaultDriverOption.CONNECTION_INIT_QUERY_TIMEOUT, initQueryTimeout));\n\t}\n\n\tprivate void mapPoolingOptions(CassandraDriverOptions options) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tCassandraProperties.Pool poolProperties = this.properties.getPool();\n\t\tmap.from(poolProperties::getIdleTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((idleTimeout) -> options.add(DefaultDriverOption.HEARTBEAT_TIMEOUT, idleTimeout));\n\t\tmap.from(poolProperties::getHeartbeatInterval)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((heartBeatInterval) -> options.add(DefaultDriverOption.HEARTBEAT_INTERVAL, heartBeatInterval));\n\t}\n\n\tprivate void mapRequestOptions(CassandraDriverOptions options) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRequest requestProperties = this.properties.getRequest();\n\t\tmap.from(requestProperties::getTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to(((timeout) -> options.add(DefaultDriverOption.REQUEST_TIMEOUT, timeout)));\n\t\tmap.from(requestProperties::getConsistency)\n\t\t\t.to(((consistency) -> options.add(DefaultDriverOption.REQUEST_CONSISTENCY, consistency)));\n\t\tmap.from(requestProperties::getSerialConsistency)\n\t\t\t.to((serialConsistency) -> options.add(DefaultDriverOption.REQUEST_SERIAL_CONSISTENCY, serialConsistency));\n\t\tmap.from(requestProperties::getPageSize)\n\t\t\t.to((pageSize) -> options.add(DefaultDriverOption.REQUEST_PAGE_SIZE, pageSize));\n\t\tThrottler throttlerProperties = requestProperties.getThrottler();\n\t\tmap.from(throttlerProperties::getType)\n\t\t\t.as(ThrottlerType::type)\n\t\t\t.to((type) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_CLASS, type));\n\t\tmap.from(throttlerProperties::getMaxQueueSize)\n\t\t\t.to((maxQueueSize) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE, maxQueueSize));\n\t\tmap.from(throttlerProperties::getMaxConcurrentRequests)\n\t\t\t.to((maxConcurrentRequests) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_CONCURRENT_REQUESTS,\n\t\t\t\t\tmaxConcurrentRequests));\n\t\tmap.from(throttlerProperties::getMaxRequestsPerSecond)\n\t\t\t.to((maxRequestsPerSecond) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_REQUESTS_PER_SECOND,\n\t\t\t\t\tmaxRequestsPerSecond));\n\t\tmap.from(throttlerProperties::getDrainInterval)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((drainInterval) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_DRAIN_INTERVAL, drainInterval));\n\t}\n\n\tprivate void mapControlConnectionOptions(CassandraDriverOptions options) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tControlconnection controlProperties = this.properties.getControlconnection();\n\t\tmap.from(controlProperties::getTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((timeout) -> options.add(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT, timeout));\n\t}\n\n\tprivate List<String> mapContactPoints(CassandraConnectionDetails connectionDetails) {\n\t\treturn connectionDetails.getContactPoints().stream().map((node) -> node.host() + \":\" + node.port()).toList();\n\t}\n\n\tprivate static final class CassandraDriverOptions {\n\n\t\tprivate final Map<String, @Nullable String> options = new LinkedHashMap<>();\n\n\t\tprivate CassandraDriverOptions add(DriverOption option, @Nullable String value) {\n\t\t\tString key = createKeyFor(option);\n\t\t\tthis.options.put(key, value);\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate CassandraDriverOptions add(DriverOption option, int value) {\n\t\t\treturn add(option, String.valueOf(value));\n\t\t}\n\n\t\tprivate CassandraDriverOptions add(DriverOption option, Enum<?> value) {\n\t\t\treturn add(option, value.name());\n\t\t}\n\n\t\tprivate CassandraDriverOptions add(DriverOption option, List<String> values) {\n\t\t\tfor (int i = 0; i < values.size(); i++) {\n\t\t\t\tthis.options.put(String.format(\"%s.%s\", createKeyFor(option), i), values.get(i));\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tprivate Config build() {\n\t\t\treturn ConfigFactory.parseMap(this.options, \"Environment\");\n\t\t}\n\n\t\tprivate static String createKeyFor(DriverOption option) {\n\t\t\treturn String.format(\"%s.%s\", DefaultDriverConfigLoader.DEFAULT_ROOT_PATH, option.getPath());\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link CassandraProperties} to {@link CassandraConnectionDetails}.\n\t */\n\tstatic final class PropertiesCassandraConnectionDetails implements CassandraConnectionDetails {\n\n\t\tprivate final CassandraProperties properties;\n\n\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\tprivate PropertiesCassandraConnectionDetails(CassandraProperties properties, @Nullable SslBundles sslBundles) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.sslBundles = sslBundles;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getContactPoints() {\n\t\t\tList<String> contactPoints = this.properties.getContactPoints();\n\t\t\treturn (contactPoints != null) ? contactPoints.stream().map(this::asNode).toList()\n\t\t\t\t\t: Collections.emptyList();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.properties.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getLocalDatacenter() {\n\t\t\treturn this.properties.getLocalDatacenter();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\tSsl ssl = this.properties.getSsl();\n\t\t\tif (ssl == null || !ssl.isEnabled()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t\t}\n\t\t\treturn SslBundle.systemDefault();\n\t\t}\n\n\t\tprivate Node asNode(String contactPoint) {\n\t\t\tint i = contactPoint.lastIndexOf(':');\n\t\t\tif (i >= 0) {\n\t\t\t\tString portCandidate = contactPoint.substring(i + 1);\n\t\t\t\tInteger port = asPort(portCandidate);\n\t\t\t\tif (port != null) {\n\t\t\t\t\treturn new Node(contactPoint.substring(0, i), port);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn new Node(contactPoint, this.properties.getPort());\n\t\t}\n\n\t\tprivate @Nullable Integer asPort(String value) {\n\t\t\ttry {\n\t\t\t\tint i = Integer.parseInt(value);\n\t\t\t\treturn (i > 0 && i < 65535) ? i : null;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/CassandraConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to a Cassandra service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface CassandraConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Cluster node addresses.\n\t * @return the cluster node addresses\n\t */\n\tList<Node> getContactPoints();\n\n\t/**\n\t * Login user of the server.\n\t * @return the login user of the server or {@code null}\n\t */\n\tdefault @Nullable String getUsername() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Login password of the server.\n\t * @return the login password of the server or {@code null}\n\t */\n\tdefault @Nullable String getPassword() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Datacenter that is considered \"local\". Contact points should be from this\n\t * datacenter.\n\t * @return the datacenter that is considered \"local\"\n\t */\n\t@Nullable String getLocalDatacenter();\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * A Cassandra node.\n\t *\n\t * @param host the hostname\n\t * @param port the port\n\t */\n\trecord Node(String host, int port) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/CassandraProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport com.datastax.oss.driver.api.core.DefaultConsistencyLevel;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\n\n/**\n * Configuration properties for Cassandra.\n *\n * @author Julien Dubois\n * @author Phillip Webb\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.cassandra\")\npublic class CassandraProperties {\n\n\t/**\n\t * Location of the configuration file to use.\n\t */\n\tprivate @Nullable Resource config;\n\n\t/**\n\t * Keyspace name to use.\n\t */\n\tprivate @Nullable String keyspaceName;\n\n\t/**\n\t * Name of the Cassandra session.\n\t */\n\tprivate @Nullable String sessionName;\n\n\t/**\n\t * Cluster node addresses in the form 'host:port', or a simple 'host' to use the\n\t * configured port.\n\t */\n\tprivate @Nullable List<String> contactPoints;\n\n\t/**\n\t * Port to use if a contact point does not specify one.\n\t */\n\tprivate int port = 9042;\n\n\t/**\n\t * Datacenter that is considered \"local\". Contact points should be from this\n\t * datacenter.\n\t */\n\tprivate @Nullable String localDatacenter;\n\n\t/**\n\t * Login user of the server.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the server.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Compression supported by the Cassandra binary protocol.\n\t */\n\tprivate @Nullable Compression compression;\n\n\t/**\n\t * Schema action to take at startup.\n\t */\n\tprivate String schemaAction = \"none\";\n\n\t/**\n\t * SSL configuration.\n\t */\n\tprivate Ssl ssl = new Ssl();\n\n\t/**\n\t * Connection configuration.\n\t */\n\tprivate final Connection connection = new Connection();\n\n\t/**\n\t * Pool configuration.\n\t */\n\tprivate final Pool pool = new Pool();\n\n\t/**\n\t * Request configuration.\n\t */\n\tprivate final Request request = new Request();\n\n\t/**\n\t * Control connection configuration.\n\t */\n\tprivate final Controlconnection controlconnection = new Controlconnection();\n\n\tpublic @Nullable Resource getConfig() {\n\t\treturn this.config;\n\t}\n\n\tpublic void setConfig(@Nullable Resource config) {\n\t\tthis.config = config;\n\t}\n\n\tpublic @Nullable String getKeyspaceName() {\n\t\treturn this.keyspaceName;\n\t}\n\n\tpublic void setKeyspaceName(@Nullable String keyspaceName) {\n\t\tthis.keyspaceName = keyspaceName;\n\t}\n\n\tpublic @Nullable String getSessionName() {\n\t\treturn this.sessionName;\n\t}\n\n\tpublic void setSessionName(@Nullable String sessionName) {\n\t\tthis.sessionName = sessionName;\n\t}\n\n\tpublic @Nullable List<String> getContactPoints() {\n\t\treturn this.contactPoints;\n\t}\n\n\tpublic void setContactPoints(@Nullable List<String> contactPoints) {\n\t\tthis.contactPoints = contactPoints;\n\t}\n\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable String getLocalDatacenter() {\n\t\treturn this.localDatacenter;\n\t}\n\n\tpublic void setLocalDatacenter(@Nullable String localDatacenter) {\n\t\tthis.localDatacenter = localDatacenter;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable Compression getCompression() {\n\t\treturn this.compression;\n\t}\n\n\tpublic void setCompression(@Nullable Compression compression) {\n\t\tthis.compression = compression;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic void setSsl(Ssl ssl) {\n\t\tthis.ssl = ssl;\n\t}\n\n\tpublic String getSchemaAction() {\n\t\treturn this.schemaAction;\n\t}\n\n\tpublic void setSchemaAction(String schemaAction) {\n\t\tthis.schemaAction = schemaAction;\n\t}\n\n\tpublic Connection getConnection() {\n\t\treturn this.connection;\n\t}\n\n\tpublic Pool getPool() {\n\t\treturn this.pool;\n\t}\n\n\tpublic Request getRequest() {\n\t\treturn this.request;\n\t}\n\n\tpublic Controlconnection getControlconnection() {\n\t\treturn this.controlconnection;\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn (this.enabled != null) ? this.enabled : this.bundle != null;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\tpublic static class Connection {\n\n\t\t/**\n\t\t * Timeout to use when establishing driver connections.\n\t\t */\n\t\tprivate @Nullable Duration connectTimeout;\n\n\t\t/**\n\t\t * Timeout to use for internal queries that run as part of the initialization\n\t\t * process, just after a connection is opened.\n\t\t */\n\t\tprivate @Nullable Duration initQueryTimeout;\n\n\t\tpublic @Nullable Duration getConnectTimeout() {\n\t\t\treturn this.connectTimeout;\n\t\t}\n\n\t\tpublic void setConnectTimeout(@Nullable Duration connectTimeout) {\n\t\t\tthis.connectTimeout = connectTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getInitQueryTimeout() {\n\t\t\treturn this.initQueryTimeout;\n\t\t}\n\n\t\tpublic void setInitQueryTimeout(@Nullable Duration initQueryTimeout) {\n\t\t\tthis.initQueryTimeout = initQueryTimeout;\n\t\t}\n\n\t}\n\n\tpublic static class Request {\n\n\t\t/**\n\t\t * How long the driver waits for a request to complete.\n\t\t */\n\t\tprivate @Nullable Duration timeout;\n\n\t\t/**\n\t\t * Queries consistency level.\n\t\t */\n\t\tprivate @Nullable DefaultConsistencyLevel consistency;\n\n\t\t/**\n\t\t * Queries serial consistency level.\n\t\t */\n\t\tprivate @Nullable DefaultConsistencyLevel serialConsistency;\n\n\t\t/**\n\t\t * How many rows will be retrieved simultaneously in a single network round-trip.\n\t\t */\n\t\tprivate @Nullable Integer pageSize;\n\n\t\tprivate final Throttler throttler = new Throttler();\n\n\t\tpublic @Nullable Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\tpublic @Nullable DefaultConsistencyLevel getConsistency() {\n\t\t\treturn this.consistency;\n\t\t}\n\n\t\tpublic void setConsistency(@Nullable DefaultConsistencyLevel consistency) {\n\t\t\tthis.consistency = consistency;\n\t\t}\n\n\t\tpublic @Nullable DefaultConsistencyLevel getSerialConsistency() {\n\t\t\treturn this.serialConsistency;\n\t\t}\n\n\t\tpublic void setSerialConsistency(@Nullable DefaultConsistencyLevel serialConsistency) {\n\t\t\tthis.serialConsistency = serialConsistency;\n\t\t}\n\n\t\tpublic @Nullable Integer getPageSize() {\n\t\t\treturn this.pageSize;\n\t\t}\n\n\t\tpublic void setPageSize(@Nullable Integer pageSize) {\n\t\t\tthis.pageSize = pageSize;\n\t\t}\n\n\t\tpublic Throttler getThrottler() {\n\t\t\treturn this.throttler;\n\t\t}\n\n\t}\n\n\t/**\n\t * Pool properties.\n\t */\n\tpublic static class Pool {\n\n\t\t/**\n\t\t * Idle timeout before an idle connection is removed.\n\t\t */\n\t\tprivate @Nullable Duration idleTimeout;\n\n\t\t/**\n\t\t * Heartbeat interval after which a message is sent on an idle connection to make\n\t\t * sure it's still alive.\n\t\t */\n\t\tprivate @Nullable Duration heartbeatInterval;\n\n\t\tpublic @Nullable Duration getIdleTimeout() {\n\t\t\treturn this.idleTimeout;\n\t\t}\n\n\t\tpublic void setIdleTimeout(@Nullable Duration idleTimeout) {\n\t\t\tthis.idleTimeout = idleTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getHeartbeatInterval() {\n\t\t\treturn this.heartbeatInterval;\n\t\t}\n\n\t\tpublic void setHeartbeatInterval(@Nullable Duration heartbeatInterval) {\n\t\t\tthis.heartbeatInterval = heartbeatInterval;\n\t\t}\n\n\t}\n\n\tpublic static class Controlconnection {\n\n\t\t/**\n\t\t * Timeout to use for control queries.\n\t\t */\n\t\tprivate @Nullable Duration timeout;\n\n\t\tpublic @Nullable Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t}\n\n\tpublic static class Throttler {\n\n\t\t/**\n\t\t * Request throttling type.\n\t\t */\n\t\tprivate @Nullable ThrottlerType type;\n\n\t\t/**\n\t\t * Maximum number of requests that can be enqueued when the throttling threshold\n\t\t * is exceeded.\n\t\t */\n\t\tprivate @Nullable Integer maxQueueSize;\n\n\t\t/**\n\t\t * Maximum number of requests that are allowed to execute in parallel.\n\t\t */\n\t\tprivate @Nullable Integer maxConcurrentRequests;\n\n\t\t/**\n\t\t * Maximum allowed request rate.\n\t\t */\n\t\tprivate @Nullable Integer maxRequestsPerSecond;\n\n\t\t/**\n\t\t * How often the throttler attempts to dequeue requests. Set this high enough that\n\t\t * each attempt will process multiple entries in the queue, but not delay requests\n\t\t * too much.\n\t\t */\n\t\tprivate @Nullable Duration drainInterval;\n\n\t\tpublic @Nullable ThrottlerType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic void setType(@Nullable ThrottlerType type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxQueueSize() {\n\t\t\treturn this.maxQueueSize;\n\t\t}\n\n\t\tpublic void setMaxQueueSize(@Nullable Integer maxQueueSize) {\n\t\t\tthis.maxQueueSize = maxQueueSize;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxConcurrentRequests() {\n\t\t\treturn this.maxConcurrentRequests;\n\t\t}\n\n\t\tpublic void setMaxConcurrentRequests(@Nullable Integer maxConcurrentRequests) {\n\t\t\tthis.maxConcurrentRequests = maxConcurrentRequests;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxRequestsPerSecond() {\n\t\t\treturn this.maxRequestsPerSecond;\n\t\t}\n\n\t\tpublic void setMaxRequestsPerSecond(@Nullable Integer maxRequestsPerSecond) {\n\t\t\tthis.maxRequestsPerSecond = maxRequestsPerSecond;\n\t\t}\n\n\t\tpublic @Nullable Duration getDrainInterval() {\n\t\t\treturn this.drainInterval;\n\t\t}\n\n\t\tpublic void setDrainInterval(@Nullable Duration drainInterval) {\n\t\t\tthis.drainInterval = drainInterval;\n\t\t}\n\n\t}\n\n\t/**\n\t * Name of the algorithm used to compress protocol frames.\n\t */\n\tpublic enum Compression {\n\n\t\t/**\n\t\t * Requires 'net.jpountz.lz4:lz4'.\n\t\t */\n\t\tLZ4,\n\n\t\t/**\n\t\t * Requires org.xerial.snappy:snappy-java.\n\t\t */\n\t\tSNAPPY,\n\n\t\t/**\n\t\t * No compression.\n\t\t */\n\t\tNONE\n\n\t}\n\n\tpublic enum ThrottlerType {\n\n\t\t/**\n\t\t * Limit the number of requests that can be executed in parallel.\n\t\t */\n\t\tCONCURRENCY_LIMITING(\"ConcurrencyLimitingRequestThrottler\"),\n\n\t\t/**\n\t\t * Limits the request rate per second.\n\t\t */\n\t\tRATE_LIMITING(\"RateLimitingRequestThrottler\"),\n\n\t\t/**\n\t\t * No request throttling.\n\t\t */\n\t\tNONE(\"PassThroughRequestThrottler\");\n\n\t\tprivate final String type;\n\n\t\tThrottlerType(String type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic String type() {\n\t\t\treturn this.type;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/CqlSessionBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link CqlSessionBuilder} to fine-tune its auto-configuration before it creates a\n * {@link CqlSession}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface CqlSessionBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link CqlSessionBuilder}.\n\t * @param cqlSessionBuilder the builder to customize\n\t */\n\tvoid customize(CqlSessionBuilder cqlSessionBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/DriverConfigLoaderBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.config.DriverConfigLoader;\nimport com.datastax.oss.driver.api.core.config.ProgrammaticDriverConfigLoaderBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link DriverConfigLoaderBuilderCustomizer} to fine-tune its auto-configuration before\n * it creates a {@link DriverConfigLoader}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic interface DriverConfigLoaderBuilderCustomizer {\n\n\t/**\n\t * Customize the {@linkplain ProgrammaticDriverConfigLoaderBuilder DriverConfigLoader\n\t * builder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(ProgrammaticDriverConfigLoaderBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/health/CassandraHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure.health;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.health.CassandraHealthContributorConfigurations.CassandraDriverConfiguration;\nimport org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link CassandraDriverHealthIndicator}.\n *\n * @author Julien Dubois\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafter = { CassandraReactiveHealthContributorAutoConfiguration.class, CassandraAutoConfiguration.class })\n@ConditionalOnClass({ CqlSession.class, CassandraDriverHealthIndicator.class,\n\t\tConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnEnabledHealthIndicator(\"cassandra\")\n@Import(CassandraDriverConfiguration.class)\npublic final class CassandraHealthContributorAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/health/CassandraHealthContributorConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure.health;\n\nimport java.util.Map;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator;\nimport org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Health contributor options for Cassandra.\n *\n * @author Stephane Nicoll\n */\nclass CassandraHealthContributorConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(CqlSession.class)\n\tstatic class CassandraDriverConfiguration\n\t\t\textends CompositeHealthContributorConfiguration<CassandraDriverHealthIndicator, CqlSession> {\n\n\t\tCassandraDriverConfiguration() {\n\t\t\tsuper(CassandraDriverHealthIndicator::new);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = { \"cassandraHealthIndicator\", \"cassandraHealthContributor\" })\n\t\tHealthContributor cassandraHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn createContributor(beanFactory, CqlSession.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(CqlSession.class)\n\tstatic class CassandraReactiveDriverConfiguration extends\n\t\t\tCompositeReactiveHealthContributorConfiguration<CassandraDriverReactiveHealthIndicator, CqlSession> {\n\n\t\tCassandraReactiveDriverConfiguration() {\n\t\t\tsuper(CassandraDriverReactiveHealthIndicator::new);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = { \"cassandraHealthIndicator\", \"cassandraHealthContributor\" })\n\t\tReactiveHealthContributor cassandraHealthContributor(Map<String, CqlSession> sessions) {\n\t\t\treturn createContributor(sessions);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/health/CassandraReactiveHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure.health;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.health.CassandraHealthContributorConfigurations.CassandraReactiveDriverConfiguration;\nimport org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link CassandraDriverReactiveHealthIndicator}.\n *\n * @author Artsiom Yudovin\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = CassandraAutoConfiguration.class)\n@ConditionalOnClass({ CqlSession.class, Flux.class, CassandraDriverReactiveHealthIndicator.class,\n\t\tConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnEnabledHealthIndicator(\"cassandra\")\n@Import(CassandraReactiveDriverConfiguration.class)\npublic final class CassandraReactiveHealthContributorAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Cassandra health.\n */\n@NullMarked\npackage org.springframework.boot.cassandra.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Cassandra.\n */\n@NullMarked\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/docker/compose/CassandraDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.docker.compose;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link CassandraConnectionDetails} for a {@code Cassandra} service.\n *\n * @author Scott Frederick\n */\nclass CassandraDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<CassandraConnectionDetails> {\n\n\tprivate static final int CASSANDRA_PORT = 9042;\n\n\tCassandraDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"cassandra\");\n\t}\n\n\t@Override\n\tprotected CassandraConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new CassandraDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link CassandraConnectionDetails} backed by a {@code Cassandra}\n\t * {@link RunningService}.\n\t */\n\tstatic class CassandraDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements CassandraConnectionDetails {\n\n\t\tprivate final List<Node> contactPoints;\n\n\t\tprivate final String datacenter;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tCassandraDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tCassandraEnvironment cassandraEnvironment = new CassandraEnvironment(service.env());\n\t\t\tthis.contactPoints = List.of(new Node(service.host(), service.ports().get(CASSANDRA_PORT)));\n\t\t\tthis.datacenter = cassandraEnvironment.getDatacenter();\n\t\t\tthis.sslBundle = getSslBundle(service);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getContactPoints() {\n\t\t\treturn this.contactPoints;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLocalDatacenter() {\n\t\t\treturn this.datacenter;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/docker/compose/CassandraEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Cassandra environment details.\n *\n * @author Scott Frederick\n */\nclass CassandraEnvironment {\n\n\tprivate final String datacenter;\n\n\tCassandraEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.datacenter = getDatacenter(env);\n\t}\n\n\tprivate static String getDatacenter(Map<String, @Nullable String> env) {\n\t\tString datacenter = env.getOrDefault(\"CASSANDRA_DC\", env.get(\"CASSANDRA_DATACENTER\"));\n\t\treturn (datacenter != null) ? datacenter : \"datacenter1\";\n\t}\n\n\tString getDatacenter() {\n\t\treturn this.datacenter;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Cassandra service connections.\n */\n@NullMarked\npackage org.springframework.boot.cassandra.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/health/CassandraDriverHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.health;\n\nimport java.util.Collection;\nimport java.util.Optional;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.metadata.Node;\nimport com.datastax.oss.driver.api.core.metadata.NodeState;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.Assert;\n\n/**\n * Simple implementation of a {@link HealthIndicator} returning status information for\n * Cassandra data stores.\n *\n * @author Alexandre Dutra\n * @author Tomasz Lelek\n * @since 4.0.0\n */\npublic class CassandraDriverHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final CqlSession session;\n\n\t/**\n\t * Create a new {@link CassandraDriverHealthIndicator} instance.\n\t * @param session the {@link CqlSession}.\n\t */\n\tpublic CassandraDriverHealthIndicator(CqlSession session) {\n\t\tsuper(\"Cassandra health check failed\");\n\t\tAssert.notNull(session, \"'session' must not be null\");\n\t\tthis.session = session;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tCollection<Node> nodes = this.session.getMetadata().getNodes().values();\n\t\tOptional<Node> nodeUp = nodes.stream().filter((node) -> node.getState() == NodeState.UP).findAny();\n\t\tbuilder.status(nodeUp.isPresent() ? Status.UP : Status.DOWN);\n\t\tnodeUp.map(Node::getCassandraVersion).ifPresent((version) -> builder.withDetail(\"version\", version));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/health/CassandraDriverReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.health;\n\nimport java.util.Collection;\nimport java.util.Optional;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.metadata.Node;\nimport com.datastax.oss.driver.api.core.metadata.NodeState;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.Assert;\n\n/**\n * Simple implementation of a {@link ReactiveHealthIndicator} returning status information\n * for Cassandra data stores.\n *\n * @author Alexandre Dutra\n * @author Tomasz Lelek\n * @since 4.0.0\n */\npublic class CassandraDriverReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate final CqlSession session;\n\n\t/**\n\t * Create a new {@link CassandraDriverReactiveHealthIndicator} instance.\n\t * @param session the {@link CqlSession}.\n\t */\n\tpublic CassandraDriverReactiveHealthIndicator(CqlSession session) {\n\t\tsuper(\"Cassandra health check failed\");\n\t\tAssert.notNull(session, \"'session' must not be null\");\n\t\tthis.session = session;\n\t}\n\n\t@Override\n\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\treturn Mono.fromSupplier(() -> {\n\t\t\tCollection<Node> nodes = this.session.getMetadata().getNodes().values();\n\t\t\tOptional<Node> nodeUp = nodes.stream().filter((node) -> node.getState() == NodeState.UP).findAny();\n\t\t\tbuilder.status(nodeUp.isPresent() ? Status.UP : Status.DOWN);\n\t\t\tnodeUp.map(Node::getCassandraVersion).ifPresent((version) -> builder.withDetail(\"version\", version));\n\t\t\treturn builder.build();\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for Cassandra.\n */\n@NullMarked\npackage org.springframework.boot.cassandra.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/testcontainers/CassandraContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.testcontainers;\n\nimport java.net.InetSocketAddress;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.cassandra.CassandraContainer;\n\nimport org.springframework.boot.cassandra.autoconfigure.CassandraConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link CassandraConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link CassandraContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass CassandraContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<CassandraContainer, CassandraConnectionDetails> {\n\n\t@Override\n\tprotected CassandraConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<CassandraContainer> source) {\n\t\treturn new CassandraContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link CassandraConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class CassandraContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<CassandraContainer> implements CassandraConnectionDetails {\n\n\t\tprivate CassandraContainerConnectionDetails(ContainerConnectionSource<CassandraContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getContactPoints() {\n\t\t\tInetSocketAddress contactPoint = getContainer().getContactPoint();\n\t\t\treturn List.of(new Node(contactPoint.getHostString(), contactPoint.getPort()));\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getLocalDatacenter() {\n\t\t\treturn getContainer().getLocalDatacenter();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/java/org/springframework/boot/cassandra/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Cassandra service connections.\n */\n@NullMarked\npackage org.springframework.boot.cassandra.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.cassandra.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Cassandra health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.cassandra.compression\",\n      \"defaultValue\": \"none\"\n    },\n    {\n      \"name\": \"spring.cassandra.connection.connect-timeout\",\n      \"defaultValue\": \"5s\"\n    },\n    {\n      \"name\": \"spring.cassandra.connection.init-query-timeout\",\n      \"defaultValue\": \"5s\"\n    },\n    {\n      \"name\": \"spring.cassandra.contact-points\",\n      \"defaultValue\": [\n        \"127.0.0.1:9042\"\n      ]\n    },\n    {\n      \"name\": \"spring.cassandra.controlconnection.timeout\",\n      \"defaultValue\": \"5s\"\n    },\n    {\n      \"name\": \"spring.cassandra.pool.heartbeat-interval\",\n      \"defaultValue\": \"30s\"\n    },\n    {\n      \"name\": \"spring.cassandra.pool.idle-timeout\",\n      \"defaultValue\": \"5s\"\n    },\n    {\n      \"name\": \"spring.cassandra.request.page-size\",\n      \"defaultValue\": 5000\n    },\n    {\n      \"name\": \"spring.cassandra.request.throttler.type\",\n      \"defaultValue\": \"none\"\n    },\n    {\n      \"name\": \"spring.cassandra.request.timeout\",\n      \"defaultValue\": \"2s\"\n    },\n    {\n      \"name\": \"spring.cassandra.ssl\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.ssl.enabled\",\n        \"level\": \"error\",\n        \"since\": \"3.1.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.cassandra.schema-action\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"org.springframework.data.cassandra.config.SchemaAction\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration\norg.springframework.boot.cassandra.autoconfigure.health.CassandraHealthContributorAutoConfiguration\norg.springframework.boot.cassandra.autoconfigure.health.CassandraReactiveHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.cassandra.docker.compose.CassandraDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.cassandra.testcontainers.CassandraContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/autoconfigure/CassandraAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.datastax.oss.driver.api.core.CqlIdentifier;\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport com.datastax.oss.driver.api.core.config.DefaultDriverOption;\nimport com.datastax.oss.driver.api.core.config.DriverConfig;\nimport com.datastax.oss.driver.api.core.config.DriverConfigLoader;\nimport com.datastax.oss.driver.api.core.config.DriverExecutionProfile;\nimport com.datastax.oss.driver.internal.core.session.throttling.ConcurrencyLimitingRequestThrottler;\nimport com.datastax.oss.driver.internal.core.session.throttling.PassThroughRequestThrottler;\nimport com.datastax.oss.driver.internal.core.session.throttling.RateLimitingRequestThrottler;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration.PropertiesCassandraConnectionDetails;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link CassandraAutoConfiguration}\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Ittay Stern\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass CassandraAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid cqlSessionBuildHasScopePrototype() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tCqlIdentifier keyspace = CqlIdentifier.fromCql(\"test\");\n\t\t\tCqlSessionBuilder firstBuilder = context.getBean(CqlSessionBuilder.class);\n\t\t\tassertThat(firstBuilder.withKeyspace(keyspace)).hasFieldOrPropertyWithValue(\"keyspace\", keyspace);\n\t\t\tCqlSessionBuilder secondBuilder = context.getBean(CqlSessionBuilder.class);\n\t\t\tassertThat(secondBuilder).hasFieldOrPropertyWithValue(\"keyspace\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid cqlSessionBuilderWithNoSslConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tCqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);\n\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"programmaticSslFactory\", false);\n\t\t});\n\t}\n\n\t@Test\n\tvoid cqlSessionBuilderWithSslEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.ssl.enabled=true\").run((context) -> {\n\t\t\tCqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);\n\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"programmaticSslFactory\", true);\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid cqlSessionBuilderWithSslBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.ssl.bundle=test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password=secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tCqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);\n\t\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"programmaticSslFactory\", true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cqlSessionBuilderWithSslBundleAndSslDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.ssl.enabled=false\", \"spring.cassandra.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tCqlSessionBuilder builder = context.getBean(CqlSessionBuilder.class);\n\t\t\t\tassertThat(builder).hasFieldOrPropertyWithValue(\"programmaticSslFactory\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cqlSessionBuilderWithInvalidSslBundle() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> assertThatException().isThrownBy(() -> context.getBean(CqlSessionBuilder.class))\n\t\t\t\t.withRootCauseInstanceOf(NoSuchSslBundleException.class)\n\t\t\t\t.withMessageContaining(\"test-bundle\"));\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithDefaultConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\tassertThat(context.getBean(DriverConfigLoader.class)\n\t\t\t\t.getInitialConfig()\n\t\t\t\t.getDefaultProfile()\n\t\t\t\t.isDefined(DefaultDriverOption.SESSION_NAME)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithContactPoints() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.contact-points=cluster.example.com:9042\",\n\t\t\t\t\t\"spring.cassandra.local-datacenter=cassandra-eu1\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\t\tDriverExecutionProfile configuration = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(configuration.getStringList(DefaultDriverOption.CONTACT_POINTS))\n\t\t\t\t\t.containsOnly(\"cluster.example.com:9042\");\n\t\t\t\tassertThat(configuration.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))\n\t\t\t\t\t.isEqualTo(\"cassandra-eu1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesCassandraConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.contact-points=localhost:9042\", \"spring.cassandra.username=a-user\",\n\t\t\t\t\t\"spring.cassandra.password=a-password\", \"spring.cassandra.local-datacenter=some-datacenter\")\n\t\t\t.withBean(CassandraConnectionDetails.class, this::cassandraConnectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class)\n\t\t\t\t\t.hasSingleBean(CassandraConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesCassandraConnectionDetails.class);\n\t\t\t\tDriverExecutionProfile configuration = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(configuration.getStringList(DefaultDriverOption.CONTACT_POINTS))\n\t\t\t\t\t.containsOnly(\"cassandra.example.com:9042\");\n\t\t\t\tassertThat(configuration.getString(DefaultDriverOption.AUTH_PROVIDER_USER_NAME)).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(configuration.getString(DefaultDriverOption.AUTH_PROVIDER_PASSWORD)).isEqualTo(\"secret-1\");\n\t\t\t\tassertThat(configuration.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))\n\t\t\t\t\t.isEqualTo(\"datacenter-1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithContactPointAndNoPort() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.contact-points=cluster.example.com,another.example.com:9041\",\n\t\t\t\t\t\"spring.cassandra.local-datacenter=cassandra-eu1\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\t\tDriverExecutionProfile configuration = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(configuration.getStringList(DefaultDriverOption.CONTACT_POINTS))\n\t\t\t\t\t.containsOnly(\"cluster.example.com:9042\", \"another.example.com:9041\");\n\t\t\t\tassertThat(configuration.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))\n\t\t\t\t\t.isEqualTo(\"cassandra-eu1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithContactPointAndNoPortAndCustomPort() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.contact-points=cluster.example.com:9041,another.example.com\",\n\t\t\t\t\t\"spring.cassandra.port=9043\", \"spring.cassandra.local-datacenter=cassandra-eu1\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\t\tDriverExecutionProfile configuration = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(configuration.getStringList(DefaultDriverOption.CONTACT_POINTS))\n\t\t\t\t\t.containsOnly(\"cluster.example.com:9041\", \"another.example.com:9043\");\n\t\t\t\tassertThat(configuration.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))\n\t\t\t\t\t.isEqualTo(\"cassandra-eu1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithCustomSessionName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.session-name=testcluster\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\tassertThat(context.getBean(DriverConfigLoader.class)\n\t\t\t\t.getInitialConfig()\n\t\t\t\t.getDefaultProfile()\n\t\t\t\t.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo(\"testcluster\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithCustomSessionNameAndCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(SimpleDriverConfigLoaderBuilderCustomizerConfig.class)\n\t\t\t.withPropertyValues(\"spring.cassandra.session-name=testcluster\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\t\tassertThat(context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile()\n\t\t\t\t\t.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo(\"overridden-name\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderCustomizeConnectionOptions() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.connection.connect-timeout=200ms\",\n\t\t\t\t\t\"spring.cassandra.connection.init-query-timeout=10\")\n\t\t\t.run((context) -> {\n\t\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.CONNECTION_CONNECT_TIMEOUT)).isEqualTo(200);\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.CONNECTION_INIT_QUERY_TIMEOUT)).isEqualTo(10);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderCustomizePoolOptions() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.pool.idle-timeout=42\", \"spring.cassandra.pool.heartbeat-interval=62\")\n\t\t\t.run((context) -> {\n\t\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.HEARTBEAT_TIMEOUT)).isEqualTo(42);\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.HEARTBEAT_INTERVAL)).isEqualTo(62);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderCustomizeRequestOptions() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.request.timeout=5s\", \"spring.cassandra.request.consistency=two\",\n\t\t\t\t\t\"spring.cassandra.request.serial-consistency=quorum\", \"spring.cassandra.request.page-size=42\")\n\t\t\t.run((context) -> {\n\t\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_TIMEOUT)).isEqualTo(5000);\n\t\t\t\tassertThat(config.getString(DefaultDriverOption.REQUEST_CONSISTENCY)).isEqualTo(\"TWO\");\n\t\t\t\tassertThat(config.getString(DefaultDriverOption.REQUEST_SERIAL_CONSISTENCY)).isEqualTo(\"QUORUM\");\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_PAGE_SIZE)).isEqualTo(42);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderCustomizeControlConnectionOptions() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.controlconnection.timeout=200ms\").run((context) -> {\n\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t.getInitialConfig()\n\t\t\t\t.getDefaultProfile();\n\t\t\tassertThat(config.getInt(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT)).isEqualTo(200);\n\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderUsePassThroughLimitingRequestThrottlerByDefault() {\n\t\tthis.contextRunner.withPropertyValues().run((context) -> {\n\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t.getInitialConfig()\n\t\t\t\t.getDefaultProfile();\n\t\t\tassertThat(config.getString(DefaultDriverOption.REQUEST_THROTTLER_CLASS))\n\t\t\t\t.isEqualTo(PassThroughRequestThrottler.class.getSimpleName());\n\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithRateLimitingRequiresExtraConfiguration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.request.throttler.type=rate-limiting\")\n\t\t\t.run((context) -> assertThatExceptionOfType(BeanCreationException.class)\n\t\t\t\t.isThrownBy(() -> context.getBean(CqlSession.class))\n\t\t\t\t.withMessageContaining(\"Error instantiating class RateLimitingRequestThrottler\")\n\t\t\t\t.withMessageContaining(\"No configuration setting found for key\"));\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderCustomizeConcurrencyLimitingRequestThrottler() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.request.throttler.type=concurrency-limiting\",\n\t\t\t\t\t\"spring.cassandra.request.throttler.max-concurrent-requests=62\",\n\t\t\t\t\t\"spring.cassandra.request.throttler.max-queue-size=72\")\n\t\t\t.run((context) -> {\n\t\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(config.getString(DefaultDriverOption.REQUEST_THROTTLER_CLASS))\n\t\t\t\t\t.isEqualTo(ConcurrencyLimitingRequestThrottler.class.getSimpleName());\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_CONCURRENT_REQUESTS)).isEqualTo(62);\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE)).isEqualTo(72);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderCustomizeRateLimitingRequestThrottler() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.request.throttler.type=rate-limiting\",\n\t\t\t\t\t\"spring.cassandra.request.throttler.max-requests-per-second=62\",\n\t\t\t\t\t\"spring.cassandra.request.throttler.max-queue-size=72\",\n\t\t\t\t\t\"spring.cassandra.request.throttler.drain-interval=16ms\")\n\t\t\t.run((context) -> {\n\t\t\t\tDriverExecutionProfile config = context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile();\n\t\t\t\tassertThat(config.getString(DefaultDriverOption.REQUEST_THROTTLER_CLASS))\n\t\t\t\t\t.isEqualTo(RateLimitingRequestThrottler.class.getSimpleName());\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_REQUESTS_PER_SECOND)).isEqualTo(62);\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE)).isEqualTo(72);\n\t\t\t\tassertThat(config.getInt(DefaultDriverOption.REQUEST_THROTTLER_DRAIN_INTERVAL)).isEqualTo(16);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithConfigComplementSettings() {\n\t\tString configLocation = \"org/springframework/boot/cassandra/autoconfigure/simple.conf\";\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cassandra.session-name=testcluster\",\n\t\t\t\t\t\"spring.cassandra.config=\" + configLocation)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\t\tassertThat(context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile()\n\t\t\t\t\t.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo(\"testcluster\");\n\t\t\t\tassertThat(context.getBean(DriverConfigLoader.class)\n\t\t\t\t\t.getInitialConfig()\n\t\t\t\t\t.getDefaultProfile()\n\t\t\t\t\t.getDuration(DefaultDriverOption.REQUEST_TIMEOUT)).isEqualTo(Duration.ofMillis(500));\n\t\t\t});\n\t}\n\n\t@Test // gh-31238\n\tvoid driverConfigLoaderWithConfigOverridesDefaults() {\n\t\tString configLocation = \"org/springframework/boot/cassandra/autoconfigure/override-defaults.conf\";\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.config=\" + configLocation).run((context) -> {\n\t\t\tDriverExecutionProfile actual = context.getBean(DriverConfigLoader.class)\n\t\t\t\t.getInitialConfig()\n\t\t\t\t.getDefaultProfile();\n\t\t\tassertThat(actual.getString(DefaultDriverOption.SESSION_NAME)).isEqualTo(\"advanced session\");\n\t\t\tassertThat(actual.getDuration(DefaultDriverOption.REQUEST_TIMEOUT)).isEqualTo(Duration.ofSeconds(2));\n\t\t\tassertThat(actual.getStringList(DefaultDriverOption.CONTACT_POINTS))\n\t\t\t\t.isEqualTo(Collections.singletonList(\"1.2.3.4:5678\"));\n\t\t\tassertThat(actual.getBoolean(DefaultDriverOption.RESOLVE_CONTACT_POINTS)).isFalse();\n\t\t\tassertThat(actual.getInt(DefaultDriverOption.REQUEST_PAGE_SIZE)).isEqualTo(11);\n\t\t\tassertThat(actual.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER)).isEqualTo(\"datacenter1\");\n\t\t\tassertThat(actual.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_CONCURRENT_REQUESTS)).isEqualTo(22);\n\t\t\tassertThat(actual.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_REQUESTS_PER_SECOND)).isEqualTo(33);\n\t\t\tassertThat(actual.getInt(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE)).isEqualTo(44);\n\t\t\tassertThat(actual.getDuration(DefaultDriverOption.CONTROL_CONNECTION_TIMEOUT))\n\t\t\t\t.isEqualTo(Duration.ofMillis(5555));\n\t\t\tassertThat(actual.getString(DefaultDriverOption.PROTOCOL_COMPRESSION)).isEqualTo(\"SNAPPY\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid placeholdersInReferenceConfAreResolvedAgainstConfigDerivedFromSpringCassandraProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.request.timeout=60s\").run((context) -> {\n\t\t\tDriverExecutionProfile actual = context.getBean(DriverConfigLoader.class)\n\t\t\t\t.getInitialConfig()\n\t\t\t\t.getDefaultProfile();\n\t\t\tassertThat(actual.getDuration(DefaultDriverOption.REQUEST_TIMEOUT)).isEqualTo(Duration.ofSeconds(60));\n\t\t\tassertThat(actual.getDuration(DefaultDriverOption.METADATA_SCHEMA_REQUEST_TIMEOUT))\n\t\t\t\t.isEqualTo(Duration.ofSeconds(60));\n\t\t});\n\t}\n\n\t@Test\n\tvoid driverConfigLoaderWithConfigCreateProfiles() {\n\t\tString configLocation = \"org/springframework/boot/cassandra/autoconfigure/profiles.conf\";\n\t\tthis.contextRunner.withPropertyValues(\"spring.cassandra.config=\" + configLocation).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DriverConfigLoader.class);\n\t\t\tDriverConfig driverConfig = context.getBean(DriverConfigLoader.class).getInitialConfig();\n\t\t\tassertThat(driverConfig.getProfiles()).containsOnlyKeys(\"default\", \"first\", \"second\");\n\t\t\tassertThat(driverConfig.getProfile(\"first\").getDuration(DefaultDriverOption.REQUEST_TIMEOUT))\n\t\t\t\t.isEqualTo(Duration.ofMillis(100));\n\t\t});\n\t}\n\n\tprivate CassandraConnectionDetails cassandraConnectionDetails() {\n\t\treturn new CassandraConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic List<Node> getContactPoints() {\n\t\t\t\treturn List.of(new Node(\"cassandra.example.com\", 9042));\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getUsername() {\n\t\t\t\treturn \"user-1\";\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getPassword() {\n\t\t\t\treturn \"secret-1\";\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getLocalDatacenter() {\n\t\t\t\treturn \"datacenter-1\";\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleDriverConfigLoaderBuilderCustomizerConfig {\n\n\t\t@Bean\n\t\tDriverConfigLoaderBuilderCustomizer customizer() {\n\t\t\treturn (builder) -> builder.withString(DefaultDriverOption.SESSION_NAME, \"overridden-name\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/autoconfigure/CassandraPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure;\n\nimport java.time.Duration;\n\nimport com.datastax.oss.driver.api.core.config.OptionsMap;\nimport com.datastax.oss.driver.api.core.config.TypedDriverOption;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CassandraProperties}.\n *\n * @author Chris Bono\n * @author Stephane Nicoll\n */\nclass CassandraPropertiesTests {\n\n\t/**\n\t * To let a configuration file override values, {@link CassandraProperties} can't have\n\t * any default hardcoded. This test makes sure that the default that we moved to\n\t * manual meta-data are accurate.\n\t */\n\t@Test\n\tvoid defaultValuesInManualMetadataAreConsistent() {\n\t\tOptionsMap driverDefaults = OptionsMap.driverDefaults();\n\t\t// spring.cassandra.connection.connect-timeout\n\t\tassertThat(driverDefaults.get(TypedDriverOption.CONNECTION_CONNECT_TIMEOUT)).isEqualTo(Duration.ofSeconds(5));\n\t\t// spring.cassandra.connection.init-query-timeout\n\t\tassertThat(driverDefaults.get(TypedDriverOption.CONNECTION_INIT_QUERY_TIMEOUT))\n\t\t\t.isEqualTo(Duration.ofSeconds(5));\n\t\t// spring.cassandra.request.timeout\n\t\tassertThat(driverDefaults.get(TypedDriverOption.REQUEST_TIMEOUT)).isEqualTo(Duration.ofSeconds(2));\n\t\t// spring.cassandra.request.page-size\n\t\tassertThat(driverDefaults.get(TypedDriverOption.REQUEST_PAGE_SIZE)).isEqualTo(5000);\n\t\t// spring.cassandra.request.throttler.type\n\t\tassertThat(driverDefaults.get(TypedDriverOption.REQUEST_THROTTLER_CLASS))\n\t\t\t.isEqualTo(\"PassThroughRequestThrottler\"); // \"none\"\n\t\t// spring.cassandra.pool.heartbeat-interval\n\t\tassertThat(driverDefaults.get(TypedDriverOption.HEARTBEAT_INTERVAL)).isEqualTo(Duration.ofSeconds(30));\n\t\t// spring.cassandra.pool.idle-timeout\n\t\tassertThat(driverDefaults.get(TypedDriverOption.HEARTBEAT_TIMEOUT)).isEqualTo(Duration.ofSeconds(5));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/autoconfigure/health/CassandraHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure.health;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cassandra.health.CassandraDriverHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CassandraHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass CassandraHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CassandraHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runWithoutCqlSessionShouldNotCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(\"cassandraHealthContributor\")\n\t\t\t.doesNotHaveBean(CassandraDriverHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWithCqlSessionShouldCreateDriverIndicator() {\n\t\tthis.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CassandraDriverHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class))\n\t\t\t.withPropertyValues(\"management.health.cassandra.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"cassandraHealthContributor\")\n\t\t\t\t.doesNotHaveBean(CassandraDriverHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/autoconfigure/health/CassandraReactiveHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.autoconfigure.health;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cassandra.health.CassandraDriverReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CassandraReactiveHealthContributorAutoConfiguration}.\n *\n * @author Artsiom Yudovin\n * @author Stephane Nicoll\n */\nclass CassandraReactiveHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CassandraReactiveHealthContributorAutoConfiguration.class,\n\t\t\t\tCassandraHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runWithoutCqlSessionShouldNotCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(\"cassandraHealthContributor\")\n\t\t\t.doesNotHaveBean(CassandraDriverReactiveHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWithCqlSessionShouldCreateIndicator() {\n\t\tthis.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class))\n\t\t\t.run((context) -> assertThat(context).hasBean(\"cassandraHealthContributor\")\n\t\t\t\t.hasSingleBean(CassandraDriverReactiveHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withBean(CqlSession.class, () -> mock(CqlSession.class))\n\t\t\t.withPropertyValues(\"management.health.cassandra.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"cassandraHealthContributor\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/docker/compose/CassandraEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CassandraEnvironment}.\n *\n * @author Scott Frederick\n */\nclass CassandraEnvironmentTests {\n\n\t@Test\n\tvoid getDatacenterWhenDatacenterIsNotSet() {\n\t\tCassandraEnvironment environment = new CassandraEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getDatacenter()).isEqualTo(\"datacenter1\");\n\t}\n\n\t@Test\n\tvoid getDatacenterWhenDcIsSet() {\n\t\tCassandraEnvironment environment = new CassandraEnvironment(Map.of(\"CASSANDRA_DC\", \"testdc1\"));\n\t\tassertThat(environment.getDatacenter()).isEqualTo(\"testdc1\");\n\t}\n\n\t@Test\n\tvoid getDatacenterWhenDatacenterIsSet() {\n\t\tCassandraEnvironment environment = new CassandraEnvironment(Map.of(\"CASSANDRA_DATACENTER\", \"testdc1\"));\n\t\tassertThat(environment.getDatacenter()).isEqualTo(\"testdc1\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/health/CassandraDriverHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.health;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.DriverTimeoutException;\nimport com.datastax.oss.driver.api.core.Version;\nimport com.datastax.oss.driver.api.core.metadata.Metadata;\nimport com.datastax.oss.driver.api.core.metadata.Node;\nimport com.datastax.oss.driver.api.core.metadata.NodeState;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CassandraDriverHealthIndicator}.\n *\n * @author Alexandre Dutra\n * @author Stephane Nicoll\n */\nclass CassandraDriverHealthIndicatorTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenCqlSessionIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new CassandraDriverHealthIndicator(null))\n\t\t\t.withMessage(\"'session' must not be null\");\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid healthWithOneUnhealthyNodeShouldReturnDown() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.DOWN);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid healthWithOneUnknownNodeShouldReturnDown() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UNKNOWN);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid healthWithOneForcedDownNodeShouldReturnDown() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.FORCED_DOWN);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeAndOneUnhealthyNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP, NodeState.DOWN);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeAndOneUnknownNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP, NodeState.UNKNOWN);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeAndOneForcedDownNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP, NodeState.FORCED_DOWN);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid healthWithNodeVersionShouldAddVersionDetail() {\n\t\tCqlSession session = mock(CqlSession.class);\n\t\tMetadata metadata = mock(Metadata.class);\n\t\tgiven(session.getMetadata()).willReturn(metadata);\n\t\tNode node = mock(Node.class);\n\t\tgiven(node.getState()).willReturn(NodeState.UP);\n\t\tgiven(node.getCassandraVersion()).willReturn(Version.V4_0_0);\n\t\tgiven(metadata.getNodes()).willReturn(createNodesWithRandomUUID(Collections.singletonList(node)));\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"version\", Version.V4_0_0);\n\t}\n\n\t@Test\n\tvoid healthWithoutNodeVersionShouldNotAddVersionDetail() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP);\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"version\");\n\t}\n\n\t@Test\n\tvoid healthWithCassandraDownShouldReturnDown() {\n\t\tCqlSession session = mock(CqlSession.class);\n\t\tgiven(session.getMetadata()).willThrow(new DriverTimeoutException(\"Test Exception\"));\n\t\tCassandraDriverHealthIndicator healthIndicator = new CassandraDriverHealthIndicator(session);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"error\",\n\t\t\t\tDriverTimeoutException.class.getName() + \": Test Exception\");\n\t}\n\n\tprivate CqlSession mockCqlSessionWithNodeState(NodeState... nodeStates) {\n\t\tCqlSession session = mock(CqlSession.class);\n\t\tMetadata metadata = mock(Metadata.class);\n\t\tList<Node> nodes = new ArrayList<>();\n\t\tfor (NodeState nodeState : nodeStates) {\n\t\t\tNode node = mock(Node.class);\n\t\t\tgiven(node.getState()).willReturn(nodeState);\n\t\t\tnodes.add(node);\n\t\t}\n\t\tgiven(session.getMetadata()).willReturn(metadata);\n\t\tgiven(metadata.getNodes()).willReturn(createNodesWithRandomUUID(nodes));\n\t\treturn session;\n\t}\n\n\tprivate Map<UUID, Node> createNodesWithRandomUUID(List<Node> nodes) {\n\t\tMap<UUID, Node> indexedNodes = new HashMap<>();\n\t\tnodes.forEach((node) -> indexedNodes.put(UUID.randomUUID(), node));\n\t\treturn indexedNodes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/java/org/springframework/boot/cassandra/health/CassandraDriverReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cassandra.health;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.DriverTimeoutException;\nimport com.datastax.oss.driver.api.core.Version;\nimport com.datastax.oss.driver.api.core.metadata.Metadata;\nimport com.datastax.oss.driver.api.core.metadata.Node;\nimport com.datastax.oss.driver.api.core.metadata.NodeState;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CassandraDriverReactiveHealthIndicator}.\n *\n * @author Alexandre Dutra\n * @author Stephane Nicoll\n */\nclass CassandraDriverReactiveHealthIndicatorTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenCqlSessionIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new CassandraDriverReactiveHealthIndicator(null))\n\t\t\t.withMessage(\"'session' must not be null\");\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.UP))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithOneUnhealthyNodeShouldReturnDown() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.DOWN);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.DOWN))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithOneUnknownNodeShouldReturnDown() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UNKNOWN);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.DOWN))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithOneForcedDownNodeShouldReturnDown() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.FORCED_DOWN);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.DOWN))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeAndOneUnhealthyNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP, NodeState.DOWN);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.UP))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeAndOneUnknownNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP, NodeState.UNKNOWN);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.UP))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithOneHealthyNodeAndOneForcedDownNodeShouldReturnUp() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP, NodeState.FORCED_DOWN);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.UP))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithNodeVersionShouldAddVersionDetail() {\n\t\tCqlSession session = mock(CqlSession.class);\n\t\tMetadata metadata = mock(Metadata.class);\n\t\tgiven(session.getMetadata()).willReturn(metadata);\n\t\tNode node = mock(Node.class);\n\t\tgiven(node.getState()).willReturn(NodeState.UP);\n\t\tgiven(node.getCassandraVersion()).willReturn(Version.V4_0_0);\n\t\tgiven(metadata.getNodes()).willReturn(createNodesWithRandomUUID(Collections.singletonList(node)));\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).containsOnlyKeys(\"version\");\n\t\t\tassertThat(h.getDetails()).containsEntry(\"version\", Version.V4_0_0);\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithoutNodeVersionShouldNotAddVersionDetail() {\n\t\tCqlSession session = mockCqlSessionWithNodeState(NodeState.UP);\n\t\tCassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator(session);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).doesNotContainKey(\"version\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWithCassandraDownShouldReturnDown() {\n\t\tCqlSession session = mock(CqlSession.class);\n\t\tgiven(session.getMetadata()).willThrow(new DriverTimeoutException(\"Test Exception\"));\n\t\tCassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator(\n\t\t\t\tsession);\n\t\tMono<Health> health = cassandraReactiveHealthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.DOWN);\n\t\t\tassertThat(h.getDetails()).containsOnlyKeys(\"error\");\n\t\t\tassertThat(h.getDetails()).containsEntry(\"error\",\n\t\t\t\t\tDriverTimeoutException.class.getName() + \": Test Exception\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\tprivate CqlSession mockCqlSessionWithNodeState(NodeState... nodeStates) {\n\t\tCqlSession session = mock(CqlSession.class);\n\t\tMetadata metadata = mock(Metadata.class);\n\t\tList<Node> nodes = new ArrayList<>();\n\t\tfor (NodeState nodeState : nodeStates) {\n\t\t\tNode node = mock(Node.class);\n\t\t\tgiven(node.getState()).willReturn(nodeState);\n\t\t\tnodes.add(node);\n\t\t}\n\t\tgiven(session.getMetadata()).willReturn(metadata);\n\t\tgiven(metadata.getNodes()).willReturn(createNodesWithRandomUUID(nodes));\n\t\treturn session;\n\t}\n\n\tprivate Map<UUID, Node> createNodesWithRandomUUID(List<Node> nodes) {\n\t\tMap<UUID, Node> indexedNodes = new HashMap<>();\n\t\tnodes.forEach((node) -> indexedNodes.put(UUID.randomUUID(), node));\n\t\treturn indexedNodes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/resources/org/springframework/boot/cassandra/autoconfigure/override-defaults.conf",
    "content": "datastax-java-driver {\n\tbasic {\n\t\tsession-name = advanced session\n\t\tload-balancing-policy {\n\t\t\tlocal-datacenter = datacenter1\n\t\t}\n\t\trequest.page-size = 11\n\t\tcontact-points = [ \"1.2.3.4:5678\" ]\n\t}\n\tadvanced {\n\t\tthrottler {\n\t\t\tmax-concurrent-requests = 22\n\t\t\tmax-requests-per-second = 33\n\t\t\tmax-queue-size = 44\n\t\t}\n\t\tcontrol-connection.timeout = 5555\n\t\tprotocol.compression = SNAPPY\n\t\tresolve-contact-points = false\n\t}\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/resources/org/springframework/boot/cassandra/autoconfigure/profiles.conf",
    "content": "datastax-java-driver {\n  profiles {\n    first {\n      basic.request.timeout = 100 milliseconds\n      basic.request.consistency = ONE\n    }\n    second {\n      basic.request.timeout = 5 seconds\n      basic.request.consistency = QUORUM\n    }\n  }\n}\n"
  },
  {
    "path": "module/spring-boot-cassandra/src/test/resources/org/springframework/boot/cassandra/autoconfigure/simple.conf",
    "content": "datastax-java-driver {\n  basic {\n    session-name = Test session\n    request.timeout = 500 milliseconds\n  }\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Cloud Foundry\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-actuator\"))\n\tapi(project(\":module:spring-boot-actuator-autoconfigure\"))\n\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-security\"))\n\toptional(project(\":module:spring-boot-webclient\"))\n\toptional(project(\":module:spring-boot-webflux\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"io.projectreactor.netty:reactor-netty-http\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-http-converter\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":module:spring-boot-restclient-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"org.springframework.security:spring-security-test\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/AccessLevel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * The specific access level granted to the cloud foundry user that's calling the\n * endpoints.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic enum AccessLevel {\n\n\t/**\n\t * Restricted access to a limited set of endpoints.\n\t */\n\tRESTRICTED(\"\", \"health\", \"info\"),\n\n\t/**\n\t * Full access to all endpoints.\n\t */\n\tFULL;\n\n\t/**\n\t * The request attribute used to store the {@link AccessLevel}.\n\t */\n\tpublic static final String REQUEST_ATTRIBUTE = \"cloudFoundryAccessLevel\";\n\n\tprivate final List<String> ids;\n\n\tAccessLevel(String... ids) {\n\t\tthis.ids = Arrays.asList(ids);\n\t}\n\n\t/**\n\t * Returns if the access level should allow access to the specified ID.\n\t * @param id the ID to check\n\t * @return {@code true} if access is allowed\n\t */\n\tpublic boolean isAccessAllowed(String id) {\n\t\treturn this.ids.isEmpty() || this.ids.contains(id);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryAuthorizationException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpStatus;\n\n/**\n * Authorization exceptions thrown to limit access to the endpoints.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class CloudFoundryAuthorizationException extends RuntimeException {\n\n\tprivate final Reason reason;\n\n\tpublic CloudFoundryAuthorizationException(Reason reason, @Nullable String message) {\n\t\tthis(reason, message, null);\n\t}\n\n\tpublic CloudFoundryAuthorizationException(Reason reason, @Nullable String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.reason = reason;\n\t}\n\n\t/**\n\t * Return the status code that should be returned to the client.\n\t * @return the HTTP status code\n\t */\n\tpublic HttpStatus getStatusCode() {\n\t\treturn getReason().getStatus();\n\t}\n\n\t/**\n\t * Return the reason why the authorization exception was thrown.\n\t * @return the reason\n\t */\n\tpublic Reason getReason() {\n\t\treturn this.reason;\n\t}\n\n\t/**\n\t * Reasons why the exception can be thrown.\n\t */\n\tpublic enum Reason {\n\n\t\t/**\n\t\t * Access Denied.\n\t\t */\n\t\tACCESS_DENIED(HttpStatus.FORBIDDEN),\n\n\t\t/**\n\t\t * Invalid Audience.\n\t\t */\n\t\tINVALID_AUDIENCE(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Invalid Issuer.\n\t\t */\n\t\tINVALID_ISSUER(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Invalid Key ID.\n\t\t */\n\t\tINVALID_KEY_ID(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Invalid Signature.\n\t\t */\n\t\tINVALID_SIGNATURE(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Invalid Token.\n\t\t */\n\t\tINVALID_TOKEN(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Missing Authorization.\n\t\t */\n\t\tMISSING_AUTHORIZATION(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Token Expired.\n\t\t */\n\t\tTOKEN_EXPIRED(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Unsupported Token Signing Algorithm.\n\t\t */\n\t\tUNSUPPORTED_TOKEN_SIGNING_ALGORITHM(HttpStatus.UNAUTHORIZED),\n\n\t\t/**\n\t\t * Service Unavailable.\n\t\t */\n\t\tSERVICE_UNAVAILABLE(HttpStatus.SERVICE_UNAVAILABLE);\n\n\t\tprivate final HttpStatus status;\n\n\t\tReason(HttpStatus status) {\n\t\t\tthis.status = status;\n\t\t}\n\n\t\tpublic HttpStatus getStatus() {\n\t\t\treturn this.status;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryEndpointExposureOutcomeContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EndpointExposureOutcomeContributor} to expose {@link EndpointExposure#WEB web}\n * endpoints for Cloud Foundry.\n *\n * @author Phillip Webb\n */\nclass CloudFoundryEndpointExposureOutcomeContributor implements EndpointExposureOutcomeContributor {\n\n\tprivate static final String PROPERTY = \"management.endpoints.cloud-foundry.exposure\";\n\n\tprivate final @Nullable IncludeExcludeEndpointFilter<?> filter;\n\n\tCloudFoundryEndpointExposureOutcomeContributor(Environment environment) {\n\t\tthis.filter = (!CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) ? null\n\t\t\t\t: new IncludeExcludeEndpointFilter<>(ExposableEndpoint.class, environment, PROPERTY, \"*\");\n\t}\n\n\t@Override\n\tpublic @Nullable ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,\n\t\t\tBuilder message) {\n\t\tif (exposures.contains(EndpointExposure.WEB) && this.filter != null && this.filter.match(endpointId)) {\n\t\t\treturn ConditionOutcome.match(message.because(\"marked as exposed by a '\" + PROPERTY + \"' property\"));\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.annotation.DiscovererEndpointFilter;\n\n/**\n * {@link EndpointFilter} for endpoints discovered by\n * {@link CloudFoundryWebEndpointDiscoverer}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryEndpointFilter extends DiscovererEndpointFilter {\n\n\tprotected CloudFoundryEndpointFilter() {\n\t\tsuper(CloudFoundryWebEndpointDiscoverer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryWebEndpointDiscoverer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.OperationFilter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.annotation.MergedAnnotations;\n\n/**\n * {@link WebEndpointDiscoverer} for Cloud Foundry that uses Cloud Foundry specific\n * extensions for the {@link HealthEndpoint}.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ImportRuntimeHints(CloudFoundryWebEndpointDiscovererRuntimeHints.class)\npublic class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {\n\n\t/**\n\t * Create a new {@link WebEndpointDiscoverer} instance.\n\t * @param applicationContext the source application context\n\t * @param parameterValueMapper the parameter value mapper\n\t * @param endpointMediaTypes the endpoint media types\n\t * @param endpointPathMappers the endpoint path mappers\n\t * @param invokerAdvisors invoker advisors to apply\n\t * @param endpointFilters endpoint filters to apply\n\t * @param operationFilters operation filters to apply\n\t */\n\tpublic CloudFoundryWebEndpointDiscoverer(ApplicationContext applicationContext,\n\t\t\tParameterValueMapper parameterValueMapper, EndpointMediaTypes endpointMediaTypes,\n\t\t\t@Nullable List<PathMapper> endpointPathMappers, Collection<OperationInvokerAdvisor> invokerAdvisors,\n\t\t\tCollection<EndpointFilter<ExposableWebEndpoint>> endpointFilters,\n\t\t\tCollection<OperationFilter<WebOperation>> operationFilters) {\n\t\tsuper(applicationContext, parameterValueMapper, endpointMediaTypes, endpointPathMappers, null, invokerAdvisors,\n\t\t\t\tendpointFilters, operationFilters);\n\t}\n\n\t@Override\n\tprotected boolean isExtensionTypeExposed(Class<?> extensionBeanType) {\n\t\t// Filter regular health endpoint extensions so a CF version can replace them\n\t\treturn !isHealthEndpointExtension(extensionBeanType)\n\t\t\t\t|| isCloudFoundryHealthEndpointExtension(extensionBeanType);\n\t}\n\n\tprivate boolean isHealthEndpointExtension(Class<?> extensionBeanType) {\n\t\treturn MergedAnnotations.from(extensionBeanType)\n\t\t\t.get(EndpointWebExtension.class)\n\t\t\t.getValue(\"endpoint\", Class.class)\n\t\t\t.map(HealthEndpoint.class::isAssignableFrom)\n\t\t\t.orElse(false);\n\t}\n\n\tprivate boolean isCloudFoundryHealthEndpointExtension(Class<?> extensionBeanType) {\n\t\treturn MergedAnnotations.from(extensionBeanType).isPresent(EndpointCloudFoundryExtension.class);\n\t}\n\n\tstatic class CloudFoundryWebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerType(CloudFoundryEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/EndpointCloudFoundryExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Identifies a type as being a Cloud Foundry specific extension for an\n * {@link Endpoint @Endpoint}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@EndpointExtension(filter = CloudFoundryEndpointFilter.class)\npublic @interface EndpointCloudFoundryExtension {\n\n\t/**\n\t * The class of the endpoint to provide a Cloud Foundry specific extension for.\n\t * @return the class of the endpoint to extend\n\t */\n\t@AliasFor(annotation = EndpointExtension.class, attribute = \"endpoint\")\n\tClass<?> endpoint();\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/SecurityResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpStatus;\n\n/**\n * Response from the Cloud Foundry security interceptors.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class SecurityResponse {\n\n\tprivate final HttpStatus status;\n\n\tprivate final @Nullable String message;\n\n\tpublic SecurityResponse(HttpStatus status) {\n\t\tthis(status, null);\n\t}\n\n\tpublic SecurityResponse(HttpStatus status, @Nullable String message) {\n\t\tthis.status = status;\n\t\tthis.message = message;\n\t}\n\n\tpublic HttpStatus getStatus() {\n\t\treturn this.status;\n\t}\n\n\tpublic @Nullable String getMessage() {\n\t\treturn this.message;\n\t}\n\n\tpublic static SecurityResponse success() {\n\t\treturn new SecurityResponse(HttpStatus.OK);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/Token.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.json.JsonParserFactory;\nimport org.springframework.util.StringUtils;\n\n/**\n * The JSON web token provided with each request that originates from Cloud Foundry.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class Token {\n\n\tprivate final String encoded;\n\n\tprivate final String signature;\n\n\tprivate final Map<String, Object> header;\n\n\tprivate final Map<String, Object> claims;\n\n\tpublic Token(String encoded) {\n\t\tthis.encoded = encoded;\n\t\tint firstPeriod = encoded.indexOf('.');\n\t\tint lastPeriod = encoded.lastIndexOf('.');\n\t\tif (firstPeriod <= 0 || lastPeriod <= firstPeriod) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,\n\t\t\t\t\t\"JWT must have header, body and signature\");\n\t\t}\n\t\tthis.header = parseJson(encoded.substring(0, firstPeriod));\n\t\tthis.claims = parseJson(encoded.substring(firstPeriod + 1, lastPeriod));\n\t\tthis.signature = encoded.substring(lastPeriod + 1);\n\t\tif (!StringUtils.hasLength(this.signature)) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,\n\t\t\t\t\t\"Token must have non-empty crypto segment\");\n\t\t}\n\t}\n\n\tprivate Map<String, Object> parseJson(String base64) {\n\t\ttry {\n\t\t\tbyte[] bytes = Base64.getUrlDecoder().decode(base64);\n\t\t\treturn JsonParserFactory.getJsonParser().parseMap(new String(bytes, StandardCharsets.UTF_8));\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, \"Token could not be parsed\", ex);\n\t\t}\n\t}\n\n\tpublic byte[] getContent() {\n\t\treturn this.encoded.substring(0, this.encoded.lastIndexOf('.')).getBytes();\n\t}\n\n\tpublic byte[] getSignature() {\n\t\treturn Base64.getUrlDecoder().decode(this.signature);\n\t}\n\n\tpublic String getSignatureAlgorithm() {\n\t\treturn getRequired(this.header, \"alg\", String.class);\n\t}\n\n\tpublic String getIssuer() {\n\t\treturn getRequired(this.claims, \"iss\", String.class);\n\t}\n\n\tpublic long getExpiry() {\n\t\treturn getRequired(this.claims, \"exp\", Integer.class).longValue();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<String> getScope() {\n\t\treturn getRequired(this.claims, \"scope\", List.class);\n\t}\n\n\tpublic String getKeyId() {\n\t\treturn getRequired(this.header, \"kid\", String.class);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> T getRequired(Map<String, Object> map, String key, Class<T> type) {\n\t\tObject value = map.get(key);\n\t\tif (value == null) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, \"Unable to get value from key \" + key);\n\t\t}\n\t\tif (!type.isInstance(value)) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,\n\t\t\t\t\t\"Unexpected value type from key \" + key + \" value \" + value);\n\t\t}\n\t\treturn (T) value;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.encoded;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Cloud Foundry endpoints.\n */\n@NullMarked\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryReactiveActuatorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.info.GitInfoContributor;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.boot.actuate.info.InfoEndpoint;\nimport org.springframework.boot.actuate.info.InfoPropertiesInfoContributor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryWebEndpointDiscoverer;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet.CloudFoundryInfoEndpointWebExtension;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.web.server.MatcherSecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterChainProxy;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.server.WebFilter;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to expose actuator endpoints for\n * Cloud Foundry to use in a reactive environment.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(after = InfoEndpointAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration\")\n@ConditionalOnBooleanProperty(name = \"management.cloudfoundry.enabled\", matchIfMissing = true)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)\npublic final class CloudFoundryReactiveActuatorAutoConfiguration {\n\n\tprivate static final String BASE_PATH = \"/cloudfoundryapplication\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnAvailableEndpoint\n\t@ConditionalOnBean({ HealthEndpoint.class, ReactiveHealthEndpointWebExtension.class })\n\tCloudFoundryReactiveHealthEndpointWebExtension cloudFoundryReactiveHealthEndpointWebExtension(\n\t\t\tReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension) {\n\t\treturn new CloudFoundryReactiveHealthEndpointWebExtension(reactiveHealthEndpointWebExtension);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnAvailableEndpoint\n\t@ConditionalOnBean({ InfoEndpoint.class, GitProperties.class })\n\tCloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(GitProperties properties,\n\t\t\tObjectProvider<InfoContributor> infoContributors) {\n\t\tList<InfoContributor> contributors = infoContributors.orderedStream()\n\t\t\t.map((infoContributor) -> (infoContributor instanceof GitInfoContributor)\n\t\t\t\t\t? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor)\n\t\t\t.toList();\n\t\treturn new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\tCloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebFluxEndpointHandlerMapping(\n\t\t\tParameterValueMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,\n\t\t\tWebClient.Builder webClientBuilder,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,\n\t\t\tApplicationContext applicationContext) {\n\t\tCloudFoundryWebEndpointDiscoverer endpointDiscoverer = new CloudFoundryWebEndpointDiscoverer(applicationContext,\n\t\t\t\tparameterMapper, endpointMediaTypes, null, Collections.emptyList(), Collections.emptyList(),\n\t\t\t\tCollections.emptyList());\n\t\tSecurityInterceptor securityInterceptor = getSecurityInterceptor(webClientBuilder,\n\t\t\t\tapplicationContext.getEnvironment());\n\t\tCollection<ExposableWebEndpoint> webEndpoints = endpointDiscoverer.getEndpoints();\n\t\tList<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();\n\t\tallEndpoints.addAll(webEndpoints);\n\t\tallEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());\n\t\treturn new CloudFoundryWebFluxEndpointHandlerMapping(new EndpointMapping(BASE_PATH), webEndpoints,\n\t\t\t\tendpointMediaTypes, getCorsConfiguration(), securityInterceptor, allEndpoints);\n\t}\n\n\tprivate SecurityInterceptor getSecurityInterceptor(WebClient.Builder webClientBuilder, Environment environment) {\n\t\tSecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(webClientBuilder, environment);\n\t\tTokenValidator tokenValidator = (cloudfoundrySecurityService != null)\n\t\t\t\t? new TokenValidator(cloudfoundrySecurityService) : null;\n\t\treturn new SecurityInterceptor(tokenValidator, cloudfoundrySecurityService,\n\t\t\t\tenvironment.getProperty(\"vcap.application.application_id\"));\n\t}\n\n\tprivate @Nullable SecurityService getCloudFoundrySecurityService(WebClient.Builder webClientBuilder,\n\t\t\tEnvironment environment) {\n\t\tString cloudControllerUrl = environment.getProperty(\"vcap.application.cf_api\");\n\t\tboolean skipSslValidation = environment.getProperty(\"management.cloudfoundry.skip-ssl-validation\",\n\t\t\t\tBoolean.class, false);\n\t\treturn (cloudControllerUrl != null)\n\t\t\t\t? new SecurityService(webClientBuilder, cloudControllerUrl, skipSslValidation) : null;\n\t}\n\n\tprivate CorsConfiguration getCorsConfiguration() {\n\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\tcorsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);\n\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));\n\t\tcorsConfiguration\n\t\t\t.setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, \"X-Cf-App-Instance\", HttpHeaders.CONTENT_TYPE));\n\t\treturn corsConfiguration;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(MatcherSecurityWebFilterChain.class)\n\tstatic class IgnoredPathsSecurityConfiguration {\n\n\t\t@Bean\n\t\tstatic WebFilterChainPostProcessor webFilterChainPostProcessor() {\n\t\t\treturn new WebFilterChainPostProcessor();\n\t\t}\n\n\t}\n\n\tstatic class WebFilterChainPostProcessor implements BeanPostProcessor {\n\n\t\tWebFilterChainPostProcessor() {\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tif (bean instanceof WebFilterChainProxy webFilterChainProxy) {\n\t\t\t\treturn postProcess(webFilterChainProxy);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate WebFilterChainProxy postProcess(WebFilterChainProxy existing) {\n\t\t\tServerWebExchangeMatcher cloudFoundryRequestMatcher = ServerWebExchangeMatchers\n\t\t\t\t.pathMatchers(BASE_PATH + \"/**\");\n\t\t\tWebFilter noOpFilter = (exchange, chain) -> chain.filter(exchange);\n\t\t\tMatcherSecurityWebFilterChain ignoredRequestFilterChain = new MatcherSecurityWebFilterChain(\n\t\t\t\t\tcloudFoundryRequestMatcher, Collections.singletonList(noOpFilter));\n\t\t\tMatcherSecurityWebFilterChain allRequestsFilterChain = new MatcherSecurityWebFilterChain(\n\t\t\t\t\tServerWebExchangeMatchers.anyExchange(), Collections.singletonList(existing));\n\t\t\treturn new WebFilterChainProxy(ignoredRequestFilterChain, allRequestsFilterChain);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryReactiveHealthEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.EndpointCloudFoundryExtension;\nimport org.springframework.boot.health.actuate.endpoint.HealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\n\n/**\n * Reactive {@link EndpointExtension @EndpointExtension} for the {@link HealthEndpoint}\n * that always exposes full health details.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@EndpointCloudFoundryExtension(endpoint = HealthEndpoint.class)\npublic class CloudFoundryReactiveHealthEndpointWebExtension {\n\n\tprivate final ReactiveHealthEndpointWebExtension delegate;\n\n\tpublic CloudFoundryReactiveHealthEndpointWebExtension(ReactiveHealthEndpointWebExtension delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@ReadOperation\n\tpublic Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion) {\n\t\treturn this.delegate.health(apiVersion, null, SecurityContext.NONE, true);\n\t}\n\n\t@ReadOperation\n\tpublic Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,\n\t\t\t@Selector(match = Match.ALL_REMAINING) String... path) {\n\t\treturn this.delegate.health(apiVersion, null, SecurityContext.NONE, true, path);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.reactivestreams.Publisher;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.SecurityResponse;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints;\nimport org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * A custom {@link RequestMappingInfoHandlerMapping} that makes web endpoints available on\n * Cloud Foundry specific URLs over HTTP using Spring WebFlux.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Brian Clozel\n */\n@ImportRuntimeHints(CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints.class)\nclass CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {\n\n\tprivate final SecurityInterceptor securityInterceptor;\n\n\tprivate final EndpointLinksResolver linksResolver;\n\n\tprivate final Collection<ExposableEndpoint<?>> allEndpoints;\n\n\tCloudFoundryWebFluxEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,\n\t\t\tCorsConfiguration corsConfiguration, SecurityInterceptor securityInterceptor,\n\t\t\tCollection<ExposableEndpoint<?>> allEndpoints) {\n\t\tsuper(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true);\n\t\tthis.linksResolver = new EndpointLinksResolver(allEndpoints);\n\t\tthis.allEndpoints = allEndpoints;\n\t\tthis.securityInterceptor = securityInterceptor;\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tsuper.initHandlerMethods();\n\t\tregisterCatchAllMapping(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Override\n\tprotected ReactiveWebOperation wrapReactiveWebOperation(ExposableWebEndpoint endpoint, WebOperation operation,\n\t\t\tReactiveWebOperation reactiveWebOperation) {\n\t\treturn new SecureReactiveWebOperation(reactiveWebOperation, this.securityInterceptor, endpoint.getEndpointId());\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn new CloudFoundryLinksHandler();\n\t}\n\n\tCollection<ExposableEndpoint<?>> getAllEndpoints() {\n\t\treturn this.allEndpoints;\n\t}\n\n\tclass CloudFoundryLinksHandler implements LinksHandler {\n\n\t\t@Override\n\t\t@Reflective\n\t\tpublic Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) {\n\t\t\tServerHttpRequest request = exchange.getRequest();\n\t\t\treturn CloudFoundryWebFluxEndpointHandlerMapping.this.securityInterceptor.preHandle(exchange, \"\")\n\t\t\t\t.map((securityResponse) -> {\n\t\t\t\t\tif (!securityResponse.getStatus().equals(HttpStatus.OK)) {\n\t\t\t\t\t\treturn new ResponseEntity<>(securityResponse.getStatus());\n\t\t\t\t\t}\n\t\t\t\t\tAccessLevel accessLevel = exchange.getAttribute(AccessLevel.REQUEST_ATTRIBUTE);\n\t\t\t\t\tMap<String, Link> links = CloudFoundryWebFluxEndpointHandlerMapping.this.linksResolver\n\t\t\t\t\t\t.resolveLinks(request.getURI().toString());\n\t\t\t\t\treturn new ResponseEntity<>(\n\t\t\t\t\t\t\tCollections.singletonMap(\"_links\", getAccessibleLinks(accessLevel, links)), HttpStatus.OK);\n\t\t\t\t});\n\t\t}\n\n\t\tprivate Map<String, Link> getAccessibleLinks(@Nullable AccessLevel accessLevel, Map<String, Link> links) {\n\t\t\tif (accessLevel == null) {\n\t\t\t\treturn new LinkedHashMap<>();\n\t\t\t}\n\t\t\treturn links.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((entry) -> entry.getKey().equals(\"self\") || accessLevel.isAccessAllowed(entry.getKey()))\n\t\t\t\t.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator root web endpoint\";\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ReactiveWebOperation} wrapper to add security.\n\t */\n\tprivate static class SecureReactiveWebOperation implements ReactiveWebOperation {\n\n\t\tprivate final ReactiveWebOperation delegate;\n\n\t\tprivate final SecurityInterceptor securityInterceptor;\n\n\t\tprivate final EndpointId endpointId;\n\n\t\tSecureReactiveWebOperation(ReactiveWebOperation delegate, SecurityInterceptor securityInterceptor,\n\t\t\t\tEndpointId endpointId) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.securityInterceptor = securityInterceptor;\n\t\t\tthis.endpointId = endpointId;\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, @Nullable Map<String, String> body) {\n\t\t\treturn this.securityInterceptor.preHandle(exchange, this.endpointId.toLowerCaseString())\n\t\t\t\t.flatMap((securityResponse) -> flatMapResponse(exchange, body, securityResponse));\n\t\t}\n\n\t\tprivate Mono<ResponseEntity<Object>> flatMapResponse(ServerWebExchange exchange,\n\t\t\t\t@Nullable Map<String, String> body, SecurityResponse securityResponse) {\n\t\t\tif (!securityResponse.getStatus().equals(HttpStatus.OK)) {\n\t\t\t\treturn Mono.just(new ResponseEntity<>(securityResponse.getStatus()));\n\t\t\t}\n\t\t\treturn this.delegate.handle(exchange, body);\n\t\t}\n\n\t}\n\n\tstatic class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/SecurityInterceptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.util.Locale;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.SecurityResponse;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.Token;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.cors.reactive.CorsUtils;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Security interceptor to validate the cloud foundry token.\n *\n * @author Madhura Bhave\n */\nclass SecurityInterceptor {\n\n\tprivate static final Log logger = LogFactory.getLog(SecurityInterceptor.class);\n\n\tprivate final @Nullable TokenValidator tokenValidator;\n\n\tprivate final @Nullable SecurityService cloudFoundrySecurityService;\n\n\tprivate final @Nullable String applicationId;\n\n\tprivate static final Mono<SecurityResponse> SUCCESS = Mono.just(SecurityResponse.success());\n\n\tSecurityInterceptor(@Nullable TokenValidator tokenValidator, @Nullable SecurityService cloudFoundrySecurityService,\n\t\t\t@Nullable String applicationId) {\n\t\tthis.tokenValidator = tokenValidator;\n\t\tthis.cloudFoundrySecurityService = cloudFoundrySecurityService;\n\t\tthis.applicationId = applicationId;\n\t}\n\n\tMono<SecurityResponse> preHandle(ServerWebExchange exchange, String id) {\n\t\tServerHttpRequest request = exchange.getRequest();\n\t\tif (CorsUtils.isPreFlightRequest(request)) {\n\t\t\treturn SUCCESS;\n\t\t}\n\t\tif (!StringUtils.hasText(this.applicationId)) {\n\t\t\treturn Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,\n\t\t\t\t\t\"Application id is not available\"));\n\t\t}\n\t\tif (this.cloudFoundrySecurityService == null || this.tokenValidator == null) {\n\t\t\treturn Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,\n\t\t\t\t\t\"Cloud controller URL is not available\"));\n\t\t}\n\t\treturn check(exchange, id).then(SUCCESS).doOnError(this::logError).onErrorResume(this::getErrorResponse);\n\t}\n\n\tprivate void logError(Throwable ex) {\n\t\tlogger.error(ex.getMessage(), ex);\n\t}\n\n\tprivate Mono<Void> check(ServerWebExchange exchange, String id) {\n\t\tAssert.state(this.tokenValidator != null, \"'tokenValidator' must not be null\");\n\t\tAssert.state(this.cloudFoundrySecurityService != null, \"'cloudFoundrySecurityService' must not be null\");\n\t\tAssert.state(this.applicationId != null, \"'applicationId' must not be null\");\n\t\ttry {\n\t\t\tToken token = getToken(exchange.getRequest());\n\t\t\treturn this.tokenValidator.validate(token)\n\t\t\t\t.then(this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId))\n\t\t\t\t.filter((accessLevel) -> accessLevel.isAccessAllowed(id))\n\t\t\t\t.switchIfEmpty(\n\t\t\t\t\t\tMono.error(new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, \"Access denied\")))\n\t\t\t\t.doOnSuccess((accessLevel) -> exchange.getAttributes().put(\"cloudFoundryAccessLevel\", accessLevel))\n\t\t\t\t.then();\n\t\t}\n\t\tcatch (CloudFoundryAuthorizationException ex) {\n\t\t\treturn Mono.error(ex);\n\t\t}\n\t}\n\n\tprivate Mono<SecurityResponse> getErrorResponse(Throwable throwable) {\n\t\tif (throwable instanceof CloudFoundryAuthorizationException cfException) {\n\t\t\treturn Mono.just(new SecurityResponse(cfException.getStatusCode(),\n\t\t\t\t\t\"{\\\"security_error\\\":\\\"\" + cfException.getMessage() + \"\\\"}\"));\n\t\t}\n\t\treturn Mono.just(new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, throwable.getMessage()));\n\t}\n\n\tprivate Token getToken(ServerHttpRequest request) {\n\t\tString authorization = request.getHeaders().getFirst(\"Authorization\");\n\t\tString bearerPrefix = \"bearer \";\n\t\tif (authorization == null || !authorization.toLowerCase(Locale.ENGLISH).startsWith(bearerPrefix)) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.MISSING_AUTHORIZATION,\n\t\t\t\t\t\"Authorization header is missing or invalid\");\n\t\t}\n\t\treturn new Token(authorization.substring(bearerPrefix.length()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/SecurityService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.netty.handler.ssl.SslProvider;\nimport io.netty.handler.ssl.util.InsecureTrustManagerFactory;\nimport reactor.core.publisher.Mono;\nimport reactor.netty.http.Http11SslContextSpec;\nimport reactor.netty.http.client.HttpClient;\nimport reactor.netty.tcp.SslProvider.GenericSslContextSpec;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.HttpStatusCode;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.util.Assert;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;\nimport org.springframework.web.reactive.function.client.WebClientResponseException;\n\n/**\n * Reactive Cloud Foundry security service to handle REST calls to the cloud controller\n * and UAA.\n *\n * @author Madhura Bhave\n */\nclass SecurityService {\n\n\tprivate static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<>() {\n\t};\n\n\tprivate final WebClient webClient;\n\n\tprivate final String cloudControllerUrl;\n\n\tprivate final Mono<String> uaaUrl;\n\n\tSecurityService(WebClient.Builder webClientBuilder, String cloudControllerUrl, boolean skipSslValidation) {\n\t\tAssert.notNull(webClientBuilder, \"'webClientBuilder' must not be null\");\n\t\tAssert.notNull(cloudControllerUrl, \"'cloudControllerUrl' must not be null\");\n\t\tif (skipSslValidation) {\n\t\t\twebClientBuilder.clientConnector(buildTrustAllSslConnector());\n\t\t}\n\t\tthis.webClient = webClientBuilder.build();\n\t\tthis.cloudControllerUrl = cloudControllerUrl;\n\t\tthis.uaaUrl = this.webClient.get()\n\t\t\t.uri(this.cloudControllerUrl + \"/info\")\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(Map.class)\n\t\t\t.map((response) -> {\n\t\t\t\tString tokenEndpoint = (String) response.get(\"token_endpoint\");\n\t\t\t\tAssert.state(tokenEndpoint != null, \"No 'token_endpoint' found in response\");\n\t\t\t\treturn tokenEndpoint;\n\t\t\t})\n\t\t\t.cacheInvalidateIf((token) -> false)\n\t\t\t.onErrorMap((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,\n\t\t\t\t\t\"Unable to fetch token keys from UAA.\"));\n\t}\n\n\tprotected ReactorClientHttpConnector buildTrustAllSslConnector() {\n\t\tHttpClient client = HttpClient.create().secure((spec) -> spec.sslContext(createSslContextSpec()));\n\t\treturn new ReactorClientHttpConnector(client);\n\t}\n\n\tprivate GenericSslContextSpec<?> createSslContextSpec() {\n\t\treturn Http11SslContextSpec.forClient()\n\t\t\t.configure((builder) -> builder.sslProvider(SslProvider.JDK)\n\t\t\t\t.trustManager(InsecureTrustManagerFactory.INSTANCE));\n\t}\n\n\t/**\n\t * Return a Mono of the access level that should be granted to the given token.\n\t * @param token the token\n\t * @param applicationId the cloud foundry application ID\n\t * @return a Mono of the access level that should be granted\n\t * @throws CloudFoundryAuthorizationException if the token is not authorized\n\t */\n\tMono<AccessLevel> getAccessLevel(String token, String applicationId) throws CloudFoundryAuthorizationException {\n\t\tString uri = getPermissionsUri(applicationId);\n\t\treturn this.webClient.get()\n\t\t\t.uri(uri)\n\t\t\t.header(\"Authorization\", \"bearer \" + token)\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(Map.class)\n\t\t\t.map(this::getAccessLevel)\n\t\t\t.onErrorMap(this::mapError);\n\t}\n\n\tprivate Throwable mapError(Throwable throwable) {\n\t\tif (throwable instanceof WebClientResponseException webClientResponseException) {\n\t\t\tHttpStatusCode statusCode = webClientResponseException.getStatusCode();\n\t\t\tif (statusCode.equals(HttpStatus.FORBIDDEN)) {\n\t\t\t\treturn new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, \"Access denied\");\n\t\t\t}\n\t\t\tif (statusCode.is4xxClientError()) {\n\t\t\t\treturn new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, \"Invalid token\", throwable);\n\t\t\t}\n\t\t}\n\t\treturn new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, \"Cloud controller not reachable\");\n\t}\n\n\tprivate AccessLevel getAccessLevel(Map<?, ?> body) {\n\t\tif (Boolean.TRUE.equals(body.get(\"read_sensitive_data\"))) {\n\t\t\treturn AccessLevel.FULL;\n\t\t}\n\t\treturn AccessLevel.RESTRICTED;\n\t}\n\n\tprivate String getPermissionsUri(String applicationId) {\n\t\treturn this.cloudControllerUrl + \"/v2/apps/\" + applicationId + \"/permissions\";\n\t}\n\n\t/**\n\t * Return a Mono of all token keys known by the UAA.\n\t * @return a Mono of token keys\n\t */\n\tMono<Map<String, String>> fetchTokenKeys() {\n\t\treturn getUaaUrl().flatMap(this::fetchTokenKeys);\n\t}\n\n\tprivate Mono<? extends Map<String, String>> fetchTokenKeys(String url) {\n\t\tRequestHeadersSpec<?> uri = this.webClient.get().uri(url + \"/token_keys\");\n\t\treturn uri.retrieve()\n\t\t\t.bodyToMono(STRING_OBJECT_MAP)\n\t\t\t.map(this::extractTokenKeys)\n\t\t\t.onErrorMap(((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, ex.getMessage())));\n\t}\n\n\tprivate Map<String, String> extractTokenKeys(Map<String, Object> response) {\n\t\tMap<String, String> tokenKeys = new HashMap<>();\n\t\tList<?> keys = (List<?>) response.get(\"keys\");\n\t\tAssert.state(keys != null, \"'keys' must not be null\");\n\t\tfor (Object key : keys) {\n\t\t\tMap<?, ?> tokenKey = (Map<?, ?>) key;\n\t\t\ttokenKeys.put((String) tokenKey.get(\"kid\"), (String) tokenKey.get(\"value\"));\n\t\t}\n\t\treturn tokenKeys;\n\t}\n\n\t/**\n\t * Return a Mono of URL of the UAA.\n\t * @return the UAA url Mono\n\t */\n\tMono<String> getUaaUrl() {\n\t\treturn this.uaaUrl;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/TokenValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.security.GeneralSecurityException;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PublicKey;\nimport java.security.Signature;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.Token;\nimport org.springframework.util.Assert;\n\n/**\n * Validator used to ensure that a signed {@link Token} has not been tampered with.\n *\n * @author Madhura Bhave\n */\nclass TokenValidator {\n\n\tprivate final SecurityService securityService;\n\n\tprivate volatile Map<String, String> cachedTokenKeys = Collections.emptyMap();\n\n\tTokenValidator(SecurityService securityService) {\n\t\tthis.securityService = securityService;\n\t}\n\n\tMono<Void> validate(Token token) {\n\t\treturn validateAlgorithm(token).then(validateKeyIdAndSignature(token))\n\t\t\t.then(validateExpiry(token))\n\t\t\t.then(validateIssuer(token))\n\t\t\t.then(validateAudience(token));\n\t}\n\n\tprivate Mono<Void> validateAlgorithm(Token token) {\n\t\tString algorithm = token.getSignatureAlgorithm();\n\t\tif (algorithm == null) {\n\t\t\treturn Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,\n\t\t\t\t\t\"Signing algorithm cannot be null\"));\n\t\t}\n\t\tif (!algorithm.equals(\"RS256\")) {\n\t\t\treturn Mono.error(new CloudFoundryAuthorizationException(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,\n\t\t\t\t\t\"Signing algorithm \" + algorithm + \" not supported\"));\n\t\t}\n\t\treturn Mono.empty();\n\t}\n\n\tprivate Mono<Void> validateKeyIdAndSignature(Token token) {\n\t\treturn getTokenKey(token).filter((tokenKey) -> hasValidSignature(token, tokenKey))\n\t\t\t.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,\n\t\t\t\t\t\"RSA Signature did not match content\")))\n\t\t\t.then();\n\t}\n\n\tprivate Mono<String> getTokenKey(Token token) {\n\t\tString keyId = token.getKeyId();\n\t\tString cached = this.cachedTokenKeys.get(keyId);\n\t\tif (cached != null) {\n\t\t\treturn Mono.just(cached);\n\t\t}\n\t\treturn this.securityService.fetchTokenKeys()\n\t\t\t.doOnSuccess(this::cacheTokenKeys)\n\t\t\t.filter((tokenKeys) -> tokenKeys.containsKey(keyId))\n\t\t\t.map((tokenKeys) -> {\n\t\t\t\tString tokenKey = tokenKeys.get(keyId);\n\t\t\t\tAssert.state(tokenKey != null, \"No token key found for '%s'\".formatted(keyId));\n\t\t\t\treturn tokenKey;\n\t\t\t})\n\t\t\t.switchIfEmpty(Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,\n\t\t\t\t\t\"Key Id present in token header does not match\")));\n\t}\n\n\tprivate void cacheTokenKeys(Map<String, String> tokenKeys) {\n\t\tthis.cachedTokenKeys = Map.copyOf(tokenKeys);\n\t}\n\n\tprivate boolean hasValidSignature(Token token, String key) {\n\t\ttry {\n\t\t\tPublicKey publicKey = getPublicKey(key);\n\t\t\tSignature signature = Signature.getInstance(\"SHA256withRSA\");\n\t\t\tsignature.initVerify(publicKey);\n\t\t\tsignature.update(token.getContent());\n\t\t\treturn signature.verify(token.getSignature());\n\t\t}\n\t\tcatch (GeneralSecurityException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {\n\t\tkey = key.replace(\"-----BEGIN PUBLIC KEY-----\\n\", \"\");\n\t\tkey = key.replace(\"-----END PUBLIC KEY-----\", \"\");\n\t\tkey = key.trim().replace(\"\\n\", \"\");\n\t\tbyte[] bytes = Base64.getDecoder().decode(key);\n\t\tX509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);\n\t\treturn KeyFactory.getInstance(\"RSA\").generatePublic(keySpec);\n\t}\n\n\tprivate Mono<Void> validateExpiry(Token token) {\n\t\tlong currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());\n\t\tif (currentTime > token.getExpiry()) {\n\t\t\treturn Mono.error(new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED, \"Token expired\"));\n\t\t}\n\t\treturn Mono.empty();\n\t}\n\n\tprivate Mono<Void> validateIssuer(Token token) {\n\t\treturn this.securityService.getUaaUrl()\n\t\t\t.map((uaaUrl) -> String.format(\"%s/oauth/token\", uaaUrl))\n\t\t\t.filter((issuerUri) -> issuerUri.equals(token.getIssuer()))\n\t\t\t.switchIfEmpty(Mono\n\t\t\t\t.error(new CloudFoundryAuthorizationException(Reason.INVALID_ISSUER, \"Token issuer does not match\")))\n\t\t\t.then();\n\t}\n\n\tprivate Mono<Void> validateAudience(Token token) {\n\t\tif (!token.getScope().contains(\"actuator.read\")) {\n\t\t\treturn Mono.error(new CloudFoundryAuthorizationException(Reason.INVALID_AUDIENCE,\n\t\t\t\t\t\"Token does not have audience actuator\"));\n\t\t}\n\t\treturn Mono.empty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Cloud Foundry WebFlux endpoints.\n */\n@NullMarked\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryActuatorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.info.GitInfoContributor;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.boot.actuate.info.InfoEndpoint;\nimport org.springframework.boot.actuate.info.InfoPropertiesInfoContributor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryWebEndpointDiscoverer;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.info.GitProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.config.annotation.web.WebSecurityConfigurer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.builders.WebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to expose actuator endpoints for\n * Cloud Foundry to use.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(after = InfoEndpointAutoConfiguration.class, afterName = {\n\t\t\"org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration\",\n\t\t\"org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration\" })\n@ConditionalOnBooleanProperty(name = \"management.cloudfoundry.enabled\", matchIfMissing = true)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(DispatcherServlet.class)\n@ConditionalOnBean(DispatcherServlet.class)\n@ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)\npublic final class CloudFoundryActuatorAutoConfiguration {\n\n\tprivate static final String BASE_PATH = \"/cloudfoundryapplication\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnAvailableEndpoint\n\t@ConditionalOnBean({ HealthEndpoint.class, HealthEndpointWebExtension.class })\n\tCloudFoundryHealthEndpointWebExtension cloudFoundryHealthEndpointWebExtension(\n\t\t\tHealthEndpointWebExtension healthEndpointWebExtension) {\n\t\treturn new CloudFoundryHealthEndpointWebExtension(healthEndpointWebExtension);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnAvailableEndpoint\n\t@ConditionalOnBean({ InfoEndpoint.class, GitProperties.class })\n\tCloudFoundryInfoEndpointWebExtension cloudFoundryInfoEndpointWebExtension(GitProperties properties,\n\t\t\tObjectProvider<InfoContributor> infoContributors) {\n\t\tList<InfoContributor> contributors = infoContributors.orderedStream()\n\t\t\t.map((infoContributor) -> (infoContributor instanceof GitInfoContributor)\n\t\t\t\t\t? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor)\n\t\t\t.toList();\n\t\treturn new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\tCloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(\n\t\t\tParameterValueMapper parameterMapper, EndpointMediaTypes endpointMediaTypes,\n\t\t\tObjectProvider<RestClient.Builder> restClientBuilder,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,\n\t\t\tApplicationContext applicationContext) {\n\t\tCloudFoundryWebEndpointDiscoverer discoverer = new CloudFoundryWebEndpointDiscoverer(applicationContext,\n\t\t\t\tparameterMapper, endpointMediaTypes, null, Collections.emptyList(), Collections.emptyList(),\n\t\t\t\tCollections.emptyList());\n\t\tSecurityInterceptor securityInterceptor = getSecurityInterceptor(\n\t\t\t\trestClientBuilder.getIfAvailable(RestClient::builder), applicationContext.getEnvironment());\n\t\tCollection<ExposableWebEndpoint> webEndpoints = discoverer.getEndpoints();\n\t\tList<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();\n\t\tallEndpoints.addAll(webEndpoints);\n\t\tallEndpoints.addAll(servletEndpointsSupplier.getEndpoints());\n\t\tallEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());\n\t\treturn new CloudFoundryWebEndpointServletHandlerMapping(new EndpointMapping(BASE_PATH), webEndpoints,\n\t\t\t\tendpointMediaTypes, getCorsConfiguration(), securityInterceptor, allEndpoints);\n\t}\n\n\tprivate SecurityInterceptor getSecurityInterceptor(RestClient.Builder restClientBuilder, Environment environment) {\n\t\tSecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(restClientBuilder, environment);\n\t\tTokenValidator tokenValidator = (cloudfoundrySecurityService != null)\n\t\t\t\t? new TokenValidator(cloudfoundrySecurityService) : null;\n\t\treturn new SecurityInterceptor(tokenValidator, cloudfoundrySecurityService,\n\t\t\t\tenvironment.getProperty(\"vcap.application.application_id\"));\n\t}\n\n\tprivate @Nullable SecurityService getCloudFoundrySecurityService(RestClient.Builder restClientBuilder,\n\t\t\tEnvironment environment) {\n\t\tString cloudControllerUrl = environment.getProperty(\"vcap.application.cf_api\");\n\t\tboolean skipSslValidation = environment.getProperty(\"management.cloudfoundry.skip-ssl-validation\",\n\t\t\t\tBoolean.class, false);\n\t\treturn (cloudControllerUrl != null)\n\t\t\t\t? new SecurityService(restClientBuilder, cloudControllerUrl, skipSslValidation) : null;\n\t}\n\n\tprivate CorsConfiguration getCorsConfiguration() {\n\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\tcorsConfiguration.addAllowedOrigin(CorsConfiguration.ALL);\n\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));\n\t\tcorsConfiguration\n\t\t\t.setAllowedHeaders(Arrays.asList(HttpHeaders.AUTHORIZATION, \"X-Cf-App-Instance\", HttpHeaders.CONTENT_TYPE));\n\t\treturn corsConfiguration;\n\t}\n\n\t/**\n\t * {@link WebSecurityConfigurer} to tell Spring Security to permit cloudfoundry\n\t * specific paths. The Cloud foundry endpoints are protected by their own security\n\t * interceptor.\n\t */\n\t@ConditionalOnClass({ WebSecurityCustomizer.class, WebSecurity.class })\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class IgnoredCloudFoundryPathsWebSecurityConfiguration {\n\n\t\tprivate static final int FILTER_CHAIN_ORDER = -1;\n\n\t\t@Bean\n\t\t@Order(FILTER_CHAIN_ORDER)\n\t\tSecurityFilterChain cloudFoundrySecurityFilterChain(HttpSecurity http) throws Exception {\n\t\t\tRequestMatcher cloudFoundryRequest = getRequestMatcher();\n\t\t\thttp.csrf((csrf) -> csrf.ignoringRequestMatchers(cloudFoundryRequest));\n\t\t\thttp.securityMatchers((matches) -> matches.requestMatchers(cloudFoundryRequest))\n\t\t\t\t.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll());\n\t\t\treturn http.build();\n\t\t}\n\n\t\tprivate RequestMatcher getRequestMatcher() {\n\t\t\treturn pathMatcher(BASE_PATH + \"/**\");\n\t\t}\n\n\t\tprivate PathPatternRequestMatcher pathMatcher(String path) {\n\t\t\treturn PathPatternRequestMatcher.withDefaults().matcher(path);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryHealthEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.EndpointCloudFoundryExtension;\nimport org.springframework.boot.health.actuate.endpoint.HealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\n\n/**\n * {@link EndpointExtension @EndpointExtension} for the {@link HealthEndpoint} that always\n * exposes full health details.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@EndpointCloudFoundryExtension(endpoint = HealthEndpoint.class)\npublic class CloudFoundryHealthEndpointWebExtension {\n\n\tprivate final HealthEndpointWebExtension delegate;\n\n\tpublic CloudFoundryHealthEndpointWebExtension(HealthEndpointWebExtension delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion) {\n\t\treturn this.delegate.health(apiVersion, null, SecurityContext.NONE, true);\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion,\n\t\t\t@Selector(match = Match.ALL_REMAINING) String... path) {\n\t\treturn this.delegate.health(apiVersion, null, SecurityContext.NONE, true, path);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryInfoEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Map;\n\nimport org.springframework.boot.actuate.endpoint.annotation.EndpointExtension;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.info.InfoEndpoint;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.EndpointCloudFoundryExtension;\n\n/**\n * {@link EndpointExtension @EndpointExtension} for the {@link InfoEndpoint} that always\n * exposes full git details.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@EndpointCloudFoundryExtension(endpoint = InfoEndpoint.class)\npublic class CloudFoundryInfoEndpointWebExtension {\n\n\tprivate final InfoEndpoint delegate;\n\n\tpublic CloudFoundryInfoEndpointWebExtension(InfoEndpoint delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@ReadOperation\n\tpublic Map<String, Object> info() {\n\t\treturn this.delegate.info();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryWebEndpointServletHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.SecurityResponse;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;\n\n/**\n * A custom {@link RequestMappingInfoHandlerMapping} that makes web endpoints available on\n * Cloud Foundry specific URLs over HTTP using Spring MVC.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Brian Clozel\n */\n@ImportRuntimeHints(CloudFoundryWebEndpointServletHandlerMappingRuntimeHints.class)\nclass CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {\n\n\tprivate static final Log logger = LogFactory.getLog(CloudFoundryWebEndpointServletHandlerMapping.class);\n\n\tprivate final SecurityInterceptor securityInterceptor;\n\n\tprivate final EndpointLinksResolver linksResolver;\n\n\tprivate final Collection<ExposableEndpoint<?>> allEndpoints;\n\n\tCloudFoundryWebEndpointServletHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,\n\t\t\tCorsConfiguration corsConfiguration, SecurityInterceptor securityInterceptor,\n\t\t\tCollection<ExposableEndpoint<?>> allEndpoints) {\n\t\tsuper(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true);\n\t\tthis.securityInterceptor = securityInterceptor;\n\t\tthis.linksResolver = new EndpointLinksResolver(allEndpoints);\n\t\tthis.allEndpoints = allEndpoints;\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tsuper.initHandlerMethods();\n\t\tregisterCatchAllMapping(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Override\n\tprotected ServletWebOperation wrapServletWebOperation(ExposableWebEndpoint endpoint, WebOperation operation,\n\t\t\tServletWebOperation servletWebOperation) {\n\t\treturn new SecureServletWebOperation(servletWebOperation, this.securityInterceptor, endpoint.getEndpointId());\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn new CloudFoundryLinksHandler();\n\t}\n\n\tCollection<ExposableEndpoint<?>> getAllEndpoints() {\n\t\treturn this.allEndpoints;\n\t}\n\n\tclass CloudFoundryLinksHandler implements LinksHandler {\n\n\t\t@Override\n\t\t@ResponseBody\n\t\t@Reflective\n\t\tpublic Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {\n\t\t\tSecurityResponse securityResponse = CloudFoundryWebEndpointServletHandlerMapping.this.securityInterceptor\n\t\t\t\t.preHandle(request, null);\n\t\t\tif (!securityResponse.getStatus().equals(HttpStatus.OK)) {\n\t\t\t\tsendFailureResponse(response, securityResponse);\n\t\t\t}\n\t\t\tAccessLevel accessLevel = (AccessLevel) request.getAttribute(AccessLevel.REQUEST_ATTRIBUTE);\n\t\t\tMap<String, Link> filteredLinks = new LinkedHashMap<>();\n\t\t\tif (accessLevel == null) {\n\t\t\t\treturn Collections.singletonMap(\"_links\", filteredLinks);\n\t\t\t}\n\t\t\tMap<String, Link> links = CloudFoundryWebEndpointServletHandlerMapping.this.linksResolver\n\t\t\t\t.resolveLinks(request.getRequestURL().toString());\n\t\t\tfilteredLinks = links.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((e) -> e.getKey().equals(\"self\") || accessLevel.isAccessAllowed(e.getKey()))\n\t\t\t\t.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n\t\t\treturn Collections.singletonMap(\"_links\", filteredLinks);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator root web endpoint\";\n\t\t}\n\n\t\tprivate void sendFailureResponse(HttpServletResponse response, SecurityResponse securityResponse) {\n\t\t\ttry {\n\t\t\t\tresponse.sendError(securityResponse.getStatus().value(), securityResponse.getMessage());\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlogger.debug(\"Failed to send error response\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ServletWebOperation} wrapper to add security.\n\t */\n\tprivate static class SecureServletWebOperation implements ServletWebOperation {\n\n\t\tprivate final ServletWebOperation delegate;\n\n\t\tprivate final SecurityInterceptor securityInterceptor;\n\n\t\tprivate final EndpointId endpointId;\n\n\t\tSecureServletWebOperation(ServletWebOperation delegate, SecurityInterceptor securityInterceptor,\n\t\t\t\tEndpointId endpointId) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.securityInterceptor = securityInterceptor;\n\t\t\tthis.endpointId = endpointId;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object handle(HttpServletRequest request, @Nullable Map<String, String> body) {\n\t\t\tSecurityResponse securityResponse = this.securityInterceptor.preHandle(request, this.endpointId);\n\t\t\tif (!securityResponse.getStatus().equals(HttpStatus.OK)) {\n\t\t\t\treturn new ResponseEntity<Object>(securityResponse.getMessage(), securityResponse.getStatus());\n\t\t\t}\n\t\t\treturn this.delegate.handle(request, body);\n\t\t}\n\n\t}\n\n\tstatic class CloudFoundryWebEndpointServletHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/SecurityInterceptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Locale;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.SecurityResponse;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.Token;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.cors.CorsUtils;\n\n/**\n * Security interceptor to validate the cloud foundry token.\n *\n * @author Madhura Bhave\n */\nclass SecurityInterceptor {\n\n\tprivate static final Log logger = LogFactory.getLog(SecurityInterceptor.class);\n\n\tprivate final @Nullable TokenValidator tokenValidator;\n\n\tprivate final @Nullable SecurityService cloudFoundrySecurityService;\n\n\tprivate final @Nullable String applicationId;\n\n\tprivate static final SecurityResponse SUCCESS = SecurityResponse.success();\n\n\tSecurityInterceptor(@Nullable TokenValidator tokenValidator, @Nullable SecurityService cloudFoundrySecurityService,\n\t\t\t@Nullable String applicationId) {\n\t\tthis.tokenValidator = tokenValidator;\n\t\tthis.cloudFoundrySecurityService = cloudFoundrySecurityService;\n\t\tthis.applicationId = applicationId;\n\t}\n\n\tSecurityResponse preHandle(HttpServletRequest request, @Nullable EndpointId endpointId) {\n\t\tif (CorsUtils.isPreFlightRequest(request)) {\n\t\t\treturn SecurityResponse.success();\n\t\t}\n\t\ttry {\n\t\t\tif (!StringUtils.hasText(this.applicationId)) {\n\t\t\t\tthrow new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,\n\t\t\t\t\t\t\"Application id is not available\");\n\t\t\t}\n\t\t\tif (this.cloudFoundrySecurityService == null || this.tokenValidator == null) {\n\t\t\t\tthrow new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,\n\t\t\t\t\t\t\"Cloud controller URL is not available\");\n\t\t\t}\n\t\t\tif (HttpMethod.OPTIONS.matches(request.getMethod())) {\n\t\t\t\treturn SUCCESS;\n\t\t\t}\n\t\t\tcheck(request, endpointId);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.error(ex);\n\t\t\tif (ex instanceof CloudFoundryAuthorizationException cfException) {\n\t\t\t\treturn new SecurityResponse(cfException.getStatusCode(),\n\t\t\t\t\t\t\"{\\\"security_error\\\":\\\"\" + cfException.getMessage() + \"\\\"}\");\n\t\t\t}\n\t\t\treturn new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());\n\t\t}\n\t\treturn SecurityResponse.success();\n\t}\n\n\tprivate void check(HttpServletRequest request, @Nullable EndpointId endpointId) {\n\t\tAssert.state(this.cloudFoundrySecurityService != null, \"'cloudFoundrySecurityService' must not be null\");\n\t\tAssert.state(this.applicationId != null, \"'applicationId' must not be null\");\n\t\tAssert.state(this.tokenValidator != null, \"'tokenValidator' must not be null\");\n\t\tToken token = getToken(request);\n\t\tthis.tokenValidator.validate(token);\n\t\tAccessLevel accessLevel = this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId);\n\t\tif (!accessLevel.isAccessAllowed((endpointId != null) ? endpointId.toLowerCaseString() : \"\")) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, \"Access denied\");\n\t\t}\n\t\trequest.setAttribute(AccessLevel.REQUEST_ATTRIBUTE, accessLevel);\n\t}\n\n\tprivate Token getToken(HttpServletRequest request) {\n\t\tString authorization = request.getHeader(\"Authorization\");\n\t\tString bearerPrefix = \"bearer \";\n\t\tif (authorization == null || !authorization.toLowerCase(Locale.ENGLISH).startsWith(bearerPrefix)) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.MISSING_AUTHORIZATION,\n\t\t\t\t\t\"Authorization header is missing or invalid\");\n\t\t}\n\t\treturn new Token(authorization.substring(bearerPrefix.length()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/SecurityService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.HttpClientErrorException;\nimport org.springframework.web.client.HttpServerErrorException;\nimport org.springframework.web.client.HttpStatusCodeException;\nimport org.springframework.web.client.RestClient;\n\n/**\n * Cloud Foundry security service to handle REST calls to the cloud controller and UAA.\n *\n * @author Madhura Bhave\n */\nclass SecurityService {\n\n\tprivate final RestClient restClient;\n\n\tprivate final String cloudControllerUrl;\n\n\tprivate @Nullable String uaaUrl;\n\n\tSecurityService(RestClient.Builder restClientBuilder, String cloudControllerUrl, boolean skipSslValidation) {\n\t\tAssert.notNull(restClientBuilder, \"'restClientBuilder' must not be null\");\n\t\tAssert.notNull(cloudControllerUrl, \"'cloudControllerUrl' must not be null\");\n\t\tif (skipSslValidation) {\n\t\t\trestClientBuilder = restClientBuilder.requestFactory(new SkipSslVerificationHttpRequestFactory());\n\t\t}\n\t\tthis.restClient = restClientBuilder.build();\n\t\tthis.cloudControllerUrl = cloudControllerUrl;\n\t}\n\n\t/**\n\t * Return the access level that should be granted to the given token.\n\t * @param token the token\n\t * @param applicationId the cloud foundry application ID\n\t * @return the access level that should be granted\n\t * @throws CloudFoundryAuthorizationException if the token is not authorized\n\t */\n\tAccessLevel getAccessLevel(String token, String applicationId) throws CloudFoundryAuthorizationException {\n\t\ttry {\n\t\t\tURI uri = getPermissionsUri(applicationId);\n\t\t\tMap<?, ?> body = this.restClient.get()\n\t\t\t\t.uri(uri)\n\t\t\t\t.header(\"Authorization\", \"bearer \" + token)\n\t\t\t\t.retrieve()\n\t\t\t\t.body(Map.class);\n\t\t\tif (body != null && Boolean.TRUE.equals(body.get(\"read_sensitive_data\"))) {\n\t\t\t\treturn AccessLevel.FULL;\n\t\t\t}\n\t\t\treturn AccessLevel.RESTRICTED;\n\t\t}\n\t\tcatch (HttpClientErrorException ex) {\n\t\t\tif (ex.getStatusCode().equals(HttpStatus.FORBIDDEN)) {\n\t\t\t\tthrow new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, \"Access denied\");\n\t\t\t}\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN, \"Invalid token\", ex);\n\t\t}\n\t\tcatch (HttpServerErrorException ex) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, \"Cloud controller not reachable\");\n\t\t}\n\t}\n\n\tprivate URI getPermissionsUri(String applicationId) {\n\t\ttry {\n\t\t\treturn new URI(this.cloudControllerUrl + \"/v2/apps/\" + applicationId + \"/permissions\");\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Return all token keys known by the UAA.\n\t * @return a map of token keys\n\t */\n\tMap<String, String> fetchTokenKeys() {\n\t\ttry {\n\t\t\tMap<?, ?> response = this.restClient.get().uri(getUaaUrl() + \"/token_keys\").retrieve().body(Map.class);\n\t\t\tAssert.state(response != null, \"'response' must not be null\");\n\t\t\treturn extractTokenKeys(response);\n\t\t}\n\t\tcatch (HttpStatusCodeException ex) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, \"UAA not reachable\");\n\t\t}\n\t}\n\n\tprivate Map<String, String> extractTokenKeys(Map<?, ?> response) {\n\t\tMap<String, String> tokenKeys = new HashMap<>();\n\t\tList<?> keys = (List<?>) response.get(\"keys\");\n\t\tAssert.state(keys != null, \"'keys' must not be null\");\n\t\tfor (Object key : keys) {\n\t\t\tMap<?, ?> tokenKey = (Map<?, ?>) key;\n\t\t\ttokenKeys.put((String) tokenKey.get(\"kid\"), (String) tokenKey.get(\"value\"));\n\t\t}\n\t\treturn tokenKeys;\n\t}\n\n\t/**\n\t * Return the URL of the UAA.\n\t * @return the UAA url\n\t */\n\tString getUaaUrl() {\n\t\tif (this.uaaUrl == null) {\n\t\t\ttry {\n\t\t\t\tMap<?, ?> response = this.restClient.get()\n\t\t\t\t\t.uri(this.cloudControllerUrl + \"/info\")\n\t\t\t\t\t.retrieve()\n\t\t\t\t\t.body(Map.class);\n\t\t\t\tAssert.state(response != null, \"'response' must not be null\");\n\t\t\t\tString tokenEndpoint = (String) response.get(\"token_endpoint\");\n\t\t\t\tAssert.state(tokenEndpoint != null, \"'tokenEndpoint' must not be null\");\n\t\t\t\tthis.uaaUrl = tokenEndpoint;\n\t\t\t}\n\t\t\tcatch (HttpStatusCodeException ex) {\n\t\t\t\tthrow new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,\n\t\t\t\t\t\t\"Unable to fetch token keys from UAA\");\n\t\t\t}\n\t\t}\n\t\treturn this.uaaUrl;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/SkipSslVerificationHttpRequestFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.io.IOException;\nimport java.net.HttpURLConnection;\nimport java.security.SecureRandom;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\n\n/**\n * {@link SimpleClientHttpRequestFactory} that skips SSL certificate verification.\n *\n * @author Madhura Bhave\n */\nclass SkipSslVerificationHttpRequestFactory extends SimpleClientHttpRequestFactory {\n\n\t@Override\n\tprotected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {\n\t\tif (connection instanceof HttpsURLConnection httpsURLConnection) {\n\t\t\tprepareHttpsConnection(httpsURLConnection);\n\t\t}\n\t\tsuper.prepareConnection(connection, httpMethod);\n\t}\n\n\tprivate void prepareHttpsConnection(HttpsURLConnection connection) {\n\t\tconnection.setHostnameVerifier(new SkipHostnameVerifier());\n\t\ttry {\n\t\t\tconnection.setSSLSocketFactory(createSslSocketFactory());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate SSLSocketFactory createSslSocketFactory() throws Exception {\n\t\tSSLContext context = SSLContext.getInstance(\"TLS\");\n\t\tcontext.init(null, new TrustManager[] { new SkipX509TrustManager() }, new SecureRandom());\n\t\treturn context.getSocketFactory();\n\t}\n\n\tprivate static final class SkipHostnameVerifier implements HostnameVerifier {\n\n\t\t@Override\n\t\tpublic boolean verify(String s, SSLSession sslSession) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n\tprivate static final class SkipX509TrustManager implements X509TrustManager {\n\n\t\t@Override\n\t\tpublic X509Certificate[] getAcceptedIssuers() {\n\t\t\treturn new X509Certificate[0];\n\t\t}\n\n\t\t@Override\n\t\tpublic void checkClientTrusted(X509Certificate[] chain, String authType) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void checkServerTrusted(X509Certificate[] chain, String authType) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/TokenValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.security.GeneralSecurityException;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PublicKey;\nimport java.security.Signature;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.Base64;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.Token;\nimport org.springframework.util.Assert;\n\n/**\n * Validator used to ensure that a signed {@link Token} has not been tampered with.\n *\n * @author Madhura Bhave\n */\nclass TokenValidator {\n\n\tprivate final SecurityService securityService;\n\n\tprivate @Nullable Map<String, String> tokenKeys;\n\n\tTokenValidator(SecurityService cloudFoundrySecurityService) {\n\t\tthis.securityService = cloudFoundrySecurityService;\n\t}\n\n\tvoid validate(Token token) {\n\t\tvalidateAlgorithm(token);\n\t\tvalidateKeyIdAndSignature(token);\n\t\tvalidateExpiry(token);\n\t\tvalidateIssuer(token);\n\t\tvalidateAudience(token);\n\t}\n\n\tprivate void validateAlgorithm(Token token) {\n\t\tString algorithm = token.getSignatureAlgorithm();\n\t\tif (algorithm == null) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE, \"Signing algorithm cannot be null\");\n\t\t}\n\t\tif (!algorithm.equals(\"RS256\")) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM,\n\t\t\t\t\t\"Signing algorithm \" + algorithm + \" not supported\");\n\t\t}\n\t}\n\n\tprivate void validateKeyIdAndSignature(Token token) {\n\t\tString keyId = token.getKeyId();\n\t\tMap<String, String> tokenKeys = this.tokenKeys;\n\t\tif (tokenKeys == null || !hasValidKeyId(tokenKeys, keyId)) {\n\t\t\ttokenKeys = this.securityService.fetchTokenKeys();\n\t\t\tif (!hasValidKeyId(tokenKeys, keyId)) {\n\t\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,\n\t\t\t\t\t\t\"Key Id present in token header does not match\");\n\t\t\t}\n\t\t\tthis.tokenKeys = tokenKeys;\n\t\t}\n\t\tString key = tokenKeys.get(keyId);\n\t\tAssert.state(key != null, \"'key' must not be null\");\n\t\tif (!hasValidSignature(token, key)) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,\n\t\t\t\t\t\"RSA Signature did not match content\");\n\t\t}\n\t}\n\n\tprivate boolean hasValidKeyId(Map<String, String> tokenKeys, String tokenKey) {\n\t\treturn tokenKeys.containsKey(tokenKey);\n\t}\n\n\tprivate boolean hasValidSignature(Token token, String key) {\n\t\ttry {\n\t\t\tPublicKey publicKey = getPublicKey(key);\n\t\t\tSignature signature = Signature.getInstance(\"SHA256withRSA\");\n\t\t\tsignature.initVerify(publicKey);\n\t\t\tsignature.update(token.getContent());\n\t\t\treturn signature.verify(token.getSignature());\n\t\t}\n\t\tcatch (GeneralSecurityException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {\n\t\tkey = key.replace(\"-----BEGIN PUBLIC KEY-----\\n\", \"\");\n\t\tkey = key.replace(\"-----END PUBLIC KEY-----\", \"\");\n\t\tkey = key.trim().replace(\"\\n\", \"\");\n\t\tbyte[] bytes = Base64.getDecoder().decode(key);\n\t\tX509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);\n\t\treturn KeyFactory.getInstance(\"RSA\").generatePublic(keySpec);\n\t}\n\n\tprivate void validateExpiry(Token token) {\n\t\tlong currentTime = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());\n\t\tif (currentTime > token.getExpiry()) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.TOKEN_EXPIRED, \"Token expired\");\n\t\t}\n\t}\n\n\tprivate void validateIssuer(Token token) {\n\t\tString uaaUrl = this.securityService.getUaaUrl();\n\t\tString issuerUri = String.format(\"%s/oauth/token\", uaaUrl);\n\t\tif (!issuerUri.equals(token.getIssuer())) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_ISSUER,\n\t\t\t\t\t\"Token issuer does not match \" + uaaUrl + \"/oauth/token\");\n\t\t}\n\t}\n\n\tprivate void validateAudience(Token token) {\n\t\tif (!token.getScope().contains(\"actuator.read\")) {\n\t\t\tthrow new CloudFoundryAuthorizationException(Reason.INVALID_AUDIENCE,\n\t\t\t\t\t\"Token does not have audience actuator\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Cloud Foundry Servlet endpoints.\n */\n@NullMarked\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive.CloudFoundryReactiveActuatorAutoConfiguration\norg.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet.CloudFoundryActuatorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/main/resources/META-INF/spring.factories",
    "content": "# Endpoint Exposure Outcome Contributors\norg.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor=\\\norg.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryEndpointExposureOutcomeContributor\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/AccessLevelTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AccessLevel}.\n *\n * @author Madhura Bhave\n */\nclass AccessLevelTests {\n\n\t@Test\n\tvoid accessToHealthEndpointShouldNotBeRestricted() {\n\t\tassertThat(AccessLevel.RESTRICTED.isAccessAllowed(\"health\")).isTrue();\n\t\tassertThat(AccessLevel.FULL.isAccessAllowed(\"health\")).isTrue();\n\t}\n\n\t@Test\n\tvoid accessToInfoEndpointShouldNotBeRestricted() {\n\t\tassertThat(AccessLevel.RESTRICTED.isAccessAllowed(\"info\")).isTrue();\n\t\tassertThat(AccessLevel.FULL.isAccessAllowed(\"info\")).isTrue();\n\t}\n\n\t@Test\n\tvoid accessToDiscoveryEndpointShouldNotBeRestricted() {\n\t\tassertThat(AccessLevel.RESTRICTED.isAccessAllowed(\"\")).isTrue();\n\t\tassertThat(AccessLevel.FULL.isAccessAllowed(\"\")).isTrue();\n\t}\n\n\t@Test\n\tvoid accessToAnyOtherEndpointShouldBeRestricted() {\n\t\tassertThat(AccessLevel.RESTRICTED.isAccessAllowed(\"env\")).isFalse();\n\t\tassertThat(AccessLevel.FULL.isAccessAllowed(\"\")).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryAuthorizationExceptionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.http.HttpStatus;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryAuthorizationException}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryAuthorizationExceptionTests {\n\n\t@Test\n\tvoid statusCodeForInvalidTokenReasonShouldBe401() {\n\t\tassertThat(createException(Reason.INVALID_TOKEN).getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForInvalidIssuerReasonShouldBe401() {\n\t\tassertThat(createException(Reason.INVALID_ISSUER).getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForInvalidAudienceReasonShouldBe401() {\n\t\tassertThat(createException(Reason.INVALID_AUDIENCE).getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForInvalidSignatureReasonShouldBe401() {\n\t\tassertThat(createException(Reason.INVALID_SIGNATURE).getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForMissingAuthorizationReasonShouldBe401() {\n\t\tassertThat(createException(Reason.MISSING_AUTHORIZATION).getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForUnsupportedSignatureAlgorithmReasonShouldBe401() {\n\t\tassertThat(createException(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForTokenExpiredReasonShouldBe401() {\n\t\tassertThat(createException(Reason.TOKEN_EXPIRED).getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid statusCodeForAccessDeniedReasonShouldBe403() {\n\t\tassertThat(createException(Reason.ACCESS_DENIED).getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid statusCodeForServiceUnavailableReasonShouldBe503() {\n\t\tassertThat(createException(Reason.SERVICE_UNAVAILABLE).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);\n\t}\n\n\tprivate CloudFoundryAuthorizationException createException(Reason reason) {\n\t\treturn new CloudFoundryAuthorizationException(reason, \"message\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryConditionalOnAvailableEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnAvailableEndpoint @ConditionalOnAvailableEndpoint} when\n * running on Cloud Foundry.\n *\n * @author Brian Clozel\n */\nclass CloudFoundryConditionalOnAvailableEndpointTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(AllEndpointsConfiguration.class)\n\t\t.withInitializer(\n\t\t\t\t(context) -> context.getEnvironment().setConversionService(new ApplicationConversionService()));\n\n\t@Test\n\tvoid outcomeOnCloudFoundryShouldMatchAll() {\n\t\tthis.contextRunner.withPropertyValues(\"VCAP_APPLICATION:---\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"info\").hasBean(\"health\").hasBean(\"spring\").hasBean(\"test\"));\n\t}\n\n\t@Endpoint(id = \"health\")\n\tstatic class HealthEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"info\")\n\tstatic class InfoEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"spring\")\n\tstatic class SpringEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t}\n\n\t@Endpoint(id = \"shutdown\", defaultAccess = Access.NONE)\n\tstatic class ShutdownEndpoint {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AllEndpointsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tHealthEndpoint health() {\n\t\t\treturn new HealthEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tInfoEndpoint info() {\n\t\t\treturn new InfoEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tSpringEndpoint spring() {\n\t\t\treturn new SpringEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tTestEndpoint test() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnAvailableEndpoint\n\t\tShutdownEndpoint shutdown() {\n\t\t\treturn new ShutdownEndpoint();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryEndpointFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.annotation.DiscoveredEndpoint;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CloudFoundryEndpointFilter}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryEndpointFilterTests {\n\n\tprivate final CloudFoundryEndpointFilter filter = new CloudFoundryEndpointFilter();\n\n\t@Test\n\tvoid matchIfDiscovererCloudFoundryShouldReturnFalse() {\n\t\tDiscoveredEndpoint<?> endpoint = mock(DiscoveredEndpoint.class);\n\t\tgiven(endpoint.wasDiscoveredBy(CloudFoundryWebEndpointDiscoverer.class)).willReturn(true);\n\t\tassertThat(this.filter.match(endpoint)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchIfDiscovererNotCloudFoundryShouldReturnFalse() {\n\t\tDiscoveredEndpoint<?> endpoint = mock(DiscoveredEndpoint.class);\n\t\tgiven(endpoint.wasDiscoveredBy(CloudFoundryWebEndpointDiscoverer.class)).willReturn(false);\n\t\tassertThat(this.filter.match(endpoint)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/CloudFoundryWebEndpointDiscovererTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoker.cache.CachingOperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.support.DefaultConversionService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CloudFoundryWebEndpointDiscoverer}.\n *\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\nclass CloudFoundryWebEndpointDiscovererTests {\n\n\t@Test\n\tvoid getEndpointsShouldAddCloudFoundryHealthExtension() {\n\t\tload(TestConfiguration.class, (discoverer) -> {\n\t\t\tCollection<ExposableWebEndpoint> endpoints = discoverer.getEndpoints();\n\t\t\tassertThat(endpoints).hasSize(2);\n\t\t\tfor (ExposableWebEndpoint endpoint : endpoints) {\n\t\t\t\tif (endpoint.getEndpointId().equals(EndpointId.of(\"health\"))) {\n\t\t\t\t\tWebOperation operation = findMainReadOperation(endpoint);\n\t\t\t\t\tassertThat(operation\n\t\t\t\t\t\t.invoke(new InvocationContext(mock(SecurityContext.class), Collections.emptyMap())))\n\t\t\t\t\t\t.isEqualTo(\"cf\");\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew CloudFoundryWebEndpointDiscovererRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(CloudFoundryEndpointFilter.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\tprivate WebOperation findMainReadOperation(ExposableWebEndpoint endpoint) {\n\t\tfor (WebOperation operation : endpoint.getOperations()) {\n\t\t\tif (operation.getRequestPredicate().getPath().equals(\"health\")) {\n\t\t\t\treturn operation;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"No main read operation found from \" + endpoint.getOperations());\n\t}\n\n\tprivate void load(Class<?> configuration, Consumer<CloudFoundryWebEndpointDiscoverer> consumer) {\n\t\tload((id) -> null, EndpointId::toString, configuration, consumer);\n\t}\n\n\tprivate void load(Function<EndpointId, @Nullable Long> timeToLive, PathMapper endpointPathMapper,\n\t\t\tClass<?> configuration, Consumer<CloudFoundryWebEndpointDiscoverer> consumer) {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configuration)) {\n\t\t\tConversionServiceParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\t\tEndpointMediaTypes mediaTypes = new EndpointMediaTypes(Collections.singletonList(\"application/json\"),\n\t\t\t\t\tCollections.singletonList(\"application/json\"));\n\t\t\tCloudFoundryWebEndpointDiscoverer discoverer = new CloudFoundryWebEndpointDiscoverer(context,\n\t\t\t\t\tparameterMapper, mediaTypes, Collections.singletonList(endpointPathMapper),\n\t\t\t\t\tCollections.singleton(new CachingOperationInvokerAdvisor(timeToLive)), Collections.emptyList(),\n\t\t\t\t\tCollections.emptyList());\n\t\t\tconsumer.accept(discoverer);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint() {\n\t\t\treturn new TestEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpointWebExtension testEndpointWebExtension() {\n\t\t\treturn new TestEndpointWebExtension();\n\t\t}\n\n\t\t@Bean\n\t\tHealthEndpoint healthEndpoint() {\n\t\t\tHealthContributorRegistry registry = mock(HealthContributorRegistry.class);\n\t\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\t\treturn new HealthEndpoint(registry, null, groups, null);\n\t\t}\n\n\t\t@Bean\n\t\tHealthEndpointWebExtension healthEndpointWebExtension() {\n\t\t\treturn new HealthEndpointWebExtension();\n\t\t}\n\n\t\t@Bean\n\t\tTestHealthEndpointCloudFoundryExtension testHealthEndpointCloudFoundryExtension() {\n\t\t\treturn new TestHealthEndpointCloudFoundryExtension();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = TestEndpoint.class)\n\tstatic class TestEndpointWebExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointWebExtension(endpoint = HealthEndpoint.class)\n\tstatic class HealthEndpointWebExtension {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@EndpointCloudFoundryExtension(endpoint = HealthEndpoint.class)\n\tstatic class TestHealthEndpointCloudFoundryExtension {\n\n\t\t@ReadOperation\n\t\tObject getAll() {\n\t\t\treturn \"cf\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/TokenTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint;\n\nimport java.util.Base64;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link Token}.\n *\n * @author Madhura Bhave\n */\nclass TokenTests {\n\n\t@Test\n\tvoid invalidJwtShouldThrowException() {\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class).isThrownBy(() -> new Token(\"invalid-token\"))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid invalidJwtClaimsShouldThrowException() {\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\", \\\"kid\\\": \\\"key-id\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"invalid-claims\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> new Token(Base64.getEncoder().encodeToString(header.getBytes()) + \".\"\n\t\t\t\t\t+ Base64.getEncoder().encodeToString(claims.getBytes())))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid invalidJwtHeaderShouldThrowException() {\n\t\tString header = \"invalid-header\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\"}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> new Token(Base64.getEncoder().encodeToString(header.getBytes()) + \".\"\n\t\t\t\t\t+ Base64.getEncoder().encodeToString(claims.getBytes())))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid emptyJwtSignatureShouldThrowException() {\n\t\tString token = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu\"\n\t\t\t\t+ \"Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ.\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class).isThrownBy(() -> new Token(token))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid validJwt() {\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"key-id\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\"}\";\n\t\tString content = Base64.getEncoder().encodeToString(header.getBytes()) + \".\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(claims.getBytes());\n\t\tString signature = Base64.getEncoder().encodeToString(\"signature\".getBytes());\n\t\tToken token = new Token(content + \".\" + signature);\n\t\tassertThat(token.getExpiry()).isEqualTo(2147483647);\n\t\tassertThat(token.getIssuer()).isEqualTo(\"http://localhost:8080/uaa/oauth/token\");\n\t\tassertThat(token.getSignatureAlgorithm()).isEqualTo(\"RS256\");\n\t\tassertThat(token.getKeyId()).isEqualTo(\"key-id\");\n\t\tassertThat(token.getContent()).isEqualTo(content.getBytes());\n\t\tassertThat(token.getSignature()).isEqualTo(Base64.getDecoder().decode(signature));\n\t}\n\n\t@Test\n\tvoid getSignatureAlgorithmWhenAlgIsNullShouldThrowException() {\n\t\tString header = \"{\\\"kid\\\": \\\"key-id\\\",  \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\"}\";\n\t\tToken token = createToken(header, claims);\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class).isThrownBy(token::getSignatureAlgorithm)\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid getIssuerWhenIssIsNullShouldThrowException() {\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\", \\\"kid\\\": \\\"key-id\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647}\";\n\t\tToken token = createToken(header, claims);\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class).isThrownBy(token::getIssuer)\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid getKidWhenKidIsNullShouldThrowException() {\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647}\";\n\t\tToken token = createToken(header, claims);\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class).isThrownBy(token::getKeyId)\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid getExpiryWhenExpIsNullShouldThrowException() {\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"key-id\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\"}\";\n\t\tToken token = createToken(header, claims);\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class).isThrownBy(token::getExpiry)\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\tprivate Token createToken(String header, String claims) {\n\t\tToken token = new Token(Base64.getEncoder().encodeToString(header.getBytes()) + \".\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(claims.getBytes()) + \".\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(\"signature\".getBytes()));\n\t\treturn token;\n\t}\n\n\tprivate Consumer<CloudFoundryAuthorizationException> reasonRequirement(Reason reason) {\n\t\treturn (ex) -> assertThat(ex.getReason()).isEqualTo(reason);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryReactiveActuatorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLException;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.netty.http.HttpResources;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet.CloudFoundryInfoEndpointWebExtension;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatusCode;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterChainProxy;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CloudFoundryReactiveActuatorAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\nclass CloudFoundryReactiveActuatorAutoConfigurationTests {\n\n\tprivate static final String V2_JSON = ApiVersion.V2.getProducedMimeType().toString();\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveWebSecurityAutoConfiguration.class,\n\t\t\t\tWebFluxAutoConfiguration.class, JacksonAutoConfiguration.class,\n\t\t\t\tHttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tWebClientCustomizerConfig.class, WebClientAutoConfiguration.class,\n\t\t\t\tManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tInfoContributorAutoConfiguration.class, InfoEndpointAutoConfiguration.class,\n\t\t\t\tProjectInfoAutoConfiguration.class, CloudFoundryReactiveActuatorAutoConfiguration.class))\n\t\t.withUserConfiguration(UserDetailsServiceConfiguration.class);\n\n\tprivate static final String BASE_PATH = \"/cloudfoundryapplication\";\n\n\t@AfterEach\n\tvoid close() {\n\t\tHttpResources.reset();\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActive() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tassertThat(handlerMapping).extracting(\"endpointMapping.path\").isEqualTo(\"/cloudfoundryapplication\");\n\t\t\t\tassertThat(handlerMapping)\n\t\t\t\t\t.extracting(\"corsConfiguration\", InstanceOfAssertFactories.type(CorsConfiguration.class))\n\t\t\t\t\t.satisfies((corsConfiguration) -> {\n\t\t\t\t\t\tassertThat(corsConfiguration.getAllowedOrigins()).contains(\"*\");\n\t\t\t\t\t\tassertThat(corsConfiguration.getAllowedMethods())\n\t\t\t\t\t\t\t.containsAll(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));\n\t\t\t\t\t\tassertThat(corsConfiguration.getAllowedHeaders())\n\t\t\t\t\t\t\t.containsAll(Arrays.asList(\"Authorization\", \"X-Cf-App-Instance\", \"Content-Type\"));\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudfoundryapplicationProducesActuatorMediaType() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = WebTestClient.bindToApplicationContext(context).build();\n\t\t\t\twebTestClient.get().uri(\"/cloudfoundryapplication\").header(\"Content-Type\", V2_JSON + \";charset=UTF-8\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActiveSetsApplicationId() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> assertThat(getHandlerMapping(context)).extracting(\"securityInterceptor.applicationId\")\n\t\t\t\t.isEqualTo(\"my-app-id\"));\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActiveSetsCloudControllerUrl() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> assertThat(getHandlerMapping(context))\n\t\t\t\t.extracting(\"securityInterceptor.cloudFoundrySecurityService.cloudControllerUrl\")\n\t\t\t\t.isEqualTo(\"https://my-cloud-controller.com\"));\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActiveAndCloudControllerUrlNotPresent() {\n\t\tthis.contextRunner.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\")\n\t\t\t.run((context) -> assertThat(context.getBean(\"cloudFoundryWebFluxEndpointHandlerMapping\",\n\t\t\t\t\tCloudFoundryWebFluxEndpointHandlerMapping.class))\n\t\t\t\t.extracting(\"securityInterceptor.cloudFoundrySecurityService\")\n\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid cloudFoundryPathsIgnoredBySpringSecurity() {\n\t\tthis.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(WebFilterChainProxy.class))\n\t\t\t\t\t.extracting(\"filters\", InstanceOfAssertFactories.list(SecurityWebFilterChain.class))\n\t\t\t\t\t.satisfies((filters) -> {\n\t\t\t\t\t\tBoolean cfBaseRequestMatches = getMatches(filters, BASE_PATH);\n\t\t\t\t\t\tBoolean cfBaseWithTrailingSlashRequestMatches = getMatches(filters, BASE_PATH + \"/\");\n\t\t\t\t\t\tBoolean cfRequestMatches = getMatches(filters, BASE_PATH + \"/test\");\n\t\t\t\t\t\tBoolean cfRequestWithAdditionalPathMatches = getMatches(filters, BASE_PATH + \"/test/a\");\n\t\t\t\t\t\tBoolean otherCfRequestMatches = getMatches(filters, BASE_PATH + \"/other-path\");\n\t\t\t\t\t\tBoolean otherRequestMatches = getMatches(filters, \"/some-other-path\");\n\t\t\t\t\t\tassertThat(cfBaseRequestMatches).isTrue();\n\t\t\t\t\t\tassertThat(cfBaseWithTrailingSlashRequestMatches).isTrue();\n\t\t\t\t\t\tassertThat(cfRequestMatches).isTrue();\n\t\t\t\t\t\tassertThat(cfRequestWithAdditionalPathMatches).isTrue();\n\t\t\t\t\t\tassertThat(otherCfRequestMatches).isTrue();\n\t\t\t\t\t\tassertThat(otherRequestMatches).isFalse();\n\t\t\t\t\t\totherRequestMatches = filters.get(1)\n\t\t\t\t\t\t\t.matches(MockServerWebExchange.from(MockServerHttpRequest.get(\"/some-other-path\").build()))\n\t\t\t\t\t\t\t.block(Duration.ofSeconds(30));\n\t\t\t\t\t\tassertThat(otherRequestMatches).isTrue();\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\tprivate static @Nullable Boolean getMatches(List<? extends SecurityWebFilterChain> filters, String urlTemplate) {\n\t\treturn filters.get(0)\n\t\t\t.matches(MockServerWebExchange.from(MockServerHttpRequest.get(urlTemplate).build()))\n\t\t\t.block(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformInactive() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.containsBean(\"cloudFoundryWebFluxEndpointHandlerMapping\")).isFalse());\n\t}\n\n\t@Test\n\tvoid cloudFoundryManagementEndpointsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"VCAP_APPLICATION=---\", \"management.cloudfoundry.enabled:false\")\n\t\t\t.run((context) -> assertThat(context.containsBean(\"cloudFoundryWebFluxEndpointHandlerMapping\")).isFalse());\n\t}\n\n\t@Test\n\tvoid allEndpointsAvailableUnderCloudFoundryWithoutEnablingWebIncludes() {\n\t\tthis.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = handlerMapping.getEndpoints();\n\t\t\t\tList<EndpointId> endpointIds = endpoints.stream().map(ExposableWebEndpoint::getEndpointId).toList();\n\t\t\t\tassertThat(endpointIds).contains(EndpointId.of(\"test\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid endpointPathCustomizationIsNotApplied() {\n\t\tthis.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = handlerMapping.getEndpoints();\n\t\t\t\tExposableWebEndpoint endpoint = endpoints.stream()\n\t\t\t\t\t.filter((candidate) -> EndpointId.of(\"test\").equals(candidate.getEndpointId()))\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.get();\n\t\t\t\tassertThat(endpoint.getOperations()).hasSize(1);\n\t\t\t\tWebOperation operation = endpoint.getOperations().iterator().next();\n\t\t\t\tassertThat(operation.getRequestPredicate().getPath()).isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid healthEndpointInvokerShouldBeCloudFoundryWebExtension() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = getHandlerMapping(context).getEndpoints();\n\t\t\t\tExposableWebEndpoint endpoint = endpoints.stream()\n\t\t\t\t\t.filter((candidate) -> candidate.getEndpointId().toLowerCaseString().equals(\"health\"))\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.get();\n\t\t\t\tassertThat(endpoint.getOperations()).hasSize(2);\n\t\t\t\tWebOperation webOperation = findOperationWithRequestPath(endpoint, \"health\");\n\t\t\t\tassertThat(webOperation).extracting(\"invoker\")\n\t\t\t\t\t.extracting(\"target\")\n\t\t\t\t\t.isInstanceOf(CloudFoundryReactiveHealthEndpointWebExtension.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"git.properties\", content = \"\"\"\n\t\t\t#Generated by Git-Commit-Id-Plugin\n\t\t\t#Thu May 23 09:26:42 BST 2013\n\t\t\tgit.commit.id.abbrev=e02a4f3\n\t\t\tgit.commit.user.email=dsyer@vmware.com\n\t\t\tgit.commit.message.full=Update Spring\n\t\t\tgit.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\n\t\t\tgit.commit.message.short=Update Spring\n\t\t\tgit.commit.user.name=Dave Syer\n\t\t\tgit.build.user.name=Dave Syer\n\t\t\tgit.build.user.email=dsyer@vmware.com\n\t\t\tgit.branch=develop\n\t\t\tgit.commit.time=2013-04-24T08\\\\:42\\\\:13+0100\n\t\t\tgit.build.time=2013-05-23T09\\\\:26\\\\:42+0100\n\t\t\t\"\"\")\n\t@SuppressWarnings(\"unchecked\")\n\tvoid gitFullDetailsAlwaysPresent() {\n\t\tthis.contextRunner.withPropertyValues(\"VCAP_APPLICATION:---\").run((context) -> {\n\t\t\tCloudFoundryInfoEndpointWebExtension extension = context\n\t\t\t\t.getBean(CloudFoundryInfoEndpointWebExtension.class);\n\t\t\tMap<String, Object> git = (Map<String, Object>) extension.info().get(\"git\");\n\t\t\tassertThat(git).isNotNull();\n\t\t\tMap<String, Object> commit = (Map<String, Object>) git.get(\"commit\");\n\t\t\tassertThat(commit).hasSize(4);\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid skipSslValidation() throws IOException {\n\t\tJksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(\"JKS\", null, \"classpath:test.jks\", \"secret\");\n\t\tSslBundle sslBundle = SslBundle.of(new JksSslStoreBundle(keyStoreDetails, keyStoreDetails));\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.useHttps(sslBundle.createSslContext().getSocketFactory(), false);\n\t\t\tserver.enqueue(new MockResponse().setResponseCode(204));\n\t\t\tserver.start();\n\t\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class))\n\t\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\",\n\t\t\t\t\t\t\"management.cloudfoundry.skip-ssl-validation:true\")\n\t\t\t\t.run((context) -> assertThat(getHandlerMapping(context))\n\t\t\t\t\t.extracting(\"securityInterceptor.cloudFoundrySecurityService.webClient\",\n\t\t\t\t\t\t\tInstanceOfAssertFactories.type(WebClient.class))\n\t\t\t\t\t.satisfies((webClient) -> {\n\t\t\t\t\t\tResponseEntity<Void> response = webClient.get()\n\t\t\t\t\t\t\t.uri(server.url(\"/\").uri())\n\t\t\t\t\t\t\t.retrieve()\n\t\t\t\t\t\t\t.toBodilessEntity()\n\t\t\t\t\t\t\t.block(Duration.ofSeconds(30));\n\t\t\t\t\t\tassertThat(response).isNotNull();\n\t\t\t\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatusCode.valueOf(204));\n\t\t\t\t\t}));\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslValidationNotSkippedByDefault() throws IOException {\n\t\tJksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(\"JKS\", null, \"classpath:test.jks\", \"secret\");\n\t\tSslBundle sslBundle = SslBundle.of(new JksSslStoreBundle(keyStoreDetails, keyStoreDetails));\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.useHttps(sslBundle.createSslContext().getSocketFactory(), false);\n\t\t\tserver.enqueue(new MockResponse().setResponseCode(204));\n\t\t\tserver.start();\n\t\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class))\n\t\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t\t.run((context) -> assertThat(getHandlerMapping(context))\n\t\t\t\t\t.extracting(\"securityInterceptor.cloudFoundrySecurityService.webClient\",\n\t\t\t\t\t\t\tInstanceOfAssertFactories.type(WebClient.class))\n\t\t\t\t\t.satisfies((webClient) -> assertThatExceptionOfType(RuntimeException.class)\n\t\t\t\t\t\t.isThrownBy(() -> webClient.get()\n\t\t\t\t\t\t\t.uri(server.url(\"/\").uri())\n\t\t\t\t\t\t\t.retrieve()\n\t\t\t\t\t\t\t.toBodilessEntity()\n\t\t\t\t\t\t\t.block(Duration.ofSeconds(30)))\n\t\t\t\t\t\t.withCauseInstanceOf(SSLException.class)));\n\t\t}\n\t}\n\n\tprivate CloudFoundryWebFluxEndpointHandlerMapping getHandlerMapping(ApplicationContext context) {\n\t\treturn context.getBean(\"cloudFoundryWebFluxEndpointHandlerMapping\",\n\t\t\t\tCloudFoundryWebFluxEndpointHandlerMapping.class);\n\t}\n\n\tprivate WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, String requestPath) {\n\t\tfor (WebOperation operation : endpoint.getOperations()) {\n\t\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\t\tif (predicate.getPath().equals(requestPath) && predicate.getProduces().contains(V3_JSON)) {\n\t\t\t\treturn operation;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"No operation found with request path \" + requestPath + \" from \" + endpoint.getOperations());\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\tString hello() {\n\t\t\treturn \"hello world\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebClientCustomizerConfig {\n\n\t\t@Bean\n\t\tWebClientCustomizer webClientCustomizer() {\n\t\t\treturn mock(WebClientCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDetailsServiceConfiguration {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withUsername(\"alice\").password(\"secret\").roles(\"admin\").build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryReactiveHealthEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.time.Duration;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.health.actuate.endpoint.CompositeHealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.HealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.IndicatedHealthDescriptor;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryReactiveHealthEndpointWebExtension}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryReactiveHealthEndpointWebExtensionTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withPropertyValues(\"VCAP_APPLICATION={}\")\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveWebSecurityAutoConfiguration.class,\n\t\t\t\tWebFluxAutoConfiguration.class, JacksonAutoConfiguration.class,\n\t\t\t\tHttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tCloudFoundryReactiveActuatorAutoConfigurationTests.WebClientCustomizerConfig.class,\n\t\t\t\tWebClientAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\tEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, CloudFoundryReactiveActuatorAutoConfiguration.class))\n\t\t.withUserConfiguration(TestHealthIndicator.class, UserDetailsServiceConfiguration.class);\n\n\t@Test\n\tvoid healthComponentsAlwaysPresent() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tCloudFoundryReactiveHealthEndpointWebExtension extension = context\n\t\t\t\t.getBean(CloudFoundryReactiveHealthEndpointWebExtension.class);\n\t\t\tWebEndpointResponse<? extends HealthDescriptor> response = extension.health(ApiVersion.V3)\n\t\t\t\t.block(Duration.ofSeconds(30));\n\t\t\tassertThat(response).isNotNull();\n\t\t\tHealthDescriptor descriptor = response.getBody();\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tMap<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();\n\t\t\tassertThat(components).isNotNull();\n\t\t\tHealthDescriptor component = components.entrySet().iterator().next().getValue();\n\t\t\tassertThat(((IndicatedHealthDescriptor) component).getDetails()).containsEntry(\"spring\", \"boot\");\n\t\t});\n\t}\n\n\tprivate static final class TestHealthIndicator implements HealthIndicator {\n\n\t\t@Override\n\t\tpublic Health health() {\n\t\t\treturn Health.up().withDetail(\"spring\", \"boot\").build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDetailsServiceConfiguration {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withUsername(\"alice\").password(\"secret\").roles(\"admin\").build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryWebFluxEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryLinksHandler;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryWebFluxEndpointHandlerMapping}.\n *\n * @author Moritz Halbritter\n */\nclass CloudFoundryWebFluxEndpointHandlerMappingTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(CloudFoundryLinksHandler.class, \"links\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/CloudFoundryWebFluxEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.cors.CorsConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CloudFoundryWebFluxEndpointHandlerMapping}.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n */\nclass CloudFoundryWebFluxEndpointIntegrationTests {\n\n\tprivate final TokenValidator tokenValidator = mock(TokenValidator.class);\n\n\tprivate final SecurityService securityService = mock(SecurityService.class);\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(\n\t\t\tAnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class,\n\t\t\t\tNettyReactiveWebServerAutoConfiguration.class))\n\t\t.withUserConfiguration(TestEndpointConfiguration.class)\n\t\t.withBean(TokenValidator.class, () -> this.tokenValidator)\n\t\t.withBean(SecurityService.class, () -> this.securityService)\n\t\t.withPropertyValues(\"server.port=0\");\n\n\t@Test\n\tvoid operationWithSecurityInterceptorForbidden() {\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(Mono.just(AccessLevel.RESTRICTED));\n\t\tthis.contextRunner.run(withWebTestClient((client) -> client.get()\n\t\t\t.uri(\"/cfApplication/test\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.FORBIDDEN)));\n\t}\n\n\t@Test\n\tvoid operationWithSecurityInterceptorSuccess() {\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(Mono.just(AccessLevel.FULL));\n\t\tthis.contextRunner.run(withWebTestClient((client) -> client.get()\n\t\t\t.uri(\"/cfApplication/test\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.OK)));\n\t}\n\n\t@Test\n\tvoid responseToOptionsRequestIncludesCorsHeaders() {\n\t\tthis.contextRunner.run(withWebTestClient((client) -> client.options()\n\t\t\t.uri(\"/cfApplication/test\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Access-Control-Request-Method\", \"POST\")\n\t\t\t.header(\"Origin\", \"https://example.com\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(\"Access-Control-Allow-Origin\", \"https://example.com\")\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(\"Access-Control-Allow-Methods\", \"GET,POST\")));\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsWithFullAccess() {\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(Mono.just(AccessLevel.FULL));\n\t\tthis.contextRunner.run(withWebTestClient((client) -> client.get()\n\t\t\t.uri(\"/cfApplication\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"_links.length()\")\n\t\t\t.isEqualTo(5)\n\t\t\t.jsonPath(\"_links.self.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.self.templated\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"_links.info.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.info.templated\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"_links.env.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.env.templated\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"_links.test.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.test.templated\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"_links.test-part.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.test-part.templated\")\n\t\t\t.isEqualTo(true)));\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsForbidden() {\n\t\tCloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,\n\t\t\t\t\"invalid-token\");\n\t\twillThrow(exception).given(this.tokenValidator).validate(any());\n\t\tthis.contextRunner.run(withWebTestClient((client) -> client.get()\n\t\t\t.uri(\"/cfApplication\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized()));\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsWithRestrictedAccess() {\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(Mono.just(AccessLevel.RESTRICTED));\n\t\tthis.contextRunner.run(withWebTestClient((client) -> client.get()\n\t\t\t.uri(\"/cfApplication\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"_links.length()\")\n\t\t\t.isEqualTo(2)\n\t\t\t.jsonPath(\"_links.self.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.self.templated\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"_links.info.href\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"_links.info.templated\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"_links.env\")\n\t\t\t.doesNotExist()\n\t\t\t.jsonPath(\"_links.test\")\n\t\t\t.doesNotExist()\n\t\t\t.jsonPath(\"_links.test-part\")\n\t\t\t.doesNotExist()));\n\t}\n\n\t@Test\n\tvoid unknownEndpointsAreForbidden() {\n\t\tthis.contextRunner.run(withWebTestClient(\n\t\t\t\t(client) -> client.get().uri(\"/cfApplication/unknown\").exchange().expectStatus().isForbidden()));\n\t}\n\n\tprivate ContextConsumer<AssertableReactiveWebApplicationContext> withWebTestClient(\n\t\t\tConsumer<WebTestClient> clientConsumer) {\n\t\treturn (context) -> {\n\t\t\tWebServer webServer = ((AnnotationConfigReactiveWebServerApplicationContext) context\n\t\t\t\t.getSourceApplicationContext()).getWebServer();\n\t\t\tassertThat(webServer).isNotNull();\n\t\t\tint port = webServer.getPort();\n\t\t\tclientConsumer.accept(WebTestClient.bindToServer()\n\t\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t\t.build());\n\t\t};\n\t}\n\n\tprivate String mockAccessToken() {\n\t\treturn \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu\"\n\t\t\t\t+ \"Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ.\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(\"signature\".getBytes());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CloudFoundryReactiveConfiguration {\n\n\t\t@Bean\n\t\tSecurityInterceptor interceptor(TokenValidator tokenValidator, SecurityService securityService) {\n\t\t\treturn new SecurityInterceptor(tokenValidator, securityService, \"app-id\");\n\t\t}\n\n\t\t@Bean\n\t\tEndpointMediaTypes EndpointMediaTypes() {\n\t\t\treturn new EndpointMediaTypes(Collections.singletonList(\"application/json\"),\n\t\t\t\t\tCollections.singletonList(\"application/json\"));\n\t\t}\n\n\t\t@Bean\n\t\tCloudFoundryWebFluxEndpointHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(\n\t\t\t\tWebEndpointDiscoverer webEndpointDiscoverer, EndpointMediaTypes endpointMediaTypes,\n\t\t\t\tSecurityInterceptor interceptor) {\n\t\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\t\tcorsConfiguration.setAllowedOrigins(Arrays.asList(\"https://example.com\"));\n\t\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(\"GET\", \"POST\"));\n\t\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointDiscoverer.getEndpoints();\n\t\t\tList<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(webEndpoints);\n\t\t\treturn new CloudFoundryWebFluxEndpointHandlerMapping(new EndpointMapping(\"/cfApplication\"), webEndpoints,\n\t\t\t\t\tendpointMediaTypes, corsConfiguration, interceptor, allEndpoints);\n\t\t}\n\n\t\t@Bean\n\t\tWebEndpointDiscoverer webEndpointDiscoverer(ApplicationContext applicationContext,\n\t\t\t\tEndpointMediaTypes endpointMediaTypes) {\n\t\t\tParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\t\treturn new WebEndpointDiscoverer(applicationContext, parameterMapper, endpointMediaTypes, null, null,\n\t\t\t\t\tCollections.emptyList(), Collections.emptyList(), Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tEndpointDelegate endpointDelegate() {\n\t\t\treturn mock(EndpointDelegate.class);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\tprivate final EndpointDelegate endpointDelegate;\n\n\t\tTestEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\tthis.endpointDelegate = endpointDelegate;\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readPart(@Selector String part) {\n\t\t\treturn Collections.singletonMap(\"part\", part);\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid write(String foo, String bar) {\n\t\t\tthis.endpointDelegate.write(foo, bar);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"env\")\n\tstatic class TestEnvEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"info\")\n\tstatic class TestInfoEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(CloudFoundryReactiveConfiguration.class)\n\tstatic class TestEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\treturn new TestEndpoint(endpointDelegate);\n\t\t}\n\n\t\t@Bean\n\t\tTestInfoEndpoint testInfoEnvEndpoint() {\n\t\t\treturn new TestInfoEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestEnvEndpoint testEnvEndpoint() {\n\t\t\treturn new TestEnvEndpoint();\n\t\t}\n\n\t}\n\n\tinterface EndpointDelegate {\n\n\t\tvoid write();\n\n\t\tvoid write(String foo, String bar);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/SecurityInterceptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.time.Duration;\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link SecurityInterceptor}.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass SecurityInterceptorTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate TokenValidator tokenValidator;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate SecurityService securityService;\n\n\tprivate SecurityInterceptor interceptor;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.interceptor = new SecurityInterceptor(this.tokenValidator, this.securityService, \"my-app-id\");\n\t}\n\n\t@Test\n\tvoid preHandleWhenRequestIsPreFlightShouldBeOk() {\n\t\tMockServerWebExchange request = MockServerWebExchange.from(MockServerHttpRequest.options(\"/a\")\n\t\t\t.header(HttpHeaders.ORIGIN, \"https://example.com\")\n\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t.build());\n\t\tStepVerifier.create(this.interceptor.preHandle(request, \"/a\"))\n\t\t\t.consumeNextWith((response) -> assertThat(response.getStatus()).isEqualTo(HttpStatus.OK))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid preHandleWhenTokenIsMissingShouldReturnMissingAuthorization() {\n\t\tMockServerWebExchange request = MockServerWebExchange.from(MockServerHttpRequest.get(\"/a\").build());\n\t\tStepVerifier.create(this.interceptor.preHandle(request, \"/a\"))\n\t\t\t.consumeNextWith(\n\t\t\t\t\t(response) -> assertThat(response.getStatus()).isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid preHandleWhenTokenIsNotBearerShouldReturnMissingAuthorization() {\n\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t.from(MockServerHttpRequest.get(\"/a\").header(HttpHeaders.AUTHORIZATION, mockAccessToken()).build());\n\t\tStepVerifier.create(this.interceptor.preHandle(request, \"/a\"))\n\t\t\t.consumeNextWith(\n\t\t\t\t\t(response) -> assertThat(response.getStatus()).isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid preHandleWhenApplicationIdIsNullShouldReturnError() {\n\t\tthis.interceptor = new SecurityInterceptor(this.tokenValidator, this.securityService, null);\n\t\tMockServerWebExchange request = MockServerWebExchange.from(MockServerHttpRequest.get(\"/a\")\n\t\t\t.header(HttpHeaders.AUTHORIZATION, \"bearer \" + mockAccessToken())\n\t\t\t.build());\n\t\tStepVerifier.create(this.interceptor.preHandle(request, \"/a\"))\n\t\t\t.consumeErrorWith((ex) -> assertThat(((CloudFoundryAuthorizationException) ex).getReason())\n\t\t\t\t.isEqualTo(Reason.SERVICE_UNAVAILABLE))\n\t\t\t.verify();\n\t}\n\n\t@Test\n\tvoid preHandleWhenCloudFoundrySecurityServiceIsNullShouldReturnError() {\n\t\tthis.interceptor = new SecurityInterceptor(this.tokenValidator, null, \"my-app-id\");\n\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t.from(MockServerHttpRequest.get(\"/a\").header(HttpHeaders.AUTHORIZATION, mockAccessToken()).build());\n\t\tStepVerifier.create(this.interceptor.preHandle(request, \"/a\"))\n\t\t\t.consumeErrorWith((ex) -> assertThat(((CloudFoundryAuthorizationException) ex).getReason())\n\t\t\t\t.isEqualTo(Reason.SERVICE_UNAVAILABLE))\n\t\t\t.verify();\n\t}\n\n\t@Test\n\tvoid preHandleWhenAccessIsNotAllowedShouldReturnAccessDenied() {\n\t\tgiven(this.securityService.getAccessLevel(mockAccessToken(), \"my-app-id\"))\n\t\t\t.willReturn(Mono.just(AccessLevel.RESTRICTED));\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tMockServerWebExchange request = MockServerWebExchange.from(MockServerHttpRequest.get(\"/a\")\n\t\t\t.header(HttpHeaders.AUTHORIZATION, \"bearer \" + mockAccessToken())\n\t\t\t.build());\n\t\tStepVerifier.create(this.interceptor.preHandle(request, \"/a\"))\n\t\t\t.consumeNextWith((response) -> assertThat(response.getStatus()).isEqualTo(Reason.ACCESS_DENIED.getStatus()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid preHandleSuccessfulWithFullAccess() {\n\t\tString accessToken = mockAccessToken();\n\t\tgiven(this.securityService.getAccessLevel(accessToken, \"my-app-id\")).willReturn(Mono.just(AccessLevel.FULL));\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/a\")\n\t\t\t.header(HttpHeaders.AUTHORIZATION, \"bearer \" + mockAccessToken())\n\t\t\t.build());\n\t\tStepVerifier.create(this.interceptor.preHandle(exchange, \"/a\")).consumeNextWith((response) -> {\n\t\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK);\n\t\t\tassertThat((AccessLevel) exchange.getAttribute(\"cloudFoundryAccessLevel\")).isEqualTo(AccessLevel.FULL);\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid preHandleSuccessfulWithRestrictedAccess() {\n\t\tString accessToken = mockAccessToken();\n\t\tgiven(this.securityService.getAccessLevel(accessToken, \"my-app-id\"))\n\t\t\t.willReturn(Mono.just(AccessLevel.RESTRICTED));\n\t\tgiven(this.tokenValidator.validate(any())).willReturn(Mono.empty());\n\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/info\")\n\t\t\t.header(HttpHeaders.AUTHORIZATION, \"bearer \" + mockAccessToken())\n\t\t\t.build());\n\t\tStepVerifier.create(this.interceptor.preHandle(exchange, \"info\")).consumeNextWith((response) -> {\n\t\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK);\n\t\t\tassertThat((AccessLevel) exchange.getAttribute(\"cloudFoundryAccessLevel\"))\n\t\t\t\t.isEqualTo(AccessLevel.RESTRICTED);\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\tprivate String mockAccessToken() {\n\t\treturn \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu\"\n\t\t\t\t+ \"Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ.\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(\"signature\".getBytes());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/SecurityServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.util.function.Consumer;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SecurityService}.\n *\n * @author Madhura Bhave\n */\nclass SecurityServiceTests {\n\n\tprivate static final String CLOUD_CONTROLLER = \"/my-cloud-controller.com\";\n\n\tprivate static final String CLOUD_CONTROLLER_PERMISSIONS = CLOUD_CONTROLLER + \"/v2/apps/my-app-id/permissions\";\n\n\tprivate static final String UAA_URL = \"https://my-cloud-controller.com/uaa\";\n\n\tprivate SecurityService securityService;\n\n\tprivate MockWebServer server;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.server = new MockWebServer();\n\t\tWebClient.Builder builder = WebClient.builder().baseUrl(this.server.url(\"/\").toString());\n\t\tthis.securityService = new SecurityService(builder, CLOUD_CONTROLLER, false);\n\t}\n\n\t@AfterEach\n\tvoid shutdown() throws Exception {\n\t\tthis.server.shutdown();\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenSpaceDeveloperShouldReturnFull() throws Exception {\n\t\tString responseBody = \"{\\\"read_sensitive_data\\\": true,\\\"read_basic_data\\\": true}\";\n\t\tprepareResponse((response) -> response.setBody(responseBody).setHeader(\"Content-Type\", \"application/json\"));\n\t\tStepVerifier.create(this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.consumeNextWith((accessLevel) -> assertThat(accessLevel).isEqualTo(AccessLevel.FULL))\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\texpectRequest((request) -> {\n\t\t\tassertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo(\"bearer my-access-token\");\n\t\t\tassertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER_PERMISSIONS);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenNotSpaceDeveloperShouldReturnRestricted() throws Exception {\n\t\tString responseBody = \"{\\\"read_sensitive_data\\\": false,\\\"read_basic_data\\\": true}\";\n\t\tprepareResponse((response) -> response.setBody(responseBody).setHeader(\"Content-Type\", \"application/json\"));\n\t\tStepVerifier.create(this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.consumeNextWith((accessLevel) -> assertThat(accessLevel).isEqualTo(AccessLevel.RESTRICTED))\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\texpectRequest((request) -> {\n\t\t\tassertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo(\"bearer my-access-token\");\n\t\t\tassertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER_PERMISSIONS);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenTokenIsNotValidShouldThrowException() throws Exception {\n\t\tprepareResponse((response) -> response.setResponseCode(401));\n\t\tStepVerifier.create(this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.consumeErrorWith((throwable) -> {\n\t\t\t\tassertThat(throwable).isInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) throwable).getReason())\n\t\t\t\t\t.isEqualTo(Reason.INVALID_TOKEN);\n\t\t\t})\n\t\t\t.verify();\n\t\texpectRequest((request) -> {\n\t\t\tassertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo(\"bearer my-access-token\");\n\t\t\tassertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER_PERMISSIONS);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenForbiddenShouldThrowException() throws Exception {\n\t\tprepareResponse((response) -> response.setResponseCode(403));\n\t\tStepVerifier.create(this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.consumeErrorWith((throwable) -> {\n\t\t\t\tassertThat(throwable).isInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) throwable).getReason())\n\t\t\t\t\t.isEqualTo(Reason.ACCESS_DENIED);\n\t\t\t})\n\t\t\t.verify();\n\t\texpectRequest((request) -> {\n\t\t\tassertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo(\"bearer my-access-token\");\n\t\t\tassertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER_PERMISSIONS);\n\t\t});\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenCloudControllerIsNotReachableThrowsException() throws Exception {\n\t\tprepareResponse((response) -> response.setResponseCode(500));\n\t\tStepVerifier.create(this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.consumeErrorWith((throwable) -> {\n\t\t\t\tassertThat(throwable).isInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) throwable).getReason())\n\t\t\t\t\t.isEqualTo(Reason.SERVICE_UNAVAILABLE);\n\t\t\t})\n\t\t\t.verify();\n\t\texpectRequest((request) -> {\n\t\t\tassertThat(request.getHeader(HttpHeaders.AUTHORIZATION)).isEqualTo(\"bearer my-access-token\");\n\t\t\tassertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER_PERMISSIONS);\n\t\t});\n\t}\n\n\t@Test\n\tvoid fetchTokenKeysWhenSuccessfulShouldReturnListOfKeysFromUAA() throws Exception {\n\t\tString tokenKeyValue = \"\"\"\n\t\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\t\tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO\n\t\t\t\trn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7\n\t\t\t\tfYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB\n\t\t\t\tLCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO\n\t\t\t\tkqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo\n\t\t\t\tjfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI\n\t\t\t\tJwIDAQAB\n\t\t\t\t-----END PUBLIC KEY-----\"\"\";\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(\"{\\\"token_endpoint\\\":\\\"/my-uaa.com\\\"}\");\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tString responseBody = \"{\\\"keys\\\" : [ {\\\"kid\\\":\\\"test-key\\\",\\\"value\\\" : \\\"\" + tokenKeyValue.replace(\"\\n\", \"\\\\n\")\n\t\t\t\t+ \"\\\"} ]}\";\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(responseBody);\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tStepVerifier.create(this.securityService.fetchTokenKeys())\n\t\t\t.consumeNextWith((tokenKeys) -> assertThat(tokenKeys.get(\"test-key\")).isEqualTo(tokenKeyValue))\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(\"/my-cloud-controller.com/info\"));\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(\"/my-uaa.com/token_keys\"));\n\t}\n\n\t@Test\n\tvoid fetchTokenKeysWhenNoKeysReturnedFromUAA() throws Exception {\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(\"{\\\"token_endpoint\\\":\\\"/my-uaa.com\\\"}\");\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tString responseBody = \"{\\\"keys\\\": []}\";\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(responseBody);\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tStepVerifier.create(this.securityService.fetchTokenKeys())\n\t\t\t.consumeNextWith((tokenKeys) -> assertThat(tokenKeys).isEmpty())\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(\"/my-cloud-controller.com/info\"));\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(\"/my-uaa.com/token_keys\"));\n\t}\n\n\t@Test\n\tvoid fetchTokenKeysWhenUnsuccessfulShouldThrowException() throws Exception {\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(\"{\\\"token_endpoint\\\":\\\"/my-uaa.com\\\"}\");\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tprepareResponse((response) -> response.setResponseCode(500));\n\t\tStepVerifier.create(this.securityService.fetchTokenKeys())\n\t\t\t.consumeErrorWith((throwable) -> assertThat(((CloudFoundryAuthorizationException) throwable).getReason())\n\t\t\t\t.isEqualTo(Reason.SERVICE_UNAVAILABLE))\n\t\t\t.verify();\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(\"/my-cloud-controller.com/info\"));\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(\"/my-uaa.com/token_keys\"));\n\t}\n\n\t@Test\n\tvoid getUaaUrlShouldCallCloudControllerInfoOnlyOnce() throws Exception {\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(\"{\\\"token_endpoint\\\":\\\"\" + UAA_URL + \"\\\"}\");\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tStepVerifier.create(this.securityService.getUaaUrl())\n\t\t\t.consumeNextWith((uaaUrl) -> assertThat(uaaUrl).isEqualTo(UAA_URL))\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(\"{\\\"token_endpoint\\\":\\\"\" + UAA_URL + \"\\\"}\");\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tStepVerifier.create(this.securityService.getUaaUrl())\n\t\t\t.consumeNextWith((uaaUrl) -> assertThat(uaaUrl).isEqualTo(UAA_URL))\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER + \"/info\"));\n\t\texpectRequestCount(1);\n\t}\n\n\t@Test\n\tvoid getUaaUrlWhenCloudControllerUrlIsNotReachableShouldThrowException() throws Exception {\n\t\tprepareResponse((response) -> response.setResponseCode(500));\n\t\tStepVerifier.create(this.securityService.getUaaUrl()).consumeErrorWith((throwable) -> {\n\t\t\tassertThat(throwable).isInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\tassertThat(((CloudFoundryAuthorizationException) throwable).getReason())\n\t\t\t\t.isEqualTo(Reason.SERVICE_UNAVAILABLE);\n\t\t}).verify();\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER + \"/info\"));\n\t}\n\n\t@Test\n\tvoid getUaaUrlShouldRetryAfterFailure() throws Exception {\n\t\tprepareResponse((response) -> response.setResponseCode(500));\n\t\tStepVerifier.create(this.securityService.getUaaUrl()).consumeErrorWith((throwable) -> {\n\t\t\tassertThat(throwable).isInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\tassertThat(((CloudFoundryAuthorizationException) throwable).getReason())\n\t\t\t\t.isEqualTo(Reason.SERVICE_UNAVAILABLE);\n\t\t}).verify();\n\t\tprepareResponse((response) -> {\n\t\t\tresponse.setBody(\"{\\\"token_endpoint\\\":\\\"\" + UAA_URL + \"\\\"}\");\n\t\t\tresponse.setHeader(\"Content-Type\", \"application/json\");\n\t\t});\n\t\tStepVerifier.create(this.securityService.getUaaUrl())\n\t\t\t.consumeNextWith((uaaUrl) -> assertThat(uaaUrl).isEqualTo(UAA_URL))\n\t\t\t.expectComplete()\n\t\t\t.verify();\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER + \"/info\"));\n\t\texpectRequest((request) -> assertThat(request.getPath()).isEqualTo(CLOUD_CONTROLLER + \"/info\"));\n\t\texpectRequestCount(2);\n\t}\n\n\tprivate void prepareResponse(Consumer<MockResponse> consumer) {\n\t\tMockResponse response = new MockResponse();\n\t\tconsumer.accept(response);\n\t\tthis.server.enqueue(response);\n\t}\n\n\tprivate void expectRequest(Consumer<RecordedRequest> consumer) throws InterruptedException {\n\t\tconsumer.accept(this.server.takeRequest());\n\t}\n\n\tprivate void expectRequestCount(int count) {\n\t\tassertThat(count).isEqualTo(this.server.getRequestCount());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/reactive/TokenValidatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.reactive;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.Signature;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.time.Duration;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\nimport reactor.test.publisher.PublisherProbe;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.Token;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link TokenValidator}.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass TokenValidatorTests {\n\n\tprivate static final byte[] DOT = \".\".getBytes();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate SecurityService securityService;\n\n\tprivate TokenValidator tokenValidator;\n\n\tprivate static final String VALID_KEY = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO\n\t\t\trn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7\n\t\t\tfYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB\n\t\t\tLCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO\n\t\t\tkqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo\n\t\t\tjfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI\n\t\t\tJwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\"\"\";\n\n\tprivate static final String INVALID_KEY = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK\n\t\t\t5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa\n\t\t\tvkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0\n\t\t\tFK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC\n\t\t\tVTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M\n\t\t\tr3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s\n\t\t\tYwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\"\"\";\n\n\tprivate static final Map<String, String> INVALID_KEYS = new ConcurrentHashMap<>();\n\n\tprivate static final Map<String, String> VALID_KEYS = new ConcurrentHashMap<>();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tVALID_KEYS.put(\"valid-key\", VALID_KEY);\n\t\tINVALID_KEYS.put(\"invalid-key\", INVALID_KEY);\n\t\tthis.tokenValidator = new TokenValidator(this.securityService);\n\t}\n\n\t@Test\n\tvoid validateTokenWhenKidValidationFailsTwiceShouldThrowException() throws Exception {\n\t\tPublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"cachedTokenKeys\", VALID_KEYS);\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"invalid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason()).isEqualTo(Reason.INVALID_KEY_ID);\n\t\t\t})\n\t\t\t.verify();\n\t\tassertThat(this.tokenValidator).hasFieldOrPropertyWithValue(\"cachedTokenKeys\", VALID_KEYS);\n\t\tfetchTokenKeys.assertWasSubscribed();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenKidValidationSucceedsInTheSecondAttempt() throws Exception {\n\t\tPublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"cachedTokenKeys\", INVALID_KEYS);\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tassertThat(this.tokenValidator).hasFieldOrPropertyWithValue(\"cachedTokenKeys\", VALID_KEYS);\n\t\tfetchTokenKeys.assertWasSubscribed();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenCacheIsEmptyShouldFetchTokenKeys() throws Exception {\n\t\tPublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tassertThat(this.tokenValidator).hasFieldOrPropertyWithValue(\"cachedTokenKeys\", VALID_KEYS);\n\t\tfetchTokenKeys.assertWasSubscribed();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenCacheEmptyAndInvalidKeyShouldThrowException() throws Exception {\n\t\tPublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.of(Mono.just(VALID_KEYS));\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(fetchTokenKeys.mono());\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"invalid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason()).isEqualTo(Reason.INVALID_KEY_ID);\n\t\t\t})\n\t\t\t.verify();\n\t\tassertThat(this.tokenValidator).hasFieldOrPropertyWithValue(\"cachedTokenKeys\", VALID_KEYS);\n\t\tfetchTokenKeys.assertWasSubscribed();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenCacheValidShouldNotFetchTokenKeys() throws Exception {\n\t\tPublisherProbe<Map<String, String>> fetchTokenKeys = PublisherProbe.empty();\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"cachedTokenKeys\", VALID_KEYS);\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tfetchTokenKeys.assertWasNotSubscribed();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenSignatureInvalidShouldThrowException() throws Exception {\n\t\tMap<String, String> KEYS = Collections.singletonMap(\"valid-key\", INVALID_KEY);\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(Mono.just(KEYS));\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason()).isEqualTo(Reason.INVALID_SIGNATURE);\n\t\t\t})\n\t\t\t.verify();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenTokenAlgorithmIsNotRS256ShouldThrowException() throws Exception {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(Mono.just(VALID_KEYS));\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{ \\\"alg\\\": \\\"HS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason())\n\t\t\t\t\t.isEqualTo(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM);\n\t\t\t})\n\t\t\t.verify();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenExpiredShouldThrowException() throws Exception {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(Mono.just(VALID_KEYS));\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"jti\\\": \\\"0236399c350c47f3ae77e67a75e75e7d\\\", \\\"exp\\\": 1477509977, \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason()).isEqualTo(Reason.TOKEN_EXPIRED);\n\t\t\t})\n\t\t\t.verify();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenIssuerIsNotValidShouldThrowException() throws Exception {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(Mono.just(VALID_KEYS));\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"https://other-uaa.com\"));\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"foo.bar\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason()).isEqualTo(Reason.INVALID_ISSUER);\n\t\t\t})\n\t\t\t.verify();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenAudienceIsNotValidShouldThrowException() throws Exception {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(Mono.just(VALID_KEYS));\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(Mono.just(\"http://localhost:8080/uaa\"));\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"foo.bar\\\"]}\";\n\t\tStepVerifier\n\t\t\t.create(this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.consumeErrorWith((ex) -> {\n\t\t\t\tassertThat(ex).isExactlyInstanceOf(CloudFoundryAuthorizationException.class);\n\t\t\t\tassertThat(((CloudFoundryAuthorizationException) ex).getReason()).isEqualTo(Reason.INVALID_AUDIENCE);\n\t\t\t})\n\t\t\t.verify();\n\t}\n\n\tprivate String getSignedToken(byte[] header, byte[] claims) throws Exception {\n\t\tPrivateKey privateKey = getPrivateKey();\n\t\tSignature signature = Signature.getInstance(\"SHA256WithRSA\");\n\t\tsignature.initSign(privateKey);\n\t\tbyte[] content = dotConcat(Base64.getUrlEncoder().encode(header), Base64.getEncoder().encode(claims));\n\t\tsignature.update(content);\n\t\tbyte[] crypto = signature.sign();\n\t\tbyte[] token = dotConcat(Base64.getUrlEncoder().encode(header), Base64.getUrlEncoder().encode(claims),\n\t\t\t\tBase64.getUrlEncoder().encode(crypto));\n\t\treturn new String(token, StandardCharsets.UTF_8);\n\t}\n\n\tprivate PrivateKey getPrivateKey() throws InvalidKeySpecException, NoSuchAlgorithmException {\n\t\tString signingKey = \"\"\"\n\t\t\t\t-----BEGIN PRIVATE KEY-----\n\t\t\t\tMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDSbn2Xa72IOcxu\n\t\t\t\ttcd+qQ6ufZ1VDe98EmpwO4VQrTd37U9kZtWU0KqeSkgnyzIWmlbyWOdbB4/v4uJa\n\t\t\t\tlGjPQjt9hvd3xOOFXzpj33sWXgMGvGAzopMk64T+7GegOFlDXguA5TZyReM7M51O\n\t\t\t\tycYwpAEsKXS+lxcG0UsxpJum/WjOLyHsMnJVnoScVBlRYZ2BMyEOuap69/H3lT/X\n\t\t\t\tpzlYEM6SrAifsaWvL2f1K7HKBt/yDkDOlZy6xmAMsghnslNSV0FvypTZrQOXia8t\n\t\t\t\tk6fjA+iN+P0LDZAgKxzn4/B/bV8/6HN/7VZJEdudi/y5qdE7SBnx6QZqCEz/YfqC\n\t\t\t\tolujacgnAgMBAAECggEAc9X2tJ/OWWrXqinOg160gkELloJxTi8lAFsDbAGuAwpT\n\t\t\t\tJcWl1KF5CmGBjsY/8ElNi2J9GJL1HOwcBhikCVNARD1DhF6RkB13mvquWwWtTMvt\n\t\t\t\teP8JWM19DIc+E+hw2rCuTGngqs7l4vTqpzBTNPtS2eiIJ1IsjsgvSEiAlk/wnW48\n\t\t\t\t11cf6SQMQcT3HNTWrS+yLycEuWKb6Khh8RpD9D+i8w2+IspWz5lTP7BrKCUNsLOx\n\t\t\t\t6+5T52HcaZ9z3wMnDqfqIKWl3h8M+q+HFQ4EN5BPWYV4fF7EOx7+Qf2fKDFPoTjC\n\t\t\t\tVTWzDRNAA1xPqwdF7IdPVOXCdaUJDOhHeXZGaTNSwQKBgQDxb9UiR/Jh1R3muL7I\n\t\t\t\tneIt1gXa0O+SK7NWYl4DkArYo7V81ztxI8r+xKEeu5zRZZkpaJHxOnd3VfADascw\n\t\t\t\tUfALvxGxN2z42lE6zdhrmxZ3ma+akQFsv7NyXcBT00sdW+xmOiCaAj0cgxNOXiV3\n\t\t\t\tsYOwUy3SqUIPO2obpb+KC5ALHwKBgQDfH+NSQ/jn89oVZ3lzUORa+Z+aL1TGsgzs\n\t\t\t\tp7IG0MTEYiR9/AExYUwJab0M4PDXhumeoACMfkCFALNVhpch2nXZv7X5445yRgfD\n\t\t\t\tONY4WknecuA0rfCLTruNWnQ3RR+BXmd9jD/5igd9hEIawz3V+jCHvAtzI8/CZIBt\n\t\t\t\tAArBs5kp+QKBgQCdxwN1n6baIDemK10iJWtFoPO6h4fH8h8EeMwPb/ZmlLVpnA4Q\n\t\t\t\tZd+mlkDkoJ5eiRKKaPfWuOqRZeuvj/wTq7g/NOIO+bWQ+rrSvuqLh5IrHpgPXmub\n\t\t\t\t8bsHJhUlspMH4KagN6ROgOAG3fGj6Qp7KdpxRCpR3KJ66czxvGNrhxre6QKBgB+s\n\t\t\t\tMCGiYnfSprd5G8VhyziazKwfYeJerfT+DQhopDXYVKPJnQW8cQW5C8wDNkzx6sHI\n\t\t\t\tpqtK1K/MnKhcVaHJmAcT7qoNQlA4Xqu4qrgPIQNBvU/dDRNJVthG6c5aspEzrG8m\n\t\t\t\t9IHgtRV9K8EOy/1O6YqrB9kNUVWf3JccdWpvqyNJAoGAORzJiQCOk4egbdcozDTo\n\t\t\t\t4Tg4qk/03qpTy5k64DxkX1nJHu8V/hsKwq9Af7Fj/iHy2Av54BLPlBaGPwMi2bzB\n\t\t\t\tgYjmUomvx/fqOTQks9Rc4PIMB43p6Rdj0sh+52SKPDR2eHbwsmpuQUXnAs20BPPI\n\t\t\t\tJ/OOn5zOs8yf26os0q3+JUM=\n\t\t\t\t-----END PRIVATE KEY-----\"\"\";\n\t\tString privateKey = signingKey.replace(\"-----BEGIN PRIVATE KEY-----\\n\", \"\");\n\t\tprivateKey = privateKey.replace(\"-----END PRIVATE KEY-----\", \"\");\n\t\tprivateKey = privateKey.replace(\"\\n\", \"\");\n\t\tbyte[] pkcs8EncodedBytes = Base64.getDecoder().decode(privateKey);\n\t\tPKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);\n\t\tKeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n\t\treturn keyFactory.generatePrivate(keySpec);\n\t}\n\n\tprivate byte[] dotConcat(byte[]... bytes) throws IOException {\n\t\tByteArrayOutputStream result = new ByteArrayOutputStream();\n\t\tfor (int i = 0; i < bytes.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tStreamUtils.copy(DOT, result);\n\t\t\t}\n\t\t\tStreamUtils.copy(bytes[i], result);\n\t\t}\n\t\treturn result.toByteArray();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryActuatorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.filter.CompositeFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;\nimport static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n/**\n * Tests for {@link CloudFoundryActuatorAutoConfiguration}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryActuatorAutoConfigurationTests {\n\n\tprivate static final String V3_JSON = ApiVersion.V3.getProducedMimeType().toString();\n\n\tprivate static final String BASE_PATH = \"/cloudfoundryapplication\";\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,\n\t\t\t\tServletWebSecurityAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\t\tJacksonAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\tHttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t/* RestTemplateAutoConfiguration.class, */ ManagementContextAutoConfiguration.class,\n\t\t\t\tServletManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, CloudFoundryActuatorAutoConfiguration.class));\n\n\t@Test\n\tvoid cloudFoundryPlatformActive() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tEndpointMapping endpointMapping = (EndpointMapping) ReflectionTestUtils.getField(handlerMapping,\n\t\t\t\t\t\t\"endpointMapping\");\n\t\t\t\tassertThat(endpointMapping).isNotNull();\n\t\t\t\tassertThat(endpointMapping.getPath()).isEqualTo(\"/cloudfoundryapplication\");\n\t\t\t\tCorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils.getField(handlerMapping,\n\t\t\t\t\t\t\"corsConfiguration\");\n\t\t\t\tassertThat(corsConfiguration).isNotNull();\n\t\t\t\tassertThat(corsConfiguration.getAllowedOrigins()).contains(\"*\");\n\t\t\t\tassertThat(corsConfiguration.getAllowedMethods())\n\t\t\t\t\t.containsAll(Arrays.asList(HttpMethod.GET.name(), HttpMethod.POST.name()));\n\t\t\t\tassertThat(corsConfiguration.getAllowedHeaders())\n\t\t\t\t\t.containsAll(Arrays.asList(\"Authorization\", \"X-Cf-App-Instance\", \"Content-Type\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudfoundryapplicationProducesActuatorMediaType() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tMockMvcTester mvc = MockMvcTester.from(context);\n\t\t\t\tassertThat(mvc.get().uri(\"/cloudfoundryapplication\")).hasHeader(\"Content-Type\", V3_JSON);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActiveSetsApplicationId() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tObject interceptor = ReflectionTestUtils.getField(handlerMapping, \"securityInterceptor\");\n\t\t\t\tassertThat(interceptor).isNotNull();\n\t\t\t\tString applicationId = (String) ReflectionTestUtils.getField(interceptor, \"applicationId\");\n\t\t\t\tassertThat(applicationId).isEqualTo(\"my-app-id\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActiveSetsCloudControllerUrl() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tObject interceptor = ReflectionTestUtils.getField(handlerMapping, \"securityInterceptor\");\n\t\t\t\tassertThat(interceptor).isNotNull();\n\t\t\t\tObject interceptorSecurityService = ReflectionTestUtils.getField(interceptor,\n\t\t\t\t\t\t\"cloudFoundrySecurityService\");\n\t\t\t\tassertThat(interceptorSecurityService).isNotNull();\n\t\t\t\tString cloudControllerUrl = (String) ReflectionTestUtils.getField(interceptorSecurityService,\n\t\t\t\t\t\t\"cloudControllerUrl\");\n\t\t\t\tassertThat(cloudControllerUrl).isEqualTo(\"https://my-cloud-controller.com\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid skipSslValidation() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\",\n\t\t\t\t\t\"management.cloudfoundry.skip-ssl-validation:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tassertThat(handlerMapping)\n\t\t\t\t\t.extracting(\"securityInterceptor.cloudFoundrySecurityService.restClient.clientRequestFactory\")\n\t\t\t\t\t.isInstanceOf(SkipSslVerificationHttpRequestFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformActiveAndCloudControllerUrlNotPresent() {\n\t\tthis.contextRunner.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tObject securityInterceptor = ReflectionTestUtils.getField(handlerMapping, \"securityInterceptor\");\n\t\t\t\tassertThat(securityInterceptor).isNotNull();\n\t\t\t\tObject interceptorSecurityService = ReflectionTestUtils.getField(securityInterceptor,\n\t\t\t\t\t\t\"cloudFoundrySecurityService\");\n\t\t\t\tassertThat(interceptorSecurityService).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudFoundryPathsPermittedBySpringSecurity() {\n\t\tthis.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\")\n\t\t\t.run((context) -> {\n\t\t\t\tSecurityFilterChain chain = getSecurityFilterChain(context);\n\t\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\t\ttestCloudFoundrySecurity(request, BASE_PATH, chain);\n\t\t\t\ttestCloudFoundrySecurity(request, BASE_PATH + \"/\", chain);\n\t\t\t\ttestCloudFoundrySecurity(request, BASE_PATH + \"/test\", chain);\n\t\t\t\ttestCloudFoundrySecurity(request, BASE_PATH + \"/test/a\", chain);\n\t\t\t\ttestCloudFoundrySecurity(request, BASE_PATH + \"/other-path\", chain);\n\t\t\t\trequest.setServletPath(\"/some-other-path\");\n\t\t\t\trequest.setRequestURI(\"/some-other-path\");\n\t\t\t\tassertThat(chain.matches(request)).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid cloudFoundryPathsPermittedWithCsrfBySpringSecurity() {\n\t\tthis.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\")\n\t\t\t.run((context) -> {\n\t\t\t\tMockMvc mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();\n\t\t\t\tmvc.perform(post(BASE_PATH + \"/test?name=test\").contentType(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.with(csrf().useInvalidToken())).andExpect(status().isServiceUnavailable());\n\t\t\t\t// If CSRF fails we'll get a 403, if it works we get service unavailable\n\t\t\t\t// because of \"Cloud controller URL is not available\"\n\t\t\t});\n\t}\n\n\tprivate SecurityFilterChain getSecurityFilterChain(AssertableWebApplicationContext context) {\n\t\tFilter springSecurityFilterChain = context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);\n\t\tFilterChainProxy filterChainProxy = getFilterChainProxy(springSecurityFilterChain);\n\t\treturn filterChainProxy.getFilterChains().get(0);\n\t}\n\n\tprivate FilterChainProxy getFilterChainProxy(Filter filter) {\n\t\tif (filter instanceof FilterChainProxy filterChainProxy) {\n\t\t\treturn filterChainProxy;\n\t\t}\n\t\tif (filter instanceof CompositeFilter) {\n\t\t\tList<?> filters = (List<?>) ReflectionTestUtils.getField(filter, \"filters\");\n\t\t\tassertThat(filters).isNotNull();\n\t\t\treturn (FilterChainProxy) filters.stream()\n\t\t\t\t.filter(FilterChainProxy.class::isInstance)\n\t\t\t\t.findFirst()\n\t\t\t\t.orElseThrow();\n\t\t}\n\t\tthrow new IllegalStateException(\"No FilterChainProxy found\");\n\t}\n\n\tprivate static void testCloudFoundrySecurity(MockHttpServletRequest request, String requestUri,\n\t\t\tSecurityFilterChain chain) {\n\t\trequest.setRequestURI(requestUri);\n\t\tassertThat(chain.matches(request)).isTrue();\n\t}\n\n\t@Test\n\tvoid cloudFoundryPlatformInactive() {\n\t\tthis.contextRunner.withPropertyValues()\n\t\t\t.run((context) -> assertThat(context.containsBean(\"cloudFoundryWebEndpointServletHandlerMapping\"))\n\t\t\t\t.isFalse());\n\t}\n\n\t@Test\n\tvoid cloudFoundryManagementEndpointsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"VCAP_APPLICATION=---\", \"management.cloudfoundry.enabled:false\")\n\t\t\t.run((context) -> assertThat(context.containsBean(\"cloudFoundryEndpointHandlerMapping\")).isFalse());\n\t}\n\n\t@Test\n\tvoid allEndpointsAvailableUnderCloudFoundryWithoutExposeAllOnWeb() {\n\t\tthis.contextRunner.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = handlerMapping.getEndpoints();\n\t\t\t\tassertThat(endpoints.stream()\n\t\t\t\t\t.filter((candidate) -> EndpointId.of(\"test\").equals(candidate.getEndpointId()))\n\t\t\t\t\t.findFirst()).isNotEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid endpointPathCustomizationIsNotApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\",\n\t\t\t\t\t\"management.endpoints.web.path-mapping.test=custom\")\n\t\t\t.withBean(TestEndpoint.class, TestEndpoint::new)\n\t\t\t.run((context) -> {\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping(context);\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = handlerMapping.getEndpoints();\n\t\t\t\tExposableWebEndpoint endpoint = endpoints.stream()\n\t\t\t\t\t.filter((candidate) -> EndpointId.of(\"test\").equals(candidate.getEndpointId()))\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.get();\n\t\t\t\tCollection<WebOperation> operations = endpoint.getOperations();\n\t\t\t\tassertThat(operations).hasSize(2);\n\t\t\t\tassertThat(operations.iterator().next().getRequestPredicate().getPath()).isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid healthEndpointInvokerShouldBeCloudFoundryWebExtension() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"VCAP_APPLICATION:---\", \"vcap.application.application_id:my-app-id\",\n\t\t\t\t\t\"vcap.application.cf_api:https://my-cloud-controller.com\")\n\t\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tCollection<ExposableWebEndpoint> endpoints = context\n\t\t\t\t\t.getBean(\"cloudFoundryWebEndpointServletHandlerMapping\",\n\t\t\t\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping.class)\n\t\t\t\t\t.getEndpoints();\n\t\t\t\tExposableWebEndpoint endpoint = endpoints.iterator().next();\n\t\t\t\tassertThat(endpoint.getOperations()).hasSize(2);\n\t\t\t\tWebOperation webOperation = findOperationWithRequestPath(endpoint, \"health\");\n\t\t\t\tassertThat(webOperation).extracting(\"invoker.target\")\n\t\t\t\t\t.isInstanceOf(CloudFoundryHealthEndpointWebExtension.class);\n\t\t\t});\n\t}\n\n\tprivate CloudFoundryWebEndpointServletHandlerMapping getHandlerMapping(ApplicationContext context) {\n\t\treturn context.getBean(\"cloudFoundryWebEndpointServletHandlerMapping\",\n\t\t\t\tCloudFoundryWebEndpointServletHandlerMapping.class);\n\t}\n\n\tprivate WebOperation findOperationWithRequestPath(ExposableWebEndpoint endpoint, String requestPath) {\n\t\tfor (WebOperation operation : endpoint.getOperations()) {\n\t\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\t\tif (predicate.getPath().equals(requestPath) && predicate.getProduces().contains(V3_JSON)) {\n\t\t\t\treturn operation;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"No operation found with request path \" + requestPath + \" from \" + endpoint.getOperations());\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\tString hello() {\n\t\t\treturn \"hello world\";\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid update(String name) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryHealthEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.health.actuate.endpoint.CompositeHealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.HealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.IndicatedHealthDescriptor;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryHealthEndpointWebExtension}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryHealthEndpointWebExtensionTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withPropertyValues(\"VCAP_APPLICATION={}\")\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(SecurityAutoConfiguration.class, ServletWebSecurityAutoConfiguration.class,\n\t\t\t\t\t\tWebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,\n\t\t\t\t\t\tDispatcherServletAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class, RestTemplateAutoConfiguration.class,\n\t\t\t\t\t\tManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,\n\t\t\t\t\t\tEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\t\tHealthContributorAutoConfiguration.class, HealthContributorRegistryAutoConfiguration.class,\n\t\t\t\t\t\tHealthEndpointAutoConfiguration.class, CloudFoundryActuatorAutoConfiguration.class))\n\t\t.withUserConfiguration(TestHealthIndicator.class);\n\n\t@Test\n\tvoid healthComponentsAlwaysPresent() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tCloudFoundryHealthEndpointWebExtension extension = context\n\t\t\t\t.getBean(CloudFoundryHealthEndpointWebExtension.class);\n\t\t\tHealthDescriptor descriptor = extension.health(ApiVersion.V3).getBody();\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tMap<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();\n\t\t\tassertThat(components).isNotNull();\n\t\t\tHealthDescriptor component = components.entrySet().iterator().next().getValue();\n\t\t\tassertThat(((IndicatedHealthDescriptor) component).getDetails()).containsEntry(\"spring\", \"boot\");\n\t\t});\n\t}\n\n\tprivate static final class TestHealthIndicator implements HealthIndicator {\n\n\t\t@Override\n\t\tpublic Health health() {\n\t\t\treturn Health.up().withDetail(\"spring\", \"boot\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryInfoEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryInfoEndpointWebExtension}.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryInfoEndpointWebExtensionTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withPropertyValues(\"VCAP_APPLICATION={}\")\n\t\t.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,\n\t\t\t\tServletWebSecurityAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\t\tJacksonAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\tHttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tRestTemplateAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\tServletManagementContextAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, ProjectInfoAutoConfiguration.class,\n\t\t\t\tInfoContributorAutoConfiguration.class, InfoEndpointAutoConfiguration.class,\n\t\t\t\tHealthEndpointAutoConfiguration.class, CloudFoundryActuatorAutoConfiguration.class));\n\n\t@Test\n\t@WithResource(name = \"git.properties\", content = \"\"\"\n\t\t\t#Generated by Git-Commit-Id-Plugin\n\t\t\t#Thu May 23 09:26:42 BST 2013\n\t\t\tgit.commit.id.abbrev=e02a4f3\n\t\t\tgit.commit.user.email=dsyer@vmware.com\n\t\t\tgit.commit.message.full=Update Spring\n\t\t\tgit.commit.id=e02a4f3b6f452cdbf6dd311f1362679eb4c31ced\n\t\t\tgit.commit.message.short=Update Spring\n\t\t\tgit.commit.user.name=Dave Syer\n\t\t\tgit.build.user.name=Dave Syer\n\t\t\tgit.build.user.email=dsyer@vmware.com\n\t\t\tgit.branch=develop\n\t\t\tgit.commit.time=2013-04-24T08\\\\:42\\\\:13+0100\n\t\t\tgit.build.time=2013-05-23T09\\\\:26\\\\:42+0100\n\t\t\t\"\"\")\n\t@SuppressWarnings(\"unchecked\")\n\tvoid gitFullDetailsAlwaysPresent() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tCloudFoundryInfoEndpointWebExtension extension = context\n\t\t\t\t.getBean(CloudFoundryInfoEndpointWebExtension.class);\n\t\t\tMap<String, Object> git = (Map<String, Object>) extension.info().get(\"git\");\n\t\t\tassertThat(git).isNotNull();\n\t\t\tMap<String, Object> commit = (Map<String, Object>) git.get(\"commit\");\n\t\t\tassertThat(commit).hasSize(4);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryMvcWebEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for web endpoints exposed using Spring MVC on CloudFoundry.\n *\n * @author Madhura Bhave\n */\nclass CloudFoundryMvcWebEndpointIntegrationTests {\n\n\tprivate final TokenValidator tokenValidator = mock(TokenValidator.class);\n\n\tprivate final SecurityService securityService = mock(SecurityService.class);\n\n\t@Test\n\tvoid operationWithSecurityInterceptorForbidden() {\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(AccessLevel.RESTRICTED);\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/cfApplication/test\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.FORBIDDEN));\n\t}\n\n\t@Test\n\tvoid operationWithSecurityInterceptorSuccess() {\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(AccessLevel.FULL);\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/cfApplication/test\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.OK));\n\t}\n\n\t@Test\n\tvoid responseToOptionsRequestIncludesCorsHeaders() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.options()\n\t\t\t\t\t.uri(\"/cfApplication/test\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Access-Control-Request-Method\", \"POST\")\n\t\t\t\t\t.header(\"Origin\", \"https://example.com\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueEquals(\"Access-Control-Allow-Origin\", \"https://example.com\")\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.valueEquals(\"Access-Control-Allow-Methods\", \"GET,POST\"));\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsWithFullAccess() {\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(AccessLevel.FULL);\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/cfApplication\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"_links.length()\")\n\t\t\t\t\t.isEqualTo(5)\n\t\t\t\t\t.jsonPath(\"_links.self.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.self.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.info.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.info.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.env.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.env.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.test.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.test.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.test-part.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.test-part.templated\")\n\t\t\t\t\t.isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsForbidden() {\n\t\tCloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(Reason.INVALID_TOKEN,\n\t\t\t\t\"invalid-token\");\n\t\twillThrow(exception).given(this.tokenValidator).validate(any());\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/cfApplication\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isUnauthorized());\n\t}\n\n\t@Test\n\tvoid linksToOtherEndpointsWithRestrictedAccess() {\n\t\tgiven(this.securityService.getAccessLevel(any(), eq(\"app-id\"))).willReturn(AccessLevel.RESTRICTED);\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/cfApplication\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.header(\"Authorization\", \"bearer \" + mockAccessToken())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"_links.length()\")\n\t\t\t\t\t.isEqualTo(2)\n\t\t\t\t\t.jsonPath(\"_links.self.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.self.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.info.href\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"_links.info.templated\")\n\t\t\t\t\t.isEqualTo(false)\n\t\t\t\t\t.jsonPath(\"_links.env\")\n\t\t\t\t\t.doesNotExist()\n\t\t\t\t\t.jsonPath(\"_links.test\")\n\t\t\t\t\t.doesNotExist()\n\t\t\t\t\t.jsonPath(\"_links.test-part\")\n\t\t\t\t\t.doesNotExist());\n\t}\n\n\t@Test\n\tvoid unknownEndpointsAreForbidden() {\n\t\tload(TestEndpointConfiguration.class,\n\t\t\t\t(client) -> client.get()\n\t\t\t\t\t.uri(\"/cfApplication/unknown\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isForbidden());\n\t}\n\n\tprivate void load(Class<?> configuration, Consumer<WebTestClient> clientConsumer) {\n\t\tBiConsumer<ApplicationContext, WebTestClient> consumer = (context, client) -> clientConsumer.accept(client);\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withUserConfiguration(configuration, CloudFoundryMvcConfiguration.class)\n\t\t\t.withBean(TokenValidator.class, () -> this.tokenValidator)\n\t\t\t.withBean(SecurityService.class, () -> this.securityService)\n\t\t\t.run((context) -> consumer.accept(context, WebTestClient.bindToServer()\n\t\t\t\t.baseUrl(\"http://localhost:\" + getPort(\n\t\t\t\t\t\t(AnnotationConfigServletWebServerApplicationContext) context.getSourceApplicationContext()))\n\t\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t\t.build()));\n\t}\n\n\tprivate int getPort(AnnotationConfigServletWebServerApplicationContext context) {\n\t\tWebServer webServer = context.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\treturn webServer.getPort();\n\t}\n\n\tprivate String mockAccessToken() {\n\t\treturn \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu\"\n\t\t\t\t+ \"Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ.\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(\"signature\".getBytes());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class CloudFoundryMvcConfiguration {\n\n\t\t@Bean\n\t\tSecurityInterceptor interceptor(TokenValidator tokenValidator, SecurityService securityService) {\n\t\t\treturn new SecurityInterceptor(tokenValidator, securityService, \"app-id\");\n\t\t}\n\n\t\t@Bean\n\t\tEndpointMediaTypes EndpointMediaTypes() {\n\t\t\treturn new EndpointMediaTypes(Collections.singletonList(\"application/json\"),\n\t\t\t\t\tCollections.singletonList(\"application/json\"));\n\t\t}\n\n\t\t@Bean\n\t\tCloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(\n\t\t\t\tWebEndpointDiscoverer webEndpointDiscoverer, EndpointMediaTypes endpointMediaTypes,\n\t\t\t\tSecurityInterceptor interceptor) {\n\t\t\tCorsConfiguration corsConfiguration = new CorsConfiguration();\n\t\t\tcorsConfiguration.setAllowedOrigins(Arrays.asList(\"https://example.com\"));\n\t\t\tcorsConfiguration.setAllowedMethods(Arrays.asList(\"GET\", \"POST\"));\n\t\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointDiscoverer.getEndpoints();\n\t\t\tList<ExposableEndpoint<?>> allEndpoints = new ArrayList<>(webEndpoints);\n\t\t\treturn new CloudFoundryWebEndpointServletHandlerMapping(new EndpointMapping(\"/cfApplication\"), webEndpoints,\n\t\t\t\t\tendpointMediaTypes, corsConfiguration, interceptor, allEndpoints);\n\t\t}\n\n\t\t@Bean\n\t\tWebEndpointDiscoverer webEndpointDiscoverer(ApplicationContext applicationContext,\n\t\t\t\tEndpointMediaTypes endpointMediaTypes) {\n\t\t\tParameterValueMapper parameterMapper = new ConversionServiceParameterValueMapper(\n\t\t\t\t\tDefaultConversionService.getSharedInstance());\n\t\t\treturn new WebEndpointDiscoverer(applicationContext, parameterMapper, endpointMediaTypes, null, null,\n\t\t\t\t\tCollections.emptyList(), Collections.emptyList(), Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tEndpointDelegate endpointDelegate() {\n\t\t\treturn mock(EndpointDelegate.class);\n\t\t}\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"test\")\n\tstatic class TestEndpoint {\n\n\t\tprivate final EndpointDelegate endpointDelegate;\n\n\t\tTestEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\tthis.endpointDelegate = endpointDelegate;\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readPart(@Selector String part) {\n\t\t\treturn Collections.singletonMap(\"part\", part);\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid write(String foo, String bar) {\n\t\t\tthis.endpointDelegate.write(foo, bar);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"env\")\n\tstatic class TestEnvEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"info\")\n\tstatic class TestInfoEndpoint {\n\n\t\t@ReadOperation\n\t\tMap<String, Object> readAll() {\n\t\t\treturn Collections.singletonMap(\"All\", true);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(CloudFoundryMvcConfiguration.class)\n\tstatic class TestEndpointConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint testEndpoint(EndpointDelegate endpointDelegate) {\n\t\t\treturn new TestEndpoint(endpointDelegate);\n\t\t}\n\n\t\t@Bean\n\t\tTestInfoEndpoint testInfoEnvEndpoint() {\n\t\t\treturn new TestInfoEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestEnvEndpoint testEnvEndpoint() {\n\t\t\treturn new TestEnvEndpoint();\n\t\t}\n\n\t}\n\n\tinterface EndpointDelegate {\n\n\t\tvoid write();\n\n\t\tvoid write(String foo, String bar);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/CloudFoundryWebEndpointServletHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryLinksHandler;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CloudFoundryWebEndpointServletHandlerMapping}.\n *\n * @author Moritz Halbritter\n */\nclass CloudFoundryWebEndpointServletHandlerMappingTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew CloudFoundryWebEndpointServletHandlerMappingRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(CloudFoundryLinksHandler.class, \"links\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/SecurityInterceptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.SecurityResponse;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.web.MockHttpServletRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link SecurityInterceptor}.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass SecurityInterceptorTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate TokenValidator tokenValidator;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate SecurityService securityService;\n\n\tprivate SecurityInterceptor interceptor;\n\n\tprivate MockHttpServletRequest request;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.interceptor = new SecurityInterceptor(this.tokenValidator, this.securityService, \"my-app-id\");\n\t\tthis.request = new MockHttpServletRequest();\n\t}\n\n\t@Test\n\tvoid preHandleWhenRequestIsPreFlightShouldReturnTrue() {\n\t\tthis.request.setMethod(\"OPTIONS\");\n\t\tthis.request.addHeader(HttpHeaders.ORIGIN, \"https://example.com\");\n\t\tthis.request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\");\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid preHandleWhenTokenIsMissingShouldReturnFalse() {\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tassertThat(response.getStatus()).isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus());\n\t}\n\n\t@Test\n\tvoid preHandleWhenTokenIsNotBearerShouldReturnFalse() {\n\t\tthis.request.addHeader(\"Authorization\", mockAccessToken());\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tassertThat(response.getStatus()).isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus());\n\t}\n\n\t@Test\n\tvoid preHandleWhenApplicationIdIsNullShouldReturnFalse() {\n\t\tthis.interceptor = new SecurityInterceptor(this.tokenValidator, this.securityService, null);\n\t\tthis.request.addHeader(\"Authorization\", \"bearer \" + mockAccessToken());\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tassertThat(response.getStatus()).isEqualTo(Reason.SERVICE_UNAVAILABLE.getStatus());\n\t}\n\n\t@Test\n\tvoid preHandleWhenCloudFoundrySecurityServiceIsNullShouldReturnFalse() {\n\t\tthis.interceptor = new SecurityInterceptor(this.tokenValidator, null, \"my-app-id\");\n\t\tthis.request.addHeader(\"Authorization\", \"bearer \" + mockAccessToken());\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tassertThat(response.getStatus()).isEqualTo(Reason.SERVICE_UNAVAILABLE.getStatus());\n\t}\n\n\t@Test\n\tvoid preHandleWhenAccessIsNotAllowedShouldReturnFalse() {\n\t\tString accessToken = mockAccessToken();\n\t\tthis.request.addHeader(\"Authorization\", \"bearer \" + accessToken);\n\t\tgiven(this.securityService.getAccessLevel(accessToken, \"my-app-id\")).willReturn(AccessLevel.RESTRICTED);\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tassertThat(response.getStatus()).isEqualTo(Reason.ACCESS_DENIED.getStatus());\n\t}\n\n\t@Test\n\tvoid preHandleSuccessfulWithFullAccess() {\n\t\tString accessToken = mockAccessToken();\n\t\tthis.request.addHeader(\"Authorization\", \"Bearer \" + accessToken);\n\t\tgiven(this.securityService.getAccessLevel(accessToken, \"my-app-id\")).willReturn(AccessLevel.FULL);\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"test\"));\n\t\tthen(this.tokenValidator).should().validate(assertArg((token) -> assertThat(token).hasToString(accessToken)));\n\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(this.request.getAttribute(\"cloudFoundryAccessLevel\")).isEqualTo(AccessLevel.FULL);\n\t}\n\n\t@Test\n\tvoid preHandleSuccessfulWithRestrictedAccess() {\n\t\tString accessToken = mockAccessToken();\n\t\tthis.request.addHeader(\"Authorization\", \"Bearer \" + accessToken);\n\t\tgiven(this.securityService.getAccessLevel(accessToken, \"my-app-id\")).willReturn(AccessLevel.RESTRICTED);\n\t\tSecurityResponse response = this.interceptor.preHandle(this.request, EndpointId.of(\"info\"));\n\t\tthen(this.tokenValidator).should().validate(assertArg((token) -> assertThat(token).hasToString(accessToken)));\n\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(this.request.getAttribute(\"cloudFoundryAccessLevel\")).isEqualTo(AccessLevel.RESTRICTED);\n\t}\n\n\tprivate String mockAccessToken() {\n\t\treturn \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwu\"\n\t\t\t\t+ \"Y29tIiwiZXhwIjoxNDI2NDIwODAwLCJhd2Vzb21lIjp0cnVlfQ.\"\n\t\t\t\t+ Base64.getEncoder().encodeToString(\"signature\".getBytes());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/SecurityServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.AccessLevel;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.header;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withServerError;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withUnauthorizedRequest;\n\n/**\n * Tests for {@link SecurityService}.\n *\n * @author Madhura Bhave\n */\nclass SecurityServiceTests {\n\n\tprivate static final String CLOUD_CONTROLLER = \"https://my-cloud-controller.com\";\n\n\tprivate static final String CLOUD_CONTROLLER_PERMISSIONS = CLOUD_CONTROLLER + \"/v2/apps/my-app-id/permissions\";\n\n\tprivate static final String UAA_URL = \"https://my-uaa.com\";\n\n\tprivate SecurityService securityService;\n\n\tprivate MockRestServiceServer server;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockServerRestTemplateCustomizer mockServerCustomizer = new MockServerRestTemplateCustomizer();\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder(mockServerCustomizer);\n\t\tthis.securityService = new SecurityService(RestClient.builder(builder.build()), CLOUD_CONTROLLER, false);\n\t\tthis.server = mockServerCustomizer.getServer();\n\t}\n\n\t@Test\n\tvoid skipSslValidationWhenTrue() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder();\n\t\tthis.securityService = new SecurityService(RestClient.builder(builder.build()), CLOUD_CONTROLLER, true);\n\t\tassertThat(this.securityService).extracting(\"restClient.clientRequestFactory\")\n\t\t\t.isInstanceOf(SkipSslVerificationHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid doNotSkipSslValidationWhenFalse() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder();\n\t\tthis.securityService = new SecurityService(RestClient.builder(builder.build()), CLOUD_CONTROLLER, false);\n\t\tassertThat(this.securityService).extracting(\"restClient.clientRequestFactory\")\n\t\t\t.isNotInstanceOf(SkipSslVerificationHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenSpaceDeveloperShouldReturnFull() {\n\t\tString responseBody = \"{\\\"read_sensitive_data\\\": true,\\\"read_basic_data\\\": true}\";\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER_PERMISSIONS))\n\t\t\t.andExpect(header(\"Authorization\", \"bearer my-access-token\"))\n\t\t\t.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));\n\t\tAccessLevel accessLevel = this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\");\n\t\tthis.server.verify();\n\t\tassertThat(accessLevel).isEqualTo(AccessLevel.FULL);\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenNotSpaceDeveloperShouldReturnRestricted() {\n\t\tString responseBody = \"{\\\"read_sensitive_data\\\": false,\\\"read_basic_data\\\": true}\";\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER_PERMISSIONS))\n\t\t\t.andExpect(header(\"Authorization\", \"bearer my-access-token\"))\n\t\t\t.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));\n\t\tAccessLevel accessLevel = this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\");\n\t\tthis.server.verify();\n\t\tassertThat(accessLevel).isEqualTo(AccessLevel.RESTRICTED);\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenTokenIsNotValidShouldThrowException() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER_PERMISSIONS))\n\t\t\t.andExpect(header(\"Authorization\", \"bearer my-access-token\"))\n\t\t\t.andRespond(withUnauthorizedRequest());\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_TOKEN));\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenForbiddenShouldThrowException() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER_PERMISSIONS))\n\t\t\t.andExpect(header(\"Authorization\", \"bearer my-access-token\"))\n\t\t\t.andRespond(withStatus(HttpStatus.FORBIDDEN));\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.satisfies(reasonRequirement(Reason.ACCESS_DENIED));\n\t}\n\n\t@Test\n\tvoid getAccessLevelWhenCloudControllerIsNotReachableThrowsException() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER_PERMISSIONS))\n\t\t\t.andExpect(header(\"Authorization\", \"bearer my-access-token\"))\n\t\t\t.andRespond(withServerError());\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> this.securityService.getAccessLevel(\"my-access-token\", \"my-app-id\"))\n\t\t\t.satisfies(reasonRequirement(Reason.SERVICE_UNAVAILABLE));\n\t}\n\n\t@Test\n\tvoid fetchTokenKeysWhenSuccessfulShouldReturnListOfKeysFromUAA() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER + \"/info\"))\n\t\t\t.andRespond(withSuccess(\"{\\\"token_endpoint\\\":\\\"https://my-uaa.com\\\"}\", MediaType.APPLICATION_JSON));\n\t\tString tokenKeyValue = \"\"\"\n\t\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\t\tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO\n\t\t\t\trn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7\n\t\t\t\tfYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB\n\t\t\t\tLCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO\n\t\t\t\tkqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo\n\t\t\t\tjfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI\n\t\t\t\tJwIDAQAB\n\t\t\t\t-----END PUBLIC KEY-----\"\"\";\n\t\tString responseBody = \"{\\\"keys\\\" : [ {\\\"kid\\\":\\\"test-key\\\",\\\"value\\\" : \\\"\" + tokenKeyValue.replace(\"\\n\", \"\\\\n\")\n\t\t\t\t+ \"\\\"} ]}\";\n\t\tthis.server.expect(requestTo(UAA_URL + \"/token_keys\"))\n\t\t\t.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));\n\t\tMap<String, String> tokenKeys = this.securityService.fetchTokenKeys();\n\t\tthis.server.verify();\n\t\tassertThat(tokenKeys).containsEntry(\"test-key\", tokenKeyValue);\n\t}\n\n\t@Test\n\tvoid fetchTokenKeysWhenNoKeysReturnedFromUAA() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER + \"/info\"))\n\t\t\t.andRespond(withSuccess(\"{\\\"token_endpoint\\\":\\\"\" + UAA_URL + \"\\\"}\", MediaType.APPLICATION_JSON));\n\t\tString responseBody = \"{\\\"keys\\\": []}\";\n\t\tthis.server.expect(requestTo(UAA_URL + \"/token_keys\"))\n\t\t\t.andRespond(withSuccess(responseBody, MediaType.APPLICATION_JSON));\n\t\tMap<String, String> tokenKeys = this.securityService.fetchTokenKeys();\n\t\tthis.server.verify();\n\t\tassertThat(tokenKeys).isEmpty();\n\t}\n\n\t@Test\n\tvoid fetchTokenKeysWhenUnsuccessfulShouldThrowException() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER + \"/info\"))\n\t\t\t.andRespond(withSuccess(\"{\\\"token_endpoint\\\":\\\"\" + UAA_URL + \"\\\"}\", MediaType.APPLICATION_JSON));\n\t\tthis.server.expect(requestTo(UAA_URL + \"/token_keys\")).andRespond(withServerError());\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> this.securityService.fetchTokenKeys())\n\t\t\t.satisfies(reasonRequirement(Reason.SERVICE_UNAVAILABLE));\n\t}\n\n\t@Test\n\tvoid getUaaUrlShouldCallCloudControllerInfoOnlyOnce() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER + \"/info\"))\n\t\t\t.andRespond(withSuccess(\"{\\\"token_endpoint\\\":\\\"\" + UAA_URL + \"\\\"}\", MediaType.APPLICATION_JSON));\n\t\tString uaaUrl = this.securityService.getUaaUrl();\n\t\tthis.server.verify();\n\t\tassertThat(uaaUrl).isEqualTo(UAA_URL);\n\t\t// Second call should not need to hit server\n\t\tuaaUrl = this.securityService.getUaaUrl();\n\t\tassertThat(uaaUrl).isEqualTo(UAA_URL);\n\t}\n\n\t@Test\n\tvoid getUaaUrlWhenCloudControllerUrlIsNotReachableShouldThrowException() {\n\t\tthis.server.expect(requestTo(CLOUD_CONTROLLER + \"/info\")).andRespond(withServerError());\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(() -> this.securityService.getUaaUrl())\n\t\t\t.satisfies(reasonRequirement(Reason.SERVICE_UNAVAILABLE));\n\t}\n\n\tprivate Consumer<CloudFoundryAuthorizationException> reasonRequirement(Reason reason) {\n\t\treturn (ex) -> assertThat(ex.getReason()).isEqualTo(reason);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/SkipSslVerificationHttpRequestFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport javax.net.ssl.SSLHandshakeException;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.web.servlet.ExampleServlet;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.client.ResourceAccessException;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Test for {@link SkipSslVerificationHttpRequestFactory}.\n */\nclass SkipSslVerificationHttpRequestFactoryTests {\n\n\tprivate @Nullable WebServer webServer;\n\n\t@AfterEach\n\tvoid shutdownContainer() {\n\t\tif (this.webServer != null) {\n\t\t\tthis.webServer.stop();\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid restCallToSelfSignedServerShouldNotThrowSslException() {\n\t\tString httpsUrl = getHttpsUrl();\n\t\tSkipSslVerificationHttpRequestFactory requestFactory = new SkipSslVerificationHttpRequestFactory();\n\t\tRestTemplate restTemplate = new RestTemplate(requestFactory);\n\t\tRestTemplate otherRestTemplate = new RestTemplate();\n\t\tResponseEntity<String> responseEntity = restTemplate.getForEntity(httpsUrl, String.class);\n\t\tassertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThatExceptionOfType(ResourceAccessException.class)\n\t\t\t.isThrownBy(() -> otherRestTemplate.getForEntity(httpsUrl, String.class))\n\t\t\t.withCauseInstanceOf(SSLHandshakeException.class);\n\t}\n\n\tprivate String getHttpsUrl() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tfactory.setSsl(getSsl(\"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(), \"/hello\"));\n\t\tthis.webServer.start();\n\t\treturn \"https://localhost:\" + this.webServer.getPort() + \"/hello\";\n\t}\n\n\tprivate Ssl getSsl(String keyPassword, String keyStore) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setEnabled(true);\n\t\tssl.setKeyPassword(keyPassword);\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\treturn ssl;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-cloudfoundry/src/test/java/org/springframework/boot/cloudfoundry/autoconfigure/actuate/endpoint/servlet/TokenValidatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.servlet;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.Signature;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.CloudFoundryAuthorizationException.Reason;\nimport org.springframework.boot.cloudfoundry.autoconfigure.actuate.endpoint.Token;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link TokenValidator}.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(MockitoExtension.class)\nclass TokenValidatorTests {\n\n\tprivate static final byte[] DOT = \".\".getBytes();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate SecurityService securityService;\n\n\tprivate TokenValidator tokenValidator;\n\n\tprivate static final String VALID_KEY = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0m59l2u9iDnMbrXHfqkO\n\t\t\trn2dVQ3vfBJqcDuFUK03d+1PZGbVlNCqnkpIJ8syFppW8ljnWweP7+LiWpRoz0I7\n\t\t\tfYb3d8TjhV86Y997Fl4DBrxgM6KTJOuE/uxnoDhZQ14LgOU2ckXjOzOdTsnGMKQB\n\t\t\tLCl0vpcXBtFLMaSbpv1ozi8h7DJyVZ6EnFQZUWGdgTMhDrmqevfx95U/16c5WBDO\n\t\t\tkqwIn7Glry9n9Suxygbf8g5AzpWcusZgDLIIZ7JTUldBb8qU2a0Dl4mvLZOn4wPo\n\t\t\tjfj9Cw2QICsc5+Pwf21fP+hzf+1WSRHbnYv8uanRO0gZ8ekGaghM/2H6gqJbo2nI\n\t\t\tJwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\"\"\";\n\n\tprivate static final String INVALID_KEY = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxzYuc22QSst/dS7geYYK\n\t\t\t5l5kLxU0tayNdixkEQ17ix+CUcUbKIsnyftZxaCYT46rQtXgCaYRdJcbB3hmyrOa\n\t\t\tvkhTpX79xJZnQmfuamMbZBqitvscxW9zRR9tBUL6vdi/0rpoUwPMEh8+Bw7CgYR0\n\t\t\tFK0DhWYBNDfe9HKcyZEv3max8Cdq18htxjEsdYO0iwzhtKRXomBWTdhD5ykd/fAC\n\t\t\tVTr4+KEY+IeLvubHVmLUhbE5NgWXxrRpGasDqzKhCTmsa2Ysf712rl57SlH0Wz/M\n\t\t\tr3F7aM9YpErzeYLrl0GhQr9BVJxOvXcVd4kmY+XkiCcrkyS1cnghnllh+LCwQu1s\n\t\t\tYwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\"\"\";\n\n\tprivate static final Map<String, String> INVALID_KEYS = Collections.singletonMap(\"invalid-key\", INVALID_KEY);\n\n\tprivate static final Map<String, String> VALID_KEYS = Collections.singletonMap(\"valid-key\", VALID_KEY);\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.tokenValidator = new TokenValidator(this.securityService);\n\t}\n\n\t@Test\n\tvoid validateTokenWhenKidValidationFailsTwiceShouldThrowException() {\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"tokenKeys\", INVALID_KEYS);\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(INVALID_KEYS);\n\t\tString header = \"{\\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{\\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_KEY_ID));\n\t}\n\n\t@Test\n\tvoid validateTokenWhenKidValidationSucceedsInTheSecondAttempt() throws Exception {\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"tokenKeys\", INVALID_KEYS);\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(VALID_KEYS);\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(\"http://localhost:8080/uaa\");\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tthis.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes())));\n\t\tthen(this.securityService).should().fetchTokenKeys();\n\t}\n\n\t@Test\n\tvoid validateTokenShouldFetchTokenKeysIfNull() throws Exception {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(VALID_KEYS);\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(\"http://localhost:8080/uaa\");\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tthis.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes())));\n\t\tthen(this.securityService).should().fetchTokenKeys();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenValidShouldNotFetchTokenKeys() throws Exception {\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"tokenKeys\", VALID_KEYS);\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(\"http://localhost:8080/uaa\");\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tthis.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes())));\n\t\tthen(this.securityService).should(never()).fetchTokenKeys();\n\t}\n\n\t@Test\n\tvoid validateTokenWhenSignatureInvalidShouldThrowException() {\n\t\tReflectionTestUtils.setField(this.tokenValidator, \"tokenKeys\",\n\t\t\t\tCollections.singletonMap(\"valid-key\", INVALID_KEY));\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\",\\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_SIGNATURE));\n\t}\n\n\t@Test\n\tvoid validateTokenWhenTokenAlgorithmIsNotRS256ShouldThrowException() {\n\t\tString header = \"{ \\\"alg\\\": \\\"HS256\\\",  \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.satisfies(reasonRequirement(Reason.UNSUPPORTED_TOKEN_SIGNING_ALGORITHM));\n\t}\n\n\t@Test\n\tvoid validateTokenWhenExpiredShouldThrowException() {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(VALID_KEYS);\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(VALID_KEYS);\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"jti\\\": \\\"0236399c350c47f3ae77e67a75e75e7d\\\", \\\"exp\\\": 1477509977, \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.satisfies(reasonRequirement(Reason.TOKEN_EXPIRED));\n\t}\n\n\t@Test\n\tvoid validateTokenWhenIssuerIsNotValidShouldThrowException() {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(VALID_KEYS);\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(\"https://other-uaa.com\");\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\", \\\"scope\\\": [\\\"actuator.read\\\"]}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\"}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_ISSUER));\n\t}\n\n\t@Test\n\tvoid validateTokenWhenAudienceIsNotValidShouldThrowException() {\n\t\tgiven(this.securityService.fetchTokenKeys()).willReturn(VALID_KEYS);\n\t\tgiven(this.securityService.getUaaUrl()).willReturn(\"http://localhost:8080/uaa\");\n\t\tString header = \"{ \\\"alg\\\": \\\"RS256\\\",  \\\"kid\\\": \\\"valid-key\\\", \\\"typ\\\": \\\"JWT\\\"}\";\n\t\tString claims = \"{ \\\"exp\\\": 2147483647, \\\"iss\\\": \\\"http://localhost:8080/uaa/oauth/token\\\", \\\"scope\\\": [\\\"foo.bar\\\"]}\";\n\t\tassertThatExceptionOfType(CloudFoundryAuthorizationException.class)\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.tokenValidator.validate(new Token(getSignedToken(header.getBytes(), claims.getBytes()))))\n\t\t\t.satisfies(reasonRequirement(Reason.INVALID_AUDIENCE));\n\t}\n\n\tprivate String getSignedToken(byte[] header, byte[] claims) throws Exception {\n\t\tPrivateKey privateKey = getPrivateKey();\n\t\tSignature signature = Signature.getInstance(\"SHA256WithRSA\");\n\t\tsignature.initSign(privateKey);\n\t\tbyte[] content = dotConcat(Base64.getUrlEncoder().encode(header), Base64.getEncoder().encode(claims));\n\t\tsignature.update(content);\n\t\tbyte[] crypto = signature.sign();\n\t\tbyte[] token = dotConcat(Base64.getUrlEncoder().encode(header), Base64.getUrlEncoder().encode(claims),\n\t\t\t\tBase64.getUrlEncoder().encode(crypto));\n\t\treturn new String(token, StandardCharsets.UTF_8);\n\t}\n\n\tprivate PrivateKey getPrivateKey() throws InvalidKeySpecException, NoSuchAlgorithmException {\n\t\tString signingKey = \"\"\"\n\t\t\t\t-----BEGIN PRIVATE KEY-----\n\t\t\t\tMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDSbn2Xa72IOcxu\n\t\t\t\ttcd+qQ6ufZ1VDe98EmpwO4VQrTd37U9kZtWU0KqeSkgnyzIWmlbyWOdbB4/v4uJa\n\t\t\t\tlGjPQjt9hvd3xOOFXzpj33sWXgMGvGAzopMk64T+7GegOFlDXguA5TZyReM7M51O\n\t\t\t\tycYwpAEsKXS+lxcG0UsxpJum/WjOLyHsMnJVnoScVBlRYZ2BMyEOuap69/H3lT/X\n\t\t\t\tpzlYEM6SrAifsaWvL2f1K7HKBt/yDkDOlZy6xmAMsghnslNSV0FvypTZrQOXia8t\n\t\t\t\tk6fjA+iN+P0LDZAgKxzn4/B/bV8/6HN/7VZJEdudi/y5qdE7SBnx6QZqCEz/YfqC\n\t\t\t\tolujacgnAgMBAAECggEAc9X2tJ/OWWrXqinOg160gkELloJxTi8lAFsDbAGuAwpT\n\t\t\t\tJcWl1KF5CmGBjsY/8ElNi2J9GJL1HOwcBhikCVNARD1DhF6RkB13mvquWwWtTMvt\n\t\t\t\teP8JWM19DIc+E+hw2rCuTGngqs7l4vTqpzBTNPtS2eiIJ1IsjsgvSEiAlk/wnW48\n\t\t\t\t11cf6SQMQcT3HNTWrS+yLycEuWKb6Khh8RpD9D+i8w2+IspWz5lTP7BrKCUNsLOx\n\t\t\t\t6+5T52HcaZ9z3wMnDqfqIKWl3h8M+q+HFQ4EN5BPWYV4fF7EOx7+Qf2fKDFPoTjC\n\t\t\t\tVTWzDRNAA1xPqwdF7IdPVOXCdaUJDOhHeXZGaTNSwQKBgQDxb9UiR/Jh1R3muL7I\n\t\t\t\tneIt1gXa0O+SK7NWYl4DkArYo7V81ztxI8r+xKEeu5zRZZkpaJHxOnd3VfADascw\n\t\t\t\tUfALvxGxN2z42lE6zdhrmxZ3ma+akQFsv7NyXcBT00sdW+xmOiCaAj0cgxNOXiV3\n\t\t\t\tsYOwUy3SqUIPO2obpb+KC5ALHwKBgQDfH+NSQ/jn89oVZ3lzUORa+Z+aL1TGsgzs\n\t\t\t\tp7IG0MTEYiR9/AExYUwJab0M4PDXhumeoACMfkCFALNVhpch2nXZv7X5445yRgfD\n\t\t\t\tONY4WknecuA0rfCLTruNWnQ3RR+BXmd9jD/5igd9hEIawz3V+jCHvAtzI8/CZIBt\n\t\t\t\tAArBs5kp+QKBgQCdxwN1n6baIDemK10iJWtFoPO6h4fH8h8EeMwPb/ZmlLVpnA4Q\n\t\t\t\tZd+mlkDkoJ5eiRKKaPfWuOqRZeuvj/wTq7g/NOIO+bWQ+rrSvuqLh5IrHpgPXmub\n\t\t\t\t8bsHJhUlspMH4KagN6ROgOAG3fGj6Qp7KdpxRCpR3KJ66czxvGNrhxre6QKBgB+s\n\t\t\t\tMCGiYnfSprd5G8VhyziazKwfYeJerfT+DQhopDXYVKPJnQW8cQW5C8wDNkzx6sHI\n\t\t\t\tpqtK1K/MnKhcVaHJmAcT7qoNQlA4Xqu4qrgPIQNBvU/dDRNJVthG6c5aspEzrG8m\n\t\t\t\t9IHgtRV9K8EOy/1O6YqrB9kNUVWf3JccdWpvqyNJAoGAORzJiQCOk4egbdcozDTo\n\t\t\t\t4Tg4qk/03qpTy5k64DxkX1nJHu8V/hsKwq9Af7Fj/iHy2Av54BLPlBaGPwMi2bzB\n\t\t\t\tgYjmUomvx/fqOTQks9Rc4PIMB43p6Rdj0sh+52SKPDR2eHbwsmpuQUXnAs20BPPI\n\t\t\t\tJ/OOn5zOs8yf26os0q3+JUM=\n\t\t\t\t-----END PRIVATE KEY-----\"\"\";\n\t\tString privateKey = signingKey.replace(\"-----BEGIN PRIVATE KEY-----\\n\", \"\");\n\t\tprivateKey = privateKey.replace(\"-----END PRIVATE KEY-----\", \"\");\n\t\tprivateKey = privateKey.replace(\"\\n\", \"\");\n\t\tbyte[] pkcs8EncodedBytes = Base64.getDecoder().decode(privateKey);\n\t\tPKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);\n\t\tKeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n\t\treturn keyFactory.generatePrivate(keySpec);\n\t}\n\n\tprivate byte[] dotConcat(byte[]... bytes) throws IOException {\n\t\tByteArrayOutputStream result = new ByteArrayOutputStream();\n\t\tfor (int i = 0; i < bytes.length; i++) {\n\t\t\tif (i > 0) {\n\t\t\t\tStreamUtils.copy(DOT, result);\n\t\t\t}\n\t\t\tStreamUtils.copy(bytes[i], result);\n\t\t}\n\t\treturn result.toByteArray();\n\t}\n\n\tprivate Consumer<CloudFoundryAuthorizationException> reasonRequirement(Reason reason) {\n\t\treturn (ex) -> assertThat(ex.getReason()).isEqualTo(reason);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Couchbase\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"com.couchbase.client:java-client\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"org.testcontainers:testcontainers-couchbase\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/dockerTest/java/org/springframework/boot/couchbase/autoconfigure/CouchbaseAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport java.time.Duration;\n\nimport com.couchbase.client.core.diagnostics.ClusterState;\nimport com.couchbase.client.core.diagnostics.DiagnosticsResult;\nimport com.couchbase.client.java.Bucket;\nimport com.couchbase.client.java.Cluster;\nimport com.couchbase.client.java.Collection;\nimport com.couchbase.client.java.env.ClusterEnvironment;\nimport com.couchbase.client.java.json.JsonObject;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.couchbase.CouchbaseService;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CouchbaseAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Brian Clozel\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass CouchbaseAutoConfigurationIntegrationTests {\n\n\tprivate static final String BUCKET_NAME = \"cbbucket\";\n\n\t@Container\n\tstatic final CouchbaseContainer couchbase = TestImage.container(CouchbaseContainer.class)\n\t\t.withEnabledServices(CouchbaseService.KV)\n\t\t.withCredentials(\"spring\", \"password\")\n\t\t.withBucket(new BucketDefinition(BUCKET_NAME).withPrimaryIndex(false));\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.couchbase.connection-string: \" + couchbase.getConnectionString(),\n\t\t\t\t\"spring.couchbase.username:spring\", \"spring.couchbase.password:password\",\n\t\t\t\t\"spring.couchbase.bucket.name:\" + BUCKET_NAME, \"spring.couchbase.env.timeouts.connect=2m\",\n\t\t\t\t\"spring.couchbase.env.timeouts.key-value=1m\");\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Cluster.class).hasSingleBean(ClusterEnvironment.class);\n\t\t\tCluster cluster = context.getBean(Cluster.class);\n\t\t\tBucket bucket = cluster.bucket(BUCKET_NAME);\n\t\t\tbucket.waitUntilReady(Duration.ofMinutes(5));\n\t\t\tDiagnosticsResult diagnostics = cluster.diagnostics();\n\t\t\tassertThat(diagnostics.state()).isEqualTo(ClusterState.ONLINE);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenCouchbaseIsUsingCustomObjectMapperThenJsonCanBeRoundTripped() {\n\t\tthis.contextRunner.withBean(ObjectMapper.class, ObjectMapper::new).run((context) -> {\n\t\t\tCluster cluster = context.getBean(Cluster.class);\n\t\t\tBucket bucket = cluster.bucket(BUCKET_NAME);\n\t\t\tbucket.waitUntilReady(Duration.ofMinutes(5));\n\t\t\tCollection collection = bucket.defaultCollection();\n\t\t\tcollection.insert(\"test-document\", JsonObject.create().put(\"a\", \"alpha\"));\n\t\t\tassertThat(collection.get(\"test-document\").contentAsObject().get(\"a\")).isEqualTo(\"alpha\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/dockerTest/java/org/springframework/boot/couchbase/testcontainers/CouchbaseContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.testcontainers;\n\nimport com.couchbase.client.java.Cluster;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.couchbase.CouchbaseService;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CouchbaseContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass CouchbaseContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CouchbaseContainer couchbase = TestImage.container(CouchbaseContainer.class)\n\t\t.withEnabledServices(CouchbaseService.KV, CouchbaseService.INDEX, CouchbaseService.QUERY)\n\t\t.withBucket(new BucketDefinition(\"cbbucket\"));\n\n\t@Autowired(required = false)\n\tprivate CouchbaseConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate Cluster cluster;\n\n\t@Test\n\tvoid connectionCanBeMadeToCouchbaseContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tassertThat(this.cluster.diagnostics().endpoints()).hasSize(1);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(CouchbaseAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/ClusterEnvironmentBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport com.couchbase.client.java.env.ClusterEnvironment;\nimport com.couchbase.client.java.env.ClusterEnvironment.Builder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Builder ClusterEnvironment.Builder} to fine-tune its auto-configuration before\n * it creates the {@link ClusterEnvironment}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ClusterEnvironmentBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link Builder ClusterEnvironment.Builder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(ClusterEnvironment.Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/CouchbaseAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\nimport javax.net.ssl.TrustManagerFactory;\n\nimport com.couchbase.client.core.env.Authenticator;\nimport com.couchbase.client.core.env.CertificateAuthenticator;\nimport com.couchbase.client.core.env.PasswordAuthenticator;\nimport com.couchbase.client.java.Cluster;\nimport com.couchbase.client.java.ClusterOptions;\nimport com.couchbase.client.java.codec.JacksonJsonSerializer;\nimport com.couchbase.client.java.env.ClusterEnvironment;\nimport com.couchbase.client.java.env.ClusterEnvironment.Builder;\nimport com.couchbase.client.java.json.JsonValueModule;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration.CouchbaseCondition;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties.Authentication.Jks;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties.Authentication.Pem;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties.Ssl;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties.Timeouts;\nimport org.springframework.boot.io.ApplicationResourceLoader;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.pem.PemSslStore;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Couchbase.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Yulin Qin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = \"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\")\n@ConditionalOnClass(Cluster.class)\n@Conditional(CouchbaseCondition.class)\n@EnableConfigurationProperties(CouchbaseProperties.class)\npublic final class CouchbaseAutoConfiguration {\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tprivate final CouchbaseProperties properties;\n\n\tCouchbaseAutoConfiguration(ResourceLoader resourceLoader, CouchbaseProperties properties) {\n\t\tthis.resourceLoader = ApplicationResourceLoader.get(resourceLoader);\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(CouchbaseConnectionDetails.class)\n\tPropertiesCouchbaseConnectionDetails couchbaseConnectionDetails(ObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesCouchbaseConnectionDetails(this.properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tClusterEnvironment couchbaseClusterEnvironment(ObjectProvider<ClusterEnvironmentBuilderCustomizer> customizers,\n\t\t\tCouchbaseConnectionDetails connectionDetails) {\n\t\tBuilder builder = initializeEnvironmentBuilder(connectionDetails);\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAuthenticator couchbaseAuthenticator(CouchbaseConnectionDetails connectionDetails) throws IOException {\n\t\tif (connectionDetails.getUsername() != null && connectionDetails.getPassword() != null) {\n\t\t\treturn PasswordAuthenticator.create(connectionDetails.getUsername(), connectionDetails.getPassword());\n\t\t}\n\t\tPem pem = this.properties.getAuthentication().getPem();\n\t\tif (pem.getCertificates() != null) {\n\t\t\tPemSslStoreDetails details = new PemSslStoreDetails(null, pem.getCertificates(), pem.getPrivateKey());\n\t\t\tPemSslStore store = PemSslStore.load(details);\n\t\t\tAssert.state(store != null, \"Unable to load key and certificates\");\n\t\t\tPrivateKey key = store.privateKey();\n\t\t\tList<X509Certificate> certificates = store.certificates();\n\t\t\tAssert.state(key != null, \"No key found\");\n\t\t\tAssert.state(certificates != null, \"No certificates found\");\n\t\t\treturn CertificateAuthenticator.fromKey(key, pem.getPrivateKeyPassword(), certificates);\n\t\t}\n\t\tJks jks = this.properties.getAuthentication().getJks();\n\t\tif (jks.getLocation() != null) {\n\t\t\tResource resource = this.resourceLoader.getResource(jks.getLocation());\n\t\t\tString keystorePassword = jks.getPassword();\n\t\t\ttry (InputStream inputStream = resource.getInputStream()) {\n\t\t\t\tKeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\t\t\tstore.load(inputStream, (keystorePassword != null) ? keystorePassword.toCharArray() : null);\n\t\t\t\treturn CertificateAuthenticator.fromKeyStore(store, keystorePassword);\n\t\t\t}\n\t\t\tcatch (GeneralSecurityException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Error reading Couchbase certificate store\", ex);\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Couchbase authentication requires username and password, or certificates\");\n\t}\n\n\t@Bean(destroyMethod = \"disconnect\")\n\t@ConditionalOnMissingBean\n\tCluster couchbaseCluster(ClusterEnvironment couchbaseClusterEnvironment, Authenticator authenticator,\n\t\t\tCouchbaseConnectionDetails connectionDetails) {\n\t\tClusterOptions options = ClusterOptions.clusterOptions(authenticator).environment(couchbaseClusterEnvironment);\n\t\treturn Cluster.connect(connectionDetails.getConnectionString(), options);\n\t}\n\n\tprivate ClusterEnvironment.Builder initializeEnvironmentBuilder(CouchbaseConnectionDetails connectionDetails) {\n\t\tClusterEnvironment.Builder builder = ClusterEnvironment.builder();\n\t\tTimeouts timeouts = this.properties.getEnv().getTimeouts();\n\t\tbuilder.timeoutConfig((config) -> config.kvTimeout(timeouts.getKeyValue())\n\t\t\t.analyticsTimeout(timeouts.getAnalytics())\n\t\t\t.kvDurableTimeout(timeouts.getKeyValueDurable())\n\t\t\t.queryTimeout(timeouts.getQuery())\n\t\t\t.viewTimeout(timeouts.getView())\n\t\t\t.searchTimeout(timeouts.getSearch())\n\t\t\t.managementTimeout(timeouts.getManagement())\n\t\t\t.connectTimeout(timeouts.getConnect())\n\t\t\t.disconnectTimeout(timeouts.getDisconnect()));\n\t\tCouchbaseProperties.Io io = this.properties.getEnv().getIo();\n\t\tbuilder.ioConfig((config) -> config.maxHttpConnections(io.getMaxEndpoints())\n\t\t\t.numKvConnections(io.getMinEndpoints())\n\t\t\t.idleHttpConnectionTimeout(io.getIdleHttpConnectionTimeout()));\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tif (sslBundle != null) {\n\t\t\tconfigureSsl(builder, sslBundle);\n\t\t}\n\t\treturn builder;\n\t}\n\n\tprivate void configureSsl(Builder builder, SslBundle sslBundle) {\n\t\tAssert.state(!sslBundle.getOptions().isSpecified(), \"SSL Options cannot be specified with Couchbase\");\n\t\tbuilder.securityConfig((config) -> {\n\t\t\tconfig.enableTls(true);\n\t\t\tTrustManagerFactory trustManagerFactory = sslBundle.getManagers().getTrustManagerFactory();\n\t\t\tif (trustManagerFactory != null) {\n\t\t\t\tconfig.trustManagerFactory(trustManagerFactory);\n\t\t\t}\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ObjectMapper.class)\n\tstatic class JacksonConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(ObjectMapper.class)\n\t\tClusterEnvironmentBuilderCustomizer jacksonClusterEnvironmentBuilderCustomizer(ObjectMapper objectMapper) {\n\t\t\treturn new JacksonClusterEnvironmentBuilderCustomizer(\n\t\t\t\t\tobjectMapper.copy().registerModule(new JsonValueModule()));\n\t\t}\n\n\t}\n\n\tprivate static final class JacksonClusterEnvironmentBuilderCustomizer\n\t\t\timplements ClusterEnvironmentBuilderCustomizer, Ordered {\n\n\t\tprivate final ObjectMapper objectMapper;\n\n\t\tprivate JacksonClusterEnvironmentBuilderCustomizer(ObjectMapper objectMapper) {\n\t\t\tthis.objectMapper = objectMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(Builder builder) {\n\t\t\tbuilder.jsonSerializer(JacksonJsonSerializer.create(this.objectMapper));\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t}\n\n\t/**\n\t * Condition that matches when {@code spring.couchbase.connection-string} has been\n\t * configured or there is a {@link CouchbaseConnectionDetails} bean.\n\t */\n\tstatic final class CouchbaseCondition extends AnyNestedCondition {\n\n\t\tCouchbaseCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.couchbase.connection-string\")\n\t\tprivate static final class CouchbaseUrlCondition {\n\n\t\t}\n\n\t\t@ConditionalOnBean(CouchbaseConnectionDetails.class)\n\t\tprivate static final class CouchbaseConnectionDetailsCondition {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link CouchbaseProperties} to {@link CouchbaseConnectionDetails}.\n\t */\n\tstatic final class PropertiesCouchbaseConnectionDetails implements CouchbaseConnectionDetails {\n\n\t\tprivate final CouchbaseProperties properties;\n\n\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\tPropertiesCouchbaseConnectionDetails(CouchbaseProperties properties, @Nullable SslBundles sslBundles) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.sslBundles = sslBundles;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getConnectionString() {\n\t\t\tString connectionString = this.properties.getConnectionString();\n\t\t\tAssert.state(connectionString != null, \"'connectionString' must not be null\");\n\t\t\treturn connectionString;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.properties.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\tSsl ssl = this.properties.getEnv().getSsl();\n\t\t\tif (!ssl.getEnabled()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t\t}\n\t\t\treturn SslBundle.systemDefault();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/CouchbaseConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to a Couchbase service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface CouchbaseConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Connection string used to locate the Couchbase cluster.\n\t * @return the connection string used to locate the Couchbase cluster\n\t */\n\tString getConnectionString();\n\n\t/**\n\t * Cluster username.\n\t * @return the cluster username\n\t */\n\t@Nullable String getUsername();\n\n\t/**\n\t * Cluster password.\n\t * @return the cluster password\n\t */\n\t@Nullable String getPassword();\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/CouchbaseProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration properties for Couchbase.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Yulin Qin\n * @author Brian Clozel\n * @author Michael Nitschinger\n * @author Scott Frederick\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.couchbase\")\npublic class CouchbaseProperties {\n\n\t/**\n\t * Connection string used to locate the Couchbase cluster.\n\t */\n\tprivate @Nullable String connectionString;\n\n\t/**\n\t * Cluster username.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Cluster password.\n\t */\n\tprivate @Nullable String password;\n\n\tprivate final Authentication authentication = new Authentication();\n\n\tprivate final Env env = new Env();\n\n\tpublic @Nullable String getConnectionString() {\n\t\treturn this.connectionString;\n\t}\n\n\tpublic void setConnectionString(@Nullable String connectionString) {\n\t\tthis.connectionString = connectionString;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Authentication getAuthentication() {\n\t\treturn this.authentication;\n\t}\n\n\tpublic Env getEnv() {\n\t\treturn this.env;\n\t}\n\n\tpublic static class Authentication {\n\n\t\tprivate final Pem pem = new Pem();\n\n\t\tprivate final Jks jks = new Jks();\n\n\t\tpublic Pem getPem() {\n\t\t\treturn this.pem;\n\t\t}\n\n\t\tpublic Jks getJks() {\n\t\t\treturn this.jks;\n\t\t}\n\n\t\tpublic static class Pem {\n\n\t\t\t/**\n\t\t\t * PEM-formatted certificates for certificate-based cluster authentication.\n\t\t\t */\n\t\t\tprivate @Nullable String certificates;\n\n\t\t\t/**\n\t\t\t * PEM-formatted private key for certificate-based cluster authentication.\n\t\t\t */\n\t\t\tprivate @Nullable String privateKey;\n\n\t\t\t/**\n\t\t\t * Private key password for certificate-based cluster authentication.\n\t\t\t */\n\t\t\tprivate @Nullable String privateKeyPassword;\n\n\t\t\tpublic @Nullable String getCertificates() {\n\t\t\t\treturn this.certificates;\n\t\t\t}\n\n\t\t\tpublic void setCertificates(@Nullable String certificates) {\n\t\t\t\tthis.certificates = certificates;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getPrivateKey() {\n\t\t\t\treturn this.privateKey;\n\t\t\t}\n\n\t\t\tpublic void setPrivateKey(@Nullable String privateKey) {\n\t\t\t\tthis.privateKey = privateKey;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getPrivateKeyPassword() {\n\t\t\t\treturn this.privateKeyPassword;\n\t\t\t}\n\n\t\t\tpublic void setPrivateKeyPassword(@Nullable String privateKeyPassword) {\n\t\t\t\tthis.privateKeyPassword = privateKeyPassword;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Jks {\n\n\t\t\t/**\n\t\t\t * Java KeyStore location for certificate-based cluster authentication.\n\t\t\t */\n\t\t\tprivate @Nullable String location;\n\n\t\t\t/**\n\t\t\t * Java KeyStore password for certificate-based cluster authentication.\n\t\t\t */\n\t\t\tprivate @Nullable String password;\n\n\t\t\tpublic @Nullable String getLocation() {\n\t\t\t\treturn this.location;\n\t\t\t}\n\n\t\t\tpublic void setLocation(@Nullable String location) {\n\t\t\t\tthis.location = location;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getPassword() {\n\t\t\t\treturn this.password;\n\t\t\t}\n\n\t\t\tpublic void setPassword(@Nullable String password) {\n\t\t\t\tthis.password = password;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Env {\n\n\t\tprivate final Io io = new Io();\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tprivate final Timeouts timeouts = new Timeouts();\n\n\t\tpublic Io getIo() {\n\t\t\treturn this.io;\n\t\t}\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic Timeouts getTimeouts() {\n\t\t\treturn this.timeouts;\n\t\t}\n\n\t}\n\n\tpublic static class Io {\n\n\t\t/**\n\t\t * Minimum number of sockets per node.\n\t\t */\n\t\tprivate int minEndpoints = 1;\n\n\t\t/**\n\t\t * Maximum number of sockets per node.\n\t\t */\n\t\tprivate int maxEndpoints = 12;\n\n\t\t/**\n\t\t * Length of time an HTTP connection may remain idle before it is closed and\n\t\t * removed from the pool.\n\t\t */\n\t\tprivate Duration idleHttpConnectionTimeout = Duration.ofSeconds(1);\n\n\t\tpublic int getMinEndpoints() {\n\t\t\treturn this.minEndpoints;\n\t\t}\n\n\t\tpublic void setMinEndpoints(int minEndpoints) {\n\t\t\tthis.minEndpoints = minEndpoints;\n\t\t}\n\n\t\tpublic int getMaxEndpoints() {\n\t\t\treturn this.maxEndpoints;\n\t\t}\n\n\t\tpublic void setMaxEndpoints(int maxEndpoints) {\n\t\t\tthis.maxEndpoints = maxEndpoints;\n\t\t}\n\n\t\tpublic Duration getIdleHttpConnectionTimeout() {\n\t\t\treturn this.idleHttpConnectionTimeout;\n\t\t}\n\n\t\tpublic void setIdleHttpConnectionTimeout(Duration idleHttpConnectionTimeout) {\n\t\t\tthis.idleHttpConnectionTimeout = idleHttpConnectionTimeout;\n\t\t}\n\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support. Enabled automatically if a \"bundle\" is provided\n\t\t * unless specified otherwise.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic Boolean getEnabled() {\n\t\t\treturn (this.enabled != null) ? this.enabled : StringUtils.hasText(this.bundle);\n\t\t}\n\n\t\tpublic void setEnabled(Boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\tpublic static class Timeouts {\n\n\t\t/**\n\t\t * Bucket connect timeout.\n\t\t */\n\t\tprivate Duration connect = Duration.ofSeconds(10);\n\n\t\t/**\n\t\t * Bucket disconnect timeout.\n\t\t */\n\t\tprivate Duration disconnect = Duration.ofSeconds(10);\n\n\t\t/**\n\t\t * Timeout for operations on a specific key-value.\n\t\t */\n\t\tprivate Duration keyValue = Duration.ofMillis(2500);\n\n\t\t/**\n\t\t * Timeout for operations on a specific key-value with a durability level.\n\t\t */\n\t\tprivate Duration keyValueDurable = Duration.ofSeconds(10);\n\n\t\t/**\n\t\t * N1QL query operations timeout.\n\t\t */\n\t\tprivate Duration query = Duration.ofSeconds(75);\n\n\t\t/**\n\t\t * Regular and geospatial view operations timeout.\n\t\t */\n\t\tprivate Duration view = Duration.ofSeconds(75);\n\n\t\t/**\n\t\t * Timeout for the search service.\n\t\t */\n\t\tprivate Duration search = Duration.ofSeconds(75);\n\n\t\t/**\n\t\t * Timeout for the analytics service.\n\t\t */\n\t\tprivate Duration analytics = Duration.ofSeconds(75);\n\n\t\t/**\n\t\t * Timeout for the management operations.\n\t\t */\n\t\tprivate Duration management = Duration.ofSeconds(75);\n\n\t\tpublic Duration getConnect() {\n\t\t\treturn this.connect;\n\t\t}\n\n\t\tpublic void setConnect(Duration connect) {\n\t\t\tthis.connect = connect;\n\t\t}\n\n\t\tpublic Duration getDisconnect() {\n\t\t\treturn this.disconnect;\n\t\t}\n\n\t\tpublic void setDisconnect(Duration disconnect) {\n\t\t\tthis.disconnect = disconnect;\n\t\t}\n\n\t\tpublic Duration getKeyValue() {\n\t\t\treturn this.keyValue;\n\t\t}\n\n\t\tpublic void setKeyValue(Duration keyValue) {\n\t\t\tthis.keyValue = keyValue;\n\t\t}\n\n\t\tpublic Duration getKeyValueDurable() {\n\t\t\treturn this.keyValueDurable;\n\t\t}\n\n\t\tpublic void setKeyValueDurable(Duration keyValueDurable) {\n\t\t\tthis.keyValueDurable = keyValueDurable;\n\t\t}\n\n\t\tpublic Duration getQuery() {\n\t\t\treturn this.query;\n\t\t}\n\n\t\tpublic void setQuery(Duration query) {\n\t\t\tthis.query = query;\n\t\t}\n\n\t\tpublic Duration getView() {\n\t\t\treturn this.view;\n\t\t}\n\n\t\tpublic void setView(Duration view) {\n\t\t\tthis.view = view;\n\t\t}\n\n\t\tpublic Duration getSearch() {\n\t\t\treturn this.search;\n\t\t}\n\n\t\tpublic void setSearch(Duration search) {\n\t\t\tthis.search = search;\n\t\t}\n\n\t\tpublic Duration getAnalytics() {\n\t\t\treturn this.analytics;\n\t\t}\n\n\t\tpublic void setAnalytics(Duration analytics) {\n\t\t\tthis.analytics = analytics;\n\t\t}\n\n\t\tpublic Duration getManagement() {\n\t\t\treturn this.management;\n\t\t}\n\n\t\tpublic void setManagement(Duration management) {\n\t\t\tthis.management = management;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/health/CouchbaseHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure.health;\n\nimport com.couchbase.client.java.Cluster;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.couchbase.health.CouchbaseHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link CouchbaseHealthIndicator}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Andy Wilkinson Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafter = { CouchbaseAutoConfiguration.class, CouchbaseReactiveHealthContributorAutoConfiguration.class })\n@ConditionalOnClass({ Cluster.class, CouchbaseHealthIndicator.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(Cluster.class)\n@ConditionalOnEnabledHealthIndicator(\"couchbase\")\npublic final class CouchbaseHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<CouchbaseHealthIndicator, Cluster> {\n\n\tCouchbaseHealthContributorAutoConfiguration() {\n\t\tsuper(CouchbaseHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"couchbaseHealthIndicator\", \"couchbaseHealthContributor\" })\n\tHealthContributor couchbaseHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, Cluster.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/health/CouchbaseReactiveHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure.health;\n\nimport com.couchbase.client.java.Cluster;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.couchbase.health.CouchbaseReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link CouchbaseReactiveHealthIndicator}.\n *\n * @author Mikalai Lushchytski\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = CouchbaseAutoConfiguration.class)\n@ConditionalOnClass({ Cluster.class, Flux.class, CouchbaseReactiveHealthIndicator.class,\n\t\tConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(Cluster.class)\n@ConditionalOnEnabledHealthIndicator(\"couchbase\")\npublic final class CouchbaseReactiveHealthContributorAutoConfiguration\n\t\textends CompositeReactiveHealthContributorConfiguration<CouchbaseReactiveHealthIndicator, Cluster> {\n\n\tCouchbaseReactiveHealthContributorAutoConfiguration() {\n\t\tsuper(CouchbaseReactiveHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"couchbaseHealthIndicator\", \"couchbaseHealthContributor\" })\n\tReactiveHealthContributor couchbaseHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, Cluster.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Couchbase health.\n */\n@NullMarked\npackage org.springframework.boot.couchbase.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Couchbase.\n */\n@NullMarked\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/health/CouchbaseHealth.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.health;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.couchbase.client.core.diagnostics.ClusterState;\nimport com.couchbase.client.core.diagnostics.DiagnosticsResult;\nimport com.couchbase.client.core.diagnostics.EndpointDiagnostics;\n\nimport org.springframework.boot.health.contributor.Health;\n\n/**\n * Details of Couchbase's health.\n *\n * @author Andy Wilkinson\n */\nclass CouchbaseHealth {\n\n\tprivate final DiagnosticsResult diagnostics;\n\n\tCouchbaseHealth(DiagnosticsResult diagnostics) {\n\t\tthis.diagnostics = diagnostics;\n\t}\n\n\tvoid applyTo(Health.Builder builder) {\n\t\tbuilder = isCouchbaseUp(this.diagnostics) ? builder.up() : builder.down();\n\t\tbuilder.withDetail(\"sdk\", this.diagnostics.sdk());\n\t\tbuilder.withDetail(\"endpoints\",\n\t\t\t\tthis.diagnostics.endpoints()\n\t\t\t\t\t.values()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.flatMap(Collection::stream)\n\t\t\t\t\t.map(this::describe)\n\t\t\t\t\t.toList());\n\t}\n\n\tprivate boolean isCouchbaseUp(DiagnosticsResult diagnostics) {\n\t\treturn diagnostics.state() == ClusterState.ONLINE;\n\t}\n\n\tprivate Map<String, Object> describe(EndpointDiagnostics endpointHealth) {\n\t\tMap<String, Object> map = new HashMap<>();\n\t\tmap.put(\"id\", endpointHealth.id());\n\t\tmap.put(\"lastActivity\", endpointHealth.lastActivity());\n\t\tmap.put(\"local\", endpointHealth.local());\n\t\tmap.put(\"remote\", endpointHealth.remote());\n\t\tmap.put(\"state\", endpointHealth.state());\n\t\tmap.put(\"type\", endpointHealth.type());\n\t\treturn map;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/health/CouchbaseHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.health;\n\nimport com.couchbase.client.core.diagnostics.DiagnosticsResult;\nimport com.couchbase.client.java.Cluster;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthIndicator} for Couchbase.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class CouchbaseHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final Cluster cluster;\n\n\t/**\n\t * Create an indicator with the specified {@link Cluster}.\n\t * @param cluster the Couchbase Cluster\n\t */\n\tpublic CouchbaseHealthIndicator(Cluster cluster) {\n\t\tsuper(\"Couchbase health check failed\");\n\t\tAssert.notNull(cluster, \"'cluster' must not be null\");\n\t\tthis.cluster = cluster;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tDiagnosticsResult diagnostics = this.cluster.diagnostics();\n\t\tnew CouchbaseHealth(diagnostics).applyTo(builder);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/health/CouchbaseReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.health;\n\nimport com.couchbase.client.java.Cluster;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\n\n/**\n * A {@link ReactiveHealthIndicator} for Couchbase.\n *\n * @author Mikalai Lushchytski\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class CouchbaseReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate final Cluster cluster;\n\n\t/**\n\t * Create a new {@link CouchbaseReactiveHealthIndicator} instance.\n\t * @param cluster the Couchbase cluster\n\t */\n\tpublic CouchbaseReactiveHealthIndicator(Cluster cluster) {\n\t\tsuper(\"Couchbase health check failed\");\n\t\tthis.cluster = cluster;\n\t}\n\n\t@Override\n\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\treturn this.cluster.reactive().diagnostics().map((diagnostics) -> {\n\t\t\tnew CouchbaseHealth(diagnostics).applyTo(builder);\n\t\t\treturn builder.build();\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for Couchbase.\n */\n@NullMarked\npackage org.springframework.boot.couchbase.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/testcontainers/CouchbaseContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.testcontainers;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.couchbase.CouchbaseContainer;\n\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link CouchbaseConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link CouchbaseContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass CouchbaseContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<CouchbaseContainer, CouchbaseConnectionDetails> {\n\n\t@Override\n\tprotected CouchbaseConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<CouchbaseContainer> source) {\n\t\treturn new CouchbaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link CouchbaseConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class CouchbaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<CouchbaseContainer> implements CouchbaseConnectionDetails {\n\n\t\tprivate CouchbaseContainerConnectionDetails(ContainerConnectionSource<CouchbaseContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getConnectionString() {\n\t\t\treturn getContainer().getConnectionString();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/java/org/springframework/boot/couchbase/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Couchbase service connections.\n */\n@NullMarked\npackage org.springframework.boot.couchbase.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.couchbase.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Couchbase health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.health.couchbase.timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Timeout for getting the Bucket information from the server.\",\n      \"defaultValue\": \"1000ms\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.0.6\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.bootstrap-hosts\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"description\": \"Couchbase nodes (host or IP address) to bootstrap from.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.connection-string\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.bucket.name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Name of the bucket to connect to.\",\n      \"deprecation\": {\n        \"reason\": \"A bucket is no longer auto-configured.\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.bucket.password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Password of the bucket.\",\n      \"deprecation\": {\n        \"reason\": \"A bucket is no longer auto-configured.\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.bootstrap.http-direct-port\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Port for the HTTP bootstrap.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.bootstrap.http-ssl-port\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Port for the HTTPS bootstrap.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.key-value\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Number of sockets per node against the key/value service.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.query\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Number of sockets per node against the query (N1QL) service.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.queryservice.max-endpoints\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of sockets per node.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.env.io.max-endpoints\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.queryservice.min-endpoints\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Minimum number of sockets per node.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.env.io.min-endpoints\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.view\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Number of sockets per node against the view service.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.viewservice.max-endpoints\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum number of sockets per node.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.env.io.max-endpoints\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.endpoints.viewservice.min-endpoints\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Minimum number of sockets per node.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.env.io.min-endpoints\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.ssl.key-store\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Path to the JVM key store that holds the certificates.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.env.ssl.bundle\",\n        \"level\": \"error\",\n        \"since\": \"3.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.ssl.key-store-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Password used to access the key store.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.couchbase.env.ssl.bundle\",\n        \"level\": \"error\",\n        \"since\": \"3.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.couchbase.env.timeouts.socket-connect\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Socket connect connections timeout.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration\norg.springframework.boot.couchbase.autoconfigure.health.CouchbaseHealthContributorAutoConfiguration\norg.springframework.boot.couchbase.autoconfigure.health.CouchbaseReactiveHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.couchbase.testcontainers.CouchbaseContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/autoconfigure/CouchbaseAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport com.couchbase.client.core.env.Authenticator;\nimport com.couchbase.client.core.env.CertificateAuthenticator;\nimport com.couchbase.client.core.env.IoConfig;\nimport com.couchbase.client.core.env.PasswordAuthenticator;\nimport com.couchbase.client.core.env.SecurityConfig;\nimport com.couchbase.client.core.env.TimeoutConfig;\nimport com.couchbase.client.java.Cluster;\nimport com.couchbase.client.java.codec.JacksonJsonSerializer;\nimport com.couchbase.client.java.codec.JsonSerializer;\nimport com.couchbase.client.java.env.ClusterEnvironment;\nimport com.couchbase.client.java.json.JsonValueModule;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration.PropertiesCouchbaseConnectionDetails;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.as;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CouchbaseAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass CouchbaseAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid connectionStringIsRequired() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClusterEnvironment.class)\n\t\t\t.doesNotHaveBean(Authenticator.class)\n\t\t\t.doesNotHaveBean(Cluster.class));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesCouchbaseConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(CouchbaseConnectionDetails.class, this::couchbaseConnectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ClusterEnvironment.class)\n\t\t\t\t\t.hasSingleBean(Cluster.class)\n\t\t\t\t\t.hasSingleBean(PasswordAuthenticator.class)\n\t\t\t\t\t.hasSingleBean(CouchbaseConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesCouchbaseConnectionDetails.class);\n\t\t\t\tCluster cluster = context.getBean(Cluster.class);\n\t\t\t\tassertThat(cluster.core()).extracting(\"connectionString.hosts\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.extractingResultOf(\"host\")\n\t\t\t\t\t.containsExactly(\"couchbase.example.com\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionStringCreateEnvironmentAndCluster() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ClusterEnvironment.class)\n\t\t\t\t\t.hasSingleBean(Authenticator.class)\n\t\t\t\t\t.hasSingleBean(Cluster.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(\"couchbaseAuthenticator\");\n\t\t\t\tassertThat(context.getBean(Cluster.class))\n\t\t\t\t\t.isSameAs(context.getBean(CouchbaseTestConfiguration.class).couchbaseCluster());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsOverridesProperties() {\n\t\tthis.contextRunner.withBean(CouchbaseConnectionDetails.class, this::couchbaseConnectionDetails)\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\", \"spring.couchbase.username=a-user\",\n\t\t\t\t\t\"spring.couchbase.password=a-password\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ClusterEnvironment.class)\n\t\t\t\t\t.hasSingleBean(PasswordAuthenticator.class)\n\t\t\t\t\t.hasSingleBean(Cluster.class);\n\t\t\t\tCluster cluster = context.getBean(Cluster.class);\n\t\t\t\tassertThat(cluster.core()).extracting(\"connectionString.hosts\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.extractingResultOf(\"host\")\n\t\t\t\t\t.containsExactly(\"couchbase.example.com\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenObjectMapperBeanIsDefinedThenClusterEnvironmentObjectMapperIsDerivedFromIt() {\n\t\tObjectMapper objectMapper = new ObjectMapper();\n\t\tobjectMapper.registerModule(new SimpleModule(\"custom\"));\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)\n\t\t\t.withBean(ObjectMapper.class, () -> objectMapper)\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\")\n\t\t\t.run((context) -> {\n\t\t\t\tClusterEnvironment env = context.getBean(ClusterEnvironment.class);\n\t\t\t\tSet<Object> expectedModuleIds = Set.of(\"custom\", new JsonValueModule().getTypeId());\n\t\t\t\tJsonSerializer serializer = env.jsonSerializer();\n\t\t\t\tassertThat(serializer).extracting(\"wrapped\")\n\t\t\t\t\t.isInstanceOf(JacksonJsonSerializer.class)\n\t\t\t\t\t.extracting(\"mapper\", as(InstanceOfAssertFactories.type(ObjectMapper.class)))\n\t\t\t\t\t.extracting(ObjectMapper::getRegisteredModuleIds)\n\t\t\t\t\t.isEqualTo(expectedModuleIds);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizeJsonSerializer() {\n\t\tJsonSerializer customJsonSerializer = mock(JsonSerializer.class);\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))\n\t\t\t.withBean(ClusterEnvironmentBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.jsonSerializer(customJsonSerializer))\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\")\n\t\t\t.run((context) -> {\n\t\t\t\tClusterEnvironment env = context.getBean(ClusterEnvironment.class);\n\t\t\t\tJsonSerializer serializer = env.jsonSerializer();\n\t\t\t\tassertThat(serializer).extracting(\"wrapped\").isSameAs(customJsonSerializer);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizeEnvIo() {\n\t\ttestClusterEnvironment((env) -> {\n\t\t\tIoConfig ioConfig = env.ioConfig();\n\t\t\tassertThat(ioConfig.numKvConnections()).isEqualTo(2);\n\t\t\tassertThat(ioConfig.maxHttpConnections()).isEqualTo(5);\n\t\t\tassertThat(ioConfig.idleHttpConnectionTimeout()).isEqualTo(Duration.ofSeconds(3));\n\t\t}, \"spring.couchbase.env.io.min-endpoints=2\", \"spring.couchbase.env.io.max-endpoints=5\",\n\t\t\t\t\"spring.couchbase.env.io.idle-http-connection-timeout=3s\");\n\t}\n\n\t@Test\n\tvoid customizeEnvTimeouts() {\n\t\ttestClusterEnvironment((env) -> {\n\t\t\tTimeoutConfig timeoutConfig = env.timeoutConfig();\n\t\t\tassertThat(timeoutConfig.connectTimeout()).isEqualTo(Duration.ofSeconds(1));\n\t\t\tassertThat(timeoutConfig.disconnectTimeout()).isEqualTo(Duration.ofSeconds(2));\n\t\t\tassertThat(timeoutConfig.kvTimeout()).isEqualTo(Duration.ofMillis(500));\n\t\t\tassertThat(timeoutConfig.kvDurableTimeout()).isEqualTo(Duration.ofMillis(750));\n\t\t\tassertThat(timeoutConfig.queryTimeout()).isEqualTo(Duration.ofSeconds(3));\n\t\t\tassertThat(timeoutConfig.viewTimeout()).isEqualTo(Duration.ofSeconds(4));\n\t\t\tassertThat(timeoutConfig.searchTimeout()).isEqualTo(Duration.ofSeconds(5));\n\t\t\tassertThat(timeoutConfig.analyticsTimeout()).isEqualTo(Duration.ofSeconds(6));\n\t\t\tassertThat(timeoutConfig.managementTimeout()).isEqualTo(Duration.ofSeconds(7));\n\t\t}, \"spring.couchbase.env.timeouts.connect=1s\", \"spring.couchbase.env.timeouts.disconnect=2s\",\n\t\t\t\t\"spring.couchbase.env.timeouts.key-value=500ms\",\n\t\t\t\t\"spring.couchbase.env.timeouts.key-value-durable=750ms\", \"spring.couchbase.env.timeouts.query=3s\",\n\t\t\t\t\"spring.couchbase.env.timeouts.view=4s\", \"spring.couchbase.env.timeouts.search=5s\",\n\t\t\t\t\"spring.couchbase.env.timeouts.analytics=6s\", \"spring.couchbase.env.timeouts.management=7s\");\n\t}\n\n\t@Test\n\tvoid enableSsl() {\n\t\ttestClusterEnvironment((env) -> {\n\t\t\tSecurityConfig securityConfig = env.securityConfig();\n\t\t\tassertThat(securityConfig.tlsEnabled()).isTrue();\n\t\t\tassertThat(securityConfig.trustManagerFactory()).isNotNull();\n\t\t}, \"spring.couchbase.env.ssl.enabled=true\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid enableSslWithBundle() {\n\t\ttestClusterEnvironment((env) -> {\n\t\t\tSecurityConfig securityConfig = env.securityConfig();\n\t\t\tassertThat(securityConfig.tlsEnabled()).isTrue();\n\t\t\tassertThat(securityConfig.trustManagerFactory()).isNotNull();\n\t\t}, \"spring.ssl.bundle.jks.test-bundle.truststore.location=classpath:test.jks\",\n\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.truststore.password=secret\",\n\t\t\t\t\"spring.couchbase.env.ssl.bundle=test-bundle\");\n\t}\n\n\t@Test\n\tvoid enableSslWithInvalidBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\",\n\t\t\t\t\t\"spring.couchbase.env.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).rootCause()\n\t\t\t\t\t.isInstanceOf(NoSuchSslBundleException.class)\n\t\t\t\t\t.hasMessageContaining(\"test-bundle\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid disableSslEvenWithBundle() {\n\t\ttestClusterEnvironment((env) -> {\n\t\t\tSecurityConfig securityConfig = env.securityConfig();\n\t\t\tassertThat(securityConfig.tlsEnabled()).isFalse();\n\t\t\tassertThat(securityConfig.trustManagerFactory()).isNull();\n\t\t}, \"spring.couchbase.env.ssl.enabled=false\", \"spring.couchbase.env.ssl.bundle=test-bundle\");\n\t}\n\n\tprivate void testClusterEnvironment(Consumer<ClusterEnvironment> environmentConsumer, String... environment) {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\")\n\t\t\t.withPropertyValues(environment)\n\t\t\t.run((context) -> environmentConsumer.accept(context.getBean(ClusterEnvironment.class)));\n\t}\n\n\t@Test\n\tvoid customizeEnvWithCustomCouchbaseConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CouchbaseTestConfiguration.class, ClusterEnvironmentCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\",\n\t\t\t\t\t\"spring.couchbase.env.timeouts.connect=100\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ClusterEnvironment.class);\n\t\t\t\tClusterEnvironment env = context.getBean(ClusterEnvironment.class);\n\t\t\t\tassertThat(env.timeoutConfig().kvTimeout()).isEqualTo(Duration.ofSeconds(5));\n\t\t\t\tassertThat(env.timeoutConfig().connectTimeout()).isEqualTo(Duration.ofSeconds(2));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid passwordAuthenticationWithUsernameAndPassword() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\", \"spring.couchbase.username=user\",\n\t\t\t\t\t\"spring.couchbase.password=secret\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PasswordAuthenticator.class));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"key.crt\", \"key.pem\" })\n\tvoid certificateAuthenticationWithPemPrivateKeyAndCertificate() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\", \"spring.couchbase.env.ssl.enabled=true\",\n\t\t\t\t\t\"spring.couchbase.authentication.pem.private-key=classpath:key.pem\",\n\t\t\t\t\t\"spring.couchbase.authentication.pem.certificates=classpath:key.crt\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CertificateAuthenticator.class));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"keystore.jks\")\n\tvoid certificateAuthenticationWithJavaKeyStore() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.couchbase.connection-string=localhost\", \"spring.couchbase.env.ssl.enabled=true\",\n\t\t\t\t\t\"spring.couchbase.authentication.jks.location=classpath:keystore.jks\",\n\t\t\t\t\t\"spring.couchbase.authentication.jks.password=secret\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CertificateAuthenticator.class));\n\t}\n\n\t@Test\n\tvoid failsWithMissingAuthentication() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.couchbase.connection-string=localhost\").run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.hasMessageContaining(\"Couchbase authentication requires username and password, or certificates\");\n\t\t});\n\t}\n\n\tprivate CouchbaseConnectionDetails couchbaseConnectionDetails() {\n\t\treturn new CouchbaseConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic String getConnectionString() {\n\t\t\t\treturn \"couchbase.example.com\";\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getUsername() {\n\t\t\t\treturn \"user-1\";\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getPassword() {\n\t\t\t\treturn \"password-1\";\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClusterEnvironmentCustomizerConfiguration {\n\n\t\t@Bean\n\t\tClusterEnvironmentBuilderCustomizer clusterEnvironmentBuilderCustomizer() {\n\t\t\treturn (builder) -> builder.timeoutConfig()\n\t\t\t\t.kvTimeout(Duration.ofSeconds(5))\n\t\t\t\t.connectTimeout(Duration.ofSeconds(2));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/autoconfigure/CouchbasePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport com.couchbase.client.core.env.IoConfig;\nimport com.couchbase.client.core.env.TimeoutConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties.Io;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties.Timeouts;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CouchbaseProperties}.\n *\n * @author Stephane Nicoll\n */\nclass CouchbasePropertiesTests {\n\n\t@Test\n\tvoid ioHaveConsistentDefaults() {\n\t\tIo io = new CouchbaseProperties().getEnv().getIo();\n\t\tassertThat(io.getMinEndpoints()).isOne();\n\t\tassertThat(io.getMaxEndpoints()).isEqualTo(IoConfig.DEFAULT_MAX_HTTP_CONNECTIONS);\n\t\tassertThat(io.getIdleHttpConnectionTimeout()).isEqualTo(IoConfig.DEFAULT_IDLE_HTTP_CONNECTION_TIMEOUT);\n\t}\n\n\t@Test\n\tvoid timeoutsHaveConsistentDefaults() {\n\t\tTimeouts timeouts = new CouchbaseProperties().getEnv().getTimeouts();\n\t\tassertThat(timeouts.getConnect()).isEqualTo(TimeoutConfig.DEFAULT_CONNECT_TIMEOUT);\n\t\tassertThat(timeouts.getDisconnect()).isEqualTo(TimeoutConfig.DEFAULT_DISCONNECT_TIMEOUT);\n\t\tassertThat(timeouts.getKeyValue()).isEqualTo(TimeoutConfig.DEFAULT_KV_TIMEOUT);\n\t\tassertThat(timeouts.getKeyValueDurable()).isEqualTo(TimeoutConfig.DEFAULT_KV_DURABLE_TIMEOUT);\n\t\tassertThat(timeouts.getQuery()).isEqualTo(TimeoutConfig.DEFAULT_QUERY_TIMEOUT);\n\t\tassertThat(timeouts.getView()).isEqualTo(TimeoutConfig.DEFAULT_VIEW_TIMEOUT);\n\t\tassertThat(timeouts.getSearch()).isEqualTo(TimeoutConfig.DEFAULT_SEARCH_TIMEOUT);\n\t\tassertThat(timeouts.getAnalytics()).isEqualTo(TimeoutConfig.DEFAULT_ANALYTICS_TIMEOUT);\n\t\tassertThat(timeouts.getManagement()).isEqualTo(TimeoutConfig.DEFAULT_MANAGEMENT_TIMEOUT);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/autoconfigure/CouchbaseTestConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure;\n\nimport com.couchbase.client.core.env.Authenticator;\nimport com.couchbase.client.java.Cluster;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test configuration for couchbase that mocks access.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\nclass CouchbaseTestConfiguration {\n\n\tprivate final Cluster cluster = mock(Cluster.class);\n\n\tprivate final Authenticator authenticator = mock(Authenticator.class);\n\n\t@Bean\n\tCluster couchbaseCluster() {\n\t\treturn this.cluster;\n\t}\n\n\t@Bean\n\tAuthenticator couchbaseAuth() {\n\t\treturn this.authenticator;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/autoconfigure/health/CouchbaseHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure.health;\n\nimport com.couchbase.client.java.Cluster;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.couchbase.health.CouchbaseHealthIndicator;\nimport org.springframework.boot.couchbase.health.CouchbaseReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CouchbaseHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass CouchbaseHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(Cluster.class, () -> mock(Cluster.class))\n\t\t.withConfiguration(AutoConfigurations.of(CouchbaseHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(CouchbaseHealthIndicator.class)\n\t\t\t.doesNotHaveBean(CouchbaseReactiveHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.couchbase.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CouchbaseHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/autoconfigure/health/CouchbaseReactiveHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.autoconfigure.health;\n\nimport com.couchbase.client.java.Cluster;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.couchbase.health.CouchbaseHealthIndicator;\nimport org.springframework.boot.couchbase.health.CouchbaseReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CouchbaseReactiveHealthContributorAutoConfiguration}.\n *\n * @author Mikalai Lushchytski\n */\nclass CouchbaseReactiveHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(Cluster.class, () -> mock(Cluster.class))\n\t\t.withConfiguration(AutoConfigurations.of(CouchbaseReactiveHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(CouchbaseReactiveHealthIndicator.class)\n\t\t\t.hasBean(\"couchbaseHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(CouchbaseHealthContributorAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CouchbaseReactiveHealthIndicator.class)\n\t\t\t\t.hasBean(\"couchbaseHealthContributor\")\n\t\t\t\t.doesNotHaveBean(CouchbaseHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.couchbase.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CouchbaseReactiveHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(\"couchbaseHealthContributor\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/health/CouchbaseHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.health;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport com.couchbase.client.core.diagnostics.DiagnosticsResult;\nimport com.couchbase.client.core.diagnostics.EndpointDiagnostics;\nimport com.couchbase.client.core.endpoint.CircuitBreaker;\nimport com.couchbase.client.core.endpoint.EndpointState;\nimport com.couchbase.client.core.service.ServiceType;\nimport com.couchbase.client.java.Cluster;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CouchbaseHealthIndicator}\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\nclass CouchbaseHealthIndicatorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid couchbaseClusterIsUp() {\n\t\tCluster cluster = mock(Cluster.class);\n\t\tCouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);\n\t\tMap<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,\n\t\t\t\tCollections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED,\n\t\t\t\t\t\tCircuitBreaker.State.DISABLED, \"127.0.0.1\", \"127.0.0.1\", Optional.empty(), Optional.of(1234L),\n\t\t\t\t\t\tOptional.of(\"endpoint-1\"), Optional.empty())));\n\n\t\tDiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, \"test-sdk\", \"test-id\");\n\t\tgiven(cluster.diagnostics()).willReturn(diagnostics);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"sdk\", \"test-sdk\");\n\t\tassertThat(health.getDetails()).containsKey(\"endpoints\");\n\t\tassertThat((List<Map<String, Object>>) health.getDetails().get(\"endpoints\")).hasSize(1);\n\t\tthen(cluster).should().diagnostics();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid couchbaseClusterIsDown() {\n\t\tCluster cluster = mock(Cluster.class);\n\t\tCouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);\n\t\tMap<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,\n\t\t\t\tArrays.asList(\n\t\t\t\t\t\tnew EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, CircuitBreaker.State.DISABLED,\n\t\t\t\t\t\t\t\t\"127.0.0.1\", \"127.0.0.1\", Optional.empty(), Optional.of(1234L),\n\t\t\t\t\t\t\t\tOptional.of(\"endpoint-1\"), Optional.empty()),\n\t\t\t\t\t\tnew EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, CircuitBreaker.State.DISABLED,\n\t\t\t\t\t\t\t\t\"127.0.0.1\", \"127.0.0.1\", Optional.empty(), Optional.of(1234L),\n\t\t\t\t\t\t\t\tOptional.of(\"endpoint-2\"), Optional.empty())));\n\t\tDiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, \"test-sdk\", \"test-id\");\n\t\tgiven(cluster.diagnostics()).willReturn(diagnostics);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"sdk\", \"test-sdk\");\n\t\tassertThat(health.getDetails()).containsKey(\"endpoints\");\n\t\tassertThat((List<Map<String, Object>>) health.getDetails().get(\"endpoints\")).hasSize(2);\n\t\tthen(cluster).should().diagnostics();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/java/org/springframework/boot/couchbase/health/CouchbaseReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.couchbase.health;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport com.couchbase.client.core.diagnostics.DiagnosticsResult;\nimport com.couchbase.client.core.diagnostics.EndpointDiagnostics;\nimport com.couchbase.client.core.endpoint.CircuitBreaker;\nimport com.couchbase.client.core.endpoint.EndpointState;\nimport com.couchbase.client.core.service.ServiceType;\nimport com.couchbase.client.java.Cluster;\nimport com.couchbase.client.java.ReactiveCluster;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CouchbaseReactiveHealthIndicator}.\n */\nclass CouchbaseReactiveHealthIndicatorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid couchbaseClusterIsUp() {\n\t\tCluster cluster = mock(Cluster.class);\n\t\tCouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);\n\t\tMap<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,\n\t\t\t\tCollections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED,\n\t\t\t\t\t\tCircuitBreaker.State.DISABLED, \"127.0.0.1\", \"127.0.0.1\", Optional.empty(), Optional.of(1234L),\n\t\t\t\t\t\tOptional.of(\"endpoint-1\"), Optional.empty())));\n\t\tDiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, \"test-sdk\", \"test-id\");\n\t\tReactiveCluster reactiveCluster = mock(ReactiveCluster.class);\n\t\tgiven(reactiveCluster.diagnostics()).willReturn(Mono.just(diagnostics));\n\t\tgiven(cluster.reactive()).willReturn(reactiveCluster);\n\t\tHealth health = healthIndicator.health().block(Duration.ofSeconds(30));\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"sdk\", \"test-sdk\");\n\t\tassertThat(health.getDetails()).containsKey(\"endpoints\");\n\t\tassertThat((List<Map<String, Object>>) health.getDetails().get(\"endpoints\")).hasSize(1);\n\t\tthen(reactiveCluster).should().diagnostics();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid couchbaseClusterIsDown() {\n\t\tCluster cluster = mock(Cluster.class);\n\t\tCouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);\n\t\tMap<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,\n\t\t\t\tArrays.asList(\n\t\t\t\t\t\tnew EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, CircuitBreaker.State.DISABLED,\n\t\t\t\t\t\t\t\t\"127.0.0.1\", \"127.0.0.1\", Optional.empty(), Optional.of(1234L),\n\t\t\t\t\t\t\t\tOptional.of(\"endpoint-1\"), Optional.empty()),\n\t\t\t\t\t\tnew EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, CircuitBreaker.State.DISABLED,\n\t\t\t\t\t\t\t\t\"127.0.0.1\", \"127.0.0.1\", Optional.empty(), Optional.of(1234L),\n\t\t\t\t\t\t\t\tOptional.of(\"endpoint-2\"), Optional.empty())));\n\t\tDiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, \"test-sdk\", \"test-id\");\n\t\tReactiveCluster reactiveCluster = mock(ReactiveCluster.class);\n\t\tgiven(reactiveCluster.diagnostics()).willReturn(Mono.just(diagnostics));\n\t\tgiven(cluster.reactive()).willReturn(reactiveCluster);\n\t\tHealth health = healthIndicator.health().block(Duration.ofSeconds(30));\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"sdk\", \"test-sdk\");\n\t\tassertThat(health.getDetails()).containsKey(\"endpoints\");\n\t\tassertThat((List<Map<String, Object>>) health.getDetails().get(\"endpoints\")).hasSize(2);\n\t\tthen(reactiveCluster).should().diagnostics();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/resources/org/springframework/boot/couchbase/autoconfigure/key.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAhECFFjLlXVdTxDdLlCifzrA0dTHHJ2mMA0GCSqGSIb3DQEBCwUAME8x\nCzAJBgNVBAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0Rl\nZmF1bHQgQ29tcGFueSBMdGQxCzAJBgNVBAMMAkNBMCAXDTIzMTAwNTA3Mjg1MFoY\nDzIxMjMwOTExMDcyODUwWjBRMQswCQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVs\ndCBDaXR5MRwwGgYDVQQKDBNEZWZhdWx0IENvbXBhbnkgTHRkMQ0wCwYDVQQDDARr\nZXkyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAspCMUdFGyKkgpMbW\n+UwSg4fdKM4qLSH7voTdsdVM9aAvLvYjBQ4gpORxDZNfUz67R0Ua0/oJt9jD49Wp\nqcq+tDOnp0dPtn2hFluV5PxM6d+MCSx/frPsfvyt9234okLL1zdLDNFYEbLhSPjA\nku3vHw/OwlJOxCRwTkPqcElIV4+IvIbzAgSffyokzm/wKVKEhoT6NcfeU+6wCkTu\nal1X8loJ+27N6jN13oGZfH7EveBqgR8rPs55+54S/OcVG/uqL9ggOGRJiIZ3jUBk\nm5cN27wKkaNg/CQwa1UjcU4qshVpknHw1dpgJ2Gbs/yUphwpEZl/FTsZFcK1KCHD\nrOp3PQIDAQABMA0GCSqGSIb3DQEBCwUAA4H/AAFmEq86broBFxs0cpImaM884PBT\nbvJBSsFhsOg6mi4Gt01G/lPSj/ExNtH3G5bytCYAPaRxNx/dCs7uON3p86ta4zL8\n2PxgyhX1oY/GG63ETwn5s3GKpRaGTNVDWvPIM9RX6+bvX/wOg8eYXVaQlG5XYadC\nMs9lWqHaM1C/iLGNmUTGcdbvhnmQDky2CwPNm+lXogSWbrsGpAmCkXJD1H+0Mx8I\nwjDVtGLBwr/8oXI8WbhvISMnS9+dd7+GLm6mU+14Kswi5I7EmBmREvkswi2IVJ6M\nGL7EY3qA6iqJWqsseYyLxiMr3nBT0SETphzoDanUQI1/jXQPrWIyjqvs\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-couchbase/src/test/resources/org/springframework/boot/couchbase/autoconfigure/key.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCykIxR0UbIqSCk\nxtb5TBKDh90oziotIfu+hN2x1Uz1oC8u9iMFDiCk5HENk19TPrtHRRrT+gm32MPj\n1ampyr60M6enR0+2faEWW5Xk/Ezp34wJLH9+s+x+/K33bfiiQsvXN0sM0VgRsuFI\n+MCS7e8fD87CUk7EJHBOQ+pwSUhXj4i8hvMCBJ9/KiTOb/ApUoSGhPo1x95T7rAK\nRO5qXVfyWgn7bs3qM3XegZl8fsS94GqBHys+znn7nhL85xUb+6ov2CA4ZEmIhneN\nQGSblw3bvAqRo2D8JDBrVSNxTiqyFWmScfDV2mAnYZuz/JSmHCkRmX8VOxkVwrUo\nIcOs6nc9AgMBAAECggEAPN9dDolG1aIeYD3uzCa8Sv2WjdIWe7NRlEXMI9MgvL1i\nSGKdVpxV0ZCU37llLkY85tNujWP4SyXIxdMxVxIoR9syJKsBSCd0sl//bgP6nmHY\nZco3HnTswu+VyLtDHuGhhtkxKwn0uXffKBaw44XcVhz38bPIaUI4zN2HPscks8BG\nj2MEl0N8P/TVrTkhgdjfoRi73VAisrEe+1wCg74BT7cmR8fEr7iNFrv955sdPGdw\nUTmx8U26++wbeYQs1ZE1713SYnRQuCUFs5GGjzOhNFi27zuhI6TafoVm9PO4j+ZC\nJUKTyUTBUsRMvm9z1IoHdjM8yInAv2g0J1bAeCTY+wKBgQDuMNMbNVoiXRKsSUry\n22T3W6HVLfLNKiYMNxsAkJjOiyyJcC+yg9BErn/haIHSafD2WmuWbW5ASViyl6fn\nD8qMluTwEaSrTgHXWI4ahWyapDShDQYp1s4dB75Aa/LVcFCay54YEtyCPzCPlj1K\njz5OBV14NEVVA2cf59fIc/LXCwKBgQC/6m3TefUp5jnN/QUOx2OtZo8Y1pVrsuMB\nAuTtb21Khxn/86ZpVzySzg79/DkSNf9/sZhzj0IkviWNP5S8iAAaFC1q08CYhdCX\nd7tVnHlzpZmmoHUhG6dlJZayr1duZrURp2rP18+wIsKiFRImAyjc6yswVRpZgAiG\ngOkHCB231wKBgGlwXZMWy/6YOtLfYvkcm5ZQDtSCkY+2j78qiZ53Y91SiHWSntqk\nNQaiRGOw0n8lfJBhOG0PphV5InV0YtQLDnurtE59UOqwDmqYfddJpujRtaZxUIAm\n4XjCW7rCzm0jWdscNbCscMaLWGDHffxKaqc5AsZaRTK73eOmysOmaCI/AoGAf/yd\nRZ1dzJWHE0Kb7uE2LlvpLo1clLh1/ySo+1eGMV+sDS+2WSYedWEKSoO8o9JzE/ui\nSd7OI6bTcEFotdqVBs9SAp45IP6Mv5bPziZOMLvNnnv/4RaKKkBJId0hl7TTKHTY\nHMg176ce2eznb4ZH6BzFbrQyoGFsThcGUPQurX0CgYBYtkDTp21TI1nuak7xpMIY\nBJQpqF5ahBf/+QYWtL0f3ca9MO2++zv5/XXitvt48cY1bCHNrVvSHgRzwSrOorZA\n5u7a5zyvfXjY3LY3k0VHddaVjU0mHsjx/1ux0wO2v8wQjOVZpT7XweB3WlUEGV7C\n5T/p+rmGg5Y5dTKUVCyvbQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data Cassandra\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-cassandra\"))\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(\"org.springframework.data:spring-data-cassandra\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-cassandra\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/dockerTest/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.data.cassandra.domain.city.City;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.cassandra.config.SchemaAction;\nimport org.springframework.data.cassandra.config.SessionFactoryFactoryBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCassandraAutoConfiguration} that require a Cassandra instance.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass DataCassandraAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(CassandraAutoConfiguration.class, DataCassandraAutoConfiguration.class))\n\t\t.withPropertyValues(\n\t\t\t\t\"spring.cassandra.contact-points:\" + cassandra.getHost() + \":\" + cassandra.getFirstMappedPort(),\n\t\t\t\t\"spring.cassandra.local-datacenter=datacenter1\", \"spring.cassandra.connection.connect-timeout=60s\",\n\t\t\t\t\"spring.cassandra.connection.init-query-timeout=60s\", \"spring.cassandra.request.timeout=60s\")\n\t\t.withInitializer((context) -> AutoConfigurationPackages.register((BeanDefinitionRegistry) context,\n\t\t\t\tCity.class.getPackage().getName()));\n\n\t@Test\n\tvoid hasDefaultSchemaActionSet() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(SessionFactoryFactoryBean.class))\n\t\t\t.hasFieldOrPropertyWithValue(\"schemaAction\", SchemaAction.NONE));\n\t}\n\n\t@Test\n\tvoid hasRecreateSchemaActionSet() {\n\t\tthis.contextRunner.withUserConfiguration(KeyspaceTestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cassandra.schemaAction=recreate_drop_unused\")\n\t\t\t.run((context) -> assertThat(context.getBean(SessionFactoryFactoryBean.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"schemaAction\", SchemaAction.RECREATE_DROP_UNUSED));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class KeyspaceTestConfiguration {\n\n\t\t@Bean\n\t\tCqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {\n\t\t\ttry (CqlSession session = cqlSessionBuilder.build()) {\n\t\t\t\tsession.execute(\"CREATE KEYSPACE IF NOT EXISTS boot_test\"\n\t\t\t\t\t\t+ \" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };\");\n\t\t\t}\n\t\t\treturn cqlSessionBuilder.withKeyspace(\"boot_test\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanPackages;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.data.cassandra.CassandraManagedTypes;\nimport org.springframework.data.cassandra.SessionFactory;\nimport org.springframework.data.cassandra.config.CassandraEntityClassScanner;\nimport org.springframework.data.cassandra.config.SchemaAction;\nimport org.springframework.data.cassandra.config.SessionFactoryFactoryBean;\nimport org.springframework.data.cassandra.core.CassandraAdminOperations;\nimport org.springframework.data.cassandra.core.CassandraOperations;\nimport org.springframework.data.cassandra.core.CassandraTemplate;\nimport org.springframework.data.cassandra.core.convert.CassandraConverter;\nimport org.springframework.data.cassandra.core.convert.CassandraCustomConversions;\nimport org.springframework.data.cassandra.core.convert.MappingCassandraConverter;\nimport org.springframework.data.cassandra.core.cql.CqlOperations;\nimport org.springframework.data.cassandra.core.cql.CqlTemplate;\nimport org.springframework.data.cassandra.core.mapping.CassandraMappingContext;\nimport org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Cassandra support.\n *\n * @author Julien Dubois\n * @author Eddú Meléndez\n * @author Mark Paluch\n * @author Madhura Bhave\n * @author Christoph Strobl\n * @since 4.0.0\n */\n@AutoConfiguration(after = CassandraAutoConfiguration.class)\n@ConditionalOnClass({ CqlSession.class, CassandraAdminOperations.class })\n@ConditionalOnBean(CqlSession.class)\npublic final class DataCassandraAutoConfiguration {\n\n\tprivate final CqlSession session;\n\n\tDataCassandraAutoConfiguration(@Lazy CqlSession session) {\n\t\tthis.session = session;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tstatic CassandraManagedTypes cassandraManagedTypes(BeanFactory beanFactory) throws ClassNotFoundException {\n\t\tList<String> packages = EntityScanPackages.get(beanFactory).getPackageNames();\n\t\tif (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) {\n\t\t\tpackages = AutoConfigurationPackages.get(beanFactory);\n\t\t}\n\t\tif (!packages.isEmpty()) {\n\t\t\treturn CassandraManagedTypes.fromIterable(CassandraEntityClassScanner.scan(packages));\n\t\t}\n\t\treturn CassandraManagedTypes.empty();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCassandraMappingContext cassandraMappingContext(CassandraManagedTypes cassandraManagedTypes,\n\t\t\tCassandraCustomConversions conversions) {\n\t\tCassandraMappingContext context = new CassandraMappingContext();\n\t\tcontext.setManagedTypes(cassandraManagedTypes);\n\t\tcontext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());\n\t\treturn context;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCassandraConverter cassandraConverter(CassandraMappingContext mapping, CassandraCustomConversions conversions) {\n\t\tMappingCassandraConverter converter = new MappingCassandraConverter(mapping);\n\t\tconverter.setCodecRegistry(() -> this.session.getContext().getCodecRegistry());\n\t\tconverter.setCustomConversions(conversions);\n\t\tconverter.setUserTypeResolver(new SimpleUserTypeResolver(this.session));\n\t\treturn converter;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(SessionFactory.class)\n\tSessionFactoryFactoryBean cassandraSessionFactory(Environment environment, CassandraConverter converter) {\n\t\tSessionFactoryFactoryBean session = new SessionFactoryFactoryBean();\n\t\tsession.setSession(this.session);\n\t\tsession.setConverter(converter);\n\t\tBinder binder = Binder.get(environment);\n\t\tbinder.bind(\"spring.cassandra.schema-action\", SchemaAction.class).ifBound(session::setSchemaAction);\n\t\treturn session;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(CqlOperations.class)\n\tCqlTemplate cqlTemplate(SessionFactory sessionFactory) {\n\t\treturn new CqlTemplate(sessionFactory);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(CassandraOperations.class)\n\tCassandraTemplate cassandraTemplate(CqlTemplate cqlTemplate, CassandraConverter converter) {\n\t\treturn new CassandraTemplate(cqlTemplate, converter);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCassandraCustomConversions cassandraCustomConversions() {\n\t\treturn new CassandraCustomConversions(Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraReactiveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.cassandra.ReactiveSession;\nimport org.springframework.data.cassandra.ReactiveSessionFactory;\nimport org.springframework.data.cassandra.core.ReactiveCassandraOperations;\nimport org.springframework.data.cassandra.core.ReactiveCassandraTemplate;\nimport org.springframework.data.cassandra.core.convert.CassandraConverter;\nimport org.springframework.data.cassandra.core.cql.ReactiveCqlOperations;\nimport org.springframework.data.cassandra.core.cql.ReactiveCqlTemplate;\nimport org.springframework.data.cassandra.core.cql.session.DefaultBridgedReactiveSession;\nimport org.springframework.data.cassandra.core.cql.session.DefaultReactiveSessionFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive Cassandra\n * support.\n *\n * @author Eddú Meléndez\n * @author Mark Paluch\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataCassandraAutoConfiguration.class)\n@ConditionalOnClass({ CqlSession.class, ReactiveCassandraTemplate.class, Flux.class })\n@ConditionalOnBean(CqlSession.class)\npublic final class DataCassandraReactiveAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tReactiveSession reactiveCassandraSession(CqlSession session) {\n\t\treturn new DefaultBridgedReactiveSession(session);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tReactiveSessionFactory reactiveCassandraSessionFactory(ReactiveSession reactiveCassandraSession) {\n\t\treturn new DefaultReactiveSessionFactory(reactiveCassandraSession);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveCqlOperations.class)\n\tReactiveCqlTemplate reactiveCqlTemplate(ReactiveSessionFactory reactiveCassandraSessionFactory) {\n\t\treturn new ReactiveCqlTemplate(reactiveCassandraSessionFactory);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveCassandraOperations.class)\n\tReactiveCassandraTemplate reactiveCassandraTemplate(ReactiveCqlTemplate reactiveCqlTemplate,\n\t\t\tCassandraConverter converter) {\n\t\treturn new ReactiveCassandraTemplate(reactiveCqlTemplate, converter);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraReactiveRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.cassandra.ReactiveSession;\nimport org.springframework.data.cassandra.repository.ReactiveCassandraRepository;\nimport org.springframework.data.cassandra.repository.config.EnableReactiveCassandraRepositories;\nimport org.springframework.data.cassandra.repository.support.ReactiveCassandraRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Cassandra Reactive\n * Repositories.\n *\n * @author Eddú Meléndez\n * @author Mark Paluch\n * @since 4.0.0\n * @see EnableReactiveCassandraRepositories\n */\n@AutoConfiguration(after = DataCassandraReactiveAutoConfiguration.class)\n@ConditionalOnClass({ ReactiveSession.class, ReactiveCassandraRepository.class })\n@ConditionalOnRepositoryType(store = \"cassandra\", type = RepositoryType.REACTIVE)\n@ConditionalOnMissingBean(ReactiveCassandraRepositoryFactoryBean.class)\n@Import(DataCassandraReactiveRepositoriesRegistrar.class)\npublic final class DataCassandraReactiveRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraReactiveRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.cassandra.repository.config.EnableReactiveCassandraRepositories;\nimport org.springframework.data.cassandra.repository.config.ReactiveCassandraRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Cassandra\n * Reactive Repositories.\n *\n * @author Eddú Meléndez\n */\nclass DataCassandraReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableReactiveCassandraRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableReactiveCassandraRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new ReactiveCassandraRepositoryConfigurationExtension();\n\t}\n\n\t@EnableReactiveCassandraRepositories\n\tprivate static final class EnableReactiveCassandraRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.cassandra.repository.CassandraRepository;\nimport org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;\nimport org.springframework.data.cassandra.repository.support.CassandraRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Cassandra\n * Repositories.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n * @see EnableCassandraRepositories\n */\n@AutoConfiguration\n@ConditionalOnClass({ CqlSession.class, CassandraRepository.class })\n@ConditionalOnRepositoryType(store = \"cassandra\", type = RepositoryType.IMPERATIVE)\n@ConditionalOnMissingBean(CassandraRepositoryFactoryBean.class)\n@Import(DataCassandraRepositoriesRegistrar.class)\npublic final class DataCassandraRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.cassandra.repository.config.CassandraRepositoryConfigurationExtension;\nimport org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Cassandra\n * Repositories.\n *\n * @author Eddú Meléndez\n */\nclass DataCassandraRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableCassandraRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableCassandraRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new CassandraRepositoryConfigurationExtension();\n\t}\n\n\t@EnableCassandraRepositories\n\tprivate static final class EnableCassandraRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/java/org/springframework/boot/data/cassandra/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Cassandra.\n */\n@NullMarked\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.cassandra.compression\",\n      \"defaultValue\": \"none\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.compression\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.config\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.config\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.connection.connect-timeout\",\n      \"defaultValue\": \"5s\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.connection.connect-timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.connection.init-query-timeout\",\n      \"defaultValue\": \"5s\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.connection.init-query-timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.contact-points\",\n      \"defaultValue\": [\n        \"127.0.0.1:9042\"\n      ],\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.contact-points\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.controlconnection.timeout\",\n      \"defaultValue\": \"5s\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.controlconnection.timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.jmx-enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JMX reporting. Default to false as Cassandra JMX reporting is not compatible with Dropwizard Metrics.\",\n      \"deprecation\": {\n        \"reason\": \"Cassandra no longer provides JMX metrics.\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.keyspace-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.keyspace-name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.load-balancing-policy\",\n      \"type\": \"java.lang.Class\",\n      \"description\": \"Class name of the load balancing policy. The class must have a default constructor.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.local-datacenter\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.local-datacenter\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.password\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.pool.heartbeat-interval\",\n      \"defaultValue\": \"30s\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.pool.heartbeat-interval\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.pool.idle-timeout\",\n      \"defaultValue\": \"5s\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.pool.idle-timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.pool.max-queue-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.throttler.max-queue-size\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.pool.pool-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Pool timeout when trying to acquire a connection from a host's pool.\",\n      \"deprecation\": {\n        \"reason\": \"No longer available.\",\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.port\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.port\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.reconnection-policy\",\n      \"type\": \"java.lang.Class\",\n      \"description\": \"Class name of the reconnection policy. The class must have a default constructor.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.repositories.type\",\n      \"type\": \"org.springframework.boot.autoconfigure.data.RepositoryType\",\n      \"description\": \"Type of Cassandra repositories to enable.\",\n      \"defaultValue\": \"auto\"\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.consistency\",\n      \"type\": \"com.datastax.oss.driver.api.core.DefaultConsistencyLevel\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.consistency\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.page-size\",\n      \"defaultValue\": 5000,\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.page-size\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.serial-consistency\",\n      \"type\": \"com.datastax.oss.driver.api.core.DefaultConsistencyLevel\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.serial-consistency\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.throttler.drain-interval\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.throttler.drain-interval\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.throttler.max-concurrent-requests\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.throttler.max-concurrent-requests\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.throttler.max-queue-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.throttler.max-queue-size\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.throttler.max-requests-per-second\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.throttler.max-requests-per-second\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.throttler.type\",\n      \"defaultValue\": \"none\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.throttler.type\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.request.timeout\",\n      \"defaultValue\": \"2s\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.request.timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.retry-policy\",\n      \"type\": \"java.lang.Class\",\n      \"description\": \"Class name of the retry policy. The class must have a default constructor.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.schema-action\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.schema-action\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.session-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.session-name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.ssl\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.ssl.enabled\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.cassandra.username\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.cassandra.username\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.cassandra.autoconfigure.DataCassandraAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraReactiveAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/autoconfigure/CassandraMockConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.context.DriverContext;\nimport com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test configuration that mocks access to Cassandra.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\nclass CassandraMockConfiguration {\n\n\tfinal CodecRegistry codecRegistry = mock(CodecRegistry.class);\n\n\t@Bean\n\tCqlSession cqlSession() {\n\t\tDriverContext context = mock(DriverContext.class);\n\t\tgiven(context.getCodecRegistry()).willReturn(this.codecRegistry);\n\t\tCqlSession cqlSession = mock(CqlSession.class);\n\t\tgiven(cqlSession.getContext()).willReturn(context);\n\t\treturn cqlSession;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport java.util.Collections;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.data.cassandra.domain.city.City;\nimport org.springframework.boot.persistence.autoconfigure.EntityScan;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.data.cassandra.core.CassandraTemplate;\nimport org.springframework.data.cassandra.core.convert.CassandraConverter;\nimport org.springframework.data.cassandra.core.convert.CassandraCustomConversions;\nimport org.springframework.data.cassandra.core.cql.CqlTemplate;\nimport org.springframework.data.cassandra.core.mapping.CassandraMappingContext;\nimport org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCassandraAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Mark Paluch\n * @author Stephane Nicoll\n */\nclass DataCassandraAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.cassandra.keyspaceName=boot_test\")\n\t\t.withUserConfiguration(CassandraMockConfiguration.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(CassandraAutoConfiguration.class, DataCassandraAutoConfiguration.class));\n\n\t@Test\n\tvoid cqlTemplateExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(CqlTemplate.class));\n\t}\n\n\t@Test\n\tvoid templateExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(CassandraTemplate.class));\n\t}\n\n\t@Test\n\tvoid templateUsesCqlTemplate() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CassandraTemplate.class);\n\t\t\tassertThat(context.getBean(CassandraTemplate.class).getCqlOperations())\n\t\t\t\t.isSameAs(context.getBean(CqlTemplate.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetManagedTypes() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CassandraMappingContext.class);\n\t\t\tCassandraMappingContext mappingContext = context.getBean(CassandraMappingContext.class);\n\t\t\tassertThat(mappingContext.getManagedTypes()).singleElement()\n\t\t\t\t.satisfies((typeInformation) -> assertThat(typeInformation.getType()).isEqualTo(City.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid userTypeResolverShouldBeSet() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CassandraConverter.class);\n\t\t\tassertThat(context.getBean(CassandraConverter.class)).extracting(\"userTypeResolver\")\n\t\t\t\t.isInstanceOf(SimpleUserTypeResolver.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid codecRegistryShouldBeSet() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CassandraConverter.class);\n\t\t\tassertThat(context.getBean(CassandraConverter.class).getCodecRegistry())\n\t\t\t\t.isSameAs(context.getBean(CassandraMockConfiguration.class).codecRegistry);\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultConversions() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tCassandraTemplate template = context.getBean(CassandraTemplate.class);\n\t\t\tassertThat(template.getConverter().getConversionService().canConvert(Person.class, String.class)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customConversions() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConversionConfig.class).run((context) -> {\n\t\t\tCassandraTemplate template = context.getBean(CassandraTemplate.class);\n\t\t\tassertThat(template.getConverter().getConversionService().canConvert(Person.class, String.class)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid clusterDoesNotExist() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tDataCassandraAutoConfiguration.class)) {\n\t\t\tassertThat(context.getBeansOfType(CqlSession.class)).isEmpty();\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(\"org.springframework.boot.data.cassandra.domain.city\")\n\tstatic class EntityScanConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConversionConfig {\n\n\t\t@Bean\n\t\tCassandraCustomConversions myCassandraCustomConversions() {\n\t\t\treturn new CassandraCustomConversions(Collections.singletonList(new MyConverter()));\n\t\t}\n\n\t}\n\n\tstatic class MyConverter implements Converter<Person, @Nullable String> {\n\n\t\t@Override\n\t\tpublic @Nullable String convert(Person o) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class Person {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.data.cassandra.domain.city.City;\nimport org.springframework.boot.persistence.autoconfigure.EntityScan;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.cassandra.core.ReactiveCassandraTemplate;\nimport org.springframework.data.cassandra.core.convert.CassandraConverter;\nimport org.springframework.data.cassandra.core.cql.ReactiveCqlTemplate;\nimport org.springframework.data.cassandra.core.mapping.CassandraMappingContext;\nimport org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCassandraReactiveAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Mark Paluch\n */\nclass DataCassandraReactiveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.cassandra.keyspaceName=boot_test\")\n\t\t.withUserConfiguration(CassandraMockConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class, DataCassandraAutoConfiguration.class,\n\t\t\t\tDataCassandraReactiveAutoConfiguration.class));\n\n\t@Test\n\tvoid reactiveCqlTemplateExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveCqlTemplate.class));\n\t}\n\n\t@Test\n\tvoid templateExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveCassandraTemplate.class));\n\t}\n\n\t@Test\n\tvoid templateUsesReactiveCqlTemplate() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveCassandraTemplate.class);\n\t\t\tassertThat(context.getBean(ReactiveCassandraTemplate.class).getReactiveCqlOperations())\n\t\t\t\t.isSameAs(context.getBean(ReactiveCqlTemplate.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetManagedTypes() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CassandraMappingContext.class);\n\t\t\tCassandraMappingContext mappingContext = context.getBean(CassandraMappingContext.class);\n\t\t\tassertThat(mappingContext.getManagedTypes()).singleElement()\n\t\t\t\t.satisfies((typeInformation) -> assertThat(typeInformation.getType()).isEqualTo(City.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid userTypeResolverShouldBeSet() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CassandraConverter.class);\n\t\t\tassertThat(context.getBean(CassandraConverter.class)).extracting(\"userTypeResolver\")\n\t\t\t\t.isInstanceOf(SimpleUserTypeResolver.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(\"org.springframework.boot.data.cassandra.domain.city\")\n\tstatic class EntityScanConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraReactiveRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.data.cassandra.domain.city.City;\nimport org.springframework.boot.data.cassandra.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.data.cassandra.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.cassandra.core.mapping.CassandraMappingContext;\nimport org.springframework.data.cassandra.repository.config.EnableReactiveCassandraRepositories;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCassandraReactiveRepositoriesAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Andy Wilkinson\n */\nclass DataCassandraReactiveRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class,\n\t\t\t\tDataCassandraRepositoriesAutoConfiguration.class, DataCassandraAutoConfiguration.class,\n\t\t\t\tDataCassandraReactiveAutoConfiguration.class, DataCassandraReactiveRepositoriesAutoConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveCityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(CqlSessionBuilder.class);\n\t\t\tassertThat(getManagedTypes(context).toList()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CqlSessionBuilder.class);\n\t\t\tassertThat(getManagedTypes(context).toList()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveCityRepository.class);\n\t\t\tassertThat(getManagedTypes(context).toList()).hasSize(1).containsOnly(City.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid enablingImperativeRepositoriesDisablesReactiveRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.cassandra.repositories.type=imperative\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid enablingNoRepositoriesDisablesReactiveRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.cassandra.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\tprivate ManagedTypes getManagedTypes(ApplicationContext context) {\n\t\tCassandraMappingContext mappingContext = context.getBean(CassandraMappingContext.class);\n\t\tObject field = ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (ManagedTypes) field;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\t@Import(CassandraMockConfiguration.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@Import(CassandraMockConfiguration.class)\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableReactiveCassandraRepositories(basePackageClasses = ReactiveCityRepository.class)\n\t@Import(CassandraMockConfiguration.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/autoconfigure/DataCassandraRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration;\nimport org.springframework.boot.data.cassandra.domain.city.City;\nimport org.springframework.boot.data.cassandra.domain.city.CityRepository;\nimport org.springframework.boot.data.cassandra.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.cassandra.core.mapping.CassandraMappingContext;\nimport org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCassandraRepositoriesAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Mark Paluch\n * @author Stephane Nicoll\n */\nclass DataCassandraRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(CassandraAutoConfiguration.class, DataCassandraRepositoriesAutoConfiguration.class,\n\t\t\t\t\tDataCassandraAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(CqlSessionBuilder.class);\n\t\t\tassertThat(getManagedTypes(context).toList()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CqlSessionBuilder.class);\n\t\t\tassertThat(getManagedTypes(context).toList()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\tassertThat(getManagedTypes(context).toList()).hasSize(1).containsOnly(City.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid enablingReactiveRepositoriesDisablesImperativeRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.cassandra.repositories.type=reactive\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid enablingNoRepositoriesDisablesImperativeRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.cassandra.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\tprivate ManagedTypes getManagedTypes(AssertableApplicationContext context) {\n\t\tCassandraMappingContext mappingContext = context.getBean(CassandraMappingContext.class);\n\t\tObject field = ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (ManagedTypes) field;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\t@Import(CassandraMockConfiguration.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@Import(CassandraMockConfiguration.class)\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableCassandraRepositories(basePackageClasses = CityRepository.class)\n\t@Import(CassandraMockConfiguration.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.domain.city;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.cassandra.core.mapping.CassandraType;\nimport org.springframework.data.cassandra.core.mapping.CassandraType.Name;\nimport org.springframework.data.cassandra.core.mapping.Column;\nimport org.springframework.data.cassandra.core.mapping.PrimaryKey;\nimport org.springframework.data.cassandra.core.mapping.Table;\n\n@Table\npublic class City {\n\n\t@PrimaryKey\n\t@CassandraType(type = Name.BIGINT)\n\tprivate @Nullable Long id;\n\n\t@Column\n\tprivate @Nullable String name;\n\n\t@Column\n\tprivate @Nullable String state;\n\n\t@Column\n\tprivate @Nullable String country;\n\n\t@Column\n\tprivate @Nullable String map;\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic @Nullable String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic void setState(String state) {\n\t\tthis.state = state;\n\t}\n\n\tpublic @Nullable String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic void setCountry(String country) {\n\t\tthis.country = country;\n\t}\n\n\tpublic @Nullable String getMap() {\n\t\treturn this.map;\n\t}\n\n\tpublic void setMap(String map) {\n\t\tthis.map = map;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.domain.city;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/domain/city/ReactiveCityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.domain.city;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface ReactiveCityRepository extends ReactiveCrudRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.cassandra.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/domain/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.domain.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra/src/test/java/org/springframework/boot/data/cassandra/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.cassandra.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data Cassandra Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-cassandra\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-cassandra\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport java.util.UUID;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.cassandra.core.CassandraTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration test for {@link DataCassandraTest @DataCassandraTest}.\n *\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataCassandraTest(properties = { \"spring.cassandra.schema-action=create-if-not-exists\",\n\t\t\"spring.cassandra.connection.connect-timeout=60s\", \"spring.cassandra.connection.init-query-timeout=60s\",\n\t\t\"spring.cassandra.request.timeout=60s\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass DataCassandraTestIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);\n\n\t@Autowired\n\tprivate CassandraTemplate cassandraTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleEntity entity = new ExampleEntity();\n\t\tentity.setDescription(\"Look, new @DataCassandraTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tentity.setId(id);\n\t\tExampleEntity savedEntity = this.exampleRepository.save(entity);\n\t\tExampleEntity getEntity = this.cassandraTemplate.selectOneById(id, ExampleEntity.class);\n\t\tassertThat(getEntity).isNotNull();\n\t\tassertThat(getEntity.getId()).isNotNull();\n\t\tassertThat(getEntity.getId()).isEqualTo(savedEntity.getId());\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class KeyspaceTestConfiguration {\n\n\t\t@Bean\n\t\tCqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {\n\t\t\ttry (CqlSession session = cqlSessionBuilder.build()) {\n\t\t\t\tsession.execute(\"CREATE KEYSPACE IF NOT EXISTS boot_test\"\n\t\t\t\t\t\t+ \" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };\");\n\t\t\t}\n\t\t\treturn cqlSessionBuilder.withKeyspace(\"boot_test\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport java.util.UUID;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for\n * {@link DataCassandraTest @DataCassandraTest}.\n *\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataCassandraTest(includeFilters = @Filter(Service.class),\n\t\tproperties = { \"spring.cassandra.schema-action=create-if-not-exists\",\n\t\t\t\t\"spring.cassandra.connection.connect-timeout=60s\", \"spring.cassandra.connection.init-query-timeout=60s\",\n\t\t\t\t\"spring.cassandra.request.timeout=60s\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass DataCassandraTestWithIncludeFilterIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CassandraContainer cassandra = TestImage.container(CassandraContainer.class);\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tExampleEntity exampleEntity = new ExampleEntity();\n\t\texampleEntity.setDescription(\"Look, new @DataCassandraTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\texampleEntity.setId(id);\n\t\tthis.exampleRepository.save(exampleEntity);\n\t\tassertThat(this.service.hasRecord(exampleEntity)).isTrue();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class KeyspaceTestConfiguration {\n\n\t\t@Bean\n\t\tCqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {\n\t\t\ttry (CqlSession session = cqlSessionBuilder.build()) {\n\t\t\t\tsession.execute(\"CREATE KEYSPACE IF NOT EXISTS boot_test\"\n\t\t\t\t\t\t+ \" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };\");\n\t\t\t}\n\t\t\treturn cqlSessionBuilder.withKeyspace(\"boot_test\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/ExampleCassandraApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataCassandraTest @DataCassandraTest} tests.\n *\n * @author Artsiom Yudovin\n */\n@SpringBootApplication\npublic class ExampleCassandraApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/ExampleEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\nimport org.springframework.data.cassandra.core.mapping.PrimaryKey;\nimport org.springframework.data.cassandra.core.mapping.Table;\n\n/**\n * Example graph used with {@link DataCassandraTest @DataCassandraTest} tests.\n *\n * @author Artsiom Yudovin\n */\n@Table\npublic class ExampleEntity {\n\n\t@PrimaryKey\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String description;\n\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\nimport org.springframework.data.cassandra.repository.CassandraRepository;\n\n/**\n * Example repository used with {@link DataCassandraTest @DataCassandraTest} tests.\n *\n * @author Artsiom Yudovin\n */\ninterface ExampleRepository extends CassandraRepository<ExampleEntity, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\nimport org.springframework.data.cassandra.core.CassandraTemplate;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataCassandraTest @DataCassandraTest} tests.\n *\n * @author Artsiom Yudovin\n */\n@Service\npublic class ExampleService {\n\n\tprivate final CassandraTemplate cassandraTemplate;\n\n\tpublic ExampleService(CassandraTemplate cassandraTemplate) {\n\t\tthis.cassandraTemplate = cassandraTemplate;\n\t}\n\n\tpublic boolean hasRecord(ExampleEntity entity) {\n\t\treturn this.cassandraTemplate.exists(entity.getId(), ExampleEntity.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/dockerTest/java/org/springframework/boot/test/autoconfigure/data/cassandra/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.test.autoconfigure.data.cassandra;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/main/java/org/springframework/boot/data/cassandra/test/autoconfigure/AutoConfigureDataCassandra.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data Cassandra\n * tests. Most tests should consider using {@link DataCassandraTest @DataCassandraTest}\n * rather than using this annotation directly.\n *\n * @author Artsiom Yudovin\n * @since 4.0.0\n * @see DataCassandraTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataCassandra {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/main/java/org/springframework/boot/data/cassandra/test/autoconfigure/DataCassandraTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for a Cassandra test that focuses <strong>only</strong> on\n * Cassandra components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data Casandra\n * tests. Similarly, component scanning is limited to Cassandra repositories and entities\n * ({@code @Table}).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Artsiom Yudovin\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataCassandraTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataCassandraTypeExcludeFilter.class)\n@AutoConfigureDataCassandra\n@ImportAutoConfiguration\npublic @interface DataCassandraTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/main/java/org/springframework/boot/data/cassandra/test/autoconfigure/DataCassandraTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataCassandraTest @DataCassandraTest}\n * support.\n *\n * @author Artsiom Yudovin\n */\nclass DataCassandraTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataCassandraTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/main/java/org/springframework/boot/data/cassandra/test/autoconfigure/DataCassandraTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataCassandraTest @DataCassandraTest}.\n *\n * @author Artsiom Yudovin\n */\nclass DataCassandraTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataCassandraTest> {\n\n\tDataCassandraTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/main/java/org/springframework/boot/data/cassandra/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data Cassandra tests.\n */\n@NullMarked\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/main/resources/META-INF/spring/org.springframework.boot.data.cassandra.test.autoconfigure.AutoConfigureDataCassandra.imports",
    "content": "org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration\norg.springframework.boot.cassandra.autoconfigure.CassandraAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraReactiveAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.cassandra.autoconfigure.DataCassandraRepositoriesAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/test/java/org/springframework/boot/data/cassandra/test/autoconfigure/DataCassandraTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Application for testing of {@link DataCassandraTest @DataCassandraTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\nclass DataCassandraTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-cassandra-test/src/test/java/org/springframework/boot/data/cassandra/test/autoconfigure/DataCassandraTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.cassandra.test.autoconfigure;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.context.DriverContext;\nimport com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTestPropertiesIntegrationTests.CassandraMockConfiguration;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for the {@link DataCassandraTest#properties properties} attribute of\n * {@link DataCassandraTest @DataCassandraTest}.\n *\n * @author Artsiom Yudovin\n */\n@Import(CassandraMockConfiguration.class)\n@DataCassandraTest(properties = \"spring.profiles.active=test\")\nclass DataCassandraTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataCassandraTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n\t@TestConfiguration\n\tstatic class CassandraMockConfiguration {\n\n\t\t@Bean\n\t\tCqlSession cqlSession() {\n\t\t\tDriverContext context = mock(DriverContext.class);\n\t\t\tCodecRegistry codecRegistry = mock(CodecRegistry.class);\n\t\t\tgiven(context.getCodecRegistry()).willReturn(codecRegistry);\n\t\t\tCqlSession cqlSession = mock(CqlSession.class);\n\t\t\tgiven(cqlSession.getContext()).willReturn(context);\n\t\t\treturn cqlSession;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data Commons\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-persistence\"))\n\tapi(\"org.springframework.data:spring-data-commons\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-jdbc\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"org.springframework.data:spring-data-jdbc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/metrics/DataMetricsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring\n * Micrometer-based Spring Data metrics.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.metrics.data\")\npublic class DataMetricsProperties {\n\n\tprivate final Repository repository = new Repository();\n\n\tpublic Repository getRepository() {\n\t\treturn this.repository;\n\t}\n\n\tpublic static class Repository {\n\n\t\t/**\n\t\t * Name of the metric for sent requests.\n\t\t */\n\t\tprivate String metricName = \"spring.data.repository.invocations\";\n\n\t\t/**\n\t\t * Auto-timed request settings.\n\t\t */\n\t\tprivate final Autotime autotime = new Autotime();\n\n\t\tpublic String getMetricName() {\n\t\t\treturn this.metricName;\n\t\t}\n\n\t\tpublic void setMetricName(String metricName) {\n\t\t\tthis.metricName = metricName;\n\t\t}\n\n\t\tpublic Autotime getAutotime() {\n\t\t\treturn this.autotime;\n\t\t}\n\n\t\tpublic static class Autotime {\n\n\t\t\t/**\n\t\t\t * Whether to enable auto-timing.\n\t\t\t */\n\t\t\tprivate boolean enabled = true;\n\n\t\t\t/**\n\t\t\t * Whether to publish percentile histograms.\n\t\t\t */\n\t\t\tprivate boolean percentilesHistogram;\n\n\t\t\t/**\n\t\t\t * Percentiles for which additional time series should be published.\n\t\t\t */\n\t\t\tprivate double @Nullable [] percentiles;\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic boolean isPercentilesHistogram() {\n\t\t\t\treturn this.percentilesHistogram;\n\t\t\t}\n\n\t\t\tpublic void setPercentilesHistogram(boolean percentilesHistogram) {\n\t\t\t\tthis.percentilesHistogram = percentilesHistogram;\n\t\t\t}\n\n\t\t\tpublic double @Nullable [] getPercentiles() {\n\t\t\t\treturn this.percentiles;\n\t\t\t}\n\n\t\t\tpublic void setPercentiles(double @Nullable [] percentiles) {\n\t\t\t\tthis.percentiles = percentiles;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/metrics/DataRepositoryMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.data.autoconfigure.metrics.DataMetricsProperties.Repository;\nimport org.springframework.boot.data.metrics.DefaultRepositoryTagsProvider;\nimport org.springframework.boot.data.metrics.MetricsRepositoryMethodInvocationListener;\nimport org.springframework.boot.data.metrics.RepositoryTagsProvider;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Repository metrics.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = {\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\",\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration\",\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration\" })\n@ConditionalOnClass(org.springframework.data.repository.Repository.class)\n@ConditionalOnBean(MeterRegistry.class)\n@EnableConfigurationProperties(DataMetricsProperties.class)\npublic final class DataRepositoryMetricsAutoConfiguration {\n\n\tprivate final DataMetricsProperties properties;\n\n\tDataRepositoryMetricsAutoConfiguration(DataMetricsProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(RepositoryTagsProvider.class)\n\tDefaultRepositoryTagsProvider repositoryTagsProvider() {\n\t\treturn new DefaultRepositoryTagsProvider();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMetricsRepositoryMethodInvocationListener metricsRepositoryMethodInvocationListener(\n\t\t\tObjectProvider<MeterRegistry> registry, RepositoryTagsProvider tagsProvider) {\n\t\tRepository properties = this.properties.getRepository();\n\t\treturn new MetricsRepositoryMethodInvocationListener(registry::getObject, tagsProvider,\n\t\t\t\tproperties.getMetricName(), new PropertiesAutoTimer(properties.getAutotime()));\n\t}\n\n\t@Bean\n\tstatic MetricsRepositoryMethodInvocationListenerBeanPostProcessor metricsRepositoryMethodInvocationListenerBeanPostProcessor(\n\t\t\tObjectProvider<MetricsRepositoryMethodInvocationListener> metricsRepositoryMethodInvocationListener) {\n\t\treturn new MetricsRepositoryMethodInvocationListenerBeanPostProcessor(\n\t\t\t\tSingletonSupplier.of(metricsRepositoryMethodInvocationListener::getObject));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/metrics/MetricsRepositoryMethodInvocationListenerBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.data.metrics.MetricsRepositoryMethodInvocationListener;\nimport org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;\nimport org.springframework.data.repository.core.support.RepositoryFactoryCustomizer;\nimport org.springframework.data.repository.core.support.RepositoryFactorySupport;\nimport org.springframework.util.Assert;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link BeanPostProcessor} to apply a {@link MetricsRepositoryMethodInvocationListener}\n * to all {@link RepositoryFactorySupport repository factories}.\n *\n * @author Phillip Webb\n */\nclass MetricsRepositoryMethodInvocationListenerBeanPostProcessor implements BeanPostProcessor {\n\n\tprivate final RepositoryFactoryCustomizer customizer;\n\n\tMetricsRepositoryMethodInvocationListenerBeanPostProcessor(\n\t\t\tSingletonSupplier<MetricsRepositoryMethodInvocationListener> listener) {\n\t\tthis.customizer = new MetricsRepositoryFactoryCustomizer(listener);\n\t}\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof RepositoryFactoryBeanSupport) {\n\t\t\t((RepositoryFactoryBeanSupport<?, ?, ?>) bean).addRepositoryFactoryCustomizer(this.customizer);\n\t\t}\n\t\treturn bean;\n\t}\n\n\tprivate static final class MetricsRepositoryFactoryCustomizer implements RepositoryFactoryCustomizer {\n\n\t\tprivate final SingletonSupplier<MetricsRepositoryMethodInvocationListener> listenerSupplier;\n\n\t\tprivate MetricsRepositoryFactoryCustomizer(\n\t\t\t\tSingletonSupplier<MetricsRepositoryMethodInvocationListener> listenerSupplier) {\n\t\t\tthis.listenerSupplier = listenerSupplier;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(RepositoryFactorySupport repositoryFactory) {\n\t\t\tMetricsRepositoryMethodInvocationListener listener = this.listenerSupplier.get();\n\t\t\tAssert.state(listener != null, \"'listener' must not be null\");\n\t\t\trepositoryFactory.addInvocationListener(listener);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/metrics/PropertiesAutoTimer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.Timer.Builder;\n\nimport org.springframework.boot.data.autoconfigure.metrics.DataMetricsProperties.Repository.Autotime;\nimport org.springframework.boot.data.metrics.AutoTimer;\n\n/**\n * {@link AutoTimer} whose behavior is configured by {@link Autotime} properties.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class PropertiesAutoTimer implements AutoTimer {\n\n\tprivate final Autotime properties;\n\n\t/**\n\t * Create a new {@link PropertiesAutoTimer} configured using the given\n\t * {@code properties}.\n\t * @param properties the properties to configure auto-timing\n\t */\n\tpublic PropertiesAutoTimer(Autotime properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Override\n\tpublic void apply(Builder builder) {\n\t\tbuilder.publishPercentileHistogram(this.properties.isPercentilesHistogram())\n\t\t\t.publishPercentiles(this.properties.getPercentiles());\n\t}\n\n\t@Override\n\tpublic boolean isEnabled() {\n\t\treturn this.properties.isEnabled();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data repository metrics.\n */\n@NullMarked\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/web/DataWebAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.web;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.data.autoconfigure.web.DataWebProperties.Pageable;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.web.PageableHandlerMethodArgumentResolver;\nimport org.springframework.data.web.config.EnableSpringDataWebSupport;\nimport org.springframework.data.web.config.PageableHandlerMethodArgumentResolverCustomizer;\nimport org.springframework.data.web.config.SortHandlerMethodArgumentResolverCustomizer;\nimport org.springframework.data.web.config.SpringDataWebSettings;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's web support.\n * <p>\n * When in effect, the auto-configuration is the equivalent of enabling Spring Data's web\n * support through the {@link EnableSpringDataWebSupport @EnableSpringDataWebSupport}\n * annotation.\n *\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration\n@EnableSpringDataWebSupport\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ PageableHandlerMethodArgumentResolver.class, WebMvcConfigurer.class })\n@ConditionalOnMissingBean(PageableHandlerMethodArgumentResolver.class)\n@EnableConfigurationProperties(DataWebProperties.class)\npublic final class DataWebAutoConfiguration {\n\n\tprivate final DataWebProperties properties;\n\n\tDataWebAutoConfiguration(DataWebProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPageableHandlerMethodArgumentResolverCustomizer pageableCustomizer() {\n\t\treturn (resolver) -> {\n\t\t\tPageable pageable = this.properties.getPageable();\n\t\t\tresolver.setPageParameterName(pageable.getPageParameter());\n\t\t\tresolver.setSizeParameterName(pageable.getSizeParameter());\n\t\t\tresolver.setOneIndexedParameters(pageable.isOneIndexedParameters());\n\t\t\tresolver.setPrefix(pageable.getPrefix());\n\t\t\tresolver.setQualifierDelimiter(pageable.getQualifierDelimiter());\n\t\t\tresolver.setFallbackPageable(PageRequest.of(0, pageable.getDefaultPageSize()));\n\t\t\tresolver.setMaxPageSize(pageable.getMaxPageSize());\n\t\t};\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSortHandlerMethodArgumentResolverCustomizer sortCustomizer() {\n\t\treturn (resolver) -> resolver.setSortParameter(this.properties.getSort().getSortParameter());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSpringDataWebSettings springDataWebSettings() {\n\t\treturn new SpringDataWebSettings(this.properties.getPageable().getSerializationMode());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/web/DataWebProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.web;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.data.web.config.EnableSpringDataWebSupport.PageSerializationMode;\n\n/**\n * Configuration properties for Spring Data Web.\n *\n * @author Vedran Pavic\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.web\")\npublic class DataWebProperties {\n\n\tprivate final Pageable pageable = new Pageable();\n\n\tprivate final Sort sort = new Sort();\n\n\tpublic Pageable getPageable() {\n\t\treturn this.pageable;\n\t}\n\n\tpublic Sort getSort() {\n\t\treturn this.sort;\n\t}\n\n\t/**\n\t * Pageable properties.\n\t */\n\tpublic static class Pageable {\n\n\t\t/**\n\t\t * Page index parameter name.\n\t\t */\n\t\tprivate String pageParameter = \"page\";\n\n\t\t/**\n\t\t * Page size parameter name.\n\t\t */\n\t\tprivate String sizeParameter = \"size\";\n\n\t\t/**\n\t\t * Whether to expose and assume 1-based page number indexes. Defaults to \"false\",\n\t\t * meaning a page number of 0 in the request equals the first page.\n\t\t */\n\t\tprivate boolean oneIndexedParameters;\n\n\t\t/**\n\t\t * General prefix to be prepended to the page number and page size parameters.\n\t\t */\n\t\tprivate String prefix = \"\";\n\n\t\t/**\n\t\t * Delimiter to be used between the qualifier and the actual page number and size\n\t\t * properties.\n\t\t */\n\t\tprivate String qualifierDelimiter = \"_\";\n\n\t\t/**\n\t\t * Default page size.\n\t\t */\n\t\tprivate int defaultPageSize = 20;\n\n\t\t/**\n\t\t * Maximum page size to be accepted.\n\t\t */\n\t\tprivate int maxPageSize = 2000;\n\n\t\t/**\n\t\t * Configures how to render Spring Data Pageable instances.\n\t\t */\n\t\tprivate PageSerializationMode serializationMode = PageSerializationMode.DIRECT;\n\n\t\tpublic String getPageParameter() {\n\t\t\treturn this.pageParameter;\n\t\t}\n\n\t\tpublic void setPageParameter(String pageParameter) {\n\t\t\tthis.pageParameter = pageParameter;\n\t\t}\n\n\t\tpublic String getSizeParameter() {\n\t\t\treturn this.sizeParameter;\n\t\t}\n\n\t\tpublic void setSizeParameter(String sizeParameter) {\n\t\t\tthis.sizeParameter = sizeParameter;\n\t\t}\n\n\t\tpublic boolean isOneIndexedParameters() {\n\t\t\treturn this.oneIndexedParameters;\n\t\t}\n\n\t\tpublic void setOneIndexedParameters(boolean oneIndexedParameters) {\n\t\t\tthis.oneIndexedParameters = oneIndexedParameters;\n\t\t}\n\n\t\tpublic String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic void setPrefix(String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t\tpublic String getQualifierDelimiter() {\n\t\t\treturn this.qualifierDelimiter;\n\t\t}\n\n\t\tpublic void setQualifierDelimiter(String qualifierDelimiter) {\n\t\t\tthis.qualifierDelimiter = qualifierDelimiter;\n\t\t}\n\n\t\tpublic int getDefaultPageSize() {\n\t\t\treturn this.defaultPageSize;\n\t\t}\n\n\t\tpublic void setDefaultPageSize(int defaultPageSize) {\n\t\t\tthis.defaultPageSize = defaultPageSize;\n\t\t}\n\n\t\tpublic int getMaxPageSize() {\n\t\t\treturn this.maxPageSize;\n\t\t}\n\n\t\tpublic void setMaxPageSize(int maxPageSize) {\n\t\t\tthis.maxPageSize = maxPageSize;\n\t\t}\n\n\t\tpublic PageSerializationMode getSerializationMode() {\n\t\t\treturn this.serializationMode;\n\t\t}\n\n\t\tpublic void setSerializationMode(PageSerializationMode serializationMode) {\n\t\t\tthis.serializationMode = serializationMode;\n\t\t}\n\n\t}\n\n\t/**\n\t * Sort properties.\n\t */\n\tpublic static class Sort {\n\n\t\t/**\n\t\t * Sort parameter name.\n\t\t */\n\t\tprivate String sortParameter = \"sort\";\n\n\t\tpublic String getSortParameter() {\n\t\t\treturn this.sortParameter;\n\t\t}\n\n\t\tpublic void setSortParameter(String sortParameter) {\n\t\t\tthis.sortParameter = sortParameter;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/autoconfigure/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data web.\n */\n@NullMarked\npackage org.springframework.boot.data.autoconfigure.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/metrics/AutoTimer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport io.micrometer.core.annotation.Timed;\nimport io.micrometer.core.instrument.Timer;\nimport io.micrometer.core.instrument.Timer.Builder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Strategy that can be used to apply {@link Timer Timers} automatically instead of using\n * {@link Timed @Timed}.\n *\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface AutoTimer {\n\n\t/**\n\t * An {@link AutoTimer} implementation that is enabled but applies no additional\n\t * customizations.\n\t */\n\tAutoTimer ENABLED = (builder) -> {\n\t};\n\n\t/**\n\t * An {@link AutoTimer} implementation that is disabled and will not record metrics.\n\t */\n\tAutoTimer DISABLED = new AutoTimer() {\n\n\t\t@Override\n\t\tpublic boolean isEnabled() {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic void apply(Builder builder) {\n\t\t\tthrow new IllegalStateException(\"AutoTimer is disabled\");\n\t\t}\n\n\t};\n\n\t/**\n\t * Return if the auto-timer is enabled and metrics should be recorded.\n\t * @return if the auto-timer is enabled\n\t */\n\tdefault boolean isEnabled() {\n\t\treturn true;\n\t}\n\n\t/**\n\t * Factory method to create a new {@link Builder Timer.Builder} with auto-timer\n\t * settings {@link #apply(Timer.Builder) applied}.\n\t * @param name the name of the timer\n\t * @return a new builder instance with auto-settings applied\n\t */\n\tdefault Timer.Builder builder(String name) {\n\t\treturn builder(() -> Timer.builder(name));\n\t}\n\n\t/**\n\t * Factory method to create a new {@link Builder Timer.Builder} with auto-timer\n\t * settings {@link #apply(Timer.Builder) applied}.\n\t * @param supplier the builder supplier\n\t * @return a new builder instance with auto-settings applied\n\t */\n\tdefault Timer.Builder builder(Supplier<Timer.Builder> supplier) {\n\t\tTimer.Builder builder = supplier.get();\n\t\tapply(builder);\n\t\treturn builder;\n\t}\n\n\t/**\n\t * Called to apply any auto-timer settings to the given {@link Builder Timer.Builder}.\n\t * @param builder the builder to apply settings to\n\t */\n\tvoid apply(Timer.Builder builder);\n\n\tstatic void apply(@Nullable AutoTimer autoTimer, String metricName, Set<Timed> annotations,\n\t\t\tConsumer<Timer.Builder> action) {\n\t\tif (!CollectionUtils.isEmpty(annotations)) {\n\t\t\tfor (Timed annotation : annotations) {\n\t\t\t\taction.accept(Timer.builder(annotation, metricName));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (autoTimer != null && autoTimer.isEnabled()) {\n\t\t\t\taction.accept(autoTimer.builder(metricName));\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/metrics/DefaultRepositoryTagsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.lang.reflect.Method;\nimport java.util.function.Function;\n\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult.State;\nimport org.springframework.util.StringUtils;\n\n/**\n * Default {@link RepositoryTagsProvider} implementation.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DefaultRepositoryTagsProvider implements RepositoryTagsProvider {\n\n\tprivate static final Tag EXCEPTION_NONE = Tag.of(\"exception\", \"None\");\n\n\t@Override\n\tpublic Iterable<Tag> repositoryTags(RepositoryMethodInvocation invocation) {\n\t\tTags tags = Tags.empty();\n\t\ttags = and(tags, invocation.getRepositoryInterface(), \"repository\", this::getSimpleClassName);\n\t\ttags = and(tags, invocation.getMethod(), \"method\", Method::getName);\n\t\tRepositoryMethodInvocationResult result = invocation.getResult();\n\t\tif (result != null) {\n\t\t\ttags = and(tags, result.getState(), \"state\", State::name);\n\t\t\ttags = and(tags, result.getError(), \"exception\", this::getExceptionName, EXCEPTION_NONE);\n\t\t}\n\t\treturn tags;\n\t}\n\n\tprivate <T> Tags and(Tags tags, @Nullable T instance, String key, Function<T, String> value) {\n\t\treturn and(tags, instance, key, value, null);\n\t}\n\n\tprivate <T> Tags and(Tags tags, @Nullable T instance, String key, Function<T, String> value,\n\t\t\t@Nullable Tag fallback) {\n\t\tif (instance != null) {\n\t\t\treturn tags.and(key, value.apply(instance));\n\t\t}\n\t\treturn (fallback != null) ? tags.and(fallback) : tags;\n\t}\n\n\tprivate String getExceptionName(Throwable error) {\n\t\treturn getSimpleClassName(error.getClass());\n\t}\n\n\tprivate String getSimpleClassName(Class<?> type) {\n\t\tString simpleName = type.getSimpleName();\n\t\treturn (!StringUtils.hasText(simpleName)) ? type.getName() : simpleName;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/metrics/MetricsRepositoryMethodInvocationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\n\nimport io.micrometer.core.annotation.Timed;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener;\nimport org.springframework.util.Assert;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * Intercepts Spring Data {@code Repository} invocations and records metrics about\n * execution time and results.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class MetricsRepositoryMethodInvocationListener implements RepositoryMethodInvocationListener {\n\n\tprivate final SingletonSupplier<MeterRegistry> registrySupplier;\n\n\tprivate final RepositoryTagsProvider tagsProvider;\n\n\tprivate final String metricName;\n\n\tprivate final AutoTimer autoTimer;\n\n\t/**\n\t * Create a new {@code MetricsRepositoryMethodInvocationListener}.\n\t * @param registrySupplier a supplier for the registry to which metrics are recorded\n\t * @param tagsProvider provider for metrics tags\n\t * @param metricName name of the metric to record\n\t * @param autoTimer the auto-timers to apply or {@code null} to disable auto-timing\n\t * @since 4.0.0\n\t */\n\tpublic MetricsRepositoryMethodInvocationListener(Supplier<MeterRegistry> registrySupplier,\n\t\t\tRepositoryTagsProvider tagsProvider, String metricName, @Nullable AutoTimer autoTimer) {\n\t\tthis.registrySupplier = (registrySupplier instanceof SingletonSupplier)\n\t\t\t\t? (SingletonSupplier<MeterRegistry>) registrySupplier : SingletonSupplier.of(registrySupplier);\n\t\tthis.tagsProvider = tagsProvider;\n\t\tthis.metricName = metricName;\n\t\tthis.autoTimer = (autoTimer != null) ? autoTimer : AutoTimer.DISABLED;\n\t}\n\n\t@Override\n\tpublic void afterInvocation(RepositoryMethodInvocation invocation) {\n\t\tSet<Timed> annotations = TimedAnnotations.get(invocation.getMethod(), invocation.getRepositoryInterface());\n\t\tIterable<Tag> tags = this.tagsProvider.repositoryTags(invocation);\n\t\tlong duration = invocation.getDuration(TimeUnit.NANOSECONDS);\n\t\tAutoTimer.apply(this.autoTimer, this.metricName, annotations, (builder) -> {\n\t\t\tMeterRegistry registry = this.registrySupplier.get();\n\t\t\tAssert.state(registry != null, \"'registry' must not be null\");\n\t\t\tbuilder.description(\"Duration of repository invocations\")\n\t\t\t\t.tags(tags)\n\t\t\t\t.register(registry)\n\t\t\t\t.record(duration, TimeUnit.NANOSECONDS);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/metrics/RepositoryTagsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport io.micrometer.core.instrument.Tag;\n\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation;\n\n/**\n * Provides {@link Tag Tags} for Spring Data {@link RepositoryMethodInvocation Repository\n * invocations}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RepositoryTagsProvider {\n\n\t/**\n\t * Provides tags to be associated with metrics for the given {@code invocation}.\n\t * @param invocation the repository invocation\n\t * @return tags to associate with metrics for the invocation\n\t */\n\tIterable<Tag> repositoryTags(RepositoryMethodInvocation invocation);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/metrics/TimedAnnotations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.micrometer.core.annotation.Timed;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.annotation.MergedAnnotationCollectors;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.util.ConcurrentReferenceHashMap;\n\n/**\n * Utility used to obtain {@link Timed @Timed} annotations from bean methods.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class TimedAnnotations {\n\n\tprivate static final Map<AnnotatedElement, Set<Timed>> cache = new ConcurrentReferenceHashMap<>();\n\n\tprivate TimedAnnotations() {\n\t}\n\n\t/**\n\t * Return {@link Timed} annotations that should be used for the given {@code method}\n\t * and {@code type}.\n\t * @param method the source method\n\t * @param type the source type\n\t * @return the {@link Timed} annotations to use or an empty set\n\t */\n\tpublic static Set<Timed> get(Method method, Class<?> type) {\n\t\tSet<Timed> methodAnnotations = findTimedAnnotations(method);\n\t\tif (!methodAnnotations.isEmpty()) {\n\t\t\treturn methodAnnotations;\n\t\t}\n\t\treturn findTimedAnnotations(type);\n\t}\n\n\tprivate static Set<Timed> findTimedAnnotations(@Nullable AnnotatedElement element) {\n\t\tif (element == null) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t\tSet<Timed> result = cache.get(element);\n\t\tif (result != null) {\n\t\t\treturn result;\n\t\t}\n\t\tMergedAnnotations annotations = MergedAnnotations.from(element);\n\t\tresult = (!annotations.isPresent(Timed.class)) ? Collections.emptySet()\n\t\t\t\t: annotations.stream(Timed.class).collect(MergedAnnotationCollectors.toAnnotationSet());\n\t\tcache.put(element, result);\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/java/org/springframework/boot/data/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Data repository metrics.\n */\n@NullMarked\npackage org.springframework.boot.data.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.autoconfigure.metrics.DataRepositoryMetricsAutoConfiguration\norg.springframework.boot.data.autoconfigure.web.DataWebAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.data.autoconfigure.web.DataWebAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/autoconfigure/metrics/DataRepositoryMetricsAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.domain.city.City;\nimport org.springframework.boot.data.domain.city.CityRepository;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;\nimport org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link DataRepositoryMetricsAutoConfiguration}.\n *\n * @author Phillip Webb\n */\n@WithResource(name = \"schema.sql\", content = \"\"\"\n\t\tCREATE TABLE CITY (\n\t\t  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\t\t  name VARCHAR(30),\n\t\t  country  VARCHAR(30)\n\t\t);\n\t\t\"\"\")\nclass DataRepositoryMetricsAutoConfigurationIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tDataRepositoryMetricsAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,\n\t\t\t\tDataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,\n\t\t\t\tDataSourceInitializationAutoConfiguration.class))\n\t\t.withUserConfiguration(TestConfig.class);\n\n\t@Test\n\tvoid repositoryMethodCallRecordsMetrics() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tcontext.getBean(CityRepository.class).count();\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.get(\"spring.data.repository.invocations\")\n\t\t\t\t.tag(\"repository\", \"CityRepository\")\n\t\t\t\t.timer()\n\t\t\t\t.count()).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotPreventMeterBindersFromDependingUponSpringDataRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SpringDataRepositoryMeterBinderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableJdbcRepositories(basePackageClasses = City.class)\n\tstatic class TestConfig extends AbstractJdbcConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SpringDataRepositoryMeterBinderConfiguration {\n\n\t\t@Bean\n\t\tMeterBinder meterBinder(CityRepository repository) {\n\t\t\treturn (registry) -> Gauge.builder(\"city.count\", repository::count);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/autoconfigure/metrics/DataRepositoryMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.function.Supplier;\n\nimport io.micrometer.core.annotation.Timed;\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Timer;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.distribution.HistogramSnapshot;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.metrics.AutoTimer;\nimport org.springframework.boot.data.metrics.DefaultRepositoryTagsProvider;\nimport org.springframework.boot.data.metrics.MetricsRepositoryMethodInvocationListener;\nimport org.springframework.boot.data.metrics.RepositoryTagsProvider;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.repository.Repository;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult.State;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataRepositoryMetricsAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass DataRepositoryMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, DataRepositoryMetricsAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid backsOffWhenMeterRegistryIsMissing() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(DataRepositoryMetricsAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RepositoryTagsProvider.class));\n\t}\n\n\t@Test\n\tvoid definesTagsProviderAndListenerWhenMeterRegistryIsPresent() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DefaultRepositoryTagsProvider.class);\n\t\t\tassertThat(context).hasSingleBean(MetricsRepositoryMethodInvocationListener.class);\n\t\t\tassertThat(context).hasSingleBean(MetricsRepositoryMethodInvocationListenerBeanPostProcessor.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid tagsProviderBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(TagsProviderConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(DefaultRepositoryTagsProvider.class);\n\t\t\tassertThat(context).hasSingleBean(TestRepositoryTagsProvider.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid metricsRepositoryMethodInvocationListenerBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(MetricsRepositoryMethodInvocationListenerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(MetricsRepositoryMethodInvocationListener.class);\n\t\t\t\tassertThat(context).hasSingleBean(TestMetricsRepositoryMethodInvocationListener.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid metricNameCanBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.data.repository.metric-name=datarepo\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context, ExampleRepository.class);\n\t\t\t\tTimer timer = registry.get(\"datarepo\").timer();\n\t\t\t\tassertThat(timer).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoTimeRequestsCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.metrics.data.repository.autotime.enabled=true\",\n\t\t\t\t\t\"management.metrics.data.repository.autotime.percentiles=0.5,0.7\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context, ExampleRepository.class);\n\t\t\t\tTimer timer = registry.get(\"spring.data.repository.invocations\").timer();\n\t\t\t\tHistogramSnapshot snapshot = timer.takeSnapshot();\n\t\t\t\tassertThat(snapshot.percentileValues()).hasSize(2);\n\t\t\t\tassertThat(snapshot.percentileValues()[0].percentile()).isEqualTo(0.5);\n\t\t\t\tassertThat(snapshot.percentileValues()[1].percentile()).isEqualTo(0.7);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid timerWorksWithTimedAnnotationsWhenAutoTimeRequestsIsFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.data.repository.autotime.enabled=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context, ExampleAnnotatedRepository.class);\n\t\t\t\tCollection<Meter> meters = registry.get(\"spring.data.repository.invocations\").meters();\n\t\t\t\tassertThat(meters).hasSize(1);\n\t\t\t\tMeter meter = meters.iterator().next();\n\t\t\t\tassertThat(meter.getId().getTag(\"method\")).isEqualTo(\"count\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotTriggerEarlyInitializationThatPreventsMeterBindersFromBindingMeters() {\n\t\tthis.contextRunner.withUserConfiguration(MeterBinderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(MeterRegistry.class).find(\"binder.test\").counter())\n\t\t\t\t.isNotNull());\n\t}\n\n\tprivate MeterRegistry getInitializedMeterRegistry(AssertableApplicationContext context,\n\t\t\tClass<?> repositoryInterface) {\n\t\tMetricsRepositoryMethodInvocationListener listener = context\n\t\t\t.getBean(MetricsRepositoryMethodInvocationListener.class);\n\t\tReflectionUtils.doWithLocalMethods(repositoryInterface, (method) -> {\n\t\t\tRepositoryMethodInvocationResult result = mock(RepositoryMethodInvocationResult.class);\n\t\t\tgiven(result.getState()).willReturn(State.SUCCESS);\n\t\t\tRepositoryMethodInvocation invocation = new RepositoryMethodInvocation(repositoryInterface, method, result,\n\t\t\t\t\t10);\n\t\t\tlistener.afterInvocation(invocation);\n\t\t});\n\t\treturn context.getBean(MeterRegistry.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TagsProviderConfiguration {\n\n\t\t@Bean\n\t\tTestRepositoryTagsProvider tagsProvider() {\n\t\t\treturn new TestRepositoryTagsProvider();\n\t\t}\n\n\t}\n\n\tprivate static final class TestRepositoryTagsProvider implements RepositoryTagsProvider {\n\n\t\t@Override\n\t\tpublic Iterable<Tag> repositoryTags(RepositoryMethodInvocation invocation) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MeterBinderConfiguration {\n\n\t\t@Bean\n\t\tMeterBinder meterBinder() {\n\t\t\treturn (registry) -> registry.counter(\"binder.test\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsRepositoryMethodInvocationListenerConfiguration {\n\n\t\t@Bean\n\t\tMetricsRepositoryMethodInvocationListener metricsRepositoryMethodInvocationListener(\n\t\t\t\tObjectFactory<MeterRegistry> registry, RepositoryTagsProvider tagsProvider) {\n\t\t\treturn new TestMetricsRepositoryMethodInvocationListener(registry::getObject, tagsProvider);\n\t\t}\n\n\t}\n\n\tstatic class TestMetricsRepositoryMethodInvocationListener extends MetricsRepositoryMethodInvocationListener {\n\n\t\tTestMetricsRepositoryMethodInvocationListener(Supplier<MeterRegistry> registrySupplier,\n\t\t\t\tRepositoryTagsProvider tagsProvider) {\n\t\t\tsuper(registrySupplier, tagsProvider, \"test\", AutoTimer.DISABLED);\n\t\t}\n\n\t}\n\n\tinterface ExampleRepository extends Repository<Example, Long> {\n\n\t\tlong count();\n\n\t}\n\n\tinterface ExampleAnnotatedRepository extends Repository<Example, Long> {\n\n\t\t@Timed\n\t\tlong count();\n\n\t\tlong delete();\n\n\t}\n\n\tstatic class Example {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/autoconfigure/metrics/MetricsRepositoryMethodInvocationListenerBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.metrics;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.data.metrics.MetricsRepositoryMethodInvocationListener;\nimport org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;\nimport org.springframework.data.repository.core.support.RepositoryFactoryCustomizer;\nimport org.springframework.data.repository.core.support.RepositoryFactorySupport;\nimport org.springframework.util.function.SingletonSupplier;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetricsRepositoryMethodInvocationListenerBeanPostProcessor}.\n *\n * @author Phillip Webb\n */\nclass MetricsRepositoryMethodInvocationListenerBeanPostProcessorTests {\n\n\tprivate final MetricsRepositoryMethodInvocationListener listener = mock(\n\t\t\tMetricsRepositoryMethodInvocationListener.class);\n\n\tprivate final MetricsRepositoryMethodInvocationListenerBeanPostProcessor postProcessor = new MetricsRepositoryMethodInvocationListenerBeanPostProcessor(\n\t\t\tSingletonSupplier.of(this.listener));\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid postProcessBeforeInitializationWhenRepositoryFactoryBeanSupportAddsListener() {\n\t\tRepositoryFactoryBeanSupport bean = mock(RepositoryFactoryBeanSupport.class);\n\t\tObject result = this.postProcessor.postProcessBeforeInitialization(bean, \"name\");\n\t\tassertThat(result).isSameAs(bean);\n\t\tArgumentCaptor<RepositoryFactoryCustomizer> customizer = ArgumentCaptor\n\t\t\t.forClass(RepositoryFactoryCustomizer.class);\n\t\tthen(bean).should().addRepositoryFactoryCustomizer(customizer.capture());\n\t\tRepositoryFactorySupport repositoryFactory = mock(RepositoryFactorySupport.class);\n\t\tcustomizer.getValue().customize(repositoryFactory);\n\t\tthen(repositoryFactory).should().addInvocationListener(this.listener);\n\t}\n\n\t@Test\n\tvoid postProcessBeforeInitializationWhenOtherBeanDoesNothing() {\n\t\tObject bean = new Object();\n\t\tObject result = this.postProcessor.postProcessBeforeInitialization(bean, \"name\");\n\t\tassertThat(result).isSameAs(bean);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/autoconfigure/web/DataWebAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.web.PageableHandlerMethodArgumentResolver;\nimport org.springframework.data.web.SortHandlerMethodArgumentResolver;\nimport org.springframework.data.web.config.EnableSpringDataWebSupport.PageSerializationMode;\nimport org.springframework.data.web.config.SpringDataWebSettings;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataWebAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Yanming Zhou\n */\nclass DataWebAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataWebAutoConfiguration.class));\n\n\t@Test\n\tvoid webSupportIsAutoConfiguredInWebApplicationContexts() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PageableHandlerMethodArgumentResolver.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffInNonWebApplicationContexts() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(DataWebAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PageableHandlerMethodArgumentResolver.class));\n\t}\n\n\t@Test\n\tvoid customizePageable() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.web.pageable.page-parameter=p\",\n\t\t\t\t\t\"spring.data.web.pageable.size-parameter=s\", \"spring.data.web.pageable.default-page-size=10\",\n\t\t\t\t\t\"spring.data.web.pageable.prefix=abc\", \"spring.data.web.pageable.qualifier-delimiter=__\",\n\t\t\t\t\t\"spring.data.web.pageable.max-page-size=100\", \"spring.data.web.pageable.serialization-mode=VIA_DTO\",\n\t\t\t\t\t\"spring.data.web.pageable.one-indexed-parameters=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tPageableHandlerMethodArgumentResolver argumentResolver = context\n\t\t\t\t\t.getBean(PageableHandlerMethodArgumentResolver.class);\n\t\t\t\tSpringDataWebSettings springDataWebSettings = context.getBean(SpringDataWebSettings.class);\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"pageParameterName\", \"p\");\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"sizeParameterName\", \"s\");\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"oneIndexedParameters\", true);\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"prefix\", \"abc\");\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"qualifierDelimiter\", \"__\");\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"fallbackPageable\", PageRequest.of(0, 10));\n\t\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"maxPageSize\", 100);\n\t\t\t\tassertThat(springDataWebSettings.pageSerializationMode()).isEqualTo(PageSerializationMode.VIA_DTO);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultPageable() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tDataWebProperties.Pageable properties = new DataWebProperties().getPageable();\n\t\t\tPageableHandlerMethodArgumentResolver argumentResolver = context\n\t\t\t\t.getBean(PageableHandlerMethodArgumentResolver.class);\n\t\t\tSpringDataWebSettings springDataWebSettings = context.getBean(SpringDataWebSettings.class);\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"pageParameterName\",\n\t\t\t\t\tproperties.getPageParameter());\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"sizeParameterName\",\n\t\t\t\t\tproperties.getSizeParameter());\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"oneIndexedParameters\",\n\t\t\t\t\tproperties.isOneIndexedParameters());\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"prefix\", properties.getPrefix());\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"qualifierDelimiter\",\n\t\t\t\t\tproperties.getQualifierDelimiter());\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"fallbackPageable\",\n\t\t\t\t\tPageRequest.of(0, properties.getDefaultPageSize()));\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"maxPageSize\", properties.getMaxPageSize());\n\t\t\tassertThat(springDataWebSettings.pageSerializationMode()).isEqualTo(properties.getSerializationMode());\n\t\t});\n\t}\n\n\t@Test\n\tvoid customizeSort() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.web.sort.sort-parameter=s\").run((context) -> {\n\t\t\tSortHandlerMethodArgumentResolver argumentResolver = context\n\t\t\t\t.getBean(SortHandlerMethodArgumentResolver.class);\n\t\t\tassertThat(argumentResolver).hasFieldOrPropertyWithValue(\"sortParameter\", \"s\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customizePageSerializationModeViaConfigProps() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.web.pageable.serialization-mode=VIA_DTO\").run((context) -> {\n\t\t\tSpringDataWebSettings springDataWebSettings = context.getBean(SpringDataWebSettings.class);\n\t\t\tassertThat(springDataWebSettings.pageSerializationMode()).isEqualTo(PageSerializationMode.VIA_DTO);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customizePageSerializationModeViaCustomBean() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customSpringDataWebSettings\", SpringDataWebSettings.class,\n\t\t\t\t\t() -> new SpringDataWebSettings(PageSerializationMode.VIA_DTO))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"springDataWebSettings\");\n\t\t\t\tSpringDataWebSettings springDataWebSettings = context.getBean(SpringDataWebSettings.class);\n\t\t\t\tassertThat(springDataWebSettings.pageSerializationMode()).isEqualTo(PageSerializationMode.VIA_DTO);\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/autoconfigure/web/DataWebWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.autoconfigure.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.data.autoconfigure.web.DataWebWebMvcTestIntegrationTests.PageableController;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring Data Web and {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\n@Import(PageableController.class)\nclass DataWebWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldSupportPageable() {\n\t\tassertThat(this.mvc.get().uri(\"/paged\").param(\"page\", \"2\").param(\"size\", \"42\")).hasStatusOk()\n\t\t\t.hasBodyTextEqualTo(\"2:42\");\n\t}\n\n\t@RestController\n\t@SpringBootConfiguration\n\tstatic class PageableController {\n\n\t\t@GetMapping(\"/paged\")\n\t\tString paged(Pageable pageable) {\n\t\t\treturn String.format(\"%s:%s\", pageable.getPageNumber(), pageable.getPageSize());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.domain.city;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\n\npublic class City {\n\n\t@Id\n\tprivate @Nullable Long id;\n\n\tprivate String name;\n\n\tprivate String country;\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.domain.city;\n\nimport org.springframework.data.repository.CrudRepository;\n\npublic interface CityRepository extends CrudRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/metrics/DefaultRepositoryTagsProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\n\nimport io.micrometer.core.instrument.Tag;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.data.repository.Repository;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult.State;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultRepositoryTagsProvider}.\n *\n * @author Phillip Webb\n */\nclass DefaultRepositoryTagsProviderTests {\n\n\tprivate final DefaultRepositoryTagsProvider provider = new DefaultRepositoryTagsProvider();\n\n\t@Test\n\tvoid repositoryTagsIncludesRepository() {\n\t\tRepositoryMethodInvocation invocation = createInvocation();\n\t\tIterable<Tag> tags = this.provider.repositoryTags(invocation);\n\t\tassertThat(tags).contains(Tag.of(\"repository\", \"ExampleRepository\"));\n\t}\n\n\t@Test\n\tvoid repositoryTagsIncludesMethod() {\n\t\tRepositoryMethodInvocation invocation = createInvocation();\n\t\tIterable<Tag> tags = this.provider.repositoryTags(invocation);\n\t\tassertThat(tags).contains(Tag.of(\"method\", \"findById\"));\n\t}\n\n\t@Test\n\tvoid repositoryTagsIncludesState() {\n\t\tRepositoryMethodInvocation invocation = createInvocation();\n\t\tIterable<Tag> tags = this.provider.repositoryTags(invocation);\n\t\tassertThat(tags).contains(Tag.of(\"state\", \"SUCCESS\"));\n\t}\n\n\t@Test\n\tvoid repositoryTagsIncludesException() {\n\t\tRepositoryMethodInvocation invocation = createInvocation(new IOException());\n\t\tIterable<Tag> tags = this.provider.repositoryTags(invocation);\n\t\tassertThat(tags).contains(Tag.of(\"exception\", \"IOException\"));\n\t}\n\n\t@Test\n\tvoid repositoryTagsWhenNoExceptionIncludesExceptionTagWithNone() {\n\t\tRepositoryMethodInvocation invocation = createInvocation();\n\t\tIterable<Tag> tags = this.provider.repositoryTags(invocation);\n\t\tassertThat(tags).contains(Tag.of(\"exception\", \"None\"));\n\t}\n\n\tprivate RepositoryMethodInvocation createInvocation() {\n\t\treturn createInvocation(null);\n\t}\n\n\tprivate RepositoryMethodInvocation createInvocation(@Nullable Throwable error) {\n\t\tClass<?> repositoryInterface = ExampleRepository.class;\n\t\tMethod method = ReflectionUtils.findMethod(repositoryInterface, \"findById\", long.class);\n\t\tassertThat(method).isNotNull();\n\t\tRepositoryMethodInvocationResult result = mock(RepositoryMethodInvocationResult.class);\n\t\tgiven(result.getState()).willReturn((error != null) ? State.ERROR : State.SUCCESS);\n\t\tgiven(result.getError()).willReturn(error);\n\t\treturn new RepositoryMethodInvocation(repositoryInterface, method, result, 0);\n\t}\n\n\tinterface ExampleRepository extends Repository<Example, Long> {\n\n\t\tExample findById(long id);\n\n\t}\n\n\tstatic class Example {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/metrics/MetricsRepositoryMethodInvocationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.lang.reflect.Method;\n\nimport io.micrometer.core.annotation.Timed;\nimport io.micrometer.core.instrument.MockClock;\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.data.repository.Repository;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocation;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult;\nimport org.springframework.data.repository.core.support.RepositoryMethodInvocationListener.RepositoryMethodInvocationResult.State;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetricsRepositoryMethodInvocationListener}.\n *\n * @author Phillip Webb\n */\nclass MetricsRepositoryMethodInvocationListenerTests {\n\n\tprivate static final String REQUEST_METRICS_NAME = \"repository.invocations\";\n\n\tprivate SimpleMeterRegistry registry;\n\n\tprivate MetricsRepositoryMethodInvocationListener listener;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockClock clock = new MockClock();\n\t\tthis.registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, clock);\n\t\tthis.listener = new MetricsRepositoryMethodInvocationListener(() -> this.registry,\n\t\t\t\tnew DefaultRepositoryTagsProvider(), REQUEST_METRICS_NAME, AutoTimer.ENABLED);\n\t}\n\n\t@Test\n\tvoid afterInvocationWhenNoTimerAnnotationsAndNoAutoTimerDoesNothing() {\n\t\tthis.listener = new MetricsRepositoryMethodInvocationListener(() -> this.registry,\n\t\t\t\tnew DefaultRepositoryTagsProvider(), REQUEST_METRICS_NAME, null);\n\t\tthis.listener.afterInvocation(createInvocation(NoAnnotationsRepository.class));\n\t\tassertThat(this.registry.find(REQUEST_METRICS_NAME).timers()).isEmpty();\n\t}\n\n\t@Test\n\tvoid afterInvocationWhenTimedMethodRecordsMetrics() {\n\t\tthis.listener.afterInvocation(createInvocation(TimedMethodRepository.class));\n\t\tassertMetricsContainsTag(\"state\", \"SUCCESS\");\n\t\tassertMetricsContainsTag(\"tag1\", \"value1\");\n\t}\n\n\t@Test\n\tvoid afterInvocationWhenTimedClassRecordsMetrics() {\n\t\tthis.listener.afterInvocation(createInvocation(TimedClassRepository.class));\n\t\tassertMetricsContainsTag(\"state\", \"SUCCESS\");\n\t\tassertMetricsContainsTag(\"taga\", \"valuea\");\n\t}\n\n\t@Test\n\tvoid afterInvocationWhenAutoTimedRecordsMetrics() {\n\t\tthis.listener.afterInvocation(createInvocation(NoAnnotationsRepository.class));\n\t\tassertMetricsContainsTag(\"state\", \"SUCCESS\");\n\t}\n\n\tprivate void assertMetricsContainsTag(String tagKey, String tagValue) {\n\t\tassertThat(this.registry.get(REQUEST_METRICS_NAME).tag(tagKey, tagValue).timer().count()).isOne();\n\t}\n\n\tprivate RepositoryMethodInvocation createInvocation(Class<?> repositoryInterface) {\n\t\tMethod method = ReflectionUtils.findMethod(repositoryInterface, \"findById\", long.class);\n\t\tassertThat(method).isNotNull();\n\t\tRepositoryMethodInvocationResult result = mock(RepositoryMethodInvocationResult.class);\n\t\tgiven(result.getState()).willReturn(State.SUCCESS);\n\t\treturn new RepositoryMethodInvocation(repositoryInterface, method, result, 0);\n\t}\n\n\tinterface NoAnnotationsRepository extends Repository<Example, Long> {\n\n\t\tExample findById(long id);\n\n\t}\n\n\tinterface TimedMethodRepository extends Repository<Example, Long> {\n\n\t\t@Timed(extraTags = { \"tag1\", \"value1\" })\n\t\tExample findById(long id);\n\n\t}\n\n\t@Timed(extraTags = { \"taga\", \"valuea\" })\n\tinterface TimedClassRepository extends Repository<Example, Long> {\n\n\t\tExample findById(long id);\n\n\t}\n\n\tstatic class Example {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-commons/src/test/java/org/springframework/boot/data/metrics/TimedAnnotationsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.metrics;\n\nimport java.lang.reflect.Method;\nimport java.util.Set;\n\nimport io.micrometer.core.annotation.Timed;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TimedAnnotations}.\n *\n * @author Phillip Webb\n */\nclass TimedAnnotationsTests {\n\n\t@Test\n\tvoid getWhenNoneReturnsEmptySet() {\n\t\tObject bean = new None();\n\t\tMethod method = ReflectionUtils.findMethod(bean.getClass(), \"handle\");\n\t\tassertThat(method).isNotNull();\n\t\tSet<Timed> annotations = TimedAnnotations.get(method, bean.getClass());\n\t\tassertThat(annotations).isEmpty();\n\t}\n\n\t@Test\n\tvoid getWhenOnMethodReturnsMethodAnnotations() {\n\t\tObject bean = new OnMethod();\n\t\tMethod method = ReflectionUtils.findMethod(bean.getClass(), \"handle\");\n\t\tassertThat(method).isNotNull();\n\t\tSet<Timed> annotations = TimedAnnotations.get(method, bean.getClass());\n\t\tassertThat(annotations).extracting(Timed::value).containsOnly(\"y\", \"z\");\n\t}\n\n\t@Test\n\tvoid getWhenNonOnMethodReturnsBeanAnnotations() {\n\t\tObject bean = new OnBean();\n\t\tMethod method = ReflectionUtils.findMethod(bean.getClass(), \"handle\");\n\t\tassertThat(method).isNotNull();\n\t\tSet<Timed> annotations = TimedAnnotations.get(method, bean.getClass());\n\t\tassertThat(annotations).extracting(Timed::value).containsOnly(\"y\", \"z\");\n\t}\n\n\tstatic class None {\n\n\t\tvoid handle() {\n\t\t}\n\n\t}\n\n\t@Timed(\"x\")\n\tstatic class OnMethod {\n\n\t\t@Timed(\"y\")\n\t\t@Timed(\"z\")\n\t\tvoid handle() {\n\t\t}\n\n\t}\n\n\t@Timed(\"y\")\n\t@Timed(\"z\")\n\tstatic class OnBean {\n\n\t\tvoid handle() {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data Couchbase\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-couchbase\"))\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.data:spring-data-couchbase\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(project(\":module:spring-boot-validation\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/CouchbaseClientFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport com.couchbase.client.java.Cluster;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.CouchbaseClientFactory;\nimport org.springframework.data.couchbase.SimpleCouchbaseClientFactory;\n\n/**\n * Configuration for a {@link CouchbaseClientFactory}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnSingleCandidate(Cluster.class)\n@ConditionalOnProperty(\"spring.data.couchbase.bucket-name\")\nclass CouchbaseClientFactoryConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCouchbaseClientFactory couchbaseClientFactory(Cluster cluster, DataCouchbaseProperties properties) {\n\t\treturn new SimpleCouchbaseClientFactory(cluster, properties.getBucketName(), properties.getScopeName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/CouchbaseClientFactoryDependentConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.CouchbaseClientFactory;\nimport org.springframework.data.couchbase.config.BeanNames;\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\nimport org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;\nimport org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;\n\n/**\n * Configuration for Couchbase-related beans that depend on a\n * {@link CouchbaseClientFactory}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)\nclass CouchbaseClientFactoryDependentConfiguration {\n\n\t@Bean(name = BeanNames.COUCHBASE_TEMPLATE)\n\t@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE)\n\tCouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,\n\t\t\tMappingCouchbaseConverter mappingCouchbaseConverter) {\n\t\treturn new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);\n\t}\n\n\t@Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)\n\t@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING)\n\tRepositoryOperationsMapping couchbaseRepositoryOperationsMapping(CouchbaseTemplate couchbaseTemplate) {\n\t\treturn new RepositoryOperationsMapping(couchbaseTemplate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport com.couchbase.client.java.Bucket;\nimport jakarta.validation.Validator;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;\nimport org.springframework.data.couchbase.repository.CouchbaseRepository;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase support.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = CouchbaseAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\")\n@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class })\n@EnableConfigurationProperties(DataCouchbaseProperties.class)\n@Import({ DataCouchbaseConfiguration.class, CouchbaseClientFactoryConfiguration.class,\n\t\tCouchbaseClientFactoryDependentConfiguration.class })\npublic final class DataCouchbaseAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Validator.class)\n\tstatic class ValidationConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnSingleCandidate(Validator.class)\n\t\tValidatingCouchbaseEventListener validationEventListener(Validator validator) {\n\t\t\treturn new ValidatingCouchbaseEventListener(validator);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.config.BeanNames;\nimport org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;\nimport org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;\nimport org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService;\nimport org.springframework.data.couchbase.core.convert.translation.TranslationService;\nimport org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;\nimport org.springframework.data.couchbase.core.mapping.Document;\nimport org.springframework.data.mapping.model.FieldNamingStrategy;\n\n/**\n * Configuration for Spring Data's couchbase support.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\nclass DataCouchbaseConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMappingCouchbaseConverter couchbaseMappingConverter(DataCouchbaseProperties properties,\n\t\t\tCouchbaseMappingContext couchbaseMappingContext, CouchbaseCustomConversions couchbaseCustomConversions) {\n\t\tMappingCouchbaseConverter converter = new MappingCouchbaseConverter(couchbaseMappingContext,\n\t\t\t\tproperties.getTypeKey());\n\t\tconverter.setCustomConversions(couchbaseCustomConversions);\n\t\treturn converter;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tTranslationService couchbaseTranslationService() {\n\t\treturn new JacksonTranslationService();\n\t}\n\n\t@Bean(name = BeanNames.COUCHBASE_MAPPING_CONTEXT)\n\t@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_MAPPING_CONTEXT)\n\tCouchbaseMappingContext couchbaseMappingContext(DataCouchbaseProperties properties,\n\t\t\tApplicationContext applicationContext, CouchbaseCustomConversions couchbaseCustomConversions)\n\t\t\tthrows ClassNotFoundException {\n\t\tCouchbaseMappingContext mappingContext = new CouchbaseMappingContext();\n\t\tmappingContext.setInitialEntitySet(new EntityScanner(applicationContext).scan(Document.class));\n\t\tmappingContext.setSimpleTypeHolder(couchbaseCustomConversions.getSimpleTypeHolder());\n\t\tClass<?> fieldNamingStrategy = properties.getFieldNamingStrategy();\n\t\tif (fieldNamingStrategy != null) {\n\t\t\tmappingContext\n\t\t\t\t.setFieldNamingStrategy((FieldNamingStrategy) BeanUtils.instantiateClass(fieldNamingStrategy));\n\t\t}\n\t\tmappingContext.setAutoIndexCreation(properties.isAutoIndex());\n\t\treturn mappingContext;\n\t}\n\n\t@Bean(name = BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)\n\t@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)\n\tCouchbaseCustomConversions couchbaseCustomConversions() {\n\t\treturn new CouchbaseCustomConversions(Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Spring Data Couchbase.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.couchbase\")\npublic class DataCouchbaseProperties {\n\n\t/**\n\t * Automatically create views and indexes. Use the meta-data provided by\n\t * \"@ViewIndexed\", \"@N1qlPrimaryIndexed\" and \"@N1qlSecondaryIndexed\".\n\t */\n\tprivate boolean autoIndex;\n\n\t/**\n\t * Name of the bucket to connect to.\n\t */\n\tprivate @Nullable String bucketName;\n\n\t/**\n\t * Name of the scope used for all collection access.\n\t */\n\tprivate @Nullable String scopeName;\n\n\t/**\n\t * Fully qualified name of the FieldNamingStrategy to use.\n\t */\n\tprivate @Nullable Class<?> fieldNamingStrategy;\n\n\t/**\n\t * Name of the field that stores the type information for complex types when using\n\t * \"MappingCouchbaseConverter\".\n\t */\n\tprivate String typeKey = \"_class\";\n\n\tpublic boolean isAutoIndex() {\n\t\treturn this.autoIndex;\n\t}\n\n\tpublic void setAutoIndex(boolean autoIndex) {\n\t\tthis.autoIndex = autoIndex;\n\t}\n\n\tpublic @Nullable String getBucketName() {\n\t\treturn this.bucketName;\n\t}\n\n\tpublic void setBucketName(@Nullable String bucketName) {\n\t\tthis.bucketName = bucketName;\n\t}\n\n\tpublic @Nullable String getScopeName() {\n\t\treturn this.scopeName;\n\t}\n\n\tpublic void setScopeName(@Nullable String scopeName) {\n\t\tthis.scopeName = scopeName;\n\t}\n\n\tpublic @Nullable Class<?> getFieldNamingStrategy() {\n\t\treturn this.fieldNamingStrategy;\n\t}\n\n\tpublic void setFieldNamingStrategy(@Nullable Class<?> fieldNamingStrategy) {\n\t\tthis.fieldNamingStrategy = fieldNamingStrategy;\n\t}\n\n\tpublic String getTypeKey() {\n\t\treturn this.typeKey;\n\t}\n\n\tpublic void setTypeKey(String typeKey) {\n\t\tthis.typeKey = typeKey;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport com.couchbase.client.java.Cluster;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Reactive Couchbase\n * support.\n *\n * @author Alex Derkach\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataCouchbaseAutoConfiguration.class)\n@ConditionalOnClass({ Cluster.class, ReactiveCouchbaseRepository.class, Flux.class })\n@Import(DataCouchbaseReactiveConfiguration.class)\npublic final class DataCouchbaseReactiveAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.CouchbaseClientFactory;\nimport org.springframework.data.couchbase.config.BeanNames;\nimport org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;\nimport org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;\nimport org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;\n\n/**\n * Configuration for Spring Data's couchbase reactive support.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnSingleCandidate(CouchbaseClientFactory.class)\nclass DataCouchbaseReactiveConfiguration {\n\n\t@Bean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE)\n\t@ConditionalOnMissingBean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE)\n\tReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory,\n\t\t\tMappingCouchbaseConverter mappingCouchbaseConverter) {\n\t\treturn new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter);\n\t}\n\n\t@Bean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING)\n\t@ConditionalOnMissingBean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING)\n\tReactiveRepositoryOperationsMapping reactiveCouchbaseRepositoryOperationsMapping(\n\t\t\tReactiveCouchbaseTemplate reactiveCouchbaseTemplate) {\n\t\treturn new ReactiveRepositoryOperationsMapping(reactiveCouchbaseTemplate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport com.couchbase.client.java.Cluster;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;\nimport org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;\nimport org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase Reactive\n * Repositories.\n *\n * @author Alex Derkach\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataCouchbaseReactiveAutoConfiguration.class)\n@ConditionalOnClass({ Cluster.class, ReactiveCouchbaseRepository.class, Flux.class })\n@ConditionalOnRepositoryType(store = \"couchbase\", type = RepositoryType.REACTIVE)\n@ConditionalOnBean(ReactiveRepositoryOperationsMapping.class)\n@ConditionalOnMissingBean(ReactiveCouchbaseRepositoryFactoryBean.class)\n@Import(DataCouchbaseReactiveRepositoriesRegistrar.class)\npublic final class DataCouchbaseReactiveRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories;\nimport org.springframework.data.couchbase.repository.config.ReactiveCouchbaseRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Couchbase\n * Reactive Repositories.\n *\n * @author Alex Derkach\n */\nclass DataCouchbaseReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableReactiveCouchbaseRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableReactiveCouchbaseRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new ReactiveCouchbaseRepositoryConfigurationExtension();\n\t}\n\n\t@EnableReactiveCouchbaseRepositories\n\tprivate static final class EnableReactiveCouchbaseRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport com.couchbase.client.java.Bucket;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.couchbase.repository.CouchbaseRepository;\nimport org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;\nimport org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase\n * Repositories.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class })\n@ConditionalOnBean(RepositoryOperationsMapping.class)\n@ConditionalOnRepositoryType(store = \"couchbase\", type = RepositoryType.IMPERATIVE)\n@ConditionalOnMissingBean(CouchbaseRepositoryFactoryBean.class)\n@Import(DataCouchbaseRepositoriesRegistrar.class)\npublic final class DataCouchbaseRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension;\nimport org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Couchbase\n * Repositories.\n *\n * @author Eddú Meléndez\n */\nclass DataCouchbaseRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableCouchbaseRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableCouchbaseRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new CouchbaseRepositoryConfigurationExtension();\n\t}\n\n\t@EnableCouchbaseRepositories\n\tprivate static final class EnableCouchbaseRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/java/org/springframework/boot/data/couchbase/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Couchbase.\n */\n@NullMarked\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.couchbase.consistency\",\n      \"type\": \"org.springframework.data.couchbase.core.query.Consistency\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.couchbase.repositories.type\",\n      \"type\": \"org.springframework.boot.autoconfigure.data.RepositoryType\",\n      \"description\": \"Type of Couchbase repositories to enable.\",\n      \"defaultValue\": \"auto\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseReactiveAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/CouchbaseMockConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.couchbase.CouchbaseClientFactory;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test configuration that mocks access to Couchbase.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\nclass CouchbaseMockConfiguration {\n\n\t@Bean\n\tCouchbaseClientFactory couchbaseClientFactory() {\n\t\treturn mock(CouchbaseClientFactory.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties;\nimport org.springframework.boot.data.couchbase.domain.city.City;\nimport org.springframework.boot.persistence.autoconfigure.EntityScan;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.data.couchbase.config.BeanNames;\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\nimport org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;\nimport org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMapper;\nimport org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;\nimport org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;\nimport org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCouchbaseAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass DataCouchbaseAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class, CouchbaseAutoConfiguration.class,\n\t\t\t\tDataCouchbaseAutoConfiguration.class));\n\n\t@Test\n\tvoid disabledIfCouchbaseIsNotConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(CouchbaseTemplate.class));\n\t}\n\n\t@Test\n\tvoid validatorIsPresent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class));\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetInitialEntitySet() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tCouchbaseMappingContext mappingContext = context.getBean(CouchbaseMappingContext.class);\n\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\tassertThat(managedTypes.toList()).containsOnly(City.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid typeKeyDefault() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseMockConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(MappingCouchbaseConverter.class).getTypeKey())\n\t\t\t\t.isEqualTo(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY));\n\t}\n\n\t@Test\n\tvoid typeKeyCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CouchbaseMockConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.couchbase.type-key=_custom\")\n\t\t\t.run((context) -> assertThat(context.getBean(MappingCouchbaseConverter.class).getTypeKey())\n\t\t\t\t.isEqualTo(\"_custom\"));\n\t}\n\n\t@Test\n\tvoid customConversions() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConversionsConfig.class).run((context) -> {\n\t\t\tCouchbaseTemplate template = context.getBean(CouchbaseTemplate.class);\n\t\t\tassertThat(\n\t\t\t\t\ttemplate.getConverter().getConversionService().canConvert(CouchbaseProperties.class, Boolean.class))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class CustomConversionsConfig {\n\n\t\t@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)\n\t\tCouchbaseCustomConversions myCustomConversions() {\n\t\t\treturn new CouchbaseCustomConversions(Collections.singletonList(new MyConverter()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(basePackageClasses = City.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class EntityScanConfig {\n\n\t}\n\n\tstatic class MyConverter implements Converter<CouchbaseProperties, Boolean> {\n\n\t\t@Override\n\t\tpublic Boolean convert(CouchbaseProperties value) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbasePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCouchbaseProperties}.\n *\n * @author Stephane Nicoll\n */\nclass DataCouchbasePropertiesTests {\n\n\t@Test\n\tvoid typeKeyHasConsistentDefault() {\n\t\tassertThat(new DataCouchbaseProperties().getTypeKey()).isEqualTo(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.data.couchbase.domain.city.CityRepository;\nimport org.springframework.boot.data.couchbase.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;\nimport org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCouchbaseRepositoriesAutoConfiguration} and\n * {@link DataCouchbaseReactiveRepositoriesAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass DataCouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests {\n\n\t@Test\n\tvoid shouldCreateInstancesForReactiveAndImperativeRepositories() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withUserConfiguration(ImperativeAndReactiveConfiguration.class, BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CityRepository.class)\n\t\t\t\t.hasSingleBean(ReactiveCityRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(CouchbaseAutoConfiguration.class)\n\t@EnableCouchbaseRepositories(basePackageClasses = CityRepository.class)\n\t@EnableReactiveCouchbaseRepositories(basePackageClasses = ReactiveCityRepository.class)\n\tstatic class ImperativeAndReactiveConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ CouchbaseMockConfiguration.class, Registrar.class })\n\tstatic class BaseConfiguration {\n\n\t}\n\n\tstatic class Registrar implements ImportSelector {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\tList<String> names = new ArrayList<>();\n\t\t\tfor (Class<?> type : new Class<?>[] { CouchbaseAutoConfiguration.class,\n\t\t\t\t\tDataCouchbaseAutoConfiguration.class, DataCouchbaseRepositoriesAutoConfiguration.class,\n\t\t\t\t\tDataCouchbaseReactiveAutoConfiguration.class,\n\t\t\t\t\tDataCouchbaseReactiveRepositoriesAutoConfiguration.class }) {\n\t\t\t\tnames.add(type.getName());\n\t\t\t}\n\t\t\treturn StringUtils.toStringArray(names);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseProperties;\nimport org.springframework.boot.data.couchbase.domain.city.City;\nimport org.springframework.boot.persistence.autoconfigure.EntityScan;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.data.couchbase.config.BeanNames;\nimport org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;\nimport org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;\nimport org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;\nimport org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCouchbaseReactiveAutoConfiguration}.\n *\n * @author Alex Derkach\n * @author Stephane Nicoll\n */\nclass DataCouchbaseReactiveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class, CouchbaseAutoConfiguration.class,\n\t\t\t\tDataCouchbaseAutoConfiguration.class, DataCouchbaseReactiveAutoConfiguration.class));\n\n\t@Test\n\tvoid disabledIfCouchbaseIsNotConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCouchbaseTemplate.class));\n\t}\n\n\t@Test\n\tvoid validatorIsPresent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class));\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetInitialEntitySet() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tCouchbaseMappingContext mappingContext = context.getBean(CouchbaseMappingContext.class);\n\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\tassertThat(managedTypes.toList()).containsOnly(City.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customConversions() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConversionsConfig.class).run((context) -> {\n\t\t\tReactiveCouchbaseTemplate template = context.getBean(ReactiveCouchbaseTemplate.class);\n\t\t\tassertThat(\n\t\t\t\t\ttemplate.getConverter().getConversionService().canConvert(CouchbaseProperties.class, Boolean.class))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class CustomConversionsConfig {\n\n\t\t@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)\n\t\tCouchbaseCustomConversions myCustomConversions() {\n\t\t\treturn new CouchbaseCustomConversions(Collections.singletonList(new MyConverter()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(basePackageClasses = City.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class EntityScanConfig {\n\n\t}\n\n\tstatic class MyConverter implements Converter<CouchbaseProperties, Boolean> {\n\n\t\t@Override\n\t\tpublic Boolean convert(CouchbaseProperties value) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseReactiveRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.data.couchbase.domain.city.City;\nimport org.springframework.boot.data.couchbase.domain.city.CityRepository;\nimport org.springframework.boot.data.couchbase.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.data.couchbase.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCouchbaseReactiveRepositoriesAutoConfiguration}.\n *\n * @author Alex Derkach\n * @author Stephane Nicoll\n */\nclass DataCouchbaseReactiveRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class, DataCouchbaseAutoConfiguration.class,\n\t\t\t\tDataCouchbaseRepositoriesAutoConfiguration.class, DataCouchbaseReactiveAutoConfiguration.class,\n\t\t\t\tDataCouchbaseReactiveRepositoriesAutoConfiguration.class));\n\n\t@Test\n\tvoid couchbaseNotAvailable() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid defaultRepository() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid imperativeRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.couchbase.repositories.type=imperative\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid disabledRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.couchbase.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid noRepositoryAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(NoRepositoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class NoRepositoryConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(DataCouchbaseReactiveRepositoriesAutoConfigurationTests.class)\n\t@EnableCouchbaseRepositories(basePackageClasses = CityRepository.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/autoconfigure/DataCouchbaseRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration;\nimport org.springframework.boot.data.couchbase.domain.city.City;\nimport org.springframework.boot.data.couchbase.domain.city.CityRepository;\nimport org.springframework.boot.data.couchbase.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataCouchbaseRepositoriesAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\nclass DataCouchbaseRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class, DataCouchbaseAutoConfiguration.class,\n\t\t\t\tDataCouchbaseRepositoriesAutoConfiguration.class));\n\n\t@Test\n\tvoid couchbaseNotAvailable() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid defaultRepository() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid reactiveRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.couchbase.repositories.type=reactive\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid disabledRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.couchbase.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid noRepositoryAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(NoRepositoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class CouchbaseNotAvailableConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\t@Import(CouchbaseMockConfiguration.class)\n\tstatic class NoRepositoryConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.domain.city;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.couchbase.core.mapping.Document;\nimport org.springframework.data.couchbase.core.mapping.Field;\n\n@Document\npublic class City {\n\n\t@Id\n\tprivate @Nullable String id;\n\n\t@Field\n\tprivate @Nullable String name;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.domain.city;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/domain/city/ReactiveCityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.domain.city;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface ReactiveCityRepository extends Repository<City, Long> {\n\n\tMono<City> save(City city);\n\n\tMono<City> findById(Long id);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.couchbase.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/domain/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.domain.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase/src/test/java/org/springframework/boot/data/couchbase/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.couchbase.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data Couchbase Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-couchbase\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-couchbase\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\tdockerTestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.couchbase.CouchbaseService;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration test for {@link DataCouchbaseTest @DataCouchbaseTest}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataCouchbaseTest(properties = { \"spring.couchbase.env.timeouts.connect=2m\",\n\t\t\"spring.couchbase.env.timeouts.key-value=1m\", \"spring.data.couchbase.bucket-name=cbbucket\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass DataCouchbaseTestIntegrationTests {\n\n\tprivate static final String BUCKET_NAME = \"cbbucket\";\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CouchbaseContainer couchbase = TestImage.container(CouchbaseContainer.class)\n\t\t.withEnabledServices(CouchbaseService.KV, CouchbaseService.INDEX, CouchbaseService.QUERY)\n\t\t.withBucket(new BucketDefinition(BUCKET_NAME));\n\n\t@Autowired\n\tprivate CouchbaseTemplate couchbaseTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument document = new ExampleDocument();\n\t\tdocument.setText(\"Look, new @DataCouchbaseTest!\");\n\t\tdocument = this.exampleRepository.save(document);\n\t\tassertThat(document.getId()).isNotNull();\n\t\tassertThat(this.couchbaseTemplate.getBucketName()).isEqualTo(BUCKET_NAME);\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTestReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.couchbase.CouchbaseService;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Sample tests for {@link DataCouchbaseTest @DataCouchbaseTest} using reactive\n * repositories.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataCouchbaseTest(properties = { \"spring.data.couchbase.bucket-name=cbbucket\",\n\t\t\"spring.couchbase.env.timeouts.connect=2m\", \"spring.couchbase.env.timeouts.key-value=1m\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass DataCouchbaseTestReactiveIntegrationTests {\n\n\tprivate static final String BUCKET_NAME = \"cbbucket\";\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CouchbaseContainer couchbase = TestImage.container(CouchbaseContainer.class)\n\t\t.withEnabledServices(CouchbaseService.KV, CouchbaseService.INDEX, CouchbaseService.QUERY)\n\t\t.withBucket(new BucketDefinition(BUCKET_NAME));\n\n\t@Autowired\n\tprivate ReactiveCouchbaseTemplate couchbaseTemplate;\n\n\t@Autowired\n\tprivate ExampleReactiveRepository exampleReactiveRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument document = new ExampleDocument();\n\t\tdocument.setText(\"Look, new @DataCouchbaseTest!\");\n\t\tdocument = this.exampleReactiveRepository.save(document).block(Duration.ofSeconds(30));\n\t\tassertThat(document).isNotNull();\n\t\tassertThat(document.getId()).isNotNull();\n\t\tassertThat(this.couchbaseTemplate.getBucketName()).isEqualTo(BUCKET_NAME);\n\t\tthis.exampleReactiveRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.couchbase.CouchbaseService;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for\n * {@link DataCouchbaseTest @DataCouchbaseTest}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataCouchbaseTest(includeFilters = @Filter(Service.class),\n\t\tproperties = { \"spring.data.couchbase.bucket-name=cbbucket\", \"spring.couchbase.env.timeouts.connect=2m\",\n\t\t\t\t\"spring.couchbase.env.timeouts.key-value=1m\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass DataCouchbaseTestWithIncludeFilterIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final CouchbaseContainer couchbase = TestImage.container(CouchbaseContainer.class)\n\t\t.withEnabledServices(CouchbaseService.KV, CouchbaseService.INDEX, CouchbaseService.QUERY)\n\t\t.withBucket(new BucketDefinition(\"cbbucket\"));\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tExampleDocument document = new ExampleDocument();\n\t\tdocument.setText(\"Look, new @DataCouchbaseTest!\");\n\t\tdocument = this.exampleRepository.save(document);\n\t\tassertThat(this.service.findById(document.getId())).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/ExampleDocument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.couchbase.core.mapping.Document;\nimport org.springframework.data.couchbase.core.mapping.id.GeneratedValue;\nimport org.springframework.data.couchbase.core.mapping.id.GenerationStrategy;\n\n/**\n * Example document used with {@link DataCouchbaseTest @DataCouchbaseTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Document\npublic class ExampleDocument {\n\n\t@Id\n\t@GeneratedValue(strategy = GenerationStrategy.UNIQUE)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String id;\n\n\tprivate @Nullable String text;\n\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/ExampleReactiveRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;\n\n/**\n * Example reactive repository used with {@link DataCouchbaseTest @DataCouchbaseTest}\n * tests.\n *\n * @author Eddú Meléndez\n */\ninterface ExampleReactiveRepository extends ReactiveCouchbaseRepository<ExampleDocument, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.springframework.data.couchbase.repository.CouchbaseRepository;\n\n/**\n * Example repository used with {@link DataCouchbaseTest @DataCouchbaseTest} tests.\n *\n * @author Eddú Meléndez\n */\ninterface ExampleRepository extends CouchbaseRepository<ExampleDocument, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/dockerTest/java/org/springframework/boot/data/couchbase/test/autoconfigure/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataCouchbaseTest @DataCouchbaseTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Service\npublic class ExampleService {\n\n\tprivate final CouchbaseTemplate couchbaseTemplate;\n\n\tpublic ExampleService(CouchbaseTemplate couchbaseTemplate) {\n\t\tthis.couchbaseTemplate = couchbaseTemplate;\n\t}\n\n\tpublic ExampleDocument findById(String id) {\n\t\treturn this.couchbaseTemplate.findById(ExampleDocument.class).one(id);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/main/java/org/springframework/boot/data/couchbase/test/autoconfigure/AutoConfigureDataCouchbase.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data Couchbase\n * tests. Most tests should consider using {@link DataCouchbaseTest @DataCouchbaseTest}\n * rather than using this annotation directly.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n * @see DataCouchbaseTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataCouchbase {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/main/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for a Data Couchbase test that focuses\n * <strong>only</strong> on Data Couchbase components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data\n * Couchbase tests. Similarly, component scanning is limited to Couchbase repositories and\n * entities ({@code @Document}).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataCouchbaseTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataCouchbaseTypeExcludeFilter.class)\n@AutoConfigureDataCouchbase\n@ImportAutoConfiguration\npublic @interface DataCouchbaseTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/main/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataCouchbaseTest @DataCouchbaseTest}\n * support.\n *\n * @author Eddú Meléndez\n */\nclass DataCouchbaseTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataCouchbaseTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/main/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataCouchbaseTest @DataCouchbaseaTest}.\n *\n * @author Eddú Meléndez\n */\nclass DataCouchbaseTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataCouchbaseTest> {\n\n\tDataCouchbaseTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/main/java/org/springframework/boot/data/couchbase/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data Couchbase tests.\n */\n@NullMarked\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/main/resources/META-INF/spring/org.springframework.boot.data.couchbase.test.autoconfigure.AutoConfigureDataCouchbase.imports",
    "content": "org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration\norg.springframework.boot.couchbase.autoconfigure.CouchbaseAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseReactiveAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.couchbase.autoconfigure.DataCouchbaseRepositoriesAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/test/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Application for testing of {@link DataCouchbaseTest @DataCouchbaseTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\nclass DataCouchbaseTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-couchbase-test/src/test/java/org/springframework/boot/data/couchbase/test/autoconfigure/DataCouchbaseTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.couchbase.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataCouchbaseTest#properties properties} attribute of\n * {@link DataCouchbaseTest @DataCouchbaseTest}.\n *\n * @author Eddú Meléndez\n */\n@DataCouchbaseTest(properties = \"spring.profiles.active=test\")\nclass DataCouchbaseTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataCouchbaseTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data Elasticsearch\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-elasticsearch\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.data:spring-data-elasticsearch\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-elasticsearch\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/dockerTest/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport java.util.Map;\n\nimport co.elastic.clients.elasticsearch.core.GetResponse;\nimport co.elastic.clients.elasticsearch.core.IndexResponse;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link DataElasticsearchAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,\n\t\t\t\tElasticsearchClientAutoConfiguration.class, DataElasticsearchAutoConfiguration.class));\n\n\t@Test\n\tvoid reactiveClientCanQueryElasticsearchNode() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.uris=\" + elasticsearch.getHttpHostAddress(),\n\t\t\t\t\t\"spring.elasticsearch.connection-timeout=120s\", \"spring.elasticsearch.socket-timeout=120s\")\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveElasticsearchClient client = context.getBean(ReactiveElasticsearchClient.class);\n\t\t\t\tMono<IndexResponse> index = client\n\t\t\t\t\t.index((b) -> b.index(\"foo\").id(\"1\").document(Map.of(\"a\", \"alpha\", \"b\", \"bravo\")));\n\t\t\t\tindex.block();\n\t\t\t\tMono<GetResponse<Object>> get = client.get((b) -> b.index(\"foo\").id(\"1\"), Object.class);\n\t\t\t\tGetResponse<Object> response = get.block();\n\t\t\t\tassertThat(response).isNotNull();\n\t\t\t\tassertThat(response.found()).isTrue();\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/dockerTest/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchReactiveRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.elasticsearch.domain.city.City;\nimport org.springframework.boot.data.elasticsearch.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.data.elasticsearch.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.config.EnableElasticsearchAuditing;\nimport org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataElasticsearchReactiveRepositoriesAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchReactiveRepositoriesAutoConfigurationTests {\n\n\t@Container\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class,\n\t\t\t\tElasticsearchRestClientAutoConfiguration.class,\n\t\t\t\tDataElasticsearchReactiveRepositoriesAutoConfiguration.class, DataElasticsearchAutoConfiguration.class))\n\t\t.withPropertyValues(\n\t\t\t\t\"spring.elasticsearch.uris=\" + elasticsearch.getHost() + \":\" + elasticsearch.getFirstMappedPort(),\n\t\t\t\t\"spring.elasticsearch.socket-timeout=30s\");\n\n\t@Test\n\tvoid backsOffWithoutReactor() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(Mono.class))\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(DataElasticsearchReactiveRepositoriesAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class)\n\t\t\t\t.hasSingleBean(ReactiveElasticsearchTemplate.class));\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchTemplate.class));\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid testAuditingConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(AuditingConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchTemplate.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableReactiveElasticsearchRepositories(basePackageClasses = ReactiveCityRepository.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableReactiveElasticsearchRepositories\n\t@EnableElasticsearchAuditing\n\tstatic class AuditingConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/dockerTest/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.elasticsearch.domain.city.City;\nimport org.springframework.boot.data.elasticsearch.domain.city.CityRepository;\nimport org.springframework.boot.data.elasticsearch.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.config.EnableElasticsearchAuditing;\nimport org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataElasticsearchRepositoriesAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchRepositoriesAutoConfigurationTests {\n\n\t@Container\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,\n\t\t\t\tElasticsearchClientAutoConfiguration.class, DataElasticsearchRepositoriesAutoConfiguration.class,\n\t\t\t\tDataElasticsearchAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.elasticsearch.uris=\" + elasticsearch.getHttpHostAddress());\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CityRepository.class)\n\t\t\t\t.hasSingleBean(ElasticsearchTemplate.class));\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid testAuditingConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(AuditingConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableElasticsearchRepositories(basePackageClasses = CityRepository.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableElasticsearchRepositories\n\t@EnableElasticsearchAuditing\n\tstatic class AuditingConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/dockerTest/java/org/springframework/boot/data/elasticsearch/domain/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.domain.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/dockerTest/java/org/springframework/boot/data/elasticsearch/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.elasticsearch.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;\nimport org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch\n * support.\n *\n * @author Brian Clozel\n * @author Artur Konczak\n * @author Mohsin Husen\n * @since 4.0.0\n * @see EnableElasticsearchRepositories\n * @see EnableReactiveElasticsearchRepositories\n */\n@AutoConfiguration(after = ElasticsearchClientAutoConfiguration.class)\n@ConditionalOnClass({ ElasticsearchTemplate.class })\n@Import({ DataElasticsearchConfiguration.BaseConfiguration.class,\n\t\tDataElasticsearchConfiguration.JavaClientConfiguration.class,\n\t\tDataElasticsearchConfiguration.ReactiveRestClientConfiguration.class })\npublic final class DataElasticsearchAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport java.util.Collections;\n\nimport co.elastic.clients.elasticsearch.ElasticsearchClient;\nimport co.elastic.clients.transport.ElasticsearchTransport;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.elasticsearch.annotations.Document;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.core.ElasticsearchOperations;\nimport org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;\nimport org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;\nimport org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;\nimport org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;\nimport org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;\n\n/**\n * Configuration classes for Spring Data for Elasticsearch\n * <p>\n * Those should be {@code @Import} in a regular auto-configuration class to guarantee\n * their order of execution.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @author Stephane Nicoll\n */\nabstract class DataElasticsearchConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tElasticsearchCustomConversions elasticsearchCustomConversions() {\n\t\t\treturn new ElasticsearchCustomConversions(Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSimpleElasticsearchMappingContext elasticsearchMappingContext(ApplicationContext applicationContext,\n\t\t\t\tElasticsearchCustomConversions elasticsearchCustomConversions) throws ClassNotFoundException {\n\t\t\tSimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();\n\t\t\tmappingContext.setInitialEntitySet(new EntityScanner(applicationContext).scan(Document.class));\n\t\t\tmappingContext.setSimpleTypeHolder(elasticsearchCustomConversions.getSimpleTypeHolder());\n\t\t\treturn mappingContext;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tElasticsearchConverter elasticsearchConverter(SimpleElasticsearchMappingContext mappingContext,\n\t\t\t\tElasticsearchCustomConversions elasticsearchCustomConversions) {\n\t\t\tMappingElasticsearchConverter converter = new MappingElasticsearchConverter(mappingContext);\n\t\t\tconverter.setConversions(elasticsearchCustomConversions);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ElasticsearchClient.class)\n\tstatic class JavaClientConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = \"elasticsearchTemplate\")\n\t\t@ConditionalOnBean(ElasticsearchClient.class)\n\t\tElasticsearchTemplate elasticsearchTemplate(ElasticsearchClient client, ElasticsearchConverter converter) {\n\t\t\treturn new ElasticsearchTemplate(client, converter);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ElasticsearchTransport.class)\n\t@ConditionalOnClass({ ReactiveElasticsearchClient.class, ElasticsearchTransport.class, Mono.class })\n\tstatic class ReactiveRestClientConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tReactiveElasticsearchClient reactiveElasticsearchClient(ElasticsearchTransport transport) {\n\t\t\treturn new ReactiveElasticsearchClient(transport);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class, name = \"reactiveElasticsearchTemplate\")\n\t\tReactiveElasticsearchTemplate reactiveElasticsearchTemplate(ReactiveElasticsearchClient client,\n\t\t\t\tElasticsearchConverter converter) {\n\t\t\treturn new ReactiveElasticsearchTemplate(client, converter);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchReactiveRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\nimport org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;\nimport org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;\nimport org.springframework.data.elasticsearch.repository.support.ReactiveElasticsearchRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch\n * Reactive Repositories.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see EnableReactiveElasticsearchRepositories\n */\n@AutoConfiguration\n@ConditionalOnClass({ ReactiveElasticsearchClient.class, ReactiveElasticsearchRepository.class, Mono.class })\n@ConditionalOnBooleanProperty(name = \"spring.data.elasticsearch.repositories.enabled\", matchIfMissing = true)\n@ConditionalOnMissingBean(ReactiveElasticsearchRepositoryFactoryBean.class)\n@Import(DataElasticsearchReactiveRepositoriesRegistrar.class)\npublic final class DataElasticsearchReactiveRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchReactiveRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;\nimport org.springframework.data.elasticsearch.repository.config.ReactiveElasticsearchRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Elasticsearch\n * Reactive Repositories.\n *\n * @author Brian Clozel\n */\nclass DataElasticsearchReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableReactiveElasticsearchRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableElasticsearchRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new ReactiveElasticsearchRepositoryConfigurationExtension();\n\t}\n\n\t@EnableReactiveElasticsearchRepositories\n\tprivate static final class EnableElasticsearchRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.elasticsearch.repository.ElasticsearchRepository;\nimport org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;\nimport org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch\n * Repositories.\n *\n * @author Artur Konczak\n * @author Mohsin Husen\n * @since 4.0.0\n * @see EnableElasticsearchRepositories\n */\n@AutoConfiguration\n@ConditionalOnClass(ElasticsearchRepository.class)\n@ConditionalOnBooleanProperty(name = \"spring.data.elasticsearch.repositories.enabled\", matchIfMissing = true)\n@ConditionalOnMissingBean(ElasticsearchRepositoryFactoryBean.class)\n@Import(DataElasticsearchRepositoriesRegistrar.class)\npublic final class DataElasticsearchRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.elasticsearch.repository.config.ElasticsearchRepositoryConfigExtension;\nimport org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Elasticsearch\n * Repositories.\n *\n * @author Artur Konczak\n * @author Mohsin Husen\n */\nclass DataElasticsearchRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableElasticsearchRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableElasticsearchRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new ElasticsearchRepositoryConfigExtension();\n\t}\n\n\t@EnableElasticsearchRepositories\n\tprivate static final class EnableElasticsearchRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/health/DataElasticsearchReactiveHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure.health;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchAutoConfiguration;\nimport org.springframework.boot.data.elasticsearch.health.DataElasticsearchReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link DataElasticsearchReactiveHealthIndicator} using the\n * {@link ReactiveElasticsearchClient}.\n *\n * @author Aleksander Lech\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataElasticsearchAutoConfiguration.class)\n@ConditionalOnClass({ ReactiveElasticsearchClient.class, Flux.class, DataElasticsearchReactiveHealthIndicator.class,\n\t\tConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(ReactiveElasticsearchClient.class)\n@ConditionalOnEnabledHealthIndicator(\"elasticsearch\")\npublic final class DataElasticsearchReactiveHealthContributorAutoConfiguration extends\n\t\tCompositeReactiveHealthContributorConfiguration<DataElasticsearchReactiveHealthIndicator, ReactiveElasticsearchClient> {\n\n\tDataElasticsearchReactiveHealthContributorAutoConfiguration() {\n\t\tsuper(DataElasticsearchReactiveHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"elasticsearchHealthIndicator\", \"elasticsearchHealthContributor\" })\n\tReactiveHealthContributor elasticsearchHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, ReactiveElasticsearchClient.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Elasticsearch health.\n */\n@NullMarked\npackage org.springframework.boot.data.elasticsearch.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Elasticsearch.\n */\n@NullMarked\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/health/DataElasticsearchReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.health;\n\nimport co.elastic.clients.elasticsearch._types.HealthStatus;\nimport co.elastic.clients.elasticsearch.cluster.HealthResponse;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\n\n/**\n * {@link HealthIndicator} for an Elasticsearch cluster using a\n * {@link ReactiveElasticsearchClient}.\n *\n * @author Brian Clozel\n * @author Aleksander Lech\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class DataElasticsearchReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate final ReactiveElasticsearchClient client;\n\n\tpublic DataElasticsearchReactiveHealthIndicator(ReactiveElasticsearchClient client) {\n\t\tsuper(\"Elasticsearch health check failed\");\n\t\tthis.client = client;\n\t}\n\n\t@Override\n\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\treturn this.client.cluster().health((b) -> b).map((response) -> processResponse(builder, response));\n\t}\n\n\tprivate Health processResponse(Health.Builder builder, HealthResponse response) {\n\t\tif (!response.timedOut()) {\n\t\t\tHealthStatus status = response.status();\n\t\t\tbuilder.status((HealthStatus.Red == status) ? Status.OUT_OF_SERVICE : Status.UP);\n\t\t\tbuilder.withDetail(\"cluster_name\", response.clusterName());\n\t\t\tbuilder.withDetail(\"status\", response.status().jsonValue());\n\t\t\tbuilder.withDetail(\"timed_out\", response.timedOut());\n\t\t\tbuilder.withDetail(\"number_of_nodes\", response.numberOfNodes());\n\t\t\tbuilder.withDetail(\"number_of_data_nodes\", response.numberOfDataNodes());\n\t\t\tbuilder.withDetail(\"active_primary_shards\", response.activePrimaryShards());\n\t\t\tbuilder.withDetail(\"active_shards\", response.activeShards());\n\t\t\tbuilder.withDetail(\"relocating_shards\", response.relocatingShards());\n\t\t\tbuilder.withDetail(\"initializing_shards\", response.initializingShards());\n\t\t\tbuilder.withDetail(\"unassigned_shards\", response.unassignedShards());\n\t\t\tbuilder.withDetail(\"delayed_unassigned_shards\", response.delayedUnassignedShards());\n\t\t\tbuilder.withDetail(\"number_of_pending_tasks\", response.numberOfPendingTasks());\n\t\t\tbuilder.withDetail(\"number_of_in_flight_fetch\", response.numberOfInFlightFetch());\n\t\t\tbuilder.withDetail(\"task_max_waiting_in_queue_millis\", response.taskMaxWaitingInQueueMillis());\n\t\t\tbuilder.withDetail(\"active_shards_percent_as_number\", response.activeShardsPercentAsNumber());\n\t\t\tbuilder.withDetail(\"unassigned_primary_shards\", response.unassignedPrimaryShards());\n\t\t\treturn builder.build();\n\t\t}\n\t\treturn builder.down().build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/java/org/springframework/boot/data/elasticsearch/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Elasticsearch health integration using Spring Data Elasticsearch.\n */\n@NullMarked\npackage org.springframework.boot.data.elasticsearch.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.elasticsearch.cluster-name\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Elasticsearch cluster name.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.elasticsearch.cluster-nodes\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Comma-separated list of cluster node addresses.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.elasticsearch.properties\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"description\": \"Additional properties used to configure the client.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.elasticsearch.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Elasticsearch repositories.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchAutoConfiguration\norg.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchRepositoriesAutoConfiguration\norg.springframework.boot.data.elasticsearch.autoconfigure.health.DataElasticsearchReactiveHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/autoconfigure/DataElasticsearchAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure;\n\nimport java.math.BigDecimal;\nimport java.util.Collections;\n\nimport co.elastic.clients.transport.ElasticsearchTransport;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.elasticsearch.domain.city.City;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;\nimport org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;\nimport org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;\nimport org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;\nimport org.springframework.data.mapping.model.SimpleTypeHolder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataElasticsearchAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Artur Konczak\n * @author Brian Clozel\n * @author Peter-Josef Meisch\n * @author Scott Frederick\n * @author Stephane Nicoll\n */\nclass DataElasticsearchAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,\n\t\t\t\tElasticsearchClientAutoConfiguration.class, DataElasticsearchAutoConfiguration.class));\n\n\t@Test\n\tvoid defaultRestBeansRegistered() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class)\n\t\t\t.hasSingleBean(ReactiveElasticsearchTemplate.class)\n\t\t\t.hasSingleBean(ElasticsearchConverter.class)\n\t\t\t.hasSingleBean(ElasticsearchConverter.class)\n\t\t\t.hasSingleBean(ElasticsearchCustomConversions.class));\n\t}\n\n\t@Test\n\tvoid defaultConversionsRegisterBigDecimalAsSimpleType() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tSimpleElasticsearchMappingContext mappingContext = context.getBean(SimpleElasticsearchMappingContext.class);\n\t\t\tassertThat(mappingContext)\n\t\t\t\t.extracting(\"simpleTypeHolder\", InstanceOfAssertFactories.type(SimpleTypeHolder.class))\n\t\t\t\t.satisfies((simpleTypeHolder) -> assertThat(simpleTypeHolder.isSimpleType(BigDecimal.class)).isTrue());\n\t\t});\n\t}\n\n\t@Test\n\tvoid customConversionsShouldBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomElasticsearchCustomConversions.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ElasticsearchCustomConversions.class).hasBean(\"testCustomConversions\");\n\t\t\tassertThat(context.getBean(ElasticsearchConverter.class)\n\t\t\t\t.getConversionService()\n\t\t\t\t.canConvert(ElasticsearchTemplate.class, Boolean.class)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customRestTemplateShouldBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRestTemplate.class)\n\t\t\t.run((context) -> assertThat(context).getBeanNames(ElasticsearchTemplate.class)\n\t\t\t\t.hasSize(1)\n\t\t\t\t.contains(\"elasticsearchTemplate\"));\n\t}\n\n\t@Test\n\tvoid customReactiveRestTemplateShouldBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomReactiveElasticsearchTemplate.class)\n\t\t\t.run((context) -> assertThat(context).getBeanNames(ReactiveElasticsearchTemplate.class)\n\t\t\t\t.hasSize(1)\n\t\t\t\t.contains(\"reactiveElasticsearchTemplate\"));\n\t}\n\n\t@Test\n\tvoid shouldFilterInitialEntityScanWithDocumentAnnotation() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tSimpleElasticsearchMappingContext mappingContext = context.getBean(SimpleElasticsearchMappingContext.class);\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(City.class)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithRestClientShouldCreateTransportAndClient() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class));\n\t}\n\n\t@Test\n\tvoid configureWhenCustomClientShouldBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientConfiguration.class, CustomClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class)\n\t\t\t\t.hasBean(\"customClient\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestClientConfiguration {\n\n\t\t@Bean\n\t\tRest5Client restClient() {\n\t\t\treturn mock(Rest5Client.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomClientConfiguration {\n\n\t\t@Bean\n\t\tReactiveElasticsearchClient customClient(ElasticsearchTransport transport) {\n\t\t\treturn new ReactiveElasticsearchClient(transport);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomElasticsearchCustomConversions {\n\n\t\t@Bean\n\t\tElasticsearchCustomConversions testCustomConversions() {\n\t\t\treturn new ElasticsearchCustomConversions(Collections.singletonList(new MyConverter()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRestTemplate {\n\n\t\t@Bean\n\t\tElasticsearchTemplate elasticsearchTemplate() {\n\t\t\treturn mock(ElasticsearchTemplate.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomReactiveElasticsearchTemplate {\n\n\t\t@Bean\n\t\tReactiveElasticsearchTemplate reactiveElasticsearchTemplate() {\n\t\t\treturn mock(ReactiveElasticsearchTemplate.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class EntityScanConfig {\n\n\t}\n\n\tstatic class MyConverter implements Converter<ElasticsearchTemplate, @Nullable Boolean> {\n\n\t\t@Override\n\t\tpublic @Nullable Boolean convert(ElasticsearchTemplate source) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/autoconfigure/health/DataElasticsearchReactiveHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchAutoConfiguration;\nimport org.springframework.boot.data.elasticsearch.health.DataElasticsearchReactiveHealthIndicator;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.health.ElasticsearchRestHealthContributorAutoConfiguration;\nimport org.springframework.boot.elasticsearch.health.ElasticsearchRestClientHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataElasticsearchReactiveHealthContributorAutoConfiguration}.\n *\n * @author Aleksander Lech\n */\nclass DataElasticsearchReactiveHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataElasticsearchAutoConfiguration.class,\n\t\t\t\tElasticsearchClientAutoConfiguration.class, ElasticsearchRestClientAutoConfiguration.class,\n\t\t\t\tDataElasticsearchReactiveHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DataElasticsearchReactiveHealthIndicator.class)\n\t\t\t\t.hasBean(\"elasticsearchHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchRestHealthContributorAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DataElasticsearchReactiveHealthIndicator.class)\n\t\t\t\t.hasBean(\"elasticsearchHealthContributor\")\n\t\t\t\t.doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.elasticsearch.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataElasticsearchReactiveHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(\"elasticsearchHealthContributor\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.domain.city;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.elasticsearch.annotations.Document;\nimport org.springframework.data.elasticsearch.annotations.Setting;\n\n@Document(indexName = \"city\")\n@Setting(shards = 1, replicas = 0, refreshInterval = \"-1\")\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.domain.city;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tPage<City> findAll(Pageable pageable);\n\n\tPage<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(String name, String country);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/domain/city/ReactiveCityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.domain.city;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface ReactiveCityRepository extends ReactiveCrudRepository<City, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.elasticsearch.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch/src/test/java/org/springframework/boot/data/elasticsearch/health/DataElasticsearchReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.health;\n\nimport java.time.Duration;\nimport java.util.Map;\n\nimport co.elastic.clients.json.jackson.JacksonJsonpMapper;\nimport co.elastic.clients.transport.rest5_client.Rest5ClientTransport;\nimport co.elastic.clients.transport.rest5_client.low_level.ResponseException;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.testsupport.junit.EnabledOnLocale;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link DataElasticsearchReactiveHealthIndicator}\n *\n * @author Brian Clozel\n * @author Scott Frederick\n */\nclass DataElasticsearchReactiveHealthIndicatorTests {\n\n\tprivate static final Duration TIMEOUT = Duration.ofSeconds(5);\n\n\tprivate MockWebServer server;\n\n\tprivate DataElasticsearchReactiveHealthIndicator healthIndicator;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tReactiveElasticsearchClient client = new ReactiveElasticsearchClient(new Rest5ClientTransport(\n\t\t\t\tRest5Client.builder(HttpHost.create(this.server.getHostName() + \":\" + this.server.getPort())).build(),\n\t\t\t\tnew JacksonJsonpMapper()));\n\t\tthis.healthIndicator = new DataElasticsearchReactiveHealthIndicator(client);\n\t}\n\n\t@AfterEach\n\tvoid shutdown() throws Exception {\n\t\tthis.server.shutdown();\n\t}\n\n\t@Test\n\tvoid elasticsearchIsUp() {\n\t\tsetupMockResponse(\"green\");\n\t\tHealth health = this.healthIndicator.health().block(TIMEOUT);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertHealthDetailsWithStatus(health.getDetails(), \"green\");\n\t}\n\n\t@Test\n\tvoid elasticsearchWithYellowStatusIsUp() {\n\t\tsetupMockResponse(\"yellow\");\n\t\tHealth health = this.healthIndicator.health().block(TIMEOUT);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertHealthDetailsWithStatus(health.getDetails(), \"yellow\");\n\t}\n\n\t@Test\n\t@EnabledOnLocale(language = \"en\")\n\tvoid elasticsearchIsDown() throws Exception {\n\t\tthis.server.shutdown();\n\t\tHealth health = this.healthIndicator.health().block(TIMEOUT);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails().get(\"error\")).asString().contains(\"Connection refused\");\n\t}\n\n\t@Test\n\tvoid elasticsearchIsDownByResponseCode() {\n\t\tthis.server.enqueue(new MockResponse().setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));\n\t\tHealth health = this.healthIndicator.health().block(TIMEOUT);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails().get(\"error\")).asString().startsWith(ResponseException.class.getName());\n\t}\n\n\t@Test\n\tvoid elasticsearchIsOutOfServiceByStatus() {\n\t\tsetupMockResponse(\"red\");\n\t\tHealth health = this.healthIndicator.health().block(TIMEOUT);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t\tassertHealthDetailsWithStatus(health.getDetails(), \"red\");\n\t}\n\n\tprivate void assertHealthDetailsWithStatus(Map<String, Object> details, String status) {\n\t\tassertThat(details).contains(entry(\"cluster_name\", \"elasticsearch\"), entry(\"status\", status),\n\t\t\t\tentry(\"timed_out\", false), entry(\"number_of_nodes\", 1), entry(\"number_of_data_nodes\", 1),\n\t\t\t\tentry(\"active_primary_shards\", 0), entry(\"active_shards\", 0), entry(\"relocating_shards\", 0),\n\t\t\t\tentry(\"initializing_shards\", 0), entry(\"unassigned_shards\", 0), entry(\"delayed_unassigned_shards\", 0),\n\t\t\t\tentry(\"number_of_pending_tasks\", 0), entry(\"number_of_in_flight_fetch\", 0),\n\t\t\t\tentry(\"task_max_waiting_in_queue_millis\", 0L), entry(\"active_shards_percent_as_number\", 100.0),\n\t\t\t\tentry(\"unassigned_primary_shards\", 10));\n\t}\n\n\tprivate void setupMockResponse(String status) {\n\t\tMockResponse mockResponse = new MockResponse().setBody(createJsonResult(status))\n\t\t\t.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)\n\t\t\t.setHeader(\"X-Elastic-Product\", \"Elasticsearch\");\n\t\tthis.server.enqueue(mockResponse);\n\t}\n\n\tprivate String createJsonResult(String status) {\n\t\treturn String.format(\n\t\t\t\t\"{\\\"cluster_name\\\":\\\"elasticsearch\\\",\" + \"\\\"status\\\":\\\"%s\\\",\\\"timed_out\\\":false,\\\"number_of_nodes\\\":1,\"\n\t\t\t\t\t\t+ \"\\\"number_of_data_nodes\\\":1,\\\"active_primary_shards\\\":0,\"\n\t\t\t\t\t\t+ \"\\\"active_shards\\\":0,\\\"relocating_shards\\\":0,\\\"initializing_shards\\\":0,\"\n\t\t\t\t\t\t+ \"\\\"unassigned_shards\\\":0,\\\"delayed_unassigned_shards\\\":0,\"\n\t\t\t\t\t\t+ \"\\\"number_of_pending_tasks\\\":0,\\\"number_of_in_flight_fetch\\\":0,\"\n\t\t\t\t\t\t+ \"\\\"task_max_waiting_in_queue_millis\\\":0,\\\"active_shards_percent_as_number\\\":100.0,\"\n\t\t\t\t\t\t+ \"\\\"unassigned_primary_shards\\\": 10 }\",\n\t\t\t\tstatus);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data Elasticsearch Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-elasticsearch\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jsonb\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"io.projectreactor:reactor-test\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-elasticsearch\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Sample test for {@link DataElasticsearchTest @DataElasticsearchTest}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataElasticsearchTest\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchTestIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\t@Autowired\n\tprivate ElasticsearchTemplate elasticsearchTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument document = new ExampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tExampleDocument savedDocument = this.exampleRepository.save(document);\n\t\tExampleDocument getDocument = this.elasticsearchTemplate.get(id, ExampleDocument.class);\n\t\tassertThat(getDocument).isNotNull();\n\t\tassertThat(getDocument.getId()).isNotNull();\n\t\tassertThat(getDocument.getId()).isEqualTo(savedDocument.getId());\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataElasticsearchTest#properties properties} attribute of\n * {@link DataElasticsearchTest @DataElasticsearchTest}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataElasticsearchTest(properties = \"spring.profiles.active=test\")\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchTestPropertiesIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataElasticsearchTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTestReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Sample tests for {@link DataElasticsearchTest @DataElasticsearchTest} using reactive\n * repositories.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataElasticsearchTest\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchTestReactiveIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\t@Autowired\n\tprivate ReactiveElasticsearchTemplate elasticsearchTemplate;\n\n\t@Autowired\n\tprivate ExampleReactiveRepository exampleReactiveRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument exampleDocument = new ExampleDocument();\n\t\texampleDocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\texampleDocument = this.exampleReactiveRepository.save(exampleDocument).block(Duration.ofSeconds(30));\n\t\tassertThat(exampleDocument).isNotNull();\n\t\tassertThat(exampleDocument.getId()).isNotNull();\n\t\tassertThat(this.elasticsearchTemplate.exists(exampleDocument.getId(), ExampleDocument.class)\n\t\t\t.block(Duration.ofSeconds(30))).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for\n * {@link DataElasticsearchTest @DataElasticsearchTest}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataElasticsearchTest(includeFilters = @Filter(Service.class))\n@Testcontainers(disabledWithoutDocker = true)\nclass DataElasticsearchTestWithIncludeFilterIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tExampleDocument document = new ExampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tExampleDocument savedDocument = this.exampleRepository.save(document);\n\t\tassertThat(savedDocument.getId()).isNotNull();\n\t\tassertThat(this.service.findById(savedDocument.getId())).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/ExampleDocument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.elasticsearch.annotations.Document;\n\n/**\n * Example document used with {@link DataElasticsearchTest @DataElasticsearchTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Document(indexName = \"examples\")\npublic class ExampleDocument {\n\n\t@Id\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String text;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/ExampleElasticsearchApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataElasticsearchTest @DataElasticsearchTest} tests.\n *\n * @author Eddú Meléndez\n */\n@SpringBootApplication\npublic class ExampleElasticsearchApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/ExampleReactiveRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;\n\n/**\n * Example reactive repository used with\n * {@link DataElasticsearchTest @DataElasticsearchTest} tests.\n *\n * @author Eddú Meléndez\n */\ninterface ExampleReactiveRepository extends ReactiveElasticsearchRepository<ExampleDocument, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.springframework.data.elasticsearch.repository.ElasticsearchRepository;\n\n/**\n * Example repository used with {@link DataElasticsearchTest @DataElasticsearchTest}\n * tests.\n *\n * @author Eddú Meléndez\n */\ninterface ExampleRepository extends ElasticsearchRepository<ExampleDocument, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/dockerTest/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataElasticsearchTest @DataElasticsearchTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Service\npublic class ExampleService {\n\n\tprivate final ElasticsearchTemplate elasticsearchTemplate;\n\n\tpublic ExampleService(ElasticsearchTemplate elasticsearchRestTemplate) {\n\t\tthis.elasticsearchTemplate = elasticsearchRestTemplate;\n\t}\n\n\tpublic @Nullable ExampleDocument findById(String id) {\n\t\treturn this.elasticsearchTemplate.get(id, ExampleDocument.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/main/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/AutoConfigureDataElasticsearch.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data\n * Elasticsearch tests. Most tests should consider using\n * {@link DataElasticsearchTest @DataElasticsearchTest} rather than using this annotation\n * directly.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n * @see DataElasticsearchTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataElasticsearch {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/main/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for a Data Elasticsearch test that focuses\n * <strong>only</strong> on Data Elasticsearch components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data\n * Elasticsearch tests. Similarly, component scanning is limited to Elasticsearch\n * repositories and entities ({@code @Document}).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataElasticsearchTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataElasticsearchTypeExcludeFilter.class)\n@AutoConfigureDataElasticsearch\n@ImportAutoConfiguration\npublic @interface DataElasticsearchTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/main/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for\n * {@link DataElasticsearchTest @DataElasticsearchTest} support.\n *\n * @author Eddú Meléndez\n */\nclass DataElasticsearchTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataElasticsearchTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/main/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/DataElasticsearchTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataElasticsearchTest @DataElasticsearchTest}.\n *\n * @author Eddú Meléndez\n */\nclass DataElasticsearchTypeExcludeFilter\n\t\textends StandardAnnotationCustomizableTypeExcludeFilter<DataElasticsearchTest> {\n\n\tDataElasticsearchTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/main/java/org/springframework/boot/data/elasticsearch/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data Elasticsearch tests.\n */\n@NullMarked\npackage org.springframework.boot.data.elasticsearch.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-elasticsearch-test/src/main/resources/META-INF/spring/org.springframework.boot.data.elasticsearch.test.autoconfigure.AutoConfigureDataElasticsearch.imports",
    "content": "org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration\norg.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchAutoConfiguration\norg.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.elasticsearch.autoconfigure.DataElasticsearchRepositoriesAutoConfiguration\norg.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration\norg.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration\noptional:org.springframework.boot.jsonb.autoconfigure.JsonbAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data JDBC\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(\"org.springframework.data:spring-data-jdbc\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-mariadb\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-mysql\")\n\n\tdockerTestRuntimeOnly(\"com.mysql:mysql-connector-j\")\n\tdockerTestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\tdockerTestRuntimeOnly(\"org.mariadb.jdbc:mariadb-java-client\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/dockerTest/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesAutoConfigurationDialectResolutionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.JdbcDatabaseContainer;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.mysql.MySQLContainer;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.jdbc.domain.city.City;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect;\nimport org.springframework.data.relational.core.dialect.Dialect;\nimport org.springframework.data.relational.core.dialect.MariaDbDialect;\nimport org.springframework.util.function.ThrowingConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataJdbcRepositoriesAutoConfiguration} when the configured dialect\n * requires resolution using a database connection.\n *\n * @author Andy Wilkinson\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass DataJdbcRepositoriesAutoConfigurationDialectResolutionTests {\n\n\t@Test\n\tvoid resolvesMariaDbDialect() {\n\t\twithContainer(MariaDBContainer.class, (runner) -> {\n\t\t\trunner.withPropertyValues(\"spring.data.jdbc.dialect=maria\").run((context) -> {\n\t\t\t\tDialect dialect = context.getBean(Dialect.class);\n\t\t\t\tassertThat(dialect).isInstanceOf(MariaDbDialect.class);\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid resolvesMySqlDialect() {\n\t\twithContainer(MySQLContainer.class, (runner) -> {\n\t\t\trunner.withPropertyValues(\"spring.data.jdbc.dialect=mysql\").run((context) -> {\n\t\t\t\tDialect dialect = context.getBean(Dialect.class);\n\t\t\t\tassertThat(dialect).isInstanceOf(JdbcMySqlDialect.class);\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate <C extends JdbcDatabaseContainer<?>> void withContainer(Class<C> containerType,\n\t\t\tThrowingConsumer<ApplicationContextRunner> callback) {\n\t\tC container = TestImage.container(containerType);\n\t\ttry {\n\t\t\tcontainer.start();\n\t\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\t\tDataJdbcRepositoriesAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t\t.withPropertyValues(\"spring.datasource.url=\" + container.getJdbcUrl(),\n\t\t\t\t\t\t\"spring.datasource.username=\" + container.getUsername(),\n\t\t\t\t\t\t\"spring.datasource.password=\" + container.getPassword());\n\t\t\tcallback.accept(contextRunner);\n\t\t}\n\t\tfinally {\n\t\t\tcontainer.close();\n\t\t}\n\t}\n\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcDatabaseDialect.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport java.util.function.Function;\n\nimport org.springframework.data.jdbc.core.dialect.DialectResolver;\nimport org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcH2Dialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcMariaDbDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcOracleDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.util.Assert;\n\n/**\n * List of database dialects that can be configured in Boot for use with Spring Data JDBC.\n *\n * @author Jens Schauder\n * @since 4.0.0\n */\npublic enum DataJdbcDatabaseDialect {\n\n\t/**\n\t * Provides an instance of {@link JdbcDb2Dialect}.\n\t */\n\tDB2(JdbcDb2Dialect.INSTANCE),\n\n\t/**\n\t * Provides an instance of {@link JdbcH2Dialect}.\n\t */\n\tH2(JdbcH2Dialect.INSTANCE),\n\n\t/**\n\t * Provides an instance of {@link JdbcHsqlDbDialect}.\n\t */\n\tHSQL(JdbcHsqlDbDialect.INSTANCE),\n\n\t/**\n\t * Resolves an instance of {@link JdbcMariaDbDialect} by querying the database\n\t * configuration.\n\t */\n\tMARIA(JdbcMariaDbDialect.class),\n\n\t/**\n\t * Resolves an instance of {@link JdbcMySqlDialect} by querying the database\n\t * configuration.\n\t */\n\tMYSQL(JdbcMySqlDialect.class),\n\n\t/**\n\t * Provides an instance of {@link JdbcOracleDialect}.\n\t */\n\tORACLE(JdbcOracleDialect.INSTANCE),\n\n\t/**\n\t * Provides an instance of {@link JdbcPostgresDialect}.\n\t */\n\tPOSTGRESQL(JdbcPostgresDialect.INSTANCE),\n\n\t/**\n\t * Provides an instance of {@link JdbcSqlServerDialect}.\n\t */\n\tSQL_SERVER(JdbcSqlServerDialect.INSTANCE);\n\n\tprivate final Function<JdbcOperations, JdbcDialect> jdbcDialectResolver;\n\n\tDataJdbcDatabaseDialect(Class<? extends JdbcDialect> jdbcDialectType) {\n\t\tthis.jdbcDialectResolver = (jdbc) -> {\n\t\t\tJdbcDialect dialect = DialectResolver.getDialect(jdbc);\n\t\t\tAssert.isInstanceOf(jdbcDialectType, dialect);\n\t\t\treturn dialect;\n\t\t};\n\t}\n\n\tDataJdbcDatabaseDialect(JdbcDialect jdbcDialect) {\n\t\tthis.jdbcDialectResolver = (jdbc) -> jdbcDialect;\n\t}\n\n\tJdbcDialect getJdbcDialect(JdbcOperations jdbc) {\n\t\treturn this.jdbcDialectResolver.apply(jdbc);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Spring Data JDBC.\n *\n * @author Jens Schauder\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.jdbc\")\npublic class DataJdbcProperties {\n\n\t/**\n\t * Dialect to use. By default, the dialect is determined by inspecting the database\n\t * connection.\n\t */\n\tprivate @Nullable DataJdbcDatabaseDialect dialect;\n\n\tpublic @Nullable DataJdbcDatabaseDialect getDialect() {\n\t\treturn this.dialect;\n\t}\n\n\tpublic void setDialect(@Nullable DataJdbcDatabaseDialect dialect) {\n\t\tthis.dialect = dialect;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.data.jdbc.core.JdbcAggregateTemplate;\nimport org.springframework.data.jdbc.core.convert.DataAccessStrategy;\nimport org.springframework.data.jdbc.core.convert.JdbcConverter;\nimport org.springframework.data.jdbc.core.convert.JdbcCustomConversions;\nimport org.springframework.data.jdbc.core.convert.RelationResolver;\nimport org.springframework.data.jdbc.core.dialect.JdbcDialect;\nimport org.springframework.data.jdbc.core.mapping.JdbcMappingContext;\nimport org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;\nimport org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;\nimport org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension;\nimport org.springframework.data.relational.RelationalManagedTypes;\nimport org.springframework.data.relational.core.mapping.NamingStrategy;\nimport org.springframework.data.relational.core.mapping.Table;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's JDBC Repositories.\n * <p>\n * Once in effect, the auto-configuration is the equivalent of enabling JDBC repositories\n * using the {@link EnableJdbcRepositories @EnableJdbcRepositories} annotation and\n * providing an {@link AbstractJdbcConfiguration} subclass.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Jens Schauder\n * @since 4.0.0\n * @see EnableJdbcRepositories\n */\n@AutoConfiguration(after = { JdbcTemplateAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })\n@ConditionalOnBean({ NamedParameterJdbcOperations.class, PlatformTransactionManager.class })\n@ConditionalOnClass({ NamedParameterJdbcOperations.class, AbstractJdbcConfiguration.class })\n@ConditionalOnBooleanProperty(name = \"spring.data.jdbc.repositories.enabled\", matchIfMissing = true)\n@EnableConfigurationProperties(DataJdbcProperties.class)\npublic final class DataJdbcRepositoriesAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(JdbcRepositoryConfigExtension.class)\n\t@Import(DataJdbcRepositoriesRegistrar.class)\n\tstatic class JdbcRepositoriesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(AbstractJdbcConfiguration.class)\n\tstatic class SpringBootJdbcConfiguration extends AbstractJdbcConfiguration {\n\n\t\tprivate final ApplicationContext applicationContext;\n\n\t\tprivate final DataJdbcProperties properties;\n\n\t\tSpringBootJdbcConfiguration(ApplicationContext applicationContext, DataJdbcProperties properties) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tprotected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {\n\t\t\treturn new EntityScanner(this.applicationContext).scan(Table.class);\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic RelationalManagedTypes jdbcManagedTypes() throws ClassNotFoundException {\n\t\t\treturn super.jdbcManagedTypes();\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,\n\t\t\t\tJdbcCustomConversions customConversions, RelationalManagedTypes jdbcManagedTypes) {\n\t\t\treturn super.jdbcMappingContext(namingStrategy, customConversions, jdbcManagedTypes);\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic JdbcConverter jdbcConverter(JdbcMappingContext mappingContext, NamedParameterJdbcOperations operations,\n\t\t\t\t@Lazy RelationResolver relationResolver, JdbcCustomConversions conversions, JdbcDialect dialect) {\n\t\t\treturn super.jdbcConverter(mappingContext, operations, relationResolver, conversions, dialect);\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic JdbcCustomConversions jdbcCustomConversions() {\n\t\t\treturn super.jdbcCustomConversions();\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic JdbcAggregateTemplate jdbcAggregateTemplate(ApplicationContext applicationContext,\n\t\t\t\tJdbcMappingContext mappingContext, JdbcConverter converter, DataAccessStrategy dataAccessStrategy) {\n\t\t\treturn super.jdbcAggregateTemplate(applicationContext, mappingContext, converter, dataAccessStrategy);\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations operations,\n\t\t\t\tJdbcConverter jdbcConverter, JdbcMappingContext context, JdbcDialect dialect) {\n\t\t\treturn super.dataAccessStrategyBean(operations, jdbcConverter, context, dialect);\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic JdbcDialect jdbcDialect(NamedParameterJdbcOperations operations) {\n\t\t\tDataJdbcDatabaseDialect dialect = this.properties.getDialect();\n\t\t\treturn (dialect != null) ? dialect.getJdbcDialect(operations.getJdbcOperations())\n\t\t\t\t\t: super.jdbcDialect(operations);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;\nimport org.springframework.data.jdbc.repository.config.JdbcRepositoryConfigExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data JDBC\n * Repositories.\n *\n * @author Andy Wilkinson\n */\nclass DataJdbcRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableJdbcRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableJdbcRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new JdbcRepositoryConfigExtension();\n\t}\n\n\t@EnableJdbcRepositories\n\tprivate static final class EnableJdbcRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data JDBC.\n */\n@NullMarked\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.jdbc.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JDBC repositories.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.jdbc.autoconfigure.DataJdbcRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.autoconfigure;\n\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Answers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.jdbc.domain.city.City;\nimport org.springframework.boot.data.jdbc.domain.city.CityRepository;\nimport org.springframework.boot.data.jdbc.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.data.jdbc.core.JdbcAggregateTemplate;\nimport org.springframework.data.jdbc.core.convert.DataAccessStrategy;\nimport org.springframework.data.jdbc.core.convert.JdbcConverter;\nimport org.springframework.data.jdbc.core.convert.JdbcCustomConversions;\nimport org.springframework.data.jdbc.core.dialect.JdbcDialect;\nimport org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect;\nimport org.springframework.data.jdbc.core.mapping.JdbcMappingContext;\nimport org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;\nimport org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;\nimport org.springframework.data.relational.RelationalManagedTypes;\nimport org.springframework.data.relational.core.dialect.Dialect;\nimport org.springframework.data.repository.Repository;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataJdbcRepositoriesAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Jens Schauder\n */\n@WithResource(name = \"schema.sql\", content = \"\"\"\n\t\tCREATE TABLE CITY (\n\t\t  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\t\t  name VARCHAR(30),\n\t\t  state  VARCHAR(30),\n\t\t  country  VARCHAR(30),\n\t\t  map  VARCHAR(30)\n\t\t);\n\t\t\"\"\")\n@WithResource(name = \"data.sql\",\n\t\tcontent = \"INSERT INTO CITY (ID, NAME, STATE, COUNTRY, MAP) values (2000, 'Washington', 'DC', 'US', 'Google');\")\nclass DataJdbcRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataJdbcRepositoriesAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithNoDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AbstractJdbcConfiguration.class));\n\t}\n\n\t@Test\n\tvoid backsOffWithNoJdbcOperations() {\n\t\tthis.contextRunner.with(database()).withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\tassertThat(context).doesNotHaveBean(AbstractJdbcConfiguration.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffWithNoTransactionManager() {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\t\tassertThat(context).hasSingleBean(NamedParameterJdbcOperations.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(AbstractJdbcConfiguration.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid basicAutoConfiguration() {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AbstractJdbcConfiguration.class);\n\t\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\t\tassertThat(context.getBean(CityRepository.class).findById(2000L)).isPresent();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetManagedTypes() {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJdbcMappingContext mappingContext = context.getBean(JdbcMappingContext.class);\n\t\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\t\tassertThat(managedTypes.toList()).containsOnly(City.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWithNoRepositories() {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AbstractJdbcConfiguration.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(Repository.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid honoursUsersEnableJdbcRepositoriesConfiguration() {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(EnableRepositoriesConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AbstractJdbcConfiguration.class);\n\t\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\t\tassertThat(context.getBean(CityRepository.class).findById(2000L)).isPresent();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomRelationalManagedTypes() {\n\t\tallowsUserToDefineCustomBean(RelationalManagedTypesConfiguration.class, RelationalManagedTypes.class,\n\t\t\t\t\"customRelationalManagedTypes\");\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomJdbcMappingContext() {\n\t\tallowsUserToDefineCustomBean(JdbcMappingContextConfiguration.class, JdbcMappingContext.class,\n\t\t\t\t\"customJdbcMappingContext\");\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomJdbcConverter() {\n\t\tallowsUserToDefineCustomBean(JdbcConverterConfiguration.class, JdbcConverter.class, \"customJdbcConverter\");\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomJdbcCustomConversions() {\n\t\tallowsUserToDefineCustomBean(JdbcCustomConversionsConfiguration.class, JdbcCustomConversions.class,\n\t\t\t\t\"customJdbcCustomConversions\");\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomJdbcAggregateTemplate() {\n\t\tallowsUserToDefineCustomBean(JdbcAggregateTemplateConfiguration.class, JdbcAggregateTemplate.class,\n\t\t\t\t\"customJdbcAggregateTemplate\");\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomDataAccessStrategy() {\n\t\tallowsUserToDefineCustomBean(DataAccessStrategyConfiguration.class, DataAccessStrategy.class,\n\t\t\t\t\"customDataAccessStrategy\");\n\t}\n\n\t@Test\n\tvoid allowsUserToDefineCustomDialect() {\n\t\tallowsUserToDefineCustomBean(DialectConfiguration.class, JdbcDialect.class, \"customDialect\");\n\t}\n\n\t@Test\n\tvoid allowsConfigurationOfDialectByProperty() {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withPropertyValues(\"spring.data.jdbc.dialect=postgresql\")\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JdbcPostgresDialect.class));\n\t}\n\n\tprivate void allowsUserToDefineCustomBean(Class<?> configuration, Class<?> beanType, String beanName) {\n\t\tthis.contextRunner.with(database())\n\t\t\t.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(configuration, EmptyConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(beanType);\n\t\t\t\tassertThat(context).hasBean(beanName);\n\t\t\t});\n\t}\n\n\tprivate Function<ApplicationContextRunner, ApplicationContextRunner> database() {\n\t\treturn (runner) -> runner\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceInitializationAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.sql.init.schema-locations=classpath:schema.sql\",\n\t\t\t\t\t\"spring.sql.init.data-locations=classpath:data.sql\", \"spring.datasource.generate-unique-name:true\");\n\t}\n\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\t@EnableJdbcRepositories(basePackageClasses = City.class)\n\tstatic class EnableRepositoriesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RelationalManagedTypesConfiguration {\n\n\t\t@Bean\n\t\tRelationalManagedTypes customRelationalManagedTypes() {\n\t\t\treturn RelationalManagedTypes.empty();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcMappingContextConfiguration {\n\n\t\t@Bean\n\t\tJdbcMappingContext customJdbcMappingContext() {\n\t\t\treturn mock(JdbcMappingContext.class, Answers.RETURNS_MOCKS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcConverterConfiguration {\n\n\t\t@Bean\n\t\tJdbcConverter customJdbcConverter() {\n\t\t\treturn mock(JdbcConverter.class, Answers.RETURNS_MOCKS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcCustomConversionsConfiguration {\n\n\t\t@Bean\n\t\tJdbcCustomConversions customJdbcCustomConversions() {\n\t\t\treturn mock(JdbcCustomConversions.class, Answers.RETURNS_MOCKS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcAggregateTemplateConfiguration {\n\n\t\t@Bean\n\t\tJdbcAggregateTemplate customJdbcAggregateTemplate() {\n\t\t\treturn mock(JdbcAggregateTemplate.class, Answers.RETURNS_MOCKS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataAccessStrategyConfiguration {\n\n\t\t@Bean\n\t\tDataAccessStrategy customDataAccessStrategy() {\n\t\t\treturn mock(DataAccessStrategy.class, Answers.RETURNS_MOCKS);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DialectConfiguration {\n\n\t\t@Bean\n\t\tDialect customDialect() {\n\t\t\treturn mock(Dialect.class, Answers.RETURNS_MOCKS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.domain.city;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.relational.core.mapping.Table;\n\n@Table(\"CITY\")\npublic class City {\n\n\t@Id\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.domain.city;\n\nimport org.springframework.data.repository.CrudRepository;\n\npublic interface CityRepository extends CrudRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.jdbc.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/domain/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.domain.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc/src/test/java/org/springframework/boot/data/jdbc/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.jdbc.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data JDBC Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-jdbc\"))\n\tapi(project(\":module:spring-boot-jdbc-test\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/main/java/org/springframework/boot/data/jdbc/test/autoconfigure/AutoConfigureDataJdbc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureJdbc;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data JDBC tests.\n * Most tests should consider using {@link DataJdbcTest @DataJdbcTest} rather than using\n * this annotation directly.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see DataJdbcTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJdbc\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataJdbc {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/main/java/org/springframework/boot/data/jdbc/test/autoconfigure/DataJdbcTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Annotation that can be used for a Data JDBC test that focuses <strong>only</strong> on\n * Data JDBC components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data JDBC\n * tests. Similarly, component scanning is limited to JDBC repositories and entities\n * ({@code @Table}), as well as beans that implement {@code AbstractJdbcConfiguration}.\n * <p>\n * By default, tests annotated with {@code @DataJdbcTest} are transactional and roll back\n * at the end of each test. They also use an embedded in-memory database (replacing any\n * explicit or usually auto-configured DataSource). The\n * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} annotation can be used to\n * override these settings.\n * <p>\n * If you are looking to load your full application configuration, but use an embedded\n * database, you should consider {@link SpringBootTest @SpringBootTest} combined with\n * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} rather than this\n * annotation.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataJdbcTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataJdbcTypeExcludeFilter.class)\n@Transactional\n@AutoConfigureDataJdbc\n@AutoConfigureTestDatabase\n@ImportAutoConfiguration\npublic @interface DataJdbcTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default, only\n\t * {@code AbstractJdbcConfiguration} beans are included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/main/java/org/springframework/boot/data/jdbc/test/autoconfigure/DataJdbcTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataJdbcTest @DataJdbcTest} support.\n *\n * @author Andy Wilkinson\n */\nclass DataJdbcTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataJdbcTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/main/java/org/springframework/boot/data/jdbc/test/autoconfigure/DataJdbcTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataJdbcTest @DataJdbcTest}.\n *\n * @author Andy Wilkinson\n * @author Ravi Undupitiya\n */\nclass DataJdbcTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataJdbcTest> {\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES = Collections.singleton(AbstractJdbcConfiguration.class);\n\n\tDataJdbcTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/main/java/org/springframework/boot/data/jdbc/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data JDBC tests.\n */\n@NullMarked\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/main/resources/META-INF/spring/org.springframework.boot.data.jdbc.test.autoconfigure.AutoConfigureDataJdbc.imports",
    "content": "org.springframework.boot.data.jdbc.autoconfigure.DataJdbcRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/DataJdbcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for {@link DataJdbcTest @DataJdbcTest}.\n *\n * @author Andy Wilkinson\n */\n@DataJdbcTest\n@TestPropertySource(\n\t\tproperties = \"spring.sql.init.schemaLocations=classpath:org/springframework/boot/data/jdbc/test/autoconfigure/schema.sql\")\nclass DataJdbcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ExampleRepository repository;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate JdbcTemplate jdbcTemplate;\n\n\t@Test\n\tvoid testRepository() {\n\t\tthis.jdbcTemplate.update(\"INSERT INTO EXAMPLE_ENTITY (id, name, reference) VALUES (1, 'a', 'alpha')\");\n\t\tthis.jdbcTemplate.update(\"INSERT INTO EXAMPLE_ENTITY (id, name, reference) VALUES (2, 'b', 'bravo')\");\n\t\tassertThat(this.repository.findAll()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithEmbeddedDefault() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).isEqualTo(\"H2\");\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleComponent() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleComponent.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/DataJdbcTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataJdbcTest#properties properties} attribute of\n * {@link DataJdbcTest @DataJdbcTest}.\n *\n * @author Andy Wilkinson\n */\n@DataJdbcTest(properties = \"spring.profiles.active=test\")\nclass DataJdbcTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataJdbcTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/DataJdbcTypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataJdbcTypeExcludeFilter}.\n *\n * @author Ravi Undupitiya\n * @author Stephane Nicoll\n */\nclass DataJdbcTypeExcludeFilterTests {\n\n\tprivate final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\t@Test\n\tvoid matchUsingDefaultFilters() throws Exception {\n\t\tDataJdbcTypeExcludeFilter filter = new DataJdbcTypeExcludeFilter(UsingDefaultFilters.class);\n\t\tassertThat(excludes(filter, TestJdbcConfiguration.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchNotUsingDefaultFilters() throws Exception {\n\t\tDataJdbcTypeExcludeFilter filter = new DataJdbcTypeExcludeFilter(NotUsingDefaultFilters.class);\n\t\tassertThat(excludes(filter, TestJdbcConfiguration.class)).isTrue();\n\t}\n\n\tprivate boolean excludes(DataJdbcTypeExcludeFilter filter, Class<?> type) throws IOException {\n\t\tMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());\n\t\treturn filter.match(metadataReader, this.metadataReaderFactory);\n\t}\n\n\t@DataJdbcTest\n\tstatic class UsingDefaultFilters {\n\n\t}\n\n\t@DataJdbcTest(useDefaultFilters = false)\n\tstatic class NotUsingDefaultFilters {\n\n\t}\n\n\tstatic class TestJdbcConfiguration extends AbstractJdbcConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/ExampleComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport org.springframework.stereotype.Component;\n\n/**\n * Example component used with {@link DataJdbcTest @DataJdbcTest} tests.\n *\n * @author Andy Wilkinson\n */\n@Component\npublic class ExampleComponent {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/ExampleDataJdbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataJdbcTest @DataJdbcTest} tests.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class ExampleDataJdbcApplication {\n\n\t@Bean\n\tpublic DataSource dataSource() {\n\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/ExampleEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.relational.core.mapping.Table;\n\n/**\n * Example entity used with {@link DataJdbcTest @DataJdbcTest} tests.\n *\n * @author Andy Wilkinson\n */\n@Table(\"EXAMPLE_ENTITY\")\npublic class ExampleEntity {\n\n\t@Id\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\tprivate final String name;\n\n\tprivate final String reference;\n\n\tpublic ExampleEntity(String name, String reference) {\n\t\tthis.name = name;\n\t\tthis.reference = reference;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getReference() {\n\t\treturn this.reference;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/java/org/springframework/boot/data/jdbc/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jdbc.test.autoconfigure;\n\nimport org.springframework.data.repository.CrudRepository;\n\n/**\n * Example repository used with {@link DataJdbcTest @DataJdbcTest} tests.\n *\n * @author Andy Wilkinson\n */\ninterface ExampleRepository extends CrudRepository<ExampleEntity, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jdbc-test/src/test/resources/org/springframework/boot/data/jdbc/test/autoconfigure/schema.sql",
    "content": "create table example_entity (id int, name varchar, reference varchar);\n"
  },
  {
    "path": "module/spring-boot-data-jpa/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data JPA\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-hibernate\"))\n\tapi(\"org.springframework.data:spring-data-jpa\")\n\tapi(\"org.springframework:spring-aspects\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.springframework.data:spring-data-envers\") {\n\t\texclude group: \"javax.activation\", module: \"javax.activation-api\"\n\t\texclude group: \"javax.persistence\", module: \"javax.persistence-api\"\n\t\texclude group: \"javax.xml.bind\", module: \"jaxb-api\"\n\t\texclude group: \"org.jboss.spec.javax.transaction\", module: \"jboss-transaction-api_1.2_spec\"\n\t}\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-jdbc\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/main/java/org/springframework/boot/data/jpa/autoconfigure/DataJpaRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.data.jpa.autoconfigure.DataJpaRepositoriesAutoConfiguration.JpaRepositoriesImportSelector;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.BootstrapExecutorRequiredException;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.data.envers.repository.config.EnableEnversRepositories;\nimport org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension;\nimport org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;\nimport org.springframework.data.repository.history.RevisionRepository;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's JPA Repositories.\n * <p>\n * Activates when there is a bean of type {@link javax.sql.DataSource} configured in the\n * context, the Spring Data JPA {@link JpaRepository} type is on the classpath, and there\n * is no other, existing {@link JpaRepository} configured.\n * <p>\n * Once in effect, the auto-configuration is the equivalent of enabling JPA repositories\n * using the {@link EnableJpaRepositories @EnableJpaRepositories} annotation.\n * <p>\n * In case {@link EnableEnversRepositories} is on the classpath,\n * {@link EnversRevisionRepositoryFactoryBean} is used instead of\n * {@link JpaRepositoryFactoryBean} to support {@link RevisionRepository} with Hibernate\n * Envers.\n * <p>\n * This configuration class will activate <em>after</em> the Hibernate auto-configuration.\n *\n * @author Phillip Webb\n * @author Josh Long\n * @author Scott Frederick\n * @author Stefano Cordio\n * @since 4.0.0\n * @see EnableJpaRepositories\n */\n@AutoConfiguration(after = { HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })\n@ConditionalOnBean(DataSource.class)\n@ConditionalOnClass(JpaRepository.class)\n@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })\n@ConditionalOnBooleanProperty(name = \"spring.data.jpa.repositories.enabled\", matchIfMissing = true)\n@Import(JpaRepositoriesImportSelector.class)\npublic final class DataJpaRepositoriesAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.data.jpa.repositories.bootstrap-mode\", havingValue = \"deferred\")\n\tEntityManagerFactoryBuilderCustomizer entityManagerFactoryBootstrapExecutorCustomizer(\n\t\t\tMap<String, AsyncTaskExecutor> taskExecutors) {\n\t\treturn (builder) -> builder.requireBootstrapExecutor(() -> BootstrapExecutorRequiredException\n\t\t\t.ofProperty(\"spring.data.jpa.repositories.bootstrap-mode\", \"deferred\"));\n\t}\n\n\t@Bean\n\tstatic LazyInitializationExcludeFilter eagerJpaMetamodelCacheCleanup() {\n\t\treturn (name, definition, type) -> \"org.springframework.data.jpa.util.JpaMetamodelCacheCleanup\".equals(name);\n\t}\n\n\tprivate @Nullable AsyncTaskExecutor determineBootstrapExecutor(Map<String, AsyncTaskExecutor> taskExecutors) {\n\t\tif (taskExecutors.size() == 1) {\n\t\t\treturn taskExecutors.values().iterator().next();\n\t\t}\n\t\treturn taskExecutors.get(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);\n\t}\n\n\tstatic class JpaRepositoriesImportSelector implements ImportSelector {\n\n\t\tprivate static final boolean ENVERS_AVAILABLE = ClassUtils.isPresent(\n\t\t\t\t\"org.springframework.data.envers.repository.config.EnableEnversRepositories\",\n\t\t\t\tJpaRepositoriesImportSelector.class.getClassLoader());\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\treturn new String[] { determineImport() };\n\t\t}\n\n\t\tprivate String determineImport() {\n\t\t\treturn ENVERS_AVAILABLE ? EnversRevisionRepositoriesRegistrar.class.getName()\n\t\t\t\t\t: DataJpaRepositoriesRegistrar.class.getName();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/main/java/org/springframework/boot/data/jpa/autoconfigure/DataJpaRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.env.Environment;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.data.jpa.repository.config.JpaRepositoryConfigExtension;\nimport org.springframework.data.repository.config.BootstrapMode;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data JPA\n * Repositories.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Scott Frederick\n */\nclass DataJpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\tprivate @Nullable BootstrapMode bootstrapMode;\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableJpaRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableJpaRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new JpaRepositoryConfigExtension();\n\t}\n\n\t@Override\n\tprotected BootstrapMode getBootstrapMode() {\n\t\treturn (this.bootstrapMode == null) ? BootstrapMode.DEFAULT : this.bootstrapMode;\n\t}\n\n\t@Override\n\tpublic void setEnvironment(Environment environment) {\n\t\tsuper.setEnvironment(environment);\n\t\tconfigureBootstrapMode(environment);\n\t}\n\n\tprivate void configureBootstrapMode(Environment environment) {\n\t\tString property = environment.getProperty(\"spring.data.jpa.repositories.bootstrap-mode\");\n\t\tif (StringUtils.hasText(property)) {\n\t\t\tthis.bootstrapMode = BootstrapMode.valueOf(property.toUpperCase(Locale.ENGLISH));\n\t\t}\n\t}\n\n\t@EnableJpaRepositories\n\tprivate static final class EnableJpaRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/main/java/org/springframework/boot/data/jpa/autoconfigure/EnversRevisionRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Envers\n * Repositories.\n *\n * @author Stefano Cordio\n */\nclass EnversRevisionRepositoriesRegistrar extends DataJpaRepositoriesRegistrar {\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableJpaRepositoriesConfiguration.class;\n\t}\n\n\t@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)\n\tprivate static final class EnableJpaRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/main/java/org/springframework/boot/data/jpa/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data JPA.\n */\n@NullMarked\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.jpa.repositories.bootstrap-mode\",\n      \"type\": \"org.springframework.data.repository.config.BootstrapMode\",\n      \"description\": \"Bootstrap mode for JPA repositories.\",\n      \"defaultValue\": \"default\"\n    },\n    {\n      \"name\": \"spring.data.jpa.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JPA repositories.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.jpa.autoconfigure.DataJpaRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/AbstractDataJpaRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport java.util.Map;\n\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.metamodel.Metamodel;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;\nimport org.springframework.boot.data.jpa.autoconfigure.domain.city.City;\nimport org.springframework.boot.data.jpa.autoconfigure.domain.city.CityRepository;\nimport org.springframework.boot.data.jpa.autoconfigure.domain.country.Country;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.data.jpa.util.JpaMetamodel;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for {@link DataJpaRepositoriesAutoConfiguration} tests.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Scott Frederick\n * @author Stefano Cordio\n */\nabstract class AbstractDataJpaRepositoriesAutoConfigurationTests {\n\n\tfinal ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HibernateJpaAutoConfiguration.class,\n\t\t\t\tDataJpaRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class))\n\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class);\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(PlatformTransactionManager.class);\n\t\t\tassertThat(context).hasSingleBean(EntityManagerFactory.class);\n\t\t\tassertThat(context.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testOverrideRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(PlatformTransactionManager.class);\n\t\t\tassertThat(context).hasSingleBean(EntityManagerFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid whenBootstrapModeDoesNotUseFallbackBootstrapExecutor() {\n\t\tthis.contextRunner.withUserConfiguration(SingleAsyncTaskExecutorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.jpa.repositories.bootstrap-mode=lazy\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid whenBootstrapModeIsDeferredBootstrapExecutorIsConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.data.jpa.repositories.bootstrap-mode=deferred\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isEqualTo(context.getBean(\"applicationTaskExecutor\")));\n\t}\n\n\t@Test\n\tvoid whenBootstrapModeIsDefaultBootstrapExecutorIsNotConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.data.jpa.repositories.bootstrap-mode=default\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid bootstrapModeIsDefaultByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleAsyncTaskExecutorConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(TaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid whenLazyInitializationIsEnabledJpaMetamodelCacheIsClearedOnContextClose() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withBean(LazyInitializationBeanFactoryPostProcessor.class)\n\t\t\t.run((context) -> assertThat(jpaMetamodelCache()).isNotEmpty());\n\t\tassertThat(jpaMetamodelCache()).isEmpty();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<Metamodel, JpaMetamodel> jpaMetamodelCache() {\n\t\tObject field = ReflectionTestUtils.getField(JpaMetamodel.class, \"CACHE\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (Map<Metamodel, JpaMetamodel>) field;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableScheduling\n\t@Import(TestConfiguration.class)\n\tstatic class MultipleAsyncTaskExecutorConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestConfiguration.class)\n\tstatic class SingleAsyncTaskExecutorConfiguration {\n\n\t\t@Bean\n\t\tSimpleAsyncTaskExecutor testAsyncTaskExecutor() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableJpaRepositories(basePackageClasses = CityRepository.class)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class CustomConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t// To not find any repositories\n\t@EnableJpaRepositories(\"foo.bar\")\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class SortOfInvalidCustomConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(Country.class)\n\tstatic class RevisionRepositoryConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/DataJpaRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataJpaRepositoriesAutoConfiguration} without Spring Data Envers on\n * the classpath.\n *\n * @author Stefano Cordio\n */\n@ClassPathExclusions(\"spring-data-envers-*.jar\")\nclass DataJpaRepositoriesAutoConfigurationTests extends AbstractDataJpaRepositoriesAutoConfigurationTests {\n\n\t@Test\n\tvoid autoConfigurationShouldFailWithRevisionRepository() {\n\t\tthis.contextRunner.withUserConfiguration(RevisionRepositoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getFailure().isInstanceOf(BeanCreationException.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/DataJpaRepositoriesWithEnversRevisionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.data.jpa.autoconfigure.domain.country.CountryRepository;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataJpaRepositoriesAutoConfiguration} with Spring Data Envers on the\n * classpath.\n *\n * @author Stefano Cordio\n */\nclass DataJpaRepositoriesWithEnversRevisionAutoConfigurationTests\n\t\textends AbstractDataJpaRepositoriesAutoConfigurationTests {\n\n\t@Test\n\tvoid autoConfigurationShouldSucceedWithRevisionRepository() {\n\t\tthis.contextRunner.withUserConfiguration(RevisionRepositoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CountryRepository.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/DataJpaRepositoriesWithSpringDataWebAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.autoconfigure.web.DataWebAutoConfiguration;\nimport org.springframework.boot.data.jpa.autoconfigure.domain.city.City;\nimport org.springframework.boot.data.jpa.autoconfigure.domain.city.CityRepository;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.geo.Distance;\nimport org.springframework.data.web.PageableHandlerMethodArgumentResolver;\nimport org.springframework.data.web.SortHandlerMethodArgumentResolver;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataWebAutoConfiguration} and\n * {@link DataJpaRepositoriesAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass DataJpaRepositoriesWithSpringDataWebAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,\n\t\t\t\tDataJpaRepositoriesAutoConfiguration.class, DataWebAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid springDataWebIsConfiguredWithJpaRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(PageableHandlerMethodArgumentResolver.class);\n\t\t\tassertThat(context).hasSingleBean(SortHandlerMethodArgumentResolver.class);\n\t\t\tassertThat(context.getBean(FormattingConversionService.class).canConvert(String.class, Distance.class))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableWebMvc\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure.domain.city;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n@Entity\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure.domain.city;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\npublic interface CityRepository extends JpaRepository<City, Long> {\n\n\t@Override\n\tPage<City> findAll(Pageable pageable);\n\n\tPage<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(String name, String country);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.jpa.autoconfigure.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/domain/country/Country.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure.domain.country;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport org.hibernate.envers.Audited;\n\n@Entity\npublic class Country implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Audited\n\t@Column\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/domain/country/CountryRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.autoconfigure.domain.country;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.repository.history.RevisionRepository;\n\npublic interface CountryRepository extends JpaRepository<Country, Long>, RevisionRepository<Country, Long, Integer> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa/src/test/java/org/springframework/boot/data/jpa/autoconfigure/domain/country/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.jpa.autoconfigure.domain.country;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data JPA Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-jpa\"))\n\tapi(project(\":module:spring-boot-jpa-test\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/main/java/org/springframework/boot/data/jpa/test/autoconfigure/AutoConfigureDataJpa.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureJdbc;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data JPA tests.\n * Most tests should consider using {@link DataJpaTest @DataJpaTest} rather than using\n * this annotation directly.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see DataJpaTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJdbc\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataJpa {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/main/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureJdbc;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.jpa.test.autoconfigure.AutoConfigureTestEntityManager;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.data.repository.config.BootstrapMode;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Annotation for a JPA test that focuses <strong>only</strong> on JPA components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data JPA\n * tests. Similarly, component scanning is limited to JPA repositories and entities\n * ({@code @Entity}).\n * <p>\n * By default, tests annotated with {@code @DataJpaTest} are transactional and roll back\n * at the end of each test. They also use an embedded in-memory database (replacing any\n * explicit or usually auto-configured DataSource). The\n * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} annotation can be used to\n * override these settings.\n * <p>\n * SQL queries are logged by default by setting the {@code spring.jpa.show-sql} property\n * to {@code true}. This can be disabled using the {@link DataJpaTest#showSql() showSql}\n * attribute.\n * <p>\n * If you are looking to load your full application configuration, but use an embedded\n * database, you should consider {@link SpringBootTest @SpringBootTest} combined with\n * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} rather than this\n * annotation.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Scott Frederick\n * @since 4.0.0\n * @see AutoConfigureDataJpa\n * @see AutoConfigureTestDatabase\n * @see AutoConfigureTestEntityManager\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataJpaTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)\n@Transactional\n@AutoConfigureDataJpa\n@AutoConfigureJdbc\n@AutoConfigureTestDatabase\n@AutoConfigureTestEntityManager\n@ImportAutoConfiguration\npublic @interface DataJpaTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * If SQL output should be logged.\n\t * @return if SQL is logged\n\t */\n\t@PropertyMapping(\"spring.jpa.show-sql\")\n\tboolean showSql() default true;\n\n\t/**\n\t * The {@link BootstrapMode} for the test repository support. Defaults to\n\t * {@link BootstrapMode#DEFAULT}.\n\t * @return the {@link BootstrapMode} to use for testing the repository\n\t */\n\t@PropertyMapping(\"spring.data.jpa.repositories.bootstrap-mode\")\n\tBootstrapMode bootstrapMode() default BootstrapMode.DEFAULT;\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/main/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataJpaTest @DataJpaTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass DataJpaTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataJpaTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/main/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataJpaTest @DataJpaTest}.\n *\n * @author Phillip Webb\n */\nclass DataJpaTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataJpaTest> {\n\n\tDataJpaTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/main/java/org/springframework/boot/data/jpa/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data JPA tests.\n */\n@NullMarked\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/main/resources/META-INF/spring/org.springframework.boot.data.jpa.test.autoconfigure.AutoConfigureDataJpa.imports",
    "content": "org.springframework.boot.data.jpa.autoconfigure.DataJpaRepositoriesAutoConfiguration\norg.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTestAttributesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.data.repository.config.BootstrapMode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for non-default attributes of {@link DataJpaTest @DataJpaTest}.\n *\n * @author Artsiom Yudovin\n * @author Scott Frederick\n */\n@DataJpaTest(properties = \"spring.profiles.active=test\", bootstrapMode = BootstrapMode.DEFERRED)\n@ImportAutoConfiguration(TaskExecutionAutoConfiguration.class)\nclass DataJpaTestAttributesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Test\n\tvoid bootstrapModeIsSet() {\n\t\tassertThat(this.environment.getProperty(\"spring.data.jpa.repositories.bootstrap-mode\"))\n\t\t\t.isEqualTo(BootstrapMode.DEFERRED.name());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.repository.config.BootstrapMode;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.simple.JdbcClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for {@link DataJpaTest @DataJpaTest}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Yanming Zhou\n */\n@DataJpaTest(properties = \"spring.jpa.hibernate.ddl-auto=create-drop\")\nclass DataJpaTestIntegrationTests {\n\n\t@Autowired\n\tprivate TestEntityManager entities;\n\n\t@Autowired\n\tprivate JdbcClient jdbcClient;\n\n\t@Autowired\n\tprivate JdbcTemplate jdbcTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository repository;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testEntityManager() {\n\t\tExampleEntity entity = this.entities.persist(new ExampleEntity(\"spring\", \"123\"));\n\t\tthis.entities.flush();\n\t\tObject id = this.entities.getId(entity);\n\t\tassertThat(id).isNotNull();\n\t\tExampleEntity found = this.entities.find(ExampleEntity.class, id);\n\t\tassertThat(found).isNotNull();\n\t\tassertThat(found.getName()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid testEntityManagerPersistAndGetId() {\n\t\tLong id = this.entities.persistAndGetId(new ExampleEntity(\"spring\", \"123\"), Long.class);\n\t\tthis.entities.flush();\n\t\tassertThat(id).isNotNull();\n\t\tString sql = \"SELECT REFERENCE FROM EXAMPLE_ENTITY WHERE ID = ?\";\n\t\tString reference = this.jdbcTemplate.queryForObject(sql, String.class, id);\n\t\tassertThat(reference).isEqualTo(\"123\");\n\t\treference = this.jdbcClient.sql(sql).param(id).query(String.class).single();\n\t\tassertThat(reference).isEqualTo(\"123\");\n\t}\n\n\t@Test\n\tvoid testRepository() {\n\t\tthis.entities.persist(new ExampleEntity(\"spring\", \"123\"));\n\t\tthis.entities.persist(new ExampleEntity(\"boot\", \"124\"));\n\t\tthis.entities.flush();\n\t\tExampleEntity found = this.repository.findByReference(\"124\");\n\t\tassertThat(found.getName()).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithEmbeddedDefault() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).isEqualTo(\"H2\");\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleComponent() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleComponent.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid bootstrapModeIsDefaultByDefault() {\n\t\tassertThat(this.applicationContext.getEnvironment().getProperty(\"spring.data.jpa.repositories.bootstrap-mode\"))\n\t\t\t.isEqualTo(BootstrapMode.DEFAULT.name());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataJpaTest#properties properties} attribute of\n * {@link DataJpaTest @DataJpaTest}.\n *\n * @author Bernie Schelberg\n */\n@DataJpaTest(properties = \"spring.profiles.active=test\")\nclass DataJpaTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataJpaTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/DataJpaTestSchemaCredentialsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link DataJpaTest @DataJpaTest} with schema credentials that\n * should be ignored to allow the auto-configured test database to be used.\n *\n * @author Andy Wilkinson\n */\n@DataJpaTest(properties = { \"spring.sql.init.username=alice\", \"spring.sql.init.password=secret\",\n\t\t\"spring.sql.init.schema-locations=classpath:org/springframework/boot/data/jpa/test/autoconfigure/schema.sql\" })\nclass DataJpaTestSchemaCredentialsIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithEmbeddedDefault() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).isEqualTo(\"H2\");\n\t\tassertThat(new JdbcTemplate(this.dataSource).queryForList(\"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES\",\n\t\t\t\tString.class))\n\t\t\t.contains(\"EXAMPLE\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/ExampleComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.springframework.stereotype.Component;\n\n/**\n * Example component used with {@link DataJpaTest @DataJpaTest} tests.\n *\n * @author Phillip Webb\n */\n@Component\npublic class ExampleComponent {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/ExampleDataJpaApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataJpaTest @DataJpaTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleDataJpaApplication {\n\n\t@Bean\n\tpublic DataSource dataSource() {\n\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/ExampleEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n/**\n * Example entity used with {@link DataJpaTest @DataJpaTest} tests.\n *\n * @author Phillip Webb\n */\n@Entity\npublic class ExampleEntity {\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String reference;\n\n\tprotected ExampleEntity() {\n\t}\n\n\tpublic ExampleEntity(String name, String reference) {\n\t\tthis.name = name;\n\t\tthis.reference = reference;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getReference() {\n\t\treturn this.reference;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/java/org/springframework/boot/data/jpa/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.jpa.test.autoconfigure;\n\nimport org.springframework.data.repository.Repository;\n\n/**\n * Example repository used with {@link DataJpaTest @DataJpaTest} tests.\n *\n * @author Phillip Webb\n */\ninterface ExampleRepository extends Repository<ExampleEntity, Long> {\n\n\tExampleEntity findByReference(String reference);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-jpa-test/src/test/resources/org/springframework/boot/data/jpa/test/autoconfigure/schema.sql",
    "content": "CREATE TABLE example(identifier INT, name varchar(64));\n"
  },
  {
    "path": "module/spring-boot-data-ldap/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data LDAP\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-ldap\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.data:spring-data-ldap\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/main/java/org/springframework/boot/data/ldap/autoconfigure/DataLdapRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.autoconfigure;\n\nimport javax.naming.ldap.LdapContext;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.ldap.repository.LdapRepository;\nimport org.springframework.data.ldap.repository.support.LdapRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's LDAP Repositories.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ LdapContext.class, LdapRepository.class })\n@ConditionalOnBooleanProperty(name = \"spring.data.ldap.repositories.enabled\", matchIfMissing = true)\n@ConditionalOnMissingBean(LdapRepositoryFactoryBean.class)\n@Import(DataLdapRepositoriesRegistrar.class)\npublic final class DataLdapRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/main/java/org/springframework/boot/data/ldap/autoconfigure/DataLdapRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.ldap.repository.config.EnableLdapRepositories;\nimport org.springframework.data.ldap.repository.config.LdapRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data LDAP\n * Repositories.\n *\n * @author Eddú Meléndez\n */\nclass DataLdapRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableLdapRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableLdapRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new LdapRepositoryConfigurationExtension();\n\t}\n\n\t@EnableLdapRepositories\n\tprivate static final class EnableLdapRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/main/java/org/springframework/boot/data/ldap/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data LDAP.\n */\n@NullMarked\npackage org.springframework.boot.data.ldap.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.ldap.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable LDAP repositories.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.ldap.autoconfigure.DataLdapRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/test/java/org/springframework/boot/data/ldap/autoconfigure/DataLdapRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.ldap.autoconfigure.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.data.ldap.autoconfigure.domain.person.Person;\nimport org.springframework.boot.data.ldap.autoconfigure.domain.person.PersonRepository;\nimport org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.ldap.repository.config.EnableLdapRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataLdapRepositoriesAutoConfiguration}\n *\n * @author Eddú Meléndez\n */\nclass DataLdapRepositoriesAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (getContext() != null) {\n\t\t\tgetContext().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tload(TestConfiguration.class);\n\t\tassertThat(getContext().getBean(PersonRepository.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tload(EmptyConfiguration.class);\n\t\tassertThat(getContext().getBeanNamesForType(PersonRepository.class)).isEmpty();\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tload(CustomizedConfiguration.class);\n\t\tassertThat(getContext().getBean(PersonRepository.class)).isNotNull();\n\t}\n\n\tprivate void load(Class<?>... configurationClasses) {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.ldap.urls:ldap://localhost:389\").applyTo(this.context);\n\t\tthis.context.register(configurationClasses);\n\t\tthis.context.register(LdapAutoConfiguration.class, DataLdapRepositoriesAutoConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t}\n\n\tprivate AnnotationConfigApplicationContext getContext() {\n\t\tAnnotationConfigApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(Person.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(DataLdapRepositoriesAutoConfigurationTests.class)\n\t@EnableLdapRepositories(basePackageClasses = PersonRepository.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/test/java/org/springframework/boot/data/ldap/autoconfigure/domain/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.autoconfigure.domain.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/test/java/org/springframework/boot/data/ldap/autoconfigure/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.ldap.autoconfigure.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/test/java/org/springframework/boot/data/ldap/autoconfigure/domain/person/Person.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.autoconfigure.domain.person;\n\nimport javax.naming.Name;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.ldap.odm.annotations.Attribute;\nimport org.springframework.ldap.odm.annotations.DnAttribute;\nimport org.springframework.ldap.odm.annotations.Entry;\nimport org.springframework.ldap.odm.annotations.Id;\n\n@Entry(objectClasses = { \"person\", \"top\" }, base = \"ou=someOu\")\npublic class Person {\n\n\t@Id\n\tprivate @Nullable Name dn;\n\n\t@Attribute(name = \"cn\")\n\t@DnAttribute(value = \"cn\", index = 1)\n\tprivate @Nullable String fullName;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/test/java/org/springframework/boot/data/ldap/autoconfigure/domain/person/PersonRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.autoconfigure.domain.person;\n\nimport javax.naming.Name;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface PersonRepository extends Repository<Person, Name> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap/src/test/java/org/springframework/boot/data/ldap/autoconfigure/domain/person/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.ldap.autoconfigure.domain.person;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data LDAP Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-ldap\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.unboundid:unboundid-ldapsdk\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/dockerTest/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTestDockerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.OpenLdapContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.ldap.core.AttributesMapper;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.query.LdapQueryBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Sample test for {@link DataLdapTest @DataLdapTest}.\n *\n * @author Eddú Meléndez\n */\n@DataLdapTest\n@Testcontainers(disabledWithoutDocker = true)\nclass DataLdapTestDockerTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final OpenLdapContainer openLdap = TestImage.container(OpenLdapContainer.class).withEnv(\"LDAP_TLS\", \"false\");\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate LdapTemplate ldapTemplate;\n\n\t@Test\n\tvoid connectionCanBeMadeToLdapContainer() {\n\t\tList<String> cn = this.ldapTemplate.search(LdapQueryBuilder.query().where(\"objectclass\").is(\"dcObject\"),\n\t\t\t\t(AttributesMapper<String>) (attributes) -> attributes.get(\"dc\").get().toString());\n\t\tassertThat(cn).singleElement().isEqualTo(\"example\");\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/main/java/org/springframework/boot/data/ldap/test/autoconfigure/AutoConfigureDataLdap.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data LDAP tests.\n * Most tests should consider using {@link DataLdapTest @DataLdapTest} rather than using\n * this annotation directly.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n * @see DataLdapTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataLdap {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/main/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for an LDAP test that focuses <strong>only</strong> on LDAP\n * components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data LDAP\n * tests. Similarly, component scanning is limited to LDAP repositories and entities\n * ({@code @Entry}).\n * <p>\n * By default, tests annotated with {@code @DataLdapTest} will use an embedded in-memory\n * LDAP process (if available).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Eddú Meléndez\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataLdapTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataLdapTypeExcludeFilter.class)\n@AutoConfigureDataLdap\n@ImportAutoConfiguration\npublic @interface DataLdapTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/main/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataLdapTest @DataLdapTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass DataLdapTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataLdapTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/main/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataLdapTest @DataLdapTest}.\n *\n * @author Eddú Meléndez\n */\nclass DataLdapTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataLdapTest> {\n\n\tDataLdapTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/main/java/org/springframework/boot/data/ldap/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data LDAP tests.\n */\n@NullMarked\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/main/resources/META-INF/spring/org.springframework.boot.data.ldap.test.autoconfigure.AutoConfigureDataLdap.imports",
    "content": "org.springframework.boot.data.ldap.autoconfigure.DataLdapRepositoriesAutoConfiguration\norg.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration\norg.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.query.LdapQuery;\nimport org.springframework.ldap.query.LdapQueryBuilder;\nimport org.springframework.ldap.support.LdapUtils;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Sample test for {@link DataLdapTest @DataLdapTest}\n *\n * @author Eddú Meléndez\n */\n@DataLdapTest\n@TestPropertySource(properties = { \"spring.ldap.embedded.base-dn=dc=spring,dc=org\",\n\t\t\"spring.ldap.embedded.ldif=classpath:org/springframework/boot/data/ldap/test/autoconfigure/schema.ldif\" })\nclass DataLdapTestIntegrationTests {\n\n\t@Autowired\n\tprivate LdapTemplate ldapTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testRepository() {\n\t\tLdapQuery ldapQuery = LdapQueryBuilder.query().where(\"cn\").is(\"Bob Smith\");\n\t\tOptional<ExampleEntry> entry = this.exampleRepository.findOne(ldapQuery);\n\t\tassertThat(entry).isPresent();\n\t\tassertThat(entry.get().getDn())\n\t\t\t.isEqualTo(LdapUtils.newLdapName(\"cn=Bob Smith,ou=company1,c=Sweden,dc=spring,dc=org\"));\n\t\tassertThat(this.ldapTemplate.findOne(ldapQuery, ExampleEntry.class).getDn())\n\t\t\t.isEqualTo(LdapUtils.newLdapName(\"cn=Bob Smith,ou=company1,c=Sweden,dc=spring,dc=org\"));\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataLdapTest#properties properties} attribute of\n * {@link DataLdapTest @DataLdapTest}.\n *\n * @author Artsiom Yudovin\n */\n@DataLdapTest(properties = \"spring.profiles.active=test\")\nclass DataLdapTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataLdapTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/DataLdapTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.ldap.query.LdapQuery;\nimport org.springframework.ldap.query.LdapQueryBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for {@link DataLdapTest @DataLdapTest}.\n *\n * @author Eddú Meléndez\n */\n@DataLdapTest(includeFilters = @Filter(Service.class))\n@TestPropertySource(properties = { \"spring.ldap.embedded.base-dn=dc=spring,dc=org\",\n\t\t\"spring.ldap.embedded.ldif=classpath:org/springframework/boot/data/ldap/test/autoconfigure/schema.ldif\" })\nclass DataLdapTestWithIncludeFilterIntegrationTests {\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tLdapQuery ldapQuery = LdapQueryBuilder.query().where(\"cn\").is(\"Will Smith\");\n\t\tassertThat(this.service.hasEntry(ldapQuery)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/ExampleEntry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport javax.naming.Name;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.ldap.odm.annotations.Entry;\nimport org.springframework.ldap.odm.annotations.Id;\n\n/**\n * Example entry used with {@link DataLdapTest @DataLdapTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Entry(objectClasses = { \"person\", \"top\" })\npublic class ExampleEntry {\n\n\t@Id\n\tprivate @Nullable Name dn;\n\n\tpublic @Nullable Name getDn() {\n\t\treturn this.dn;\n\t}\n\n\tpublic void setDn(@Nullable Name dn) {\n\t\tthis.dn = dn;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/ExampleLdapApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataLdapTest @DataLdapTest} tests.\n *\n * @author Eddú Meléndez\n */\n@SpringBootApplication\npublic class ExampleLdapApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.springframework.data.ldap.repository.LdapRepository;\n\n/**\n * Example repository used with {@link DataLdapTest @DataLdapTest} tests.\n *\n * @author Eddú Meléndez\n */\ninterface ExampleRepository extends LdapRepository<ExampleEntry> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/java/org/springframework/boot/data/ldap/test/autoconfigure/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.ldap.test.autoconfigure;\n\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.query.LdapQuery;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataLdapTest @DataLdapTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Service\npublic class ExampleService {\n\n\tprivate final LdapTemplate ldapTemplate;\n\n\tpublic ExampleService(LdapTemplate ldapTemplate) {\n\t\tthis.ldapTemplate = ldapTemplate;\n\t}\n\n\tpublic boolean hasEntry(LdapQuery query) {\n\t\treturn this.ldapTemplate.find(query, ExampleEntry.class).size() == 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-ldap-test/src/test/resources/org/springframework/boot/data/ldap/test/autoconfigure/schema.ldif",
    "content": "dn: dc=spring,dc=org\nobjectclass: top\nobjectclass: domain\nobjectclass: extensibleObject\ndc: spring\n\ndn: ou=groups,dc=spring,dc=org\nobjectclass: top\nobjectclass: organizationalUnit\nou: groups\n\ndn: cn=ROLE_USER,ou=groups,dc=spring,dc=org\nobjectclass: top\nobjectclass: groupOfUniqueNames\ncn: ROLE_USER\nuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\nuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\nuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\nuniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org\n\ndn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org\nobjectclass: top\nobjectclass: groupOfUniqueNames\ncn: ROLE_ADMIN\nuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\ndn: c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: country\nc: Sweden\ndescription: The country of Sweden\n\ndn: ou=company1,c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: organizationalUnit\nou: company1\ndescription: First company in Sweden\n\ndn: cn=Alice Smith,ou=company1,c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: alice.smith\nuserPassword: password\ncn: Alice Smith\nsn: Alice Smith\ndescription: Sweden, Company1, Alice Smith\ntelephoneNumber: +46 555-123456\n\ndn: cn=Bob Smith,ou=company1,c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: bob.smith\nuserPassword: password\ncn: Bob Smith\nsn: Bob Smith\ndescription: Sweden, Company1, Some Person2\ntelephoneNumber: +46 555-654321\n\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data MongoDB\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-mongodb\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.data:spring-data-mongodb\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(\"org.mongodb:mongodb-driver-reactivestreams\")\n\toptional(\"org.mongodb:mongodb-driver-sync\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.client.MongoClient;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.mongodb.autoconfigure.MongoProperties;\nimport org.springframework.boot.mongodb.autoconfigure.PropertiesMongoConnectionDetails;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.gridfs.GridFsTemplate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's MongoDB support.\n * <p>\n * Registers a {@link MongoTemplate} and {@link GridFsTemplate} beans if no other beans of\n * the same type are configured.\n * <p>\n * Honors the {@literal spring.mongodb.database} property if set, otherwise connects to\n * the {@literal test} database.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Josh Long\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Christoph Strobl\n * @since 4.0.0\n */\n@AutoConfiguration(after = MongoAutoConfiguration.class)\n@ConditionalOnClass({ MongoClient.class, MongoTemplate.class })\n@EnableConfigurationProperties({ MongoProperties.class, DataMongoProperties.class })\n@Import({ DataMongoConfiguration.class, MongoDatabaseFactoryConfiguration.class,\n\t\tMongoDatabaseFactoryDependentConfiguration.class })\npublic final class DataMongoAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(MongoConnectionDetails.class)\n\tPropertiesMongoConnectionDetails mongoConnectionDetails(MongoProperties properties,\n\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesMongoConnectionDetails(properties, sslBundles.getIfAvailable());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.mapping.model.FieldNamingStrategy;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.MongoManagedTypes;\nimport org.springframework.data.mongodb.core.convert.DbRefResolver;\nimport org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;\nimport org.springframework.data.mongodb.core.convert.MappingMongoConverter;\nimport org.springframework.data.mongodb.core.convert.MongoConverter;\nimport org.springframework.data.mongodb.core.convert.MongoCustomConversions;\nimport org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;\nimport org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;\nimport org.springframework.data.mongodb.core.mapping.Document;\nimport org.springframework.data.mongodb.core.mapping.MongoMappingContext;\n\n/**\n * Base configuration class for Spring Data's mongo support.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author Scott Fredericks\n */\n@Configuration(proxyBeanMethods = false)\nclass DataMongoConfiguration {\n\n\tprivate final DataMongoProperties properties;\n\n\tDataMongoConfiguration(DataMongoProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tstatic MongoManagedTypes mongoManagedTypes(ApplicationContext applicationContext) throws ClassNotFoundException {\n\t\treturn MongoManagedTypes.fromIterable(new EntityScanner(applicationContext).scan(Document.class));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMongoMappingContext mongoMappingContext(MongoCustomConversions conversions, MongoManagedTypes managedTypes) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tMongoMappingContext context = new MongoMappingContext();\n\t\tmap.from(this.properties.isAutoIndexCreation()).to(context::setAutoIndexCreation);\n\t\tcontext.setManagedTypes(managedTypes);\n\t\tClass<?> strategyClass = this.properties.getFieldNamingStrategy();\n\t\tif (strategyClass != null) {\n\t\t\tcontext.setFieldNamingStrategy((FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass));\n\t\t}\n\t\tcontext.setSimpleTypeHolder(conversions.getSimpleTypeHolder());\n\t\treturn context;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMongoCustomConversions mongoCustomConversions() {\n\t\treturn MongoCustomConversions.create(this::configureConversions);\n\t}\n\n\tprivate void configureConversions(MongoConverterConfigurationAdapter configurer) {\n\t\tPropertyMapper.get().from(this.properties.getRepresentation()::getBigDecimal).to(configurer::bigDecimal);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(MongoConverter.class)\n\tMappingMongoConverter mappingMongoConverter(ObjectProvider<MongoDatabaseFactory> factory,\n\t\t\tMongoMappingContext context, MongoCustomConversions conversions) {\n\t\tMongoDatabaseFactory mongoDatabaseFactory = factory.getIfAvailable();\n\t\tDbRefResolver dbRefResolver = (mongoDatabaseFactory != null) ? new DefaultDbRefResolver(mongoDatabaseFactory)\n\t\t\t\t: NoOpDbRefResolver.INSTANCE;\n\t\tMappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);\n\t\tmappingConverter.setCustomConversions(conversions);\n\t\treturn mappingConverter;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.data.mongodb.core.convert.MongoCustomConversions.BigDecimalRepresentation;\n\n/**\n * Configuration properties for Spring Data MongoDB.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.mongodb\")\npublic class DataMongoProperties {\n\n\t/**\n\t * Whether to enable auto-index creation.\n\t */\n\tprivate @Nullable Boolean autoIndexCreation;\n\n\t/**\n\t * Fully qualified name of the FieldNamingStrategy to use.\n\t */\n\tprivate @Nullable Class<?> fieldNamingStrategy;\n\n\tprivate final Gridfs gridfs = new Gridfs();\n\n\tprivate final Representation representation = new Representation();\n\n\tpublic @Nullable Boolean isAutoIndexCreation() {\n\t\treturn this.autoIndexCreation;\n\t}\n\n\tpublic void setAutoIndexCreation(@Nullable Boolean autoIndexCreation) {\n\t\tthis.autoIndexCreation = autoIndexCreation;\n\t}\n\n\tpublic @Nullable Class<?> getFieldNamingStrategy() {\n\t\treturn this.fieldNamingStrategy;\n\t}\n\n\tpublic void setFieldNamingStrategy(@Nullable Class<?> fieldNamingStrategy) {\n\t\tthis.fieldNamingStrategy = fieldNamingStrategy;\n\t}\n\n\tpublic Gridfs getGridfs() {\n\t\treturn this.gridfs;\n\t}\n\n\tpublic Representation getRepresentation() {\n\t\treturn this.representation;\n\t}\n\n\tpublic static class Gridfs {\n\n\t\t/**\n\t\t * GridFS database name.\n\t\t */\n\t\tprivate @Nullable String database;\n\n\t\t/**\n\t\t * GridFS bucket name.\n\t\t */\n\t\tprivate @Nullable String bucket;\n\n\t\tpublic @Nullable String getDatabase() {\n\t\t\treturn this.database;\n\t\t}\n\n\t\tpublic void setDatabase(@Nullable String database) {\n\t\t\tthis.database = database;\n\t\t}\n\n\t\tpublic @Nullable String getBucket() {\n\t\t\treturn this.bucket;\n\t\t}\n\n\t\tpublic void setBucket(@Nullable String bucket) {\n\t\t\tthis.bucket = bucket;\n\t\t}\n\n\t}\n\n\tpublic static class Representation {\n\n\t\t/**\n\t\t * Representation to use when converting a BigDecimal.\n\t\t */\n\t\tprivate @Nullable BigDecimalRepresentation bigDecimal = BigDecimalRepresentation.UNSPECIFIED;\n\n\t\tpublic @Nullable BigDecimalRepresentation getBigDecimal() {\n\t\t\treturn this.bigDecimal;\n\t\t}\n\n\t\tpublic void setBigDecimal(@Nullable BigDecimalRepresentation bigDecimal) {\n\t\t\tthis.bigDecimal = bigDecimal;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoReactiveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport java.util.Optional;\n\nimport com.mongodb.ClientSessionOptions;\nimport com.mongodb.reactivestreams.client.ClientSession;\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport com.mongodb.reactivestreams.client.MongoDatabase;\nimport org.bson.codecs.Codec;\nimport org.bson.codecs.configuration.CodecRegistry;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.data.mongodb.autoconfigure.DataMongoProperties.Gridfs;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.mongodb.autoconfigure.MongoProperties;\nimport org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.io.buffer.DataBufferFactory;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.dao.support.PersistenceExceptionTranslator;\nimport org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.ReactiveMongoOperations;\nimport org.springframework.data.mongodb.core.ReactiveMongoTemplate;\nimport org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.convert.MappingMongoConverter;\nimport org.springframework.data.mongodb.core.convert.MongoConverter;\nimport org.springframework.data.mongodb.gridfs.ReactiveGridFsOperations;\nimport org.springframework.data.mongodb.gridfs.ReactiveGridFsTemplate;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive mongo\n * support.\n * <p>\n * Registers a {@link ReactiveMongoTemplate} bean if no other bean of the same type is\n * configured.\n *\n * @author Mark Paluch\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(after = MongoReactiveAutoConfiguration.class)\n@ConditionalOnClass({ MongoClient.class, ReactiveMongoTemplate.class })\n@ConditionalOnBean(MongoClient.class)\n@EnableConfigurationProperties({ MongoProperties.class, DataMongoProperties.class })\n@Import(DataMongoConfiguration.class)\npublic final class DataMongoReactiveAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveMongoDatabaseFactory.class)\n\tSimpleReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory(MongoProperties properties, MongoClient mongo,\n\t\t\tMongoConnectionDetails connectionDetails) {\n\t\tString database = properties.getDatabase();\n\t\tif (database == null) {\n\t\t\tdatabase = connectionDetails.getConnectionString().getDatabase();\n\t\t}\n\t\tAssert.hasText(database, \"Database name must not be empty\");\n\t\treturn new SimpleReactiveMongoDatabaseFactory(mongo, database);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveMongoOperations.class)\n\tReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory,\n\t\t\tMongoConverter converter) {\n\t\treturn new ReactiveMongoTemplate(reactiveMongoDatabaseFactory, converter);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(DataBufferFactory.class)\n\tDefaultDataBufferFactory dataBufferFactory() {\n\t\treturn new DefaultDataBufferFactory();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveGridFsOperations.class)\n\tReactiveGridFsTemplate reactiveGridFsTemplate(DataMongoProperties dataProperties,\n\t\t\tReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory, MappingMongoConverter mappingMongoConverter,\n\t\t\tDataBufferFactory dataBufferFactory) {\n\t\treturn new ReactiveGridFsTemplate(dataBufferFactory,\n\t\t\t\tnew GridFsReactiveMongoDatabaseFactory(reactiveMongoDatabaseFactory, dataProperties),\n\t\t\t\tmappingMongoConverter, dataProperties.getGridfs().getBucket());\n\t}\n\n\t/**\n\t * {@link ReactiveMongoDatabaseFactory} decorator to use {@link Gridfs#getDatabase()}\n\t * from the {@link MongoProperties} when set.\n\t */\n\tstatic class GridFsReactiveMongoDatabaseFactory implements ReactiveMongoDatabaseFactory {\n\n\t\tprivate final ReactiveMongoDatabaseFactory delegate;\n\n\t\tprivate final DataMongoProperties properties;\n\n\t\tGridFsReactiveMongoDatabaseFactory(ReactiveMongoDatabaseFactory delegate, DataMongoProperties properties) {\n\t\t\tthis.delegate = delegate;\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasCodecFor(Class<?> type) {\n\t\t\treturn this.delegate.hasCodecFor(type);\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<MongoDatabase> getMongoDatabase() throws DataAccessException {\n\t\t\tString gridFsDatabase = getGridFsDatabase();\n\t\t\tif (StringUtils.hasText(gridFsDatabase)) {\n\t\t\t\treturn this.delegate.getMongoDatabase(gridFsDatabase);\n\t\t\t}\n\t\t\treturn this.delegate.getMongoDatabase();\n\t\t}\n\n\t\tprivate @Nullable String getGridFsDatabase() {\n\t\t\treturn this.properties.getGridfs().getDatabase();\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<MongoDatabase> getMongoDatabase(String dbName) throws DataAccessException {\n\t\t\treturn this.delegate.getMongoDatabase(dbName);\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> Optional<Codec<T>> getCodecFor(Class<T> type) {\n\t\t\treturn this.delegate.getCodecFor(type);\n\t\t}\n\n\t\t@Override\n\t\tpublic PersistenceExceptionTranslator getExceptionTranslator() {\n\t\t\treturn this.delegate.getExceptionTranslator();\n\t\t}\n\n\t\t@Override\n\t\tpublic CodecRegistry getCodecRegistry() {\n\t\t\treturn this.delegate.getCodecRegistry();\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<ClientSession> getSession(ClientSessionOptions options) {\n\t\t\treturn this.delegate.getSession(options);\n\t\t}\n\n\t\t@Override\n\t\tpublic ReactiveMongoDatabaseFactory withSession(ClientSession session) {\n\t\t\treturn this.delegate.withSession(session);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isTransactionActive() {\n\t\t\treturn this.delegate.isTransactionActive();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoReactiveRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.reactivestreams.client.MongoClient;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;\nimport org.springframework.data.mongodb.repository.config.ReactiveMongoRepositoryConfigurationExtension;\nimport org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Mongo Reactive\n * Repositories.\n * <p>\n * Activates when there is no bean of type\n * {@link org.springframework.data.mongodb.repository.support.ReactiveMongoRepositoryFactoryBean}\n * configured in the context, the Spring Data Mongo {@link ReactiveMongoRepository} type\n * is on the classpath, the ReactiveStreams Mongo client driver API is on the classpath,\n * and there is no other configured {@link ReactiveMongoRepository}.\n * <p>\n * Once in effect, the auto-configuration is the equivalent of enabling Mongo repositories\n * using the {@link EnableReactiveMongoRepositories @EnableReactiveMongoRepositories}\n * annotation.\n *\n * @author Mark Paluch\n * @since 4.0.0\n * @see EnableReactiveMongoRepositories\n */\n@AutoConfiguration(after = DataMongoReactiveAutoConfiguration.class)\n@ConditionalOnClass({ MongoClient.class, ReactiveMongoRepository.class })\n@ConditionalOnMissingBean({ ReactiveMongoRepositoryFactoryBean.class,\n\t\tReactiveMongoRepositoryConfigurationExtension.class })\n@ConditionalOnRepositoryType(store = \"mongodb\", type = RepositoryType.REACTIVE)\n@Import(DataMongoReactiveRepositoriesRegistrar.class)\npublic final class DataMongoReactiveRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoReactiveRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;\nimport org.springframework.data.mongodb.repository.config.ReactiveMongoRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Mongo Reactive\n * Repositories.\n *\n * @author Mark Paluch\n */\nclass DataMongoReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableReactiveMongoRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableReactiveMongoRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new ReactiveMongoRepositoryConfigurationExtension();\n\t}\n\n\t@EnableReactiveMongoRepositories\n\tprivate static final class EnableReactiveMongoRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.client.MongoClient;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.mongodb.repository.MongoRepository;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\nimport org.springframework.data.mongodb.repository.config.MongoRepositoryConfigurationExtension;\nimport org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Mongo\n * Repositories.\n * <p>\n * Activates when there is no bean of type\n * {@link org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean}\n * configured in the context, the Spring Data Mongo\n * {@link org.springframework.data.mongodb.repository.MongoRepository} type is on the\n * classpath, the Mongo client driver API is on the classpath, and there is no other\n * configured {@link org.springframework.data.mongodb.repository.MongoRepository}.\n * <p>\n * Once in effect, the auto-configuration is the equivalent of enabling Mongo repositories\n * using the {@link EnableMongoRepositories @EnableMongoRepositories} annotation.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Josh Long\n * @since 4.0.0\n * @see EnableMongoRepositories\n */\n@AutoConfiguration(after = DataMongoAutoConfiguration.class)\n@ConditionalOnClass({ MongoClient.class, MongoRepository.class })\n@ConditionalOnMissingBean({ MongoRepositoryFactoryBean.class, MongoRepositoryConfigurationExtension.class })\n@ConditionalOnRepositoryType(store = \"mongodb\", type = RepositoryType.IMPERATIVE)\n@Import(DataMongoRepositoriesRegistrar.class)\npublic final class DataMongoRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\nimport org.springframework.data.mongodb.repository.config.MongoRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Mongo\n * Repositories.\n *\n * @author Dave Syer\n */\nclass DataMongoRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableMongoRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableMongoRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new MongoRepositoryConfigurationExtension();\n\t}\n\n\t@EnableMongoRepositories\n\tprivate static final class EnableMongoRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDatabaseFactoryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.client.MongoClient;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.mongodb.autoconfigure.MongoProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.MongoDatabaseFactorySupport;\nimport org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration for a {@link MongoDatabaseFactory}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(MongoDatabaseFactory.class)\n@ConditionalOnSingleCandidate(MongoClient.class)\nclass MongoDatabaseFactoryConfiguration {\n\n\t@Bean\n\tMongoDatabaseFactorySupport<?> mongoDatabaseFactory(MongoClient mongoClient, MongoProperties properties,\n\t\t\tMongoConnectionDetails connectionDetails) {\n\t\tString database = properties.getDatabase();\n\t\tif (database == null) {\n\t\t\tdatabase = connectionDetails.getConnectionString().getDatabase();\n\t\t}\n\t\tAssert.hasText(database, \"Database name must not be empty\");\n\t\treturn new SimpleMongoClientDatabaseFactory(mongoClient, database);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDatabaseFactoryDependentConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.ClientSessionOptions;\nimport com.mongodb.client.ClientSession;\nimport com.mongodb.client.MongoDatabase;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.data.mongodb.autoconfigure.DataMongoProperties.Gridfs;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.dao.support.PersistenceExceptionTranslator;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.MongoOperations;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.convert.MongoConverter;\nimport org.springframework.data.mongodb.gridfs.GridFsOperations;\nimport org.springframework.data.mongodb.gridfs.GridFsTemplate;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration for Mongo-related beans that depend on a {@link MongoDatabaseFactory}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBean(MongoDatabaseFactory.class)\nclass MongoDatabaseFactoryDependentConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(MongoOperations.class)\n\tMongoTemplate mongoTemplate(MongoDatabaseFactory factory, MongoConverter converter) {\n\t\treturn new MongoTemplate(factory, converter);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(GridFsOperations.class)\n\tGridFsTemplate gridFsTemplate(DataMongoProperties properties, MongoDatabaseFactory factory,\n\t\t\tMongoTemplate mongoTemplate) {\n\t\treturn new GridFsTemplate(new GridFsMongoDatabaseFactory(factory, properties), mongoTemplate.getConverter(),\n\t\t\t\tproperties.getGridfs().getBucket());\n\t}\n\n\t/**\n\t * {@link MongoDatabaseFactory} decorator to respect {@link Gridfs#getDatabase()} if\n\t * set.\n\t */\n\tstatic class GridFsMongoDatabaseFactory implements MongoDatabaseFactory {\n\n\t\tprivate final MongoDatabaseFactory mongoDatabaseFactory;\n\n\t\tprivate final DataMongoProperties properties;\n\n\t\tGridFsMongoDatabaseFactory(MongoDatabaseFactory mongoDatabaseFactory, DataMongoProperties properties) {\n\t\t\tAssert.notNull(mongoDatabaseFactory, \"'mongoDatabaseFactory' must not be null\");\n\t\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\t\tthis.mongoDatabaseFactory = mongoDatabaseFactory;\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic MongoDatabase getMongoDatabase() throws DataAccessException {\n\t\t\tString gridFsDatabase = getGridFsDatabase();\n\t\t\tif (StringUtils.hasText(gridFsDatabase)) {\n\t\t\t\treturn this.mongoDatabaseFactory.getMongoDatabase(gridFsDatabase);\n\t\t\t}\n\t\t\treturn this.mongoDatabaseFactory.getMongoDatabase();\n\t\t}\n\n\t\t@Override\n\t\tpublic MongoDatabase getMongoDatabase(String dbName) throws DataAccessException {\n\t\t\treturn this.mongoDatabaseFactory.getMongoDatabase(dbName);\n\t\t}\n\n\t\t@Override\n\t\tpublic PersistenceExceptionTranslator getExceptionTranslator() {\n\t\t\treturn this.mongoDatabaseFactory.getExceptionTranslator();\n\t\t}\n\n\t\t@Override\n\t\tpublic ClientSession getSession(ClientSessionOptions options) {\n\t\t\treturn this.mongoDatabaseFactory.getSession(options);\n\t\t}\n\n\t\t@Override\n\t\tpublic MongoDatabaseFactory withSession(ClientSession session) {\n\t\t\treturn this.mongoDatabaseFactory.withSession(session);\n\t\t}\n\n\t\tprivate @Nullable String getGridFsDatabase() {\n\t\t\treturn this.properties.getGridfs().getDatabase();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data MongoDB.\n */\n@NullMarked\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n  \t{\n      \"name\": \"management.health.mongo.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.health.mongodb.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.health.mongodb.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable MongoDB health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.data.mongodb.grid-fs-database\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.mongodb.gridfs.database\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.repositories.type\",\n      \"type\": \"org.springframework.boot.autoconfigure.data.RepositoryType\",\n      \"description\": \"Type of Mongo repositories to enable.\",\n      \"defaultValue\": \"auto\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.data.mongodb.field-naming-strategy\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"org.springframework.data.mapping.model.FieldNamingStrategy\"\n          }\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.mongodb.autoconfigure.DataMongoAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoReactiveAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/alt/CityMongoDbRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.alt;\n\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.City;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityMongoDbRepository extends Repository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/alt/ReactiveCityMongoDbRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.alt;\n\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.City;\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface ReactiveCityMongoDbRepository extends ReactiveCrudRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/alt/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.mongodb.alt;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport java.time.LocalDateTime;\nimport java.util.Arrays;\nimport java.util.function.Supplier;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoClients;\nimport com.mongodb.client.MongoCollection;\nimport com.mongodb.client.gridfs.GridFSBucket;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.City;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.country.Country;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.mongodb.autoconfigure.PropertiesMongoConnectionDetails;\nimport org.springframework.boot.persistence.autoconfigure.EntityScan;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;\nimport org.springframework.data.mapping.model.FieldNamingStrategy;\nimport org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;\nimport org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;\nimport org.springframework.data.mongodb.core.convert.MappingMongoConverter;\nimport org.springframework.data.mongodb.core.convert.MongoCustomConversions;\nimport org.springframework.data.mongodb.core.mapping.MongoMappingContext;\nimport org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;\nimport org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;\nimport org.springframework.data.mongodb.gridfs.GridFsTemplate;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataMongoAutoConfiguration}.\n *\n * @author Josh Long\n * @author Oliver Gierke\n * @author Mark Paluch\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass DataMongoAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tMongoAutoConfiguration.class, DataMongoAutoConfiguration.class));\n\n\t@Test\n\tvoid templateExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoTemplate.class));\n\t}\n\n\t@Test\n\tvoid whenGridFsDatabaseIsConfiguredThenGridFsTemplateIsAutoConfiguredAndUsesIt() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.gridfs.database:grid\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GridFsTemplate.class);\n\t\t\tGridFsTemplate template = context.getBean(GridFsTemplate.class);\n\t\t\tGridFSBucket bucket = getBucket(template);\n\t\t\tassertThat(bucket).extracting(\"filesCollection\", InstanceOfAssertFactories.type(MongoCollection.class))\n\t\t\t\t.extracting((collection) -> collection.getNamespace().getDatabaseName())\n\t\t\t\t.isEqualTo(\"grid\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenGridFsBucketIsConfiguredThenGridFsTemplateIsAutoConfiguredAndUsesIt() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.gridfs.bucket:test-bucket\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GridFsTemplate.class);\n\t\t\tGridFsTemplate template = context.getBean(GridFsTemplate.class);\n\t\t\tGridFSBucket bucket = getBucket(template);\n\t\t\tassertThat(bucket.getBucketName()).isEqualTo(\"test-bucket\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customConversions() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConversionsConfig.class).run((context) -> {\n\t\t\tMongoTemplate template = context.getBean(MongoTemplate.class);\n\t\t\tassertThat(template.getConverter().getConversionService().canConvert(MongoClient.class, Boolean.class))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\")\n\tvoid customBigDecimalDeprecatedRepresentation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.representation.big-decimal=string\")\n\t\t\t.run((context) -> assertThat(context.getBean(MongoCustomConversions.class)).extracting(\"converters\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.map((converter) -> converter.getClass().getName())\n\t\t\t\t.anySatisfy((className) -> assertThat(className).contains(\"BigDecimalToStringConverter\"))\n\t\t\t\t.anySatisfy((className) -> assertThat(className).contains(\"BigIntegerToStringConverter\")));\n\t}\n\n\t@Test\n\tvoid customBigDecimalRepresentation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.representation.big-decimal=decimal128\")\n\t\t\t.run((context) -> assertThat(context.getBean(MongoCustomConversions.class)).extracting(\"converters\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.map((converter) -> converter.getClass().getName())\n\t\t\t\t.anySatisfy((className) -> assertThat(className).contains(\"BigDecimalToDecimal128Converter\"))\n\t\t\t\t.anySatisfy((className) -> assertThat(className).contains(\"BigIntegerToDecimal128Converter\")));\n\t}\n\n\t@Test\n\tvoid defaultBigDecimalRepresentation() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.getBean(MongoCustomConversions.class)).extracting(\"converters\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.map((converter) -> converter.getClass().getName())\n\t\t\t\t.filteredOn((className) -> className.startsWith(\"org.springframework.data.mongodb\"))\n\t\t\t\t.noneSatisfy((className) -> assertThat(className).contains(\"BigDecimalTo\"))\n\t\t\t\t.noneSatisfy((className) -> assertThat(className).contains(\"BigIntegerTo\")));\n\t}\n\n\t@Test\n\tvoid usesAutoConfigurationPackageToPickUpDocumentTypes() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tString cityPackage = City.class.getPackage().getName();\n\t\tAutoConfigurationPackages.register(context, cityPackage);\n\t\tcontext.register(MongoAutoConfiguration.class, DataMongoAutoConfiguration.class);\n\t\ttry {\n\t\t\tcontext.refresh();\n\t\t\tassertDomainTypesDiscovered(context.getBean(MongoMappingContext.class), City.class);\n\t\t}\n\t\tfinally {\n\t\t\tcontext.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultFieldNamingStrategy() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tFieldNamingStrategy fieldNamingStrategy = getFieldNamingStrategy(mappingContext);\n\t\t\tassertThat(fieldNamingStrategy.getClass()).isEqualTo(PropertyNameFieldNamingStrategy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customFieldNamingStrategy() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.mongodb.field-naming-strategy:\"\n\t\t\t\t\t+ CamelCaseAbbreviatingFieldNamingStrategy.class.getName())\n\t\t\t.run((context) -> {\n\t\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\t\tFieldNamingStrategy fieldNamingStrategy = getFieldNamingStrategy(mappingContext);\n\t\t\t\tassertThat(fieldNamingStrategy.getClass()).isEqualTo(CamelCaseAbbreviatingFieldNamingStrategy.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultAutoIndexCreation() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tassertThat(mappingContext.isAutoIndexCreation()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customAutoIndexCreation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.autoIndexCreation:true\").run((context) -> {\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tassertThat(mappingContext.isAutoIndexCreation()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid interfaceFieldNamingStrategy() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.mongodb.field-naming-strategy:\" + FieldNamingStrategy.class.getName())\n\t\t\t.run((context) -> assertThat(context).getFailure().isInstanceOf(BeanCreationException.class));\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetManagedTypes() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\tassertThat(managedTypes.toList()).containsOnly(City.class, Country.class);\n\t\t});\n\n\t}\n\n\t@Test\n\tvoid registersDefaultSimpleTypesWithMappingContext() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tMongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(Sample.class);\n\t\t\tassertThat(entity).isNotNull();\n\t\t\tMongoPersistentProperty dateProperty = entity.getPersistentProperty(\"date\");\n\t\t\tassertThat(dateProperty).isNotNull();\n\t\t\tassertThat(dateProperty.isEntity()).isFalse();\n\t\t});\n\n\t}\n\n\t@Test\n\tvoid backsOffIfMongoClientBeanIsNotPresent() {\n\t\tApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(DataMongoAutoConfiguration.class));\n\t\trunner.run((context) -> assertThat(context).doesNotHaveBean(MongoTemplate.class));\n\t}\n\n\t@Test\n\tvoid createsMongoDatabaseFactoryForPreferredMongoClient() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMongoDatabaseFactory dbFactory = context.getBean(MongoDatabaseFactory.class);\n\t\t\tassertThat(dbFactory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid createsMongoDatabaseFactoryForFallbackMongoClient() {\n\t\tthis.contextRunner.withUserConfiguration(FallbackMongoClientConfiguration.class).run((context) -> {\n\t\t\tMongoDatabaseFactory dbFactory = context.getBean(MongoDatabaseFactory.class);\n\t\t\tassertThat(dbFactory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresIfUserProvidesMongoDatabaseFactoryButNoClient() {\n\t\tthis.contextRunner.withUserConfiguration(MongoDatabaseFactoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoTemplate.class));\n\t}\n\n\t@Test\n\tvoid databaseHasDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMongoDatabaseFactory factory = context.getBean(MongoDatabaseFactory.class);\n\t\t\tassertThat(factory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t\tassertThat(factory.getMongoDatabase().getName()).isEqualTo(\"test\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid databasePropertyIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.database=mydb\").run((context) -> {\n\t\t\tMongoDatabaseFactory factory = context.getBean(MongoDatabaseFactory.class);\n\t\t\tassertThat(factory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t\tassertThat(factory.getMongoDatabase().getName()).isEqualTo(\"mydb\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid databaseInUriPropertyIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/mydb\").run((context) -> {\n\t\t\tMongoDatabaseFactory factory = context.getBean(MongoDatabaseFactory.class);\n\t\t\tassertThat(factory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t\tassertThat(factory.getMongoDatabase().getName()).isEqualTo(\"mydb\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid databasePropertyOverridesUriProperty() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/notused\",\n\t\t\t\t\t\"spring.mongodb.database=mydb\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoDatabaseFactory factory = context.getBean(MongoDatabaseFactory.class);\n\t\t\t\tassertThat(factory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t\t\tassertThat(factory.getMongoDatabase().getName()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid databasePropertyIsUsedWhenNoDatabaseInUri() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/\", \"spring.mongodb.database=mydb\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoDatabaseFactory factory = context.getBean(MongoDatabaseFactory.class);\n\t\t\t\tassertThat(factory).isInstanceOf(SimpleMongoClientDatabaseFactory.class);\n\t\t\t\tassertThat(factory.getMongoDatabase().getName()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextFailsWhenDatabaseNotSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/\")\n\t\t\t.run((context) -> assertThat(context).getFailure().hasMessageContaining(\"Database name must not be empty\"));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesMongoConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(MongoConnectionDetails.class, () -> new MongoConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic ConnectionString getConnectionString() {\n\t\t\t\treturn new ConnectionString(\"mongodb://localhost/testdb\");\n\t\t\t}\n\n\t\t})\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesMongoConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid mappingMongoConverterHasADefaultDbRefResolver() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMappingMongoConverter converter = context.getBean(MappingMongoConverter.class);\n\t\t\tassertThat(converter).extracting(\"dbRefResolver\").isInstanceOf(DefaultDbRefResolver.class);\n\t\t});\n\t}\n\n\tprivate static void assertDomainTypesDiscovered(MongoMappingContext mappingContext, Class<?>... types) {\n\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\tassertThat(managedTypes).isNotNull();\n\t\tassertThat(managedTypes.toList()).containsOnly(types);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate GridFSBucket getBucket(GridFsTemplate template) {\n\t\tSupplier<GridFSBucket> field = (Supplier<GridFSBucket>) ReflectionTestUtils.getField(template,\n\t\t\t\t\"bucketSupplier\");\n\t\tassertThat(field).isNotNull();\n\t\treturn field.get();\n\t}\n\n\tprivate FieldNamingStrategy getFieldNamingStrategy(MongoMappingContext mappingContext) {\n\t\tObject field = ReflectionTestUtils.getField(mappingContext, \"fieldNamingStrategy\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (FieldNamingStrategy) field;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConversionsConfig {\n\n\t\t@Bean\n\t\tMongoCustomConversions customConversions() {\n\t\t\treturn new MongoCustomConversions(Arrays.asList(new MyConverter()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(\"org.springframework.boot.data.mongodb.autoconfigure\")\n\tstatic class EntityScanConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FallbackMongoClientConfiguration {\n\n\t\t@Bean\n\t\tcom.mongodb.client.MongoClient fallbackMongoClient() {\n\t\t\treturn MongoClients.create();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MongoDatabaseFactoryConfiguration {\n\n\t\t@Bean\n\t\tMongoDatabaseFactory mongoDatabaseFactory() {\n\t\t\treturn new SimpleMongoClientDatabaseFactory(MongoClients.create(), \"test\");\n\t\t}\n\n\t}\n\n\tstatic class MyConverter implements Converter<MongoClient, @Nullable Boolean> {\n\n\t\t@Override\n\t\tpublic @Nullable Boolean convert(MongoClient source) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class Sample {\n\n\t\t@Nullable LocalDateTime date;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.data.mongodb.core.convert.MongoCustomConversions.BigDecimalRepresentation;\nimport org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataMongoProperties}.\n *\n * @author Andy Wilkinson\n */\nclass DataMongoPropertiesTests {\n\n\t@Test\n\tvoid canBindAutoIndexCreation() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(DataMongoAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.data.mongodb.auto-index-creation=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tDataMongoProperties properties = context.getBean(DataMongoProperties.class);\n\t\t\t\tassertThat(properties.isAutoIndexCreation()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultBigDecimalRepresentationIsAlignedWithSpringData() {\n\t\tBigDecimalRepresentation springDataDefault = springDataDefaultBigDecimalRepresentation();\n\t\tBigDecimalRepresentation springBootDefault = new DataMongoProperties().getRepresentation().getBigDecimal();\n\t\tassertThat(springBootDefault).isEqualTo(springDataDefault);\n\t}\n\n\tprivate BigDecimalRepresentation springDataDefaultBigDecimalRepresentation() {\n\t\tObject field = ReflectionTestUtils.getField(new MongoConverterConfigurationAdapter(), \"bigDecimals\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (BigDecimalRepresentation) field;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoReactiveAndBlockingRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.CityRepository;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportSelector;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\nimport org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataMongoRepositoriesAutoConfiguration} and\n * {@link DataMongoReactiveRepositoriesAutoConfiguration}.\n *\n * @author Mark Paluch\n */\nclass DataMongoReactiveAndBlockingRepositoriesAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid shouldCreateInstancesForReactiveAndBlockingRepositories() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(BlockingAndReactiveConfiguration.class, BaseConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(CityRepository.class)).isNotNull();\n\t\tassertThat(this.context.getBean(ReactiveCityRepository.class)).isNotNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(MongoAutoConfiguration.class)\n\t@EnableMongoRepositories(basePackageClasses = ReactiveCityRepository.class)\n\t@EnableReactiveMongoRepositories(basePackageClasses = ReactiveCityRepository.class)\n\tstatic class BlockingAndReactiveConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(Registrar.class)\n\tstatic class BaseConfiguration {\n\n\t}\n\n\tstatic class Registrar implements ImportSelector {\n\n\t\t@Override\n\t\tpublic String[] selectImports(AnnotationMetadata importingClassMetadata) {\n\t\t\tList<String> names = new ArrayList<>();\n\t\t\tfor (Class<?> type : new Class<?>[] { MongoAutoConfiguration.class, MongoReactiveAutoConfiguration.class,\n\t\t\t\t\tDataMongoAutoConfiguration.class, DataMongoRepositoriesAutoConfiguration.class,\n\t\t\t\t\tDataMongoReactiveAutoConfiguration.class, DataMongoReactiveRepositoriesAutoConfiguration.class }) {\n\t\t\t\tnames.add(type.getName());\n\t\t\t}\n\t\t\treturn StringUtils.toStringArray(names);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport java.time.Duration;\n\nimport com.mongodb.reactivestreams.client.MongoCollection;\nimport com.mongodb.reactivestreams.client.MongoDatabase;\nimport com.mongodb.reactivestreams.client.gridfs.GridFSBucket;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.ReactiveMongoTemplate;\nimport org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;\nimport org.springframework.data.mongodb.core.convert.MappingMongoConverter;\nimport org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;\nimport org.springframework.data.mongodb.gridfs.ReactiveGridFsTemplate;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataMongoReactiveAutoConfiguration}.\n *\n * @author Mark Paluch\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass DataMongoReactiveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tMongoReactiveAutoConfiguration.class, DataMongoReactiveAutoConfiguration.class));\n\n\t@Test\n\tvoid templateExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveMongoTemplate.class));\n\t}\n\n\t@Test\n\tvoid whenNoGridFsDatabaseIsConfiguredTheGridFsTemplateUsesTheMainDatabase() {\n\t\tthis.contextRunner.run((context) -> assertThat(grisFsTemplateDatabaseName(context)).isEqualTo(\"test\"));\n\t}\n\n\t@Test\n\tvoid whenGridFsDatabaseIsConfiguredThenGridFsTemplateUsesIt() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.gridfs.database:grid\")\n\t\t\t.run((context) -> assertThat(grisFsTemplateDatabaseName(context)).isEqualTo(\"grid\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid whenGridFsBucketIsConfiguredThenGridFsTemplateUsesIt() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.mongodb.gridfs.bucket:test-bucket\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveGridFsTemplate.class);\n\t\t\tReactiveGridFsTemplate template = context.getBean(ReactiveGridFsTemplate.class);\n\t\t\tMono<GridFSBucket> field = (Mono<GridFSBucket>) ReflectionTestUtils.getField(template, \"bucketSupplier\");\n\t\t\tassertThat(field).isNotNull();\n\t\t\tGridFSBucket bucket = field.block(Duration.ofSeconds(30));\n\t\t\tassertThat(bucket).isNotNull();\n\t\t\tassertThat(bucket.getBucketName()).isEqualTo(\"test-bucket\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffIfMongoClientBeanIsNotPresent() {\n\t\tApplicationContextRunner runner = new ApplicationContextRunner().withConfiguration(AutoConfigurations\n\t\t\t.of(PropertyPlaceholderAutoConfiguration.class, DataMongoReactiveAutoConfiguration.class));\n\t\trunner.run((context) -> assertThat(context).doesNotHaveBean(DataMongoReactiveAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid databaseHasDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tReactiveMongoDatabaseFactory factory = context.getBean(ReactiveMongoDatabaseFactory.class);\n\t\t\tassertThat(factory).isInstanceOf(SimpleReactiveMongoDatabaseFactory.class);\n\t\t\tMongoDatabase mongoDatabase = factory.getMongoDatabase().block();\n\t\t\tassertThat(mongoDatabase).isNotNull();\n\t\t\tassertThat(mongoDatabase.getName()).isEqualTo(\"test\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid databasePropertyIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.database=mydb\").run((context) -> {\n\t\t\tReactiveMongoDatabaseFactory factory = context.getBean(ReactiveMongoDatabaseFactory.class);\n\t\t\tassertThat(factory).isInstanceOf(SimpleReactiveMongoDatabaseFactory.class);\n\t\t\tMongoDatabase mongoDatabase = factory.getMongoDatabase().block();\n\t\t\tassertThat(mongoDatabase).isNotNull();\n\t\t\tassertThat(mongoDatabase.getName()).isEqualTo(\"mydb\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid databaseInUriPropertyIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/mydb\").run((context) -> {\n\t\t\tReactiveMongoDatabaseFactory factory = context.getBean(ReactiveMongoDatabaseFactory.class);\n\t\t\tassertThat(factory).isInstanceOf(SimpleReactiveMongoDatabaseFactory.class);\n\t\t\tMongoDatabase mongoDatabase = factory.getMongoDatabase().block();\n\t\t\tassertThat(mongoDatabase).isNotNull();\n\t\t\tassertThat(mongoDatabase.getName()).isEqualTo(\"mydb\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid databasePropertyOverridesUriProperty() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/notused\",\n\t\t\t\t\t\"spring.mongodb.database=mydb\")\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveMongoDatabaseFactory factory = context.getBean(ReactiveMongoDatabaseFactory.class);\n\t\t\t\tassertThat(factory).isInstanceOf(SimpleReactiveMongoDatabaseFactory.class);\n\t\t\t\tMongoDatabase mongoDatabase = factory.getMongoDatabase().block();\n\t\t\t\tassertThat(mongoDatabase).isNotNull();\n\t\t\t\tassertThat(mongoDatabase.getName()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid databasePropertyIsUsedWhenNoDatabaseInUri() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/\", \"spring.mongodb.database=mydb\")\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveMongoDatabaseFactory factory = context.getBean(ReactiveMongoDatabaseFactory.class);\n\t\t\t\tassertThat(factory).isInstanceOf(SimpleReactiveMongoDatabaseFactory.class);\n\t\t\t\tMongoDatabase mongoDatabase = factory.getMongoDatabase().block();\n\t\t\t\tassertThat(mongoDatabase).isNotNull();\n\t\t\t\tassertThat(mongoDatabase.getName()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextFailsWhenDatabaseNotSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://mongo.example.com/\")\n\t\t\t.run((context) -> assertThat(context).getFailure().hasMessageContaining(\"Database name must not be empty\"));\n\t}\n\n\t@Test\n\tvoid mappingMongoConverterHasANoOpDbRefResolver() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMappingMongoConverter converter = context.getBean(MappingMongoConverter.class);\n\t\t\tassertThat(converter).extracting(\"dbRefResolver\").isInstanceOf(NoOpDbRefResolver.class);\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate String grisFsTemplateDatabaseName(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(ReactiveGridFsTemplate.class);\n\t\tReactiveGridFsTemplate template = context.getBean(ReactiveGridFsTemplate.class);\n\t\tMono<GridFSBucket> field = (Mono<GridFSBucket>) ReflectionTestUtils.getField(template, \"bucketSupplier\");\n\t\tassertThat(field).isNotNull();\n\t\tGridFSBucket bucket = field.block(Duration.ofSeconds(30));\n\t\tassertThat(bucket).isNotNull();\n\t\tMongoCollection<?> collection = (MongoCollection<?>) ReflectionTestUtils.getField(bucket, \"filesCollection\");\n\t\tassertThat(collection).isNotNull();\n\t\treturn collection.getNamespace().getDatabaseName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoReactiveRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.mongodb.alt.CityMongoDbRepository;\nimport org.springframework.boot.data.mongodb.alt.ReactiveCityMongoDbRepository;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.City;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.data.mongodb.autoconfigure.empty.EmptyDataPackage;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.data.mongodb.core.mapping.MongoMappingContext;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\nimport org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataMongoReactiveRepositoriesAutoConfiguration}.\n *\n * @author Mark Paluch\n * @author Andy Wilkinson\n */\nclass DataMongoReactiveRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, DataMongoAutoConfiguration.class,\n\t\t\t\tMongoReactiveAutoConfiguration.class, DataMongoReactiveAutoConfiguration.class,\n\t\t\t\tDataMongoReactiveRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveCityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(MongoClient.class);\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\tassertThat(managedTypes.toList()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityMongoDbRepository.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid enablingImperativeRepositoriesDisablesReactiveRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.mongodb.repositories.type=imperative\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid enablingNoRepositoriesDisablesReactiveRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.mongodb.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(DataMongoReactiveRepositoriesAutoConfigurationTests.class)\n\t@EnableMongoRepositories(basePackageClasses = CityMongoDbRepository.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t// To not find any repositories\n\t@EnableReactiveMongoRepositories(\"foo.bar\")\n\t@TestAutoConfigurationPackage(DataMongoReactiveRepositoriesAutoConfigurationTests.class)\n\tstatic class SortOfInvalidCustomConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure;\n\nimport com.mongodb.client.MongoClient;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.mongodb.alt.CityMongoDbRepository;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.City;\nimport org.springframework.boot.data.mongodb.autoconfigure.domain.city.CityRepository;\nimport org.springframework.boot.data.mongodb.autoconfigure.empty.EmptyDataPackage;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.data.mongodb.core.mapping.MongoMappingContext;\nimport org.springframework.data.mongodb.repository.config.EnableMongoRepositories;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataMongoRepositoriesAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n */\nclass DataMongoRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, DataMongoAutoConfiguration.class,\n\t\t\t\tDataMongoRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\tassertThat(context).hasSingleBean(MongoClient.class);\n\t\t\tMongoMappingContext mappingContext = context.getBean(MongoMappingContext.class);\n\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\tassertThat(managedTypes.toList()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizedConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CityMongoDbRepository.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid enablingReactiveRepositoriesDisablesImperativeRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.mongodb.repositories.type=reactive\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid enablingNoRepositoriesDisablesImperativeRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.mongodb.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(DataMongoRepositoriesAutoConfigurationTests.class)\n\t@EnableMongoRepositories(basePackageClasses = CityMongoDbRepository.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t// To not find any repositories\n\t@EnableMongoRepositories(\"foo.bar\")\n\t@TestAutoConfigurationPackage(DataMongoRepositoriesAutoConfigurationTests.class)\n\tstatic class SortOfInvalidCustomConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.city;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n@Document\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.city;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tPage<City> findAll(Pageable pageable);\n\n\tPage<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(String name, String country);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/city/PersistentEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.city;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.annotation.Persistent;\n\n@Persistent\npublic class PersistentEntity implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/city/ReactiveCityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.city;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface ReactiveCityRepository extends Repository<City, Long> {\n\n\tFlux<City> findAll();\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/country/Country.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.country;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n@Document\npublic class Country implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tprotected Country() {\n\t}\n\n\tpublic Country(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/country/CountryRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.country;\n\nimport org.springframework.data.repository.Repository;\n\npublic interface CountryRepository extends Repository<Country, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/domain/country/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.mongodb.autoconfigure.domain.country;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.autoconfigure.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.mongodb.autoconfigure.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data MongoDB Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-mongodb\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":module:spring-boot-data-mongodb\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"io.projectreactor:reactor-core\")\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.mongodb:mongodb-driver-reactivestreams\")\n\tdockerTestImplementation(\"org.mongodb:mongodb-driver-sync\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-mongodb\")\n\n\tdockerTestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.mongodb.core.MongoTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Sample test for {@link DataMongoTest @DataMongoTest}.\n *\n * @author Michael Simons\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataMongoTest\n@Testcontainers(disabledWithoutDocker = true)\nclass DataMongoTestIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class);\n\n\t@Autowired\n\tprivate MongoTemplate mongoTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument exampleDocument = new ExampleDocument();\n\t\texampleDocument.setText(\"Look, new @DataMongoTest!\");\n\t\texampleDocument = this.exampleRepository.save(exampleDocument);\n\t\tassertThat(exampleDocument.getId()).isNotNull();\n\t\tassertThat(this.mongoTemplate.collectionExists(\"exampleDocuments\")).isTrue();\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTestReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.mongodb.core.ReactiveMongoTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Sample tests for {@link DataMongoTest @DataMongoTest} using reactive repositories.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataMongoTest\n@Testcontainers(disabledWithoutDocker = true)\nclass DataMongoTestReactiveIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class);\n\n\t@Autowired\n\tprivate ReactiveMongoTemplate mongoTemplate;\n\n\t@Autowired\n\tprivate ExampleReactiveRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument exampleDocument = new ExampleDocument();\n\t\texampleDocument.setText(\"Look, new @DataMongoTest!\");\n\t\texampleDocument = this.exampleRepository.save(exampleDocument).block(Duration.ofSeconds(30));\n\t\tassertThat(exampleDocument).isNotNull();\n\t\tassertThat(exampleDocument.getId()).isNotNull();\n\t\tassertThat(this.mongoTemplate.collectionExists(\"exampleDocuments\").block(Duration.ofSeconds(30))).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for {@link DataMongoTest @DataMongoTest}.\n *\n * @author Michael Simons\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataMongoTest(includeFilters = @Filter(Service.class))\n@Testcontainers(disabledWithoutDocker = true)\nclass DataMongoTestWithIncludeFilterIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class);\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tassertThat(this.service.hasCollection(\"foobar\")).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/ExampleDocument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n/**\n * Example document used with {@link DataMongoTest @DataMongoTest} tests.\n *\n * @author Michael Simons\n */\n@Document(collection = \"exampleDocuments\")\npublic class ExampleDocument {\n\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String text;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/ExampleReactiveRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\n\n/**\n * Example reactive repository used with {@link DataMongoTest @DataMongoTest} tests.\n *\n * @author Stephane Nicoll\n */\ninterface ExampleReactiveRepository extends ReactiveMongoRepository<ExampleDocument, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\n/**\n * Example repository used with {@link DataMongoTest @DataMongoTest} tests.\n *\n * @author Michael Simons\n */\ninterface ExampleRepository extends MongoRepository<ExampleDocument, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataMongoTest @DataMongoTest} tests.\n *\n * @author Michael Simons\n */\n@Service\npublic class ExampleService {\n\n\tprivate final MongoTemplate mongoTemplate;\n\n\tpublic ExampleService(MongoTemplate mongoTemplate) {\n\t\tthis.mongoTemplate = mongoTemplate;\n\t}\n\n\tpublic boolean hasCollection(String collectionName) {\n\t\treturn this.mongoTemplate.collectionExists(collectionName);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/dockerTest/java/org/springframework/boot/data/mongodb/test/autoconfigure/TransactionalDataMongoTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.mongodb.MongoDatabaseFactory;\nimport org.springframework.data.mongodb.MongoTransactionManager;\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for using {@link DataMongoTest @DataMongoTest} with transactions.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\n@DataMongoTest\n@Transactional\n@Testcontainers(disabledWithoutDocker = true)\nclass TransactionalDataMongoTestIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class).withReplicaSet();\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleDocument exampleDocument = new ExampleDocument();\n\t\texampleDocument.setText(\"Look, new @DataMongoTest!\");\n\t\texampleDocument = this.exampleRepository.save(exampleDocument);\n\t\tassertThat(exampleDocument.getId()).isNotNull();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class TransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tMongoTransactionManager mongoTransactionManager(MongoDatabaseFactory dbFactory) {\n\t\t\treturn new MongoTransactionManager(dbFactory);\n\t\t}\n\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class MongoInitializationConfiguration {\n\n\t\t@Bean\n\t\tMongoInitializer mongoInitializer(MongoTemplate template) {\n\t\t\treturn new MongoInitializer(template);\n\t\t}\n\n\t\tstatic class MongoInitializer implements InitializingBean {\n\n\t\t\tprivate final MongoTemplate template;\n\n\t\t\tMongoInitializer(MongoTemplate template) {\n\t\t\t\tthis.template = template;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void afterPropertiesSet() throws Exception {\n\t\t\t\tthis.template.createCollection(\"exampleDocuments\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/main/java/org/springframework/boot/data/mongodb/test/autoconfigure/AutoConfigureDataMongo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data MongoDB\n * tests. Most tests should consider using {@link DataMongoTest @DataMongoTest} rather\n * than using this annotation directly.\n *\n * @author Michael Simons\n * @since 4.0.0\n * @see DataMongoTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataMongo {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/main/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for a MongoDB test that focuses <strong>only</strong> on\n * MongoDB components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data Mongo\n * tests. Similarly, component scanning is limited to Mongo repositories and entities\n * ({@code @Document}).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Michael Simons\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataMongoTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataMongoTypeExcludeFilter.class)\n@AutoConfigureDataMongo\n@ImportAutoConfiguration\npublic @interface DataMongoTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/main/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataMongoTest @DataMongoTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass DataMongoTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataMongoTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/main/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataMongoTest @DataMongoTest}.\n *\n * @author Michael Simons\n */\nclass DataMongoTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataMongoTest> {\n\n\tDataMongoTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/main/java/org/springframework/boot/data/mongodb/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data Mongo tests.\n */\n@NullMarked\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/main/resources/META-INF/spring/org.springframework.boot.data.mongodb.test.autoconfigure.AutoConfigureDataMongo.imports",
    "content": "org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoReactiveAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.mongodb.autoconfigure.DataMongoRepositoriesAutoConfiguration\norg.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration\norg.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/test/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Test application for testing {@link DataMongoTest @DataMongoTest}.\n *\n * @author Michael Simons\n */\n@SpringBootApplication\npublic class DataMongoTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-mongodb-test/src/test/java/org/springframework/boot/data/mongodb/test/autoconfigure/DataMongoTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.mongodb.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataMongoTest#properties properties} attribute of\n * {@link DataMongoTest @DataMongoTest}.\n *\n * @author Artsiom Yudovin\n */\n@DataMongoTest(properties = \"spring.profiles.active=test\")\nclass DataMongoTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataMongoTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data Neo4j\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-neo4j\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.data:spring-data-neo4j\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-neo4j\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/dockerTest/java/org/springframework/boot/data/neo4j/autoconfigure/Neo4jRepositoriesAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.data.neo4j.domain.country.CountryRepository;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test to ensure that the properties get read and applied during the auto-configuration.\n *\n * @author Michael J. Simons\n */\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\nclass Neo4jRepositoriesAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final Neo4jContainer neo4j = TestImage.container(Neo4jContainer.class);\n\n\t@DynamicPropertySource\n\tstatic void neo4jProperties(DynamicPropertyRegistry registry) {\n\t\tregistry.add(\"spring.neo4j.uri\", neo4j::getBoltUrl);\n\t\tregistry.add(\"spring.neo4j.authentication.username\", () -> \"neo4j\");\n\t\tregistry.add(\"spring.neo4j.authentication.password\", neo4j::getAdminPassword);\n\t}\n\n\t@Autowired\n\tprivate CountryRepository countryRepository;\n\n\t@Test\n\tvoid ensureRepositoryIsReady() {\n\t\tassertThat(this.countryRepository.count()).isZero();\n\t}\n\n\t@Configuration\n\t@EnableNeo4jRepositories(basePackageClasses = CountryRepository.class)\n\t@ImportAutoConfiguration({ Neo4jAutoConfiguration.class, DataNeo4jAutoConfiguration.class,\n\t\t\tDataNeo4jRepositoriesAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport java.util.Set;\n\nimport org.neo4j.driver.Driver;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanner;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizers;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.neo4j.aot.Neo4jManagedTypes;\nimport org.springframework.data.neo4j.core.DatabaseSelectionProvider;\nimport org.springframework.data.neo4j.core.Neo4jClient;\nimport org.springframework.data.neo4j.core.Neo4jOperations;\nimport org.springframework.data.neo4j.core.Neo4jTemplate;\nimport org.springframework.data.neo4j.core.convert.Neo4jConversions;\nimport org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;\nimport org.springframework.data.neo4j.core.schema.Node;\nimport org.springframework.data.neo4j.core.schema.RelationshipProperties;\nimport org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;\nimport org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j.\n *\n * @author Michael Hunger\n * @author Josh Long\n * @author Vince Bickers\n * @author Stephane Nicoll\n * @author Kazuki Shimizu\n * @author Michael J. Simons\n * @since 4.0.0\n */\n@AutoConfiguration(before = TransactionAutoConfiguration.class,\n\t\tafter = { Neo4jAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class })\n@ConditionalOnClass({ Driver.class, Neo4jTransactionManager.class, PlatformTransactionManager.class })\n@EnableConfigurationProperties(DataNeo4jProperties.class)\n@ConditionalOnBean(Driver.class)\npublic final class DataNeo4jAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tNeo4jConversions neo4jConversions() {\n\t\treturn new Neo4jConversions();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tNeo4jManagedTypes neo4jManagedTypes(ApplicationContext applicationContext) throws ClassNotFoundException {\n\t\tSet<Class<?>> initialEntityClasses = new EntityScanner(applicationContext).scan(Node.class,\n\t\t\t\tRelationshipProperties.class);\n\t\treturn Neo4jManagedTypes.fromIterable(initialEntityClasses);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tNeo4jMappingContext neo4jMappingContext(Neo4jManagedTypes managedTypes, Neo4jConversions neo4jConversions) {\n\t\tNeo4jMappingContext context = new Neo4jMappingContext(neo4jConversions);\n\t\tcontext.setManagedTypes(managedTypes);\n\t\treturn context;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDatabaseSelectionProvider databaseSelectionProvider(DataNeo4jProperties properties) {\n\t\tString database = properties.getDatabase();\n\t\treturn (database != null) ? DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database)\n\t\t\t\t: DatabaseSelectionProvider.getDefaultSelectionProvider();\n\t}\n\n\t@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)\n\t@ConditionalOnMissingBean\n\tNeo4jClient neo4jClient(Driver driver, DatabaseSelectionProvider databaseNameProvider) {\n\t\treturn Neo4jClient.create(driver, databaseNameProvider);\n\t}\n\n\t@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)\n\t@ConditionalOnMissingBean(Neo4jOperations.class)\n\tNeo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext) {\n\t\treturn new Neo4jTemplate(neo4jClient, neo4jMappingContext);\n\t}\n\n\t@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)\n\t@ConditionalOnMissingBean(TransactionManager.class)\n\tNeo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider,\n\t\t\tObjectProvider<TransactionManagerCustomizers> optionalCustomizers) {\n\t\tNeo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider);\n\t\toptionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager));\n\t\treturn transactionManager;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Spring Data Neo4j.\n *\n * @author Michael J. Simons\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.neo4j\")\npublic class DataNeo4jProperties {\n\n\t/**\n\t * Database name to use. By default, the server decides the default database to use.\n\t */\n\tprivate @Nullable String database;\n\n\tpublic @Nullable String getDatabase() {\n\t\treturn this.database;\n\t}\n\n\tpublic void setDatabase(@Nullable String database) {\n\t\tthis.database = database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jReactiveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.neo4j.driver.Driver;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jClient;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jOperations;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;\nimport org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;\nimport org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;\nimport org.springframework.transaction.ReactiveTransactionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive Neo4j\n * support.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataNeo4jAutoConfiguration.class)\n@ConditionalOnClass({ Driver.class, ReactiveNeo4jTemplate.class, ReactiveTransactionManager.class, Flux.class })\n@ConditionalOnBean(Driver.class)\n@EnableConfigurationProperties(DataNeo4jProperties.class)\npublic final class DataNeo4jReactiveAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tReactiveDatabaseSelectionProvider reactiveDatabaseSelectionProvider(DataNeo4jProperties properties) {\n\t\tString database = properties.getDatabase();\n\t\treturn (database != null) ? ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database)\n\t\t\t\t: ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider();\n\t}\n\n\t@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)\n\t@ConditionalOnMissingBean\n\tReactiveNeo4jClient reactiveNeo4jClient(Driver driver, ReactiveDatabaseSelectionProvider databaseNameProvider) {\n\t\treturn ReactiveNeo4jClient.create(driver, databaseNameProvider);\n\t}\n\n\t@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)\n\t@ConditionalOnMissingBean(ReactiveNeo4jOperations.class)\n\t@ConditionalOnBean(Neo4jMappingContext.class)\n\tReactiveNeo4jTemplate reactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient,\n\t\t\tNeo4jMappingContext neo4jMappingContext) {\n\t\treturn new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jReactiveRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.neo4j.driver.Driver;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;\nimport org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;\nimport org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j Reactive\n * Repositories.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataNeo4jReactiveAutoConfiguration.class)\n@ConditionalOnClass({ Driver.class, ReactiveNeo4jRepository.class, Flux.class })\n@ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class,\n\t\tReactiveNeo4jRepositoryConfigurationExtension.class })\n@ConditionalOnRepositoryType(store = \"neo4j\", type = RepositoryType.REACTIVE)\n@Import(DataNeo4jReactiveRepositoriesRegistrar.class)\npublic final class DataNeo4jReactiveRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jReactiveRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;\nimport org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Neo4j reactive\n * Repositories.\n *\n * @author Michael J. Simons\n */\nclass DataNeo4jReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableReactiveNeo4jRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableReactiveNeo4jRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new ReactiveNeo4jRepositoryConfigurationExtension();\n\t}\n\n\t@EnableReactiveNeo4jRepositories\n\tprivate static final class EnableReactiveNeo4jRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.neo4j.driver.Driver;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;\nimport org.springframework.boot.autoconfigure.data.RepositoryType;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\nimport org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;\nimport org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;\nimport org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j\n * Repositories.\n * <p>\n * Activates when there is no bean of type {@link Neo4jRepositoryFactoryBean} or\n * {@link Neo4jRepositoryConfigurationExtension} configured in the context, the Spring\n * Data Neo4j {@link Neo4jRepository} type is on the classpath, the Neo4j client driver\n * API is on the classpath, and there is no other configured {@link Neo4jRepository}.\n * <p>\n * Once in effect, the auto-configuration is the equivalent of enabling Neo4j repositories\n * using the {@link EnableNeo4jRepositories @EnableNeo4jRepositories} annotation.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Josh Long\n * @author Michael J. Simons\n * @since 4.0.0\n * @see EnableNeo4jRepositories\n */\n@AutoConfiguration(after = DataNeo4jAutoConfiguration.class)\n@ConditionalOnClass({ Driver.class, Neo4jRepository.class })\n@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class })\n@ConditionalOnRepositoryType(store = \"neo4j\", type = RepositoryType.IMPERATIVE)\n@Import(DataNeo4jRepositoriesRegistrar.class)\npublic final class DataNeo4jRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;\nimport org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Neo4j\n * Repositories.\n *\n * @author Michael Hunger\n */\nclass DataNeo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableNeo4jRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableNeo4jRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new Neo4jRepositoryConfigurationExtension();\n\t}\n\n\t@EnableNeo4jRepositories\n\tprivate static final class EnableNeo4jRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/java/org/springframework/boot/data/neo4j/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Neo4j.\n */\n@NullMarked\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.neo4j.auto-index\",\n      \"description\": \"Auto index mode.\",\n      \"defaultValue\": \"none\",\n      \"deprecation\": {\n        \"reason\": \"Automatic index creation is no longer supported.\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.embedded.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable embedded mode if the embedded driver is available.\",\n      \"deprecation\": {\n        \"reason\": \"Embedded mode is no longer supported, please use Testcontainers instead.\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.open-in-view\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Register OpenSessionInViewInterceptor that binds a Neo4j Session to the thread for the entire processing of the request.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Login password of the server.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.neo4j.authentication.password\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Neo4j repositories.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.data.neo4j.repositories.type\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.repositories.type\",\n      \"type\": \"org.springframework.boot.autoconfigure.data.RepositoryType\",\n      \"description\": \"Type of Neo4j repositories to enable.\",\n      \"defaultValue\": \"auto\"\n    },\n    {\n      \"name\": \"spring.data.neo4j.uri\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"URI used by the driver. Auto-detected by default.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.neo4j.uri\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.use-native-types\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use Neo4j native types wherever possible.\",\n      \"deprecation\": {\n        \"reason\": \"Native type support is now built-in.\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.neo4j.username\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Login user of the server.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.neo4j.authentication.username\",\n        \"level\": \"error\",\n        \"since\": \"2.4.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.neo4j.autoconfigure.DataNeo4jAutoConfiguration\norg.springframework.boot.data.neo4j.autoconfigure.DataNeo4jReactiveAutoConfiguration\norg.springframework.boot.data.neo4j.autoconfigure.DataNeo4jReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.neo4j.autoconfigure.DataNeo4jRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.neo4j.domain.scan.TestNode;\nimport org.springframework.boot.data.neo4j.domain.scan.TestNonAnnotated;\nimport org.springframework.boot.data.neo4j.domain.scan.TestPersistent;\nimport org.springframework.boot.data.neo4j.domain.scan.TestRelationshipProperties;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.neo4j.aot.Neo4jManagedTypes;\nimport org.springframework.data.neo4j.core.DatabaseSelection;\nimport org.springframework.data.neo4j.core.DatabaseSelectionProvider;\nimport org.springframework.data.neo4j.core.Neo4jClient;\nimport org.springframework.data.neo4j.core.Neo4jOperations;\nimport org.springframework.data.neo4j.core.Neo4jTemplate;\nimport org.springframework.data.neo4j.core.convert.Neo4jConversions;\nimport org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;\nimport org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.ReactiveTransactionManager;\nimport org.springframework.transaction.TransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataNeo4jAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Michael Hunger\n * @author Vince Bickers\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n * @author Michael J. Simons\n */\nclass DataNeo4jAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(MockedDriverConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, DataNeo4jAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldProvideConversions() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jConversions.class));\n\t}\n\n\t@Test\n\tvoid shouldProvideDefaultDatabaseNameProvider() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DatabaseSelectionProvider.class);\n\t\t\tassertThat(context.getBean(DatabaseSelectionProvider.class))\n\t\t\t\t.isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider());\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseDatabaseNameIfSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.neo4j.database=test\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DatabaseSelectionProvider.class);\n\t\t\tassertThat(context.getBean(DatabaseSelectionProvider.class).getDatabaseSelection())\n\t\t\t\t.isEqualTo(DatabaseSelection.byName(\"test\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingDatabaseNameProvider() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.neo4j.database=ignored\")\n\t\t\t.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DatabaseSelectionProvider.class);\n\t\t\t\tassertThat(context.getBean(DatabaseSelectionProvider.class).getDatabaseSelection())\n\t\t\t\t\t.isEqualTo(DatabaseSelection.byName(\"custom\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldProvideNeo4jClient() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class));\n\t}\n\n\t@Test\n\tvoid shouldProvideNeo4jClientWithCustomDatabaseSelectionProvider() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Neo4jClient.class);\n\t\t\tassertThat(context.getBean(Neo4jClient.class)).extracting(\"databaseSelectionProvider\")\n\t\t\t\t.isSameAs(context.getBean(DatabaseSelectionProvider.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingNeo4jClient() {\n\t\tthis.contextRunner.withUserConfiguration(Neo4jClientConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class).hasBean(\"myCustomClient\"));\n\t}\n\n\t@Test\n\tvoid shouldProvideNeo4jTemplate() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jTemplate.class));\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingNeo4jTemplate() {\n\t\tthis.contextRunner.withBean(\"myCustomOperations\", Neo4jOperations.class, () -> mock(Neo4jOperations.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jOperations.class).hasBean(\"myCustomOperations\"));\n\t}\n\n\t@Test\n\tvoid shouldProvideTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Neo4jTransactionManager.class);\n\t\t\tassertThat(context.getBean(Neo4jTransactionManager.class)).extracting(\"databaseSelectionProvider\")\n\t\t\t\t.isSameAs(context.getBean(DatabaseSelectionProvider.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackoffIfReactiveTransactionManagerIsSet() {\n\t\tthis.contextRunner.withBean(ReactiveTransactionManager.class, () -> mock(ReactiveTransactionManager.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Neo4jTransactionManager.class)\n\t\t\t\t.hasSingleBean(TransactionManager.class));\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingTransactionManager() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"myCustomTransactionManager\", PlatformTransactionManager.class,\n\t\t\t\t\t() -> mock(PlatformTransactionManager.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PlatformTransactionManager.class)\n\t\t\t\t.hasBean(\"myCustomTransactionManager\"));\n\t}\n\n\t@Test\n\tvoid shouldFilterInitialEntityScanWithKnownAnnotations() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tNeo4jMappingContext mappingContext = context.getBean(Neo4jMappingContext.class);\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestNode.class)).isTrue();\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestPersistent.class)).isFalse();\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestRelationshipProperties.class)).isTrue();\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestNonAnnotated.class)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldProvideManagedTypes() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Neo4jManagedTypes.class);\n\t\t\tassertThat(context.getBean(Neo4jMappingContext.class))\n\t\t\t\t.extracting((mappingContext) -> ReflectionTestUtils.getField(mappingContext, \"managedTypes\"))\n\t\t\t\t.isEqualTo(context.getBean(Neo4jManagedTypes.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingManagedTypes() {\n\t\tNeo4jManagedTypes managedTypes = Neo4jManagedTypes.from();\n\t\tthis.contextRunner.withBean(\"customManagedTypes\", Neo4jManagedTypes.class, () -> managedTypes)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Neo4jManagedTypes.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(\"neo4jManagedTypes\");\n\t\t\t\tassertThat(context.getBean(Neo4jMappingContext.class))\n\t\t\t\t\t.extracting((mappingContext) -> ReflectionTestUtils.getField(mappingContext, \"managedTypes\"))\n\t\t\t\t\t.isSameAs(managedTypes);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDatabaseSelectionProviderConfiguration {\n\n\t\t@Bean\n\t\tDatabaseSelectionProvider databaseSelectionProvider() {\n\t\t\treturn () -> DatabaseSelection.byName(\"custom\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(TestPersistent.class)\n\tstatic class EntityScanConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Neo4jClientConfig {\n\n\t\t@Bean\n\t\tNeo4jClient myCustomClient(Driver driver) {\n\t\t\treturn Neo4jClient.create(driver);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.neo4j.domain.scan.TestNode;\nimport org.springframework.boot.data.neo4j.domain.scan.TestNonAnnotated;\nimport org.springframework.boot.data.neo4j.domain.scan.TestPersistent;\nimport org.springframework.boot.data.neo4j.domain.scan.TestRelationshipProperties;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.neo4j.core.DatabaseSelection;\nimport org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jClient;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jOperations;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;\nimport org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;\nimport org.springframework.transaction.ReactiveTransactionManager;\nimport org.springframework.transaction.TransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataNeo4jReactiveAutoConfiguration}.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n */\nclass DataNeo4jReactiveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(MockedDriverConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, DataNeo4jAutoConfiguration.class,\n\t\t\t\tDataNeo4jReactiveAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldBackOffIfNoMappingContextIsProvided() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(MockedDriverConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(Neo4jAutoConfiguration.class, DataNeo4jReactiveAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Neo4jMappingContext.class));\n\t}\n\n\t@Test\n\tvoid shouldProvideDefaultDatabaseNameProvider() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class);\n\t\t\tassertThat(context.getBean(ReactiveDatabaseSelectionProvider.class))\n\t\t\t\t.isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider());\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseDatabaseNameIfSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.neo4j.database=test\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class);\n\t\t\tStepVerifier.create(context.getBean(ReactiveDatabaseSelectionProvider.class).getDatabaseSelection())\n\t\t\t\t.consumeNextWith((databaseSelection) -> assertThat(databaseSelection.getValue()).isEqualTo(\"test\"))\n\t\t\t\t.expectComplete();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingDatabaseNameProvider() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.neo4j.database=ignored\")\n\t\t\t.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class);\n\t\t\t\tStepVerifier.create(context.getBean(ReactiveDatabaseSelectionProvider.class).getDatabaseSelection())\n\t\t\t\t\t.consumeNextWith(\n\t\t\t\t\t\t\t(databaseSelection) -> assertThat(databaseSelection.getValue()).isEqualTo(\"custom\"))\n\t\t\t\t\t.expectComplete();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldProvideReactiveNeo4jClient() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jClient.class));\n\t}\n\n\t@Test\n\tvoid shouldProvideReactiveNeo4jClientWithCustomDatabaseSelectionProvider() {\n\t\tthis.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveNeo4jClient.class);\n\t\t\t\tassertThat(context.getBean(ReactiveNeo4jClient.class)).extracting(\"databaseSelectionProvider\")\n\t\t\t\t\t.isSameAs(context.getBean(ReactiveDatabaseSelectionProvider.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingReactiveNeo4jClient() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveNeo4jClientConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jClient.class)\n\t\t\t\t.hasBean(\"myCustomReactiveClient\"));\n\t}\n\n\t@Test\n\tvoid shouldProvideReactiveNeo4jTemplate() {\n\t\tthis.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTemplate.class));\n\t}\n\n\t@Test\n\tvoid shouldReuseExistingReactiveNeo4jTemplate() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"myCustomReactiveOperations\", ReactiveNeo4jOperations.class,\n\t\t\t\t\t() -> mock(ReactiveNeo4jOperations.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jOperations.class)\n\t\t\t\t.hasBean(\"myCustomReactiveOperations\"));\n\t}\n\n\t@Test\n\tvoid shouldUseExistingReactiveTransactionManager() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"myCustomReactiveTransactionManager\", ReactiveTransactionManager.class,\n\t\t\t\t\t() -> mock(ReactiveTransactionManager.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveTransactionManager.class)\n\t\t\t\t.hasSingleBean(TransactionManager.class));\n\t}\n\n\t@Test\n\tvoid shouldFilterInitialEntityScanWithKnownAnnotations() {\n\t\tthis.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {\n\t\t\tNeo4jMappingContext mappingContext = context.getBean(Neo4jMappingContext.class);\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestNode.class)).isTrue();\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestPersistent.class)).isFalse();\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestRelationshipProperties.class)).isTrue();\n\t\t\tassertThat(mappingContext.hasPersistentEntityFor(TestNonAnnotated.class)).isFalse();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomReactiveDatabaseSelectionProviderConfiguration {\n\n\t\t@Bean\n\t\tReactiveDatabaseSelectionProvider databaseNameProvider() {\n\t\t\treturn () -> Mono.just(DatabaseSelection.byName(\"custom\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(TestPersistent.class)\n\tstatic class EntityScanConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveNeo4jClientConfig {\n\n\t\t@Bean\n\t\tReactiveNeo4jClient myCustomReactiveClient(Driver driver) {\n\t\t\treturn ReactiveNeo4jClient.create(driver);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jReactiveRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.neo4j.domain.city.City;\nimport org.springframework.boot.data.neo4j.domain.city.CityRepository;\nimport org.springframework.boot.data.neo4j.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.data.neo4j.domain.country.CountryRepository;\nimport org.springframework.boot.data.neo4j.domain.country.ReactiveCountryRepository;\nimport org.springframework.boot.data.neo4j.domain.empty.EmptyPackage;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;\nimport org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;\nimport org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataNeo4jReactiveRepositoriesAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Michael J. Simons\n */\nclass DataNeo4jReactiveRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(MockedDriverConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(DataNeo4jAutoConfiguration.class,\n\t\t\t\tDataNeo4jReactiveAutoConfiguration.class, DataNeo4jRepositoriesAutoConfiguration.class,\n\t\t\t\tDataNeo4jReactiveRepositoriesAutoConfiguration.class));\n\n\t@Test\n\tvoid configurationWithDefaultRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class));\n\t}\n\n\t@Test\n\tvoid configurationWithNoRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTemplate.class)\n\t\t\t\t.doesNotHaveBean(ReactiveNeo4jRepository.class));\n\t}\n\n\t@Test\n\tvoid configurationWithDisabledRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.neo4j.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveNeo4jRepository.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTemplate.class)\n\t\t\t\t.doesNotHaveBean(ReactiveNeo4jRepository.class));\n\t}\n\n\t@Test\n\tvoid shouldRespectAtEnableReactiveNeo4jRepositories() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class)\n\t\t\t.withPropertyValues(\"spring.data.neo4j.repositories.type=reactive\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)\n\t\t\t\t.doesNotHaveBean(ReactiveCityRepository.class)\n\t\t\t\t.doesNotHaveBean(CountryRepository.class)\n\t\t\t\t.hasSingleBean(ReactiveCountryRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableReactiveNeo4jRepositories(\"foo.bar\")\n\t@TestAutoConfigurationPackage(DataNeo4jReactiveRepositoriesAutoConfigurationTests.class)\n\tstatic class SortOfInvalidCustomConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class)\n\tstatic class WithCustomReactiveRepositoryScan {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/autoconfigure/DataNeo4jRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.neo4j.domain.city.City;\nimport org.springframework.boot.data.neo4j.domain.city.CityRepository;\nimport org.springframework.boot.data.neo4j.domain.city.ReactiveCityRepository;\nimport org.springframework.boot.data.neo4j.domain.country.CountryRepository;\nimport org.springframework.boot.data.neo4j.domain.country.ReactiveCountryRepository;\nimport org.springframework.boot.data.neo4j.domain.empty.EmptyPackage;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\nimport org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;\nimport org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataNeo4jRepositoriesAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Michael Hunger\n * @author Vince Bickers\n * @author Stephane Nicoll\n * @author Michael J. Simons\n */\nclass DataNeo4jRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(MockedDriverConfiguration.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(DataNeo4jAutoConfiguration.class, DataNeo4jRepositoriesAutoConfiguration.class));\n\n\t@Test\n\tvoid configurationWithDefaultRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(CityRepository.class));\n\t}\n\n\t@Test\n\tvoid configurationWithNoRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jTransactionManager.class)\n\t\t\t\t.doesNotHaveBean(Neo4jRepository.class));\n\t}\n\n\t@Test\n\tvoid configurationWithDisabledRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.neo4j.repositories.type=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Neo4jRepository.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jTransactionManager.class)\n\t\t\t\t.doesNotHaveBean(Neo4jRepository.class));\n\t}\n\n\t@Test\n\tvoid shouldRespectAtEnableNeo4jRepositories() {\n\t\tthis.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomRepositoryScan.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)\n\t\t\t\t.doesNotHaveBean(ReactiveCityRepository.class)\n\t\t\t\t.hasSingleBean(CountryRepository.class)\n\t\t\t\t.doesNotHaveBean(ReactiveCountryRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableNeo4jRepositories(basePackageClasses = CountryRepository.class)\n\tstatic class WithCustomRepositoryScan {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WithFakeEnabledReactiveNeo4jRepositories {\n\n\t\t@Bean\n\t\tReactiveNeo4jRepositoryFactoryBean<?, ?, ?> reactiveNeo4jRepositoryFactoryBean() {\n\t\t\treturn mock(ReactiveNeo4jRepositoryFactoryBean.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableNeo4jRepositories(\"foo.bar\")\n\t@TestAutoConfigurationPackage(DataNeo4jRepositoriesAutoConfigurationTests.class)\n\tstatic class SortOfInvalidCustomConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/autoconfigure/MockedDriverConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.autoconfigure;\n\nimport org.mockito.ArgumentMatchers;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Session;\nimport org.neo4j.driver.SessionConfig;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Driver configuration mocked to avoid instantiation of a real driver with connection\n * creation.\n *\n * @author Michael J. Simons\n */\n@Configuration(proxyBeanMethods = false)\nclass MockedDriverConfiguration {\n\n\t@Bean\n\tDriver driver() {\n\t\tDriver driver = mock(Driver.class);\n\t\tSession session = mock(Session.class);\n\t\tgiven(driver.session(ArgumentMatchers.any(SessionConfig.class))).willReturn(session);\n\t\treturn driver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.city;\n\nimport java.io.Serializable;\n\nimport org.springframework.boot.data.neo4j.domain.country.Country;\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\nimport org.springframework.data.neo4j.core.schema.Node;\n\n@Node\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate final String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate final Country country;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tpublic City(String name, Country country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic Country getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.city;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\n\npublic interface CityRepository extends Neo4jRepository<City, Long> {\n\n\t@Override\n\tPage<City> findAll(Pageable pageable);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/city/ReactiveCityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.city;\n\nimport org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;\n\npublic interface ReactiveCityRepository extends ReactiveNeo4jRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.neo4j.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/country/Country.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.country;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\nimport org.springframework.data.neo4j.core.schema.Node;\n\n@Node\npublic class Country implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\tprivate final String name;\n\n\tpublic Country(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/country/CountryRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.country;\n\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\n\npublic interface CountryRepository extends Neo4jRepository<Country, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/country/ReactiveCountryRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.country;\n\nimport org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;\n\npublic interface ReactiveCountryRepository extends ReactiveNeo4jRepository<Country, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/country/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.neo4j.domain.country;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/empty/EmptyPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.empty;\n\npublic class EmptyPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.neo4j.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/scan/TestNode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.scan;\n\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\nimport org.springframework.data.neo4j.core.schema.Node;\n\n@Node\npublic class TestNode {\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/scan/TestNonAnnotated.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.scan;\n\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\n\npublic class TestNonAnnotated {\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/scan/TestPersistent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.scan;\n\nimport org.springframework.data.annotation.Persistent;\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\n\n@Persistent\npublic class TestPersistent {\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/scan/TestRelationshipProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.domain.scan;\n\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\nimport org.springframework.data.neo4j.core.schema.RelationshipProperties;\n\n@RelationshipProperties\npublic class TestRelationshipProperties {\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tLong id;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j/src/test/java/org/springframework/boot/data/neo4j/domain/scan/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.neo4j.domain.scan;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data Neo4j Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-neo4j\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"io.projectreactor:reactor-test\")\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-neo4j\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.neo4j.core.Neo4jTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration test for {@link DataNeo4jTest @DataNeo4jTest}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Michael Simons\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataNeo4jTest\n@Testcontainers(disabledWithoutDocker = true)\nclass DataNeo4jTestIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final Neo4jContainer neo4j = TestImage.container(Neo4jContainer.class);\n\n\t@Autowired\n\tprivate Neo4jTemplate neo4jTemplate;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testRepository() {\n\t\tExampleGraph exampleGraph = new ExampleGraph(\"Look, new @DataNeo4jTest!\");\n\t\tassertThat(exampleGraph.getId()).isNull();\n\t\tExampleGraph savedGraph = this.exampleRepository.save(exampleGraph);\n\t\tassertThat(savedGraph.getId()).isNotNull();\n\t\tassertThat(this.neo4jTemplate.count(ExampleGraph.class)).isOne();\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataNeo4jTest#properties properties} attribute of\n * {@link DataNeo4jTest @DataNeo4jTest}.\n *\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataNeo4jTest(properties = \"spring.profiles.active=test\")\nclass DataNeo4jTestPropertiesIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final Neo4jContainer neo4j = TestImage.container(Neo4jContainer.class).withoutAuthentication();\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataNeo4jTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTestReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;\nimport org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;\nimport org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;\nimport org.springframework.transaction.annotation.Propagation;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Integration tests for {@link DataNeo4jTest @DataNeo4jTest} with reactive style.\n *\n * @author Michael J. Simons\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@DataNeo4jTest\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\n@Testcontainers(disabledWithoutDocker = true)\nclass DataNeo4jTestReactiveIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final Neo4jContainer neo4j = TestImage.container(Neo4jContainer.class).withoutAuthentication();\n\n\t@Autowired\n\tprivate ReactiveNeo4jTemplate neo4jTemplate;\n\n\t@Autowired\n\tprivate ExampleReactiveRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testRepository() {\n\t\tMono.just(new ExampleGraph(\"Look, new @DataNeo4jTest with reactive!\"))\n\t\t\t.flatMap(this.exampleRepository::save)\n\t\t\t.as(StepVerifier::create)\n\t\t\t.expectNextCount(1)\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tStepVerifier.create(this.neo4jTemplate.count(ExampleGraph.class))\n\t\t\t.expectNext(1L)\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class ReactiveTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tReactiveNeo4jTransactionManager reactiveTransactionManager(Driver driver,\n\t\t\t\tReactiveDatabaseSelectionProvider databaseNameProvider) {\n\t\t\treturn new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for {@link DataNeo4jTest @DataNeo4jTest}.\n *\n * @author Eddú Meléndez\n * @author Michael Simons\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataNeo4jTest(includeFilters = @Filter(Service.class))\nclass DataNeo4jTestWithIncludeFilterIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final Neo4jContainer neo4j = TestImage.container(Neo4jContainer.class).withoutAuthentication();\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tassertThat(this.service.hasNode(ExampleGraph.class)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/ExampleGraph.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.data.neo4j.core.schema.GeneratedValue;\nimport org.springframework.data.neo4j.core.schema.Id;\nimport org.springframework.data.neo4j.core.schema.Node;\nimport org.springframework.data.neo4j.core.schema.Property;\n\n/**\n * Example graph used with {@link DataNeo4jTest @DataNeo4jTest} tests.\n *\n * @author Eddú Meléndez\n */\n@Node\npublic class ExampleGraph {\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Property\n\tprivate String description;\n\n\tpublic ExampleGraph(String description) {\n\t\tthis.description = description;\n\t}\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(String description) {\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/ExampleNeo4jApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataNeo4jTest @DataNeo4jTest} tests.\n *\n * @author Eddú Meléndez\n */\n@SpringBootApplication\npublic class ExampleNeo4jApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/ExampleReactiveRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;\n\n/**\n * Example reactive repository used with {@link DataNeo4jTest @DataNeo4jTest} tests.\n *\n * @author Stephane Nicoll\n */\ninterface ExampleReactiveRepository extends ReactiveNeo4jRepository<ExampleGraph, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.data.neo4j.repository.Neo4jRepository;\n\n/**\n * Example repository used with {@link DataNeo4jTest @DataNeo4jTest} tests.\n *\n * @author Eddú Meléndez\n */\ninterface ExampleRepository extends Neo4jRepository<ExampleGraph, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/dockerTest/java/org/springframework/boot/data/neo4j/test/autoconfigure/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.data.neo4j.core.Neo4jTemplate;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataNeo4jTest @DataNeo4jTest} tests.\n *\n * @author Eddú Meléndez\n * @author Michael J. Simons\n */\n@Service\npublic class ExampleService {\n\n\tprivate final Neo4jTemplate neo4jTemplate;\n\n\tpublic ExampleService(Neo4jTemplate neo4jTemplate) {\n\t\tthis.neo4jTemplate = neo4jTemplate;\n\t}\n\n\tpublic boolean hasNode(Class<?> type) {\n\t\treturn this.neo4jTemplate.count(type) == 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/main/java/org/springframework/boot/data/neo4j/test/autoconfigure/AutoConfigureDataNeo4j.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data Neo4j\n * tests. Most tests should consider using {@link DataNeo4jTest @DataNeo4jTest} rather\n * than using this annotation directly.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataNeo4j {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/main/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Annotation that can be used for a Neo4j test that focuses <strong>only</strong> on\n * Neo4j components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data Neo4j\n * tests. Similarly, component scanning is limited to Neo4j repositories and entities\n * ({@code @Node} and {@code @RelationshipProperties}).\n * <p>\n * By default, tests annotated with {@code @DataNeo4jTest} are transactional with the\n * usual test-related semantics (i.e. rollback by default). This feature is not supported\n * with reactive access so this should be disabled by annotating the test class with\n * {@code @Transactional(propagation = Propagation.NOT_SUPPORTED)}.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataNeo4jTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataNeo4jTypeExcludeFilter.class)\n@Transactional\n@AutoConfigureDataNeo4j\n@ImportAutoConfiguration\npublic @interface DataNeo4jTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/main/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataNeo4jTest @DataNeo4jTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass DataNeo4jTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataNeo4jTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/main/java/org/springframework/boot/data/neo4j/test/autoconfigure/DataNeo4jTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataNeo4jTest @DataNeo4jTest}.\n *\n * @author Eddú Meléndez\n */\nclass DataNeo4jTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataNeo4jTest> {\n\n\tDataNeo4jTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/main/java/org/springframework/boot/data/neo4j/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data Neo4j tests.\n */\n@NullMarked\npackage org.springframework.boot.data.neo4j.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-neo4j-test/src/main/resources/META-INF/spring/org.springframework.boot.data.neo4j.test.autoconfigure.AutoConfigureDataNeo4j.imports",
    "content": "org.springframework.boot.data.neo4j.autoconfigure.DataNeo4jAutoConfiguration\norg.springframework.boot.data.neo4j.autoconfigure.DataNeo4jReactiveAutoConfiguration\norg.springframework.boot.data.neo4j.autoconfigure.DataNeo4jReactiveRepositoriesAutoConfiguration\norg.springframework.boot.data.neo4j.autoconfigure.DataNeo4jRepositoriesAutoConfiguration\norg.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data R2DBC\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-r2dbc\"))\n\tapi(\"io.r2dbc:r2dbc-spi\")\n\tapi(\"io.r2dbc:r2dbc-pool\")\n\tapi(\"org.springframework.data:spring-data-r2dbc\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"io.r2dbc:r2dbc-h2\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/main/java/org/springframework/boot/data/r2dbc/autoconfigure/DataR2dbcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanner;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.convert.CustomConversions;\nimport org.springframework.data.r2dbc.convert.MappingR2dbcConverter;\nimport org.springframework.data.r2dbc.convert.R2dbcConverter;\nimport org.springframework.data.r2dbc.convert.R2dbcCustomConversions;\nimport org.springframework.data.r2dbc.core.R2dbcEntityTemplate;\nimport org.springframework.data.r2dbc.dialect.DialectResolver;\nimport org.springframework.data.r2dbc.dialect.R2dbcDialect;\nimport org.springframework.data.r2dbc.mapping.R2dbcMappingContext;\nimport org.springframework.data.relational.RelationalManagedTypes;\nimport org.springframework.data.relational.core.mapping.DefaultNamingStrategy;\nimport org.springframework.data.relational.core.mapping.NamingStrategy;\nimport org.springframework.data.relational.core.mapping.Table;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link DatabaseClient}.\n *\n * @author Mark Paluch\n * @author Oliver Drotbohm\n * @since 4.0.0\n */\n@AutoConfiguration(after = R2dbcAutoConfiguration.class)\n@ConditionalOnClass({ DatabaseClient.class, R2dbcEntityTemplate.class })\n@ConditionalOnSingleCandidate(DatabaseClient.class)\npublic final class DataR2dbcAutoConfiguration {\n\n\tprivate final DatabaseClient databaseClient;\n\n\tprivate final R2dbcDialect dialect;\n\n\tDataR2dbcAutoConfiguration(DatabaseClient databaseClient) {\n\t\tthis.databaseClient = databaseClient;\n\t\tthis.dialect = DialectResolver.getDialect(this.databaseClient.getConnectionFactory());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tR2dbcEntityTemplate r2dbcEntityTemplate(R2dbcConverter r2dbcConverter) {\n\t\treturn new R2dbcEntityTemplate(this.databaseClient, this.dialect, r2dbcConverter);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tstatic RelationalManagedTypes r2dbcManagedTypes(ApplicationContext applicationContext)\n\t\t\tthrows ClassNotFoundException {\n\t\treturn RelationalManagedTypes.fromIterable(new EntityScanner(applicationContext).scan(Table.class));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tR2dbcMappingContext r2dbcMappingContext(ObjectProvider<NamingStrategy> namingStrategy,\n\t\t\tR2dbcCustomConversions r2dbcCustomConversions, RelationalManagedTypes r2dbcManagedTypes) {\n\t\tR2dbcMappingContext relationalMappingContext = new R2dbcMappingContext(\n\t\t\t\tnamingStrategy.getIfAvailable(() -> DefaultNamingStrategy.INSTANCE));\n\t\trelationalMappingContext.setSimpleTypeHolder(r2dbcCustomConversions.getSimpleTypeHolder());\n\t\trelationalMappingContext.setManagedTypes(r2dbcManagedTypes);\n\t\treturn relationalMappingContext;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMappingR2dbcConverter r2dbcConverter(R2dbcMappingContext mappingContext,\n\t\t\tR2dbcCustomConversions r2dbcCustomConversions) {\n\t\treturn new MappingR2dbcConverter(mappingContext, r2dbcCustomConversions);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tR2dbcCustomConversions r2dbcCustomConversions() {\n\t\tList<Object> converters = new ArrayList<>(this.dialect.getConverters());\n\t\tconverters.addAll(R2dbcCustomConversions.STORE_CONVERTERS);\n\t\treturn new R2dbcCustomConversions(\n\t\t\t\tCustomConversions.StoreConversions.of(this.dialect.getSimpleTypeHolder(), converters),\n\t\t\t\tCollections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/main/java/org/springframework/boot/data/r2dbc/autoconfigure/DataR2dbcRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.r2dbc.repository.R2dbcRepository;\nimport org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;\nimport org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactoryBean;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data R2DBC Repositories.\n *\n * @author Mark Paluch\n * @since 4.0.0\n * @see EnableR2dbcRepositories\n */\n@AutoConfiguration(after = DataR2dbcAutoConfiguration.class)\n@ConditionalOnClass({ ConnectionFactory.class, R2dbcRepository.class })\n@ConditionalOnBean(DatabaseClient.class)\n@ConditionalOnBooleanProperty(name = \"spring.data.r2dbc.repositories.enabled\", matchIfMissing = true)\n@ConditionalOnMissingBean(R2dbcRepositoryFactoryBean.class)\n@Import(DataR2dbcRepositoriesAutoConfigureRegistrar.class)\npublic final class DataR2dbcRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/main/java/org/springframework/boot/data/r2dbc/autoconfigure/DataR2dbcRepositoriesAutoConfigureRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;\nimport org.springframework.data.r2dbc.repository.config.R2dbcRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data R2DBC\n * Repositories.\n *\n * @author Mark Paluch\n */\nclass DataR2dbcRepositoriesAutoConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableR2dbcRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableR2dbcRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new R2dbcRepositoryConfigurationExtension();\n\t}\n\n\t@EnableR2dbcRepositories\n\tprivate static final class EnableR2dbcRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/main/java/org/springframework/boot/data/r2dbc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for Spring Data R2DBC.\n */\n@NullMarked\npackage org.springframework.boot.data.r2dbc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.data.r2dbc.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable R2DBC repositories.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.r2dbc.autoconfigure.DataR2dbcAutoConfiguration\norg.springframework.boot.data.r2dbc.autoconfigure.DataR2dbcRepositoriesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/autoconfigure/DataR2dbcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.r2dbc.domain.city.City;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.data.domain.ManagedTypes;\nimport org.springframework.data.r2dbc.core.R2dbcEntityTemplate;\nimport org.springframework.data.r2dbc.mapping.R2dbcMappingContext;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataR2dbcAutoConfiguration}.\n *\n * @author Mark Paluch\n */\nclass DataR2dbcAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class, DataR2dbcAutoConfiguration.class));\n\n\t@Test\n\tvoid r2dbcEntityTemplateIsConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(R2dbcEntityTemplate.class));\n\t}\n\n\t@Test\n\tvoid entityScanShouldSetManagedTypes() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tR2dbcMappingContext mappingContext = context.getBean(R2dbcMappingContext.class);\n\t\t\tManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, \"managedTypes\");\n\t\t\tassertThat(managedTypes).isNotNull();\n\t\t\tassertThat(managedTypes.toList()).containsOnly(City.class);\n\t\t});\n\t}\n\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/autoconfigure/DataR2dbcRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.data.r2dbc.domain.city.City;\nimport org.springframework.boot.data.r2dbc.domain.city.CityRepository;\nimport org.springframework.boot.data.r2dbc.domain.empty.EmptyDataPackage;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;\nimport org.springframework.data.r2dbc.repository.config.R2dbcRepositoryConfigurationExtension;\nimport org.springframework.data.repository.Repository;\nimport org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataR2dbcRepositoriesAutoConfiguration}.\n *\n * @author Mark Paluch\n */\n@WithResource(name = \"schema.sql\", content = \"\"\"\n\t\tCREATE TABLE CITY (\n\t\t  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\t\t  name VARCHAR(30),\n\t\t  state  VARCHAR(30),\n\t\t  country  VARCHAR(30),\n\t\t  map  VARCHAR(30)\n\t\t);\n\t\t\"\"\")\n@WithResource(name = \"data.sql\",\n\t\tcontent = \"INSERT INTO CITY (ID, NAME, STATE, COUNTRY, MAP) values (2000, 'Washington', 'DC', 'US', 'Google');\")\nclass DataR2dbcRepositoriesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataR2dbcRepositoriesAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithNoConnectionFactory() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(R2dbcRepositoryConfigurationExtension.class));\n\t}\n\n\t@Test\n\tvoid backsOffWithNoDatabaseClientOperations() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.r2dbc\"))\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(DatabaseClient.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(R2dbcRepositoryConfigurationExtension.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid basicAutoConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class, DataR2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DatabaseInitializationConfiguration.class, TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.r2dbc.generate-unique-name:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\t\tcontext.getBean(CityRepository.class)\n\t\t\t\t\t.findById(2000L)\n\t\t\t\t\t.as(StepVerifier::create)\n\t\t\t\t\t.expectNextCount(1)\n\t\t\t\t\t.expectComplete()\n\t\t\t\t\t.verify(Duration.ofSeconds(30));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWithNoRepositories() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(EmptyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Repository.class));\n\t}\n\n\t@Test\n\tvoid honorsUsersEnableR2dbcRepositoriesConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class, DataR2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DatabaseInitializationConfiguration.class, EnableRepositoriesConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.r2dbc.generate-unique-name:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(CityRepository.class);\n\t\t\t\tcontext.getBean(CityRepository.class)\n\t\t\t\t\t.findById(2000L)\n\t\t\t\t\t.as(StepVerifier::create)\n\t\t\t\t\t.expectNextCount(1)\n\t\t\t\t\t.expectComplete()\n\t\t\t\t\t.verify(Duration.ofSeconds(30));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DatabaseInitializationConfiguration {\n\n\t\t@Autowired\n\t\tvoid initializeDatabase(ConnectionFactory connectionFactory) {\n\t\t\tResourceLoader resourceLoader = new DefaultResourceLoader();\n\t\t\tResource[] scripts = new Resource[] { resourceLoader.getResource(\"classpath:schema.sql\"),\n\t\t\t\t\tresourceLoader.getResource(\"classpath:data.sql\") };\n\t\t\tnew ResourceDatabasePopulator(scripts).populate(connectionFactory).block();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyDataPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableR2dbcRepositories(basePackageClasses = City.class)\n\tstatic class EnableRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.domain.city;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.relational.core.mapping.Table;\n\n@Table(\"CITY\")\npublic class City {\n\n\t@Id\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.domain.city;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface CityRepository extends ReactiveCrudRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.r2dbc.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/domain/empty/EmptyDataPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.domain.empty;\n\npublic class EmptyDataPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc/src/test/java/org/springframework/boot/data/r2dbc/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.r2dbc.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data R2DBC Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-r2dbc\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"io.r2dbc:r2dbc-h2\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/main/java/org/springframework/boot/data/r2dbc/test/autoconfigure/AutoConfigureDataR2dbc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data R2DBC\n * tests. Most tests should consider using {@link DataR2dbcTest @DataR2dbcTest} rather\n * than using this annotation directly.\n *\n * @author Mark Paluch\n * @see DataR2dbcTest\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureDataSourceInitialization\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataR2dbc {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/main/java/org/springframework/boot/data/r2dbc/test/autoconfigure/DataR2dbcTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for a R2DBC test that focuses <strong>only</strong> on Data\n * R2DBC components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data R2DBC\n * tests. Similarly, component scanning is limited to R2DBC repositories and entities\n * ({@code @Table}).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataR2dbcTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataR2dbcTypeExcludeFilter.class)\n@AutoConfigureDataR2dbc\n@ImportAutoConfiguration\npublic @interface DataR2dbcTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/main/java/org/springframework/boot/data/r2dbc/test/autoconfigure/DataR2dbcTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataR2dbcTest @DataR2dbcTest} support.\n *\n * @author Mark Paluch\n */\nclass DataR2dbcTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataR2dbcTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/main/java/org/springframework/boot/data/r2dbc/test/autoconfigure/DataR2dbcTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataR2dbcTest @DataR2dbcTest}.\n *\n * @author Mark Paluch\n */\nclass DataR2dbcTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataR2dbcTest> {\n\n\tDataR2dbcTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/main/java/org/springframework/boot/data/r2dbc/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data R2DBC tests.\n */\n@NullMarked\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/main/resources/META-INF/spring/org.springframework.boot.data.r2dbc.test.autoconfigure.AutoConfigureDataR2dbc.imports",
    "content": "org.springframework.boot.data.r2dbc.autoconfigure.DataR2dbcAutoConfiguration\norg.springframework.boot.data.r2dbc.autoconfigure.DataR2dbcRepositoriesAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.R2dbcInitializationAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.R2dbcTransactionManagerAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/test/java/org/springframework/boot/data/r2dbc/test/autoconfigure/DataR2dbcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Map;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for {@link DataR2dbcTest}.\n *\n * @author Mark Paluch\n */\n@DataR2dbcTest(\n\t\tproperties = \"spring.sql.init.schemaLocations=classpath:org/springframework/boot/data/r2dbc/test/autoconfigure/schema.sql\")\nclass DataR2dbcTestIntegrationTests {\n\n\t@Autowired\n\tprivate DatabaseClient databaseClient;\n\n\t@Autowired\n\tprivate ConnectionFactory connectionFactory;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testDatabaseClient() {\n\t\tFlux<Map<String, Object>> all = this.databaseClient.sql(\"SELECT * FROM example\").fetch().all();\n\t\tStepVerifier.create(all).expectNextCount(1).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid replacesDefinedConnectionFactoryWithEmbeddedDefault() {\n\t\tString product = this.connectionFactory.getMetadata().getName();\n\t\tassertThat(product).isEqualTo(\"H2\");\n\t}\n\n\t@Test\n\tvoid registersExampleRepository() {\n\t\tassertThat(this.applicationContext.getBeanNamesForType(ExampleRepository.class)).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/test/java/org/springframework/boot/data/r2dbc/test/autoconfigure/DataR2dbcTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataR2dbcTest#properties properties} attribute of\n * {@link DataR2dbcTest @DataR2dbcTest}.\n *\n * @author Mark Paluch\n */\n@DataR2dbcTest(properties = \"spring.profiles.active=test\")\nclass DataR2dbcTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataR2dbcTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/test/java/org/springframework/boot/data/r2dbc/test/autoconfigure/Example.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.relational.core.mapping.Table;\n\n/**\n * Example entity used with {@link DataR2dbcTest} tests.\n *\n * @author Mark Paluch\n */\n@Table\npublic class Example {\n\n\t@Id\n\t@Nullable String id;\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/test/java/org/springframework/boot/data/r2dbc/test/autoconfigure/ExampleR2dbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication} used with {@link DataR2dbcTest} tests.\n *\n * @author Mark Paluch\n */\n@SpringBootApplication\npublic class ExampleR2dbcApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/test/java/org/springframework/boot/data/r2dbc/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.r2dbc.test.autoconfigure;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\n/**\n * Example {@link ReactiveCrudRepository} used with {@link DataR2dbcTest} tests.\n *\n * @author Mark Paluch\n */\npublic interface ExampleRepository extends ReactiveCrudRepository<Example, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-r2dbc-test/src/test/resources/org/springframework/boot/data/r2dbc/test/autoconfigure/schema.sql",
    "content": "drop table if exists example;\ncreate table example (id int, name varchar);\ninsert into example VALUES (1, 'Spring Boot');\n"
  },
  {
    "path": "module/spring-boot-data-redis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data Redis\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"io.lettuce:lettuce-core\")\n\tapi(\"org.springframework.data:spring-data-redis\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\timplementation(project(\":module:spring-boot-netty\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"com.redis:testcontainers-redis\")\n\toptional(\"redis.clients:jedis\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-testcontainers\")))\n\tdockerTestImplementation(\"ch.qos.logback:logback-classic\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/java/org/springframework/boot/data/redis/autoconfigure/DataRedisRepositoriesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.redis.domain.city.City;\nimport org.springframework.boot.data.redis.domain.city.CityRepository;\nimport org.springframework.boot.data.redis.domain.empty.EmptyPackage;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.repository.configuration.EnableRedisRepositories;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisRepositoriesAutoConfiguration}.\n *\n * @author Eddú Meléndez\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass DataRedisRepositoriesAutoConfigurationTests {\n\n\t@Container\n\tpublic static RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tTestPropertyValues\n\t\t\t.of(\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.applyTo(this.context.getEnvironment());\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tthis.context.register(TestConfiguration.class, DataRedisAutoConfiguration.class,\n\t\t\t\tDataRedisRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(CityRepository.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid testNoRepositoryConfiguration() {\n\t\tthis.context.register(EmptyConfiguration.class, DataRedisAutoConfiguration.class,\n\t\t\t\tDataRedisRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(\"redisTemplate\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid doesNotTriggerDefaultRepositoryDetectionIfCustomized() {\n\t\tthis.context.register(CustomizedConfiguration.class, DataRedisAutoConfiguration.class,\n\t\t\t\tDataRedisRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(CityRepository.class)).isNotNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(EmptyPackage.class)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(DataRedisRepositoriesAutoConfigurationTests.class)\n\t@EnableRedisRepositories(basePackageClasses = CityRepository.class)\n\tstatic class CustomizedConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/java/org/springframework/boot/data/redis/docker/compose/DataRedisDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.docker.compose;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Standalone;\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for {@link RedisDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Eddú Meléndez\n */\nclass DataRedisDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"redis-compose.yaml\", image = TestImage.REDIS)\n\tvoid runCreatesConnectionDetails(DataRedisConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"redis-ssl-compose.yaml\", image = TestImage.REDIS,\n\t\t\tadditionalResources = { \"ca.crt\", \"server.crt\", \"server.key\", \"client.crt\", \"client.key\" })\n\tvoid runWithSslCreatesConnectionDetails(DataRedisConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\tassertThat(sslContext).isNotNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"redis-compose.yaml\", image = TestImage.REDIS_STACK)\n\tvoid runWithRedisStackCreatesConnectionDetails(DataRedisConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"redis-compose.yaml\", image = TestImage.REDIS_STACK_SERVER)\n\tvoid runWithRedisStackServerCreatesConnectionDetails(DataRedisConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(DataRedisConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isNull();\n\t\tassertThat(connectionDetails.getPassword()).isNull();\n\t\tassertThat(connectionDetails.getCluster()).isNull();\n\t\tassertThat(connectionDetails.getSentinel()).isNull();\n\t\tStandalone standalone = connectionDetails.getStandalone();\n\t\tassertThat(standalone).isNotNull();\n\t\tassertThat(standalone.getDatabase()).isZero();\n\t\tassertThat(standalone.getPort()).isGreaterThan(0);\n\t\tassertThat(standalone.getHost()).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/java/org/springframework/boot/data/redis/testcontainers/CustomRedisContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.testcontainers;\n\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport com.redis.testcontainers.RedisContainer;\nimport com.redis.testcontainers.RedisStackContainer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.TestContainerConnectionSource;\nimport org.springframework.core.annotation.MergedAnnotation;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for {@link RedisContainerConnectionDetailsFactory} when using a custom container\n * without \"redis\" as the name.\n *\n * @author Phillip Webb\n */\nclass CustomRedisContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid getConnectionDetailsWhenRedisContainerWithCustomName() {\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(null);\n\t\tMergedAnnotation<ServiceConnection> annotation = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"value\", \"\"));\n\t\tSupplier<RedisContainer> containerSupplier = () -> new RedisContainer(\"redis\");\n\t\tContainerConnectionSource<RedisContainer> source = TestContainerConnectionSource.create(\"test\",\n\t\t\t\tmock(Origin.class), RedisContainer.class, \"mycustomimage\", annotation, containerSupplier);\n\t\tMap<Class<?>, ConnectionDetails> connectionDetails = factories.getConnectionDetails(source, true);\n\t\tassertThat(connectionDetails.get(DataRedisConnectionDetails.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid getConnectionDetailsWhenRedisStackContainerWithCustomName() {\n\t\tConnectionDetailsFactories factories = new ConnectionDetailsFactories(null);\n\t\tMergedAnnotation<ServiceConnection> annotation = MergedAnnotation.of(ServiceConnection.class,\n\t\t\t\tMap.of(\"value\", \"\"));\n\t\tSupplier<RedisStackContainer> containerSupplier = () -> new RedisStackContainer(\"redis\");\n\t\tContainerConnectionSource<RedisStackContainer> source = TestContainerConnectionSource.create(\"test\",\n\t\t\t\tmock(Origin.class), RedisStackContainer.class, \"mycustomimage\", annotation, containerSupplier);\n\t\tMap<Class<?>, ConnectionDetails> connectionDetails = factories.getConnectionDetails(source, true);\n\t\tassertThat(connectionDetails.get(DataRedisConnectionDetails.class)).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/java/org/springframework/boot/data/redis/testcontainers/RedisContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.testcontainers;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RedisContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass RedisContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired(required = false)\n\tprivate DataRedisConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate RedisConnectionFactory connectionFactory;\n\n\t@Test\n\tvoid connectionCanBeMadeToRedisContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\ttry (RedisConnection connection = this.connectionFactory.getConnection()) {\n\t\t\tassertThat(connection.commands().echo(\"Hello, World\".getBytes())).isEqualTo(\"Hello, World\".getBytes());\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(DataRedisAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/java/org/springframework/boot/data/redis/testcontainers/RedisStackContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.testcontainers;\n\nimport com.redis.testcontainers.RedisStackContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RedisContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass RedisStackContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RedisStackContainer redis = TestImage.container(RedisStackContainer.class);\n\n\t@Autowired(required = false)\n\tprivate DataRedisConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate RedisConnectionFactory connectionFactory;\n\n\t@Test\n\tvoid connectionCanBeMadeToRedisContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\ttry (RedisConnection connection = this.connectionFactory.getConnection()) {\n\t\t\tassertThat(connection.commands().echo(\"Hello, World\".getBytes())).isEqualTo(\"Hello, World\".getBytes());\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(DataRedisAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/java/org/springframework/boot/data/redis/testcontainers/RedisStackServerContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.testcontainers;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.RedisStackServerContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RedisContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass RedisStackServerContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RedisStackServerContainer redis = TestImage.container(RedisStackServerContainer.class);\n\n\t@Autowired(required = false)\n\tprivate DataRedisConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate RedisConnectionFactory connectionFactory;\n\n\t@Test\n\tvoid connectionCanBeMadeToRedisContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\ttry (RedisConnection connection = this.connectionFactory.getConnection()) {\n\t\t\tassertThat(connection.commands().echo(\"Hello, World\".getBytes())).isEqualTo(\"Hello, World\".getBytes());\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(DataRedisAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/redis-compose.yaml",
    "content": "services:\n  redis:\n    image: '{imageName}'\n    ports:\n      - '6379'\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/redis-ssl-compose.yaml",
    "content": "services:\n  redis:\n    image: '{imageName}'\n    ports:\n      - '6379'\n    secrets:\n      - ssl-ca\n      - ssl-key\n      - ssl-cert\n    command: 'redis-server --tls-port 6379 --port 0 --tls-cert-file /run/secrets/ssl-cert --tls-key-file /run/secrets/ssl-key --tls-ca-cert-file /run/secrets/ssl-ca'\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'\n      - 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\nsecrets:\n  ssl-ca:\n    file: 'ca.crt'\n  ssl-key:\n    file: 'server.key'\n  ssl-cert:\n    file: 'server.crt'\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/org/springframework/boot/data/redis/docker/compose/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/ClientResourcesBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport io.lettuce.core.resource.ClientResources;\nimport io.lettuce.core.resource.ClientResources.Builder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Builder} to fine-tune its auto-configuration before it creates the\n * {@link ClientResources}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic interface ClientResourcesBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link Builder}.\n\t * @param clientResourcesBuilder the builder to customize\n\t */\n\tvoid customize(Builder clientResourcesBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisOperations;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.StringRedisTemplate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis support.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Christian Dupuis\n * @author Christoph Strobl\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Marco Aust\n * @author Mark Paluch\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(RedisOperations.class)\n@EnableConfigurationProperties(DataRedisProperties.class)\n@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })\npublic final class DataRedisAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(DataRedisConnectionDetails.class)\n\tPropertiesDataRedisConnectionDetails redisConnectionDetails(DataRedisProperties properties,\n\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesDataRedisConnectionDetails(properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"redisTemplate\")\n\t@ConditionalOnSingleCandidate(RedisConnectionFactory.class)\n\tRedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {\n\t\tRedisTemplate<Object, Object> template = new RedisTemplate<>();\n\t\ttemplate.setConnectionFactory(redisConnectionFactory);\n\t\treturn template;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnSingleCandidate(RedisConnectionFactory.class)\n\tStringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {\n\t\treturn new StringRedisTemplate(redisConnectionFactory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisConnectionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Cluster;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Node;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Sentinel;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Standalone;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisProperties.Pool;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.data.redis.connection.RedisClusterConfiguration;\nimport org.springframework.data.redis.connection.RedisNode;\nimport org.springframework.data.redis.connection.RedisPassword;\nimport org.springframework.data.redis.connection.RedisSentinelConfiguration;\nimport org.springframework.data.redis.connection.RedisStandaloneConfiguration;\nimport org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Base Redis connection configuration.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Alen Turkovic\n * @author Scott Frederick\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nabstract class DataRedisConnectionConfiguration {\n\n\tprivate static final boolean COMMONS_POOL2_AVAILABLE = ClassUtils.isPresent(\"org.apache.commons.pool2.ObjectPool\",\n\t\t\tDataRedisConnectionConfiguration.class.getClassLoader());\n\n\tprivate final DataRedisProperties properties;\n\n\tprivate final @Nullable RedisStandaloneConfiguration standaloneConfiguration;\n\n\tprivate final @Nullable RedisSentinelConfiguration sentinelConfiguration;\n\n\tprivate final @Nullable RedisClusterConfiguration clusterConfiguration;\n\n\tprivate final @Nullable RedisStaticMasterReplicaConfiguration masterReplicaConfiguration;\n\n\tprivate final DataRedisConnectionDetails connectionDetails;\n\n\tprotected final Mode mode;\n\n\tprotected DataRedisConnectionConfiguration(DataRedisProperties properties,\n\t\t\tDataRedisConnectionDetails connectionDetails,\n\t\t\tObjectProvider<RedisStandaloneConfiguration> standaloneConfigurationProvider,\n\t\t\tObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,\n\t\t\tObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider,\n\t\t\tObjectProvider<RedisStaticMasterReplicaConfiguration> masterReplicaConfiguration) {\n\t\tthis.properties = properties;\n\t\tthis.standaloneConfiguration = standaloneConfigurationProvider.getIfAvailable();\n\t\tthis.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();\n\t\tthis.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();\n\t\tthis.masterReplicaConfiguration = masterReplicaConfiguration.getIfAvailable();\n\t\tthis.connectionDetails = connectionDetails;\n\t\tthis.mode = determineMode();\n\t}\n\n\tprotected final RedisStandaloneConfiguration getStandaloneConfig() {\n\t\tif (this.standaloneConfiguration != null) {\n\t\t\treturn this.standaloneConfiguration;\n\t\t}\n\t\tRedisStandaloneConfiguration config = new RedisStandaloneConfiguration();\n\t\tStandalone standalone = this.connectionDetails.getStandalone();\n\t\tAssert.state(standalone != null, \"'standalone' must not be null\");\n\t\tconfig.setHostName(standalone.getHost());\n\t\tconfig.setPort(standalone.getPort());\n\t\tconfig.setUsername(this.connectionDetails.getUsername());\n\t\tconfig.setPassword(RedisPassword.of(this.connectionDetails.getPassword()));\n\t\tconfig.setDatabase(standalone.getDatabase());\n\t\treturn config;\n\t}\n\n\tprotected final @Nullable RedisSentinelConfiguration getSentinelConfig() {\n\t\tif (this.sentinelConfiguration != null) {\n\t\t\treturn this.sentinelConfiguration;\n\t\t}\n\t\tif (this.connectionDetails.getSentinel() != null) {\n\t\t\tRedisSentinelConfiguration config = new RedisSentinelConfiguration();\n\t\t\tconfig.master(this.connectionDetails.getSentinel().getMaster());\n\t\t\tconfig.setSentinels(createSentinels(this.connectionDetails.getSentinel()));\n\t\t\tconfig.setUsername(this.connectionDetails.getUsername());\n\t\t\tString password = this.connectionDetails.getPassword();\n\t\t\tif (password != null) {\n\t\t\t\tconfig.setPassword(RedisPassword.of(password));\n\t\t\t}\n\t\t\tconfig.setSentinelUsername(this.connectionDetails.getSentinel().getUsername());\n\t\t\tString sentinelPassword = this.connectionDetails.getSentinel().getPassword();\n\t\t\tif (sentinelPassword != null) {\n\t\t\t\tconfig.setSentinelPassword(RedisPassword.of(sentinelPassword));\n\t\t\t}\n\t\t\tconfig.setDatabase(this.connectionDetails.getSentinel().getDatabase());\n\t\t\treturn config;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create a {@link RedisClusterConfiguration} if necessary.\n\t * @return {@literal null} if no cluster settings are set.\n\t */\n\tprotected final @Nullable RedisClusterConfiguration getClusterConfiguration() {\n\t\tif (this.clusterConfiguration != null) {\n\t\t\treturn this.clusterConfiguration;\n\t\t}\n\t\tDataRedisProperties.Cluster clusterProperties = this.properties.getCluster();\n\t\tif (this.connectionDetails.getCluster() != null) {\n\t\t\tRedisClusterConfiguration config = new RedisClusterConfiguration();\n\t\t\tconfig.setClusterNodes(getNodes(this.connectionDetails.getCluster()));\n\t\t\tif (clusterProperties != null && clusterProperties.getMaxRedirects() != null) {\n\t\t\t\tconfig.setMaxRedirects(clusterProperties.getMaxRedirects());\n\t\t\t}\n\t\t\tconfig.setUsername(this.connectionDetails.getUsername());\n\t\t\tString password = this.connectionDetails.getPassword();\n\t\t\tif (password != null) {\n\t\t\t\tconfig.setPassword(RedisPassword.of(password));\n\t\t\t}\n\t\t\treturn config;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprotected final @Nullable RedisStaticMasterReplicaConfiguration getMasterReplicaConfiguration() {\n\t\tif (this.masterReplicaConfiguration != null) {\n\t\t\treturn this.masterReplicaConfiguration;\n\t\t}\n\t\tif (this.connectionDetails.getMasterReplica() != null) {\n\t\t\tList<Node> nodes = this.connectionDetails.getMasterReplica().getNodes();\n\t\t\tAssert.state(!nodes.isEmpty(), \"At least one node is required for master-replica configuration\");\n\t\t\tRedisStaticMasterReplicaConfiguration config = new RedisStaticMasterReplicaConfiguration(\n\t\t\t\t\tnodes.get(0).host(), nodes.get(0).port());\n\t\t\tnodes.stream().skip(1).forEach((node) -> config.addNode(node.host(), node.port()));\n\t\t\tconfig.setUsername(this.connectionDetails.getUsername());\n\t\t\tString password = this.connectionDetails.getPassword();\n\t\t\tif (password != null) {\n\t\t\t\tconfig.setPassword(RedisPassword.of(password));\n\t\t\t}\n\t\t\treturn config;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<RedisNode> getNodes(Cluster cluster) {\n\t\treturn cluster.getNodes().stream().map(this::asRedisNode).toList();\n\t}\n\n\tprivate RedisNode asRedisNode(Node node) {\n\t\treturn new RedisNode(node.host(), node.port());\n\t}\n\n\tprotected final DataRedisProperties getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tprotected @Nullable SslBundle getSslBundle() {\n\t\treturn this.connectionDetails.getSslBundle();\n\t}\n\n\tprotected final boolean isSslEnabled() {\n\t\treturn getProperties().getSsl().isEnabled();\n\t}\n\n\tprotected final boolean urlUsesSsl(String url) {\n\t\treturn DataRedisUrl.of(url).useSsl();\n\t}\n\n\tprotected boolean isPoolEnabled(Pool pool) {\n\t\tBoolean enabled = pool.getEnabled();\n\t\treturn (enabled != null) ? enabled : COMMONS_POOL2_AVAILABLE;\n\t}\n\n\tprivate List<RedisNode> createSentinels(Sentinel sentinel) {\n\t\tList<RedisNode> nodes = new ArrayList<>();\n\t\tfor (Node node : sentinel.getNodes()) {\n\t\t\tnodes.add(asRedisNode(node));\n\t\t}\n\t\treturn nodes;\n\t}\n\n\tprotected final DataRedisConnectionDetails getConnectionDetails() {\n\t\treturn this.connectionDetails;\n\t}\n\n\tprivate Mode determineMode() {\n\t\tif (getSentinelConfig() != null) {\n\t\t\treturn Mode.SENTINEL;\n\t\t}\n\t\tif (getClusterConfiguration() != null) {\n\t\t\treturn Mode.CLUSTER;\n\t\t}\n\t\tif (getMasterReplicaConfiguration() != null) {\n\t\t\treturn Mode.MASTER_REPLICA;\n\t\t}\n\t\treturn Mode.STANDALONE;\n\t}\n\n\tenum Mode {\n\n\t\tSTANDALONE, CLUSTER, MASTER_REPLICA, SENTINEL\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.util.Assert;\n\n/**\n * Details required to establish a connection to a Redis service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface DataRedisConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Login username of the redis server.\n\t * @return the login username of the redis server\n\t */\n\tdefault @Nullable String getUsername() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Login password of the redis server.\n\t * @return the login password of the redis server\n\t */\n\tdefault @Nullable String getPassword() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Redis standalone configuration. Mutually exclusive with {@link #getSentinel()},\n\t * {@link #getCluster()} and {@link #getMasterReplica()}.\n\t * @return the Redis standalone configuration\n\t */\n\tdefault @Nullable Standalone getStandalone() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Redis sentinel configuration. Mutually exclusive with {@link #getStandalone()},\n\t * {@link #getCluster()} and {@link #getMasterReplica()}.\n\t * @return the Redis sentinel configuration\n\t */\n\tdefault @Nullable Sentinel getSentinel() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Redis cluster configuration. Mutually exclusive with {@link #getStandalone()},\n\t * {@link #getSentinel()} and {@link #getMasterReplica()}.\n\t * @return the Redis cluster configuration\n\t */\n\tdefault @Nullable Cluster getCluster() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Redis master replica configuration. Mutually exclusive with\n\t * {@link #getStandalone()}, {@link #getSentinel()} and {@link #getCluster()}.\n\t * @return the Redis master replica configuration\n\t */\n\tdefault @Nullable MasterReplica getMasterReplica() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Redis standalone configuration.\n\t */\n\tinterface Standalone {\n\n\t\t/**\n\t\t * Redis server host.\n\t\t * @return the redis server host\n\t\t */\n\t\tString getHost();\n\n\t\t/**\n\t\t * Redis server port.\n\t\t * @return the redis server port\n\t\t */\n\t\tint getPort();\n\n\t\t/**\n\t\t * Database index used by the connection factory.\n\t\t * @return the database index used by the connection factory\n\t\t */\n\t\tdefault int getDatabase() {\n\t\t\treturn 0;\n\t\t}\n\n\t\t/**\n\t\t * Creates a new instance with the given host and port.\n\t\t * @param host the host\n\t\t * @param port the port\n\t\t * @return the new instance\n\t\t */\n\t\tstatic Standalone of(String host, int port) {\n\t\t\treturn of(host, port, 0);\n\t\t}\n\n\t\t/**\n\t\t * Creates a new instance with the given host, port and database.\n\t\t * @param host the host\n\t\t * @param port the port\n\t\t * @param database the database\n\t\t * @return the new instance\n\t\t */\n\t\tstatic Standalone of(String host, int port, int database) {\n\t\t\tAssert.hasLength(host, \"'host' must not be empty\");\n\t\t\treturn new Standalone() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getHost() {\n\t\t\t\t\treturn host;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic int getPort() {\n\t\t\t\t\treturn port;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic int getDatabase() {\n\t\t\t\t\treturn database;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t/**\n\t * Redis sentinel configuration.\n\t */\n\tinterface Sentinel {\n\n\t\t/**\n\t\t * Database index used by the connection factory.\n\t\t * @return the database index used by the connection factory\n\t\t */\n\t\tint getDatabase();\n\n\t\t/**\n\t\t * Name of the Redis server.\n\t\t * @return the name of the Redis server\n\t\t */\n\t\tString getMaster();\n\n\t\t/**\n\t\t * List of nodes.\n\t\t * @return the list of nodes\n\t\t */\n\t\tList<Node> getNodes();\n\n\t\t/**\n\t\t * Login username for authenticating with sentinel(s).\n\t\t * @return the login username for authenticating with sentinel(s) or {@code null}\n\t\t */\n\t\t@Nullable String getUsername();\n\n\t\t/**\n\t\t * Password for authenticating with sentinel(s).\n\t\t * @return the password for authenticating with sentinel(s) or {@code null}\n\t\t */\n\t\t@Nullable String getPassword();\n\n\t}\n\n\t/**\n\t * Redis cluster configuration.\n\t */\n\tinterface Cluster {\n\n\t\t/**\n\t\t * Nodes to bootstrap from. This represents an \"initial\" list of cluster nodes and\n\t\t * is required to have at least one entry.\n\t\t * @return nodes to bootstrap from\n\t\t */\n\t\tList<Node> getNodes();\n\n\t}\n\n\t/**\n\t * Redis master replica configuration.\n\t */\n\tinterface MasterReplica {\n\n\t\t/**\n\t\t * Static nodes to use. This represents the full list of cluster nodes and is\n\t\t * required to have at least one entry.\n\t\t * @return the nodes to use\n\t\t */\n\t\tList<Node> getNodes();\n\n\t}\n\n\t/**\n\t * A node in a sentinel or cluster configuration.\n\t *\n\t * @param host the hostname of the node\n\t * @param port the port of the node\n\t */\n\trecord Node(String host, int port) {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Redis.\n *\n * @author Dave Syer\n * @author Christoph Strobl\n * @author Eddú Meléndez\n * @author Marco Aust\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.redis\")\npublic class DataRedisProperties {\n\n\t/**\n\t * Database index used by the connection factory.\n\t */\n\tprivate int database;\n\n\t/**\n\t * Connection URL. Overrides host, port, username, password, and database. Example:\n\t * redis://user:password@example.com:6379/8\n\t */\n\tprivate @Nullable String url;\n\n\t/**\n\t * Redis server host.\n\t */\n\tprivate String host = \"localhost\";\n\n\t/**\n\t * Login username of the redis server.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the redis server.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Redis server port.\n\t */\n\tprivate int port = 6379;\n\n\t/**\n\t * Read timeout.\n\t */\n\tprivate @Nullable Duration timeout;\n\n\t/**\n\t * Connection timeout.\n\t */\n\tprivate @Nullable Duration connectTimeout;\n\n\t/**\n\t * Client name to be set on connections with CLIENT SETNAME.\n\t */\n\tprivate @Nullable String clientName;\n\n\t/**\n\t * Type of client to use. By default, auto-detected according to the classpath.\n\t */\n\tprivate @Nullable ClientType clientType;\n\n\tprivate @Nullable Sentinel sentinel;\n\n\tprivate @Nullable Cluster cluster;\n\n\tprivate @Nullable Masterreplica masterreplica;\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tprivate final Jedis jedis = new Jedis();\n\n\tprivate final Lettuce lettuce = new Lettuce();\n\n\tpublic int getDatabase() {\n\t\treturn this.database;\n\t}\n\n\tpublic void setDatabase(int database) {\n\t\tthis.database = database;\n\t}\n\n\tpublic @Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\tpublic void setUrl(@Nullable String url) {\n\t\tthis.url = url;\n\t}\n\n\tpublic String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic @Nullable Duration getTimeout() {\n\t\treturn this.timeout;\n\t}\n\n\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\tpublic @Nullable Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(@Nullable Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic @Nullable String getClientName() {\n\t\treturn this.clientName;\n\t}\n\n\tpublic void setClientName(@Nullable String clientName) {\n\t\tthis.clientName = clientName;\n\t}\n\n\tpublic @Nullable ClientType getClientType() {\n\t\treturn this.clientType;\n\t}\n\n\tpublic void setClientType(@Nullable ClientType clientType) {\n\t\tthis.clientType = clientType;\n\t}\n\n\tpublic @Nullable Sentinel getSentinel() {\n\t\treturn this.sentinel;\n\t}\n\n\tpublic void setSentinel(@Nullable Sentinel sentinel) {\n\t\tthis.sentinel = sentinel;\n\t}\n\n\tpublic @Nullable Cluster getCluster() {\n\t\treturn this.cluster;\n\t}\n\n\tpublic void setCluster(@Nullable Cluster cluster) {\n\t\tthis.cluster = cluster;\n\t}\n\n\tpublic @Nullable Masterreplica getMasterreplica() {\n\t\treturn this.masterreplica;\n\t}\n\n\tpublic void setMasterreplica(@Nullable Masterreplica masterreplica) {\n\t\tthis.masterreplica = masterreplica;\n\t}\n\n\tpublic Jedis getJedis() {\n\t\treturn this.jedis;\n\t}\n\n\tpublic Lettuce getLettuce() {\n\t\treturn this.lettuce;\n\t}\n\n\t/**\n\t * Type of Redis client to use.\n\t */\n\tpublic enum ClientType {\n\n\t\t/**\n\t\t * Use the Lettuce redis client.\n\t\t */\n\t\tLETTUCE,\n\n\t\t/**\n\t\t * Use the Jedis redis client.\n\t\t */\n\t\tJEDIS\n\n\t}\n\n\t/**\n\t * Pool properties.\n\t */\n\tpublic static class Pool {\n\n\t\t/**\n\t\t * Whether to enable the pool. Enabled automatically if \"commons-pool2\" is\n\t\t * available. With Jedis, pooling is implicitly enabled in sentinel mode and this\n\t\t * setting only applies to single node setup.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * Maximum number of \"idle\" connections in the pool. Use a negative value to\n\t\t * indicate an unlimited number of idle connections.\n\t\t */\n\t\tprivate int maxIdle = 8;\n\n\t\t/**\n\t\t * Target for the minimum number of idle connections to maintain in the pool. This\n\t\t * setting only has an effect if both it and time between eviction runs are\n\t\t * positive.\n\t\t */\n\t\tprivate int minIdle;\n\n\t\t/**\n\t\t * Maximum number of connections that can be allocated by the pool at a given\n\t\t * time. Use a negative value for no limit.\n\t\t */\n\t\tprivate int maxActive = 8;\n\n\t\t/**\n\t\t * Maximum amount of time a connection allocation should block before throwing an\n\t\t * exception when the pool is exhausted. Use a negative value to block\n\t\t * indefinitely.\n\t\t */\n\t\tprivate Duration maxWait = Duration.ofMillis(-1);\n\n\t\t/**\n\t\t * Time between runs of the idle object evictor thread. When positive, the idle\n\t\t * object evictor thread starts, otherwise no idle object eviction is performed.\n\t\t */\n\t\tprivate @Nullable Duration timeBetweenEvictionRuns;\n\n\t\tpublic @Nullable Boolean getEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(@Nullable Boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic int getMaxIdle() {\n\t\t\treturn this.maxIdle;\n\t\t}\n\n\t\tpublic void setMaxIdle(int maxIdle) {\n\t\t\tthis.maxIdle = maxIdle;\n\t\t}\n\n\t\tpublic int getMinIdle() {\n\t\t\treturn this.minIdle;\n\t\t}\n\n\t\tpublic void setMinIdle(int minIdle) {\n\t\t\tthis.minIdle = minIdle;\n\t\t}\n\n\t\tpublic int getMaxActive() {\n\t\t\treturn this.maxActive;\n\t\t}\n\n\t\tpublic void setMaxActive(int maxActive) {\n\t\t\tthis.maxActive = maxActive;\n\t\t}\n\n\t\tpublic Duration getMaxWait() {\n\t\t\treturn this.maxWait;\n\t\t}\n\n\t\tpublic void setMaxWait(Duration maxWait) {\n\t\t\tthis.maxWait = maxWait;\n\t\t}\n\n\t\tpublic @Nullable Duration getTimeBetweenEvictionRuns() {\n\t\t\treturn this.timeBetweenEvictionRuns;\n\t\t}\n\n\t\tpublic void setTimeBetweenEvictionRuns(@Nullable Duration timeBetweenEvictionRuns) {\n\t\t\tthis.timeBetweenEvictionRuns = timeBetweenEvictionRuns;\n\t\t}\n\n\t}\n\n\t/**\n\t * Cluster properties.\n\t */\n\tpublic static class Cluster {\n\n\t\t/**\n\t\t * List of \"host:port\" pairs to bootstrap from. This represents an \"initial\" list\n\t\t * of cluster nodes and is required to have at least one entry.\n\t\t */\n\t\tprivate @Nullable List<String> nodes;\n\n\t\t/**\n\t\t * Maximum number of redirects to follow when executing commands across the\n\t\t * cluster.\n\t\t */\n\t\tprivate @Nullable Integer maxRedirects;\n\n\t\tpublic @Nullable List<String> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t\tpublic void setNodes(@Nullable List<String> nodes) {\n\t\t\tthis.nodes = nodes;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxRedirects() {\n\t\t\treturn this.maxRedirects;\n\t\t}\n\n\t\tpublic void setMaxRedirects(@Nullable Integer maxRedirects) {\n\t\t\tthis.maxRedirects = maxRedirects;\n\t\t}\n\n\t}\n\n\t/**\n\t * Master Replica properties.\n\t */\n\tpublic static class Masterreplica {\n\n\t\t/**\n\t\t * Static list of \"host:port\" pairs to use, at least one entry is required.\n\t\t */\n\t\tprivate @Nullable List<String> nodes;\n\n\t\tpublic @Nullable List<String> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t\tpublic void setNodes(@Nullable List<String> nodes) {\n\t\t\tthis.nodes = nodes;\n\t\t}\n\n\t}\n\n\t/**\n\t * Redis sentinel properties.\n\t */\n\tpublic static class Sentinel {\n\n\t\t/**\n\t\t * Name of the Redis server.\n\t\t */\n\t\tprivate @Nullable String master;\n\n\t\t/**\n\t\t * List of \"host:port\" pairs.\n\t\t */\n\t\tprivate @Nullable List<String> nodes;\n\n\t\t/**\n\t\t * Login username for authenticating with sentinel(s).\n\t\t */\n\t\tprivate @Nullable String username;\n\n\t\t/**\n\t\t * Password for authenticating with sentinel(s).\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\tpublic @Nullable String getMaster() {\n\t\t\treturn this.master;\n\t\t}\n\n\t\tpublic void setMaster(@Nullable String master) {\n\t\t\tthis.master = master;\n\t\t}\n\n\t\tpublic @Nullable List<String> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t\tpublic void setNodes(@Nullable List<String> nodes) {\n\t\t\tthis.nodes = nodes;\n\t\t}\n\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support. Enabled automatically if \"bundle\" is provided\n\t\t * unless specified otherwise.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn (this.enabled != null) ? this.enabled : this.bundle != null;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\t/**\n\t * Jedis client properties.\n\t */\n\tpublic static class Jedis {\n\n\t\t/**\n\t\t * Jedis pool configuration.\n\t\t */\n\t\tprivate final Pool pool = new Pool();\n\n\t\tpublic Pool getPool() {\n\t\t\treturn this.pool;\n\t\t}\n\n\t}\n\n\t/**\n\t * Lettuce client properties.\n\t */\n\tpublic static class Lettuce {\n\n\t\t/**\n\t\t * Shutdown timeout.\n\t\t */\n\t\tprivate Duration shutdownTimeout = Duration.ofMillis(100);\n\n\t\t/**\n\t\t * Defines from which Redis nodes data is read.\n\t\t */\n\t\tprivate @Nullable String readFrom;\n\n\t\t/**\n\t\t * Lettuce pool configuration.\n\t\t */\n\t\tprivate final Pool pool = new Pool();\n\n\t\tprivate final Cluster cluster = new Cluster();\n\n\t\tpublic Duration getShutdownTimeout() {\n\t\t\treturn this.shutdownTimeout;\n\t\t}\n\n\t\tpublic void setShutdownTimeout(Duration shutdownTimeout) {\n\t\t\tthis.shutdownTimeout = shutdownTimeout;\n\t\t}\n\n\t\tpublic @Nullable String getReadFrom() {\n\t\t\treturn this.readFrom;\n\t\t}\n\n\t\tpublic void setReadFrom(@Nullable String readFrom) {\n\t\t\tthis.readFrom = readFrom;\n\t\t}\n\n\t\tpublic Pool getPool() {\n\t\t\treturn this.pool;\n\t\t}\n\n\t\tpublic Cluster getCluster() {\n\t\t\treturn this.cluster;\n\t\t}\n\n\t\tpublic static class Cluster {\n\n\t\t\tprivate final Refresh refresh = new Refresh();\n\n\t\t\tpublic Refresh getRefresh() {\n\t\t\t\treturn this.refresh;\n\t\t\t}\n\n\t\t\tpublic static class Refresh {\n\n\t\t\t\t/**\n\t\t\t\t * Whether to discover and query all cluster nodes for obtaining the\n\t\t\t\t * cluster topology. When set to false, only the initial seed nodes are\n\t\t\t\t * used as sources for topology discovery.\n\t\t\t\t */\n\t\t\t\tprivate boolean dynamicRefreshSources = true;\n\n\t\t\t\t/**\n\t\t\t\t * Cluster topology refresh period.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Duration period;\n\n\t\t\t\tpublic boolean isDynamicRefreshSources() {\n\t\t\t\t\treturn this.dynamicRefreshSources;\n\t\t\t\t}\n\n\t\t\t\tpublic void setDynamicRefreshSources(boolean dynamicRefreshSources) {\n\t\t\t\t\tthis.dynamicRefreshSources = dynamicRefreshSources;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Duration getPeriod() {\n\t\t\t\t\treturn this.period;\n\t\t\t\t}\n\n\t\t\t\tpublic void setPeriod(@Nullable Duration period) {\n\t\t\t\t\tthis.period = period;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisReactiveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\nimport org.springframework.data.redis.core.ReactiveRedisTemplate;\nimport org.springframework.data.redis.core.ReactiveStringRedisTemplate;\nimport org.springframework.data.redis.serializer.RedisSerializationContext;\nimport org.springframework.data.redis.serializer.RedisSerializer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive Redis\n * support.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataRedisAutoConfiguration.class)\n@ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisTemplate.class, Flux.class })\npublic final class DataRedisReactiveAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"reactiveRedisTemplate\")\n\t@ConditionalOnBean(ReactiveRedisConnectionFactory.class)\n\tReactiveRedisTemplate<Object, Object> reactiveRedisTemplate(\n\t\t\tReactiveRedisConnectionFactory reactiveRedisConnectionFactory, ResourceLoader resourceLoader) {\n\t\tRedisSerializer<Object> javaSerializer = RedisSerializer.java(resourceLoader.getClassLoader());\n\t\tRedisSerializationContext<Object, Object> serializationContext = RedisSerializationContext\n\t\t\t.newSerializationContext()\n\t\t\t.key(javaSerializer)\n\t\t\t.value(javaSerializer)\n\t\t\t.hashKey(javaSerializer)\n\t\t\t.hashValue(javaSerializer)\n\t\t\t.build();\n\t\treturn new ReactiveRedisTemplate<>(reactiveRedisConnectionFactory, serializationContext);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"reactiveStringRedisTemplate\")\n\t@ConditionalOnBean(ReactiveRedisConnectionFactory.class)\n\tReactiveStringRedisTemplate reactiveStringRedisTemplate(\n\t\t\tReactiveRedisConnectionFactory reactiveRedisConnectionFactory) {\n\t\treturn new ReactiveStringRedisTemplate(reactiveRedisConnectionFactory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisRepositoriesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.repository.configuration.EnableRedisRepositories;\nimport org.springframework.data.redis.repository.support.RedisRepositoryFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis\n * Repositories.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see EnableRedisRepositories\n */\n@AutoConfiguration(after = DataRedisAutoConfiguration.class)\n@ConditionalOnClass(EnableRedisRepositories.class)\n@ConditionalOnBean(RedisConnectionFactory.class)\n@ConditionalOnBooleanProperty(name = \"spring.data.redis.repositories.enabled\", matchIfMissing = true)\n@ConditionalOnMissingBean(RedisRepositoryFactoryBean.class)\n@Import(DataRedisRepositoriesRegistrar.class)\npublic final class DataRedisRepositoriesAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisRepositoriesRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.lang.annotation.Annotation;\n\nimport org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.data.redis.repository.configuration.EnableRedisRepositories;\nimport org.springframework.data.redis.repository.configuration.RedisRepositoryConfigurationExtension;\nimport org.springframework.data.repository.config.RepositoryConfigurationExtension;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Redis\n * Repositories.\n *\n * @author Eddú Meléndez\n */\nclass DataRedisRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {\n\n\t@Override\n\tprotected Class<? extends Annotation> getAnnotation() {\n\t\treturn EnableRedisRepositories.class;\n\t}\n\n\t@Override\n\tprotected Class<?> getConfiguration() {\n\t\treturn EnableRedisRepositoriesConfiguration.class;\n\t}\n\n\t@Override\n\tprotected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {\n\t\treturn new RedisRepositoryConfigurationExtension();\n\t}\n\n\t@EnableRedisRepositories\n\tprivate static final class EnableRedisRepositoriesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisUrl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.StringUtils;\n\n/**\n * A parsed URL used to connect to Redis.\n *\n * @param uri the source URI\n * @param useSsl if SSL is used to connect\n * @param credentials the connection credentials\n * @param database the database index\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Alen Turkovic\n * @author Scott Frederick\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Yanming Zhou\n * @author Phillip Webb\n */\nrecord DataRedisUrl(URI uri, boolean useSsl, Credentials credentials, int database) {\n\n\t@Contract(\"!null -> !null\")\n\tstatic @Nullable DataRedisUrl of(@Nullable String url) {\n\t\treturn (url != null) ? of(toUri(url)) : null;\n\t}\n\n\tprivate static DataRedisUrl of(URI uri) {\n\t\tboolean useSsl = (\"rediss\".equals(uri.getScheme()));\n\t\tCredentials credentials = Credentials.fromUserInfo(uri.getUserInfo());\n\t\tint database = getDatabase(uri);\n\t\treturn new DataRedisUrl(uri, useSsl, credentials, database);\n\t}\n\n\tprivate static int getDatabase(URI uri) {\n\t\tString path = uri.getPath();\n\t\tString[] split = (!StringUtils.hasText(path)) ? new String[0] : path.split(\"/\", 2);\n\t\treturn (split.length > 1 && !split[1].isEmpty()) ? Integer.parseInt(split[1]) : 0;\n\t}\n\n\tprivate static URI toUri(String url) {\n\t\ttry {\n\t\t\tURI uri = new URI(url);\n\t\t\tString scheme = uri.getScheme();\n\t\t\tif (!\"redis\".equals(scheme) && !\"rediss\".equals(scheme)) {\n\t\t\t\tthrow new DataRedisUrlSyntaxException(url);\n\t\t\t}\n\t\t\treturn uri;\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new DataRedisUrlSyntaxException(url, ex);\n\t\t}\n\t}\n\n\t/**\n\t * Redis connection credentials.\n\t *\n\t * @param username the username or {@code null}\n\t * @param password the password\n\t */\n\trecord Credentials(@Nullable String username, @Nullable String password) {\n\n\t\tprivate static final Credentials NONE = new Credentials(null, null);\n\n\t\tprivate static Credentials fromUserInfo(@Nullable String userInfo) {\n\t\t\tif (userInfo == null) {\n\t\t\t\treturn NONE;\n\t\t\t}\n\t\t\tint index = userInfo.indexOf(':');\n\t\t\tif (index != -1) {\n\t\t\t\treturn new Credentials(userInfo.substring(0, index), userInfo.substring(index + 1));\n\t\t\t}\n\t\t\treturn new Credentials(null, userInfo);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisUrlSyntaxException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\n/**\n * Exception thrown when a Redis URL is malformed or invalid.\n *\n * @author Scott Frederick\n */\nclass DataRedisUrlSyntaxException extends RuntimeException {\n\n\tprivate final String url;\n\n\tDataRedisUrlSyntaxException(String url, Exception cause) {\n\t\tsuper(buildMessage(url), cause);\n\t\tthis.url = url;\n\t}\n\n\tDataRedisUrlSyntaxException(String url) {\n\t\tsuper(buildMessage(url));\n\t\tthis.url = url;\n\t}\n\n\tString getUrl() {\n\t\treturn this.url;\n\t}\n\n\tprivate static String buildMessage(String url) {\n\t\treturn \"Invalid Redis URL '\" + url + \"'\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/DataRedisUrlSyntaxFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * A {@code FailureAnalyzer} that performs analysis of failures caused by a\n * {@link DataRedisUrlSyntaxException}.\n *\n * @author Scott Frederick\n */\nclass DataRedisUrlSyntaxFailureAnalyzer extends AbstractFailureAnalyzer<DataRedisUrlSyntaxException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, DataRedisUrlSyntaxException cause) {\n\t\ttry {\n\t\t\tURI uri = new URI(cause.getUrl());\n\t\t\tif (\"redis-sentinel\".equals(uri.getScheme())) {\n\t\t\t\treturn new FailureAnalysis(getUnsupportedSchemeDescription(cause.getUrl(), uri.getScheme()),\n\t\t\t\t\t\t\"Use spring.data.redis.sentinel properties instead of spring.data.redis.url to configure Redis sentinel addresses.\",\n\t\t\t\t\t\tcause);\n\t\t\t}\n\t\t\tif (\"redis-socket\".equals(uri.getScheme())) {\n\t\t\t\treturn new FailureAnalysis(getUnsupportedSchemeDescription(cause.getUrl(), uri.getScheme()),\n\t\t\t\t\t\t\"Configure the appropriate Spring Data Redis connection beans directly instead of setting the property 'spring.data.redis.url'.\",\n\t\t\t\t\t\tcause);\n\t\t\t}\n\t\t\tif (!\"redis\".equals(uri.getScheme()) && !\"rediss\".equals(uri.getScheme())) {\n\t\t\t\treturn new FailureAnalysis(getUnsupportedSchemeDescription(cause.getUrl(), uri.getScheme()),\n\t\t\t\t\t\t\"Use the scheme 'redis://' for insecure or 'rediss://' for secure Redis standalone configuration.\",\n\t\t\t\t\t\tcause);\n\t\t\t}\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\t// fall through to default description and action\n\t\t}\n\t\treturn new FailureAnalysis(getDefaultDescription(cause.getUrl()),\n\t\t\t\t\"Review the value of the property 'spring.data.redis.url'.\", cause);\n\t}\n\n\tprivate String getDefaultDescription(String url) {\n\t\treturn \"The URL '\" + url + \"' is not valid for configuring Spring Data Redis. \";\n\t}\n\n\tprivate String getUnsupportedSchemeDescription(String url, String scheme) {\n\t\treturn getDefaultDescription(url) + \"The scheme '\" + scheme + \"' is not supported.\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/JedisClientConfigurationBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.springframework.data.redis.connection.jedis.JedisClientConfiguration;\nimport org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link JedisClientConfigurationBuilder} to fine-tune its auto-configuration before it\n * creates the {@link JedisClientConfiguration}.\n *\n * @author Mark Paluch\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface JedisClientConfigurationBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link JedisClientConfigurationBuilder}.\n\t * @param clientConfigurationBuilder the builder to customize\n\t */\n\tvoid customize(JedisClientConfigurationBuilder clientConfigurationBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/JedisConnectionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport javax.net.ssl.SSLParameters;\n\nimport org.apache.commons.pool2.impl.GenericObjectPool;\nimport redis.clients.jedis.ConnectionPoolConfig;\nimport redis.clients.jedis.Jedis;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.data.redis.connection.RedisClusterConfiguration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisSentinelConfiguration;\nimport org.springframework.data.redis.connection.RedisStandaloneConfiguration;\nimport org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;\nimport org.springframework.data.redis.connection.jedis.JedisClientConfiguration;\nimport org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;\nimport org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisSslClientConfigurationBuilder;\nimport org.springframework.data.redis.connection.jedis.JedisConnection;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Redis connection configuration using Jedis.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })\n@ConditionalOnMissingBean(RedisConnectionFactory.class)\n@ConditionalOnProperty(name = \"spring.data.redis.client-type\", havingValue = \"jedis\", matchIfMissing = true)\nclass JedisConnectionConfiguration extends DataRedisConnectionConfiguration {\n\n\tJedisConnectionConfiguration(DataRedisProperties properties,\n\t\t\tObjectProvider<RedisStandaloneConfiguration> standaloneConfigurationProvider,\n\t\t\tObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,\n\t\t\tObjectProvider<RedisClusterConfiguration> clusterConfiguration,\n\t\t\tObjectProvider<RedisStaticMasterReplicaConfiguration> masterReplicaConfiguration,\n\t\t\tDataRedisConnectionDetails connectionDetails) {\n\t\tsuper(properties, connectionDetails, standaloneConfigurationProvider, sentinelConfiguration,\n\t\t\t\tclusterConfiguration, masterReplicaConfiguration);\n\t}\n\n\t@Bean\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tJedisConnectionFactory redisConnectionFactory(\n\t\t\tObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {\n\t\treturn createJedisConnectionFactory(builderCustomizers);\n\t}\n\n\t@Bean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tJedisConnectionFactory redisConnectionFactoryVirtualThreads(\n\t\t\tObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {\n\t\tJedisConnectionFactory factory = createJedisConnectionFactory(builderCustomizers);\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(\"redis-\");\n\t\texecutor.setVirtualThreads(true);\n\t\tfactory.setExecutor(executor);\n\t\treturn factory;\n\t}\n\n\tprivate JedisConnectionFactory createJedisConnectionFactory(\n\t\t\tObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {\n\t\tJedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);\n\t\treturn switch (this.mode) {\n\t\t\tcase STANDALONE -> new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);\n\t\t\tcase CLUSTER -> {\n\t\t\t\tRedisClusterConfiguration clusterConfiguration = getClusterConfiguration();\n\t\t\t\tAssert.state(clusterConfiguration != null, \"'clusterConfiguration' must not be null\");\n\t\t\t\tyield new JedisConnectionFactory(clusterConfiguration, clientConfiguration);\n\t\t\t}\n\t\t\tcase SENTINEL -> {\n\t\t\t\tRedisSentinelConfiguration sentinelConfig = getSentinelConfig();\n\t\t\t\tAssert.state(sentinelConfig != null, \"'sentinelConfig' must not be null\");\n\t\t\t\tyield new JedisConnectionFactory(sentinelConfig, clientConfiguration);\n\t\t\t}\n\t\t\tcase MASTER_REPLICA -> throw new IllegalStateException(\"'masterReplicaConfig' is not supported by Jedis\");\n\t\t};\n\t}\n\n\tprivate JedisClientConfiguration getJedisClientConfiguration(\n\t\t\tObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {\n\t\tJedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());\n\t\tapplySslIfNeeded(builder);\n\t\tDataRedisProperties.Pool pool = getProperties().getJedis().getPool();\n\t\tif (isPoolEnabled(pool)) {\n\t\t\tapplyPooling(pool, builder);\n\t\t}\n\t\tString url = getProperties().getUrl();\n\t\tif (StringUtils.hasText(url)) {\n\t\t\tcustomizeConfigurationFromUrl(builder, url);\n\t\t}\n\t\tbuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate JedisClientConfigurationBuilder applyProperties(JedisClientConfigurationBuilder builder) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(getProperties().getTimeout()).to(builder::readTimeout);\n\t\tmap.from(getProperties().getConnectTimeout()).to(builder::connectTimeout);\n\t\tmap.from(getProperties().getClientName()).whenHasText().to(builder::clientName);\n\t\treturn builder;\n\t}\n\n\tprivate void applySslIfNeeded(JedisClientConfigurationBuilder builder) {\n\t\tSslBundle sslBundle = getSslBundle();\n\t\tif (sslBundle == null) {\n\t\t\treturn;\n\t\t}\n\t\tJedisSslClientConfigurationBuilder sslBuilder = builder.useSsl();\n\t\tsslBuilder.sslSocketFactory(sslBundle.createSslContext().getSocketFactory());\n\t\tSslOptions sslOptions = sslBundle.getOptions();\n\t\tSSLParameters sslParameters = new SSLParameters();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(sslOptions.getCiphers()).to(sslParameters::setCipherSuites);\n\t\tmap.from(sslOptions.getEnabledProtocols()).to(sslParameters::setProtocols);\n\t\tsslBuilder.sslParameters(sslParameters);\n\t}\n\n\tprivate void applyPooling(DataRedisProperties.Pool pool,\n\t\t\tJedisClientConfiguration.JedisClientConfigurationBuilder builder) {\n\t\tbuilder.usePooling().poolConfig(poolConfig(pool));\n\t}\n\n\tprivate ConnectionPoolConfig poolConfig(DataRedisProperties.Pool pool) {\n\t\tConnectionPoolConfig config = new ConnectionPoolConfig();\n\t\tconfig.setMaxTotal(pool.getMaxActive());\n\t\tconfig.setMaxIdle(pool.getMaxIdle());\n\t\tconfig.setMinIdle(pool.getMinIdle());\n\t\tif (pool.getTimeBetweenEvictionRuns() != null) {\n\t\t\tconfig.setTimeBetweenEvictionRuns(pool.getTimeBetweenEvictionRuns());\n\t\t}\n\t\tif (pool.getMaxWait() != null) {\n\t\t\tconfig.setMaxWait(pool.getMaxWait());\n\t\t}\n\t\treturn config;\n\t}\n\n\tprivate void customizeConfigurationFromUrl(JedisClientConfiguration.JedisClientConfigurationBuilder builder,\n\t\t\tString url) {\n\t\tif (urlUsesSsl(url)) {\n\t\t\tbuilder.useSsl();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/LettuceClientConfigurationBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link LettuceClientConfigurationBuilder} to fine-tune its auto-configuration before it\n * creates the {@link LettuceClientConfiguration}. To customize only the\n * {@link LettuceClientConfiguration#getClientOptions() client options} of the\n * configuration, use {@link LettuceClientOptionsBuilderCustomizer} instead.\n *\n * @author Mark Paluch\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface LettuceClientConfigurationBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link LettuceClientConfigurationBuilder}.\n\t * @param clientConfigurationBuilder the builder to customize\n\t */\n\tvoid customize(LettuceClientConfigurationBuilder clientConfigurationBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/LettuceClientOptionsBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport io.lettuce.core.ClientOptions;\nimport io.lettuce.core.ClientOptions.Builder;\n\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Builder} to fine-tune its auto-configuration before it creates the\n * {@link ClientOptions} of the {@link LettuceClientConfiguration}. To customize the\n * entire configuration, use {@link LettuceClientConfigurationBuilderCustomizer} instead.\n *\n * @author Soohyun Lim\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface LettuceClientOptionsBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link Builder}.\n\t * @param clientOptionsBuilder the builder to customize\n\t */\n\tvoid customize(Builder clientOptionsBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/LettuceConnectionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.lettuce.core.ClientOptions;\nimport io.lettuce.core.ReadFrom;\nimport io.lettuce.core.RedisClient;\nimport io.lettuce.core.SocketOptions;\nimport io.lettuce.core.TimeoutOptions;\nimport io.lettuce.core.api.StatefulConnection;\nimport io.lettuce.core.cluster.ClusterClientOptions;\nimport io.lettuce.core.cluster.ClusterTopologyRefreshOptions;\nimport io.lettuce.core.cluster.ClusterTopologyRefreshOptions.Builder;\nimport io.lettuce.core.resource.ClientResources;\nimport io.lettuce.core.resource.DefaultClientResources;\nimport org.apache.commons.pool2.impl.GenericObjectPoolConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisProperties.Lettuce.Cluster.Refresh;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisProperties.Pool;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.data.redis.connection.RedisClusterConfiguration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisSentinelConfiguration;\nimport org.springframework.data.redis.connection.RedisStandaloneConfiguration;\nimport org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Redis connection configuration using Lettuce.\n *\n * @author Mark Paluch\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(RedisClient.class)\n@ConditionalOnProperty(name = \"spring.data.redis.client-type\", havingValue = \"lettuce\", matchIfMissing = true)\nclass LettuceConnectionConfiguration extends DataRedisConnectionConfiguration {\n\n\tLettuceConnectionConfiguration(DataRedisProperties properties,\n\t\t\tObjectProvider<RedisStandaloneConfiguration> standaloneConfigurationProvider,\n\t\t\tObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,\n\t\t\tObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider,\n\t\t\tObjectProvider<RedisStaticMasterReplicaConfiguration> masterReplicaConfiguration,\n\t\t\tDataRedisConnectionDetails connectionDetails) {\n\t\tsuper(properties, connectionDetails, standaloneConfigurationProvider, sentinelConfigurationProvider,\n\t\t\t\tclusterConfigurationProvider, masterReplicaConfiguration);\n\t}\n\n\t@Bean(destroyMethod = \"shutdown\")\n\t@ConditionalOnMissingBean(ClientResources.class)\n\tDefaultClientResources lettuceClientResources(ObjectProvider<ClientResourcesBuilderCustomizer> customizers) {\n\t\tDefaultClientResources.Builder builder = DefaultClientResources.builder();\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(RedisConnectionFactory.class)\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tLettuceConnectionFactory redisConnectionFactory(\n\t\t\tObjectProvider<LettuceClientConfigurationBuilderCustomizer> clientConfigurationBuilderCustomizers,\n\t\t\tObjectProvider<LettuceClientOptionsBuilderCustomizer> clientOptionsBuilderCustomizers,\n\t\t\tClientResources clientResources) {\n\t\treturn createConnectionFactory(clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers,\n\t\t\t\tclientResources);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(RedisConnectionFactory.class)\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tLettuceConnectionFactory redisConnectionFactoryVirtualThreads(\n\t\t\tObjectProvider<LettuceClientConfigurationBuilderCustomizer> clientConfigurationBuilderCustomizers,\n\t\t\tObjectProvider<LettuceClientOptionsBuilderCustomizer> clientOptionsBuilderCustomizers,\n\t\t\tClientResources clientResources) {\n\t\tLettuceConnectionFactory factory = createConnectionFactory(clientConfigurationBuilderCustomizers,\n\t\t\t\tclientOptionsBuilderCustomizers, clientResources);\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(\"redis-\");\n\t\texecutor.setVirtualThreads(true);\n\t\tfactory.setExecutor(executor);\n\t\treturn factory;\n\t}\n\n\tprivate LettuceConnectionFactory createConnectionFactory(\n\t\t\tObjectProvider<LettuceClientConfigurationBuilderCustomizer> clientConfigurationBuilderCustomizers,\n\t\t\tObjectProvider<LettuceClientOptionsBuilderCustomizer> clientOptionsBuilderCustomizers,\n\t\t\tClientResources clientResources) {\n\t\tLettuceClientConfiguration clientConfiguration = getLettuceClientConfiguration(\n\t\t\t\tclientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources,\n\t\t\t\tgetProperties().getLettuce().getPool());\n\t\treturn switch (this.mode) {\n\t\t\tcase STANDALONE -> new LettuceConnectionFactory(getStandaloneConfig(), clientConfiguration);\n\t\t\tcase CLUSTER -> {\n\t\t\t\tRedisClusterConfiguration clusterConfiguration = getClusterConfiguration();\n\t\t\t\tAssert.state(clusterConfiguration != null, \"'clusterConfiguration' must not be null\");\n\t\t\t\tyield new LettuceConnectionFactory(clusterConfiguration, clientConfiguration);\n\t\t\t}\n\t\t\tcase SENTINEL -> {\n\t\t\t\tRedisSentinelConfiguration sentinelConfig = getSentinelConfig();\n\t\t\t\tAssert.state(sentinelConfig != null, \"'sentinelConfig' must not be null\");\n\t\t\t\tyield new LettuceConnectionFactory(sentinelConfig, clientConfiguration);\n\t\t\t}\n\t\t\tcase MASTER_REPLICA -> {\n\t\t\t\tRedisStaticMasterReplicaConfiguration masterReplicaConfiguration = getMasterReplicaConfiguration();\n\t\t\t\tAssert.state(masterReplicaConfiguration != null, \"'masterReplicaConfig' must not be null\");\n\t\t\t\tyield new LettuceConnectionFactory(masterReplicaConfiguration, clientConfiguration);\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate LettuceClientConfiguration getLettuceClientConfiguration(\n\t\t\tObjectProvider<LettuceClientConfigurationBuilderCustomizer> clientConfigurationBuilderCustomizers,\n\t\t\tObjectProvider<LettuceClientOptionsBuilderCustomizer> clientOptionsBuilderCustomizers,\n\t\t\tClientResources clientResources, Pool pool) {\n\t\tLettuceClientConfigurationBuilder builder = createBuilder(pool);\n\t\tSslBundle sslBundle = getSslBundle();\n\t\tapplyProperties(builder, sslBundle);\n\t\tString url = getProperties().getUrl();\n\t\tif (StringUtils.hasText(url)) {\n\t\t\tcustomizeConfigurationFromUrl(builder, url);\n\t\t}\n\t\tbuilder.clientOptions(createClientOptions(clientOptionsBuilderCustomizers, sslBundle));\n\t\tbuilder.clientResources(clientResources);\n\t\tclientConfigurationBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate LettuceClientConfigurationBuilder createBuilder(Pool pool) {\n\t\tif (isPoolEnabled(pool)) {\n\t\t\treturn new PoolBuilderFactory().createBuilder(pool);\n\t\t}\n\t\treturn LettuceClientConfiguration.builder();\n\t}\n\n\tprivate void applyProperties(LettuceClientConfigurationBuilder builder, @Nullable SslBundle sslBundle) {\n\t\tif (sslBundle != null) {\n\t\t\tbuilder.useSsl();\n\t\t}\n\t\tif (getProperties().getTimeout() != null) {\n\t\t\tbuilder.commandTimeout(getProperties().getTimeout());\n\t\t}\n\t\tif (getProperties().getLettuce() != null) {\n\t\t\tDataRedisProperties.Lettuce lettuce = getProperties().getLettuce();\n\t\t\tif (lettuce.getShutdownTimeout() != null && !lettuce.getShutdownTimeout().isZero()) {\n\t\t\t\tbuilder.shutdownTimeout(getProperties().getLettuce().getShutdownTimeout());\n\t\t\t}\n\t\t\tString readFrom = lettuce.getReadFrom();\n\t\t\tif (readFrom != null) {\n\t\t\t\tbuilder.readFrom(getReadFrom(readFrom));\n\t\t\t}\n\t\t}\n\t\tif (StringUtils.hasText(getProperties().getClientName())) {\n\t\t\tbuilder.clientName(getProperties().getClientName());\n\t\t}\n\t}\n\n\tprivate ReadFrom getReadFrom(String readFrom) {\n\t\tint index = readFrom.indexOf(':');\n\t\tif (index == -1) {\n\t\t\treturn ReadFrom.valueOf(getCanonicalReadFromName(readFrom));\n\t\t}\n\t\tString name = getCanonicalReadFromName(readFrom.substring(0, index));\n\t\tString value = readFrom.substring(index + 1);\n\t\treturn ReadFrom.valueOf(name + \":\" + value);\n\t}\n\n\tprivate String getCanonicalReadFromName(String name) {\n\t\tStringBuilder canonicalName = new StringBuilder(name.length());\n\t\tname.chars()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.forEach((c) -> canonicalName.append((char) c));\n\t\treturn canonicalName.toString();\n\t}\n\n\tprivate ClientOptions createClientOptions(\n\t\t\tObjectProvider<LettuceClientOptionsBuilderCustomizer> clientConfigurationBuilderCustomizers,\n\t\t\t@Nullable SslBundle sslBundle) {\n\t\tClientOptions.Builder builder = initializeClientOptionsBuilder();\n\t\tDuration connectTimeout = getProperties().getConnectTimeout();\n\t\tif (connectTimeout != null) {\n\t\t\tbuilder.socketOptions(SocketOptions.builder().connectTimeout(connectTimeout).build());\n\t\t}\n\t\tif (sslBundle != null) {\n\t\t\tio.lettuce.core.SslOptions.Builder sslOptionsBuilder = io.lettuce.core.SslOptions.builder();\n\t\t\tsslOptionsBuilder.keyManager(sslBundle.getManagers().getKeyManagerFactory());\n\t\t\tsslOptionsBuilder.trustManager(sslBundle.getManagers().getTrustManagerFactory());\n\t\t\tSslOptions sslOptions = sslBundle.getOptions();\n\t\t\tif (sslOptions.getCiphers() != null) {\n\t\t\t\tsslOptionsBuilder.cipherSuites(sslOptions.getCiphers());\n\t\t\t}\n\t\t\tif (sslOptions.getEnabledProtocols() != null) {\n\t\t\t\tsslOptionsBuilder.protocols(sslOptions.getEnabledProtocols());\n\t\t\t}\n\t\t\tbuilder.sslOptions(sslOptionsBuilder.build());\n\t\t}\n\t\tbuilder.timeoutOptions(TimeoutOptions.enabled());\n\t\tclientConfigurationBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate ClientOptions.Builder initializeClientOptionsBuilder() {\n\t\tif (getProperties().getCluster() != null) {\n\t\t\tClusterClientOptions.Builder builder = ClusterClientOptions.builder();\n\t\t\tRefresh refreshProperties = getProperties().getLettuce().getCluster().getRefresh();\n\t\t\tBuilder refreshBuilder = ClusterTopologyRefreshOptions.builder()\n\t\t\t\t.dynamicRefreshSources(refreshProperties.isDynamicRefreshSources());\n\t\t\tif (refreshProperties.getPeriod() != null) {\n\t\t\t\trefreshBuilder.enablePeriodicRefresh(refreshProperties.getPeriod());\n\t\t\t}\n\t\t\treturn builder.topologyRefreshOptions(refreshBuilder.build());\n\t\t}\n\t\treturn ClientOptions.builder();\n\t}\n\n\tprivate void customizeConfigurationFromUrl(LettuceClientConfiguration.LettuceClientConfigurationBuilder builder,\n\t\t\tString url) {\n\t\tif (urlUsesSsl(url)) {\n\t\t\tbuilder.useSsl();\n\t\t}\n\t}\n\n\t/**\n\t * Inner class to allow optional commons-pool2 dependency.\n\t */\n\tprivate static final class PoolBuilderFactory {\n\n\t\tLettuceClientConfigurationBuilder createBuilder(Pool properties) {\n\t\t\treturn LettucePoolingClientConfiguration.builder().poolConfig(getPoolConfig(properties));\n\t\t}\n\n\t\tprivate GenericObjectPoolConfig<StatefulConnection<?, ?>> getPoolConfig(Pool properties) {\n\t\t\tGenericObjectPoolConfig<StatefulConnection<?, ?>> config = new GenericObjectPoolConfig<>();\n\t\t\tconfig.setMaxTotal(properties.getMaxActive());\n\t\t\tconfig.setMaxIdle(properties.getMaxIdle());\n\t\t\tconfig.setMinIdle(properties.getMinIdle());\n\t\t\tif (properties.getTimeBetweenEvictionRuns() != null) {\n\t\t\t\tconfig.setTimeBetweenEvictionRuns(properties.getTimeBetweenEvictionRuns());\n\t\t\t}\n\t\t\tif (properties.getMaxWait() != null) {\n\t\t\t\tconfig.setMaxWait(properties.getMaxWait());\n\t\t\t}\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/PropertiesDataRedisConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Adapts {@link DataRedisProperties} to {@link DataRedisConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Yanming Zhou\n * @author Phillip Webb\n */\nclass PropertiesDataRedisConnectionDetails implements DataRedisConnectionDetails {\n\n\tprivate final DataRedisProperties properties;\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\tPropertiesDataRedisConnectionDetails(DataRedisProperties properties, @Nullable SslBundles sslBundles) {\n\t\tthis.properties = properties;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic @Nullable String getUsername() {\n\t\tDataRedisUrl redisUrl = getRedisUrl();\n\t\treturn (redisUrl != null) ? redisUrl.credentials().username() : this.properties.getUsername();\n\t}\n\n\t@Override\n\tpublic @Nullable String getPassword() {\n\t\tDataRedisUrl redisUrl = getRedisUrl();\n\t\treturn (redisUrl != null) ? redisUrl.credentials().password() : this.properties.getPassword();\n\t}\n\n\t@Override\n\tpublic @Nullable SslBundle getSslBundle() {\n\t\tif (!this.properties.getSsl().isEnabled()) {\n\t\t\treturn null;\n\t\t}\n\t\tString bundleName = this.properties.getSsl().getBundle();\n\t\tif (StringUtils.hasLength(bundleName)) {\n\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\treturn this.sslBundles.getBundle(bundleName);\n\t\t}\n\t\treturn SslBundle.systemDefault();\n\t}\n\n\t@Override\n\tpublic Standalone getStandalone() {\n\t\tDataRedisUrl redisUrl = getRedisUrl();\n\t\treturn (redisUrl != null)\n\t\t\t\t? Standalone.of(redisUrl.uri().getHost(), redisUrl.uri().getPort(), redisUrl.database())\n\t\t\t\t: Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase());\n\t}\n\n\t@Override\n\tpublic @Nullable Sentinel getSentinel() {\n\t\tDataRedisProperties.Sentinel sentinel = this.properties.getSentinel();\n\t\treturn (sentinel != null) ? new PropertiesSentinel(getStandalone().getDatabase(), sentinel) : null;\n\t}\n\n\t@Override\n\tpublic @Nullable Cluster getCluster() {\n\t\tDataRedisProperties.Cluster cluster = this.properties.getCluster();\n\t\treturn (cluster != null) ? new PropertiesCluster(cluster) : null;\n\t}\n\n\t@Override\n\tpublic @Nullable MasterReplica getMasterReplica() {\n\t\tDataRedisProperties.Masterreplica masterreplica = this.properties.getMasterreplica();\n\t\treturn (masterreplica != null) ? new PropertiesMasterReplica(masterreplica) : null;\n\t}\n\n\tprivate @Nullable DataRedisUrl getRedisUrl() {\n\t\treturn DataRedisUrl.of(this.properties.getUrl());\n\t}\n\n\tprivate static List<Node> asNodes(@Nullable List<String> nodes) {\n\t\tif (nodes == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\treturn nodes.stream().map(PropertiesDataRedisConnectionDetails::asNode).toList();\n\t}\n\n\tprivate static Node asNode(String node) {\n\t\tint portSeparatorIndex = node.lastIndexOf(':');\n\t\tString host = node.substring(0, portSeparatorIndex);\n\t\tint port = Integer.parseInt(node.substring(portSeparatorIndex + 1));\n\t\treturn new Node(host, port);\n\t}\n\n\t/**\n\t * {@link Cluster} implementation backed by properties.\n\t */\n\tprivate static class PropertiesCluster implements Cluster {\n\n\t\tprivate final List<Node> nodes;\n\n\t\tPropertiesCluster(DataRedisProperties.Cluster properties) {\n\t\t\tthis.nodes = asNodes(properties.getNodes());\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link MasterReplica} implementation backed by properties.\n\t */\n\tprivate static class PropertiesMasterReplica implements MasterReplica {\n\n\t\tprivate final List<Node> nodes;\n\n\t\tPropertiesMasterReplica(DataRedisProperties.Masterreplica properties) {\n\t\t\tthis.nodes = asNodes(properties.getNodes());\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Sentinel} implementation backed by properties.\n\t */\n\tprivate static class PropertiesSentinel implements Sentinel {\n\n\t\tprivate final int database;\n\n\t\tprivate final DataRedisProperties.Sentinel properties;\n\n\t\tPropertiesSentinel(int database, DataRedisProperties.Sentinel properties) {\n\t\t\tthis.database = database;\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getDatabase() {\n\t\t\treturn this.database;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getMaster() {\n\t\t\tString master = this.properties.getMaster();\n\t\t\tAssert.state(master != null, \"'master' must not be null\");\n\t\t\treturn master;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getNodes() {\n\t\t\treturn asNodes(this.properties.getNodes());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.properties.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/health/DataRedisHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure.health;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.health.DataRedisHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link DataRedisHealthIndicator}.\n *\n * @author Christian Dupuis\n * @author Richard Santana\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafter = { DataRedisAutoConfiguration.class, DataRedisReactiveHealthContributorAutoConfiguration.class })\n@ConditionalOnClass({ RedisConnectionFactory.class, HealthIndicator.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(RedisConnectionFactory.class)\n@ConditionalOnEnabledHealthIndicator(\"redis\")\npublic final class DataRedisHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<DataRedisHealthIndicator, RedisConnectionFactory> {\n\n\tDataRedisHealthContributorAutoConfiguration() {\n\t\tsuper(DataRedisHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"redisHealthIndicator\", \"redisHealthContributor\" })\n\tHealthContributor redisHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, RedisConnectionFactory.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/health/DataRedisReactiveHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure.health;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisReactiveAutoConfiguration;\nimport org.springframework.boot.data.redis.health.DataRedisReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link DataRedisReactiveHealthIndicator}.\n *\n * @author Christian Dupuis\n * @author Richard Santana\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataRedisReactiveAutoConfiguration.class)\n@ConditionalOnClass({ ReactiveRedisConnectionFactory.class, Flux.class, ReactiveHealthIndicator.class,\n\t\tConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(ReactiveRedisConnectionFactory.class)\n@ConditionalOnEnabledHealthIndicator(\"redis\")\npublic final class DataRedisReactiveHealthContributorAutoConfiguration extends\n\t\tCompositeReactiveHealthContributorConfiguration<DataRedisReactiveHealthIndicator, ReactiveRedisConnectionFactory> {\n\n\tDataRedisReactiveHealthContributorAutoConfiguration() {\n\t\tsuper(DataRedisReactiveHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"redisHealthIndicator\", \"redisHealthContributor\" })\n\tReactiveHealthContributor redisHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, ReactiveRedisConnectionFactory.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Redis health.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/observation/LettuceObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure.observation;\n\nimport io.lettuce.core.RedisClient;\nimport io.lettuce.core.tracing.MicrometerTracing;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.data.redis.autoconfigure.ClientResourcesBuilderCustomizer;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for Lettuce observability.\n *\n * @author Antonin Arquey\n * @author Yanming Zhou\n * @author Dũng Đăng Minh\n * @since 4.0.0\n */\n@AutoConfiguration(before = DataRedisAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnClass({ RedisClient.class, MicrometerTracing.class, ObservationRegistry.class })\n@ConditionalOnBean(ObservationRegistry.class)\npublic final class LettuceObservationAutoConfiguration {\n\n\t@Bean\n\tClientResourcesBuilderCustomizer lettuceObservation(ObservationRegistry observationRegistry) {\n\t\treturn (client) -> client.tracing(new MicrometerTracing(observationRegistry, \"Redis\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Redis observation.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.autoconfigure.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data Redis.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/docker/compose/RedisDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link DataRedisConnectionDetails} for a {@code redis} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Eddú Meléndez\n */\nclass RedisDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<DataRedisConnectionDetails> {\n\n\tprivate static final String[] REDIS_CONTAINER_NAMES = { \"redis\", \"redis/redis-stack\", \"redis/redis-stack-server\" };\n\n\tprivate static final int REDIS_PORT = 6379;\n\n\tRedisDockerComposeConnectionDetailsFactory() {\n\t\tsuper(REDIS_CONTAINER_NAMES);\n\t}\n\n\t@Override\n\tprotected DataRedisConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new RedisDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link DataRedisConnectionDetails} backed by a {@code redis}\n\t * {@link RunningService}.\n\t */\n\tstatic class RedisDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements DataRedisConnectionDetails {\n\n\t\tprivate final Standalone standalone;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tRedisDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.standalone = Standalone.of(service.host(), service.ports().get(REDIS_PORT));\n\t\t\tthis.sslBundle = getSslBundle(service);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t\t@Override\n\t\tpublic Standalone getStandalone() {\n\t\t\treturn this.standalone;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Redis service connections.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/health/DataRedisHealth.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.health;\n\nimport java.util.Properties;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.data.redis.connection.ClusterInfo;\n\n/**\n * Shared class used by {@link DataRedisHealthIndicator} and\n * {@link DataRedisReactiveHealthIndicator} to provide health details.\n *\n * @author Phillip Webb\n */\nfinal class DataRedisHealth {\n\n\tprivate DataRedisHealth() {\n\t}\n\n\tstatic Health.Builder up(Health.Builder builder, Properties info) {\n\t\tbuilder.withDetail(\"version\", info.getProperty(\"redis_version\", \"unknown\"));\n\t\treturn builder.up();\n\t}\n\n\tstatic Health.Builder fromClusterInfo(Health.Builder builder, ClusterInfo clusterInfo) {\n\t\tLong clusterSize = clusterInfo.getClusterSize();\n\t\tif (clusterSize != null) {\n\t\t\tbuilder.withDetail(\"cluster_size\", clusterSize);\n\t\t}\n\t\tLong slotsOk = clusterInfo.getSlotsOk();\n\t\tif (slotsOk != null) {\n\t\t\tbuilder.withDetail(\"slots_up\", slotsOk);\n\t\t}\n\t\tLong slotsFail = clusterInfo.getSlotsFail();\n\t\tif (slotsFail != null) {\n\t\t\tbuilder.withDetail(\"slots_fail\", slotsFail);\n\t\t}\n\t\tif (\"fail\".equalsIgnoreCase(clusterInfo.getState())) {\n\t\t\treturn builder.down();\n\t\t}\n\t\telse {\n\t\t\treturn builder.up();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/health/DataRedisHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.health;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.data.redis.connection.RedisClusterConnection;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisConnectionUtils;\nimport org.springframework.util.Assert;\n\n/**\n * Simple implementation of a {@link HealthIndicator} returning status information for\n * Redis data stores.\n *\n * @author Christian Dupuis\n * @author Richard Santana\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class DataRedisHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final RedisConnectionFactory redisConnectionFactory;\n\n\tpublic DataRedisHealthIndicator(RedisConnectionFactory connectionFactory) {\n\t\tsuper(\"Redis health check failed\");\n\t\tAssert.notNull(connectionFactory, \"'connectionFactory' must not be null\");\n\t\tthis.redisConnectionFactory = connectionFactory;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tRedisConnection connection = RedisConnectionUtils.getConnection(this.redisConnectionFactory);\n\t\ttry {\n\t\t\tdoHealthCheck(builder, connection);\n\t\t}\n\t\tfinally {\n\t\t\tRedisConnectionUtils.releaseConnection(connection, this.redisConnectionFactory);\n\t\t}\n\t}\n\n\tprivate void doHealthCheck(Health.Builder builder, RedisConnection connection) {\n\t\tif (connection instanceof RedisClusterConnection clusterConnection) {\n\t\t\tDataRedisHealth.fromClusterInfo(builder, clusterConnection.clusterGetClusterInfo());\n\t\t}\n\t\telse {\n\t\t\tDataRedisHealth.up(builder, connection.serverCommands().info());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/health/DataRedisReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.health;\n\nimport java.util.Properties;\n\nimport reactor.core.publisher.Mono;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.data.redis.connection.ClusterInfo;\nimport org.springframework.data.redis.connection.ReactiveRedisClusterConnection;\nimport org.springframework.data.redis.connection.ReactiveRedisConnection;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\n\n/**\n * A {@link ReactiveHealthIndicator} for Redis.\n *\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Artsiom Yudovin\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class DataRedisReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate final ReactiveRedisConnectionFactory connectionFactory;\n\n\tpublic DataRedisReactiveHealthIndicator(ReactiveRedisConnectionFactory connectionFactory) {\n\t\tsuper(\"Redis health check failed\");\n\t\tthis.connectionFactory = connectionFactory;\n\t}\n\n\t@Override\n\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\treturn getConnection().flatMap((connection) -> doHealthCheck(builder, connection));\n\t}\n\n\tprivate Mono<ReactiveRedisConnection> getConnection() {\n\t\treturn Mono.fromSupplier(this.connectionFactory::getReactiveConnection)\n\t\t\t.subscribeOn(Schedulers.boundedElastic());\n\t}\n\n\tprivate Mono<Health> doHealthCheck(Health.Builder builder, ReactiveRedisConnection connection) {\n\t\treturn getHealth(builder, connection).onErrorResume((ex) -> Mono.just(builder.down(ex).build()))\n\t\t\t.flatMap((health) -> connection.closeLater().thenReturn(health));\n\t}\n\n\tprivate Mono<Health> getHealth(Health.Builder builder, ReactiveRedisConnection connection) {\n\t\tif (connection instanceof ReactiveRedisClusterConnection clusterConnection) {\n\t\t\treturn clusterConnection.clusterGetClusterInfo().map((info) -> fromClusterInfo(builder, info));\n\t\t}\n\t\treturn connection.serverCommands().info(\"server\").map((info) -> up(builder, info));\n\t}\n\n\tprivate Health up(Health.Builder builder, Properties info) {\n\t\treturn DataRedisHealth.up(builder, info).build();\n\t}\n\n\tprivate Health fromClusterInfo(Health.Builder builder, ClusterInfo clusterInfo) {\n\t\treturn DataRedisHealth.fromClusterInfo(builder, clusterInfo).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Redis health integration using Spring Data Redis.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/testcontainers/RedisContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.testcontainers;\n\nimport java.util.List;\n\nimport com.redis.testcontainers.RedisContainer;\nimport com.redis.testcontainers.RedisStackContainer;\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link DataRedisConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer}\n * using the {@code \"redis\"} image.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Eddú Meléndez\n */\nclass RedisContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, DataRedisConnectionDetails> {\n\n\tprivate static final List<String> REDIS_IMAGE_NAMES = List.of(\"redis\", \"redis/redis-stack\",\n\t\t\t\"redis/redis-stack-server\");\n\n\tprivate static final int REDIS_PORT = 6379;\n\n\tRedisContainerConnectionDetailsFactory() {\n\t\tsuper(REDIS_IMAGE_NAMES);\n\t}\n\n\t@Override\n\tprotected boolean sourceAccepts(ContainerConnectionSource<Container<?>> source, Class<?> requiredContainerType,\n\t\t\tClass<?> requiredConnectionDetailsType) {\n\t\treturn super.sourceAccepts(source, requiredContainerType, requiredConnectionDetailsType)\n\t\t\t\t|| source.accepts(ContainerConnectionDetailsFactory.ANY_CONNECTION_NAME, RedisContainer.class,\n\t\t\t\t\t\trequiredConnectionDetailsType)\n\t\t\t\t|| source.accepts(ContainerConnectionDetailsFactory.ANY_CONNECTION_NAME, RedisStackContainer.class,\n\t\t\t\t\t\trequiredConnectionDetailsType);\n\t}\n\n\t@Override\n\tprotected DataRedisConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\treturn new RedisContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link DataRedisConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class RedisContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>\n\t\t\timplements DataRedisConnectionDetails {\n\n\t\tprivate RedisContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t\t@Override\n\t\tpublic Standalone getStandalone() {\n\t\t\treturn Standalone.of(getContainer().getHost(), getContainer().getMappedPort(REDIS_PORT));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/java/org/springframework/boot/data/redis/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Redis service connections.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.redis.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Redis health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.data.redis.lettuce.cluster.refresh.adaptive\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"reason\": \"All adaptive triggers are enabled by default.\",\n        \"level\": \"error\",\n        \"since\": \"4.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.redis.repositories.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Redis repositories.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.data.redis.ssl\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.ssl.enabled\",\n        \"level\": \"error\",\n        \"since\": \"3.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.client-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.client-name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.client-type\",\n      \"type\": \"org.springframework.boot.data.redis.autoconfigure.DataRedisProperties$ClientType\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.client-type\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.cluster.max-redirects\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.cluster.max-redirects\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.cluster.nodes\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.cluster.nodes\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.connect-timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.database\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.database\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.host\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.host\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.jedis.pool.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.jedis.pool.max-active\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.jedis.pool.max-idle\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.jedis.pool.max-wait\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.jedis.pool.min-idle\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.jedis.pool.time-between-eviction-runs\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.cluster.refresh.adaptive\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.lettuce.cluster.refresh.adaptive\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.cluster.refresh.dynamic-refresh-sources\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.lettuce.cluster.refresh.dynamic-refresh-sources\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.cluster.refresh.period\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.lettuce.cluster.refresh.period\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.pool.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.pool.max-active\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.pool.max-idle\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.pool.max-wait\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.pool.min-idle\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.pool.time-between-eviction-runs\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.lettuce.shutdown-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.lettuce.shutdown-timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.password\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.port\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.port\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.sentinel.master\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.sentinel.master\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.sentinel.nodes\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.sentinel.nodes\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.sentinel.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.sentinel.password\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.sentinel.username\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.sentinel.username\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.ssl\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.ssl\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.timeout\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.url\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.url\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.redis.username\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.data.redis.username\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.data.redis.lettuce.read-from\",\n      \"values\": [\n        {\n          \"value\": \"any\",\n          \"description\": \"Read from any node.\"\n        },\n        {\n          \"value\": \"any-replica\",\n          \"description\": \"Read from any replica node.\"\n        },\n        {\n          \"value\": \"lowest-latency\",\n          \"description\": \"Read from the node with the lowest latency during topology discovery.\"\n        },\n        {\n          \"value\": \"regex:\",\n          \"description\": \"Read from any node that has RedisURI matching with the given pattern.\"\n        },\n        {\n          \"value\": \"replica\",\n          \"description\": \"Read from the replica only.\"\n        },\n        {\n          \"value\": \"replica-preferred\",\n          \"description\": \"Read preferred from replica and fall back to upstream if no replica is available.\"\n        },\n        {\n          \"value\": \"subnet:\",\n          \"description\": \"Read from any node in the subnets.\"\n        },\n        {\n          \"value\": \"upstream\",\n          \"description\": \"Read from the upstream only.\"\n        },\n        {\n          \"value\": \"upstream-preferred\",\n          \"description\": \"Read preferred from the upstream and fall back to a replica if the upstream is not available.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.DataRedisReactiveAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.DataRedisRepositoriesAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.health.DataRedisHealthContributorAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.health.DataRedisReactiveHealthContributorAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.observation.LettuceObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.data.redis.docker.compose.RedisDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.data.redis.testcontainers.RedisContainerConnectionDetailsFactory\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.data.redis.autoconfigure.DataRedisUrlSyntaxFailureAnalyzer\n\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/DataRedisAutoConfigurationJedisTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.assertj.SimpleAsyncTaskExecutorAssert;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.jedis.JedisClientConfiguration.JedisClientConfigurationBuilder;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisAutoConfiguration} when Lettuce is not on the classpath.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Weix Sun\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@ClassPathExclusions(\"lettuce-core-*.jar\")\nclass DataRedisAutoConfigurationJedisTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid connectionFactoryDefaultsToJedis() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(\"redisConnectionFactory\"))\n\t\t\t.isInstanceOf(JedisConnectionFactory.class));\n\t}\n\n\t@Test\n\tvoid connectionFactoryIsNotCreatedWhenLettuceIsSelected() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.client-type=lettuce\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RedisConnectionFactory.class));\n\t}\n\n\t@Test\n\tvoid testOverrideRedisConfiguration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.database:1\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getDatabase()).isOne();\n\t\t\t\tassertThat(getUserName(cf)).isNull();\n\t\t\t\tassertThat(cf.getPassword()).isNull();\n\t\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testCustomizeRedisConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid usesConnectionDetailsIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsConfiguration.class).run((context) -> {\n\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisUrlConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.url:redis://user:password@example:33\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\t\tassertThat(getUserName(cf)).isEqualTo(\"user\");\n\t\t\t\tassertThat(cf.getPassword()).isEqualTo(\"password\");\n\t\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testOverrideUrlRedisConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.password:xyz\",\n\t\t\t\t\t\"spring.data.redis.port:1000\", \"spring.data.redis.ssl.enabled:false\",\n\t\t\t\t\t\"spring.data.redis.url:rediss://user:password@example:33\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\t\tassertThat(getUserName(cf)).isEqualTo(\"user\");\n\t\t\t\tassertThat(cf.getPassword()).isEqualTo(\"password\");\n\t\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testPasswordInUrlWithColon() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.url:redis://:pass:word@example:33\").run((context) -> {\n\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\tassertThat(getUserName(cf)).isEmpty();\n\t\t\tassertThat(cf.getPassword()).isEqualTo(\"pass:word\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testPasswordInUrlStartsWithColon() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.url:redis://user::pass:word@example:33\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\t\tassertThat(getUserName(cf)).isEqualTo(\"user\");\n\t\t\t\tassertThat(cf.getPassword()).isEqualTo(\":pass:word\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithPool() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.jedis.pool.min-idle:1\",\n\t\t\t\t\t\"spring.data.redis.jedis.pool.max-idle:4\", \"spring.data.redis.jedis.pool.max-active:16\",\n\t\t\t\t\t\"spring.data.redis.jedis.pool.max-wait:2000\",\n\t\t\t\t\t\"spring.data.redis.jedis.pool.time-between-eviction-runs:30000\")\n\t\t\t.withUserConfiguration(JedisDisableStartupConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getPoolConfig()).satisfies((poolConfig) -> {\n\t\t\t\t\tassertThat(poolConfig.getMinIdle()).isOne();\n\t\t\t\t\tassertThat(poolConfig.getMaxIdle()).isEqualTo(4);\n\t\t\t\t\tassertThat(poolConfig.getMaxTotal()).isEqualTo(16);\n\t\t\t\t\tassertThat(poolConfig.getMaxWaitDuration()).isEqualTo(Duration.ofSeconds(2));\n\t\t\t\t\tassertThat(poolConfig.getDurationBetweenEvictionRuns()).isEqualTo(Duration.ofSeconds(30));\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationDisabledPool() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.jedis.pool.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getClientConfiguration().isUsePooling()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithTimeoutAndConnectTimeout() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.timeout:250\",\n\t\t\t\t\t\"spring.data.redis.connect-timeout:1000\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getTimeout()).isEqualTo(250);\n\t\t\t\tassertThat(cf.getClientConfiguration().getConnectTimeout().toMillis()).isEqualTo(1000);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithDefaultTimeouts() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\").run((context) -> {\n\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\tassertThat(cf.getTimeout()).isEqualTo(2000);\n\t\t\tassertThat(cf.getClientConfiguration().getConnectTimeout().toMillis()).isEqualTo(2000);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClientName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.client-name:spring-boot\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getClientName()).isEqualTo(\"spring-boot\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinel() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:127.0.0.1:26379,127.0.0.1:26380\")\n\t\t\t.withUserConfiguration(JedisConnectionFactoryCaptorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory connectionFactory = JedisConnectionFactoryCaptor.connectionFactory;\n\t\t\t\tassertThat(connectionFactory).isNotNull();\n\t\t\t\tassertThat(connectionFactory.isRedisSentinelAware()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinelAndAuthentication() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.username=user\", \"spring.data.redis.password=password\",\n\t\t\t\t\t\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:127.0.0.1:26379,127.0.0.1:26380\")\n\t\t\t.withUserConfiguration(JedisConnectionFactoryCaptorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory connectionFactory = JedisConnectionFactoryCaptor.connectionFactory;\n\t\t\t\tassertThat(connectionFactory).isNotNull();\n\t\t\t\tassertThat(connectionFactory.isRedisSentinelAware()).isTrue();\n\t\t\t\tassertThat(getUserName(connectionFactory)).isEqualTo(\"user\");\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(\"password\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithCluster() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\")\n\t\t\t.withUserConfiguration(JedisConnectionFactoryCaptorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory connectionFactory = JedisConnectionFactoryCaptor.connectionFactory;\n\t\t\t\tassertThat(connectionFactory).isNotNull();\n\t\t\t\tassertThat(connectionFactory.isRedisClusterAware()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWitMasterReplica() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.masterreplica.nodes=127.0.0.1:27379,127.0.0.1:27380\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"'masterReplicaConfig' is not supported by Jedis\"));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSslEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.ssl.enabled:true\").run((context) -> {\n\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid testRedisConfigurationWithSslBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location:classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password:secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password:password\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSslDisabledAndBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.ssl.enabled:false\", \"spring.data.redis.ssl.bundle:test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tJedisConnectionFactory cf = context.getBean(JedisConnectionFactory.class);\n\t\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUsePlatformThreadsByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJedisConnectionFactory factory = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(factory).extracting(\"executor\").isNull();\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldUseVirtualThreadsIfEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tJedisConnectionFactory factory = context.getBean(JedisConnectionFactory.class);\n\t\t\tassertThat(factory).extracting(\"executor\")\n\t\t\t\t.satisfies((executor) -> SimpleAsyncTaskExecutorAssert.assertThat((SimpleAsyncTaskExecutor) executor)\n\t\t\t\t\t.usesVirtualThreads());\n\t\t});\n\t}\n\n\tprivate @Nullable String getUserName(JedisConnectionFactory factory) {\n\t\treturn ReflectionTestUtils.invokeMethod(factory, \"getRedisUsername\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConfiguration {\n\n\t\t@Bean\n\t\tJedisClientConfigurationBuilderCustomizer customizer() {\n\t\t\treturn JedisClientConfigurationBuilder::useSsl;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tDataRedisConnectionDetails redisConnectionDetails() {\n\t\t\treturn new DataRedisConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Standalone getStandalone() {\n\t\t\t\t\treturn new Standalone() {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic String getHost() {\n\t\t\t\t\t\t\treturn \"localhost\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic int getPort() {\n\t\t\t\t\t\t\treturn 6379;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JedisConnectionFactoryCaptorConfiguration {\n\n\t\t@Bean\n\t\tstatic JedisConnectionFactoryCaptor jedisConnectionFactoryCaptor() {\n\t\t\treturn new JedisConnectionFactoryCaptor();\n\t\t}\n\n\t}\n\n\tstatic class JedisConnectionFactoryCaptor implements BeanPostProcessor {\n\n\t\tstatic @Nullable JedisConnectionFactory connectionFactory;\n\n\t\t@Override\n\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) {\n\t\t\tif (bean instanceof JedisConnectionFactory jedisConnectionFactory) {\n\t\t\t\tconnectionFactory = jedisConnectionFactory;\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JedisDisableStartupConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor jedisDisableStartup() {\n\t\t\treturn new BeanPostProcessor() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) {\n\t\t\t\t\tif (bean instanceof JedisConnectionFactory jedisConnectionFactory) {\n\t\t\t\t\t\tjedisConnectionFactory.setEarlyStartup(false);\n\t\t\t\t\t\tjedisConnectionFactory.setAutoStartup(false);\n\t\t\t\t\t}\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/DataRedisAutoConfigurationLettuceWithoutCommonsPool2Tests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisAutoConfiguration} when commons-pool2 is not on the\n * classpath.\n *\n * @author Stephane Nicoll\n */\n@ClassPathExclusions(\"commons-pool2-*.jar\")\nclass DataRedisAutoConfigurationLettuceWithoutCommonsPool2Tests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class));\n\n\t@Test\n\tvoid poolWithoutCommonsPool2IsDisabledByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\").run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\tassertThat(cf.getClientConfiguration()).isNotInstanceOf(LettucePoolingClientConfiguration.class);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/DataRedisAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.EnumSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport io.lettuce.core.ClientOptions;\nimport io.lettuce.core.ReadFrom;\nimport io.lettuce.core.ReadFrom.Nodes;\nimport io.lettuce.core.RedisURI;\nimport io.lettuce.core.cluster.ClusterClientOptions;\nimport io.lettuce.core.cluster.ClusterTopologyRefreshOptions.RefreshTrigger;\nimport io.lettuce.core.cluster.models.partitions.RedisClusterNode;\nimport io.lettuce.core.models.role.RedisNodeDescription;\nimport io.lettuce.core.resource.DefaultClientResources;\nimport io.lettuce.core.tracing.Tracing;\nimport org.apache.commons.pool2.impl.GenericObjectPoolConfig;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisProperties.Pool;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.assertj.SimpleAsyncTaskExecutorAssert;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.data.redis.connection.NamedNode;\nimport org.springframework.data.redis.connection.RedisClusterConfiguration;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisNode;\nimport org.springframework.data.redis.connection.RedisPassword;\nimport org.springframework.data.redis.connection.RedisSentinelConfiguration;\nimport org.springframework.data.redis.connection.RedisStandaloneConfiguration;\nimport org.springframework.data.redis.connection.RedisStaticMasterReplicaConfiguration;\nimport org.springframework.data.redis.connection.jedis.JedisConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;\nimport org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration.LettuceClientConfigurationBuilder;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\nimport org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;\nimport org.springframework.data.redis.core.RedisOperations;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataRedisAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Christoph Strobl\n * @author Eddú Meléndez\n * @author Marco Aust\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Alen Turkovic\n * @author Scott Frederick\n * @author Weix Sun\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DataRedisAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultRedisConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBean(\"redisTemplate\")).isInstanceOf(RedisOperations.class);\n\t\t\tassertThat(context).hasSingleBean(StringRedisTemplate.class);\n\t\t\tassertThat(context).hasSingleBean(RedisConnectionFactory.class);\n\t\t\tassertThat(context.getBean(RedisConnectionFactory.class)).isInstanceOf(LettuceConnectionFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testOverrideRedisConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.database:1\",\n\t\t\t\t\t\"spring.data.redis.lettuce.shutdown-timeout:500\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getDatabase()).isOne();\n\t\t\t\tassertThat(getUserName(cf)).isNull();\n\t\t\t\tassertThat(cf.getPassword()).isNull();\n\t\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\t\tassertThat(cf.getShutdownTimeout()).isEqualTo(500);\n\t\t\t});\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource\n\tvoid shouldConfigureLettuceReadFromProperty(String type, ReadFrom readFrom) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.lettuce.read-from:\" + type).run((context) -> {\n\t\t\tLettuceConnectionFactory factory = context.getBean(LettuceConnectionFactory.class);\n\t\t\tLettuceClientConfiguration configuration = factory.getClientConfiguration();\n\t\t\tassertThat(configuration.getReadFrom()).hasValue(readFrom);\n\t\t});\n\t}\n\n\tstatic Stream<Arguments> shouldConfigureLettuceReadFromProperty() {\n\t\treturn Stream.of(Arguments.of(\"any\", ReadFrom.ANY), Arguments.of(\"any-replica\", ReadFrom.ANY_REPLICA),\n\t\t\t\tArguments.of(\"lowest-latency\", ReadFrom.LOWEST_LATENCY), Arguments.of(\"replica\", ReadFrom.REPLICA),\n\t\t\t\tArguments.of(\"replica-preferred\", ReadFrom.REPLICA_PREFERRED),\n\t\t\t\tArguments.of(\"upstream\", ReadFrom.UPSTREAM),\n\t\t\t\tArguments.of(\"upstream-preferred\", ReadFrom.UPSTREAM_PREFERRED));\n\t}\n\n\t@Test\n\tvoid shouldConfigureLettuceRegexReadFromProperty() {\n\t\tRedisClusterNode node1 = createRedisNode(\"redis-node-1.region-1.example.com\");\n\t\tRedisClusterNode node2 = createRedisNode(\"redis-node-2.region-1.example.com\");\n\t\tRedisClusterNode node3 = createRedisNode(\"redis-node-1.region-2.example.com\");\n\t\tRedisClusterNode node4 = createRedisNode(\"redis-node-2.region-2.example.com\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.lettuce.read-from:regex:.*region-1.*\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory factory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tLettuceClientConfiguration configuration = factory.getClientConfiguration();\n\t\t\t\tassertThat(configuration.getReadFrom()).hasValueSatisfying((readFrom) -> {\n\t\t\t\t\tList<RedisNodeDescription> result = readFrom.select(new RedisNodes(node1, node2, node3, node4));\n\t\t\t\t\tassertThat(result).hasSize(2).containsExactly(node1, node2);\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureLettuceSubnetReadFromProperty() {\n\t\tRedisClusterNode nodeInSubnetIpv4 = createRedisNode(\"192.0.2.1\");\n\t\tRedisClusterNode nodeNotInSubnetIpv4 = createRedisNode(\"198.51.100.1\");\n\t\tRedisClusterNode nodeInSubnetIpv6 = createRedisNode(\"2001:db8:abcd:0000::1\");\n\t\tRedisClusterNode nodeNotInSubnetIpv6 = createRedisNode(\"2001:db8:abcd:1000::\");\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.lettuce.read-from:subnet:192.0.2.0/24,2001:db8:abcd:0000::/52\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory factory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tLettuceClientConfiguration configuration = factory.getClientConfiguration();\n\t\t\t\tassertThat(configuration.getReadFrom()).hasValueSatisfying((readFrom) -> {\n\t\t\t\t\tList<RedisNodeDescription> result = readFrom.select(new RedisNodes(nodeInSubnetIpv4,\n\t\t\t\t\t\t\tnodeNotInSubnetIpv4, nodeInSubnetIpv6, nodeNotInSubnetIpv6));\n\t\t\t\t\tassertThat(result).hasSize(2).containsExactly(nodeInSubnetIpv4, nodeInSubnetIpv6);\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testCustomizeClientResources() {\n\t\tTracing tracing = mock(Tracing.class);\n\t\tthis.contextRunner.withBean(ClientResourcesBuilderCustomizer.class, () -> (builder) -> builder.tracing(tracing))\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultClientResources clientResources = context.getBean(DefaultClientResources.class);\n\t\t\t\tassertThat(clientResources.tracing()).isEqualTo(tracing);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testCustomizeRedisConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t\tassertThat(cf.getClientConfiguration().getClientOptions())\n\t\t\t\t.hasValueSatisfying((options) -> assertThat(options.isAutoReconnect()).isFalse());\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisUrlConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.url:redis://user:password@example:33\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\t\tassertThat(getUserName(cf)).isEqualTo(\"user\");\n\t\t\t\tassertThat(cf.getPassword()).isEqualTo(\"password\");\n\t\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testOverrideUrlRedisConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.redis.data.user:alice\",\n\t\t\t\t\t\"spring.data.redis.password:xyz\", \"spring.data.redis.port:1000\",\n\t\t\t\t\t\"spring.data.redis.ssl.enabled:false\", \"spring.data.redis.url:rediss://user:password@example:33\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\t\tassertThat(getUserName(cf)).isEqualTo(\"user\");\n\t\t\t\tassertThat(cf.getPassword()).isEqualTo(\"password\");\n\t\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testPasswordInUrlWithColon() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.url:redis://:pass:word@example:33\").run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\tassertThat(getUserName(cf)).isEmpty();\n\t\t\tassertThat(cf.getPassword()).isEqualTo(\"pass:word\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testPasswordInUrlStartsWithColon() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.url:redis://user::pass:word@example:33\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"example\");\n\t\t\t\tassertThat(cf.getPort()).isEqualTo(33);\n\t\t\t\tassertThat(getUserName(cf)).isEqualTo(\"user\");\n\t\t\t\tassertThat(cf.getPassword()).isEqualTo(\":pass:word\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationUsePoolByDefault() {\n\t\tPool defaultPool = new DataRedisProperties().getLettuce().getPool();\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\").run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\tGenericObjectPoolConfig<?> poolConfig = getPoolingClientConfiguration(cf).getPoolConfig();\n\t\t\tassertThat(poolConfig.getMinIdle()).isEqualTo(defaultPool.getMinIdle());\n\t\t\tassertThat(poolConfig.getMaxIdle()).isEqualTo(defaultPool.getMaxIdle());\n\t\t\tassertThat(poolConfig.getMaxTotal()).isEqualTo(defaultPool.getMaxActive());\n\t\t\tassertThat(poolConfig.getMaxWaitDuration()).isEqualTo(defaultPool.getMaxWait());\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithCustomPoolSettings() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.lettuce.pool.min-idle:1\",\n\t\t\t\t\t\"spring.data.redis.lettuce.pool.max-idle:4\", \"spring.data.redis.lettuce.pool.max-active:16\",\n\t\t\t\t\t\"spring.data.redis.lettuce.pool.max-wait:2000\",\n\t\t\t\t\t\"spring.data.redis.lettuce.pool.time-between-eviction-runs:30000\",\n\t\t\t\t\t\"spring.data.redis.lettuce.shutdown-timeout:1000\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tGenericObjectPoolConfig<?> poolConfig = getPoolingClientConfiguration(cf).getPoolConfig();\n\t\t\t\tassertThat(poolConfig.getMinIdle()).isOne();\n\t\t\t\tassertThat(poolConfig.getMaxIdle()).isEqualTo(4);\n\t\t\t\tassertThat(poolConfig.getMaxTotal()).isEqualTo(16);\n\t\t\t\tassertThat(poolConfig.getMaxWaitDuration()).isEqualTo(Duration.ofSeconds(2));\n\t\t\t\tassertThat(poolConfig.getDurationBetweenEvictionRuns()).isEqualTo(Duration.ofSeconds(30));\n\t\t\t\tassertThat(cf.getShutdownTimeout()).isEqualTo(1000);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationDisabledPool() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.lettuce.pool.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getClientConfiguration()).isNotInstanceOf(LettucePoolingClientConfiguration.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithTimeoutAndConnectTimeout() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.timeout:250\",\n\t\t\t\t\t\"spring.data.redis.connect-timeout:1000\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getTimeout()).isEqualTo(250);\n\t\t\t\tassertThat(cf.getClientConfiguration()\n\t\t\t\t\t.getClientOptions()\n\t\t\t\t\t.get()\n\t\t\t\t\t.getSocketOptions()\n\t\t\t\t\t.getConnectTimeout()\n\t\t\t\t\t.toMillis()).isEqualTo(1000);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithDefaultTimeouts() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\").run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\tassertThat(cf.getTimeout()).isEqualTo(60000);\n\t\t\tassertThat(cf.getClientConfiguration()\n\t\t\t\t.getClientOptions()\n\t\t\t\t.get()\n\t\t\t\t.getSocketOptions()\n\t\t\t\t.getConnectTimeout()\n\t\t\t\t.toMillis()).isEqualTo(10000);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithCustomBean() {\n\t\tthis.contextRunner.withUserConfiguration(RedisStandaloneConfig.class).run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClientName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.host:foo\", \"spring.data.redis.client-name:spring-boot\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.getHostName()).isEqualTo(\"foo\");\n\t\t\t\tassertThat(cf.getClientName()).isEqualTo(\"spring-boot\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionFactoryWithJedisClientType() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.client-type:jedis\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RedisConnectionFactory.class);\n\t\t\tassertThat(context.getBean(RedisConnectionFactory.class)).isInstanceOf(JedisConnectionFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid connectionFactoryWithLettuceClientType() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.client-type:lettuce\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RedisConnectionFactory.class);\n\t\t\tassertThat(context.getBean(RedisConnectionFactory.class)).isInstanceOf(LettuceConnectionFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinel() {\n\t\tList<String> sentinels = Arrays.asList(\"127.0.0.1:26379\", \"127.0.0.1:26380\");\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:\" + StringUtils.collectionToCommaDelimitedString(sentinels))\n\t\t\t.run((context) -> assertThat(context.getBean(LettuceConnectionFactory.class).isRedisSentinelAware())\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithIpv6Sentinel() {\n\t\tList<String> sentinels = Arrays.asList(\"[0:0:0:0:0:0:0:1]:26379\", \"[0:0:0:0:0:0:0:1]:26380\");\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:\" + StringUtils.collectionToCommaDelimitedString(sentinels))\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory connectionFactory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.isRedisSentinelAware()).isTrue();\n\t\t\t\tRedisSentinelConfiguration sentinelConfiguration = connectionFactory.getSentinelConfiguration();\n\t\t\t\tassertThat(sentinelConfiguration).isNotNull();\n\t\t\t\tassertThat(sentinelConfiguration.getSentinels()).isNotNull()\n\t\t\t\t\t.containsExactlyInAnyOrder(new RedisNode(\"[0:0:0:0:0:0:0:1]\", 26379),\n\t\t\t\t\t\t\tnew RedisNode(\"[0:0:0:0:0:0:0:1]\", 26380));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinelAndDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.database:1\", \"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:127.0.0.1:26379, 127.0.0.1:26380\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory connectionFactory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getDatabase()).isOne();\n\t\t\t\tassertThat(connectionFactory.isRedisSentinelAware()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinelAndAuthentication() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.username=user\", \"spring.data.redis.password=password\",\n\t\t\t\t\t\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:127.0.0.1:26379,  127.0.0.1:26380\")\n\t\t\t.run(assertSentinelConfiguration(\"user\", \"password\", (sentinelConfiguration) -> {\n\t\t\t\tassertThat(sentinelConfiguration.getSentinelPassword().isPresent()).isFalse();\n\t\t\t\tSet<RedisNode> sentinels = sentinelConfiguration.getSentinels();\n\t\t\t\tassertThat(sentinels.stream().map(Object::toString).collect(Collectors.toSet()))\n\t\t\t\t\t.contains(\"127.0.0.1:26379\", \"127.0.0.1:26380\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinelPasswordAndDataNodePassword() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.password=password\", \"spring.data.redis.sentinel.password=secret\",\n\t\t\t\t\t\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:127.0.0.1:26379,  127.0.0.1:26380\")\n\t\t\t.run(assertSentinelConfiguration(null, \"password\", (sentinelConfiguration) -> {\n\t\t\t\tassertThat(sentinelConfiguration.getSentinelUsername()).isNull();\n\t\t\t\tassertThat(new String(sentinelConfiguration.getSentinelPassword().get())).isEqualTo(\"secret\");\n\t\t\t\tSet<RedisNode> sentinels = sentinelConfiguration.getSentinels();\n\t\t\t\tassertThat(sentinels.stream().map(Object::toString).collect(Collectors.toSet()))\n\t\t\t\t\t.contains(\"127.0.0.1:26379\", \"127.0.0.1:26380\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSentinelAuthenticationAndDataNodeAuthentication() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.username=username\", \"spring.data.redis.password=password\",\n\t\t\t\t\t\"spring.data.redis.sentinel.username=sentinel\", \"spring.data.redis.sentinel.password=secret\",\n\t\t\t\t\t\"spring.data.redis.sentinel.master:mymaster\",\n\t\t\t\t\t\"spring.data.redis.sentinel.nodes:127.0.0.1:26379,  127.0.0.1:26380\")\n\t\t\t.run(assertSentinelConfiguration(\"username\", \"password\", (sentinelConfiguration) -> {\n\t\t\t\tassertThat(sentinelConfiguration.getSentinelUsername()).isEqualTo(\"sentinel\");\n\t\t\t\tassertThat(new String(sentinelConfiguration.getSentinelPassword().get())).isEqualTo(\"secret\");\n\t\t\t\tSet<RedisNode> sentinels = sentinelConfiguration.getSentinels();\n\t\t\t\tassertThat(sentinels.stream().map(Object::toString).collect(Collectors.toSet()))\n\t\t\t\t\t.contains(\"127.0.0.1:26379\", \"127.0.0.1:26380\");\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertSentinelConfiguration(@Nullable String userName,\n\t\t\tString password, Consumer<RedisSentinelConfiguration> sentinelConfiguration) {\n\t\treturn (context) -> {\n\t\t\tLettuceConnectionFactory connectionFactory = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(getUserName(connectionFactory)).isEqualTo(userName);\n\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(password);\n\t\t\tassertThat(connectionFactory.getSentinelConfiguration()).satisfies(sentinelConfiguration);\n\t\t};\n\t}\n\n\t@Test\n\tvoid testRedisSentinelUrlConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.data.redis.url=redis-sentinel://username:password@127.0.0.1:26379,127.0.0.1:26380/mymaster\")\n\t\t\t.run((context) -> assertThatIllegalStateException()\n\t\t\t\t.isThrownBy(() -> context.getBean(LettuceConnectionFactory.class))\n\t\t\t\t.withRootCauseInstanceOf(DataRedisUrlSyntaxException.class)\n\t\t\t\t.havingRootCause()\n\t\t\t\t.withMessageContaining(\n\t\t\t\t\t\t\"Invalid Redis URL 'redis-sentinel://username:password@127.0.0.1:26379,127.0.0.1:26380/mymaster'\"));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithCluster() {\n\t\tList<String> clusterNodes = Arrays.asList(\"127.0.0.1:27379\", \"127.0.0.1:27380\", \"[::1]:27381\");\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.cluster.nodes[0]:\" + clusterNodes.get(0),\n\t\t\t\t\t\"spring.data.redis.cluster.nodes[1]:\" + clusterNodes.get(1),\n\t\t\t\t\t\"spring.data.redis.cluster.nodes[2]:\" + clusterNodes.get(2))\n\t\t\t.run((context) -> {\n\t\t\t\tRedisClusterConfiguration clusterConfiguration = context.getBean(LettuceConnectionFactory.class)\n\t\t\t\t\t.getClusterConfiguration();\n\t\t\t\tassertThat(clusterConfiguration).isNotNull();\n\t\t\t\tassertThat(clusterConfiguration.getClusterNodes()).hasSize(3);\n\t\t\t\tassertThat(clusterConfiguration.getClusterNodes()).containsExactlyInAnyOrder(\n\t\t\t\t\t\tnew RedisNode(\"127.0.0.1\", 27379), new RedisNode(\"127.0.0.1\", 27380),\n\t\t\t\t\t\tnew RedisNode(\"[::1]\", 27381));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterAndAuthentication() {\n\t\tList<String> clusterNodes = Arrays.asList(\"127.0.0.1:27379\", \"127.0.0.1:27380\");\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.username=user\", \"spring.data.redis.password=password\",\n\t\t\t\t\t\"spring.data.redis.cluster.nodes[0]:\" + clusterNodes.get(0),\n\t\t\t\t\t\"spring.data.redis.cluster.nodes[1]:\" + clusterNodes.get(1))\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory connectionFactory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(getUserName(connectionFactory)).isEqualTo(\"user\");\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(\"password\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithMasterReplicaAndNoNode() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.masterreplica.nodes=\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessage(\"At least one node is required for master-replica configuration\"));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithMasterReplica() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.masterreplica.nodes=127.0.0.1:28319,127.0.0.1:28320,[::1]:28321\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory connectionFactory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory.getSentinelConfiguration()).isNull();\n\t\t\t\tassertThat(connectionFactory.getClusterConfiguration()).isNull();\n\t\t\t\tassertThat(connectionFactory).extracting(\"configuration\")\n\t\t\t\t\t.isInstanceOfSatisfying(RedisStaticMasterReplicaConfiguration.class,\n\t\t\t\t\t\t\t(masterReplicaConfiguration) -> assertThat(masterReplicaConfiguration.getNodes()\n\t\t\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t\t\t.map((config) -> new RedisNode(config.getHostName(), config.getPort())))\n\t\t\t\t\t\t\t\t.containsExactly(new RedisNode(\"127.0.0.1\", 28319), new RedisNode(\"127.0.0.1\", 28320),\n\t\t\t\t\t\t\t\t\t\tnew RedisNode(\"[::1]\", 28321)));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithMasterAndAuthentication() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.username=user\", \"spring.data.redis.password=password\",\n\t\t\t\t\t\"spring.data.redis.masterreplica.nodes=127.0.0.1:28319,127.0.0.1:28320\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory connectionFactory = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(getUserName(connectionFactory)).isEqualTo(\"user\");\n\t\t\t\tassertThat(connectionFactory.getPassword()).isEqualTo(\"password\");\n\t\t\t\tassertThat(connectionFactory).extracting(\"configuration\")\n\t\t\t\t\t.isInstanceOf(RedisStaticMasterReplicaConfiguration.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationCreateClientOptionsByDefault() {\n\t\tthis.contextRunner.run(assertClientOptions(ClientOptions.class, (options) -> {\n\t\t\tassertThat(options.getTimeoutOptions().isApplyConnectionTimeout()).isTrue();\n\t\t\tassertThat(options.getTimeoutOptions().isTimeoutCommands()).isTrue();\n\t\t}));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterCreateClusterClientOptions() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\")\n\t\t\t.run(assertClientOptions(ClusterClientOptions.class, (options) -> {\n\t\t\t\tassertThat(options.getTimeoutOptions().isApplyConnectionTimeout()).isTrue();\n\t\t\t\tassertThat(options.getTimeoutOptions().isTimeoutCommands()).isTrue();\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterRefreshPeriod() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\",\n\t\t\t\t\t\"spring.data.redis.lettuce.cluster.refresh.period=30s\")\n\t\t\t.run(assertClientOptions(ClusterClientOptions.class,\n\t\t\t\t\t(options) -> assertThat(options.getTopologyRefreshOptions().getRefreshPeriod()).hasSeconds(30)));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterAdaptiveRefresh() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\",\n\t\t\t\t\t\"spring.data.redis.lettuce.cluster.refresh.adaptive=true\")\n\t\t\t.run(assertClientOptions(ClusterClientOptions.class,\n\t\t\t\t\t(options) -> assertThat(options.getTopologyRefreshOptions().getAdaptiveRefreshTriggers())\n\t\t\t\t\t\t.isEqualTo(EnumSet.allOf(RefreshTrigger.class))));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterRefreshPeriodHasNoEffectWithNonClusteredConfiguration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.cluster.refresh.period=30s\")\n\t\t\t.run(assertClientOptions(ClientOptions.class,\n\t\t\t\t\t(options) -> assertThat(options.getClass()).isEqualTo(ClientOptions.class)));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterDynamicRefreshSourcesEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\",\n\t\t\t\t\t\"spring.data.redis.lettuce.cluster.refresh.dynamic-refresh-sources=true\")\n\t\t\t.run(assertClientOptions(ClusterClientOptions.class,\n\t\t\t\t\t(options) -> assertThat(options.getTopologyRefreshOptions().useDynamicRefreshSources()).isTrue()));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterDynamicRefreshSourcesDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\",\n\t\t\t\t\t\"spring.data.redis.lettuce.cluster.refresh.dynamic-refresh-sources=false\")\n\t\t\t.run(assertClientOptions(ClusterClientOptions.class,\n\t\t\t\t\t(options) -> assertThat(options.getTopologyRefreshOptions().useDynamicRefreshSources()).isFalse()));\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithClusterDynamicSourcesUnspecifiedUsesDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.cluster.nodes=127.0.0.1:27379,127.0.0.1:27380\",\n\t\t\t\t\t\"spring.data.redis.lettuce.cluster.refresh.dynamic-sources=\")\n\t\t\t.run(assertClientOptions(ClusterClientOptions.class,\n\t\t\t\t\t(options) -> assertThat(options.getTopologyRefreshOptions().useDynamicRefreshSources()).isTrue()));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesDataRedisConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid usesStandaloneFromCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsStandaloneConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataRedisConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesDataRedisConnectionDetails.class);\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\tRedisStandaloneConfiguration configuration = cf.getStandaloneConfiguration();\n\t\t\tassertThat(configuration.getHostName()).isEqualTo(\"redis.example.com\");\n\t\t\tassertThat(configuration.getPort()).isEqualTo(16379);\n\t\t\tassertThat(configuration.getDatabase()).isOne();\n\t\t\tassertThat(configuration.getUsername()).isEqualTo(\"user-1\");\n\t\t\tassertThat(configuration.getPassword()).isEqualTo(RedisPassword.of(\"password-1\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid usesSentinelFromCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsSentinelConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataRedisConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesDataRedisConnectionDetails.class);\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\tRedisSentinelConfiguration configuration = cf.getSentinelConfiguration();\n\t\t\tassertThat(configuration).isNotNull();\n\t\t\tassertThat(configuration.getSentinelUsername()).isEqualTo(\"sentinel-1\");\n\t\t\tassertThat(configuration.getSentinelPassword().get()).isEqualTo(\"secret-1\".toCharArray());\n\t\t\tassertThat(configuration.getSentinels()).containsExactly(new RedisNode(\"node-1\", 12345));\n\t\t\tassertThat(configuration.getUsername()).isEqualTo(\"user-1\");\n\t\t\tassertThat(configuration.getPassword()).isEqualTo(RedisPassword.of(\"password-1\"));\n\t\t\tassertThat(configuration.getDatabase()).isOne();\n\t\t\tNamedNode master = configuration.getMaster();\n\t\t\tassertThat(master).isNotNull();\n\t\t\tassertThat(master.getName()).isEqualTo(\"master.redis.example.com\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid usesClusterFromCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsClusterConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataRedisConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesDataRedisConnectionDetails.class);\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\tRedisClusterConfiguration configuration = cf.getClusterConfiguration();\n\t\t\tassertThat(configuration).isNotNull();\n\t\t\tassertThat(configuration.getUsername()).isEqualTo(\"user-1\");\n\t\t\tassertThat(configuration.getPassword().get()).isEqualTo(\"password-1\".toCharArray());\n\t\t\tassertThat(configuration.getClusterNodes()).containsExactly(new RedisNode(\"node-1\", 12345),\n\t\t\t\t\tnew RedisNode(\"node-2\", 23456));\n\t\t});\n\t}\n\n\t@Test\n\tvoid usesMasterReplicaFromCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsMasterReplicaConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataRedisConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesDataRedisConnectionDetails.class);\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\tassertThat(cf).extracting(\"configuration\")\n\t\t\t\t.isInstanceOfSatisfying(RedisStaticMasterReplicaConfiguration.class,\n\t\t\t\t\t\t(masterReplicationConfiguration) -> {\n\t\t\t\t\t\t\tassertThat(masterReplicationConfiguration.getUsername()).isEqualTo(\"user-1\");\n\t\t\t\t\t\t\tassertThat(masterReplicationConfiguration.getPassword().get())\n\t\t\t\t\t\t\t\t.isEqualTo(\"password-1\".toCharArray());\n\t\t\t\t\t\t\tassertThat(masterReplicationConfiguration.getNodes())\n\t\t\t\t\t\t\t\t.map((nodeConfiguration) -> new RedisNode(nodeConfiguration.getHostName(),\n\t\t\t\t\t\t\t\t\t\tnodeConfiguration.getPort()))\n\t\t\t\t\t\t\t\t.containsExactly(new RedisNode(\"node-1\", 12345), new RedisNode(\"node-2\", 23456));\n\t\t\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSslEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.data.redis.ssl.enabled:true\").run((context) -> {\n\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid testRedisConfigurationWithSslBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location:classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password:secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password:password\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.isUseSsl()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRedisConfigurationWithSslDisabledBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.ssl.enabled:false\", \"spring.data.redis.ssl.bundle:test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tLettuceConnectionFactory cf = context.getBean(LettuceConnectionFactory.class);\n\t\t\t\tassertThat(cf.isUseSsl()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUsePlatformThreadsByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tLettuceConnectionFactory factory = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(factory).extracting(\"executor\").isNull();\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldUseVirtualThreadsIfEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tLettuceConnectionFactory factory = context.getBean(LettuceConnectionFactory.class);\n\t\t\tassertThat(factory).extracting(\"executor\")\n\t\t\t\t.satisfies((executor) -> SimpleAsyncTaskExecutorAssert.assertThat((SimpleAsyncTaskExecutor) executor)\n\t\t\t\t\t.usesVirtualThreads());\n\t\t});\n\t}\n\n\tprivate <T extends ClientOptions> ContextConsumer<AssertableApplicationContext> assertClientOptions(\n\t\t\tClass<T> expectedType, Consumer<T> options) {\n\t\treturn (context) -> {\n\t\t\tLettuceClientConfiguration clientConfiguration = context.getBean(LettuceConnectionFactory.class)\n\t\t\t\t.getClientConfiguration();\n\t\t\tassertThat(clientConfiguration.getClientOptions()).isPresent();\n\t\t\tClientOptions clientOptions = clientConfiguration.getClientOptions().get();\n\t\t\tassertThat(clientOptions.getClass()).isEqualTo(expectedType);\n\t\t\toptions.accept(expectedType.cast(clientOptions));\n\t\t};\n\t}\n\n\tprivate LettucePoolingClientConfiguration getPoolingClientConfiguration(LettuceConnectionFactory factory) {\n\t\treturn (LettucePoolingClientConfiguration) factory.getClientConfiguration();\n\t}\n\n\tprivate @Nullable String getUserName(LettuceConnectionFactory factory) {\n\t\treturn ReflectionTestUtils.invokeMethod(factory, \"getRedisUsername\");\n\t}\n\n\tprivate RedisClusterNode createRedisNode(String host) {\n\t\tRedisClusterNode node = new RedisClusterNode();\n\t\tnode.setUri(RedisURI.Builder.redis(host).build());\n\t\treturn node;\n\t}\n\n\tprivate static final class RedisNodes implements Nodes {\n\n\t\tprivate final List<RedisNodeDescription> descriptions;\n\n\t\tRedisNodes(RedisNodeDescription... descriptions) {\n\t\t\tthis.descriptions = List.of(descriptions);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<RedisNodeDescription> getNodes() {\n\t\t\treturn this.descriptions;\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<RedisNodeDescription> iterator() {\n\t\t\treturn this.descriptions.iterator();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConfiguration {\n\n\t\t@Bean\n\t\tLettuceClientConfigurationBuilderCustomizer customizer() {\n\t\t\treturn LettuceClientConfigurationBuilder::useSsl;\n\t\t}\n\n\t\t@Bean\n\t\tLettuceClientOptionsBuilderCustomizer clientOptionsBuilderCustomizer() {\n\t\t\treturn (builder) -> builder.autoReconnect(false);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RedisStandaloneConfig {\n\n\t\t@Bean\n\t\tRedisStandaloneConfiguration standaloneConfiguration() {\n\t\t\tRedisStandaloneConfiguration config = new RedisStandaloneConfiguration();\n\t\t\tconfig.setHostName(\"foo\");\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsStandaloneConfiguration {\n\n\t\t@Bean\n\t\tDataRedisConnectionDetails redisConnectionDetails() {\n\t\t\treturn new DataRedisConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"password-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Standalone getStandalone() {\n\t\t\t\t\treturn new Standalone() {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic int getDatabase() {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic String getHost() {\n\t\t\t\t\t\t\treturn \"redis.example.com\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic int getPort() {\n\t\t\t\t\t\t\treturn 16379;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsSentinelConfiguration {\n\n\t\t@Bean\n\t\tDataRedisConnectionDetails redisConnectionDetails() {\n\t\t\treturn new DataRedisConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"password-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Sentinel getSentinel() {\n\t\t\t\t\treturn new Sentinel() {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic int getDatabase() {\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic String getMaster() {\n\t\t\t\t\t\t\treturn \"master.redis.example.com\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic List<Node> getNodes() {\n\t\t\t\t\t\t\treturn List.of(new Node(\"node-1\", 12345));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic String getUsername() {\n\t\t\t\t\t\t\treturn \"sentinel-1\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic String getPassword() {\n\t\t\t\t\t\t\treturn \"secret-1\";\n\t\t\t\t\t\t}\n\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsClusterConfiguration {\n\n\t\t@Bean\n\t\tDataRedisConnectionDetails redisConnectionDetails() {\n\t\t\treturn new DataRedisConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"password-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Cluster getCluster() {\n\t\t\t\t\treturn new Cluster() {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic List<Node> getNodes() {\n\t\t\t\t\t\t\treturn List.of(new Node(\"node-1\", 12345), new Node(\"node-2\", 23456));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsMasterReplicaConfiguration {\n\n\t\t@Bean\n\t\tDataRedisConnectionDetails redisConnectionDetails() {\n\t\t\treturn new DataRedisConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"password-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic MasterReplica getMasterReplica() {\n\t\t\t\t\treturn new MasterReplica() {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic List<Node> getNodes() {\n\t\t\t\t\t\t\treturn List.of(new Node(\"node-1\", 12345), new Node(\"node-2\", 23456));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/DataRedisReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.data.redis.core.ReactiveRedisTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisReactiveAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass DataRedisReactiveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(DataRedisAutoConfiguration.class, DataRedisReactiveAutoConfiguration.class));\n\n\t@Test\n\tvoid testDefaultRedisConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMap<String, ?> beans = context.getBeansOfType(ReactiveRedisTemplate.class);\n\t\t\tassertThat(beans).containsOnlyKeys(\"reactiveRedisTemplate\", \"reactiveStringRedisTemplate\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/PropertiesRedisConnectionDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Cluster;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.MasterReplica;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Node;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisConnectionDetails.Sentinel;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PropertiesDataRedisConnectionDetails}.\n *\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass PropertiesRedisConnectionDetailsTests {\n\n\tprivate DataRedisProperties properties;\n\n\tprivate PropertiesDataRedisConnectionDetails connectionDetails;\n\n\tprivate DefaultSslBundleRegistry sslBundleRegistry;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new DataRedisProperties();\n\t\tthis.sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tthis.connectionDetails = new PropertiesDataRedisConnectionDetails(this.properties, this.sslBundleRegistry);\n\t}\n\n\t@Test\n\tvoid connectionIsConfiguredWithDefaults() {\n\t\tDataRedisConnectionDetails.Standalone standalone = this.connectionDetails.getStandalone();\n\t\tassertThat(standalone.getHost()).isEqualTo(\"localhost\");\n\t\tassertThat(standalone.getPort()).isEqualTo(6379);\n\t\tassertThat(standalone.getDatabase()).isEqualTo(0);\n\t\tassertThat(this.connectionDetails.getSentinel()).isNull();\n\t\tassertThat(this.connectionDetails.getCluster()).isNull();\n\t\tassertThat(this.connectionDetails.getMasterReplica()).isNull();\n\t\tassertThat(this.connectionDetails.getUsername()).isNull();\n\t\tassertThat(this.connectionDetails.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid credentialsAreConfiguredFromUrlWithUsernameAndPassword() {\n\t\tthis.properties.setUrl(\"redis://user:secret@example.com\");\n\t\tassertThat(this.connectionDetails.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(this.connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid credentialsAreConfiguredFromUrlWithUsernameAndColon() {\n\t\tthis.properties.setUrl(\"redis://user:@example.com\");\n\t\tthis.properties.setUsername(\"notused\");\n\t\tthis.properties.setPassword(\"notused\");\n\t\tassertThat(this.connectionDetails.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(this.connectionDetails.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid credentialsAreConfiguredFromUrlWithColonAndPassword() {\n\t\tthis.properties.setUrl(\"redis://:secret@example.com\");\n\t\tthis.properties.setUsername(\"notused\");\n\t\tthis.properties.setPassword(\"notused\");\n\t\tassertThat(this.connectionDetails.getUsername()).isEmpty();\n\t\tassertThat(this.connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid credentialsAreConfiguredFromUrlWithPasswordOnly() {\n\t\tthis.properties.setUrl(\"redis://secret@example.com\");\n\t\tthis.properties.setUsername(\"notused\");\n\t\tthis.properties.setPassword(\"notused\");\n\t\tassertThat(this.connectionDetails.getUsername()).isNull();\n\t\tassertThat(this.connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid credentialsAreConfiguredFromProperties() {\n\t\tthis.properties.setUsername(\"user\");\n\t\tthis.properties.setPassword(\"secret\");\n\t\tassertThat(this.connectionDetails.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(this.connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid standaloneIsConfiguredFromUrl() {\n\t\tthis.properties.setUrl(\"redis://example.com:1234/9999\");\n\t\tthis.properties.setHost(\"notused\");\n\t\tthis.properties.setPort(9999);\n\t\tthis.properties.setDatabase(5);\n\t\tDataRedisConnectionDetails.Standalone standalone = this.connectionDetails.getStandalone();\n\t\tassertThat(standalone.getHost()).isEqualTo(\"example.com\");\n\t\tassertThat(standalone.getPort()).isEqualTo(1234);\n\t\tassertThat(standalone.getDatabase()).isEqualTo(9999);\n\t}\n\n\t@Test\n\tvoid standaloneIsConfiguredFromUrlWithoutDatabase() {\n\t\tthis.properties.setUrl(\"redis://example.com:1234\");\n\t\tthis.properties.setDatabase(5);\n\t\tPropertiesDataRedisConnectionDetails connectionDetails = new PropertiesDataRedisConnectionDetails(\n\t\t\t\tthis.properties, null);\n\t\tDataRedisConnectionDetails.Standalone standalone = connectionDetails.getStandalone();\n\t\tassertThat(standalone.getHost()).isEqualTo(\"example.com\");\n\t\tassertThat(standalone.getPort()).isEqualTo(1234);\n\t\tassertThat(standalone.getDatabase()).isEqualTo(0);\n\t}\n\n\t@Test\n\tvoid standaloneIsConfiguredFromProperties() {\n\t\tthis.properties.setHost(\"example.com\");\n\t\tthis.properties.setPort(1234);\n\t\tthis.properties.setDatabase(5);\n\t\tDataRedisConnectionDetails.Standalone standalone = this.connectionDetails.getStandalone();\n\t\tassertThat(standalone.getHost()).isEqualTo(\"example.com\");\n\t\tassertThat(standalone.getPort()).isEqualTo(1234);\n\t\tassertThat(standalone.getDatabase()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid clusterIsConfigured() {\n\t\tDataRedisProperties.Cluster cluster = new DataRedisProperties.Cluster();\n\t\tcluster.setNodes(List.of(\"localhost:1111\", \"127.0.0.1:2222\", \"[::1]:3333\"));\n\t\tthis.properties.setCluster(cluster);\n\t\tCluster actualCluster = this.connectionDetails.getCluster();\n\t\tassertThat(actualCluster).isNotNull();\n\t\tassertThat(actualCluster.getNodes()).containsExactly(new Node(\"localhost\", 1111), new Node(\"127.0.0.1\", 2222),\n\t\t\t\tnew Node(\"[::1]\", 3333));\n\t}\n\n\t@Test\n\tvoid masterReplicaIsConfigured() {\n\t\tDataRedisProperties.Masterreplica masterReplica = new DataRedisProperties.Masterreplica();\n\t\tmasterReplica.setNodes(List.of(\"localhost:1111\", \"127.0.0.1:2222\", \"[::1]:3333\"));\n\t\tthis.properties.setMasterreplica(masterReplica);\n\t\tMasterReplica actualMasterReplica = this.connectionDetails.getMasterReplica();\n\t\tassertThat(actualMasterReplica).isNotNull();\n\t\tassertThat(actualMasterReplica.getNodes()).containsExactly(new Node(\"localhost\", 1111),\n\t\t\t\tnew Node(\"127.0.0.1\", 2222), new Node(\"[::1]\", 3333));\n\t}\n\n\t@Test\n\tvoid sentinelIsConfigured() {\n\t\tDataRedisProperties.Sentinel sentinel = new DataRedisProperties.Sentinel();\n\t\tsentinel.setNodes(List.of(\"localhost:1111\", \"127.0.0.1:2222\", \"[::1]:3333\"));\n\t\tthis.properties.setSentinel(sentinel);\n\t\tthis.properties.setDatabase(5);\n\t\tPropertiesDataRedisConnectionDetails connectionDetails = new PropertiesDataRedisConnectionDetails(\n\t\t\t\tthis.properties, null);\n\t\tSentinel actualSentinel = connectionDetails.getSentinel();\n\t\tassertThat(actualSentinel).isNotNull();\n\t\tassertThat(actualSentinel.getNodes()).containsExactly(new Node(\"localhost\", 1111), new Node(\"127.0.0.1\", 2222),\n\t\t\t\tnew Node(\"[::1]\", 3333));\n\t\tassertThat(actualSentinel.getDatabase()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid sentinelDatabaseIsConfiguredFromUrl() {\n\t\tDataRedisProperties.Sentinel sentinel = new DataRedisProperties.Sentinel();\n\t\tsentinel.setNodes(List.of(\"localhost:1111\", \"127.0.0.1:2222\", \"[::1]:3333\"));\n\t\tthis.properties.setSentinel(sentinel);\n\t\tthis.properties.setUrl(\"redis://example.com:1234/9999\");\n\t\tthis.properties.setDatabase(5);\n\t\tPropertiesDataRedisConnectionDetails connectionDetails = new PropertiesDataRedisConnectionDetails(\n\t\t\t\tthis.properties, null);\n\t\tSentinel actualSentinel = connectionDetails.getSentinel();\n\t\tassertThat(actualSentinel).isNotNull();\n\t\tassertThat(actualSentinel.getDatabase()).isEqualTo(9999);\n\t}\n\n\t@Test\n\tvoid shouldReturnSslBundle() {\n\t\tSslBundle bundle1 = mock(SslBundle.class);\n\t\tthis.sslBundleRegistry.registerBundle(\"bundle-1\", bundle1);\n\t\tthis.properties.getSsl().setBundle(\"bundle-1\");\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isSameAs(bundle1);\n\t}\n\n\t@Test\n\tvoid shouldReturnSystemBundleIfSslIsEnabledButBundleNotSet() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\t@Test\n\tvoid shouldReturnNullIfSslIsNotEnabled() {\n\t\tthis.properties.getSsl().setEnabled(false);\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/RedisPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport io.lettuce.core.cluster.ClusterTopologyRefreshOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisProperties.Lettuce;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisProperties}.\n *\n * @author Stephane Nicoll\n */\nclass RedisPropertiesTests {\n\n\t@Test\n\tvoid lettuceDefaultsAreConsistent() {\n\t\tLettuce lettuce = new DataRedisProperties().getLettuce();\n\t\tClusterTopologyRefreshOptions defaultClusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()\n\t\t\t.build();\n\t\tassertThat(lettuce.getCluster().getRefresh().isDynamicRefreshSources())\n\t\t\t.isEqualTo(defaultClusterTopologyRefreshOptions.useDynamicRefreshSources());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/RedisUrlSyntaxFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisUrlSyntaxFailureAnalyzer}.\n *\n * @author Scott Frederick\n */\nclass RedisUrlSyntaxFailureAnalyzerTests {\n\n\t@Test\n\tvoid analyzeInvalidUrlSyntax() {\n\t\tDataRedisUrlSyntaxException exception = new DataRedisUrlSyntaxException(\"redis://invalid\");\n\t\tFailureAnalysis analysis = new DataRedisUrlSyntaxFailureAnalyzer().analyze(exception);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\"The URL 'redis://invalid' is not valid\");\n\t\tassertThat(analysis.getAction()).contains(\"Review the value of the property 'spring.data.redis.url'\");\n\t}\n\n\t@Test\n\tvoid analyzeRedisHttpUrl() {\n\t\tDataRedisUrlSyntaxException exception = new DataRedisUrlSyntaxException(\"http://127.0.0.1:26379/mymaster\");\n\t\tFailureAnalysis analysis = new DataRedisUrlSyntaxFailureAnalyzer().analyze(exception);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\"The URL 'http://127.0.0.1:26379/mymaster' is not valid\")\n\t\t\t.contains(\"The scheme 'http' is not supported\");\n\t\tassertThat(analysis.getAction()).contains(\"Use the scheme 'redis://' for insecure or 'rediss://' for secure\");\n\t}\n\n\t@Test\n\tvoid analyzeRedisSentinelUrl() {\n\t\tDataRedisUrlSyntaxException exception = new DataRedisUrlSyntaxException(\n\t\t\t\t\"redis-sentinel://username:password@127.0.0.1:26379,127.0.0.1:26380/mymaster\");\n\t\tFailureAnalysis analysis = new DataRedisUrlSyntaxFailureAnalyzer().analyze(exception);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\n\t\t\t\t\"The URL 'redis-sentinel://username:password@127.0.0.1:26379,127.0.0.1:26380/mymaster' is not valid\")\n\t\t\t.contains(\"The scheme 'redis-sentinel' is not supported\");\n\t\tassertThat(analysis.getAction()).contains(\"Use spring.data.redis.sentinel properties\");\n\t}\n\n\t@Test\n\tvoid analyzeRedisSocketUrl() {\n\t\tDataRedisUrlSyntaxException exception = new DataRedisUrlSyntaxException(\"redis-socket:///redis/redis.sock\");\n\t\tFailureAnalysis analysis = new DataRedisUrlSyntaxFailureAnalyzer().analyze(exception);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).contains(\"The URL 'redis-socket:///redis/redis.sock' is not valid\")\n\t\t\t.contains(\"The scheme 'redis-socket' is not supported\");\n\t\tassertThat(analysis.getAction()).contains(\"Configure the appropriate Spring Data Redis connection beans\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/health/DataRedisHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.health.DataRedisHealthIndicator;\nimport org.springframework.boot.data.redis.health.DataRedisReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n */\n@ClassPathExclusions({ \"reactor-core*.jar\", \"lettuce-core*.jar\" })\nclass DataRedisHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class,\n\t\t\t\tDataRedisHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(DataRedisHealthIndicator.class)\n\t\t\t.doesNotHaveBean(DataRedisReactiveHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.redis.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataRedisHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(DataRedisReactiveHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/health/DataRedisReactiveHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.health.DataRedisHealthIndicator;\nimport org.springframework.boot.data.redis.health.DataRedisReactiveHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRedisReactiveHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass DataRedisReactiveHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class,\n\t\t\t\tDataRedisReactiveHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(DataRedisReactiveHealthIndicator.class)\n\t\t\t.hasBean(\"redisHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataRedisHealthContributorAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DataRedisReactiveHealthIndicator.class)\n\t\t\t\t.hasBean(\"redisHealthContributor\")\n\t\t\t\t.doesNotHaveBean(DataRedisHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.redis.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataRedisReactiveHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(\"redisHealthContributor\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/autoconfigure/observation/LettuceObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.autoconfigure.observation;\n\nimport io.lettuce.core.resource.ClientResources;\nimport io.lettuce.core.tracing.MicrometerTracing;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LettuceObservationAutoConfiguration}.\n *\n * @author Antonin Arquey\n * @author Stephane Nicoll\n */\nclass LettuceObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LettuceObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid whenThereIsAnObservationRegistryThenMicrometerTracingIsAdded() {\n\t\tthis.contextRunner.withBean(TestObservationRegistry.class, TestObservationRegistry::create)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tClientResources clientResources = context.getBean(LettuceConnectionFactory.class).getClientResources();\n\t\t\t\tassertThat(clientResources).isNotNull();\n\t\t\t\tassertThat(clientResources.tracing()).isInstanceOf(MicrometerTracing.class);\n\t\t\t});\n\n\t}\n\n\t@Test\n\tvoid whenThereIsNoObservationRegistryThenClientResourcesCustomizationBacksOff() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class)).run((context) -> {\n\t\t\tClientResources clientResources = context.getBean(LettuceConnectionFactory.class).getClientResources();\n\t\t\tassertThat(clientResources).isNotNull();\n\t\t\tassertThat(clientResources.tracing()).isNotInstanceOf(MicrometerTracing.class);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.domain.city;\n\nimport java.io.Serializable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.redis.core.RedisHash;\n\n@RedisHash(\"cities\")\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.domain.city;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tPage<City> findAll(Pageable pageable);\n\n\tPage<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(String name, String country);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.redis.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/domain/empty/EmptyPackage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.domain.empty;\n\npublic class EmptyPackage {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/domain/empty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.redis.domain.empty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/health/DataRedisReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.health;\n\nimport java.time.Duration;\nimport java.util.Properties;\n\nimport io.lettuce.core.RedisConnectionException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.data.redis.RedisConnectionFailureException;\nimport org.springframework.data.redis.connection.ClusterInfo;\nimport org.springframework.data.redis.connection.ReactiveRedisClusterConnection;\nimport org.springframework.data.redis.connection.ReactiveRedisConnection;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\nimport org.springframework.data.redis.connection.ReactiveServerCommands;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataRedisReactiveHealthIndicator}.\n *\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Nikolay Rybak\n * @author Artsiom Yudovin\n * @author Scott Frederick\n */\nclass DataRedisReactiveHealthIndicatorTests {\n\n\t@Test\n\tvoid redisIsUp() {\n\t\tProperties info = new Properties();\n\t\tinfo.put(\"redis_version\", \"2.8.9\");\n\t\tReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);\n\t\tgiven(redisConnection.closeLater()).willReturn(Mono.empty());\n\t\tReactiveServerCommands commands = mock(ReactiveServerCommands.class);\n\t\tgiven(commands.info(\"server\")).willReturn(Mono.just(info));\n\t\tDataRedisReactiveHealthIndicator healthIndicator = createHealthIndicator(redisConnection, commands);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).containsOnlyKeys(\"version\");\n\t\t\tassertThat(h.getDetails()).containsEntry(\"version\", \"2.8.9\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\tthen(redisConnection).should().closeLater();\n\t}\n\n\t@Test\n\tvoid redisIsUpWithMissingVersion() {\n\t\tProperties info = new Properties();\n\t\tReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);\n\t\tgiven(redisConnection.closeLater()).willReturn(Mono.empty());\n\t\tReactiveServerCommands commands = mock(ReactiveServerCommands.class);\n\t\tgiven(commands.info(\"server\")).willReturn(Mono.just(info));\n\t\tDataRedisReactiveHealthIndicator healthIndicator = createHealthIndicator(redisConnection, commands);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).containsOnlyKeys(\"version\");\n\t\t\tassertThat(h.getDetails()).containsEntry(\"version\", \"unknown\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\tthen(redisConnection).should().closeLater();\n\t}\n\n\t@Test\n\tvoid healthWhenClusterStateIsAbsentShouldBeUp() {\n\t\tReactiveRedisConnectionFactory redisConnectionFactory = createClusterConnectionFactory(null);\n\t\tDataRedisReactiveHealthIndicator healthIndicator = new DataRedisReactiveHealthIndicator(redisConnectionFactory);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"cluster_size\", 4L);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"slots_up\", 4L);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"slots_fail\", 0L);\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\tthen(redisConnectionFactory.getReactiveConnection()).should().closeLater();\n\t}\n\n\t@Test\n\tvoid healthWhenClusterStateIsOkShouldBeUp() {\n\t\tReactiveRedisConnectionFactory redisConnectionFactory = createClusterConnectionFactory(\"ok\");\n\t\tDataRedisReactiveHealthIndicator healthIndicator = new DataRedisReactiveHealthIndicator(redisConnectionFactory);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"cluster_size\", 4L);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"slots_up\", 4L);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"slots_fail\", 0L);\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthWhenClusterStateIsFailShouldBeDown() {\n\t\tReactiveRedisConnectionFactory redisConnectionFactory = createClusterConnectionFactory(\"fail\");\n\t\tDataRedisReactiveHealthIndicator healthIndicator = new DataRedisReactiveHealthIndicator(redisConnectionFactory);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.DOWN);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"slots_up\", 3L);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"slots_fail\", 1L);\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid redisCommandIsDown() {\n\t\tReactiveServerCommands commands = mock(ReactiveServerCommands.class);\n\t\tgiven(commands.info(\"server\")).willReturn(Mono.error(new RedisConnectionFailureException(\"Connection failed\")));\n\t\tReactiveRedisConnection redisConnection = mock(ReactiveRedisConnection.class);\n\t\tgiven(redisConnection.closeLater()).willReturn(Mono.empty());\n\t\tDataRedisReactiveHealthIndicator healthIndicator = createHealthIndicator(redisConnection, commands);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.DOWN))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tthen(redisConnection).should().closeLater();\n\t}\n\n\t@Test\n\tvoid redisConnectionIsDown() {\n\t\tReactiveRedisConnectionFactory redisConnectionFactory = mock(ReactiveRedisConnectionFactory.class);\n\t\tgiven(redisConnectionFactory.getReactiveConnection())\n\t\t\t.willThrow(new RedisConnectionException(\"Unable to connect to localhost:6379\"));\n\t\tDataRedisReactiveHealthIndicator healthIndicator = new DataRedisReactiveHealthIndicator(redisConnectionFactory);\n\t\tMono<Health> health = healthIndicator.health();\n\t\tStepVerifier.create(health)\n\t\t\t.consumeNextWith((h) -> assertThat(h.getStatus()).isEqualTo(Status.DOWN))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\tprivate DataRedisReactiveHealthIndicator createHealthIndicator(ReactiveRedisConnection redisConnection,\n\t\t\tReactiveServerCommands serverCommands) {\n\t\tReactiveRedisConnectionFactory redisConnectionFactory = mock(ReactiveRedisConnectionFactory.class);\n\t\tgiven(redisConnectionFactory.getReactiveConnection()).willReturn(redisConnection);\n\t\tgiven(redisConnection.serverCommands()).willReturn(serverCommands);\n\t\treturn new DataRedisReactiveHealthIndicator(redisConnectionFactory);\n\t}\n\n\tprivate ReactiveRedisConnectionFactory createClusterConnectionFactory(@Nullable String state) {\n\t\tProperties clusterProperties = new Properties();\n\t\tif (state != null) {\n\t\t\tclusterProperties.setProperty(\"cluster_state\", state);\n\t\t}\n\t\tclusterProperties.setProperty(\"cluster_size\", \"4\");\n\t\tboolean failure = \"fail\".equals(state);\n\t\tclusterProperties.setProperty(\"cluster_slots_ok\", failure ? \"3\" : \"4\");\n\t\tclusterProperties.setProperty(\"cluster_slots_fail\", failure ? \"1\" : \"0\");\n\t\tReactiveRedisClusterConnection redisConnection = mock(ReactiveRedisClusterConnection.class);\n\t\tgiven(redisConnection.closeLater()).willReturn(Mono.empty());\n\t\tgiven(redisConnection.clusterGetClusterInfo()).willReturn(Mono.just(new ClusterInfo(clusterProperties)));\n\t\tReactiveRedisConnectionFactory redisConnectionFactory = mock(ReactiveRedisConnectionFactory.class);\n\t\tgiven(redisConnectionFactory.getReactiveConnection()).willReturn(redisConnection);\n\t\treturn redisConnectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis/src/test/java/org/springframework/boot/data/redis/health/RedisHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.health;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.data.redis.RedisConnectionFailureException;\nimport org.springframework.data.redis.connection.ClusterInfo;\nimport org.springframework.data.redis.connection.RedisClusterConnection;\nimport org.springframework.data.redis.connection.RedisClusterNode;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisServerCommands;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataRedisHealthIndicator}.\n *\n * @author Christian Dupuis\n * @author Richard Santana\n * @author Stephane Nicoll\n */\nclass RedisHealthIndicatorTests {\n\n\t@Test\n\tvoid redisIsUp() {\n\t\tProperties info = new Properties();\n\t\tinfo.put(\"redis_version\", \"2.8.9\");\n\t\tRedisConnection redisConnection = mock(RedisConnection.class);\n\t\tRedisServerCommands serverCommands = mock(RedisServerCommands.class);\n\t\tgiven(redisConnection.serverCommands()).willReturn(serverCommands);\n\t\tgiven(serverCommands.info()).willReturn(info);\n\t\tDataRedisHealthIndicator healthIndicator = createHealthIndicator(redisConnection);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"version\", \"2.8.9\");\n\t}\n\n\t@Test\n\tvoid redisIsUpWithMissingVersion() {\n\t\tProperties info = new Properties();\n\t\tRedisConnection redisConnection = mock(RedisConnection.class);\n\t\tRedisServerCommands serverCommands = mock(RedisServerCommands.class);\n\t\tgiven(redisConnection.serverCommands()).willReturn(serverCommands);\n\t\tgiven(serverCommands.info()).willReturn(info);\n\t\tDataRedisHealthIndicator healthIndicator = createHealthIndicator(redisConnection);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"version\", \"unknown\");\n\t}\n\n\t@Test\n\tvoid redisIsDown() {\n\t\tRedisConnection redisConnection = mock(RedisConnection.class);\n\t\tRedisServerCommands serverCommands = mock(RedisServerCommands.class);\n\t\tgiven(redisConnection.serverCommands()).willReturn(serverCommands);\n\t\tgiven(serverCommands.info()).willThrow(new RedisConnectionFailureException(\"Connection failed\"));\n\t\tDataRedisHealthIndicator healthIndicator = createHealthIndicator(redisConnection);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat((String) health.getDetails().get(\"error\")).contains(\"Connection failed\");\n\t}\n\n\t@Test\n\tvoid healthWhenClusterStateIsAbsentShouldBeUp() {\n\t\tRedisConnectionFactory redisConnectionFactory = createClusterConnectionFactory(null);\n\t\tDataRedisHealthIndicator healthIndicator = new DataRedisHealthIndicator(redisConnectionFactory);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"cluster_size\", 4L);\n\t\tassertThat(health.getDetails()).containsEntry(\"slots_up\", 4L);\n\t\tassertThat(health.getDetails()).containsEntry(\"slots_fail\", 0L);\n\t\tthen(redisConnectionFactory).should(atLeastOnce()).getConnection();\n\t}\n\n\t@Test\n\tvoid healthWhenClusterStateIsOkShouldBeUp() {\n\t\tRedisConnectionFactory redisConnectionFactory = createClusterConnectionFactory(\"ok\");\n\t\tDataRedisHealthIndicator healthIndicator = new DataRedisHealthIndicator(redisConnectionFactory);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"cluster_size\", 4L);\n\t\tassertThat(health.getDetails()).containsEntry(\"slots_up\", 4L);\n\t\tassertThat(health.getDetails()).containsEntry(\"slots_fail\", 0L);\n\t\tthen(redisConnectionFactory).should(atLeastOnce()).getConnection();\n\t}\n\n\t@Test\n\tvoid healthWhenClusterStateIsFailShouldBeDown() {\n\t\tRedisConnectionFactory redisConnectionFactory = createClusterConnectionFactory(\"fail\");\n\t\tDataRedisHealthIndicator healthIndicator = new DataRedisHealthIndicator(redisConnectionFactory);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"cluster_size\", 4L);\n\t\tassertThat(health.getDetails()).containsEntry(\"slots_up\", 3L);\n\t\tassertThat(health.getDetails()).containsEntry(\"slots_fail\", 1L);\n\t\tthen(redisConnectionFactory).should(atLeastOnce()).getConnection();\n\t}\n\n\tprivate DataRedisHealthIndicator createHealthIndicator(RedisConnection redisConnection) {\n\t\tRedisConnectionFactory redisConnectionFactory = mock(RedisConnectionFactory.class);\n\t\tgiven(redisConnectionFactory.getConnection()).willReturn(redisConnection);\n\t\treturn new DataRedisHealthIndicator(redisConnectionFactory);\n\t}\n\n\tprivate RedisConnectionFactory createClusterConnectionFactory(@Nullable String state) {\n\t\tProperties clusterProperties = new Properties();\n\t\tif (state != null) {\n\t\t\tclusterProperties.setProperty(\"cluster_state\", state);\n\t\t}\n\t\tclusterProperties.setProperty(\"cluster_size\", \"4\");\n\t\tboolean failure = \"fail\".equals(state);\n\t\tclusterProperties.setProperty(\"cluster_slots_ok\", failure ? \"3\" : \"4\");\n\t\tclusterProperties.setProperty(\"cluster_slots_fail\", failure ? \"1\" : \"0\");\n\t\tList<RedisClusterNode> redisMasterNodes = Arrays.asList(new RedisClusterNode(\"127.0.0.1\", 7001),\n\t\t\t\tnew RedisClusterNode(\"127.0.0.2\", 7001));\n\t\tRedisClusterConnection redisConnection = mock(RedisClusterConnection.class);\n\t\tgiven(redisConnection.clusterGetNodes()).willReturn(redisMasterNodes);\n\t\tgiven(redisConnection.clusterGetClusterInfo()).willReturn(new ClusterInfo(clusterProperties));\n\t\tRedisConnectionFactory redisConnectionFactory = mock(RedisConnectionFactory.class);\n\t\tgiven(redisConnectionFactory.getConnection()).willReturn(redisConnection);\n\t\treturn redisConnectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Data Redis Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-data-redis\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"io.projectreactor:reactor-test\")\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\tdockerTestRuntimeOnly(\"io.lettuce:lettuce-core\")\n\tdockerTestRuntimeOnly(\"org.springframework.data:spring-data-redis\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.redis.core.RedisOperations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration test for {@link DataRedisTest @DataRedisTest}.\n *\n * @author Jayaram Pradhan\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataRedisTest\nclass DataRedisTestIntegrationTests {\n\n\tprivate static final Charset CHARSET = StandardCharsets.UTF_8;\n\n\t@Container\n\t@ServiceConnection\n\tstatic RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired\n\tprivate RedisOperations<Object, Object> operations;\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testRepository() {\n\t\tPersonHash personHash = new PersonHash();\n\t\tpersonHash.setDescription(\"Look, new @DataRedisTest!\");\n\t\tassertThat(personHash.getId()).isNull();\n\t\tPersonHash savedEntity = this.exampleRepository.save(personHash);\n\t\tassertThat(savedEntity.getId()).isNotNull();\n\t\tassertThat(this.operations\n\t\t\t.execute((org.springframework.data.redis.connection.RedisConnection connection) -> connection.keyCommands()\n\t\t\t\t.exists((\"persons:\" + savedEntity.getId()).getBytes(CHARSET))))\n\t\t\t.isTrue();\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link DataRedisTest#properties properties} attribute of\n * {@link DataRedisTest @DataRedisTest}.\n *\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataRedisTest(properties = \"spring.profiles.active=test\")\nclass DataRedisTestPropertiesIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(DataRedisTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTestReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.UUID;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.data.redis.core.ReactiveRedisOperations;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Integration test for {@link DataRedisTest @DataRedisTest} using reactive operations.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataRedisTest\nclass DataRedisTestReactiveIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired\n\tprivate ReactiveRedisOperations<Object, Object> operations;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testRepository() {\n\t\tString id = UUID.randomUUID().toString();\n\t\tStepVerifier.create(this.operations.opsForValue().set(id, \"Hello World\"))\n\t\t\t.expectNext(Boolean.TRUE)\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tStepVerifier.create(this.operations.opsForValue().get(id))\n\t\t\t.expectNext(\"Hello World\")\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tStepVerifier.create(this.operations.execute((action) -> action.serverCommands().flushDb()))\n\t\t\t.expectNext(\"OK\")\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleService() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Service;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for {@link DataRedisTest @DataRedisTest}.\n *\n * @author Jayaram Pradhan\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataRedisTest(includeFilters = @Filter(Service.class))\nclass DataRedisTestWithIncludeFilterIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired\n\tprivate ExampleRepository exampleRepository;\n\n\t@Autowired\n\tprivate ExampleService service;\n\n\t@Test\n\tvoid testService() {\n\t\tPersonHash personHash = new PersonHash();\n\t\tpersonHash.setDescription(\"Look, new @DataRedisTest!\");\n\t\tassertThat(personHash.getId()).isNull();\n\t\tPersonHash savedEntity = this.exampleRepository.save(personHash);\n\t\tassertThat(this.service.hasRecord(savedEntity)).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/ExampleRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link DataRedisTest @DataRedisTest} tests.\n *\n * @author Jayaram Pradhan\n */\n@SpringBootApplication\npublic class ExampleRedisApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport org.springframework.data.repository.CrudRepository;\n\n/**\n * Example repository used with {@link DataRedisTest @DataRedisTest} tests.\n *\n * @author Jayaram Pradhan\n */\ninterface ExampleRepository extends CrudRepository<PersonHash, String> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/ExampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.core.RedisOperations;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example service used with {@link DataRedisTest @DataRedisTest} tests.\n *\n * @author Jayaram Pradhan\n */\n@Service\npublic class ExampleService {\n\n\tprivate static final Charset CHARSET = StandardCharsets.UTF_8;\n\n\tprivate final RedisOperations<Object, Object> operations;\n\n\tpublic ExampleService(RedisOperations<Object, Object> operations) {\n\t\tthis.operations = operations;\n\t}\n\n\tpublic boolean hasRecord(PersonHash personHash) {\n\t\treturn this.operations.execute((RedisConnection connection) -> connection.keyCommands()\n\t\t\t.exists((\"persons:\" + personHash.getId()).getBytes(CHARSET)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/dockerTest/java/org/springframework/boot/data/redis/test/autoconfigure/PersonHash.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.redis.core.RedisHash;\n\n/**\n * Example graph used with {@link DataRedisTest @DataRedisTest} tests.\n *\n * @author Jayaram Pradhan\n */\n@RedisHash(\"persons\")\npublic class PersonHash {\n\n\t@Id\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String description;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(@Nullable String description) {\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/main/java/org/springframework/boot/data/redis/test/autoconfigure/AutoConfigureDataRedis.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Data redis\n * tests. Most tests should consider using {@link DataRedisTest @DataRedisTest} rather\n * than using this annotation directly.\n *\n * @author Jayaram Pradhan\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureDataRedis {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/main/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation for a Data Redis test that focuses <strong>only</strong> on Redis\n * components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Data Redis\n * tests. Similarly, component scanning is limited to Redis repositories and entities\n * ({@code @RedisHash}).\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Jayaram Pradhan\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(DataRedisTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(DataRedisTypeExcludeFilter.class)\n@AutoConfigureDataRedis\n@ImportAutoConfiguration\npublic @interface DataRedisTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/main/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link DataRedisTest @DataRedisTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass DataRedisTestContextBootstrapper extends TestSliceTestContextBootstrapper<DataRedisTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/main/java/org/springframework/boot/data/redis/test/autoconfigure/DataRedisTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link DataRedisTest @DataRedisTest}.\n *\n * @author Jayaram Pradhan\n */\nclass DataRedisTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataRedisTest> {\n\n\tDataRedisTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/main/java/org/springframework/boot/data/redis/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Data Redis tests.\n */\n@NullMarked\npackage org.springframework.boot.data.redis.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-redis-test/src/main/resources/META-INF/spring/org.springframework.boot.data.redis.test.autoconfigure.AutoConfigureDataRedis.imports",
    "content": "org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.DataRedisReactiveAutoConfiguration\norg.springframework.boot.data.redis.autoconfigure.DataRedisRepositoriesAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-rest/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Data REST\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-data-commons\"))\n\tapi(project(\":module:spring-boot-jackson\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(project(\":module:spring-boot-webmvc\"))\n\tapi(\"org.springframework.data:spring-data-rest-webmvc\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-data-jpa\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/main/java/org/springframework/boot/data/rest/autoconfigure/DataRestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.rest.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.data.autoconfigure.web.DataWebAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.rest.core.config.RepositoryRestConfiguration;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Data REST.\n * <p>\n * Activates when the application is a web application and no\n * {@link RepositoryRestMvcConfiguration} is found.\n * <p>\n * Once in effect, the auto-configuration allows to configure any property of\n * {@link RepositoryRestConfiguration} using the {@code spring.data.rest} prefix.\n *\n * @author Rob Winch\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(before = DataWebAutoConfiguration.class, after = JacksonAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnMissingBean(RepositoryRestMvcConfiguration.class)\n@ConditionalOnClass(RepositoryRestMvcConfiguration.class)\n@EnableConfigurationProperties(DataRestProperties.class)\n@Import(RepositoryRestMvcConfiguration.class)\npublic final class DataRestAutoConfiguration {\n\n\t@Bean\n\tSpringBootRepositoryRestConfigurer springBootRepositoryRestConfigurer(\n\t\t\tObjectProvider<JsonMapperBuilderCustomizer> jsonMapperBuilderCustomizers, DataRestProperties properties) {\n\t\treturn new SpringBootRepositoryRestConfigurer(jsonMapperBuilderCustomizers.orderedStream().toList(),\n\t\t\t\tproperties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/main/java/org/springframework/boot/data/rest/autoconfigure/DataRestProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.rest.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.data.rest.core.config.RepositoryRestConfiguration;\nimport org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy.RepositoryDetectionStrategies;\nimport org.springframework.http.MediaType;\n\n/**\n * Configuration properties for Spring Data REST.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.data.rest\")\npublic class DataRestProperties {\n\n\t/**\n\t * Base path to be used by Spring Data REST to expose repository resources.\n\t */\n\tprivate @Nullable String basePath;\n\n\t/**\n\t * Default size of pages.\n\t */\n\tprivate @Nullable Integer defaultPageSize;\n\n\t/**\n\t * Maximum size of pages.\n\t */\n\tprivate @Nullable Integer maxPageSize;\n\n\t/**\n\t * Name of the URL query string parameter that indicates what page to return.\n\t */\n\tprivate @Nullable String pageParamName;\n\n\t/**\n\t * Name of the URL query string parameter that indicates how many results to return at\n\t * once.\n\t */\n\tprivate @Nullable String limitParamName;\n\n\t/**\n\t * Name of the URL query string parameter that indicates what direction to sort\n\t * results.\n\t */\n\tprivate @Nullable String sortParamName;\n\n\t/**\n\t * Strategy to use to determine which repositories get exposed.\n\t */\n\tprivate RepositoryDetectionStrategies detectionStrategy = RepositoryDetectionStrategies.DEFAULT;\n\n\t/**\n\t * Content type to use as a default when none is specified.\n\t */\n\tprivate @Nullable MediaType defaultMediaType;\n\n\t/**\n\t * Whether to return a response body after creating an entity.\n\t */\n\tprivate @Nullable Boolean returnBodyOnCreate;\n\n\t/**\n\t * Whether to return a response body after updating an entity.\n\t */\n\tprivate @Nullable Boolean returnBodyOnUpdate;\n\n\t/**\n\t * Whether to return a response body after deleting an entity.\n\t */\n\tprivate @Nullable Boolean returnBodyOnDelete;\n\n\t/**\n\t * Whether to enable enum value translation through the Spring Data REST default\n\t * resource bundle.\n\t */\n\tprivate @Nullable Boolean enableEnumTranslation;\n\n\tpublic @Nullable String getBasePath() {\n\t\treturn this.basePath;\n\t}\n\n\tpublic void setBasePath(@Nullable String basePath) {\n\t\tthis.basePath = basePath;\n\t}\n\n\tpublic @Nullable Integer getDefaultPageSize() {\n\t\treturn this.defaultPageSize;\n\t}\n\n\tpublic void setDefaultPageSize(@Nullable Integer defaultPageSize) {\n\t\tthis.defaultPageSize = defaultPageSize;\n\t}\n\n\tpublic @Nullable Integer getMaxPageSize() {\n\t\treturn this.maxPageSize;\n\t}\n\n\tpublic void setMaxPageSize(@Nullable Integer maxPageSize) {\n\t\tthis.maxPageSize = maxPageSize;\n\t}\n\n\tpublic @Nullable String getPageParamName() {\n\t\treturn this.pageParamName;\n\t}\n\n\tpublic void setPageParamName(@Nullable String pageParamName) {\n\t\tthis.pageParamName = pageParamName;\n\t}\n\n\tpublic @Nullable String getLimitParamName() {\n\t\treturn this.limitParamName;\n\t}\n\n\tpublic void setLimitParamName(@Nullable String limitParamName) {\n\t\tthis.limitParamName = limitParamName;\n\t}\n\n\tpublic @Nullable String getSortParamName() {\n\t\treturn this.sortParamName;\n\t}\n\n\tpublic void setSortParamName(@Nullable String sortParamName) {\n\t\tthis.sortParamName = sortParamName;\n\t}\n\n\tpublic RepositoryDetectionStrategies getDetectionStrategy() {\n\t\treturn this.detectionStrategy;\n\t}\n\n\tpublic void setDetectionStrategy(RepositoryDetectionStrategies detectionStrategy) {\n\t\tthis.detectionStrategy = detectionStrategy;\n\t}\n\n\tpublic @Nullable MediaType getDefaultMediaType() {\n\t\treturn this.defaultMediaType;\n\t}\n\n\tpublic void setDefaultMediaType(@Nullable MediaType defaultMediaType) {\n\t\tthis.defaultMediaType = defaultMediaType;\n\t}\n\n\tpublic @Nullable Boolean getReturnBodyOnCreate() {\n\t\treturn this.returnBodyOnCreate;\n\t}\n\n\tpublic void setReturnBodyOnCreate(@Nullable Boolean returnBodyOnCreate) {\n\t\tthis.returnBodyOnCreate = returnBodyOnCreate;\n\t}\n\n\tpublic @Nullable Boolean getReturnBodyOnUpdate() {\n\t\treturn this.returnBodyOnUpdate;\n\t}\n\n\tpublic void setReturnBodyOnUpdate(@Nullable Boolean returnBodyOnUpdate) {\n\t\tthis.returnBodyOnUpdate = returnBodyOnUpdate;\n\t}\n\n\tpublic @Nullable Boolean getReturnBodyOnDelete() {\n\t\treturn this.returnBodyOnDelete;\n\t}\n\n\tpublic void setReturnBodyOnDelete(@Nullable Boolean returnBodyOnDelete) {\n\t\tthis.returnBodyOnDelete = returnBodyOnDelete;\n\t}\n\n\tpublic @Nullable Boolean getEnableEnumTranslation() {\n\t\treturn this.enableEnumTranslation;\n\t}\n\n\tpublic void setEnableEnumTranslation(@Nullable Boolean enableEnumTranslation) {\n\t\tthis.enableEnumTranslation = enableEnumTranslation;\n\t}\n\n\tpublic void applyTo(RepositoryRestConfiguration rest) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this::getBasePath).to(rest::setBasePath);\n\t\tmap.from(this::getDefaultPageSize).to(rest::setDefaultPageSize);\n\t\tmap.from(this::getMaxPageSize).to(rest::setMaxPageSize);\n\t\tmap.from(this::getPageParamName).to(rest::setPageParamName);\n\t\tmap.from(this::getLimitParamName).to(rest::setLimitParamName);\n\t\tmap.from(this::getSortParamName).to(rest::setSortParamName);\n\t\tmap.from(this::getDetectionStrategy).to(rest::setRepositoryDetectionStrategy);\n\t\tmap.from(this::getDefaultMediaType).to(rest::setDefaultMediaType);\n\t\tmap.from(this::getReturnBodyOnCreate).to(rest::setReturnBodyOnCreate);\n\t\tmap.from(this::getReturnBodyOnUpdate).to(rest::setReturnBodyOnUpdate);\n\t\tmap.from(this::getReturnBodyOnDelete).to(rest::setReturnBodyOnDelete);\n\t\tmap.from(this::getEnableEnumTranslation).to(rest::setEnableEnumTranslation);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/main/java/org/springframework/boot/data/rest/autoconfigure/SpringBootRepositoryRestConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.rest.autoconfigure;\n\nimport java.util.List;\n\nimport tools.jackson.databind.cfg.MapperBuilder;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.data.rest.core.config.RepositoryRestConfiguration;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\n\n/**\n * A {@code RepositoryRestConfigurer} that applies configuration items from the\n * {@code spring.data.rest} namespace to Spring Data REST. Also, if any\n * {@link JsonMapperBuilderCustomizer JsonMapperBuilderCustomizers} are available, they\n * are used to configure Spring Data REST's {@link JsonMapper JsonMappers}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@Order(0)\nclass SpringBootRepositoryRestConfigurer implements RepositoryRestConfigurer {\n\n\tprivate final List<JsonMapperBuilderCustomizer> jsonMapperBuilderCustomizers;\n\n\tprivate final DataRestProperties properties;\n\n\tSpringBootRepositoryRestConfigurer(List<JsonMapperBuilderCustomizer> jsonMapperBuilderCustomizers,\n\t\t\tDataRestProperties properties) {\n\t\tthis.jsonMapperBuilderCustomizers = jsonMapperBuilderCustomizers;\n\t\tthis.properties = properties;\n\t}\n\n\t@Override\n\tpublic void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {\n\t\tthis.properties.applyTo(config);\n\t}\n\n\t@Override\n\tpublic void configureJacksonObjectMapper(MapperBuilder<?, ?> mapperBuilder) {\n\t\tif (mapperBuilder instanceof JsonMapper.Builder jsonMapperBuilder) {\n\t\t\tthis.jsonMapperBuilderCustomizers.forEach((customizer) -> customizer.customize(jsonMapperBuilder));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/main/java/org/springframework/boot/data/rest/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data REST.\n */\n@NullMarked\npackage org.springframework.boot.data.rest.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.data.rest.autoconfigure.DataRestAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/test/java/org/springframework/boot/data/rest/autoconfigure/DataRestAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.rest.autoconfigure;\n\nimport java.net.URI;\nimport java.text.SimpleDateFormat;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.data.jpa.autoconfigure.DataJpaRepositoriesAutoConfiguration;\nimport org.springframework.boot.data.rest.domain.city.City;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.rest.core.config.RepositoryRestConfiguration;\nimport org.springframework.data.rest.core.mapping.RepositoryDetectionStrategy.RepositoryDetectionStrategies;\nimport org.springframework.data.rest.webmvc.BaseUri;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataRestAutoConfiguration}.\n *\n * @author Rob Winch\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass DataRestAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (getContext() != null) {\n\t\t\tgetContext().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultRepositoryConfiguration() {\n\t\tload(TestConfiguration.class);\n\t\tassertThat(getContext().getBean(RepositoryRestMvcConfiguration.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid testWithCustomBasePath() {\n\t\tload(TestConfiguration.class, \"spring.data.rest.base-path:foo\");\n\t\tassertThat(getContext().getBean(RepositoryRestMvcConfiguration.class)).isNotNull();\n\t\tRepositoryRestConfiguration bean = getContext().getBean(RepositoryRestConfiguration.class);\n\t\tURI expectedUri = URI.create(\"/foo\");\n\t\tassertThat(bean.getBasePath()).as(\"Custom basePath not set\").isEqualTo(expectedUri);\n\t\tBaseUri baseUri = getContext().getBean(BaseUri.class);\n\t\tassertThat(expectedUri).as(\"Custom basePath has not been applied to BaseUri bean\").isEqualTo(baseUri.getUri());\n\t}\n\n\t@Test\n\tvoid testWithCustomSettings() {\n\t\tload(TestConfiguration.class, \"spring.data.rest.default-page-size:42\", \"spring.data.rest.max-page-size:78\",\n\t\t\t\t\"spring.data.rest.page-param-name:_page\", \"spring.data.rest.limit-param-name:_limit\",\n\t\t\t\t\"spring.data.rest.sort-param-name:_sort\", \"spring.data.rest.detection-strategy=visibility\",\n\t\t\t\t\"spring.data.rest.default-media-type:application/my-json\",\n\t\t\t\t\"spring.data.rest.return-body-on-create:false\", \"spring.data.rest.return-body-on-update:false\",\n\t\t\t\t\"spring.data.rest.return-body-on-delete:false\", \"spring.data.rest.enable-enum-translation:true\");\n\t\tassertThat(getContext().getBean(RepositoryRestMvcConfiguration.class)).isNotNull();\n\t\tRepositoryRestConfiguration bean = getContext().getBean(RepositoryRestConfiguration.class);\n\t\tassertThat(bean.getDefaultPageSize()).isEqualTo(42);\n\t\tassertThat(bean.getMaxPageSize()).isEqualTo(78);\n\t\tassertThat(bean.getPageParamName()).isEqualTo(\"_page\");\n\t\tassertThat(bean.getLimitParamName()).isEqualTo(\"_limit\");\n\t\tassertThat(bean.getSortParamName()).isEqualTo(\"_sort\");\n\t\tassertThat(bean.getRepositoryDetectionStrategy()).isEqualTo(RepositoryDetectionStrategies.VISIBILITY);\n\t\tassertThat(bean.getDefaultMediaType()).isEqualTo(MediaType.parseMediaType(\"application/my-json\"));\n\t\tassertReturnBody(bean);\n\t\tassertThat(bean.isEnableEnumTranslation()).isTrue();\n\t}\n\n\tprivate void assertReturnBody(RepositoryRestConfiguration bean) {\n\t\tassertThat(bean.returnBodyOnCreate(null)).isFalse();\n\t\tassertThat(bean.returnBodyOnUpdate(null)).isFalse();\n\t\tassertThat(bean.returnBodyOnDelete(null)).isFalse();\n\t}\n\n\t@Test\n\tvoid testWithCustomConfigurer() {\n\t\tload(TestConfigurationWithConfigurer.class, \"spring.data.rest.detection-strategy=visibility\",\n\t\t\t\t\"spring.data.rest.default-media-type:application/my-json\");\n\t\tassertThat(getContext().getBean(RepositoryRestMvcConfiguration.class)).isNotNull();\n\t\tRepositoryRestConfiguration bean = getContext().getBean(RepositoryRestConfiguration.class);\n\t\tassertThat(bean.getRepositoryDetectionStrategy()).isEqualTo(RepositoryDetectionStrategies.ALL);\n\t\tassertThat(bean.getDefaultMediaType()).isEqualTo(MediaType.parseMediaType(\"application/my-custom-json\"));\n\t\tassertThat(bean.getMaxPageSize()).isEqualTo(78);\n\t}\n\n\t@Test\n\tvoid backOffWithCustomConfiguration() {\n\t\tload(TestConfigurationWithRestMvcConfig.class, \"spring.data.rest.base-path:foo\");\n\t\tassertThat(getContext().getBean(RepositoryRestMvcConfiguration.class)).isNotNull();\n\t\tRepositoryRestConfiguration bean = getContext().getBean(RepositoryRestConfiguration.class);\n\t\tassertThat(bean.getBasePath()).isEqualTo(URI.create(\"\"));\n\t}\n\n\tprivate void load(Class<?> config, String... environment) {\n\t\tAnnotationConfigServletWebApplicationContext applicationContext = new AnnotationConfigServletWebApplicationContext();\n\t\tapplicationContext.setServletContext(new MockServletContext());\n\t\tapplicationContext.register(config, BaseConfiguration.class);\n\t\tTestPropertyValues.of(environment).applyTo(applicationContext);\n\t\tapplicationContext.refresh();\n\t\tthis.context = applicationContext;\n\t}\n\n\tprivate AnnotationConfigServletWebApplicationContext getContext() {\n\t\tAnnotationConfigServletWebApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\t@ImportAutoConfiguration({ HibernateJpaAutoConfiguration.class, DataJpaRepositoriesAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class, DataRestAutoConfiguration.class,\n\t\t\tJacksonAutoConfiguration.class })\n\tstatic class BaseConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableWebMvc\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Import({ TestConfiguration.class, TestRepositoryRestConfigurer.class })\n\tstatic class TestConfigurationWithConfigurer {\n\n\t}\n\n\t@Import({ TestConfiguration.class, RepositoryRestMvcConfiguration.class })\n\tstatic class TestConfigurationWithRestMvcConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@EnableWebMvc\n\tstatic class TestConfigurationWithJsonMapperBuilder {\n\n\t\t@Bean\n\t\tJsonMapper.Builder jsonMapperBuilder() {\n\t\t\treturn JsonMapper.builder().defaultDateFormat(new SimpleDateFormat(\"yyyy-MM\"));\n\t\t}\n\n\t}\n\n\tstatic class TestRepositoryRestConfigurer implements RepositoryRestConfigurer {\n\n\t\t@Override\n\t\tpublic void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {\n\t\t\tconfig.setRepositoryDetectionStrategy(RepositoryDetectionStrategies.ALL);\n\t\t\tconfig.setDefaultMediaType(MediaType.parseMediaType(\"application/my-custom-json\"));\n\t\t\tconfig.setMaxPageSize(78);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/test/java/org/springframework/boot/data/rest/domain/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.rest.domain.city;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n@Entity\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/test/java/org/springframework/boot/data/rest/domain/city/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.data.rest.domain.city;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.jpa.repository.JpaRepository;\n\npublic interface CityRepository extends JpaRepository<City, Long> {\n\n\t@Override\n\tPage<City> findAll(Pageable pageable);\n\n\tPage<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(String name, String country);\n\n}\n"
  },
  {
    "path": "module/spring-boot-data-rest/src/test/java/org/springframework/boot/data/rest/domain/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.data.rest.domain.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.integration-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Developer Tools\"\n\nconfigurations {\n\tintTestDependencies {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":core:spring-boot-autoconfigure\"))\n\n\tintTestDependencies(project(\":core:spring-boot-autoconfigure\"))\n\tintTestDependencies(project(\":module:spring-boot-http-converter\"))\n\tintTestDependencies(project(\":module:spring-boot-tomcat\"))\n\tintTestDependencies(project(\":module:spring-boot-jackson\"))\n\tintTestDependencies(project(\":module:spring-boot-webmvc\"))\n\tintTestDependencies(\"ch.qos.logback:logback-classic\")\n\tintTestDependencies(\"jakarta.annotation:jakarta.annotation-api\")\n\tintTestDependencies(\"org.apache.logging.log4j:log4j-to-slf4j\")\n\tintTestDependencies(\"org.slf4j:jul-to-slf4j\")\n\n\tintTestImplementation(project(\":core:spring-boot-autoconfigure\"))\n\tintTestImplementation(project(\":core:spring-boot-test\"))\n\tintTestImplementation(project(\":module:spring-boot-restclient\"))\n\tintTestImplementation(project(\":module:spring-boot-resttestclient\"))\n\tintTestImplementation(project(\":test-support:spring-boot-test-support\"))\n\tintTestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\tintTestImplementation(\"net.bytebuddy:byte-buddy\")\n\n\tintTestRuntimeOnly(\"org.springframework:spring-web\")\n\n\toptional(project(\":module:spring-boot-jdbc\"))\n\toptional(project(\":module:spring-boot-jpa\"))\n\toptional(project(\":module:spring-boot-r2dbc\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(project(\":module:spring-boot-security\"))\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"io.r2dbc:r2dbc-spi\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.apache.derby:derbytools\")\n\toptional(\"org.hibernate.orm:hibernate-core\")\n\toptional(\"org.springframework:spring-jdbc\")\n\toptional(\"org.springframework:spring-orm\")\n\toptional(\"org.springframework:spring-web\")\n\toptional(\"org.springframework.security:spring-security-config\")\n\toptional(\"org.springframework.security:spring-security-web\")\n\toptional(\"org.springframework.data:spring-data-redis\")\n\toptional(\"org.springframework.session:spring-session-core\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-freemarker\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-r2dbc\")))\n\ttestImplementation(\"ch.qos.logback:logback-classic\")\n\ttestImplementation(\"com.h2database:h2\")\n\ttestImplementation(\"com.zaxxer:HikariCP\")\n\ttestImplementation(\"org.apache.derby:derby\")\n\ttestImplementation(\"org.apache.derby:derbyclient\")\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-websocket\")\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-core\")\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\ttestImplementation(\"org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jakarta-client\")\n\ttestImplementation(\"org.hsqldb:hsqldb\")\n\ttestImplementation(\"org.postgresql:postgresql\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\ttestImplementation(\"org.springframework:spring-websocket\")\n\ttestImplementation(\"org.springframework.hateoas:spring-hateoas\")\n\ttestImplementation(\"org.springframework.security:spring-security-test\")\n\n\ttestRuntimeOnly(\"org.aspectj:aspectjweaver\")\n\ttestRuntimeOnly(\"org.yaml:snakeyaml\")\n\ttestRuntimeOnly(\"io.r2dbc:r2dbc-h2\")\n}\n\ntasks.register(\"syncIntTestDependencies\", Sync) {\n\tdestinationDir = file(layout.buildDirectory.dir(\"dependencies\"))\n\tfrom {\n\t\tconfigurations.intTestDependencies\n\t}\n\tfrom jar\n}\n\nintTest {\n\tdependsOn syncIntTestDependencies\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileIntTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/com/example/ControllerOne.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class ControllerOne {\n\n\t@RequestMapping(\"/one\")\n\tpublic String one() {\n\t\treturn \"one\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/com/example/DevToolsTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.server.context.WebServerPortFileWriter;\n\n@SpringBootApplication\nclass DevToolsTestApplication {\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(DevToolsTestApplication.class).listeners(new WebServerPortFileWriter(args[0]))\n\t\t\t.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/com/example/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage com.example;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/AbstractApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.springframework.util.FileSystemUtils;\n\n/**\n * Base class for all {@link ApplicationLauncher} implementations.\n *\n * @author Andy Wilkinson\n */\nabstract class AbstractApplicationLauncher implements ApplicationLauncher {\n\n\tprivate final Directories directories;\n\n\tAbstractApplicationLauncher(Directories directories) {\n\t\tthis.directories = directories;\n\t}\n\n\tprotected final void copyApplicationTo(File location) throws IOException {\n\t\tFileSystemUtils.deleteRecursively(location);\n\t\tlocation.mkdirs();\n\t\tFileSystemUtils.copyRecursively(new File(this.directories.getTestClassesDirectory(), \"com\"),\n\t\t\t\tnew File(location, \"com\"));\n\t}\n\n\tprotected final List<String> getDependencyJarPaths() {\n\t\treturn Stream.of(this.directories.getDependenciesDirectory().listFiles()).map(File::getAbsolutePath).toList();\n\t}\n\n\tprotected final Directories getDirectories() {\n\t\treturn this.directories;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/AbstractDevToolsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport net.bytebuddy.ByteBuddy;\nimport net.bytebuddy.description.annotation.AnnotationDescription;\nimport net.bytebuddy.description.modifier.Visibility;\nimport net.bytebuddy.dynamic.DynamicType;\nimport net.bytebuddy.implementation.FixedValue;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.extension.RegisterExtension;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.util.Assert;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Base class for DevTools integration tests.\n *\n * @author Andy Wilkinson\n */\nabstract class AbstractDevToolsIntegrationTests {\n\n\tprotected static final BuildOutput buildOutput = new BuildOutput(AbstractDevToolsIntegrationTests.class);\n\n\tprotected final File serverPortFile = new File(buildOutput.getRootLocation(), \"server.port\");\n\n\t@RegisterExtension\n\tprotected final JvmLauncher javaLauncher = new JvmLauncher();\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprotected static File temp;\n\n\tprivate @Nullable LaunchedApplication launchedApplication;\n\n\tprotected LaunchedApplication launchApplication(ApplicationLauncher applicationLauncher, String... args)\n\t\t\tthrows Exception {\n\t\tthis.serverPortFile.delete();\n\t\tthis.launchedApplication = applicationLauncher.launchApplication(this.javaLauncher, this.serverPortFile, args);\n\t\treturn this.launchedApplication;\n\t}\n\n\t@AfterEach\n\tvoid stopApplication() throws InterruptedException {\n\t\tAssert.notNull(this.launchedApplication, \"Application has not been launched\");\n\t\tthis.launchedApplication.stop();\n\t}\n\n\tprotected int awaitServerPort() throws Exception {\n\t\tLaunchedApplication launchedApplication = this.launchedApplication;\n\t\tAssert.notNull(launchedApplication, \"Application has not been launched\");\n\t\tint port = Awaitility.waitAtMost(Duration.ofMinutes(3))\n\t\t\t.until(() -> new ApplicationState(this.serverPortFile, launchedApplication),\n\t\t\t\t\tApplicationState::hasServerPort)\n\t\t\t.getServerPort();\n\t\tthis.serverPortFile.delete();\n\t\tlaunchedApplication.restartRemote(port);\n\t\tThread.sleep(1000);\n\t\treturn port;\n\t}\n\n\tprotected ControllerBuilder controller(String name) {\n\t\tAssert.notNull(this.launchedApplication, \"Application has not been launched\");\n\t\treturn new ControllerBuilder(name, this.launchedApplication.getClassesDirectory());\n\t}\n\n\tprotected static final class ControllerBuilder {\n\n\t\tprivate final List<String> mappings = new ArrayList<>();\n\n\t\tprivate final String name;\n\n\t\tprivate final File classesDirectory;\n\n\t\tprotected ControllerBuilder(String name, File classesDirectory) {\n\t\t\tthis.name = name;\n\t\t\tthis.classesDirectory = classesDirectory;\n\t\t}\n\n\t\tprotected ControllerBuilder withRequestMapping(String mapping) {\n\t\t\tthis.mappings.add(mapping);\n\t\t\treturn this;\n\t\t}\n\n\t\tprotected void build() throws Exception {\n\t\t\tDynamicType.Builder<Object> builder = new ByteBuddy().subclass(Object.class)\n\t\t\t\t.name(this.name)\n\t\t\t\t.annotateType(AnnotationDescription.Builder.ofType(RestController.class).build());\n\t\t\tfor (String mapping : this.mappings) {\n\t\t\t\tbuilder = builder.defineMethod(mapping, String.class, Visibility.PUBLIC)\n\t\t\t\t\t.intercept(FixedValue.value(mapping))\n\t\t\t\t\t.annotateMethod(AnnotationDescription.Builder.ofType(RequestMapping.class)\n\t\t\t\t\t\t.defineArray(\"value\", mapping)\n\t\t\t\t\t\t.build());\n\t\t\t}\n\t\t\tbuilder.make().saveIn(this.classesDirectory);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/ApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\n\n/**\n * Launches an application with DevTools.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\npublic interface ApplicationLauncher {\n\n\tLaunchedApplication launchApplication(JvmLauncher javaLauncher, File serverPortFile) throws Exception;\n\n\tLaunchedApplication launchApplication(JvmLauncher jvmLauncher, File serverPortFile, String... additionalArgs)\n\t\t\tthrows Exception;\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/ApplicationState.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.time.Instant;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.tests.JvmLauncher.LaunchedJvm;\nimport org.springframework.util.Assert;\n\n/**\n * State of an application.\n *\n * @author Andy Wilkinson\n */\nfinal class ApplicationState {\n\n\tprivate final Instant launchTime;\n\n\tprivate final @Nullable Integer serverPort;\n\n\tprivate final FileContents out;\n\n\tprivate final FileContents err;\n\n\tApplicationState(File serverPortFile, LaunchedJvm jvm) {\n\t\tthis(serverPortFile, jvm.getStandardOut(), jvm.getStandardError(), jvm.getLaunchTime());\n\t}\n\n\tApplicationState(File serverPortFile, LaunchedApplication application) {\n\t\tthis(serverPortFile, application.getStandardOut(), application.getStandardError(), application.getLaunchTime());\n\t}\n\n\tprivate ApplicationState(File serverPortFile, File out, File err, Instant launchTime) {\n\t\tthis.serverPort = new FileContents(serverPortFile).get(Integer::parseInt);\n\t\tthis.out = new FileContents(out);\n\t\tthis.err = new FileContents(err);\n\t\tthis.launchTime = launchTime;\n\t}\n\n\tboolean hasServerPort() {\n\t\treturn this.serverPort != null;\n\t}\n\n\tint getServerPort() {\n\t\tAssert.notNull(this.serverPort, \"No server port is available\");\n\t\treturn this.serverPort;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn String.format(\"Application launched at %s produced output:%n%s%n%s\", this.launchTime, this.out,\n\t\t\t\tthis.err);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/DevToolsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.core5.util.TimeValue;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for DevTools.\n *\n * @author Andy Wilkinson\n */\nclass DevToolsIntegrationTests extends AbstractDevToolsIntegrationTests {\n\n\tprivate final TestRestTemplate template = new TestRestTemplate(new RestTemplateBuilder()\n\t\t.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(HttpClients.custom()\n\t\t\t.setRetryStrategy(new DefaultHttpRequestRetryStrategy(10, TimeValue.of(1, TimeUnit.SECONDS)))\n\t\t\t.build())));\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid addARequestMappingToAnExistingController(ApplicationLauncher applicationLauncher) throws Exception {\n\t\tlaunchApplication(applicationLauncher, \"--logging.level.org.springframework.boot=trace\");\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\tcontroller(\"com.example.ControllerOne\").withRequestMapping(\"one\").withRequestMapping(\"two\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid removeARequestMappingFromAnExistingController(ApplicationLauncher applicationLauncher) throws Exception {\n\t\tlaunchApplication(applicationLauncher);\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tcontroller(\"com.example.ControllerOne\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForEntity(urlBase + \"/one\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid createAController(ApplicationLauncher applicationLauncher) throws Exception {\n\t\tlaunchApplication(applicationLauncher);\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\tcontroller(\"com.example.ControllerTwo\").withRequestMapping(\"two\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid createAControllerAndThenAddARequestMapping(ApplicationLauncher applicationLauncher) throws Exception {\n\t\tlaunchApplication(applicationLauncher);\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\tcontroller(\"com.example.ControllerTwo\").withRequestMapping(\"two\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\t\tcontroller(\"com.example.ControllerTwo\").withRequestMapping(\"two\").withRequestMapping(\"three\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/three\", String.class)).isEqualTo(\"three\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid createAControllerAndThenAddARequestMappingToAnExistingController(ApplicationLauncher applicationLauncher)\n\t\t\tthrows Exception {\n\t\tlaunchApplication(applicationLauncher);\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\tcontroller(\"com.example.ControllerTwo\").withRequestMapping(\"two\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\t\tcontroller(\"com.example.ControllerOne\").withRequestMapping(\"one\").withRequestMapping(\"three\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/three\", String.class)).isEqualTo(\"three\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid deleteAController(ApplicationLauncher applicationLauncher) throws Exception {\n\t\tLaunchedApplication launchedApplication = launchApplication(applicationLauncher);\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(new File(launchedApplication.getClassesDirectory(), \"com/example/ControllerOne.class\").delete())\n\t\t\t.isTrue();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForEntity(urlBase + \"/one\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid createAControllerAndThenDeleteIt(ApplicationLauncher applicationLauncher) throws Exception {\n\t\tLaunchedApplication launchedApplication = launchApplication(applicationLauncher);\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\tcontroller(\"com.example.ControllerTwo\").withRequestMapping(\"two\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(this.template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\t\tassertThat(new File(launchedApplication.getClassesDirectory(), \"com/example/ControllerTwo.class\").delete())\n\t\t\t.isTrue();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(this.template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\tstatic Object[] parameters() {\n\t\tDirectories directories = new Directories(buildOutput, temp);\n\t\treturn new Object[] { new Object[] { new LocalApplicationLauncher(directories) },\n\t\t\t\tnew Object[] { new ExplodedRemoteApplicationLauncher(directories) },\n\t\t\t\tnew Object[] { new JarFileRemoteApplicationLauncher(directories) } };\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/DevToolsWithLazyInitializationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.http.HttpStatus;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for DevTools with lazy initialization enabled.\n *\n * @author Madhura Bhave\n */\nclass DevToolsWithLazyInitializationIntegrationTests extends AbstractDevToolsIntegrationTests {\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"parameters\")\n\tvoid addARequestMappingToAnExistingControllerWhenLazyInit(ApplicationLauncher applicationLauncher)\n\t\t\tthrows Exception {\n\t\tlaunchApplication(applicationLauncher, \"--spring.main.lazy-initialization=true\");\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\tString urlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(template.getForEntity(urlBase + \"/two\", String.class).getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\tcontroller(\"com.example.ControllerOne\").withRequestMapping(\"one\").withRequestMapping(\"two\").build();\n\t\turlBase = \"http://localhost:\" + awaitServerPort();\n\t\tassertThat(template.getForObject(urlBase + \"/one\", String.class)).isEqualTo(\"one\");\n\t\tassertThat(template.getForObject(urlBase + \"/two\", String.class)).isEqualTo(\"two\");\n\t}\n\n\tstatic Object[] parameters() {\n\t\tDirectories directories = new Directories(buildOutput, temp);\n\t\treturn new Object[] { new Object[] { new LocalApplicationLauncher(directories) },\n\t\t\t\tnew Object[] { new ExplodedRemoteApplicationLauncher(directories) },\n\t\t\t\tnew Object[] { new JarFileRemoteApplicationLauncher(directories) } };\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/Directories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\n\nimport org.springframework.boot.testsupport.BuildOutput;\n\n/**\n * Various directories used by the {@link ApplicationLauncher ApplicationLaunchers}.\n *\n * @author Andy Wilkinson\n */\nclass Directories {\n\n\tprivate final BuildOutput buildOutput;\n\n\tprivate final File temp;\n\n\tDirectories(BuildOutput buildOutput, File temp) {\n\t\tthis.buildOutput = buildOutput;\n\t\tthis.temp = temp;\n\t}\n\n\tFile getTestClassesDirectory() {\n\t\treturn this.buildOutput.getTestClassesLocation();\n\t}\n\n\tFile getRemoteAppDirectory() {\n\t\treturn new File(this.temp, \"remote\");\n\t}\n\n\tFile getDependenciesDirectory() {\n\t\treturn new File(this.buildOutput.getRootLocation(), \"dependencies\");\n\t}\n\n\tFile getAppDirectory() {\n\t\treturn new File(this.temp, \"app\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/ExplodedRemoteApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationLauncher} that launches a remote application with its classes\n * available directly on the file system.\n *\n * @author Andy Wilkinson\n */\npublic class ExplodedRemoteApplicationLauncher extends RemoteApplicationLauncher {\n\n\tpublic ExplodedRemoteApplicationLauncher(Directories directories) {\n\t\tsuper(directories);\n\t}\n\n\t@Override\n\tprotected String createApplicationClassPath() throws Exception {\n\t\tFile appDirectory = getDirectories().getAppDirectory();\n\t\tcopyApplicationTo(appDirectory);\n\t\tList<String> entries = new ArrayList<>();\n\t\tentries.add(appDirectory.getAbsolutePath());\n\t\tentries.addAll(getDependencyJarPaths());\n\t\treturn StringUtils.collectionToDelimitedString(entries, File.pathSeparator);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"exploded remote\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/FileContents.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * Provides access to the contents of a file.\n *\n * @author Andy Wilkinson\n */\nclass FileContents {\n\n\tprivate final File file;\n\n\tFileContents(File file) {\n\t\tthis.file = file;\n\t}\n\n\t@Nullable String get() {\n\t\treturn get(Function.identity());\n\t}\n\n\t<T> @Nullable T get(Function<String, T> transformer) {\n\t\tif ((!this.file.exists()) || this.file.length() == 0) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn transformer.apply(FileCopyUtils.copyToString(new FileReader(this.file)));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable String toString() {\n\t\treturn get();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/JarFileRemoteApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\n\nimport org.springframework.util.StreamUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationLauncher} that launches a remote application with its classes in a\n * jar file.\n *\n * @author Andy Wilkinson\n */\npublic class JarFileRemoteApplicationLauncher extends RemoteApplicationLauncher {\n\n\tpublic JarFileRemoteApplicationLauncher(Directories directories) {\n\t\tsuper(directories);\n\t}\n\n\t@Override\n\tprotected String createApplicationClassPath() throws Exception {\n\t\tFile appDirectory = getDirectories().getAppDirectory();\n\t\tcopyApplicationTo(appDirectory);\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, \"1.0\");\n\t\tFile appJar = new File(appDirectory, \"app.jar\");\n\t\tJarOutputStream output = new JarOutputStream(new FileOutputStream(appJar), manifest);\n\t\taddToJar(output, appDirectory, appDirectory);\n\t\toutput.close();\n\t\tList<String> entries = new ArrayList<>();\n\t\tentries.add(appJar.getAbsolutePath());\n\t\tentries.addAll(getDependencyJarPaths());\n\t\treturn StringUtils.collectionToDelimitedString(entries, File.pathSeparator);\n\t}\n\n\tprivate void addToJar(JarOutputStream output, File root, File current) throws IOException {\n\t\tfor (File file : current.listFiles()) {\n\t\t\tif (file.isDirectory()) {\n\t\t\t\taddToJar(output, root, file);\n\t\t\t}\n\t\t\toutput.putNextEntry(new ZipEntry(\n\t\t\t\t\tfile.getAbsolutePath().substring(root.getAbsolutePath().length() + 1).replace(\"\\\\\", \"/\")\n\t\t\t\t\t\t\t+ (file.isDirectory() ? \"/\" : \"\")));\n\t\t\tif (file.isFile()) {\n\t\t\t\ttry (FileInputStream input = new FileInputStream(file)) {\n\t\t\t\t\tStreamUtils.copy(input, output);\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput.closeEntry();\n\t\t}\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"jar file remote\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/JvmLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.extension.BeforeTestExecutionCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Extension} that launches a JVM and redirects its output to a test\n * method-specific location.\n *\n * @author Andy Wilkinson\n */\nclass JvmLauncher implements BeforeTestExecutionCallback {\n\n\tprivate static final Pattern NON_ALPHABET_PATTERN = Pattern.compile(\"[^A-Za-z]+\");\n\n\tprivate final BuildOutput buildOutput = new BuildOutput(getClass());\n\n\tprivate @Nullable File outputDirectory;\n\n\t@Override\n\tpublic void beforeTestExecution(ExtensionContext context) throws Exception {\n\t\tthis.outputDirectory = new File(this.buildOutput.getRootLocation(),\n\t\t\t\t\"output/\" + NON_ALPHABET_PATTERN.matcher(context.getRequiredTestMethod().getName()).replaceAll(\"\"));\n\t\tthis.outputDirectory.mkdirs();\n\t}\n\n\tLaunchedJvm launch(String name, String classpath, String... args) throws IOException {\n\t\tList<String> command = new ArrayList<>(\n\t\t\t\tArrays.asList(System.getProperty(\"java.home\") + \"/bin/java\", \"-cp\", classpath));\n\t\tcommand.addAll(Arrays.asList(args));\n\t\tFile standardOut = new File(this.outputDirectory, name + \".out\");\n\t\tFile standardError = new File(this.outputDirectory, name + \".err\");\n\t\tProcess process = new ProcessBuilder(StringUtils.toStringArray(command)).redirectError(standardError)\n\t\t\t.redirectOutput(standardOut)\n\t\t\t.start();\n\t\treturn new LaunchedJvm(process, standardOut, standardError);\n\t}\n\n\tstatic class LaunchedJvm {\n\n\t\tprivate final Process process;\n\n\t\tprivate final Instant launchTime = Instant.now();\n\n\t\tprivate final File standardOut;\n\n\t\tprivate final File standardError;\n\n\t\tLaunchedJvm(Process process, File standardOut, File standardError) {\n\t\t\tthis.process = process;\n\t\t\tthis.standardOut = standardOut;\n\t\t\tthis.standardError = standardError;\n\t\t}\n\n\t\tProcess getProcess() {\n\t\t\treturn this.process;\n\t\t}\n\n\t\tInstant getLaunchTime() {\n\t\t\treturn this.launchTime;\n\t\t}\n\n\t\tFile getStandardOut() {\n\t\t\treturn this.standardOut;\n\t\t}\n\n\t\tFile getStandardError() {\n\t\t\treturn this.standardError;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/LaunchedApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.time.Instant;\nimport java.util.function.BiFunction;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * An application launched by {@link ApplicationLauncher}.\n *\n * @author Andy Wilkinson\n */\nclass LaunchedApplication {\n\n\tprivate final File classesDirectory;\n\n\tprivate final File standardOut;\n\n\tprivate final File standardError;\n\n\tprivate final Process localProcess;\n\n\tprivate @Nullable Process remoteProcess;\n\n\tprivate final Instant launchTime = Instant.now();\n\n\tprivate final @Nullable BiFunction<Integer, File, Process> remoteProcessRestarter;\n\n\tLaunchedApplication(File classesDirectory, File standardOut, File standardError, Process localProcess,\n\t\t\t@Nullable Process remoteProcess, @Nullable BiFunction<Integer, File, Process> remoteProcessRestarter) {\n\t\tthis.classesDirectory = classesDirectory;\n\t\tthis.standardOut = standardOut;\n\t\tthis.standardError = standardError;\n\t\tthis.localProcess = localProcess;\n\t\tthis.remoteProcess = remoteProcess;\n\t\tthis.remoteProcessRestarter = remoteProcessRestarter;\n\t}\n\n\tvoid restartRemote(int port) throws InterruptedException {\n\t\tif (this.remoteProcessRestarter != null) {\n\t\t\tstop(this.remoteProcess);\n\t\t\tthis.remoteProcess = this.remoteProcessRestarter.apply(port, this.classesDirectory);\n\t\t}\n\t}\n\n\tvoid stop() throws InterruptedException {\n\t\tstop(this.localProcess);\n\t\tstop(this.remoteProcess);\n\t}\n\n\tprivate void stop(@Nullable Process process) throws InterruptedException {\n\t\tif (process != null) {\n\t\t\tprocess.destroy();\n\t\t\tprocess.waitFor();\n\t\t}\n\t}\n\n\tFile getStandardOut() {\n\t\treturn this.standardOut;\n\t}\n\n\tFile getStandardError() {\n\t\treturn this.standardError;\n\t}\n\n\tFile getClassesDirectory() {\n\t\treturn this.classesDirectory;\n\t}\n\n\tInstant getLaunchTime() {\n\t\treturn this.launchTime;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/LocalApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.springframework.boot.devtools.tests.JvmLauncher.LaunchedJvm;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationLauncher} that launches a local application with DevTools enabled.\n *\n * @author Andy Wilkinson\n */\npublic class LocalApplicationLauncher extends AbstractApplicationLauncher {\n\n\tLocalApplicationLauncher(Directories directories) {\n\t\tsuper(directories);\n\t}\n\n\t@Override\n\tpublic LaunchedApplication launchApplication(JvmLauncher jvmLauncher, File serverPortFile) throws Exception {\n\t\tLaunchedJvm jvm = jvmLauncher.launch(\"local\", createApplicationClassPath(),\n\t\t\t\t\"com.example.DevToolsTestApplication\", serverPortFile.getAbsolutePath(), \"--server.port=0\");\n\t\treturn new LaunchedApplication(getDirectories().getAppDirectory(), jvm.getStandardOut(), jvm.getStandardError(),\n\t\t\t\tjvm.getProcess(), null, null);\n\t}\n\n\t@Override\n\tpublic LaunchedApplication launchApplication(JvmLauncher jvmLauncher, File serverPortFile, String... additionalArgs)\n\t\t\tthrows Exception {\n\t\tList<String> args = new ArrayList<>(Arrays.asList(\"com.example.DevToolsTestApplication\",\n\t\t\t\tserverPortFile.getAbsolutePath(), \"--server.port=0\"));\n\t\targs.addAll(Arrays.asList(additionalArgs));\n\t\tLaunchedJvm jvm = jvmLauncher.launch(\"local\", createApplicationClassPath(), args.toArray(new String[] {}));\n\t\treturn new LaunchedApplication(getDirectories().getAppDirectory(), jvm.getStandardOut(), jvm.getStandardError(),\n\t\t\t\tjvm.getProcess(), null, null);\n\t}\n\n\tprotected String createApplicationClassPath() throws Exception {\n\t\tFile appDirectory = getDirectories().getAppDirectory();\n\t\tcopyApplicationTo(appDirectory);\n\t\tList<String> entries = new ArrayList<>();\n\t\tentries.add(appDirectory.getAbsolutePath());\n\t\tentries.addAll(getDependencyJarPaths());\n\t\treturn StringUtils.collectionToDelimitedString(entries, File.pathSeparator);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"local\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/RemoteApplicationLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.tests;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.BiFunction;\n\nimport org.awaitility.Awaitility;\nimport org.awaitility.core.ConditionTimeoutException;\n\nimport org.springframework.boot.devtools.RemoteSpringApplication;\nimport org.springframework.boot.devtools.tests.JvmLauncher.LaunchedJvm;\nimport org.springframework.util.StringUtils;\n\nimport static org.hamcrest.Matchers.containsString;\n\n/**\n * Base class for {@link ApplicationLauncher} implementations that use\n * {@link RemoteSpringApplication}.\n *\n * @author Andy Wilkinson\n */\nabstract class RemoteApplicationLauncher extends AbstractApplicationLauncher {\n\n\tRemoteApplicationLauncher(Directories directories) {\n\t\tsuper(directories);\n\t}\n\n\t@Override\n\tpublic LaunchedApplication launchApplication(JvmLauncher javaLauncher, File serverPortFile) throws Exception {\n\t\tLaunchedJvm applicationJvm = javaLauncher.launch(\"app\", createApplicationClassPath(),\n\t\t\t\t\"com.example.DevToolsTestApplication\", serverPortFile.getAbsolutePath(), \"--server.port=0\",\n\t\t\t\t\"--spring.devtools.remote.secret=secret\");\n\t\tint port = awaitServerPort(applicationJvm, serverPortFile);\n\t\tBiFunction<Integer, File, Process> remoteRestarter = getRemoteRestarter(javaLauncher);\n\t\treturn new LaunchedApplication(getDirectories().getRemoteAppDirectory(), applicationJvm.getStandardOut(),\n\t\t\t\tapplicationJvm.getStandardError(), applicationJvm.getProcess(), remoteRestarter.apply(port, null),\n\t\t\t\tremoteRestarter);\n\t}\n\n\t@Override\n\tpublic LaunchedApplication launchApplication(JvmLauncher javaLauncher, File serverPortFile,\n\t\t\tString... additionalArgs) throws Exception {\n\t\tList<String> args = new ArrayList<>(Arrays.asList(\"com.example.DevToolsTestApplication\",\n\t\t\t\tserverPortFile.getAbsolutePath(), \"--server.port=0\", \"--spring.devtools.remote.secret=secret\"));\n\t\targs.addAll(Arrays.asList(additionalArgs));\n\t\tLaunchedJvm applicationJvm = javaLauncher.launch(\"app\", createApplicationClassPath(),\n\t\t\t\targs.toArray(new String[] {}));\n\t\tint port = awaitServerPort(applicationJvm, serverPortFile);\n\t\tBiFunction<Integer, File, Process> remoteRestarter = getRemoteRestarter(javaLauncher);\n\t\treturn new LaunchedApplication(getDirectories().getRemoteAppDirectory(), applicationJvm.getStandardOut(),\n\t\t\t\tapplicationJvm.getStandardError(), applicationJvm.getProcess(), remoteRestarter.apply(port, null),\n\t\t\t\tremoteRestarter);\n\t}\n\n\tprivate BiFunction<Integer, File, Process> getRemoteRestarter(JvmLauncher javaLauncher) {\n\t\treturn (port, classesDirectory) -> {\n\t\t\ttry {\n\t\t\t\tLaunchedJvm remoteSpringApplicationJvm = javaLauncher.launch(\"remote-spring-application\",\n\t\t\t\t\t\tcreateRemoteSpringApplicationClassPath(classesDirectory),\n\t\t\t\t\t\tRemoteSpringApplication.class.getName(), \"--spring.devtools.remote.secret=secret\",\n\t\t\t\t\t\t\"http://localhost:\" + port);\n\t\t\t\tawaitRemoteSpringApplication(remoteSpringApplicationJvm);\n\t\t\t\treturn remoteSpringApplicationJvm.getProcess();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t};\n\t}\n\n\tprotected abstract String createApplicationClassPath() throws Exception;\n\n\tprivate String createRemoteSpringApplicationClassPath(File classesDirectory) throws Exception {\n\t\tFile remoteAppDirectory = getDirectories().getRemoteAppDirectory();\n\t\tif (classesDirectory == null) {\n\t\t\tcopyApplicationTo(remoteAppDirectory);\n\t\t}\n\t\tList<String> entries = new ArrayList<>();\n\t\tentries.add(remoteAppDirectory.getAbsolutePath());\n\t\tentries.addAll(getDependencyJarPaths());\n\t\treturn StringUtils.collectionToDelimitedString(entries, File.pathSeparator);\n\t}\n\n\tprivate int awaitServerPort(LaunchedJvm jvm, File serverPortFile) {\n\t\treturn Awaitility.waitAtMost(Duration.ofMinutes(3))\n\t\t\t.until(() -> new ApplicationState(serverPortFile, jvm), ApplicationState::hasServerPort)\n\t\t\t.getServerPort();\n\t}\n\n\tprivate void awaitRemoteSpringApplication(LaunchedJvm launchedJvm) {\n\t\tFileContents contents = new FileContents(launchedJvm.getStandardOut());\n\t\ttry {\n\t\t\tAwaitility.waitAtMost(Duration.ofMinutes(3))\n\t\t\t\t.until(contents::get, containsString(\"Started RemoteSpringApplication\"));\n\t\t}\n\t\tcatch (ConditionTimeoutException ex) {\n\t\t\tif (!launchedJvm.getProcess().isAlive()) {\n\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\"Process exited with status \" + launchedJvm.getProcess().exitValue()\n\t\t\t\t\t\t\t\t+ \" before producing expected standard output.\\n\\nStandard output:\\n\\n\" + contents.get()\n\t\t\t\t\t\t\t\t+ \"\\n\\nStandard error:\\n\\n\" + new FileContents(launchedJvm.getStandardError()).get(),\n\t\t\t\t\t\tex);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/intTest/java/org/springframework/boot/devtools/tests/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.devtools.tests;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/RemoteSpringApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.springframework.boot.Banner;\nimport org.springframework.boot.ResourceBanner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor;\nimport org.springframework.boot.context.logging.LoggingApplicationListener;\nimport org.springframework.boot.devtools.remote.client.RemoteClientConfiguration;\nimport org.springframework.boot.devtools.restart.RestartInitializer;\nimport org.springframework.boot.devtools.restart.RestartScopeInitializer;\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.boot.support.AnsiOutputApplicationListener;\nimport org.springframework.boot.support.EnvironmentPostProcessorApplicationListener;\nimport org.springframework.boot.support.EnvironmentPostProcessorsFactory;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.io.ClassPathResource;\n\n/**\n * Application that can be used to establish a link to remotely running Spring Boot code.\n * Allows remote updates (if enabled). This class should be launched from within your IDE\n * and should have the same classpath configuration as the locally developed application.\n * The remote URL of the application should be provided as a non-option argument.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see RemoteClientConfiguration\n */\npublic final class RemoteSpringApplication {\n\n\tprivate RemoteSpringApplication() {\n\t}\n\n\tprivate void run(String[] args) {\n\t\tRestarter.initialize(args, RestartInitializer.NONE);\n\t\tSpringApplication application = new SpringApplication(RemoteClientConfiguration.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setBanner(getBanner());\n\t\tapplication.setInitializers(getInitializers());\n\t\tapplication.setListeners(getListeners());\n\t\tapplication.run(args);\n\t\twaitIndefinitely();\n\t}\n\n\tprivate Collection<ApplicationContextInitializer<?>> getInitializers() {\n\t\tList<ApplicationContextInitializer<?>> initializers = new ArrayList<>();\n\t\tinitializers.add(new RestartScopeInitializer());\n\t\treturn initializers;\n\t}\n\n\tprivate Collection<ApplicationListener<?>> getListeners() {\n\t\tList<ApplicationListener<?>> listeners = new ArrayList<>();\n\t\tlisteners.add(new AnsiOutputApplicationListener());\n\t\tlisteners.add(EnvironmentPostProcessorApplicationListener\n\t\t\t.with(EnvironmentPostProcessorsFactory.of(ConfigDataEnvironmentPostProcessor.class)));\n\t\tlisteners.add(new LoggingApplicationListener());\n\t\tlisteners.add(new RemoteUrlPropertyExtractor());\n\t\treturn listeners;\n\t}\n\n\tprivate Banner getBanner() {\n\t\tClassPathResource banner = new ClassPathResource(\"remote-banner.txt\", RemoteSpringApplication.class);\n\t\treturn new ResourceBanner(banner);\n\t}\n\n\tprivate void waitIndefinitely() {\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Run the {@link RemoteSpringApplication}.\n\t * @param args the program arguments (including the remote URL as a non-option\n\t * argument)\n\t */\n\tpublic static void main(String[] args) {\n\t\tnew RemoteSpringApplication().run(args);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/RemoteUrlPropertyExtractor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.CommandLinePropertySource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationListener} to extract the remote URL for the\n * {@link RemoteSpringApplication} to use.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass RemoteUrlPropertyExtractor implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {\n\n\tprivate static final String NON_OPTION_ARGS = CommandLinePropertySource.DEFAULT_NON_OPTION_ARGS_PROPERTY_NAME;\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {\n\t\tConfigurableEnvironment environment = event.getEnvironment();\n\t\tString url = cleanRemoteUrl(environment.getProperty(NON_OPTION_ARGS));\n\t\tAssert.state(StringUtils.hasLength(url), \"No remote URL specified\");\n\t\tAssert.state(url.indexOf(',') == -1, \"Multiple URLs specified\");\n\t\ttry {\n\t\t\tnew URI(url);\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(\"Malformed URL '\" + url + \"'\");\n\t\t}\n\t\tMap<String, Object> source = Collections.singletonMap(\"remoteUrl\", url);\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"remoteUrl\", source);\n\t\tenvironment.getPropertySources().addLast(propertySource);\n\t}\n\n\tprivate @Nullable String cleanRemoteUrl(@Nullable String url) {\n\t\tif (StringUtils.hasText(url) && url.endsWith(\"/\")) {\n\t\t\treturn url.substring(0, url.length() - 1);\n\t\t}\n\t\treturn url;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/ConditionEvaluationDeltaLoggingListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.util.Assert;\n\n/**\n * An {@link ApplicationListener} that logs the delta of condition evaluation across\n * restarts.\n *\n * @author Andy Wilkinson\n */\nclass ConditionEvaluationDeltaLoggingListener\n\t\timplements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {\n\n\tprivate static final ConcurrentHashMap<String, ConditionEvaluationReport> previousReports = new ConcurrentHashMap<>();\n\n\tprivate static final Log logger = LogFactory.getLog(ConditionEvaluationDeltaLoggingListener.class);\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate volatile ApplicationContext context;\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationReadyEvent event) {\n\t\tif (!event.getApplicationContext().equals(this.context)) {\n\t\t\treturn;\n\t\t}\n\t\tConditionEvaluationReport report = event.getApplicationContext().getBean(ConditionEvaluationReport.class);\n\t\tString contextId = event.getApplicationContext().getId();\n\t\tConditionEvaluationReport previousReport = previousReports.get(contextId);\n\t\tif (previousReport != null) {\n\t\t\tConditionEvaluationReport delta = report.getDelta(previousReport);\n\t\t\tif (!delta.getConditionAndOutcomesBySource().isEmpty() || !delta.getExclusions().isEmpty()\n\t\t\t\t\t|| !delta.getUnconditionalClasses().isEmpty()) {\n\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\tlogger.info(\"Condition evaluation delta:\"\n\t\t\t\t\t\t\t+ new ConditionEvaluationReportMessage(delta, \"CONDITION EVALUATION DELTA\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Condition evaluation unchanged\");\n\t\t\t}\n\t\t}\n\t\tAssert.state(contextId != null, \"'contextId' must not be null\");\n\t\tpreviousReports.put(contextId, report);\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) {\n\t\tthis.context = applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/ConditionalOnEnabledDevTools.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when DevTools is enabled.\n *\n * @author Andy Wilkinson\n * @since 3.5.0\n */\n@SuppressWarnings(\"removal\")\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnEnabledDevToolsCondition.class)\npublic @interface ConditionalOnEnabledDevTools {\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.apache.derby.jdbc.EmbeddedDriver;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration.DatabaseShutdownExecutorEntityManagerFactoryDependsOnConfiguration;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration.DevToolsDataSourceCondition;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ConfigurationCondition;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for DevTools-specific\n * {@link DataSource} configuration.\n *\n * @author Andy Wilkinson\n * @since 1.3.3\n */\n@ConditionalOnClass(DataSource.class)\n@ConditionalOnEnabledDevTools\n@Conditional(DevToolsDataSourceCondition.class)\n@AutoConfiguration(afterName = \"org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\")\n@Import(DatabaseShutdownExecutorEntityManagerFactoryDependsOnConfiguration.class)\npublic final class DevToolsDataSourceAutoConfiguration {\n\n\t@Bean\n\tNonEmbeddedInMemoryDatabaseShutdownExecutor inMemoryDatabaseShutdownExecutor(DataSource dataSource,\n\t\t\tDataSourceProperties dataSourceProperties) {\n\t\treturn new NonEmbeddedInMemoryDatabaseShutdownExecutor(dataSource, dataSourceProperties);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ EntityManagerFactoryDependsOnPostProcessor.class,\n\t\t\tLocalContainerEntityManagerFactoryBean.class })\n\t@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)\n\t@Import(DatabaseShutdownExecutorEntityManagerFactoryDependsOnPostProcessor.class)\n\tstatic class DatabaseShutdownExecutorEntityManagerFactoryDependsOnConfiguration {\n\n\t}\n\n\t/**\n\t * Post processor to ensure that {@link jakarta.persistence.EntityManagerFactory}\n\t * beans depend on the {@code inMemoryDatabaseShutdownExecutor} bean.\n\t */\n\tstatic class DatabaseShutdownExecutorEntityManagerFactoryDependsOnPostProcessor\n\t\t\textends EntityManagerFactoryDependsOnPostProcessor {\n\n\t\tDatabaseShutdownExecutorEntityManagerFactoryDependsOnPostProcessor() {\n\t\t\tsuper(\"inMemoryDatabaseShutdownExecutor\");\n\t\t}\n\n\t}\n\n\tstatic final class NonEmbeddedInMemoryDatabaseShutdownExecutor implements DisposableBean {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprivate final DataSourceProperties dataSourceProperties;\n\n\t\tNonEmbeddedInMemoryDatabaseShutdownExecutor(DataSource dataSource, DataSourceProperties dataSourceProperties) {\n\t\t\tthis.dataSource = dataSource;\n\t\t\tthis.dataSourceProperties = dataSourceProperties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroy() throws Exception {\n\t\t\tfor (InMemoryDatabase inMemoryDatabase : InMemoryDatabase.values()) {\n\t\t\t\tif (inMemoryDatabase.matches(this.dataSourceProperties)) {\n\t\t\t\t\tinMemoryDatabase.shutdown(this.dataSource);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate enum InMemoryDatabase {\n\n\t\t\t/*\n\t\t\t * @deprecated since 4.1.0 for removal in 4.3.0 as Derby is EOL.\n\t\t\t */\n\t\t\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\t\t\tDERBY(null, Set.of(\"org.apache.derby.jdbc.EmbeddedDriver\"), (dataSource) -> {\n\t\t\t\tString url;\n\t\t\t\ttry (Connection connection = dataSource.getConnection()) {\n\t\t\t\t\turl = connection.getMetaData().getURL();\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tnew EmbeddedDriver().connect(url + \";drop=true\", new Properties()).close();\n\t\t\t\t}\n\t\t\t\tcatch (SQLException ex) {\n\t\t\t\t\tif (!\"08006\".equals(ex.getSQLState())) {\n\t\t\t\t\t\tthrow ex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}),\n\n\t\t\tH2(\"jdbc:h2:mem:\", Set.of(\"org.h2.Driver\", \"org.h2.jdbcx.JdbcDataSource\")),\n\n\t\t\tHSQLDB(\"jdbc:hsqldb:mem:\", Set.of(\"org.hsqldb.jdbcDriver\", \"org.hsqldb.jdbc.JDBCDriver\",\n\t\t\t\t\t\"org.hsqldb.jdbc.pool.JDBCXADataSource\"));\n\n\t\t\tprivate final @Nullable String urlPrefix;\n\n\t\t\tprivate final ShutdownHandler shutdownHandler;\n\n\t\t\tprivate final Set<String> driverClassNames;\n\n\t\t\tInMemoryDatabase(@Nullable String urlPrefix, Set<String> driverClassNames) {\n\t\t\t\tthis(urlPrefix, driverClassNames, (dataSource) -> {\n\t\t\t\t\ttry (Connection connection = dataSource.getConnection()) {\n\t\t\t\t\t\ttry (Statement statement = connection.createStatement()) {\n\t\t\t\t\t\t\tstatement.execute(\"SHUTDOWN\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tInMemoryDatabase(@Nullable String urlPrefix, Set<String> driverClassNames,\n\t\t\t\t\tShutdownHandler shutdownHandler) {\n\t\t\t\tthis.urlPrefix = urlPrefix;\n\t\t\t\tthis.driverClassNames = driverClassNames;\n\t\t\t\tthis.shutdownHandler = shutdownHandler;\n\t\t\t}\n\n\t\t\tboolean matches(DataSourceProperties properties) {\n\t\t\t\tString url = properties.getUrl();\n\t\t\t\treturn (url == null || this.urlPrefix == null || url.startsWith(this.urlPrefix))\n\t\t\t\t\t\t&& this.driverClassNames.contains(properties.determineDriverClassName());\n\t\t\t}\n\n\t\t\tvoid shutdown(DataSource dataSource) throws SQLException {\n\t\t\t\tthis.shutdownHandler.shutdown(dataSource);\n\t\t\t}\n\n\t\t\t@FunctionalInterface\n\t\t\tinterface ShutdownHandler {\n\n\t\t\t\tvoid shutdown(DataSource dataSource) throws SQLException;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class DevToolsDataSourceCondition extends SpringBootCondition implements ConfigurationCondition {\n\n\t\t@Override\n\t\tpublic ConfigurationPhase getConfigurationPhase() {\n\t\t\treturn ConfigurationPhase.REGISTER_BEAN;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"DevTools DataSource Condition\");\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\t\tString[] dataSourceBeanNames = beanFactory.getBeanNamesForType(DataSource.class, true, false);\n\t\t\tif (dataSourceBeanNames.length != 1) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"a single DataSource bean\").atAll());\n\t\t\t}\n\t\t\tif (beanFactory.getBeanNamesForType(DataSourceProperties.class, true, false).length != 1) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"a single DataSourceProperties bean\").atAll());\n\t\t\t}\n\t\t\tBeanDefinition dataSourceDefinition = context.getRegistry().getBeanDefinition(dataSourceBeanNames[0]);\n\t\t\tif (dataSourceDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition\n\t\t\t\t\t&& annotatedBeanDefinition.getFactoryMethodMetadata() != null\n\t\t\t\t\t&& annotatedBeanDefinition.getFactoryMethodMetadata()\n\t\t\t\t\t\t.getDeclaringClassName()\n\t\t\t\t\t\t.startsWith(DataSourceAutoConfiguration.class.getPackage().getName()\n\t\t\t\t\t\t\t\t+ \".DataSourceConfiguration$\")) {\n\t\t\t\treturn ConditionOutcome.match(message.foundExactly(\"auto-configured DataSource\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"an auto-configured DataSource\").atAll());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.DeprecatedConfigurationProperty;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration properties for developer tools.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 1.3.0\n */\n@ConfigurationProperties(\"spring.devtools\")\npublic class DevToolsProperties {\n\n\tprivate final Restart restart = new Restart();\n\n\tprivate final Livereload livereload = new Livereload();\n\n\t@NestedConfigurationProperty\n\tprivate final RemoteDevToolsProperties remote = new RemoteDevToolsProperties();\n\n\tpublic Restart getRestart() {\n\t\treturn this.restart;\n\t}\n\n\tpublic Livereload getLivereload() {\n\t\treturn this.livereload;\n\t}\n\n\tpublic RemoteDevToolsProperties getRemote() {\n\t\treturn this.remote;\n\t}\n\n\t/**\n\t * Restart properties.\n\t */\n\tpublic static class Restart {\n\n\t\tprivate static final String DEFAULT_RESTART_EXCLUDES = \"META-INF/maven/**,\"\n\t\t\t\t+ \"META-INF/resources/**,resources/**,static/**,public/**,templates/**,\"\n\t\t\t\t+ \"**/*Test.class,**/*Tests.class,git.properties,META-INF/build-info.properties\";\n\n\t\t/**\n\t\t * Whether to enable automatic restart.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\t/**\n\t\t * Patterns that should be excluded from triggering a full restart.\n\t\t */\n\t\tprivate String exclude = DEFAULT_RESTART_EXCLUDES;\n\n\t\t/**\n\t\t * Additional patterns that should be excluded from triggering a full restart.\n\t\t */\n\t\tprivate @Nullable String additionalExclude;\n\n\t\t/**\n\t\t * Amount of time to wait between polling for classpath changes.\n\t\t */\n\t\tprivate Duration pollInterval = Duration.ofSeconds(1);\n\n\t\t/**\n\t\t * Amount of quiet time required without any classpath changes before a restart is\n\t\t * triggered.\n\t\t */\n\t\tprivate Duration quietPeriod = Duration.ofMillis(400);\n\n\t\t/**\n\t\t * Name of a specific file that, when changed, triggers the restart check. Must be\n\t\t * a simple name (without any path) of a file that appears on your classpath. If\n\t\t * not specified, any classpath file change triggers the restart.\n\t\t */\n\t\tprivate @Nullable String triggerFile;\n\n\t\t/**\n\t\t * Additional paths to watch for changes.\n\t\t */\n\t\tprivate List<File> additionalPaths = new ArrayList<>();\n\n\t\t/**\n\t\t * Whether to log the condition evaluation delta upon restart.\n\t\t */\n\t\tprivate boolean logConditionEvaluationDelta = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic String[] getAllExclude() {\n\t\t\tList<String> allExclude = new ArrayList<>();\n\t\t\tif (StringUtils.hasText(this.exclude)) {\n\t\t\t\tallExclude.addAll(StringUtils.commaDelimitedListToSet(this.exclude));\n\t\t\t}\n\t\t\tif (StringUtils.hasText(this.additionalExclude)) {\n\t\t\t\tallExclude.addAll(StringUtils.commaDelimitedListToSet(this.additionalExclude));\n\t\t\t}\n\t\t\treturn StringUtils.toStringArray(allExclude);\n\t\t}\n\n\t\tpublic String getExclude() {\n\t\t\treturn this.exclude;\n\t\t}\n\n\t\tpublic void setExclude(String exclude) {\n\t\t\tthis.exclude = exclude;\n\t\t}\n\n\t\tpublic @Nullable String getAdditionalExclude() {\n\t\t\treturn this.additionalExclude;\n\t\t}\n\n\t\tpublic void setAdditionalExclude(@Nullable String additionalExclude) {\n\t\t\tthis.additionalExclude = additionalExclude;\n\t\t}\n\n\t\tpublic Duration getPollInterval() {\n\t\t\treturn this.pollInterval;\n\t\t}\n\n\t\tpublic void setPollInterval(Duration pollInterval) {\n\t\t\tthis.pollInterval = pollInterval;\n\t\t}\n\n\t\tpublic Duration getQuietPeriod() {\n\t\t\treturn this.quietPeriod;\n\t\t}\n\n\t\tpublic void setQuietPeriod(Duration quietPeriod) {\n\t\t\tthis.quietPeriod = quietPeriod;\n\t\t}\n\n\t\tpublic @Nullable String getTriggerFile() {\n\t\t\treturn this.triggerFile;\n\t\t}\n\n\t\tpublic void setTriggerFile(@Nullable String triggerFile) {\n\t\t\tthis.triggerFile = triggerFile;\n\t\t}\n\n\t\tpublic List<File> getAdditionalPaths() {\n\t\t\treturn this.additionalPaths;\n\t\t}\n\n\t\tpublic void setAdditionalPaths(List<File> additionalPaths) {\n\t\t\tthis.additionalPaths = additionalPaths;\n\t\t}\n\n\t\tpublic boolean isLogConditionEvaluationDelta() {\n\t\t\treturn this.logConditionEvaluationDelta;\n\t\t}\n\n\t\tpublic void setLogConditionEvaluationDelta(boolean logConditionEvaluationDelta) {\n\t\t\tthis.logConditionEvaluationDelta = logConditionEvaluationDelta;\n\t\t}\n\n\t}\n\n\t/**\n\t * LiveReload properties.\n\t */\n\tpublic static class Livereload {\n\n\t\t/**\n\t\t * Whether to enable a livereload.com-compatible server.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Server port.\n\t\t */\n\t\tprivate int port = 35729;\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Deprecated with no replacement\", since = \"4.1.0\")\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Deprecated with no replacement\", since = \"4.1.0\")\n\t\tpublic int getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tpublic void setPort(int port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.reactivestreams.Publisher;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsR2dbcAutoConfiguration.DevToolsConnectionFactoryCondition;\nimport org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.ConfigurationCondition;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for DevTools-specific R2DBC\n * configuration.\n *\n * @author Phillip Webb\n * @since 2.5.6\n */\n@ConditionalOnClass(ConnectionFactory.class)\n@ConditionalOnEnabledDevTools\n@Conditional(DevToolsConnectionFactoryCondition.class)\n@AutoConfiguration(afterName = \"org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration\")\npublic final class DevToolsR2dbcAutoConfiguration {\n\n\t@Bean\n\tInMemoryR2dbcDatabaseShutdownExecutor inMemoryR2dbcDatabaseShutdownExecutor(\n\t\t\tApplicationEventPublisher eventPublisher, ConnectionFactory connectionFactory) {\n\t\treturn new InMemoryR2dbcDatabaseShutdownExecutor(eventPublisher, connectionFactory);\n\t}\n\n\tfinal class InMemoryR2dbcDatabaseShutdownExecutor implements DisposableBean {\n\n\t\tprivate final ApplicationEventPublisher eventPublisher;\n\n\t\tprivate final ConnectionFactory connectionFactory;\n\n\t\tInMemoryR2dbcDatabaseShutdownExecutor(ApplicationEventPublisher eventPublisher,\n\t\t\t\tConnectionFactory connectionFactory) {\n\t\t\tthis.eventPublisher = eventPublisher;\n\t\t\tthis.connectionFactory = connectionFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroy() throws Exception {\n\t\t\tif (shouldShutdown()) {\n\t\t\t\tMono.usingWhen(this.connectionFactory.create(), this::executeShutdown, this::closeConnection,\n\t\t\t\t\t\tthis::closeConnection, this::closeConnection)\n\t\t\t\t\t.block();\n\t\t\t\tthis.eventPublisher.publishEvent(new R2dbcDatabaseShutdownEvent(this.connectionFactory));\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean shouldShutdown() {\n\t\t\ttry {\n\t\t\t\treturn EmbeddedDatabaseConnection.isEmbedded(this.connectionFactory);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tprivate Mono<?> executeShutdown(Connection connection) {\n\t\t\treturn Mono.from(connection.createStatement(\"SHUTDOWN\").execute());\n\t\t}\n\n\t\tprivate Publisher<Void> closeConnection(Connection connection) {\n\t\t\treturn closeConnection(connection, null);\n\t\t}\n\n\t\tprivate Publisher<Void> closeConnection(Connection connection, @Nullable Throwable ex) {\n\t\t\treturn connection.close();\n\t\t}\n\n\t}\n\n\tstatic class DevToolsConnectionFactoryCondition extends SpringBootCondition implements ConfigurationCondition {\n\n\t\t@Override\n\t\tpublic ConfigurationPhase getConfigurationPhase() {\n\t\t\treturn ConfigurationPhase.REGISTER_BEAN;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"DevTools ConnectionFactory Condition\");\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\t\tString[] beanNames = beanFactory.getBeanNamesForType(ConnectionFactory.class, true, false);\n\t\t\tif (beanNames.length != 1) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"a single ConnectionFactory bean\").atAll());\n\t\t\t}\n\t\t\tBeanDefinition beanDefinition = context.getRegistry().getBeanDefinition(beanNames[0]);\n\t\t\tif (beanDefinition instanceof AnnotatedBeanDefinition annotatedBeanDefinition\n\t\t\t\t\t&& isAutoConfigured(annotatedBeanDefinition)) {\n\t\t\t\treturn ConditionOutcome.match(message.foundExactly(\"auto-configured ConnectionFactory\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"an auto-configured ConnectionFactory\").atAll());\n\t\t}\n\n\t\tprivate boolean isAutoConfigured(AnnotatedBeanDefinition beanDefinition) {\n\t\t\tMethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();\n\t\t\treturn methodMetadata != null && methodMetadata.getDeclaringClassName()\n\t\t\t\t.startsWith(R2dbcAutoConfiguration.class.getPackage().getName());\n\t\t}\n\n\t}\n\n\tstatic class R2dbcDatabaseShutdownEvent {\n\n\t\tprivate final ConnectionFactory connectionFactory;\n\n\t\tR2dbcDatabaseShutdownEvent(ConnectionFactory connectionFactory) {\n\t\t\tthis.connectionFactory = connectionFactory;\n\t\t}\n\n\t\tConnectionFactory getConnectionFactory() {\n\t\t\treturn this.connectionFactory;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/FileWatchingFailureHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.springframework.boot.devtools.classpath.ClassPathDirectories;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.boot.devtools.filewatch.FileChangeListener;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory;\nimport org.springframework.boot.devtools.restart.FailureHandler;\nimport org.springframework.boot.devtools.restart.Restarter;\n\n/**\n * {@link FailureHandler} that waits for filesystem changes before retrying.\n *\n * @author Phillip Webb\n */\nclass FileWatchingFailureHandler implements FailureHandler {\n\n\tprivate final FileSystemWatcherFactory fileSystemWatcherFactory;\n\n\tFileWatchingFailureHandler(FileSystemWatcherFactory fileSystemWatcherFactory) {\n\t\tthis.fileSystemWatcherFactory = fileSystemWatcherFactory;\n\t}\n\n\t@Override\n\tpublic Outcome handle(Throwable failure) {\n\t\tCountDownLatch latch = new CountDownLatch(1);\n\t\tFileSystemWatcher watcher = this.fileSystemWatcherFactory.getFileSystemWatcher();\n\t\twatcher.addSourceDirectories(new ClassPathDirectories(Restarter.getInstance().getInitialUrls()));\n\t\twatcher.addListener(new Listener(latch));\n\t\twatcher.start();\n\t\ttry {\n\t\t\tlatch.await();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t\treturn Outcome.RETRY;\n\t}\n\n\tprivate static class Listener implements FileChangeListener {\n\n\t\tprivate final CountDownLatch latch;\n\n\t\tListener(CountDownLatch latch) {\n\t\t\tthis.latch = latch;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onChange(Set<ChangedFiles> changeSet) {\n\t\t\tthis.latch.countDown();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsProperties.Restart;\nimport org.springframework.boot.devtools.classpath.ClassPathChangedEvent;\nimport org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;\nimport org.springframework.boot.devtools.classpath.ClassPathRestartStrategy;\nimport org.springframework.boot.devtools.classpath.PatternClassPathRestartStrategy;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory;\nimport org.springframework.boot.devtools.filewatch.SnapshotStateRepository;\nimport org.springframework.boot.devtools.restart.ConditionalOnInitializedRestarter;\nimport org.springframework.boot.devtools.restart.RestartScope;\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.event.GenericApplicationListener;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for local development support.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Vladimir Tsanev\n * @since 1.3.0\n */\n@AutoConfiguration\n@ConditionalOnInitializedRestarter\n@EnableConfigurationProperties(DevToolsProperties.class)\npublic final class LocalDevToolsAutoConfiguration {\n\n\t/**\n\t * Local LiveReload configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.devtools.livereload.enabled\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class LiveReloadConfiguration {\n\n\t\t@Bean\n\t\t@RestartScope\n\t\t@ConditionalOnMissingBean\n\t\torg.springframework.boot.devtools.livereload.LiveReloadServer liveReloadServer(DevToolsProperties properties) {\n\t\t\treturn new org.springframework.boot.devtools.livereload.LiveReloadServer(\n\t\t\t\t\tproperties.getLivereload().getPort(), Restarter.getInstance().getThreadFactory());\n\t\t}\n\n\t\t@Bean\n\t\tOptionalLiveReloadServer optionalLiveReloadServer(\n\t\t\t\torg.springframework.boot.devtools.livereload.LiveReloadServer liveReloadServer) {\n\t\t\treturn new OptionalLiveReloadServer(liveReloadServer);\n\t\t}\n\n\t\t@Bean\n\t\tLiveReloadServerEventListener liveReloadServerEventListener(OptionalLiveReloadServer liveReloadServer) {\n\t\t\treturn new LiveReloadServerEventListener(liveReloadServer);\n\t\t}\n\n\t}\n\n\t/**\n\t * Local Restart Configuration.\n\t */\n\t@Lazy(false)\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.devtools.restart.enabled\", matchIfMissing = true)\n\tstatic class RestartConfiguration {\n\n\t\tprivate final DevToolsProperties properties;\n\n\t\tRestartConfiguration(DevToolsProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Bean\n\t\tRestartingClassPathChangeChangedEventListener restartingClassPathChangedEventListener(\n\t\t\t\tFileSystemWatcherFactory fileSystemWatcherFactory) {\n\t\t\treturn new RestartingClassPathChangeChangedEventListener(fileSystemWatcherFactory);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tClassPathFileSystemWatcher classPathFileSystemWatcher(FileSystemWatcherFactory fileSystemWatcherFactory,\n\t\t\t\tClassPathRestartStrategy classPathRestartStrategy) {\n\t\t\tURL[] urls = Restarter.getInstance().getInitialUrls();\n\t\t\tAssert.state(urls != null, \"'urls' must not be null\");\n\t\t\tClassPathFileSystemWatcher watcher = new ClassPathFileSystemWatcher(fileSystemWatcherFactory,\n\t\t\t\t\tclassPathRestartStrategy, urls);\n\t\t\twatcher.setStopWatcherOnRestart(true);\n\t\t\treturn watcher;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tClassPathRestartStrategy classPathRestartStrategy() {\n\t\t\treturn new PatternClassPathRestartStrategy(this.properties.getRestart().getAllExclude());\n\t\t}\n\n\t\t@Bean\n\t\tFileSystemWatcherFactory fileSystemWatcherFactory() {\n\t\t\treturn this::newFileSystemWatcher;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBooleanProperty(name = \"spring.devtools.restart.log-condition-evaluation-delta\",\n\t\t\t\tmatchIfMissing = true)\n\t\tConditionEvaluationDeltaLoggingListener conditionEvaluationDeltaLoggingListener() {\n\t\t\treturn new ConditionEvaluationDeltaLoggingListener();\n\t\t}\n\n\t\tprivate FileSystemWatcher newFileSystemWatcher() {\n\t\t\tRestart restartProperties = this.properties.getRestart();\n\t\t\tFileSystemWatcher watcher = new FileSystemWatcher(true, restartProperties.getPollInterval(),\n\t\t\t\t\trestartProperties.getQuietPeriod(), SnapshotStateRepository.STATIC);\n\t\t\tString triggerFile = restartProperties.getTriggerFile();\n\t\t\tif (StringUtils.hasLength(triggerFile)) {\n\t\t\t\twatcher.setTriggerFilter(new TriggerFileFilter(triggerFile));\n\t\t\t}\n\t\t\tList<File> additionalPaths = restartProperties.getAdditionalPaths();\n\t\t\tfor (File path : additionalPaths) {\n\t\t\t\twatcher.addSourceDirectory(path.getAbsoluteFile());\n\t\t\t}\n\t\t\treturn watcher;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tstatic class LiveReloadServerEventListener implements GenericApplicationListener {\n\n\t\tprivate final OptionalLiveReloadServer liveReloadServer;\n\n\t\tLiveReloadServerEventListener(OptionalLiveReloadServer liveReloadServer) {\n\t\t\tthis.liveReloadServer = liveReloadServer;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsEventType(ResolvableType eventType) {\n\t\t\tClass<?> type = eventType.getRawClass();\n\t\t\tif (type == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn ContextRefreshedEvent.class.isAssignableFrom(type)\n\t\t\t\t\t|| ClassPathChangedEvent.class.isAssignableFrom(type);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsSourceType(@Nullable Class<?> sourceType) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tif (event instanceof ContextRefreshedEvent || (event instanceof ClassPathChangedEvent classPathChangedEvent\n\t\t\t\t\t&& !classPathChangedEvent.isRestartRequired())) {\n\t\t\t\tthis.liveReloadServer.triggerReload();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t}\n\n\tstatic class RestartingClassPathChangeChangedEventListener implements ApplicationListener<ClassPathChangedEvent> {\n\n\t\tprivate static final Log logger = LogFactory.getLog(RestartingClassPathChangeChangedEventListener.class);\n\n\t\tprivate final FileSystemWatcherFactory fileSystemWatcherFactory;\n\n\t\tRestartingClassPathChangeChangedEventListener(FileSystemWatcherFactory fileSystemWatcherFactory) {\n\t\t\tthis.fileSystemWatcherFactory = fileSystemWatcherFactory;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ClassPathChangedEvent event) {\n\t\t\tif (event.isRestartRequired()) {\n\t\t\t\tlogger.info(LogMessage.format(\"Restarting due to %s\", event.overview()));\n\t\t\t\tlogger.debug(LogMessage.format(\"Change set: %s\", event.getChangeSet()));\n\t\t\t\tRestarter.getInstance().restart(new FileWatchingFailureHandler(this.fileSystemWatcherFactory));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/OnEnabledDevToolsCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.devtools.system.DevToolsEnablementDeducer;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * A condition that checks if DevTools should be enabled.\n *\n * @author Madhura Bhave\n */\nclass OnEnabledDevToolsCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Devtools\");\n\t\tboolean shouldEnable = DevToolsEnablementDeducer.shouldEnable(Thread.currentThread());\n\t\tif (!shouldEnable) {\n\t\t\treturn ConditionOutcome.noMatch(message.because(\"devtools is disabled for current context.\"));\n\t\t}\n\t\treturn ConditionOutcome.match(message.because(\"devtools enabled.\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.devtools.livereload.LiveReloadServer;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * Manages an optional {@link LiveReloadServer}. The {@link LiveReloadServer} may\n * gracefully fail to start (e.g. because of a port conflict) or may be omitted entirely.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @deprecated since 4.1.0 for removal in 4.3.0 with no replacement.\n */\n@Deprecated(since = \"4.1.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class OptionalLiveReloadServer implements InitializingBean {\n\n\tprivate static final Log logger = LogFactory.getLog(OptionalLiveReloadServer.class);\n\n\tprivate @Nullable LiveReloadServer server;\n\n\t/**\n\t * Create a new {@link OptionalLiveReloadServer} instance.\n\t * @param server the server to manage or {@code null}\n\t */\n\tpublic OptionalLiveReloadServer(@Nullable LiveReloadServer server) {\n\t\tthis.server = server;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tstartServer();\n\t}\n\n\tvoid startServer() {\n\t\tif (this.server != null) {\n\t\t\ttry {\n\t\t\t\tint port = this.server.getPort();\n\t\t\t\tif (!this.server.isStarted()) {\n\t\t\t\t\tport = this.server.start();\n\t\t\t\t}\n\t\t\t\tlogger.info(LogMessage.format(\"LiveReload server is running on port %s\", port));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlogger.warn(\"Unable to start LiveReload server\");\n\t\t\t\tlogger.debug(\"Live reload start error\", ex);\n\t\t\t\tthis.server = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Trigger LiveReload if the server is up and running.\n\t */\n\tpublic void triggerReload() {\n\t\tif (this.server != null) {\n\t\t\tthis.server.triggerReload();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.util.Collection;\n\nimport jakarta.servlet.Filter;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.devtools.remote.server.AccessManager;\nimport org.springframework.boot.devtools.remote.server.Dispatcher;\nimport org.springframework.boot.devtools.remote.server.DispatcherFilter;\nimport org.springframework.boot.devtools.remote.server.Handler;\nimport org.springframework.boot.devtools.remote.server.HandlerMapper;\nimport org.springframework.boot.devtools.remote.server.HttpHeaderAccessManager;\nimport org.springframework.boot.devtools.remote.server.HttpStatusHandler;\nimport org.springframework.boot.devtools.remote.server.UrlHandlerMapper;\nimport org.springframework.boot.devtools.restart.server.DefaultSourceDirectoryUrlFilter;\nimport org.springframework.boot.devtools.restart.server.HttpRestartServer;\nimport org.springframework.boot.devtools.restart.server.HttpRestartServerHandler;\nimport org.springframework.boot.devtools.restart.server.SourceDirectoryUrlFilter;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties.Servlet;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for remote development support.\n *\n * @author Phillip Webb\n * @author Rob Winch\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 1.3.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration\")\n@ConditionalOnEnabledDevTools\n@ConditionalOnProperty(\"spring.devtools.remote.secret\")\n@ConditionalOnClass({ Filter.class, ServerHttpRequest.class, ServerProperties.class })\n@Import(RemoteDevtoolsSecurityConfiguration.class)\n@EnableConfigurationProperties({ ServerProperties.class, DevToolsProperties.class })\npublic final class RemoteDevToolsAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(RemoteDevToolsAutoConfiguration.class);\n\n\tprivate final DevToolsProperties properties;\n\n\tRemoteDevToolsAutoConfiguration(DevToolsProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAccessManager remoteDevToolsAccessManager() {\n\t\tRemoteDevToolsProperties remoteProperties = this.properties.getRemote();\n\t\tString secret = remoteProperties.getSecret();\n\t\tAssert.state(secret != null, \"'secret' must not be null\");\n\t\treturn new HttpHeaderAccessManager(remoteProperties.getSecretHeaderName(), secret);\n\t}\n\n\t@Bean\n\tHandlerMapper remoteDevToolsHealthCheckHandlerMapper(ServerProperties serverProperties) {\n\t\tHandler handler = new HttpStatusHandler();\n\t\tServlet servlet = serverProperties.getServlet();\n\t\tString servletContextPath = (servlet.getContextPath() != null) ? servlet.getContextPath() : \"\";\n\t\treturn new UrlHandlerMapper(servletContextPath + this.properties.getRemote().getContextPath(), handler);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDispatcherFilter remoteDevToolsDispatcherFilter(AccessManager accessManager, Collection<HandlerMapper> mappers) {\n\t\tDispatcher dispatcher = new Dispatcher(accessManager, mappers);\n\t\treturn new DispatcherFilter(dispatcher);\n\t}\n\n\t/**\n\t * Configuration for remote update and restarts.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.devtools.remote.restart.enabled\", matchIfMissing = true)\n\tstatic class RemoteRestartConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSourceDirectoryUrlFilter remoteRestartSourceDirectoryUrlFilter() {\n\t\t\treturn new DefaultSourceDirectoryUrlFilter();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tHttpRestartServer remoteRestartHttpRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {\n\t\t\treturn new HttpRestartServer(sourceDirectoryUrlFilter);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = \"remoteRestartHandlerMapper\")\n\t\tUrlHandlerMapper remoteRestartHandlerMapper(HttpRestartServer server, ServerProperties serverProperties,\n\t\t\t\tDevToolsProperties properties) {\n\t\t\tServlet servlet = serverProperties.getServlet();\n\t\t\tRemoteDevToolsProperties remote = properties.getRemote();\n\t\t\tString servletContextPath = (servlet.getContextPath() != null) ? servlet.getContextPath() : \"\";\n\t\t\tString url = servletContextPath + remote.getContextPath() + \"/restart\";\n\t\t\tlogger.warn(LogMessage.format(\"Listening for remote restart updates on %s\", url));\n\t\t\tHandler handler = new HttpRestartServerHandler(server);\n\t\t\treturn new UrlHandlerMapper(url, handler);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Configuration properties for remote Spring Boot applications.\n *\n * @author Phillip Webb\n * @author Rob Winch\n * @since 1.3.0\n * @see DevToolsProperties\n */\npublic class RemoteDevToolsProperties {\n\n\tpublic static final String DEFAULT_CONTEXT_PATH = \"/.~~spring-boot!~\";\n\n\tpublic static final String DEFAULT_SECRET_HEADER_NAME = \"X-AUTH-TOKEN\";\n\n\t/**\n\t * Context path used to handle the remote connection.\n\t */\n\tprivate String contextPath = DEFAULT_CONTEXT_PATH;\n\n\t/**\n\t * A shared secret required to establish a connection (required to enable remote\n\t * support).\n\t */\n\tprivate @Nullable String secret;\n\n\t/**\n\t * HTTP header used to transfer the shared secret.\n\t */\n\tprivate String secretHeaderName = DEFAULT_SECRET_HEADER_NAME;\n\n\tprivate final Restart restart = new Restart();\n\n\tprivate final Proxy proxy = new Proxy();\n\n\tpublic String getContextPath() {\n\t\treturn this.contextPath;\n\t}\n\n\tpublic void setContextPath(String contextPath) {\n\t\tthis.contextPath = contextPath;\n\t}\n\n\tpublic @Nullable String getSecret() {\n\t\treturn this.secret;\n\t}\n\n\tpublic void setSecret(@Nullable String secret) {\n\t\tthis.secret = secret;\n\t}\n\n\tpublic String getSecretHeaderName() {\n\t\treturn this.secretHeaderName;\n\t}\n\n\tpublic void setSecretHeaderName(String secretHeaderName) {\n\t\tthis.secretHeaderName = secretHeaderName;\n\t}\n\n\tpublic Restart getRestart() {\n\t\treturn this.restart;\n\t}\n\n\tpublic Proxy getProxy() {\n\t\treturn this.proxy;\n\t}\n\n\tpublic static class Restart {\n\n\t\t/**\n\t\t * Whether to enable remote restart.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\tpublic static class Proxy {\n\n\t\t/**\n\t\t * The host of the proxy to use to connect to the remote application.\n\t\t */\n\t\tprivate @Nullable String host;\n\n\t\t/**\n\t\t * The port of the proxy to use to connect to the remote application.\n\t\t */\n\t\tprivate @Nullable Integer port;\n\n\t\tpublic @Nullable String getHost() {\n\t\t\treturn this.host;\n\t\t}\n\n\t\tpublic void setHost(@Nullable String host) {\n\t\t\tthis.host = host;\n\t\t}\n\n\t\tpublic @Nullable Integer getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tpublic void setPort(@Nullable Integer port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/RemoteDevtoolsSecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\n\n/**\n * Spring Security configuration that allows anonymous access to the remote devtools\n * endpoint.\n *\n * @author Madhura Bhave\n */\n@ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })\n@Configuration(proxyBeanMethods = false)\nclass RemoteDevtoolsSecurityConfiguration {\n\n\tprivate final String url;\n\n\tRemoteDevtoolsSecurityConfiguration(DevToolsProperties devToolsProperties, ServerProperties serverProperties) {\n\t\tServerProperties.Servlet servlet = serverProperties.getServlet();\n\t\tString servletContextPath = (servlet.getContextPath() != null) ? servlet.getContextPath() : \"\";\n\t\tthis.url = servletContextPath + devToolsProperties.getRemote().getContextPath() + \"/restart\";\n\t}\n\n\t@Bean\n\t@Order(SecurityFilterProperties.BASIC_AUTH_ORDER - 1)\n\tSecurityFilterChain devtoolsSecurityFilterChain(HttpSecurity http) {\n\t\thttp.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher(this.url));\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().anonymous());\n\t\thttp.csrf(CsrfConfigurer::disable);\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileFilter;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link FileFilter} that accepts only a specific \"trigger\" file.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class TriggerFileFilter implements FileFilter {\n\n\tprivate final String name;\n\n\tpublic TriggerFileFilter(String name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic boolean accept(File file) {\n\t\treturn file.getName().equals(this.name);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for {@code spring-boot-devtools}.\n */\n@NullMarked\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathChangedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.util.Set;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ApplicationEvent} containing details of a classpath change.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ClassPathFileChangeListener\n */\npublic class ClassPathChangedEvent extends ApplicationEvent {\n\n\tprivate final Set<ChangedFiles> changeSet;\n\n\tprivate final boolean restartRequired;\n\n\t/**\n\t * Create a new {@link ClassPathChangedEvent}.\n\t * @param source the source of the event\n\t * @param changeSet the changed files\n\t * @param restartRequired if a restart is required due to the change\n\t */\n\tpublic ClassPathChangedEvent(Object source, Set<ChangedFiles> changeSet, boolean restartRequired) {\n\t\tsuper(source);\n\t\tAssert.notNull(changeSet, \"'changeSet' must not be null\");\n\t\tthis.changeSet = changeSet;\n\t\tthis.restartRequired = restartRequired;\n\t}\n\n\t/**\n\t * Return details of the files that changed.\n\t * @return the changed files\n\t */\n\tpublic Set<ChangedFiles> getChangeSet() {\n\t\treturn this.changeSet;\n\t}\n\n\t/**\n\t * Return if an application restart is required due to the change.\n\t * @return if an application restart is required\n\t */\n\tpublic boolean isRestartRequired() {\n\t\treturn this.restartRequired;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new ToStringCreator(this).append(\"changeSet\", this.changeSet)\n\t\t\t.append(\"restartRequired\", this.restartRequired)\n\t\t\t.toString();\n\t}\n\n\t/**\n\t * Return an overview of the changes that triggered this event.\n\t * @return an overview of the changes\n\t * @since 2.6.11\n\t */\n\tpublic String overview() {\n\t\tint added = 0;\n\t\tint deleted = 0;\n\t\tint modified = 0;\n\t\tfor (ChangedFiles changedFiles : this.changeSet) {\n\t\t\tfor (ChangedFile changedFile : changedFiles) {\n\t\t\t\tType type = changedFile.getType();\n\t\t\t\tif (type == Type.ADD) {\n\t\t\t\t\tadded++;\n\t\t\t\t}\n\t\t\t\telse if (type == Type.DELETE) {\n\t\t\t\t\tdeleted++;\n\t\t\t\t}\n\t\t\t\telse if (type == Type.MODIFY) {\n\t\t\t\t\tmodified++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tint size = added + deleted + modified;\n\t\treturn String.format(\"%s (%s, %s, %s)\", quantityOfUnit(size, \"class path change\"),\n\t\t\t\tquantityOfUnit(added, \"addition\"), quantityOfUnit(deleted, \"deletion\"),\n\t\t\t\tquantityOfUnit(modified, \"modification\"));\n\t}\n\n\tprivate String quantityOfUnit(int quantity, String unit) {\n\t\treturn quantity + \" \" + ((quantity != 1) ? unit + \"s\" : unit);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathDirectories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * Provides access to entries on the classpath that refer to directories.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class ClassPathDirectories implements Iterable<File> {\n\n\tprivate static final Log logger = LogFactory.getLog(ClassPathDirectories.class);\n\n\tprivate final List<File> directories = new ArrayList<>();\n\n\tpublic ClassPathDirectories(URL @Nullable [] urls) {\n\t\tif (urls != null) {\n\t\t\taddUrls(urls);\n\t\t}\n\t}\n\n\tprivate void addUrls(URL[] urls) {\n\t\tfor (URL url : urls) {\n\t\t\taddUrl(url);\n\t\t}\n\t}\n\n\tprivate void addUrl(URL url) {\n\t\tif (url.getProtocol().equals(\"file\") && url.getPath().endsWith(\"/\")) {\n\t\t\ttry {\n\t\t\t\tthis.directories.add(ResourceUtils.getFile(url));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlogger.warn(LogMessage.format(\"Unable to get classpath URL %s\", url));\n\t\t\t\tlogger.trace(LogMessage.format(\"Unable to get classpath URL %s\", url), ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic Iterator<File> iterator() {\n\t\treturn Collections.unmodifiableList(this.directories).iterator();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathFileChangeListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.boot.devtools.filewatch.FileChangeListener;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.boot.devtools.restart.AgentReloader;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link FileChangeListener} to publish {@link ClassPathChangedEvent\n * ClassPathChangedEvents}.\n *\n * @author Phillip Webb\n * @see ClassPathFileSystemWatcher\n */\nclass ClassPathFileChangeListener implements FileChangeListener {\n\n\tprivate final ApplicationEventPublisher eventPublisher;\n\n\tprivate final ClassPathRestartStrategy restartStrategy;\n\n\tprivate final @Nullable FileSystemWatcher fileSystemWatcherToStop;\n\n\t/**\n\t * Create a new {@link ClassPathFileChangeListener} instance.\n\t * @param eventPublisher the event publisher used send events\n\t * @param restartStrategy the restart strategy to use\n\t * @param fileSystemWatcherToStop the file system watcher to stop on a restart (or\n\t * {@code null})\n\t */\n\tClassPathFileChangeListener(ApplicationEventPublisher eventPublisher, ClassPathRestartStrategy restartStrategy,\n\t\t\t@Nullable FileSystemWatcher fileSystemWatcherToStop) {\n\t\tAssert.notNull(eventPublisher, \"'eventPublisher' must not be null\");\n\t\tAssert.notNull(restartStrategy, \"'restartStrategy' must not be null\");\n\t\tthis.eventPublisher = eventPublisher;\n\t\tthis.restartStrategy = restartStrategy;\n\t\tthis.fileSystemWatcherToStop = fileSystemWatcherToStop;\n\t}\n\n\t@Override\n\tpublic void onChange(Set<ChangedFiles> changeSet) {\n\t\tboolean restart = isRestartRequired(changeSet);\n\t\tpublishEvent(new ClassPathChangedEvent(this, changeSet, restart));\n\t}\n\n\tprivate void publishEvent(ClassPathChangedEvent event) {\n\t\tthis.eventPublisher.publishEvent(event);\n\t\tif (event.isRestartRequired() && this.fileSystemWatcherToStop != null) {\n\t\t\tthis.fileSystemWatcherToStop.stop();\n\t\t}\n\t}\n\n\tprivate boolean isRestartRequired(Set<ChangedFiles> changeSet) {\n\t\tif (AgentReloader.isActive()) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (ChangedFiles changedFiles : changeSet) {\n\t\t\tfor (ChangedFile changedFile : changedFiles) {\n\t\t\t\tif (this.restartStrategy.isRestartRequired(changedFile)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathFileSystemWatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.net.URL;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.util.Assert;\n\n/**\n * Encapsulates a {@link FileSystemWatcher} to watch the local classpath directories for\n * changes.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ClassPathFileChangeListener\n */\npublic class ClassPathFileSystemWatcher implements InitializingBean, DisposableBean, ApplicationContextAware {\n\n\tprivate final FileSystemWatcher fileSystemWatcher;\n\n\tprivate final @Nullable ClassPathRestartStrategy restartStrategy;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext applicationContext;\n\n\tprivate boolean stopWatcherOnRestart;\n\n\t/**\n\t * Create a new {@link ClassPathFileSystemWatcher} instance.\n\t * @param fileSystemWatcherFactory a factory to create the underlying\n\t * {@link FileSystemWatcher} used to monitor the local file system\n\t * @param restartStrategy the classpath restart strategy\n\t * @param urls the URLs to watch\n\t */\n\tpublic ClassPathFileSystemWatcher(FileSystemWatcherFactory fileSystemWatcherFactory,\n\t\t\t@Nullable ClassPathRestartStrategy restartStrategy, URL[] urls) {\n\t\tAssert.notNull(fileSystemWatcherFactory, \"'fileSystemWatcherFactory' must not be null\");\n\t\tAssert.notNull(urls, \"'urls' must not be null\");\n\t\tthis.fileSystemWatcher = fileSystemWatcherFactory.getFileSystemWatcher();\n\t\tthis.restartStrategy = restartStrategy;\n\t\tthis.fileSystemWatcher.addSourceDirectories(new ClassPathDirectories(urls));\n\t}\n\n\t/**\n\t * Set if the {@link FileSystemWatcher} should be stopped when a full restart occurs.\n\t * @param stopWatcherOnRestart if the watcher should be stopped when a restart occurs\n\t */\n\tpublic void setStopWatcherOnRestart(boolean stopWatcherOnRestart) {\n\t\tthis.stopWatcherOnRestart = stopWatcherOnRestart;\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (this.restartStrategy != null) {\n\t\t\tFileSystemWatcher watcherToStop = null;\n\t\t\tif (this.stopWatcherOnRestart) {\n\t\t\t\twatcherToStop = this.fileSystemWatcher;\n\t\t\t}\n\t\t\tthis.fileSystemWatcher.addListener(\n\t\t\t\t\tnew ClassPathFileChangeListener(this.applicationContext, this.restartStrategy, watcherToStop));\n\t\t}\n\t\tthis.fileSystemWatcher.start();\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tthis.fileSystemWatcher.stop();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/ClassPathRestartStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\n\n/**\n * Strategy interface used to determine when a changed classpath file should trigger a\n * full application restart. For example, static web resources might not require a full\n * restart whereas class files would.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see PatternClassPathRestartStrategy\n */\n@FunctionalInterface\npublic interface ClassPathRestartStrategy {\n\n\t/**\n\t * Return true if a full restart is required.\n\t * @param file the changed file\n\t * @return {@code true} if a full restart is required\n\t */\n\tboolean isRestartRequired(ChangedFile file);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/PatternClassPathRestartStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.StringUtils;\n\n/**\n * Ant style pattern based {@link ClassPathRestartStrategy}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ClassPathRestartStrategy\n */\npublic class PatternClassPathRestartStrategy implements ClassPathRestartStrategy {\n\n\tprivate final AntPathMatcher matcher = new AntPathMatcher();\n\n\tprivate final String[] excludePatterns;\n\n\tpublic PatternClassPathRestartStrategy(String[] excludePatterns) {\n\t\tthis.excludePatterns = excludePatterns;\n\t}\n\n\tpublic PatternClassPathRestartStrategy(@Nullable String excludePatterns) {\n\t\tthis(StringUtils.commaDelimitedListToStringArray(excludePatterns));\n\t}\n\n\t@Override\n\tpublic boolean isRestartRequired(ChangedFile file) {\n\t\tfor (String pattern : this.excludePatterns) {\n\t\t\tif (this.matcher.match(pattern, file.getRelativeName())) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/classpath/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for classpath monitoring.\n */\n@NullMarked\npackage org.springframework.boot.devtools.classpath;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.env;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.devtools.system.DevToolsEnablementDeducer;\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.env.PropertySourceLoader;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnvironmentPostProcessor} to add devtools properties from the user's home\n * directory.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author HaiTao Zhang\n * @author Madhura Bhave\n * @since 1.3.0\n */\npublic class DevToolsHomePropertiesPostProcessor implements EnvironmentPostProcessor {\n\n\tprivate static final String LEGACY_FILE_NAME = \".spring-boot-devtools.properties\";\n\n\tprivate static final String[] FILE_NAMES = new String[] { \"spring-boot-devtools.yml\", \"spring-boot-devtools.yaml\",\n\t\t\t\"spring-boot-devtools.properties\" };\n\n\tprivate static final String CONFIG_PATH = \"/.config/spring-boot/\";\n\n\tprivate static final Set<PropertySourceLoader> PROPERTY_SOURCE_LOADERS;\n\n\tprivate final Properties systemProperties;\n\n\tprivate final Map<String, String> environmentVariables;\n\n\tstatic {\n\t\tSet<PropertySourceLoader> propertySourceLoaders = new HashSet<>();\n\t\tpropertySourceLoaders.add(new PropertiesPropertySourceLoader());\n\t\tif (ClassUtils.isPresent(\"org.yaml.snakeyaml.Yaml\", null)) {\n\t\t\tpropertySourceLoaders.add(new YamlPropertySourceLoader());\n\t\t}\n\t\tPROPERTY_SOURCE_LOADERS = Collections.unmodifiableSet(propertySourceLoaders);\n\t}\n\n\tpublic DevToolsHomePropertiesPostProcessor() {\n\t\tthis(System.getenv(), System.getProperties());\n\t}\n\n\tDevToolsHomePropertiesPostProcessor(Map<String, String> environmentVariables, Properties systemProperties) {\n\t\tthis.environmentVariables = environmentVariables;\n\t\tthis.systemProperties = systemProperties;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (DevToolsEnablementDeducer.shouldEnable(Thread.currentThread())) {\n\t\t\tList<PropertySource<?>> propertySources = getPropertySources();\n\t\t\tif (propertySources.isEmpty()) {\n\t\t\t\taddPropertySource(propertySources, LEGACY_FILE_NAME, (file) -> \"devtools-local\");\n\t\t\t}\n\t\t\tpropertySources.forEach(environment.getPropertySources()::addFirst);\n\t\t}\n\t}\n\n\tprivate List<PropertySource<?>> getPropertySources() {\n\t\tList<PropertySource<?>> propertySources = new ArrayList<>();\n\t\tfor (String fileName : FILE_NAMES) {\n\t\t\taddPropertySource(propertySources, CONFIG_PATH + fileName, this::getPropertySourceName);\n\t\t}\n\t\treturn propertySources;\n\t}\n\n\tprivate String getPropertySourceName(File file) {\n\t\treturn \"devtools-local: [\" + file.toURI() + \"]\";\n\t}\n\n\tprivate void addPropertySource(List<PropertySource<?>> propertySources, String fileName,\n\t\t\tFunction<File, String> propertySourceNamer) {\n\t\tFile home = getHomeDirectory();\n\t\tFile file = (home != null) ? new File(home, fileName) : null;\n\t\tFileSystemResource resource = (file != null) ? new FileSystemResource(file) : null;\n\t\tif (resource != null && resource.exists() && resource.isFile()) {\n\t\t\taddPropertySource(propertySources, resource, propertySourceNamer);\n\t\t}\n\t}\n\n\tprivate void addPropertySource(List<PropertySource<?>> propertySources, FileSystemResource resource,\n\t\t\tFunction<File, String> propertySourceNamer) {\n\t\ttry {\n\t\t\tString name = propertySourceNamer.apply(resource.getFile());\n\t\t\tfor (PropertySourceLoader loader : PROPERTY_SOURCE_LOADERS) {\n\t\t\t\tif (canLoadFileExtension(loader, resource.getFilename())) {\n\t\t\t\t\tpropertySources.addAll(loader.load(name, resource));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load \" + resource.getFilename(), ex);\n\t\t}\n\t}\n\n\tprivate boolean canLoadFileExtension(PropertySourceLoader loader, String name) {\n\t\treturn Arrays.stream(loader.getFileExtensions())\n\t\t\t.anyMatch((fileExtension) -> StringUtils.endsWithIgnoreCase(name, fileExtension));\n\t}\n\n\tprotected @Nullable File getHomeDirectory() {\n\t\treturn getHomeDirectory(() -> this.environmentVariables.get(\"SPRING_DEVTOOLS_HOME\"),\n\t\t\t\t() -> this.systemProperties.getProperty(\"spring.devtools.home\"),\n\t\t\t\t() -> this.systemProperties.getProperty(\"user.home\"));\n\t}\n\n\t@SafeVarargs\n\tprivate @Nullable File getHomeDirectory(Supplier<String>... pathSuppliers) {\n\t\tfor (Supplier<String> pathSupplier : pathSuppliers) {\n\t\t\tString path = pathSupplier.get();\n\t\t\tif (StringUtils.hasText(path)) {\n\t\t\t\treturn new File(path);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.env;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.devtools.logger.DevToolsLogFactory;\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.boot.devtools.settings.DevToolsSettings;\nimport org.springframework.boot.devtools.system.DevToolsEnablementDeducer;\nimport org.springframework.core.NativeDetector;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnvironmentPostProcessor} to add properties that make sense when working at\n * development time.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 1.3.0\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\npublic class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostProcessor {\n\n\tprivate static final Log logger = DevToolsLogFactory.getLog(DevToolsPropertyDefaultsPostProcessor.class);\n\n\tprivate static final String ENABLED = \"spring.devtools.add-properties\";\n\n\tprivate static final String WEB_LOGGING = \"logging.level.web\";\n\n\tprivate static final String[] WEB_ENVIRONMENT_CLASSES = {\n\t\t\t\"org.springframework.web.context.ConfigurableWebEnvironment\",\n\t\t\t\"org.springframework.boot.web.reactive.context.ConfigurableReactiveWebEnvironment\" };\n\n\tprivate static final Map<String, Object> PROPERTIES;\n\n\tstatic {\n\t\tif (NativeDetector.inNativeImage()) {\n\t\t\tPROPERTIES = Collections.emptyMap();\n\t\t}\n\t\telse {\n\t\t\tPROPERTIES = DevToolsSettings.get().getPropertyDefaults();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (DevToolsEnablementDeducer.shouldEnable(Thread.currentThread()) && isLocalApplication(environment)) {\n\t\t\tif (canAddProperties(environment)) {\n\t\t\t\tlogger.info(LogMessage.format(\"Devtools property defaults active! Set '%s' to 'false' to disable\",\n\t\t\t\t\t\tENABLED));\n\t\t\t\tenvironment.getPropertySources().addLast(new MapPropertySource(\"devtools\", PROPERTIES));\n\t\t\t}\n\t\t\tif (isWebApplication(environment) && !environment.containsProperty(WEB_LOGGING)) {\n\t\t\t\tlogger.info(LogMessage.format(\n\t\t\t\t\t\t\"For additional web related logging consider setting the '%s' property to 'DEBUG'\",\n\t\t\t\t\t\tWEB_LOGGING));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isLocalApplication(ConfigurableEnvironment environment) {\n\t\treturn environment.getPropertySources().get(\"remoteUrl\") == null;\n\t}\n\n\tprivate boolean canAddProperties(Environment environment) {\n\t\tif (environment.getProperty(ENABLED, Boolean.class, true)) {\n\t\t\treturn isRestarterInitialized() || isRemoteRestartEnabled(environment);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isRestarterInitialized() {\n\t\ttry {\n\t\t\tRestarter restarter = Restarter.getInstance();\n\t\t\treturn (restarter != null && restarter.getInitialUrls() != null);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean isRemoteRestartEnabled(Environment environment) {\n\t\treturn environment.containsProperty(\"spring.devtools.remote.secret\");\n\t}\n\n\tprivate boolean isWebApplication(Environment environment) {\n\t\tfor (String candidate : WEB_ENVIRONMENT_CLASSES) {\n\t\t\tClass<?> environmentClass = resolveClassName(candidate, environment.getClass().getClassLoader());\n\t\t\tif (environmentClass != null && environmentClass.isInstance(environment)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate @Nullable Class<?> resolveClassName(String candidate, ClassLoader classLoader) {\n\t\ttry {\n\t\t\treturn ClassUtils.resolveClassName(candidate, classLoader);\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * DevTools classes relating to Spring Framework's\n * {@link org.springframework.core.env.Environment}.\n */\n@NullMarked\npackage org.springframework.boot.devtools.env;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/ChangedFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A single file that has changed.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ChangedFiles\n */\npublic final class ChangedFile {\n\n\tprivate final File sourceDirectory;\n\n\tprivate final File file;\n\n\tprivate final Type type;\n\n\t/**\n\t * Create a new {@link ChangedFile} instance.\n\t * @param sourceDirectory the source directory\n\t * @param file the file\n\t * @param type the type of change\n\t */\n\tpublic ChangedFile(File sourceDirectory, File file, Type type) {\n\t\tAssert.notNull(sourceDirectory, \"'sourceDirectory' must not be null\");\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tthis.sourceDirectory = sourceDirectory;\n\t\tthis.file = file;\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * Return the file that was changed.\n\t * @return the file\n\t */\n\tpublic File getFile() {\n\t\treturn this.file;\n\t}\n\n\t/**\n\t * Return the type of change.\n\t * @return the type of change\n\t */\n\tpublic Type getType() {\n\t\treturn this.type;\n\t}\n\n\t/**\n\t * Return the name of the file relative to the source directory.\n\t * @return the relative name\n\t */\n\tpublic String getRelativeName() {\n\t\tFile directory = this.sourceDirectory.getAbsoluteFile();\n\t\tFile file = this.file.getAbsoluteFile();\n\t\tString directoryName = StringUtils.cleanPath(directory.getPath());\n\t\tString fileName = StringUtils.cleanPath(file.getPath());\n\t\tAssert.state(fileName.startsWith(directoryName),\n\t\t\t\t() -> \"The file \" + fileName + \" is not contained in the source directory \" + directoryName);\n\t\treturn fileName.substring(directoryName.length() + 1);\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof ChangedFile other) {\n\t\t\treturn this.file.equals(other.file) && this.type.equals(other.type);\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.file.hashCode() * 31 + this.type.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.file + \" (\" + this.type + \")\";\n\t}\n\n\t/**\n\t * Change types.\n\t */\n\tpublic enum Type {\n\n\t\t/**\n\t\t * A new file has been added.\n\t\t */\n\t\tADD,\n\n\t\t/**\n\t\t * An existing file has been modified.\n\t\t */\n\t\tMODIFY,\n\n\t\t/**\n\t\t * An existing file has been deleted.\n\t\t */\n\t\tDELETE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/ChangedFiles.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A collections of files from a specific source directory that have changed.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see FileChangeListener\n * @see ChangedFiles\n */\npublic final class ChangedFiles implements Iterable<ChangedFile> {\n\n\tprivate final File sourceDirectory;\n\n\tprivate final Set<ChangedFile> files;\n\n\tpublic ChangedFiles(File sourceDirectory, Set<ChangedFile> files) {\n\t\tthis.sourceDirectory = sourceDirectory;\n\t\tthis.files = Collections.unmodifiableSet(files);\n\t}\n\n\t/**\n\t * The source directory being watched.\n\t * @return the source directory\n\t */\n\tpublic File getSourceDirectory() {\n\t\treturn this.sourceDirectory;\n\t}\n\n\t@Override\n\tpublic Iterator<ChangedFile> iterator() {\n\t\treturn getFiles().iterator();\n\t}\n\n\t/**\n\t * The files that have been changed.\n\t * @return the changed files\n\t */\n\tpublic Set<ChangedFile> getFiles() {\n\t\treturn this.files;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof ChangedFiles other) {\n\t\t\treturn this.sourceDirectory.equals(other.sourceDirectory) && this.files.equals(other.files);\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.files.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.sourceDirectory + \" \" + this.files;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/DirectorySnapshot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\nimport org.springframework.util.Assert;\n\n/**\n * A snapshot of a directory at a given point in time.\n *\n * @author Phillip Webb\n */\nclass DirectorySnapshot {\n\n\tprivate static final Set<String> DOTS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(\".\", \"..\")));\n\n\tprivate final File directory;\n\n\tprivate final Date time;\n\n\tprivate final Set<FileSnapshot> files;\n\n\t/**\n\t * Create a new {@link DirectorySnapshot} for the given directory.\n\t * @param directory the source directory\n\t */\n\tDirectorySnapshot(File directory) {\n\t\tAssert.notNull(directory, \"'directory' must not be null\");\n\t\tAssert.isTrue(!directory.isFile(), () -> \"'directory' [%s] must not be a file\".formatted(directory));\n\t\tthis.directory = directory;\n\t\tthis.time = new Date();\n\t\tSet<FileSnapshot> files = new LinkedHashSet<>();\n\t\tcollectFiles(directory, files);\n\t\tthis.files = Collections.unmodifiableSet(files);\n\t}\n\n\tprivate void collectFiles(File source, Set<FileSnapshot> result) {\n\t\tFile[] children = source.listFiles();\n\t\tif (children != null) {\n\t\t\tfor (File child : children) {\n\t\t\t\tif (child.isDirectory() && !DOTS.contains(child.getName())) {\n\t\t\t\t\tcollectFiles(child, result);\n\t\t\t\t}\n\t\t\t\telse if (child.isFile()) {\n\t\t\t\t\tresult.add(new FileSnapshot(child));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tChangedFiles getChangedFiles(DirectorySnapshot snapshot, @Nullable FileFilter triggerFilter) {\n\t\tAssert.notNull(snapshot, \"'snapshot' must not be null\");\n\t\tFile directory = this.directory;\n\t\tAssert.isTrue(snapshot.directory.equals(directory),\n\t\t\t\t() -> \"'snapshot' source directory must be '\" + directory + \"'\");\n\t\tSet<ChangedFile> changes = new LinkedHashSet<>();\n\t\tMap<File, FileSnapshot> previousFiles = getFilesMap();\n\t\tfor (FileSnapshot currentFile : snapshot.files) {\n\t\t\tif (acceptChangedFile(triggerFilter, currentFile)) {\n\t\t\t\tFileSnapshot previousFile = previousFiles.remove(currentFile.getFile());\n\t\t\t\tif (previousFile == null) {\n\t\t\t\t\tchanges.add(new ChangedFile(directory, currentFile.getFile(), Type.ADD));\n\t\t\t\t}\n\t\t\t\telse if (!previousFile.equals(currentFile)) {\n\t\t\t\t\tchanges.add(new ChangedFile(directory, currentFile.getFile(), Type.MODIFY));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (FileSnapshot previousFile : previousFiles.values()) {\n\t\t\tif (acceptChangedFile(triggerFilter, previousFile)) {\n\t\t\t\tchanges.add(new ChangedFile(directory, previousFile.getFile(), Type.DELETE));\n\t\t\t}\n\t\t}\n\t\treturn new ChangedFiles(directory, changes);\n\t}\n\n\tprivate boolean acceptChangedFile(@Nullable FileFilter triggerFilter, FileSnapshot file) {\n\t\treturn (triggerFilter == null || !triggerFilter.accept(file.getFile()));\n\t}\n\n\tprivate Map<File, FileSnapshot> getFilesMap() {\n\t\tMap<File, FileSnapshot> files = new LinkedHashMap<>();\n\t\tfor (FileSnapshot file : this.files) {\n\t\t\tfiles.put(file.getFile(), file);\n\t\t}\n\t\treturn files;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof DirectorySnapshot other) {\n\t\t\treturn equals(other, null);\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\tboolean equals(DirectorySnapshot other, @Nullable FileFilter filter) {\n\t\tif (this.directory.equals(other.directory)) {\n\t\t\tSet<FileSnapshot> ourFiles = filter(this.files, filter);\n\t\t\tSet<FileSnapshot> otherFiles = filter(other.files, filter);\n\t\t\treturn ourFiles.equals(otherFiles);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Set<FileSnapshot> filter(Set<FileSnapshot> source, @Nullable FileFilter filter) {\n\t\tif (filter == null) {\n\t\t\treturn source;\n\t\t}\n\t\tSet<FileSnapshot> filtered = new LinkedHashSet<>();\n\t\tfor (FileSnapshot file : source) {\n\t\t\tif (filter.accept(file.getFile())) {\n\t\t\t\tfiltered.add(file);\n\t\t\t}\n\t\t}\n\t\treturn filtered;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint hashCode = this.directory.hashCode();\n\t\thashCode = 31 * hashCode + this.files.hashCode();\n\t\treturn hashCode;\n\t}\n\n\t/**\n\t * Return the source directory of this snapshot.\n\t * @return the source directory\n\t */\n\tFile getDirectory() {\n\t\treturn this.directory;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.directory + \" snapshot at \" + this.time;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileChangeListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.util.Set;\n\n/**\n * Callback interface when file changes are detected.\n *\n * @author Andy Clement\n * @author Phillip Webb\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface FileChangeListener {\n\n\t/**\n\t * Called when files have been changed.\n\t * @param changeSet a set of the {@link ChangedFiles}\n\t */\n\tvoid onChange(Set<ChangedFiles> changeSet);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSnapshot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A snapshot of a File at a given point in time.\n *\n * @author Phillip Webb\n */\nclass FileSnapshot {\n\n\tprivate final File file;\n\n\tprivate final boolean exists;\n\n\tprivate final long length;\n\n\tprivate final long lastModified;\n\n\tFileSnapshot(File file) {\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tAssert.isTrue(file.isFile() || !file.exists(), () -> \"'file' [%s] must be a normal file\".formatted(file));\n\t\tthis.file = file;\n\t\tthis.exists = file.exists();\n\t\tthis.length = file.length();\n\t\tthis.lastModified = file.lastModified();\n\t}\n\n\tFile getFile() {\n\t\treturn this.file;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof FileSnapshot other) {\n\t\t\tboolean equals = this.file.equals(other.file);\n\t\t\tequals = equals && this.exists == other.exists;\n\t\t\tequals = equals && this.length == other.length;\n\t\t\tequals = equals && this.lastModified == other.lastModified;\n\t\t\treturn equals;\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint hashCode = this.file.hashCode();\n\t\thashCode = 31 * hashCode + Boolean.hashCode(this.exists);\n\t\thashCode = 31 * hashCode + Long.hashCode(this.length);\n\t\thashCode = 31 * hashCode + Long.hashCode(this.lastModified);\n\t\treturn hashCode;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.file.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Watches specific directories for file changes.\n *\n * @author Andy Clement\n * @author Phillip Webb\n * @since 1.3.0\n * @see FileChangeListener\n */\npublic class FileSystemWatcher {\n\n\tprivate static final Duration DEFAULT_POLL_INTERVAL = Duration.ofMillis(1000);\n\n\tprivate static final Duration DEFAULT_QUIET_PERIOD = Duration.ofMillis(400);\n\n\tprivate final List<FileChangeListener> listeners = new ArrayList<>();\n\n\tprivate final boolean daemon;\n\n\tprivate final long pollInterval;\n\n\tprivate final long quietPeriod;\n\n\tprivate final SnapshotStateRepository snapshotStateRepository;\n\n\tprivate final AtomicInteger remainingScans = new AtomicInteger(-1);\n\n\tprivate final Map<File, @Nullable DirectorySnapshot> directories = new HashMap<>();\n\n\tprivate @Nullable Thread watchThread;\n\n\tprivate @Nullable FileFilter triggerFilter;\n\n\tprivate final Object monitor = new Object();\n\n\t/**\n\t * Create a new {@link FileSystemWatcher} instance.\n\t */\n\tpublic FileSystemWatcher() {\n\t\tthis(true, DEFAULT_POLL_INTERVAL, DEFAULT_QUIET_PERIOD);\n\t}\n\n\t/**\n\t * Create a new {@link FileSystemWatcher} instance.\n\t * @param daemon if a daemon thread used to monitor changes\n\t * @param pollInterval the amount of time to wait between checking for changes\n\t * @param quietPeriod the amount of time required after a change has been detected to\n\t * ensure that updates have completed\n\t */\n\tpublic FileSystemWatcher(boolean daemon, Duration pollInterval, Duration quietPeriod) {\n\t\tthis(daemon, pollInterval, quietPeriod, null);\n\t}\n\n\t/**\n\t * Create a new {@link FileSystemWatcher} instance.\n\t * @param daemon if a daemon thread used to monitor changes\n\t * @param pollInterval the amount of time to wait between checking for changes\n\t * @param quietPeriod the amount of time required after a change has been detected to\n\t * ensure that updates have completed\n\t * @param snapshotStateRepository the snapshot state repository\n\t * @since 2.4.0\n\t */\n\tpublic FileSystemWatcher(boolean daemon, Duration pollInterval, Duration quietPeriod,\n\t\t\t@Nullable SnapshotStateRepository snapshotStateRepository) {\n\t\tAssert.notNull(pollInterval, \"'pollInterval' must not be null\");\n\t\tAssert.notNull(quietPeriod, \"'quietPeriod' must not be null\");\n\t\tAssert.isTrue(pollInterval.toMillis() > 0, \"'pollInterval' must be positive\");\n\t\tAssert.isTrue(quietPeriod.toMillis() > 0, \"'quietPeriod' must be positive\");\n\t\tAssert.isTrue(pollInterval.toMillis() > quietPeriod.toMillis(),\n\t\t\t\t\"'pollInterval' must be greater than QuietPeriod\");\n\t\tthis.daemon = daemon;\n\t\tthis.pollInterval = pollInterval.toMillis();\n\t\tthis.quietPeriod = quietPeriod.toMillis();\n\t\tthis.snapshotStateRepository = (snapshotStateRepository != null) ? snapshotStateRepository\n\t\t\t\t: SnapshotStateRepository.NONE;\n\t}\n\n\t/**\n\t * Add listener for file change events. Cannot be called after the watcher has been\n\t * {@link #start() started}.\n\t * @param fileChangeListener the listener to add\n\t */\n\tpublic void addListener(FileChangeListener fileChangeListener) {\n\t\tAssert.notNull(fileChangeListener, \"'fileChangeListener' must not be null\");\n\t\tsynchronized (this.monitor) {\n\t\t\tcheckNotStarted();\n\t\t\tthis.listeners.add(fileChangeListener);\n\t\t}\n\t}\n\n\t/**\n\t * Add source directories to monitor. Cannot be called after the watcher has been\n\t * {@link #start() started}.\n\t * @param directories the directories to monitor\n\t */\n\tpublic void addSourceDirectories(Iterable<File> directories) {\n\t\tAssert.notNull(directories, \"'directories' must not be null\");\n\t\tsynchronized (this.monitor) {\n\t\t\tdirectories.forEach(this::addSourceDirectory);\n\t\t}\n\t}\n\n\t/**\n\t * Add a source directory to monitor. Cannot be called after the watcher has been\n\t * {@link #start() started}.\n\t * @param directory the directory to monitor\n\t */\n\tpublic void addSourceDirectory(File directory) {\n\t\tAssert.notNull(directory, \"'directory' must not be null\");\n\t\tAssert.isTrue(!directory.isFile(), () -> \"'directory' [%s] must not be a file\".formatted(directory));\n\t\tsynchronized (this.monitor) {\n\t\t\tcheckNotStarted();\n\t\t\tthis.directories.put(directory, null);\n\t\t}\n\t}\n\n\t/**\n\t * Set an optional {@link FileFilter} used to limit the files that trigger a change.\n\t * @param triggerFilter a trigger filter or null\n\t */\n\tpublic void setTriggerFilter(@Nullable FileFilter triggerFilter) {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.triggerFilter = triggerFilter;\n\t\t}\n\t}\n\n\tprivate void checkNotStarted() {\n\t\tAssert.state(this.watchThread == null, \"FileSystemWatcher already started\");\n\t}\n\n\t/**\n\t * Start monitoring the source directory for changes.\n\t */\n\tpublic void start() {\n\t\tsynchronized (this.monitor) {\n\t\t\tcreateOrRestoreInitialSnapshots();\n\t\t\tif (this.watchThread == null) {\n\t\t\t\tMap<File, DirectorySnapshot> localDirectories = new HashMap<>(this.directories);\n\t\t\t\tWatcher watcher = new Watcher(this.remainingScans, new ArrayList<>(this.listeners), this.triggerFilter,\n\t\t\t\t\t\tthis.pollInterval, this.quietPeriod, localDirectories, this.snapshotStateRepository);\n\t\t\t\tthis.watchThread = new Thread(watcher);\n\t\t\t\tthis.watchThread.setName(\"File Watcher\");\n\t\t\t\tthis.watchThread.setDaemon(this.daemon);\n\t\t\t\tthis.watchThread.start();\n\t\t\t}\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void createOrRestoreInitialSnapshots() {\n\t\tMap<File, DirectorySnapshot> restored = (Map<File, DirectorySnapshot>) this.snapshotStateRepository.restore();\n\t\tthis.directories.replaceAll((f, v) -> {\n\t\t\tDirectorySnapshot restoredSnapshot = (restored != null) ? restored.get(f) : null;\n\t\t\treturn (restoredSnapshot != null) ? restoredSnapshot : new DirectorySnapshot(f);\n\t\t});\n\t}\n\n\t/**\n\t * Stop monitoring the source directories.\n\t */\n\tpublic void stop() {\n\t\tstopAfter(0);\n\t}\n\n\t/**\n\t * Stop monitoring the source directories.\n\t * @param remainingScans the number of remaining scans\n\t */\n\tvoid stopAfter(int remainingScans) {\n\t\tThread thread;\n\t\tsynchronized (this.monitor) {\n\t\t\tthread = this.watchThread;\n\t\t\tif (thread != null) {\n\t\t\t\tthis.remainingScans.set(remainingScans);\n\t\t\t\tif (remainingScans <= 0) {\n\t\t\t\t\tthread.interrupt();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.watchThread = null;\n\t\t}\n\t\tif (thread != null && Thread.currentThread() != thread) {\n\t\t\ttry {\n\t\t\t\tthread.join();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static final class Watcher implements Runnable {\n\n\t\tprivate final AtomicInteger remainingScans;\n\n\t\tprivate final List<FileChangeListener> listeners;\n\n\t\tprivate final @Nullable FileFilter triggerFilter;\n\n\t\tprivate final long pollInterval;\n\n\t\tprivate final long quietPeriod;\n\n\t\tprivate Map<File, DirectorySnapshot> directories;\n\n\t\tprivate final SnapshotStateRepository snapshotStateRepository;\n\n\t\tprivate Watcher(AtomicInteger remainingScans, List<FileChangeListener> listeners,\n\t\t\t\t@Nullable FileFilter triggerFilter, long pollInterval, long quietPeriod,\n\t\t\t\tMap<File, DirectorySnapshot> directories, SnapshotStateRepository snapshotStateRepository) {\n\t\t\tthis.remainingScans = remainingScans;\n\t\t\tthis.listeners = listeners;\n\t\t\tthis.triggerFilter = triggerFilter;\n\t\t\tthis.pollInterval = pollInterval;\n\t\t\tthis.quietPeriod = quietPeriod;\n\t\t\tthis.directories = directories;\n\t\t\tthis.snapshotStateRepository = snapshotStateRepository;\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\tint remainingScans = this.remainingScans.get();\n\t\t\twhile (remainingScans > 0 || remainingScans == -1) {\n\t\t\t\ttry {\n\t\t\t\t\tif (remainingScans > 0) {\n\t\t\t\t\t\tthis.remainingScans.decrementAndGet();\n\t\t\t\t\t}\n\t\t\t\t\tscan();\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t\tremainingScans = this.remainingScans.get();\n\t\t\t}\n\t\t}\n\n\t\tprivate void scan() throws InterruptedException {\n\t\t\tThread.sleep(this.pollInterval - this.quietPeriod);\n\t\t\tMap<File, DirectorySnapshot> previous;\n\t\t\tMap<File, DirectorySnapshot> current = this.directories;\n\t\t\tdo {\n\t\t\t\tprevious = current;\n\t\t\t\tcurrent = getCurrentSnapshots();\n\t\t\t\tThread.sleep(this.quietPeriod);\n\t\t\t}\n\t\t\twhile (isDifferent(previous, current));\n\t\t\tif (isDifferent(this.directories, current)) {\n\t\t\t\tupdateSnapshots(current.values());\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isDifferent(Map<File, DirectorySnapshot> previous, Map<File, DirectorySnapshot> current) {\n\t\t\tif (!previous.keySet().equals(current.keySet())) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (Map.Entry<File, DirectorySnapshot> entry : previous.entrySet()) {\n\t\t\t\tDirectorySnapshot previousDirectory = entry.getValue();\n\t\t\t\tDirectorySnapshot currentDirectory = current.get(entry.getKey());\n\t\t\t\tAssert.state(currentDirectory != null, \"'currentDirectory' must not be null\");\n\t\t\t\tif (!previousDirectory.equals(currentDirectory, this.triggerFilter)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate Map<File, DirectorySnapshot> getCurrentSnapshots() {\n\t\t\tMap<File, DirectorySnapshot> snapshots = new LinkedHashMap<>();\n\t\t\tfor (File directory : this.directories.keySet()) {\n\t\t\t\tsnapshots.put(directory, new DirectorySnapshot(directory));\n\t\t\t}\n\t\t\treturn snapshots;\n\t\t}\n\n\t\tprivate void updateSnapshots(Collection<DirectorySnapshot> snapshots) {\n\t\t\tMap<File, DirectorySnapshot> updated = new LinkedHashMap<>();\n\t\t\tSet<ChangedFiles> changeSet = new LinkedHashSet<>();\n\t\t\tfor (DirectorySnapshot snapshot : snapshots) {\n\t\t\t\tDirectorySnapshot previous = this.directories.get(snapshot.getDirectory());\n\t\t\t\tupdated.put(snapshot.getDirectory(), snapshot);\n\t\t\t\tAssert.state(previous != null, \"'previous' must not be null\");\n\t\t\t\tChangedFiles changedFiles = previous.getChangedFiles(snapshot, this.triggerFilter);\n\t\t\t\tif (!changedFiles.getFiles().isEmpty()) {\n\t\t\t\t\tchangeSet.add(changedFiles);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.directories = updated;\n\t\t\tthis.snapshotStateRepository.save(updated);\n\t\t\tif (!changeSet.isEmpty()) {\n\t\t\t\tfireListeners(Collections.unmodifiableSet(changeSet));\n\t\t\t}\n\t\t}\n\n\t\tprivate void fireListeners(Set<ChangedFiles> changeSet) {\n\t\t\tfor (FileChangeListener listener : this.listeners) {\n\t\t\t\tlistener.onChange(changeSet);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\n/**\n * Factory used to create new {@link FileSystemWatcher} instances.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface FileSystemWatcherFactory {\n\n\t/**\n\t * Create a new {@link FileSystemWatcher}.\n\t * @return a new {@link FileSystemWatcher}\n\t */\n\tFileSystemWatcher getFileSystemWatcher();\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/SnapshotStateRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Repository used by {@link FileSystemWatcher} to save file/directory snapshots across\n * restarts.\n *\n * @author Phillip Webb\n * @since 2.4.0\n */\npublic interface SnapshotStateRepository {\n\n\t/**\n\t * A No-op {@link SnapshotStateRepository} that does not save state.\n\t */\n\tSnapshotStateRepository NONE = new SnapshotStateRepository() {\n\n\t\t@Override\n\t\tpublic void save(Object state) {\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object restore() {\n\t\t\treturn null;\n\t\t}\n\n\t};\n\n\t/**\n\t * A {@link SnapshotStateRepository} that uses a static instance to keep state across\n\t * restarts.\n\t */\n\tSnapshotStateRepository STATIC = StaticSnapshotStateRepository.INSTANCE;\n\n\t/**\n\t * Save the given state in the repository.\n\t * @param state the state to save\n\t */\n\tvoid save(Object state);\n\n\t/**\n\t * Restore any previously saved state.\n\t * @return the previously saved state or {@code null}\n\t */\n\t@Nullable Object restore();\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/StaticSnapshotStateRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link SnapshotStateRepository} that uses a single static instance.\n *\n * @author Phillip Webb\n */\nclass StaticSnapshotStateRepository implements SnapshotStateRepository {\n\n\tstatic final StaticSnapshotStateRepository INSTANCE = new StaticSnapshotStateRepository();\n\n\tprivate volatile @Nullable Object state;\n\n\t@Override\n\tpublic void save(Object state) {\n\t\tthis.state = state;\n\t}\n\n\t@Override\n\tpublic @Nullable Object restore() {\n\t\treturn this.state;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/filewatch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Class to watch the local filesystem for changes.\n */\n@NullMarked\npackage org.springframework.boot.devtools.filewatch;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Connection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link LiveReloadServer} connection.\n *\n * @author Phillip Webb\n * @author Francis Lavoie\n */\n@SuppressWarnings(\"removal\")\nclass Connection {\n\n\tprivate static final Log logger = LogFactory.getLog(Connection.class);\n\n\tprivate static final Pattern WEBSOCKET_KEY_PATTERN = Pattern.compile(\"^sec-websocket-key:(.*)$\",\n\t\t\tPattern.MULTILINE | Pattern.CASE_INSENSITIVE);\n\n\tpublic static final String WEBSOCKET_GUID = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n\n\tprivate final Socket socket;\n\n\tprivate final ConnectionInputStream inputStream;\n\n\tprivate final ConnectionOutputStream outputStream;\n\n\tprivate final String header;\n\n\tprivate volatile boolean webSocket;\n\n\tprivate volatile boolean running = true;\n\n\t/**\n\t * Create a new {@link Connection} instance.\n\t * @param socket the source socket\n\t * @param inputStream the socket input stream\n\t * @param outputStream the socket output stream\n\t * @throws IOException in case of I/O errors\n\t */\n\tConnection(Socket socket, InputStream inputStream, OutputStream outputStream) throws IOException {\n\t\tthis.socket = socket;\n\t\tthis.inputStream = new ConnectionInputStream(inputStream);\n\t\tthis.outputStream = new ConnectionOutputStream(outputStream);\n\t\tString header = this.inputStream.readHeader();\n\t\tlogger.debug(LogMessage.format(\"Established livereload connection [%s]\", header));\n\t\tthis.header = header;\n\t}\n\n\t/**\n\t * Run the connection.\n\t * @throws Exception in case of errors\n\t */\n\tvoid run() throws Exception {\n\t\tString lowerCaseHeader = this.header.toLowerCase(Locale.ROOT);\n\t\tif (lowerCaseHeader.contains(\"upgrade: websocket\") && lowerCaseHeader.contains(\"sec-websocket-version: 13\")) {\n\t\t\trunWebSocket();\n\t\t}\n\t\tif (lowerCaseHeader.contains(\"get /livereload.js\")) {\n\t\t\tInputStream stream = getClass().getResourceAsStream(\"livereload.js\");\n\t\t\tAssert.state(stream != null, \"Resource 'livereload.js' not found\");\n\t\t\tthis.outputStream.writeHttp(stream, \"text/javascript\");\n\t\t}\n\t}\n\n\tprivate void runWebSocket() throws Exception {\n\t\tthis.webSocket = true;\n\t\tString accept = getWebsocketAcceptResponse();\n\t\tthis.outputStream.writeHeaders(\"HTTP/1.1 101 Switching Protocols\", \"Upgrade: websocket\", \"Connection: Upgrade\",\n\t\t\t\t\"Sec-WebSocket-Accept: \" + accept);\n\t\tnew Frame(\"{\\\"command\\\":\\\"hello\\\",\\\"protocols\\\":[\\\"http://livereload.com/protocols/official-7\\\"],\"\n\t\t\t\t+ \"\\\"serverName\\\":\\\"spring-boot\\\"}\")\n\t\t\t.write(this.outputStream);\n\t\twhile (this.running) {\n\t\t\treadWebSocketFrame();\n\t\t}\n\t}\n\n\tprivate void readWebSocketFrame() throws IOException {\n\t\ttry {\n\t\t\tFrame frame = Frame.read(this.inputStream);\n\t\t\tif (frame.getType() == Frame.Type.PING) {\n\t\t\t\twriteWebSocketFrame(new Frame(Frame.Type.PONG));\n\t\t\t}\n\t\t\telse if (frame.getType() == Frame.Type.CLOSE) {\n\t\t\t\tthrow new ConnectionClosedException();\n\t\t\t}\n\t\t\telse if (frame.getType() == Frame.Type.TEXT) {\n\t\t\t\tlogger.debug(LogMessage.format(\"Received LiveReload text frame %s\", frame));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IOException(\"Unexpected Frame Type \" + frame.getType());\n\t\t\t}\n\t\t}\n\t\tcatch (SocketTimeoutException ex) {\n\t\t\twriteWebSocketFrame(new Frame(Frame.Type.PING));\n\t\t\tFrame frame = Frame.read(this.inputStream);\n\t\t\tif (frame.getType() != Frame.Type.PONG) {\n\t\t\t\tthrow new IllegalStateException(\"No Pong\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Trigger livereload for the client using this connection.\n\t * @throws IOException in case of I/O errors\n\t */\n\tvoid triggerReload() throws IOException {\n\t\tif (this.webSocket) {\n\t\t\tlogger.debug(\"Triggering LiveReload\");\n\t\t\twriteWebSocketFrame(new Frame(\"{\\\"command\\\":\\\"reload\\\",\\\"path\\\":\\\"/\\\"}\"));\n\t\t}\n\t}\n\n\tprivate void writeWebSocketFrame(Frame frame) throws IOException {\n\t\tframe.write(this.outputStream);\n\t}\n\n\tprivate String getWebsocketAcceptResponse() throws NoSuchAlgorithmException {\n\t\tMatcher matcher = WEBSOCKET_KEY_PATTERN.matcher(this.header);\n\t\tAssert.state(matcher.find(), \"No Sec-WebSocket-Key\");\n\t\tString response = matcher.group(1).trim() + WEBSOCKET_GUID;\n\t\tMessageDigest messageDigest = MessageDigest.getInstance(\"SHA-1\");\n\t\tmessageDigest.update(response.getBytes(), 0, response.length());\n\t\treturn Base64.getEncoder().encodeToString(messageDigest.digest());\n\t}\n\n\t/**\n\t * Close the connection.\n\t * @throws IOException in case of I/O errors\n\t */\n\tvoid close() throws IOException {\n\t\tthis.running = false;\n\t\tthis.socket.close();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionClosedException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.IOException;\n\n/**\n * Exception throw when the client closes the connection.\n *\n * @author Phillip Webb\n */\nclass ConnectionClosedException extends IOException {\n\n\tConnectionClosedException() {\n\t\tsuper(\"Connection closed\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionInputStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * {@link InputStream} for a server connection.\n *\n * @author Phillip Webb\n */\nclass ConnectionInputStream extends FilterInputStream {\n\n\tprivate static final String HEADER_END = \"\\r\\n\\r\\n\";\n\n\tprivate static final int BUFFER_SIZE = 4096;\n\n\tConnectionInputStream(InputStream in) {\n\t\tsuper(in);\n\t}\n\n\t/**\n\t * Read the HTTP header from the {@link InputStream}. Note: This method doesn't expect\n\t * any HTTP content after the header since the initial request is usually just a\n\t * WebSocket upgrade.\n\t * @return the HTTP header\n\t * @throws IOException in case of I/O errors\n\t */\n\tString readHeader() throws IOException {\n\t\tbyte[] buffer = new byte[BUFFER_SIZE];\n\t\tStringBuilder content = new StringBuilder(BUFFER_SIZE);\n\t\twhile (content.indexOf(HEADER_END) == -1) {\n\t\t\tint amountRead = checkedRead(buffer, 0, BUFFER_SIZE);\n\t\t\tcontent.append(new String(buffer, 0, amountRead));\n\t\t}\n\t\treturn content.substring(0, content.indexOf(HEADER_END));\n\t}\n\n\t/**\n\t * Repeatedly read the underlying {@link InputStream} until the requested number of\n\t * bytes have been loaded.\n\t * @param buffer the destination buffer\n\t * @param offset the buffer offset\n\t * @param length the amount of data to read\n\t * @throws IOException in case of I/O errors\n\t */\n\tvoid readFully(byte[] buffer, int offset, int length) throws IOException {\n\t\twhile (length > 0) {\n\t\t\tint amountRead = checkedRead(buffer, offset, length);\n\t\t\toffset += amountRead;\n\t\t\tlength -= amountRead;\n\t\t}\n\t}\n\n\t/**\n\t * Read a single byte from the stream (checking that the end of the stream hasn't been\n\t * reached).\n\t * @return the content\n\t * @throws IOException in case of I/O errors\n\t */\n\tint checkedRead() throws IOException {\n\t\tint b = read();\n\t\tif (b == -1) {\n\t\t\tthrow new IOException(\"End of stream\");\n\t\t}\n\t\treturn (b & 0xff);\n\t}\n\n\t/**\n\t * Read a number of bytes from the stream (checking that the end of the stream hasn't\n\t * been reached).\n\t * @param buffer the destination buffer\n\t * @param offset the buffer offset\n\t * @param length the length to read\n\t * @return the amount of data read\n\t * @throws IOException in case of I/O errors\n\t */\n\tint checkedRead(byte[] buffer, int offset, int length) throws IOException {\n\t\tint amountRead = read(buffer, offset, length);\n\t\tif (amountRead == -1) {\n\t\t\tthrow new IOException(\"End of stream\");\n\t\t}\n\t\treturn amountRead;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/ConnectionOutputStream.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * {@link OutputStream} for a server connection.\n *\n * @author Phillip Webb\n */\nclass ConnectionOutputStream extends FilterOutputStream {\n\n\tConnectionOutputStream(OutputStream out) {\n\t\tsuper(out);\n\t}\n\n\t@Override\n\tpublic void write(byte[] b, int off, int len) throws IOException {\n\t\tthis.out.write(b, off, len);\n\t}\n\n\tvoid writeHttp(InputStream content, String contentType) throws IOException {\n\t\tbyte[] bytes = FileCopyUtils.copyToByteArray(content);\n\t\twriteHeaders(\"HTTP/1.1 200 OK\", \"Content-Type: \" + contentType, \"Content-Length: \" + bytes.length,\n\t\t\t\t\"Connection: close\");\n\t\twrite(bytes);\n\t\tflush();\n\t}\n\n\tvoid writeHeaders(String... headers) throws IOException {\n\t\tStringBuilder response = new StringBuilder();\n\t\tfor (String header : headers) {\n\t\t\tresponse.append(header).append(\"\\r\\n\");\n\t\t}\n\t\tresponse.append(\"\\r\\n\");\n\t\twrite(response.toString().getBytes());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/Frame.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.springframework.util.Assert;\n\n/**\n * A limited implementation of a WebSocket Frame used to carry LiveReload data.\n *\n * @author Phillip Webb\n */\nclass Frame {\n\n\tprivate static final byte[] NO_BYTES = new byte[0];\n\n\tprivate final Type type;\n\n\tprivate final byte[] payload;\n\n\t/**\n\t * Create a new {@link Type#TEXT text} {@link Frame} instance with the specified\n\t * payload.\n\t * @param payload the text payload\n\t */\n\tFrame(String payload) {\n\t\tAssert.notNull(payload, \"'payload' must not be null\");\n\t\tthis.type = Type.TEXT;\n\t\tthis.payload = payload.getBytes();\n\t}\n\n\tFrame(Type type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tthis.type = type;\n\t\tthis.payload = NO_BYTES;\n\t}\n\n\tFrame(Type type, byte[] payload) {\n\t\tthis.type = type;\n\t\tthis.payload = payload;\n\t}\n\n\tType getType() {\n\t\treturn this.type;\n\t}\n\n\tbyte[] getPayload() {\n\t\treturn this.payload;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn new String(this.payload);\n\t}\n\n\tvoid write(OutputStream outputStream) throws IOException {\n\t\toutputStream.write(0x80 | this.type.code);\n\t\tif (this.payload.length < 126) {\n\t\t\toutputStream.write(this.payload.length & 0x7F);\n\t\t}\n\t\telse {\n\t\t\toutputStream.write(0x7E);\n\t\t\toutputStream.write(this.payload.length >> 8 & 0xFF);\n\t\t\toutputStream.write(this.payload.length & 0xFF);\n\t\t}\n\t\toutputStream.write(this.payload);\n\t\toutputStream.flush();\n\t}\n\n\tstatic Frame read(ConnectionInputStream inputStream) throws IOException {\n\t\tint firstByte = inputStream.checkedRead();\n\t\tAssert.state((firstByte & 0x80) != 0, \"Fragmented frames are not supported\");\n\t\tint maskAndLength = inputStream.checkedRead();\n\t\tboolean hasMask = (maskAndLength & 0x80) != 0;\n\t\tint length = (maskAndLength & 0x7F);\n\t\tAssert.state(length != 127, \"Large frames are not supported\");\n\t\tif (length == 126) {\n\t\t\tlength = ((inputStream.checkedRead()) << 8 | inputStream.checkedRead());\n\t\t}\n\t\tbyte[] mask = new byte[4];\n\t\tif (hasMask) {\n\t\t\tinputStream.readFully(mask, 0, mask.length);\n\t\t}\n\t\tbyte[] payload = new byte[length];\n\t\tinputStream.readFully(payload, 0, length);\n\t\tif (hasMask) {\n\t\t\tfor (int i = 0; i < payload.length; i++) {\n\t\t\t\tpayload[i] ^= mask[i % 4];\n\t\t\t}\n\t\t}\n\t\treturn new Frame(Type.forCode(firstByte & 0x0F), payload);\n\t}\n\n\t/**\n\t * Frame types.\n\t */\n\tenum Type {\n\n\t\t/**\n\t\t * Continuation frame.\n\t\t */\n\t\tCONTINUATION(0x00),\n\n\t\t/**\n\t\t * Text frame.\n\t\t */\n\t\tTEXT(0x01),\n\n\t\t/**\n\t\t * Binary frame.\n\t\t */\n\t\tBINARY(0x02),\n\n\t\t/**\n\t\t * Close frame.\n\t\t */\n\t\tCLOSE(0x08),\n\n\t\t/**\n\t\t * Ping frame.\n\t\t */\n\t\tPING(0x09),\n\n\t\t/**\n\t\t * Pong frame.\n\t\t */\n\t\tPONG(0x0A);\n\n\t\tprivate final int code;\n\n\t\tType(int code) {\n\t\t\tthis.code = code;\n\t\t}\n\n\t\tstatic Type forCode(int code) {\n\t\t\tfor (Type type : values()) {\n\t\t\t\tif (type.code == code) {\n\t\t\t\t\treturn type;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unknown code \" + code);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/LiveReloadServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\n\n/**\n * A <a href=\"https://github.com/livereload\">livereload</a> server.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @deprecated since 4.1.0 for removal in 4.3.0 with no replacement.\n */\n@Deprecated(since = \"4.1.0\", forRemoval = true)\npublic class LiveReloadServer {\n\n\t/**\n\t * The default live reload server port.\n\t */\n\tpublic static final int DEFAULT_PORT = 35729;\n\n\tprivate static final Log logger = LogFactory.getLog(LiveReloadServer.class);\n\n\tprivate static final int READ_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(4);\n\n\tprivate final ExecutorService executor = Executors.newCachedThreadPool(new WorkerThreadFactory());\n\n\tprivate final List<Connection> connections = new ArrayList<>();\n\n\tprivate final Object monitor = new Object();\n\n\tprivate final int port;\n\n\tprivate final ThreadFactory threadFactory;\n\n\tprivate @Nullable ServerSocket serverSocket;\n\n\tprivate @Nullable Thread listenThread;\n\n\t/**\n\t * Create a new {@link LiveReloadServer} listening on the default port.\n\t */\n\tpublic LiveReloadServer() {\n\t\tthis(DEFAULT_PORT);\n\t}\n\n\t/**\n\t * Create a new {@link LiveReloadServer} listening on the default port with a specific\n\t * {@link ThreadFactory}.\n\t * @param threadFactory the thread factory\n\t */\n\tpublic LiveReloadServer(ThreadFactory threadFactory) {\n\t\tthis(DEFAULT_PORT, threadFactory);\n\t}\n\n\t/**\n\t * Create a new {@link LiveReloadServer} listening on the specified port.\n\t * @param port the listen port\n\t */\n\tpublic LiveReloadServer(int port) {\n\t\tthis(port, Thread::new);\n\t}\n\n\t/**\n\t * Create a new {@link LiveReloadServer} listening on the specified port with a\n\t * specific {@link ThreadFactory}.\n\t * @param port the listen port\n\t * @param threadFactory the thread factory\n\t */\n\tpublic LiveReloadServer(int port, ThreadFactory threadFactory) {\n\t\tthis.port = port;\n\t\tthis.threadFactory = threadFactory;\n\t}\n\n\t/**\n\t * Start the livereload server and accept incoming connections.\n\t * @return the port on which the server is listening\n\t * @throws IOException in case of I/O errors\n\t */\n\tpublic int start() throws IOException {\n\t\tsynchronized (this.monitor) {\n\t\t\tAssert.state(!isStarted(), \"Server already started\");\n\t\t\tlogger.debug(LogMessage.format(\"Starting live reload server on port %s\", this.port));\n\t\t\tthis.serverSocket = new ServerSocket(this.port);\n\t\t\tint localPort = this.serverSocket.getLocalPort();\n\t\t\tthis.listenThread = this.threadFactory.newThread(this::acceptConnections);\n\t\t\tthis.listenThread.setDaemon(true);\n\t\t\tthis.listenThread.setName(\"Live Reload Server\");\n\t\t\tthis.listenThread.start();\n\t\t\treturn localPort;\n\t\t}\n\t}\n\n\t/**\n\t * Return if the server has been started.\n\t * @return {@code true} if the server is running\n\t */\n\tpublic boolean isStarted() {\n\t\tsynchronized (this.monitor) {\n\t\t\treturn this.listenThread != null;\n\t\t}\n\t}\n\n\t/**\n\t * Return the port that the server is listening on.\n\t * @return the server port\n\t */\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\tprivate void acceptConnections() {\n\t\tAssert.state(this.serverSocket != null, \"'serverSocket' must not be null\");\n\t\tdo {\n\t\t\ttry {\n\t\t\t\tSocket socket = this.serverSocket.accept();\n\t\t\t\tsocket.setSoTimeout(READ_TIMEOUT);\n\t\t\t\tthis.executor.execute(new ConnectionHandler(socket));\n\t\t\t}\n\t\t\tcatch (SocketTimeoutException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\tlogger.debug(\"LiveReload server error\", ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twhile (!this.serverSocket.isClosed());\n\t}\n\n\t/**\n\t * Gracefully stop the livereload server.\n\t * @throws IOException in case of I/O errors\n\t */\n\tpublic void stop() throws IOException {\n\t\tsynchronized (this.monitor) {\n\t\t\tif (this.listenThread != null) {\n\t\t\t\tcloseAllConnections();\n\t\t\t\ttry {\n\t\t\t\t\tthis.executor.shutdown();\n\t\t\t\t\tthis.executor.awaitTermination(1, TimeUnit.MINUTES);\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t\tAssert.state(this.serverSocket != null, \"'serverSocket' must not be null\");\n\t\t\t\tthis.serverSocket.close();\n\t\t\t\ttry {\n\t\t\t\t\tthis.listenThread.join();\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t\tthis.listenThread = null;\n\t\t\t\tthis.serverSocket = null;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void closeAllConnections() throws IOException {\n\t\tsynchronized (this.connections) {\n\t\t\tfor (Connection connection : this.connections) {\n\t\t\t\tconnection.close();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Trigger livereload of all connected clients.\n\t */\n\tpublic void triggerReload() {\n\t\tsynchronized (this.monitor) {\n\t\t\tsynchronized (this.connections) {\n\t\t\t\tfor (Connection connection : this.connections) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconnection.triggerReload();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t\tlogger.debug(\"Unable to send reload message\", ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void addConnection(Connection connection) {\n\t\tsynchronized (this.connections) {\n\t\t\tthis.connections.add(connection);\n\t\t}\n\t}\n\n\tprivate void removeConnection(Connection connection) {\n\t\tsynchronized (this.connections) {\n\t\t\tthis.connections.remove(connection);\n\t\t}\n\t}\n\n\t/**\n\t * Factory method used to create the {@link Connection}.\n\t * @param socket the source socket\n\t * @param inputStream the socket input stream\n\t * @param outputStream the socket output stream\n\t * @return a connection\n\t * @throws IOException in case of I/O errors\n\t */\n\tprotected Connection createConnection(Socket socket, InputStream inputStream, OutputStream outputStream)\n\t\t\tthrows IOException {\n\t\treturn new Connection(socket, inputStream, outputStream);\n\t}\n\n\t/**\n\t * {@link Runnable} to handle a single connection.\n\t *\n\t * @see Connection\n\t */\n\tprivate class ConnectionHandler implements Runnable {\n\n\t\tprivate final Socket socket;\n\n\t\tprivate final InputStream inputStream;\n\n\t\tConnectionHandler(Socket socket) throws IOException {\n\t\t\tthis.socket = socket;\n\t\t\tthis.inputStream = socket.getInputStream();\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\ttry {\n\t\t\t\thandle();\n\t\t\t}\n\t\t\tcatch (ConnectionClosedException ex) {\n\t\t\t\tlogger.debug(\"LiveReload connection closed\");\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\tlogger.debug(\"LiveReload error\", ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void handle() throws Exception {\n\t\t\ttry {\n\t\t\t\ttry (OutputStream outputStream = this.socket.getOutputStream()) {\n\t\t\t\t\tConnection connection = createConnection(this.socket, this.inputStream, outputStream);\n\t\t\t\t\trunConnection(connection);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tthis.inputStream.close();\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.socket.close();\n\t\t\t}\n\t\t}\n\n\t\tprivate void runConnection(Connection connection) throws Exception {\n\t\t\ttry {\n\t\t\t\taddConnection(connection);\n\t\t\t\tconnection.run();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tremoveConnection(connection);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ThreadFactory} to create the worker threads.\n\t */\n\tprivate static final class WorkerThreadFactory implements ThreadFactory {\n\n\t\tprivate final AtomicInteger threadNumber = new AtomicInteger(1);\n\n\t\t@Override\n\t\tpublic Thread newThread(Runnable r) {\n\t\t\tThread thread = new Thread(r);\n\t\t\tthread.setDaemon(true);\n\t\t\tthread.setName(\"Live Reload #\" + this.threadNumber.getAndIncrement());\n\t\t\treturn thread;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/livereload/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for the livereload protocol.\n */\n@NullMarked\npackage org.springframework.boot.devtools.livereload;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/DevToolsLogFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.logger;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\n\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.logging.DeferredLog;\nimport org.springframework.context.ApplicationListener;\n\n/**\n * Devtools deferred logging support.\n *\n * @author Phillip Webb\n * @since 2.1.0\n */\npublic final class DevToolsLogFactory {\n\n\tprivate static final Map<Log, Class<?>> logs = new LinkedHashMap<>();\n\n\tprivate DevToolsLogFactory() {\n\t}\n\n\t/**\n\t * Get a {@link Log} instance for the specified source that will be automatically\n\t * {@link DeferredLog#switchTo(Class) switched} when the\n\t * {@link ApplicationPreparedEvent context is prepared}.\n\t * @param source the source for logging\n\t * @return a {@link DeferredLog} instance\n\t */\n\tpublic static Log getLog(Class<?> source) {\n\t\tsynchronized (logs) {\n\t\t\tLog log = new DeferredLog();\n\t\t\tlogs.put(log, source);\n\t\t\treturn log;\n\t\t}\n\t}\n\n\t/**\n\t * Listener used to log and switch when the context is ready.\n\t */\n\tstatic class Listener implements ApplicationListener<ApplicationPreparedEvent> {\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationPreparedEvent event) {\n\t\t\tsynchronized (logs) {\n\t\t\t\tlogs.forEach((log, source) -> {\n\t\t\t\t\tif (log instanceof DeferredLog deferredLog) {\n\t\t\t\t\t\tdeferredLog.switchTo(source);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tlogs.clear();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/logger/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Devtools specific logging concerns.\n */\n@NullMarked\npackage org.springframework.boot.devtools.logger;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot developer tools.\n */\n@NullMarked\npackage org.springframework.boot.devtools;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectOutputStream;\nimport java.net.MalformedURLException;\nimport java.net.SocketException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.devtools.classpath.ClassPathChangedEvent;\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.HttpStatusCode;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\n\n/**\n * Listens and pushes any classpath updates to a remote endpoint.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.3.0\n */\npublic class ClassPathChangeUploader implements ApplicationListener<ClassPathChangedEvent> {\n\n\tprivate static final Map<ChangedFile.Type, ClassLoaderFile.Kind> TYPE_MAPPINGS;\n\n\tstatic {\n\t\tMap<ChangedFile.Type, ClassLoaderFile.Kind> map = new EnumMap<>(ChangedFile.Type.class);\n\t\tmap.put(ChangedFile.Type.ADD, ClassLoaderFile.Kind.ADDED);\n\t\tmap.put(ChangedFile.Type.DELETE, ClassLoaderFile.Kind.DELETED);\n\t\tmap.put(ChangedFile.Type.MODIFY, ClassLoaderFile.Kind.MODIFIED);\n\t\tTYPE_MAPPINGS = Collections.unmodifiableMap(map);\n\t}\n\n\tprivate static final Log logger = LogFactory.getLog(ClassPathChangeUploader.class);\n\n\tprivate final URI uri;\n\n\tprivate final ClientHttpRequestFactory requestFactory;\n\n\tpublic ClassPathChangeUploader(String url, ClientHttpRequestFactory requestFactory) {\n\t\tAssert.hasLength(url, \"'url' must not be empty\");\n\t\tAssert.notNull(requestFactory, \"'requestFactory' must not be null\");\n\t\ttry {\n\t\t\tthis.uri = new URL(url).toURI();\n\t\t}\n\t\tcatch (URISyntaxException | MalformedURLException ex) {\n\t\t\tthrow new IllegalArgumentException(\"Malformed URL '\" + url + \"'\");\n\t\t}\n\t\tthis.requestFactory = requestFactory;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ClassPathChangedEvent event) {\n\t\ttry {\n\t\t\tClassLoaderFiles classLoaderFiles = getClassLoaderFiles(event);\n\t\t\tbyte[] bytes = serialize(classLoaderFiles);\n\t\t\tperformUpload(bytes, event);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate void performUpload(byte[] bytes, ClassPathChangedEvent event) throws IOException {\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\ttry {\n\t\t\t\t\tClientHttpRequest request = this.requestFactory.createRequest(this.uri, HttpMethod.POST);\n\t\t\t\t\tHttpHeaders headers = request.getHeaders();\n\t\t\t\t\theaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);\n\t\t\t\t\theaders.setContentLength(bytes.length);\n\t\t\t\t\tFileCopyUtils.copy(bytes, request.getBody());\n\t\t\t\t\tlogUpload(event);\n\t\t\t\t\ttry (ClientHttpResponse response = request.execute()) {\n\t\t\t\t\t\tHttpStatusCode statusCode = response.getStatusCode();\n\t\t\t\t\t\tAssert.state(statusCode == HttpStatus.OK,\n\t\t\t\t\t\t\t\t() -> \"Unexpected \" + statusCode + \" response uploading class files\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcatch (SocketException ex) {\n\t\t\t\t\tlogger.warn(LogMessage.format(\n\t\t\t\t\t\t\t\"A failure occurred when uploading to %s. Upload will be retried in 2 seconds\", this.uri));\n\t\t\t\t\tlogger.debug(\"Upload failure\", ex);\n\t\t\t\t\tThread.sleep(2000);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate void logUpload(ClassPathChangedEvent event) {\n\t\tlogger.info(LogMessage.format(\"Uploading %s\", event.overview()));\n\t}\n\n\tprivate byte[] serialize(ClassLoaderFiles classLoaderFiles) throws IOException {\n\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n\t\tObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);\n\t\tobjectOutputStream.writeObject(classLoaderFiles);\n\t\tobjectOutputStream.close();\n\t\treturn outputStream.toByteArray();\n\t}\n\n\tprivate ClassLoaderFiles getClassLoaderFiles(ClassPathChangedEvent event) throws IOException {\n\t\tClassLoaderFiles files = new ClassLoaderFiles();\n\t\tfor (ChangedFiles changedFiles : event.getChangeSet()) {\n\t\t\tString sourceDirectory = changedFiles.getSourceDirectory().getAbsolutePath();\n\t\t\tfor (ChangedFile changedFile : changedFiles) {\n\t\t\t\tfiles.addFile(sourceDirectory, changedFile.getRelativeName(), asClassLoaderFile(changedFile));\n\t\t\t}\n\t\t}\n\t\treturn files;\n\t}\n\n\tprivate ClassLoaderFile asClassLoaderFile(ChangedFile changedFile) throws IOException {\n\t\tClassLoaderFile.Kind kind = TYPE_MAPPINGS.get(changedFile.getType());\n\t\tAssert.state(kind != null, \"'kind' must not be null\");\n\t\tbyte[] bytes = (kind != Kind.DELETED) ? FileCopyUtils.copyToByteArray(changedFile.getFile()) : null;\n\t\tlong lastModified = (kind != Kind.DELETED) ? changedFile.getFile().lastModified() : System.currentTimeMillis();\n\t\treturn new ClassLoaderFile(kind, lastModified, bytes);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTrigger.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Runnable} that waits to trigger live reload until the remote server has\n * restarted.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass DelayedLiveReloadTrigger implements Runnable {\n\n\tprivate static final long SHUTDOWN_TIME = 1000;\n\n\tprivate static final long SLEEP_TIME = 500;\n\n\tprivate static final long TIMEOUT = 30000;\n\n\tprivate static final Log logger = LogFactory.getLog(DelayedLiveReloadTrigger.class);\n\n\tprivate final OptionalLiveReloadServer liveReloadServer;\n\n\tprivate final ClientHttpRequestFactory requestFactory;\n\n\tprivate final URI uri;\n\n\tprivate long shutdownTime = SHUTDOWN_TIME;\n\n\tprivate long sleepTime = SLEEP_TIME;\n\n\tprivate long timeout = TIMEOUT;\n\n\tDelayedLiveReloadTrigger(OptionalLiveReloadServer liveReloadServer, ClientHttpRequestFactory requestFactory,\n\t\t\tString url) {\n\t\tAssert.notNull(liveReloadServer, \"'liveReloadServer' must not be null\");\n\t\tAssert.notNull(requestFactory, \"'requestFactory' must not be null\");\n\t\tAssert.hasLength(url, \"'url' must not be empty\");\n\t\tthis.liveReloadServer = liveReloadServer;\n\t\tthis.requestFactory = requestFactory;\n\t\ttry {\n\t\t\tthis.uri = new URI(url);\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalArgumentException(ex);\n\t\t}\n\t}\n\n\tprotected void setTimings(long shutdown, long sleep, long timeout) {\n\t\tthis.shutdownTime = shutdown;\n\t\tthis.sleepTime = sleep;\n\t\tthis.timeout = timeout;\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\ttry {\n\t\t\tThread.sleep(this.shutdownTime);\n\t\t\tlong start = System.currentTimeMillis();\n\t\t\twhile (!isUp()) {\n\t\t\t\tlong runTime = System.currentTimeMillis() - start;\n\t\t\t\tif (runTime > this.timeout) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tThread.sleep(this.sleepTime);\n\t\t\t}\n\t\t\tlogger.info(\"Remote server has changed, triggering LiveReload\");\n\t\t\tthis.liveReloadServer.triggerReload();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n\tprivate boolean isUp() {\n\t\ttry {\n\t\t\tClientHttpRequest request = createRequest();\n\t\t\ttry (ClientHttpResponse response = request.execute()) {\n\t\t\t\treturn response.getStatusCode() == HttpStatus.OK;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate ClientHttpRequest createRequest() throws IOException {\n\t\treturn this.requestFactory.createRequest(this.uri, HttpMethod.GET);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/HttpHeaderInterceptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.IOException;\n\nimport org.springframework.http.HttpRequest;\nimport org.springframework.http.client.ClientHttpRequestExecution;\nimport org.springframework.http.client.ClientHttpRequestInterceptor;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ClientHttpRequestInterceptor} to populate arbitrary HTTP headers with a value.\n * For example, it might be used to provide an X-AUTH-TOKEN and value for security\n * purposes.\n *\n * @author Rob Winch\n * @since 1.3.0\n */\npublic class HttpHeaderInterceptor implements ClientHttpRequestInterceptor {\n\n\tprivate final String name;\n\n\tprivate final String value;\n\n\t/**\n\t * Creates a new {@link HttpHeaderInterceptor} instance.\n\t * @param name the header name to populate. Cannot be null or empty.\n\t * @param value the header value to populate. Cannot be null or empty.\n\t */\n\tpublic HttpHeaderInterceptor(String name, String value) {\n\t\tAssert.hasLength(name, \"'name' must not be empty\");\n\t\tAssert.hasLength(value, \"'value' must not be empty\");\n\t\tthis.name = name;\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)\n\t\t\tthrows IOException {\n\t\trequest.getHeaders().add(this.name, this.value);\n\t\treturn execution.execute(request, body);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/RemoteClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.net.InetSocketAddress;\nimport java.net.Proxy.Type;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsProperties;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsProperties.Restart;\nimport org.springframework.boot.devtools.autoconfigure.RemoteDevToolsProperties;\nimport org.springframework.boot.devtools.autoconfigure.RemoteDevToolsProperties.Proxy;\nimport org.springframework.boot.devtools.autoconfigure.TriggerFileFilter;\nimport org.springframework.boot.devtools.classpath.ClassPathChangedEvent;\nimport org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;\nimport org.springframework.boot.devtools.classpath.ClassPathRestartStrategy;\nimport org.springframework.boot.devtools.classpath.PatternClassPathRestartStrategy;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory;\nimport org.springframework.boot.devtools.restart.DefaultRestartInitializer;\nimport org.springframework.boot.devtools.restart.RestartScope;\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpRequestInterceptor;\nimport org.springframework.http.client.InterceptingClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration used to connect to remote Spring Boot applications.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see org.springframework.boot.devtools.RemoteSpringApplication\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(DevToolsProperties.class)\n@SuppressWarnings(\"removal\")\npublic class RemoteClientConfiguration implements InitializingBean {\n\n\tprivate static final Log logger = LogFactory.getLog(RemoteClientConfiguration.class);\n\n\tprivate final DevToolsProperties properties;\n\n\t@Value(\"${remoteUrl}\")\n\tprivate @Nullable String remoteUrl;\n\n\tpublic RemoteClientConfiguration(DevToolsProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\tpublic static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {\n\t\treturn new PropertySourcesPlaceholderConfigurer();\n\t}\n\n\t@Bean\n\tpublic ClientHttpRequestFactory clientHttpRequestFactory() {\n\t\tList<ClientHttpRequestInterceptor> interceptors = Collections.singletonList(getSecurityInterceptor());\n\t\tSimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();\n\t\tProxy proxy = this.properties.getRemote().getProxy();\n\t\tif (proxy.getHost() != null && proxy.getPort() != null) {\n\t\t\trequestFactory\n\t\t\t\t.setProxy(new java.net.Proxy(Type.HTTP, new InetSocketAddress(proxy.getHost(), proxy.getPort())));\n\t\t}\n\t\treturn new InterceptingClientHttpRequestFactory(requestFactory, interceptors);\n\t}\n\n\tprivate ClientHttpRequestInterceptor getSecurityInterceptor() {\n\t\tRemoteDevToolsProperties remoteProperties = this.properties.getRemote();\n\t\tString secretHeaderName = remoteProperties.getSecretHeaderName();\n\t\tString secret = remoteProperties.getSecret();\n\t\tAssert.state(secret != null,\n\t\t\t\t\"The environment value 'spring.devtools.remote.secret' is required to secure your connection.\");\n\t\treturn new HttpHeaderInterceptor(secretHeaderName, secret);\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tlogWarnings();\n\t}\n\n\tprivate void logWarnings() {\n\t\tRemoteDevToolsProperties remoteProperties = this.properties.getRemote();\n\t\tif (!remoteProperties.getRestart().isEnabled()) {\n\t\t\tlogger.warn(\"Remote restart is disabled.\");\n\t\t}\n\t\tif (this.remoteUrl == null || !this.remoteUrl.startsWith(\"https://\")) {\n\t\t\tlogger.warn(LogMessage.format(\n\t\t\t\t\t\"The connection to %s is insecure. You should use a URL starting with 'https://'.\",\n\t\t\t\t\tthis.remoteUrl));\n\t\t}\n\t}\n\n\t/**\n\t * LiveReload configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.devtools.livereload.enabled\")\n\tstatic class LiveReloadConfiguration {\n\n\t\tprivate final DevToolsProperties properties;\n\n\t\tprivate final ClientHttpRequestFactory clientHttpRequestFactory;\n\n\t\tprivate final String remoteUrl;\n\n\t\tprivate final ExecutorService executor = Executors.newSingleThreadExecutor();\n\n\t\tLiveReloadConfiguration(DevToolsProperties properties, ClientHttpRequestFactory clientHttpRequestFactory,\n\t\t\t\t@Value(\"${remoteUrl}\") String remoteUrl) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.clientHttpRequestFactory = clientHttpRequestFactory;\n\t\t\tthis.remoteUrl = remoteUrl;\n\t\t}\n\n\t\t@Bean\n\t\t@RestartScope\n\t\t@ConditionalOnMissingBean\n\t\torg.springframework.boot.devtools.livereload.LiveReloadServer liveReloadServer() {\n\t\t\treturn new org.springframework.boot.devtools.livereload.LiveReloadServer(\n\t\t\t\t\tthis.properties.getLivereload().getPort(), Restarter.getInstance().getThreadFactory());\n\t\t}\n\n\t\t@Bean\n\t\tApplicationListener<ClassPathChangedEvent> liveReloadTriggeringClassPathChangedEventListener(\n\t\t\t\torg.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer optionalLiveReloadServer) {\n\t\t\treturn (event) -> {\n\t\t\t\tString url = this.remoteUrl + this.properties.getRemote().getContextPath();\n\t\t\t\tthis.executor.execute(\n\t\t\t\t\t\tnew DelayedLiveReloadTrigger(optionalLiveReloadServer, this.clientHttpRequestFactory, url));\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\torg.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer optionalLiveReloadServer(\n\t\t\t\tObjectProvider<org.springframework.boot.devtools.livereload.LiveReloadServer> liveReloadServer) {\n\t\t\treturn new org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer(\n\t\t\t\t\tliveReloadServer.getIfAvailable());\n\t\t}\n\n\t\tfinal ExecutorService getExecutor() {\n\t\t\treturn this.executor;\n\t\t}\n\n\t}\n\n\t/**\n\t * Client configuration for remote update and restarts.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.devtools.remote.restart.enabled\", matchIfMissing = true)\n\tstatic class RemoteRestartClientConfiguration {\n\n\t\tprivate final DevToolsProperties properties;\n\n\t\tRemoteRestartClientConfiguration(DevToolsProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Bean\n\t\tClassPathFileSystemWatcher classPathFileSystemWatcher(FileSystemWatcherFactory fileSystemWatcherFactory,\n\t\t\t\tClassPathRestartStrategy classPathRestartStrategy) {\n\t\t\tDefaultRestartInitializer restartInitializer = new DefaultRestartInitializer();\n\t\t\tURL[] urls = restartInitializer.getInitialUrls(Thread.currentThread());\n\t\t\tif (urls == null) {\n\t\t\t\turls = new URL[0];\n\t\t\t}\n\t\t\treturn new ClassPathFileSystemWatcher(fileSystemWatcherFactory, classPathRestartStrategy, urls);\n\t\t}\n\n\t\t@Bean\n\t\tFileSystemWatcherFactory getFileSystemWatcherFactory() {\n\t\t\treturn this::newFileSystemWatcher;\n\t\t}\n\n\t\tprivate FileSystemWatcher newFileSystemWatcher() {\n\t\t\tRestart restartProperties = this.properties.getRestart();\n\t\t\tFileSystemWatcher watcher = new FileSystemWatcher(true, restartProperties.getPollInterval(),\n\t\t\t\t\trestartProperties.getQuietPeriod());\n\t\t\tString triggerFile = restartProperties.getTriggerFile();\n\t\t\tif (StringUtils.hasLength(triggerFile)) {\n\t\t\t\twatcher.setTriggerFilter(new TriggerFileFilter(triggerFile));\n\t\t\t}\n\t\t\treturn watcher;\n\t\t}\n\n\t\t@Bean\n\t\tClassPathRestartStrategy classPathRestartStrategy() {\n\t\t\treturn new PatternClassPathRestartStrategy(this.properties.getRestart().getAllExclude());\n\t\t}\n\n\t\t@Bean\n\t\tClassPathChangeUploader classPathChangeUploader(ClientHttpRequestFactory requestFactory,\n\t\t\t\t@Value(\"${remoteUrl}\") String remoteUrl) {\n\t\t\tString url = remoteUrl + this.properties.getRemote().getContextPath() + \"/restart\";\n\t\t\treturn new ClassPathChangeUploader(url, requestFactory);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Client support for a remotely running Spring Boot application.\n */\n@NullMarked\npackage org.springframework.boot.devtools.remote.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/AccessManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.springframework.http.server.ServerHttpRequest;\n\n/**\n * Provides access control for a {@link Dispatcher}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface AccessManager {\n\n\t/**\n\t * {@link AccessManager} that permits all requests.\n\t */\n\tAccessManager PERMIT_ALL = (request) -> true;\n\n\t/**\n\t * Determine if the specific request is allowed to be handled by the\n\t * {@link Dispatcher}.\n\t * @param request the request to check\n\t * @return {@code true} if access is allowed.\n\t */\n\tboolean isAllowed(ServerHttpRequest request);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/Dispatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * Dispatcher used to route incoming remote server requests to a {@link Handler}. Similar\n * to {@code DispatchServlet} in Spring MVC but separate to ensure that remote support can\n * be used regardless of any web framework.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see HandlerMapper\n */\npublic class Dispatcher {\n\n\tprivate final AccessManager accessManager;\n\n\tprivate final List<HandlerMapper> mappers;\n\n\tpublic Dispatcher(AccessManager accessManager, Collection<HandlerMapper> mappers) {\n\t\tAssert.notNull(accessManager, \"'accessManager' must not be null\");\n\t\tAssert.notNull(mappers, \"'mappers' must not be null\");\n\t\tthis.accessManager = accessManager;\n\t\tthis.mappers = new ArrayList<>(mappers);\n\t\tAnnotationAwareOrderComparator.sort(this.mappers);\n\t}\n\n\t/**\n\t * Dispatch the specified request to an appropriate {@link Handler}.\n\t * @param request the request\n\t * @param response the response\n\t * @return {@code true} if the request was dispatched\n\t * @throws IOException in case of I/O errors\n\t */\n\tpublic boolean handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {\n\t\tfor (HandlerMapper mapper : this.mappers) {\n\t\t\tHandler handler = mapper.getHandler(request);\n\t\t\tif (handler != null) {\n\t\t\t\thandle(handler, request, response);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate void handle(Handler handler, ServerHttpRequest request, ServerHttpResponse response) throws IOException {\n\t\tif (!this.accessManager.isAllowed(request)) {\n\t\t\tresponse.setStatusCode(HttpStatus.FORBIDDEN);\n\t\t\treturn;\n\t\t}\n\t\thandler.handle(request, response);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/DispatcherFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * Servlet filter providing integration with the remote server {@link Dispatcher}.\n *\n * @author Phillip Webb\n * @author Rob Winch\n * @since 1.3.0\n */\npublic class DispatcherFilter implements Filter {\n\n\tprivate final Dispatcher dispatcher;\n\n\tpublic DispatcherFilter(Dispatcher dispatcher) {\n\t\tAssert.notNull(dispatcher, \"'dispatcher' must not be null\");\n\t\tthis.dispatcher = dispatcher;\n\t}\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tif (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {\n\t\t\tdoFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);\n\t\t}\n\t\telse {\n\t\t\tchain.doFilter(request, response);\n\t\t}\n\t}\n\n\tprivate void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tServerHttpRequest serverRequest = new ServletServerHttpRequest(request);\n\t\tServerHttpResponse serverResponse = new ServletServerHttpResponse(response);\n\t\tif (!this.dispatcher.handle(serverRequest, serverResponse)) {\n\t\t\tchain.doFilter(request, response);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/Handler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport java.io.IOException;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\n\n/**\n * A single handler that is able to process an incoming remote server request.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface Handler {\n\n\t/**\n\t * Handle the request.\n\t * @param request the request\n\t * @param response the response\n\t * @throws IOException in case of I/O errors\n\t */\n\tvoid handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HandlerMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.server.ServerHttpRequest;\n\n/**\n * Interface to provide a mapping between a {@link ServerHttpRequest} and a\n * {@link Handler}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface HandlerMapper {\n\n\t/**\n\t * Return the handler for the given request or {@code null}.\n\t * @param request the request\n\t * @return a {@link Handler} or {@code null}\n\t */\n\t@Nullable Handler getHandler(ServerHttpRequest request);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.util.Assert;\n\n/**\n * {@link AccessManager} that checks for the presence of an HTTP header secret.\n *\n * @author Rob Winch\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class HttpHeaderAccessManager implements AccessManager {\n\n\tprivate final String headerName;\n\n\tprivate final String expectedSecret;\n\n\tpublic HttpHeaderAccessManager(String headerName, String expectedSecret) {\n\t\tAssert.hasLength(headerName, \"'headerName' must not be empty\");\n\t\tAssert.hasLength(expectedSecret, \"'expectedSecret' must not be empty\");\n\t\tthis.headerName = headerName;\n\t\tthis.expectedSecret = expectedSecret;\n\t}\n\n\t@Override\n\tpublic boolean isAllowed(ServerHttpRequest request) {\n\t\tString providedSecret = request.getHeaders().getFirst(this.headerName);\n\t\treturn this.expectedSecret.equals(providedSecret);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/HttpStatusHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport java.io.IOException;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Handler} that responds with a specific {@link HttpStatus}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class HttpStatusHandler implements Handler {\n\n\tprivate final HttpStatus status;\n\n\t/**\n\t * Create a new {@link HttpStatusHandler} instance that will respond with an HTTP OK\n\t * 200 status.\n\t */\n\tpublic HttpStatusHandler() {\n\t\tthis(HttpStatus.OK);\n\t}\n\n\t/**\n\t * Create a new {@link HttpStatusHandler} instance that will respond with the\n\t * specified status.\n\t * @param status the status\n\t */\n\tpublic HttpStatusHandler(HttpStatus status) {\n\t\tAssert.notNull(status, \"'status' must not be null\");\n\t\tthis.status = status;\n\t}\n\n\t@Override\n\tpublic void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {\n\t\tresponse.setStatusCode(this.status);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/UrlHandlerMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HandlerMapper} implementation that maps incoming URLs.\n *\n * @author Rob Winch\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class UrlHandlerMapper implements HandlerMapper {\n\n\tprivate final String requestUri;\n\n\tprivate final Handler handler;\n\n\t/**\n\t * Create a new {@link UrlHandlerMapper}.\n\t * @param url the URL to map\n\t * @param handler the handler to use\n\t */\n\tpublic UrlHandlerMapper(String url, Handler handler) {\n\t\tAssert.hasLength(url, \"'url' must not be empty\");\n\t\tAssert.isTrue(url.startsWith(\"/\"), \"'url' must start with '/'\");\n\t\tthis.requestUri = url;\n\t\tthis.handler = handler;\n\t}\n\n\t@Override\n\tpublic @Nullable Handler getHandler(ServerHttpRequest request) {\n\t\tif (this.requestUri.equals(request.getURI().getPath())) {\n\t\t\treturn this.handler;\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/remote/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Server support for a remotely running Spring Boot application.\n */\n@NullMarked\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/AgentReloader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ClassUtils;\n\n/**\n * Utility to determine if a Java agent based reloader (e.g. JRebel) is being used.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic abstract class AgentReloader {\n\n\tprivate static final Set<String> AGENT_CLASSES;\n\n\tstatic {\n\t\tSet<String> agentClasses = new LinkedHashSet<>();\n\t\tagentClasses.add(\"org.zeroturnaround.javarebel.Integration\");\n\t\tagentClasses.add(\"org.zeroturnaround.javarebel.ReloaderFactory\");\n\t\tagentClasses.add(\"org.hotswap.agent.HotswapAgent\");\n\t\tAGENT_CLASSES = Collections.unmodifiableSet(agentClasses);\n\t}\n\n\tprivate AgentReloader() {\n\t}\n\n\t/**\n\t * Determine if any agent reloader is active.\n\t * @return true if agent reloading is active\n\t */\n\tpublic static boolean isActive() {\n\t\treturn isActive(null) || isActive(AgentReloader.class.getClassLoader())\n\t\t\t\t|| isActive(ClassLoader.getSystemClassLoader());\n\t}\n\n\tprivate static boolean isActive(@Nullable ClassLoader classLoader) {\n\t\tfor (String agentClass : AGENT_CLASSES) {\n\t\t\tif (ClassUtils.isPresent(agentClass, classLoader)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.management.ManagementFactory;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.stream.Stream;\n\nimport org.apache.commons.logging.Log;\n\nimport org.springframework.boot.devtools.logger.DevToolsLogFactory;\nimport org.springframework.boot.devtools.settings.DevToolsSettings;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.StringUtils;\n\n/**\n * A filtered collection of URLs which can change after the application has started.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nfinal class ChangeableUrls implements Iterable<URL> {\n\n\tprivate static final Log logger = DevToolsLogFactory.getLog(ChangeableUrls.class);\n\n\tprivate final List<URL> urls;\n\n\tprivate ChangeableUrls(URL... urls) {\n\t\tDevToolsSettings settings = DevToolsSettings.get();\n\t\tList<URL> reloadableUrls = new ArrayList<>(urls.length);\n\t\tfor (URL url : urls) {\n\t\t\tif ((settings.isRestartInclude(url) || isDirectoryUrl(url.toString())) && !settings.isRestartExclude(url)) {\n\t\t\t\treloadableUrls.add(url);\n\t\t\t}\n\t\t}\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Matching URLs for reloading : \" + reloadableUrls);\n\t\t}\n\t\tthis.urls = Collections.unmodifiableList(reloadableUrls);\n\t}\n\n\tprivate boolean isDirectoryUrl(String urlString) {\n\t\treturn urlString.startsWith(\"file:\") && urlString.endsWith(\"/\");\n\t}\n\n\t@Override\n\tpublic Iterator<URL> iterator() {\n\t\treturn this.urls.iterator();\n\t}\n\n\tint size() {\n\t\treturn this.urls.size();\n\t}\n\n\tURL[] toArray() {\n\t\treturn this.urls.toArray(new URL[0]);\n\t}\n\n\tList<URL> toList() {\n\t\treturn Collections.unmodifiableList(this.urls);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.urls.toString();\n\t}\n\n\tstatic ChangeableUrls fromClassLoader(ClassLoader classLoader) {\n\t\tList<URL> urls = new ArrayList<>();\n\t\tfor (URL url : urlsFromClassLoader(classLoader)) {\n\t\t\turls.add(url);\n\t\t\turls.addAll(getUrlsFromClassPathOfJarManifestIfPossible(url));\n\t\t}\n\t\treturn fromUrls(urls);\n\t}\n\n\tprivate static URL[] urlsFromClassLoader(ClassLoader classLoader) {\n\t\tif (classLoader instanceof URLClassLoader urlClassLoader) {\n\t\t\treturn urlClassLoader.getURLs();\n\t\t}\n\t\treturn Stream.of(ManagementFactory.getRuntimeMXBean().getClassPath().split(File.pathSeparator))\n\t\t\t.map(ChangeableUrls::toURL)\n\t\t\t.toArray(URL[]::new);\n\t}\n\n\tprivate static URL toURL(String classPathEntry) {\n\t\ttry {\n\t\t\treturn new File(classPathEntry).toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalArgumentException(\"URL could not be created from '\" + classPathEntry + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate static List<URL> getUrlsFromClassPathOfJarManifestIfPossible(URL url) {\n\t\ttry {\n\t\t\tFile file = new File(url.toURI());\n\t\t\tif (file.isFile()) {\n\t\t\t\ttry (JarFile jarFile = new JarFile(file)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn getUrlsFromManifestClassPathAttribute(url, jarFile);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\"Failed to read Class-Path attribute from manifest of jar \" + url, ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Assume it's not a jar and continue\n\t\t}\n\t\treturn Collections.emptyList();\n\t}\n\n\tprivate static List<URL> getUrlsFromManifestClassPathAttribute(URL jarUrl, JarFile jarFile) throws IOException {\n\t\tManifest manifest = jarFile.getManifest();\n\t\tif (manifest == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tString classPath = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);\n\t\tif (!StringUtils.hasText(classPath)) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tString[] entries = StringUtils.delimitedListToStringArray(classPath, \" \");\n\t\tList<URL> urls = new ArrayList<>(entries.length);\n\t\tList<URL> nonExistentEntries = new ArrayList<>();\n\t\tfor (String entry : entries) {\n\t\t\ttry {\n\t\t\t\tURL referenced = new URL(jarUrl, entry);\n\t\t\t\tif (new File(referenced.getFile()).exists()) {\n\t\t\t\t\turls.add(referenced);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treferenced = new URL(jarUrl, URLDecoder.decode(entry, StandardCharsets.UTF_8));\n\t\t\t\t\tif (new File(referenced.getFile()).exists()) {\n\t\t\t\t\t\turls.add(referenced);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tnonExistentEntries.add(referenced);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (MalformedURLException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Class-Path attribute contains malformed URL\", ex);\n\t\t\t}\n\t\t}\n\t\tif (!nonExistentEntries.isEmpty()) {\n\t\t\tlogger.info(LogMessage.of(() -> \"The Class-Path manifest attribute in \" + jarFile.getName()\n\t\t\t\t\t+ \" referenced one or more files that do not exist: \"\n\t\t\t\t\t+ StringUtils.collectionToCommaDelimitedString(nonExistentEntries)));\n\t\t}\n\t\treturn urls;\n\t}\n\n\tstatic ChangeableUrls fromUrls(Collection<URL> urls) {\n\t\treturn fromUrls(new ArrayList<>(urls).toArray(new URL[urls.size()]));\n\t}\n\n\tstatic ChangeableUrls fromUrls(URL... urls) {\n\t\treturn new ChangeableUrls(urls);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.reflect.Field;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFileURLStreamHandler;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.AbstractApplicationContext;\nimport org.springframework.core.io.AbstractResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.UrlResource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.PathMatcher;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.ServletContextResource;\nimport org.springframework.web.context.support.ServletContextResourcePatternResolver;\n\n/**\n * A {@code ResourcePatternResolver} that considers {@link ClassLoaderFiles} when\n * resolving resources.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nfinal class ClassLoaderFilesResourcePatternResolver implements ResourcePatternResolver {\n\n\tprivate static final String[] LOCATION_PATTERN_PREFIXES = { CLASSPATH_ALL_URL_PREFIX, CLASSPATH_URL_PREFIX };\n\n\tprivate static final String WEB_CONTEXT_CLASS = \"org.springframework.web.context.WebApplicationContext\";\n\n\tprivate final ResourcePatternResolver patternResolverDelegate;\n\n\tprivate final PathMatcher antPathMatcher = new AntPathMatcher();\n\n\tprivate final ClassLoaderFiles classLoaderFiles;\n\n\tClassLoaderFilesResourcePatternResolver(AbstractApplicationContext applicationContext,\n\t\t\tClassLoaderFiles classLoaderFiles) {\n\t\tthis.classLoaderFiles = classLoaderFiles;\n\t\tthis.patternResolverDelegate = getResourcePatternResolverFactory()\n\t\t\t.getResourcePatternResolver(applicationContext, retrieveResourceLoader(applicationContext));\n\t}\n\n\tprivate @Nullable ResourceLoader retrieveResourceLoader(ApplicationContext applicationContext) {\n\t\tField field = ReflectionUtils.findField(applicationContext.getClass(), \"resourceLoader\", ResourceLoader.class);\n\t\tif (field == null) {\n\t\t\treturn null;\n\t\t}\n\t\tReflectionUtils.makeAccessible(field);\n\t\treturn (ResourceLoader) ReflectionUtils.getField(field, applicationContext);\n\t}\n\n\tprivate ResourcePatternResolverFactory getResourcePatternResolverFactory() {\n\t\tif (ClassUtils.isPresent(WEB_CONTEXT_CLASS, null)) {\n\t\t\treturn new WebResourcePatternResolverFactory();\n\t\t}\n\t\treturn new ResourcePatternResolverFactory();\n\t}\n\n\t@Override\n\tpublic @Nullable ClassLoader getClassLoader() {\n\t\treturn this.patternResolverDelegate.getClassLoader();\n\t}\n\n\t@Override\n\tpublic Resource getResource(String location) {\n\t\tResource candidate = this.patternResolverDelegate.getResource(location);\n\t\tif (isDeleted(candidate)) {\n\t\t\treturn new DeletedClassLoaderFileResource(location);\n\t\t}\n\t\treturn candidate;\n\t}\n\n\t@Override\n\tpublic Resource[] getResources(String locationPattern) throws IOException {\n\t\tList<Resource> resources = new ArrayList<>();\n\t\tResource[] candidates = this.patternResolverDelegate.getResources(locationPattern);\n\t\tfor (Resource candidate : candidates) {\n\t\t\tif (!isDeleted(candidate)) {\n\t\t\t\tresources.add(candidate);\n\t\t\t}\n\t\t}\n\t\tresources.addAll(getAdditionalResources(locationPattern));\n\t\treturn resources.toArray(new Resource[0]);\n\t}\n\n\tprivate List<Resource> getAdditionalResources(String locationPattern) throws MalformedURLException {\n\t\tList<Resource> additionalResources = new ArrayList<>();\n\t\tString trimmedLocationPattern = trimLocationPattern(locationPattern);\n\t\tfor (Entry<String, ClassLoaderFile> entry : this.classLoaderFiles.getFileEntries()) {\n\t\t\tString name = entry.getKey();\n\t\t\tClassLoaderFile file = entry.getValue();\n\t\t\tif (file.getKind() != Kind.DELETED && this.antPathMatcher.match(trimmedLocationPattern, name)) {\n\t\t\t\tURL url = new URL(\"reloaded\", null, -1, \"/\" + name, new ClassLoaderFileURLStreamHandler(file));\n\t\t\t\tUrlResource resource = new UrlResource(url);\n\t\t\t\tadditionalResources.add(resource);\n\t\t\t}\n\t\t}\n\t\treturn additionalResources;\n\t}\n\n\tprivate String trimLocationPattern(String pattern) {\n\t\tfor (String prefix : LOCATION_PATTERN_PREFIXES) {\n\t\t\tif (pattern.startsWith(prefix)) {\n\t\t\t\treturn pattern.substring(prefix.length());\n\t\t\t}\n\t\t}\n\t\treturn pattern;\n\t}\n\n\tprivate boolean isDeleted(Resource resource) {\n\t\tfor (Entry<String, ClassLoaderFile> entry : this.classLoaderFiles.getFileEntries()) {\n\t\t\ttry {\n\t\t\t\tString name = entry.getKey();\n\t\t\t\tClassLoaderFile file = entry.getValue();\n\t\t\t\tif (file.getKind() == Kind.DELETED && resource.exists()\n\t\t\t\t\t\t&& resource.getURI().toString().endsWith(name)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to retrieve URI from '\" + resource + \"'\", ex);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * A {@link Resource} that represents a {@link ClassLoaderFile} that has been\n\t * {@link Kind#DELETED deleted}.\n\t */\n\tstatic final class DeletedClassLoaderFileResource extends AbstractResource {\n\n\t\tprivate final String name;\n\n\t\tprivate DeletedClassLoaderFileResource(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean exists() {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDescription() {\n\t\t\treturn \"Deleted: \" + this.name;\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\tthrow new IOException(this.name + \" has been deleted\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Factory used to create the {@link ResourcePatternResolver} delegate.\n\t */\n\tprivate static class ResourcePatternResolverFactory {\n\n\t\tResourcePatternResolver getResourcePatternResolver(AbstractApplicationContext applicationContext,\n\t\t\t\t@Nullable ResourceLoader resourceLoader) {\n\t\t\tResourceLoader targetResourceLoader = (resourceLoader != null) ? resourceLoader\n\t\t\t\t\t: new ApplicationContextResourceLoader(applicationContext::getProtocolResolvers);\n\t\t\treturn new PathMatchingResourcePatternResolver(targetResourceLoader);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ResourcePatternResolverFactory} to be used when the classloader can access\n\t * {@link WebApplicationContext}.\n\t */\n\tprivate static final class WebResourcePatternResolverFactory extends ResourcePatternResolverFactory {\n\n\t\t@Override\n\t\tpublic ResourcePatternResolver getResourcePatternResolver(AbstractApplicationContext applicationContext,\n\t\t\t\t@Nullable ResourceLoader resourceLoader) {\n\t\t\tif (applicationContext instanceof WebApplicationContext) {\n\t\t\t\treturn getServletContextResourcePatternResolver(applicationContext, resourceLoader);\n\t\t\t}\n\t\t\treturn super.getResourcePatternResolver(applicationContext, resourceLoader);\n\t\t}\n\n\t\tprivate ResourcePatternResolver getServletContextResourcePatternResolver(\n\t\t\t\tAbstractApplicationContext applicationContext, @Nullable ResourceLoader resourceLoader) {\n\t\t\tResourceLoader targetResourceLoader = (resourceLoader != null) ? resourceLoader\n\t\t\t\t\t: new WebApplicationContextResourceLoader(applicationContext::getProtocolResolvers,\n\t\t\t\t\t\t\t(WebApplicationContext) applicationContext);\n\t\t\treturn new ServletContextResourcePatternResolver(targetResourceLoader);\n\t\t}\n\n\t}\n\n\tprivate static class ApplicationContextResourceLoader extends DefaultResourceLoader {\n\n\t\tprivate final Supplier<Collection<ProtocolResolver>> protocolResolvers;\n\n\t\tApplicationContextResourceLoader(Supplier<Collection<ProtocolResolver>> protocolResolvers) {\n\t\t\tsuper(null);\n\t\t\tthis.protocolResolvers = protocolResolvers;\n\t\t}\n\n\t\t@Override\n\t\tpublic Collection<ProtocolResolver> getProtocolResolvers() {\n\t\t\treturn this.protocolResolvers.get();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ResourceLoader} that optionally supports {@link ServletContextResource\n\t * ServletContextResources}.\n\t */\n\tprivate static class WebApplicationContextResourceLoader extends ApplicationContextResourceLoader {\n\n\t\tprivate final WebApplicationContext applicationContext;\n\n\t\tWebApplicationContextResourceLoader(Supplier<Collection<ProtocolResolver>> protocolResolvers,\n\t\t\t\tWebApplicationContext applicationContext) {\n\t\t\tsuper(protocolResolvers);\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tprotected Resource getResourceByPath(String path) {\n\t\t\tif (this.applicationContext.getServletContext() != null) {\n\t\t\t\treturn new ServletContextResource(this.applicationContext.getServletContext(), path);\n\t\t\t}\n\t\t\treturn super.getResourceByPath(path);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ConditionalOnInitializedRestarter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when the {@link RestartInitializer}\n * has been applied with non {@code null} URLs.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(OnInitializedRestarterCondition.class)\npublic @interface ConditionalOnInitializedRestarter {\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/DefaultRestartInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.net.URL;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.system.DevToolsEnablementDeducer;\n\n/**\n * Default {@link RestartInitializer} that only enable initial restart when running a\n * standard \"main\" method. Skips initialization when running \"fat\" jars (included\n * exploded) or when running from a test.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.3.0\n */\npublic class DefaultRestartInitializer implements RestartInitializer {\n\n\t@Override\n\tpublic URL @Nullable [] getInitialUrls(Thread thread) {\n\t\tif (!isMain(thread)) {\n\t\t\treturn null;\n\t\t}\n\t\tif (!DevToolsEnablementDeducer.shouldEnable(thread)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn getUrls(thread);\n\t}\n\n\t/**\n\t * Returns if the thread is for a main invocation. By default\n\t * {@link #isMainThread(Thread)} checks the name of the thread} and\n\t * {@link #isDevelopmentClassLoader(ClassLoader) the context classloader}.\n\t * @param thread the thread to check\n\t * @return {@code true} if the thread is a main invocation\n\t * @see #isMainThread\n\t * @see #isDevelopmentClassLoader(ClassLoader)\n\t */\n\tprotected boolean isMain(Thread thread) {\n\t\treturn isMainThread(thread) && isDevelopmentClassLoader(thread.getContextClassLoader());\n\t}\n\n\t/**\n\t * Returns whether the given {@code thread} is considered to be the main thread.\n\t * @param thread the thread to check\n\t * @return {@code true} if it's the main thread, otherwise {@code false}\n\t * @since 2.4.0\n\t */\n\tprotected boolean isMainThread(Thread thread) {\n\t\treturn thread.getName().equals(\"main\");\n\t}\n\n\t/**\n\t * Returns whether the given {@code classLoader} is one that is typically used during\n\t * development.\n\t * @param classLoader the ClassLoader to check\n\t * @return {@code true} if it's a ClassLoader typically used during development,\n\t * otherwise {@code false}\n\t * @since 2.4.0\n\t */\n\tprotected boolean isDevelopmentClassLoader(ClassLoader classLoader) {\n\t\treturn classLoader.getClass().getName().contains(\"AppClassLoader\");\n\t}\n\n\t/**\n\t * Return the URLs that should be used with initialization.\n\t * @param thread the source thread\n\t * @return the URLs\n\t */\n\tprotected URL[] getUrls(Thread thread) {\n\t\treturn ChangeableUrls.fromClassLoader(thread.getContextClassLoader()).toArray();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/FailureHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\n/**\n * Strategy used to handle launch failures.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface FailureHandler {\n\n\t/**\n\t * {@link FailureHandler} that always aborts.\n\t */\n\tFailureHandler NONE = (failure) -> Outcome.ABORT;\n\n\t/**\n\t * Handle a run failure. Implementations may block, for example to wait until specific\n\t * files are updated.\n\t * @param failure the exception\n\t * @return the outcome\n\t */\n\tOutcome handle(Throwable failure);\n\n\t/**\n\t * Various outcomes for the handler.\n\t */\n\tenum Outcome {\n\n\t\t/**\n\t\t * Abort the relaunch.\n\t\t */\n\t\tABORT,\n\n\t\t/**\n\t\t * Try again to relaunch the application.\n\t\t */\n\t\tRETRY\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/MainMethod.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * The \"main\" method located from a running thread.\n *\n * @author Phillip Webb\n */\nclass MainMethod {\n\n\tprivate final Method method;\n\n\tMainMethod() {\n\t\tthis(Thread.currentThread());\n\t}\n\n\tMainMethod(Thread thread) {\n\t\tAssert.notNull(thread, \"'thread' must not be null\");\n\t\tthis.method = getMainMethod(thread);\n\t}\n\n\tprivate Method getMainMethod(Thread thread) {\n\t\tStackTraceElement[] stackTrace = thread.getStackTrace();\n\t\tfor (int i = stackTrace.length - 1; i >= 0; i--) {\n\t\t\tStackTraceElement element = stackTrace[i];\n\t\t\tif (\"main\".equals(element.getMethodName()) && !isLoaderClass(element.getClassName())) {\n\t\t\t\tMethod method = getMainMethod(element);\n\t\t\t\tif (method != null) {\n\t\t\t\t\treturn method;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Unable to find main method\");\n\t}\n\n\tprivate boolean isLoaderClass(String className) {\n\t\treturn className.startsWith(\"org.springframework.boot.loader.\");\n\t}\n\n\tprivate @Nullable Method getMainMethod(StackTraceElement element) {\n\t\ttry {\n\t\t\tClass<?> elementClass = Class.forName(element.getClassName());\n\t\t\tMethod method = getMainMethod(elementClass);\n\t\t\tif (Modifier.isStatic(method.getModifiers())) {\n\t\t\t\treturn method;\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static Method getMainMethod(Class<?> clazz) throws Exception {\n\t\ttry {\n\t\t\treturn clazz.getDeclaredMethod(\"main\", String[].class);\n\t\t}\n\t\tcatch (NoSuchMethodException ex) {\n\t\t\treturn clazz.getDeclaredMethod(\"main\");\n\t\t}\n\t}\n\n\t/**\n\t * Returns the actual main method.\n\t * @return the main method\n\t */\n\tMethod getMethod() {\n\t\treturn this.method;\n\t}\n\n\t/**\n\t * Return the name of the declaring class.\n\t * @return the declaring class name\n\t */\n\tString getDeclaringClassName() {\n\t\treturn this.method.getDeclaringClass().getName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/OnInitializedRestarterCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link Condition} that checks that a {@link Restarter} is available and initialized.\n *\n * @author Phillip Webb\n * @see ConditionalOnInitializedRestarter\n */\nclass OnInitializedRestarterCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Initialized Restarter Condition\");\n\t\tRestarter restarter = getRestarter();\n\t\tif (restarter == null) {\n\t\t\treturn ConditionOutcome.noMatch(message.because(\"unavailable\"));\n\t\t}\n\t\tif (restarter.getInitialUrls() == null) {\n\t\t\treturn ConditionOutcome.noMatch(message.because(\"initialized without URLs\"));\n\t\t}\n\t\treturn ConditionOutcome.match(message.because(\"available and initialized\"));\n\t}\n\n\tprivate @Nullable Restarter getRestarter() {\n\t\ttry {\n\t\t\treturn Restarter.getInstance();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.devtools.system.DevToolsEnablementDeducer;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * {@link ApplicationListener} to initialize the {@link Restarter}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.3.0\n * @see Restarter\n */\npublic class RestartApplicationListener implements ApplicationListener<ApplicationEvent>, Ordered {\n\n\tprivate static final String ENABLED_PROPERTY = \"spring.devtools.restart.enabled\";\n\n\tprivate static final Log logger = LogFactory.getLog(RestartApplicationListener.class);\n\n\tprivate int order = HIGHEST_PRECEDENCE;\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\tif (event instanceof ApplicationStartingEvent startingEvent) {\n\t\t\tonApplicationStartingEvent(startingEvent);\n\t\t}\n\t\tif (event instanceof ApplicationPreparedEvent preparedEvent) {\n\t\t\tonApplicationPreparedEvent(preparedEvent);\n\t\t}\n\t\tif (event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) {\n\t\t\tRestarter.getInstance().finish();\n\t\t}\n\t\tif (event instanceof ApplicationFailedEvent failedEvent) {\n\t\t\tonApplicationFailedEvent(failedEvent);\n\t\t}\n\t}\n\n\tprivate void onApplicationStartingEvent(ApplicationStartingEvent event) {\n\t\t// It's too early to use the Spring environment, but we should still allow\n\t\t// users to disable restart using a System property.\n\t\tString enabled = System.getProperty(ENABLED_PROPERTY);\n\t\tRestartInitializer restartInitializer = null;\n\t\tif (enabled == null) {\n\t\t\tif (implicitlyEnableRestart()) {\n\t\t\t\trestartInitializer = new DefaultRestartInitializer();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Restart disabled due to context in which it is running\");\n\t\t\t\tRestarter.disable();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse if (Boolean.parseBoolean(enabled)) {\n\t\t\trestartInitializer = new DefaultRestartInitializer() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected boolean isDevelopmentClassLoader(ClassLoader classLoader) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t};\n\t\t\tlogger.info(LogMessage.format(\n\t\t\t\t\t\"Restart enabled irrespective of application packaging due to System property '%s' being set to true\",\n\t\t\t\t\tENABLED_PROPERTY));\n\t\t}\n\t\tif (restartInitializer != null) {\n\t\t\tString[] args = event.getArgs();\n\t\t\tboolean restartOnInitialize = !AgentReloader.isActive();\n\t\t\tif (!restartOnInitialize) {\n\t\t\t\tlogger.info(\"Restart disabled due to an agent-based reloader being active\");\n\t\t\t}\n\t\t\tRestarter.initialize(args, false, restartInitializer, restartOnInitialize);\n\t\t}\n\t\telse {\n\t\t\tlogger.info(LogMessage.format(\"Restart disabled due to System property '%s' being set to false\",\n\t\t\t\t\tENABLED_PROPERTY));\n\t\t\tRestarter.disable();\n\t\t}\n\t}\n\n\tboolean implicitlyEnableRestart() {\n\t\treturn DevToolsEnablementDeducer.shouldEnable(Thread.currentThread());\n\t}\n\n\tprivate void onApplicationPreparedEvent(ApplicationPreparedEvent event) {\n\t\tRestarter.getInstance().prepare(event.getApplicationContext());\n\t}\n\n\tprivate void onApplicationFailedEvent(ApplicationFailedEvent event) {\n\t\tRestarter.getInstance().remove(event.getApplicationContext());\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order of the listener.\n\t * @param order the order of the listener\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.net.URL;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Strategy interface used to initialize a {@link Restarter}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see DefaultRestartInitializer\n */\n@FunctionalInterface\npublic interface RestartInitializer {\n\n\t/**\n\t * {@link RestartInitializer} that doesn't return any URLs.\n\t */\n\tRestartInitializer NONE = (thread) -> null;\n\n\t/**\n\t * Return the initial set of URLs for the {@link Restarter} or {@code null} if no\n\t * initial restart is required.\n\t * @param thread the source thread\n\t * @return initial URLs or {@code null}\n\t */\n\tURL @Nullable [] getInitialUrls(Thread thread);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Thread used to launch a restarted application.\n *\n * @author Phillip Webb\n */\nclass RestartLauncher extends Thread {\n\n\tprivate final String mainClassName;\n\n\tprivate final String[] args;\n\n\tprivate @Nullable Throwable error;\n\n\tRestartLauncher(ClassLoader classLoader, String mainClassName, String[] args,\n\t\t\tUncaughtExceptionHandler exceptionHandler) {\n\t\tthis.mainClassName = mainClassName;\n\t\tthis.args = args;\n\t\tsetName(\"restartedMain\");\n\t\tsetUncaughtExceptionHandler(exceptionHandler);\n\t\tsetDaemon(false);\n\t\tsetContextClassLoader(classLoader);\n\t}\n\n\t@Override\n\tpublic void run() {\n\t\ttry {\n\t\t\tClass<?> mainClass = Class.forName(this.mainClassName, false, getContextClassLoader());\n\t\t\tMethod mainMethod = mainClass.getDeclaredMethod(\"main\", String[].class);\n\t\t\tmainMethod.setAccessible(true);\n\t\t\tmainMethod.invoke(null, new Object[] { this.args });\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthis.error = ex;\n\t\t\tgetUncaughtExceptionHandler().uncaughtException(this, ex);\n\t\t}\n\t}\n\n\t@Nullable Throwable getError() {\n\t\treturn this.error;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\n/**\n * Listener that is notified of application restarts.\n *\n * @author Andy Wilkinson\n * @since 1.3.0\n */\n@FunctionalInterface\npublic interface RestartListener {\n\n\t/**\n\t * Called before an application restart.\n\t */\n\tvoid beforeRestart();\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartScope.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Scope;\n\n/**\n * Restart {@code @Scope} Annotation used to indicate that a bean should remain between\n * restarts.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see RestartScopeInitializer\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Scope(\"restart\")\npublic @interface RestartScope {\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/RestartScopeInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.beans.factory.config.Scope;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Support for a 'restart' {@link Scope} that allows beans to remain between restarts.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class RestartScopeInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.getBeanFactory().registerScope(\"restart\", new RestartScope());\n\t}\n\n\t/**\n\t * {@link Scope} that stores beans as {@link Restarter} attributes.\n\t */\n\tprivate static final class RestartScope implements Scope {\n\n\t\t@Override\n\t\tpublic Object get(String name, ObjectFactory<?> objectFactory) {\n\t\t\treturn Restarter.getInstance().getOrAddAttribute(name, objectFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic Object remove(String name) {\n\t\t\treturn Restarter.getInstance().removeAttribute(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerDestructionCallback(String name, Runnable callback) {\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object resolveContextualObject(String key) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getConversationId() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/Restarter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.beans.Introspector;\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.lang.reflect.Field;\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.BlockingDeque;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.LinkedBlockingDeque;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.CachedIntrospectionResults;\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.devtools.restart.FailureHandler.Outcome;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.boot.devtools.restart.classloader.RestartClassLoader;\nimport org.springframework.boot.logging.DeferredLog;\nimport org.springframework.cglib.core.ClassNameReader;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Allows a running application to be restarted with an updated classpath. The restarter\n * works by creating a new application ClassLoader that is split into two parts. The top\n * part contains static URLs that don't change (for example 3rd party libraries and Spring\n * Boot itself) and the bottom part contains URLs where classes and resources might be\n * updated.\n * <p>\n * The Restarter should be {@link #initialize(String[]) initialized} early to ensure that\n * classes are loaded multiple times. Mostly the {@link RestartApplicationListener} can be\n * relied upon to perform initialization, however, you may need to call\n * {@link #initialize(String[])} directly if your SpringApplication arguments are not\n * identical to your main method arguments.\n * <p>\n * By default, applications running in an IDE (i.e. those not packaged as \"uber jars\")\n * will automatically detect URLs that can change. It's also possible to manually\n * configure URLs or class file updates for remote restart scenarios.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 1.3.0\n * @see RestartApplicationListener\n * @see #initialize(String[])\n * @see #getInstance()\n * @see #restart()\n */\npublic class Restarter {\n\n\tprivate static final Object INSTANCE_MONITOR = new Object();\n\n\tprivate static final String[] NO_ARGS = {};\n\n\tprivate static @Nullable Restarter instance;\n\n\tprivate final Set<URL> urls = new LinkedHashSet<>();\n\n\tprivate final ClassLoaderFiles classLoaderFiles = new ClassLoaderFiles();\n\n\tprivate final Map<String, Object> attributes = new ConcurrentHashMap<>();\n\n\tprivate final BlockingDeque<LeakSafeThread> leakSafeThreads = new LinkedBlockingDeque<>();\n\n\tprivate final Lock stopLock = new ReentrantLock();\n\n\tprivate final Object monitor = new Object();\n\n\tprivate Log logger = new DeferredLog();\n\n\tprivate final boolean forceReferenceCleanup;\n\n\tprivate boolean enabled = true;\n\n\tprivate final URL @Nullable [] initialUrls;\n\n\tprivate final @Nullable String mainClassName;\n\n\tprivate final ClassLoader applicationClassLoader;\n\n\tprivate final String[] args;\n\n\tprivate final UncaughtExceptionHandler exceptionHandler;\n\n\tprivate boolean finished;\n\n\tprivate final List<ConfigurableApplicationContext> rootContexts = new CopyOnWriteArrayList<>();\n\n\t/**\n\t * Internal constructor to create a new {@link Restarter} instance.\n\t * @param thread the source thread\n\t * @param args the application arguments\n\t * @param forceReferenceCleanup if soft/weak reference cleanup should be forced\n\t * @param initializer the restart initializer\n\t * @see #initialize(String[])\n\t */\n\tprotected Restarter(Thread thread, String[] args, boolean forceReferenceCleanup, RestartInitializer initializer) {\n\t\tAssert.notNull(thread, \"'thread' must not be null\");\n\t\tAssert.notNull(args, \"'args' must not be null\");\n\t\tAssert.notNull(initializer, \"'initializer' must not be null\");\n\t\tif (this.logger.isDebugEnabled()) {\n\t\t\tthis.logger.debug(\"Creating new Restarter for thread \" + thread);\n\t\t}\n\t\tSilentExitExceptionHandler.setup(thread);\n\t\tthis.forceReferenceCleanup = forceReferenceCleanup;\n\t\tthis.initialUrls = initializer.getInitialUrls(thread);\n\t\tthis.mainClassName = getMainClassName(thread);\n\t\tthis.applicationClassLoader = thread.getContextClassLoader();\n\t\tthis.args = args;\n\t\tthis.exceptionHandler = thread.getUncaughtExceptionHandler();\n\t\tthis.leakSafeThreads.add(new LeakSafeThread());\n\t}\n\n\tprivate @Nullable String getMainClassName(Thread thread) {\n\t\ttry {\n\t\t\treturn new MainMethod(thread).getDeclaringClassName();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprotected void initialize(boolean restartOnInitialize) {\n\t\tpreInitializeLeakyClasses();\n\t\tif (this.initialUrls != null) {\n\t\t\tthis.urls.addAll(Arrays.asList(this.initialUrls));\n\t\t\tif (restartOnInitialize) {\n\t\t\t\tthis.logger.debug(\"Immediately restarting application\");\n\t\t\t\timmediateRestart();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void immediateRestart() {\n\t\ttry {\n\t\t\tgetLeakSafeThread().callAndWait(() -> {\n\t\t\t\tstart(FailureHandler.NONE);\n\t\t\t\tcleanupCaches();\n\t\t\t\treturn new Object();\n\t\t\t});\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.logger.warn(\"Unable to initialize restarter\", ex);\n\t\t}\n\t\tSilentExitExceptionHandler.exitCurrentThread();\n\t}\n\n\t/**\n\t * CGLIB has a private exception field which needs to initialized early to ensure that\n\t * the stacktrace doesn't retain a reference to the RestartClassLoader.\n\t */\n\tprivate void preInitializeLeakyClasses() {\n\t\ttry {\n\t\t\tClass<?> readerClass = ClassNameReader.class;\n\t\t\tField field = readerClass.getDeclaredField(\"EARLY_EXIT\");\n\t\t\tfield.setAccessible(true);\n\t\t\t((Throwable) field.get(null)).fillInStackTrace();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.logger.warn(\"Unable to pre-initialize classes\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Set if restart support is enabled.\n\t * @param enabled if restart support is enabled\n\t */\n\tprivate void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * Add additional URLs to be includes in the next restart.\n\t * @param urls the urls to add\n\t */\n\tpublic void addUrls(Collection<URL> urls) {\n\t\tAssert.notNull(urls, \"'urls' must not be null\");\n\t\tthis.urls.addAll(urls);\n\t}\n\n\t/**\n\t * Add additional {@link ClassLoaderFiles} to be included in the next restart.\n\t * @param classLoaderFiles the files to add\n\t */\n\tpublic void addClassLoaderFiles(ClassLoaderFiles classLoaderFiles) {\n\t\tAssert.notNull(classLoaderFiles, \"'classLoaderFiles' must not be null\");\n\t\tthis.classLoaderFiles.addAll(classLoaderFiles);\n\t}\n\n\t/**\n\t * Return a {@link ThreadFactory} that can be used to create leak safe threads.\n\t * @return a leak safe thread factory\n\t */\n\tpublic ThreadFactory getThreadFactory() {\n\t\treturn new LeakSafeThreadFactory();\n\t}\n\n\t/**\n\t * Restart the running application.\n\t */\n\tpublic void restart() {\n\t\trestart(FailureHandler.NONE);\n\t}\n\n\t/**\n\t * Restart the running application.\n\t * @param failureHandler a failure handler to deal with application that doesn't start\n\t */\n\tpublic void restart(FailureHandler failureHandler) {\n\t\tif (!this.enabled) {\n\t\t\tthis.logger.debug(\"Application restart is disabled\");\n\t\t\treturn;\n\t\t}\n\t\tthis.logger.debug(\"Restarting application\");\n\t\tgetLeakSafeThread().call(() -> {\n\t\t\tRestarter.this.stop();\n\t\t\tRestarter.this.start(failureHandler);\n\t\t\treturn new Object();\n\t\t});\n\t}\n\n\t/**\n\t * Start the application.\n\t * @param failureHandler a failure handler for application that won't start\n\t * @throws Exception in case of errors\n\t */\n\tprotected void start(FailureHandler failureHandler) throws Exception {\n\t\tdo {\n\t\t\tThrowable error = doStart();\n\t\t\tif (error == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (failureHandler.handle(error) == Outcome.ABORT) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\twhile (true);\n\t}\n\n\tprivate @Nullable Throwable doStart() throws Exception {\n\t\tAssert.state(this.mainClassName != null, \"Unable to find the main class to restart\");\n\t\tURL[] urls = this.urls.toArray(new URL[0]);\n\t\tClassLoaderFiles updatedFiles = new ClassLoaderFiles(this.classLoaderFiles);\n\t\tClassLoader classLoader = new RestartClassLoader(this.applicationClassLoader, urls, updatedFiles);\n\t\tif (this.logger.isDebugEnabled()) {\n\t\t\tthis.logger.debug(\"Starting application \" + this.mainClassName + \" with URLs \" + Arrays.asList(urls));\n\t\t}\n\t\treturn relaunch(classLoader);\n\t}\n\n\t/**\n\t * Relaunch the application using the specified classloader.\n\t * @param classLoader the classloader to use\n\t * @return any exception that caused the launch to fail or {@code null}\n\t * @throws Exception in case of errors\n\t */\n\tprotected @Nullable Throwable relaunch(ClassLoader classLoader) throws Exception {\n\t\tAssert.state(this.mainClassName != null, \"'mainClassName' must not be null\");\n\t\tRestartLauncher launcher = new RestartLauncher(classLoader, this.mainClassName, this.args,\n\t\t\t\tthis.exceptionHandler);\n\t\tlauncher.start();\n\t\tlauncher.join();\n\t\treturn launcher.getError();\n\t}\n\n\t/**\n\t * Stop the application.\n\t * @throws Exception in case of errors\n\t */\n\tprotected void stop() throws Exception {\n\t\tthis.logger.debug(\"Stopping application\");\n\t\tthis.stopLock.lock();\n\t\ttry {\n\t\t\tfor (ConfigurableApplicationContext context : this.rootContexts) {\n\t\t\t\tcontext.close();\n\t\t\t\tthis.rootContexts.remove(context);\n\t\t\t}\n\t\t\tcleanupCaches();\n\t\t\tif (this.forceReferenceCleanup) {\n\t\t\t\tforceReferenceCleanup();\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tthis.stopLock.unlock();\n\t\t}\n\t\tSystem.gc();\n\t\tSystem.runFinalization();\n\t}\n\n\tprivate void cleanupCaches() {\n\t\tIntrospector.flushCaches();\n\t\tcleanupKnownCaches();\n\t}\n\n\tprivate void cleanupKnownCaches() {\n\t\t// Whilst not strictly necessary it helps to clean up soft reference caches\n\t\t// early rather than waiting for memory limits to be reached\n\t\tResolvableType.clearCache();\n\t\tcleanCachedIntrospectionResultsCache();\n\t\tReflectionUtils.clearCache();\n\t\tclearAnnotationUtilsCache();\n\t}\n\n\tprivate void cleanCachedIntrospectionResultsCache() {\n\t\tclear(CachedIntrospectionResults.class, \"acceptedClassLoaders\");\n\t\tclear(CachedIntrospectionResults.class, \"strongClassCache\");\n\t\tclear(CachedIntrospectionResults.class, \"softClassCache\");\n\t}\n\n\tprivate void clearAnnotationUtilsCache() {\n\t\ttry {\n\t\t\tAnnotationUtils.clearCache();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tclear(AnnotationUtils.class, \"findAnnotationCache\");\n\t\t\tclear(AnnotationUtils.class, \"annotatedInterfaceCache\");\n\t\t}\n\t}\n\n\tprivate void clear(Class<?> type, String fieldName) {\n\t\ttry {\n\t\t\tField field = type.getDeclaredField(fieldName);\n\t\t\tfield.setAccessible(true);\n\t\t\tObject instance = field.get(null);\n\t\t\tif (instance instanceof Set) {\n\t\t\t\t((Set<?>) instance).clear();\n\t\t\t}\n\t\t\tif (instance instanceof Map) {\n\t\t\t\t((Map<?, ?>) instance).keySet().removeIf(this::isFromRestartClassLoader);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (this.logger.isDebugEnabled()) {\n\t\t\t\tthis.logger.debug(\"Unable to clear field \" + type + \" \" + fieldName, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isFromRestartClassLoader(Object object) {\n\t\treturn (object instanceof Class && ((Class<?>) object).getClassLoader() instanceof RestartClassLoader);\n\t}\n\n\t/**\n\t * Cleanup any soft/weak references by forcing an {@link OutOfMemoryError} error.\n\t */\n\tprivate void forceReferenceCleanup() {\n\t\ttry {\n\t\t\tfinal List<long[]> memory = new LinkedList<>();\n\t\t\twhile (true) {\n\t\t\t\tmemory.add(new long[102400]);\n\t\t\t}\n\t\t}\n\t\tcatch (OutOfMemoryError ex) {\n\t\t\t// Expected\n\t\t}\n\t}\n\n\t/**\n\t * Called to finish {@link Restarter} initialization when application logging is\n\t * available.\n\t */\n\tvoid finish() {\n\t\tsynchronized (this.monitor) {\n\t\t\tif (!isFinished()) {\n\t\t\t\tthis.logger = DeferredLog.replay(this.logger, LogFactory.getLog(getClass()));\n\t\t\t\tthis.finished = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tboolean isFinished() {\n\t\tsynchronized (this.monitor) {\n\t\t\treturn this.finished;\n\t\t}\n\t}\n\n\tvoid prepare(ConfigurableApplicationContext applicationContext) {\n\t\tif (!this.enabled || (applicationContext != null && applicationContext.getParent() != null)) {\n\t\t\treturn;\n\t\t}\n\t\tif (applicationContext instanceof GenericApplicationContext genericContext) {\n\t\t\tprepare(genericContext);\n\t\t}\n\t\tthis.rootContexts.add(applicationContext);\n\t}\n\n\tvoid remove(@Nullable ConfigurableApplicationContext applicationContext) {\n\t\tif (applicationContext != null) {\n\t\t\tthis.rootContexts.remove(applicationContext);\n\t\t}\n\t}\n\n\tprivate void prepare(GenericApplicationContext applicationContext) {\n\t\tResourceLoader resourceLoader = new ClassLoaderFilesResourcePatternResolver(applicationContext,\n\t\t\t\tthis.classLoaderFiles);\n\t\tapplicationContext.setResourceLoader(resourceLoader);\n\t}\n\n\tprivate LeakSafeThread getLeakSafeThread() {\n\t\ttry {\n\t\t\treturn this.leakSafeThreads.takeFirst();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tpublic Object getOrAddAttribute(String name, final ObjectFactory<?> objectFactory) {\n\t\tObject value = this.attributes.get(name);\n\t\tif (value == null) {\n\t\t\tvalue = objectFactory.getObject();\n\t\t\tthis.attributes.put(name, value);\n\t\t}\n\t\treturn value;\n\t}\n\n\tpublic Object removeAttribute(String name) {\n\t\treturn this.attributes.remove(name);\n\t}\n\n\t/**\n\t * Return the initial set of URLs as configured by the {@link RestartInitializer}.\n\t * @return the initial URLs or {@code null}\n\t */\n\tpublic URL @Nullable [] getInitialUrls() {\n\t\treturn this.initialUrls;\n\t}\n\n\t/**\n\t * Initialize and disable restart support.\n\t */\n\tpublic static void disable() {\n\t\tinitialize(NO_ARGS, false, RestartInitializer.NONE);\n\t\tgetInstance().setEnabled(false);\n\t}\n\n\t/**\n\t * Initialize restart support. See\n\t * {@link #initialize(String[], boolean, RestartInitializer)} for details.\n\t * @param args main application arguments\n\t * @see #initialize(String[], boolean, RestartInitializer)\n\t */\n\tpublic static void initialize(String[] args) {\n\t\tinitialize(args, false, new DefaultRestartInitializer());\n\t}\n\n\t/**\n\t * Initialize restart support. See\n\t * {@link #initialize(String[], boolean, RestartInitializer)} for details.\n\t * @param args main application arguments\n\t * @param initializer the restart initializer\n\t * @see #initialize(String[], boolean, RestartInitializer)\n\t */\n\tpublic static void initialize(String[] args, RestartInitializer initializer) {\n\t\tinitialize(args, false, initializer, true);\n\t}\n\n\t/**\n\t * Initialize restart support. See\n\t * {@link #initialize(String[], boolean, RestartInitializer)} for details.\n\t * @param args main application arguments\n\t * @param forceReferenceCleanup if forcing of soft/weak reference should happen on\n\t * @see #initialize(String[], boolean, RestartInitializer)\n\t */\n\tpublic static void initialize(String[] args, boolean forceReferenceCleanup) {\n\t\tinitialize(args, forceReferenceCleanup, new DefaultRestartInitializer());\n\t}\n\n\t/**\n\t * Initialize restart support. See\n\t * {@link #initialize(String[], boolean, RestartInitializer, boolean)} for details.\n\t * @param args main application arguments\n\t * @param forceReferenceCleanup if forcing of soft/weak reference should happen on\n\t * @param initializer the restart initializer\n\t * @see #initialize(String[], boolean, RestartInitializer)\n\t */\n\tpublic static void initialize(String[] args, boolean forceReferenceCleanup, RestartInitializer initializer) {\n\t\tinitialize(args, forceReferenceCleanup, initializer, true);\n\t}\n\n\t/**\n\t * Initialize restart support for the current application. Called automatically by\n\t * {@link RestartApplicationListener} but can also be called directly if main\n\t * application arguments are not the same as those passed to the\n\t * {@link SpringApplication}.\n\t * @param args main application arguments\n\t * @param forceReferenceCleanup if forcing of soft/weak reference should happen on\n\t * each restart. This will slow down restarts and is intended primarily for testing\n\t * @param initializer the restart initializer\n\t * @param restartOnInitialize if the restarter should be restarted immediately when\n\t * the {@link RestartInitializer} returns non {@code null} results\n\t */\n\tpublic static void initialize(String[] args, boolean forceReferenceCleanup, RestartInitializer initializer,\n\t\t\tboolean restartOnInitialize) {\n\t\tRestarter localInstance = null;\n\t\tsynchronized (INSTANCE_MONITOR) {\n\t\t\tif (instance == null) {\n\t\t\t\tlocalInstance = new Restarter(Thread.currentThread(), args, forceReferenceCleanup, initializer);\n\t\t\t\tinstance = localInstance;\n\t\t\t}\n\t\t}\n\t\tif (localInstance != null) {\n\t\t\tlocalInstance.initialize(restartOnInitialize);\n\t\t}\n\t}\n\n\t/**\n\t * Return the active {@link Restarter} instance. Cannot be called before\n\t * {@link #initialize(String[]) initialization}.\n\t * @return the restarter\n\t */\n\tpublic static Restarter getInstance() {\n\t\tsynchronized (INSTANCE_MONITOR) {\n\t\t\tAssert.state(instance != null, \"Restarter has not been initialized\");\n\t\t\treturn instance;\n\t\t}\n\t}\n\n\t/**\n\t * Set the restarter instance (useful for testing).\n\t * @param instance the instance to set\n\t */\n\tstatic void setInstance(Restarter instance) {\n\t\tsynchronized (INSTANCE_MONITOR) {\n\t\t\tRestarter.instance = instance;\n\t\t}\n\t}\n\n\t/**\n\t * Clear the instance. Primarily provided for tests and not usually used in\n\t * application code.\n\t */\n\tpublic static void clearInstance() {\n\t\tsynchronized (INSTANCE_MONITOR) {\n\t\t\tinstance = null;\n\t\t}\n\t}\n\n\t/**\n\t * Thread that is created early so not to retain the {@link RestartClassLoader}.\n\t */\n\tprivate class LeakSafeThread extends Thread {\n\n\t\tprivate @Nullable Callable<?> callable;\n\n\t\tprivate @Nullable Object result;\n\n\t\tLeakSafeThread() {\n\t\t\tsetDaemon(false);\n\t\t}\n\n\t\tvoid call(Callable<?> callable) {\n\t\t\tthis.callable = callable;\n\t\t\tstart();\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\t<V> V callAndWait(Callable<V> callable) {\n\t\t\tthis.callable = callable;\n\t\t\tstart();\n\t\t\ttry {\n\t\t\t\tjoin();\n\t\t\t\tAssert.state(this.result != null, \"'this.result' must not be null\");\n\t\t\t\treturn (V) this.result;\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\t// We are safe to refresh the ActionThread (and indirectly call\n\t\t\t// AccessController.getContext()) since our stack doesn't include the\n\t\t\t// RestartClassLoader\n\t\t\ttry {\n\t\t\t\tRestarter.this.leakSafeThreads.put(new LeakSafeThread());\n\t\t\t\tAssert.state(this.callable != null, \"'callable' must not be null\");\n\t\t\t\tthis.result = this.callable.call();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t\tSystem.exit(1);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ThreadFactory} that creates a leak safe thread.\n\t */\n\tprivate final class LeakSafeThreadFactory implements ThreadFactory {\n\n\t\t@Override\n\t\tpublic Thread newThread(Runnable runnable) {\n\t\t\treturn getLeakSafeThread().callAndWait(() -> {\n\t\t\t\tThread thread = new Thread(runnable);\n\t\t\t\tthread.setContextClassLoader(Restarter.this.applicationClassLoader);\n\t\t\t\treturn thread;\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Arrays;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link UncaughtExceptionHandler} decorator that allows a thread to exit silently.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass SilentExitExceptionHandler implements UncaughtExceptionHandler {\n\n\tprivate final @Nullable UncaughtExceptionHandler delegate;\n\n\tSilentExitExceptionHandler(@Nullable UncaughtExceptionHandler delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic void uncaughtException(Thread thread, Throwable exception) {\n\t\tif (exception instanceof SilentExitException || (exception instanceof InvocationTargetException targetException\n\t\t\t\t&& targetException.getTargetException() instanceof SilentExitException)) {\n\t\t\tif (isJvmExiting(thread)) {\n\t\t\t\tpreventNonZeroExitCode();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.delegate != null) {\n\t\t\tthis.delegate.uncaughtException(thread, exception);\n\t\t}\n\t}\n\n\tprivate boolean isJvmExiting(Thread exceptionThread) {\n\t\tfor (Thread thread : getAllThreads()) {\n\t\t\tif (thread != exceptionThread && thread.isAlive() && !thread.isDaemon()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprotected Thread[] getAllThreads() {\n\t\tThreadGroup rootThreadGroup = getRootThreadGroup();\n\t\tThread[] threads = new Thread[32];\n\t\tint count = rootThreadGroup.enumerate(threads);\n\t\twhile (count == threads.length) {\n\t\t\tthreads = new Thread[threads.length * 2];\n\t\t\tcount = rootThreadGroup.enumerate(threads);\n\t\t}\n\t\treturn Arrays.copyOf(threads, count);\n\t}\n\n\tprivate ThreadGroup getRootThreadGroup() {\n\t\tThreadGroup candidate = Thread.currentThread().getThreadGroup();\n\t\twhile (candidate.getParent() != null) {\n\t\t\tcandidate = candidate.getParent();\n\t\t}\n\t\treturn candidate;\n\t}\n\n\tprotected void preventNonZeroExitCode() {\n\t\tSystem.exit(0);\n\t}\n\n\tstatic void setup(Thread thread) {\n\t\tUncaughtExceptionHandler handler = thread.getUncaughtExceptionHandler();\n\t\tif (!(handler instanceof SilentExitExceptionHandler)) {\n\t\t\thandler = new SilentExitExceptionHandler(handler);\n\t\t\tthread.setUncaughtExceptionHandler(handler);\n\t\t}\n\t}\n\n\tstatic void exitCurrentThread() {\n\t\tthrow new SilentExitException();\n\t}\n\n\tprivate static final class SilentExitException extends RuntimeException {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFile.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport java.io.Serial;\nimport java.io.Serializable;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A single file that may be served from a {@link ClassLoader}. Can be used to represent\n * files that have been added, modified or deleted since the original JAR was created.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ClassLoaderFileRepository\n */\npublic class ClassLoaderFile implements Serializable {\n\n\t@Serial\n\tprivate static final long serialVersionUID = 1;\n\n\tprivate final Kind kind;\n\n\tprivate final byte @Nullable [] contents;\n\n\tprivate final long lastModified;\n\n\t/**\n\t * Create a new {@link ClassLoaderFile} instance.\n\t * @param kind the kind of file\n\t * @param contents the file contents\n\t */\n\tpublic ClassLoaderFile(Kind kind, byte @Nullable [] contents) {\n\t\tthis(kind, System.currentTimeMillis(), contents);\n\t}\n\n\t/**\n\t * Create a new {@link ClassLoaderFile} instance.\n\t * @param kind the kind of file\n\t * @param lastModified the last modified time\n\t * @param contents the file contents\n\t */\n\tpublic ClassLoaderFile(Kind kind, long lastModified, byte @Nullable [] contents) {\n\t\tAssert.notNull(kind, \"'kind' must not be null\");\n\t\tif (kind == Kind.DELETED) {\n\t\t\tAssert.isTrue(contents == null, \"'contents' must be null\");\n\t\t}\n\t\telse {\n\t\t\tAssert.isTrue(contents != null, \"'contents' must not be null\");\n\t\t}\n\t\tthis.kind = kind;\n\t\tthis.lastModified = lastModified;\n\t\tthis.contents = contents;\n\t}\n\n\t/**\n\t * Return the file {@link Kind} (added, modified, deleted).\n\t * @return the kind\n\t */\n\tpublic Kind getKind() {\n\t\treturn this.kind;\n\t}\n\n\t/**\n\t * Return the time that the file was last modified.\n\t * @return the last modified time\n\t */\n\tpublic long getLastModified() {\n\t\treturn this.lastModified;\n\t}\n\n\t/**\n\t * Return the contents of the file as a byte array or {@code null} if\n\t * {@link #getKind()} is {@link Kind#DELETED}.\n\t * @return the contents or {@code null}\n\t */\n\tpublic byte @Nullable [] getContents() {\n\t\treturn this.contents;\n\t}\n\n\t/**\n\t * The kinds of class load files.\n\t */\n\tpublic enum Kind {\n\n\t\t/**\n\t\t * The file has been added since the original JAR was created.\n\t\t */\n\t\tADDED,\n\n\t\t/**\n\t\t * The file has been modified since the original JAR was created.\n\t\t */\n\t\tMODIFIED,\n\n\t\t/**\n\t\t * The file has been deleted since the original JAR was created.\n\t\t */\n\t\tDELETED\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A container for files that may be served from a {@link ClassLoader}. Can be used to\n * represent files that have been added, modified or deleted since the original JAR was\n * created.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ClassLoaderFile\n */\n@FunctionalInterface\npublic interface ClassLoaderFileRepository {\n\n\t/**\n\t * Empty {@link ClassLoaderFileRepository} implementation.\n\t */\n\tClassLoaderFileRepository NONE = (name) -> null;\n\n\t/**\n\t * Return a {@link ClassLoaderFile} for the given name or {@code null} if no file is\n\t * contained in this collection.\n\t * @param name the name of the file\n\t * @return a {@link ClassLoaderFile} or {@code null}\n\t */\n\t@Nullable ClassLoaderFile getFile(@Nullable String name);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileURLStreamHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLStreamHandler;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link URLStreamHandler} for the contents of a {@link ClassLoaderFile}.\n *\n * @author Phillip Webb\n * @since 1.5.0\n */\npublic class ClassLoaderFileURLStreamHandler extends URLStreamHandler {\n\n\tprivate final ClassLoaderFile file;\n\n\tpublic ClassLoaderFileURLStreamHandler(ClassLoaderFile file) {\n\t\tthis.file = file;\n\t}\n\n\t@Override\n\tprotected URLConnection openConnection(URL url) throws IOException {\n\t\treturn new Connection(url);\n\t}\n\n\tprivate class Connection extends URLConnection {\n\n\t\tConnection(URL url) {\n\t\t\tsuper(url);\n\t\t}\n\n\t\t@Override\n\t\tpublic void connect() throws IOException {\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\tbyte[] contents = ClassLoaderFileURLStreamHandler.this.file.getContents();\n\t\t\tAssert.state(contents != null, \"'contents' must not be null\");\n\t\t\treturn new ByteArrayInputStream(contents);\n\t\t}\n\n\t\t@Override\n\t\tpublic long getLastModified() {\n\t\t\treturn ClassLoaderFileURLStreamHandler.this.file.getLastModified();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFiles.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport java.io.Serial;\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport javax.management.loading.ClassLoaderRepository;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link ClassLoaderFileRepository} that maintains a collection of\n * {@link ClassLoaderFile} items grouped by source directories.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see ClassLoaderFile\n * @see ClassLoaderRepository\n */\npublic class ClassLoaderFiles implements ClassLoaderFileRepository, Serializable {\n\n\t@Serial\n\tprivate static final long serialVersionUID = 1;\n\n\tprivate final Map<String, SourceDirectory> sourceDirectories;\n\n\t/**\n\t * A flattened map of all files from all source directories for fast, O(1) lookups.\n\t * The key is the file's relative path, and the value is the ClassLoaderFile.\n\t */\n\tprivate final Map<String, ClassLoaderFile> filesByName;\n\n\t/**\n\t * Create a new {@link ClassLoaderFiles} instance.\n\t */\n\tpublic ClassLoaderFiles() {\n\t\tthis.sourceDirectories = new LinkedHashMap<>();\n\t\tthis.filesByName = new LinkedHashMap<>();\n\t}\n\n\t/**\n\t * Create a new {@link ClassLoaderFiles} instance.\n\t * @param classLoaderFiles the source classloader files.\n\t */\n\tpublic ClassLoaderFiles(ClassLoaderFiles classLoaderFiles) {\n\t\tAssert.notNull(classLoaderFiles, \"'classLoaderFiles' must not be null\");\n\t\tthis.sourceDirectories = new LinkedHashMap<>(classLoaderFiles.sourceDirectories);\n\t\tthis.filesByName = new LinkedHashMap<>(classLoaderFiles.filesByName);\n\t}\n\n\t/**\n\t * Add all elements items from the specified {@link ClassLoaderFiles} to this\n\t * instance.\n\t * @param files the files to add\n\t */\n\tpublic void addAll(ClassLoaderFiles files) {\n\t\tAssert.notNull(files, \"'files' must not be null\");\n\t\tfor (SourceDirectory directory : files.getSourceDirectories()) {\n\t\t\tfor (Map.Entry<String, ClassLoaderFile> entry : directory.getFilesEntrySet()) {\n\t\t\t\taddFile(directory.getName(), entry.getKey(), entry.getValue());\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add a single {@link ClassLoaderFile} to the collection.\n\t * @param name the name of the file\n\t * @param file the file to add\n\t */\n\tpublic void addFile(String name, ClassLoaderFile file) {\n\t\taddFile(\"\", name, file);\n\t}\n\n\t/**\n\t * Add a single {@link ClassLoaderFile} to the collection.\n\t * @param sourceDirectory the source directory of the file\n\t * @param name the name of the file\n\t * @param file the file to add\n\t */\n\tpublic void addFile(String sourceDirectory, String name, ClassLoaderFile file) {\n\t\tAssert.notNull(sourceDirectory, \"'sourceDirectory' must not be null\");\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tremoveAll(name);\n\t\tgetOrCreateSourceDirectory(sourceDirectory).add(name, file);\n\t\tthis.filesByName.put(name, file);\n\t}\n\n\tprivate void removeAll(String name) {\n\t\tfor (SourceDirectory sourceDirectory : this.sourceDirectories.values()) {\n\t\t\tsourceDirectory.remove(name);\n\t\t}\n\t\tthis.filesByName.remove(name);\n\t}\n\n\t/**\n\t * Get or create a {@link SourceDirectory} with the given name.\n\t * @param name the name of the directory\n\t * @return an existing or newly added {@link SourceDirectory}\n\t */\n\tprotected final SourceDirectory getOrCreateSourceDirectory(String name) {\n\t\treturn this.sourceDirectories.computeIfAbsent(name, (key) -> new SourceDirectory(name));\n\t}\n\n\t/**\n\t * Return all {@link SourceDirectory SourceDirectories} that have been added to the\n\t * collection.\n\t * @return a collection of {@link SourceDirectory} items\n\t */\n\tpublic Collection<SourceDirectory> getSourceDirectories() {\n\t\treturn Collections.unmodifiableCollection(this.sourceDirectories.values());\n\t}\n\n\t/**\n\t * Return the size of the collection.\n\t * @return the size of the collection\n\t */\n\tpublic int size() {\n\t\treturn this.filesByName.size();\n\t}\n\n\t@Override\n\tpublic @Nullable ClassLoaderFile getFile(@Nullable String name) {\n\t\treturn this.filesByName.get(name);\n\t}\n\n\t/**\n\t * Returns a set of all file entries across all source directories for efficient\n\t * iteration.\n\t * @return a set of all file entries\n\t * @since 4.0.0\n\t */\n\tpublic Set<Entry<String, ClassLoaderFile>> getFileEntries() {\n\t\treturn Collections.unmodifiableSet(this.filesByName.entrySet());\n\t}\n\n\t/**\n\t * An individual source directory that is being managed by the collection.\n\t */\n\tpublic static class SourceDirectory implements Serializable {\n\n\t\t@Serial\n\t\tprivate static final long serialVersionUID = 1;\n\n\t\tprivate final String name;\n\n\t\tprivate final Map<String, ClassLoaderFile> files = new LinkedHashMap<>();\n\n\t\tSourceDirectory(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Set<Entry<String, ClassLoaderFile>> getFilesEntrySet() {\n\t\t\treturn this.files.entrySet();\n\t\t}\n\n\t\tprotected final void add(String name, ClassLoaderFile file) {\n\t\t\tthis.files.put(name, file);\n\t\t}\n\n\t\tprotected final void remove(String name) {\n\t\t\tthis.files.remove(name);\n\t\t}\n\n\t\tprotected final @Nullable ClassLoaderFile get(String name) {\n\t\t\treturn this.files.get(name);\n\t\t}\n\n\t\t/**\n\t\t * Return the name of the source directory.\n\t\t * @return the name of the source directory\n\t\t */\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\t/**\n\t\t * Return all {@link ClassLoaderFile ClassLoaderFiles} in the collection that are\n\t\t * contained in this source directory.\n\t\t * @return the files contained in the source directory\n\t\t */\n\t\tpublic Collection<ClassLoaderFile> getFiles() {\n\t\t\treturn Collections.unmodifiableCollection(this.files.values());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.security.ProtectionDomain;\nimport java.util.Enumeration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.core.SmartClassLoader;\nimport org.springframework.util.Assert;\n\n/**\n * Disposable {@link ClassLoader} used to support application restarting. Provides parent\n * last loading for the specified URLs.\n *\n * @author Andy Clement\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class RestartClassLoader extends URLClassLoader implements SmartClassLoader {\n\n\tprivate final ClassLoaderFileRepository updatedFiles;\n\n\t/**\n\t * Create a new {@link RestartClassLoader} instance.\n\t * @param parent the parent classloader\n\t * @param urls the urls managed by the classloader\n\t */\n\tpublic RestartClassLoader(ClassLoader parent, URL[] urls) {\n\t\tthis(parent, urls, ClassLoaderFileRepository.NONE);\n\t}\n\n\t/**\n\t * Create a new {@link RestartClassLoader} instance.\n\t * @param parent the parent classloader\n\t * @param updatedFiles any files that have been updated since the JARs referenced in\n\t * URLs were created.\n\t * @param urls the urls managed by the classloader\n\t */\n\tpublic RestartClassLoader(ClassLoader parent, URL[] urls, ClassLoaderFileRepository updatedFiles) {\n\t\tsuper(urls, parent);\n\t\tAssert.notNull(parent, \"'parent' must not be null\");\n\t\tAssert.notNull(updatedFiles, \"'updatedFiles' must not be null\");\n\t\tthis.updatedFiles = updatedFiles;\n\t}\n\n\t@Override\n\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t// Use the parent since we're shadowing resource and we don't want duplicates\n\t\tEnumeration<URL> resources = getParent().getResources(name);\n\t\tClassLoaderFile file = this.updatedFiles.getFile(name);\n\t\tif (file != null) {\n\t\t\t// Assume that we're replacing just the first item\n\t\t\tif (resources.hasMoreElements()) {\n\t\t\t\tresources.nextElement();\n\t\t\t}\n\t\t\tif (file.getKind() != Kind.DELETED) {\n\t\t\t\treturn new CompoundEnumeration<>(createFileUrl(name, file), resources);\n\t\t\t}\n\t\t}\n\t\treturn resources;\n\t}\n\n\t@Override\n\tpublic @Nullable URL getResource(String name) {\n\t\tClassLoaderFile file = this.updatedFiles.getFile(name);\n\t\tif (file != null && file.getKind() == Kind.DELETED) {\n\t\t\treturn null;\n\t\t}\n\t\tURL resource = findResource(name);\n\t\tif (resource != null) {\n\t\t\treturn resource;\n\t\t}\n\t\treturn getParent().getResource(name);\n\t}\n\n\t@Override\n\tpublic @Nullable URL findResource(String name) {\n\t\tfinal ClassLoaderFile file = this.updatedFiles.getFile(name);\n\t\tif (file == null) {\n\t\t\treturn super.findResource(name);\n\t\t}\n\t\tif (file.getKind() == Kind.DELETED) {\n\t\t\treturn null;\n\t\t}\n\t\treturn createFileUrl(name, file);\n\t}\n\n\t@Override\n\tpublic Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\tString path = name.replace('.', '/').concat(\".class\");\n\t\tClassLoaderFile file = this.updatedFiles.getFile(path);\n\t\tif (file != null && file.getKind() == Kind.DELETED) {\n\t\t\tthrow new ClassNotFoundException(name);\n\t\t}\n\t\tsynchronized (getClassLoadingLock(name)) {\n\t\t\tClass<?> loadedClass = findLoadedClass(name);\n\t\t\tif (loadedClass == null) {\n\t\t\t\ttry {\n\t\t\t\t\tloadedClass = findClass(name);\n\t\t\t\t}\n\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\tloadedClass = Class.forName(name, false, getParent());\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (resolve) {\n\t\t\t\tresolveClass(loadedClass);\n\t\t\t}\n\t\t\treturn loadedClass;\n\t\t}\n\t}\n\n\t@Override\n\tprotected Class<?> findClass(String name) throws ClassNotFoundException {\n\t\tString path = name.replace('.', '/').concat(\".class\");\n\t\tfinal ClassLoaderFile file = this.updatedFiles.getFile(path);\n\t\tif (file == null) {\n\t\t\treturn super.findClass(name);\n\t\t}\n\t\tif (file.getKind() == Kind.DELETED) {\n\t\t\tthrow new ClassNotFoundException(name);\n\t\t}\n\t\tbyte[] bytes = file.getContents();\n\t\tAssert.state(bytes != null, \"'bytes' must not be null\");\n\t\treturn defineClass(name, bytes, 0, bytes.length);\n\t}\n\n\t@Override\n\tpublic Class<?> publicDefineClass(String name, byte[] b, @Nullable ProtectionDomain protectionDomain) {\n\t\treturn defineClass(name, b, 0, b.length, protectionDomain);\n\t}\n\n\t@Override\n\tpublic ClassLoader getOriginalClassLoader() {\n\t\treturn getParent();\n\t}\n\n\tprivate URL createFileUrl(String name, ClassLoaderFile file) {\n\t\ttry {\n\t\t\treturn new URL(\"reloaded\", null, -1, \"/\" + name, new ClassLoaderFileURLStreamHandler(file));\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isClassReloadable(Class<?> classType) {\n\t\treturn (classType.getClassLoader() instanceof RestartClassLoader);\n\t}\n\n\t/**\n\t * Compound {@link Enumeration} that adds an item to the front.\n\t */\n\tprivate static class CompoundEnumeration<E> implements Enumeration<E> {\n\n\t\tprivate @Nullable E firstElement;\n\n\t\tprivate final Enumeration<E> enumeration;\n\n\t\tCompoundEnumeration(@Nullable E firstElement, Enumeration<E> enumeration) {\n\t\t\tthis.firstElement = firstElement;\n\t\t\tthis.enumeration = enumeration;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean hasMoreElements() {\n\t\t\treturn (this.firstElement != null || this.enumeration.hasMoreElements());\n\t\t}\n\n\t\t@Override\n\t\tpublic E nextElement() {\n\t\t\tif (this.firstElement == null) {\n\t\t\t\treturn this.enumeration.nextElement();\n\t\t\t}\n\t\t\tE element = this.firstElement;\n\t\t\tthis.firstElement = null;\n\t\t\treturn element;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/classloader/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classloaders used for reload support.\n */\n@NullMarked\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Application restart support.\n */\n@NullMarked\npackage org.springframework.boot.devtools.restart;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/server/DefaultSourceDirectoryUrlFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.net.URL;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Default implementation of {@link SourceDirectoryUrlFilter} that attempts to match URLs\n * using common naming conventions.\n *\n * @author Phillip Webb\n * @since 2.3.0\n */\npublic class DefaultSourceDirectoryUrlFilter implements SourceDirectoryUrlFilter {\n\n\tprivate static final String[] COMMON_ENDINGS = { \"/target/classes\", \"/bin\" };\n\n\tprivate static final Pattern URL_MODULE_PATTERN = Pattern.compile(\".*/(.+)\\\\.jar\");\n\n\tprivate static final Pattern VERSION_PATTERN = Pattern.compile(\"^-\\\\d+(?:\\\\.\\\\d+)*(?:[.-].+)?$\");\n\n\t@Override\n\tpublic boolean isMatch(String sourceDirectory, URL url) {\n\t\tString jarName = getJarName(url);\n\t\tif (!StringUtils.hasLength(jarName)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn isMatch(sourceDirectory, jarName);\n\t}\n\n\tprivate @Nullable String getJarName(URL url) {\n\t\tMatcher matcher = URL_MODULE_PATTERN.matcher(url.toString());\n\t\tif (matcher.find()) {\n\t\t\treturn matcher.group(1);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isMatch(String sourceDirectory, String jarName) {\n\t\tsourceDirectory = stripTrailingSlash(sourceDirectory);\n\t\tsourceDirectory = stripCommonEnds(sourceDirectory);\n\t\tString[] directories = StringUtils.delimitedListToStringArray(sourceDirectory, \"/\");\n\t\tfor (int i = directories.length - 1; i >= 0; i--) {\n\t\t\tif (isDirectoryMatch(directories[i], jarName)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isDirectoryMatch(String directory, String jarName) {\n\t\tif (!jarName.startsWith(directory)) {\n\t\t\treturn false;\n\t\t}\n\t\tString version = jarName.substring(directory.length());\n\t\treturn version.isEmpty() || VERSION_PATTERN.matcher(version).matches();\n\t}\n\n\tprivate String stripTrailingSlash(String string) {\n\t\tif (string.endsWith(\"/\")) {\n\t\t\treturn string.substring(0, string.length() - 1);\n\t\t}\n\t\treturn string;\n\t}\n\n\tprivate String stripCommonEnds(String string) {\n\t\tfor (String ending : COMMON_ENDINGS) {\n\t\t\tif (string.endsWith(ending)) {\n\t\t\t\treturn string.substring(0, string.length() - ending.length());\n\t\t\t}\n\t\t}\n\t\treturn string;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/server/HttpRestartServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * An HTTP server that can be used to upload updated {@link ClassLoaderFiles} and trigger\n * restarts.\n *\n * @author Phillip Webb\n * @since 1.3.0\n * @see RestartServer\n */\npublic class HttpRestartServer {\n\n\tprivate static final Log logger = LogFactory.getLog(HttpRestartServer.class);\n\n\tprivate final RestartServer server;\n\n\t/**\n\t * Create a new {@link HttpRestartServer} instance.\n\t * @param sourceDirectoryUrlFilter the source filter used to link remote directory to\n\t * the local classpath\n\t */\n\tpublic HttpRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {\n\t\tAssert.notNull(sourceDirectoryUrlFilter, \"'sourceDirectoryUrlFilter' must not be null\");\n\t\tthis.server = new RestartServer(sourceDirectoryUrlFilter);\n\t}\n\n\t/**\n\t * Create a new {@link HttpRestartServer} instance.\n\t * @param restartServer the underlying restart server\n\t */\n\tpublic HttpRestartServer(RestartServer restartServer) {\n\t\tAssert.notNull(restartServer, \"'restartServer' must not be null\");\n\t\tthis.server = restartServer;\n\t}\n\n\t/**\n\t * Handle a server request.\n\t * @param request the request\n\t * @param response the response\n\t * @throws IOException in case of I/O errors\n\t */\n\tpublic void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {\n\t\ttry {\n\t\t\tAssert.state(request.getHeaders().getContentLength() > 0, \"No content\");\n\t\t\tObjectInputStream objectInputStream = new ObjectInputStream(request.getBody());\n\t\t\tClassLoaderFiles files = (ClassLoaderFiles) objectInputStream.readObject();\n\t\t\tobjectInputStream.close();\n\t\t\tthis.server.updateAndRestart(files);\n\t\t\tresponse.setStatusCode(HttpStatus.OK);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.warn(\"Unable to handler restart server HTTP request\", ex);\n\t\t\tresponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/server/HttpRestartServerHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.io.IOException;\n\nimport org.springframework.boot.devtools.remote.server.Handler;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * Adapts {@link HttpRestartServer} to a {@link Handler}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class HttpRestartServerHandler implements Handler {\n\n\tprivate final HttpRestartServer server;\n\n\t/**\n\t * Create a new {@link HttpRestartServerHandler} instance.\n\t * @param server the server to adapt\n\t */\n\tpublic HttpRestartServerHandler(HttpRestartServer server) {\n\t\tAssert.notNull(server, \"'server' must not be null\");\n\t\tthis.server = server;\n\t}\n\n\t@Override\n\tpublic void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {\n\t\tthis.server.handle(request, response);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/server/RestartServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * Server used to {@link Restarter restart} the current application with updated\n * {@link ClassLoaderFiles}.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class RestartServer {\n\n\tprivate static final Log logger = LogFactory.getLog(RestartServer.class);\n\n\tprivate final SourceDirectoryUrlFilter sourceDirectoryUrlFilter;\n\n\tprivate final ClassLoader classLoader;\n\n\t/**\n\t * Create a new {@link RestartServer} instance.\n\t * @param sourceDirectoryUrlFilter the source filter used to link remote directory to\n\t * the local classpath\n\t */\n\tpublic RestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {\n\t\tthis(sourceDirectoryUrlFilter, Thread.currentThread().getContextClassLoader());\n\t}\n\n\t/**\n\t * Create a new {@link RestartServer} instance.\n\t * @param sourceDirectoryUrlFilter the source filter used to link remote directory to\n\t * the local classpath\n\t * @param classLoader the application classloader\n\t */\n\tpublic RestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter, ClassLoader classLoader) {\n\t\tAssert.notNull(sourceDirectoryUrlFilter, \"'sourceDirectoryUrlFilter' must not be null\");\n\t\tAssert.notNull(classLoader, \"'classLoader' must not be null\");\n\t\tthis.sourceDirectoryUrlFilter = sourceDirectoryUrlFilter;\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t/**\n\t * Update the current running application with the specified {@link ClassLoaderFiles}\n\t * and trigger a reload.\n\t * @param files updated class loader files\n\t */\n\tpublic void updateAndRestart(ClassLoaderFiles files) {\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tSet<URL> classLoaderUrls = getClassLoaderUrls();\n\t\tfor (SourceDirectory directory : files.getSourceDirectories()) {\n\t\t\tfor (Entry<String, ClassLoaderFile> entry : directory.getFilesEntrySet()) {\n\t\t\t\tfor (URL url : classLoaderUrls) {\n\t\t\t\t\tif (updateFileSystem(url, entry.getKey(), entry.getValue())) {\n\t\t\t\t\t\turls.add(url);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\turls.addAll(getMatchingUrls(classLoaderUrls, directory.getName()));\n\t\t}\n\t\tupdateTimeStamp(urls);\n\t\trestart(urls, files);\n\t}\n\n\tprivate boolean updateFileSystem(URL url, String name, ClassLoaderFile classLoaderFile) {\n\t\tif (!isDirectoryUrl(url.toString())) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tFile directory = ResourceUtils.getFile(url);\n\t\t\tFile file = new File(directory, name);\n\t\t\tif (file.exists() && file.canWrite()) {\n\t\t\t\tif (classLoaderFile.getKind() == Kind.DELETED) {\n\t\t\t\t\treturn file.delete();\n\t\t\t\t}\n\t\t\t\tbyte[] contents = classLoaderFile.getContents();\n\t\t\t\tAssert.state(contents != null, \"'contents' must not be null\");\n\t\t\t\tFileCopyUtils.copy(contents, file);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isDirectoryUrl(String urlString) {\n\t\treturn urlString.startsWith(\"file:\") && urlString.endsWith(\"/\");\n\t}\n\n\tprivate Set<URL> getMatchingUrls(Set<URL> urls, String sourceDirectory) {\n\t\tSet<URL> matchingUrls = new LinkedHashSet<>();\n\t\tfor (URL url : urls) {\n\t\t\tif (this.sourceDirectoryUrlFilter.isMatch(sourceDirectory, url)) {\n\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\tlogger.debug(\"URL \" + url + \" matched against source directory \" + sourceDirectory);\n\t\t\t\t}\n\t\t\t\tmatchingUrls.add(url);\n\t\t\t}\n\t\t}\n\t\treturn matchingUrls;\n\t}\n\n\tprivate Set<URL> getClassLoaderUrls() {\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tClassLoader classLoader = this.classLoader;\n\t\twhile (classLoader != null) {\n\t\t\tif (classLoader instanceof URLClassLoader urlClassLoader) {\n\t\t\t\tCollections.addAll(urls, urlClassLoader.getURLs());\n\t\t\t}\n\t\t\tclassLoader = classLoader.getParent();\n\t\t}\n\t\treturn urls;\n\t}\n\n\tprivate void updateTimeStamp(Iterable<URL> urls) {\n\t\tfor (URL url : urls) {\n\t\t\tupdateTimeStamp(url);\n\t\t}\n\t}\n\n\tprivate void updateTimeStamp(URL url) {\n\t\ttry {\n\t\t\tURL actualUrl = ResourceUtils.extractJarFileURL(url);\n\t\t\tFile file = ResourceUtils.getFile(actualUrl, \"Jar URL\");\n\t\t\tfile.setLastModified(System.currentTimeMillis());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t/**\n\t * Called to restart the application.\n\t * @param urls the updated URLs\n\t * @param files the updated files\n\t */\n\tprotected void restart(Set<URL> urls, ClassLoaderFiles files) {\n\t\tRestarter restarter = Restarter.getInstance();\n\t\trestarter.addUrls(urls);\n\t\trestarter.addClassLoaderFiles(files);\n\t\trestarter.restart();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/server/SourceDirectoryUrlFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.net.URL;\n\n/**\n * Filter URLs based on a source directory name. Used to match URLs from the running\n * classpath against source directory on a remote system.\n *\n * @author Phillip Webb\n * @since 2.3.0\n * @see DefaultSourceDirectoryUrlFilter\n */\n@FunctionalInterface\npublic interface SourceDirectoryUrlFilter {\n\n\t/**\n\t * Determine if the specified URL matches a source directory.\n\t * @param sourceDirectory the source directory\n\t * @param url the URL to check\n\t * @return {@code true} if the URL matches\n\t */\n\tboolean isMatch(String sourceDirectory, URL url);\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Remote restart server.\n */\n@NullMarked\npackage org.springframework.boot.devtools.restart.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/settings/DevToolsSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.settings;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.devtools.logger.DevToolsLogFactory;\nimport org.springframework.core.io.UrlResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\n\n/**\n * DevTools settings loaded from {@literal /META-INF/spring-devtools.properties} files.\n *\n * @author Phillip Webb\n * @since 1.3.0\n */\npublic class DevToolsSettings {\n\n\t/**\n\t * The location to look for settings properties. Can be present in multiple JAR files.\n\t */\n\tpublic static final String SETTINGS_RESOURCE_LOCATION = \"META-INF/spring-devtools.properties\";\n\n\tprivate static final Log logger = DevToolsLogFactory.getLog(DevToolsSettings.class);\n\n\tprivate static @Nullable DevToolsSettings settings;\n\n\tprivate final List<Pattern> restartIncludePatterns = new ArrayList<>();\n\n\tprivate final List<Pattern> restartExcludePatterns = new ArrayList<>();\n\n\tprivate final Map<String, Object> propertyDefaults = new HashMap<>();\n\n\tDevToolsSettings() {\n\t}\n\n\tprivate void add(Map<?, ?> properties) {\n\t\tMap<String, Pattern> includes = getPatterns(properties, \"restart.include.\");\n\t\tthis.restartIncludePatterns.addAll(includes.values());\n\t\tMap<String, Pattern> excludes = getPatterns(properties, \"restart.exclude.\");\n\t\tthis.restartExcludePatterns.addAll(excludes.values());\n\t\tproperties.forEach((key, value) -> {\n\t\t\tString name = String.valueOf(key);\n\t\t\tif (name.startsWith(\"defaults.\")) {\n\t\t\t\tname = name.substring(\"defaults.\".length());\n\t\t\t\tthis.propertyDefaults.put(name, value);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate Map<String, Pattern> getPatterns(Map<?, ?> properties, String prefix) {\n\t\tMap<String, Pattern> patterns = new LinkedHashMap<>();\n\t\tproperties.forEach((key, value) -> {\n\t\t\tString name = String.valueOf(key);\n\t\t\tif (name.startsWith(prefix)) {\n\t\t\t\tPattern pattern = Pattern.compile((String) value);\n\t\t\t\tpatterns.put(name, pattern);\n\t\t\t}\n\t\t});\n\t\treturn patterns;\n\t}\n\n\tpublic boolean isRestartInclude(URL url) {\n\t\treturn isMatch(url.toString(), this.restartIncludePatterns);\n\t}\n\n\tpublic boolean isRestartExclude(URL url) {\n\t\treturn isMatch(url.toString(), this.restartExcludePatterns);\n\t}\n\n\tpublic Map<String, Object> getPropertyDefaults() {\n\t\treturn Collections.unmodifiableMap(this.propertyDefaults);\n\t}\n\n\tprivate boolean isMatch(String url, List<Pattern> patterns) {\n\t\tfor (Pattern pattern : patterns) {\n\t\t\tif (pattern.matcher(url).find()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static DevToolsSettings get() {\n\t\tif (settings == null) {\n\t\t\tsettings = load();\n\t\t}\n\t\treturn settings;\n\t}\n\n\tstatic DevToolsSettings load() {\n\t\treturn load(SETTINGS_RESOURCE_LOCATION);\n\t}\n\n\tstatic DevToolsSettings load(String location) {\n\t\ttry {\n\t\t\tDevToolsSettings settings = new DevToolsSettings();\n\t\t\tEnumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(location);\n\t\t\twhile (urls.hasMoreElements()) {\n\t\t\t\tsettings.add(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));\n\t\t\t}\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tlogger.debug(\"Included patterns for restart : \" + settings.restartIncludePatterns);\n\t\t\t\tlogger.debug(\"Excluded patterns for restart : \" + settings.restartExcludePatterns);\n\t\t\t}\n\t\t\treturn settings;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load devtools settings from location [\" + location + \"]\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/settings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for loading DevTools settings.\n */\n@NullMarked\npackage org.springframework.boot.devtools.settings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/system/DevToolsEnablementDeducer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.system;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.SpringApplicationAotProcessor;\nimport org.springframework.core.NativeDetector;\n\n/**\n * Utility to deduce if DevTools should be enabled in the current context.\n *\n * @author Madhura Bhave\n * @since 2.2.0\n */\npublic final class DevToolsEnablementDeducer {\n\n\tprivate static final Set<String> SKIPPED_STACK_ELEMENTS;\n\n\tstatic {\n\t\tSet<String> skipped = new LinkedHashSet<>();\n\t\tskipped.add(\"org.junit.runners.\");\n\t\tskipped.add(\"org.junit.platform.\");\n\t\tskipped.add(\"org.springframework.boot.test.\");\n\t\tskipped.add(SpringApplicationAotProcessor.class.getName());\n\t\tskipped.add(\"cucumber.runtime.\");\n\t\tSKIPPED_STACK_ELEMENTS = Collections.unmodifiableSet(skipped);\n\t}\n\n\tprivate DevToolsEnablementDeducer() {\n\t}\n\n\t/**\n\t * Checks if a specific {@link StackTraceElement} in the current thread's stacktrace\n\t * should cause devtools to be disabled. Devtools will also be disabled if running in\n\t * a native image.\n\t * @param thread the current thread\n\t * @return {@code true} if devtools should be enabled\n\t */\n\tpublic static boolean shouldEnable(Thread thread) {\n\t\tif (NativeDetector.inNativeImage()) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (StackTraceElement element : thread.getStackTrace()) {\n\t\t\tif (isSkippedStackElement(element)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate static boolean isSkippedStackElement(StackTraceElement element) {\n\t\tfor (String skipped : SKIPPED_STACK_ELEMENTS) {\n\t\t\tif (element.getClassName().startsWith(skipped)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Devtools system support classes.\n */\n@NullMarked\npackage org.springframework.boot.devtools.system;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.devtools.add-properties\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable development property defaults.\",\n      \"defaultValue\": true\n    }\n  ],\n  \"hints\": []\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration\norg.springframework.boot.devtools.autoconfigure.DevToolsR2dbcAutoConfiguration\norg.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration\norg.springframework.boot.devtools.autoconfigure.RemoteDevToolsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/resources/META-INF/spring-devtools.properties",
    "content": "restart.exclude.spring-boot=/spring-boot/(bin|build|out)/\nrestart.exclude.spring-boot-devtools=/spring-boot-devtools/(bin|build|out)/\nrestart.exclude.spring-boot-autoconfigure=/spring-boot-autoconfigure/(bin|build|out)/\nrestart.exclude.spring-boot-actuator=/spring-boot-actuator/(bin|build|out)/\nrestart.exclude.spring-boot-starter=/spring-boot-starter/(bin|build|out)/\nrestart.exclude.spring-boot-starters=/spring-boot-starter-[\\\\w-]+/\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/resources/META-INF/spring.factories",
    "content": "# ApplicationContext Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.devtools.restart.RestartScopeInitializer\n\n# Application Listeners\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.devtools.logger.DevToolsLogFactory$Listener,\\\norg.springframework.boot.devtools.restart.RestartApplicationListener\n\n# Environment Post Processors\norg.springframework.boot.EnvironmentPostProcessor=\\\norg.springframework.boot.devtools.env.DevToolsHomePropertiesPostProcessor,\\\norg.springframework.boot.devtools.env.DevToolsPropertyDefaultsPostProcessor\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/resources/org/springframework/boot/devtools/livereload/livereload.js",
    "content": "(function() {\nvar __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __less = {}, __startup = {};\n\n// customevents\nvar CustomEvents;\nCustomEvents = {\n  bind: function(element, eventName, handler) {\n    if (element.addEventListener) {\n      return element.addEventListener(eventName, handler, false);\n    } else if (element.attachEvent) {\n      element[eventName] = 1;\n      return element.attachEvent('onpropertychange', function(event) {\n        if (event.propertyName === eventName) {\n          return handler();\n        }\n      });\n    } else {\n      throw new Error(\"Attempt to attach custom event \" + eventName + \" to something which isn't a DOMElement\");\n    }\n  },\n  fire: function(element, eventName) {\n    var event;\n    if (element.addEventListener) {\n      event = document.createEvent('HTMLEvents');\n      event.initEvent(eventName, true, true);\n      return document.dispatchEvent(event);\n    } else if (element.attachEvent) {\n      if (element[eventName]) {\n        return element[eventName]++;\n      }\n    } else {\n      throw new Error(\"Attempt to fire custom event \" + eventName + \" on something which isn't a DOMElement\");\n    }\n  }\n};\n__customevents.bind = CustomEvents.bind;\n__customevents.fire = CustomEvents.fire;\n\n// protocol\nvar PROTOCOL_6, PROTOCOL_7, Parser, ProtocolError;\nvar __indexOf = Array.prototype.indexOf || function(item) {\n  for (var i = 0, l = this.length; i < l; i++) {\n    if (this[i] === item) return i;\n  }\n  return -1;\n};\n__protocol.PROTOCOL_6 = PROTOCOL_6 = 'http://livereload.com/protocols/official-6';\n__protocol.PROTOCOL_7 = PROTOCOL_7 = 'http://livereload.com/protocols/official-7';\n__protocol.ProtocolError = ProtocolError = (function() {\n  function ProtocolError(reason, data) {\n    this.message = \"LiveReload protocol error (\" + reason + \") after receiving data: \\\"\" + data + \"\\\".\";\n  }\n  return ProtocolError;\n})();\n__protocol.Parser = Parser = (function() {\n  function Parser(handlers) {\n    this.handlers = handlers;\n    this.reset();\n  }\n  Parser.prototype.reset = function() {\n    return this.protocol = null;\n  };\n  Parser.prototype.process = function(data) {\n    var command, message, options, _ref;\n    try {\n      if (!(this.protocol != null)) {\n        if (data.match(/^!!ver:([\\d.]+)$/)) {\n          this.protocol = 6;\n        } else if (message = this._parseMessage(data, ['hello'])) {\n          if (!message.protocols.length) {\n            throw new ProtocolError(\"no protocols specified in handshake message\");\n          } else if (__indexOf.call(message.protocols, PROTOCOL_7) >= 0) {\n            this.protocol = 7;\n          } else if (__indexOf.call(message.protocols, PROTOCOL_6) >= 0) {\n            this.protocol = 6;\n          } else {\n            throw new ProtocolError(\"no supported protocols found\");\n          }\n        }\n        return this.handlers.connected(this.protocol);\n      } else if (this.protocol === 6) {\n        message = JSON.parse(data);\n        if (!message.length) {\n          throw new ProtocolError(\"protocol 6 messages must be arrays\");\n        }\n        command = message[0], options = message[1];\n        if (command !== 'refresh') {\n          throw new ProtocolError(\"unknown protocol 6 command\");\n        }\n        return this.handlers.message({\n          command: 'reload',\n          path: options.path,\n          liveCSS: (_ref = options.apply_css_live) != null ? _ref : true\n        });\n      } else {\n        message = this._parseMessage(data, ['reload', 'alert']);\n        return this.handlers.message(message);\n      }\n    } catch (e) {\n      if (e instanceof ProtocolError) {\n        return this.handlers.error(e);\n      } else {\n        throw e;\n      }\n    }\n  };\n  Parser.prototype._parseMessage = function(data, validCommands) {\n    var message, _ref;\n    try {\n      message = JSON.parse(data);\n    } catch (e) {\n      throw new ProtocolError('unparsable JSON', data);\n    }\n    if (!message.command) {\n      throw new ProtocolError('missing \"command\" key', data);\n    }\n    if (_ref = message.command, __indexOf.call(validCommands, _ref) < 0) {\n      throw new ProtocolError(\"invalid command '\" + message.command + \"', only valid commands are: \" + (validCommands.join(', ')) + \")\", data);\n    }\n    return message;\n  };\n  return Parser;\n})();\n\n// connector\n// Generated by CoffeeScript 1.3.3\nvar Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref;\n\n_ref = __protocol, Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7;\n\nVersion = '2.0.8';\n\n__connector.Connector = Connector = (function() {\n\n  function Connector(options, WebSocket, Timer, handlers) {\n    var _this = this;\n    this.options = options;\n    this.WebSocket = WebSocket;\n    this.Timer = Timer;\n    this.handlers = handlers;\n    this._uri = \"ws://\" + this.options.host + \":\" + this.options.port + \"/livereload\";\n    this._nextDelay = this.options.mindelay;\n    this._connectionDesired = false;\n    this.protocol = 0;\n    this.protocolParser = new Parser({\n      connected: function(protocol) {\n        _this.protocol = protocol;\n        _this._handshakeTimeout.stop();\n        _this._nextDelay = _this.options.mindelay;\n        _this._disconnectionReason = 'broken';\n        return _this.handlers.connected(protocol);\n      },\n      error: function(e) {\n        _this.handlers.error(e);\n        return _this._closeOnError();\n      },\n      message: function(message) {\n        return _this.handlers.message(message);\n      }\n    });\n    this._handshakeTimeout = new Timer(function() {\n      if (!_this._isSocketConnected()) {\n        return;\n      }\n      _this._disconnectionReason = 'handshake-timeout';\n      return _this.socket.close();\n    });\n    this._reconnectTimer = new Timer(function() {\n      if (!_this._connectionDesired) {\n        return;\n      }\n      return _this.connect();\n    });\n    this.connect();\n  }\n\n  Connector.prototype._isSocketConnected = function() {\n    return this.socket && this.socket.readyState === this.WebSocket.OPEN;\n  };\n\n  Connector.prototype.connect = function() {\n    var _this = this;\n    this._connectionDesired = true;\n    if (this._isSocketConnected()) {\n      return;\n    }\n    this._reconnectTimer.stop();\n    this._disconnectionReason = 'cannot-connect';\n    this.protocolParser.reset();\n    this.handlers.connecting();\n    this.socket = new this.WebSocket(this._uri);\n    this.socket.onopen = function(e) {\n      return _this._onopen(e);\n    };\n    this.socket.onclose = function(e) {\n      return _this._onclose(e);\n    };\n    this.socket.onmessage = function(e) {\n      return _this._onmessage(e);\n    };\n    return this.socket.onerror = function(e) {\n      return _this._onerror(e);\n    };\n  };\n\n  Connector.prototype.disconnect = function() {\n    this._connectionDesired = false;\n    this._reconnectTimer.stop();\n    if (!this._isSocketConnected()) {\n      return;\n    }\n    this._disconnectionReason = 'manual';\n    return this.socket.close();\n  };\n\n  Connector.prototype._scheduleReconnection = function() {\n    if (!this._connectionDesired) {\n      return;\n    }\n    if (!this._reconnectTimer.running) {\n      this._reconnectTimer.start(this._nextDelay);\n      return this._nextDelay = Math.min(this.options.maxdelay, this._nextDelay * 2);\n    }\n  };\n\n  Connector.prototype.sendCommand = function(command) {\n    if (this.protocol == null) {\n      return;\n    }\n    return this._sendCommand(command);\n  };\n\n  Connector.prototype._sendCommand = function(command) {\n    return this.socket.send(JSON.stringify(command));\n  };\n\n  Connector.prototype._closeOnError = function() {\n    this._handshakeTimeout.stop();\n    this._disconnectionReason = 'error';\n    return this.socket.close();\n  };\n\n  Connector.prototype._onopen = function(e) {\n    var hello;\n    this.handlers.socketConnected();\n    this._disconnectionReason = 'handshake-failed';\n    hello = {\n      command: 'hello',\n      protocols: [PROTOCOL_6, PROTOCOL_7]\n    };\n    hello.ver = Version;\n    if (this.options.ext) {\n      hello.ext = this.options.ext;\n    }\n    if (this.options.extver) {\n      hello.extver = this.options.extver;\n    }\n    if (this.options.snipver) {\n      hello.snipver = this.options.snipver;\n    }\n    this._sendCommand(hello);\n    return this._handshakeTimeout.start(this.options.handshake_timeout);\n  };\n\n  Connector.prototype._onclose = function(e) {\n    this.protocol = 0;\n    this.handlers.disconnected(this._disconnectionReason, this._nextDelay);\n    return this._scheduleReconnection();\n  };\n\n  Connector.prototype._onerror = function(e) {};\n\n  Connector.prototype._onmessage = function(e) {\n    return this.protocolParser.process(e.data);\n  };\n\n  return Connector;\n\n})();\n\n// timer\nvar Timer;\nvar __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };\n__timer.Timer = Timer = (function() {\n  function Timer(func) {\n    this.func = func;\n    this.running = false;\n    this.id = null;\n    this._handler = __bind(function() {\n      this.running = false;\n      this.id = null;\n      return this.func();\n    }, this);\n  }\n  Timer.prototype.start = function(timeout) {\n    if (this.running) {\n      clearTimeout(this.id);\n    }\n    this.id = setTimeout(this._handler, timeout);\n    return this.running = true;\n  };\n  Timer.prototype.stop = function() {\n    if (this.running) {\n      clearTimeout(this.id);\n      this.running = false;\n      return this.id = null;\n    }\n  };\n  return Timer;\n})();\nTimer.start = function(timeout, func) {\n  return setTimeout(func, timeout);\n};\n\n// options\nvar Options;\n__options.Options = Options = (function() {\n  function Options() {\n    this.host = null;\n    this.port = 35729;\n    this.snipver = null;\n    this.ext = null;\n    this.extver = null;\n    this.mindelay = 1000;\n    this.maxdelay = 60000;\n    this.handshake_timeout = 5000;\n  }\n  Options.prototype.set = function(name, value) {\n    switch (typeof this[name]) {\n      case 'undefined':\n        break;\n      case 'number':\n        return this[name] = +value;\n      default:\n        return this[name] = value;\n    }\n  };\n  return Options;\n})();\nOptions.extract = function(document) {\n  var element, keyAndValue, m, mm, options, pair, src, _i, _j, _len, _len2, _ref, _ref2;\n  _ref = document.getElementsByTagName('script');\n  for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n    element = _ref[_i];\n    if ((src = element.src) && (m = src.match(/^[^:]+:\\/\\/(.*)\\/z?livereload\\.js(?:\\?(.*))?$/))) {\n      options = new Options();\n      if (mm = m[1].match(/^([^\\/:]+)(?::(\\d+))?$/)) {\n        options.host = mm[1];\n        if (mm[2]) {\n          options.port = parseInt(mm[2], 10);\n        }\n      }\n      if (m[2]) {\n        _ref2 = m[2].split('&');\n        for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {\n          pair = _ref2[_j];\n          if ((keyAndValue = pair.split('=')).length > 1) {\n            options.set(keyAndValue[0].replace(/-/g, '_'), keyAndValue.slice(1).join('='));\n          }\n        }\n      }\n      return options;\n    }\n  }\n  return null;\n};\n\n// reloader\n// Generated by CoffeeScript 1.3.1\n(function() {\n  var IMAGE_STYLES, Reloader, numberOfMatchingSegments, pathFromUrl, pathsMatch, pickBestMatch, splitUrl;\n\n  splitUrl = function(url) {\n    var hash, index, params;\n    if ((index = url.indexOf('#')) >= 0) {\n      hash = url.slice(index);\n      url = url.slice(0, index);\n    } else {\n      hash = '';\n    }\n    if ((index = url.indexOf('?')) >= 0) {\n      params = url.slice(index);\n      url = url.slice(0, index);\n    } else {\n      params = '';\n    }\n    return {\n      url: url,\n      params: params,\n      hash: hash\n    };\n  };\n\n  pathFromUrl = function(url) {\n    var path;\n    url = splitUrl(url).url;\n    if (url.indexOf('file://') === 0) {\n      path = url.replace(/^file:\\/\\/(localhost)?/, '');\n    } else {\n      path = url.replace(/^([^:]+:)?\\/\\/([^:\\/]+)(:\\d*)?\\//, '/');\n    }\n    return decodeURIComponent(path);\n  };\n\n  pickBestMatch = function(path, objects, pathFunc) {\n    var bestMatch, object, score, _i, _len;\n    bestMatch = {\n      score: 0\n    };\n    for (_i = 0, _len = objects.length; _i < _len; _i++) {\n      object = objects[_i];\n      score = numberOfMatchingSegments(path, pathFunc(object));\n      if (score > bestMatch.score) {\n        bestMatch = {\n          object: object,\n          score: score\n        };\n      }\n    }\n    if (bestMatch.score > 0) {\n      return bestMatch;\n    } else {\n      return null;\n    }\n  };\n\n  numberOfMatchingSegments = function(path1, path2) {\n    var comps1, comps2, eqCount, len;\n    path1 = path1.replace(/^\\/+/, '').toLowerCase();\n    path2 = path2.replace(/^\\/+/, '').toLowerCase();\n    if (path1 === path2) {\n      return 10000;\n    }\n    comps1 = path1.split('/').reverse();\n    comps2 = path2.split('/').reverse();\n    len = Math.min(comps1.length, comps2.length);\n    eqCount = 0;\n    while (eqCount < len && comps1[eqCount] === comps2[eqCount]) {\n      ++eqCount;\n    }\n    return eqCount;\n  };\n\n  pathsMatch = function(path1, path2) {\n    return numberOfMatchingSegments(path1, path2) > 0;\n  };\n\n  IMAGE_STYLES = [\n    {\n      selector: 'background',\n      styleNames: ['backgroundImage']\n    }, {\n      selector: 'border',\n      styleNames: ['borderImage', 'webkitBorderImage', 'MozBorderImage']\n    }\n  ];\n\n  __reloader.Reloader = Reloader = (function() {\n\n    Reloader.name = 'Reloader';\n\n    function Reloader(window, console, Timer) {\n      this.window = window;\n      this.console = console;\n      this.Timer = Timer;\n      this.document = this.window.document;\n      this.importCacheWaitPeriod = 200;\n      this.plugins = [];\n    }\n\n    Reloader.prototype.addPlugin = function(plugin) {\n      return this.plugins.push(plugin);\n    };\n\n    Reloader.prototype.analyze = function(callback) {\n      return results;\n    };\n\n    Reloader.prototype.reload = function(path, options) {\n      var plugin, _base, _i, _len, _ref;\n      this.options = options;\n      if ((_base = this.options).stylesheetReloadTimeout == null) {\n        _base.stylesheetReloadTimeout = 15000;\n      }\n      _ref = this.plugins;\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        plugin = _ref[_i];\n        if (plugin.reload && plugin.reload(path, options)) {\n          return;\n        }\n      }\n      if (options.liveCSS) {\n        if (path.match(/\\.css$/i)) {\n          if (this.reloadStylesheet(path)) {\n            return;\n          }\n        }\n      }\n      if (options.liveImg) {\n        if (path.match(/\\.(jpe?g|png|gif)$/i)) {\n          this.reloadImages(path);\n          return;\n        }\n      }\n      return this.reloadPage();\n    };\n\n    Reloader.prototype.reloadPage = function() {\n      return this.window.document.location.reload();\n    };\n\n    Reloader.prototype.reloadImages = function(path) {\n      var expando, img, selector, styleNames, styleSheet, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3, _results;\n      expando = this.generateUniqueString();\n      _ref = this.document.images;\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        img = _ref[_i];\n        if (pathsMatch(path, pathFromUrl(img.src))) {\n          img.src = this.generateCacheBustUrl(img.src, expando);\n        }\n      }\n      if (this.document.querySelectorAll) {\n        for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {\n          _ref1 = IMAGE_STYLES[_j], selector = _ref1.selector, styleNames = _ref1.styleNames;\n          _ref2 = this.document.querySelectorAll(\"[style*=\" + selector + \"]\");\n          for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {\n            img = _ref2[_k];\n            this.reloadStyleImages(img.style, styleNames, path, expando);\n          }\n        }\n      }\n      if (this.document.styleSheets) {\n        _ref3 = this.document.styleSheets;\n        _results = [];\n        for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {\n          styleSheet = _ref3[_l];\n          _results.push(this.reloadStylesheetImages(styleSheet, path, expando));\n        }\n        return _results;\n      }\n    };\n\n    Reloader.prototype.reloadStylesheetImages = function(styleSheet, path, expando) {\n      var rule, rules, styleNames, _i, _j, _len, _len1;\n      try {\n        rules = styleSheet != null ? styleSheet.cssRules : void 0;\n      } catch (e) {\n\n      }\n      if (!rules) {\n        return;\n      }\n      for (_i = 0, _len = rules.length; _i < _len; _i++) {\n        rule = rules[_i];\n        switch (rule.type) {\n          case CSSRule.IMPORT_RULE:\n            this.reloadStylesheetImages(rule.styleSheet, path, expando);\n            break;\n          case CSSRule.STYLE_RULE:\n            for (_j = 0, _len1 = IMAGE_STYLES.length; _j < _len1; _j++) {\n              styleNames = IMAGE_STYLES[_j].styleNames;\n              this.reloadStyleImages(rule.style, styleNames, path, expando);\n            }\n            break;\n          case CSSRule.MEDIA_RULE:\n            this.reloadStylesheetImages(rule, path, expando);\n        }\n      }\n    };\n\n    Reloader.prototype.reloadStyleImages = function(style, styleNames, path, expando) {\n      var newValue, styleName, value, _i, _len,\n        _this = this;\n      for (_i = 0, _len = styleNames.length; _i < _len; _i++) {\n        styleName = styleNames[_i];\n        value = style[styleName];\n        if (typeof value === 'string') {\n          newValue = value.replace(/\\burl\\s*\\(([^)]*)\\)/, function(match, src) {\n            if (pathsMatch(path, pathFromUrl(src))) {\n              return \"url(\" + (_this.generateCacheBustUrl(src, expando)) + \")\";\n            } else {\n              return match;\n            }\n          });\n          if (newValue !== value) {\n            style[styleName] = newValue;\n          }\n        }\n      }\n    };\n\n    Reloader.prototype.reloadStylesheet = function(path) {\n      var imported, link, links, match, style, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1,\n        _this = this;\n      links = (function() {\n        var _i, _len, _ref, _results;\n        _ref = this.document.getElementsByTagName('link');\n        _results = [];\n        for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n          link = _ref[_i];\n          if (link.rel === 'stylesheet' && !link.__LiveReload_pendingRemoval) {\n            _results.push(link);\n          }\n        }\n        return _results;\n      }).call(this);\n      imported = [];\n      _ref = this.document.getElementsByTagName('style');\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        style = _ref[_i];\n        if (style.sheet) {\n          this.collectImportedStylesheets(style, style.sheet, imported);\n        }\n      }\n      for (_j = 0, _len1 = links.length; _j < _len1; _j++) {\n        link = links[_j];\n        this.collectImportedStylesheets(link, link.sheet, imported);\n      }\n      if (this.window.StyleFix && this.document.querySelectorAll) {\n        _ref1 = this.document.querySelectorAll('style[data-href]');\n        for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) {\n          style = _ref1[_k];\n          links.push(style);\n        }\n      }\n      this.console.log(\"LiveReload found \" + links.length + \" LINKed stylesheets, \" + imported.length + \" @imported stylesheets\");\n      match = pickBestMatch(path, links.concat(imported), function(l) {\n        return pathFromUrl(_this.linkHref(l));\n      });\n      if (match) {\n        if (match.object.rule) {\n          this.console.log(\"LiveReload is reloading imported stylesheet: \" + match.object.href);\n          this.reattachImportedRule(match.object);\n        } else {\n          this.console.log(\"LiveReload is reloading stylesheet: \" + (this.linkHref(match.object)));\n          this.reattachStylesheetLink(match.object);\n        }\n      } else {\n        this.console.log(\"LiveReload will reload all stylesheets because path '\" + path + \"' did not match any specific one\");\n        for (_l = 0, _len3 = links.length; _l < _len3; _l++) {\n          link = links[_l];\n          this.reattachStylesheetLink(link);\n        }\n      }\n      return true;\n    };\n\n    Reloader.prototype.collectImportedStylesheets = function(link, styleSheet, result) {\n      var index, rule, rules, _i, _len;\n      try {\n        rules = styleSheet != null ? styleSheet.cssRules : void 0;\n      } catch (e) {\n\n      }\n      if (rules && rules.length) {\n        for (index = _i = 0, _len = rules.length; _i < _len; index = ++_i) {\n          rule = rules[index];\n          switch (rule.type) {\n            case CSSRule.CHARSET_RULE:\n              continue;\n            case CSSRule.IMPORT_RULE:\n              result.push({\n                link: link,\n                rule: rule,\n                index: index,\n                href: rule.href\n              });\n              this.collectImportedStylesheets(link, rule.styleSheet, result);\n              break;\n            default:\n              break;\n          }\n        }\n      }\n    };\n\n    Reloader.prototype.waitUntilCssLoads = function(clone, func) {\n      var callbackExecuted, executeCallback, poll,\n        _this = this;\n      callbackExecuted = false;\n      executeCallback = function() {\n        if (callbackExecuted) {\n          return;\n        }\n        callbackExecuted = true;\n        return func();\n      };\n      clone.onload = function() {\n        console.log(\"onload!\");\n        _this.knownToSupportCssOnLoad = true;\n        return executeCallback();\n      };\n      if (!this.knownToSupportCssOnLoad) {\n        (poll = function() {\n          if (clone.sheet) {\n            console.log(\"polling!\");\n            return executeCallback();\n          } else {\n            return _this.Timer.start(50, poll);\n          }\n        })();\n      }\n      return this.Timer.start(this.options.stylesheetReloadTimeout, executeCallback);\n    };\n\n    Reloader.prototype.linkHref = function(link) {\n      return link.href || link.getAttribute('data-href');\n    };\n\n    Reloader.prototype.reattachStylesheetLink = function(link) {\n      var clone, parent,\n        _this = this;\n      if (link.__LiveReload_pendingRemoval) {\n        return;\n      }\n      link.__LiveReload_pendingRemoval = true;\n      if (link.tagName === 'STYLE') {\n        clone = this.document.createElement('link');\n        clone.rel = 'stylesheet';\n        clone.media = link.media;\n        clone.disabled = link.disabled;\n      } else {\n        clone = link.cloneNode(false);\n      }\n      clone.href = this.generateCacheBustUrl(this.linkHref(link));\n      parent = link.parentNode;\n      if (parent.lastChild === link) {\n        parent.appendChild(clone);\n      } else {\n        parent.insertBefore(clone, link.nextSibling);\n      }\n      return this.waitUntilCssLoads(clone, function() {\n        var additionalWaitingTime;\n        if (/AppleWebKit/.test(navigator.userAgent)) {\n          additionalWaitingTime = 5;\n        } else {\n          additionalWaitingTime = 200;\n        }\n        return _this.Timer.start(additionalWaitingTime, function() {\n          var _ref;\n          if (!link.parentNode) {\n            return;\n          }\n          link.parentNode.removeChild(link);\n          clone.onreadystatechange = null;\n          return (_ref = _this.window.StyleFix) != null ? _ref.link(clone) : void 0;\n        });\n      });\n    };\n\n    Reloader.prototype.reattachImportedRule = function(_arg) {\n      var href, index, link, media, newRule, parent, rule, tempLink,\n        _this = this;\n      rule = _arg.rule, index = _arg.index, link = _arg.link;\n      parent = rule.parentStyleSheet;\n      href = this.generateCacheBustUrl(rule.href);\n      media = rule.media.length ? [].join.call(rule.media, ', ') : '';\n      newRule = \"@import url(\\\"\" + href + \"\\\") \" + media + \";\";\n      rule.__LiveReload_newHref = href;\n      tempLink = this.document.createElement(\"link\");\n      tempLink.rel = 'stylesheet';\n      tempLink.href = href;\n      tempLink.__LiveReload_pendingRemoval = true;\n      if (link.parentNode) {\n        link.parentNode.insertBefore(tempLink, link);\n      }\n      return this.Timer.start(this.importCacheWaitPeriod, function() {\n        if (tempLink.parentNode) {\n          tempLink.parentNode.removeChild(tempLink);\n        }\n        if (rule.__LiveReload_newHref !== href) {\n          return;\n        }\n        parent.insertRule(newRule, index);\n        parent.deleteRule(index + 1);\n        rule = parent.cssRules[index];\n        rule.__LiveReload_newHref = href;\n        return _this.Timer.start(_this.importCacheWaitPeriod, function() {\n          if (rule.__LiveReload_newHref !== href) {\n            return;\n          }\n          parent.insertRule(newRule, index);\n          return parent.deleteRule(index + 1);\n        });\n      });\n    };\n\n    Reloader.prototype.generateUniqueString = function() {\n      return 'livereload=' + Date.now();\n    };\n\n    Reloader.prototype.generateCacheBustUrl = function(url, expando) {\n      var hash, oldParams, params, _ref;\n      if (expando == null) {\n        expando = this.generateUniqueString();\n      }\n      _ref = splitUrl(url), url = _ref.url, hash = _ref.hash, oldParams = _ref.params;\n      if (this.options.overrideURL) {\n        if (url.indexOf(this.options.serverURL) < 0) {\n          url = this.options.serverURL + this.options.overrideURL + \"?url=\" + encodeURIComponent(url);\n        }\n      }\n      params = oldParams.replace(/(\\?|&)livereload=(\\d+)/, function(match, sep) {\n        return \"\" + sep + expando;\n      });\n      if (params === oldParams) {\n        if (oldParams.length === 0) {\n          params = \"?\" + expando;\n        } else {\n          params = \"\" + oldParams + \"&\" + expando;\n        }\n      }\n      return url + params + hash;\n    };\n\n    return Reloader;\n\n  })();\n\n}).call(this);\n\n// livereload\nvar Connector, LiveReload, Options, Reloader, Timer;\n\nConnector = __connector.Connector;\n\nTimer = __timer.Timer;\n\nOptions = __options.Options;\n\nReloader = __reloader.Reloader;\n\n__livereload.LiveReload = LiveReload = (function() {\n\n  function LiveReload(window) {\n    var _this = this;\n    this.window = window;\n    this.listeners = {};\n    this.plugins = [];\n    this.pluginIdentifiers = {};\n    this.console = this.window.location.href.match(/LR-verbose/) && this.window.console && this.window.console.log && this.window.console.error ? this.window.console : {\n      log: function() {},\n      error: function() {}\n    };\n    if (!(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket)) {\n      console.error(\"LiveReload disabled because the browser does not seem to support web sockets\");\n      return;\n    }\n    if (!(this.options = Options.extract(this.window.document))) {\n      console.error(\"LiveReload disabled because it could not find its own <SCRIPT> tag\");\n      return;\n    }\n    this.reloader = new Reloader(this.window, this.console, Timer);\n    this.connector = new Connector(this.options, this.WebSocket, Timer, {\n      connecting: function() {},\n      socketConnected: function() {},\n      connected: function(protocol) {\n        var _base;\n        if (typeof (_base = _this.listeners).connect === \"function\") {\n          _base.connect();\n        }\n        _this.log(\"LiveReload is connected to \" + _this.options.host + \":\" + _this.options.port + \" (protocol v\" + protocol + \").\");\n        return _this.analyze();\n      },\n      error: function(e) {\n        if (e instanceof ProtocolError) {\n          return console.log(\"\" + e.message + \".\");\n        } else {\n          return console.log(\"LiveReload internal error: \" + e.message);\n        }\n      },\n      disconnected: function(reason, nextDelay) {\n        var _base;\n        if (typeof (_base = _this.listeners).disconnect === \"function\") {\n          _base.disconnect();\n        }\n        switch (reason) {\n          case 'cannot-connect':\n            return _this.log(\"LiveReload cannot connect to \" + _this.options.host + \":\" + _this.options.port + \", will retry in \" + nextDelay + \" sec.\");\n          case 'broken':\n            return _this.log(\"LiveReload disconnected from \" + _this.options.host + \":\" + _this.options.port + \", reconnecting in \" + nextDelay + \" sec.\");\n          case 'handshake-timeout':\n            return _this.log(\"LiveReload cannot connect to \" + _this.options.host + \":\" + _this.options.port + \" (handshake timeout), will retry in \" + nextDelay + \" sec.\");\n          case 'handshake-failed':\n            return _this.log(\"LiveReload cannot connect to \" + _this.options.host + \":\" + _this.options.port + \" (handshake failed), will retry in \" + nextDelay + \" sec.\");\n          case 'manual':\n            break;\n          case 'error':\n            break;\n          default:\n            return _this.log(\"LiveReload disconnected from \" + _this.options.host + \":\" + _this.options.port + \" (\" + reason + \"), reconnecting in \" + nextDelay + \" sec.\");\n        }\n      },\n      message: function(message) {\n        switch (message.command) {\n          case 'reload':\n            return _this.performReload(message);\n          case 'alert':\n            return _this.performAlert(message);\n        }\n      }\n    });\n  }\n\n  LiveReload.prototype.on = function(eventName, handler) {\n    return this.listeners[eventName] = handler;\n  };\n\n  LiveReload.prototype.log = function(message) {\n    return this.console.log(\"\" + message);\n  };\n\n  LiveReload.prototype.performReload = function(message) {\n    var _ref, _ref2;\n    this.log(\"LiveReload received reload request for \" + message.path + \".\");\n    return this.reloader.reload(message.path, {\n      liveCSS: (_ref = message.liveCSS) != null ? _ref : true,\n      liveImg: (_ref2 = message.liveImg) != null ? _ref2 : true,\n      originalPath: message.originalPath || '',\n      overrideURL: message.overrideURL || '',\n      serverURL: \"http://\" + this.options.host + \":\" + this.options.port\n    });\n  };\n\n  LiveReload.prototype.performAlert = function(message) {\n    return alert(message.message);\n  };\n\n  LiveReload.prototype.shutDown = function() {\n    var _base;\n    this.connector.disconnect();\n    this.log(\"LiveReload disconnected.\");\n    return typeof (_base = this.listeners).shutdown === \"function\" ? _base.shutdown() : void 0;\n  };\n\n  LiveReload.prototype.hasPlugin = function(identifier) {\n    return !!this.pluginIdentifiers[identifier];\n  };\n\n  LiveReload.prototype.addPlugin = function(pluginClass) {\n    var plugin;\n    var _this = this;\n    if (this.hasPlugin(pluginClass.identifier)) return;\n    this.pluginIdentifiers[pluginClass.identifier] = true;\n    plugin = new pluginClass(this.window, {\n      _livereload: this,\n      _reloader: this.reloader,\n      _connector: this.connector,\n      console: this.console,\n      Timer: Timer,\n      generateCacheBustUrl: function(url) {\n        return _this.reloader.generateCacheBustUrl(url);\n      }\n    });\n    this.plugins.push(plugin);\n    this.reloader.addPlugin(plugin);\n  };\n\n  LiveReload.prototype.analyze = function() {\n    var plugin, pluginData, pluginsData, _i, _len, _ref;\n    if (!(this.connector.protocol >= 7)) return;\n    pluginsData = {};\n    _ref = this.plugins;\n    for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n      plugin = _ref[_i];\n      pluginsData[plugin.constructor.identifier] = pluginData = (typeof plugin.analyze === \"function\" ? plugin.analyze() : void 0) || {};\n      pluginData.version = plugin.constructor.version;\n    }\n    this.connector.sendCommand({\n      command: 'info',\n      plugins: pluginsData,\n      url: this.window.location.href\n    });\n  };\n\n  return LiveReload;\n\n})();\n\n// less\nvar LessPlugin;\n__less = LessPlugin = (function() {\n  LessPlugin.identifier = 'less';\n  LessPlugin.version = '1.0';\n  function LessPlugin(window, host) {\n    this.window = window;\n    this.host = host;\n  }\n  LessPlugin.prototype.reload = function(path, options) {\n    if (this.window.less && this.window.less.refresh) {\n      if (path.match(/\\.less$/i)) {\n        return this.reloadLess(path);\n      }\n      if (options.originalPath.match(/\\.less$/i)) {\n        return this.reloadLess(options.originalPath);\n      }\n    }\n    return false;\n  };\n  LessPlugin.prototype.reloadLess = function(path) {\n    var link, links, _i, _len;\n    links = (function() {\n      var _i, _len, _ref, _results;\n      _ref = document.getElementsByTagName('link');\n      _results = [];\n      for (_i = 0, _len = _ref.length; _i < _len; _i++) {\n        link = _ref[_i];\n        if (link.href && link.rel === 'stylesheet/less' || (link.rel.match(/stylesheet/) && link.type.match(/^text\\/(x-)?less$/))) {\n          _results.push(link);\n        }\n      }\n      return _results;\n    })();\n    if (links.length === 0) {\n      return false;\n    }\n    for (_i = 0, _len = links.length; _i < _len; _i++) {\n      link = links[_i];\n      link.href = this.host.generateCacheBustUrl(link.href);\n    }\n    this.host.console.log(\"LiveReload is asking LESS to recompile all stylesheets\");\n    this.window.less.refresh(true);\n    return true;\n  };\n  LessPlugin.prototype.analyze = function() {\n    return {\n      disable: !!(this.window.less && this.window.less.refresh)\n    };\n  };\n  return LessPlugin;\n})();\n\n// startup\nvar CustomEvents, LiveReload, k;\nCustomEvents = __customevents;\nLiveReload = window.LiveReload = new (__livereload.LiveReload)(window);\nfor (k in window) {\n  if (k.match(/^LiveReloadPlugin/)) {\n    LiveReload.addPlugin(window[k]);\n  }\n}\nLiveReload.addPlugin(__less);\nLiveReload.on('shutdown', function() {\n  return delete window.LiveReload;\n});\nLiveReload.on('connect', function() {\n  return CustomEvents.fire(document, 'LiveReloadConnect');\n});\nLiveReload.on('disconnect', function() {\n  return CustomEvents.fire(document, 'LiveReloadDisconnect');\n});\nCustomEvents.bind(document, 'LiveReloadShutDown', function() {\n  return LiveReload.shutDown();\n});\n})();\n"
  },
  {
    "path": "module/spring-boot-devtools/src/main/resources/org/springframework/boot/devtools/remote-banner.txt",
    "content": "  .   ____          _                                              __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` |        | _ \\___ _ __  ___| |_ ___ \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \\/ _ \\  _/ -_) ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, |        |_|_\\___|_|_|_\\___/\\__\\___|/ / / /\n =========|_|==============|___/===================================/_/_/_/\n :: Spring Boot Remote :: ${spring-boot.formatted-version}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/RemoteUrlPropertyExtractorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools;\n\nimport ch.qos.logback.classic.Logger;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link RemoteUrlPropertyExtractor}.\n *\n * @author Phillip Webb\n */\nclass RemoteUrlPropertyExtractorTests {\n\n\t@AfterEach\n\tvoid preventRunFailuresFromPollutingLoggerContext() {\n\t\t((Logger) LoggerFactory.getLogger(RemoteUrlPropertyExtractorTests.class)).getLoggerContext()\n\t\t\t.getTurboFilterList()\n\t\t\t.clear();\n\t}\n\n\t@Test\n\tvoid missingUrl() {\n\t\tassertThatIllegalStateException().isThrownBy(this::doTest).withMessageContaining(\"No remote URL specified\");\n\t}\n\n\t@Test\n\tvoid malformedUrl() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> doTest(\"::://wibble\"))\n\t\t\t.withMessageContaining(\"Malformed URL '::://wibble'\");\n\n\t}\n\n\t@Test\n\tvoid multipleUrls() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> doTest(\"http://localhost:8080\", \"http://localhost:9090\"))\n\t\t\t.withMessageContaining(\"Multiple URLs specified\");\n\t}\n\n\t@Test\n\tvoid validUrl() {\n\t\tApplicationContext context = doTest(\"http://localhost:8080\");\n\t\tassertThat(context.getEnvironment().getProperty(\"remoteUrl\")).isEqualTo(\"http://localhost:8080\");\n\t}\n\n\t@Test\n\tvoid cleanValidUrl() {\n\t\tApplicationContext context = doTest(\"http://localhost:8080/\");\n\t\tassertThat(context.getEnvironment().getProperty(\"remoteUrl\")).isEqualTo(\"http://localhost:8080\");\n\t}\n\n\tprivate ApplicationContext doTest(String... args) {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.addListeners(new RemoteUrlPropertyExtractor());\n\t\treturn application.run(args);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Collection;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Base class for tests for {@link DevToolsDataSourceAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nabstract class AbstractDevToolsDataSourceAutoConfigurationTests {\n\n\t@Test\n\tvoid singleManuallyConfiguredDataSourceIsNotClosed() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t() -> createContext(SingleDataSourceConfiguration.class))) {\n\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\tStatement statement = configureDataSourceBehavior(dataSource);\n\t\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid multipleDataSourcesAreIgnored() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t() -> createContext(MultipleDataSourcesConfiguration.class))) {\n\t\t\tCollection<DataSource> dataSources = context.getBeansOfType(DataSource.class).values();\n\t\t\tfor (DataSource dataSource : dataSources) {\n\t\t\t\tStatement statement = configureDataSourceBehavior(dataSource);\n\t\t\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid emptyFactoryMethodMetadataIgnored() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tDataSource dataSource = mock(DataSource.class);\n\t\t\tAnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(dataSource.getClass());\n\t\t\tcontext.registerBeanDefinition(\"dataSource\", beanDefinition);\n\t\t\tcontext.register(DevToolsDataSourceAutoConfiguration.class);\n\t\t\tcontext.refresh();\n\t\t}\n\t}\n\n\tprotected final Statement configureDataSourceBehavior(DataSource dataSource) throws SQLException {\n\t\tConnection connection = mock(Connection.class);\n\t\tStatement statement = mock(Statement.class);\n\t\twillReturn(connection).given(dataSource).getConnection();\n\t\tgiven(connection.createStatement()).willReturn(statement);\n\t\treturn statement;\n\t}\n\n\tprotected ConfigurableApplicationContext getContext(Supplier<ConfigurableApplicationContext> supplier)\n\t\t\tthrows Exception {\n\t\tAtomicReference<ConfigurableApplicationContext> atomicReference = new AtomicReference<>();\n\t\tThread thread = new Thread(() -> {\n\t\t\tConfigurableApplicationContext context = supplier.get();\n\t\t\tatomicReference.getAndSet(context);\n\t\t});\n\t\tthread.start();\n\t\tthread.join();\n\t\tConfigurableApplicationContext context = atomicReference.get();\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\tprotected final ConfigurableApplicationContext createContext(Class<?>... classes) {\n\t\treturn createContext(null, classes);\n\t}\n\n\tprotected final ConfigurableApplicationContext createContext(@Nullable String driverClassName,\n\t\t\tClass<?>... classes) {\n\t\treturn createContext(driverClassName, null, classes);\n\t}\n\n\tprotected final ConfigurableApplicationContext createContext(@Nullable String driverClassName, @Nullable String url,\n\t\t\tClass<?>... classes) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(classes);\n\t\tcontext.register(DevToolsDataSourceAutoConfiguration.class);\n\t\tif (driverClassName != null) {\n\t\t\tTestPropertyValues.of(\"spring.datasource.driver-class-name:\" + driverClassName).applyTo(context);\n\t\t}\n\t\tif (url != null) {\n\t\t\tTestPropertyValues.of(\"spring.datasource.url:\" + url).applyTo(context);\n\t\t}\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SingleDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleDataSourcesConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSourceOne() {\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t\t@Bean\n\t\tDataSource dataSourceTwo() {\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceSpyConfiguration {\n\n\t\t@Bean\n\t\tstatic DataSourceSpyBeanPostProcessor dataSourceSpyBeanPostProcessor() {\n\t\t\treturn new DataSourceSpyBeanPostProcessor();\n\t\t}\n\n\t}\n\n\tstatic class DataSourceSpyBeanPostProcessor implements BeanPostProcessor, Ordered {\n\n\t\t@Override\n\t\tpublic @Nullable Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tif (bean instanceof DataSource) {\n\t\t\t\tbean = spy(bean);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsEmbeddedDataSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link DevToolsDataSourceAutoConfiguration} with an embedded data source.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"HikariCP-*.jar\")\nclass DevToolsEmbeddedDataSourceAutoConfigurationTests extends AbstractDevToolsDataSourceAutoConfigurationTests {\n\n\t@Test\n\tvoid autoConfiguredDataSourceIsNotShutdown() throws SQLException {\n\t\tConfigurableApplicationContext context = createContext(DataSourceAutoConfiguration.class,\n\t\t\t\tDataSourceSpyConfiguration.class);\n\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\tcontext.close();\n\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.io.File;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.time.Duration;\nimport java.util.Objects;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport com.zaxxer.hikari.HikariPoolMXBean;\nimport org.apache.derby.jdbc.EmbeddedDriver;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.jdbc.DataSourceUnwrapper;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link DevToolsDataSourceAutoConfiguration} with a pooled data source.\n *\n * @author Andy Wilkinson\n */\nclass DevToolsPooledDataSourceAutoConfigurationTests extends AbstractDevToolsDataSourceAutoConfigurationTests {\n\n\t@BeforeEach\n\tvoid before(@TempDir File tempDir) {\n\t\tSystem.setProperty(\"derby.stream.error.file\", new File(tempDir, \"derby.log\").getAbsolutePath());\n\t}\n\n\t@AfterEach\n\tvoid after() {\n\t\tSystem.clearProperty(\"derby.stream.error.file\");\n\t}\n\n\t@Test\n\tvoid autoConfiguredInMemoryDataSourceIsShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t() -> createContext(DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should().execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid autoConfiguredExternalDataSourceIsNotShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(() -> createContext(\"org.postgresql.Driver\",\n\t\t\t\tDataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid h2ServerIsNotShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(() -> createContext(\"org.h2.Driver\",\n\t\t\t\t\"jdbc:h2:hsql://localhost\", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid inMemoryH2IsShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(() -> createContext(\"org.h2.Driver\",\n\t\t\t\t\"jdbc:h2:mem:test\", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should().execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid hsqlServerIsNotShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(() -> createContext(\"org.hsqldb.jdbcDriver\",\n\t\t\t\t\"jdbc:hsqldb:hsql://localhost\", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid inMemoryHsqlIsShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(() -> createContext(\"org.hsqldb.jdbcDriver\",\n\t\t\t\t\"jdbc:hsqldb:mem:test\", DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should().execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid derbyClientIsNotShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t() -> createContext(\"org.apache.derby.jdbc.ClientDriver\", \"jdbc:derby://localhost\",\n\t\t\t\t\t\tDataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tStatement statement = configureDataSourceBehavior(context.getBean(DataSource.class));\n\t\t\tcontext.close();\n\t\t\tthen(statement).should(never()).execute(\"SHUTDOWN\");\n\t\t}\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid inMemoryDerbyIsShutdown() throws Exception {\n\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t() -> createContext(\"org.apache.derby.jdbc.EmbeddedDriver\", \"jdbc:derby:memory:test;create=true\",\n\t\t\t\t\t\tDataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class))) {\n\t\t\tHikariDataSource dataSource = Objects\n\t\t\t\t.requireNonNull(DataSourceUnwrapper.unwrap(context.getBean(DataSource.class), HikariDataSource.class));\n\t\t\tJdbcTemplate jdbc = new JdbcTemplate(dataSource);\n\t\t\tjdbc.execute(\"SELECT 1 FROM SYSIBM.SYSDUMMY1\");\n\t\t\tHikariPoolMXBean pool = dataSource.getHikariPoolMXBean();\n\t\t\t// Prevent a race between Hikari's initialization and Derby shutdown\n\t\t\tAwaitility.await()\n\t\t\t\t.atMost(Duration.ofSeconds(30))\n\t\t\t\t.until(pool::getIdleConnections, (idle) -> idle == dataSource.getMinimumIdle());\n\t\t\tcontext.close();\n\t\t\t// Connect should fail as DB no longer exists\n\t\t\tassertThatExceptionOfType(SQLException.class).isThrownBy(() -> connect(\"jdbc:derby:memory:test\"))\n\t\t\t\t.satisfies((ex) -> assertThat(ex.getSQLState()).isEqualTo(\"XJ004\"));\n\t\t\t// Shut Derby down fully so that it closes its log file\n\t\t\tassertThatExceptionOfType(SQLException.class).isThrownBy(() -> connect(\"jdbc:derby:;shutdown=true\"));\n\t\t}\n\t}\n\n\tprivate void connect(String jdbcUrl) throws SQLException {\n\t\tnew EmbeddedDriver().connect(jdbcUrl, new Properties()).close();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DevToolsProperties}.\n *\n * @author Stephane Nicoll\n */\nclass DevToolsPropertiesTests {\n\n\tprivate final DevToolsProperties devToolsProperties = new DevToolsProperties();\n\n\t@Test\n\tvoid additionalExcludeKeepsDefaults() {\n\t\tDevToolsProperties.Restart restart = this.devToolsProperties.getRestart();\n\t\trestart.setAdditionalExclude(\"foo/**,bar/**\");\n\t\tassertThat(restart.getAllExclude()).containsOnly(\"META-INF/maven/**\", \"META-INF/resources/**\", \"resources/**\",\n\t\t\t\t\"static/**\", \"public/**\", \"templates/**\", \"**/*Test.class\", \"**/*Tests.class\", \"git.properties\",\n\t\t\t\t\"META-INF/build-info.properties\", \"foo/**\", \"bar/**\");\n\t}\n\n\t@Test\n\tvoid additionalExcludeNoDefault() {\n\t\tDevToolsProperties.Restart restart = this.devToolsProperties.getRestart();\n\t\trestart.setExclude(\"\");\n\t\trestart.setAdditionalExclude(\"foo/**,bar/**\");\n\t\tassertThat(restart.getAllExclude()).containsOnly(\"foo/**\", \"bar/**\");\n\t}\n\n\t@Test\n\tvoid additionalExcludeCustomDefault() {\n\t\tDevToolsProperties.Restart restart = this.devToolsProperties.getRestart();\n\t\trestart.setExclude(\"biz/**\");\n\t\trestart.setAdditionalExclude(\"foo/**,bar/**\");\n\t\tassertThat(restart.getAllExclude()).containsOnly(\"biz/**\", \"foo/**\", \"bar/**\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsR2dbcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;\nimport org.springframework.boot.devtools.autoconfigure.DevToolsR2dbcAutoConfiguration.R2dbcDatabaseShutdownEvent;\nimport org.springframework.boot.r2dbc.SimpleConnectionFactoryProvider.SimpleTestConnectionFactory;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ObjectUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DevToolsR2dbcAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass DevToolsR2dbcAutoConfigurationTests {\n\n\tstatic List<ConnectionFactory> shutdowns = Collections.synchronizedList(new ArrayList<>());\n\n\tabstract static class Common {\n\n\t\t@BeforeEach\n\t\tvoid reset() {\n\t\t\tshutdowns.clear();\n\t\t}\n\n\t\t@Test\n\t\tvoid autoConfiguredInMemoryConnectionFactoryIsShutdown() throws Exception {\n\t\t\tConfigurableApplicationContext context = getContext(this::createContext);\n\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\tcontext.close();\n\t\t\tassertThat(shutdowns).contains(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid nonEmbeddedConnectionFactoryIsNotShutdown() throws Exception {\n\t\t\ttry (ConfigurableApplicationContext context = getContext(() -> createContext(\"r2dbc:h2:file:///testdb\"))) {\n\t\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(shutdowns).doesNotContain(connectionFactory);\n\t\t\t}\n\t\t}\n\n\t\t@Test\n\t\tvoid singleManuallyConfiguredConnectionFactoryIsNotClosed() throws Exception {\n\t\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t\t() -> createContext(SingleConnectionFactoryConfiguration.class))) {\n\t\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(shutdowns).doesNotContain(connectionFactory);\n\t\t\t}\n\t\t}\n\n\t\t@Test\n\t\tvoid multipleConnectionFactoriesAreIgnored() throws Exception {\n\t\t\ttry (ConfigurableApplicationContext context = getContext(\n\t\t\t\t\t() -> createContext(MultipleConnectionFactoriesConfiguration.class))) {\n\t\t\t\tCollection<ConnectionFactory> connectionFactory = context.getBeansOfType(ConnectionFactory.class)\n\t\t\t\t\t.values();\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(shutdowns).doesNotContainAnyElementsOf(connectionFactory);\n\t\t\t}\n\t\t}\n\n\t\t@Test\n\t\tvoid emptyFactoryMethodMetadataIgnored() throws Exception {\n\t\t\tConfigurableApplicationContext context = getContext(this::getEmptyFactoryMethodMetadataIgnoredContext);\n\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\tcontext.close();\n\t\t\tassertThat(shutdowns).doesNotContain(connectionFactory);\n\t\t}\n\n\t\tprivate ConfigurableApplicationContext getEmptyFactoryMethodMetadataIgnoredContext() {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tConnectionFactory connectionFactory = new SimpleTestConnectionFactory();\n\t\t\tAnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(\n\t\t\t\t\tconnectionFactory.getClass());\n\t\t\tcontext.registerBeanDefinition(\"connectionFactory\", beanDefinition);\n\t\t\tcontext.register(R2dbcAutoConfiguration.class, DevToolsR2dbcAutoConfiguration.class);\n\t\t\tcontext.refresh();\n\t\t\treturn context;\n\t\t}\n\n\t\tprotected ConfigurableApplicationContext getContext(Supplier<ConfigurableApplicationContext> supplier)\n\t\t\t\tthrows Exception {\n\t\t\tAtomicReference<ConfigurableApplicationContext> atomicReference = new AtomicReference<>();\n\t\t\tThread thread = new Thread(() -> {\n\t\t\t\tConfigurableApplicationContext context = supplier.get();\n\t\t\t\tatomicReference.getAndSet(context);\n\t\t\t});\n\t\t\tthread.start();\n\t\t\tthread.join();\n\t\t\tConfigurableApplicationContext context = atomicReference.get();\n\t\t\tassertThat(context).isNotNull();\n\t\t\treturn context;\n\t\t}\n\n\t\tprotected final ConfigurableApplicationContext createContext(Class<?>... classes) {\n\t\t\treturn createContext(null, classes);\n\t\t}\n\n\t\tprotected final ConfigurableApplicationContext createContext(@Nullable String url, Class<?>... classes) {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tif (!ObjectUtils.isEmpty(classes)) {\n\t\t\t\tcontext.register(classes);\n\t\t\t}\n\t\t\tcontext.register(R2dbcAutoConfiguration.class, DevToolsR2dbcAutoConfiguration.class);\n\t\t\tif (url != null) {\n\t\t\t\tTestPropertyValues.of(\"spring.r2dbc.url:\" + url).applyTo(context);\n\t\t\t}\n\t\t\tcontext.addApplicationListener(ApplicationListener.forPayload(this::onEvent));\n\t\t\tcontext.refresh();\n\t\t\treturn context;\n\t\t}\n\n\t\tprivate void onEvent(R2dbcDatabaseShutdownEvent event) {\n\t\t\tshutdowns.add(event.getConnectionFactory());\n\t\t}\n\n\t}\n\n\t@Nested\n\t@ClassPathExclusions(\"r2dbc-pool*.jar\")\n\tclass Embedded extends Common {\n\n\t}\n\n\t@Nested\n\tclass Pooled extends Common {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SingleConnectionFactoryConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactory() {\n\t\t\treturn new SimpleTestConnectionFactory();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleConnectionFactoriesConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactoryOne() {\n\t\t\treturn new SimpleTestConnectionFactory();\n\t\t}\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactoryTwo() {\n\t\t\treturn new SimpleTestConnectionFactory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/LocalDevToolsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\nimport org.apache.catalina.Container;\nimport org.apache.catalina.core.StandardWrapper;\nimport org.apache.jasper.EmbeddedServletOptions;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.devtools.classpath.ClassPathChangedEvent;\nimport org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;\nimport org.springframework.boot.devtools.livereload.LiveReloadServer;\nimport org.springframework.boot.devtools.restart.FailureHandler;\nimport org.springframework.boot.devtools.restart.MockRestartInitializer;\nimport org.springframework.boot.devtools.restart.MockRestarter;\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.boot.freemarker.autoconfigure.FreeMarkerAutoConfiguration;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.servlet.view.AbstractTemplateViewResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.reset;\n\n/**\n * Tests for {@link LocalDevToolsAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Vladimir Tsanev\n */\n@ExtendWith(MockRestarter.class)\n@SuppressWarnings(\"removal\")\nclass LocalDevToolsAutoConfigurationTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultPropertyCanBeOverriddenFromCommandLine() throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class, \"--spring.freemarker.cache=true\"));\n\t\tAbstractTemplateViewResolver resolver = this.context.getBean(AbstractTemplateViewResolver.class);\n\t\tassertThat(resolver.isCache()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultPropertyCanBeOverriddenFromUserHomeProperties() throws Exception {\n\t\tString userHome = System.getProperty(\"user.home\");\n\t\tSystem.setProperty(\"user.home\", new File(\"src/test/resources/user-home\").getAbsolutePath());\n\t\ttry {\n\t\t\tthis.context = getContext(() -> initializeAndRun(Config.class));\n\t\t\tAbstractTemplateViewResolver resolver = this.context.getBean(AbstractTemplateViewResolver.class);\n\t\t\tassertThat(resolver.isCache()).isTrue();\n\t\t}\n\t\tfinally {\n\t\t\tSystem.setProperty(\"user.home\", userHome);\n\t\t}\n\t}\n\n\t@Test\n\tvoid resourceCachePeriodIsZero() throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(WebResourcesConfig.class));\n\t\tResources properties = this.context.getBean(WebProperties.class).getResources();\n\t\tassertThat(properties.getCache().getPeriod()).isZero();\n\t}\n\n\t@Test\n\tvoid liveReloadTriggeredOnContextRefresh() throws Exception {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.livereload.enabled\", true);\n\t\tthis.context = getContext(() -> initializeAndRun(ConfigWithMockLiveReload.class, properties));\n\t\tLiveReloadServer server = this.context.getBean(LiveReloadServer.class);\n\t\treset(server);\n\t\tthis.context.publishEvent(new ContextRefreshedEvent(this.context));\n\t\tthen(server).should().triggerReload();\n\t}\n\n\t@Test\n\tvoid liveReloadTriggeredOnClassPathChangeWithoutRestart() throws Exception {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.livereload.enabled\", true);\n\t\tthis.context = getContext(() -> initializeAndRun(ConfigWithMockLiveReload.class, properties));\n\t\tLiveReloadServer server = this.context.getBean(LiveReloadServer.class);\n\t\treset(server);\n\t\tClassPathChangedEvent event = new ClassPathChangedEvent(this.context, Collections.emptySet(), false);\n\t\tthis.context.publishEvent(event);\n\t\tthen(server).should().triggerReload();\n\t}\n\n\t@Test\n\tvoid liveReloadNotTriggeredOnClassPathChangeWithRestart() throws Exception {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.livereload.enabled\", true);\n\t\tthis.context = getContext(() -> initializeAndRun(ConfigWithMockLiveReload.class, properties));\n\t\tLiveReloadServer server = this.context.getBean(LiveReloadServer.class);\n\t\treset(server);\n\t\tClassPathChangedEvent event = new ClassPathChangedEvent(this.context, Collections.emptySet(), true);\n\t\tthis.context.publishEvent(event);\n\t\tthen(server).should(never()).triggerReload();\n\t}\n\n\t@Test\n\tvoid liveReloadDisabledByDefault() throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class));\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(OptionalLiveReloadServer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid restartTriggeredOnClassPathChangeWithRestart(Restarter restarter) throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class));\n\t\tClassPathChangedEvent event = new ClassPathChangedEvent(this.context, Collections.emptySet(), true);\n\t\tthis.context.publishEvent(event);\n\t\tthen(restarter).should().restart(any(FailureHandler.class));\n\t}\n\n\t@Test\n\tvoid restartNotTriggeredOnClassPathChangeWithRestart(Restarter restarter) throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class));\n\t\tClassPathChangedEvent event = new ClassPathChangedEvent(this.context, Collections.emptySet(), false);\n\t\tthis.context.publishEvent(event);\n\t\tthen(restarter).should(never()).restart();\n\t}\n\n\t@Test\n\tvoid restartWatchingClassPath() throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class));\n\t\tClassPathFileSystemWatcher watcher = this.context.getBean(ClassPathFileSystemWatcher.class);\n\t\tassertThat(watcher).isNotNull();\n\t}\n\n\t@Test\n\tvoid restartDisabled() throws Exception {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.restart.enabled\", false);\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class, properties));\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(ClassPathFileSystemWatcher.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid restartWithTriggerFile() throws Exception {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.restart.trigger-file\", \"somefile.txt\");\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class, properties));\n\t\tClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class);\n\t\tObject watcher = ReflectionTestUtils.getField(classPathWatcher, \"fileSystemWatcher\");\n\t\tassertThat(watcher).isNotNull();\n\t\tObject filter = ReflectionTestUtils.getField(watcher, \"triggerFilter\");\n\t\tassertThat(filter).isNotNull();\n\t\tassertThat(filter).isInstanceOf(TriggerFileFilter.class);\n\t}\n\n\t@Test\n\tvoid watchingAdditionalPaths() throws Exception {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.restart.additional-paths\", \"src/main/java,src/test/java\");\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class, properties));\n\t\tClassPathFileSystemWatcher classPathWatcher = this.context.getBean(ClassPathFileSystemWatcher.class);\n\t\tObject watcher = ReflectionTestUtils.getField(classPathWatcher, \"fileSystemWatcher\");\n\t\tassertThat(watcher).isNotNull();\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tMap<File, Object> directories = (Map<File, Object>) ReflectionTestUtils.getField(watcher, \"directories\");\n\t\tassertThat(directories).hasSize(2)\n\t\t\t.containsKey(new File(\"src/main/java\").getAbsoluteFile())\n\t\t\t.containsKey(new File(\"src/test/java\").getAbsoluteFile());\n\t}\n\n\t@Test\n\tvoid devToolsSwitchesJspServletToDevelopmentMode() throws Exception {\n\t\tthis.context = getContext(() -> initializeAndRun(Config.class));\n\t\tTomcatWebServer tomcatContainer = (TomcatWebServer) ((ServletWebServerApplicationContext) this.context)\n\t\t\t.getWebServer();\n\t\tassertThat(tomcatContainer).isNotNull();\n\t\tContainer context = tomcatContainer.getTomcat().getHost().findChildren()[0];\n\t\tStandardWrapper jspServletWrapper = (StandardWrapper) context.findChild(\"jsp\");\n\t\tEmbeddedServletOptions options = (EmbeddedServletOptions) ReflectionTestUtils\n\t\t\t.getField(jspServletWrapper.getServlet(), \"options\");\n\t\tassertThat(options).isNotNull();\n\t\tassertThat(options.getDevelopment()).isTrue();\n\t}\n\n\tprivate ConfigurableApplicationContext getContext(Supplier<ConfigurableApplicationContext> supplier)\n\t\t\tthrows Exception {\n\t\tAtomicReference<ConfigurableApplicationContext> atomicReference = new AtomicReference<>();\n\t\tThread thread = new Thread(() -> {\n\t\t\tConfigurableApplicationContext context = supplier.get();\n\t\t\tatomicReference.getAndSet(context);\n\t\t});\n\t\tthread.start();\n\t\tthread.join();\n\t\tConfigurableApplicationContext context = atomicReference.get();\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\tprivate ConfigurableApplicationContext initializeAndRun(Class<?> config, String... args) {\n\t\treturn initializeAndRun(config, Collections.emptyMap(), args);\n\t}\n\n\tprivate ConfigurableApplicationContext initializeAndRun(Class<?> config, Map<String, Object> properties,\n\t\t\tString... args) {\n\t\tRestarter.initialize(new String[0], false, new MockRestartInitializer(), false);\n\t\tSpringApplication application = new SpringApplication(config);\n\t\tapplication.setDefaultProperties(getDefaultProperties(properties));\n\t\treturn application.run(args);\n\t}\n\n\tprivate Map<String, Object> getDefaultProperties(Map<String, Object> specifiedProperties) {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.devtools.livereload.port\", 0);\n\t\tproperties.put(\"server.port\", 0);\n\t\tproperties.putAll(specifiedProperties);\n\t\treturn properties;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, LocalDevToolsAutoConfiguration.class,\n\t\t\tFreeMarkerAutoConfiguration.class })\n\tstatic class Config {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, LocalDevToolsAutoConfiguration.class,\n\t\t\tFreeMarkerAutoConfiguration.class })\n\tstatic class ConfigWithMockLiveReload {\n\n\t\t@Bean\n\t\tLiveReloadServer liveReloadServer() {\n\t\t\treturn mock(LiveReloadServer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, LocalDevToolsAutoConfiguration.class })\n\tstatic class WebResourcesConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SessionRedisTemplateConfig {\n\n\t\t@Bean\n\t\tRedisTemplate<Object, Object> sessionRedisTemplate() {\n\t\t\tRedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();\n\t\t\tredisTemplate.setConnectionFactory(mock(RedisConnectionFactory.class));\n\t\t\treturn redisTemplate;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/OnEnabledDevToolsConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OnEnabledDevToolsCondition}.\n *\n * @author Madhura Bhave\n */\nclass OnEnabledDevToolsConditionTests {\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(TestConfiguration.class);\n\t}\n\n\t@Test\n\tvoid outcomeWhenDevtoolsShouldBeEnabledIsTrueShouldMatch() throws Exception {\n\t\tAtomicBoolean containsBean = new AtomicBoolean();\n\t\tThread thread = new Thread(() -> {\n\t\t\tOnEnabledDevToolsConditionTests.this.context.refresh();\n\t\t\tcontainsBean.set(OnEnabledDevToolsConditionTests.this.context.containsBean(\"test\"));\n\t\t});\n\t\tthread.start();\n\t\tthread.join();\n\t\tassertThat(containsBean).isTrue();\n\t}\n\n\t@Test\n\tvoid outcomeWhenDevtoolsShouldBeEnabledIsFalseShouldNotMatch() {\n\t\tOnEnabledDevToolsConditionTests.this.context.refresh();\n\t\tassertThat(OnEnabledDevToolsConditionTests.this.context.containsBean(\"test\")).isFalse();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"removal\")\n\t\t@Conditional(OnEnabledDevToolsCondition.class)\n\t\tString test() {\n\t\t\treturn \"hello\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/OptionalLiveReloadServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.devtools.livereload.LiveReloadServer;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link OptionalLiveReloadServer}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass OptionalLiveReloadServerTests {\n\n\t@Test\n\tvoid nullServer() {\n\t\tOptionalLiveReloadServer server = new OptionalLiveReloadServer(null);\n\t\tserver.startServer();\n\t\tserver.triggerReload();\n\t}\n\n\t@Test\n\tvoid serverWontStart() throws Exception {\n\t\tLiveReloadServer delegate = mock(LiveReloadServer.class);\n\t\tOptionalLiveReloadServer server = new OptionalLiveReloadServer(delegate);\n\t\twillThrow(new RuntimeException(\"Error\")).given(delegate).start();\n\t\tserver.startServer();\n\t\tserver.triggerReload();\n\t\tthen(delegate).should(never()).triggerReload();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/RemoteDevToolsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.Filter;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.devtools.remote.server.DispatcherFilter;\nimport org.springframework.boot.devtools.restart.MockRestarter;\nimport org.springframework.boot.devtools.restart.server.HttpRestartServer;\nimport org.springframework.boot.devtools.restart.server.SourceDirectoryUrlFilter;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.mock.web.MockFilterChain;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;\n\n/**\n * Tests for {@link RemoteDevToolsAutoConfiguration}.\n *\n * @author Rob Winch\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@ExtendWith(MockRestarter.class)\nclass RemoteDevToolsAutoConfigurationTests {\n\n\tprivate static final String DEFAULT_CONTEXT_PATH = RemoteDevToolsProperties.DEFAULT_CONTEXT_PATH;\n\n\tprivate static final String DEFAULT_SECRET_HEADER_NAME = RemoteDevToolsProperties.DEFAULT_SECRET_HEADER_NAME;\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\tprivate MockHttpServletRequest request;\n\n\tprivate MockHttpServletResponse response;\n\n\tprivate MockFilterChain chain;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.request = new MockHttpServletRequest();\n\t\tthis.response = new MockHttpServletResponse();\n\t\tthis.chain = new MockFilterChain();\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid disabledIfRemoteSecretIsMissing() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"a:b\"));\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(DispatcherFilter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid ignoresUnmappedUrl() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(\"/restart\");\n\t\tthis.request.addHeader(DEFAULT_SECRET_HEADER_NAME, \"supersecret\");\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertRestartInvoked(false);\n\t}\n\n\t@Test\n\tvoid ignoresIfMissingSecretFromRequest() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(DEFAULT_CONTEXT_PATH + \"/restart\");\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertRestartInvoked(false);\n\t}\n\n\t@Test\n\tvoid ignoresInvalidSecretInRequest() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(DEFAULT_CONTEXT_PATH + \"/restart\");\n\t\tthis.request.addHeader(DEFAULT_SECRET_HEADER_NAME, \"invalid\");\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertRestartInvoked(false);\n\t}\n\n\t@Test\n\tvoid invokeRestartWithDefaultSetup() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(DEFAULT_CONTEXT_PATH + \"/restart\");\n\t\tthis.request.addHeader(DEFAULT_SECRET_HEADER_NAME, \"supersecret\");\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertRestartInvoked(true);\n\t}\n\n\t@Test\n\tvoid invokeRestartWithCustomServerContextPath() throws Exception {\n\t\tthis.context = getContext(\n\t\t\t\t() -> loadContext(\"spring.devtools.remote.secret:supersecret\", \"server.servlet.context-path:/test\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(\"/test\" + DEFAULT_CONTEXT_PATH + \"/restart\");\n\t\tthis.request.addHeader(DEFAULT_SECRET_HEADER_NAME, \"supersecret\");\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertRestartInvoked(true);\n\t}\n\n\t@Test\n\tvoid securityConfigurationShouldAllowAccess() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tMockMvcTester mvc = MockMvcTester.from(this.context,\n\t\t\t\t(builder) -> builder.apply(springSecurity()).addFilter(filter).build());\n\t\tassertThat(mvc.get().uri(DEFAULT_CONTEXT_PATH + \"/restart\").header(DEFAULT_SECRET_HEADER_NAME, \"supersecret\"))\n\t\t\t.hasStatusOk();\n\t\tassertRestartInvoked(true);\n\t\tassertThat(this.context.containsBean(\"devtoolsSecurityFilterChain\")).isTrue();\n\t}\n\n\t@Test\n\tvoid securityConfigurationShouldAllowAccessToCustomPath() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\",\n\t\t\t\t\"server.servlet.context-path:/test\", \"spring.devtools.remote.context-path:/custom\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tMockMvcTester mvc = MockMvcTester.from(this.context,\n\t\t\t\t(builder) -> builder.apply(springSecurity()).addFilter(filter).build());\n\t\tassertThat(mvc.get().uri(\"/test/custom/restart\").header(DEFAULT_SECRET_HEADER_NAME, \"supersecret\"))\n\t\t\t.hasStatusOk();\n\t\tassertRestartInvoked(true);\n\t}\n\n\t@Test\n\tvoid securityConfigurationDoesNotAffectOtherPaths() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tFilter securityFilterChain = this.context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);\n\t\tMockMvcTester mvc = MockMvcTester.from(this.context,\n\t\t\t\t(builder) -> builder.addFilter(securityFilterChain).addFilter(filter).build());\n\t\tassertThat(mvc.get().uri(\"/my-path\")).hasStatus(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid disableRestart() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\",\n\t\t\t\t\"spring.devtools.remote.restart.enabled:false\"));\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(\"remoteRestartHandlerMapper\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid devToolsHealthReturns200() throws Exception {\n\t\tthis.context = getContext(() -> loadContext(\"spring.devtools.remote.secret:supersecret\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(DEFAULT_CONTEXT_PATH);\n\t\tthis.request.addHeader(DEFAULT_SECRET_HEADER_NAME, \"supersecret\");\n\t\tthis.response.setStatus(500);\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid devToolsHealthWithCustomServerContextPathReturns200() throws Exception {\n\t\tthis.context = getContext(\n\t\t\t\t() -> loadContext(\"spring.devtools.remote.secret:supersecret\", \"server.servlet.context-path:/test\"));\n\t\tDispatcherFilter filter = this.context.getBean(DispatcherFilter.class);\n\t\tthis.request.setRequestURI(\"/test\" + DEFAULT_CONTEXT_PATH);\n\t\tthis.request.addHeader(DEFAULT_SECRET_HEADER_NAME, \"supersecret\");\n\t\tthis.response.setStatus(500);\n\t\tfilter.doFilter(this.request, this.response, this.chain);\n\t\tassertThat(this.response.getStatus()).isEqualTo(200);\n\t}\n\n\tprivate AnnotationConfigServletWebApplicationContext getContext(\n\t\t\tSupplier<AnnotationConfigServletWebApplicationContext> supplier) throws Exception {\n\t\tAtomicReference<AnnotationConfigServletWebApplicationContext> atomicReference = new AtomicReference<>();\n\t\tThread thread = new Thread(() -> {\n\t\t\tAnnotationConfigServletWebApplicationContext context = supplier.get();\n\t\t\tatomicReference.getAndSet(context);\n\t\t});\n\t\tthread.start();\n\t\tthread.join();\n\t\tAnnotationConfigServletWebApplicationContext context = atomicReference.get();\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\tprivate void assertRestartInvoked(boolean value) {\n\t\tassertThat(this.context).isNotNull();\n\t\tassertThat(this.context.getBean(MockHttpRestartServer.class).invoked).isEqualTo(value);\n\t}\n\n\tprivate AnnotationConfigServletWebApplicationContext loadContext(String... properties) {\n\t\tAnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\t\tcontext.setServletContext(new MockServletContext());\n\t\tcontext.register(Config.class, SecurityAutoConfiguration.class, ServletWebSecurityAutoConfiguration.class,\n\t\t\t\tRemoteDevToolsAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tTestPropertyValues.of(properties).applyTo(context);\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tHttpRestartServer remoteRestartHttpRestartServer() {\n\t\t\tSourceDirectoryUrlFilter sourceDirectoryUrlFilter = mock(SourceDirectoryUrlFilter.class);\n\t\t\treturn new MockHttpRestartServer(sourceDirectoryUrlFilter);\n\t\t}\n\n\t}\n\n\t/**\n\t * Mock {@link HttpRestartServer} implementation.\n\t */\n\tstatic class MockHttpRestartServer extends HttpRestartServer {\n\n\t\tprivate boolean invoked;\n\n\t\tMockHttpRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter) {\n\t\t\tsuper(sourceDirectoryUrlFilter);\n\t\t}\n\n\t\t@Override\n\t\tpublic void handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\tthis.invoked = true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/TriggerFileFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.autoconfigure;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link TriggerFileFilter}.\n *\n * @author Phillip Webb\n */\nclass TriggerFileFilterTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid nameMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TriggerFileFilter(null))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\tvoid acceptNameMatch() throws Exception {\n\t\tFile file = new File(this.tempDir, \"thefile.txt\");\n\t\tfile.createNewFile();\n\t\tassertThat(new TriggerFileFilter(\"thefile.txt\").accept(file)).isTrue();\n\t}\n\n\t@Test\n\tvoid doesNotAcceptNameMismatch() throws Exception {\n\t\tFile file = new File(this.tempDir, \"notthefile.txt\");\n\t\tfile.createNewFile();\n\t\tassertThat(new TriggerFileFilter(\"thefile.txt\").accept(file)).isFalse();\n\t}\n\n\t@Test\n\tvoid testName() throws Exception {\n\t\tFile file = new File(this.tempDir, \".triggerfile\");\n\t\tfile.createNewFile();\n\t\tassertThat(new TriggerFileFilter(\".triggerfile\").accept(file)).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathChangedEventTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ClassPathChangedEvent}.\n *\n * @author Phillip Webb\n */\nclass ClassPathChangedEventTests {\n\n\tprivate final Object source = new Object();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid changeSetMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangedEvent(this.source, null, false))\n\t\t\t.withMessageContaining(\"'changeSet' must not be null\");\n\t}\n\n\t@Test\n\tvoid getChangeSet() {\n\t\tSet<ChangedFiles> changeSet = new LinkedHashSet<>();\n\t\tClassPathChangedEvent event = new ClassPathChangedEvent(this.source, changeSet, false);\n\t\tassertThat(event.getChangeSet()).isSameAs(changeSet);\n\t}\n\n\t@Test\n\tvoid getRestartRequired() {\n\t\tSet<ChangedFiles> changeSet = new LinkedHashSet<>();\n\t\tClassPathChangedEvent event;\n\t\tevent = new ClassPathChangedEvent(this.source, changeSet, false);\n\t\tassertThat(event.isRestartRequired()).isFalse();\n\t\tevent = new ClassPathChangedEvent(this.source, changeSet, true);\n\t\tassertThat(event.isRestartRequired()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileChangeListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.context.ApplicationEventPublisher;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ClassPathFileChangeListener}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass ClassPathFileChangeListenerTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationEventPublisher eventPublisher;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassPathRestartStrategy restartStrategy;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate FileSystemWatcher fileSystemWatcher;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid eventPublisherMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ClassPathFileChangeListener(null, this.restartStrategy, this.fileSystemWatcher))\n\t\t\t.withMessageContaining(\"'eventPublisher' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid restartStrategyMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ClassPathFileChangeListener(this.eventPublisher, null, this.fileSystemWatcher))\n\t\t\t.withMessageContaining(\"'restartStrategy' must not be null\");\n\t}\n\n\t@Test\n\tvoid sendsEventWithoutRestart() {\n\t\ttestSendsEvent(false);\n\t\tthen(this.fileSystemWatcher).should(never()).stop();\n\t}\n\n\t@Test\n\tvoid sendsEventWithRestart() {\n\t\ttestSendsEvent(true);\n\t\tthen(this.fileSystemWatcher).should().stop();\n\t}\n\n\tprivate void testSendsEvent(boolean restart) {\n\t\tClassPathFileChangeListener listener = new ClassPathFileChangeListener(this.eventPublisher,\n\t\t\t\tthis.restartStrategy, this.fileSystemWatcher);\n\t\tFile directory = new File(\"s1\");\n\t\tFile file = new File(\"f1\");\n\t\tChangedFile file1 = new ChangedFile(directory, file, ChangedFile.Type.ADD);\n\t\tChangedFile file2 = new ChangedFile(directory, file, ChangedFile.Type.ADD);\n\t\tSet<ChangedFile> files = new LinkedHashSet<>();\n\t\tfiles.add(file1);\n\t\tfiles.add(file2);\n\t\tChangedFiles changedFiles = new ChangedFiles(new File(\"source\"), files);\n\t\tSet<ChangedFiles> changeSet = Collections.singleton(changedFiles);\n\t\tif (restart) {\n\t\t\tgiven(this.restartStrategy.isRestartRequired(file2)).willReturn(true);\n\t\t}\n\t\tlistener.onChange(changeSet);\n\t\tthen(this.eventPublisher).should()\n\t\t\t.publishEvent(assertArg((applicationEvent) -> assertThat(applicationEvent)\n\t\t\t\t.isInstanceOfSatisfying(ClassPathChangedEvent.class, (classPathChangedEvent) -> {\n\t\t\t\t\tassertThat(classPathChangedEvent.getChangeSet()).isEqualTo(changeSet);\n\t\t\t\t\tassertThat(classPathChangedEvent.isRestartRequired()).isEqualTo(restart);\n\t\t\t\t})));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/ClassPathFileSystemWatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcher;\nimport org.springframework.boot.devtools.filewatch.FileSystemWatcherFactory;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ClassPathFileSystemWatcher}.\n *\n * @author Phillip Webb\n */\nclass ClassPathFileSystemWatcherTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid urlsMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ClassPathFileSystemWatcher(mock(FileSystemWatcherFactory.class),\n\t\t\t\t\tmock(ClassPathRestartStrategy.class), (URL[]) null))\n\t\t\t.withMessageContaining(\"'urls' must not be null\");\n\t}\n\n\t@Test\n\tvoid configuredWithRestartStrategy(@TempDir File directory) throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tList<URL> urls = new ArrayList<>();\n\t\turls.add(new URL(\"https://spring.io\"));\n\t\turls.add(directory.toURI().toURL());\n\t\tproperties.put(\"urls\", urls);\n\t\tMapPropertySource propertySource = new MapPropertySource(\"test\", properties);\n\t\tcontext.getEnvironment().getPropertySources().addLast(propertySource);\n\t\tcontext.register(Config.class);\n\t\tcontext.refresh();\n\t\tThread.sleep(200);\n\t\tFile classFile = new File(directory, \"Example.class\");\n\t\tFileCopyUtils.copy(\"file\".getBytes(), classFile);\n\t\tThread.sleep(1000);\n\t\tList<ClassPathChangedEvent> events = context.getBean(Listener.class).getEvents();\n\t\tfor (int i = 0; i < 20; i++) {\n\t\t\tif (!events.isEmpty()) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tThread.sleep(500);\n\t\t}\n\t\tassertThat(events).hasSize(1);\n\t\tassertThat(events.get(0).getChangeSet().iterator().next()).extracting(ChangedFile::getFile)\n\t\t\t.containsExactly(classFile);\n\t\tcontext.close();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\tpublic final Environment environment;\n\n\t\tConfig(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Bean\n\t\tClassPathFileSystemWatcher watcher(ClassPathRestartStrategy restartStrategy) {\n\t\t\tFileSystemWatcher watcher = new FileSystemWatcher(false, Duration.ofMillis(100), Duration.ofMillis(10));\n\t\t\tURL[] urls = this.environment.getProperty(\"urls\", URL[].class);\n\t\t\tassertThat(urls).isNotNull();\n\t\t\treturn new ClassPathFileSystemWatcher(new MockFileSystemWatcherFactory(watcher), restartStrategy, urls);\n\t\t}\n\n\t\t@Bean\n\t\tClassPathRestartStrategy restartStrategy() {\n\t\t\treturn (file) -> false;\n\t\t}\n\n\t\t@Bean\n\t\tListener listener() {\n\t\t\treturn new Listener();\n\t\t}\n\n\t}\n\n\tstatic class Listener implements ApplicationListener<ClassPathChangedEvent> {\n\n\t\tprivate final List<ClassPathChangedEvent> events = new CopyOnWriteArrayList<>();\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ClassPathChangedEvent event) {\n\t\t\tthis.events.add(event);\n\t\t}\n\n\t\tList<ClassPathChangedEvent> getEvents() {\n\t\t\treturn this.events;\n\t\t}\n\n\t}\n\n\tstatic class MockFileSystemWatcherFactory implements FileSystemWatcherFactory {\n\n\t\tprivate final FileSystemWatcher watcher;\n\n\t\tMockFileSystemWatcherFactory(FileSystemWatcher watcher) {\n\t\t\tthis.watcher = watcher;\n\t\t}\n\n\t\t@Override\n\t\tpublic FileSystemWatcher getFileSystemWatcher() {\n\t\t\treturn this.watcher;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/classpath/PatternClassPathRestartStrategyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.classpath;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PatternClassPathRestartStrategy}.\n *\n * @author Phillip Webb\n * @author Andrew Landsverk\n */\nclass PatternClassPathRestartStrategyTests {\n\n\t@Test\n\tvoid nullPattern() {\n\t\tClassPathRestartStrategy strategy = createStrategy(null);\n\t\tassertRestartRequired(strategy, \"a/b.txt\", true);\n\t}\n\n\t@Test\n\tvoid emptyPattern() {\n\t\tClassPathRestartStrategy strategy = createStrategy(\"\");\n\t\tassertRestartRequired(strategy, \"a/b.txt\", true);\n\t}\n\n\t@Test\n\tvoid singlePattern() {\n\t\tClassPathRestartStrategy strategy = createStrategy(\"static/**\");\n\t\tassertRestartRequired(strategy, \"static/file.txt\", false);\n\t\tassertRestartRequired(strategy, \"static/directory/file.txt\", false);\n\t\tassertRestartRequired(strategy, \"public/file.txt\", true);\n\t\tassertRestartRequired(strategy, \"public/directory/file.txt\", true);\n\t}\n\n\t@Test\n\tvoid multiplePatterns() {\n\t\tClassPathRestartStrategy strategy = createStrategy(\"static/**,public/**\");\n\t\tassertRestartRequired(strategy, \"static/file.txt\", false);\n\t\tassertRestartRequired(strategy, \"static/directory/file.txt\", false);\n\t\tassertRestartRequired(strategy, \"public/file.txt\", false);\n\t\tassertRestartRequired(strategy, \"public/directory/file.txt\", false);\n\t\tassertRestartRequired(strategy, \"src/file.txt\", true);\n\t\tassertRestartRequired(strategy, \"src/directory/file.txt\", true);\n\t}\n\n\t@Test\n\tvoid pomChange() {\n\t\tClassPathRestartStrategy strategy = createStrategy(\"META-INF/maven/**\");\n\t\tassertRestartRequired(strategy, \"pom.xml\", true);\n\t\tString mavenDirectory = \"META-INF/maven/org.springframework.boot/spring-boot-devtools\";\n\t\tassertRestartRequired(strategy, mavenDirectory + \"/pom.xml\", false);\n\t\tassertRestartRequired(strategy, mavenDirectory + \"/pom.properties\", false);\n\t}\n\n\t@Test\n\tvoid testChange() {\n\t\tClassPathRestartStrategy strategy = createStrategy(\"**/*Test.class,**/*Tests.class\");\n\t\tassertRestartRequired(strategy, \"com/example/ExampleTests.class\", false);\n\t\tassertRestartRequired(strategy, \"com/example/ExampleTest.class\", false);\n\t\tassertRestartRequired(strategy, \"com/example/Example.class\", true);\n\t}\n\n\tprivate ClassPathRestartStrategy createStrategy(@Nullable String pattern) {\n\t\treturn new PatternClassPathRestartStrategy(pattern);\n\t}\n\n\tprivate void assertRestartRequired(ClassPathRestartStrategy strategy, String relativeName, boolean expected) {\n\t\tassertThat(strategy.isRestartRequired(mockFile(relativeName))).isEqualTo(expected);\n\t}\n\n\tprivate ChangedFile mockFile(String relativeName) {\n\t\treturn new ChangedFile(new File(\".\"), new File(\"./\" + relativeName), Type.ADD);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.env;\n\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.devtools.restart.RestartInitializer;\nimport org.springframework.boot.devtools.restart.Restarter;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Integration tests for the configuration of development-time properties\n *\n * @author Andy Wilkinson\n */\nclass DevToolPropertiesIntegrationTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tRestarter.initialize(new String[] {}, false, new MockInitializer(), false);\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tRestarter.clearInstance();\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@WithResource(name = \"META-INF/spring-devtools.properties\", content = \"defaults.com.example.enabled=true\")\n\tvoid classPropertyConditionIsAffectedByDevToolProperties() throws Exception {\n\t\tSpringApplication application = new SpringApplication(ClassConditionConfiguration.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = getContext(application::run);\n\t\tthis.context.getBean(ClassConditionConfiguration.class);\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@WithResource(name = \"META-INF/spring-devtools.properties\", content = \"defaults.com.example.enabled=true\")\n\tvoid beanMethodPropertyConditionIsAffectedByDevToolProperties() throws Exception {\n\t\tSpringApplication application = new SpringApplication(BeanConditionConfiguration.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = getContext(application::run);\n\t\tthis.context.getBean(MyBean.class);\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@WithResource(name = \"META-INF/spring-devtools.properties\", content = \"defaults.com.example.enabled=true\")\n\tvoid postProcessWhenRestarterDisabledAndRemoteSecretNotSetShouldNotAddPropertySource() throws Exception {\n\t\tRestarter.clearInstance();\n\t\tRestarter.disable();\n\t\tSpringApplication application = new SpringApplication(BeanConditionConfiguration.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = getContext(application::run);\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(MyBean.class);\n\t\t});\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@WithResource(name = \"META-INF/spring-devtools.properties\", content = \"defaults.com.example.enabled=true\")\n\tvoid postProcessWhenRestarterDisabledAndRemoteSecretSetShouldAddPropertySource() throws Exception {\n\t\tRestarter.clearInstance();\n\t\tRestarter.disable();\n\t\tSpringApplication application = new SpringApplication(BeanConditionConfiguration.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.setDefaultProperties(Collections.singletonMap(\"spring.devtools.remote.secret\", \"donttell\"));\n\t\tthis.context = getContext(application::run);\n\t\tthis.context.getBean(MyBean.class);\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\t@WithResource(name = \"META-INF/spring-devtools.properties\", content = \"\"\"\n\t\t\tdefaults.com.example.one=alpha\n\t\t\tdefaults.com.example.two=bravo\n\t\t\t\"\"\")\n\tvoid postProcessSetsPropertyDefaults() throws Exception {\n\t\tSpringApplication application = new SpringApplication(TestConfiguration.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tthis.context = getContext(application::run);\n\t\tConfigurableEnvironment environment = this.context.getEnvironment();\n\t\tString one = environment.getProperty(\"com.example.one\");\n\t\tassertThat(one).isEqualTo(\"alpha\");\n\t\tString two = environment.getProperty(\"com.example.two\");\n\t\tassertThat(two).isEqualTo(\"bravo\");\n\t}\n\n\tprotected ConfigurableApplicationContext getContext(Supplier<ConfigurableApplicationContext> supplier)\n\t\t\tthrows Exception {\n\t\tAtomicReference<ConfigurableApplicationContext> atomicReference = new AtomicReference<>();\n\t\tThread thread = new Thread(() -> {\n\t\t\tConfigurableApplicationContext context = supplier.get();\n\t\t\tatomicReference.getAndSet(context);\n\t\t});\n\t\tthread.start();\n\t\tthread.join();\n\t\tConfigurableApplicationContext context = atomicReference.get();\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(\"com.example.enabled\")\n\tstatic class ClassConditionConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BeanConditionConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnProperty(\"com.example.enabled\")\n\t\tMyBean myBean() {\n\t\t\treturn new MyBean();\n\t\t}\n\n\t}\n\n\tstatic class MyBean {\n\n\t}\n\n\tstatic class MockInitializer implements RestartInitializer {\n\n\t\t@Override\n\t\tpublic URL[] getInitialUrls(Thread thread) {\n\t\t\treturn new URL[] {};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolsHomePropertiesPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.env;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DevToolsHomePropertiesPostProcessor}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author HaiTao Zhang\n * @author Madhura Bhave\n */\nclass DevToolsHomePropertiesPostProcessorTests {\n\n\tprivate String configDir;\n\n\tprivate File home;\n\n\tprivate File customHome;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File tempDir) {\n\t\tthis.home = new File(tempDir, \"default-home\");\n\t\tthis.customHome = new File(tempDir, \"custom-home\");\n\t\tthis.configDir = this.home + \"/.config/spring-boot/\";\n\t\tnew File(this.configDir).mkdirs();\n\t}\n\n\t@Test\n\tvoid loadsPropertiesFromHomeDirectoryUsingProperties() throws Exception {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"abc\", \"def\");\n\t\twriteFile(properties, \".spring-boot-devtools.properties\");\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc\")).isEqualTo(\"def\");\n\t}\n\n\t@Test\n\tvoid loadsPropertiesFromCustomHomeDirectorySetUsingSystemProperty() throws Exception {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"uvw\", \"xyz\");\n\t\twriteFile(properties, this.customHome, \".config/spring-boot/spring-boot-devtools.properties\");\n\t\tProperties systemProperties = new Properties();\n\t\tsystemProperties.setProperty(\"spring.devtools.home\", this.customHome.getAbsolutePath());\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment(systemProperties);\n\t\tassertThat(environment.getProperty(\"uvw\")).isEqualTo(\"xyz\");\n\t}\n\n\t@Test\n\tvoid loadsPropertiesFromCustomHomeDirectorySetUsingEnvironmentVariable() throws Exception {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"uvw\", \"xyz\");\n\t\twriteFile(properties, this.customHome, \".config/spring-boot/spring-boot-devtools.properties\");\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment(\n\t\t\t\tCollections.singletonMap(\"SPRING_DEVTOOLS_HOME\", this.customHome.getAbsolutePath()));\n\t\tassertThat(environment.getProperty(\"uvw\")).isEqualTo(\"xyz\");\n\t}\n\n\t@Test\n\tvoid loadsPropertiesFromConfigDirectoryUsingProperties() throws Exception {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"abc\", \"def\");\n\t\tOutputStream out = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.properties\"));\n\t\tproperties.store(out, null);\n\t\tout.close();\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc\")).isEqualTo(\"def\");\n\t}\n\n\t@Test\n\tvoid loadsPropertiesFromConfigDirectoryUsingYml() throws Exception {\n\t\tOutputStream out = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.yml\"));\n\t\tFile file = new ClassPathResource(\"spring-devtools.yaml\", getClass()).getFile();\n\t\tbyte[] content = Files.readAllBytes(file.toPath());\n\t\tout.write(content);\n\t\tout.close();\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc.xyz\")).isEqualTo(\"def\");\n\t}\n\n\t@Test\n\tvoid loadsPropertiesFromConfigDirectoryUsingYaml() throws Exception {\n\t\tOutputStream out = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.yaml\"));\n\t\tFile file = new ClassPathResource(\"spring-devtools.yaml\", getClass()).getFile();\n\t\tbyte[] content = Files.readAllBytes(file.toPath());\n\t\tout.write(content);\n\t\tout.close();\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc.xyz\")).isEqualTo(\"def\");\n\t}\n\n\t@Test\n\tvoid loadFromConfigDirectoryWithPropertiesTakingPrecedence() throws Exception {\n\t\tOutputStream out = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.yaml\"));\n\t\tFile file = new ClassPathResource(\"spring-devtools.yaml\", getClass()).getFile();\n\t\tbyte[] content = Files.readAllBytes(file.toPath());\n\t\tout.write(content);\n\t\tout.close();\n\t\tProperties properties2 = new Properties();\n\t\tproperties2.put(\"abc.xyz\", \"jkl\");\n\t\tOutputStream out2 = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.properties\"));\n\t\tproperties2.store(out2, null);\n\t\tout2.close();\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc.xyz\")).isEqualTo(\"jkl\");\n\t\tassertThat(environment.getProperty(\"bing\")).isEqualTo(\"blip\");\n\t}\n\n\t@Test\n\tvoid loadFromConfigDirectoryTakesPrecedenceOverHomeDirectory() throws Exception {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"abc\", \"def\");\n\t\tproperties.put(\"bar\", \"baz\");\n\t\twriteFile(properties, \".spring-boot-devtools.properties\");\n\t\tProperties properties2 = new Properties();\n\t\tproperties2.put(\"abc\", \"jkl\");\n\t\tOutputStream out2 = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.properties\"));\n\t\tproperties2.store(out2, null);\n\t\tout2.close();\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc\")).isEqualTo(\"jkl\");\n\t\tassertThat(environment.getProperty(\"bar\")).isNull();\n\t}\n\n\t@Test\n\tvoid loadFromConfigDirectoryWithYamlTakesPrecedenceOverHomeDirectory() throws Exception {\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"abc.xyz\", \"jkl\");\n\t\tproperties.put(\"bar\", \"baz\");\n\t\twriteFile(properties, \".spring-boot-devtools.properties\");\n\t\tOutputStream out2 = new FileOutputStream(new File(this.configDir, \"spring-boot-devtools.yml\"));\n\t\tFile file = new ClassPathResource(\"spring-devtools.yaml\", getClass()).getFile();\n\t\tbyte[] content = Files.readAllBytes(file.toPath());\n\t\tout2.write(content);\n\t\tout2.close();\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc.xyz\")).isEqualTo(\"def\");\n\t\tassertThat(environment.getProperty(\"bar\")).isNull();\n\t}\n\n\t@Test\n\tvoid ignoresMissingHomeProperties() throws Exception {\n\t\tConfigurableEnvironment environment = getPostProcessedEnvironment();\n\t\tassertThat(environment.getProperty(\"abc\")).isNull();\n\t}\n\n\tprivate void writeFile(Properties properties, String path) throws IOException {\n\t\twriteFile(properties, this.home, path);\n\t}\n\n\tprivate void writeFile(Properties properties, File home, String path) throws IOException {\n\t\tFile file = new File(home, path);\n\t\tfile.getParentFile().mkdirs();\n\t\ttry (OutputStream out = new FileOutputStream(file)) {\n\t\t\tproperties.store(out, null);\n\t\t}\n\t}\n\n\tprivate ConfigurableEnvironment getPostProcessedEnvironment() throws Exception {\n\t\treturn getPostProcessedEnvironment(null, null);\n\t}\n\n\tprivate ConfigurableEnvironment getPostProcessedEnvironment(Properties systemProperties) throws Exception {\n\t\treturn getPostProcessedEnvironment(null, systemProperties);\n\t}\n\n\tprivate ConfigurableEnvironment getPostProcessedEnvironment(Map<String, String> env) throws Exception {\n\t\treturn getPostProcessedEnvironment(env, null);\n\t}\n\n\tprivate ConfigurableEnvironment getPostProcessedEnvironment(@Nullable Map<String, String> env,\n\t\t\t@Nullable Properties systemProperties) throws Exception {\n\t\tif (systemProperties == null) {\n\t\t\tsystemProperties = new Properties();\n\t\t\tsystemProperties.setProperty(\"user.home\", this.home.getAbsolutePath());\n\t\t}\n\t\tConfigurableEnvironment environment = new MockEnvironment();\n\t\tDevToolsHomePropertiesPostProcessor postProcessor = new DevToolsHomePropertiesPostProcessor(\n\t\t\t\t(env != null) ? env : Collections.emptyMap(), systemProperties);\n\t\trunPostProcessor(() -> postProcessor.postProcessEnvironment(environment, new SpringApplication()));\n\t\treturn environment;\n\t}\n\n\tprotected void runPostProcessor(Runnable runnable) throws Exception {\n\t\tThread thread = new Thread(runnable);\n\t\tthread.start();\n\t\tthread.join();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/ChangedFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ChangedFile}.\n *\n * @author Phillip Webb\n */\nclass ChangedFileTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid sourceDirectoryMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ChangedFile(null, new File(this.tempDir, \"file\"), Type.ADD))\n\t\t\t.withMessageContaining(\"'sourceDirectory' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fileMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ChangedFile(new File(this.tempDir, \"directory\"), null, Type.ADD))\n\t\t\t.withMessageContaining(\"'file' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid typeMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new ChangedFile(new File(this.tempDir, \"file\"), new File(this.tempDir, \"directory\"), null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid getFile() {\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\tChangedFile changedFile = new ChangedFile(new File(this.tempDir, \"directory\"), file, Type.ADD);\n\t\tassertThat(changedFile.getFile()).isEqualTo(file);\n\t}\n\n\t@Test\n\tvoid getType() {\n\t\tChangedFile changedFile = new ChangedFile(new File(this.tempDir, \"directory\"), new File(this.tempDir, \"file\"),\n\t\t\t\tType.DELETE);\n\t\tassertThat(changedFile.getType()).isEqualTo(Type.DELETE);\n\t}\n\n\t@Test\n\tvoid getRelativeName() {\n\t\tFile subDirectory = new File(this.tempDir, \"A\");\n\t\tFile file = new File(subDirectory, \"B.txt\");\n\t\tChangedFile changedFile = new ChangedFile(this.tempDir, file, Type.ADD);\n\t\tassertThat(changedFile.getRelativeName()).isEqualTo(\"A/B.txt\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/DirectorySnapshotTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DirectorySnapshot}.\n *\n * @author Phillip Webb\n */\nclass DirectorySnapshotTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\tprivate File directory;\n\n\tprivate DirectorySnapshot initialSnapshot;\n\n\t@BeforeEach\n\tvoid setup() throws Exception {\n\t\tthis.directory = createTestDirectoryStructure();\n\t\tthis.initialSnapshot = new DirectorySnapshot(this.directory);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid directoryMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DirectorySnapshot(null))\n\t\t\t.withMessageContaining(\"'directory' must not be null\");\n\t}\n\n\t@Test\n\tvoid directoryMustNotBeFile() throws Exception {\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\tfile.createNewFile();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DirectorySnapshot(file))\n\t\t\t.withMessageContaining(\"'directory' [\" + file + \"] must not be a file\");\n\t}\n\n\t@Test\n\tvoid directoryDoesNotHaveToExist() {\n\t\tFile file = new File(this.tempDir, \"does/not/exist\");\n\t\tDirectorySnapshot snapshot = new DirectorySnapshot(file);\n\t\tassertThat(snapshot).isEqualTo(new DirectorySnapshot(file));\n\t}\n\n\t@Test\n\tvoid equalsWhenNothingHasChanged() {\n\t\tDirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);\n\t\tassertThat(this.initialSnapshot).isEqualTo(updatedSnapshot);\n\t\tassertThat(this.initialSnapshot).hasSameHashCodeAs(updatedSnapshot);\n\t}\n\n\t@Test\n\tvoid notEqualsWhenAFileIsAdded() throws Exception {\n\t\tnew File(new File(this.directory, \"directory1\"), \"newfile\").createNewFile();\n\t\tDirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);\n\t\tassertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot);\n\t}\n\n\t@Test\n\tvoid notEqualsWhenAFileIsDeleted() {\n\t\tnew File(new File(this.directory, \"directory1\"), \"file1\").delete();\n\t\tDirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);\n\t\tassertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot);\n\t}\n\n\t@Test\n\tvoid notEqualsWhenAFileIsModified() throws Exception {\n\t\tFile file1 = new File(new File(this.directory, \"directory1\"), \"file1\");\n\t\tFileCopyUtils.copy(\"updatedcontent\".getBytes(), file1);\n\t\tDirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);\n\t\tassertThat(this.initialSnapshot).isNotEqualTo(updatedSnapshot);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getChangedFilesSnapshotMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.initialSnapshot.getChangedFiles(null, null))\n\t\t\t.withMessageContaining(\"'snapshot' must not be null\");\n\t}\n\n\t@Test\n\tvoid getChangedFilesSnapshotMustBeTheSameSourceDirectory() {\n\t\tassertThatIllegalArgumentException().isThrownBy(\n\t\t\t\t() -> this.initialSnapshot.getChangedFiles(new DirectorySnapshot(createTestDirectoryStructure()), null))\n\t\t\t.withMessageContaining(\"'snapshot' source directory must be '\" + this.directory + \"'\");\n\t}\n\n\t@Test\n\tvoid getChangedFilesWhenNothingHasChanged() {\n\t\tDirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);\n\t\tthis.initialSnapshot.getChangedFiles(updatedSnapshot, null);\n\t}\n\n\t@Test\n\tvoid getChangedFilesWhenAFileIsAddedAndDeletedAndChanged() throws Exception {\n\t\tFile directory1 = new File(this.directory, \"directory1\");\n\t\tFile file1 = new File(directory1, \"file1\");\n\t\tFile file2 = new File(directory1, \"file2\");\n\t\tFile newFile = new File(directory1, \"newfile\");\n\t\tFileCopyUtils.copy(\"updatedcontent\".getBytes(), file1);\n\t\tfile2.delete();\n\t\tnewFile.createNewFile();\n\t\tDirectorySnapshot updatedSnapshot = new DirectorySnapshot(this.directory);\n\t\tChangedFiles changedFiles = this.initialSnapshot.getChangedFiles(updatedSnapshot, null);\n\t\tassertThat(changedFiles.getSourceDirectory()).isEqualTo(this.directory);\n\t\tassertThat(getChangedFile(changedFiles, file1).getType()).isEqualTo(Type.MODIFY);\n\t\tassertThat(getChangedFile(changedFiles, file2).getType()).isEqualTo(Type.DELETE);\n\t\tassertThat(getChangedFile(changedFiles, newFile).getType()).isEqualTo(Type.ADD);\n\t}\n\n\tprivate ChangedFile getChangedFile(ChangedFiles changedFiles, File file) {\n\t\tfor (ChangedFile changedFile : changedFiles) {\n\t\t\tif (changedFile.getFile().equals(file)) {\n\t\t\t\treturn changedFile;\n\t\t\t}\n\t\t}\n\t\tthrow new AssertionError(\"File '%s' not found\".formatted(file));\n\t}\n\n\tprivate File createTestDirectoryStructure() throws IOException {\n\t\tFile root = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tFile directory1 = new File(root, \"directory1\");\n\t\tdirectory1.mkdirs();\n\t\tFileCopyUtils.copy(\"abc\".getBytes(), new File(directory1, \"file1\"));\n\t\tFileCopyUtils.copy(\"abc\".getBytes(), new File(directory1, \"file2\"));\n\t\treturn root;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSnapshotTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Date;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link FileSnapshot}.\n *\n * @author Phillip Webb\n */\nclass FileSnapshotTests {\n\n\tprivate static final long TWO_MINS = TimeUnit.MINUTES.toMillis(2);\n\n\tprivate static final long MODIFIED = new Date().getTime() - TimeUnit.DAYS.toMillis(10);\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fileMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new FileSnapshot(null))\n\t\t\t.withMessageContaining(\"'file' must not be null\");\n\t}\n\n\t@Test\n\tvoid fileMustNotBeADirectory() {\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\tfile.mkdir();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new FileSnapshot(file))\n\t\t\t.withMessageContaining(\"'file' [\" + file + \"] must be a normal file\");\n\t}\n\n\t@Test\n\tvoid equalsIfTheSame() throws Exception {\n\t\tFile file = createNewFile(\"abc\", MODIFIED);\n\t\tFile fileCopy = new File(file, \"x\").getParentFile();\n\t\tFileSnapshot snapshot1 = new FileSnapshot(file);\n\t\tFileSnapshot snapshot2 = new FileSnapshot(fileCopy);\n\t\tassertThat(snapshot1).isEqualTo(snapshot2);\n\t\tassertThat(snapshot1).hasSameHashCodeAs(snapshot2);\n\t}\n\n\t@Test\n\tvoid notEqualsIfDeleted() throws Exception {\n\t\tFile file = createNewFile(\"abc\", MODIFIED);\n\t\tFileSnapshot snapshot1 = new FileSnapshot(file);\n\t\tfile.delete();\n\t\tassertThat(snapshot1).isNotEqualTo(new FileSnapshot(file));\n\t}\n\n\t@Test\n\tvoid notEqualsIfLengthChanges() throws Exception {\n\t\tFile file = createNewFile(\"abc\", MODIFIED);\n\t\tFileSnapshot snapshot1 = new FileSnapshot(file);\n\t\tsetupFile(file, \"abcd\", MODIFIED);\n\t\tassertThat(snapshot1).isNotEqualTo(new FileSnapshot(file));\n\t}\n\n\t@Test\n\tvoid notEqualsIfLastModifiedChanges() throws Exception {\n\t\tFile file = createNewFile(\"abc\", MODIFIED);\n\t\tFileSnapshot snapshot1 = new FileSnapshot(file);\n\t\tsetupFile(file, \"abc\", MODIFIED + TWO_MINS);\n\t\tassertThat(snapshot1).isNotEqualTo(new FileSnapshot(file));\n\t}\n\n\tprivate File createNewFile(String content, long lastModified) throws IOException {\n\t\tFile file = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tsetupFile(file, content, lastModified);\n\t\treturn file;\n\t}\n\n\tprivate void setupFile(File file, String content, long lastModified) throws IOException {\n\t\tFileCopyUtils.copy(content.getBytes(), file);\n\t\tfile.setLastModified(lastModified);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/filewatch/FileSystemWatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.filewatch;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link FileSystemWatcher}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass FileSystemWatcherTests {\n\n\tprivate FileSystemWatcher watcher;\n\n\tprivate final List<Set<ChangedFiles>> changes = Collections.synchronizedList(new ArrayList<>());\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.watcher = setupWatcher(20, 10);\n\t}\n\n\t@Test\n\tvoid pollIntervalMustBePositive() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new FileSystemWatcher(true, Duration.ofMillis(0), Duration.ofMillis(1)))\n\t\t\t.withMessageContaining(\"'pollInterval' must be positive\");\n\t}\n\n\t@Test\n\tvoid quietPeriodMustBePositive() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new FileSystemWatcher(true, Duration.ofMillis(1), Duration.ofMillis(0)))\n\t\t\t.withMessageContaining(\"'quietPeriod' must be positive\");\n\t}\n\n\t@Test\n\tvoid pollIntervalMustBeGreaterThanQuietPeriod() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new FileSystemWatcher(true, Duration.ofMillis(1), Duration.ofMillis(1)))\n\t\t\t.withMessageContaining(\"'pollInterval' must be greater than QuietPeriod\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid listenerMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addListener(null))\n\t\t\t.withMessageContaining(\"'fileChangeListener' must not be null\");\n\t}\n\n\t@Test\n\tvoid cannotAddListenerToStartedListener() {\n\t\tthis.watcher.start();\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.watcher.addListener(mock(FileChangeListener.class)))\n\t\t\t.withMessageContaining(\"FileSystemWatcher already started\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid sourceDirectoryMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addSourceDirectory(null))\n\t\t\t.withMessageContaining(\"'directory' must not be null\");\n\t}\n\n\t@Test\n\tvoid sourceDirectoryMustNotBeAFile() throws IOException {\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\tassertThat(file.createNewFile()).isTrue();\n\t\tassertThat(file).isFile();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.watcher.addSourceDirectory(file))\n\t\t\t.withMessageContaining(\"'directory' [\" + file + \"] must not be a file\");\n\t}\n\n\t@Test\n\tvoid cannotAddSourceDirectoryToStartedListener() {\n\t\tthis.watcher.start();\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.watcher.addSourceDirectory(this.tempDir))\n\t\t\t.withMessageContaining(\"FileSystemWatcher already started\");\n\t}\n\n\t@Test\n\tvoid addFile() throws Exception {\n\t\tFile directory = startWithNewDirectory();\n\t\tFile file = touch(new File(directory, \"test.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tChangedFile expected = new ChangedFile(directory, file, Type.ADD);\n\t\tassertThat(getAllFileChanges()).containsExactly(expected);\n\t}\n\n\t@Test\n\tvoid addNestedFile() throws Exception {\n\t\tFile directory = startWithNewDirectory();\n\t\tFile file = touch(new File(new File(directory, \"sub\"), \"text.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tChangedFile expected = new ChangedFile(directory, file, Type.ADD);\n\t\tassertThat(getAllFileChanges()).containsExactly(expected);\n\t}\n\n\t@Test\n\tvoid createSourceDirectoryAndAddFile() throws IOException {\n\t\tFile directory = new File(this.tempDir, \"does/not/exist\");\n\t\tassertThat(directory).doesNotExist();\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.start();\n\t\tdirectory.mkdirs();\n\t\tFile file = touch(new File(directory, \"text.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tChangedFile expected = new ChangedFile(directory, file, Type.ADD);\n\t\tassertThat(getAllFileChanges()).containsExactly(expected);\n\t}\n\n\t@Test\n\tvoid waitsForPollingInterval() throws Exception {\n\t\tthis.watcher = setupWatcher(10, 1);\n\t\tFile directory = startWithNewDirectory();\n\t\ttouch(new File(directory, \"test1.txt\"));\n\t\twhile (this.changes.size() != 1) {\n\t\t\tThread.sleep(10);\n\t\t}\n\t\ttouch(new File(directory, \"test2.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tassertThat(this.changes).hasSize(2);\n\t}\n\n\t@Test\n\tvoid waitsForQuietPeriod() throws Exception {\n\t\tthis.watcher = setupWatcher(300, 200);\n\t\tFile directory = startWithNewDirectory();\n\t\tfor (int i = 0; i < 100; i++) {\n\t\t\ttouch(new File(directory, i + \"test.txt\"));\n\t\t\tThread.sleep(10);\n\t\t}\n\t\tthis.watcher.stopAfter(1);\n\t\tassertThat(getAllFileChanges()).hasSize(100);\n\t}\n\n\t@Test\n\tvoid withExistingFiles() throws Exception {\n\t\tFile directory = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory.mkdir();\n\t\ttouch(new File(directory, \"test.txt\"));\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.start();\n\t\tFile file = touch(new File(directory, \"test2.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tChangedFile expected = new ChangedFile(directory, file, Type.ADD);\n\t\tassertThat(getAllFileChanges()).contains(expected);\n\t}\n\n\t@Test\n\tvoid multipleSources() throws Exception {\n\t\tFile directory1 = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory1.mkdir();\n\t\tFile directory2 = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory2.mkdir();\n\t\tthis.watcher.addSourceDirectory(directory1);\n\t\tthis.watcher.addSourceDirectory(directory2);\n\t\tthis.watcher.start();\n\t\tFile file1 = touch(new File(directory1, \"test.txt\"));\n\t\tFile file2 = touch(new File(directory2, \"test.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tSet<ChangedFiles> change = this.changes.stream().flatMap(Set<ChangedFiles>::stream).collect(Collectors.toSet());\n\t\tassertThat(change).hasSize(2);\n\t\tfor (ChangedFiles changedFiles : change) {\n\t\t\tif (changedFiles.getSourceDirectory().equals(directory1)) {\n\t\t\t\tChangedFile file = new ChangedFile(directory1, file1, Type.ADD);\n\t\t\t\tassertThat(changedFiles.getFiles()).containsOnly(file);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tChangedFile file = new ChangedFile(directory2, file2, Type.ADD);\n\t\t\t\tassertThat(changedFiles.getFiles()).containsOnly(file);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid multipleListeners() throws Exception {\n\t\tFile directory = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory.mkdir();\n\t\tfinal List<Set<ChangedFiles>> listener2Changes = new ArrayList<>();\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.addListener(listener2Changes::add);\n\t\tthis.watcher.start();\n\t\tFile file = touch(new File(directory, \"test.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tChangedFile expected = new ChangedFile(directory, file, Type.ADD);\n\t\tSet<ChangedFile> changeSet = getAllFileChanges();\n\t\tassertThat(changeSet).contains(expected);\n\t\tassertThat(getAllFileChanges(listener2Changes)).isEqualTo(changeSet);\n\t}\n\n\t@Test\n\tvoid modifyDeleteAndAdd() throws Exception {\n\t\tFile directory = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory.mkdir();\n\t\tFile modify = touch(new File(directory, \"modify.txt\"));\n\t\tFile delete = touch(new File(directory, \"delete.txt\"));\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.start();\n\t\tFileCopyUtils.copy(\"abc\".getBytes(), modify);\n\t\tdelete.delete();\n\t\tFile add = touch(new File(directory, \"add.txt\"));\n\t\tthis.watcher.stopAfter(1);\n\t\tSet<ChangedFile> actual = getAllFileChanges();\n\t\tSet<ChangedFile> expected = new HashSet<>();\n\t\texpected.add(new ChangedFile(directory, modify, Type.MODIFY));\n\t\texpected.add(new ChangedFile(directory, delete, Type.DELETE));\n\t\texpected.add(new ChangedFile(directory, add, Type.ADD));\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid withTriggerFilter() throws Exception {\n\t\tFile directory = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory.mkdir();\n\t\tFile file = touch(new File(directory, \"file.txt\"));\n\t\tFile trigger = touch(new File(directory, \"trigger.txt\"));\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.setTriggerFilter((candidate) -> candidate.getName().equals(\"trigger.txt\"));\n\t\tthis.watcher.start();\n\t\tFileCopyUtils.copy(\"abc\".getBytes(), file);\n\t\tThread.sleep(100);\n\t\tassertThat(this.changes).isEmpty();\n\t\tFileCopyUtils.copy(\"abc\".getBytes(), trigger);\n\t\tthis.watcher.stopAfter(1);\n\t\tSet<ChangedFile> actual = getAllFileChanges();\n\t\tSet<ChangedFile> expected = new HashSet<>();\n\t\texpected.add(new ChangedFile(directory, file, Type.MODIFY));\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid withSnapshotRepository() throws Exception {\n\t\tSnapshotStateRepository repository = new TestSnapshotStateRepository();\n\t\tthis.watcher = setupWatcher(20, 10, repository);\n\t\tFile directory = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory.mkdir();\n\t\tFile file = touch(new File(directory, \"file.txt\"));\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.start();\n\t\tfile.delete();\n\t\tthis.watcher.stopAfter(1);\n\t\tthis.changes.clear();\n\t\tFile recreate = touch(new File(directory, \"file.txt\"));\n\t\tthis.watcher = setupWatcher(20, 10, repository);\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.start();\n\t\tthis.watcher.stopAfter(1);\n\t\tSet<ChangedFile> actual = getAllFileChanges();\n\t\tSet<ChangedFile> expected = new HashSet<>();\n\t\texpected.add(new ChangedFile(directory, recreate, Type.ADD));\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\tprivate FileSystemWatcher setupWatcher(long pollingInterval, long quietPeriod) {\n\t\treturn setupWatcher(pollingInterval, quietPeriod, null);\n\t}\n\n\tprivate FileSystemWatcher setupWatcher(long pollingInterval, long quietPeriod,\n\t\t\t@Nullable SnapshotStateRepository snapshotStateRepository) {\n\t\tFileSystemWatcher watcher = new FileSystemWatcher(false, Duration.ofMillis(pollingInterval),\n\t\t\t\tDuration.ofMillis(quietPeriod), snapshotStateRepository);\n\t\twatcher.addListener(FileSystemWatcherTests.this.changes::add);\n\t\treturn watcher;\n\t}\n\n\tprivate File startWithNewDirectory() {\n\t\tFile directory = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tdirectory.mkdir();\n\t\tthis.watcher.addSourceDirectory(directory);\n\t\tthis.watcher.start();\n\t\treturn directory;\n\t}\n\n\tprivate Set<ChangedFile> getAllFileChanges() {\n\t\treturn getAllFileChanges(this.changes);\n\t}\n\n\tprivate Set<ChangedFile> getAllFileChanges(List<Set<ChangedFiles>> changes) {\n\t\treturn changes.stream()\n\t\t\t.flatMap(Set<ChangedFiles>::stream)\n\t\t\t.flatMap((changedFiles) -> changedFiles.getFiles().stream())\n\t\t\t.collect(Collectors.toSet());\n\t}\n\n\tprivate File touch(File file) throws IOException {\n\t\tfile.getParentFile().mkdirs();\n\t\tFileOutputStream fileOutputStream = new FileOutputStream(file);\n\t\tfileOutputStream.close();\n\t\treturn file;\n\t}\n\n\tprivate static final class TestSnapshotStateRepository implements SnapshotStateRepository {\n\n\t\tprivate @Nullable Object state;\n\n\t\t@Override\n\t\tpublic void save(Object state) {\n\t\t\tthis.state = state;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object restore() {\n\t\t\treturn this.state;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/ConnectionInputStreamTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link ConnectionInputStream}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"resource\")\nclass ConnectionInputStreamTests {\n\n\tprivate static final byte[] NO_BYTES = {};\n\n\t@Test\n\tvoid readHeader() throws Exception {\n\t\tString header = \"\";\n\t\tfor (int i = 0; i < 100; i++) {\n\t\t\theader += \"x-something-\" + i + \": xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\";\n\t\t}\n\t\tString data = header + \"\\r\\n\\r\\ncontent\\r\\n\";\n\t\tConnectionInputStream inputStream = new ConnectionInputStream(new ByteArrayInputStream(data.getBytes()));\n\t\tassertThat(inputStream.readHeader()).isEqualTo(header);\n\t}\n\n\t@Test\n\tvoid readFully() throws Exception {\n\t\tbyte[] bytes = \"the data that we want to read fully\".getBytes();\n\t\tLimitedInputStream source = new LimitedInputStream(new ByteArrayInputStream(bytes), 2);\n\t\tConnectionInputStream inputStream = new ConnectionInputStream(source);\n\t\tbyte[] buffer = new byte[bytes.length];\n\t\tinputStream.readFully(buffer, 0, buffer.length);\n\t\tassertThat(buffer).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid checkedRead() {\n\t\tConnectionInputStream inputStream = new ConnectionInputStream(new ByteArrayInputStream(NO_BYTES));\n\t\tassertThatIOException().isThrownBy(inputStream::checkedRead).withMessageContaining(\"End of stream\");\n\t}\n\n\t@Test\n\tvoid checkedReadArray() {\n\t\tbyte[] buffer = new byte[100];\n\t\tConnectionInputStream inputStream = new ConnectionInputStream(new ByteArrayInputStream(NO_BYTES));\n\t\tassertThatIOException().isThrownBy(() -> inputStream.checkedRead(buffer, 0, buffer.length))\n\t\t\t.withMessageContaining(\"End of stream\");\n\t}\n\n\tstatic class LimitedInputStream extends FilterInputStream {\n\n\t\tprivate final int max;\n\n\t\tprotected LimitedInputStream(InputStream in, int max) {\n\t\t\tsuper(in);\n\t\t\tthis.max = max;\n\t\t}\n\n\t\t@Override\n\t\tpublic int read(byte[] b, int off, int len) throws IOException {\n\t\t\treturn super.read(b, off, Math.min(len, this.max));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/ConnectionOutputStreamTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.OutputStream;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionOutputStream}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"resource\")\nclass ConnectionOutputStreamTests {\n\n\t@Test\n\tvoid write() throws Exception {\n\t\tOutputStream out = mock(OutputStream.class);\n\t\tConnectionOutputStream outputStream = new ConnectionOutputStream(out);\n\t\tbyte[] b = new byte[100];\n\t\toutputStream.write(b, 1, 2);\n\t\tthen(out).should().write(b, 1, 2);\n\t}\n\n\t@Test\n\tvoid writeHttp() throws Exception {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tConnectionOutputStream outputStream = new ConnectionOutputStream(out);\n\t\toutputStream.writeHttp(new ByteArrayInputStream(\"hi\".getBytes()), \"x-type\");\n\t\tString expected = \"\";\n\t\texpected += \"HTTP/1.1 200 OK\\r\\n\";\n\t\texpected += \"Content-Type: x-type\\r\\n\";\n\t\texpected += \"Content-Length: 2\\r\\n\";\n\t\texpected += \"Connection: close\\r\\n\\r\\n\";\n\t\texpected += \"hi\";\n\t\tassertThat(out).hasToString(expected);\n\t}\n\n\t@Test\n\tvoid writeHeaders() throws Exception {\n\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\tConnectionOutputStream outputStream = new ConnectionOutputStream(out);\n\t\toutputStream.writeHeaders(\"A: a\", \"B: b\");\n\t\toutputStream.flush();\n\t\tString expected = \"\";\n\t\texpected += \"A: a\\r\\n\";\n\t\texpected += \"B: b\\r\\n\\r\\n\";\n\t\tassertThat(out).hasToString(expected);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/FrameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Frame}.\n *\n * @author Phillip Webb\n */\nclass FrameTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid payloadMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Frame((String) null))\n\t\t\t.withMessageContaining(\"'payload' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid typeMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Frame((Frame.Type) null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid textPayload() {\n\t\tFrame frame = new Frame(\"abc\");\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.TEXT);\n\t\tassertThat(frame.getPayload()).isEqualTo(\"abc\".getBytes());\n\t}\n\n\t@Test\n\tvoid typedPayload() {\n\t\tFrame frame = new Frame(Frame.Type.CLOSE);\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.CLOSE);\n\t\tassertThat(frame.getPayload()).isEqualTo(new byte[] {});\n\t}\n\n\t@Test\n\tvoid writeSmallPayload() throws Exception {\n\t\tString payload = createString(1);\n\t\tFrame frame = new Frame(payload);\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\tframe.write(bos);\n\t\tassertThat(bos.toByteArray()).isEqualTo(new byte[] { (byte) 0x81, 0x01, 0x41 });\n\t}\n\n\t@Test\n\tvoid writeLargePayload() throws Exception {\n\t\tString payload = createString(126);\n\t\tFrame frame = new Frame(payload);\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\tframe.write(bos);\n\t\tbyte[] bytes = bos.toByteArray();\n\t\tassertThat(bytes).hasSize(130);\n\t\tassertThat(bytes[0]).isEqualTo((byte) 0x81);\n\t\tassertThat(bytes[1]).isEqualTo((byte) 0x7E);\n\t\tassertThat(bytes[2]).isEqualTo((byte) 0x00);\n\t\tassertThat(bytes[3]).isEqualTo((byte) 126);\n\t\tassertThat(bytes[4]).isEqualTo((byte) 0x41);\n\t\tassertThat(bytes[5]).isEqualTo((byte) 0x41);\n\t}\n\n\t@Test\n\tvoid readFragmentedNotSupported() {\n\t\tbyte[] bytes = new byte[] { 0x0F };\n\t\tassertThatIllegalStateException().isThrownBy(() -> Frame.read(newConnectionInputStream(bytes)))\n\t\t\t.withMessageContaining(\"Fragmented frames are not supported\");\n\t}\n\n\t@Test\n\tvoid readLargeFramesNotSupported() {\n\t\tbyte[] bytes = new byte[] { (byte) 0x80, (byte) 0xFF };\n\t\tassertThatIllegalStateException().isThrownBy(() -> Frame.read(newConnectionInputStream(bytes)))\n\t\t\t.withMessageContaining(\"Large frames are not supported\");\n\t}\n\n\t@Test\n\tvoid readSmallTextFrame() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x81, (byte) 0x02, 0x41, 0x41 };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.TEXT);\n\t\tassertThat(frame.getPayload()).isEqualTo(new byte[] { 0x41, 0x41 });\n\t}\n\n\t@Test\n\tvoid readMaskedTextFrame() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x81, (byte) 0x82, 0x0F, 0x0F, 0x0F, 0x0F, 0x4E, 0x4E };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.TEXT);\n\t\tassertThat(frame.getPayload()).isEqualTo(new byte[] { 0x41, 0x41 });\n\t}\n\n\t@Test\n\tvoid readLargeTextFrame() throws Exception {\n\t\tbyte[] bytes = new byte[134];\n\t\tArrays.fill(bytes, (byte) 0x4E);\n\t\tbytes[0] = (byte) 0x81;\n\t\tbytes[1] = (byte) 0xFE;\n\t\tbytes[2] = 0x00;\n\t\tbytes[3] = 126;\n\t\tbytes[4] = 0x0F;\n\t\tbytes[5] = 0x0F;\n\t\tbytes[6] = 0x0F;\n\t\tbytes[7] = 0x0F;\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.TEXT);\n\t\tassertThat(frame.getPayload()).isEqualTo(createString(126).getBytes());\n\t}\n\n\t@Test\n\tvoid readContinuation() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x80, (byte) 0x00 };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.CONTINUATION);\n\t}\n\n\t@Test\n\tvoid readBinary() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x82, (byte) 0x00 };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.BINARY);\n\t}\n\n\t@Test\n\tvoid readClose() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x88, (byte) 0x00 };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.CLOSE);\n\t}\n\n\t@Test\n\tvoid readPing() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x89, (byte) 0x00 };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.PING);\n\t}\n\n\t@Test\n\tvoid readPong() throws Exception {\n\t\tbyte[] bytes = new byte[] { (byte) 0x8A, (byte) 0x00 };\n\t\tFrame frame = Frame.read(newConnectionInputStream(bytes));\n\t\tassertThat(frame.getType()).isEqualTo(Frame.Type.PONG);\n\t}\n\n\tprivate ConnectionInputStream newConnectionInputStream(byte[] bytes) {\n\t\treturn new ConnectionInputStream(new ByteArrayInputStream(bytes));\n\t}\n\n\tprivate String createString(int length) {\n\t\tchar[] chars = new char[length];\n\t\tArrays.fill(chars, 'A');\n\t\treturn new String(chars);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/livereload/LiveReloadServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.livereload;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.URI;\nimport java.net.UnknownHostException;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport jakarta.websocket.ClientEndpointConfig;\nimport jakarta.websocket.ClientEndpointConfig.Configurator;\nimport jakarta.websocket.Endpoint;\nimport jakarta.websocket.Extension;\nimport jakarta.websocket.HandshakeResponse;\nimport jakarta.websocket.WebSocketContainer;\nimport org.apache.tomcat.websocket.WsWebSocketContainer;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.PingMessage;\nimport org.springframework.web.socket.PongMessage;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketExtension;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.WebSocketMessage;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter;\nimport org.springframework.web.socket.adapter.standard.StandardWebSocketSession;\nimport org.springframework.web.socket.adapter.standard.WebSocketToStandardExtensionAdapter;\nimport org.springframework.web.socket.client.WebSocketClient;\nimport org.springframework.web.socket.client.standard.StandardWebSocketClient;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.awaitility.Awaitility.await;\nimport static org.hamcrest.Matchers.empty;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\n\n/**\n * Tests for {@link LiveReloadServer}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@SuppressWarnings(\"removal\")\nclass LiveReloadServerTests {\n\n\tprivate static final String HANDSHAKE = \"{command: 'hello', \"\n\t\t\t+ \"protocols: ['http://livereload.com/protocols/official-7']}\";\n\n\tprivate int port;\n\n\tprivate MonitoredLiveReloadServer server;\n\n\t@BeforeEach\n\tvoid setUp() throws Exception {\n\t\tthis.server = new MonitoredLiveReloadServer(0);\n\t\tthis.port = this.server.start();\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws Exception {\n\t\tthis.server.stop();\n\t}\n\n\t@Test\n\t@Disabled\n\tvoid servesLivereloadJs() throws Exception {\n\t\tRestTemplate template = new RestTemplate();\n\t\tURI uri = new URI(\"http://localhost:\" + this.port + \"/livereload.js\");\n\t\tString script = template.getForObject(uri, String.class);\n\t\tassertThat(script).contains(\"livereload.com/protocols/official-7\");\n\t}\n\n\t@Test\n\tvoid triggerReload() throws Exception {\n\t\tLiveReloadWebSocketHandler handler = connect();\n\t\tthis.server.triggerReload();\n\t\tList<String> messages = await().atMost(Duration.ofSeconds(10))\n\t\t\t.until(handler::getMessages, (msgs) -> msgs.size() == 2);\n\t\tassertThat(messages.get(0)).contains(\"http://livereload.com/protocols/official-7\");\n\t\tassertThat(messages.get(1)).contains(\"command\\\":\\\"reload\\\"\");\n\t}\n\n\t@Test // gh-26813\n\tvoid triggerReloadWithUppercaseHeaders() throws Exception {\n\t\tLiveReloadWebSocketHandler handler = connect(UppercaseWebSocketClient::new);\n\t\tthis.server.triggerReload();\n\t\tList<String> messages = await().atMost(Duration.ofSeconds(10))\n\t\t\t.until(handler::getMessages, (msgs) -> msgs.size() == 2);\n\t\tassertThat(messages.get(0)).contains(\"http://livereload.com/protocols/official-7\");\n\t\tassertThat(messages.get(1)).contains(\"command\\\":\\\"reload\\\"\");\n\t}\n\n\t@Test\n\tvoid pingPong() throws Exception {\n\t\tLiveReloadWebSocketHandler handler = connect();\n\t\thandler.sendMessage(new PingMessage());\n\t\tawait().atMost(Duration.ofSeconds(10)).until(handler::getPongCount, is(1));\n\t}\n\n\t@Test\n\tvoid clientClose() throws Exception {\n\t\tLiveReloadWebSocketHandler handler = connect();\n\t\thandler.close();\n\t\tawaitClosedException();\n\t\tassertThat(this.server.getClosedExceptions()).isNotEmpty();\n\t}\n\n\tprivate void awaitClosedException() {\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(10)).until(this.server::getClosedExceptions, is(not(empty())));\n\t}\n\n\t@Test\n\tvoid serverClose() throws Exception {\n\t\tLiveReloadWebSocketHandler handler = connect();\n\t\tthis.server.stop();\n\t\tCloseStatus closeStatus = await().atMost(Duration.ofSeconds(10))\n\t\t\t.until(handler::getCloseStatus, Objects::nonNull);\n\t\tassertThat(closeStatus.getCode()).isEqualTo(1006);\n\t}\n\n\tprivate LiveReloadWebSocketHandler connect() throws Exception {\n\t\treturn connect(StandardWebSocketClient::new);\n\t}\n\n\tprivate LiveReloadWebSocketHandler connect(Function<WebSocketContainer, WebSocketClient> clientFactory)\n\t\t\tthrows Exception {\n\t\tWsWebSocketContainer webSocketContainer = new WsWebSocketContainer();\n\t\tWebSocketClient client = clientFactory.apply(webSocketContainer);\n\t\tLiveReloadWebSocketHandler handler = new LiveReloadWebSocketHandler();\n\t\tclient.execute(handler, \"ws://localhost:\" + this.port + \"/livereload\");\n\t\thandler.awaitHello();\n\t\treturn handler;\n\t}\n\n\t/**\n\t * {@link LiveReloadServer} with additional monitoring.\n\t */\n\tstatic class MonitoredLiveReloadServer extends LiveReloadServer {\n\n\t\tprivate final List<ConnectionClosedException> closedExceptions = new ArrayList<>();\n\n\t\tprivate final Object monitor = new Object();\n\n\t\tMonitoredLiveReloadServer(int port) {\n\t\t\tsuper(port);\n\t\t}\n\n\t\t@Override\n\t\tprotected Connection createConnection(java.net.Socket socket, InputStream inputStream,\n\t\t\t\tOutputStream outputStream) throws IOException {\n\t\t\treturn new MonitoredConnection(socket, inputStream, outputStream);\n\t\t}\n\n\t\tList<ConnectionClosedException> getClosedExceptions() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\treturn new ArrayList<>(this.closedExceptions);\n\t\t\t}\n\t\t}\n\n\t\tprivate class MonitoredConnection extends Connection {\n\n\t\t\tMonitoredConnection(java.net.Socket socket, InputStream inputStream, OutputStream outputStream)\n\t\t\t\t\tthrows IOException {\n\t\t\t\tsuper(socket, inputStream, outputStream);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void run() throws Exception {\n\t\t\t\ttry {\n\t\t\t\t\tsuper.run();\n\t\t\t\t}\n\t\t\t\tcatch (ConnectionClosedException ex) {\n\t\t\t\t\tsynchronized (MonitoredLiveReloadServer.this.monitor) {\n\t\t\t\t\t\tMonitoredLiveReloadServer.this.closedExceptions.add(ex);\n\t\t\t\t\t}\n\t\t\t\t\tthrow ex;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tclass LiveReloadWebSocketHandler extends TextWebSocketHandler {\n\n\t\tprivate volatile @Nullable WebSocketSession session;\n\n\t\tprivate final CountDownLatch helloLatch = new CountDownLatch(2);\n\n\t\tprivate final List<String> messages = new CopyOnWriteArrayList<>();\n\n\t\tprivate final AtomicInteger pongCount = new AtomicInteger();\n\n\t\tprivate volatile @Nullable CloseStatus closeStatus;\n\n\t\t@Override\n\t\tpublic void afterConnectionEstablished(WebSocketSession session) throws Exception {\n\t\t\tthis.session = session;\n\t\t\tsession.sendMessage(new TextMessage(HANDSHAKE));\n\t\t\tthis.helloLatch.countDown();\n\t\t}\n\n\t\tvoid awaitHello() throws InterruptedException {\n\t\t\tthis.helloLatch.await(1, TimeUnit.MINUTES);\n\t\t}\n\n\t\t@Override\n\t\tprotected void handleTextMessage(WebSocketSession session, TextMessage message) {\n\t\t\tString payload = message.getPayload();\n\t\t\tthis.messages.add(payload);\n\t\t\tif (payload.contains(\"hello\")) {\n\t\t\t\tthis.helloLatch.countDown();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected void handlePongMessage(WebSocketSession session, PongMessage message) {\n\t\t\tthis.pongCount.incrementAndGet();\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {\n\t\t\tthis.closeStatus = status;\n\t\t}\n\n\t\tvoid sendMessage(WebSocketMessage<?> message) throws IOException {\n\t\t\tWebSocketSession session = this.session;\n\t\t\tassertThat(session).isNotNull();\n\t\t\tsession.sendMessage(message);\n\t\t}\n\n\t\tvoid close() throws IOException {\n\t\t\tWebSocketSession session = this.session;\n\t\t\tassertThat(session).isNotNull();\n\t\t\tsession.close();\n\t\t}\n\n\t\tList<String> getMessages() {\n\t\t\treturn this.messages;\n\t\t}\n\n\t\tint getPongCount() {\n\t\t\treturn this.pongCount.get();\n\t\t}\n\n\t\t@Nullable CloseStatus getCloseStatus() {\n\t\t\treturn this.closeStatus;\n\t\t}\n\n\t}\n\n\tstatic class UppercaseWebSocketClient extends StandardWebSocketClient {\n\n\t\tprivate final WebSocketContainer webSocketContainer;\n\n\t\tUppercaseWebSocketClient(WebSocketContainer webSocketContainer) {\n\t\t\tsuper(webSocketContainer);\n\t\t\tthis.webSocketContainer = webSocketContainer;\n\t\t}\n\n\t\t@Override\n\t\tprotected CompletableFuture<WebSocketSession> executeInternal(WebSocketHandler webSocketHandler,\n\t\t\t\tHttpHeaders headers, URI uri, List<String> protocols, List<WebSocketExtension> extensions,\n\t\t\t\tMap<String, Object> attributes) {\n\t\t\tInetSocketAddress localAddress = new InetSocketAddress(getLocalHost(), uri.getPort());\n\t\t\tInetSocketAddress remoteAddress = new InetSocketAddress(uri.getHost(), uri.getPort());\n\t\t\tStandardWebSocketSession session = new StandardWebSocketSession(headers, attributes, localAddress,\n\t\t\t\t\tremoteAddress);\n\t\t\tStream<Extension> adaptedExtensions = extensions.stream().map(WebSocketToStandardExtensionAdapter::new);\n\t\t\tClientEndpointConfig endpointConfig = ClientEndpointConfig.Builder.create()\n\t\t\t\t.configurator(new UppercaseWebSocketClientConfigurator(headers))\n\t\t\t\t.preferredSubprotocols(protocols)\n\t\t\t\t.extensions(adaptedExtensions.toList())\n\t\t\t\t.build();\n\t\t\tendpointConfig.getUserProperties().putAll(getUserProperties());\n\t\t\tEndpoint endpoint = new StandardWebSocketHandlerAdapter(webSocketHandler, session);\n\t\t\tCallable<WebSocketSession> connectTask = () -> {\n\t\t\t\tthis.webSocketContainer.connectToServer(endpoint, endpointConfig, uri);\n\t\t\t\treturn session;\n\t\t\t};\n\t\t\tAsyncTaskExecutor taskExecutor = getTaskExecutor();\n\t\t\tassertThat(taskExecutor).isNotNull();\n\t\t\treturn taskExecutor.submitCompletable(connectTask);\n\t\t}\n\n\t\tprivate InetAddress getLocalHost() {\n\t\t\ttry {\n\t\t\t\treturn InetAddress.getLocalHost();\n\t\t\t}\n\t\t\tcatch (UnknownHostException ex) {\n\t\t\t\treturn InetAddress.getLoopbackAddress();\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static class UppercaseWebSocketClientConfigurator extends Configurator {\n\n\t\tprivate final HttpHeaders headers;\n\n\t\tUppercaseWebSocketClientConfigurator(HttpHeaders headers) {\n\t\t\tthis.headers = headers;\n\t\t}\n\n\t\t@Override\n\t\tpublic void beforeRequest(Map<String, List<String>> requestHeaders) {\n\t\t\tMap<String, List<String>> uppercaseRequestHeaders = new LinkedHashMap<>();\n\t\t\trequestHeaders.forEach((key, value) -> uppercaseRequestHeaders.put(key.toUpperCase(Locale.ROOT), value));\n\t\t\trequestHeaders.clear();\n\t\t\trequestHeaders.putAll(uppercaseRequestHeaders);\n\t\t\tthis.headers.forEach(requestHeaders::put);\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterResponse(HandshakeResponse response) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/ClassPathChangeUploaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.ObjectInputStream;\nimport java.net.SocketException;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.classpath.ClassPathChangedEvent;\nimport org.springframework.boot.devtools.filewatch.ChangedFile;\nimport org.springframework.boot.devtools.filewatch.ChangedFile.Type;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;\nimport org.springframework.boot.devtools.test.MockClientHttpRequestFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.http.client.MockClientHttpRequest;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ClassPathChangeUploader}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ClassPathChangeUploaderTests {\n\n\tprivate MockClientHttpRequestFactory requestFactory;\n\n\tprivate ClassPathChangeUploader uploader;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.requestFactory = new MockClientHttpRequestFactory();\n\t\tthis.uploader = new ClassPathChangeUploader(\"http://localhost/upload\", this.requestFactory);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid urlMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangeUploader(null, this.requestFactory))\n\t\t\t.withMessageContaining(\"'url' must not be empty\");\n\t}\n\n\t@Test\n\tvoid urlMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassPathChangeUploader(\"\", this.requestFactory))\n\t\t\t.withMessageContaining(\"'url' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid requestFactoryMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ClassPathChangeUploader(\"http://localhost:8080\", null))\n\t\t\t.withMessageContaining(\"'requestFactory' must not be null\");\n\t}\n\n\t@Test\n\tvoid urlMustNotBeMalformed() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new ClassPathChangeUploader(\"htttttp:///ttest\", this.requestFactory))\n\t\t\t.withMessageContaining(\"Malformed URL 'htttttp:///ttest'\");\n\t}\n\n\t@Test\n\tvoid sendsClassLoaderFiles(@TempDir File sourceDirectory) throws Exception {\n\t\tClassPathChangedEvent event = createClassPathChangedEvent(sourceDirectory);\n\t\tthis.requestFactory.willRespond(HttpStatus.OK);\n\t\tthis.uploader.onApplicationEvent(event);\n\t\tassertThat(this.requestFactory.getExecutedRequests()).hasSize(1);\n\t\tMockClientHttpRequest request = this.requestFactory.getExecutedRequests().get(0);\n\t\tverifyUploadRequest(sourceDirectory, request);\n\t}\n\n\t@Test\n\tvoid retriesOnSocketException(@TempDir File sourceDirectory) throws Exception {\n\t\tClassPathChangedEvent event = createClassPathChangedEvent(sourceDirectory);\n\t\tthis.requestFactory.willRespond(new SocketException());\n\t\tthis.requestFactory.willRespond(HttpStatus.OK);\n\t\tthis.uploader.onApplicationEvent(event);\n\t\tassertThat(this.requestFactory.getExecutedRequests()).hasSize(2);\n\t\tverifyUploadRequest(sourceDirectory, this.requestFactory.getExecutedRequests().get(1));\n\t}\n\n\tprivate void verifyUploadRequest(File sourceDirectory, MockClientHttpRequest request)\n\t\t\tthrows IOException, ClassNotFoundException {\n\t\tClassLoaderFiles classLoaderFiles = deserialize(request.getBodyAsBytes());\n\t\tCollection<SourceDirectory> sourceDirectories = classLoaderFiles.getSourceDirectories();\n\t\tassertThat(sourceDirectories).hasSize(1);\n\t\tSourceDirectory classSourceDirectory = sourceDirectories.iterator().next();\n\t\tassertThat(classSourceDirectory.getName()).isEqualTo(sourceDirectory.getAbsolutePath());\n\t\tIterator<ClassLoaderFile> classFiles = classSourceDirectory.getFiles().iterator();\n\t\tassertClassFile(classFiles.next(), \"File1\", ClassLoaderFile.Kind.ADDED);\n\t\tassertClassFile(classFiles.next(), \"File2\", ClassLoaderFile.Kind.MODIFIED);\n\t\tassertClassFile(classFiles.next(), null, ClassLoaderFile.Kind.DELETED);\n\t\tassertThat(classFiles.hasNext()).isFalse();\n\t}\n\n\tprivate void assertClassFile(ClassLoaderFile file, @Nullable String content, Kind kind) {\n\t\tassertThat(file.getContents()).isEqualTo((content != null) ? content.getBytes() : null);\n\t\tassertThat(file.getKind()).isEqualTo(kind);\n\t}\n\n\tprivate ClassPathChangedEvent createClassPathChangedEvent(File sourceDirectory) throws IOException {\n\t\tSet<ChangedFile> files = new LinkedHashSet<>();\n\t\tFile file1 = createFile(sourceDirectory, \"File1\");\n\t\tFile file2 = createFile(sourceDirectory, \"File2\");\n\t\tFile file3 = createFile(sourceDirectory, \"File3\");\n\t\tfiles.add(new ChangedFile(sourceDirectory, file1, Type.ADD));\n\t\tfiles.add(new ChangedFile(sourceDirectory, file2, Type.MODIFY));\n\t\tfiles.add(new ChangedFile(sourceDirectory, file3, Type.DELETE));\n\t\tSet<ChangedFiles> changeSet = new LinkedHashSet<>();\n\t\tchangeSet.add(new ChangedFiles(sourceDirectory, files));\n\t\treturn new ClassPathChangedEvent(this, changeSet, false);\n\t}\n\n\tprivate File createFile(File sourceDirectory, String name) throws IOException {\n\t\tFile file = new File(sourceDirectory, name);\n\t\tFileCopyUtils.copy(name.getBytes(), file);\n\t\treturn file;\n\t}\n\n\tprivate ClassLoaderFiles deserialize(byte[] bytes) throws IOException, ClassNotFoundException {\n\t\tObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));\n\t\treturn (ClassLoaderFiles) objectInputStream.readObject();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/DelayedLiveReloadTriggerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.IOException;\nimport java.net.URI;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link DelayedLiveReloadTrigger}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\n@SuppressWarnings(\"removal\")\nclass DelayedLiveReloadTriggerTests {\n\n\tprivate static final String URL = \"http://localhost:8080\";\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate OptionalLiveReloadServer liveReloadServer;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequestFactory requestFactory;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequest errorRequest;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequest okRequest;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpResponse errorResponse;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpResponse okResponse;\n\n\tprivate DelayedLiveReloadTrigger trigger;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.trigger = new DelayedLiveReloadTrigger(this.liveReloadServer, this.requestFactory, URL);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid liveReloadServerMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DelayedLiveReloadTrigger(null, this.requestFactory, URL))\n\t\t\t.withMessageContaining(\"'liveReloadServer' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid requestFactoryMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, null, URL))\n\t\t\t.withMessageContaining(\"'requestFactory' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid urlMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, this.requestFactory, null))\n\t\t\t.withMessageContaining(\"'url' must not be empty\");\n\t}\n\n\t@Test\n\tvoid urlMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DelayedLiveReloadTrigger(this.liveReloadServer, this.requestFactory, \"\"))\n\t\t\t.withMessageContaining(\"'url' must not be empty\");\n\t}\n\n\t@Test\n\tvoid triggerReloadOnStatus() throws Exception {\n\t\tgiven(this.errorRequest.execute()).willReturn(this.errorResponse);\n\t\tgiven(this.okRequest.execute()).willReturn(this.okResponse);\n\t\tgiven(this.errorResponse.getStatusCode()).willReturn(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tgiven(this.okResponse.getStatusCode()).willReturn(HttpStatus.OK);\n\t\tgiven(this.requestFactory.createRequest(new URI(URL), HttpMethod.GET)).willThrow(new IOException())\n\t\t\t.willReturn(this.errorRequest, this.okRequest);\n\t\tlong startTime = System.currentTimeMillis();\n\t\tthis.trigger.setTimings(10, 200, 30000);\n\t\tthis.trigger.run();\n\t\tassertThat(System.currentTimeMillis() - startTime).isGreaterThan(300L);\n\t\tthen(this.liveReloadServer).should().triggerReload();\n\t}\n\n\t@Test\n\tvoid timeout() throws Exception {\n\t\tgiven(this.requestFactory.createRequest(new URI(URL), HttpMethod.GET)).willThrow(new IOException());\n\t\tthis.trigger.setTimings(10, 0, 10);\n\t\tthis.trigger.run();\n\t\tthen(this.liveReloadServer).should(never()).triggerReload();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/HttpHeaderInterceptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.http.HttpRequest;\nimport org.springframework.http.client.ClientHttpRequestExecution;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.mock.web.MockHttpServletRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link HttpHeaderInterceptor}.\n *\n * @author Rob Winch\n * @since 1.3.0\n */\n@ExtendWith(MockitoExtension.class)\nclass HttpHeaderInterceptorTests {\n\n\tprivate String name;\n\n\tprivate String value;\n\n\tprivate HttpHeaderInterceptor interceptor;\n\n\tprivate HttpRequest request;\n\n\tprivate byte[] body;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequestExecution execution;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpResponse response;\n\n\tprivate MockHttpServletRequest httpRequest;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.body = new byte[] {};\n\t\tthis.httpRequest = new MockHttpServletRequest();\n\t\tthis.request = new ServletServerHttpRequest(this.httpRequest);\n\t\tthis.name = \"X-AUTH-TOKEN\";\n\t\tthis.value = \"secret\";\n\t\tthis.interceptor = new HttpHeaderInterceptor(this.name, this.value);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid constructorNullHeaderName() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(null, this.value))\n\t\t\t.withMessageContaining(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\tvoid constructorEmptyHeaderName() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(\"\", this.value))\n\t\t\t.withMessageContaining(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid constructorNullHeaderValue() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(this.name, null))\n\t\t\t.withMessageContaining(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid constructorEmptyHeaderValue() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderInterceptor(this.name, \"\"))\n\t\t\t.withMessageContaining(\"'value' must not be empty\");\n\t}\n\n\t@Test\n\tvoid intercept() throws IOException {\n\t\tgiven(this.execution.execute(this.request, this.body)).willReturn(this.response);\n\t\tClientHttpResponse result = this.interceptor.intercept(this.request, this.body, this.execution);\n\t\tassertThat(this.request.getHeaders().getFirst(this.name)).isEqualTo(this.value);\n\t\tassertThat(result).isEqualTo(this.response);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/client/RemoteClientConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.client;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer;\nimport org.springframework.boot.devtools.classpath.ClassPathChangedEvent;\nimport org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;\nimport org.springframework.boot.devtools.filewatch.ChangedFiles;\nimport org.springframework.boot.devtools.livereload.LiveReloadServer;\nimport org.springframework.boot.devtools.remote.server.Dispatcher;\nimport org.springframework.boot.devtools.remote.server.DispatcherFilter;\nimport org.springframework.boot.devtools.restart.MockRestarter;\nimport org.springframework.boot.devtools.restart.RestartScopeInitializer;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RemoteClientConfiguration}.\n *\n * @author Phillip Webb\n */\n@ExtendWith({ OutputCaptureExtension.class, MockRestarter.class })\nclass RemoteClientConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebServerApplicationContext context;\n\n\tprivate @Nullable AnnotationConfigApplicationContext clientContext;\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tif (this.clientContext != null) {\n\t\t\tthis.clientContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid warnIfRestartDisabled(CapturedOutput output) {\n\t\tconfigure(\"spring.devtools.remote.restart.enabled:false\");\n\t\tassertThat(output).contains(\"Remote restart is disabled\");\n\t}\n\n\t@Test\n\tvoid warnIfNotHttps(CapturedOutput output) {\n\t\tconfigure(\"http://localhost\", true);\n\t\tassertThat(output).contains(\"is insecure\");\n\t}\n\n\t@Test\n\tvoid doesntWarnIfUsingHttps(CapturedOutput output) {\n\t\tconfigure(\"https://localhost\", true);\n\t\tassertThat(output).doesNotContain(\"is insecure\");\n\t}\n\n\t@Test\n\tvoid failIfNoSecret() {\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> configure(\"http://localhost\", false))\n\t\t\t.withMessageContaining(\"required to secure your connection\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid liveReloadOnClassPathChanged() {\n\t\tconfigure(\"spring.devtools.livereload.enabled:true\");\n\t\tSet<ChangedFiles> changeSet = new HashSet<>();\n\t\tClassPathChangedEvent event = new ClassPathChangedEvent(this, changeSet, false);\n\t\tassertThat(this.clientContext).isNotNull();\n\t\tthis.clientContext.publishEvent(event);\n\t\tLiveReloadServer server = this.clientContext.getBean(LiveReloadServer.class);\n\t\tAwaitility.await().atMost(Duration.ofMinutes(1)).untilAsserted(() -> then(server).should().triggerReload());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid liveReloadDisabledByDefault() {\n\t\tconfigure();\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> getContext().getBean(OptionalLiveReloadServer.class));\n\t}\n\n\t@Test\n\tvoid remoteRestartDisabled() {\n\t\tconfigure(\"spring.devtools.remote.restart.enabled:false\");\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> getContext().getBean(ClassPathFileSystemWatcher.class));\n\t}\n\n\tprivate void configure(String... pairs) {\n\t\tconfigure(\"http://localhost\", true, pairs);\n\t}\n\n\tprivate AnnotationConfigServletWebServerApplicationContext getContext() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\tprivate void configure(String remoteUrl, boolean setSecret, String... pairs) {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.register(Config.class);\n\t\tif (setSecret) {\n\t\t\tTestPropertyValues.of(\"spring.devtools.remote.secret:secret\").applyTo(this.context);\n\t\t}\n\t\tthis.context.refresh();\n\t\tthis.clientContext = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(pairs).applyTo(this.clientContext);\n\t\tnew RestartScopeInitializer().initialize(this.clientContext);\n\t\tthis.clientContext.register(ClientConfig.class, RemoteClientConfiguration.class);\n\t\tif (setSecret) {\n\t\t\tTestPropertyValues.of(\"spring.devtools.remote.secret:secret\").applyTo(this.clientContext);\n\t\t}\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tString remoteUrlProperty = \"remoteUrl:\" + remoteUrl + \":\" + webServer.getPort();\n\t\tTestPropertyValues.of(remoteUrlProperty).applyTo(this.clientContext);\n\t\tthis.clientContext.refresh();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\t\twebServerFactory.setRegisterDefaultServlet(true);\n\t\t\treturn webServerFactory;\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherFilter dispatcherFilter() throws IOException {\n\t\t\treturn new DispatcherFilter(dispatcher());\n\t\t}\n\n\t\tDispatcher dispatcher() throws IOException {\n\t\t\tDispatcher dispatcher = mock(Dispatcher.class);\n\t\t\tServerHttpRequest anyRequest = any(ServerHttpRequest.class);\n\t\t\tServerHttpResponse anyResponse = any(ServerHttpResponse.class);\n\t\t\tgiven(dispatcher.handle(anyRequest, anyResponse)).willReturn(true);\n\t\t\treturn dispatcher;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@SuppressWarnings(\"removal\")\n\tstatic class ClientConfig {\n\n\t\t@Bean\n\t\tLiveReloadServer liveReloadServer() {\n\t\t\treturn mock(LiveReloadServer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpResponse;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willReturn;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DispatcherFilter}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass DispatcherFilterTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Dispatcher dispatcher;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate FilterChain chain;\n\n\tprivate DispatcherFilter filter;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.filter = new DispatcherFilter(this.dispatcher);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid dispatcherMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DispatcherFilter(null))\n\t\t\t.withMessageContaining(\"'dispatcher' must not be null\");\n\t}\n\n\t@Test\n\tvoid ignoresNotServletRequests() throws Exception {\n\t\tServletRequest request = mock(ServletRequest.class);\n\t\tServletResponse response = mock(ServletResponse.class);\n\t\tthis.filter.doFilter(request, response, this.chain);\n\t\tthen(this.dispatcher).shouldHaveNoInteractions();\n\t\tthen(this.chain).should().doFilter(request, response);\n\t}\n\n\t@Test\n\tvoid ignoredByDispatcher() throws Exception {\n\t\tHttpServletRequest request = new MockHttpServletRequest(\"GET\", \"/hello\");\n\t\tHttpServletResponse response = new MockHttpServletResponse();\n\t\tthis.filter.doFilter(request, response, this.chain);\n\t\tthen(this.chain).should().doFilter(request, response);\n\t}\n\n\t@Test\n\tvoid handledByDispatcher() throws Exception {\n\t\tHttpServletRequest request = new MockHttpServletRequest(\"GET\", \"/hello\");\n\t\tHttpServletResponse response = new MockHttpServletResponse();\n\t\twillReturn(true).given(this.dispatcher).handle(any(ServerHttpRequest.class), any(ServerHttpResponse.class));\n\t\tthis.filter.doFilter(request, response, this.chain);\n\t\tthen(this.chain).shouldHaveNoInteractions();\n\t\tthen(this.dispatcher).should()\n\t\t\t.handle(assertArg((serverHttpRequest) -> assertThat(serverHttpRequest).isInstanceOfSatisfying(\n\t\t\t\t\tServletServerHttpRequest.class,\n\t\t\t\t\t(servletServerHttpRequest) -> assertThat(servletServerHttpRequest.getServletRequest())\n\t\t\t\t\t\t.isEqualTo(request))),\n\t\t\t\t\tassertArg((serverHttpResponse) -> assertThat(serverHttpResponse).isInstanceOfSatisfying(\n\t\t\t\t\t\t\tServletServerHttpResponse.class,\n\t\t\t\t\t\t\t(servletServerHttpResponse) -> assertThat(servletServerHttpResponse.getServletResponse())\n\t\t\t\t\t\t\t\t.isEqualTo(response))));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/DispatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.InOrder;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpResponse;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link Dispatcher}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass DispatcherTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate AccessManager accessManager;\n\n\tprivate final MockHttpServletResponse response = new MockHttpServletResponse();\n\n\tprivate final ServerHttpRequest serverRequest = new ServletServerHttpRequest(new MockHttpServletRequest());\n\n\tprivate final ServerHttpResponse serverResponse = new ServletServerHttpResponse(this.response);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid accessManagerMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Dispatcher(null, Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'accessManager' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid mappersMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Dispatcher(this.accessManager, null))\n\t\t\t.withMessageContaining(\"'mappers' must not be null\");\n\t}\n\n\t@Test\n\tvoid accessManagerVetoRequest() throws Exception {\n\t\tgiven(this.accessManager.isAllowed(any(ServerHttpRequest.class))).willReturn(false);\n\t\tHandlerMapper mapper = mock(HandlerMapper.class);\n\t\tHandler handler = mock(Handler.class);\n\t\tgiven(mapper.getHandler(any(ServerHttpRequest.class))).willReturn(handler);\n\t\tDispatcher dispatcher = new Dispatcher(this.accessManager, Collections.singleton(mapper));\n\t\tdispatcher.handle(this.serverRequest, this.serverResponse);\n\t\tthen(handler).shouldHaveNoInteractions();\n\t\tassertThat(this.response.getStatus()).isEqualTo(403);\n\t}\n\n\t@Test\n\tvoid accessManagerAllowRequest() throws Exception {\n\t\tgiven(this.accessManager.isAllowed(any(ServerHttpRequest.class))).willReturn(true);\n\t\tHandlerMapper mapper = mock(HandlerMapper.class);\n\t\tHandler handler = mock(Handler.class);\n\t\tgiven(mapper.getHandler(any(ServerHttpRequest.class))).willReturn(handler);\n\t\tDispatcher dispatcher = new Dispatcher(this.accessManager, Collections.singleton(mapper));\n\t\tdispatcher.handle(this.serverRequest, this.serverResponse);\n\t\tthen(handler).should().handle(this.serverRequest, this.serverResponse);\n\t}\n\n\t@Test\n\tvoid ordersMappers() throws Exception {\n\t\tHandlerMapper mapper1 = mock(HandlerMapper.class, withSettings().extraInterfaces(Ordered.class));\n\t\tHandlerMapper mapper2 = mock(HandlerMapper.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) mapper1).getOrder()).willReturn(1);\n\t\tgiven(((Ordered) mapper2).getOrder()).willReturn(2);\n\t\tList<HandlerMapper> mappers = Arrays.asList(mapper2, mapper1);\n\t\tDispatcher dispatcher = new Dispatcher(AccessManager.PERMIT_ALL, mappers);\n\t\tdispatcher.handle(this.serverRequest, this.serverResponse);\n\t\tInOrder inOrder = inOrder(mapper1, mapper2);\n\t\tthen(mapper1).should(inOrder).getHandler(this.serverRequest);\n\t\tthen(mapper2).should(inOrder).getHandler(this.serverRequest);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpHeaderAccessManagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.mock.web.MockHttpServletRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link HttpHeaderAccessManager}.\n *\n * @author Rob Winch\n * @author Phillip Webb\n */\nclass HttpHeaderAccessManagerTests {\n\n\tprivate static final String HEADER = \"X-AUTH_TOKEN\";\n\n\tprivate static final String SECRET = \"password\";\n\n\tprivate MockHttpServletRequest request;\n\n\tprivate ServerHttpRequest serverRequest;\n\n\tprivate HttpHeaderAccessManager manager;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.request = new MockHttpServletRequest(\"GET\", \"/\");\n\t\tthis.serverRequest = new ServletServerHttpRequest(this.request);\n\t\tthis.manager = new HttpHeaderAccessManager(HEADER, SECRET);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid headerNameMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(null, SECRET))\n\t\t\t.withMessageContaining(\"'headerName' must not be empty\");\n\t}\n\n\t@Test\n\tvoid headerNameMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(\"\", SECRET))\n\t\t\t.withMessageContaining(\"'headerName' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid expectedSecretMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(HEADER, null))\n\t\t\t.withMessageContaining(\"'expectedSecret' must not be empty\");\n\t}\n\n\t@Test\n\tvoid expectedSecretMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpHeaderAccessManager(HEADER, \"\"))\n\t\t\t.withMessageContaining(\"'expectedSecret' must not be empty\");\n\t}\n\n\t@Test\n\tvoid allowsMatching() {\n\t\tthis.request.addHeader(HEADER, SECRET);\n\t\tassertThat(this.manager.isAllowed(this.serverRequest)).isTrue();\n\t}\n\n\t@Test\n\tvoid disallowsWrongSecret() {\n\t\tthis.request.addHeader(HEADER, \"wrong\");\n\t\tassertThat(this.manager.isAllowed(this.serverRequest)).isFalse();\n\t}\n\n\t@Test\n\tvoid disallowsNoSecret() {\n\t\tassertThat(this.manager.isAllowed(this.serverRequest)).isFalse();\n\t}\n\n\t@Test\n\tvoid disallowsWrongHeader() {\n\t\tthis.request.addHeader(\"X-WRONG\", SECRET);\n\t\tassertThat(this.manager.isAllowed(this.serverRequest)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/HttpStatusHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpResponse;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link HttpStatusHandler}.\n *\n * @author Phillip Webb\n */\nclass HttpStatusHandlerTests {\n\n\tprivate MockHttpServletRequest servletRequest;\n\n\tprivate MockHttpServletResponse servletResponse;\n\n\tprivate ServerHttpResponse response;\n\n\tprivate ServerHttpRequest request;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.servletRequest = new MockHttpServletRequest();\n\t\tthis.servletResponse = new MockHttpServletResponse();\n\t\tthis.request = new ServletServerHttpRequest(this.servletRequest);\n\t\tthis.response = new ServletServerHttpResponse(this.servletResponse);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid statusMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpStatusHandler(null))\n\t\t\t.withMessageContaining(\"'status' must not be null\");\n\t}\n\n\t@Test\n\tvoid respondsOk() throws Exception {\n\t\tHttpStatusHandler handler = new HttpStatusHandler();\n\t\thandler.handle(this.request, this.response);\n\t\tassertThat(this.servletResponse.getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid respondsWithStatus() throws Exception {\n\t\tHttpStatusHandler handler = new HttpStatusHandler(HttpStatus.EXPECTATION_FAILED);\n\t\thandler.handle(this.request, this.response);\n\t\tassertThat(this.servletResponse.getStatus()).isEqualTo(417);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/remote/server/UrlHandlerMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.remote.server;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.mock.web.MockHttpServletRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link UrlHandlerMapper}.\n *\n * @author Rob Winch\n * @author Phillip Webb\n */\nclass UrlHandlerMapperTests {\n\n\tprivate final Handler handler = mock(Handler.class);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid requestUriMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new UrlHandlerMapper(null, this.handler))\n\t\t\t.withMessageContaining(\"'url' must not be empty\");\n\t}\n\n\t@Test\n\tvoid requestUriMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new UrlHandlerMapper(\"\", this.handler))\n\t\t\t.withMessageContaining(\"'url' must not be empty\");\n\t}\n\n\t@Test\n\tvoid requestUrlMustStartWithSlash() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new UrlHandlerMapper(\"tunnel\", this.handler))\n\t\t\t.withMessageContaining(\"'url' must start with '/'\");\n\t}\n\n\t@Test\n\tvoid handlesMatchedUrl() {\n\t\tUrlHandlerMapper mapper = new UrlHandlerMapper(\"/tunnel\", this.handler);\n\t\tHttpServletRequest servletRequest = new MockHttpServletRequest(\"GET\", \"/tunnel\");\n\t\tServerHttpRequest request = new ServletServerHttpRequest(servletRequest);\n\t\tassertThat(mapper.getHandler(request)).isEqualTo(this.handler);\n\t}\n\n\t@Test\n\tvoid ignoresDifferentUrl() {\n\t\tUrlHandlerMapper mapper = new UrlHandlerMapper(\"/tunnel\", this.handler);\n\t\tHttpServletRequest servletRequest = new MockHttpServletRequest(\"GET\", \"/tunnel/other\");\n\t\tServerHttpRequest request = new ServletServerHttpRequest(servletRequest);\n\t\tassertThat(mapper.getHandler(request)).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.UUID;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarOutputStream;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipOutputStream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ChangeableUrls}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ChangeableUrlsTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid directoryUrl() throws Exception {\n\t\tURL url = makeUrl(\"myproject\");\n\t\tassertThat(ChangeableUrls.fromUrls(url)).hasSize(1);\n\t}\n\n\t@Test\n\tvoid fileUrl() throws Exception {\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\tfile.createNewFile();\n\t\tURL url = file.toURI().toURL();\n\t\tassertThat(ChangeableUrls.fromUrls(url)).isEmpty();\n\t}\n\n\t@Test\n\tvoid httpUrl() throws Exception {\n\t\tURL url = new URL(\"https://spring.io\");\n\t\tassertThat(ChangeableUrls.fromUrls(url)).isEmpty();\n\t}\n\n\t@Test\n\tvoid httpsUrl() throws Exception {\n\t\tURL url = new URL(\"https://spring.io\");\n\t\tassertThat(ChangeableUrls.fromUrls(url)).isEmpty();\n\t}\n\n\t@Test\n\tvoid skipsUrls() throws Exception {\n\t\tChangeableUrls urls = ChangeableUrls.fromUrls(makeUrl(\"spring-boot\"), makeUrl(\"spring-boot-autoconfigure\"),\n\t\t\t\tmakeUrl(\"spring-boot-actuator\"), makeUrl(\"spring-boot-starter\"),\n\t\t\t\tmakeUrl(\"spring-boot-starter-some-thing\"));\n\t\tassertThat(urls).isEmpty();\n\t}\n\n\t@Test\n\tvoid urlsFromJarClassPathAreConsidered() throws Exception {\n\t\tFile relative = new File(this.tempDir, UUID.randomUUID().toString());\n\t\trelative.mkdir();\n\t\tFile absolute = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tabsolute.mkdirs();\n\t\tURL absoluteUrl = absolute.toURI().toURL();\n\t\tFile jarWithClassPath = makeJarFileWithUrlsInManifestClassPath(\"project-core/target/classes/\",\n\t\t\t\t\"project-web/target/classes/\", \"project%20space/target/classes/\", \"does-not-exist/target/classes/\",\n\t\t\t\trelative.getName() + \"/\", absoluteUrl);\n\t\tnew File(jarWithClassPath.getParentFile(), \"project-core/target/classes\").mkdirs();\n\t\tnew File(jarWithClassPath.getParentFile(), \"project-web/target/classes\").mkdirs();\n\t\tnew File(jarWithClassPath.getParentFile(), \"project space/target/classes\").mkdirs();\n\t\tChangeableUrls urls = ChangeableUrls.fromClassLoader(\n\t\t\t\tnew URLClassLoader(new URL[] { jarWithClassPath.toURI().toURL(), makeJarFileWithNoManifest() }));\n\t\tassertThat(urls.toList()).containsExactly(\n\t\t\t\tnew URL(jarWithClassPath.toURI().toURL(), \"project-core/target/classes/\"),\n\t\t\t\tnew URL(jarWithClassPath.toURI().toURL(), \"project-web/target/classes/\"),\n\t\t\t\tnew URL(jarWithClassPath.toURI().toURL(), \"project space/target/classes/\"), relative.toURI().toURL(),\n\t\t\t\tabsoluteUrl);\n\t}\n\n\tprivate URL makeUrl(String name) throws IOException {\n\t\tFile file = new File(this.tempDir, UUID.randomUUID().toString());\n\t\tfile = new File(file, name);\n\t\tfile = new File(file, \"build\");\n\t\tfile = new File(file, \"classes\");\n\t\tfile.mkdirs();\n\t\treturn file.toURI().toURL();\n\t}\n\n\tprivate File makeJarFileWithUrlsInManifestClassPath(Object... urls) throws Exception {\n\t\tFile classpathJar = new File(this.tempDir, \"classpath.jar\");\n\t\tManifest manifest = new Manifest();\n\t\tmanifest.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(), \"1.0\");\n\t\tmanifest.getMainAttributes()\n\t\t\t.putValue(Attributes.Name.CLASS_PATH.toString(), StringUtils.arrayToDelimitedString(urls, \" \"));\n\t\tnew JarOutputStream(new FileOutputStream(classpathJar), manifest).close();\n\t\treturn classpathJar;\n\t}\n\n\tprivate URL makeJarFileWithNoManifest() throws Exception {\n\t\tFile classpathJar = new File(this.tempDir, \"no-manifest.jar\");\n\t\tnew ZipOutputStream(new FileOutputStream(classpathJar)).close();\n\t\treturn classpathJar.toURI().toURL();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ClassLoaderFilesResourcePatternResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.restart.ClassLoaderFilesResourcePatternResolver.DeletedClassLoaderFileResource;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.ProtocolResolver;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\nimport org.springframework.web.context.support.ServletContextResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ClassLoaderFilesResourcePatternResolver}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass ClassLoaderFilesResourcePatternResolverTests {\n\n\tprivate ClassLoaderFiles files;\n\n\tprivate ClassLoaderFilesResourcePatternResolver resolver;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.files = new ClassLoaderFiles();\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(new GenericApplicationContext(), this.files);\n\t}\n\n\t@Test\n\tvoid getClassLoaderShouldReturnClassLoader() {\n\t\tassertThat(this.resolver.getClassLoader()).isNotNull();\n\t}\n\n\t@Test\n\tvoid getResourceShouldReturnResource() {\n\t\tResource resource = this.resolver.getResource(\"index.html\");\n\t\tassertThat(resource).isInstanceOf(ClassPathResource.class);\n\t}\n\n\t@Test\n\tvoid getResourceWhenHasServletContextShouldReturnServletResource() {\n\t\tGenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tResource resource = this.resolver.getResource(\"index.html\");\n\t\tassertThat(resource).isInstanceOf(ServletContextResource.class);\n\t}\n\n\t@Test\n\tvoid getResourceWhenDeletedShouldReturnDeletedResource(@TempDir File directory) throws Exception {\n\t\tFile file = createFile(directory, \"name.class\");\n\t\tthis.files.addFile(directory.getName(), \"name.class\", new ClassLoaderFile(Kind.DELETED, null));\n\t\tResource resource = this.resolver.getResource(\"file:\" + file.getAbsolutePath());\n\t\tassertThat(resource).isInstanceOf(DeletedClassLoaderFileResource.class);\n\t}\n\n\t@Test\n\tvoid getResourcesShouldReturnResources(@TempDir File directory) throws Exception {\n\t\tFile file = createFile(directory, \"name.class\");\n\t\tResource[] resources = this.resolver.getResources(\"file:\" + directory.getAbsolutePath() + \"/**\");\n\t\tassertThat(resources).extracting(Resource::getFile).containsExactly(file);\n\t}\n\n\t@Test\n\tvoid getResourcesWhenDeletedShouldFilterDeleted(@TempDir File directory) throws Exception {\n\t\tcreateFile(directory, \"name.class\");\n\t\tthis.files.addFile(directory.getName(), \"name.class\", new ClassLoaderFile(Kind.DELETED, null));\n\t\tResource[] resources = this.resolver.getResources(\"file:\" + directory.getAbsolutePath() + \"/**\");\n\t\tassertThat(resources).isEmpty();\n\t}\n\n\t@Test\n\tvoid customResourceLoaderIsUsedInNonWebApplication() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tResourceLoader resourceLoader = mock(ResourceLoader.class);\n\t\tcontext.setResourceLoader(resourceLoader);\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tthis.resolver.getResource(\"foo.txt\");\n\t\tthen(resourceLoader).should().getResource(\"foo.txt\");\n\t}\n\n\t@Test\n\tvoid customProtocolResolverIsUsedInNonWebApplication() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tResource resource = mock(Resource.class);\n\t\tProtocolResolver resolver = mockProtocolResolver(\"foo:some-file.txt\", resource);\n\t\tcontext.addProtocolResolver(resolver);\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tResource actual = this.resolver.getResource(\"foo:some-file.txt\");\n\t\tassertThat(actual).isSameAs(resource);\n\t\tthen(resolver).should().resolve(eq(\"foo:some-file.txt\"), any(ResourceLoader.class));\n\t}\n\n\t@Test\n\tvoid customProtocolResolverRegisteredAfterCreationIsUsedInNonWebApplication() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tResource resource = mock(Resource.class);\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tProtocolResolver resolver = mockProtocolResolver(\"foo:some-file.txt\", resource);\n\t\tcontext.addProtocolResolver(resolver);\n\t\tResource actual = this.resolver.getResource(\"foo:some-file.txt\");\n\t\tassertThat(actual).isSameAs(resource);\n\t\tthen(resolver).should().resolve(eq(\"foo:some-file.txt\"), any(ResourceLoader.class));\n\t}\n\n\t@Test\n\tvoid customResourceLoaderIsUsedInWebApplication() {\n\t\tGenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());\n\t\tResourceLoader resourceLoader = mock(ResourceLoader.class);\n\t\tcontext.setResourceLoader(resourceLoader);\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tthis.resolver.getResource(\"foo.txt\");\n\t\tthen(resourceLoader).should().getResource(\"foo.txt\");\n\t}\n\n\t@Test\n\tvoid customProtocolResolverIsUsedInWebApplication() {\n\t\tGenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());\n\t\tResource resource = mock(Resource.class);\n\t\tProtocolResolver resolver = mockProtocolResolver(\"foo:some-file.txt\", resource);\n\t\tcontext.addProtocolResolver(resolver);\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tResource actual = this.resolver.getResource(\"foo:some-file.txt\");\n\t\tassertThat(actual).isSameAs(resource);\n\t\tthen(resolver).should().resolve(eq(\"foo:some-file.txt\"), any(ResourceLoader.class));\n\t}\n\n\t@Test\n\tvoid customProtocolResolverRegisteredAfterCreationIsUsedInWebApplication() {\n\t\tGenericWebApplicationContext context = new GenericWebApplicationContext(new MockServletContext());\n\t\tResource resource = mock(Resource.class);\n\t\tthis.resolver = new ClassLoaderFilesResourcePatternResolver(context, this.files);\n\t\tProtocolResolver resolver = mockProtocolResolver(\"foo:some-file.txt\", resource);\n\t\tcontext.addProtocolResolver(resolver);\n\t\tResource actual = this.resolver.getResource(\"foo:some-file.txt\");\n\t\tassertThat(actual).isSameAs(resource);\n\t\tthen(resolver).should().resolve(eq(\"foo:some-file.txt\"), any(ResourceLoader.class));\n\t}\n\n\tprivate ProtocolResolver mockProtocolResolver(String path, Resource resource) {\n\t\tProtocolResolver resolver = mock(ProtocolResolver.class);\n\t\tgiven(resolver.resolve(eq(path), any(ResourceLoader.class))).willReturn(resource);\n\t\treturn resolver;\n\t}\n\n\tprivate File createFile(File directory, String name) throws IOException {\n\t\tFile file = new File(directory, name);\n\t\tFileCopyUtils.copy(\"test\".getBytes(), file);\n\t\treturn file;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/DefaultRestartInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultRestartInitializer}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass DefaultRestartInitializerTests {\n\n\t@Test\n\tvoid jUnitStackShouldReturnNull() {\n\t\ttestSkippedStacks(\"org.junit.runners.Something\");\n\t}\n\n\t@Test\n\tvoid jUnit5StackShouldReturnNull() {\n\t\ttestSkippedStacks(\"org.junit.platform.Something\");\n\t}\n\n\t@Test\n\tvoid springTestStackShouldReturnNull() {\n\t\ttestSkippedStacks(\"org.springframework.boot.test.Something\");\n\t}\n\n\t@Test\n\tvoid cucumberStackShouldReturnNull() {\n\t\ttestSkippedStacks(\"cucumber.runtime.Runtime.run\");\n\t}\n\n\t@Test\n\tvoid validMainThreadShouldReturnUrls() {\n\t\tDefaultRestartInitializer initializer = new DefaultRestartInitializer();\n\t\tClassLoader classLoader = new MockAppClassLoader(getClass().getClassLoader());\n\t\tThread thread = new Thread();\n\t\tthread.setName(\"main\");\n\t\tthread.setContextClassLoader(classLoader);\n\t\tassertThat(initializer.getInitialUrls(thread)).isNotNull();\n\t}\n\n\t@Test\n\tvoid threadNotNamedMainShouldReturnNull() {\n\t\tDefaultRestartInitializer initializer = new DefaultRestartInitializer();\n\t\tClassLoader classLoader = new MockAppClassLoader(getClass().getClassLoader());\n\t\tThread thread = new Thread();\n\t\tthread.setName(\"buscuit\");\n\t\tthread.setContextClassLoader(classLoader);\n\t\tassertThat(initializer.getInitialUrls(thread)).isNull();\n\t}\n\n\t@Test\n\tvoid threadNotUsingAppClassLoader() {\n\t\tDefaultRestartInitializer initializer = new DefaultRestartInitializer();\n\t\tClassLoader classLoader = new MockLauncherClassLoader(getClass().getClassLoader());\n\t\tThread thread = new Thread();\n\t\tthread.setName(\"main\");\n\t\tthread.setContextClassLoader(classLoader);\n\t\tassertThat(initializer.getInitialUrls(thread)).isNull();\n\t}\n\n\t@Test\n\tvoid urlsCanBeRetrieved() throws IOException {\n\t\tThread thread = Thread.currentThread();\n\t\tClassLoader classLoader = thread.getContextClassLoader();\n\t\ttry (URLClassLoader contextClassLoader = new URLClassLoader(\n\t\t\t\tnew URL[] { new URL(\"file:test-app/build/classes/main/\") }, classLoader)) {\n\t\t\tthread.setContextClassLoader(contextClassLoader);\n\t\t\tassertThat(new DefaultRestartInitializer().getUrls(thread)).isNotEmpty();\n\t\t}\n\t\tfinally {\n\t\t\tthread.setContextClassLoader(classLoader);\n\t\t}\n\t}\n\n\tprotected void testSkippedStacks(String s) {\n\t\tDefaultRestartInitializer initializer = new DefaultRestartInitializer();\n\t\tClassLoader classLoader = new MockAppClassLoader(getClass().getClassLoader());\n\t\tThread thread = mock(Thread.class);\n\t\tgiven(thread.getName()).willReturn(\"main\");\n\t\tStackTraceElement element = new StackTraceElement(s, \"someMethod\", \"someFile\", 123);\n\t\tgiven(thread.getStackTrace()).willReturn(new StackTraceElement[] { element });\n\t\tgiven(thread.getContextClassLoader()).willReturn(classLoader);\n\t\tassertThat(initializer.getInitialUrls(thread)).isNull();\n\t}\n\n\tstatic class MockAppClassLoader extends ClassLoader {\n\n\t\tMockAppClassLoader(ClassLoader parent) {\n\t\t\tsuper(parent);\n\t\t}\n\n\t}\n\n\tstatic class MockLauncherClassLoader extends ClassLoader {\n\n\t\tMockLauncherClassLoader(ClassLoader parent) {\n\t\t\tsuper(parent);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MainMethodTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.lang.reflect.Method;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.launch.FakeJarLauncher;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MainMethod}.\n *\n * @author Phillip Webb\n */\nclass MainMethodTests {\n\n\tprivate static final ThreadLocal<MainMethod> mainMethod = new ThreadLocal<>();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid threadMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new MainMethod(null))\n\t\t\t.withMessageContaining(\"'thread' must not be null\");\n\t}\n\n\t@Test\n\tvoid validMainMethod() throws Exception {\n\t\tMethod actualMain = Valid.class.getMethod(\"main\", String[].class);\n\t\tMainMethod method = new TestThread(Valid::main).test();\n\t\tassertThat(method.getMethod()).isEqualTo(actualMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(actualMain.getDeclaringClass().getName());\n\t}\n\n\t@Test // gh-35214\n\tvoid nestedMainMethod() throws Exception {\n\t\tMainMethod method = new TestThread(Nested::main).test();\n\t\tMethod nestedMain = Nested.class.getMethod(\"main\", String[].class);\n\t\tassertThat(method.getMethod()).isEqualTo(nestedMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(nestedMain.getDeclaringClass().getName());\n\t}\n\n\t@Test // gh-39733\n\tvoid viaJarLauncher() throws Exception {\n\t\tFakeJarLauncher.action = (args) -> Valid.main(args);\n\t\tMainMethod method = new TestThread(FakeJarLauncher::main).test();\n\t\tMethod expectedMain = Valid.class.getMethod(\"main\", String[].class);\n\t\tassertThat(method.getMethod()).isEqualTo(expectedMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(expectedMain.getDeclaringClass().getName());\n\t}\n\n\t@Test\n\tvoid detectPublicMainMethod() throws Exception {\n\t\tMethod actualMain = PublicMainMethod.class.getMethod(\"main\", String[].class);\n\t\tMainMethod method = new TestThread(PublicMainMethod::main).test();\n\t\tassertThat(method.getMethod()).isEqualTo(actualMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(actualMain.getDeclaringClass().getName());\n\t}\n\n\t@Test\n\tvoid detectPublicParameterlessMainMethod() throws Exception {\n\t\tMethod actualMain = PublicParameterlessMainMethod.class.getMethod(\"main\");\n\t\tMainMethod method = new TestThread(PublicParameterlessMainMethod::main).test();\n\t\tassertThat(method.getMethod()).isEqualTo(actualMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(actualMain.getDeclaringClass().getName());\n\t}\n\n\t@Test\n\tvoid detectPackagePrivateMainMethod() throws Exception {\n\t\tMethod actualMain = PackagePrivateMainMethod.class.getDeclaredMethod(\"main\", String[].class);\n\t\tMainMethod method = new TestThread(PackagePrivateMainMethod::main).test();\n\t\tassertThat(method.getMethod()).isEqualTo(actualMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(actualMain.getDeclaringClass().getName());\n\t}\n\n\t@Test\n\tvoid detectPackagePrivateParameterlessMainMethod() throws Exception {\n\t\tMethod actualMain = PackagePrivateParameterlessMainMethod.class.getDeclaredMethod(\"main\");\n\t\tMainMethod method = new TestThread(PackagePrivateParameterlessMainMethod::main).test();\n\t\tassertThat(method.getMethod()).isEqualTo(actualMain);\n\t\tassertThat(method.getDeclaringClassName()).isEqualTo(actualMain.getDeclaringClass().getName());\n\t}\n\n\t@Test\n\tvoid nonStatic() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new TestThread(() -> new NonStaticMainMethod().main()).test())\n\t\t\t.withMessageContaining(\"Unable to find main method\");\n\t}\n\n\tstatic class TestThread extends Thread {\n\n\t\tprivate final Runnable runnable;\n\n\t\tprivate @Nullable Exception exception;\n\n\t\tprivate @Nullable MainMethod mainMethod;\n\n\t\tTestThread(Runnable runnable) {\n\t\t\tthis.runnable = runnable;\n\t\t}\n\n\t\tMainMethod test() throws InterruptedException {\n\t\t\tstart();\n\t\t\tjoin();\n\t\t\tif (this.exception != null) {\n\t\t\t\tReflectionUtils.rethrowRuntimeException(this.exception);\n\t\t\t}\n\t\t\tMainMethod mainMethod = this.mainMethod;\n\t\t\tassertThat(mainMethod).isNotNull();\n\t\t\treturn mainMethod;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run() {\n\t\t\ttry {\n\t\t\t\tthis.runnable.run();\n\t\t\t\tthis.mainMethod = MainMethodTests.mainMethod.get();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthis.exception = ex;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static class Valid {\n\n\t\tpublic static void main(String... args) {\n\t\t\tsomeOtherMethod();\n\t\t}\n\n\t\tprivate static void someOtherMethod() {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t}\n\n\t}\n\n\tpublic static class Nested {\n\n\t\tpublic static void main(String... args) {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t\tValid.main(args);\n\t\t}\n\n\t}\n\n\tpublic static class PublicMainMethod {\n\n\t\tpublic static void main(String... args) {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t}\n\n\t}\n\n\tpublic static class PublicParameterlessMainMethod {\n\n\t\tpublic static void main() {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t}\n\n\t}\n\n\tpublic static class PackagePrivateMainMethod {\n\n\t\tstatic void main(String... args) {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t}\n\n\t}\n\n\tpublic static class PackagePrivateParameterlessMainMethod {\n\n\t\tstatic void main() {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t}\n\n\t}\n\n\tpublic static class NonStaticMainMethod {\n\n\t\tvoid main(String... args) {\n\t\t\tmainMethod.set(new MainMethod());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MockRestartInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.net.URL;\n\n/**\n * Simple mock {@link RestartInitializer} that returns an empty array of URLs.\n *\n * @author Phillip Webb\n */\npublic class MockRestartInitializer implements RestartInitializer {\n\n\t@Override\n\tpublic URL[] getInitialUrls(Thread thread) {\n\t\treturn new URL[] {};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/MockRestarter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolver;\n\nimport org.springframework.beans.factory.ObjectFactory;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Mocked version of {@link Restarter}.\n *\n * @author Phillip Webb\n */\npublic class MockRestarter implements BeforeEachCallback, AfterEachCallback, ParameterResolver {\n\n\tprivate final Map<String, Object> attributes = new HashMap<>();\n\n\tprivate final Restarter mock = mock(Restarter.class);\n\n\tpublic Restarter getMock() {\n\t\treturn this.mock;\n\t}\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\tthis.attributes.clear();\n\t\tRestarter.clearInstance();\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tRestarter.setInstance(this.mock);\n\t\tgiven(this.mock.getInitialUrls()).willReturn(new URL[] {});\n\t\tgiven(this.mock.getOrAddAttribute(anyString(), any(ObjectFactory.class))).willAnswer((invocation) -> {\n\t\t\tString name = invocation.getArgument(0);\n\t\t\tObjectFactory<?> factory = invocation.getArgument(1);\n\t\t\tObject attribute = MockRestarter.this.attributes.get(name);\n\t\t\tif (attribute == null) {\n\t\t\t\tattribute = factory.getObject();\n\t\t\t\tMockRestarter.this.attributes.put(name, attribute);\n\t\t\t}\n\t\t\treturn attribute;\n\t\t});\n\t\tgiven(this.mock.getThreadFactory()).willReturn(Thread::new);\n\t}\n\n\t@Override\n\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\treturn parameterContext.getParameter().getType().equals(Restarter.class);\n\t}\n\n\t@Override\n\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\treturn this.mock;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/OnInitializedRestarterConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.net.URL;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OnInitializedRestarterCondition}.\n *\n * @author Phillip Webb\n */\nclass OnInitializedRestarterConditionTests {\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid cleanup() {\n\t\tRestarter.clearInstance();\n\t}\n\n\t@Test\n\tvoid noInstance() {\n\t\tRestarter.clearInstance();\n\t\tConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class);\n\t\tassertThat(context.containsBean(\"bean\")).isFalse();\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid noInitialization() {\n\t\tRestarter.initialize(new String[0], false, RestartInitializer.NONE);\n\t\tConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class);\n\t\tassertThat(context.containsBean(\"bean\")).isFalse();\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid initialized() throws Exception {\n\t\tThread thread = new Thread(TestInitialized::main);\n\t\tthread.start();\n\t\tthread.join(30000);\n\t\tassertThat(thread.isAlive()).isFalse();\n\t}\n\n\tstatic class TestInitialized {\n\n\t\tstatic void main(String... args) {\n\t\t\tRestartInitializer initializer = mock(RestartInitializer.class);\n\t\t\tgiven(initializer.getInitialUrls(any(Thread.class))).willReturn(new URL[0]);\n\t\t\tRestarter.initialize(new String[0], false, initializer);\n\t\t\tConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class);\n\t\t\tassertThat(context.containsBean(\"bean\")).isTrue();\n\t\t\tcontext.close();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\t@ConditionalOnInitializedRestarter\n\t\tString bean() {\n\t\t\treturn \"bean\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartApplicationListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.bootstrap.DefaultBootstrapContext;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationPreparedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RestartApplicationListener}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass RestartApplicationListenerTests {\n\n\tprivate static final String ENABLED_PROPERTY = \"spring.devtools.restart.enabled\";\n\n\tprivate static final String[] ARGS = new String[] { \"a\", \"b\", \"c\" };\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid cleanup() {\n\t\tRestarter.clearInstance();\n\t\tSystem.clearProperty(ENABLED_PROPERTY);\n\t}\n\n\t@Test\n\tvoid isHighestPriority() {\n\t\tassertThat(new RestartApplicationListener().getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE);\n\t}\n\n\t@Test\n\tvoid initializeWithReady() {\n\t\ttestInitialize(false, new ImplicitlyEnabledRestartApplicationListener());\n\t\tassertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue(\"args\", ARGS);\n\t\tassertThat(Restarter.getInstance().isFinished()).isTrue();\n\t\tassertThat((List<?>) ReflectionTestUtils.getField(Restarter.getInstance(), \"rootContexts\")).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid initializeWithFail() {\n\t\ttestInitialize(true, new ImplicitlyEnabledRestartApplicationListener());\n\t\tassertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue(\"args\", ARGS);\n\t\tassertThat(Restarter.getInstance().isFinished()).isTrue();\n\t\tassertThat((List<?>) ReflectionTestUtils.getField(Restarter.getInstance(), \"rootContexts\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid disableWithSystemProperty(CapturedOutput output) {\n\t\tSystem.setProperty(ENABLED_PROPERTY, \"false\");\n\t\ttestInitialize(false, new ImplicitlyEnabledRestartApplicationListener());\n\t\tassertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue(\"enabled\", false);\n\t\tassertThat(output).contains(\"Restart disabled due to System property\");\n\t}\n\n\t@Test\n\tvoid enableWithSystemProperty(CapturedOutput output) {\n\t\tSystem.setProperty(ENABLED_PROPERTY, \"true\");\n\t\ttestInitialize(false, new ImplicitlyEnabledRestartApplicationListener());\n\t\tassertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue(\"enabled\", true);\n\t\tassertThat(output).contains(\"Restart enabled irrespective of application packaging due to System property\");\n\t}\n\n\t@Test\n\tvoid enableWithSystemPropertyWhenImplicitlyDisabled(CapturedOutput output) {\n\t\tSystem.setProperty(ENABLED_PROPERTY, \"true\");\n\t\ttestInitialize(false, new RestartApplicationListener());\n\t\tassertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue(\"enabled\", true);\n\t\tassertThat(output).contains(\"Restart enabled irrespective of application packaging due to System property\");\n\t}\n\n\t@Test\n\tvoid implicitlyDisabledInTests(CapturedOutput output) {\n\t\ttestInitialize(false, new RestartApplicationListener());\n\t\tassertThat(Restarter.getInstance()).hasFieldOrPropertyWithValue(\"enabled\", false);\n\t\tassertThat(output).contains(\"Restart disabled due to context in which it is running\");\n\t}\n\n\tprivate void testInitialize(boolean failed, RestartApplicationListener listener) {\n\t\tRestarter.clearInstance();\n\t\tDefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();\n\t\tSpringApplication application = new SpringApplication();\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tlistener.onApplicationEvent(new ApplicationStartingEvent(bootstrapContext, application, ARGS));\n\t\tassertThat(Restarter.getInstance()).isNotNull();\n\t\tassertThat(Restarter.getInstance().isFinished()).isFalse();\n\t\tlistener.onApplicationEvent(new ApplicationPreparedEvent(application, ARGS, context));\n\t\tif (failed) {\n\t\t\tlistener.onApplicationEvent(new ApplicationFailedEvent(application, ARGS, context, new RuntimeException()));\n\t\t}\n\t\telse {\n\t\t\tlistener.onApplicationEvent(new ApplicationReadyEvent(application, ARGS, context, null));\n\t\t}\n\t}\n\n\tprivate static final class ImplicitlyEnabledRestartApplicationListener extends RestartApplicationListener {\n\n\t\t@Override\n\t\tboolean implicitlyEnableRestart() {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestartScopeInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.ContextRefreshedEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RestartScopeInitializer}.\n *\n * @author Phillip Webb\n */\nclass RestartScopeInitializerTests {\n\n\tprivate static @Nullable AtomicInteger createCount;\n\n\tprivate static @Nullable AtomicInteger refreshCount;\n\n\t@Test\n\tvoid restartScope() {\n\t\tcreateCount = new AtomicInteger();\n\t\trefreshCount = new AtomicInteger();\n\t\tConfigurableApplicationContext context = runApplication();\n\t\tcontext.close();\n\t\tcontext = runApplication();\n\t\tcontext.close();\n\t\tassertThat(createCount.get()).isOne();\n\t\tassertThat(refreshCount.get()).isEqualTo(2);\n\t}\n\n\tprivate ConfigurableApplicationContext runApplication() {\n\t\tSpringApplication application = new SpringApplication(Config.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\treturn application.run();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\t@RestartScope\n\t\tScopeTestBean scopeTestBean() {\n\t\t\treturn new ScopeTestBean();\n\t\t}\n\n\t}\n\n\tstatic class ScopeTestBean implements ApplicationListener<ContextRefreshedEvent> {\n\n\t\tScopeTestBean() {\n\t\t\tassertThat(createCount).isNotNull();\n\t\t\tcreateCount.incrementAndGet();\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextRefreshedEvent event) {\n\t\t\tassertThat(refreshCount).isNotNull();\n\t\t\trefreshCount.incrementAndGet();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/RestarterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.as;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Restarter}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass RestarterTests {\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tRestarterInitializer.setRestarterInstance();\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tRestarter.clearInstance();\n\t}\n\n\t@Test\n\tvoid cantGetInstanceBeforeInitialize() {\n\t\tRestarter.clearInstance();\n\t\tassertThatIllegalStateException().isThrownBy(Restarter::getInstance)\n\t\t\t.withMessageContaining(\"Restarter has not been initialized\");\n\t}\n\n\t@Test\n\tvoid testRestart(CapturedOutput output) {\n\t\tRestarter.clearInstance();\n\t\tThread thread = new Thread(SampleApplication::main);\n\t\tthread.start();\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).untilAsserted(() -> {\n\t\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Tick 0\")).isGreaterThan(1);\n\t\t\tassertThat(StringUtils.countOccurrencesOf(output.toString(), \"Tick 1\")).isGreaterThan(1);\n\t\t\tassertThat(CloseCountingApplicationListener.closed).isGreaterThan(0);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDisabled() {\n\t\tRestarter.disable();\n\t\tConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);\n\t\tRestarter.getInstance().prepare(context);\n\t\tassertThat(Restarter.getInstance()).extracting(\"rootContexts\", as(InstanceOfAssertFactories.LIST)).isEmpty();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid getOrAddAttributeWithNewAttribute() {\n\t\tObjectFactory objectFactory = mock(ObjectFactory.class);\n\t\tgiven(objectFactory.getObject()).willReturn(\"abc\");\n\t\tObject attribute = Restarter.getInstance().getOrAddAttribute(\"x\", objectFactory);\n\t\tassertThat(attribute).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addUrlsMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Restarter.getInstance().addUrls(null))\n\t\t\t.withMessageContaining(\"'urls' must not be null\");\n\t}\n\n\t@Test\n\tvoid addUrls() throws Exception {\n\t\tURL url = new URL(\"file:/proj/module-a.jar!/\");\n\t\tCollection<URL> urls = Collections.singleton(url);\n\t\tRestarter restarter = Restarter.getInstance();\n\t\trestarter.addUrls(urls);\n\t\trestarter.restart();\n\t\tClassLoader classLoader = ((TestableRestarter) restarter).getRelaunchClassLoader();\n\t\tassertThat(classLoader).isNotNull();\n\t\tassertThat(((URLClassLoader) classLoader).getURLs()[0]).isEqualTo(url);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addClassLoaderFilesMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> Restarter.getInstance().addClassLoaderFiles(null))\n\t\t\t.withMessageContaining(\"'classLoaderFiles' must not be null\");\n\t}\n\n\t@Test\n\tvoid addClassLoaderFiles() {\n\t\tClassLoaderFiles classLoaderFiles = new ClassLoaderFiles();\n\t\tclassLoaderFiles.addFile(\"f\", new ClassLoaderFile(Kind.ADDED, \"abc\".getBytes()));\n\t\tRestarter restarter = Restarter.getInstance();\n\t\trestarter.addClassLoaderFiles(classLoaderFiles);\n\t\trestarter.restart();\n\t\tClassLoader classLoader = ((TestableRestarter) restarter).getRelaunchClassLoader();\n\t\tassertThat(classLoader).isNotNull();\n\t\tassertThat(classLoader.getResourceAsStream(\"f\")).hasContent(\"abc\");\n\t}\n\n\t@Test\n\tvoid getOrAddAttributeWithExistingAttribute() {\n\t\tRestarter.getInstance().getOrAddAttribute(\"x\", () -> \"abc\");\n\t\tObjectFactory<?> objectFactory = mock(ObjectFactory.class);\n\t\tObject attribute = Restarter.getInstance().getOrAddAttribute(\"x\", objectFactory);\n\t\tassertThat(attribute).isEqualTo(\"abc\");\n\t\tthen(objectFactory).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid getOrAddAttributeWithRecursion() {\n\t\tRestarter restarter = Restarter.getInstance();\n\t\tObject added = restarter.getOrAddAttribute(\"postgresContainer\", () -> {\n\t\t\trestarter.getOrAddAttribute(\"rabbitContainer\", () -> \"def\");\n\t\t\treturn \"abc\";\n\t\t});\n\t\tObjectFactory<?> objectFactory = mock(ObjectFactory.class);\n\t\tassertThat(added).isEqualTo(\"abc\");\n\t\tassertThat(restarter.getOrAddAttribute(\"postgresContainer\", objectFactory)).isEqualTo(\"abc\");\n\t\tassertThat(restarter.getOrAddAttribute(\"rabbitContainer\", objectFactory)).isEqualTo(\"def\");\n\t\tthen(objectFactory).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid getThreadFactory() throws Exception {\n\t\tfinal ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();\n\t\tfinal ClassLoader contextClassLoader = new URLClassLoader(new URL[0]);\n\t\tThread thread = new Thread(() -> {\n\t\t\tRunnable runnable = mock(Runnable.class);\n\t\t\tThread regular = new Thread();\n\t\t\tThreadFactory factory = Restarter.getInstance().getThreadFactory();\n\t\t\tThread viaFactory = factory.newThread(runnable);\n\t\t\t// Regular threads will inherit the current thread\n\t\t\tassertThat(regular.getContextClassLoader()).isEqualTo(contextClassLoader);\n\t\t\t// Factory threads should inherit from the initial thread\n\t\t\tassertThat(viaFactory.getContextClassLoader()).isEqualTo(parentLoader);\n\t\t});\n\t\tthread.setContextClassLoader(contextClassLoader);\n\t\tthread.start();\n\t\tthread.join();\n\t}\n\n\t@Test\n\tvoid getInitialUrls() throws Exception {\n\t\tRestarter.clearInstance();\n\t\tRestartInitializer initializer = mock(RestartInitializer.class);\n\t\tURL[] urls = new URL[] { new URL(\"file:/proj/module-a.jar!/\") };\n\t\tgiven(initializer.getInitialUrls(any(Thread.class))).willReturn(urls);\n\t\tRestarter.initialize(new String[0], false, initializer, false);\n\t\tassertThat(Restarter.getInstance().getInitialUrls()).isEqualTo(urls);\n\t}\n\n\t@Component\n\t@EnableScheduling\n\tstatic class SampleApplication {\n\n\t\tprivate int count;\n\n\t\tprivate static final AtomicBoolean restart = new AtomicBoolean();\n\n\t\t@Scheduled(fixedDelay = 200)\n\t\tvoid tickBean() {\n\t\t\tSystem.out.println(\"Tick \" + this.count++ + \" \" + Thread.currentThread());\n\t\t}\n\n\t\t@Scheduled(initialDelay = 500, fixedDelay = 500)\n\t\tvoid restart() {\n\t\t\tif (SampleApplication.restart.compareAndSet(false, true)) {\n\t\t\t\tRestarter.getInstance().restart();\n\t\t\t}\n\t\t}\n\n\t\tstatic void main(String... args) {\n\t\t\tRestarter.initialize(args, false, new MockRestartInitializer(), true);\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\t\tSampleApplication.class);\n\t\t\tcontext.addApplicationListener(new CloseCountingApplicationListener());\n\t\t\tRestarter.getInstance().prepare(context);\n\t\t}\n\n\t}\n\n\tstatic class CloseCountingApplicationListener implements ApplicationListener<ContextClosedEvent> {\n\n\t\tstatic int closed;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextClosedEvent event) {\n\t\t\tclosed++;\n\t\t}\n\n\t}\n\n\tstatic class TestableRestarter extends Restarter {\n\n\t\tprivate @Nullable ClassLoader relaunchClassLoader;\n\n\t\tTestableRestarter() {\n\t\t\tthis(Thread.currentThread(), new String[] {}, false, new MockRestartInitializer());\n\t\t}\n\n\t\tprotected TestableRestarter(Thread thread, String[] args, boolean forceReferenceCleanup,\n\t\t\t\tRestartInitializer initializer) {\n\t\t\tsuper(thread, args, forceReferenceCleanup, initializer);\n\t\t}\n\n\t\t@Override\n\t\tpublic void restart(FailureHandler failureHandler) {\n\t\t\ttry {\n\t\t\t\tstop();\n\t\t\t\tstart(failureHandler);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected @Nullable Throwable relaunch(ClassLoader classLoader) {\n\t\t\tthis.relaunchClassLoader = classLoader;\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tprotected void stop() {\n\t\t}\n\n\t\t@Nullable ClassLoader getRelaunchClassLoader() {\n\t\t\treturn this.relaunchClassLoader;\n\t\t}\n\n\t}\n\n\tstatic class RestarterInitializer {\n\n\t\tstatic void setRestarterInstance() {\n\t\t\tmain(new String[0]);\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tRestarter.setInstance(new TestableRestarter());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/SilentExitExceptionHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart;\n\nimport java.util.concurrent.CountDownLatch;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link SilentExitExceptionHandler}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass SilentExitExceptionHandlerTests {\n\n\t@Test\n\tvoid setupAndExit() throws Exception {\n\t\tTestThread testThread = new TestThread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tSilentExitExceptionHandler.exitCurrentThread();\n\t\t\t\tfail(\"Didn't exit\");\n\t\t\t}\n\t\t};\n\t\tSilentExitExceptionHandler.setup(testThread);\n\t\ttestThread.startAndJoin();\n\t\tassertThat(testThread.getThrown()).isNull();\n\t}\n\n\t@Test\n\tvoid doesntInterfereWithOtherExceptions() throws Exception {\n\t\tTestThread testThread = new TestThread() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tthrow new IllegalStateException(\"Expected\");\n\t\t\t}\n\t\t};\n\t\tSilentExitExceptionHandler.setup(testThread);\n\t\ttestThread.startAndJoin();\n\t\tThrowable thrown = testThread.getThrown();\n\t\tassertThat(thrown).isNotNull();\n\t\tassertThat(thrown.getMessage()).isEqualTo(\"Expected\");\n\t}\n\n\t@Test\n\tvoid preventsNonZeroExitCodeWhenAllOtherThreadsAreDaemonThreads() {\n\t\ttry {\n\t\t\tSilentExitExceptionHandler.exitCurrentThread();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tTestSilentExitExceptionHandler silentExitExceptionHandler = new TestSilentExitExceptionHandler();\n\t\t\tsilentExitExceptionHandler.uncaughtException(Thread.currentThread(), ex);\n\t\t\ttry {\n\t\t\t\tassertThat(silentExitExceptionHandler.nonZeroExitCodePrevented).isTrue();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tsilentExitExceptionHandler.cleanUp();\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class TestThread extends Thread {\n\n\t\tprivate @Nullable Throwable thrown;\n\n\t\tTestThread() {\n\t\t\tsetUncaughtExceptionHandler((thread, exception) -> TestThread.this.thrown = exception);\n\t\t}\n\n\t\t@Nullable Throwable getThrown() {\n\t\t\treturn this.thrown;\n\t\t}\n\n\t\tvoid startAndJoin() throws InterruptedException {\n\t\t\tstart();\n\t\t\tjoin();\n\t\t}\n\n\t}\n\n\tstatic class TestSilentExitExceptionHandler extends SilentExitExceptionHandler {\n\n\t\tprivate boolean nonZeroExitCodePrevented;\n\n\t\tprivate final Object monitor = new Object();\n\n\t\tTestSilentExitExceptionHandler() {\n\t\t\tsuper(null);\n\t\t}\n\n\t\t@Override\n\t\tprotected void preventNonZeroExitCode() {\n\t\t\tthis.nonZeroExitCodePrevented = true;\n\t\t}\n\n\t\t@Override\n\t\tprotected Thread[] getAllThreads() {\n\t\t\tfinal CountDownLatch threadRunning = new CountDownLatch(1);\n\t\t\tThread daemonThread = new Thread(() -> {\n\t\t\t\tsynchronized (TestSilentExitExceptionHandler.this.monitor) {\n\t\t\t\t\tthreadRunning.countDown();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tTestSilentExitExceptionHandler.this.monitor.wait();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tdaemonThread.setDaemon(true);\n\t\t\tdaemonThread.start();\n\t\t\ttry {\n\t\t\t\tthreadRunning.await();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t\treturn new Thread[] { Thread.currentThread(), daemonThread };\n\t\t}\n\n\t\tprivate void cleanUp() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.monitor.notifyAll();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFileTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ClassLoaderFile}.\n *\n * @author Phillip Webb\n */\nclass ClassLoaderFileTests {\n\n\tpublic static final byte[] BYTES = \"ABC\".getBytes();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid kindMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(null, null))\n\t\t\t.withMessageContaining(\"'kind' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addedContentsMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.ADDED, null))\n\t\t\t.withMessageContaining(\"'contents' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid modifiedContentsMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.MODIFIED, null))\n\t\t\t.withMessageContaining(\"'contents' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid deletedContentsMustBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFile(Kind.DELETED, new byte[10]))\n\t\t\t.withMessageContaining(\"'contents' must be null\");\n\t}\n\n\t@Test\n\tvoid added() {\n\t\tClassLoaderFile file = new ClassLoaderFile(Kind.ADDED, BYTES);\n\t\tassertThat(file.getKind()).isEqualTo(ClassLoaderFile.Kind.ADDED);\n\t\tassertThat(file.getContents()).isEqualTo(BYTES);\n\t}\n\n\t@Test\n\tvoid modified() {\n\t\tClassLoaderFile file = new ClassLoaderFile(Kind.MODIFIED, BYTES);\n\t\tassertThat(file.getKind()).isEqualTo(ClassLoaderFile.Kind.MODIFIED);\n\t\tassertThat(file.getContents()).isEqualTo(BYTES);\n\t}\n\n\t@Test\n\tvoid deleted() {\n\t\tClassLoaderFile file = new ClassLoaderFile(Kind.DELETED, null);\n\t\tassertThat(file.getKind()).isEqualTo(ClassLoaderFile.Kind.DELETED);\n\t\tassertThat(file.getContents()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/ClassLoaderFilesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.ObjectInputStream;\nimport java.io.ObjectOutputStream;\nimport java.util.Iterator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles.SourceDirectory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ClassLoaderFiles}.\n *\n * @author Phillip Webb\n */\nclass ClassLoaderFilesTests {\n\n\tprivate final ClassLoaderFiles files = new ClassLoaderFiles();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addFileNameMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.files.addFile(null, mock(ClassLoaderFile.class)))\n\t\t\t.withMessageContaining(\"'name' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addFileFileMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.files.addFile(\"test\", null))\n\t\t\t.withMessageContaining(\"'file' must not be null\");\n\t}\n\n\t@Test\n\tvoid getFileWithNullName() {\n\t\tassertThat(this.files.getFile(null)).isNull();\n\t}\n\n\t@Test\n\tvoid addAndGet() {\n\t\tClassLoaderFile file = new ClassLoaderFile(Kind.ADDED, new byte[10]);\n\t\tthis.files.addFile(\"myfile\", file);\n\t\tassertThat(this.files.getFile(\"myfile\")).isEqualTo(file);\n\t}\n\n\t@Test\n\tvoid getMissing() {\n\t\tassertThat(this.files.getFile(\"missing\")).isNull();\n\t}\n\n\t@Test\n\tvoid addTwice() {\n\t\tClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]);\n\t\tClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\tthis.files.addFile(\"myfile\", file1);\n\t\tthis.files.addFile(\"myfile\", file2);\n\t\tassertThat(this.files.getFile(\"myfile\")).isEqualTo(file2);\n\t}\n\n\t@Test\n\tvoid addTwiceInDifferentSourceDirectories() {\n\t\tClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]);\n\t\tClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\tthis.files.addFile(\"a\", \"myfile\", file1);\n\t\tthis.files.addFile(\"b\", \"myfile\", file2);\n\t\tassertThat(this.files.getFile(\"myfile\")).isEqualTo(file2);\n\t\tassertThat(this.files.getOrCreateSourceDirectory(\"a\").getFiles()).isEmpty();\n\t\tassertThat(this.files.getOrCreateSourceDirectory(\"b\").getFiles()).hasSize(1);\n\t}\n\n\t@Test\n\tvoid getSourceDirectories() {\n\t\tClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]);\n\t\tClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\tClassLoaderFile file3 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\tClassLoaderFile file4 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\tthis.files.addFile(\"a\", \"myfile1\", file1);\n\t\tthis.files.addFile(\"a\", \"myfile2\", file2);\n\t\tthis.files.addFile(\"b\", \"myfile3\", file3);\n\t\tthis.files.addFile(\"b\", \"myfile4\", file4);\n\t\tIterator<SourceDirectory> sourceDirectories = this.files.getSourceDirectories().iterator();\n\t\tSourceDirectory sourceDirectory1 = sourceDirectories.next();\n\t\tSourceDirectory sourceDirectory2 = sourceDirectories.next();\n\t\tassertThat(sourceDirectories.hasNext()).isFalse();\n\t\tassertThat(sourceDirectory1.getName()).isEqualTo(\"a\");\n\t\tassertThat(sourceDirectory2.getName()).isEqualTo(\"b\");\n\t\tassertThat(sourceDirectory1.getFiles()).containsOnly(file1, file2);\n\t\tassertThat(sourceDirectory2.getFiles()).containsOnly(file3, file4);\n\t}\n\n\t@Test\n\tvoid serialize() throws Exception {\n\t\tClassLoaderFile file = new ClassLoaderFile(Kind.ADDED, new byte[10]);\n\t\tthis.files.addFile(\"myfile\", file);\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\tObjectOutputStream oos = new ObjectOutputStream(bos);\n\t\toos.writeObject(this.files);\n\t\toos.close();\n\t\tObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));\n\t\tClassLoaderFiles readObject = (ClassLoaderFiles) ois.readObject();\n\t\tassertThat(readObject.getFile(\"myfile\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid addAll() {\n\t\tClassLoaderFile file1 = new ClassLoaderFile(Kind.ADDED, new byte[10]);\n\t\tthis.files.addFile(\"a\", \"myfile1\", file1);\n\t\tClassLoaderFiles toAdd = new ClassLoaderFiles();\n\t\tClassLoaderFile file2 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\tClassLoaderFile file3 = new ClassLoaderFile(Kind.MODIFIED, new byte[10]);\n\t\ttoAdd.addFile(\"a\", \"myfile2\", file2);\n\t\ttoAdd.addFile(\"b\", \"myfile3\", file3);\n\t\tthis.files.addAll(toAdd);\n\t\tIterator<SourceDirectory> sourceDirectories = this.files.getSourceDirectories().iterator();\n\t\tSourceDirectory sourceDirectory1 = sourceDirectories.next();\n\t\tSourceDirectory sourceDirectory2 = sourceDirectories.next();\n\t\tassertThat(sourceDirectories.hasNext()).isFalse();\n\t\tassertThat(sourceDirectory1.getName()).isEqualTo(\"a\");\n\t\tassertThat(sourceDirectory2.getName()).isEqualTo(\"b\");\n\t\tassertThat(sourceDirectory1.getFiles()).containsOnly(file1, file2);\n\t}\n\n\t@Test\n\tvoid getSize() {\n\t\tthis.files.addFile(\"s1\", \"n1\", mock(ClassLoaderFile.class));\n\t\tthis.files.addFile(\"s1\", \"n2\", mock(ClassLoaderFile.class));\n\t\tthis.files.addFile(\"s2\", \"n3\", mock(ClassLoaderFile.class));\n\t\tthis.files.addFile(\"s2\", \"n1\", mock(ClassLoaderFile.class));\n\t\tassertThat(this.files.size()).isEqualTo(3);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid classLoaderFilesMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ClassLoaderFiles(null))\n\t\t\t.withMessageContaining(\"'classLoaderFiles' must not be null\");\n\t}\n\n\t@Test\n\tvoid constructFromExistingSet() {\n\t\tthis.files.addFile(\"s1\", \"n1\", mock(ClassLoaderFile.class));\n\t\tthis.files.addFile(\"s1\", \"n2\", mock(ClassLoaderFile.class));\n\t\tClassLoaderFiles copy = new ClassLoaderFiles(this.files);\n\t\tthis.files.addFile(\"s2\", \"n3\", mock(ClassLoaderFile.class));\n\t\tassertThat(this.files.size()).isEqualTo(3);\n\t\tassertThat(copy.size()).isEqualTo(2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/RestartClassLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.ZipEntry;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link RestartClassLoader}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"resource\")\nclass RestartClassLoaderTests {\n\n\tprivate static final String PACKAGE = RestartClassLoaderTests.class.getPackage().getName();\n\n\tprivate static final String PACKAGE_PATH = PACKAGE.replace('.', '/');\n\n\tprivate File sampleJarFile;\n\n\tprivate URLClassLoader parentClassLoader;\n\n\tprivate ClassLoaderFiles updatedFiles;\n\n\tprivate RestartClassLoader reloadClassLoader;\n\n\t@BeforeEach\n\tvoid setup(@TempDir File tempDir) throws Exception {\n\t\tthis.sampleJarFile = createSampleJarFile(tempDir);\n\t\tURL url = this.sampleJarFile.toURI().toURL();\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tURL[] urls = new URL[] { url };\n\t\tthis.parentClassLoader = new URLClassLoader(urls, classLoader);\n\t\tthis.updatedFiles = new ClassLoaderFiles();\n\t\tthis.reloadClassLoader = new RestartClassLoader(this.parentClassLoader, urls, this.updatedFiles);\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws Exception {\n\t\tthis.reloadClassLoader.close();\n\t\tthis.parentClassLoader.close();\n\t}\n\n\tprivate File createSampleJarFile(File tempDir) throws IOException {\n\t\tFile file = new File(tempDir, \"sample.jar\");\n\t\tJarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(file));\n\t\tjarOutputStream.putNextEntry(new ZipEntry(PACKAGE_PATH + \"/Sample.class\"));\n\t\tStreamUtils.copy(getClass().getResourceAsStream(\"Sample.class\"), jarOutputStream);\n\t\tjarOutputStream.closeEntry();\n\t\tjarOutputStream.putNextEntry(new ZipEntry(PACKAGE_PATH + \"/Sample.txt\"));\n\t\tStreamUtils.copy(\"fromchild\", StandardCharsets.UTF_8, jarOutputStream);\n\t\tjarOutputStream.closeEntry();\n\t\tjarOutputStream.close();\n\t\treturn file;\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid parentMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RestartClassLoader(null, new URL[] {}))\n\t\t\t.withMessageContaining(\"'parent' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid updatedFilesMustNotBeNull() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new RestartClassLoader(this.parentClassLoader, new URL[] {}, null))\n\t\t\t.withMessageContaining(\"'updatedFiles' must not be null\");\n\t}\n\n\t@Test\n\tvoid getResourceFromReloadableUrl() throws Exception {\n\t\tString content = readString(this.reloadClassLoader.getResourceAsStream(PACKAGE_PATH + \"/Sample.txt\"));\n\t\tassertThat(content).startsWith(\"fromchild\");\n\t}\n\n\t@Test\n\tvoid getResourceFromParent() throws Exception {\n\t\tString content = readString(this.reloadClassLoader.getResourceAsStream(PACKAGE_PATH + \"/Parent.txt\"));\n\t\tassertThat(content).startsWith(\"fromparent\");\n\t}\n\n\t@Test\n\tvoid getResourcesFiltersDuplicates() throws Exception {\n\t\tList<URL> resources = toList(this.reloadClassLoader.getResources(PACKAGE_PATH + \"/Sample.txt\"));\n\t\tassertThat(resources).hasSize(1);\n\t}\n\n\t@Test\n\tvoid loadClassFromReloadableUrl() throws Exception {\n\t\tClass<?> loaded = Class.forName(PACKAGE + \".Sample\", false, this.reloadClassLoader);\n\t\tassertThat(loaded.getClassLoader()).isEqualTo(this.reloadClassLoader);\n\t}\n\n\t@Test\n\tvoid loadClassFromParent() throws Exception {\n\t\tClass<?> loaded = Class.forName(PACKAGE + \".SampleParent\", false, this.reloadClassLoader);\n\t\tassertThat(loaded.getClassLoader()).isEqualTo(getClass().getClassLoader());\n\t}\n\n\t@Test\n\tvoid getDeletedResource() {\n\t\tString name = PACKAGE_PATH + \"/Sample.txt\";\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.DELETED, null));\n\t\tassertThat(this.reloadClassLoader.getResource(name)).isNull();\n\t}\n\n\t@Test\n\tvoid getDeletedResourceAsStream() {\n\t\tString name = PACKAGE_PATH + \"/Sample.txt\";\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.DELETED, null));\n\t\tassertThat(this.reloadClassLoader.getResourceAsStream(name)).isNull();\n\t}\n\n\t@Test\n\tvoid getUpdatedResource() throws Exception {\n\t\tString name = PACKAGE_PATH + \"/Sample.txt\";\n\t\tbyte[] bytes = \"abc\".getBytes();\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.MODIFIED, bytes));\n\t\tURL resource = this.reloadClassLoader.getResource(name);\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(FileCopyUtils.copyToByteArray(resource.openStream())).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid getResourcesWithDeleted() throws Exception {\n\t\tString name = PACKAGE_PATH + \"/Sample.txt\";\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.DELETED, null));\n\t\tList<URL> resources = toList(this.reloadClassLoader.getResources(name));\n\t\tassertThat(resources).isEmpty();\n\t}\n\n\t@Test\n\tvoid getResourcesWithUpdated() throws Exception {\n\t\tString name = PACKAGE_PATH + \"/Sample.txt\";\n\t\tbyte[] bytes = \"abc\".getBytes();\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.MODIFIED, bytes));\n\t\tList<URL> resources = toList(this.reloadClassLoader.getResources(name));\n\t\tassertThat(FileCopyUtils.copyToByteArray(resources.get(0).openStream())).isEqualTo(bytes);\n\t}\n\n\t@Test\n\tvoid getDeletedClass() {\n\t\tString name = PACKAGE_PATH + \"/Sample.class\";\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.DELETED, null));\n\t\tassertThatExceptionOfType(ClassNotFoundException.class)\n\t\t\t.isThrownBy(() -> Class.forName(PACKAGE + \".Sample\", false, this.reloadClassLoader));\n\t}\n\n\t@Test\n\tvoid getUpdatedClass() {\n\t\tString name = PACKAGE_PATH + \"/Sample.class\";\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.MODIFIED, new byte[10]));\n\t\tassertThatExceptionOfType(ClassFormatError.class)\n\t\t\t.isThrownBy(() -> Class.forName(PACKAGE + \".Sample\", false, this.reloadClassLoader));\n\t}\n\n\t@Test\n\tvoid getAddedClass() throws Exception {\n\t\tString name = PACKAGE_PATH + \"/SampleParent.class\";\n\t\tbyte[] bytes = FileCopyUtils.copyToByteArray(getClass().getResourceAsStream(\"SampleParent.class\"));\n\t\tthis.updatedFiles.addFile(name, new ClassLoaderFile(Kind.ADDED, bytes));\n\t\tClass<?> loaded = Class.forName(PACKAGE + \".SampleParent\", false, this.reloadClassLoader);\n\t\tassertThat(loaded.getClassLoader()).isEqualTo(this.reloadClassLoader);\n\t}\n\n\t@Test\n\tvoid proxyOnClassFromSystemClassLoaderDoesNotYieldWarning() {\n\t\tProxyFactory pf = new ProxyFactory(new HashMap<>());\n\t\tpf.setProxyTargetClass(true);\n\t\tpf.getProxy(this.reloadClassLoader);\n\t\t// Warning would happen outside the boundary of the test\n\t}\n\n\t@Test\n\tvoid packagePrivateClassLoadedByParentClassLoaderCanBeProxied() throws IOException {\n\t\ttry (RestartClassLoader restartClassLoader = new RestartClassLoader(ExampleTransactional.class.getClassLoader(),\n\t\t\t\tnew URL[] { this.sampleJarFile.toURI().toURL() }, this.updatedFiles)) {\n\t\t\tnew ApplicationContextRunner().withClassLoader(restartClassLoader)\n\t\t\t\t.withUserConfiguration(ProxyConfiguration.class)\n\t\t\t\t.run((context) -> assertThat(context).getBean(ExampleTransactional.class)\n\t\t\t\t\t.matches(AopUtils::isCglibProxy)\n\t\t\t\t\t.extracting(Object::getClass)\n\t\t\t\t\t.extracting(Class::getClassLoader)\n\t\t\t\t\t.isEqualTo(ExampleTransactional.class.getClassLoader()));\n\t\t}\n\t}\n\n\tprivate String readString(InputStream in) throws IOException {\n\t\treturn new String(FileCopyUtils.copyToByteArray(in));\n\t}\n\n\tprivate <T> List<T> toList(Enumeration<T> enumeration) {\n\t\treturn (enumeration != null) ? Collections.list(enumeration) : Collections.emptyList();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAspectJAutoProxy(proxyTargetClass = true)\n\t@EnableTransactionManagement\n\tstatic class ProxyConfiguration {\n\n\t\t@Bean\n\t\tExampleTransactional exampleTransactional() {\n\t\t\treturn new ExampleTransactional();\n\t\t}\n\n\t}\n\n\tstatic class ExampleTransactional implements ExampleInterface {\n\n\t\t@Override\n\t\t@Transactional\n\t\tpublic String doIt() {\n\t\t\treturn \"hello\";\n\t\t}\n\n\t}\n\n\tinterface ExampleInterface {\n\n\t\tString doIt();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/Sample.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\n/**\n * A sample class used to test reloading.\n *\n * @author Phillip Webb\n */\npublic class Sample {\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/classloader/SampleParent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.classloader;\n\n/**\n * A sample class used to test reloading.\n *\n * @author Phillip Webb\n */\npublic class SampleParent {\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/DefaultSourceDirectoryUrlFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DefaultSourceDirectoryUrlFilter}.\n *\n * @author Phillip Webb\n */\nclass DefaultSourceDirectoryUrlFilterTests {\n\n\tprivate static final String SOURCE_ROOT = \"/Users/me/code/some-root/\";\n\n\tprivate static final List<String> COMMON_POSTFIXES;\n\n\tstatic {\n\t\tList<String> postfixes = new ArrayList<>();\n\t\tpostfixes.add(\".jar\");\n\t\tpostfixes.add(\"-1.3.0.jar\");\n\t\tpostfixes.add(\"-1.3.0-SNAPSHOT.jar\");\n\t\tpostfixes.add(\"-1.3.0.BUILD-SNAPSHOT.jar\");\n\t\tpostfixes.add(\"-1.3.0.M1.jar\");\n\t\tpostfixes.add(\"-1.3.0.RC1.jar\");\n\t\tpostfixes.add(\"-1.3.0.RELEASE.jar\");\n\t\tpostfixes.add(\"-1.3.0.Final.jar\");\n\t\tpostfixes.add(\"-1.3.0.GA.jar\");\n\t\tpostfixes.add(\"-1.3.0.0.0.0.jar\");\n\t\tCOMMON_POSTFIXES = Collections.unmodifiableList(postfixes);\n\t}\n\n\tprivate final DefaultSourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();\n\n\t@Test\n\tvoid mavenSourceDirectory() throws Exception {\n\t\tdoTest(\"my-module/target/classes/\");\n\t}\n\n\t@Test\n\tvoid gradleEclipseSourceDirectory() throws Exception {\n\t\tdoTest(\"my-module/bin/\");\n\t}\n\n\t@Test\n\tvoid unusualSourceDirectory() throws Exception {\n\t\tdoTest(\"my-module/something/quite/quite/mad/\");\n\t}\n\n\tprivate void doTest(String sourcePostfix) throws MalformedURLException {\n\t\tdoTest(sourcePostfix, \"my-module\", true);\n\t\tdoTest(sourcePostfix, \"my-module-other\", false);\n\t\tdoTest(sourcePostfix, \"my-module-other-again\", false);\n\t\tdoTest(sourcePostfix, \"my-module.other\", false);\n\t}\n\n\tprivate void doTest(String sourcePostfix, String moduleRoot, boolean expected) throws MalformedURLException {\n\t\tString sourceDirectory = SOURCE_ROOT + sourcePostfix;\n\t\tfor (String postfix : COMMON_POSTFIXES) {\n\t\t\tfor (URL url : getUrls(moduleRoot + postfix)) {\n\t\t\t\tboolean match = this.filter.isMatch(sourceDirectory, url);\n\t\t\t\tassertThat(match).as(url + \" against \" + sourceDirectory).isEqualTo(expected);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate List<URL> getUrls(String name) throws MalformedURLException {\n\t\tList<URL> urls = new ArrayList<>();\n\t\turls.add(new URL(\"file:/some/path/\" + name));\n\t\turls.add(new URL(\"file:/some/path/\" + name + \"!/\"));\n\t\tfor (String postfix : COMMON_POSTFIXES) {\n\t\t\turls.add(new URL(\"jar:file:/some/path/lib-module\" + postfix + \"!/lib/\" + name));\n\t\t\turls.add(new URL(\"jar:file:/some/path/lib-module\" + postfix + \"!/lib/\" + name + \"!/\"));\n\t\t}\n\t\treturn urls;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.server.ServerHttpRequest;\nimport org.springframework.http.server.ServerHttpResponse;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpRestartServerHandler}.\n *\n * @author Phillip Webb\n */\nclass HttpRestartServerHandlerTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid serverMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServerHandler(null))\n\t\t\t.withMessageContaining(\"'server' must not be null\");\n\t}\n\n\t@Test\n\tvoid handleDelegatesToServer() throws Exception {\n\t\tHttpRestartServer server = mock(HttpRestartServer.class);\n\t\tHttpRestartServerHandler handler = new HttpRestartServerHandler(server);\n\t\tServerHttpRequest request = mock(ServerHttpRequest.class);\n\t\tServerHttpResponse response = mock(ServerHttpResponse.class);\n\t\thandler.handle(request, response);\n\t\tthen(server).should().handle(request, response);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/HttpRestartServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectOutputStream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.http.server.ServletServerHttpResponse;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link HttpRestartServer}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass HttpRestartServerTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate RestartServer delegate;\n\n\tprivate HttpRestartServer server;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.server = new HttpRestartServer(this.delegate);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid sourceDirectoryUrlFilterMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((SourceDirectoryUrlFilter) null))\n\t\t\t.withMessageContaining(\"'sourceDirectoryUrlFilter' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid restartServerMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new HttpRestartServer((RestartServer) null))\n\t\t\t.withMessageContaining(\"'restartServer' must not be null\");\n\t}\n\n\t@Test\n\tvoid sendClassLoaderFiles() throws Exception {\n\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tClassLoaderFiles files = new ClassLoaderFiles();\n\t\tfiles.addFile(\"name\", new ClassLoaderFile(Kind.ADDED, new byte[0]));\n\t\tbyte[] bytes = serialize(files);\n\t\trequest.setContent(bytes);\n\t\tthis.server.handle(new ServletServerHttpRequest(request), new ServletServerHttpResponse(response));\n\t\tthen(this.delegate).should()\n\t\t\t.updateAndRestart(\n\t\t\t\t\tassertArg((classLoaderFiles) -> assertThat(classLoaderFiles.getFile(\"name\")).isNotNull()));\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid sendNoContent() throws Exception {\n\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tthis.server.handle(new ServletServerHttpRequest(request), new ServletServerHttpResponse(response));\n\t\tthen(this.delegate).shouldHaveNoInteractions();\n\t\tassertThat(response.getStatus()).isEqualTo(500);\n\n\t}\n\n\t@Test\n\tvoid sendBadData() throws Exception {\n\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\trequest.setContent(new byte[] { 0, 0, 0 });\n\t\tthis.server.handle(new ServletServerHttpRequest(request), new ServletServerHttpResponse(response));\n\t\tthen(this.delegate).shouldHaveNoInteractions();\n\t\tassertThat(response.getStatus()).isEqualTo(500);\n\t}\n\n\tprivate byte[] serialize(Object object) throws IOException {\n\t\tByteArrayOutputStream bos = new ByteArrayOutputStream();\n\t\tObjectOutputStream oos = new ObjectOutputStream(bos);\n\t\toos.writeObject(object);\n\t\toos.close();\n\t\treturn bos.toByteArray();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/server/RestartServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.restart.server;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFile.Kind;\nimport org.springframework.boot.devtools.restart.classloader.ClassLoaderFiles;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link RestartServer}.\n *\n * @author Phillip Webb\n */\nclass RestartServerTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid sourceDirectoryUrlFilterMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RestartServer((SourceDirectoryUrlFilter) null))\n\t\t\t.withMessageContaining(\"'sourceDirectoryUrlFilter' must not be null\");\n\t}\n\n\t@Test\n\tvoid updateAndRestart() throws Exception {\n\t\tURL url1 = new URL(\"file:/proj/module-a.jar!/\");\n\t\tURL url2 = new URL(\"file:/proj/module-b.jar!/\");\n\t\tURL url3 = new URL(\"file:/proj/module-c.jar!/\");\n\t\tURL url4 = new URL(\"file:/proj/module-d.jar!/\");\n\t\tURLClassLoader classLoaderA = new URLClassLoader(new URL[] { url1, url2 });\n\t\tURLClassLoader classLoaderB = new URLClassLoader(new URL[] { url3, url4 }, classLoaderA);\n\t\tSourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();\n\t\tMockRestartServer server = new MockRestartServer(filter, classLoaderB);\n\t\tClassLoaderFiles files = new ClassLoaderFiles();\n\t\tClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, new byte[0]);\n\t\tClassLoaderFile fileB = new ClassLoaderFile(Kind.ADDED, new byte[0]);\n\t\tfiles.addFile(\"my/module-a\", \"ClassA.class\", fileA);\n\t\tfiles.addFile(\"my/module-c\", \"ClassB.class\", fileB);\n\t\tserver.updateAndRestart(files);\n\t\tSet<URL> expectedUrls = new LinkedHashSet<>(Arrays.asList(url1, url3));\n\t\tassertThat(server.restartUrls).isEqualTo(expectedUrls);\n\t\tassertThat(server.restartFiles).isEqualTo(files);\n\t}\n\n\t@Test\n\tvoid updateSetsJarLastModified(@TempDir File directory) throws Exception {\n\t\tlong startTime = System.currentTimeMillis();\n\t\tFile jarFile = new File(directory, \"module-a.jar\");\n\t\tnew FileOutputStream(jarFile).close();\n\t\tjarFile.setLastModified(0);\n\t\tURL url = jarFile.toURI().toURL();\n\t\tURLClassLoader classLoader = new URLClassLoader(new URL[] { url });\n\t\tSourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();\n\t\tMockRestartServer server = new MockRestartServer(filter, classLoader);\n\t\tClassLoaderFiles files = new ClassLoaderFiles();\n\t\tClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, new byte[0]);\n\t\tfiles.addFile(\"my/module-a\", \"ClassA.class\", fileA);\n\t\tserver.updateAndRestart(files);\n\t\tassertThat(jarFile.lastModified()).isGreaterThan(startTime - 1000);\n\t}\n\n\t@Test\n\tvoid updateReplacesLocalFilesWhenPossible(@TempDir File directory) throws Exception {\n\t\t// This is critical for Cloud Foundry support where the application is\n\t\t// run exploded and resources can be found from the servlet root (outside the\n\t\t// classloader)\n\t\tFile classFile = new File(directory, \"ClassA.class\");\n\t\tFileCopyUtils.copy(\"abc\".getBytes(), classFile);\n\t\tURL url = directory.toURI().toURL();\n\t\tURLClassLoader classLoader = new URLClassLoader(new URL[] { url });\n\t\tSourceDirectoryUrlFilter filter = new DefaultSourceDirectoryUrlFilter();\n\t\tMockRestartServer server = new MockRestartServer(filter, classLoader);\n\t\tClassLoaderFiles files = new ClassLoaderFiles();\n\t\tClassLoaderFile fileA = new ClassLoaderFile(Kind.ADDED, \"def\".getBytes());\n\t\tfiles.addFile(\"my/module-a\", \"ClassA.class\", fileA);\n\t\tserver.updateAndRestart(files);\n\t\tassertThat(FileCopyUtils.copyToByteArray(classFile)).isEqualTo(\"def\".getBytes());\n\t}\n\n\tstatic class MockRestartServer extends RestartServer {\n\n\t\tMockRestartServer(SourceDirectoryUrlFilter sourceDirectoryUrlFilter, ClassLoader classLoader) {\n\t\t\tsuper(sourceDirectoryUrlFilter, classLoader);\n\t\t}\n\n\t\tprivate @Nullable Set<URL> restartUrls;\n\n\t\tprivate @Nullable ClassLoaderFiles restartFiles;\n\n\t\t@Override\n\t\tprotected void restart(Set<URL> urls, ClassLoaderFiles files) {\n\t\t\tthis.restartUrls = urls;\n\t\t\tthis.restartFiles = files;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/settings/DevToolsSettingsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.settings;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DevToolsSettings}.\n *\n * @author Phillip Webb\n */\nclass DevToolsSettingsTests {\n\n\tprivate static final String ROOT = DevToolsSettingsTests.class.getPackage().getName().replace('.', '/') + \"/\";\n\n\t@Test\n\tvoid includePatterns() throws Exception {\n\t\tDevToolsSettings settings = DevToolsSettings.load(ROOT + \"spring-devtools-include.properties\");\n\t\tassertThat(settings.isRestartInclude(new URL(\"file://test/a\"))).isTrue();\n\t\tassertThat(settings.isRestartInclude(new URL(\"file://test/b\"))).isTrue();\n\t\tassertThat(settings.isRestartInclude(new URL(\"file://test/c\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid excludePatterns() throws Exception {\n\t\tDevToolsSettings settings = DevToolsSettings.load(ROOT + \"spring-devtools-exclude.properties\");\n\t\tassertThat(settings.isRestartExclude(new URL(\"file://test/a\"))).isTrue();\n\t\tassertThat(settings.isRestartExclude(new URL(\"file://test/b\"))).isTrue();\n\t\tassertThat(settings.isRestartExclude(new URL(\"file://test/c\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid defaultIncludePatterns(@TempDir File tempDir) throws Exception {\n\t\tDevToolsSettings settings = DevToolsSettings.get();\n\t\tassertThat(settings.isRestartExclude(makeUrl(tempDir, \"spring-boot\"))).isTrue();\n\t\tassertThat(settings.isRestartExclude(makeUrl(tempDir, \"spring-boot-autoconfigure\"))).isTrue();\n\t\tassertThat(settings.isRestartExclude(makeUrl(tempDir, \"spring-boot-actuator\"))).isTrue();\n\t\tassertThat(settings.isRestartExclude(makeUrl(tempDir, \"spring-boot-starter\"))).isTrue();\n\t\tassertThat(settings.isRestartExclude(makeUrl(tempDir, \"spring-boot-starter-some-thing\"))).isTrue();\n\t}\n\n\t@Test\n\tvoid propertyDefaults() {\n\t\tDevToolsSettings settings = DevToolsSettings.load(ROOT + \"spring-devtools-defaults.properties\");\n\t\tMap<String, Object> propertyDefaults = settings.getPropertyDefaults();\n\t\tassertThat(propertyDefaults)\n\t\t\t.containsExactlyInAnyOrderEntriesOf(Map.of(\"com.example.a\", \"true\", \"com.example.b\", \"17\"));\n\t}\n\n\tprivate URL makeUrl(File file, String name) throws IOException {\n\t\tfile = new File(file, name);\n\t\tfile = new File(file, \"build\");\n\t\tfile = new File(file, \"classes\");\n\t\tfile.mkdirs();\n\t\treturn file.toURI().toURL();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/test/MockClientHttpRequestFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.devtools.test;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.mock.http.client.MockClientHttpRequest;\nimport org.springframework.mock.http.client.MockClientHttpResponse;\n\n/**\n * Mock {@link ClientHttpRequestFactory}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic class MockClientHttpRequestFactory implements ClientHttpRequestFactory {\n\n\tprivate static final byte[] NO_DATA = {};\n\n\tprivate final AtomicLong seq = new AtomicLong();\n\n\tprivate final Deque<Object> responses = new ArrayDeque<>();\n\n\tprivate final List<MockClientHttpRequest> executedRequests = new ArrayList<>();\n\n\t@Override\n\tpublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {\n\t\treturn new MockRequest(uri, httpMethod);\n\t}\n\n\tpublic void willRespond(HttpStatus... response) {\n\t\tfor (HttpStatus status : response) {\n\t\t\tthis.responses.add(new Response(0, null, status));\n\t\t}\n\t}\n\n\tpublic void willRespond(IOException... response) {\n\t\tfor (IOException exception : response) {\n\t\t\tthis.responses.addLast(exception);\n\t\t}\n\t}\n\n\tpublic void willRespond(String... response) {\n\t\tfor (String payload : response) {\n\t\t\tthis.responses.add(new Response(0, payload.getBytes(), HttpStatus.OK));\n\t\t}\n\t}\n\n\tpublic void willRespondAfterDelay(int delay, HttpStatus status) {\n\t\tthis.responses.add(new Response(delay, null, status));\n\t}\n\n\tpublic List<MockClientHttpRequest> getExecutedRequests() {\n\t\treturn this.executedRequests;\n\t}\n\n\tprivate class MockRequest extends MockClientHttpRequest {\n\n\t\tMockRequest(URI uri, HttpMethod httpMethod) {\n\t\t\tsuper(httpMethod, uri);\n\t\t}\n\n\t\t@Override\n\t\tprotected ClientHttpResponse executeInternal() throws IOException {\n\t\t\tMockClientHttpRequestFactory.this.executedRequests.add(this);\n\t\t\tObject response = MockClientHttpRequestFactory.this.responses.pollFirst();\n\t\t\tif (response instanceof IOException ioException) {\n\t\t\t\tthrow ioException;\n\t\t\t}\n\t\t\tif (response == null) {\n\t\t\t\tresponse = new Response(0, null, HttpStatus.GONE);\n\t\t\t}\n\t\t\treturn ((Response) response).asHttpResponse(MockClientHttpRequestFactory.this.seq);\n\t\t}\n\n\t}\n\n\tstatic class Response {\n\n\t\tprivate final int delay;\n\n\t\tprivate final byte @Nullable [] payload;\n\n\t\tprivate final HttpStatus status;\n\n\t\tResponse(int delay, byte @Nullable [] payload, HttpStatus status) {\n\t\t\tthis.delay = delay;\n\t\t\tthis.payload = payload;\n\t\t\tthis.status = status;\n\t\t}\n\n\t\tClientHttpResponse asHttpResponse(AtomicLong seq) {\n\t\t\tMockClientHttpResponse httpResponse = new MockClientHttpResponse(\n\t\t\t\t\t(this.payload != null) ? this.payload : NO_DATA, this.status);\n\t\t\twaitForDelay();\n\t\t\tif (this.payload != null) {\n\t\t\t\thttpResponse.getHeaders().setContentLength(this.payload.length);\n\t\t\t\thttpResponse.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);\n\t\t\t\thttpResponse.getHeaders().add(\"x-seq\", Long.toString(seq.incrementAndGet()));\n\t\t\t}\n\t\t\treturn httpResponse;\n\t\t}\n\n\t\tprivate void waitForDelay() {\n\t\t\tif (this.delay > 0) {\n\t\t\t\ttry {\n\t\t\t\t\tThread.sleep(this.delay);\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/test/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.devtools.test;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/loader/launch/FakeJarLauncher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.loader.launch;\n\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Fake launcher in the {@code org.springframework.boot.loader.launch} package used in\n * {@code MainMethodTests}.\n *\n * @author Phillip Webb\n */\npublic final class FakeJarLauncher {\n\n\tpublic static @Nullable Consumer<String[]> action;\n\n\tprivate FakeJarLauncher() {\n\t}\n\n\tpublic static void main(String... args) {\n\t\tif (action != null) {\n\t\t\taction.accept(args);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/java/org/springframework/boot/loader/launch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.loader.launch;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/env/spring-devtools.yaml",
    "content": "abc:\n  xyz: def\nbing: blip"
  },
  {
    "path": "module/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/restart/classloader/Parent.txt",
    "content": "fromparent\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/settings/spring-devtools-defaults.properties",
    "content": "defaults.com.example.a=true\ndefaults.com.example.b=17\n\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/settings/spring-devtools-exclude.properties",
    "content": "restart.exclude.a=a.*\nrestart.exclude.b=b.*\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/resources/org/springframework/boot/devtools/settings/spring-devtools-include.properties",
    "content": "restart.include.a=a.*\nrestart.include.b=b.*\n"
  },
  {
    "path": "module/spring-boot-devtools/src/test/resources/user-home/.spring-boot-devtools.properties",
    "content": "spring.freemarker.cache=true\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Elasticsearch\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"co.elastic.clients:elasticsearch-rest5-client\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-jsonb\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(\"co.elastic.clients:elasticsearch-java\")\n\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"jakarta.json.bind:jakarta.json.bind-api\")\n\toptional(\"org.testcontainers:testcontainers-elasticsearch\")\n\toptional(\"tools.jackson.core:jackson-databind\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":module:spring-boot-jackson\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-elasticsearch\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\t\n\tdockerTestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-jsonb\"))\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchClientAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.util.Map;\n\nimport co.elastic.clients.elasticsearch.ElasticsearchClient;\nimport co.elastic.clients.elasticsearch.core.GetResponse;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ElasticsearchClientAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass ElasticsearchClientAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,\n\t\t\t\tElasticsearchRestClientAutoConfiguration.class, ElasticsearchClientAutoConfiguration.class));\n\n\t@Test\n\tvoid reactiveClientCanQueryElasticsearchNode() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.uris=\" + elasticsearch.getHttpHostAddress(),\n\t\t\t\t\t\"spring.elasticsearch.connection-timeout=120s\", \"spring.elasticsearch.socket-timeout=120s\")\n\t\t\t.run((context) -> {\n\t\t\t\tElasticsearchClient client = context.getBean(ElasticsearchClient.class);\n\t\t\t\tclient.index((b) -> b.index(\"foo\").id(\"1\").document(Map.of(\"a\", \"alpha\", \"b\", \"bravo\")));\n\t\t\t\tGetResponse<Object> response = client.get((b) -> b.index(\"foo\").id(\"1\"), Object.class);\n\t\t\t\tassertThat(response).isNotNull();\n\t\t\t\tassertThat(response.found()).isTrue();\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchRestClientAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.io.InputStream;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Request;\nimport co.elastic.clients.transport.rest5_client.low_level.Response;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ElasticsearchRestClientAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Vedran Pavic\n * @author Evgeniy Cheban\n * @author Filip Hrisafov\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass ElasticsearchRestClientAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));\n\n\t@Test\n\tvoid restClientCanQueryElasticsearchNode() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.uris=\" + elasticsearch.getHttpHostAddress(),\n\t\t\t\t\t\"spring.elasticsearch.connection-timeout=120s\", \"spring.elasticsearch.socket-timeout=120s\")\n\t\t\t.run((context) -> {\n\t\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\t\tRequest index = new Request(\"PUT\", \"/test/_doc/2\");\n\t\t\t\tindex.setJsonEntity(\"{\" + \"  \\\"a\\\": \\\"alpha\\\",\" + \"  \\\"b\\\": \\\"bravo\\\"\" + \"}\");\n\t\t\t\tclient.performRequest(index);\n\t\t\t\tRequest getRequest = new Request(\"GET\", \"/test/_doc/2\");\n\t\t\t\tResponse response = client.performRequest(getRequest);\n\t\t\t\ttry (InputStream input = response.getEntity().getContent()) {\n\t\t\t\t\tJsonNode result = new ObjectMapper().readTree(input);\n\t\t\t\t\tassertThat(result.path(\"found\").asBoolean()).isTrue();\n\t\t\t\t}\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/java/org/springframework/boot/elasticsearch/docker/compose/ElasticsearchDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node.Protocol;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ElasticsearchDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ElasticsearchDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"elasticsearch-compose.yaml\", image = TestImage.ELASTICSEARCH_9)\n\tvoid runCreatesConnectionDetails(ElasticsearchConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails, Protocol.HTTP);\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"elasticsearch-ssl-compose.yaml\", image = TestImage.ELASTICSEARCH_9,\n\t\t\tadditionalResources = { \"ca.crt\", \"server.crt\", \"server.key\", \"client.crt\", \"client.key\" })\n\tvoid runWithSslCreatesConnectionDetails(ElasticsearchConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails, Protocol.HTTPS);\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\tprivate void assertConnectionDetails(ElasticsearchConnectionDetails connectionDetails, Protocol expectedProtocol) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"elastic\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getPathPrefix()).isNull();\n\t\tassertThat(connectionDetails.getNodes()).hasSize(1);\n\t\tNode node = connectionDetails.getNodes().get(0);\n\t\tassertThat(node.hostname()).isNotNull();\n\t\tassertThat(node.port()).isGreaterThan(0);\n\t\tassertThat(node.protocol()).isEqualTo(expectedProtocol);\n\t\tassertThat(node.username()).isEqualTo(\"elastic\");\n\t\tassertThat(node.password()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/java/org/springframework/boot/elasticsearch/testcontainers/ElasticsearchContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.testcontainers;\n\nimport java.io.IOException;\nimport java.time.Duration;\n\nimport co.elastic.clients.elasticsearch.ElasticsearchClient;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.ElasticsearchContainer9;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ElasticsearchContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass ElasticsearchContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ElasticsearchContainer elasticsearch = new ElasticsearchContainer9().withStartupAttempts(5)\n\t\t.withStartupTimeout(Duration.ofMinutes(10));\n\n\t@Autowired(required = false)\n\tprivate ElasticsearchConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate ElasticsearchClient client;\n\n\t@Test\n\tvoid connectionCanBeMadeToElasticsearchContainer() throws IOException {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tassertThat(this.client.cluster().health().numberOfNodes()).isEqualTo(1);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ ElasticsearchClientAutoConfiguration.class,\n\t\t\tElasticsearchRestClientAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/elasticsearch-compose.yaml",
    "content": "services:\n  elasticsearch:\n    image: '{imageName}'\n    environment:\n      - 'ELASTIC_PASSWORD=secret'\n      - 'ES_JAVA_OPTS=-Xmx512m'\n      - 'xpack.security.enabled=false'\n      - 'discovery.type=single-node'\n    ports:\n      - '9200'\n      - '9300'\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/elasticsearch-ssl-compose.yaml",
    "content": "services:\n  elasticsearch:\n    image: '{imageName}'\n    environment:\n      - 'ELASTIC_PASSWORD=secret'\n      - 'ES_JAVA_OPTS=-Xmx512m'\n      - 'xpack.security.enabled=true'\n      - 'xpack.security.http.ssl.enabled=true'\n      - 'xpack.security.http.ssl.key=/usr/share/elasticsearch/config/ssl/server.key'\n      - 'xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/ssl/server.crt'\n      - 'xpack.security.http.ssl.certificate_authorities=/usr/share/elasticsearch/config/ssl/ca.crt'\n      - 'xpack.security.http.ssl.client_authentication=required'\n      - 'discovery.type=single-node'\n    ports:\n      - '9200'\n      - '9300'\n    healthcheck:\n      test: [\"CMD-SHELL\", \"curl -fk --cert /usr/share/elasticsearch/config/ssl/client.crt \\\n      --key /usr/share/elasticsearch/config/ssl/client.key \\\n      -u elastic:secret https://localhost:9200/_cluster/health || exit 1\"]\n      interval: 5s\n      retries: 5\n      start_period: 60s\n      timeout: 10s\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'\n      - 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\n    volumes:\n      - ./server.key:/usr/share/elasticsearch/config/ssl/server.key\n      - ./server.crt:/usr/share/elasticsearch/config/ssl/server.crt\n      - ./ca.crt:/usr/share/elasticsearch/config/ssl/ca.crt\n      - ./client.key:/usr/share/elasticsearch/config/ssl/client.key\n      - ./client.crt:/usr/share/elasticsearch/config/ssl/client.crt"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/org/springframework/boot/elasticsearch/docker/compose/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport co.elastic.clients.elasticsearch.ElasticsearchClient;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientConfigurations.ElasticsearchClientConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientConfigurations.ElasticsearchTransportConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientConfigurations.JsonpMapperConfiguration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch's Java client.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(after = { ElasticsearchRestClientAutoConfiguration.class },\n\t\tafterName = { \"org.springframework.boot.jsonb.autoconfigure.JsonbAutoConfiguration\" })\n@ConditionalOnBean(Rest5Client.class)\n@ConditionalOnClass(ElasticsearchClient.class)\n@Import({ JsonpMapperConfiguration.class, ElasticsearchTransportConfiguration.class,\n\t\tElasticsearchClientConfiguration.class })\npublic final class ElasticsearchClientAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchClientConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport co.elastic.clients.elasticsearch.ElasticsearchClient;\nimport co.elastic.clients.json.JsonpMapper;\nimport co.elastic.clients.json.SimpleJsonpMapper;\nimport co.elastic.clients.json.jackson.Jackson3JsonpMapper;\nimport co.elastic.clients.json.jackson.JacksonJsonpMapper;\nimport co.elastic.clients.json.jsonb.JsonbJsonpMapper;\nimport co.elastic.clients.transport.ElasticsearchTransport;\nimport co.elastic.clients.transport.rest5_client.Rest5ClientOptions;\nimport co.elastic.clients.transport.rest5_client.Rest5ClientTransport;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport jakarta.json.bind.Jsonb;\nimport jakarta.json.spi.JsonProvider;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Configurations for import into {@link ElasticsearchClientAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ElasticsearchClientConfigurations {\n\n\t@Import({ JacksonJsonpMapperConfiguration.class, Jackson2JsonpMapperConfiguration.class,\n\t\t\tJsonbJsonpMapperConfiguration.class, SimpleJsonpMapperConfiguration.class })\n\tstatic class JsonpMapperConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(JsonpMapper.class)\n\t@ConditionalOnClass(JsonMapper.class)\n\tstatic class JacksonJsonpMapperConfiguration {\n\n\t\t@Bean\n\t\tJackson3JsonpMapper jacksonJsonpMapper() {\n\t\t\treturn new Jackson3JsonpMapper();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(JsonpMapper.class)\n\t@ConditionalOnClass(ObjectMapper.class)\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tstatic class Jackson2JsonpMapperConfiguration {\n\n\t\t@Bean\n\t\tJacksonJsonpMapper jacksonJsonpMapper() {\n\t\t\treturn new JacksonJsonpMapper();\n\t\t}\n\n\t}\n\n\t@ConditionalOnMissingBean(JsonpMapper.class)\n\t@ConditionalOnBean(Jsonb.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JsonbJsonpMapperConfiguration {\n\n\t\t@Bean\n\t\tJsonbJsonpMapper jsonbJsonpMapper(Jsonb jsonb) {\n\t\t\treturn new JsonbJsonpMapper(JsonProvider.provider(), jsonb);\n\t\t}\n\n\t}\n\n\t@ConditionalOnMissingBean(JsonpMapper.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleJsonpMapperConfiguration {\n\n\t\t@Bean\n\t\tSimpleJsonpMapper simpleJsonpMapper() {\n\t\t\treturn new SimpleJsonpMapper();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(ElasticsearchTransport.class)\n\tstatic class ElasticsearchTransportConfiguration {\n\n\t\t@Bean\n\t\tRest5ClientTransport restClientTransport(Rest5Client restClient, JsonpMapper jsonMapper,\n\t\t\t\tObjectProvider<Rest5ClientOptions> restClientOptions) {\n\t\t\treturn new Rest5ClientTransport(restClient, jsonMapper, restClientOptions.getIfAvailable());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ElasticsearchTransport.class)\n\tstatic class ElasticsearchClientConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tElasticsearchClient elasticsearchClient(ElasticsearchTransport transport) {\n\t\t\treturn new ElasticsearchClient(transport);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to an Elasticsearch service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface ElasticsearchConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * List of the Elasticsearch nodes to use.\n\t * @return list of the Elasticsearch nodes to use\n\t */\n\tList<Node> getNodes();\n\n\t/**\n\t * Username for authentication with Elasticsearch.\n\t * @return username for authentication with Elasticsearch or {@code null}\n\t */\n\tdefault @Nullable String getUsername() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Password for authentication with Elasticsearch.\n\t * @return password for authentication with Elasticsearch or {@code null}\n\t */\n\tdefault @Nullable String getPassword() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * API key for authentication with Elasticsearch.\n\t * @return the API key for authentication with Elasticsearch or {@code null}\n\t */\n\tdefault @Nullable String getApiKey() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Prefix added to the path of every request sent to Elasticsearch.\n\t * @return prefix added to the path of every request sent to Elasticsearch or\n\t * {@code null}\n\t */\n\tdefault @Nullable String getPathPrefix() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * An Elasticsearch node.\n\t *\n\t * @param hostname the hostname\n\t * @param port the port\n\t * @param protocol the protocol\n\t * @param username the username or {@code null}\n\t * @param password the password or {@code null}\n\t */\n\trecord Node(String hostname, int port, Node.Protocol protocol, @Nullable String username,\n\t\t\t@Nullable String password) {\n\n\t\tpublic Node(String host, int port, Node.Protocol protocol) {\n\t\t\tthis(host, port, protocol, null, null);\n\t\t}\n\n\t\tURI toUri() {\n\t\t\ttry {\n\t\t\t\treturn new URI(this.protocol.getScheme(), userInfo(), this.hostname, this.port, null, null, null);\n\t\t\t}\n\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Can't construct URI\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable String userInfo() {\n\t\t\tif (this.username == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn (this.password != null) ? (this.username + \":\" + this.password) : this.username;\n\t\t}\n\n\t\t/**\n\t\t * Connection protocol.\n\t\t */\n\t\tpublic enum Protocol {\n\n\t\t\t/**\n\t\t\t * HTTP.\n\t\t\t */\n\t\t\tHTTP(\"http\"),\n\n\t\t\t/**\n\t\t\t * HTTPS.\n\t\t\t */\n\t\t\tHTTPS(\"https\");\n\n\t\t\tprivate final String scheme;\n\n\t\t\tProtocol(String scheme) {\n\t\t\t\tthis.scheme = scheme;\n\t\t\t}\n\n\t\t\tString getScheme() {\n\t\t\t\treturn this.scheme;\n\t\t\t}\n\n\t\t\tstatic Protocol forScheme(String scheme) {\n\t\t\t\tfor (Protocol protocol : values()) {\n\t\t\t\t\tif (protocol.scheme.equals(scheme)) {\n\t\t\t\t\t\treturn protocol;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthrow new IllegalArgumentException(\"Unknown scheme '\" + scheme + \"'\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Elasticsearch.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.elasticsearch\")\npublic class ElasticsearchProperties {\n\n\t/**\n\t * List of the Elasticsearch instances to use.\n\t */\n\tprivate List<String> uris = new ArrayList<>(Collections.singletonList(\"http://localhost:9200\"));\n\n\t/**\n\t * Username for authentication with Elasticsearch.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Password for authentication with Elasticsearch.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * API key for authentication with Elasticsearch.\n\t */\n\tprivate @Nullable String apiKey;\n\n\t/**\n\t * Connection timeout used when communicating with Elasticsearch.\n\t */\n\tprivate Duration connectionTimeout = Duration.ofSeconds(1);\n\n\t/**\n\t * Socket timeout used when communicating with Elasticsearch.\n\t */\n\tprivate Duration socketTimeout = Duration.ofSeconds(30);\n\n\t/**\n\t * Whether to enable socket keep alive between client and Elasticsearch.\n\t */\n\tprivate boolean socketKeepAlive = true;\n\n\t/**\n\t * Prefix added to the path of every request sent to Elasticsearch.\n\t */\n\tprivate @Nullable String pathPrefix;\n\n\tprivate final Restclient restclient = new Restclient();\n\n\tpublic List<String> getUris() {\n\t\treturn this.uris;\n\t}\n\n\tpublic void setUris(List<String> uris) {\n\t\tthis.uris = uris;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable String getApiKey() {\n\t\treturn this.apiKey;\n\t}\n\n\tpublic void setApiKey(@Nullable String apiKey) {\n\t\tthis.apiKey = apiKey;\n\t}\n\n\tpublic Duration getConnectionTimeout() {\n\t\treturn this.connectionTimeout;\n\t}\n\n\tpublic void setConnectionTimeout(Duration connectionTimeout) {\n\t\tthis.connectionTimeout = connectionTimeout;\n\t}\n\n\tpublic Duration getSocketTimeout() {\n\t\treturn this.socketTimeout;\n\t}\n\n\tpublic void setSocketTimeout(Duration socketTimeout) {\n\t\tthis.socketTimeout = socketTimeout;\n\t}\n\n\tpublic boolean isSocketKeepAlive() {\n\t\treturn this.socketKeepAlive;\n\t}\n\n\tpublic void setSocketKeepAlive(boolean socketKeepAlive) {\n\t\tthis.socketKeepAlive = socketKeepAlive;\n\t}\n\n\tpublic @Nullable String getPathPrefix() {\n\t\treturn this.pathPrefix;\n\t}\n\n\tpublic void setPathPrefix(@Nullable String pathPrefix) {\n\t\tthis.pathPrefix = pathPrefix;\n\t}\n\n\tpublic Restclient getRestclient() {\n\t\treturn this.restclient;\n\t}\n\n\tpublic static class Restclient {\n\n\t\tprivate final Sniffer sniffer = new Sniffer();\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tpublic Sniffer getSniffer() {\n\t\t\treturn this.sniffer;\n\t\t}\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic static class Sniffer {\n\n\t\t\t/**\n\t\t\t * Whether the sniffer is enabled.\n\t\t\t */\n\t\t\tprivate boolean enabled;\n\n\t\t\t/**\n\t\t\t * Interval between consecutive ordinary sniff executions.\n\t\t\t */\n\t\t\tprivate Duration interval = Duration.ofMinutes(5);\n\n\t\t\t/**\n\t\t\t * Delay of a sniff execution scheduled after a failure.\n\t\t\t */\n\t\t\tprivate Duration delayAfterFailure = Duration.ofMinutes(1);\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic Duration getInterval() {\n\t\t\t\treturn this.interval;\n\t\t\t}\n\n\t\t\tpublic void setInterval(Duration interval) {\n\t\t\t\tthis.interval = interval;\n\t\t\t}\n\n\t\t\tpublic Duration getDelayAfterFailure() {\n\t\t\t\treturn this.delayAfterFailure;\n\t\t\t}\n\n\t\t\tpublic void setDelayAfterFailure(Duration delayAfterFailure) {\n\t\t\t\tthis.delayAfterFailure = delayAfterFailure;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Ssl {\n\n\t\t\t/**\n\t\t\t * SSL bundle name.\n\t\t\t */\n\t\t\tprivate @Nullable String bundle;\n\n\t\t\tpublic @Nullable String getBundle() {\n\t\t\t\treturn this.bundle;\n\t\t\t}\n\n\t\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\t\tthis.bundle = bundle;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchRestClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientConfigurations.RestClientConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientConfigurations.RestClientSnifferConfiguration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch REST clients.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = SslAutoConfiguration.class)\n@ConditionalOnClass(Rest5ClientBuilder.class)\n@EnableConfigurationProperties(ElasticsearchProperties.class)\n@Import({ RestClientBuilderConfiguration.class, RestClientConfiguration.class, RestClientSnifferConfiguration.class })\npublic final class ElasticsearchRestClientAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchRestClientConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport javax.net.ssl.SSLContext;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;\nimport co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer;\nimport co.elastic.clients.transport.rest5_client.low_level.sniffer.SnifferBuilder;\nimport org.apache.hc.client5.http.auth.AuthScope;\nimport org.apache.hc.client5.http.auth.Credentials;\nimport org.apache.hc.client5.http.auth.UsernamePasswordCredentials;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;\nimport org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\nimport org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;\nimport org.apache.hc.client5.http.ssl.NoopHostnameVerifier;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.message.BasicHeader;\nimport org.apache.hc.core5.reactor.IOReactorConfig;\nimport org.apache.hc.core5.reactor.ssl.SSLBufferMode;\nimport org.apache.hc.core5.util.Timeout;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node.Protocol;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchProperties.Restclient.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Elasticsearch rest client configurations.\n *\n * @author Stephane Nicoll\n * @author Filip Hrisafov\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Laura Trotta\n */\nclass ElasticsearchRestClientConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(Rest5ClientBuilder.class)\n\tstatic class RestClientBuilderConfiguration {\n\n\t\tprivate final ElasticsearchProperties properties;\n\n\t\tRestClientBuilderConfiguration(ElasticsearchProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ElasticsearchConnectionDetails.class)\n\t\tPropertiesElasticsearchConnectionDetails elasticsearchConnectionDetails(ObjectProvider<SslBundles> sslBundles) {\n\t\t\treturn new PropertiesElasticsearchConnectionDetails(this.properties, sslBundles.getIfAvailable());\n\t\t}\n\n\t\t@Bean\n\t\tRest5ClientBuilderCustomizer defaultRestClientBuilderCustomizer(\n\t\t\t\tElasticsearchConnectionDetails connectionDetails) {\n\t\t\treturn new DefaultRest5ClientBuilderCustomizer(this.properties, connectionDetails);\n\t\t}\n\n\t\t@Bean\n\t\tRest5ClientBuilder elasticsearchRestClientBuilder(ElasticsearchConnectionDetails connectionDetails,\n\t\t\t\tObjectProvider<Rest5ClientBuilderCustomizer> builderCustomizers) {\n\t\t\tRest5ClientBuilder builder = Rest5Client.builder(connectionDetails.getNodes()\n\t\t\t\t.stream()\n\t\t\t\t.map((node) -> new HttpHost(node.protocol().getScheme(), node.hostname(), node.port()))\n\t\t\t\t.toArray(HttpHost[]::new));\n\t\t\tif (connectionDetails.getApiKey() != null) {\n\t\t\t\tbuilder.setDefaultHeaders(\n\t\t\t\t\t\tnew Header[] { new BasicHeader(\"Authorization\", \"ApiKey \" + connectionDetails.getApiKey()) });\n\t\t\t}\n\t\t\tbuilder.setHttpClientConfigCallback((httpClientBuilder) -> builderCustomizers.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(httpClientBuilder)));\n\t\t\tbuilder.setConnectionManagerCallback((connectionManagerBuilder) -> builderCustomizers.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(connectionManagerBuilder)));\n\t\t\tbuilder.setConnectionConfigCallback((connectionConfigBuilder) -> builderCustomizers.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(connectionConfigBuilder)));\n\t\t\tbuilder.setRequestConfigCallback((requestConfigBuilder) -> builderCustomizers.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(requestConfigBuilder)));\n\t\t\tString pathPrefix = connectionDetails.getPathPrefix();\n\t\t\tif (pathPrefix != null) {\n\t\t\t\tbuilder.setPathPrefix(pathPrefix);\n\t\t\t}\n\t\t\tbuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(Rest5Client.class)\n\tstatic class RestClientConfiguration {\n\n\t\t@Bean\n\t\tRest5Client elasticsearchRestClient(Rest5ClientBuilder restClientBuilder) {\n\t\t\treturn restClientBuilder.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(Rest5Client.class)\n\t@ConditionalOnProperty(name = \"spring.elasticsearch.restclient.sniffer.enabled\")\n\tstatic class RestClientSnifferConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSniffer elasticsearchSniffer(Rest5Client client, ElasticsearchProperties properties) {\n\t\t\tSnifferBuilder builder = Sniffer.builder(client);\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tDuration interval = properties.getRestclient().getSniffer().getInterval();\n\t\t\tmap.from(interval).asInt(Duration::toMillis).to(builder::setSniffIntervalMillis);\n\t\t\tDuration delayAfterFailure = properties.getRestclient().getSniffer().getDelayAfterFailure();\n\t\t\tmap.from(delayAfterFailure).asInt(Duration::toMillis).to(builder::setSniffAfterFailureDelayMillis);\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\tstatic class DefaultRest5ClientBuilderCustomizer implements Rest5ClientBuilderCustomizer, Ordered {\n\n\t\tprivate final ElasticsearchProperties properties;\n\n\t\tprivate final ElasticsearchConnectionDetails connectionDetails;\n\n\t\tDefaultRest5ClientBuilderCustomizer(ElasticsearchProperties properties,\n\t\t\t\tElasticsearchConnectionDetails connectionDetails) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.connectionDetails = connectionDetails;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(Rest5ClientBuilder restClientBuilder) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(HttpAsyncClientBuilder httpClientBuilder) {\n\t\t\thttpClientBuilder\n\t\t\t\t.setDefaultCredentialsProvider(new ConnectionDetailsCredentialsProvider(this.connectionDetails));\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this.properties::isSocketKeepAlive)\n\t\t\t\t.to((keepAlive) -> httpClientBuilder\n\t\t\t\t\t.setIOReactorConfig(IOReactorConfig.custom().setSoKeepAlive(keepAlive).build()));\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ConnectionConfig.Builder connectionConfigBuilder) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this.properties::getConnectionTimeout)\n\t\t\t\t.as(Timeout::of)\n\t\t\t\t.to(connectionConfigBuilder::setConnectTimeout);\n\t\t\tmap.from(this.properties::getSocketTimeout).as(Timeout::of).to(connectionConfigBuilder::setSocketTimeout);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder) {\n\t\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\t\tif (sslBundle != null) {\n\t\t\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\t\t\tSslOptions sslOptions = sslBundle.getOptions();\n\t\t\t\tDefaultClientTlsStrategy tlsStrategy = new DefaultClientTlsStrategy(sslContext,\n\t\t\t\t\t\tsslOptions.getEnabledProtocols(), sslOptions.getCiphers(), SSLBufferMode.STATIC,\n\t\t\t\t\t\tNoopHostnameVerifier.INSTANCE);\n\t\t\t\tconnectionManagerBuilder.setTlsStrategy(tlsStrategy);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t}\n\n\tprivate static class ConnectionDetailsCredentialsProvider extends BasicCredentialsProvider {\n\n\t\tConnectionDetailsCredentialsProvider(ElasticsearchConnectionDetails connectionDetails) {\n\t\t\tString username = connectionDetails.getUsername();\n\t\t\tif (StringUtils.hasText(username)) {\n\t\t\t\tString password = connectionDetails.getPassword();\n\t\t\t\tchar[] passwordChars = StringUtils.hasText(password) ? password.toCharArray() : null;\n\t\t\t\tCredentials credentials = new UsernamePasswordCredentials(username, passwordChars);\n\t\t\t\tsetCredentials(new AuthScope(null, -1), credentials);\n\t\t\t}\n\t\t\tStream<URI> uris = getUris(connectionDetails);\n\t\t\turis.filter(this::hasUserInfo).forEach(this::addUserInfoCredentials);\n\t\t}\n\n\t\tprivate Stream<URI> getUris(ElasticsearchConnectionDetails connectionDetails) {\n\t\t\treturn connectionDetails.getNodes().stream().map(Node::toUri);\n\t\t}\n\n\t\tprivate boolean hasUserInfo(@Nullable URI uri) {\n\t\t\treturn uri != null && StringUtils.hasLength(uri.getUserInfo());\n\t\t}\n\n\t\tprivate void addUserInfoCredentials(URI uri) {\n\t\t\tAuthScope authScope = new AuthScope(uri.getHost(), uri.getPort());\n\t\t\tCredentials credentials = createUserInfoCredentials(uri.getUserInfo());\n\t\t\tsetCredentials(authScope, credentials);\n\t\t}\n\n\t\tprivate Credentials createUserInfoCredentials(String userInfo) {\n\t\t\tint delimiter = userInfo.indexOf(\":\");\n\t\t\tif (delimiter == -1) {\n\t\t\t\treturn new UsernamePasswordCredentials(userInfo, null);\n\t\t\t}\n\t\t\tString username = userInfo.substring(0, delimiter);\n\t\t\tString password = userInfo.substring(delimiter + 1);\n\t\t\treturn new UsernamePasswordCredentials(username, password.toCharArray());\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link ElasticsearchProperties} to {@link ElasticsearchConnectionDetails}.\n\t */\n\tstatic class PropertiesElasticsearchConnectionDetails implements ElasticsearchConnectionDetails {\n\n\t\tprivate final ElasticsearchProperties properties;\n\n\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\tPropertiesElasticsearchConnectionDetails(ElasticsearchProperties properties, @Nullable SslBundles sslBundles) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.sslBundles = sslBundles;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getNodes() {\n\t\t\treturn this.properties.getUris().stream().map(this::createNode).toList();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.properties.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getApiKey() {\n\t\t\treturn this.properties.getApiKey();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPathPrefix() {\n\t\t\treturn this.properties.getPathPrefix();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\tSsl ssl = this.properties.getRestclient().getSsl();\n\t\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate Node createNode(String uri) {\n\t\t\tif (!(uri.startsWith(\"http://\") || uri.startsWith(\"https://\"))) {\n\t\t\t\turi = \"http://\" + uri;\n\t\t\t}\n\t\t\treturn createNode(URI.create(uri));\n\t\t}\n\n\t\tprivate Node createNode(URI uri) {\n\t\t\tString userInfo = uri.getUserInfo();\n\t\t\tProtocol protocol = Protocol.forScheme(uri.getScheme());\n\t\t\tif (!StringUtils.hasLength(userInfo)) {\n\t\t\t\treturn new Node(uri.getHost(), uri.getPort(), protocol, null, null);\n\t\t\t}\n\t\t\tint separatorIndex = userInfo.indexOf(':');\n\t\t\tif (separatorIndex == -1) {\n\t\t\t\treturn new Node(uri.getHost(), uri.getPort(), protocol, userInfo, null);\n\t\t\t}\n\t\t\tString[] components = userInfo.split(\":\");\n\t\t\treturn new Node(uri.getHost(), uri.getPort(), protocol, components[0],\n\t\t\t\t\t(components.length > 1) ? components[1] : \"\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/Rest5ClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Rest5ClientBuilder} to fine-tune its auto-configuration before it creates a\n * {@link Rest5Client}.\n *\n * @author Brian Clozel\n * @author Vedran Pavic\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface Rest5ClientBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link Rest5ClientBuilder}.\n\t * <p>\n\t * Possibly overrides customizations made with the {@code \"spring.elasticsearch.rest\"}\n\t * configuration properties namespace. For more targeted changes, see:\n\t * <ul>\n\t * <li>{@link #customize(HttpAsyncClientBuilder)}</li>\n\t * <li>{@link #customize(RequestConfig.Builder)}</li>\n\t * <li>{@link #customize(PoolingAsyncClientConnectionManagerBuilder)}</li>\n\t * <li>{@link #customize(ConnectionConfig.Builder)}</li>\n\t * </ul>\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(Rest5ClientBuilder builder);\n\n\t/**\n\t * Customize the {@link HttpAsyncClientBuilder}. Unlike\n\t * {@link Rest5ClientBuilder#setHttpClientConfigCallback(Consumer)}, implementing this\n\t * method does not replace other customization of the HTTP client builder.\n\t * @param httpAsyncClientBuilder the HTTP client builder\n\t */\n\tdefault void customize(HttpAsyncClientBuilder httpAsyncClientBuilder) {\n\t}\n\n\t/**\n\t * Customize the {@link org.apache.hc.client5.http.config.RequestConfig.Builder}.\n\t * Unlike {@link Rest5ClientBuilder#setRequestConfigCallback(Consumer)}, implementing\n\t * this method does not replace other customization of the request config builder.\n\t * @param requestConfigBuilder the request config builder\n\t */\n\tdefault void customize(RequestConfig.Builder requestConfigBuilder) {\n\t}\n\n\t/**\n\t * Customize the {@link PoolingAsyncClientConnectionManagerBuilder}. Unlike\n\t * {@link Rest5ClientBuilder#setConnectionManagerCallback(Consumer)}, implementing\n\t * this method does not replace other customization of the connection manager builder.\n\t * @param connectionManagerBuilder the connection manager builder\n\t */\n\tdefault void customize(PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder) {\n\t}\n\n\t/**\n\t * Customize the {@link org.apache.hc.client5.http.config.ConnectionConfig.Builder}.\n\t * Unlike {@link Rest5ClientBuilder#setConnectionConfigCallback(Consumer)},\n\t * implementing this method does not replace other customization of the connection\n\t * config builder.\n\t * @param connectionConfigBuilder the connection config builder\n\t */\n\tdefault void customize(ConnectionConfig.Builder connectionConfigBuilder) {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/health/ElasticsearchRestHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure.health;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.health.ElasticsearchRestClientHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link ElasticsearchRestClientHealthIndicator}.\n *\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(after = ElasticsearchRestClientAutoConfiguration.class)\n@ConditionalOnClass({ Rest5Client.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(Rest5Client.class)\n@ConditionalOnEnabledHealthIndicator(\"elasticsearch\")\npublic final class ElasticsearchRestHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, Rest5Client> {\n\n\tElasticsearchRestHealthContributorAutoConfiguration() {\n\t\tsuper(ElasticsearchRestClientHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"elasticsearchHealthIndicator\", \"elasticsearchHealthContributor\" })\n\tHealthContributor elasticsearchHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, Rest5Client.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Elasticsearch health.\n */\n@NullMarked\npackage org.springframework.boot.elasticsearch.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Elasticsearch client.\n */\n@NullMarked\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/docker/compose/ElasticsearchDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.docker.compose;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node.Protocol;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link ElasticsearchConnectionDetails} for an {@code elasticsearch} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ElasticsearchDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<ElasticsearchConnectionDetails> {\n\n\tprivate static final int ELASTICSEARCH_PORT = 9200;\n\n\tprotected ElasticsearchDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"elasticsearch\");\n\t}\n\n\t@Override\n\tprotected ElasticsearchConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ElasticsearchDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link ElasticsearchConnectionDetails} backed by an {@code elasticsearch}\n\t * {@link RunningService}.\n\t */\n\tstatic class ElasticsearchDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements ElasticsearchConnectionDetails {\n\n\t\tprivate final ElasticsearchEnvironment environment;\n\n\t\tprivate final List<Node> nodes;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tElasticsearchDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new ElasticsearchEnvironment(service.env());\n\t\t\tthis.sslBundle = getSslBundle(service);\n\t\t\tProtocol protocol = (this.sslBundle != null) ? Protocol.HTTPS : Protocol.HTTP;\n\t\t\tthis.nodes = List.of(new Node(service.host(), service.ports().get(ELASTICSEARCH_PORT), protocol,\n\t\t\t\t\tgetUsername(), getPassword()));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn \"elastic\";\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/docker/compose/ElasticsearchEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Elasticsearch environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ElasticsearchEnvironment {\n\n\tprivate final @Nullable String password;\n\n\tElasticsearchEnvironment(Map<String, @Nullable String> env) {\n\t\tAssert.state(!env.containsKey(\"ELASTIC_PASSWORD_FILE\"), \"ELASTIC_PASSWORD_FILE is not supported\");\n\t\tthis.password = env.get(\"ELASTIC_PASSWORD\");\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Elasticsearch service connections.\n */\n@NullMarked\npackage org.springframework.boot.elasticsearch.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/health/ElasticsearchRestClientHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.health;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Request;\nimport co.elastic.clients.transport.rest5_client.low_level.Response;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport org.apache.hc.core5.http.HttpStatus;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.json.JsonParser;\nimport org.springframework.boot.json.JsonParserFactory;\nimport org.springframework.util.StreamUtils;\n\n/**\n * {@link HealthIndicator} for an Elasticsearch cluster using a {@link Rest5Client}.\n *\n * @author Artsiom Yudovin\n * @author Brian Clozel\n * @author Filip Hrisafov\n * @since 4.0.0\n */\npublic class ElasticsearchRestClientHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate static final String RED_STATUS = \"red\";\n\n\tprivate final Rest5Client client;\n\n\tprivate final JsonParser jsonParser;\n\n\tpublic ElasticsearchRestClientHealthIndicator(Rest5Client client) {\n\t\tsuper(\"Elasticsearch health check failed\");\n\t\tthis.client = client;\n\t\tthis.jsonParser = JsonParserFactory.getJsonParser();\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tResponse response = this.client.performRequest(new Request(\"GET\", \"/_cluster/health/\"));\n\t\tif (response.getStatusCode() != HttpStatus.SC_OK) {\n\t\t\tbuilder.down();\n\t\t\tbuilder.withDetail(\"statusCode\", response.getStatusCode());\n\t\t\tbuilder.withDetail(\"warnings\", response.getWarnings());\n\t\t\treturn;\n\t\t}\n\t\ttry (InputStream inputStream = response.getEntity().getContent()) {\n\t\t\tdoHealthCheck(builder, StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));\n\t\t}\n\t}\n\n\tprivate void doHealthCheck(Health.Builder builder, String json) {\n\t\tMap<String, Object> response = this.jsonParser.parseMap(json);\n\t\tString status = (String) response.get(\"status\");\n\t\tbuilder.status((RED_STATUS.equals(status)) ? Status.OUT_OF_SERVICE : Status.UP);\n\t\tbuilder.withDetails(response);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for Elasticsearch.\n */\n@NullMarked\npackage org.springframework.boot.elasticsearch.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/testcontainers/ElasticsearchContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.testcontainers;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\n\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node.Protocol;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.Ssl;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link ElasticsearchConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link ElasticsearchContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ElasticsearchContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<ElasticsearchContainer, ElasticsearchConnectionDetails> {\n\n\tprivate static final int DEFAULT_PORT = 9200;\n\n\t@Override\n\tprotected ElasticsearchConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<ElasticsearchContainer> source) {\n\t\treturn new ElasticsearchContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link ElasticsearchConnectionDetails} backed by a\n\t * {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class ElasticsearchContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<ElasticsearchContainer> implements ElasticsearchConnectionDetails {\n\n\t\tprivate volatile @Nullable SslBundle sslBundle;\n\n\t\tprivate ElasticsearchContainerConnectionDetails(ContainerConnectionSource<ElasticsearchContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn \"elastic\";\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn getContainer().getEnvMap().get(\"ELASTIC_PASSWORD\");\n\t\t}\n\n\t\t@Override\n\t\tpublic List<Node> getNodes() {\n\t\t\tString host = getContainer().getHost();\n\t\t\tInteger port = getContainer().getMappedPort(DEFAULT_PORT);\n\t\t\treturn List.of(new Node(host, port, (getSslBundle() != null) ? Protocol.HTTPS : Protocol.HTTP,\n\t\t\t\t\tgetUsername(), getPassword()));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\tif (this.sslBundle != null) {\n\t\t\t\treturn this.sslBundle;\n\t\t\t}\n\t\t\tSslBundle sslBundle = super.getSslBundle();\n\t\t\tif (sslBundle != null) {\n\t\t\t\tthis.sslBundle = sslBundle;\n\t\t\t\treturn sslBundle;\n\t\t\t}\n\t\t\tif (hasAnnotation(Ssl.class)) {\n\t\t\t\tbyte[] caCertificate = getContainer().caCertAsBytes().orElse(null);\n\t\t\t\tif (caCertificate != null) {\n\t\t\t\t\tKeyStore trustStore = createTrustStore(caCertificate);\n\t\t\t\t\tsslBundle = createSslBundleWithTrustStore(trustStore);\n\t\t\t\t\tthis.sslBundle = sslBundle;\n\t\t\t\t\treturn sslBundle;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate SslBundle createSslBundleWithTrustStore(KeyStore trustStore) {\n\t\t\treturn SslBundle.of(SslStoreBundle.of(null, null, trustStore));\n\t\t}\n\n\t\tprivate KeyStore createTrustStore(byte[] caCertificate) {\n\t\t\ttry {\n\t\t\t\tKeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\t\t\tkeyStore.load(null, null);\n\t\t\t\tCertificateFactory certFactory = CertificateFactory.getInstance(\"X.509\");\n\t\t\t\tCertificate certificate = certFactory.generateCertificate(new ByteArrayInputStream(caCertificate));\n\t\t\t\tkeyStore.setCertificateEntry(\"ca\", certificate);\n\t\t\t\treturn keyStore;\n\t\t\t}\n\t\t\tcatch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to create keystore from CA certificate\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Elasticsearch service connections.\n */\n@NullMarked\npackage org.springframework.boot.elasticsearch.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.elasticsearch.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Elasticsearch health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.health.elasticsearch.indices\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"description\": \"Comma-separated index names.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"management.health.elasticsearch.response-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Time to wait for a response from the cluster.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.connection-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Connection timeout.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.multi-threaded\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable connection requests from multiple execution threads.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Login password.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.proxy.host\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Proxy host the HTTP client should use.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.proxy.port\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Proxy port the HTTP client should use.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Read timeout.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.uris\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"description\": \"Comma-separated list of the Elasticsearch instances to use.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.jest.username\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Login username.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.elasticsearch.uris\",\n      \"defaultValue\": [\n        \"http://localhost:9200\"\n      ]\n    },\n    {\n      \"name\": \"spring.elasticsearch.webclient.max-in-memory-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"description\": \"Limit on the number of bytes that can be buffered whenever the input stream needs to be aggregated.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Reactive Elasticsearch client no longer uses WebClient.\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration\norg.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration\norg.springframework.boot.elasticsearch.autoconfigure.health.ElasticsearchRestHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.elasticsearch.docker.compose.ElasticsearchDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.elasticsearch.testcontainers.ElasticsearchContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/test/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport co.elastic.clients.elasticsearch.ElasticsearchClient;\nimport co.elastic.clients.json.JsonpMapper;\nimport co.elastic.clients.json.SimpleJsonpMapper;\nimport co.elastic.clients.json.jackson.Jackson3JsonpMapper;\nimport co.elastic.clients.json.jackson.JacksonJsonpMapper;\nimport co.elastic.clients.json.jsonb.JsonbJsonpMapper;\nimport co.elastic.clients.transport.ElasticsearchTransport;\nimport co.elastic.clients.transport.rest5_client.Rest5ClientTransport;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.jsonb.autoconfigure.JsonbAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ElasticsearchClientAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ElasticsearchClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class));\n\n\t@Test\n\tvoid withoutRestClientThenAutoConfigurationShouldBackOff() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchTransport.class)\n\t\t\t.doesNotHaveBean(JsonpMapper.class)\n\t\t\t.doesNotHaveBean(ElasticsearchClient.class));\n\t}\n\n\t@Test\n\tvoid withRestClientAutoConfigurationShouldDefineClientAndSupportingBeans() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)\n\t\t\t\t.hasSingleBean(Rest5ClientTransport.class)\n\t\t\t\t.hasSingleBean(ElasticsearchClient.class));\n\t}\n\n\t@Test\n\tvoid withoutJsonbOrJacksonShouldDefineSimpleMapper() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JsonMapper.class, ObjectMapper.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)\n\t\t\t\t.hasSingleBean(SimpleJsonpMapper.class));\n\t}\n\n\t@Test\n\tvoid withJsonbShouldDefineJsonbMapper() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JsonMapper.class, ObjectMapper.class))\n\t\t\t.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)\n\t\t\t\t.hasSingleBean(JsonbJsonpMapper.class));\n\t}\n\n\t@Test\n\tvoid withJacksonShouldDefineJacksonMapper() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)\n\t\t\t\t.hasSingleBean(Jackson3JsonpMapper.class));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tvoid withoutJackson3ShouldDefineJackson2Mapper() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JsonMapper.class))\n\t\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)\n\t\t\t\t.hasSingleBean(JacksonJsonpMapper.class));\n\t}\n\n\t@Test\n\tvoid withJacksonAndJsonbShouldDefineJacksonMapper() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class, JacksonAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)\n\t\t\t\t.hasSingleBean(Jackson3JsonpMapper.class));\n\t}\n\n\t@Test\n\tvoid withCustomMapperTransportShouldUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(JsonpMapperConfiguration.class)\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JsonpMapper.class).hasBean(\"customJsonpMapper\");\n\t\t\t\tJsonpMapper mapper = context.getBean(JsonpMapper.class);\n\t\t\t\tassertThat(context.getBean(ElasticsearchTransport.class).jsonpMapper()).isSameAs(mapper);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withCustomTransportClientShouldUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(TransportConfiguration.class)\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ElasticsearchTransport.class).hasBean(\"customElasticsearchTransport\");\n\t\t\t\tElasticsearchTransport transport = context.getBean(ElasticsearchTransport.class);\n\t\t\t\tassertThat(context.getBean(ElasticsearchClient.class)._transport()).isSameAs(transport);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonJsonpMapperDoesNotUseGlobalObjectMapper() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.withBean(ObjectMapper.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJsonMapper jsonMapper = context.getBean(JsonMapper.class);\n\t\t\t\tJackson3JsonpMapper jacksonJsonpMapper = context.getBean(Jackson3JsonpMapper.class);\n\t\t\t\tassertThat(jacksonJsonpMapper.objectMapper()).isNotSameAs(jsonMapper);\n\t\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tvoid jackson2JsonpMapperDoesNotUseGlobalObjectMapper() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JsonMapper.class))\n\t\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfiguration.class)\n\t\t\t.withBean(ObjectMapper.class)\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper objectMapper = context.getBean(ObjectMapper.class);\n\t\t\t\tJacksonJsonpMapper jacksonJsonpMapper = context.getBean(JacksonJsonpMapper.class);\n\t\t\t\tassertThat(jacksonJsonpMapper.objectMapper()).isNotSameAs(objectMapper);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestClientConfiguration {\n\n\t\t@Bean\n\t\tRest5Client restClient() {\n\t\t\treturn mock(Rest5Client.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JsonpMapperConfiguration {\n\n\t\t@Bean\n\t\tJsonpMapper customJsonpMapper() {\n\t\t\treturn mock(JsonpMapper.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TransportConfiguration {\n\n\t\t@Bean\n\t\tElasticsearchTransport customElasticsearchTransport(JsonpMapper mapper) {\n\t\t\treturn mock(ElasticsearchTransport.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/test/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchRestClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Node;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;\nimport co.elastic.clients.transport.rest5_client.low_level.sniffer.Sniffer;\nimport org.apache.hc.client5.http.HttpRoute;\nimport org.apache.hc.client5.http.auth.AuthScope;\nimport org.apache.hc.client5.http.auth.CredentialsProvider;\nimport org.apache.hc.client5.http.auth.UsernamePasswordCredentials;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\nimport org.apache.hc.core5.function.Resolver;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.HttpHost;\nimport org.apache.hc.core5.http.config.Registry;\nimport org.apache.hc.core5.util.Timeout;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchConnectionDetails.Node.Protocol;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientConfigurations.PropertiesElasticsearchConnectionDetails;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ElasticsearchRestClientAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Vedran Pavic\n * @author Evgeniy Cheban\n * @author Filip Hrisafov\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @author Laura Trotta\n */\nclass ElasticsearchRestClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid configureShouldCreateRest5ClientBuilderAndRest5Client() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(Rest5Client.class)\n\t\t\t.hasSingleBean(Rest5ClientBuilder.class));\n\t}\n\n\t@Test\n\tvoid configureWhenCustomRest5ClientShouldBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRest5ClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Rest5ClientBuilder.class)\n\t\t\t\t.hasSingleBean(Rest5Client.class)\n\t\t\t\t.hasBean(\"customRest5Client\"));\n\t}\n\n\t@Test\n\tvoid configureWhenBuilderCustomizerShouldApply() {\n\t\tthis.contextRunner.withUserConfiguration(BuilderCustomizerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Rest5Client.class);\n\t\t\tRest5Client restClient = context.getBean(Rest5Client.class);\n\t\t\tassertThat(restClient).hasFieldOrPropertyWithValue(\"pathPrefix\", \"/test\");\n\t\t\tassertThat(restClient).extracting(\"client.defaultConfig.cookieSpec\").isEqualTo(\"rfc6265-lax\");\n\t\t\tassertThat(restClient).extracting(\"client.manager.pool.maxTotal\").isEqualTo(100);\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithNoTimeoutsApplyDefaults() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Rest5Client.class);\n\t\t\tRest5Client restClient = context.getBean(Rest5Client.class);\n\t\t\tassertTimeouts(restClient, Duration.ofMillis(Rest5ClientBuilder.DEFAULT_CONNECT_TIMEOUT_MILLIS),\n\t\t\t\t\tDuration.ofMillis(Rest5ClientBuilder.DEFAULT_SOCKET_TIMEOUT_MILLIS));\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithCustomTimeouts() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.connection-timeout=15s\", \"spring.elasticsearch.socket-timeout=1m\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Rest5Client.class);\n\t\t\t\tRest5Client restClient = context.getBean(Rest5Client.class);\n\t\t\t\tassertTimeouts(restClient, Duration.ofSeconds(15), Duration.ofMinutes(1));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static void assertTimeouts(Rest5Client restClient, Duration connectTimeout, Duration socketTimeout) {\n\t\tassertThat(restClient).extracting(\"client.manager.connectionConfigResolver\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(Resolver.class))\n\t\t\t.extracting((resolver) -> ((Resolver<HttpRoute, ConnectionConfig>) resolver).resolve(null))\n\t\t\t.satisfies((connectionConfig) -> {\n\t\t\t\tassertThat(connectionConfig.getSocketTimeout()).isEqualTo(Timeout.of(socketTimeout));\n\t\t\t\tassertThat(connectionConfig.getConnectTimeout()).isEqualTo(Timeout.of(connectTimeout));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureUriWithNoScheme() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.uris=localhost:9876\").run((context) -> {\n\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\tassertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))\n\t\t\t\t.containsExactly(\"http://localhost:9876\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureUriWithUsernameOnly() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.uris=http://user@localhost:9200\").run((context) -> {\n\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\tassertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))\n\t\t\t\t.containsExactly(\"http://localhost:9200\");\n\t\t\tassertThat(client)\n\t\t\t\t.extracting(\"client.credentialsProvider\", InstanceOfAssertFactories.type(CredentialsProvider.class))\n\t\t\t\t.satisfies((credentialsProvider) -> {\n\t\t\t\t\tUsernamePasswordCredentials credentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t.getCredentials(new AuthScope(\"localhost\", 9200), null);\n\t\t\t\t\tassertThat(credentials.getUserPrincipal().getName()).isEqualTo(\"user\");\n\t\t\t\t\tassertThat(credentials.getUserPassword()).isNull();\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureUriWithUsernameAndEmptyPassword() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.uris=http://user:@localhost:9200\")\n\t\t\t.run((context) -> {\n\t\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\t\tassertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))\n\t\t\t\t\t.containsExactly(\"http://localhost:9200\");\n\t\t\t\tassertThat(client)\n\t\t\t\t\t.extracting(\"client.credentialsProvider\", InstanceOfAssertFactories.type(CredentialsProvider.class))\n\t\t\t\t\t.satisfies((credentialsProvider) -> {\n\t\t\t\t\t\tUsernamePasswordCredentials credentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t\t.getCredentials(new AuthScope(\"localhost\", 9200), null);\n\t\t\t\t\t\tassertThat(credentials.getUserPrincipal().getName()).isEqualTo(\"user\");\n\t\t\t\t\t\tassertThat(credentials.getUserPassword()).isEmpty();\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureUriWithUsernameAndPasswordWhenUsernameAndPasswordPropertiesSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.uris=http://user:password@localhost:9200,localhost:9201\",\n\t\t\t\t\t\"spring.elasticsearch.username=admin\", \"spring.elasticsearch.password=admin\")\n\t\t\t.run((context) -> {\n\t\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\t\tassertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))\n\t\t\t\t\t.containsExactly(\"http://localhost:9200\", \"http://localhost:9201\");\n\t\t\t\tassertThat(client)\n\t\t\t\t\t.extracting(\"client.credentialsProvider\", InstanceOfAssertFactories.type(CredentialsProvider.class))\n\t\t\t\t\t.satisfies((credentialsProvider) -> {\n\t\t\t\t\t\tUsernamePasswordCredentials uriCredentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t\t.getCredentials(new AuthScope(\"localhost\", 9200), null);\n\t\t\t\t\t\tassertThat(uriCredentials.getUserPrincipal().getName()).isEqualTo(\"user\");\n\t\t\t\t\t\tassertThat(uriCredentials.getUserPassword()).containsExactly(\"password\".toCharArray());\n\t\t\t\t\t\tUsernamePasswordCredentials defaultCredentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t\t.getCredentials(new AuthScope(\"localhost\", 9201), null);\n\t\t\t\t\t\tassertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo(\"admin\");\n\t\t\t\t\t\tassertThat(defaultCredentials.getUserPassword()).containsExactly(\"admin\".toCharArray());\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenApiKeyIsConfiguredThenAuthorizationHeaderIsPresent() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.api-key=some-api-key\").run((context) -> {\n\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\tassertThat(client).extracting(\"defaultHeaders\", InstanceOfAssertFactories.list(Header.class))\n\t\t\t\t.satisfiesOnlyOnce((header) -> {\n\t\t\t\t\tassertThat(header.getName().equals(\"Authorization\"));\n\t\t\t\t\tassertThat(header.getValue().equals(\"ApiKey some-api-key\"));\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenApiKeyAndUsernameAndPasswordAreConfiguredThenBothFormsOfCredentialsArePresent() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.api-key=some-api-key\", \"spring.elasticsearch.username=alice\",\n\t\t\t\t\t\"spring.elasticsearch.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\t\tassertThat(client).extracting(\"defaultHeaders\", InstanceOfAssertFactories.list(Header.class))\n\t\t\t\t\t.satisfiesOnlyOnce((header) -> {\n\t\t\t\t\t\tassertThat(header.getName().equals(\"Authorization\"));\n\t\t\t\t\t\tassertThat(header.getValue().equals(\"ApiKey some-api-key\"));\n\t\t\t\t\t});\n\t\t\t\tassertThat(client)\n\t\t\t\t\t.extracting(\"client.credentialsProvider\", InstanceOfAssertFactories.type(CredentialsProvider.class))\n\t\t\t\t\t.satisfies((credentialsProvider) -> {\n\t\t\t\t\t\tUsernamePasswordCredentials defaultCredentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t\t.getCredentials(new AuthScope(null, -1), null);\n\t\t\t\t\t\tassertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo(\"alice\");\n\t\t\t\t\t\tassertThat(defaultCredentials.getUserPassword()).containsExactly(\"secret\".toCharArray());\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithCustomPathPrefix() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.path-prefix=/some/prefix\").run((context) -> {\n\t\t\tRest5Client client = context.getBean(Rest5Client.class);\n\t\t\tassertThat(client).extracting(\"pathPrefix\").isEqualTo(\"/some/prefix\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithNoSocketKeepAliveApplyDefault() {\n\t\tRest5Client client = Rest5Client.builder(new HttpHost(\"http\", \"localhost\", 9201)).build();\n\t\tassertThat(client.getHttpClient()).extracting(\"ioReactor.workers\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.ARRAY)\n\t\t\t.satisfies((workers) -> assertThat(workers[0]).extracting(\"reactorConfig.soKeepAlive\").isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid configureWithCustomSocketKeepAlive() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.socket-keep-alive=false\")\n\t\t\t.run((context) -> assertThat(context.getBean(Rest5Client.class).getHttpClient())\n\t\t\t\t.extracting(\"ioReactor.workers\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.ARRAY)\n\t\t\t\t.satisfies(\n\t\t\t\t\t\t(workers) -> assertThat(workers[0]).extracting(\"reactorConfig.soKeepAlive\").isEqualTo(false)));\n\t}\n\n\t@Test\n\tvoid configureShouldNotCreateSnifferUsingRest5ClientByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Sniffer.class));\n\t}\n\n\t@Test\n\tvoid configureWithSnifferEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.restclient.sniffer.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Sniffer.class);\n\t\t\tassertThat(context.getBean(Sniffer.class)).hasFieldOrPropertyWithValue(\"restClient\",\n\t\t\t\t\tcontext.getBean(Rest5Client.class));\n\t\t\t// Validate shutdown order as the sniffer must be shutdown before the\n\t\t\t// client\n\t\t\tassertThat(context.getBeanFactory().getDependentBeans(\"elasticsearchRestClient\"))\n\t\t\t\t.contains(\"elasticsearchSniffer\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithCustomSnifferSettings() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.elasticsearch.restclient.sniffer.enabled=true\",\n\t\t\t\t\t\"spring.elasticsearch.restclient.sniffer.interval=180s\",\n\t\t\t\t\t\"spring.elasticsearch.restclient.sniffer.delay-after-failure=30s\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Sniffer.class);\n\t\t\t\tSniffer sniffer = context.getBean(Sniffer.class);\n\t\t\t\tassertThat(sniffer).hasFieldOrPropertyWithValue(\"sniffIntervalMillis\",\n\t\t\t\t\t\tDuration.ofMinutes(3).toMillis());\n\t\t\t\tassertThat(sniffer).hasFieldOrPropertyWithValue(\"sniffAfterFailureDelayMillis\",\n\t\t\t\t\t\tDuration.ofSeconds(30).toMillis());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWhenCustomSnifferShouldBackOff() {\n\t\tSniffer customSniffer = mock(Sniffer.class);\n\t\tthis.contextRunner.withPropertyValues(\"spring.elasticsearch.restclient.sniffer.enabled=true\")\n\t\t\t.withBean(Sniffer.class, () -> customSniffer)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Sniffer.class);\n\t\t\t\tSniffer sniffer = context.getBean(Sniffer.class);\n\t\t\t\tassertThat(sniffer).isSameAs(customSniffer);\n\t\t\t\tthen(customSniffer).shouldHaveNoInteractions();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesElasticsearchConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Rest5Client.class)\n\t\t\t\t.hasSingleBean(ElasticsearchConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesElasticsearchConnectionDetails.class);\n\t\t\tRest5Client restClient = context.getBean(Rest5Client.class);\n\t\t\tassertThat(restClient).hasFieldOrPropertyWithValue(\"pathPrefix\", \"/some-path\");\n\t\t\tassertThat(restClient.getNodes().stream().map(Node::getHost).map(HttpHost::toString))\n\t\t\t\t.containsExactly(\"http://elastic.example.com:9200\");\n\t\t\tassertThat(restClient)\n\t\t\t\t.extracting(\"client.credentialsProvider\", InstanceOfAssertFactories.type(CredentialsProvider.class))\n\t\t\t\t.satisfies((credentialsProvider) -> {\n\t\t\t\t\tUsernamePasswordCredentials uriCredentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t.getCredentials(new AuthScope(\"any.elastic.example.com\", 80), null);\n\t\t\t\t\tassertThat(uriCredentials.getUserPrincipal().getName()).isEqualTo(\"user-1\");\n\t\t\t\t\tassertThat(uriCredentials.getUserPassword()).containsExactly(\"password-1\".toCharArray());\n\t\t\t\t})\n\t\t\t\t.satisfies((credentialsProvider) -> {\n\t\t\t\t\tUsernamePasswordCredentials uriCredentials = (UsernamePasswordCredentials) credentialsProvider\n\t\t\t\t\t\t.getCredentials(new AuthScope(\"elastic.example.com\", 9200), null);\n\t\t\t\t\tassertThat(uriCredentials.getUserPrincipal().getName()).isEqualTo(\"node-user-1\");\n\t\t\t\t\tassertThat(uriCredentials.getUserPassword()).containsExactly(\"node-password-1\".toCharArray());\n\t\t\t\t});\n\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\t@SuppressWarnings(\"unchecked\")\n\tvoid configureWithSslBundle() {\n\t\tList<String> properties = new ArrayList<>();\n\t\tproperties.add(\"spring.elasticsearch.restclient.ssl.bundle=mybundle\");\n\t\tproperties.add(\"spring.ssl.bundle.jks.mybundle.truststore.location=classpath:test.jks\");\n\t\tproperties.add(\"spring.ssl.bundle.jks.mybundle.options.ciphers=DESede\");\n\t\tproperties.add(\"spring.ssl.bundle.jks.mybundle.options.enabled-protocols=TLSv1.3\");\n\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new)).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Rest5Client.class);\n\t\t\tRest5Client restClient = context.getBean(Rest5Client.class);\n\t\t\tassertThat(restClient).extracting(\"client.manager.connectionOperator.tlsStrategyLookup\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(Registry.class))\n\t\t\t\t.extracting((registry) -> registry.lookup(\"https\"))\n\t\t\t\t.satisfies((tlsStrategy) -> {\n\t\t\t\t\tassertThat(tlsStrategy).extracting(\"supportedProtocols\").isEqualTo(new String[] { \"TLSv1.3\" });\n\t\t\t\t\tassertThat(tlsStrategy).extracting(\"supportedCipherSuites\").isEqualTo(new String[] { \"DESede\" });\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tElasticsearchConnectionDetails elasticsearchConnectionDetails() {\n\t\t\treturn new ElasticsearchConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic List<Node> getNodes() {\n\t\t\t\t\treturn List\n\t\t\t\t\t\t.of(new Node(\"elastic.example.com\", 9200, Protocol.HTTP, \"node-user-1\", \"node-password-1\"));\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"password-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPathPrefix() {\n\t\t\t\t\treturn \"/some-path\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BuilderCustomizerConfiguration {\n\n\t\t@Bean\n\t\tRest5ClientBuilderCustomizer myCustomizer() {\n\t\t\treturn new Rest5ClientBuilderCustomizer() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void customize(Rest5ClientBuilder builder) {\n\t\t\t\t\tbuilder.setPathPrefix(\"/test\");\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void customize(HttpAsyncClientBuilder httpClientBuilder) {\n\t\t\t\t\thttpClientBuilder.setConnectionManager(\n\t\t\t\t\t\t\tPoolingAsyncClientConnectionManagerBuilder.create().setMaxConnTotal(100).build());\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void customize(RequestConfig.Builder builder) {\n\t\t\t\t\tbuilder.setCookieSpec(\"rfc6265-lax\");\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void customize(ConnectionConfig.Builder connectionConfigBuilder) {\n\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRest5ClientConfiguration {\n\n\t\t@Bean\n\t\tRest5Client customRest5Client(Rest5ClientBuilder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TwoCustomRest5ClientConfiguration {\n\n\t\t@Bean\n\t\tRest5Client customRest5Client(Rest5ClientBuilder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\tRest5Client customRest5Client1(Rest5ClientBuilder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/test/java/org/springframework/boot/elasticsearch/autoconfigure/health/ElasticsearchRestHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.autoconfigure.health;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;\nimport org.springframework.boot.elasticsearch.health.ElasticsearchRestClientHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ElasticsearchRestHealthContributorAutoConfiguration}.\n *\n * @author Filip Hrisafov\n * @author Andy Wilkinson\n */\nclass ElasticsearchRestHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,\n\t\t\t\tElasticsearchRestHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)\n\t\t\t\t.hasBean(\"elasticsearchHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWithoutRestClientShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Rest5Client.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(\"elasticsearchHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWithRestClientShouldCreateIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)\n\t\t\t\t.hasBean(\"elasticsearchHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.elasticsearch.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(\"elasticsearchHealthContributor\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRestClientConfiguration {\n\n\t\t@Bean\n\t\tRest5Client customRestClient(Rest5ClientBuilder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/test/java/org/springframework/boot/elasticsearch/docker/compose/ElasticsearchEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ElasticsearchEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ElasticsearchEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasElasticPasswordFileThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new ElasticsearchEnvironment(Map.of(\"ELASTIC_PASSWORD_FILE\", \"afile\")))\n\t\t\t.withMessage(\"ELASTIC_PASSWORD_FILE is not supported\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenNoPassword() {\n\t\tElasticsearchEnvironment environment = new ElasticsearchEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPassword() {\n\t\tElasticsearchEnvironment environment = new ElasticsearchEnvironment(Map.of(\"ELASTIC_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-elasticsearch/src/test/java/org/springframework/boot/elasticsearch/health/ElasticsearchRestClientHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.elasticsearch.health;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Map;\n\nimport co.elastic.clients.transport.rest5_client.low_level.Request;\nimport co.elastic.clients.transport.rest5_client.low_level.Response;\nimport co.elastic.clients.transport.rest5_client.low_level.Rest5Client;\nimport org.apache.hc.core5.http.ContentType;\nimport org.apache.hc.core5.http.io.entity.BasicHttpEntity;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ElasticsearchRestClientHealthIndicator}.\n *\n * @author Artsiom Yudovin\n * @author Filip Hrisafov\n */\nclass ElasticsearchRestClientHealthIndicatorTests {\n\n\tprivate final Rest5Client restClient = mock(Rest5Client.class);\n\n\tprivate final ElasticsearchRestClientHealthIndicator elasticsearchRestClientHealthIndicator = new ElasticsearchRestClientHealthIndicator(\n\t\t\tthis.restClient);\n\n\t@Test\n\tvoid elasticsearchIsUp() throws IOException {\n\t\tBasicHttpEntity httpEntity = new BasicHttpEntity(\n\t\t\t\tnew ByteArrayInputStream(createJsonResult(200, \"green\").getBytes()), ContentType.APPLICATION_JSON);\n\t\tResponse response = mock(Response.class);\n\t\tgiven(response.getStatusCode()).willReturn(200);\n\t\tgiven(response.getEntity()).willReturn(httpEntity);\n\t\tgiven(this.restClient.performRequest(any(Request.class))).willReturn(response);\n\t\torg.springframework.boot.health.contributor.Health health = this.elasticsearchRestClientHealthIndicator\n\t\t\t.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertHealthDetailsWithStatus(health.getDetails(), \"green\");\n\t}\n\n\t@Test\n\tvoid elasticsearchWithYellowStatusIsUp() throws IOException {\n\t\tBasicHttpEntity httpEntity = new BasicHttpEntity(\n\t\t\t\tnew ByteArrayInputStream(createJsonResult(200, \"yellow\").getBytes()), ContentType.APPLICATION_JSON);\n\t\tResponse response = mock(Response.class);\n\t\tgiven(response.getStatusCode()).willReturn(200);\n\t\tgiven(response.getEntity()).willReturn(httpEntity);\n\t\tgiven(this.restClient.performRequest(any(Request.class))).willReturn(response);\n\t\tHealth health = this.elasticsearchRestClientHealthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertHealthDetailsWithStatus(health.getDetails(), \"yellow\");\n\t}\n\n\t@Test\n\tvoid elasticsearchIsDown() throws IOException {\n\t\tgiven(this.restClient.performRequest(any(Request.class))).willThrow(new IOException(\"Couldn't connect\"));\n\t\tHealth health = this.elasticsearchRestClientHealthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).contains(entry(\"error\", \"java.io.IOException: Couldn't connect\"));\n\t}\n\n\t@Test\n\tvoid elasticsearchIsDownByResponseCode() throws IOException {\n\t\tResponse response = mock(Response.class);\n\t\tgiven(response.getStatusCode()).willReturn(500);\n\t\tgiven(response.getWarnings()).willReturn(List.of(\"Bad things happened\"));\n\t\tgiven(this.restClient.performRequest(any(Request.class))).willReturn(response);\n\t\tHealth health = this.elasticsearchRestClientHealthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).contains(entry(\"statusCode\", 500),\n\t\t\t\tentry(\"warnings\", List.of(\"Bad things happened\")));\n\t}\n\n\t@Test\n\tvoid elasticsearchIsOutOfServiceByStatus() throws IOException {\n\t\tBasicHttpEntity httpEntity = new BasicHttpEntity(\n\t\t\t\tnew ByteArrayInputStream(createJsonResult(200, \"red\").getBytes()), ContentType.APPLICATION_JSON);\n\t\tResponse response = mock(Response.class);\n\t\tgiven(response.getStatusCode()).willReturn(200);\n\t\tgiven(response.getEntity()).willReturn(httpEntity);\n\t\tgiven(this.restClient.performRequest(any(Request.class))).willReturn(response);\n\t\tHealth health = this.elasticsearchRestClientHealthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t\tassertHealthDetailsWithStatus(health.getDetails(), \"red\");\n\t}\n\n\tprivate void assertHealthDetailsWithStatus(Map<String, Object> details, String status) {\n\t\tassertThat(details).contains(entry(\"cluster_name\", \"elasticsearch\"), entry(\"status\", status),\n\t\t\t\tentry(\"timed_out\", false), entry(\"number_of_nodes\", 1), entry(\"number_of_data_nodes\", 1),\n\t\t\t\tentry(\"active_primary_shards\", 0), entry(\"active_shards\", 0), entry(\"relocating_shards\", 0),\n\t\t\t\tentry(\"initializing_shards\", 0), entry(\"unassigned_shards\", 0), entry(\"delayed_unassigned_shards\", 0),\n\t\t\t\tentry(\"number_of_pending_tasks\", 0), entry(\"number_of_in_flight_fetch\", 0),\n\t\t\t\tentry(\"task_max_waiting_in_queue_millis\", 0), entry(\"active_shards_percent_as_number\", 100.0),\n\t\t\t\tentry(\"unassigned_primary_shards\", 10));\n\t}\n\n\tprivate String createJsonResult(int responseCode, String status) {\n\t\tif (responseCode == 200) {\n\t\t\treturn String.format(\"{\\\"cluster_name\\\":\\\"elasticsearch\\\",\"\n\t\t\t\t\t+ \"\\\"status\\\":\\\"%s\\\",\\\"timed_out\\\":false,\\\"number_of_nodes\\\":1,\"\n\t\t\t\t\t+ \"\\\"number_of_data_nodes\\\":1,\\\"active_primary_shards\\\":0,\"\n\t\t\t\t\t+ \"\\\"active_shards\\\":0,\\\"relocating_shards\\\":0,\\\"initializing_shards\\\":0,\"\n\t\t\t\t\t+ \"\\\"unassigned_shards\\\":0,\\\"delayed_unassigned_shards\\\":0,\"\n\t\t\t\t\t+ \"\\\"number_of_pending_tasks\\\":0,\\\"number_of_in_flight_fetch\\\":0,\"\n\t\t\t\t\t+ \"\\\"task_max_waiting_in_queue_millis\\\":0,\\\"active_shards_percent_as_number\\\":100.0,\"\n\t\t\t\t\t+ \"\\\"unassigned_primary_shards\\\": 10 }\", status);\n\t\t}\n\t\treturn \"{\\n  \\\"error\\\": \\\"Server Error\\\",\\n  \\\"status\\\": \" + responseCode + \"\\n}\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Flyway\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(\"org.flywaydb:flyway-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(\"org.flywaydb:flyway-database-oracle\")\n\toptional(\"org.flywaydb:flyway-database-postgresql\")\n\toptional(\"org.flywaydb:flyway-sqlserver\")\n\toptional(\"org.testcontainers:testcontainers-jdbc\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\tdockerTestRuntimeOnly(\"org.postgresql:postgresql\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"jakarta.persistence:jakarta.persistence-api\")\n\ttestImplementation(\"org.hibernate.orm:hibernate-core\")\n\ttestImplementation(\"org.hsqldb:hsqldb\")\n\ttestImplementation(\"org.postgresql:postgresql\")\n\ttestImplementation(\"org.springframework:spring-orm\")\n\n\ttestCompileOnly(\"org.checkerframework:checker-qual\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\ttestRuntimeOnly(\"org.flywaydb:flyway-database-hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/dockerTest/java/org/springframework/boot/flyway/docker/compose/JdbcAdaptingFlywayConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.flyway.autoconfigure.FlywayConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcAdaptingFlywayConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass JdbcAdaptingFlywayConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"flyway-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetails(FlywayConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:postgresql://\").endsWith(\"/mydatabase\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/dockerTest/java/org/springframework/boot/flyway/testcontainers/FlywayContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.testcontainers;\n\nimport org.flywaydb.core.Flyway;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link FlywayContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass FlywayContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final PostgreSQLContainer postgres = TestImage.container(PostgreSQLContainer.class);\n\n\t@Autowired(required = false)\n\tprivate JdbcConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate Flyway flyway;\n\n\t@Test\n\tvoid connectionCanBeMadeToJdbcContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tJdbcTemplate jdbc = new JdbcTemplate(this.flyway.getConfiguration().getDataSource());\n\t\tassertThatNoException().isThrownBy(() -> jdbc.execute(\"SELECT * from public.flyway_schema_history\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(FlywayAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-flyway/src/dockerTest/resources/org/springframework/boot/flyway/docker/compose/flyway-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n"
  },
  {
    "path": "module/spring-boot-flyway/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/FlywayDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.flywaydb.core.Flyway;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\n\n/**\n * A {@link DatabaseInitializerDetector} for {@link Flyway}.\n *\n * @author Andy Wilkinson\n */\nclass FlywayDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\treturn Collections.singleton(Flyway.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/actuate/endpoint/FlywayEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.actuate.endpoint;\n\nimport java.time.Instant;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.flywaydb.core.Flyway;\nimport org.flywaydb.core.api.MigrationInfo;\nimport org.flywaydb.core.api.MigrationState;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * {@link Endpoint @Endpoint} to expose flyway info.\n *\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Endpoint(id = \"flyway\")\npublic class FlywayEndpoint {\n\n\tprivate final ApplicationContext context;\n\n\tpublic FlywayEndpoint(ApplicationContext context) {\n\t\tthis.context = context;\n\t}\n\n\t@ReadOperation\n\tpublic FlywayBeansDescriptor flywayBeans() {\n\t\tApplicationContext target = this.context;\n\t\tMap<@Nullable String, ContextFlywayBeansDescriptor> contextFlywayBeans = new HashMap<>();\n\t\twhile (target != null) {\n\t\t\tMap<String, FlywayDescriptor> flywayBeans = new HashMap<>();\n\t\t\ttarget.getBeansOfType(Flyway.class)\n\t\t\t\t.forEach((name, flyway) -> flywayBeans.put(name, new FlywayDescriptor(flyway.info().all())));\n\t\t\tApplicationContext parent = target.getParent();\n\t\t\tcontextFlywayBeans.put(target.getId(),\n\t\t\t\t\tnew ContextFlywayBeansDescriptor(flywayBeans, (parent != null) ? parent.getId() : null));\n\t\t\ttarget = parent;\n\t\t}\n\t\treturn new FlywayBeansDescriptor(contextFlywayBeans);\n\t}\n\n\t/**\n\t * Description of an application's {@link Flyway} beans.\n\t */\n\tpublic static final class FlywayBeansDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<@Nullable String, ContextFlywayBeansDescriptor> contexts;\n\n\t\tprivate FlywayBeansDescriptor(Map<@Nullable String, ContextFlywayBeansDescriptor> contexts) {\n\t\t\tthis.contexts = contexts;\n\t\t}\n\n\t\tpublic Map<@Nullable String, ContextFlywayBeansDescriptor> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an application context's {@link Flyway} beans.\n\t */\n\tpublic static final class ContextFlywayBeansDescriptor {\n\n\t\tprivate final Map<String, FlywayDescriptor> flywayBeans;\n\n\t\tprivate final @Nullable String parentId;\n\n\t\tprivate ContextFlywayBeansDescriptor(Map<String, FlywayDescriptor> flywayBeans, @Nullable String parentId) {\n\t\t\tthis.flywayBeans = flywayBeans;\n\t\t\tthis.parentId = parentId;\n\t\t}\n\n\t\tpublic Map<String, FlywayDescriptor> getFlywayBeans() {\n\t\t\treturn this.flywayBeans;\n\t\t}\n\n\t\tpublic @Nullable String getParentId() {\n\t\t\treturn this.parentId;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link Flyway} bean.\n\t */\n\tpublic static class FlywayDescriptor {\n\n\t\tprivate final List<FlywayMigrationDescriptor> migrations;\n\n\t\tprivate FlywayDescriptor(MigrationInfo[] migrations) {\n\t\t\tthis.migrations = Stream.of(migrations).map(FlywayMigrationDescriptor::new).toList();\n\t\t}\n\n\t\tpublic FlywayDescriptor(List<FlywayMigrationDescriptor> migrations) {\n\t\t\tthis.migrations = migrations;\n\t\t}\n\n\t\tpublic List<FlywayMigrationDescriptor> getMigrations() {\n\t\t\treturn this.migrations;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a migration performed by Flyway.\n\t */\n\tpublic static final class FlywayMigrationDescriptor {\n\n\t\tprivate final String type;\n\n\t\tprivate final Integer checksum;\n\n\t\tprivate final @Nullable String version;\n\n\t\tprivate final String description;\n\n\t\tprivate final String script;\n\n\t\tprivate final MigrationState state;\n\n\t\tprivate final String installedBy;\n\n\t\tprivate final @Nullable Instant installedOn;\n\n\t\tprivate final Integer installedRank;\n\n\t\tprivate final Integer executionTime;\n\n\t\tprivate FlywayMigrationDescriptor(MigrationInfo info) {\n\t\t\tthis.type = info.getType().name();\n\t\t\tthis.checksum = info.getChecksum();\n\t\t\tthis.version = nullSafeToString(info.getVersion());\n\t\t\tthis.description = info.getDescription();\n\t\t\tthis.script = info.getScript();\n\t\t\tthis.state = info.getState();\n\t\t\tthis.installedBy = info.getInstalledBy();\n\t\t\tthis.installedRank = info.getInstalledRank();\n\t\t\tthis.executionTime = info.getExecutionTime();\n\t\t\tthis.installedOn = nullSafeToInstant(info.getInstalledOn());\n\t\t}\n\n\t\tprivate @Nullable String nullSafeToString(@Nullable Object obj) {\n\t\t\treturn (obj != null) ? obj.toString() : null;\n\t\t}\n\n\t\tprivate @Nullable Instant nullSafeToInstant(@Nullable Date date) {\n\t\t\treturn (date != null) ? Instant.ofEpochMilli(date.getTime()) : null;\n\t\t}\n\n\t\tpublic String getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic Integer getChecksum() {\n\t\t\treturn this.checksum;\n\t\t}\n\n\t\tpublic @Nullable String getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\tpublic String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tpublic String getScript() {\n\t\t\treturn this.script;\n\t\t}\n\n\t\tpublic MigrationState getState() {\n\t\t\treturn this.state;\n\t\t}\n\n\t\tpublic String getInstalledBy() {\n\t\t\treturn this.installedBy;\n\t\t}\n\n\t\tpublic @Nullable Instant getInstalledOn() {\n\t\t\treturn this.installedOn;\n\t\t}\n\n\t\tpublic Integer getInstalledRank() {\n\t\t\treturn this.installedRank;\n\t\t}\n\n\t\tpublic Integer getExecutionTime() {\n\t\t\treturn this.executionTime;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for Flyway.\n */\n@NullMarked\npackage org.springframework.boot.flyway.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.sql.DatabaseMetaData;\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport javax.sql.DataSource;\n\nimport org.flywaydb.core.Flyway;\nimport org.flywaydb.core.api.MigrationVersion;\nimport org.flywaydb.core.api.callback.Callback;\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\nimport org.flywaydb.core.api.migration.JavaMigration;\nimport org.flywaydb.core.extensibility.ConfigurationExtension;\nimport org.flywaydb.database.oracle.OracleConfigurationExtension;\nimport org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension;\nimport org.flywaydb.database.sqlserver.SQLServerConfigurationExtension;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBinding;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration.FlywayAutoConfigurationRuntimeHints;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration.FlywayDataSourceCondition;\nimport org.springframework.boot.flyway.autoconfigure.FlywayProperties.Oracle;\nimport org.springframework.boot.flyway.autoconfigure.FlywayProperties.Postgresql;\nimport org.springframework.boot.flyway.autoconfigure.FlywayProperties.Sqlserver;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.support.JdbcUtils;\nimport org.springframework.jdbc.support.MetaDataAccessException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Flyway database migrations.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Jacques-Etienne Beaudet\n * @author Eddú Meléndez\n * @author Dominic Gunn\n * @author Dan Zheng\n * @author András Deák\n * @author Semyon Danilov\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataSourceAutoConfiguration.class)\n@ConditionalOnClass(Flyway.class)\n@Conditional(FlywayDataSourceCondition.class)\n@ConditionalOnBooleanProperty(name = \"spring.flyway.enabled\", matchIfMissing = true)\n@Import(DatabaseInitializationDependencyConfigurer.class)\n@ImportRuntimeHints(FlywayAutoConfigurationRuntimeHints.class)\npublic final class FlywayAutoConfiguration {\n\n\t@Bean\n\t@ConfigurationPropertiesBinding\n\tstatic StringOrNumberToMigrationVersionConverter stringOrNumberMigrationVersionConverter() {\n\t\treturn new StringOrNumberToMigrationVersionConverter();\n\t}\n\n\t@Bean\n\tFlywaySchemaManagementProvider flywayDefaultDdlModeProvider(ObjectProvider<Flyway> flyways) {\n\t\treturn new FlywaySchemaManagementProvider(flyways);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JdbcUtils.class)\n\t@ConditionalOnMissingBean(Flyway.class)\n\t@EnableConfigurationProperties(FlywayProperties.class)\n\tstatic class FlywayConfiguration {\n\n\t\tprivate final FlywayProperties properties;\n\n\t\tFlywayConfiguration(FlywayProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Bean\n\t\tResourceProviderCustomizer resourceProviderCustomizer() {\n\t\t\treturn new ResourceProviderCustomizer();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(FlywayConnectionDetails.class)\n\t\tPropertiesFlywayConnectionDetails flywayConnectionDetails() {\n\t\t\treturn new PropertiesFlywayConnectionDetails(this.properties);\n\t\t}\n\n\t\t@Bean\n\t\tFlyway flyway(FlywayConnectionDetails connectionDetails, ResourceLoader resourceLoader,\n\t\t\t\tObjectProvider<DataSource> dataSource, @FlywayDataSource ObjectProvider<DataSource> flywayDataSource,\n\t\t\t\tObjectProvider<FlywayConfigurationCustomizer> fluentConfigurationCustomizers,\n\t\t\t\tObjectProvider<JavaMigration> javaMigrations, ObjectProvider<Callback> callbacks,\n\t\t\t\tResourceProviderCustomizer resourceProviderCustomizer) {\n\t\t\tFluentConfiguration configuration = new FluentConfiguration(resourceLoader.getClassLoader());\n\t\t\tconfigureDataSource(configuration, flywayDataSource.getIfAvailable(), dataSource.getIfUnique(),\n\t\t\t\t\tconnectionDetails);\n\t\t\tconfigureProperties(configuration, this.properties);\n\t\t\tconfigureCallbacks(configuration, callbacks.orderedStream().toList());\n\t\t\tconfigureJavaMigrations(configuration, javaMigrations.orderedStream().toList());\n\t\t\tfluentConfigurationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configuration));\n\t\t\tresourceProviderCustomizer.customize(configuration);\n\t\t\treturn configuration.load();\n\t\t}\n\n\t\tprivate void configureDataSource(FluentConfiguration configuration, @Nullable DataSource flywayDataSource,\n\t\t\t\t@Nullable DataSource dataSource, FlywayConnectionDetails connectionDetails) {\n\t\t\tDataSource migrationDataSource = getMigrationDataSource(flywayDataSource, dataSource, connectionDetails);\n\t\t\tconfiguration.dataSource(migrationDataSource);\n\t\t}\n\n\t\tprivate DataSource getMigrationDataSource(@Nullable DataSource flywayDataSource,\n\t\t\t\t@Nullable DataSource dataSource, FlywayConnectionDetails connectionDetails) {\n\t\t\tif (flywayDataSource != null) {\n\t\t\t\treturn flywayDataSource;\n\t\t\t}\n\t\t\tString url = connectionDetails.getJdbcUrl();\n\t\t\tif (url != null) {\n\t\t\t\tDataSourceBuilder<?> builder = DataSourceBuilder.create().type(SimpleDriverDataSource.class);\n\t\t\t\tbuilder.url(url);\n\t\t\t\tapplyConnectionDetails(connectionDetails, builder);\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tString user = connectionDetails.getUsername();\n\t\t\tif (user != null && dataSource != null) {\n\t\t\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource)\n\t\t\t\t\t.type(SimpleDriverDataSource.class);\n\t\t\t\tapplyConnectionDetails(connectionDetails, builder);\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tAssert.state(dataSource != null, \"Flyway migration DataSource missing\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t\tprivate void applyConnectionDetails(FlywayConnectionDetails connectionDetails, DataSourceBuilder<?> builder) {\n\t\t\tbuilder.username(connectionDetails.getUsername());\n\t\t\tbuilder.password(connectionDetails.getPassword());\n\t\t\tString driverClassName = connectionDetails.getDriverClassName();\n\t\t\tif (StringUtils.hasText(driverClassName)) {\n\t\t\t\tbuilder.driverClassName(driverClassName);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Configure the given {@code configuration} using the given {@code properties}.\n\t\t * <p>\n\t\t * To maximize forwards- and backwards-compatibility method references are not\n\t\t * used.\n\t\t * @param configuration the configuration\n\t\t * @param properties the properties\n\t\t */\n\t\t@SuppressWarnings(\"removal\")\n\t\tprivate void configureProperties(FluentConfiguration configuration, FlywayProperties properties) {\n\t\t\t// NOTE: Using method references in the mapper methods can break\n\t\t\t// back-compatibility (see gh-38164)\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tString[] locations = new LocationResolver(configuration.getDataSource())\n\t\t\t\t.resolveLocations(properties.getLocations())\n\t\t\t\t.toArray(new String[0]);\n\t\t\tconfiguration.locations(locations);\n\t\t\tmap.from(properties.getCallbackLocations())\n\t\t\t\t.when((callbackLocations) -> !ObjectUtils.isEmpty(callbackLocations))\n\t\t\t\t.to((callbackLocations) -> configuration.callbackLocations(\n\t\t\t\t\t\tnew LocationResolver(configuration.getDataSource()).resolveLocations(callbackLocations)\n\t\t\t\t\t\t\t.toArray(new String[0])));\n\t\t\tmap.from(properties.isFailOnMissingLocations())\n\t\t\t\t.to((failOnMissingLocations) -> configuration.failOnMissingLocations(failOnMissingLocations));\n\t\t\tmap.from(properties.getEncoding()).to((encoding) -> configuration.encoding(encoding));\n\t\t\tmap.from(properties.getConnectRetries())\n\t\t\t\t.to((connectRetries) -> configuration.connectRetries(connectRetries));\n\t\t\tmap.from(properties.getConnectRetriesInterval())\n\t\t\t\t.as(Duration::getSeconds)\n\t\t\t\t.as(Long::intValue)\n\t\t\t\t.to((connectRetriesInterval) -> configuration.connectRetriesInterval(connectRetriesInterval));\n\t\t\tmap.from(properties.getLockRetryCount())\n\t\t\t\t.to((lockRetryCount) -> configuration.lockRetryCount(lockRetryCount));\n\t\t\tmap.from(properties.getDefaultSchema()).to((schema) -> configuration.defaultSchema(schema));\n\t\t\tmap.from(properties.getSchemas())\n\t\t\t\t.as(StringUtils::toStringArray)\n\t\t\t\t.to((schemas) -> configuration.schemas(schemas));\n\t\t\tmap.from(properties.isCreateSchemas()).to((createSchemas) -> configuration.createSchemas(createSchemas));\n\t\t\tmap.from(properties.getTable()).to((table) -> configuration.table(table));\n\t\t\tmap.from(properties.getTablespace()).to((tablespace) -> configuration.tablespace(tablespace));\n\t\t\tmap.from(properties.getBaselineDescription())\n\t\t\t\t.to((baselineDescription) -> configuration.baselineDescription(baselineDescription));\n\t\t\tmap.from(properties.getBaselineVersion())\n\t\t\t\t.to((baselineVersion) -> configuration.baselineVersion(baselineVersion));\n\t\t\tmap.from(properties.getInstalledBy()).to((installedBy) -> configuration.installedBy(installedBy));\n\t\t\tmap.from(properties.getPlaceholders()).to((placeholders) -> configuration.placeholders(placeholders));\n\t\t\tmap.from(properties.getPlaceholderPrefix())\n\t\t\t\t.to((placeholderPrefix) -> configuration.placeholderPrefix(placeholderPrefix));\n\t\t\tmap.from(properties.getPlaceholderSuffix())\n\t\t\t\t.to((placeholderSuffix) -> configuration.placeholderSuffix(placeholderSuffix));\n\t\t\tmap.from(properties.getPlaceholderSeparator())\n\t\t\t\t.to((placeHolderSeparator) -> configuration.placeholderSeparator(placeHolderSeparator));\n\t\t\tmap.from(properties.isPlaceholderReplacement())\n\t\t\t\t.to((placeholderReplacement) -> configuration.placeholderReplacement(placeholderReplacement));\n\t\t\tmap.from(properties.getSqlMigrationPrefix())\n\t\t\t\t.to((sqlMigrationPrefix) -> configuration.sqlMigrationPrefix(sqlMigrationPrefix));\n\t\t\tmap.from(properties.getSqlMigrationSuffixes())\n\t\t\t\t.as(StringUtils::toStringArray)\n\t\t\t\t.to((sqlMigrationSuffixes) -> configuration.sqlMigrationSuffixes(sqlMigrationSuffixes));\n\t\t\tmap.from(properties.getSqlMigrationSeparator())\n\t\t\t\t.to((sqlMigrationSeparator) -> configuration.sqlMigrationSeparator(sqlMigrationSeparator));\n\t\t\tmap.from(properties.getRepeatableSqlMigrationPrefix())\n\t\t\t\t.to((repeatableSqlMigrationPrefix) -> configuration\n\t\t\t\t\t.repeatableSqlMigrationPrefix(repeatableSqlMigrationPrefix));\n\t\t\tmap.from(properties.getTarget()).to((target) -> configuration.target(target));\n\t\t\tmap.from(properties.isBaselineOnMigrate())\n\t\t\t\t.to((baselineOnMigrate) -> configuration.baselineOnMigrate(baselineOnMigrate));\n\t\t\tmap.from(properties.isCleanDisabled()).to((cleanDisabled) -> configuration.cleanDisabled(cleanDisabled));\n\t\t\tmap.from(properties.isGroup()).to((group) -> configuration.group(group));\n\t\t\tmap.from(properties.isMixed()).to((mixed) -> configuration.mixed(mixed));\n\t\t\tmap.from(properties.isOutOfOrder()).to((outOfOrder) -> configuration.outOfOrder(outOfOrder));\n\t\t\tmap.from(properties.isSkipDefaultCallbacks())\n\t\t\t\t.to((skipDefaultCallbacks) -> configuration.skipDefaultCallbacks(skipDefaultCallbacks));\n\t\t\tmap.from(properties.isSkipDefaultResolvers())\n\t\t\t\t.to((skipDefaultResolvers) -> configuration.skipDefaultResolvers(skipDefaultResolvers));\n\t\t\tmap.from(properties.isValidateMigrationNaming())\n\t\t\t\t.to((validateMigrationNaming) -> configuration.validateMigrationNaming(validateMigrationNaming));\n\t\t\tmap.from(properties.isValidateOnMigrate())\n\t\t\t\t.to((validateOnMigrate) -> configuration.validateOnMigrate(validateOnMigrate));\n\t\t\tmap.from(properties.getInitSqls())\n\t\t\t\t.whenNot(CollectionUtils::isEmpty)\n\t\t\t\t.as((initSqls) -> StringUtils.collectionToDelimitedString(initSqls, \"\\n\"))\n\t\t\t\t.to((initSql) -> configuration.initSql(initSql));\n\t\t\tmap.from(properties.getScriptPlaceholderPrefix())\n\t\t\t\t.to((prefix) -> configuration.scriptPlaceholderPrefix(prefix));\n\t\t\tmap.from(properties.getScriptPlaceholderSuffix())\n\t\t\t\t.to((suffix) -> configuration.scriptPlaceholderSuffix(suffix));\n\t\t\tmap.from(properties.getPowershellExecutable())\n\t\t\t\t.to((powershellExecutable) -> configuration.powershellExecutable(powershellExecutable));\n\t\t\tconfigureExecuteInTransaction(configuration, properties, map);\n\t\t\tmap.from(properties::getLoggers).to((loggers) -> configuration.loggers(loggers));\n\t\t\tmap.from(properties::getCommunityDbSupportEnabled)\n\t\t\t\t.to((communityDbSupportEnabled) -> configuration.communityDBSupportEnabled(communityDbSupportEnabled));\n\t\t\tmap.from(properties.getBatch()).to((batch) -> configuration.batch(batch));\n\t\t\tmap.from(properties.getDryRunOutput()).to((dryRunOutput) -> configuration.dryRunOutput(dryRunOutput));\n\t\t\tmap.from(properties.getErrorOverrides())\n\t\t\t\t.to((errorOverrides) -> configuration.errorOverrides(errorOverrides));\n\t\t\tmap.from(properties.getStream()).to((stream) -> configuration.stream(stream));\n\t\t\tmap.from(properties.getJdbcProperties())\n\t\t\t\t.whenNot(Map::isEmpty)\n\t\t\t\t.to((jdbcProperties) -> configuration.jdbcProperties(jdbcProperties));\n\t\t\tmap.from(properties.getKerberosConfigFile())\n\t\t\t\t.to((configFile) -> configuration.kerberosConfigFile(configFile));\n\t\t\tmap.from(properties.getOutputQueryResults())\n\t\t\t\t.to((outputQueryResults) -> configuration.outputQueryResults(outputQueryResults));\n\t\t\tmap.from(properties.getSkipExecutingMigrations())\n\t\t\t\t.to((skipExecutingMigrations) -> configuration.skipExecutingMigrations(skipExecutingMigrations));\n\t\t\tmap.from(properties.getIgnoreMigrationPatterns())\n\t\t\t\t.to((ignoreMigrationPatterns) -> configuration\n\t\t\t\t\t.ignoreMigrationPatterns(ignoreMigrationPatterns.toArray(new String[0])));\n\t\t\tmap.from(properties.getDetectEncoding())\n\t\t\t\t.to((detectEncoding) -> configuration.detectEncoding(detectEncoding));\n\t\t}\n\n\t\tprivate void configureExecuteInTransaction(FluentConfiguration configuration, FlywayProperties properties,\n\t\t\t\tPropertyMapper map) {\n\t\t\ttry {\n\t\t\t\tmap.from(properties.isExecuteInTransaction()).to(configuration::executeInTransaction);\n\t\t\t}\n\t\t\tcatch (NoSuchMethodError ex) {\n\t\t\t\t// Flyway < 9.14\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureCallbacks(FluentConfiguration configuration, List<Callback> callbacks) {\n\t\t\tif (!callbacks.isEmpty()) {\n\t\t\t\tconfiguration.callbacks(callbacks.toArray(new Callback[0]));\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureJavaMigrations(FluentConfiguration flyway, List<JavaMigration> migrations) {\n\t\t\tif (!migrations.isEmpty()) {\n\t\t\t\tflyway.javaMigrations(migrations.toArray(new JavaMigration[0]));\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tFlywayMigrationInitializer flywayInitializer(Flyway flyway,\n\t\t\t\tObjectProvider<FlywayMigrationStrategy> migrationStrategy) {\n\t\t\treturn new FlywayMigrationInitializer(flyway, migrationStrategy.getIfAvailable());\n\t\t}\n\n\t\t@ConditionalOnClass(name = \"org.flywaydb.database.sqlserver.SQLServerConfigurationExtension\")\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class SqlServerConfiguration {\n\n\t\t\t@Bean\n\t\t\tSqlServerFlywayConfigurationCustomizer sqlServerFlywayConfigurationCustomizer(FlywayProperties properties) {\n\t\t\t\treturn new SqlServerFlywayConfigurationCustomizer(properties);\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(name = \"org.flywaydb.database.oracle.OracleConfigurationExtension\")\n\t\tstatic class OracleConfiguration {\n\n\t\t\t@Bean\n\t\t\tOracleFlywayConfigurationCustomizer oracleFlywayConfigurationCustomizer(FlywayProperties properties) {\n\t\t\t\treturn new OracleFlywayConfigurationCustomizer(properties);\n\t\t\t}\n\n\t\t}\n\n\t\t@ConditionalOnClass(name = \"org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension\")\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class PostgresqlConfiguration {\n\n\t\t\t@Bean\n\t\t\tPostgresqlFlywayConfigurationCustomizer postgresqlFlywayConfigurationCustomizer(\n\t\t\t\t\tFlywayProperties properties) {\n\t\t\t\treturn new PostgresqlFlywayConfigurationCustomizer(properties);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tprivate static class LocationResolver {\n\n\t\tprivate static final String VENDOR_PLACEHOLDER = \"{vendor}\";\n\n\t\tprivate final DataSource dataSource;\n\n\t\tLocationResolver(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\tList<String> resolveLocations(List<String> locations) {\n\t\t\tif (usesVendorLocation(locations)) {\n\t\t\t\tDatabaseDriver databaseDriver = getDatabaseDriver();\n\t\t\t\treturn replaceVendorLocations(locations, databaseDriver);\n\t\t\t}\n\t\t\treturn locations;\n\t\t}\n\n\t\tprivate List<String> replaceVendorLocations(List<String> locations, DatabaseDriver databaseDriver) {\n\t\t\tif (databaseDriver == DatabaseDriver.UNKNOWN) {\n\t\t\t\treturn locations;\n\t\t\t}\n\t\t\tString vendor = databaseDriver.getId();\n\t\t\treturn locations.stream().map((location) -> location.replace(VENDOR_PLACEHOLDER, vendor)).toList();\n\t\t}\n\n\t\tprivate DatabaseDriver getDatabaseDriver() {\n\t\t\ttry {\n\t\t\t\tString url = JdbcUtils.extractDatabaseMetaData(this.dataSource, DatabaseMetaData::getURL);\n\t\t\t\treturn DatabaseDriver.fromJdbcUrl(url);\n\t\t\t}\n\t\t\tcatch (MetaDataAccessException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\n\t\t}\n\n\t\tprivate boolean usesVendorLocation(Collection<String> locations) {\n\t\t\tfor (String location : locations) {\n\t\t\t\tif (location.contains(VENDOR_PLACEHOLDER)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t/**\n\t * Convert a String or Number to a {@link MigrationVersion}.\n\t */\n\tstatic class StringOrNumberToMigrationVersionConverter implements GenericConverter {\n\n\t\tprivate static final Set<ConvertiblePair> CONVERTIBLE_TYPES;\n\n\t\tstatic {\n\t\t\tSet<ConvertiblePair> types = new HashSet<>(2);\n\t\t\ttypes.add(new ConvertiblePair(String.class, MigrationVersion.class));\n\t\t\ttypes.add(new ConvertiblePair(Number.class, MigrationVersion.class));\n\t\t\tCONVERTIBLE_TYPES = Collections.unmodifiableSet(types);\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\t\treturn CONVERTIBLE_TYPES;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\t\tString value = ObjectUtils.nullSafeToString(source);\n\t\t\treturn MigrationVersion.fromVersion(value);\n\t\t}\n\n\t}\n\n\tstatic final class FlywayDataSourceCondition extends AnyNestedCondition {\n\n\t\tFlywayDataSourceCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnBean(DataSource.class)\n\t\tprivate static final class DataSourceBeanCondition {\n\n\t\t}\n\n\t\t@ConditionalOnBean(JdbcConnectionDetails.class)\n\t\tprivate static final class JdbcConnectionDetailsCondition {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.flyway.url\")\n\t\tprivate static final class FlywayUrlCondition {\n\n\t\t}\n\n\t}\n\n\tstatic class FlywayAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"db/migration/**\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link FlywayProperties} to {@link FlywayConnectionDetails}.\n\t */\n\tstatic final class PropertiesFlywayConnectionDetails implements FlywayConnectionDetails {\n\n\t\tprivate final FlywayProperties properties;\n\n\t\tPropertiesFlywayConnectionDetails(FlywayProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.properties.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getJdbcUrl() {\n\t\t\treturn this.properties.getUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getDriverClassName() {\n\t\t\treturn this.properties.getDriverClassName();\n\t\t}\n\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic final class OracleFlywayConfigurationCustomizer implements FlywayConfigurationCustomizer {\n\n\t\tprivate final FlywayProperties properties;\n\n\t\tOracleFlywayConfigurationCustomizer(FlywayProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(FluentConfiguration configuration) {\n\t\t\tExtension<OracleConfigurationExtension> extension = new Extension<>(configuration,\n\t\t\t\t\tOracleConfigurationExtension.class, \"Oracle\");\n\t\t\tOracle properties = this.properties.getOracle();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getSqlplus).to(extension.via((ext, sqlplus) -> ext.setSqlplus(sqlplus)));\n\t\t\tmap.from(properties::getSqlplusWarn)\n\t\t\t\t.to(extension.via((ext, sqlplusWarn) -> ext.setSqlplusWarn(sqlplusWarn)));\n\t\t\tmap.from(properties::getWalletLocation)\n\t\t\t\t.to(extension.via((ext, walletLocation) -> ext.setWalletLocation(walletLocation)));\n\t\t\tmap.from(properties::getKerberosCacheFile)\n\t\t\t\t.to(extension.via((ext, kerberosCacheFile) -> ext.setKerberosCacheFile(kerberosCacheFile)));\n\t\t}\n\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic final class PostgresqlFlywayConfigurationCustomizer implements FlywayConfigurationCustomizer {\n\n\t\tprivate final FlywayProperties properties;\n\n\t\tPostgresqlFlywayConfigurationCustomizer(FlywayProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(FluentConfiguration configuration) {\n\t\t\tExtension<PostgreSQLConfigurationExtension> extension = new Extension<>(configuration,\n\t\t\t\t\tPostgreSQLConfigurationExtension.class, \"PostgreSQL\");\n\t\t\tPostgresql properties = this.properties.getPostgresql();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getTransactionalLock)\n\t\t\t\t.to(extension.via((ext, transactionalLock) -> ext.setTransactionalLock(transactionalLock)));\n\t\t}\n\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic final class SqlServerFlywayConfigurationCustomizer implements FlywayConfigurationCustomizer {\n\n\t\tprivate final FlywayProperties properties;\n\n\t\tSqlServerFlywayConfigurationCustomizer(FlywayProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(FluentConfiguration configuration) {\n\t\t\tExtension<SQLServerConfigurationExtension> extension = new Extension<>(configuration,\n\t\t\t\t\tSQLServerConfigurationExtension.class, \"SQL Server\");\n\t\t\tSqlserver properties = this.properties.getSqlserver();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getKerberosLoginFile).to(extension.via(this::setKerberosLoginFile));\n\t\t}\n\n\t\tprivate void setKerberosLoginFile(SQLServerConfigurationExtension configuration, String file) {\n\t\t\tconfiguration.getKerberos().getLogin().setFile(file);\n\t\t}\n\n\t}\n\n\t/**\n\t * Helper class used to map properties to a {@link ConfigurationExtension}.\n\t *\n\t * @param <E> the extension type\n\t */\n\tstatic class Extension<E extends ConfigurationExtension> {\n\n\t\tprivate final Supplier<E> extension;\n\n\t\tExtension(FluentConfiguration configuration, Class<E> type, String name) {\n\t\t\tthis.extension = SingletonSupplier.of(() -> {\n\t\t\t\tE extension = configuration.getPluginRegister().getExact(type);\n\t\t\t\tAssert.state(extension != null, () -> \"Flyway %s extension missing\".formatted(name));\n\t\t\t\treturn extension;\n\t\t\t});\n\t\t}\n\n\t\t<T> Consumer<T> via(BiConsumer<E, T> action) {\n\t\t\treturn (value) -> action.accept(this.extension.get(), value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayConfigurationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the flyway\n * configuration.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface FlywayConfigurationCustomizer {\n\n\t/**\n\t * Customize the flyway configuration.\n\t * @param configuration the {@link FluentConfiguration} to customize\n\t */\n\tvoid customize(FluentConfiguration configuration);\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\n/**\n * Details required for Flyway to establish a connection to an SQL service using JDBC.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface FlywayConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Username for the database or {@code null} if no Flyway-specific configuration is\n\t * required.\n\t * @return the username for the database or {@code null}\n\t */\n\t@Nullable String getUsername();\n\n\t/**\n\t * Password for the database or {@code null} if no Flyway-specific configuration is\n\t * required.\n\t * @return the password for the database or {@code null}\n\t */\n\t@Nullable String getPassword();\n\n\t/**\n\t * JDBC URL for the database or {@code null} if no Flyway-specific configuration is\n\t * required.\n\t * @return the JDBC URL for the database or {@code null}\n\t */\n\t@Nullable String getJdbcUrl();\n\n\t/**\n\t * The name of the JDBC driver class. Defaults to the class name of the driver\n\t * specified in the JDBC URL or {@code null} when no JDBC URL is configured.\n\t * @return the JDBC driver class name or {@code null}\n\t * @see #getJdbcUrl()\n\t * @see DatabaseDriver#fromJdbcUrl(String)\n\t * @see DatabaseDriver#getDriverClassName()\n\t */\n\tdefault @Nullable String getDriverClassName() {\n\t\tString jdbcUrl = getJdbcUrl();\n\t\treturn (jdbcUrl != null) ? DatabaseDriver.fromJdbcUrl(jdbcUrl).getDriverClassName() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayDataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\n/**\n * Qualifier annotation for a DataSource to be injected into Flyway. If used for a second\n * data source, the other (main) one would normally be marked as {@code @Primary}.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface FlywayDataSource {\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.Flyway;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.flyway.actuate.endpoint.FlywayEndpoint;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link FlywayEndpoint}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = FlywayAutoConfiguration.class)\n@ConditionalOnClass({ Flyway.class, ConditionalOnAvailableEndpoint.class })\n@ConditionalOnAvailableEndpoint(FlywayEndpoint.class)\npublic final class FlywayEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(Flyway.class)\n\t@ConditionalOnMissingBean\n\tFlywayEndpoint flywayEndpoint(ApplicationContext context) {\n\t\treturn new FlywayEndpoint(context);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayMigrationInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.Flyway;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * {@link InitializingBean} used to trigger {@link Flyway} migration through the\n * {@link FlywayMigrationStrategy}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class FlywayMigrationInitializer implements InitializingBean, Ordered {\n\n\tprivate final Flyway flyway;\n\n\tprivate final @Nullable FlywayMigrationStrategy migrationStrategy;\n\n\tprivate int order;\n\n\t/**\n\t * Create a new {@link FlywayMigrationInitializer} instance.\n\t * @param flyway the flyway instance\n\t */\n\tpublic FlywayMigrationInitializer(Flyway flyway) {\n\t\tthis(flyway, null);\n\t}\n\n\t/**\n\t * Create a new {@link FlywayMigrationInitializer} instance.\n\t * @param flyway the flyway instance\n\t * @param migrationStrategy the migration strategy or {@code null}\n\t */\n\tpublic FlywayMigrationInitializer(Flyway flyway, @Nullable FlywayMigrationStrategy migrationStrategy) {\n\t\tAssert.notNull(flyway, \"'flyway' must not be null\");\n\t\tthis.flyway = flyway;\n\t\tthis.migrationStrategy = migrationStrategy;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (this.migrationStrategy != null) {\n\t\t\tthis.migrationStrategy.migrate(this.flyway);\n\t\t}\n\t\telse {\n\t\t\ttry {\n\t\t\t\tthis.flyway.migrate();\n\t\t\t}\n\t\t\tcatch (NoSuchMethodError ex) {\n\t\t\t\t// Flyway < 7.0\n\t\t\t\tthis.flyway.getClass().getMethod(\"migrate\").invoke(this.flyway);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayMigrationInitializerDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\n\n/**\n * A {@link DatabaseInitializerDetector} for {@link FlywayMigrationInitializer}.\n *\n * @author Andy Wilkinson\n */\nclass FlywayMigrationInitializerDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\treturn Collections.singleton(FlywayMigrationInitializer.class);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayMigrationStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.Flyway;\n\n/**\n * Strategy used to initialize {@link Flyway} migration. Custom implementations may be\n * registered as a {@code @Bean} to override the default migration behavior.\n *\n * @author Andreas Ahlenstorf\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface FlywayMigrationStrategy {\n\n\t/**\n\t * Trigger flyway migration.\n\t * @param flyway the flyway instance\n\t */\n\tvoid migrate(Flyway flyway);\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywayProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.io.File;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\n\n/**\n * Configuration properties for Flyway database migrations.\n *\n * @author Dave Syer\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Chris Bono\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.flyway\")\npublic class FlywayProperties {\n\n\t/**\n\t * Whether to enable flyway.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Whether to fail if a location of migration scripts doesn't exist.\n\t */\n\tprivate boolean failOnMissingLocations;\n\n\t/**\n\t * Locations of migrations scripts. Can contain the special \"{vendor}\" placeholder to\n\t * use vendor-specific locations.\n\t */\n\tprivate List<String> locations = new ArrayList<>(Collections.singletonList(\"classpath:db/migration\"));\n\n\t/**\n\t * Locations of callbacks. Can contain the special \"{vendor}\" placeholder to use\n\t * vendor-specific callbacks. Unprefixed locations or locations starting with\n\t * \"classpath:\" point to a package on the classpath and may contain both SQL and\n\t * Java-based callbacks. Locations starting with \"filesystem:\" point to a directory on\n\t * the filesystem, may only contain SQL callbacks.\n\t */\n\tprivate List<String> callbackLocations = new ArrayList<>();\n\n\t/**\n\t * Encoding of SQL migrations.\n\t */\n\tprivate Charset encoding = StandardCharsets.UTF_8;\n\n\t/**\n\t * Maximum number of retries when attempting to connect to the database.\n\t */\n\tprivate int connectRetries;\n\n\t/**\n\t * Maximum time between retries when attempting to connect to the database. If a\n\t * duration suffix is not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate Duration connectRetriesInterval = Duration.ofSeconds(120);\n\n\t/**\n\t * Maximum number of retries when trying to obtain a lock.\n\t */\n\tprivate int lockRetryCount = 50;\n\n\t/**\n\t * Default schema name managed by Flyway (case-sensitive).\n\t */\n\tprivate @Nullable String defaultSchema;\n\n\t/**\n\t * Scheme names managed by Flyway (case-sensitive).\n\t */\n\tprivate List<String> schemas = new ArrayList<>();\n\n\t/**\n\t * Whether Flyway should attempt to create the schemas specified in the schemas\n\t * property.\n\t */\n\tprivate boolean createSchemas = true;\n\n\t/**\n\t * Name of the schema history table that will be used by Flyway.\n\t */\n\tprivate String table = \"flyway_schema_history\";\n\n\t/**\n\t * Tablespace in which the schema history table is created. Ignored when using a\n\t * database that does not support tablespaces. Defaults to the default tablespace of\n\t * the connection used by Flyway.\n\t */\n\tprivate @Nullable String tablespace;\n\n\t/**\n\t * Description to tag an existing schema with when applying a baseline.\n\t */\n\tprivate String baselineDescription = \"<< Flyway Baseline >>\";\n\n\t/**\n\t * Version to tag an existing schema with when executing baseline.\n\t */\n\tprivate String baselineVersion = \"1\";\n\n\t/**\n\t * Username recorded in the schema history table as having applied the migration.\n\t */\n\tprivate @Nullable String installedBy;\n\n\t/**\n\t * Placeholders and their replacements to apply to sql migration scripts.\n\t */\n\tprivate Map<String, String> placeholders = new HashMap<>();\n\n\t/**\n\t * Prefix of placeholders in migration scripts.\n\t */\n\tprivate String placeholderPrefix = \"${\";\n\n\t/**\n\t * Suffix of placeholders in migration scripts.\n\t */\n\tprivate String placeholderSuffix = \"}\";\n\n\t/**\n\t * Separator of default placeholders.\n\t */\n\tprivate String placeholderSeparator = \":\";\n\n\t/**\n\t * Perform placeholder replacement in migration scripts.\n\t */\n\tprivate boolean placeholderReplacement = true;\n\n\t/**\n\t * File name prefix for SQL migrations.\n\t */\n\tprivate String sqlMigrationPrefix = \"V\";\n\n\t/**\n\t * File name suffix for SQL migrations.\n\t */\n\tprivate List<String> sqlMigrationSuffixes = new ArrayList<>(Collections.singleton(\".sql\"));\n\n\t/**\n\t * File name separator for SQL migrations.\n\t */\n\tprivate String sqlMigrationSeparator = \"__\";\n\n\t/**\n\t * File name prefix for repeatable SQL migrations.\n\t */\n\tprivate String repeatableSqlMigrationPrefix = \"R\";\n\n\t/**\n\t * Target version up to which migrations should be considered.\n\t */\n\tprivate String target = \"latest\";\n\n\t/**\n\t * Login user of the database to migrate.\n\t */\n\tprivate @Nullable String user;\n\n\t/**\n\t * Login password of the database to migrate.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.\n\t */\n\tprivate @Nullable String driverClassName;\n\n\t/**\n\t * JDBC url of the database to migrate. If not set, the primary configured data source\n\t * is used.\n\t */\n\tprivate @Nullable String url;\n\n\t/**\n\t * SQL statements to execute to initialize a connection immediately after obtaining\n\t * it.\n\t */\n\tprivate List<String> initSqls = new ArrayList<>();\n\n\t/**\n\t * Whether to automatically call baseline when migrating a non-empty schema.\n\t */\n\tprivate boolean baselineOnMigrate;\n\n\t/**\n\t * Whether to disable cleaning of the database.\n\t */\n\tprivate boolean cleanDisabled = true;\n\n\t/**\n\t * Whether to group all pending migrations together in the same transaction when\n\t * applying them.\n\t */\n\tprivate boolean group;\n\n\t/**\n\t * Whether to allow mixing transactional and non-transactional statements within the\n\t * same migration.\n\t */\n\tprivate boolean mixed;\n\n\t/**\n\t * Whether to allow migrations to be run out of order.\n\t */\n\tprivate boolean outOfOrder;\n\n\t/**\n\t * Whether to skip default callbacks. If true, only custom callbacks are used.\n\t */\n\tprivate boolean skipDefaultCallbacks;\n\n\t/**\n\t * Whether to skip default resolvers. If true, only custom resolvers are used.\n\t */\n\tprivate boolean skipDefaultResolvers;\n\n\t/**\n\t * Whether to validate migrations and callbacks whose scripts do not obey the correct\n\t * naming convention.\n\t */\n\tprivate boolean validateMigrationNaming;\n\n\t/**\n\t * Whether to automatically call validate when performing a migration.\n\t */\n\tprivate boolean validateOnMigrate = true;\n\n\t/**\n\t * Prefix of placeholders in migration scripts.\n\t */\n\tprivate String scriptPlaceholderPrefix = \"FP__\";\n\n\t/**\n\t * Suffix of placeholders in migration scripts.\n\t */\n\tprivate String scriptPlaceholderSuffix = \"__\";\n\n\t/**\n\t * PowerShell executable to use for running PowerShell scripts. Default to\n\t * \"powershell\" on Windows, \"pwsh\" on other platforms.\n\t */\n\tprivate @Nullable String powershellExecutable;\n\n\t/**\n\t * Whether Flyway should execute SQL within a transaction.\n\t */\n\tprivate boolean executeInTransaction = true;\n\n\t/**\n\t * Loggers Flyway should use.\n\t */\n\tprivate String[] loggers = { \"slf4j\" };\n\n\t/**\n\t * Whether to batch SQL statements when executing them.\n\t */\n\tprivate @Nullable Boolean batch;\n\n\t/**\n\t * File to which the SQL statements of a migration dry run should be output. Requires\n\t * Flyway Teams.\n\t */\n\tprivate @Nullable File dryRunOutput;\n\n\t/**\n\t * Rules for the built-in error handling to override specific SQL states and error\n\t * codes. Requires Flyway Teams.\n\t */\n\tprivate String @Nullable [] errorOverrides;\n\n\t/**\n\t * Whether to stream SQL migrations when executing them.\n\t */\n\tprivate @Nullable Boolean stream;\n\n\t/**\n\t * Properties to pass to the JDBC driver.\n\t */\n\tprivate Map<String, String> jdbcProperties = new HashMap<>();\n\n\t/**\n\t * Path of the Kerberos config file. Requires Flyway Teams.\n\t */\n\tprivate @Nullable String kerberosConfigFile;\n\n\t/**\n\t * Whether Flyway should output a table with the results of queries when executing\n\t * migrations.\n\t */\n\tprivate @Nullable Boolean outputQueryResults;\n\n\t/**\n\t * Whether Flyway should skip executing the contents of the migrations and only update\n\t * the schema history table.\n\t */\n\tprivate @Nullable Boolean skipExecutingMigrations;\n\n\t/**\n\t * List of patterns that identify migrations to ignore when performing validation.\n\t */\n\tprivate List<String> ignoreMigrationPatterns = Collections.singletonList(\"*:future\");\n\n\t/**\n\t * Whether to attempt to automatically detect SQL migration file encoding.\n\t */\n\tprivate @Nullable Boolean detectEncoding;\n\n\t/**\n\t * Whether to enable community database support.\n\t */\n\tprivate @Nullable Boolean communityDbSupportEnabled;\n\n\tprivate final Oracle oracle = new Oracle();\n\n\tprivate final Postgresql postgresql = new Postgresql();\n\n\tprivate final Sqlserver sqlserver = new Sqlserver();\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic boolean isFailOnMissingLocations() {\n\t\treturn this.failOnMissingLocations;\n\t}\n\n\tpublic void setFailOnMissingLocations(boolean failOnMissingLocations) {\n\t\tthis.failOnMissingLocations = failOnMissingLocations;\n\t}\n\n\tpublic List<String> getLocations() {\n\t\treturn this.locations;\n\t}\n\n\tpublic void setLocations(List<String> locations) {\n\t\tthis.locations = locations;\n\t}\n\n\tpublic List<String> getCallbackLocations() {\n\t\treturn this.callbackLocations;\n\t}\n\n\tpublic void setCallbackLocations(List<String> callbackLocations) {\n\t\tthis.callbackLocations = callbackLocations;\n\t}\n\n\tpublic Charset getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\tpublic void setEncoding(Charset encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\tpublic int getConnectRetries() {\n\t\treturn this.connectRetries;\n\t}\n\n\tpublic void setConnectRetries(int connectRetries) {\n\t\tthis.connectRetries = connectRetries;\n\t}\n\n\tpublic Duration getConnectRetriesInterval() {\n\t\treturn this.connectRetriesInterval;\n\t}\n\n\tpublic void setConnectRetriesInterval(Duration connectRetriesInterval) {\n\t\tthis.connectRetriesInterval = connectRetriesInterval;\n\t}\n\n\tpublic int getLockRetryCount() {\n\t\treturn this.lockRetryCount;\n\t}\n\n\tpublic void setLockRetryCount(Integer lockRetryCount) {\n\t\tthis.lockRetryCount = lockRetryCount;\n\t}\n\n\tpublic @Nullable String getDefaultSchema() {\n\t\treturn this.defaultSchema;\n\t}\n\n\tpublic void setDefaultSchema(@Nullable String defaultSchema) {\n\t\tthis.defaultSchema = defaultSchema;\n\t}\n\n\tpublic List<String> getSchemas() {\n\t\treturn this.schemas;\n\t}\n\n\tpublic void setSchemas(List<String> schemas) {\n\t\tthis.schemas = schemas;\n\t}\n\n\tpublic boolean isCreateSchemas() {\n\t\treturn this.createSchemas;\n\t}\n\n\tpublic void setCreateSchemas(boolean createSchemas) {\n\t\tthis.createSchemas = createSchemas;\n\t}\n\n\tpublic String getTable() {\n\t\treturn this.table;\n\t}\n\n\tpublic void setTable(String table) {\n\t\tthis.table = table;\n\t}\n\n\tpublic @Nullable String getTablespace() {\n\t\treturn this.tablespace;\n\t}\n\n\tpublic void setTablespace(@Nullable String tablespace) {\n\t\tthis.tablespace = tablespace;\n\t}\n\n\tpublic String getBaselineDescription() {\n\t\treturn this.baselineDescription;\n\t}\n\n\tpublic void setBaselineDescription(String baselineDescription) {\n\t\tthis.baselineDescription = baselineDescription;\n\t}\n\n\tpublic String getBaselineVersion() {\n\t\treturn this.baselineVersion;\n\t}\n\n\tpublic void setBaselineVersion(String baselineVersion) {\n\t\tthis.baselineVersion = baselineVersion;\n\t}\n\n\tpublic @Nullable String getInstalledBy() {\n\t\treturn this.installedBy;\n\t}\n\n\tpublic void setInstalledBy(@Nullable String installedBy) {\n\t\tthis.installedBy = installedBy;\n\t}\n\n\tpublic Map<String, String> getPlaceholders() {\n\t\treturn this.placeholders;\n\t}\n\n\tpublic void setPlaceholders(Map<String, String> placeholders) {\n\t\tthis.placeholders = placeholders;\n\t}\n\n\tpublic String getPlaceholderPrefix() {\n\t\treturn this.placeholderPrefix;\n\t}\n\n\tpublic void setPlaceholderPrefix(String placeholderPrefix) {\n\t\tthis.placeholderPrefix = placeholderPrefix;\n\t}\n\n\tpublic String getPlaceholderSuffix() {\n\t\treturn this.placeholderSuffix;\n\t}\n\n\tpublic void setPlaceholderSuffix(String placeholderSuffix) {\n\t\tthis.placeholderSuffix = placeholderSuffix;\n\t}\n\n\tpublic String getPlaceholderSeparator() {\n\t\treturn this.placeholderSeparator;\n\t}\n\n\tpublic void setPlaceholderSeparator(String placeholderSeparator) {\n\t\tthis.placeholderSeparator = placeholderSeparator;\n\t}\n\n\tpublic boolean isPlaceholderReplacement() {\n\t\treturn this.placeholderReplacement;\n\t}\n\n\tpublic void setPlaceholderReplacement(boolean placeholderReplacement) {\n\t\tthis.placeholderReplacement = placeholderReplacement;\n\t}\n\n\tpublic String getSqlMigrationPrefix() {\n\t\treturn this.sqlMigrationPrefix;\n\t}\n\n\tpublic void setSqlMigrationPrefix(String sqlMigrationPrefix) {\n\t\tthis.sqlMigrationPrefix = sqlMigrationPrefix;\n\t}\n\n\tpublic List<String> getSqlMigrationSuffixes() {\n\t\treturn this.sqlMigrationSuffixes;\n\t}\n\n\tpublic void setSqlMigrationSuffixes(List<String> sqlMigrationSuffixes) {\n\t\tthis.sqlMigrationSuffixes = sqlMigrationSuffixes;\n\t}\n\n\tpublic String getSqlMigrationSeparator() {\n\t\treturn this.sqlMigrationSeparator;\n\t}\n\n\tpublic void setSqlMigrationSeparator(String sqlMigrationSeparator) {\n\t\tthis.sqlMigrationSeparator = sqlMigrationSeparator;\n\t}\n\n\tpublic String getRepeatableSqlMigrationPrefix() {\n\t\treturn this.repeatableSqlMigrationPrefix;\n\t}\n\n\tpublic void setRepeatableSqlMigrationPrefix(String repeatableSqlMigrationPrefix) {\n\t\tthis.repeatableSqlMigrationPrefix = repeatableSqlMigrationPrefix;\n\t}\n\n\tpublic String getTarget() {\n\t\treturn this.target;\n\t}\n\n\tpublic void setTarget(String target) {\n\t\tthis.target = target;\n\t}\n\n\tpublic @Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\tpublic void setUser(@Nullable String user) {\n\t\tthis.user = user;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable String getDriverClassName() {\n\t\treturn this.driverClassName;\n\t}\n\n\tpublic void setDriverClassName(@Nullable String driverClassName) {\n\t\tthis.driverClassName = driverClassName;\n\t}\n\n\tpublic @Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\tpublic void setUrl(@Nullable String url) {\n\t\tthis.url = url;\n\t}\n\n\tpublic List<String> getInitSqls() {\n\t\treturn this.initSqls;\n\t}\n\n\tpublic void setInitSqls(List<String> initSqls) {\n\t\tthis.initSqls = initSqls;\n\t}\n\n\tpublic boolean isBaselineOnMigrate() {\n\t\treturn this.baselineOnMigrate;\n\t}\n\n\tpublic void setBaselineOnMigrate(boolean baselineOnMigrate) {\n\t\tthis.baselineOnMigrate = baselineOnMigrate;\n\t}\n\n\tpublic boolean isCleanDisabled() {\n\t\treturn this.cleanDisabled;\n\t}\n\n\tpublic void setCleanDisabled(boolean cleanDisabled) {\n\t\tthis.cleanDisabled = cleanDisabled;\n\t}\n\n\tpublic boolean isGroup() {\n\t\treturn this.group;\n\t}\n\n\tpublic void setGroup(boolean group) {\n\t\tthis.group = group;\n\t}\n\n\tpublic boolean isMixed() {\n\t\treturn this.mixed;\n\t}\n\n\tpublic void setMixed(boolean mixed) {\n\t\tthis.mixed = mixed;\n\t}\n\n\tpublic boolean isOutOfOrder() {\n\t\treturn this.outOfOrder;\n\t}\n\n\tpublic void setOutOfOrder(boolean outOfOrder) {\n\t\tthis.outOfOrder = outOfOrder;\n\t}\n\n\tpublic boolean isSkipDefaultCallbacks() {\n\t\treturn this.skipDefaultCallbacks;\n\t}\n\n\tpublic void setSkipDefaultCallbacks(boolean skipDefaultCallbacks) {\n\t\tthis.skipDefaultCallbacks = skipDefaultCallbacks;\n\t}\n\n\tpublic boolean isSkipDefaultResolvers() {\n\t\treturn this.skipDefaultResolvers;\n\t}\n\n\tpublic void setSkipDefaultResolvers(boolean skipDefaultResolvers) {\n\t\tthis.skipDefaultResolvers = skipDefaultResolvers;\n\t}\n\n\tpublic boolean isValidateMigrationNaming() {\n\t\treturn this.validateMigrationNaming;\n\t}\n\n\tpublic void setValidateMigrationNaming(boolean validateMigrationNaming) {\n\t\tthis.validateMigrationNaming = validateMigrationNaming;\n\t}\n\n\tpublic boolean isValidateOnMigrate() {\n\t\treturn this.validateOnMigrate;\n\t}\n\n\tpublic void setValidateOnMigrate(boolean validateOnMigrate) {\n\t\tthis.validateOnMigrate = validateOnMigrate;\n\t}\n\n\tpublic String getScriptPlaceholderPrefix() {\n\t\treturn this.scriptPlaceholderPrefix;\n\t}\n\n\tpublic void setScriptPlaceholderPrefix(String scriptPlaceholderPrefix) {\n\t\tthis.scriptPlaceholderPrefix = scriptPlaceholderPrefix;\n\t}\n\n\tpublic String getScriptPlaceholderSuffix() {\n\t\treturn this.scriptPlaceholderSuffix;\n\t}\n\n\tpublic void setScriptPlaceholderSuffix(String scriptPlaceholderSuffix) {\n\t\tthis.scriptPlaceholderSuffix = scriptPlaceholderSuffix;\n\t}\n\n\tpublic @Nullable String getPowershellExecutable() {\n\t\treturn this.powershellExecutable;\n\t}\n\n\tpublic void setPowershellExecutable(@Nullable String powershellExecutable) {\n\t\tthis.powershellExecutable = powershellExecutable;\n\t}\n\n\tpublic boolean isExecuteInTransaction() {\n\t\treturn this.executeInTransaction;\n\t}\n\n\tpublic void setExecuteInTransaction(boolean executeInTransaction) {\n\t\tthis.executeInTransaction = executeInTransaction;\n\t}\n\n\tpublic String[] getLoggers() {\n\t\treturn this.loggers;\n\t}\n\n\tpublic void setLoggers(String[] loggers) {\n\t\tthis.loggers = loggers;\n\t}\n\n\tpublic @Nullable Boolean getBatch() {\n\t\treturn this.batch;\n\t}\n\n\tpublic void setBatch(@Nullable Boolean batch) {\n\t\tthis.batch = batch;\n\t}\n\n\tpublic @Nullable File getDryRunOutput() {\n\t\treturn this.dryRunOutput;\n\t}\n\n\tpublic void setDryRunOutput(@Nullable File dryRunOutput) {\n\t\tthis.dryRunOutput = dryRunOutput;\n\t}\n\n\tpublic String @Nullable [] getErrorOverrides() {\n\t\treturn this.errorOverrides;\n\t}\n\n\tpublic void setErrorOverrides(String @Nullable [] errorOverrides) {\n\t\tthis.errorOverrides = errorOverrides;\n\t}\n\n\tpublic @Nullable Boolean getStream() {\n\t\treturn this.stream;\n\t}\n\n\tpublic void setStream(@Nullable Boolean stream) {\n\t\tthis.stream = stream;\n\t}\n\n\tpublic Map<String, String> getJdbcProperties() {\n\t\treturn this.jdbcProperties;\n\t}\n\n\tpublic void setJdbcProperties(Map<String, String> jdbcProperties) {\n\t\tthis.jdbcProperties = jdbcProperties;\n\t}\n\n\tpublic @Nullable String getKerberosConfigFile() {\n\t\treturn this.kerberosConfigFile;\n\t}\n\n\tpublic void setKerberosConfigFile(@Nullable String kerberosConfigFile) {\n\t\tthis.kerberosConfigFile = kerberosConfigFile;\n\t}\n\n\tpublic @Nullable Boolean getOutputQueryResults() {\n\t\treturn this.outputQueryResults;\n\t}\n\n\tpublic void setOutputQueryResults(@Nullable Boolean outputQueryResults) {\n\t\tthis.outputQueryResults = outputQueryResults;\n\t}\n\n\tpublic @Nullable Boolean getSkipExecutingMigrations() {\n\t\treturn this.skipExecutingMigrations;\n\t}\n\n\tpublic void setSkipExecutingMigrations(@Nullable Boolean skipExecutingMigrations) {\n\t\tthis.skipExecutingMigrations = skipExecutingMigrations;\n\t}\n\n\tpublic List<String> getIgnoreMigrationPatterns() {\n\t\treturn this.ignoreMigrationPatterns;\n\t}\n\n\tpublic void setIgnoreMigrationPatterns(List<String> ignoreMigrationPatterns) {\n\t\tthis.ignoreMigrationPatterns = ignoreMigrationPatterns;\n\t}\n\n\tpublic @Nullable Boolean getDetectEncoding() {\n\t\treturn this.detectEncoding;\n\t}\n\n\tpublic void setDetectEncoding(final @Nullable Boolean detectEncoding) {\n\t\tthis.detectEncoding = detectEncoding;\n\t}\n\n\tpublic @Nullable Boolean getCommunityDbSupportEnabled() {\n\t\treturn this.communityDbSupportEnabled;\n\t}\n\n\tpublic void setCommunityDbSupportEnabled(@Nullable Boolean communityDbSupportEnabled) {\n\t\tthis.communityDbSupportEnabled = communityDbSupportEnabled;\n\t}\n\n\tpublic Oracle getOracle() {\n\t\treturn this.oracle;\n\t}\n\n\tpublic Postgresql getPostgresql() {\n\t\treturn this.postgresql;\n\t}\n\n\tpublic Sqlserver getSqlserver() {\n\t\treturn this.sqlserver;\n\t}\n\n\t/**\n\t * {@code OracleConfigurationExtension} properties.\n\t */\n\tpublic static class Oracle {\n\n\t\t/**\n\t\t * Whether to enable support for Oracle SQL*Plus commands. Requires Flyway Teams.\n\t\t */\n\t\tprivate @Nullable Boolean sqlplus;\n\n\t\t/**\n\t\t * Whether to issue a warning rather than an error when a not-yet-supported Oracle\n\t\t * SQL*Plus statement is encountered. Requires Flyway Teams.\n\t\t */\n\t\tprivate @Nullable Boolean sqlplusWarn;\n\n\t\t/**\n\t\t * Path of the Oracle Kerberos cache file. Requires Flyway Teams.\n\t\t */\n\t\tprivate @Nullable String kerberosCacheFile;\n\n\t\t/**\n\t\t * Location of the Oracle Wallet, used to sign in to the database automatically.\n\t\t * Requires Flyway Teams.\n\t\t */\n\t\tprivate @Nullable String walletLocation;\n\n\t\tpublic @Nullable Boolean getSqlplus() {\n\t\t\treturn this.sqlplus;\n\t\t}\n\n\t\tpublic void setSqlplus(@Nullable Boolean sqlplus) {\n\t\t\tthis.sqlplus = sqlplus;\n\t\t}\n\n\t\tpublic @Nullable Boolean getSqlplusWarn() {\n\t\t\treturn this.sqlplusWarn;\n\t\t}\n\n\t\tpublic void setSqlplusWarn(@Nullable Boolean sqlplusWarn) {\n\t\t\tthis.sqlplusWarn = sqlplusWarn;\n\t\t}\n\n\t\tpublic @Nullable String getKerberosCacheFile() {\n\t\t\treturn this.kerberosCacheFile;\n\t\t}\n\n\t\tpublic void setKerberosCacheFile(@Nullable String kerberosCacheFile) {\n\t\t\tthis.kerberosCacheFile = kerberosCacheFile;\n\t\t}\n\n\t\tpublic @Nullable String getWalletLocation() {\n\t\t\treturn this.walletLocation;\n\t\t}\n\n\t\tpublic void setWalletLocation(@Nullable String walletLocation) {\n\t\t\tthis.walletLocation = walletLocation;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@code PostgreSQLConfigurationExtension} properties.\n\t */\n\tpublic static class Postgresql {\n\n\t\t/**\n\t\t * Whether transactional advisory locks should be used. If set to false,\n\t\t * session-level locks are used instead.\n\t\t */\n\t\tprivate @Nullable Boolean transactionalLock;\n\n\t\tpublic @Nullable Boolean getTransactionalLock() {\n\t\t\treturn this.transactionalLock;\n\t\t}\n\n\t\tpublic void setTransactionalLock(@Nullable Boolean transactionalLock) {\n\t\t\tthis.transactionalLock = transactionalLock;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@code SQLServerConfigurationExtension} properties.\n\t */\n\tpublic static class Sqlserver {\n\n\t\t/**\n\t\t * Path to the SQL Server Kerberos login file. Requires Flyway Teams.\n\t\t */\n\t\tprivate @Nullable String kerberosLoginFile;\n\n\t\tpublic @Nullable String getKerberosLoginFile() {\n\t\t\treturn this.kerberosLoginFile;\n\t\t}\n\n\t\tpublic void setKerberosLoginFile(@Nullable String kerberosLoginFile) {\n\t\t\tthis.kerberosLoginFile = kerberosLoginFile;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/FlywaySchemaManagementProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.util.stream.StreamSupport;\n\nimport javax.sql.DataSource;\n\nimport org.flywaydb.core.Flyway;\n\nimport org.springframework.boot.jdbc.SchemaManagement;\nimport org.springframework.boot.jdbc.SchemaManagementProvider;\n\n/**\n * A Flyway {@link SchemaManagementProvider} that determines if the schema is managed by\n * looking at available {@link Flyway} instances.\n *\n * @author Stephane Nicoll\n */\nclass FlywaySchemaManagementProvider implements SchemaManagementProvider {\n\n\tprivate final Iterable<Flyway> flywayInstances;\n\n\tFlywaySchemaManagementProvider(Iterable<Flyway> flywayInstances) {\n\t\tthis.flywayInstances = flywayInstances;\n\t}\n\n\t@Override\n\tpublic SchemaManagement getSchemaManagement(DataSource dataSource) {\n\t\treturn StreamSupport.stream(this.flywayInstances.spliterator(), false)\n\t\t\t.map((flyway) -> flyway.getConfiguration().getDataSource())\n\t\t\t.filter(dataSource::equals)\n\t\t\t.findFirst()\n\t\t\t.map((managedDataSource) -> SchemaManagement.MANAGED)\n\t\t\t.orElse(SchemaManagement.UNMANAGED);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/NativeImageResourceProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.function.Predicate;\n\nimport org.flywaydb.core.api.FlywayException;\nimport org.flywaydb.core.api.Location;\nimport org.flywaydb.core.api.ResourceProvider;\nimport org.flywaydb.core.api.resource.LoadableResource;\nimport org.flywaydb.core.internal.resource.classpath.ClassPathResource;\nimport org.flywaydb.core.internal.scanner.Scanner;\nimport org.flywaydb.core.internal.util.StringUtils;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.NativeDetector;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\n/**\n * A Flyway {@link ResourceProvider} which supports GraalVM native-image.\n * <p>\n * It delegates work to Flyways {@link Scanner}, and additionally uses\n * {@link PathMatchingResourcePatternResolver} to find migration files in a native image.\n *\n * @author Moritz Halbritter\n */\nclass NativeImageResourceProvider implements ResourceProvider {\n\n\tprivate final Scanner<?> scanner;\n\n\tprivate final ClassLoader classLoader;\n\n\tprivate final Collection<Location> locations;\n\n\tprivate final Charset encoding;\n\n\tprivate final boolean failOnMissingLocations;\n\n\tprivate final List<LocatedResource> locatedResources = new ArrayList<>();\n\n\tprivate final Lock lock = new ReentrantLock();\n\n\tprivate boolean initialized;\n\n\tNativeImageResourceProvider(Scanner<?> scanner, ClassLoader classLoader, Collection<Location> locations,\n\t\t\tCharset encoding, boolean failOnMissingLocations) {\n\t\tthis.scanner = scanner;\n\t\tthis.classLoader = classLoader;\n\t\tthis.locations = locations;\n\t\tthis.encoding = encoding;\n\t\tthis.failOnMissingLocations = failOnMissingLocations;\n\t}\n\n\t@Override\n\tpublic @Nullable LoadableResource getResource(String name) {\n\t\tif (!NativeDetector.inNativeImage()) {\n\t\t\treturn this.scanner.getResource(name);\n\t\t}\n\t\tLoadableResource resource = this.scanner.getResource(name);\n\t\tif (resource != null) {\n\t\t\treturn resource;\n\t\t}\n\t\tif (this.classLoader.getResource(name) == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ClassPathResource(null, name, this.classLoader, this.encoding);\n\t}\n\n\t@Override\n\tpublic Collection<LoadableResource> getResources(String prefix, String[] suffixes) {\n\t\tif (!NativeDetector.inNativeImage()) {\n\t\t\treturn this.scanner.getResources(prefix, suffixes);\n\t\t}\n\t\tensureInitialized();\n\t\tPredicate<LocatedResource> matchesPrefixAndSuffixes = (locatedResource) -> StringUtils\n\t\t\t.startsAndEndsWith(locatedResource.resource.getFilename(), prefix, suffixes);\n\t\tList<LoadableResource> result = new ArrayList<>(this.scanner.getResources(prefix, suffixes));\n\t\tthis.locatedResources.stream()\n\t\t\t.filter(matchesPrefixAndSuffixes)\n\t\t\t.map(this::asClassPathResource)\n\t\t\t.forEach(result::add);\n\t\treturn result;\n\t}\n\n\tprivate ClassPathResource asClassPathResource(LocatedResource locatedResource) {\n\t\tLocation location = locatedResource.location();\n\t\tString fileNameWithAbsolutePath = location.getRootPath() + \"/\" + locatedResource.resource().getFilename();\n\t\treturn new ClassPathResource(location, fileNameWithAbsolutePath, this.classLoader, this.encoding);\n\t}\n\n\tprivate void ensureInitialized() {\n\t\tthis.lock.lock();\n\t\ttry {\n\t\t\tif (!this.initialized) {\n\t\t\t\tinitialize();\n\t\t\t\tthis.initialized = true;\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tthis.lock.unlock();\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate void initialize() {\n\t\tPathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();\n\t\tfor (Location location : this.locations) {\n\t\t\tif (!location.isClassPath()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tResource root = resolver.getResource(location.getDescriptor());\n\t\t\tif (!root.exists()) {\n\t\t\t\tif (this.failOnMissingLocations) {\n\t\t\t\t\tthrow new FlywayException(\"Location \" + location.getDescriptor() + \" doesn't exist\");\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tResource[] resources = getResources(resolver, location, root);\n\t\t\tfor (Resource resource : resources) {\n\t\t\t\tthis.locatedResources.add(new LocatedResource(resource, location));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Resource[] getResources(PathMatchingResourcePatternResolver resolver, Location location, Resource root) {\n\t\ttry {\n\t\t\treturn resolver.getResources(root.getURI() + \"/**/*\");\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(\"Failed to list resources for \" + location.getDescriptor(), ex);\n\t\t}\n\t}\n\n\tprivate record LocatedResource(Resource resource, Location location) {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/NativeImageResourceProviderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.util.Arrays;\n\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\nimport org.flywaydb.core.api.migration.JavaMigration;\nimport org.flywaydb.core.internal.scanner.Scanner;\n\n/**\n * Registers {@link NativeImageResourceProvider} as a Flyway\n * {@link org.flywaydb.core.api.ResourceProvider}.\n *\n * @author Moritz Halbritter\n */\nclass NativeImageResourceProviderCustomizer extends ResourceProviderCustomizer {\n\n\t@Override\n\tpublic void customize(FluentConfiguration configuration) {\n\t\tif (configuration.getResourceProvider() == null) {\n\t\t\tScanner<JavaMigration> scanner = new Scanner<>(JavaMigration.class, configuration,\n\t\t\t\t\tconfiguration.getLocations());\n\t\t\tNativeImageResourceProvider resourceProvider = new NativeImageResourceProvider(scanner,\n\t\t\t\t\tconfiguration.getClassLoader(), Arrays.asList(configuration.getLocations()),\n\t\t\t\t\tconfiguration.getEncoding(), configuration.isFailOnMissingLocations());\n\t\t\tconfiguration.resourceProvider(resourceProvider);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/ResourceProviderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\n\n/**\n * A Flyway customizer which gets replaced with\n * {@link NativeImageResourceProviderCustomizer} when running in a native image.\n *\n * @author Moritz Halbritter\n */\nclass ResourceProviderCustomizer {\n\n\tvoid customize(FluentConfiguration configuration) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/ResourceProviderCustomizerBeanRegistrationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport javax.lang.model.element.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GeneratedMethod;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.javapoet.CodeBlock;\n\n/**\n * Replaces the {@link ResourceProviderCustomizer} bean with a\n * {@link NativeImageResourceProviderCustomizer} bean.\n *\n * @author Moritz Halbritter\n */\nclass ResourceProviderCustomizerBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {\n\n\t@Override\n\tpublic @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n\t\tif (registeredBean.getBeanClass().equals(ResourceProviderCustomizer.class)) {\n\t\t\treturn BeanRegistrationAotContribution\n\t\t\t\t.withCustomCodeFragments((codeFragments) -> new AotContribution(codeFragments, registeredBean));\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static class AotContribution extends BeanRegistrationCodeFragmentsDecorator {\n\n\t\tprivate final RegisteredBean registeredBean;\n\n\t\tprotected AotContribution(BeanRegistrationCodeFragments delegate, RegisteredBean registeredBean) {\n\t\t\tsuper(delegate);\n\t\t\tthis.registeredBean = registeredBean;\n\t\t}\n\n\t\t@Override\n\t\tpublic CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,\n\t\t\t\tBeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {\n\t\t\tGeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add(\"getInstance\", (method) -> {\n\t\t\t\tmethod.addJavadoc(\"Get the bean instance for '$L'.\", this.registeredBean.getBeanName());\n\t\t\t\tmethod.addModifiers(Modifier.PRIVATE, Modifier.STATIC);\n\t\t\t\tmethod.returns(NativeImageResourceProviderCustomizer.class);\n\t\t\t\tCodeBlock.Builder code = CodeBlock.builder();\n\t\t\t\tcode.addStatement(\"return new $T()\", NativeImageResourceProviderCustomizer.class);\n\t\t\t\tmethod.addCode(code.build());\n\t\t\t});\n\t\t\treturn generatedMethod.toMethodReference().toCodeBlock();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Flyway.\n */\n@NullMarked\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/docker/compose/JdbcAdaptingFlywayConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;\nimport org.springframework.boot.flyway.autoconfigure.FlywayConnectionDetails;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link ConnectionDetailsFactory} that produces {@link FlywayConnectionDetails} by\n * adapting {@link JdbcConnectionDetails}.\n *\n * @author Andy Wilkinson\n */\nclass JdbcAdaptingFlywayConnectionDetailsFactory\n\t\timplements ConnectionDetailsFactory<JdbcConnectionDetails, FlywayConnectionDetails> {\n\n\t@Override\n\tpublic FlywayConnectionDetails getConnectionDetails(JdbcConnectionDetails input) {\n\t\treturn new FlywayConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getUsername() {\n\t\t\t\treturn input.getUsername();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getPassword() {\n\t\t\t\treturn input.getPassword();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getJdbcUrl() {\n\t\t\t\treturn input.getJdbcUrl();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getDriverClassName() {\n\t\t\t\treturn input.getDriverClassName();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Flyway service connections.\n */\n@NullMarked\npackage org.springframework.boot.flyway.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom support for Flyway database migration.\n */\n@NullMarked\npackage org.springframework.boot.flyway;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/testcontainers/FlywayContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.testcontainers;\n\nimport org.testcontainers.containers.JdbcDatabaseContainer;\n\nimport org.springframework.boot.flyway.autoconfigure.FlywayConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link FlywayConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link JdbcDatabaseContainer}.\n *\n * @author Andy Wilkinson\n */\nclass FlywayContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<JdbcDatabaseContainer<?>, FlywayConnectionDetails> {\n\n\t@Override\n\tprotected FlywayConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\treturn new FlywayContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link FlywayConnectionDetails} backed by a {@link JdbcDatabaseContainer}.\n\t */\n\tprivate static final class FlywayContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<JdbcDatabaseContainer<?>> implements FlywayConnectionDetails {\n\n\t\tprivate FlywayContainerConnectionDetails(ContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn getContainer().getJdbcUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDriverClassName() {\n\t\t\treturn getContainer().getDriverClassName();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/java/org/springframework/boot/flyway/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Flyway service connections.\n */\n@NullMarked\npackage org.springframework.boot.flyway.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/resources/META-INF/spring/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.flyway.baseline-migration-prefix\",\n      \"defaultValue\": \"B\",\n      \"description\": \"Filename prefix for baseline migrations. Requires Flyway Teams.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 9.0\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.check-location\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.fail-on-missing-locations\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.cherry-pick\",\n      \"description\": \"Migrations that Flyway should consider when migrating or undoing. When empty all available migrations are considered. Requires Flyway Teams.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 10\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.clean-on-validation-error\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to automatically call clean when a validation error occurs.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Deprecated in Flyway 10.18 and removed in Flyway 11.0\",\n        \"since\": \"3.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.community-db-support-enabled\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.flyway.dry-run-output\",\n      \"type\": \"java.io.OutputStream\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Flyway Teams only.\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.error-handlers\",\n      \"type\": \"org.flywaydb.core.api.errorhandler.ErrorHandler[]\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Flyway Teams only.\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.ignore-future-migrations\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to ignore future migrations when reading the schema history table.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 9.0\",\n        \"replacement\": \"spring.flyway.ignore-migration-patterns\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.ignore-ignored-migrations\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to ignore ignored migrations when reading the schema history table.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 9.0\",\n        \"replacement\": \"spring.flyway.ignore-migration-patterns\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.ignore-missing-migrations\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to ignore missing migrations when reading the schema history table.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 9.0\",\n        \"replacement\": \"spring.flyway.ignore-migration-patterns\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.ignore-pending-migrations\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to ignore pending migrations when reading the schema history table.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 9.0\",\n        \"replacement\": \"spring.flyway.ignore-migration-patterns\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.license-key\",\n      \"description\": \"License key for Flyway Teams.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 10\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.locations\",\n      \"sourceType\": \"org.springframework.boot.flyway.autoconfigure.FlywayProperties\",\n      \"defaultValue\": [\n        \"classpath:db/migration\"\n      ]\n    },\n    {\n      \"name\": \"spring.flyway.oracle-kerberos-cache-file\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.oracle.kerberos-cache-file\",\n        \"level\": \"error\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.oracle-kerberos-config-file\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.kerberos-config-file\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.oracle-sqlplus\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.oracle.sqlplus\",\n        \"level\": \"error\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.oracle-sqlplus-warn\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.oracle.sqlplus-warn\",\n        \"level\": \"error\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.oracle-wallet-location\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.oracle.wallet-location\",\n        \"level\": \"error\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.sql-migration-suffix\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.sql-migration-suffixes\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.sql-migration-suffixes\",\n      \"sourceType\": \"org.springframework.boot.flyway.autoconfigure.FlywayProperties\",\n      \"defaultValue\": [\n        \".sql\"\n      ]\n    },\n    {\n      \"name\": \"spring.flyway.sql-server-kerberos-login-file\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"spring.flyway.sqlserver.kerberos-login-file\",\n        \"level\": \"error\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.undo-sql-migration-prefix\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in Flyway 10\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.vault-secrets\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in the open source release of Flyway 7.12.\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.vault-token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in the open source release of Flyway 7.12.\"\n      }\n    },\n    {\n      \"name\": \"spring.flyway.vault-url\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Removed in the open source release of Flyway 7.12.\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-flyway/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\\\norg.springframework.boot.flyway.autoconfigure.ResourceProviderCustomizerBeanRegistrationAotProcessor\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration\norg.springframework.boot.flyway.autoconfigure.FlywayEndpointAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization.imports",
    "content": "org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-flyway/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.flyway.docker.compose.JdbcAdaptingFlywayConnectionDetailsFactory,\\\norg.springframework.boot.flyway.testcontainers.FlywayContainerConnectionDetailsFactory\n\n# Database Initializer Detectors\norg.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\\\norg.springframework.boot.flyway.FlywayDatabaseInitializerDetector,\\\norg.springframework.boot.flyway.autoconfigure.FlywayMigrationInitializerDatabaseInitializerDetector\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/actuate/endpoint/FlywayEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.actuate.endpoint;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.flyway.actuate.endpoint.FlywayEndpoint.ContextFlywayBeansDescriptor;\nimport org.springframework.boot.flyway.actuate.endpoint.FlywayEndpoint.FlywayDescriptor;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.flyway.autoconfigure.FlywayMigrationStrategy;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FlywayEndpoint}.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@WithResource(name = \"db/migration/V1__init.sql\", content = \"DROP TABLE IF EXISTS TEST;\")\n@WithResource(name = \"db/migration/V2__update.sql\", content = \"DROP TABLE IF EXISTS TEST;\")\n@WithResource(name = \"db/migration/V3__update.sql\", content = \"DROP TABLE IF EXISTS TEST;\")\nclass FlywayEndpointTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t.withBean(\"endpoint\", FlywayEndpoint.class);\n\n\t@Test\n\tvoid flywayReportIsProduced() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tContextFlywayBeansDescriptor descriptor = context.getBean(FlywayEndpoint.class)\n\t\t\t\t.flywayBeans()\n\t\t\t\t.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tMap<String, FlywayDescriptor> flywayBeans = descriptor.getFlywayBeans();\n\t\t\tassertThat(flywayBeans).hasSize(1);\n\t\t\tassertThat(flywayBeans.values().iterator().next().getMigrations()).hasSize(3);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenFlywayHasBeenBaselinedFlywayReportIsProduced() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.flyway.baseline-version=2\")\n\t\t\t.withBean(FlywayMigrationStrategy.class, () -> (flyway) -> {\n\t\t\t\tflyway.baseline();\n\t\t\t\tflyway.migrate();\n\t\t\t})\n\t\t\t.run((context) -> {\n\t\t\t\tContextFlywayBeansDescriptor descriptor = context.getBean(FlywayEndpoint.class)\n\t\t\t\t\t.flywayBeans()\n\t\t\t\t\t.getContexts()\n\t\t\t\t\t.get(context.getId());\n\t\t\t\tassertThat(descriptor).isNotNull();\n\t\t\t\tMap<String, FlywayDescriptor> flywayBeans = descriptor.getFlywayBeans();\n\t\t\t\tassertThat(flywayBeans).hasSize(1);\n\t\t\t\tassertThat(flywayBeans.values().iterator().next().getMigrations()).hasSize(4);\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/Flyway110AutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.Flyway;\nimport org.flywaydb.core.api.Location;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FlywayAutoConfiguration} with Flyway 10.0.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions({ \"flyway-core-*.jar\", \"flyway-sqlserver-*.jar\" })\n@ClassPathOverrides({ \"org.flywaydb:flyway-core:11.0.0\" })\nclass Flyway110AutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid defaultFlyway() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\tassertThat(flyway.getConfiguration().getLocations())\n\t\t\t\t.containsExactly(createLocation(\"classpath:db/migration\"));\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static Location createLocation(String location) {\n\t\treturn new Location(location);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/FlywayAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.io.Serializable;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport org.flywaydb.core.Flyway;\nimport org.flywaydb.core.api.Location;\nimport org.flywaydb.core.api.MigrationVersion;\nimport org.flywaydb.core.api.callback.Callback;\nimport org.flywaydb.core.api.callback.Context;\nimport org.flywaydb.core.api.callback.Event;\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\nimport org.flywaydb.core.api.migration.JavaMigration;\nimport org.flywaydb.core.api.pattern.ValidatePattern;\nimport org.flywaydb.core.internal.configuration.models.ResolvedEnvironment;\nimport org.flywaydb.core.internal.license.FlywayEditionUpgradeRequiredException;\nimport org.flywaydb.database.oracle.OracleConfigurationExtension;\nimport org.flywaydb.database.postgresql.PostgreSQLConfigurationExtension;\nimport org.flywaydb.database.sqlserver.SQLServerConfigurationExtension;\nimport org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.InOrder;\nimport org.postgresql.Driver;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration.FlywayAutoConfigurationRuntimeHints;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration.OracleFlywayConfigurationCustomizer;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration.PostgresqlFlywayConfigurationCustomizer;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration.SqlServerFlywayConfigurationCustomizer;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.SchemaManagement;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.stereotype.Component;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link FlywayAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Dominic Gunn\n * @author András Deák\n * @author Takaaki Shimbo\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass FlywayAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid backsOffWithNoDataSourceBeanAndNoFlywayUrl() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Flyway.class));\n\t}\n\n\t@Test\n\tvoid createsDataSourceWithNoDataSourceBeanAndFlywayUrl() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.flyway.url:jdbc:hsqldb:mem:\" + UUID.randomUUID())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffWithFlywayUrlAndNoSpringJdbc() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.flyway.url:jdbc:hsqldb:mem:\" + UUID.randomUUID())\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.jdbc\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Flyway.class));\n\t}\n\n\t@Test\n\tvoid createDataSourceWithUrl() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.url:jdbc:hsqldb:mem:flywaytest\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayPropertiesAreUsedOverJdbcConnectionDetails() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JdbcConnectionDetailsConfiguration.class,\n\t\t\t\t\tMockFlywayMigrationStrategy.class)\n\t\t\t.withPropertyValues(\"spring.flyway.url=jdbc:hsqldb:mem:flywaytest\", \"spring.flyway.user=some-user\",\n\t\t\t\t\t\"spring.flyway.password=some-password\",\n\t\t\t\t\t\"spring.flyway.driver-class-name=org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tDataSource dataSource = flyway.getConfiguration().getDataSource();\n\t\t\t\tassertThat(dataSource).isInstanceOf(SimpleDriverDataSource.class);\n\t\t\t\tSimpleDriverDataSource simpleDriverDataSource = (SimpleDriverDataSource) dataSource;\n\t\t\t\tassertThat(simpleDriverDataSource.getUrl()).isEqualTo(\"jdbc:hsqldb:mem:flywaytest\");\n\t\t\t\tassertThat(simpleDriverDataSource.getUsername()).isEqualTo(\"some-user\");\n\t\t\t\tassertThat(simpleDriverDataSource.getPassword()).isEqualTo(\"some-password\");\n\t\t\t\tassertThat(simpleDriverDataSource.getDriver()).isInstanceOf(org.hsqldb.jdbc.JDBCDriver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayConnectionDetailsAreUsedOverFlywayProperties() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayConnectionDetailsConfiguration.class,\n\t\t\t\t\tMockFlywayMigrationStrategy.class)\n\t\t\t.withPropertyValues(\"spring.flyway.url=jdbc:hsqldb:mem:flywaytest\", \"spring.flyway.user=some-user\",\n\t\t\t\t\t\"spring.flyway.password=some-password\",\n\t\t\t\t\t\"spring.flyway.driver-class-name=org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tDataSource dataSource = flyway.getConfiguration().getDataSource();\n\t\t\t\tassertThat(dataSource).isInstanceOf(SimpleDriverDataSource.class);\n\t\t\t\tSimpleDriverDataSource simpleDriverDataSource = (SimpleDriverDataSource) dataSource;\n\t\t\t\tassertThat(simpleDriverDataSource.getUrl())\n\t\t\t\t\t.isEqualTo(\"jdbc:postgresql://database.example.com:12345/database-1\");\n\t\t\t\tassertThat(simpleDriverDataSource.getUsername()).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(simpleDriverDataSource.getPassword()).isEqualTo(\"secret-1\");\n\t\t\t\tassertThat(simpleDriverDataSource.getDriver()).isInstanceOf(Driver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseMainDataSourceWhenThereIsNoFlywaySpecificConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JdbcConnectionDetailsConfiguration.class,\n\t\t\t\t\tMockFlywayMigrationStrategy.class)\n\t\t\t.withPropertyValues(\"spring.datasource.url=jdbc:hsqldb:mem:flywaytest\", \"spring.datasource.user=some-user\",\n\t\t\t\t\t\"spring.datasource.password=some-password\",\n\t\t\t\t\t\"spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getDataSource()).isSameAs(context.getBean(DataSource.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createDataSourceWithUser() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.url:jdbc:hsqldb:mem:\" + UUID.randomUUID(), \"spring.flyway.user:sa\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createDataSourceDoesNotFallbackToEmbeddedProperties() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.url:jdbc:hsqldb:mem:flywaytest\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tDataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource();\n\t\t\t\tassertThat(dataSource).isNotNull();\n\t\t\t\tassertThat(dataSource).hasFieldOrPropertyWithValue(\"username\", null);\n\t\t\t\tassertThat(dataSource).hasFieldOrPropertyWithValue(\"password\", null);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createDataSourceWithUserAndFallbackToEmbeddedProperties() {\n\t\tthis.contextRunner.withUserConfiguration(PropertiesBackedH2DataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.user:test\", \"spring.flyway.password:secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tDataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource();\n\t\t\t\tassertThat(dataSource).isNotNull();\n\t\t\t\tassertThat(dataSource).extracting(\"url\").asString().startsWith(\"jdbc:h2:mem:\");\n\t\t\t\tassertThat(dataSource).extracting(\"username\").asString().isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createDataSourceWithUserAndCustomEmbeddedProperties() {\n\t\tthis.contextRunner.withUserConfiguration(CustomBackedH2DataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.user:test\", \"spring.flyway.password:secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tString expectedName = context.getBean(CustomBackedH2DataSourceConfiguration.class).name;\n\t\t\t\tString propertiesName = context.getBean(DataSourceProperties.class).determineDatabaseName();\n\t\t\t\tassertThat(expectedName).isNotEqualTo(propertiesName);\n\t\t\t\tDataSource dataSource = context.getBean(Flyway.class).getConfiguration().getDataSource();\n\t\t\t\tassertThat(dataSource).isNotNull();\n\t\t\t\tassertThat(dataSource).extracting(\"url\").asString().startsWith(\"jdbc:h2:mem:\").contains(expectedName);\n\t\t\t\tassertThat(dataSource).extracting(\"username\").asString().isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayDataSource() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FlywayDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource())\n\t\t\t\t\t.isEqualTo(context.getBean(\"flywayDataSource\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayDataSourceIsUsedWhenJdbcConnectionDetailsIsAvailable() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FlywayDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tJdbcConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class);\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource())\n\t\t\t\t\t.isEqualTo(context.getBean(\"flywayDataSource\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayDataSourceIsUsedWhenFlywayConnectionDetailsIsAvailable() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FlywayDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tFlywayConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(FlywayConnectionDetails.class);\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource())\n\t\t\t\t\t.isEqualTo(context.getBean(\"flywayDataSource\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayDataSourceWithoutDataSourceAutoConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(FlywayDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource())\n\t\t\t\t.isEqualTo(context.getBean(\"flywayDataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid flywayMultipleDataSources() {\n\t\tthis.contextRunner.withUserConfiguration(FlywayMultipleDataSourcesConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\tassertThat(context.getBean(Flyway.class).getConfiguration().getDataSource())\n\t\t\t\t.isEqualTo(context.getBean(\"flywayDataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid schemaManagementProviderDetectsDataSource() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(FlywayDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tFlywaySchemaManagementProvider schemaManagementProvider = context\n\t\t\t\t\t.getBean(FlywaySchemaManagementProvider.class);\n\t\t\t\tassertThat(schemaManagementProvider\n\t\t\t\t\t.getSchemaManagement(context.getBean(\"normalDataSource\", DataSource.class)))\n\t\t\t\t\t.isEqualTo(SchemaManagement.UNMANAGED);\n\t\t\t\tassertThat(schemaManagementProvider\n\t\t\t\t\t.getSchemaManagement(context.getBean(\"flywayDataSource\", DataSource.class)))\n\t\t\t\t\t.isEqualTo(SchemaManagement.MANAGED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultFlyway() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\tassertThat(flyway.getConfiguration().getLocations())\n\t\t\t\t.containsExactly(createLocation(\"classpath:db/migration\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid overrideLocations() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.locations:classpath:db/changelog,classpath:db/migration\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getLocations()).containsExactly(\n\t\t\t\t\t\tcreateLocation(\"classpath:db/changelog\"), createLocation(\"classpath:db/migration\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid overrideLocationsList() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.locations[0]:classpath:db/changelog\",\n\t\t\t\t\t\"spring.flyway.locations[1]:classpath:db/migration\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getLocations()).containsExactly(\n\t\t\t\t\t\tcreateLocation(\"classpath:db/changelog\"), createLocation(\"classpath:db/migration\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid overrideSchemas() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.schemas:public\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(Arrays.asList(flyway.getConfiguration().getSchemas())).hasToString(\"[public]\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid overrideDataSourceAndDriverClassName() {\n\t\tString jdbcUrl = \"jdbc:hsqldb:mem:flyway\" + UUID.randomUUID();\n\t\tString driverClassName = \"org.hsqldb.jdbcDriver\";\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.url:\" + jdbcUrl, \"spring.flyway.driver-class-name:\" + driverClassName)\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) flyway.getConfiguration().getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);\n\t\t\t\tjava.sql.Driver driver = dataSource.getDriver();\n\t\t\t\tassertThat(driver).isNotNull();\n\t\t\t\tassertThat(driver.getClass().getName()).isEqualTo(driverClassName);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid changeLogDoesNotExist() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.fail-on-missing-locations=true\",\n\t\t\t\t\t\"spring.flyway.locations:filesystem:no-such-dir\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().isInstanceOf(BeanCreationException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid failOnMissingLocationsAllMissing() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.fail-on-missing-locations=true\")\n\t\t\t.withPropertyValues(\"spring.flyway.locations:classpath:db/missing1,classpath:db/migration2\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().isInstanceOf(BeanCreationException.class);\n\t\t\t\tassertThat(context).getFailure().hasMessageContaining(\"Unable to resolve location\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/V1.1__refine.sql\")\n\t@WithResource(name = \"db/migration/V1__init.sql\", content = \"DROP TABLE IF EXISTS TEST\")\n\tvoid failOnMissingLocationsDoesNotFailWhenAllExist() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.fail-on-missing-locations=true\")\n\t\t\t.withPropertyValues(\"spring.flyway.locations:classpath:db/changelog,classpath:db/migration\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/V1.1__refine.sql\")\n\t@WithResource(name = \"db/migration/V1__init.sql\", content = \"DROP TABLE IF EXISTS TEST\")\n\tvoid failOnMissingLocationsAllExistWithImplicitClasspathPrefix() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.fail-on-missing-locations=true\")\n\t\t\t.withPropertyValues(\"spring.flyway.locations:db/changelog,db/migration\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/migration/V1__init.sql\", content = \"DROP TABLE IF EXISTS TEST\")\n\tvoid failOnMissingLocationsFilesystemPrefixDoesNotFailWhenAllExist(@ResourcePath(\"db/migration\") String migration) {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.fail-on-missing-locations=true\")\n\t\t\t.withPropertyValues(\"spring.flyway.locations:filesystem:\" + migration)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid customFlywayMigrationStrategy() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, MockFlywayMigrationStrategy.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tcontext.getBean(MockFlywayMigrationStrategy.class).assertCalled();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid flywayJavaMigrations() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayJavaMigrationsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getJavaMigrations()).hasSize(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customFlywayMigrationInitializer() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlywayMigrationInitializer.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlywayMigrationInitializer initializer = context.getBean(FlywayMigrationInitializer.class);\n\t\t\t\tassertThat(initializer.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid customFlywayWithJpa() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlywayWithJpaConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid customFlywayWithJdbc() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomFlywayWithJdbcConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid customFlywayMigrationInitializerWithJpa() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tCustomFlywayMigrationInitializerWithJpaConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid customFlywayMigrationInitializerWithJdbc() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tCustomFlywayMigrationInitializerWithJdbcConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid overrideBaselineVersionString() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.baseline-version=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getBaselineVersion()).isEqualTo(MigrationVersion.fromVersion(\"0\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid overrideBaselineVersionNumber() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.baseline-version=1\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getBaselineVersion()).isEqualTo(MigrationVersion.fromVersion(\"1\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/vendors/h2/V1__init.sql\", content = \"DROP TABLE IF EXISTS TEST;\")\n\tvoid useVendorDirectory() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.locations=classpath:db/vendors/{vendor},classpath:db/changelog\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getLocations()).containsExactlyInAnyOrder(\n\t\t\t\t\t\tcreateLocation(\"classpath:db/vendors/h2\"), createLocation(\"classpath:db/changelog\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/vendors/h2/V1__init.sql\", content = \"DROP TABLE IF EXISTS TEST;\")\n\tvoid useOneLocationWithVendorDirectory() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.locations=classpath:db/vendors/{vendor}\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getLocations())\n\t\t\t\t\t.containsExactly(createLocation(\"classpath:db/vendors/h2\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"com/example/h2/beforeEachMigrate.sql\", content = \"DROP TABLE IF EXISTS TEMP;\")\n\tvoid useOneCallbackLocationWithVendorSpecificPackage() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.callback-locations=classpath:com.example.{vendor}\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getCallbackLocations())\n\t\t\t\t\t.containsExactly(createLocation(\"classpath:com.example.h2\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid callbacksAreConfiguredAndOrderedByName() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CallbackConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tCallback callbackOne = context.getBean(\"callbackOne\", Callback.class);\n\t\t\t\tCallback callbackTwo = context.getBean(\"callbackTwo\", Callback.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getCallbacks()).hasSize(2);\n\t\t\t\tInOrder orderedCallbacks = inOrder(callbackOne, callbackTwo);\n\t\t\t\torderedCallbacks.verify(callbackTwo).handle(any(Event.class), any(Context.class));\n\t\t\t\torderedCallbacks.verify(callbackOne).handle(any(Event.class), any(Context.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configurationCustomizersAreConfiguredAndOrdered() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, ConfigurationCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getConnectRetries()).isEqualTo(5);\n\t\t\t\tassertThat(flyway.getConfiguration().getBaselineDescription()).isEqualTo(\"<< Custom baseline >>\");\n\t\t\t\tassertThat(flyway.getConfiguration().getBaselineVersion()).isEqualTo(MigrationVersion.fromVersion(\"1\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid callbackAndMigrationBeansAreAppliedToConfigurationBeforeCustomizersAreCalled() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, FlywayJavaMigrationsConfiguration.class,\n\t\t\t\t\tCallbackConfiguration.class)\n\t\t\t.withBean(FlywayConfigurationCustomizer.class, () -> (configuration) -> {\n\t\t\t\tassertThat(configuration.getCallbacks()).isNotEmpty();\n\t\t\t\tassertThat(configuration.getJavaMigrations()).isNotEmpty();\n\t\t\t})\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid batchIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.batch=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getModernConfig().getFlyway().getBatch()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid dryRunOutputIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.dryRunOutput=dryrun.sql\")\n\t\t\t.run(validateFlywayTeamsPropertyOnly(\"dryRunOutput\"));\n\t}\n\n\t@Test\n\tvoid errorOverridesIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.errorOverrides=D12345\")\n\t\t\t.run(validateFlywayTeamsPropertyOnly(\"errorOverrides\"));\n\t}\n\n\t@Test\n\tvoid oracleExtensionIsNotLoadedByDefault() {\n\t\tFluentConfiguration configuration = mock(FluentConfiguration.class);\n\t\tnew OracleFlywayConfigurationCustomizer(new FlywayProperties()).customize(configuration);\n\t\tthen(configuration).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid oracleSqlplusIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.oracle.sqlplus=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class)\n\t\t\t\t.getConfiguration()\n\t\t\t\t.getPluginRegister()\n\t\t\t\t.getExact(OracleConfigurationExtension.class)\n\t\t\t\t.getSqlplus()).isTrue());\n\n\t}\n\n\t@Test\n\tvoid oracleSqlplusWarnIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.oracle.sqlplus-warn=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class)\n\t\t\t\t.getConfiguration()\n\t\t\t\t.getPluginRegister()\n\t\t\t\t.getExact(OracleConfigurationExtension.class)\n\t\t\t\t.getSqlplusWarn()).isTrue());\n\t}\n\n\t@Test\n\tvoid oracleWallerLocationIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.oracle.wallet-location=/tmp/my.wallet\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class)\n\t\t\t\t.getConfiguration()\n\t\t\t\t.getPluginRegister()\n\t\t\t\t.getExact(OracleConfigurationExtension.class)\n\t\t\t\t.getWalletLocation()).isEqualTo(\"/tmp/my.wallet\"));\n\t}\n\n\t@Test\n\tvoid oracleKerberosCacheFileIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.oracle.kerberos-cache-file=/tmp/cache\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class)\n\t\t\t\t.getConfiguration()\n\t\t\t\t.getPluginRegister()\n\t\t\t\t.getExact(OracleConfigurationExtension.class)\n\t\t\t\t.getKerberosCacheFile()).isEqualTo(\"/tmp/cache\"));\n\t}\n\n\t@Test\n\tvoid streamIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.stream=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getModernConfig().getFlyway().getStream()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customFlywayClassLoader() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, ResourceLoaderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Flyway.class);\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getClassLoader()).isInstanceOf(CustomClassLoader.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid initSqlsWithDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.init-sqls=SELECT 1\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getInitSql()).isEqualTo(\"SELECT 1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid initSqlsWithFlywayUrl() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.flyway.url:jdbc:h2:mem:\" + UUID.randomUUID(),\n\t\t\t\t\t\"spring.flyway.init-sqls=SELECT 1\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getInitSql()).isEqualTo(\"SELECT 1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jdbcPropertiesAreCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.jdbc-properties.prop=value\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tResolvedEnvironment environment = flyway.getConfiguration()\n\t\t\t\t\t.getCachedResolvedEnvironments()\n\t\t\t\t\t.get(flyway.getConfiguration().getCurrentEnvironmentName());\n\t\t\t\tassertThat(environment).isNotNull();\n\t\t\t\tassertThat(environment.getJdbcProperties()).containsEntry(\"prop\", \"value\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid kerberosConfigFileIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.kerberos-config-file=/tmp/config\")\n\t\t\t.run(validateFlywayTeamsPropertyOnly(\"kerberosConfigFile\"));\n\t}\n\n\t@Test\n\tvoid outputQueryResultsIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.output-query-results=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getModernConfig().getFlyway().getOutputQueryResults()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid powershellExecutableIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.powershell-executable=my-pwsh\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getPowershellExecutable())\n\t\t\t\t.isEqualTo(\"my-pwsh\"));\n\t}\n\n\t@Test\n\tvoid postgresqlExtensionIsNotLoadedByDefault() {\n\t\tFluentConfiguration configuration = mock(FluentConfiguration.class);\n\t\tnew PostgresqlFlywayConfigurationCustomizer(new FlywayProperties()).customize(configuration);\n\t\tthen(configuration).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid postgresqlTransactionalLockIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.postgresql.transactional-lock=false\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class)\n\t\t\t\t.getConfiguration()\n\t\t\t\t.getPluginRegister()\n\t\t\t\t.getExact(PostgreSQLConfigurationExtension.class)\n\t\t\t\t.isTransactionalLock()).isFalse());\n\t}\n\n\t@Test\n\tvoid sqlServerExtensionIsNotLoadedByDefault() {\n\t\tFluentConfiguration configuration = mock(FluentConfiguration.class);\n\t\tnew SqlServerFlywayConfigurationCustomizer(new FlywayProperties()).customize(configuration);\n\t\tthen(configuration).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid sqlServerKerberosLoginFileIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.sqlserver.kerberos-login-file=/tmp/config\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class)\n\t\t\t\t.getConfiguration()\n\t\t\t\t.getPluginRegister()\n\t\t\t\t.getExact(SQLServerConfigurationExtension.class)\n\t\t\t\t.getKerberos()\n\t\t\t\t.getLogin()\n\t\t\t\t.getFile()).isEqualTo(\"/tmp/config\"));\n\t}\n\n\t@Test\n\tvoid skipExecutingMigrationsIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.skip-executing-migrations=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tFlyway flyway = context.getBean(Flyway.class);\n\t\t\t\tassertThat(flyway.getConfiguration().getModernConfig().getFlyway().getSkipExecutingMigrations())\n\t\t\t\t\t.isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid scriptPlaceholderPrefixIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.script-placeholder-prefix=SPP\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getScriptPlaceholderPrefix())\n\t\t\t\t.isEqualTo(\"SPP\"));\n\t}\n\n\t@Test\n\tvoid scriptPlaceholderSuffixIsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.script-placeholder-suffix=SPS\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getScriptPlaceholderSuffix())\n\t\t\t\t.isEqualTo(\"SPS\"));\n\t}\n\n\t@Test\n\tvoid containsResourceProviderCustomizer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.flyway.url:jdbc:hsqldb:mem:\" + UUID.randomUUID())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ResourceProviderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid loggers() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getLoggers())\n\t\t\t\t.containsExactly(\"slf4j\"));\n\t}\n\n\t@Test\n\tvoid overrideLoggers() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.loggers=apache-commons\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getLoggers())\n\t\t\t\t.containsExactly(\"apache-commons\"));\n\t}\n\n\t@Test\n\tvoid shouldRegisterResourceHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew FlywayAutoConfigurationRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"db/migration/\")).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"db/migration/V1__init.sql\")).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"db/migration/nested/V2__users.sql\"))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid detectEncodingCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.detect-encoding=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().isDetectEncoding())\n\t\t\t\t.isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid ignoreMigrationPatternsCorrectlyMapped() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.ignore-migration-patterns=*:missing\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getIgnoreMigrationPatterns())\n\t\t\t\t.containsExactly(ValidatePattern.fromPattern(\"*:missing\")));\n\t}\n\n\t@Test\n\tvoid ignoreMigrationPatternsUsesDefaultValuesWhenNotSet() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getIgnoreMigrationPatterns())\n\t\t\t\t.containsExactly(new FluentConfiguration().getIgnoreMigrationPatterns()));\n\t}\n\n\t@Test\n\tvoid ignoreMigrationPatternsWhenEmpty() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.flyway.ignore-migration-patterns=\")\n\t\t\t.run((context) -> assertThat(context.getBean(Flyway.class).getConfiguration().getIgnoreMigrationPatterns())\n\t\t\t\t.isEmpty());\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> validateFlywayTeamsPropertyOnly(String propertyName) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tThrowable failure = context.getStartupFailure();\n\t\t\tassertThat(failure).hasRootCauseInstanceOf(FlywayEditionUpgradeRequiredException.class);\n\t\t\tassertThat(failure).hasMessageContaining(String.format(\" %s \", propertyName));\n\t\t};\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static Location createLocation(String location) {\n\t\treturn new Location(location);\n\t}\n\n\tprivate static Map<String, ?> configureJpaProperties() {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"configured\", \"manually\");\n\t\tproperties.put(\"hibernate.transaction.jta.platform\", NoJtaPlatform.INSTANCE);\n\t\treturn properties;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FlywayDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource normalDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:hsqldb:mem:normal\").username(\"sa\").build();\n\t\t}\n\n\t\t@FlywayDataSource\n\t\t@Bean(defaultCandidate = false)\n\t\tDataSource flywayDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:hsqldb:mem:flywaytest\").username(\"sa\").build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FlywayMultipleDataSourcesConfiguration {\n\n\t\t@Bean\n\t\tDataSource firstDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:hsqldb:mem:first\").username(\"sa\").build();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource secondDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:hsqldb:mem:second\").username(\"sa\").build();\n\t\t}\n\n\t\t@FlywayDataSource\n\t\t@Bean(defaultCandidate = false)\n\t\tDataSource flywayDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:hsqldb:mem:flywaytest\").username(\"sa\").build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FlywayJavaMigrationsConfiguration {\n\n\t\t@Bean\n\t\tTestMigration migration1() {\n\t\t\treturn new TestMigration(\"2\", \"M1\");\n\t\t}\n\n\t\t@Bean\n\t\tTestMigration migration2() {\n\t\t\treturn new TestMigration(\"3\", \"M2\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceLoaderConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tResourceLoader customClassLoader() {\n\t\t\treturn new DefaultResourceLoader(new CustomClassLoader(getClass().getClassLoader()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFlywayMigrationInitializer {\n\n\t\t@Bean\n\t\tFlywayMigrationInitializer flywayMigrationInitializer(Flyway flyway) {\n\t\t\tFlywayMigrationInitializer initializer = new FlywayMigrationInitializer(flyway);\n\t\t\tinitializer.setOrder(Ordered.HIGHEST_PRECEDENCE);\n\t\t\treturn initializer;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFlyway {\n\n\t\t@Bean\n\t\tFlyway customFlyway() {\n\t\t\treturn Flyway.configure().load();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFlywayMigrationInitializerWithJpaConfiguration {\n\n\t\t@Bean\n\t\tFlywayMigrationInitializer customFlywayMigrationInitializer(Flyway flyway) {\n\t\t\treturn new FlywayMigrationInitializer(flyway);\n\t\t}\n\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource) {\n\t\t\tLocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();\n\t\t\tlocalContainerEntityManagerFactoryBean.setDataSource(dataSource);\n\t\t\tlocalContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());\n\t\t\tlocalContainerEntityManagerFactoryBean.setJpaPropertyMap(configureJpaProperties());\n\t\t\treturn localContainerEntityManagerFactoryBean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFlywayWithJpaConfiguration {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprotected CustomFlywayWithJpaConfiguration(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tFlyway customFlyway() {\n\t\t\treturn Flyway.configure().load();\n\t\t}\n\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {\n\t\t\tLocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();\n\t\t\tlocalContainerEntityManagerFactoryBean.setDataSource(this.dataSource);\n\t\t\tlocalContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());\n\t\t\tlocalContainerEntityManagerFactoryBean.setJpaPropertyMap(configureJpaProperties());\n\t\t\treturn localContainerEntityManagerFactoryBean;\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CustomFlywayWithJdbcConfiguration {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprotected CustomFlywayWithJdbcConfiguration(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tFlyway customFlyway() {\n\t\t\treturn Flyway.configure().load();\n\t\t}\n\n\t\t@Bean\n\t\tJdbcOperations jdbcOperations() {\n\t\t\treturn new JdbcTemplate(this.dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tNamedParameterJdbcOperations namedParameterJdbcOperations() {\n\t\t\treturn new NamedParameterJdbcTemplate(this.dataSource);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tprotected static class CustomFlywayMigrationInitializerWithJdbcConfiguration {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprotected CustomFlywayMigrationInitializerWithJdbcConfiguration(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tpublic FlywayMigrationInitializer customFlywayMigrationInitializer(Flyway flyway) {\n\t\t\treturn new FlywayMigrationInitializer(flyway);\n\t\t}\n\n\t\t@Bean\n\t\tpublic JdbcOperations jdbcOperations() {\n\t\t\treturn new JdbcTemplate(this.dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tpublic NamedParameterJdbcOperations namedParameterJdbcOperations() {\n\t\t\treturn new NamedParameterJdbcTemplate(this.dataSource);\n\t\t}\n\n\t}\n\n\t@Component\n\tstatic class MockFlywayMigrationStrategy implements FlywayMigrationStrategy {\n\n\t\tprivate boolean called;\n\n\t\t@Override\n\t\tpublic void migrate(Flyway flyway) {\n\t\t\tthis.called = true;\n\t\t}\n\n\t\tvoid assertCalled() {\n\t\t\tassertThat(this.called).isTrue();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CallbackConfiguration {\n\n\t\t@Bean\n\t\tCallback callbackOne() {\n\t\t\treturn mockCallback(\"b\");\n\t\t}\n\n\t\t@Bean\n\t\tCallback callbackTwo() {\n\t\t\treturn mockCallback(\"a\");\n\t\t}\n\n\t\tprivate Callback mockCallback(String name) {\n\t\t\tCallback callback = mock(Callback.class);\n\t\t\tgiven(callback.supports(any(Event.class), any(Context.class))).willReturn(true);\n\t\t\tgiven(callback.getCallbackName()).willReturn(name);\n\t\t\treturn callback;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigurationCustomizerConfiguration {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tFlywayConfigurationCustomizer customizerOne() {\n\t\t\treturn (configuration) -> configuration.connectRetries(5).baselineVersion(\"1\");\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tFlywayConfigurationCustomizer customizerTwo() {\n\t\t\treturn (configuration) -> configuration.connectRetries(10).baselineDescription(\"<< Custom baseline >>\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(DataSourceProperties.class)\n\tabstract static class AbstractUserH2DataSourceConfiguration {\n\n\t\t@Bean(destroyMethod = \"shutdown\")\n\t\tEmbeddedDatabase dataSource(DataSourceProperties properties) throws SQLException {\n\t\t\tEmbeddedDatabase database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.setName(getDatabaseName(properties))\n\t\t\t\t.build();\n\t\t\tinsertUser(database);\n\t\t\treturn database;\n\t\t}\n\n\t\tprotected abstract String getDatabaseName(DataSourceProperties properties);\n\n\t\tprivate void insertUser(EmbeddedDatabase database) throws SQLException {\n\t\t\ttry (Connection connection = database.getConnection()) {\n\t\t\t\tconnection.prepareStatement(\"CREATE USER test password 'secret'\").execute();\n\t\t\t\tconnection.prepareStatement(\"ALTER USER test ADMIN TRUE\").execute();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PropertiesBackedH2DataSourceConfiguration extends AbstractUserH2DataSourceConfiguration {\n\n\t\t@Override\n\t\tprotected String getDatabaseName(DataSourceProperties properties) {\n\t\t\tString result = properties.determineDatabaseName();\n\t\t\tassertThat(result).isNotNull();\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomBackedH2DataSourceConfiguration extends AbstractUserH2DataSourceConfiguration {\n\n\t\tprivate final String name = UUID.randomUUID().toString();\n\n\t\t@Override\n\t\tprotected String getDatabaseName(DataSourceProperties properties) {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic final class CustomClassLoader extends ClassLoader {\n\n\t\tprivate CustomClassLoader(ClassLoader parent) {\n\t\t\tsuper(parent);\n\t\t}\n\n\t}\n\n\tprivate static final class TestMigration implements JavaMigration {\n\n\t\tprivate final MigrationVersion version;\n\n\t\tprivate final String description;\n\n\t\tprivate TestMigration(String version, String description) {\n\t\t\tthis.version = MigrationVersion.fromVersion(version);\n\t\t\tthis.description = description;\n\t\t}\n\n\t\t@Override\n\t\tpublic MigrationVersion getVersion() {\n\t\t\treturn this.version;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\t@Override\n\t\tpublic Integer getChecksum() {\n\t\t\treturn 1;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canExecuteInTransaction() {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void migrate(org.flywaydb.core.api.migration.Context context) {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tJdbcConnectionDetails jdbcConnectionDetails() {\n\t\t\treturn new JdbcConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getJdbcUrl() {\n\t\t\t\t\treturn \"jdbc:postgresql://database.example.com:12345/database-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"secret-1\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FlywayConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tFlywayConnectionDetails flywayConnectionDetails() {\n\t\t\treturn new FlywayConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getJdbcUrl() {\n\t\t\t\t\treturn \"jdbc:postgresql://database.example.com:12345/database-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"secret-1\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"META-INF/persistence.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<persistence version=\"2.0\" xmlns=\"http://java.sun.com/xml/ns/persistence\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/persistence https://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">\n\t\t\t\t\t\t<persistence-unit name=\"manually-configured\">\n\t\t\t\t\t\t\t<class>org.springframework.boot.flyway.autoconfigure.FlywayAutoConfigurationTests$City</class>\n\t\t\t\t\t\t\t<exclude-unlisted-classes>true</exclude-unlisted-classes>\n\t\t\t\t\t\t</persistence-unit>\n\t\t\t\t\t</persistence>\n\t\t\t\t\t\"\"\")\n\t@interface WithMetaInfPersistenceXmlResource {\n\n\t}\n\n\t@Entity\n\tpublic static class City implements Serializable {\n\n\t\tprivate static final long serialVersionUID = 1L;\n\n\t\t@Id\n\t\t@GeneratedValue\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate Long id;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String name;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String state;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String country;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String map;\n\n\t\tprotected City() {\n\t\t}\n\n\t\tCity(String name, String state, String country, String map) {\n\t\t\tthis.name = name;\n\t\t\tthis.state = state;\n\t\t\tthis.country = country;\n\t\t\tthis.map = map;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getState() {\n\t\t\treturn this.state;\n\t\t}\n\n\t\tpublic String getCountry() {\n\t\t\treturn this.country;\n\t\t}\n\n\t\tpublic String getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/FlywayAutoConfigureDataSourceInitializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Tests for Flyway using\n * {@link AutoConfigureDataSourceInitialization @AutoConfigureDataSourceInitialization}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureDataSourceInitialization\nclass FlywayAutoConfigureDataSourceInitializationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid flywayIsIncludedInAutoConfigureDataSourceInitialization() {\n\t\tassertThat(this.context).has(importedAutoConfiguration(FlywayAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/FlywayEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport org.flywaydb.core.Flyway;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.flyway.actuate.endpoint.FlywayEndpoint;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link FlywayEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass FlywayEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FlywayEndpointAutoConfiguration.class))\n\t\t.withBean(Flyway.class, () -> mock(Flyway.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=flyway\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(FlywayEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.flyway.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(FlywayEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(FlywayEndpoint.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/FlywayPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.beans.PropertyDescriptor;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.flywaydb.core.api.Location;\nimport org.flywaydb.core.api.MigrationVersion;\nimport org.flywaydb.core.api.configuration.ClassicConfiguration;\nimport org.flywaydb.core.api.configuration.Configuration;\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\nimport org.flywaydb.core.api.pattern.ValidatePattern;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeanWrapper;\nimport org.springframework.beans.PropertyAccessorFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FlywayProperties}.\n *\n * @author Stephane Nicoll\n * @author Chris Bono\n */\nclass FlywayPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tFlywayProperties properties = new FlywayProperties();\n\t\tConfiguration configuration = new FluentConfiguration();\n\t\tassertThat(properties.isFailOnMissingLocations()).isEqualTo(configuration.isFailOnMissingLocations());\n\t\tassertThat(properties.getLocations().stream().map(this::toLocation).toArray(Location[]::new))\n\t\t\t.isEqualTo(configuration.getLocations());\n\t\tassertThat(properties.getCallbackLocations().stream().map(this::toLocation).toArray(Location[]::new))\n\t\t\t.isEqualTo(configuration.getCallbackLocations());\n\t\tassertThat(properties.getEncoding()).isEqualTo(configuration.getEncoding());\n\t\tassertThat(properties.getConnectRetries()).isEqualTo(configuration.getConnectRetries());\n\t\tassertThat(properties.getConnectRetriesInterval()).extracting(Duration::getSeconds)\n\t\t\t.extracting(Long::intValue)\n\t\t\t.isEqualTo(configuration.getConnectRetriesInterval());\n\t\tassertThat(properties.getLockRetryCount()).isEqualTo(configuration.getLockRetryCount());\n\t\tassertThat(properties.getDefaultSchema()).isEqualTo(configuration.getDefaultSchema());\n\t\tassertThat(properties.getSchemas()).isEqualTo(Arrays.asList(configuration.getSchemas()));\n\t\tassertThat(properties.isCreateSchemas()).isEqualTo(configuration.isCreateSchemas());\n\t\tassertThat(properties.getTable()).isEqualTo(configuration.getTable());\n\t\tassertThat(properties.getBaselineDescription()).isEqualTo(configuration.getBaselineDescription());\n\t\tassertThat(MigrationVersion.fromVersion(properties.getBaselineVersion()))\n\t\t\t.isEqualTo(configuration.getBaselineVersion());\n\t\tassertThat(properties.getInstalledBy()).isEqualTo(configuration.getInstalledBy());\n\t\tassertThat(properties.getPlaceholders()).isEqualTo(configuration.getPlaceholders());\n\t\tassertThat(properties.getPlaceholderPrefix()).isEqualToIgnoringWhitespace(configuration.getPlaceholderPrefix());\n\t\tassertThat(properties.getPlaceholderSuffix()).isEqualTo(configuration.getPlaceholderSuffix());\n\t\tassertThat(properties.isPlaceholderReplacement()).isEqualTo(configuration.isPlaceholderReplacement());\n\t\tassertThat(properties.getPowershellExecutable()).isEqualTo(configuration.getPowershellExecutable());\n\t\tassertThat(properties.getSqlMigrationPrefix()).isEqualTo(configuration.getSqlMigrationPrefix());\n\t\tassertThat(properties.getSqlMigrationSuffixes()).containsExactly(configuration.getSqlMigrationSuffixes());\n\t\tassertThat(properties.getSqlMigrationSeparator()).isEqualTo(configuration.getSqlMigrationSeparator());\n\t\tassertThat(properties.getRepeatableSqlMigrationPrefix())\n\t\t\t.isEqualTo(configuration.getRepeatableSqlMigrationPrefix());\n\t\tassertThat(MigrationVersion.fromVersion(properties.getTarget())).isEqualTo(configuration.getTarget());\n\t\tassertThat(configuration.getInitSql()).isNull();\n\t\tassertThat(properties.getInitSqls()).isEmpty();\n\t\tassertThat(properties.isBaselineOnMigrate()).isEqualTo(configuration.isBaselineOnMigrate());\n\t\tassertThat(properties.isCleanDisabled()).isEqualTo(configuration.isCleanDisabled());\n\t\tassertThat(properties.isGroup()).isEqualTo(configuration.isGroup());\n\t\tassertThat(properties.isMixed()).isEqualTo(configuration.isMixed());\n\t\tassertThat(properties.isOutOfOrder()).isEqualTo(configuration.isOutOfOrder());\n\t\tassertThat(properties.isSkipDefaultCallbacks()).isEqualTo(configuration.isSkipDefaultCallbacks());\n\t\tassertThat(properties.isSkipDefaultResolvers()).isEqualTo(configuration.isSkipDefaultResolvers());\n\t\tassertThat(properties.isValidateMigrationNaming()).isEqualTo(configuration.isValidateMigrationNaming());\n\t\tassertThat(properties.isValidateOnMigrate()).isEqualTo(configuration.isValidateOnMigrate());\n\t\tassertThat(properties.getDetectEncoding()).isNull();\n\t\tassertThat(properties.getPlaceholderSeparator()).isEqualTo(configuration.getPlaceholderSeparator());\n\t\tassertThat(properties.getScriptPlaceholderPrefix()).isEqualTo(configuration.getScriptPlaceholderPrefix());\n\t\tassertThat(properties.getScriptPlaceholderSuffix()).isEqualTo(configuration.getScriptPlaceholderSuffix());\n\t\tassertThat(properties.isExecuteInTransaction()).isEqualTo(configuration.isExecuteInTransaction());\n\t\tassertThat(properties.getCommunityDbSupportEnabled()).isNull();\n\t\tassertThat(properties.getIgnoreMigrationPatterns().stream().map(ValidatePattern::fromPattern))\n\t\t\t.containsExactly(configuration.getIgnoreMigrationPatterns());\n\t}\n\n\t@Test\n\tvoid loggersIsOverriddenToSlf4j() {\n\t\tassertThat(new FluentConfiguration().getLoggers()).containsExactly(\"auto\");\n\t\tassertThat(new FlywayProperties().getLoggers()).containsExactly(\"slf4j\");\n\t}\n\n\t@Test\n\tvoid expectedPropertiesAreManaged() {\n\t\tMap<String, PropertyDescriptor> properties = indexProperties(\n\t\t\t\tPropertyAccessorFactory.forBeanPropertyAccess(new FlywayProperties()));\n\t\tMap<String, PropertyDescriptor> configuration = indexProperties(\n\t\t\t\tPropertyAccessorFactory.forBeanPropertyAccess(new ClassicConfiguration()));\n\t\t// Properties specific settings\n\t\tignoreProperties(properties, \"url\", \"driverClassName\", \"user\", \"password\", \"enabled\");\n\t\t// Properties that are managed by specific extensions\n\t\tignoreProperties(properties, \"oracle\", \"postgresql\", \"sqlserver\");\n\t\t// Properties that are only used on the command line\n\t\tignoreProperties(configuration, \"jarDirs\");\n\t\t// https://github.com/flyway/flyway/issues/3732\n\t\tignoreProperties(configuration, \"environment\");\n\t\t// High level object we can't set with properties\n\t\tignoreProperties(configuration, \"callbacks\", \"classLoader\", \"dataSource\", \"javaMigrations\",\n\t\t\t\t\"javaMigrationClassProvider\", \"pluginRegister\", \"resourceProvider\", \"resolvers\");\n\t\t// Properties we don't want to expose\n\t\tignoreProperties(configuration, \"resolversAsClassNames\", \"callbacksAsClassNames\", \"driver\", \"modernConfig\",\n\t\t\t\t\"currentResolvedEnvironment\", \"reportFilename\", \"reportEnabled\", \"workingDirectory\",\n\t\t\t\t\"cachedDataSources\", \"cachedResolvedEnvironments\", \"currentEnvironmentName\", \"allEnvironments\",\n\t\t\t\t\"environmentProvisionMode\", \"provisionMode\");\n\t\t// Handled by the conversion service\n\t\tignoreProperties(configuration, \"baselineVersionAsString\", \"encodingAsString\", \"locationsAsStrings\",\n\t\t\t\t\"callbackLocationsAsStrings\", \"targetAsString\");\n\t\t// Handled as initSql array\n\t\tignoreProperties(configuration, \"initSql\");\n\t\tignoreProperties(properties, \"initSqls\");\n\t\t// Handled as dryRunOutput\n\t\tignoreProperties(configuration, \"dryRunOutputAsFile\", \"dryRunOutputAsFileName\");\n\t\t// Handled as createSchemas\n\t\tignoreProperties(configuration, \"shouldCreateSchemas\");\n\t\t// Getters for the DataSource settings rather than actual properties\n\t\tignoreProperties(configuration, \"databaseType\", \"password\", \"url\", \"user\");\n\t\t// Properties not exposed by Flyway\n\t\tignoreProperties(configuration, \"failOnMissingTarget\");\n\t\t// Properties managed by a proprietary extension\n\t\tignoreProperties(configuration, \"cherryPick\");\n\t\taliasProperty(configuration, \"communityDBSupportEnabled\", \"communityDbSupportEnabled\");\n\t\tList<String> configurationKeys = new ArrayList<>(configuration.keySet());\n\t\tCollections.sort(configurationKeys);\n\t\tList<String> propertiesKeys = new ArrayList<>(properties.keySet());\n\t\tCollections.sort(propertiesKeys);\n\t\tassertThat(configurationKeys).containsExactlyElementsOf(propertiesKeys);\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate Location toLocation(String location) {\n\t\treturn new Location(location);\n\t}\n\n\tprivate void ignoreProperties(Map<String, ?> index, String... propertyNames) {\n\t\tfor (String propertyName : propertyNames) {\n\t\t\tassertThat(index.remove(propertyName)).describedAs(\"Property to ignore should be present \" + propertyName)\n\t\t\t\t.isNotNull();\n\t\t}\n\t}\n\n\tprivate void aliasProperty(Map<String, PropertyDescriptor> index, String originalName, String alias) {\n\t\tPropertyDescriptor descriptor = index.remove(originalName);\n\t\tassertThat(descriptor).describedAs(\"Property to alias should be present \" + originalName).isNotNull();\n\t\tindex.put(alias, descriptor);\n\t}\n\n\tprivate Map<String, PropertyDescriptor> indexProperties(BeanWrapper beanWrapper) {\n\t\tMap<String, PropertyDescriptor> descriptor = new HashMap<>();\n\t\tfor (PropertyDescriptor propertyDescriptor : beanWrapper.getPropertyDescriptors()) {\n\t\t\tdescriptor.put(propertyDescriptor.getName(), propertyDescriptor);\n\t\t}\n\t\tignoreProperties(descriptor, \"class\");\n\t\treturn descriptor;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/NativeImageResourceProviderCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.flywaydb.core.api.ResourceProvider;\nimport org.flywaydb.core.api.configuration.FluentConfiguration;\nimport org.flywaydb.core.api.resource.LoadableResource;\nimport org.flywaydb.core.internal.resource.NoopResourceProvider;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.testsupport.classpath.resources.WithResources;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NativeImageResourceProviderCustomizer}.\n *\n * @author Moritz Halbritter\n */\nclass NativeImageResourceProviderCustomizerTests {\n\n\tprivate final NativeImageResourceProviderCustomizer customizer = new NativeImageResourceProviderCustomizer();\n\n\t@Test\n\tvoid shouldInstallNativeImageResourceProvider() {\n\t\tFluentConfiguration configuration = new FluentConfiguration();\n\t\tassertThat(configuration.getResourceProvider()).isNull();\n\t\tthis.customizer.customize(configuration);\n\t\tassertThat(configuration.getResourceProvider()).isInstanceOf(NativeImageResourceProvider.class);\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/migration/V1__init.sql\")\n\tvoid nativeImageResourceProviderShouldFindMigrations() {\n\t\tFluentConfiguration configuration = new FluentConfiguration();\n\t\tthis.customizer.customize(configuration);\n\t\tResourceProvider resourceProvider = configuration.getResourceProvider();\n\t\tCollection<LoadableResource> migrations = resourceProvider.getResources(\"V\", new String[] { \".sql\" });\n\t\tLoadableResource migration = resourceProvider.getResource(\"V1__init.sql\");\n\t\tassertThat(migrations).containsExactly(migration);\n\t}\n\n\t@Test\n\t@WithResources({ @WithResource(name = \"db/migration/V1__init.sql\"),\n\t\t\t@WithResource(name = \"db/migration/nested/V2__users.sql\") })\n\tvoid nativeImageResourceProviderShouldFindNestedMigrations() {\n\t\tFluentConfiguration configuration = new FluentConfiguration();\n\t\tthis.customizer.customize(configuration);\n\t\tResourceProvider resourceProvider = configuration.getResourceProvider();\n\t\tCollection<LoadableResource> migrations = resourceProvider.getResources(\"V\", new String[] { \".sql\" });\n\t\tLoadableResource v1 = resourceProvider.getResource(\"V1__init.sql\");\n\t\tLoadableResource v2 = resourceProvider.getResource(\"nested/V2__users.sql\");\n\t\tassertThat(migrations).containsExactlyInAnyOrder(v1, v2);\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomResourceProvider() {\n\t\tFluentConfiguration configuration = new FluentConfiguration();\n\t\tconfiguration.resourceProvider(NoopResourceProvider.INSTANCE);\n\t\tthis.customizer.customize(configuration);\n\t\tassertThat(configuration.getResourceProvider()).isEqualTo(NoopResourceProvider.INSTANCE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-flyway/src/test/java/org/springframework/boot/flyway/autoconfigure/ResourceProviderCustomizerBeanRegistrationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.flyway.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ResourceProviderCustomizerBeanRegistrationAotProcessor}.\n *\n * @author Moritz Halbritter\n */\nclass ResourceProviderCustomizerBeanRegistrationAotProcessorTests {\n\n\tprivate final DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();\n\n\tprivate final ResourceProviderCustomizerBeanRegistrationAotProcessor processor = new ResourceProviderCustomizerBeanRegistrationAotProcessor();\n\n\t@Test\n\tvoid beanRegistrationAotProcessorIsRegistered() {\n\t\tassertThat(AotServices.factories().load(BeanRegistrationAotProcessor.class))\n\t\t\t.anyMatch(ResourceProviderCustomizerBeanRegistrationAotProcessor.class::isInstance);\n\t}\n\n\t@Test\n\tvoid shouldIgnoreNonResourceProviderCustomizerBeans() {\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);\n\t\tthis.beanFactory.registerBeanDefinition(\"test\", beanDefinition);\n\t\tBeanRegistrationAotContribution contribution = this.processor\n\t\t\t.processAheadOfTime(RegisteredBean.of(this.beanFactory, \"test\"));\n\t\tassertThat(contribution).isNull();\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid shouldReplaceResourceProviderCustomizer() {\n\t\tcompile(createContext(ResourceProviderCustomizerConfiguration.class), (freshContext) -> {\n\t\t\tfreshContext.refresh();\n\t\t\tResourceProviderCustomizer bean = freshContext.getBean(ResourceProviderCustomizer.class);\n\t\t\tassertThat(bean).isInstanceOf(NativeImageResourceProviderCustomizer.class);\n\t\t});\n\t}\n\n\tprivate GenericApplicationContext createContext(Class<?>... types) {\n\t\tGenericApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tArrays.stream(types).forEach((type) -> context.registerBean(type));\n\t\treturn context;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void compile(GenericApplicationContext context, Consumer<GenericApplicationContext> freshContext) {\n\t\tTestGenerationContext generationContext = new TestGenerationContext(TestTarget.class);\n\t\tClassName className = new ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\tgenerationContext.writeGeneratedContent();\n\t\tTestCompiler.forSystem()\n\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t.with(generationContext)\n\t\t\t.compile((compiled) -> {\n\t\t\t\tGenericApplicationContext freshApplicationContext = new GenericApplicationContext();\n\t\t\t\tApplicationContextInitializer<GenericApplicationContext> initializer = compiled\n\t\t\t\t\t.getInstance(ApplicationContextInitializer.class, className.toString());\n\t\t\t\tinitializer.initialize(freshApplicationContext);\n\t\t\t\tfreshContext.accept(freshApplicationContext);\n\t\t\t});\n\t}\n\n\tstatic class TestTarget {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceProviderCustomizerConfiguration {\n\n\t\t@Bean\n\t\tResourceProviderCustomizer resourceProviderCustomizer() {\n\t\t\treturn new ResourceProviderCustomizer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Freemarker\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.freemarker:freemarker\")\n\tapi(\"org.springframework:spring-context-support\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-webflux\"))\n\toptional(project(\":module:spring-boot-webflux-test\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-servlet\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/AbstractFreeMarkerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;\n\n/**\n * Base class for shared FreeMarker configuration.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n */\nabstract class AbstractFreeMarkerConfiguration {\n\n\tprivate final FreeMarkerProperties properties;\n\n\tprivate final List<FreeMarkerVariablesCustomizer> variablesCustomizers;\n\n\tprotected AbstractFreeMarkerConfiguration(FreeMarkerProperties properties,\n\t\t\tObjectProvider<FreeMarkerVariablesCustomizer> variablesCustomizers) {\n\t\tthis.properties = properties;\n\t\tthis.variablesCustomizers = variablesCustomizers.orderedStream().toList();\n\t}\n\n\tprotected final FreeMarkerProperties getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tprotected void applyProperties(FreeMarkerConfigurationFactory factory) {\n\t\tfactory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());\n\t\tfactory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());\n\t\tString charsetName = this.properties.getCharsetName();\n\t\tif (charsetName != null) {\n\t\t\tfactory.setDefaultEncoding(charsetName);\n\t\t}\n\t\tfactory.setFreemarkerSettings(createFreeMarkerSettings());\n\t\tfactory.setFreemarkerVariables(createFreeMarkerVariables());\n\t}\n\n\tprivate Properties createFreeMarkerSettings() {\n\t\tProperties settings = new Properties();\n\t\tsettings.put(\"recognize_standard_file_extensions\", \"true\");\n\t\tsettings.putAll(this.properties.getSettings());\n\t\treturn settings;\n\t}\n\n\tprivate Map<String, Object> createFreeMarkerVariables() {\n\t\tMap<String, Object> variables = new HashMap<>();\n\t\tfor (FreeMarkerVariablesCustomizer customizer : this.variablesCustomizers) {\n\t\t\tcustomizer.customizeFreeMarkerVariables(variables);\n\t\t}\n\t\treturn variables;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.template.TemplateLocation;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for FreeMarker.\n *\n * @author Andy Wilkinson\n * @author Dave Syer\n * @author Kazuki Shimizu\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class })\n@EnableConfigurationProperties(FreeMarkerProperties.class)\n@Import({ FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class,\n\t\tFreeMarkerNonWebConfiguration.class })\npublic final class FreeMarkerAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(FreeMarkerAutoConfiguration.class);\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final FreeMarkerProperties properties;\n\n\tFreeMarkerAutoConfiguration(ApplicationContext applicationContext, FreeMarkerProperties properties) {\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.properties = properties;\n\t\tcheckTemplateLocationExists();\n\t}\n\n\tprivate void checkTemplateLocationExists() {\n\t\tif (logger.isWarnEnabled() && this.properties.isCheckTemplateLocation()) {\n\t\t\tList<TemplateLocation> locations = getLocations();\n\t\t\tif (locations.stream().noneMatch(this::locationExists)) {\n\t\t\t\tString suffix = (locations.size() == 1) ? \"\" : \"s\";\n\t\t\t\tlogger.warn(\"Cannot find template location\" + suffix + \": \" + locations\n\t\t\t\t\t\t+ \" (please add some templates, \" + \"check your FreeMarker configuration, or set \"\n\t\t\t\t\t\t+ \"spring.freemarker.check-template-location=false)\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate List<TemplateLocation> getLocations() {\n\t\tList<TemplateLocation> locations = new ArrayList<>();\n\t\tfor (String templateLoaderPath : this.properties.getTemplateLoaderPath()) {\n\t\t\tTemplateLocation location = new TemplateLocation(templateLoaderPath);\n\t\t\tlocations.add(location);\n\t\t}\n\t\treturn locations;\n\t}\n\n\tprivate boolean locationExists(TemplateLocation location) {\n\t\treturn location.exists(this.applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerNonWebConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean;\n\n/**\n * Configuration for FreeMarker when used in a non-web context.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnNotWebApplication\nclass FreeMarkerNonWebConfiguration extends AbstractFreeMarkerConfiguration {\n\n\tFreeMarkerNonWebConfiguration(FreeMarkerProperties properties,\n\t\t\tObjectProvider<FreeMarkerVariablesCustomizer> variablesCustomizers) {\n\t\tsuper(properties, variablesCustomizers);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tFreeMarkerConfigurationFactoryBean freeMarkerConfiguration() {\n\t\tFreeMarkerConfigurationFactoryBean freeMarkerFactoryBean = new FreeMarkerConfigurationFactoryBean();\n\t\tapplyProperties(freeMarkerFactoryBean);\n\t\treturn freeMarkerFactoryBean;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\nimport org.springframework.util.MimeType;\nimport org.springframework.web.servlet.view.AbstractTemplateViewResolver;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring FreeMarker.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.freemarker\")\npublic class FreeMarkerProperties {\n\n\tpublic static final String DEFAULT_TEMPLATE_LOADER_PATH = \"classpath:/templates/\";\n\n\tpublic static final String DEFAULT_PREFIX = \"\";\n\n\tpublic static final String DEFAULT_SUFFIX = \".ftlh\";\n\n\tprivate static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf(\"text/html\");\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\t/**\n\t * Whether to enable template caching.\n\t */\n\tprivate boolean cache;\n\n\t/**\n\t * Content-Type value.\n\t */\n\tprivate MimeType contentType = DEFAULT_CONTENT_TYPE;\n\n\t/**\n\t * Template encoding.\n\t */\n\tprivate Charset charset = DEFAULT_CHARSET;\n\n\t/**\n\t * View names that can be resolved.\n\t */\n\tprivate String @Nullable [] viewNames;\n\n\t/**\n\t * Whether to check that the templates location exists.\n\t */\n\tprivate boolean checkTemplateLocation = true;\n\n\t/**\n\t * Prefix that gets prepended to view names when building a URL.\n\t */\n\tprivate String prefix = DEFAULT_PREFIX;\n\n\t/**\n\t * Suffix that gets appended to view names when building a URL.\n\t */\n\tprivate String suffix = DEFAULT_SUFFIX;\n\n\t/**\n\t * Name of the RequestContext attribute for all views.\n\t */\n\tprivate @Nullable String requestContextAttribute;\n\n\t/**\n\t * Whether all request attributes should be added to the model prior to merging with\n\t * the template.\n\t */\n\tprivate boolean exposeRequestAttributes;\n\n\t/**\n\t * Whether all HttpSession attributes should be added to the model prior to merging\n\t * with the template.\n\t */\n\tprivate boolean exposeSessionAttributes;\n\n\t/**\n\t * Whether HttpServletRequest attributes are allowed to override (hide) controller\n\t * generated model attributes of the same name.\n\t */\n\tprivate boolean allowRequestOverride;\n\n\t/**\n\t * Whether to expose a RequestContext for use by Spring's macro library, under the\n\t * name \"springMacroRequestContext\".\n\t */\n\tprivate boolean exposeSpringMacroHelpers = true;\n\n\t/**\n\t * Whether HttpSession attributes are allowed to override (hide) controller generated\n\t * model attributes of the same name.\n\t */\n\tprivate boolean allowSessionOverride;\n\n\t/**\n\t * Well-known FreeMarker keys which are passed to FreeMarker's Configuration.\n\t */\n\tprivate Map<String, String> settings = new HashMap<>();\n\n\t/**\n\t * List of template paths.\n\t */\n\tprivate String[] templateLoaderPath = new String[] { DEFAULT_TEMPLATE_LOADER_PATH };\n\n\t/**\n\t * Whether to prefer file system access for template loading to enable hot detection\n\t * of template changes. When a template path is detected as a directory, templates are\n\t * loaded from the directory only and other matching classpath locations will not be\n\t * considered.\n\t */\n\tprivate boolean preferFileSystemAccess;\n\n\tpublic void setCheckTemplateLocation(boolean checkTemplateLocation) {\n\t\tthis.checkTemplateLocation = checkTemplateLocation;\n\t}\n\n\tpublic boolean isCheckTemplateLocation() {\n\t\treturn this.checkTemplateLocation;\n\t}\n\n\tpublic String @Nullable [] getViewNames() {\n\t\treturn this.viewNames;\n\t}\n\n\tpublic void setViewNames(String @Nullable [] viewNames) {\n\t\tthis.viewNames = viewNames;\n\t}\n\n\tpublic boolean isCache() {\n\t\treturn this.cache;\n\t}\n\n\tpublic void setCache(boolean cache) {\n\t\tthis.cache = cache;\n\t}\n\n\tpublic MimeType getContentType() {\n\t\tif (this.contentType.getCharset() == null) {\n\t\t\tMap<String, String> parameters = new LinkedHashMap<>();\n\t\t\tparameters.put(\"charset\", this.charset.name());\n\t\t\tparameters.putAll(this.contentType.getParameters());\n\t\t\treturn new MimeType(this.contentType, parameters);\n\t\t}\n\t\treturn this.contentType;\n\t}\n\n\tpublic void setContentType(MimeType contentType) {\n\t\tthis.contentType = contentType;\n\t}\n\n\tpublic Charset getCharset() {\n\t\treturn this.charset;\n\t}\n\n\tpublic @Nullable String getCharsetName() {\n\t\treturn (this.charset != null) ? this.charset.name() : null;\n\t}\n\n\tpublic void setCharset(Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\tpublic Map<String, String> getSettings() {\n\t\treturn this.settings;\n\t}\n\n\tpublic void setSettings(Map<String, String> settings) {\n\t\tthis.settings = settings;\n\t}\n\n\tpublic String[] getTemplateLoaderPath() {\n\t\treturn this.templateLoaderPath;\n\t}\n\n\tpublic void setTemplateLoaderPath(String... templateLoaderPaths) {\n\t\tthis.templateLoaderPath = templateLoaderPaths;\n\t}\n\n\tpublic boolean isPreferFileSystemAccess() {\n\t\treturn this.preferFileSystemAccess;\n\t}\n\n\tpublic void setPreferFileSystemAccess(boolean preferFileSystemAccess) {\n\t\tthis.preferFileSystemAccess = preferFileSystemAccess;\n\t}\n\n\tpublic String getPrefix() {\n\t\treturn this.prefix;\n\t}\n\n\tpublic void setPrefix(String prefix) {\n\t\tthis.prefix = prefix;\n\t}\n\n\tpublic String getSuffix() {\n\t\treturn this.suffix;\n\t}\n\n\tpublic void setSuffix(String suffix) {\n\t\tthis.suffix = suffix;\n\t}\n\n\tpublic @Nullable String getRequestContextAttribute() {\n\t\treturn this.requestContextAttribute;\n\t}\n\n\tpublic void setRequestContextAttribute(@Nullable String requestContextAttribute) {\n\t\tthis.requestContextAttribute = requestContextAttribute;\n\t}\n\n\tpublic boolean isExposeRequestAttributes() {\n\t\treturn this.exposeRequestAttributes;\n\t}\n\n\tpublic void setExposeRequestAttributes(boolean exposeRequestAttributes) {\n\t\tthis.exposeRequestAttributes = exposeRequestAttributes;\n\t}\n\n\tpublic boolean isExposeSessionAttributes() {\n\t\treturn this.exposeSessionAttributes;\n\t}\n\n\tpublic void setExposeSessionAttributes(boolean exposeSessionAttributes) {\n\t\tthis.exposeSessionAttributes = exposeSessionAttributes;\n\t}\n\n\tpublic boolean isAllowRequestOverride() {\n\t\treturn this.allowRequestOverride;\n\t}\n\n\tpublic void setAllowRequestOverride(boolean allowRequestOverride) {\n\t\tthis.allowRequestOverride = allowRequestOverride;\n\t}\n\n\tpublic boolean isAllowSessionOverride() {\n\t\treturn this.allowSessionOverride;\n\t}\n\n\tpublic void setAllowSessionOverride(boolean allowSessionOverride) {\n\t\tthis.allowSessionOverride = allowSessionOverride;\n\t}\n\n\tpublic boolean isExposeSpringMacroHelpers() {\n\t\treturn this.exposeSpringMacroHelpers;\n\t}\n\n\tpublic void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {\n\t\tthis.exposeSpringMacroHelpers = exposeSpringMacroHelpers;\n\t}\n\n\t/**\n\t * Apply the given properties to a {@link AbstractTemplateViewResolver}. Use Object in\n\t * signature to avoid runtime dependency on MVC, which means that the template engine\n\t * can be used in a non-web application.\n\t * @param viewResolver the resolver to apply the properties to.\n\t */\n\tpublic void applyToMvcViewResolver(Object viewResolver) {\n\t\tAssert.isInstanceOf(AbstractTemplateViewResolver.class, viewResolver,\n\t\t\t\t() -> \"ViewResolver is not an instance of AbstractTemplateViewResolver :\" + viewResolver);\n\t\tAbstractTemplateViewResolver resolver = (AbstractTemplateViewResolver) viewResolver;\n\t\tresolver.setPrefix(getPrefix());\n\t\tresolver.setSuffix(getSuffix());\n\t\tresolver.setCache(isCache());\n\t\tif (getContentType() != null) {\n\t\t\tresolver.setContentType(getContentType().toString());\n\t\t}\n\t\tresolver.setViewNames(getViewNames());\n\t\tresolver.setExposeRequestAttributes(isExposeRequestAttributes());\n\t\tresolver.setAllowRequestOverride(isAllowRequestOverride());\n\t\tresolver.setAllowSessionOverride(isAllowSessionOverride());\n\t\tresolver.setExposeSessionAttributes(isExposeSessionAttributes());\n\t\tresolver.setExposeSpringMacroHelpers(isExposeSpringMacroHelpers());\n\t\tresolver.setRequestContextAttribute(getRequestContextAttribute());\n\t\t// The resolver usually acts as a fallback resolver (e.g. like a\n\t\t// InternalResourceViewResolver) so it needs to have low precedence\n\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerReactiveWebConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfig;\nimport org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer;\nimport org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver;\n\n/**\n * Configuration for FreeMarker when used in a reactive web context.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass(FreeMarkerConfigurer.class)\n@AutoConfigureAfter(name = \"org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration\")\nclass FreeMarkerReactiveWebConfiguration extends AbstractFreeMarkerConfiguration {\n\n\tFreeMarkerReactiveWebConfiguration(FreeMarkerProperties properties,\n\t\t\tObjectProvider<FreeMarkerVariablesCustomizer> variablesCustomizers) {\n\t\tsuper(properties, variablesCustomizers);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(FreeMarkerConfig.class)\n\tFreeMarkerConfigurer freeMarkerConfigurer() {\n\t\tFreeMarkerConfigurer configurer = new FreeMarkerConfigurer();\n\t\tapplyProperties(configurer);\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\tfreemarker.template.Configuration freeMarkerConfiguration(FreeMarkerConfig configurer) {\n\t\treturn configurer.getConfiguration();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"freeMarkerViewResolver\")\n\tFreeMarkerViewResolver freeMarkerViewResolver() {\n\t\tFreeMarkerViewResolver resolver = new FreeMarkerViewResolver();\n\t\tresolver.setPrefix(getProperties().getPrefix());\n\t\tresolver.setSuffix(getProperties().getSuffix());\n\t\tresolver.setRequestContextAttribute(getProperties().getRequestContextAttribute());\n\t\tresolver.setViewNames(getProperties().getViewNames());\n\t\treturn resolver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerServletWebConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Servlet;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;\n\n/**\n * Configuration for FreeMarker when used in a servlet web context.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class })\n@AutoConfigureAfter(name = \"org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration\")\nclass FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration {\n\n\tprotected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties,\n\t\t\tObjectProvider<FreeMarkerVariablesCustomizer> variablesCustomizers) {\n\t\tsuper(properties, variablesCustomizers);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(FreeMarkerConfig.class)\n\tFreeMarkerConfigurer freeMarkerConfigurer() {\n\t\tFreeMarkerConfigurer configurer = new FreeMarkerConfigurer();\n\t\tapplyProperties(configurer);\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\tfreemarker.template.Configuration freeMarkerConfiguration(FreeMarkerConfig configurer) {\n\t\treturn configurer.getConfiguration();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"freeMarkerViewResolver\")\n\tFreeMarkerViewResolver freeMarkerViewResolver() {\n\t\tFreeMarkerViewResolver resolver = new FreeMarkerViewResolver();\n\t\tgetProperties().applyToMvcViewResolver(resolver);\n\t\treturn resolver;\n\t}\n\n\t@Bean\n\t@ConditionalOnEnabledResourceChain\n\t@ConditionalOnMissingFilterBean\n\tFilterRegistrationBean<ResourceUrlEncodingFilter> resourceUrlEncodingFilter() {\n\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> registration = new FilterRegistrationBean<>(\n\t\t\t\tnew ResourceUrlEncodingFilter());\n\t\tregistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);\n\t\treturn registration;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerTemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.autoconfigure.template.PathBasedTemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TemplateAvailabilityProvider} that provides availability information for\n * FreeMarker view templates.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class FreeMarkerTemplateAvailabilityProvider extends PathBasedTemplateAvailabilityProvider {\n\n\tprivate static final String REQUIRED_CLASS_NAME = \"freemarker.template.Configuration\";\n\n\tpublic FreeMarkerTemplateAvailabilityProvider() {\n\t\tsuper(REQUIRED_CLASS_NAME, FreeMarkerTemplateAvailabilityProperties.class, \"spring.freemarker\");\n\t}\n\n\tprotected static final class FreeMarkerTemplateAvailabilityProperties extends TemplateAvailabilityProperties {\n\n\t\tprivate List<String> templateLoaderPath = new ArrayList<>(\n\t\t\t\tArrays.asList(FreeMarkerProperties.DEFAULT_TEMPLATE_LOADER_PATH));\n\n\t\tFreeMarkerTemplateAvailabilityProperties() {\n\t\t\tsuper(FreeMarkerProperties.DEFAULT_PREFIX, FreeMarkerProperties.DEFAULT_SUFFIX);\n\t\t}\n\n\t\t@Override\n\t\tprotected List<String> getLoaderPath() {\n\t\t\treturn this.templateLoaderPath;\n\t\t}\n\n\t\tpublic List<String> getTemplateLoaderPath() {\n\t\t\treturn this.templateLoaderPath;\n\t\t}\n\n\t\tpublic void setTemplateLoaderPath(List<String> templateLoaderPath) {\n\t\t\tthis.templateLoaderPath = templateLoaderPath;\n\t\t}\n\n\t}\n\n\tstatic class FreeMarkerTemplateAvailabilityRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tif (ClassUtils.isPresent(REQUIRED_CLASS_NAME, classLoader)) {\n\t\t\t\tBindableRuntimeHintsRegistrar.forTypes(FreeMarkerTemplateAvailabilityProperties.class)\n\t\t\t\t\t.registerHints(hints, classLoader);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerVariablesCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.util.Map;\n\nimport freemarker.template.Configuration;\n\nimport org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the FreeMarker\n * {@link Configuration#getSharedVariableNames() shared variables} to fine-tune their\n * auto-configuration before they are used by an auto-configured\n * {@link FreeMarkerConfigurationFactory}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface FreeMarkerVariablesCustomizer {\n\n\t/**\n\t * Customize the {@code variables} to be set as well-known FreeMarker objects.\n\t * @param variables the variables to customize\n\t * @see FreeMarkerConfigurationFactory#setFreemarkerVariables(Map)\n\t */\n\tvoid customizeFreeMarkerVariables(Map<String, Object> variables);\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/java/org/springframework/boot/freemarker/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for FreeMarker.\n */\n@NullMarked\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.freemarker.allow-request-override\",\n      \"description\": \"Whether HttpServletRequest attributes are allowed to override (hide) controller generated model attributes of the same name. Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.allow-session-override\",\n      \"description\": \"Whether HttpSession attributes are allowed to override (hide) controller generated model attributes of the same name. Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.cache\",\n      \"description\": \"Whether to enable template caching. Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.content-type\",\n      \"description\": \"Content-Type value. Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"No longer required. To use FreeMarker without auto-configuration, depend directly on FreeMarker instead of spring-boot-freemarker.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.freemarker.expose-request-attributes\",\n      \"description\": \"Whether all request attributes should be added to the model prior to merging with the template. Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.expose-session-attributes\",\n      \"description\": \"Whether all HttpSession attributes should be added to the model prior to merging with the template. Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.expose-spring-macro-helpers\",\n      \"description\": \"Whether to expose a RequestContext for use by Spring's macro library, under the name \\\"springMacroRequestContext\\\". Only supported with Spring MVC.\"\n    },\n    {\n      \"name\": \"spring.freemarker.prefix\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"spring.freemarker.suffix\",\n      \"defaultValue\": \".ftlh\"\n    }\n  ],\n  \"hints\": [],\n  \"ignored\": {\n    \"properties\": []\n  }\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.freemarker.autoconfigure.FreeMarkerTemplateAvailabilityProvider$FreeMarkerTemplateAvailabilityRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.freemarker.autoconfigure.FreeMarkerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.AutoConfigureWebFlux.imports",
    "content": "org.springframework.boot.freemarker.autoconfigure.FreeMarkerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.freemarker.autoconfigure.FreeMarkerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.freemarker.cache=false\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/main/resources/META-INF/spring.factories",
    "content": "# Template Availability Providers\norg.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\\\norg.springframework.boot.freemarker.autoconfigure.FreeMarkerTemplateAvailabilityProvider\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerAutoConfigurationReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.io.StringWriter;\nimport java.time.Duration;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.web.reactive.result.view.View;\nimport org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfig;\nimport org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer;\nimport org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FreeMarkerAutoConfiguration} Reactive support.\n *\n * @author Brian Clozel\n */\nclass FreeMarkerAutoConfigurationReactiveIntegrationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FreeMarkerAutoConfiguration.class));\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid clearReactorSchedulers() {\n\t\tSchedulers.shutdownNow();\n\t}\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBean(FreeMarkerViewResolver.class)).isNotNull();\n\t\t\tassertThat(context.getBean(FreeMarkerConfigurer.class)).isNotNull();\n\t\t\tassertThat(context.getBean(FreeMarkerConfig.class)).isNotNull();\n\t\t\tassertThat(context.getBean(freemarker.template.Configuration.class)).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.ftlh\", content = \"home\")\n\tvoid defaultViewResolution() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMockServerWebExchange exchange = render(context, \"home\");\n\t\t\tString result = exchange.getResponse().getBodyAsString().block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).contains(\"home\");\n\t\t\tassertThat(exchange.getResponse().getHeaders().getContentType()).isEqualTo(MediaType.TEXT_HTML);\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/prefix/prefixed.ftlh\", content = \"prefixed\")\n\tvoid customPrefix() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.freemarker.prefix:prefix/\").run((context) -> {\n\t\t\tMockServerWebExchange exchange = render(context, \"prefixed\");\n\t\t\tString result = exchange.getResponse().getBodyAsString().block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).contains(\"prefixed\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/suffixed.freemarker\", content = \"suffixed\")\n\tvoid customSuffix() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.freemarker.suffix:.freemarker\").run((context) -> {\n\t\t\tMockServerWebExchange exchange = render(context, \"suffixed\");\n\t\t\tString result = exchange.getResponse().getBodyAsString().block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).contains(\"suffixed\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.ftlh\", content = \"custom\")\n\tvoid customTemplateLoaderPath() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.freemarker.templateLoaderPath:classpath:/custom-templates/\")\n\t\t\t.run((context) -> {\n\t\t\t\tMockServerWebExchange exchange = render(context, \"custom\");\n\t\t\t\tString result = exchange.getResponse().getBodyAsString().block(Duration.ofSeconds(30));\n\t\t\t\tassertThat(result).contains(\"custom\");\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\t@Test\n\tvoid customFreeMarkerSettings() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.freemarker.settings.boolean_format:yup,nope\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(FreeMarkerConfigurer.class).getConfiguration().getSetting(\"boolean_format\"))\n\t\t\t\t.isEqualTo(\"yup,nope\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/message.ftlh\", content = \"Message: ${greeting}\")\n\tvoid renderTemplate() {\n\t\tthis.contextRunner.withPropertyValues().run((context) -> {\n\t\t\tFreeMarkerConfigurer freemarker = context.getBean(FreeMarkerConfigurer.class);\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\tfreemarker.getConfiguration().getTemplate(\"message.ftlh\").process(new DataModel(), writer);\n\t\t\tassertThat(writer.toString()).contains(\"Hello World\");\n\t\t});\n\t}\n\n\tprivate MockServerWebExchange render(ApplicationContext context, String viewName) {\n\t\tFreeMarkerViewResolver resolver = context.getBean(FreeMarkerViewResolver.class);\n\t\tMono<View> view = resolver.resolveViewName(viewName, Locale.UK);\n\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/path\"));\n\t\tview.flatMap((v) -> v.render(null, MediaType.TEXT_HTML, exchange)).block(Duration.ofSeconds(30));\n\t\treturn exchange;\n\t}\n\n\tpublic static class DataModel {\n\n\t\tpublic String getGreeting() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerAutoConfigurationServletIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.io.StringWriter;\nimport java.util.EnumSet;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.servlet.filter.OrderedCharacterEncodingFilter;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;\nimport org.springframework.web.servlet.support.RequestContext;\nimport org.springframework.web.servlet.view.AbstractTemplateViewResolver;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerConfig;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;\nimport org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FreeMarkerAutoConfiguration} Servlet support.\n *\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n */\nclass FreeMarkerAutoConfigurationServletIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tload();\n\t\tassertThat(getContext().getBean(FreeMarkerViewResolver.class)).isNotNull();\n\t\tassertThat(getContext().getBean(FreeMarkerConfigurer.class)).isNotNull();\n\t\tassertThat(getContext().getBean(FreeMarkerConfig.class)).isNotNull();\n\t\tassertThat(getContext().getBean(freemarker.template.Configuration.class)).isNotNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.ftlh\", content = \"home\")\n\tvoid defaultViewResolution() throws Exception {\n\t\tload();\n\t\tMockHttpServletResponse response = render(\"home\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"home\");\n\t\tassertThat(response.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.ftlh\", content = \"home\")\n\tvoid customContentType() throws Exception {\n\t\tload(\"spring.freemarker.contentType:application/json\");\n\t\tMockHttpServletResponse response = render(\"home\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"home\");\n\t\tassertThat(response.getContentType()).isEqualTo(\"application/json;charset=UTF-8\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/prefix/prefixed.ftlh\", content = \"prefixed\")\n\tvoid customPrefix() throws Exception {\n\t\tload(\"spring.freemarker.prefix:prefix/\");\n\t\tMockHttpServletResponse response = render(\"prefixed\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"prefixed\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/suffixed.freemarker\", content = \"suffixed\")\n\tvoid customSuffix() throws Exception {\n\t\tload(\"spring.freemarker.suffix:.freemarker\");\n\t\tMockHttpServletResponse response = render(\"suffixed\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"suffixed\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.ftlh\", content = \"custom\")\n\tvoid customTemplateLoaderPath() throws Exception {\n\t\tload(\"spring.freemarker.templateLoaderPath:classpath:/custom-templates/\");\n\t\tMockHttpServletResponse response = render(\"custom\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"custom\");\n\t}\n\n\t@Test\n\tvoid disableCache() {\n\t\tload(\"spring.freemarker.cache:false\");\n\t\tassertThat(getContext().getBean(FreeMarkerViewResolver.class).getCacheLimit()).isZero();\n\t}\n\n\t@Test\n\tvoid allowSessionOverride() {\n\t\tload(\"spring.freemarker.allow-session-override:true\");\n\t\tAbstractTemplateViewResolver viewResolver = getContext().getBean(FreeMarkerViewResolver.class);\n\t\tassertThat(viewResolver).hasFieldOrPropertyWithValue(\"allowSessionOverride\", true);\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\t@Test\n\tvoid customFreeMarkerSettings() {\n\t\tload(\"spring.freemarker.settings.boolean_format:yup,nope\");\n\t\tassertThat(getContext().getBean(FreeMarkerConfigurer.class).getConfiguration().getSetting(\"boolean_format\"))\n\t\t\t.isEqualTo(\"yup,nope\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/message.ftlh\", content = \"Message: ${greeting}\")\n\tvoid renderTemplate() throws Exception {\n\t\tload();\n\t\tFreeMarkerConfigurer freemarker = getContext().getBean(FreeMarkerConfigurer.class);\n\t\tStringWriter writer = new StringWriter();\n\t\tfreemarker.getConfiguration().getTemplate(\"message.ftlh\").process(new DataModel(), writer);\n\t\tassertThat(writer.toString()).contains(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid registerResourceHandlingFilterDisabledByDefault() {\n\t\tload();\n\t\tassertThat(getContext().getBeansOfType(FilterRegistrationBean.class)).isEmpty();\n\t}\n\n\t@Test\n\tvoid registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() {\n\t\tload(\"spring.web.resources.chain.enabled:true\");\n\t\tFilterRegistrationBean<?> registration = getContext().getBean(FilterRegistrationBean.class);\n\t\tassertThat(registration.getFilter()).isInstanceOf(ResourceUrlEncodingFilter.class);\n\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\tEnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid registerResourceHandlingFilterWithOtherRegistrationBean() {\n\t\t// gh-14897\n\t\tload(FilterRegistrationOtherConfiguration.class, \"spring.web.resources.chain.enabled:true\");\n\t\tMap<String, FilterRegistrationBean> beans = getContext().getBeansOfType(FilterRegistrationBean.class);\n\t\tassertThat(beans).hasSize(2);\n\t\tFilterRegistrationBean registration = beans.values()\n\t\t\t.stream()\n\t\t\t.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\tEnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid registerResourceHandlingFilterWithResourceRegistrationBean() {\n\t\t// gh-14926\n\t\tload(FilterRegistrationResourceConfiguration.class, \"spring.web.resources.chain.enabled:true\");\n\t\tMap<String, FilterRegistrationBean> beans = getContext().getBeansOfType(FilterRegistrationBean.class);\n\t\tassertThat(beans).hasSize(1);\n\t\tFilterRegistrationBean registration = beans.values()\n\t\t\t.stream()\n\t\t\t.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)\n\t\t\t.findFirst()\n\t\t\t.get();\n\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\", EnumSet.of(DispatcherType.INCLUDE));\n\t}\n\n\tprivate void load(String... env) {\n\t\tload(BaseConfiguration.class, env);\n\t}\n\n\tprivate void load(Class<?> config, String... env) {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.setServletContext(new MockServletContext());\n\t\tTestPropertyValues.of(env).applyTo(this.context);\n\t\tthis.context.register(config);\n\t\tthis.context.refresh();\n\t}\n\n\tprivate MockHttpServletResponse render(String viewName) throws Exception {\n\t\tFreeMarkerViewResolver resolver = getContext().getBean(FreeMarkerViewResolver.class);\n\t\tView view = resolver.resolveViewName(viewName, Locale.UK);\n\t\tassertThat(view).isNotNull();\n\t\tHttpServletRequest request = new MockHttpServletRequest();\n\t\trequest.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tview.render(null, request, response);\n\t\treturn response;\n\t}\n\n\tprivate AnnotationConfigServletWebApplicationContext getContext() {\n\t\tAnnotationConfigServletWebApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ FreeMarkerAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tstatic class BaseConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class FilterRegistrationResourceConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> filterRegistration() {\n\t\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> bean = new FilterRegistrationBean<>(\n\t\t\t\t\tnew ResourceUrlEncodingFilter());\n\t\t\tbean.setDispatcherTypes(EnumSet.of(DispatcherType.INCLUDE));\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class FilterRegistrationOtherConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<OrderedCharacterEncodingFilter> filterRegistration() {\n\t\t\treturn new FilterRegistrationBean<>(new OrderedCharacterEncodingFilter());\n\t\t}\n\n\t}\n\n\tpublic static class DataModel {\n\n\t\tpublic String getGreeting() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.io.StringWriter;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link FreeMarkerAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass FreeMarkerAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FreeMarkerAutoConfiguration.class));\n\n\t@Test\n\t@WithResource(name = \"templates/message.ftlh\", content = \"Message: ${greeting}\")\n\tvoid renderNonWebAppTemplate() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tfreemarker.template.Configuration freemarker = context.getBean(freemarker.template.Configuration.class);\n\t\t\tStringWriter writer = new StringWriter();\n\t\t\tfreemarker.getTemplate(\"message.ftlh\").process(new DataModel(), writer);\n\t\t\tassertThat(writer.toString()).contains(\"Hello World\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid nonExistentTemplateLocation(CapturedOutput output) {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.freemarker.templateLoaderPath:\"\n\t\t\t\t\t+ \"classpath:/does-not-exist/,classpath:/also-does-not-exist\")\n\t\t\t.run((context) -> assertThat(output).contains(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\tvoid emptyTemplateLocation(CapturedOutput output, @TempDir Path tempDir) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.freemarker.templateLoaderPath:file:\" + tempDir.toAbsolutePath())\n\t\t\t.run((context) -> assertThat(output).doesNotContain(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\tvoid nonExistentLocationAndEmptyLocation(CapturedOutput output, @TempDir Path tempDir) {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.freemarker.templateLoaderPath:\" + \"classpath:/does-not-exist/,file:\"\n\t\t\t\t\t+ tempDir.toAbsolutePath())\n\t\t\t.run((context) -> assertThat(output).doesNotContain(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\tvoid variableCustomizerShouldBeApplied() {\n\t\tFreeMarkerVariablesCustomizer customizer = mock(FreeMarkerVariablesCustomizer.class);\n\t\tthis.contextRunner.withBean(FreeMarkerVariablesCustomizer.class, () -> customizer)\n\t\t\t.run((context) -> then(customizer).should().customizeFreeMarkerVariables(any()));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid variableCustomizersShouldBeAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(VariablesCustomizersConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(freemarker.template.Configuration.class);\n\t\t\tfreemarker.template.Configuration configuration = context.getBean(freemarker.template.Configuration.class);\n\t\t\tassertThat(configuration.getSharedVariableNames()).contains(\"order\", \"one\", \"two\");\n\t\t\tassertThat(configuration.getSharedVariable(\"order\")).hasToString(\"5\");\n\t\t});\n\t}\n\n\tpublic static class DataModel {\n\n\t\tpublic String getGreeting() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class VariablesCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tFreeMarkerVariablesCustomizer variablesCustomizer() {\n\t\t\treturn (variables) -> {\n\t\t\t\tvariables.put(\"order\", 5);\n\t\t\t\tvariables.put(\"one\", \"one\");\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tFreeMarkerVariablesCustomizer anotherVariablesCustomizer() {\n\t\t\treturn (variables) -> {\n\t\t\t\tvariables.put(\"order\", 2);\n\t\t\t\tvariables.put(\"two\", \"two\");\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.MimeTypeUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FreeMarkerProperties}.\n *\n * @author Stephane Nicoll\n */\nclass FreeMarkerPropertiesTests {\n\n\t@Test\n\tvoid defaultContentType() {\n\t\tassertThat(new FreeMarkerProperties().getContentType()).hasToString(\"text/html;charset=UTF-8\");\n\t}\n\n\t@Test\n\tvoid customContentTypeDefaultCharset() {\n\t\tFreeMarkerProperties properties = new FreeMarkerProperties();\n\t\tproperties.setContentType(MimeTypeUtils.parseMimeType(\"text/plain\"));\n\t\tassertThat(properties.getContentType()).hasToString(\"text/plain;charset=UTF-8\");\n\t}\n\n\t@Test\n\tvoid defaultContentTypeCustomCharset() {\n\t\tFreeMarkerProperties properties = new FreeMarkerProperties();\n\t\tproperties.setCharset(StandardCharsets.UTF_16);\n\t\tassertThat(properties.getContentType()).hasToString(\"text/html;charset=UTF-16\");\n\t}\n\n\t@Test\n\tvoid customContentTypeCustomCharset() {\n\t\tFreeMarkerProperties properties = new FreeMarkerProperties();\n\t\tproperties.setContentType(MimeTypeUtils.parseMimeType(\"text/plain\"));\n\t\tproperties.setCharset(StandardCharsets.UTF_16);\n\t\tassertThat(properties.getContentType()).hasToString(\"text/plain;charset=UTF-16\");\n\t}\n\n\t@Test\n\tvoid customContentTypeWithPropertyAndCustomCharset() {\n\t\tFreeMarkerProperties properties = new FreeMarkerProperties();\n\t\tproperties.setContentType(MimeTypeUtils.parseMimeType(\"text/plain;foo=bar\"));\n\t\tproperties.setCharset(StandardCharsets.UTF_16);\n\t\tassertThat(properties.getContentType()).hasToString(\"text/plain;charset=UTF-16;foo=bar\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerTemplateAvailabilityProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.freemarker.autoconfigure.FreeMarkerTemplateAvailabilityProvider.FreeMarkerTemplateAvailabilityProperties;\nimport org.springframework.boot.freemarker.autoconfigure.FreeMarkerTemplateAvailabilityProvider.FreeMarkerTemplateAvailabilityRuntimeHints;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FreeMarkerTemplateAvailabilityProvider}.\n *\n * @author Andy Wilkinson\n */\nclass FreeMarkerTemplateAvailabilityProviderTests {\n\n\tprivate final TemplateAvailabilityProvider provider = new FreeMarkerTemplateAvailabilityProvider();\n\n\tprivate final ResourceLoader resourceLoader = new DefaultResourceLoader();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\t@WithResource(name = \"templates/home.ftlh\")\n\tvoid availabilityOfTemplateInDefaultLocation() {\n\t\tassertThat(this.provider.isTemplateAvailable(\"home\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid availabilityOfTemplateThatDoesNotExist() {\n\t\tassertThat(this.provider.isTemplateAvailable(\"whatever\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.ftlh\")\n\tvoid availabilityOfTemplateWithCustomLoaderPath() {\n\t\tthis.environment.setProperty(\"spring.freemarker.template-loader-path\", \"classpath:/custom-templates/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"custom\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.ftlh\")\n\tvoid availabilityOfTemplateWithCustomLoaderPathConfiguredAsAList() {\n\t\tthis.environment.setProperty(\"spring.freemarker.template-loader-path[0]\", \"classpath:/custom-templates/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"custom\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/prefix/prefixed.ftlh\")\n\tvoid availabilityOfTemplateWithCustomPrefix() {\n\t\tthis.environment.setProperty(\"spring.freemarker.prefix\", \"prefix/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"prefixed\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/suffixed.freemarker\")\n\tvoid availabilityOfTemplateWithCustomSuffix() {\n\t\tthis.environment.setProperty(\"spring.freemarker.suffix\", \".freemarker\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"suffixed\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid shouldRegisterFreeMarkerTemplateAvailabilityPropertiesRuntimeHints() {\n\t\tassertThat(AotServices.factories().load(RuntimeHintsRegistrar.class))\n\t\t\t.hasAtLeastOneElementOfType(FreeMarkerTemplateAvailabilityRuntimeHints.class);\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew FreeMarkerTemplateAvailabilityRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tTypeHint typeHint = hints.reflection().getTypeHint(FreeMarkerTemplateAvailabilityProperties.class);\n\t\tassertThat(typeHint).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerWebFluxTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for FreeMarker with {@link WebFluxTest @WebFluxTest}.\n *\n * @author Andy Wilkinson\n */\n@WebFluxTest\nclass FreeMarkerWebFluxTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid freemarkerAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(FreeMarkerAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-freemarker/src/test/java/org/springframework/boot/freemarker/autoconfigure/FreeMarkerWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.freemarker.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for FreeMarker with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass FreeMarkerWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid freemarkerAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(FreeMarkerAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot GraphQL\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.graphql:spring-graphql\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-http-converter\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(project(\":module:spring-boot-rsocket\"))\n\toptional(project(\":module:spring-boot-security\"))\n\toptional(project(\":module:spring-boot-webflux\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\toptional(\"com.querydsl:querydsl-core\")\n\toptional(\"io.projectreactor.netty:reactor-netty-http\")\n\toptional(\"io.rsocket:rsocket-transport-netty\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"jakarta.websocket:jakarta.websocket-api\")\n\toptional(\"jakarta.websocket:jakarta.websocket-client-api\")\n\toptional(\"org.springframework:spring-websocket\")\n\toptional(\"org.springframework.data:spring-data-commons\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-http-codec\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\ttestImplementation(\"org.springframework.graphql:spring-graphql-test\")\n\ttestImplementation(\"org.springframework.security:spring-security-test\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/ConditionalOnGraphQlSchema.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when a GraphQL schema is defined for\n * the application, through schema files or infrastructure beans.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(DefaultGraphQlSchemaCondition.class)\npublic @interface ConditionalOnGraphQlSchema {\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/DefaultGraphQlSchemaCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.ConfigurationCondition;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternUtils;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Condition} that checks whether a GraphQL schema has been defined in the\n * application. This is looking for:\n * <ul>\n * <li>schema files in the {@link GraphQlProperties configured locations}</li>\n * <li>or {@link GraphQlSourceBuilderCustomizer} beans</li>\n * <li>or a {@link GraphQlSource} bean</li>\n * </ul>\n *\n * @author Brian Clozel\n * @see ConditionalOnGraphQlSchema\n */\nclass DefaultGraphQlSchemaCondition extends SpringBootCondition implements ConfigurationCondition {\n\n\t@Override\n\tpublic ConfigurationCondition.ConfigurationPhase getConfigurationPhase() {\n\t\treturn ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tboolean match = false;\n\t\tList<ConditionMessage> messages = new ArrayList<>(2);\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnGraphQlSchema.class);\n\t\tBinder binder = Binder.get(context.getEnvironment());\n\t\tGraphQlProperties.Schema schema = binder.bind(\"spring.graphql.schema\", GraphQlProperties.Schema.class)\n\t\t\t.orElse(new GraphQlProperties.Schema());\n\t\tResourcePatternResolver resourcePatternResolver = ResourcePatternUtils\n\t\t\t.getResourcePatternResolver(context.getResourceLoader());\n\t\tList<Resource> schemaResources = resolveSchemaResources(resourcePatternResolver, schema.getLocations(),\n\t\t\t\tschema.getFileExtensions());\n\t\tif (!schemaResources.isEmpty()) {\n\t\t\tmatch = true;\n\t\t\tmessages.add(message.found(\"schema\", \"schemas\").items(ConditionMessage.Style.QUOTE, schemaResources));\n\t\t}\n\t\telse {\n\t\t\tmessages.add(message.didNotFind(\"schema files in locations\")\n\t\t\t\t.items(ConditionMessage.Style.QUOTE, Arrays.asList(schema.getLocations())));\n\t\t}\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\tString[] customizerBeans = beanFactory.getBeanNamesForType(GraphQlSourceBuilderCustomizer.class, false, false);\n\t\tif (customizerBeans.length != 0) {\n\t\t\tmatch = true;\n\t\t\tmessages.add(message.found(\"customizer\", \"customizers\").items(Arrays.asList(customizerBeans)));\n\t\t}\n\t\telse {\n\t\t\tmessages.add((message.didNotFind(\"GraphQlSourceBuilderCustomizer\").atAll()));\n\t\t}\n\t\tString[] graphQlSourceBeanNames = beanFactory.getBeanNamesForType(GraphQlSource.class, false, false);\n\t\tif (graphQlSourceBeanNames.length != 0) {\n\t\t\tmatch = true;\n\t\t\tmessages.add(message.found(\"GraphQlSource\").items(Arrays.asList(graphQlSourceBeanNames)));\n\t\t}\n\t\telse {\n\t\t\tmessages.add((message.didNotFind(\"GraphQlSource\").atAll()));\n\t\t}\n\t\treturn new ConditionOutcome(match, ConditionMessage.of(messages));\n\t}\n\n\tprivate List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String[] locations,\n\t\t\tString[] extensions) {\n\t\tList<Resource> resources = new ArrayList<>();\n\t\tfor (String location : locations) {\n\t\t\tfor (String extension : extensions) {\n\t\t\t\tresources.addAll(resolveSchemaResources(resolver, location + \"*\" + extension));\n\t\t\t}\n\t\t}\n\t\treturn resources;\n\t}\n\n\tprivate List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String pattern) {\n\t\ttry {\n\t\t\treturn Arrays.asList(resolver.getResources(pattern));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/GraphQlAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\nimport graphql.GraphQL;\nimport graphql.execution.instrumentation.Instrumentation;\nimport graphql.introspection.Introspection;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.data.domain.ScrollPosition;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.method.HandlerMethodArgumentResolver;\nimport org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;\nimport org.springframework.graphql.data.pagination.ConnectionFieldTypeVisitor;\nimport org.springframework.graphql.data.pagination.CursorEncoder;\nimport org.springframework.graphql.data.pagination.CursorStrategy;\nimport org.springframework.graphql.data.pagination.EncodingCursorStrategy;\nimport org.springframework.graphql.data.query.ScrollPositionCursorStrategy;\nimport org.springframework.graphql.data.query.SliceConnectionAdapter;\nimport org.springframework.graphql.data.query.WindowConnectionAdapter;\nimport org.springframework.graphql.execution.BatchLoaderRegistry;\nimport org.springframework.graphql.execution.ConnectionTypeDefinitionConfigurer;\nimport org.springframework.graphql.execution.DataFetcherExceptionResolver;\nimport org.springframework.graphql.execution.DefaultBatchLoaderRegistry;\nimport org.springframework.graphql.execution.DefaultExecutionGraphQlService;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.graphql.execution.SubscriptionExceptionResolver;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for creating a Spring GraphQL base\n * infrastructure.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ GraphQL.class, GraphQlSource.class })\n@ConditionalOnGraphQlSchema\n@EnableConfigurationProperties(GraphQlProperties.class)\n@ImportRuntimeHints(GraphQlAutoConfiguration.GraphQlResourcesRuntimeHints.class)\npublic final class GraphQlAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(GraphQlAutoConfiguration.class);\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlSource graphQlSource(ResourcePatternResolver resourcePatternResolver, GraphQlProperties properties,\n\t\t\tObjectProvider<DataFetcherExceptionResolver> exceptionResolvers,\n\t\t\tObjectProvider<SubscriptionExceptionResolver> subscriptionExceptionResolvers,\n\t\t\tObjectProvider<Instrumentation> instrumentations, ObjectProvider<RuntimeWiringConfigurer> wiringConfigurers,\n\t\t\tObjectProvider<GraphQlSourceBuilderCustomizer> sourceCustomizers) {\n\n\t\tString[] schemaLocations = properties.getSchema().getLocations();\n\t\tList<Resource> schemaResources = new ArrayList<>();\n\t\tschemaResources.addAll(resolveSchemaResources(resourcePatternResolver, schemaLocations,\n\t\t\t\tproperties.getSchema().getFileExtensions()));\n\t\tschemaResources.addAll(Arrays.asList(properties.getSchema().getAdditionalFiles()));\n\n\t\tGraphQlSource.SchemaResourceBuilder builder = GraphQlSource.schemaResourceBuilder()\n\t\t\t.schemaResources(schemaResources.toArray(new Resource[0]))\n\t\t\t.exceptionResolvers(exceptionResolvers.orderedStream().toList())\n\t\t\t.subscriptionExceptionResolvers(subscriptionExceptionResolvers.orderedStream().toList())\n\t\t\t.instrumentation(instrumentations.orderedStream().toList());\n\t\tif (properties.getSchema().getInspection().isEnabled()) {\n\t\t\tbuilder.inspectSchemaMappings(logger::info);\n\t\t}\n\t\tif (!properties.getSchema().getIntrospection().isEnabled()) {\n\t\t\tIntrospection.enabledJvmWide(false);\n\t\t}\n\t\tbuilder.configureTypeDefinitions(new ConnectionTypeDefinitionConfigurer());\n\t\twiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);\n\t\tsourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String[] locations,\n\t\t\tString[] extensions) {\n\t\tList<Resource> resources = new ArrayList<>();\n\t\tfor (String location : locations) {\n\t\t\tfor (String extension : extensions) {\n\t\t\t\tresources.addAll(resolveSchemaResources(resolver, location + \"*\" + extension));\n\t\t\t}\n\t\t}\n\t\treturn resources;\n\t}\n\n\tprivate List<Resource> resolveSchemaResources(ResourcePatternResolver resolver, String pattern) {\n\t\ttry {\n\t\t\treturn Arrays.asList(resolver.getResources(pattern));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tlogger.debug(LogMessage.format(\"Could not resolve schema location: '%s'\", pattern), ex);\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tBatchLoaderRegistry batchLoaderRegistry() {\n\t\treturn new DefaultBatchLoaderRegistry();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tExecutionGraphQlService executionGraphQlService(GraphQlSource graphQlSource,\n\t\t\tBatchLoaderRegistry batchLoaderRegistry) {\n\t\tDefaultExecutionGraphQlService service = new DefaultExecutionGraphQlService(graphQlSource);\n\t\tservice.addDataLoaderRegistrar(batchLoaderRegistry);\n\t\treturn service;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAnnotatedControllerConfigurer annotatedControllerConfigurer(\n\t\t\t@Qualifier(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) ObjectProvider<Executor> executorProvider,\n\t\t\tObjectProvider<HandlerMethodArgumentResolver> argumentResolvers) {\n\t\tAnnotatedControllerConfigurer controllerConfigurer = new AnnotatedControllerConfigurer();\n\t\tcontrollerConfigurer\n\t\t\t.configureBinder((options) -> options.conversionService(ApplicationConversionService.getSharedInstance()));\n\t\texecutorProvider.ifAvailable(controllerConfigurer::setExecutor);\n\t\targumentResolvers.orderedStream().forEach(controllerConfigurer::addCustomArgumentResolver);\n\t\treturn controllerConfigurer;\n\t}\n\n\t@Bean\n\tDataFetcherExceptionResolver annotatedControllerConfigurerDataFetcherExceptionResolver(\n\t\t\tAnnotatedControllerConfigurer annotatedControllerConfigurer) {\n\t\treturn annotatedControllerConfigurer.getExceptionResolver();\n\t}\n\n\t@ConditionalOnClass(ScrollPosition.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GraphQlDataAutoConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tEncodingCursorStrategy<ScrollPosition> cursorStrategy() {\n\t\t\treturn CursorStrategy.withEncoder(new ScrollPositionCursorStrategy(), CursorEncoder.base64());\n\t\t}\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tGraphQlSourceBuilderCustomizer cursorStrategyCustomizer(CursorStrategy<?> cursorStrategy) {\n\t\t\tif (cursorStrategy.supports(ScrollPosition.class)) {\n\t\t\t\tCursorStrategy<ScrollPosition> scrollCursorStrategy = (CursorStrategy<ScrollPosition>) cursorStrategy;\n\t\t\t\tConnectionFieldTypeVisitor connectionFieldTypeVisitor = ConnectionFieldTypeVisitor\n\t\t\t\t\t.create(List.of(new WindowConnectionAdapter(scrollCursorStrategy),\n\t\t\t\t\t\t\tnew SliceConnectionAdapter(scrollCursorStrategy)));\n\t\t\t\treturn (builder) -> builder.typeVisitors(List.of(connectionFieldTypeVisitor));\n\t\t\t}\n\t\t\treturn (builder) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class GraphQlResourcesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"graphql/**/*.graphqls\").registerPattern(\"graphql/**/*.gqls\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/GraphQlCorsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.cors.CorsConfiguration;\n\n/**\n * Configuration properties for GraphQL endpoint's CORS support.\n *\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.graphql.cors\")\npublic class GraphQlCorsProperties {\n\n\t/**\n\t * List of origins to allow with '*' allowing all origins. When allow-credentials is\n\t * enabled, '*' cannot be used, and setting origin patterns should be considered\n\t * instead. When neither allowed origins nor allowed origin patterns are set,\n\t * cross-origin requests are effectively disabled.\n\t */\n\tprivate List<String> allowedOrigins = new ArrayList<>();\n\n\t/**\n\t * List of origin patterns to allow. Unlike allowed origins which only support '*',\n\t * origin patterns are more flexible, e.g. 'https://*.example.com', and can be used\n\t * with allow-credentials. When neither allowed origins nor allowed origin patterns\n\t * are set, cross-origin requests are effectively disabled.\n\t */\n\tprivate List<String> allowedOriginPatterns = new ArrayList<>();\n\n\t/**\n\t * List of HTTP methods to allow. '*' allows all methods. When not set, defaults to\n\t * GET.\n\t */\n\tprivate List<String> allowedMethods = new ArrayList<>();\n\n\t/**\n\t * List of HTTP headers to allow in a request. '*' allows all headers.\n\t */\n\tprivate List<String> allowedHeaders = new ArrayList<>();\n\n\t/**\n\t * List of headers to include in a response.\n\t */\n\tprivate List<String> exposedHeaders = new ArrayList<>();\n\n\t/**\n\t * Whether credentials are supported. When not set, credentials are not supported.\n\t */\n\tprivate @Nullable Boolean allowCredentials;\n\n\t/**\n\t * How long the response from a pre-flight request can be cached by clients. If a\n\t * duration suffix is not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate Duration maxAge = Duration.ofSeconds(1800);\n\n\tpublic List<String> getAllowedOrigins() {\n\t\treturn this.allowedOrigins;\n\t}\n\n\tpublic void setAllowedOrigins(List<String> allowedOrigins) {\n\t\tthis.allowedOrigins = allowedOrigins;\n\t}\n\n\tpublic List<String> getAllowedOriginPatterns() {\n\t\treturn this.allowedOriginPatterns;\n\t}\n\n\tpublic void setAllowedOriginPatterns(List<String> allowedOriginPatterns) {\n\t\tthis.allowedOriginPatterns = allowedOriginPatterns;\n\t}\n\n\tpublic List<String> getAllowedMethods() {\n\t\treturn this.allowedMethods;\n\t}\n\n\tpublic void setAllowedMethods(List<String> allowedMethods) {\n\t\tthis.allowedMethods = allowedMethods;\n\t}\n\n\tpublic List<String> getAllowedHeaders() {\n\t\treturn this.allowedHeaders;\n\t}\n\n\tpublic void setAllowedHeaders(List<String> allowedHeaders) {\n\t\tthis.allowedHeaders = allowedHeaders;\n\t}\n\n\tpublic List<String> getExposedHeaders() {\n\t\treturn this.exposedHeaders;\n\t}\n\n\tpublic void setExposedHeaders(List<String> exposedHeaders) {\n\t\tthis.exposedHeaders = exposedHeaders;\n\t}\n\n\tpublic @Nullable Boolean getAllowCredentials() {\n\t\treturn this.allowCredentials;\n\t}\n\n\tpublic void setAllowCredentials(@Nullable Boolean allowCredentials) {\n\t\tthis.allowCredentials = allowCredentials;\n\t}\n\n\tpublic Duration getMaxAge() {\n\t\treturn this.maxAge;\n\t}\n\n\tpublic void setMaxAge(Duration maxAge) {\n\t\tthis.maxAge = maxAge;\n\t}\n\n\tpublic @Nullable CorsConfiguration toCorsConfiguration() {\n\t\tif (CollectionUtils.isEmpty(this.allowedOrigins) && CollectionUtils.isEmpty(this.allowedOriginPatterns)) {\n\t\t\treturn null;\n\t\t}\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tCorsConfiguration config = new CorsConfiguration();\n\t\tmap.from(this::getAllowedOrigins).to(config::setAllowedOrigins);\n\t\tmap.from(this::getAllowedOriginPatterns).to(config::setAllowedOriginPatterns);\n\t\tmap.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty).to(config::setAllowedHeaders);\n\t\tmap.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty).to(config::setAllowedMethods);\n\t\tmap.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty).to(config::setExposedHeaders);\n\t\tmap.from(this::getMaxAge).as(Duration::getSeconds).to(config::setMaxAge);\n\t\tmap.from(this::getAllowCredentials).to(config::setAllowCredentials);\n\t\treturn config;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/GraphQlProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Arrays;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\n\n/**\n * {@link ConfigurationProperties Properties} for Spring GraphQL.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.graphql\")\npublic class GraphQlProperties {\n\n\tprivate final Http http = new Http();\n\n\tprivate final Graphiql graphiql = new Graphiql();\n\n\tprivate final Rsocket rsocket = new Rsocket();\n\n\tprivate final Schema schema = new Schema();\n\n\tprivate final Websocket websocket = new Websocket();\n\n\tpublic Http getHttp() {\n\t\treturn this.http;\n\t}\n\n\tpublic Graphiql getGraphiql() {\n\t\treturn this.graphiql;\n\t}\n\n\tpublic Schema getSchema() {\n\t\treturn this.schema;\n\t}\n\n\tpublic Websocket getWebsocket() {\n\t\treturn this.websocket;\n\t}\n\n\tpublic Rsocket getRsocket() {\n\t\treturn this.rsocket;\n\t}\n\n\tpublic static class Http {\n\n\t\t/**\n\t\t * Path at which to expose a GraphQL request HTTP endpoint.\n\t\t */\n\t\tprivate String path = \"/graphql\";\n\n\t\tprivate final Sse sse = new Sse();\n\n\t\tpublic String getPath() {\n\t\t\treturn this.path;\n\t\t}\n\n\t\tpublic void setPath(String path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tpublic Sse getSse() {\n\t\t\treturn this.sse;\n\t\t}\n\n\t}\n\n\tpublic static class Schema {\n\n\t\t/**\n\t\t * Locations of GraphQL schema files.\n\t\t */\n\t\tprivate String[] locations = new String[] { \"classpath:graphql/**/\" };\n\n\t\t/**\n\t\t * File extensions for GraphQL schema files.\n\t\t */\n\t\tprivate String[] fileExtensions = new String[] { \".graphqls\", \".gqls\" };\n\n\t\t/**\n\t\t * Locations of additional, individual schema files to parse.\n\t\t */\n\t\tprivate Resource[] additionalFiles = new Resource[0];\n\n\t\tprivate final Inspection inspection = new Inspection();\n\n\t\tprivate final Introspection introspection = new Introspection();\n\n\t\tprivate final Printer printer = new Printer();\n\n\t\tpublic String[] getLocations() {\n\t\t\treturn this.locations;\n\t\t}\n\n\t\tpublic void setLocations(String[] locations) {\n\t\t\tthis.locations = appendSlashIfNecessary(locations);\n\t\t}\n\n\t\tpublic String[] getFileExtensions() {\n\t\t\treturn this.fileExtensions;\n\t\t}\n\n\t\tpublic void setFileExtensions(String[] fileExtensions) {\n\t\t\tthis.fileExtensions = fileExtensions;\n\t\t}\n\n\t\tpublic Resource[] getAdditionalFiles() {\n\t\t\treturn this.additionalFiles;\n\t\t}\n\n\t\tpublic void setAdditionalFiles(Resource[] additionalFiles) {\n\t\t\tthis.additionalFiles = additionalFiles;\n\t\t}\n\n\t\tprivate String[] appendSlashIfNecessary(String[] locations) {\n\t\t\treturn Arrays.stream(locations)\n\t\t\t\t.map((location) -> location.endsWith(\"/\") ? location : location + \"/\")\n\t\t\t\t.toArray(String[]::new);\n\t\t}\n\n\t\tpublic Inspection getInspection() {\n\t\t\treturn this.inspection;\n\t\t}\n\n\t\tpublic Introspection getIntrospection() {\n\t\t\treturn this.introspection;\n\t\t}\n\n\t\tpublic Printer getPrinter() {\n\t\t\treturn this.printer;\n\t\t}\n\n\t\tpublic static class Inspection {\n\n\t\t\t/**\n\t\t\t * Whether schema should be compared to the application to detect missing\n\t\t\t * mappings.\n\t\t\t */\n\t\t\tprivate boolean enabled = true;\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Introspection {\n\n\t\t\t/**\n\t\t\t * Whether field introspection should be enabled at the schema level.\n\t\t\t */\n\t\t\tprivate boolean enabled = true;\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Printer {\n\n\t\t\t/**\n\t\t\t * Whether the endpoint that prints the schema is enabled. Schema is available\n\t\t\t * under spring.graphql.http.path + \"/schema\".\n\t\t\t */\n\t\t\tprivate boolean enabled;\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Graphiql {\n\n\t\t/**\n\t\t * Path to the GraphiQL UI endpoint.\n\t\t */\n\t\tprivate String path = \"/graphiql\";\n\n\t\t/**\n\t\t * Whether the default GraphiQL UI is enabled.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\tpublic String getPath() {\n\t\t\treturn this.path;\n\t\t}\n\n\t\tpublic void setPath(String path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\tpublic static class Websocket {\n\n\t\t/**\n\t\t * Path of the GraphQL WebSocket subscription endpoint.\n\t\t */\n\t\tprivate @Nullable String path;\n\n\t\t/**\n\t\t * Time within which the initial {@code CONNECTION_INIT} type message must be\n\t\t * received.\n\t\t */\n\t\tprivate Duration connectionInitTimeout = Duration.ofSeconds(60);\n\n\t\t/**\n\t\t * Maximum idle period before a server keep-alive ping is sent to client.\n\t\t */\n\t\tprivate @Nullable Duration keepAlive;\n\n\t\tpublic @Nullable String getPath() {\n\t\t\treturn this.path;\n\t\t}\n\n\t\tpublic void setPath(@Nullable String path) {\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tpublic Duration getConnectionInitTimeout() {\n\t\t\treturn this.connectionInitTimeout;\n\t\t}\n\n\t\tpublic void setConnectionInitTimeout(Duration connectionInitTimeout) {\n\t\t\tthis.connectionInitTimeout = connectionInitTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getKeepAlive() {\n\t\t\treturn this.keepAlive;\n\t\t}\n\n\t\tpublic void setKeepAlive(@Nullable Duration keepAlive) {\n\t\t\tthis.keepAlive = keepAlive;\n\t\t}\n\n\t}\n\n\tpublic static class Rsocket {\n\n\t\t/**\n\t\t * Mapping of the RSocket message handler.\n\t\t */\n\t\tprivate @Nullable String mapping;\n\n\t\tpublic @Nullable String getMapping() {\n\t\t\treturn this.mapping;\n\t\t}\n\n\t\tpublic void setMapping(@Nullable String mapping) {\n\t\t\tthis.mapping = mapping;\n\t\t}\n\n\t}\n\n\tpublic static class Sse {\n\n\t\t/**\n\t\t * How frequently keep-alive messages should be sent.\n\t\t */\n\t\tprivate @Nullable Duration keepAlive;\n\n\t\t/**\n\t\t * Time required for concurrent handling to complete.\n\t\t */\n\t\tprivate @Nullable Duration timeout;\n\n\t\tpublic @Nullable Duration getKeepAlive() {\n\t\t\treturn this.keepAlive;\n\t\t}\n\n\t\tpublic void setKeepAlive(@Nullable Duration keepAlive) {\n\t\t\tthis.keepAlive = keepAlive;\n\t\t}\n\n\t\tpublic @Nullable Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/GraphQlSourceBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport org.springframework.graphql.execution.GraphQlSource;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize properties of\n * {@link org.springframework.graphql.execution.GraphQlSource.SchemaResourceBuilder\n * Builder} to fine-tune its auto-configuration.\n *\n * @author Rossen Stoyanchev\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface GraphQlSourceBuilderCustomizer {\n\n\t/**\n\t * Customize the\n\t * {@link org.springframework.graphql.execution.GraphQlSource.SchemaResourceBuilder\n\t * Builder} instance.\n\t * @param builder builder the builder to customize\n\t */\n\tvoid customize(GraphQlSource.SchemaResourceBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlQueryByExampleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport graphql.GraphQL;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.repository.query.QueryByExampleExecutor;\nimport org.springframework.graphql.data.query.QueryByExampleDataFetcher;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} that creates a\n * {@link GraphQlSourceBuilderCustomizer}s to detect Spring Data repositories with Query\n * By Example support and register them as {@code DataFetcher}s for any queries with a\n * matching return type.\n *\n * @author Rossen Stoyanchev\n * @since 4.0.0\n * @see QueryByExampleDataFetcher#autoRegistrationConfigurer(List, List)\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnClass({ GraphQL.class, QueryByExampleDataFetcher.class, QueryByExampleExecutor.class })\n@ConditionalOnBean(GraphQlSource.class)\npublic final class GraphQlQueryByExampleAutoConfiguration {\n\n\t@Bean\n\tGraphQlSourceBuilderCustomizer queryByExampleRegistrar(ObjectProvider<QueryByExampleExecutor<?>> executors) {\n\t\tRuntimeWiringConfigurer configurer = QueryByExampleDataFetcher\n\t\t\t.autoRegistrationConfigurer(executors.orderedStream().toList(), Collections.emptyList());\n\t\treturn (builder) -> builder.configureRuntimeWiring(configurer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlQuerydslAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.querydsl.core.Query;\nimport graphql.GraphQL;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.querydsl.QuerydslPredicateExecutor;\nimport org.springframework.graphql.data.query.QuerydslDataFetcher;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} that creates a\n * {@link GraphQlSourceBuilderCustomizer}s to detect Spring Data repositories with\n * Querydsl support and register them as {@code DataFetcher}s for any queries with a\n * matching return type.\n *\n * @author Rossen Stoyanchev\n * @author Brian Clozel\n * @since 4.0.0\n * @see QuerydslDataFetcher#autoRegistrationConfigurer(List, List)\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnClass({ GraphQL.class, Query.class, QuerydslDataFetcher.class, QuerydslPredicateExecutor.class })\n@ConditionalOnBean(GraphQlSource.class)\npublic final class GraphQlQuerydslAutoConfiguration {\n\n\t@Bean\n\tGraphQlSourceBuilderCustomizer querydslRegistrar(ObjectProvider<QuerydslPredicateExecutor<?>> executors) {\n\t\tRuntimeWiringConfigurer configurer = QuerydslDataFetcher\n\t\t\t.autoRegistrationConfigurer(executors.orderedStream().toList(), Collections.emptyList());\n\t\treturn (builder) -> builder.configureRuntimeWiring(configurer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlReactiveQueryByExampleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport graphql.GraphQL;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;\nimport org.springframework.graphql.data.query.QueryByExampleDataFetcher;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} that creates a\n * {@link GraphQlSourceBuilderCustomizer}s to detect Spring Data repositories with Query\n * By Example support and register them as {@code DataFetcher}s for any queries with a\n * matching return type.\n *\n * @author Rossen Stoyanchev\n * @since 4.0.0\n * @see QueryByExampleDataFetcher#autoRegistrationConfigurer(List, List)\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnClass({ GraphQL.class, QueryByExampleDataFetcher.class, ReactiveQueryByExampleExecutor.class })\n@ConditionalOnBean(GraphQlSource.class)\npublic final class GraphQlReactiveQueryByExampleAutoConfiguration {\n\n\t@Bean\n\tGraphQlSourceBuilderCustomizer reactiveQueryByExampleRegistrar(\n\t\t\tObjectProvider<ReactiveQueryByExampleExecutor<?>> reactiveExecutors) {\n\t\tRuntimeWiringConfigurer configurer = QueryByExampleDataFetcher\n\t\t\t.autoRegistrationConfigurer(Collections.emptyList(), reactiveExecutors.orderedStream().toList());\n\t\treturn (builder) -> builder.configureRuntimeWiring(configurer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlReactiveQuerydslAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport com.querydsl.core.Query;\nimport graphql.GraphQL;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor;\nimport org.springframework.graphql.data.query.QuerydslDataFetcher;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} that creates a\n * {@link GraphQlSourceBuilderCustomizer}s to detect Spring Data repositories with\n * Querydsl support and register them as {@code DataFetcher}s for any queries with a\n * matching return type.\n *\n * @author Rossen Stoyanchev\n * @author Brian Clozel\n * @since 4.0.0\n * @see QuerydslDataFetcher#autoRegistrationConfigurer(List, List)\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnClass({ GraphQL.class, Query.class, QuerydslDataFetcher.class, ReactiveQuerydslPredicateExecutor.class })\n@ConditionalOnBean(GraphQlSource.class)\npublic final class GraphQlReactiveQuerydslAutoConfiguration {\n\n\t@Bean\n\tGraphQlSourceBuilderCustomizer reactiveQuerydslRegistrar(\n\t\t\tObjectProvider<ReactiveQuerydslPredicateExecutor<?>> reactiveExecutors) {\n\t\tRuntimeWiringConfigurer configurer = QuerydslDataFetcher.autoRegistrationConfigurer(Collections.emptyList(),\n\t\t\t\treactiveExecutors.orderedStream().toList());\n\t\treturn (builder) -> builder.configureRuntimeWiring(configurer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/data/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for data integrations with GraphQL.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/observation/GraphQlObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.observation;\n\nimport graphql.GraphQL;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.observation.DataFetcherObservationConvention;\nimport org.springframework.graphql.observation.DataLoaderObservationConvention;\nimport org.springframework.graphql.observation.ExecutionRequestObservationConvention;\nimport org.springframework.graphql.observation.GraphQlObservationInstrumentation;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring\n * GraphQL endpoints.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnBean(ObservationRegistry.class)\n@ConditionalOnClass({ GraphQL.class, GraphQlSource.class, Observation.class })\npublic final class GraphQlObservationAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlObservationInstrumentation graphQlObservationInstrumentation(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<ExecutionRequestObservationConvention> executionConvention,\n\t\t\tObjectProvider<DataFetcherObservationConvention> dataFetcherConvention,\n\t\t\tObjectProvider<DataLoaderObservationConvention> dataLoaderObservationConvention) {\n\t\treturn new GraphQlObservationInstrumentation(observationRegistry, executionConvention.getIfAvailable(),\n\t\t\t\tdataFetcherConvention.getIfAvailable(), dataLoaderObservationConvention.getIfAvailable());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring GraphQL observations.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring GraphQL.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/reactive/GraphQlWebFluxAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.reactive;\n\nimport java.util.Collections;\n\nimport graphql.GraphQL;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlCorsProperties;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.server.WebGraphQlHandler;\nimport org.springframework.graphql.server.WebGraphQlInterceptor;\nimport org.springframework.graphql.server.webflux.GraphQlHttpHandler;\nimport org.springframework.graphql.server.webflux.GraphQlRequestPredicates;\nimport org.springframework.graphql.server.webflux.GraphQlSseHandler;\nimport org.springframework.graphql.server.webflux.GraphQlWebSocketHandler;\nimport org.springframework.graphql.server.webflux.GraphiQlHandler;\nimport org.springframework.graphql.server.webflux.SchemaHandler;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.util.Assert;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.config.CorsRegistry;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;\nimport org.springframework.web.reactive.socket.server.support.WebSocketUpgradeHandlerPredicate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for enabling Spring GraphQL over\n * WebFlux.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass({ GraphQL.class, GraphQlHttpHandler.class })\n@ConditionalOnBean(ExecutionGraphQlService.class)\n@EnableConfigurationProperties(GraphQlCorsProperties.class)\n@ImportRuntimeHints(GraphQlWebFluxAutoConfiguration.GraphiQlResourceHints.class)\npublic final class GraphQlWebFluxAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(GraphQlWebFluxAutoConfiguration.class);\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {\n\t\treturn new GraphQlHttpHandler(webGraphQlHandler);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlSseHandler graphQlSseHandler(WebGraphQlHandler webGraphQlHandler, GraphQlProperties properties) {\n\t\treturn new GraphQlSseHandler(webGraphQlHandler, properties.getHttp().getSse().getTimeout(),\n\t\t\t\tproperties.getHttp().getSse().getKeepAlive());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tWebGraphQlHandler webGraphQlHandler(ExecutionGraphQlService service,\n\t\t\tObjectProvider<WebGraphQlInterceptor> interceptors) {\n\t\treturn WebGraphQlHandler.builder(service).interceptors(interceptors.orderedStream().toList()).build();\n\t}\n\n\t@Bean\n\t@Order(0)\n\tRouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler httpHandler, GraphQlSseHandler sseHandler,\n\t\t\tObjectProvider<GraphQlSource> graphQlSourceProvider, GraphQlProperties properties) {\n\t\tString path = properties.getHttp().getPath();\n\t\tlogger.info(LogMessage.format(\"GraphQL endpoint HTTP POST %s\", path));\n\t\tRouterFunctions.Builder builder = RouterFunctions.route();\n\t\tbuilder.route(GraphQlRequestPredicates.graphQlHttp(path), httpHandler::handleRequest);\n\t\tbuilder.route(GraphQlRequestPredicates.graphQlSse(path), sseHandler::handleRequest);\n\t\tbuilder.POST(path, this::unsupportedMediaType);\n\t\tbuilder.GET(path, this::onlyAllowPost);\n\t\tif (properties.getGraphiql().isEnabled()) {\n\t\t\tGraphiQlHandler graphQlHandler = createGraphQlHandler(properties, path);\n\t\t\tbuilder.GET(properties.getGraphiql().getPath(), graphQlHandler::handleRequest);\n\t\t}\n\t\tGraphQlSource graphQlSource = graphQlSourceProvider.getIfAvailable();\n\t\tif (properties.getSchema().getPrinter().isEnabled() && graphQlSource != null) {\n\t\t\tSchemaHandler schemaHandler = new SchemaHandler(graphQlSource);\n\t\t\tbuilder.GET(path + \"/schema\", schemaHandler::handleRequest);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\tprivate GraphiQlHandler createGraphQlHandler(GraphQlProperties properties, String path) {\n\t\treturn new GraphiQlHandler(path, properties.getWebsocket().getPath());\n\t}\n\n\tprivate Mono<ServerResponse> unsupportedMediaType(ServerRequest request) {\n\t\treturn ServerResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).headers(this::acceptJson).build();\n\t}\n\n\tprivate void acceptJson(HttpHeaders headers) {\n\t\theaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));\n\t}\n\n\tprivate Mono<ServerResponse> onlyAllowPost(ServerRequest request) {\n\t\treturn ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build();\n\t}\n\n\tprivate void onlyAllowPost(HttpHeaders headers) {\n\t\theaders.setAllow(Collections.singleton(HttpMethod.POST));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GraphQlEndpointCorsConfiguration implements WebFluxConfigurer {\n\n\t\tfinal GraphQlProperties graphQlProperties;\n\n\t\tfinal GraphQlCorsProperties corsProperties;\n\n\t\tGraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlCorsProperties corsProps) {\n\t\t\tthis.graphQlProperties = graphQlProps;\n\t\t\tthis.corsProperties = corsProps;\n\t\t}\n\n\t\t@Override\n\t\tpublic void addCorsMappings(CorsRegistry registry) {\n\t\t\tCorsConfiguration configuration = this.corsProperties.toCorsConfiguration();\n\t\t\tif (configuration != null) {\n\t\t\t\tregistry.addMapping(this.graphQlProperties.getHttp().getPath()).combine(configuration);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(\"spring.graphql.websocket.path\")\n\tstatic class WebSocketConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tGraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,\n\t\t\t\tGraphQlProperties properties, ServerCodecConfigurer configurer) {\n\t\t\treturn new GraphQlWebSocketHandler(webGraphQlHandler, configurer,\n\t\t\t\t\tproperties.getWebsocket().getConnectionInitTimeout(), properties.getWebsocket().getKeepAlive());\n\t\t}\n\n\t\t@Bean\n\t\tHandlerMapping graphQlWebSocketEndpoint(GraphQlWebSocketHandler graphQlWebSocketHandler,\n\t\t\t\tGraphQlProperties properties) {\n\t\t\tString path = properties.getWebsocket().getPath();\n\t\t\tAssert.state(path != null, \"'path' must not be null\");\n\t\t\tlogger.info(LogMessage.format(\"GraphQL endpoint WebSocket %s\", path));\n\t\t\tSimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();\n\t\t\tmapping.setHandlerPredicate(new WebSocketUpgradeHandlerPredicate());\n\t\t\tmapping.setUrlMap(Collections.singletonMap(path, graphQlWebSocketHandler));\n\t\t\tmapping.setOrder(-2); // Ahead of HTTP endpoint (\"routerFunctionMapping\" bean)\n\t\t\treturn mapping;\n\t\t}\n\n\t}\n\n\tstatic class GraphiQlResourceHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"graphiql/index.html\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for WebFlux support in Spring GraphQL.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/rsocket/GraphQlRSocketAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.rsocket;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport graphql.GraphQL;\nimport io.rsocket.core.RSocketServer;\nimport reactor.netty.http.server.HttpServer;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.codec.Encoder;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.server.GraphQlRSocketHandler;\nimport org.springframework.graphql.server.RSocketGraphQlInterceptor;\nimport org.springframework.http.codec.json.JacksonJsonEncoder;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for enabling Spring GraphQL over\n * RSocket.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class,\n\t\tafterName = { \"org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\" })\n@ConditionalOnClass({ GraphQL.class, GraphQlSource.class, RSocketServer.class, HttpServer.class })\n@ConditionalOnBean({ RSocketMessageHandler.class, AnnotatedControllerConfigurer.class })\n@ConditionalOnProperty(\"spring.graphql.rsocket.mapping\")\npublic final class GraphQlRSocketAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlRSocketHandler graphQlRSocketHandler(ExecutionGraphQlService graphQlService,\n\t\t\tObjectProvider<RSocketGraphQlInterceptor> interceptors, JsonEncoderSupplier jsonEncoderSupplier) {\n\t\treturn new GraphQlRSocketHandler(graphQlService, interceptors.orderedStream().toList(),\n\t\t\t\tjsonEncoderSupplier.jsonEncoder());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlRSocketController graphQlRSocketController(GraphQlRSocketHandler handler) {\n\t\treturn new GraphQlRSocketController(handler);\n\t}\n\n\tinterface JsonEncoderSupplier {\n\n\t\tEncoder<?> jsonEncoder();\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(JsonMapper.class)\n\t@ConditionalOnProperty(name = \"spring.graphql.rsocket.preferred-json-mapper\", havingValue = \"jackson\",\n\t\t\tmatchIfMissing = true)\n\tstatic class JacksonJsonEncoderSupplierConfiguration {\n\n\t\t@Bean\n\t\tJsonEncoderSupplier jacksonJsonEncoderSupplier(JsonMapper jsonMapper) {\n\t\t\treturn () -> new JacksonJsonEncoder(jsonMapper);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ObjectMapper.class)\n\t@Conditional(NoJacksonOrJackson2Preferred.class)\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tstatic class Jackson2JsonEncoderSupplierConfiguration {\n\n\t\t@Bean\n\t\tJsonEncoderSupplier jackson2JsonEncoderSupplier(ObjectMapper objectMapper) {\n\t\t\treturn () -> new org.springframework.http.codec.json.Jackson2JsonEncoder(objectMapper);\n\t\t}\n\n\t}\n\n\tstatic class NoJacksonOrJackson2Preferred extends AnyNestedCondition {\n\n\t\tNoJacksonOrJackson2Preferred() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnMissingClass(\"tools.jackson.databind.json.JsonMapper\")\n\t\tstatic class NoJackson {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = \"spring.graphql.rsocket.preferred-json-mapper\", havingValue = \"jackson2\")\n\t\tstatic class Jackson2Preferred {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/rsocket/GraphQlRSocketController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.rsocket;\n\nimport java.util.Map;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.graphql.server.GraphQlRSocketHandler;\nimport org.springframework.messaging.handler.annotation.MessageMapping;\nimport org.springframework.stereotype.Controller;\n\n@Controller\nclass GraphQlRSocketController {\n\n\tprivate final GraphQlRSocketHandler handler;\n\n\tGraphQlRSocketController(GraphQlRSocketHandler handler) {\n\t\tthis.handler = handler;\n\t}\n\n\t@MessageMapping(\"${spring.graphql.rsocket.mapping}\")\n\tMono<Map<String, Object>> handle(Map<String, Object> payload) {\n\t\treturn this.handler.handle(payload);\n\t}\n\n\t@MessageMapping(\"${spring.graphql.rsocket.mapping}\")\n\tFlux<Map<String, Object>> handleSubscription(Map<String, Object> payload) {\n\t\treturn this.handler.handleSubscription(payload);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/rsocket/RSocketGraphQlClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.rsocket;\n\nimport graphql.GraphQL;\nimport io.rsocket.RSocket;\nimport io.rsocket.transport.netty.client.TcpClientTransport;\n\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.graphql.client.RSocketGraphQlClient;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.util.MimeTypeUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link RSocketGraphQlClient}.\n * This auto-configuration creates\n * {@link org.springframework.graphql.client.RSocketGraphQlClient.Builder\n * RSocketGraphQlClient.Builder} prototype beans, as the builders are stateful and should\n * not be reused to build client instances with different configurations.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = \"org.springframework.boot.rsocket.autoconfigure.RSocketRequesterAutoConfiguration\")\n@ConditionalOnClass({ GraphQL.class, RSocketGraphQlClient.class, RSocketRequester.class, RSocket.class,\n\t\tTcpClientTransport.class })\npublic final class RSocketGraphQlClientAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnMissingBean\n\tRSocketGraphQlClient.Builder<?> rsocketGraphQlClientBuilder(RSocketRequester.Builder rsocketRequesterBuilder) {\n\t\treturn RSocketGraphQlClient.builder(rsocketRequesterBuilder.dataMimeType(MimeTypeUtils.APPLICATION_JSON));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/rsocket/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for RSocket integration with GraphQL.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure.rsocket;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/security/GraphQlWebFluxSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.security;\n\nimport graphql.GraphQL;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.graphql.autoconfigure.reactive.GraphQlWebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.graphql.execution.ReactiveSecurityDataFetcherExceptionResolver;\nimport org.springframework.graphql.server.webflux.GraphQlHttpHandler;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for enabling Security support for\n * Spring GraphQL with WebFlux.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = GraphQlWebFluxAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass({ GraphQL.class, GraphQlHttpHandler.class, EnableWebFluxSecurity.class })\n@ConditionalOnBean(GraphQlHttpHandler.class)\npublic final class GraphQlWebFluxSecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tReactiveSecurityDataFetcherExceptionResolver reactiveSecurityDataFetcherExceptionResolver() {\n\t\treturn new ReactiveSecurityDataFetcherExceptionResolver();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/security/GraphQlWebMvcSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.security;\n\nimport graphql.GraphQL;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.graphql.autoconfigure.servlet.GraphQlWebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.graphql.execution.SecurityDataFetcherExceptionResolver;\nimport org.springframework.graphql.server.webmvc.GraphQlHttpHandler;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for enabling Security support for\n * Spring GraphQL with MVC.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = GraphQlWebMvcAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ GraphQL.class, GraphQlHttpHandler.class, EnableWebSecurity.class })\n@ConditionalOnBean(GraphQlHttpHandler.class)\npublic final class GraphQlWebMvcSecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSecurityDataFetcherExceptionResolver securityDataFetcherExceptionResolver() {\n\t\treturn new SecurityDataFetcherExceptionResolver();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/security/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for Security support in Spring GraphQL.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure.security;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/servlet/GraphQlWebMvcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.servlet;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport graphql.GraphQL;\nimport jakarta.websocket.server.ServerContainer;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlCorsProperties;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlProperties;\nimport org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.server.WebGraphQlHandler;\nimport org.springframework.graphql.server.WebGraphQlInterceptor;\nimport org.springframework.graphql.server.webmvc.GraphQlHttpHandler;\nimport org.springframework.graphql.server.webmvc.GraphQlRequestPredicates;\nimport org.springframework.graphql.server.webmvc.GraphQlSseHandler;\nimport org.springframework.graphql.server.webmvc.GraphQlWebSocketHandler;\nimport org.springframework.graphql.server.webmvc.GraphiQlHandler;\nimport org.springframework.graphql.server.webmvc.SchemaHandler;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.util.Assert;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.servlet.HandlerMapping;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.function.RouterFunction;\nimport org.springframework.web.servlet.function.RouterFunctions;\nimport org.springframework.web.servlet.function.ServerRequest;\nimport org.springframework.web.servlet.function.ServerResponse;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.server.support.DefaultHandshakeHandler;\nimport org.springframework.web.socket.server.support.WebSocketHandlerMapping;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for enabling Spring GraphQL over\n * Spring MVC.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ GraphQL.class, GraphQlHttpHandler.class })\n@ConditionalOnBean(ExecutionGraphQlService.class)\n@EnableConfigurationProperties(GraphQlCorsProperties.class)\n@ImportRuntimeHints(GraphQlWebMvcAutoConfiguration.GraphiQlResourceHints.class)\npublic final class GraphQlWebMvcAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(GraphQlWebMvcAutoConfiguration.class);\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {\n\t\treturn new GraphQlHttpHandler(webGraphQlHandler);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphQlSseHandler graphQlSseHandler(WebGraphQlHandler webGraphQlHandler, GraphQlProperties properties) {\n\t\treturn new GraphQlSseHandler(webGraphQlHandler, properties.getHttp().getSse().getTimeout(),\n\t\t\t\tproperties.getHttp().getSse().getKeepAlive());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tWebGraphQlHandler webGraphQlHandler(ExecutionGraphQlService service,\n\t\t\tObjectProvider<WebGraphQlInterceptor> interceptors) {\n\t\treturn WebGraphQlHandler.builder(service).interceptors(interceptors.orderedStream().toList()).build();\n\t}\n\n\t@Bean\n\t@Order(0)\n\tRouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler httpHandler, GraphQlSseHandler sseHandler,\n\t\t\tObjectProvider<GraphQlSource> graphQlSourceProvider, GraphQlProperties properties) {\n\t\tString path = properties.getHttp().getPath();\n\t\tlogger.info(LogMessage.format(\"GraphQL endpoint HTTP POST %s\", path));\n\t\tRouterFunctions.Builder builder = RouterFunctions.route();\n\t\tbuilder.route(GraphQlRequestPredicates.graphQlHttp(path), httpHandler::handleRequest);\n\t\tbuilder.route(GraphQlRequestPredicates.graphQlSse(path), sseHandler::handleRequest);\n\t\tbuilder.POST(path, this::unsupportedMediaType);\n\t\tbuilder.GET(path, this::onlyAllowPost);\n\t\tif (properties.getGraphiql().isEnabled()) {\n\t\t\tGraphiQlHandler graphiQLHandler = createGraphiQLHandler(properties, path);\n\t\t\tbuilder.GET(properties.getGraphiql().getPath(), graphiQLHandler::handleRequest);\n\t\t}\n\t\tGraphQlSource graphQlSource = graphQlSourceProvider.getIfAvailable();\n\t\tif (properties.getSchema().getPrinter().isEnabled() && graphQlSource != null) {\n\t\t\tSchemaHandler schemaHandler = new SchemaHandler(graphQlSource);\n\t\t\tbuilder.GET(path + \"/schema\", schemaHandler::handleRequest);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\tprivate GraphiQlHandler createGraphiQLHandler(GraphQlProperties properties, String path) {\n\t\treturn new GraphiQlHandler(path, properties.getWebsocket().getPath());\n\t}\n\n\tprivate ServerResponse unsupportedMediaType(ServerRequest request) {\n\t\treturn ServerResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).headers(this::acceptJson).build();\n\t}\n\n\tprivate void acceptJson(HttpHeaders headers) {\n\t\theaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));\n\t}\n\n\tprivate ServerResponse onlyAllowPost(ServerRequest request) {\n\t\treturn ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).headers(this::onlyAllowPost).build();\n\t}\n\n\tprivate void onlyAllowPost(HttpHeaders headers) {\n\t\theaders.setAllow(Collections.singleton(HttpMethod.POST));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GraphQlEndpointCorsConfiguration implements WebMvcConfigurer {\n\n\t\tfinal GraphQlProperties graphQlProperties;\n\n\t\tfinal GraphQlCorsProperties corsProperties;\n\n\t\tGraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlCorsProperties corsProps) {\n\t\t\tthis.graphQlProperties = graphQlProps;\n\t\t\tthis.corsProperties = corsProps;\n\t\t}\n\n\t\t@Override\n\t\tpublic void addCorsMappings(CorsRegistry registry) {\n\t\t\tCorsConfiguration configuration = this.corsProperties.toCorsConfiguration();\n\t\t\tif (configuration != null) {\n\t\t\t\tregistry.addMapping(this.graphQlProperties.getHttp().getPath()).combine(configuration);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ HttpMessageConverter.class, ServerContainer.class, WebSocketHandler.class })\n\t@ConditionalOnProperty(\"spring.graphql.websocket.path\")\n\tstatic class WebSocketConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tGraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,\n\t\t\t\tGraphQlProperties properties, ObjectProvider<ServerHttpMessageConvertersCustomizer> customizers) {\n\t\t\treturn new GraphQlWebSocketHandler(webGraphQlHandler, getJsonConverter(customizers),\n\t\t\t\t\tproperties.getWebsocket().getConnectionInitTimeout(), properties.getWebsocket().getKeepAlive());\n\t\t}\n\n\t\tprivate HttpMessageConverter<Object> getJsonConverter(\n\t\t\t\tObjectProvider<ServerHttpMessageConvertersCustomizer> customizers) {\n\t\t\tServerBuilder serverBuilder = HttpMessageConverters.forServer().registerDefaults();\n\t\t\tcustomizers.forEach((customizer) -> customizer.customize(serverBuilder));\n\t\t\tfor (HttpMessageConverter<?> converter : serverBuilder.build()) {\n\t\t\t\tif (canReadJsonMap(converter)) {\n\t\t\t\t\treturn asObjectHttpMessageConverter(converter);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"No JSON converter\");\n\t\t}\n\n\t\tprivate boolean canReadJsonMap(HttpMessageConverter<?> candidate) {\n\t\t\treturn candidate.canRead(Map.class, MediaType.APPLICATION_JSON);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate HttpMessageConverter<Object> asObjectHttpMessageConverter(HttpMessageConverter<?> converter) {\n\t\t\treturn (HttpMessageConverter<Object>) converter;\n\t\t}\n\n\t\t@Bean\n\t\tHandlerMapping graphQlWebSocketMapping(GraphQlWebSocketHandler handler, GraphQlProperties properties) {\n\t\t\tString path = properties.getWebsocket().getPath();\n\t\t\tAssert.state(path != null, \"'path' must not be null\");\n\t\t\tlogger.info(LogMessage.format(\"GraphQL endpoint WebSocket %s\", path));\n\t\t\tWebSocketHandlerMapping mapping = new WebSocketHandlerMapping();\n\t\t\tmapping.setWebSocketUpgradeMatch(true);\n\t\t\tmapping.setUrlMap(Collections.singletonMap(path,\n\t\t\t\t\thandler.initWebSocketHttpRequestHandler(new DefaultHandshakeHandler())));\n\t\t\tmapping.setOrder(-2); // Ahead of HTTP endpoint (\"routerFunctionMapping\" bean)\n\t\t\treturn mapping;\n\t\t}\n\n\t}\n\n\tstatic class GraphiQlResourceHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"graphiql/index.html\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/java/org/springframework/boot/graphql/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for MVC support in Spring GraphQL.\n */\n@NullMarked\npackage org.springframework.boot.graphql.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.metrics.graphql.autotime.enabled\",\n      \"description\": \"Whether to automatically time web client requests.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Requests are timed automatically.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.graphql.autotime.percentiles\",\n      \"description\": \"Computed non-aggregable percentiles to publish.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Should be configured globally via management.metrics.distribution.percentiles.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.graphql.autotime.percentiles-histogram\",\n      \"description\": \"Whether percentile histograms should be published.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Should be configured globally via management.metrics.distribution.percentiles-histogram.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.graphql.path\",\n      \"type\": \"java.lang.String\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.graphql.http.path\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.graphql.rsocket.preferred-json-mapper\",\n      \"type\": \"java.lang.String\",\n      \"defaultValue\": \"jackson\",\n      \"description\": \"Preferred JSON mapper to use. By default, auto-detected according to the environment. Supported values are 'jackson' and 'jackson2' (deprecated).\"\n    },\n    {\n      \"name\": \"spring.graphql.schema.file-extensions\",\n      \"defaultValue\": \".graphqls,.gqls\"\n    },\n    {\n      \"name\": \"spring.graphql.schema.locations\",\n      \"defaultValue\": \"classpath:graphql/**/\"\n    },\n    {\n      \"name\": \"spring.graphql.sse.timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.graphql.http.sse.timeout\",\n        \"since\": \"3.5.0\"\n      }\n    }\n  ],\n  \"hints\": [\n  {\n    \"name\": \"spring.graphql.cors.allowed-headers\",\n      \"values\": [\n        {\n          \"value\": \"*\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.graphql.cors.allowed-methods\",\n      \"values\": [\n        {\n          \"value\": \"*\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.graphql.cors.allowed-origins\",\n      \"values\": [\n        {\n          \"value\": \"*\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.graphql.rsocket.preferred-json-mapper\",\n      \"values\": [\n        {\n          \"value\": \"jackson\"\n        },\n        {\n          \"value\": \"jackson2\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.data.GraphQlQueryByExampleAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.data.GraphQlQuerydslAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.data.GraphQlReactiveQueryByExampleAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.data.GraphQlReactiveQuerydslAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.observation.GraphQlObservationAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.reactive.GraphQlWebFluxAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.rsocket.GraphQlRSocketAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.rsocket.RSocketGraphQlClientAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.security.GraphQlWebFluxSecurityAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.security.GraphQlWebMvcSecurityAutoConfiguration\norg.springframework.boot.graphql.autoconfigure.servlet.GraphQlWebMvcAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-graphql/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.graphql.graphiql.enabled=true\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/Book.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport org.springframework.data.annotation.Id;\n\n/**\n * Sample class for\n *\n * @author Brian Clozel\n */\npublic class Book {\n\n\t@Id\n\t@SuppressWarnings(\"NullAway.Init\")\n\tString id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tString name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tint pageCount;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tString author;\n\n\tprotected Book() {\n\t}\n\n\tpublic Book(String id, String name, int pageCount, String author) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.pageCount = pageCount;\n\t\tthis.author = author;\n\t}\n\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getPageCount() {\n\t\treturn this.pageCount;\n\t}\n\n\tpublic void setPageCount(int pageCount) {\n\t\tthis.pageCount = pageCount;\n\t}\n\n\tpublic String getAuthor() {\n\t\treturn this.author;\n\t}\n\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/DefaultGraphQlSchemaConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnGraphQlSchema}.\n *\n * @author Brian Clozel\n */\nclass DefaultGraphQlSchemaConditionTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\t@WithResource(name = \"graphql/one.graphqls\")\n\t@WithResource(name = \"graphql/two.graphqls\")\n\tvoid matchesWhenSchemaFilesAreDetected() {\n\t\tthis.contextRunner.withUserConfiguration(TestingConfiguration.class).run((context) -> {\n\t\t\tdidMatch(context);\n\t\t\tassertThat(conditionReportMessage(context)).contains(\"@ConditionalOnGraphQlSchema found schemas\")\n\t\t\t\t.contains(\"@ConditionalOnGraphQlSchema did not find GraphQlSourceBuilderCustomizer\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid matchesWhenCustomizerIsDetected() {\n\t\tthis.contextRunner.withUserConfiguration(CustomCustomizerConfiguration.class, TestingConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.graphql.schema.locations=classpath:graphql/missing\")\n\t\t\t.run((context) -> {\n\t\t\t\tdidMatch(context);\n\t\t\t\tassertThat(conditionReportMessage(context)).contains(\n\t\t\t\t\t\t\"@ConditionalOnGraphQlSchema did not find schema files in locations 'classpath:graphql/missing/'\")\n\t\t\t\t\t.contains(\"@ConditionalOnGraphQlSchema found customizer myBuilderCustomizer\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotMatchWhenBothAreMissing() {\n\t\tthis.contextRunner.withUserConfiguration(TestingConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.graphql.schema.locations=classpath:graphql/missing\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"success\");\n\t\t\t\tassertThat(conditionReportMessage(context)).contains(\n\t\t\t\t\t\t\"@ConditionalOnGraphQlSchema did not find schema files in locations 'classpath:graphql/missing/'\")\n\t\t\t\t\t.contains(\"@ConditionalOnGraphQlSchema did not find GraphQlSourceBuilderCustomizer\");\n\t\t\t});\n\t}\n\n\tprivate void didMatch(AssertableApplicationContext context) {\n\t\tassertThat(context).hasBean(\"success\");\n\t\tassertThat(context.getBean(\"success\")).isEqualTo(\"success\");\n\t}\n\n\tprivate @Nullable String conditionReportMessage(AssertableApplicationContext context) {\n\t\tCollection<ConditionEvaluationReport.ConditionAndOutcomes> conditionAndOutcomes = ConditionEvaluationReport\n\t\t\t.get(context.getSourceApplicationContext().getBeanFactory())\n\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t.values();\n\t\treturn conditionAndOutcomes.iterator().next().iterator().next().getOutcome().getMessage();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnGraphQlSchema\n\tstatic class TestingConfiguration {\n\n\t\t@Bean\n\t\tString success() {\n\t\t\treturn \"success\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomCustomizerConfiguration {\n\n\t\t@Bean\n\t\tGraphQlSourceBuilderCustomizer myBuilderCustomizer() {\n\t\t\treturn (builder) -> {\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/GraphQlAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.Executor;\n\nimport graphql.GraphQL;\nimport graphql.execution.instrumentation.ChainedInstrumentation;\nimport graphql.execution.instrumentation.Instrumentation;\nimport graphql.introspection.Introspection;\nimport graphql.schema.GraphQLObjectType;\nimport graphql.schema.GraphQLOutputType;\nimport graphql.schema.GraphQLSchema;\nimport graphql.schema.idl.RuntimeWiring;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration.GraphQlResourcesRuntimeHints;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.method.HandlerMethodArgumentResolver;\nimport org.springframework.graphql.data.method.annotation.support.AnnotatedControllerConfigurer;\nimport org.springframework.graphql.data.pagination.EncodingCursorStrategy;\nimport org.springframework.graphql.execution.BatchLoaderRegistry;\nimport org.springframework.graphql.execution.DataFetcherExceptionResolver;\nimport org.springframework.graphql.execution.DataLoaderRegistrar;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlAutoConfiguration}.\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\n@ExtendWith(OutputCaptureExtension.class)\nclass GraphQlAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GraphQlAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldContributeDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GraphQlSource.class)\n\t\t\t.hasSingleBean(BatchLoaderRegistry.class)\n\t\t\t.hasSingleBean(ExecutionGraphQlService.class)\n\t\t\t.hasSingleBean(AnnotatedControllerConfigurer.class)\n\t\t\t.hasSingleBean(EncodingCursorStrategy.class));\n\t}\n\n\t@Test\n\tvoid schemaShouldScanNestedFolders() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GraphQlSource.class);\n\t\t\tGraphQlSource graphQlSource = context.getBean(GraphQlSource.class);\n\t\t\tGraphQLSchema schema = graphQlSource.schema();\n\t\t\tassertThat(schema.getObjectType(\"Book\")).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackoffWhenSchemaFileIsMissing() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.schema.locations:classpath:missing/\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed().doesNotHaveBean(GraphQlSource.class));\n\t}\n\n\t@Test\n\tvoid shouldUseProgrammaticallyDefinedBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGraphQlBuilderConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customGraphQlSourceBuilder\");\n\t\t\tassertThat(context).hasSingleBean(GraphQlSource.Builder.class);\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"graphql/types/person.custom\", content = \"\"\"\n\t\t\ttype Person {\n\t\t\t    id: ID\n\t\t\t    name: String\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid shouldScanLocationsWithCustomExtension() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.schema.file-extensions:.graphqls,.custom\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GraphQlSource.class);\n\t\t\t\tGraphQlSource graphQlSource = context.getBean(GraphQlSource.class);\n\t\t\t\tGraphQLSchema schema = graphQlSource.schema();\n\t\t\t\tassertThat(schema.getObjectType(\"Book\")).isNotNull();\n\t\t\t\tassertThat(schema.getObjectType(\"Person\")).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"graphql/types/person.custom\", content = \"\"\"\n\t\t\ttype Person {\n\t\t\t    id: ID\n\t\t\t    name: String\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid shouldConfigureAdditionalSchemaFiles() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.graphql.schema.additional-files=classpath:graphql/types/person.custom\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GraphQlSource.class);\n\t\t\t\tGraphQlSource graphQlSource = context.getBean(GraphQlSource.class);\n\t\t\t\tGraphQLSchema schema = graphQlSource.schema();\n\t\t\t\tassertThat(schema.getObjectType(\"Book\")).isNotNull();\n\t\t\t\tassertThat(schema.getObjectType(\"Person\")).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomGraphQlSource() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGraphQlSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).getBeanNames(GraphQlSource.class).containsOnly(\"customGraphQlSource\");\n\t\t\tassertThat(context).hasSingleBean(GraphQlProperties.class)\n\t\t\t\t.hasSingleBean(BatchLoaderRegistry.class)\n\t\t\t\t.hasSingleBean(ExecutionGraphQlService.class)\n\t\t\t\t.hasSingleBean(AnnotatedControllerConfigurer.class)\n\t\t\t\t.hasSingleBean(EncodingCursorStrategy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureDataFetcherExceptionResolvers() {\n\t\tthis.contextRunner.withUserConfiguration(DataFetcherExceptionResolverConfiguration.class).run((context) -> {\n\t\t\tGraphQlSource graphQlSource = context.getBean(GraphQlSource.class);\n\t\t\tGraphQL graphQL = graphQlSource.graphQl();\n\t\t\tassertThat(graphQL.getQueryStrategy()).extracting(\"dataFetcherExceptionHandler\")\n\t\t\t\t.satisfies((exceptionHandler) -> {\n\t\t\t\t\tassertThat(exceptionHandler.getClass().getName()).endsWith(\"ExceptionResolversExceptionHandler\");\n\t\t\t\t\tassertThat(exceptionHandler).extracting(\"resolvers\")\n\t\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t\t.hasSize(2);\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureInstrumentation() {\n\t\tthis.contextRunner.withUserConfiguration(InstrumentationConfiguration.class).run((context) -> {\n\t\t\tGraphQlSource graphQlSource = context.getBean(GraphQlSource.class);\n\t\t\tInstrumentation customInstrumentation = context.getBean(\"customInstrumentation\", Instrumentation.class);\n\t\t\tGraphQL graphQL = graphQlSource.graphQl();\n\t\t\tassertThat(graphQL).extracting(\"instrumentation\")\n\t\t\t\t.isInstanceOf(ChainedInstrumentation.class)\n\t\t\t\t.extracting(\"instrumentations\", InstanceOfAssertFactories.iterable(Instrumentation.class))\n\t\t\t\t.contains(customInstrumentation);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldApplyRuntimeWiringConfigurers() {\n\t\tthis.contextRunner.withUserConfiguration(RuntimeWiringConfigurerConfiguration.class).run((context) -> {\n\t\t\tRuntimeWiringConfigurerConfiguration.CustomRuntimeWiringConfigurer configurer = context\n\t\t\t\t.getBean(RuntimeWiringConfigurerConfiguration.CustomRuntimeWiringConfigurer.class);\n\t\t\tassertThat(configurer.applied).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldApplyGraphQlSourceBuilderCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(GraphQlSourceBuilderCustomizerConfiguration.class).run((context) -> {\n\t\t\tGraphQlSourceBuilderCustomizerConfiguration.CustomGraphQlSourceBuilderCustomizer customizer = context\n\t\t\t\t.getBean(GraphQlSourceBuilderCustomizerConfiguration.CustomGraphQlSourceBuilderCustomizer.class);\n\t\t\tassertThat(customizer.applied).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid schemaInspectionShouldBeEnabledByDefault(CapturedOutput output) {\n\t\tthis.contextRunner.run((context) -> assertThat(output).contains(\"GraphQL schema inspection\"));\n\t}\n\n\t@Test\n\tvoid fieldIntrospectionShouldBeEnabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(Introspection.isEnabledJvmWide()).isTrue());\n\t}\n\n\t@Test\n\tvoid shouldDisableFieldIntrospection() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.schema.introspection.enabled:false\")\n\t\t\t.run((context) -> assertThat(Introspection.isEnabledJvmWide()).isFalse());\n\t}\n\n\t@Test\n\tvoid shouldConfigureCustomBatchLoaderRegistry() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customBatchLoaderRegistry\", BatchLoaderRegistry.class, () -> mock(BatchLoaderRegistry.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(BatchLoaderRegistry.class);\n\t\t\t\tassertThat(context.getBean(\"customBatchLoaderRegistry\"))\n\t\t\t\t\t.isSameAs(context.getBean(BatchLoaderRegistry.class));\n\t\t\t\tassertThat(context.getBean(ExecutionGraphQlService.class))\n\t\t\t\t\t.extracting(\"dataLoaderRegistrars\", InstanceOfAssertFactories.list(DataLoaderRegistrar.class))\n\t\t\t\t\t.containsOnly(context.getBean(BatchLoaderRegistry.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew GraphQlResourcesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"graphql/sample/schema.gqls\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"graphql/other.graphqls\")).accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldContributeConnectionTypeDefinitionConfigurer() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGraphQlBuilderConfiguration.class).run((context) -> {\n\t\t\tGraphQlSource graphQlSource = context.getBean(GraphQlSource.class);\n\t\t\tGraphQLSchema schema = graphQlSource.schema();\n\t\t\tGraphQLOutputType bookConnection = schema.getQueryType().getField(\"books\").getType();\n\t\t\tassertThat(bookConnection).isInstanceOf(GraphQLObjectType.class);\n\t\t\tassertThat((GraphQLObjectType) bookConnection)\n\t\t\t\t.satisfies((connection) -> assertThat(connection.getFieldDefinition(\"edges\")).isNotNull());\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenApplicationTaskExecutorIsDefinedThenAnnotatedControllerConfigurerShouldUseIt() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tAnnotatedControllerConfigurer annotatedControllerConfigurer = context\n\t\t\t\t\t.getBean(AnnotatedControllerConfigurer.class);\n\t\t\t\tassertThat(annotatedControllerConfigurer).extracting(\"executor\")\n\t\t\t\t\t.isSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomExecutorIsDefinedThenAnnotatedControllerConfigurerDoesNotUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(CustomExecutorConfiguration.class).run((context) -> {\n\t\t\tAnnotatedControllerConfigurer annotatedControllerConfigurer = context\n\t\t\t\t.getBean(AnnotatedControllerConfigurer.class);\n\t\t\tassertThat(annotatedControllerConfigurer).extracting(\"executor\").isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenAHandlerMethodArgumentResolverIsDefinedThenAnnotatedControllerConfigurerShouldUseIt() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHandlerMethodArgumentResolverConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(AnnotatedControllerConfigurer.class))\n\t\t\t\t.extracting(\"customArgumentResolvers\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.hasSize(1));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomGraphQlBuilderConfiguration {\n\n\t\t@Bean\n\t\tGraphQlSource.SchemaResourceBuilder customGraphQlSourceBuilder() {\n\t\t\treturn GraphQlSource.schemaResourceBuilder()\n\t\t\t\t.schemaResources(new ClassPathResource(\"graphql/schema.graphqls\"),\n\t\t\t\t\t\tnew ClassPathResource(\"graphql/types/book.graphqls\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomGraphQlSourceConfiguration {\n\n\t\t@Bean\n\t\tGraphQlSource customGraphQlSource() {\n\t\t\tByteArrayResource schemaResource = new ByteArrayResource(\n\t\t\t\t\t\"type Query { greeting: String }\".getBytes(StandardCharsets.UTF_8));\n\t\t\treturn GraphQlSource.schemaResourceBuilder().schemaResources(schemaResource).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataFetcherExceptionResolverConfiguration {\n\n\t\t@Bean\n\t\tDataFetcherExceptionResolver customDataFetcherExceptionResolver() {\n\t\t\treturn mock(DataFetcherExceptionResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class InstrumentationConfiguration {\n\n\t\t@Bean\n\t\tInstrumentation customInstrumentation() {\n\t\t\treturn mock(Instrumentation.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RuntimeWiringConfigurerConfiguration {\n\n\t\t@Bean\n\t\tCustomRuntimeWiringConfigurer customRuntimeWiringConfigurer() {\n\t\t\treturn new CustomRuntimeWiringConfigurer();\n\t\t}\n\n\t\tpublic static class CustomRuntimeWiringConfigurer implements RuntimeWiringConfigurer {\n\n\t\t\tpublic boolean applied;\n\n\t\t\t@Override\n\t\t\tpublic void configure(RuntimeWiring.Builder builder) {\n\t\t\t\tthis.applied = true;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class GraphQlSourceBuilderCustomizerConfiguration {\n\n\t\t@Bean\n\t\tCustomGraphQlSourceBuilderCustomizer customGraphQlSourceBuilderCustomizer() {\n\t\t\treturn new CustomGraphQlSourceBuilderCustomizer();\n\t\t}\n\n\t\tpublic static class CustomGraphQlSourceBuilderCustomizer implements GraphQlSourceBuilderCustomizer {\n\n\t\t\tpublic boolean applied;\n\n\t\t\t@Override\n\t\t\tpublic void customize(GraphQlSource.SchemaResourceBuilder builder) {\n\t\t\t\tthis.applied = true;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomExecutorConfiguration {\n\n\t\t@Bean\n\t\tExecutor customExecutor() {\n\t\t\treturn mock(Executor.class);\n\t\t}\n\n\t}\n\n\tstatic class CustomHandlerMethodArgumentResolverConfiguration {\n\n\t\t@Bean\n\t\tHandlerMethodArgumentResolver customHandlerMethodArgumentResolver() {\n\t\t\treturn mock(HandlerMethodArgumentResolver.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/GraphQlTestDataFetchers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport graphql.schema.DataFetcher;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test utility class holding {@link DataFetcher} implementations.\n *\n * @author Brian Clozel\n */\npublic final class GraphQlTestDataFetchers {\n\n\tprivate static final List<Book> books = Arrays.asList(\n\t\t\tnew Book(\"book-1\", \"GraphQL for beginners\", 100, \"John GraphQL\"),\n\t\t\tnew Book(\"book-2\", \"Harry Potter and the Philosopher's Stone\", 223, \"Joanne Rowling\"),\n\t\t\tnew Book(\"book-3\", \"Moby Dick\", 635, \"Moby Dick\"), new Book(\"book-3\", \"Moby Dick\", 635, \"Moby Dick\"));\n\n\tprivate GraphQlTestDataFetchers() {\n\n\t}\n\n\tpublic static DataFetcher<Book> getBookByIdDataFetcher() {\n\t\treturn (environment) -> {\n\t\t\tString id = environment.getArgument(\"id\");\n\t\t\tassertThat(id).isNotNull();\n\t\t\treturn getBookById(id);\n\t\t};\n\t}\n\n\tpublic static DataFetcher<Flux<Book>> getBooksOnSaleDataFetcher() {\n\t\treturn (environment) -> {\n\t\t\tInteger minPages = environment.getArgument(\"minPages\");\n\t\t\tassertThat(minPages).isNotNull();\n\t\t\treturn getBooksOnSale(minPages);\n\t\t};\n\t}\n\n\tpublic static @Nullable Book getBookById(String id) {\n\t\treturn books.stream().filter((book) -> book.getId().equals(id)).findFirst().orElse(null);\n\t}\n\n\tpublic static Flux<Book> getBooksOnSale(int minPages) {\n\t\treturn Flux.fromIterable(books).filter((book) -> book.getPageCount() >= minPages);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/QBook.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure;\n\nimport com.querydsl.core.types.Path;\nimport com.querydsl.core.types.PathMetadata;\nimport com.querydsl.core.types.PathMetadataFactory;\nimport com.querydsl.core.types.dsl.EntityPathBase;\nimport com.querydsl.core.types.dsl.NumberPath;\nimport com.querydsl.core.types.dsl.StringPath;\n\n/**\n * QBook is a Querydsl query type for Book. This class is usually generated by the\n * Querydsl annotation processor.\n */\npublic class QBook extends EntityPathBase<Book> {\n\n\tprivate static final long serialVersionUID = -1932588188L;\n\n\tpublic static final QBook book = new QBook(\"book\");\n\n\tpublic final StringPath author = createString(\"author\");\n\n\tpublic final StringPath id = createString(\"id\");\n\n\tpublic final StringPath name = createString(\"name\");\n\n\tpublic final NumberPath<Integer> pageCount = createNumber(\"pageCount\", Integer.class);\n\n\tpublic QBook(String variable) {\n\t\tsuper(Book.class, PathMetadataFactory.forVariable(variable));\n\t}\n\n\tpublic QBook(Path<? extends Book> path) {\n\t\tsuper(path.getType(), path.getMetadata());\n\t}\n\n\tpublic QBook(PathMetadata metadata) {\n\t\tsuper(Book.class, metadata);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlQueryByExampleAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport java.util.Optional;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.Book;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.QueryByExampleExecutor;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.GraphQlRepository;\nimport org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlQueryByExampleAutoConfiguration}\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlQueryByExampleAutoConfigurationTests {\n\n\tprivate static final Book book = new Book(\"42\", \"Test title\", 42, \"Test Author\");\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(GraphQlAutoConfiguration.class, GraphQlQueryByExampleAutoConfiguration.class))\n\t\t.withUserConfiguration(MockRepositoryConfig.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=servlet\");\n\n\tvoid shouldRegisterDataFetcherForQueryByExampleRepositories() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tExecutionGraphQlService graphQlService = context.getBean(ExecutionGraphQlService.class);\n\t\t\tExecutionGraphQlServiceTester graphQlTester = ExecutionGraphQlServiceTester.create(graphQlService);\n\t\t\tgraphQlTester.document(\"{ bookById(id: 1) {name}}\")\n\t\t\t\t.execute()\n\t\t\t\t.path(\"bookById.name\")\n\t\t\t\t.entity(String.class)\n\t\t\t\t.isEqualTo(\"Test title\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockRepositoryConfig {\n\n\t\t@Bean\n\t\tMockRepository mockRepository() {\n\t\t\tMockRepository mockRepository = mock(MockRepository.class);\n\t\t\tgiven(mockRepository.findBy(any(), any())).willReturn(Optional.of(book));\n\t\t\treturn mockRepository;\n\t\t}\n\n\t}\n\n\t@GraphQlRepository\n\tinterface MockRepository extends CrudRepository<Book, Long>, QueryByExampleExecutor<Book> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlQuerydslAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.Book;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.querydsl.QuerydslPredicateExecutor;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.GraphQlRepository;\nimport org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlQuerydslAutoConfiguration}.\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlQuerydslAutoConfigurationTests {\n\n\tprivate static final Book book = new Book(\"42\", \"Test title\", 42, \"Test Author\");\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(GraphQlAutoConfiguration.class, GraphQlQuerydslAutoConfiguration.class))\n\t\t.withUserConfiguration(MockRepositoryConfig.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=servlet\");\n\n\t@Test\n\tvoid shouldRegisterDataFetcherForQueryDslRepositories() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tExecutionGraphQlService graphQlService = context.getBean(ExecutionGraphQlService.class);\n\t\t\tGraphQlTester graphQlTester = ExecutionGraphQlServiceTester.create(graphQlService);\n\t\t\tgraphQlTester.document(\"{ bookById(id: 1) {name}}\")\n\t\t\t\t.execute()\n\t\t\t\t.path(\"bookById.name\")\n\t\t\t\t.entity(String.class)\n\t\t\t\t.isEqualTo(\"Test title\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffWithoutQueryDsl() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"com.querydsl.core\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"querydslRegistrar\")\n\t\t\t\t.doesNotHaveBean(GraphQlQuerydslAutoConfiguration.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockRepositoryConfig {\n\n\t\t@Bean\n\t\tMockRepository mockRepository() {\n\t\t\tMockRepository mockRepository = mock(MockRepository.class);\n\t\t\tgiven(mockRepository.findBy(any(), any())).willReturn(Optional.of(book));\n\t\t\treturn mockRepository;\n\t\t}\n\n\t}\n\n\t@GraphQlRepository\n\tinterface MockRepository extends CrudRepository<Book, Long>, QuerydslPredicateExecutor<Book> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlReactiveQueryByExampleAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.Book;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.GraphQlRepository;\nimport org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlReactiveQueryByExampleAutoConfiguration}\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlReactiveQueryByExampleAutoConfigurationTests {\n\n\tprivate static final Mono<Book> bookPublisher = Mono.just(new Book(\"42\", \"Test title\", 42, \"Test Author\"));\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GraphQlAutoConfiguration.class,\n\t\t\t\tGraphQlReactiveQueryByExampleAutoConfiguration.class))\n\t\t.withUserConfiguration(MockRepositoryConfig.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\");\n\n\t@Test\n\tvoid shouldRegisterDataFetcherForQueryByExampleRepositories() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tExecutionGraphQlService graphQlService = context.getBean(ExecutionGraphQlService.class);\n\t\t\tGraphQlTester graphQlTester = ExecutionGraphQlServiceTester.create(graphQlService);\n\t\t\tgraphQlTester.document(\"{ bookById(id: 1) {name}}\")\n\t\t\t\t.execute()\n\t\t\t\t.path(\"bookById.name\")\n\t\t\t\t.entity(String.class)\n\t\t\t\t.isEqualTo(\"Test title\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockRepositoryConfig {\n\n\t\t@Bean\n\t\tMockRepository mockRepository() {\n\t\t\tMockRepository mockRepository = mock(MockRepository.class);\n\t\t\tgiven(mockRepository.findBy(any(), any())).willReturn(bookPublisher);\n\t\t\treturn mockRepository;\n\t\t}\n\n\t}\n\n\t@GraphQlRepository\n\tinterface MockRepository extends ReactiveCrudRepository<Book, Long>, ReactiveQueryByExampleExecutor<Book> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/data/GraphQlReactiveQuerydslAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.data;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.Book;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.querydsl.ReactiveQuerydslPredicateExecutor;\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.data.GraphQlRepository;\nimport org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlReactiveQuerydslAutoConfiguration}\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlReactiveQuerydslAutoConfigurationTests {\n\n\tprivate static final Mono<Book> bookPublisher = Mono.just(new Book(\"42\", \"Test title\", 42, \"Test Author\"));\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(GraphQlAutoConfiguration.class, GraphQlReactiveQuerydslAutoConfiguration.class))\n\t\t.withUserConfiguration(MockRepositoryConfig.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\");\n\n\t@Test\n\tvoid shouldRegisterDataFetcherForQueryDslRepositories() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tExecutionGraphQlService graphQlService = context.getBean(ExecutionGraphQlService.class);\n\t\t\tGraphQlTester graphQlTester = ExecutionGraphQlServiceTester.create(graphQlService);\n\t\t\tgraphQlTester.document(\"{ bookById(id: 1) {name}}\")\n\t\t\t\t.execute()\n\t\t\t\t.path(\"bookById.name\")\n\t\t\t\t.entity(String.class)\n\t\t\t\t.isEqualTo(\"Test title\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffWithoutQueryDsl() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"com.querydsl.core\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"querydslRegistrar\")\n\t\t\t\t.doesNotHaveBean(GraphQlReactiveQuerydslAutoConfiguration.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockRepositoryConfig {\n\n\t\t@Bean\n\t\tMockRepository mockRepository() {\n\t\t\tMockRepository mockRepository = mock(MockRepository.class);\n\t\t\tgiven(mockRepository.findBy(any(), any())).willReturn(bookPublisher);\n\t\t\treturn mockRepository;\n\t\t}\n\n\t}\n\n\t@GraphQlRepository\n\tinterface MockRepository extends ReactiveCrudRepository<Book, Long>, ReactiveQuerydslPredicateExecutor<Book> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/observation/GraphQlObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.graphql.observation.DefaultDataFetcherObservationConvention;\nimport org.springframework.graphql.observation.DefaultDataLoaderObservationConvention;\nimport org.springframework.graphql.observation.DefaultExecutionRequestObservationConvention;\nimport org.springframework.graphql.observation.GraphQlObservationInstrumentation;\nimport org.springframework.graphql.server.WebGraphQlHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlObservationAutoConfiguration}.\n *\n * @author Brian Clozel\n */\nclass GraphQlObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(TestObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(GraphQlObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWhenObservationRegistryIsMissing() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(GraphQlObservationAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GraphQlObservationInstrumentation.class));\n\t}\n\n\t@Test\n\tvoid definesInstrumentationWhenObservationRegistryIsPresent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GraphQlObservationInstrumentation.class));\n\t}\n\n\t@Test\n\tvoid instrumentationBacksOffIfAlreadyPresent() {\n\t\tthis.contextRunner.withUserConfiguration(InstrumentationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GraphQlObservationInstrumentation.class)\n\t\t\t\t.hasBean(\"customInstrumentation\"));\n\t}\n\n\t@Test\n\tvoid instrumentationUsesCustomConventionsIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConventionsConfiguration.class).run((context) -> {\n\t\t\tGraphQlObservationInstrumentation instrumentation = context\n\t\t\t\t.getBean(GraphQlObservationInstrumentation.class);\n\t\t\tassertThat(instrumentation).extracting(\"requestObservationConvention\")\n\t\t\t\t.isInstanceOf(CustomExecutionRequestObservationConvention.class);\n\t\t\tassertThat(instrumentation).extracting(\"dataFetcherObservationConvention\")\n\t\t\t\t.isInstanceOf(CustomDataFetcherObservationConvention.class);\n\t\t\tassertThat(instrumentation).extracting(\"dataLoaderObservationConvention\")\n\t\t\t\t.isInstanceOf(CustomDataLoaderObservationConvention.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class InstrumentationConfiguration {\n\n\t\t@Bean\n\t\tGraphQlObservationInstrumentation customInstrumentation(ObservationRegistry registry) {\n\t\t\treturn new GraphQlObservationInstrumentation(registry);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConventionsConfiguration {\n\n\t\t@Bean\n\t\tCustomExecutionRequestObservationConvention customExecutionConvention() {\n\t\t\treturn new CustomExecutionRequestObservationConvention();\n\t\t}\n\n\t\t@Bean\n\t\tCustomDataFetcherObservationConvention customDataFetcherConvention() {\n\t\t\treturn new CustomDataFetcherObservationConvention();\n\t\t}\n\n\t\t@Bean\n\t\tCustomDataLoaderObservationConvention customDataLoaderConvention() {\n\t\t\treturn new CustomDataLoaderObservationConvention();\n\t\t}\n\n\t}\n\n\tstatic class CustomExecutionRequestObservationConvention extends DefaultExecutionRequestObservationConvention {\n\n\t}\n\n\tstatic class CustomDataFetcherObservationConvention extends DefaultDataFetcherObservationConvention {\n\n\t}\n\n\tstatic class CustomDataLoaderObservationConvention extends DefaultDataLoaderObservationConvention {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebGraphQlConfiguration {\n\n\t\t@Bean\n\t\tWebGraphQlHandler webGraphQlHandler() {\n\t\t\treturn mock(WebGraphQlHandler.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/reactive/GraphQlWebFluxAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.reactive;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport graphql.schema.idl.TypeRuntimeWiring;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.graphql.server.WebGraphQlHandler;\nimport org.springframework.graphql.server.WebGraphQlInterceptor;\nimport org.springframework.graphql.server.webflux.GraphQlHttpHandler;\nimport org.springframework.graphql.server.webflux.GraphQlSseHandler;\nimport org.springframework.graphql.server.webflux.GraphQlWebSocketHandler;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.EntityExchangeResult;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.function.server.RouterFunction;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraphQlWebFluxAutoConfiguration}\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlWebFluxAutoConfigurationTests {\n\n\tprivate static final String BASE_URL = \"https://spring.example.org/\";\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,\n\t\t\t\tCodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,\n\t\t\t\tGraphQlWebFluxAutoConfiguration.class))\n\t\t.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\", \"spring.graphql.graphiql.enabled=true\",\n\t\t\t\t\"spring.graphql.schema.printer.enabled=true\", \"spring.graphql.cors.allowed-origins=https://example.com\",\n\t\t\t\t\"spring.graphql.cors.allowed-methods=POST\", \"spring.graphql.cors.allow-credentials=true\");\n\n\t@Test\n\tvoid shouldContributeDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GraphQlHttpHandler.class)\n\t\t\t.hasSingleBean(WebGraphQlHandler.class)\n\t\t\t.doesNotHaveBean(GraphQlWebSocketHandler.class));\n\t}\n\n\t@Test\n\tvoid simpleQueryShouldWork() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tclient.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE)\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"data.bookById.name\")\n\t\t\t\t.isEqualTo(\"GraphQL for beginners\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid SseSubscriptionShouldWork() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ booksOnSale(minPages: 50){ id name pageCount author } }\";\n\t\t\tEntityExchangeResult<String> result = client.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.accept(MediaType.TEXT_EVENT_STREAM)\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"subscription TestSubscription \" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentTypeCompatibleWith(MediaType.TEXT_EVENT_STREAM)\n\t\t\t\t.expectBody(String.class)\n\t\t\t\t.returnResult();\n\t\t\tassertThat(result.getResponseBody()).contains(\"event:next\",\n\t\t\t\t\t\"data:{\\\"data\\\":{\\\"booksOnSale\\\":{\\\"id\\\":\\\"book-1\\\",\\\"name\\\":\\\"GraphQL for beginners\\\",\\\"pageCount\\\":100,\\\"author\\\":\\\"John GraphQL\\\"}}}\",\n\t\t\t\t\t\"event:next\",\n\t\t\t\t\t\"data:{\\\"data\\\":{\\\"booksOnSale\\\":{\\\"id\\\":\\\"book-2\\\",\\\"name\\\":\\\"Harry Potter and the Philosopher's Stone\\\",\\\"pageCount\\\":223,\\\"author\\\":\\\"Joanne Rowling\\\"}}}\",\n\t\t\t\t\t\"event:complete\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid unsupportedContentTypeShouldBeRejected() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tclient.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.UNSUPPORTED_MEDIA_TYPE)\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(\"Accept\", \"application/json\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid httpGetQueryShouldBeRejected() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/graphql?query={query}\", \"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.METHOD_NOT_ALLOWED)\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(\"Allow\", \"POST\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRejectMissingQuery() {\n\t\ttestWithWebClient(\n\t\t\t\t(client) -> client.post().uri(\"/graphql\").bodyValue(\"{}\").exchange().expectStatus().isBadRequest());\n\t}\n\n\t@Test\n\tvoid shouldRejectQueryWithInvalidJson() {\n\t\ttestWithWebClient(\n\t\t\t\t(client) -> client.post().uri(\"/graphql\").bodyValue(\":)\").exchange().expectStatus().isBadRequest());\n\t}\n\n\t@Test\n\tvoid shouldConfigureWebInterceptors() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\n\t\t\tclient.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(\"X-Custom-Header\", \"42\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldExposeSchemaEndpoint() {\n\t\ttestWithWebClient((client) -> client.get()\n\t\t\t.uri(\"/graphql/schema\")\n\t\t\t.accept(MediaType.ALL)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectHeader()\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.expectBody(String.class)\n\t\t\t.value((Consumer<@Nullable String>) (body) -> assertThat(body).contains(\"type Book\")));\n\t}\n\n\t@Test\n\tvoid shouldExposeGraphiqlEndpoint() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/graphiql\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.is3xxRedirection()\n\t\t\t\t.expectHeader()\n\t\t\t\t.location(\"https://spring.example.org/graphiql?path=/graphql\");\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/graphiql?path=/graphql\")\n\t\t\t\t.accept(MediaType.ALL)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(MediaType.TEXT_HTML);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupportCors() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{\" + \"  bookById(id: \\\\\\\"book-1\\\\\\\"){ \" + \"    id\" + \"    name\" + \"    pageCount\"\n\t\t\t\t\t+ \"    author\" + \"  }\" + \"}\";\n\t\t\tclient.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"POST\")\n\t\t\t\t.header(HttpHeaders.ORIGIN, \"https://example.com\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, \"https://example.com\")\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, \"true\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureWebSocketBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.websocket.path=/ws\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GraphQlWebSocketHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureWebSocketProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.graphql.websocket.path=/ws\",\n\t\t\t\t\t\"spring.graphql.websocket.connection-init-timeout=120s\", \"spring.graphql.websocket.keep-alive=30s\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GraphQlWebSocketHandler.class);\n\t\t\t\tGraphQlWebSocketHandler graphQlWebSocketHandler = context.getBean(GraphQlWebSocketHandler.class);\n\t\t\t\tassertThat(graphQlWebSocketHandler).extracting(\"initTimeoutDuration\")\n\t\t\t\t\t.isEqualTo(Duration.ofSeconds(120));\n\t\t\t\tassertThat(graphQlWebSocketHandler).extracting(\"keepAliveDuration\").isEqualTo(Duration.ofSeconds(30));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureSseTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.http.sse.timeout=10s\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GraphQlSseHandler.class);\n\t\t\tGraphQlSseHandler handler = context.getBean(GraphQlSseHandler.class);\n\t\t\tassertThat(handler).hasFieldOrPropertyWithValue(\"timeout\", Duration.ofSeconds(10));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureSseKeepAlive() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.http.sse.keep-alive=5s\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GraphQlSseHandler.class);\n\t\t\tGraphQlSseHandler handler = context.getBean(GraphQlSseHandler.class);\n\t\t\tassertThat(handler).hasFieldOrPropertyWithValue(\"keepAliveDuration\", Duration.ofSeconds(5));\n\t\t});\n\t}\n\n\t@Test\n\tvoid routerFunctionShouldHaveOrderZero() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRouterFunctions.class).run((context) -> {\n\t\t\tMap<String, ?> beans = context.getBeansOfType(RouterFunction.class);\n\t\t\tObject[] ordered = context.getBeanProvider(RouterFunction.class).orderedStream().toArray();\n\t\t\tassertThat(beans.get(\"before\")).isSameAs(ordered[0]);\n\t\t\tassertThat(beans.get(\"graphQlRouterFunction\")).isSameAs(ordered[1]);\n\t\t\tassertThat(beans.get(\"after\")).isSameAs(ordered[2]);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew GraphQlWebFluxAutoConfiguration.GraphiQlResourceHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"graphiql/index.html\")).accepts(hints);\n\t}\n\n\tprivate void testWithWebClient(Consumer<WebTestClient> consumer) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = WebTestClient.bindToApplicationContext(context)\n\t\t\t\t.configureClient()\n\t\t\t\t.defaultHeaders((headers) -> {\n\t\t\t\t\theaders.setContentType(MediaType.APPLICATION_JSON);\n\t\t\t\t\theaders.setAccept(Collections.singletonList(MediaType.APPLICATION_GRAPHQL_RESPONSE));\n\t\t\t\t})\n\t\t\t\t.baseUrl(BASE_URL)\n\t\t\t\t.build();\n\t\t\tconsumer.accept(client);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataFetchersConfiguration {\n\n\t\t@Bean\n\t\tRuntimeWiringConfigurer bookDataFetcher() {\n\t\t\treturn (builder) -> {\n\t\t\t\tbuilder.type(TypeRuntimeWiring.newTypeWiring(\"Query\")\n\t\t\t\t\t.dataFetcher(\"bookById\", GraphQlTestDataFetchers.getBookByIdDataFetcher()));\n\t\t\t\tbuilder.type(TypeRuntimeWiring.newTypeWiring(\"Subscription\")\n\t\t\t\t\t.dataFetcher(\"booksOnSale\", GraphQlTestDataFetchers.getBooksOnSaleDataFetcher()));\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebInterceptor {\n\n\t\t@Bean\n\t\tWebGraphQlInterceptor customWebGraphQlInterceptor() {\n\t\t\treturn (webInput, interceptorChain) -> interceptorChain.next(webInput)\n\t\t\t\t.doOnNext((output) -> output.getResponseHeaders().add(\"X-Custom-Header\", \"42\"));\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CustomRouterFunctions {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tRouterFunction<?> before() {\n\t\t\treturn (r) -> Mono.empty();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tRouterFunction<?> after() {\n\t\t\treturn (r) -> Mono.empty();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/rsocket/GraphQlRSocketAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.rsocket;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.function.Consumer;\n\nimport graphql.schema.idl.TypeRuntimeWiring;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.reactor.netty.NettyRouteProvider;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketServerAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;\nimport org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.graphql.client.RSocketGraphQlClient;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.graphql.server.GraphQlRSocketHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraphQlRSocketAutoConfiguration}\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlRSocketAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(JacksonAutoConfiguration.class, RSocketStrategiesAutoConfiguration.class,\n\t\t\t\t\t\tRSocketMessagingAutoConfiguration.class, RSocketServerAutoConfiguration.class,\n\t\t\t\t\t\tGraphQlAutoConfiguration.class, GraphQlRSocketAutoConfiguration.class))\n\t\t.withUserConfiguration(DataFetchersConfiguration.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\", \"spring.graphql.rsocket.mapping=graphql\");\n\n\t@Test\n\tvoid shouldContributeDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GraphQlRSocketHandler.class)\n\t\t\t.hasSingleBean(GraphQlRSocketController.class));\n\t}\n\n\t@Test\n\tvoid simpleQueryShouldWorkWithTcpServer() {\n\t\ttestWithRSocketTcp(this::assertThatSimpleQueryWorks);\n\t}\n\n\t@Test\n\tvoid simpleQueryShouldWorkWithWebSocketServer() {\n\t\ttestWithRSocketWebSocket(this::assertThatSimpleQueryWorks);\n\t}\n\n\t@Test\n\tvoid usesJacksonByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"jacksonJsonEncoderSupplier\"));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid usesJackson2WhenItIsPreferred() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.rsocket.preferred-json-mapper=jackson2\")\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasBean(\"jackson2JsonEncoderSupplier\"));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid usesJackson2WhenJacksonIsAbsent() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(Thread.currentThread().getContextClassLoader(), JsonMapper.class))\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> assertThat(context).hasBean(\"jackson2JsonEncoderSupplier\"));\n\t}\n\n\tprivate void assertThatSimpleQueryWorks(RSocketGraphQlClient client) {\n\t\tString document = \"{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }\";\n\t\tString bookName = client.document(document)\n\t\t\t.retrieve(\"bookById.name\")\n\t\t\t.toEntity(String.class)\n\t\t\t.block(Duration.ofSeconds(5));\n\t\tassertThat(bookName).isEqualTo(\"GraphQL for beginners\");\n\t}\n\n\tprivate void testWithRSocketTcp(Consumer<RSocketGraphQlClient> consumer) {\n\t\tReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(JacksonAutoConfiguration.class, RSocketStrategiesAutoConfiguration.class,\n\t\t\t\t\t\t\tRSocketMessagingAutoConfiguration.class, RSocketServerAutoConfiguration.class,\n\t\t\t\t\t\t\tGraphQlAutoConfiguration.class, GraphQlRSocketAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DataFetchersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\", \"spring.graphql.rsocket.mapping=graphql\");\n\t\tcontextRunner.withInitializer(new RSocketPortInfoApplicationContextInitializer())\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tString serverPort = context.getEnvironment().getProperty(\"local.rsocket.server.port\");\n\t\t\t\tRSocketGraphQlClient client = RSocketGraphQlClient.builder()\n\t\t\t\t\t.tcp(\"localhost\", Integer.parseInt(serverPort))\n\t\t\t\t\t.route(\"graphql\")\n\t\t\t\t\t.build();\n\t\t\t\tconsumer.accept(client);\n\t\t\t});\n\t}\n\n\tprivate void testWithRSocketWebSocket(Consumer<RSocketGraphQlClient> consumer) {\n\t\tReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(\n\t\t\t\tAnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,\n\t\t\t\t\tErrorWebFluxAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tJacksonAutoConfiguration.class, RSocketStrategiesAutoConfiguration.class,\n\t\t\t\t\tRSocketMessagingAutoConfiguration.class, RSocketServerAutoConfiguration.class,\n\t\t\t\t\tGraphQlAutoConfiguration.class, GraphQlRSocketAutoConfiguration.class))\n\t\t\t.withInitializer(new ServerPortInfoApplicationContextInitializer())\n\t\t\t.withUserConfiguration(DataFetchersConfiguration.class, NettyServerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\", \"server.port=0\",\n\t\t\t\t\t\"spring.graphql.rsocket.mapping=graphql\", \"spring.rsocket.server.transport=websocket\",\n\t\t\t\t\t\"spring.rsocket.server.mapping-path=/rsocket\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tString serverPort = context.getEnvironment().getProperty(\"local.server.port\");\n\t\t\tRSocketGraphQlClient client = RSocketGraphQlClient.builder()\n\t\t\t\t.webSocket(URI.create(\"ws://localhost:\" + serverPort + \"/rsocket\"))\n\t\t\t\t.route(\"graphql\")\n\t\t\t\t.build();\n\t\t\tconsumer.accept(client);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NettyServerConfiguration {\n\n\t\t@Bean\n\t\tNettyReactiveWebServerFactory serverFactory(NettyRouteProvider routeProvider) {\n\t\t\tNettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory(0);\n\t\t\tserverFactory.addRouteProviders(routeProvider);\n\t\t\treturn serverFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataFetchersConfiguration {\n\n\t\t@Bean\n\t\tRuntimeWiringConfigurer bookDataFetcher() {\n\t\t\treturn (builder) -> builder.type(TypeRuntimeWiring.newTypeWiring(\"Query\")\n\t\t\t\t.dataFetcher(\"bookById\", GraphQlTestDataFetchers.getBookByIdDataFetcher()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/rsocket/RSocketGraphQlClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.rsocket;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketRequesterAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.graphql.client.RSocketGraphQlClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RSocketGraphQlClientAutoConfiguration}.\n *\n * @author Brian Clozel\n */\nclass RSocketGraphQlClientAutoConfigurationTests {\n\n\tprivate static final RSocketGraphQlClient.Builder<?> builderInstance = RSocketGraphQlClient.builder();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RSocketStrategiesAutoConfiguration.class,\n\t\t\t\tRSocketRequesterAutoConfiguration.class, RSocketGraphQlClientAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldCreateBuilder() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(RSocketGraphQlClient.Builder.class));\n\t}\n\n\t@Test\n\tvoid shouldGetPrototypeScopedBean() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRSocketGraphQlClient.Builder<?> first = context.getBean(RSocketGraphQlClient.Builder.class);\n\t\t\tRSocketGraphQlClient.Builder<?> second = context.getBean(RSocketGraphQlClient.Builder.class);\n\t\t\tassertThat(first).isNotEqualTo(second);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotCreateBuilderIfAlreadyPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRSocketGraphQlClientBuilder.class).run((context) -> {\n\t\t\tRSocketGraphQlClient.Builder<?> builder = context.getBean(RSocketGraphQlClient.Builder.class);\n\t\t\tassertThat(builder).isEqualTo(builderInstance);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRSocketGraphQlClientBuilder {\n\n\t\t@Bean\n\t\tRSocketGraphQlClient.Builder<?> myRSocketGraphQlClientBuilder() {\n\t\t\treturn builderInstance;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/security/GraphQlWebFluxSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.security;\n\nimport java.util.Collections;\nimport java.util.function.Consumer;\n\nimport graphql.schema.idl.TypeRuntimeWiring;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.Book;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;\nimport org.springframework.boot.graphql.autoconfigure.reactive.GraphQlWebFluxAutoConfiguration;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.graphql.execution.ErrorType;\nimport org.springframework.graphql.execution.ReactiveSecurityDataFetcherExceptionResolver;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity.CsrfSpec;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for {@link GraphQlWebFluxSecurityAutoConfiguration}.\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlWebFluxSecurityAutoConfigurationTests {\n\n\tprivate static final String BASE_URL = \"https://spring.example.org/graphql\";\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,\n\t\t\t\tCodecsAutoConfiguration.class, JacksonAutoConfiguration.class, GraphQlAutoConfiguration.class,\n\t\t\t\tGraphQlWebFluxAutoConfiguration.class, GraphQlWebFluxSecurityAutoConfiguration.class,\n\t\t\t\tReactiveWebSecurityAutoConfiguration.class))\n\t\t.withUserConfiguration(DataFetchersConfiguration.class, SecurityConfig.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\");\n\n\t@Test\n\tvoid contributesExceptionResolver() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveSecurityDataFetcherExceptionResolver.class));\n\t}\n\n\t@Test\n\tvoid anonymousUserShouldBeUnauthorized() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author }}\";\n\t\t\tclient.post()\n\t\t\t\t.uri(\"\")\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"data.bookById.name\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"errors[0].extensions.classification\")\n\t\t\t\t.isEqualTo(ErrorType.UNAUTHORIZED.toString());\n\t\t});\n\t}\n\n\t@Test\n\tvoid authenticatedUserShouldGetData() {\n\t\ttestWithWebClient((client) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author }}\";\n\t\t\tclient.post()\n\t\t\t\t.uri(\"\")\n\t\t\t\t.headers((headers) -> headers.setBasicAuth(\"rob\", \"rob\"))\n\t\t\t\t.bodyValue(\"{  \\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"data.bookById.name\")\n\t\t\t\t.isEqualTo(\"GraphQL for beginners\")\n\t\t\t\t.jsonPath(\"errors[0].extensions.classification\")\n\t\t\t\t.doesNotExist();\n\t\t});\n\t}\n\n\tprivate void testWithWebClient(Consumer<WebTestClient> consumer) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = WebTestClient.bindToApplicationContext(context)\n\t\t\t\t.configureClient()\n\t\t\t\t.defaultHeaders((headers) -> {\n\t\t\t\t\theaders.setContentType(MediaType.APPLICATION_JSON);\n\t\t\t\t\theaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));\n\t\t\t\t})\n\t\t\t\t.baseUrl(BASE_URL)\n\t\t\t\t.build();\n\t\t\tconsumer.accept(client);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataFetchersConfiguration {\n\n\t\t@Bean\n\t\tRuntimeWiringConfigurer bookDataFetcher(BookService bookService) {\n\t\t\treturn (builder) -> builder.type(TypeRuntimeWiring.newTypeWiring(\"Query\").dataFetcher(\"bookById\", (env) -> {\n\t\t\t\tString id = env.getArgument(\"id\");\n\t\t\t\tassertThat(id).isNotNull();\n\t\t\t\treturn bookService.getBookdById(id);\n\t\t\t}));\n\t\t}\n\n\t\t@Bean\n\t\tBookService bookService() {\n\t\t\treturn new BookService();\n\t\t}\n\n\t}\n\n\tstatic class BookService {\n\n\t\t@PreAuthorize(\"hasRole('USER')\")\n\t\tMono<Book> getBookdById(String id) {\n\t\t\treturn Mono.justOrEmpty(GraphQlTestDataFetchers.getBookById(id));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFluxSecurity\n\t@EnableReactiveMethodSecurity\n\tstatic class SecurityConfig {\n\n\t\t@Bean\n\t\tSecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {\n\t\t\treturn http.csrf(CsrfSpec::disable)\n\t\t\t\t// Demonstrate that method security works\n\t\t\t\t// Best practice to use both for defense in depth\n\t\t\t\t.authorizeExchange((requests) -> requests.anyExchange().permitAll())\n\t\t\t\t.httpBasic(withDefaults())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"deprecation\")\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\tUser.UserBuilder userBuilder = User.withDefaultPasswordEncoder();\n\t\t\tUserDetails rob = userBuilder.username(\"rob\").password(\"rob\").roles(\"USER\").build();\n\t\t\tUserDetails admin = userBuilder.username(\"admin\").password(\"admin\").roles(\"USER\", \"ADMIN\").build();\n\t\t\treturn new MapReactiveUserDetailsService(rob, admin);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/security/GraphQlWebMvcSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.security;\n\nimport graphql.schema.idl.TypeRuntimeWiring;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.Book;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;\nimport org.springframework.boot.graphql.autoconfigure.servlet.GraphQlWebMvcAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.graphql.execution.ErrorType;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.graphql.execution.SecurityDataFetcherExceptionResolver;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.DefaultSecurityFilterChain;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\nimport static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;\nimport static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\n\n/**\n * Tests for {@link GraphQlWebMvcSecurityAutoConfiguration}.\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlWebMvcSecurityAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,\n\t\t\t\tWebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\t\tJacksonAutoConfiguration.class, GraphQlAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class,\n\t\t\t\tGraphQlWebMvcSecurityAutoConfiguration.class, SecurityAutoConfiguration.class))\n\t\t.withUserConfiguration(DataFetchersConfiguration.class, SecurityConfig.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=servlet\");\n\n\t@Test\n\tvoid contributesSecurityComponents() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SecurityDataFetcherExceptionResolver.class));\n\t}\n\n\t@Test\n\tvoid anonymousUserShouldBeUnauthorized() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author }}\";\n\t\t\tassertThat(mvc.post().uri(\"/graphql\").content(\"{\\\"query\\\": \\\"\" + query + \"\\\"}\")).satisfies((result) -> {\n\t\t\t\tassertThat(result).hasStatusOk().hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON);\n\t\t\t\tassertThat(result).bodyJson()\n\t\t\t\t\t.doesNotHavePath(\"data.bookById.name\")\n\t\t\t\t\t.extractingPath(\"errors[0].extensions.classification\")\n\t\t\t\t\t.asString()\n\t\t\t\t\t.isEqualTo(ErrorType.UNAUTHORIZED.toString());\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid authenticatedUserShouldGetData() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{  bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author }}\";\n\t\t\tassertThat(mvc.post().uri(\"/graphql\").content(\"{\\\"query\\\": \\\"\" + query + \"\\\"}\").with(user(\"rob\")))\n\t\t\t\t.satisfies((result) -> {\n\t\t\t\t\tassertThat(result).hasStatusOk().hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON);\n\t\t\t\t\tassertThat(result).bodyJson()\n\t\t\t\t\t\t.doesNotHavePath(\"errors\")\n\t\t\t\t\t\t.extractingPath(\"data.bookById.name\")\n\t\t\t\t\t\t.asString()\n\t\t\t\t\t\t.isEqualTo(\"GraphQL for beginners\");\n\t\t\t\t});\n\t\t});\n\t}\n\n\tprivate void withMockMvc(ThrowingConsumer<MockMvcTester> mvc) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMediaType mediaType = MediaType.APPLICATION_JSON;\n\t\t\tMockMvcTester mockMVc = MockMvcTester.from(context,\n\t\t\t\t\t(builder) -> builder.defaultRequest(post(\"/graphql\").contentType(mediaType).accept(mediaType))\n\t\t\t\t\t\t.apply(springSecurity())\n\t\t\t\t\t\t.build());\n\t\t\tmvc.accept(mockMVc);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataFetchersConfiguration {\n\n\t\t@Bean\n\t\tRuntimeWiringConfigurer bookDataFetcher(BookService bookService) {\n\t\t\treturn (builder) -> builder.type(TypeRuntimeWiring.newTypeWiring(\"Query\").dataFetcher(\"bookById\", (env) -> {\n\t\t\t\tString id = env.getArgument(\"id\");\n\t\t\t\tassertThat(id).isNotNull();\n\t\t\t\treturn bookService.getBookdById(id);\n\t\t\t}));\n\t\t}\n\n\t\t@Bean\n\t\tBookService bookService() {\n\t\t\treturn new BookService();\n\t\t}\n\n\t}\n\n\tstatic class BookService {\n\n\t\t@PreAuthorize(\"hasRole('USER')\")\n\t\t@Nullable Book getBookdById(String id) {\n\t\t\treturn GraphQlTestDataFetchers.getBookById(id);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\t@EnableMethodSecurity(prePostEnabled = true)\n\t@SuppressWarnings(\"deprecation\")\n\tstatic class SecurityConfig {\n\n\t\t@Bean\n\t\tDefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) {\n\t\t\treturn http.csrf(CsrfConfigurer::disable)\n\t\t\t\t// Demonstrate that method security works\n\t\t\t\t// Best practice to use both for defense in depth\n\t\t\t\t.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll())\n\t\t\t\t.httpBasic(withDefaults())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tInMemoryUserDetailsManager userDetailsService() {\n\t\t\tUser.UserBuilder userBuilder = User.withDefaultPasswordEncoder();\n\t\t\tUserDetails rob = userBuilder.username(\"rob\").password(\"rob\").roles(\"USER\").build();\n\t\t\tUserDetails admin = userBuilder.username(\"admin\").password(\"admin\").roles(\"USER\", \"ADMIN\").build();\n\t\t\treturn new InMemoryUserDetailsManager(rob, admin);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql/src/test/java/org/springframework/boot/graphql/autoconfigure/servlet/GraphQlWebMvcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.autoconfigure.servlet;\n\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport graphql.schema.idl.TypeRuntimeWiring;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlTestDataFetchers;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.graphql.server.WebGraphQlHandler;\nimport org.springframework.graphql.server.WebGraphQlInterceptor;\nimport org.springframework.graphql.server.webmvc.GraphQlHttpHandler;\nimport org.springframework.graphql.server.webmvc.GraphQlSseHandler;\nimport org.springframework.graphql.server.webmvc.GraphQlWebSocketHandler;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.servlet.HandlerMapping;\nimport org.springframework.web.servlet.function.RouterFunction;\nimport org.springframework.web.servlet.function.support.RouterFunctionMapping;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.socket.server.support.WebSocketHandlerMapping;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\n\n/**\n * Tests for {@link GraphQlWebMvcAutoConfiguration}.\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"graphql/types/book.graphqls\", content = \"\"\"\n\t\ttype Book {\n\t\t    id: ID\n\t\t    name: String\n\t\t    pageCount: Int\n\t\t    author: String\n\t\t}\n\t\t\"\"\")\n@WithResource(name = \"graphql/schema.graphqls\", content = \"\"\"\n\t\ttype Query {\n\t\t    greeting(name: String! = \"Spring\"): String!\n\t\t    bookById(id: ID): Book\n\t\t    books: BookConnection\n\t\t}\n\n\t\ttype Subscription {\n\t\t    booksOnSale(minPages: Int) : Book!\n\t\t}\n\t\t\"\"\")\nclass GraphQlWebMvcAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,\n\t\t\t\tWebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\t\tJacksonAutoConfiguration.class, GraphQlAutoConfiguration.class, GraphQlWebMvcAutoConfiguration.class))\n\t\t.withUserConfiguration(DataFetchersConfiguration.class, CustomWebInterceptor.class)\n\t\t.withPropertyValues(\"spring.main.web-application-type=servlet\", \"spring.graphql.graphiql.enabled=true\",\n\t\t\t\t\"spring.graphql.schema.printer.enabled=true\", \"spring.graphql.cors.allowed-origins=https://example.com\",\n\t\t\t\t\"spring.graphql.cors.allowed-methods=POST\", \"spring.graphql.cors.allow-credentials=true\");\n\n\t@Test\n\tvoid shouldContributeDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GraphQlHttpHandler.class)\n\t\t\t.hasSingleBean(WebGraphQlHandler.class)\n\t\t\t.doesNotHaveBean(GraphQlWebSocketHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureSseTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.http.sse.timeout=10s\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GraphQlSseHandler.class);\n\t\t\tGraphQlSseHandler handler = context.getBean(GraphQlSseHandler.class);\n\t\t\tassertThat(handler).hasFieldOrPropertyWithValue(\"timeout\", Duration.ofSeconds(10));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureSseKeepAlive() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.http.sse.keep-alive=5s\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GraphQlSseHandler.class);\n\t\t\tGraphQlSseHandler handler = context.getBean(GraphQlSseHandler.class);\n\t\t\tassertThat(handler).hasFieldOrPropertyWithValue(\"keepAliveDuration\", Duration.ofSeconds(5));\n\t\t});\n\t}\n\n\t@Test\n\tvoid simpleQueryShouldWork() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tassertThat(mvc.post().uri(\"/graphql\").content(\"{\\\"query\\\": \\\"\" + query + \"\\\"}\")).satisfies((result) -> {\n\t\t\t\tassertThat(result).hasStatusOk().hasContentTypeCompatibleWith(MediaType.APPLICATION_GRAPHQL_RESPONSE);\n\t\t\t\tassertThat(result).bodyJson()\n\t\t\t\t\t.extractingPath(\"data.bookById.name\")\n\t\t\t\t\t.asString()\n\t\t\t\t\t.isEqualTo(\"GraphQL for beginners\");\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid SseSubscriptionShouldWork() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{ booksOnSale(minPages: 50){ id name pageCount author } }\";\n\t\t\tassertThat(mvc.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.accept(MediaType.TEXT_EVENT_STREAM)\n\t\t\t\t.content(\"{\\\"query\\\": \\\"subscription TestSubscription \" + query + \"\\\"}\")).satisfies((result) -> {\n\t\t\t\t\tassertThat(result).hasStatusOk().hasContentTypeCompatibleWith(MediaType.TEXT_EVENT_STREAM);\n\t\t\t\t\tassertThat(result).bodyText()\n\t\t\t\t\t\t.containsSubsequence(\"event:next\",\n\t\t\t\t\t\t\t\t\"data:{\\\"data\\\":{\\\"booksOnSale\\\":{\\\"id\\\":\\\"book-1\\\",\\\"name\\\":\\\"GraphQL for beginners\\\",\\\"pageCount\\\":100,\\\"author\\\":\\\"John GraphQL\\\"}}}\",\n\t\t\t\t\t\t\t\t\"event:next\",\n\t\t\t\t\t\t\t\t\"data:{\\\"data\\\":{\\\"booksOnSale\\\":{\\\"id\\\":\\\"book-2\\\",\\\"name\\\":\\\"Harry Potter and the Philosopher's Stone\\\",\\\"pageCount\\\":223,\\\"author\\\":\\\"Joanne Rowling\\\"}}}\");\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid unsupportedContentTypeShouldBeRejected() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tassertThat(mvc.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.content(\"{\\\"query\\\": \\\"\" + query + \"\\\"}\")\n\t\t\t\t.contentType(MediaType.TEXT_PLAIN)).hasStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)\n\t\t\t\t.headers()\n\t\t\t\t.hasValue(\"Accept\", \"application/json\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid httpGetQueryShouldBeRejected() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tassertThat(mvc.get().uri(\"/graphql?query={query}\", \"{\\\"query\\\": \\\"\" + query + \"\\\"}\"))\n\t\t\t\t.hasStatus(HttpStatus.METHOD_NOT_ALLOWED)\n\t\t\t\t.headers()\n\t\t\t\t.hasValue(\"Allow\", \"POST\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRejectMissingQuery() {\n\t\twithMockMvc((mvc) -> assertThat(mvc.post().uri(\"/graphql\").content(\"{}\")).hasStatus(HttpStatus.BAD_REQUEST));\n\t}\n\n\t@Test\n\tvoid shouldRejectQueryWithInvalidJson() {\n\t\twithMockMvc((mvc) -> assertThat(mvc.post().uri(\"/graphql\").content(\":)\")).hasStatus(HttpStatus.BAD_REQUEST));\n\t}\n\n\t@Test\n\tvoid shouldConfigureWebInterceptors() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{ bookById(id: \\\\\\\"book-1\\\\\\\"){ id name pageCount author } }\";\n\t\t\tassertThat(mvc.post().uri(\"/graphql\").content(\"{\\\"query\\\": \\\"\" + query + \"\\\"}\")).hasStatusOk()\n\t\t\t\t.headers()\n\t\t\t\t.hasValue(\"X-Custom-Header\", \"42\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldExposeSchemaEndpoint() {\n\t\twithMockMvc((mvc) -> assertThat(mvc.get().uri(\"/graphql/schema\")).hasStatusOk()\n\t\t\t.hasContentType(MediaType.TEXT_PLAIN)\n\t\t\t.bodyText()\n\t\t\t.contains(\"type Book\"));\n\t}\n\n\t@Test\n\tvoid shouldExposeGraphiqlEndpoint() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tassertThat(mvc.get().uri(\"/graphiql\")).hasStatus3xxRedirection()\n\t\t\t\t.hasRedirectedUrl(\"http://localhost/graphiql?path=/graphql\");\n\t\t\tassertThat(mvc.get().uri(\"/graphiql?path=/graphql\")).hasStatusOk()\n\t\t\t\t.contentType()\n\t\t\t\t.isEqualTo(MediaType.TEXT_HTML);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupportCors() {\n\t\twithMockMvc((mvc) -> {\n\t\t\tString query = \"{\" + \"  bookById(id: \\\\\\\"book-1\\\\\\\"){ \" + \"    id\" + \"    name\" + \"    pageCount\"\n\t\t\t\t\t+ \"    author\" + \"  }\" + \"}\";\n\t\t\tassertThat(mvc.post()\n\t\t\t\t.uri(\"/graphql\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"POST\")\n\t\t\t\t.header(HttpHeaders.ORIGIN, \"https://example.com\")\n\t\t\t\t.content(\"{\\\"query\\\": \\\"\" + query + \"\\\"}\"))\n\t\t\t\t.satisfies((result) -> assertThat(result).hasStatusOk()\n\t\t\t\t\t.headers()\n\t\t\t\t\t.hasValue(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, \"https://example.com\")\n\t\t\t\t\t.hasValue(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, \"true\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureWebSocketBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.graphql.websocket.path=/ws\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(GraphQlWebSocketHandler.class);\n\t\t\tassertThat(context.getBeanProvider(HandlerMapping.class).orderedStream().toList()).containsSubsequence(\n\t\t\t\t\tcontext.getBean(WebSocketHandlerMapping.class), context.getBean(RouterFunctionMapping.class),\n\t\t\t\t\tcontext.getBean(RequestMappingHandlerMapping.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureWebSocketProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.graphql.websocket.path=/ws\",\n\t\t\t\t\t\"spring.graphql.websocket.connection-init-timeout=120s\", \"spring.graphql.websocket.keep-alive=30s\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GraphQlWebSocketHandler.class);\n\t\t\t\tGraphQlWebSocketHandler graphQlWebSocketHandler = context.getBean(GraphQlWebSocketHandler.class);\n\t\t\t\tassertThat(graphQlWebSocketHandler).extracting(\"initTimeoutDuration\")\n\t\t\t\t\t.isEqualTo(Duration.ofSeconds(120));\n\t\t\t\tassertThat(graphQlWebSocketHandler).extracting(\"keepAliveDuration\").isEqualTo(Duration.ofSeconds(30));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid routerFunctionShouldHaveOrderZero() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRouterFunctions.class).run((context) -> {\n\t\t\tMap<String, ?> beans = context.getBeansOfType(RouterFunction.class);\n\t\t\tObject[] ordered = context.getBeanProvider(RouterFunction.class).orderedStream().toArray();\n\t\t\tassertThat(beans.get(\"before\")).isSameAs(ordered[0]);\n\t\t\tassertThat(beans.get(\"graphQlRouterFunction\")).isSameAs(ordered[1]);\n\t\t\tassertThat(beans.get(\"after\")).isSameAs(ordered[2]);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew GraphQlWebMvcAutoConfiguration.GraphiQlResourceHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"graphiql/index.html\")).accepts(hints);\n\t}\n\n\tprivate void withMockMvc(ThrowingConsumer<MockMvcTester> mvc) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMockMvcTester mockMVc = MockMvcTester.from(context,\n\t\t\t\t\t(builder) -> builder\n\t\t\t\t\t\t.defaultRequest(post(\"/graphql\").contentType(MediaType.APPLICATION_JSON)\n\t\t\t\t\t\t\t.accept(MediaType.APPLICATION_GRAPHQL_RESPONSE))\n\t\t\t\t\t\t.build());\n\t\t\tmvc.accept(mockMVc);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataFetchersConfiguration {\n\n\t\t@Bean\n\t\tRuntimeWiringConfigurer bookDataFetcher() {\n\t\t\treturn (builder) -> {\n\t\t\t\tbuilder.type(TypeRuntimeWiring.newTypeWiring(\"Query\")\n\t\t\t\t\t.dataFetcher(\"bookById\", GraphQlTestDataFetchers.getBookByIdDataFetcher()));\n\t\t\t\tbuilder.type(TypeRuntimeWiring.newTypeWiring(\"Subscription\")\n\t\t\t\t\t.dataFetcher(\"booksOnSale\", GraphQlTestDataFetchers.getBooksOnSaleDataFetcher()));\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebInterceptor {\n\n\t\t@Bean\n\t\tWebGraphQlInterceptor customWebGraphQlInterceptor() {\n\t\t\treturn (webInput, interceptorChain) -> interceptorChain.next(webInput)\n\t\t\t\t.doOnNext((output) -> output.getResponseHeaders().add(\"X-Custom-Header\", \"42\"));\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CustomRouterFunctions {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tRouterFunction<?> before() {\n\t\t\treturn (r) -> Optional.empty();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tRouterFunction<?> after() {\n\t\t\treturn (r) -> Optional.empty();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot GraphQL Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(\"org.springframework.graphql:spring-graphql-test\")\n\n\timplementation(project(\":module:spring-boot-graphql\"))\n\timplementation(project(\":module:spring-boot-jackson\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-validation\"))\n\toptional(project(\":module:spring-boot-webclient\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(project(\":module:spring-boot-webtestclient\"))\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\toptional(\"org.springframework:spring-web\")\n\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"tools.jackson.core:jackson-databind\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/AutoConfigureGraphQl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Spring GraphQL\n * tests. Most tests should consider using {@link GraphQlTest @GraphQlTest} rather than\n * using this annotation directly.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see GraphQlTest\n * @see org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration\n * @see org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\n * @see org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureGraphQl {\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/GraphQlTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureGraphQlTester;\nimport org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation to perform GraphQL tests focusing on GraphQL request execution without a Web\n * layer, and loading only a subset of the application configuration.\n * <p>\n * The annotation disables full auto-configuration and instead loads only components\n * relevant to GraphQL tests, including the following:\n * <ul>\n * <li>{@code @Controller}\n * <li>{@code @ControllerAdvice}\n * <li>{@code RuntimeWiringConfigurer}\n * <li>{@code @JacksonComponent}\n * <li>{@code @JsonComponent} (deprecated)\n * <li>{@code Converter}\n * <li>{@code GenericConverter}\n * <li>{@code DataFetcherExceptionResolver}\n * <li>{@code Instrumentation}\n * <li>{@code GraphQlSourceBuilderCustomizer}\n * </ul>\n * <p>\n * The annotation does not automatically load {@code @Component}, {@code @Service},\n * {@code @Repository}, and other beans.\n * <p>\n * By default, tests annotated with {@code @GraphQlTest} have a\n * {@link org.springframework.graphql.test.tester.GraphQlTester} configured. For more\n * fine-grained control of the GraphQlTester, use\n * {@link AutoConfigureGraphQlTester @AutoConfigureGraphQlTester}.\n * <p>\n * Typically {@code @GraphQlTest} is used in combination with\n * {@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}\n * or {@link org.springframework.context.annotation.Import @Import} to load any\n * collaborators and other components required for the tests.\n * <p>\n * To load your full application configuration instead and test via\n * {@code HttpGraphQlTester}, consider using\n * {@link org.springframework.boot.test.context.SpringBootTest @SpringBootTest} combined\n * with {@link AutoConfigureHttpGraphQlTester @AutoConfigureHttpGraphQlTester}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see AutoConfigureGraphQlTester\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(GraphQlTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(GraphQlTypeExcludeFilter.class)\n@AutoConfigureJson\n@AutoConfigureGraphQl\n@AutoConfigureGraphQlTester\n@ImportAutoConfiguration\npublic @interface GraphQlTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the controllers to test. This is an alias of {@link #controllers()} which\n\t * can be used for brevity if no other attributes are defined. See\n\t * {@link #controllers()} for details.\n\t * @see #controllers()\n\t * @return the controllers to test\n\t */\n\t@AliasFor(\"controllers\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the controllers to test. May be left blank if all {@code @Controller}\n\t * beans should be added to the application context.\n\t * @see #value()\n\t * @return the controllers to test\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] controllers() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default, only\n\t * {@code @Controller} (when no explicit {@link #controllers() controllers} are\n\t * defined), {@code ControllerAdvice}, {@code RuntimeWiringConfigurer},\n\t * {@code @JacksonComponent}, {@code @JsonComponent} (deprecated), {@code Converter},\n\t * {@code GenericConverter}, {@code DataFetcherExceptionResolver},\n\t * {@code Instrumentation} and {@code GraphQlSourceBuilderCustomizer} beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/GraphQlTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link GraphQlTest @GraphQlTest}.\n *\n * @author Brian Clozel\n */\nclass GraphQlTestContextBootstrapper extends TestSliceTestContextBootstrapper<GraphQlTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/GraphQlTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport graphql.execution.instrumentation.Instrumentation;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer;\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.graphql.execution.DataFetcherExceptionResolver;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\n\n/**\n * {@link TypeExcludeFilter} for {@link GraphQlTest @GraphQlTest}.\n *\n * @author Brian Clozel\n */\nclass GraphQlTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<GraphQlTest> {\n\n\tprivate static final Class<?>[] NO_CONTROLLERS = {};\n\n\tprivate static final String[] OPTIONAL_INCLUDES = { \"tools.jackson.databind.JacksonModule\",\n\t\t\t\"com.fasterxml.jackson.databind.Module\", \"org.springframework.boot.jackson2.JsonComponent\" };\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>();\n\t\tincludes.add(ControllerAdvice.class);\n\t\tincludes.add(JacksonComponent.class);\n\t\tincludes.add(RuntimeWiringConfigurer.class);\n\t\tincludes.add(Converter.class);\n\t\tincludes.add(GenericConverter.class);\n\t\tincludes.add(DataFetcherExceptionResolver.class);\n\t\tincludes.add(Instrumentation.class);\n\t\tincludes.add(GraphQlSourceBuilderCustomizer.class);\n\t\tfor (String optionalInclude : OPTIONAL_INCLUDES) {\n\t\t\ttry {\n\t\t\t\tincludes.add(ClassUtils.forName(optionalInclude, null));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tKNOWN_INCLUDES = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES_AND_CONTROLLER;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>(KNOWN_INCLUDES);\n\t\tincludes.add(Controller.class);\n\t\tKNOWN_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate final Class<?>[] controllers;\n\n\tGraphQlTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.controllers = getAnnotation().getValue(\"controllers\", Class[].class).orElse(NO_CONTROLLERS);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\tif (ObjectUtils.isEmpty(this.controllers)) {\n\t\t\treturn KNOWN_INCLUDES_AND_CONTROLLER;\n\t\t}\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.controllers));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for GraphQL testing.\n */\n@NullMarked\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/AutoConfigureGraphQlTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\n/**\n * Annotation that can be applied to a test class to enable a {@link GraphQlTester}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see GraphQlTesterAutoConfiguration\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureGraphQlTester {\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/AutoConfigureHttpGraphQlTester.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.graphql.test.tester.HttpGraphQlTester;\n\n/**\n * Annotation that can be applied to a test class to enable an {@link HttpGraphQlTester}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see HttpGraphQlTesterAutoConfiguration\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureWebTestClient\n@ImportAutoConfiguration\npublic @interface AutoConfigureHttpGraphQlTester {\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/GraphQlTesterAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport graphql.GraphQL;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.test.tester.ExecutionGraphQlServiceTester;\nimport org.springframework.graphql.test.tester.GraphQlTester;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.json.JacksonJsonDecoder;\nimport org.springframework.http.codec.json.JacksonJsonEncoder;\n\n/**\n * Auto-configuration for {@link GraphQlTester}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = GraphQlAutoConfiguration.class)\n@ConditionalOnClass({ GraphQL.class, GraphQlTester.class })\npublic final class GraphQlTesterAutoConfiguration {\n\n\tprivate static final MediaType APPLICATION_GRAPHQL = new MediaType(\"application\", \"graphql+json\");\n\n\t@Bean\n\t@ConditionalOnBean(ExecutionGraphQlService.class)\n\t@ConditionalOnMissingBean\n\tExecutionGraphQlServiceTester graphQlTester(ExecutionGraphQlService graphQlService,\n\t\t\tObjectProvider<JsonMapper> jsonMapperProvider) {\n\t\tExecutionGraphQlServiceTester.Builder<?> builder = ExecutionGraphQlServiceTester.builder(graphQlService);\n\t\tjsonMapperProvider.ifAvailable((objectMapper) -> {\n\t\t\tbuilder.encoder(new JacksonJsonEncoder(objectMapper, MediaType.APPLICATION_GRAPHQL_RESPONSE,\n\t\t\t\t\tMediaType.APPLICATION_JSON, APPLICATION_GRAPHQL));\n\t\t\tbuilder.decoder(new JacksonJsonDecoder(objectMapper, MediaType.APPLICATION_JSON));\n\t\t});\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/HttpGraphQlTesterAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.graphql.autoconfigure.GraphQlProperties;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.graphql.test.tester.HttpGraphQlTester;\nimport org.springframework.graphql.test.tester.WebGraphQlTester;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * Auto-configuration for {@link HttpGraphQlTester}.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = \"org.springframework.boot.webtestclient.autoconfigure.WebTestClientAutoConfiguration\")\n@ConditionalOnClass({ WebClient.class, WebTestClient.class, WebGraphQlTester.class })\n@EnableConfigurationProperties(GraphQlProperties.class)\npublic final class HttpGraphQlTesterAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(WebTestClient.class)\n\t@ConditionalOnMissingBean\n\tHttpGraphQlTester webTestClientGraphQlTester(ApplicationContext applicationContext, WebTestClient webTestClient,\n\t\t\tGraphQlProperties properties) {\n\t\tString graphQlPath = properties.getHttp().getPath();\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.get(applicationContext);\n\t\treturn HttpGraphQlTester.create(createWebTestClient(webTestClient.mutate(), localTestWebServer, graphQlPath));\n\t}\n\n\tprivate WebTestClient createWebTestClient(WebTestClient.Builder builder,\n\t\t\t@Nullable LocalTestWebServer localTestWebServer, String graphQlPath) {\n\t\treturn (localTestWebServer != null)\n\t\t\t\t? builder.uriBuilderFactory(localTestWebServer.withPath(graphQlPath).uriBuilderFactory()).build()\n\t\t\t\t: builder.baseUrl(graphQlPath).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for GraphQL tester.\n */\n@NullMarked\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/resources/META-INF/spring/org.springframework.boot.graphql.test.autoconfigure.AutoConfigureGraphQl.imports",
    "content": "org.springframework.boot.graphql.autoconfigure.GraphQlAutoConfiguration\noptional:org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration\noptional:org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/resources/META-INF/spring/org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureGraphQlTester.imports",
    "content": "org.springframework.boot.graphql.test.autoconfigure.tester.GraphQlTesterAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/main/resources/META-INF/spring/org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester.imports",
    "content": "org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/Book.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\npublic class Book {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tString id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tString name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tint pageCount;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tString author;\n\n\tprotected Book() {\n\t}\n\n\tpublic Book(String id, String name, int pageCount, String author) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.pageCount = pageCount;\n\t\tthis.author = author;\n\t}\n\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getPageCount() {\n\t\treturn this.pageCount;\n\t}\n\n\tpublic void setPageCount(int pageCount) {\n\t\tthis.pageCount = pageCount;\n\t}\n\n\tpublic String getAuthor() {\n\t\treturn this.author;\n\t}\n\n\tpublic void setAuthor(String author) {\n\t\tthis.author = author;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/BookController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport org.springframework.graphql.data.method.annotation.Argument;\nimport org.springframework.graphql.data.method.annotation.QueryMapping;\nimport org.springframework.stereotype.Controller;\n\n/**\n * Example {@code @Controller} to be tested with {@link GraphQlTest @GraphQlTest}.\n *\n * @author Brian Clozel\n */\n@Controller\npublic class BookController {\n\n\t@QueryMapping\n\tpublic Book bookById(@Argument String id) {\n\t\treturn new Book(\"42\", \"Sample Book\", 100, \"Jane Spring\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/ExampleGraphQlApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link GraphQlTest @GraphQlTest} tests.\n *\n * @author Brian Clozel\n */\n@SpringBootApplication\npublic class ExampleGraphQlApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/GraphQlTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\n/**\n * Integration test for {@link GraphQlTest @GraphQlTest} annotated tests.\n *\n * @author Brian Clozel\n */\n@GraphQlTest(BookController.class)\nclass GraphQlTestIntegrationTests {\n\n\t@Autowired\n\tprivate GraphQlTester graphQlTester;\n\n\t@Test\n\tvoid getBookdByIdShouldReturnTestBook() {\n\t\tString query = \"{ bookById(id: \\\"book-1\\\"){ id name pageCount author } }\";\n\t\tthis.graphQlTester.document(query).execute().path(\"data.bookById.id\").entity(String.class).isEqualTo(\"42\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/GraphQlTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link GraphQlTest#properties properties} attribute of\n * {@link GraphQlTest @GraphQlTest}.\n *\n * @author Andy Wilkinson\n */\n@GraphQlTest(properties = \"spring.profiles.active=test\")\nclass GraphQlTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(GraphQlTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/GraphQlTypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport graphql.GraphQLError;\nimport graphql.execution.instrumentation.Instrumentation;\nimport graphql.schema.DataFetchingEnvironment;\nimport graphql.schema.idl.RuntimeWiring;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport tools.jackson.databind.module.SimpleModule;\n\nimport org.springframework.boot.graphql.autoconfigure.GraphQlSourceBuilderCustomizer;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.graphql.execution.DataFetcherExceptionResolver;\nimport org.springframework.graphql.execution.GraphQlSource;\nimport org.springframework.graphql.execution.RuntimeWiringConfigurer;\nimport org.springframework.graphql.server.WebGraphQlInterceptor;\nimport org.springframework.graphql.server.WebGraphQlRequest;\nimport org.springframework.graphql.server.WebGraphQlResponse;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraphQlTypeExcludeFilter}\n *\n * @author Brian Clozel\n */\nclass GraphQlTypeExcludeFilterTests {\n\n\tprivate final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\t@Test\n\tvoid matchWhenHasNoControllers() throws Exception {\n\t\tGraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithNoControllers.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleInstrumentation.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenHasController() throws Exception {\n\t\tGraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithController.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleInstrumentation.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchNotUsingDefaultFilters() throws Exception {\n\t\tGraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(NotUsingDefaultFilters.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isTrue();\n\t\tassertThat(excludes(filter, Controller2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleInstrumentation.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWithIncludeFilter() throws Exception {\n\t\tGraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithIncludeFilter.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleInstrumentation.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWithExcludeFilter() throws Exception {\n\t\tGraphQlTypeExcludeFilter filter = new GraphQlTypeExcludeFilter(WithExcludeFilter.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isTrue();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleRuntimeWiringConfigurer.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebInterceptor.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleDataFetcherExceptionResolver.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleInstrumentation.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleGraphQlSourceBuilderCustomizer.class)).isFalse();\n\t}\n\n\tprivate boolean excludes(GraphQlTypeExcludeFilter filter, Class<?> type) throws IOException {\n\t\tMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());\n\t\treturn filter.match(metadataReader, this.metadataReaderFactory);\n\t}\n\n\t@GraphQlTest\n\tstatic class WithNoControllers {\n\n\t}\n\n\t@GraphQlTest(Controller1.class)\n\tstatic class WithController {\n\n\t}\n\n\t@GraphQlTest(useDefaultFilters = false)\n\tstatic class NotUsingDefaultFilters {\n\n\t}\n\n\t@GraphQlTest(includeFilters = @ComponentScan.Filter(Repository.class))\n\tstatic class WithIncludeFilter {\n\n\t}\n\n\t@GraphQlTest(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Controller1.class))\n\tstatic class WithExcludeFilter {\n\n\t}\n\n\t@Controller\n\tstatic class Controller1 {\n\n\t}\n\n\t@Controller\n\tstatic class Controller2 {\n\n\t}\n\n\t@ControllerAdvice\n\tstatic class ExampleControllerAdvice {\n\n\t}\n\n\t@Service\n\tstatic class ExampleService {\n\n\t}\n\n\t@Repository\n\tstatic class ExampleRepository {\n\n\t}\n\n\tstatic class ExampleRuntimeWiringConfigurer implements RuntimeWiringConfigurer {\n\n\t\t@Override\n\t\tpublic void configure(RuntimeWiring.Builder builder) {\n\n\t\t}\n\n\t}\n\n\tstatic class ExampleWebInterceptor implements WebGraphQlInterceptor {\n\n\t\t@Override\n\t\tpublic Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {\n\t\t\treturn Mono.empty();\n\t\t}\n\n\t}\n\n\tstatic class ExampleModule extends SimpleModule {\n\n\t}\n\n\tstatic class ExampleDataFetcherExceptionResolver implements DataFetcherExceptionResolver {\n\n\t\t@Override\n\t\tpublic Mono<List<GraphQLError>> resolveException(Throwable exception, DataFetchingEnvironment environment) {\n\t\t\treturn Mono.empty();\n\t\t}\n\n\t}\n\n\tstatic class ExampleInstrumentation implements Instrumentation {\n\n\t}\n\n\tstatic class ExampleGraphQlSourceBuilderCustomizer implements GraphQlSourceBuilderCustomizer {\n\n\t\t@Override\n\t\tpublic void customize(GraphQlSource.SchemaResourceBuilder builder) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/tester/GraphQlTesterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.graphql.ExecutionGraphQlService;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GraphQlTesterAutoConfiguration}.\n *\n * @author Brian Clozel\n */\nclass GraphQlTesterAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, GraphQlTesterAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotContributeTesterIfGraphQlServiceNotPresent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasNotFailed().doesNotHaveBean(GraphQlTester.class));\n\t}\n\n\t@Test\n\tvoid shouldContributeTester() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGraphQlServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed().hasSingleBean(GraphQlTester.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomGraphQlServiceConfiguration {\n\n\t\t@Bean\n\t\tExecutionGraphQlService graphQlService() {\n\t\t\treturn mock(ExecutionGraphQlService.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/tester/HttpGraphQlTesterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.graphql.test.autoconfigure.tester;\n\nimport java.net.URI;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webtestclient.autoconfigure.WebTestClientAutoConfiguration;\nimport org.springframework.graphql.test.tester.HttpGraphQlTester;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.web.util.UriBuilderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpGraphQlTesterAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass HttpGraphQlTesterAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpGraphQlTesterAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotContributeTesterIfWebTestClientNotPresent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpGraphQlTester.class));\n\t}\n\n\t@Test\n\tvoid shouldContributeTesterBoutToMockMvc() {\n\t\tthis.contextRunner.withBean(MockMvc.class, () -> mock(MockMvc.class))\n\t\t\t.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpGraphQlTester.class);\n\t\t\t\tassertThat(context.getBean(HttpGraphQlTester.class)).extracting(\"webTestClient\")\n\t\t\t\t\t.extracting(\"builder\")\n\t\t\t\t\t.extracting(\"baseUrl\")\n\t\t\t\t\t.isEqualTo(\"/graphql\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\t\t\torg.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestLocalTestWebServerProvider\n\t\t\t\t\t\"\"\")\n\tvoid shouldContributeTesterBoundToHttpServer() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpGraphQlTester.class);\n\t\t\t\tassertThat(context.getBean(HttpGraphQlTester.class)).extracting(\"webTestClient\")\n\t\t\t\t\t.extracting(\"builder\")\n\t\t\t\t\t.extracting(\"uriBuilderFactory\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(UriBuilderFactory.class))\n\t\t\t\t\t.satisfies((uriBuilderFactory) -> assertThat(uriBuilderFactory.uriString(\"/something\").build())\n\t\t\t\t\t\t.isEqualTo(URI.create(\"https://localhost:4242/graphql/something\")));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\t\t\torg.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestLocalTestWebServerProvider\n\t\t\t\t\t\"\"\")\n\tvoid shouldContributeTesterBoundToHttpServerUsingCustomGraphQlHttpPath() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.graphql.http.path=/api/graphql\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpGraphQlTester.class);\n\t\t\t\tassertThat(context.getBean(HttpGraphQlTester.class)).extracting(\"webTestClient\")\n\t\t\t\t\t.extracting(\"builder\")\n\t\t\t\t\t.extracting(\"uriBuilderFactory\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(UriBuilderFactory.class))\n\t\t\t\t\t.satisfies((uriBuilderFactory) -> assertThat(uriBuilderFactory.uriString(\"/something\").build())\n\t\t\t\t\t\t.isEqualTo(URI.create(\"https://localhost:4242/api/graphql/something\")));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\treturn LocalTestWebServer.of(Scheme.HTTPS, 4242);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-graphql-test/src/test/resources/graphql/schema.graphqls",
    "content": "type Query {\n    bookById(id: ID): Book\n}\n\ntype Book {\n    id: ID\n    name: String\n    pageCount: Int\n    author: String\n}"
  },
  {
    "path": "module/spring-boot-groovy-templates/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Groovy Templates\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.apache.groovy:groovy-templates\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplateAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\n\nimport groovy.text.markup.MarkupTemplateEngine;\nimport jakarta.servlet.Servlet;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.template.TemplateLocation;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.web.servlet.view.UrlBasedViewResolver;\nimport org.springframework.web.servlet.view.groovy.GroovyMarkupConfig;\nimport org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer;\nimport org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;\n\n/**\n * Auto-configuration support for Groovy templates in MVC. By default creates a\n * {@link MarkupTemplateEngine} configured from {@link GroovyTemplateProperties}, but you\n * can override that by providing your own {@link GroovyMarkupConfig} or even a\n * {@link MarkupTemplateEngine} of a different type.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(MarkupTemplateEngine.class)\n@EnableConfigurationProperties(GroovyTemplateProperties.class)\npublic final class GroovyTemplateAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(GroovyTemplateAutoConfiguration.class);\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(GroovyMarkupConfigurer.class)\n\tstatic class GroovyMarkupConfiguration {\n\n\t\tprivate final ApplicationContext applicationContext;\n\n\t\tprivate final GroovyTemplateProperties properties;\n\n\t\tGroovyMarkupConfiguration(ApplicationContext applicationContext, GroovyTemplateProperties properties) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t\tthis.properties = properties;\n\t\t\tcheckTemplateLocationExists();\n\t\t}\n\n\t\tprivate void checkTemplateLocationExists() {\n\t\t\tif (this.properties.isCheckTemplateLocation() && !isUsingGroovyAllJar()) {\n\t\t\t\tTemplateLocation location = new TemplateLocation(this.properties.getResourceLoaderPath());\n\t\t\t\tif (!location.exists(this.applicationContext)) {\n\t\t\t\t\tlogger.warn(LogMessage.format(\n\t\t\t\t\t\t\t\"Cannot find template location: %s (please add some templates, check your Groovy \"\n\t\t\t\t\t\t\t\t\t+ \"configuration, or set spring.groovy.template.check-template-location=false)\",\n\t\t\t\t\t\t\tlocation));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * MarkupTemplateEngine could be loaded from groovy-templates or groovy-all.\n\t\t * Unfortunately it's quite common for people to use groovy-all and not actually\n\t\t * need templating support. This method attempts to check the source jar so that\n\t\t * we can skip the {@code /template} directory check for such cases.\n\t\t * @return true if the groovy-all jar is used\n\t\t */\n\t\tprivate boolean isUsingGroovyAllJar() {\n\t\t\ttry {\n\t\t\t\tProtectionDomain domain = MarkupTemplateEngine.class.getProtectionDomain();\n\t\t\t\tCodeSource codeSource = domain.getCodeSource();\n\t\t\t\treturn codeSource != null && codeSource.getLocation().toString().contains(\"-all\");\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(GroovyMarkupConfig.class)\n\t\tGroovyMarkupConfigurer groovyMarkupConfigurer(ObjectProvider<MarkupTemplateEngine> templateEngine,\n\t\t\t\tEnvironment environment) {\n\t\t\tGroovyMarkupConfigurer configurer = new GroovyMarkupConfigurer();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this.properties::isAutoEscape).to(configurer::setAutoEscape);\n\t\t\tmap.from(this.properties::isAutoIndent).to(configurer::setAutoIndent);\n\t\t\tmap.from(this.properties::getAutoIndentString).to(configurer::setAutoIndentString);\n\t\t\tmap.from(this.properties::isAutoNewLine).to(configurer::setAutoNewLine);\n\t\t\tmap.from(this.properties::getBaseTemplateClass).to(configurer::setBaseTemplateClass);\n\t\t\tmap.from(this.properties::isCache).to(configurer::setCacheTemplates);\n\t\t\tmap.from(this.properties::getDeclarationEncoding).to(configurer::setDeclarationEncoding);\n\t\t\tmap.from(this.properties::isExpandEmptyElements).to(configurer::setExpandEmptyElements);\n\t\t\tmap.from(this.properties::getLocale).to(configurer::setLocale);\n\t\t\tmap.from(this.properties::getNewLineString).to(configurer::setNewLineString);\n\t\t\tmap.from(this.properties::getResourceLoaderPath).to(configurer::setResourceLoaderPath);\n\t\t\tmap.from(this.properties::isUseDoubleQuotes).to(configurer::setUseDoubleQuotes);\n\t\t\tBinder.get(environment).bind(\"spring.groovy.template.configuration\", Bindable.ofInstance(configurer));\n\t\t\ttemplateEngine.ifAvailable(configurer::setTemplateEngine);\n\t\t\treturn configurer;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ Servlet.class, LocaleContextHolder.class, UrlBasedViewResolver.class })\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\tstatic class GroovyWebConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = \"groovyMarkupViewResolver\")\n\t\tGroovyMarkupViewResolver groovyMarkupViewResolver(GroovyTemplateProperties properties) {\n\t\t\tGroovyMarkupViewResolver resolver = new GroovyMarkupViewResolver();\n\t\t\tproperties.applyToMvcViewResolver(resolver);\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.autoconfigure.template.PathBasedTemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TemplateAvailabilityProvider} that provides availability information for Groovy\n * view templates.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\npublic class GroovyTemplateAvailabilityProvider extends PathBasedTemplateAvailabilityProvider {\n\n\tprivate static final String REQUIRED_CLASS_NAME = \"groovy.text.TemplateEngine\";\n\n\tpublic GroovyTemplateAvailabilityProvider() {\n\t\tsuper(REQUIRED_CLASS_NAME, GroovyTemplateAvailabilityProperties.class, \"spring.groovy.template\");\n\t}\n\n\tprotected static final class GroovyTemplateAvailabilityProperties extends TemplateAvailabilityProperties {\n\n\t\tprivate List<String> resourceLoaderPath = new ArrayList<>(\n\t\t\t\tArrays.asList(GroovyTemplateProperties.DEFAULT_RESOURCE_LOADER_PATH));\n\n\t\tGroovyTemplateAvailabilityProperties() {\n\t\t\tsuper(GroovyTemplateProperties.DEFAULT_PREFIX, GroovyTemplateProperties.DEFAULT_SUFFIX);\n\t\t}\n\n\t\t@Override\n\t\tprotected List<String> getLoaderPath() {\n\t\t\treturn this.resourceLoaderPath;\n\t\t}\n\n\t\tpublic List<String> getResourceLoaderPath() {\n\t\t\treturn this.resourceLoaderPath;\n\t\t}\n\n\t\tpublic void setResourceLoaderPath(List<String> resourceLoaderPath) {\n\t\t\tthis.resourceLoaderPath = resourceLoaderPath;\n\t\t}\n\n\t}\n\n\tstatic class GroovyTemplateAvailabilityRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tif (ClassUtils.isPresent(REQUIRED_CLASS_NAME, classLoader)) {\n\t\t\t\tBindableRuntimeHintsRegistrar.forTypes(GroovyTemplateAvailabilityProperties.class)\n\t\t\t\t\t.registerHints(hints, classLoader);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplateProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport groovy.text.markup.BaseTemplate;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\nimport org.springframework.util.MimeType;\nimport org.springframework.web.servlet.view.AbstractTemplateViewResolver;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Groovy\n * templates.\n *\n * @author Dave Syer\n * @author Marten Deinum\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.groovy.template\")\npublic class GroovyTemplateProperties {\n\n\tpublic static final String DEFAULT_RESOURCE_LOADER_PATH = \"classpath:/templates/\";\n\n\tpublic static final String DEFAULT_PREFIX = \"\";\n\n\tpublic static final String DEFAULT_SUFFIX = \".tpl\";\n\n\tpublic static final String DEFAULT_REQUEST_CONTEXT_ATTRIBUTE = \"spring\";\n\n\tprivate static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf(\"text/html\");\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\t/**\n\t * Whether to enable template caching.\n\t */\n\tprivate boolean cache;\n\n\t/**\n\t * Content-Type value.\n\t */\n\tprivate MimeType contentType = DEFAULT_CONTENT_TYPE;\n\n\t/**\n\t * Template encoding.\n\t */\n\tprivate Charset charset = DEFAULT_CHARSET;\n\n\t/**\n\t * View names that can be resolved.\n\t */\n\tprivate String @Nullable [] viewNames;\n\n\t/**\n\t * Whether to check that the templates location exists.\n\t */\n\tprivate boolean checkTemplateLocation = true;\n\n\t/**\n\t * Prefix that gets prepended to view names when building a URL.\n\t */\n\tprivate String prefix = DEFAULT_PREFIX;\n\n\t/**\n\t * Suffix that gets appended to view names when building a URL.\n\t */\n\tprivate String suffix = DEFAULT_SUFFIX;\n\n\t/**\n\t * Name of the RequestContext attribute for all views.\n\t */\n\tprivate String requestContextAttribute = DEFAULT_REQUEST_CONTEXT_ATTRIBUTE;\n\n\t/**\n\t * Whether all request attributes should be added to the model prior to merging with\n\t * the template.\n\t */\n\tprivate boolean exposeRequestAttributes;\n\n\t/**\n\t * Whether all HttpSession attributes should be added to the model prior to merging\n\t * with the template.\n\t */\n\tprivate boolean exposeSessionAttributes;\n\n\t/**\n\t * Whether HttpServletRequest attributes are allowed to override (hide) controller\n\t * generated model attributes of the same name.\n\t */\n\tprivate boolean allowRequestOverride;\n\n\t/**\n\t * Whether to expose a RequestContext for use by Spring's macro library, under the\n\t * name \"springMacroRequestContext\".\n\t */\n\tprivate boolean exposeSpringMacroHelpers = true;\n\n\t/**\n\t * Whether HttpSession attributes are allowed to override (hide) controller generated\n\t * model attributes of the same name.\n\t */\n\tprivate boolean allowSessionOverride;\n\n\t/**\n\t * Whether models that are assignable to CharSequence are escaped automatically.\n\t */\n\tprivate boolean autoEscape;\n\n\t/**\n\t * Whether indents are rendered automatically.\n\t */\n\tprivate boolean autoIndent;\n\n\t/**\n\t * String used for auto-indents.\n\t */\n\tprivate @Nullable String autoIndentString;\n\n\t/**\n\t * Whether new lines are rendered automatically.\n\t */\n\tprivate boolean autoNewLine;\n\n\t/**\n\t * Template base class.\n\t */\n\tprivate Class<? extends BaseTemplate> baseTemplateClass = BaseTemplate.class;\n\n\t/**\n\t * Encoding used to write the declaration heading.\n\t */\n\tprivate @Nullable String declarationEncoding;\n\n\t/**\n\t * Whether elements without a body should be written expanded (&lt;br&gt;&lt;/br&gt;)\n\t * or not (&lt;br/&gt;).\n\t */\n\tprivate boolean expandEmptyElements;\n\n\t/**\n\t * Default locale for template resolution.\n\t */\n\tprivate @Nullable Locale locale;\n\n\t/**\n\t * String used to write a new line. Defaults to the system's line separator.\n\t */\n\tprivate @Nullable String newLineString;\n\n\t/**\n\t * Template path.\n\t */\n\tprivate String resourceLoaderPath = DEFAULT_RESOURCE_LOADER_PATH;\n\n\t/**\n\t * Whether attributes should use double quotes.\n\t */\n\tprivate boolean useDoubleQuotes;\n\n\tpublic boolean isCheckTemplateLocation() {\n\t\treturn this.checkTemplateLocation;\n\t}\n\n\tpublic void setCheckTemplateLocation(boolean checkTemplateLocation) {\n\t\tthis.checkTemplateLocation = checkTemplateLocation;\n\t}\n\n\tpublic String @Nullable [] getViewNames() {\n\t\treturn this.viewNames;\n\t}\n\n\tpublic void setViewNames(String @Nullable [] viewNames) {\n\t\tthis.viewNames = viewNames;\n\t}\n\n\tpublic boolean isCache() {\n\t\treturn this.cache;\n\t}\n\n\tpublic void setCache(boolean cache) {\n\t\tthis.cache = cache;\n\t}\n\n\tpublic MimeType getContentType() {\n\t\tif (this.contentType.getCharset() == null) {\n\t\t\tMap<String, String> parameters = new LinkedHashMap<>();\n\t\t\tparameters.put(\"charset\", this.charset.name());\n\t\t\tparameters.putAll(this.contentType.getParameters());\n\t\t\treturn new MimeType(this.contentType, parameters);\n\t\t}\n\t\treturn this.contentType;\n\t}\n\n\tpublic void setContentType(MimeType contentType) {\n\t\tthis.contentType = contentType;\n\t}\n\n\tpublic Charset getCharset() {\n\t\treturn this.charset;\n\t}\n\n\tpublic @Nullable String getCharsetName() {\n\t\treturn (this.charset != null) ? this.charset.name() : null;\n\t}\n\n\tpublic void setCharset(Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\tpublic boolean isAutoEscape() {\n\t\treturn this.autoEscape;\n\t}\n\n\tpublic void setAutoEscape(boolean autoEscape) {\n\t\tthis.autoEscape = autoEscape;\n\t}\n\n\tpublic boolean isAutoIndent() {\n\t\treturn this.autoIndent;\n\t}\n\n\tpublic void setAutoIndent(boolean autoIndent) {\n\t\tthis.autoIndent = autoIndent;\n\t}\n\n\tpublic @Nullable String getAutoIndentString() {\n\t\treturn this.autoIndentString;\n\t}\n\n\tpublic void setAutoIndentString(@Nullable String autoIndentString) {\n\t\tthis.autoIndentString = autoIndentString;\n\t}\n\n\tpublic boolean isAutoNewLine() {\n\t\treturn this.autoNewLine;\n\t}\n\n\tpublic void setAutoNewLine(boolean autoNewLine) {\n\t\tthis.autoNewLine = autoNewLine;\n\t}\n\n\tpublic Class<? extends BaseTemplate> getBaseTemplateClass() {\n\t\treturn this.baseTemplateClass;\n\t}\n\n\tpublic void setBaseTemplateClass(Class<? extends BaseTemplate> baseTemplateClass) {\n\t\tthis.baseTemplateClass = baseTemplateClass;\n\t}\n\n\tpublic @Nullable String getDeclarationEncoding() {\n\t\treturn this.declarationEncoding;\n\t}\n\n\tpublic void setDeclarationEncoding(@Nullable String declarationEncoding) {\n\t\tthis.declarationEncoding = declarationEncoding;\n\t}\n\n\tpublic boolean isExpandEmptyElements() {\n\t\treturn this.expandEmptyElements;\n\t}\n\n\tpublic void setExpandEmptyElements(boolean expandEmptyElements) {\n\t\tthis.expandEmptyElements = expandEmptyElements;\n\t}\n\n\tpublic @Nullable Locale getLocale() {\n\t\treturn this.locale;\n\t}\n\n\tpublic void setLocale(@Nullable Locale locale) {\n\t\tthis.locale = locale;\n\t}\n\n\tpublic @Nullable String getNewLineString() {\n\t\treturn this.newLineString;\n\t}\n\n\tpublic void setNewLineString(@Nullable String newLineString) {\n\t\tthis.newLineString = newLineString;\n\t}\n\n\tpublic String getResourceLoaderPath() {\n\t\treturn this.resourceLoaderPath;\n\t}\n\n\tpublic void setResourceLoaderPath(String resourceLoaderPath) {\n\t\tthis.resourceLoaderPath = resourceLoaderPath;\n\t}\n\n\tpublic boolean isUseDoubleQuotes() {\n\t\treturn this.useDoubleQuotes;\n\t}\n\n\tpublic void setUseDoubleQuotes(boolean useDoubleQuotes) {\n\t\tthis.useDoubleQuotes = useDoubleQuotes;\n\t}\n\n\tpublic String getPrefix() {\n\t\treturn this.prefix;\n\t}\n\n\tpublic void setPrefix(String prefix) {\n\t\tthis.prefix = prefix;\n\t}\n\n\tpublic String getSuffix() {\n\t\treturn this.suffix;\n\t}\n\n\tpublic void setSuffix(String suffix) {\n\t\tthis.suffix = suffix;\n\t}\n\n\tpublic String getRequestContextAttribute() {\n\t\treturn this.requestContextAttribute;\n\t}\n\n\tpublic void setRequestContextAttribute(String requestContextAttribute) {\n\t\tthis.requestContextAttribute = requestContextAttribute;\n\t}\n\n\tpublic boolean isExposeRequestAttributes() {\n\t\treturn this.exposeRequestAttributes;\n\t}\n\n\tpublic void setExposeRequestAttributes(boolean exposeRequestAttributes) {\n\t\tthis.exposeRequestAttributes = exposeRequestAttributes;\n\t}\n\n\tpublic boolean isExposeSessionAttributes() {\n\t\treturn this.exposeSessionAttributes;\n\t}\n\n\tpublic void setExposeSessionAttributes(boolean exposeSessionAttributes) {\n\t\tthis.exposeSessionAttributes = exposeSessionAttributes;\n\t}\n\n\tpublic boolean isAllowRequestOverride() {\n\t\treturn this.allowRequestOverride;\n\t}\n\n\tpublic void setAllowRequestOverride(boolean allowRequestOverride) {\n\t\tthis.allowRequestOverride = allowRequestOverride;\n\t}\n\n\tpublic boolean isAllowSessionOverride() {\n\t\treturn this.allowSessionOverride;\n\t}\n\n\tpublic void setAllowSessionOverride(boolean allowSessionOverride) {\n\t\tthis.allowSessionOverride = allowSessionOverride;\n\t}\n\n\tpublic boolean isExposeSpringMacroHelpers() {\n\t\treturn this.exposeSpringMacroHelpers;\n\t}\n\n\tpublic void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {\n\t\tthis.exposeSpringMacroHelpers = exposeSpringMacroHelpers;\n\t}\n\n\t/**\n\t * Apply the given properties to a {@link AbstractTemplateViewResolver}. Use Object in\n\t * signature to avoid runtime dependency on MVC, which means that the template engine\n\t * can be used in a non-web application.\n\t * @param viewResolver the resolver to apply the properties to.\n\t */\n\tpublic void applyToMvcViewResolver(Object viewResolver) {\n\t\tAssert.isInstanceOf(AbstractTemplateViewResolver.class, viewResolver,\n\t\t\t\t() -> \"ViewResolver is not an instance of AbstractTemplateViewResolver :\" + viewResolver);\n\t\tAbstractTemplateViewResolver resolver = (AbstractTemplateViewResolver) viewResolver;\n\t\tresolver.setPrefix(getPrefix());\n\t\tresolver.setSuffix(getSuffix());\n\t\tresolver.setCache(isCache());\n\t\tMimeType contentType = getContentType();\n\t\tif (contentType != null) {\n\t\t\tresolver.setContentType(contentType.toString());\n\t\t}\n\t\tresolver.setViewNames(getViewNames());\n\t\tresolver.setExposeRequestAttributes(isExposeRequestAttributes());\n\t\tresolver.setAllowRequestOverride(isAllowRequestOverride());\n\t\tresolver.setAllowSessionOverride(isAllowSessionOverride());\n\t\tresolver.setExposeSessionAttributes(isExposeSessionAttributes());\n\t\tresolver.setExposeSpringMacroHelpers(isExposeSpringMacroHelpers());\n\t\tresolver.setRequestContextAttribute(getRequestContextAttribute());\n\t\t// The resolver usually acts as a fallback resolver (e.g. like a\n\t\t// InternalResourceViewResolver) so it needs to have low precedence\n\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/java/org/springframework/boot/groovy/template/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Groovy templates.\n */\n@NullMarked\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.groovy.template.configuration.auto-escape\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.auto-escape\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.auto-indent\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.auto-indent\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.auto-indent-string\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.auto-indent-string\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.auto-new-line\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.auto-new-line\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.base-template-class\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.base-template-class\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.cache-templates\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.cache\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.declaration-encoding\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.declaration-encoding\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.expand-empty-elements\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.expand-empty-elements\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.locale\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.locale\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.new-line-string\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.new-line-string\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.resource-loader-path\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.resource-loader-path\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.configuration.use-double-quotes\",\n      \"deprecation\": {\n        \"replacement\": \"spring.groovy.template.use-double-quotes\",\n        \"level\": \"warning\",\n        \"since\": \"3.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"No longer required. To use Groovy Templates without auto-configuration, depend directly on Groovy Templates instead of spring-boot-groovy-templates.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.groovy.template.prefix\",\n      \"defaultValue\": \"\"\n    },\n    {\n      \"name\": \"spring.groovy.template.suffix\",\n      \"defaultValue\": \".tpl\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.groovy.template.autoconfigure.GroovyTemplateAvailabilityProvider$GroovyTemplateAvailabilityRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.groovy.template.autoconfigure.GroovyTemplateAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.groovy.template.autoconfigure.GroovyTemplateAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.groovy.template.cache=false\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/main/resources/META-INF/spring.factories",
    "content": "# Template Availability Providers\norg.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\\\norg.springframework.boot.groovy.template.autoconfigure.GroovyTemplateAvailabilityProvider\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/test/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplateAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport java.io.File;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport groovy.text.markup.BaseTemplate;\nimport groovy.text.markup.DelegatingIndentWriter;\nimport groovy.text.markup.MarkupTemplateEngine;\nimport groovy.text.markup.TemplateConfiguration;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.support.RequestContext;\nimport org.springframework.web.servlet.view.groovy.GroovyMarkupConfig;\nimport org.springframework.web.servlet.view.groovy.GroovyMarkupConfigurer;\nimport org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GroovyTemplateAutoConfiguration}.\n *\n * @author Dave Syer\n */\nclass GroovyTemplateAutoConfigurationTests {\n\n\tprivate final BuildOutput buildOutput = new BuildOutput(getClass());\n\n\tprivate final AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\n\t@BeforeEach\n\tvoid setupContext() {\n\t\tthis.context.setServletContext(new MockServletContext());\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tLocaleContextHolder.resetLocaleContext();\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupViewResolver.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid emptyTemplateLocation() {\n\t\tnew File(this.buildOutput.getTestResourcesLocation(), \"empty-templates/empty-directory\").mkdirs();\n\t\tregisterAndRefreshContext(\"spring.groovy.template.resource-loader-path:classpath:/templates/empty-directory/\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.tpl\", content = \"yield 'home'\")\n\tvoid defaultViewResolution() throws Exception {\n\t\tregisterAndRefreshContext();\n\t\tMockHttpServletResponse response = render(\"home\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"home\");\n\t\tassertThat(response.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/includes.tpl\", content = \"\"\"\n\t\t\tyield 'include'\n\t\t\tinclude template: 'included.tpl'\n\t\t\t\"\"\")\n\t@WithResource(name = \"templates/included.tpl\", content = \"yield 'here'\")\n\tvoid includesViewResolution() throws Exception {\n\t\tregisterAndRefreshContext();\n\t\tMockHttpServletResponse response = render(\"includes\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"here\");\n\t\tassertThat(response.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/includes.tpl\", content = \"\"\"\n\t\t\tyield 'include'\n\t\t\tinclude template: 'included.tpl'\n\t\t\t\"\"\")\n\t@WithResource(name = \"templates/included_fr.tpl\", content = \"yield 'voila'\")\n\tvoid localeViewResolution() throws Exception {\n\t\tregisterAndRefreshContext();\n\t\tMockHttpServletResponse response = render(\"includes\", Locale.FRENCH);\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"voila\");\n\t\tassertThat(response.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.tpl\", content = \"yield 'home'\")\n\tvoid customContentType() throws Exception {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.contentType:application/json\");\n\t\tMockHttpServletResponse response = render(\"home\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"home\");\n\t\tassertThat(response.getContentType()).isEqualTo(\"application/json;charset=UTF-8\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/prefix/prefixed.tpl\", content = \"yield \\\"prefixed\\\"\")\n\tvoid customPrefix() throws Exception {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.prefix:prefix/\");\n\t\tMockHttpServletResponse response = render(\"prefixed\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"prefixed\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/suffixed.groovytemplate\", content = \"yield \\\"suffixed\\\"\")\n\tvoid customSuffix() throws Exception {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.suffix:.groovytemplate\");\n\t\tMockHttpServletResponse response = render(\"suffixed\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"suffixed\");\n\t}\n\n\t@Test\n\tvoid defaultResourceLoaderPath() throws Exception {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getResourceLoaderPath())\n\t\t\t.isEqualTo(GroovyTemplateProperties.DEFAULT_RESOURCE_LOADER_PATH);\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.tpl\", content = \"yield \\\"custom\\\"\")\n\tvoid customResourceLoaderPath() throws Exception {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.resource-loader-path:classpath:/custom-templates/\");\n\t\tMockHttpServletResponse response = render(\"custom\");\n\t\tString result = response.getContentAsString();\n\t\tassertThat(result).contains(\"custom\");\n\t}\n\n\t@Test\n\tvoid disableCache() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.cache:false\");\n\t\tassertThat(this.context.getBean(GroovyMarkupViewResolver.class).getCacheLimit()).isZero();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/message.tpl\", content = \"yield \\\"Message: ${greeting}\\\"\")\n\tvoid renderTemplate() throws Exception {\n\t\tregisterAndRefreshContext();\n\t\tGroovyMarkupConfig config = this.context.getBean(GroovyMarkupConfig.class);\n\t\tMarkupTemplateEngine engine = config.getTemplateEngine();\n\t\tWriter writer = new StringWriter();\n\t\tengine.createTemplate(new ClassPathResource(\"templates/message.tpl\").getFile())\n\t\t\t.make(new HashMap<>(Collections.singletonMap(\"greeting\", \"Hello World\")))\n\t\t\t.writeTo(writer);\n\t\tassertThat(writer.toString()).contains(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid enableAutoEscape() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.auto-escape:true\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).isAutoEscape()).isTrue();\n\t}\n\n\t@Test\n\tvoid enableAutoIndent() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.auto-indent:true\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).isAutoIndent()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultAutoIndentString() {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getAutoIndentString())\n\t\t\t.isEqualTo(DelegatingIndentWriter.SPACES);\n\t}\n\n\t@Test\n\tvoid customAutoIndentString() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.auto-indent-string:\\\\t\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getAutoIndentString()).isEqualTo(\"\\\\t\");\n\t}\n\n\t@Test\n\tvoid enableAutoNewLine() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.auto-new-line:true\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).isAutoNewLine()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultBaseTemplateClass() {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getBaseTemplateClass())\n\t\t\t.isEqualTo(BaseTemplate.class);\n\t}\n\n\t@Test\n\tvoid customBaseTemplateClass() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.base-template-class:\" + CustomBaseTemplate.class.getName());\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getBaseTemplateClass())\n\t\t\t.isEqualTo(CustomBaseTemplate.class);\n\t}\n\n\t@Test\n\tvoid defaultDeclarationEncoding() {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getDeclarationEncoding()).isNull();\n\t}\n\n\t@Test\n\tvoid customDeclarationEncoding() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.declaration-encoding:UTF-8\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getDeclarationEncoding()).isEqualTo(\"UTF-8\");\n\t}\n\n\t@Test\n\tvoid enableExpandEmptyElements() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.expand-empty-elements:true\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).isExpandEmptyElements()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultLocale() {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getLocale()).isEqualTo(Locale.getDefault());\n\t}\n\n\t@Test\n\tvoid customLocale() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.locale:en_US\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getLocale()).isEqualTo(Locale.US);\n\t}\n\n\t@Test\n\tvoid defaultNewLineString() {\n\t\tregisterAndRefreshContext();\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getNewLineString())\n\t\t\t.isEqualTo(System.lineSeparator());\n\t}\n\n\t@Test\n\tvoid customNewLineString() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.new-line-string:\\\\r\\\\n\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).getNewLineString()).isEqualTo(\"\\\\r\\\\n\");\n\t}\n\n\t@Test\n\tvoid enableUseDoubleQuotes() {\n\t\tregisterAndRefreshContext(\"spring.groovy.template.use-double-quotes:true\");\n\t\tassertThat(this.context.getBean(GroovyMarkupConfigurer.class).isUseDoubleQuotes()).isTrue();\n\t}\n\n\tprivate void registerAndRefreshContext(String... env) {\n\t\tTestPropertyValues.of(env).applyTo(this.context);\n\t\tthis.context.register(GroovyTemplateAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t}\n\n\tprivate MockHttpServletResponse render(String viewName) throws Exception {\n\t\treturn render(viewName, Locale.UK);\n\t}\n\n\tprivate MockHttpServletResponse render(String viewName, Locale locale) throws Exception {\n\t\tLocaleContextHolder.setLocale(locale);\n\t\tGroovyMarkupViewResolver resolver = this.context.getBean(GroovyMarkupViewResolver.class);\n\t\tView view = resolver.resolveViewName(viewName, locale);\n\t\tassertThat(view).isNotNull();\n\t\tHttpServletRequest request = new MockHttpServletRequest();\n\t\trequest.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tview.render(null, request, response);\n\t\treturn response;\n\t}\n\n\tstatic class CustomBaseTemplate extends BaseTemplate {\n\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tCustomBaseTemplate(MarkupTemplateEngine templateEngine, Map model, Map<String, String> modelTypes,\n\t\t\t\tTemplateConfiguration configuration) {\n\t\t\tsuper(templateEngine, model, modelTypes, configuration);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object run() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/test/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplateAvailabilityProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.beans.factory.aot.AotServices;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.groovy.template.autoconfigure.GroovyTemplateAvailabilityProvider.GroovyTemplateAvailabilityProperties;\nimport org.springframework.boot.groovy.template.autoconfigure.GroovyTemplateAvailabilityProvider.GroovyTemplateAvailabilityRuntimeHints;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GroovyTemplateAvailabilityProvider}.\n *\n * @author Andy Wilkinson\n */\nclass GroovyTemplateAvailabilityProviderTests {\n\n\tprivate final TemplateAvailabilityProvider provider = new GroovyTemplateAvailabilityProvider();\n\n\tprivate final ResourceLoader resourceLoader = new DefaultResourceLoader();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\t@WithResource(name = \"templates/home.tpl\")\n\tvoid availabilityOfTemplateInDefaultLocation() {\n\t\tassertThat(this.provider.isTemplateAvailable(\"home\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid availabilityOfTemplateThatDoesNotExist() {\n\t\tassertThat(this.provider.isTemplateAvailable(\"whatever\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.tpl\")\n\tvoid availabilityOfTemplateWithCustomLoaderPath() {\n\t\tthis.environment.setProperty(\"spring.groovy.template.resource-loader-path\", \"classpath:/custom-templates/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"custom\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.tpl\")\n\tvoid availabilityOfTemplateWithCustomLoaderPathConfiguredAsAList() {\n\t\tthis.environment.setProperty(\"spring.groovy.template.resource-loader-path[0]\", \"classpath:/custom-templates/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"custom\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/prefix/prefixed.tpl\")\n\tvoid availabilityOfTemplateWithCustomPrefix() {\n\t\tthis.environment.setProperty(\"spring.groovy.template.prefix\", \"prefix/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"prefixed\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/suffixed.groovytemplate\")\n\tvoid availabilityOfTemplateWithCustomSuffix() {\n\t\tthis.environment.setProperty(\"spring.groovy.template.suffix\", \".groovytemplate\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"suffixed\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid shouldRegisterGroovyTemplateAvailabilityPropertiesRuntimeHints() {\n\t\tassertThat(AotServices.factories().load(RuntimeHintsRegistrar.class))\n\t\t\t.hasAtLeastOneElementOfType(GroovyTemplateAvailabilityRuntimeHints.class);\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew GroovyTemplateAvailabilityRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tTypeHint typeHint = hints.reflection().getTypeHint(GroovyTemplateAvailabilityProperties.class);\n\t\tassertThat(typeHint).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/test/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplatePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.MimeTypeUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GroovyTemplateProperties}.\n *\n * @author Stephane Nicoll\n */\nclass GroovyTemplatePropertiesTests {\n\n\t@Test\n\tvoid defaultContentType() {\n\t\tassertThat(new GroovyTemplateProperties().getContentType()).hasToString(\"text/html;charset=UTF-8\");\n\t}\n\n\t@Test\n\tvoid customContentTypeDefaultCharset() {\n\t\tGroovyTemplateProperties properties = new GroovyTemplateProperties();\n\t\tproperties.setContentType(MimeTypeUtils.parseMimeType(\"text/plain\"));\n\t\tassertThat(properties.getContentType()).hasToString(\"text/plain;charset=UTF-8\");\n\t}\n\n\t@Test\n\tvoid defaultContentTypeCustomCharset() {\n\t\tGroovyTemplateProperties properties = new GroovyTemplateProperties();\n\t\tproperties.setCharset(StandardCharsets.UTF_16);\n\t\tassertThat(properties.getContentType()).hasToString(\"text/html;charset=UTF-16\");\n\t}\n\n\t@Test\n\tvoid customContentTypeCustomCharset() {\n\t\tGroovyTemplateProperties properties = new GroovyTemplateProperties();\n\t\tproperties.setContentType(MimeTypeUtils.parseMimeType(\"text/plain\"));\n\t\tproperties.setCharset(StandardCharsets.UTF_16);\n\t\tassertThat(properties.getContentType()).hasToString(\"text/plain;charset=UTF-16\");\n\t}\n\n\t@Test\n\tvoid customContentTypeWithPropertyAndCustomCharset() {\n\t\tGroovyTemplateProperties properties = new GroovyTemplateProperties();\n\t\tproperties.setContentType(MimeTypeUtils.parseMimeType(\"text/plain;foo=bar\"));\n\t\tproperties.setCharset(StandardCharsets.UTF_16);\n\t\tassertThat(properties.getContentType()).hasToString(\"text/plain;charset=UTF-16;foo=bar\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-groovy-templates/src/test/java/org/springframework/boot/groovy/template/autoconfigure/GroovyTemplateWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.groovy.template.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Groovy Templates with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass GroovyTemplateWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid groovyTemplateAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(GroovyTemplateAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot gRPC Client\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.grpc:spring-grpc-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(\"io.grpc:grpc-grpclb\")\n\toptional(\"io.grpc:grpc-stub\")\n\toptional(\"io.grpc:grpc-netty\")\n\toptional(\"io.grpc:grpc-netty-shaded\")\n\toptional(\"io.grpc:grpc-inprocess\")\n\toptional(\"io.grpc:grpc-kotlin-stub\") {\n\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t}\n\toptional(\"io.grpc:grpc-xds\") {\n\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t}\n\toptional(\"io.micrometer:micrometer-core\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.yaml:snakeyaml\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/CompositeChannelFactoryAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.stub.AbstractStub;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.grpc.client.CompositeGrpcChannelFactory;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.GrpcChannelFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a\n * {@link CompositeGrpcChannelFactory}.\n *\n * @author Chris Bono\n * @since 4.1.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ AbstractStub.class, GrpcChannelBuilderCustomizer.class })\n@ConditionalOnProperty(name = \"spring.grpc.client.enabled\", matchIfMissing = true)\n@Conditional(CompositeChannelFactoryAutoConfiguration.MultipleNonPrimaryChannelFactoriesCondition.class)\npublic final class CompositeChannelFactoryAutoConfiguration {\n\n\t@Bean\n\t@Primary\n\tCompositeGrpcChannelFactory compositeChannelFactory(ObjectProvider<GrpcChannelFactory> channelFactoriesProvider) {\n\t\treturn new CompositeGrpcChannelFactory(channelFactoriesProvider.orderedStream().toList());\n\t}\n\n\tstatic class MultipleNonPrimaryChannelFactoriesCondition extends NoneNestedConditions {\n\n\t\tMultipleNonPrimaryChannelFactoriesCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnMissingBean(GrpcChannelFactory.class)\n\t\tstatic class NoChannelFactoryCondition {\n\n\t\t}\n\n\t\t@ConditionalOnSingleCandidate(GrpcChannelFactory.class)\n\t\tstatic class SingleInjectableChannelFactoryCondition {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/ConditionalOnGrpcClientChannelFactoryEnabled.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when\n * {@code spring.grpc.client.channelfactory.enabled} is {@code true} or missing.\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ConditionalOnBooleanProperty(name = \"spring.grpc.client.channelfactory.enabled\", matchIfMissing = true)\n@interface ConditionalOnGrpcClientChannelFactoryEnabled {\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcChannelBuilderCustomizers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ManagedChannelBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\n\n/**\n * Invokes the customizations to a {@link ManagedChannelBuilder} based on the provided\n * beans.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass GrpcChannelBuilderCustomizers {\n\n\tprivate final List<GrpcChannelBuilderCustomizer<?>> customizers;\n\n\tGrpcChannelBuilderCustomizers(GrpcClientProperties grpcClientProperties,\n\t\t\tObjectProvider<CompressorRegistry> compressorRegistry,\n\t\t\tObjectProvider<DecompressorRegistry> decompressorRegistry,\n\t\t\tObjectProvider<GrpcChannelBuilderCustomizer<?>> customizers,\n\t\t\tObjectProvider<GrpcClientDefaultServiceConfigCustomizer> defaultServiceConfigCustomizers) {\n\t\tthis(grpcClientProperties, compressorRegistry.getIfAvailable(), decompressorRegistry.getIfAvailable(),\n\t\t\t\tcustomizers.orderedStream().toList(), defaultServiceConfigCustomizers.orderedStream().toList());\n\t}\n\n\tGrpcChannelBuilderCustomizers(List<? extends GrpcChannelBuilderCustomizer<?>> customizers) {\n\t\tthis(null, null, null, customizers, Collections.emptyList());\n\t}\n\n\tGrpcChannelBuilderCustomizers(@Nullable GrpcClientProperties grpcClientProperties,\n\t\t\t@Nullable CompressorRegistry compressorRegistry, @Nullable DecompressorRegistry decompressorRegistry,\n\t\t\tList<? extends GrpcChannelBuilderCustomizer<?>> customizers,\n\t\t\tList<? extends GrpcClientDefaultServiceConfigCustomizer> defaultServiceConfigCustomizers) {\n\t\tList<GrpcChannelBuilderCustomizer<?>> all = new ArrayList<>();\n\t\taddCustomizer(all, compressorRegistry, ManagedChannelBuilder::compressorRegistry);\n\t\taddCustomizer(all, decompressorRegistry, ManagedChannelBuilder::decompressorRegistry);\n\t\tif (grpcClientProperties != null) {\n\t\t\tall.add(new PropertiesGrpcChannelBuilderCustomizer<>(grpcClientProperties));\n\t\t}\n\t\tall.addAll(customizers);\n\t\tall.add(customizeDefaultServiceConfig(grpcClientProperties, defaultServiceConfigCustomizers));\n\t\tthis.customizers = List.copyOf(all);\n\t}\n\n\tprivate static <B extends ManagedChannelBuilder<B>, T> void addCustomizer(\n\t\t\tList<GrpcChannelBuilderCustomizer<?>> customizers, @Nullable T bean, BiConsumer<B, T> action) {\n\t\tif (bean != null) {\n\t\t\tGrpcChannelBuilderCustomizer<B> customizer = (target, builder) -> action.accept(builder, bean);\n\t\t\tcustomizers.add(customizer);\n\t\t}\n\t}\n\n\tprivate <B extends ManagedChannelBuilder<B>> GrpcChannelBuilderCustomizer<B> customizeDefaultServiceConfig(\n\t\t\t@Nullable GrpcClientProperties properties,\n\t\t\tList<? extends GrpcClientDefaultServiceConfigCustomizer> customizers) {\n\t\tPropertiesGrpcClientDefaultServiceConfigCustomizer propertiesCustomizer = (properties != null)\n\t\t\t\t? new PropertiesGrpcClientDefaultServiceConfigCustomizer(properties) : null;\n\t\treturn (target, builder) -> {\n\t\t\tMap<String, Object> defaultServiceConfig = new LinkedHashMap<>();\n\t\t\tif (propertiesCustomizer != null) {\n\t\t\t\tpropertiesCustomizer.customize(target, defaultServiceConfig);\n\t\t\t}\n\t\t\tcustomizers.forEach((customizer) -> customizer.customize(target, defaultServiceConfig));\n\t\t\tif (!defaultServiceConfig.isEmpty()) {\n\t\t\t\tbuilder.defaultServiceConfig(defaultServiceConfig);\n\t\t\t}\n\t\t};\n\t}\n\n\t<T extends ManagedChannelBuilder<T>> List<GrpcChannelBuilderCustomizer<T>> forFactory() {\n\t\treturn List.of(this::apply);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t<T extends ManagedChannelBuilder<?>> void apply(String target, T builder) {\n\t\tLambdaSafe.callbacks(GrpcChannelBuilderCustomizer.class, this.customizers, builder)\n\t\t\t.withLogger(GrpcChannelBuilderCustomizers.class)\n\t\t\t.invoke((customizer) -> customizer.customize(target, builder));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcChannelFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport org.springframework.grpc.client.GrpcChannelFactory;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link GrpcChannelFactory} before it is fully initialized, in particular to tune its\n * configuration.\n *\n * @author Chris Bono\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface GrpcChannelFactoryCustomizer {\n\n\t/**\n\t * Customize the given {@link GrpcChannelFactory}.\n\t * @param factory the factory to customize\n\t */\n\tvoid customize(GrpcChannelFactory factory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ManagedChannelBuilder;\nimport io.grpc.stub.AbstractStub;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.grpc.client.ChannelCredentialsProvider;\nimport org.springframework.grpc.client.ClientInterceptorsConfigurer;\nimport org.springframework.grpc.client.CoroutineStubFactory;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC clients.\n *\n * @author Dave Syer\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(before = CompositeChannelFactoryAutoConfiguration.class)\n@ConditionalOnClass({ AbstractStub.class, GrpcChannelBuilderCustomizer.class })\n@ConditionalOnProperty(name = \"spring.grpc.client.enabled\", matchIfMissing = true)\n@EnableConfigurationProperties(GrpcClientProperties.class)\n@Import({ GrpcClientCodecConfiguration.class, ShadedNettyGrpcClientConfiguration.class,\n\t\tNettyGrpcClientConfiguration.class, InProcessGrpcClientConfiguration.class })\npublic final class GrpcClientAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tClientInterceptorsConfigurer grpcClientInterceptorsConfigurer(ApplicationContext applicationContext) {\n\t\treturn new ClientInterceptorsConfigurer(applicationContext);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ChannelCredentialsProvider.class)\n\tPropertiesChannelCredentialsProvider grpcChannelCredentialsProvider(SslBundles bundles,\n\t\t\tGrpcClientProperties properties) {\n\t\treturn new PropertiesChannelCredentialsProvider(properties, bundles);\n\t}\n\n\t@Bean\n\t<T extends ManagedChannelBuilder<T>> PropertiesGrpcChannelBuilderCustomizer<T> grpcClientPropertiesChannelCustomizer(\n\t\t\tGrpcClientProperties properties) {\n\t\treturn new PropertiesGrpcChannelBuilderCustomizer<>(properties);\n\t}\n\n\t@Bean\n\tGrpcChannelBuilderCustomizers grpcDefaultServicesChannelBuilderCustomizer(GrpcClientProperties grpcClientProperties,\n\t\t\tObjectProvider<CompressorRegistry> compressorRegistry,\n\t\t\tObjectProvider<DecompressorRegistry> decompressorRegistry,\n\t\t\tObjectProvider<GrpcChannelBuilderCustomizer<?>> customizers,\n\t\t\tObjectProvider<GrpcClientDefaultServiceConfigCustomizer> defaultServiceConfigCustomizers) {\n\t\treturn new GrpcChannelBuilderCustomizers(grpcClientProperties, compressorRegistry, decompressorRegistry,\n\t\t\t\tcustomizers, defaultServiceConfigCustomizers);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = \"io.grpc.kotlin.AbstractCoroutineStub\")\n\tstatic class GrpcClientCoroutineStubConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tCoroutineStubFactory coroutineStubFactory() {\n\t\t\treturn new CoroutineStubFactory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientCodecConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.List;\n\nimport io.grpc.Codec;\nimport io.grpc.Compressor;\nimport io.grpc.CompressorRegistry;\nimport io.grpc.Decompressor;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ManagedChannelBuilder;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * The configuration that contains all codec related beans for clients.\n *\n * @author Andrei Lisa\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(Codec.class)\nclass GrpcClientCodecConfiguration {\n\n\t/**\n\t * The compressor registry that is set on the\n\t * {@link ManagedChannelBuilder#compressorRegistry(CompressorRegistry) channel\n\t * builder}.\n\t * @param compressors the compressors to use on the registry\n\t * @return a new {@link CompressorRegistry#newEmptyInstance() registry} with the\n\t * specified compressors or the {@link CompressorRegistry#getDefaultInstance() default\n\t * registry} if no custom compressors are available in the application context.\n\t */\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCompressorRegistry grpcCompressorRegistry(List<Compressor> compressors) {\n\t\tif (compressors.isEmpty()) {\n\t\t\treturn CompressorRegistry.getDefaultInstance();\n\t\t}\n\t\tCompressorRegistry registry = CompressorRegistry.newEmptyInstance();\n\t\tcompressors.forEach(registry::register);\n\t\treturn registry;\n\t}\n\n\t/**\n\t * The decompressor registry that is set on the\n\t * {@link ManagedChannelBuilder#decompressorRegistry(DecompressorRegistry) channel\n\t * builder}.\n\t * @param decompressors the decompressors to use on the registry\n\t * @return a new {@link DecompressorRegistry#emptyInstance() registry} with the\n\t * specified decompressors or the {@link DecompressorRegistry#getDefaultInstance()\n\t * default registry} if no custom decompressors are available in the application\n\t * context.\n\t */\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDecompressorRegistry grpcDecompressorRegistry(List<Decompressor> decompressors) {\n\t\tif (decompressors.isEmpty()) {\n\t\t\treturn DecompressorRegistry.getDefaultInstance();\n\t\t}\n\t\tDecompressorRegistry registry = DecompressorRegistry.emptyInstance();\n\t\tfor (Decompressor decompressor : decompressors) {\n\t\t\tregistry = registry.with(decompressor, false);\n\t\t}\n\t\treturn registry;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientDefaultServiceConfigCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.Map;\n\nimport io.grpc.ManagedChannelBuilder;\n\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.VirtualTargets;\n\n/**\n * Callback interface that can be used to customize the default service config of the gRPC\n * channel.\n * <p>\n * This customizer should be used instead of calling\n * {@link ManagedChannelBuilder#defaultServiceConfig(Map)} from a\n * {@link GrpcChannelBuilderCustomizer} since it allows multiple customizers to update the\n * same default service config, rather than having a \"last wins\" outcome.\n *\n * @author Phillip Webb\n * @since 4.1.0\n * @see GrpcChannelBuilderCustomizer\n */\n@FunctionalInterface\npublic interface GrpcClientDefaultServiceConfigCustomizer {\n\n\t/**\n\t * Customize the given default service config.\n\t * @param target the target (which may be a {@link VirtualTargets virtual target}).\n\t * @param defaultServiceConfig the default service config to customize\n\t */\n\tvoid customize(String target, Map<String, Object> defaultServiceConfig);\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.stub.AbstractStub;\nimport io.micrometer.core.instrument.binder.grpc.GrpcClientObservationConvention;\nimport io.micrometer.core.instrument.binder.grpc.ObservationGrpcClientInterceptor;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.grpc.client.GlobalClientInterceptor;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC observation support.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnClass({ AbstractStub.class, GrpcChannelBuilderCustomizer.class, ObservationRegistry.class,\n\t\tObservationGrpcClientInterceptor.class })\n@ConditionalOnProperty(name = \"spring.grpc.client.enabled\", matchIfMissing = true)\n@ConditionalOnProperty(name = \"spring.grpc.client.observation.enabled\", havingValue = \"true\", matchIfMissing = true)\n@ConditionalOnBean(ObservationRegistry.class)\npublic final class GrpcClientObservationAutoConfiguration {\n\n\t@Bean\n\t@GlobalClientInterceptor\n\t@ConditionalOnMissingBean\n\tObservationGrpcClientInterceptor grpcClientObservationInterceptor(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<GrpcClientObservationConvention> customConvention) {\n\t\tObservationGrpcClientInterceptor interceptor = new ObservationGrpcClientInterceptor(observationRegistry);\n\t\tcustomConvention.ifAvailable(interceptor::setCustomConvention);\n\t\treturn interceptor;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Configuration properties for gRPC clients.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@ConfigurationProperties(\"spring.grpc.client\")\npublic class GrpcClientProperties {\n\n\t/**\n\t * Map of channels configured by name.\n\t */\n\tprivate final Map<String, Channel> channel = new LinkedHashMap<>();\n\n\tpublic Map<String, Channel> getChannel() {\n\t\treturn this.channel;\n\t}\n\n\t/**\n\t * Channel properties.\n\t */\n\tpublic static class Channel {\n\n\t\tstatic final String DEFAULT_TARGET = \"static://localhost:9090\";\n\n\t\t/**\n\t\t * Channel target address.\n\t\t */\n\t\tprivate String target = DEFAULT_TARGET;\n\n\t\t/**\n\t\t * Custom User-Agent for the channel.\n\t\t */\n\t\tprivate @Nullable String userAgent;\n\n\t\t/**\n\t\t * Whether to bypass certificate validation for easier testing (so the remote\n\t\t * certificate could be anonymous). Should not be enabled in production.\n\t\t */\n\t\tprivate boolean bypassCertificateValidation;\n\n\t\t/**\n\t\t * Service config for the channel.\n\t\t */\n\t\tprivate @Nullable ServiceConfig serviceConfig;\n\n\t\tprivate final Inbound inbound = new Inbound();\n\n\t\t@Name(\"default\")\n\t\tprivate final Default defaultProperties = new Default();\n\n\t\tprivate final Idle idle = new Idle();\n\n\t\tprivate final Keepalive keepalive = new Keepalive();\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tprivate final Health health = new Health();\n\n\t\tpublic String getTarget() {\n\t\t\treturn this.target;\n\t\t}\n\n\t\tpublic void setTarget(String target) {\n\t\t\tthis.target = target;\n\t\t}\n\n\t\tpublic @Nullable String getUserAgent() {\n\t\t\treturn this.userAgent;\n\t\t}\n\n\t\tpublic void setUserAgent(@Nullable String userAgent) {\n\t\t\tthis.userAgent = userAgent;\n\t\t}\n\n\t\tpublic boolean isBypassCertificateValidation() {\n\t\t\treturn this.bypassCertificateValidation;\n\t\t}\n\n\t\tpublic void setBypassCertificateValidation(boolean bypassCertificateValidation) {\n\t\t\tthis.bypassCertificateValidation = bypassCertificateValidation;\n\t\t}\n\n\t\tpublic @Nullable ServiceConfig getServiceConfig() {\n\t\t\treturn this.serviceConfig;\n\t\t}\n\n\t\tpublic void setServiceConfig(@Nullable ServiceConfig serviceConfig) {\n\t\t\tthis.serviceConfig = serviceConfig;\n\t\t}\n\n\t\tpublic Inbound getInbound() {\n\t\t\treturn this.inbound;\n\t\t}\n\n\t\tpublic Default getDefault() {\n\t\t\treturn this.defaultProperties;\n\t\t}\n\n\t\tpublic Idle getIdle() {\n\t\t\treturn this.idle;\n\t\t}\n\n\t\tpublic Keepalive getKeepalive() {\n\t\t\treturn this.keepalive;\n\t\t}\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic Health getHealth() {\n\t\t\treturn this.health;\n\t\t}\n\n\t\t/**\n\t\t * In-bound properties.\n\t\t */\n\t\tpublic static class Inbound {\n\n\t\t\tprivate final Message message = new Message();\n\n\t\t\tprivate final Metadata metadata = new Metadata();\n\n\t\t\tpublic Message getMessage() {\n\t\t\t\treturn this.message;\n\t\t\t}\n\n\t\t\tpublic Metadata getMetadata() {\n\t\t\t\treturn this.metadata;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * In-bound message properties.\n\t\t\t */\n\t\t\tpublic static class Message {\n\n\t\t\t\t/**\n\t\t\t\t * Maximum message size allowed to be received by the channel. Set to '-1'\n\t\t\t\t * to use the highest possible limit (not recommended).\n\t\t\t\t */\n\t\t\t\tprivate DataSize maxSize = DataSize.ofBytes(4194304);\n\n\t\t\t\tpublic DataSize getMaxSize() {\n\t\t\t\t\treturn this.maxSize;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxSize(DataSize maxSize) {\n\t\t\t\t\tthis.maxSize = maxSize;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * In-bound metadata properties.\n\t\t\t */\n\t\t\tpublic static class Metadata {\n\n\t\t\t\t/**\n\t\t\t\t * Maximum metadata size allowed to be received by the channel. Set to\n\t\t\t\t * '-1' to use the highest possible limit (not recommended).\n\t\t\t\t */\n\t\t\t\tprivate DataSize maxSize = DataSize.ofBytes(8192);\n\n\t\t\t\tpublic DataSize getMaxSize() {\n\t\t\t\t\treturn this.maxSize;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxSize(DataSize maxSize) {\n\t\t\t\t\tthis.maxSize = maxSize;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Properties for client defaults.\n\t\t */\n\t\tpublic static class Default {\n\n\t\t\t/**\n\t\t\t * Default deadline for RPCs performed on this channel. If a duration suffix\n\t\t\t * is not specified, seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate @Nullable Duration deadline;\n\n\t\t\t/**\n\t\t\t * Load balancing policy the channel should use.\n\t\t\t */\n\t\t\tprivate String loadBalancingPolicy = \"round_robin\";\n\n\t\t\tpublic @Nullable Duration getDeadline() {\n\t\t\t\treturn this.deadline;\n\t\t\t}\n\n\t\t\tpublic void setDeadline(@Nullable Duration deadline) {\n\t\t\t\tthis.deadline = deadline;\n\t\t\t}\n\n\t\t\tpublic String getLoadBalancingPolicy() {\n\t\t\t\treturn this.loadBalancingPolicy;\n\t\t\t}\n\n\t\t\tpublic void setLoadBalancingPolicy(String loadBalancingPolicy) {\n\t\t\t\tthis.loadBalancingPolicy = loadBalancingPolicy;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Idle properties.\n\t\t */\n\t\tpublic static class Idle {\n\n\t\t\t/**\n\t\t\t * Time without ongoing RPCs before going to idle mode. If a duration suffix\n\t\t\t * is not specified, seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate Duration timeout = Duration.ofSeconds(20);\n\n\t\t\tpublic Duration getTimeout() {\n\t\t\t\treturn this.timeout;\n\t\t\t}\n\n\t\t\tpublic void setTimeout(Duration timeout) {\n\t\t\t\tthis.timeout = timeout;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Keep-alive properties.\n\t\t */\n\t\tpublic static class Keepalive {\n\n\t\t\t/**\n\t\t\t * Delay before sending a keepAlive. Note that shorter intervals increase the\n\t\t\t * network burden for the server, and this value cannot be lower than\n\t\t\t * 'permitKeepAliveTime' on the server. If a duration suffix is not specified,\n\t\t\t * seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate Duration time = Duration.ofMinutes(5);\n\n\t\t\t/**\n\t\t\t * Default timeout for a keep-alive ping request. If a duration suffix is not\n\t\t\t * specified, seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate Duration timeout = Duration.ofSeconds(20);\n\n\t\t\t/**\n\t\t\t * Whether a keepAlive will be performed when there are no outstanding RPC on\n\t\t\t * a connection.\n\t\t\t */\n\t\t\tprivate boolean withoutCalls;\n\n\t\t\tpublic Duration getTime() {\n\t\t\t\treturn this.time;\n\t\t\t}\n\n\t\t\tpublic void setTime(Duration time) {\n\t\t\t\tthis.time = time;\n\t\t\t}\n\n\t\t\tpublic Duration getTimeout() {\n\t\t\t\treturn this.timeout;\n\t\t\t}\n\n\t\t\tpublic void setTimeout(Duration timeout) {\n\t\t\t\tthis.timeout = timeout;\n\t\t\t}\n\n\t\t\tpublic boolean isWithoutCalls() {\n\t\t\t\treturn this.withoutCalls;\n\t\t\t}\n\n\t\t\tpublic void setWithoutCalls(boolean withoutCalls) {\n\t\t\t\tthis.withoutCalls = withoutCalls;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Health properties.\n\t\t */\n\t\tpublic static class Health {\n\n\t\t\t/**\n\t\t\t * Whether to enable client-side health check for the channel.\n\t\t\t */\n\t\t\tprivate boolean enabled;\n\n\t\t\t/**\n\t\t\t * Name of the service to check health on.\n\t\t\t */\n\t\t\tprivate @Nullable String serviceName;\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getServiceName() {\n\t\t\t\treturn this.serviceName;\n\t\t\t}\n\n\t\t\tpublic void setServiceName(String serviceName) {\n\t\t\t\tthis.serviceName = serviceName;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * SSL properties.\n\t\t */\n\t\tpublic static class Ssl {\n\n\t\t\t/**\n\t\t\t * Whether to enable SSL support. Enabled automatically if \"bundle\" is\n\t\t\t * provided unless specified otherwise.\n\t\t\t */\n\t\t\tprivate @Nullable Boolean enabled;\n\n\t\t\t/**\n\t\t\t * SSL bundle name.\n\t\t\t */\n\t\t\tprivate @Nullable String bundle;\n\n\t\t\tpublic @Nullable Boolean getEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(@Nullable Boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getBundle() {\n\t\t\t\treturn this.bundle;\n\t\t\t}\n\n\t\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\t\tthis.bundle = bundle;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/InProcessGrpcClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.inprocess.InProcessChannelBuilder;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.client.ClientInterceptorFilter;\nimport org.springframework.grpc.client.ClientInterceptorsConfigurer;\nimport org.springframework.grpc.client.InProcessGrpcChannelFactory;\n\n/**\n * {@link Configuration @Configuration} for an in-process gRPC client.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(InProcessChannelBuilder.class)\n@ConditionalOnMissingBean(InProcessGrpcChannelFactory.class)\n@ConditionalOnGrpcClientChannelFactoryEnabled\n@ConditionalOnProperty(name = \"spring.grpc.client.inprocess.enabled\", havingValue = \"true\", matchIfMissing = true)\nclass InProcessGrpcClientConfiguration {\n\n\t@Bean\n\tInProcessGrpcChannelFactory inProcessGrpcChannelFactory(GrpcChannelBuilderCustomizers grpcChannelBuilderCustomizers,\n\t\t\tClientInterceptorsConfigurer interceptorsConfigurer,\n\t\t\tObjectProvider<ClientInterceptorFilter> interceptorFilter,\n\t\t\tObjectProvider<GrpcChannelFactoryCustomizer> channelFactoryCustomizers) {\n\t\tInProcessGrpcChannelFactory factory = new InProcessGrpcChannelFactory(\n\t\t\t\tgrpcChannelBuilderCustomizers.forFactory(), interceptorsConfigurer);\n\t\tinterceptorFilter.ifAvailable(factory::setInterceptorFilter);\n\t\tchannelFactoryCustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/NettyGrpcClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.Channel;\nimport io.grpc.netty.NettyChannelBuilder;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.grpc.client.ChannelCredentialsProvider;\nimport org.springframework.grpc.client.ClientInterceptorsConfigurer;\nimport org.springframework.grpc.client.GrpcChannelFactory;\nimport org.springframework.grpc.client.InProcessGrpcChannelFactory;\nimport org.springframework.grpc.client.NettyGrpcChannelFactory;\n\n/**\n * {@link Configuration @Configuration} for a Netty gRPC client.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ Channel.class, NettyChannelBuilder.class })\n@ConditionalOnMissingBean(value = GrpcChannelFactory.class, ignored = InProcessGrpcChannelFactory.class)\n@ConditionalOnGrpcClientChannelFactoryEnabled\nclass NettyGrpcClientConfiguration {\n\n\t@Bean\n\tNettyGrpcChannelFactory nettyGrpcChannelFactory(Environment environment, GrpcClientProperties properties,\n\t\t\tGrpcChannelBuilderCustomizers grpcChannelBuilderCustomizers,\n\t\t\tClientInterceptorsConfigurer interceptorsConfigurer,\n\t\t\tObjectProvider<GrpcChannelFactoryCustomizer> channelFactoryCustomizers,\n\t\t\tChannelCredentialsProvider credentials) {\n\t\tNettyGrpcChannelFactory factory = new NettyGrpcChannelFactory(grpcChannelBuilderCustomizers.forFactory(),\n\t\t\t\tinterceptorsConfigurer);\n\t\tfactory.setCredentialsProvider(credentials);\n\t\tfactory.setVirtualTargets(new PropertiesVirtualTargets(environment, properties));\n\t\tchannelFactoryCustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesChannelCredentialsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.ChannelCredentials;\nimport io.grpc.InsecureChannelCredentials;\nimport io.grpc.TlsChannelCredentials;\nimport io.grpc.TlsChannelCredentials.Builder;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.grpc.client.ChannelCredentialsProvider;\nimport org.springframework.grpc.internal.InsecureTrustManagerFactory;\n\n/**\n * {@link ChannelCredentialsProvider} backed by {@link GrpcClientProperties}.\n *\n * @param properties the client properties\n * @param bundles the SSL bundles\n * @author David Syer\n * @author Phillip Webb\n */\nrecord PropertiesChannelCredentialsProvider(GrpcClientProperties properties,\n\t\tSslBundles bundles) implements ChannelCredentialsProvider {\n\n\t@Override\n\tpublic ChannelCredentials getChannelCredentials(String target) {\n\t\tChannel channel = this.properties.getChannel().get(target);\n\t\tchannel = (channel != null) ? channel : this.properties.getChannel().get(\"default\");\n\t\tif (channel == null || isInsecure(channel.getSsl())) {\n\t\t\treturn InsecureChannelCredentials.create();\n\t\t}\n\t\tBuilder builder = TlsChannelCredentials.newBuilder();\n\t\tif (channel.getSsl().getBundle() != null) {\n\t\t\tSslBundle bundle = this.bundles.getBundle(channel.getSsl().getBundle());\n\t\t\tbuilder.trustManager(bundle.getManagers().getTrustManagerFactory().getTrustManagers());\n\t\t\tbuilder.keyManager(bundle.getManagers().getKeyManagerFactory().getKeyManagers());\n\t\t}\n\t\tif (channel.isBypassCertificateValidation()) {\n\t\t\tbuilder.trustManager(InsecureTrustManagerFactory.INSTANCE.getTrustManagers());\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\tprivate boolean isInsecure(Ssl ssl) {\n\t\treturn Boolean.FALSE.equals(ssl.getEnabled()) || (ssl.getBundle() == null && ssl.getEnabled() == null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesGrpcChannelBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport io.grpc.ManagedChannelBuilder;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.interceptor.DefaultDeadlineSetupClientInterceptor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link GrpcChannelBuilderCustomizer} that maps {@link GrpcClientProperties} to a\n * {@link ManagedChannelBuilder}.\n *\n * @param <T> the type of the builder\n * @param properties the properties to map\n * @author David Syer\n * @author Chris Bono\n * @author Phillip Webb\n */\nrecord PropertiesGrpcChannelBuilderCustomizer<T extends ManagedChannelBuilder<T>>(\n\t\tGrpcClientProperties properties) implements GrpcChannelBuilderCustomizer<T> {\n\n\tprivate static final Channel STOCK_DEFAULT_CHANNEL = new Channel();\n\n\t@Override\n\tpublic void customize(String target, T builder) {\n\t\tChannel channel = getChannel(target);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(channel::getUserAgent).to(builder::userAgent);\n\t\tmap.from(channel.getInbound().getMessage()::getMaxSize).asInt(this::maxSize).to(builder::maxInboundMessageSize);\n\t\tmap.from(channel.getInbound().getMetadata()::getMaxSize)\n\t\t\t.asInt(this::maxSize)\n\t\t\t.to(builder::maxInboundMetadataSize);\n\t\tmap.from(channel.getDefault()::getDeadline)\n\t\t\t.when((deadline) -> deadline.toMillis() > 0L)\n\t\t\t.as(DefaultDeadlineSetupClientInterceptor::new)\n\t\t\t.to(builder::intercept);\n\t\tmap.from(channel.getDefault()::getLoadBalancingPolicy)\n\t\t\t.when((policy) -> supportsLoadBalancing(target, channel))\n\t\t\t.to(builder::defaultLoadBalancingPolicy);\n\t\tmap.from(channel.getIdle()::getTimeout).to(durationProperty(builder::idleTimeout));\n\t\tmap.from(channel.getKeepalive()::getTime).to(durationProperty(builder::keepAliveTime));\n\t\tmap.from(channel.getKeepalive()::getTimeout).to(durationProperty(builder::keepAliveTimeout));\n\t\tmap.from(channel.getKeepalive()::isWithoutCalls).to(builder::keepAliveWithoutCalls);\n\t}\n\n\tprivate Channel getChannel(String target) {\n\t\tChannel channel = this.properties.getChannel().get(target);\n\t\tchannel = (channel != null) ? channel : this.properties.getChannel().get(\"default\");\n\t\treturn (channel != null) ? channel : STOCK_DEFAULT_CHANNEL;\n\t}\n\n\tprivate boolean supportsLoadBalancing(String target, Channel channel) {\n\t\treturn !(isUnixOrInProcessTarget(target) || isUnixOrInProcessTarget(channel.getTarget()));\n\t}\n\n\tprivate boolean isUnixOrInProcessTarget(String target) {\n\t\treturn target.startsWith(\"unix:\") || target.startsWith(\"in-process:\");\n\t}\n\n\tConsumer<Duration> durationProperty(BiConsumer<Long, TimeUnit> setter) {\n\t\treturn (duration) -> setter.accept(duration.toNanos(), TimeUnit.NANOSECONDS);\n\t}\n\n\tprivate int maxSize(DataSize maxSize) {\n\t\tlong bytes = maxSize.toBytes();\n\t\tAssert.state(bytes >= 0 || bytes == -1, () -> \"Unsupported max size value \" + maxSize);\n\t\treturn (bytes >= 0 && bytes <= Integer.MAX_VALUE) ? (int) bytes : Integer.MAX_VALUE;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesGrpcClientDefaultServiceConfigCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel.Health;\nimport org.springframework.util.Assert;\n\n/**\n * {@link GrpcClientDefaultServiceConfigCustomizer} to apply {@link GrpcClientProperties}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @param properties the client properties\n */\nrecord PropertiesGrpcClientDefaultServiceConfigCustomizer(\n\t\tGrpcClientProperties properties) implements GrpcClientDefaultServiceConfigCustomizer {\n\n\t@Override\n\tpublic void customize(String target, Map<String, Object> defaultServiceConfig) {\n\t\tChannel channel = this.properties.getChannel().get(target);\n\t\tchannel = (channel != null) ? channel : this.properties.getChannel().get(\"default\");\n\t\tif (channel == null) {\n\t\t\treturn;\n\t\t}\n\t\tapplyServiceConfig(channel.getServiceConfig(), defaultServiceConfig);\n\t\tapplyHealth(channel.getHealth(), defaultServiceConfig);\n\t}\n\n\tprivate void applyServiceConfig(@Nullable ServiceConfig serviceConfig, Map<String, Object> defaultServiceConfig) {\n\t\tif (serviceConfig != null) {\n\t\t\tserviceConfig.applyTo(defaultServiceConfig);\n\t\t}\n\t}\n\n\tprivate void applyHealth(Health health, Map<String, Object> defaultServiceConfig) {\n\t\tif (!health.isEnabled()) {\n\t\t\treturn;\n\t\t}\n\t\tString serviceName = (health.getServiceName() != null) ? health.getServiceName() : \"\";\n\t\tMap<String, Object> healthCheckConfig = cloneOrCreateHealthCheckConfig(defaultServiceConfig);\n\t\tString existingServiceName = (String) healthCheckConfig.get(ServiceConfig.HEALTH_CHECK_SERVICE_NAME_KEY);\n\t\tAssert.state(existingServiceName == null || serviceName.equals(existingServiceName),\n\t\t\t\t() -> \"Unable to change health check config service name from '%s' to '%s'\"\n\t\t\t\t\t.formatted(existingServiceName, serviceName));\n\t\thealthCheckConfig.put(ServiceConfig.HEALTH_CHECK_SERVICE_NAME_KEY, serviceName);\n\t\tdefaultServiceConfig.put(ServiceConfig.HEALTH_CHECK_CONFIG_KEY, healthCheckConfig);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, Object> cloneOrCreateHealthCheckConfig(Map<String, Object> defaultServiceConfig) {\n\t\tMap<String, Object> healthCheckConfig = (Map<String, Object>) defaultServiceConfig\n\t\t\t.get(ServiceConfig.HEALTH_CHECK_CONFIG_KEY);\n\t\treturn new LinkedHashMap<>((healthCheckConfig != null) ? healthCheckConfig : Collections.emptyMap());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesVirtualTargets.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.grpc.client.VirtualTargets;\n\n/**\n * {@link VirtualTargets} supporting named channels from {@link GrpcClientProperties} and\n * directly specified targets (which may include property placeholders).\n *\n * @param propertyResolver the property resolver\n * @param properties the client properties\n * @author Chris Bono\n * @author Phillip Webb\n */\nrecord PropertiesVirtualTargets(PropertyResolver propertyResolver,\n\t\tGrpcClientProperties properties) implements VirtualTargets {\n\n\t@Override\n\tpublic String getTarget(String target) {\n\t\tChannel channel = this.properties.getChannel().get(target);\n\t\tif (channel != null) {\n\t\t\treturn clean(this.propertyResolver.resolvePlaceholders(channel.getTarget()));\n\t\t}\n\t\tif (\"default\".equals(target)) {\n\t\t\treturn clean(Channel.DEFAULT_TARGET);\n\t\t}\n\t\ttarget = this.propertyResolver.resolvePlaceholders(target);\n\t\tif (target.contains(\":/\") || target.startsWith(\"unix:\")) {\n\t\t\treturn clean(target);\n\t\t}\n\t\treturn target;\n\t}\n\n\tprivate String clean(String target) {\n\t\tif (target.startsWith(\"static:\") || target.startsWith(\"tcp:\")) {\n\t\t\tString withoutScheme = target.substring(target.indexOf(\":\") + 1);\n\t\t\treturn withoutScheme.replaceFirst(\"/*\", \"\");\n\t\t}\n\t\treturn target;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/ServiceConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport io.grpc.Status;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.PropertyMapper.Source.Adapter;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Bindable service configuration for gRPC channel. Allows type safe binding of common\n * service configuration options which can ultimately be applied to the {@link Map}\n * provided by a {@link GrpcClientDefaultServiceConfigCustomizer}.\n * <p>\n * The configuration provided here is a subset of the canonical <a href=\n * \"https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto\">service_config.proto</a>\n * protocol definition. For advanced or experimental service configurations, use the\n * {@link GrpcClientDefaultServiceConfigCustomizer} to directly add any entries supported\n * by {@code grpc-java}.\n *\n * @author Phillip Webb\n * @param loadbalancing load balancing configurations in the order that they should be\n * applied\n * @param method method configuration\n * @param retrythrottling retry throttling policy\n * @param healthcheck health check configuration\n * @since 4.1.0\n * @see GrpcClientDefaultServiceConfigCustomizer\n * @see io.grpc.internal.ServiceConfigUtil\n */\npublic record ServiceConfig(@Nullable List<LoadBalancingConfig> loadbalancing, @Nullable List<MethodConfig> method,\n\t\t@Nullable RetryThrottlingPolicy retrythrottling, @Nullable HealthCheckConfig healthcheck) {\n\n\tstatic final String HEALTH_CHECK_CONFIG_KEY = \"healthCheckConfig\";\n\n\tstatic final String HEALTH_CHECK_SERVICE_NAME_KEY = \"serviceName\";\n\n\t/**\n\t * Apply this service config to the given gRPC Java config Map.\n\t * @param grpcJavaConfig the gRPC Java config map\n\t */\n\tpublic void applyTo(Map<String, Object> grpcJavaConfig) {\n\t\tapplyTo(new GrpcJavaConfig(grpcJavaConfig));\n\t}\n\n\tprivate void applyTo(GrpcJavaConfig config) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this::loadbalancing)\n\t\t\t.as(listOf(LoadBalancingConfig::grpcJavaConfig))\n\t\t\t.to(config.in(\"loadBalancingConfig\"));\n\t\tmap.from(this::method).as(listOf(MethodConfig::grpcJavaConfig)).to(config.in(\"methodConfig\"));\n\t\tmap.from(this::retrythrottling).as(RetryThrottlingPolicy::grpcJavaConfig).to(config.in(\"retryThrottling\"));\n\t\tmap.from(this::healthcheck).as(HealthCheckConfig::grpcJavaConfig).to(config.in(HEALTH_CHECK_CONFIG_KEY));\n\t}\n\n\tstatic <T> Adapter<List<T>, @Nullable List<Map<String, Object>>> listOf(Function<T, Map<String, Object>> adapter) {\n\t\treturn (list) -> (!CollectionUtils.isEmpty(list)) ? list.stream().map(adapter).toList() : null;\n\t}\n\n\tstatic String durationString(Duration duration) {\n\t\treturn duration.getSeconds() + \".\" + duration.getNano() + \"s\";\n\t}\n\n\tstatic String bytesString(DataSize dataSize) {\n\t\treturn Long.toString(dataSize.toBytes());\n\t}\n\n\t/**\n\t * Load balancing config.\n\t *\n\t * @param pickfirst 'pick first' load balancing\n\t * @param roundrobin 'round robin' load balancing\n\t * @param weightedroundrobin 'weighted round robin' load balancing\n\t * @param grpc 'grpc' load balancing\n\t */\n\tpublic record LoadBalancingConfig(@Nullable PickFirstLoadBalancingConfig pickfirst,\n\t\t\t@Nullable RoundRobinLoadBalancingConfig roundrobin,\n\t\t\t@Nullable WeightedRoundRobinLoadBalancingConfig weightedroundrobin,\n\t\t\t@Nullable GrpcLoadBalancingConfig grpc) {\n\n\t\tpublic LoadBalancingConfig {\n\t\t\tif (pickfirst == null && roundrobin == null && weightedroundrobin == null && grpc == null) {\n\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"loadbalancing\", null,\n\t\t\t\t\t\t\"Missing load balancing strategy\");\n\t\t\t}\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\tentries.put(\"loadbalancing.pickfirst\", pickfirst);\n\t\t\t\tentries.put(\"loadbalancing.roundrobin\", roundrobin);\n\t\t\t\tentries.put(\"loadbalancing.weightedroundrobin\", weightedroundrobin);\n\t\t\t\tentries.put(\"loadbalancing.grpc\", grpc);\n\t\t\t});\n\t\t}\n\n\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\tLinkedHashMap<String, Object> grpcJavaConfig = new LinkedHashMap<>();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::pickfirst)\n\t\t\t\t.as(PickFirstLoadBalancingConfig::grpcJavaConfig)\n\t\t\t\t.to((loadBalancingConfig) -> grpcJavaConfig.put(\"pick_first\", loadBalancingConfig));\n\t\t\tmap.from(this::roundrobin)\n\t\t\t\t.as(RoundRobinLoadBalancingConfig::grpcJavaConfig)\n\t\t\t\t.to((loadBalancingConfig) -> grpcJavaConfig.put(\"round_robin\", loadBalancingConfig));\n\t\t\tmap.from(this::weightedroundrobin)\n\t\t\t\t.as(WeightedRoundRobinLoadBalancingConfig::grpcJavaConfig)\n\t\t\t\t.to((loadBalancingConfig) -> grpcJavaConfig.put(\"weighted_round_robin\", loadBalancingConfig));\n\t\t\tmap.from(this::grpc)\n\t\t\t\t.as(GrpcLoadBalancingConfig::grpcJavaConfig)\n\t\t\t\t.to((loadBalancingConfig) -> grpcJavaConfig.put(\"grpclb\", loadBalancingConfig));\n\t\t\treturn grpcJavaConfig;\n\t\t}\n\n\t\t/**\n\t\t * 'pick first' load balancing.\n\t\t *\n\t\t * @param shuffleAddressList randomly shuffle the list of addresses received from\n\t\t * the name resolver before attempting to connect to them.\n\t\t */\n\t\tpublic record PickFirstLoadBalancingConfig(Boolean shuffleAddressList) {\n\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\t// Aligned with PickFirstLoadBalancerProvider\n\t\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(this::shuffleAddressList).to(grpcJavaConfig.in(\"shuffleAddressList\"));\n\t\t\t\treturn grpcJavaConfig.asMap();\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * 'round robin' load balancing.\n\t\t */\n\t\tpublic record RoundRobinLoadBalancingConfig() {\n\n\t\t\t/**\n\t\t\t * Return the gRPC java config as supported by the\n\t\t\t * {@code SecretRoundRobinLoadBalancerProvider}.\n\t\t\t * @return the config\n\t\t\t */\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\treturn Collections.emptyMap();\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * 'weighted round robin' load balancing.\n\t\t *\n\t\t * @param blackoutPeriod must report load metrics continuously for at least this\n\t\t * long before the endpoint weight will be used\n\t\t * @param weightExpirationPeriod if has not reported load metrics in this long,\n\t\t * then we stop using the reported weight\n\t\t * @param outOfBandReportingPeriod load reporting interval to request from the\n\t\t * server\n\t\t * @param enableOutOfBandLoadReport whether to enable out-of-band utilization\n\t\t * reporting collections from the endpoints\n\t\t * @param weightUpdatePeriod how often endpoint weights are recalculated\n\t\t * @param errorUtilizationPenalty multiplier used to adjust endpoint weights with\n\t\t * the error rate calculated as eps/qps\n\t\t */\n\t\tpublic record WeightedRoundRobinLoadBalancingConfig(Duration blackoutPeriod, Duration weightExpirationPeriod,\n\t\t\t\tDuration outOfBandReportingPeriod, Boolean enableOutOfBandLoadReport, Duration weightUpdatePeriod,\n\t\t\t\tFloat errorUtilizationPenalty) {\n\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\t// Aligned with WeightedRoundRobinLoadBalancerProvider\n\t\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(this::blackoutPeriod)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"blackoutPeriod\"));\n\t\t\t\tmap.from(this::weightExpirationPeriod)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"weightExpirationPeriod\"));\n\t\t\t\tmap.from(this::outOfBandReportingPeriod)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"oobReportingPeriod\"));\n\t\t\t\tmap.from(this::enableOutOfBandLoadReport).to(grpcJavaConfig.in(\"enableOobLoadReport\"));\n\t\t\t\tmap.from(this::weightUpdatePeriod)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"weightUpdatePeriod\"));\n\t\t\t\tmap.from(this::errorUtilizationPenalty).to(grpcJavaConfig.in(\"errorUtilizationPenalty\"));\n\t\t\t\treturn grpcJavaConfig.asMap();\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * 'grpc' load balancing.\n\t\t *\n\t\t * @param child what load balancer policies to use for routing between the backend\n\t\t * addresses\n\t\t * @param serviceName override of the service name to be sent to the balancer\n\t\t * @param initialFallbackTimeout timeout in seconds for receiving the server list\n\t\t */\n\t\tpublic record GrpcLoadBalancingConfig(List<LoadBalancingConfig> child, String serviceName,\n\t\t\t\tDuration initialFallbackTimeout) {\n\n\t\t\tpublic GrpcLoadBalancingConfig {\n\t\t\t\tchild.forEach(this::assertChild);\n\t\t\t}\n\n\t\t\tprivate void assertChild(LoadBalancingConfig child) {\n\t\t\t\tif (child.pickfirst() == null && child.roundrobin() == null) {\n\t\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"loadbalancing.grpc.child\", null,\n\t\t\t\t\t\t\t\"Only 'pickfirst' or 'roundrobin' child load balancer strategies can be used\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\t// Aligned with GrpclbLoadBalancerProvider\n\t\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(this::child)\n\t\t\t\t\t.as(listOf(LoadBalancingConfig::grpcJavaConfig))\n\t\t\t\t\t.to(grpcJavaConfig.in(\"childPolicy\"));\n\t\t\t\tmap.from(this::serviceName).to(grpcJavaConfig.in(\"serviceName\"));\n\t\t\t\tmap.from(this::initialFallbackTimeout)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"initialFallbackTimeout\"));\n\t\t\t\treturn grpcJavaConfig.asMap();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Method configuration.\n\t *\n\t * @param name Names of the methods to which this configuration applies\n\t * @param waitForReady Whether RPCs sent to this method should wait until the\n\t * connection is ready by default\n\t * @param maxRequestMessage maximum allowed payload size for an individual request or\n\t * object in a stream\n\t * @param maxResponseMessage maximum allowed payload size for an individual response\n\t * or object in a stream\n\t * @param timeout default timeout for RPCs sent to this method\n\t * @param retry retry policy for outgoing RPCs\n\t * @param hedging hedging policy for outgoing RPCs\n\t */\n\tpublic record MethodConfig(List<Name> name, Boolean waitForReady, DataSize maxRequestMessage,\n\t\t\tDataSize maxResponseMessage, Duration timeout, RetryPolicy retry, HedgingPolicy hedging) {\n\n\t\tpublic MethodConfig {\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\tentries.put(\"method.retry\", retry);\n\t\t\t\tentries.put(\"method.hedging\", hedging);\n\t\t\t});\n\t\t}\n\n\t\tstatic @Nullable List<Map<String, Object>> grpcJavaConfigs(List<MethodConfig> methodConfigs) {\n\t\t\treturn (!CollectionUtils.isEmpty(methodConfigs))\n\t\t\t\t\t? methodConfigs.stream().map(MethodConfig::grpcJavaConfig).toList() : null;\n\t\t}\n\n\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::name).as(listOf(Name::grpcJavaConfig)).to(grpcJavaConfig.in(\"name\"));\n\t\t\tmap.from(this::waitForReady).to(grpcJavaConfig.in(\"waitForReady\"));\n\t\t\tmap.from(this::maxRequestMessage)\n\t\t\t\t.as(ServiceConfig::bytesString)\n\t\t\t\t.to(grpcJavaConfig.in(\"maxRequestMessageBytes\"));\n\t\t\tmap.from(this::maxResponseMessage)\n\t\t\t\t.as(ServiceConfig::bytesString)\n\t\t\t\t.to(grpcJavaConfig.in(\"maxResponseMessageBytes\"));\n\t\t\tmap.from(this::timeout).as(ServiceConfig::durationString).to(grpcJavaConfig.in(\"timeout\"));\n\t\t\tmap.from(this::retry).as(RetryPolicy::grpcJavaConfig).to(grpcJavaConfig.in(\"retryPolicy\"));\n\t\t\tmap.from(this::hedging).as(HedgingPolicy::grpcJavaConfig).to(grpcJavaConfig.in(\"hedgingPolicy\"));\n\t\t\treturn grpcJavaConfig.asMap();\n\t\t}\n\n\t\t/**\n\t\t * The name of a gRPC method.\n\t\t *\n\t\t * @param service service name\n\t\t * @param method method name\n\t\t */\n\t\tpublic record Name(String service, String method) {\n\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(this::service).to(grpcJavaConfig.in(\"service\"));\n\t\t\t\tmap.from(this::method).to(grpcJavaConfig.in(\"method\"));\n\t\t\t\treturn grpcJavaConfig.asMap();\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Retry policy for outgoing RPCs.\n\t\t *\n\t\t * @param maxAttempts maximum number of RPC attempts, including the original\n\t\t * attempt\n\t\t * @param initialBackoff initial exponential backoff\n\t\t * @param maxBackoff maximum exponential backoff\n\t\t * @param backoffMultiplier exponential backoff multiplier\n\t\t * @param perAttemptReceiveTimeout per-attempt receive timeout\n\t\t * @param retryableStatusCodes status codes that may be retried\n\t\t */\n\t\tpublic record RetryPolicy(Integer maxAttempts, Duration initialBackoff, Duration maxBackoff,\n\t\t\t\tDouble backoffMultiplier, Duration perAttemptReceiveTimeout, Set<Status.Code> retryableStatusCodes) {\n\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(this::maxAttempts).as(Objects::toString).to(grpcJavaConfig.in(\"maxAttempts\"));\n\t\t\t\tmap.from(this::initialBackoff)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"initialBackoff\"));\n\t\t\t\tmap.from(this::maxBackoff).as(ServiceConfig::durationString).to(grpcJavaConfig.in(\"maxBackoff\"));\n\t\t\t\tmap.from(this::backoffMultiplier).to(grpcJavaConfig.in(\"backoffMultiplier\"));\n\t\t\t\tmap.from(this::perAttemptReceiveTimeout)\n\t\t\t\t\t.as(ServiceConfig::durationString)\n\t\t\t\t\t.to(grpcJavaConfig.in(\"perAttemptRecvTimeout\"));\n\t\t\t\tmap.from(this::retryableStatusCodes)\n\t\t\t\t\t.as((codes) -> codes.stream().map(Objects::toString).toList())\n\t\t\t\t\t.to(grpcJavaConfig.in(\"retryableStatusCodes\"));\n\t\t\t\treturn grpcJavaConfig.asMap();\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Hedging policy for outgoing RPCs.\n\t\t *\n\t\t * @param maxAttempts maximum number of send attempts\n\t\t * @param delay delay for subsequent RPCs\n\t\t * @param nonFatalStatusCodes status codes which indicate other hedged RPCs may\n\t\t * still succeed\n\t\t */\n\t\tpublic record HedgingPolicy(Integer maxAttempts, Duration delay, Set<Status.Code> nonFatalStatusCodes) {\n\n\t\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(this::maxAttempts).as(Objects::toString).to(grpcJavaConfig.in(\"maxAttempts\"));\n\t\t\t\tmap.from(this::delay).as(ServiceConfig::durationString).to(grpcJavaConfig.in(\"hedgingDelay\"));\n\t\t\t\tmap.from(this::nonFatalStatusCodes)\n\t\t\t\t\t.as((codes) -> codes.stream().map(Objects::toString).toList())\n\t\t\t\t\t.to(grpcJavaConfig.in(\"nonFatalStatusCodes\"));\n\t\t\t\treturn grpcJavaConfig.asMap();\n\t\t\t}\n\n\t\t}\n\t}\n\n\t/**\n\t * Retry throttling policy.\n\t *\n\t * @param maxTokens maximum number of tokens\n\t * @param tokenRatio the token ratio\n\t */\n\tpublic record RetryThrottlingPolicy(Float maxTokens, Float tokenRatio) {\n\n\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::maxTokens).as(Objects::toString).to(grpcJavaConfig.in(\"maxTokens\"));\n\t\t\tmap.from(this::tokenRatio).as(Objects::toString).to(grpcJavaConfig.in(\"tokenRatio\"));\n\t\t\treturn grpcJavaConfig.asMap();\n\t\t}\n\n\t}\n\n\t/**\n\t * Health check configuration.\n\t *\n\t * @param serviceName service name to use in the health-checking request.\n\t */\n\tpublic record HealthCheckConfig(String serviceName) {\n\n\t\tMap<String, Object> grpcJavaConfig() {\n\t\t\tGrpcJavaConfig grpcJavaConfig = new GrpcJavaConfig();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::serviceName).to(grpcJavaConfig.in(HEALTH_CHECK_SERVICE_NAME_KEY));\n\t\t\treturn grpcJavaConfig.asMap();\n\t\t}\n\n\t}\n\n\t/**\n\t * Internal helper to collection gRPC java config.\n\t *\n\t * @param asMap the underlying data as a map\n\t */\n\trecord GrpcJavaConfig(Map<String, Object> asMap) {\n\n\t\tGrpcJavaConfig() {\n\t\t\tthis(new LinkedHashMap<>());\n\t\t}\n\n\t\t<T> Consumer<T> in(String key) {\n\t\t\treturn (value) -> this.asMap.put(key, value);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/ShadedNettyGrpcClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.grpc.client.ChannelCredentialsProvider;\nimport org.springframework.grpc.client.ClientInterceptorsConfigurer;\nimport org.springframework.grpc.client.GrpcChannelFactory;\nimport org.springframework.grpc.client.InProcessGrpcChannelFactory;\nimport org.springframework.grpc.client.ShadedNettyGrpcChannelFactory;\n\n/**\n * {@link Configuration @Configuration} for a Shaded Netty gRPC client.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ io.grpc.netty.shaded.io.netty.channel.Channel.class,\n\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class })\n@ConditionalOnMissingBean(value = GrpcChannelFactory.class, ignored = InProcessGrpcChannelFactory.class)\n@ConditionalOnGrpcClientChannelFactoryEnabled\nclass ShadedNettyGrpcClientConfiguration {\n\n\t@Bean\n\tShadedNettyGrpcChannelFactory shadedNettyGrpcChannelFactory(Environment environment,\n\t\t\tGrpcClientProperties properties, GrpcChannelBuilderCustomizers grpcChannelBuilderCustomizers,\n\t\t\tClientInterceptorsConfigurer interceptorsConfigurer,\n\t\t\tObjectProvider<GrpcChannelFactoryCustomizer> channelFactoryCustomizers,\n\t\t\tChannelCredentialsProvider credentials) {\n\t\tShadedNettyGrpcChannelFactory factory = new ShadedNettyGrpcChannelFactory(\n\t\t\t\tgrpcChannelBuilderCustomizers.forFactory(), interceptorsConfigurer);\n\t\tfactory.setCredentialsProvider(credentials);\n\t\tfactory.setVirtualTargets(new PropertiesVirtualTargets(environment, properties));\n\t\tchannelFactoryCustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/java/org/springframework/boot/grpc/client/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for gRPC clients.\n */\n@NullMarked\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.grpc.client.channelfactory.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable gRPC channel factory bean auto-configuration.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.grpc.client.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable gRPC client auto-configuration.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.grpc.client.inprocess.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to configure the in-process channel factory.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.grpc.client.observation.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Observations on the client.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.grpc.client.autoconfigure.CompositeChannelFactoryAutoConfiguration\norg.springframework.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration\norg.springframework.boot.grpc.client.autoconfigure.GrpcClientObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/CompositeChannelFactoryAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.inprocess.InProcessChannelBuilder;\nimport io.grpc.netty.NettyChannelBuilder;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.grpc.client.CompositeGrpcChannelFactory;\nimport org.springframework.grpc.client.GrpcChannelFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CompositeChannelFactoryAutoConfiguration}.\n *\n * @author Chris Bono\n */\nclass CompositeChannelFactoryAutoConfigurationTests {\n\n\tprivate ApplicationContextRunner contextRunnerWithoutChannelFactories() {\n\t\treturn new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(GrpcClientAutoConfiguration.class, SslAutoConfiguration.class,\n\t\t\t\t\tCompositeChannelFactoryAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class,\n\t\t\t\t\tNettyChannelBuilder.class, InProcessChannelBuilder.class));\n\t}\n\n\t@Test\n\tvoid whenNoChannelFactoriesDoesNotAutoconfigureComposite() {\n\t\tthis.contextRunnerWithoutChannelFactories()\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid whenSingleChannelFactoryDoesNotAutoconfigureComposite() {\n\t\tGrpcChannelFactory channelFactory1 = mock();\n\t\tthis.contextRunnerWithoutChannelFactories()\n\t\t\t.withBean(\"channelFactory1\", GrpcChannelFactory.class, () -> channelFactory1)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcChannelFactory.class)\n\t\t\t\t.getBean(GrpcChannelFactory.class)\n\t\t\t\t.isNotInstanceOf(CompositeGrpcChannelFactory.class)\n\t\t\t\t.isSameAs(channelFactory1));\n\t}\n\n\t@Test\n\tvoid whenMultipleChannelFactoriesWithPrimaryDoesNotAutoconfigureComposite() {\n\t\tGrpcChannelFactory channelFactory1 = mock();\n\t\tGrpcChannelFactory channelFactory2 = mock();\n\t\tthis.contextRunnerWithoutChannelFactories()\n\t\t\t.withBean(\"channelFactory1\", GrpcChannelFactory.class, () -> channelFactory1)\n\t\t\t.withBean(\"channelFactory2\", GrpcChannelFactory.class, () -> channelFactory2, (bd) -> bd.setPrimary(true))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t\t.containsOnlyKeys(\"channelFactory1\", \"channelFactory2\");\n\t\t\t\tassertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t\t.isNotInstanceOf(CompositeGrpcChannelFactory.class)\n\t\t\t\t\t.isSameAs(channelFactory2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenMultipleChannelFactoriesDoesAutoconfigureComposite() {\n\t\tGrpcChannelFactory channelFactory1 = mock();\n\t\tGrpcChannelFactory channelFactory2 = mock();\n\t\tthis.contextRunnerWithoutChannelFactories()\n\t\t\t.withBean(\"channelFactory1\", GrpcChannelFactory.class, () -> channelFactory1)\n\t\t\t.withBean(\"channelFactory2\", GrpcChannelFactory.class, () -> channelFactory2)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t\t.containsOnlyKeys(\"channelFactory1\", \"channelFactory2\", \"compositeChannelFactory\");\n\t\t\t\tassertThat(context).getBean(GrpcChannelFactory.class).isInstanceOf(CompositeGrpcChannelFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid compositeAutoconfiguredAsExpected() {\n\t\tthis.contextRunnerWithoutChannelFactories()\n\t\t\t.withUserConfiguration(MultipleFactoriesTestConfig.class)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(CompositeGrpcChannelFactory.class)\n\t\t\t\t.extracting(\"channelFactories\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(GrpcChannelFactory.class))\n\t\t\t\t.containsExactly(MultipleFactoriesTestConfig.CHANNEL_FACTORY_BAR,\n\t\t\t\t\t\tMultipleFactoriesTestConfig.CHANNEL_FACTORY_BAZ,\n\t\t\t\t\t\tMultipleFactoriesTestConfig.CHANNEL_FACTORY_FOO));\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleFactoriesTestConfig {\n\n\t\tstatic GrpcChannelFactory CHANNEL_FACTORY_FOO = mock();\n\t\tstatic GrpcChannelFactory CHANNEL_FACTORY_BAR = mock();\n\t\tstatic GrpcChannelFactory CHANNEL_FACTORY_BAZ = mock();\n\n\t\t@Bean\n\t\t@Order(3)\n\t\tGrpcChannelFactory channelFactoryFoo() {\n\t\t\treturn CHANNEL_FACTORY_FOO;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tGrpcChannelFactory channelFactoryBar() {\n\t\t\treturn CHANNEL_FACTORY_BAR;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tGrpcChannelFactory channelFactoryBaz() {\n\t\t\treturn CHANNEL_FACTORY_BAZ;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcChannelBuilderCustomizersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ManagedChannelBuilder;\nimport io.grpc.netty.NettyChannelBuilder;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.boot.grpc.client.autoconfigure.ServiceConfig.HealthCheckConfig;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link GrpcChannelBuilderCustomizers}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass GrpcChannelBuilderCustomizersTests {\n\n\t@Test\n\tvoid applyWhenHasProperties() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tchannel.setUserAgent(\"spring-boot\");\n\t\tproperties.getChannel().put(\"target\", channel);\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tthen(builder).should().userAgent(\"spring-boot\");\n\t}\n\n\t@Test\n\tvoid applyWhenHasCompressorRegistry() {\n\t\tCompressorRegistry compressorRegistry = mock();\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(null, compressorRegistry, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tthen(builder).should().compressorRegistry(compressorRegistry);\n\t}\n\n\t@Test\n\tvoid applyWhenHasDecompressorRegistry() {\n\t\tDecompressorRegistry decompressorRegistry = mock();\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(null, null, decompressorRegistry,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tthen(builder).should().decompressorRegistry(decompressorRegistry);\n\t}\n\n\t@Test\n\tvoid applyWhenEmptyCustomizersDoesNothing() {\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tnew GrpcChannelBuilderCustomizers(Collections.emptyList()).apply(\"target\", builder);\n\t\tthen(builder).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenSimpleChannelBuilder() {\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(\n\t\t\t\tList.of(new SimpleChannelBuilderCustomizer()));\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tthen(builder).should().flowControlWindow(100);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid applyWhenGenericCustomizersRespectsGeneric() {\n\t\tList<TestCustomizer<?>> list = new ArrayList<>();\n\t\tlist.add(new TestCustomizer<>());\n\t\tlist.add(new TestNettyChannelBuilderCustomizer());\n\t\tlist.add(new TestShadedNettyChannelBuilderCustomizer());\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(list);\n\t\tcustomizers.apply(\"target\", mock(ManagedChannelBuilder.class));\n\t\tassertThat(list.get(0).getCount()).isOne();\n\t\tassertThat(list.get(1).getCount()).isZero();\n\t\tassertThat(list.get(2).getCount()).isZero();\n\t\tcustomizers.apply(\"target\", mock(NettyChannelBuilder.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t\tassertThat(list.get(2).getCount()).isZero();\n\t\tcustomizers.apply(\"target\", mock(io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(3);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t\tassertThat(list.get(2).getCount()).isOne();\n\t}\n\n\t@Test\n\tvoid applyWhenHasGrpcClientDefaultServiceConfigCustomizers() {\n\t\tGrpcClientDefaultServiceConfigCustomizer defaultConfigCustomizer1 = (target, defaultServiceConfig) -> {\n\t\t\tdefaultServiceConfig.put(\"c\", \"v1\");\n\t\t\tdefaultServiceConfig.put(\"c1\", \"v1\");\n\t\t};\n\t\tGrpcClientDefaultServiceConfigCustomizer defaultConfigCustomizer2 = (target, defaultServiceConfig) -> {\n\t\t\tdefaultServiceConfig.put(\"c\", \"v2\");\n\t\t\tdefaultServiceConfig.put(\"c2\", \"v2\");\n\t\t};\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(null, null, null,\n\t\t\t\tCollections.emptyList(), List.of(defaultConfigCustomizer1, defaultConfigCustomizer2));\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\texpected.put(\"c\", \"v2\");\n\t\texpected.put(\"c1\", \"v1\");\n\t\texpected.put(\"c2\", \"v2\");\n\t\tthen(builder).should().defaultServiceConfig(expected);\n\t}\n\n\t@Test\n\tvoid applyWhenHasChannelHealthAddsHealthServiceConfig() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tchannel.getHealth().setEnabled(true);\n\t\tchannel.getHealth().setServiceName(\"testservice\");\n\t\tproperties.getChannel().put(\"target\", channel);\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\texpected.put(\"healthCheckConfig\", Map.of(\"serviceName\", \"testservice\"));\n\t\tthen(builder).should().defaultServiceConfig(expected);\n\t}\n\n\t@Test\n\tvoid applyWhenHasDefaultHealthAddsHealthServiceConfig() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tchannel.getHealth().setEnabled(true);\n\t\tchannel.getHealth().setServiceName(\"testdefaultservice\");\n\t\tproperties.getChannel().put(\"default\", channel);\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\texpected.put(\"healthCheckConfig\", Map.of(\"serviceName\", \"testdefaultservice\"));\n\t\tthen(builder).should().defaultServiceConfig(expected);\n\t}\n\n\t@Test\n\tvoid applyWhenHasServiceConfig() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tServiceConfig serviceConfig = new ServiceConfig(null, null, null, new HealthCheckConfig(\"test\"));\n\t\tchannel.setServiceConfig(serviceConfig);\n\t\tproperties.getChannel().put(\"default\", channel);\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\texpected.put(\"healthCheckConfig\", Map.of(\"serviceName\", \"test\"));\n\t\tthen(builder).should().defaultServiceConfig(expected);\n\t}\n\n\t@Test\n\tvoid applyWhenHasClashingServiceConfigAndHealth() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tchannel.getHealth().setEnabled(true);\n\t\tchannel.getHealth().setServiceName(\"fromhealth\");\n\t\tServiceConfig serviceConfig = new ServiceConfig(null, null, null, new HealthCheckConfig(\"fromservice\"));\n\t\tchannel.setServiceConfig(serviceConfig);\n\t\tproperties.getChannel().put(\"default\", channel);\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tassertThatIllegalStateException().isThrownBy(() -> customizers.apply(\"target\", builder))\n\t\t\t.withMessage(\"Unable to change health check config service name from 'fromservice' to 'fromhealth'\");\n\t}\n\n\t@Test\n\tvoid applyWhenHealthEnabledAndNoServiceNameAddsHealthConfig() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tchannel.getHealth().setEnabled(true);\n\t\tproperties.getChannel().put(\"target\", channel);\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tMap<String, Object> expected = new LinkedHashMap<>();\n\t\texpected.put(\"healthCheckConfig\", Map.of(\"serviceName\", \"\"));\n\t\tthen(builder).should().defaultServiceConfig(expected);\n\t}\n\n\t@Test\n\tvoid applyWhenNoCustomizersOrHealthDoesNotSetDefaultServiceConfig() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tGrpcChannelBuilderCustomizers customizers = new GrpcChannelBuilderCustomizers(properties, null, null,\n\t\t\t\tCollections.emptyList(), Collections.emptyList());\n\t\tNettyChannelBuilder builder = mock(NettyChannelBuilder.class);\n\t\tcustomizers.apply(\"target\", builder);\n\t\tthen(builder).should(never()).defaultServiceConfig(any());\n\t}\n\n\tstatic class SimpleChannelBuilderCustomizer implements GrpcChannelBuilderCustomizer<NettyChannelBuilder> {\n\n\t\t@Override\n\t\tpublic void customize(String target, NettyChannelBuilder channelBuilder) {\n\t\t\tchannelBuilder.flowControlWindow(100);\n\t\t}\n\n\t}\n\n\t/**\n\t * Test customizer that will match any {@link GrpcChannelBuilderCustomizer}.\n\t *\n\t * @param <T> the builder type\n\t */\n\tstatic class TestCustomizer<T extends ManagedChannelBuilder<T>> implements GrpcChannelBuilderCustomizer<T> {\n\n\t\tprivate int count;\n\n\t\t@Override\n\t\tpublic void customize(String targetOrChannelName, T channelBuilder) {\n\t\t\tthis.count++;\n\t\t}\n\n\t\tint getCount() {\n\t\t\treturn this.count;\n\t\t}\n\n\t}\n\n\t/**\n\t * Test customizer that will match only {@link NettyChannelBuilder}.\n\t */\n\tstatic class TestNettyChannelBuilderCustomizer extends TestCustomizer<NettyChannelBuilder> {\n\n\t}\n\n\t/**\n\t * Test customizer that will match only\n\t * {@link io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder}.\n\t */\n\tstatic class TestShadedNettyChannelBuilderCustomizer\n\t\t\textends TestCustomizer<io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport io.grpc.Codec;\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ManagedChannelBuilder;\nimport io.grpc.inprocess.InProcessChannelBuilder;\nimport io.grpc.kotlin.AbstractCoroutineStub;\nimport io.grpc.netty.NettyChannelBuilder;\nimport io.grpc.stub.AbstractStub;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration.GrpcClientCoroutineStubConfiguration;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.boot.grpc.client.autoconfigure.test.scan.DummyBlockingGrpc;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.grpc.client.ChannelCredentialsProvider;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.GrpcChannelFactory;\nimport org.springframework.grpc.client.InProcessGrpcChannelFactory;\nimport org.springframework.grpc.client.NettyGrpcChannelFactory;\nimport org.springframework.grpc.client.ShadedNettyGrpcChannelFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyMap;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link GrpcClientAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\n@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\nclass GrpcClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GrpcClientAutoConfiguration.class, SslAutoConfiguration.class));\n\n\tprivate final ApplicationContextRunner contextRunnerWithoutInProcessChannelFactory = this.contextRunner\n\t\t.withPropertyValues(\"spring.grpc.client.inprocess.enabled=false\");\n\n\t@Test\n\tvoid whenGrpcStubNotOnClasspathThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(AbstractStub.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenGrpcKotlinIsNotOnClasspathThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(AbstractCoroutineStub.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientCoroutineStubConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenClientEnabledPropertySetFalseThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenClientEnabledPropertyNotSetThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GrpcClientAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenClientEnabledPropertySetTrueThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcClientAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedCredentialsProviderDoesNotAutoConfigureBean() {\n\t\tChannelCredentialsProvider customCredentialsProvider = mock(ChannelCredentialsProvider.class);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customCredentialsProvider\", ChannelCredentialsProvider.class, () -> customCredentialsProvider)\n\t\t\t.run((context) -> assertThat(context).getBean(ChannelCredentialsProvider.class)\n\t\t\t\t.isSameAs(customCredentialsProvider));\n\t}\n\n\t@Test\n\tvoid credentialsProviderAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(PropertiesChannelCredentialsProvider.class)\n\t\t\t.hasFieldOrPropertyWithValue(\"properties\", context.getBean(GrpcClientProperties.class))\n\t\t\t.extracting(\"bundles\")\n\t\t\t.isInstanceOf(SslBundles.class));\n\t}\n\n\t@Test\n\tvoid clientPropertiesAutoConfiguredResolvesPlaceholders() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.client.channel.c1.target=my-server-${channelName}:8888\", \"channelName=foo\")\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcClientProperties.class).satisfies((properties) -> {\n\t\t\t\tChannel channel = properties.getChannel().get(\"c1\");\n\t\t\t\tassertThat(channel).isNotNull();\n\t\t\t\tassertThat(channel.getTarget()).isEqualTo(\"my-server-foo:8888\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid clientPropertiesChannelCustomizerAutoConfiguredWithHealthAsExpected() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.client.channel.test.health.enabled=true\",\n\t\t\t\t\t\"spring.grpc.client.channel.test.health.service-name=my-service\")\n\t\t\t.run((context) -> {\n\t\t\t\tGrpcChannelBuilderCustomizers customizers = context.getBean(GrpcChannelBuilderCustomizers.class);\n\t\t\t\tManagedChannelBuilder<?> builder = Mockito.mock();\n\t\t\t\tcustomizers.apply(\"test\", builder);\n\t\t\t\tMap<String, ?> healthCheckConfig = Map.of(\"healthCheckConfig\", Map.of(\"serviceName\", \"my-service\"));\n\t\t\t\tthen(builder).should().defaultServiceConfig(healthCheckConfig);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientPropertiesChannelCustomizerAutoConfiguredWithoutHealthAsExpected() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGrpcChannelBuilderCustomizers customizers = context.getBean(GrpcChannelBuilderCustomizers.class);\n\t\t\tManagedChannelBuilder<?> builder = Mockito.mock();\n\t\t\tcustomizers.apply(\"test\", builder);\n\t\t\tthen(builder).should(never()).defaultServiceConfig(anyMap());\n\t\t});\n\t}\n\n\t@Test\n\tvoid compressionCustomizerAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGrpcChannelBuilderCustomizers customizers = context.getBean(GrpcChannelBuilderCustomizers.class);\n\t\t\tCompressorRegistry compressorRegistry = context.getBean(CompressorRegistry.class);\n\t\t\tManagedChannelBuilder<?> builder = Mockito.mock();\n\t\t\tcustomizers.apply(\"testChannel\", builder);\n\t\t\tthen(builder).should().compressorRegistry(compressorRegistry);\n\t\t});\n\t}\n\n\t@Test\n\tvoid compressionCustomizerWhenNoRegistry() {\n\t\t// Codec class guards the imported GrpcCodecConfiguration to hide registry\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Codec.class)).run((context) -> {\n\t\t\tGrpcChannelBuilderCustomizers customizers = context.getBean(GrpcChannelBuilderCustomizers.class);\n\t\t\tManagedChannelBuilder<?> builder = Mockito.mock();\n\t\t\tcustomizers.apply(\"testChannel\", builder);\n\t\t\tthen(builder).should(never()).compressorRegistry(any());\n\t\t});\n\t}\n\n\t@Test\n\tvoid decompressionCustomizerAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGrpcChannelBuilderCustomizers customizers = context.getBean(GrpcChannelBuilderCustomizers.class);\n\t\t\tDecompressorRegistry decompressorRegistry = context.getBean(DecompressorRegistry.class);\n\t\t\tManagedChannelBuilder<?> builder = Mockito.mock();\n\t\t\tcustomizers.apply(\"testChannel\", builder);\n\t\t\tthen(builder).should().decompressorRegistry(decompressorRegistry);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenNoDecompressorRegistryThenDecompressionCustomizerIsNotConfigured() {\n\t\t// Codec class guards the imported GrpcCodecConfiguration to hide registry\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Codec.class)).run((context) -> {\n\t\t\tGrpcChannelBuilderCustomizers customizers = context.getBean(GrpcChannelBuilderCustomizers.class);\n\t\t\tManagedChannelBuilder<?> builder = Mockito.mock();\n\t\t\tcustomizers.apply(\"testChannel\", builder);\n\t\t\tthen(builder).should(never()).compressorRegistry(any());\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenInProcessEnabledPropNotSetDoesAutoconfigureInProcess() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t.containsKey(\"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenInProcessEnabledPropSetToTrueDoesAutoconfigureInProcess() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.inprocess.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t.containsKey(\"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenInProcessEnabledPropSetToFalseDoesNotAutoconfigureInProcess() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.inprocess.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t.doesNotContainKey(\"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenInProcessIsNotOnClasspathDoesNotAutoconfigureInProcess() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(InProcessChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t.doesNotContainKey(\"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedInProcessChannelFactoryDoesNotAutoConfigureBean() {\n\t\tInProcessGrpcChannelFactory customChannelFactory = mock();\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyChannelBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.withBean(\"customChannelFactory\", InProcessGrpcChannelFactory.class, () -> customChannelFactory)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class).isSameAs(customChannelFactory));\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedChannelFactoryDoesNotAutoConfigureNettyOrShadedNetty() {\n\t\tGrpcChannelFactory customChannelFactory = mock();\n\t\tthis.contextRunnerWithoutInProcessChannelFactory\n\t\t\t.withBean(\"customChannelFactory\", GrpcChannelFactory.class, () -> customChannelFactory)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class).isSameAs(customChannelFactory));\n\t}\n\n\t@Test\n\tvoid userDefinedChannelFactoryWithInProcessChannelFactory() {\n\t\tGrpcChannelFactory customChannelFactory = mock();\n\t\tthis.contextRunner.withBean(\"customChannelFactory\", GrpcChannelFactory.class, () -> customChannelFactory)\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t.containsOnlyKeys(\"customChannelFactory\", \"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenShadedAndNonShadedNettyOnClasspathShadedNettyFactoryIsAutoConfigured() {\n\t\tthis.contextRunnerWithoutInProcessChannelFactory\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(ShadedNettyGrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid shadedNettyWithInProcessChannelFactory() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t.containsOnlyKeys(\"shadedNettyGrpcChannelFactory\", \"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenOnlyNonShadedNettyOnClasspathNonShadedNettyFactoryIsAutoConfigured() {\n\t\tthis.contextRunnerWithoutInProcessChannelFactory\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(NettyGrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid nonShadedNettyWithInProcessChannelFactory() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcChannelFactory.class)\n\t\t\t\t.containsOnlyKeys(\"nettyGrpcChannelFactory\", \"inProcessGrpcChannelFactory\"));\n\t}\n\n\t@Test\n\tvoid whenShadedNettyAndNettyNotOnClasspathNoChannelFactoryIsAutoConfigured() {\n\t\tthis.contextRunnerWithoutInProcessChannelFactory\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyChannelBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid noChannelFactoryWithInProcessChannelFactory() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyChannelBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(InProcessGrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid shadedNettyChannelFactoryAutoConfiguredAsExpected() {\n\t\tthis.contextRunnerWithoutInProcessChannelFactory\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(ShadedNettyGrpcChannelFactory.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"credentials\", context.getBean(PropertiesChannelCredentialsProvider.class))\n\t\t\t\t.extracting(\"targets\")\n\t\t\t\t.isInstanceOf(PropertiesVirtualTargets.class));\n\t}\n\n\t@Test\n\tvoid nettyChannelFactoryAutoConfiguredAsExpected() {\n\t\tthis.contextRunnerWithoutInProcessChannelFactory\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(NettyGrpcChannelFactory.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"credentials\", context.getBean(PropertiesChannelCredentialsProvider.class))\n\t\t\t\t.extracting(\"targets\")\n\t\t\t\t.isInstanceOf(PropertiesVirtualTargets.class));\n\t}\n\n\t@Test\n\tvoid inProcessChannelFactoryAutoConfiguredAsExpected() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyChannelBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(InProcessGrpcChannelFactory.class)\n\t\t\t\t.extracting(\"credentials\")\n\t\t\t\t.isSameAs(ChannelCredentialsProvider.INSECURE));\n\t}\n\n\t@Test\n\tvoid shadedNettyChannelFactoryAutoConfiguredWithCustomizers() {\n\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder builder = mock();\n\t\tchannelFactoryAutoConfiguredWithCustomizers(this.contextRunnerWithoutInProcessChannelFactory, builder,\n\t\t\t\tShadedNettyGrpcChannelFactory.class);\n\t}\n\n\t@Test\n\tvoid nettyChannelFactoryAutoConfiguredWithCustomizers() {\n\t\tNettyChannelBuilder builder = mock();\n\t\tchannelFactoryAutoConfiguredWithCustomizers(\n\t\t\t\tthis.contextRunnerWithoutInProcessChannelFactory.withClassLoader(\n\t\t\t\t\t\tnew FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class)),\n\t\t\t\tbuilder, NettyGrpcChannelFactory.class);\n\t}\n\n\t@Test\n\tvoid inProcessChannelFactoryAutoConfiguredWithCustomizers() {\n\t\tInProcessChannelBuilder builder = mock();\n\t\tchannelFactoryAutoConfiguredWithCustomizers(\n\t\t\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(NettyChannelBuilder.class,\n\t\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.class)),\n\t\t\t\tbuilder, InProcessGrpcChannelFactory.class);\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> void channelFactoryAutoConfiguredWithCustomizers(\n\t\t\tApplicationContextRunner contextRunner, ManagedChannelBuilder<T> mockChannelBuilder,\n\t\t\tClass<?> expectedChannelFactoryType) {\n\t\tcontextRunner.withUserConfiguration(ChannelBuilderCustomizersConfig.class)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcChannelFactory.class)\n\t\t\t\t.isInstanceOf(expectedChannelFactoryType)\n\t\t\t\t.extracting(\"globalCustomizers\", InstanceOfAssertFactories.list(GrpcChannelBuilderCustomizer.class))\n\t\t\t\t.satisfies((allCustomizers) -> {\n\t\t\t\t\tallCustomizers.forEach((c) -> c.customize(\"channel1\", mockChannelBuilder));\n\t\t\t\t\tInOrder ordered = inOrder(mockChannelBuilder);\n\t\t\t\t\tordered.verify(mockChannelBuilder).keepAliveTime(40L, TimeUnit.SECONDS);\n\t\t\t\t\tordered.verify(mockChannelBuilder).keepAliveTime(50L, TimeUnit.SECONDS);\n\t\t\t\t}));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@AutoConfigurationPackage(basePackageClasses = DummyBlockingGrpc.class)\n\tstatic class AutoConfigurePackagesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ChannelBuilderCustomizersConfig {\n\n\t\t@Bean\n\t\t@Order(100)\n\t\t<T extends ManagedChannelBuilder<T>> GrpcChannelBuilderCustomizer<T> customizerOne() {\n\t\t\treturn (target, builder) -> builder.keepAliveTime(40L, TimeUnit.SECONDS);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(200)\n\t\t<T extends ManagedChannelBuilder<T>> GrpcChannelBuilderCustomizer<T> customizerTwo() {\n\t\t\treturn (target, builder) -> builder.keepAliveTime(50L, TimeUnit.SECONDS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.util.Map;\n\nimport io.grpc.stub.AbstractStub;\nimport io.micrometer.core.instrument.binder.grpc.ObservationGrpcClientInterceptor;\nimport io.micrometer.observation.ObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.grpc.client.GlobalClientInterceptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link GrpcClientObservationAutoConfiguration}.\n *\n * @author Chris Bono\n */\nclass GrpcClientObservationAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfigurations = AutoConfigurations\n\t\t.of(GrpcClientObservationAutoConfiguration.class);\n\n\tprivate ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(autoConfigurations)\n\t\t.withBean(\"observationRegistry\", ObservationRegistry.class, Mockito::mock);\n\n\t@Test\n\tvoid whenObservationRegistryNotOnClasspathAutoConfigSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ObservationRegistry.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationGrpcClientInterceptorNotOnClasspathAutoConfigSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ObservationGrpcClientInterceptor.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationRegistryNotProvidedThenAutoConfigSkipped() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationPropertyEnabledThenAutoConfigNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.observation.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationPropertyDisabledThenAutoConfigIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.observation.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenClientEnabledPropertyNotSetThenAutoConfigNotSkipped() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenClientEnabledPropertySetTrueThenAutoConfigIsNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenClientEnabledPropertySetFalseThenAutoConfigIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.client.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenGrpcStubNotOnClasspathThenAutoConfigIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(AbstractStub.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenAllConditionsAreMetThenInterceptorConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ObservationGrpcClientInterceptor.class);\n\t\t\tMap<String, Object> annotated = context.getBeansWithAnnotation(GlobalClientInterceptor.class);\n\t\t\tassertThat(annotated).hasEntrySatisfying(\"grpcClientObservationInterceptor\",\n\t\t\t\t\tObservationGrpcClientInterceptor.class::isInstance);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GrpcClientProperties}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass GrpcClientPropertiesTests {\n\n\t@Test\n\t@WithResource(name = \"client.yaml\", content = \"\"\"\n\t\t\tchannel:\n\t\t\t  a:\n\t\t\t   target: static://my-server:8888\n\t\t\t  b:\n\t\t\t   user-agent: me\"\"\")\n\tvoid defaultValues() throws Exception {\n\t\tGrpcClientProperties properties = bind();\n\t\tChannel channelA = properties.getChannel().get(\"a\");\n\t\tassertThat(channelA).isNotNull();\n\t\tassertThat(channelA.getUserAgent()).isNull();\n\t\tassertThat(channelA.isBypassCertificateValidation()).isFalse();\n\t\tassertThat(channelA.getInbound().getMessage().getMaxSize()).isEqualTo(DataSize.ofBytes(4194304));\n\t\tassertThat(channelA.getInbound().getMetadata().getMaxSize()).isEqualTo(DataSize.ofBytes(8192));\n\t\tassertThat(channelA.getDefault().getDeadline()).isNull();\n\t\tassertThat(channelA.getIdle().getTimeout()).isEqualTo(Duration.ofSeconds(20));\n\t\tassertThat(channelA.getKeepalive().getTime()).isEqualTo(Duration.ofMinutes(5));\n\t\tassertThat(channelA.getKeepalive().getTimeout()).isEqualTo(Duration.ofSeconds(20));\n\t\tassertThat(channelA.getKeepalive().isWithoutCalls()).isFalse();\n\t\tassertThat(channelA.getSsl().getEnabled()).isNull();\n\t\tassertThat(channelA.getSsl().getBundle()).isNull();\n\t\tChannel channelB = properties.getChannel().get(\"b\");\n\t\tassertThat(channelB).isNotNull();\n\t\tassertThat(channelB.getTarget()).isEqualTo(\"static://localhost:9090\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"client.yaml\", content = \"\"\"\n\t\t\tchannel:\n\t\t\t  test:\n\t\t\t    target: static://my-server:8888\n\t\t\t    user-agent: me\n\t\t\t    bypass-certificate-validation: true\n\t\t\t    inbound:\n\t\t\t      message:\n\t\t\t        max-size: 200MB\n\t\t\t      metadata:\n\t\t\t        max-size: 1GB\n\t\t\t    default:\n\t\t\t      deadline: 1s\n\t\t\t      load-balancing-policy: pick_first\n\t\t\t    idle:\n\t\t\t      timeout: 1m\n\t\t\t    keepalive:\n\t\t\t      time: 200s\n\t\t\t      timeout: 60000ms\n\t\t\t      without-calls: true\n\t\t\t    ssl:\n\t\t\t      enabled: true\n\t\t\t      bundle: my-bundle\n\t\t\t    health:\n\t\t\t      enabled: true\n\t\t\t      service-name: my-service\"\"\")\n\tvoid specificProperties() throws Exception {\n\t\tGrpcClientProperties properties = bind();\n\t\tChannel channel = properties.getChannel().get(\"test\");\n\t\tassertThat(channel).isNotNull();\n\t\tassertThat(channel.getTarget()).isEqualTo(\"static://my-server:8888\");\n\t\tassertThat(channel.getUserAgent()).isEqualTo(\"me\");\n\t\tassertThat(channel.isBypassCertificateValidation()).isTrue();\n\t\tassertThat(channel.getInbound().getMessage().getMaxSize()).isEqualTo(DataSize.ofMegabytes(200));\n\t\tassertThat(channel.getInbound().getMetadata().getMaxSize()).isEqualTo(DataSize.ofGigabytes(1));\n\t\tassertThat(channel.getDefault().getDeadline()).isEqualTo(Duration.ofSeconds(1));\n\t\tassertThat(channel.getIdle().getTimeout()).isEqualTo(Duration.ofMinutes(1));\n\t\tassertThat(channel.getKeepalive().getTime()).isEqualTo(Duration.ofSeconds(200));\n\t\tassertThat(channel.getKeepalive().getTimeout()).isEqualTo(Duration.ofMillis(60000));\n\t\tassertThat(channel.getKeepalive().isWithoutCalls()).isTrue();\n\t\tassertThat(channel.getSsl().getEnabled()).isTrue();\n\t\tassertThat(channel.getSsl().getBundle()).isEqualTo(\"my-bundle\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"client.yaml\", content = \"\"\"\n\t\t\tchannel:\n\t\t\t  test:\n\t\t\t    idle:\n\t\t\t      timeout: 1\n\t\t\t    keepalive:\n\t\t\t      time: 60\n\t\t\t      timeout: 5\"\"\")\n\tvoid withoutKeepAliveUnitsSpecified() throws Exception {\n\t\tGrpcClientProperties properties = bind();\n\t\tChannel channel = properties.getChannel().get(\"test\");\n\t\tassertThat(channel).isNotNull();\n\t\tassertThat(channel.getIdle().getTimeout()).isEqualTo(Duration.ofSeconds(1));\n\t\tassertThat(channel.getKeepalive().getTime()).isEqualTo(Duration.ofSeconds(60));\n\t\tassertThat(channel.getKeepalive().getTimeout()).isEqualTo(Duration.ofSeconds(5));\n\t}\n\n\t@Test\n\t@WithResource(name = \"client.yaml\", content = \"\"\"\n\t\t\tchannel:\n\t\t\t  test:\n\t\t\t    inbound:\n\t\t\t      message:\n\t\t\t        max-size: 1000\n\t\t\t      metadata:\n\t\t\t        max-size: 256\"\"\")\n\tvoid withoutInboundSizeUnitsSpecified() throws Exception {\n\t\tGrpcClientProperties properties = bind();\n\t\tChannel channel = properties.getChannel().get(\"test\");\n\t\tassertThat(channel).isNotNull();\n\t\tassertThat(channel.getInbound().getMessage().getMaxSize()).isEqualTo(DataSize.ofBytes(1000));\n\t\tassertThat(channel.getInbound().getMetadata().getMaxSize()).isEqualTo(DataSize.ofBytes(256));\n\t}\n\n\tprivate GrpcClientProperties bind() throws Exception {\n\t\tStandardEnvironment environment = new StandardEnvironment();\n\t\tnew YamlPropertySourceLoader().load(\"client.yaml\", new ClassPathResource(\"client.yaml\"))\n\t\t\t.forEach(environment.getPropertySources()::addLast);\n\t\treturn Binder.get(environment)\n\t\t\t.bind(\"\", Bindable.of(GrpcClientProperties.class))\n\t\t\t.orElseGet(GrpcClientProperties::new);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcCodecConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport io.grpc.Codec;\nimport io.grpc.Compressor;\nimport io.grpc.CompressorRegistry;\nimport io.grpc.Decompressor;\nimport io.grpc.DecompressorRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcClientCodecConfiguration}.\n *\n * @author Andrei Lisa\n */\nclass GrpcCodecConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GrpcClientCodecConfiguration.class));\n\n\t@Test\n\tvoid whenCodecNotOnClasspathThenAutoconfigurationSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Codec.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcClientCodecConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenHasCustomCompressorRegistryDoesNotAutoConfigureBean() {\n\t\tCompressorRegistry customRegistry = mock();\n\t\tthis.contextRunner.withBean(\"customCompressorRegistry\", CompressorRegistry.class, () -> customRegistry)\n\t\t\t.run((context) -> assertThat(context).getBean(CompressorRegistry.class).isSameAs(customRegistry));\n\t}\n\n\t@Test\n\tvoid compressorRegistryAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(CompressorRegistry.class)\n\t\t\t.isSameAs(CompressorRegistry.getDefaultInstance()));\n\t}\n\n\t@Test\n\tvoid whenCustomCompressorsThenCompressorRegistryIsNewInstance() {\n\t\tCompressor compressor = mock();\n\t\tgiven(compressor.getMessageEncoding()).willReturn(\"foo\");\n\t\tthis.contextRunner.withBean(Compressor.class, () -> compressor).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CompressorRegistry.class);\n\t\t\tCompressorRegistry registry = context.getBean(CompressorRegistry.class);\n\t\t\tassertThat(registry).isNotSameAs(CompressorRegistry.getDefaultInstance());\n\t\t\tassertThat(registry.lookupCompressor(\"foo\")).isSameAs(compressor);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasCustomDecompressorRegistryDoesNotAutoConfigureBean() {\n\t\tDecompressorRegistry customRegistry = mock();\n\t\tthis.contextRunner.withBean(\"customDecompressorRegistry\", DecompressorRegistry.class, () -> customRegistry)\n\t\t\t.run((context) -> assertThat(context).getBean(DecompressorRegistry.class).isSameAs(customRegistry));\n\t}\n\n\t@Test\n\tvoid decompressorRegistryAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(DecompressorRegistry.class)\n\t\t\t.isSameAs(DecompressorRegistry.getDefaultInstance()));\n\t}\n\n\t@Test\n\tvoid whenCustomDecompressorsThenDecompressorRegistryIsNewInstance() {\n\t\tDecompressor decompressor = mock();\n\t\tgiven(decompressor.getMessageEncoding()).willReturn(\"foo\");\n\t\tthis.contextRunner.withBean(Decompressor.class, () -> decompressor).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DecompressorRegistry.class);\n\t\t\tDecompressorRegistry registry = context.getBean(DecompressorRegistry.class);\n\t\t\tassertThat(registry).isNotSameAs(DecompressorRegistry.getDefaultInstance());\n\t\t\tassertThat(registry.lookupDecompressor(\"foo\")).isSameAs(decompressor);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesChannelCredentialsProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\nimport javax.net.ssl.X509ExtendedTrustManager;\n\nimport io.grpc.ChannelCredentials;\nimport io.grpc.InsecureChannelCredentials;\nimport io.grpc.TlsChannelCredentials;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslManagerBundle;\nimport org.springframework.grpc.client.ChannelCredentialsProvider;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PropertiesChannelCredentialsProvider}.\n *\n * @author Phillip Webb\n */\nclass PropertiesChannelCredentialsProviderTests {\n\n\tprivate final TrustManager[] trustManagers = { mock() };\n\n\tprivate final KeyManager[] keyManagers = { mock() };\n\n\t@Test\n\tvoid getChannelCredentialsWhenTargetMatchesChannel() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.getSsl().setEnabled(true);\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry();\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tTlsChannelCredentials credentials = (TlsChannelCredentials) provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials.getTrustManagers()).isNull();\n\t\tassertThat(credentials.getKeyManagers()).isNull();\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenTargetDoesNotMatchChannelAndHasDefault() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.getSsl().setEnabled(true);\n\t\tproperties.getChannel().put(\"default\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry();\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tTlsChannelCredentials credentials = (TlsChannelCredentials) provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials.getTrustManagers()).isNull();\n\t\tassertThat(credentials.getKeyManagers()).isNull();\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenTargetDoesNotMatchChannelAndHasNoDefaultUsesInsecure() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry();\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tChannelCredentials credentials = provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials).isInstanceOf(InsecureChannelCredentials.class);\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenSslExplicitlyDisabled() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.getSsl().setEnabled(false);\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry();\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tChannelCredentials credentials = provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials).isInstanceOf(InsecureChannelCredentials.class);\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenSslExplicitlyEnabledAndNoBundle() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.getSsl().setEnabled(true);\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry();\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tTlsChannelCredentials credentials = (TlsChannelCredentials) provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials.getTrustManagers()).isNull();\n\t\tassertThat(credentials.getKeyManagers()).isNull();\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenNoSslEnabledSetButHasBundle() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.getSsl().setBundle(\"test\");\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry(\"test\", mockBundle());\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tTlsChannelCredentials credentials = (TlsChannelCredentials) provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials.getTrustManagers()).containsExactly(this.trustManagers);\n\t\tassertThat(credentials.getKeyManagers()).containsExactly(this.keyManagers);\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenNoSslEnabledSetAndNoBundle() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry();\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tChannelCredentials credentials = provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials).isInstanceOf(InsecureChannelCredentials.class);\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenSslEnabledAndHasBundle() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.getSsl().setEnabled(true);\n\t\tchannelProperties.getSsl().setBundle(\"test\");\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry(\"test\", mockBundle());\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tTlsChannelCredentials credentials = (TlsChannelCredentials) provider.getChannelCredentials(\"test\");\n\t\tassertThat(credentials.getTrustManagers()).containsExactly(this.trustManagers);\n\t\tassertThat(credentials.getKeyManagers()).containsExactly(this.keyManagers);\n\t}\n\n\t@Test\n\tvoid getChannelCredentialsWhenBypassCertificateValidation() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tchannelProperties.setBypassCertificateValidation(true);\n\t\tchannelProperties.getSsl().setBundle(\"test\");\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tSslBundles sslBundles = new DefaultSslBundleRegistry(\"test\", mockBundle());\n\t\tChannelCredentialsProvider provider = new PropertiesChannelCredentialsProvider(properties, sslBundles);\n\t\tTlsChannelCredentials credentials = (TlsChannelCredentials) provider.getChannelCredentials(\"test\");\n\t\tTrustManager trustManager = credentials.getTrustManagers().get(0);\n\t\tassertThat(trustManager.getClass().getName()).contains(\"InsecureTrustManager\");\n\t\tassertThat(((X509ExtendedTrustManager) trustManager).getAcceptedIssuers()).isEmpty();\n\t\tassertThat(credentials.getKeyManagers()).containsExactly(this.keyManagers);\n\t}\n\n\tprivate SslBundle mockBundle() {\n\t\tSslBundle bundle = mock();\n\t\tSslManagerBundle managerBundle = mock();\n\t\tTrustManagerFactory trustManagerFactory = mock();\n\t\tKeyManagerFactory keyManagerFactory = mock();\n\t\tgiven(bundle.getManagers()).willReturn(managerBundle);\n\t\tgiven(managerBundle.getTrustManagerFactory()).willReturn(trustManagerFactory);\n\t\tgiven(managerBundle.getKeyManagerFactory()).willReturn(keyManagerFactory);\n\t\tgiven(trustManagerFactory.getTrustManagers()).willReturn(this.trustManagers);\n\t\tgiven(keyManagerFactory.getKeyManagers()).willReturn(this.keyManagers);\n\t\treturn bundle;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesGrpcChannelBuilderCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport io.grpc.ClientInterceptor;\nimport io.grpc.ManagedChannelBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.interceptor.DefaultDeadlineSetupClientInterceptor;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link PropertiesGrpcChannelBuilderCustomizer}.\n *\n * @author Phillip Webb\n */\nclass PropertiesGrpcChannelBuilderCustomizerTests {\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenHasMatchingChannel() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tproperties.getChannel().put(\"test\", createTestChannelProperties());\n\t\tGrpcChannelBuilderCustomizer<T> customizer = new PropertiesGrpcChannelBuilderCustomizer<>(properties);\n\t\tT builder = mock();\n\t\tcustomizer.customize(\"test\", builder);\n\t\tassertMapped(builder);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenHasDefaultChannel() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tproperties.getChannel().put(\"default\", createTestChannelProperties());\n\t\tGrpcChannelBuilderCustomizer<T> customizer = new PropertiesGrpcChannelBuilderCustomizer<>(properties);\n\t\tT builder = mock();\n\t\tcustomizer.customize(\"test\", builder);\n\t\tassertMapped(builder);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenHasNoMatchAndNoDefault() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tproperties.getChannel().put(\"other\", createTestChannelProperties());\n\t\tGrpcChannelBuilderCustomizer<T> customizer = new PropertiesGrpcChannelBuilderCustomizer<>(properties);\n\t\tT builder = mock();\n\t\tcustomizer.customize(\"test\", builder);\n\t\tassertMappedStockDefaults(builder);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenChannelDoesNotSupportLoadBalancingDoesNotMapDefaultLoadBalancer() {\n\t\tassertNoLoadBalancerMappedBasedOnChannel(\"unix:test\");\n\t\tassertNoLoadBalancerMappedBasedOnChannel(\"in-process:test\");\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> void assertNoLoadBalancerMappedBasedOnChannel(String target) {\n\t\tT builder = getBuilder((channelProperties) -> {\n\t\t\tchannelProperties.setTarget(target);\n\t\t\tchannelProperties.getDefault().setLoadBalancingPolicy(\"testlbp\");\n\t\t});\n\t\tthen(builder).should(never()).defaultLoadBalancingPolicy(any());\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenTargetDoesNotSupportLoadBalancingDoesNotMapDefaultLoadBalancer() {\n\t\tGrpcChannelBuilderCustomizer<?> customizer = getCustomizer(\n\t\t\t\t(channelProperties) -> channelProperties.setTarget(\"static://localhost:1234\"));\n\t\tassertNoLoadBalancerMappedBasedOnTarget(customizer, \"unix:test\");\n\t\tassertNoLoadBalancerMappedBasedOnTarget(customizer, \"in-process:test\");\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> void assertNoLoadBalancerMappedBasedOnTarget(\n\t\t\tGrpcChannelBuilderCustomizer<T> customizer, String target) {\n\t\tT builder = mock();\n\t\tcustomizer.customize(target, builder);\n\t\tthen(builder).should(never()).defaultLoadBalancingPolicy(any());\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenMaxMessageSizeIsMinusOneUsesMaxValue() {\n\t\tT builder = getBuilder(\n\t\t\t\t(channelProperties) -> channelProperties.getInbound().getMessage().setMaxSize(DataSize.ofBytes(-1)));\n\t\tthen(builder).should().maxInboundMessageSize(Integer.MAX_VALUE);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenMaxMessageSizeIsTooBigUsesMaxValue() {\n\t\tT builder = getBuilder((channelProperties) -> channelProperties.getInbound()\n\t\t\t.getMessage()\n\t\t\t.setMaxSize(DataSize.ofBytes((long) Integer.MAX_VALUE + 100)));\n\t\tthen(builder).should().maxInboundMessageSize(Integer.MAX_VALUE);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenMaxMessageSizeIsNegativeAndNotMinusOneThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> getBuilder(\n\t\t\t\t(channelProperties) -> channelProperties.getInbound().getMessage().setMaxSize(DataSize.ofBytes(-2))))\n\t\t\t.withMessage(\"Unsupported max size value -2B\");\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenMaxMetadataSizeIsMinusOneUsesMaxValue() {\n\t\tT builder = getBuilder(\n\t\t\t\t(channelProperties) -> channelProperties.getInbound().getMetadata().setMaxSize(DataSize.ofBytes(-1)));\n\t\tthen(builder).should().maxInboundMetadataSize(Integer.MAX_VALUE);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenMaxMetadataSizeIsTooBigUsesMaxValue() {\n\t\tT builder = getBuilder((channelProperties) -> channelProperties.getInbound()\n\t\t\t.getMetadata()\n\t\t\t.setMaxSize(DataSize.ofBytes((long) Integer.MAX_VALUE + 100)));\n\t\tthen(builder).should().maxInboundMetadataSize(Integer.MAX_VALUE);\n\t}\n\n\t@Test\n\t<T extends ManagedChannelBuilder<T>> void customizeWhenMaxMetadataSizeIsNegativeAndNotMinusOneThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> getBuilder(\n\t\t\t\t(channelProperties) -> channelProperties.getInbound().getMetadata().setMaxSize(DataSize.ofBytes(-2))))\n\t\t\t.withMessage(\"Unsupported max size value -2B\");\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> T getBuilder(Consumer<Channel> setup) {\n\t\tGrpcChannelBuilderCustomizer<T> customizer = getCustomizer(setup);\n\t\tT builder = mock();\n\t\tcustomizer.customize(\"test\", builder);\n\t\treturn builder;\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> GrpcChannelBuilderCustomizer<T> getCustomizer(\n\t\t\tConsumer<Channel> setup) {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channelProperties = new Channel();\n\t\tsetup.accept(channelProperties);\n\t\tproperties.getChannel().put(\"test\", channelProperties);\n\t\tGrpcChannelBuilderCustomizer<T> customizer = new PropertiesGrpcChannelBuilderCustomizer<>(properties);\n\t\treturn customizer;\n\t}\n\n\tprivate Channel createTestChannelProperties() {\n\t\tChannel properties = new Channel();\n\t\tproperties.setUserAgent(\"testua\");\n\t\tproperties.getInbound().getMessage().setMaxSize(DataSize.ofBytes(10));\n\t\tproperties.getInbound().getMetadata().setMaxSize(DataSize.ofBytes(20));\n\t\tproperties.getDefault().setDeadline(Duration.ofMinutes(5));\n\t\tproperties.getDefault().setLoadBalancingPolicy(\"testlbp\");\n\t\tproperties.getIdle().setTimeout(Duration.ofMinutes(6));\n\t\tproperties.getKeepalive().setTime(Duration.ofMinutes(7));\n\t\tproperties.getKeepalive().setTimeout(Duration.ofMinutes(8));\n\t\tproperties.getKeepalive().setWithoutCalls(true);\n\t\treturn properties;\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> void assertMapped(T builder) {\n\t\tthen(builder).should().userAgent(\"testua\");\n\t\tthen(builder).should().maxInboundMessageSize(10);\n\t\tthen(builder).should().maxInboundMetadataSize(20);\n\t\tArgumentCaptor<ClientInterceptor[]> interceptors = ArgumentCaptor.captor();\n\t\tthen(builder).should().intercept(interceptors.capture());\n\t\tClientInterceptor interceptor = interceptors.getValue()[0];\n\t\tassertThat(interceptor).isInstanceOf(DefaultDeadlineSetupClientInterceptor.class)\n\t\t\t.extracting(\"defaultDeadline\")\n\t\t\t.isEqualTo(Duration.ofMinutes(5));\n\t\tthen(builder).should().defaultLoadBalancingPolicy(\"testlbp\");\n\t\tthen(builder).should().idleTimeout(360000000000L, TimeUnit.NANOSECONDS);\n\t\tthen(builder).should().keepAliveTime(420000000000L, TimeUnit.NANOSECONDS);\n\t\tthen(builder).should().keepAliveTimeout(480000000000L, TimeUnit.NANOSECONDS);\n\t\tthen(builder).should().keepAliveWithoutCalls(true);\n\t}\n\n\tprivate <T extends ManagedChannelBuilder<T>> void assertMappedStockDefaults(T builder) {\n\t\tthen(builder).should().maxInboundMessageSize(4194304);\n\t\tthen(builder).should().maxInboundMetadataSize(8192);\n\t\tthen(builder).should().defaultLoadBalancingPolicy(\"round_robin\");\n\t\tthen(builder).should().idleTimeout(20000000000L, TimeUnit.NANOSECONDS);\n\t\tthen(builder).should().keepAliveTime(300000000000L, TimeUnit.NANOSECONDS);\n\t\tthen(builder).should().keepAliveTimeout(20000000000L, TimeUnit.NANOSECONDS);\n\t\tthen(builder).should().keepAliveWithoutCalls(false);\n\t\tthen(builder).shouldHaveNoMoreInteractions();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/PropertiesVirtualTargetsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientProperties.Channel;\nimport org.springframework.grpc.client.VirtualTargets;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesVirtualTargets}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass PropertiesVirtualTargetsTests {\n\n\t@Test\n\tvoid getTargetWhenHasMatchingChannel() {\n\t\tGrpcClientProperties properties = createProperties(\"test\", \"my-server:8888\");\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"test\")).isEqualTo(\"my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenDefaultAndDefaultChannelDefined() {\n\t\tGrpcClientProperties properties = createProperties(\"default\", \"my-server:8888\");\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"default\")).isEqualTo(\"my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenDefaultAndNoDefaultChannelDefined() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"default\")).isEqualTo(\"localhost:9090\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenChannelHasStaticTargetReturnsStrippedTarget() {\n\t\tGrpcClientProperties properties = createProperties(\"test\", \"static://my-server:8888\");\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"test\")).isEqualTo(\"my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenChannelHasTcpTargetReturnsStrippedTarget() {\n\t\tGrpcClientProperties properties = createProperties(\"test\", \"tcp://my-server:8888\");\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"test\")).isEqualTo(\"my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenChannelHasOtherUrlTarget() {\n\t\tGrpcClientProperties properties = createProperties(\"test\", \"foo://my-server:8888\");\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"test\")).isEqualTo(\"foo://my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenStaticReturnsStripped() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"static://my-server:8888\")).isEqualTo(\"my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenTcpReturnsStripped() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"tcp://my-server:8888\")).isEqualTo(\"my-server:8888\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenUnixUrlDoesNotPrependStatic() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"foo://bar\")).isEqualTo(\"foo://bar\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenUrlReturnsAsIs() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"unix:foo\")).isEqualTo(\"unix:foo\");\n\t}\n\n\t@Test\n\tvoid getTargetUrlWhenHasColonWithoutSlashReturnsAsIs() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(new MockEnvironment(), properties);\n\t\tassertThat(targets.getTarget(\"localhost:123/bar\")).isEqualTo(\"localhost:123/bar\");\n\t}\n\n\t@Test\n\tvoid getTargetWhenNotChannelNameResolvesPlaceholders() {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"channelName\", \"foo\");\n\t\tVirtualTargets targets = new PropertiesVirtualTargets(environment, properties);\n\t\tassertThat(targets.getTarget(\"my-server-${channelName}:8888\")).isEqualTo(\"my-server-foo:8888\");\n\t}\n\n\tprivate GrpcClientProperties createProperties(String name, String target) {\n\t\tGrpcClientProperties properties = new GrpcClientProperties();\n\t\tChannel channel = new Channel();\n\t\tchannel.setTarget(target);\n\t\tproperties.getChannel().put(name, channel);\n\t\treturn properties;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/ServiceConfigTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.grpc.LoadBalancerRegistry;\nimport io.grpc.NameResolver.ConfigOrError;\nimport io.grpc.Status.Code;\nimport io.grpc.internal.AutoConfiguredLoadBalancerFactory;\nimport io.grpc.internal.ScParser;\nimport io.grpc.internal.ServiceConfigUtil;\nimport io.grpc.internal.ServiceConfigUtil.LbConfig;\nimport io.grpc.internal.ServiceConfigUtil.PolicySelection;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.env.YamlPropertySourceLoader;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link ServiceConfig}.\n *\n * @author Phillip Webb\n */\nclass ServiceConfigTests {\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - pickfirst: {}\n\t\t\t\"\"\")\n\tvoid pickFirstLoadBalancing() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(1);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"pick_first\");\n\t\tPolicySelection loadBalancingPolicySelection = getLoadBalancingPolicySelection(loadBalancingConfigs);\n\t\tassertThat(loadBalancingPolicySelection.toString()).contains(\"PickFirstLoadBalancer\");\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"shuffleAddressList\").isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - pickfirst:\n\t\t\t      shuffle-address-list: true\n\t\t\t\"\"\")\n\tvoid pickFirstLoadBalancingWithProperties() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(1);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"pick_first\");\n\t\tPolicySelection loadBalancingPolicySelection = getLoadBalancingPolicySelection(loadBalancingConfigs);\n\t\tassertThat(loadBalancingPolicySelection.toString()).contains(\"PickFirstLoadBalancer\");\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"shuffleAddressList\").isEqualTo(Boolean.TRUE);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - roundrobin: {}\n\t\t\t\"\"\")\n\tvoid roundRobinLoadBalancing() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(1);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"round_robin\");\n\t\tPolicySelection loadBalancingPolicySelection = getLoadBalancingPolicySelection(loadBalancingConfigs);\n\t\tassertThat(loadBalancingPolicySelection.toString()).contains(\"policy=round_robin\")\n\t\t\t.contains(\"no service config\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - weightedroundrobin: {}\n\t\t\t\"\"\")\n\tvoid weightedRoundRobinLoadBalancing() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(1);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"weighted_round_robin\");\n\t\tPolicySelection loadBalancingPolicySelection = getLoadBalancingPolicySelection(loadBalancingConfigs);\n\t\tassertThat(loadBalancingPolicySelection.toString()).contains(\"WeightedRoundRobinLoadBalancerProvider\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - weightedroundrobin:\n\t\t\t      blackout-period: 1m\n\t\t\t      weight-expiration-period: 500ms\n\t\t\t      out-of-band-reporting-period: 1s\n\t\t\t      enable-out-of-band-load-report: true\n\t\t\t      weight-update-period: 2s\n\t\t\t      error-utilization-penalty: 0.5\n\t\t\t\"\"\")\n\tvoid weightedRoundRobinLoadBalancingWithProperties() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(1);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"weighted_round_robin\");\n\t\tPolicySelection loadBalancingPolicySelection = getLoadBalancingPolicySelection(loadBalancingConfigs);\n\t\tassertThat(loadBalancingPolicySelection.toString()).contains(\"WeightedRoundRobinLoadBalancerProvider\");\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"blackoutPeriodNanos\")\n\t\t\t.isEqualTo(Duration.ofMinutes(1).toNanos());\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"weightExpirationPeriodNanos\")\n\t\t\t.isEqualTo(Duration.ofMillis(500).toNanos());\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"enableOobLoadReport\").isEqualTo(true);\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"oobReportingPeriodNanos\")\n\t\t\t.isEqualTo(Duration.ofSeconds(1).toNanos());\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"weightUpdatePeriodNanos\")\n\t\t\t.isEqualTo(Duration.ofSeconds(2).toNanos());\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"errorUtilizationPenalty\").isEqualTo(0.5f);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - grpc:\n\t\t\t      child:\n\t\t\t      - roundrobin: {}\n\t\t\t      - pickfirst: {}\n\t\t\t      service-name: test\n\t\t\t      initial-fallback-timeout: 10s\n\t\t\t\"\"\")\n\tvoid grpcLoadBalancingWithProperties() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(1);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"grpclb\");\n\t\tPolicySelection loadBalancingPolicySelection = getLoadBalancingPolicySelection(loadBalancingConfigs);\n\t\tassertThat(loadBalancingPolicySelection.toString()).contains(\"GrpclbLoadBalancerProvider\");\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"mode\").hasToString(\"ROUND_ROBIN\");\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"serviceName\").isEqualTo(\"test\");\n\t\tassertThat(loadBalancingPolicySelection.getConfig()).extracting(\"fallbackTimeoutMs\")\n\t\t\t.isEqualTo(Duration.ofSeconds(10).toMillis());\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - pickfirst: {}\n\t\t\t  - weightedroundrobin: {}\n\t\t\t\"\"\")\n\tvoid multipleLoadBalancerPolicies() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"loadBalancingConfig\");\n\t\tList<Map<String, ?>> loadBalancingConfigs = ServiceConfigUtil.getLoadBalancingConfigsFromServiceConfig(map);\n\t\tassertThat(loadBalancingConfigs).hasSize(2);\n\t\tassertThat(loadBalancingConfigs.get(0)).containsKey(\"pick_first\");\n\t\tassertThat(loadBalancingConfigs.get(1)).containsKey(\"weighted_round_robin\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - pickfirst: {}\n\t\t\t    weightedroundrobin: {}\n\t\t\t\"\"\")\n\tvoid whenMultipleLoadBalancingPoliciesInListItemThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bindAndGetAsMap())\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  load-balancing:\n\t\t\t  - {}\n\t\t\t\"\"\")\n\tvoid whenNoLoadBalancingPoliciesInListItemThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bindAndGetAsMap())\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(InvalidConfigurationPropertyValueException.class);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  method:\n\t\t\t  - name:\n\t\t\t    - service: s-one\n\t\t\t      method: m-one\n\t\t\t    - service: s-two\n\t\t\t      method: m-two\n\t\t\t    wait-for-ready: true\n\t\t\t    max-request-message: 10KB\n\t\t\t    max-response-message: 20KB\n\t\t\t    timeout: 30s\n\t\t\t\"\"\")\n\t@SuppressWarnings(\"unchecked\")\n\tvoid methodConfig() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"methodConfig\");\n\t\tMap<String, ?> serviceMethodMap = getServiceMethodMap(map, false);\n\t\tassertThat(serviceMethodMap).containsOnlyKeys(\"s-one/m-one\", \"s-two/m-two\");\n\t\tObject methodInfo = serviceMethodMap.get(\"s-one/m-one\");\n\t\tassertThat(methodInfo).extracting(\"timeoutNanos\").isEqualTo(Duration.ofSeconds(30).toNanos());\n\t\tassertThat(methodInfo).extracting(\"waitForReady\").isEqualTo(Boolean.TRUE);\n\t\tassertThat(methodInfo).extracting(\"maxOutboundMessageSize\").isEqualTo(10240);\n\t\tassertThat(methodInfo).extracting(\"maxInboundMessageSize\").isEqualTo(20480);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  method:\n\t\t\t  - name:\n\t\t\t    - service: s-one\n\t\t\t      method: m-one\n\t\t\t    retry:\n\t\t\t      max-attempts: 2\n\t\t\t      initial-backoff: 1m\n\t\t\t      max-backoff: 1h\n\t\t\t      backoff-multiplier: 2.5\n\t\t\t      per-attempt-receive-timeout: 2s\n\t\t\t      retryable-status-codes:\n\t\t\t      - cancelled\n\t\t\t      - already-exists\n\t\t\t\"\"\")\n\tvoid methodConfigRetryPolicy() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tMap<String, ?> serviceMethodMap = getServiceMethodMap(map, true);\n\t\tObject methodInfo = serviceMethodMap.get(\"s-one/m-one\");\n\t\tassertThat(methodInfo).extracting(\"retryPolicy.maxAttempts\").isEqualTo(2);\n\t\tassertThat(methodInfo).extracting(\"retryPolicy.initialBackoffNanos\").isEqualTo(Duration.ofMinutes(1).toNanos());\n\t\tassertThat(methodInfo).extracting(\"retryPolicy.maxBackoffNanos\").isEqualTo(Duration.ofHours(1).toNanos());\n\t\tassertThat(methodInfo).extracting(\"retryPolicy.backoffMultiplier\").isEqualTo(2.5);\n\t\tassertThat(methodInfo).extracting(\"retryPolicy.perAttemptRecvTimeoutNanos\")\n\t\t\t.isEqualTo(Duration.ofSeconds(2).toNanos());\n\t\tassertThat(methodInfo).extracting(\"retryPolicy.retryableStatusCodes\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.SET)\n\t\t\t.containsExactlyInAnyOrder(Code.CANCELLED, Code.ALREADY_EXISTS);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  method:\n\t\t\t  - name:\n\t\t\t    - service: s-one\n\t\t\t      method: m-one\n\t\t\t    hedging:\n\t\t\t      max-attempts: 4\n\t\t\t      delay: 6s\n\t\t\t      non-fatal-status-codes:\n\t\t\t      - invalid-argument\n\t\t\t      - deadline-exceeded\n\t\t\t\"\"\")\n\tvoid methodConfigHedgingPolicy() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tMap<String, ?> serviceMethodMap = getServiceMethodMap(map, true);\n\t\tObject methodInfo = serviceMethodMap.get(\"s-one/m-one\");\n\t\tassertThat(methodInfo).extracting(\"hedgingPolicy.maxAttempts\").isEqualTo(4);\n\t\tassertThat(methodInfo).extracting(\"hedgingPolicy.hedgingDelayNanos\").isEqualTo(Duration.ofSeconds(6).toNanos());\n\t\tassertThat(methodInfo).extracting(\"hedgingPolicy.nonFatalStatusCodes\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.SET)\n\t\t\t.containsExactlyInAnyOrder(Code.INVALID_ARGUMENT, Code.DEADLINE_EXCEEDED);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  method:\n\t\t\t  - name:\n\t\t\t    - service: s-one\n\t\t\t      method: m-one\n\t\t\t    retry: {}\n\t\t\t    hedging: {}\n\t\t\t\"\"\")\n\tvoid whenMultiplePoliciesInMethodConfigThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bindAndGetAsMap())\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  retrythrottling:\n\t\t\t    max-tokens: 2.5\n\t\t\t    token-ratio: 1.5\n\t\t\t\"\"\")\n\tvoid retryThrottling() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"retryThrottling\");\n\t\tObject throttle = ReflectionTestUtils.invokeMethod(ServiceConfigUtil.class, \"getThrottlePolicy\", map);\n\t\tassertThat(throttle).extracting(\"maxTokens\").isEqualTo(2500);\n\t\tassertThat(throttle).extracting(\"tokenRatio\").isEqualTo(1500);\n\t}\n\n\t@Test\n\t@WithResource(name = \"config.yaml\", content = \"\"\"\n\t\t\tconfig:\n\t\t\t  healthcheck:\n\t\t\t    service-name: test\n\t\t\t\"\"\")\n\t@SuppressWarnings(\"unchecked\")\n\tvoid healthCheck() throws Exception {\n\t\tMap<String, Object> map = bindAndGetAsMap();\n\t\tassertThat(map).containsKey(\"healthCheckConfig\");\n\t\tMap<String, Object> healthCheckedService = (Map<String, Object>) ServiceConfigUtil.getHealthCheckedService(map);\n\t\tassertThat(healthCheckedService).hasSize(1).containsEntry(\"serviceName\", \"test\");\n\t}\n\n\tprivate PolicySelection getLoadBalancingPolicySelection(List<Map<String, ?>> rawConfigs) {\n\t\tList<LbConfig> unwrappedConfigs = ServiceConfigUtil.unwrapLoadBalancingConfigList(rawConfigs);\n\t\tLoadBalancerRegistry registry = LoadBalancerRegistry.getDefaultRegistry();\n\t\tConfigOrError selected = ServiceConfigUtil.selectLbPolicyFromList(unwrappedConfigs, registry);\n\t\tassertThat(selected).isNotNull();\n\t\tPolicySelection policySelection = (PolicySelection) selected.getConfig();\n\t\tif (policySelection == null) {\n\t\t\tSystem.err.println(selected);\n\t\t\tSystem.err.println(selected.getError());\n\t\t\tif (selected.getError() != null && selected.getError().asException() != null) {\n\t\t\t\tselected.getError().asException().printStackTrace();\n\t\t\t}\n\t\t}\n\t\tassertThat(policySelection).isNotNull();\n\t\treturn policySelection;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, ?> getServiceMethodMap(Map<String, Object> map, boolean retryEnabled) {\n\t\tScParser scParser = new ScParser(retryEnabled, 100, 100, new AutoConfiguredLoadBalancerFactory(\"pick_first\"));\n\t\tObject config = scParser.parseServiceConfig(map).getConfig();\n\t\tassertThat(config).isNotNull();\n\t\tObject serviceMethodMap = ReflectionTestUtils.getField(config, \"serviceMethodMap\");\n\t\tassertThat(serviceMethodMap).isNotNull();\n\t\treturn (Map<String, ?>) serviceMethodMap;\n\t}\n\n\tprivate Map<String, Object> bindAndGetAsMap() throws Exception {\n\t\tMap<String, Object> map = new LinkedHashMap<>();\n\t\tbind().applyTo(map);\n\t\treturn map;\n\t}\n\n\tprivate ServiceConfig bind() throws Exception {\n\t\tYamlPropertySourceLoader loader = new YamlPropertySourceLoader();\n\t\tPropertySource<?> propertySource = loader.load(\"config.yaml\", new ClassPathResource(\"config.yaml\")).get(0);\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.getPropertySources().addLast(propertySource);\n\t\tBinder binder = Binder.get(environment);\n\t\treturn binder.bind(\"config\", ServiceConfig.class).get();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/test/scan/DummyBlockingGrpc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure.test.scan;\n\nimport io.grpc.CallOptions;\nimport io.grpc.Channel;\nimport io.grpc.stub.AbstractBlockingStub;\nimport io.grpc.stub.AbstractStub.StubFactory;\n\npublic final class DummyBlockingGrpc {\n\n\tprivate DummyBlockingGrpc() {\n\t}\n\n\tpublic static DummyBlockingStub newBlockingStub(io.grpc.Channel channel) {\n\t\treturn AbstractBlockingStub.newStub((StubFactory<DummyBlockingStub>) DummyBlockingStub::new, channel);\n\t}\n\n\tpublic static class DummyBlockingStub extends AbstractBlockingStub<DummyBlockingStub> {\n\n\t\tprotected DummyBlockingStub(Channel channel, CallOptions callOptions) {\n\t\t\tsuper(channel, callOptions);\n\t\t}\n\n\t\t@Override\n\t\tprotected DummyBlockingStub build(Channel channel, CallOptions callOptions) {\n\t\t\treturn new DummyBlockingStub(channel, callOptions);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/test/scan/DummyBlockingV2Grpc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.client.autoconfigure.test.scan;\n\nimport io.grpc.CallOptions;\nimport io.grpc.Channel;\nimport io.grpc.stub.AbstractBlockingStub;\nimport io.grpc.stub.AbstractStub.StubFactory;\n\npublic final class DummyBlockingV2Grpc {\n\n\tprivate DummyBlockingV2Grpc() {\n\t}\n\n\tpublic static DummyBlockingV2Stub newBlockingV2Stub(io.grpc.Channel channel) {\n\t\treturn AbstractBlockingStub.newStub((StubFactory<DummyBlockingV2Stub>) DummyBlockingV2Stub::new, channel);\n\t}\n\n\tpublic static class DummyBlockingV2Stub extends AbstractBlockingStub<DummyBlockingV2Stub> {\n\n\t\tprotected DummyBlockingV2Stub(Channel channel, CallOptions callOptions) {\n\t\t\tsuper(channel, callOptions);\n\t\t}\n\n\t\t@Override\n\t\tprotected DummyBlockingV2Stub build(Channel channel, CallOptions callOptions) {\n\t\t\treturn new DummyBlockingV2Stub(channel, callOptions);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/test/scan/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.grpc.client.autoconfigure.test.scan;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot gRPC Server\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.grpc:spring-grpc-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(project(\":module:spring-boot-security\"))\n\toptional(project(\":module:spring-boot-security-oauth2-resource-server\"))\n\toptional(\"com.fasterxml.jackson.core:jackson-annotations\")\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"io.grpc:grpc-servlet-jakarta\")\n\toptional(\"io.grpc:grpc-services\")\n\toptional(\"io.grpc:grpc-netty\")\n\toptional(\"io.grpc:grpc-netty-shaded\")\n\toptional(\"io.grpc:grpc-inprocess\")\n\toptional(\"io.grpc:grpc-kotlin-stub\") {\n\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t}\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"io.micrometer:context-propagation\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/GrpcServletRegistration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport io.grpc.ServerServiceDefinition;\nimport io.grpc.ServiceDescriptor;\nimport io.grpc.servlet.jakarta.GrpcServlet;\nimport io.grpc.servlet.jakarta.ServletServerBuilder;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletRegistration.Dynamic;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.servlet.DynamicRegistrationBean;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.grpc.server.service.GrpcServiceSpec;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link DynamicRegistrationBean} that can be used to register a {@link GrpcServlet}.\n *\n * @author David Syer\n * @author Chris Bono\n * @author Toshiaki Maki\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class GrpcServletRegistration extends DynamicRegistrationBean<Dynamic> {\n\n\tprivate static final Log logger = LogFactory.getLog(GrpcServletRegistration.class);\n\n\tprivate final GrpcServlet servlet;\n\n\tprivate final String[] urlMappings;\n\n\t/**\n\t * Create a new {@link GrpcServletRegistration} instance.\n\t * @param serviceDiscoverer the gRPC service discoverer\n\t * @param serviceConfigurer the gRPC service configurer\n\t */\n\tpublic GrpcServletRegistration(GrpcServiceDiscoverer serviceDiscoverer, GrpcServiceConfigurer serviceConfigurer) {\n\t\tthis(serviceDiscoverer, serviceConfigurer, null);\n\t}\n\n\t/**\n\t * Create a new {@link GrpcServletRegistration} instance.\n\t * @param serviceDiscoverer the gRPC service discoverer\n\t * @param serviceConfigurer the gRPC service configurer\n\t * @param serverBuilderCustomizer an optional customizer to configure the\n\t * {@link ServletServerBuilder}\n\t */\n\tpublic GrpcServletRegistration(GrpcServiceDiscoverer serviceDiscoverer, GrpcServiceConfigurer serviceConfigurer,\n\t\t\t@Nullable Consumer<ServletServerBuilder> serverBuilderCustomizer) {\n\t\tAssert.notNull(serviceDiscoverer, \"'serviceDiscoverer' must not be null\");\n\t\tAssert.notNull(serviceConfigurer, \"'serviceConfigurer' must not be null\");\n\t\tServletServerBuilder builder = new ServletServerBuilder();\n\t\tList<String> urlMappings = new ArrayList<>();\n\t\tfor (GrpcServiceSpec spec : serviceDiscoverer.findServices()) {\n\t\t\tServiceDescriptor descriptor = spec.service().bindService().getServiceDescriptor();\n\t\t\tlogger.info(LogMessage.format(\"Registering servlet gRPC service: %s\", descriptor.getName()));\n\t\t\turlMappings.add(\"/\" + descriptor.getName() + \"/*\");\n\t\t\tServerServiceDefinition definition = serviceConfigurer.configure(spec, null);\n\t\t\tbuilder.addService(definition);\n\t\t}\n\t\tif (serverBuilderCustomizer != null) {\n\t\t\tserverBuilderCustomizer.accept(builder);\n\t\t}\n\t\tthis.servlet = builder.buildServlet();\n\t\tthis.urlMappings = urlMappings.toArray(String[]::new);\n\t}\n\n\t@Override\n\tprotected Dynamic addRegistration(String description, ServletContext servletContext) {\n\t\treturn servletContext.addServlet(getName(), this.servlet);\n\t}\n\n\t@Override\n\tprotected void configure(Dynamic registration) {\n\t\tsuper.configure(registration);\n\t\tif (!ObjectUtils.isEmpty(this.urlMappings)) {\n\t\t\tregistration.addMapping(this.urlMappings);\n\t\t}\n\t}\n\n\t@Override\n\tprotected String getDescription() {\n\t\treturn getName();\n\t}\n\n\tprivate String getName() {\n\t\treturn getOrDeduceName(this.servlet);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/ConditionalOnGrpcServerFactoryEnabled.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that matches when\n * {@code spring.grpc.server.factory.enabled} is {@code true} or missing.\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.factory.enabled\", matchIfMissing = true)\n@interface ConditionalOnGrpcServerFactoryEnabled {\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/ConditionalOnMissingNetworkGrpcServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\n\n/**\n * {@link Conditional @Conditional} that matches when no network gRPC server is found.\n * Concretely:\n * <ul>\n * <li>There are no {@link GrpcServletRegistration} beans.</li>\n * <li>There are no {@link GrpcServerFactory} beans (ignoring\n * {@link InProcessGrpcServerFactory} beans)</li>\n * </ul>\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(MissingNetworkGrpcServerCondition.class)\n@interface ConditionalOnMissingNetworkGrpcServer {\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.List;\n\nimport io.grpc.BindableService;\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.Grpc;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.ServerBuilderCustomizer;\nimport org.springframework.grpc.server.exception.CompositeGrpcExceptionHandler;\nimport org.springframework.grpc.server.exception.GrpcExceptionHandler;\nimport org.springframework.grpc.server.exception.GrpcExceptionHandlerInterceptor;\nimport org.springframework.grpc.server.exception.ReactiveStubBeanDefinitionRegistrar;\nimport org.springframework.grpc.server.service.DefaultGrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.DefaultGrpcServiceDiscoverer;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring gRPC server-side\n * components.\n *\n * @author David Syer\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ GrpcServerFactory.class, Grpc.class })\n@ConditionalOnBean(BindableService.class)\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.enabled\", matchIfMissing = true)\n@EnableConfigurationProperties(GrpcServerProperties.class)\n@Import({ GrpcServerCodecConfiguration.class, ServletGrpcServerConfiguration.class,\n\t\tShadedNettyGrpcServerConfiguration.class, NettyGrpcServerConfiguration.class,\n\t\tInProcessGrpcServerConfiguration.class })\npublic final class GrpcServerAutoConfiguration {\n\n\t@Bean\n\tGrpcServerBuilderCustomizers grpcServerBuilderCustomizers(GrpcServerProperties grpcServerProperties,\n\t\t\tObjectProvider<CompressorRegistry> compressorRegistry,\n\t\t\tObjectProvider<DecompressorRegistry> decompressorRegistry,\n\t\t\tObjectProvider<GrpcServerExecutorProvider> executorProvider,\n\t\t\tObjectProvider<ServerBuilderCustomizer<?>> customizers) {\n\t\treturn new GrpcServerBuilderCustomizers(grpcServerProperties, compressorRegistry, decompressorRegistry,\n\t\t\t\texecutorProvider, customizers);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(GrpcServiceConfigurer.class)\n\tDefaultGrpcServiceConfigurer grpcServiceConfigurer(ApplicationContext applicationContext) {\n\t\treturn new DefaultGrpcServiceConfigurer(applicationContext);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(GrpcServiceDiscoverer.class)\n\tDefaultGrpcServiceDiscoverer grpcServiceDiscoverer(ApplicationContext applicationContext) {\n\t\treturn new DefaultGrpcServiceDiscoverer(applicationContext);\n\t}\n\n\t@Bean\n\t@GlobalServerInterceptor\n\t@ConditionalOnMissingBean\n\tGrpcExceptionHandlerInterceptor globalExceptionHandlerInterceptor(List<GrpcExceptionHandler> exceptionHandlers) {\n\t\tCompositeGrpcExceptionHandler compositeHandler = new CompositeGrpcExceptionHandler(\n\t\t\t\texceptionHandlers.toArray(GrpcExceptionHandler[]::new));\n\t\treturn new GrpcExceptionHandlerInterceptor(compositeHandler);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = \"com.salesforce.reactivegrpc.common.Function\")\n\t@Import(ReactiveStubBeanDefinitionRegistrar.class)\n\tstatic class ReactiveStubConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerBuilderCustomizers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ServerBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.grpc.server.ServerBuilderCustomizer;\n\n/**\n * Invokes the customizations to a {@link ServerBuilder} based on the provided beans.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass GrpcServerBuilderCustomizers {\n\n\tprivate final List<ServerBuilderCustomizer<?>> customizers;\n\n\tGrpcServerBuilderCustomizers(GrpcServerProperties grpcServerProperties,\n\t\t\tObjectProvider<CompressorRegistry> compressorRegistry,\n\t\t\tObjectProvider<DecompressorRegistry> decompressorRegistry,\n\t\t\tObjectProvider<GrpcServerExecutorProvider> executorProvider,\n\t\t\tObjectProvider<ServerBuilderCustomizer<?>> customizers) {\n\t\tthis(grpcServerProperties, compressorRegistry.getIfAvailable(), decompressorRegistry.getIfAvailable(),\n\t\t\t\texecutorProvider.getIfAvailable(), customizers.orderedStream().toList());\n\t}\n\n\tGrpcServerBuilderCustomizers(List<? extends ServerBuilderCustomizer<?>> customizers) {\n\t\tthis(null, null, null, null, customizers);\n\t}\n\n\tGrpcServerBuilderCustomizers(@Nullable GrpcServerProperties grpcServerProperties,\n\t\t\t@Nullable CompressorRegistry compressorRegistry, @Nullable DecompressorRegistry decompressorRegistry,\n\t\t\t@Nullable GrpcServerExecutorProvider executorProvider,\n\t\t\tList<? extends ServerBuilderCustomizer<?>> customizers) {\n\t\tList<ServerBuilderCustomizer<?>> all = new ArrayList<>();\n\t\taddCustomizer(all, compressorRegistry, ServerBuilder::compressorRegistry);\n\t\taddCustomizer(all, decompressorRegistry, ServerBuilder::decompressorRegistry);\n\t\taddCustomizer(all, executorProvider, (builder, bean) -> builder.executor(bean.getExecutor()));\n\t\tif (grpcServerProperties != null) {\n\t\t\tall.add(new PropertiesServerBuilderCustomizer<>(grpcServerProperties));\n\t\t}\n\t\tall.addAll(customizers);\n\t\tthis.customizers = List.copyOf(all);\n\t}\n\n\tprivate static <B extends ServerBuilder<B>, T> void addCustomizer(List<ServerBuilderCustomizer<?>> customizers,\n\t\t\t@Nullable T bean, BiConsumer<B, T> action) {\n\t\tif (bean != null) {\n\t\t\tServerBuilderCustomizer<B> customizer = (builder) -> action.accept(builder, bean);\n\t\t\tcustomizers.add(customizer);\n\t\t}\n\t}\n\n\t<T extends ServerBuilder<T>> List<ServerBuilderCustomizer<T>> forFactory() {\n\t\treturn List.of(this::apply);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t<T extends ServerBuilder<?>> void apply(T builder) {\n\t\tLambdaSafe.callbacks(ServerBuilderCustomizer.class, this.customizers, builder)\n\t\t\t.withLogger(GrpcServerBuilderCustomizers.class)\n\t\t\t.invoke((customizer) -> customizer.customize(builder));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerCodecConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.List;\n\nimport io.grpc.Compressor;\nimport io.grpc.CompressorRegistry;\nimport io.grpc.Decompressor;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ServerBuilder;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link Configuration @Configuration} for gRPC codecs.\n *\n * @author Andrei Lisa\n */\n@Configuration(proxyBeanMethods = false)\nclass GrpcServerCodecConfiguration {\n\n\t/**\n\t * The compressor registry that is set on the\n\t * {@link ServerBuilder#compressorRegistry(CompressorRegistry) server builder} .\n\t * @param compressors the compressors to use on the registry\n\t * @return a new {@link CompressorRegistry#newEmptyInstance() registry} with the\n\t * specified compressors or the {@link CompressorRegistry#getDefaultInstance() default\n\t * registry} if no custom compressors are available in the application context.\n\t */\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCompressorRegistry grpcCompressorRegistry(List<Compressor> compressors) {\n\t\tif (compressors.isEmpty()) {\n\t\t\treturn CompressorRegistry.getDefaultInstance();\n\t\t}\n\t\tCompressorRegistry registry = CompressorRegistry.newEmptyInstance();\n\t\tcompressors.forEach(registry::register);\n\t\treturn registry;\n\t}\n\n\t/**\n\t * The decompressor registry that is set on the\n\t * {@link ServerBuilder#decompressorRegistry(DecompressorRegistry) server builder}.\n\t * @param decompressors the decompressors to use on the registry\n\t * @return a new {@link DecompressorRegistry#emptyInstance() registry} with the\n\t * specified decompressors or the {@link DecompressorRegistry#getDefaultInstance()\n\t * default registry} if no custom decompressors are available in the application\n\t * context.\n\t */\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDecompressorRegistry grpcDecompressorRegistry(List<Decompressor> decompressors) {\n\t\tif (decompressors.isEmpty()) {\n\t\t\treturn DecompressorRegistry.getDefaultInstance();\n\t\t}\n\t\tDecompressorRegistry registry = DecompressorRegistry.emptyInstance();\n\t\tfor (Decompressor decompressor : decompressors) {\n\t\t\tregistry = registry.with(decompressor, false);\n\t\t}\n\t\treturn registry;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerExecutorProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.concurrent.Executor;\n\n/**\n * Strategy interface to determine the {@link Executor} to use for the gRPC server.\n *\n * @author Chris Bono\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface GrpcServerExecutorProvider {\n\n\t/**\n\t * Returns a {@link Executor} for the gRPC server, if it needs to be customized.\n\t * @return the executor to use for the gRPC server\n\t */\n\tExecutor getExecutor();\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport org.springframework.grpc.server.GrpcServerFactory;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link GrpcServerFactory server factory} before it is fully initialized.\n *\n * @author Chris Bono\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface GrpcServerFactoryCustomizer {\n\n\t/**\n\t * Customize the given {@link GrpcServerFactory}.\n\t * @param serverFactory the server factory to customize\n\t */\n\tvoid customize(GrpcServerFactory serverFactory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.BindableService;\nimport io.micrometer.core.instrument.binder.grpc.GrpcServerObservationConvention;\nimport io.micrometer.core.instrument.binder.grpc.ObservationGrpcServerInterceptor;\nimport io.micrometer.core.instrument.kotlin.ObservationCoroutineContextServerInterceptor;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC server-side observations.\n *\n * @author Sunny Tang\n * @author Chris Bono\n * @author Dave Syer\n * @author Andrey Litvitski\n * @since 4.1.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnClass({ BindableService.class, GrpcServerFactory.class, ObservationRegistry.class,\n\t\tObservationGrpcServerInterceptor.class })\n@ConditionalOnBean(ObservationRegistry.class)\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.enabled\", matchIfMissing = true)\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.observation.enabled\", matchIfMissing = true)\npublic final class GrpcServerObservationAutoConfiguration {\n\n\t@Bean\n\t@Order(0)\n\t@GlobalServerInterceptor\n\t@ConditionalOnMissingBean\n\tObservationGrpcServerInterceptor grpcServerObservationInterceptor(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<GrpcServerObservationConvention> customConvention) {\n\t\tObservationGrpcServerInterceptor interceptor = new ObservationGrpcServerInterceptor(observationRegistry);\n\t\tcustomConvention.ifAvailable(interceptor::setCustomConvention);\n\t\treturn interceptor;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = { \"io.grpc.kotlin.AbstractCoroutineStub\", \"io.micrometer.context.ContextRegistry\" })\n\tstatic class GrpcServerCoroutineStubConfiguration {\n\n\t\t@Bean\n\t\t@Order(10)\n\t\t@GlobalServerInterceptor\n\t\tObservationCoroutineContextServerInterceptor grpcServerObservationCoroutineContextServerInterceptor(\n\t\t\t\tObservationRegistry observationRegistry) {\n\t\t\treturn new ObservationCoroutineContextServerInterceptor(observationRegistry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.net.InetAddress;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport io.grpc.TlsServerCredentials.ClientAuth;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DataSizeUnit;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.util.unit.DataUnit;\n\n/**\n * {@link ConfigurationProperties Properties} for Spring gRPC servers.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@ConfigurationProperties(\"spring.grpc.server\")\npublic class GrpcServerProperties {\n\n\t/**\n\t * Port on which the gRPC server should listen. Use '0' to bind to a dynamic port.\n\t */\n\tprivate @Nullable Integer port;\n\n\t/**\n\t * Network address to which the gRPC server should bind.\n\t */\n\tprivate @Nullable InetAddress address;\n\n\tprivate final Shutdown shutdown = new Shutdown();\n\n\tprivate final Inbound inbound = new Inbound();\n\n\tprivate final Inprocess inprocess = new Inprocess();\n\n\tprivate final Keepalive keepalive = new Keepalive();\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tprivate final Netty netty = new Netty();\n\n\tprivate final Servlet servlet = new Servlet();\n\n\tpublic @Nullable Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(@Nullable Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable InetAddress getAddress() {\n\t\treturn this.address;\n\t}\n\n\tpublic void setAddress(@Nullable InetAddress address) {\n\t\tthis.address = address;\n\t}\n\n\tpublic Shutdown getShutdown() {\n\t\treturn this.shutdown;\n\t}\n\n\tpublic Inbound getInbound() {\n\t\treturn this.inbound;\n\t}\n\n\tpublic Inprocess getInprocess() {\n\t\treturn this.inprocess;\n\t}\n\n\tpublic Keepalive getKeepalive() {\n\t\treturn this.keepalive;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic Netty getNetty() {\n\t\treturn this.netty;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\t/**\n\t * Server shutdown properties.\n\t */\n\tpublic static class Shutdown {\n\n\t\t/**\n\t\t * Maximum time to wait for the server to gracefully shutdown. When the value is\n\t\t * negative, the server waits forever. When the value is 0, the server will force\n\t\t * shutdown immediately. If a duration suffix is not specified, seconds will be\n\t\t * used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate Duration gracePeriod = Duration.ofSeconds(30);\n\n\t\tpublic Duration getGracePeriod() {\n\t\t\treturn this.gracePeriod;\n\t\t}\n\n\t\tpublic void setGracePeriod(Duration gracePeriod) {\n\t\t\tthis.gracePeriod = gracePeriod;\n\t\t}\n\n\t}\n\n\t/**\n\t * In-bound properties.\n\t */\n\tpublic static class Inbound {\n\n\t\tprivate final Message message = new Message();\n\n\t\tprivate final Metadata metadata = new Metadata();\n\n\t\tpublic Message getMessage() {\n\t\t\treturn this.message;\n\t\t}\n\n\t\tpublic Metadata getMetadata() {\n\t\t\treturn this.metadata;\n\t\t}\n\n\t\t/**\n\t\t * In-bound message properties.\n\t\t */\n\t\tpublic static class Message {\n\n\t\t\t/**\n\t\t\t * Maximum message size allowed to be received by the server. If a data size\n\t\t\t * suffix is not specified, bytes will be used.\n\t\t\t */\n\t\t\t@DataSizeUnit(DataUnit.BYTES)\n\t\t\tprivate DataSize maxSize = DataSize.ofBytes(4194304);\n\n\t\t\tpublic DataSize getMaxSize() {\n\t\t\t\treturn this.maxSize;\n\t\t\t}\n\n\t\t\tpublic void setMaxSize(DataSize maxSize) {\n\t\t\t\tthis.maxSize = maxSize;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * In-bound metadata properties.\n\t\t */\n\t\tpublic static class Metadata {\n\n\t\t\t/**\n\t\t\t * Maximum metadata size allowed to be received by the server. If a data size\n\t\t\t * suffix is not specified, bytes will be used.\n\t\t\t */\n\t\t\t@DataSizeUnit(DataUnit.BYTES)\n\t\t\tprivate DataSize maxSize = DataSize.ofBytes(8192);\n\n\t\t\tpublic DataSize getMaxSize() {\n\t\t\t\treturn this.maxSize;\n\t\t\t}\n\n\t\t\tpublic void setMaxSize(DataSize maxSize) {\n\t\t\t\tthis.maxSize = maxSize;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * In-process gRPC properties.\n\t */\n\tpublic static class Inprocess {\n\n\t\t/**\n\t\t * Name of the in-process server or null to not start the in-process server.\n\t\t */\n\t\tprivate @Nullable String name;\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\t/**\n\t * Keep-alive properties.\n\t */\n\tpublic static class Keepalive {\n\n\t\t/**\n\t\t * Duration without read activity before sending a keep alive ping. If a duration\n\t\t * suffix is not specified, seconds will be used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate @Nullable Duration time = Duration.ofHours(2);\n\n\t\t/**\n\t\t * Maximum time to wait for read activity after sending a keep alive ping. If the\n\t\t * sender does not receive an acknowledgment within this time, it will close the\n\t\t * connection. If a duration suffix is not specified, seconds will be used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate @Nullable Duration timeout = Duration.ofSeconds(20);\n\n\t\tprivate final Permit permit = new Permit();\n\n\t\tprivate final Connection connection = new Connection();\n\n\t\tpublic @Nullable Duration getTime() {\n\t\t\treturn this.time;\n\t\t}\n\n\t\tpublic void setTime(@Nullable Duration time) {\n\t\t\tthis.time = time;\n\t\t}\n\n\t\tpublic @Nullable Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\tpublic Permit getPermit() {\n\t\t\treturn this.permit;\n\t\t}\n\n\t\tpublic Connection getConnection() {\n\t\t\treturn this.connection;\n\t\t}\n\n\t\t/**\n\t\t * Keep-alive permit properties.\n\t\t */\n\t\tpublic static class Permit {\n\n\t\t\t/**\n\t\t\t * Maximum keep-alive time clients are permitted to configure. If a duration\n\t\t\t * suffix is not specified, seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate @Nullable Duration time = Duration.ofMinutes(5);\n\n\t\t\t/**\n\t\t\t * Whether clients are permitted to send keep alive pings when there are no\n\t\t\t * outstanding RPCs on the connection.\n\t\t\t */\n\t\t\tprivate boolean withoutCalls;\n\n\t\t\tpublic @Nullable Duration getTime() {\n\t\t\t\treturn this.time;\n\t\t\t}\n\n\t\t\tpublic void setTime(@Nullable Duration time) {\n\t\t\t\tthis.time = time;\n\t\t\t}\n\n\t\t\tpublic boolean isWithoutCalls() {\n\t\t\t\treturn this.withoutCalls;\n\t\t\t}\n\n\t\t\tpublic void setWithoutCalls(boolean withoutCalls) {\n\t\t\t\tthis.withoutCalls = withoutCalls;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Keep-alive connection properties.\n\t\t */\n\t\tpublic static class Connection {\n\n\t\t\t/**\n\t\t\t * Maximum time a connection can remain idle before being gracefully\n\t\t\t * terminated (infinite if not specified). If a duration suffix is not\n\t\t\t * specified, seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate @Nullable Duration maxIdleTime;\n\n\t\t\t/**\n\t\t\t * Maximum time a connection may exist before being gracefully terminated\n\t\t\t * (infinite if not specified). If a duration suffix is not specified, seconds\n\t\t\t * will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate @Nullable Duration maxAge;\n\n\t\t\t/**\n\t\t\t * Maximum time for graceful connection termination. If a duration suffix is\n\t\t\t * not specified, seconds will be used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate @Nullable Duration gracePeriod = Duration.ofSeconds(30);\n\n\t\t\tpublic @Nullable Duration getMaxIdleTime() {\n\t\t\t\treturn this.maxIdleTime;\n\t\t\t}\n\n\t\t\tpublic void setMaxIdleTime(@Nullable Duration maxIdleTime) {\n\t\t\t\tthis.maxIdleTime = maxIdleTime;\n\t\t\t}\n\n\t\t\tpublic @Nullable Duration getMaxAge() {\n\t\t\t\treturn this.maxAge;\n\t\t\t}\n\n\t\t\tpublic void setMaxAge(@Nullable Duration maxAge) {\n\t\t\t\tthis.maxAge = maxAge;\n\t\t\t}\n\n\t\t\tpublic @Nullable Duration getGracePeriod() {\n\t\t\t\treturn this.gracePeriod;\n\t\t\t}\n\n\t\t\tpublic void setGracePeriod(@Nullable Duration gracePeriod) {\n\t\t\t\tthis.gracePeriod = gracePeriod;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * SSL properties.\n\t */\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * Client authentication mode.\n\t\t */\n\t\tprivate ClientAuth clientAuth = ClientAuth.NONE;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\t/**\n\t\t * Whether client authentication is secure (that is certificates are checked). Do\n\t\t * not set this to false in production.\n\t\t */\n\t\tprivate boolean secure = true;\n\n\t\tpublic @Nullable Boolean getEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(@Nullable Boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t\tpublic void setClientAuth(ClientAuth clientAuth) {\n\t\t\tthis.clientAuth = clientAuth;\n\t\t}\n\n\t\tpublic ClientAuth getClientAuth() {\n\t\t\treturn this.clientAuth;\n\t\t}\n\n\t\tpublic void setSecure(boolean secure) {\n\t\t\tthis.secure = secure;\n\t\t}\n\n\t\tpublic boolean isSecure() {\n\t\t\treturn this.secure;\n\t\t}\n\n\t}\n\n\t/**\n\t * Netty server properties.\n\t */\n\tpublic static class Netty {\n\n\t\t/**\n\t\t * Transport mechanism used for Netty and Netty Shaded servers. If not specified,\n\t\t * the appropriate transport will be picked based on the 'domain-socket-path' or\n\t\t * 'address/port'.\n\t\t */\n\t\tprivate @Nullable Transport transport;\n\n\t\t/**\n\t\t * Path of the domain socket that should be used.\n\t\t */\n\t\tprivate @Nullable String domainSocketPath;\n\n\t\tpublic @Nullable Transport getTransport() {\n\t\t\treturn this.transport;\n\t\t}\n\n\t\tpublic void setTransport(@Nullable Transport transport) {\n\t\t\tthis.transport = transport;\n\t\t}\n\n\t\tpublic @Nullable String getDomainSocketPath() {\n\t\t\treturn this.domainSocketPath;\n\t\t}\n\n\t\tpublic void setDomainSocketPath(@Nullable String domainSocketPath) {\n\t\t\tthis.domainSocketPath = domainSocketPath;\n\t\t}\n\n\t\tpublic enum Transport {\n\n\t\t\t/**\n\t\t\t * TCP transport.\n\t\t\t */\n\t\t\tTCP,\n\n\t\t\t/**\n\t\t\t * Domain socket transport.\n\t\t\t */\n\t\t\tDOMAIN_SOCKET\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Servlet properties.\n\t */\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Whether to use a servlet server in a servlet-based web application. When the\n\t\t * value is false, a native gRPC server will be created as long as one is\n\t\t * available, and it will listen on its own port. Should only be needed if the\n\t\t * GrpcServlet is on the classpath.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Whether to validate that HTTP/2 is enabled. Validation may need to be skipped\n\t\t * if your servlet container is not configured using properties.\n\t\t */\n\t\tprivate boolean validateHttp2 = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic boolean isValidateHttp2() {\n\t\t\treturn this.validateHttp2;\n\t\t}\n\n\t\tpublic void setValidateHttp2(boolean validateHttp2) {\n\t\t\tthis.validateHttp2 = validateHttp2;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerServicesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.BindableService;\nimport io.grpc.protobuf.services.ProtoReflectionServiceV1;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC server services.\n *\n * @author Haris Zujo\n * @author Dave Syer\n * @author Chris Bono\n * @author Andrey Litvitski\n * @since 4.1.0\n */\n@AutoConfiguration(before = GrpcServerAutoConfiguration.class)\n@ConditionalOnClass({ GrpcServerFactory.class, io.grpc.Grpc.class })\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.enabled\", matchIfMissing = true)\npublic final class GrpcServerServicesAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ProtoReflectionServiceV1.class)\n\t@ConditionalOnBean(BindableService.class)\n\t@ConditionalOnBooleanProperty(name = \"spring.grpc.server.reflection.enabled\", matchIfMissing = true)\n\tstatic class GrpcServerReflectionServiceConfiguration {\n\n\t\t@Bean\n\t\tBindableService grpcServerReflectionService() {\n\t\t\treturn ProtoReflectionServiceV1.newInstance();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/InProcessGrpcServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Configuration @Configuration} for an in-process gRPC server.\n *\n * @author David Syer\n * @author Chris Bono\n * @author Toshiaki Maki\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(InProcessGrpcServerFactory.class)\n@ConditionalOnProperty(\"spring.grpc.server.inprocess.name\")\n@ConditionalOnGrpcServerFactoryEnabled\nclass InProcessGrpcServerConfiguration {\n\n\t@Bean\n\tInProcessGrpcServerFactory inProcessGrpcServerFactory(GrpcServerProperties properties,\n\t\t\tGrpcServiceDiscoverer serviceDiscoverer, GrpcServiceConfigurer serviceConfigurer,\n\t\t\tGrpcServerBuilderCustomizers grpcServerBuilderCustomizers,\n\t\t\tObjectProvider<GrpcServerFactoryCustomizer> customizers) {\n\t\tString inProcessName = properties.getInprocess().getName();\n\t\tAssert.state(inProcessName != null, \"No inprocess name provided\");\n\t\tInProcessGrpcServerFactory factory = new InProcessGrpcServerFactory(inProcessName,\n\t\t\t\tgrpcServerBuilderCustomizers.forFactory());\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\tserviceDiscoverer.findServices()\n\t\t\t.stream()\n\t\t\t.map((spec) -> serviceConfigurer.configure(spec, factory))\n\t\t\t.forEach(factory::addService);\n\t\treturn factory;\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(InProcessGrpcServerFactory.class)\n\t@ConditionalOnMissingBean(name = \"inProcessGrpcServerLifecycle\")\n\tGrpcServerLifecycle inProcessGrpcServerLifecycle(InProcessGrpcServerFactory factory,\n\t\t\tGrpcServerProperties properties, ApplicationEventPublisher eventPublisher) {\n\t\treturn new GrpcServerLifecycle(factory, properties.getShutdown().getGracePeriod(), eventPublisher);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/MissingNetworkGrpcServerCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.AllNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\n\n/**\n * {@link Condition} that matches when no network gRPC server is found.\n *\n * @author Phillip Webb\n */\nclass MissingNetworkGrpcServerCondition extends AllNestedConditions {\n\n\tMissingNetworkGrpcServerCondition() {\n\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t}\n\n\t@ConditionalOnMissingBean(GrpcServletRegistration.class)\n\tstatic class MissingGrpcServletRegistrationBean {\n\n\t}\n\n\t@ConditionalOnMissingBean(value = GrpcServerFactory.class, ignored = InProcessGrpcServerFactory.class)\n\tstatic class MissingGrpcFactoryBean {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/NettyAddress.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.net.InetAddress;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerProperties.Netty.Transport;\nimport org.springframework.grpc.internal.GrpcUtils;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.util.StringUtils;\n\n/**\n * Represents the network address for a {@link GrpcServerFactory}.\n *\n * @author Phillip Webb\n * @param transport the transport to use\n * @param address the bind address\n * @param port the listen port\n * @param domainSocketPath the domain socket path\n */\nrecord NettyAddress(@Nullable Transport transport, @Nullable InetAddress address, @Nullable Integer port,\n\t\t@Nullable String domainSocketPath) {\n\n\t@Override\n\tpublic String toString() {\n\t\tTransport transport = (this.transport != null) ? this.transport : deduceTransport();\n\t\treturn switch (transport) {\n\t\t\tcase TCP -> tcpAddress();\n\t\t\tcase DOMAIN_SOCKET -> domainSocketAddress();\n\t\t};\n\t}\n\n\tprivate Transport deduceTransport() {\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\tentries.put(\"spring.grpc.server.address\", this.address);\n\t\t\tentries.put(\"spring.grpc.server.netty.domain-socket-path\", this.domainSocketPath);\n\t\t});\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\tentries.put(\"spring.grpc.server.port\", this.port);\n\t\t\tentries.put(\"spring.grpc.server.netty.domain-socket-path\", this.domainSocketPath);\n\t\t});\n\t\tif (this.address != null || this.port != null) {\n\t\t\treturn Transport.TCP;\n\t\t}\n\t\tif (this.domainSocketPath != null) {\n\t\t\treturn Transport.DOMAIN_SOCKET;\n\t\t}\n\t\treturn Transport.TCP;\n\t}\n\n\tprivate String tcpAddress() {\n\t\tString address = (this.address != null) ? toString(this.address) : GrpcUtils.ANY_IP_ADDRESS;\n\t\tint port = (this.port != null) ? this.port : GrpcUtils.DEFAULT_PORT;\n\t\treturn address + \":\" + port;\n\t}\n\n\tprivate String domainSocketAddress() {\n\t\tif (!StringUtils.hasText(this.domainSocketPath)) {\n\t\t\tthrow new InvalidConfigurationPropertyValueException(\"spring.grpc.server.netty.domain-socket-path\",\n\t\t\t\t\tthis.domainSocketPath,\n\t\t\t\t\t\"A path is required when spring.grpc.server.netty.transport is set to 'domain-socket'\");\n\t\t}\n\t\treturn \"unix:\" + this.domainSocketPath;\n\t}\n\n\tprivate static String toString(InetAddress address) {\n\t\tString hostName = address.getHostName();\n\t\treturn (hostName != null) ? hostName : address.getHostAddress();\n\t}\n\n\tstatic NettyAddress fromProperties(GrpcServerProperties properties) {\n\t\treturn new NettyAddress(properties.getNetty().getTransport(), properties.getAddress(), properties.getPort(),\n\t\t\t\tproperties.getNetty().getDomainSocketPath());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/NettyGrpcServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.netty.NettyServerBuilder;\nimport io.netty.handler.ssl.util.InsecureTrustManagerFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.NettyGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\n\n/**\n * {@link Configuration @Configuration} for a Netty gRPC server.\n *\n * @author David Syer\n * @author Chris Bono\n * @author Toshiaki Maki\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(NettyServerBuilder.class)\n@ConditionalOnMissingNetworkGrpcServer\n@ConditionalOnGrpcServerFactoryEnabled\nclass NettyGrpcServerConfiguration {\n\n\t@Bean\n\tNettyGrpcServerFactory nettyGrpcServerFactory(GrpcServerProperties properties,\n\t\t\tGrpcServiceDiscoverer serviceDiscoverer, GrpcServiceConfigurer serviceConfigurer,\n\t\t\tGrpcServerBuilderCustomizers grpcServerBuilderCustomizers, SslBundles bundles,\n\t\t\tObjectProvider<GrpcServerFactoryCustomizer> customizers) {\n\t\tNettyAddress address = NettyAddress.fromProperties(properties);\n\t\tServerCredentials credentials = ServerCredentials.get(properties.getSsl(), bundles,\n\t\t\t\tInsecureTrustManagerFactory.INSTANCE);\n\t\tNettyGrpcServerFactory factory = new NettyGrpcServerFactory(address.toString(),\n\t\t\t\tgrpcServerBuilderCustomizers.forFactory(), credentials.keyManagerFactory(),\n\t\t\t\tcredentials.trustManagerFactory(), credentials.clientAuth());\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\tserviceDiscoverer.findServices()\n\t\t\t.stream()\n\t\t\t.map((spec) -> serviceConfigurer.configure(spec, factory))\n\t\t\t.forEach(factory::addService);\n\t\treturn factory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"nettyGrpcServerLifecycle\")\n\tGrpcServerLifecycle nettyGrpcServerLifecycle(NettyGrpcServerFactory factory, GrpcServerProperties properties,\n\t\t\tApplicationEventPublisher eventPublisher) {\n\t\treturn new GrpcServerLifecycle(factory, properties.getShutdown().getGracePeriod(), eventPublisher);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/PropertiesServerBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport io.grpc.ServerBuilder;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerProperties.Inbound;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerProperties.Keepalive;\nimport org.springframework.grpc.server.ServerBuilderCustomizer;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link ServerBuilderCustomizer} that maps {@link GrpcServerProperties} to a\n * {@link ServerBuilder}.\n *\n * @param <T> the type of server builder\n * @param properties the properties to map\n * @author Chris Bono\n * @author Phillip Webb\n */\nrecord PropertiesServerBuilderCustomizer<T extends ServerBuilder<T>>(\n\t\tGrpcServerProperties properties) implements ServerBuilderCustomizer<T> {\n\n\t@Override\n\tpublic void customize(T builder) {\n\t\tmapInboundProperties(this.properties.getInbound(), builder);\n\t\tif (supportsKeepAliveProperties(builder)) {\n\t\t\tmapKeepaliveProperties(this.properties.getKeepalive(), builder);\n\t\t}\n\t}\n\n\tprivate void mapInboundProperties(Inbound properties, T builder) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties.getMessage()::getMaxSize).asInt(DataSize::toBytes).to(builder::maxInboundMessageSize);\n\t\tmap.from(properties.getMetadata()::getMaxSize).asInt(DataSize::toBytes).to(builder::maxInboundMetadataSize);\n\t}\n\n\tprivate void mapKeepaliveProperties(Keepalive properties, T builder) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getTime).to(durationProperty(builder::keepAliveTime));\n\t\tmap.from(properties::getTimeout).to(durationProperty(builder::keepAliveTimeout));\n\t\tmap.from(properties.getConnection()::getMaxIdleTime).to(durationProperty(builder::maxConnectionIdle));\n\t\tmap.from(properties.getConnection()::getMaxAge).to(durationProperty(builder::maxConnectionAge));\n\t\tmap.from(properties.getConnection()::getGracePeriod).to(durationProperty(builder::maxConnectionAgeGrace));\n\t\tmap.from(properties.getPermit()::getTime).to(durationProperty(builder::permitKeepAliveTime));\n\t\tmap.from(properties.getPermit()::isWithoutCalls).to(builder::permitKeepAliveWithoutCalls);\n\t}\n\n\tprivate Consumer<Duration> durationProperty(BiConsumer<Long, TimeUnit> setter) {\n\t\treturn (duration) -> setter.accept(duration.toNanos(), TimeUnit.NANOSECONDS);\n\t}\n\n\tprivate boolean supportsKeepAliveProperties(T builder) {\n\t\treturn !isInstance(\"io.grpc.inprocess.InProcessServerBuilder\", builder)\n\t\t\t\t&& !isInstance(\"io.grpc.servlet.jakarta.ServletServerBuilder\", builder);\n\t}\n\n\tprivate boolean isInstance(String className, T builder) {\n\t\ttry {\n\t\t\treturn ClassUtils.forName(className, builder.getClass().getClassLoader()).isInstance(builder);\n\t\t}\n\t\tcatch (ClassNotFoundException | LinkageError ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/ServerCredentials.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport io.grpc.TlsServerCredentials.ClientAuth;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslManagerBundle;\nimport org.springframework.util.Assert;\n\n/**\n * Server credential details to use with gRPC servers.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @param keyManagerFactory the key manager factory to use or {@code null}\n * @param trustManagerFactory the trust manager factory to use or {@code null}\n * @param clientAuth the client auth to use\n */\nrecord ServerCredentials(@Nullable KeyManagerFactory keyManagerFactory,\n\t\t@Nullable TrustManagerFactory trustManagerFactory, ClientAuth clientAuth) {\n\n\t/**\n\t * Return the credentials to use based on the given properties.\n\t * @param properties the SSL properties\n\t * @param bundles the SSL bundles\n\t * @param insecureTrustManagerFactory the trust manager factory to use for insecure\n\t * connections\n\t * @return the server credentials to use\n\t */\n\tstatic ServerCredentials get(GrpcServerProperties.Ssl properties, SslBundles bundles,\n\t\t\tTrustManagerFactory insecureTrustManagerFactory) {\n\t\tBoolean enabled = properties.getEnabled();\n\t\tString bundle = properties.getBundle();\n\t\tClientAuth clientAuth = properties.getClientAuth();\n\t\tif (Boolean.FALSE.equals(enabled) || (enabled == null && bundle == null)) {\n\t\t\treturn new ServerCredentials(null, null, clientAuth);\n\t\t}\n\t\tAssert.state(bundle != null,\n\t\t\t\t() -> \"SSL bundle-name is requested when 'spring.grpc.server.ssl.enabled' is true\");\n\t\tSslManagerBundle managers = bundles.getBundle(bundle).getManagers();\n\t\tKeyManagerFactory keyManagerFactory = managers.getKeyManagerFactory();\n\t\tTrustManagerFactory trustManagerFactory = (!properties.isSecure()) ? insecureTrustManagerFactory\n\t\t\t\t: managers.getTrustManagerFactory();\n\t\treturn new ServerCredentials(keyManagerFactory, trustManagerFactory, clientAuth);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/ServletGrpcServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.servlet.jakarta.GrpcServlet;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.diagnostics.FailureAnalyzedException;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\n\n/**\n * {@link Configuration @Configuration} for a Servlet gRPC server.\n *\n * @author David Syer\n * @author Chris Bono\n * @author Toshiaki Maki\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)\n@ConditionalOnClass(GrpcServlet.class)\n@ConditionalOnMissingNetworkGrpcServer\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.servlet.enabled\", matchIfMissing = true)\nclass ServletGrpcServerConfiguration {\n\n\t@Bean\n\tGrpcServletRegistration grpcServletRegistration(Environment environment, GrpcServerProperties properties,\n\t\t\tGrpcServiceDiscoverer serviceDiscoverer, GrpcServiceConfigurer serviceConfigurer,\n\t\t\tGrpcServerBuilderCustomizers grpcServerBuilderCustomizers) {\n\t\tif (properties.getServlet().isValidateHttp2()\n\t\t\t\t&& !Boolean.TRUE.equals(environment.getProperty(\"server.http2.enabled\", Boolean.class))) {\n\t\t\tthrow new FailureAnalyzedException(\n\t\t\t\t\t\"Configuration property 'server.http2.enabled' should be set to true for gRPC support\",\n\t\t\t\t\t\"Update your application to correct the invalid configuration.\\n\"\n\t\t\t\t\t\t\t+ \"You can also set 'spring.grpc.server.servlet.validate-http2' to false to disable the validation.\");\n\t\t}\n\t\treturn new GrpcServletRegistration(serviceDiscoverer, serviceConfigurer, grpcServerBuilderCustomizers::apply);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/ShadedNettyGrpcServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;\nimport io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.ShadedNettyGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\n\n/**\n * {@link Configuration @Configuration} for a Shaded Netty gRPC server.\n *\n * @author David Syer\n * @author Chris Bono\n * @author Toshiaki Maki\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(NettyServerBuilder.class)\n@ConditionalOnMissingNetworkGrpcServer\n@ConditionalOnGrpcServerFactoryEnabled\nclass ShadedNettyGrpcServerConfiguration {\n\n\t@Bean\n\tShadedNettyGrpcServerFactory shadedNettyGrpcServerFactory(GrpcServerProperties properties,\n\t\t\tGrpcServiceDiscoverer serviceDiscoverer, GrpcServiceConfigurer serviceConfigurer,\n\t\t\tGrpcServerBuilderCustomizers grpcServerBuilderCustomizers, SslBundles bundles,\n\t\t\tObjectProvider<GrpcServerFactoryCustomizer> customizers) {\n\t\tNettyAddress address = NettyAddress.fromProperties(properties);\n\t\tServerCredentials serverCredentials = ServerCredentials.get(properties.getSsl(), bundles,\n\t\t\t\tInsecureTrustManagerFactory.INSTANCE);\n\t\tShadedNettyGrpcServerFactory factory = new ShadedNettyGrpcServerFactory(address.toString(),\n\t\t\t\tgrpcServerBuilderCustomizers.forFactory(), serverCredentials.keyManagerFactory(),\n\t\t\t\tserverCredentials.trustManagerFactory(), serverCredentials.clientAuth());\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\tserviceDiscoverer.findServices()\n\t\t\t.stream()\n\t\t\t.map((spec) -> serviceConfigurer.configure(spec, factory))\n\t\t\t.forEach(factory::addService);\n\t\treturn factory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"shadedNettyGrpcServerLifecycle\")\n\tGrpcServerLifecycle shadedNettyGrpcServerLifecycle(ShadedNettyGrpcServerFactory factory,\n\t\t\tGrpcServerProperties properties, ApplicationEventPublisher eventPublisher) {\n\t\treturn new GrpcServerLifecycle(factory, properties.getShutdown().getGracePeriod(), eventPublisher);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/AutoConfiguredHealthCheckedGrpcComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponent;\nimport org.springframework.boot.grpc.server.health.StatusAggregator;\nimport org.springframework.boot.grpc.server.health.StatusMapper;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembership;\n\n/**\n * Auto-configured {@link HealthCheckedGrpcComponent}.\n *\n * @author Phillip Webb\n */\nclass AutoConfiguredHealthCheckedGrpcComponent implements HealthCheckedGrpcComponent {\n\n\tprivate final HealthContributorMembership membership;\n\n\tprivate final StatusAggregator statusAggregator;\n\n\tprivate final StatusMapper statusMapper;\n\n\tAutoConfiguredHealthCheckedGrpcComponent(HealthContributorMembership membership, StatusAggregator statusAggregator,\n\t\t\tStatusMapper statusMapper) {\n\t\tthis.membership = membership;\n\t\tthis.statusAggregator = statusAggregator;\n\t\tthis.statusMapper = statusMapper;\n\t}\n\n\t@Override\n\tpublic boolean isMember(String healthContributorName) {\n\t\treturn this.membership.isMember(healthContributorName);\n\t}\n\n\t@Override\n\tpublic StatusAggregator getStatusAggregator() {\n\t\treturn this.statusAggregator;\n\t}\n\n\t@Override\n\tpublic StatusMapper getStatusMapper() {\n\t\treturn this.statusMapper;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/AutoConfiguredHealthCheckedGrpcComponents.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.function.Supplier;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;\nimport org.springframework.boot.grpc.server.autoconfigure.health.GrpcServerHealthProperties.Service;\nimport org.springframework.boot.grpc.server.autoconfigure.health.GrpcServerHealthProperties.Status;\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponent;\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponents;\nimport org.springframework.boot.grpc.server.health.StatusAggregator;\nimport org.springframework.boot.grpc.server.health.StatusMapper;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembership;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Auto-configured {@link HealthCheckedGrpcComponents}.\n *\n * @author Phillip Webb\n */\nclass AutoConfiguredHealthCheckedGrpcComponents implements HealthCheckedGrpcComponents {\n\n\tprivate final HealthCheckedGrpcComponent server;\n\n\tprivate final Map<String, HealthCheckedGrpcComponent> services;\n\n\t/**\n\t * Create a new {@link AutoConfiguredHealthCheckedGrpcComponents} instance.\n\t * @param applicationContext the application context used to check for override beans\n\t * @param properties the gRPC server health properties\n\t */\n\tAutoConfiguredHealthCheckedGrpcComponents(ApplicationContext applicationContext,\n\t\t\tGrpcServerHealthProperties properties) {\n\t\tListableBeanFactory beanFactory = (applicationContext instanceof ConfigurableApplicationContext configurableContext)\n\t\t\t\t? configurableContext.getBeanFactory() : applicationContext;\n\t\tStatusAggregator statusAggregator = getNonQualifiedBean(beanFactory, StatusAggregator.class,\n\t\t\t\t() -> StatusAggregator.of(properties.getStatus().getOrder()));\n\t\tStatusMapper statusMapper = getNonQualifiedBean(beanFactory, StatusMapper.class,\n\t\t\t\t() -> StatusMapper.of(properties.getStatus().getMapping()));\n\t\tthis.server = new AutoConfiguredHealthCheckedGrpcComponent(HealthContributorMembership.always(),\n\t\t\t\tstatusAggregator, statusMapper);\n\t\tthis.services = createServices(properties.getService(), beanFactory, statusAggregator, statusMapper);\n\t}\n\n\tprivate Map<String, HealthCheckedGrpcComponent> createServices(Map<String, Service> serviceProperties,\n\t\t\tBeanFactory beanFactory, StatusAggregator defaultStatusAggregator, StatusMapper defaultStatusMapper) {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new TreeMap<>();\n\t\tserviceProperties.forEach((serviceName, service) -> {\n\t\t\tStatus status = service.getStatus();\n\t\t\tStatusAggregator statusAggregator = getQualifiedBean(beanFactory, StatusAggregator.class, serviceName,\n\t\t\t\t\t() -> createStatusAggregator(status.getOrder(), defaultStatusAggregator));\n\t\t\tStatusMapper statusMapper = getQualifiedBean(beanFactory, StatusMapper.class, serviceName,\n\t\t\t\t\t() -> createStatusMapper(status.getMapping(), defaultStatusMapper));\n\t\t\tHealthContributorMembership membership = HealthContributorMembership.byIncludeExclude(service.getInclude(),\n\t\t\t\t\tservice.getExclude());\n\t\t\tservices.put(serviceName,\n\t\t\t\t\tnew AutoConfiguredHealthCheckedGrpcComponent(membership, statusAggregator, statusMapper));\n\t\t});\n\t\treturn Collections.unmodifiableMap(services);\n\t}\n\n\tprivate StatusAggregator createStatusAggregator(List<String> order, StatusAggregator defaultStatusAggregator) {\n\t\treturn (!CollectionUtils.isEmpty(order)) ? StatusAggregator.of(order) : defaultStatusAggregator;\n\t}\n\n\tprivate StatusMapper createStatusMapper(Map<String, ServingStatus> mapping, StatusMapper defaultStatusMapper) {\n\t\treturn (!CollectionUtils.isEmpty(mapping)) ? StatusMapper.of(mapping) : defaultStatusMapper;\n\t}\n\n\tprivate <T> T getNonQualifiedBean(ListableBeanFactory beanFactory, Class<T> type, Supplier<T> fallback) {\n\t\tList<String> candidates = new ArrayList<>();\n\t\tfor (String beanName : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {\n\t\t\tString[] aliases = beanFactory.getAliases(beanName);\n\t\t\tif (!BeanFactoryAnnotationUtils.isQualifierMatch(\n\t\t\t\t\t(qualifier) -> !qualifier.equals(beanName) && !ObjectUtils.containsElement(aliases, qualifier),\n\t\t\t\t\tbeanName, beanFactory)) {\n\t\t\t\tcandidates.add(beanName);\n\t\t\t}\n\t\t}\n\t\tif (candidates.isEmpty()) {\n\t\t\treturn fallback.get();\n\t\t}\n\t\tif (candidates.size() == 1) {\n\t\t\treturn beanFactory.getBean(candidates.get(0), type);\n\t\t}\n\t\treturn beanFactory.getBean(type);\n\t}\n\n\tprivate <T> T getQualifiedBean(BeanFactory beanFactory, Class<T> type, String qualifier, Supplier<T> fallback) {\n\t\ttry {\n\t\t\treturn BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, type, qualifier);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn fallback.get();\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable HealthCheckedGrpcComponent getServer() {\n\t\treturn this.server;\n\t}\n\n\t@Override\n\tpublic Set<String> getServiceNames() {\n\t\treturn this.services.keySet();\n\t}\n\n\t@Override\n\tpublic @Nullable HealthCheckedGrpcComponent getService(String serviceName) {\n\t\treturn this.services.get(serviceName);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/GrpcServerHealthAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport io.grpc.BindableService;\nimport io.grpc.Grpc;\nimport io.grpc.protobuf.services.HealthStatusManager;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.grpc.server.autoconfigure.health.GrpcServerHealthAutoConfiguration.NotDisabledAndHasBindableServiceOrExplicitlyEnabledCondition;\nimport org.springframework.boot.grpc.server.health.GrpcServerHealth;\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponents;\nimport org.springframework.boot.grpc.server.health.StatusAggregator;\nimport org.springframework.boot.grpc.server.health.StatusMapper;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembershipValidator;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC server-side health service.\n *\n * @author Daniel Theuke\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration\")\n@ConditionalOnClass({ GrpcServerFactory.class, Grpc.class, HealthStatusManager.class })\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.enabled\", matchIfMissing = true)\n@Conditional(NotDisabledAndHasBindableServiceOrExplicitlyEnabledCondition.class)\n@EnableConfigurationProperties(GrpcServerHealthProperties.class)\npublic final class GrpcServerHealthAutoConfiguration {\n\n\t@Bean(destroyMethod = \"enterTerminalState\")\n\t@ConditionalOnMissingBean\n\tHealthStatusManager grpcServerHealthStatusManager() {\n\t\treturn new HealthStatusManager();\n\t}\n\n\t@Bean\n\tBindableService grpcServerHealthService(HealthStatusManager healthStatusManager) {\n\t\treturn healthStatusManager.getHealthService();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(type = \"org.springframework.boot.health.registry.HealthContributorRegistry\")\n\tstatic class GrpcServerHealthContributorConfiguration {\n\n\t\tstatic final String VALIDATE_MEMBERSHIP_PROPERTY = \"spring.grpc.server.health.services.validate-membership\";\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tStatusAggregator grpcServerHealthStatusAggregator(GrpcServerHealthProperties properties) {\n\t\t\treturn StatusAggregator.of(properties.getStatus().getOrder());\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tStatusMapper grpcServerHealthHttpCodeStatusMapper(GrpcServerHealthProperties properties) {\n\t\t\treturn StatusMapper.of(properties.getStatus().getMapping());\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(HealthCheckedGrpcComponents.class)\n\t\tAutoConfiguredHealthCheckedGrpcComponents grpcServerHealthCheckedGrpcComponents(\n\t\t\t\tApplicationContext applicationContext, GrpcServerHealthProperties properties) {\n\t\t\treturn new AutoConfiguredHealthCheckedGrpcComponents(applicationContext, properties);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tGrpcServerHealth grpcServerHealth(HealthContributorRegistry healthContributorRegistry,\n\t\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,\n\t\t\t\tHealthCheckedGrpcComponents healthCheckedGrpcComponents) {\n\t\t\treturn new GrpcServerHealth(healthContributorRegistry, reactiveHealthContributorRegistry.getIfAvailable(),\n\t\t\t\t\thealthCheckedGrpcComponents);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBooleanProperty(name = VALIDATE_MEMBERSHIP_PROPERTY, matchIfMissing = true)\n\t\tHealthContributorMembershipValidator grpcServerHealthServiceMembershipValidator(\n\t\t\t\tGrpcServerHealthProperties properties, HealthContributorRegistry healthContributorRegistry,\n\t\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry) {\n\t\t\treturn new HealthContributorMembershipValidator(healthContributorRegistry,\n\t\t\t\t\treactiveHealthContributorRegistry.getIfAvailable(), VALIDATE_MEMBERSHIP_PROPERTY,\n\t\t\t\t\t(members) -> properties.getService().forEach((serviceName, service) -> {\n\t\t\t\t\t\tString property = \"spring.grpc.server.health.service.\" + serviceName;\n\t\t\t\t\t\tmembers.member(property + \".include\", service.getInclude());\n\t\t\t\t\t\tmembers.member(property + \".exclude\", service.getExclude());\n\t\t\t\t\t}));\n\t\t}\n\n\t}\n\n\tstatic class NotDisabledAndHasBindableServiceOrExplicitlyEnabledCondition extends AnyNestedCondition {\n\n\t\tNotDisabledAndHasBindableServiceOrExplicitlyEnabledCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnBean(BindableService.class)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.grpc.server.health.enabled\", matchIfMissing = true)\n\t\tstatic class NotDisabledAndHasBindableService {\n\n\t\t}\n\n\t\t@ConditionalOnBooleanProperty(name = \"spring.grpc.server.health.enabled\")\n\t\tstatic class ExplicitlyEnabled {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/GrpcServerHealthProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link ConfigurationProperties Properties} for Spring gRPC server health.\n *\n * @author Phillip Webb\n * @author Chris Bono\n * @since 4.1.0\n */\n@ConfigurationProperties(\"spring.grpc.server.health\")\npublic class GrpcServerHealthProperties {\n\n\t/**\n\t * Whether to auto-configure the Health feature on the gRPC server.\n\t */\n\tprivate @Nullable Boolean enabled;\n\n\t/**\n\t * Whether to include the overall server health.\n\t */\n\tprivate boolean includeOverallHealth = true;\n\n\tprivate final Services services = new Services();\n\n\t/**\n\t * Service-specific health reporting.\n\t */\n\tprivate final Map<String, Service> service = new LinkedHashMap<>();\n\n\t/**\n\t * Status configuration.\n\t */\n\tprivate final Status status = new Status();\n\n\t/**\n\t * Schedule configuration.\n\t */\n\tprivate final Schedule schedule = new Schedule();\n\n\tpublic @Nullable Boolean getEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(@Nullable Boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic boolean isIncludeOverallHealth() {\n\t\treturn this.includeOverallHealth;\n\t}\n\n\tpublic void setIncludeOverallHealth(boolean includeOverallHealth) {\n\t\tthis.includeOverallHealth = includeOverallHealth;\n\t}\n\n\tpublic Services getServices() {\n\t\treturn this.services;\n\t}\n\n\tpublic Map<String, Service> getService() {\n\t\treturn this.service;\n\t}\n\n\tpublic Status getStatus() {\n\t\treturn this.status;\n\t}\n\n\tpublic Schedule getSchedule() {\n\t\treturn this.schedule;\n\t}\n\n\t/**\n\t * Properties applying to all services.\n\t */\n\tpublic static class Services {\n\n\t\t/**\n\t\t * Whether to validate health membership for services on startup. Validation fails\n\t\t * if a service includes or excludes a health contributor that does not exist.\n\t\t */\n\t\tprivate boolean validateMembership = true;\n\n\t\tpublic boolean isValidateMembership() {\n\t\t\treturn this.validateMembership;\n\t\t}\n\n\t\tpublic void setValidateMembership(boolean validateMembership) {\n\t\t\tthis.validateMembership = validateMembership;\n\t\t}\n\n\t}\n\n\t/**\n\t * Health for a specific service.\n\t */\n\tpublic static class Service {\n\n\t\t/**\n\t\t * Health indicator IDs that should be included or '*' for all.\n\t\t */\n\t\tprivate @Nullable Set<String> include;\n\n\t\t/**\n\t\t * Health indicator IDs that should be excluded or '*' for all.\n\t\t */\n\t\tprivate @Nullable Set<String> exclude;\n\n\t\t@NestedConfigurationProperty\n\t\tprivate final Status status = new Status();\n\n\t\tpublic Status getStatus() {\n\t\t\treturn this.status;\n\t\t}\n\n\t\tpublic @Nullable Set<String> getInclude() {\n\t\t\treturn this.include;\n\t\t}\n\n\t\tpublic void setInclude(@Nullable Set<String> include) {\n\t\t\tthis.include = include;\n\t\t}\n\n\t\tpublic @Nullable Set<String> getExclude() {\n\t\t\treturn this.exclude;\n\t\t}\n\n\t\tpublic void setExclude(@Nullable Set<String> exclude) {\n\t\t\tthis.exclude = exclude;\n\t\t}\n\n\t}\n\n\t/**\n\t * Status properties for the group.\n\t */\n\tpublic static class Status {\n\n\t\t/**\n\t\t * List of health statuses in order of severity.\n\t\t */\n\t\tprivate List<String> order = new ArrayList<>();\n\n\t\t/**\n\t\t * Mapping of health statuses to gRPC service status. By default, registered\n\t\t * health statuses map to sensible defaults (for example, UP maps to SERVING).\n\t\t */\n\t\tprivate final Map<String, ServingStatus> mapping = new HashMap<>();\n\n\t\tpublic List<String> getOrder() {\n\t\t\treturn this.order;\n\t\t}\n\n\t\tpublic void setOrder(List<String> statusOrder) {\n\t\t\tif (!CollectionUtils.isEmpty(statusOrder)) {\n\t\t\t\tthis.order = statusOrder;\n\t\t\t}\n\t\t}\n\n\t\tpublic Map<String, ServingStatus> getMapping() {\n\t\t\treturn this.mapping;\n\t\t}\n\n\t}\n\n\t/**\n\t * Health task scheduling.\n\t */\n\tpublic static class Schedule {\n\n\t\t/**\n\t\t * Whether to schedule updates to gRPC server health based on application health.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\t/**\n\t\t * How often to update the health status. If a duration suffix is not specified,\n\t\t * seconds will be used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate Duration period = Duration.ofSeconds(5);\n\n\t\t/**\n\t\t * Initial delay before updating the health status the very first time. If a\n\t\t * duration suffix is not specified, seconds will be used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate Duration delay = Duration.ofSeconds(5);\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic Duration getPeriod() {\n\t\t\treturn this.period;\n\t\t}\n\n\t\tpublic void setPeriod(Duration period) {\n\t\t\tthis.period = period;\n\t\t}\n\n\t\tpublic Duration getDelay() {\n\t\t\treturn this.delay;\n\t\t}\n\n\t\tpublic void setDelay(Duration delay) {\n\t\t\tthis.delay = delay;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/GrpcServerHealthScheduler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.concurrent.ScheduledFuture;\n\nimport io.grpc.protobuf.services.HealthStatusManager;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.grpc.server.health.GrpcServerHealth;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * Schedules gRPC health updates once the gRPC server has been started.\n *\n * @author Phillip Webb\n * @author Chris Bono\n */\nclass GrpcServerHealthScheduler implements ApplicationListener<GrpcServerStartedEvent> {\n\n\tprivate static final Log logger = LogFactory.getLog(GrpcServerHealthScheduler.class);\n\n\tprivate final SingletonSupplier<ScheduledFuture<?>> scheduleHealth;\n\n\tGrpcServerHealthScheduler(GrpcServerHealth grpcServerHealth, HealthStatusManager grpcServerHealthStatusManager,\n\t\t\tTaskScheduler taskScheduler, Duration period, Duration delay) {\n\t\tthis(Clock.systemDefaultZone(), grpcServerHealth, grpcServerHealthStatusManager, taskScheduler, period, delay);\n\t}\n\n\tGrpcServerHealthScheduler(Clock clock, GrpcServerHealth grpcServerHealth,\n\t\t\tHealthStatusManager grpcServerHealthStatusManager, TaskScheduler taskScheduler, Duration period,\n\t\t\tDuration delay) {\n\t\tthis.scheduleHealth = SingletonSupplier.of(() -> {\n\t\t\tlogger.debug(LogMessage\n\t\t\t\t.of(() -> \"Scheduling gRPC server health updates every %s seconds (after a delay of %s seconds)\"\n\t\t\t\t\t.formatted((period.toMillis() / 1000.0), delay.toMillis() / 1000.0)));\n\t\t\tRunnable task = () -> grpcServerHealth.update(grpcServerHealthStatusManager);\n\t\t\treturn taskScheduler.scheduleAtFixedRate(task, Instant.now(clock).plus(delay), period);\n\t\t});\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(GrpcServerStartedEvent event) {\n\t\tthis.scheduleHealth.get();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/GrpcServerHealthSchedulerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport io.grpc.Grpc;\nimport io.grpc.protobuf.services.HealthStatusManager;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.task.DefaultTaskSchedulerConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.health.GrpcServerHealthProperties.Schedule;\nimport org.springframework.boot.grpc.server.health.GrpcServerHealth;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.scheduling.TaskScheduler;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to invoke {@link GrpcServerHealth}\n * updates using a {@link TaskScheduler}.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(after = GrpcServerHealthAutoConfiguration.class)\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.health.schedule.enabled\", matchIfMissing = true)\n@Import(DefaultTaskSchedulerConfiguration.class)\n@ConditionalOnClass({ GrpcServerFactory.class, Grpc.class, HealthStatusManager.class })\npublic final class GrpcServerHealthSchedulerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean({ TaskScheduler.class, GrpcServerHealth.class })\n\tGrpcServerHealthScheduler grpcServerHealthScheduler(GrpcServerHealth grpcServerHealth,\n\t\t\tHealthStatusManager grpcServerHealthStatusManager, TaskScheduler taskScheduler,\n\t\t\tGrpcServerHealthProperties properties) {\n\t\tSchedule schedule = properties.getSchedule();\n\t\treturn new GrpcServerHealthScheduler(grpcServerHealth, grpcServerHealthStatusManager, taskScheduler,\n\t\t\t\tschedule.getPeriod(), schedule.getDelay());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for gRPC server health checks.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for gRPC server.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/GrpcDisableCsrfHttpConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.boot.grpc.server.autoconfigure.security.web.servlet.GrpcRequest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.csrf.CsrfFilter;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * A custom {@link AbstractHttpConfigurer} that disables CSRF protection for gRPC\n * requests.\n * <p>\n * This configurer checks the application context to determine if CSRF protection should\n * be disabled for gRPC requests based on the property\n * {@code spring.grpc.server.security.csrf.enabled}. By default, CSRF protection is\n * disabled unless explicitly enabled in the application properties.\n * </p>\n *\n * @author Dave Syer\n * @see AbstractHttpConfigurer\n * @see HttpSecurity\n */\nclass GrpcDisableCsrfHttpConfigurer extends AbstractHttpConfigurer<GrpcDisableCsrfHttpConfigurer, HttpSecurity> {\n\n\t@Override\n\tpublic void init(HttpSecurity http) {\n\t\tApplicationContext context = http.getSharedObject(ApplicationContext.class);\n\t\tif (context != null && isCsrfConfigurerPresent(http) && hasBean(context, GrpcServiceDiscoverer.class)\n\t\t\t\t&& hasBean(context, GrpcServletRegistration.class) && isCsrfEnabled(context)) {\n\t\t\thttp.csrf(this::disable);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate boolean isCsrfConfigurerPresent(HttpSecurity http) {\n\t\treturn http.getConfigurer(CsrfConfigurer.class) != null;\n\t}\n\n\tprivate boolean hasBean(ApplicationContext context, Class<?> type) {\n\t\treturn !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type));\n\t}\n\n\tprivate boolean isCsrfEnabled(ApplicationContext context) {\n\t\treturn context.getEnvironment().getProperty(\"spring.grpc.server.security.csrf.enabled\", Boolean.class, true);\n\t}\n\n\tprivate void disable(CsrfConfigurer<HttpSecurity> csrf) {\n\t\tcsrf.requireCsrfProtectionMatcher(GrpcCsrfRequestMatcher.INSTANCE);\n\t}\n\n\tstatic class GrpcCsrfRequestMatcher implements RequestMatcher {\n\n\t\tstatic final GrpcCsrfRequestMatcher INSTANCE = new GrpcCsrfRequestMatcher();\n\n\t\t@Override\n\t\tpublic boolean matches(HttpServletRequest request) {\n\t\t\treturn CsrfFilter.DEFAULT_CSRF_MATCHER.matches(request) && !GrpcRequest.toAnyService().matches(request);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/GrpcServerOAuth2ResourceServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport io.grpc.BindableService;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.security.AuthenticationProcessInterceptor;\nimport org.springframework.grpc.server.security.GrpcSecurity;\nimport org.springframework.security.config.ObjectPostProcessor;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC OAuth2 resource server.\n *\n * @author Dave Syer\n * @author Andrey Litvitski\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(beforeName = \"org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration\",\n\t\tafterName = { \"org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration\" },\n\t\tafter = { GrpcServerSecurityAutoConfiguration.class, GrpcServerAutoConfiguration.class })\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.enabled\", matchIfMissing = true)\n@ConditionalOnClass({ BindableService.class, GrpcServerFactory.class, ObjectPostProcessor.class })\n@ConditionalOnMissingBean(AuthenticationProcessInterceptor.class)\n@ConditionalOnBean(GrpcSecurity.class)\npublic final class GrpcServerOAuth2ResourceServerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(OpaqueTokenIntrospector.class)\n\t@GlobalServerInterceptor\n\tAuthenticationProcessInterceptor opaqueTokenAuthenticationProcessInterceptor(GrpcSecurity grpcSecurity)\n\t\t\tthrows Exception {\n\t\tgrpcSecurity.authorizeRequests((requests) -> requests.allRequests().authenticated());\n\t\tgrpcSecurity.oauth2ResourceServer((resourceServer) -> resourceServer.opaqueToken(withDefaults()));\n\t\treturn grpcSecurity.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(JwtDecoder.class)\n\t@GlobalServerInterceptor\n\tAuthenticationProcessInterceptor jwtAuthenticationProcessInterceptor(GrpcSecurity grpcSecurity) throws Exception {\n\t\tgrpcSecurity.authorizeRequests((requests) -> requests.allRequests().authenticated());\n\t\tgrpcSecurity.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()));\n\t\treturn grpcSecurity.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/GrpcServerSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport io.grpc.BindableService;\nimport io.grpc.internal.GrpcUtil;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerExecutorProvider;\nimport org.springframework.boot.grpc.server.autoconfigure.security.GrpcServerSecurityAutoConfiguration.ExceptionHandlerConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.security.GrpcServerSecurityAutoConfiguration.GrpcNativeSecurityConfigurerConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.security.GrpcServerSecurityAutoConfiguration.GrpcServletSecurityConfigurerConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.security.CoroutineSecurityContextInterceptor;\nimport org.springframework.grpc.server.security.GrpcSecurity;\nimport org.springframework.grpc.server.security.SecurityContextServerInterceptor;\nimport org.springframework.grpc.server.security.SecurityGrpcExceptionHandler;\nimport org.springframework.security.concurrent.DelegatingSecurityContextExecutor;\nimport org.springframework.security.config.ObjectPostProcessor;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;\nimport org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;\nimport org.springframework.security.web.SecurityFilterChain;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for gRPC server-side security.\n *\n * @author Dave Syer\n * @author Chris Bono\n * @author Andrey Litvitski\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(after = GrpcServerAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration\")\n@ConditionalOnBooleanProperty(name = \"spring.grpc.server.enabled\", matchIfMissing = true)\n@ConditionalOnClass({ BindableService.class, GrpcServerFactory.class, ObjectPostProcessor.class })\n@Import({ ExceptionHandlerConfiguration.class, GrpcNativeSecurityConfigurerConfiguration.class,\n\t\tGrpcServletSecurityConfigurerConfiguration.class })\npublic final class GrpcServerSecurityAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(AuthenticationConfiguration.class)\n\tstatic class ExceptionHandlerConfiguration {\n\n\t\t@Bean\n\t\tSecurityGrpcExceptionHandler accessExceptionHandler() {\n\t\t\treturn new SecurityGrpcExceptionHandler();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(GrpcServerFactory.class)\n\t@EnableGlobalAuthentication\n\tstatic class GrpcNativeSecurityConfigurerConfiguration {\n\n\t\t@Bean\n\t\tGrpcSecurity grpcSecurity(ApplicationContext context, ObjectPostProcessor<Object> objectPostProcessor,\n\t\t\t\tAuthenticationConfiguration authenticationConfiguration) {\n\t\t\tAuthenticationManagerBuilder authenticationManagerBuilder = authenticationConfiguration\n\t\t\t\t.authenticationManagerBuilder(objectPostProcessor, context);\n\t\t\tauthenticationManagerBuilder\n\t\t\t\t.parentAuthenticationManager(authenticationConfiguration.getAuthenticationManager());\n\t\t\treturn new GrpcSecurity(objectPostProcessor, authenticationManagerBuilder, context);\n\t\t}\n\n\t}\n\n\t@ConditionalOnBean({ GrpcServletRegistration.class, SecurityFilterChain.class })\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GrpcServletSecurityConfigurerConfiguration {\n\n\t\t@Bean\n\t\t@GlobalServerInterceptor\n\t\tSecurityContextServerInterceptor securityContextInterceptor() {\n\t\t\treturn new SecurityContextServerInterceptor();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tGrpcServerExecutorProvider grpcServerExecutorProvider() {\n\t\t\treturn () -> new DelegatingSecurityContextExecutor(GrpcUtil.SHARED_CHANNEL_EXECUTOR.create());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = \"io.grpc.kotlin.CoroutineContextServerInterceptor\")\n\tstatic class GrpcServerCoroutineStubConfiguration {\n\n\t\t@Bean\n\t\t@GlobalServerInterceptor\n\t\t@ConditionalOnMissingBean\n\t\tCoroutineSecurityContextInterceptor coroutineSecurityContextInterceptor() {\n\t\t\treturn new CoroutineSecurityContextInterceptor();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for gRPC server security.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/web/reactive/GrpcRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security.web.reactive;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.grpc.server.autoconfigure.security.web.servlet.GrpcRequest.GrpcServletRequestMatcher;\nimport org.springframework.boot.security.web.reactive.ApplicationContextServerWebExchangeMatcher;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Factory that can be used to create a {@link ServerWebExchangeMatcher} to match against\n * gRPC service locations.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic final class GrpcRequest {\n\n\tprivate GrpcRequest() {\n\t}\n\n\t/**\n\t * Returns a matcher that includes all gRPC services. The\n\t * {@link GrpcReactiveRequestMatcher#excluding(String...) excluding} method can be\n\t * used to remove specific services by name if required. For example:\n\t *\n\t * <pre class=\"code\">\n\t * GrpcReactiveRequest.toAnyService().excluding(\"my-service\")\n\t * </pre>\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic static GrpcReactiveRequestMatcher toAnyService() {\n\t\treturn new GrpcReactiveRequestMatcher(Collections.emptySet());\n\t}\n\n\t/**\n\t * The matcher used to match against service locations.\n\t */\n\tpublic static final class GrpcReactiveRequestMatcher\n\t\t\textends ApplicationContextServerWebExchangeMatcher<GrpcServiceDiscoverer> {\n\n\t\tprivate static final ServerWebExchangeMatcher EMPTY_MATCHER = (exchange) -> MatchResult.notMatch();\n\n\t\tprivate final Set<String> excludes;\n\n\t\tprivate volatile @Nullable ServerWebExchangeMatcher delegate;\n\n\t\tprivate GrpcReactiveRequestMatcher(Set<String> excludes) {\n\t\t\tsuper(GrpcServiceDiscoverer.class);\n\t\t\tthis.excludes = excludes;\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link GrpcServletRequestMatcher} based on this one but excluding\n\t\t * the specified services.\n\t\t * @param services additional services to exclude\n\t\t * @return a new {@link GrpcServletRequestMatcher}\n\t\t */\n\t\tpublic GrpcReactiveRequestMatcher excluding(String... services) {\n\t\t\treturn excluding(Set.of(services));\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link GrpcServletRequestMatcher} based on this one but excluding\n\t\t * the specified services.\n\t\t * @param services additional service names to exclude\n\t\t * @return a new {@link GrpcServletRequestMatcher}\n\t\t */\n\t\tpublic GrpcReactiveRequestMatcher excluding(Collection<String> services) {\n\t\t\tAssert.notNull(services, \"'services' must not be null\");\n\t\t\tSet<String> excludes = new LinkedHashSet<>(this.excludes);\n\t\t\texcludes.addAll(services);\n\t\t\treturn new GrpcReactiveRequestMatcher(excludes);\n\t\t}\n\n\t\t@Override\n\t\tprotected void initialized(Supplier<GrpcServiceDiscoverer> context) {\n\t\t\tthis.delegate = createDelegate(context.get());\n\n\t\t}\n\n\t\tprivate ServerWebExchangeMatcher createDelegate(GrpcServiceDiscoverer serviceDiscoverer) {\n\t\t\tList<ServerWebExchangeMatcher> delegateMatchers = getDelegateMatchers(serviceDiscoverer);\n\t\t\treturn (!CollectionUtils.isEmpty(delegateMatchers)) ? new OrServerWebExchangeMatcher(delegateMatchers)\n\t\t\t\t\t: EMPTY_MATCHER;\n\t\t}\n\n\t\tprivate List<ServerWebExchangeMatcher> getDelegateMatchers(GrpcServiceDiscoverer serviceDiscoverer) {\n\t\t\treturn getPatterns(serviceDiscoverer).map(this::getDelegateMatcher).toList();\n\t\t}\n\n\t\tprivate Stream<String> getPatterns(GrpcServiceDiscoverer serviceDiscoverer) {\n\t\t\treturn serviceDiscoverer.listServiceNames().stream().filter(this::isExcluded).map(this::getPath);\n\t\t}\n\n\t\tprivate boolean isExcluded(String service) {\n\t\t\treturn this.excludes.stream().noneMatch((candidate) -> candidate.equals(service));\n\t\t}\n\n\t\tprivate String getPath(String service) {\n\t\t\treturn \"/\" + service + \"/**\";\n\t\t}\n\n\t\tprivate ServerWebExchangeMatcher getDelegateMatcher(String path) {\n\t\t\tAssert.hasText(path, \"'path' must not be empty\");\n\t\t\treturn new PathPatternParserServerWebExchangeMatcher(path);\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<MatchResult> matches(ServerWebExchange exchange, Supplier<GrpcServiceDiscoverer> context) {\n\t\t\tAssert.state(this.delegate != null, \"'delegate' must not be null\");\n\t\t\treturn this.delegate.matches(exchange);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/web/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for gRPC web security when using a reactive stack.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server.autoconfigure.security.web.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/web/servlet/GrpcRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security.web.servlet;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.security.web.util.matcher.OrRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Factory that can be used to create a {@link RequestMatcher} to match against gRPC\n * service locations.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic final class GrpcRequest {\n\n\tprivate static final RequestMatcher EMPTY_MATCHER = (request) -> false;\n\n\tprivate static final GrpcServletRequestMatcher TO_ANY_SERVICE = new GrpcServletRequestMatcher(\n\t\t\tCollections.emptySet());\n\n\tprivate GrpcRequest() {\n\t}\n\n\t/**\n\t * Returns a matcher that includes all gRPC services. The\n\t * {@link GrpcServletRequestMatcher#excluding(String...) excluding} method can be used\n\t * to remove specific services by name if required. For example:\n\t *\n\t * <pre class=\"code\">\n\t * GrpcServletRequest.toAnyService().excluding(\"my-service\")\n\t * </pre>\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static GrpcServletRequestMatcher toAnyService() {\n\t\treturn TO_ANY_SERVICE;\n\t}\n\n\t/**\n\t * The matcher used to match against service locations.\n\t */\n\tpublic static final class GrpcServletRequestMatcher\n\t\t\textends ApplicationContextRequestMatcher<GrpcServiceDiscoverer> {\n\n\t\tprivate final Set<String> excludes;\n\n\t\tprivate volatile @Nullable RequestMatcher delegate;\n\n\t\tprivate GrpcServletRequestMatcher(Set<String> exclusions) {\n\t\t\tsuper(GrpcServiceDiscoverer.class);\n\t\t\tthis.excludes = exclusions;\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link GrpcServletRequestMatcher} based on this one but excluding\n\t\t * the specified services.\n\t\t * @param services additional services to exclude\n\t\t * @return a new {@link GrpcServletRequestMatcher}\n\t\t */\n\t\tpublic GrpcServletRequestMatcher excluding(String... services) {\n\t\t\treturn excluding(Set.of(services));\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link GrpcServletRequestMatcher} based on this one but excluding\n\t\t * the specified services.\n\t\t * @param services additional service names to exclude\n\t\t * @return a new {@link GrpcServletRequestMatcher}\n\t\t */\n\t\tpublic GrpcServletRequestMatcher excluding(Collection<String> services) {\n\t\t\tAssert.notNull(services, \"'services' must not be null\");\n\t\t\tSet<String> excludes = new LinkedHashSet<>(this.excludes);\n\t\t\texcludes.addAll(services);\n\t\t\treturn new GrpcServletRequestMatcher(excludes);\n\t\t}\n\n\t\t@Override\n\t\tprotected void initialized(Supplier<GrpcServiceDiscoverer> context) {\n\t\t\tthis.delegate = createDelegate(context.get());\n\t\t}\n\n\t\tprivate RequestMatcher createDelegate(GrpcServiceDiscoverer grpcServiceDiscoverer) {\n\t\t\tList<RequestMatcher> delegateMatchers = getDelegateMatchers(grpcServiceDiscoverer);\n\t\t\treturn (!CollectionUtils.isEmpty(delegateMatchers)) ? new OrRequestMatcher(delegateMatchers)\n\t\t\t\t\t: EMPTY_MATCHER;\n\t\t}\n\n\t\tprivate List<RequestMatcher> getDelegateMatchers(GrpcServiceDiscoverer serviceDiscoverer) {\n\t\t\treturn getPatterns(serviceDiscoverer).map(this::getDelegateMatcher).toList();\n\t\t}\n\n\t\tprivate Stream<String> getPatterns(GrpcServiceDiscoverer serviceDiscoverer) {\n\t\t\treturn serviceDiscoverer.listServiceNames().stream().filter(this::isExcluded).map(this::getPath);\n\t\t}\n\n\t\tprivate boolean isExcluded(String service) {\n\t\t\treturn this.excludes.stream().noneMatch((candidate) -> candidate.equals(service));\n\t\t}\n\n\t\tprivate String getPath(String service) {\n\t\t\treturn \"/\" + service + \"/**\";\n\t\t}\n\n\t\tprivate RequestMatcher getDelegateMatcher(String path) {\n\t\t\tAssert.hasText(path, \"'path' must not be empty\");\n\t\t\treturn PathPatternRequestMatcher.withDefaults().matcher(path);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matches(HttpServletRequest request, Supplier<GrpcServiceDiscoverer> context) {\n\t\t\tAssert.state(this.delegate != null, \"'delegate' must not be null\");\n\t\t\treturn this.delegate.matches(request);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/security/web/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for gRPC web security when using a servlet stack.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server.autoconfigure.security.web.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/GrpcServerHealth.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.BiConsumer;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport io.grpc.protobuf.services.HealthStatusManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.util.Assert;\n\n/**\n * Provides health information for a gRPC server that can be used to update a\n * {@link HealthStatusManager}.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic class GrpcServerHealth {\n\n\tprivate final HealthContributorRegistry registry;\n\n\tprivate final @Nullable ReactiveHealthContributorRegistry fallbackRegistry;\n\n\tprivate final HealthCheckedGrpcComponents components;\n\n\t/**\n\t * Create a new {@link GrpcServerHealth} instance.\n\t * @param registry the health contributor registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @param components the components used to provide the server health\n\t */\n\tpublic GrpcServerHealth(HealthContributorRegistry registry,\n\t\t\t@Nullable ReactiveHealthContributorRegistry fallbackRegistry, HealthCheckedGrpcComponents components) {\n\t\tAssert.notNull(registry, \"'registry' must not be null\");\n\t\tAssert.notNull(components, \"'components' must not be null\");\n\t\tthis.registry = registry;\n\t\tthis.fallbackRegistry = fallbackRegistry;\n\t\tthis.components = components;\n\t}\n\n\tpublic void update(HealthStatusManager manager) {\n\t\tupdate(manager::setStatus);\n\t}\n\n\tpublic void update(BiConsumer<String, ServingStatus> updater) {\n\t\tCache cache = new Cache();\n\t\tHealthCheckedGrpcComponent serverComponent = this.components.getServer();\n\t\tif (serverComponent != null) {\n\t\t\tupdater.accept(\"\", getServingStatus(cache, serverComponent));\n\t\t}\n\t\tfor (String serviceName : this.components.getServiceNames()) {\n\t\t\tHealthCheckedGrpcComponent serviceComponent = this.components.getService(serviceName);\n\t\t\tif (!serviceName.isEmpty() && serviceComponent != null) {\n\t\t\t\tupdater.accept(serviceName, getServingStatus(cache, serviceComponent));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ServingStatus getServingStatus(Cache cache, HealthCheckedGrpcComponent component) {\n\t\tSet<Status> statuses = new LinkedHashSet<>();\n\t\tcollectStatuses(cache, component, statuses, this.registry, \"\");\n\t\tif (this.fallbackRegistry != null) {\n\t\t\tcollectStatuses(cache, component, statuses, this.fallbackRegistry.asHealthContributors(), \"\");\n\t\t}\n\t\tStatus status = component.getStatusAggregator().getAggregateStatus(statuses);\n\t\treturn component.getStatusMapper().getServingStatus(status);\n\t}\n\n\tprivate void collectStatuses(Cache cache, HealthCheckedGrpcComponent component, Set<Status> statuses,\n\t\t\tHealthContributors contributors, String prefix) {\n\t\tfor (HealthContributors.Entry entry : contributors) {\n\t\t\tString name = (prefix.isEmpty()) ? entry.name() : prefix + \"/\" + entry.name();\n\t\t\tif (entry.contributor() instanceof CompositeHealthContributor composite) {\n\t\t\t\tcollectStatuses(cache, component, statuses, composite, name);\n\t\t\t}\n\t\t\telse if (component.isMember(name)) {\n\t\t\t\tHealth health = cache.getHealth(name, (HealthIndicator) entry.contributor());\n\t\t\t\tif (health != null) {\n\t\t\t\t\tstatuses.add(health.getStatus());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic class Cache {\n\n\t\tprivate final Map<String, Health> health = new HashMap<>();\n\n\t\t@Nullable Health getHealth(String name, HealthIndicator indicator) {\n\t\t\treturn this.health.computeIfAbsent(name, (key) -> indicator.health(false));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/HealthCheckedGrpcComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\n/**\n * A single gRPC component that can be checked for health.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic interface HealthCheckedGrpcComponent {\n\n\t/**\n\t * Returns {@code true} if the given health contributor is a member of this component.\n\t * @param healthContributorName the contributor name\n\t * @return {@code true} if the contributor is a member\n\t */\n\tboolean isMember(String healthContributorName);\n\n\t/**\n\t * Returns the status aggregator that should be used for this component.\n\t * @return the status aggregator\n\t */\n\tStatusAggregator getStatusAggregator();\n\n\t/**\n\t * Returns the {@link StatusMapper} that should be used for this component.\n\t * @return the status mapper\n\t */\n\tStatusMapper getStatusMapper();\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/HealthCheckedGrpcComponents.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A collection of {@link HealthCheckedGrpcComponent components} used to check the health\n * of a gRPC server.\n *\n * @author Phillip Webb\n * @since 4.1.0\n * @see GrpcServerHealth\n */\npublic interface HealthCheckedGrpcComponents {\n\n\t/**\n\t * Return the component that represents the overall server health or {@code null} if\n\t * no overall health should be reported.\n\t * @return the server component or {@code null}\n\t */\n\t@Nullable HealthCheckedGrpcComponent getServer();\n\n\t/**\n\t * Return the names of the services that contribute health checks.\n\t * @return the service names\n\t */\n\tSet<String> getServiceNames();\n\n\t/**\n\t * Return the component for the service with the specified name or {@code null} if the\n\t * name is not known.\n\t * @param serviceName the name of the service\n\t * @return the service component or {@code null}\n\t */\n\t@Nullable HealthCheckedGrpcComponent getService(String serviceName);\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/SimpleServingStatusMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.lang.Contract;\n\n/**\n * Simple {@link StatusMapper} backed by map of {@link Status#getCode() status code} to\n * {@link ServingStatus}.\n *\n * @author Phillip Webb\n */\nclass SimpleServingStatusMapper implements StatusMapper {\n\n\tstatic final SimpleServingStatusMapper DEFAULT_MAPPINGS;\n\tstatic {\n\t\tMap<String, ServingStatus> mappings = new HashMap<>();\n\t\tmappings.put(Status.DOWN.getCode(), ServingStatus.NOT_SERVING);\n\t\tmappings.put(Status.OUT_OF_SERVICE.getCode(), ServingStatus.NOT_SERVING);\n\t\tmappings.put(Status.UNKNOWN.getCode(), ServingStatus.UNKNOWN);\n\t\tDEFAULT_MAPPINGS = new SimpleServingStatusMapper(mappings);\n\t}\n\n\tprivate final Map<String, ServingStatus> mappings;\n\n\tSimpleServingStatusMapper(Map<String, ServingStatus> mappings) {\n\t\tthis.mappings = getUniformMappings(mappings);\n\t}\n\n\t@Override\n\tpublic ServingStatus getServingStatus(Status status) {\n\t\tString code = getUniformCode(status.getCode());\n\t\treturn this.mappings.getOrDefault(code, ServingStatus.SERVING);\n\t}\n\n\tprivate static Map<String, ServingStatus> getUniformMappings(Map<String, ServingStatus> mappings) {\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\tfor (Map.Entry<String, ServingStatus> entry : mappings.entrySet()) {\n\t\t\tString code = getUniformCode(entry.getKey());\n\t\t\tif (code != null) {\n\t\t\t\tresult.putIfAbsent(code, entry.getValue());\n\t\t\t}\n\t\t}\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate static @Nullable String getUniformCode(@Nullable String code) {\n\t\treturn (code != null) ? code.codePoints()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)\n\t\t\t.toString() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/SimpleStatusAggregator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.lang.Contract;\n\n/**\n * {@link StatusAggregator} backed by an ordered status list.\n *\n * @author Phillip Webb\n */\nclass SimpleStatusAggregator implements StatusAggregator {\n\n\tstatic final SimpleStatusAggregator DEFAULT_ORDER = new SimpleStatusAggregator(\n\t\t\tStatus.DEFAULT_ORDER.stream().map(Status::getCode));\n\n\tprivate final List<String> order;\n\n\tprivate final Comparator<Status> comparator = Comparator.comparingInt(this::orderIndex)\n\t\t.thenComparing(Status::getCode);\n\n\tSimpleStatusAggregator(Stream<String> order) {\n\t\tthis.order = order.map(SimpleStatusAggregator::getUniformCode).toList();\n\t}\n\n\t@Override\n\tpublic Status getAggregateStatus(Set<Status> statuses) {\n\t\treturn statuses.stream().filter(this::contains).min(this.comparator).orElse(Status.UNKNOWN);\n\t}\n\n\tprivate boolean contains(Status status) {\n\t\treturn this.order.contains(getUniformCode(status));\n\t}\n\n\tprivate int orderIndex(Status status) {\n\t\treturn this.order.indexOf(getUniformCode(status));\n\t}\n\n\tprivate static @Nullable String getUniformCode(Status status) {\n\t\treturn getUniformCode(status.getCode());\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate static @Nullable String getUniformCode(@Nullable String code) {\n\t\treturn (code != null) ? code.codePoints()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)\n\t\t\t.toString() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/StatusAggregator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Strategy used to aggregate {@link Status} instances.\n * <p>\n * This is required in order to combine subsystem states expressed through\n * {@link Health#getStatus()} into one state for the gRPC health.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface StatusAggregator {\n\n\t/**\n\t * Return the aggregate status for the given set of statuses.\n\t * @param statuses the statuses to aggregate\n\t * @return the aggregate status\n\t */\n\tdefault Status getAggregateStatus(Status... statuses) {\n\t\treturn getAggregateStatus(new LinkedHashSet<>(Arrays.asList(statuses)));\n\t}\n\n\t/**\n\t * Return the aggregate status for the given set of statuses.\n\t * @param statuses the statuses to aggregate\n\t * @return the aggregate status\n\t */\n\tStatus getAggregateStatus(Set<Status> statuses);\n\n\t/**\n\t * Return a {@link StatusAggregator} backed by the given ordered status list.\n\t * @param order the status order\n\t * @return a {@link StatusAggregator} instance or {@link #getDefault()} if no order is\n\t * provided\n\t */\n\tstatic StatusAggregator of(Status... order) {\n\t\treturn (!ObjectUtils.isEmpty(order)) ? new SimpleStatusAggregator(Arrays.stream(order).map(Status::getCode))\n\t\t\t\t: getDefault();\n\t}\n\n\t/**\n\t * Return a {@link StatusAggregator} backed by the given ordered status list.\n\t * @param order the status order\n\t * @return a {@link StatusAggregator} instance or {@link #getDefault()} if no order is\n\t * provided\n\t */\n\tstatic StatusAggregator of(String... order) {\n\t\treturn (!ObjectUtils.isEmpty(order)) ? new SimpleStatusAggregator(Arrays.stream(order)) : getDefault();\n\t}\n\n\t/**\n\t * Return a {@link StatusAggregator} backed by the given ordered status list.\n\t * @param order the status order\n\t * @return a {@link StatusAggregator} instance or {@link #getDefault()} if no order is\n\t * provided\n\t */\n\tstatic StatusAggregator of(List<String> order) {\n\t\treturn (!ObjectUtils.isEmpty(order)) ? new SimpleStatusAggregator(order.stream()) : getDefault();\n\t}\n\n\t/**\n\t * Return {@link StatusAggregator} instance using default ordering rules.\n\t * @return a {@code StatusAggregator} with default ordering rules.\n\t */\n\tstatic StatusAggregator getDefault() {\n\t\treturn SimpleStatusAggregator.DEFAULT_ORDER;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/StatusMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.Map;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Strategy used to map a {@link Status health status} to a gRPC {@link ServingStatus}.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface StatusMapper {\n\n\t/**\n\t * Return the gRPC serving status that corresponds to the given {@link Status health\n\t * status}.\n\t * @param status the health status to map\n\t * @return the corresponding gRPC serving status\n\t */\n\tServingStatus getServingStatus(Status status);\n\n\t/**\n\t * Create a new {@link StatusMapper} with the specified mappings.\n\t * @param mappings the mappings to use or {@code null} to use the default mappings\n\t * @return a {@link StatusMapper} or {@link #getDefault()}\n\t */\n\tstatic StatusMapper of(@Nullable Map<String, ServingStatus> mappings) {\n\t\treturn CollectionUtils.isEmpty(mappings) ? SimpleServingStatusMapper.DEFAULT_MAPPINGS\n\t\t\t\t: new SimpleServingStatusMapper(mappings);\n\t}\n\n\t/**\n\t * Return an {@link StatusMapper} instance using default mappings.\n\t * @return a mapper using default mappings\n\t */\n\tstatic StatusMapper getDefault() {\n\t\treturn SimpleServingStatusMapper.DEFAULT_MAPPINGS;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for gRPC server health checks.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring gRPC server support classes.\n */\n@NullMarked\npackage org.springframework.boot.grpc.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.grpc.server.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable gRPC server auto-configuration.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.grpc.server.factory.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable gRPC server factory bean auto-configuration.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.grpc.server.observation.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Observations on the server.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.grpc.server.reflection.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Reflection on the gRPC server.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration\norg.springframework.boot.grpc.server.autoconfigure.GrpcServerObservationAutoConfiguration\norg.springframework.boot.grpc.server.autoconfigure.GrpcServerServicesAutoConfiguration\norg.springframework.boot.grpc.server.autoconfigure.health.GrpcServerHealthAutoConfiguration\norg.springframework.boot.grpc.server.autoconfigure.health.GrpcServerHealthSchedulerAutoConfiguration\norg.springframework.boot.grpc.server.autoconfigure.security.GrpcServerOAuth2ResourceServerAutoConfiguration\norg.springframework.boot.grpc.server.autoconfigure.security.GrpcServerSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer=\\\norg.springframework.boot.grpc.server.autoconfigure.security.GrpcDisableCsrfHttpConfigurer\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/GrpcServletRegistrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerInterceptor;\nimport io.grpc.ServerServiceDefinition;\nimport io.grpc.servlet.jakarta.GrpcServlet;\nimport io.grpc.servlet.jakarta.ServletServerBuilder;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration.Dynamic;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.grpc.server.service.GrpcServiceInfo;\nimport org.springframework.grpc.server.service.GrpcServiceSpec;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link GrpcServletRegistration}.\n *\n * @author Phillip Webb\n */\nclass GrpcServletRegistrationTests {\n\n\tprivate final GrpcServiceConfigurer serviceConfigurer = mock();\n\n\tprivate final GrpcServiceDiscoverer serviceDiscoverer = mock();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenServiceDiscovererIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new GrpcServletRegistration(null, this.serviceConfigurer))\n\t\t\t.withMessage(\"'serviceDiscoverer' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenServiceConfigurerIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new GrpcServletRegistration(this.serviceDiscoverer, null))\n\t\t\t.withMessage(\"'serviceConfigurer' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenServerBuilderCustomizerIsNullDoesNotApplyCustomization() {\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> new GrpcServletRegistration(this.serviceDiscoverer, this.serviceConfigurer, null));\n\t}\n\n\t@Test\n\tvoid createWhenServerBuilderCustomizerIsNotNullAppliesCustomization() {\n\t\tConsumer<ServletServerBuilder> serverBuilderCustomizer = mock();\n\t\tnew GrpcServletRegistration(this.serviceDiscoverer, this.serviceConfigurer, serverBuilderCustomizer);\n\t\tthen(serverBuilderCustomizer).should().accept(any(ServletServerBuilder.class));\n\t}\n\n\t@Test\n\tvoid addRegistrationAddsBuiltServlet() {\n\t\tGrpcServletRegistration registration = new GrpcServletRegistration(this.serviceDiscoverer,\n\t\t\t\tthis.serviceConfigurer);\n\t\tServletContext servletContext = mock();\n\t\tDynamic result = mock();\n\t\tgiven(servletContext.addServlet(eq(\"grpcServlet\"), any(GrpcServlet.class))).willReturn(result);\n\t\tassertThat(registration.addRegistration(\"test\", servletContext)).isEqualTo(result);\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasServicesRegistersAndAddsUrlMappingsBasedOnDescriptorName() throws ServletException {\n\t\tBindableService service1 = mock(BindableService.class);\n\t\tServerServiceDefinition serviceDefinition1 = ServerServiceDefinition.builder(\"s1\").build();\n\t\tgiven(service1.bindService()).willReturn(serviceDefinition1);\n\t\tGrpcServiceInfo info1 = new GrpcServiceInfo(emptyServiceInterceptors(), new String[0], false);\n\t\tBindableService service2 = mock(BindableService.class);\n\t\tServerServiceDefinition serviceDefinition2 = ServerServiceDefinition.builder(\"s2\").build();\n\t\tgiven(service2.bindService()).willReturn(serviceDefinition2);\n\t\tGrpcServiceInfo info2 = new GrpcServiceInfo(emptyServiceInterceptors(), new String[0], false);\n\t\tList<GrpcServiceSpec> specs = new ArrayList<>();\n\t\tspecs.add(new GrpcServiceSpec(service1, info1));\n\t\tspecs.add(new GrpcServiceSpec(service2, info2));\n\t\tgiven(this.serviceDiscoverer.findServices()).willReturn(specs);\n\t\tgiven(this.serviceConfigurer.configure(any(GrpcServiceSpec.class), eq(null))).willAnswer((invocation) -> {\n\t\t\tGrpcServiceSpec spec = invocation.getArgument(0, GrpcServiceSpec.class);\n\t\t\treturn spec.service().bindService();\n\t\t});\n\t\tGrpcServletRegistration registration = new GrpcServletRegistration(this.serviceDiscoverer,\n\t\t\t\tthis.serviceConfigurer);\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tDynamic result = mock(Dynamic.class);\n\t\tgiven(servletContext.addServlet(eq(\"grpcServlet\"), any(GrpcServlet.class))).willReturn(result);\n\t\tregistration.onStartup(servletContext);\n\t\tthen(result).should().addMapping(\"/s1/*\", \"/s2/*\");\n\t}\n\n\t@Test\n\tvoid onStartupWhenHasNoServicesDoesNotAddUrlMappings() throws ServletException {\n\t\tgiven(this.serviceDiscoverer.findServices()).willReturn(Collections.emptyList());\n\t\tgiven(this.serviceConfigurer.configure(any(GrpcServiceSpec.class), eq(null))).willAnswer((invocation) -> {\n\t\t\tGrpcServiceSpec spec = invocation.getArgument(0, GrpcServiceSpec.class);\n\t\t\treturn spec.service().bindService();\n\t\t});\n\t\tGrpcServletRegistration registration = new GrpcServletRegistration(this.serviceDiscoverer,\n\t\t\t\tthis.serviceConfigurer);\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tDynamic result = mock(Dynamic.class);\n\t\tgiven(servletContext.addServlet(eq(\"grpcServlet\"), any(GrpcServlet.class))).willReturn(result);\n\t\tregistration.onStartup(servletContext);\n\t\tthen(result).should(never()).addMapping();\n\t}\n\n\t@Test\n\tvoid getDescriptionReturnsDeducedServletName() {\n\t\tGrpcServletRegistration registration = new GrpcServletRegistration(this.serviceDiscoverer,\n\t\t\t\tthis.serviceConfigurer);\n\t\tassertThat(registration.getDescription()).isEqualTo(\"grpcServlet\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Class<? extends ServerInterceptor>[] emptyServiceInterceptors() {\n\t\treturn (Class<? extends ServerInterceptor>[]) new Class<?>[] {};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerServiceDefinition;\nimport io.grpc.ServiceDescriptor;\nimport io.grpc.inprocess.InProcessServerBuilder;\nimport io.grpc.internal.GrpcUtil;\nimport io.grpc.netty.NettyServerBuilder;\nimport io.grpc.servlet.jakarta.GrpcServlet;\nimport io.grpc.servlet.jakarta.ServletServerBuilder;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;\nimport org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\nimport org.springframework.grpc.server.NettyGrpcServerFactory;\nimport org.springframework.grpc.server.ServerBuilderCustomizer;\nimport org.springframework.grpc.server.ShadedNettyGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.service.DefaultGrpcServiceDiscoverer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Andrey Litvitski\n * @author Phillip Webb\n */\nclass GrpcServerAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfigurations = AutoConfigurations\n\t\t.of(GrpcServerAutoConfiguration.class, SslAutoConfiguration.class);\n\n\tprivate final BindableService service = mock();\n\n\tprivate final ServerServiceDefinition serviceDefinition = ServerServiceDefinition.builder(\"my-service\").build();\n\n\tprivate ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(autoConfigurations)\n\t\t.with(this::noOpLifecycleBeans)\n\t\t.with(this::serviceBean);\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tgiven(this.service.bindService()).willReturn(this.serviceDefinition);\n\t}\n\n\t@Test\n\tvoid whenGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BindableService.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenSpringGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerFactory.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenNoBindableServicesRegisteredAutoConfigurationIsSkipped() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertySetFalseThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertyNotSetThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GrpcServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertySetTrueThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedGrpcServiceDiscovererDoesNotAutoConfigureBean() {\n\t\tGrpcServiceDiscoverer customGrpcServiceDiscoverer = mock(GrpcServiceDiscoverer.class);\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.with(this::noOpLifecycleBeans)\n\t\t\t.withBean(\"customGrpcServiceDiscoverer\", GrpcServiceDiscoverer.class, () -> customGrpcServiceDiscoverer)\n\t\t\t.withPropertyValues(\"spring.grpc.server.port=0\")\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcServiceDiscoverer.class)\n\t\t\t\t.isSameAs(customGrpcServiceDiscoverer));\n\t}\n\n\t@Test\n\tvoid grpcServiceDiscovererAutoConfiguredAsExpected() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.with(this::serviceBean)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcServiceDiscoverer.class)\n\t\t\t\t.isInstanceOf(DefaultGrpcServiceDiscoverer.class));\n\t}\n\n\t@Test\n\tvoid serverBuilderCustomizersAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.withUserConfiguration(ServerBuilderCustomizersConfig.class)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcServerBuilderCustomizers.class)\n\t\t\t\t.extracting(\"customizers\", InstanceOfAssertFactories.list(ServerBuilderCustomizer.class))\n\t\t\t\t.contains(ServerBuilderCustomizersConfig.bar, ServerBuilderCustomizersConfig.foo));\n\t}\n\n\t@Test\n\tvoid customizersAreAppliedToNettyServer() {\n\t\tAtomicReference<NettyServerBuilder> applied = new AtomicReference<>();\n\t\tServerBuilderCustomizer<NettyServerBuilder> customizer = applied::set;\n\t\tthis.contextRunner.withBean(ServerBuilderCustomizer.class, () -> customizer)\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(GrpcServerFactory.class).createServer();\n\t\t\t\tassertThat(applied.get()).isInstanceOf(NettyServerBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizersAreAppliedToShadedNettyServer() {\n\t\tAtomicReference<io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder> applied = new AtomicReference<>();\n\t\tServerBuilderCustomizer<io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder> customizer = applied::set;\n\t\tthis.contextRunner.withBean(ServerBuilderCustomizer.class, () -> customizer)\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(GrpcServerFactory.class).createServer();\n\t\t\t\tassertThat(applied.get()).isInstanceOf(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizersAreAppliedToInProcessServer() {\n\t\tAtomicReference<InProcessServerBuilder> applied = new AtomicReference<>();\n\t\tServerBuilderCustomizer<InProcessServerBuilder> customizer = applied::set;\n\t\tthis.contextRunner.withBean(ServerBuilderCustomizer.class, () -> customizer)\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.withPropertyValues(\"spring.grpc.server.inprocess.name=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(GrpcServerFactory.class).createServer();\n\t\t\t\tassertThat(applied.get()).isInstanceOf(InProcessServerBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedServerFactoryDoesNotAutoConfigureBean() {\n\t\tGrpcServerFactory customServerFactory = mock(GrpcServerFactory.class);\n\t\tthis.contextRunner.withBean(\"customServerFactory\", GrpcServerFactory.class, () -> customServerFactory)\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcServerFactory.class).isSameAs(customServerFactory));\n\t}\n\n\t@Test\n\tvoid userDefinedServerFactoryWithInProcessServerFactory() {\n\t\tGrpcServerFactory customServerFactory = mock(GrpcServerFactory.class);\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.inprocess.name=foo\")\n\t\t\t.withBean(\"customServerFactory\", GrpcServerFactory.class, () -> customServerFactory)\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcServerFactory.class)\n\t\t\t\t.containsOnlyKeys(\"customServerFactory\", \"inProcessGrpcServerFactory\"));\n\t}\n\n\t@Test\n\tvoid whenShadedAndNonShadedNettyOnClasspathShadedNettyFactoryIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(GrpcServerFactory.class)\n\t\t\t.isInstanceOf(ShadedNettyGrpcServerFactory.class));\n\t}\n\n\t@Test\n\tvoid shadedNettyFactoryWithInProcessServerFactory() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.inprocess.name=foo\")\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcServerFactory.class)\n\t\t\t\t.containsOnlyKeys(\"shadedNettyGrpcServerFactory\", \"inProcessGrpcServerFactory\"));\n\t}\n\n\t@Test\n\tvoid whenOnlyNonShadedNettyOnClasspathNonShadedNettyFactoryIsAutoConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcServerFactory.class)\n\t\t\t\t.isInstanceOf(NettyGrpcServerFactory.class));\n\t}\n\n\t@Test\n\tvoid nonShadedNettyFactoryWithInProcessServerFactory() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.withPropertyValues(\"spring.grpc.server.inprocess.name=foo\")\n\t\t\t.run((context) -> assertThat(context).getBeans(GrpcServerFactory.class)\n\t\t\t\t.containsOnlyKeys(\"nettyGrpcServerFactory\", \"inProcessGrpcServerFactory\"));\n\t}\n\n\t@Test\n\tvoid whenShadedNettyAndNettyNotOnClasspathNoServerFactoryIsAutoConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerFactory.class));\n\t}\n\n\t@Test\n\tvoid noServerFactoryWithInProcessServerFactory() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.withPropertyValues(\"spring.grpc.server.inprocess.name=foo\")\n\t\t\t.run((context) -> assertThat(context).getBean(GrpcServerFactory.class)\n\t\t\t\t.isInstanceOf(InProcessGrpcServerFactory.class));\n\t}\n\n\t@Test\n\tvoid shadedNettyServerFactoryAutoConfiguredWithCustomLifecycle() {\n\t\tGrpcServerLifecycle customServerLifecycle = mock(GrpcServerLifecycle.class);\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.with(this::serviceBean)\n\t\t\t.withBean(\"shadedNettyGrpcServerLifecycle\", GrpcServerLifecycle.class, () -> customServerLifecycle)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBean(GrpcServerFactory.class).isInstanceOf(ShadedNettyGrpcServerFactory.class);\n\t\t\t\tassertThat(context).getBean(\"shadedNettyGrpcServerLifecycle\", GrpcServerLifecycle.class)\n\t\t\t\t\t.isSameAs(customServerLifecycle);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid nettyServerFactoryAutoConfiguredWithCustomLifecycle() {\n\t\tGrpcServerLifecycle customServerLifecycle = mock(GrpcServerLifecycle.class);\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.with(this::serviceBean)\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.withBean(\"nettyGrpcServerLifecycle\", GrpcServerLifecycle.class, () -> customServerLifecycle)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBean(GrpcServerFactory.class).isInstanceOf(NettyGrpcServerFactory.class);\n\t\t\t\tassertThat(context).getBean(\"nettyGrpcServerLifecycle\", GrpcServerLifecycle.class)\n\t\t\t\t\t.isSameAs(customServerLifecycle);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid inProcessServerFactoryAutoConfiguredWithCustomLifecycle() {\n\t\tGrpcServerLifecycle customServerLifecycle = mock(GrpcServerLifecycle.class);\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.with(this::serviceBean)\n\t\t\t.withPropertyValues(\"spring.grpc.server.inprocess.name=foo\")\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.withBean(\"inProcessGrpcServerLifecycle\", GrpcServerLifecycle.class, () -> customServerLifecycle)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBean(GrpcServerFactory.class).isInstanceOf(InProcessGrpcServerFactory.class);\n\t\t\t\tassertThat(context).getBean(\"inProcessGrpcServerLifecycle\", GrpcServerLifecycle.class)\n\t\t\t\t\t.isSameAs(customServerLifecycle);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shadedNettyServerFactoryAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.address=192.168.0.1\", \"spring.grpc.server.port=6160\")\n\t\t\t.run(assertThatServerIsConfigured(ShadedNettyGrpcServerFactory.class, \"192.168.0.1:6160\",\n\t\t\t\t\t\"shadedNettyGrpcServerLifecycle\"));\n\t}\n\n\t@Test\n\tvoid nettyServerFactoryAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.address=192.168.0.1\", \"spring.grpc.server.port=6160\")\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.run(assertThatServerIsConfigured(NettyGrpcServerFactory.class, \"192.168.0.1:6160\",\n\t\t\t\t\t\"nettyGrpcServerLifecycle\"));\n\t}\n\n\t@Test\n\tvoid serverFactoryAutoConfiguredInWebAppWhenServletDisabled() {\n\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.with(this::noOpLifecycleBeans)\n\t\t\t.with(this::serviceBean)\n\t\t\t.withPropertyValues(\"spring.grpc.server.address=192.168.0.1\")\n\t\t\t.withPropertyValues(\"spring.grpc.server.port=6160\")\n\t\t\t.withPropertyValues(\"spring.grpc.server.servlet.enabled=false\")\n\t\t\t.run(assertThatServerIsConfigured(ShadedNettyGrpcServerFactory.class, \"192.168.0.1:6160\",\n\t\t\t\t\t\"shadedNettyGrpcServerLifecycle\"));\n\t}\n\n\t@Test\n\tvoid inProcessServerFactoryAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.inprocess.name=foo\")\n\t\t\t.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class,\n\t\t\t\t\tio.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.run(assertThatServerIsConfigured(InProcessGrpcServerFactory.class, \"foo\", \"inProcessGrpcServerLifecycle\"));\n\t}\n\n\t@Test\n\tvoid nettyServerFactoryAutoConfiguredWithSsl() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.address=192.168.0.1\", \"spring.grpc.server.port=6160\",\n\t\t\t\t\"spring.grpc.server.ssl.bundle=ssltest\",\n\t\t\t\t\"spring.ssl.bundle.jks.ssltest.keystore.location=classpath:org/springframework/boot/grpc/server/autoconfigure/test.jks\",\n\t\t\t\t\"spring.ssl.bundle.jks.ssltest.keystore.password=secret\",\n\t\t\t\t\"spring.ssl.bundle.jks.ssltest.key.password=password\")\n\t\t\t.withClassLoader(new FilteredClassLoader(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class))\n\t\t\t.run(assertThatServerIsConfigured(NettyGrpcServerFactory.class, \"192.168.0.1:6160\",\n\t\t\t\t\t\"nettyGrpcServerLifecycle\"));\n\t}\n\n\tprivate ContextConsumer<? super ApplicationContextAssertProvider<?>> assertThatServerIsConfigured(\n\t\t\tClass<?> expectedServerFactoryType, String expectedAddress, String expectedLifecycleBeanName) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).getBean(GrpcServerFactory.class)\n\t\t\t\t.isInstanceOf(expectedServerFactoryType)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"address\", expectedAddress)\n\t\t\t\t.extracting(\"serviceList\", InstanceOfAssertFactories.list(ServerServiceDefinition.class))\n\t\t\t\t.singleElement()\n\t\t\t\t.extracting(ServerServiceDefinition::getServiceDescriptor)\n\t\t\t\t.extracting(ServiceDescriptor::getName)\n\t\t\t\t.isEqualTo(\"my-service\");\n\t\t\tassertThat(context).getBean(expectedLifecycleBeanName, GrpcServerLifecycle.class).isNotNull();\n\t\t};\n\t}\n\n\tprivate <R extends AbstractApplicationContextRunner<R, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> R serviceBean(\n\t\t\tR contextRunner) {\n\t\treturn contextRunner.withBean(BindableService.class, () -> this.service);\n\t}\n\n\tprivate <R extends AbstractApplicationContextRunner<R, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> R noOpLifecycleBeans(\n\t\t\tR contextRunner) {\n\t\treturn contextRunner.withBean(\"shadedNettyGrpcServerLifecycle\", GrpcServerLifecycle.class, Mockito::mock)\n\t\t\t.withBean(\"nettyGrpcServerLifecycle\", GrpcServerLifecycle.class, Mockito::mock)\n\t\t\t.withBean(\"inProcessGrpcServerLifecycle\", GrpcServerLifecycle.class, Mockito::mock);\n\t}\n\n\t@Nested\n\tclass ServletServerAutoConfigurationTests {\n\n\t\tprivate WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t\t.withConfiguration(autoConfigurations)\n\t\t\t.with(GrpcServerAutoConfigurationTests.this::serviceBean)\n\t\t\t.withPropertyValues(\"server.http2.enabled=true\");\n\n\t\t@Test\n\t\tvoid whenGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BindableService.class))\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServletGrpcServerConfiguration.class)\n\t\t\t\t\t.doesNotHaveBean(ServletRegistrationBean.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenSpringGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerFactory.class))\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServletGrpcServerConfiguration.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNoBindableServicesRegisteredAutoConfigurationIsSkipped() {\n\t\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServletGrpcServerConfiguration.class)\n\t\t\t\t\t.doesNotHaveBean(ServletRegistrationBean.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenGrpcServletNotOnClasspathAutoConfigurationIsSkipped() {\n\t\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServlet.class))\n\t\t\t\t.withPropertyValues(\"spring.grpc.server.port=0\")\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServletGrpcServerConfiguration.class)\n\t\t\t\t\t.doesNotHaveBean(ServletRegistrationBean.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenWebApplicationServletIsAutoConfigured() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(GrpcServletRegistration.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenServerBuilderCustomizerIsRegistered() {\n\t\t\tServerBuilderCustomizer<ServletServerBuilder> customizer = mock();\n\t\t\tthis.contextRunner.withBean(ServerBuilderCustomizer.class, () -> customizer)\n\t\t\t\t.run((context) -> then(customizer).should().customize(any(ServletServerBuilder.class)));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenMaxInboundMessageSizeIsSetThenItIsUsed() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.inbound.message.max-size=10KB\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(GrpcServletRegistration.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"servlet.servletAdapter.maxInboundMessageSize\",\n\t\t\t\t\t\t\tMath.toIntExact(DataSize.ofKilobytes(10).toBytes())));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenMaxInboundMessageSizeIsNotSetThenDefaultIsUsed() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(GrpcServletRegistration.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"servlet.servletAdapter.maxInboundMessageSize\",\n\t\t\t\t\t\tGrpcUtil.DEFAULT_MAX_MESSAGE_SIZE));\n\t\t}\n\n\t\t@Test\n\t\tvoid customizersAreAppliedToServletServer() {\n\t\t\tAtomicReference<ServletServerBuilder> applied = new AtomicReference<>();\n\t\t\tServerBuilderCustomizer<ServletServerBuilder> customizer = applied::set;\n\t\t\tthis.contextRunner.withBean(ServerBuilderCustomizer.class, () -> customizer)\n\t\t\t\t.run((context) -> assertThat(applied.get()).isInstanceOf(ServletServerBuilder.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHttp2EnabledPropertyMissing() {\n\t\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t\t.with(GrpcServerAutoConfigurationTests.this::serviceBean)\n\t\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t\t.hasMessageContaining(\n\t\t\t\t\t\t\t\"Configuration property 'server.http2.enabled' should be set to true for gRPC support\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHttp2EnabledPropertyFalse() {\n\t\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t\t.with(GrpcServerAutoConfigurationTests.this::serviceBean)\n\t\t\t\t.withPropertyValues(\"server.http2.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t\t.hasMessageContaining(\n\t\t\t\t\t\t\t\"Configuration property 'server.http2.enabled' should be set to true for gRPC support\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHttp2EnabledPropertyMissingAndValidationDisabled() {\n\t\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t\t.with(GrpcServerAutoConfigurationTests.this::serviceBean)\n\t\t\t\t.withPropertyValues(\"spring.grpc.server.servlet.validate-http2=false\")\n\t\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServerBuilderCustomizersConfig {\n\n\t\tstatic ServerBuilderCustomizer<?> foo = mock();\n\n\t\tstatic ServerBuilderCustomizer<?> bar = mock();\n\n\t\t@Bean\n\t\t@Order(200)\n\t\tServerBuilderCustomizer<?> customizerFoo() {\n\t\t\treturn foo;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(100)\n\t\tServerBuilderCustomizer<?> customizerBar() {\n\t\t\treturn bar;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerBuilderCustomizersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\n\nimport io.grpc.CompressorRegistry;\nimport io.grpc.DecompressorRegistry;\nimport io.grpc.ServerBuilder;\nimport io.grpc.netty.NettyServerBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.Mockito;\n\nimport org.springframework.grpc.server.ServerBuilderCustomizer;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerBuilderCustomizers}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass GrpcServerBuilderCustomizersTests {\n\n\t@Test\n\tvoid applyWhenEmptyCustomizersDoesNothing() {\n\t\tServerBuilder<?> serverBuilder = mock(ServerBuilder.class);\n\t\tnew GrpcServerBuilderCustomizers(Collections.emptyList()).apply(serverBuilder);\n\t\tthen(serverBuilder).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid applyWhenSimpleCustomizer() {\n\t\tGrpcServerBuilderCustomizers customizers = new GrpcServerBuilderCustomizers(\n\t\t\t\tList.of(new SimpleServerBuilderCustomizer()));\n\t\tNettyServerBuilder serverBuilder = mock(NettyServerBuilder.class);\n\t\tcustomizers.apply(serverBuilder);\n\t\tthen(serverBuilder).should().maxConnectionAge(100L, TimeUnit.SECONDS);\n\t}\n\n\t@Test\n\tvoid applyWhenGenericCustomizersRespectsGeneric() {\n\t\tList<TestCustomizer<?>> list = new ArrayList<>();\n\t\tlist.add(new TestCustomizer<>());\n\t\tlist.add(new TestNettyServerBuilderCustomizer());\n\t\tlist.add(new TestShadedNettyServerBuilderCustomizer());\n\t\tGrpcServerBuilderCustomizers customizers = new GrpcServerBuilderCustomizers(list);\n\t\tcustomizers.apply(mock(ServerBuilder.class));\n\t\tassertThat(list.get(0).getCount()).isOne();\n\t\tassertThat(list.get(1).getCount()).isZero();\n\t\tassertThat(list.get(2).getCount()).isZero();\n\t\tcustomizers.apply(mock(NettyServerBuilder.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t\tassertThat(list.get(2).getCount()).isZero();\n\t\tcustomizers.apply(mock(io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(3);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t\tassertThat(list.get(2).getCount()).isOne();\n\t}\n\n\t@Test\n\tvoid applyWhenHasInjectedBeans() {\n\t\tCompressorRegistry compressorRegistry = mock();\n\t\tDecompressorRegistry decompressorRegistry = mock();\n\t\tGrpcServerExecutorProvider executorProvider = mock();\n\t\tExecutor executor = mock();\n\t\tgiven(executorProvider.getExecutor()).willReturn(executor);\n\t\tGrpcServerProperties properties = new GrpcServerProperties();\n\t\tproperties.getInbound().getMessage().setMaxSize(DataSize.ofMegabytes(10));\n\t\tGrpcServerBuilderCustomizers customizers = new GrpcServerBuilderCustomizers(properties, compressorRegistry,\n\t\t\t\tdecompressorRegistry, executorProvider, List.of(new SimpleServerBuilderCustomizer()));\n\t\tNettyServerBuilder serverBuilder = mock(NettyServerBuilder.class);\n\t\tcustomizers.apply(serverBuilder);\n\t\tInOrder ordered = Mockito.inOrder(serverBuilder);\n\t\tthen(serverBuilder).should(ordered).compressorRegistry(compressorRegistry);\n\t\tthen(serverBuilder).should(ordered).decompressorRegistry(decompressorRegistry);\n\t\tthen(serverBuilder).should().executor(executor);\n\t\tthen(serverBuilder).should(ordered).maxConnectionAge(100L, TimeUnit.SECONDS);\n\t}\n\n\t/**\n\t * Test customizer that will match {@link NettyServerBuilder} and apply a simple\n\t * customization.\n\t */\n\tstatic class SimpleServerBuilderCustomizer implements ServerBuilderCustomizer<NettyServerBuilder> {\n\n\t\t@Override\n\t\tpublic void customize(NettyServerBuilder serverBuilder) {\n\t\t\tserverBuilder.maxConnectionAge(100, TimeUnit.SECONDS);\n\t\t}\n\n\t}\n\n\t/**\n\t * Test customizer that will match all {@link ServerBuilderCustomizer}.\n\t *\n\t * @param <T> the builder type\n\t */\n\tstatic class TestCustomizer<T extends ServerBuilder<T>> implements ServerBuilderCustomizer<T> {\n\n\t\tprivate int count;\n\n\t\t@Override\n\t\tpublic void customize(T serverBuilder) {\n\t\t\tthis.count++;\n\t\t}\n\n\t\tint getCount() {\n\t\t\treturn this.count;\n\t\t}\n\n\t}\n\n\t/**\n\t * Test customizer that will match only {@link NettyServerBuilder}.\n\t */\n\tstatic class TestNettyServerBuilderCustomizer extends TestCustomizer<NettyServerBuilder> {\n\n\t}\n\n\t/**\n\t * Test customizer that will match only\n\t * {@link io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder}.\n\t */\n\tstatic class TestShadedNettyServerBuilderCustomizer\n\t\t\textends TestCustomizer<io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerCodecConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.Compressor;\nimport io.grpc.CompressorRegistry;\nimport io.grpc.Decompressor;\nimport io.grpc.DecompressorRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerCodecConfiguration}.\n *\n * @author Andrei Lisa\n */\nclass GrpcServerCodecConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GrpcServerCodecConfiguration.class));\n\n\t@Test\n\tvoid compressorRegistryWhenHasUserDefinedRegistryDoesNotAutoConfigureBean() {\n\t\tCompressorRegistry customRegistry = mock();\n\t\tthis.contextRunner.withBean(\"customCompressorRegistry\", CompressorRegistry.class, () -> customRegistry)\n\t\t\t.run((context) -> assertThat(context).getBean(CompressorRegistry.class).isSameAs(customRegistry));\n\t}\n\n\t@Test\n\tvoid compressorRegistryWhenNoCompressorsAutoConfiguresDefaultInstance() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(CompressorRegistry.class)\n\t\t\t.isSameAs(CompressorRegistry.getDefaultInstance()));\n\t}\n\n\t@Test\n\tvoid compressorRegistryWhenHasCompressorsAutoConfiguresNewInstance() {\n\t\tCompressor compressor = mock();\n\t\tgiven(compressor.getMessageEncoding()).willReturn(\"foo\");\n\t\tthis.contextRunner.withBean(Compressor.class, () -> compressor).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CompressorRegistry.class);\n\t\t\tCompressorRegistry registry = context.getBean(CompressorRegistry.class);\n\t\t\tassertThat(registry).isNotSameAs(CompressorRegistry.getDefaultInstance());\n\t\t\tassertThat(registry.lookupCompressor(\"foo\")).isSameAs(compressor);\n\t\t});\n\t}\n\n\t@Test\n\tvoid decompressorRegistryWhenHasUserDefinedRegistryDoesNotAutoConfigureBean() {\n\t\tDecompressorRegistry customRegistry = mock();\n\t\tthis.contextRunner.withBean(\"customDecompressorRegistry\", DecompressorRegistry.class, () -> customRegistry)\n\t\t\t.run((context) -> assertThat(context).getBean(DecompressorRegistry.class).isSameAs(customRegistry));\n\t}\n\n\t@Test\n\tvoid decompressorRegistryWhenNoDecompressorsAutoConfiguresDefaultInstance() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(DecompressorRegistry.class)\n\t\t\t.isSameAs(DecompressorRegistry.getDefaultInstance()));\n\t}\n\n\t@Test\n\tvoid decompressorRegistryWhenHasDecompressorsAutoConfiguresNewInstance() {\n\t\tDecompressor decompressor = mock();\n\t\tgiven(decompressor.getMessageEncoding()).willReturn(\"foo\");\n\t\tthis.contextRunner.withBean(Decompressor.class, () -> decompressor).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DecompressorRegistry.class);\n\t\t\tDecompressorRegistry registry = context.getBean(DecompressorRegistry.class);\n\t\t\tassertThat(registry).isNotSameAs(DecompressorRegistry.getDefaultInstance());\n\t\t\tassertThat(registry.lookupDecompressor(\"foo\")).isSameAs(decompressor);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerInterceptor;\nimport io.micrometer.context.ContextRegistry;\nimport io.micrometer.core.instrument.binder.grpc.GrpcServerObservationConvention;\nimport io.micrometer.core.instrument.binder.grpc.ObservationGrpcServerInterceptor;\nimport io.micrometer.core.instrument.kotlin.ObservationCoroutineContextServerInterceptor;\nimport io.micrometer.observation.ObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for the {@link GrpcServerObservationAutoConfiguration}.\n *\n * @author Chris Bono\n */\nclass GrpcServerObservationAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfigurations = AutoConfigurations\n\t\t.of(GrpcServerObservationAutoConfiguration.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(autoConfigurations)\n\t\t.withBean(\"observationRegistry\", ObservationRegistry.class, Mockito::mock);\n\n\t@Test\n\tvoid whenGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BindableService.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenSpringGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerFactory.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationRegistryNotOnClasspathAutoConfigurationSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ObservationRegistry.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationGrpcServerInterceptorNotOnClasspathAutoConfigurationSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ObservationGrpcServerInterceptor.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationRegistryNotProvidedThenAutoConfigurationSkipped() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationPropertyEnabledThenAutoConfigurationNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.observation.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenObservationPropertyDisabledThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.observation.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertySetFalseThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertyNotSetThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertySetTrueThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerObservationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenAllConditionsAreMetThenInterceptorConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ObservationGrpcServerInterceptor.class);\n\t\t\tMap<String, Object> annotated = context.getBeansWithAnnotation(GlobalServerInterceptor.class);\n\t\t\tList<ServerInterceptor> interceptors = context.getBeanProvider(ServerInterceptor.class)\n\t\t\t\t.orderedStream()\n\t\t\t\t.toList();\n\t\t\tassertThat(annotated).hasSize(2);\n\t\t\tassertThat(interceptors.get(0)).isInstanceOf(ObservationGrpcServerInterceptor.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomConventionBeanIsPresentThenInterceptorUsesIt() {\n\t\tGrpcServerObservationConvention customConvention = mock(GrpcServerObservationConvention.class);\n\t\tthis.contextRunner.withBean(GrpcServerObservationConvention.class, () -> customConvention)\n\t\t\t.run((context) -> assertThat(context.getBean(ObservationGrpcServerInterceptor.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"customConvention\", customConvention));\n\t}\n\n\t@Test\n\tvoid whenMicrometerContextPropagationIsNotOnClasspathCoroutineInterceptorIsNotCreated() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ContextRegistry.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ObservationGrpcServerInterceptor.class)\n\t\t\t\t.doesNotHaveBean(ObservationCoroutineContextServerInterceptor.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.net.InetAddress;\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.grpc.TlsServerCredentials.ClientAuth;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GrpcServerProperties}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass GrpcServerPropertiesTests {\n\n\tprivate GrpcServerProperties bindProperties(Map<String, String> map) {\n\t\treturn new Binder(new MapConfigurationPropertySource(map))\n\t\t\t.bind(\"spring.grpc.server\", GrpcServerProperties.class)\n\t\t\t.get();\n\t}\n\n\t@Test\n\tvoid bind() throws Exception {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"spring.grpc.server.address\", \"192.168.0.1\");\n\t\tGrpcServerProperties properties = bindProperties(map);\n\t\tassertThat(properties.getAddress()).isEqualTo(InetAddress.getByName(\"192.168.0.1\"));\n\t}\n\n\t@Test\n\tvoid defaultAddressIsNull() {\n\t\tassertThat(new GrpcServerProperties().getAddress()).isNull();\n\t}\n\n\t@Nested\n\tclass ShutdownProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.shutdown.grace-period\", \"10m\");\n\t\t\tGrpcServerProperties properties = bindProperties(map);\n\t\t\tassertThat(properties.getShutdown().getGracePeriod()).isEqualTo(Duration.ofMinutes(10));\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWithoutUnits() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.shutdown.grace-period\", \"10\");\n\t\t\tGrpcServerProperties properties = bindProperties(map);\n\t\t\tassertThat(properties.getShutdown().getGracePeriod()).isEqualTo(Duration.ofSeconds(10));\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass InboundProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.inbound.message.max-size\", \"20MB\");\n\t\t\tmap.put(\"spring.grpc.server.inbound.metadata.max-size\", \"1MB\");\n\t\t\tGrpcServerProperties properties = bindProperties(map);\n\t\t\tassertThat(properties.getInbound().getMessage().getMaxSize()).isEqualTo(DataSize.ofMegabytes(20));\n\t\t\tassertThat(properties.getInbound().getMetadata().getMaxSize()).isEqualTo(DataSize.ofMegabytes(1));\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWithoutUnits() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.inbound.message.max-size\", \"1048576\");\n\t\t\tmap.put(\"spring.grpc.server.inbound.metadata.max-size\", \"1024\");\n\t\t\tGrpcServerProperties properties = bindProperties(map);\n\t\t\tassertThat(properties.getInbound().getMessage().getMaxSize()).isEqualTo(DataSize.ofMegabytes(1));\n\t\t\tassertThat(properties.getInbound().getMetadata().getMaxSize()).isEqualTo(DataSize.ofKilobytes(1));\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass KeepAliveProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.keepalive.time\", \"45m\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.timeout\", \"40s\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.permit.time\", \"33s\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.permit.without-calls\", \"true\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.connection.max-idle-time\", \"1h\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.connection.max-age\", \"3h\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.connection.grace-period\", \"21s\");\n\t\t\tGrpcServerProperties.Keepalive properties = bindProperties(map).getKeepalive();\n\t\t\tassertThatPropertiesSetAsExpected(properties);\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWithoutUnits() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.keepalive.time\", \"2700\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.timeout\", \"40\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.permit.time\", \"33\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.permit.without-calls\", \"true\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.connection.max-idle-time\", \"3600\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.connection.max-age\", \"10800\");\n\t\t\tmap.put(\"spring.grpc.server.keepalive.connection.grace-period\", \"21\");\n\t\t\tGrpcServerProperties.Keepalive properties = bindProperties(map).getKeepalive();\n\t\t\tassertThatPropertiesSetAsExpected(properties);\n\t\t}\n\n\t\tprivate void assertThatPropertiesSetAsExpected(GrpcServerProperties.Keepalive properties) {\n\t\t\tassertThat(properties.getTime()).isEqualTo(Duration.ofMinutes(45));\n\t\t\tassertThat(properties.getTimeout()).isEqualTo(Duration.ofSeconds(40));\n\t\t\tassertThat(properties.getPermit().getTime()).isEqualTo(Duration.ofSeconds(33));\n\t\t\tassertThat(properties.getPermit().isWithoutCalls()).isTrue();\n\t\t\tassertThat(properties.getConnection().getMaxIdleTime()).isEqualTo(Duration.ofHours(1));\n\t\t\tassertThat(properties.getConnection().getMaxAge()).isEqualTo(Duration.ofHours(3));\n\t\t\tassertThat(properties.getConnection().getGracePeriod()).isEqualTo(Duration.ofSeconds(21));\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass SslProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.grpc.server.ssl.enabled\", \"true\");\n\t\t\tmap.put(\"spring.grpc.server.ssl.client-auth\", \"require\");\n\t\t\tmap.put(\"spring.grpc.server.ssl.bundle\", \"test\");\n\t\t\tmap.put(\"spring.grpc.server.ssl.secure\", \"false\");\n\t\t\tGrpcServerProperties.Ssl properties = bindProperties(map).getSsl();\n\t\t\tassertThat(properties.getEnabled()).isTrue();\n\t\t\tassertThat(properties.getClientAuth()).isEqualTo(ClientAuth.REQUIRE);\n\t\t\tassertThat(properties.getBundle()).isEqualTo(\"test\");\n\t\t\tassertThat(properties.isSecure()).isFalse();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerServicesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport io.grpc.BindableService;\nimport io.grpc.protobuf.services.ProtoReflectionServiceV1;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerServicesAutoConfiguration.GrpcServerReflectionServiceConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GrpcServerServicesAutoConfiguration}.\n *\n * @author Haris Zujo\n * @author Chris Bono\n * @author Andrey Litvitski\n * @author Phillip Webb\n */\nclass GrpcServerServicesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GrpcServerServicesAutoConfiguration.class))\n\t\t.withBean(\"noopServerLifecycle\", GrpcServerLifecycle.class, Mockito::mock)\n\t\t.withBean(BindableService.class, Mockito::mock);\n\n\t@Nested\n\tclass GrpcServerReflectionServiceConfigurationTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = GrpcServerServicesAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenAutoConfigurationIsNotSkippedCreatesReflectionServiceBean() {\n\t\t\tthis.contextRunner.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GrpcServerReflectionServiceConfiguration.class);\n\t\t\t\tassertThat(context).hasBean(\"grpcServerReflectionService\");\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenGrpcServicesNotOnClasspathAutoConfigurationIsSkipped() {\n\t\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ProtoReflectionServiceV1.class))\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerReflectionServiceConfiguration.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNoBindableServiceDefinedAutoConfigurationIsSkipped() {\n\t\t\tnew ApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(GrpcServerServicesAutoConfiguration.class))\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerReflectionServiceConfiguration.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenReflectionEnabledPropertyIsTrueAutoConfigurationIsNotSkipped() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.reflection.enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context).hasBean(\"grpcServerReflectionService\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenReflectionEnabledPropertyIsFalseAutoConfigurationIsSkipped() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.reflection.enabled=false\").run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"grpcServerReflectionService\");\n\t\t\t\tassertThat(context).doesNotHaveBean(GrpcServerReflectionServiceConfiguration.class);\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenServerEnabledPropertyIsTrueAutoConfigurationIsNotSkipped() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context).hasBean(\"grpcServerReflectionService\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenServerEnabledPropertyIsFalseAutoConfigurationIsSkipped() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=false\").run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(\"grpcServerReflectionService\");\n\t\t\t\tassertThat(context).doesNotHaveBean(GrpcServerReflectionServiceConfiguration.class);\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/NettyAddressTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.net.InetAddress;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerProperties.Netty.Transport;\nimport org.springframework.grpc.internal.GrpcUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link NettyAddress}.\n *\n * @author Phillip Webb\n */\nclass NettyAddressTests {\n\n\t@Test\n\tvoid whenNoTransportAndNoAddressOrPortOrDomainSocketPathBindsToDefault() {\n\t\tNettyAddress address = new NettyAddress(null, null, null, null);\n\t\tassertThat(address).hasToString(GrpcUtils.ANY_IP_ADDRESS + \":\" + GrpcUtils.DEFAULT_PORT);\n\t}\n\n\t@Test\n\tvoid whenNoTransportAndOnlyPortBindsToAllAddressesUsingPort() {\n\t\tNettyAddress address = new NettyAddress(null, null, 1234, null);\n\t\tassertThat(address).hasToString(GrpcUtils.ANY_IP_ADDRESS + \":1234\");\n\t}\n\n\t@Test\n\tvoid whenNoTransportAndOnlyAddressBindsToAddressUsingPort9090() throws Exception {\n\t\tInetAddress inetAddress = InetAddress.getByName(\"localhost\");\n\t\tNettyAddress address = new NettyAddress(null, inetAddress, null, null);\n\t\tassertThat(address).hasToString(\"localhost:\" + GrpcUtils.DEFAULT_PORT);\n\t}\n\n\t@Test\n\tvoid whenNoTransportAndOnlyAddressWithoutNameBindsToAddressUsingPort9090() throws Exception {\n\t\tInetAddress inetAddress = InetAddress.getByName(\"192.168.1.0\");\n\t\tNettyAddress address = new NettyAddress(null, inetAddress, null, null);\n\t\tassertThat(address).hasToString(\"192.168.1.0:\" + GrpcUtils.DEFAULT_PORT);\n\t}\n\n\t@Test\n\tvoid whenNoTransportAndOnlyDomainSocketPathBindsToDomainSocket() {\n\t\tNettyAddress address = new NettyAddress(null, null, null, \"/ds\");\n\t\tassertThat(address).hasToString(\"unix:/ds\");\n\t}\n\n\t@Test\n\tvoid whenNoTransportAndPortAndDomainSocketPathThrowsException() {\n\t\tNettyAddress address = new NettyAddress(null, null, 1234, \"/ds\");\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(() -> address.toString())\n\t\t\t.withMessage(\n\t\t\t\t\t\"The configuration properties 'spring.grpc.server.port, spring.grpc.server.netty.domain-socket-path' \"\n\t\t\t\t\t\t\t+ \"are mutually exclusive and 'spring.grpc.server.port, spring.grpc.server.netty.domain-socket-path' \"\n\t\t\t\t\t\t\t+ \"have been configured together\");\n\t}\n\n\t@Test\n\tvoid whenNoTransportAndAddressAndDomainSocketPathThrowsException() throws Exception {\n\t\tInetAddress inetAddress = InetAddress.getByName(\"192.168.1.0\");\n\t\tNettyAddress address = new NettyAddress(null, inetAddress, null, \"/ds\");\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(() -> address.toString())\n\t\t\t.withMessage(\n\t\t\t\t\t\"The configuration properties 'spring.grpc.server.address, spring.grpc.server.netty.domain-socket-path' \"\n\t\t\t\t\t\t\t+ \"are mutually exclusive and 'spring.grpc.server.address, spring.grpc.server.netty.domain-socket-path' \"\n\t\t\t\t\t\t\t+ \"have been configured together\");\n\t}\n\n\t@Test\n\tvoid whenTcpTransportBindsToTcp() throws Exception {\n\t\tInetAddress inetAddress = InetAddress.getByName(\"192.168.1.0\");\n\t\tNettyAddress address = new NettyAddress(Transport.TCP, inetAddress, 1234, \"/ds\");\n\t\tassertThat(address).hasToString(\"192.168.1.0:1234\");\n\t}\n\n\t@Test\n\tvoid whenDomainSocketTransportAndNoDomainPathThrowsException() {\n\t\tNettyAddress address = new NettyAddress(Transport.DOMAIN_SOCKET, null, null, \"\");\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyValueException.class).isThrownBy(() -> address.toString())\n\t\t\t.withMessage(\"Property spring.grpc.server.netty.domain-socket-path with value '' is invalid: \"\n\t\t\t\t\t+ \"A path is required when spring.grpc.server.netty.transport is set to 'domain-socket'\");\n\t}\n\n\t@Test\n\tvoid whenDomainSocketTransportAndDomainPathBindsToDomainPath() throws Exception {\n\t\tInetAddress inetAddress = InetAddress.getByName(\"192.168.1.0\");\n\t\tNettyAddress address = new NettyAddress(Transport.DOMAIN_SOCKET, inetAddress, 1234, \"/ds\");\n\t\tassertThat(address).hasToString(\"unix:/ds\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/PropertiesServerBuilderCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.grpc.ServerBuilder;\nimport io.grpc.inprocess.InProcessServerBuilder;\nimport io.grpc.netty.NettyServerBuilder;\nimport io.grpc.servlet.jakarta.ServletServerBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.verification.VerificationMode;\n\nimport org.springframework.util.unit.DataSize;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link PropertiesServerBuilderCustomizer}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass PropertiesServerBuilderCustomizerTests {\n\n\t@Test\n\tvoid customizeWhenNettyServerBuilder() {\n\t\tNettyServerBuilder builder = mock();\n\t\tPropertiesServerBuilderCustomizer<NettyServerBuilder> customizer = new PropertiesServerBuilderCustomizer<>(\n\t\t\t\tgetProperties());\n\t\tcustomizer.customize(builder);\n\t\tassertExpectedMapping(builder, atLeastOnce());\n\t}\n\n\t@Test\n\tvoid customizeWhenInProcessServerBuilder() {\n\t\tInProcessServerBuilder builder = mock();\n\t\tPropertiesServerBuilderCustomizer<InProcessServerBuilder> customizer = new PropertiesServerBuilderCustomizer<>(\n\t\t\t\tgetProperties());\n\t\tcustomizer.customize(builder);\n\t\tassertExpectedMapping(builder, never());\n\t}\n\n\t@Test\n\tvoid customizeWhenServletServerBuilder() {\n\t\tServletServerBuilder builder = mock();\n\t\tPropertiesServerBuilderCustomizer<ServletServerBuilder> customizer = new PropertiesServerBuilderCustomizer<>(\n\t\t\t\tgetProperties());\n\t\tcustomizer.customize(builder);\n\t\tassertExpectedMapping(builder, never());\n\t}\n\n\tprivate GrpcServerProperties getProperties() {\n\t\tGrpcServerProperties properties = new GrpcServerProperties();\n\t\tproperties.getInbound().getMessage().setMaxSize(DataSize.ofMegabytes(333));\n\t\tproperties.getInbound().getMetadata().setMaxSize(DataSize.ofKilobytes(111));\n\t\tproperties.getKeepalive().setTime(Duration.ofHours(1));\n\t\tproperties.getKeepalive().setTimeout(Duration.ofSeconds(10));\n\t\tproperties.getKeepalive().getConnection().setMaxIdleTime(Duration.ofHours(2));\n\t\tproperties.getKeepalive().getConnection().setMaxAge(Duration.ofHours(3));\n\t\tproperties.getKeepalive().getConnection().setGracePeriod(Duration.ofSeconds(45));\n\t\tproperties.getKeepalive().getPermit().setTime(Duration.ofMinutes(7));\n\t\tproperties.getKeepalive().getPermit().setWithoutCalls(true);\n\t\treturn properties;\n\t}\n\n\tprivate void assertExpectedMapping(ServerBuilder<?> builder, VerificationMode keepAliveMode) {\n\t\tthen(builder).should().maxInboundMessageSize(Math.toIntExact(DataSize.ofMegabytes(333).toBytes()));\n\t\tthen(builder).should().maxInboundMetadataSize(Math.toIntExact(DataSize.ofKilobytes(111).toBytes()));\n\t\tthen(builder).should(keepAliveMode).keepAliveTime(Duration.ofHours(1).toNanos(), TimeUnit.NANOSECONDS);\n\t\tthen(builder).should(keepAliveMode).keepAliveTimeout(Duration.ofSeconds(10).toNanos(), TimeUnit.NANOSECONDS);\n\t\tthen(builder).should(keepAliveMode).maxConnectionIdle(Duration.ofHours(2).toNanos(), TimeUnit.NANOSECONDS);\n\t\tthen(builder).should(keepAliveMode).maxConnectionAge(Duration.ofHours(3).toNanos(), TimeUnit.NANOSECONDS);\n\t\tthen(builder).should(keepAliveMode)\n\t\t\t.maxConnectionAgeGrace(Duration.ofSeconds(45).toNanos(), TimeUnit.NANOSECONDS);\n\t\tthen(builder).should(keepAliveMode).permitKeepAliveTime(Duration.ofMinutes(7).toNanos(), TimeUnit.NANOSECONDS);\n\t\tthen(builder).should(keepAliveMode).permitKeepAliveWithoutCalls(true);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/ServerCredentialsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport io.grpc.TlsServerCredentials.ClientAuth;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerProperties.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslManagerBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ServerCredentials}.\n *\n * @author Phillip Webb\n */\nclass ServerCredentialsTests {\n\n\tprivate final TrustManagerFactory insecureTrustManagerFactory = mock();\n\n\tprivate final SslBundles bundles = mock();\n\n\tprivate final TrustManagerFactory bundleTrustManagerFactory = mock();\n\n\tprivate final KeyManagerFactory bundleKeyManagerFactory = mock();\n\n\tServerCredentialsTests() {\n\t\tSslBundle bundle = mock();\n\t\tSslManagerBundle managers = mock();\n\t\tgiven(this.bundles.getBundle(\"test\")).willReturn(bundle);\n\t\tgiven(bundle.getManagers()).willReturn(managers);\n\t\tgiven(managers.getTrustManagerFactory()).willReturn(this.bundleTrustManagerFactory);\n\t\tgiven(managers.getKeyManagerFactory()).willReturn(this.bundleKeyManagerFactory);\n\t}\n\n\t@Test\n\tvoid getWhenNotEnabledAndNoBundleReturnsNullManagers() {\n\t\tServerCredentials credentials = get((properties) -> {\n\t\t});\n\t\tassertThat(credentials.keyManagerFactory()).isNull();\n\t\tassertThat(credentials.trustManagerFactory()).isNull();\n\t\tassertThat(credentials.clientAuth()).isEqualTo(ClientAuth.NONE);\n\t}\n\n\t@Test\n\tvoid getWhenDisabledReturnsNullManagers() {\n\t\tServerCredentials credentials = get((properties) -> {\n\t\t\tproperties.put(\"spring.grpc.server.ssl.enabled\", \"false\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.client-auth\", \"require\");\n\t\t});\n\t\tassertThat(credentials.keyManagerFactory()).isNull();\n\t\tassertThat(credentials.trustManagerFactory()).isNull();\n\t\tassertThat(credentials.clientAuth()).isEqualTo(ClientAuth.REQUIRE);\n\t}\n\n\t@Test\n\tvoid getWhenEnabledTrueAndNoBundleNameThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> get((properties) -> {\n\t\t\tproperties.put(\"spring.grpc.server.ssl.enabled\", \"true\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.client-auth\", \"require\");\n\t\t})).withMessage(\"SSL bundle-name is requested when 'spring.grpc.server.ssl.enabled' is true\");\n\t}\n\n\t@Test\n\tvoid getWhenHasBundleName() {\n\t\tServerCredentials credentials = get((properties) -> {\n\t\t\tproperties.put(\"spring.grpc.server.ssl.bundle\", \"test\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.client-auth\", \"require\");\n\t\t});\n\t\tassertThat(credentials.keyManagerFactory()).isEqualTo(this.bundleKeyManagerFactory);\n\t\tassertThat(credentials.trustManagerFactory()).isEqualTo(this.bundleTrustManagerFactory);\n\t\tassertThat(credentials.clientAuth()).isEqualTo(ClientAuth.REQUIRE);\n\t}\n\n\t@Test\n\tvoid getWhenHasBundleNameAndEnabled() {\n\t\tServerCredentials credentials = get((properties) -> {\n\t\t\tproperties.put(\"spring.grpc.server.ssl.enabled\", \"true\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.bundle\", \"test\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.client-auth\", \"require\");\n\t\t});\n\t\tassertThat(credentials.keyManagerFactory()).isEqualTo(this.bundleKeyManagerFactory);\n\t\tassertThat(credentials.trustManagerFactory()).isEqualTo(this.bundleTrustManagerFactory);\n\t\tassertThat(credentials.clientAuth()).isEqualTo(ClientAuth.REQUIRE);\n\t}\n\n\t@Test\n\tvoid getWhenHasBundleNameAndSecureFalse() {\n\t\tServerCredentials credentials = get((properties) -> {\n\t\t\tproperties.put(\"spring.grpc.server.ssl.enabled\", \"true\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.bundle\", \"test\");\n\t\t\tproperties.put(\"spring.grpc.server.ssl.secure\", \"false\");\n\t\t});\n\t\tassertThat(credentials.keyManagerFactory()).isEqualTo(this.bundleKeyManagerFactory);\n\t\tassertThat(credentials.trustManagerFactory()).isEqualTo(this.insecureTrustManagerFactory);\n\t\tassertThat(credentials.clientAuth()).isEqualTo(ClientAuth.NONE);\n\t}\n\n\tprivate ServerCredentials get(Consumer<Map<String, String>> properties) {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tproperties.accept(map);\n\t\tSsl ssl = new Binder(new MapConfigurationPropertySource(map))\n\t\t\t.bind(\"spring.grpc.server\", GrpcServerProperties.class)\n\t\t\t.orElseGet(GrpcServerProperties::new)\n\t\t\t.getSsl();\n\t\treturn ServerCredentials.get(ssl, this.bundles, this.insecureTrustManagerFactory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/health/AutoConfiguredHealthCheckedGrpcComponentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.grpc.server.health.StatusAggregator;\nimport org.springframework.boot.grpc.server.health.StatusMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfiguredHealthCheckedGrpcComponent}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass AutoConfiguredHealthCheckedGrpcComponentTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate StatusAggregator statusAggregator;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate StatusMapper statusMapper;\n\n\t@Test\n\tvoid isMemberWhenMembershipMatchesAcceptsTrue() {\n\t\tAutoConfiguredHealthCheckedGrpcComponent component = new AutoConfiguredHealthCheckedGrpcComponent(\n\t\t\t\t(name) -> name.startsWith(\"a\"), this.statusAggregator, this.statusMapper);\n\t\tassertThat(component.isMember(\"albert\")).isTrue();\n\t\tassertThat(component.isMember(\"arnold\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isMemberWhenMembershipRejectsReturnsFalse() {\n\t\tAutoConfiguredHealthCheckedGrpcComponent component = new AutoConfiguredHealthCheckedGrpcComponent(\n\t\t\t\t(name) -> name.startsWith(\"a\"), this.statusAggregator, this.statusMapper);\n\t\tassertThat(component.isMember(\"bert\")).isFalse();\n\t\tassertThat(component.isMember(\"ernie\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getStatusAggregatorReturnsStatusAggregator() {\n\t\tAutoConfiguredHealthCheckedGrpcComponent component = new AutoConfiguredHealthCheckedGrpcComponent(\n\t\t\t\t(name) -> true, this.statusAggregator, this.statusMapper);\n\t\tassertThat(component.getStatusAggregator()).isSameAs(this.statusAggregator);\n\t}\n\n\t@Test\n\tvoid getStatusMapperReturnsStatusMapper() {\n\t\tAutoConfiguredHealthCheckedGrpcComponent component = new AutoConfiguredHealthCheckedGrpcComponent(\n\t\t\t\t(name) -> true, this.statusAggregator, this.statusMapper);\n\t\tassertThat(component.getStatusMapper()).isSameAs(this.statusMapper);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/health/AutoConfiguredHealthCheckedGrpcComponentsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport java.util.Collections;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponent;\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponents;\nimport org.springframework.boot.grpc.server.health.StatusAggregator;\nimport org.springframework.boot.grpc.server.health.StatusMapper;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfiguredHealthCheckedGrpcComponent}.\n *\n * @author Phillip Webb\n */\nclass AutoConfiguredHealthCheckedGrpcComponentsTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AutoConfiguredHealthCheckedGrpcComponentsTestConfiguration.class));\n\n\t@Test\n\tvoid getServerMatchesAllMembers() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\tassertThat(server).isNotNull();\n\t\t\tassertThat(server.isMember(\"a\")).isTrue();\n\t\t\tassertThat(server.isMember(\"b\")).isTrue();\n\t\t\tassertThat(server.isMember(\"C\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getServiceNamesReturnsServiceNames() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tassertThat(components.getServiceNames()).containsExactlyInAnyOrder(\"a\", \"b\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid getServiceWhenServiceExistsReturnsService() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\").run((context) -> {\n\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\tHealthCheckedGrpcComponent component = components.getService(\"a\");\n\t\t\tassertThat(component).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getServiceWhenServiceDoesNotExistReturnsNull() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\").run((context) -> {\n\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\tHealthCheckedGrpcComponent component = components.getService(\"b\");\n\t\t\tassertThat(component).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenNoDefinedBeansAdaptsProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.status.mapping.down=serving\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorBeanReturnsInstanceWithAggregatorUsedForAllServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorBeanAndServiceSpecificPropertyReturnsInstanceThatUsesBeanOnlyForUnconfiguredServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorPropertyReturnsInstanceWithPropertyUsedForAllServices() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorPropertyAndServiceSpecificPropertyReturnsInstanceWithPropertyUsedForExpectedServices() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.order=unknown,up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorPropertyAndServiceQualifiedBeanReturnsInstanceWithBeanUsedForExpectedServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorServiceAConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasServiceSpecificStatusAggregatorPropertyAndServiceQualifiedBeanReturnsInstanceWithBeanUsedForExpectedServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorServiceAConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.order=up,down\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.status.order=up,down\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.DOWN);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusMapperBeanReturnsInstanceWithMapperUsedForAllServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusMapperBeanAndServiceSpecificPropertyReturnsInstanceThatUsesBeanOnlyForUnconfiguredServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusMapperPropertyReturnsInstanceWithPropertyUsedForAllServices() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusMapperPropertyAndServiceSpecificPropertyReturnsInstanceWithPropertyUsedForExpectedServices() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.mapping.down=unrecognized\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.UNRECOGNIZED);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusMapperPropertyAndServiceQualifiedBeanReturnsInstanceWithBeanUsedForExpectedServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusMapperServiceAConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasServiceSpecificStatusMapperPropertyAndServiceQualifiedBeanReturnsInstanceWithBeanUsedForExpectedServices() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusMapperServiceAConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.a.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.a.status.mapping.down=service-unknown\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.include=*\",\n\t\t\t\t\t\"spring.grpc.server.health.service.b.status.mapping.down=service-unknown\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tHealthCheckedGrpcComponent server = components.getServer();\n\t\t\t\tHealthCheckedGrpcComponent serviceA = components.getService(\"a\");\n\t\t\t\tHealthCheckedGrpcComponent serviceB = components.getService(\"b\");\n\t\t\t\tassertThat(server).isNotNull();\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(server.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.NOT_SERVING);\n\t\t\t\tassertThat(serviceA).isNotNull();\n\t\t\t\tassertThat(serviceA.getStatusMapper().getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.SERVING);\n\t\t\t\tassertThat(serviceB).isNotNull();\n\t\t\t\tassertThat(serviceB.getStatusMapper().getServingStatus(Status.DOWN))\n\t\t\t\t\t.isEqualTo(ServingStatus.SERVICE_UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(GrpcServerHealthProperties.class)\n\tstatic class AutoConfiguredHealthCheckedGrpcComponentsTestConfiguration {\n\n\t\t@Bean\n\t\tAutoConfiguredHealthCheckedGrpcComponents healthCheckedGrpcComponents(\n\t\t\t\tConfigurableApplicationContext applicationContext, GrpcServerHealthProperties properties) {\n\t\t\treturn new AutoConfiguredHealthCheckedGrpcComponents(applicationContext, properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomStatusAggregatorConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tStatusAggregator statusAggregator() {\n\t\t\treturn StatusAggregator.of(Status.UNKNOWN, Status.UP, Status.DOWN);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomStatusAggregatorServiceAConfiguration {\n\n\t\t@Bean\n\t\t@Qualifier(\"a\")\n\t\tStatusAggregator statusAggregator() {\n\t\t\treturn StatusAggregator.of(Status.UNKNOWN, Status.UP, Status.DOWN);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomStatusMapperConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tStatusMapper statusMapper() {\n\t\t\treturn StatusMapper.of(Collections.singletonMap(Status.DOWN.getCode(), ServingStatus.SERVING));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomStatusMapperServiceAConfiguration {\n\n\t\t@Bean\n\t\t@Qualifier(\"a\")\n\t\tStatusMapper statusMapper() {\n\t\t\treturn StatusMapper.of(Collections.singletonMap(Status.DOWN.getCode(), ServingStatus.SERVING));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/health/GrpcServerHealthAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.grpc.BindableService;\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport io.grpc.protobuf.services.HealthStatusManager;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;\nimport org.springframework.boot.diagnostics.FailureAnalyzedException;\nimport org.springframework.boot.grpc.server.health.GrpcServerHealth;\nimport org.springframework.boot.grpc.server.health.HealthCheckedGrpcComponents;\nimport org.springframework.boot.grpc.server.health.StatusAggregator;\nimport org.springframework.boot.grpc.server.health.StatusMapper;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembershipValidator;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerHealthAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Chris Bono\n * @author Andrey Litvitski\n */\nclass GrpcServerHealthAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfigurations = AutoConfigurations.of(\n\t\t\tGrpcServerHealthAutoConfiguration.class, GrpcServerHealthSchedulerAutoConfiguration.class,\n\t\t\tHealthContributorRegistryAutoConfiguration.class, TaskSchedulingAutoConfiguration.class);\n\n\tprivate final BindableService service = mock();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t.withConfiguration(autoConfigurations)\n\t\t.with(this::serviceBean);\n\n\t@Test\n\tvoid autoConfiguresBeans() {\n\t\tthis.contextRunner.run(this::assertConfigured);\n\t}\n\n\t@Test\n\tvoid whenNoBindableServiceDefinedDoesNotAutoConfigureBeans() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations).run(this::assertNotConfigured);\n\t}\n\n\t@Test\n\tvoid whenNoBindableServiceDefinedButHealthEnabledPropertyIsTrueAutoConfiguresBeans() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.enabled=true\")\n\t\t\t.run(this::assertConfigured);\n\t}\n\n\t@Test\n\tvoid whenGrpcNotOnClasspathDoesNotAutoConfigureBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BindableService.class))\n\t\t\t.run(this::assertNotConfigured);\n\t}\n\n\t@Test\n\tvoid whenSpringGrpcNotOnClasspathDoesNotAutoConfigureBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerFactory.class))\n\t\t\t.run(this::assertNotConfigured);\n\t}\n\n\t@Test\n\tvoid whenHealthStatusManagerNotOnClasspathDoesNotAutoConfigureBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(HealthStatusManager.class))\n\t\t\t.run(this::assertNotConfigured);\n\t}\n\n\t@Test\n\tvoid whenNoTaskSchedulerDoesNotAutoConfigureHealthScheduler() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(GrpcServerHealthAutoConfiguration.class,\n\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class))\n\t\t\t.with(this::serviceBean)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerHealthScheduler.class));\n\t}\n\n\t@Test\n\tvoid whenHealthScheduleEnabledPropertyFalseDoesNotAutoConfigureHealthScheduler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.schedule.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerHealthScheduler.class));\n\t}\n\n\t@Test\n\tvoid whenHealthScheduleEnabledPropertyTrueDoesAutoConfigureHealthScheduler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.schedule.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerHealthScheduler.class));\n\t}\n\n\t@Test\n\tvoid whenHealthEnabledPropertyIsTrueAutoConfiguresBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.enabled=true\").run(this::assertConfigured);\n\t}\n\n\t@Test\n\tvoid whenHealthEnabledPropertyIsFalseDoesNotAutoConfigureBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.enabled=false\").run(this::assertNotConfigured);\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertyIsFalseDoesNotAutoConfigureBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=false\").run(this::assertNotConfigured);\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertyIsTrueAutoConfiguresBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=true\").run(this::assertConfigured);\n\t}\n\n\t@Test\n\tvoid enterTerminalStateIsCalledOnShutdown() {\n\t\tAtomicReference<HealthStatusManager> manager = new AtomicReference<>();\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tmanager.set(context.getBean(HealthStatusManager.class));\n\t\t\tassertTerminalState(manager.get(), false);\n\t\t});\n\t\tassertTerminalState(manager.get(), true);\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedHealthStatusManagerDoesNotAutoConfigureBean() {\n\t\tHealthStatusManager customHealthStatusManager = mock();\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customHealthStatusManager\", HealthStatusManager.class, () -> customHealthStatusManager)\n\t\t\t.run((context) -> assertThat(context).getBean(HealthStatusManager.class)\n\t\t\t\t.isSameAs(customHealthStatusManager));\n\t}\n\n\t@Test\n\tvoid whenHasNoHealthContributorRegistryOnlyAutoConfiguresBasicService() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(GrpcServerHealthAutoConfiguration.class,\n\t\t\t\t\tTaskSchedulingAutoConfiguration.class))\n\t\t\t.with(this::serviceBean)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HealthStatusManager.class);\n\t\t\t\tassertThat(context).hasBean(\"grpcServerHealthService\");\n\t\t\t\tassertThat(context).doesNotHaveBean(GrpcServerHealth.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createsStatusAggregatorFromProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\").run((context) -> {\n\t\t\tStatusAggregator aggregator = context.getBean(StatusAggregator.class);\n\t\t\tassertThat(aggregator.getAggregateStatus(Status.UP, Status.DOWN)).isEqualTo(Status.UP);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasStatusAggregatorBeanIgnoresProperties() {\n\t\tthis.contextRunner.withUserConfiguration(StatusAggregatorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.order=up,down\")\n\t\t\t.run((context) -> {\n\t\t\t\tStatusAggregator aggregator = context.getBean(StatusAggregator.class);\n\t\t\t\tassertThat(aggregator.getAggregateStatus(Status.UP, Status.DOWN)).isEqualTo(Status.UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createsStatusMapperFromProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.status.mapping.up=not-serving\")\n\t\t\t.run((context) -> {\n\t\t\t\tStatusMapper mapper = context.getBean(StatusMapper.class);\n\t\t\t\tassertThat(mapper.getServingStatus(Status.UP)).isEqualTo(ServingStatus.NOT_SERVING);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasStatusMapperBeanIgnoresProperties() {\n\t\tthis.contextRunner.withUserConfiguration(StatusMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.status.mapping.up=not-serving\")\n\t\t\t.run((context) -> {\n\t\t\t\tStatusMapper mapper = context.getBean(StatusMapper.class);\n\t\t\t\tassertThat(mapper.getServingStatus(Status.UP)).isEqualTo(ServingStatus.UNRECOGNIZED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createsHealthCheckedGrpcComponents() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.health.service.test.include=*\").run((context) -> {\n\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\tassertThat(components).isInstanceOf(AutoConfiguredHealthCheckedGrpcComponents.class);\n\t\t\tassertThat(components.getServiceNames()).containsOnly(\"test\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenComponentsIncludesContributorThatExistsDoesNotFail() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.test.include=composite/b/c\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid whenHealthCheckedGrpcComponentsIncludesReactiveContributorThatExists() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeReactiveHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.test.include=composite/b/c\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid whenHealthCheckedGrpcComponentsIncludesContributorThatDoesNotExistThrowsException() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.test.include=composite/b/c,nope\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(FailureAnalyzedException.class)\n\t\t\t\t\t.hasMessage(\"Health contributor 'nope' defined in \"\n\t\t\t\t\t\t\t+ \"'spring.grpc.server.health.service.test.include' does not exist\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHealthCheckedGrpcComponentsExcludesContributorThatDoesNotExistThrowsException() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.test.exclude=composite/b/d\",\n\t\t\t\t\t\"spring.grpc.server.health.service.test.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(FailureAnalyzedException.class)\n\t\t\t\t\t.hasMessage(\"Health contributor 'composite/b/d' defined in \"\n\t\t\t\t\t\t\t+ \"'spring.grpc.server.health.service.test.exclude' does not exist\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHealthCheckedGrpcComponentsIncludesContributorThatDoesNotExistAndValidationDisabledCreatesComponents() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.services.validate-membership=false\",\n\t\t\t\t\t\"spring.grpc.server.health.service.test.include=nope\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tassertThat(components).isInstanceOf(AutoConfiguredHealthCheckedGrpcComponents.class);\n\t\t\t\tassertThat(components.getServiceNames()).containsOnly(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasHealthCheckedGrpcComponentsBeanDoesNotCreateAdditional() {\n\t\tthis.contextRunner.withUserConfiguration(HealthCheckedGrpcComponentsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.grpc.server.health.service.test.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthCheckedGrpcComponents components = context.getBean(HealthCheckedGrpcComponents.class);\n\t\t\t\tassertThat(components.getServiceNames()).containsOnly(\"mock\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createsGrpcServerHealth() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGrpcServerHealth serverHealth = context.getBean(GrpcServerHealth.class);\n\t\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\t\tserverHealth.update(result::put);\n\t\t\tassertThat(result).containsExactly(entry(\"\", ServingStatus.SERVING));\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasGrpcServerHealthBeanDoesNotCreateAdditional() {\n\t\tthis.contextRunner.withUserConfiguration(GrpcServerHealthConfiguration.class).run((context) -> {\n\t\t\tGrpcServerHealth serverHealth = context.getBean(GrpcServerHealth.class);\n\t\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\t\tserverHealth.update(result::put);\n\t\t\tassertThat(result).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWithIndicatorsInParentContextFindsIndicators() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(DownHealthIndicatorConfiguration.class)\n\t\t\t.run((parent) -> new ApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t\t\t.with(this::serviceBean)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tGrpcServerHealth serverHealth = context.getBean(GrpcServerHealth.class);\n\t\t\t\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\t\t\t\tserverHealth.update(result::put);\n\t\t\t\t\tassertThat(result).containsExactly(entry(\"\", ServingStatus.NOT_SERVING));\n\t\t\t\t}));\n\t}\n\n\tprivate void assertTerminalState(HealthStatusManager healthStatusManager, boolean expected) {\n\t\tassertThat(healthStatusManager).extracting(\"healthService.terminal\").isEqualTo(expected);\n\t}\n\n\tprivate void assertConfigured(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(HealthStatusManager.class);\n\t\tassertThat(context).hasBean(\"grpcServerHealthService\");\n\t\tassertThat(context).hasSingleBean(StatusAggregator.class);\n\t\tassertThat(context).hasSingleBean(StatusMapper.class);\n\t\tassertThat(context).hasSingleBean(HealthCheckedGrpcComponents.class);\n\t\tassertThat(context).hasSingleBean(GrpcServerHealth.class);\n\t\tassertThat(context).hasSingleBean(HealthContributorMembershipValidator.class);\n\t\tassertThat(context).hasSingleBean(GrpcServerHealthScheduler.class);\n\t}\n\n\tprivate void assertNotConfigured(AssertableApplicationContext context) {\n\t\tassertThat(context).doesNotHaveBean(HealthStatusManager.class);\n\t\tassertThat(context).doesNotHaveBean(\"grpcServerHealthService\");\n\t\tassertThat(context).doesNotHaveBean(GrpcServerHealthAutoConfiguration.class);\n\t}\n\n\tprivate <R extends AbstractApplicationContextRunner<R, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> R serviceBean(\n\t\t\tR contextRunner) {\n\t\treturn contextRunner.withBean(BindableService.class, () -> this.service);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthIndicatorsConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator simpleHealthIndicator() {\n\t\t\treturn () -> Health.up().withDetail(\"counter\", 42).build();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator additionalHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t\t@Bean\n\t\tReactiveHealthIndicator reactiveHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DownHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator downHealthIndicator() {\n\t\t\treturn () -> Health.down().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CompositeHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\tCompositeHealthContributor compositeHealthIndicator() {\n\t\t\treturn CompositeHealthContributor.fromMap(Map.of(\"a\", createHealthIndicator(), \"b\",\n\t\t\t\t\tCompositeHealthContributor.fromMap(Map.of(\"c\", createHealthIndicator()))));\n\t\t}\n\n\t\tprivate HealthIndicator createHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CompositeReactiveHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\tCompositeReactiveHealthContributor compositeHealthIndicator() {\n\t\t\treturn CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", createHealthIndicator(), \"b\",\n\t\t\t\t\tCompositeReactiveHealthContributor.fromMap(Map.of(\"c\", createHealthIndicator()))));\n\t\t}\n\n\t\tprivate ReactiveHealthIndicator createHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StatusAggregatorConfiguration {\n\n\t\t@Bean\n\t\tStatusAggregator statusAggregator() {\n\t\t\treturn (statuses) -> Status.UNKNOWN;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StatusMapperConfiguration {\n\n\t\t@Bean\n\t\tStatusMapper statusMapper() {\n\t\t\treturn (status) -> ServingStatus.UNRECOGNIZED;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthCheckedGrpcComponentsConfiguration {\n\n\t\t@Bean\n\t\tHealthCheckedGrpcComponents healthCheckedGrpcComponents() {\n\t\t\tHealthCheckedGrpcComponents components = mock();\n\t\t\tgiven(components.getServiceNames()).willReturn(Collections.singleton(\"mock\"));\n\t\t\treturn components;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GrpcServerHealthConfiguration {\n\n\t\t@Bean\n\t\tGrpcServerHealth grpcServerHealth() {\n\t\t\treturn mock();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/health/GrpcServerHealthSchedulerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.health;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneId;\n\nimport io.grpc.protobuf.services.HealthStatusManager;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.grpc.server.health.GrpcServerHealth;\nimport org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;\nimport org.springframework.scheduling.TaskScheduler;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link GrpcServerHealthScheduler}.\n *\n * @author Phillip Webb\n */\nclass GrpcServerHealthSchedulerTests {\n\n\t@Test\n\tvoid onApplicationEventWhenEventIsGrpcStartStartsHealth() {\n\t\tClock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault());\n\t\tGrpcServerHealth serverHealth = mock();\n\t\tHealthStatusManager statusManager = mock();\n\t\tTaskScheduler taskScheduler = mock();\n\t\tDuration period = Duration.ofSeconds(10);\n\t\tDuration delay = Duration.ofSeconds(30);\n\t\tGrpcServerHealthScheduler healthScheduler = new GrpcServerHealthScheduler(clock, serverHealth, statusManager,\n\t\t\t\ttaskScheduler, period, delay);\n\t\tthen(serverHealth).should(never()).update(statusManager);\n\t\thealthScheduler.onApplicationEvent(new GrpcServerStartedEvent(mock(), mock(), \"localhost\", 123));\n\t\tInstant startTime = Instant.now(clock).plus(delay);\n\t\tArgumentCaptor<Runnable> runnable = ArgumentCaptor.captor();\n\t\tthen(taskScheduler).should().scheduleAtFixedRate(runnable.capture(), eq(startTime), eq(period));\n\t\tthen(serverHealth).should(never()).update(statusManager);\n\t\trunnable.getValue().run();\n\t\tthen(serverHealth).should().update(statusManager);\n\t}\n\n\t@Test\n\tvoid onApplicationEventWhenEventIsGrpcStartAndCalledTwiceStartsHealthOnlyOnce() {\n\t\tGrpcServerHealth serverHealth = mock();\n\t\tHealthStatusManager statusManager = mock();\n\t\tTaskScheduler taskScheduler = mock();\n\t\tGrpcServerHealthScheduler healthScheduler = new GrpcServerHealthScheduler(serverHealth, statusManager,\n\t\t\t\ttaskScheduler, Duration.ofSeconds(10), Duration.ofSeconds(30));\n\t\tthen(serverHealth).should(never()).update(statusManager);\n\t\thealthScheduler.onApplicationEvent(new GrpcServerStartedEvent(mock(), mock(), \"localhost\", 123));\n\t\thealthScheduler.onApplicationEvent(new GrpcServerStartedEvent(mock(), mock(), \"localhost\", 345));\n\t\tthen(taskScheduler).should(times(1)).scheduleAtFixedRate(any(), any(), any());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/security/GrpcDisableCsrfHttpConfigurerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport java.util.HashMap;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.boot.grpc.server.autoconfigure.security.GrpcDisableCsrfHttpConfigurer.GrpcCsrfRequestMatcher;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.security.config.ObjectPostProcessor;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link GrpcDisableCsrfHttpConfigurer}.\n *\n * @author Phillip Webb\n */\nclass GrpcDisableCsrfHttpConfigurerTests {\n\n\tprivate GrpcDisableCsrfHttpConfigurer configurer = new GrpcDisableCsrfHttpConfigurer();\n\n\t@Test\n\tvoid initDisablesCsrf() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tStaticApplicationContext applicationContext = addApplicationContext(http);\n\t\taddServiceDiscoverer(applicationContext);\n\t\taddGrpcServletRegistration(applicationContext);\n\t\tCsrfConfigurer<?> csrf = addCsrf(http);\n\t\tthis.configurer.init(http);\n\t\tArgumentCaptor<RequestMatcher> matcher = ArgumentCaptor.captor();\n\t\tthen(csrf).should().requireCsrfProtectionMatcher(matcher.capture());\n\t\tassertThat(matcher.getValue()).isSameAs(GrpcCsrfRequestMatcher.INSTANCE);\n\t}\n\n\t@Test\n\tvoid initWhenNoApplicationContextDoesNothing() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tCsrfConfigurer<?> csrf = addCsrf(http);\n\t\tthis.configurer.init(http);\n\t\tthen(csrf).should(never()).requireCsrfProtectionMatcher(any());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid initWhenNoCsrfConfigurerDoesNothing() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tStaticApplicationContext applicationContext = addApplicationContext(http);\n\t\taddServiceDiscoverer(applicationContext);\n\t\taddGrpcServletRegistration(applicationContext);\n\t\tthis.configurer.init(http);\n\t\tCsrfConfigurer<?> csrfConfigurer = http.getConfigurer(CsrfConfigurer.class);\n\t\tassertThat(csrfConfigurer).isNull();\n\t}\n\n\t@Test\n\tvoid initWhenNoGrpcServiceDiscovererBeanDoesNothing() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tStaticApplicationContext applicationContext = addApplicationContext(http);\n\t\taddGrpcServletRegistration(applicationContext);\n\t\tCsrfConfigurer<?> csrf = addCsrf(http);\n\t\tthis.configurer.init(http);\n\t\tthen(csrf).should(never()).requireCsrfProtectionMatcher(any());\n\t}\n\n\t@Test\n\tvoid initWhenNoGrpcServletRegistrationBeanDoesNothing() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tStaticApplicationContext applicationContext = addApplicationContext(http);\n\t\taddServiceDiscoverer(applicationContext);\n\t\tCsrfConfigurer<?> csrf = addCsrf(http);\n\t\tthis.configurer.init(http);\n\t\tthen(csrf).should(never()).requireCsrfProtectionMatcher(any());\n\t}\n\n\t@Test\n\tvoid initWhenEnabledPropertyFalseDoesNothing() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tStaticApplicationContext applicationContext = addApplicationContext(http);\n\t\tTestPropertyValues.of(\"spring.grpc.server.security.csrf.enabled=false\").applyTo(applicationContext);\n\t\taddServiceDiscoverer(applicationContext);\n\t\taddGrpcServletRegistration(applicationContext);\n\t\tCsrfConfigurer<?> csrf = addCsrf(http);\n\t\tthis.configurer.init(http);\n\t\tthen(csrf).should(never()).requireCsrfProtectionMatcher(any());\n\t}\n\n\t@Test\n\tvoid initWhenEnabledPropertyTrueDisablesCsrf() {\n\t\tObjectPostProcessor<Object> objectPostProcessor = ObjectPostProcessor.identity();\n\t\tAuthenticationManagerBuilder authenticationBuilder = new AuthenticationManagerBuilder(objectPostProcessor);\n\t\tHttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, new HashMap<>());\n\t\tStaticApplicationContext applicationContext = addApplicationContext(http);\n\t\tTestPropertyValues.of(\"spring.grpc.server.security.csrf.enabled=true\").applyTo(applicationContext);\n\t\taddServiceDiscoverer(applicationContext);\n\t\taddGrpcServletRegistration(applicationContext);\n\t\tCsrfConfigurer<?> csrf = addCsrf(http);\n\t\tthis.configurer.init(http);\n\t\tArgumentCaptor<RequestMatcher> matcher = ArgumentCaptor.captor();\n\t\tthen(csrf).should().requireCsrfProtectionMatcher(matcher.capture());\n\t\tassertThat(matcher.getValue()).isSameAs(GrpcCsrfRequestMatcher.INSTANCE);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate CsrfConfigurer<?> addCsrf(HttpSecurity http) {\n\t\tCsrfConfigurer<?> csrf = mock();\n\t\thttp.with((CsrfConfigurer) csrf);\n\t\treturn csrf;\n\t}\n\n\tprivate StaticApplicationContext addApplicationContext(HttpSecurity http) {\n\t\tStaticApplicationContext applicationContext = new StaticApplicationContext();\n\t\thttp.setSharedObject(ApplicationContext.class, applicationContext);\n\t\treturn applicationContext;\n\t}\n\n\tprivate void addServiceDiscoverer(StaticApplicationContext applicationContext) {\n\t\tGrpcServiceDiscoverer serviceDiscoverer = mock();\n\t\tapplicationContext.registerBean(GrpcServiceDiscoverer.class, serviceDiscoverer);\n\t}\n\n\tprivate void addGrpcServletRegistration(StaticApplicationContext applicationContext) {\n\t\tGrpcServletRegistration servletRegistration = mock();\n\t\tapplicationContext.registerBean(GrpcServletRegistration.class, servletRegistration);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/security/GrpcServerOAuth2ResourceServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerServiceDefinition;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.context.annotation.UserConfigurations;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;\nimport org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.security.AuthenticationProcessInterceptor;\nimport org.springframework.grpc.server.security.GrpcSecurity;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.ObjectPostProcessor;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerOAuth2ResourceServerAutoConfiguration}.\n *\n * @author Chris Bono\n */\nclass GrpcServerOAuth2ResourceServerAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfigurations = AutoConfigurations\n\t\t.of(OAuth2ResourceServerAutoConfiguration.class, GrpcServerOAuth2ResourceServerAutoConfiguration.class);\n\n\tprivate ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(autoConfigurations)\n\t\t.withUserConfiguration(GrpcSecurityConfiguration.class)\n\t\t.with(this::serviceBean)\n\t\t.withBean(\"noopServerLifecycle\", GrpcServerLifecycle.class, Mockito::mock);\n\n\t@Test\n\tvoid jwtConfiguredWhenIssuerIsProvided() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AuthenticationProcessInterceptor.class));\n\t}\n\n\t@Test\n\tvoid jwtConfiguredWhenJwkSetIsProvided() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9000\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AuthenticationProcessInterceptor.class));\n\t}\n\n\t@Test\n\tvoid customInterceptorWhenJwkSetIsProvided() {\n\t\tthis.contextRunner.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.withConfiguration(UserConfigurations.of(CustomInterceptorConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9000\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AuthenticationProcessInterceptor.class));\n\t}\n\n\t@Test\n\tvoid notConfiguredWhenIssuerNotProvided() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AuthenticationProcessInterceptor.class));\n\t}\n\n\t@Test\n\tvoid notConfiguredInWebApplication() {\n\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.withConfiguration(AutoConfigurations.of(ServletWebSecurityAutoConfiguration.class,\n\t\t\t\t\tOAuth2ResourceServerAutoConfiguration.class))\n\t\t\t.with(this::serviceBean)\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AuthenticationProcessInterceptor.class));\n\t}\n\n\t@Test\n\tvoid notConfiguredInWebApplicationWithNoBindableService() {\n\t\tnew WebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.withConfiguration(AutoConfigurations.of(ServletWebSecurityAutoConfiguration.class,\n\t\t\t\t\tOAuth2ResourceServerAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AuthenticationProcessInterceptor.class));\n\t}\n\n\tprivate <R extends AbstractApplicationContextRunner<R, C, A>, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider<C>> R serviceBean(\n\t\t\tR contextRunner) {\n\t\tBindableService service = mock();\n\t\tServerServiceDefinition serviceDefinition = ServerServiceDefinition.builder(\"my-service\").build();\n\t\tgiven(service.bindService()).willReturn(serviceDefinition);\n\t\treturn contextRunner.withBean(BindableService.class, () -> service);\n\t}\n\n\tstatic class FailingApplicationFailedEventContext extends AnnotationConfigServletWebApplicationContext {\n\n\t\t@Override\n\t\tpublic void refresh() {\n\t\t\ttry {\n\t\t\t\tsuper.refresh();\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\tpublishEvent(new ApplicationFailedEvent(new SpringApplication(this), new String[0], this, ex));\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomInterceptorConfiguration {\n\n\t\t@Bean\n\t\t@GlobalServerInterceptor\n\t\tAuthenticationProcessInterceptor jwtSecurityFilterChain(GrpcSecurity grpc) throws Exception {\n\t\t\treturn grpc.authorizeRequests((requests) -> requests.allRequests().authenticated())\n\t\t\t\t.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(Customizer.withDefaults()))\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class GrpcSecurityConfiguration {\n\n\t\t@Bean\n\t\tGrpcSecurity grpcSecurity(ApplicationContext context, ObjectPostProcessor<Object> objectPostProcessor,\n\t\t\t\tAuthenticationConfiguration authenticationConfiguration) {\n\t\t\tAuthenticationManagerBuilder authenticationManagerBuilder = authenticationConfiguration\n\t\t\t\t.authenticationManagerBuilder(objectPostProcessor, context);\n\t\t\tauthenticationManagerBuilder\n\t\t\t\t.parentAuthenticationManager(authenticationConfiguration.getAuthenticationManager());\n\t\t\treturn new GrpcSecurity(objectPostProcessor, authenticationManagerBuilder, context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/security/GrpcServerSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security;\n\nimport io.grpc.BindableService;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerExecutorProvider;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.exception.GrpcExceptionHandler;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.security.AuthenticationProcessInterceptor;\nimport org.springframework.grpc.server.security.GrpcSecurity;\nimport org.springframework.grpc.server.security.SecurityContextServerInterceptor;\nimport org.springframework.grpc.server.security.SecurityGrpcExceptionHandler;\nimport org.springframework.security.config.ObjectPostProcessor;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerSecurityAutoConfiguration}.\n *\n * @author Chris Bono\n */\nclass GrpcServerSecurityAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GrpcServerSecurityAutoConfiguration.class))\n\t\t.withBean(\"noopServerLifecycle\", GrpcServerLifecycle.class, Mockito::mock);\n\n\t@Test\n\tvoid whenSpringSecurityNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ObjectPostProcessor.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BindableService.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenSpringGrpcNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerFactory.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenSpringGrpcAndSpringSecurityPresentAndUsingGrpcServletCreatesGrpcSecurity() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.withConfiguration(AutoConfigurations.of(GrpcServerSecurityAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SecurityContextServerInterceptor.class);\n\t\t\t\tassertThat(context).hasSingleBean(GrpcServerExecutorProvider.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenSpringGrpcAndSpringSecurityPresentAndUsingGrpcNativeCreatesGrpcSecurity() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.withConfiguration(AutoConfigurations.of(GrpcServerSecurityAutoConfiguration.class))\n\t\t\t.withUserConfiguration(NativeConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcSecurity.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertySetFalseThenAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GrpcServerSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertyNotSetThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenServerEnabledPropertySetTrueThenAutoConfigurationIsNotSkipped() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.grpc.server.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GrpcServerSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid grpcSecurityAutoConfiguredAsExpected() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).getBean(GrpcExceptionHandler.class).isInstanceOf(SecurityGrpcExceptionHandler.class);\n\t\t\tassertThat(context).getBean(AuthenticationProcessInterceptor.class).isNull();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class ServletConfiguration {\n\n\t\t@Bean\n\t\tGrpcServletRegistration grpcServletRegistration() {\n\t\t\treturn new GrpcServletRegistration(mock(), mock());\n\t\t}\n\n\t\t@Bean\n\t\tSecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\t\treturn http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableMethodSecurity\n\tstatic class NativeConfiguration {\n\n\t\t@Bean\n\t\tGrpcServerFactory grpcServerFactory() {\n\t\t\treturn mock();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/security/web/reactive/GrpcRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security.web.reactive;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerServiceDefinition;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.grpc.server.autoconfigure.security.web.reactive.GrpcRequest.GrpcReactiveRequestMatcher;\nimport org.springframework.boot.web.context.reactive.GenericReactiveWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.grpc.server.service.DefaultGrpcServiceDiscoverer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.http.server.reactive.MockServerHttpResponse;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult;\nimport org.springframework.web.server.adapter.DefaultServerWebExchange;\nimport org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;\nimport org.springframework.web.server.session.DefaultWebSessionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcRequest}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\nclass GrpcRequestTests {\n\n\tprivate GenericReactiveWebApplicationContext context = new GenericReactiveWebApplicationContext();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockService service1 = mock();\n\t\tgiven(service1.bindService()).willReturn(ServerServiceDefinition.builder(\"my-service\").build());\n\t\tMockService service2 = mock();\n\t\tgiven(service2.bindService()).willReturn(ServerServiceDefinition.builder(\"my-other-service\").build());\n\t\tthis.context.registerBean(\"s1\", BindableService.class, () -> service1);\n\t\tthis.context.registerBean(\"s2\", BindableService.class, () -> service2);\n\t\tthis.context.registerBean(GrpcServiceDiscoverer.class, () -> new DefaultGrpcServiceDiscoverer(this.context));\n\t\tthis.context.refresh();\n\t}\n\n\t@Test\n\tvoid whenToAnyService() {\n\t\tGrpcReactiveRequestMatcher matcher = GrpcRequest.toAnyService();\n\t\tassertThat(isMatch(matcher, \"/my-service/Method\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-service/Other\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-other-service/Other\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/notaservice\")).isFalse();\n\t}\n\n\t@Test\n\tvoid whenToAnyServiceWithExclude() {\n\t\tGrpcReactiveRequestMatcher matcher = GrpcRequest.toAnyService().excluding(\"my-other-service\");\n\t\tassertThat(isMatch(matcher, \"/my-service/Method\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-service/Other\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-other-service/Other\")).isFalse();\n\t\tassertThat(isMatch(matcher, \"/notaservice\")).isFalse();\n\t}\n\n\tprivate boolean isMatch(GrpcReactiveRequestMatcher matcher, String path) {\n\t\tMockExchange request = mockRequest(path);\n\t\tMatchResult result = matcher.matches(request).block();\n\t\treturn (result != null) && result.isMatch();\n\t}\n\n\tprivate MockExchange mockRequest(String path) {\n\t\tMockServerHttpRequest servletContext = MockServerHttpRequest.get(path).build();\n\t\tMockExchange request = new MockExchange(servletContext, this.context);\n\t\treturn request;\n\t}\n\n\tinterface MockService extends BindableService {\n\n\t}\n\n\tstatic class MockExchange extends DefaultServerWebExchange {\n\n\t\tprivate ApplicationContext context;\n\n\t\tMockExchange(MockServerHttpRequest request, ApplicationContext context) {\n\t\t\tsuper(request, new MockServerHttpResponse(), new DefaultWebSessionManager(), ServerCodecConfigurer.create(),\n\t\t\t\t\tnew AcceptHeaderLocaleContextResolver());\n\t\t\tthis.context = context;\n\t\t}\n\n\t\t@Override\n\t\tpublic ApplicationContext getApplicationContext() {\n\t\t\treturn this.context;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/security/web/servlet/GrpcRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.autoconfigure.security.web.servlet;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerServiceDefinition;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.grpc.server.autoconfigure.security.web.servlet.GrpcRequest.GrpcServletRequestMatcher;\nimport org.springframework.grpc.server.service.DefaultGrpcServiceDiscoverer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for {@link GrpcRequest}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\nclass GrpcRequestTests {\n\n\tprivate GenericWebApplicationContext context = new GenericWebApplicationContext();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockService service1 = mock();\n\t\tgiven(service1.bindService()).willReturn(ServerServiceDefinition.builder(\"my-service\").build());\n\t\tMockService service2 = mock();\n\t\tgiven(service2.bindService()).willReturn(ServerServiceDefinition.builder(\"my-other-service\").build());\n\t\tthis.context.registerBean(\"s1\", BindableService.class, () -> service1);\n\t\tthis.context.registerBean(\"s2\", BindableService.class, () -> service2);\n\t\tthis.context.registerBean(GrpcServiceDiscoverer.class, () -> new DefaultGrpcServiceDiscoverer(this.context));\n\t\tthis.context.refresh();\n\t}\n\n\t@Test\n\tvoid whenToAnyService() {\n\t\tGrpcServletRequestMatcher matcher = GrpcRequest.toAnyService();\n\t\tassertThat(isMatch(matcher, \"/my-service/Method\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-service/Other\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-other-service/Other\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/notaservice\")).isFalse();\n\t}\n\n\t@Test\n\tvoid whenToAnyServiceWithExclude() {\n\t\tGrpcServletRequestMatcher matcher = GrpcRequest.toAnyService().excluding(\"my-other-service\");\n\t\tassertThat(isMatch(matcher, \"/my-service/Method\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-service/Other\")).isTrue();\n\t\tassertThat(isMatch(matcher, \"/my-other-service/Other\")).isFalse();\n\t\tassertThat(isMatch(matcher, \"/notaservice\")).isFalse();\n\t}\n\n\tprivate boolean isMatch(GrpcServletRequestMatcher matcher, String path) {\n\t\tMockHttpServletRequest request = mockRequest(path);\n\t\treturn matcher.matches(request);\n\t}\n\n\tprivate MockHttpServletRequest mockRequest(String path) {\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\tMockHttpServletRequest request = new MockHttpServletRequest(servletContext);\n\t\trequest.setRequestURI(path);\n\t\treturn request;\n\t}\n\n\tinterface MockService extends BindableService {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/health/GrpcServerHealthTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcServerHealth}.\n *\n * @author Phillip Webb\n */\nclass GrpcServerHealthTests {\n\n\tprivate static final HealthIndicator UP = () -> Health.up().build();\n\n\tprivate static final HealthIndicator DOWN = () -> Health.down().build();\n\n\tprivate static final ReactiveHealthIndicator REACTIVE_DOWN = () -> Mono.just(Health.down().build());\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenRegistryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new GrpcServerHealth(null, null, mock()))\n\t\t\t.withMessage(\"'registry' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenComponentsIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new GrpcServerHealth(mock(), null, null))\n\t\t\t.withMessage(\"'components' must not be null\");\n\t}\n\n\t@Test\n\tvoid updateWhenHasServerComponentAndUp() {\n\t\tassertThat(updateWithServerComponent(\"test\", UP)).containsExactly(entry(\"\", ServingStatus.SERVING));\n\t}\n\n\t@Test\n\tvoid updateWhenHasServerComponentAndDown() {\n\t\tassertThat(updateWithServerComponent(\"test\", DOWN)).containsExactly(entry(\"\", ServingStatus.NOT_SERVING));\n\t}\n\n\t@Test\n\tvoid updateWhenHasServerComponentAndMissing() {\n\t\tassertThat(updateWithServerComponent(\"other\", UP)).containsExactly(entry(\"\", ServingStatus.UNKNOWN));\n\t}\n\n\tprivate Map<String, ServingStatus> updateWithServerComponent(String indicatorName, HealthIndicator indicator) {\n\t\tHealthCheckedGrpcComponent server = new TestHealthCheckedGrpcComponent(Set.of(\"test\"));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(server, Collections.emptyMap());\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(indicatorName, indicator);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\treturn result;\n\t}\n\n\t@Test\n\tvoid updateWhenHasServices() {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\", new TestHealthCheckedGrpcComponent(Set.of(\"up\")));\n\t\tservices.put(\"two\", new TestHealthCheckedGrpcComponent(Set.of(\"down\")));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(\"up\", UP);\n\t\tregistry.registerContributor(\"down\", DOWN);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.SERVING),\n\t\t\t\tentry(\"two\", ServingStatus.NOT_SERVING));\n\t}\n\n\t@Test\n\tvoid updateUsesCache() {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\", new TestHealthCheckedGrpcComponent(Set.of(\"test\")));\n\t\tservices.put(\"two\", new TestHealthCheckedGrpcComponent(Set.of(\"test\")));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tHealthIndicator contributor = mock();\n\t\tgiven(contributor.health(false)).willReturn(Health.up().build(), Health.down().build());\n\t\tregistry.registerContributor(\"test\", contributor);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.SERVING), entry(\"two\", ServingStatus.SERVING));\n\t}\n\n\t@Test\n\tvoid updateWhenHasEmptyNamedServicesDoesNotIncludeIt() {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"\", new TestHealthCheckedGrpcComponent(Set.of(\"up\")));\n\t\tservices.put(\"one\", new TestHealthCheckedGrpcComponent(Set.of(\"up\")));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(\"up\", UP);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.SERVING));\n\t}\n\n\t@Test\n\tvoid updateWhenHasFallbackRegistry() {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\", new TestHealthCheckedGrpcComponent(Set.of(\"1\")));\n\t\tservices.put(\"two\", new TestHealthCheckedGrpcComponent(Set.of(\"2\")));\n\t\tservices.put(\"three\", new TestHealthCheckedGrpcComponent(Set.of(\"3\")));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tDefaultReactiveHealthContributorRegistry fallbackRegistry = new DefaultReactiveHealthContributorRegistry();\n\t\tregistry.registerContributor(\"1\", UP);\n\t\tregistry.registerContributor(\"2\", UP);\n\t\tfallbackRegistry.registerContributor(\"2\", REACTIVE_DOWN);\n\t\tfallbackRegistry.registerContributor(\"3\", REACTIVE_DOWN);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, fallbackRegistry, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.SERVING), entry(\"two\", ServingStatus.SERVING),\n\t\t\t\tentry(\"three\", ServingStatus.NOT_SERVING));\n\t}\n\n\t@Test\n\tvoid updateWhenHasCompositeContributor() {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\", new TestHealthCheckedGrpcComponent(Set.of(\"dbs\", \"dbs/db1\", \"dbs/db2\")));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tHealthContributor contributor = CompositeHealthContributor.fromMap(Map.of(\"db1\", UP, \"db2\", DOWN));\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(\"dbs\", contributor);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.NOT_SERVING));\n\t}\n\n\t@Test\n\tvoid updateFiltersIndicatorsAndCompositeParentByName() {\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\", new TestHealthCheckedGrpcComponent(Set.of(\"dbs\", \"dbs/db1\")));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tHealthContributor contributor = CompositeHealthContributor.fromMap(Map.of(\"db1\", UP, \"db2\", DOWN));\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(\"dbs\", contributor);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.SERVING));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid updateCallsStatusAggregator() {\n\t\tStatusAggregator statusAggregator = mock();\n\t\tgiven(statusAggregator.getAggregateStatus((Set<Status>) any(Set.class))).willReturn(Status.DOWN);\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\",\n\t\t\t\tnew TestHealthCheckedGrpcComponent(Set.of(\"up\"), statusAggregator, StatusMapper.getDefault()));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(\"up\", UP);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.NOT_SERVING));\n\t\tthen(statusAggregator).should().getAggregateStatus(Set.of(Status.UP));\n\t}\n\n\t@Test\n\tvoid updateCallsStatusMapper() {\n\t\tStatusMapper statusMapper = mock();\n\t\tgiven(statusMapper.getServingStatus(Status.UP)).willReturn(ServingStatus.UNRECOGNIZED);\n\t\tMap<String, HealthCheckedGrpcComponent> services = new LinkedHashMap<>();\n\t\tservices.put(\"one\",\n\t\t\t\tnew TestHealthCheckedGrpcComponent(Set.of(\"up\"), StatusAggregator.getDefault(), statusMapper));\n\t\tHealthCheckedGrpcComponents components = new TestHealthCheckedGrpcComponents(null, services);\n\t\tDefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\t\tregistry.registerContributor(\"up\", UP);\n\t\tGrpcServerHealth health = new GrpcServerHealth(registry, null, components);\n\t\tMap<String, ServingStatus> result = new LinkedHashMap<>();\n\t\thealth.update(result::put);\n\t\tassertThat(result).containsExactly(entry(\"one\", ServingStatus.UNRECOGNIZED));\n\t\tthen(statusMapper).should().getServingStatus(Status.UP);\n\t}\n\n\tstatic class TestHealthCheckedGrpcComponents implements HealthCheckedGrpcComponents {\n\n\t\tprivate final @Nullable HealthCheckedGrpcComponent server;\n\n\t\tprivate final Map<String, HealthCheckedGrpcComponent> services;\n\n\t\tTestHealthCheckedGrpcComponents(@Nullable HealthCheckedGrpcComponent server,\n\t\t\t\tMap<String, HealthCheckedGrpcComponent> services) {\n\t\t\tthis.server = server;\n\t\t\tthis.services = services;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable HealthCheckedGrpcComponent getServer() {\n\t\t\treturn this.server;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> getServiceNames() {\n\t\t\treturn this.services.keySet();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable HealthCheckedGrpcComponent getService(String serviceName) {\n\t\t\treturn this.services.get(serviceName);\n\t\t}\n\n\t}\n\n\tprivate static class TestHealthCheckedGrpcComponent implements HealthCheckedGrpcComponent {\n\n\t\tprivate final Set<String> members;\n\n\t\tprivate final StatusAggregator statusAggregator;\n\n\t\tprivate final StatusMapper statusMapper;\n\n\t\tTestHealthCheckedGrpcComponent(Set<String> members) {\n\t\t\tthis(members, StatusAggregator.getDefault(), StatusMapper.getDefault());\n\t\t}\n\n\t\tTestHealthCheckedGrpcComponent(Set<String> members, StatusAggregator statusAggregator,\n\t\t\t\tStatusMapper statusMapper) {\n\t\t\tthis.members = members;\n\t\t\tthis.statusAggregator = statusAggregator;\n\t\t\tthis.statusMapper = statusMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isMember(String healthContributorName) {\n\t\t\treturn this.members.contains(healthContributorName);\n\t\t}\n\n\t\t@Override\n\t\tpublic StatusAggregator getStatusAggregator() {\n\t\t\treturn this.statusAggregator;\n\t\t}\n\n\t\t@Override\n\t\tpublic StatusMapper getStatusMapper() {\n\t\t\treturn this.statusMapper;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/health/StatusAggregatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StatusAggregator}.\n *\n * @author Phillip Webb\n */\nclass StatusAggregatorTests {\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenUsingDefaultInstance() {\n\t\tStatusAggregator aggregator = StatusAggregator.getDefault();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenUsingCustomOrder() {\n\t\tStatusAggregator aggregator = StatusAggregator.of(Status.UNKNOWN, Status.UP, Status.OUT_OF_SERVICE,\n\t\t\t\tStatus.DOWN);\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenHasCustomStatusAndUsingDefaultOrder() {\n\t\tStatusAggregator aggregator = StatusAggregator.getDefault();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE,\n\t\t\t\tnew Status(\"CUSTOM\"));\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenHasCustomStatusAndUsingCustomOrder() {\n\t\tStatusAggregator aggregator = StatusAggregator.of(\"DOWN\", \"OUT_OF_SERVICE\", \"UP\", \"UNKNOWN\", \"CUSTOM\");\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE,\n\t\t\t\tnew Status(\"CUSTOM\"));\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid ofWithNonUniformCodes() {\n\t\tStatusAggregator aggregator = StatusAggregator.of(\"out-of-service\", \"up\");\n\t\tStatus status = aggregator.getAggregateStatus(Status.UP, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.OUT_OF_SERVICE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/health/StatusMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.server.health;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.grpc.health.v1.HealthCheckResponse.ServingStatus;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StatusMapper}.\n *\n * @author Phillip Webb\n */\nclass StatusMapperTests {\n\n\t@Test\n\tvoid createWhenMappingsAreNullUsesDefaultMappings() {\n\t\tStatusMapper mapper = StatusMapper.of(null);\n\t\tassertThat(mapper.getServingStatus(Status.UNKNOWN)).isEqualTo(ServingStatus.UNKNOWN);\n\t\tassertThat(mapper.getServingStatus(Status.UP)).isEqualTo(ServingStatus.SERVING);\n\t\tassertThat(mapper.getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.NOT_SERVING);\n\t\tassertThat(mapper.getServingStatus(Status.OUT_OF_SERVICE)).isEqualTo(ServingStatus.NOT_SERVING);\n\t}\n\n\t@Test\n\tvoid getServingStatusReturnsMappedStatus() {\n\t\tMap<String, ServingStatus> map = new LinkedHashMap<>();\n\t\tmap.put(\"up\", ServingStatus.UNRECOGNIZED);\n\t\tmap.put(\"down\", ServingStatus.UNKNOWN);\n\t\tStatusMapper mapper = StatusMapper.of(map);\n\t\tassertThat(mapper.getServingStatus(Status.UP)).isEqualTo(ServingStatus.UNRECOGNIZED);\n\t\tassertThat(mapper.getServingStatus(Status.DOWN)).isEqualTo(ServingStatus.UNKNOWN);\n\t\tassertThat(mapper.getServingStatus(Status.OUT_OF_SERVICE)).isEqualTo(ServingStatus.SERVING);\n\t}\n\n\t@Test\n\tvoid getServingStatusWhenMappingsAreNotUniformReturnsMappedStatus() {\n\t\tMap<String, ServingStatus> map = new LinkedHashMap<>();\n\t\tmap.put(\"out-of-service\", ServingStatus.SERVING);\n\t\tStatusMapper mapper = StatusMapper.of(map);\n\t\tassertThat(mapper.getServingStatus(Status.OUT_OF_SERVICE)).isEqualTo(ServingStatus.SERVING);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot gRPC Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-grpc-client\"))\n\tapi(project(\":module:spring-boot-grpc-server\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"io.grpc:grpc-inprocess\")\n\toptional(\"io.grpc:grpc-stub\")\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.grpc:grpc-netty\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/AutoConfigureTestGrpcTransport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.grpc.server.GrpcServletRegistration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.grpc.client.GrpcChannelFactory;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\n/**\n * Annotation that can be applied to a test class to enable test in-process gRPC\n * transport. Starts a test in-process gRPC server and configures a\n * {@code GrpcChannelFactory} that will connect all targets to it.\n *\n * @author Dave Syer\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n * @see TestGrpcTransportAutoConfiguration\n */\n@Target({ ElementType.TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureTestGrpcTransport {\n\n\t/**\n\t * Enables auto-configuration of the {@link GrpcServletRegistration}. Defaults to\n\t * {@code false} since servlet registration is unnecessary when using test in-process\n\t * transport.\n\t * @return if servlet support is enabled\n\t */\n\t@PropertyMapping(\"spring.grpc.server.servlet.enabled\")\n\tboolean enableServlet() default false;\n\n\t/**\n\t * Enables auto-configuration of {@link GrpcServerFactory} beans. Defaults to\n\t * {@code false} since additional server factories are unnecessary when using test\n\t * in-process transport.\n\t * @return if server factories are enabled\n\t */\n\t@PropertyMapping(\"spring.grpc.server.factory.enabled\")\n\tboolean enableServerFactory() default false;\n\n\t/**\n\t * Enables auto-configuration of {@link GrpcChannelFactory} beans. Defaults to\n\t * {@code false} since additional channel factories are unnecessary when using test\n\t * in-process transport.\n\t * @return if channel factories are enabled\n\t */\n\t@PropertyMapping(\"spring.grpc.client.channelfactory.enabled\")\n\tboolean enableChannelFactory() default false;\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/GrpcPortInfoApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.grpc.Server;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;\n\n/**\n * {@link ApplicationContextInitializer} that sets {@link Environment} properties for the\n * ports that {@link Server gRPC servers} are actually listening on. The property\n * {@literal \"local.grpc.server.port\"} can be injected directly into tests using\n * {@link Value @Value} or obtained through the {@link Environment}.\n * <p>\n * Properties are automatically propagated up to any parent context.\n *\n * @author Dave Syer\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass GrpcPortInfoApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.addApplicationListener(new Listener(applicationContext));\n\t}\n\n\tprivate static class Listener implements ApplicationListener<GrpcServerStartedEvent> {\n\n\t\tprivate static final String PROPERTY_NAME = \"local.grpc.server.port\";\n\n\t\tprivate static final String PROPERTY_SOURCE_NAME = \"server.ports\";\n\n\t\tprivate final ConfigurableApplicationContext applicationContext;\n\n\t\tListener(ConfigurableApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(GrpcServerStartedEvent event) {\n\t\t\tGrpcServerFactory factory = event.getSource().getFactory();\n\t\t\tif (factory instanceof InProcessGrpcServerFactory || factory instanceof TestGrpcServerFactory\n\t\t\t\t\t|| event.getPort() == -1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetPortProperty(this.applicationContext, event.getPort());\n\t\t}\n\n\t\tprivate void setPortProperty(ApplicationContext context, int port) {\n\t\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\t\tsetPortProperty(configurableContext.getEnvironment(), port);\n\t\t\t}\n\t\t\tif (context.getParent() != null) {\n\t\t\t\tsetPortProperty(context.getParent(), port);\n\t\t\t}\n\t\t}\n\n\t\tprivate void setPortProperty(ConfigurableEnvironment environment, int port) {\n\t\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\t\tPropertySource<?> source = sources.get(PROPERTY_SOURCE_NAME);\n\t\t\tif (source == null) {\n\t\t\t\tsource = new MapPropertySource(PROPERTY_SOURCE_NAME, new HashMap<>());\n\t\t\t\tsources.addFirst(source);\n\t\t\t}\n\t\t\tsetPortProperty(port, source);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate void setPortProperty(int port, PropertySource<?> source) {\n\t\t\t((Map<String, Object>) source.getSource()).put(PROPERTY_NAME, port);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/LocalGrpcServerPort.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Annotation at the field or method/constructor parameter level that injects the gRPC\n * server port that was allocated at runtime. Provides a convenient alternative for\n * <code>&#064;Value(&quot;${local.grpc.server.port}&quot;)</code>.\n *\n * @author Dave Syer\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.1.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Value(\"${local.grpc.server.port}\")\npublic @interface LocalGrpcServerPort {\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/TestGrpcChannelFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport java.util.Collections;\n\nimport io.grpc.ChannelCredentials;\nimport io.grpc.inprocess.InProcessChannelBuilder;\n\nimport org.springframework.grpc.client.ClientInterceptorsConfigurer;\nimport org.springframework.grpc.client.DefaultGrpcChannelFactory;\nimport org.springframework.grpc.client.GrpcChannelFactory;\n\n/**\n * {@link GrpcChannelFactory} for testing with in-process transport.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass TestGrpcChannelFactory extends DefaultGrpcChannelFactory<InProcessChannelBuilder> {\n\n\tTestGrpcChannelFactory(String address, ClientInterceptorsConfigurer interceptorsConfigurer) {\n\t\tsuper(Collections.emptyList(), interceptorsConfigurer);\n\t\tsetVirtualTargets((path) -> address);\n\t}\n\n\t@Override\n\tpublic boolean supports(String target) {\n\t\treturn true;\n\t}\n\n\t@Override\n\tprotected InProcessChannelBuilder newChannelBuilder(String target, ChannelCredentials creds) {\n\t\treturn InProcessChannelBuilder.forName(target);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/TestGrpcServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport java.util.Collections;\n\nimport io.grpc.inprocess.InProcessServerBuilder;\n\nimport org.springframework.grpc.server.DefaultGrpcServerFactory;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\n/**\n * {@link GrpcServerFactory} for testing with in-process transport.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass TestGrpcServerFactory extends DefaultGrpcServerFactory<InProcessServerBuilder> {\n\n\tTestGrpcServerFactory(String address) {\n\t\tsuper(address, Collections.emptyList(), null, null, null);\n\t}\n\n\t@Override\n\tprotected InProcessServerBuilder newServerBuilder() {\n\t\treturn InProcessServerBuilder.forName(address());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/TestGrpcTransportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport io.grpc.BindableService;\nimport io.grpc.inprocess.InProcessServerBuilder;\nimport io.grpc.stub.AbstractStub;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.grpc.client.ClientInterceptorsConfigurer;\nimport org.springframework.grpc.client.GrpcChannelFactory;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\nimport org.springframework.grpc.server.ServerServiceDefinitionFilter;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.service.GrpcServiceConfigurer;\nimport org.springframework.grpc.server.service.GrpcServiceDiscoverer;\n\n/**\n * Auto-configuration for an in-process test gRPC transport.\n *\n * @author Chris Bono\n * @author Dave Syer\n * @author Andrey Litvitski\n * @author Phillip Webb\n * @since 4.1.0\n * @see AutoConfigureTestGrpcTransport\n */\n@AutoConfiguration(before = { GrpcServerAutoConfiguration.class, GrpcClientAutoConfiguration.class })\n@ConditionalOnClass({ InProcessServerBuilder.class, InProcessGrpcServerFactory.class })\npublic final class TestGrpcTransportAutoConfiguration {\n\n\tprivate static final String address = InProcessServerBuilder.generateName();\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(GrpcServerFactory.class)\n\t@ConditionalOnBean(BindableService.class)\n\tstatic class TestGrpcServerTransportAutoConfiguration {\n\n\t\t@Bean\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tTestGrpcServerFactory testGrpcServerFactory(GrpcServiceDiscoverer serviceDiscoverer,\n\t\t\t\tGrpcServiceConfigurer serviceConfigurer, ObjectProvider<ServerServiceDefinitionFilter> serviceFilter) {\n\t\t\tTestGrpcServerFactory factory = new TestGrpcServerFactory(address);\n\t\t\tserviceFilter.ifAvailable(factory::setServiceFilter);\n\t\t\tserviceDiscoverer.findServices()\n\t\t\t\t.stream()\n\t\t\t\t.map((spec) -> serviceConfigurer.configure(spec, factory))\n\t\t\t\t.forEach(factory::addService);\n\t\t\treturn factory;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tGrpcServerLifecycle testGrpcServerLifecycle(TestGrpcServerFactory testGrpcServerFactory,\n\t\t\t\tGrpcServerProperties properties, ApplicationEventPublisher eventPublisher) {\n\t\t\treturn new GrpcServerLifecycle(testGrpcServerFactory, properties.getShutdown().getGracePeriod(),\n\t\t\t\t\teventPublisher);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ AbstractStub.class, GrpcChannelFactory.class })\n\tstatic class TestGrpcClientTransportAutoConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tClientInterceptorsConfigurer grpcClientInterceptorsConfigurer(ApplicationContext applicationContext) {\n\t\t\treturn new ClientInterceptorsConfigurer(applicationContext);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tTestGrpcChannelFactory testGrpcChannelFactory(ClientInterceptorsConfigurer interceptorsConfigurer) {\n\t\t\treturn new TestGrpcChannelFactory(address, interceptorsConfigurer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/java/org/springframework/boot/grpc/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring gRPC tests.\n */\n@NullMarked\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/resources/META-INF/spring/org.springframework.boot.grpc.test.autoconfigure.AutoConfigureTestGrpcTransport.imports",
    "content": "org.springframework.boot.grpc.test.autoconfigure.TestGrpcTransportAutoConfiguration"
  },
  {
    "path": "module/spring-boot-grpc-test/src/main/resources/META-INF/spring.factories",
    "content": "# Application Context Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.grpc.test.autoconfigure.GrpcPortInfoApplicationContextInitializer\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/test/java/org/springframework/boot/grpc/test/autoconfigure/AutoConfigureTestGrpcTransportOverrideTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureTestGrpcTransport} with override attributes.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@AutoConfigureTestGrpcTransport(enableServlet = true, enableServerFactory = true, enableChannelFactory = true)\nclass AutoConfigureTestGrpcTransportOverrideTests {\n\n\t@Test\n\tvoid setsEnabledPropertiesToTrue(@Autowired Environment environment) {\n\t\tassertThat(environment.getProperty(\"spring.grpc.server.servlet.enabled\", Boolean.class)).isTrue();\n\t\tassertThat(environment.getProperty(\"spring.grpc.server.factory.enabled\", Boolean.class)).isTrue();\n\t\tassertThat(environment.getProperty(\"spring.grpc.client.channelfactory.enabled\", Boolean.class)).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/test/java/org/springframework/boot/grpc/test/autoconfigure/AutoConfigureTestGrpcTransportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureTestGrpcTransport}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@AutoConfigureTestGrpcTransport\nclass AutoConfigureTestGrpcTransportTests {\n\n\t@Test\n\tvoid setsEnabledPropertiesToFalse(@Autowired Environment environment) {\n\t\tassertThat(environment.getProperty(\"spring.grpc.server.servlet.enabled\", Boolean.class)).isFalse();\n\t\tassertThat(environment.getProperty(\"spring.grpc.server.factory.enabled\", Boolean.class)).isFalse();\n\t\tassertThat(environment.getProperty(\"spring.grpc.client.channelfactory.enabled\", Boolean.class)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/test/java/org/springframework/boot/grpc/test/autoconfigure/GrpcPortInfoApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport io.grpc.Server;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GrpcServerFactory;\nimport org.springframework.grpc.server.InProcessGrpcServerFactory;\nimport org.springframework.grpc.server.NettyGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link GrpcPortInfoApplicationContextInitializer}.\n *\n * @author Phillip Webb\n */\nclass GrpcPortInfoApplicationContextInitializerTests {\n\n\tprivate static final String PORT_PROPERTY = \"local.grpc.server.port\";\n\n\t@Test\n\tvoid whenServerHasAddressInitializerSetsPortProperty() {\n\t\tNettyGrpcServerFactory factory = mock();\n\t\ttestListener(factory, 65535, \"65535\");\n\t}\n\n\t@Test\n\tvoid whenServerHasNoAddressInitializerSetsNoPortProperty() {\n\t\tNettyGrpcServerFactory factory = mock();\n\t\ttestListener(factory, -1, null);\n\t}\n\n\t@Test\n\tvoid whenInProcessGrpcServerFactorySetsNoPortProperty() {\n\t\tInProcessGrpcServerFactory factory = mock();\n\t\ttestListener(factory, 65535, null);\n\t}\n\n\t@Test\n\tvoid whenTestGrpcServerFactorySetsNoPortProperty() {\n\t\tTestGrpcServerFactory factory = mock();\n\t\ttestListener(factory, 65535, null);\n\t}\n\n\tprivate void testListener(GrpcServerFactory factory, int port, @Nullable String expected) {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class)) {\n\t\t\tcontext.getBean(GrpcPortInfoApplicationContextInitializer.class).initialize(context);\n\t\t\tGrpcServerLifecycle lifecycle = mock();\n\t\t\tServer server = mock();\n\t\t\tgiven(lifecycle.getFactory()).willReturn(factory);\n\t\t\tGrpcServerStartedEvent event = new GrpcServerStartedEvent(lifecycle, server, \"localhost\", port);\n\t\t\tcontext.publishEvent(event);\n\t\t\tassertThat(context.getEnvironment().getProperty(PORT_PROPERTY)).isEqualTo(expected);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tGrpcPortInfoApplicationContextInitializer grpcPortInfoApplicationContextInitializer() {\n\t\t\treturn new GrpcPortInfoApplicationContextInitializer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/test/java/org/springframework/boot/grpc/test/autoconfigure/TestGrpcChannelFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport io.grpc.ManagedChannel;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TestGrpcChannelFactory}.\n *\n * @author Phillip Webb\n */\nclass TestGrpcChannelFactoryTests {\n\n\tprivate TestGrpcChannelFactory factory = new TestGrpcChannelFactory(\"test\", mock());\n\n\t@Test\n\tvoid supportsReturnsTrue() {\n\t\tassertThat(this.factory.supports(\"inprocess:test\")).isTrue();\n\t\tassertThat(this.factory.supports(\"static:*:0\")).isTrue();\n\t}\n\n\t@Test\n\tvoid createChannelReturnsInProcessChannel() {\n\t\tManagedChannel channel = this.factory.createChannel(\"static:*:0\");\n\t\tassertThat(channel).extracting(\"delegate.originalTransportFactory\")\n\t\t\t.satisfies((transportFactory) -> assertThat(transportFactory.getClass().getName()).contains(\"InProcess\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/test/java/org/springframework/boot/grpc/test/autoconfigure/TestGrpcServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport io.grpc.Server;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestGrpcServerFactory}.\n *\n * @author Phillip Webb\n */\nclass TestGrpcServerFactoryTests {\n\n\tprivate TestGrpcServerFactory factory = new TestGrpcServerFactory(\"test\");\n\n\t@Test\n\tvoid createServerReturnsInProcessServer() {\n\t\tServer server = this.factory.createServer();\n\t\tassertThat(server).extracting(\"transportServer\")\n\t\t\t.satisfies((transportServer) -> assertThat(transportServer.getClass().getName()).contains(\"InProcess\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-grpc-test/src/test/java/org/springframework/boot/grpc/test/autoconfigure/TestGrpcTransportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.grpc.test.autoconfigure;\n\nimport io.grpc.BindableService;\nimport io.grpc.ServerServiceDefinition;\nimport io.grpc.stub.AbstractStub;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;\nimport org.springframework.boot.grpc.server.autoconfigure.GrpcServerServicesAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.grpc.client.GrpcChannelFactory;\nimport org.springframework.grpc.server.GrpcServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TestGrpcTransportAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass TestGrpcTransportAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfiguration = AutoConfigurations.of(\n\t\t\tTestGrpcTransportAutoConfiguration.class, GrpcServerAutoConfiguration.class,\n\t\t\tGrpcServerServicesAutoConfiguration.class, SslAutoConfiguration.class, GrpcClientAutoConfiguration.class);\n\n\tprivate final BindableService service = mock();\n\n\tprivate final ServerServiceDefinition serviceDefinition = ServerServiceDefinition.builder(\"my-service\").build();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(autoConfiguration)\n\t\t.withBean(BindableService.class, () -> this.service);\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tgiven(this.service.bindService()).willReturn(this.serviceDefinition);\n\t}\n\n\t@Test\n\tvoid createsTestGrpcServerFactoryBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(TestGrpcServerFactory.class));\n\t}\n\n\t@Test\n\tvoid createsGrpcServerLifecycleBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"testGrpcServerLifecycle\"));\n\t}\n\n\t@Test\n\tvoid whenNoBindableServiceDoesNotCreateServerBeans() {\n\t\tnew ApplicationContextRunner().withConfiguration(autoConfiguration).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(TestGrpcServerFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(\"testGrpcServerLifecycle\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenNoGrpcServerFactoryClassDoesNotCreateServerBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerFactory.class)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(TestGrpcServerFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(\"testGrpcServerLifecycle\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid createsTestGrpcChannelFactoryBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(TestGrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid whenNoAbstractStubClassDoesNotCreateClientBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(AbstractStub.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TestGrpcChannelFactory.class));\n\t}\n\n\t@Test\n\tvoid whenNoGrpcChannelFactoryClassDoesNotCreateClientBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(GrpcChannelFactory.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TestGrpcChannelFactory.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot GSON\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"com.google.code.gson:gson\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/java/org/springframework/boot/gson/autoconfigure/GsonAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.Strictness;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Gson.\n *\n * @author David Liu\n * @author Ivan Golovko\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Gson.class)\n@EnableConfigurationProperties(GsonProperties.class)\npublic final class GsonAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {\n\t\tGsonBuilder builder = new GsonBuilder();\n\t\tcustomizers.forEach((c) -> c.customize(builder));\n\t\treturn builder;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGson gson(GsonBuilder gsonBuilder) {\n\t\treturn gsonBuilder.create();\n\t}\n\n\t@Bean\n\tStandardGsonBuilderCustomizer standardGsonBuilderCustomizer(GsonProperties gsonProperties) {\n\t\treturn new StandardGsonBuilderCustomizer(gsonProperties);\n\t}\n\n\tstatic final class StandardGsonBuilderCustomizer implements GsonBuilderCustomizer, Ordered {\n\n\t\tprivate final GsonProperties properties;\n\n\t\tStandardGsonBuilderCustomizer(GsonProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(GsonBuilder builder) {\n\t\t\tGsonProperties properties = this.properties;\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getGenerateNonExecutableJson).whenTrue().toCall(builder::generateNonExecutableJson);\n\t\t\tmap.from(properties::getExcludeFieldsWithoutExposeAnnotation)\n\t\t\t\t.whenTrue()\n\t\t\t\t.toCall(builder::excludeFieldsWithoutExposeAnnotation);\n\t\t\tmap.from(properties::getSerializeNulls).whenTrue().toCall(builder::serializeNulls);\n\t\t\tmap.from(properties::getEnableComplexMapKeySerialization)\n\t\t\t\t.whenTrue()\n\t\t\t\t.toCall(builder::enableComplexMapKeySerialization);\n\t\t\tmap.from(properties::getDisableInnerClassSerialization)\n\t\t\t\t.whenTrue()\n\t\t\t\t.toCall(builder::disableInnerClassSerialization);\n\t\t\tmap.from(properties::getLongSerializationPolicy).to(builder::setLongSerializationPolicy);\n\t\t\tmap.from(properties::getFieldNamingPolicy).to(builder::setFieldNamingPolicy);\n\t\t\tmap.from(properties::getPrettyPrinting).whenTrue().toCall(builder::setPrettyPrinting);\n\t\t\tmap.from(properties::getStrictness).to(strictnessOrLeniency(builder));\n\t\t\tmap.from(properties::getDisableHtmlEscaping).whenTrue().toCall(builder::disableHtmlEscaping);\n\t\t\tmap.from(properties::getDateFormat).to(builder::setDateFormat);\n\t\t}\n\n\t\t@SuppressWarnings(\"deprecation\")\n\t\tprivate Consumer<GsonProperties.Strictness> strictnessOrLeniency(GsonBuilder builder) {\n\t\t\tif (ClassUtils.isPresent(\"com.google.gson.Strictness\", getClass().getClassLoader())) {\n\t\t\t\treturn (strictness) -> builder.setStrictness(Strictness.valueOf(strictness.name()));\n\t\t\t}\n\t\t\treturn (strictness) -> {\n\t\t\t\tif (strictness == GsonProperties.Strictness.LENIENT) {\n\t\t\t\t\tbuilder.setLenient();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/java/org/springframework/boot/gson/autoconfigure/GsonBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link GsonBuilder} to fine-tune its auto-configuration before it creates a\n * {@link Gson} instance.\n *\n * @author Ivan Golovko\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface GsonBuilderCustomizer {\n\n\t/**\n\t * Customize the GsonBuilder.\n\t * @param gsonBuilder the GsonBuilder to customize\n\t */\n\tvoid customize(GsonBuilder gsonBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/java/org/springframework/boot/gson/autoconfigure/GsonProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport com.google.gson.FieldNamingPolicy;\nimport com.google.gson.Gson;\nimport com.google.gson.LongSerializationPolicy;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties to configure {@link Gson}.\n *\n * @author Ivan Golovko\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.gson\")\npublic class GsonProperties {\n\n\t/**\n\t * Whether to generate non-executable JSON by prefixing the output with some special\n\t * text.\n\t */\n\tprivate @Nullable Boolean generateNonExecutableJson;\n\n\t/**\n\t * Whether to exclude all fields from consideration for serialization or\n\t * deserialization that do not have the \"Expose\" annotation.\n\t */\n\tprivate @Nullable Boolean excludeFieldsWithoutExposeAnnotation;\n\n\t/**\n\t * Whether to serialize null fields.\n\t */\n\tprivate @Nullable Boolean serializeNulls;\n\n\t/**\n\t * Whether to enable serialization of complex map keys (i.e. non-primitives).\n\t */\n\tprivate @Nullable Boolean enableComplexMapKeySerialization;\n\n\t/**\n\t * Whether to exclude inner classes during serialization.\n\t */\n\tprivate @Nullable Boolean disableInnerClassSerialization;\n\n\t/**\n\t * Serialization policy for Long and long types.\n\t */\n\tprivate @Nullable LongSerializationPolicy longSerializationPolicy;\n\n\t/**\n\t * Naming policy that should be applied to an object's field during serialization and\n\t * deserialization.\n\t */\n\tprivate @Nullable FieldNamingPolicy fieldNamingPolicy;\n\n\t/**\n\t * Whether to output serialized JSON that fits in a page for pretty printing.\n\t */\n\tprivate @Nullable Boolean prettyPrinting;\n\n\t/**\n\t * Sets how strictly the RFC 8259 specification will be enforced when reading and\n\t * writing JSON.\n\t */\n\tprivate @Nullable Strictness strictness;\n\n\t/**\n\t * Whether to disable the escaping of HTML characters such as '<', '>', etc.\n\t */\n\tprivate @Nullable Boolean disableHtmlEscaping;\n\n\t/**\n\t * Format to use when serializing Date objects.\n\t */\n\tprivate @Nullable String dateFormat;\n\n\tpublic @Nullable Boolean getGenerateNonExecutableJson() {\n\t\treturn this.generateNonExecutableJson;\n\t}\n\n\tpublic void setGenerateNonExecutableJson(@Nullable Boolean generateNonExecutableJson) {\n\t\tthis.generateNonExecutableJson = generateNonExecutableJson;\n\t}\n\n\tpublic @Nullable Boolean getExcludeFieldsWithoutExposeAnnotation() {\n\t\treturn this.excludeFieldsWithoutExposeAnnotation;\n\t}\n\n\tpublic void setExcludeFieldsWithoutExposeAnnotation(@Nullable Boolean excludeFieldsWithoutExposeAnnotation) {\n\t\tthis.excludeFieldsWithoutExposeAnnotation = excludeFieldsWithoutExposeAnnotation;\n\t}\n\n\tpublic @Nullable Boolean getSerializeNulls() {\n\t\treturn this.serializeNulls;\n\t}\n\n\tpublic void setSerializeNulls(@Nullable Boolean serializeNulls) {\n\t\tthis.serializeNulls = serializeNulls;\n\t}\n\n\tpublic @Nullable Boolean getEnableComplexMapKeySerialization() {\n\t\treturn this.enableComplexMapKeySerialization;\n\t}\n\n\tpublic void setEnableComplexMapKeySerialization(@Nullable Boolean enableComplexMapKeySerialization) {\n\t\tthis.enableComplexMapKeySerialization = enableComplexMapKeySerialization;\n\t}\n\n\tpublic @Nullable Boolean getDisableInnerClassSerialization() {\n\t\treturn this.disableInnerClassSerialization;\n\t}\n\n\tpublic void setDisableInnerClassSerialization(@Nullable Boolean disableInnerClassSerialization) {\n\t\tthis.disableInnerClassSerialization = disableInnerClassSerialization;\n\t}\n\n\tpublic @Nullable LongSerializationPolicy getLongSerializationPolicy() {\n\t\treturn this.longSerializationPolicy;\n\t}\n\n\tpublic void setLongSerializationPolicy(@Nullable LongSerializationPolicy longSerializationPolicy) {\n\t\tthis.longSerializationPolicy = longSerializationPolicy;\n\t}\n\n\tpublic @Nullable FieldNamingPolicy getFieldNamingPolicy() {\n\t\treturn this.fieldNamingPolicy;\n\t}\n\n\tpublic void setFieldNamingPolicy(@Nullable FieldNamingPolicy fieldNamingPolicy) {\n\t\tthis.fieldNamingPolicy = fieldNamingPolicy;\n\t}\n\n\tpublic @Nullable Boolean getPrettyPrinting() {\n\t\treturn this.prettyPrinting;\n\t}\n\n\tpublic void setPrettyPrinting(@Nullable Boolean prettyPrinting) {\n\t\tthis.prettyPrinting = prettyPrinting;\n\t}\n\n\tpublic @Nullable Strictness getStrictness() {\n\t\treturn this.strictness;\n\t}\n\n\tpublic void setStrictness(@Nullable Strictness strictness) {\n\t\tthis.strictness = strictness;\n\t}\n\n\tpublic void setLenient(@Nullable Boolean lenient) {\n\t\tsetStrictness((lenient != null && lenient) ? Strictness.LENIENT : Strictness.STRICT);\n\t}\n\n\tpublic @Nullable Boolean getDisableHtmlEscaping() {\n\t\treturn this.disableHtmlEscaping;\n\t}\n\n\tpublic void setDisableHtmlEscaping(@Nullable Boolean disableHtmlEscaping) {\n\t\tthis.disableHtmlEscaping = disableHtmlEscaping;\n\t}\n\n\tpublic @Nullable String getDateFormat() {\n\t\treturn this.dateFormat;\n\t}\n\n\tpublic void setDateFormat(@Nullable String dateFormat) {\n\t\tthis.dateFormat = dateFormat;\n\t}\n\n\t/**\n\t * Enumeration of levels of strictness. Values are the same as those on\n\t * {@link com.google.gson.Strictness} that was introduced in Gson 2.11. To maximize\n\t * backwards compatibility, the Gson enum is not used directly.\n\t */\n\tpublic enum Strictness {\n\n\t\t/**\n\t\t * Lenient compliance.\n\t\t */\n\t\tLENIENT,\n\n\t\t/**\n\t\t * Strict compliance with some small deviations for legacy reasons.\n\t\t */\n\t\tLEGACY_STRICT,\n\n\t\t/**\n\t\t * Strict compliance.\n\t\t */\n\t\tSTRICT\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/java/org/springframework/boot/gson/autoconfigure/GsonTesterTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport com.google.gson.Gson;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.test.autoconfigure.json.ConditionalOnJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonMarshalTesterRuntimeHints;\nimport org.springframework.boot.test.autoconfigure.json.JsonTesterFactoryBean;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.context.annotation.Scope;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link GsonTester}.\n *\n * @author Phjllip Webb\n */\n@AutoConfiguration(after = GsonAutoConfiguration.class)\n@ConditionalOnJsonTesters\nfinal class GsonTesterTestAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnBean(Gson.class)\n\t@ImportRuntimeHints(GsonTesterRuntimeHints.class)\n\tFactoryBean<GsonTester<?>> gsonTesterFactoryBean(Gson gson) {\n\t\treturn new JsonTesterFactoryBean<>(GsonTester.class, gson);\n\t}\n\n\tstatic class GsonTesterRuntimeHints extends JsonMarshalTesterRuntimeHints {\n\n\t\tGsonTesterRuntimeHints() {\n\t\t\tsuper(GsonTester.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/java/org/springframework/boot/gson/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for GSON.\n */\n@NullMarked\npackage org.springframework.boot.gson.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.gson.lenient\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.gson.strictness\",\n        \"since\": \"3.4.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.gson.autoconfigure.GsonAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJson.imports",
    "content": "org.springframework.boot.gson.autoconfigure.GsonAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-gson/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters.imports",
    "content": "org.springframework.boot.gson.autoconfigure.GsonTesterTestAutoConfiguration"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/Gson210AutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport com.google.gson.Gson;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GsonAutoConfiguration} with Gson 2.10.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"gson-*.jar\")\n@ClassPathOverrides(\"com.google.code.gson:gson:2.10\")\nclass Gson210AutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class));\n\n\t@Test\n\tvoid gsonRegistration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":1}\");\n\t\t});\n\t}\n\n\tpublic class DataObject {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate Long data = 1L;\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final @Nullable String owner = null;\n\n\t\tpublic void setData(Long data) {\n\t\t\tthis.data = data;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/GsonAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport com.google.gson.ExclusionStrategy;\nimport com.google.gson.FieldAttributes;\nimport com.google.gson.FieldNamingPolicy;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.LongSerializationPolicy;\nimport com.google.gson.Strictness;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.skyscreamer.jsonassert.JSONAssert;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GsonAutoConfiguration}.\n *\n * @author David Liu\n * @author Ivan Golovko\n * @author Stephane Nicoll\n */\nclass GsonAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class));\n\n\t@Test\n\tvoid gsonRegistration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":1}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid generateNonExecutableJsonTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.generate-non-executable-json:true\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isNotEqualTo(\"{\\\"data\\\":1}\");\n\t\t\tassertThat(gson.toJson(new DataObject())).endsWith(\"{\\\"data\\\":1}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid generateNonExecutableJsonFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.generate-non-executable-json:false\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":1}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid excludeFieldsWithoutExposeAnnotationTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.exclude-fields-without-expose-annotation:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{}\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid excludeFieldsWithoutExposeAnnotationFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.exclude-fields-without-expose-annotation:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":1}\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid serializeNullsTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.serialize-nulls:true\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.serializeNulls()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid serializeNullsFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.serialize-nulls:false\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.serializeNulls()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableComplexMapKeySerializationTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.enable-complex-map-key-serialization:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\t\tMap<DataObject, String> original = new LinkedHashMap<>();\n\t\t\t\toriginal.put(new DataObject(), \"a\");\n\t\t\t\tassertThat(gson.toJson(original)).isEqualTo(\"[[{\\\"data\\\":1},\\\"a\\\"]]\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableComplexMapKeySerializationFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.enable-complex-map-key-serialization:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\t\tMap<DataObject, String> original = new LinkedHashMap<>();\n\t\t\t\toriginal.put(new DataObject(), \"a\");\n\t\t\t\tassertThat(gson.toJson(original)).contains(DataObject.class.getName()).doesNotContain(\"\\\"data\\\":\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid notDisableInnerClassSerialization() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tWrapperObject wrapperObject = new WrapperObject();\n\t\t\tassertThat(gson.toJson(wrapperObject.new NestedObject())).isEqualTo(\"{\\\"data\\\":\\\"nested\\\"}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid disableInnerClassSerializationTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.disable-inner-class-serialization:true\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tWrapperObject wrapperObject = new WrapperObject();\n\t\t\tassertThat(gson.toJson(wrapperObject.new NestedObject())).isEqualTo(\"null\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid disableInnerClassSerializationFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.disable-inner-class-serialization:false\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tWrapperObject wrapperObject = new WrapperObject();\n\t\t\tassertThat(gson.toJson(wrapperObject.new NestedObject())).isEqualTo(\"{\\\"data\\\":\\\"nested\\\"}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid withLongSerializationPolicy() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.long-serialization-policy:\" + LongSerializationPolicy.STRING)\n\t\t\t.run((context) -> {\n\t\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":\\\"1\\\"}\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withFieldNamingPolicy() {\n\t\tFieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.UPPER_CAMEL_CASE;\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.field-naming-policy:\" + fieldNamingPolicy).run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.fieldNamingStrategy()).isEqualTo(fieldNamingPolicy);\n\t\t});\n\t}\n\n\t@Test\n\tvoid additionalGsonBuilderCustomization() {\n\t\tthis.contextRunner.withUserConfiguration(GsonBuilderCustomizerConfig.class).run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customGsonBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(GsonBuilderConfig.class).run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tJSONAssert.assertEquals(\"{\\\"data\\\":1,\\\"owner\\\":null}\", gson.toJson(new DataObject()), true);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withPrettyPrintingTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.pretty-printing:true\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\n  \\\"data\\\": 1\\n}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid withPrettyPrintingFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.pretty-printing:false\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":1}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid withoutStrictness() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson).hasFieldOrPropertyWithValue(\"strictness\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withStrictnessStrict() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.strictness:strict\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson).hasFieldOrPropertyWithValue(\"strictness\", Strictness.STRICT);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withStrictnessLegacyStrict() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.strictness:legacy-strict\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson).hasFieldOrPropertyWithValue(\"strictness\", Strictness.LEGACY_STRICT);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withStrictnessLenient() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.strictness:lenient\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson).hasFieldOrPropertyWithValue(\"strictness\", Strictness.LENIENT);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withoutDisableHtmlEscaping() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.htmlSafe()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid withDisableHtmlEscapingTrue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.disable-html-escaping:true\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.htmlSafe()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid withDisableHtmlEscapingFalse() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.disable-html-escaping:false\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tassertThat(gson.htmlSafe()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.gson.date-format:H\").run((context) -> {\n\t\t\tGson gson = context.getBean(Gson.class);\n\t\t\tZonedDateTime dateTime = ZonedDateTime.of(1988, 6, 25, 20, 30, 0, 0, ZoneId.systemDefault());\n\t\t\tassertThat(gson.toJson(Date.from(dateTime.toInstant()))).isEqualTo(\"\\\"20\\\"\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GsonBuilderCustomizerConfig {\n\n\t\t@Bean\n\t\tGsonBuilderCustomizer customSerializationExclusionStrategy() {\n\t\t\treturn (gsonBuilder) -> gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {\n\t\t\t\t@Override\n\t\t\t\tpublic boolean shouldSkipField(FieldAttributes fieldAttributes) {\n\t\t\t\t\treturn \"data\".equals(fieldAttributes.getName());\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic boolean shouldSkipClass(Class<?> aClass) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GsonBuilderConfig {\n\n\t\t@Bean\n\t\tGsonBuilder customGsonBuilder() {\n\t\t\treturn new GsonBuilder().serializeNulls();\n\t\t}\n\n\t}\n\n\tpublic class DataObject {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate Long data = 1L;\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tprivate final @Nullable String owner = null;\n\n\t\tpublic void setData(Long data) {\n\t\t\tthis.data = data;\n\t\t}\n\n\t}\n\n\tpublic class WrapperObject {\n\n\t\t@SuppressWarnings(\"unused\")\n\t\tclass NestedObject {\n\n\t\t\tprivate final String data = \"nested\";\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/GsonPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport com.google.gson.Strictness;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GsonProperties}.\n *\n * @author Andy Wilkinson\n */\nclass GsonPropertiesTests {\n\n\t@Test\n\tvoid valuesOfOurStrictnessMatchValuesOfGsonsStrictness() {\n\t\tassertThat(namesOf(GsonProperties.Strictness.values())).isEqualTo(namesOf(Strictness.values()));\n\t}\n\n\tprivate List<String> namesOf(Enum<?>[] input) {\n\t\treturn Stream.of(input).map(Enum::name).toList();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/GsonTesterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.autoconfigure.json.JsonTestersAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GsonTesterTestAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass GsonTesterAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner().withConfiguration(AutoConfigurations\n\t\t.of(JsonTestersAutoConfiguration.class, GsonAutoConfiguration.class, GsonTesterTestAutoConfiguration.class));\n\n\t@Test\n\tvoid hintsAreContributed() {\n\t\tthis.runner.withPropertyValues(\"spring.test.jsontesters.enabled=true\").prepare((context) -> {\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\t\tnew ApplicationContextAotGenerator().processAheadOfTime(\n\t\t\t\t\t(GenericApplicationContext) context.getSourceApplicationContext(), generationContext);\n\t\t\tReflectionHintsPredicates hints = RuntimeHintsPredicates.reflection();\n\t\t\tassertThat(hints.onType(GsonTester.class)).accepts(generationContext.getRuntimeHints());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/GsonAutoConfigureJsonIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest;\n\nimport com.google.gson.Gson;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Integration tests for {@link AutoConfigureJson @AutoConfigureJson} with Gson.\n *\n * @author Andy Wilkinson\n */\n@AutoConfigureJson\n@ExtendWith(SpringExtension.class)\nclass GsonAutoConfigureJsonIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid gsonIsAvailable() {\n\t\tassertThatNoException().isThrownBy(() -> this.context.getBean(Gson.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/JsonTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Application for testing of {@link JsonTest @JsonTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\nclass JsonTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/JsonTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.gson.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.gson.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Eddú Meléndez\n */\n@JsonTest\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestIntegrationTests {\n\n\t@Autowired\n\tprivate GsonTester<ExampleBasicObject> gsonJson;\n\n\t@Test\n\tvoid gson() throws Exception {\n\t\tExampleBasicObject object = new ExampleBasicObject();\n\t\tobject.setValue(\"spring\");\n\t\tassertThat(this.gsonJson.write(object)).isEqualToJson(\"example.json\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/JsonTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.gson.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.gson.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Phillip Webb\n */\n@JsonTest\n@AutoConfigureJsonTesters(enabled = false)\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired(required = false)\n\tprivate GsonTester<ExampleBasicObject> gsonTester;\n\n\t@Test\n\tvoid gson() {\n\t\tassertThat(this.gsonTester).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/SpringBootTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.gson.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.gson.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureJsonTesters\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass SpringBootTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired\n\tprivate GsonTester<ExampleBasicObject> gsonTester;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.gsonTester).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/app/ExampleBasicObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest.app;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Example object to read/write as JSON.\n *\n * @author Phillip Webb\n */\npublic class ExampleBasicObject {\n\n\tprivate @Nullable String value;\n\n\tpublic @Nullable String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj != null && obj.getClass() == getClass()) {\n\t\t\treturn Objects.equals(this.value, ((ExampleBasicObject) obj).value);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hashCode(this.value);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/app/ExampleJsonApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.gson.autoconfigure.jsontest.app;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link JsonTest @JsonTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleJsonApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/app/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.gson.autoconfigure.jsontest.app;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/java/org/springframework/boot/gson/autoconfigure/jsontest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.gson.autoconfigure.jsontest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-gson/src/test/resources/org/springframework/boot/gson/autoconfigure/jsontest/example.json",
    "content": "{\n   \"value\" : \"spring\"\n}\n"
  },
  {
    "path": "module/spring-boot-h2console/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot H2\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"jakarta.servlet:jakarta.servlet-api\")\n\tapi(\"com.h2database:h2\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-jdbc\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-h2console/src/main/java/org/springframework/boot/h2console/autoconfigure/H2ConsoleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.h2console.autoconfigure;\n\nimport java.sql.Connection;\nimport java.util.List;\nimport java.util.Objects;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.h2.server.web.JakartaWebServlet;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.h2console.autoconfigure.H2ConsoleProperties.Settings;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.log.LogMessage;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for H2's web console.\n *\n * @author Andy Wilkinson\n * @author Marten Deinum\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(JakartaWebServlet.class)\n@ConditionalOnBooleanProperty(\"spring.h2.console.enabled\")\n@EnableConfigurationProperties(H2ConsoleProperties.class)\npublic final class H2ConsoleAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(H2ConsoleAutoConfiguration.class);\n\n\tprivate final H2ConsoleProperties properties;\n\n\tH2ConsoleAutoConfiguration(H2ConsoleProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\tServletRegistrationBean<JakartaWebServlet> h2Console() {\n\t\tString path = this.properties.getPath();\n\t\tString urlMapping = path + (path.endsWith(\"/\") ? \"*\" : \"/*\");\n\t\tServletRegistrationBean<JakartaWebServlet> registration = new ServletRegistrationBean<>(new JakartaWebServlet(),\n\t\t\t\turlMapping);\n\t\tconfigureH2ConsoleSettings(registration, this.properties.getSettings());\n\t\treturn registration;\n\t}\n\n\t@Bean\n\tH2ConsoleLogger h2ConsoleLogger(ObjectProvider<DataSource> dataSources) {\n\t\treturn new H2ConsoleLogger(dataSources, this.properties.getPath());\n\t}\n\n\tprivate void configureH2ConsoleSettings(ServletRegistrationBean<JakartaWebServlet> registration,\n\t\t\tSettings settings) {\n\t\tif (settings.isTrace()) {\n\t\t\tregistration.addInitParameter(\"trace\", \"\");\n\t\t}\n\t\tif (settings.isWebAllowOthers()) {\n\t\t\tregistration.addInitParameter(\"webAllowOthers\", \"\");\n\t\t}\n\t\tif (settings.getWebAdminPassword() != null) {\n\t\t\tregistration.addInitParameter(\"webAdminPassword\", settings.getWebAdminPassword());\n\t\t}\n\t}\n\n\tstatic class H2ConsoleLogger {\n\n\t\tH2ConsoleLogger(ObjectProvider<DataSource> dataSources, String path) {\n\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\t\t\twithThreadContextClassLoader(classLoader, () -> log(getConnectionUrls(dataSources), path));\n\t\t\t}\n\t\t}\n\n\t\tprivate void withThreadContextClassLoader(ClassLoader classLoader, Runnable action) {\n\t\t\tClassLoader previous = Thread.currentThread().getContextClassLoader();\n\t\t\ttry {\n\t\t\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\t\t\taction.run();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tThread.currentThread().setContextClassLoader(previous);\n\t\t\t}\n\t\t}\n\n\t\tprivate List<String> getConnectionUrls(ObjectProvider<DataSource> dataSources) {\n\t\t\treturn dataSources.orderedStream(ObjectProvider.UNFILTERED)\n\t\t\t\t.map(this::getConnectionUrl)\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.toList();\n\t\t}\n\n\t\tprivate @Nullable String getConnectionUrl(DataSource dataSource) {\n\t\t\ttry (Connection connection = dataSource.getConnection()) {\n\t\t\t\treturn \"'\" + connection.getMetaData().getURL() + \"'\";\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprivate void log(List<String> urls, String path) {\n\t\t\tif (!urls.isEmpty()) {\n\t\t\t\tlogger.info(LogMessage.format(\"H2 console available at '%s'. %s available at %s\", path,\n\t\t\t\t\t\t(urls.size() > 1) ? \"Databases\" : \"Database\", String.join(\", \", urls)));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-h2console/src/main/java/org/springframework/boot/h2console/autoconfigure/H2ConsoleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.h2console.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration properties for H2's console.\n *\n * @author Andy Wilkinson\n * @author Marten Deinum\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.h2.console\")\npublic class H2ConsoleProperties {\n\n\t/**\n\t * Path at which the console is available.\n\t */\n\tprivate String path = \"/h2-console\";\n\n\t/**\n\t * Whether to enable the console.\n\t */\n\tprivate boolean enabled;\n\n\tprivate final Settings settings = new Settings();\n\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\tpublic void setPath(String path) {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tAssert.isTrue(path.length() > 1, \"'path' must have length greater than 1\");\n\t\tAssert.isTrue(path.startsWith(\"/\"), \"'path' must start with '/'\");\n\t\tthis.path = path;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Settings getSettings() {\n\t\treturn this.settings;\n\t}\n\n\tpublic static class Settings {\n\n\t\t/**\n\t\t * Whether to enable trace output.\n\t\t */\n\t\tprivate boolean trace;\n\n\t\t/**\n\t\t * Whether to enable remote access.\n\t\t */\n\t\tprivate boolean webAllowOthers;\n\n\t\t/**\n\t\t * Password to access preferences and tools of H2 Console.\n\t\t */\n\t\tprivate @Nullable String webAdminPassword;\n\n\t\tpublic boolean isTrace() {\n\t\t\treturn this.trace;\n\t\t}\n\n\t\tpublic void setTrace(boolean trace) {\n\t\t\tthis.trace = trace;\n\t\t}\n\n\t\tpublic boolean isWebAllowOthers() {\n\t\t\treturn this.webAllowOthers;\n\t\t}\n\n\t\tpublic void setWebAllowOthers(boolean webAllowOthers) {\n\t\t\tthis.webAllowOthers = webAllowOthers;\n\t\t}\n\n\t\tpublic @Nullable String getWebAdminPassword() {\n\t\t\treturn this.webAdminPassword;\n\t\t}\n\n\t\tpublic void setWebAdminPassword(@Nullable String webAdminPassword) {\n\t\t\tthis.webAdminPassword = webAdminPassword;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-h2console/src/main/java/org/springframework/boot/h2console/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for H2's Console.\n */\n@NullMarked\npackage org.springframework.boot.h2console.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-h2console/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.h2console.autoconfigure.H2ConsoleAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-h2console/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.h2.console.enabled=true\n"
  },
  {
    "path": "module/spring-boot-h2console/src/test/java/org/springframework/boot/h2console/autoconfigure/H2ConsoleAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.h2console.autoconfigure;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBindException;\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link H2ConsoleAutoConfiguration}\n *\n * @author Andy Wilkinson\n * @author Marten Deinum\n * @author Stephane Nicoll\n * @author Shraddha Yeole\n * @author Phillip Webb\n */\nclass H2ConsoleAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(H2ConsoleAutoConfiguration.class));\n\n\t@Test\n\tvoid consoleIsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ServletRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid propertyCanEnableConsole() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.h2.console.enabled=true\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ServletRegistrationBean.class);\n\t\t\tServletRegistrationBean<?> registrationBean = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registrationBean.getUrlMappings()).contains(\"/h2-console/*\");\n\t\t\tassertThat(registrationBean.getInitParameters()).doesNotContainKey(\"trace\");\n\t\t\tassertThat(registrationBean.getInitParameters()).doesNotContainKey(\"webAllowOthers\");\n\t\t\tassertThat(registrationBean.getInitParameters()).doesNotContainKey(\"webAdminPassword\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPathMustBeginWithASlash() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.h2.console.enabled=true\", \"spring.h2.console.path=custom\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(BeanCreationException.class)\n\t\t\t\t\t.cause()\n\t\t\t\t\t.isInstanceOf(ConfigurationPropertiesBindException.class)\n\t\t\t\t\t.cause()\n\t\t\t\t\t.isInstanceOf(BindException.class)\n\t\t\t\t\t.hasMessageContaining(\"Failed to bind properties under 'spring.h2.console'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customPathWithTrailingSlash() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.h2.console.enabled=true\", \"spring.h2.console.path=/custom/\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ServletRegistrationBean.class);\n\t\t\t\tServletRegistrationBean<?> registrationBean = context.getBean(ServletRegistrationBean.class);\n\t\t\t\tassertThat(registrationBean.getUrlMappings()).contains(\"/custom/*\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customPath() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.h2.console.enabled=true\", \"spring.h2.console.path=/custom\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ServletRegistrationBean.class);\n\t\t\t\tServletRegistrationBean<?> registrationBean = context.getBean(ServletRegistrationBean.class);\n\t\t\t\tassertThat(registrationBean.getUrlMappings()).contains(\"/custom/*\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customInitParameters() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\", \"spring.h2.console.settings.trace=true\",\n\t\t\t\t\t\"spring.h2.console.settings.web-allow-others=true\",\n\t\t\t\t\t\"spring.h2.console.settings.web-admin-password=abcd\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ServletRegistrationBean.class);\n\t\t\t\tServletRegistrationBean<?> registrationBean = context.getBean(ServletRegistrationBean.class);\n\t\t\t\tassertThat(registrationBean.getUrlMappings()).contains(\"/h2-console/*\");\n\t\t\t\tassertThat(registrationBean.getInitParameters()).containsEntry(\"trace\", \"\");\n\t\t\t\tassertThat(registrationBean.getInitParameters()).containsEntry(\"webAllowOthers\", \"\");\n\t\t\t\tassertThat(registrationBean.getInitParameters()).containsEntry(\"webAdminPassword\", \"abcd\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@ExtendWith(OutputCaptureExtension.class)\n\tvoid singleDataSourceUrlIsLoggedWhenOnlyOneAvailable(CapturedOutput output) {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\ttry (Connection connection = context.getBean(DataSource.class).getConnection()) {\n\t\t\t\t\tassertThat(output).contains(\"H2 console available at '/h2-console'. Database available at '\"\n\t\t\t\t\t\t\t+ connection.getMetaData().getURL() + \"'\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\t@ExtendWith(OutputCaptureExtension.class)\n\tvoid noDataSourceIsLoggedWhenNoneAvailable(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(FailingDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\")\n\t\t\t.run((context) -> assertThat(output).doesNotContain(\"H2 console available\"));\n\t}\n\n\t@Test\n\t@ExtendWith(OutputCaptureExtension.class)\n\tvoid allDataSourceUrlsAreLoggedWhenMultipleAvailable(CapturedOutput output) {\n\t\tClassLoader webAppClassLoader = new URLClassLoader(new URL[0]);\n\t\tthis.contextRunner.withClassLoader(webAppClassLoader)\n\t\t\t.withUserConfiguration(FailingDataSourceConfiguration.class, MultiDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\")\n\t\t\t.run((context) -> assertThat(output).contains(\n\t\t\t\t\t\"H2 console available at '/h2-console'. Databases available at 'someJdbcUrl', 'anotherJdbcUrl'\"));\n\t}\n\n\t@Test\n\t@ExtendWith(OutputCaptureExtension.class)\n\tvoid allDataSourceUrlsAreLoggedWhenNonCandidate(CapturedOutput output) {\n\t\tClassLoader webAppClassLoader = new URLClassLoader(new URL[0]);\n\t\tthis.contextRunner.withClassLoader(webAppClassLoader)\n\t\t\t.withUserConfiguration(FailingDataSourceConfiguration.class, MultiDataSourceNonCandidateConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\")\n\t\t\t.run((context) -> assertThat(output).contains(\n\t\t\t\t\t\"H2 console available at '/h2-console'. Databases available at 'someJdbcUrl', 'anotherJdbcUrl'\"));\n\t}\n\n\t@Test\n\tvoid h2ConsoleShouldNotFailIfDatabaseConnectionFails() {\n\t\tthis.contextRunner.withUserConfiguration(FailingDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\")\n\t\t\t.run((context) -> assertThat(context.isRunning()).isTrue());\n\t}\n\n\t@Test\n\t@ExtendWith(OutputCaptureExtension.class)\n\tvoid dataSourceIsNotInitializedEarly(CapturedOutput output) {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(H2ConsoleAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(EarlyInitializationConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.h2.console.enabled=true\", \"server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\ttry (Connection connection = context.getBean(DataSource.class).getConnection()) {\n\t\t\t\t\tassertThat(output).contains(\"H2 console available at '/h2-console'. Database available at '\"\n\t\t\t\t\t\t\t+ connection.getMetaData().getURL() + \"'\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate static DataSource mockDataSource(String url, ClassLoader classLoader) throws SQLException {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tgiven(dataSource.getConnection()).will((invocation) -> {\n\t\t\tassertThat(Thread.currentThread().getContextClassLoader()).isEqualTo(classLoader);\n\t\t\tConnection connection = mock(Connection.class);\n\t\t\tDatabaseMetaData metadata = mock(DatabaseMetaData.class);\n\t\t\tgiven(connection.getMetaData()).willReturn(metadata);\n\t\t\tgiven(metadata.getURL()).willReturn(url);\n\t\t\treturn connection;\n\t\t});\n\t\treturn dataSource;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FailingDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() throws SQLException {\n\t\t\tDataSource dataSource = mock(DataSource.class);\n\t\t\tgiven(dataSource.getConnection()).willThrow(IllegalStateException.class);\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultiDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tDataSource anotherDataSource() throws SQLException {\n\t\t\treturn mockDataSource(\"anotherJdbcUrl\", getClass().getClassLoader());\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tDataSource someDataSource() throws SQLException {\n\t\t\treturn mockDataSource(\"someJdbcUrl\", getClass().getClassLoader());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultiDataSourceNonCandidateConfiguration {\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tDataSource anotherDataSource() throws SQLException {\n\t\t\treturn mockDataSource(\"anotherJdbcUrl\", getClass().getClassLoader());\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\t@Order(0)\n\t\tDataSource nonDefaultDataSource() throws SQLException {\n\t\t\treturn mockDataSource(\"someJdbcUrl\", getClass().getClassLoader());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EarlyInitializationConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource(ConfigurableApplicationContext applicationContext) {\n\t\t\tassertThat(applicationContext.getBeanFactory().isConfigurationFrozen()).isTrue();\n\t\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-h2console/src/test/java/org/springframework/boot/h2console/autoconfigure/H2ConsolePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.h2console.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link H2ConsoleProperties}.\n *\n * @author Madhura Bhave\n */\nclass H2ConsolePropertiesTests {\n\n\t@Test\n\tvoid pathMustNotBeEmpty() {\n\t\tH2ConsoleProperties properties = new H2ConsoleProperties();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> properties.setPath(\"\"))\n\t\t\t.withMessageContaining(\"'path' must have length greater than 1\");\n\t}\n\n\t@Test\n\tvoid pathMustHaveLengthGreaterThanOne() {\n\t\tH2ConsoleProperties properties = new H2ConsoleProperties();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> properties.setPath(\"/\"))\n\t\t\t.withMessageContaining(\"'path' must have length greater than 1\");\n\t}\n\n\t@Test\n\tvoid customPathMustBeginWithASlash() {\n\t\tH2ConsoleProperties properties = new H2ConsoleProperties();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> properties.setPath(\"custom\"))\n\t\t\t.withMessageContaining(\"'path' must start with '/'\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Hateoas\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.hateoas:spring-hateoas\")\n\n\timplementation(project(\":module:spring-boot-jackson\"))\n\timplementation(\"org.springframework:spring-webmvc\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/main/java/org/springframework/boot/hateoas/autoconfigure/HateoasProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hateoas.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties Properties} for Spring HATEOAS.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.hateoas\")\npublic class HateoasProperties {\n\n\t/**\n\t * Whether application/hal+json responses should be sent to requests that accept\n\t * application/json.\n\t */\n\tprivate boolean useHalAsDefaultJsonMediaType = true;\n\n\tpublic boolean isUseHalAsDefaultJsonMediaType() {\n\t\treturn this.useHalAsDefaultJsonMediaType;\n\t}\n\n\tpublic void setUseHalAsDefaultJsonMediaType(boolean useHalAsDefaultJsonMediaType) {\n\t\tthis.useHalAsDefaultJsonMediaType = useHalAsDefaultJsonMediaType;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/main/java/org/springframework/boot/hateoas/autoconfigure/HypermediaAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hateoas.autoconfigure;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.hateoas.EntityModel;\nimport org.springframework.hateoas.client.LinkDiscoverers;\nimport org.springframework.hateoas.config.EnableHypermediaSupport;\nimport org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;\nimport org.springframework.hateoas.mediatype.hal.HalConfiguration;\nimport org.springframework.http.MediaType;\nimport org.springframework.plugin.core.Plugin;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring HATEOAS's\n * {@link EnableHypermediaSupport @EnableHypermediaSupport}.\n *\n * @author Roy Clarkson\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ EntityModel.class, RequestMapping.class, RequestMappingHandlerAdapter.class, Plugin.class,\n\t\tJsonMapper.class })\n@ConditionalOnWebApplication\n@EnableConfigurationProperties(HateoasProperties.class)\npublic final class HypermediaAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBooleanProperty(name = \"spring.hateoas.use-hal-as-default-json-media-type\", matchIfMissing = true)\n\tHalConfiguration applicationJsonHalConfiguration() {\n\t\treturn new HalConfiguration().withMediaType(MediaType.APPLICATION_JSON);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(LinkDiscoverers.class)\n\t@EnableHypermediaSupport(type = HypermediaType.HAL)\n\tstatic class HypermediaConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/main/java/org/springframework/boot/hateoas/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring HATEOAS.\n */\n@NullMarked\npackage org.springframework.boot.hateoas.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.hateoas.autoconfigure.HypermediaAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.hateoas.autoconfigure.HypermediaAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/test/java/org/springframework/boot/hateoas/autoconfigure/HypermediaAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hateoas.autoconfigure;\n\nimport java.util.Optional;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.hateoas.autoconfigure.HypermediaAutoConfiguration.HypermediaConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.hateoas.MediaTypes;\nimport org.springframework.hateoas.RepresentationModel;\nimport org.springframework.hateoas.client.LinkDiscoverer;\nimport org.springframework.hateoas.client.LinkDiscoverers;\nimport org.springframework.hateoas.config.EnableHypermediaSupport;\nimport org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;\nimport org.springframework.hateoas.mediatype.hal.HalLinkDiscoverer;\nimport org.springframework.hateoas.server.EntityLinks;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HypermediaAutoConfiguration}.\n *\n * @author Roy Clarkson\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass HypermediaAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(BaseConfig.class);\n\n\t@Test\n\tvoid autoConfigurationWhenSpringMvcNotOnClasspathShouldBackOff() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(RequestMappingHandlerAdapter.class))\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(HypermediaConfiguration.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid linkDiscoverersCreated() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tLinkDiscoverers discoverers = context.getBean(LinkDiscoverers.class);\n\t\t\tassertThat(discoverers).isNotNull();\n\t\t\tOptional<LinkDiscoverer> discoverer = discoverers.getLinkDiscovererFor(MediaTypes.HAL_JSON);\n\t\t\tassertThat(discoverer).containsInstanceOf(HalLinkDiscoverer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid entityLinksCreated() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tEntityLinks discoverers = context.getBean(EntityLinks.class);\n\t\t\tassertThat(discoverers).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid doesBackOffIfEnableHypermediaSupportIsDeclaredManually() {\n\t\tthis.contextRunner.withUserConfiguration(EnableHypermediaSupportConfig.class)\n\t\t\t.withPropertyValues(\"spring.jackson.serialization.INDENT_OUTPUT:true\")\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(HypermediaConfiguration.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid whenUsingTheDefaultConfigurationThenMappingJacksonConverterCanWriteHateoasTypeAsApplicationJson() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRequestMappingHandlerAdapter handlerAdapter = context.getBean(RequestMappingHandlerAdapter.class);\n\t\t\tOptional<HttpMessageConverter<?>> mappingJacksonConverter = handlerAdapter.getMessageConverters()\n\t\t\t\t.stream()\n\t\t\t\t.filter(JacksonJsonHttpMessageConverter.class::isInstance)\n\t\t\t\t.findFirst();\n\t\t\tassertThat(mappingJacksonConverter).hasValueSatisfying(\n\t\t\t\t\t(converter) -> assertThat(converter.canWrite(RepresentationModel.class, MediaType.APPLICATION_JSON))\n\t\t\t\t\t\t.isTrue());\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHalIsNotTheDefaultJsonMediaTypeThenMappingJacksonConverterCannotWriteHateoasTypeAsApplicationJson() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.hateoas.use-hal-as-default-json-media-type:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tRequestMappingHandlerAdapter handlerAdapter = context.getBean(RequestMappingHandlerAdapter.class);\n\t\t\t\tOptional<HttpMessageConverter<?>> mappingJacksonConverter = handlerAdapter.getMessageConverters()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter(JacksonJsonHttpMessageConverter.class::isInstance)\n\t\t\t\t\t.findFirst();\n\t\t\t\tassertThat(mappingJacksonConverter).hasValueSatisfying((converter) -> assertThat(\n\t\t\t\t\t\tconverter.canWrite(RepresentationModel.class, MediaType.APPLICATION_JSON))\n\t\t\t\t\t.isFalse());\n\t\t\t});\n\t}\n\n\t@EnableWebMvc\n\t@ImportAutoConfiguration(HypermediaAutoConfiguration.class)\n\tstatic class BaseConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableHypermediaSupport(type = HypermediaType.HAL)\n\tstatic class EnableHypermediaSupportConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/test/java/org/springframework/boot/hateoas/autoconfigure/HypermediaAutoConfigurationWithoutJacksonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hateoas.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.mock.web.MockServletContext;\n\n/**\n * Tests for {@link HypermediaAutoConfiguration} when Jackson is not on the classpath.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"jackson-*.jar\")\nclass HypermediaAutoConfigurationWithoutJacksonTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@Test\n\tvoid jacksonRelatedConfigurationBacksOff() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(BaseConfig.class);\n\t\tthis.context.setServletContext(new MockServletContext());\n\t\tthis.context.refresh();\n\t}\n\n\t@ImportAutoConfiguration(HypermediaAutoConfiguration.class)\n\tstatic class BaseConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hateoas/src/test/java/org/springframework/boot/hateoas/autoconfigure/HypermediaWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hateoas.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.hateoas.EntityModel;\nimport org.springframework.hateoas.Link;\nimport org.springframework.hateoas.LinkRelation;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link WebMvcTest @WebMvcTest} and Spring HATEOAS.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass HypermediaWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid plainResponse() {\n\t\tassertThat(this.mvc.get().uri(\"/hateoas/plain\")).hasContentType(\"application/json\");\n\t}\n\n\t@Test\n\tvoid hateoasResponse() {\n\t\tassertThat(this.mvc.get().uri(\"/hateoas/resource\")).hasContentType(\"application/hal+json\");\n\t}\n\n\t@SpringBootConfiguration\n\t@Import(HateoasController.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@RestController\n\t@RequestMapping(\"/hateoas\")\n\tstatic class HateoasController {\n\n\t\t@RequestMapping(\"/resource\")\n\t\tEntityModel<Map<String, String>> resource() {\n\t\t\treturn EntityModel.of(new HashMap<>(), Link.of(\"self\", LinkRelation.of(\"https://api.example.com\")));\n\t\t}\n\n\t\t@RequestMapping(\"/plain\")\n\t\tMap<String, String> plain() {\n\t\t\treturn new HashMap<>();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Hazelcast\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"com.hazelcast:hazelcast\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-hibernate\"))\n\toptional(\"com.hazelcast:hazelcast-spring\")\n\toptional(\"org.slf4j:slf4j-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-hibernate\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-testcontainers\")))\n\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/java/org/springframework/boot/hazelcast/docker/compose/HazelcastDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.docker.compose;\n\nimport java.util.UUID;\n\nimport com.hazelcast.client.HazelcastClient;\nimport com.hazelcast.client.config.ClientConfig;\nimport com.hazelcast.config.Config;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.map.IMap;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link HazelcastDockerComposeConnectionDetailsFactory}.\n *\n * @author Dmytro Nosan\n */\nclass HazelcastDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"hazelcast-compose.yaml\", image = TestImage.HAZELCAST)\n\tvoid runCreatesConnectionDetails(HazelcastConnectionDetails connectionDetails) {\n\t\tClientConfig config = connectionDetails.getClientConfig();\n\t\tassertThat(config.getClusterName()).isEqualTo(Config.DEFAULT_CLUSTER_NAME);\n\t\tverifyConnection(config);\n\t}\n\n\t@DockerComposeTest(composeFile = \"hazelcast-cluster-name-compose.yaml\", image = TestImage.HAZELCAST)\n\tvoid runCreatesConnectionDetailsCustomClusterName(HazelcastConnectionDetails connectionDetails) {\n\t\tClientConfig config = connectionDetails.getClientConfig();\n\t\tassertThat(config.getClusterName()).isEqualTo(\"spring-boot\");\n\t\tverifyConnection(config);\n\t}\n\n\tprivate static void verifyConnection(ClientConfig config) {\n\t\tHazelcastInstance hazelcastInstance = HazelcastClient.newHazelcastClient(config);\n\t\ttry {\n\t\t\tIMap<String, String> map = hazelcastInstance.getMap(UUID.randomUUID().toString());\n\t\t\tmap.put(\"docker\", \"compose\");\n\t\t\tassertThat(map.get(\"docker\")).isEqualTo(\"compose\");\n\t\t}\n\t\tfinally {\n\t\t\thazelcastInstance.shutdown();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/java/org/springframework/boot/hazelcast/testcontainers/CustomClusterNameHazelcastContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.testcontainers;\n\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\nimport com.hazelcast.client.config.ClientConfig;\nimport com.hazelcast.client.impl.clientside.HazelcastClientProxy;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.map.IMap;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.HazelcastContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastContainerConnectionDetailsFactory} with a custom hazelcast\n * cluster name.\n *\n * @author Dmytro Nosan\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass CustomClusterNameHazelcastContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final HazelcastContainer hazelcast = TestImage.container(HazelcastContainer.class)\n\t\t.withClusterName(\"spring-boot\");\n\n\t@Autowired(required = false)\n\tprivate HazelcastConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate HazelcastInstance hazelcastInstance;\n\n\t@Test\n\tvoid connectionCanBeMadeToHazelcastContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tassertThat(this.hazelcastInstance).satisfies(clusterName(\"spring-boot\"));\n\t\tIMap<String, String> map = this.hazelcastInstance.getMap(UUID.randomUUID().toString());\n\t\tmap.put(\"test\", \"containers\");\n\t\tassertThat(map.get(\"test\")).isEqualTo(\"containers\");\n\t}\n\n\tprivate static Consumer<HazelcastInstance> clusterName(String name) {\n\t\treturn (hazelcastInstance) -> {\n\t\t\tassertThat(hazelcastInstance).isInstanceOf(HazelcastClientProxy.class);\n\t\t\tHazelcastClientProxy proxy = (HazelcastClientProxy) hazelcastInstance;\n\t\t\tassertThat(proxy.getClientConfig()).extracting(ClientConfig::getClusterName).isEqualTo(name);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(HazelcastAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/java/org/springframework/boot/hazelcast/testcontainers/HazelcastContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.testcontainers;\n\nimport java.util.UUID;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.map.IMap;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.HazelcastContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastContainerConnectionDetailsFactory}.\n *\n * @author Dmytro Nosan\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass HazelcastContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final HazelcastContainer hazelcast = TestImage.container(HazelcastContainer.class);\n\n\t@Autowired(required = false)\n\tprivate HazelcastConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate HazelcastInstance hazelcastInstance;\n\n\t@Test\n\tvoid connectionCanBeMadeToHazelcastContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tIMap<String, String> map = this.hazelcastInstance.getMap(UUID.randomUUID().toString());\n\t\tmap.put(\"test\", \"containers\");\n\t\tassertThat(map.get(\"test\")).isEqualTo(\"containers\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(HazelcastAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/resources/org/springframework/boot/hazelcast/docker/compose/hazelcast-cluster-name-compose.yaml",
    "content": "services:\n  hazelcast:\n    image: '{imageName}'\n    environment:\n      HZ_CLUSTERNAME: \"spring-boot\"\n    ports:\n      - '5701'\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/resources/org/springframework/boot/hazelcast/docker/compose/hazelcast-compose.yaml",
    "content": "services:\n  hazelcast:\n    image: '{imageName}'\n    ports:\n      - '5701'\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.core.HazelcastInstance;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Hazelcast IMDG. Creates a\n * {@link HazelcastInstance} based on explicit configuration or when a default\n * configuration file is found in the environment.\n *\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 4.0.0\n * @see HazelcastConfigResourceCondition\n */\n@AutoConfiguration\n@ConditionalOnClass(HazelcastInstance.class)\n@EnableConfigurationProperties(HazelcastProperties.class)\n@Import({ HazelcastClientConfiguration.class, HazelcastServerConfiguration.class })\npublic final class HazelcastAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastClientConfigAvailableCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\n\nimport com.hazelcast.client.config.ClientConfigRecognizer;\nimport com.hazelcast.config.ConfigStream;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HazelcastConfigResourceCondition} that checks if the\n * {@code spring.hazelcast.config} configuration key is defined.\n *\n * @author Stephane Nicoll\n */\nclass HazelcastClientConfigAvailableCondition extends HazelcastConfigResourceCondition {\n\n\tHazelcastClientConfigAvailableCondition() {\n\t\tsuper(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY, \"file:./hazelcast-client.xml\",\n\t\t\t\t\"classpath:/hazelcast-client.xml\", \"file:./hazelcast-client.yaml\", \"classpath:/hazelcast-client.yaml\",\n\t\t\t\t\"file:./hazelcast-client.yml\", \"classpath:/hazelcast-client.yml\");\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tif (context.getEnvironment().containsProperty(HAZELCAST_CONFIG_PROPERTY)) {\n\t\t\tConditionOutcome configValidationOutcome = HazelcastClientValidation.clientConfigOutcome(context,\n\t\t\t\t\tHAZELCAST_CONFIG_PROPERTY, startConditionMessage());\n\t\t\treturn (configValidationOutcome != null) ? configValidationOutcome : ConditionOutcome\n\t\t\t\t.match(startConditionMessage().foundExactly(\"property \" + HAZELCAST_CONFIG_PROPERTY));\n\t\t}\n\t\treturn getResourceOutcome(context, metadata);\n\t}\n\n\tstatic class HazelcastClientValidation {\n\n\t\tstatic @Nullable ConditionOutcome clientConfigOutcome(ConditionContext context, String propertyName,\n\t\t\t\tBuilder builder) {\n\t\t\tString resourcePath = context.getEnvironment().getProperty(propertyName);\n\t\t\tAssert.state(resourcePath != null, \"'resourcePath' must not be null\");\n\t\t\tResource resource = context.getResourceLoader().getResource(resourcePath);\n\t\t\tif (!resource.exists()) {\n\t\t\t\treturn ConditionOutcome.noMatch(builder.because(\"Hazelcast configuration does not exist\"));\n\t\t\t}\n\t\t\ttry (InputStream in = resource.getInputStream()) {\n\t\t\t\tboolean clientConfig = new ClientConfigRecognizer().isRecognized(new ConfigStream(in));\n\t\t\t\treturn new ConditionOutcome(clientConfig, existingConfigurationOutcome(resource, clientConfig));\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tprivate static String existingConfigurationOutcome(Resource resource, boolean client) throws IOException {\n\t\t\tURL location = resource.getURL();\n\t\t\treturn client ? \"Hazelcast client configuration detected at '\" + location + \"'\"\n\t\t\t\t\t: \"Hazelcast server configuration detected  at '\" + location + \"'\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.client.HazelcastClient;\nimport com.hazelcast.core.HazelcastInstance;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Configuration for Hazelcast client.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(HazelcastClient.class)\n@ConditionalOnMissingBean(HazelcastInstance.class)\n@Import({ HazelcastConnectionDetailsConfiguration.class, HazelcastClientInstanceConfiguration.class })\nclass HazelcastClientConfiguration {\n\n\tstatic final String CONFIG_SYSTEM_PROPERTY = \"hazelcast.client.config\";\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastClientInstanceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.client.HazelcastClient;\nimport com.hazelcast.client.config.ClientConfig;\nimport com.hazelcast.core.HazelcastInstance;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration for Hazelcast client instance.\n *\n * @author Dmytro Nosan\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBean(HazelcastConnectionDetails.class)\nclass HazelcastClientInstanceConfiguration {\n\n\t@Bean\n\tHazelcastInstance hazelcastInstance(HazelcastConnectionDetails hazelcastConnectionDetails) {\n\t\tClientConfig config = hazelcastConnectionDetails.getClientConfig();\n\t\treturn (!StringUtils.hasText(config.getInstanceName())) ? HazelcastClient.newHazelcastClient(config)\n\t\t\t\t: HazelcastClient.getOrCreateHazelcastClient(config);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastConfigCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.config.Config;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * auto-configured Hazelcast server {@link Config configuration}.\n *\n * @author Jaromir Hamala\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface HazelcastConfigCustomizer {\n\n\t/**\n\t * Customize the configuration.\n\t * @param config the {@link Config} to customize\n\t */\n\tvoid customize(Config config);\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastConfigResourceCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ResourceCondition;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link SpringBootCondition} used to check if the Hazelcast configuration is available.\n * This either kicks in if a default configuration has been found or if configurable\n * property referring to the resource to use has been set.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Vedran Pavic\n * @since 4.0.0\n */\npublic abstract class HazelcastConfigResourceCondition extends ResourceCondition {\n\n\tprotected static final String HAZELCAST_CONFIG_PROPERTY = \"spring.hazelcast.config\";\n\n\tprivate final String configSystemProperty;\n\n\tprotected HazelcastConfigResourceCondition(String configSystemProperty, String... resourceLocations) {\n\t\tsuper(\"Hazelcast\", HAZELCAST_CONFIG_PROPERTY, resourceLocations);\n\t\tAssert.notNull(configSystemProperty, \"'configSystemProperty' must not be null\");\n\t\tthis.configSystemProperty = configSystemProperty;\n\t}\n\n\t@Override\n\tprotected ConditionOutcome getResourceOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tif (System.getProperty(this.configSystemProperty) != null) {\n\t\t\treturn ConditionOutcome\n\t\t\t\t.match(startConditionMessage().because(\"System property '\" + this.configSystemProperty + \"' is set.\"));\n\t\t}\n\t\treturn super.getResourceOutcome(context, metadata);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.client.config.ClientConfig;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a client connection to a Hazelcast instance.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\npublic interface HazelcastConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * The {@link ClientConfig} for Hazelcast client.\n\t * @return the client config\n\t */\n\tClientConfig getClientConfig();\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastConnectionDetailsConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.client.config.ClientConfig;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * {@link Configuration} for providing {@link HazelcastConnectionDetails}.\n *\n * @author Dmytro Nosan\n * @author Moritz Halbritter\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(HazelcastConnectionDetails.class)\nclass HazelcastConnectionDetailsConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(ClientConfig.class)\n\t@Conditional(HazelcastClientConfigAvailableCondition.class)\n\tstatic class HazelcastClientConfigFileConfiguration {\n\n\t\t@Bean\n\t\tHazelcastConnectionDetails hazelcastConnectionDetails(HazelcastProperties properties,\n\t\t\t\tResourceLoader resourceLoader) {\n\t\t\treturn new PropertiesHazelcastConnectionDetails(properties, resourceLoader);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(ClientConfig.class)\n\tstatic class HazelcastClientConfigConfiguration {\n\n\t\t@Bean\n\t\tHazelcastConnectionDetails hazelcastConnectionDetails(ClientConfig config) {\n\t\t\treturn () -> config;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastJpaDependencyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport jakarta.persistence.EntityManagerFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AllNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastJpaDependencyAutoConfiguration.HazelcastInstanceEntityManagerFactoryDependsOnConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\n\n/**\n * Additional configuration to ensure that {@link EntityManagerFactory} beans depend on\n * the {@code hazelcastInstance} bean.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = HazelcastAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\")\n@ConditionalOnClass({ HazelcastInstance.class, LocalContainerEntityManagerFactoryBean.class })\n@Import(HazelcastInstanceEntityManagerFactoryDependsOnConfiguration.class)\npublic final class HazelcastJpaDependencyAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(EntityManagerFactoryDependsOnPostProcessor.class)\n\t@Conditional(OnHazelcastAndJpaCondition.class)\n\t@Import(HazelcastInstanceEntityManagerFactoryDependsOnPostProcessor.class)\n\tstatic class HazelcastInstanceEntityManagerFactoryDependsOnConfiguration {\n\n\t}\n\n\tstatic class HazelcastInstanceEntityManagerFactoryDependsOnPostProcessor\n\t\t\textends EntityManagerFactoryDependsOnPostProcessor {\n\n\t\tHazelcastInstanceEntityManagerFactoryDependsOnPostProcessor() {\n\t\t\tsuper(\"hazelcastInstance\");\n\t\t}\n\n\t}\n\n\tstatic class OnHazelcastAndJpaCondition extends AllNestedConditions {\n\n\t\tOnHazelcastAndJpaCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnBean(name = \"hazelcastInstance\")\n\t\tstatic class HasHazelcastInstance {\n\n\t\t}\n\n\t\t@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)\n\t\tstatic class HasJpa {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration properties for the hazelcast integration.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.hazelcast\")\npublic class HazelcastProperties {\n\n\t/**\n\t * The location of the configuration file to use to initialize Hazelcast.\n\t */\n\tprivate @Nullable Resource config;\n\n\tpublic @Nullable Resource getConfig() {\n\t\treturn this.config;\n\t}\n\n\tpublic void setConfig(@Nullable Resource config) {\n\t\tthis.config = config;\n\t}\n\n\t/**\n\t * Resolve the config location if set.\n\t * @return the location or {@code null} if it is not set\n\t * @throws IllegalArgumentException if the config attribute is set to an unknown\n\t * location\n\t */\n\tpublic @Nullable Resource resolveConfigLocation() {\n\t\tResource config = this.config;\n\t\tif (config == null) {\n\t\t\treturn null;\n\t\t}\n\t\tAssert.state(config.exists(), () -> \"Hazelcast configuration does not exist '\" + config.getDescription() + \"'\");\n\t\treturn config;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\n\nimport com.hazelcast.config.Config;\nimport com.hazelcast.core.Hazelcast;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.spring.context.SpringManagedContext;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.ResourceUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration for Hazelcast server.\n *\n * @author Stephane Nicoll\n * @author Vedran Pavic\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(HazelcastInstance.class)\nclass HazelcastServerConfiguration {\n\n\tstatic final String CONFIG_SYSTEM_PROPERTY = \"hazelcast.config\";\n\n\tstatic final String HAZELCAST_LOGGING_TYPE = \"hazelcast.logging.type\";\n\n\tprivate static HazelcastInstance getHazelcastInstance(Config config) {\n\t\tif (StringUtils.hasText(config.getInstanceName())) {\n\t\t\treturn Hazelcast.getOrCreateHazelcastInstance(config);\n\t\t}\n\t\treturn Hazelcast.newHazelcastInstance(config);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(Config.class)\n\t@Conditional(ConfigAvailableCondition.class)\n\tstatic class HazelcastServerConfigFileConfiguration {\n\n\t\t@Bean\n\t\tHazelcastInstance hazelcastInstance(HazelcastProperties properties, ResourceLoader resourceLoader,\n\t\t\t\tObjectProvider<HazelcastConfigCustomizer> hazelcastConfigCustomizers) throws IOException {\n\t\t\tResource configLocation = properties.resolveConfigLocation();\n\t\t\tConfig config = (configLocation != null) ? loadConfig(configLocation) : Config.load();\n\t\t\tconfig.setClassLoader(resourceLoader.getClassLoader());\n\t\t\thazelcastConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(config));\n\t\t\treturn getHazelcastInstance(config);\n\t\t}\n\n\t\tprivate Config loadConfig(Resource configLocation) throws IOException {\n\t\t\tURL configUrl = configLocation.getURL();\n\t\t\tConfig config = loadConfig(configUrl);\n\t\t\tif (ResourceUtils.isFileURL(configUrl)) {\n\t\t\t\tconfig.setConfigurationFile(configLocation.getFile());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconfig.setConfigurationUrl(configUrl);\n\t\t\t}\n\t\t\treturn config;\n\t\t}\n\n\t\tprivate Config loadConfig(URL configUrl) throws IOException {\n\t\t\ttry (InputStream stream = configUrl.openStream()) {\n\t\t\t\treturn Config.loadFromStream(stream);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(Config.class)\n\tstatic class HazelcastServerConfigConfiguration {\n\n\t\t@Bean\n\t\tHazelcastInstance hazelcastInstance(Config config) {\n\t\t\treturn getHazelcastInstance(config);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(SpringManagedContext.class)\n\tstatic class SpringManagedContextHazelcastConfigCustomizerConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tHazelcastConfigCustomizer springManagedContextHazelcastConfigCustomizer(ApplicationContext applicationContext) {\n\t\t\treturn (config) -> {\n\t\t\t\tSpringManagedContext managementContext = new SpringManagedContext();\n\t\t\t\tmanagementContext.setApplicationContext(applicationContext);\n\t\t\t\tconfig.setManagedContext(managementContext);\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.slf4j.Logger.class)\n\tstatic class HazelcastLoggingConfigCustomizerConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tHazelcastConfigCustomizer loggingHazelcastConfigCustomizer() {\n\t\t\treturn (config) -> {\n\t\t\t\tif (!config.getProperties().containsKey(HAZELCAST_LOGGING_TYPE)) {\n\t\t\t\t\tconfig.setProperty(HAZELCAST_LOGGING_TYPE, \"slf4j\");\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link HazelcastConfigResourceCondition} that checks if the\n\t * {@code spring.hazelcast.config} configuration key is defined.\n\t */\n\tstatic class ConfigAvailableCondition extends HazelcastConfigResourceCondition {\n\n\t\tConfigAvailableCondition() {\n\t\t\tsuper(CONFIG_SYSTEM_PROPERTY, \"file:./hazelcast.xml\", \"classpath:/hazelcast.xml\", \"file:./hazelcast.yaml\",\n\t\t\t\t\t\"classpath:/hazelcast.yaml\", \"file:./hazelcast.yml\", \"classpath:/hazelcast.yml\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/PropertiesHazelcastConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.URL;\nimport java.util.Locale;\n\nimport com.hazelcast.client.config.ClientConfig;\nimport com.hazelcast.client.config.XmlClientConfigBuilder;\nimport com.hazelcast.client.config.YamlClientConfigBuilder;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * Adapts {@link HazelcastProperties} to {@link HazelcastConnectionDetails}.\n *\n * @author Dmytro Nosan\n */\nclass PropertiesHazelcastConnectionDetails implements HazelcastConnectionDetails {\n\n\tprivate final HazelcastProperties properties;\n\n\tprivate final ResourceLoader resourceLoader;\n\n\tPropertiesHazelcastConnectionDetails(HazelcastProperties properties, ResourceLoader resourceLoader) {\n\t\tthis.properties = properties;\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tpublic ClientConfig getClientConfig() {\n\t\tResource configLocation = this.properties.resolveConfigLocation();\n\t\tClientConfig config = (configLocation != null) ? loadClientConfig(configLocation) : ClientConfig.load();\n\t\tconfig.setClassLoader(this.resourceLoader.getClassLoader());\n\t\treturn config;\n\t}\n\n\tprivate ClientConfig loadClientConfig(Resource configLocation) {\n\t\ttry {\n\t\t\tURL configUrl = configLocation.getURL();\n\t\t\tString configFileName = configUrl.getPath().toLowerCase(Locale.ROOT);\n\t\t\treturn (!isYaml(configFileName)) ? new XmlClientConfigBuilder(configUrl).build()\n\t\t\t\t\t: new YamlClientConfigBuilder(configUrl).build();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(\"Failed to load Hazelcast config\", ex);\n\t\t}\n\t}\n\n\tprivate boolean isYaml(String configFileName) {\n\t\treturn configFileName.endsWith(\".yaml\") || configFileName.endsWith(\".yml\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/health/HazelcastHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure.health;\n\nimport com.hazelcast.core.HazelcastInstance;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.hazelcast.health.HazelcastHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link HazelcastHealthIndicator}.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@AutoConfiguration(after = HazelcastAutoConfiguration.class)\n@ConditionalOnClass({ HazelcastInstance.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(HazelcastInstance.class)\n@ConditionalOnEnabledHealthIndicator(\"hazelcast\")\npublic final class HazelcastHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<HazelcastHealthIndicator, HazelcastInstance> {\n\n\tHazelcastHealthContributorAutoConfiguration() {\n\t\tsuper(HazelcastHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"hazelcastHealthIndicator\", \"hazelcastHealthContributor\" })\n\tHealthContributor hazelcastHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, HazelcastInstance.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Hazelcast health.\n */\n@NullMarked\npackage org.springframework.boot.hazelcast.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Hazelcast.\n */\n@NullMarked\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/docker/compose/HazelcastDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.docker.compose;\n\nimport com.hazelcast.client.config.ClientConfig;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link HazelcastConnectionDetails} for a {@code hazelcast} service.\n *\n * @author Dmytro Nosan\n */\nclass HazelcastDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<HazelcastConnectionDetails> {\n\n\tprivate static final int DEFAULT_PORT = 5701;\n\n\tprotected HazelcastDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"hazelcast/hazelcast\", \"com.hazelcast.client.config.ClientConfig\");\n\t}\n\n\t@Override\n\tprotected HazelcastConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new HazelcastDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link HazelcastConnectionDetails} backed by a {@code hazelcast}\n\t * {@link RunningService}.\n\t */\n\tstatic class HazelcastDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements HazelcastConnectionDetails {\n\n\t\tprivate final String host;\n\n\t\tprivate final int port;\n\n\t\tprivate final HazelcastEnvironment environment;\n\n\t\tHazelcastDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.host = service.host();\n\t\t\tthis.port = service.ports().get(DEFAULT_PORT);\n\t\t\tthis.environment = new HazelcastEnvironment(service.env());\n\t\t}\n\n\t\t@Override\n\t\tpublic ClientConfig getClientConfig() {\n\t\t\tClientConfig config = new ClientConfig();\n\t\t\tif (this.environment.getClusterName() != null) {\n\t\t\t\tconfig.setClusterName(this.environment.getClusterName());\n\t\t\t}\n\t\t\tconfig.getNetworkConfig().addAddress(this.host + \":\" + this.port);\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/docker/compose/HazelcastEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Hazelcast environment details.\n *\n * @author Dmytro Nosan\n */\nclass HazelcastEnvironment {\n\n\tprivate final @Nullable String clusterName;\n\n\tHazelcastEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.clusterName = env.get(\"HZ_CLUSTERNAME\");\n\t}\n\n\t@Nullable String getClusterName() {\n\t\treturn this.clusterName;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Hazelcast service connections.\n */\n@NullMarked\npackage org.springframework.boot.hazelcast.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/health/HazelcastHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.health;\n\nimport com.hazelcast.core.HazelcastInstance;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthIndicator} for Hazelcast.\n *\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n * @author Tommy Karlsson\n * @since 4.0.0\n */\npublic class HazelcastHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final HazelcastInstance hazelcast;\n\n\tpublic HazelcastHealthIndicator(HazelcastInstance hazelcast) {\n\t\tsuper(\"Hazelcast health check failed\");\n\t\tAssert.notNull(hazelcast, \"'hazelcast' must not be null\");\n\t\tthis.hazelcast = hazelcast;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) {\n\t\tif (!this.hazelcast.getLifecycleService().isRunning()) {\n\t\t\tbuilder.down();\n\t\t\treturn;\n\t\t}\n\t\tthis.hazelcast.executeTransaction((context) -> {\n\t\t\tString uuid = this.hazelcast.getLocalEndpoint().getUuid().toString();\n\t\t\tbuilder.up().withDetail(\"name\", this.hazelcast.getName()).withDetail(\"uuid\", uuid);\n\t\t\treturn null;\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for Hazelcast.\n */\n@NullMarked\npackage org.springframework.boot.hazelcast.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/testcontainers/HazelcastContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.testcontainers;\n\nimport java.util.Map;\n\nimport com.hazelcast.client.config.ClientConfig;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link HazelcastConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer}\n * using the {@code \"hazelcast/hazelcast\"} image.\n *\n * @author Dmytro Nosan\n */\nclass HazelcastContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, HazelcastConnectionDetails> {\n\n\tprivate static final int DEFAULT_PORT = 5701;\n\n\tprivate static final String CLUSTER_NAME_ENV = \"HZ_CLUSTERNAME\";\n\n\tHazelcastContainerConnectionDetailsFactory() {\n\t\tsuper(\"hazelcast/hazelcast\", \"com.hazelcast.client.config.ClientConfig\");\n\t}\n\n\t@Override\n\tprotected HazelcastConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\treturn new HazelcastContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link HazelcastConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class HazelcastContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>\n\t\t\timplements HazelcastConnectionDetails {\n\n\t\tprivate HazelcastContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ClientConfig getClientConfig() {\n\t\t\tClientConfig config = new ClientConfig();\n\t\t\tContainer<?> container = getContainer();\n\t\t\tMap<String, String> env = container.getEnvMap();\n\t\t\tString clusterName = env.get(CLUSTER_NAME_ENV);\n\t\t\tif (clusterName != null) {\n\t\t\t\tconfig.setClusterName(clusterName);\n\t\t\t}\n\t\t\tconfig.getNetworkConfig().addAddress(container.getHost() + \":\" + container.getMappedPort(DEFAULT_PORT));\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/java/org/springframework/boot/hazelcast/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Hazelcast service connections.\n */\n@NullMarked\npackage org.springframework.boot.hazelcast.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration\norg.springframework.boot.hazelcast.autoconfigure.HazelcastJpaDependencyAutoConfiguration\norg.springframework.boot.hazelcast.autoconfigure.health.HazelcastHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.hazelcast.docker.compose.HazelcastDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.hazelcast.testcontainers.HazelcastContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastAutoConfigurationClientTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.MalformedURLException;\nimport java.nio.file.Files;\nimport java.util.Set;\n\nimport com.hazelcast.client.HazelcastClient;\nimport com.hazelcast.client.config.ClientConfig;\nimport com.hazelcast.client.impl.clientside.HazelcastClientProxy;\nimport com.hazelcast.config.Config;\nimport com.hazelcast.config.NetworkConfig;\nimport com.hazelcast.core.Hazelcast;\nimport com.hazelcast.core.HazelcastInstance;\nimport org.assertj.core.api.Condition;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastAutoConfiguration} specific to the client.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\nclass HazelcastAutoConfigurationClientTests {\n\n\t/**\n\t * Servers the test clients will connect to.\n\t */\n\tprivate static HazelcastInstance hazelcastServer;\n\n\tprivate static String endpointAddress;\n\n\t@BeforeAll\n\tstatic void init() {\n\t\tConfig config = Config.load();\n\t\tNetworkConfig networkConfig = config.getNetworkConfig();\n\t\tnetworkConfig.setPort(0);\n\t\tnetworkConfig.setPublicAddress(\"localhost\");\n\t\thazelcastServer = Hazelcast.newHazelcastInstance(config);\n\t\tInetSocketAddress inetSocketAddress = (InetSocketAddress) hazelcastServer.getLocalEndpoint().getSocketAddress();\n\t\tendpointAddress = inetSocketAddress.getHostString() + \":\" + inetSocketAddress.getPort();\n\t}\n\n\t@AfterAll\n\tstatic void close() {\n\t\tif (hazelcastServer != null) {\n\t\t\thazelcastServer.shutdown();\n\t\t}\n\t}\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class));\n\n\t@Test\n\tvoid systemPropertyWithXml() {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.xml\");\n\t\tthis.contextRunner\n\t\t\t.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + \"=\" + config.getAbsolutePath())\n\t\t\t.run(assertSpecificHazelcastClient(\"explicit-xml\"));\n\t}\n\n\t@Test\n\tvoid systemPropertyWithYaml() {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.yaml\");\n\t\tthis.contextRunner\n\t\t\t.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + \"=\" + config.getAbsolutePath())\n\t\t\t.run(assertSpecificHazelcastClient(\"explicit-yaml\"));\n\t}\n\n\t@Test\n\tvoid systemPropertyWithYml() {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.yml\");\n\t\tthis.contextRunner\n\t\t\t.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + \"=\" + config.getAbsolutePath())\n\t\t\t.run(assertSpecificHazelcastClient(\"explicit-yml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigUrlWithXml() throws MalformedURLException {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.xml\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=\" + config.toURI().toURL())\n\t\t\t.run(assertSpecificHazelcastClient(\"explicit-xml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigUrlWithYaml() throws MalformedURLException {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.yaml\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=\" + config.toURI().toURL())\n\t\t\t.run(assertSpecificHazelcastClient(\"explicit-yaml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigUrlWithYml() throws MalformedURLException {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.yml\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=\" + config.toURI().toURL())\n\t\t\t.run(assertSpecificHazelcastClient(\"explicit-yml\"));\n\t}\n\n\t@Test\n\tvoid unknownConfigFile() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=foo/bar/unknown.xml\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"foo/bar/unknown.xml\"));\n\t}\n\n\t@Test\n\tvoid clientConfigTakesPrecedence() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastServerAndClientConfig.class)\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=this-is-ignored.xml\")\n\t\t\t.run((context) -> assertThat(context).getBean(HazelcastInstance.class)\n\t\t\t\t.isInstanceOf(HazelcastClientProxy.class));\n\t}\n\n\t@Test\n\tvoid connectionDetailsTakesPrecedenceOverConfigFile() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastConnectionDetailsConfig.class)\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=this-is-ignored.xml\")\n\t\t\t.run(assertSpecificHazelcastClient(\"connection-details\"));\n\t}\n\n\t@Test\n\tvoid connectionDetailsTakesPrecedenceOverUserDefinedClientConfig() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(HazelcastConnectionDetailsConfig.class, HazelcastServerAndClientConfig.class)\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=this-is-ignored.xml\")\n\t\t\t.run(assertSpecificHazelcastClient(\"connection-details\"));\n\t}\n\n\t@Test\n\tvoid clientConfigWithInstanceNameCreatesClientIfNecessary() throws MalformedURLException {\n\t\tassertThat(HazelcastClient.getHazelcastClientByName(\"spring-boot\")).isNull();\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-instance.xml\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=\" + config.toURI().toURL())\n\t\t\t.run((context) -> assertThat(context).getBean(HazelcastInstance.class)\n\t\t\t\t.extracting(HazelcastInstance::getName)\n\t\t\t\t.isEqualTo(\"spring-boot\"));\n\t}\n\n\t@Test\n\tvoid autoConfiguredClientConfigUsesApplicationClassLoader() throws MalformedURLException {\n\t\tFile config = prepareConfiguration(\"src/test/resources/org/springframework/\"\n\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-client-specific.xml\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=\" + config.toURI().toURL()).run((context) -> {\n\t\t\tHazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);\n\t\t\tassertThat(hazelcast).isInstanceOf(HazelcastClientProxy.class);\n\t\t\tClientConfig clientConfig = ((HazelcastClientProxy) hazelcast).getClientConfig();\n\t\t\tassertThat(clientConfig.getClassLoader()).isSameAs(context.getSourceApplicationContext().getClassLoader());\n\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertSpecificHazelcastClient(String label) {\n\t\treturn (context) -> assertThat(context).getBean(HazelcastInstance.class)\n\t\t\t.isInstanceOf(HazelcastInstance.class)\n\t\t\t.has(labelEqualTo(label));\n\t}\n\n\tprivate static Condition<HazelcastInstance> labelEqualTo(String label) {\n\t\treturn new Condition<>((o) -> ((HazelcastClientProxy) o).getClientConfig()\n\t\t\t.getLabels()\n\t\t\t.stream()\n\t\t\t.anyMatch((e) -> e.equals(label)), \"Label equals to \" + label);\n\t}\n\n\tprivate File prepareConfiguration(String input) {\n\t\tFile configFile = new File(input);\n\t\ttry {\n\t\t\tString config = FileCopyUtils.copyToString(new FileReader(configFile));\n\t\t\tconfig = config.replace(\"${address}\", endpointAddress);\n\t\t\tSystem.out.println(config);\n\t\t\tFile outputFile = new File(Files.createTempDirectory(getClass().getSimpleName()).toFile(),\n\t\t\t\t\tconfigFile.getName());\n\t\t\tFileCopyUtils.copy(config, new FileWriter(outputFile));\n\t\t\treturn outputFile;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastConnectionDetailsConfig {\n\n\t\t@Bean\n\t\tHazelcastConnectionDetails hazelcastConnectionDetails() {\n\t\t\tClientConfig config = new ClientConfig();\n\t\t\tconfig.setLabels(Set.of(\"connection-details\"));\n\t\t\tconfig.getConnectionStrategyConfig().getConnectionRetryConfig().setClusterConnectTimeoutMillis(60000);\n\t\t\tconfig.getNetworkConfig().getAddresses().add(endpointAddress);\n\t\t\treturn () -> config;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastServerAndClientConfig {\n\n\t\t@Bean\n\t\tConfig config() {\n\t\t\treturn new Config();\n\t\t}\n\n\t\t@Bean\n\t\tClientConfig clientConfig() {\n\t\t\tClientConfig config = new ClientConfig();\n\t\t\tconfig.getConnectionStrategyConfig().getConnectionRetryConfig().setClusterConnectTimeoutMillis(60000);\n\t\t\tconfig.getNetworkConfig().getAddresses().add(endpointAddress);\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastAutoConfigurationServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Map;\n\nimport com.hazelcast.config.Config;\nimport com.hazelcast.config.JoinConfig;\nimport com.hazelcast.config.QueueConfig;\nimport com.hazelcast.core.Hazelcast;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.map.EntryProcessor;\nimport com.hazelcast.map.IMap;\nimport com.hazelcast.spring.context.SpringAware;\nimport com.hazelcast.spring.context.SpringManagedContext;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastAutoConfiguration} when the client library is not present.\n *\n * @author Stephane Nicoll\n */\nclass HazelcastAutoConfigurationServerTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class));\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid defaultConfigFile() {\n\t\t// hazelcast.xml present in root classpath\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getConfigurationUrl()).isEqualTo(new ClassPathResource(\"hazelcast.xml\").getURL());\n\t\t});\n\t}\n\n\t@Test\n\tvoid systemPropertyWithXml() {\n\t\tthis.contextRunner\n\t\t\t.withSystemProperties(HazelcastServerConfiguration.CONFIG_SYSTEM_PROPERTY\n\t\t\t\t\t+ \"=classpath:org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.xml\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\t\tassertThat(config.getMapConfigs().keySet()).containsOnly(\"foobar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid systemPropertyWithYaml() {\n\t\tthis.contextRunner\n\t\t\t.withSystemProperties(HazelcastServerConfiguration.CONFIG_SYSTEM_PROPERTY\n\t\t\t\t\t+ \"=classpath:org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yaml\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\t\tassertThat(config.getMapConfigs().keySet()).containsOnly(\"foobar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid systemPropertyWithYml() {\n\t\tthis.contextRunner\n\t\t\t.withSystemProperties(HazelcastServerConfiguration.CONFIG_SYSTEM_PROPERTY\n\t\t\t\t\t+ \"=classpath:org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yml\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\t\tassertThat(config.getMapConfigs().keySet()).containsOnly(\"foobar\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid explicitConfigFileWithXml() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=org/springframework/boot/hazelcast/autoconfigure/\"\n\t\t\t\t\t+ \"hazelcast-specific.xml\")\n\t\t\t.run(assertSpecificHazelcastServer(\n\t\t\t\t\t\"org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.xml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigFileWithYaml() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=org/springframework/boot/hazelcast/autoconfigure/\"\n\t\t\t\t\t+ \"hazelcast-specific.yaml\")\n\t\t\t.run(assertSpecificHazelcastServer(\n\t\t\t\t\t\"org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yaml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigFileWithYml() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=org/springframework/boot/hazelcast/autoconfigure/\"\n\t\t\t\t\t+ \"hazelcast-specific.yml\")\n\t\t\t.run(assertSpecificHazelcastServer(\n\t\t\t\t\t\"org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigUrlWithXml() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=classpath:org/springframework/\"\n\t\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-specific.xml\")\n\t\t\t.run(assertSpecificHazelcastServer(\n\t\t\t\t\t\"org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.xml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigUrlWithYaml() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=classpath:org/springframework/\"\n\t\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-specific.yaml\")\n\t\t\t.run(assertSpecificHazelcastServer(\n\t\t\t\t\t\"org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yaml\"));\n\t}\n\n\t@Test\n\tvoid explicitConfigUrlWithYml() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=classpath:org/springframework/\"\n\t\t\t\t\t+ \"boot/hazelcast/autoconfigure/hazelcast-specific.yml\")\n\t\t\t.run(assertSpecificHazelcastServer(\n\t\t\t\t\t\"org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yml\"));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertSpecificHazelcastServer(String location) {\n\t\treturn (context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tString configurationLocation = (config.getConfigurationUrl() != null)\n\t\t\t\t\t? config.getConfigurationUrl().toString()\n\t\t\t\t\t: config.getConfigurationFile().toURI().toURL().toString();\n\t\t\tassertThat(configurationLocation).endsWith(location);\n\t\t};\n\t}\n\n\t@Test\n\tvoid unknownConfigFile() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.hazelcast.config=foo/bar/unknown.xml\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"foo/bar/unknown.xml\"));\n\t}\n\n\t@Test\n\tvoid configInstanceWithName() {\n\t\tConfig config = createTestConfig(\"my-test-instance\");\n\t\tHazelcastInstance existing = Hazelcast.newHazelcastInstance(config);\n\t\ttry {\n\t\t\tthis.contextRunner.withUserConfiguration(HazelcastConfigWithName.class)\n\t\t\t\t.withPropertyValues(\"spring.hazelcast.config=this-is-ignored.xml\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tHazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);\n\t\t\t\t\tassertThat(hazelcast.getConfig().getInstanceName()).isEqualTo(\"my-test-instance\");\n\t\t\t\t\t// Should reuse any existing instance by default.\n\t\t\t\t\tassertThat(hazelcast).isEqualTo(existing);\n\t\t\t\t});\n\t\t}\n\t\tfinally {\n\t\t\texisting.shutdown();\n\t\t}\n\t}\n\n\t@Test\n\tvoid configInstanceWithoutName() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastConfigNoName.class)\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=this-is-ignored.xml\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\t\tMap<String, QueueConfig> queueConfigs = config.getQueueConfigs();\n\t\t\t\tassertThat(queueConfigs.keySet()).containsOnly(\"another-queue\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid autoConfiguredConfigUsesApplicationClassLoader() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getClassLoader()).isSameAs(context.getSourceApplicationContext().getClassLoader());\n\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid autoConfiguredConfigUsesSpringManagedContext() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getManagedContext()).isInstanceOf(SpringManagedContext.class);\n\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid autoConfiguredConfigCanUseSpringAwareComponent() {\n\t\tthis.contextRunner.withPropertyValues(\"test.hazelcast.key=42\").run((context) -> {\n\t\t\tHazelcastInstance hz = context.getBean(HazelcastInstance.class);\n\t\t\tIMap<String, String> map = hz.getMap(\"test\");\n\t\t\tassertThat(map.executeOnKey(\"test.hazelcast.key\", new SpringAwareEntryProcessor<>())).isEqualTo(\"42\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid autoConfiguredConfigWithoutHazelcastSpringDoesNotUseSpringManagedContext() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(\n\t\t\t\t\tnew FilteredClassLoader(Thread.currentThread().getContextClassLoader(), SpringManagedContext.class))\n\t\t\t.run((context) -> {\n\t\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\t\tassertThat(config.getManagedContext()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid autoConfiguredContextCanOverrideManagementContextUsingCustomizer() {\n\t\tthis.contextRunner.withBean(TestHazelcastConfigCustomizer.class).run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getManagedContext()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\t@WithHazelcastXmlResource\n\tvoid autoConfiguredConfigSetsHazelcastLoggingToSlf4j() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getProperty(HazelcastServerConfiguration.HAZELCAST_LOGGING_TYPE)).isEqualTo(\"slf4j\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredConfigCanOverrideHazelcastLogging() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastConfigWithJDKLogging.class).run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getProperty(HazelcastServerConfiguration.HAZELCAST_LOGGING_TYPE)).isEqualTo(\"jdk\");\n\t\t});\n\t}\n\n\tprivate static Config createTestConfig(String instanceName) {\n\t\tConfig config = new Config(instanceName);\n\t\tJoinConfig join = config.getNetworkConfig().getJoin();\n\t\tjoin.getAutoDetectionConfig().setEnabled(false);\n\t\tjoin.getMulticastConfig().setEnabled(false);\n\t\treturn config;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastConfigWithName {\n\n\t\t@Bean\n\t\tConfig myHazelcastConfig() {\n\t\t\treturn new Config(\"my-test-instance\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastConfigNoName {\n\n\t\t@Bean\n\t\tConfig anotherHazelcastConfig() {\n\t\t\tConfig config = createTestConfig(\"another-test-instance\");\n\t\t\tconfig.addQueueConfig(new QueueConfig(\"another-queue\"));\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastConfigWithJDKLogging {\n\n\t\t@Bean\n\t\tConfig anotherHazelcastConfig() {\n\t\t\tConfig config = new Config();\n\t\t\tconfig.setProperty(HazelcastServerConfiguration.HAZELCAST_LOGGING_TYPE, \"jdk\");\n\t\t\treturn config;\n\t\t}\n\n\t}\n\n\t@SpringAware\n\tstatic class SpringAwareEntryProcessor<V> implements EntryProcessor<String, V, String> {\n\n\t\t@Autowired\n\t\tprivate Environment environment;\n\n\t\t@Override\n\t\tpublic @Nullable String process(Map.Entry<String, V> entry) {\n\t\t\treturn this.environment.getProperty(entry.getKey());\n\t\t}\n\n\t}\n\n\t@Order(1)\n\tstatic class TestHazelcastConfigCustomizer implements HazelcastConfigCustomizer {\n\n\t\t@Override\n\t\tpublic void customize(Config config) {\n\t\t\tconfig.setManagedContext(null);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"hazelcast.xml\", content = \"\"\"\n\t\t\t<hazelcast\n\t\t\t\txsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t\t\txmlns=\"http://www.hazelcast.com/schema/config\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t\t\t\t<instance-name>default-instance</instance-name>\n\t\t\t\t<map name=\"defaultCache\" />\n\t\t\t\t<network>\n\t\t\t\t\t<join>\n\t\t\t\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t\t\t\t<multicast enabled=\"false\" />\n\t\t\t\t\t</join>\n\t\t\t\t</network>\n\t\t\t</hazelcast>\n\t\t\t\"\"\")\n\t@interface WithHazelcastXmlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport com.hazelcast.config.Config;\nimport com.hazelcast.core.HazelcastInstance;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastAutoConfiguration} with full classpath.\n *\n * @author Stephane Nicoll\n */\nclass HazelcastAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class));\n\n\t@Test\n\t@WithResource(name = \"hazelcast.xml\", content = \"\"\"\n\t\t\t<hazelcast\n\t\t\t\txsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t\t\txmlns=\"http://www.hazelcast.com/schema/config\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t\t\t\t<instance-name>default-instance</instance-name>\n\t\t\t\t<map name=\"defaultCache\" />\n\t\t\t\t<network>\n\t\t\t\t\t<join>\n\t\t\t\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t\t\t\t<multicast enabled=\"false\" />\n\t\t\t\t\t</join>\n\t\t\t\t</network>\n\t\t\t</hazelcast>\n\t\t\t\"\"\")\n\t@WithResource(name = \"hazelcast.yml\", content = \"\"\"\n\t\t\thazelcast:\n\t\t\t  network:\n\t\t\t    join:\n\t\t\t      auto-detection:\n\t\t\t        enabled: false\n\t\t\t      multicast:\n\t\t\t        enabled: false\n\t\t\t\"\"\")\n\t@WithResource(name = \"hazelcast.yaml\", content = \"\"\"\n\t\t\thazelcast:\n\t\t\t  network:\n\t\t\t    join:\n\t\t\t      auto-detection:\n\t\t\t        enabled: false\n\t\t\t      multicast:\n\t\t\t        enabled: false\n\t\t\t\"\"\")\n\tvoid defaultConfigFileIsHazelcastXml() {\n\t\t// no hazelcast-client.xml and hazelcast.xml is present in root classpath\n\t\t// this also asserts that XML has priority over YAML\n\t\t// as hazelcast.yaml, hazelcast.yml, and hazelcast.xml are available.\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConfig config = context.getBean(HazelcastInstance.class).getConfig();\n\t\t\tassertThat(config.getConfigurationUrl()).isEqualTo(new ClassPathResource(\"hazelcast.xml\").getURL());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastClientConfigAvailableConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HazelcastClientConfigAvailableCondition}.\n *\n * @author Stephane Nicoll\n */\nclass HazelcastClientConfigAvailableConditionTests {\n\n\tprivate final HazelcastClientConfigAvailableCondition condition = new HazelcastClientConfigAvailableCondition();\n\n\t@Test\n\tvoid explicitConfigurationWithClientConfigMatches() {\n\t\tConditionOutcome outcome = getMatchOutcome(new MockEnvironment().withProperty(\"spring.hazelcast.config\",\n\t\t\t\t\"classpath:org/springframework/boot/hazelcast/autoconfigure/hazelcast-client-specific.xml\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage()).contains(\"Hazelcast client configuration detected\");\n\t}\n\n\t@Test\n\tvoid explicitConfigurationWithServerConfigDoesNotMatch() {\n\t\tConditionOutcome outcome = getMatchOutcome(new MockEnvironment().withProperty(\"spring.hazelcast.config\",\n\t\t\t\t\"classpath:org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.xml\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage()).contains(\"Hazelcast server configuration detected\");\n\t}\n\n\t@Test\n\tvoid explicitConfigurationWithMissingConfigDoesNotMatch() {\n\t\tConditionOutcome outcome = getMatchOutcome(new MockEnvironment().withProperty(\"spring.hazelcast.config\",\n\t\t\t\t\"classpath:org/springframework/boot/hazelcast/autoconfigure/test-config-does-not-exist.xml\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage()).contains(\"Hazelcast configuration does not exist\");\n\t}\n\n\tprivate ConditionOutcome getMatchOutcome(Environment environment) {\n\t\tConditionContext conditionContext = mock(ConditionContext.class);\n\t\tgiven(conditionContext.getEnvironment()).willReturn(environment);\n\t\tgiven(conditionContext.getResourceLoader()).willReturn(new DefaultResourceLoader());\n\t\treturn this.condition.getMatchOutcome(conditionContext, mock(AnnotatedTypeMetadata.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/HazelcastJpaDependencyAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastJpaDependencyAutoConfiguration.HazelcastInstanceEntityManagerFactoryDependsOnPostProcessor;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryDependsOnPostProcessor;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HazelcastJpaDependencyAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass HazelcastJpaDependencyAutoConfigurationTests {\n\n\tprivate static final String POST_PROCESSOR_BEAN_NAME = HazelcastInstanceEntityManagerFactoryDependsOnPostProcessor.class\n\t\t.getName();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,\n\t\t\t\tHazelcastJpaDependencyAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid registrationIfHazelcastInstanceHasRegularBeanName() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastConfiguration.class).run((context) -> {\n\t\t\tassertThat(postProcessors(context)).containsKey(POST_PROCESSOR_BEAN_NAME);\n\t\t\tassertThat(entityManagerFactoryDependencies(context)).contains(\"hazelcastInstance\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid noRegistrationIfHazelcastInstanceHasCustomBeanName() {\n\t\tthis.contextRunner.withUserConfiguration(HazelcastCustomNameConfiguration.class).run((context) -> {\n\t\t\tassertThat(entityManagerFactoryDependencies(context)).doesNotContain(\"hazelcastInstance\");\n\t\t\tassertThat(postProcessors(context)).doesNotContainKey(POST_PROCESSOR_BEAN_NAME);\n\t\t});\n\t}\n\n\t@Test\n\tvoid noRegistrationWithNoHazelcastInstance() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(entityManagerFactoryDependencies(context)).doesNotContain(\"hazelcastInstance\");\n\t\t\tassertThat(postProcessors(context)).doesNotContainKey(POST_PROCESSOR_BEAN_NAME);\n\t\t});\n\t}\n\n\t@Test\n\tvoid noRegistrationWithNoEntityManagerFactory() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(HazelcastConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(HazelcastJpaDependencyAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(postProcessors(context)).doesNotContainKey(POST_PROCESSOR_BEAN_NAME));\n\t}\n\n\tprivate Map<String, EntityManagerFactoryDependsOnPostProcessor> postProcessors(\n\t\t\tAssertableApplicationContext context) {\n\t\treturn context.getBeansOfType(EntityManagerFactoryDependsOnPostProcessor.class);\n\t}\n\n\tprivate List<String> entityManagerFactoryDependencies(AssertableApplicationContext context) {\n\t\tString[] dependsOn = ((BeanDefinitionRegistry) context.getSourceApplicationContext())\n\t\t\t.getBeanDefinition(\"entityManagerFactory\")\n\t\t\t.getDependsOn();\n\t\treturn (dependsOn != null) ? Arrays.asList(dependsOn) : Collections.emptyList();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastConfiguration {\n\n\t\t@Bean\n\t\tHazelcastInstance hazelcastInstance() {\n\t\t\treturn mock(HazelcastInstance.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HazelcastCustomNameConfiguration {\n\n\t\t@Bean\n\t\tHazelcastInstance myHazelcastInstance() {\n\t\t\treturn mock(HazelcastInstance.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/health/HazelcastHealthContributorAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure.health;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.hazelcast.health.HazelcastHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link HazelcastHealthContributorAutoConfiguration}.\n *\n * @author Dmytro Nosan\n */\n@WithResource(name = \"hazelcast.xml\", content = \"\"\"\n\t\t<hazelcast\n\t\t\t\txsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t\t\txmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t\t\t<map name=\"defaultCache\" />\n\t\t\t<network>\n\t\t\t\t<join>\n\t\t\t\t\t<auto-detection enabled=\"false\"/>\n\t\t\t\t\t<multicast enabled=\"false\"/>\n\t\t\t\t</join>\n\t\t\t</network>\n\t\t</hazelcast>\n\t\t\"\"\")\nclass HazelcastHealthContributorAutoConfigurationIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HazelcastHealthContributorAutoConfiguration.class,\n\t\t\t\tHazelcastAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid hazelcastUp() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(HazelcastInstance.class).hasSingleBean(HazelcastHealthIndicator.class);\n\t\t\tHazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);\n\t\t\tHealth health = context.getBean(HazelcastHealthIndicator.class).health();\n\t\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(health.getDetails()).containsOnlyKeys(\"name\", \"uuid\")\n\t\t\t\t.containsEntry(\"name\", hazelcast.getName())\n\t\t\t\t.containsEntry(\"uuid\", hazelcast.getLocalEndpoint().getUuid().toString());\n\t\t});\n\t}\n\n\t@Test\n\tvoid hazelcastDown() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tcontext.getBean(HazelcastInstance.class).shutdown();\n\t\t\tassertThat(context).hasSingleBean(HazelcastHealthIndicator.class);\n\t\t\tHealth health = context.getBean(HazelcastHealthIndicator.class).health();\n\t\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/autoconfigure/health/HazelcastHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.hazelcast.health.HazelcastHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastHealthContributorAutoConfiguration}.\n *\n * @author Dmytro Nosan\n */\n@WithResource(name = \"hazelcast.xml\", content = \"\"\"\n\t\t<hazelcast\n\t\t\t\txsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t\t\txmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\t\t\t<map name=\"defaultCache\" />\n\t\t\t<network>\n\t\t\t\t<join>\n\t\t\t\t\t<auto-detection enabled=\"false\"/>\n\t\t\t\t\t<multicast enabled=\"false\"/>\n\t\t\t\t</join>\n\t\t\t</network>\n\t\t</hazelcast>\n\t\t\"\"\")\nclass HazelcastHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class,\n\t\t\t\tHazelcastHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(HazelcastHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.hazelcast.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HazelcastHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/docker/compose/HazelcastEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastEnvironment}.\n *\n * @author Dmytro Nosan\n */\nclass HazelcastEnvironmentTests {\n\n\t@Test\n\tvoid getClusterNameWhenHasNoHzClusterNameSet() {\n\t\tHazelcastEnvironment environment = new HazelcastEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getClusterName()).isNull();\n\t}\n\n\t@Test\n\tvoid getClusterNameWhenHzClusterNameSet() {\n\t\tHazelcastEnvironment environment = new HazelcastEnvironment(Map.of(\"HZ_CLUSTERNAME\", \"spring-boot\"));\n\t\tassertThat(environment.getClusterName()).isEqualTo(\"spring-boot\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/health/HazelcastHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.health;\n\nimport com.hazelcast.core.HazelcastException;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.core.LifecycleService;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.hazelcast.autoconfigure.HazelcastAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HazelcastHealthIndicator}.\n *\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n * @author Tommy Karlsson\n */\n@WithResource(name = \"hazelcast.xml\", content = \"\"\"\n\t\t<hazelcast xmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t\t\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t   xsi:schemaLocation=\"http://www.hazelcast.com/schema/config\n\t\t           http://www.hazelcast.com/schema/config/hazelcast-config-5.0.xsd\">\n\t\t\t<instance-name>actuator-hazelcast</instance-name>\n\t\t\t<map name=\"defaultCache\" />\n\t\t\t<network>\n\t\t\t\t<join>\n\t\t\t\t\t<auto-detection enabled=\"false\"/>\n\t\t\t\t\t<multicast enabled=\"false\"/>\n\t\t\t\t</join>\n\t\t\t</network>\n\t\t</hazelcast>\n\t\t\"\"\")\nclass HazelcastHealthIndicatorTests {\n\n\t@Test\n\tvoid hazelcastUp() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=hazelcast.xml\")\n\t\t\t.run((context) -> {\n\t\t\t\tHazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);\n\t\t\t\tHealth health = new HazelcastHealthIndicator(hazelcast).health();\n\t\t\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\t\t\tassertThat(health.getDetails()).containsOnlyKeys(\"name\", \"uuid\")\n\t\t\t\t\t.containsEntry(\"name\", \"actuator-hazelcast\");\n\t\t\t\tassertThat(health.getDetails().get(\"uuid\")).asString().isNotEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hazelcastShutdown() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.hazelcast.config=hazelcast.xml\")\n\t\t\t.run((context) -> {\n\t\t\t\tHazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);\n\t\t\t\thazelcast.shutdown();\n\t\t\t\tHealth health = new HazelcastHealthIndicator(hazelcast).health();\n\t\t\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hazelcastLifecycleNotRunning() {\n\t\tHazelcastInstance hazelcast = mockHazelcastInstance(false);\n\t\tHealth health = new HazelcastHealthIndicator(hazelcast).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tthen(hazelcast).should().getLifecycleService();\n\t\tthen(hazelcast).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid hazelcastDown() {\n\t\tHazelcastInstance hazelcast = mockHazelcastInstance(true);\n\t\tgiven(hazelcast.executeTransaction(any())).willThrow(new HazelcastException());\n\t\tHealth health = new HazelcastHealthIndicator(hazelcast).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tthen(hazelcast).should().getLifecycleService();\n\t\tthen(hazelcast).should().executeTransaction(any());\n\t\tthen(hazelcast).shouldHaveNoMoreInteractions();\n\t}\n\n\tprivate static HazelcastInstance mockHazelcastInstance(boolean isRunning) {\n\t\tLifecycleService lifecycleService = mock(LifecycleService.class);\n\t\tgiven(lifecycleService.isRunning()).willReturn(isRunning);\n\t\tHazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);\n\t\tgiven(hazelcastInstance.getLifecycleService()).willReturn(lifecycleService);\n\t\treturn hazelcastInstance;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/java/org/springframework/boot/hazelcast/testcontainers/HazelcastContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hazelcast.testcontainers;\n\nimport com.hazelcast.client.config.ClientConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HazelcastContainerConnectionDetailsFactory}.\n *\n * @author Dmytro Nosan\n */\nclass HazelcastContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ClientConfig.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-client-instance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hazelcast-client xmlns=\"http://www.hazelcast.com/schema/client-config\"\n\t\t\t\t  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t  xsi:schemaLocation=\"http://www.hazelcast.com/schema/client-config hazelcast-client-config-5.0.xsd\">\n\t<instance-name>spring-boot</instance-name>\n\t<connection-strategy>\n\t\t<connection-retry>\n\t\t\t<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>\n\t\t</connection-retry>\n\t</connection-strategy>\n\t<network>\n\t\t<cluster-members>\n\t\t\t<address>${address}</address>\n\t\t</cluster-members>\n\t</network>\n</hazelcast-client>\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-client-specific.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hazelcast-client xmlns=\"http://www.hazelcast.com/schema/client-config\"\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txsi:schemaLocation=\"http://www.hazelcast.com/schema/client-config hazelcast-client-config-5.0.xsd\">\n\t<client-labels>\n\t\t<label>explicit-xml</label>\n\t</client-labels>\n\t<connection-strategy>\n\t\t<connection-retry>\n\t\t\t<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>\n\t\t</connection-retry>\n\t</connection-strategy>\n\t<network>\n\t\t<cluster-members>\n\t\t\t<address>${address}</address>\n\t\t</cluster-members>\n\t</network>\n</hazelcast-client>\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-client-specific.yaml",
    "content": "hazelcast-client:\n  client-labels:\n    - explicit-yaml\n  connection-strategy:\n    connection-retry:\n      cluster-connect-timeout-millis: 60000\n  network:\n    cluster-members:\n      - ${address}"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-client-specific.yml",
    "content": "hazelcast-client:\n  client-labels:\n    - explicit-yml\n  connection-strategy:\n    connection-retry:\n      cluster-connect-timeout-millis: 60000\n  network:\n    cluster-members:\n      - ${address}\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.xml",
    "content": "<hazelcast xsi:schemaLocation=\"http://www.hazelcast.com/schema/config hazelcast-config-5.0.xsd\"\n\t\t   xmlns=\"http://www.hazelcast.com/schema/config\"\n\t\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n\t<queue name=\"foobar\"/>\n\n\t<map name=\"foobar\">\n\t\t<time-to-live-seconds>3600</time-to-live-seconds>\n\t\t<max-idle-seconds>600</max-idle-seconds>\n\t</map>\n\n\t<network>\n\t\t<join>\n\t\t\t<auto-detection enabled=\"false\" />\n\t\t\t<multicast enabled=\"false\"/>\n\t\t</join>\n\t</network>\n\n</hazelcast>\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yaml",
    "content": "hazelcast:\n  network:\n    join:\n      auto-detection:\n        enabled: false\n      multicast:\n        enabled: false\n\n  map:\n    foobar:\n      time-to-live-seconds: 3600\n      max-idle-seconds: 600\n"
  },
  {
    "path": "module/spring-boot-hazelcast/src/test/resources/org/springframework/boot/hazelcast/autoconfigure/hazelcast-specific.yml",
    "content": "hazelcast:\n  network:\n    join:\n      auto-detection:\n        enabled: false\n      multicast:\n        enabled: false\n\n  map:\n    foobar:\n      time-to-live-seconds: 3600\n      max-idle-seconds: 600\n"
  },
  {
    "path": "module/spring-boot-health/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Health\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n\ttestImplementation(\"org.springframework.security:spring-security-core\")\n\ttestImplementation(\"org.springframework:spring-web\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/AdditionalHealthEndpointPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Value object that represents an additional path for a {@link HealthEndpointGroup}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic final class AdditionalHealthEndpointPath {\n\n\tprivate final WebServerNamespace namespace;\n\n\tprivate final String value;\n\n\tprivate final String canonicalValue;\n\n\tprivate AdditionalHealthEndpointPath(WebServerNamespace namespace, String value) {\n\t\tthis.namespace = namespace;\n\t\tthis.value = value;\n\t\tthis.canonicalValue = (!value.startsWith(\"/\")) ? \"/\" + value : value;\n\t}\n\n\t/**\n\t * Returns the {@link WebServerNamespace} associated with this path.\n\t * @return the server namespace\n\t */\n\tpublic WebServerNamespace getNamespace() {\n\t\treturn this.namespace;\n\t}\n\n\t/**\n\t * Returns the value corresponding to this path.\n\t * @return the path\n\t */\n\tpublic String getValue() {\n\t\treturn this.value;\n\t}\n\n\t/**\n\t * Returns {@code true} if this path has the given {@link WebServerNamespace}.\n\t * @param webServerNamespace the server namespace\n\t * @return the new instance\n\t */\n\tpublic boolean hasNamespace(WebServerNamespace webServerNamespace) {\n\t\treturn this.namespace.equals(webServerNamespace);\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tAdditionalHealthEndpointPath other = (AdditionalHealthEndpointPath) obj;\n\t\tboolean result = true;\n\t\tresult = result && this.namespace.equals(other.namespace);\n\t\tresult = result && this.canonicalValue.equals(other.canonicalValue);\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + this.namespace.hashCode();\n\t\tresult = prime * result + this.canonicalValue.hashCode();\n\t\treturn result;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.namespace.getValue() + \":\" + this.value;\n\t}\n\n\t/**\n\t * Creates an {@link AdditionalHealthEndpointPath} from the given input. The input\n\t * must contain a prefix and value separated by a `:`. The value must be limited to\n\t * one path segment. For example, `server:/healthz`.\n\t * @param value the value to parse\n\t * @return the new instance\n\t */\n\tpublic static AdditionalHealthEndpointPath from(String value) {\n\t\tAssert.hasText(value, \"'value' must not be null\");\n\t\tString[] values = value.split(\":\");\n\t\tAssert.isTrue(values.length == 2, \"'value' must contain a valid namespace and value separated by ':'.\");\n\t\tAssert.isTrue(StringUtils.hasText(values[0]), \"'value' must contain a valid namespace.\");\n\t\tWebServerNamespace namespace = WebServerNamespace.from(values[0]);\n\t\tvalidateValue(values[1]);\n\t\treturn new AdditionalHealthEndpointPath(namespace, values[1]);\n\t}\n\n\t/**\n\t * Creates an {@link AdditionalHealthEndpointPath} from the given\n\t * {@link WebServerNamespace} and value.\n\t * @param webServerNamespace the server namespace\n\t * @param value the value\n\t * @return the new instance\n\t */\n\tpublic static AdditionalHealthEndpointPath of(WebServerNamespace webServerNamespace, String value) {\n\t\tAssert.notNull(webServerNamespace, \"'webServerNamespace' must not be null.\");\n\t\tAssert.notNull(value, \"'value' must not be null.\");\n\t\tvalidateValue(value);\n\t\treturn new AdditionalHealthEndpointPath(webServerNamespace, value);\n\t}\n\n\tprivate static void validateValue(String value) {\n\t\tAssert.isTrue(StringUtils.countOccurrencesOf(value, \"/\") <= 1 && value.indexOf(\"/\") <= 0,\n\t\t\t\t\"'value' must contain only one segment.\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/CompositeHealthDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.Assert;\n\n/**\n * Description of health that is composed of other {@link HealthDescriptor health\n * descriptors}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic sealed class CompositeHealthDescriptor extends HealthDescriptor permits SystemHealthDescriptor {\n\n\tprivate final ApiVersion apiVersion;\n\n\tprivate final Status status;\n\n\tprivate final @Nullable Map<String, HealthDescriptor> components;\n\n\tCompositeHealthDescriptor(ApiVersion apiVersion, Status status,\n\t\t\t@Nullable Map<String, HealthDescriptor> components) {\n\t\tAssert.notNull(apiVersion, \"'apiVersion' must not be null\");\n\t\tAssert.notNull(status, \"'status' must not be null\");\n\t\tthis.apiVersion = apiVersion;\n\t\tthis.status = status;\n\t\tthis.components = (components != null) ? new TreeMap<>(components) : components;\n\t}\n\n\t@Override\n\tpublic Status getStatus() {\n\t\treturn this.status;\n\t}\n\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic @Nullable Map<String, HealthDescriptor> getComponents() {\n\t\treturn (this.apiVersion == ApiVersion.V3) ? this.components : null;\n\t}\n\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic @Nullable Map<String, HealthDescriptor> getDetails() {\n\t\treturn (this.apiVersion == ApiVersion.V2) ? this.components : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/Contributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Iterator;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.util.StringUtils;\n\n/**\n * Allows {@link HealthEndpointSupport} to access blocking or reactive contributors and\n * registries in a uniform way.\n *\n * @param <H> the health type\n * @param <D> the descriptor type\n * @author Phillip Webb\n */\nsealed interface Contributor<H, D> extends Iterable<Contributor.Child<H, D>> {\n\n\t/**\n\t * Return if this contributor is a composite and may have children.\n\t * @return if the contributor is a composite\n\t */\n\tboolean isComposite();\n\n\t/**\n\t * Get the child with the given name. Must only be called if {@link #isComposite()}\n\t * returns {@code true}.\n\t * @param name the child name\n\t * @return the child or {@code null}\n\t */\n\t@Nullable Contributor<H, D> getChild(String name);\n\n\t/**\n\t * Get the health. Must only be called if {@link #isComposite()} returns\n\t * {@code false}.\n\t * @param includeDetails if details are to be included.\n\t * @return the health\n\t */\n\t@Nullable D getDescriptor(boolean includeDetails);\n\n\t/**\n\t * Return an identifier for logging purposes.\n\t * @param name the name if known\n\t * @return an identifier\n\t */\n\tdefault String getIdentifier(String name) {\n\t\tString className = getContributorClassName();\n\t\treturn (!StringUtils.hasLength(name)) ? className : className + \" (\" + name + \")\";\n\t}\n\n\t/**\n\t * Return the class name of the underlying contributor.\n\t * @return the contributor class name\n\t */\n\tString getContributorClassName();\n\n\t/**\n\t * Factory method to create a blocking {@link Contributor} from the given registries.\n\t * @param registry the source registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @return a new {@link Contributor}\n\t */\n\tstatic Blocking blocking(HealthContributorRegistry registry,\n\t\t\t@Nullable ReactiveHealthContributorRegistry fallbackRegistry) {\n\t\treturn new Blocking((fallbackRegistry != null)\n\t\t\t\t? HealthContributors.of(registry, fallbackRegistry.asHealthContributors()) : registry);\n\t}\n\n\t/**\n\t * Factory method to create a reactive {@link Contributor} from the given registries.\n\t * @param registry the registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @return a new {@link Contributor}\n\t */\n\tstatic Reactive reactive(ReactiveHealthContributorRegistry registry,\n\t\t\t@Nullable HealthContributorRegistry fallbackRegistry) {\n\t\treturn new Reactive((fallbackRegistry != null)\n\t\t\t\t? ReactiveHealthContributors.of(registry, ReactiveHealthContributors.adapt(fallbackRegistry))\n\t\t\t\t: registry);\n\t}\n\n\t/**\n\t * A child consisting of a name and a contributor.\n\t *\n\t * @param <H> the health type\n\t * @param <D> the descriptor type\n\t * @param name the child name\n\t * @param contributor the contributor\n\t */\n\trecord Child<H, D>(String name, Contributor<H, D> contributor) {\n\n\t}\n\n\t/**\n\t * {@link Contributor} to adapt the blocking {@link HealthContributor} and\n\t * {@link HealthContributors} types.\n\t *\n\t * @param contributor the underlying contributor\n\t */\n\trecord Blocking(Object contributor) implements Contributor<Health, HealthDescriptor> {\n\n\t\t@Override\n\t\tpublic boolean isComposite() {\n\t\t\treturn contributor() instanceof HealthContributors;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Blocking getChild(String name) {\n\t\t\tHealthContributor child = ((HealthContributors) contributor()).getContributor(name);\n\t\t\treturn (child != null) ? new Blocking(child) : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<Child<Health, HealthDescriptor>> iterator() {\n\t\t\treturn ((HealthContributors) contributor()).stream()\n\t\t\t\t.map((entry) -> new Child<>(entry.name(), new Blocking(entry.contributor())))\n\t\t\t\t.iterator();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable HealthDescriptor getDescriptor(boolean includeDetails) {\n\t\t\tHealth health = ((HealthIndicator) contributor()).health(includeDetails);\n\t\t\treturn (health != null) ? new IndicatedHealthDescriptor(health) : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getContributorClassName() {\n\t\t\treturn contributor().getClass().getName();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Contributor} to adapt the reactive {@link ReactiveHealthContributor} and\n\t * {@link ReactiveHealthContributors} types.\n\t *\n\t * @param contributor the underlying contributor\n\t */\n\trecord Reactive(\n\t\t\tObject contributor) implements Contributor<Mono<? extends Health>, Mono<? extends HealthDescriptor>> {\n\n\t\t@Override\n\t\tpublic boolean isComposite() {\n\t\t\treturn contributor() instanceof ReactiveHealthContributors;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Reactive getChild(String name) {\n\t\t\tReactiveHealthContributor child = ((ReactiveHealthContributors) contributor()).getContributor(name);\n\t\t\treturn (child != null) ? new Reactive(child) : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<Child<Mono<? extends Health>, Mono<? extends HealthDescriptor>>> iterator() {\n\t\t\treturn ((ReactiveHealthContributors) contributor()).stream()\n\t\t\t\t.map((entry) -> new Child<>(entry.name(), new Reactive(entry.contributor())))\n\t\t\t\t.iterator();\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<? extends HealthDescriptor> getDescriptor(boolean includeDetails) {\n\t\t\tMono<Health> health = ((ReactiveHealthIndicator) this.contributor).health(includeDetails);\n\t\t\treturn health.map(IndicatedHealthDescriptor::new);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getContributorClassName() {\n\t\t\treturn contributor().getClass().getName();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport com.fasterxml.jackson.annotation.JsonUnwrapped;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.health.contributor.Status;\n\n/**\n * Description of health including a status.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract sealed class HealthDescriptor implements OperationResponseBody\n\t\tpermits IndicatedHealthDescriptor, CompositeHealthDescriptor {\n\n\t/**\n\t * Return the status of the component.\n\t * @return the component status\n\t */\n\t@JsonUnwrapped\n\tpublic abstract Status getStatus();\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\n\n/**\n * {@link Endpoint @Endpoint} to expose application health information.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@Endpoint(id = \"health\")\npublic class HealthEndpoint extends HealthEndpointSupport<Health, HealthDescriptor> {\n\n\t/**\n\t * Health endpoint id.\n\t */\n\tpublic static final EndpointId ID = EndpointId.of(\"health\");\n\n\t/**\n\t * Create a new {@link HealthEndpoint} instance.\n\t * @param registry the health contributor registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @param groups the health endpoint groups\n\t * @param slowContributorLoggingThreshold duration after which slow health indicator\n\t * logging should occur\n\t */\n\tpublic HealthEndpoint(HealthContributorRegistry registry,\n\t\t\t@Nullable ReactiveHealthContributorRegistry fallbackRegistry, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowContributorLoggingThreshold) {\n\t\tsuper(Contributor.blocking(registry, fallbackRegistry), groups, slowContributorLoggingThreshold);\n\t}\n\n\t@ReadOperation\n\tpublic HealthDescriptor health() {\n\t\tHealthDescriptor health = health(ApiVersion.V3, EMPTY_PATH);\n\t\treturn (health != null) ? health : IndicatedHealthDescriptor.UP;\n\t}\n\n\t@ReadOperation\n\tpublic @Nullable HealthDescriptor healthForPath(@Selector(match = Match.ALL_REMAINING) String... path) {\n\t\treturn health(ApiVersion.V3, path);\n\t}\n\n\tprivate @Nullable HealthDescriptor health(ApiVersion apiVersion, String... path) {\n\t\tResult<HealthDescriptor> result = getResult(apiVersion, null, SecurityContext.NONE, true, path);\n\t\treturn (result != null) ? result.descriptor() : null;\n\t}\n\n\t@Override\n\tprotected HealthDescriptor aggregateDescriptors(ApiVersion apiVersion, Map<String, HealthDescriptor> contributions,\n\t\t\tStatusAggregator statusAggregator, boolean showComponents, @Nullable Set<String> groupNames) {\n\t\treturn getCompositeDescriptor(apiVersion, contributions, statusAggregator, showComponents, groupNames);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\n\n/**\n * A logical grouping of {@link HealthContributor health contributors} that can be exposed\n * by the {@link HealthEndpoint}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic interface HealthEndpointGroup {\n\n\t/**\n\t * Returns {@code true} if the given contributor is a member of this group.\n\t * @param name the contributor name\n\t * @return {@code true} if the contributor is a member of this group\n\t */\n\tboolean isMember(String name);\n\n\t/**\n\t * Returns if {@link CompositeHealthDescriptor#getComponents() health components}\n\t * should be shown in the response.\n\t * @param securityContext the endpoint security context\n\t * @return {@code true} to shown details or {@code false} to hide them\n\t */\n\tboolean showComponents(SecurityContext securityContext);\n\n\t/**\n\t * Returns if {@link Health#getDetails() health details} should be shown in the\n\t * response.\n\t * @param securityContext the endpoint security context\n\t * @return {@code true} to shown details or {@code false} to hide them\n\t */\n\tboolean showDetails(SecurityContext securityContext);\n\n\t/**\n\t * Returns the status aggregator that should be used for this group.\n\t * @return the status aggregator for this group\n\t */\n\tStatusAggregator getStatusAggregator();\n\n\t/**\n\t * Returns the {@link HttpCodeStatusMapper} that should be used for this group.\n\t * @return the HTTP code status mapper\n\t */\n\tHttpCodeStatusMapper getHttpCodeStatusMapper();\n\n\t/**\n\t * Return an additional path that can be used to map the health group to an\n\t * alternative location.\n\t * @return the additional health path or {@code null}\n\t */\n\t@Nullable AdditionalHealthEndpointPath getAdditionalPath();\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointGroups.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.util.Assert;\n\n/**\n * A collection of {@link HealthEndpointGroup groups} for use with a health endpoint.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface HealthEndpointGroups {\n\n\t/**\n\t * Return the primary group used by the endpoint.\n\t * @return the primary group (never {@code null})\n\t */\n\tHealthEndpointGroup getPrimary();\n\n\t/**\n\t * Return the names of any additional groups.\n\t * @return the additional group names\n\t */\n\tSet<String> getNames();\n\n\t/**\n\t * Return the group with the specified name or {@code null} if the name is not known.\n\t * @param name the name of the group\n\t * @return the {@link HealthEndpointGroup} or {@code null}\n\t */\n\t@Nullable HealthEndpointGroup get(String name);\n\n\t/**\n\t * Return the group with the specified additional path or {@code null} if no group\n\t * with that path is found.\n\t * @param path the additional path\n\t * @return the matching {@link HealthEndpointGroup} or {@code null}\n\t */\n\tdefault @Nullable HealthEndpointGroup get(AdditionalHealthEndpointPath path) {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tfor (String name : getNames()) {\n\t\t\tHealthEndpointGroup group = get(name);\n\t\t\tAssert.state(group != null, \"'group' must not be null\");\n\t\t\tif (path.equals(group.getAdditionalPath())) {\n\t\t\t\treturn group;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return all the groups with an additional path on the specified\n\t * {@link WebServerNamespace}.\n\t * @param namespace the {@link WebServerNamespace}\n\t * @return the matching groups\n\t */\n\tdefault Set<HealthEndpointGroup> getAllWithAdditionalPath(WebServerNamespace namespace) {\n\t\tAssert.notNull(namespace, \"'namespace' must not be null\");\n\t\tSet<HealthEndpointGroup> filteredGroups = new LinkedHashSet<>();\n\t\tgetNames().stream()\n\t\t\t.map(this::get)\n\t\t\t.filter((group) -> group != null && group.getAdditionalPath() != null\n\t\t\t\t\t&& group.getAdditionalPath().hasNamespace(namespace))\n\t\t\t.forEach(filteredGroups::add);\n\t\treturn filteredGroups;\n\t}\n\n\t/**\n\t * Factory method to create a {@link HealthEndpointGroups} instance.\n\t * @param primary the primary group\n\t * @param additional the additional groups\n\t * @return a new {@link HealthEndpointGroups} instance\n\t */\n\tstatic HealthEndpointGroups of(HealthEndpointGroup primary, Map<String, HealthEndpointGroup> additional) {\n\t\tAssert.notNull(primary, \"'primary' must not be null\");\n\t\tAssert.notNull(additional, \"'additional' must not be null\");\n\t\treturn new HealthEndpointGroups() {\n\n\t\t\t@Override\n\t\t\tpublic HealthEndpointGroup getPrimary() {\n\t\t\t\treturn primary;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Set<String> getNames() {\n\t\t\t\treturn additional.keySet();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable HealthEndpointGroup get(String name) {\n\t\t\t\treturn additional.get(name);\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointGroupsPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\n/**\n * Hook that allows for custom modification of {@link HealthEndpointGroups} &mdash; for\n * example, automatically adding additional auto-configured groups.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface HealthEndpointGroupsPostProcessor {\n\n\t/**\n\t * Post-process the given {@link HealthEndpointGroups} instance.\n\t * @param groups the existing groups instance\n\t * @return a post-processed groups instance, or the original instance if not\n\t * post-processing was required\n\t */\n\tHealthEndpointGroups postProcessHealthEndpointGroups(HealthEndpointGroups groups);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointSupport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.convert.DurationStyle;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for health endpoints and health endpoint extensions.\n *\n * @param <H> the health type\n * @param <D> the descriptor type\n * @author Phillip Webb\n * @author Scott Frederick\n */\nabstract class HealthEndpointSupport<H, D> {\n\n\tstatic final String[] EMPTY_PATH = {};\n\n\tprivate static final Log logger = LogFactory.getLog(HealthEndpointSupport.class);\n\n\tprivate final Contributor<H, D> rootContributor;\n\n\tprivate final HealthEndpointGroups groups;\n\n\tprivate final @Nullable Duration slowContributorLoggingThreshold;\n\n\t/**\n\t * Create a new {@link HealthEndpointSupport} instance.\n\t * @param rootContributor the health contributor registry\n\t * @param groups the health endpoint groups\n\t * @param slowContributorLoggingThreshold duration after which slow health contributor\n\t * logging should occur\n\t */\n\tHealthEndpointSupport(Contributor<H, D> rootContributor, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowContributorLoggingThreshold) {\n\t\tAssert.notNull(rootContributor, \"'rootContributor' must not be null\");\n\t\tAssert.notNull(groups, \"'groups' must not be null\");\n\t\tthis.rootContributor = rootContributor;\n\t\tthis.groups = groups;\n\t\tthis.slowContributorLoggingThreshold = slowContributorLoggingThreshold;\n\t}\n\n\t@Nullable Result<D> getResult(ApiVersion apiVersion, @Nullable WebServerNamespace serverNamespace,\n\t\t\tSecurityContext securityContext, boolean showAll, String... path) {\n\t\tHealthEndpointGroup group = (path.length > 0) ? getGroup(serverNamespace, path) : null;\n\t\tif (group != null) {\n\t\t\treturn getResult(apiVersion, group, securityContext, showAll, path, 1);\n\t\t}\n\t\treturn getResult(apiVersion, this.groups.getPrimary(), securityContext, showAll, path, 0);\n\t}\n\n\tprivate @Nullable HealthEndpointGroup getGroup(@Nullable WebServerNamespace serverNamespace, String... path) {\n\t\tif (this.groups.get(path[0]) != null) {\n\t\t\treturn this.groups.get(path[0]);\n\t\t}\n\t\tif (serverNamespace != null) {\n\t\t\treturn this.groups.get(AdditionalHealthEndpointPath.of(serverNamespace, path[0]));\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable Result<D> getResult(ApiVersion apiVersion, HealthEndpointGroup group,\n\t\t\tSecurityContext securityContext, boolean showAll, String[] path, int pathOffset) {\n\t\tboolean showComponents = showAll || group.showComponents(securityContext);\n\t\tboolean showDetails = showAll || group.showDetails(securityContext);\n\t\tboolean isSystemHealth = group == this.groups.getPrimary() && pathOffset == 0;\n\t\tboolean isRoot = path.length - pathOffset == 0;\n\t\tif (!showComponents && !isRoot) {\n\t\t\treturn null;\n\t\t}\n\t\tContributor<H, D> contributor = getContributor(path, pathOffset);\n\t\tif (contributor == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString name = getName(path, pathOffset);\n\t\tSet<String> groupNames = (!isSystemHealth) ? null : new TreeSet<>(this.groups.getNames());\n\t\tD descriptor = getDescriptor(apiVersion, group, name, contributor, showComponents, showDetails, groupNames);\n\t\treturn (descriptor != null) ? new Result<>(descriptor, group) : null;\n\t}\n\n\tprivate @Nullable Contributor<H, D> getContributor(String[] path, int pathOffset) {\n\t\tContributor<H, D> contributor = this.rootContributor;\n\t\twhile (pathOffset < path.length) {\n\t\t\tAssert.state(contributor != null, \"'contributor' must not be null\");\n\t\t\tif (!contributor.isComposite()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tcontributor = contributor.getChild(path[pathOffset]);\n\t\t\tpathOffset++;\n\t\t}\n\t\treturn contributor;\n\t}\n\n\tprivate String getName(String[] path, int pathOffset) {\n\t\tStringBuilder name = new StringBuilder();\n\t\twhile (pathOffset < path.length) {\n\t\t\tname.append((!name.isEmpty()) ? \"/\" : \"\");\n\t\t\tname.append(path[pathOffset]);\n\t\t\tpathOffset++;\n\t\t}\n\t\treturn name.toString();\n\t}\n\n\tprivate @Nullable D getDescriptor(ApiVersion apiVersion, HealthEndpointGroup group, String name,\n\t\t\tContributor<H, D> contributor, boolean showComponents, boolean showDetails,\n\t\t\t@Nullable Set<String> groupNames) {\n\t\tif (contributor.isComposite()) {\n\t\t\treturn getAggregateDescriptor(apiVersion, group, name, contributor, showComponents, showDetails,\n\t\t\t\t\tgroupNames);\n\t\t}\n\t\tif (name.isEmpty() || group.isMember(name)) {\n\t\t\treturn getDescriptorAndLogIfSlow(contributor, name, showDetails);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable D getAggregateDescriptor(ApiVersion apiVersion, HealthEndpointGroup group, String name,\n\t\t\tContributor<H, D> contributor, boolean showComponents, boolean showDetails,\n\t\t\t@Nullable Set<String> groupNames) {\n\t\tString prefix = (StringUtils.hasText(name)) ? name + \"/\" : \"\";\n\t\tMap<String, D> descriptors = new LinkedHashMap<>();\n\t\tfor (Contributor.Child<H, D> child : contributor) {\n\t\t\tString childName = child.name();\n\t\t\tD descriptor = getDescriptor(apiVersion, group, prefix + childName, child.contributor(), showComponents,\n\t\t\t\t\tshowDetails, null);\n\t\t\tif (descriptor != null) {\n\t\t\t\tdescriptors.put(childName, descriptor);\n\t\t\t}\n\t\t}\n\t\tif (descriptors.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn aggregateDescriptors(apiVersion, descriptors, group.getStatusAggregator(), showComponents, groupNames);\n\t}\n\n\tprivate @Nullable D getDescriptorAndLogIfSlow(Contributor<H, D> contributor, String name, boolean showDetails) {\n\t\tInstant start = Instant.now();\n\t\ttry {\n\t\t\treturn contributor.getDescriptor(showDetails);\n\t\t}\n\t\tfinally {\n\t\t\tif (logger.isWarnEnabled() && this.slowContributorLoggingThreshold != null) {\n\t\t\t\tDuration duration = Duration.between(start, Instant.now());\n\t\t\t\tif (duration.compareTo(this.slowContributorLoggingThreshold) > 0) {\n\t\t\t\t\tlogger.warn(LogMessage.format(\"Health contributor %s took %s to respond\",\n\t\t\t\t\t\t\tcontributor.getIdentifier(name), DurationStyle.SIMPLE.print(duration)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tabstract D aggregateDescriptors(ApiVersion apiVersion, Map<String, D> descriptors,\n\t\t\tStatusAggregator statusAggregator, boolean showComponents, @Nullable Set<String> groupNames);\n\n\tfinal CompositeHealthDescriptor getCompositeDescriptor(ApiVersion apiVersion,\n\t\t\tMap<String, HealthDescriptor> descriptors, StatusAggregator statusAggregator, boolean showComponents,\n\t\t\t@Nullable Set<String> groupNames) {\n\t\tStatus status = statusAggregator\n\t\t\t.getAggregateStatus(descriptors.values().stream().map(this::getStatus).collect(Collectors.toSet()));\n\t\tdescriptors = (!showComponents) ? null : descriptors;\n\t\treturn (groupNames != null) ? new SystemHealthDescriptor(apiVersion, status, descriptors, groupNames)\n\t\t\t\t: new CompositeHealthDescriptor(apiVersion, status, descriptors);\n\t}\n\n\tprivate Status getStatus(@Nullable HealthDescriptor component) {\n\t\treturn (component != null) ? component.getStatus() : Status.UNKNOWN;\n\t}\n\n\t/**\n\t * A health result containing descriptor and the group that created it.\n\t *\n\t * @param descriptor the health descriptor\n\t * @param group the group used to create the health\n\t * @param <D> the details type\n\t */\n\trecord Result<D>(D descriptor, HealthEndpointGroup group) {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * {@link EndpointWebExtension @EndpointWebExtension} for the {@link HealthEndpoint}.\n *\n * @author Christian Dupuis\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@EndpointWebExtension(endpoint = HealthEndpoint.class)\n@ImportRuntimeHints(HealthEndpointWebExtensionRuntimeHints.class)\npublic class HealthEndpointWebExtension extends HealthEndpointSupport<Health, HealthDescriptor> {\n\n\t/**\n\t * Create a new {@link HealthEndpointWebExtension} instance.\n\t * @param registry the health contributor registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @param groups the health endpoint groups\n\t * @param slowContributorLoggingThreshold duration after which slow health indicator\n\t * logging should occur\n\t */\n\tpublic HealthEndpointWebExtension(HealthContributorRegistry registry,\n\t\t\t@Nullable ReactiveHealthContributorRegistry fallbackRegistry, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowContributorLoggingThreshold) {\n\t\tsuper(Contributor.blocking(registry, fallbackRegistry), groups, slowContributorLoggingThreshold);\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,\n\t\t\tSecurityContext securityContext) {\n\t\treturn health(apiVersion, serverNamespace, securityContext, false, EMPTY_PATH);\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion, WebServerNamespace serverNamespace,\n\t\t\tSecurityContext securityContext, @Selector(match = Match.ALL_REMAINING) String... path) {\n\t\treturn health(apiVersion, serverNamespace, securityContext, false, path);\n\t}\n\n\tpublic WebEndpointResponse<HealthDescriptor> health(ApiVersion apiVersion,\n\t\t\t@Nullable WebServerNamespace serverNamespace, SecurityContext securityContext, boolean showAll,\n\t\t\tString... path) {\n\t\tResult<HealthDescriptor> result = getResult(apiVersion, serverNamespace, securityContext, showAll, path);\n\t\tif (result == null) {\n\t\t\treturn (Arrays.equals(path, EMPTY_PATH))\n\t\t\t\t\t? new WebEndpointResponse<>(IndicatedHealthDescriptor.UP, WebEndpointResponse.STATUS_OK)\n\t\t\t\t\t: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);\n\t\t}\n\t\tHealthDescriptor descriptor = result.descriptor();\n\t\tHealthEndpointGroup group = result.group();\n\t\tint statusCode = group.getHttpCodeStatusMapper().getStatusCode(descriptor.getStatus());\n\t\treturn new WebEndpointResponse<>(descriptor, statusCode);\n\t}\n\n\t@Override\n\tprotected HealthDescriptor aggregateDescriptors(ApiVersion apiVersion, Map<String, HealthDescriptor> contributions,\n\t\t\tStatusAggregator statusAggregator, boolean showComponents, @Nullable Set<String> groupNames) {\n\t\treturn getCompositeDescriptor(apiVersion, contributions, statusAggregator, showComponents, groupNames);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointWebExtensionRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * {@link RuntimeHintsRegistrar} used by {@link HealthEndpointWebExtension} and\n * {@link ReactiveHealthEndpointWebExtension}.\n *\n * @author Moritz Halbritter\n */\nclass HealthEndpointWebExtensionRuntimeHints implements RuntimeHintsRegistrar {\n\n\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), IndicatedHealthDescriptor.class,\n\t\t\t\tCompositeHealthDescriptor.class, SystemHealthDescriptor.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/HttpCodeStatusMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Strategy used to map a {@link Status health status} to an HTTP status code.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface HttpCodeStatusMapper {\n\n\t/**\n\t * An {@link HttpCodeStatusMapper} instance using default mappings.\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of #getDefault()\n\t */\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tHttpCodeStatusMapper DEFAULT = new SimpleHttpCodeStatusMapper();\n\n\t/**\n\t * Return the HTTP status code that corresponds to the given {@link Status health\n\t * status}.\n\t * @param status the health status to map\n\t * @return the corresponding HTTP status code\n\t */\n\tint getStatusCode(Status status);\n\n\t/**\n\t * Create a new {@link HttpCodeStatusMapper} with the specified mappings.\n\t * @param mappings the mappings to use or {@code null} to use the default mappings\n\t * @return a {@link HttpCodeStatusMapper} or {@link #getDefault()}\n\t * @since 4.1.0\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic HttpCodeStatusMapper of(@Nullable Map<String, Integer> mappings) {\n\t\treturn CollectionUtils.isEmpty(mappings) ? SimpleHttpCodeStatusMapper.DEFAULT_MAPPINGS\n\t\t\t\t: new SimpleHttpCodeStatusMapper(mappings);\n\t}\n\n\t/**\n\t * Return an {@link HttpCodeStatusMapper} instance using default mappings.\n\t * @return a mapper using default mappings\n\t * @since 4.1.0\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic HttpCodeStatusMapper getDefault() {\n\t\treturn SimpleHttpCodeStatusMapper.DEFAULT_MAPPINGS;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/IndicatedHealthDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\n\n/**\n * Description of health obtained from a {@link HealthIndicator} or\n * {@link ReactiveHealthIndicator}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class IndicatedHealthDescriptor extends HealthDescriptor {\n\n\tstatic final IndicatedHealthDescriptor UP = new IndicatedHealthDescriptor(Health.up().build());\n\n\tprivate final Health health;\n\n\tIndicatedHealthDescriptor(Health health) {\n\t\tthis.health = health;\n\t}\n\n\t@Override\n\tpublic Status getStatus() {\n\t\treturn this.health.getStatus();\n\t}\n\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic Map<String, Object> getDetails() {\n\t\treturn this.health.getDetails();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/ReactiveHealthEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector.Match;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * Reactive {@link EndpointWebExtension @EndpointWebExtension} for the\n * {@link HealthEndpoint}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\n@EndpointWebExtension(endpoint = HealthEndpoint.class)\n@ImportRuntimeHints(HealthEndpointWebExtensionRuntimeHints.class)\npublic class ReactiveHealthEndpointWebExtension\n\t\textends HealthEndpointSupport<Mono<? extends Health>, Mono<? extends HealthDescriptor>> {\n\n\t/**\n\t * Create a new {@link ReactiveHealthEndpointWebExtension} instance.\n\t * @param registry the health contributor registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @param groups the health endpoint groups\n\t * @param slowContributorLoggingThreshold duration after which slow health indicator\n\t * logging should occur\n\t */\n\tpublic ReactiveHealthEndpointWebExtension(ReactiveHealthContributorRegistry registry,\n\t\t\t@Nullable HealthContributorRegistry fallbackRegistry, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowContributorLoggingThreshold) {\n\t\tsuper(Contributor.reactive(registry, fallbackRegistry), groups, slowContributorLoggingThreshold);\n\t}\n\n\t@ReadOperation\n\tpublic Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,\n\t\t\t@Nullable WebServerNamespace serverNamespace, SecurityContext securityContext) {\n\t\treturn health(apiVersion, serverNamespace, securityContext, false, EMPTY_PATH);\n\t}\n\n\t@ReadOperation\n\tpublic Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,\n\t\t\t@Nullable WebServerNamespace serverNamespace, SecurityContext securityContext,\n\t\t\t@Selector(match = Match.ALL_REMAINING) String... path) {\n\t\treturn health(apiVersion, serverNamespace, securityContext, false, path);\n\t}\n\n\tpublic Mono<WebEndpointResponse<? extends HealthDescriptor>> health(ApiVersion apiVersion,\n\t\t\t@Nullable WebServerNamespace serverNamespace, SecurityContext securityContext, boolean showAll,\n\t\t\tString... path) {\n\t\tResult<Mono<? extends HealthDescriptor>> result = getResult(apiVersion, serverNamespace, securityContext,\n\t\t\t\tshowAll, path);\n\t\tif (result == null) {\n\t\t\treturn (Arrays.equals(path, EMPTY_PATH))\n\t\t\t\t\t? Mono.just(new WebEndpointResponse<>(IndicatedHealthDescriptor.UP, WebEndpointResponse.STATUS_OK))\n\t\t\t\t\t: Mono.just(new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND));\n\t\t}\n\t\tHealthEndpointGroup group = result.group();\n\t\treturn result.descriptor().map((health) -> {\n\t\t\tint statusCode = group.getHttpCodeStatusMapper().getStatusCode(health.getStatus());\n\t\t\treturn new WebEndpointResponse<>(health, statusCode);\n\t\t});\n\t}\n\n\t@Override\n\tprotected Mono<? extends HealthDescriptor> aggregateDescriptors(ApiVersion apiVersion,\n\t\t\tMap<String, Mono<? extends HealthDescriptor>> contributions, StatusAggregator statusAggregator,\n\t\t\tboolean showComponents, @Nullable Set<String> groupNames) {\n\t\treturn Flux.fromIterable(contributions.entrySet())\n\t\t\t.flatMap(NamedHealthDescriptor::create)\n\t\t\t.collectMap(NamedHealthDescriptor::name, NamedHealthDescriptor::descriptor)\n\t\t\t.map((components) -> this.getCompositeDescriptor(apiVersion, components, statusAggregator, showComponents,\n\t\t\t\t\tgroupNames));\n\t}\n\n\t/**\n\t * A named {@link HealthDescriptor}.\n\t */\n\tprivate record NamedHealthDescriptor(String name, HealthDescriptor descriptor) {\n\n\t\tstatic Mono<NamedHealthDescriptor> create(Map.Entry<String, Mono<? extends HealthDescriptor>> entry) {\n\t\t\tMono<String> name = Mono.just(entry.getKey());\n\t\t\tMono<? extends HealthDescriptor> health = entry.getValue();\n\t\t\treturn Mono.zip(NamedHealthDescriptor::ofPair, name, health);\n\t\t}\n\n\t\tprivate static NamedHealthDescriptor ofPair(Object... pair) {\n\t\t\treturn new NamedHealthDescriptor((String) pair[0], (HealthDescriptor) pair[1]);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/SimpleHttpCodeStatusMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Simple {@link HttpCodeStatusMapper} backed by map of {@link Status#getCode() status\n * code} to HTTP status code.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n * {@link HttpCodeStatusMapper#of}\n */\n@Deprecated(since = \"4.1.0\", forRemoval = true)\npublic class SimpleHttpCodeStatusMapper implements HttpCodeStatusMapper {\n\n\tstatic final SimpleHttpCodeStatusMapper DEFAULT_MAPPINGS;\n\tstatic {\n\t\tMap<String, Integer> mappings = new HashMap<>();\n\t\tmappings.put(Status.DOWN.getCode(), WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t\tmappings.put(Status.OUT_OF_SERVICE.getCode(), WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t\tDEFAULT_MAPPINGS = new SimpleHttpCodeStatusMapper(mappings);\n\t}\n\n\tprivate final Map<String, Integer> mappings;\n\n\t/**\n\t * Create a new {@link SimpleHttpCodeStatusMapper} instance using default mappings.\n\t */\n\tpublic SimpleHttpCodeStatusMapper() {\n\t\tthis((Map<String, Integer>) null);\n\t}\n\n\t/**\n\t * Create a new {@link SimpleHttpCodeStatusMapper} with the specified mappings.\n\t * @param mappings the mappings to use or {@code null} to use the default mappings\n\t */\n\tpublic SimpleHttpCodeStatusMapper(@Nullable Map<String, Integer> mappings) {\n\t\tthis.mappings = CollectionUtils.isEmpty(mappings) ? DEFAULT_MAPPINGS.mappings : getUniformMappings(mappings);\n\t}\n\n\t@Override\n\tpublic int getStatusCode(Status status) {\n\t\tString code = getUniformCode(status.getCode());\n\t\treturn this.mappings.getOrDefault(code, WebEndpointResponse.STATUS_OK);\n\t}\n\n\tprivate static Map<String, Integer> getUniformMappings(Map<String, Integer> mappings) {\n\t\tMap<String, Integer> result = new LinkedHashMap<>();\n\t\tfor (Map.Entry<String, Integer> entry : mappings.entrySet()) {\n\t\t\tString code = getUniformCode(entry.getKey());\n\t\t\tif (code != null) {\n\t\t\t\tresult.putIfAbsent(code, entry.getValue());\n\t\t\t}\n\t\t}\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate static @Nullable String getUniformCode(@Nullable String code) {\n\t\treturn (code != null) ? code.codePoints()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)\n\t\t\t.toString() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/SimpleStatusAggregator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link StatusAggregator} backed by an ordered status list.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @deprecated since 4.1.0 for removal in 4.3.0 in favor of {@link StatusAggregator#of}\n */\n@Deprecated(since = \"4.1.0\", forRemoval = true)\npublic class SimpleStatusAggregator implements StatusAggregator {\n\n\tstatic final SimpleStatusAggregator DEFAULT_ORDER = new SimpleStatusAggregator();\n\n\tprivate final List<String> order;\n\n\tprivate final Comparator<Status> comparator = Comparator.comparingInt(this::orderIndex)\n\t\t.thenComparing(Status::getCode);\n\n\tpublic SimpleStatusAggregator() {\n\t\tthis(Status.DEFAULT_ORDER.stream().map(Status::getCode));\n\t}\n\n\tpublic SimpleStatusAggregator(Status... order) {\n\t\tthis.order = ObjectUtils.isEmpty(order) ? DEFAULT_ORDER.order\n\t\t\t\t: Arrays.stream(order).map(SimpleStatusAggregator::getUniformCode).toList();\n\t}\n\n\tpublic SimpleStatusAggregator(String... order) {\n\t\tthis.order = ObjectUtils.isEmpty(order) ? DEFAULT_ORDER.order\n\t\t\t\t: Arrays.stream(order).map(SimpleStatusAggregator::getUniformCode).toList();\n\t}\n\n\tpublic SimpleStatusAggregator(List<String> order) {\n\t\tthis.order = CollectionUtils.isEmpty(order) ? DEFAULT_ORDER.order\n\t\t\t\t: order.stream().map(SimpleStatusAggregator::getUniformCode).toList();\n\t}\n\n\tSimpleStatusAggregator(Stream<String> order) {\n\t\tthis.order = order.map(SimpleStatusAggregator::getUniformCode).toList();\n\t}\n\n\t@Override\n\tpublic Status getAggregateStatus(Set<Status> statuses) {\n\t\treturn statuses.stream().filter(this::contains).min(this.comparator).orElse(Status.UNKNOWN);\n\t}\n\n\tprivate boolean contains(Status status) {\n\t\treturn this.order.contains(getUniformCode(status));\n\t}\n\n\tprivate int orderIndex(Status status) {\n\t\treturn this.order.indexOf(getUniformCode(status));\n\t}\n\n\tprivate static @Nullable String getUniformCode(Status status) {\n\t\treturn getUniformCode(status.getCode());\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate static @Nullable String getUniformCode(@Nullable String code) {\n\t\treturn (code != null) ? code.codePoints()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)\n\t\t\t.toString() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/StatusAggregator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Strategy used to aggregate {@link Status} instances.\n * <p>\n * This is required in order to combine subsystem states expressed through\n * {@link Health#getStatus()} into one state for the health endpoint.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface StatusAggregator {\n\n\t/**\n\t * Return the aggregate status for the given set of statuses.\n\t * @param statuses the statuses to aggregate\n\t * @return the aggregate status\n\t */\n\tdefault Status getAggregateStatus(Status... statuses) {\n\t\treturn getAggregateStatus(new LinkedHashSet<>(Arrays.asList(statuses)));\n\t}\n\n\t/**\n\t * Return the aggregate status for the given set of statuses.\n\t * @param statuses the statuses to aggregate\n\t * @return the aggregate status\n\t */\n\tStatus getAggregateStatus(Set<Status> statuses);\n\n\t/**\n\t * Return a {@link StatusAggregator} backed by the given ordered status list.\n\t * @param order the status order\n\t * @return a {@link StatusAggregator} instance or {@link #getDefault()} if no order is\n\t * provided\n\t * @since 4.1.0\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic StatusAggregator of(Status... order) {\n\t\treturn (!ObjectUtils.isEmpty(order)) ? new SimpleStatusAggregator(Arrays.stream(order).map(Status::getCode))\n\t\t\t\t: getDefault();\n\t}\n\n\t/**\n\t * Return a {@link StatusAggregator} backed by the given ordered status list.\n\t * @param order the status order\n\t * @return a {@link StatusAggregator} instance or {@link #getDefault()} if no order is\n\t * provided\n\t * @since 4.1.0\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic StatusAggregator of(String... order) {\n\t\treturn (!ObjectUtils.isEmpty(order)) ? new SimpleStatusAggregator(Arrays.stream(order)) : getDefault();\n\t}\n\n\t/**\n\t * Return a {@link StatusAggregator} backed by the given ordered status list.\n\t * @param order the status order\n\t * @return a {@link StatusAggregator} instance or {@link #getDefault()} if no order is\n\t * provided\n\t * @since 4.1.0\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic StatusAggregator of(List<String> order) {\n\t\treturn (!ObjectUtils.isEmpty(order)) ? new SimpleStatusAggregator(order.stream()) : getDefault();\n\t}\n\n\t/**\n\t * Return {@link StatusAggregator} instance using default ordering rules.\n\t * @return a {@code StatusAggregator} with default ordering rules.\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic StatusAggregator getDefault() {\n\t\treturn SimpleStatusAggregator.DEFAULT_ORDER;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/SystemHealthDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.health.contributor.Status;\n\n/**\n * Description of overall system health.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class SystemHealthDescriptor extends CompositeHealthDescriptor {\n\n\tprivate final @Nullable Set<String> groups;\n\n\tSystemHealthDescriptor(ApiVersion apiVersion, Status status, @Nullable Map<String, HealthDescriptor> components,\n\t\t\t@Nullable Set<String> groups) {\n\t\tsuper(apiVersion, status, components);\n\t\tthis.groups = groups;\n\t}\n\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic @Nullable Set<String> getGroups() {\n\t\treturn this.groups;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for health.\n */\n@NullMarked\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/application/AvailabilityStateHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.AvailabilityState;\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link HealthIndicator} that checks a specific {@link AvailabilityState} of the\n * application.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class AvailabilityStateHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final ApplicationAvailability applicationAvailability;\n\n\tprivate final Class<? extends AvailabilityState> stateType;\n\n\tprivate final Map<@Nullable AvailabilityState, Status> statusMappings = new HashMap<>();\n\n\t/**\n\t * Create a new {@link AvailabilityStateHealthIndicator} instance.\n\t * @param <S> the availability state type\n\t * @param applicationAvailability the application availability\n\t * @param stateType the availability state type\n\t * @param statusMappings consumer used to set up the status mappings\n\t */\n\tpublic <S extends AvailabilityState> AvailabilityStateHealthIndicator(\n\t\t\tApplicationAvailability applicationAvailability, Class<S> stateType,\n\t\t\tConsumer<StatusMappings<S>> statusMappings) {\n\t\tAssert.notNull(applicationAvailability, \"'applicationAvailability' must not be null\");\n\t\tAssert.notNull(stateType, \"'stateType' must not be null\");\n\t\tAssert.notNull(statusMappings, \"'statusMappings' must not be null\");\n\t\tthis.applicationAvailability = applicationAvailability;\n\t\tthis.stateType = stateType;\n\t\tstatusMappings.accept(this.statusMappings::put);\n\t\tassertAllEnumsMapped(stateType);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate <S extends AvailabilityState> void assertAllEnumsMapped(Class<S> stateType) {\n\t\tif (!this.statusMappings.containsKey(null) && Enum.class.isAssignableFrom(stateType)) {\n\t\t\tEnumSet elements = EnumSet.allOf((Class) stateType);\n\t\t\tfor (Object element : elements) {\n\t\t\t\tAssert.state(this.statusMappings.containsKey(element),\n\t\t\t\t\t\t() -> \"StatusMappings does not include \" + element);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tAvailabilityState state = getState(this.applicationAvailability);\n\t\tStatus status = this.statusMappings.get(state);\n\t\tif (status == null) {\n\t\t\tstatus = this.statusMappings.get(null);\n\t\t}\n\t\tAssert.state(status != null, () -> \"No mapping provided for \" + state);\n\t\tbuilder.status(status);\n\t}\n\n\t/**\n\t * Return the current availability state. Subclasses can override this method if a\n\t * different retrieval mechanism is needed.\n\t * @param applicationAvailability the application availability\n\t * @return the current availability state\n\t */\n\tprotected @Nullable AvailabilityState getState(ApplicationAvailability applicationAvailability) {\n\t\treturn applicationAvailability.getState(this.stateType);\n\t}\n\n\t/**\n\t * Callback used to add status mappings.\n\t *\n\t * @param <S> the availability state type\n\t */\n\tpublic interface StatusMappings<S extends AvailabilityState> {\n\n\t\t/**\n\t\t * Add the status that should be used if no explicit mapping is defined.\n\t\t * @param status the default status\n\t\t */\n\t\tdefault void addDefaultStatus(Status status) {\n\t\t\tadd(null, status);\n\t\t}\n\n\t\t/**\n\t\t * Add a new status mapping .\n\t\t * @param availabilityState the availability state\n\t\t * @param status the mapped status\n\t\t */\n\t\tvoid add(@Nullable S availabilityState, Status status);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/application/DiskSpaceHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport java.io.File;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * A {@link HealthIndicator} that checks available disk space and reports a status of\n * {@link Status#DOWN} when it drops below a configurable threshold.\n *\n * @author Mattias Severson\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class DiskSpaceHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate static final Log logger = LogFactory.getLog(DiskSpaceHealthIndicator.class);\n\n\tprivate final File path;\n\n\tprivate final DataSize threshold;\n\n\t/**\n\t * Create a new {@code DiskSpaceHealthIndicator} instance.\n\t * @param path the Path used to compute the available disk space\n\t * @param threshold the minimum disk space that should be available\n\t */\n\tpublic DiskSpaceHealthIndicator(File path, DataSize threshold) {\n\t\tsuper(\"DiskSpace health check failed\");\n\t\tthis.path = path;\n\t\tthis.threshold = threshold;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tlong diskFreeInBytes = this.path.getUsableSpace();\n\t\tif (diskFreeInBytes >= this.threshold.toBytes()) {\n\t\t\tbuilder.up();\n\t\t}\n\t\telse {\n\t\t\tlogger.warn(LogMessage.format(\n\t\t\t\t\t\"Free disk space at path '%s' below threshold. Available: %d bytes (threshold: %s)\",\n\t\t\t\t\tthis.path.getAbsolutePath(), diskFreeInBytes, this.threshold));\n\t\t\tbuilder.down();\n\t\t}\n\t\tbuilder.withDetail(\"total\", this.path.getTotalSpace())\n\t\t\t.withDetail(\"free\", diskFreeInBytes)\n\t\t\t.withDetail(\"threshold\", this.threshold.toBytes())\n\t\t\t.withDetail(\"path\", this.path.getAbsolutePath())\n\t\t\t.withDetail(\"exists\", this.path.exists());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/application/LivenessStateHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.AvailabilityState;\nimport org.springframework.boot.availability.LivenessState;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\n\n/**\n * A {@link HealthIndicator} that checks the {@link LivenessState} of the application.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class LivenessStateHealthIndicator extends AvailabilityStateHealthIndicator {\n\n\tpublic LivenessStateHealthIndicator(ApplicationAvailability availability) {\n\t\tsuper(availability, LivenessState.class, (statusMappings) -> {\n\t\t\tstatusMappings.add(LivenessState.CORRECT, Status.UP);\n\t\t\tstatusMappings.add(LivenessState.BROKEN, Status.DOWN);\n\t\t});\n\t}\n\n\t@Override\n\tprotected AvailabilityState getState(ApplicationAvailability applicationAvailability) {\n\t\treturn applicationAvailability.getLivenessState();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/application/ReadinessStateHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.AvailabilityState;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\n\n/**\n * A {@link HealthIndicator} that checks the {@link ReadinessState} of the application.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ReadinessStateHealthIndicator extends AvailabilityStateHealthIndicator {\n\n\tpublic ReadinessStateHealthIndicator(ApplicationAvailability availability) {\n\t\tsuper(availability, ReadinessState.class, (statusMappings) -> {\n\t\t\tstatusMappings.add(ReadinessState.ACCEPTING_TRAFFIC, Status.UP);\n\t\t\tstatusMappings.add(ReadinessState.REFUSING_TRAFFIC, Status.OUT_OF_SERVICE);\n\t\t});\n\t}\n\n\t@Override\n\tprotected AvailabilityState getState(ApplicationAvailability applicationAvailability) {\n\t\treturn applicationAvailability.getReadinessState();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/application/SslHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.info.SslInfo.BundleInfo;\nimport org.springframework.boot.info.SslInfo.CertificateChainInfo;\nimport org.springframework.boot.info.SslInfo.CertificateInfo;\nimport org.springframework.boot.info.SslInfo.CertificateValidityInfo;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthIndicator} that checks the certificates the application uses and reports\n * {@link Status#OUT_OF_SERVICE} when a certificate is invalid.\n *\n * @author Jonatan Ivanov\n * @author Young Jae You\n * @since 4.0.0\n */\npublic class SslHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final SslInfo sslInfo;\n\n\tprivate final Duration expiryThreshold;\n\n\tpublic SslHealthIndicator(SslInfo sslInfo, Duration expiryThreshold) {\n\t\tsuper(\"SSL health check failed\");\n\t\tAssert.notNull(sslInfo, \"'sslInfo' must not be null\");\n\t\tthis.sslInfo = sslInfo;\n\t\tthis.expiryThreshold = expiryThreshold;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tList<CertificateChainInfo> validCertificateChains = new ArrayList<>();\n\t\tList<CertificateChainInfo> invalidCertificateChains = new ArrayList<>();\n\t\tList<CertificateChainInfo> expiringCertificateChains = new ArrayList<>();\n\t\tfor (BundleInfo bundle : this.sslInfo.getBundles()) {\n\t\t\tfor (CertificateChainInfo certificateChain : bundle.getCertificateChains()) {\n\t\t\t\tif (containsOnlyValidCertificates(certificateChain)) {\n\t\t\t\t\tvalidCertificateChains.add(certificateChain);\n\t\t\t\t\tif (containsExpiringCertificate(certificateChain)) {\n\t\t\t\t\t\texpiringCertificateChains.add(certificateChain);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (containsInvalidCertificate(certificateChain)) {\n\t\t\t\t\tinvalidCertificateChains.add(certificateChain);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbuilder.status((invalidCertificateChains.isEmpty()) ? Status.UP : Status.OUT_OF_SERVICE);\n\t\tbuilder.withDetail(\"expiringChains\", expiringCertificateChains);\n\t\tbuilder.withDetail(\"invalidChains\", invalidCertificateChains);\n\t\tbuilder.withDetail(\"validChains\", validCertificateChains);\n\t}\n\n\tprivate boolean containsOnlyValidCertificates(CertificateChainInfo certificateChain) {\n\t\treturn validatableCertificates(certificateChain).allMatch(this::isValidCertificate);\n\t}\n\n\tprivate boolean containsInvalidCertificate(CertificateChainInfo certificateChain) {\n\t\treturn validatableCertificates(certificateChain).anyMatch(this::isNotValidCertificate);\n\t}\n\n\tprivate boolean containsExpiringCertificate(CertificateChainInfo certificateChain) {\n\t\treturn validatableCertificates(certificateChain).anyMatch(this::isExpiringCertificate);\n\t}\n\n\tprivate Stream<CertificateInfo> validatableCertificates(CertificateChainInfo certificateChain) {\n\t\treturn certificateChain.getCertificates().stream().filter((certificate) -> certificate.getValidity() != null);\n\t}\n\n\tprivate boolean isValidCertificate(CertificateInfo certificate) {\n\t\tCertificateValidityInfo validity = certificate.getValidity();\n\t\tAssert.state(validity != null, \"'validity' must not be null\");\n\t\treturn validity.getStatus().isValid();\n\t}\n\n\tprivate boolean isNotValidCertificate(CertificateInfo certificate) {\n\t\treturn !isValidCertificate(certificate);\n\t}\n\n\tprivate boolean isExpiringCertificate(CertificateInfo certificate) {\n\t\tInstant validityEnds = certificate.getValidityEnds();\n\t\tAssert.state(validityEnds != null, \"'validityEnds' must not be null\");\n\t\treturn Instant.now().plus(this.expiryThreshold).isAfter(validityEnds);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/application/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health indicators providing information about an application.\n */\n@NullMarked\npackage org.springframework.boot.health.application;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AutoConfiguredHealthEndpointGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembership;\n\n/**\n * Auto-configured {@link HealthEndpointGroup}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass AutoConfiguredHealthEndpointGroup implements HealthEndpointGroup {\n\n\tprivate final HealthContributorMembership membership;\n\n\tprivate final StatusAggregator statusAggregator;\n\n\tprivate final HttpCodeStatusMapper httpCodeStatusMapper;\n\n\tprivate final @Nullable Show showComponents;\n\n\tprivate final Show showDetails;\n\n\tprivate final Collection<String> roles;\n\n\tprivate final @Nullable AdditionalHealthEndpointPath additionalPath;\n\n\t/**\n\t * Create a new {@link AutoConfiguredHealthEndpointGroup} instance.\n\t * @param membership used to test for group membership\n\t * @param statusAggregator the status aggregator to use\n\t * @param httpCodeStatusMapper the HTTP code status mapper to use\n\t * @param showComponents the show components setting\n\t * @param showDetails the show details setting\n\t * @param roles the roles to match\n\t * @param additionalPath the additional path to use for this group\n\t */\n\tAutoConfiguredHealthEndpointGroup(HealthContributorMembership membership, StatusAggregator statusAggregator,\n\t\t\tHttpCodeStatusMapper httpCodeStatusMapper, @Nullable Show showComponents, Show showDetails,\n\t\t\tCollection<String> roles, @Nullable AdditionalHealthEndpointPath additionalPath) {\n\t\tthis.membership = membership;\n\t\tthis.statusAggregator = statusAggregator;\n\t\tthis.httpCodeStatusMapper = httpCodeStatusMapper;\n\t\tthis.showComponents = showComponents;\n\t\tthis.showDetails = showDetails;\n\t\tthis.roles = roles;\n\t\tthis.additionalPath = additionalPath;\n\t}\n\n\t@Override\n\tpublic boolean isMember(String name) {\n\t\treturn this.membership.isMember(name);\n\t}\n\n\t@Override\n\tpublic boolean showComponents(SecurityContext securityContext) {\n\t\tShow show = (this.showComponents != null) ? this.showComponents : this.showDetails;\n\t\treturn show.isShown(securityContext, this.roles);\n\t}\n\n\t@Override\n\tpublic boolean showDetails(SecurityContext securityContext) {\n\t\treturn this.showDetails.isShown(securityContext, this.roles);\n\t}\n\n\t@Override\n\tpublic StatusAggregator getStatusAggregator() {\n\t\treturn this.statusAggregator;\n\t}\n\n\t@Override\n\tpublic HttpCodeStatusMapper getHttpCodeStatusMapper() {\n\t\treturn this.httpCodeStatusMapper;\n\t}\n\n\t@Override\n\tpublic @Nullable AdditionalHealthEndpointPath getAdditionalPath() {\n\t\treturn this.additionalPath;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AutoConfiguredHealthEndpointGroups.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointProperties.Group;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthProperties.Status;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembership;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Auto-configured {@link HealthEndpointGroups}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AutoConfiguredHealthEndpointGroups implements HealthEndpointGroups, AdditionalPathsMapper {\n\n\tprivate final HealthEndpointGroup primaryGroup;\n\n\tprivate final Map<String, HealthEndpointGroup> groups;\n\n\t/**\n\t * Create a new {@link AutoConfiguredHealthEndpointGroups} instance.\n\t * @param applicationContext the application context used to check for override beans\n\t * @param properties the health endpoint properties\n\t */\n\tAutoConfiguredHealthEndpointGroups(ApplicationContext applicationContext, HealthEndpointProperties properties) {\n\t\tListableBeanFactory beanFactory = (applicationContext instanceof ConfigurableApplicationContext configurableContext)\n\t\t\t\t? configurableContext.getBeanFactory() : applicationContext;\n\t\tShow showComponents = properties.getShowComponents();\n\t\tShow showDetails = properties.getShowDetails();\n\t\tSet<String> roles = properties.getRoles();\n\t\tStatusAggregator statusAggregator = getNonQualifiedBean(beanFactory, StatusAggregator.class,\n\t\t\t\t() -> StatusAggregator.of(properties.getStatus().getOrder()));\n\t\tHttpCodeStatusMapper statusMapper = getNonQualifiedBean(beanFactory, HttpCodeStatusMapper.class,\n\t\t\t\t() -> HttpCodeStatusMapper.of(properties.getStatus().getHttpMapping()));\n\t\tthis.primaryGroup = new AutoConfiguredHealthEndpointGroup(HealthContributorMembership.always(),\n\t\t\t\tstatusAggregator, statusMapper, showComponents, showDetails, roles, null);\n\t\tthis.groups = createGroups(properties.getGroup(), beanFactory, statusAggregator, statusMapper, showComponents,\n\t\t\t\tshowDetails, roles);\n\t}\n\n\tprivate Map<String, HealthEndpointGroup> createGroups(Map<String, Group> groupProperties, BeanFactory beanFactory,\n\t\t\tStatusAggregator defaultStatusAggregator, HttpCodeStatusMapper defaultStatusMapper,\n\t\t\t@Nullable Show defaultShowComponents, Show defaultShowDetails, Set<String> defaultRoles) {\n\t\tMap<String, HealthEndpointGroup> groups = new TreeMap<>();\n\t\tgroupProperties.forEach((groupName, group) -> {\n\t\t\tStatus status = group.getStatus();\n\t\t\tShow showComponents = (group.getShowComponents() != null) ? group.getShowComponents()\n\t\t\t\t\t: defaultShowComponents;\n\t\t\tShow showDetails = (group.getShowDetails() != null) ? group.getShowDetails() : defaultShowDetails;\n\t\t\tSet<String> roles = !CollectionUtils.isEmpty(group.getRoles()) ? group.getRoles() : defaultRoles;\n\t\t\tStatusAggregator statusAggregator = getQualifiedBean(beanFactory, StatusAggregator.class, groupName,\n\t\t\t\t\t() -> createStatusAggregator(status.getOrder(), defaultStatusAggregator));\n\t\t\tHttpCodeStatusMapper statusMapper = getQualifiedBean(beanFactory, HttpCodeStatusMapper.class, groupName,\n\t\t\t\t\t() -> createStatusMapper(status.getHttpMapping(), defaultStatusMapper));\n\t\t\tHealthContributorMembership membership = HealthContributorMembership.byIncludeExclude(group.getInclude(),\n\t\t\t\t\tgroup.getExclude());\n\t\t\tAdditionalHealthEndpointPath additionalPath = (group.getAdditionalPath() != null)\n\t\t\t\t\t? AdditionalHealthEndpointPath.from(group.getAdditionalPath()) : null;\n\t\t\tgroups.put(groupName, new AutoConfiguredHealthEndpointGroup(membership, statusAggregator, statusMapper,\n\t\t\t\t\tshowComponents, showDetails, roles, additionalPath));\n\t\t});\n\t\treturn Collections.unmodifiableMap(groups);\n\t}\n\n\tprivate StatusAggregator createStatusAggregator(List<String> order, StatusAggregator defaultStatusAggregator) {\n\t\treturn (!CollectionUtils.isEmpty(order)) ? StatusAggregator.of(order) : defaultStatusAggregator;\n\t}\n\n\tprivate HttpCodeStatusMapper createStatusMapper(Map<String, Integer> mapping,\n\t\t\tHttpCodeStatusMapper defaultStatusMapper) {\n\t\treturn (!CollectionUtils.isEmpty(mapping)) ? HttpCodeStatusMapper.of(mapping) : defaultStatusMapper;\n\t}\n\n\tprivate <T> T getNonQualifiedBean(ListableBeanFactory beanFactory, Class<T> type, Supplier<T> fallback) {\n\t\tList<String> candidates = new ArrayList<>();\n\t\tfor (String beanName : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {\n\t\t\tString[] aliases = beanFactory.getAliases(beanName);\n\t\t\tif (!BeanFactoryAnnotationUtils.isQualifierMatch(\n\t\t\t\t\t(qualifier) -> !qualifier.equals(beanName) && !ObjectUtils.containsElement(aliases, qualifier),\n\t\t\t\t\tbeanName, beanFactory)) {\n\t\t\t\tcandidates.add(beanName);\n\t\t\t}\n\t\t}\n\t\tif (candidates.isEmpty()) {\n\t\t\treturn fallback.get();\n\t\t}\n\t\tif (candidates.size() == 1) {\n\t\t\treturn beanFactory.getBean(candidates.get(0), type);\n\t\t}\n\t\treturn beanFactory.getBean(type);\n\t}\n\n\tprivate <T> T getQualifiedBean(BeanFactory beanFactory, Class<T> type, String qualifier, Supplier<T> fallback) {\n\t\ttry {\n\t\t\treturn BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, type, qualifier);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn fallback.get();\n\t\t}\n\t}\n\n\t@Override\n\tpublic HealthEndpointGroup getPrimary() {\n\t\treturn this.primaryGroup;\n\t}\n\n\t@Override\n\tpublic Set<String> getNames() {\n\t\treturn this.groups.keySet();\n\t}\n\n\t@Override\n\tpublic @Nullable HealthEndpointGroup get(String name) {\n\t\treturn this.groups.get(name);\n\t}\n\n\t@Override\n\tpublic @Nullable List<String> getAdditionalPaths(EndpointId endpointId, WebServerNamespace webServerNamespace) {\n\t\tif (!HealthEndpoint.ID.equals(endpointId)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn streamAllGroups().map(HealthEndpointGroup::getAdditionalPath)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.filter((additionalPath) -> additionalPath.hasNamespace(webServerNamespace))\n\t\t\t.map(AdditionalHealthEndpointPath::getValue)\n\t\t\t.toList();\n\t}\n\n\tprivate Stream<HealthEndpointGroup> streamAllGroups() {\n\t\treturn Stream.concat(Stream.of(this.primaryGroup), this.groups.values().stream());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.health.application.LivenessStateHealthIndicator;\nimport org.springframework.boot.health.application.ReadinessStateHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.application.AvailabilityHealthContributorAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for availability probes.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = { AvailabilityHealthContributorAutoConfiguration.class,\n\t\tApplicationAvailabilityAutoConfiguration.class })\n@ConditionalOnClass(name = \"org.springframework.boot.actuate.endpoint.annotation.Endpoint\")\n@ConditionalOnBooleanProperty(name = \"management.endpoint.health.probes.enabled\", matchIfMissing = true)\npublic final class AvailabilityProbesAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"livenessStateHealthIndicator\")\n\tLivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) {\n\t\treturn new LivenessStateHealthIndicator(applicationAvailability);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"readinessStateHealthIndicator\")\n\tReadinessStateHealthIndicator readinessStateHealthIndicator(ApplicationAvailability applicationAvailability) {\n\t\treturn new ReadinessStateHealthIndicator(applicationAvailability);\n\t}\n\n\t@Bean\n\tAvailabilityProbesHealthEndpointGroupsPostProcessor availabilityProbesHealthEndpointGroupsPostProcessor(\n\t\t\tEnvironment environment) {\n\t\treturn new AvailabilityProbesHealthEndpointGroupsPostProcessor(environment);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesHealthEndpointGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\n\n/**\n * {@link HealthEndpointGroup} used to support availability probes.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n */\nclass AvailabilityProbesHealthEndpointGroup implements HealthEndpointGroup {\n\n\tprivate final Set<String> members;\n\n\tprivate final @Nullable AdditionalHealthEndpointPath additionalPath;\n\n\tAvailabilityProbesHealthEndpointGroup(@Nullable AdditionalHealthEndpointPath additionalPath, String... members) {\n\t\tthis.members = new HashSet<>(Arrays.asList(members));\n\t\tthis.additionalPath = additionalPath;\n\t}\n\n\t@Override\n\tpublic boolean isMember(String name) {\n\t\treturn this.members.contains(name);\n\t}\n\n\t@Override\n\tpublic boolean showComponents(SecurityContext securityContext) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic boolean showDetails(SecurityContext securityContext) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic StatusAggregator getStatusAggregator() {\n\t\treturn StatusAggregator.getDefault();\n\t}\n\n\t@Override\n\tpublic HttpCodeStatusMapper getHttpCodeStatusMapper() {\n\t\treturn HttpCodeStatusMapper.getDefault();\n\t}\n\n\t@Override\n\tpublic @Nullable AdditionalHealthEndpointPath getAdditionalPath() {\n\t\treturn this.additionalPath;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesHealthEndpointGroups.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthEndpointGroups} decorator to support availability probes.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n * @author Madhura Bhave\n */\nclass AvailabilityProbesHealthEndpointGroups implements HealthEndpointGroups, AdditionalPathsMapper {\n\n\tprivate final HealthEndpointGroups groups;\n\n\tprivate final Map<String, HealthEndpointGroup> probeGroups;\n\n\tprivate final Set<String> names;\n\n\tprivate static final String LIVENESS = \"liveness\";\n\n\tprivate static final String READINESS = \"readiness\";\n\n\tAvailabilityProbesHealthEndpointGroups(HealthEndpointGroups groups, boolean addAdditionalPaths) {\n\t\tAssert.notNull(groups, \"'groups' must not be null\");\n\t\tthis.groups = groups;\n\t\tthis.probeGroups = createProbeGroups(addAdditionalPaths);\n\t\tSet<String> names = new LinkedHashSet<>(groups.getNames());\n\t\tnames.addAll(this.probeGroups.keySet());\n\t\tthis.names = Collections.unmodifiableSet(names);\n\t}\n\n\tprivate Map<String, HealthEndpointGroup> createProbeGroups(boolean addAdditionalPaths) {\n\t\tMap<String, HealthEndpointGroup> probeGroups = new LinkedHashMap<>();\n\t\tprobeGroups.put(LIVENESS, getOrCreateProbeGroup(addAdditionalPaths, LIVENESS, \"/livez\", \"livenessState\"));\n\t\tprobeGroups.put(READINESS, getOrCreateProbeGroup(addAdditionalPaths, READINESS, \"/readyz\", \"readinessState\"));\n\t\treturn Collections.unmodifiableMap(probeGroups);\n\t}\n\n\tprivate HealthEndpointGroup getOrCreateProbeGroup(boolean addAdditionalPath, String name, String path,\n\t\t\tString members) {\n\t\tHealthEndpointGroup group = this.groups.get(name);\n\t\tif (group != null) {\n\t\t\treturn determineAdditionalPathForExistingGroup(addAdditionalPath, path, group);\n\t\t}\n\t\tAdditionalHealthEndpointPath additionalPath = (!addAdditionalPath) ? null\n\t\t\t\t: AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER, path);\n\t\treturn new AvailabilityProbesHealthEndpointGroup(additionalPath, members);\n\t}\n\n\tprivate HealthEndpointGroup determineAdditionalPathForExistingGroup(boolean addAdditionalPath, String path,\n\t\t\tHealthEndpointGroup group) {\n\t\tif (addAdditionalPath && group.getAdditionalPath() == null) {\n\t\t\tAdditionalHealthEndpointPath additionalPath = AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER,\n\t\t\t\t\tpath);\n\t\t\treturn new DelegatingAvailabilityProbesHealthEndpointGroup(group, additionalPath);\n\t\t}\n\t\treturn group;\n\t}\n\n\t@Override\n\tpublic HealthEndpointGroup getPrimary() {\n\t\treturn this.groups.getPrimary();\n\t}\n\n\t@Override\n\tpublic Set<String> getNames() {\n\t\treturn this.names;\n\t}\n\n\t@Override\n\tpublic @Nullable HealthEndpointGroup get(String name) {\n\t\tHealthEndpointGroup group = this.groups.get(name);\n\t\tif (group == null || isProbeGroup(name)) {\n\t\t\tgroup = this.probeGroups.get(name);\n\t\t}\n\t\treturn group;\n\t}\n\n\tprivate boolean isProbeGroup(String name) {\n\t\treturn name.equals(LIVENESS) || name.equals(READINESS);\n\t}\n\n\t@Override\n\tpublic @Nullable List<String> getAdditionalPaths(EndpointId endpointId, WebServerNamespace webServerNamespace) {\n\t\tif (!HealthEndpoint.ID.equals(endpointId)) {\n\t\t\treturn null;\n\t\t}\n\t\tList<String> additionalPaths = new ArrayList<>();\n\t\tif (this.groups instanceof AdditionalPathsMapper additionalPathsMapper) {\n\t\t\tList<String> mappedAdditionalPaths = getAdditionalPaths(endpointId, webServerNamespace,\n\t\t\t\t\tadditionalPathsMapper);\n\t\t\tif (mappedAdditionalPaths != null) {\n\t\t\t\tadditionalPaths.addAll(mappedAdditionalPaths);\n\t\t\t}\n\t\t}\n\t\tadditionalPaths.addAll(this.probeGroups.values()\n\t\t\t.stream()\n\t\t\t.map(HealthEndpointGroup::getAdditionalPath)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.filter((additionalPath) -> additionalPath.hasNamespace(webServerNamespace))\n\t\t\t.map(AdditionalHealthEndpointPath::getValue)\n\t\t\t.toList());\n\t\treturn additionalPaths;\n\t}\n\n\tprivate static @Nullable List<String> getAdditionalPaths(EndpointId endpointId,\n\t\t\tWebServerNamespace webServerNamespace, AdditionalPathsMapper additionalPathsMapper) {\n\t\treturn additionalPathsMapper.getAdditionalPaths(endpointId, webServerNamespace);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesHealthEndpointGroupsPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroupsPostProcessor;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link HealthEndpointGroupsPostProcessor} to add\n * {@link AvailabilityProbesHealthEndpointGroups}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@Order(Ordered.LOWEST_PRECEDENCE)\nclass AvailabilityProbesHealthEndpointGroupsPostProcessor implements HealthEndpointGroupsPostProcessor {\n\n\tprivate final boolean addAdditionalPaths;\n\n\tAvailabilityProbesHealthEndpointGroupsPostProcessor(Environment environment) {\n\t\tthis.addAdditionalPaths = \"true\"\n\t\t\t.equalsIgnoreCase(environment.getProperty(\"management.endpoint.health.probes.add-additional-paths\"));\n\t}\n\n\t@Override\n\tpublic HealthEndpointGroups postProcessHealthEndpointGroups(HealthEndpointGroups groups) {\n\t\treturn new AvailabilityProbesHealthEndpointGroups(groups, this.addAdditionalPaths);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/DelegatingAvailabilityProbesHealthEndpointGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthEndpointGroup} used to support availability probes that delegates to an\n * existing group.\n *\n * @author Madhura Bhave\n */\nclass DelegatingAvailabilityProbesHealthEndpointGroup implements HealthEndpointGroup {\n\n\tprivate final HealthEndpointGroup delegate;\n\n\tprivate final AdditionalHealthEndpointPath additionalPath;\n\n\tDelegatingAvailabilityProbesHealthEndpointGroup(HealthEndpointGroup delegate,\n\t\t\tAdditionalHealthEndpointPath additionalPath) {\n\t\tAssert.notNull(delegate, \"'delegate' must not be null\");\n\t\tthis.delegate = delegate;\n\t\tthis.additionalPath = additionalPath;\n\t}\n\n\t@Override\n\tpublic boolean isMember(String name) {\n\t\treturn this.delegate.isMember(name);\n\t}\n\n\t@Override\n\tpublic boolean showComponents(SecurityContext securityContext) {\n\t\treturn this.delegate.showComponents(securityContext);\n\t}\n\n\t@Override\n\tpublic boolean showDetails(SecurityContext securityContext) {\n\t\treturn this.delegate.showDetails(securityContext);\n\t}\n\n\t@Override\n\tpublic StatusAggregator getStatusAggregator() {\n\t\treturn this.delegate.getStatusAggregator();\n\t}\n\n\t@Override\n\tpublic HttpCodeStatusMapper getHttpCodeStatusMapper() {\n\t\treturn this.delegate.getHttpCodeStatusMapper();\n\t}\n\n\t@Override\n\tpublic AdditionalHealthEndpointPath getAdditionalPath() {\n\t\treturn this.additionalPath;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/GroupsHealthContributorNameValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.registry.HealthContributorNameValidator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthContributorNameValidator} to ensure names don't clash with groups.\n *\n * @author Phillip Webb\n */\nclass GroupsHealthContributorNameValidator implements HealthContributorNameValidator {\n\n\tprivate final Set<String> groupNames;\n\n\tGroupsHealthContributorNameValidator(@Nullable HealthEndpointGroups groups) {\n\t\tthis.groupNames = (groups != null) ? groups.getNames() : Collections.emptySet();\n\t}\n\n\t@Override\n\tpublic void validate(String name) throws IllegalStateException {\n\t\tAssert.state(!this.groupNames.contains(name),\n\t\t\t\t() -> \"HealthContributor with name \\\"\" + name + \"\\\" clashes with group\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HealthEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(after = HealthContributorRegistryAutoConfiguration.class)\n@ConditionalOnClass(name = \"org.springframework.boot.actuate.endpoint.annotation.Endpoint\")\n@ConditionalOnBean(type = \"org.springframework.boot.health.registry.HealthContributorRegistry\")\n@ConditionalOnAvailableEndpoint(HealthEndpoint.class)\n@EnableConfigurationProperties(HealthEndpointProperties.class)\n@Import({ HealthEndpointConfiguration.class, HealthEndpointWebExtensionConfiguration.class,\n\t\tHealthEndpointReactiveWebExtensionConfiguration.class })\npublic final class HealthEndpointAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthEndpointConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroupsPostProcessor;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorMembershipValidator;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for {@link HealthEndpoint} infrastructure beans.\n *\n * @author Phillip Webb\n * @see HealthEndpointAutoConfiguration\n */\n@Configuration(proxyBeanMethods = false)\nclass HealthEndpointConfiguration {\n\n\tprivate static final String VALIDATE_MEMBERSHIP_PROPERTY = \"management.endpoint.health.validate-group-membership\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStatusAggregator healthStatusAggregator(HealthEndpointProperties properties) {\n\t\treturn StatusAggregator.of(properties.getStatus().getOrder());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHttpCodeStatusMapper healthHttpCodeStatusMapper(HealthEndpointProperties properties) {\n\t\treturn HttpCodeStatusMapper.of(properties.getStatus().getHttpMapping());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(HealthEndpointGroups.class)\n\tAutoConfiguredHealthEndpointGroups healthEndpointGroups(ApplicationContext applicationContext,\n\t\t\tHealthEndpointProperties properties) {\n\t\treturn new AutoConfiguredHealthEndpointGroups(applicationContext, properties);\n\t}\n\n\t@Bean\n\tGroupsHealthContributorNameValidator groupsHealthContributorNameValidator(\n\t\t\tObjectProvider<HealthEndpointGroups> healthEndpointGroups) {\n\t\treturn new GroupsHealthContributorNameValidator(healthEndpointGroups.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnBooleanProperty(name = VALIDATE_MEMBERSHIP_PROPERTY, matchIfMissing = true)\n\tHealthContributorMembershipValidator healthEndpointGroupMembershipValidator(HealthEndpointProperties properties,\n\t\t\tHealthContributorRegistry healthContributorRegistry,\n\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry) {\n\t\treturn new HealthContributorMembershipValidator(healthContributorRegistry,\n\t\t\t\treactiveHealthContributorRegistry.getIfAvailable(), VALIDATE_MEMBERSHIP_PROPERTY,\n\t\t\t\t(members) -> properties.getGroup().forEach((groupName, group) -> {\n\t\t\t\t\tString property = \"management.endpoint.health.group.\" + groupName;\n\t\t\t\t\tmembers.member(property + \".include\".formatted(groupName), group.getInclude());\n\t\t\t\t\tmembers.member(property + \".exclude\".formatted(groupName), group.getExclude());\n\t\t\t\t}));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHealthEndpoint healthEndpoint(HealthContributorRegistry healthContributorRegistry,\n\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,\n\t\t\tHealthEndpointGroups groups, HealthEndpointProperties properties) {\n\t\treturn new HealthEndpoint(healthContributorRegistry, reactiveHealthContributorRegistry.getIfAvailable(), groups,\n\t\t\t\tproperties.getLogging().getSlowIndicatorThreshold());\n\t}\n\n\t@Bean\n\tstatic HealthEndpointGroupsBeanPostProcessor healthEndpointGroupsBeanPostProcessor(\n\t\t\tObjectProvider<HealthEndpointGroupsPostProcessor> healthEndpointGroupsPostProcessors) {\n\t\treturn new HealthEndpointGroupsBeanPostProcessor(healthEndpointGroupsPostProcessors);\n\t}\n\n\t/**\n\t * {@link BeanPostProcessor} to invoke {@link HealthEndpointGroupsPostProcessor}\n\t * beans.\n\t */\n\tstatic class HealthEndpointGroupsBeanPostProcessor implements BeanPostProcessor {\n\n\t\tprivate final ObjectProvider<HealthEndpointGroupsPostProcessor> postProcessors;\n\n\t\tHealthEndpointGroupsBeanPostProcessor(ObjectProvider<HealthEndpointGroupsPostProcessor> postProcessors) {\n\t\t\tthis.postProcessors = postProcessors;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tif (bean instanceof HealthEndpointGroups groups) {\n\t\t\t\treturn applyPostProcessors(groups);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate Object applyPostProcessors(HealthEndpointGroups bean) {\n\t\t\tfor (HealthEndpointGroupsPostProcessor postProcessor : this.postProcessors.orderedStream()\n\t\t\t\t.toArray(HealthEndpointGroupsPostProcessor[]::new)) {\n\t\t\t\tbean = postProcessor.postProcessHealthEndpointGroups(bean);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\n\n/**\n * Configuration properties for {@link HealthEndpoint}.\n *\n * @author Phillip Webb\n * @author Leo Li\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.endpoint.health\")\npublic class HealthEndpointProperties extends HealthProperties {\n\n\t/**\n\t * When to show full health details.\n\t */\n\tprivate Show showDetails = Show.NEVER;\n\n\t/**\n\t * Health endpoint groups.\n\t */\n\tprivate final Map<String, Group> group = new LinkedHashMap<>();\n\n\tprivate final Logging logging = new Logging();\n\n\t@Override\n\tpublic Show getShowDetails() {\n\t\treturn this.showDetails;\n\t}\n\n\tpublic void setShowDetails(Show showDetails) {\n\t\tthis.showDetails = showDetails;\n\t}\n\n\tpublic Map<String, Group> getGroup() {\n\t\treturn this.group;\n\t}\n\n\tpublic Logging getLogging() {\n\t\treturn this.logging;\n\t}\n\n\t/**\n\t * A health endpoint group.\n\t */\n\tpublic static class Group extends HealthProperties {\n\n\t\tpublic static final String SERVER_PREFIX = \"server:\";\n\n\t\tpublic static final String MANAGEMENT_PREFIX = \"management:\";\n\n\t\t/**\n\t\t * Health indicator IDs that should be included or '*' for all.\n\t\t */\n\t\tprivate @Nullable Set<String> include;\n\n\t\t/**\n\t\t * Health indicator IDs that should be excluded or '*' for all.\n\t\t */\n\t\tprivate @Nullable Set<String> exclude;\n\n\t\t/**\n\t\t * When to show full health details. Defaults to the value of\n\t\t * 'management.endpoint.health.show-details'.\n\t\t */\n\t\tprivate @Nullable Show showDetails;\n\n\t\t/**\n\t\t * Additional path that this group can be made available on. The additional path\n\t\t * must start with a valid prefix, either `server` or `management` to indicate if\n\t\t * it will be available on the main port or the management port. For instance,\n\t\t * `server:/healthz` will configure the group on the main port at `/healthz`.\n\t\t */\n\t\tprivate @Nullable String additionalPath;\n\n\t\tpublic @Nullable Set<String> getInclude() {\n\t\t\treturn this.include;\n\t\t}\n\n\t\tpublic void setInclude(@Nullable Set<String> include) {\n\t\t\tthis.include = include;\n\t\t}\n\n\t\tpublic @Nullable Set<String> getExclude() {\n\t\t\treturn this.exclude;\n\t\t}\n\n\t\tpublic void setExclude(@Nullable Set<String> exclude) {\n\t\t\tthis.exclude = exclude;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Show getShowDetails() {\n\t\t\treturn this.showDetails;\n\t\t}\n\n\t\tpublic void setShowDetails(@Nullable Show showDetails) {\n\t\t\tthis.showDetails = showDetails;\n\t\t}\n\n\t\tpublic @Nullable String getAdditionalPath() {\n\t\t\treturn this.additionalPath;\n\t\t}\n\n\t\tpublic void setAdditionalPath(@Nullable String additionalPath) {\n\t\t\tthis.additionalPath = additionalPath;\n\t\t}\n\n\t}\n\n\t/**\n\t * Health logging properties.\n\t */\n\tpublic static class Logging {\n\n\t\t/**\n\t\t * Threshold after which a warning will be logged for slow health indicators.\n\t\t */\n\t\tprivate Duration slowIndicatorThreshold = Duration.ofSeconds(10);\n\n\t\tpublic Duration getSlowIndicatorThreshold() {\n\t\t\treturn this.slowIndicatorThreshold;\n\t\t}\n\n\t\tpublic void setSlowIndicatorThreshold(Duration slowIndicatorThreshold) {\n\t\t\tthis.slowIndicatorThreshold = slowIndicatorThreshold;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthEndpointReactiveWebExtensionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for {@link HealthEndpoint} reactive web extensions.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see HealthEndpointAutoConfiguration\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\nclass HealthEndpointReactiveWebExtensionConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(HealthEndpoint.class)\n\tReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension(\n\t\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry,\n\t\t\tObjectProvider<HealthContributorRegistry> healthContributorRegistry, HealthEndpointGroups groups,\n\t\t\tHealthEndpointProperties properties) {\n\t\treturn new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry,\n\t\t\t\thealthContributorRegistry.getIfAvailable(), groups,\n\t\t\t\tproperties.getLogging().getSlowIndicatorThreshold());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthEndpointWebExtensionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for {@link HealthEndpoint} web extensions.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @see HealthEndpointAutoConfiguration\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnBean(HealthEndpoint.class)\n@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\nclass HealthEndpointWebExtensionConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHealthEndpointWebExtension healthEndpointWebExtension(HealthContributorRegistry healthContributorRegistry,\n\t\t\tObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry,\n\t\t\tHealthEndpointGroups groups, HealthEndpointProperties properties) {\n\t\treturn new HealthEndpointWebExtension(healthContributorRegistry,\n\t\t\t\treactiveHealthContributorRegistry.getIfAvailable(), groups,\n\t\t\t\tproperties.getLogging().getSlowIndicatorThreshold());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Properties used to configure the health endpoint and endpoint groups.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class HealthProperties {\n\n\t@NestedConfigurationProperty\n\tprivate final Status status = new Status();\n\n\t/**\n\t * When to show components. If not specified the 'show-details' setting will be used.\n\t */\n\tprivate @Nullable Show showComponents;\n\n\t/**\n\t * Roles used to determine whether a user is authorized to be shown details. When\n\t * empty, all authenticated users are authorized.\n\t */\n\tprivate Set<String> roles = new HashSet<>();\n\n\tpublic Status getStatus() {\n\t\treturn this.status;\n\t}\n\n\tpublic @Nullable Show getShowComponents() {\n\t\treturn this.showComponents;\n\t}\n\n\tpublic void setShowComponents(@Nullable Show showComponents) {\n\t\tthis.showComponents = showComponents;\n\t}\n\n\tpublic abstract @Nullable Show getShowDetails();\n\n\tpublic Set<String> getRoles() {\n\t\treturn this.roles;\n\t}\n\n\tpublic void setRoles(Set<String> roles) {\n\t\tthis.roles = roles;\n\t}\n\n\t/**\n\t * Status properties for the group.\n\t */\n\tpublic static class Status {\n\n\t\t/**\n\t\t * List of health statuses in order of severity.\n\t\t */\n\t\tprivate List<String> order = new ArrayList<>();\n\n\t\t/**\n\t\t * Mapping of health statuses to HTTP status codes. By default, registered health\n\t\t * statuses map to sensible defaults (for example, UP maps to 200).\n\t\t */\n\t\tprivate final Map<String, Integer> httpMapping = new HashMap<>();\n\n\t\tpublic List<String> getOrder() {\n\t\t\treturn this.order;\n\t\t}\n\n\t\tpublic void setOrder(List<String> statusOrder) {\n\t\t\tif (!CollectionUtils.isEmpty(statusOrder)) {\n\t\t\t\tthis.order = statusOrder;\n\t\t\t}\n\t\t}\n\n\t\tpublic Map<String, Integer> getHttpMapping() {\n\t\t\treturn this.httpMapping;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for health actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/application/AvailabilityHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.health.application.AvailabilityStateHealthIndicator;\nimport org.springframework.boot.health.application.LivenessStateHealthIndicator;\nimport org.springframework.boot.health.application.ReadinessStateHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link AvailabilityStateHealthIndicator}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = ApplicationAvailabilityAutoConfiguration.class)\n@ConditionalOnClass(Health.class)\npublic final class AvailabilityHealthContributorAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"livenessStateHealthIndicator\")\n\t@ConditionalOnBooleanProperty(\"management.health.livenessstate.enabled\")\n\tLivenessStateHealthIndicator livenessStateHealthIndicator(ApplicationAvailability applicationAvailability) {\n\t\treturn new LivenessStateHealthIndicator(applicationAvailability);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"readinessStateHealthIndicator\")\n\t@ConditionalOnBooleanProperty(\"management.health.readinessstate.enabled\")\n\tReadinessStateHealthIndicator readinessStateHealthIndicator(ApplicationAvailability applicationAvailability) {\n\t\treturn new ReadinessStateHealthIndicator(applicationAvailability);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/application/DiskSpaceHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.application.DiskSpaceHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link DiskSpaceHealthIndicator}.\n *\n * @author Mattias Severson\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(before = HealthContributorAutoConfiguration.class)\n@ConditionalOnClass(Health.class)\n@ConditionalOnEnabledHealthIndicator(\"diskspace\")\n@EnableConfigurationProperties(DiskSpaceHealthIndicatorProperties.class)\npublic final class DiskSpaceHealthContributorAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"diskSpaceHealthIndicator\")\n\tDiskSpaceHealthIndicator diskSpaceHealthIndicator(DiskSpaceHealthIndicatorProperties properties) {\n\t\treturn new DiskSpaceHealthIndicator(properties.getPath(), properties.getThreshold());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/application/DiskSpaceHealthIndicatorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport java.io.File;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.health.application.DiskSpaceHealthIndicator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * External configuration properties for {@link DiskSpaceHealthIndicator}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.health.diskspace\")\npublic class DiskSpaceHealthIndicatorProperties {\n\n\t/**\n\t * Path used to compute the available disk space.\n\t */\n\tprivate File path = new File(\".\");\n\n\t/**\n\t * Minimum disk space that should be available.\n\t */\n\tprivate DataSize threshold = DataSize.ofMegabytes(10);\n\n\tpublic File getPath() {\n\t\treturn this.path;\n\t}\n\n\tpublic void setPath(File path) {\n\t\tthis.path = path;\n\t}\n\n\tpublic DataSize getThreshold() {\n\t\treturn this.threshold;\n\t}\n\n\tpublic void setThreshold(DataSize threshold) {\n\t\tAssert.isTrue(!threshold.isNegative(), \"'threshold' must be greater than or equal to 0\");\n\t\tthis.threshold = threshold;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/application/SslHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.application.SslHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link SslHealthIndicator}.\n *\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@AutoConfiguration(before = HealthContributorAutoConfiguration.class)\n@ConditionalOnClass(Health.class)\n@ConditionalOnEnabledHealthIndicator(\"ssl\")\n@EnableConfigurationProperties(SslHealthIndicatorProperties.class)\npublic final class SslHealthContributorAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"sslHealthIndicator\")\n\tSslHealthIndicator sslHealthIndicator(SslInfo sslInfo, SslHealthIndicatorProperties properties) {\n\t\treturn new SslHealthIndicator(sslInfo, properties.getCertificateValidityWarningThreshold());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSslInfo sslInfo(SslBundles sslBundles) {\n\t\treturn new SslInfo(sslBundles);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/application/SslHealthIndicatorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.health.application.SslHealthIndicator;\n\n/**\n * External configuration properties for {@link SslHealthIndicator}.\n *\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.health.ssl\")\npublic class SslHealthIndicatorProperties {\n\n\t/**\n\t * If an SSL Certificate will be invalid within the time span defined by this\n\t * threshold, it should trigger a warning.\n\t */\n\tprivate Duration certificateValidityWarningThreshold = Duration.ofDays(14);\n\n\tpublic Duration getCertificateValidityWarningThreshold() {\n\t\treturn this.certificateValidityWarningThreshold;\n\t}\n\n\tpublic void setCertificateValidityWarningThreshold(Duration certificateValidityWarningThreshold) {\n\t\tthis.certificateValidityWarningThreshold = certificateValidityWarningThreshold;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/application/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/AbstractCompositeHealthContributorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.util.Assert;\n\n/**\n * Base class for health contributor configurations that can combine source beans into a\n * composite.\n *\n * @param <C> the contributor type\n * @param <I> the health indicator type\n * @param <B> the bean type\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nabstract class AbstractCompositeHealthContributorConfiguration<C, I extends C, B> {\n\n\tprivate final Function<B, I> indicatorFactory;\n\n\t/**\n\t * Creates a {@code AbstractCompositeHealthContributorConfiguration} that will use the\n\t * given {@code indicatorFactory} to create health indicator instances.\n\t * @param indicatorFactory the function to create health indicators\n\t */\n\tprotected AbstractCompositeHealthContributorConfiguration(Function<B, I> indicatorFactory) {\n\t\tthis.indicatorFactory = indicatorFactory;\n\t}\n\n\t/**\n\t * Creates a composite contributor from the beans of the given {@code beanType}\n\t * retrieved from the given {@code beanFactory}.\n\t * @param beanFactory the bean factory from which the beans are retrieved\n\t * @param beanType the type of the beans that are retrieved\n\t * @return the contributor\n\t */\n\tprotected final C createContributor(ConfigurableListableBeanFactory beanFactory, Class<B> beanType) {\n\t\treturn createContributor(SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, beanType));\n\t}\n\n\tprotected final C createContributor(Map<String, B> beans) {\n\t\tAssert.notEmpty(beans, \"'beans' must not be empty\");\n\t\tif (beans.size() == 1) {\n\t\t\treturn createIndicator(beans.values().iterator().next());\n\t\t}\n\t\treturn createComposite(beans);\n\t}\n\n\tprotected abstract C createComposite(Map<String, B> beans);\n\n\tprotected I createIndicator(B bean) {\n\t\treturn this.indicatorFactory.apply(bean);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/CompositeHealthContributorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\n\n/**\n * Base class for health contributor configurations that can combine source beans into a\n * composite.\n *\n * @param <I> the health indicator type\n * @param <B> the bean type\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class CompositeHealthContributorConfiguration<I extends HealthIndicator, B>\n\t\textends AbstractCompositeHealthContributorConfiguration<HealthContributor, I, B> {\n\n\t/**\n\t * Creates a {@code CompositeHealthContributorConfiguration} that will use the given\n\t * {@code indicatorFactory} to create {@link HealthIndicator} instances.\n\t * @param indicatorFactory the function to create health indicator instances\n\t */\n\tpublic CompositeHealthContributorConfiguration(Function<B, I> indicatorFactory) {\n\t\tsuper(indicatorFactory);\n\t}\n\n\t@Override\n\tprotected final HealthContributor createComposite(Map<String, B> beans) {\n\t\treturn CompositeHealthContributor.fromMap(beans, this::createIndicator);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/CompositeReactiveHealthContributorConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\n\n/**\n * Base class for health contributor configurations that can combine source beans into a\n * composite.\n *\n * @param <I> the health indicator type\n * @param <B> the bean type\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class CompositeReactiveHealthContributorConfiguration<I extends ReactiveHealthIndicator, B>\n\t\textends AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, I, B> {\n\n\t/**\n\t * Creates a {@code CompositeReactiveHealthContributorConfiguration} that will use the\n\t * given {@code indicatorFactory} to create {@link ReactiveHealthIndicator} instances.\n\t * @param indicatorFactory the function to create health indicator instances\n\t */\n\tpublic CompositeReactiveHealthContributorConfiguration(Function<B, I> indicatorFactory) {\n\t\tsuper(indicatorFactory);\n\t}\n\n\t@Override\n\tprotected final ReactiveHealthContributor createComposite(Map<String, B> beans) {\n\t\treturn CompositeReactiveHealthContributor.fromMap(beans, this::createIndicator);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/ConditionalOnEnabledHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether a default health indicator is\n * enabled. Matches if the value of the {@code management.health.<name>.enabled} property\n * is {@code true}. Otherwise, matches if the value of the\n * {@code management.health.defaults.enabled} property is {@code true} or if it is not\n * configured.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnEnabledHealthIndicatorCondition.class)\npublic @interface ConditionalOnEnabledHealthIndicator {\n\n\t/**\n\t * The name of the health indicator.\n\t * @return the name of the health indicator\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/HealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.PingHealthIndicator;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for default {@link HealthContributor\n * health contributors}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\npublic final class HealthContributorAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnEnabledHealthIndicator(\"ping\")\n\tPingHealthIndicator pingHealthContributor() {\n\t\treturn new PingHealthIndicator();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/HealthContributorMembership.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Determines if a health contributor is a member of a group or collection.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface HealthContributorMembership {\n\n\t/**\n\t * Returns {@code true} if the given contributor is a member.\n\t * @param name the contributor name\n\t * @return {@code true} if the contributor is a member\n\t */\n\tboolean isMember(String name);\n\n\t/**\n\t * Return a {@link HealthContributorMembership} that always matches.\n\t * @return a {@link HealthContributorMembership} instance that always matches\n\t */\n\tstatic HealthContributorMembership always() {\n\t\treturn (name) -> true;\n\t}\n\n\t/**\n\t * Return a {@link HealthContributorMembership} instance that matches based on include\n\t * and exclude patterns. Support {@code '*'} patterns and {@code '/'} separated names.\n\t * @param include the include patterns or {@code null}\n\t * @param exclude the exclude patterns of {@code null}\n\t * @return a new {@link HealthContributorMembership} instance\n\t */\n\tstatic HealthContributorMembership byIncludeExclude(@Nullable Set<String> include, @Nullable Set<String> exclude) {\n\t\treturn new IncludeExcludeHealthContributorMembership(include, exclude);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/HealthContributorMembershipValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Set;\nimport java.util.function.BiFunction;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.boot.diagnostics.FailureAnalyzedException;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link SmartInitializingSingleton} that validates health membership, throwing a\n * {@link FailureAnalyzedException} if an included or excluded contributor does not exist.\n * This implementation supports the same include/exclude patterns as\n * {@link HealthContributorMembership#byIncludeExclude(Set, Set)}\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic class HealthContributorMembershipValidator implements SmartInitializingSingleton {\n\n\tprivate final HealthContributorRegistry registry;\n\n\tprivate final @Nullable ReactiveHealthContributorRegistry fallbackRegistry;\n\n\tprivate final String disableValidationProperty;\n\n\tprivate final Consumer<Members> members;\n\n\t/**\n\t * Create a new {@link HealthContributorMembershipValidator} instance.\n\t * @param registry the health registry\n\t * @param fallbackRegistry the fallback registry or {@code null}\n\t * @param disableValidationProperty the property that can be used to disable\n\t * validation\n\t * @param members consumer used to provide the members\n\t */\n\tpublic HealthContributorMembershipValidator(HealthContributorRegistry registry,\n\t\t\t@Nullable ReactiveHealthContributorRegistry fallbackRegistry, String disableValidationProperty,\n\t\t\tConsumer<Members> members) {\n\t\tthis.registry = registry;\n\t\tthis.fallbackRegistry = fallbackRegistry;\n\t\tthis.disableValidationProperty = disableValidationProperty;\n\t\tthis.members = members;\n\t}\n\n\t@Override\n\tpublic void afterSingletonsInstantiated() {\n\t\tvalidateMembers();\n\t}\n\n\tprivate void validateMembers() {\n\t\tthis.members.accept(this::validate);\n\t}\n\n\tprivate void validate(String property, @Nullable Set<String> names) {\n\t\tif (CollectionUtils.isEmpty(names)) {\n\t\t\treturn;\n\t\t}\n\t\tfor (String name : names) {\n\t\t\tif (\"*\".equals(name)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tString[] path = name.split(\"/\");\n\t\t\tif (!contributorExists(path)) {\n\t\t\t\tString description = \"Health contributor '%s' defined in '%s' does not exist\".formatted(name, property);\n\t\t\t\tString action = \"Update your application to correct the invalid configuration.\\nYou can also set '%s' to false to disable the validation.\"\n\t\t\t\t\t.formatted(this.disableValidationProperty);\n\t\t\t\tthrow new FailureAnalyzedException(description, action);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean contributorExists(String[] path) {\n\t\treturn contributorExistsInMainRegistry(path) || contributorExistsInFallbackRegistry(path);\n\t}\n\n\tprivate boolean contributorExistsInMainRegistry(String[] path) {\n\t\treturn contributorExists(path, this.registry, HealthContributors.class, HealthContributors::getContributor);\n\t}\n\n\tprivate boolean contributorExistsInFallbackRegistry(String[] path) {\n\t\treturn contributorExists(path, this.fallbackRegistry, ReactiveHealthContributors.class,\n\t\t\t\tReactiveHealthContributors::getContributor);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <C> boolean contributorExists(String[] path, @Nullable Object registry, Class<C> collectionType,\n\t\t\tBiFunction<C, String, Object> getFromCollection) {\n\t\tint pathOffset = 0;\n\t\tObject contributor = registry;\n\t\twhile (pathOffset < path.length) {\n\t\t\tif (contributor == null || !collectionType.isInstance(contributor)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcontributor = getFromCollection.apply((C) contributor, path[pathOffset]);\n\t\t\tpathOffset++;\n\t\t}\n\t\treturn (contributor != null);\n\t}\n\n\t/**\n\t * Callback used to provide member information.\n\t */\n\t@FunctionalInterface\n\tpublic interface Members {\n\n\t\t/**\n\t\t * Provide members.\n\t\t * @param property the property providing the members\n\t\t * @param members the members\n\t\t */\n\t\tvoid member(String property, @Nullable Set<String> members);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/IncludeExcludeHealthContributorMembership.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Member predicate that matches based on {@code include} and {@code exclude} sets.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass IncludeExcludeHealthContributorMembership implements HealthContributorMembership {\n\n\tprivate final Set<String> include;\n\n\tprivate final Set<String> exclude;\n\n\tIncludeExcludeHealthContributorMembership(@Nullable Set<String> include, @Nullable Set<String> exclude) {\n\t\tthis.include = clean(include);\n\t\tthis.exclude = clean(exclude);\n\t}\n\n\t@Override\n\tpublic boolean isMember(String name) {\n\t\tname = clean(name);\n\t\treturn isIncluded(name) && !isExcluded(name);\n\t}\n\n\tprivate boolean isIncluded(String name) {\n\t\treturn this.include.isEmpty() || this.include.contains(\"*\") || isIncludedName(name);\n\t}\n\n\tprivate boolean isIncludedName(String name) {\n\t\tif (this.include.contains(name)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (name.contains(\"/\")) {\n\t\t\tString parent = name.substring(0, name.lastIndexOf(\"/\"));\n\t\t\treturn isIncludedName(parent);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate boolean isExcluded(String name) {\n\t\treturn this.exclude.contains(\"*\") || isExcludedName(name);\n\t}\n\n\tprivate boolean isExcludedName(String name) {\n\t\tif (this.exclude.contains(name)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (name.contains(\"/\")) {\n\t\t\tString parent = name.substring(0, name.lastIndexOf(\"/\"));\n\t\t\treturn isExcludedName(parent);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate Set<String> clean(@Nullable Set<String> names) {\n\t\tif (names == null) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t\tSet<String> cleaned = names.stream().map(this::clean).collect(Collectors.toCollection(LinkedHashSet::new));\n\t\treturn Collections.unmodifiableSet(cleaned);\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate @Nullable String clean(@Nullable String name) {\n\t\treturn (name != null) ? name.trim() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/OnEnabledHealthIndicatorCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link Condition} that checks if a health indicator is enabled.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass OnEnabledHealthIndicatorCondition extends SpringBootCondition {\n\n\tprivate static final String DEFAULTS_PROPERTY_NAME = \"management.health.defaults.enabled\";\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tMergedAnnotation<?> annotation = metadata.getAnnotations().get(ConditionalOnEnabledHealthIndicator.class);\n\t\tString name = annotation.getString(MergedAnnotation.VALUE);\n\t\tEnvironment environment = context.getEnvironment();\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnEnabledHealthIndicator.class);\n\t\tString propertyName = \"management.health.\" + name + \".enabled\";\n\t\tif (environment.containsProperty(propertyName)) {\n\t\t\tboolean match = environment.getProperty(propertyName, Boolean.class, true);\n\t\t\treturn new ConditionOutcome(match, message.because(propertyName + \" is \" + match));\n\t\t}\n\t\tboolean match = Boolean.parseBoolean(context.getEnvironment().getProperty(DEFAULTS_PROPERTY_NAME, \"true\"));\n\t\treturn new ConditionOutcome(match, message.because(DEFAULTS_PROPERTY_NAME + \" is considered \" + match));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/contributor/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for health contributors.\n */\n@NullMarked\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/registry/HealthContributorNameGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.registry;\n\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\n/**\n * Strategy used to create health contributor names from bean names.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface HealthContributorNameGenerator {\n\n\t/**\n\t * Generate the health contributor name for the given bean name.\n\t * @param beanName the bean name\n\t * @return the health contributor name\n\t */\n\tString generateContributorName(String beanName);\n\n\t/**\n\t * Return a registrar that can be used to register the given contributor beans with a\n\t * generated name.\n\t * @param <C> the contributor type\n\t * @param contributorBeans the contributor beans\n\t * @return a registrar\n\t */\n\tdefault <C> Consumer<BiConsumer<String, C>> registrar(Map<String, C> contributorBeans) {\n\t\treturn (initialRegistrations) -> {\n\t\t\tcontributorBeans.forEach((beanName, contributorBean) -> {\n\t\t\t\tString contributorName = generateContributorName(beanName);\n\t\t\t\ttry {\n\t\t\t\t\tinitialRegistrations.accept(contributorName, contributorBean);\n\t\t\t\t}\n\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\"Unable to register contributor named '%s' of type %s from bean '%s': %s\"\n\t\t\t\t\t\t\t\t.formatted(contributorName, contributorBean.getClass(), beanName, ex.getMessage()),\n\t\t\t\t\t\t\tex);\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\t}\n\n\t/**\n\t * Return a {@link HealthContributorNameGenerator} that uses the unchanged bean name\n\t * as the health contributor name.\n\t * @return a new {@link HealthContributorNameGenerator} instance\n\t */\n\tstatic HealthContributorNameGenerator unchanged() {\n\t\treturn (beanName) -> beanName;\n\t}\n\n\t/**\n\t * Return a {@link HealthContributorNameGenerator} that removes standard suffixes.\n\t * @return a new {@link HealthContributorNameGenerator} instance\n\t */\n\tstatic HealthContributorNameGenerator withoutStandardSuffixes() {\n\t\treturn withoutSuffixes(\"healthindicator\", \"healthcontributor\");\n\t}\n\n\t/**\n\t * Return a {@link HealthContributorNameGenerator} that removes the given suffixes.\n\t * @param suffixes the suffixes to remove (not case sensitive)\n\t * @return a new {@link HealthContributorNameGenerator} instance\n\t */\n\tstatic HealthContributorNameGenerator withoutSuffixes(String... suffixes) {\n\t\treturn (beanName) -> {\n\t\t\tfor (String suffix : suffixes) {\n\t\t\t\tif (beanName != null && beanName.toLowerCase(Locale.ENGLISH).endsWith(suffix)) {\n\t\t\t\t\treturn beanName.substring(0, beanName.length() - suffix.length());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn beanName;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/registry/HealthContributorRegistryAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.registry;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorNameValidator;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link HealthContributorRegistry} and {@link ReactiveHealthContributorRegistry}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\npublic final class HealthContributorRegistryAutoConfiguration {\n\n\tHealthContributorRegistryAutoConfiguration() {\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(HealthContributorRegistry.class)\n\tDefaultHealthContributorRegistry healthContributorRegistry(Map<String, HealthContributor> contributorBeans,\n\t\t\tObjectProvider<HealthContributorNameGenerator> nameGeneratorProvider,\n\t\t\tList<HealthContributorNameValidator> nameValidators) {\n\t\tHealthContributorNameGenerator nameGenerator = nameGeneratorProvider\n\t\t\t.getIfAvailable(HealthContributorNameGenerator::withoutStandardSuffixes);\n\t\treturn new DefaultHealthContributorRegistry(nameValidators, nameGenerator.registrar(contributorBeans));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Flux.class)\n\tstatic class ReactiveHealthContributorRegistryConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ReactiveHealthContributorRegistry.class)\n\t\tDefaultReactiveHealthContributorRegistry reactiveHealthContributorRegistry(\n\t\t\t\tMap<String, ReactiveHealthContributor> contributorBeans,\n\t\t\t\tObjectProvider<HealthContributorNameGenerator> nameGeneratorProvider,\n\t\t\t\tList<HealthContributorNameValidator> nameValidators) {\n\t\t\tHealthContributorNameGenerator nameGenerator = nameGeneratorProvider\n\t\t\t\t.getIfAvailable(HealthContributorNameGenerator::withoutStandardSuffixes);\n\t\t\treturn new DefaultReactiveHealthContributorRegistry(nameValidators,\n\t\t\t\t\tnameGenerator.registrar(contributorBeans));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/autoconfigure/registry/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for health registries.\n */\n@NullMarked\npackage org.springframework.boot.health.autoconfigure.registry;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/AbstractHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.function.Function;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base {@link HealthIndicator} implementations that encapsulates creation of\n * {@link Health} instance and error handling.\n * <p>\n * This implementation is only suitable if an {@link Exception} raised from\n * {@link #doHealthCheck(Health.Builder)} should create a {@link Status#DOWN} health\n * status.\n *\n * @author Christian Dupuis\n * @since 4.0.0\n */\npublic abstract class AbstractHealthIndicator implements HealthIndicator {\n\n\tprivate static final @Nullable String NO_MESSAGE = null;\n\n\tprivate static final String DEFAULT_MESSAGE = \"Health check failed\";\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\tprivate final Function<Exception, @Nullable String> healthCheckFailedMessage;\n\n\t/**\n\t * Create a new {@link AbstractHealthIndicator} instance with a default\n\t * {@code healthCheckFailedMessage}.\n\t */\n\tprotected AbstractHealthIndicator() {\n\t\tthis(NO_MESSAGE);\n\t}\n\n\t/**\n\t * Create a new {@link AbstractHealthIndicator} instance with a specific message to\n\t * log when the health check fails.\n\t * @param healthCheckFailedMessage the message to log on health check failure\n\t */\n\tprotected AbstractHealthIndicator(@Nullable String healthCheckFailedMessage) {\n\t\tthis.healthCheckFailedMessage = (ex) -> healthCheckFailedMessage;\n\t}\n\n\t/**\n\t * Create a new {@link AbstractHealthIndicator} instance with a specific message to\n\t * log when the health check fails.\n\t * @param healthCheckFailedMessage the message to log on health check failure\n\t */\n\tprotected AbstractHealthIndicator(Function<Exception, @Nullable String> healthCheckFailedMessage) {\n\t\tAssert.notNull(healthCheckFailedMessage, \"'healthCheckFailedMessage' must not be null\");\n\t\tthis.healthCheckFailedMessage = healthCheckFailedMessage;\n\t}\n\n\t@Override\n\tpublic final Health health() {\n\t\tHealth.Builder builder = new Health.Builder();\n\t\ttry {\n\t\t\tdoHealthCheck(builder);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tbuilder.down(ex);\n\t\t}\n\t\tlogExceptionIfPresent(builder.getException());\n\t\treturn builder.build();\n\t}\n\n\tprivate void logExceptionIfPresent(@Nullable Throwable throwable) {\n\t\tif (throwable != null && this.logger.isWarnEnabled()) {\n\t\t\tString message = (throwable instanceof Exception ex) ? this.healthCheckFailedMessage.apply(ex) : null;\n\t\t\tthis.logger.warn(StringUtils.hasText(message) ? message : DEFAULT_MESSAGE, throwable);\n\t\t}\n\t}\n\n\t/**\n\t * Actual health check logic.\n\t * @param builder the {@link Health.Builder} to report health status and details\n\t * @throws Exception any {@link Exception} that should create a {@link Status#DOWN}\n\t * system status.\n\t */\n\tprotected abstract void doHealthCheck(Health.Builder builder) throws Exception;\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/AbstractReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.function.Function;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base {@link ReactiveHealthIndicator} implementations that encapsulates creation of\n * {@link Health} instance and error handling.\n *\n * @author Stephane Nicoll\n * @author Nikolay Rybak\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic abstract class AbstractReactiveHealthIndicator implements ReactiveHealthIndicator {\n\n\tprivate static final @Nullable String NO_MESSAGE = null;\n\n\tprivate static final String DEFAULT_MESSAGE = \"Health check failed\";\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\tprivate final Function<Throwable, @Nullable String> healthCheckFailedMessage;\n\n\t/**\n\t * Create a new {@link AbstractReactiveHealthIndicator} instance with a default\n\t * {@code healthCheckFailedMessage}.\n\t */\n\tprotected AbstractReactiveHealthIndicator() {\n\t\tthis(NO_MESSAGE);\n\t}\n\n\t/**\n\t * Create a new {@link AbstractReactiveHealthIndicator} instance with a specific\n\t * message to log when the health check fails.\n\t * @param healthCheckFailedMessage the message to log on health check failure\n\t */\n\tprotected AbstractReactiveHealthIndicator(@Nullable String healthCheckFailedMessage) {\n\t\tthis.healthCheckFailedMessage = (ex) -> healthCheckFailedMessage;\n\t}\n\n\t/**\n\t * Create a new {@link AbstractReactiveHealthIndicator} instance with a specific\n\t * message to log when the health check fails.\n\t * @param healthCheckFailedMessage the message to log on health check failure\n\t */\n\tprotected AbstractReactiveHealthIndicator(Function<Throwable, @Nullable String> healthCheckFailedMessage) {\n\t\tAssert.notNull(healthCheckFailedMessage, \"'healthCheckFailedMessage' must not be null\");\n\t\tthis.healthCheckFailedMessage = healthCheckFailedMessage;\n\t}\n\n\t@Override\n\tpublic final Mono<Health> health() {\n\t\ttry {\n\t\t\tHealth.Builder builder = new Health.Builder();\n\t\t\tMono<Health> result = doHealthCheck(builder).onErrorResume(this::handleFailure);\n\t\t\treturn result.doOnNext((health) -> logExceptionIfPresent(builder.getException()));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn handleFailure(ex);\n\t\t}\n\t}\n\n\tprivate void logExceptionIfPresent(@Nullable Throwable ex) {\n\t\tif (ex != null && this.logger.isWarnEnabled()) {\n\t\t\tString message = (ex instanceof Exception) ? this.healthCheckFailedMessage.apply(ex) : null;\n\t\t\tthis.logger.warn(StringUtils.hasText(message) ? message : DEFAULT_MESSAGE, ex);\n\t\t}\n\t}\n\n\tprivate Mono<Health> handleFailure(Throwable ex) {\n\t\tlogExceptionIfPresent(ex);\n\t\treturn Mono.just(new Health.Builder().down(ex).build());\n\t}\n\n\t/**\n\t * Actual health check logic. If an error occurs in the pipeline, it will be handled\n\t * automatically.\n\t * @param builder the {@link Health.Builder} to report health status and details\n\t * @return a {@link Mono} that provides the {@link Health}\n\t */\n\tprotected abstract Mono<Health> doHealthCheck(Health.Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/CompositeHealthContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\n\n/**\n * A {@link HealthContributor} that is composed of other {@link HealthContributor}\n * instances.\n *\n * @author Phillip Webb\n * @author Guirong Hu\n * @since 4.0.0\n * @see CompositeReactiveHealthContributor\n */\npublic non-sealed interface CompositeHealthContributor extends HealthContributor, HealthContributors {\n\n\t/**\n\t * Factory method that will create a {@link CompositeHealthContributor} from the\n\t * specified map.\n\t * @param map the source map\n\t * @return a composite health contributor instance\n\t */\n\tstatic CompositeHealthContributor fromMap(Map<String, ? extends HealthContributor> map) {\n\t\treturn fromMap(map, Function.identity());\n\t}\n\n\t/**\n\t * Factory method that will create a {@link CompositeHealthContributor} from the\n\t * specified map.\n\t * @param <V> the value type\n\t * @param map the source map\n\t * @param valueAdapter function used to adapt the map value\n\t * @return a composite health contributor instance\n\t */\n\tstatic <V> CompositeHealthContributor fromMap(Map<String, V> map,\n\t\t\tFunction<V, ? extends HealthContributor> valueAdapter) {\n\t\treturn new MapCompositeHealthContributor<>(map, valueAdapter);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/CompositeHealthContributorAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\n/**\n * Adapts a {@link CompositeHealthContributor} to a\n * {@link CompositeReactiveHealthContributor}.\n *\n * @author Phillip Webb\n * @see ReactiveHealthContributor#adapt(HealthContributor)\n */\nclass CompositeHealthContributorAdapter extends HealthContributorsAdapter\n\t\timplements CompositeReactiveHealthContributor {\n\n\tCompositeHealthContributorAdapter(HealthContributors delegate) {\n\t\tsuper(delegate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/CompositeHealthContributors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link HealthContributors} composed of other {@link HealthContributors}.\n *\n * @author Phillip Webb\n * @see HealthContributors#of(HealthContributors...)\n */\nclass CompositeHealthContributors implements HealthContributors {\n\n\tprivate final List<HealthContributors> contributors;\n\n\tCompositeHealthContributors(HealthContributors... contributors) {\n\t\tthis.contributors = List.of(contributors);\n\t}\n\n\t@Override\n\tpublic @Nullable HealthContributor getContributor(String name) {\n\t\treturn this.contributors.stream()\n\t\t\t.map((contributors) -> contributors.getContributor(name))\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\tSet<String> seen = new HashSet<>();\n\t\treturn this.contributors.stream()\n\t\t\t.flatMap(HealthContributors::stream)\n\t\t\t.filter((element) -> seen.add(element.name()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/CompositeReactiveHealthContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\n\n/**\n * A {@link ReactiveHealthContributor} that is composed of other\n * {@link ReactiveHealthContributor} instances.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see CompositeHealthContributor\n */\npublic non-sealed interface CompositeReactiveHealthContributor\n\t\textends ReactiveHealthContributor, ReactiveHealthContributors {\n\n\t@Override\n\tdefault CompositeHealthContributor asHealthContributor() {\n\t\treturn new CompositeReactiveHealthContributorAdapter(this);\n\t}\n\n\t/**\n\t * Factory method that will create a {@link CompositeReactiveHealthContributor} from\n\t * the specified map.\n\t * @param map the source map\n\t * @return a composite health contributor instance\n\t */\n\tstatic CompositeReactiveHealthContributor fromMap(Map<String, ? extends ReactiveHealthContributor> map) {\n\t\treturn fromMap(map, Function.identity());\n\t}\n\n\t/**\n\t * Factory method that will create a {@link CompositeReactiveHealthContributor} from\n\t * the specified map.\n\t * @param <V> the value type\n\t * @param map the source map\n\t * @param valueAdapter function used to adapt the map value\n\t * @return a composite health contributor instance\n\t */\n\tstatic <V> CompositeReactiveHealthContributor fromMap(Map<String, V> map,\n\t\t\tFunction<V, ? extends ReactiveHealthContributor> valueAdapter) {\n\t\treturn new MapCompositeReactiveHealthContributor<>(map, valueAdapter);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/CompositeReactiveHealthContributorAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\n/**\n * Adapts a {@link CompositeReactiveHealthContributor} to a\n * {@link CompositeHealthContributor}.\n *\n * @author Phillip Webb\n * @see CompositeReactiveHealthContributor#asHealthContributor()\n */\nclass CompositeReactiveHealthContributorAdapter extends ReactiveHealthContributorsAdapter\n\t\timplements CompositeHealthContributor {\n\n\tCompositeReactiveHealthContributorAdapter(ReactiveHealthContributors delegate) {\n\t\tsuper(delegate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/CompositeReactiveHealthContributors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link ReactiveHealthContributors} composed of other\n * {@link ReactiveHealthContributors}.\n *\n * @author Phillip Webb\n * @see ReactiveHealthContributors#of(ReactiveHealthContributors...)\n */\nclass CompositeReactiveHealthContributors implements ReactiveHealthContributors {\n\n\tprivate final List<ReactiveHealthContributors> contributors;\n\n\tCompositeReactiveHealthContributors(ReactiveHealthContributors... contributors) {\n\t\tthis.contributors = List.of(contributors);\n\t}\n\n\t@Override\n\tpublic @Nullable ReactiveHealthContributor getContributor(String name) {\n\t\treturn this.contributors.stream()\n\t\t\t.map((reactiveContributors) -> reactiveContributors.getContributor(name))\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\tSet<String> seen = new HashSet<>();\n\t\treturn this.contributors.stream()\n\t\t\t.flatMap(ReactiveHealthContributors::stream)\n\t\t\t.filter((element) -> seen.add(element.name()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/Health.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.annotation.JsonUnwrapped;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * The health of a component or subsystem in including its {@link Status} as well as any\n * additional contextual details. Subclasses should expect to be serialized and presented\n * to the user, typically as JSON.\n * <p>\n * {@link Health} instances can be created by using {@link Builder}'s fluent API. Typical\n * usage in a {@link HealthIndicator} would be:\n *\n * <pre class=\"code\">\n * try {\n * \t// do some test to determine state of component\n * \treturn Health.up().withDetail(\"version\", \"1.1.2\").build();\n * }\n * catch (Exception ex) {\n * \treturn Health.down(ex).build();\n * }\n * </pre>\n *\n * @author Christian Dupuis\n * @author Phillip Webb\n * @author Michael Pratt\n * @since 4.0.0\n */\npublic final class Health {\n\n\tprivate final Status status;\n\n\tprivate final Map<String, Object> details;\n\n\t/**\n\t * Create a new {@link Health} instance with the specified status and details.\n\t * @param builder the Builder to use\n\t */\n\tprivate Health(Builder builder) {\n\t\tAssert.notNull(builder, \"'builder' must not be null\");\n\t\tthis.status = builder.status;\n\t\tthis.details = Collections.unmodifiableMap(builder.details);\n\t}\n\n\tHealth(Status status, Map<String, Object> details) {\n\t\tthis.status = status;\n\t\tthis.details = details;\n\t}\n\n\t/**\n\t * Return the status of the health.\n\t * @return the status (never {@code null})\n\t */\n\t@JsonUnwrapped\n\tpublic Status getStatus() {\n\t\treturn this.status;\n\t}\n\n\t/**\n\t * Return the details of the health.\n\t * @return the details (or an empty map)\n\t */\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic Map<String, Object> getDetails() {\n\t\treturn this.details;\n\t}\n\n\tHealth withoutDetails() {\n\t\treturn (this.details.isEmpty()) ? this : status(getStatus()).build();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof Health other) {\n\t\t\treturn this.status.equals(other.status) && this.details.equals(other.details);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint hashCode = this.status.hashCode();\n\t\treturn 13 * hashCode + this.details.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getStatus() + \" \" + getDetails();\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with an {@link Status#UNKNOWN} status.\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder unknown() {\n\t\treturn status(Status.UNKNOWN);\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with an {@link Status#UP} status.\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder up() {\n\t\treturn status(Status.UP);\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with an {@link Status#DOWN} status and the\n\t * specified exception details.\n\t * @param ex the exception\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder down(Throwable ex) {\n\t\treturn down().withException(ex);\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with a {@link Status#DOWN} status.\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder down() {\n\t\treturn status(Status.DOWN);\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with an {@link Status#OUT_OF_SERVICE} status.\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder outOfService() {\n\t\treturn status(Status.OUT_OF_SERVICE);\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with a specific status code.\n\t * @param statusCode the status code\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder status(String statusCode) {\n\t\treturn status(new Status(statusCode));\n\t}\n\n\t/**\n\t * Create a new {@link Builder} instance with a specific {@link Status}.\n\t * @param status the status\n\t * @return a new {@link Builder} instance\n\t */\n\tpublic static Builder status(Status status) {\n\t\treturn new Builder(status);\n\t}\n\n\t/**\n\t * Builder for creating immutable {@link Health} instances.\n\t */\n\tpublic static class Builder {\n\n\t\tprivate Status status;\n\n\t\tprivate final Map<String, Object> details;\n\n\t\tprivate @Nullable Throwable exception;\n\n\t\t/**\n\t\t * Create new Builder instance.\n\t\t */\n\t\tpublic Builder() {\n\t\t\tthis.status = Status.UNKNOWN;\n\t\t\tthis.details = new LinkedHashMap<>();\n\t\t}\n\n\t\t/**\n\t\t * Create new Builder instance, setting status to given {@code status}.\n\t\t * @param status the {@link Status} to use\n\t\t */\n\t\tpublic Builder(Status status) {\n\t\t\tAssert.notNull(status, \"'status' must not be null\");\n\t\t\tthis.status = status;\n\t\t\tthis.details = new LinkedHashMap<>();\n\t\t}\n\n\t\t/**\n\t\t * Create new Builder instance, setting status to given {@code status} and details\n\t\t * to given {@code details}.\n\t\t * @param status the {@link Status} to use\n\t\t * @param details the details {@link Map} to use\n\t\t */\n\t\tpublic Builder(Status status, Map<String, ?> details) {\n\t\t\tAssert.notNull(status, \"'status' must not be null\");\n\t\t\tAssert.notNull(details, \"'details' must not be null\");\n\t\t\tthis.status = status;\n\t\t\tthis.details = new LinkedHashMap<>(details);\n\t\t}\n\n\t\t/**\n\t\t * Record detail for given {@link Exception}.\n\t\t * @param exception the exception\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder withException(Throwable exception) {\n\t\t\tAssert.notNull(exception, \"'exception' must not be null\");\n\t\t\tthis.exception = exception;\n\t\t\treturn withDetail(\"error\", exception.getClass().getName() + \": \" + exception.getMessage());\n\t\t}\n\n\t\t/**\n\t\t * Record detail using given {@code key} and {@code value}.\n\t\t * @param key the detail key\n\t\t * @param value the detail value\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder withDetail(String key, Object value) {\n\t\t\tAssert.notNull(key, \"'key' must not be null\");\n\t\t\tAssert.notNull(value, \"'value' must not be null\");\n\t\t\tthis.details.put(key, value);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Record details from the given {@code details} map. Keys from the given map\n\t\t * replace any existing keys if there are duplicates.\n\t\t * @param details map of details\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder withDetails(Map<String, ?> details) {\n\t\t\tAssert.notNull(details, \"'details' must not be null\");\n\t\t\tthis.details.putAll(details);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Set status to {@link Status#UNKNOWN} status.\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder unknown() {\n\t\t\treturn status(Status.UNKNOWN);\n\t\t}\n\n\t\t/**\n\t\t * Set status to {@link Status#UP} status.\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder up() {\n\t\t\treturn status(Status.UP);\n\t\t}\n\n\t\t/**\n\t\t * Set status to {@link Status#DOWN} and add details for given {@link Throwable}.\n\t\t * @param ex the exception\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder down(Throwable ex) {\n\t\t\treturn down().withException(ex);\n\t\t}\n\n\t\t/**\n\t\t * Set status to {@link Status#DOWN}.\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder down() {\n\t\t\treturn status(Status.DOWN);\n\t\t}\n\n\t\t/**\n\t\t * Set status to {@link Status#OUT_OF_SERVICE}.\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder outOfService() {\n\t\t\treturn status(Status.OUT_OF_SERVICE);\n\t\t}\n\n\t\t/**\n\t\t * Set status to given {@code statusCode}.\n\t\t * @param statusCode the status code\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder status(String statusCode) {\n\t\t\treturn status(new Status(statusCode));\n\t\t}\n\n\t\t/**\n\t\t * Set status to given {@link Status} instance.\n\t\t * @param status the status\n\t\t * @return this {@link Builder} instance\n\t\t */\n\t\tpublic Builder status(Status status) {\n\t\t\tthis.status = status;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Create a new {@link Health} instance with the previously specified code and\n\t\t * details.\n\t\t * @return a new {@link Health} instance\n\t\t */\n\t\tpublic Health build() {\n\t\t\treturn new Health(this);\n\t\t}\n\n\t\t/**\n\t\t * Return the {@link Exception}.\n\t\t * @return the exception or {@code null} if the builder has no exception\n\t\t */\n\t\t@Nullable Throwable getException() {\n\t\t\treturn this.exception;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/HealthContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\n/**\n * Contributes health information, either directly ({@link HealthIndicator}) or via other\n * contributors ({@link CompositeHealthContributor}).\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see HealthIndicator\n * @see CompositeHealthContributor\n */\npublic sealed interface HealthContributor permits HealthIndicator, CompositeHealthContributor {\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/HealthContributors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Iterator;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A collection of named {@link HealthContributor health contributors}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface HealthContributors extends Iterable<HealthContributors.Entry> {\n\n\t/**\n\t * Return the contributor with the given name.\n\t * @param name the name of the contributor\n\t * @return a contributor instance or {@code null}\n\t */\n\t@Nullable HealthContributor getContributor(String name);\n\n\t@Override\n\tdefault Iterator<Entry> iterator() {\n\t\treturn stream().iterator();\n\t}\n\n\t/**\n\t * Return a stream of the contributor entries.\n\t * @return the stream of named contributors\n\t */\n\tStream<HealthContributors.Entry> stream();\n\n\t/**\n\t * Factory method to create a new {@link HealthContributors} instance composed of the\n\t * given contributors.\n\t * @param contributors the source contributors in the order they should be combined\n\t * @return a new {@link HealthContributors} instance\n\t */\n\tstatic HealthContributors of(HealthContributors... contributors) {\n\t\treturn new CompositeHealthContributors(contributors);\n\t}\n\n\t/**\n\t * A health contributor entry.\n\t *\n\t * @param name the name of the contributor\n\t * @param contributor the contributor\n\t */\n\trecord Entry(String name, HealthContributor contributor) {\n\n\t\tpublic Entry {\n\t\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\t\tAssert.notNull(contributor, \"'contributor' must not be null\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/HealthContributorsAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Adapts {@link HealthContributors} to {@link ReactiveHealthContributors}.\n *\n * @author Phillip Webb\n * @see ReactiveHealthContributors#adapt(HealthContributors)\n */\nclass HealthContributorsAdapter implements ReactiveHealthContributors {\n\n\tprivate final HealthContributors delegate;\n\n\tHealthContributorsAdapter(HealthContributors delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic @Nullable ReactiveHealthContributor getContributor(String name) {\n\t\treturn ReactiveHealthContributor.adapt(this.delegate.getContributor(name));\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\treturn this.delegate.stream()\n\t\t\t.map((entry) -> new Entry(entry.name(), ReactiveHealthContributor.adapt(entry.contributor())));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/HealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Directly contributes {@link Health} information for specific component or subsystem.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic non-sealed interface HealthIndicator extends HealthContributor {\n\n\t/**\n\t * Return an indication of health.\n\t * @param includeDetails if details should be included or removed\n\t * @return the health\n\t */\n\tdefault @Nullable Health health(boolean includeDetails) {\n\t\tHealth health = health();\n\t\tif (health == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn includeDetails ? health : health.withoutDetails();\n\t}\n\n\t/**\n\t * Return an indication of health.\n\t * @return the health\n\t */\n\t@Nullable Health health();\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/HealthIndicatorAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport reactor.core.publisher.Mono;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.util.Assert;\n\n/**\n * Adapts a {@link HealthIndicator} to a {@link ReactiveHealthIndicator} so that it can be\n * safely invoked in a reactive environment.\n *\n * @author Stephane Nicoll\n * @see ReactiveHealthContributor#adapt(HealthContributor)\n */\nclass HealthIndicatorAdapter implements ReactiveHealthIndicator {\n\n\tprivate final HealthIndicator delegate;\n\n\tHealthIndicatorAdapter(HealthIndicator delegate) {\n\t\tAssert.notNull(delegate, \"'delegate' must not be null\");\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic Mono<Health> health() {\n\t\treturn Mono.fromCallable(this.delegate::health).subscribeOn(Schedulers.boundedElastic());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/MapCompositeHealthContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link CompositeHealthContributor} backed by a map with values adapted as necessary.\n *\n * @param <V> the value type\n * @author Phillip Webb\n * @see CompositeHealthContributor#fromMap(Map, Function)\n */\nclass MapCompositeHealthContributor<V> implements CompositeHealthContributor {\n\n\tprivate final Map<String, HealthContributor> contributors;\n\n\tMapCompositeHealthContributor(Map<String, V> map, Function<V, ? extends HealthContributor> valueAdapter) {\n\t\tAssert.notNull(map, \"'map' must not be null\");\n\t\tAssert.notNull(valueAdapter, \"'valueAdapter' must not be null\");\n\t\tLinkedHashMap<String, HealthContributor> contributors = new LinkedHashMap<>();\n\t\tmap.forEach((key, value) -> {\n\t\t\tAssert.notNull(key, \"'map' must not contain null keys\");\n\t\t\tAssert.notNull(value, \"'map' must not contain null values\");\n\t\t\tAssert.isTrue(!key.contains(\"/\"), \"'map' keys must not contain a '/'\");\n\t\t\tcontributors.put(key, valueAdapter.apply(value));\n\t\t});\n\t\tthis.contributors = Collections.unmodifiableMap(contributors);\n\t}\n\n\t@Override\n\tpublic @Nullable HealthContributor getContributor(String name) {\n\t\treturn this.contributors.get(name);\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\treturn this.contributors.entrySet().stream().map((entry) -> new Entry(entry.getKey(), entry.getValue()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/MapCompositeReactiveHealthContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link CompositeReactiveHealthContributor} backed by a map with values adapted as\n * necessary.\n *\n * @param <V> the value type\n * @author Phillip Webb\n * @see CompositeReactiveHealthContributor#fromMap(Map, Function)\n */\nclass MapCompositeReactiveHealthContributor<V> implements CompositeReactiveHealthContributor {\n\n\tprivate final Map<String, ReactiveHealthContributor> contributors;\n\n\tMapCompositeReactiveHealthContributor(Map<String, V> map,\n\t\t\tFunction<V, ? extends ReactiveHealthContributor> valueAdapter) {\n\t\tAssert.notNull(map, \"'map' must not be null\");\n\t\tAssert.notNull(valueAdapter, \"'valueAdapter' must not be null\");\n\t\tLinkedHashMap<String, ReactiveHealthContributor> contributors = new LinkedHashMap<>();\n\t\tmap.forEach((key, value) -> {\n\t\t\tAssert.notNull(key, \"'map' must not contain null keys\");\n\t\t\tAssert.notNull(value, \"'map' must not contain null values\");\n\t\t\tAssert.isTrue(!key.contains(\"/\"), \"'map' keys must not contain a '/'\");\n\t\t\tcontributors.put(key, valueAdapter.apply(value));\n\t\t});\n\t\tthis.contributors = Collections.unmodifiableMap(contributors);\n\t}\n\n\t@Override\n\tpublic @Nullable ReactiveHealthContributor getContributor(String name) {\n\t\treturn this.contributors.get(name);\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\treturn this.contributors.entrySet().stream().map((entry) -> new Entry(entry.getKey(), entry.getValue()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/PingHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\n/**\n * Auto-configured {@link HealthIndicator} that always returns {@link Status#UP}.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @since 4.0.0\n * @see Status#UP\n */\npublic class PingHealthIndicator extends AbstractHealthIndicator {\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tbuilder.up();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/ReactiveHealthContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Contributes health information, either directly ({@link ReactiveHealthIndicator}) or\n * via other contributors ({@link CompositeReactiveHealthContributor}).\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see ReactiveHealthIndicator\n * @see CompositeReactiveHealthContributor\n */\npublic sealed interface ReactiveHealthContributor permits ReactiveHealthIndicator, CompositeReactiveHealthContributor {\n\n\t/**\n\t * Return this reactive contributor as a standard blocking {@link HealthContributor}.\n\t * @return a blocking health contributor\n\t */\n\tHealthContributor asHealthContributor();\n\n\t/**\n\t * Adapts the given {@link HealthContributor} into a {@link ReactiveHealthContributor}\n\t * by scheduling blocking calls to {@link Schedulers#boundedElastic()}.\n\t * @param contributor the contributor to adapt or {@code null}\n\t * @return the adapted contributor\n\t */\n\t@Contract(\"!null -> !null\")\n\tstatic @Nullable ReactiveHealthContributor adapt(@Nullable HealthContributor contributor) {\n\t\tif (contributor == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (contributor instanceof HealthIndicator healthIndicator) {\n\t\t\treturn new HealthIndicatorAdapter(healthIndicator);\n\t\t}\n\t\tif (contributor instanceof CompositeHealthContributor compositeHealthContributor) {\n\t\t\treturn new CompositeHealthContributorAdapter(compositeHealthContributor);\n\t\t}\n\t\tthrow new IllegalStateException(\"Unknown 'contributor' type\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/ReactiveHealthContributors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Iterator;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\n\n/**\n * A collection of named {@link ReactiveHealthContributor reactive health contributors}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface ReactiveHealthContributors extends Iterable<ReactiveHealthContributors.Entry> {\n\n\t/**\n\t * Return the contributor with the given name.\n\t * @param name the name of the contributor\n\t * @return a contributor instance or {@code null}\n\t */\n\t@Nullable ReactiveHealthContributor getContributor(String name);\n\n\t@Override\n\tdefault Iterator<Entry> iterator() {\n\t\treturn stream().iterator();\n\t}\n\n\t/**\n\t * Return a stream of the contributor entries.\n\t * @return the stream of named contributors\n\t */\n\tStream<ReactiveHealthContributors.Entry> stream();\n\n\t/**\n\t * Return these reactive contributors as standard blocking {@link HealthContributors}.\n\t * @return blocking health contributors\n\t */\n\tdefault HealthContributors asHealthContributors() {\n\t\treturn new ReactiveHealthContributorsAdapter(this);\n\t}\n\n\t/**\n\t * Factory method to create a new {@link ReactiveHealthContributors} instance composed\n\t * of the given contributors.\n\t * @param contributors the source contributors in the order they should be combined\n\t * @return a new {@link ReactiveHealthContributors} instance\n\t */\n\tstatic ReactiveHealthContributors of(ReactiveHealthContributors... contributors) {\n\t\treturn new CompositeReactiveHealthContributors(contributors);\n\t}\n\n\t/**\n\t * Adapts the given {@link HealthContributors} into a\n\t * {@link ReactiveHealthContributors} by scheduling blocking calls to\n\t * {@link Schedulers#boundedElastic()}.\n\t * @param contributors the contributors to adapt or {@code null}\n\t * @return the adapted contributor\n\t * @see ReactiveHealthContributor#adapt(HealthContributor)\n\t */\n\t@Contract(\"!null -> !null\")\n\tstatic @Nullable ReactiveHealthContributors adapt(@Nullable HealthContributors contributors) {\n\t\treturn (contributors != null) ? new HealthContributorsAdapter(contributors) : null;\n\t}\n\n\t/**\n\t * A reactive health contributor entry.\n\t *\n\t * @param name the name of the contributor\n\t * @param contributor the contributor\n\t */\n\trecord Entry(String name, ReactiveHealthContributor contributor) {\n\n\t\tpublic Entry {\n\t\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\t\tAssert.notNull(contributor, \"'contributor' must not be null\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/ReactiveHealthContributorsAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Adapts {@link ReactiveHealthContributors} to {@link HealthContributors}.\n *\n * @author Phillip Webb\n * @see ReactiveHealthContributors#asHealthContributors()\n */\nclass ReactiveHealthContributorsAdapter implements HealthContributors {\n\n\tprivate final ReactiveHealthContributors delegate;\n\n\tReactiveHealthContributorsAdapter(ReactiveHealthContributors delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic @Nullable HealthContributor getContributor(String name) {\n\t\treturn adapt(this.delegate.getContributor(name));\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\treturn this.delegate.stream().map((entry) -> new Entry(entry.name(), adapt(entry.contributor())));\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate @Nullable HealthContributor adapt(@Nullable ReactiveHealthContributor contributor) {\n\t\treturn (contributor != null) ? contributor.asHealthContributor() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/ReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport reactor.core.publisher.Mono;\n\n/**\n * Directly contributes {@link Health} information for specific reactive component or\n * subsystem.\n * <p>\n * This is non-blocking contract that is meant to be used in a reactive application. See\n * {@link HealthIndicator} for the traditional contract.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see HealthIndicator\n */\n@FunctionalInterface\npublic non-sealed interface ReactiveHealthIndicator extends ReactiveHealthContributor {\n\n\t@Override\n\tdefault HealthIndicator asHealthContributor() {\n\t\treturn new ReactiveHealthIndicatorAdapter(this);\n\t}\n\n\t/**\n\t * Provide the indicator of health.\n\t * @param includeDetails if details should be included or removed\n\t * @return a {@link Mono} that provides the {@link Health}\n\t */\n\tdefault Mono<Health> health(boolean includeDetails) {\n\t\tMono<Health> health = health();\n\t\treturn includeDetails ? health : health.map(Health::withoutDetails);\n\t}\n\n\t/**\n\t * Provide the indicator of health.\n\t * @return a {@link Mono} that provides the {@link Health}\n\t */\n\tMono<Health> health();\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/ReactiveHealthIndicatorAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Adapts a {@link ReactiveHealthIndicator} to a {@link HealthIndicator}.\n *\n * @author Phillip Webb\n * @see ReactiveHealthIndicator#asHealthContributor()\n */\nclass ReactiveHealthIndicatorAdapter implements HealthIndicator {\n\n\tprivate final ReactiveHealthIndicator delegate;\n\n\tReactiveHealthIndicatorAdapter(ReactiveHealthIndicator indicator) {\n\t\tthis.delegate = indicator;\n\t}\n\n\t@Override\n\tpublic @Nullable Health health(boolean includeDetails) {\n\t\treturn this.delegate.health(includeDetails).block();\n\t}\n\n\t@Override\n\tpublic @Nullable Health health() {\n\t\treturn this.delegate.health().block();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/Status.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.List;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Value object to express state of a component or subsystem.\n * <p>\n * Status provides convenient constants for commonly used states like {@link #UP},\n * {@link #DOWN} or {@link #OUT_OF_SERVICE}.\n * <p>\n * Custom states can also be created and used throughout the Spring Boot Health subsystem.\n *\n * @author Christian Dupuis\n * @since 4.0.0\n */\n@JsonInclude(Include.NON_EMPTY)\npublic final class Status {\n\n\t/**\n\t * {@link Status} indicating that the component or subsystem is in an unknown state.\n\t */\n\tpublic static final Status UNKNOWN = new Status(\"UNKNOWN\");\n\n\t/**\n\t * {@link Status} indicating that the component or subsystem is functioning as\n\t * expected.\n\t */\n\tpublic static final Status UP = new Status(\"UP\");\n\n\t/**\n\t * {@link Status} indicating that the component or subsystem has suffered an\n\t * unexpected failure.\n\t */\n\tpublic static final Status DOWN = new Status(\"DOWN\");\n\n\t/**\n\t * {@link Status} indicating that the component or subsystem has been taken out of\n\t * service and should not be used.\n\t */\n\tpublic static final Status OUT_OF_SERVICE = new Status(\"OUT_OF_SERVICE\");\n\n\t/**\n\t * The default order use to prioritize standard status instances.\n\t * @since 4.1.0\n\t */\n\tpublic static final List<Status> DEFAULT_ORDER = List.of(DOWN, OUT_OF_SERVICE, UP, UNKNOWN);\n\n\tprivate final String code;\n\n\tprivate final String description;\n\n\t/**\n\t * Create a new {@link Status} instance with the given code and an empty description.\n\t * @param code the status code\n\t */\n\tpublic Status(String code) {\n\t\tthis(code, \"\");\n\t}\n\n\t/**\n\t * Create a new {@link Status} instance with the given code and description.\n\t * @param code the status code\n\t * @param description a description of the status\n\t */\n\tpublic Status(String code, String description) {\n\t\tAssert.notNull(code, \"'code' must not be null\");\n\t\tAssert.notNull(description, \"'description' must not be null\");\n\t\tthis.code = code;\n\t\tthis.description = description;\n\t}\n\n\t/**\n\t * Return the code for this status.\n\t * @return the code\n\t */\n\t@JsonProperty(\"status\")\n\tpublic String getCode() {\n\t\treturn this.code;\n\t}\n\n\t/**\n\t * Return the description of this status.\n\t * @return the description\n\t */\n\t@JsonInclude(Include.NON_EMPTY)\n\tpublic String getDescription() {\n\t\treturn this.description;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof Status other) {\n\t\t\treturn ObjectUtils.nullSafeEquals(this.code, other.code);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.code.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.code;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/contributor/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to contributing health information about an application.\n */\n@NullMarked\npackage org.springframework.boot.health.contributor;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/AbstractRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Internal base class for health registries.\n *\n * @param <C> the contributor type\n * @param <E> the entry type\n * @author Phillip Webb\n */\nabstract class AbstractRegistry<C, E> {\n\n\tprivate final Collection<HealthContributorNameValidator> nameValidators;\n\n\tprivate final BiFunction<String, C, E> entryAdapter;\n\n\tprivate volatile Map<String, C> contributors;\n\n\tprivate final Object monitor = new Object();\n\n\tAbstractRegistry(BiFunction<String, C, E> entryAdapter,\n\t\t\t@Nullable Collection<? extends HealthContributorNameValidator> nameValidators,\n\t\t\t@Nullable Consumer<BiConsumer<String, C>> initialRegistrations) {\n\t\tthis.nameValidators = (nameValidators != null) ? List.copyOf(nameValidators) : Collections.emptyList();\n\t\tthis.entryAdapter = entryAdapter;\n\t\tMap<String, C> contributors = new LinkedHashMap<>();\n\t\tif (initialRegistrations != null) {\n\t\t\tinitialRegistrations.accept((name, contributor) -> registerContributor(contributors, name, contributor));\n\t\t}\n\t\tthis.contributors = Collections.unmodifiableMap(contributors);\n\t}\n\n\tvoid registerContributor(String name, C contributor) {\n\t\tsynchronized (this.monitor) {\n\t\t\tMap<String, C> contributors = new LinkedHashMap<>(this.contributors);\n\t\t\tregisterContributor(contributors, name, contributor);\n\t\t\tthis.contributors = Collections.unmodifiableMap(contributors);\n\t\t}\n\t}\n\n\tprivate void registerContributor(Map<String, C> contributors, String name, C contributor) {\n\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\tAssert.notNull(contributor, \"'contributor' must not be null\");\n\t\tverifyName(name, contributor);\n\t\tAssert.state(!contributors.containsKey(name),\n\t\t\t\t() -> \"A contributor named \\\"\" + name + \"\\\" has already been registered\");\n\t\tcontributors.put(name, contributor);\n\t}\n\n\t@Nullable C unregisterContributor(String name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tsynchronized (this.monitor) {\n\t\t\tC unregistered = this.contributors.get(name);\n\t\t\tif (unregistered != null) {\n\t\t\t\tMap<String, C> contributors = new LinkedHashMap<>(this.contributors);\n\t\t\t\tcontributors.remove(name);\n\t\t\t\tthis.contributors = Collections.unmodifiableMap(contributors);\n\t\t\t}\n\t\t\treturn unregistered;\n\t\t}\n\t}\n\n\t@Nullable C getContributor(String name) {\n\t\treturn this.contributors.get(name);\n\t}\n\n\tStream<E> stream() {\n\t\treturn this.contributors.entrySet()\n\t\t\t.stream()\n\t\t\t.map((entry) -> this.entryAdapter.apply(entry.getKey(), entry.getValue()));\n\t}\n\n\tprivate void verifyName(String name, C contributor) {\n\t\tAssert.state(StringUtils.hasText(name),\n\t\t\t\t() -> \"Name for contributor '%s' must not be empty\".formatted(contributor));\n\t\tif (!CollectionUtils.isEmpty(this.nameValidators)) {\n\t\t\tthis.nameValidators.forEach((nameValidator) -> nameValidator.validate(name));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/DefaultHealthContributorRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport java.util.Collection;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors.Entry;\n\n/**\n * Default {@link HealthContributorRegistry} implementation.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DefaultHealthContributorRegistry extends AbstractRegistry<HealthContributor, Entry>\n\t\timplements HealthContributorRegistry {\n\n\t/**\n\t * Create a new empty {@link DefaultHealthContributorRegistry} instance.\n\t */\n\tpublic DefaultHealthContributorRegistry() {\n\t\tthis(null, null);\n\t}\n\n\t/**\n\t * Create a new {@link DefaultHealthContributorRegistry} instance.\n\t * @param nameValidators the name validators to apply\n\t * @param initialRegistrations callback to setup any initial registrations\n\t */\n\tpublic DefaultHealthContributorRegistry(\n\t\t\t@Nullable Collection<? extends HealthContributorNameValidator> nameValidators,\n\t\t\t@Nullable Consumer<BiConsumer<String, HealthContributor>> initialRegistrations) {\n\t\tsuper(Entry::new, nameValidators, initialRegistrations);\n\t}\n\n\t@Override\n\tpublic @Nullable HealthContributor getContributor(String name) {\n\t\treturn super.getContributor(name);\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\treturn super.stream();\n\t}\n\n\t@Override\n\tpublic void registerContributor(String name, HealthContributor contributor) {\n\t\tsuper.registerContributor(name, contributor);\n\t}\n\n\t@Override\n\tpublic @Nullable HealthContributor unregisterContributor(String name) {\n\t\treturn super.unregisterContributor(name);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/DefaultReactiveHealthContributorRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport java.util.Collection;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;\n\n/**\n * Default {@link ReactiveHealthContributorRegistry} implementation.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DefaultReactiveHealthContributorRegistry extends AbstractRegistry<ReactiveHealthContributor, Entry>\n\t\timplements ReactiveHealthContributorRegistry {\n\n\t/**\n\t * Create a new empty {@link DefaultReactiveHealthContributorRegistry} instance.\n\t */\n\tpublic DefaultReactiveHealthContributorRegistry() {\n\t\tthis(null, null);\n\t}\n\n\t/**\n\t * Create a new {@link DefaultReactiveHealthContributorRegistry} instance.\n\t * @param nameValidators the name validators to apply\n\t * @param initialRegistrations callback to setup any initial registrations\n\t */\n\tpublic DefaultReactiveHealthContributorRegistry(\n\t\t\t@Nullable Collection<? extends HealthContributorNameValidator> nameValidators,\n\t\t\t@Nullable Consumer<BiConsumer<String, ReactiveHealthContributor>> initialRegistrations) {\n\t\tsuper(Entry::new, nameValidators, initialRegistrations);\n\t}\n\n\t@Override\n\tpublic @Nullable ReactiveHealthContributor getContributor(String name) {\n\t\treturn super.getContributor(name);\n\t}\n\n\t@Override\n\tpublic Stream<Entry> stream() {\n\t\treturn super.stream();\n\t}\n\n\t@Override\n\tpublic void registerContributor(String name, ReactiveHealthContributor contributor) {\n\t\tsuper.registerContributor(name, contributor);\n\t}\n\n\t@Override\n\tpublic @Nullable ReactiveHealthContributor unregisterContributor(String name) {\n\t\treturn super.unregisterContributor(name);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/HealthContributorNameValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\n/**\n * Interface that can be used to validate names before they are added to a health\n * contributor registry.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface HealthContributorNameValidator {\n\n\t/**\n\t * Validate the contributor name.\n\t * @param name the name to validate\n\t * @throws IllegalStateException on an invalid name\n\t */\n\tvoid validate(String name) throws IllegalStateException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/HealthContributorRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors;\n\n/**\n * A mutable registry of {@link HealthContributor health contributors}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface HealthContributorRegistry extends HealthContributors {\n\n\t/**\n\t * Register a contributor with the given {@code name}.\n\t * @param name the name of the contributor\n\t * @param contributor the contributor to register\n\t * @throws IllegalStateException if the contributor cannot be registered with the\n\t * given {@code name}.\n\t */\n\tvoid registerContributor(String name, HealthContributor contributor);\n\n\t/**\n\t * Unregister a previously registered contributor.\n\t * @param name the name of the contributor to unregister\n\t * @return the unregistered indicator, or {@code null} if no indicator was found in\n\t * the registry for the given {@code name}.\n\t */\n\t@Nullable HealthContributor unregisterContributor(String name);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/ReactiveHealthContributorRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\n\n/**\n * A mutable registry of {@link ReactiveHealthContributor reactive health contributors}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface ReactiveHealthContributorRegistry extends ReactiveHealthContributors {\n\n\t/**\n\t * Register a contributor with the given {@code name}.\n\t * @param name the name of the contributor\n\t * @param contributor the contributor to register\n\t * @throws IllegalStateException if the contributor cannot be registered with the\n\t * given {@code name}.\n\t */\n\tvoid registerContributor(String name, ReactiveHealthContributor contributor);\n\n\t/**\n\t * Unregister a previously registered contributor.\n\t * @param name the name of the contributor to unregister\n\t * @return the unregistered indicator, or {@code null} if no indicator was found in\n\t * the registry for the given {@code name}.\n\t */\n\t@Nullable ReactiveHealthContributor unregisterContributor(String name);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/java/org/springframework/boot/health/registry/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health registry support.\n */\n@NullMarked\npackage org.springframework.boot.health.registry;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-health/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.endpoint.health.probes.add-additional-paths\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to make the liveness and readiness health groups available on the main server port.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.endpoint.health.probes.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable liveness and readiness probes.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.endpoint.health.status.order\",\n      \"defaultValue\": [\n        \"DOWN\",\n        \"OUT_OF_SERVICE\",\n        \"UP\",\n        \"UNKNOWN\"\n      ]\n    },\n    {\n      \"name\": \"management.endpoint.health.validate-group-membership\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to validate health group membership on startup. Validation fails if a group includes or excludes a health contributor that does not exist.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.health.defaults.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable default health indicators.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.health.diskspace.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable disk space health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.health.influxdb.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"InfluxDB support has been removed.\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"management.health.livenessstate.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable liveness state health check.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.health.ping.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable ping health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.health.probes.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable liveness and readiness probes.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.endpoint.health.probes.enabled\",\n        \"since\": \"2.3.2\"\n      }\n    },\n    {\n      \"name\": \"management.health.readinessstate.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable readiness state health check.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"management.health.ssl.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable SSL certificate health check.\",\n      \"defaultValue\": true\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"management.health.status.order\",\n      \"values\": [\n        {\n          \"value\": \"UNKNOWN\"\n        },\n        {\n          \"value\": \"UP\"\n        },\n        {\n          \"value\": \"DOWN\"\n        },\n        {\n          \"value\": \"OUT_OF_SERVICE\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.health.autoconfigure.actuate.endpoint.AvailabilityProbesAutoConfiguration\norg.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration\norg.springframework.boot.health.autoconfigure.application.AvailabilityHealthContributorAutoConfiguration\norg.springframework.boot.health.autoconfigure.application.DiskSpaceHealthContributorAutoConfiguration\norg.springframework.boot.health.autoconfigure.application.SslHealthContributorAutoConfiguration\norg.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration\norg.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/AdditionalHealthEndpointPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AdditionalHealthEndpointPath}.\n *\n * @author Madhura Bhave\n */\nclass AdditionalHealthEndpointPathTests {\n\n\t@Test\n\tvoid fromValidPathShouldCreatePath() {\n\t\tAdditionalHealthEndpointPath path = AdditionalHealthEndpointPath.from(\"server:/my-path\");\n\t\tassertThat(path.getValue()).isEqualTo(\"/my-path\");\n\t\tassertThat(path.getNamespace()).isEqualTo(WebServerNamespace.SERVER);\n\t}\n\n\t@Test\n\tvoid fromValidPathWithoutSlashShouldCreatePath() {\n\t\tAdditionalHealthEndpointPath path = AdditionalHealthEndpointPath.from(\"server:my-path\");\n\t\tassertThat(path.getValue()).isEqualTo(\"my-path\");\n\t\tassertThat(path.getNamespace()).isEqualTo(WebServerNamespace.SERVER);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid fromNullPathShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> AdditionalHealthEndpointPath.from(null));\n\t}\n\n\t@Test\n\tvoid fromEmptyPathShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> AdditionalHealthEndpointPath.from(\"\"));\n\t}\n\n\t@Test\n\tvoid fromPathWithNoNamespaceShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> AdditionalHealthEndpointPath.from(\"my-path\"));\n\t}\n\n\t@Test\n\tvoid fromPathWithEmptyNamespaceShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> AdditionalHealthEndpointPath.from(\":my-path\"));\n\t}\n\n\t@Test\n\tvoid fromPathWithMultipleSegmentsShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> AdditionalHealthEndpointPath.from(\"server:/my-path/my-sub-path\"));\n\t}\n\n\t@Test\n\tvoid fromPathWithMultipleSegmentsNotStartingWithSlashShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> AdditionalHealthEndpointPath.from(\"server:my-path/my-sub-path\"));\n\t}\n\n\t@Test\n\tvoid pathsWithTheSameNamespaceAndValueAreEqual() {\n\t\tassertThat(AdditionalHealthEndpointPath.from(\"server:/my-path\"))\n\t\t\t.isEqualTo(AdditionalHealthEndpointPath.from(\"server:/my-path\"));\n\t}\n\n\t@Test\n\tvoid pathsWithTheDifferentNamespaceAndSameValueAreNotEqual() {\n\t\tassertThat(AdditionalHealthEndpointPath.from(\"server:/my-path\"))\n\t\t\t.isNotEqualTo((AdditionalHealthEndpointPath.from(\"management:/my-path\")));\n\t}\n\n\t@Test\n\tvoid pathsWithTheSameNamespaceAndValuesWithNoSlashAreEqual() {\n\t\tassertThat(AdditionalHealthEndpointPath.from(\"server:/my-path\"))\n\t\t\t.isEqualTo((AdditionalHealthEndpointPath.from(\"server:my-path\")));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWithNullNamespaceShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> AdditionalHealthEndpointPath.of(null, \"my-sub-path\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWithNullPathShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER, null));\n\t}\n\n\t@Test\n\tvoid ofWithMultipleSegmentValueShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER, \"/my-path/my-subpath\"));\n\t}\n\n\t@Test\n\tvoid ofShouldCreatePath() {\n\t\tAdditionalHealthEndpointPath additionalPath = AdditionalHealthEndpointPath.of(WebServerNamespace.SERVER,\n\t\t\t\t\"my-path\");\n\t\tassertThat(additionalPath.getValue()).isEqualTo(\"my-path\");\n\t\tassertThat(additionalPath.getNamespace()).isEqualTo(WebServerNamespace.SERVER);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/CompositeHealthDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link CompositeHealthDescriptor}.\n *\n * @author Phillip Webb\n */\nclass CompositeHealthDescriptorTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenApiVersionIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new CompositeHealthDescriptor(null, Status.UP, Collections.emptyMap()))\n\t\t\t.withMessage(\"'apiVersion' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenStatusIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new CompositeHealthDescriptor(ApiVersion.V3, null, Collections.emptyMap()))\n\t\t\t.withMessage(\"'status' must not be null\");\n\t}\n\n\t@Test\n\tvoid getStatusReturnsStatus() {\n\t\tCompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V3, Status.UP,\n\t\t\t\tCollections.emptyMap());\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid getComponentReturnsComponents() {\n\t\tMap<String, HealthDescriptor> components = new LinkedHashMap<>();\n\t\tcomponents.put(\"a\", new IndicatedHealthDescriptor(Health.up().build()));\n\t\tCompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V3, Status.UP, components);\n\t\tassertThat(descriptor.getComponents()).isEqualTo(components);\n\t}\n\n\t@Test\n\tvoid serializeV3WithJacksonReturnsValidJson() throws Exception {\n\t\tMap<String, HealthDescriptor> components = new LinkedHashMap<>();\n\t\tcomponents.put(\"db1\", new IndicatedHealthDescriptor(Health.up().build()));\n\t\tcomponents.put(\"db2\", new IndicatedHealthDescriptor(Health.down().withDetail(\"a\", \"b\").build()));\n\t\tCompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V3, Status.UP, components);\n\t\tJsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\"\"\"\n\t\t\t\t{\"components\":{\"db1\":{\"status\":\"UP\"},\"db2\":{\"details\":{\"a\":\"b\"},\"status\":\"DOWN\"}},\"status\":\"UP\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid serializeV2WithJacksonReturnsValidJson() throws Exception {\n\t\tMap<String, HealthDescriptor> components = new LinkedHashMap<>();\n\t\tcomponents.put(\"db1\", new IndicatedHealthDescriptor(Health.up().build()));\n\t\tcomponents.put(\"db2\", new IndicatedHealthDescriptor(Health.down().withDetail(\"a\", \"b\").build()));\n\t\tCompositeHealthDescriptor descriptor = new CompositeHealthDescriptor(ApiVersion.V2, Status.UP, components);\n\t\tJsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\"\"\"\n\t\t\t\t{\"details\":{\"db1\":{\"status\":\"UP\"},\"db2\":{\"details\":{\"a\":\"b\"},\"status\":\"DOWN\"}},\"status\":\"UP\"}\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointGroupsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HealthEndpointGroups}.\n *\n * @author Phillip Webb\n */\nclass HealthEndpointGroupsTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenPrimaryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> HealthEndpointGroups.of(null, Collections.emptyMap()))\n\t\t\t.withMessage(\"'primary' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenAdditionalIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> HealthEndpointGroups.of(mock(HealthEndpointGroup.class), null))\n\t\t\t.withMessage(\"'additional' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofReturnsHealthEndpointGroupsInstance() {\n\t\tHealthEndpointGroup primary = mock(HealthEndpointGroup.class);\n\t\tHealthEndpointGroup group = mock(HealthEndpointGroup.class);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(primary, Collections.singletonMap(\"group\", group));\n\t\tassertThat(groups.getPrimary()).isSameAs(primary);\n\t\tassertThat(groups.getNames()).containsExactly(\"group\");\n\t\tassertThat(groups.get(\"group\")).isSameAs(group);\n\t\tassertThat(groups.get(\"missing\")).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointSupportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointSupport.Result;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for {@link HealthEndpointSupport} tests.\n *\n * @param <E> the endpoint type;\n * @param <H> the health type\n * @param <D> the descriptor type\n * @param <R> the registry type\n * @param <C> the contributor type\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nabstract class HealthEndpointSupportTests<E extends HealthEndpointSupport<H, D>, H, D, R, C> {\n\n\tfinal Health up = Health.up().withDetail(\"spring\", \"boot\").build();\n\n\tfinal Health down = Health.down().build();\n\n\tfinal TestHealthEndpointGroup primaryGroup = new TestHealthEndpointGroup();\n\n\tfinal TestHealthEndpointGroup allTheAs = new TestHealthEndpointGroup((name) -> name.startsWith(\"a\"));\n\n\tfinal HealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"alltheas\", this.allTheAs));\n\n\t@Test\n\tvoid getResultWhenPathIsEmptyUsesPrimaryGroup() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tE support = create(registry, this.groups);\n\t\tResult<D> result = support.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.group()).isEqualTo(this.primaryGroup);\n\t\tSystemHealthDescriptor descriptor = (SystemHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor.getComponents()).containsKey(\"test\");\n\t\tassertThat(descriptor.getDetails()).isNull();\n\t}\n\n\t@Test\n\tvoid getResultWhenPathIsNotGroupReturnsResultFromPrimaryGroup() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"test\");\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.group()).isEqualTo(this.primaryGroup);\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getResultWhenPathIsGroupReturnsResultFromGroup() {\n\t\tR registry = createRegistry(\"atest\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"alltheas\", \"atest\");\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.group()).isEqualTo(this.allTheAs);\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getResultWhenAlwaysShowIsFalseAndGroupIsTrueShowsComponents() {\n\t\tC contributor = createContributor(this.up);\n\t\tC compositeContributor = createCompositeContributor(Map.of(\"spring\", contributor));\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"test\");\n\t\tassertThat(result).isNotNull();\n\t\tCompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getComponents()).containsKey(\"spring\");\n\t}\n\n\t@Test\n\tvoid getResultWhenAlwaysShowIsFalseAndGroupIsFalseCannotAccessComponent() {\n\t\tthis.primaryGroup.setShowComponents(false);\n\t\tC contributor = createContributor(this.up);\n\t\tC compositeContributor = createCompositeContributor(Map.of(\"spring\", contributor));\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> rootResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tassertThat(rootResult).isNotNull();\n\t\tCompositeHealthDescriptor rootDescriptor = (CompositeHealthDescriptor) getDescriptor(rootResult);\n\t\tassertThat(rootDescriptor.getComponents()).isNullOrEmpty();\n\t\tResult<D> componentResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"test\");\n\t\tassertThat(componentResult).isNull();\n\t}\n\n\t@Test\n\tvoid getResultWhenAlwaysShowIsTrueShowsComponents() {\n\t\tthis.primaryGroup.setShowComponents(true);\n\t\tC contributor = createContributor(this.up);\n\t\tC compositeContributor = createCompositeContributor(Map.of(\"spring\", contributor));\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> rootResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tassertThat(rootResult).isNotNull();\n\t\tCompositeHealthDescriptor rootDescriptor = (CompositeHealthDescriptor) getDescriptor(rootResult);\n\t\tassertThat(rootDescriptor.getComponents()).containsKey(\"test\");\n\t\tResult<D> componentResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"test\");\n\t\tassertThat(componentResult).isNotNull();\n\t\tCompositeHealthDescriptor componentDescriptor = (CompositeHealthDescriptor) getDescriptor(componentResult);\n\t\tassertThat(componentDescriptor.getComponents()).containsKey(\"spring\");\n\t}\n\n\t@Test\n\tvoid getResultWhenAlwaysShowIsFalseAndGroupIsTrueShowsDetails() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"test\");\n\t\tassertThat(result).isNotNull();\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getResultWhenAlwaysShowIsFalseAndGroupIsFalseShowsNoDetails() {\n\t\tthis.primaryGroup.setShowDetails(false);\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> rootResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tResult<D> componentResult = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"test\");\n\t\tassertThat(rootResult).isNotNull();\n\t\tassertThat(getDescriptor(rootResult).getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(componentResult).isNull();\n\t}\n\n\t@Test\n\tvoid getResultWhenAlwaysShowIsTrueShowsDetails() {\n\t\tthis.primaryGroup.setShowDetails(false);\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, true, \"test\");\n\t\tassertThat(result).isNotNull();\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getResultWhenCompositeReturnsAggregateResult() {\n\t\tMap<String, C> contributors = new LinkedHashMap<>();\n\t\tcontributors.put(\"a\", createContributor(this.up));\n\t\tcontributors.put(\"b\", createContributor(this.down));\n\t\tR registry = createRegistry(\"test\", createCompositeContributor(contributors));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tassertThat(result).isNotNull();\n\t\tCompositeHealthDescriptor root = (CompositeHealthDescriptor) getDescriptor(result);\n\t\tMap<String, HealthDescriptor> rootComponents = root.getComponents();\n\t\tassertThat(rootComponents).isNotNull();\n\t\tCompositeHealthDescriptor component = (CompositeHealthDescriptor) rootComponents.get(\"test\");\n\t\tassertThat(root.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(component).isNotNull();\n\t\tassertThat(component.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(component.getComponents()).containsOnlyKeys(\"a\", \"b\");\n\t}\n\n\t@Test\n\tvoid getResultWhenPathDoesNotExistReturnsNull() {\n\t\tR registry = createRegistry(\"test\", createCompositeContributor(Collections.emptyMap()));\n\t\tResult<D> result = create(registry, this.groups).getResult(ApiVersion.V3, null, SecurityContext.NONE, false,\n\t\t\t\t\"missing\");\n\t\tassertThat(result).isNull();\n\t}\n\n\t@Test\n\tvoid getResultWhenPathIsEmptyIncludesGroups() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tassertThat(result).isNotNull();\n\t\tSystemHealthDescriptor descriptor = (SystemHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getGroups()).containsOnly(\"alltheas\");\n\t}\n\n\t@Test\n\tvoid getResultWhenPathIsGroupDoesNotIncludesGroups() {\n\t\tR registry = createRegistry(\"atest\", createContributor(this.up));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"alltheas\");\n\t\tassertThat(result).isNotNull();\n\t\tHealthDescriptor descriptor = getDescriptor(result);\n\t\tassertThat(descriptor).isInstanceOf(CompositeHealthDescriptor.class);\n\t\tassertThat(descriptor).isNotInstanceOf(SystemHealthDescriptor.class);\n\t}\n\n\t@Test\n\tvoid getResultWithEmptyCompositeReturnsNullResult() { // gh-18687\n\t\tR registry = createRegistry(\"test\", createCompositeContributor(Collections.emptyMap()));\n\t\tE endpoint = create(registry, this.groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false);\n\t\tassertThat(result).isNull();\n\t}\n\n\t@Test\n\tvoid getResultWhenGroupContainsCompositeContributorReturnsHealth() {\n\t\tC contributor = createContributor(this.up);\n\t\tC compositeContributor = createCompositeContributor(Map.of(\"spring\", contributor));\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith(\"test\"));\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"testGroup\");\n\t\tassertThat(result).isNotNull();\n\t\tCompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getComponents()).containsKey(\"test\");\n\t}\n\n\t@Test\n\tvoid getResultWhenGroupContainsComponentOfCompositeContributorReturnsHealth() {\n\t\tCompositeHealthDescriptor descriptor = getCompositeHealthDescriptor((name) -> name.equals(\"test/spring-1\"));\n\t\tMap<String, HealthDescriptor> components = descriptor.getComponents();\n\t\tassertThat(components).isNotNull().containsKey(\"test\");\n\t\tCompositeHealthDescriptor test = (CompositeHealthDescriptor) components.get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tMap<String, HealthDescriptor> testComponents = test.getComponents();\n\t\tassertThat(testComponents).isNotNull();\n\t\tassertThat(testComponents).containsKey(\"spring-1\");\n\t\tassertThat(testComponents).doesNotContainKey(\"spring-2\");\n\t\tassertThat(testComponents).doesNotContainKey(\"test\");\n\t}\n\n\t@Test\n\tvoid getResultWhenGroupExcludesComponentOfCompositeContributorReturnsHealth() {\n\t\tCompositeHealthDescriptor descriptor = getCompositeHealthDescriptor(\n\t\t\t\t(name) -> name.startsWith(\"test/\") && !name.equals(\"test/spring-2\"));\n\t\tMap<String, HealthDescriptor> components = descriptor.getComponents();\n\t\tassertThat(components).isNotNull().containsKey(\"test\");\n\t\tCompositeHealthDescriptor test = (CompositeHealthDescriptor) components.get(\"test\");\n\t\tassertThat(test).isNotNull();\n\t\tassertThat(test.getComponents()).containsKey(\"spring-1\");\n\t\tassertThat(test.getComponents()).doesNotContainKey(\"spring-2\");\n\t}\n\n\tprivate CompositeHealthDescriptor getCompositeHealthDescriptor(Predicate<String> memberPredicate) {\n\t\tC contributor1 = createContributor(this.up);\n\t\tC contributor2 = createContributor(this.down);\n\t\tMap<String, C> contributors = new LinkedHashMap<>();\n\t\tcontributors.put(\"spring-1\", contributor1);\n\t\tcontributors.put(\"spring-2\", contributor2);\n\t\tC compositeContributor = createCompositeContributor(contributors);\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(memberPredicate);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"testGroup\");\n\t\tassertThat(result).isNotNull();\n\t\treturn (CompositeHealthDescriptor) getDescriptor(result);\n\t}\n\n\t@Test\n\tvoid getResultForPathWhenGroupContainsComponentOfCompositeContributorReturnsHealth() {\n\t\tMap<String, C> contributors = new LinkedHashMap<>();\n\t\tcontributors.put(\"spring-1\", createNestedHealthContributor(\"spring-1\"));\n\t\tcontributors.put(\"spring-2\", createNestedHealthContributor(\"spring-2\"));\n\t\tC compositeContributor = createCompositeContributor(contributors);\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(\n\t\t\t\t(name) -> name.startsWith(\"test\") && !name.equals(\"test/spring-1/b\"));\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"testGroup\", \"test\");\n\t\tassertThat(result).isNotNull();\n\t\tCompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);\n\t\tMap<String, HealthDescriptor> components = descriptor.getComponents();\n\t\tassertThat(components).isNotNull();\n\t\tassertThat(components).containsKey(\"spring-1\");\n\t\tassertThat(components).containsKey(\"spring-2\");\n\t\tCompositeHealthDescriptor spring1 = (CompositeHealthDescriptor) components.get(\"spring-1\");\n\t\tCompositeHealthDescriptor spring2 = (CompositeHealthDescriptor) components.get(\"spring-2\");\n\t\tassertThat(spring1).isNotNull();\n\t\tassertThat(spring1.getComponents()).containsKey(\"a\");\n\t\tassertThat(spring1.getComponents()).containsKey(\"c\");\n\t\tassertThat(spring1.getComponents()).doesNotContainKey(\"b\");\n\t\tassertThat(spring2).isNotNull();\n\t\tassertThat(spring2.getComponents()).containsKey(\"a\");\n\t\tassertThat(spring2.getComponents()).containsKey(\"c\");\n\t\tassertThat(spring2.getComponents()).containsKey(\"b\");\n\t}\n\n\t@Test\n\tvoid getResultForComponentPathWhenNotPartOfGroup() {\n\t\tMap<String, C> contributors = new LinkedHashMap<>();\n\t\tcontributors.put(\"spring-1\", createNestedHealthContributor(\"spring-1\"));\n\t\tcontributors.put(\"spring-2\", createNestedHealthContributor(\"spring-2\"));\n\t\tC compositeContributor = createCompositeContributor(contributors);\n\t\tR registry = createRegistry(\"test\", compositeContributor);\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup(\n\t\t\t\t(name) -> name.startsWith(\"test\") && !name.equals(\"test/spring-1/b\"));\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, null, SecurityContext.NONE, false, \"testGroup\", \"test\",\n\t\t\t\t\"spring-1\", \"b\");\n\t\tassertThat(result).isNull();\n\t}\n\n\tprivate C createNestedHealthContributor(String name) {\n\t\tMap<String, C> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", createContributor(Health.up().withDetail(\"hello\", name + \"-a\").build()));\n\t\tmap.put(\"b\", createContributor(Health.up().withDetail(\"hello\", name + \"-b\").build()));\n\t\tmap.put(\"c\", createContributor(Health.up().withDetail(\"hello\", name + \"-c\").build()));\n\t\treturn createCompositeContributor(map);\n\t}\n\n\t@Test\n\tvoid getResultWhenGroupHasAdditionalPath() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith(\"test\"));\n\t\ttestGroup.setAdditionalPath(AdditionalHealthEndpointPath.from(\"server:/healthz\"));\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, WebServerNamespace.SERVER, SecurityContext.NONE, false,\n\t\t\t\t\"healthz\");\n\t\tassertThat(result).isNotNull();\n\t\tCompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getComponents()).containsKey(\"test\");\n\t}\n\n\t@Test\n\tvoid getResultWhenGroupHasAdditionalPathAndShowComponentsFalse() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith(\"test\"));\n\t\ttestGroup.setAdditionalPath(AdditionalHealthEndpointPath.from(\"server:/healthz\"));\n\t\ttestGroup.setShowComponents(false);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, WebServerNamespace.SERVER, SecurityContext.NONE, false,\n\t\t\t\t\"healthz\");\n\t\tassertThat(result).isNotNull();\n\t\tCompositeHealthDescriptor descriptor = (CompositeHealthDescriptor) getDescriptor(result);\n\t\tassertThat(descriptor.getStatus().getCode()).isEqualTo(\"UP\");\n\t\tassertThat(descriptor.getComponents()).isNull();\n\t}\n\n\t@Test\n\tvoid getResultWithPathWhenGroupHasAdditionalPathAndShowComponentsFalse() {\n\t\tR registry = createRegistry(\"test\", createContributor(this.up));\n\t\tTestHealthEndpointGroup testGroup = new TestHealthEndpointGroup((name) -> name.startsWith(\"test\"));\n\t\ttestGroup.setAdditionalPath(AdditionalHealthEndpointPath.from(\"server:/healthz\"));\n\t\ttestGroup.setShowComponents(false);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(this.primaryGroup, Map.of(\"testGroup\", testGroup));\n\t\tE endpoint = create(registry, groups);\n\t\tResult<D> result = endpoint.getResult(ApiVersion.V3, WebServerNamespace.SERVER, SecurityContext.NONE, false,\n\t\t\t\t\"healthz\", \"test\");\n\t\tassertThat(result).isNull();\n\t}\n\n\tprotected final E create(R registry, HealthEndpointGroups groups) {\n\t\treturn create(registry, groups, null);\n\t}\n\n\tprotected abstract E create(R registry, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowContributorLoggingThreshold);\n\n\tprotected final R createRegistry(String name, C contributor) {\n\t\treturn createRegistry((registrations) -> registrations.accept(name, contributor));\n\t}\n\n\tprotected abstract R createRegistry(@Nullable Consumer<BiConsumer<String, C>> initialRegistrations);\n\n\tprotected abstract C createContributor(Health health);\n\n\tprotected abstract C createCompositeContributor(Map<String, C> contributors);\n\n\tprotected abstract HealthDescriptor getDescriptor(Result<D> result);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointSupport.Result;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HealthEndpoint}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass HealthEndpointTests extends\n\t\tHealthEndpointSupportTests<HealthEndpoint, Health, HealthDescriptor, HealthContributorRegistry, HealthContributor> {\n\n\t@Test\n\tvoid healthReturnsSystemHealth() {\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tHealthEndpoint endpoint = create(registry, this.groups);\n\t\tHealthDescriptor descriptor = endpoint.health();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor).isInstanceOf(SystemHealthDescriptor.class);\n\t}\n\n\t@Test\n\tvoid healthWithNoContributorReturnsUp() {\n\t\tHealthContributorRegistry registry = createRegistry(null);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap());\n\t\tHealthEndpoint endpoint = create(registry, groups);\n\t\tHealthDescriptor descriptor = endpoint.health();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor).isInstanceOf(IndicatedHealthDescriptor.class);\n\t}\n\n\t@Test\n\tvoid healthWhenPathDoesNotExistReturnsNull() {\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tHealthEndpoint endpoint = create(registry, this.groups);\n\t\tHealthDescriptor descriptor = endpoint.healthForPath(\"missing\");\n\t\tassertThat(descriptor).isNull();\n\t}\n\n\t@Test\n\tvoid healthWhenPathExistsReturnsHealth() {\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tHealthEndpoint endpoint = create(registry, this.groups);\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) endpoint.healthForPath(\"test\");\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid healthWhenIndicatorIsSlow(CapturedOutput output) {\n\t\tHealthIndicator indicator = () -> {\n\t\t\ttry {\n\t\t\t\tThread.sleep(100);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\treturn this.up;\n\t\t};\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", indicator);\n\t\tHealthEndpoint endpoint = create(registry, this.groups, Duration.ofMillis(10));\n\t\tendpoint.health();\n\t\tassertThat(output).contains(\"Health contributor\");\n\t\tassertThat(output).contains(\"to respond\");\n\t}\n\n\t@Override\n\tprotected HealthEndpoint create(HealthContributorRegistry registry, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowContributorLoggingThreshold) {\n\t\treturn new HealthEndpoint(registry, null, groups, slowContributorLoggingThreshold);\n\t}\n\n\t@Override\n\tprotected HealthContributorRegistry createRegistry(\n\t\t\t@Nullable Consumer<BiConsumer<String, HealthContributor>> initialRegistrations) {\n\t\treturn new DefaultHealthContributorRegistry(Collections.emptyList(), initialRegistrations);\n\t}\n\n\t@Override\n\tprotected HealthContributor createContributor(Health health) {\n\t\treturn (HealthIndicator) () -> health;\n\t}\n\n\t@Override\n\tprotected HealthContributor createCompositeContributor(Map<String, HealthContributor> contributors) {\n\t\treturn CompositeHealthContributor.fromMap(contributors);\n\t}\n\n\t@Override\n\tprotected HealthDescriptor getDescriptor(Result<HealthDescriptor> result) {\n\t\treturn result.descriptor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointWebExtensionRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthEndpointWebExtensionRuntimeHints}.\n *\n * @author Moritz Halbritter\n */\nclass HealthEndpointWebExtensionRuntimeHintsTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew HealthEndpointWebExtensionRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tSet<Class<?>> bindingTypes = Set.of(IndicatedHealthDescriptor.class, SystemHealthDescriptor.class,\n\t\t\t\tCompositeHealthDescriptor.class);\n\t\tfor (Class<?> bindingType : bindingTypes) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(bindingType)\n\t\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/HealthEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointSupport.Result;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HealthEndpointWebExtension}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass HealthEndpointWebExtensionTests extends\n\t\tHealthEndpointSupportTests<HealthEndpointWebExtension, Health, HealthDescriptor, HealthContributorRegistry, HealthContributor> {\n\n\t@Test\n\tvoid healthReturnsSystemHealth() {\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tHealthEndpointWebExtension endpoint = create(registry, this.groups);\n\t\tWebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,\n\t\t\t\tSecurityContext.NONE);\n\t\tHealthDescriptor descriptor = response.getBody();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor).isInstanceOf(SystemHealthDescriptor.class);\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid healthWithNoContributorReturnsUp() {\n\t\tHealthContributorRegistry registry = createRegistry(null);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap());\n\t\tHealthEndpointWebExtension endpoint = create(registry, groups);\n\t\tWebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,\n\t\t\t\tSecurityContext.NONE);\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t\tHealthDescriptor descriptor = response.getBody();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor).isInstanceOf(IndicatedHealthDescriptor.class);\n\t}\n\n\t@Test\n\tvoid healthWhenPathDoesNotExistReturnsHttp404() {\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tHealthEndpointWebExtension endpoint = create(registry, this.groups);\n\t\tWebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,\n\t\t\t\tSecurityContext.NONE, \"missing\");\n\t\tassertThat(response.getBody()).isNull();\n\t\tassertThat(response.getStatus()).isEqualTo(404);\n\t}\n\n\t@Test\n\tvoid healthWhenPathExistsReturnsHealth() {\n\t\tHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tHealthEndpointWebExtension endpoint = create(registry, this.groups);\n\t\tWebEndpointResponse<HealthDescriptor> response = endpoint.health(ApiVersion.LATEST, WebServerNamespace.SERVER,\n\t\t\t\tSecurityContext.NONE, \"test\");\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) response.getBody();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Override\n\tprotected HealthEndpointWebExtension create(HealthContributorRegistry registry, HealthEndpointGroups groups,\n\t\t\t@Nullable Duration slowIndicatorLoggingThreshold) {\n\t\treturn new HealthEndpointWebExtension(registry, null, groups, slowIndicatorLoggingThreshold);\n\t}\n\n\t@Override\n\tprotected HealthContributorRegistry createRegistry(\n\t\t\t@Nullable Consumer<BiConsumer<String, HealthContributor>> initialRegistrations) {\n\t\treturn new DefaultHealthContributorRegistry(Collections.emptyList(), initialRegistrations);\n\t}\n\n\t@Override\n\tprotected HealthContributor createContributor(Health health) {\n\t\treturn (HealthIndicator) () -> health;\n\t}\n\n\t@Override\n\tprotected HealthContributor createCompositeContributor(Map<String, HealthContributor> contributors) {\n\t\treturn CompositeHealthContributor.fromMap(contributors);\n\t}\n\n\t@Override\n\tprotected HealthDescriptor getDescriptor(Result<HealthDescriptor> result) {\n\t\treturn result.descriptor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/HttpCodeStatusMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpCodeStatusMapper}.\n *\n * @author Phillip Webb\n */\nclass HttpCodeStatusMapperTests {\n\n\t@Test\n\tvoid createWhenMappingsAreNullUsesDefaultMappings() {\n\t\tHttpCodeStatusMapper mapper = HttpCodeStatusMapper.of(null);\n\t\tassertThat(mapper.getStatusCode(Status.UNKNOWN)).isEqualTo(WebEndpointResponse.STATUS_OK);\n\t\tassertThat(mapper.getStatusCode(Status.UP)).isEqualTo(WebEndpointResponse.STATUS_OK);\n\t\tassertThat(mapper.getStatusCode(Status.DOWN)).isEqualTo(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t\tassertThat(mapper.getStatusCode(Status.OUT_OF_SERVICE))\n\t\t\t.isEqualTo(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t}\n\n\t@Test\n\tvoid getStatusCodeReturnsMappedStatus() {\n\t\tMap<String, Integer> map = new LinkedHashMap<>();\n\t\tmap.put(\"up\", 123);\n\t\tmap.put(\"down\", 456);\n\t\tHttpCodeStatusMapper mapper = HttpCodeStatusMapper.of(map);\n\t\tassertThat(mapper.getStatusCode(Status.UP)).isEqualTo(123);\n\t\tassertThat(mapper.getStatusCode(Status.DOWN)).isEqualTo(456);\n\t\tassertThat(mapper.getStatusCode(Status.OUT_OF_SERVICE)).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid getStatusCodeWhenMappingsAreNotUniformReturnsMappedStatus() {\n\t\tMap<String, Integer> map = new LinkedHashMap<>();\n\t\tmap.put(\"out-of-service\", 123);\n\t\tHttpCodeStatusMapper mapper = HttpCodeStatusMapper.of(map);\n\t\tassertThat(mapper.getStatusCode(Status.OUT_OF_SERVICE)).isEqualTo(123);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/IndicatedHealthDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.health.contributor.Health;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IndicatedHealthDescriptor}.\n *\n * @author Phillip Webb\n */\nclass IndicatedHealthDescriptorTests {\n\n\t@Test\n\tvoid serializeWithJacksonReturnsValidJson() throws Exception {\n\t\tIndicatedHealthDescriptor descriptor = new IndicatedHealthDescriptor(\n\t\t\t\tHealth.outOfService().withDetail(\"spring\", \"boot\").build());\n\t\tJsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\"\"\"\n\t\t\t\t{\"details\":{\"spring\":\"boot\"},\"status\":\"OUT_OF_SERVICE\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid serializeWithJacksonWhenEmptyDetailsReturnsValidJson() throws Exception {\n\t\tIndicatedHealthDescriptor descriptor = new IndicatedHealthDescriptor(Health.outOfService().build());\n\t\tJsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\"\"\"\n\t\t\t\t{\"status\":\"OUT_OF_SERVICE\"}\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/ReactiveHealthEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointSupport.Result;\nimport org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveHealthEndpointWebExtension}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass ReactiveHealthEndpointWebExtensionTests extends\n\t\tHealthEndpointSupportTests<ReactiveHealthEndpointWebExtension, Mono<? extends Health>, Mono<? extends HealthDescriptor>, ReactiveHealthContributorRegistry, ReactiveHealthContributor> {\n\n\t@Test\n\tvoid healthReturnsSystemHealth() {\n\t\tReactiveHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tReactiveHealthEndpointWebExtension endpoint = create(registry, this.groups);\n\t\tWebEndpointResponse<? extends HealthDescriptor> response = endpoint\n\t\t\t.health(ApiVersion.LATEST, null, SecurityContext.NONE)\n\t\t\t.block();\n\t\tassertThat(response).isNotNull();\n\t\tHealthDescriptor descriptor = response.getBody();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor).isInstanceOf(SystemHealthDescriptor.class);\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid healthWithNoContributorReturnsUp() {\n\t\tReactiveHealthContributorRegistry registry = createRegistry(null);\n\t\tHealthEndpointGroups groups = HealthEndpointGroups.of(mock(HealthEndpointGroup.class), Collections.emptyMap());\n\t\tReactiveHealthEndpointWebExtension endpoint = create(registry, groups);\n\t\tWebEndpointResponse<? extends HealthDescriptor> response = endpoint\n\t\t\t.health(ApiVersion.LATEST, null, SecurityContext.NONE)\n\t\t\t.block();\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t\tHealthDescriptor descriptor = response.getBody();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor).isInstanceOf(IndicatedHealthDescriptor.class);\n\t}\n\n\t@Test\n\tvoid healthWhenPathDoesNotExistReturnsHttp404() {\n\t\tReactiveHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tReactiveHealthEndpointWebExtension endpoint = create(registry, this.groups);\n\t\tWebEndpointResponse<? extends HealthDescriptor> response = endpoint\n\t\t\t.health(ApiVersion.LATEST, null, SecurityContext.NONE, \"missing\")\n\t\t\t.block();\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getBody()).isNull();\n\t\tassertThat(response.getStatus()).isEqualTo(404);\n\t}\n\n\t@Test\n\tvoid healthWhenPathExistsReturnsHealth() {\n\t\tReactiveHealthContributorRegistry registry = createRegistry(\"test\", createContributor(this.up));\n\t\tReactiveHealthEndpointWebExtension endpoint = create(registry, this.groups);\n\t\tWebEndpointResponse<? extends HealthDescriptor> response = endpoint\n\t\t\t.health(ApiVersion.LATEST, null, SecurityContext.NONE, \"test\")\n\t\t\t.block();\n\t\tassertThat(response).isNotNull();\n\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) response.getBody();\n\t\tassertThat(descriptor).isNotNull();\n\t\tassertThat(descriptor.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(descriptor.getDetails()).containsEntry(\"spring\", \"boot\");\n\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t}\n\n\t@Override\n\tprotected ReactiveHealthEndpointWebExtension create(ReactiveHealthContributorRegistry registry,\n\t\t\tHealthEndpointGroups groups, @Nullable Duration slowContributorLoggingThreshold) {\n\t\treturn new ReactiveHealthEndpointWebExtension(registry, null, groups, slowContributorLoggingThreshold);\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributorRegistry createRegistry(\n\t\t\t@Nullable Consumer<BiConsumer<String, ReactiveHealthContributor>> initialRegistrations) {\n\t\treturn new DefaultReactiveHealthContributorRegistry(Collections.emptyList(), initialRegistrations);\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributor createContributor(Health health) {\n\t\treturn (ReactiveHealthIndicator) () -> Mono.just(health);\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributor createCompositeContributor(\n\t\t\tMap<String, ReactiveHealthContributor> contributors) {\n\t\treturn CompositeReactiveHealthContributor.fromMap(contributors);\n\t}\n\n\t@Override\n\tprotected HealthDescriptor getDescriptor(Result<Mono<? extends HealthDescriptor>> result) {\n\t\tHealthDescriptor descriptor = result.descriptor().block();\n\t\tassertThat(descriptor).isNotNull();\n\t\treturn descriptor;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/ReactiveHealthIndicatorImplementationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractReactiveHealthIndicator}.\n *\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ReactiveHealthIndicatorImplementationTests {\n\n\t@Test\n\tvoid healthUp(CapturedOutput output) {\n\t\tStepVerifier.create(new SimpleReactiveHealthIndicator().health())\n\t\t\t.consumeNextWith((health) -> assertThat(health).isEqualTo(Health.up().build()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tassertThat(output).doesNotContain(\"Health check failed for simple\");\n\t}\n\n\t@Test\n\tvoid healthDownWithCustomErrorMessage(CapturedOutput output) {\n\t\tStepVerifier.create(new CustomErrorMessageReactiveHealthIndicator().health())\n\t\t\t.consumeNextWith(\n\t\t\t\t\t(health) -> assertThat(health).isEqualTo(Health.down(new UnsupportedOperationException()).build()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tassertThat(output).contains(\"Health check failed for custom\");\n\t}\n\n\t@Test\n\tvoid healthDownWithCustomErrorMessageFunction(CapturedOutput output) {\n\t\tStepVerifier.create(new CustomErrorMessageFunctionReactiveHealthIndicator().health())\n\t\t\t.consumeNextWith((health) -> assertThat(health).isEqualTo(Health.down(new RuntimeException()).build()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tassertThat(output).contains(\"Health check failed with RuntimeException\");\n\t}\n\n\tprivate static final class SimpleReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\t\tSimpleReactiveHealthIndicator() {\n\t\t\tsuper(\"Health check failed for simple\");\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\treturn Mono.just(builder.up().build());\n\t\t}\n\n\t}\n\n\tprivate static final class CustomErrorMessageReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\t\tCustomErrorMessageReactiveHealthIndicator() {\n\t\t\tsuper(\"Health check failed for custom\");\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\treturn Mono.error(new UnsupportedOperationException());\n\t\t}\n\n\t}\n\n\tprivate static final class CustomErrorMessageFunctionReactiveHealthIndicator\n\t\t\textends AbstractReactiveHealthIndicator {\n\n\t\tCustomErrorMessageFunctionReactiveHealthIndicator() {\n\t\t\tsuper((ex) -> \"Health check failed with \" + ex.getClass().getSimpleName());\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\tthrow new RuntimeException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/SimpleHttpCodeStatusMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SimpleHttpCodeStatusMapper}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass SimpleHttpCodeStatusMapperTests {\n\n\t@Test\n\tvoid createWhenMappingsAreNullUsesDefaultMappings() {\n\t\tSimpleHttpCodeStatusMapper mapper = new SimpleHttpCodeStatusMapper(null);\n\t\tassertThat(mapper.getStatusCode(Status.UNKNOWN)).isEqualTo(WebEndpointResponse.STATUS_OK);\n\t\tassertThat(mapper.getStatusCode(Status.UP)).isEqualTo(WebEndpointResponse.STATUS_OK);\n\t\tassertThat(mapper.getStatusCode(Status.DOWN)).isEqualTo(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t\tassertThat(mapper.getStatusCode(Status.OUT_OF_SERVICE))\n\t\t\t.isEqualTo(WebEndpointResponse.STATUS_SERVICE_UNAVAILABLE);\n\t}\n\n\t@Test\n\tvoid getStatusCodeReturnsMappedStatus() {\n\t\tMap<String, Integer> map = new LinkedHashMap<>();\n\t\tmap.put(\"up\", 123);\n\t\tmap.put(\"down\", 456);\n\t\tSimpleHttpCodeStatusMapper mapper = new SimpleHttpCodeStatusMapper(map);\n\t\tassertThat(mapper.getStatusCode(Status.UP)).isEqualTo(123);\n\t\tassertThat(mapper.getStatusCode(Status.DOWN)).isEqualTo(456);\n\t\tassertThat(mapper.getStatusCode(Status.OUT_OF_SERVICE)).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid getStatusCodeWhenMappingsAreNotUniformReturnsMappedStatus() {\n\t\tMap<String, Integer> map = new LinkedHashMap<>();\n\t\tmap.put(\"out-of-service\", 123);\n\t\tSimpleHttpCodeStatusMapper mapper = new SimpleHttpCodeStatusMapper(map);\n\t\tassertThat(mapper.getStatusCode(Status.OUT_OF_SERVICE)).isEqualTo(123);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/SimpleStatusAggregatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SimpleStatusAggregator}\n *\n * @author Phillip Webb\n * @author Christian Dupuis\n */\n@SuppressWarnings(\"removal\")\nclass SimpleStatusAggregatorTests {\n\n\t@Test\n\tvoid getAggregateStatusWhenUsingDefaultInstance() {\n\t\tStatusAggregator aggregator = StatusAggregator.getDefault();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid getAggregateStatusWhenUsingNewDefaultOrder() {\n\t\tSimpleStatusAggregator aggregator = new SimpleStatusAggregator();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid getAggregateStatusWhenUsingCustomOrder() {\n\t\tSimpleStatusAggregator aggregator = new SimpleStatusAggregator(Status.UNKNOWN, Status.UP, Status.OUT_OF_SERVICE,\n\t\t\t\tStatus.DOWN);\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid getAggregateStatusWhenHasCustomStatusAndUsingDefaultOrder() {\n\t\tSimpleStatusAggregator aggregator = new SimpleStatusAggregator();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE,\n\t\t\t\tnew Status(\"CUSTOM\"));\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid getAggregateStatusWhenHasCustomStatusAndUsingCustomOrder() {\n\t\tSimpleStatusAggregator aggregator = new SimpleStatusAggregator(\"DOWN\", \"OUT_OF_SERVICE\", \"UP\", \"UNKNOWN\",\n\t\t\t\t\"CUSTOM\");\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE,\n\t\t\t\tnew Status(\"CUSTOM\"));\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid createWithNonUniformCodes() {\n\t\tSimpleStatusAggregator aggregator = new SimpleStatusAggregator(\"out-of-service\", \"up\");\n\t\tStatus status = aggregator.getAggregateStatus(Status.UP, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.OUT_OF_SERVICE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/StatusAggregatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StatusAggregator}.\n *\n * @author Phillip Webb\n */\nclass StatusAggregatorTests {\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenUsingDefaultInstance() {\n\t\tStatusAggregator aggregator = StatusAggregator.getDefault();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenUsingCustomOrder() {\n\t\tStatusAggregator aggregator = StatusAggregator.of(Status.UNKNOWN, Status.UP, Status.OUT_OF_SERVICE,\n\t\t\t\tStatus.DOWN);\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenHasCustomStatusAndUsingDefaultOrder() {\n\t\tStatusAggregator aggregator = StatusAggregator.getDefault();\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE,\n\t\t\t\tnew Status(\"CUSTOM\"));\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid ofAndGetAggregateStatusWhenHasCustomStatusAndUsingCustomOrder() {\n\t\tStatusAggregator aggregator = StatusAggregator.of(\"DOWN\", \"OUT_OF_SERVICE\", \"UP\", \"UNKNOWN\", \"CUSTOM\");\n\t\tStatus status = aggregator.getAggregateStatus(Status.DOWN, Status.UP, Status.UNKNOWN, Status.OUT_OF_SERVICE,\n\t\t\t\tnew Status(\"CUSTOM\"));\n\t\tassertThat(status).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid ofWithNonUniformCodes() {\n\t\tStatusAggregator aggregator = StatusAggregator.of(\"out-of-service\", \"up\");\n\t\tStatus status = aggregator.getAggregateStatus(Status.UP, Status.OUT_OF_SERVICE);\n\t\tassertThat(status).isEqualTo(Status.OUT_OF_SERVICE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/SystemHealthDescriptorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SystemHealthDescriptor}.\n *\n * @author Phillip Webb\n */\nclass SystemHealthDescriptorTests {\n\n\t@Test\n\tvoid serializeWithJacksonReturnsValidJson() throws Exception {\n\t\tMap<String, HealthDescriptor> components = new LinkedHashMap<>();\n\t\tcomponents.put(\"db1\", new IndicatedHealthDescriptor(Health.up().build()));\n\t\tcomponents.put(\"db2\", new IndicatedHealthDescriptor(Health.down().withDetail(\"a\", \"b\").build()));\n\t\tSet<String> groups = new LinkedHashSet<>(Arrays.asList(\"liveness\", \"readiness\"));\n\t\tSystemHealthDescriptor descriptor = new SystemHealthDescriptor(ApiVersion.V3, Status.UP, components, groups);\n\t\tJsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\n\t\t\t\t\"\"\"\n\t\t\t\t\t\t{\"components\":{\"db1\":{\"status\":\"UP\"},\"db2\":{\"details\":{\"a\":\"b\"},\"status\":\"DOWN\"}},\"groups\":[\"liveness\",\"readiness\"],\"status\":\"UP\"}\"\"\");\n\t}\n\n\t@Test\n\tvoid serializeWhenNoGroupsWithJacksonReturnsValidJson() throws Exception {\n\t\tMap<String, HealthDescriptor> components = new LinkedHashMap<>();\n\t\tcomponents.put(\"db1\", new IndicatedHealthDescriptor(Health.up().build()));\n\t\tcomponents.put(\"db2\", new IndicatedHealthDescriptor(Health.down().withDetail(\"a\", \"b\").build()));\n\t\tSystemHealthDescriptor descriptor = new SystemHealthDescriptor(ApiVersion.V3, Status.UP, components, null);\n\t\tJsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\"\"\"\n\t\t\t\t{\"components\":{\"db1\":{\"status\":\"UP\"},\"db2\":{\"details\":{\"a\":\"b\"},\"status\":\"DOWN\"}},\"status\":\"UP\"}\"\"\");\n\t}\n\n\t@Test // gh-26797\n\tvoid serializeV2WithJacksonAndDisabledCanOverrideAccessModifiersReturnsValidJson() throws Exception {\n\t\tMap<String, HealthDescriptor> components = new LinkedHashMap<>();\n\t\tcomponents.put(\"db1\", new IndicatedHealthDescriptor(Health.up().build()));\n\t\tcomponents.put(\"db2\", new IndicatedHealthDescriptor(Health.down().withDetail(\"a\", \"b\").build()));\n\t\tSystemHealthDescriptor descriptor = new SystemHealthDescriptor(ApiVersion.V2, Status.UP, components, null);\n\t\tJsonMapper mapper = JsonMapper.builder()\n\t\t\t.enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)\n\t\t\t.disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)\n\t\t\t.build();\n\t\tString json = mapper.writeValueAsString(descriptor);\n\t\tassertThat(json).isEqualTo(\"\"\"\n\t\t\t\t{\"details\":{\"db1\":{\"status\":\"UP\"},\"db2\":{\"details\":{\"a\":\"b\"},\"status\":\"DOWN\"}},\"status\":\"UP\"}\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/actuate/endpoint/TestHealthEndpointGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.actuate.endpoint;\n\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\n\n/**\n * Test implementation of {@link HealthEndpointGroups}.\n *\n * @author Phillip Webb\n */\nclass TestHealthEndpointGroup implements HealthEndpointGroup {\n\n\tprivate final StatusAggregator statusAggregator = StatusAggregator.getDefault();\n\n\tprivate final HttpCodeStatusMapper httpCodeStatusMapper = HttpCodeStatusMapper.getDefault();\n\n\tprivate final Predicate<String> memberPredicate;\n\n\tprivate @Nullable Boolean showComponents;\n\n\tprivate boolean showDetails = true;\n\n\tprivate @Nullable AdditionalHealthEndpointPath additionalPath;\n\n\tTestHealthEndpointGroup() {\n\t\tthis((name) -> true);\n\t}\n\n\tTestHealthEndpointGroup(Predicate<String> memberPredicate) {\n\t\tthis.memberPredicate = memberPredicate;\n\t}\n\n\t@Override\n\tpublic boolean isMember(String name) {\n\t\treturn this.memberPredicate.test(name);\n\t}\n\n\t@Override\n\tpublic boolean showComponents(SecurityContext securityContext) {\n\t\treturn (this.showComponents != null) ? this.showComponents : this.showDetails;\n\t}\n\n\tvoid setShowComponents(Boolean showComponents) {\n\t\tthis.showComponents = showComponents;\n\t}\n\n\t@Override\n\tpublic boolean showDetails(SecurityContext securityContext) {\n\t\treturn this.showDetails;\n\t}\n\n\tvoid setShowDetails(boolean includeDetails) {\n\t\tthis.showDetails = includeDetails;\n\t}\n\n\t@Override\n\tpublic StatusAggregator getStatusAggregator() {\n\t\treturn this.statusAggregator;\n\t}\n\n\t@Override\n\tpublic HttpCodeStatusMapper getHttpCodeStatusMapper() {\n\t\treturn this.httpCodeStatusMapper;\n\t}\n\n\t@Override\n\tpublic @Nullable AdditionalHealthEndpointPath getAdditionalPath() {\n\t\treturn this.additionalPath;\n\t}\n\n\tvoid setAdditionalPath(AdditionalHealthEndpointPath additionalPath) {\n\t\tthis.additionalPath = additionalPath;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/application/AvailabilityStateHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.AvailabilityState;\nimport org.springframework.boot.availability.LivenessState;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link AvailabilityStateHealthIndicator}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass AvailabilityStateHealthIndicatorTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationAvailability applicationAvailability;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenApplicationAvailabilityIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new AvailabilityStateHealthIndicator(null, LivenessState.class, (statusMappings) -> {\n\t\t\t}))\n\t\t\t.withMessage(\"'applicationAvailability' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenStateTypeIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(\n\t\t\t\t() -> new AvailabilityStateHealthIndicator(this.applicationAvailability, null, (statusMappings) -> {\n\t\t\t\t}))\n\t\t\t.withMessage(\"'stateType' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenStatusMappingIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> new AvailabilityStateHealthIndicator(this.applicationAvailability, LivenessState.class, null))\n\t\t\t.withMessage(\"'statusMappings' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenStatusMappingDoesNotCoverAllEnumsThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new AvailabilityStateHealthIndicator(this.applicationAvailability, LivenessState.class,\n\t\t\t\t\t(statusMappings) -> statusMappings.add(LivenessState.CORRECT, Status.UP)))\n\t\t\t.withMessage(\"StatusMappings does not include BROKEN\");\n\t}\n\n\t@Test\n\tvoid healthReturnsMappedStatus() {\n\t\tAvailabilityStateHealthIndicator indicator = new AvailabilityStateHealthIndicator(this.applicationAvailability,\n\t\t\t\tLivenessState.class, (statusMappings) -> {\n\t\t\t\t\tstatusMappings.add(LivenessState.CORRECT, Status.UP);\n\t\t\t\t\tstatusMappings.add(LivenessState.BROKEN, Status.DOWN);\n\t\t\t\t});\n\t\tgiven(this.applicationAvailability.getState(LivenessState.class)).willReturn(LivenessState.BROKEN);\n\t\tHealth health = indicator.health(false);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n\t@Test\n\tvoid healthReturnsDefaultStatus() {\n\t\tAvailabilityStateHealthIndicator indicator = new AvailabilityStateHealthIndicator(this.applicationAvailability,\n\t\t\t\tLivenessState.class, (statusMappings) -> {\n\t\t\t\t\tstatusMappings.add(LivenessState.CORRECT, Status.UP);\n\t\t\t\t\tstatusMappings.addDefaultStatus(Status.UNKNOWN);\n\t\t\t\t});\n\t\tgiven(this.applicationAvailability.getState(LivenessState.class)).willReturn(LivenessState.BROKEN);\n\t\tHealth health = indicator.health(false);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid healthWhenNotEnumReturnsMappedStatus() {\n\t\tAvailabilityStateHealthIndicator indicator = new AvailabilityStateHealthIndicator(this.applicationAvailability,\n\t\t\t\tTestAvailabilityState.class, (statusMappings) -> {\n\t\t\t\t\tstatusMappings.add(TestAvailabilityState.ONE, Status.UP);\n\t\t\t\t\tstatusMappings.addDefaultStatus(Status.DOWN);\n\t\t\t\t});\n\t\tgiven(this.applicationAvailability.getState(TestAvailabilityState.class)).willReturn(TestAvailabilityState.TWO);\n\t\tHealth health = indicator.health(false);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n\tstatic class TestAvailabilityState implements AvailabilityState {\n\n\t\tstatic final TestAvailabilityState ONE = new TestAvailabilityState();\n\n\t\tstatic final TestAvailabilityState TWO = new TestAvailabilityState();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/application/DiskSpaceHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link DiskSpaceHealthIndicator}.\n *\n * @author Mattias Severson\n * @author Stephane Nicoll\n */\n@ExtendWith(MockitoExtension.class)\nclass DiskSpaceHealthIndicatorTests {\n\n\tprivate static final DataSize THRESHOLD = DataSize.ofKilobytes(1);\n\n\tprivate static final DataSize TOTAL_SPACE = DataSize.ofKilobytes(10);\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate File fileMock;\n\n\tprivate HealthIndicator healthIndicator;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.healthIndicator = new DiskSpaceHealthIndicator(this.fileMock, THRESHOLD);\n\t}\n\n\t@Test\n\tvoid diskSpaceIsUp() {\n\t\tgiven(this.fileMock.exists()).willReturn(true);\n\t\tlong freeSpace = THRESHOLD.toBytes() + 10;\n\t\tgiven(this.fileMock.getUsableSpace()).willReturn(freeSpace);\n\t\tgiven(this.fileMock.getTotalSpace()).willReturn(TOTAL_SPACE.toBytes());\n\t\tgiven(this.fileMock.getAbsolutePath()).willReturn(\"/absolute-path\");\n\t\tHealth health = this.healthIndicator.health();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"threshold\", THRESHOLD.toBytes());\n\t\tassertThat(health.getDetails()).containsEntry(\"free\", freeSpace);\n\t\tassertThat(health.getDetails()).containsEntry(\"total\", TOTAL_SPACE.toBytes());\n\t\tassertThat(health.getDetails()).containsEntry(\"path\", \"/absolute-path\");\n\t\tassertThat(health.getDetails()).containsEntry(\"exists\", true);\n\t}\n\n\t@Test\n\tvoid diskSpaceIsDown() {\n\t\tgiven(this.fileMock.exists()).willReturn(true);\n\t\tlong freeSpace = THRESHOLD.toBytes() - 10;\n\t\tgiven(this.fileMock.getUsableSpace()).willReturn(freeSpace);\n\t\tgiven(this.fileMock.getTotalSpace()).willReturn(TOTAL_SPACE.toBytes());\n\t\tgiven(this.fileMock.getAbsolutePath()).willReturn(\"/absolute-path\");\n\t\tHealth health = this.healthIndicator.health();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"threshold\", THRESHOLD.toBytes());\n\t\tassertThat(health.getDetails()).containsEntry(\"free\", freeSpace);\n\t\tassertThat(health.getDetails()).containsEntry(\"total\", TOTAL_SPACE.toBytes());\n\t\tassertThat(health.getDetails()).containsEntry(\"path\", \"/absolute-path\");\n\t\tassertThat(health.getDetails()).containsEntry(\"exists\", true);\n\t}\n\n\t@Test\n\tvoid whenPathDoesNotExistDiskSpaceIsDown() {\n\t\tHealth health = new DiskSpaceHealthIndicator(new File(\"does/not/exist\"), THRESHOLD).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"free\", 0L);\n\t\tassertThat(health.getDetails()).containsEntry(\"total\", 0L);\n\t\tassertThat(health.getDetails()).containsEntry(\"exists\", false);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/application/LivenessStateHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.LivenessState;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LivenessStateHealthIndicator}\n *\n * @author Brian Clozel\n */\nclass LivenessStateHealthIndicatorTests {\n\n\tprivate ApplicationAvailability availability;\n\n\tprivate LivenessStateHealthIndicator healthIndicator;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.availability = mock(ApplicationAvailability.class);\n\t\tthis.healthIndicator = new LivenessStateHealthIndicator(this.availability);\n\t}\n\n\t@Test\n\tvoid livenessIsLive() {\n\t\tgiven(this.availability.getLivenessState()).willReturn(LivenessState.CORRECT);\n\t\tassertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid livenessIsBroken() {\n\t\tgiven(this.availability.getLivenessState()).willReturn(LivenessState.BROKEN);\n\t\tassertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.DOWN);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/application/ReadinessStateHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReadinessStateHealthIndicator}\n *\n * @author Brian Clozel\n */\nclass ReadinessStateHealthIndicatorTests {\n\n\tprivate ApplicationAvailability availability;\n\n\tprivate ReadinessStateHealthIndicator healthIndicator;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.availability = mock(ApplicationAvailability.class);\n\t\tthis.healthIndicator = new ReadinessStateHealthIndicator(this.availability);\n\t}\n\n\t@Test\n\tvoid readinessIsReady() {\n\t\tgiven(this.availability.getReadinessState()).willReturn(ReadinessState.ACCEPTING_TRAFFIC);\n\t\tassertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.UP);\n\t}\n\n\t@Test\n\tvoid readinessIsUnready() {\n\t\tgiven(this.availability.getReadinessState()).willReturn(ReadinessState.REFUSING_TRAFFIC);\n\t\tassertThat(this.healthIndicator.health().getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/application/SslHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.application;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.List;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.info.SslInfo.BundleInfo;\nimport org.springframework.boot.info.SslInfo.CertificateChainInfo;\nimport org.springframework.boot.info.SslInfo.CertificateInfo;\nimport org.springframework.boot.info.SslInfo.CertificateValidityInfo;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SslHealthIndicator}.\n *\n * @author Jonatan Ivanov\n */\nclass SslHealthIndicatorTests {\n\n\tprivate final CertificateInfo certificateInfo = mock(CertificateInfo.class);\n\n\tprivate final CertificateValidityInfo validity = mock(CertificateValidityInfo.class);\n\n\tprivate SslHealthIndicator healthIndicator;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tSslInfo sslInfo = mock(SslInfo.class);\n\t\tBundleInfo bundle = mock(BundleInfo.class);\n\t\tCertificateChainInfo certificateChain = mock(CertificateChainInfo.class);\n\t\tthis.healthIndicator = new SslHealthIndicator(sslInfo, Duration.ofDays(7));\n\t\tgiven(sslInfo.getBundles()).willReturn(List.of(bundle));\n\t\tgiven(bundle.getCertificateChains()).willReturn(List.of(certificateChain));\n\t\tgiven(certificateChain.getCertificates()).willReturn(List.of(this.certificateInfo));\n\t\tgiven(this.certificateInfo.getValidity()).willReturn(this.validity);\n\t}\n\n\t@Test\n\tvoid shouldBeUpIfNoSslIssuesDetected() {\n\t\tgiven(this.certificateInfo.getValidityEnds()).willReturn(Instant.now().plus(Duration.ofDays(365)));\n\t\tgiven(this.validity.getStatus()).willReturn(CertificateValidityInfo.Status.VALID);\n\t\tHealth health = this.healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertDetailsKeys(health);\n\t\tList<CertificateChainInfo> validChains = getValidChains(health);\n\t\tassertThat(validChains).hasSize(1);\n\t\tassertThat(validChains.get(0)).isInstanceOf(CertificateChainInfo.class);\n\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\tassertThat(invalidChains).isEmpty();\n\t}\n\n\t@Test\n\tvoid shouldBeOutOfServiceIfACertificateIsExpired() {\n\t\tgiven(this.validity.getStatus()).willReturn(CertificateValidityInfo.Status.EXPIRED);\n\t\tHealth health = this.healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t\tassertDetailsKeys(health);\n\t\tList<CertificateChainInfo> validChains = getValidChains(health);\n\t\tassertThat(validChains).isEmpty();\n\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\tassertThat(invalidChains).hasSize(1);\n\t\tassertThat(invalidChains.get(0)).isInstanceOf(CertificateChainInfo.class);\n\t}\n\n\t@Test\n\tvoid shouldBeOutOfServiceIfACertificateIsNotYetValid() {\n\t\tgiven(this.validity.getStatus()).willReturn(CertificateValidityInfo.Status.NOT_YET_VALID);\n\t\tHealth health = this.healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t\tassertDetailsKeys(health);\n\t\tList<CertificateChainInfo> validChains = getValidChains(health);\n\t\tassertThat(validChains).isEmpty();\n\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\tassertThat(invalidChains).hasSize(1);\n\t\tassertThat(invalidChains.get(0)).isInstanceOf(CertificateChainInfo.class);\n\n\t}\n\n\t@Test\n\tvoid shouldReportWarningIfACertificateWillExpireSoon() {\n\t\tgiven(this.validity.getStatus()).willReturn(CertificateValidityInfo.Status.VALID);\n\t\tgiven(this.certificateInfo.getValidityEnds()).willReturn(Instant.now().plus(Duration.ofDays(3)));\n\t\tHealth health = this.healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertDetailsKeys(health);\n\t\tList<CertificateChainInfo> expiring = getExpiringChains(health);\n\t\tassertThat(expiring).hasSize(1);\n\t\tassertThat(expiring.get(0)).isInstanceOf(CertificateChainInfo.class);\n\t\tList<CertificateChainInfo> validChains = getValidChains(health);\n\t\tassertThat(validChains).hasSize(1);\n\t\tassertThat(validChains.get(0)).isInstanceOf(CertificateChainInfo.class);\n\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\tassertThat(invalidChains).isEmpty();\n\t}\n\n\tprivate static void assertDetailsKeys(Health health) {\n\t\tassertThat(health.getDetails()).containsOnlyKeys(\"expiringChains\", \"validChains\", \"invalidChains\");\n\t}\n\n\tprivate static List<CertificateChainInfo> getExpiringChains(Health health) {\n\t\treturn getChains(health, \"expiringChains\");\n\t}\n\n\tprivate static List<CertificateChainInfo> getInvalidChains(Health health) {\n\t\treturn getChains(health, \"invalidChains\");\n\t}\n\n\tprivate static List<CertificateChainInfo> getValidChains(Health health) {\n\t\treturn getChains(health, \"validChains\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static List<CertificateChainInfo> getChains(Health health, String name) {\n\t\tObject details = health.getDetails().get(name);\n\t\tassertThat(details).isNotNull();\n\t\treturn (List<CertificateChainInfo>) details;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AutoConfiguredHealthEndpointGroupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.security.Principal;\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AutoConfiguredHealthEndpointGroup}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass AutoConfiguredHealthEndpointGroupTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate StatusAggregator statusAggregator;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate HttpCodeStatusMapper httpCodeStatusMapper;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate SecurityContext securityContext;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Principal principal;\n\n\t@Test\n\tvoid isMemberWhenMembershipMatchesAcceptsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> name.startsWith(\"a\"),\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);\n\t\tassertThat(group.isMember(\"albert\")).isTrue();\n\t\tassertThat(group.isMember(\"arnold\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isMemberWhenMembershipRejectsReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> name.startsWith(\"a\"),\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);\n\t\tassertThat(group.isMember(\"bert\")).isFalse();\n\t\tassertThat(group.isMember(\"ernie\")).isFalse();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsNeverReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.NEVER, Collections.emptySet(), null);\n\t\tassertThat(group.showDetails(SecurityContext.NONE)).isFalse();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsAlwaysReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);\n\t\tassertThat(group.showDetails(SecurityContext.NONE)).isTrue();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsWhenAuthorizedAndPrincipalIsNullReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED, Collections.emptySet(),\n\t\t\t\tnull);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(null);\n\t\tassertThat(group.showDetails(this.securityContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsWhenAuthorizedAndRolesAreEmptyReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED, Collections.emptySet(),\n\t\t\t\tnull);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(this.principal);\n\t\tassertThat(group.showDetails(this.securityContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsWhenAuthorizedAndUseIsInRoleReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,\n\t\t\t\tArrays.asList(\"admin\", \"root\", \"bossmode\"), null);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(this.principal);\n\t\tgiven(this.securityContext.isUserInRole(\"admin\")).willReturn(false);\n\t\tgiven(this.securityContext.isUserInRole(\"root\")).willReturn(true);\n\t\tassertThat(group.showDetails(this.securityContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsWhenAuthorizedAndUserIsNotInRoleReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,\n\t\t\t\tArrays.asList(\"admin\", \"root\", \"bossmode\"), null);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(this.principal);\n\t\tassertThat(group.showDetails(this.securityContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsWhenAuthorizedAndUserHasRightAuthorityReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,\n\t\t\t\tArrays.asList(\"admin\", \"root\", \"bossmode\"), null);\n\t\tAuthentication principal = mock(Authentication.class);\n\t\tgiven(principal.getAuthorities())\n\t\t\t.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(\"admin\")));\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(principal);\n\t\tassertThat(group.showDetails(this.securityContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid showDetailsWhenShowDetailsIsWhenAuthorizedAndUserDoesNotHaveRightAuthoritiesReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.WHEN_AUTHORIZED,\n\t\t\t\tArrays.asList(\"admin\", \"rot\", \"bossmode\"), null);\n\t\tAuthentication principal = mock(Authentication.class);\n\t\tgiven(principal.getAuthorities())\n\t\t\t.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(\"other\")));\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(principal);\n\t\tassertThat(group.showDetails(this.securityContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsNullDelegatesToShowDetails() {\n\t\tAutoConfiguredHealthEndpointGroup alwaysGroup = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);\n\t\tassertThat(alwaysGroup.showComponents(SecurityContext.NONE)).isTrue();\n\t\tAutoConfiguredHealthEndpointGroup neverGroup = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.NEVER, Collections.emptySet(), null);\n\t\tassertThat(neverGroup.showComponents(SecurityContext.NONE)).isFalse();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsNeverReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.NEVER, Show.ALWAYS, Collections.emptySet(),\n\t\t\t\tnull);\n\t\tassertThat(group.showComponents(SecurityContext.NONE)).isFalse();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsAlwaysReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.ALWAYS, Show.NEVER, Collections.emptySet(),\n\t\t\t\tnull);\n\t\tassertThat(group.showComponents(SecurityContext.NONE)).isTrue();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsWhenAuthorizedAndPrincipalIsNullReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,\n\t\t\t\tCollections.emptySet(), null);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(null);\n\t\tassertThat(group.showComponents(this.securityContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsWhenAuthorizedAndRolesAreEmptyReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,\n\t\t\t\tCollections.emptySet(), null);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(this.principal);\n\t\tassertThat(group.showComponents(this.securityContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsWhenAuthorizedAndUseIsInRoleReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,\n\t\t\t\tArrays.asList(\"admin\", \"root\", \"bossmode\"), null);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(this.principal);\n\t\tgiven(this.securityContext.isUserInRole(\"admin\")).willReturn(false);\n\t\tgiven(this.securityContext.isUserInRole(\"root\")).willReturn(true);\n\t\tassertThat(group.showComponents(this.securityContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsWhenAuthorizedAndUserIsNotInRoleReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,\n\t\t\t\tArrays.asList(\"admin\", \"rot\", \"bossmode\"), null);\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(this.principal);\n\t\tassertThat(group.showComponents(this.securityContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsWhenAuthorizedAndUserHasRightAuthoritiesReturnsTrue() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,\n\t\t\t\tArrays.asList(\"admin\", \"root\", \"bossmode\"), null);\n\t\tAuthentication principal = mock(Authentication.class);\n\t\tgiven(principal.getAuthorities())\n\t\t\t.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(\"admin\")));\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(principal);\n\t\tassertThat(group.showComponents(this.securityContext)).isTrue();\n\t}\n\n\t@Test\n\tvoid showComponentsWhenShowComponentsIsWhenAuthorizedAndUserDoesNotHaveRightAuthoritiesReturnsFalse() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, Show.WHEN_AUTHORIZED, Show.NEVER,\n\t\t\t\tArrays.asList(\"admin\", \"rot\", \"bossmode\"), null);\n\t\tAuthentication principal = mock(Authentication.class);\n\t\tgiven(principal.getAuthorities())\n\t\t\t.willAnswer((invocation) -> Collections.singleton(new SimpleGrantedAuthority(\"other\")));\n\t\tgiven(this.securityContext.getPrincipal()).willReturn(principal);\n\t\tassertThat(group.showComponents(this.securityContext)).isFalse();\n\t}\n\n\t@Test\n\tvoid getStatusAggregatorReturnsStatusAggregator() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);\n\t\tassertThat(group.getStatusAggregator()).isSameAs(this.statusAggregator);\n\t}\n\n\t@Test\n\tvoid getHttpCodeStatusMapperReturnsHttpCodeStatusMapper() {\n\t\tAutoConfiguredHealthEndpointGroup group = new AutoConfiguredHealthEndpointGroup((name) -> true,\n\t\t\t\tthis.statusAggregator, this.httpCodeStatusMapper, null, Show.ALWAYS, Collections.emptySet(), null);\n\t\tassertThat(group.getHttpCodeStatusMapper()).isSameAs(this.httpCodeStatusMapper);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AutoConfiguredHealthEndpointGroupsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfiguredHealthEndpointGroups}.\n *\n * @author Phillip Webb\n * @author Leo Li\n */\nclass AutoConfiguredHealthEndpointGroupsTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AutoConfiguredHealthEndpointGroupsTestConfiguration.class));\n\n\t@Test\n\tvoid getPrimaryGroupMatchesAllMembers() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\tassertThat(primary.isMember(\"a\")).isTrue();\n\t\t\tassertThat(primary.isMember(\"b\")).isTrue();\n\t\t\tassertThat(primary.isMember(\"C\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getNamesReturnsGroupNames() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tassertThat(groups.getNames()).containsExactlyInAnyOrder(\"a\", \"b\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid getGroupWhenGroupExistsReturnsGroup() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.group.a.include=*\").run((context) -> {\n\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\tHealthEndpointGroup group = groups.get(\"a\");\n\t\t\tassertThat(group).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getGroupWhenGroupDoesNotExistReturnsNull() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.group.a.include=*\").run((context) -> {\n\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\tHealthEndpointGroup group = groups.get(\"b\");\n\t\t\tassertThat(group).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenNoDefinedBeansAdaptsProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.show-components=always\",\n\t\t\t\t\t\"management.endpoint.health.show-details=never\", \"management.endpoint.health.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.status.http-mapping.down=200\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tassertThat(primary.showComponents(SecurityContext.NONE)).isTrue();\n\t\t\t\tassertThat(primary.showDetails(SecurityContext.NONE)).isFalse();\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorBeanReturnsInstanceWithAggregatorUsedForAllGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorBeanAndGroupSpecificPropertyReturnsInstanceThatUsesBeanOnlyForUnconfiguredGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorPropertyReturnsInstanceWithPropertyUsedForAllGroups() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorPropertyAndGroupSpecificPropertyReturnsInstanceWithPropertyUsedForExpectedGroups() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.order=unknown,up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasStatusAggregatorPropertyAndGroupQualifiedBeanReturnsInstanceWithBeanUsedForExpectedGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorGroupAConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasGroupSpecificStatusAggregatorPropertyAndGroupQualifiedBeanReturnsInstanceWithBeanUsedForExpectedGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomStatusAggregatorGroupAConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.order=up,down\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.b.status.order=up,down\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.DOWN);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UNKNOWN);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getStatusAggregator().getAggregateStatus(Status.UP, Status.DOWN, Status.UNKNOWN))\n\t\t\t\t\t.isEqualTo(Status.UP);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasHttpCodeStatusMapperBeanReturnsInstanceWithMapperUsedForAllGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpCodeStatusMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasHttpCodeStatusMapperBeanAndGroupSpecificPropertyReturnsInstanceThatUsesBeanOnlyForUnconfiguredGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpCodeStatusMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasHttpCodeStatusMapperPropertyReturnsInstanceWithPropertyUsedForAllGroups() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasHttpCodeStatusMapperPropertyAndGroupSpecificPropertyReturnsInstanceWithPropertyUsedForExpectedGroups() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.http-mapping.down=202\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(202);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasHttpCodeStatusMapperPropertyAndGroupQualifiedBeanReturnsInstanceWithBeanUsedForExpectedGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpCodeStatusMapperGroupAConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenHasGroupSpecificHttpCodeStatusMapperPropertyAndGroupQualifiedBeanReturnsInstanceWithBeanUsedForExpectedGroups() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpCodeStatusMapperGroupAConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.a.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.a.status.http-mapping.down=201\",\n\t\t\t\t\t\"management.endpoint.health.group.b.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.b.status.http-mapping.down=201\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup primary = groups.getPrimary();\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tHealthEndpointGroup groupB = groups.get(\"b\");\n\t\t\t\tassertThat(primary.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(503);\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(200);\n\t\t\t\tassertThat(groupB).isNotNull();\n\t\t\t\tassertThat(groupB.getHttpCodeStatusMapper().getStatusCode(Status.DOWN)).isEqualTo(201);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createWhenGroupWithNoShowDetailsOverrideInheritsShowDetails() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.show-details=always\",\n\t\t\t\t\t\"management.endpoint.health.group.a.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tHealthEndpointGroup groupA = groups.get(\"a\");\n\t\t\t\tassertThat(groupA).isNotNull();\n\t\t\t\tassertThat(groupA.showDetails(SecurityContext.NONE)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid getAdditionalPathsReturnsAllAdditionalPaths() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.a.additional-path=server:/a\",\n\t\t\t\t\t\"management.endpoint.health.group.b.additional-path=server:/b\",\n\t\t\t\t\t\"management.endpoint.health.group.c.additional-path=management:/c\",\n\t\t\t\t\t\"management.endpoint.health.group.d.additional-path=management:/d\")\n\t\t\t.run((context) -> {\n\t\t\t\tAdditionalPathsMapper additionalPathsMapper = context.getBean(AdditionalPathsMapper.class);\n\t\t\t\tassertThat(additionalPathsMapper.getAdditionalPaths(HealthEndpoint.ID, WebServerNamespace.SERVER))\n\t\t\t\t\t.containsExactlyInAnyOrder(\"/a\", \"/b\");\n\t\t\t\tassertThat(additionalPathsMapper.getAdditionalPaths(HealthEndpoint.ID, WebServerNamespace.MANAGEMENT))\n\t\t\t\t\t.containsExactlyInAnyOrder(\"/c\", \"/d\");\n\t\t\t\tassertThat(additionalPathsMapper.getAdditionalPaths(EndpointId.of(\"other\"), WebServerNamespace.SERVER))\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(HealthEndpointProperties.class)\n\tstatic class AutoConfiguredHealthEndpointGroupsTestConfiguration {\n\n\t\t@Bean\n\t\tAutoConfiguredHealthEndpointGroups healthEndpointGroups(ConfigurableApplicationContext applicationContext,\n\t\t\t\tHealthEndpointProperties properties) {\n\t\t\treturn new AutoConfiguredHealthEndpointGroups(applicationContext, properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomStatusAggregatorConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tStatusAggregator statusAggregator() {\n\t\t\treturn StatusAggregator.of(Status.UNKNOWN, Status.UP, Status.DOWN);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomStatusAggregatorGroupAConfiguration {\n\n\t\t@Bean\n\t\t@Qualifier(\"a\")\n\t\tStatusAggregator statusAggregator() {\n\t\t\treturn StatusAggregator.of(Status.UNKNOWN, Status.UP, Status.DOWN);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHttpCodeStatusMapperConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tHttpCodeStatusMapper httpCodeStatusMapper() {\n\t\t\treturn HttpCodeStatusMapper.of(Collections.singletonMap(Status.DOWN.getCode(), 200));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHttpCodeStatusMapperGroupAConfiguration {\n\n\t\t@Bean\n\t\t@Qualifier(\"a\")\n\t\tHttpCodeStatusMapper httpCodeStatusMapper() {\n\t\t\treturn HttpCodeStatusMapper.of(Collections.singletonMap(Status.DOWN.getCode(), 200));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.health.application.LivenessStateHealthIndicator;\nimport org.springframework.boot.health.application.ReadinessStateHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.application.AvailabilityHealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AvailabilityProbesAutoConfiguration}.\n *\n * @author Brian Clozel\n */\nclass AvailabilityProbesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ApplicationAvailabilityAutoConfiguration.class,\n\t\t\t\tAvailabilityHealthContributorAutoConfiguration.class, AvailabilityProbesAutoConfiguration.class));\n\n\t@Test\n\tvoid probesWhenDefaultAddsBeans() {\n\t\tthis.contextRunner.run(this::hasProbesBeans);\n\t}\n\n\t@Test\n\tvoid probesWhenPropertyEnabledAddsBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.probes.enabled=true\")\n\t\t\t.run(this::hasProbesBeans);\n\t}\n\n\t@Test\n\tvoid probesWhenNoActuatorDependencyDoesNotAddBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Endpoint.class.getName()))\n\t\t\t.run(this::doesNotHaveProbeBeans);\n\t}\n\n\t@Test\n\tvoid probesWhenPropertyDisabledDoesNotAddBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.probes.enabled=false\")\n\t\t\t.run(this::doesNotHaveProbeBeans);\n\t}\n\n\tprivate void hasProbesBeans(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t.hasSingleBean(LivenessStateHealthIndicator.class)\n\t\t\t.hasBean(\"livenessStateHealthIndicator\")\n\t\t\t.hasSingleBean(ReadinessStateHealthIndicator.class)\n\t\t\t.hasBean(\"readinessStateHealthIndicator\")\n\t\t\t.hasSingleBean(AvailabilityProbesHealthEndpointGroupsPostProcessor.class);\n\t}\n\n\tprivate void doesNotHaveProbeBeans(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t.doesNotHaveBean(LivenessStateHealthIndicator.class)\n\t\t\t.doesNotHaveBean(ReadinessStateHealthIndicator.class)\n\t\t\t.doesNotHaveBean(AvailabilityProbesHealthEndpointGroupsPostProcessor.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesHealthEndpointGroupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AvailabilityProbesHealthEndpointGroup}.\n *\n * @author Phillip Webb\n */\nclass AvailabilityProbesHealthEndpointGroupTests {\n\n\tprivate final AvailabilityProbesHealthEndpointGroup group = new AvailabilityProbesHealthEndpointGroup(null, \"a\",\n\t\t\t\"b\");\n\n\t@Test\n\tvoid isMemberWhenMemberReturnsTrue() {\n\t\tassertThat(this.group.isMember(\"a\")).isTrue();\n\t\tassertThat(this.group.isMember(\"b\")).isTrue();\n\t}\n\n\t@Test\n\tvoid isMemberWhenNotMemberReturnsFalse() {\n\t\tassertThat(this.group.isMember(\"c\")).isFalse();\n\t}\n\n\t@Test\n\tvoid showComponentsReturnsFalse() {\n\t\tassertThat(this.group.showComponents(mock(SecurityContext.class))).isFalse();\n\t}\n\n\t@Test\n\tvoid showDetailsReturnsFalse() {\n\t\tassertThat(this.group.showDetails(mock(SecurityContext.class))).isFalse();\n\t}\n\n\t@Test\n\tvoid getStatusAggregatorReturnsDefaultStatusAggregator() {\n\t\tassertThat(this.group.getStatusAggregator()).isEqualTo(StatusAggregator.getDefault());\n\t}\n\n\t@Test\n\tvoid getHttpCodeStatusMapperReturnsDefaultHttpCodeStatusMapper() {\n\t\tassertThat(this.group.getHttpCodeStatusMapper()).isEqualTo(HttpCodeStatusMapper.getDefault());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesHealthEndpointGroupsPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.web.AdditionalPathsMapper;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AvailabilityProbesHealthEndpointGroupsPostProcessor}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AvailabilityProbesHealthEndpointGroupsPostProcessorTests {\n\n\tprivate final AvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(\n\t\t\tnew MockEnvironment());\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenGroupsAlreadyContainedReturnsOriginal() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\tSet<String> names = new LinkedHashSet<>();\n\t\tnames.add(\"test\");\n\t\tnames.add(\"readiness\");\n\t\tnames.add(\"liveness\");\n\t\tgiven(groups.getNames()).willReturn(names);\n\t\tassertThat(this.postProcessor.postProcessHealthEndpointGroups(groups))\n\t\t\t.isInstanceOf(AvailabilityProbesHealthEndpointGroups.class);\n\t}\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenGroupContainsOneReturnsPostProcessed() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\tSet<String> names = new LinkedHashSet<>();\n\t\tnames.add(\"test\");\n\t\tnames.add(\"readiness\");\n\t\tgiven(groups.getNames()).willReturn(names);\n\t\tassertThat(this.postProcessor.postProcessHealthEndpointGroups(groups))\n\t\t\t.isInstanceOf(AvailabilityProbesHealthEndpointGroups.class);\n\t}\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenGroupsContainsNoneReturnsProcessed() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\tSet<String> names = new LinkedHashSet<>();\n\t\tnames.add(\"test\");\n\t\tnames.add(\"spring\");\n\t\tnames.add(\"boot\");\n\t\tgiven(groups.getNames()).willReturn(names);\n\t\tassertThat(this.postProcessor.postProcessHealthEndpointGroups(groups))\n\t\t\t.isInstanceOf(AvailabilityProbesHealthEndpointGroups.class);\n\t}\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsTrue() {\n\t\tHealthEndpointGroups postProcessed = getPostProcessed(\"true\");\n\t\tHealthEndpointGroup liveness = postProcessed.get(\"liveness\");\n\t\tassertThat(liveness).isNotNull();\n\t\tHealthEndpointGroup readiness = postProcessed.get(\"readiness\");\n\t\tassertThat(readiness).isNotNull();\n\t\tassertThat(liveness.getAdditionalPath()).hasToString(\"server:/livez\");\n\t\tassertThat(readiness.getAdditionalPath()).hasToString(\"server:/readyz\");\n\t}\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenGroupsAlreadyContainedAndAdditionalPathPropertyIsTrue() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\tSet<String> names = new LinkedHashSet<>();\n\t\tnames.add(\"test\");\n\t\tnames.add(\"readiness\");\n\t\tnames.add(\"liveness\");\n\t\tgiven(groups.getNames()).willReturn(names);\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"management.endpoint.health.probes.add-additional-paths\", \"true\");\n\t\tAvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(\n\t\t\t\tenvironment);\n\t\tHealthEndpointGroups postProcessed = postProcessor.postProcessHealthEndpointGroups(groups);\n\t\tHealthEndpointGroup liveness = postProcessed.get(\"liveness\");\n\t\tassertThat(liveness).isNotNull();\n\t\tHealthEndpointGroup readiness = postProcessed.get(\"readiness\");\n\t\tassertThat(readiness).isNotNull();\n\t\tassertThat(liveness.getAdditionalPath()).hasToString(\"server:/livez\");\n\t\tassertThat(readiness.getAdditionalPath()).hasToString(\"server:/readyz\");\n\t}\n\n\t@Test\n\tvoid delegatesAdditionalPathMappingToOriginalBean() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class,\n\t\t\t\tMockito.withSettings().extraInterfaces(AdditionalPathsMapper.class));\n\t\tgiven(((AdditionalPathsMapper) groups).getAdditionalPaths(EndpointId.of(\"health\"), WebServerNamespace.SERVER))\n\t\t\t.willReturn(List.of(\"/one\", \"/two\", \"/three\"));\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tAvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(\n\t\t\t\tenvironment);\n\t\tHealthEndpointGroups postProcessed = postProcessor.postProcessHealthEndpointGroups(groups);\n\t\tassertThat(postProcessed).isInstanceOf(AdditionalPathsMapper.class);\n\t\tAdditionalPathsMapper additionalPathsMapper = (AdditionalPathsMapper) postProcessed;\n\t\tassertThat(additionalPathsMapper.getAdditionalPaths(EndpointId.of(\"health\"), WebServerNamespace.SERVER))\n\t\t\t.containsExactly(\"/one\", \"/two\", \"/three\");\n\t}\n\n\t@Test\n\tvoid whenAddAdditionalPathsIsTrueThenIncludesOwnAdditionalPathsInGetAdditionalPathsResult() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class,\n\t\t\t\tMockito.withSettings().extraInterfaces(AdditionalPathsMapper.class));\n\t\tgiven(((AdditionalPathsMapper) groups).getAdditionalPaths(EndpointId.of(\"health\"), WebServerNamespace.SERVER))\n\t\t\t.willReturn(List.of(\"/one\", \"/two\", \"/three\"));\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"management.endpoint.health.probes.add-additional-paths\", \"true\");\n\t\tAvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(\n\t\t\t\tenvironment);\n\t\tHealthEndpointGroups postProcessed = postProcessor.postProcessHealthEndpointGroups(groups);\n\t\tassertThat(postProcessed).isInstanceOf(AdditionalPathsMapper.class);\n\t\tAdditionalPathsMapper additionalPathsMapper = (AdditionalPathsMapper) postProcessed;\n\t\tassertThat(additionalPathsMapper.getAdditionalPaths(EndpointId.of(\"health\"), WebServerNamespace.SERVER))\n\t\t\t.containsExactly(\"/one\", \"/two\", \"/three\", \"/livez\", \"/readyz\");\n\t}\n\n\tprivate HealthEndpointGroups getPostProcessed(String value) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"management.endpoint.health.probes.add-additional-paths\", value);\n\t\tAvailabilityProbesHealthEndpointGroupsPostProcessor postProcessor = new AvailabilityProbesHealthEndpointGroupsPostProcessor(\n\t\t\t\tenvironment);\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\treturn postProcessor.postProcessHealthEndpointGroups(groups);\n\t}\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsFalse() {\n\t\tHealthEndpointGroups postProcessed = getPostProcessed(\"false\");\n\t\tHealthEndpointGroup liveness = postProcessed.get(\"liveness\");\n\t\tassertThat(liveness).isNotNull();\n\t\tHealthEndpointGroup readiness = postProcessed.get(\"readiness\");\n\t\tassertThat(readiness).isNotNull();\n\t\tassertThat(liveness.getAdditionalPath()).isNull();\n\t\tassertThat(readiness.getAdditionalPath()).isNull();\n\t}\n\n\t@Test\n\tvoid postProcessHealthEndpointGroupsWhenAdditionalPathPropertyIsNull() {\n\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\tHealthEndpointGroups postProcessed = this.postProcessor.postProcessHealthEndpointGroups(groups);\n\t\tHealthEndpointGroup liveness = postProcessed.get(\"liveness\");\n\t\tassertThat(liveness).isNotNull();\n\t\tHealthEndpointGroup readiness = postProcessed.get(\"readiness\");\n\t\tassertThat(readiness).isNotNull();\n\t\tassertThat(liveness.getAdditionalPath()).isNull();\n\t\tassertThat(readiness.getAdditionalPath()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/AvailabilityProbesHealthEndpointGroupsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AvailabilityProbesHealthEndpointGroups}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass AvailabilityProbesHealthEndpointGroupsTests {\n\n\tprivate HealthEndpointGroups delegate;\n\n\tprivate HealthEndpointGroup group;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.delegate = mock(HealthEndpointGroups.class);\n\t\tthis.group = mock(HealthEndpointGroup.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenGroupsIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new AvailabilityProbesHealthEndpointGroups(null, false))\n\t\t\t.withMessage(\"'groups' must not be null\");\n\t}\n\n\t@Test\n\tvoid getPrimaryDelegatesToGroups() {\n\t\tgiven(this.delegate.getPrimary()).willReturn(this.group);\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tassertThat(availabilityProbes.getPrimary()).isEqualTo(this.group);\n\t}\n\n\t@Test\n\tvoid getNamesIncludesAvailabilityProbeGroups() {\n\t\tgiven(this.delegate.getNames()).willReturn(Collections.singleton(\"test\"));\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tassertThat(availabilityProbes.getNames()).containsExactly(\"test\", \"liveness\", \"readiness\");\n\t}\n\n\t@Test\n\tvoid getWhenProbeInDelegateReturnsOriginalGroup() {\n\t\tHealthEndpointGroup group = mock(HealthEndpointGroup.class);\n\t\tHttpCodeStatusMapper mapper = mock(HttpCodeStatusMapper.class);\n\t\tgiven(group.getHttpCodeStatusMapper()).willReturn(mapper);\n\t\tgiven(this.delegate.get(\"liveness\")).willReturn(group);\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tassertThat(availabilityProbes.get(\"liveness\")).isEqualTo(group);\n\t\tassertThat(group.getHttpCodeStatusMapper()).isEqualTo(mapper);\n\t}\n\n\t@Test\n\tvoid getWhenProbeInDelegateAndExistingAdditionalPathReturnsOriginalGroup() {\n\t\tHealthEndpointGroup group = mock(HealthEndpointGroup.class);\n\t\tgiven(group.getAdditionalPath()).willReturn(AdditionalHealthEndpointPath.from(\"server:test\"));\n\t\tgiven(this.delegate.get(\"liveness\")).willReturn(group);\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, true);\n\t\tHealthEndpointGroup liveness = availabilityProbes.get(\"liveness\");\n\t\tassertThat(liveness).isNotNull();\n\t\tassertThat(liveness).isEqualTo(group);\n\t\tAdditionalHealthEndpointPath additionalPath = liveness.getAdditionalPath();\n\t\tassertThat(additionalPath).isNotNull();\n\t\tassertThat(additionalPath.getValue()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid getWhenProbeInDelegateAndAdditionalPathReturnsGroupWithAdditionalPath() {\n\t\tgiven(this.delegate.get(\"liveness\")).willReturn(this.group);\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, true);\n\t\tHealthEndpointGroup liveness = availabilityProbes.get(\"liveness\");\n\t\tassertThat(liveness).isNotNull();\n\t\tAdditionalHealthEndpointPath additionalPath = liveness.getAdditionalPath();\n\t\tassertThat(additionalPath).isNotNull();\n\t\tassertThat(additionalPath.getValue()).isEqualTo(\"/livez\");\n\t}\n\n\t@Test\n\tvoid getWhenProbeNotInDelegateReturnsProbeGroup() {\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tassertThat(availabilityProbes.get(\"liveness\")).isInstanceOf(AvailabilityProbesHealthEndpointGroup.class);\n\t}\n\n\t@Test\n\tvoid getWhenNotProbeAndNotInDelegateReturnsNull() {\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tassertThat(availabilityProbes.get(\"mygroup\")).isNull();\n\t}\n\n\t@Test\n\tvoid getLivenessProbeHasOnlyLivenessStateAsMember() {\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tHealthEndpointGroup probeGroup = availabilityProbes.get(\"liveness\");\n\t\tassertThat(probeGroup).isNotNull();\n\t\tassertThat(probeGroup.isMember(\"livenessState\")).isTrue();\n\t\tassertThat(probeGroup.isMember(\"readinessState\")).isFalse();\n\t}\n\n\t@Test\n\tvoid getReadinessProbeHasOnlyReadinessStateAsMember() {\n\t\tHealthEndpointGroups availabilityProbes = new AvailabilityProbesHealthEndpointGroups(this.delegate, false);\n\t\tHealthEndpointGroup probeGroup = availabilityProbes.get(\"readiness\");\n\t\tassertThat(probeGroup).isNotNull();\n\t\tassertThat(probeGroup.isMember(\"livenessState\")).isFalse();\n\t\tassertThat(probeGroup.isMember(\"readinessState\")).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/DelegatingAvailabilityProbesHealthEndpointGroupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DelegatingAvailabilityProbesHealthEndpointGroup}.\n *\n * @author Madhura Bhave\n */\nclass DelegatingAvailabilityProbesHealthEndpointGroupTests {\n\n\tprivate DelegatingAvailabilityProbesHealthEndpointGroup group;\n\n\tprivate HttpCodeStatusMapper mapper;\n\n\tprivate StatusAggregator aggregator;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tHealthEndpointGroup delegate = mock(HealthEndpointGroup.class);\n\t\tthis.mapper = mock(HttpCodeStatusMapper.class);\n\t\tthis.aggregator = mock(StatusAggregator.class);\n\t\tgiven(delegate.getHttpCodeStatusMapper()).willReturn(this.mapper);\n\t\tgiven(delegate.getStatusAggregator()).willReturn(this.aggregator);\n\t\tgiven(delegate.showComponents(any())).willReturn(true);\n\t\tgiven(delegate.showDetails(any())).willReturn(false);\n\t\tgiven(delegate.isMember(\"test\")).willReturn(true);\n\t\tthis.group = new DelegatingAvailabilityProbesHealthEndpointGroup(delegate,\n\t\t\t\tAdditionalHealthEndpointPath.from(\"server:test\"));\n\t}\n\n\t@Test\n\tvoid groupDelegatesToDelegate() {\n\t\tassertThat(this.group.getHttpCodeStatusMapper()).isEqualTo(this.mapper);\n\t\tassertThat(this.group.getStatusAggregator()).isEqualTo(this.aggregator);\n\t\tassertThat(this.group.isMember(\"test\")).isTrue();\n\t\tassertThat(this.group.showDetails(SecurityContext.NONE)).isFalse();\n\t\tassertThat(this.group.showComponents(SecurityContext.NONE)).isTrue();\n\t\tassertThat(this.group.getAdditionalPath().getValue()).isEqualTo(\"test\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/actuate/endpoint/HealthEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.ApiVersion;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.diagnostics.FailureAnalyzedException;\nimport org.springframework.boot.health.actuate.endpoint.CompositeHealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.HealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroupsPostProcessor;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.health.actuate.endpoint.HttpCodeStatusMapper;\nimport org.springframework.boot.health.actuate.endpoint.IndicatedHealthDescriptor;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\nimport org.springframework.boot.health.actuate.endpoint.StatusAggregator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HealthEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass HealthEndpointAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\tprivate final ReactiveWebApplicationContextRunner reactiveContextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runWhenHealthEndpointIsDisabledDoesNotCreateBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(StatusAggregator.class);\n\t\t\tassertThat(context).doesNotHaveBean(HttpCodeStatusMapper.class);\n\t\t\tassertThat(context).doesNotHaveBean(HealthEndpointGroups.class);\n\t\t\tassertThat(context).doesNotHaveBean(HealthEndpoint.class);\n\t\t\tassertThat(context).doesNotHaveBean(HealthEndpointWebExtension.class);\n\t\t\tassertThat(context).doesNotHaveBean(ReactiveHealthEndpointWebExtension.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesStatusAggregatorFromProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.status.order=up,down\").run((context) -> {\n\t\t\tStatusAggregator aggregator = context.getBean(StatusAggregator.class);\n\t\t\tassertThat(aggregator.getAggregateStatus(Status.UP, Status.DOWN)).isEqualTo(Status.UP);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasStatusAggregatorBeanIgnoresProperties() {\n\t\tthis.contextRunner.withUserConfiguration(StatusAggregatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.order=up,down\")\n\t\t\t.run((context) -> {\n\t\t\t\tStatusAggregator aggregator = context.getBean(StatusAggregator.class);\n\t\t\t\tassertThat(aggregator.getAggregateStatus(Status.UP, Status.DOWN)).isEqualTo(Status.UNKNOWN);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesHttpCodeStatusMapperFromProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.status.http-mapping.up=123\")\n\t\t\t.run((context) -> {\n\t\t\t\tHttpCodeStatusMapper mapper = context.getBean(HttpCodeStatusMapper.class);\n\t\t\t\tassertThat(mapper.getStatusCode(Status.UP)).isEqualTo(123);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHttpCodeStatusMapperBeanIgnoresProperties() {\n\t\tthis.contextRunner.withUserConfiguration(HttpCodeStatusMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.status.http-mapping.up=123\")\n\t\t\t.run((context) -> {\n\t\t\t\tHttpCodeStatusMapper mapper = context.getBean(HttpCodeStatusMapper.class);\n\t\t\t\tassertThat(mapper.getStatusCode(Status.UP)).isEqualTo(456);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesHealthEndpointGroups() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.group.ready.include=*\").run((context) -> {\n\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\tassertThat(groups).isInstanceOf(AutoConfiguredHealthEndpointGroups.class);\n\t\t\tassertThat(groups.getNames()).containsOnly(\"ready\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runDoesNotFailWhenHealthEndpointGroupIncludesContributorThatExists() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.ready.include=composite/b/c\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test // gh-48387\n\tvoid runDoesNotFailWhenHealthEndpointGroupIncludesReactiveContributorThatExists() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeReactiveHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.ready.include=composite/b/c\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid runFailsWhenHealthEndpointGroupIncludesContributorThatDoesNotExist() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.ready.include=composite/b/c,nope\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(FailureAnalyzedException.class)\n\t\t\t\t\t.hasMessage(\"Health contributor 'nope' defined in \"\n\t\t\t\t\t\t\t+ \"'management.endpoint.health.group.ready.include' does not exist\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runFailsWhenHealthEndpointGroupExcludesContributorThatDoesNotExist() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.ready.exclude=composite/b/d\",\n\t\t\t\t\t\"management.endpoint.health.group.ready.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(FailureAnalyzedException.class)\n\t\t\t\t\t.hasMessage(\"Health contributor 'composite/b/d' defined in \"\n\t\t\t\t\t\t\t+ \"'management.endpoint.health.group.ready.exclude' does not exist\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesHealthEndpointGroupThatIncludesContributorThatDoesNotExistWhenValidationIsDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.validate-group-membership=false\",\n\t\t\t\t\t\"management.endpoint.health.group.ready.include=nope\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tassertThat(groups).isInstanceOf(AutoConfiguredHealthEndpointGroups.class);\n\t\t\t\tassertThat(groups.getNames()).containsOnly(\"ready\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHealthEndpointGroupsBeanDoesNotCreateAdditionalHealthEndpointGroups() {\n\t\tthis.contextRunner.withUserConfiguration(HealthEndpointGroupsConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.ready.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tassertThat(groups.getNames()).containsOnly(\"mock\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesHealthContributorRegistryContainingHealthBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).containsExactlyInAnyOrder(\"simple\", \"additional\", \"ping\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenNoReactorCreatesHealthContributorRegistryContainingHealthBeans() {\n\t\tClassLoader classLoader = new FilteredClassLoader(Mono.class, Flux.class);\n\t\tthis.contextRunner.withClassLoader(classLoader).run((context) -> {\n\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).containsExactlyInAnyOrder(\"simple\", \"additional\", \"ping\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHealthContributorRegistryBeanDoesNotCreateAdditionalRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(HealthContributorRegistryConfiguration.class).run((context) -> {\n\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesHealthEndpoint() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.show-details=always\").run((context) -> {\n\t\t\tHealthEndpoint endpoint = context.getBean(HealthEndpoint.class);\n\t\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) endpoint.healthForPath(\"simple\");\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getDetails()).containsEntry(\"counter\", 42);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHealthEndpointBeanDoesNotCreateAdditionalHealthEndpoint() {\n\t\tthis.contextRunner.withUserConfiguration(HealthEndpointConfiguration.class).run((context) -> {\n\t\t\tHealthEndpoint endpoint = context.getBean(HealthEndpoint.class);\n\t\t\tassertThat(endpoint.health()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesReactiveHealthContributorRegistryContainingReactiveHealthBeans() {\n\t\tthis.reactiveContextRunner.run((context) -> {\n\t\t\tReactiveHealthContributorRegistry reactiveRegistry = context\n\t\t\t\t.getBean(ReactiveHealthContributorRegistry.class);\n\t\t\tObject[] names = reactiveRegistry.stream().map(ReactiveHealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).containsExactlyInAnyOrder(\"reactive\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasReactiveHealthContributorRegistryBeanDoesNotCreateAdditionalReactiveHealthContributorRegistry() {\n\t\tthis.reactiveContextRunner.withUserConfiguration(ReactiveHealthContributorRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveHealthContributorRegistry registry = context.getBean(ReactiveHealthContributorRegistry.class);\n\t\t\t\tObject[] names = registry.stream().map(ReactiveHealthContributors.Entry::name).toArray();\n\t\t\t\tassertThat(names).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesHealthEndpointWebExtension() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHealthEndpointWebExtension webExtension = context.getBean(HealthEndpointWebExtension.class);\n\t\t\tWebEndpointResponse<HealthDescriptor> response = webExtension.health(ApiVersion.V3,\n\t\t\t\t\tWebServerNamespace.SERVER, SecurityContext.NONE, true, \"simple\");\n\t\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) response.getBody();\n\t\t\tassertThat(response.getStatus()).isEqualTo(200);\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getDetails()).containsEntry(\"counter\", 42);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHealthEndpointWebExtensionBeanDoesNotCreateExtraHealthEndpointWebExtension() {\n\t\tthis.contextRunner.withUserConfiguration(HealthEndpointWebExtensionConfiguration.class).run((context) -> {\n\t\t\tHealthEndpointWebExtension webExtension = context.getBean(HealthEndpointWebExtension.class);\n\t\t\tWebEndpointResponse<HealthDescriptor> response = webExtension.health(ApiVersion.V3,\n\t\t\t\t\tWebServerNamespace.SERVER, SecurityContext.NONE, true, \"simple\");\n\t\t\tassertThat(response).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid runCreatesReactiveHealthEndpointWebExtension() {\n\t\tthis.reactiveContextRunner.run((context) -> {\n\t\t\tReactiveHealthEndpointWebExtension webExtension = context.getBean(ReactiveHealthEndpointWebExtension.class);\n\t\t\tMono<WebEndpointResponse<? extends HealthDescriptor>> responseMono = webExtension.health(ApiVersion.V3,\n\t\t\t\t\tWebServerNamespace.SERVER, SecurityContext.NONE, true, \"simple\");\n\t\t\tWebEndpointResponse<? extends HealthDescriptor> response = responseMono.block();\n\t\t\tassertThat(response).isNotNull();\n\t\t\tIndicatedHealthDescriptor descriptor = (IndicatedHealthDescriptor) (response.getBody());\n\t\t\tassertThat(descriptor).isNotNull();\n\t\t\tassertThat(descriptor.getDetails()).containsEntry(\"counter\", 42);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasReactiveHealthEndpointWebExtensionBeanDoesNotCreateExtraReactiveHealthEndpointWebExtension() {\n\t\tthis.reactiveContextRunner.withUserConfiguration(ReactiveHealthEndpointWebExtensionConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveHealthEndpointWebExtension webExtension = context\n\t\t\t\t\t.getBean(ReactiveHealthEndpointWebExtension.class);\n\t\t\t\tMono<WebEndpointResponse<? extends HealthDescriptor>> response = webExtension.health(ApiVersion.V3,\n\t\t\t\t\t\tWebServerNamespace.SERVER, SecurityContext.NONE, true, \"simple\");\n\t\t\t\tassertThat(response).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHealthEndpointGroupsPostProcessorPerformsProcessing() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.group.ready.include=*\")\n\t\t\t.withUserConfiguration(HealthEndpointGroupsConfiguration.class, TestHealthEndpointGroupsPostProcessor.class)\n\t\t\t.run((context) -> {\n\t\t\t\tHealthEndpointGroups groups = context.getBean(HealthEndpointGroups.class);\n\t\t\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> groups.get(\"test\"))\n\t\t\t\t\t.withMessage(\"postprocessed\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithIndicatorsInParentContextFindsIndicators() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t\t.run((parent) -> new WebApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,\n\t\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class))\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tHealthDescriptor descriptor = context.getBean(HealthEndpoint.class).health();\n\t\t\t\t\tMap<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();\n\t\t\t\t\tassertThat(components).containsKeys(\"additional\", \"ping\", \"simple\");\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid runWithReactiveContextAndIndicatorsInParentContextFindsIndicators() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t\t.run((parent) -> new ReactiveWebApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(HealthEndpointAutoConfiguration.class,\n\t\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthContributorAutoConfiguration.class,\n\t\t\t\t\t\tWebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class))\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tHealthDescriptor descriptor = context.getBean(HealthEndpoint.class).health();\n\t\t\t\t\tMap<String, HealthDescriptor> components = ((CompositeHealthDescriptor) descriptor).getComponents();\n\t\t\t\t\tassertThat(components).containsKeys(\"additional\", \"ping\", \"simple\");\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid runWithClashingGroupNameThrowsException() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.group.ping.include=*\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.hasMessageContaining(\"HealthContributor with name \\\"ping\\\" clashes with group\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthIndicatorsConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator simpleHealthIndicator() {\n\t\t\treturn () -> Health.up().withDetail(\"counter\", 42).build();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator additionalHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t\t@Bean\n\t\tReactiveHealthIndicator reactiveHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CompositeHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\tCompositeHealthContributor compositeHealthIndicator() {\n\t\t\treturn CompositeHealthContributor.fromMap(Map.of(\"a\", createHealthIndicator(), \"b\",\n\t\t\t\t\tCompositeHealthContributor.fromMap(Map.of(\"c\", createHealthIndicator()))));\n\t\t}\n\n\t\tprivate HealthIndicator createHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CompositeReactiveHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\tCompositeReactiveHealthContributor compositeHealthIndicator() {\n\t\t\treturn CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", createHealthIndicator(), \"b\",\n\t\t\t\t\tCompositeReactiveHealthContributor.fromMap(Map.of(\"c\", createHealthIndicator()))));\n\t\t}\n\n\t\tprivate ReactiveHealthIndicator createHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StatusAggregatorConfiguration {\n\n\t\t@Bean\n\t\tStatusAggregator statusAggregator() {\n\t\t\treturn (statuses) -> Status.UNKNOWN;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpCodeStatusMapperConfiguration {\n\n\t\t@Bean\n\t\tHttpCodeStatusMapper httpCodeStatusMapper() {\n\t\t\treturn (status) -> 456;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthEndpointGroupsConfiguration {\n\n\t\t@Bean\n\t\tHealthEndpointGroups healthEndpointGroups() {\n\t\t\tHealthEndpointGroups groups = mock(HealthEndpointGroups.class);\n\t\t\tgiven(groups.getNames()).willReturn(Collections.singleton(\"mock\"));\n\t\t\treturn groups;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthContributorRegistryConfiguration {\n\n\t\t@Bean\n\t\tHealthContributorRegistry healthContributorRegistry() {\n\t\t\treturn new DefaultHealthContributorRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthEndpointConfiguration {\n\n\t\t@Bean\n\t\tHealthEndpoint healthEndpoint() {\n\t\t\treturn mock(HealthEndpoint.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveHealthContributorRegistryConfiguration {\n\n\t\t@Bean\n\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry() {\n\t\t\treturn new DefaultReactiveHealthContributorRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthEndpointWebExtensionConfiguration {\n\n\t\t@Bean\n\t\tHealthEndpointWebExtension healthEndpointWebExtension() {\n\t\t\treturn mock(HealthEndpointWebExtension.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveHealthEndpointWebExtensionConfiguration {\n\n\t\t@Bean\n\t\tReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension() {\n\t\t\treturn mock(ReactiveHealthEndpointWebExtension.class);\n\t\t}\n\n\t}\n\n\tstatic class TestHealthEndpointGroupsPostProcessor implements HealthEndpointGroupsPostProcessor {\n\n\t\t@Override\n\t\tpublic HealthEndpointGroups postProcessHealthEndpointGroups(HealthEndpointGroups groups) {\n\t\t\tgiven(groups.get(\"test\")).willThrow(new RuntimeException(\"postprocessed\"));\n\t\t\treturn groups;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/application/AvailabilityHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration;\nimport org.springframework.boot.availability.ApplicationAvailability;\nimport org.springframework.boot.health.application.LivenessStateHealthIndicator;\nimport org.springframework.boot.health.application.ReadinessStateHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AvailabilityHealthContributorAutoConfiguration}\n *\n * @author Brian Clozel\n */\nclass AvailabilityHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ApplicationAvailabilityAutoConfiguration.class,\n\t\t\t\tAvailabilityHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid probesWhenNotKubernetesAddsNoBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t.doesNotHaveBean(LivenessStateHealthIndicator.class)\n\t\t\t.doesNotHaveBean(ReadinessStateHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid livenessIndicatorWhenPropertyEnabledAddsBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.livenessState.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t\t.hasSingleBean(LivenessStateHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(ReadinessStateHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid readinessIndicatorWhenPropertyEnabledAddsBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.readinessState.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ApplicationAvailability.class)\n\t\t\t\t.hasSingleBean(ReadinessStateHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(LivenessStateHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/application/DiskSpaceHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.application.DiskSpaceHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DiskSpaceHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass DiskSpaceHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DiskSpaceHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(DiskSpaceHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid thresholdMustBePositive() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.diskspace.threshold=-10MB\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessage(\"'threshold' must be greater than or equal to 0\"));\n\t}\n\n\t@Test\n\tvoid thresholdCanBeCustomized() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.diskspace.threshold=20MB\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DiskSpaceHealthIndicator.class);\n\t\t\tassertThat(context.getBean(DiskSpaceHealthIndicator.class)).hasFieldOrPropertyWithValue(\"threshold\",\n\t\t\t\t\tDataSize.ofMegabytes(20));\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenPathDoesNotExistShouldCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.diskspace.path=does/not/exist\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DiskSpaceHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.diskspace.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DiskSpaceHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/application/SslHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.application;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.health.application.SslHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.application.SslHealthContributorAutoConfigurationTests.CustomSslInfoConfiguration.CustomSslHealthIndicator;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.info.SslInfo.CertificateChainInfo;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslHealthContributorAutoConfiguration}.\n *\n * @author Jonatan Ivanov\n */\n@WithPackageResources(\"test.jks\")\nclass SslHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SslHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, SslAutoConfiguration.class))\n\t\t.withPropertyValues(\"server.ssl.bundle=ssltest\",\n\t\t\t\t\"spring.ssl.bundle.jks.ssltest.keystore.location=classpath:test.jks\");\n\n\t@Test\n\tvoid beansShouldNotBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.ssl.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(SslInfo.class));\n\t}\n\n\t@Test\n\tvoid beansShouldBeConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SslHealthIndicator.class);\n\t\t\tassertThat(context).hasSingleBean(SslInfo.class);\n\t\t\tHealth health = context.getBean(SslHealthIndicator.class).health();\n\t\t\tassertThat(health.getStatus()).isSameAs(Status.OUT_OF_SERVICE);\n\t\t\tassertDetailsKeys(health);\n\t\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\t\tassertThat(invalidChains).hasSize(1);\n\t\t\tassertThat(invalidChains).first().isInstanceOf(CertificateChainInfo.class);\n\n\t\t});\n\t}\n\n\t@Test\n\tvoid beansShouldBeConfiguredWithWarningThreshold() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.ssl.certificate-validity-warning-threshold=1d\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SslHealthIndicator.class);\n\t\t\t\tassertThat(context).hasSingleBean(SslInfo.class);\n\t\t\t\tassertThat(context).hasSingleBean(SslHealthIndicatorProperties.class);\n\t\t\t\tassertThat(context.getBean(SslHealthIndicatorProperties.class).getCertificateValidityWarningThreshold())\n\t\t\t\t\t.isEqualTo(Duration.ofDays(1));\n\t\t\t\tHealth health = context.getBean(SslHealthIndicator.class).health();\n\t\t\t\tassertThat(health.getStatus()).isSameAs(Status.OUT_OF_SERVICE);\n\t\t\t\tassertDetailsKeys(health);\n\t\t\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\t\t\tassertThat(invalidChains).hasSize(1);\n\t\t\t\tassertThat(invalidChains).first().isInstanceOf(CertificateChainInfo.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customBeansShouldBeConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(CustomSslInfoConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SslHealthIndicator.class);\n\t\t\tassertThat(context.getBean(SslHealthIndicator.class))\n\t\t\t\t.isSameAs(context.getBean(CustomSslHealthIndicator.class));\n\t\t\tassertThat(context).hasSingleBean(SslInfo.class);\n\t\t\tassertThat(context.getBean(SslInfo.class)).isSameAs(context.getBean(\"customSslInfo\"));\n\t\t\tHealth health = context.getBean(SslHealthIndicator.class).health();\n\t\t\tassertThat(health.getStatus()).isSameAs(Status.OUT_OF_SERVICE);\n\t\t\tassertDetailsKeys(health);\n\t\t\tList<CertificateChainInfo> invalidChains = getInvalidChains(health);\n\t\t\tassertThat(invalidChains).hasSize(1);\n\t\t\tassertThat(invalidChains).first().isInstanceOf(CertificateChainInfo.class);\n\t\t});\n\t}\n\n\tprivate static void assertDetailsKeys(Health health) {\n\t\tassertThat(health.getDetails()).containsOnlyKeys(\"expiringChains\", \"validChains\", \"invalidChains\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static List<CertificateChainInfo> getInvalidChains(Health health) {\n\t\tList<CertificateChainInfo> invalidChains = (List<CertificateChainInfo>) health.getDetails()\n\t\t\t.get(\"invalidChains\");\n\t\tassertThat(invalidChains).isNotNull();\n\t\treturn invalidChains;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSslInfoConfiguration {\n\n\t\t@Bean\n\t\tSslHealthIndicator sslHealthIndicator(SslInfo sslInfo) {\n\t\t\treturn new CustomSslHealthIndicator(sslInfo);\n\t\t}\n\n\t\t@Bean\n\t\tSslInfo customSslInfo(SslBundles sslBundles) {\n\t\t\treturn new SslInfo(sslBundles);\n\t\t}\n\n\t\tstatic class CustomSslHealthIndicator extends SslHealthIndicator {\n\n\t\t\tCustomSslHealthIndicator(SslInfo sslInfo) {\n\t\t\t\tsuper(sslInfo, Duration.ofDays(7));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/AbstractCompositeHealthContributorConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AbstractCompositeHealthContributorConfiguration}.\n *\n * @param <C> the contributor type\n * @param <I> the health indicator type\n * @author Phillip Webb\n */\nabstract class AbstractCompositeHealthContributorConfigurationTests<C, I extends C> {\n\n\tprivate final @Nullable Class<?> indicatorType;\n\n\tAbstractCompositeHealthContributorConfigurationTests() {\n\t\tResolvableType type = ResolvableType.forClass(AbstractCompositeHealthContributorConfigurationTests.class,\n\t\t\t\tgetClass());\n\t\tthis.indicatorType = type.resolveGeneric(1);\n\t}\n\n\t@Test\n\tvoid createContributorWhenBeansIsEmptyThrowsException() {\n\t\tMap<String, TestBean> beans = Collections.emptyMap();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> newComposite().createContributor(beans))\n\t\t\t.withMessage(\"'beans' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createContributorWhenBeansHasSingleElementCreatesIndicator() {\n\t\tMap<String, TestBean> beans = Collections.singletonMap(\"test\", new TestBean());\n\t\tC contributor = newComposite().createContributor(beans);\n\t\tassertThat(contributor).isInstanceOf(this.indicatorType);\n\t}\n\n\t@Test\n\tvoid createContributorWhenBeansHasMultipleElementsCreatesComposite() {\n\t\tMap<String, TestBean> beans = new LinkedHashMap<>();\n\t\tbeans.put(\"test1\", new TestBean());\n\t\tbeans.put(\"test2\", new TestBean());\n\t\tC contributor = newComposite().createContributor(beans);\n\t\tassertThat(contributor).isNotInstanceOf(this.indicatorType);\n\t\tassertThat(ClassUtils.getShortName(contributor.getClass())).startsWith(\"MapComposite\");\n\t}\n\n\t@Test\n\tvoid createContributorWhenBeanFactoryHasNoBeansThrowsException() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.refresh();\n\t\t\tassertThatIllegalArgumentException()\n\t\t\t\t.isThrownBy(() -> newComposite().createContributor(context.getBeanFactory(), TestBean.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid createContributorWhenBeanFactoryHasSingleBeanCreatesIndicator() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.register(SingleBeanConfiguration.class);\n\t\t\tcontext.refresh();\n\t\t\tC contributor = newComposite().createContributor(context.getBeanFactory(), TestBean.class);\n\t\t\tassertThat(contributor).isInstanceOf(this.indicatorType);\n\t\t}\n\t}\n\n\t@Test\n\tvoid createContributorWhenBeanFactoryHasMultipleBeansCreatesComposite() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.register(MultipleBeansConfiguration.class);\n\t\t\tcontext.refresh();\n\t\t\tC contributor = newComposite().createContributor(context.getBeanFactory(), TestBean.class);\n\t\t\tassertThat(contributor).isNotInstanceOf(this.indicatorType);\n\t\t\tassertThat(ClassUtils.getShortName(contributor.getClass())).startsWith(\"MapComposite\");\n\t\t\tassertThat(allNamesFromComposite(contributor)).containsExactlyInAnyOrder(\"standard\", \"nonDefault\");\n\t\t}\n\t}\n\n\tprotected abstract AbstractCompositeHealthContributorConfiguration<C, I, TestBean> newComposite();\n\n\tprotected abstract Stream<String> allNamesFromComposite(C composite);\n\n\tstatic class TestBean {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleBeansConfiguration {\n\n\t\t@Bean\n\t\tTestBean standard() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tTestBean nonDefault() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tTestBean nonAutowire() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SingleBeanConfiguration {\n\n\t\t@Bean\n\t\tTestBean standard() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tTestBean nonAutowire() {\n\t\t\treturn new TestBean();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/CompositeHealthContributorConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.stream.Stream;\n\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfigurationTests.TestHealthIndicator;\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors;\n\n/**\n * Tests for {@link CompositeHealthContributorConfiguration}.\n *\n * @author Phillip Webb\n */\nclass CompositeHealthContributorConfigurationTests\n\t\textends AbstractCompositeHealthContributorConfigurationTests<HealthContributor, TestHealthIndicator> {\n\n\t@Override\n\tprotected AbstractCompositeHealthContributorConfiguration<HealthContributor, TestHealthIndicator, TestBean> newComposite() {\n\t\treturn new TestCompositeHealthContributorConfiguration();\n\t}\n\n\t@Override\n\tprotected Stream<String> allNamesFromComposite(HealthContributor composite) {\n\t\treturn ((HealthContributors) composite).stream().map(HealthContributors.Entry::name);\n\t}\n\n\tstatic class TestCompositeHealthContributorConfiguration\n\t\t\textends CompositeHealthContributorConfiguration<TestHealthIndicator, TestBean> {\n\n\t\tTestCompositeHealthContributorConfiguration() {\n\t\t\tsuper(TestHealthIndicator::new);\n\t\t}\n\n\t}\n\n\tstatic class TestHealthIndicator extends AbstractHealthIndicator {\n\n\t\tTestHealthIndicator(TestBean testBean) {\n\t\t}\n\n\t\t@Override\n\t\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\t\tbuilder.up();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/CompositeReactiveHealthContributorConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.stream.Stream;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfigurationTests.TestReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\n\n/**\n * Tests for {@link CompositeReactiveHealthContributorConfiguration}.\n *\n * @author Phillip Webb\n */\nclass CompositeReactiveHealthContributorConfigurationTests extends\n\t\tAbstractCompositeHealthContributorConfigurationTests<ReactiveHealthContributor, TestReactiveHealthIndicator> {\n\n\t@Override\n\tprotected AbstractCompositeHealthContributorConfiguration<ReactiveHealthContributor, TestReactiveHealthIndicator, TestBean> newComposite() {\n\t\treturn new TestCompositeReactiveHealthContributorConfiguration();\n\t}\n\n\t@Override\n\tprotected Stream<String> allNamesFromComposite(ReactiveHealthContributor composite) {\n\t\treturn ((ReactiveHealthContributors) composite).stream().map(ReactiveHealthContributors.Entry::name);\n\t}\n\n\tstatic class TestCompositeReactiveHealthContributorConfiguration\n\t\t\textends CompositeReactiveHealthContributorConfiguration<TestReactiveHealthIndicator, TestBean> {\n\n\t\tTestCompositeReactiveHealthContributorConfiguration() {\n\t\t\tsuper(TestReactiveHealthIndicator::new);\n\t\t}\n\n\t}\n\n\tstatic class TestReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\t\tTestReactiveHealthIndicator(TestBean testBean) {\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\treturn Mono.just(builder.up().build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/ConditionalOnEnabledHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.PingHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnEnabledHealthIndicator}.\n *\n * @author Phillip Webb\n */\nclass ConditionalOnEnabledHealthIndicatorTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(CustomHealthIndicatorConfiguration.class);\n\n\t@Test\n\tvoid whenNoPropertyCreatesBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid whenIndicatorPropertyTrueCreatesBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.custom.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid whenIndicatorPropertyFalseDoesNotCreateBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.custom.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid whenDefaultsPropertyTrueCreatesBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.defaults.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid whenDefaultsPropertyFalseDoesNotCreateBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.defaults.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid whenIndicatorPropertyTrueAndDefaultsPropertyFalseCreatesBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.health.custom.enabled=true\", \"management.health.defaults.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid whenIndicatorPropertyFalseAndDefaultsPropertyTrueDoesNotCreateBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.health.custom.enabled=false\", \"management.health.defaults.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HealthIndicator.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnEnabledHealthIndicator(\"custom\")\n\t\tPingHealthIndicator customHealthIndicator() {\n\t\t\treturn new PingHealthIndicator();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/HealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.PingHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass HealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runWhenNoOtherIndicatorsCreatesPingHealthIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(HealthIndicator.class)\n\t\t\t.isInstanceOf(PingHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenHasDefinedIndicatorCreatesPingHealthIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHealthIndicatorConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PingHealthIndicator.class)\n\t\t\t\t.hasSingleBean(CustomHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenHasDefaultsDisabledDoesNotCreatePingHealthIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.health.defaults.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenHasDefaultsDisabledAndPingIndicatorEnabledCreatesPingHealthIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHealthIndicatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.health.defaults.enabled:false\", \"management.health.ping.enabled:true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PingHealthIndicator.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHealthIndicatorConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnEnabledHealthIndicator(\"custom\")\n\t\tHealthIndicator customHealthIndicator() {\n\t\t\treturn new CustomHealthIndicator();\n\t\t}\n\n\t}\n\n\tstatic class CustomHealthIndicator implements HealthIndicator {\n\n\t\t@Override\n\t\tpublic Health health() {\n\t\t\treturn Health.down().build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/HealthContributorMembershipTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.function.Predicate;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthContributorMembership}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\nclass HealthContributorMembershipTests {\n\n\t@Nested\n\tclass ByIncludeExcludeTests {\n\n\t\t@Test\n\t\tvoid isMemberWhenEmptyIncludeAndExcludeAcceptsAll() {\n\t\t\tHealthContributorMembership membership = HealthContributorMembership.byIncludeExclude(null, null);\n\t\t\tassertThat(asPredicate(membership)).accepts(\"a\", \"b\", \"c\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenStarIncludeAndEmptyExcludeAcceptsAll() {\n\t\t\tHealthContributorMembership membership = include(\"*\").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"a\", \"b\", \"c\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenEmptyIncludeAndNonEmptyExcludeAcceptsAllButExclude() {\n\t\t\tHealthContributorMembership membership = HealthContributorMembership.byIncludeExclude(null,\n\t\t\t\t\tCollections.singleton(\"c\"));\n\t\t\tassertThat(asPredicate(membership)).accepts(\"a\", \"b\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenStarIncludeAndSpecificExcludeDoesNotAcceptExclude() {\n\t\t\tHealthContributorMembership membership = include(\"*\").exclude(\"c\");\n\t\t\tassertThat(asPredicate(membership)).accepts(\"a\", \"b\").rejects(\"c\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenSpecificIncludeAcceptsOnlyIncluded() {\n\t\t\tHealthContributorMembership membership = include(\"a\", \"b\").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"a\", \"b\").rejects(\"c\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenSpecifiedIncludeAndSpecifiedExcludeAcceptsAsExpected() {\n\t\t\tHealthContributorMembership membership = include(\"a\", \"b\", \"c\").exclude(\"c\");\n\t\t\tassertThat(asPredicate(membership)).accepts(\"a\", \"b\").rejects(\"c\", \"d\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenSpecifiedIncludeAndStarExcludeRejectsAll() {\n\t\t\tHealthContributorMembership membership = include(\"a\", \"b\", \"c\").exclude(\"*\");\n\t\t\tassertThat(asPredicate(membership)).rejects(\"a\", \"b\", \"c\", \"d\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenCamelCaseIncludeAcceptsOnlyIncluded() {\n\t\t\tHealthContributorMembership membership = include(\"myEndpoint\").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"myEndpoint\").rejects(\"d\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenHyphenCaseIncludeAcceptsOnlyIncluded() {\n\t\t\tHealthContributorMembership membership = include(\"my-endpoint\").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"my-endpoint\").rejects(\"d\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenExtraWhitespaceAcceptsTrimmedVersion() {\n\t\t\tHealthContributorMembership membership = include(\"  myEndpoint  \").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"myEndpoint\").rejects(\"d\");\n\t\t}\n\n\t\t@Test\n\t\tvoid isMemberWhenSpecifiedIncludeWithSlash() {\n\t\t\tHealthContributorMembership membership = include(\"test/a\").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"test/a\").rejects(\"test\").rejects(\"test/b\");\n\t\t}\n\n\t\t@Test\n\t\tvoid specifiedIncludeShouldIncludeNested() {\n\t\t\tHealthContributorMembership membership = include(\"test\").exclude();\n\t\t\tassertThat(asPredicate(membership)).accepts(\"test/a/d\").accepts(\"test/b\").rejects(\"foo\");\n\t\t}\n\n\t\t@Test\n\t\tvoid specifiedIncludeShouldNotIncludeExcludedNested() {\n\t\t\tHealthContributorMembership membership = include(\"test\").exclude(\"test/b\");\n\t\t\tassertThat(asPredicate(membership)).accepts(\"test/a\").rejects(\"test/b\").rejects(\"foo\");\n\t\t}\n\n\t\t@Test // gh-29251\n\t\tvoid specifiedExcludeShouldExcludeNestedChildren() {\n\t\t\tHealthContributorMembership membership = include(\"*\").exclude(\"test\");\n\t\t\tassertThat(asPredicate(membership)).rejects(\"test\").rejects(\"test/a\").rejects(\"test/a\").accepts(\"other\");\n\t\t}\n\n\t\tprivate Predicate<String> asPredicate(HealthContributorMembership membership) {\n\t\t\treturn membership::isMember;\n\t\t}\n\n\t\tprivate Builder include(String... include) {\n\t\t\treturn new Builder(include);\n\t\t}\n\n\t\tprivate static class Builder {\n\n\t\t\tprivate final String[] include;\n\n\t\t\tBuilder(String[] include) {\n\t\t\t\tthis.include = include;\n\t\t\t}\n\n\t\t\tHealthContributorMembership exclude(String... exclude) {\n\t\t\t\treturn HealthContributorMembership.byIncludeExclude(asSet(this.include), asSet(exclude));\n\t\t\t}\n\n\t\t\tprivate @Nullable Set<String> asSet(String @Nullable [] names) {\n\t\t\t\treturn (names != null) ? new LinkedHashSet<>(Arrays.asList(names)) : null;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/contributor/HealthContributorMembershipValidatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.contributor;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalyzedException;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link HealthContributorMembershipValidator}.\n *\n * @author Phillip Webb\n */\nclass HealthContributorMembershipValidatorTests {\n\n\tprivate static final HealthIndicator UP = () -> Health.up().build();\n\n\tprivate final DefaultHealthContributorRegistry registry = new DefaultHealthContributorRegistry();\n\n\tprivate final DefaultReactiveHealthContributorRegistry fallbackRegistry = new DefaultReactiveHealthContributorRegistry();\n\n\t@Test\n\tvoid validateWhenNoNamesDoesNotThrow() {\n\t\tHealthContributorMembershipValidator validator = new HealthContributorMembershipValidator(this.registry, null,\n\t\t\t\t\"my.disable-validation\", (members) -> members.member(\"include\", Collections.emptySet()));\n\t\tvalidator.afterSingletonsInstantiated();\n\t}\n\n\t@Test\n\tvoid validateWhenNameIncludesAsteriskDoesNotThrow() {\n\t\tHealthContributorMembershipValidator validator = new HealthContributorMembershipValidator(this.registry, null,\n\t\t\t\t\"my.disable-validation\", (members) -> members.member(\"include\", Set.of(\"*\")));\n\t\tvalidator.afterSingletonsInstantiated();\n\t}\n\n\t@Test\n\tvoid validateWhenContributorDoesNotExistThrows() {\n\t\tHealthContributorMembershipValidator validator = new HealthContributorMembershipValidator(this.registry, null,\n\t\t\t\t\"my.disable-validation\", (members) -> members.member(\"include\", Set.of(\"test\")));\n\t\tassertThatExceptionOfType(FailureAnalyzedException.class)\n\t\t\t.isThrownBy(() -> validator.afterSingletonsInstantiated())\n\t\t\t.withMessage(\"Health contributor 'test' defined in 'include' does not exist\")\n\t\t\t.satisfies((ex) -> assertThat(ex.analysis().getAction()).contains(\"my.disable-validation\"));\n\t}\n\n\t@Test\n\tvoid validateWhenContributorExistsInRegistryDoesNotThrow() {\n\t\tthis.registry.registerContributor(\"test\", UP);\n\t\tHealthContributorMembershipValidator validator = new HealthContributorMembershipValidator(this.registry, null,\n\t\t\t\t\"my.disable-validation\", (members) -> members.member(\"include\", Set.of(\"test\")));\n\t\tvalidator.afterSingletonsInstantiated();\n\t}\n\n\t@Test\n\tvoid validateWhenContributorExistsInFallbackRegistryDoesNotThrow() {\n\t\tthis.fallbackRegistry.registerContributor(\"test\", ReactiveHealthContributor.adapt(UP));\n\t\tHealthContributorMembershipValidator validator = new HealthContributorMembershipValidator(this.registry,\n\t\t\t\tthis.fallbackRegistry, \"my.disable-validation\", (members) -> members.member(\"include\", Set.of(\"test\")));\n\t\tvalidator.afterSingletonsInstantiated();\n\t}\n\n\t@Test\n\tvoid validateWhenNestedContributorExistsInRegistryDoesNotThrow() {\n\t\tthis.registry.registerContributor(\"test\", CompositeHealthContributor.fromMap(Map.of(\"nested\", UP)));\n\t\tHealthContributorMembershipValidator validator = new HealthContributorMembershipValidator(this.registry, null,\n\t\t\t\t\"my.disable-validation\", (members) -> members.member(\"include\", Set.of(\"test/nested\")));\n\t\tvalidator.afterSingletonsInstantiated();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/registry/HealthContributorNameGeneratorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.registry;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthContributorNameGenerator}.\n *\n * @author Phillip Webb\n */\nclass HealthContributorNameGeneratorTests {\n\n\t@Test\n\tvoid withoutStandardSuffixesWhenNameDoesNotEndWithSuffixReturnsName() {\n\t\tassertThat(HealthContributorNameGenerator.withoutStandardSuffixes().generateContributorName(\"test\"))\n\t\t\t.isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid withoutStandardSuffixesWhenNameEndsWithSuffixReturnsNewName() {\n\t\tassertThat(\n\t\t\t\tHealthContributorNameGenerator.withoutStandardSuffixes().generateContributorName(\"testHealthIndicator\"))\n\t\t\t.isEqualTo(\"test\");\n\t\tassertThat(HealthContributorNameGenerator.withoutStandardSuffixes()\n\t\t\t.generateContributorName(\"testHealthContributor\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid withoutStandardSuffixesWhenNameEndsWithSuffixInDifferentReturnsNewName() {\n\t\tassertThat(\n\t\t\t\tHealthContributorNameGenerator.withoutStandardSuffixes().generateContributorName(\"testHEALTHindicator\"))\n\t\t\t.isEqualTo(\"test\");\n\t\tassertThat(HealthContributorNameGenerator.withoutStandardSuffixes()\n\t\t\t.generateContributorName(\"testHEALTHcontributor\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid withoutStandardSuffixesWhenNameContainsSuffixReturnsName() {\n\t\tassertThat(HealthContributorNameGenerator.withoutStandardSuffixes()\n\t\t\t.generateContributorName(\"testHealthIndicatorTest\")).isEqualTo(\"testHealthIndicatorTest\");\n\t\tassertThat(HealthContributorNameGenerator.withoutStandardSuffixes()\n\t\t\t.generateContributorName(\"testHealthContributorTest\")).isEqualTo(\"testHealthContributorTest\");\n\t}\n\n\t@Test\n\tvoid withoutSuffixesStripsSuffix() {\n\t\tHealthContributorNameGenerator generator = HealthContributorNameGenerator.withoutSuffixes(\"spring\", \"boot\");\n\t\tassertThat(generator.generateContributorName(\"testspring\")).isEqualTo(\"test\");\n\t\tassertThat(generator.generateContributorName(\"tEsTsPrInG\")).isEqualTo(\"tEsT\");\n\t\tassertThat(generator.generateContributorName(\"springboot\")).isEqualTo(\"spring\");\n\t\tassertThat(generator.generateContributorName(\"springspring\")).isEqualTo(\"spring\");\n\t\tassertThat(generator.generateContributorName(\"test\")).isEqualTo(\"test\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/autoconfigure/registry/HealthContributorRegistryAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.autoconfigure.registry;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.registry.DefaultHealthContributorRegistry;\nimport org.springframework.boot.health.registry.DefaultReactiveHealthContributorRegistry;\nimport org.springframework.boot.health.registry.HealthContributorRegistry;\nimport org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthContributorRegistryAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass HealthContributorRegistryAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class));\n\n\t@Test\n\tvoid runCreatesHealthContributorRegistriesContainingHealthBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).containsExactlyInAnyOrder(\"simple\", \"additional\", \"ping\");\n\t\t\tReactiveHealthContributorRegistry reactiveRegistry = context\n\t\t\t\t.getBean(ReactiveHealthContributorRegistry.class);\n\t\t\tObject[] reactiveNames = reactiveRegistry.stream().map(ReactiveHealthContributors.Entry::name).toArray();\n\t\t\tassertThat(reactiveNames).containsExactlyInAnyOrder(\"reactive\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenNoReactorCreatesHealthContributorRegistryContainingHealthBeans() {\n\t\tClassLoader classLoader = new FilteredClassLoader(Mono.class, Flux.class);\n\t\tthis.contextRunner.withClassLoader(classLoader).run((context) -> {\n\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).containsExactlyInAnyOrder(\"simple\", \"additional\", \"ping\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasHealthContributorRegistryBeanDoesNotCreateAdditionalRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(HealthContributorRegistryConfiguration.class).run((context) -> {\n\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\tassertThat(names).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenHasReactiveHealthContributorRegistryBeanDoesNotCreateAdditionalReactiveHealthContributorRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveHealthContributorRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveHealthContributorRegistry registry = context.getBean(ReactiveHealthContributorRegistry.class);\n\t\t\t\tObject[] names = registry.stream().map(ReactiveHealthContributors.Entry::name).toArray();\n\t\t\t\tassertThat(names).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithIndicatorsInParentContextFindsIndicators() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t\t.run((parent) -> new ApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class))\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tHealthContributorRegistry registry = context.getBean(HealthContributorRegistry.class);\n\t\t\t\t\tObject[] names = registry.stream().map(HealthContributors.Entry::name).toArray();\n\t\t\t\t\tassertThat(names).containsExactlyInAnyOrder(\"simple\", \"additional\", \"ping\");\n\t\t\t\t\tReactiveHealthContributorRegistry reactiveRegistry = context\n\t\t\t\t\t\t.getBean(ReactiveHealthContributorRegistry.class);\n\t\t\t\t\tObject[] reactiveNames = reactiveRegistry.stream()\n\t\t\t\t\t\t.map(ReactiveHealthContributors.Entry::name)\n\t\t\t\t\t\t.toArray();\n\t\t\t\t\tassertThat(reactiveNames).containsExactlyInAnyOrder(\"reactive\");\n\t\t\t\t}));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthIndicatorsConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator simpleHealthIndicator() {\n\t\t\treturn () -> Health.up().withDetail(\"counter\", 42).build();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator additionalHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t\t@Bean\n\t\tReactiveHealthIndicator reactiveHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthContributorRegistryConfiguration {\n\n\t\t@Bean\n\t\tHealthContributorRegistry healthContributorRegistry() {\n\t\t\treturn new DefaultHealthContributorRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveHealthContributorRegistryConfiguration {\n\n\t\t@Bean\n\t\tReactiveHealthContributorRegistry reactiveHealthContributorRegistry() {\n\t\t\treturn new DefaultReactiveHealthContributorRegistry();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/AbstractHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractHealthIndicator}.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass AbstractHealthIndicatorTests {\n\n\t@Test\n\tvoid healthCheckWhenUpDoesNotLogHealthCheckFailedMessage(CapturedOutput output) {\n\t\tTestHealthIndicator indicator = new TestHealthIndicator(\"Test message\", Health.Builder::up);\n\t\tHealth heath = indicator.health();\n\t\tassertThat(heath.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(output).doesNotContain(\"Test message\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionThrownLogsHealthCheckFailedMessage(CapturedOutput output) {\n\t\tTestHealthIndicator indicator = new TestHealthIndicator(\"Test message\", (builder) -> {\n\t\t\tthrow new IllegalStateException(\"Test exception\");\n\t\t});\n\t\tHealth heath = indicator.health();\n\t\tassertThat(heath.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Test message\").contains(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionConfiguredLogsHealthCheckFailedMessage(CapturedOutput output) {\n\t\tHealth heath = new TestHealthIndicator(\"Test message\",\n\t\t\t\t(builder) -> builder.down().withException(new IllegalStateException(\"Test exception\")))\n\t\t\t.health();\n\t\tassertThat(heath.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Test message\").contains(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionConfiguredDoesNotLogHealthCheckFailedMessageTwice(CapturedOutput output) {\n\t\tTestHealthIndicator indicator = new TestHealthIndicator(\"Test message\", (builder) -> {\n\t\t\tIllegalStateException ex = new IllegalStateException(\"Test exception\");\n\t\t\tbuilder.down().withException(ex);\n\t\t\tthrow ex;\n\t\t});\n\t\tHealth heath = indicator.health();\n\t\tassertThat(heath.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Test message\").containsOnlyOnce(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionAndNoFailureMessageLogsDefaultMessage(CapturedOutput output) {\n\t\tTestHealthIndicator indicator = new TestHealthIndicator(\n\t\t\t\t(builder) -> builder.down().withException(new IllegalStateException(\"Test exception\")));\n\t\tHealth heath = indicator.health();\n\t\tassertThat(heath.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Health check failed\").contains(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithErrorLogsDefaultMessage(CapturedOutput output) {\n\t\tTestHealthIndicator indicator = new TestHealthIndicator(\"Test Message\",\n\t\t\t\t(builder) -> builder.down().withException(new Error(\"Test error\")));\n\t\tHealth heath = indicator.health();\n\t\tassertThat(heath.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Health check failed\").contains(\"Test error\");\n\t}\n\n\tstatic class TestHealthIndicator extends AbstractHealthIndicator {\n\n\t\tprivate final Consumer<Health.Builder> action;\n\n\t\tTestHealthIndicator(String message, Consumer<Health.Builder> action) {\n\t\t\tsuper(message);\n\t\t\tthis.action = action;\n\t\t}\n\n\t\tTestHealthIndicator(Consumer<Health.Builder> action) {\n\t\t\tthis.action = action;\n\t\t}\n\n\t\t@Override\n\t\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\t\tthis.action.accept(builder);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/AbstractReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractReactiveHealthIndicator}.\n *\n * @author Moritz Halbritter\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass AbstractReactiveHealthIndicatorTests {\n\n\t@Test\n\tvoid healthCheckWhenUpDoesNotLogHealthCheckFailedMessage(CapturedOutput output) {\n\t\tHealth health = new AbstractReactiveHealthIndicator(\"Test message\") {\n\n\t\t\t@Override\n\t\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\t\treturn Mono.just(builder.up().build());\n\t\t\t}\n\n\t\t}.health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(output).doesNotContain(\"Test message\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionThrownLogsHealthCheckFailedMessage(CapturedOutput output) {\n\t\tHealth health = new AbstractReactiveHealthIndicator(\"Test message\") {\n\n\t\t\t@Override\n\t\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\t\tthrow new IllegalStateException(\"Test exception\");\n\t\t\t}\n\n\t\t}.health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Test message\").contains(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionConfiguredLogsHealthCheckFailedMessage(CapturedOutput output) {\n\t\tHealth health = new AbstractReactiveHealthIndicator(\"Test message\") {\n\n\t\t\t@Override\n\t\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\t\treturn Mono.just(builder.down().withException(new IllegalStateException(\"Test exception\")).build());\n\t\t\t}\n\n\t\t}.health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Test message\").contains(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionConfiguredDoesNotLogHealthCheckFailedMessageTwice(CapturedOutput output) {\n\t\tHealth health = new AbstractReactiveHealthIndicator(\"Test message\") {\n\n\t\t\t@Override\n\t\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\t\tIllegalStateException ex = new IllegalStateException(\"Test exception\");\n\t\t\t\tbuilder.down().withException(ex);\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t}.health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Test message\").containsOnlyOnce(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithExceptionAndNoFailureMessageLogsDefaultMessage(CapturedOutput output) {\n\t\tHealth health = new AbstractReactiveHealthIndicator() {\n\n\t\t\t@Override\n\t\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\t\treturn Mono.just(builder.down().withException(new IllegalStateException(\"Test exception\")).build());\n\t\t\t}\n\n\t\t}.health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Health check failed\").contains(\"Test exception\");\n\t}\n\n\t@Test\n\tvoid healthCheckWhenDownWithErrorLogsDefaultMessage(CapturedOutput output) {\n\t\tHealth health = new AbstractReactiveHealthIndicator(\"Test Message\") {\n\n\t\t\t@Override\n\t\t\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\t\t\treturn Mono.just(builder.down().withException(new Error(\"Test error\")).build());\n\t\t\t}\n\n\t\t}.health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(output).contains(\"Health check failed\").contains(\"Test error\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/CompositeHealthContributorAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\n/**\n * Tests for {@link CompositeHealthContributorAdapter}.\n *\n * @author Phillip Webb\n */\nclass CompositeHealthContributorAdapterTests extends HealthContributorsAdapterTests {\n\n\t@Override\n\tprotected CompositeHealthContributorAdapter createAdapter(CompositeHealthContributor delegate) {\n\t\treturn new CompositeHealthContributorAdapter(delegate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/CompositeHealthContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompositeHealthContributor}.\n *\n * @author Phillip Webb\n * @author Guirong Hu\n */\nclass CompositeHealthContributorTests {\n\n\t@Test\n\tvoid fromMapReturnsCompositeHealthContributorMapAdapter() {\n\t\tMap<String, HealthContributor> map = new LinkedHashMap<>();\n\t\tHealthIndicator indicator = () -> Health.down().build();\n\t\tmap.put(\"test\", indicator);\n\t\tCompositeHealthContributor composite = CompositeHealthContributor.fromMap(map);\n\t\tassertThat(composite).isInstanceOf(MapCompositeHealthContributor.class);\n\t\tHealthContributors.Entry entry = composite.iterator().next();\n\t\tassertThat(entry.name()).isEqualTo(\"test\");\n\t\tassertThat(entry.contributor()).isSameAs(indicator);\n\t}\n\n\t@Test\n\tvoid fromMapWithAdapterReturnsCompositeHealthContributorMapAdapter() {\n\t\tMap<String, HealthContributor> map = new LinkedHashMap<>();\n\t\tHealthIndicator downIndicator = () -> Health.down().build();\n\t\tHealthIndicator upIndicator = () -> Health.up().build();\n\t\tmap.put(\"test\", downIndicator);\n\t\tCompositeHealthContributor composite = CompositeHealthContributor.fromMap(map, (value) -> upIndicator);\n\t\tassertThat(composite).isInstanceOf(MapCompositeHealthContributor.class);\n\t\tHealthContributors.Entry entry = composite.iterator().next();\n\t\tassertThat(entry.name()).isEqualTo(\"test\");\n\t\tassertThat(entry.contributor()).isSameAs(upIndicator);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/CompositeHealthContributorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.HealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CompositeHealthContributors}.\n *\n * @author Phillip Webb\n */\nclass CompositeHealthContributorsTests {\n\n\t@Test\n\tvoid getContributorWhenManyReturnsFirstContributor() {\n\t\tHealthIndicator a1 = mock(HealthIndicator.class);\n\t\tCompositeHealthContributor c1 = CompositeHealthContributor.fromMap(Map.of(\"a\", a1));\n\t\tHealthIndicator a2 = mock(HealthIndicator.class);\n\t\tCompositeHealthContributor c2 = CompositeHealthContributor.fromMap(Map.of(\"a\", a2));\n\t\tHealthContributors composite = HealthContributors.of(c1, c2);\n\t\tassertThat(composite.getContributor(\"a\")).isSameAs(a1);\n\t}\n\n\t@Test\n\tvoid getContributorWhenNoneReturnsNull() {\n\t\tHealthIndicator a = mock(HealthIndicator.class);\n\t\tHealthContributors composite = HealthContributors.of(CompositeHealthContributor.fromMap(Map.of(\"a\", a)));\n\t\tassertThat(composite.getContributor(\"x\")).isNull();\n\t}\n\n\t@Test\n\tvoid streamStreamsWithoutDuplicates() {\n\t\tHealthIndicator a1 = mock(HealthIndicator.class);\n\t\tCompositeHealthContributor c1 = CompositeHealthContributor.fromMap(Map.of(\"a\", a1));\n\t\tHealthIndicator a2 = mock(HealthIndicator.class);\n\t\tCompositeHealthContributor c2 = CompositeHealthContributor.fromMap(Map.of(\"a\", a2));\n\t\tHealthIndicator b = mock(HealthIndicator.class);\n\t\tCompositeHealthContributor c3 = CompositeHealthContributor.fromMap(Map.of(\"b\", b));\n\t\tHealthContributors composite = HealthContributors.of(c1, c2, c3);\n\t\tassertThat(composite.stream()).containsExactly(new Entry(\"a\", a1), new Entry(\"b\", b));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/CompositeReactiveHealthContributorAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\n/**\n * Tests for {@link CompositeReactiveHealthContributorAdapter}.\n *\n * @author Phillip Webb\n */\nclass CompositeReactiveHealthContributorAdapterTests extends ReactiveHealthContributorsAdapterTests {\n\n\t@Override\n\tprotected CompositeReactiveHealthContributorAdapter createAdapter(CompositeReactiveHealthContributor delegate) {\n\t\treturn new CompositeReactiveHealthContributorAdapter(delegate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/CompositeReactiveHealthContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompositeReactiveHealthContributor}.\n *\n * @author Phillip Webb\n */\nclass CompositeReactiveHealthContributorTests {\n\n\t@Test\n\tvoid asHealthContributorReturnsAdaptedContributor() {\n\t\tReactiveHealthIndicator indicator = () -> Mono.just(Health.up().withDetail(\"spring\", \"boot\").build());\n\t\tMap<String, ReactiveHealthContributor> reactiveContributors = Map.of(\"test\", indicator);\n\t\tCompositeReactiveHealthContributor contributor = CompositeReactiveHealthContributor\n\t\t\t.fromMap(reactiveContributors);\n\t\tCompositeHealthContributor adapted = contributor.asHealthContributor();\n\t\tHealthIndicator byName = (HealthIndicator) adapted.getContributor(\"test\");\n\t\tassertThat(byName).isNotNull();\n\t\tHealth health = byName.health(true);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t\tHealthContributors.Entry entry = adapted.iterator().next();\n\t\tassertThat(entry.name()).isEqualTo(\"test\");\n\t\tHealthIndicator byEntry = (HealthIndicator) entry.contributor();\n\t\thealth = byEntry.health(true);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid fromMapReturnsCompositeReactiveHealthContributorMapAdapter() {\n\t\tMap<String, ReactiveHealthContributor> map = new LinkedHashMap<>();\n\t\tReactiveHealthIndicator indicator = () -> Mono.just(Health.down().build());\n\t\tmap.put(\"test\", indicator);\n\t\tCompositeReactiveHealthContributor composite = CompositeReactiveHealthContributor.fromMap(map);\n\t\tassertThat(composite).isInstanceOf(MapCompositeReactiveHealthContributor.class);\n\t\tReactiveHealthContributors.Entry entry = composite.iterator().next();\n\t\tassertThat(entry.name()).isEqualTo(\"test\");\n\t\tassertThat(entry.contributor()).isSameAs(indicator);\n\t}\n\n\t@Test\n\tvoid fromMapWithAdapterReturnsCompositeReactiveHealthContributorMapAdapter() {\n\t\tMap<String, ReactiveHealthContributor> map = new LinkedHashMap<>();\n\t\tReactiveHealthIndicator downIndicator = () -> Mono.just(Health.down().build());\n\t\tReactiveHealthIndicator upIndicator = () -> Mono.just(Health.up().build());\n\t\tmap.put(\"test\", downIndicator);\n\t\tCompositeReactiveHealthContributor composite = CompositeReactiveHealthContributor.fromMap(map,\n\t\t\t\t(value) -> upIndicator);\n\t\tassertThat(composite).isInstanceOf(MapCompositeReactiveHealthContributor.class);\n\t\tReactiveHealthContributors.Entry entry = composite.iterator().next();\n\t\tassertThat(entry.name()).isEqualTo(\"test\");\n\t\tassertThat(entry.contributor()).isSameAs(upIndicator);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/CompositeReactiveHealthContributorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link CompositeReactiveHealthContributors}.\n *\n * @author Phillip Webb\n */\nclass CompositeReactiveHealthContributorsTests {\n\n\t@Test\n\tvoid getContributorWhenManyReturnsFirstContributor() {\n\t\tReactiveHealthIndicator a1 = mock(ReactiveHealthIndicator.class);\n\t\tCompositeReactiveHealthContributor c1 = CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a1));\n\t\tReactiveHealthIndicator a2 = mock(ReactiveHealthIndicator.class);\n\t\tCompositeReactiveHealthContributor c2 = CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a2));\n\t\tReactiveHealthContributors composite = ReactiveHealthContributors.of(c1, c2);\n\t\tassertThat(composite.getContributor(\"a\")).isSameAs(a1);\n\t}\n\n\t@Test\n\tvoid getContributorWhenNoneReturnsNull() {\n\t\tReactiveHealthIndicator a = mock(ReactiveHealthIndicator.class);\n\t\tReactiveHealthContributors composite = ReactiveHealthContributors\n\t\t\t.of(CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a)));\n\t\tassertThat(composite.getContributor(\"x\")).isNull();\n\t}\n\n\t@Test\n\tvoid streamStreamsWithoutDuplicates() {\n\t\tReactiveHealthIndicator a1 = mock(ReactiveHealthIndicator.class);\n\t\tCompositeReactiveHealthContributor c1 = CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a1));\n\t\tReactiveHealthIndicator a2 = mock(ReactiveHealthIndicator.class);\n\t\tCompositeReactiveHealthContributor c2 = CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a2));\n\t\tReactiveHealthIndicator b = mock(ReactiveHealthIndicator.class);\n\t\tCompositeReactiveHealthContributor c3 = CompositeReactiveHealthContributor.fromMap(Map.of(\"b\", b));\n\t\tReactiveHealthContributors composite = ReactiveHealthContributors.of(c1, c2, c3);\n\t\tassertThat(composite.stream()).containsExactly(new Entry(\"a\", a1), new Entry(\"b\", b));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/HealthContributorsAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\nimport java.util.Iterator;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthContributorsAdapter}.\n *\n * @author Phillip Webb\n */\nclass HealthContributorsAdapterTests {\n\n\t@Test\n\tvoid iteratorWhenDelegateContainsHealthIndicatorAdaptsDelegate() {\n\t\tHealthIndicator indicator = () -> Health.up().withDetail(\"spring\", \"boot\").build();\n\t\tCompositeHealthContributor delegate = CompositeHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"test\", indicator));\n\t\tHealthContributorsAdapter adapter = createAdapter(delegate);\n\t\tIterator<ReactiveHealthContributors.Entry> iterator = adapter.iterator();\n\t\tassertThat(iterator.hasNext()).isTrue();\n\t\tReactiveHealthContributors.Entry adapted = iterator.next();\n\t\tassertThat(adapted.name()).isEqualTo(\"test\");\n\t\tassertThat(adapted.contributor()).isInstanceOf(ReactiveHealthIndicator.class);\n\t\tHealth health = ((ReactiveHealthIndicator) adapted.contributor()).health(true).block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid iteratorWhenDelegateContainsCompositeHealthContributorAdaptsDelegate() {\n\t\tHealthIndicator indicator = () -> Health.up().withDetail(\"spring\", \"boot\").build();\n\t\tCompositeHealthContributor composite = CompositeHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"test1\", indicator));\n\t\tCompositeHealthContributor delegate = CompositeHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"test2\", composite));\n\t\tHealthContributorsAdapter adapter = createAdapter(delegate);\n\t\tIterator<ReactiveHealthContributors.Entry> iterator = adapter.iterator();\n\t\tassertThat(iterator.hasNext()).isTrue();\n\t\tReactiveHealthContributors.Entry adapted = iterator.next();\n\t\tassertThat(adapted.name()).isEqualTo(\"test2\");\n\t\tassertThat(adapted.contributor()).isInstanceOf(CompositeReactiveHealthContributor.class);\n\t\tReactiveHealthContributor nested = ((CompositeReactiveHealthContributor) adapted.contributor())\n\t\t\t.getContributor(\"test1\");\n\t\tassertThat(nested).isNotNull();\n\t\tHealth health = ((ReactiveHealthIndicator) nested).health(true).block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getContributorAdaptsDelegate() {\n\t\tHealthIndicator indicator = () -> Health.up().withDetail(\"spring\", \"boot\").build();\n\t\tCompositeHealthContributor delegate = CompositeHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"test\", indicator));\n\t\tHealthContributorsAdapter adapter = createAdapter(delegate);\n\t\tReactiveHealthContributor adapted = adapter.getContributor(\"test\");\n\t\tassertThat(adapted).isNotNull();\n\t\tHealth health = ((ReactiveHealthIndicator) adapted).health(true).block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\tprotected HealthContributorsAdapter createAdapter(CompositeHealthContributor delegate) {\n\t\treturn new CompositeHealthContributorAdapter(delegate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/HealthContributorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.HealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HealthContributors}.\n *\n * @author Phillip Webb\n */\nclass HealthContributorsTests {\n\n\t@Test\n\tvoid iteratorAdaptsStream() {\n\t\tEntry e1 = new Entry(\"e1\", mock(HealthIndicator.class));\n\t\tEntry e2 = new Entry(\"e2\", mock(HealthIndicator.class));\n\t\tHealthContributors contributors = new HealthContributors() {\n\n\t\t\t@Override\n\t\t\tpublic Stream<Entry> stream() {\n\t\t\t\treturn Stream.of(e1, e2);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable HealthContributor getContributor(String name) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t};\n\t\tassertThat(contributors).containsExactly(e1, e2);\n\t}\n\n\t@Test\n\tvoid createEntryWhenNameIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Entry(\"\", mock(HealthIndicator.class)))\n\t\t\t.withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createEntryWhenContributorIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Entry(\"test\", null))\n\t\t\t.withMessage(\"'contributor' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofCreatesComposite() {\n\t\tHealthContributors c = mock(HealthContributors.class);\n\t\tassertThat(HealthContributors.of(c)).isInstanceOf(CompositeHealthContributors.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/HealthIndicatorAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.test.StepVerifier;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HealthIndicatorAdapter}.\n *\n * @author Stephane Nicoll\n */\nclass HealthIndicatorAdapterTests {\n\n\t@Test\n\tvoid delegateReturnsHealth() {\n\t\tHealthIndicator delegate = mock(HealthIndicator.class);\n\t\tHealthIndicatorAdapter adapter = new HealthIndicatorAdapter(delegate);\n\t\tHealth status = Health.up().build();\n\t\tgiven(delegate.health()).willReturn(status);\n\t\tStepVerifier.create(adapter.health()).expectNext(status).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid delegateThrowError() {\n\t\tHealthIndicator delegate = mock(HealthIndicator.class);\n\t\tHealthIndicatorAdapter adapter = new HealthIndicatorAdapter(delegate);\n\t\tgiven(delegate.health()).willThrow(new IllegalStateException(\"Expected\"));\n\t\tStepVerifier.create(adapter.health()).expectError(IllegalStateException.class).verify(Duration.ofSeconds(10));\n\t}\n\n\t@Test\n\tvoid delegateRunsOnTheElasticScheduler() {\n\t\tString currentThread = Thread.currentThread().getName();\n\t\tHealthIndicator delegate = () -> Health\n\t\t\t.status(Thread.currentThread().getName().equals(currentThread) ? Status.DOWN : Status.UP)\n\t\t\t.build();\n\t\tHealthIndicatorAdapter adapter = new HealthIndicatorAdapter(delegate);\n\t\tStepVerifier.create(adapter.health())\n\t\t\t.expectNext(Health.status(Status.UP).build())\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/HealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthIndicator}.\n *\n * @author Phillip Webb\n */\nclass HealthIndicatorTests {\n\n\tprivate final HealthIndicator indicator = () -> Health.up().withDetail(\"spring\", \"boot\").build();\n\n\t@Test\n\tvoid getHealthWhenIncludeDetailsIsTrueReturnsHealthWithDetails() {\n\t\tHealth health = this.indicator.health(true);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getHealthWhenIncludeDetailsIsFalseReturnsHealthWithoutDetails() {\n\t\tHealth health = this.indicator.health(false);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/HealthTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link Health}.\n *\n * @author Phillip Webb\n * @author Michael Pratt\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass HealthTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid statusMustNotBeNull() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Health.Builder(null, null))\n\t\t\t.withMessageContaining(\"'status' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithStatus() {\n\t\tHealth health = Health.status(Status.UP).build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid createWithDetails() {\n\t\tHealth health = new Health.Builder(Status.UP, Collections.singletonMap(\"a\", \"b\")).build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tHealth h1 = new Health.Builder(Status.UP, Collections.singletonMap(\"a\", \"b\")).build();\n\t\tHealth h2 = new Health.Builder(Status.UP, Collections.singletonMap(\"a\", \"b\")).build();\n\t\tHealth h3 = new Health.Builder(Status.UP).build();\n\t\tassertThat(h1).isEqualTo(h1);\n\t\tassertThat(h1).isEqualTo(h2);\n\t\tassertThat(h1).isNotEqualTo(h3);\n\t\tassertThat(h1).hasSameHashCodeAs(h1);\n\t\tassertThat(h1).hasSameHashCodeAs(h2);\n\t\tassertThat(h1.hashCode()).isNotEqualTo(h3.hashCode());\n\t}\n\n\t@Test\n\tvoid withException() {\n\t\tRuntimeException ex = new RuntimeException(\"bang\");\n\t\tHealth health = new Health.Builder(Status.UP, Collections.singletonMap(\"a\", \"b\")).withException(ex).build();\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"b\"),\n\t\t\t\tentry(\"error\", \"java.lang.RuntimeException: bang\"));\n\t}\n\n\t@Test\n\tvoid withDetails() {\n\t\tHealth health = new Health.Builder(Status.UP, Collections.singletonMap(\"a\", \"b\")).withDetail(\"c\", \"d\").build();\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"b\"), entry(\"c\", \"d\"));\n\t}\n\n\t@Test\n\tvoid withDetailsMap() {\n\t\tMap<String, Object> details = new LinkedHashMap<>();\n\t\tdetails.put(\"a\", \"b\");\n\t\tdetails.put(\"c\", \"d\");\n\t\tHealth health = Health.up().withDetails(details).build();\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"b\"), entry(\"c\", \"d\"));\n\t}\n\n\t@Test\n\tvoid withDetailsMapDuplicateKeys() {\n\t\tMap<String, Object> details = new LinkedHashMap<>();\n\t\tdetails.put(\"c\", \"d\");\n\t\tdetails.put(\"a\", \"e\");\n\t\tHealth health = Health.up().withDetail(\"a\", \"b\").withDetails(details).build();\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"e\"), entry(\"c\", \"d\"));\n\t}\n\n\t@Test\n\tvoid withDetailsMultipleMaps() {\n\t\tMap<String, Object> details1 = new LinkedHashMap<>();\n\t\tdetails1.put(\"a\", \"b\");\n\t\tdetails1.put(\"c\", \"d\");\n\t\tMap<String, Object> details2 = new LinkedHashMap<>();\n\t\tdetails1.put(\"a\", \"e\");\n\t\tdetails1.put(\"1\", \"2\");\n\t\tHealth health = Health.up().withDetails(details1).withDetails(details2).build();\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"e\"), entry(\"c\", \"d\"), entry(\"1\", \"2\"));\n\t}\n\n\t@Test\n\tvoid unknownWithDetails() {\n\t\tHealth health = new Health.Builder().unknown().withDetail(\"a\", \"b\").build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid unknown() {\n\t\tHealth health = new Health.Builder().unknown().build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UNKNOWN);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid upWithDetails() {\n\t\tHealth health = new Health.Builder().up().withDetail(\"a\", \"b\").build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid up() {\n\t\tHealth health = new Health.Builder().up().build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid downWithException() {\n\t\tRuntimeException ex = new RuntimeException(\"bang\");\n\t\tHealth health = Health.down(ex).build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"error\", \"java.lang.RuntimeException: bang\"));\n\t}\n\n\t@Test\n\tvoid down() {\n\t\tHealth health = Health.down().build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid outOfService() {\n\t\tHealth health = Health.outOfService().build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid statusCode() {\n\t\tHealth health = Health.status(\"UP\").build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid status() {\n\t\tHealth health = Health.status(Status.UP).build();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n\t@Test\n\tvoid serializeWithJacksonReturnsValidJson() throws Exception {\n\t\tHealth health = Health.down().withDetail(\"a\", \"b\").build();\n\t\tJsonMapper mapper = new JsonMapper();\n\t\tString json = mapper.writeValueAsString(health);\n\t\tassertThat(json).isEqualTo(\"{\\\"details\\\":{\\\"a\\\":\\\"b\\\"},\\\"status\\\":\\\"DOWN\\\"}\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/MapCompositeHealthContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.HealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MapCompositeHealthContributor}.\n *\n * @author Phillip Webb\n */\nclass MapCompositeHealthContributorTests\n\t\textends MapCompositeTests<CompositeHealthContributor, HealthContributor, Entry> {\n\n\t@Override\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tprotected CompositeHealthContributor create(Map<String, String> map,\n\t\t\t@Nullable Function<String, HealthContributor> valueAdapter) {\n\t\treturn new MapCompositeHealthContributor<>(map, valueAdapter);\n\t}\n\n\t@Override\n\tprotected Stream<Entry> stream(CompositeHealthContributor composite) {\n\t\treturn composite.stream();\n\t}\n\n\t@Override\n\tprotected @Nullable HealthContributor getContributor(CompositeHealthContributor composite, String name) {\n\t\treturn composite.getContributor(name);\n\t}\n\n\t@Override\n\tprotected HealthContributor createContributor(String data) {\n\t\treturn (HealthIndicator) () -> Health.up().withDetail(\"data\", data).build();\n\t}\n\n\t@Override\n\tprotected @Nullable String getData(HealthContributor contributor) {\n\t\tHealth health = ((HealthIndicator) contributor).health();\n\t\tassertThat(health).isNotNull();\n\t\treturn (String) health.getDetails().get(\"data\");\n\t}\n\n\t@Override\n\tprotected String getName(Entry entry) {\n\t\treturn entry.name();\n\t}\n\n\t@Override\n\tprotected HealthContributor getContributor(Entry entry) {\n\t\treturn entry.contributor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/MapCompositeReactiveHealthContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MapCompositeReactiveHealthContributor}.\n *\n * @author Phillip Webb\n */\nclass MapCompositeReactiveHealthContributorTests\n\t\textends MapCompositeTests<CompositeReactiveHealthContributor, ReactiveHealthContributor, Entry> {\n\n\t@Override\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tprotected CompositeReactiveHealthContributor create(Map<String, String> map,\n\t\t\t@Nullable Function<String, ReactiveHealthContributor> valueAdapter) {\n\t\treturn new MapCompositeReactiveHealthContributor<>(map, valueAdapter);\n\t}\n\n\t@Override\n\tprotected Stream<Entry> stream(CompositeReactiveHealthContributor composite) {\n\t\treturn composite.stream();\n\t}\n\n\t@Override\n\tprotected @Nullable ReactiveHealthContributor getContributor(CompositeReactiveHealthContributor composite,\n\t\t\tString name) {\n\t\treturn composite.getContributor(name);\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributor createContributor(String data) {\n\t\treturn (ReactiveHealthIndicator) () -> Mono.just(Health.up().withDetail(\"data\", data).build());\n\t}\n\n\t@Override\n\tprotected @Nullable String getData(ReactiveHealthContributor contributor) {\n\t\tHealth health = ((ReactiveHealthIndicator) contributor).health().block();\n\t\tassertThat(health).isNotNull();\n\t\treturn (String) health.getDetails().get(\"data\");\n\t}\n\n\t@Override\n\tprotected String getName(Entry entry) {\n\t\treturn entry.name();\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributor getContributor(Entry entry) {\n\t\treturn entry.contributor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/MapCompositeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Base class for {@link Map} backed composites.\n *\n * @param <T> the composite type\n * @param <C> the contributor type\n * @param <E> the entry type\n * @author Phillip Webb\n * @author Guirong Hu\n */\nabstract class MapCompositeTests<T, C, E> {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenMapIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createWithData(null, Function.identity()))\n\t\t\t.withMessage(\"'map' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenValueAdapterIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> createWithData(Collections.emptyMap(), null))\n\t\t\t.withMessage(\"'valueAdapter' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenMapContainsNullValueThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> createWithData(Collections.singletonMap(\"test\", null), Function.identity()))\n\t\t\t.withMessage(\"'map' must not contain null values\");\n\t}\n\n\t@Test\n\tvoid createWhenMapContainsNullKeyThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> createWithData(Collections.singletonMap(null, \"test\"), Function.identity()))\n\t\t\t.withMessage(\"'map' must not contain null keys\");\n\t}\n\n\t@Test\n\tvoid createWhenMapContainsKeyWithSlashThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> createWithData(Collections.singletonMap(\"test/key\", \"test\"), Function.identity()))\n\t\t\t.withMessage(\"'map' keys must not contain a '/'\");\n\t}\n\n\t@Test\n\tvoid streamReturnsAdaptedEntries() {\n\t\tT composite = create();\n\t\tList<E> streamed = stream(composite).toList();\n\t\tassertThat(streamed).hasSize(2);\n\t\tE one = streamed.get(0);\n\t\tE two = streamed.get(1);\n\t\tassertThat(getName(one)).isEqualTo(\"one\");\n\t\tassertThat(getData(getContributor(one))).isEqualTo(\"eno\");\n\t\tassertThat(getName(two)).isEqualTo(\"two\");\n\t\tassertThat(getData(getContributor(two))).isEqualTo(\"owt\");\n\t}\n\n\t@Test\n\tvoid getContributorReturnsAdaptedEntry() {\n\t\tT composite = create();\n\t\tassertThat(getContributorData(composite, \"one\")).isEqualTo(\"eno\");\n\t\tassertThat(getContributorData(composite, \"two\")).isEqualTo(\"owt\");\n\t}\n\n\t@Test\n\tvoid getContributorCallsAdaptersOnlyOnce() {\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"one\", \"one\");\n\t\tmap.put(\"two\", \"two\");\n\t\tint callCount = map.size();\n\t\tAtomicInteger counter = new AtomicInteger(0);\n\t\tT composite = createWithData(map, (name) -> count(name, counter));\n\t\tassertThat(getContributorData(composite, \"one\")).isEqualTo(\"eno\");\n\t\tassertThat(counter.get()).isEqualTo(callCount);\n\t\tassertThat(getContributorData(composite, \"two\")).isEqualTo(\"owt\");\n\t\tassertThat(counter.get()).isEqualTo(callCount);\n\t}\n\n\t@Test\n\tvoid getContributorWhenNotInMapReturnsNull() {\n\t\tT composite = create();\n\t\tassertThat(getContributor(composite, \"missing\")).isNull();\n\t}\n\n\tprivate String count(CharSequence charSequence, AtomicInteger counter) {\n\t\tcounter.incrementAndGet();\n\t\treturn reverse(charSequence);\n\t}\n\n\tprivate String reverse(CharSequence charSequence) {\n\t\treturn new StringBuilder(charSequence).reverse().toString();\n\t}\n\n\tprivate T create() {\n\t\tMap<String, String> map = new LinkedHashMap<>();\n\t\tmap.put(\"one\", \"one\");\n\t\tmap.put(\"two\", \"two\");\n\t\treturn createWithData(map, this::reverse);\n\t}\n\n\tprivate T createWithData(Map<String, String> map, Function<String, String> dataAdapter) {\n\t\treturn create(map, (dataAdapter != null) ? (key) -> createContributor(dataAdapter.apply(key)) : null);\n\t}\n\n\tprivate @Nullable String getContributorData(T composite, String name) {\n\t\tC contributor = getContributor(composite, name);\n\t\tassertThat(contributor).isNotNull();\n\t\treturn getData(contributor);\n\t}\n\n\tprotected abstract T create(Map<String, String> map, @Nullable Function<String, C> valueAdapter);\n\n\tprotected abstract Stream<E> stream(T composite);\n\n\tprotected abstract @Nullable C getContributor(T composite, String name);\n\n\tprotected abstract C createContributor(String data);\n\n\tprotected abstract @Nullable String getData(C contributor);\n\n\tprotected abstract String getName(E entry);\n\n\tprotected abstract C getContributor(E entry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/PingHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PingHealthIndicator}.\n *\n * @author Phillip Webb\n */\nclass PingHealthIndicatorTests {\n\n\t@Test\n\tvoid indicatesUp() {\n\t\tPingHealthIndicator healthIndicator = new PingHealthIndicator();\n\t\tassertThat(healthIndicator.health().getStatus()).isEqualTo(Status.UP);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/ReactiveHealthContributorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveHealthContributor}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass ReactiveHealthContributorTests {\n\n\t@Test\n\tvoid adaptWhenHealthIndicatorReturnsHealthIndicatorReactiveAdapter() {\n\t\tHealthIndicator indicator = () -> Health.outOfService().build();\n\t\tReactiveHealthContributor adapted = ReactiveHealthContributor.adapt(indicator);\n\t\tassertThat(adapted).isInstanceOf(HealthIndicatorAdapter.class);\n\t\tHealth health = ((ReactiveHealthIndicator) adapted).health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t}\n\n\t@Test\n\tvoid adaptWhenCompositeHealthContributorReturnsCompositeHealthContributorReactiveAdapter() {\n\t\tHealthIndicator indicator = () -> Health.outOfService().build();\n\t\tCompositeHealthContributor contributor = CompositeHealthContributor\n\t\t\t.fromMap(Collections.singletonMap(\"a\", indicator));\n\t\tReactiveHealthContributor adapted = ReactiveHealthContributor.adapt(contributor);\n\t\tassertThat(adapted).isInstanceOf(CompositeHealthContributorAdapter.class);\n\t\tReactiveHealthContributor contained = ((CompositeReactiveHealthContributor) adapted).getContributor(\"a\");\n\t\tassertThat(contained).isNotNull();\n\t\tHealth health = ((ReactiveHealthIndicator) contained).health().block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.OUT_OF_SERVICE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/ReactiveHealthContributorsAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Answers;\n\nimport org.springframework.boot.health.contributor.HealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link ReactiveHealthContributorsAdapter}.\n *\n * @author Phillip Webb\n */\nclass ReactiveHealthContributorsAdapterTests {\n\n\t@Test\n\tvoid getContributorWhenNoneReturnsNull() {\n\t\tReactiveHealthIndicator a = mock(ReactiveHealthIndicator.class,\n\t\t\t\twithSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));\n\t\tCompositeReactiveHealthContributor delegate = CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a));\n\t\tReactiveHealthContributorsAdapter adapter = createAdapter(delegate);\n\t\tassertThat(adapter.getContributor(\"x\")).isNull();\n\t}\n\n\t@Test\n\tvoid getContributorReturnsAdaptedContributor() {\n\t\tReactiveHealthIndicator a = mock(ReactiveHealthIndicator.class,\n\t\t\t\twithSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));\n\t\tCompositeReactiveHealthContributor delegate = CompositeReactiveHealthContributor.fromMap(Map.of(\"a\", a));\n\t\tReactiveHealthContributorsAdapter adapter = createAdapter(delegate);\n\t\tassertThat(adapter.getContributor(\"a\")).isInstanceOf(ReactiveHealthIndicatorAdapter.class);\n\t\tassertThat(adapter.getContributor(\"a\")).extracting(\"delegate\").isSameAs(a);\n\t}\n\n\t@Test\n\tvoid streamAdaptsEntries() {\n\t\tReactiveHealthIndicator a = mock(ReactiveHealthIndicator.class,\n\t\t\t\twithSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));\n\t\tReactiveHealthIndicator b = mock(ReactiveHealthIndicator.class,\n\t\t\t\twithSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));\n\t\tMap<String, ReactiveHealthIndicator> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", a);\n\t\tmap.put(\"b\", b);\n\t\tCompositeReactiveHealthContributor delegate = CompositeReactiveHealthContributor.fromMap(map);\n\t\tReactiveHealthContributorsAdapter adapter = createAdapter(delegate);\n\t\tassertThat(adapter.stream().map(Entry::name)).containsExactly(\"a\", \"b\");\n\t\tObject[] contributors = adapter.stream().map(Entry::contributor).toArray();\n\t\tassertThat(contributors[0]).isInstanceOf(ReactiveHealthIndicatorAdapter.class);\n\t\tassertThat(contributors[0]).extracting(\"delegate\").isSameAs(a);\n\t\tassertThat(contributors[1]).isInstanceOf(ReactiveHealthIndicatorAdapter.class);\n\t\tassertThat(contributors[1]).extracting(\"delegate\").isSameAs(b);\n\t}\n\n\tprotected ReactiveHealthContributorsAdapter createAdapter(CompositeReactiveHealthContributor delegate) {\n\t\treturn new CompositeReactiveHealthContributorAdapter(delegate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/ReactiveHealthContributorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Answers;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link ReactiveHealthContributors}.\n *\n * @author Phillip Webb\n */\nclass ReactiveHealthContributorsTests {\n\n\t@Test\n\tvoid iteratorAdaptsStream() {\n\t\tEntry e1 = new Entry(\"e1\", mock(ReactiveHealthIndicator.class));\n\t\tEntry e2 = new Entry(\"e2\", mock(ReactiveHealthIndicator.class));\n\t\tReactiveHealthContributors contributors = new ReactiveHealthContributors() {\n\n\t\t\t@Override\n\t\t\tpublic Stream<Entry> stream() {\n\t\t\t\treturn Stream.of(e1, e2);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable ReactiveHealthContributor getContributor(String name) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t};\n\t\tassertThat(contributors).containsExactly(e1, e2);\n\t}\n\n\t@Test\n\tvoid asHealthContributorsReturnsAdapter() {\n\t\tReactiveHealthContributors contributors = mock(ReactiveHealthContributors.class,\n\t\t\t\twithSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));\n\t\tassertThat(contributors.asHealthContributors()).isInstanceOf(ReactiveHealthContributorsAdapter.class);\n\t}\n\n\t@Test\n\tvoid ofCreateComposite() {\n\t\tReactiveHealthContributors c = mock(ReactiveHealthContributors.class);\n\t\tassertThat(ReactiveHealthContributors.of(c)).isInstanceOf(CompositeReactiveHealthContributors.class);\n\t}\n\n\t@Test\n\tvoid adaptWhenNullReturnsNull() {\n\t\tassertThat(ReactiveHealthContributors.adapt(null)).isNull();\n\t}\n\n\t@Test\n\tvoid adaptReturnsAdapter() {\n\t\tHealthContributors c = mock(HealthContributors.class);\n\t\tassertThat(ReactiveHealthContributors.adapt(c)).isInstanceOf(HealthContributorsAdapter.class);\n\t}\n\n\t@Test\n\tvoid createEntryWhenNameIsEmptyThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Entry(\"\", mock(ReactiveHealthIndicator.class)))\n\t\t\t.withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createEntryWhenContributorIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Entry(\"test\", null))\n\t\t\t.withMessage(\"'contributor' must not be null\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/ReactiveHealthIndicatorAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveHealthIndicatorAdapter}.\n *\n * @author Phillip Webb\n */\nclass ReactiveHealthIndicatorAdapterTests {\n\n\t@Test\n\tvoid getHealthReturnsDetails() {\n\t\tReactiveHealthIndicator reactiveHealthIndicator = () -> Mono\n\t\t\t.just(Health.up().withDetail(\"test\", \"test\").build());\n\t\tReactiveHealthIndicatorAdapter adapter = new ReactiveHealthIndicatorAdapter(reactiveHealthIndicator);\n\t\tHealth health = adapter.health();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"test\", \"test\");\n\t}\n\n\t@Test\n\tvoid getHealthWithoutDetailsReturnsHealth() {\n\t\tReactiveHealthIndicator reactiveHealthIndicator = () -> Mono\n\t\t\t.just(Health.up().withDetail(\"test\", \"test\").build());\n\t\tReactiveHealthIndicatorAdapter adapter = new ReactiveHealthIndicatorAdapter(reactiveHealthIndicator);\n\t\tHealth health = adapter.health(false);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/ReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveHealthIndicator}.\n *\n * @author Phillip Webb\n */\nclass ReactiveHealthIndicatorTests {\n\n\tprivate final ReactiveHealthIndicator indicator = () -> Mono.just(Health.up().withDetail(\"spring\", \"boot\").build());\n\n\t@Test\n\tvoid asHealthContributor() {\n\t\tHealthIndicator adapted = this.indicator.asHealthContributor();\n\t\tHealth health = adapted.health(true);\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getHealthWhenIncludeDetailsIsTrueReturnsHealthWithDetails() {\n\t\tHealth health = this.indicator.health(true).block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"spring\", \"boot\");\n\t}\n\n\t@Test\n\tvoid getHealthWhenIncludeDetailsIsFalseReturnsHealthWithoutDetails() {\n\t\tHealth health = this.indicator.health(false).block();\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/contributor/StatusTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.contributor;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link Status}.\n *\n * @author Phillip Webb\n */\nclass StatusTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenCodeIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Status(null, \"\"))\n\t\t\t.withMessage(\"'code' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenDescriptionIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new Status(\"code\", null))\n\t\t\t.withMessage(\"'description' must not be null\");\n\t}\n\n\t@Test\n\tvoid getCodeReturnsCode() {\n\t\tStatus status = new Status(\"spring\", \"boot\");\n\t\tassertThat(status.getCode()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getDescriptionReturnsDescription() {\n\t\tStatus status = new Status(\"spring\", \"boot\");\n\t\tassertThat(status.getDescription()).isEqualTo(\"boot\");\n\t}\n\n\t@Test\n\tvoid equalsAndHashCode() {\n\t\tStatus one = new Status(\"spring\", \"boot\");\n\t\tStatus two = new Status(\"spring\", \"framework\");\n\t\tStatus three = new Status(\"spock\", \"framework\");\n\t\tassertThat(one).isEqualTo(one).isEqualTo(two).isNotEqualTo(three);\n\t\tassertThat(one).hasSameHashCodeAs(two);\n\t}\n\n\t@Test\n\tvoid toStringReturnsCode() {\n\t\tassertThat(Status.OUT_OF_SERVICE.getCode()).isEqualTo(\"OUT_OF_SERVICE\");\n\t}\n\n\t@Test\n\tvoid serializeWithJacksonReturnsValidJson() throws Exception {\n\t\tStatus status = new Status(\"spring\", \"boot\");\n\t\tJsonMapper mapper = new JsonMapper();\n\t\tString json = mapper.writeValueAsString(status);\n\t\tassertThat(json).isEqualTo(\"{\\\"description\\\":\\\"boot\\\",\\\"status\\\":\\\"spring\\\"}\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/registry/AbstractHealthContributorRegistryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link AbstractRegistry}.\n *\n * @param <C> the contributor type\n * @param <E> the entry type\n * @author Phillip Webb\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\nabstract class AbstractHealthContributorRegistryTests<C, E> {\n\n\tprivate AbstractRegistry<C, E> registry;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.registry = createRegistry(Collections.emptyList(), null);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerContributorWhenNameIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.registry.registerContributor(null, mockHealthIndicator()))\n\t\t\t.withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerContributorWhenContributorIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.registry.registerContributor(\"one\", null))\n\t\t\t.withMessage(\"'contributor' must not be null\");\n\t}\n\n\t@Test\n\tvoid registerContributorRegistersContributors() {\n\t\tC c1 = mockHealthIndicator();\n\t\tC c2 = mockHealthIndicator();\n\t\tthis.registry.registerContributor(\"one\", c1);\n\t\tthis.registry.registerContributor(\"two\", c2);\n\t\tassertThat((Iterable<?>) this.registry).hasSize(2);\n\t\tassertThat(this.registry.getContributor(\"one\")).isSameAs(c1);\n\t\tassertThat(this.registry.getContributor(\"two\")).isSameAs(c2);\n\t}\n\n\t@Test\n\tvoid registerContributorWhenNameAlreadyUsedThrowsException() {\n\t\tthis.registry.registerContributor(\"one\", mockHealthIndicator());\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.registry.registerContributor(\"one\", mockHealthIndicator()))\n\t\t\t.withMessageContaining(\"A contributor named \\\"one\\\" has already been registered\");\n\t}\n\n\t@Test\n\tvoid unregisterContributorUnregistersContributor() {\n\t\tC c1 = mockHealthIndicator();\n\t\tC c2 = mockHealthIndicator();\n\t\tthis.registry.registerContributor(\"one\", c1);\n\t\tthis.registry.registerContributor(\"two\", c2);\n\t\tassertThat((Iterable<?>) this.registry).hasSize(2);\n\t\tC two = this.registry.unregisterContributor(\"two\");\n\t\tassertThat(two).isSameAs(c2);\n\t\tassertThat((Iterable<?>) this.registry).hasSize(1);\n\t}\n\n\t@Test\n\tvoid unregisterContributorWhenUnknownReturnsNull() {\n\t\tthis.registry.registerContributor(\"one\", mockHealthIndicator());\n\t\tassertThat((Iterable<?>) this.registry).hasSize(1);\n\t\tObject two = this.registry.unregisterContributor(\"two\");\n\t\tassertThat(two).isNull();\n\t\tassertThat((Iterable<?>) this.registry).hasSize(1);\n\t}\n\n\t@Test\n\tvoid getContributorReturnsContributor() {\n\t\tC c1 = mockHealthIndicator();\n\t\tthis.registry.registerContributor(\"one\", c1);\n\t\tassertThat(this.registry.getContributor(\"one\")).isEqualTo(c1);\n\t}\n\n\t@Test\n\tvoid streamStreamsContributors() {\n\t\tC c1 = mockHealthIndicator();\n\t\tC c2 = mockHealthIndicator();\n\t\tthis.registry.registerContributor(\"one\", c1);\n\t\tthis.registry.registerContributor(\"two\", c2);\n\t\tList<E> streamed = this.registry.stream().toList();\n\t\tassertThat(streamed).hasSize(2);\n\t\tE first = streamed.get(0);\n\t\tE second = streamed.get(1);\n\t\tassertThat(name(first)).isEqualTo(\"one\");\n\t\tassertThat(contributor(first)).isEqualTo(c1);\n\t\tassertThat(name(second)).isEqualTo(\"two\");\n\t\tassertThat(contributor(second)).isEqualTo(c2);\n\t}\n\n\t@Test\n\tvoid nameValidatorsValidateMapKeys() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> createRegistry(testValidator(), (initialRegistrations) -> {\n\t\t\tinitialRegistrations.accept(\"ok\", mockHealthIndicator());\n\t\t\tinitialRegistrations.accept(\"fail\", mockHealthIndicator());\n\t\t})).withMessage(\"Failed validation\");\n\t}\n\n\t@Test\n\tvoid nameValidatorsValidateRegisteredName() {\n\t\tAbstractRegistry<C, E> registry = createRegistry(testValidator(), null);\n\t\tregistry.registerContributor(\"ok\", mockHealthIndicator());\n\t\tassertThatIllegalStateException().isThrownBy(() -> registry.registerContributor(\"fail\", mockHealthIndicator()))\n\t\t\t.withMessage(\"Failed validation\");\n\t}\n\n\tprivate List<HealthContributorNameValidator> testValidator() {\n\t\treturn List.of((name) -> Assert.state(!\"fail\".equals(name), \"Failed validation\"));\n\t}\n\n\tprotected abstract AbstractRegistry<C, E> createRegistry(\n\t\t\tCollection<? extends HealthContributorNameValidator> nameValidators,\n\t\t\t@Nullable Consumer<BiConsumer<String, C>> initialRegistrations);\n\n\tprotected abstract C mockHealthIndicator();\n\n\tprotected abstract String name(E entry);\n\n\tprotected abstract C contributor(E entry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/registry/DefaultHealthContributorRegistryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport java.util.Collection;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.health.contributor.HealthContributors.Entry;\nimport org.springframework.boot.health.contributor.HealthIndicator;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultHealthContributorRegistry}.\n *\n * @author Phillip Webb\n */\nclass DefaultHealthContributorRegistryTests\n\t\textends AbstractHealthContributorRegistryTests<HealthContributor, HealthContributors.Entry> {\n\n\t@Override\n\tprotected AbstractRegistry<HealthContributor, Entry> createRegistry(\n\t\t\tCollection<? extends HealthContributorNameValidator> nameValidators,\n\t\t\t@Nullable Consumer<BiConsumer<String, HealthContributor>> initialRegistrations) {\n\t\treturn new DefaultHealthContributorRegistry(nameValidators, initialRegistrations);\n\t}\n\n\t@Override\n\tprotected HealthContributor mockHealthIndicator() {\n\t\treturn mock(HealthIndicator.class);\n\t}\n\n\t@Override\n\tprotected String name(Entry entry) {\n\t\treturn entry.name();\n\t}\n\n\t@Override\n\tprotected HealthContributor contributor(Entry entry) {\n\t\treturn entry.contributor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-health/src/test/java/org/springframework/boot/health/registry/DefaultReactiveHealthContributorRegistryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.health.registry;\n\nimport java.util.Collection;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributors.Entry;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultReactiveHealthContributorRegistry}.\n *\n * @author Phillip Webb\n */\nclass DefaultReactiveHealthContributorRegistryTests\n\t\textends AbstractHealthContributorRegistryTests<ReactiveHealthContributor, ReactiveHealthContributors.Entry> {\n\n\t@Override\n\tprotected AbstractRegistry<ReactiveHealthContributor, Entry> createRegistry(\n\t\t\tCollection<? extends HealthContributorNameValidator> nameValidators,\n\t\t\t@Nullable Consumer<BiConsumer<String, ReactiveHealthContributor>> initialRegistrations) {\n\t\treturn new DefaultReactiveHealthContributorRegistry(nameValidators, initialRegistrations);\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributor mockHealthIndicator() {\n\t\treturn mock(ReactiveHealthIndicator.class);\n\t}\n\n\t@Override\n\tprotected String name(Entry entry) {\n\t\treturn entry.name();\n\t}\n\n\t@Override\n\tprotected ReactiveHealthContributor contributor(Entry entry) {\n\t\treturn entry.contributor();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Hibernate\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-jpa\"))\n\tapi(\"org.hibernate.orm:hibernate-core\")\n\tapi(\"org.springframework:spring-orm\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"org.hibernate.orm:hibernate-micrometer\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-liquibase\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"com.zaxxer:HikariCP\")\n\ttestImplementation(\"javax.cache:cache-api\")\n\ttestImplementation(\"org.ehcache:ehcache\") {\n\t\tartifact {\n\t\t\tclassifier = 'jakarta'\n\t\t}\n\t}\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.hibernate.orm:hibernate-envers\")\n\ttestImplementation(\"org.hibernate.orm:hibernate-jcache\")\n\ttestImplementation(\"org.springframework:spring-context-support\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/SpringImplicitNamingStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate;\n\nimport org.hibernate.boot.model.naming.Identifier;\nimport org.hibernate.boot.model.naming.ImplicitJoinTableNameSource;\nimport org.hibernate.boot.model.naming.ImplicitNamingStrategy;\nimport org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;\n\n/**\n * Hibernate {@link ImplicitNamingStrategy} that follows Spring recommended naming\n * conventions. Naming conventions implemented here are identical to\n * {@link ImplicitNamingStrategyJpaCompliantImpl} with the exception that join table names\n * are of the form\n * <code>{owning_physical_table_name}_{association_owning_property_name}</code>.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class SpringImplicitNamingStrategy extends ImplicitNamingStrategyJpaCompliantImpl {\n\n\t@Override\n\tpublic Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {\n\t\tString name = source.getOwningPhysicalTableName() + \"_\"\n\t\t\t\t+ source.getAssociationOwningAttributePath().getProperty();\n\t\treturn toIdentifier(name, source.getBuildingContext());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/SpringJtaPlatform.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate;\n\nimport jakarta.transaction.TransactionManager;\nimport jakarta.transaction.UserTransaction;\nimport org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.transaction.jta.JtaTransactionManager;\nimport org.springframework.util.Assert;\n\n/**\n * Generic Hibernate {@link AbstractJtaPlatform} implementation that simply resolves the\n * JTA {@link UserTransaction} and {@link TransactionManager} from the Spring-configured\n * {@link JtaTransactionManager} implementation.\n *\n * @author Josh Long\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class SpringJtaPlatform extends AbstractJtaPlatform {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate final JtaTransactionManager transactionManager;\n\n\tpublic SpringJtaPlatform(JtaTransactionManager transactionManager) {\n\t\tAssert.notNull(transactionManager, \"'transactionManager' must not be null\");\n\t\tthis.transactionManager = transactionManager;\n\t}\n\n\t@Override\n\tprotected @Nullable TransactionManager locateTransactionManager() {\n\t\treturn this.transactionManager.getTransactionManager();\n\t}\n\n\t@Override\n\tprotected @Nullable UserTransaction locateUserTransaction() {\n\t\treturn this.transactionManager.getUserTransaction();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/HibernateDefaultDdlAutoProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.stream.StreamSupport;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.jdbc.SchemaManagement;\nimport org.springframework.boot.jdbc.SchemaManagementProvider;\n\n/**\n * A {@link SchemaManagementProvider} that invokes a configurable number of\n * {@link SchemaManagementProvider} instances for embedded data sources only.\n *\n * @author Stephane Nicoll\n */\nclass HibernateDefaultDdlAutoProvider implements SchemaManagementProvider {\n\n\tprivate final Iterable<SchemaManagementProvider> providers;\n\n\tHibernateDefaultDdlAutoProvider(Iterable<SchemaManagementProvider> providers) {\n\t\tthis.providers = providers;\n\t}\n\n\tString getDefaultDdlAuto(DataSource dataSource) {\n\t\tif (!EmbeddedDatabaseConnection.isEmbedded(dataSource)) {\n\t\t\treturn \"none\";\n\t\t}\n\t\tSchemaManagement schemaManagement = getSchemaManagement(dataSource);\n\t\tif (SchemaManagement.MANAGED.equals(schemaManagement)) {\n\t\t\treturn \"none\";\n\t\t}\n\t\treturn \"create-drop\";\n\t}\n\n\t@Override\n\tpublic SchemaManagement getSchemaManagement(DataSource dataSource) {\n\t\treturn StreamSupport.stream(this.providers.spliterator(), false)\n\t\t\t.map((provider) -> provider.getSchemaManagement(dataSource))\n\t\t\t.filter(SchemaManagement.MANAGED::equals)\n\t\t\t.findFirst()\n\t\t\t.orElse(SchemaManagement.UNMANAGED);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/HibernateJpaAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport jakarta.persistence.EntityManager;\nimport org.hibernate.engine.spi.SessionImplementor;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.boot.transaction.jta.autoconfigure.JtaAutoConfiguration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Hibernate JPA.\n *\n * @author Phillip Webb\n * @author Josh Long\n * @author Manuel Doninger\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafter = { DataSourceAutoConfiguration.class, JtaAutoConfiguration.class,\n\t\t\t\tTransactionManagerCustomizationAutoConfiguration.class },\n\t\tbefore = { TransactionAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })\n@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class, EntityManager.class, SessionImplementor.class })\n@EnableConfigurationProperties(JpaProperties.class)\n@Import(HibernateJpaConfiguration.class)\npublic final class HibernateJpaAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/HibernateJpaConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport javax.sql.DataSource;\n\nimport org.hibernate.boot.model.naming.ImplicitNamingStrategy;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategy;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeHint;\nimport org.springframework.aot.hint.TypeHint.Builder;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.hibernate.SpringImplicitNamingStrategy;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaConfiguration.HibernateRuntimeHints;\nimport org.springframework.boot.jdbc.SchemaManagementProvider;\nimport org.springframework.boot.jdbc.metadata.CompositeDataSourcePoolMetadataProvider;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.boot.jpa.autoconfigure.JpaBaseConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\n/**\n * {@link JpaBaseConfiguration} implementation for Hibernate.\n *\n * @author Phillip Webb\n * @author Josh Long\n * @author Manuel Doninger\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(HibernateProperties.class)\n@ConditionalOnSingleCandidate(DataSource.class)\n@ImportRuntimeHints(HibernateRuntimeHints.class)\nclass HibernateJpaConfiguration extends JpaBaseConfiguration {\n\n\tprivate static final String PROVIDER_DISABLES_AUTOCOMMIT = \"hibernate.connection.provider_disables_autocommit\";\n\n\t/**\n\t * {@code NoJtaPlatform} implementations for various Hibernate versions.\n\t */\n\tprivate static final String[] NO_JTA_PLATFORM_CLASSES = {\n\t\t\t\"org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform\",\n\t\t\t\"org.hibernate.service.jta.platform.internal.NoJtaPlatform\" };\n\n\tprivate final HibernateProperties hibernateProperties;\n\n\tprivate final HibernateDefaultDdlAutoProvider defaultDdlAutoProvider;\n\n\tprivate final DataSourcePoolMetadataProvider poolMetadataProvider;\n\n\tprivate final ObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator;\n\n\tprivate final List<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers;\n\n\tHibernateJpaConfiguration(DataSource dataSource, JpaProperties jpaProperties,\n\t\t\tObjectProvider<JtaTransactionManager> jtaTransactionManager, HibernateProperties hibernateProperties,\n\t\t\tObjectProvider<Collection<DataSourcePoolMetadataProvider>> metadataProviders,\n\t\t\tObjectProvider<SchemaManagementProvider> providers,\n\t\t\tObjectProvider<PhysicalNamingStrategy> physicalNamingStrategy,\n\t\t\tObjectProvider<ImplicitNamingStrategy> implicitNamingStrategy,\n\t\t\tObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator,\n\t\t\tObjectProvider<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) {\n\t\tsuper(dataSource, jpaProperties, jtaTransactionManager);\n\t\tthis.hibernateProperties = hibernateProperties;\n\t\tthis.defaultDdlAutoProvider = new HibernateDefaultDdlAutoProvider(providers);\n\t\tthis.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider(metadataProviders.getIfAvailable());\n\t\tthis.sqlExceptionTranslator = sqlExceptionTranslator;\n\t\tthis.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers(\n\t\t\t\tphysicalNamingStrategy.getIfAvailable(), implicitNamingStrategy.getIfAvailable(),\n\t\t\t\thibernatePropertiesCustomizers.orderedStream().toList());\n\t}\n\n\tprivate List<HibernatePropertiesCustomizer> determineHibernatePropertiesCustomizers(\n\t\t\t@Nullable PhysicalNamingStrategy physicalNamingStrategy,\n\t\t\t@Nullable ImplicitNamingStrategy implicitNamingStrategy,\n\t\t\tList<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) {\n\t\tList<HibernatePropertiesCustomizer> customizers = new ArrayList<>();\n\t\tif (physicalNamingStrategy != null || implicitNamingStrategy != null) {\n\t\t\tcustomizers\n\t\t\t\t.add(new NamingStrategiesHibernatePropertiesCustomizer(physicalNamingStrategy, implicitNamingStrategy));\n\t\t}\n\t\tcustomizers.addAll(hibernatePropertiesCustomizers);\n\t\treturn customizers;\n\t}\n\n\t@Override\n\tprotected HibernateJpaVendorAdapter createJpaVendorAdapter() {\n\t\tHibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();\n\t\tthis.sqlExceptionTranslator.ifUnique(adapter.getJpaDialect()::setJdbcExceptionTranslator);\n\t\tJtaTransactionManager jtaTransactionManager = getJtaTransactionManager();\n\t\tif (jtaTransactionManager != null) {\n\t\t\tadapter.setJtaTransactionManager(jtaTransactionManager);\n\t\t}\n\t\treturn adapter;\n\t}\n\n\t@Override\n\tprotected Map<String, Object> getVendorProperties(DataSource dataSource) {\n\t\tSupplier<String> defaultDdlMode = () -> this.defaultDdlAutoProvider.getDefaultDdlAuto(dataSource);\n\t\treturn new LinkedHashMap<>(this.hibernateProperties.determineHibernateProperties(\n\t\t\t\tgetProperties().getProperties(), new HibernateSettings().ddlAuto(defaultDdlMode)\n\t\t\t\t\t.hibernatePropertiesCustomizers(this.hibernatePropertiesCustomizers)));\n\t}\n\n\t@Override\n\tprotected void customizeVendorProperties(Map<String, Object> vendorProperties) {\n\t\tsuper.customizeVendorProperties(vendorProperties);\n\t\tif (!vendorProperties.containsKey(PROVIDER_DISABLES_AUTOCOMMIT)) {\n\t\t\tconfigureProviderDisablesAutocommit(vendorProperties);\n\t\t}\n\t}\n\n\tprivate void configureProviderDisablesAutocommit(Map<String, Object> vendorProperties) {\n\t\tif (isDataSourceAutoCommitDisabled() && !isJta()) {\n\t\t\tvendorProperties.put(PROVIDER_DISABLES_AUTOCOMMIT, \"true\");\n\t\t}\n\t}\n\n\tprivate boolean isDataSourceAutoCommitDisabled() {\n\t\tDataSourcePoolMetadata poolMetadata = this.poolMetadataProvider.getDataSourcePoolMetadata(getDataSource());\n\t\treturn poolMetadata != null && Boolean.FALSE.equals(poolMetadata.getDefaultAutoCommit());\n\t}\n\n\tprivate static class NamingStrategiesHibernatePropertiesCustomizer implements HibernatePropertiesCustomizer {\n\n\t\tprivate final @Nullable PhysicalNamingStrategy physicalNamingStrategy;\n\n\t\tprivate final @Nullable ImplicitNamingStrategy implicitNamingStrategy;\n\n\t\tNamingStrategiesHibernatePropertiesCustomizer(@Nullable PhysicalNamingStrategy physicalNamingStrategy,\n\t\t\t\t@Nullable ImplicitNamingStrategy implicitNamingStrategy) {\n\t\t\tthis.physicalNamingStrategy = physicalNamingStrategy;\n\t\t\tthis.implicitNamingStrategy = implicitNamingStrategy;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(Map<String, Object> hibernateProperties) {\n\t\t\tif (this.physicalNamingStrategy != null) {\n\t\t\t\thibernateProperties.put(\"hibernate.physical_naming_strategy\", this.physicalNamingStrategy);\n\t\t\t}\n\t\t\tif (this.implicitNamingStrategy != null) {\n\t\t\t\thibernateProperties.put(\"hibernate.implicit_naming_strategy\", this.implicitNamingStrategy);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class HibernateRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate static final Consumer<Builder> INVOKE_DECLARED_CONSTRUCTORS = TypeHint\n\t\t\t.builtWith(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tfor (String noJtaPlatformClass : NO_JTA_PLATFORM_CLASSES) {\n\t\t\t\thints.reflection().registerType(TypeReference.of(noJtaPlatformClass), INVOKE_DECLARED_CONSTRUCTORS);\n\t\t\t}\n\t\t\thints.reflection().registerType(SpringImplicitNamingStrategy.class, INVOKE_DECLARED_CONSTRUCTORS);\n\t\t\thints.reflection().registerType(PhysicalNamingStrategySnakeCaseImpl.class, INVOKE_DECLARED_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/HibernateProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;\nimport org.hibernate.cfg.MappingSettings;\nimport org.hibernate.cfg.PersistenceSettings;\nimport org.hibernate.cfg.SchemaToolingSettings;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.hibernate.SpringImplicitNamingStrategy;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration properties for Hibernate.\n *\n * @author Stephane Nicoll\n * @author Chris Bono\n * @since 4.0.0\n * @see JpaProperties\n */\n@ConfigurationProperties(\"spring.jpa.hibernate\")\npublic class HibernateProperties {\n\n\tprivate static final String DISABLED_SCANNER_CLASS = \"org.hibernate.boot.archive.scan.internal.DisabledScanner\";\n\n\tprivate final Naming naming = new Naming();\n\n\t/**\n\t * DDL mode. This is actually a shortcut for the \"hibernate.hbm2ddl.auto\" property.\n\t * Defaults to \"create-drop\" when using an embedded database and no schema manager was\n\t * detected. Otherwise, defaults to \"none\".\n\t */\n\tprivate @Nullable String ddlAuto;\n\n\tpublic @Nullable String getDdlAuto() {\n\t\treturn this.ddlAuto;\n\t}\n\n\tpublic void setDdlAuto(@Nullable String ddlAuto) {\n\t\tthis.ddlAuto = ddlAuto;\n\t}\n\n\tpublic Naming getNaming() {\n\t\treturn this.naming;\n\t}\n\n\t/**\n\t * Determine the configuration properties for the initialization of the main Hibernate\n\t * EntityManagerFactory based on standard JPA properties and\n\t * {@link HibernateSettings}.\n\t * @param jpaProperties standard JPA properties\n\t * @param settings the settings to apply when determining the configuration properties\n\t * @return the Hibernate properties to use\n\t */\n\tpublic Map<String, Object> determineHibernateProperties(Map<String, String> jpaProperties,\n\t\t\tHibernateSettings settings) {\n\t\tAssert.notNull(jpaProperties, \"'jpaProperties' must not be null\");\n\t\tAssert.notNull(settings, \"'settings' must not be null\");\n\t\treturn getAdditionalProperties(jpaProperties, settings);\n\t}\n\n\tprivate Map<String, Object> getAdditionalProperties(Map<String, String> existing, HibernateSettings settings) {\n\t\tMap<String, Object> result = new HashMap<>(existing);\n\t\tapplyScanner(result);\n\t\tgetNaming().applyNamingStrategies(result);\n\t\tString ddlAuto = determineDdlAuto(existing, settings::getDdlAuto);\n\t\tif (StringUtils.hasText(ddlAuto) && !\"none\".equals(ddlAuto)) {\n\t\t\tresult.put(SchemaToolingSettings.HBM2DDL_AUTO, ddlAuto);\n\t\t}\n\t\telse {\n\t\t\tresult.remove(SchemaToolingSettings.HBM2DDL_AUTO);\n\t\t}\n\t\tCollection<HibernatePropertiesCustomizer> customizers = settings.getHibernatePropertiesCustomizers();\n\t\tif (!ObjectUtils.isEmpty(customizers)) {\n\t\t\tcustomizers.forEach((customizer) -> customizer.customize(result));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate void applyScanner(Map<String, Object> result) {\n\t\tif (!result.containsKey(PersistenceSettings.SCANNER) && ClassUtils.isPresent(DISABLED_SCANNER_CLASS, null)) {\n\t\t\tresult.put(PersistenceSettings.SCANNER, DISABLED_SCANNER_CLASS);\n\t\t}\n\t}\n\n\tprivate @Nullable String determineDdlAuto(Map<String, String> existing, Supplier<@Nullable String> defaultDdlAuto) {\n\t\tString ddlAuto = existing.get(SchemaToolingSettings.HBM2DDL_AUTO);\n\t\tif (ddlAuto != null) {\n\t\t\treturn ddlAuto;\n\t\t}\n\t\tif (this.ddlAuto != null) {\n\t\t\treturn this.ddlAuto;\n\t\t}\n\t\tif (existing.get(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION) != null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn defaultDdlAuto.get();\n\t}\n\n\tpublic static class Naming {\n\n\t\t/**\n\t\t * Fully qualified name of the implicit naming strategy.\n\t\t */\n\t\tprivate @Nullable String implicitStrategy;\n\n\t\t/**\n\t\t * Fully qualified name of the physical naming strategy.\n\t\t */\n\t\tprivate @Nullable String physicalStrategy;\n\n\t\tpublic @Nullable String getImplicitStrategy() {\n\t\t\treturn this.implicitStrategy;\n\t\t}\n\n\t\tpublic void setImplicitStrategy(@Nullable String implicitStrategy) {\n\t\t\tthis.implicitStrategy = implicitStrategy;\n\t\t}\n\n\t\tpublic @Nullable String getPhysicalStrategy() {\n\t\t\treturn this.physicalStrategy;\n\t\t}\n\n\t\tpublic void setPhysicalStrategy(@Nullable String physicalStrategy) {\n\t\t\tthis.physicalStrategy = physicalStrategy;\n\t\t}\n\n\t\tprivate void applyNamingStrategies(Map<String, Object> properties) {\n\t\t\tapplyNamingStrategy(properties, MappingSettings.IMPLICIT_NAMING_STRATEGY, this.implicitStrategy,\n\t\t\t\t\tSpringImplicitNamingStrategy.class::getName);\n\t\t\tapplyNamingStrategy(properties, MappingSettings.PHYSICAL_NAMING_STRATEGY, this.physicalStrategy,\n\t\t\t\t\tPhysicalNamingStrategySnakeCaseImpl.class::getName);\n\t\t}\n\n\t\tprivate void applyNamingStrategy(Map<String, Object> properties, String key, @Nullable Object strategy,\n\t\t\t\tSupplier<String> defaultStrategy) {\n\t\t\tif (strategy != null) {\n\t\t\t\tproperties.put(key, strategy);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tproperties.computeIfAbsent(key, (k) -> defaultStrategy.get());\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/HibernatePropertiesCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.Map;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the Hibernate\n * properties to customize their auto-configuration prior to use by the auto-configured\n * {@code EntityManagerFactory}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface HibernatePropertiesCustomizer {\n\n\t/**\n\t * Customize the specified JPA vendor properties.\n\t * @param hibernateProperties the JPA vendor properties to customize\n\t */\n\tvoid customize(Map<String, Object> hibernateProperties);\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/HibernateSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Settings to apply when configuring Hibernate.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class HibernateSettings {\n\n\tprivate @Nullable Supplier<String> ddlAuto;\n\n\tprivate @Nullable Collection<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers;\n\n\tpublic HibernateSettings ddlAuto(@Nullable Supplier<String> ddlAuto) {\n\t\tthis.ddlAuto = ddlAuto;\n\t\treturn this;\n\t}\n\n\tpublic @Nullable String getDdlAuto() {\n\t\treturn (this.ddlAuto != null) ? this.ddlAuto.get() : null;\n\t}\n\n\tpublic HibernateSettings hibernatePropertiesCustomizers(\n\t\t\tCollection<HibernatePropertiesCustomizer> hibernatePropertiesCustomizers) {\n\t\tthis.hibernatePropertiesCustomizers = new ArrayList<>(hibernatePropertiesCustomizers);\n\t\treturn this;\n\t}\n\n\tpublic @Nullable Collection<HibernatePropertiesCustomizer> getHibernatePropertiesCustomizers() {\n\t\treturn this.hibernatePropertiesCustomizers;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/metrics/HibernateMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure.metrics;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.PersistenceException;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.stat.HibernateMetrics;\n\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available\n * Hibernate {@link EntityManagerFactory} instances that have statistics enabled.\n *\n * @author Rui Figueira\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = HibernateJpaAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnClass({ EntityManagerFactory.class, SessionFactory.class, HibernateMetrics.class, MeterRegistry.class })\n@ConditionalOnBean({ EntityManagerFactory.class, MeterRegistry.class })\npublic final class HibernateMetricsAutoConfiguration implements SmartInitializingSingleton {\n\n\tprivate static final String ENTITY_MANAGER_FACTORY_SUFFIX = \"entityManagerFactory\";\n\n\tprivate final Map<String, EntityManagerFactory> entityManagerFactories;\n\n\tprivate final MeterRegistry meterRegistry;\n\n\tHibernateMetricsAutoConfiguration(ConfigurableListableBeanFactory beanFactory, MeterRegistry meterRegistry) {\n\t\tthis.entityManagerFactories = SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory,\n\t\t\t\tEntityManagerFactory.class);\n\t\tthis.meterRegistry = meterRegistry;\n\t}\n\n\t@Override\n\tpublic void afterSingletonsInstantiated() {\n\t\tbindEntityManagerFactoriesToRegistry(this.entityManagerFactories, this.meterRegistry);\n\t}\n\n\tprivate void bindEntityManagerFactoriesToRegistry(Map<String, EntityManagerFactory> entityManagerFactories,\n\t\t\tMeterRegistry registry) {\n\t\tentityManagerFactories.forEach((name, factory) -> bindEntityManagerFactoryToRegistry(name, factory, registry));\n\t}\n\n\tprivate void bindEntityManagerFactoryToRegistry(String beanName, EntityManagerFactory entityManagerFactory,\n\t\t\tMeterRegistry registry) {\n\t\tString entityManagerFactoryName = getEntityManagerFactoryName(beanName);\n\t\ttry {\n\t\t\tnew HibernateMetrics(entityManagerFactory.unwrap(SessionFactory.class), entityManagerFactoryName,\n\t\t\t\t\tCollections.emptyList())\n\t\t\t\t.bindTo(registry);\n\t\t}\n\t\tcatch (PersistenceException ex) {\n\t\t\t// Continue\n\t\t}\n\t}\n\n\t/**\n\t * Get the name of an {@link EntityManagerFactory} based on its {@code beanName}.\n\t * @param beanName the name of the {@link EntityManagerFactory} bean\n\t * @return a name for the given entity manager factory\n\t */\n\tprivate String getEntityManagerFactoryName(String beanName) {\n\t\tif (beanName.length() > ENTITY_MANAGER_FACTORY_SUFFIX.length()\n\t\t\t\t&& StringUtils.endsWithIgnoreCase(beanName, ENTITY_MANAGER_FACTORY_SUFFIX)) {\n\t\t\treturn beanName.substring(0, beanName.length() - ENTITY_MANAGER_FACTORY_SUFFIX.length());\n\t\t}\n\t\treturn beanName;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JPA and Spring ORM.\n */\n@NullMarked\npackage org.springframework.boot.hibernate.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JPA and Spring ORM.\n */\n@NullMarked\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/java/org/springframework/boot/hibernate/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Hibernate Support classes.\n */\n@NullMarked\npackage org.springframework.boot.hibernate;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.jpa.hibernate.use-new-id-generator-mappings\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to use Hibernate's newer IdentifierGenerator for AUTO, TABLE and SEQUENCE. This is actually a shortcut for the \\\"hibernate.id.new_generator_mappings\\\" property. When not specified will default to \\\"true\\\".\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Hibernate no longer supports disabling the use of new ID generator mappings.\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.jpa.hibernate.ddl-auto\",\n      \"values\": [\n        {\n          \"value\": \"create\",\n          \"description\": \"Create the schema and destroy previous data.\"\n        },\n        {\n          \"value\": \"create-drop\",\n          \"description\": \"Create and then destroy the schema at the end of the session.\"\n        },\n        {\n          \"value\": \"create-only\",\n          \"description\": \"Create the schema.\"\n        },\n        {\n          \"value\": \"drop\",\n          \"description\": \"Drop the schema.\"\n        },\n        {\n          \"value\": \"none\",\n          \"description\": \"Disable DDL handling.\"\n        },\n        {\n          \"value\": \"truncate\",\n          \"description\": \"Truncate the tables in the schema.\"\n        },\n        {\n          \"value\": \"update\",\n          \"description\": \"Update the schema if necessary.\"\n        },\n        {\n          \"value\": \"validate\",\n          \"description\": \"Validate the schema, make no changes to the database.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.jpa.hibernate.naming.implicit-strategy\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"org.hibernate.boot.model.naming.ImplicitNamingStrategy\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.jpa.hibernate.naming.physical-strategy\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"org.hibernate.boot.model.naming.PhysicalNamingStrategy\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\norg.springframework.boot.hibernate.autoconfigure.metrics.HibernateMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/CustomHibernateJpaAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.hibernate.boot.model.naming.ImplicitNamingStrategy;\nimport org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategy;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.hibernate.autoconfigure.test.city.City;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.orm.jpa.vendor.Database;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Additional tests for {@link HibernateJpaAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\nclass CustomHibernateJpaAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class));\n\n\t@Test\n\tvoid namingStrategyDelegatorTakesPrecedence() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.properties.hibernate.ejb.naming_strategy_delegator:\"\n\t\t\t\t\t+ \"org.hibernate.cfg.naming.ImprovedNamingStrategyDelegator\")\n\t\t\t.run((context) -> {\n\t\t\t\tJpaProperties jpaProperties = context.getBean(JpaProperties.class);\n\t\t\t\tHibernateProperties hibernateProperties = context.getBean(HibernateProperties.class);\n\t\t\t\tMap<String, Object> properties = hibernateProperties\n\t\t\t\t\t.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());\n\t\t\t\tassertThat(properties).doesNotContainKey(\"hibernate.ejb.naming_strategy\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid namingStrategyBeansAreUsed() {\n\t\tthis.contextRunner.withUserConfiguration(NamingStrategyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.url:jdbc:h2:mem:naming-strategy-beans\")\n\t\t\t.run((context) -> {\n\t\t\t\tHibernateJpaConfiguration jpaConfiguration = context.getBean(HibernateJpaConfiguration.class);\n\t\t\t\tMap<String, Object> hibernateProperties = jpaConfiguration\n\t\t\t\t\t.getVendorProperties(context.getBean(DataSource.class));\n\t\t\t\tassertThat(hibernateProperties).containsEntry(\"hibernate.implicit_naming_strategy\",\n\t\t\t\t\t\tNamingStrategyConfiguration.implicitNamingStrategy);\n\t\t\t\tassertThat(hibernateProperties).containsEntry(\"hibernate.physical_naming_strategy\",\n\t\t\t\t\t\tNamingStrategyConfiguration.physicalNamingStrategy);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hibernatePropertiesCustomizersAreAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(HibernatePropertiesCustomizerConfiguration.class).run((context) -> {\n\t\t\tHibernateJpaConfiguration jpaConfiguration = context.getBean(HibernateJpaConfiguration.class);\n\t\t\tMap<String, Object> hibernateProperties = jpaConfiguration\n\t\t\t\t.getVendorProperties(context.getBean(DataSource.class));\n\t\t\tassertThat(hibernateProperties).containsEntry(\"test.counter\", 2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDatabaseIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.url:jdbc:h2:mem:testdb\").run((context) -> {\n\t\t\tHibernateJpaVendorAdapter bean = context.getBean(HibernateJpaVendorAdapter.class);\n\t\t\tDatabase database = (Database) ReflectionTestUtils.getField(bean, \"database\");\n\t\t\tassertThat(database).isEqualTo(Database.DEFAULT);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tDataSource dataSource = mock(DataSource.class);\n\t\t\ttry {\n\t\t\t\tgiven(dataSource.getConnection()).willReturn(mock(Connection.class));\n\t\t\t\tgiven(dataSource.getConnection().getMetaData()).willReturn(mock(DatabaseMetaData.class));\n\t\t\t}\n\t\t\tcatch (SQLException ex) {\n\t\t\t\t// Do nothing\n\t\t\t}\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NamingStrategyConfiguration {\n\n\t\tstatic final ImplicitNamingStrategy implicitNamingStrategy = new ImplicitNamingStrategyJpaCompliantImpl();\n\n\t\tstatic final PhysicalNamingStrategy physicalNamingStrategy = new PhysicalNamingStrategyStandardImpl();\n\n\t\t@Bean\n\t\tImplicitNamingStrategy implicitNamingStrategy() {\n\t\t\treturn implicitNamingStrategy;\n\t\t}\n\n\t\t@Bean\n\t\tPhysicalNamingStrategy physicalNamingStrategy() {\n\t\t\treturn physicalNamingStrategy;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HibernatePropertiesCustomizerConfiguration {\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tHibernatePropertiesCustomizer sampleCustomizer() {\n\t\t\treturn ((hibernateProperties) -> hibernateProperties.put(\"test.counter\", 2));\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tHibernatePropertiesCustomizer anotherCustomizer() {\n\t\t\treturn ((hibernateProperties) -> hibernateProperties.put(\"test.counter\", 1));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/Hibernate2ndLevelCacheIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport javax.cache.CacheManager;\nimport javax.cache.Caching;\n\nimport org.ehcache.jsr107.EhcacheCachingProvider;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.jcache.JCacheCacheManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for Hibernate 2nd level cache with jcache.\n *\n * @author Stephane Nicoll\n */\nclass Hibernate2ndLevelCacheIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t.withUserConfiguration(TestConfiguration.class);\n\n\t@Test\n\tvoid hibernate2ndLevelCacheWithJCacheAndEhCache() {\n\t\tString cachingProviderFqn = EhcacheCachingProvider.class.getName();\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cache.type=jcache\", \"spring.cache.jcache.provider=\" + cachingProviderFqn,\n\t\t\t\t\t\"spring.jpa.properties.hibernate.cache.region.factory_class=jcache\",\n\t\t\t\t\t\"spring.jpa.properties.hibernate.cache.provider=\" + cachingProviderFqn)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableCaching\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tCacheManager cacheManager() {\n\t\t\treturn Caching.getCachingProvider(EhcacheCachingProvider.class.getName()).getCacheManager();\n\t\t}\n\n\t\t@Bean\n\t\tJCacheCacheManager jcacheCacheManager(CacheManager cacheManager) {\n\t\t\treturn new JCacheCacheManager(cacheManager);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/HibernateDefaultDdlAutoProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.Collections;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.SchemaManagement;\nimport org.springframework.boot.jdbc.SchemaManagementProvider;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HibernateDefaultDdlAutoProvider}.\n *\n * @author Stephane Nicoll\n */\nclass HibernateDefaultDdlAutoProviderTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.sql.init.mode:never\");\n\n\t@Test\n\tvoid defaultDDlAutoForEmbedded() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHibernateDefaultDdlAutoProvider ddlAutoProvider = new HibernateDefaultDdlAutoProvider(\n\t\t\t\t\tCollections.emptyList());\n\t\t\tassertThat(ddlAutoProvider.getDefaultDdlAuto(context.getBean(DataSource.class))).isEqualTo(\"create-drop\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDDlAutoForEmbeddedWithPositiveContributor() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\tSchemaManagementProvider provider = mock(SchemaManagementProvider.class);\n\t\t\tgiven(provider.getSchemaManagement(dataSource)).willReturn(SchemaManagement.MANAGED);\n\t\t\tHibernateDefaultDdlAutoProvider ddlAutoProvider = new HibernateDefaultDdlAutoProvider(\n\t\t\t\t\tCollections.singletonList(provider));\n\t\t\tassertThat(ddlAutoProvider.getDefaultDdlAuto(dataSource)).isEqualTo(\"none\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDDlAutoForEmbeddedWithNegativeContributor() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\tSchemaManagementProvider provider = mock(SchemaManagementProvider.class);\n\t\t\tgiven(provider.getSchemaManagement(dataSource)).willReturn(SchemaManagement.UNMANAGED);\n\t\t\tHibernateDefaultDdlAutoProvider ddlAutoProvider = new HibernateDefaultDdlAutoProvider(\n\t\t\t\t\tCollections.singletonList(provider));\n\t\t\tassertThat(ddlAutoProvider.getDefaultDdlAuto(dataSource)).isEqualTo(\"create-drop\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/HibernateJpaAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.metamodel.ManagedType;\nimport jakarta.persistence.spi.PersistenceUnitInfo;\nimport jakarta.transaction.Synchronization;\nimport jakarta.transaction.Transaction;\nimport jakarta.transaction.TransactionManager;\nimport jakarta.transaction.UserTransaction;\nimport org.hibernate.boot.model.naming.ImplicitNamingStrategy;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategy;\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;\nimport org.hibernate.cfg.ManagedBeanSettings;\nimport org.hibernate.cfg.SchemaToolingSettings;\nimport org.hibernate.dialect.H2Dialect;\nimport org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;\nimport org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;\nimport org.hibernate.internal.SessionFactoryImpl;\nimport org.hibernate.jpa.HibernatePersistenceProvider;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.hibernate.SpringImplicitNamingStrategy;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfigurationTests.JpaUsingApplicationListenerConfiguration.EventCapturingApplicationListener;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaConfiguration.HibernateRuntimeHints;\nimport org.springframework.boot.hibernate.autoconfigure.mapping.NonAnnotatedEntity;\nimport org.springframework.boot.hibernate.autoconfigure.test.city.City;\nimport org.springframework.boot.hibernate.autoconfigure.test.country.Country;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.XADataSourceAutoConfiguration;\nimport org.springframework.boot.jpa.EntityManagerFactoryBuilder;\nimport org.springframework.boot.jpa.autoconfigure.BootstrapExecutorRequiredException;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryBuilderCustomizer;\nimport org.springframework.boot.jpa.autoconfigure.JpaBaseConfiguration;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.boot.transaction.jta.autoconfigure.JtaAutoConfiguration;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\nimport org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.JpaVendorAdapter;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.hibernate.ConfigurableJtaPlatform;\nimport org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager;\nimport org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;\nimport org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;\nimport org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for {@link HibernateJpaAutoConfiguration} and {@link JpaBaseConfiguration}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Yanming Zhou\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n * @author Chris Bono\n * @author Moritz Halbritter\n */\nclass HibernateJpaAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\"spring.jta.log-dir=\" + new File(new BuildOutput(getClass()).getRootLocation(), \"transaction-logs\"))\n\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class,\n\t\t\t\tTransactionManagerCustomizationAutoConfiguration.class, DataSourceInitializationAutoConfiguration.class,\n\t\t\t\tHibernateJpaAutoConfiguration.class));\n\n\t@Test\n\tvoid notConfiguredIfDataSourceIsNotAvailable() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HibernateJpaAutoConfiguration.class))\n\t\t\t.run(assertJpaIsNotAutoConfigured());\n\t}\n\n\t@Test\n\tvoid notConfiguredIfNoSingleDataSourceCandidateIsAvailable() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HibernateJpaAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestTwoDataSourcesConfiguration.class)\n\t\t\t.run(assertJpaIsNotAutoConfigured());\n\t}\n\n\tprotected ContextConsumer<AssertableApplicationContext> assertJpaIsNotAutoConfigured() {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasNotFailed();\n\t\t\tassertThat(context).hasSingleBean(JpaProperties.class);\n\t\t\tassertThat(context).doesNotHaveBean(TransactionManager.class);\n\t\t\tassertThat(context).doesNotHaveBean(EntityManagerFactory.class);\n\t\t};\n\t}\n\n\t@Test\n\tvoid configuredWithAutoConfiguredDataSource() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\tassertThat(context).hasSingleBean(JpaTransactionManager.class);\n\t\t\tassertThat(context).hasSingleBean(EntityManagerFactory.class);\n\t\t\tassertThat(context).hasSingleBean(PersistenceManagedTypes.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid configuredWithSingleCandidateDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(TestTwoDataSourcesAndPrimaryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).getBeans(DataSource.class).hasSize(2);\n\t\t\tassertThat(context).hasSingleBean(JpaTransactionManager.class);\n\t\t\tassertThat(context).hasSingleBean(EntityManagerFactory.class);\n\t\t\tassertThat(context).hasSingleBean(PersistenceManagedTypes.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jpaTransactionManagerTakesPrecedenceOverSimpleDataSourceOne() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\t\tassertThat(context).hasSingleBean(JpaTransactionManager.class);\n\t\t\t\tassertThat(context).getBean(\"transactionManager\").isInstanceOf(JpaTransactionManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid openEntityManagerInViewInterceptorIsCreated() {\n\t\tnew WebApplicationContextRunner().withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tTransactionAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OpenEntityManagerInViewInterceptor.class));\n\t}\n\n\t@Test\n\tvoid openEntityManagerInViewInterceptorIsNotRegisteredWhenFilterPresent() {\n\t\tnew WebApplicationContextRunner().withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.withUserConfiguration(TestFilterConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tTransactionAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OpenEntityManagerInViewInterceptor.class));\n\t}\n\n\t@Test\n\tvoid openEntityManagerInViewInterceptorIsNotRegisteredWhenFilterRegistrationPresent() {\n\t\tnew WebApplicationContextRunner().withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.withUserConfiguration(TestFilterRegistrationConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tTransactionAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OpenEntityManagerInViewInterceptor.class));\n\t}\n\n\t@Test\n\tvoid openEntityManagerInViewInterceptorAutoConfigurationBacksOffWhenManuallyRegistered() {\n\t\tnew WebApplicationContextRunner().withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.withUserConfiguration(TestInterceptorManualConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tTransactionAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).getBean(OpenEntityManagerInViewInterceptor.class)\n\t\t\t\t.isExactlyInstanceOf(\n\t\t\t\t\t\tTestInterceptorManualConfiguration.ManualOpenEntityManagerInViewInterceptor.class));\n\t}\n\n\t@Test\n\tvoid openEntityManagerInViewInterceptorIsNotRegisteredWhenExplicitlyOff() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\", \"spring.jpa.open-in-view=false\")\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tTransactionAutoConfiguration.class, HibernateJpaAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OpenEntityManagerInViewInterceptor.class));\n\t}\n\n\t@Test\n\tvoid whenBackgroundBootstrapingAndSingleAsyncTaksExecutorConfiguresBackgroundExecutor() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.bootstrap=async\")\n\t\t\t.withUserConfiguration(SingleAsyncTaskExecutorConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isInstanceOf(SimpleAsyncTaskExecutor.class));\n\t}\n\n\t@Test\n\tvoid whenBackgroundBootstrapingAndApplicationTaksExecutorConfiguresBackgroundExecutor() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.bootstrap=async\")\n\t\t\t.withUserConfiguration(MultipleAsyncTaskExecutorsConfiguration.class,\n\t\t\t\t\tApplicationTaskExecutorConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isSameAs(context.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)));\n\t}\n\n\t@Test\n\tvoid whenBackgroundBootstrapingAndMissingTaksExecutorThrowsException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.bootstrap=async\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(BootstrapExecutorRequiredException.class)\n\t\t\t\t.message()\n\t\t\t\t.contains(\"bootstrap executor is required when 'spring.jpa.bootstrap' is set to 'async'\"));\n\t}\n\n\t@Test\n\tvoid whenBackgroundBootstrapingAndMultipleTaksExecutorThrowsException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.bootstrap=async\")\n\t\t\t.withUserConfiguration(MultipleAsyncTaskExecutorsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(BootstrapExecutorRequiredException.class)\n\t\t\t\t.message()\n\t\t\t\t.contains(\"bootstrap executor is required when 'spring.jpa.bootstrap' is set to 'async'\"));\n\t}\n\n\t@Test\n\tvoid whenBackgroundBootstrapingAndCustomizedBackgroundExecutorThrowsException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.bootstrap=async\")\n\t\t\t.withBean(EntityManagerFactoryBuilderCustomizer.class, this::bootstrapExecutorCustomizer)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getBootstrapExecutor())\n\t\t\t\t.isInstanceOf(SimpleAsyncTaskExecutor.class));\n\t}\n\n\tprivate EntityManagerFactoryBuilderCustomizer bootstrapExecutorCustomizer() {\n\t\treturn (builder) -> builder.setBootstrapExecutor(new SimpleAsyncTaskExecutor());\n\t}\n\n\t@Test\n\tvoid customJpaProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.properties.a:b\", \"spring.jpa.properties.a.b:c\", \"spring.jpa.properties.c:d\")\n\t\t\t.run((context) -> {\n\t\t\t\tLocalContainerEntityManagerFactoryBean bean = context\n\t\t\t\t\t.getBean(LocalContainerEntityManagerFactoryBean.class);\n\t\t\t\tMap<String, Object> map = bean.getJpaPropertyMap();\n\t\t\t\tassertThat(map).containsEntry(\"a\", \"b\");\n\t\t\t\tassertThat(map).containsEntry(\"c\", \"d\");\n\t\t\t\tassertThat(map).containsEntry(\"a.b\", \"c\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid usesManuallyDefinedLocalContainerEntityManagerFactoryBeanUsingBuilder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.a=b\")\n\t\t\t.withUserConfiguration(TestConfigurationWithEntityManagerFactoryBuilder.class)\n\t\t\t.run((context) -> {\n\t\t\t\tLocalContainerEntityManagerFactoryBean factoryBean = context\n\t\t\t\t\t.getBean(LocalContainerEntityManagerFactoryBean.class);\n\t\t\t\tMap<String, Object> map = factoryBean.getJpaPropertyMap();\n\t\t\t\tassertThat(map).containsEntry(\"configured\", \"manually\").containsEntry(\"a\", \"b\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tLocalContainerEntityManagerFactoryBean factoryBean = context\n\t\t\t\t\t.getBean(LocalContainerEntityManagerFactoryBean.class);\n\t\t\t\tMap<String, Object> map = factoryBean.getJpaPropertyMap();\n\t\t\t\tassertThat(map).containsEntry(\"configured\", \"manually\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid usesManuallyDefinedEntityManagerFactoryIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfigurationWithLocalContainerEntityManagerFactoryBean.class)\n\t\t\t.run((context) -> {\n\t\t\t\tEntityManagerFactory factoryBean = context.getBean(EntityManagerFactory.class);\n\t\t\t\tMap<String, Object> map = factoryBean.getProperties();\n\t\t\t\tassertThat(map).containsEntry(\"configured\", \"manually\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid usesManuallyDefinedTransactionManagerBeanIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfigurationWithTransactionManager.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JpaTransactionManager.class);\n\t\t\tJpaTransactionManager txManager = context.getBean(JpaTransactionManager.class);\n\t\t\tassertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultPersistenceManagedTypes() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(PersistenceManagedTypes.class);\n\t\t\tEntityManager entityManager = context.getBean(EntityManagerFactory.class).createEntityManager();\n\t\t\tassertThat(getManagedJavaTypes(entityManager)).contains(City.class).doesNotContain(Country.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPersistenceManagedTypes() {\n\t\tthis.contextRunner\n\t\t\t.withBean(PersistenceManagedTypes.class, () -> PersistenceManagedTypes.of(Country.class.getName()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PersistenceManagedTypes.class);\n\t\t\t\tEntityManager entityManager = context.getBean(EntityManagerFactory.class).createEntityManager();\n\t\t\t\tassertThat(getManagedJavaTypes(entityManager)).contains(Country.class).doesNotContain(City.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customPersistenceUnitManager() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfigurationWithCustomPersistenceUnitManager.class)\n\t\t\t.run((context) -> {\n\t\t\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean = context\n\t\t\t\t\t.getBean(LocalContainerEntityManagerFactoryBean.class);\n\t\t\t\tassertThat(entityManagerFactoryBean).hasFieldOrPropertyWithValue(\"persistenceUnitManager\",\n\t\t\t\t\t\tcontext.getBean(PersistenceUnitManager.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customPersistenceUnitPostProcessors() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfigurationWithCustomPersistenceUnitPostProcessors.class)\n\t\t\t.run((context) -> {\n\t\t\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean = context\n\t\t\t\t\t.getBean(LocalContainerEntityManagerFactoryBean.class);\n\t\t\t\tPersistenceUnitInfo persistenceUnitInfo = entityManagerFactoryBean.getPersistenceUnitInfo();\n\t\t\t\tassertThat(persistenceUnitInfo).isNotNull();\n\t\t\t\tassertThat(persistenceUnitInfo.getManagedClassNames())\n\t\t\t\t\t.contains(\"customized.attribute.converter.class.name\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customPersistenceUnitProcessorsAddedByServeralContributors() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfigurationWithMultipleCustomPersistenceUnitPostProcessors.class)\n\t\t\t.run((context) -> {\n\t\t\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean = context\n\t\t\t\t\t.getBean(LocalContainerEntityManagerFactoryBean.class);\n\t\t\t\tPersistenceUnitInfo persistenceUnitInfo = entityManagerFactoryBean.getPersistenceUnitInfo();\n\t\t\t\tassertThat(persistenceUnitInfo).isNotNull();\n\t\t\t\tassertThat(persistenceUnitInfo.getManagedClassNames()).contains(\n\t\t\t\t\t\t\"customized.attribute.converter.class.name\",\n\t\t\t\t\t\t\"customized.attribute.converter.class.anotherName\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customManagedClassNameFilter() {\n\t\tthis.contextRunner.withBean(ManagedClassNameFilter.class, () -> (s) -> !s.endsWith(\"City\"))\n\t\t\t.withUserConfiguration(AutoConfigurePackageForCountry.class)\n\t\t\t.run((context) -> {\n\t\t\t\tEntityManager entityManager = context.getBean(EntityManagerFactory.class).createEntityManager();\n\t\t\t\tassertThat(getManagedJavaTypes(entityManager)).contains(Country.class).doesNotContain(City.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDmlScriptWithMissingDdl() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.sql.init.data-locations:classpath:/city.sql\",\n\t\t\t\t// Missing:\n\t\t\t\t\"spring.sql.init.schema-locations:classpath:/ddl.sql\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).hasMessageContaining(\"ddl.sql\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDmlScript() {\n\t\t// This can't succeed because the data SQL is executed immediately after the\n\t\t// schema and Hibernate hasn't initialized yet at that point\n\t\tthis.contextRunner.withPropertyValues(\"spring.sql.init.data-locations:/city.sql\").run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(BeanCreationException.class);\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"city.sql\",\n\t\t\tcontent = \"INSERT INTO CITY (ID, NAME, STATE, COUNTRY, MAP) values (2000, 'Washington', 'DC', 'US', 'Google')\")\n\tvoid testDmlScriptRunsEarly() {\n\t\tthis.contextRunner.withUserConfiguration(TestInitializedJpaConfiguration.class)\n\t\t\t.withClassLoader(new HideDataScriptClassLoader())\n\t\t\t.withPropertyValues(\"spring.jpa.show-sql=true\", \"spring.jpa.properties.hibernate.format_sql=true\",\n\t\t\t\t\t\"spring.jpa.properties.hibernate.highlight_sql=true\", \"spring.jpa.hibernate.ddl-auto:create-drop\",\n\t\t\t\t\t\"spring.sql.init.data-locations:/city.sql\", \"spring.jpa.defer-datasource-initialization=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(TestInitializedJpaConfiguration.class).called).isTrue());\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/city/V1__init.sql\", content = \"\"\"\n\t\t\tCREATE SEQUENCE city_seq INCREMENT BY 50;\n\t\t\tCREATE TABLE CITY (\n\t\t\t  id         BIGINT GENERATED BY DEFAULT AS IDENTITY,\n\t\t\t  name VARCHAR(30),\n\t\t\t  state VARCHAR(30),\n\t\t\t  country VARCHAR(30),\n\t\t\t  map VARCHAR(30)\n\t\t\t);\n\t\t\t\"\"\")\n\tvoid testFlywaySwitchOffDdlAuto() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.sql.init.mode:never\", \"spring.flyway.locations:classpath:db/city\")\n\t\t\t.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/city/V1__init.sql\", content = \"\"\"\n\t\t\tCREATE SEQUENCE city_seq INCREMENT BY 50;\n\n\t\t\tCREATE TABLE CITY (\n\t\t\t  id         BIGINT GENERATED BY DEFAULT AS IDENTITY,\n\t\t\t  name VARCHAR(30),\n\t\t\t  state VARCHAR(30),\n\t\t\t  country VARCHAR(30),\n\t\t\t  map VARCHAR(30)\n\t\t\t);\n\t\t\t\"\"\")\n\tvoid testFlywayPlusValidation() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.sql.init.mode:never\", \"spring.flyway.locations:classpath:db/city\",\n\t\t\t\t\t\"spring.jpa.hibernate.ddl-auto:validate\")\n\t\t\t.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-city.yaml\", content = \"\"\"\n\t\t\tdatabaseChangeLog:\n\t\t\t- changeSet:\n\t\t\t    id: 1\n\t\t\t    author: dsyer\n\t\t\t    changes:\n\t\t\t      - createSequence:\n\t\t\t          sequenceName: city_seq\n\t\t\t          incrementBy: 50\n\t\t\t      - createTable:\n\t\t\t          tableName: city\n\t\t\t          columns:\n\t\t\t            - column:\n\t\t\t                name: id\n\t\t\t                type: bigint\n\t\t\t                autoIncrement: true\n\t\t\t                constraints:\n\t\t\t                  primaryKey: true\n\t\t\t                  nullable: false\n\t\t\t            - column:\n\t\t\t                name: name\n\t\t\t                type: varchar(50)\n\t\t\t                constraints:\n\t\t\t                  nullable: false\n\t\t\t            - column:\n\t\t\t                name: state\n\t\t\t                type: varchar(50)\n\t\t\t                constraints:\n\t\t\t                  nullable: false\n\t\t\t            - column:\n\t\t\t                name: country\n\t\t\t                type: varchar(50)\n\t\t\t                constraints:\n\t\t\t                  nullable: false\n\t\t\t            - column:\n\t\t\t                name: map\n\t\t\t                type: varchar(50)\n\t\t\t                constraints:\n\t\t\t                  nullable: true\n\t\t\t\"\"\")\n\tvoid testLiquibasePlusValidation() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.liquibase.change-log:classpath:db/changelog/db.changelog-city.yaml\",\n\t\t\t\t\t\"spring.jpa.hibernate.ddl-auto:validate\")\n\t\t\t.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid hibernateDialectIsNotSetByDefault() {\n\t\tthis.contextRunner.run(assertJpaVendorAdapter(\n\t\t\t\t(adapter) -> assertThat(adapter.getJpaPropertyMap()).doesNotContainKeys(\"hibernate.dialect\")));\n\t}\n\n\t@Test\n\tvoid shouldConfigureHibernateJpaDialectWithSqlExceptionTranslatorIfPresent() {\n\t\tSQLStateSQLExceptionTranslator sqlExceptionTranslator = new SQLStateSQLExceptionTranslator();\n\t\tthis.contextRunner.withBean(SQLStateSQLExceptionTranslator.class, () -> sqlExceptionTranslator)\n\t\t\t.run(assertJpaVendorAdapter(\n\t\t\t\t\t(adapter) -> assertThat(adapter.getJpaDialect()).extracting(\"exceptionTranslator\")\n\t\t\t\t\t\t.hasFieldOrPropertyWithValue(\"jdbcExceptionTranslator\", sqlExceptionTranslator)));\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureHibernateJpaDialectWithSqlExceptionTranslatorIfNotUnique() {\n\t\tSQLStateSQLExceptionTranslator sqlExceptionTranslator1 = new SQLStateSQLExceptionTranslator();\n\t\tSQLStateSQLExceptionTranslator sqlExceptionTranslator2 = new SQLStateSQLExceptionTranslator();\n\t\tthis.contextRunner\n\t\t\t.withBean(\"sqlExceptionTranslator1\", SQLExceptionTranslator.class, () -> sqlExceptionTranslator1)\n\t\t\t.withBean(\"sqlExceptionTranslator2\", SQLExceptionTranslator.class, () -> sqlExceptionTranslator2)\n\t\t\t.run(assertJpaVendorAdapter(\n\t\t\t\t\t(adapter) -> assertThat(adapter.getJpaDialect()).extracting(\"exceptionTranslator\")\n\t\t\t\t\t\t.hasFieldOrPropertyWithValue(\"jdbcExceptionTranslator\", null)));\n\t}\n\n\t@Test\n\tvoid hibernateDialectIsSetWhenDatabaseIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.database=H2\")\n\t\t\t.run(assertJpaVendorAdapter((adapter) -> assertThat(adapter.getJpaPropertyMap())\n\t\t\t\t.contains(entry(\"hibernate.dialect\", H2Dialect.class.getName()))));\n\t}\n\n\t@Test\n\tvoid hibernateDialectIsSetWhenDatabasePlatformIsSet() {\n\t\tString databasePlatform = TestH2Dialect.class.getName();\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.database-platform=\" + databasePlatform)\n\t\t\t.run(assertJpaVendorAdapter((adapter) -> assertThat(adapter.getJpaPropertyMap())\n\t\t\t\t.contains(entry(\"hibernate.dialect\", databasePlatform))));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertJpaVendorAdapter(\n\t\t\tConsumer<HibernateJpaVendorAdapter> adapter) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(JpaVendorAdapter.class);\n\t\t\tassertThat(context).hasSingleBean(HibernateJpaVendorAdapter.class);\n\t\t\tadapter.accept(context.getBean(HibernateJpaVendorAdapter.class));\n\t\t};\n\t}\n\n\t@Test\n\tvoid jtaDefaultPlatform() {\n\t\tthis.contextRunner.withUserConfiguration(JtaTransactionManagerConfiguration.class)\n\t\t\t.run(assertJtaPlatform(ConfigurableJtaPlatform.class));\n\t}\n\n\t@Test\n\tvoid jtaCustomPlatform() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.jpa.properties.hibernate.transaction.jta.platform:\" + TestJtaPlatform.class.getName())\n\t\t\t.withConfiguration(AutoConfigurations.of(JtaAutoConfiguration.class))\n\t\t\t.run(assertJtaPlatform(TestJtaPlatform.class));\n\t}\n\n\t@Test\n\tvoid jtaNotUsedByTheApplication() {\n\t\tthis.contextRunner.run(assertJtaPlatform(NoJtaPlatform.class));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertJtaPlatform(Class<? extends JtaPlatform> expectedType) {\n\t\treturn (context) -> {\n\t\t\tSessionFactoryImpl sessionFactory = context.getBean(LocalContainerEntityManagerFactoryBean.class)\n\t\t\t\t.getNativeEntityManagerFactory()\n\t\t\t\t.unwrap(SessionFactoryImpl.class);\n\t\t\tassertThat(sessionFactory.getServiceRegistry().getService(JtaPlatform.class)).isInstanceOf(expectedType);\n\t\t};\n\t}\n\n\t@Test\n\tvoid jtaCustomTransactionManagerUsingProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.transaction.default-timeout:30\",\n\t\t\t\t\t\"spring.transaction.rollback-on-commit-failure:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tJpaTransactionManager transactionManager = context.getBean(JpaTransactionManager.class);\n\t\t\t\tassertThat(transactionManager.getDefaultTimeout()).isEqualTo(30);\n\t\t\t\tassertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationBacksOffWithSeveralDataSources() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class,\n\t\t\t\t\tXADataSourceAutoConfiguration.class, JtaAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestTwoDataSourcesConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).doesNotHaveBean(EntityManagerFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid providerDisablesAutoCommitIsConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.type:\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.hikari.auto-commit:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class)\n\t\t\t\t\t.getJpaPropertyMap();\n\t\t\t\tassertThat(jpaProperties).contains(entry(\"hibernate.connection.provider_disables_autocommit\", \"true\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid providerDisablesAutoCommitIsNotConfiguredIfAutoCommitIsEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.type:\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.hikari.auto-commit:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class)\n\t\t\t\t\t.getJpaPropertyMap();\n\t\t\t\tassertThat(jpaProperties).doesNotContainKeys(\"hibernate.connection.provider_disables_autocommit\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid providerDisablesAutoCommitIsNotConfiguredIfPropertyIsSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.type:\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.hikari.auto-commit:false\",\n\t\t\t\t\t\"spring.jpa.properties.hibernate.connection.provider_disables_autocommit=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class)\n\t\t\t\t\t.getJpaPropertyMap();\n\t\t\t\tassertThat(jpaProperties).contains(entry(\"hibernate.connection.provider_disables_autocommit\", \"false\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid providerDisablesAutoCommitIsNotConfiguredWithJta() {\n\t\tthis.contextRunner.withUserConfiguration(JtaTransactionManagerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.type:\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.hikari.auto-commit:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, Object> jpaProperties = context.getBean(LocalContainerEntityManagerFactoryBean.class)\n\t\t\t\t\t.getJpaPropertyMap();\n\t\t\t\tassertThat(jpaProperties).doesNotContainKeys(\"hibernate.connection.provider_disables_autocommit\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/mappings/non-annotated.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\t\t\t\t\t<entity-mappings xmlns=\"http://xmlns.jcp.org/xml/ns/persistence/orm\"\n\t\t\t\t\t\t\t\t\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\t\t\t\t\t xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/persistence/orm https://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/orm_2_1.xsd\"\n\t\t\t\t\t\t\t\t\t version=\"2.1\">\n\t\t\t\t\t\t<entity class=\"org.springframework.boot.hibernate.autoconfigure.mapping.NonAnnotatedEntity\">\n\t\t\t\t\t\t\t<table name=\"NON_ANNOTATED\"/>\n\t\t\t\t\t\t\t<attributes>\n\t\t\t\t\t\t\t\t<id name=\"id\">\n\t\t\t\t\t\t\t\t\t<column name=\"id\"/>\n\t\t\t\t\t\t\t\t\t<generated-value strategy=\"IDENTITY\"/>\n\t\t\t\t\t\t\t\t</id>\n\t\t\t\t\t\t\t\t<basic name=\"item\">\n\t\t\t\t\t\t\t\t\t<column name=\"item\"/>\n\t\t\t\t\t\t\t\t</basic>\n\t\t\t\t\t\t\t</attributes>\n\t\t\t\t\t\t</entity>\n\t\t\t\t\t</entity-mappings>\n\t\t\t\t\t\"\"\")\n\t@WithResource(name = \"non-annotated-data.sql\",\n\t\t\tcontent = \"INSERT INTO NON_ANNOTATED (id, item) values (2000, 'Test');\")\n\tvoid customResourceMapping() {\n\t\tthis.contextRunner.withClassLoader(new HideDataScriptClassLoader())\n\t\t\t.withPropertyValues(\"spring.sql.init.data-locations:classpath:non-annotated-data.sql\",\n\t\t\t\t\t\"spring.jpa.mapping-resources=META-INF/mappings/non-annotated.xml\",\n\t\t\t\t\t\"spring.jpa.defer-datasource-initialization=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tEntityManager em = context.getBean(EntityManagerFactory.class).createEntityManager();\n\t\t\t\tNonAnnotatedEntity found = em.find(NonAnnotatedEntity.class, 2000L);\n\t\t\t\tassertThat(found).isNotNull();\n\t\t\t\tassertThat(found.getItem()).isEqualTo(\"Test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid physicalNamingStrategyCanBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(TestPhysicalNamingStrategyConfiguration.class).run((context) -> {\n\t\t\tMap<String, Object> hibernateProperties = getVendorProperties(context);\n\t\t\tassertThat(hibernateProperties)\n\t\t\t\t.contains(entry(\"hibernate.physical_naming_strategy\", context.getBean(\"testPhysicalNamingStrategy\")));\n\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid implicitNamingStrategyCanBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(TestImplicitNamingStrategyConfiguration.class).run((context) -> {\n\t\t\tMap<String, Object> hibernateProperties = getVendorProperties(context);\n\t\t\tassertThat(hibernateProperties)\n\t\t\t\t.contains(entry(\"hibernate.implicit_naming_strategy\", context.getBean(\"testImplicitNamingStrategy\")));\n\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid namingStrategyInstancesTakePrecedenceOverNamingStrategyProperties() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(TestPhysicalNamingStrategyConfiguration.class,\n\t\t\t\t\tTestImplicitNamingStrategyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jpa.hibernate.naming.physical-strategy:com.example.Physical\",\n\t\t\t\t\t\"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, Object> hibernateProperties = getVendorProperties(context);\n\t\t\t\tassertThat(hibernateProperties).contains(\n\t\t\t\t\t\tentry(\"hibernate.physical_naming_strategy\", context.getBean(\"testPhysicalNamingStrategy\")),\n\t\t\t\t\t\tentry(\"hibernate.implicit_naming_strategy\", context.getBean(\"testImplicitNamingStrategy\")));\n\t\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hibernatePropertiesCustomizerTakesPrecedenceOverStrategyInstancesAndNamingStrategyProperties() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(TestHibernatePropertiesCustomizerConfiguration.class,\n\t\t\t\t\tTestPhysicalNamingStrategyConfiguration.class, TestImplicitNamingStrategyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jpa.hibernate.naming.physical-strategy:com.example.Physical\",\n\t\t\t\t\t\"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, Object> hibernateProperties = getVendorProperties(context);\n\t\t\t\tTestHibernatePropertiesCustomizerConfiguration configuration = context\n\t\t\t\t\t.getBean(TestHibernatePropertiesCustomizerConfiguration.class);\n\t\t\t\tassertThat(hibernateProperties).contains(\n\t\t\t\t\t\tentry(\"hibernate.physical_naming_strategy\", configuration.physicalNamingStrategy),\n\t\t\t\t\t\tentry(\"hibernate.implicit_naming_strategy\", configuration.implicitNamingStrategy));\n\t\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid beanContainerIsConfiguredByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(\n\t\t\t\tcontext.getBean(LocalContainerEntityManagerFactoryBean.class).getJpaPropertyMap())\n\t\t\t.containsKey(ManagedBeanSettings.BEAN_CONTAINER));\n\t}\n\n\t@Test\n\t@WithResource(name = \"city.sql\",\n\t\t\tcontent = \"INSERT INTO CITY (ID, NAME, STATE, COUNTRY, MAP) values (2000, 'Washington', 'DC', 'US', 'Google')\")\n\tvoid eventListenerCanBeRegisteredAsBeans() {\n\t\tthis.contextRunner.withUserConfiguration(TestInitializedJpaConfiguration.class)\n\t\t\t.withClassLoader(new HideDataScriptClassLoader())\n\t\t\t.withPropertyValues(\"spring.jpa.show-sql=true\", \"spring.jpa.hibernate.ddl-auto:create-drop\",\n\t\t\t\t\t\"spring.sql.init.data-locations:classpath:/city.sql\",\n\t\t\t\t\t\"spring.jpa.defer-datasource-initialization=true\")\n\t\t\t.run((context) -> {\n\t\t\t\t// See CityListener\n\t\t\t\tassertThat(context).hasSingleBean(City.class);\n\t\t\t\tassertThat(context.getBean(City.class).getName()).isEqualTo(\"Washington\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid vendorPropertiesWithEmbeddedDatabaseAndNoDdlProperty() {\n\t\tthis.contextRunner.run(vendorProperties((vendorProperties) -> {\n\t\t\tassertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);\n\t\t\tassertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, \"create-drop\");\n\t\t}));\n\t}\n\n\t@Test\n\tvoid vendorPropertiesWhenDdlAutoPropertyIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.hibernate.ddl-auto=update\")\n\t\t\t.run(vendorProperties((vendorProperties) -> {\n\t\t\t\tassertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);\n\t\t\t\tassertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, \"update\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid vendorPropertiesWhenDdlAutoPropertyAndHibernatePropertiesAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.hibernate.ddl-auto=update\",\n\t\t\t\t\t\"spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop\")\n\t\t\t.run(vendorProperties((vendorProperties) -> {\n\t\t\t\tassertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION);\n\t\t\t\tassertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, \"create-drop\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid vendorPropertiesWhenDdlAutoPropertyIsSetToNone() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.hibernate.ddl-auto=none\")\n\t\t\t.run(vendorProperties((vendorProperties) -> assertThat(vendorProperties).doesNotContainKeys(\n\t\t\t\t\tSchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, SchemaToolingSettings.HBM2DDL_AUTO)));\n\t}\n\n\t@Test\n\tvoid vendorPropertiesWhenJpaDdlActionIsSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.properties.jakarta.persistence.schema-generation.database.action=create\")\n\t\t\t.run(vendorProperties((vendorProperties) -> {\n\t\t\t\tassertThat(vendorProperties).containsEntry(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION,\n\t\t\t\t\t\t\"create\");\n\t\t\t\tassertThat(vendorProperties).doesNotContainKeys(SchemaToolingSettings.HBM2DDL_AUTO);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid vendorPropertiesWhenBothDdlAutoPropertiesAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.properties.jakarta.persistence.schema-generation.database.action=create\",\n\t\t\t\t\t\"spring.jpa.hibernate.ddl-auto=create-only\")\n\t\t\t.run(vendorProperties((vendorProperties) -> {\n\t\t\t\tassertThat(vendorProperties).containsEntry(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION,\n\t\t\t\t\t\t\"create\");\n\t\t\t\tassertThat(vendorProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, \"create-only\");\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> vendorProperties(\n\t\t\tConsumer<Map<String, Object>> vendorProperties) {\n\t\treturn (context) -> vendorProperties.accept(getVendorProperties(context));\n\t}\n\n\tprivate static Map<String, Object> getVendorProperties(ConfigurableApplicationContext context) {\n\t\treturn context.getBean(HibernateJpaConfiguration.class).getVendorProperties(context.getBean(DataSource.class));\n\t}\n\n\t@Test\n\tvoid withSyncBootstrappingAnApplicationListenerThatUsesJpaDoesNotTriggerABeanCurrentlyInCreationException() {\n\t\tthis.contextRunner.withUserConfiguration(JpaUsingApplicationListenerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasNotFailed();\n\t\t\tEventCapturingApplicationListener listener = context.getBean(EventCapturingApplicationListener.class);\n\t\t\tassertThat(listener.events).hasSize(1);\n\t\t\tassertThat(listener.events).hasOnlyElementsOfType(ContextRefreshedEvent.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withAsyncBootstrappingAnApplicationListenerThatUsesJpaDoesNotTriggerABeanCurrentlyInCreationException() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(AsyncBootstrappingConfiguration.class,\n\t\t\t\t\tJpaUsingApplicationListenerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tEventCapturingApplicationListener listener = context.getBean(EventCapturingApplicationListener.class);\n\t\t\t\tassertThat(listener.events).hasSize(1);\n\t\t\t\tassertThat(listener.events).hasOnlyElementsOfType(ContextRefreshedEvent.class);\n\t\t\t\t// createEntityManager requires Hibernate bootstrapping to be complete\n\t\t\t\tassertThatNoException()\n\t\t\t\t\t.isThrownBy(() -> context.getBean(EntityManagerFactory.class).createEntityManager());\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid whenLocalContainerEntityManagerFactoryBeanHasNoJpaVendorAdapterAutoConfigurationSucceeds() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(\n\t\t\t\t\tTestConfigurationWithLocalContainerEntityManagerFactoryBeanWithNoJpaVendorAdapter.class)\n\t\t\t.run((context) -> {\n\t\t\t\tEntityManagerFactory factoryBean = context.getBean(EntityManagerFactory.class);\n\t\t\t\tMap<String, Object> map = factoryBean.getProperties();\n\t\t\t\tassertThat(map).containsEntry(\"configured\", \"manually\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registersHintsForJtaClasses() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew HibernateRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tfor (String noJtaPlatformClass : Arrays.asList(\n\t\t\t\t\"org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform\",\n\t\t\t\t\"org.hibernate.service.jta.platform.internal.NoJtaPlatform\")) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(TypeReference.of(noJtaPlatformClass))\n\t\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints);\n\t\t}\n\t}\n\n\t@Test\n\tvoid registersHintsForNamingClasses() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew HibernateRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tfor (Class<?> noJtaPlatformClass : Arrays.asList(SpringImplicitNamingStrategy.class,\n\t\t\t\tPhysicalNamingStrategySnakeCaseImpl.class)) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(noJtaPlatformClass)\n\t\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(hints);\n\t\t}\n\t}\n\n\t@Test\n\t@Disabled(\"gh-40177\")\n\tvoid whenSpringJpaGenerateDdlIsNotSetThenTableIsNotCreated() {\n\t\t// spring.jpa.generated-ddl defaults to false but this test still fails because\n\t\t// we're using an embedded database which means that HibernateProperties defaults\n\t\t// hibernate.hbm2ddl.auto to create-drop, replacing the\n\t\t// hibernate.hbm2ddl.auto=none that comes from generate-ddl being false.\n\t\tthis.contextRunner.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\tvoid whenSpringJpaGenerateDdlIsTrueThenTableIsCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.generate-ddl=true\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).contains(\"CITY\"));\n\t}\n\n\t@Test\n\t@Disabled(\"gh-40177\")\n\tvoid whenSpringJpaGenerateDdlIsFalseThenTableIsNotCreated() {\n\t\t// This test fails because we're using an embedded database which means that\n\t\t// HibernateProperties defaults hibernate.hbm2ddl.auto to create-drop, replacing\n\t\t// the hibernate.hbm2ddl.auto=none that comes from setting generate-ddl to false.\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.generate-ddl=false\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\tvoid whenHbm2DdlAutoIsNoneThenTableIsNotCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.hibernate.hbm2ddl.auto=none\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\tvoid whenSpringJpaHibernateDdlAutoIsNoneThenTableIsNotCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.hibernate.ddl-auto=none\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\t@Disabled(\"gh-40177\")\n\tvoid whenSpringJpaGenerateDdlIsTrueAndSpringJpaHibernateDdlAutoIsNoneThenTableIsNotCreated() {\n\t\t// This test fails because when ddl-auto is set to none, we remove\n\t\t// hibernate.hbm2ddl.auto from Hibernate properties. This then allows\n\t\t// spring.jpa.generate-ddl to set it to create-drop\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.generate-ddl=true\", \"spring.jpa.hibernate.ddl-auto=none\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\tvoid whenSpringJpaGenerateDdlIsTrueAndSpringJpaHibernateDdlAutoIsDropThenTableIsNotCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.generate-ddl=true\", \"spring.jpa.hibernate.ddl-auto=drop\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\tvoid whenSpringJpaGenerateDdlIsTrueAndJakartaSchemaGenerationIsNoneThenTableIsNotCreated() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.generate-ddl=true\",\n\t\t\t\t\t\"spring.jpa.properties.jakarta.persistence.schema-generation.database.action=none\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\t@Test\n\tvoid whenSpringJpaGenerateDdlIsTrueSpringJpaHibernateDdlAutoIsCreateAndJakartaSchemaGenerationIsNoneThenTableIsNotCreated() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.generate-ddl=true\", \"spring.jpa.hibernate.ddl-auto=create\",\n\t\t\t\t\t\"spring.jpa.properties.jakarta.persistence.schema-generation.database.action=none\")\n\t\t\t.run((context) -> assertThat(tablesFrom(context)).doesNotContain(\"CITY\"));\n\t}\n\n\tprivate List<String> tablesFrom(AssertableApplicationContext context) {\n\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\tJdbcTemplate jdbc = new JdbcTemplate(dataSource);\n\t\tList<String> tables = jdbc.query(\"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES\",\n\t\t\t\t(results, row) -> results.getString(1));\n\t\treturn tables;\n\t}\n\n\tprivate Class<?>[] getManagedJavaTypes(EntityManager entityManager) {\n\t\tSet<ManagedType<?>> managedTypes = entityManager.getMetamodel().getManagedTypes();\n\t\treturn managedTypes.stream().map(ManagedType::getJavaType).toArray(Class<?>[]::new);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class TestTwoDataSourcesConfiguration {\n\n\t\t@Bean\n\t\tDataSource firstDataSource() {\n\t\t\treturn createRandomDataSource();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource secondDataSource() {\n\t\t\treturn createRandomDataSource();\n\t\t}\n\n\t\tprivate DataSource createRandomDataSource() {\n\t\t\tString url = \"jdbc:h2:mem:init-\" + UUID.randomUUID();\n\t\t\treturn DataSourceBuilder.create().url(url).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestTwoDataSourcesAndPrimaryConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tDataSource firstDataSource() {\n\t\t\treturn createRandomDataSource();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource secondDataSource() {\n\t\t\treturn createRandomDataSource();\n\t\t}\n\n\t\tprivate DataSource createRandomDataSource() {\n\t\t\tString url = \"jdbc:h2:mem:init-\" + UUID.randomUUID();\n\t\t\treturn DataSourceBuilder.create().url(url).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tprotected static class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestFilterConfiguration {\n\n\t\t@Bean\n\t\tOpenEntityManagerInViewFilter openEntityManagerInViewFilter() {\n\t\t\treturn new OpenEntityManagerInViewFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestFilterRegistrationConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<OpenEntityManagerInViewFilter> openEntityManagerInViewFilterFilterRegistrationBean() {\n\t\t\treturn new FilterRegistrationBean<>();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestInterceptorManualConfiguration {\n\n\t\t@Bean\n\t\tOpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {\n\t\t\treturn new ManualOpenEntityManagerInViewInterceptor();\n\t\t}\n\n\t\tstatic class ManualOpenEntityManagerInViewInterceptor extends OpenEntityManagerInViewInterceptor {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfigurationWithEntityManagerFactoryBuilder extends TestConfiguration {\n\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder,\n\t\t\t\tDataSource dataSource) {\n\t\t\treturn builder.dataSource(dataSource).properties(Map.of(\"configured\", \"manually\")).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfigurationWithLocalContainerEntityManagerFactoryBean extends TestConfiguration {\n\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter adapter) {\n\t\t\tLocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();\n\t\t\tfactoryBean.setJpaVendorAdapter(adapter);\n\t\t\tfactoryBean.setDataSource(dataSource);\n\t\t\tfactoryBean.setPersistenceUnitName(\"manually-configured\");\n\t\t\tMap<String, Object> properties = new HashMap<>();\n\t\t\tproperties.put(\"configured\", \"manually\");\n\t\t\tproperties.put(\"hibernate.transaction.jta.platform\", NoJtaPlatform.INSTANCE);\n\t\t\tfactoryBean.setJpaPropertyMap(properties);\n\t\t\treturn factoryBean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfigurationWithEntityManagerFactory extends TestConfiguration {\n\n\t\t@Bean\n\t\tEntityManagerFactory entityManagerFactory(DataSource dataSource, JpaVendorAdapter adapter) {\n\t\t\tLocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();\n\t\t\tfactoryBean.setJpaVendorAdapter(adapter);\n\t\t\tfactoryBean.setDataSource(dataSource);\n\t\t\tfactoryBean.setPersistenceUnitName(\"manually-configured\");\n\t\t\tMap<String, Object> properties = new HashMap<>();\n\t\t\tproperties.put(\"configured\", \"manually\");\n\t\t\tproperties.put(\"hibernate.transaction.jta.platform\", NoJtaPlatform.INSTANCE);\n\t\t\tfactoryBean.setJpaPropertyMap(properties);\n\t\t\tfactoryBean.afterPropertiesSet();\n\t\t\tEntityManagerFactory bean = factoryBean.getObject();\n\t\t\tassertThat(bean).isNotNull();\n\t\t\treturn bean;\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager(EntityManagerFactory emf) {\n\t\t\tJpaTransactionManager transactionManager = new JpaTransactionManager();\n\t\t\ttransactionManager.setEntityManagerFactory(emf);\n\t\t\treturn transactionManager;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class TestConfigurationWithTransactionManager {\n\n\t\t@Bean\n\t\tJpaTransactionManager testTransactionManager() {\n\t\t\treturn new CustomJpaTransactionManager();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(Country.class)\n\tstatic class AutoConfigurePackageForCountry {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(HibernateJpaAutoConfigurationTests.class)\n\tstatic class TestConfigurationWithCustomPersistenceUnitManager {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tTestConfigurationWithCustomPersistenceUnitManager(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tPersistenceUnitManager persistenceUnitManager() {\n\t\t\tDefaultPersistenceUnitManager persistenceUnitManager = new DefaultPersistenceUnitManager();\n\t\t\tpersistenceUnitManager.setDefaultDataSource(this.dataSource);\n\t\t\tpersistenceUnitManager.setPackagesToScan(City.class.getPackage().getName());\n\t\t\treturn persistenceUnitManager;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(HibernateJpaAutoConfigurationTests.class)\n\tstatic class TestConfigurationWithCustomPersistenceUnitPostProcessors {\n\n\t\t@Bean\n\t\tEntityManagerFactoryBuilderCustomizer entityManagerFactoryBuilderCustomizer() {\n\t\t\treturn (builder) -> builder.setPersistenceUnitPostProcessors(\n\t\t\t\t\t(pui) -> pui.addManagedClassName(\"customized.attribute.converter.class.name\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(HibernateJpaAutoConfigurationTests.class)\n\tstatic class TestConfigurationWithMultipleCustomPersistenceUnitPostProcessors {\n\n\t\t@Bean\n\t\tEntityManagerFactoryBuilderCustomizer entityManagerFactoryBuilderCustomizer() {\n\t\t\treturn (builder) -> builder.addPersistenceUnitPostProcessors(\n\t\t\t\t\t(pui) -> pui.addManagedClassName(\"customized.attribute.converter.class.name\"));\n\t\t}\n\n\t\t@Bean\n\t\tEntityManagerFactoryBuilderCustomizer anotherEntityManagerFactoryBuilderCustomizer() {\n\t\t\treturn (builder) -> builder.addPersistenceUnitPostProcessors(\n\t\t\t\t\t(pui) -> pui.addManagedClassName(\"customized.attribute.converter.class.anotherName\"));\n\t\t}\n\n\t}\n\n\tstatic class CustomJpaTransactionManager extends JpaTransactionManager {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"META-INF/persistence.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<persistence version=\"2.0\" xmlns=\"http://java.sun.com/xml/ns/persistence\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/persistence https://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">\n\t\t\t\t\t\t<persistence-unit name=\"manually-configured\">\n\t\t\t\t\t\t\t<class>org.springframework.boot.jpa.autoconfigure.test.city.City</class>\n\t\t\t\t\t\t\t<exclude-unlisted-classes>true</exclude-unlisted-classes>\n\t\t\t\t\t\t</persistence-unit>\n\t\t\t\t\t</persistence>\n\t\t\t\t\t\"\"\")\n\tprotected @interface WithMetaInfPersistenceXmlResource {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\t@DependsOnDatabaseInitialization\n\tstatic class TestInitializedJpaConfiguration {\n\n\t\tprivate boolean called;\n\n\t\t@Autowired\n\t\tvoid validateDataSourceIsInitialized(EntityManagerFactory entityManagerFactory) {\n\t\t\t// Inject the entity manager to validate it is initialized at the injection\n\t\t\t// point\n\t\t\tEntityManager entityManager = entityManagerFactory.createEntityManager();\n\t\t\tCity city = entityManager.find(City.class, 2000L);\n\t\t\tassertThat(city).isNotNull();\n\t\t\tassertThat(city.getName()).isEqualTo(\"Washington\");\n\t\t\tthis.called = true;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestImplicitNamingStrategyConfiguration {\n\n\t\t@Bean\n\t\tImplicitNamingStrategy testImplicitNamingStrategy() {\n\t\t\treturn new SpringImplicitNamingStrategy();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestPhysicalNamingStrategyConfiguration {\n\n\t\t@Bean\n\t\tPhysicalNamingStrategy testPhysicalNamingStrategy() {\n\t\t\treturn new PhysicalNamingStrategySnakeCaseImpl();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestHibernatePropertiesCustomizerConfiguration {\n\n\t\tprivate final PhysicalNamingStrategy physicalNamingStrategy = new PhysicalNamingStrategySnakeCaseImpl();\n\n\t\tprivate final ImplicitNamingStrategy implicitNamingStrategy = new SpringImplicitNamingStrategy();\n\n\t\t@Bean\n\t\tHibernatePropertiesCustomizer testHibernatePropertiesCustomizer() {\n\t\t\treturn (hibernateProperties) -> {\n\t\t\t\thibernateProperties.put(\"hibernate.physical_naming_strategy\", this.physicalNamingStrategy);\n\t\t\t\thibernateProperties.put(\"hibernate.implicit_naming_strategy\", this.implicitNamingStrategy);\n\t\t\t};\n\t\t}\n\n\t}\n\n\tpublic static class TestJtaPlatform implements JtaPlatform {\n\n\t\t@Override\n\t\tpublic TransactionManager retrieveTransactionManager() {\n\t\t\treturn mock(TransactionManager.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic UserTransaction retrieveUserTransaction() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic Object getTransactionIdentifier(Transaction transaction) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canRegisterSynchronization() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerSynchronization(Synchronization synchronization) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic int getCurrentStatus() {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n\tstatic class HideDataScriptClassLoader extends URLClassLoader {\n\n\t\tprivate static final List<String> HIDDEN_RESOURCES = Arrays.asList(\"schema-all.sql\", \"schema.sql\");\n\n\t\tHideDataScriptClassLoader() {\n\t\t\tsuper(new URL[0], Thread.currentThread().getContextClassLoader());\n\t\t}\n\n\t\t@Override\n\t\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t\tif (HIDDEN_RESOURCES.contains(name)) {\n\t\t\t\treturn Collections.emptyEnumeration();\n\t\t\t}\n\t\t\treturn super.getResources(name);\n\t\t}\n\n\t}\n\n\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\tstatic class JpaUsingApplicationListenerConfiguration {\n\n\t\t@Bean\n\t\tEventCapturingApplicationListener jpaUsingApplicationListener(EntityManagerFactory emf) {\n\t\t\treturn new EventCapturingApplicationListener();\n\t\t}\n\n\t\tstatic class EventCapturingApplicationListener implements ApplicationListener<ApplicationEvent> {\n\n\t\t\tprivate final List<ApplicationEvent> events = new ArrayList<>();\n\n\t\t\t@Override\n\t\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\t\tthis.events.add(event);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AsyncBootstrappingConfiguration {\n\n\t\t@Bean\n\t\tThreadPoolTaskExecutor ThreadPoolTaskExecutor() {\n\t\t\treturn new ThreadPoolTaskExecutor();\n\t\t}\n\n\t\t@Bean\n\t\tEntityManagerFactoryBuilderCustomizer asyncBootstrappingCustomizer(ThreadPoolTaskExecutor executor) {\n\t\t\treturn (builder) -> builder.setBootstrapExecutor(executor);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfigurationWithLocalContainerEntityManagerFactoryBeanWithNoJpaVendorAdapter\n\t\t\textends TestConfiguration {\n\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {\n\t\t\tLocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();\n\t\t\tfactoryBean.setDataSource(dataSource);\n\t\t\tfactoryBean.setPersistenceUnitName(\"manually-configured\");\n\t\t\tfactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);\n\t\t\tMap<String, Object> properties = new HashMap<>();\n\t\t\tproperties.put(\"configured\", \"manually\");\n\t\t\tproperties.put(\"hibernate.transaction.jta.platform\", NoJtaPlatform.INSTANCE);\n\t\t\tfactoryBean.setJpaPropertyMap(properties);\n\t\t\treturn factoryBean;\n\t\t}\n\n\t}\n\n\tpublic static class TestH2Dialect extends H2Dialect {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JtaTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tJtaTransactionManager jtaTransactionManager() {\n\t\t\tJtaTransactionManager jtaTransactionManager = new JtaTransactionManager();\n\t\t\tjtaTransactionManager.setUserTransaction(mock(UserTransaction.class));\n\t\t\tjtaTransactionManager.setTransactionManager(mock(TransactionManager.class));\n\t\t\treturn jtaTransactionManager;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SingleAsyncTaskExecutorConfiguration {\n\n\t\t@Bean\n\t\tSimpleAsyncTaskExecutor exampleTaskExecutor() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleAsyncTaskExecutorsConfiguration {\n\n\t\t@Bean\n\t\tSimpleAsyncTaskExecutor exampleTaskExecutor1() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t\t@Bean\n\t\tSimpleAsyncTaskExecutor exampleTaskExecutor2() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ApplicationTaskExecutorConfiguration {\n\n\t\t@Bean\n\t\tSimpleAsyncTaskExecutor applicationTaskExecutor() {\n\t\t\treturn new SimpleAsyncTaskExecutor();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/HibernatePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport org.hibernate.boot.model.naming.PhysicalNamingStrategySnakeCaseImpl;\nimport org.hibernate.cfg.MappingSettings;\nimport org.hibernate.cfg.PersistenceSettings;\nimport org.hibernate.cfg.SchemaToolingSettings;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.hibernate.SpringImplicitNamingStrategy;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link HibernateProperties}.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @author Chris Bono\n */\n@ExtendWith(MockitoExtension.class)\nclass HibernatePropertiesTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfiguration.class);\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Supplier<String> ddlAutoSupplier;\n\n\t@Test\n\tvoid noCustomNamingStrategy() {\n\t\tthis.contextRunner.run(assertHibernateProperties((hibernateProperties) -> {\n\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t\tassertThat(hibernateProperties).containsEntry(MappingSettings.PHYSICAL_NAMING_STRATEGY,\n\t\t\t\t\tPhysicalNamingStrategySnakeCaseImpl.class.getName());\n\t\t\tassertThat(hibernateProperties).containsEntry(MappingSettings.IMPLICIT_NAMING_STRATEGY,\n\t\t\t\t\tSpringImplicitNamingStrategy.class.getName());\n\t\t}));\n\t}\n\n\t@Test\n\tvoid hibernate5CustomNamingStrategies() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.hibernate.naming.implicit-strategy:com.example.Implicit\",\n\t\t\t\t\t\"spring.jpa.hibernate.naming.physical-strategy:com.example.Physical\")\n\t\t\t.run(assertHibernateProperties((hibernateProperties) -> {\n\t\t\t\tassertThat(hibernateProperties).contains(\n\t\t\t\t\t\tentry(MappingSettings.IMPLICIT_NAMING_STRATEGY, \"com.example.Implicit\"),\n\t\t\t\t\t\tentry(MappingSettings.PHYSICAL_NAMING_STRATEGY, \"com.example.Physical\"));\n\t\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid hibernate5CustomNamingStrategiesViaJpaProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.properties.hibernate.implicit_naming_strategy:com.example.Implicit\",\n\t\t\t\t\t\"spring.jpa.properties.hibernate.physical_naming_strategy:com.example.Physical\")\n\t\t\t.run(assertHibernateProperties((hibernateProperties) -> {\n\t\t\t\t// You can override them as we don't provide any default\n\t\t\t\tassertThat(hibernateProperties).contains(\n\t\t\t\t\t\tentry(MappingSettings.IMPLICIT_NAMING_STRATEGY, \"com.example.Implicit\"),\n\t\t\t\t\t\tentry(MappingSettings.PHYSICAL_NAMING_STRATEGY, \"com.example.Physical\"));\n\t\t\t\tassertThat(hibernateProperties).doesNotContainKeys(\"hibernate.ejb.naming_strategy\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid scannerUsesDisabledScannerByDefault() {\n\t\tthis.contextRunner.run(assertHibernateProperties((hibernateProperties) -> assertThat(hibernateProperties)\n\t\t\t.containsEntry(PersistenceSettings.SCANNER, \"org.hibernate.boot.archive.scan.internal.DisabledScanner\")));\n\t}\n\n\t@Test\n\tvoid scannerCanBeCustomized() {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.jpa.properties.hibernate.archive.scanner:org.hibernate.boot.archive.scan.internal.StandardScanner\")\n\t\t\t.run(assertHibernateProperties((hibernateProperties) -> assertThat(hibernateProperties).containsEntry(\n\t\t\t\t\tPersistenceSettings.SCANNER, \"org.hibernate.boot.archive.scan.internal.StandardScanner\")));\n\t}\n\n\t@Test\n\tvoid defaultDdlAutoIsNotInvokedIfPropertyIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.hibernate.ddl-auto=validate\")\n\t\t\t.run(assertDefaultDdlAutoNotInvoked(\"validate\"));\n\t}\n\n\t@Test\n\tvoid defaultDdlAutoIsNotInvokedIfHibernateSpecificPropertyIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.hibernate.hbm2ddl.auto=create\")\n\t\t\t.run(assertDefaultDdlAutoNotInvoked(\"create\"));\n\t}\n\n\t@Test\n\tvoid defaultDdlAutoIsNotInvokedAndDdlAutoIsNotSetIfJpaDbActionPropertyIsSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.jpa.properties.jakarta.persistence.schema-generation.database.action=drop-and-create\")\n\t\t\t.run(assertHibernateProperties((hibernateProperties) -> {\n\t\t\t\tassertThat(hibernateProperties).doesNotContainKey(SchemaToolingSettings.HBM2DDL_AUTO);\n\t\t\t\tassertThat(hibernateProperties).containsEntry(SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION,\n\t\t\t\t\t\t\"drop-and-create\");\n\t\t\t\tthen(this.ddlAutoSupplier).should(never()).get();\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertDefaultDdlAutoNotInvoked(String expectedDdlAuto) {\n\t\treturn assertHibernateProperties((hibernateProperties) -> {\n\t\t\tassertThat(hibernateProperties).containsEntry(SchemaToolingSettings.HBM2DDL_AUTO, expectedDdlAuto);\n\t\t\tthen(this.ddlAutoSupplier).should(never()).get();\n\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertHibernateProperties(\n\t\t\tConsumer<Map<String, Object>> consumer) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(JpaProperties.class);\n\t\t\tassertThat(context).hasSingleBean(HibernateProperties.class);\n\t\t\tMap<String, Object> hibernateProperties = context.getBean(HibernateProperties.class)\n\t\t\t\t.determineHibernateProperties(context.getBean(JpaProperties.class).getProperties(),\n\t\t\t\t\t\tnew HibernateSettings().ddlAuto(this.ddlAutoSupplier));\n\t\t\tconsumer.accept(hibernateProperties);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties({ JpaProperties.class, HibernateProperties.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/mapping/NonAnnotatedEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure.mapping;\n\n/**\n * A non annotated entity that is handled by a custom \"mapping-file\".\n *\n * @author Stephane Nicoll\n */\npublic class NonAnnotatedEntity {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String item;\n\n\tprotected NonAnnotatedEntity() {\n\t}\n\n\tpublic NonAnnotatedEntity(String item) {\n\t\tthis.item = item;\n\t}\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getItem() {\n\t\treturn this.item;\n\t}\n\n\tpublic void setItem(String value) {\n\t\tthis.item = value;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/mapping/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.hibernate.autoconfigure.mapping;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/metrics/HibernateMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure.metrics;\n\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.PersistenceException;\nimport org.hibernate.SessionFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentMatchers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration;\nimport org.springframework.boot.jpa.EntityManagerFactoryBuilder;\nimport org.springframework.boot.jpa.autoconfigure.EntityManagerFactoryBuilderCustomizer;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HibernateMetricsAutoConfiguration}.\n *\n * @author Rui Figueira\n * @author Stephane Nicoll\n */\nclass HibernateMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,\n\t\t\t\tHibernateMetricsAutoConfiguration.class, MetricsAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid autoConfiguredEntityManagerFactoryWithStatsIsInstrumented() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.hibernate.generate_statistics:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"hibernate.statements\").tags(\"entityManagerFactory\", \"entityManagerFactory\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredEntityManagerFactoryWithoutStatsIsNotInstrumented() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.hibernate.generate_statistics:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class);\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hibernate.statements\").meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid entityManagerFactoryInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.metrics.enable.hibernate=false\",\n\t\t\t\t\t\"spring.jpa.properties.hibernate.generate_statistics:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class);\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hibernate.statements\").meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allEntityManagerFactoriesCanBeInstrumented() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.hibernate.generate_statistics:true\")\n\t\t\t.withUserConfiguration(MultipleEntityManagerFactoriesConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"firstEntityManagerFactory\", EntityManagerFactory.class).unwrap(SessionFactory.class);\n\t\t\t\tcontext.getBean(\"nonDefault\", EntityManagerFactory.class).unwrap(SessionFactory.class);\n\t\t\t\tcontext.getBean(\"nonAutowire\", EntityManagerFactory.class).unwrap(SessionFactory.class);\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hibernate.statements\").meters())\n\t\t\t\t\t.map((meter) -> meter.getId().getTag(\"entityManagerFactory\"))\n\t\t\t\t\t.containsOnly(\"first\", \"nonDefault\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid entityManagerFactoryInstrumentationIsDisabledIfNotHibernateSessionFactory() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jpa.properties.hibernate.generate_statistics:true\")\n\t\t\t.withUserConfiguration(NonHibernateEntityManagerFactoryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\t// ensure EntityManagerFactory is not a Hibernate SessionFactory\n\t\t\t\tassertThatExceptionOfType(PersistenceException.class)\n\t\t\t\t\t.isThrownBy(() -> context.getBean(EntityManagerFactory.class).unwrap(SessionFactory.class));\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hibernate.statements\").meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid entityManagerFactoryInstrumentationIsDisabledIfHibernateIsNotAvailable() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(SessionFactory.class))\n\t\t\t.withUserConfiguration(NonHibernateEntityManagerFactoryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(HibernateMetricsAutoConfiguration.class);\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hibernate.statements\").meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"city-schema.sql\", content = \"\"\"\n\t\t\tCREATE TABLE CITY (\n\t\t\t  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\t\t\t  name VARCHAR(30),\n\t\t\t  state  VARCHAR(30),\n\t\t\t  country  VARCHAR(30),\n\t\t\t  map  VARCHAR(30)\n\t\t\t);\n\t\t\t\"\"\")\n\t@WithResource(name = \"city-data.sql\",\n\t\t\tcontent = \"INSERT INTO CITY (ID, NAME, STATE, COUNTRY, MAP) values (2000, 'Washington', 'DC', 'US', 'Google');\")\n\tvoid entityManagerFactoryInstrumentationDoesNotDeadlockWithDeferredInitialization() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jpa.properties.hibernate.generate_statistics:true\",\n\t\t\t\t\t\"spring.sql.init.schema-locations:city-schema.sql\", \"spring.sql.init.data-locations=city-data.sql\")\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceInitializationAutoConfiguration.class))\n\t\t\t.withBean(EntityManagerFactoryBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setBootstrapExecutor(new SimpleAsyncTaskExecutor()))\n\t\t\t.run((context) -> {\n\t\t\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(DataSource.class));\n\t\t\t\tassertThat(jdbcTemplate.queryForObject(\"SELECT COUNT(*) from CITY\", Integer.class)).isOne();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"hibernate.statements\").tags(\"entityManagerFactory\", \"entityManagerFactory\").meter();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tSimpleMeterRegistry simpleMeterRegistry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Entity\n\tstatic class MyEntity {\n\n\t\t@Id\n\t\t@GeneratedValue\n\t\tprivate @Nullable Long id;\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleEntityManagerFactoriesConfiguration {\n\n\t\tprivate static final Class<?>[] PACKAGE_CLASSES = new Class<?>[] { MyEntity.class };\n\n\t\t@Primary\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean firstEntityManagerFactory(DataSource ds) {\n\t\t\treturn createSessionFactory(ds);\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tLocalContainerEntityManagerFactoryBean nonDefault(DataSource ds) {\n\t\t\treturn createSessionFactory(ds);\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tLocalContainerEntityManagerFactoryBean nonAutowire(DataSource ds) {\n\t\t\treturn createSessionFactory(ds);\n\t\t}\n\n\t\tprivate LocalContainerEntityManagerFactoryBean createSessionFactory(DataSource ds) {\n\t\t\tFunction<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> Map\n\t\t\t\t.of(\"hibernate.generate_statistics\", \"true\");\n\t\t\treturn new EntityManagerFactoryBuilder(new HibernateJpaVendorAdapter(), jpaPropertiesFactory, null)\n\t\t\t\t.dataSource(ds)\n\t\t\t\t.packages(PACKAGE_CLASSES)\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonHibernateEntityManagerFactoryConfiguration {\n\n\t\t@Bean\n\t\tEntityManagerFactory entityManagerFactory() {\n\t\t\tEntityManagerFactory mockedFactory = mock(EntityManagerFactory.class);\n\t\t\t// enforces JPA contract\n\t\t\tgiven(mockedFactory.unwrap(ArgumentMatchers.<Class<SessionFactory>>any()))\n\t\t\t\t.willThrow(PersistenceException.class);\n\t\t\treturn mockedFactory;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/test/city/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure.test.city;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.EntityListeners;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n@Entity\n@EntityListeners(CityListener.class)\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String state, String country, String map) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t\tthis.country = country;\n\t\tthis.map = map;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/test/city/CityListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure.test.city;\n\nimport jakarta.persistence.PostLoad;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\n\npublic class CityListener {\n\n\tprivate @Nullable ConfigurableBeanFactory beanFactory;\n\n\tpublic CityListener() {\n\t}\n\n\t@Autowired\n\tpublic CityListener(ConfigurableBeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@PostLoad\n\tpublic void postLoad(City city) {\n\t\tif (this.beanFactory != null) {\n\t\t\tthis.beanFactory.registerSingleton(City.class.getName(), city);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/test/city/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.hibernate.autoconfigure.test.city;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/test/country/Country.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.hibernate.autoconfigure.test.country;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport org.hibernate.envers.Audited;\n\n@Entity\npublic class Country implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Audited\n\t@Column\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-hibernate/src/test/java/org/springframework/boot/hibernate/autoconfigure/test/country/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.hibernate.autoconfigure.test.country;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot HTTP Client\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-web\")\n\n\timplementation(project(\":module:spring-boot-http-converter\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-reactor-netty\"))\n\toptional(\"org.apache.httpcomponents.client5:httpclient5\")\n\toptional(\"org.apache.httpcomponents.core5:httpcore5-reactive\")\n\toptional(\"org.eclipse.jetty:jetty-client\")\n\toptional(\"org.eclipse.jetty:jetty-reactive-httpclient\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/AbstractClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.util.Assert;\n\n/**\n * Internal base class used for {@link ClientHttpRequestFactoryBuilder} implementations.\n *\n * @param <T> the {@link ClientHttpRequestFactory} type\n * @author Phillip Webb\n */\nabstract class AbstractClientHttpRequestFactoryBuilder<T extends ClientHttpRequestFactory>\n\t\timplements ClientHttpRequestFactoryBuilder<T> {\n\n\tprivate final List<Consumer<T>> customizers;\n\n\tprotected AbstractClientHttpRequestFactoryBuilder(@Nullable List<Consumer<T>> customizers) {\n\t\tthis.customizers = (customizers != null) ? customizers : Collections.emptyList();\n\t}\n\n\tprotected final List<Consumer<T>> getCustomizers() {\n\t\treturn this.customizers;\n\t}\n\n\tprotected final List<Consumer<T>> mergedCustomizers(Consumer<T> customizer) {\n\t\tAssert.notNull(this.customizers, \"'customizer' must not be null\");\n\t\treturn merge(this.customizers, List.of(customizer));\n\t}\n\n\tprotected final List<Consumer<T>> mergedCustomizers(Collection<Consumer<T>> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tAssert.noNullElements(customizers, \"'customizers' must not contain null elements\");\n\t\treturn merge(this.customizers, customizers);\n\t}\n\n\tprivate <E> List<E> merge(Collection<E> list, Collection<? extends E> additional) {\n\t\tList<E> merged = new ArrayList<>(list);\n\t\tmerged.addAll(additional);\n\t\treturn List.copyOf(merged);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic final T build(@Nullable HttpClientSettings settings) {\n\t\tT factory = createClientHttpRequestFactory((settings != null) ? settings : HttpClientSettings.defaults());\n\t\tLambdaSafe.callbacks(Consumer.class, this.customizers, factory).invoke((consumer) -> consumer.accept(factory));\n\t\treturn factory;\n\t}\n\n\tprotected abstract T createClientHttpRequestFactory(HttpClientSettings settings);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.util.Assert;\n\n/**\n * Interface used to build a fully configured {@link ClientHttpRequestFactory}. Builders\n * for {@link #httpComponents() Apache HTTP Components}, {@link #jetty() Jetty},\n * {@link #reactor() Reactor}, {@link #jdk() JDK} and {@link #simple() simple client} can\n * be obtained using the factory methods on this interface. The {@link #of(Class)} and\n * {@link #of(Supplier)} methods may be used to instantiate other\n * {@link ClientHttpRequestFactory} instances using reflection.\n *\n * @param <T> the {@link ClientHttpRequestFactory} type\n * @author Phillip Webb\n * @since 3.4.0\n */\n@FunctionalInterface\npublic interface ClientHttpRequestFactoryBuilder<T extends ClientHttpRequestFactory> {\n\n\t/**\n\t * Build a default configured {@link ClientHttpRequestFactory}.\n\t * @return a default configured {@link ClientHttpRequestFactory}.\n\t */\n\tdefault T build() {\n\t\treturn build(null);\n\t}\n\n\t/**\n\t * Build a fully configured {@link ClientHttpRequestFactory}, applying the given\n\t * {@code settings} if they are provided.\n\t * @param settings the settings to apply or {@code null}\n\t * @return a fully configured {@link ClientHttpRequestFactory}.\n\t */\n\tT build(@Nullable HttpClientSettings settings);\n\n\t/**\n\t * Return a new {@link ClientHttpRequestFactoryBuilder} that applies the given\n\t * customizer to the {@link ClientHttpRequestFactory} after it has been built.\n\t * @param customizer the customizers to apply\n\t * @return a new {@link ClientHttpRequestFactoryBuilder} instance\n\t */\n\tdefault ClientHttpRequestFactoryBuilder<T> withCustomizer(Consumer<T> customizer) {\n\t\treturn withCustomizers(List.of(customizer));\n\t}\n\n\t/**\n\t * Return a new {@link ClientHttpRequestFactoryBuilder} that applies the given\n\t * customizers to the {@link ClientHttpRequestFactory} after it has been built.\n\t * @param customizers the customizers to apply\n\t * @return a new {@link ClientHttpRequestFactoryBuilder} instance\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tdefault ClientHttpRequestFactoryBuilder<T> withCustomizers(Collection<Consumer<T>> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tAssert.noNullElements(customizers, \"'customizers' must not contain null elements\");\n\t\treturn (settings) -> {\n\t\t\tT factory = build(settings);\n\t\t\tLambdaSafe.callbacks(Consumer.class, customizers, factory).invoke((consumer) -> consumer.accept(factory));\n\t\t\treturn factory;\n\t\t};\n\t}\n\n\t/**\n\t * Return a {@link HttpComponentsClientHttpRequestFactoryBuilder} that can be used to\n\t * build a {@link HttpComponentsClientHttpRequestFactory}.\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder}\n\t */\n\tstatic HttpComponentsClientHttpRequestFactoryBuilder httpComponents() {\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder();\n\t}\n\n\t/**\n\t * Return a {@link JettyClientHttpRequestFactoryBuilder} that can be used to build a\n\t * {@link JettyClientHttpRequestFactory}.\n\t * @return a new {@link JettyClientHttpRequestFactoryBuilder}\n\t */\n\tstatic JettyClientHttpRequestFactoryBuilder jetty() {\n\t\treturn new JettyClientHttpRequestFactoryBuilder();\n\t}\n\n\t/**\n\t * Return a {@link ReactorClientHttpRequestFactoryBuilder} that can be used to build a\n\t * {@link ReactorClientHttpRequestFactory}.\n\t * @return a new {@link ReactorClientHttpRequestFactoryBuilder}\n\t */\n\tstatic ReactorClientHttpRequestFactoryBuilder reactor() {\n\t\treturn new ReactorClientHttpRequestFactoryBuilder();\n\t}\n\n\t/**\n\t * Return a {@link JdkClientHttpRequestFactoryBuilder} that can be used to build a\n\t * {@link JdkClientHttpRequestFactory} .\n\t * @return a new {@link JdkClientHttpRequestFactoryBuilder}\n\t */\n\tstatic JdkClientHttpRequestFactoryBuilder jdk() {\n\t\treturn new JdkClientHttpRequestFactoryBuilder();\n\t}\n\n\t/**\n\t * Return a {@link SimpleClientHttpRequestFactoryBuilder} that can be used to build a\n\t * {@link SimpleClientHttpRequestFactory} .\n\t * @return a new {@link SimpleClientHttpRequestFactoryBuilder}\n\t */\n\tstatic SimpleClientHttpRequestFactoryBuilder simple() {\n\t\treturn new SimpleClientHttpRequestFactoryBuilder();\n\t}\n\n\t/**\n\t * Return a new {@link ClientHttpRequestFactoryBuilder} for the given\n\t * {@code requestFactoryType}. The following implementations are supported without the\n\t * use of reflection:\n\t * <ul>\n\t * <li>{@link HttpComponentsClientHttpRequestFactory}</li>\n\t * <li>{@link JdkClientHttpRequestFactory}</li>\n\t * <li>{@link JettyClientHttpRequestFactory}</li>\n\t * <li>{@link ReactorClientHttpRequestFactory}</li>\n\t * <li>{@link SimpleClientHttpRequestFactory}</li>\n\t * </ul>\n\t * @param <T> the {@link ClientHttpRequestFactory} type\n\t * @param requestFactoryType the {@link ClientHttpRequestFactory} type\n\t * @return a new {@link ClientHttpRequestFactoryBuilder}\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <T extends ClientHttpRequestFactory> ClientHttpRequestFactoryBuilder<T> of(Class<T> requestFactoryType) {\n\t\tAssert.notNull(requestFactoryType, \"'requestFactoryType' must not be null\");\n\t\tAssert.isTrue(requestFactoryType != ClientHttpRequestFactory.class,\n\t\t\t\t\"'requestFactoryType' must be an implementation of ClientHttpRequestFactory\");\n\t\tif (requestFactoryType == HttpComponentsClientHttpRequestFactory.class) {\n\t\t\treturn (ClientHttpRequestFactoryBuilder<T>) httpComponents();\n\t\t}\n\t\tif (requestFactoryType == JettyClientHttpRequestFactory.class) {\n\t\t\treturn (ClientHttpRequestFactoryBuilder<T>) jetty();\n\t\t}\n\t\tif (requestFactoryType == ReactorClientHttpRequestFactory.class) {\n\t\t\treturn (ClientHttpRequestFactoryBuilder<T>) reactor();\n\t\t}\n\t\tif (requestFactoryType == JdkClientHttpRequestFactory.class) {\n\t\t\treturn (ClientHttpRequestFactoryBuilder<T>) jdk();\n\t\t}\n\t\tif (requestFactoryType == SimpleClientHttpRequestFactory.class) {\n\t\t\treturn (ClientHttpRequestFactoryBuilder<T>) simple();\n\t\t}\n\t\treturn new ReflectiveComponentsClientHttpRequestFactoryBuilder<>(requestFactoryType);\n\t}\n\n\t/**\n\t * Return a new {@link ClientHttpRequestFactoryBuilder} from the given supplier, using\n\t * reflection to ultimately apply the {@link HttpClientSettings}.\n\t * @param <T> the {@link ClientHttpRequestFactory} type\n\t * @param requestFactorySupplier the {@link ClientHttpRequestFactory} supplier\n\t * @return a new {@link ClientHttpRequestFactoryBuilder}\n\t */\n\tstatic <T extends ClientHttpRequestFactory> ClientHttpRequestFactoryBuilder<T> of(\n\t\t\tSupplier<T> requestFactorySupplier) {\n\t\treturn new ReflectiveComponentsClientHttpRequestFactoryBuilder<>(requestFactorySupplier);\n\t}\n\n\t/**\n\t * Detect the most suitable {@link ClientHttpRequestFactoryBuilder} based on the\n\t * classpath. The method favors builders in the following order:\n\t * <ol>\n\t * <li>{@link #httpComponents()}</li>\n\t * <li>{@link #jetty()}</li>\n\t * <li>{@link #reactor()}</li>\n\t * <li>{@link #jdk()}</li>\n\t * <li>{@link #simple()}</li>\n\t * </ol>\n\t * @return the most suitable {@link ClientHttpRequestFactoryBuilder} for the classpath\n\t */\n\tstatic ClientHttpRequestFactoryBuilder<? extends ClientHttpRequestFactory> detect() {\n\t\treturn detect(null);\n\t}\n\n\t/**\n\t * Detect the most suitable {@link ClientHttpRequestFactoryBuilder} based on the\n\t * classpath. The method favors builders in the following order:\n\t * <ol>\n\t * <li>{@link #httpComponents()}</li>\n\t * <li>{@link #jetty()}</li>\n\t * <li>{@link #reactor()}</li>\n\t * <li>{@link #jdk()}</li>\n\t * <li>{@link #simple()}</li>\n\t * </ol>\n\t * @param classLoader the class loader to use for detection\n\t * @return the most suitable {@link ClientHttpRequestFactoryBuilder} for the classpath\n\t * @since 3.5.0\n\t */\n\tstatic ClientHttpRequestFactoryBuilder<? extends ClientHttpRequestFactory> detect(\n\t\t\t@Nullable ClassLoader classLoader) {\n\t\tif (HttpComponentsClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {\n\t\t\treturn httpComponents();\n\t\t}\n\t\tif (JettyClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {\n\t\t\treturn jetty();\n\t\t}\n\t\tif (ReactorClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {\n\t\t\treturn reactor();\n\t\t}\n\t\tif (JdkClientHttpRequestFactoryBuilder.Classes.present(classLoader)) {\n\t\t\treturn jdk();\n\t\t}\n\t\treturn simple();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ClientHttpRequestFactoryRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.net.HttpURLConnection;\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link RuntimeHintsRegistrar} for {@link ClientHttpRequestFactory} implementations.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ClientHttpRequestFactoryRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tif (ClassUtils.isPresent(\"org.springframework.http.client.ClientHttpRequestFactory\", classLoader)) {\n\t\t\tregisterHints(hints.reflection(), classLoader);\n\t\t}\n\t}\n\n\tprivate void registerHints(ReflectionHints hints, @Nullable ClassLoader classLoader) {\n\t\thints.registerField(findField(AbstractClientHttpRequestFactoryWrapper.class, \"requestFactory\"));\n\t\tregisterClientHttpRequestFactoryHints(hints, classLoader,\n\t\t\t\tHttpComponentsClientHttpRequestFactoryBuilder.Classes.HTTP_CLIENTS,\n\t\t\t\t() -> registerReflectionHints(hints, HttpComponentsClientHttpRequestFactory.class));\n\t\tregisterClientHttpRequestFactoryHints(hints, classLoader,\n\t\t\t\tJettyClientHttpRequestFactoryBuilder.Classes.HTTP_CLIENT,\n\t\t\t\t() -> registerReflectionHints(hints, JettyClientHttpRequestFactory.class, long.class));\n\t\tregisterClientHttpRequestFactoryHints(hints, classLoader,\n\t\t\t\tReactorClientHttpRequestFactoryBuilder.Classes.HTTP_CLIENT,\n\t\t\t\t() -> registerReflectionHints(hints, ReactorClientHttpRequestFactory.class, long.class));\n\t\tregisterClientHttpRequestFactoryHints(hints, classLoader,\n\t\t\t\tJdkClientHttpRequestFactoryBuilder.Classes.HTTP_CLIENT,\n\t\t\t\t() -> registerReflectionHints(hints, JdkClientHttpRequestFactory.class));\n\t\thints.registerType(SimpleClientHttpRequestFactory.class, (typeHint) -> {\n\t\t\ttypeHint.onReachableType(HttpURLConnection.class);\n\t\t\tregisterReflectionHints(hints, SimpleClientHttpRequestFactory.class);\n\t\t});\n\t}\n\n\tprivate void registerClientHttpRequestFactoryHints(ReflectionHints hints, @Nullable ClassLoader classLoader,\n\t\t\tString className, Runnable action) {\n\t\thints.registerTypeIfPresent(classLoader, className, (typeHint) -> {\n\t\t\ttypeHint.onReachableType(TypeReference.of(className));\n\t\t\taction.run();\n\t\t});\n\t}\n\n\tprivate void registerReflectionHints(ReflectionHints hints,\n\t\t\tClass<? extends ClientHttpRequestFactory> requestFactoryType) {\n\t\tregisterReflectionHints(hints, requestFactoryType, int.class);\n\t}\n\n\tprivate void registerReflectionHints(ReflectionHints hints,\n\t\t\tClass<? extends ClientHttpRequestFactory> requestFactoryType, Class<?> readTimeoutType) {\n\t\tregisterMethod(hints, requestFactoryType, \"setConnectTimeout\", int.class);\n\t\tregisterMethod(hints, requestFactoryType, \"setConnectTimeout\", Duration.class);\n\t\tregisterMethod(hints, requestFactoryType, \"setReadTimeout\", readTimeoutType);\n\t\tregisterMethod(hints, requestFactoryType, \"setReadTimeout\", Duration.class);\n\t}\n\n\tprivate void registerMethod(ReflectionHints hints, Class<? extends ClientHttpRequestFactory> requestFactoryType,\n\t\t\tString methodName, Class<?>... parameterTypes) {\n\t\tMethod method = ReflectionUtils.findMethod(requestFactoryType, methodName, parameterTypes);\n\t\tif (method != null) {\n\t\t\thints.registerMethod(method, ExecutableMode.INVOKE);\n\t\t}\n\t}\n\n\tprivate Field findField(Class<?> type, String name) {\n\t\tField field = ReflectionUtils.findField(type, name);\n\t\tAssert.state(field != null, () -> \"Unable to find field '%s' on %s\".formatted(type.getName(), name));\n\t\treturn field;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/Empty.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.util.function.Consumer;\n\n/**\n * Helper for empty functional interfaces.\n *\n * @author Phillip Webb\n */\nfinal class Empty {\n\n\tprivate static final Consumer<?> EMPTY_CUSTOMIZER = (t) -> {\n\t};\n\n\tprivate Empty() {\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <T> Consumer<T> consumer() {\n\t\treturn (Consumer<T>) EMPTY_CUSTOMIZER;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpClientSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Settings that can be applied when creating an imperative or reactive HTTP client.\n *\n * @param cookieHandling the cookie handling strategy to use or null to use the underlying\n * library's default\n * @param redirects the follow redirect strategy to use or null to redirect whenever the\n * underlying library allows it\n * @param connectTimeout the connect timeout\n * @param readTimeout the read timeout\n * @param sslBundle the SSL bundle providing SSL configuration\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic record HttpClientSettings(@Nullable HttpCookieHandling cookieHandling, @Nullable HttpRedirects redirects,\n\t\t@Nullable Duration connectTimeout, @Nullable Duration readTimeout, @Nullable SslBundle sslBundle) {\n\n\t/**\n\t * Create a new {@link HttpClientSettings} instance.\n\t * @param redirects the follow redirect strategy to use\n\t * @param connectTimeout the connect timeout\n\t * @param readTimeout the read timeout\n\t * @param sslBundle the SSL bundle providing SSL configuration\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link HttpClientSettings#HttpClientSettings(HttpCookieHandling, HttpRedirects, Duration, Duration, SslBundle)}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic HttpClientSettings(@Nullable HttpRedirects redirects, @Nullable Duration connectTimeout,\n\t\t\t@Nullable Duration readTimeout, @Nullable SslBundle sslBundle) {\n\t\tthis(null, redirects, connectTimeout, readTimeout, sslBundle);\n\t}\n\n\tprivate static final HttpClientSettings defaults = new HttpClientSettings(null, null, null, null, null);\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance with an updated cookie handling\n\t * setting.\n\t * @param cookieHandling the new cookie handling setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.1.0\n\t */\n\tpublic HttpClientSettings withCookieHandling(@Nullable HttpCookieHandling cookieHandling) {\n\t\treturn new HttpClientSettings(cookieHandling, this.redirects, this.connectTimeout, this.readTimeout,\n\t\t\t\tthis.sslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance with an updated connect timeout\n\t * setting.\n\t * @param connectTimeout the new connect timeout setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic HttpClientSettings withConnectTimeout(@Nullable Duration connectTimeout) {\n\t\treturn new HttpClientSettings(this.cookieHandling, this.redirects, connectTimeout, this.readTimeout,\n\t\t\t\tthis.sslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance with an updated read timeout\n\t * setting.\n\t * @param readTimeout the new read timeout setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic HttpClientSettings withReadTimeout(@Nullable Duration readTimeout) {\n\t\treturn new HttpClientSettings(this.cookieHandling, this.redirects, this.connectTimeout, readTimeout,\n\t\t\t\tthis.sslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance with an updated connect and read\n\t * timeout setting.\n\t * @param connectTimeout the new connect timeout setting\n\t * @param readTimeout the new read timeout setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic HttpClientSettings withTimeouts(@Nullable Duration connectTimeout, @Nullable Duration readTimeout) {\n\t\treturn new HttpClientSettings(this.cookieHandling, this.redirects, connectTimeout, readTimeout, this.sslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance with an updated SSL bundle\n\t * setting.\n\t * @param sslBundle the new SSL bundle setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic HttpClientSettings withSslBundle(@Nullable SslBundle sslBundle) {\n\t\treturn new HttpClientSettings(this.cookieHandling, this.redirects, this.connectTimeout, this.readTimeout,\n\t\t\t\tsslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance with an updated redirect setting.\n\t * @param redirects the new redirects setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic HttpClientSettings withRedirects(@Nullable HttpRedirects redirects) {\n\t\treturn new HttpClientSettings(this.cookieHandling, redirects, this.connectTimeout, this.readTimeout,\n\t\t\t\tthis.sslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} instance using values from this instance\n\t * when they are present, or otherwise using values from {@code other}.\n\t * @param other the settings to be used to obtain values not present in this instance\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic HttpClientSettings orElse(@Nullable HttpClientSettings other) {\n\t\tif (other == null) {\n\t\t\treturn this;\n\t\t}\n\t\tHttpCookieHandling cookieHandling = (cookieHandling() != null) ? cookieHandling() : other.cookieHandling();\n\t\tHttpRedirects redirects = (redirects() != null) ? redirects() : other.redirects();\n\t\tDuration connectTimeout = (connectTimeout() != null) ? connectTimeout() : other.connectTimeout();\n\t\tDuration readTimeout = (readTimeout() != null) ? readTimeout() : other.readTimeout();\n\t\tSslBundle sslBundle = (sslBundle() != null) ? sslBundle() : other.sslBundle();\n\t\treturn new HttpClientSettings(cookieHandling, redirects, connectTimeout, readTimeout, sslBundle);\n\t}\n\n\t/**\n\t * Return a new {@link HttpClientSettings} using defaults for all settings other than\n\t * the provided SSL bundle.\n\t * @param sslBundle the SSL bundle setting\n\t * @return a new {@link HttpClientSettings} instance\n\t * @since 4.0.0\n\t */\n\tpublic static HttpClientSettings ofSslBundle(@Nullable SslBundle sslBundle) {\n\t\treturn defaults().withSslBundle(sslBundle);\n\t}\n\n\t/**\n\t * Use defaults settings, which can differ depending on the implementation.\n\t * @return default settings\n\t * @since 4.0.0\n\t */\n\tpublic static HttpClientSettings defaults() {\n\t\treturn defaults;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.UnaryOperator;\n\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;\nimport org.apache.hc.client5.http.ssl.TlsSocketStrategy;\nimport org.apache.hc.core5.http.io.SocketConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.HttpComponentsHttpClientBuilder.TlsSocketStrategyFactory;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpRequestFactoryBuilder#httpComponents()}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.4.0\n */\npublic final class HttpComponentsClientHttpRequestFactoryBuilder\n\t\textends AbstractClientHttpRequestFactoryBuilder<HttpComponentsClientHttpRequestFactory> {\n\n\tprivate final HttpComponentsHttpClientBuilder httpClientBuilder;\n\n\tHttpComponentsClientHttpRequestFactoryBuilder() {\n\t\tthis(null, new HttpComponentsHttpClientBuilder());\n\t}\n\n\tprivate HttpComponentsClientHttpRequestFactoryBuilder(\n\t\t\t@Nullable List<Consumer<HttpComponentsClientHttpRequestFactory>> customizers,\n\t\t\tHttpComponentsHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withCustomizer(\n\t\t\tConsumer<HttpComponentsClientHttpRequestFactory> customizer) {\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withCustomizers(\n\t\t\tCollection<Consumer<HttpComponentsClientHttpRequestFactory>> customizers) {\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(mergedCustomizers(customizers),\n\t\t\t\tthis.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies\n\t * additional customization to the underlying {@link HttpClientBuilder}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withHttpClientCustomizer(\n\t\t\tConsumer<HttpClientBuilder> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies\n\t * additional customization to the underlying\n\t * {@link PoolingHttpClientConnectionManagerBuilder}.\n\t * @param connectionManagerCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withConnectionManagerCustomizer(\n\t\t\tConsumer<PoolingHttpClientConnectionManagerBuilder> connectionManagerCustomizer) {\n\t\tAssert.notNull(connectionManagerCustomizer, \"'connectionManagerCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withConnectionManagerCustomizer(connectionManagerCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies\n\t * additional customization to the underlying\n\t * {@link org.apache.hc.core5.http.io.SocketConfig.Builder}.\n\t * @param socketConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withSocketConfigCustomizer(\n\t\t\tConsumer<SocketConfig.Builder> socketConfigCustomizer) {\n\t\tAssert.notNull(socketConfigCustomizer, \"'socketConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withSocketConfigCustomizer(socketConfigCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} that applies additional\n\t * customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.ConnectionConfig.Builder}.\n\t * @param connectionConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withConnectionConfigCustomizer(\n\t\t\tConsumer<ConnectionConfig.Builder> connectionConfigCustomizer) {\n\t\tAssert.notNull(connectionConfigCustomizer, \"'connectionConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withConnectionConfigCustomizer(connectionConfigCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} with a\n\t * replacement {@link TlsSocketStrategy} factory.\n\t * @param tlsSocketStrategyFactory the new factory used to create a\n\t * {@link TlsSocketStrategy} for a given {@link SslBundle}\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withTlsSocketStrategyFactory(\n\t\t\tTlsSocketStrategyFactory tlsSocketStrategyFactory) {\n\t\tAssert.notNull(tlsSocketStrategyFactory, \"'tlsSocketStrategyFactory' must not be null\");\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withTlsSocketStrategyFactory(tlsSocketStrategyFactory));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies\n\t * additional customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.RequestConfig.Builder} used for default\n\t * requests.\n\t * @param defaultRequestConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder withDefaultRequestConfigCustomizer(\n\t\t\tConsumer<RequestConfig.Builder> defaultRequestConfigCustomizer) {\n\t\tAssert.notNull(defaultRequestConfigCustomizer, \"'defaultRequestConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies the\n\t * given customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic HttpComponentsClientHttpRequestFactoryBuilder with(\n\t\t\tUnaryOperator<HttpComponentsClientHttpRequestFactoryBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected HttpComponentsClientHttpRequestFactory createClientHttpRequestFactory(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings);\n\t\treturn new HttpComponentsClientHttpRequestFactory(httpClient);\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENTS = \"org.apache.hc.client5.http.impl.classic.HttpClients\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENTS, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpComponentsHttpAsyncClientBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport org.apache.hc.client5.http.async.HttpAsyncClient;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\nimport org.apache.hc.core5.http.nio.ssl.TlsStrategy;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.util.Assert;\n\n/**\n * Builder that can be used to create a\n * <a href=\"https://hc.apache.org/httpcomponents-client-ga/\">Apache HttpComponents</a>\n * {@link HttpAsyncClient}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.5.0\n */\npublic final class HttpComponentsHttpAsyncClientBuilder {\n\n\tprivate final Consumer<HttpAsyncClientBuilder> customizer;\n\n\tprivate final Consumer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCustomizer;\n\n\tprivate final Consumer<ConnectionConfig.Builder> connectionConfigCustomizer;\n\n\tprivate final Consumer<RequestConfig.Builder> defaultRequestConfigCustomizer;\n\n\tprivate final Function<@Nullable SslBundle, @Nullable TlsStrategy> tlsStrategyFactory;\n\n\tpublic HttpComponentsHttpAsyncClientBuilder() {\n\t\tthis(Empty.consumer(), Empty.consumer(), Empty.consumer(), Empty.consumer(),\n\t\t\t\tHttpComponentsSslBundleTlsStrategy::get);\n\t}\n\n\tprivate HttpComponentsHttpAsyncClientBuilder(Consumer<HttpAsyncClientBuilder> customizer,\n\t\t\tConsumer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCustomizer,\n\t\t\tConsumer<ConnectionConfig.Builder> connectionConfigCustomizer,\n\t\t\tConsumer<RequestConfig.Builder> defaultRequestConfigCustomizer,\n\t\t\tFunction<@Nullable SslBundle, @Nullable TlsStrategy> tlsStrategyFactory) {\n\t\tthis.customizer = customizer;\n\t\tthis.connectionManagerCustomizer = connectionManagerCustomizer;\n\t\tthis.connectionConfigCustomizer = connectionConfigCustomizer;\n\t\tthis.defaultRequestConfigCustomizer = defaultRequestConfigCustomizer;\n\t\tthis.tlsStrategyFactory = tlsStrategyFactory;\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpAsyncClientBuilder} that applies additional\n\t * customization to the underlying {@link HttpAsyncClientBuilder}.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpAsyncClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpAsyncClientBuilder withCustomizer(Consumer<HttpAsyncClientBuilder> customizer) {\n\t\tAssert.notNull(customizer, \"'customizer' must not be null\");\n\t\treturn new HttpComponentsHttpAsyncClientBuilder(this.customizer.andThen(customizer),\n\t\t\t\tthis.connectionManagerCustomizer, this.connectionConfigCustomizer, this.defaultRequestConfigCustomizer,\n\t\t\t\tthis.tlsStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpAsyncClientBuilder} that applies additional\n\t * customization to the underlying {@link PoolingAsyncClientConnectionManagerBuilder}.\n\t * @param connectionManagerCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpAsyncClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpAsyncClientBuilder withConnectionManagerCustomizer(\n\t\t\tConsumer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCustomizer) {\n\t\tAssert.notNull(connectionManagerCustomizer, \"'connectionManagerCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpAsyncClientBuilder(this.customizer,\n\t\t\t\tthis.connectionManagerCustomizer.andThen(connectionManagerCustomizer), this.connectionConfigCustomizer,\n\t\t\t\tthis.defaultRequestConfigCustomizer, this.tlsStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpAsyncClientBuilder} that applies additional\n\t * customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.ConnectionConfig.Builder}.\n\t * @param connectionConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpAsyncClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpAsyncClientBuilder withConnectionConfigCustomizer(\n\t\t\tConsumer<ConnectionConfig.Builder> connectionConfigCustomizer) {\n\t\tAssert.notNull(connectionConfigCustomizer, \"'connectionConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpAsyncClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.connectionConfigCustomizer.andThen(connectionConfigCustomizer),\n\t\t\t\tthis.defaultRequestConfigCustomizer, this.tlsStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpAsyncClientBuilder} with a replacement\n\t * {@link TlsStrategy} factory.\n\t * @param tlsStrategyFactory the new factory used to create a {@link TlsStrategy} for\n\t * a given {@link SslBundle}\n\t * @return a new {@link HttpComponentsHttpAsyncClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpAsyncClientBuilder withTlsStrategyFactory(\n\t\t\tFunction<@Nullable SslBundle, @Nullable TlsStrategy> tlsStrategyFactory) {\n\t\tAssert.notNull(tlsStrategyFactory, \"'tlsStrategyFactory' must not be null\");\n\t\treturn new HttpComponentsHttpAsyncClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.connectionConfigCustomizer, this.defaultRequestConfigCustomizer, tlsStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpAsyncClientBuilder} that applies additional\n\t * customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.RequestConfig.Builder} used for default\n\t * requests.\n\t * @param defaultRequestConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpAsyncClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpAsyncClientBuilder withDefaultRequestConfigCustomizer(\n\t\t\tConsumer<RequestConfig.Builder> defaultRequestConfigCustomizer) {\n\t\tAssert.notNull(defaultRequestConfigCustomizer, \"'defaultRequestConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpAsyncClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.connectionConfigCustomizer,\n\t\t\t\tthis.defaultRequestConfigCustomizer.andThen(defaultRequestConfigCustomizer), this.tlsStrategyFactory);\n\t}\n\n\t/**\n\t * Build a new {@link HttpAsyncClient} instance with the given settings applied.\n\t * @param settings the settings to apply\n\t * @return a new {@link CloseableHttpAsyncClient} instance\n\t */\n\tpublic CloseableHttpAsyncClient build(@Nullable HttpClientSettings settings) {\n\t\tsettings = (settings != null) ? settings : HttpClientSettings.defaults();\n\t\tHttpAsyncClientBuilder builder = HttpAsyncClientBuilder.create()\n\t\t\t.useSystemProperties()\n\t\t\t.setRedirectStrategy(HttpComponentsRedirectStrategy.get(settings.redirects()))\n\t\t\t.setConnectionManager(createConnectionManager(settings))\n\t\t\t.setDefaultRequestConfig(createDefaultRequestConfig());\n\t\tthis.customizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate PoolingAsyncClientConnectionManager createConnectionManager(HttpClientSettings settings) {\n\t\tPoolingAsyncClientConnectionManagerBuilder builder = PoolingAsyncClientConnectionManagerBuilder.create()\n\t\t\t.useSystemProperties();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tbuilder.setDefaultConnectionConfig(createConnectionConfig(settings));\n\t\tmap.from(settings::sslBundle).as(this.tlsStrategyFactory::apply).to(builder::setTlsStrategy);\n\t\tthis.connectionManagerCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate ConnectionConfig createConnectionConfig(HttpClientSettings settings) {\n\t\tConnectionConfig.Builder builder = ConnectionConfig.custom();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::connectTimeout)\n\t\t\t.as(Duration::toMillis)\n\t\t\t.to((timeout) -> builder.setConnectTimeout(timeout, TimeUnit.MILLISECONDS));\n\t\tmap.from(settings::readTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((timeout) -> builder.setSocketTimeout(timeout, TimeUnit.MILLISECONDS));\n\t\tthis.connectionConfigCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate RequestConfig createDefaultRequestConfig() {\n\t\tRequestConfig.Builder builder = RequestConfig.custom();\n\t\tthis.defaultRequestConfigCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpComponentsHttpClientBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.net.http.HttpClient;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.cookie.StandardCookieSpec;\nimport org.apache.hc.client5.http.impl.classic.CloseableHttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;\nimport org.apache.hc.client5.http.ssl.TlsSocketStrategy;\nimport org.apache.hc.core5.http.io.SocketConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.util.Assert;\n\n/**\n * Builder that can be used to create a\n * <a href=\"https://hc.apache.org/httpcomponents-client-ga/\">Apache HttpComponents</a>\n * {@link HttpClient}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.5.0\n */\npublic final class HttpComponentsHttpClientBuilder {\n\n\tprivate final Consumer<HttpClientBuilder> customizer;\n\n\tprivate final Consumer<PoolingHttpClientConnectionManagerBuilder> connectionManagerCustomizer;\n\n\tprivate final Consumer<SocketConfig.Builder> socketConfigCustomizer;\n\n\tprivate final Consumer<ConnectionConfig.Builder> connectionConfigCustomizer;\n\n\tprivate final Consumer<RequestConfig.Builder> defaultRequestConfigCustomizer;\n\n\tprivate final TlsSocketStrategyFactory tlsSocketStrategyFactory;\n\n\tpublic HttpComponentsHttpClientBuilder() {\n\t\tthis(Empty.consumer(), Empty.consumer(), Empty.consumer(), Empty.consumer(), Empty.consumer(),\n\t\t\t\tHttpComponentsSslBundleTlsStrategy::get);\n\t}\n\n\tprivate HttpComponentsHttpClientBuilder(Consumer<HttpClientBuilder> customizer,\n\t\t\tConsumer<PoolingHttpClientConnectionManagerBuilder> connectionManagerCustomizer,\n\t\t\tConsumer<SocketConfig.Builder> socketConfigCustomizer,\n\t\t\tConsumer<ConnectionConfig.Builder> connectionConfigCustomizer,\n\t\t\tConsumer<RequestConfig.Builder> defaultRequestConfigCustomizer,\n\t\t\tTlsSocketStrategyFactory tlsSocketStrategyFactory) {\n\t\tthis.customizer = customizer;\n\t\tthis.connectionManagerCustomizer = connectionManagerCustomizer;\n\t\tthis.socketConfigCustomizer = socketConfigCustomizer;\n\t\tthis.connectionConfigCustomizer = connectionConfigCustomizer;\n\t\tthis.defaultRequestConfigCustomizer = defaultRequestConfigCustomizer;\n\t\tthis.tlsSocketStrategyFactory = tlsSocketStrategyFactory;\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} that applies additional\n\t * customization to the underlying {@link HttpClientBuilder}.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpClientBuilder withCustomizer(Consumer<HttpClientBuilder> customizer) {\n\t\tAssert.notNull(customizer, \"'customizer' must not be null\");\n\t\treturn new HttpComponentsHttpClientBuilder(this.customizer.andThen(customizer),\n\t\t\t\tthis.connectionManagerCustomizer, this.socketConfigCustomizer, this.connectionConfigCustomizer,\n\t\t\t\tthis.defaultRequestConfigCustomizer, this.tlsSocketStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} that applies additional\n\t * customization to the underlying {@link PoolingHttpClientConnectionManagerBuilder}.\n\t * @param connectionManagerCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpClientBuilder withConnectionManagerCustomizer(\n\t\t\tConsumer<PoolingHttpClientConnectionManagerBuilder> connectionManagerCustomizer) {\n\t\tAssert.notNull(connectionManagerCustomizer, \"'connectionManagerCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpClientBuilder(this.customizer,\n\t\t\t\tthis.connectionManagerCustomizer.andThen(connectionManagerCustomizer), this.socketConfigCustomizer,\n\t\t\t\tthis.connectionConfigCustomizer, this.defaultRequestConfigCustomizer, this.tlsSocketStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} that applies additional\n\t * customization to the underlying\n\t * {@link org.apache.hc.core5.http.io.SocketConfig.Builder}.\n\t * @param socketConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpClientBuilder withSocketConfigCustomizer(\n\t\t\tConsumer<SocketConfig.Builder> socketConfigCustomizer) {\n\t\tAssert.notNull(socketConfigCustomizer, \"'socketConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.socketConfigCustomizer.andThen(socketConfigCustomizer), this.connectionConfigCustomizer,\n\t\t\t\tthis.defaultRequestConfigCustomizer, this.tlsSocketStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} that applies additional\n\t * customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.ConnectionConfig.Builder}.\n\t * @param connectionConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpClientBuilder withConnectionConfigCustomizer(\n\t\t\tConsumer<ConnectionConfig.Builder> connectionConfigCustomizer) {\n\t\tAssert.notNull(connectionConfigCustomizer, \"'connectionConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.socketConfigCustomizer, this.connectionConfigCustomizer.andThen(connectionConfigCustomizer),\n\t\t\t\tthis.defaultRequestConfigCustomizer, this.tlsSocketStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} with a replacement\n\t * {@link TlsSocketStrategy} factory.\n\t * @param tlsSocketStrategyFactory the new factory used to create a\n\t * {@link TlsSocketStrategy}. The function will be provided with a {@link SslBundle}\n\t * or {@code null} if no bundle is selected. Only non {@code null} results will be\n\t * applied.\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpClientBuilder withTlsSocketStrategyFactory(\n\t\t\tTlsSocketStrategyFactory tlsSocketStrategyFactory) {\n\t\tAssert.notNull(tlsSocketStrategyFactory, \"'tlsSocketStrategyFactory' must not be null\");\n\t\treturn new HttpComponentsHttpClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.socketConfigCustomizer, this.connectionConfigCustomizer, this.defaultRequestConfigCustomizer,\n\t\t\t\ttlsSocketStrategyFactory);\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsHttpClientBuilder} that applies additional\n\t * customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.RequestConfig.Builder} used for default\n\t * requests.\n\t * @param defaultRequestConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpClientBuilder} instance\n\t */\n\tpublic HttpComponentsHttpClientBuilder withDefaultRequestConfigCustomizer(\n\t\t\tConsumer<RequestConfig.Builder> defaultRequestConfigCustomizer) {\n\t\tAssert.notNull(defaultRequestConfigCustomizer, \"'defaultRequestConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsHttpClientBuilder(this.customizer, this.connectionManagerCustomizer,\n\t\t\t\tthis.socketConfigCustomizer, this.connectionConfigCustomizer,\n\t\t\t\tthis.defaultRequestConfigCustomizer.andThen(defaultRequestConfigCustomizer),\n\t\t\t\tthis.tlsSocketStrategyFactory);\n\t}\n\n\t/**\n\t * Build a new {@link HttpClient} instance with the given settings applied.\n\t * @param settings the settings to apply\n\t * @return a new {@link HttpClient} instance\n\t */\n\tpublic CloseableHttpClient build(@Nullable HttpClientSettings settings) {\n\t\tsettings = (settings != null) ? settings : HttpClientSettings.defaults();\n\t\tHttpClientBuilder builder = HttpClientBuilder.create()\n\t\t\t.useSystemProperties()\n\t\t\t.setRedirectStrategy(HttpComponentsRedirectStrategy.get(settings.redirects()))\n\t\t\t.setConnectionManager(createConnectionManager(settings))\n\t\t\t.setDefaultRequestConfig(createDefaultRequestConfig(settings));\n\t\tthis.customizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate PoolingHttpClientConnectionManager createConnectionManager(HttpClientSettings settings) {\n\t\tPoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder.create()\n\t\t\t.useSystemProperties();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tbuilder.setDefaultSocketConfig(createSocketConfig());\n\t\tbuilder.setDefaultConnectionConfig(createConnectionConfig(settings));\n\t\tmap.from(settings::sslBundle)\n\t\t\t.always()\n\t\t\t.as(this.tlsSocketStrategyFactory::getTlsSocketStrategy)\n\t\t\t.to(builder::setTlsSocketStrategy);\n\t\tthis.connectionManagerCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate SocketConfig createSocketConfig() {\n\t\tSocketConfig.Builder builder = SocketConfig.custom();\n\t\tthis.socketConfigCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate ConnectionConfig createConnectionConfig(HttpClientSettings settings) {\n\t\tConnectionConfig.Builder builder = ConnectionConfig.custom();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::connectTimeout)\n\t\t\t.as(Duration::toMillis)\n\t\t\t.to((timeout) -> builder.setConnectTimeout(timeout, TimeUnit.MILLISECONDS));\n\t\tmap.from(settings::readTimeout)\n\t\t\t.asInt(Duration::toMillis)\n\t\t\t.to((timeout) -> builder.setSocketTimeout(timeout, TimeUnit.MILLISECONDS));\n\t\tthis.connectionConfigCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate RequestConfig createDefaultRequestConfig(HttpClientSettings settings) {\n\t\tRequestConfig.Builder builder = RequestConfig.custom();\n\t\tif (settings.cookieHandling() != null) {\n\t\t\tString cookieSpec = switch (settings.cookieHandling()) {\n\t\t\t\tcase ENABLE_WHEN_POSSIBLE, ENABLE -> StandardCookieSpec.STRICT;\n\t\t\t\tcase DISABLE -> StandardCookieSpec.IGNORE;\n\t\t\t};\n\t\t\tbuilder.setCookieSpec(cookieSpec);\n\t\t}\n\t\tthis.defaultRequestConfigCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\t/**\n\t * Factory that can be used to optionally create a {@link TlsSocketStrategy} given an\n\t * {@link SslBundle}.\n\t *\n\t * @since 4.0.0\n\t */\n\tpublic interface TlsSocketStrategyFactory {\n\n\t\t/**\n\t\t * Return the {@link TlsSocketStrategy} to use for the given bundle.\n\t\t * @param sslBundle the SSL bundle or {@code null}\n\t\t * @return the {@link TlsSocketStrategy} to use or {@code null}\n\t\t */\n\t\t@Nullable TlsSocketStrategy getTlsSocketStrategy(@Nullable SslBundle sslBundle);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpComponentsRedirectStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.net.URI;\n\nimport org.apache.hc.client5.http.impl.DefaultRedirectStrategy;\nimport org.apache.hc.client5.http.protocol.RedirectStrategy;\nimport org.apache.hc.core5.http.HttpRequest;\nimport org.apache.hc.core5.http.HttpResponse;\nimport org.apache.hc.core5.http.protocol.HttpContext;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Adapts {@link HttpRedirects} to an\n * <a href=\"https://hc.apache.org/httpcomponents-client-ga/\">Apache HttpComponents</a>\n * {@link RedirectStrategy}.\n *\n * @author Phillip Webb\n */\nfinal class HttpComponentsRedirectStrategy {\n\n\tprivate HttpComponentsRedirectStrategy() {\n\t}\n\n\tstatic RedirectStrategy get(@Nullable HttpRedirects redirects) {\n\t\tif (redirects == null) {\n\t\t\treturn DefaultRedirectStrategy.INSTANCE;\n\t\t}\n\t\treturn switch (redirects) {\n\t\t\tcase FOLLOW_WHEN_POSSIBLE, FOLLOW -> DefaultRedirectStrategy.INSTANCE;\n\t\t\tcase DONT_FOLLOW -> NoFollowRedirectStrategy.INSTANCE;\n\t\t};\n\t}\n\n\t/**\n\t * {@link RedirectStrategy} that never follows redirects.\n\t */\n\tprivate static final class NoFollowRedirectStrategy implements RedirectStrategy {\n\n\t\tprivate static final RedirectStrategy INSTANCE = new NoFollowRedirectStrategy();\n\n\t\tprivate NoFollowRedirectStrategy() {\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable URI getLocationURI(HttpRequest request, HttpResponse response, HttpContext context) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpComponentsSslBundleTlsStrategy.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;\nimport org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.lang.Contract;\n\n/**\n * Adapts {@link SslBundle} to an\n * <a href=\"https://hc.apache.org/httpcomponents-client-ga/\">Apache HttpComponents</a>\n * {@link DefaultClientTlsStrategy}.\n *\n * @author Phillip Webb\n */\nfinal class HttpComponentsSslBundleTlsStrategy {\n\n\tprivate HttpComponentsSslBundleTlsStrategy() {\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tstatic @Nullable DefaultClientTlsStrategy get(@Nullable SslBundle sslBundle) {\n\t\tif (sslBundle == null) {\n\t\t\treturn null;\n\t\t}\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\treturn new DefaultClientTlsStrategy(sslContext, options.getEnabledProtocols(), options.getCiphers(), null,\n\t\t\t\tnew DefaultHostnameVerifier());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpCookieHandling.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\n/**\n * Cookie handling strategies supported by HTTP clients.\n *\n * @author Apoorv Darshan\n * @since 4.1.0\n */\npublic enum HttpCookieHandling {\n\n\t/**\n\t * Enable cookie handling (if the underlying library has support). When enabled,\n\t * cookies received in a response are stored and automatically included in subsequent\n\t * matching requests.\n\t */\n\tENABLE_WHEN_POSSIBLE,\n\n\t/**\n\t * Enable cookie handling (fail if the underlying library has no support). When\n\t * enabled, cookies received in a response are stored and automatically included in\n\t * subsequent matching requests.\n\t */\n\tENABLE,\n\n\t/**\n\t * Disable cookie handling (fail if the underlying library has no support).\n\t */\n\tDISABLE\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/HttpRedirects.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\n/**\n * Redirect strategies support by HTTP clients.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic enum HttpRedirects {\n\n\t/**\n\t * Follow redirects (if the underlying library has support).\n\t */\n\tFOLLOW_WHEN_POSSIBLE,\n\n\t/**\n\t * Follow redirects (fail if the underlying library has no support).\n\t */\n\tFOLLOW,\n\n\t/**\n\t * Don't follow redirects (fail if the underlying library has no support).\n\t */\n\tDONT_FOLLOW\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JdkClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.net.http.HttpClient;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.function.Consumer;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpRequestFactoryBuilder#jdk()}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Sangmin Park\n * @since 3.4.0\n */\npublic final class JdkClientHttpRequestFactoryBuilder\n\t\textends AbstractClientHttpRequestFactoryBuilder<JdkClientHttpRequestFactory> {\n\n\tprivate final JdkHttpClientBuilder httpClientBuilder;\n\n\tJdkClientHttpRequestFactoryBuilder() {\n\t\tthis(null, new JdkHttpClientBuilder());\n\t}\n\n\tprivate JdkClientHttpRequestFactoryBuilder(@Nullable List<Consumer<JdkClientHttpRequestFactory>> customizers,\n\t\t\tJdkHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic JdkClientHttpRequestFactoryBuilder withCustomizer(Consumer<JdkClientHttpRequestFactory> customizer) {\n\t\treturn new JdkClientHttpRequestFactoryBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic JdkClientHttpRequestFactoryBuilder withCustomizers(\n\t\t\tCollection<Consumer<JdkClientHttpRequestFactory>> customizers) {\n\t\treturn new JdkClientHttpRequestFactoryBuilder(mergedCustomizers(customizers), this.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link JdkClientHttpRequestFactoryBuilder} that uses the given\n\t * executor with the underlying {@link java.net.http.HttpClient.Builder}.\n\t * @param executor the executor to use\n\t * @return a new {@link JdkClientHttpRequestFactoryBuilder} instance\n\t * @since 4.0.0\n\t */\n\tpublic JdkClientHttpRequestFactoryBuilder withExecutor(Executor executor) {\n\t\treturn new JdkClientHttpRequestFactoryBuilder(getCustomizers(), this.httpClientBuilder.withExecutor(executor));\n\t}\n\n\t/**\n\t * Return a new {@link JdkClientHttpRequestFactoryBuilder} that applies additional\n\t * customization to the underlying {@link java.net.http.HttpClient.Builder}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link JdkClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic JdkClientHttpRequestFactoryBuilder withHttpClientCustomizer(\n\t\t\tConsumer<HttpClient.Builder> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new JdkClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JdkClientHttpRequestFactoryBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link JdkClientHttpRequestFactoryBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic JdkClientHttpRequestFactoryBuilder with(UnaryOperator<JdkClientHttpRequestFactoryBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected JdkClientHttpRequestFactory createClientHttpRequestFactory(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings.withReadTimeout(null));\n\t\tJdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::readTimeout).to(requestFactory::setReadTimeout);\n\t\treturn requestFactory;\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENT = \"java.net.http.HttpClient\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENT, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JdkHttpClientBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.net.CookieHandler;\nimport java.net.CookieManager;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpClient.Redirect;\nimport java.util.concurrent.Executor;\nimport java.util.function.Consumer;\n\nimport javax.net.ssl.SSLParameters;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.util.Assert;\n\n/**\n * Builder that can be used to create a JDK {@link HttpClient}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.5.0\n */\npublic final class JdkHttpClientBuilder {\n\n\tprivate final Consumer<HttpClient.Builder> customizer;\n\n\tpublic JdkHttpClientBuilder() {\n\t\tthis(Empty.consumer());\n\t}\n\n\tprivate JdkHttpClientBuilder(Consumer<HttpClient.Builder> customizer) {\n\t\tthis.customizer = customizer;\n\t}\n\n\t/**\n\t * Return a new {@link JdkHttpClientBuilder} that uses the given executor with the\n\t * underlying {@link java.net.http.HttpClient.Builder}.\n\t * @param executor the executor to use\n\t * @return a new {@link JdkHttpClientBuilder} instance\n\t * @since 4.0.0\n\t */\n\tpublic JdkHttpClientBuilder withExecutor(Executor executor) {\n\t\tAssert.notNull(executor, \"'executor' must not be null\");\n\t\treturn withCustomizer((httpClient) -> httpClient.executor(executor));\n\t}\n\n\t/**\n\t * Return a new {@link JdkHttpClientBuilder} that applies additional customization to\n\t * the underlying {@link java.net.http.HttpClient.Builder}.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link JdkHttpClientBuilder} instance\n\t */\n\tpublic JdkHttpClientBuilder withCustomizer(Consumer<HttpClient.Builder> customizer) {\n\t\tAssert.notNull(customizer, \"'customizer' must not be null\");\n\t\treturn new JdkHttpClientBuilder(this.customizer.andThen(customizer));\n\t}\n\n\t/**\n\t * Build a new {@link HttpClient} instance with the given settings applied.\n\t * @param settings the settings to apply\n\t * @return a new {@link HttpClient} instance\n\t */\n\tpublic HttpClient build(@Nullable HttpClientSettings settings) {\n\t\tsettings = (settings != null) ? settings : HttpClientSettings.defaults();\n\t\tAssert.isTrue(settings.readTimeout() == null, \"'settings' must not have a 'readTimeout'\");\n\t\tHttpClient.Builder builder = HttpClient.newBuilder();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::cookieHandling).as(this::asCookieHandler).to(builder::cookieHandler);\n\t\tmap.from(settings::redirects).always().as(this::asHttpClientRedirect).to(builder::followRedirects);\n\t\tmap.from(settings::connectTimeout).to(builder::connectTimeout);\n\t\tmap.from(settings::sslBundle).as(SslBundle::createSslContext).to(builder::sslContext);\n\t\tmap.from(settings::sslBundle).as(this::asSslParameters).to(builder::sslParameters);\n\t\tthis.customizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate SSLParameters asSslParameters(SslBundle sslBundle) {\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tSSLParameters parameters = new SSLParameters();\n\t\tparameters.setCipherSuites(options.getCiphers());\n\t\tparameters.setProtocols(options.getEnabledProtocols());\n\t\treturn parameters;\n\t}\n\n\tprivate @Nullable CookieHandler asCookieHandler(HttpCookieHandling cookieHandling) {\n\t\treturn switch (cookieHandling) {\n\t\t\tcase ENABLE_WHEN_POSSIBLE, ENABLE -> new CookieManager();\n\t\t\tcase DISABLE -> null;\n\t\t};\n\t}\n\n\tprivate Redirect asHttpClientRedirect(@Nullable HttpRedirects redirects) {\n\t\tif (redirects == null) {\n\t\t\treturn Redirect.NORMAL;\n\t\t}\n\t\treturn switch (redirects) {\n\t\t\tcase FOLLOW_WHEN_POSSIBLE, FOLLOW -> Redirect.NORMAL;\n\t\t\tcase DONT_FOLLOW -> Redirect.NEVER;\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JettyClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.UnaryOperator;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.eclipse.jetty.client.HttpClientTransport;\nimport org.eclipse.jetty.io.ClientConnector;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpRequestFactoryBuilder#jetty()}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.4.0\n */\npublic final class JettyClientHttpRequestFactoryBuilder\n\t\textends AbstractClientHttpRequestFactoryBuilder<JettyClientHttpRequestFactory> {\n\n\tprivate final JettyHttpClientBuilder httpClientBuilder;\n\n\tJettyClientHttpRequestFactoryBuilder() {\n\t\tthis(null, new JettyHttpClientBuilder());\n\t}\n\n\tprivate JettyClientHttpRequestFactoryBuilder(@Nullable List<Consumer<JettyClientHttpRequestFactory>> customizers,\n\t\t\tJettyHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic JettyClientHttpRequestFactoryBuilder withCustomizer(Consumer<JettyClientHttpRequestFactory> customizer) {\n\t\treturn new JettyClientHttpRequestFactoryBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic JettyClientHttpRequestFactoryBuilder withCustomizers(\n\t\t\tCollection<Consumer<JettyClientHttpRequestFactory>> customizers) {\n\t\treturn new JettyClientHttpRequestFactoryBuilder(mergedCustomizers(customizers), this.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpRequestFactoryBuilder} that applies additional\n\t * customization to the underlying {@link HttpClient}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link JettyClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic JettyClientHttpRequestFactoryBuilder withHttpClientCustomizer(Consumer<HttpClient> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new JettyClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpRequestFactoryBuilder} that uses the given\n\t * factory to create the {@link HttpClientTransport}.\n\t * @param httpClientTransportFactory the {@link HttpClientTransport} factory to use\n\t * @return a new {@link JettyClientHttpRequestFactoryBuilder} instance\n\t * @since 4.0.0\n\t */\n\tpublic JettyClientHttpRequestFactoryBuilder withHttpClientTransportFactory(\n\t\t\tFunction<ClientConnector, HttpClientTransport> httpClientTransportFactory) {\n\t\tAssert.notNull(httpClientTransportFactory, \"'httpClientTransportFactory' must not be null\");\n\t\treturn new JettyClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientTransportFactory(httpClientTransportFactory));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpRequestFactoryBuilder} that applies additional\n\t * customization to the underlying {@link HttpClientTransport}.\n\t * @param httpClientTransportCustomizer the customizer to apply\n\t * @return a new {@link JettyClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic JettyClientHttpRequestFactoryBuilder withHttpClientTransportCustomizer(\n\t\t\tConsumer<HttpClientTransport> httpClientTransportCustomizer) {\n\t\tAssert.notNull(httpClientTransportCustomizer, \"'httpClientTransportCustomizer' must not be null\");\n\t\treturn new JettyClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientTransportCustomizer(httpClientTransportCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpRequestFactoryBuilder} that applies additional\n\t * customization to the underlying {@link ClientConnector}.\n\t * @param clientConnectorCustomizerCustomizer the customizer to apply\n\t * @return a new {@link JettyClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic JettyClientHttpRequestFactoryBuilder withClientConnectorCustomizerCustomizer(\n\t\t\tConsumer<ClientConnector> clientConnectorCustomizerCustomizer) {\n\t\tAssert.notNull(clientConnectorCustomizerCustomizer, \"'clientConnectorCustomizerCustomizer' must not be null\");\n\t\treturn new JettyClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withClientConnectorCustomizerCustomizer(clientConnectorCustomizerCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpRequestFactoryBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link JettyClientHttpRequestFactoryBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic JettyClientHttpRequestFactoryBuilder with(UnaryOperator<JettyClientHttpRequestFactoryBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected JettyClientHttpRequestFactory createClientHttpRequestFactory(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings.withTimeouts(null, null));\n\t\tJettyClientHttpRequestFactory requestFactory = new JettyClientHttpRequestFactory(httpClient);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::connectTimeout).asInt(Duration::toMillis).to(requestFactory::setConnectTimeout);\n\t\tmap.from(settings::readTimeout).asInt(Duration::toMillis).to(requestFactory::setReadTimeout);\n\t\treturn requestFactory;\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENT = \"org.eclipse.jetty.client.HttpClient\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENT, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/JettyHttpClientBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.eclipse.jetty.client.HttpClientTransport;\nimport org.eclipse.jetty.client.Request;\nimport org.eclipse.jetty.client.transport.HttpClientTransportDynamic;\nimport org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;\nimport org.eclipse.jetty.http.HttpCookieStore;\nimport org.eclipse.jetty.io.ClientConnector;\nimport org.eclipse.jetty.util.ssl.SslContextFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.util.Assert;\n\n/**\n * Builder that can be used to create a Jetty {@link HttpClient}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.5.0\n */\npublic final class JettyHttpClientBuilder {\n\n\tprivate final Consumer<HttpClient> customizer;\n\n\tprivate final Function<ClientConnector, HttpClientTransport> httpClientTransportFactory;\n\n\tprivate final Consumer<HttpClientTransport> httpClientTransportCustomizer;\n\n\tprivate final Consumer<ClientConnector> clientConnectorCustomizerCustomizer;\n\n\tpublic JettyHttpClientBuilder() {\n\t\tthis(Empty.consumer(), JettyHttpClientBuilder::createHttpClientTransport, Empty.consumer(), Empty.consumer());\n\t}\n\n\tprivate JettyHttpClientBuilder(Consumer<HttpClient> customizer,\n\t\t\tFunction<ClientConnector, HttpClientTransport> httpClientTransportFactory,\n\t\t\tConsumer<HttpClientTransport> httpClientTransportCustomizer,\n\t\t\tConsumer<ClientConnector> clientConnectorCustomizerCustomizer) {\n\t\tthis.customizer = customizer;\n\t\tthis.httpClientTransportFactory = httpClientTransportFactory;\n\t\tthis.httpClientTransportCustomizer = httpClientTransportCustomizer;\n\t\tthis.clientConnectorCustomizerCustomizer = clientConnectorCustomizerCustomizer;\n\t}\n\n\tprivate static HttpClientTransport createHttpClientTransport(ClientConnector connector) {\n\t\treturn (connector.getSslContextFactory() != null) ? new HttpClientTransportDynamic(connector)\n\t\t\t\t: new HttpClientTransportOverHTTP(connector);\n\t}\n\n\t/**\n\t * Return a new {@link JettyHttpClientBuilder} that applies additional customization\n\t * to the underlying {@link HttpClient}.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link JettyHttpClientBuilder} instance\n\t */\n\tpublic JettyHttpClientBuilder withCustomizer(Consumer<HttpClient> customizer) {\n\t\tAssert.notNull(customizer, \"'customizer' must not be null\");\n\t\treturn new JettyHttpClientBuilder(this.customizer.andThen(customizer), this.httpClientTransportFactory,\n\t\t\t\tthis.httpClientTransportCustomizer, this.clientConnectorCustomizerCustomizer);\n\t}\n\n\t/**\n\t * Return a new {@link JettyHttpClientBuilder} that uses the given factory to create\n\t * the {@link HttpClientTransport}.\n\t * @param httpClientTransportFactory the {@link HttpClientTransport} factory to use\n\t * @return a new {@link JettyHttpClientBuilder} instance\n\t * @since 4.0.0\n\t */\n\tpublic JettyHttpClientBuilder withHttpClientTransportFactory(\n\t\t\tFunction<ClientConnector, HttpClientTransport> httpClientTransportFactory) {\n\t\tAssert.notNull(httpClientTransportFactory, \"'httpClientTransportFactory' must not be null\");\n\t\treturn new JettyHttpClientBuilder(this.customizer, httpClientTransportFactory,\n\t\t\t\tthis.httpClientTransportCustomizer, this.clientConnectorCustomizerCustomizer);\n\t}\n\n\t/**\n\t * Return a new {@link JettyHttpClientBuilder} that applies additional customization\n\t * to the underlying {@link HttpClientTransport}.\n\t * @param httpClientTransportCustomizer the customizer to apply\n\t * @return a new {@link JettyHttpClientBuilder} instance\n\t */\n\tpublic JettyHttpClientBuilder withHttpClientTransportCustomizer(\n\t\t\tConsumer<HttpClientTransport> httpClientTransportCustomizer) {\n\t\tAssert.notNull(httpClientTransportCustomizer, \"'httpClientTransportCustomizer' must not be null\");\n\t\treturn new JettyHttpClientBuilder(this.customizer, this.httpClientTransportFactory,\n\t\t\t\tthis.httpClientTransportCustomizer.andThen(httpClientTransportCustomizer),\n\t\t\t\tthis.clientConnectorCustomizerCustomizer);\n\t}\n\n\t/**\n\t * Return a new {@link JettyHttpClientBuilder} that applies additional customization\n\t * to the underlying {@link ClientConnector}.\n\t * @param clientConnectorCustomizerCustomizer the customizer to apply\n\t * @return a new {@link JettyHttpClientBuilder} instance\n\t */\n\tpublic JettyHttpClientBuilder withClientConnectorCustomizerCustomizer(\n\t\t\tConsumer<ClientConnector> clientConnectorCustomizerCustomizer) {\n\t\tAssert.notNull(clientConnectorCustomizerCustomizer, \"'clientConnectorCustomizerCustomizer' must not be null\");\n\t\treturn new JettyHttpClientBuilder(this.customizer, this.httpClientTransportFactory,\n\t\t\t\tthis.httpClientTransportCustomizer,\n\t\t\t\tthis.clientConnectorCustomizerCustomizer.andThen(clientConnectorCustomizerCustomizer));\n\t}\n\n\t/**\n\t * Build a new {@link HttpClient} instance with the given settings applied.\n\t * @param settings the settings to apply\n\t * @return a new {@link HttpClient} instance\n\t */\n\tpublic HttpClient build(@Nullable HttpClientSettings settings) {\n\t\tsettings = (settings != null) ? settings : HttpClientSettings.defaults();\n\t\tHttpClientTransport transport = createTransport(settings);\n\t\tthis.httpClientTransportCustomizer.accept(transport);\n\t\tHttpClient httpClient = createHttpClient(settings.readTimeout(), transport);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::connectTimeout).as(Duration::toMillis).to(httpClient::setConnectTimeout);\n\t\tmap.from(settings::cookieHandling).as(this::asCookieStore).to(httpClient::setHttpCookieStore);\n\t\tmap.from(settings::redirects).always().as(this::followRedirects).to(httpClient::setFollowRedirects);\n\t\tthis.customizer.accept(httpClient);\n\t\treturn httpClient;\n\t}\n\n\tprivate HttpClient createHttpClient(@Nullable Duration readTimeout, HttpClientTransport transport) {\n\t\treturn (readTimeout != null) ? new HttpClientWithReadTimeout(transport, readTimeout)\n\t\t\t\t: new HttpClient(transport);\n\t}\n\n\tprivate HttpClientTransport createTransport(HttpClientSettings settings) {\n\t\tClientConnector connector = createClientConnector(settings.sslBundle());\n\t\tHttpClientTransport clientTransport = this.httpClientTransportFactory.apply(connector);\n\t\tAssert.state(clientTransport != null, \"'httpClientTransportFactory' did not return a client transport\");\n\t\treturn clientTransport;\n\t}\n\n\tprivate ClientConnector createClientConnector(@Nullable SslBundle sslBundle) {\n\t\tClientConnector connector = new ClientConnector();\n\t\tif (sslBundle != null) {\n\t\t\tconnector.setSslContextFactory(createSslContextFactory(sslBundle));\n\t\t}\n\t\tthis.clientConnectorCustomizerCustomizer.accept(connector);\n\t\treturn connector;\n\t}\n\n\tprivate SslContextFactory.Client createSslContextFactory(SslBundle sslBundle) {\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\tSslContextFactory.Client factory = new SslContextFactory.Client();\n\t\tfactory.setSslContext(sslContext);\n\t\tif (options.getCiphers() != null) {\n\t\t\tfactory.setIncludeCipherSuites(options.getCiphers());\n\t\t\tfactory.setExcludeCipherSuites();\n\t\t}\n\t\tif (options.getEnabledProtocols() != null) {\n\t\t\tfactory.setIncludeProtocols(options.getEnabledProtocols());\n\t\t\tfactory.setExcludeProtocols();\n\t\t}\n\t\treturn factory;\n\t}\n\n\tprivate @Nullable HttpCookieStore asCookieStore(HttpCookieHandling cookieHandling) {\n\t\treturn switch (cookieHandling) {\n\t\t\tcase ENABLE_WHEN_POSSIBLE, ENABLE -> new HttpCookieStore.Default();\n\t\t\tcase DISABLE -> new HttpCookieStore.Empty();\n\t\t};\n\t}\n\n\tprivate boolean followRedirects(@Nullable HttpRedirects redirects) {\n\t\tif (redirects == null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn switch (redirects) {\n\t\t\tcase FOLLOW_WHEN_POSSIBLE, FOLLOW -> true;\n\t\t\tcase DONT_FOLLOW -> false;\n\t\t};\n\t}\n\n\t/**\n\t * {@link HttpClient} subclass that sets the read timeout.\n\t */\n\tstatic class HttpClientWithReadTimeout extends HttpClient {\n\n\t\tprivate final Duration readTimeout;\n\n\t\tHttpClientWithReadTimeout(HttpClientTransport transport, Duration readTimeout) {\n\t\t\tsuper(transport);\n\t\t\tthis.readTimeout = readTimeout;\n\t\t}\n\n\t\t@Override\n\t\tpublic org.eclipse.jetty.client.Request newRequest(java.net.URI uri) {\n\t\t\tRequest request = super.newRequest(uri);\n\t\t\trequest.timeout(this.readTimeout.toMillis(), TimeUnit.MILLISECONDS);\n\t\t\treturn request;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ReactorClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.http.client.HttpClient;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpRequestFactoryBuilder#reactor()}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.4.0\n */\npublic final class ReactorClientHttpRequestFactoryBuilder\n\t\textends AbstractClientHttpRequestFactoryBuilder<ReactorClientHttpRequestFactory> {\n\n\tprivate final ReactorHttpClientBuilder httpClientBuilder;\n\n\tReactorClientHttpRequestFactoryBuilder() {\n\t\tthis(null, new ReactorHttpClientBuilder());\n\t}\n\n\tprivate ReactorClientHttpRequestFactoryBuilder(\n\t\t\t@Nullable List<Consumer<ReactorClientHttpRequestFactory>> customizers,\n\t\t\tReactorHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic ReactorClientHttpRequestFactoryBuilder withCustomizer(Consumer<ReactorClientHttpRequestFactory> customizer) {\n\t\treturn new ReactorClientHttpRequestFactoryBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic ReactorClientHttpRequestFactoryBuilder withCustomizers(\n\t\t\tCollection<Consumer<ReactorClientHttpRequestFactory>> customizers) {\n\t\treturn new ReactorClientHttpRequestFactoryBuilder(mergedCustomizers(customizers), this.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpRequestFactoryBuilder} that uses the given\n\t * {@link ReactorResourceFactory} to create the underlying {@link HttpClient}.\n\t * @param reactorResourceFactory the {@link ReactorResourceFactory} to use\n\t * @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance\n\t * @since 3.5.0\n\t */\n\tpublic ReactorClientHttpRequestFactoryBuilder withReactorResourceFactory(\n\t\t\tReactorResourceFactory reactorResourceFactory) {\n\t\tAssert.notNull(reactorResourceFactory, \"'reactorResourceFactory' must not be null\");\n\t\treturn new ReactorClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withReactorResourceFactory(reactorResourceFactory));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpRequestFactoryBuilder} that uses the given\n\t * factory to create the underlying {@link HttpClient}.\n\t * @param factory the factory to use\n\t * @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance\n\t * @since 3.5.0\n\t */\n\tpublic ReactorClientHttpRequestFactoryBuilder withHttpClientFactory(Supplier<HttpClient> factory) {\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\treturn new ReactorClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientFactory(factory));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpRequestFactoryBuilder} that applies additional\n\t * customization to the underlying {@link HttpClient}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link ReactorClientHttpRequestFactoryBuilder} instance\n\t */\n\tpublic ReactorClientHttpRequestFactoryBuilder withHttpClientCustomizer(\n\t\t\tUnaryOperator<HttpClient> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new ReactorClientHttpRequestFactoryBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpRequestFactoryBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link ReactorClientHttpRequestFactoryBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic ReactorClientHttpRequestFactoryBuilder with(\n\t\t\tUnaryOperator<ReactorClientHttpRequestFactoryBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected ReactorClientHttpRequestFactory createClientHttpRequestFactory(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings.withTimeouts(null, null));\n\t\tReactorClientHttpRequestFactory requestFactory = new ReactorClientHttpRequestFactory(httpClient);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::connectTimeout).asInt(Duration::toMillis).to(requestFactory::setConnectTimeout);\n\t\tmap.from(settings::readTimeout).asInt(Duration::toMillis).to(requestFactory::setReadTimeout);\n\t\treturn requestFactory;\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENT = \"reactor.netty.http.client.HttpClient\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENT, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ReactorHttpClientBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport javax.net.ssl.SSLException;\n\nimport io.netty.channel.ChannelOption;\nimport io.netty.handler.ssl.SslContextBuilder;\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.http.client.HttpClient;\nimport reactor.netty.tcp.SslProvider.SslContextSpec;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslManagerBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * Builder that can be used to create a Reactor Netty {@link HttpClient}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.5.0\n */\npublic final class ReactorHttpClientBuilder {\n\n\tprivate final Supplier<HttpClient> factory;\n\n\tprivate final UnaryOperator<HttpClient> customizer;\n\n\tpublic ReactorHttpClientBuilder() {\n\t\tthis(HttpClient::create, UnaryOperator.identity());\n\t}\n\n\tprivate ReactorHttpClientBuilder(Supplier<HttpClient> httpClientFactory, UnaryOperator<HttpClient> customizer) {\n\t\tthis.factory = httpClientFactory;\n\t\tthis.customizer = customizer;\n\t}\n\n\t/**\n\t * Return a new {@link ReactorHttpClientBuilder} that uses the given\n\t * {@link ReactorResourceFactory} to create the {@link HttpClient}.\n\t * @param reactorResourceFactory the {@link ReactorResourceFactory} to use\n\t * @return a new {@link ReactorHttpClientBuilder} instance\n\t */\n\tpublic ReactorHttpClientBuilder withReactorResourceFactory(ReactorResourceFactory reactorResourceFactory) {\n\t\tAssert.notNull(reactorResourceFactory, \"'reactorResourceFactory' must not be null\");\n\t\treturn new ReactorHttpClientBuilder(() -> HttpClient.create(reactorResourceFactory.getConnectionProvider()),\n\t\t\t\t(httpClient) -> this.customizer.apply(httpClient).runOn(reactorResourceFactory.getLoopResources()));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorHttpClientBuilder} that uses the given factory to create\n\t * the {@link HttpClient}.\n\t * @param factory the factory to use\n\t * @return a new {@link ReactorHttpClientBuilder} instance\n\t */\n\tpublic ReactorHttpClientBuilder withHttpClientFactory(Supplier<HttpClient> factory) {\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\treturn new ReactorHttpClientBuilder(factory, this.customizer);\n\t}\n\n\t/**\n\t * Return a new {@link ReactorHttpClientBuilder} that applies additional customization\n\t * to the underlying {@link HttpClient}.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link ReactorHttpClientBuilder} instance\n\t */\n\tpublic ReactorHttpClientBuilder withHttpClientCustomizer(UnaryOperator<HttpClient> customizer) {\n\t\tAssert.notNull(customizer, \"'customizer' must not be null\");\n\t\treturn new ReactorHttpClientBuilder(this.factory,\n\t\t\t\t(httpClient) -> customizer.apply(this.customizer.apply(httpClient)));\n\t}\n\n\t/**\n\t * Build a new {@link HttpClient} instance with the given settings applied.\n\t * @param settings the settings to apply\n\t * @return a new {@link HttpClient} instance\n\t */\n\tpublic HttpClient build(@Nullable HttpClientSettings settings) {\n\t\tsettings = (settings != null) ? settings : HttpClientSettings.defaults();\n\t\tHttpClient httpClient = applyDefaults(this.factory.get());\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\thttpClient = map.from(settings::connectTimeout).to(httpClient, this::setConnectTimeout);\n\t\thttpClient = map.from(settings::readTimeout).to(httpClient, HttpClient::responseTimeout);\n\t\thttpClient = map.from(settings::redirects)\n\t\t\t.orFrom(() -> HttpRedirects.FOLLOW_WHEN_POSSIBLE)\n\t\t\t.as(this::followRedirects)\n\t\t\t.to(httpClient, HttpClient::followRedirect);\n\t\tif (HttpCookieHandling.ENABLE.equals(settings.cookieHandling())) {\n\t\t\tthrow new IllegalArgumentException(\"Reactor Netty HTTP client does not support cookie handling\");\n\t\t}\n\t\thttpClient = map.from(settings::sslBundle).to(httpClient, this::secure);\n\t\treturn this.customizer.apply(httpClient);\n\t}\n\n\tHttpClient applyDefaults(HttpClient httpClient) {\n\t\t// Aligns with Spring Framework defaults\n\t\treturn httpClient.compress(true);\n\t}\n\n\tprivate HttpClient setConnectTimeout(HttpClient httpClient, Duration timeout) {\n\t\treturn httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) timeout.toMillis());\n\t}\n\n\tprivate boolean followRedirects(HttpRedirects redirects) {\n\t\treturn switch (redirects) {\n\t\t\tcase FOLLOW_WHEN_POSSIBLE, FOLLOW -> true;\n\t\t\tcase DONT_FOLLOW -> false;\n\t\t};\n\t}\n\n\tprivate HttpClient secure(HttpClient httpClient, SslBundle sslBundle) {\n\t\treturn httpClient.secure((ThrowingConsumer.of((spec) -> configureSsl(spec, sslBundle))));\n\t}\n\n\tprivate void configureSsl(SslContextSpec spec, SslBundle sslBundle) throws SSLException {\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tSslManagerBundle managers = sslBundle.getManagers();\n\t\tSslContextBuilder builder = SslContextBuilder.forClient()\n\t\t\t.keyManager(managers.getKeyManagerFactory())\n\t\t\t.trustManager(managers.getTrustManagerFactory())\n\t\t\t.ciphers(SslOptions.asSet(options.getCiphers()))\n\t\t\t.protocols(options.getEnabledProtocols());\n\t\tspec.sslContext(builder.build());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/ReflectiveComponentsClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.time.Duration;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Internal builder for {@link ClientHttpRequestFactoryBuilder#of(Class)} and\n * {@link ClientHttpRequestFactoryBuilder#of(Supplier)}.\n *\n * @param <T> the {@link ClientHttpRequestFactory} type\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nfinal class ReflectiveComponentsClientHttpRequestFactoryBuilder<T extends ClientHttpRequestFactory>\n\t\timplements ClientHttpRequestFactoryBuilder<T> {\n\n\tprivate final Supplier<T> requestFactorySupplier;\n\n\tReflectiveComponentsClientHttpRequestFactoryBuilder(Supplier<T> requestFactorySupplier) {\n\t\tAssert.notNull(requestFactorySupplier, \"'requestFactorySupplier' must not be null\");\n\t\tthis.requestFactorySupplier = requestFactorySupplier;\n\t}\n\n\tReflectiveComponentsClientHttpRequestFactoryBuilder(Class<T> requestFactoryType) {\n\t\tAssert.notNull(requestFactoryType, \"'requestFactoryType' must not be null\");\n\t\tthis.requestFactorySupplier = () -> createRequestFactory(requestFactoryType);\n\t}\n\n\tprivate static <T extends ClientHttpRequestFactory> T createRequestFactory(Class<T> requestFactory) {\n\t\ttry {\n\t\t\tConstructor<T> constructor = requestFactory.getDeclaredConstructor();\n\t\t\tconstructor.setAccessible(true);\n\t\t\treturn constructor.newInstance();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic T build(@Nullable HttpClientSettings settings) {\n\t\tT requestFactory = this.requestFactorySupplier.get();\n\t\tif (settings != null) {\n\t\t\tconfigure(requestFactory, settings);\n\t\t}\n\t\treturn requestFactory;\n\t}\n\n\tprivate void configure(ClientHttpRequestFactory requestFactory, HttpClientSettings settings) {\n\t\tAssert.state(settings.sslBundle() == null, \"Unable to set SSL bundle using reflection\");\n\t\tAssert.state(settings.redirects() == null || settings.redirects() == HttpRedirects.FOLLOW_WHEN_POSSIBLE,\n\t\t\t\t\"Unable to set redirect follow using reflection\");\n\t\tAssert.state(\n\t\t\t\tsettings.cookieHandling() == null\n\t\t\t\t\t\t|| settings.cookieHandling() == HttpCookieHandling.ENABLE_WHEN_POSSIBLE,\n\t\t\t\t\"Unable to set HTTP cookie handling using reflection\");\n\t\tClientHttpRequestFactory unwrapped = unwrapRequestFactoryIfNecessary(requestFactory);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::connectTimeout).to((connectTimeout) -> setConnectTimeout(unwrapped, connectTimeout));\n\t\tmap.from(settings::readTimeout).to((readTimeout) -> setReadTimeout(unwrapped, readTimeout));\n\t}\n\n\tprivate ClientHttpRequestFactory unwrapRequestFactoryIfNecessary(ClientHttpRequestFactory requestFactory) {\n\t\tif (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) {\n\t\t\treturn requestFactory;\n\t\t}\n\t\tField field = ReflectionUtils.findField(AbstractClientHttpRequestFactoryWrapper.class, \"requestFactory\");\n\t\tAssert.state(field != null, \"'field' must not be null\");\n\t\tReflectionUtils.makeAccessible(field);\n\t\tClientHttpRequestFactory unwrappedRequestFactory = requestFactory;\n\t\twhile (unwrappedRequestFactory instanceof AbstractClientHttpRequestFactoryWrapper) {\n\t\t\tunwrappedRequestFactory = (ClientHttpRequestFactory) ReflectionUtils.getField(field,\n\t\t\t\t\tunwrappedRequestFactory);\n\t\t}\n\t\tAssert.state(unwrappedRequestFactory != null, \"'unwrappedRequestFactory' must not be null\");\n\t\treturn unwrappedRequestFactory;\n\t}\n\n\tprivate void setConnectTimeout(ClientHttpRequestFactory factory, Duration connectTimeout) {\n\t\tMethod method = tryFindMethod(factory, \"setConnectTimeout\", Duration.class);\n\t\tif (method != null) {\n\t\t\tinvoke(factory, method, connectTimeout);\n\t\t\treturn;\n\t\t}\n\t\tmethod = findMethod(factory, \"setConnectTimeout\", int.class);\n\t\tint timeout = Math.toIntExact(connectTimeout.toMillis());\n\t\tinvoke(factory, method, timeout);\n\t}\n\n\tprivate void setReadTimeout(ClientHttpRequestFactory factory, Duration readTimeout) {\n\t\tMethod method = tryFindMethod(factory, \"setReadTimeout\", Duration.class);\n\t\tif (method != null) {\n\t\t\tinvoke(factory, method, readTimeout);\n\t\t\treturn;\n\t\t}\n\t\tmethod = findMethod(factory, \"setReadTimeout\", int.class);\n\t\tint timeout = Math.toIntExact(readTimeout.toMillis());\n\t\tinvoke(factory, method, timeout);\n\t}\n\n\tprivate Method findMethod(ClientHttpRequestFactory requestFactory, String methodName, Class<?>... parameters) {\n\t\tMethod method = ReflectionUtils.findMethod(requestFactory.getClass(), methodName, parameters);\n\t\tAssert.state(method != null, () -> \"Request factory %s does not have a suitable %s method\"\n\t\t\t.formatted(requestFactory.getClass().getName(), methodName));\n\t\tAssert.state(!method.isAnnotationPresent(Deprecated.class),\n\t\t\t\t() -> \"Request factory %s has the %s method marked as deprecated\"\n\t\t\t\t\t.formatted(requestFactory.getClass().getName(), methodName));\n\t\treturn method;\n\t}\n\n\tprivate @Nullable Method tryFindMethod(ClientHttpRequestFactory requestFactory, String methodName,\n\t\t\tClass<?>... parameters) {\n\t\tMethod method = ReflectionUtils.findMethod(requestFactory.getClass(), methodName, parameters);\n\t\tif (method == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (method.isAnnotationPresent(Deprecated.class)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn method;\n\t}\n\n\tprivate void invoke(ClientHttpRequestFactory requestFactory, Method method, Object... parameters) {\n\t\tReflectionUtils.invokeMethod(method, requestFactory, parameters);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/SimpleClientHttpRequestFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.io.IOException;\nimport java.net.HttpURLConnection;\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.UnaryOperator;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLSocketFactory;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.util.Assert;\n\n/**\n * Builder for {@link ClientHttpRequestFactoryBuilder#simple()}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 3.4.0\n */\npublic final class SimpleClientHttpRequestFactoryBuilder\n\t\textends AbstractClientHttpRequestFactoryBuilder<SimpleClientHttpRequestFactory> {\n\n\tSimpleClientHttpRequestFactoryBuilder() {\n\t\tthis(null);\n\t}\n\n\tprivate SimpleClientHttpRequestFactoryBuilder(\n\t\t\t@Nullable List<Consumer<SimpleClientHttpRequestFactory>> customizers) {\n\t\tsuper(customizers);\n\t}\n\n\t@Override\n\tpublic SimpleClientHttpRequestFactoryBuilder withCustomizer(Consumer<SimpleClientHttpRequestFactory> customizer) {\n\t\treturn new SimpleClientHttpRequestFactoryBuilder(mergedCustomizers(customizer));\n\t}\n\n\t@Override\n\tpublic SimpleClientHttpRequestFactoryBuilder withCustomizers(\n\t\t\tCollection<Consumer<SimpleClientHttpRequestFactory>> customizers) {\n\t\treturn new SimpleClientHttpRequestFactoryBuilder(mergedCustomizers(customizers));\n\t}\n\n\t/**\n\t * Return a new {@link SimpleClientHttpRequestFactoryBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link SimpleClientHttpRequestFactoryBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic SimpleClientHttpRequestFactoryBuilder with(UnaryOperator<SimpleClientHttpRequestFactoryBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected SimpleClientHttpRequestFactory createClientHttpRequestFactory(HttpClientSettings settings) {\n\t\tif (settings.cookieHandling() == HttpCookieHandling.ENABLE) {\n\t\t\tthrow new IllegalArgumentException(\"Simple HTTP request factory does not support HTTP cookie handling\");\n\t\t}\n\t\tSslBundle sslBundle = settings.sslBundle();\n\t\tSimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpsRequestFactory(settings);\n\t\tAssert.state(sslBundle == null || !sslBundle.getOptions().isSpecified(),\n\t\t\t\t\"SSL Options cannot be specified with Java connections\");\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::readTimeout).asInt(Duration::toMillis).to(requestFactory::setReadTimeout);\n\t\tmap.from(settings::connectTimeout).asInt(Duration::toMillis).to(requestFactory::setConnectTimeout);\n\t\treturn requestFactory;\n\t}\n\n\t/**\n\t * {@link SimpleClientHttpsRequestFactory} to configure SSL from an {@link SslBundle}\n\t * and {@link Redirects}.\n\t */\n\tprivate static class SimpleClientHttpsRequestFactory extends SimpleClientHttpRequestFactory {\n\n\t\tprivate final HttpClientSettings settings;\n\n\t\tSimpleClientHttpsRequestFactory(HttpClientSettings settings) {\n\t\t\tthis.settings = settings;\n\t\t}\n\n\t\t@Override\n\t\tprotected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {\n\t\t\tsuper.prepareConnection(connection, httpMethod);\n\t\t\tif (this.settings.sslBundle() != null && connection instanceof HttpsURLConnection secureConnection) {\n\t\t\t\tSSLSocketFactory socketFactory = this.settings.sslBundle().createSslContext().getSocketFactory();\n\t\t\t\tsecureConnection.setSSLSocketFactory(socketFactory);\n\t\t\t}\n\t\t\tif (this.settings.redirects() == HttpRedirects.DONT_FOLLOW) {\n\t\t\t\tconnection.setInstanceFollowRedirects(false);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/ApiversionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.bind.Name;\n\n/**\n * API Version properties for both reactive and imperative HTTP Clients.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ApiversionProperties {\n\n\t/**\n\t * Default version that should be used for each request.\n\t */\n\t@Name(\"default\")\n\tprivate @Nullable String defaultVersion;\n\n\t/**\n\t * How version details should be inserted into requests.\n\t */\n\tprivate final Insert insert = new Insert();\n\n\tpublic @Nullable String getDefaultVersion() {\n\t\treturn this.defaultVersion;\n\t}\n\n\tpublic void setDefaultVersion(@Nullable String defaultVersion) {\n\t\tthis.defaultVersion = defaultVersion;\n\t}\n\n\tpublic Insert getInsert() {\n\t\treturn this.insert;\n\t}\n\n\tpublic static class Insert {\n\n\t\t/**\n\t\t * Insert the version into a header with the given name.\n\t\t */\n\t\tprivate @Nullable String header;\n\n\t\t/**\n\t\t * Insert the version into a query parameter with the given name.\n\t\t */\n\t\tprivate @Nullable String queryParameter;\n\n\t\t/**\n\t\t * Insert the version into a path segment at the given index.\n\t\t */\n\t\tprivate @Nullable Integer pathSegment;\n\n\t\t/**\n\t\t * Insert the version into a media type parameter with the given name.\n\t\t */\n\t\tprivate @Nullable String mediaTypeParameter;\n\n\t\tpublic @Nullable String getHeader() {\n\t\t\treturn this.header;\n\t\t}\n\n\t\tpublic void setHeader(@Nullable String header) {\n\t\t\tthis.header = header;\n\t\t}\n\n\t\tpublic @Nullable String getQueryParameter() {\n\t\t\treturn this.queryParameter;\n\t\t}\n\n\t\tpublic void setQueryParameter(@Nullable String queryParameter) {\n\t\t\tthis.queryParameter = queryParameter;\n\t\t}\n\n\t\tpublic @Nullable Integer getPathSegment() {\n\t\t\treturn this.pathSegment;\n\t\t}\n\n\t\tpublic void setPathSegment(@Nullable Integer pathSegment) {\n\t\t\tthis.pathSegment = pathSegment;\n\t\t}\n\n\t\tpublic @Nullable String getMediaTypeParameter() {\n\t\t\treturn this.mediaTypeParameter;\n\t\t}\n\n\t\tpublic void setMediaTypeParameter(@Nullable String mediaTypeParameter) {\n\t\t\tthis.mediaTypeParameter = mediaTypeParameter;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/ClientHttpRequestFactoryBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\n\n/**\n * Customizer that can be used to modify the auto-configured\n * {@link ClientHttpRequestFactoryBuilder} when its type matches.\n *\n * @param <B> the builder type\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface ClientHttpRequestFactoryBuilderCustomizer<B extends ClientHttpRequestFactoryBuilder<?>> {\n\n\t/**\n\t * Customize the given builder.\n\t * @param builder the builder to customize\n\t * @return the customized builder\n\t */\n\tB customize(B builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HttpClientSettings}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = SslAutoConfiguration.class)\n@EnableConfigurationProperties(HttpClientsProperties.class)\npublic final class HttpClientAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHttpClientSettings httpClientSettings(ObjectProvider<SslBundles> sslBundles, HttpClientsProperties properties) {\n\t\tHttpClientSettingsPropertyMapper propertyMapper = new HttpClientSettingsPropertyMapper(\n\t\t\t\tsslBundles.getIfAvailable(), null);\n\t\treturn propertyMapper.map(properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\n\n/**\n * Base class for configuration properties common to both imperative and reactive HTTP\n * clients.\n *\n * @author Olga Maciaszek-Sharma\n * @author Rossen Stoyanchev\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class HttpClientProperties extends HttpClientSettingsProperties {\n\n\t/**\n\t * Base url to set in the underlying HTTP client group. By default, set to\n\t * {@code null}.\n\t */\n\tprivate @Nullable String baseUrl;\n\n\t/**\n\t * Default request headers for interface client group. By default, set to empty\n\t * {@link Map}.\n\t */\n\tprivate Map<String, List<String>> defaultHeader = new LinkedHashMap<>();\n\n\t/**\n\t * API version properties.\n\t */\n\t@NestedConfigurationProperty\n\tprivate final ApiversionProperties apiversion = new ApiversionProperties();\n\n\tpublic @Nullable String getBaseUrl() {\n\t\treturn this.baseUrl;\n\t}\n\n\tpublic void setBaseUrl(@Nullable String baseUrl) {\n\t\tthis.baseUrl = baseUrl;\n\t}\n\n\tpublic Map<String, List<String>> getDefaultHeader() {\n\t\treturn this.defaultHeader;\n\t}\n\n\tpublic void setDefaultHeader(Map<String, List<String>> defaultHeaders) {\n\t\tthis.defaultHeader = defaultHeaders;\n\t}\n\n\tpublic ApiversionProperties getApiversion() {\n\t\treturn this.apiversion;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientSettingsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpCookieHandling;\nimport org.springframework.boot.http.client.HttpRedirects;\n\n/**\n * Base class for configuration properties configure {@link HttpClientSettings}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see HttpClientSettings\n */\npublic abstract class HttpClientSettingsProperties {\n\n\t/**\n\t * Handling for HTTP redirects.\n\t */\n\tprivate @Nullable HttpRedirects redirects;\n\n\t/**\n\t * Default connect timeout for a client HTTP request.\n\t */\n\tprivate @Nullable Duration connectTimeout;\n\n\t/**\n\t * Default read timeout for a client HTTP request.\n\t */\n\tprivate @Nullable Duration readTimeout;\n\n\t/**\n\t * Handling for HTTP cookies.\n\t */\n\tprivate @Nullable HttpCookieHandling cookieHandling;\n\n\t/**\n\t * Default SSL configuration for a client HTTP request.\n\t */\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic @Nullable HttpRedirects getRedirects() {\n\t\treturn this.redirects;\n\t}\n\n\tpublic void setRedirects(@Nullable HttpRedirects redirects) {\n\t\tthis.redirects = redirects;\n\t}\n\n\tpublic @Nullable Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(@Nullable Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic @Nullable Duration getReadTimeout() {\n\t\treturn this.readTimeout;\n\t}\n\n\tpublic void setReadTimeout(@Nullable Duration readTimeout) {\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\tpublic @Nullable HttpCookieHandling getCookieHandling() {\n\t\treturn this.cookieHandling;\n\t}\n\n\tpublic void setCookieHandling(@Nullable HttpCookieHandling cookieHandling) {\n\t\tthis.cookieHandling = cookieHandling;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\t/**\n\t * SSL configuration.\n\t */\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * SSL bundle to use.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientSettingsPropertyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\n\n/**\n * Utility that can be used to map {@link HttpClientSettingsProperties} to\n * {@link HttpClientSettings}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class HttpClientSettingsPropertyMapper {\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\tprivate final HttpClientSettings settings;\n\n\tpublic HttpClientSettingsPropertyMapper(@Nullable SslBundles sslBundles, @Nullable HttpClientSettings settings) {\n\t\tthis.sslBundles = sslBundles;\n\t\tthis.settings = (settings != null) ? settings : HttpClientSettings.defaults();\n\t}\n\n\tpublic HttpClientSettings map(@Nullable HttpClientSettingsProperties properties) {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults();\n\t\tif (properties != null) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tsettings = map.from(properties::getRedirects).to(settings, HttpClientSettings::withRedirects);\n\t\t\tsettings = map.from(properties::getConnectTimeout).to(settings, HttpClientSettings::withConnectTimeout);\n\t\t\tsettings = map.from(properties::getReadTimeout).to(settings, HttpClientSettings::withReadTimeout);\n\t\t\tsettings = map.from(properties::getCookieHandling).to(settings, HttpClientSettings::withCookieHandling);\n\t\t\tsettings = map.from(properties::getSsl)\n\t\t\t\t.as(HttpClientSettingsProperties.Ssl::getBundle)\n\t\t\t\t.as(this::getSslBundle)\n\t\t\t\t.to(settings, HttpClientSettings::withSslBundle);\n\t\t}\n\t\treturn settings.orElse(this.settings);\n\t}\n\n\tprivate SslBundle getSslBundle(String name) {\n\t\tAssert.state(this.sslBundles != null, \"No 'sslBundles' available\");\n\t\treturn this.sslBundles.getBundle(name);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/HttpClientsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} to configure the defaults used\n * for all imperative and reactive HTTP clients.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.http.clients\")\npublic class HttpClientsProperties extends HttpClientSettingsProperties {\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport java.net.URI;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.ApiVersionInserter;\n\n/**\n * {@link ApiVersionInserter} backed by {@link ApiversionProperties}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class PropertiesApiVersionInserter implements ApiVersionInserter {\n\n\tstatic final PropertiesApiVersionInserter EMPTY = new PropertiesApiVersionInserter(new ApiVersionInserter() {\n\t});\n\n\tprivate final ApiVersionInserter delegate;\n\n\tprivate PropertiesApiVersionInserter(ApiVersionInserter delegate) {\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic URI insertVersion(Object version, URI uri) {\n\t\treturn this.delegate.insertVersion(version, uri);\n\t}\n\n\t@Override\n\tpublic void insertVersion(Object version, HttpHeaders headers) {\n\t\tthis.delegate.insertVersion(version, headers);\n\t}\n\n\t/**\n\t * Factory method to get a new {@link PropertiesApiVersionInserter} for the given\n\t * properties.\n\t * @param properties the API version properties\n\t * @return an {@link PropertiesApiVersionInserter} configured from the properties\n\t */\n\tpublic static PropertiesApiVersionInserter get(ApiversionProperties.Insert properties) {\n\t\tBuilder builder = builder(properties);\n\t\treturn (builder != null) ? new PropertiesApiVersionInserter(builder.build()) : EMPTY;\n\t}\n\n\t/**\n\t * Factory method to create a new\n\t * {@link org.springframework.web.client.ApiVersionInserter.Builder builder} from the\n\t * given properties, if there are any.\n\t * @param properties the API version properties\n\t * @return a builder configured from the properties or {@code null} if no properties\n\t * were mapped\n\t */\n\tprivate static ApiVersionInserter.@Nullable Builder builder(ApiversionProperties.Insert properties) {\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tApiVersionInserter.Builder builder = ApiVersionInserter.builder();\n\t\tCounter counter = new Counter();\n\t\tmap.from(properties::getHeader).whenHasText().as(counter::counted).to(builder::useHeader);\n\t\tmap.from(properties::getQueryParameter).whenHasText().as(counter::counted).to(builder::useQueryParam);\n\t\tmap.from(properties::getPathSegment).as(counter::counted).to(builder::usePathSegment);\n\t\tmap.from(properties::getMediaTypeParameter).as(counter::counted).to(builder::useMediaTypeParam);\n\t\treturn (!counter.isEmpty()) ? builder : null;\n\t}\n\n\t/**\n\t * Internal counter used to track if properties were applied.\n\t */\n\tprivate static final class Counter {\n\n\t\tprivate boolean empty = true;\n\n\t\t<T> T counted(T value) {\n\t\t\tthis.empty = false;\n\t\t\treturn value;\n\t\t}\n\n\t\tboolean isEmpty() {\n\t\t\treturn this.empty;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/imperative/ImperativeHttpClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.imperative;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.autoconfigure.ClientHttpRequestFactoryBuilderCustomizer;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.http.client.ClientHttpRequestFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for imperative HTTP clients.\n *\n * @author Phillip Webb\n * @author Sangmin Park\n * @since 4.0.0\n * @see HttpClientAutoConfiguration\n */\n@AutoConfiguration(after = HttpClientAutoConfiguration.class)\n@ConditionalOnClass(ClientHttpRequestFactory.class)\n@Conditional(NotReactiveWebApplicationCondition.class)\n@EnableConfigurationProperties(ImperativeHttpClientsProperties.class)\npublic final class ImperativeHttpClientAutoConfiguration {\n\n\tprivate final Environment environment;\n\n\tImperativeHttpClientAutoConfiguration(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder(ResourceLoader resourceLoader,\n\t\t\tImperativeHttpClientsProperties properties,\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilderCustomizer<?>> clientHttpRequestFactoryBuilderCustomizers) {\n\t\tClientHttpRequestFactoryBuilder<?> builder = (properties.getFactory() != null)\n\t\t\t\t? properties.getFactory().builder()\n\t\t\t\t: ClientHttpRequestFactoryBuilder.detect(resourceLoader.getClassLoader());\n\t\tif (builder instanceof JdkClientHttpRequestFactoryBuilder jdk && Threading.VIRTUAL.isActive(this.environment)) {\n\t\t\tbuilder = jdk.withExecutor(new VirtualThreadTaskExecutor(\"httpclient-\"));\n\t\t}\n\t\treturn customize(builder, clientHttpRequestFactoryBuilderCustomizers.orderedStream().toList());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ClientHttpRequestFactoryBuilder<?> customize(ClientHttpRequestFactoryBuilder<?> builder,\n\t\t\tList<ClientHttpRequestFactoryBuilderCustomizer<?>> customizers) {\n\t\tClientHttpRequestFactoryBuilder<?>[] builderReference = { builder };\n\t\tLambdaSafe.callbacks(ClientHttpRequestFactoryBuilderCustomizer.class, customizers, builderReference[0])\n\t\t\t.invoke((customizer) -> builderReference[0] = customizer.customize(builderReference[0]));\n\t\treturn builderReference[0];\n\t}\n\n\t@Bean\n\t@Lazy\n\t@ConditionalOnMissingBean\n\tClientHttpRequestFactory clientHttpRequestFactory(\n\t\t\tClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder, HttpClientSettings httpClientSettings) {\n\t\treturn clientHttpRequestFactoryBuilder.build(httpClientSettings);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/imperative/ImperativeHttpClientsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.imperative;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientsProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} to configure the defaults used\n * for imperative HTTP clients.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see HttpClientsProperties\n */\n@ConfigurationProperties(\"spring.http.clients.imperative\")\npublic class ImperativeHttpClientsProperties {\n\n\t/**\n\t * Default factory used for a client HTTP request.\n\t */\n\tprivate @Nullable Factory factory;\n\n\tpublic @Nullable Factory getFactory() {\n\t\treturn this.factory;\n\t}\n\n\tpublic void setFactory(@Nullable Factory factory) {\n\t\tthis.factory = factory;\n\t}\n\n\t/**\n\t * Supported factory types.\n\t */\n\tpublic enum Factory {\n\n\t\t/**\n\t\t * Apache HttpComponents HttpClient.\n\t\t */\n\t\tHTTP_COMPONENTS(ClientHttpRequestFactoryBuilder::httpComponents),\n\n\t\t/**\n\t\t * Jetty's HttpClient.\n\t\t */\n\t\tJETTY(ClientHttpRequestFactoryBuilder::jetty),\n\n\t\t/**\n\t\t * Reactor-Netty.\n\t\t */\n\t\tREACTOR(ClientHttpRequestFactoryBuilder::reactor),\n\n\t\t/**\n\t\t * Java's HttpClient.\n\t\t */\n\t\tJDK(ClientHttpRequestFactoryBuilder::jdk),\n\n\t\t/**\n\t\t * Standard JDK facilities.\n\t\t */\n\t\tSIMPLE(ClientHttpRequestFactoryBuilder::simple);\n\n\t\tprivate final Supplier<ClientHttpRequestFactoryBuilder<?>> builderSupplier;\n\n\t\tFactory(Supplier<ClientHttpRequestFactoryBuilder<?>> builderSupplier) {\n\t\t\tthis.builderSupplier = builderSupplier;\n\t\t}\n\n\t\tClientHttpRequestFactoryBuilder<?> builder() {\n\t\t\treturn this.builderSupplier.get();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/imperative/NotReactiveWebApplicationCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.imperative;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\n\n/**\n * {@link SpringBootCondition} that applies only when running in a non-reactive web\n * application.\n *\n * @author Phillip Webb\n */\nclass NotReactiveWebApplicationCondition extends NoneNestedConditions {\n\n\tNotReactiveWebApplicationCondition() {\n\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t}\n\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\tprivate static final class ReactiveWebApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/imperative/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for client-side imperative HTTP.\n */\n@NullMarked\npackage org.springframework.boot.http.client.autoconfigure.imperative;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties.Web.Client;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for HTTP client-related metrics.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Raheela Aslam\n * @author Brian Clozel\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnClass({ ObservationProperties.class, MeterRegistry.class, MetricsProperties.class })\n@ConditionalOnBean(MeterRegistry.class)\n@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })\npublic final class HttpClientMetricsAutoConfiguration {\n\n\t@Bean\n\t@Order(0)\n\tMaximumAllowableTagsMeterFilter metricsHttpClientUriTagFilter(ObservationProperties observationProperties,\n\t\t\tMetricsProperties metricsProperties) {\n\t\tClient clientProperties = metricsProperties.getWeb().getClient();\n\t\tString meterNamePrefix = observationProperties.getHttp().getClient().getRequests().getName();\n\t\tint maxUriTags = clientProperties.getMaxUriTags();\n\t\treturn new MaximumAllowableTagsMeterFilter(meterNamePrefix, \"uri\", maxUriTags, \"Are you using 'uriVariables'?\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for client-side HTTP metrics.\n */\n@NullMarked\npackage org.springframework.boot.http.client.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for client-side HTTP.\n */\n@NullMarked\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/reactive/ClientHttpConnectorBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\n\n/**\n * Customizer that can be used to modify the auto-configured\n * {@link ClientHttpConnectorBuilder} when its type matches.\n *\n * @param <B> the builder type\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic interface ClientHttpConnectorBuilderCustomizer<B extends ClientHttpConnectorBuilder<?>> {\n\n\t/**\n\t * Customize the given builder.\n\t * @param builder the builder to customize\n\t * @return the customized builder\n\t */\n\tB customize(B builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/reactive/ConditionalOnClientHttpConnectorBuilderDetection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link Condition} that checks that {@link ClientHttpConnectorBuilder} can be detected.\n *\n * @author Phillip Webb\n */\nclass ConditionalOnClientHttpConnectorBuilderDetection extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\ttry {\n\t\t\tClientHttpConnectorBuilder.detect(context.getClassLoader());\n\t\t\treturn ConditionOutcome.match(\"Detected ClientHttpConnectorBuilder\");\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\treturn ConditionOutcome.noMatch(\"Unable to detect ClientHttpConnectorBuilder\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/reactive/ReactiveHttpClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport java.util.List;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.JdkClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.ReactorClientHttpConnectorBuilder;\nimport org.springframework.boot.reactor.netty.autoconfigure.ReactorNettyConfigurations;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for reactive HTTP clients.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see HttpClientAutoConfiguration\n */\n@AutoConfiguration(after = HttpClientAutoConfiguration.class)\n@ConditionalOnClass({ ClientHttpConnector.class, Mono.class })\n@Conditional(ConditionalOnClientHttpConnectorBuilderDetection.class)\n@EnableConfigurationProperties(ReactiveHttpClientsProperties.class)\npublic final class ReactiveHttpClientAutoConfiguration {\n\n\tprivate final Environment environment;\n\n\tReactiveHttpClientAutoConfiguration(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tClientHttpConnectorBuilder<?> clientHttpConnectorBuilder(ResourceLoader resourceLoader,\n\t\t\tReactiveHttpClientsProperties properties,\n\t\t\tObjectProvider<ClientHttpConnectorBuilderCustomizer<?>> clientHttpConnectorBuilderCustomizers) {\n\t\tClientHttpConnectorBuilder<?> builder = (properties.getConnector() != null)\n\t\t\t\t? properties.getConnector().builder()\n\t\t\t\t: ClientHttpConnectorBuilder.detect(resourceLoader.getClassLoader());\n\t\tif (builder instanceof JdkClientHttpConnectorBuilder jdk && Threading.VIRTUAL.isActive(this.environment)) {\n\t\t\tbuilder = jdk.withExecutor(new VirtualThreadTaskExecutor(\"httpclient-\"));\n\t\t}\n\t\treturn customize(builder, clientHttpConnectorBuilderCustomizers.orderedStream().toList());\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ClientHttpConnectorBuilder<?> customize(ClientHttpConnectorBuilder<?> builder,\n\t\t\tList<ClientHttpConnectorBuilderCustomizer<?>> customizers) {\n\t\tClientHttpConnectorBuilder<?>[] builderReference = { builder };\n\t\tLambdaSafe.callbacks(ClientHttpConnectorBuilderCustomizer.class, customizers, builderReference[0])\n\t\t\t.invoke((customizer) -> builderReference[0] = customizer.customize(builderReference[0]));\n\t\treturn builderReference[0];\n\t}\n\n\t@Bean\n\t@Lazy\n\t@ConditionalOnMissingBean\n\tClientHttpConnector clientHttpConnector(ResourceLoader resourceLoader,\n\t\t\tObjectProvider<ClientHttpConnectorBuilder<?>> clientHttpConnectorBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings) {\n\t\treturn clientHttpConnectorBuilder\n\t\t\t.getIfAvailable(() -> ClientHttpConnectorBuilder.detect(resourceLoader.getClassLoader()))\n\t\t\t.build(httpClientSettings.getIfAvailable(HttpClientSettings::defaults));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ reactor.netty.http.client.HttpClient.class, ReactorNettyConfigurations.class })\n\t@Import(ReactorNettyConfigurations.ReactorResourceFactoryConfiguration.class)\n\tstatic class ReactorNetty {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tClientHttpConnectorBuilderCustomizer<ReactorClientHttpConnectorBuilder> reactorResourceFactoryClientHttpConnectorBuilderCustomizer(\n\t\t\t\tReactorResourceFactory reactorResourceFactory) {\n\t\t\treturn (builder) -> builder.withReactorResourceFactory(reactorResourceFactory);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/reactive/ReactiveHttpClientsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientsProperties;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} to configure the defaults used\n * for reactive HTTP clients.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see HttpClientsProperties\n */\n@ConfigurationProperties(\"spring.http.clients.reactive\")\npublic class ReactiveHttpClientsProperties {\n\n\t/**\n\t * Default connector used for a client HTTP request.\n\t */\n\tprivate @Nullable Connector connector;\n\n\tpublic @Nullable Connector getConnector() {\n\t\treturn this.connector;\n\t}\n\n\tpublic void setConnector(@Nullable Connector connector) {\n\t\tthis.connector = connector;\n\t}\n\n\t/**\n\t * Supported factory types.\n\t */\n\tpublic enum Connector {\n\n\t\t/**\n\t\t * Reactor-Netty.\n\t\t */\n\t\tREACTOR(ClientHttpConnectorBuilder::reactor),\n\n\t\t/**\n\t\t * Jetty's HttpClient.\n\t\t */\n\t\tJETTY(ClientHttpConnectorBuilder::jetty),\n\n\t\t/**\n\t\t * Apache HttpComponents HttpClient.\n\t\t */\n\t\tHTTP_COMPONENTS(ClientHttpConnectorBuilder::httpComponents),\n\n\t\t/**\n\t\t * Java's HttpClient.\n\t\t */\n\t\tJDK(ClientHttpConnectorBuilder::jdk);\n\n\t\tprivate final Supplier<ClientHttpConnectorBuilder<?>> builderSupplier;\n\n\t\tConnector(Supplier<ClientHttpConnectorBuilder<?>> builderSupplier) {\n\t\t\tthis.builderSupplier = builderSupplier;\n\t\t}\n\n\t\tClientHttpConnectorBuilder<?> builder() {\n\t\t\treturn this.builderSupplier.get();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for client-side reactive HTTP.\n */\n@NullMarked\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/service/HttpServiceClientProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.service;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientProperties;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties.HttpServiceClientPropertiesRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.env.Environment;\n\n/**\n * Properties for HTTP Service clients.\n *\n * @author Olga Maciaszek-Sharma\n * @author Rossen Stoyanchev\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ImportRuntimeHints(HttpServiceClientPropertiesRuntimeHints.class)\npublic class HttpServiceClientProperties {\n\n\tprivate final Map<String, HttpClientProperties> properties;\n\n\tHttpServiceClientProperties(Map<String, HttpClientProperties> properties) {\n\t\tthis.properties = properties;\n\n\t}\n\n\t/**\n\t * Return the {@link HttpClientProperties} for the given named client.\n\t * @param name the service client name\n\t * @return the properties or {@code null}\n\t */\n\tpublic @Nullable HttpClientProperties get(String name) {\n\t\treturn this.properties.get(name);\n\t}\n\n\tstatic HttpServiceClientProperties bind(Environment environment) {\n\t\treturn new HttpServiceClientProperties(Binder.get(environment)\n\t\t\t.bind(\"spring.http.serviceclient\", Bindable.mapOf(String.class, HttpClientProperties.class))\n\t\t\t.orElse(Collections.emptyMap()));\n\t}\n\n\tstatic class HttpServiceClientPropertiesRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tBindableRuntimeHintsRegistrar.forTypes(HttpClientProperties.class).registerHints(hints, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/service/HttpServiceClientPropertiesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.service;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link HttpServiceClientProperties}.\n *\n * @author Phillip Webb\n * @since 4.0.2\n */\n@AutoConfiguration\npublic final class HttpServiceClientPropertiesAutoConfiguration {\n\n\t@Bean\n\tHttpServiceClientProperties httpServiceClientProperties(Environment environment) {\n\t\treturn HttpServiceClientProperties.bind(environment);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/autoconfigure/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration support classes for HTTP Service Clients.\n */\n@NullMarked\npackage org.springframework.boot.http.client.autoconfigure.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Client-side HTTP support classes.\n */\n@NullMarked\npackage org.springframework.boot.http.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/AbstractClientHttpConnectorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.util.Assert;\n\n/**\n * Internal base class used for {@link ClientHttpConnectorBuilder} implementations.\n *\n * @param <T> the {@link ClientHttpConnector} type\n * @author Phillip Webb\n */\nabstract class AbstractClientHttpConnectorBuilder<T extends ClientHttpConnector>\n\t\timplements ClientHttpConnectorBuilder<T> {\n\n\tprivate final List<Consumer<T>> customizers;\n\n\tprotected AbstractClientHttpConnectorBuilder(@Nullable List<Consumer<T>> customizers) {\n\t\tthis.customizers = (customizers != null) ? customizers : Collections.emptyList();\n\t}\n\n\tprotected final List<Consumer<T>> getCustomizers() {\n\t\treturn this.customizers;\n\t}\n\n\tprotected final List<Consumer<T>> mergedCustomizers(Consumer<T> customizer) {\n\t\tAssert.notNull(this.customizers, \"'customizer' must not be null\");\n\t\treturn merge(this.customizers, List.of(customizer));\n\t}\n\n\tprotected final List<Consumer<T>> mergedCustomizers(Collection<Consumer<T>> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tAssert.noNullElements(customizers, \"'customizers' must not contain null elements\");\n\t\treturn merge(this.customizers, customizers);\n\t}\n\n\tprivate <E> List<E> merge(Collection<E> list, Collection<? extends E> additional) {\n\t\tList<E> merged = new ArrayList<>(list);\n\t\tmerged.addAll(additional);\n\t\treturn List.copyOf(merged);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic final T build(@Nullable HttpClientSettings settings) {\n\t\tT connector = createClientHttpConnector((settings != null) ? settings : HttpClientSettings.defaults());\n\t\tLambdaSafe.callbacks(Consumer.class, this.customizers, connector)\n\t\t\t.invoke((consumer) -> consumer.accept(connector));\n\t\treturn connector;\n\t}\n\n\tprotected abstract T createClientHttpConnector(HttpClientSettings settings);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/ClientHttpConnectorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.http.client.reactive.HttpComponentsClientHttpConnector;\nimport org.springframework.http.client.reactive.JdkClientHttpConnector;\nimport org.springframework.http.client.reactive.JettyClientHttpConnector;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.util.Assert;\n\n/**\n * Interface used to build a fully configured {@link ClientHttpConnector}. Builders for\n * {@link #reactor() Reactor}, {@link #jetty() Jetty}, {@link #httpComponents() Apache\n * HTTP Components} and {@link #jdk() JDK} can be obtained using the factory methods on\n * this interface. The {@link #of(Class)} method may be used to instantiate based on the\n * connector type.\n *\n * @param <T> the {@link ClientHttpConnector} type\n * @author Phillip Webb\n * @since 3.5.0\n */\n@FunctionalInterface\npublic interface ClientHttpConnectorBuilder<T extends ClientHttpConnector> {\n\n\t/**\n\t * Build a default configured {@link ClientHttpConnectorBuilder}.\n\t * @return a default configured {@link ClientHttpConnectorBuilder}.\n\t */\n\tdefault T build() {\n\t\treturn build(null);\n\t}\n\n\t/**\n\t * Build a fully configured {@link ClientHttpConnector}, applying the given\n\t * {@code settings} if they are provided.\n\t * @param settings the settings to apply or {@code null}\n\t * @return a fully configured {@link ClientHttpConnector}.\n\t */\n\tT build(@Nullable HttpClientSettings settings);\n\n\t/**\n\t * Return a new {@link ClientHttpConnectorBuilder} that applies the given customizer\n\t * to the {@link ClientHttpConnector} after it has been built.\n\t * @param customizer the customizers to apply\n\t * @return a new {@link ClientHttpConnectorBuilder} instance\n\t */\n\tdefault ClientHttpConnectorBuilder<T> withCustomizer(Consumer<T> customizer) {\n\t\treturn withCustomizers(List.of(customizer));\n\t}\n\n\t/**\n\t * Return a new {@link ClientHttpConnectorBuilder} that applies the given customizers\n\t * to the {@link ClientHttpConnector} after it has been built.\n\t * @param customizers the customizers to apply\n\t * @return a new {@link ClientHttpConnectorBuilder} instance\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tdefault ClientHttpConnectorBuilder<T> withCustomizers(Collection<Consumer<T>> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tAssert.noNullElements(customizers, \"'customizers' must not contain null elements\");\n\t\treturn (settings) -> {\n\t\t\tT factory = build(settings);\n\t\t\tLambdaSafe.callbacks(Consumer.class, customizers, factory).invoke((consumer) -> consumer.accept(factory));\n\t\t\treturn factory;\n\t\t};\n\t}\n\n\t/**\n\t * Return a {@link HttpComponentsClientHttpConnectorBuilder} that can be used to build\n\t * a {@link HttpComponentsClientHttpConnector}.\n\t * @return a new {@link HttpComponentsClientHttpConnectorBuilder}\n\t */\n\tstatic HttpComponentsClientHttpConnectorBuilder httpComponents() {\n\t\treturn new HttpComponentsClientHttpConnectorBuilder();\n\t}\n\n\t/**\n\t * Return a {@link JettyClientHttpConnectorBuilder} that can be used to build a\n\t * {@link JettyClientHttpConnector}.\n\t * @return a new {@link JettyClientHttpConnectorBuilder}\n\t */\n\tstatic JettyClientHttpConnectorBuilder jetty() {\n\t\treturn new JettyClientHttpConnectorBuilder();\n\t}\n\n\t/**\n\t * Return a {@link ReactorClientHttpConnectorBuilder} that can be used to build a\n\t * {@link ReactorClientHttpConnector}.\n\t * @return a new {@link ReactorClientHttpConnectorBuilder}\n\t */\n\tstatic ReactorClientHttpConnectorBuilder reactor() {\n\t\treturn new ReactorClientHttpConnectorBuilder();\n\t}\n\n\t/**\n\t * Return a {@link JdkClientHttpConnectorBuilder} that can be used to build a\n\t * {@link JdkClientHttpConnector} .\n\t * @return a new {@link JdkClientHttpConnectorBuilder}\n\t */\n\tstatic JdkClientHttpConnectorBuilder jdk() {\n\t\treturn new JdkClientHttpConnectorBuilder();\n\t}\n\n\t/**\n\t * Return a new {@link ClientHttpConnectorBuilder} for the given\n\t * {@code requestFactoryType}. The following implementations are supported:\n\t * <ul>\n\t * <li>{@link ReactorClientHttpConnector}</li>\n\t * <li>{@link JettyClientHttpConnector}</li>\n\t * <li>{@link HttpComponentsClientHttpConnector}</li>\n\t * <li>{@link JdkClientHttpConnector}</li>\n\t * </ul>\n\t * @param <T> the {@link ClientHttpConnector} type\n\t * @param clientHttpConnectorType the {@link ClientHttpConnector} type\n\t * @return a new {@link ClientHttpConnectorBuilder}\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tstatic <T extends ClientHttpConnector> ClientHttpConnectorBuilder<T> of(Class<T> clientHttpConnectorType) {\n\t\tAssert.notNull(clientHttpConnectorType, \"'requestFactoryType' must not be null\");\n\t\tAssert.isTrue(clientHttpConnectorType != ClientHttpConnector.class,\n\t\t\t\t\"'clientHttpConnectorType' must be an implementation of ClientHttpConnector\");\n\t\tif (clientHttpConnectorType == ReactorClientHttpConnector.class) {\n\t\t\treturn (ClientHttpConnectorBuilder<T>) reactor();\n\t\t}\n\t\tif (clientHttpConnectorType == JettyClientHttpConnector.class) {\n\t\t\treturn (ClientHttpConnectorBuilder<T>) jetty();\n\t\t}\n\t\tif (clientHttpConnectorType == HttpComponentsClientHttpConnector.class) {\n\t\t\treturn (ClientHttpConnectorBuilder<T>) httpComponents();\n\t\t}\n\t\tif (clientHttpConnectorType == JdkClientHttpConnector.class) {\n\t\t\treturn (ClientHttpConnectorBuilder<T>) jdk();\n\t\t}\n\t\tthrow new IllegalArgumentException(\n\t\t\t\t\"'clientHttpConnectorType' %s is not supported\".formatted(clientHttpConnectorType.getName()));\n\t}\n\n\t/**\n\t * Detect the most suitable {@link ClientHttpConnectorBuilder} based on the classpath.\n\t * The method favors builders in the following order:\n\t * <ol>\n\t * <li>{@link #reactor()}</li>\n\t * <li>{@link #jetty()}</li>\n\t * <li>{@link #httpComponents()}</li>\n\t * <li>{@link #jdk()}</li>\n\t * </ol>\n\t * @return the most suitable {@link ClientHttpConnectorBuilder} for the classpath\n\t */\n\tstatic ClientHttpConnectorBuilder<? extends ClientHttpConnector> detect() {\n\t\treturn detect(null);\n\t}\n\n\t/**\n\t * Detect the most suitable {@link ClientHttpConnectorBuilder} based on the classpath.\n\t * The method favors builders in the following order:\n\t * <ol>\n\t * <li>{@link #reactor()}</li>\n\t * <li>{@link #jetty()}</li>\n\t * <li>{@link #httpComponents()}</li>\n\t * <li>{@link #jdk()}</li>\n\t * </ol>\n\t * @param classLoader the class loader to use for detection\n\t * @return the most suitable {@link ClientHttpConnectorBuilder} for the classpath\n\t */\n\tstatic ClientHttpConnectorBuilder<? extends ClientHttpConnector> detect(@Nullable ClassLoader classLoader) {\n\t\tif (ReactorClientHttpConnectorBuilder.Classes.present(classLoader)) {\n\t\t\treturn reactor();\n\t\t}\n\t\tif (JettyClientHttpConnectorBuilder.Classes.present(classLoader)) {\n\t\t\treturn jetty();\n\t\t}\n\t\tif (HttpComponentsClientHttpConnectorBuilder.Classes.present(classLoader)) {\n\t\t\treturn httpComponents();\n\t\t}\n\t\tif (JdkClientHttpConnectorBuilder.Classes.present(classLoader)) {\n\t\t\treturn jdk();\n\t\t}\n\t\tthrow new IllegalStateException(\"Unable to detect any ClientHttpConnectorBuilder\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/HttpComponentsClientHttpConnectorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.UnaryOperator;\n\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\nimport org.apache.hc.core5.http.nio.ssl.TlsStrategy;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpComponentsHttpAsyncClientBuilder;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.http.client.reactive.HttpComponentsClientHttpConnector;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpConnectorBuilder#httpComponents()}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic final class HttpComponentsClientHttpConnectorBuilder\n\t\textends AbstractClientHttpConnectorBuilder<HttpComponentsClientHttpConnector> {\n\n\tprivate final HttpComponentsHttpAsyncClientBuilder httpClientBuilder;\n\n\tHttpComponentsClientHttpConnectorBuilder() {\n\t\tthis(null, new HttpComponentsHttpAsyncClientBuilder());\n\t}\n\n\tprivate HttpComponentsClientHttpConnectorBuilder(\n\t\t\t@Nullable List<Consumer<HttpComponentsClientHttpConnector>> customizers,\n\t\t\tHttpComponentsHttpAsyncClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpConnectorBuilder} that applies\n\t * additional customization to the underlying {@link HttpAsyncClientBuilder}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsHttpAsyncClientBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpConnectorBuilder withHttpClientCustomizer(\n\t\t\tConsumer<HttpAsyncClientBuilder> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'customizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpConnectorBuilder} that applies\n\t * additional customization to the underlying\n\t * {@link PoolingAsyncClientConnectionManagerBuilder}.\n\t * @param connectionManagerCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpConnectorBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpConnectorBuilder withConnectionManagerCustomizer(\n\t\t\tConsumer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCustomizer) {\n\t\tAssert.notNull(connectionManagerCustomizer, \"'connectionManagerCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withConnectionManagerCustomizer(connectionManagerCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpConnectorBuilder} that applies\n\t * additional customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.ConnectionConfig.Builder}.\n\t * @param connectionConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpConnectorBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpConnectorBuilder withConnectionConfigCustomizer(\n\t\t\tConsumer<ConnectionConfig.Builder> connectionConfigCustomizer) {\n\t\tAssert.notNull(connectionConfigCustomizer, \"'connectionConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withConnectionConfigCustomizer(connectionConfigCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpConnectorBuilder} with a replacement\n\t * {@link TlsStrategy} factory.\n\t * @param tlsStrategyFactory the new factory used to create a {@link TlsStrategy} for\n\t * a given {@link SslBundle}\n\t * @return a new {@link HttpComponentsClientHttpConnectorBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpConnectorBuilder withTlsSocketStrategyFactory(\n\t\t\tFunction<@Nullable SslBundle, @Nullable TlsStrategy> tlsStrategyFactory) {\n\t\tAssert.notNull(tlsStrategyFactory, \"'tlsStrategyFactory' must not be null\");\n\t\treturn new HttpComponentsClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withTlsStrategyFactory(tlsStrategyFactory));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpConnectorBuilder} that applies\n\t * additional customization to the underlying\n\t * {@link org.apache.hc.client5.http.config.RequestConfig.Builder} used for default\n\t * requests.\n\t * @param defaultRequestConfigCustomizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpConnectorBuilder} instance\n\t */\n\tpublic HttpComponentsClientHttpConnectorBuilder withDefaultRequestConfigCustomizer(\n\t\t\tConsumer<RequestConfig.Builder> defaultRequestConfigCustomizer) {\n\t\tAssert.notNull(defaultRequestConfigCustomizer, \"'defaultRequestConfigCustomizer' must not be null\");\n\t\treturn new HttpComponentsClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link HttpComponentsClientHttpConnectorBuilder} that applies the\n\t * given customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link HttpComponentsClientHttpConnectorBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic HttpComponentsClientHttpConnectorBuilder with(\n\t\t\tUnaryOperator<HttpComponentsClientHttpConnectorBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected HttpComponentsClientHttpConnector createClientHttpConnector(HttpClientSettings settings) {\n\t\tCloseableHttpAsyncClient client = this.httpClientBuilder.build(settings);\n\t\treturn new HttpComponentsClientHttpConnector(client);\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENTS = \"org.apache.hc.client5.http.impl.async.HttpAsyncClients\";\n\n\t\tstatic final String REACTIVE_RESPONSE_CONSUMER = \"org.apache.hc.core5.reactive.ReactiveResponseConsumer\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENTS, classLoader)\n\t\t\t\t\t&& ClassUtils.isPresent(REACTIVE_RESPONSE_CONSUMER, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/JdkClientHttpConnectorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.net.http.HttpClient;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.function.Consumer;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.JdkHttpClientBuilder;\nimport org.springframework.http.client.reactive.JdkClientHttpConnector;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpConnectorBuilder#jdk()}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic final class JdkClientHttpConnectorBuilder extends AbstractClientHttpConnectorBuilder<JdkClientHttpConnector> {\n\n\tprivate final JdkHttpClientBuilder httpClientBuilder;\n\n\tJdkClientHttpConnectorBuilder() {\n\t\tthis(null, new JdkHttpClientBuilder());\n\t}\n\n\tprivate JdkClientHttpConnectorBuilder(@Nullable List<Consumer<JdkClientHttpConnector>> customizers,\n\t\t\tJdkHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic JdkClientHttpConnectorBuilder withCustomizer(Consumer<JdkClientHttpConnector> customizer) {\n\t\treturn new JdkClientHttpConnectorBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic JdkClientHttpConnectorBuilder withCustomizers(Collection<Consumer<JdkClientHttpConnector>> customizers) {\n\t\treturn new JdkClientHttpConnectorBuilder(mergedCustomizers(customizers), this.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link JdkClientHttpConnectorBuilder} that uses the given executor\n\t * with the underlying {@link java.net.http.HttpClient.Builder}.\n\t * @param executor the executor to use\n\t * @return a new {@link JdkClientHttpConnectorBuilder} instance\n\t * @since 4.0.0\n\t */\n\tpublic JdkClientHttpConnectorBuilder withExecutor(Executor executor) {\n\t\treturn new JdkClientHttpConnectorBuilder(getCustomizers(), this.httpClientBuilder.withExecutor(executor));\n\t}\n\n\t/**\n\t * Return a new {@link JdkClientHttpConnectorBuilder} that applies additional\n\t * customization to the underlying {@link java.net.http.HttpClient.Builder}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link JdkClientHttpConnectorBuilder} instance\n\t */\n\tpublic JdkClientHttpConnectorBuilder withHttpClientCustomizer(Consumer<HttpClient.Builder> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new JdkClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JdkClientHttpConnectorBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link JdkClientHttpConnectorBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic JdkClientHttpConnectorBuilder with(UnaryOperator<JdkClientHttpConnectorBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected JdkClientHttpConnector createClientHttpConnector(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings.withReadTimeout(null));\n\t\tJdkClientHttpConnector connector = new JdkClientHttpConnector(httpClient);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(settings::readTimeout).to(connector::setReadTimeout);\n\t\treturn connector;\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENT = \"java.net.http.HttpClient\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENT, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/JettyClientHttpConnectorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.UnaryOperator;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.eclipse.jetty.client.HttpClientTransport;\nimport org.eclipse.jetty.io.ClientConnector;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.JettyHttpClientBuilder;\nimport org.springframework.http.client.reactive.JettyClientHttpConnector;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpConnectorBuilder#jetty()}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic final class JettyClientHttpConnectorBuilder\n\t\textends AbstractClientHttpConnectorBuilder<JettyClientHttpConnector> {\n\n\tprivate final JettyHttpClientBuilder httpClientBuilder;\n\n\tJettyClientHttpConnectorBuilder() {\n\t\tthis(null, new JettyHttpClientBuilder());\n\t}\n\n\tprivate JettyClientHttpConnectorBuilder(@Nullable List<Consumer<JettyClientHttpConnector>> customizers,\n\t\t\tJettyHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic JettyClientHttpConnectorBuilder withCustomizer(Consumer<JettyClientHttpConnector> customizer) {\n\t\treturn new JettyClientHttpConnectorBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic JettyClientHttpConnectorBuilder withCustomizers(Collection<Consumer<JettyClientHttpConnector>> customizers) {\n\t\treturn new JettyClientHttpConnectorBuilder(mergedCustomizers(customizers), this.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpConnectorBuilder} that uses the given factory to\n\t * create the {@link HttpClientTransport}.\n\t * @param httpClientTransportFactory the {@link HttpClientTransport} factory to use\n\t * @return a new {@link JettyClientHttpConnectorBuilder} instance\n\t * @since 4.0.0\n\t */\n\tpublic JettyClientHttpConnectorBuilder withHttpClientTransportFactory(\n\t\t\tFunction<ClientConnector, HttpClientTransport> httpClientTransportFactory) {\n\t\tAssert.notNull(httpClientTransportFactory, \"'httpClientTransportFactory' must not be null\");\n\t\treturn new JettyClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientTransportFactory(httpClientTransportFactory));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpConnectorBuilder} that applies additional\n\t * customization to the underlying {@link HttpClient}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link JettyClientHttpConnectorBuilder} instance\n\t */\n\tpublic JettyClientHttpConnectorBuilder withHttpClientCustomizer(Consumer<HttpClient> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new JettyClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpConnectorBuilder} that applies additional\n\t * customization to the underlying {@link HttpClientTransport}.\n\t * @param httpClientTransportCustomizer the customizer to apply\n\t * @return a new {@link JettyClientHttpConnectorBuilder} instance\n\t */\n\tpublic JettyClientHttpConnectorBuilder withHttpClientTransportCustomizer(\n\t\t\tConsumer<HttpClientTransport> httpClientTransportCustomizer) {\n\t\tAssert.notNull(httpClientTransportCustomizer, \"'httpClientTransportCustomizer' must not be null\");\n\t\treturn new JettyClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientTransportCustomizer(httpClientTransportCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpConnectorBuilder} that applies additional\n\t * customization to the underlying {@link ClientConnector}.\n\t * @param clientConnectorCustomizerCustomizer the customizer to apply\n\t * @return a new {@link JettyClientHttpConnectorBuilder} instance\n\t */\n\tpublic JettyClientHttpConnectorBuilder withClientConnectorCustomizerCustomizer(\n\t\t\tConsumer<ClientConnector> clientConnectorCustomizerCustomizer) {\n\t\tAssert.notNull(clientConnectorCustomizerCustomizer, \"'clientConnectorCustomizerCustomizer' must not be null\");\n\t\treturn new JettyClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withClientConnectorCustomizerCustomizer(clientConnectorCustomizerCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link JettyClientHttpConnectorBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link JettyClientHttpConnectorBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic JettyClientHttpConnectorBuilder with(UnaryOperator<JettyClientHttpConnectorBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected JettyClientHttpConnector createClientHttpConnector(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings);\n\t\treturn new JettyClientHttpConnector(httpClient);\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENT = \"org.eclipse.jetty.client.HttpClient\";\n\n\t\tstatic final String REACTIVE_REQUEST = \"org.eclipse.jetty.reactive.client.ReactiveRequest\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENT, classLoader)\n\t\t\t\t\t&& ClassUtils.isPresent(REACTIVE_REQUEST, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/ReactorClientHttpConnectorBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.http.client.HttpClient;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.ReactorHttpClientBuilder;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ClientHttpConnectorBuilder#reactor()}.\n *\n * @author Phillip Webb\n * @since 3.5.0\n */\npublic final class ReactorClientHttpConnectorBuilder\n\t\textends AbstractClientHttpConnectorBuilder<ReactorClientHttpConnector> {\n\n\tprivate final ReactorHttpClientBuilder httpClientBuilder;\n\n\tReactorClientHttpConnectorBuilder() {\n\t\tthis(null, new ReactorHttpClientBuilder());\n\t}\n\n\tprivate ReactorClientHttpConnectorBuilder(@Nullable List<Consumer<ReactorClientHttpConnector>> customizers,\n\t\t\tReactorHttpClientBuilder httpClientBuilder) {\n\t\tsuper(customizers);\n\t\tthis.httpClientBuilder = httpClientBuilder;\n\t}\n\n\t@Override\n\tpublic ReactorClientHttpConnectorBuilder withCustomizer(Consumer<ReactorClientHttpConnector> customizer) {\n\t\treturn new ReactorClientHttpConnectorBuilder(mergedCustomizers(customizer), this.httpClientBuilder);\n\t}\n\n\t@Override\n\tpublic ReactorClientHttpConnectorBuilder withCustomizers(\n\t\t\tCollection<Consumer<ReactorClientHttpConnector>> customizers) {\n\t\treturn new ReactorClientHttpConnectorBuilder(mergedCustomizers(customizers), this.httpClientBuilder);\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpConnectorBuilder} that uses the given\n\t * {@link ReactorResourceFactory} to create the underlying {@link HttpClient}.\n\t * @param reactorResourceFactory the {@link ReactorResourceFactory} to use\n\t * @return a new {@link ReactorClientHttpConnectorBuilder} instance\n\t */\n\tpublic ReactorClientHttpConnectorBuilder withReactorResourceFactory(ReactorResourceFactory reactorResourceFactory) {\n\t\tAssert.notNull(reactorResourceFactory, \"'reactorResourceFactory' must not be null\");\n\t\treturn new ReactorClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withReactorResourceFactory(reactorResourceFactory));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpConnectorBuilder} that uses the given factory\n\t * to create the underlying {@link HttpClient}.\n\t * @param factory the factory to use\n\t * @return a new {@link ReactorClientHttpConnectorBuilder} instance\n\t */\n\tpublic ReactorClientHttpConnectorBuilder withHttpClientFactory(Supplier<HttpClient> factory) {\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\treturn new ReactorClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientFactory(factory));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpConnectorBuilder} that applies additional\n\t * customization to the underlying {@link HttpClient}.\n\t * @param httpClientCustomizer the customizer to apply\n\t * @return a new {@link ReactorClientHttpConnectorBuilder} instance\n\t */\n\tpublic ReactorClientHttpConnectorBuilder withHttpClientCustomizer(UnaryOperator<HttpClient> httpClientCustomizer) {\n\t\tAssert.notNull(httpClientCustomizer, \"'httpClientCustomizer' must not be null\");\n\t\treturn new ReactorClientHttpConnectorBuilder(getCustomizers(),\n\t\t\t\tthis.httpClientBuilder.withHttpClientCustomizer(httpClientCustomizer));\n\t}\n\n\t/**\n\t * Return a new {@link ReactorClientHttpConnectorBuilder} that applies the given\n\t * customizer. This can be useful for applying pre-packaged customizations.\n\t * @param customizer the customizer to apply\n\t * @return a new {@link ReactorClientHttpConnectorBuilder}\n\t * @since 4.0.0\n\t */\n\tpublic ReactorClientHttpConnectorBuilder with(UnaryOperator<ReactorClientHttpConnectorBuilder> customizer) {\n\t\treturn customizer.apply(this);\n\t}\n\n\t@Override\n\tprotected ReactorClientHttpConnector createClientHttpConnector(HttpClientSettings settings) {\n\t\tHttpClient httpClient = this.httpClientBuilder.build(settings);\n\t\treturn new ReactorClientHttpConnector(httpClient);\n\t}\n\n\tstatic class Classes {\n\n\t\tstatic final String HTTP_CLIENT = \"reactor.netty.http.client.HttpClient\";\n\n\t\tstatic boolean present(@Nullable ClassLoader classLoader) {\n\t\t\treturn ClassUtils.isPresent(HTTP_CLIENT, classLoader);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/java/org/springframework/boot/http/client/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Client-side reactive HTTP support classes.\n */\n@NullMarked\npackage org.springframework.boot.http.client.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.http.client.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Default connect timeout for a client HTTP request.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.connect-timeout\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.client.factory\",\n      \"description\": \"Default factory used for a client HTTP request.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.imperative.factory\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.client.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Default read timeout for a client HTTP request.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.read-timeout\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.client.redirects\",\n      \"description\": \"Handling for HTTP redirects.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.redirects\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.client.ssl.bundle\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"SSL bundle to use.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.ssl.bundle\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.reactiveclient.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Default connect timeout for a client HTTP request.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.connect-timeout\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.reactiveclient.connector\",\n      \"description\": \"Default connector used for a client HTTP request.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.reactive.connector\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.reactiveclient.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Default read timeout for a client HTTP request.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.read-timeout\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.reactiveclient.redirects\",\n      \"type\": \"org.springframework.boot.http.client.HttpRedirects\",\n      \"description\": \"Handling for HTTP redirects.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.redirects\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.reactiveclient.ssl.bundle\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"SSL bundle to use.\",\n      \"deprecated\": true,\n      \"deprecation\": {\n        \"replacement\": \"spring.http.clients.ssl.bundle\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.serviceclient\",\n      \"type\": \"java.util.Map<String,org.springframework.boot.http.client.autoconfigure.HttpClientProperties>\",\n      \"description\": \"HTTP Service Client definitions\",\n      \"sourceType\": \"org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.http.client.ClientHttpRequestFactoryRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-http-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration\norg.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration\norg.springframework.boot.http.client.autoconfigure.metrics.HttpClientMetricsAutoConfiguration\norg.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration\norg.springframework.boot.http.client.autoconfigure.service.HttpServiceClientPropertiesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/AbstractClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport javax.net.ssl.SSLHandshakeException;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.Ssl.ClientAuth;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Base class for {@link ClientHttpRequestFactoryBuilder} tests.\n *\n * @param <T> The {@link ClientHttpRequestFactory} type\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nabstract class AbstractClientHttpRequestFactoryBuilderTests<T extends ClientHttpRequestFactory> {\n\n\tprivate static final Function<HttpMethod, HttpStatus> ALWAYS_FOUND = (method) -> HttpStatus.FOUND;\n\n\tprivate final Class<T> requestFactoryType;\n\n\tprivate final ClientHttpRequestFactoryBuilder<T> builder;\n\n\tAbstractClientHttpRequestFactoryBuilderTests(Class<T> requestFactoryType,\n\t\t\tClientHttpRequestFactoryBuilder<T> builder) {\n\t\tthis.requestFactoryType = requestFactoryType;\n\t\tthis.builder = builder;\n\t}\n\n\t@Test\n\tvoid buildReturnsRequestFactoryOfExpectedType() {\n\t\tT requestFactory = this.builder.build();\n\t\tassertThat(requestFactory).isInstanceOf(this.requestFactoryType);\n\t}\n\n\t@Test\n\tvoid buildWhenHasConnectTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofSeconds(60));\n\t\tT requestFactory = this.builder.build(settings);\n\t\tassertThat(connectTimeout(requestFactory)).isEqualTo(Duration.ofSeconds(60).toMillis());\n\t}\n\n\t@Test\n\tvoid buildWhenHadReadTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(Duration.ofSeconds(120));\n\t\tT requestFactory = this.builder.build(settings);\n\t\tassertThat(readTimeout(requestFactory)).isEqualTo(Duration.ofSeconds(120).toMillis());\n\t}\n\n\t@ParameterizedTest\n\t@WithPackageResources(\"test.jks\")\n\t@ValueSource(strings = { \"GET\", \"POST\" })\n\tvoid connectWithSslBundle(String httpMethod) throws Exception {\n\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\twebServerFactory.setSsl(ssl());\n\t\tWebServer webServer = webServerFactory\n\t\t\t.getWebServer((context) -> context.addServlet(\"test\", TestServlet.class).addMapping(\"/\"));\n\t\ttry {\n\t\t\twebServer.start();\n\t\t\tint port = webServer.getPort();\n\t\t\tURI uri = new URI(\"https://localhost:%s\".formatted(port));\n\t\t\tClientHttpRequestFactory insecureRequestFactory = this.builder.build();\n\t\t\tClientHttpRequest insecureRequest = request(insecureRequestFactory, uri, httpMethod);\n\t\t\tassertThatExceptionOfType(SSLHandshakeException.class)\n\t\t\t\t.isThrownBy(() -> insecureRequest.execute().getBody());\n\t\t\tClientHttpRequestFactory secureRequestFactory = this.builder\n\t\t\t\t.build(HttpClientSettings.ofSslBundle(sslBundle()));\n\t\t\tClientHttpRequest secureRequest = request(secureRequestFactory, uri, httpMethod);\n\t\t\tString secureResponse = StreamUtils.copyToString(secureRequest.execute().getBody(), StandardCharsets.UTF_8);\n\t\t\tassertThat(secureResponse).contains(\"Received \" + httpMethod + \" request to /\");\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@WithPackageResources(\"test.jks\")\n\t@ValueSource(strings = { \"GET\", \"POST\" })\n\tvoid connectWithSslBundleAndOptionsMismatch(String httpMethod) throws Exception {\n\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\twebServerFactory.setSsl(ssl(\"TLS_AES_128_GCM_SHA256\"));\n\t\tWebServer webServer = webServerFactory\n\t\t\t.getWebServer((context) -> context.addServlet(\"test\", TestServlet.class).addMapping(\"/\"));\n\t\ttry {\n\t\t\twebServer.start();\n\t\t\tint port = webServer.getPort();\n\t\t\tURI uri = new URI(\"https://localhost:%s\".formatted(port));\n\t\t\tClientHttpRequestFactory requestFactory = this.builder.build(\n\t\t\t\t\tHttpClientSettings.ofSslBundle(sslBundle(SslOptions.of(Set.of(\"TLS_AES_256_GCM_SHA384\"), null))));\n\t\t\tClientHttpRequest secureRequest = request(requestFactory, uri, httpMethod);\n\t\t\tassertThatExceptionOfType(SSLHandshakeException.class).isThrownBy(() -> secureRequest.execute().getBody());\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\" })\n\tvoid redirectDefault(String httpMethod) throws Exception {\n\t\ttestRedirect(null, HttpMethod.valueOf(httpMethod), this::getExpectedRedirect);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\" })\n\tvoid redirectFollow(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.FOLLOW);\n\t\ttestRedirect(settings, HttpMethod.valueOf(httpMethod), this::getExpectedRedirect);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\" })\n\tvoid redirectDontFollow(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\ttestRedirect(settings, HttpMethod.valueOf(httpMethod), ALWAYS_FOUND);\n\t}\n\n\tprotected final void testRedirect(@Nullable HttpClientSettings settings, HttpMethod httpMethod,\n\t\t\tFunction<HttpMethod, HttpStatus> expectedStatusForMethod) throws URISyntaxException, IOException {\n\t\tHttpStatus expectedStatus = expectedStatusForMethod.apply(httpMethod);\n\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\tWebServer webServer = webServerFactory\n\t\t\t.getWebServer((context) -> context.addServlet(\"test\", TestServlet.class).addMapping(\"/\"));\n\t\ttry {\n\t\t\twebServer.start();\n\t\t\tint port = webServer.getPort();\n\t\t\tURI uri = new URI(\"http://localhost:%s\".formatted(port) + \"/redirect\");\n\t\t\tClientHttpRequestFactory requestFactory = this.builder.build(settings);\n\t\t\tClientHttpRequest request = requestFactory.createRequest(uri, httpMethod);\n\t\t\tClientHttpResponse response = request.execute();\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(expectedStatus);\n\t\t\tif (expectedStatus == HttpStatus.OK) {\n\t\t\t\tassertThat(response.getBody()).asString(StandardCharsets.UTF_8).contains(\"request to /redirected\");\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n\tprivate ClientHttpRequest request(ClientHttpRequestFactory factory, URI uri, String method) throws IOException {\n\t\treturn factory.createRequest(uri, HttpMethod.valueOf(method));\n\t}\n\n\tprivate Ssl ssl(String... ciphers) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(ClientAuth.NEED);\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setTrustStore(\"classpath:test.jks\");\n\t\tif (ciphers.length > 0) {\n\t\t\tssl.setCiphers(ciphers);\n\t\t}\n\t\treturn ssl;\n\t}\n\n\tprotected final SslBundle sslBundle() {\n\t\treturn sslBundle(SslOptions.NONE);\n\t}\n\n\tprotected final SslBundle sslBundle(SslOptions sslOptions) {\n\t\tJksSslStoreDetails storeDetails = JksSslStoreDetails.forLocation(\"classpath:test.jks\");\n\t\tJksSslStoreBundle stores = new JksSslStoreBundle(storeDetails, storeDetails);\n\t\treturn SslBundle.of(stores, SslBundleKey.of(\"password\"), sslOptions);\n\t}\n\n\tprotected HttpStatus getExpectedRedirect(HttpMethod httpMethod) {\n\t\treturn HttpStatus.OK;\n\t}\n\n\tprotected abstract long connectTimeout(T requestFactory);\n\n\tprotected abstract long readTimeout(T requestFactory);\n\n\tpublic static class TestServlet extends HttpServlet {\n\n\t\t@Override\n\t\tpublic void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {\n\t\t\tif (\"/redirect\".equals(req.getRequestURI())) {\n\t\t\t\tres.sendRedirect(\"/redirected\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.getWriter().println(\"Received \" + req.getMethod() + \" request to \" + req.getRequestURI());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/ClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ClientHttpRequestFactoryBuilder}.\n *\n * @author Phillip Webb\n */\nclass ClientHttpRequestFactoryBuilderTests {\n\n\t@Test\n\tvoid withCustomizerAppliesCustomizers() {\n\t\tClientHttpRequestFactoryBuilder<JettyClientHttpRequestFactory> builder = (\n\t\t\t\tsettings) -> new JettyClientHttpRequestFactory();\n\t\tbuilder = builder.withCustomizer(this::setJettyReadTimeout);\n\t\tJettyClientHttpRequestFactory factory = builder.build(null);\n\t\tassertThat(factory).extracting(\"readTimeout\").isEqualTo(5000L);\n\t}\n\n\t@Test\n\tvoid withCustomizersAppliesCustomizers() {\n\t\tClientHttpRequestFactoryBuilder<JettyClientHttpRequestFactory> builder = (\n\t\t\t\tsettings) -> new JettyClientHttpRequestFactory();\n\t\tbuilder = builder.withCustomizers(List.of(this::setJettyReadTimeout));\n\t\tJettyClientHttpRequestFactory factory = builder.build(null);\n\t\tassertThat(factory).extracting(\"readTimeout\").isEqualTo(5000L);\n\t}\n\n\t@Test\n\tvoid httpComponentsReturnsHttpComponentsFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.httpComponents())\n\t\t\t.isInstanceOf(HttpComponentsClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid jettyReturnsJettyFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.jetty()).isInstanceOf(JettyClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid reactorReturnsReactorFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.reactor())\n\t\t\t.isInstanceOf(ReactorClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid jdkReturnsJdkFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.jdk()).isInstanceOf(JdkClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid simpleReturnsSimpleFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.simple()).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid ofWhenExactlyClientHttpRequestFactoryTypeThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ClientHttpRequestFactoryBuilder.of(ClientHttpRequestFactory.class))\n\t\t\t.withMessage(\"'requestFactoryType' must be an implementation of ClientHttpRequestFactory\");\n\t}\n\n\t@Test\n\tvoid ofWhenSimpleFactoryReturnsSimpleFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.of(SimpleClientHttpRequestFactory.class))\n\t\t\t.isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid ofWhenHttpComponentsFactoryReturnsHttpComponentsFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.of(HttpComponentsClientHttpRequestFactory.class))\n\t\t\t.isInstanceOf(HttpComponentsClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid ofWhenReactorFactoryReturnsReactorFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.of(ReactorClientHttpRequestFactory.class))\n\t\t\t.isInstanceOf(ReactorClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid ofWhenJdkFactoryReturnsJdkFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.of(JdkClientHttpRequestFactory.class))\n\t\t\t.isInstanceOf(JdkClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid ofWhenUnknownTypeReturnsReflectiveFactoryBuilder() {\n\t\tClientHttpRequestFactoryBuilder<TestClientHttpRequestFactory> builder = ClientHttpRequestFactoryBuilder\n\t\t\t.of(TestClientHttpRequestFactory.class);\n\t\tassertThat(builder).isInstanceOf(ReflectiveComponentsClientHttpRequestFactoryBuilder.class);\n\t\tassertThat(builder.build(null)).isInstanceOf(TestClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWithSupplierWhenSupplierIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> ClientHttpRequestFactoryBuilder.of((Supplier<ClientHttpRequestFactory>) null))\n\t\t\t.withMessage(\"'requestFactorySupplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofWithSupplierReturnsReflectiveFactoryBuilder() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.of(SimpleClientHttpRequestFactory::new))\n\t\t\t.isInstanceOf(ReflectiveComponentsClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\tvoid detectWhenHttpComponents() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.detect())\n\t\t\t.isInstanceOf(HttpComponentsClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"httpclient5-*.jar\")\n\tvoid detectWhenJetty() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.detect()).isInstanceOf(JettyClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"httpclient5-*.jar\", \"jetty-client-*.jar\" })\n\tvoid detectWhenReactor() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.detect()).isInstanceOf(ReactorClientHttpRequestFactoryBuilder.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"httpclient5-*.jar\", \"jetty-client-*.jar\", \"reactor-netty-http-*.jar\" })\n\tvoid detectWhenJdk() {\n\t\tassertThat(ClientHttpRequestFactoryBuilder.detect()).isInstanceOf(JdkClientHttpRequestFactoryBuilder.class);\n\t}\n\n\tprivate void setJettyReadTimeout(JettyClientHttpRequestFactory factory) {\n\t\tfactory.setReadTimeout(Duration.ofSeconds(5));\n\t}\n\n\tpublic static class TestClientHttpRequestFactory implements ClientHttpRequestFactory {\n\n\t\t@Override\n\t\tpublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/ClientHttpRequestFactoryRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ClientHttpRequestFactoryRuntimeHints}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass ClientHttpRequestFactoryRuntimeHintsTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ClientHttpRequestFactoryRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tField requestFactoryField = ReflectionUtils.findField(AbstractClientHttpRequestFactoryWrapper.class,\n\t\t\t\t\"requestFactory\");\n\t\tassertThat(requestFactoryField).isNotNull();\n\t\tassertThat(reflection.onFieldAccess(requestFactoryField)).accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHttpComponentHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ClientHttpRequestFactoryRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(HttpComponentsClientHttpRequestFactory.class, \"setReadTimeout\", int.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(HttpComponentsClientHttpRequestFactory.class, \"setReadTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterJettyClientHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ClientHttpRequestFactoryRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(JettyClientHttpRequestFactory.class, \"setConnectTimeout\", int.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(JettyClientHttpRequestFactory.class, \"setConnectTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(JettyClientHttpRequestFactory.class, \"setReadTimeout\", long.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(JettyClientHttpRequestFactory.class, \"setReadTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterReactorHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ClientHttpRequestFactoryRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(ReactorClientHttpRequestFactory.class, \"setConnectTimeout\", int.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(ReactorClientHttpRequestFactory.class, \"setConnectTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(ReactorClientHttpRequestFactory.class, \"setReadTimeout\", long.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(ReactorClientHttpRequestFactory.class, \"setReadTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterSimpleHttpHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ClientHttpRequestFactoryRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(SimpleClientHttpRequestFactory.class, \"setConnectTimeout\", int.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(SimpleClientHttpRequestFactory.class, \"setConnectTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(SimpleClientHttpRequestFactory.class, \"setReadTimeout\", int.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(SimpleClientHttpRequestFactory.class, \"setReadTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterJdkHttpHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew ClientHttpRequestFactoryRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tassertThat(\n\t\t\t\treflection.onMethodInvocation(method(JdkClientHttpRequestFactory.class, \"setReadTimeout\", int.class)))\n\t\t\t.accepts(hints);\n\t\tassertThat(reflection\n\t\t\t.onMethodInvocation(method(JdkClientHttpRequestFactory.class, \"setReadTimeout\", Duration.class)))\n\t\t\t.accepts(hints);\n\t}\n\n\tprivate static Method method(Class<?> target, String name, Class<?>... parameterTypes) {\n\t\tMethod method = ReflectionUtils.findMethod(target, name, parameterTypes);\n\t\tassertThat(method).isNotNull();\n\t\treturn method;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/HttpClientSettingsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ssl.SslBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpClientSettings}.\n *\n * @author Phillip Webb\n */\nclass HttpClientSettingsTests {\n\n\tprivate static final Duration ONE_SECOND = Duration.ofSeconds(1);\n\n\tprivate static final Duration TWO_SECONDS = Duration.ofSeconds(2);\n\n\t@Test\n\tvoid defaults() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults();\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isNull();\n\t}\n\n\t@Test\n\tvoid createWithNulls() {\n\t\tHttpClientSettings settings = new HttpClientSettings(null, null, null, null, null);\n\t\tassertThat(settings.cookieHandling()).isNull();\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isNull();\n\t}\n\n\t@Test\n\tvoid withConnectTimeoutReturnsInstanceWithUpdatedConnectionTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(ONE_SECOND);\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isEqualTo(ONE_SECOND);\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isNull();\n\t}\n\n\t@Test\n\tvoid withReadTimeoutReturnsInstanceWithUpdatedReadTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(ONE_SECOND);\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isEqualTo(ONE_SECOND);\n\t\tassertThat(settings.sslBundle()).isNull();\n\t}\n\n\t@Test\n\tvoid withSslBundleReturnsInstanceWithUpdatedSslBundle() {\n\t\tSslBundle sslBundle = mock(SslBundle.class);\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withSslBundle(sslBundle);\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isSameAs(sslBundle);\n\t}\n\n\t@Test\n\tvoid withCookieHandlingReturnsInstanceWithUpdatedCookieHandling() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.DISABLE);\n\t\tassertThat(settings.cookieHandling()).isEqualTo(HttpCookieHandling.DISABLE);\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isNull();\n\t}\n\n\t@Test\n\tvoid withRedirectsReturnsInstanceWithUpdatedRedirect() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\tassertThat(settings.redirects()).isEqualTo(HttpRedirects.DONT_FOLLOW);\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isNull();\n\t}\n\n\t@Test\n\tvoid orElseReturnsNewInstanceWithUpdatedValues() {\n\t\tSslBundle sslBundle = mock(SslBundle.class);\n\t\tHttpClientSettings settings = new HttpClientSettings(null, null, ONE_SECOND, null, null)\n\t\t\t.orElse(new HttpClientSettings(HttpCookieHandling.ENABLE, HttpRedirects.FOLLOW_WHEN_POSSIBLE, TWO_SECONDS,\n\t\t\t\t\tTWO_SECONDS, sslBundle));\n\t\tassertThat(settings.cookieHandling()).isEqualTo(HttpCookieHandling.ENABLE);\n\t\tassertThat(settings.redirects()).isEqualTo(HttpRedirects.FOLLOW_WHEN_POSSIBLE);\n\t\tassertThat(settings.connectTimeout()).isEqualTo(ONE_SECOND);\n\t\tassertThat(settings.readTimeout()).isEqualTo(TWO_SECONDS);\n\t\tassertThat(settings.sslBundle()).isEqualTo(sslBundle);\n\t}\n\n\t@Test\n\tvoid ofSslBundleCreatesNewSettings() {\n\t\tSslBundle sslBundle = mock(SslBundle.class);\n\t\tHttpClientSettings settings = HttpClientSettings.ofSslBundle(sslBundle);\n\t\tassertThat(settings.redirects()).isNull();\n\t\tassertThat(settings.connectTimeout()).isNull();\n\t\tassertThat(settings.readTimeout()).isNull();\n\t\tassertThat(settings.sslBundle()).isSameAs(sslBundle);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/HttpComponentsClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.hc.client5.http.HttpRoute;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.cookie.StandardCookieSpec;\nimport org.apache.hc.client5.http.impl.classic.CloseableHttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;\nimport org.apache.hc.core5.function.Resolver;\nimport org.apache.hc.core5.http.io.SocketConfig;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.boot.http.client.HttpComponentsHttpClientBuilder.TlsSocketStrategyFactory;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpComponentsClientHttpRequestFactoryBuilder} and\n * {@link HttpComponentsHttpClientBuilder}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass HttpComponentsClientHttpRequestFactoryBuilderTests\n\t\textends AbstractClientHttpRequestFactoryBuilderTests<HttpComponentsClientHttpRequestFactory> {\n\n\tHttpComponentsClientHttpRequestFactoryBuilderTests() {\n\t\tsuper(HttpComponentsClientHttpRequestFactory.class, ClientHttpRequestFactoryBuilder.httpComponents());\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tTestCustomizer<HttpClientBuilder> httpClientCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClientBuilder> httpClientCustomizer2 = new TestCustomizer<>();\n\t\tTestCustomizer<PoolingHttpClientConnectionManagerBuilder> connectionManagerCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<SocketConfig.Builder> socketConfigCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<SocketConfig.Builder> socketConfigCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<RequestConfig.Builder> defaultRequestConfigCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<RequestConfig.Builder> defaultRequestConfigCustomizer1 = new TestCustomizer<>();\n\t\tClientHttpRequestFactoryBuilder.httpComponents()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.withConnectionManagerCustomizer(connectionManagerCustomizer)\n\t\t\t.withSocketConfigCustomizer(socketConfigCustomizer)\n\t\t\t.withSocketConfigCustomizer(socketConfigCustomizer1)\n\t\t\t.withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer)\n\t\t\t.withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer1)\n\t\t\t.build();\n\t\thttpClientCustomizer1.assertCalled();\n\t\thttpClientCustomizer2.assertCalled();\n\t\tconnectionManagerCustomizer.assertCalled();\n\t\tsocketConfigCustomizer.assertCalled();\n\t\tsocketConfigCustomizer1.assertCalled();\n\t\tdefaultRequestConfigCustomizer.assertCalled();\n\t\tdefaultRequestConfigCustomizer1.assertCalled();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid withTlsSocketStrategyFactory() {\n\t\tHttpClientSettings settings = HttpClientSettings.ofSslBundle(sslBundle());\n\t\tList<SslBundle> bundles = new ArrayList<>();\n\t\tTlsSocketStrategyFactory tlsSocketStrategyFactory = (bundle) -> {\n\t\t\tbundles.add(bundle);\n\t\t\treturn (socket, target, port, attachment, context) -> null;\n\t\t};\n\t\tClientHttpRequestFactoryBuilder.httpComponents()\n\t\t\t.withTlsSocketStrategyFactory(tlsSocketStrategyFactory)\n\t\t\t.build(settings);\n\t\tassertThat(bundles).contains(settings.sslBundle());\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tTestCustomizer<HttpClientBuilder> customizer = new TestCustomizer<>();\n\t\tClientHttpRequestFactoryBuilder.httpComponents()\n\t\t\t.with((builder) -> builder.withHttpClientCustomizer(customizer))\n\t\t\t.build();\n\t\tcustomizer.assertCalled();\n\t}\n\n\t@Test\n\tvoid defaultCookieHandling() {\n\t\tHttpComponentsClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.httpComponents()\n\t\t\t.build(HttpClientSettings.defaults());\n\t\tassertThat(factory).extracting(\"httpClient.defaultConfig.cookieSpec\").isNull();\n\t}\n\n\t@Test\n\tvoid cookieHandlingDisabled() {\n\t\tHttpComponentsClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.httpComponents()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.DISABLE));\n\t\tassertThat(factory).extracting(\"httpClient.defaultConfig.cookieSpec\").isEqualTo(StandardCookieSpec.IGNORE);\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(names = { \"ENABLE\", \"ENABLE_WHEN_POSSIBLE\" })\n\tvoid cookieHandlingEnabled(HttpCookieHandling cookieHandling) {\n\t\tHttpComponentsClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.httpComponents()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(cookieHandling));\n\t\tassertThat(factory).extracting(\"httpClient.defaultConfig.cookieSpec\").isEqualTo(StandardCookieSpec.STRICT);\n\t}\n\n\t@Override\n\tprotected long connectTimeout(HttpComponentsClientHttpRequestFactory requestFactory) {\n\t\treturn getConnectorConfig(requestFactory).getConnectTimeout().toMilliseconds();\n\t}\n\n\t@Override\n\tprotected long readTimeout(HttpComponentsClientHttpRequestFactory requestFactory) {\n\t\treturn getConnectorConfig(requestFactory).getSocketTimeout().toMilliseconds();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ConnectionConfig getConnectorConfig(HttpComponentsClientHttpRequestFactory requestFactory) {\n\t\tCloseableHttpClient httpClient = (CloseableHttpClient) ReflectionTestUtils.getField(requestFactory,\n\t\t\t\t\"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tObject manager = ReflectionTestUtils.getField(httpClient, \"connManager\");\n\t\tassertThat(manager).isNotNull();\n\t\tResolver<HttpRoute, ConnectionConfig> resolver = (Resolver<HttpRoute, ConnectionConfig>) ReflectionTestUtils\n\t\t\t.getField(manager, \"connectionConfigResolver\");\n\t\tassertThat(resolver).isNotNull();\n\t\treturn resolver.resolve(null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/JdkClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.net.http.HttpClient;\nimport java.time.Duration;\nimport java.util.concurrent.Executor;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JdkClientHttpRequestFactoryBuilder} and {@link JdkHttpClientBuilder}.\n *\n * @author Phillip Webb\n */\nclass JdkClientHttpRequestFactoryBuilderTests\n\t\textends AbstractClientHttpRequestFactoryBuilderTests<JdkClientHttpRequestFactory> {\n\n\tJdkClientHttpRequestFactoryBuilderTests() {\n\t\tsuper(JdkClientHttpRequestFactory.class, ClientHttpRequestFactoryBuilder.jdk());\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tTestCustomizer<HttpClient.Builder> httpClientCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClient.Builder> httpClientCustomizer2 = new TestCustomizer<>();\n\t\tClientHttpRequestFactoryBuilder.jdk()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.build();\n\t\thttpClientCustomizer1.assertCalled();\n\t\thttpClientCustomizer2.assertCalled();\n\t}\n\n\t@Test\n\tvoid withExecutor() {\n\t\tExecutor executor = new SimpleAsyncTaskExecutor();\n\t\tJdkClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jdk().withExecutor(executor).build();\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(factory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tassertThat(httpClient.executor()).containsSame(executor);\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tTestCustomizer<HttpClient.Builder> customizer = new TestCustomizer<>();\n\t\tClientHttpRequestFactoryBuilder.jdk().with((builder) -> builder.withHttpClientCustomizer(customizer)).build();\n\t\tcustomizer.assertCalled();\n\t}\n\n\t@Test\n\tvoid defaultCookieHandling() {\n\t\tJdkClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t.build(HttpClientSettings.defaults());\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(factory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tassertThat(httpClient.cookieHandler()).isEmpty();\n\t}\n\n\t@Test\n\tvoid cookieHandlingDisabled() {\n\t\tJdkClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.DISABLE));\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(factory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tassertThat(httpClient.cookieHandler()).isEmpty();\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(names = { \"ENABLE\", \"ENABLE_WHEN_POSSIBLE\" })\n\tvoid cookieHandlingEnabled(HttpCookieHandling cookieHandling) {\n\t\tJdkClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(cookieHandling));\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(factory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tassertThat(httpClient.cookieHandler()).isNotEmpty();\n\t}\n\n\t@Override\n\tprotected long connectTimeout(JdkClientHttpRequestFactory requestFactory) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(requestFactory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn httpClient.connectTimeout().get().toMillis();\n\t}\n\n\t@Override\n\tprotected long readTimeout(JdkClientHttpRequestFactory requestFactory) {\n\t\tDuration readTimeout = (Duration) ReflectionTestUtils.getField(requestFactory, \"readTimeout\");\n\t\tassertThat(readTimeout).isNotNull();\n\t\treturn readTimeout.toMillis();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/JettyClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.eclipse.jetty.client.HttpClientTransport;\nimport org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;\nimport org.eclipse.jetty.http.HttpCookieStore;\nimport org.eclipse.jetty.io.ClientConnector;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JettyClientHttpRequestFactoryBuilder} and\n * {@link JettyHttpClientBuilder}.\n *\n * @author Phillip Webb\n */\nclass JettyClientHttpRequestFactoryBuilderTests\n\t\textends AbstractClientHttpRequestFactoryBuilderTests<JettyClientHttpRequestFactory> {\n\n\tJettyClientHttpRequestFactoryBuilderTests() {\n\t\tsuper(JettyClientHttpRequestFactory.class, ClientHttpRequestFactoryBuilder.jetty());\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tTestCustomizer<HttpClient> httpClientCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClient> httpClientCustomizer2 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClientTransport> httpClientTransportCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<ClientConnector> clientConnectorCustomizerCustomizer = new TestCustomizer<>();\n\t\tClientHttpRequestFactoryBuilder.jetty()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.withHttpClientTransportCustomizer(httpClientTransportCustomizer)\n\t\t\t.withClientConnectorCustomizerCustomizer(clientConnectorCustomizerCustomizer)\n\t\t\t.build();\n\t\thttpClientCustomizer1.assertCalled();\n\t\thttpClientCustomizer2.assertCalled();\n\t\thttpClientTransportCustomizer.assertCalled();\n\t\tclientConnectorCustomizerCustomizer.assertCalled();\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tTestCustomizer<HttpClient> customizer = new TestCustomizer<>();\n\t\tClientHttpRequestFactoryBuilder.jetty().with((builder) -> builder.withHttpClientCustomizer(customizer)).build();\n\t\tcustomizer.assertCalled();\n\t}\n\n\t@Test\n\tvoid withHttpClientTransportFactory() {\n\t\tJettyClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jetty()\n\t\t\t.withHttpClientTransportFactory(TestHttpClientTransport::new)\n\t\t\t.build();\n\t\tassertThat(factory).extracting(\"httpClient\")\n\t\t\t.extracting(\"transport\")\n\t\t\t.isInstanceOf(TestHttpClientTransport.class);\n\t}\n\n\t@Test\n\tvoid defaultCookieHandling() {\n\t\tJettyClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jetty()\n\t\t\t.build(HttpClientSettings.defaults());\n\t\tassertThat(factory).extracting(\"httpClient.cookieStore\").isNull();\n\t}\n\n\t@Test\n\tvoid cookieHandlingDisabled() {\n\t\tJettyClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jetty()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.DISABLE));\n\t\tassertThat(factory).extracting(\"httpClient.cookieStore\").isInstanceOf(HttpCookieStore.Empty.class);\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(names = { \"ENABLE\", \"ENABLE_WHEN_POSSIBLE\" })\n\tvoid cookieHandlingEnabled(HttpCookieHandling cookieHandling) {\n\t\tJettyClientHttpRequestFactory factory = ClientHttpRequestFactoryBuilder.jetty()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(cookieHandling));\n\t\tassertThat(factory).extracting(\"httpClient.cookieStore\").isInstanceOf(HttpCookieStore.Default.class);\n\t}\n\n\t@Override\n\tprotected long connectTimeout(JettyClientHttpRequestFactory requestFactory) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(requestFactory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn httpClient.getConnectTimeout();\n\t}\n\n\t@Override\n\tprotected long readTimeout(JettyClientHttpRequestFactory requestFactory) {\n\t\tObject field = ReflectionTestUtils.getField(requestFactory, \"readTimeout\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (long) field;\n\t}\n\n\tstatic class TestHttpClientTransport extends HttpClientTransportOverHTTP {\n\n\t\tTestHttpClientTransport(ClientConnector connector) {\n\t\t\tsuper(connector);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/ReactorClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport io.netty.channel.ChannelOption;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport reactor.netty.http.client.HttpClient;\n\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ReactorClientHttpRequestFactoryBuilder} and\n * {@link ReactorHttpClientBuilder}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ReactorClientHttpRequestFactoryBuilderTests\n\t\textends AbstractClientHttpRequestFactoryBuilderTests<ReactorClientHttpRequestFactory> {\n\n\tReactorClientHttpRequestFactoryBuilderTests() {\n\t\tsuper(ReactorClientHttpRequestFactory.class, ClientHttpRequestFactoryBuilder.reactor());\n\t}\n\n\t@Test\n\tvoid withHttpClientFactory() {\n\t\tboolean[] called = new boolean[1];\n\t\tSupplier<HttpClient> httpClientFactory = () -> {\n\t\t\tcalled[0] = true;\n\t\t\treturn HttpClient.create();\n\t\t};\n\t\tClientHttpRequestFactoryBuilder.reactor().withHttpClientFactory(httpClientFactory).build();\n\t\tassertThat(called).containsExactly(true);\n\t}\n\n\t@Test\n\tvoid withReactorResourceFactory() {\n\t\tReactorResourceFactory resourceFactory = spy(new ReactorResourceFactory());\n\t\tClientHttpRequestFactoryBuilder.reactor().withReactorResourceFactory(resourceFactory).build();\n\t\tthen(resourceFactory).should().getConnectionProvider();\n\t\tthen(resourceFactory).should().getLoopResources();\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tList<HttpClient> httpClients = new ArrayList<>();\n\t\tUnaryOperator<HttpClient> httpClientCustomizer1 = (httpClient) -> {\n\t\t\thttpClients.add(httpClient);\n\t\t\treturn httpClient;\n\t\t};\n\t\tUnaryOperator<HttpClient> httpClientCustomizer2 = (httpClient) -> {\n\t\t\thttpClients.add(httpClient);\n\t\t\treturn httpClient;\n\t\t};\n\t\tClientHttpRequestFactoryBuilder.reactor()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.build();\n\t\tassertThat(httpClients).hasSize(2);\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tboolean[] called = new boolean[1];\n\t\tSupplier<HttpClient> httpClientFactory = () -> {\n\t\t\tcalled[0] = true;\n\t\t\treturn HttpClient.create();\n\t\t};\n\t\tClientHttpRequestFactoryBuilder.reactor()\n\t\t\t.with((builder) -> builder.withHttpClientFactory(httpClientFactory))\n\t\t\t.build();\n\t\tassertThat(called).containsExactly(true);\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(names = { \"DISABLE\", \"ENABLE_WHEN_POSSIBLE\" })\n\tvoid doesNotThrowWhenCookieHandlingNotEnabled(HttpCookieHandling cookieHandling) {\n\t\tassertThatNoException().isThrownBy(() -> ClientHttpRequestFactoryBuilder.reactor()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(cookieHandling)));\n\t}\n\n\t@Test\n\tvoid throwsWhenCookieHandlingEnabled() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ClientHttpRequestFactoryBuilder.reactor()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.ENABLE)));\n\t}\n\n\t@Override\n\tprotected long connectTimeout(ReactorClientHttpRequestFactory requestFactory) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(requestFactory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tObject connectTimeout = httpClient.configuration().options().get(ChannelOption.CONNECT_TIMEOUT_MILLIS);\n\t\tassertThat(connectTimeout).isNotNull();\n\t\treturn (int) connectTimeout;\n\t}\n\n\t@Override\n\tprotected long readTimeout(ReactorClientHttpRequestFactory requestFactory) {\n\t\tDuration readTimeout = (Duration) ReflectionTestUtils.getField(requestFactory, \"readTimeout\");\n\t\tassertThat(readTimeout).isNotNull();\n\t\treturn readTimeout.toMillis();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/ReflectiveComponentsClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.net.URI;\nimport java.time.Duration;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.client.BufferingClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ReflectiveComponentsClientHttpRequestFactoryBuilder}.\n *\n * @author Phillip Webb\n */\nclass ReflectiveComponentsClientHttpRequestFactoryBuilderTests\n\t\textends AbstractClientHttpRequestFactoryBuilderTests<ClientHttpRequestFactory> {\n\n\tReflectiveComponentsClientHttpRequestFactoryBuilderTests() {\n\t\tsuper(ClientHttpRequestFactory.class, ClientHttpRequestFactoryBuilder.of(JettyClientHttpRequestFactory::new));\n\t}\n\n\t@Override\n\tvoid connectWithSslBundle(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.ofSslBundle(sslBundle());\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofTestRequestFactory().build(settings))\n\t\t\t.withMessage(\"Unable to set SSL bundler using reflection\");\n\t}\n\n\t@Override\n\tvoid redirectFollow(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.FOLLOW);\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofTestRequestFactory().build(settings))\n\t\t\t.withMessage(\"Unable to set redirect follow using reflection\");\n\t}\n\n\t@Override\n\tvoid redirectDontFollow(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofTestRequestFactory().build(settings))\n\t\t\t.withMessage(\"Unable to set redirect follow using reflection\");\n\t}\n\n\t@Test\n\tvoid cookieHandlingEnable() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.ENABLE);\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofTestRequestFactory().build(settings))\n\t\t\t.withMessage(\"Unable to set HTTP cookie handling using reflection\");\n\t}\n\n\t@Test\n\tvoid cookieHandlingDisable() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.DISABLE);\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofTestRequestFactory().build(settings))\n\t\t\t.withMessage(\"Unable to set HTTP cookie handling using reflection\");\n\t}\n\n\t@Override\n\tvoid connectWithSslBundleAndOptionsMismatch(String httpMethod) throws Exception {\n\t\tassertThatIllegalStateException().isThrownBy(() -> super.connectWithSslBundleAndOptionsMismatch(httpMethod))\n\t\t\t.withMessage(\"Unable to set SSL bundler using reflection\");\n\t}\n\n\t@Test\n\tvoid buildWithClassCreatesFactory() {\n\t\tassertThat(ofTestRequestFactory().build()).isInstanceOf(TestClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenHasConnectTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofSeconds(60));\n\t\tTestClientHttpRequestFactory requestFactory = ofTestRequestFactory().build(settings);\n\t\tassertThat(requestFactory.connectTimeout).isEqualTo(Duration.ofSeconds(60).toMillis());\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenHasReadTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(Duration.ofSeconds(90));\n\t\tTestClientHttpRequestFactory requestFactory = ofTestRequestFactory().build(settings);\n\t\tassertThat(requestFactory.readTimeout).isEqualTo(Duration.ofSeconds(90).toMillis());\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenUnconfigurableTypeWithConnectTimeoutThrowsException() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofSeconds(60));\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofUnconfigurableRequestFactory().build(settings))\n\t\t\t.withMessageContaining(\"suitable setConnectTimeout method\");\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenUnconfigurableTypeWithReadTimeoutThrowsException() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(Duration.ofSeconds(60));\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofUnconfigurableRequestFactory().build(settings))\n\t\t\t.withMessageContaining(\"suitable setReadTimeout method\");\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenDeprecatedMethodsTypeWithConnectTimeoutThrowsException() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofSeconds(60));\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofDeprecatedMethodsRequestFactory().build(settings))\n\t\t\t.withMessageContaining(\"setConnectTimeout method marked as deprecated\");\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenDeprecatedMethodsTypeWithReadTimeoutThrowsException() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(Duration.ofSeconds(60));\n\t\tassertThatIllegalStateException().isThrownBy(() -> ofDeprecatedMethodsRequestFactory().build(settings))\n\t\t\t.withMessageContaining(\"setReadTimeout method marked as deprecated\");\n\t}\n\n\t@Test\n\tvoid buildWithSupplierWhenWrappedRequestFactoryTypeWithConnectTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofMillis(1234));\n\t\tSimpleClientHttpRequestFactory wrappedRequestFactory = new SimpleClientHttpRequestFactory();\n\t\tClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder\n\t\t\t.of(() -> new BufferingClientHttpRequestFactory(wrappedRequestFactory))\n\t\t\t.build(settings);\n\t\tassertThat(requestFactory).extracting(\"requestFactory\").isSameAs(wrappedRequestFactory);\n\t\tassertThat(wrappedRequestFactory).hasFieldOrPropertyWithValue(\"connectTimeout\", 1234);\n\t}\n\n\t@Test\n\tvoid buildWithSupplierWhenWrappedRequestFactoryTypeWithReadTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(Duration.ofMillis(1234));\n\t\tSimpleClientHttpRequestFactory wrappedRequestFactory = new SimpleClientHttpRequestFactory();\n\t\tClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder\n\t\t\t.of(() -> new BufferingClientHttpRequestFactory(wrappedRequestFactory))\n\t\t\t.build(settings);\n\t\tassertThat(requestFactory).extracting(\"requestFactory\").isSameAs(wrappedRequestFactory);\n\t\tassertThat(wrappedRequestFactory).hasFieldOrPropertyWithValue(\"readTimeout\", 1234);\n\t}\n\n\t@Test\n\tvoid buildWithClassWhenHasMultipleTimeoutSettersFavorsDurationMethods() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults()\n\t\t\t.withConnectTimeout(Duration.ofSeconds(1))\n\t\t\t.withReadTimeout(Duration.ofSeconds(2));\n\t\tIntAndDurationTimeoutsClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder\n\t\t\t.of(IntAndDurationTimeoutsClientHttpRequestFactory.class)\n\t\t\t.build(settings);\n\t\tassertThat((requestFactory).connectTimeout).isZero();\n\t\tassertThat((requestFactory).readTimeout).isZero();\n\t\tassertThat((requestFactory).connectTimeoutDuration).isEqualTo(Duration.ofSeconds(1));\n\t\tassertThat((requestFactory).readTimeoutDuration).isEqualTo(Duration.ofSeconds(2));\n\t}\n\n\tprivate ClientHttpRequestFactoryBuilder<TestClientHttpRequestFactory> ofTestRequestFactory() {\n\t\treturn ClientHttpRequestFactoryBuilder.of(TestClientHttpRequestFactory.class);\n\t}\n\n\tprivate ClientHttpRequestFactoryBuilder<UnconfigurableClientHttpRequestFactory> ofUnconfigurableRequestFactory() {\n\t\treturn ClientHttpRequestFactoryBuilder.of(UnconfigurableClientHttpRequestFactory.class);\n\t}\n\n\tprivate ClientHttpRequestFactoryBuilder<DeprecatedMethodsClientHttpRequestFactory> ofDeprecatedMethodsRequestFactory() {\n\t\treturn ClientHttpRequestFactoryBuilder.of(DeprecatedMethodsClientHttpRequestFactory.class);\n\t}\n\n\t@Override\n\tprotected long connectTimeout(ClientHttpRequestFactory requestFactory) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(requestFactory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn httpClient.getConnectTimeout();\n\t}\n\n\t@Override\n\tprotected long readTimeout(ClientHttpRequestFactory requestFactory) {\n\t\tObject field = ReflectionTestUtils.getField(requestFactory, \"readTimeout\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (long) field;\n\t}\n\n\tpublic static class TestClientHttpRequestFactory implements ClientHttpRequestFactory {\n\n\t\tprivate int connectTimeout;\n\n\t\tprivate int readTimeout;\n\n\t\t@Override\n\t\tpublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\tpublic void setConnectTimeout(int timeout) {\n\t\t\tthis.connectTimeout = timeout;\n\t\t}\n\n\t\tpublic void setReadTimeout(int timeout) {\n\t\t\tthis.readTimeout = timeout;\n\t\t}\n\n\t}\n\n\tpublic static class UnconfigurableClientHttpRequestFactory implements ClientHttpRequestFactory {\n\n\t\t@Override\n\t\tpublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n\tpublic static class DeprecatedMethodsClientHttpRequestFactory implements ClientHttpRequestFactory {\n\n\t\t@Override\n\t\tpublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Deprecated(since = \"3.0.0\", forRemoval = false)\n\t\tpublic void setConnectTimeout(int timeout) {\n\t\t}\n\n\t\t@Deprecated(since = \"3.0.0\", forRemoval = false)\n\t\tpublic void setReadTimeout(int timeout) {\n\t\t}\n\n\t\t@Deprecated(since = \"3.0.0\", forRemoval = false)\n\t\tpublic void setBufferRequestBody(boolean bufferRequestBody) {\n\t\t}\n\n\t}\n\n\tpublic static class IntAndDurationTimeoutsClientHttpRequestFactory implements ClientHttpRequestFactory {\n\n\t\tprivate int readTimeout;\n\n\t\tprivate int connectTimeout;\n\n\t\tprivate @Nullable Duration readTimeoutDuration;\n\n\t\tprivate @Nullable Duration connectTimeoutDuration;\n\n\t\t@Override\n\t\tpublic ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\tpublic void setConnectTimeout(int timeout) {\n\t\t\tthis.connectTimeout = timeout;\n\t\t}\n\n\t\tpublic void setReadTimeout(int timeout) {\n\t\t\tthis.readTimeout = timeout;\n\t\t}\n\n\t\tpublic void setConnectTimeout(@Nullable Duration timeout) {\n\t\t\tthis.connectTimeoutDuration = timeout;\n\t\t}\n\n\t\tpublic void setReadTimeout(@Nullable Duration timeout) {\n\t\t\tthis.readTimeoutDuration = timeout;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/SimpleClientHttpRequestFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SimpleClientHttpRequestFactoryBuilder}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass SimpleClientHttpRequestFactoryBuilderTests\n\t\textends AbstractClientHttpRequestFactoryBuilderTests<SimpleClientHttpRequestFactory> {\n\n\tSimpleClientHttpRequestFactoryBuilderTests() {\n\t\tsuper(SimpleClientHttpRequestFactory.class, ClientHttpRequestFactoryBuilder.simple());\n\t}\n\n\t@Override\n\tprotected long connectTimeout(SimpleClientHttpRequestFactory requestFactory) {\n\t\tObject field = ReflectionTestUtils.getField(requestFactory, \"connectTimeout\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (int) field;\n\t}\n\n\t@Override\n\tprotected long readTimeout(SimpleClientHttpRequestFactory requestFactory) {\n\t\tObject field = ReflectionTestUtils.getField(requestFactory, \"readTimeout\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (int) field;\n\t}\n\n\t@Override\n\tvoid connectWithSslBundleAndOptionsMismatch(String httpMethod) throws Exception {\n\t\tassertThatIllegalStateException().isThrownBy(() -> super.connectWithSslBundleAndOptionsMismatch(httpMethod))\n\t\t\t.withMessage(\"SSL Options cannot be specified with Java connections\");\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"DELETE\" })\n\t@Override\n\tvoid redirectDefault(String httpMethod) throws Exception {\n\t\tsuper.redirectDefault(httpMethod);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"DELETE\" })\n\t@Override\n\tvoid redirectFollow(String httpMethod) throws Exception {\n\t\tsuper.redirectFollow(httpMethod);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"DELETE\" })\n\t@Override\n\tvoid redirectDontFollow(String httpMethod) throws Exception {\n\t\tsuper.redirectDontFollow(httpMethod);\n\t}\n\n\t@Test\n\tvoid throwsWhenCookieHandlingEnabled() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ClientHttpRequestFactoryBuilder.simple()\n\t\t\t.build(HttpClientSettings.defaults().withCookieHandling(HttpCookieHandling.ENABLE)));\n\t}\n\n\t@Override\n\tprotected HttpStatus getExpectedRedirect(HttpMethod httpMethod) {\n\t\treturn (httpMethod != HttpMethod.GET) ? HttpStatus.FOUND : HttpStatus.OK;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/TestCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client;\n\nimport java.util.function.Consumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test customizer that can assert that it has been called.\n *\n * @param <T> type being customized\n * @author Phillip Webb\n */\nclass TestCustomizer<T> implements Consumer<T> {\n\n\tprivate boolean called;\n\n\t@Override\n\tpublic void accept(T t) {\n\t\tthis.called = true;\n\t}\n\n\tvoid assertCalled() {\n\t\tassertThat(this.called).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/HttpClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpClientAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass HttpClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpClientAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid createsDefaultHttpClientSettings() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(HttpClientSettings.class))\n\t\t\t.isEqualTo(HttpClientSettings.defaults()));\n\t}\n\n\t@Test\n\tvoid createsHttpClientSettingsFromProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.clients.redirects=dont-follow\", \"spring.http.clients.connect-timeout=1s\",\n\t\t\t\t\t\"spring.http.clients.read-timeout=2s\")\n\t\t\t.run((context) -> assertThat(context.getBean(HttpClientSettings.class)).isEqualTo(new HttpClientSettings(\n\t\t\t\t\tnull, HttpRedirects.DONT_FOLLOW, Duration.ofSeconds(1), Duration.ofSeconds(2), null)));\n\t}\n\n\t@Test\n\tvoid doesNotReplaceUserProvidedHttpClientSettings() {\n\t\tthis.contextRunner.withUserConfiguration(TestHttpClientConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(HttpClientSettings.class))\n\t\t\t\t.isEqualTo(new HttpClientSettings(null, null, Duration.ofSeconds(1), Duration.ofSeconds(2), null)));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestHttpClientConfiguration {\n\n\t\t@Bean\n\t\tHttpClientSettings httpClientSettings() {\n\t\t\treturn HttpClientSettings.defaults().withTimeouts(Duration.ofSeconds(1), Duration.ofSeconds(2));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/HttpClientSettingsPropertyMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpCookieHandling;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpClientSettingsPropertyMapper}.\n *\n * @author Steve Armstrong\n */\nclass HttpClientSettingsPropertyMapperTests {\n\n\t@Test\n\tvoid mapWhenPropertiesIsNullAndBaseSettingsIsNullReturnsDefaults() {\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, null);\n\t\tHttpClientSettings result = mapper.map(null);\n\t\tassertThat(result).isEqualTo(HttpClientSettings.defaults());\n\t}\n\n\t@Test\n\tvoid mapWhenPropertiesIsNullReturnsBaseSettings() {\n\t\tHttpClientSettings baseSettings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofSeconds(10));\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, baseSettings);\n\t\tHttpClientSettings result = mapper.map(null);\n\t\tassertThat(result).isEqualTo(baseSettings);\n\t}\n\n\t@Test\n\tvoid mapMapsRedirects() {\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, null);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.setRedirects(HttpRedirects.DONT_FOLLOW);\n\t\tHttpClientSettings result = mapper.map(properties);\n\t\tassertThat(result.redirects()).isEqualTo(HttpRedirects.DONT_FOLLOW);\n\t}\n\n\t@Test\n\tvoid mapMapsConnectTimeout() {\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, null);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.setConnectTimeout(Duration.ofSeconds(5));\n\t\tHttpClientSettings result = mapper.map(properties);\n\t\tassertThat(result.connectTimeout()).isEqualTo(Duration.ofSeconds(5));\n\t}\n\n\t@Test\n\tvoid mapMapsReadTimeout() {\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, null);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.setReadTimeout(Duration.ofSeconds(30));\n\t\tHttpClientSettings result = mapper.map(properties);\n\t\tassertThat(result.readTimeout()).isEqualTo(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid mapMapsCookieHandling() {\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, null);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.setCookieHandling(HttpCookieHandling.DISABLE);\n\t\tHttpClientSettings result = mapper.map(properties);\n\t\tassertThat(result.cookieHandling()).isEqualTo(HttpCookieHandling.DISABLE);\n\t}\n\n\t@Test\n\tvoid mapMapsSslBundle() {\n\t\tSslBundle sslBundle = mock(SslBundle.class);\n\t\tSslBundles sslBundles = mock(SslBundles.class);\n\t\tgiven(sslBundles.getBundle(\"test-bundle\")).willReturn(sslBundle);\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(sslBundles, null);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.getSsl().setBundle(\"test-bundle\");\n\t\tHttpClientSettings result = mapper.map(properties);\n\t\tassertThat(result.sslBundle()).isSameAs(sslBundle);\n\t}\n\n\t@Test\n\tvoid mapUsesBaseSettingsForMissingProperties() {\n\t\tHttpClientSettings baseSettings = new HttpClientSettings(null, HttpRedirects.FOLLOW_WHEN_POSSIBLE,\n\t\t\t\tDuration.ofSeconds(15), Duration.ofSeconds(25), null);\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, baseSettings);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.setConnectTimeout(Duration.ofSeconds(5));\n\t\tHttpClientSettings result = mapper.map(properties);\n\t\tassertThat(result.redirects()).isEqualTo(HttpRedirects.FOLLOW_WHEN_POSSIBLE);\n\t\tassertThat(result.connectTimeout()).isEqualTo(Duration.ofSeconds(5));\n\t\tassertThat(result.readTimeout()).isEqualTo(Duration.ofSeconds(25));\n\t}\n\n\t@Test\n\tvoid mapWhenSslBundleRequestedButSslBundlesIsNullThrowsException() {\n\t\tHttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(null, null);\n\t\tTestHttpClientSettingsProperties properties = new TestHttpClientSettingsProperties();\n\t\tproperties.getSsl().setBundle(\"test-bundle\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> mapper.map(properties))\n\t\t\t.withMessage(\"No 'sslBundles' available\");\n\t}\n\n\tstatic class TestHttpClientSettingsProperties extends HttpClientSettingsProperties {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/PropertiesApiVersionInserterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.autoconfigure.ApiversionProperties.Insert;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.client.ApiVersionInserter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link PropertiesApiVersionInserter}.\n *\n * @author Phillip Webb\n */\nclass PropertiesApiVersionInserterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getWhenPropertiesIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> PropertiesApiVersionInserter.get(null))\n\t\t\t.withMessage(\"'properties' must not be null\");\n\t}\n\n\t@Test\n\tvoid getReturnsInserterBasedOnProperties() throws Exception {\n\t\tInsert properties = new ApiversionProperties().getInsert();\n\t\tproperties.setHeader(\"x-test\");\n\t\tproperties.setQueryParameter(\"v\");\n\t\tproperties.setPathSegment(1);\n\t\tproperties.setMediaTypeParameter(\"mtp\");\n\t\tApiVersionInserter inserter = PropertiesApiVersionInserter.get(properties);\n\t\tURI uri = new URI(\"https://example.com/foo/bar\");\n\t\tassertThat(inserter.insertVersion(\"123\", uri)).hasToString(\"https://example.com/foo/123/bar?v=123\");\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setContentType(MediaType.APPLICATION_JSON);\n\t\tinserter.insertVersion(\"123\", headers);\n\t\tassertThat(headers.get(\"x-test\")).containsExactly(\"123\");\n\t\tMediaType contentType = headers.getContentType();\n\t\tassertThat(contentType).isNotNull();\n\t\tassertThat(contentType.getParameters()).containsEntry(\"mtp\", \"123\");\n\t}\n\n\t@Test\n\tvoid getWhenNoPropertiesReturnsEmpty() {\n\t\tInsert properties = new ApiversionProperties().getInsert();\n\t\tApiVersionInserter inserter = PropertiesApiVersionInserter.get(properties);\n\t\tassertThat(inserter).isEqualTo(PropertiesApiVersionInserter.EMPTY);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/imperative/ImperativeHttpClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.imperative;\n\nimport java.net.http.HttpClient;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.JettyClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.ReactorClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.autoconfigure.ClientHttpRequestFactoryBuilderCustomizer;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImperativeHttpClientAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass ImperativeHttpClientAutoConfigurationTests {\n\n\tprivate static final AutoConfigurations autoConfigurations = AutoConfigurations\n\t\t.of(ImperativeHttpClientAutoConfiguration.class, HttpClientAutoConfiguration.class, SslAutoConfiguration.class);\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(autoConfigurations);\n\n\t@Test\n\tvoid configuresDetectedClientHttpRequestFactoryBuilder() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ClientHttpRequestFactoryBuilder.class));\n\t}\n\n\t@Test\n\tvoid configuresDefinedClientHttpRequestFactoryBuilder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.clients.imperative.factory=simple\")\n\t\t\t.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))\n\t\t\t\t.isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class));\n\t}\n\n\t@Test\n\tvoid configuresClientHttpRequestFactorySettings() {\n\t\tthis.contextRunner.withPropertyValues(sslPropertyValues().toArray(String[]::new))\n\t\t\t.withPropertyValues(\"spring.http.clients.redirects=dont-follow\", \"spring.http.clients.connect-timeout=10s\",\n\t\t\t\t\t\"spring.http.clients.read-timeout=20s\", \"spring.http.clients.ssl.bundle=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tHttpClientSettings settings = context.getBean(HttpClientSettings.class);\n\t\t\t\tassertThat(settings.redirects()).isEqualTo(HttpRedirects.DONT_FOLLOW);\n\t\t\t\tassertThat(settings.connectTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t\t\t\tassertThat(settings.readTimeout()).isEqualTo(Duration.ofSeconds(20));\n\t\t\t\tSslBundle sslBundle = settings.sslBundle();\n\t\t\t\tassertThat(sslBundle).isNotNull();\n\t\t\t\tassertThat(sslBundle.getKey().getAlias()).isEqualTo(\"alias1\");\n\t\t\t});\n\t}\n\n\tprivate List<String> sslPropertyValues() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/autoconfigure/ssl/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.key.alias=alias1\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.type=PKCS12\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.private-key=\" + location + \"rsa-key.pem\");\n\t\treturn propertyValues;\n\t}\n\n\t@Test\n\tvoid whenHttpComponentsIsUnavailableThenJettyClientBeansAreDefined() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(org.apache.hc.client5.http.impl.classic.HttpClients.class))\n\t\t\t.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))\n\t\t\t\t.isExactlyInstanceOf(JettyClientHttpRequestFactoryBuilder.class));\n\t}\n\n\t@Test\n\tvoid whenHttpComponentsAndJettyAreUnavailableThenReactorClientBeansAreDefined() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(org.apache.hc.client5.http.impl.classic.HttpClients.class,\n\t\t\t\t\torg.eclipse.jetty.client.HttpClient.class))\n\t\t\t.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))\n\t\t\t\t.isExactlyInstanceOf(ReactorClientHttpRequestFactoryBuilder.class));\n\t}\n\n\t@Test\n\tvoid whenHttpComponentsAndJettyAndReactorAreUnavailableThenJdkClientBeansAreDefined() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(org.apache.hc.client5.http.impl.classic.HttpClients.class,\n\t\t\t\t\torg.eclipse.jetty.client.HttpClient.class, reactor.netty.http.client.HttpClient.class))\n\t\t\t.run((context) -> assertThat(context.getBean(ClientHttpRequestFactoryBuilder.class))\n\t\t\t\t.isExactlyInstanceOf(JdkClientHttpRequestFactoryBuilder.class));\n\t}\n\n\t@Test\n\tvoid whenReactiveWebApplicationBeansAreNotConfigured() {\n\t\tnew ReactiveWebApplicationContextRunner().withConfiguration(autoConfigurations)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ClientHttpRequestFactoryBuilder.class)\n\t\t\t\t.hasSingleBean(HttpClientSettings.class));\n\t}\n\n\t@Test\n\tvoid clientHttpRequestFactoryBuilderCustomizersAreApplied() {\n\t\tthis.contextRunner.withUserConfiguration(ClientHttpRequestFactoryBuilderCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tClientHttpRequestFactory factory = context.getBean(ClientHttpRequestFactoryBuilder.class).build();\n\t\t\t\tassertThat(factory).extracting(\"readTimeout\").isEqualTo(5L);\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenVirtualThreadsEnabledAndUsingJdkHttpClientUsesVirtualThreadExecutor() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.clients.imperative.factory=jdk\", \"spring.threads.virtual.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tClientHttpRequestFactory factory = context.getBean(ClientHttpRequestFactoryBuilder.class).build();\n\t\t\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(factory, \"httpClient\");\n\t\t\t\tassertThat(httpClient).isNotNull();\n\t\t\t\tassertThat(httpClient.executor()).containsInstanceOf(VirtualThreadTaskExecutor.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientHttpRequestFactoryBuilderCustomizersConfiguration {\n\n\t\t@Bean\n\t\tClientHttpRequestFactoryBuilderCustomizer<HttpComponentsClientHttpRequestFactoryBuilder> httpComponentsCustomizer() {\n\t\t\treturn (builder) -> builder.withCustomizer((factory) -> factory.setReadTimeout(5));\n\t\t}\n\n\t\t@Bean\n\t\tClientHttpRequestFactoryBuilderCustomizer<JettyClientHttpRequestFactoryBuilder> jettyCustomizer() {\n\t\t\treturn (builder) -> {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/imperative/ImperativeHttpClientsPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.imperative;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.JdkClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.JettyClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.ReactorClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.SimpleClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientsProperties.Factory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ImperativeHttpClientsProperties}.\n *\n * @author Phillip Webb\n */\nclass ImperativeHttpClientsPropertiesTests {\n\n\t@Nested\n\tclass FactoryTests {\n\n\t\t@Test\n\t\tvoid httpComponentsBuilder() {\n\t\t\tassertThat(Factory.HTTP_COMPONENTS.builder())\n\t\t\t\t.isInstanceOf(HttpComponentsClientHttpRequestFactoryBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid jettyBuilder() {\n\t\t\tassertThat(Factory.JETTY.builder()).isInstanceOf(JettyClientHttpRequestFactoryBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid reactorBuilder() {\n\t\t\tassertThat(Factory.REACTOR.builder()).isInstanceOf(ReactorClientHttpRequestFactoryBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid jdkBuilder() {\n\t\t\tassertThat(Factory.JDK.builder()).isInstanceOf(JdkClientHttpRequestFactoryBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid simpleBuilder() {\n\t\t\tassertThat(Factory.SIMPLE.builder()).isInstanceOf(SimpleClientHttpRequestFactoryBuilder.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/metrics/HttpClientMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.metrics;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpClientMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass HttpClientMetricsAutoConfigurationTests {\n\n\t@Test\n\tvoid afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(HttpClientMetricsAutoConfiguration.class, MetricsAutoConfiguration.class))\n\t\t\t.withBean(SimpleMeterRegistry.class)\n\t\t\t.withPropertyValues(\"management.metrics.web.client.max-uri-tags=2\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry meterRegistry = context.getBean(MeterRegistry.class);\n\t\t\t\tfor (int i = 0; i < 3; i++) {\n\t\t\t\t\tmeterRegistry.timer(\"http.client.requests\", \"uri\", \"/test/\" + i).record(Duration.ofSeconds(1));\n\t\t\t\t}\n\t\t\t\tassertThat(meterRegistry.find(\"http.client.requests\").timers()).hasSize(2);\n\t\t\t\tassertThat(output).contains(\"Reached the maximum number of 'uri' tags for 'http.client.requests'.\")\n\t\t\t\t\t.contains(\"Are you using 'uriVariables'?\");\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/reactive/ReactiveHttpClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClients;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport reactor.netty.http.client.HttpClient;\nimport reactor.netty.resources.LoopResources;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.JdkClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.JettyClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.ReactorClientHttpConnectorBuilder;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveHttpClientAutoConfiguration}\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass ReactiveHttpClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveHttpClientAutoConfiguration.class,\n\t\t\t\tHttpClientAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid whenReactorIsAvailableThenReactorBeansAreDefined() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tBeanDefinition connectorDefinition = context.getBeanFactory().getBeanDefinition(\"clientHttpConnector\");\n\t\t\tassertThat(connectorDefinition.isLazyInit()).isTrue();\n\t\t\tassertThat(context).hasSingleBean(ReactorResourceFactory.class);\n\t\t\tassertThat(context.getBean(ClientHttpConnectorBuilder.class))\n\t\t\t\t.isExactlyInstanceOf(ReactorClientHttpConnectorBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenReactorIsUnavailableThenJettyClientBeansAreDefined() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class)).run((context) -> {\n\t\t\tBeanDefinition connectorDefinition = context.getBeanFactory().getBeanDefinition(\"clientHttpConnector\");\n\t\t\tassertThat(connectorDefinition.isLazyInit()).isTrue();\n\t\t\tassertThat(context.getBean(ClientHttpConnectorBuilder.class))\n\t\t\t\t.isExactlyInstanceOf(JettyClientHttpConnectorBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenReactorAndHttpClientAreUnavailableThenJettyClientBeansAreDefined() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class, HttpAsyncClients.class))\n\t\t\t.run((context) -> {\n\t\t\t\tBeanDefinition connectorDefinition = context.getBeanFactory().getBeanDefinition(\"clientHttpConnector\");\n\t\t\t\tassertThat(connectorDefinition.isLazyInit()).isTrue();\n\t\t\t\tassertThat(context.getBean(ClientHttpConnectorBuilder.class))\n\t\t\t\t\t.isExactlyInstanceOf(JettyClientHttpConnectorBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenReactorAndHttpClientAndJettyAreUnavailableThenJdkClientBeansAreDefined() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(HttpClient.class, HttpAsyncClients.class,\n\t\t\t\t\torg.eclipse.jetty.client.HttpClient.class))\n\t\t\t.run((context) -> {\n\t\t\t\tBeanDefinition connectorDefinition = context.getBeanFactory().getBeanDefinition(\"clientHttpConnector\");\n\t\t\t\tassertThat(connectorDefinition.isLazyInit()).isTrue();\n\t\t\t\tassertThat(context.getBean(ClientHttpConnectorBuilder.class))\n\t\t\t\t\t.isExactlyInstanceOf(JdkClientHttpConnectorBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotOverrideCustomClientConnector() {\n\t\tthis.contextRunner.withUserConfiguration(CustomClientHttpConnectorConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ClientHttpConnector.class);\n\t\t\tassertThat(context).hasBean(\"customConnector\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomReactorResourceFactory() {\n\t\tthis.contextRunner.withUserConfiguration(CustomReactorResourceConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ClientHttpConnector.class);\n\t\t\tassertThat(context).hasSingleBean(ReactorResourceFactory.class);\n\t\t\tassertThat(context).hasBean(\"customReactorResourceFactory\");\n\t\t\tClientHttpConnector connector = context.getBean(ClientHttpConnector.class);\n\t\t\tassertThat(connector).extracting(\"httpClient.config.loopResources\")\n\t\t\t\t.isEqualTo(context.getBean(\"customReactorResourceFactory\", ReactorResourceFactory.class)\n\t\t\t\t\t.getLoopResources());\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseReactorResourceFactory() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ClientHttpConnector.class);\n\t\t\tassertThat(context).hasSingleBean(ReactorResourceFactory.class);\n\t\t\tClientHttpConnector connector = context.getBean(ClientHttpConnector.class);\n\t\t\tassertThat(connector).extracting(\"httpClient.config.loopResources\")\n\t\t\t\t.isEqualTo(context.getBean(ReactorResourceFactory.class).getLoopResources());\n\t\t});\n\t}\n\n\t@Test\n\tvoid configuresDetectedClientHttpConnectorBuilderBuilder() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ClientHttpConnectorBuilder.class));\n\t}\n\n\t@Test\n\tvoid configuresDefinedClientHttpConnectorBuilder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.clients.reactive.connector=jetty\")\n\t\t\t.run((context) -> assertThat(context.getBean(ClientHttpConnectorBuilder.class))\n\t\t\t\t.isInstanceOf(JettyClientHttpConnectorBuilder.class));\n\t}\n\n\t@Test\n\tvoid configuresClientHttpConnectorSettings() {\n\t\tthis.contextRunner.withPropertyValues(sslPropertyValues().toArray(String[]::new))\n\t\t\t.withPropertyValues(\"spring.http.clients.redirects=dont-follow\", \"spring.http.clients.connect-timeout=10s\",\n\t\t\t\t\t\"spring.http.clients.read-timeout=20s\", \"spring.http.clients.ssl.bundle=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tHttpClientSettings settings = context.getBean(HttpClientSettings.class);\n\t\t\t\tassertThat(settings.redirects()).isEqualTo(HttpRedirects.DONT_FOLLOW);\n\t\t\t\tassertThat(settings.connectTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t\t\t\tassertThat(settings.readTimeout()).isEqualTo(Duration.ofSeconds(20));\n\t\t\t\tSslBundle sslBundle = settings.sslBundle();\n\t\t\t\tassertThat(sslBundle).isNotNull();\n\t\t\t\tassertThat(sslBundle.getKey().getAlias()).isEqualTo(\"alias1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBeConditionalOnAtLeastOneHttpConnectorClass() {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(reactor.netty.http.client.HttpClient.class,\n\t\t\t\torg.eclipse.jetty.client.HttpClient.class, org.apache.hc.client5.http.impl.async.HttpAsyncClients.class,\n\t\t\t\tjava.net.http.HttpClient.class);\n\t\tassertThatIllegalStateException().as(\"enough filtering\")\n\t\t\t.isThrownBy(() -> ClientHttpConnectorBuilder.detect(classLoader));\n\t\tthis.contextRunner.withClassLoader(classLoader)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ClientHttpConnector.class)\n\t\t\t\t.hasSingleBean(HttpClientSettings.class));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid whenVirtualThreadsEnabledAndUsingJdkHttpClientUsesVirtualThreadExecutor() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.clients.reactive.connector=jdk\", \"spring.threads.virtual.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tClientHttpConnector connector = context.getBean(ClientHttpConnectorBuilder.class).build();\n\t\t\t\tjava.net.http.HttpClient httpClient = (java.net.http.HttpClient) ReflectionTestUtils.getField(connector,\n\t\t\t\t\t\t\"httpClient\");\n\t\t\t\tassertThat(httpClient).isNotNull();\n\t\t\t\tassertThat(httpClient.executor()).containsInstanceOf(VirtualThreadTaskExecutor.class);\n\t\t\t});\n\t}\n\n\tprivate List<String> sslPropertyValues() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/autoconfigure/ssl/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.key.alias=alias1\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.type=PKCS12\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.certificate=\" + location + \"rsa-cert.pem\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.pem.test.truststore.private-key=\" + location + \"rsa-key.pem\");\n\t\treturn propertyValues;\n\t}\n\n\t@Test\n\tvoid clientHttpConnectorBuilderCustomizersAreApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.clients.reactive.connector=jdk\")\n\t\t\t.withUserConfiguration(ClientHttpConnectorBuilderCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tClientHttpConnector connector = context.getBean(ClientHttpConnectorBuilder.class).build();\n\t\t\t\tassertThat(connector).extracting(\"readTimeout\").isEqualTo(Duration.ofSeconds(5));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomClientHttpConnectorConfig {\n\n\t\t@Bean\n\t\tClientHttpConnector customConnector() {\n\t\t\treturn mock(ClientHttpConnector.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomReactorResourceConfig {\n\n\t\t@Bean\n\t\tReactorResourceFactory customReactorResourceFactory() {\n\t\t\tReactorResourceFactory reactorResourceFactory = new ReactorResourceFactory();\n\t\t\treactorResourceFactory.setUseGlobalResources(false);\n\t\t\treactorResourceFactory.setLoopResources(LoopResources.create(\"custom-loop\", 1, true));\n\t\t\treturn reactorResourceFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientHttpConnectorBuilderCustomizersConfiguration {\n\n\t\t@Bean\n\t\tClientHttpConnectorBuilderCustomizer<JdkClientHttpConnectorBuilder> jdkCustomizer() {\n\t\t\treturn (builder) -> builder.withCustomizer((connector) -> connector.setReadTimeout(Duration.ofSeconds(5)));\n\t\t}\n\n\t\t@Bean\n\t\tClientHttpConnectorBuilderCustomizer<JettyClientHttpConnectorBuilder> jettyCustomizer() {\n\t\t\treturn (builder) -> {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/reactive/ReactiveHttpClientsPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.reactive;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientsProperties.Connector;\nimport org.springframework.boot.http.client.reactive.HttpComponentsClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.JdkClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.JettyClientHttpConnectorBuilder;\nimport org.springframework.boot.http.client.reactive.ReactorClientHttpConnectorBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveHttpClientsProperties}.\n *\n * @author Phillip Webb\n */\nclass ReactiveHttpClientsPropertiesTests {\n\n\t@Nested\n\tclass ConnectorTests {\n\n\t\t@Test\n\t\tvoid reactorBuilder() {\n\t\t\tassertThat(Connector.REACTOR.builder()).isInstanceOf(ReactorClientHttpConnectorBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid jettyBuilder() {\n\t\t\tassertThat(Connector.JETTY.builder()).isInstanceOf(JettyClientHttpConnectorBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid httpComponentsBuilder() {\n\t\t\tassertThat(Connector.HTTP_COMPONENTS.builder())\n\t\t\t\t.isInstanceOf(HttpComponentsClientHttpConnectorBuilder.class);\n\t\t}\n\n\t\t@Test\n\t\tvoid jdkBuilder() {\n\t\t\tassertThat(Connector.JDK.builder()).isInstanceOf(JdkClientHttpConnectorBuilder.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/autoconfigure/service/HttpServiceClientPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.autoconfigure.service;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.http.client.autoconfigure.ApiversionProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientProperties;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties.HttpServiceClientPropertiesRuntimeHints;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpServiceClientProperties}.\n *\n * @author Phillip Webb\n */\nclass HttpServiceClientPropertiesTests {\n\n\t@Test\n\tvoid bindProperties() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.base-url\", \"https://example.com/olga\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.default-header.secure\", \"very,somewhat\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.default-header.test\", \"true\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.redirects\", \"dont-follow\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.connect-timeout\", \"10s\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.read-timeout\", \"20s\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c1.ssl.bundle\", \"usual\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c2.base-url\", \"https://example.com/rossen\");\n\t\tenvironment.setProperty(\"spring.http.serviceclient.c3.base-url\", \"https://example.com/phil\");\n\t\tHttpServiceClientProperties properties = HttpServiceClientProperties.bind(environment);\n\t\tHttpClientProperties c1 = properties.get(\"c1\");\n\t\tassertThat(c1).isNotNull();\n\t\tassertThat(c1.getBaseUrl()).isEqualTo(\"https://example.com/olga\");\n\t\tassertThat(c1.getDefaultHeader()).containsOnly(Map.entry(\"secure\", List.of(\"very\", \"somewhat\")),\n\t\t\t\tMap.entry(\"test\", List.of(\"true\")));\n\t\tassertThat(c1.getRedirects()).isEqualTo(HttpRedirects.DONT_FOLLOW);\n\t\tassertThat(c1.getConnectTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t\tassertThat(c1.getReadTimeout()).isEqualTo(Duration.ofSeconds(20));\n\t\tassertThat(c1.getSsl().getBundle()).isEqualTo(\"usual\");\n\t\tHttpClientProperties c2 = properties.get(\"c2\");\n\t\tassertThat(c2).isNotNull();\n\t\tassertThat(c2.getBaseUrl()).isEqualTo(\"https://example.com/rossen\");\n\t\tHttpClientProperties c3 = properties.get(\"c3\");\n\t\tassertThat(c3).isNotNull();\n\t\tassertThat(c3.getBaseUrl()).isEqualTo(\"https://example.com/phil\");\n\t\tassertThat(properties.get(\"c4\")).isNull();\n\n\t}\n\n\t@Test\n\tvoid registersHintsForBindingOfHttpClientProperties() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew HttpServiceClientPropertiesRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(HttpClientProperties.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ApiversionProperties.class)).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ApiversionProperties.Insert.class)).accepts(hints);\n\t}\n\n\t@Configuration\n\t@EnableConfigurationProperties(HttpServiceClientProperties.class)\n\tstatic class PropertiesConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/AbstractClientHttpConnectorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.time.Duration;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport javax.net.ssl.SSLHandshakeException;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.Ssl.ClientAuth;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.web.reactive.function.client.ClientRequest;\nimport org.springframework.web.reactive.function.client.ClientResponse;\nimport org.springframework.web.reactive.function.client.ExchangeFunctions;\nimport org.springframework.web.reactive.function.client.WebClientRequestException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Base class for {@link ClientHttpConnectorBuilder} tests.\n *\n * @param <T> The {@link ClientHttpConnector} type\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nabstract class AbstractClientHttpConnectorBuilderTests<T extends ClientHttpConnector> {\n\n\tprivate static final Function<HttpMethod, HttpStatus> ALWAYS_FOUND = (method) -> HttpStatus.FOUND;\n\n\tprivate final Class<T> connectorType;\n\n\tprivate final ClientHttpConnectorBuilder<T> builder;\n\n\tAbstractClientHttpConnectorBuilderTests(Class<T> connectorType, ClientHttpConnectorBuilder<T> builder) {\n\t\tthis.connectorType = connectorType;\n\t\tthis.builder = builder;\n\t}\n\n\t@Test\n\tvoid buildReturnsConnectorOfExpectedType() {\n\t\tT connector = this.builder.build();\n\t\tassertThat(connector).isInstanceOf(this.connectorType);\n\t}\n\n\t@Test\n\tvoid buildWhenHasConnectTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withConnectTimeout(Duration.ofSeconds(60));\n\t\tT connector = this.builder.build(settings);\n\t\tassertThat(connectTimeout(connector)).isEqualTo(Duration.ofSeconds(60).toMillis());\n\t}\n\n\t@Test\n\tvoid buildWhenHadReadTimeout() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withReadTimeout(Duration.ofSeconds(120));\n\t\tT connector = this.builder.build(settings);\n\t\tassertThat(readTimeout(connector)).isEqualTo(Duration.ofSeconds(120).toMillis());\n\t}\n\n\t@ParameterizedTest\n\t@WithPackageResources(\"test.jks\")\n\t@ValueSource(strings = { \"GET\", \"POST\" })\n\tvoid connectWithSslBundle(String httpMethod) throws Exception {\n\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\twebServerFactory.setSsl(ssl());\n\t\tWebServer webServer = webServerFactory\n\t\t\t.getWebServer((context) -> context.addServlet(\"test\", TestServlet.class).addMapping(\"/\"));\n\t\ttry {\n\t\t\twebServer.start();\n\t\t\tint port = webServer.getPort();\n\t\t\tURI uri = new URI(\"https://localhost:%s\".formatted(port));\n\t\t\tClientHttpConnector insecureConnector = this.builder.build();\n\t\t\tClientRequest insecureRequest = createRequest(httpMethod, uri);\n\t\t\tassertThatExceptionOfType(WebClientRequestException.class)\n\t\t\t\t.isThrownBy(() -> getResponse(insecureConnector, insecureRequest))\n\t\t\t\t.withCauseInstanceOf(SSLHandshakeException.class);\n\t\t\tClientHttpConnector secureConnector = this.builder.build(HttpClientSettings.ofSslBundle(sslBundle()));\n\t\t\tClientRequest secureRequest = createRequest(httpMethod, uri);\n\t\t\tClientResponse secureResponse = getResponse(secureConnector, secureRequest);\n\t\t\tassertThat(secureResponse.bodyToMono(String.class).block())\n\t\t\t\t.contains(\"Received \" + httpMethod + \" request to /\");\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@WithPackageResources(\"test.jks\")\n\t@ValueSource(strings = { \"GET\", \"POST\" })\n\tvoid connectWithSslBundleAndOptionsMismatch(String httpMethod) throws Exception {\n\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\twebServerFactory.setSsl(ssl(\"TLS_AES_128_GCM_SHA256\"));\n\t\tWebServer webServer = webServerFactory\n\t\t\t.getWebServer((context) -> context.addServlet(\"test\", TestServlet.class).addMapping(\"/\"));\n\t\ttry {\n\t\t\twebServer.start();\n\t\t\tint port = webServer.getPort();\n\t\t\tURI uri = new URI(\"https://localhost:%s\".formatted(port));\n\t\t\tClientHttpConnector secureConnector = this.builder.build(\n\t\t\t\t\tHttpClientSettings.ofSslBundle(sslBundle(SslOptions.of(Set.of(\"TLS_AES_256_GCM_SHA384\"), null))));\n\t\t\tClientRequest secureRequest = createRequest(httpMethod, uri);\n\t\t\tassertThatExceptionOfType(WebClientRequestException.class)\n\t\t\t\t.isThrownBy(() -> getResponse(secureConnector, secureRequest))\n\t\t\t\t.withCauseInstanceOf(SSLHandshakeException.class);\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\" })\n\tvoid redirectDefault(String httpMethod) throws Exception {\n\t\ttestRedirect(null, HttpMethod.valueOf(httpMethod), this::getExpectedRedirect);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\" })\n\tvoid redirectFollow(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.FOLLOW);\n\t\ttestRedirect(settings, HttpMethod.valueOf(httpMethod), this::getExpectedRedirect);\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\" })\n\tvoid redirectDontFollow(String httpMethod) throws Exception {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\ttestRedirect(settings, HttpMethod.valueOf(httpMethod), ALWAYS_FOUND);\n\t}\n\n\tprotected final void testRedirect(@Nullable HttpClientSettings settings, HttpMethod httpMethod,\n\t\t\tFunction<HttpMethod, HttpStatus> expectedStatusForMethod) throws URISyntaxException {\n\t\tHttpStatus expectedStatus = expectedStatusForMethod.apply(httpMethod);\n\t\tTomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory(0);\n\t\tWebServer webServer = webServerFactory\n\t\t\t.getWebServer((context) -> context.addServlet(\"test\", TestServlet.class).addMapping(\"/\"));\n\t\ttry {\n\t\t\twebServer.start();\n\t\t\tint port = webServer.getPort();\n\t\t\tURI uri = new URI(\"http://localhost:%s\".formatted(port) + \"/redirect\");\n\t\t\tClientHttpConnector connector = this.builder.build(settings);\n\t\t\tClientRequest request = createRequest(httpMethod, uri);\n\t\t\tClientResponse response = getResponse(connector, request);\n\t\t\tassertThat(response.statusCode()).isEqualTo(expectedStatus);\n\t\t\tif (expectedStatus == HttpStatus.OK) {\n\t\t\t\tassertThat(response.bodyToMono(String.class).block()).contains(\"request to /redirected\");\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n\tprivate ClientRequest createRequest(String httpMethod, URI uri) {\n\t\treturn createRequest(HttpMethod.valueOf(httpMethod), uri);\n\t}\n\n\tprivate ClientRequest createRequest(HttpMethod httpMethod, URI uri) {\n\t\treturn ClientRequest.create(httpMethod, uri).build();\n\t}\n\n\tprivate ClientResponse getResponse(ClientHttpConnector connector, ClientRequest request) {\n\t\tClientResponse response = ExchangeFunctions.create(connector).exchange(request).block();\n\t\tassertThat(response).isNotNull();\n\t\treturn response;\n\t}\n\n\tprivate Ssl ssl(String... ciphers) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(ClientAuth.NEED);\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setTrustStore(\"classpath:test.jks\");\n\t\tif (ciphers.length > 0) {\n\t\t\tssl.setCiphers(ciphers);\n\t\t}\n\t\treturn ssl;\n\t}\n\n\tprotected final SslBundle sslBundle() {\n\t\treturn sslBundle(SslOptions.NONE);\n\t}\n\n\tprotected final SslBundle sslBundle(SslOptions sslOptions) {\n\t\tJksSslStoreDetails storeDetails = JksSslStoreDetails.forLocation(\"classpath:test.jks\");\n\t\tJksSslStoreBundle stores = new JksSslStoreBundle(storeDetails, storeDetails);\n\t\treturn SslBundle.of(stores, SslBundleKey.of(\"password\"), sslOptions);\n\t}\n\n\tprotected HttpStatus getExpectedRedirect(HttpMethod httpMethod) {\n\t\treturn HttpStatus.OK;\n\t}\n\n\tprotected abstract long connectTimeout(T connector);\n\n\tprotected abstract long readTimeout(T connector);\n\n\tpublic static class TestServlet extends HttpServlet {\n\n\t\t@Override\n\t\tpublic void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {\n\t\t\tif (\"/redirect\".equals(req.getRequestURI())) {\n\t\t\t\tres.sendRedirect(\"/redirected\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.getWriter().println(\"Received \" + req.getMethod() + \" request to \" + req.getRequestURI());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/HttpComponentsClientHttpConnectorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.apache.hc.client5.http.HttpRoute;\nimport org.apache.hc.client5.http.async.HttpAsyncClient;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;\nimport org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;\nimport org.apache.hc.core5.function.Resolver;\nimport org.apache.hc.core5.http.nio.ssl.TlsStrategy;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpComponentsHttpAsyncClientBuilder;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.http.client.reactive.HttpComponentsClientHttpConnector;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpComponentsClientHttpConnectorBuilder} and\n * {@link HttpComponentsHttpAsyncClientBuilder}.\n *\n * @author Phillip Webb\n */\nclass HttpComponentsClientHttpConnectorBuilderTests\n\t\textends AbstractClientHttpConnectorBuilderTests<HttpComponentsClientHttpConnector> {\n\n\tHttpComponentsClientHttpConnectorBuilderTests() {\n\t\tsuper(HttpComponentsClientHttpConnector.class, ClientHttpConnectorBuilder.httpComponents());\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tTestCustomizer<HttpAsyncClientBuilder> httpClientCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpAsyncClientBuilder> httpClientCustomizer2 = new TestCustomizer<>();\n\t\tTestCustomizer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<ConnectionConfig.Builder> connectionConfigCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<ConnectionConfig.Builder> connectionConfigCustomizer2 = new TestCustomizer<>();\n\t\tTestCustomizer<RequestConfig.Builder> defaultRequestConfigCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<RequestConfig.Builder> defaultRequestConfigCustomizer1 = new TestCustomizer<>();\n\t\tClientHttpConnectorBuilder.httpComponents()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.withConnectionManagerCustomizer(connectionManagerCustomizer)\n\t\t\t.withConnectionConfigCustomizer(connectionConfigCustomizer1)\n\t\t\t.withConnectionConfigCustomizer(connectionConfigCustomizer2)\n\t\t\t.withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer)\n\t\t\t.withDefaultRequestConfigCustomizer(defaultRequestConfigCustomizer1)\n\t\t\t.build();\n\t\thttpClientCustomizer1.assertCalled();\n\t\thttpClientCustomizer2.assertCalled();\n\t\tconnectionManagerCustomizer.assertCalled();\n\t\tconnectionConfigCustomizer1.assertCalled();\n\t\tconnectionConfigCustomizer2.assertCalled();\n\t\tdefaultRequestConfigCustomizer.assertCalled();\n\t\tdefaultRequestConfigCustomizer1.assertCalled();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid withTlsSocketStrategyFactory() {\n\t\tHttpClientSettings settings = HttpClientSettings.ofSslBundle(sslBundle());\n\t\tList<SslBundle> bundles = new ArrayList<>();\n\t\tFunction<@Nullable SslBundle, @Nullable TlsStrategy> tlsSocketStrategyFactory = (bundle) -> {\n\t\t\tbundles.add(bundle);\n\t\t\treturn (sessionLayer, host, localAddress, remoteAddress, attachment, handshakeTimeout) -> false;\n\t\t};\n\t\tClientHttpConnectorBuilder.httpComponents()\n\t\t\t.withTlsSocketStrategyFactory(tlsSocketStrategyFactory)\n\t\t\t.build(settings);\n\t\tassertThat(bundles).contains(settings.sslBundle());\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tTestCustomizer<HttpAsyncClientBuilder> customizer = new TestCustomizer<>();\n\t\tClientHttpConnectorBuilder.httpComponents()\n\t\t\t.with((builder) -> builder.withHttpClientCustomizer(customizer))\n\t\t\t.build();\n\t\tcustomizer.assertCalled();\n\t}\n\n\t@Override\n\tprotected long connectTimeout(HttpComponentsClientHttpConnector connector) {\n\t\treturn getConnectorConfig(connector).getConnectTimeout().toMilliseconds();\n\t}\n\n\t@Override\n\tprotected long readTimeout(HttpComponentsClientHttpConnector connector) {\n\t\treturn getConnectorConfig(connector).getSocketTimeout().toMilliseconds();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ConnectionConfig getConnectorConfig(HttpComponentsClientHttpConnector connector) {\n\t\tHttpAsyncClient httpClient = (HttpAsyncClient) ReflectionTestUtils.getField(connector, \"client\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tObject manager = ReflectionTestUtils.getField(httpClient, \"manager\");\n\t\tassertThat(manager).isNotNull();\n\t\tResolver<HttpRoute, ConnectionConfig> connectionConfigResolver = (Resolver<HttpRoute, ConnectionConfig>) ReflectionTestUtils\n\t\t\t.getField(manager, \"connectionConfigResolver\");\n\t\tassertThat(connectionConfigResolver).isNotNull();\n\t\treturn connectionConfigResolver.resolve(null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/JdkClientHttpConnectorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.net.http.HttpClient;\nimport java.time.Duration;\nimport java.util.concurrent.Executor;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.JdkHttpClientBuilder;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.http.client.reactive.JdkClientHttpConnector;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JdkClientHttpConnectorBuilder} and {@link JdkHttpClientBuilder}.\n *\n * @author Phillip Webb\n */\nclass JdkClientHttpConnectorBuilderTests extends AbstractClientHttpConnectorBuilderTests<JdkClientHttpConnector> {\n\n\tJdkClientHttpConnectorBuilderTests() {\n\t\tsuper(JdkClientHttpConnector.class, ClientHttpConnectorBuilder.jdk());\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tTestCustomizer<HttpClient.Builder> httpClientCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClient.Builder> httpClientCustomizer2 = new TestCustomizer<>();\n\t\tClientHttpConnectorBuilder.jdk()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.build();\n\t\thttpClientCustomizer1.assertCalled();\n\t\thttpClientCustomizer2.assertCalled();\n\t}\n\n\t@Test\n\tvoid withExecutor() {\n\t\tExecutor executor = new SimpleAsyncTaskExecutor();\n\t\tJdkClientHttpConnector connector = ClientHttpConnectorBuilder.jdk().withExecutor(executor).build();\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tassertThat(httpClient.executor()).containsSame(executor);\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tTestCustomizer<HttpClient.Builder> customizer = new TestCustomizer<>();\n\t\tClientHttpConnectorBuilder.jdk().with((builder) -> builder.withHttpClientCustomizer(customizer)).build();\n\t\tcustomizer.assertCalled();\n\t}\n\n\t@Override\n\tprotected long connectTimeout(JdkClientHttpConnector connector) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn httpClient.connectTimeout().get().toMillis();\n\t}\n\n\t@Override\n\tprotected long readTimeout(JdkClientHttpConnector connector) {\n\t\tDuration readTimeout = (Duration) ReflectionTestUtils.getField(connector, \"readTimeout\");\n\t\tassertThat(readTimeout).isNotNull();\n\t\treturn readTimeout.toMillis();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/JettyClientHttpConnectorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.time.Duration;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.eclipse.jetty.client.HttpClientTransport;\nimport org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;\nimport org.eclipse.jetty.io.ClientConnector;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.JettyHttpClientBuilder;\nimport org.springframework.http.client.reactive.JettyClientHttpConnector;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JettyClientHttpConnectorBuilder} and {@link JettyHttpClientBuilder}.\n *\n * @author Phillip Webb\n */\nclass JettyClientHttpConnectorBuilderTests extends AbstractClientHttpConnectorBuilderTests<JettyClientHttpConnector> {\n\n\tJettyClientHttpConnectorBuilderTests() {\n\t\tsuper(JettyClientHttpConnector.class, ClientHttpConnectorBuilder.jetty());\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tTestCustomizer<HttpClient> httpClientCustomizer1 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClient> httpClientCustomizer2 = new TestCustomizer<>();\n\t\tTestCustomizer<HttpClientTransport> httpClientTransportCustomizer = new TestCustomizer<>();\n\t\tTestCustomizer<ClientConnector> clientConnectorCustomizerCustomizer = new TestCustomizer<>();\n\t\tClientHttpConnectorBuilder.jetty()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.withHttpClientTransportCustomizer(httpClientTransportCustomizer)\n\t\t\t.withClientConnectorCustomizerCustomizer(clientConnectorCustomizerCustomizer)\n\t\t\t.build();\n\t\thttpClientCustomizer1.assertCalled();\n\t\thttpClientCustomizer2.assertCalled();\n\t\thttpClientTransportCustomizer.assertCalled();\n\t\tclientConnectorCustomizerCustomizer.assertCalled();\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tTestCustomizer<HttpClient> customizer = new TestCustomizer<>();\n\t\tClientHttpConnectorBuilder.jetty().with((builder) -> builder.withHttpClientCustomizer(customizer)).build();\n\t\tcustomizer.assertCalled();\n\t}\n\n\t@Test\n\tvoid withHttpClientTransportFactory() {\n\t\tJettyClientHttpConnector connector = ClientHttpConnectorBuilder.jetty()\n\t\t\t.withHttpClientTransportFactory(TestHttpClientTransport::new)\n\t\t\t.build();\n\t\tassertThat(connector).extracting(\"httpClient\")\n\t\t\t.extracting(\"transport\")\n\t\t\t.isInstanceOf(TestHttpClientTransport.class);\n\t}\n\n\t@Override\n\tprotected long connectTimeout(JettyClientHttpConnector connector) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn httpClient.getConnectTimeout();\n\t}\n\n\t@Override\n\tprotected long readTimeout(JettyClientHttpConnector connector) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tObject field = ReflectionTestUtils.getField(httpClient, \"readTimeout\");\n\t\tassertThat(field).isNotNull();\n\t\treturn ((Duration) field).toMillis();\n\t}\n\n\tstatic class TestHttpClientTransport extends HttpClientTransportOverHTTP {\n\n\t\tTestHttpClientTransport(ClientConnector connector) {\n\t\t\tsuper(connector);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/ReactorClientHttpConnectorBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport io.netty.channel.ChannelOption;\nimport org.junit.jupiter.api.Test;\nimport reactor.netty.http.client.HttpClient;\n\nimport org.springframework.boot.http.client.ReactorHttpClientBuilder;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ReactorClientHttpConnectorBuilder} and\n * {@link ReactorHttpClientBuilder}.\n *\n * @author Phillip Webb\n */\nclass ReactorClientHttpConnectorBuilderTests\n\t\textends AbstractClientHttpConnectorBuilderTests<ReactorClientHttpConnector> {\n\n\tReactorClientHttpConnectorBuilderTests() {\n\t\tsuper(ReactorClientHttpConnector.class, ClientHttpConnectorBuilder.reactor());\n\t}\n\n\t@Test\n\tvoid withHttpClientFactory() {\n\t\tboolean[] called = new boolean[1];\n\t\tSupplier<HttpClient> httpClientFactory = () -> {\n\t\t\tcalled[0] = true;\n\t\t\treturn HttpClient.create();\n\t\t};\n\t\tClientHttpConnectorBuilder.reactor().withHttpClientFactory(httpClientFactory).build();\n\t\tassertThat(called).containsExactly(true);\n\t}\n\n\t@Test\n\tvoid withReactorResourceFactory() {\n\t\tReactorResourceFactory resourceFactory = spy(new ReactorResourceFactory());\n\t\tClientHttpConnectorBuilder.reactor().withReactorResourceFactory(resourceFactory).build();\n\t\tthen(resourceFactory).should().getConnectionProvider();\n\t\tthen(resourceFactory).should().getLoopResources();\n\t}\n\n\t@Test\n\tvoid withCustomizers() {\n\t\tList<HttpClient> httpClients = new ArrayList<>();\n\t\tUnaryOperator<HttpClient> httpClientCustomizer1 = (httpClient) -> {\n\t\t\thttpClients.add(httpClient);\n\t\t\treturn httpClient;\n\t\t};\n\t\tUnaryOperator<HttpClient> httpClientCustomizer2 = (httpClient) -> {\n\t\t\thttpClients.add(httpClient);\n\t\t\treturn httpClient;\n\t\t};\n\t\tClientHttpConnectorBuilder.reactor()\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer1)\n\t\t\t.withHttpClientCustomizer(httpClientCustomizer2)\n\t\t\t.build();\n\t\tassertThat(httpClients).hasSize(2);\n\t}\n\n\t@Test\n\tvoid with() {\n\t\tboolean[] called = new boolean[1];\n\t\tSupplier<HttpClient> httpClientFactory = () -> {\n\t\t\tcalled[0] = true;\n\t\t\treturn HttpClient.create();\n\t\t};\n\t\tClientHttpConnectorBuilder.reactor()\n\t\t\t.with((builder) -> builder.withHttpClientFactory(httpClientFactory))\n\t\t\t.build();\n\t\tassertThat(called).containsExactly(true);\n\t}\n\n\t@Override\n\tprotected long connectTimeout(ReactorClientHttpConnector connector) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tObject connectTimeout = httpClient.configuration().options().get(ChannelOption.CONNECT_TIMEOUT_MILLIS);\n\t\tassertThat(connectTimeout).isNotNull();\n\t\treturn (int) connectTimeout;\n\t}\n\n\t@Override\n\tprotected long readTimeout(ReactorClientHttpConnector connector) {\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(connector, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tDuration responseTimeout = httpClient.configuration().responseTimeout();\n\t\tassertThat(responseTimeout).isNotNull();\n\t\treturn (int) responseTimeout.toMillis();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-client/src/test/java/org/springframework/boot/http/client/reactive/TestCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.client.reactive;\n\nimport java.util.function.Consumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test customizer that can assert that it has been called.\n *\n * @param <T> type being customized\n * @author Phillip Webb\n */\nclass TestCustomizer<T> implements Consumer<T> {\n\n\tprivate boolean called;\n\n\t@Override\n\tpublic void accept(T t) {\n\t\tthis.called = true;\n\t}\n\n\tvoid assertCalled() {\n\t\tassertThat(this.called).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-codec/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot HTTP Codec\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-kotlinx-serialization-json\"))\n\toptional(\"org.springframework:spring-webflux\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/CodecCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.codec;\n\nimport org.springframework.http.codec.CodecConfigurer;\n\n/**\n * Callback interface that can be used to customize codecs configuration for an HTTP\n * client and/or server with a {@link CodecConfigurer}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface CodecCustomizer {\n\n\t/**\n\t * Callback to customize a {@link CodecConfigurer} instance.\n\t * @param configurer codec configurer to customize\n\t */\n\tvoid customize(CodecConfigurer configurer);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/autoconfigure/CodecsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.codec.autoconfigure;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport kotlinx.serialization.json.Json;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.codec.CodecConfigurer;\nimport org.springframework.http.codec.json.JacksonJsonDecoder;\nimport org.springframework.http.codec.json.JacksonJsonEncoder;\nimport org.springframework.http.codec.json.KotlinSerializationJsonDecoder;\nimport org.springframework.http.codec.json.KotlinSerializationJsonEncoder;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link org.springframework.core.codec.Encoder Encoders} and\n * {@link org.springframework.core.codec.Decoder Decoders}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\",\n\t\t\"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\" })\n@ConditionalOnClass({ CodecConfigurer.class, WebClient.class })\npublic final class CodecsAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JsonMapper.class)\n\t@ConditionalOnProperty(name = \"spring.http.codecs.preferred-json-mapper\", havingValue = \"jackson\",\n\t\t\tmatchIfMissing = true)\n\tstatic class JacksonJsonCodecConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnBean(JsonMapper.class)\n\t\tCodecCustomizer jacksonCodecCustomizer(JsonMapper jsonMapper) {\n\t\t\treturn (configurer) -> {\n\t\t\t\tCodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs();\n\t\t\t\tdefaults.jacksonJsonDecoder(new JacksonJsonDecoder(jsonMapper));\n\t\t\t\tdefaults.jacksonJsonEncoder(new JacksonJsonEncoder(jsonMapper));\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ObjectMapper.class)\n\t@Conditional(NoJacksonOrJackson2Preferred.class)\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tstatic class Jackson2JsonCodecConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnBean(ObjectMapper.class)\n\t\tCodecCustomizer jackson2CodecCustomizer(ObjectMapper objectMapper) {\n\t\t\treturn (configurer) -> {\n\t\t\t\tCodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs();\n\t\t\t\tdefaults.jacksonJsonDecoder(new org.springframework.http.codec.json.Jackson2JsonDecoder(objectMapper));\n\t\t\t\tdefaults.jacksonJsonEncoder(new org.springframework.http.codec.json.Jackson2JsonEncoder(objectMapper));\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Json.class)\n\tstatic class KotlinxSerializationJsonCodecConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(Json.class)\n\t\tCodecCustomizer kotlinxJsonCodecCustomizer(Json json, ResourceLoader resourceLoader) {\n\t\t\tClassLoader classLoader = resourceLoader.getClassLoader();\n\t\t\tboolean hasAnyJsonSupport = ClassUtils.isPresent(\"tools.jackson.databind.json.JsonMapper\", classLoader)\n\t\t\t\t\t|| ClassUtils.isPresent(\"com.fasterxml.jackson.databind.ObjectMapper\", classLoader)\n\t\t\t\t\t|| ClassUtils.isPresent(\"com.google.gson.Gson\", classLoader);\n\n\t\t\treturn (configurer) -> {\n\t\t\t\tCodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs();\n\t\t\t\tdefaults.kotlinSerializationJsonEncoder(hasAnyJsonSupport ? new KotlinSerializationJsonEncoder(json)\n\t\t\t\t\t\t: new KotlinSerializationJsonEncoder(json, (type) -> true));\n\t\t\t\tdefaults.kotlinSerializationJsonDecoder(hasAnyJsonSupport ? new KotlinSerializationJsonDecoder(json)\n\t\t\t\t\t\t: new KotlinSerializationJsonDecoder(json, (type) -> true));\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(HttpCodecsProperties.class)\n\tstatic class DefaultCodecsConfiguration {\n\n\t\t@Bean\n\t\tDefaultCodecCustomizer defaultCodecCustomizer(HttpCodecsProperties httpCodecProperties) {\n\t\t\treturn new DefaultCodecCustomizer(httpCodecProperties.isLogRequestDetails(),\n\t\t\t\t\thttpCodecProperties.getMaxInMemorySize());\n\t\t}\n\n\t\tstatic final class DefaultCodecCustomizer implements CodecCustomizer, Ordered {\n\n\t\t\tprivate final boolean logRequestDetails;\n\n\t\t\tprivate final @Nullable DataSize maxInMemorySize;\n\n\t\t\tDefaultCodecCustomizer(boolean logRequestDetails, @Nullable DataSize maxInMemorySize) {\n\t\t\t\tthis.logRequestDetails = logRequestDetails;\n\t\t\t\tthis.maxInMemorySize = maxInMemorySize;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(CodecConfigurer configurer) {\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tCodecConfigurer.DefaultCodecs defaultCodecs = configurer.defaultCodecs();\n\t\t\t\tdefaultCodecs.enableLoggingRequestDetails(this.logRequestDetails);\n\t\t\t\tmap.from(this.maxInMemorySize).asInt(DataSize::toBytes).to(defaultCodecs::maxInMemorySize);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic int getOrder() {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class NoJacksonOrJackson2Preferred extends AnyNestedCondition {\n\n\t\tNoJacksonOrJackson2Preferred() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnMissingClass(\"tools.jackson.databind.json.JsonMapper\")\n\t\tstatic class NoJackson {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = \"spring.http.codecs.preferred-json-mapper\", havingValue = \"jackson2\")\n\t\tstatic class Jackson2Preferred {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/autoconfigure/HttpCodecsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.codec.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link ConfigurationProperties Properties} for reactive HTTP codecs.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.http.codecs\")\npublic class HttpCodecsProperties {\n\n\t/**\n\t * Whether to log form data at DEBUG level, and headers at TRACE level.\n\t */\n\tprivate boolean logRequestDetails;\n\n\t/**\n\t * Limit on the number of bytes that can be buffered whenever the input stream needs\n\t * to be aggregated. This applies only to the auto-configured WebFlux server and\n\t * WebClient instances. By default this is not set, in which case individual codec\n\t * defaults apply. Most codecs are limited to 256K by default.\n\t */\n\tprivate @Nullable DataSize maxInMemorySize;\n\n\tpublic boolean isLogRequestDetails() {\n\t\treturn this.logRequestDetails;\n\t}\n\n\tpublic void setLogRequestDetails(boolean logRequestDetails) {\n\t\tthis.logRequestDetails = logRequestDetails;\n\t}\n\n\tpublic @Nullable DataSize getMaxInMemorySize() {\n\t\treturn this.maxInMemorySize;\n\t}\n\n\tpublic void setMaxInMemorySize(@Nullable DataSize maxInMemorySize) {\n\t\tthis.maxInMemorySize = maxInMemorySize;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for HTTP codecs.\n */\n@NullMarked\npackage org.springframework.boot.http.codec.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for web-based codecs.\n */\n@NullMarked\npackage org.springframework.boot.http.codec;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{ \n  \"properties\": [\n    {\n      \"name\": \"spring.http.codecs.preferred-json-mapper\",\n      \"type\": \"java.lang.String\",\n      \"defaultValue\": \"jackson\",\n      \"description\": \"Preferred JSON mapper to use for HTTP encoding and decoding. By default, auto-detected according to the environment. Supported values are 'jackson' and 'jackson2' (deprecated).\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.http.codecs.preferred-json-mapper\",\n      \"values\": [\n        {\n          \"value\": \"jackson\"\n        },\n        {\n          \"value\": \"jackson2\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-http-codec/src/test/java/org/springframework/boot/http/codec/autoconfigure/CodecsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.codec.autoconfigure;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport kotlinx.serialization.json.Json;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.CodecConfigurer;\nimport org.springframework.http.codec.CodecConfigurer.DefaultCodecs;\nimport org.springframework.http.codec.EncoderHttpMessageWriter;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.http.codec.json.KotlinSerializationJsonEncoder;\nimport org.springframework.http.codec.support.DefaultClientCodecConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CodecsAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass CodecsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(CodecsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigShouldProvideALoggingRequestDetailsCustomizer() {\n\t\tthis.contextRunner.run((context) -> assertThat(defaultCodecs(context))\n\t\t\t.hasFieldOrPropertyWithValue(\"enableLoggingRequestDetails\", false));\n\t}\n\n\t@Test\n\tvoid loggingRequestDetailsCustomizerShouldUseHttpCodecsProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.codecs.log-request-details=true\")\n\t\t\t.run((context) -> assertThat(defaultCodecs(context))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"enableLoggingRequestDetails\", true));\n\t}\n\n\t@Test\n\tvoid maxInMemorySizeShouldUseHttpCodecProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.codecs.max-in-memory-size=64KB\")\n\t\t\t.run((context) -> assertThat(defaultCodecs(context)).hasFieldOrPropertyWithValue(\"maxInMemorySize\",\n\t\t\t\t\t64 * 1024));\n\t}\n\n\t@Test\n\tvoid defaultCodecCustomizerBeanShouldHaveOrderZero() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.getBean(\"defaultCodecCustomizer\", Ordered.class).getOrder()).isZero());\n\t}\n\n\t@Test\n\tvoid jacksonCodecCustomizerBacksOffWhenThereIsNoJsonMapper() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(\"jacksonCodecCustomizer\"));\n\t}\n\n\t@Test\n\tvoid jacksonCodecCustomizerIsAutoConfiguredWhenJsonMapperIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(JsonMapperConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"jacksonCodecCustomizer\"));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tvoid jacksonCodecCustomizerBacksOffWhenJackson2IsPreferred() {\n\t\tthis.contextRunner.withUserConfiguration(JsonMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.http.codecs.preferred-json-mapper=jackson2\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"jacksonCodecCustomizer\"));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tvoid jackson2CodecCustomizerIsAutoConfiguredWhenObjectMapperIsPresentAndJackson2IsPreferred() {\n\t\tthis.contextRunner.withUserConfiguration(ObjectMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.http.codecs.preferred-json-mapper=jackson2\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"jackson2CodecCustomizer\"));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tvoid jackson2CodecCustomizerIsAutoConfiguredWhenObjectMapperIsPresentAndJacksonIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(ObjectMapperConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(JsonMapper.class.getPackage().getName()))\n\t\t\t.run((context) -> assertThat(context).hasBean(\"jackson2CodecCustomizer\"));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tvoid jackson2CodecCustomizerBacksOffWhenJackson2IsPreferredButThereIsNoObjectMapper() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.codecs.preferred-json-mapper=jackson2\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"jackson2CodecCustomizer\"));\n\t}\n\n\t@Test\n\tvoid userProvidedCustomizerCanOverrideJacksonCodecCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(JsonMapperConfiguration.class, CodecCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tList<CodecCustomizer> codecCustomizers = context.getBean(CodecCustomizers.class).codecCustomizers;\n\t\t\t\tassertThat(codecCustomizers).hasSize(3);\n\t\t\t\tassertThat(codecCustomizers.get(2)).isInstanceOf(TestCodecCustomizer.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid maxInMemorySizeEnforcedInDefaultCodecs() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.codecs.max-in-memory-size=1MB\")\n\t\t\t.run((context) -> assertThat(defaultCodecs(context)).hasFieldOrPropertyWithValue(\"maxInMemorySize\",\n\t\t\t\t\t1048576));\n\t}\n\n\t@Test\n\tvoid kotlinSerializationUsesLimitedPredicateWhenOtherJsonConverterIsAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(KotlinxJsonConfiguration.class).run((context) -> {\n\t\t\tKotlinSerializationJsonEncoder encoder = findEncoder(context, KotlinSerializationJsonEncoder.class);\n\t\t\tassertThat(encoder.canEncode(ResolvableType.forClass(Map.class), MediaType.APPLICATION_JSON)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid kotlinSerializationUsesUnrestrictedPredicateWhenNoOtherJsonConverterIsAvailable() {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(JsonMapper.class.getPackage().getName(),\n\t\t\t\tObjectMapper.class.getPackage().getName());\n\t\tthis.contextRunner.withClassLoader(classLoader)\n\t\t\t.withUserConfiguration(KotlinxJsonConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tKotlinSerializationJsonEncoder encoder = findEncoder(context, KotlinSerializationJsonEncoder.class);\n\t\t\t\tassertThat(encoder.canEncode(ResolvableType.forClass(Map.class), MediaType.APPLICATION_JSON)).isTrue();\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> T findEncoder(AssertableApplicationContext context, Class<T> encoderClass) {\n\t\tServerCodecConfigurer configurer = ServerCodecConfigurer.create();\n\t\tcontext.getBeansOfType(CodecCustomizer.class).values().forEach((codec) -> codec.customize(configurer));\n\t\treturn (T) configurer.getWriters()\n\t\t\t.stream()\n\t\t\t.filter((writer) -> writer instanceof EncoderHttpMessageWriter<?>)\n\t\t\t.map((writer) -> (EncoderHttpMessageWriter<?>) writer)\n\t\t\t.map(EncoderHttpMessageWriter::getEncoder)\n\t\t\t.filter((encoder) -> encoderClass.isAssignableFrom(encoder.getClass()))\n\t\t\t.findFirst()\n\t\t\t.orElseThrow();\n\t}\n\n\tprivate DefaultCodecs defaultCodecs(AssertableApplicationContext context) {\n\t\tCodecCustomizer customizer = context.getBean(CodecCustomizer.class);\n\t\tCodecConfigurer configurer = new DefaultClientCodecConfigurer();\n\t\tcustomizer.customize(configurer);\n\t\treturn configurer.defaultCodecs();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JsonMapperConfiguration {\n\n\t\t@Bean\n\t\tJsonMapper jsonMapper() {\n\t\t\treturn new JsonMapper();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObjectMapperConfiguration {\n\n\t\t@Bean\n\t\tObjectMapper objectMapper() {\n\t\t\treturn new ObjectMapper();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class KotlinxJsonConfiguration {\n\n\t\t@Bean\n\t\tJson kotlinxJson() {\n\t\t\treturn Json.Default;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CodecCustomizerConfiguration {\n\n\t\t@Bean\n\t\tCodecCustomizer codecCustomizer() {\n\t\t\treturn new TestCodecCustomizer();\n\t\t}\n\n\t\t@Bean\n\t\tCodecCustomizers codecCustomizers(List<CodecCustomizer> customizers) {\n\t\t\treturn new CodecCustomizers(customizers);\n\t\t}\n\n\t}\n\n\tprivate static final class TestCodecCustomizer implements CodecCustomizer {\n\n\t\t@Override\n\t\tpublic void customize(CodecConfigurer configurer) {\n\t\t}\n\n\t}\n\n\tprivate static final class CodecCustomizers {\n\n\t\tprivate final List<CodecCustomizer> codecCustomizers;\n\n\t\tprivate CodecCustomizers(List<CodecCustomizer> codecCustomizers) {\n\t\t\tthis.codecCustomizers = codecCustomizers;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot HTTP Converter\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-web\")\n\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-gson\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-jsonb\"))\n\toptional(project(\":module:spring-boot-kotlinx-serialization-json\"))\n\toptional(\"com.fasterxml.jackson.dataformat:jackson-dataformat-xml\")\n\toptional(\"com.google.code.gson:gson\")\n\toptional(\"jakarta.json.bind:jakarta.json.bind-api\")\n\toptional(\"org.springframework:spring-webmvc\")\n\toptional(\"tools.jackson.dataformat:jackson-dataformat-xml\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.springframework.data:spring-data-rest-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestRuntimeOnly(\"org.eclipse:yasson\")\n\ttestRuntimeOnly(\"org.springframework:spring-webflux\")\n\ttestRuntimeOnly(\"tools.jackson.dataformat:jackson-dataformat-cbor\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/ClientHttpMessageConvertersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\n\n/**\n * Callback interface that can be used to customize a {@link HttpMessageConverters} for\n * client usage.\n *\n * @author Brian Clozel\n * @since 4.0\n */\n@FunctionalInterface\npublic interface ClientHttpMessageConvertersCustomizer {\n\n\t/**\n\t * Callback to customize a {@link ClientBuilder HttpMessageConverters.ClientBuilder}\n\t * instance.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(ClientBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/DefaultClientHttpMessageConvertersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;\n\n@SuppressWarnings(\"deprecation\")\nclass DefaultClientHttpMessageConvertersCustomizer implements ClientHttpMessageConvertersCustomizer {\n\n\tprivate final @Nullable HttpMessageConverters legacyConverters;\n\n\tprivate final Collection<HttpMessageConverter<?>> converters;\n\n\tDefaultClientHttpMessageConvertersCustomizer(@Nullable HttpMessageConverters legacyConverters,\n\t\t\tCollection<HttpMessageConverter<?>> converters) {\n\t\tthis.legacyConverters = legacyConverters;\n\t\tthis.converters = converters;\n\t}\n\n\t@Override\n\tpublic void customize(ClientBuilder builder) {\n\t\tif (this.legacyConverters != null) {\n\t\t\tthis.legacyConverters.forEach(builder::addCustomConverter);\n\t\t}\n\t\telse {\n\t\t\tbuilder.registerDefaults();\n\t\t\tthis.converters.forEach((converter) -> {\n\t\t\t\tif (converter instanceof KotlinSerializationJsonHttpMessageConverter) {\n\t\t\t\t\tbuilder.withKotlinSerializationJsonConverter(converter);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuilder.addCustomConverter(converter);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/DefaultServerHttpMessageConvertersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;\n\n@SuppressWarnings(\"deprecation\")\nclass DefaultServerHttpMessageConvertersCustomizer implements ServerHttpMessageConvertersCustomizer {\n\n\tprivate final @Nullable HttpMessageConverters legacyConverters;\n\n\tprivate final Collection<HttpMessageConverter<?>> converters;\n\n\tDefaultServerHttpMessageConvertersCustomizer(@Nullable HttpMessageConverters legacyConverters,\n\t\t\tCollection<HttpMessageConverter<?>> converters) {\n\n\t\tthis.legacyConverters = legacyConverters;\n\t\tthis.converters = converters;\n\t}\n\n\t@Override\n\tpublic void customize(ServerBuilder builder) {\n\t\tif (this.legacyConverters != null) {\n\t\t\tthis.legacyConverters.forEach(builder::addCustomConverter);\n\t\t}\n\t\telse {\n\t\t\tbuilder.registerDefaults();\n\t\t\tthis.converters.forEach((converter) -> {\n\t\t\t\tif (converter instanceof KotlinSerializationJsonHttpMessageConverter) {\n\t\t\t\t\tbuilder.withKotlinSerializationJsonConverter(converter);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbuilder.addCustomConverter(converter);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/GsonHttpMessageConvertersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport com.google.gson.Gson;\n\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.GsonHttpMessageConverter;\n\n/**\n * Configuration for HTTP Message converters that use Gson.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Brian Clozel\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(Gson.class)\nclass GsonHttpMessageConvertersConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(Gson.class)\n\t@Conditional(PreferGsonOrJacksonAndJsonbUnavailableCondition.class)\n\tstatic class GsonHttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnMissingBean(GsonHttpMessageConverter.class)\n\t\tGsonHttpConvertersCustomizer gsonHttpMessageConvertersCustomizer(Gson gson) {\n\t\t\treturn new GsonHttpConvertersCustomizer(gson);\n\t\t}\n\n\t}\n\n\tstatic class GsonHttpConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final GsonHttpMessageConverter converter;\n\n\t\tGsonHttpConvertersCustomizer(Gson gson) {\n\t\t\tthis.converter = new GsonHttpMessageConverter(gson);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withJsonConverter(this.converter);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withJsonConverter(this.converter);\n\t\t}\n\n\t}\n\n\tprivate static class PreferGsonOrJacksonAndJsonbUnavailableCondition extends AnyNestedCondition {\n\n\t\tPreferGsonOrJacksonAndJsonbUnavailableCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,\n\t\t\t\thavingValue = \"gson\")\n\t\tstatic class GsonPreferred {\n\n\t\t}\n\n\t\t@Conditional(JacksonAndJsonbUnavailableCondition.class)\n\t\tstatic class JacksonJsonbUnavailable {\n\n\t\t}\n\n\t}\n\n\tprivate static class JacksonAndJsonbUnavailableCondition extends NoneNestedConditions {\n\n\t\tJacksonAndJsonbUnavailableCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnBean(JacksonHttpMessageConvertersConfiguration.JacksonJsonHttpMessageConvertersCustomizer.class)\n\t\tstatic class JacksonAvailable {\n\n\t\t}\n\n\t\t@SuppressWarnings(\"removal\")\n\t\t@ConditionalOnBean(Jackson2HttpMessageConvertersConfiguration.Jackson2JsonMessageConvertersCustomizer.class)\n\t\tstatic class Jackson2Available {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,\n\t\t\t\thavingValue = \"jsonb\")\n\t\tstatic class JsonbPreferred {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConverters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;\nimport org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;\n\n/**\n * Bean used to manage the {@link HttpMessageConverter}s used in a Spring Boot\n * application. Provides a convenient way to add and merge additional\n * {@link HttpMessageConverter}s to a web application.\n * <p>\n * An instance of this bean can be registered with specific\n * {@link #HttpMessageConverters(HttpMessageConverter...) additional converters} if\n * needed, otherwise default converters will be used.\n * <p>\n * NOTE: The default converters used are the same as standard Spring MVC (see\n * {@link WebMvcConfigurationSupport}) with some slight re-ordering to put XML converters\n * at the back of the list.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see #HttpMessageConverters(HttpMessageConverter...)\n * @see #HttpMessageConverters(Collection)\n * @see #getConverters()\n * @deprecated since 4.0 in favor of {@link ClientHttpMessageConvertersCustomizer} and\n * {@link ServerHttpMessageConvertersCustomizer}.\n */\n@Deprecated(since = \"4.0\")\npublic class HttpMessageConverters implements Iterable<HttpMessageConverter<?>> {\n\n\tprivate static final List<Class<?>> NON_REPLACING_CONVERTERS;\n\n\tstatic {\n\t\tList<Class<?>> nonReplacingConverters = new ArrayList<>();\n\t\taddClassIfExists(nonReplacingConverters,\n\t\t\t\t\"org.springframework.hateoas.server.mvc.TypeConstrainedJacksonJsonHttpMessageConverter\");\n\t\tNON_REPLACING_CONVERTERS = Collections.unmodifiableList(nonReplacingConverters);\n\t}\n\n\tprivate static final MultiValueMap<Class<?>, Class<?>> EQUIVALENT_CONVERTERS;\n\n\tstatic {\n\t\tMultiValueMap<Class<?>, Class<?>> equivalentConverters = new LinkedMultiValueMap<>();\n\t\tputIfExists(equivalentConverters, \"org.springframework.http.converter.json.JacksonJsonHttpMessageConverter\",\n\t\t\t\t\"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter\",\n\t\t\t\t\"org.springframework.http.converter.json.GsonHttpMessageConverter\",\n\t\t\t\t\"org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter\");\n\t\tputIfExists(equivalentConverters, \"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter\",\n\t\t\t\t\"org.springframework.http.converter.json.GsonHttpMessageConverter\",\n\t\t\t\t\"org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter\");\n\t\tEQUIVALENT_CONVERTERS = CollectionUtils.unmodifiableMultiValueMap(equivalentConverters);\n\t}\n\n\tprivate final List<HttpMessageConverter<?>> converters;\n\n\t/**\n\t * Create a new {@link HttpMessageConverters} instance with the specified additional\n\t * converters.\n\t * @param additionalConverters additional converters to be added. Items are added just\n\t * before any default converter of the same type (or at the front of the list if no\n\t * default converter is found). The {@link #postProcessConverters(List)} method can be\n\t * used for further converter manipulation.\n\t */\n\tpublic HttpMessageConverters(HttpMessageConverter<?>... additionalConverters) {\n\t\tthis(Arrays.asList(additionalConverters));\n\t}\n\n\t/**\n\t * Create a new {@link HttpMessageConverters} instance with the specified additional\n\t * converters.\n\t * @param additionalConverters additional converters to be added. Items are added just\n\t * before any default converter of the same type (or at the front of the list if no\n\t * default converter is found). The {@link #postProcessConverters(List)} method can be\n\t * used for further converter manipulation.\n\t */\n\tpublic HttpMessageConverters(Collection<HttpMessageConverter<?>> additionalConverters) {\n\t\tthis(true, additionalConverters);\n\t}\n\n\t/**\n\t * Create a new {@link HttpMessageConverters} instance with the specified converters.\n\t * @param addDefaultConverters if default converters should be added\n\t * @param converters converters to be added. Items are added just before any default\n\t * converter of the same type (or at the front of the list if no default converter is\n\t * found). The {@link #postProcessConverters(List)} method can be used for further\n\t * converter manipulation.\n\t */\n\tpublic HttpMessageConverters(boolean addDefaultConverters, Collection<HttpMessageConverter<?>> converters) {\n\t\tList<HttpMessageConverter<?>> combined = getCombinedConverters(converters,\n\t\t\t\taddDefaultConverters ? getDefaultConverters() : Collections.emptyList());\n\t\tcombined = postProcessConverters(combined);\n\t\tthis.converters = Collections.unmodifiableList(combined);\n\t}\n\n\tprivate List<HttpMessageConverter<?>> getCombinedConverters(Collection<HttpMessageConverter<?>> converters,\n\t\t\tList<HttpMessageConverter<?>> defaultConverters) {\n\t\tList<HttpMessageConverter<?>> combined = new ArrayList<>();\n\t\tList<HttpMessageConverter<?>> processing = new ArrayList<>(converters);\n\t\tfor (HttpMessageConverter<?> defaultConverter : defaultConverters) {\n\t\t\tIterator<HttpMessageConverter<?>> iterator = processing.iterator();\n\t\t\twhile (iterator.hasNext()) {\n\t\t\t\tHttpMessageConverter<?> candidate = iterator.next();\n\t\t\t\tif (isReplacement(defaultConverter, candidate)) {\n\t\t\t\t\tcombined.add(candidate);\n\t\t\t\t\titerator.remove();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcombined.add(defaultConverter);\n\t\t\tif (defaultConverter instanceof AllEncompassingFormHttpMessageConverter allEncompassingConverter) {\n\t\t\t\tconfigurePartConverters(allEncompassingConverter, converters);\n\t\t\t}\n\t\t}\n\t\tcombined.addAll(0, processing);\n\t\treturn combined;\n\t}\n\n\tprivate boolean isReplacement(HttpMessageConverter<?> defaultConverter, HttpMessageConverter<?> candidate) {\n\t\tfor (Class<?> nonReplacingConverter : NON_REPLACING_CONVERTERS) {\n\t\t\tif (nonReplacingConverter.isInstance(candidate)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tClass<?> converterClass = defaultConverter.getClass();\n\t\tif (ClassUtils.isAssignableValue(converterClass, candidate)) {\n\t\t\treturn true;\n\t\t}\n\t\tList<Class<?>> equivalentClasses = EQUIVALENT_CONVERTERS.get(converterClass);\n\t\treturn (equivalentClasses != null) && equivalentClasses.stream()\n\t\t\t.anyMatch((equivalentClass) -> equivalentClass != null\n\t\t\t\t\t&& ClassUtils.isAssignableValue(equivalentClass, candidate));\n\t}\n\n\tprivate void configurePartConverters(AllEncompassingFormHttpMessageConverter formConverter,\n\t\t\tCollection<HttpMessageConverter<?>> converters) {\n\t\tList<HttpMessageConverter<?>> partConverters = formConverter.getPartConverters();\n\t\tList<HttpMessageConverter<?>> combinedConverters = getCombinedConverters(converters, partConverters);\n\t\tcombinedConverters = postProcessPartConverters(combinedConverters);\n\t\tformConverter.setPartConverters(combinedConverters);\n\t}\n\n\t/**\n\t * Method that can be used to post-process the {@link HttpMessageConverter} list\n\t * before it is used.\n\t * @param converters a mutable list of the converters that will be used.\n\t * @return the final converts list to use\n\t */\n\tprotected List<HttpMessageConverter<?>> postProcessConverters(List<HttpMessageConverter<?>> converters) {\n\t\treturn converters;\n\t}\n\n\t/**\n\t * Method that can be used to post-process the {@link HttpMessageConverter} list\n\t * before it is used to configure the part converters of\n\t * {@link AllEncompassingFormHttpMessageConverter}.\n\t * @param converters a mutable list of the converters that will be used.\n\t * @return the final converts list to use\n\t */\n\tprotected List<HttpMessageConverter<?>> postProcessPartConverters(List<HttpMessageConverter<?>> converters) {\n\t\treturn converters;\n\t}\n\n\tprivate List<HttpMessageConverter<?>> getDefaultConverters() {\n\t\tList<HttpMessageConverter<?>> converters = new ArrayList<>();\n\t\tif (ClassUtils.isPresent(\"org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport\",\n\t\t\t\tnull)) {\n\t\t\tconverters.addAll(new WebMvcConfigurationSupport() {\n\n\t\t\t\tpublic List<HttpMessageConverter<?>> defaultMessageConverters() {\n\t\t\t\t\treturn super.getMessageConverters();\n\t\t\t\t}\n\n\t\t\t}.defaultMessageConverters());\n\t\t}\n\t\telse {\n\t\t\tconverters.addAll(new RestTemplate().getMessageConverters());\n\t\t}\n\t\treorderXmlConvertersToEnd(converters);\n\t\treturn converters;\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate void reorderXmlConvertersToEnd(List<HttpMessageConverter<?>> converters) {\n\t\tList<HttpMessageConverter<?>> xml = new ArrayList<>();\n\t\tfor (Iterator<HttpMessageConverter<?>> iterator = converters.iterator(); iterator.hasNext();) {\n\t\t\tHttpMessageConverter<?> converter = iterator.next();\n\t\t\tif ((converter instanceof AbstractXmlHttpMessageConverter)\n\t\t\t\t\t|| (converter instanceof org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter)) {\n\t\t\t\txml.add(converter);\n\t\t\t\titerator.remove();\n\t\t\t}\n\t\t}\n\t\tconverters.addAll(xml);\n\t}\n\n\t@Override\n\tpublic Iterator<HttpMessageConverter<?>> iterator() {\n\t\treturn getConverters().iterator();\n\t}\n\n\t/**\n\t * Return an immutable list of the converters in the order that they will be\n\t * registered.\n\t * @return the converters\n\t */\n\tpublic List<HttpMessageConverter<?>> getConverters() {\n\t\treturn this.converters;\n\t}\n\n\tprivate static void addClassIfExists(List<Class<?>> list, String className) {\n\t\ttry {\n\t\t\tlist.add(Class.forName(className));\n\t\t}\n\t\tcatch (ClassNotFoundException | NoClassDefFoundError ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate static void putIfExists(MultiValueMap<Class<?>, Class<?>> map, String keyClassName,\n\t\t\tString... valueClassNames) {\n\t\tfor (String valueClassName : valueClassNames) {\n\t\t\ttry {\n\t\t\t\tmap.add(Class.forName(keyClassName), Class.forName(valueClassName));\n\t\t\t}\n\t\t\tcatch (ClassNotFoundException | NoClassDefFoundError ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration.NotReactiveWebApplicationCondition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.StringHttpMessageConverter;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HttpMessageConverter}s.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Piotr Maj\n * @author Oliver Gierke\n * @author David Liu\n * @author Andy Wilkinson\n * @author Sebastien Deleuze\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Dmitry Sulman\n * @author Brian Clozel\n * @since 4.0.0\n */\n@SuppressWarnings(\"removal\")\n@AutoConfiguration(afterName = { \"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\",\n\t\t\"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\",\n\t\t\"org.springframework.boot.jsonb.autoconfigure.JsonbAutoConfiguration\",\n\t\t\"org.springframework.boot.gson.autoconfigure.GsonAutoConfiguration\",\n\t\t\"org.springframework.boot.kotlinx.serialization.json.autoconfigure.KotlinxSerializationJsonAutoConfiguration\" })\n@ConditionalOnClass(HttpMessageConverter.class)\n@Conditional(NotReactiveWebApplicationCondition.class)\n@Import({ JacksonHttpMessageConvertersConfiguration.class, Jackson2HttpMessageConvertersConfiguration.class,\n\t\tGsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class,\n\t\tKotlinSerializationHttpMessageConvertersConfiguration.class })\npublic final class HttpMessageConvertersAutoConfiguration {\n\n\tstatic final String PREFERRED_MAPPER_PROPERTY = \"spring.http.converters.preferred-json-mapper\";\n\n\t@Bean\n\t@Order(0)\n\t@SuppressWarnings(\"deprecation\")\n\tClientHttpMessageConvertersCustomizer clientConvertersCustomizer(\n\t\t\tObjectProvider<HttpMessageConverters> legacyConverters,\n\t\t\tObjectProvider<HttpMessageConverter<?>> converters) {\n\t\treturn new DefaultClientHttpMessageConvertersCustomizer(legacyConverters.getIfAvailable(),\n\t\t\t\tconverters.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@Order(0)\n\t@SuppressWarnings(\"deprecation\")\n\tServerHttpMessageConvertersCustomizer serverConvertersCustomizer(\n\t\t\tObjectProvider<HttpMessageConverters> legacyConverters,\n\t\t\tObjectProvider<HttpMessageConverter<?>> converters) {\n\t\treturn new DefaultServerHttpMessageConvertersCustomizer(legacyConverters.getIfAvailable(),\n\t\t\t\tconverters.orderedStream().toList());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(HttpMessageConvertersProperties.class)\n\tprotected static class StringHttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(StringHttpMessageConverter.class)\n\t\tStringHttpMessageConvertersCustomizer stringHttpMessageConvertersCustomizer(\n\t\t\t\tHttpMessageConvertersProperties properties) {\n\t\t\treturn new StringHttpMessageConvertersCustomizer(properties);\n\t\t}\n\n\t}\n\n\tstatic class StringHttpMessageConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tStringHttpMessageConverter converter;\n\n\t\tStringHttpMessageConvertersCustomizer(HttpMessageConvertersProperties properties) {\n\t\t\tthis.converter = new StringHttpMessageConverter(properties.getStringEncodingCharset());\n\t\t\tthis.converter.setWriteAcceptCharset(false);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withStringConverter(this.converter);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withStringConverter(this.converter);\n\t\t}\n\n\t}\n\n\tstatic class NotReactiveWebApplicationCondition extends NoneNestedConditions {\n\n\t\tNotReactiveWebApplicationCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t\tprivate static final class ReactiveWebApplication {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for HTTP message conversion.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.http.converters\")\npublic class HttpMessageConvertersProperties {\n\n\t/**\n\t * Charset to use for String conversion.\n\t */\n\tprivate Charset stringEncodingCharset = StandardCharsets.UTF_8;\n\n\tpublic Charset getStringEncodingCharset() {\n\t\treturn this.stringEncodingCharset;\n\t}\n\n\tpublic void setStringEncodingCharset(Charset stringEncodingCharset) {\n\t\tthis.stringEncodingCharset = stringEncodingCharset;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/Jackson2HttpMessageConvertersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.dataformat.xml.XmlMapper;\n\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.http.converter.autoconfigure.JacksonHttpMessageConvertersConfiguration.JacksonJsonHttpMessageConvertersCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;\n\n/**\n * Configuration for HTTP message converters that use Jackson 2.\n *\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@Configuration(proxyBeanMethods = false)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass Jackson2HttpMessageConvertersConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ObjectMapper.class)\n\t@ConditionalOnBean(ObjectMapper.class)\n\t@Conditional(PreferJackson2OrJacksonUnavailableCondition.class)\n\tstatic class MappingJackson2HttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnMissingBean(org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class)\n\t\tJackson2JsonMessageConvertersCustomizer jackson2HttpMessageConvertersCustomizer(ObjectMapper objectMapper) {\n\t\t\treturn new Jackson2JsonMessageConvertersCustomizer(objectMapper);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(XmlMapper.class)\n\t@ConditionalOnBean(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class)\n\tprotected static class MappingJackson2XmlHttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnMissingBean(org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter.class)\n\t\tJackson2XmlMessageConvertersCustomizer mappingJackson2XmlHttpMessageConverter(\n\t\t\t\tJackson2ObjectMapperBuilder builder) {\n\t\t\treturn new Jackson2XmlMessageConvertersCustomizer(builder.createXmlMapper(true).build());\n\t\t}\n\n\t}\n\n\tstatic class Jackson2JsonMessageConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final ObjectMapper objectMapper;\n\n\t\tJackson2JsonMessageConvertersCustomizer(ObjectMapper objectMapper) {\n\t\t\tthis.objectMapper = objectMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withJsonConverter(\n\t\t\t\t\tnew org.springframework.http.converter.json.MappingJackson2HttpMessageConverter(this.objectMapper));\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withJsonConverter(\n\t\t\t\t\tnew org.springframework.http.converter.json.MappingJackson2HttpMessageConverter(this.objectMapper));\n\t\t}\n\n\t}\n\n\tstatic class Jackson2XmlMessageConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final ObjectMapper objectMapper;\n\n\t\tJackson2XmlMessageConvertersCustomizer(ObjectMapper objectMapper) {\n\t\t\tthis.objectMapper = objectMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withXmlConverter(new org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter(\n\t\t\t\t\tthis.objectMapper));\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withXmlConverter(new org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter(\n\t\t\t\t\tthis.objectMapper));\n\t\t}\n\n\t}\n\n\tprivate static class PreferJackson2OrJacksonUnavailableCondition extends AnyNestedCondition {\n\n\t\tPreferJackson2OrJacksonUnavailableCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,\n\t\t\t\thavingValue = \"jackson2\")\n\t\tstatic class Jackson2Preferred {\n\n\t\t}\n\n\t\t@ConditionalOnMissingBean(JacksonJsonHttpMessageConvertersCustomizer.class)\n\t\tstatic class JacksonUnavailable {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/JacksonHttpMessageConvertersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.dataformat.xml.XmlMapper;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;\n\n/**\n * Configuration for HTTP message converters that use Jackson.\n *\n * @author Andy Wilkinson\n * @author Brian Clozel\n */\n@Configuration(proxyBeanMethods = false)\nclass JacksonHttpMessageConvertersConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JsonMapper.class)\n\t@ConditionalOnBean(JsonMapper.class)\n\t@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,\n\t\t\thavingValue = \"jackson\", matchIfMissing = true)\n\tstatic class JacksonJsonHttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnMissingBean(value = JacksonJsonHttpMessageConverter.class,\n\t\t\t\tignoredType = { \"org.springframework.hateoas.server.mvc.TypeConstrainedJacksonJsonHttpMessageConverter\",\n\t\t\t\t\t\t\"org.springframework.data.rest.webmvc.alps.AlpsJacksonJsonHttpMessageConverter\" })\n\t\tJacksonJsonHttpMessageConvertersCustomizer jacksonJsonHttpMessageConvertersCustomizer(JsonMapper jsonMapper) {\n\t\t\treturn new JacksonJsonHttpMessageConvertersCustomizer(jsonMapper);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(XmlMapper.class)\n\t@ConditionalOnBean(XmlMapper.class)\n\tprotected static class JacksonXmlHttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnMissingBean(JacksonXmlHttpMessageConverter.class)\n\t\tJacksonXmlHttpMessageConvertersCustomizer jacksonXmlHttpMessageConvertersCustomizer(XmlMapper xmlMapper) {\n\t\t\treturn new JacksonXmlHttpMessageConvertersCustomizer(xmlMapper);\n\t\t}\n\n\t}\n\n\tstatic class JacksonJsonHttpMessageConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final JsonMapper jsonMapper;\n\n\t\tJacksonJsonHttpMessageConvertersCustomizer(JsonMapper jsonMapper) {\n\t\t\tthis.jsonMapper = jsonMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withJsonConverter(new JacksonJsonHttpMessageConverter(this.jsonMapper));\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withJsonConverter(new JacksonJsonHttpMessageConverter(this.jsonMapper));\n\t\t}\n\n\t}\n\n\tstatic class JacksonXmlHttpMessageConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final XmlMapper xmlMapper;\n\n\t\tJacksonXmlHttpMessageConvertersCustomizer(XmlMapper xmlMapper) {\n\t\t\tthis.xmlMapper = xmlMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withXmlConverter(new JacksonXmlHttpMessageConverter(this.xmlMapper));\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withXmlConverter(new JacksonXmlHttpMessageConverter(this.xmlMapper));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/JsonbHttpMessageConvertersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport jakarta.json.bind.Jsonb;\n\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.http.converter.autoconfigure.GsonHttpMessageConvertersConfiguration.GsonHttpConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.JacksonHttpMessageConvertersConfiguration.JacksonJsonHttpMessageConvertersCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.JsonbHttpMessageConverter;\n\n/**\n * Configuration for HTTP Message converters that use JSON-B.\n *\n * @author Eddú Meléndez\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(Jsonb.class)\nclass JsonbHttpMessageConvertersConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(Jsonb.class)\n\t@Conditional(PreferJsonbOrMissingJacksonAndGsonCondition.class)\n\tstatic class JsonbHttpMessageConverterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnMissingBean(JsonbHttpMessageConverter.class)\n\t\tJsonbHttpMessageConvertersCustomizer jsonbHttpMessageConvertersCustomizer(Jsonb jsonb) {\n\t\t\treturn new JsonbHttpMessageConvertersCustomizer(jsonb);\n\t\t}\n\n\t}\n\n\tstatic class JsonbHttpMessageConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final JsonbHttpMessageConverter converter;\n\n\t\tJsonbHttpMessageConvertersCustomizer(Jsonb jsonb) {\n\t\t\tthis.converter = new JsonbHttpMessageConverter(jsonb);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withJsonConverter(this.converter);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withJsonConverter(this.converter);\n\t\t}\n\n\t}\n\n\tprivate static class PreferJsonbOrMissingJacksonAndGsonCondition extends AnyNestedCondition {\n\n\t\tPreferJsonbOrMissingJacksonAndGsonCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY,\n\t\t\t\thavingValue = \"jsonb\")\n\t\tstatic class JsonbPreferred {\n\n\t\t}\n\n\t\t@SuppressWarnings(\"removal\")\n\t\t@ConditionalOnMissingBean({ JacksonJsonHttpMessageConvertersCustomizer.class,\n\t\t\t\tJackson2HttpMessageConvertersConfiguration.Jackson2JsonMessageConvertersCustomizer.class,\n\t\t\t\tGsonHttpConvertersCustomizer.class })\n\t\tstatic class JacksonAndGsonMissing {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/KotlinSerializationHttpMessageConvertersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport kotlinx.serialization.Serializable;\nimport kotlinx.serialization.json.Json;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Configuration for HTTP message converters that use Kotlin Serialization.\n *\n * @author Brian Clozel\n * @author Dmitry Sulman\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass({ Serializable.class, Json.class })\n@ConditionalOnBean(Json.class)\nclass KotlinSerializationHttpMessageConvertersConfiguration {\n\n\t@Bean\n\t@Order(0)\n\t@ConditionalOnMissingBean(KotlinSerializationJsonHttpMessageConverter.class)\n\tKotlinSerializationJsonConvertersCustomizer kotlinSerializationJsonConvertersCustomizer(Json json,\n\t\t\tResourceLoader resourceLoader) {\n\t\treturn new KotlinSerializationJsonConvertersCustomizer(json, resourceLoader);\n\t}\n\n\tstatic class KotlinSerializationJsonConvertersCustomizer\n\t\t\timplements ClientHttpMessageConvertersCustomizer, ServerHttpMessageConvertersCustomizer {\n\n\t\tprivate final KotlinSerializationJsonHttpMessageConverter converter;\n\n\t\tKotlinSerializationJsonConvertersCustomizer(Json json, ResourceLoader resourceLoader) {\n\t\t\tClassLoader classLoader = resourceLoader.getClassLoader();\n\t\t\tboolean hasAnyJsonSupport = ClassUtils.isPresent(\"tools.jackson.databind.json.JsonMapper\", classLoader)\n\t\t\t\t\t|| ClassUtils.isPresent(\"com.fasterxml.jackson.databind.ObjectMapper\", classLoader)\n\t\t\t\t\t|| ClassUtils.isPresent(\"com.google.gson.Gson\", classLoader);\n\t\t\tthis.converter = hasAnyJsonSupport ? new KotlinSerializationJsonHttpMessageConverter(json)\n\t\t\t\t\t: new KotlinSerializationJsonHttpMessageConverter(json, (type) -> true);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ClientBuilder builder) {\n\t\t\tbuilder.withKotlinSerializationJsonConverter(this.converter);\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ServerBuilder builder) {\n\t\t\tbuilder.withKotlinSerializationJsonConverter(this.converter);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/MessageConverterBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;\n\n/**\n * {@link BackgroundPreinitializer} Spring's {@link HttpMessageConverter} implementations.\n *\n * @author Phillip Webb\n */\nfinal class MessageConverterBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tnew AllEncompassingFormHttpMessageConverter();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/ServerHttpMessageConvertersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\n\n/**\n * Callback interface that can be used to customize a {@link HttpMessageConverters} for\n * server usage.\n *\n * @author Brian Clozel\n * @since 4.0\n */\n@FunctionalInterface\npublic interface ServerHttpMessageConvertersCustomizer {\n\n\t/**\n\t * Callback to customize a {@link ServerBuilder} instance.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(ServerBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/java/org/springframework/boot/http/converter/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for HTTP converters.\n */\n@NullMarked\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.http.converters.preferred-json-mapper\",\n      \"type\": \"java.lang.String\",\n      \"defaultValue\": \"jackson\",\n      \"description\": \"Preferred JSON mapper to use for HTTP message conversion. By default, auto-detected according to the environment. Supported values are 'jackson', 'jackson2' (deprecated), 'gson' and 'jsonb'. When other JSON mapping libraries are present, use a custom HttpMessageConverters bean to control the preferred mapper.\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.http.converters.preferred-json-mapper\",\n      \"values\": [\n        {\n          \"value\": \"gson\"\n        },\n        {\n          \"value\": \"jackson\"\n        },\n        {\n          \"value\": \"jackson2\"\n        },\n        {\n          \"value\": \"jsonb\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/main/resources/META-INF/spring.factories",
    "content": "# Background Preinitializers\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer=\\\norg.springframework.boot.http.converter.autoconfigure.MessageConverterBackgroundPreinitializer\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.google.gson.Gson;\nimport jakarta.json.bind.Jsonb;\nimport jakarta.json.bind.JsonbBuilder;\nimport kotlinx.serialization.json.Json;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.dataformat.xml.XmlMapper;\n\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.http.converter.autoconfigure.GsonHttpMessageConvertersConfiguration.GsonHttpConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.JacksonHttpMessageConvertersConfiguration.JacksonJsonHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.JacksonHttpMessageConvertersConfiguration.JacksonXmlHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.JsonbHttpMessageConvertersConfiguration.JsonbHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.KotlinSerializationHttpMessageConvertersConfiguration.KotlinSerializationJsonConvertersCustomizer;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.rest.webmvc.alps.AlpsJacksonJsonHttpMessageConverter;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;\nimport org.springframework.hateoas.RepresentationModel;\nimport org.springframework.hateoas.mediatype.hal.forms.HalFormsHttpMessageConverter;\nimport org.springframework.hateoas.server.mvc.TypeConstrainedJacksonJsonHttpMessageConverter;\nimport org.springframework.http.HttpInputMessage;\nimport org.springframework.http.HttpOutputMessage;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.AbstractHttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.HttpMessageNotReadableException;\nimport org.springframework.http.converter.HttpMessageNotWritableException;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.http.converter.json.GsonHttpMessageConverter;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.http.converter.json.JsonbHttpMessageConverter;\nimport org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;\nimport org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpMessageConvertersAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author David Liu\n * @author Andy Wilkinson\n * @author Sebastien Deleuze\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Sebastien Deleuze\n * @author Dmitry Sulman\n * @author Brian Clozel\n */\nclass HttpMessageConvertersAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class));\n\n\t@Test\n\tvoid jacksonNotAvailable() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JsonMapper.class.getPackage().getName()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(JsonMapper.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(JacksonXmlHttpMessageConvertersCustomizer.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonDefaultConverter() {\n\t\tthis.contextRunner.withUserConfiguration(JacksonJsonMapperConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\tassertConverterIsRegistered(context, JacksonJsonHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonServerCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJsonConverterConfig.class).run((context) -> {\n\t\t\tassertConverterIsNotRegistered(context, JacksonJsonHttpMessageConverter.class);\n\t\t\tassertConverterIsRegistered(context, CustomConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonConverterWithBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(JacksonJsonMapperBuilderConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\tassertConverterIsRegistered(context, JacksonJsonHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonXmlConverterWithBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(JacksonXmlMapperBuilderConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JacksonXmlHttpMessageConvertersCustomizer.class);\n\t\t\tassertConverterIsRegistered(context, JacksonXmlHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonCustomConverter() {\n\t\tthis.contextRunner.withUserConfiguration(JacksonJsonMapperConfig.class, JacksonConverterConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\t\tHttpMessageConverters serverConverters = getServerConverters(context);\n\t\t\t\tassertThat(serverConverters)\n\t\t\t\t\t.contains(context.getBean(\"customJacksonMessageConverter\", JacksonJsonHttpMessageConverter.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonServerAndClientConvertersShouldBeDifferent() {\n\t\tthis.contextRunner.withUserConfiguration(JacksonJsonMapperConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\tJacksonJsonHttpMessageConverter serverConverter = findConverter(getServerConverters(context),\n\t\t\t\t\tJacksonJsonHttpMessageConverter.class);\n\t\t\tJacksonJsonHttpMessageConverter clientConverter = findConverter(getClientConverters(context),\n\t\t\t\t\tJacksonJsonHttpMessageConverter.class);\n\t\t\tassertThat(serverConverter).isNotEqualTo(clientConverter);\n\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid jackson2DefaultConverter() {\n\t\tthis.contextRunner.withUserConfiguration(Jackson2ObjectMapperConfig.class)\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> assertConverterIsRegistered(context,\n\t\t\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid jackson2ConverterWithBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(Jackson2ObjectMapperBuilderConfig.class)\n\t\t\t.run((context) -> assertConverterIsRegistered(context,\n\t\t\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid jackson2CustomConverter() {\n\t\tthis.contextRunner.withUserConfiguration(Jackson2ObjectMapperConfig.class, Jackson2ConverterConfig.class)\n\t\t\t.run((context) -> assertConverterIsRegistered(context,\n\t\t\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class));\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid jackson2ServerAndClientJsonConvertersShouldBeDifferent() {\n\t\tthis.contextRunner.withUserConfiguration(Jackson2ObjectMapperConfig.class)\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(\n\t\t\t\t\t\tJackson2HttpMessageConvertersConfiguration.Jackson2JsonMessageConvertersCustomizer.class);\n\t\t\t\tHttpMessageConverter<?> serverConverter = findConverter(getServerConverters(context),\n\t\t\t\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class);\n\t\t\t\tHttpMessageConverter<?> clientConverter = findConverter(getClientConverters(context),\n\t\t\t\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class);\n\t\t\t\tassertThat(serverConverter).isNotEqualTo(clientConverter);\n\t\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid jackson2ServerAndClientXmlConvertersShouldBeDifferent() {\n\t\tthis.contextRunner.withUserConfiguration(Jackson2ObjectMapperConfig.class)\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(\n\t\t\t\t\t\tJackson2HttpMessageConvertersConfiguration.Jackson2XmlMessageConvertersCustomizer.class);\n\t\t\t\tHttpMessageConverter<?> serverConverter = findConverter(getServerConverters(context),\n\t\t\t\t\t\torg.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter.class);\n\t\t\t\tHttpMessageConverter<?> clientConverter = findConverter(getClientConverters(context),\n\t\t\t\t\t\torg.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter.class);\n\t\t\t\tassertThat(serverConverter).isNotEqualTo(clientConverter);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid gsonNotAvailable() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(Gson.class);\n\t\t\tassertConverterIsNotRegistered(context, GsonHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid gsonDefaultConverter() {\n\t\tthis.contextRunner.withBean(Gson.class)\n\t\t\t.run((context) -> assertConverterIsRegistered(context, GsonHttpMessageConverter.class));\n\t}\n\n\t@Test\n\tvoid gsonCustomConverter() {\n\t\tthis.contextRunner.withUserConfiguration(GsonConverterConfig.class)\n\t\t\t.withBean(Gson.class)\n\t\t\t.run((context) -> assertThat(getServerConverters(context))\n\t\t\t\t.contains(context.getBean(\"customGsonMessageConverter\", GsonHttpMessageConverter.class)));\n\t}\n\n\t@Test\n\tvoid gsonCanBePreferred() {\n\t\tallOptionsRunner().withPropertyValues(\"spring.http.converters.preferred-json-mapper:gson\").run((context) -> {\n\t\t\tassertConverterIsRegistered(context, GsonHttpMessageConverter.class);\n\t\t\tassertConverterIsNotRegistered(context, JsonbHttpMessageConverter.class);\n\t\t\tassertConverterIsNotRegistered(context, JacksonJsonHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jsonbNotAvailable() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(Jsonb.class);\n\t\t\tassertConverterIsNotRegistered(context, JsonbHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jsonbDefaultConverter() {\n\t\tthis.contextRunner.withBean(Jsonb.class, JsonbBuilder::create)\n\t\t\t.run((context) -> assertConverterIsRegistered(context, JsonbHttpMessageConverter.class));\n\t}\n\n\t@Test\n\tvoid jsonbCustomConverter() {\n\t\tthis.contextRunner.withUserConfiguration(JsonbConverterConfig.class)\n\t\t\t.withBean(Jsonb.class, JsonbBuilder::create)\n\t\t\t.run((context) -> assertThat(getServerConverters(context))\n\t\t\t\t.contains(context.getBean(\"customJsonbMessageConverter\", JsonbHttpMessageConverter.class)));\n\t}\n\n\t@Test\n\tvoid jsonbCanBePreferred() {\n\t\tallOptionsRunner().withPropertyValues(\"spring.http.converters.preferred-json-mapper:jsonb\").run((context) -> {\n\t\t\tassertConverterIsRegistered(context, JsonbHttpMessageConverter.class);\n\t\t\tassertConverterIsNotRegistered(context, GsonHttpMessageConverter.class);\n\t\t\tassertConverterIsNotRegistered(context, JacksonJsonHttpMessageConverter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid kotlinSerializationNotAvailable() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(Json.class);\n\t\t\tassertThat(context).doesNotHaveBean(KotlinSerializationJsonConvertersCustomizer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid kotlinSerializationCustomConverter() {\n\t\tthis.contextRunner.withUserConfiguration(KotlinSerializationConverterConfig.class)\n\t\t\t.withBean(Json.class, () -> Json.Default)\n\t\t\t.run((context) -> assertConverterIsRegistered(context, KotlinSerializationJsonHttpMessageConverter.class));\n\t}\n\n\t@Test\n\tvoid kotlinSerializationOrderedAheadOfJsonConverter() {\n\t\tallOptionsRunner().run((context) -> {\n\t\t\tassertConverterIsRegistered(context, KotlinSerializationJsonHttpMessageConverter.class);\n\t\t\tassertConvertersRegisteredWithHttpMessageConverters(context,\n\t\t\t\t\tList.of(KotlinSerializationJsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid kotlinSerializationUsesLimitedPredicateWhenOtherJsonConverterIsAvailable() {\n\t\tallOptionsRunner().run((context) -> {\n\t\t\tKotlinSerializationJsonHttpMessageConverter converter = findConverter(getServerConverters(context),\n\t\t\t\t\tKotlinSerializationJsonHttpMessageConverter.class);\n\t\t\tassertThat(converter.canWrite(Map.class, MediaType.APPLICATION_JSON)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid stringDefaultConverter() {\n\t\tthis.contextRunner.run((context) -> assertConverterIsRegistered(context, StringHttpMessageConverter.class));\n\t}\n\n\t@Test\n\tvoid stringCustomConverter() {\n\t\tthis.contextRunner.withUserConfiguration(StringConverterConfig.class).run((context) -> {\n\t\t\tassertThat(getClientConverters(context))\n\t\t\t\t.filteredOn((converter) -> converter instanceof StringHttpMessageConverter)\n\t\t\t\t.hasSize(2);\n\t\t\tassertThat(getServerConverters(context))\n\t\t\t\t.filteredOn((converter) -> converter instanceof StringHttpMessageConverter)\n\t\t\t\t.hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid typeConstrainedConverterDoesNotPreventAutoConfigurationOfJacksonConverter() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(JacksonJsonMapperBuilderConfig.class, TypeConstrainedConverterConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\t\tassertConvertersRegisteredWithHttpMessageConverters(context, List\n\t\t\t\t\t.of(TypeConstrainedJacksonJsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid typeConstrainedConverterFromSpringDataDoesNotPreventAutoConfigurationOfJacksonConverter() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(JacksonJsonMapperBuilderConfig.class, RepositoryRestMvcConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JacksonJsonHttpMessageConvertersCustomizer.class);\n\t\t\t\tassertConvertersRegisteredWithHttpMessageConverters(context, List.of(HalFormsHttpMessageConverter.class,\n\t\t\t\t\t\tAlpsJacksonJsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonIsPreferredByDefault() {\n\t\tallOptionsRunner().run((context) -> {\n\t\t\tassertBeanExists(context, JacksonJsonHttpMessageConvertersCustomizer.class,\n\t\t\t\t\t\"jacksonJsonHttpMessageConvertersCustomizer\");\n\t\t\tassertConverterIsRegistered(context, JacksonJsonHttpMessageConverter.class);\n\t\t\tassertThat(context).doesNotHaveBean(GsonHttpConvertersCustomizer.class);\n\t\t\tassertThat(context).doesNotHaveBean(JsonbHttpMessageConvertersCustomizer.class);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid jackson2IsPreferredIfJacksonIsNotAvailable() {\n\t\tallOptionsRunner().withClassLoader(new FilteredClassLoader(JsonMapper.class.getPackage().getName()))\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> {\n\t\t\t\tassertConverterIsRegistered(context,\n\t\t\t\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter.class);\n\t\t\t\tassertConverterIsNotRegistered(context, GsonHttpMessageConverter.class);\n\t\t\t\tassertConverterIsNotRegistered(context, JsonbHttpMessageConverter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid gsonIsPreferredIfJacksonAndJackson2AreNotAvailable() {\n\t\tallOptionsRunner()\n\t\t\t.withClassLoader(new FilteredClassLoader(JsonMapper.class.getPackage().getName(),\n\t\t\t\t\tObjectMapper.class.getPackage().getName()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertConverterIsRegistered(context, GsonHttpMessageConverter.class);\n\t\t\t\tassertConverterIsNotRegistered(context, JsonbHttpMessageConverter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jsonbIsPreferredIfJacksonAndGsonAreNotAvailable() {\n\t\tallOptionsRunner()\n\t\t\t.withClassLoader(new FilteredClassLoader(JsonMapper.class.getPackage().getName(),\n\t\t\t\t\tObjectMapper.class.getPackage().getName(), Gson.class.getPackage().getName()))\n\t\t\t.run((context) -> assertConverterIsRegistered(context, JsonbHttpMessageConverter.class));\n\t}\n\n\t@Test\n\tvoid whenServletWebApplicationHttpMessageConvertersIsConfigured() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DefaultClientHttpMessageConvertersCustomizer.class)\n\t\t\t\t.hasSingleBean(DefaultClientHttpMessageConvertersCustomizer.class));\n\t}\n\n\t@Test\n\tvoid whenReactiveWebApplicationHttpMessageConvertersIsNotConfigured() {\n\t\tnew ReactiveWebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServerHttpMessageConvertersCustomizer.class)\n\t\t\t\t.doesNotHaveBean(ClientHttpMessageConvertersCustomizer.class));\n\t}\n\n\t@Test\n\tvoid whenEncodingCharsetIsNotConfiguredThenStringMessageConverterUsesUtf8() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tStringHttpMessageConverter converter = findConverter(getServerConverters(context),\n\t\t\t\t\t\tStringHttpMessageConverter.class);\n\t\t\t\tassertThat(converter.getDefaultCharset()).isEqualTo(StandardCharsets.UTF_8);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenEncodingCharsetIsConfiguredThenStringMessageConverterUsesSpecificCharset() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.http.converters.string-encoding-charset=UTF-16\")\n\t\t\t.run((context) -> {\n\t\t\t\tStringHttpMessageConverter serverConverter = findConverter(getServerConverters(context),\n\t\t\t\t\t\tStringHttpMessageConverter.class);\n\t\t\t\tassertThat(serverConverter.getDefaultCharset()).isEqualTo(StandardCharsets.UTF_16);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultServerConvertersCustomizerHasOrderZero() {\n\t\tdefaultConvertersCustomizerHasOrderZero(DefaultServerHttpMessageConvertersCustomizer.class);\n\t}\n\n\t@Test\n\tvoid defaultClientConvertersCustomizerHasOrderZero() {\n\t\tdefaultConvertersCustomizerHasOrderZero(DefaultClientHttpMessageConvertersCustomizer.class);\n\t}\n\n\tprivate <T> void defaultConvertersCustomizerHasOrderZero(Class<T> customizerType) {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, T> customizers = context.getBeansOfType(customizerType);\n\t\t\t\tassertThat(customizers).hasSize(1);\n\t\t\t\tDefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();\n\t\t\t\tcustomizers.keySet().forEach((beanName) -> assertThat(beanFactory.getOrder(beanName)).isZero());\n\t\t\t});\n\t}\n\n\tprivate ApplicationContextRunner allOptionsRunner() {\n\t\treturn this.contextRunner.withBean(Gson.class)\n\t\t\t.withBean(JsonMapper.class)\n\t\t\t.withBean(ObjectMapper.class, ObjectMapper::new)\n\t\t\t.withBean(Jsonb.class, JsonbBuilder::create)\n\t\t\t.withBean(Json.class, () -> Json.Default);\n\t}\n\n\tprivate void assertConverterIsRegistered(AssertableApplicationContext context,\n\t\t\tClass<? extends HttpMessageConverter<?>> converterType) {\n\t\tassertThat(getClientConverters(context)).filteredOn((c) -> converterType.isAssignableFrom(c.getClass()))\n\t\t\t.hasSize(1);\n\t\tassertThat(getServerConverters(context)).filteredOn((c) -> converterType.isAssignableFrom(c.getClass()))\n\t\t\t.hasSize(1);\n\t}\n\n\tprivate void assertConverterIsNotRegistered(AssertableApplicationContext context,\n\t\t\tClass<? extends HttpMessageConverter<?>> converterType) {\n\t\tassertThat(getClientConverters(context)).filteredOn((c) -> converterType.isAssignableFrom(c.getClass()))\n\t\t\t.isEmpty();\n\t\tassertThat(getServerConverters(context)).filteredOn((c) -> converterType.isAssignableFrom(c.getClass()))\n\t\t\t.isEmpty();\n\t}\n\n\tprivate void assertBeanExists(AssertableApplicationContext context, Class<?> type, String beanName) {\n\t\tassertThat(context).getBean(beanName).isInstanceOf(type);\n\t\tassertThat(context).hasBean(beanName);\n\t}\n\n\tprivate HttpMessageConverters getClientConverters(ApplicationContext context) {\n\t\tClientBuilder clientBuilder = HttpMessageConverters.forClient().registerDefaults();\n\t\tcontext.getBeanProvider(ClientHttpMessageConvertersCustomizer.class)\n\t\t\t.orderedStream()\n\t\t\t.forEach((customizer) -> customizer.customize(clientBuilder));\n\t\treturn clientBuilder.build();\n\t}\n\n\tprivate HttpMessageConverters getServerConverters(ApplicationContext context) {\n\t\tServerBuilder serverBuilder = HttpMessageConverters.forServer().registerDefaults();\n\t\tcontext.getBeanProvider(ServerHttpMessageConvertersCustomizer.class)\n\t\t\t.orderedStream()\n\t\t\t.forEach((customizer) -> customizer.customize(serverBuilder));\n\t\treturn serverBuilder.build();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T extends HttpMessageConverter<?>> T findConverter(HttpMessageConverters converters,\n\t\t\tClass<? extends HttpMessageConverter<?>> type) {\n\t\tfor (HttpMessageConverter<?> converter : converters) {\n\t\t\tif (type.isAssignableFrom(converter.getClass())) {\n\t\t\t\treturn (T) converter;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Could not find converter of type \" + type);\n\t}\n\n\tprivate void assertConvertersRegisteredWithHttpMessageConverters(AssertableApplicationContext context,\n\t\t\tList<Class<? extends HttpMessageConverter<?>>> types) {\n\t\tHttpMessageConverters clientConverters = getClientConverters(context);\n\t\tList<Class<?>> clientConverterTypes = new ArrayList<>();\n\t\tclientConverters.forEach((converter) -> clientConverterTypes.add(converter.getClass()));\n\t\tassertThat(clientConverterTypes).containsSubsequence(types);\n\n\t\tHttpMessageConverters serverConverters = getServerConverters(context);\n\t\tList<Class<?>> serverConverterTypes = new ArrayList<>();\n\t\tserverConverters.forEach((converter) -> serverConverterTypes.add(converter.getClass()));\n\t\tassertThat(serverConverterTypes).containsSubsequence(types);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JacksonJsonMapperConfig {\n\n\t\t@Bean\n\t\tJsonMapper jsonMapper() {\n\t\t\treturn new JsonMapper();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJsonConverterConfig {\n\n\t\t@Bean\n\t\tJsonMapper jsonMapper() {\n\t\t\treturn new JsonMapper();\n\t\t}\n\n\t\t@Bean\n\t\tServerHttpMessageConvertersCustomizer jsonServerCustomizer() {\n\t\t\treturn (configurer) -> configurer.withJsonConverter(new CustomConverter(MediaType.APPLICATION_JSON));\n\t\t}\n\n\t\t@Bean\n\t\tClientHttpMessageConvertersCustomizer jsonClientCustomizer() {\n\t\t\treturn (configurer) -> configurer.withJsonConverter(new CustomConverter(MediaType.APPLICATION_JSON));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JacksonJsonMapperBuilderConfig {\n\n\t\t@Bean\n\t\tJsonMapper jsonMapper() {\n\t\t\treturn new JsonMapper();\n\t\t}\n\n\t\t@Bean\n\t\tJsonMapper.Builder builder() {\n\t\t\treturn JsonMapper.builder();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JacksonXmlMapperBuilderConfig {\n\n\t\t@Bean\n\t\tXmlMapper xmlMapper() {\n\t\t\treturn new XmlMapper();\n\t\t}\n\n\t\t@Bean\n\t\tXmlMapper.Builder builder() {\n\t\t\treturn XmlMapper.builder();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JacksonConverterConfig {\n\n\t\t@Bean\n\t\tJacksonJsonHttpMessageConverter customJacksonMessageConverter(JsonMapper jsonMapperMapper) {\n\t\t\tJacksonJsonHttpMessageConverter converter = new JacksonJsonHttpMessageConverter(jsonMapperMapper);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@SuppressWarnings(\"removal\")\n\tstatic class Jackson2ObjectMapperConfig {\n\n\t\t@Bean\n\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder objectMapperBuilder() {\n\t\t\treturn new org.springframework.http.converter.json.Jackson2ObjectMapperBuilder();\n\t\t}\n\n\t\t@Bean\n\t\tObjectMapper objectMapper() {\n\t\t\treturn new ObjectMapper();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tstatic class Jackson2ObjectMapperBuilderConfig {\n\n\t\t@Bean\n\t\tObjectMapper objectMapper() {\n\t\t\treturn new ObjectMapper();\n\t\t}\n\n\t\t@Bean\n\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder() {\n\t\t\treturn new org.springframework.http.converter.json.Jackson2ObjectMapperBuilder();\n\t\t}\n\n\t}\n\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@Configuration(proxyBeanMethods = false)\n\t@SuppressWarnings(\"removal\")\n\tstatic class Jackson2ConverterConfig {\n\n\t\t@Bean\n\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter customJacksonMessageConverter(\n\t\t\t\tObjectMapper objectMapper) {\n\t\t\torg.springframework.http.converter.json.MappingJackson2HttpMessageConverter converter = new org.springframework.http.converter.json.MappingJackson2HttpMessageConverter();\n\t\t\tconverter.setObjectMapper(objectMapper);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class GsonConverterConfig {\n\n\t\t@Bean\n\t\tGsonHttpMessageConverter customGsonMessageConverter(Gson gson) {\n\t\t\tGsonHttpMessageConverter converter = new GsonHttpMessageConverter();\n\t\t\tconverter.setGson(gson);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JsonbConverterConfig {\n\n\t\t@Bean\n\t\tJsonbHttpMessageConverter customJsonbMessageConverter(Jsonb jsonb) {\n\t\t\tJsonbHttpMessageConverter converter = new JsonbHttpMessageConverter();\n\t\t\tconverter.setJsonb(jsonb);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class KotlinSerializationConverterConfig {\n\n\t\t@Bean\n\t\tKotlinSerializationJsonHttpMessageConverter customKotlinSerializationJsonHttpMessageConverter(Json json) {\n\t\t\treturn new KotlinSerializationJsonHttpMessageConverter(json);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StringConverterConfig {\n\n\t\t@Bean\n\t\tStringHttpMessageConverter customStringMessageConverter() {\n\t\t\treturn new StringHttpMessageConverter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TypeConstrainedConverterConfiguration {\n\n\t\t@Bean\n\t\tTypeConstrainedJacksonJsonHttpMessageConverter typeConstrainedConverter() {\n\t\t\treturn new TypeConstrainedJacksonJsonHttpMessageConverter(RepresentationModel.class);\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"NullAway\")\n\tstatic class CustomConverter extends AbstractHttpMessageConverter<Object> {\n\n\t\tCustomConverter(MediaType supportedMediaType) {\n\t\t\tsuper(supportedMediaType);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean supports(Class<?> clazz) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tprotected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)\n\t\t\t\tthrows IOException, HttpMessageNotReadableException {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tprotected void writeInternal(Object o, HttpOutputMessage outputMessage)\n\t\t\t\tthrows IOException, HttpMessageNotWritableException {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersAutoConfigurationWithoutJacksonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HttpMessageConvertersAutoConfiguration} without Jackson on the\n * classpath.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"jackson-*.jar\")\nclass HttpMessageConvertersAutoConfigurationWithoutJacksonTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationWorksWithSpringHateoasButWithoutJackson() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"clientConvertersCustomizer\")\n\t\t\t.hasBean(\"serverConvertersCustomizer\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-http-converter/src/test/java/org/springframework/boot/http/converter/autoconfigure/HttpMessageConvertersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.http.converter.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.converter.ByteArrayHttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.ResourceHttpMessageConverter;\nimport org.springframework.http.converter.ResourceRegionHttpMessageConverter;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.http.converter.cbor.JacksonCborHttpMessageConverter;\nimport org.springframework.http.converter.json.GsonHttpMessageConverter;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.http.converter.json.KotlinSerializationJsonHttpMessageConverter;\nimport org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;\nimport org.springframework.http.converter.xml.JacksonXmlHttpMessageConverter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpMessageConverters}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\n@SuppressWarnings(\"deprecation\")\nclass HttpMessageConvertersTests {\n\n\t@Test\n\tvoid containsDefaults() {\n\t\tHttpMessageConverters converters = new HttpMessageConverters();\n\t\tList<Class<?>> converterClasses = new ArrayList<>();\n\t\tfor (HttpMessageConverter<?> converter : converters) {\n\t\t\tconverterClasses.add(converter.getClass());\n\t\t}\n\t\tassertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,\n\t\t\t\tStringHttpMessageConverter.class, ResourceHttpMessageConverter.class,\n\t\t\t\tResourceRegionHttpMessageConverter.class, AllEncompassingFormHttpMessageConverter.class,\n\t\t\t\tKotlinSerializationJsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class,\n\t\t\t\tJacksonCborHttpMessageConverter.class, JacksonXmlHttpMessageConverter.class);\n\t}\n\n\t@Test\n\tvoid addBeforeExistingConverter() {\n\t\tJacksonJsonHttpMessageConverter converter1 = new JacksonJsonHttpMessageConverter();\n\t\tJacksonJsonHttpMessageConverter converter2 = new JacksonJsonHttpMessageConverter();\n\t\tHttpMessageConverters converters = new HttpMessageConverters(converter1, converter2);\n\t\tassertThat(converters.getConverters()).contains(converter1);\n\t\tassertThat(converters.getConverters()).contains(converter2);\n\t\tList<JacksonJsonHttpMessageConverter> httpConverters = new ArrayList<>();\n\t\tfor (HttpMessageConverter<?> candidate : converters) {\n\t\t\tif (candidate instanceof JacksonJsonHttpMessageConverter jsonConverter) {\n\t\t\t\thttpConverters.add(jsonConverter);\n\t\t\t}\n\t\t}\n\t\t// The existing converter is still there, but with a lower priority\n\t\tassertThat(httpConverters).hasSize(3);\n\t\tassertThat(httpConverters.indexOf(converter1)).isZero();\n\t\tassertThat(httpConverters.indexOf(converter2)).isOne();\n\t\tassertThat(converters.getConverters().indexOf(converter1)).isNotZero();\n\t}\n\n\t@Test\n\tvoid addBeforeExistingEquivalentConverter() {\n\t\tGsonHttpMessageConverter converter1 = new GsonHttpMessageConverter();\n\t\tHttpMessageConverters converters = new HttpMessageConverters(converter1);\n\t\tStream<Class<?>> converterClasses = converters.getConverters().stream().map(HttpMessageConverter::getClass);\n\t\tassertThat(converterClasses).containsSequence(KotlinSerializationJsonHttpMessageConverter.class,\n\t\t\t\tGsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class);\n\t}\n\n\t@Test\n\tvoid addBeforeExistingAnotherEquivalentConverter() {\n\t\tKotlinSerializationJsonHttpMessageConverter converter1 = new KotlinSerializationJsonHttpMessageConverter();\n\t\tHttpMessageConverters converters = new HttpMessageConverters(converter1);\n\t\tStream<Class<?>> converterClasses = converters.getConverters().stream().map(HttpMessageConverter::getClass);\n\t\tassertThat(converterClasses).containsSequence(KotlinSerializationJsonHttpMessageConverter.class,\n\t\t\t\tJacksonJsonHttpMessageConverter.class);\n\t}\n\n\t@Test\n\tvoid addBeforeExistingMultipleEquivalentConverters() {\n\t\tGsonHttpMessageConverter converter1 = new GsonHttpMessageConverter();\n\t\tKotlinSerializationJsonHttpMessageConverter converter2 = new KotlinSerializationJsonHttpMessageConverter();\n\t\tHttpMessageConverters converters = new HttpMessageConverters(converter1, converter2);\n\t\tStream<Class<?>> converterClasses = converters.getConverters().stream().map(HttpMessageConverter::getClass);\n\t\tassertThat(converterClasses).containsSequence(KotlinSerializationJsonHttpMessageConverter.class,\n\t\t\t\tGsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class);\n\t}\n\n\t@Test\n\tvoid addNewConverters() {\n\t\tHttpMessageConverter<?> converter1 = mock(HttpMessageConverter.class);\n\t\tHttpMessageConverter<?> converter2 = mock(HttpMessageConverter.class);\n\t\tHttpMessageConverters converters = new HttpMessageConverters(converter1, converter2);\n\t\tassertThat(converters.getConverters().get(0)).isEqualTo(converter1);\n\t\tassertThat(converters.getConverters().get(1)).isEqualTo(converter2);\n\t}\n\n\t@Test\n\tvoid convertersAreAddedToFormPartConverter() {\n\t\tHttpMessageConverter<?> converter1 = mock(HttpMessageConverter.class);\n\t\tHttpMessageConverter<?> converter2 = mock(HttpMessageConverter.class);\n\t\tList<HttpMessageConverter<?>> converters = new HttpMessageConverters(converter1, converter2).getConverters();\n\t\tList<HttpMessageConverter<?>> partConverters = extractFormPartConverters(converters);\n\t\tassertThat(partConverters.get(0)).isEqualTo(converter1);\n\t\tassertThat(partConverters.get(1)).isEqualTo(converter2);\n\t}\n\n\t@Test\n\tvoid postProcessConverters() {\n\t\tHttpMessageConverters converters = new HttpMessageConverters() {\n\n\t\t\t@Override\n\t\t\tprotected List<HttpMessageConverter<?>> postProcessConverters(List<HttpMessageConverter<?>> converters) {\n\t\t\t\tconverters.removeIf(JacksonXmlHttpMessageConverter.class::isInstance);\n\t\t\t\treturn converters;\n\t\t\t}\n\n\t\t};\n\t\tList<Class<?>> converterClasses = new ArrayList<>();\n\t\tfor (HttpMessageConverter<?> converter : converters) {\n\t\t\tconverterClasses.add(converter.getClass());\n\t\t}\n\t\tassertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,\n\t\t\t\tStringHttpMessageConverter.class, ResourceHttpMessageConverter.class,\n\t\t\t\tResourceRegionHttpMessageConverter.class, AllEncompassingFormHttpMessageConverter.class,\n\t\t\t\tKotlinSerializationJsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class,\n\t\t\t\tJacksonCborHttpMessageConverter.class);\n\t}\n\n\t@Test\n\tvoid postProcessPartConverters() {\n\t\tHttpMessageConverters converters = new HttpMessageConverters() {\n\n\t\t\t@Override\n\t\t\tprotected List<HttpMessageConverter<?>> postProcessPartConverters(\n\t\t\t\t\tList<HttpMessageConverter<?>> converters) {\n\t\t\t\tconverters.removeIf(JacksonXmlHttpMessageConverter.class::isInstance);\n\t\t\t\treturn converters;\n\t\t\t}\n\n\t\t};\n\t\tList<Class<?>> converterClasses = new ArrayList<>();\n\t\tfor (HttpMessageConverter<?> converter : extractFormPartConverters(converters.getConverters())) {\n\t\t\tconverterClasses.add(converter.getClass());\n\t\t}\n\t\tassertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,\n\t\t\t\tStringHttpMessageConverter.class, ResourceHttpMessageConverter.class,\n\t\t\t\tKotlinSerializationJsonHttpMessageConverter.class, JacksonJsonHttpMessageConverter.class,\n\t\t\t\tJacksonCborHttpMessageConverter.class);\n\t}\n\n\tprivate List<HttpMessageConverter<?>> extractFormPartConverters(List<HttpMessageConverter<?>> converters) {\n\t\tAllEncompassingFormHttpMessageConverter formConverter = findFormConverter(converters);\n\t\tassertThat(formConverter).isNotNull();\n\t\treturn formConverter.getPartConverters();\n\t}\n\n\tprivate @Nullable AllEncompassingFormHttpMessageConverter findFormConverter(\n\t\t\tCollection<HttpMessageConverter<?>> converters) {\n\t\tfor (HttpMessageConverter<?> converter : converters) {\n\t\t\tif (converter instanceof AllEncompassingFormHttpMessageConverter allEncompassingConverter) {\n\t\t\t\treturn allEncompassingConverter;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Integration\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.integration:spring-integration-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jdbc\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-rsocket\"))\n\toptional(\"org.springframework.integration:spring-integration-jdbc\")\n\toptional(\"org.springframework.integration:spring-integration-jmx\")\n\toptional(\"org.springframework.integration:spring-integration-rsocket\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-rsocket\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-sql\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-jersey\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webflux\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webmvc\")))\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(project(\":module:spring-boot-reactor-netty\"))\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/actuate/endpoint/IntegrationGraphEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.actuate.endpoint;\n\nimport java.util.Collection;\nimport java.util.Map;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.integration.graph.Graph;\nimport org.springframework.integration.graph.IntegrationGraphServer;\nimport org.springframework.integration.graph.IntegrationNode;\nimport org.springframework.integration.graph.LinkNode;\n\n/**\n * {@link Endpoint @Endpoint} to expose the Spring Integration graph.\n *\n * @author Tim Ysewyn\n * @since 4.0.0\n */\n@Endpoint(id = \"integrationgraph\")\npublic class IntegrationGraphEndpoint {\n\n\tprivate final IntegrationGraphServer graphServer;\n\n\t/**\n\t * Create a new {@code IntegrationGraphEndpoint} instance that exposes a graph\n\t * containing all the Spring Integration components in the given\n\t * {@link IntegrationGraphServer}.\n\t * @param graphServer the integration graph server\n\t */\n\tpublic IntegrationGraphEndpoint(IntegrationGraphServer graphServer) {\n\t\tthis.graphServer = graphServer;\n\t}\n\n\t@ReadOperation\n\tpublic GraphDescriptor graph() {\n\t\treturn new GraphDescriptor(this.graphServer.getGraph());\n\t}\n\n\t@WriteOperation\n\tpublic void rebuild() {\n\t\tthis.graphServer.rebuild();\n\t}\n\n\t/**\n\t * Description of a {@link Graph}.\n\t */\n\tpublic static class GraphDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<String, Object> contentDescriptor;\n\n\t\tprivate final Collection<IntegrationNode> nodes;\n\n\t\tprivate final Collection<LinkNode> links;\n\n\t\tGraphDescriptor(Graph graph) {\n\t\t\tthis.contentDescriptor = graph.contentDescriptor();\n\t\t\tthis.nodes = graph.nodes();\n\t\t\tthis.links = graph.links();\n\t\t}\n\n\t\tpublic Map<String, Object> getContentDescriptor() {\n\t\t\treturn this.contentDescriptor;\n\t\t}\n\n\t\tpublic Collection<IntegrationNode> getNodes() {\n\t\t\treturn this.nodes;\n\t\t}\n\n\t\tpublic Collection<LinkNode> getLinks() {\n\t\t\treturn this.links;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for Spring Integration.\n */\n@NullMarked\npackage org.springframework.boot.integration.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.time.Duration;\n\nimport javax.management.MBeanServer;\nimport javax.sql.DataSource;\n\nimport io.rsocket.transport.netty.server.TcpServerTransport;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.autoconfigure.jmx.JmxProperties;\nimport org.springframework.boot.autoconfigure.task.DefaultTaskSchedulerConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.OnDatabaseInitializationCondition;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.integration.config.EnableIntegration;\nimport org.springframework.integration.config.EnableIntegrationManagement;\nimport org.springframework.integration.config.IntegrationComponentScanRegistrar;\nimport org.springframework.integration.config.IntegrationManagementConfigurer;\nimport org.springframework.integration.context.IntegrationContextUtils;\nimport org.springframework.integration.jdbc.store.JdbcMessageStore;\nimport org.springframework.integration.jmx.config.EnableIntegrationMBeanExport;\nimport org.springframework.integration.monitor.IntegrationMBeanExporter;\nimport org.springframework.integration.rsocket.ClientRSocketConnector;\nimport org.springframework.integration.rsocket.IntegrationRSocketEndpoint;\nimport org.springframework.integration.rsocket.ServerRSocketConnector;\nimport org.springframework.integration.rsocket.ServerRSocketMessageHandler;\nimport org.springframework.integration.rsocket.outbound.RSocketOutboundGateway;\nimport org.springframework.integration.scheduling.PollerMetadata;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.scheduling.Trigger;\nimport org.springframework.scheduling.support.CronTrigger;\nimport org.springframework.scheduling.support.PeriodicTrigger;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration\n * Auto-configuration} for Spring Integration.\n *\n * @author Artem Bilan\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Madhura Bhave\n * @author Yong-Hyun Kim\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration(beforeName = \"org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration\",\n\t\tafter = { JmxAutoConfiguration.class, TaskSchedulingAutoConfiguration.class },\n\t\tafterName = \"org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\")\n@ConditionalOnClass(EnableIntegration.class)\n@EnableConfigurationProperties({ IntegrationProperties.class, JmxProperties.class })\n@Import(DefaultTaskSchedulerConfiguration.class)\npublic final class IntegrationAutoConfiguration {\n\n\t@Bean(name = IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME)\n\t@ConditionalOnMissingBean(name = IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME)\n\tstatic org.springframework.integration.context.IntegrationProperties integrationGlobalProperties(\n\t\t\tIntegrationProperties properties) {\n\t\torg.springframework.integration.context.IntegrationProperties integrationProperties = new org.springframework.integration.context.IntegrationProperties();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties.getChannel().isAutoCreate()).to(integrationProperties::setChannelsAutoCreate);\n\t\tmap.from(properties.getChannel().getMaxUnicastSubscribers())\n\t\t\t.to(integrationProperties::setChannelsMaxUnicastSubscribers);\n\t\tmap.from(properties.getChannel().getMaxBroadcastSubscribers())\n\t\t\t.to(integrationProperties::setChannelsMaxBroadcastSubscribers);\n\t\tmap.from(properties.getError().isRequireSubscribers())\n\t\t\t.to(integrationProperties::setErrorChannelRequireSubscribers);\n\t\tmap.from(properties.getError().isIgnoreFailures()).to(integrationProperties::setErrorChannelIgnoreFailures);\n\t\tmap.from(properties.getEndpoint().isThrowExceptionOnLateReply())\n\t\t\t.to(integrationProperties::setMessagingTemplateThrowExceptionOnLateReply);\n\t\tmap.from(properties.getEndpoint().getDefaultTimeout())\n\t\t\t.as(Duration::toMillis)\n\t\t\t.to(integrationProperties::setEndpointsDefaultTimeout);\n\t\tmap.from(properties.getEndpoint().getReadOnlyHeaders())\n\t\t\t.as(StringUtils::toStringArray)\n\t\t\t.to(integrationProperties::setReadOnlyHeaders);\n\t\tmap.from(properties.getEndpoint().getNoAutoStartup())\n\t\t\t.as(StringUtils::toStringArray)\n\t\t\t.to(integrationProperties::setNoAutoStartupEndpoints);\n\t\treturn integrationProperties;\n\t}\n\n\t/**\n\t * Basic Spring Integration configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableIntegration\n\tprotected static class IntegrationConfiguration {\n\n\t\t@Bean(PollerMetadata.DEFAULT_POLLER)\n\t\t@ConditionalOnMissingBean(name = PollerMetadata.DEFAULT_POLLER)\n\t\tPollerMetadata defaultPollerMetadata(IntegrationProperties integrationProperties,\n\t\t\t\tObjectProvider<PollerMetadataCustomizer> customizers) {\n\t\t\tIntegrationProperties.Poller poller = integrationProperties.getPoller();\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.integration.poller.cron\",\n\t\t\t\t\t\tStringUtils.hasText(poller.getCron()) ? poller.getCron() : null);\n\t\t\t\tentries.put(\"spring.integration.poller.fixed-delay\", poller.getFixedDelay());\n\t\t\t\tentries.put(\"spring.integration.poller.fixed-rate\", poller.getFixedRate());\n\t\t\t});\n\t\t\tPollerMetadata pollerMetadata = new PollerMetadata();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(poller::getMaxMessagesPerPoll).to(pollerMetadata::setMaxMessagesPerPoll);\n\t\t\tmap.from(poller::getReceiveTimeout).as(Duration::toMillis).to(pollerMetadata::setReceiveTimeout);\n\t\t\tmap.from(poller).as(this::asTrigger).to(pollerMetadata::setTrigger);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(pollerMetadata));\n\t\t\treturn pollerMetadata;\n\t\t}\n\n\t\tprivate @Nullable Trigger asTrigger(IntegrationProperties.Poller poller) {\n\t\t\tif (StringUtils.hasText(poller.getCron())) {\n\t\t\t\treturn new CronTrigger(poller.getCron());\n\t\t\t}\n\t\t\tif (poller.getFixedDelay() != null) {\n\t\t\t\treturn createPeriodicTrigger(poller.getFixedDelay(), poller.getInitialDelay(), false);\n\t\t\t}\n\t\t\tif (poller.getFixedRate() != null) {\n\t\t\t\treturn createPeriodicTrigger(poller.getFixedRate(), poller.getInitialDelay(), true);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate Trigger createPeriodicTrigger(Duration period, @Nullable Duration initialDelay, boolean fixedRate) {\n\t\t\tPeriodicTrigger trigger = new PeriodicTrigger(period);\n\t\t\tif (initialDelay != null) {\n\t\t\t\ttrigger.setInitialDelay(initialDelay);\n\t\t\t}\n\t\t\ttrigger.setFixedRate(fixedRate);\n\t\t\treturn trigger;\n\t\t}\n\n\t}\n\n\t/**\n\t * Spring Integration JMX configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(EnableIntegrationMBeanExport.class)\n\t@ConditionalOnMissingBean(value = IntegrationMBeanExporter.class, search = SearchStrategy.CURRENT)\n\t@ConditionalOnBean(MBeanServer.class)\n\t@ConditionalOnBooleanProperty(\"spring.jmx.enabled\")\n\tprotected static class IntegrationJmxConfiguration {\n\n\t\t@Bean\n\t\tstatic IntegrationMBeanExporter integrationMbeanExporter(ApplicationContext applicationContext) {\n\t\t\treturn new IntegrationMBeanExporter() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void afterSingletonsInstantiated() {\n\t\t\t\t\tJmxProperties properties = applicationContext.getBean(JmxProperties.class);\n\t\t\t\t\tString defaultDomain = properties.getDefaultDomain();\n\t\t\t\t\tif (StringUtils.hasLength(defaultDomain)) {\n\t\t\t\t\t\tsetDefaultDomain(defaultDomain);\n\t\t\t\t\t}\n\t\t\t\t\tsetServer(applicationContext.getBean(properties.getServer(), MBeanServer.class));\n\t\t\t\t\tsuper.afterSingletonsInstantiated();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t/**\n\t * Integration management configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(EnableIntegrationManagement.class)\n\t@ConditionalOnMissingBean(value = IntegrationManagementConfigurer.class,\n\t\t\tname = IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME, search = SearchStrategy.CURRENT)\n\tprotected static class IntegrationManagementConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableIntegrationManagement(\n\t\t\t\tdefaultLoggingEnabled = \"${spring.integration.management.default-logging-enabled:true}\",\n\t\t\t\tobservationPatterns = \"${spring.integration.management.observation-patterns:}\")\n\t\tprotected static class EnableIntegrationManagementConfiguration {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Integration component scan configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(IntegrationComponentScanRegistrar.class)\n\t@Import(IntegrationAutoConfigurationScanRegistrar.class)\n\tprotected static class IntegrationComponentScanConfiguration {\n\n\t}\n\n\t/**\n\t * Integration JDBC configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(DataSource.class)\n\t@ConditionalOnClass({ JdbcMessageStore.class, DataSourceScriptDatabaseInitializer.class })\n\t@EnableConfigurationProperties(IntegrationJdbcProperties.class)\n\tprotected static class IntegrationJdbcConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@Conditional(OnIntegrationDatasourceInitializationCondition.class)\n\t\tIntegrationDataSourceScriptDatabaseInitializer integrationDataSourceInitializer(DataSource dataSource,\n\t\t\t\tIntegrationJdbcProperties properties) {\n\t\t\treturn new IntegrationDataSourceScriptDatabaseInitializer(dataSource, properties);\n\t\t}\n\n\t\tstatic class OnIntegrationDatasourceInitializationCondition extends OnDatabaseInitializationCondition {\n\n\t\t\tOnIntegrationDatasourceInitializationCondition() {\n\t\t\t\tsuper(\"Integration\", \"spring.integration.jdbc.initialize-schema\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Integration RSocket configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ IntegrationRSocketEndpoint.class, RSocketRequester.class, io.rsocket.RSocket.class })\n\t@Conditional(IntegrationRSocketConfiguration.AnyRSocketChannelAdapterAvailable.class)\n\tprotected static class IntegrationRSocketConfiguration {\n\n\t\t/**\n\t\t * Check if either an {@link IntegrationRSocketEndpoint} or\n\t\t * {@link RSocketOutboundGateway} bean is available.\n\t\t */\n\t\tstatic class AnyRSocketChannelAdapterAvailable extends AnyNestedCondition {\n\n\t\t\tAnyRSocketChannelAdapterAvailable() {\n\t\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t\t}\n\n\t\t\t@ConditionalOnBean(IntegrationRSocketEndpoint.class)\n\t\t\tstatic class IntegrationRSocketEndpointAvailable {\n\n\t\t\t}\n\n\t\t\t@ConditionalOnBean(RSocketOutboundGateway.class)\n\t\t\tstatic class RSocketOutboundGatewayAvailable {\n\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(TcpServerTransport.class)\n\t\tprotected static class IntegrationRSocketServerConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean(ServerRSocketMessageHandler.class)\n\t\t\tRSocketMessageHandler serverRSocketMessageHandler(RSocketStrategies rSocketStrategies,\n\t\t\t\t\tIntegrationProperties integrationProperties) {\n\n\t\t\t\tRSocketMessageHandler messageHandler = new ServerRSocketMessageHandler(\n\t\t\t\t\t\tintegrationProperties.getRsocket().getServer().isMessageMappingEnabled());\n\t\t\t\tmessageHandler.setRSocketStrategies(rSocketStrategies);\n\t\t\t\treturn messageHandler;\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean\n\t\t\tServerRSocketConnector serverRSocketConnector(ServerRSocketMessageHandler messageHandler) {\n\t\t\t\treturn new ServerRSocketConnector(messageHandler);\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tprotected static class IntegrationRSocketClientConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean\n\t\t\t@Conditional(RemoteRSocketServerAddressConfigured.class)\n\t\t\tClientRSocketConnector clientRSocketConnector(IntegrationProperties integrationProperties,\n\t\t\t\t\tRSocketStrategies rSocketStrategies) {\n\t\t\t\tIntegrationProperties.RSocket.Client client = integrationProperties.getRsocket().getClient();\n\t\t\t\tClientRSocketConnector clientRSocketConnector;\n\t\t\t\tif (client.getUri() != null) {\n\t\t\t\t\tclientRSocketConnector = new ClientRSocketConnector(client.getUri());\n\t\t\t\t}\n\t\t\t\telse if (client.getHost() != null && client.getPort() != null) {\n\t\t\t\t\tclientRSocketConnector = new ClientRSocketConnector(client.getHost(), client.getPort());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IllegalStateException(\"Neither uri nor host and port is set\");\n\t\t\t\t}\n\t\t\t\tclientRSocketConnector.setRSocketStrategies(rSocketStrategies);\n\t\t\t\treturn clientRSocketConnector;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Check if a remote address is configured for the RSocket Integration client.\n\t\t\t */\n\t\t\tstatic class RemoteRSocketServerAddressConfigured extends AnyNestedCondition {\n\n\t\t\t\tRemoteRSocketServerAddressConfigured() {\n\t\t\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t\t\t}\n\n\t\t\t\t@ConditionalOnProperty(\"spring.integration.rsocket.client.uri\")\n\t\t\t\tstatic class WebSocketAddressConfigured {\n\n\t\t\t\t}\n\n\t\t\t\t@ConditionalOnProperty({ \"spring.integration.rsocket.client.host\",\n\t\t\t\t\t\t\"spring.integration.rsocket.client.port\" })\n\t\t\t\tstatic class TcpAddressConfigured {\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationAutoConfigurationScanRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.integration.annotation.IntegrationComponentScan;\nimport org.springframework.integration.config.IntegrationComponentScanRegistrar;\n\n/**\n * Variation of {@link IntegrationComponentScanRegistrar} the links\n * {@link AutoConfigurationPackages}.\n *\n * @author Artem Bilan\n * @author Phillip Webb\n */\nclass IntegrationAutoConfigurationScanRegistrar extends IntegrationComponentScanRegistrar implements BeanFactoryAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanFactory beanFactory;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,\n\t\t\tfinal BeanDefinitionRegistry registry) {\n\t\tsuper.registerBeanDefinitions(AnnotationMetadata.introspect(IntegrationComponentScanConfiguration.class),\n\t\t\t\tregistry);\n\t}\n\n\t@Override\n\tprotected Collection<String> getBasePackages(AnnotationAttributes componentScan, BeanDefinitionRegistry registry) {\n\t\treturn (AutoConfigurationPackages.has(this.beanFactory) ? AutoConfigurationPackages.get(this.beanFactory)\n\t\t\t\t: Collections.emptyList());\n\t}\n\n\t@IntegrationComponentScan\n\tprivate static final class IntegrationComponentScanConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationDataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer;\n\n/**\n * {@link DataSourceScriptDatabaseInitializer} for the Spring Integration database. May be\n * registered as a bean to override auto-configuration.\n *\n * @author Vedran Pavic\n * @author Andy Wilkinson\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class IntegrationDataSourceScriptDatabaseInitializer\n\t\textends PropertiesBasedDataSourceScriptDatabaseInitializer<IntegrationJdbcProperties> {\n\n\t/**\n\t * Create a new {@link IntegrationDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the Spring Integration data source\n\t * @param properties the Spring Integration JDBC properties\n\t * @see #getSettings\n\t */\n\tpublic IntegrationDataSourceScriptDatabaseInitializer(DataSource dataSource, IntegrationJdbcProperties properties) {\n\t\tsuper(dataSource, properties, Map.of(DatabaseDriver.MARIADB, \"mysql\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationGraphEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.integration.actuate.endpoint.IntegrationGraphEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.integration.config.IntegrationConfigurationBeanFactoryPostProcessor;\nimport org.springframework.integration.graph.IntegrationGraphServer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the\n * {@link IntegrationGraphEndpoint}.\n *\n * @author Tim Ysewyn\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = IntegrationAutoConfiguration.class)\n@ConditionalOnClass({ IntegrationGraphServer.class, IntegrationGraphEndpoint.class,\n\t\tConditionalOnAvailableEndpoint.class })\n@ConditionalOnBean(IntegrationConfigurationBeanFactoryPostProcessor.class)\n@ConditionalOnAvailableEndpoint(IntegrationGraphEndpoint.class)\npublic final class IntegrationGraphEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tIntegrationGraphEndpoint integrationGraphEndpoint(IntegrationGraphServer integrationGraphServer) {\n\t\treturn new IntegrationGraphEndpoint(integrationGraphServer);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tIntegrationGraphServer integrationGraphServer() {\n\t\treturn new IntegrationGraphServer();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationJdbcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.init.DatabaseInitializationProperties;\n\n/**\n * Configuration properties for Spring Integration JDBC.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Artem Bilan\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.integration.jdbc\")\npublic class IntegrationJdbcProperties extends DatabaseInitializationProperties {\n\n\tprivate static final String DEFAULT_SCHEMA_LOCATION = \"classpath:org/springframework/\"\n\t\t\t+ \"integration/jdbc/schema-@@platform@@.sql\";\n\n\t@Override\n\tpublic String getDefaultSchemaLocation() {\n\t\treturn DEFAULT_SCHEMA_LOCATION;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Spring Integration.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Artem Bilan\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.integration\")\npublic class IntegrationProperties {\n\n\tprivate final Channel channel = new Channel();\n\n\tprivate final Endpoint endpoint = new Endpoint();\n\n\tprivate final Error error = new Error();\n\n\tprivate final RSocket rsocket = new RSocket();\n\n\tprivate final Poller poller = new Poller();\n\n\tprivate final Management management = new Management();\n\n\tpublic Channel getChannel() {\n\t\treturn this.channel;\n\t}\n\n\tpublic Endpoint getEndpoint() {\n\t\treturn this.endpoint;\n\t}\n\n\tpublic Error getError() {\n\t\treturn this.error;\n\t}\n\n\tpublic RSocket getRsocket() {\n\t\treturn this.rsocket;\n\t}\n\n\tpublic Poller getPoller() {\n\t\treturn this.poller;\n\t}\n\n\tpublic Management getManagement() {\n\t\treturn this.management;\n\t}\n\n\tpublic static class Channel {\n\n\t\t/**\n\t\t * Whether to create input channels if necessary.\n\t\t */\n\t\tprivate boolean autoCreate = true;\n\n\t\t/**\n\t\t * Default number of subscribers allowed on, for example, a 'DirectChannel'.\n\t\t */\n\t\tprivate int maxUnicastSubscribers = Integer.MAX_VALUE;\n\n\t\t/**\n\t\t * Default number of subscribers allowed on, for example, a\n\t\t * 'PublishSubscribeChannel'.\n\t\t */\n\t\tprivate int maxBroadcastSubscribers = Integer.MAX_VALUE;\n\n\t\tpublic void setAutoCreate(boolean autoCreate) {\n\t\t\tthis.autoCreate = autoCreate;\n\t\t}\n\n\t\tpublic boolean isAutoCreate() {\n\t\t\treturn this.autoCreate;\n\t\t}\n\n\t\tpublic void setMaxUnicastSubscribers(int maxUnicastSubscribers) {\n\t\t\tthis.maxUnicastSubscribers = maxUnicastSubscribers;\n\t\t}\n\n\t\tpublic int getMaxUnicastSubscribers() {\n\t\t\treturn this.maxUnicastSubscribers;\n\t\t}\n\n\t\tpublic void setMaxBroadcastSubscribers(int maxBroadcastSubscribers) {\n\t\t\tthis.maxBroadcastSubscribers = maxBroadcastSubscribers;\n\t\t}\n\n\t\tpublic int getMaxBroadcastSubscribers() {\n\t\t\treturn this.maxBroadcastSubscribers;\n\t\t}\n\n\t}\n\n\tpublic static class Endpoint {\n\n\t\t/**\n\t\t * Whether to throw an exception when a reply is not expected anymore by a\n\t\t * gateway.\n\t\t */\n\t\tprivate boolean throwExceptionOnLateReply;\n\n\t\t/**\n\t\t * List of message header names that should not be populated into Message\n\t\t * instances during a header copying operation.\n\t\t */\n\t\tprivate List<String> readOnlyHeaders = new ArrayList<>();\n\n\t\t/**\n\t\t * List of endpoint bean names patterns that should not be started automatically\n\t\t * during application startup.\n\t\t */\n\t\tprivate List<String> noAutoStartup = new ArrayList<>();\n\n\t\t/**\n\t\t * Default timeout for blocking operations such as sending or receiving messages.\n\t\t */\n\t\tprivate Duration defaultTimeout = Duration.ofSeconds(30);\n\n\t\tpublic void setThrowExceptionOnLateReply(boolean throwExceptionOnLateReply) {\n\t\t\tthis.throwExceptionOnLateReply = throwExceptionOnLateReply;\n\t\t}\n\n\t\tpublic boolean isThrowExceptionOnLateReply() {\n\t\t\treturn this.throwExceptionOnLateReply;\n\t\t}\n\n\t\tpublic List<String> getReadOnlyHeaders() {\n\t\t\treturn this.readOnlyHeaders;\n\t\t}\n\n\t\tpublic void setReadOnlyHeaders(List<String> readOnlyHeaders) {\n\t\t\tthis.readOnlyHeaders = readOnlyHeaders;\n\t\t}\n\n\t\tpublic List<String> getNoAutoStartup() {\n\t\t\treturn this.noAutoStartup;\n\t\t}\n\n\t\tpublic void setNoAutoStartup(List<String> noAutoStartup) {\n\t\t\tthis.noAutoStartup = noAutoStartup;\n\t\t}\n\n\t\tpublic Duration getDefaultTimeout() {\n\t\t\treturn this.defaultTimeout;\n\t\t}\n\n\t\tpublic void setDefaultTimeout(Duration defaultTimeout) {\n\t\t\tthis.defaultTimeout = defaultTimeout;\n\t\t}\n\n\t}\n\n\tpublic static class Error {\n\n\t\t/**\n\t\t * Whether to not silently ignore messages on the global 'errorChannel' when there\n\t\t * are no subscribers.\n\t\t */\n\t\tprivate boolean requireSubscribers = true;\n\n\t\t/**\n\t\t * Whether to ignore failures for one or more of the handlers of the global\n\t\t * 'errorChannel'.\n\t\t */\n\t\tprivate boolean ignoreFailures = true;\n\n\t\tpublic boolean isRequireSubscribers() {\n\t\t\treturn this.requireSubscribers;\n\t\t}\n\n\t\tpublic void setRequireSubscribers(boolean requireSubscribers) {\n\t\t\tthis.requireSubscribers = requireSubscribers;\n\t\t}\n\n\t\tpublic boolean isIgnoreFailures() {\n\t\t\treturn this.ignoreFailures;\n\t\t}\n\n\t\tpublic void setIgnoreFailures(boolean ignoreFailures) {\n\t\t\tthis.ignoreFailures = ignoreFailures;\n\t\t}\n\n\t}\n\n\tpublic static class RSocket {\n\n\t\tprivate final Client client = new Client();\n\n\t\tprivate final Server server = new Server();\n\n\t\tpublic Client getClient() {\n\t\t\treturn this.client;\n\t\t}\n\n\t\tpublic Server getServer() {\n\t\t\treturn this.server;\n\t\t}\n\n\t\tpublic static class Client {\n\n\t\t\t/**\n\t\t\t * TCP RSocket server host to connect to.\n\t\t\t */\n\t\t\tprivate @Nullable String host;\n\n\t\t\t/**\n\t\t\t * TCP RSocket server port to connect to.\n\t\t\t */\n\t\t\tprivate @Nullable Integer port;\n\n\t\t\t/**\n\t\t\t * WebSocket RSocket server uri to connect to.\n\t\t\t */\n\t\t\tprivate @Nullable URI uri;\n\n\t\t\tpublic void setHost(@Nullable String host) {\n\t\t\t\tthis.host = host;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getHost() {\n\t\t\t\treturn this.host;\n\t\t\t}\n\n\t\t\tpublic void setPort(@Nullable Integer port) {\n\t\t\t\tthis.port = port;\n\t\t\t}\n\n\t\t\tpublic @Nullable Integer getPort() {\n\t\t\t\treturn this.port;\n\t\t\t}\n\n\t\t\tpublic void setUri(@Nullable URI uri) {\n\t\t\t\tthis.uri = uri;\n\t\t\t}\n\n\t\t\tpublic @Nullable URI getUri() {\n\t\t\t\treturn this.uri;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Server {\n\n\t\t\t/**\n\t\t\t * Whether to handle message mapping for RSocket through Spring Integration.\n\t\t\t */\n\t\t\tprivate boolean messageMappingEnabled;\n\n\t\t\tpublic boolean isMessageMappingEnabled() {\n\t\t\t\treturn this.messageMappingEnabled;\n\t\t\t}\n\n\t\t\tpublic void setMessageMappingEnabled(boolean messageMappingEnabled) {\n\t\t\t\tthis.messageMappingEnabled = messageMappingEnabled;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Poller {\n\n\t\t/**\n\t\t * Maximum number of messages to poll per polling cycle.\n\t\t */\n\t\tprivate int maxMessagesPerPoll = Integer.MIN_VALUE; // PollerMetadata.MAX_MESSAGES_UNBOUNDED\n\n\t\t/**\n\t\t * How long to wait for messages on poll.\n\t\t */\n\t\tprivate Duration receiveTimeout = Duration.ofSeconds(1); // PollerMetadata.DEFAULT_RECEIVE_TIMEOUT\n\n\t\t/**\n\t\t * Polling delay period. Mutually exclusive with 'cron' and 'fixedRate'.\n\t\t */\n\t\tprivate @Nullable Duration fixedDelay;\n\n\t\t/**\n\t\t * Polling rate period. Mutually exclusive with 'fixedDelay' and 'cron'.\n\t\t */\n\t\tprivate @Nullable Duration fixedRate;\n\n\t\t/**\n\t\t * Polling initial delay. Applied for 'fixedDelay' and 'fixedRate'; ignored for\n\t\t * 'cron'.\n\t\t */\n\t\tprivate @Nullable Duration initialDelay;\n\n\t\t/**\n\t\t * Cron expression for polling. Mutually exclusive with 'fixedDelay' and\n\t\t * 'fixedRate'.\n\t\t */\n\t\tprivate @Nullable String cron;\n\n\t\tpublic int getMaxMessagesPerPoll() {\n\t\t\treturn this.maxMessagesPerPoll;\n\t\t}\n\n\t\tpublic void setMaxMessagesPerPoll(int maxMessagesPerPoll) {\n\t\t\tthis.maxMessagesPerPoll = maxMessagesPerPoll;\n\t\t}\n\n\t\tpublic Duration getReceiveTimeout() {\n\t\t\treturn this.receiveTimeout;\n\t\t}\n\n\t\tpublic void setReceiveTimeout(Duration receiveTimeout) {\n\t\t\tthis.receiveTimeout = receiveTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getFixedDelay() {\n\t\t\treturn this.fixedDelay;\n\t\t}\n\n\t\tpublic void setFixedDelay(@Nullable Duration fixedDelay) {\n\t\t\tthis.fixedDelay = fixedDelay;\n\t\t}\n\n\t\tpublic @Nullable Duration getFixedRate() {\n\t\t\treturn this.fixedRate;\n\t\t}\n\n\t\tpublic void setFixedRate(@Nullable Duration fixedRate) {\n\t\t\tthis.fixedRate = fixedRate;\n\t\t}\n\n\t\tpublic @Nullable Duration getInitialDelay() {\n\t\t\treturn this.initialDelay;\n\t\t}\n\n\t\tpublic void setInitialDelay(@Nullable Duration initialDelay) {\n\t\t\tthis.initialDelay = initialDelay;\n\t\t}\n\n\t\tpublic @Nullable String getCron() {\n\t\t\treturn this.cron;\n\t\t}\n\n\t\tpublic void setCron(@Nullable String cron) {\n\t\t\tthis.cron = cron;\n\t\t}\n\n\t}\n\n\tpublic static class Management {\n\n\t\t/**\n\t\t * Whether Spring Integration components should perform logging in the main\n\t\t * message flow. When disabled, such logging will be skipped without checking the\n\t\t * logging level. When enabled, such logging is controlled as normal by the\n\t\t * logging system's log level configuration.\n\t\t */\n\t\tprivate boolean defaultLoggingEnabled = true;\n\n\t\t/**\n\t\t * List of simple patterns to match against the names of Spring Integration\n\t\t * components. When matched, observation instrumentation will be performed for the\n\t\t * component. Please refer to the javadoc of the smartMatch method of Spring\n\t\t * Integration's PatternMatchUtils for details of the pattern syntax.\n\t\t */\n\t\tprivate List<String> observationPatterns = new ArrayList<>();\n\n\t\tpublic boolean isDefaultLoggingEnabled() {\n\t\t\treturn this.defaultLoggingEnabled;\n\t\t}\n\n\t\tpublic void setDefaultLoggingEnabled(boolean defaultLoggingEnabled) {\n\t\t\tthis.defaultLoggingEnabled = defaultLoggingEnabled;\n\t\t}\n\n\t\tpublic List<String> getObservationPatterns() {\n\t\t\treturn this.observationPatterns;\n\t\t}\n\n\t\tpublic void setObservationPatterns(List<String> observationPatterns) {\n\t\t\tthis.observationPatterns = observationPatterns;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/IntegrationPropertiesEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.env.OriginTrackedMapPropertySource;\nimport org.springframework.boot.env.PropertiesPropertySourceLoader;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.integration.context.IntegrationProperties;\n\n/**\n * An {@link EnvironmentPostProcessor} that maps the configuration of\n * {@code META-INF/spring.integration.properties} in the environment.\n *\n * @author Artem Bilan\n * @author Stephane Nicoll\n */\nclass IntegrationPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tResource resource = new ClassPathResource(\"META-INF/spring.integration.properties\");\n\t\tif (resource.exists()) {\n\t\t\tregisterIntegrationPropertiesPropertySource(environment, resource);\n\t\t}\n\t}\n\n\tprotected void registerIntegrationPropertiesPropertySource(ConfigurableEnvironment environment, Resource resource) {\n\t\tPropertiesPropertySourceLoader loader = new PropertiesPropertySourceLoader();\n\t\ttry {\n\t\t\tOriginTrackedMapPropertySource propertyFileSource = (OriginTrackedMapPropertySource) loader\n\t\t\t\t.load(\"META-INF/spring.integration.properties\", resource)\n\t\t\t\t.get(0);\n\t\t\tenvironment.getPropertySources().addLast(new IntegrationPropertiesPropertySource(propertyFileSource));\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to load integration properties from \" + resource, ex);\n\t\t}\n\t}\n\n\tprivate static final class IntegrationPropertiesPropertySource extends PropertySource<Map<String, Object>>\n\t\t\timplements OriginLookup<String> {\n\n\t\tprivate static final String PREFIX = \"spring.integration.\";\n\n\t\tprivate static final Map<String, String> KEYS_MAPPING;\n\n\t\tstatic {\n\t\t\tMap<String, String> mappings = new HashMap<>();\n\t\t\tmappings.put(PREFIX + \"channel.auto-create\", IntegrationProperties.CHANNELS_AUTOCREATE);\n\t\t\tmappings.put(PREFIX + \"channel.max-unicast-subscribers\",\n\t\t\t\t\tIntegrationProperties.CHANNELS_MAX_UNICAST_SUBSCRIBERS);\n\t\t\tmappings.put(PREFIX + \"channel.max-broadcast-subscribers\",\n\t\t\t\t\tIntegrationProperties.CHANNELS_MAX_BROADCAST_SUBSCRIBERS);\n\t\t\tmappings.put(PREFIX + \"error.require-subscribers\", IntegrationProperties.ERROR_CHANNEL_REQUIRE_SUBSCRIBERS);\n\t\t\tmappings.put(PREFIX + \"error.ignore-failures\", IntegrationProperties.ERROR_CHANNEL_IGNORE_FAILURES);\n\t\t\tmappings.put(PREFIX + \"endpoint.default-timeout\", IntegrationProperties.ENDPOINTS_DEFAULT_TIMEOUT);\n\t\t\tmappings.put(PREFIX + \"endpoint.throw-exception-on-late-reply\",\n\t\t\t\t\tIntegrationProperties.THROW_EXCEPTION_ON_LATE_REPLY);\n\t\t\tmappings.put(PREFIX + \"endpoint.read-only-headers\", IntegrationProperties.READ_ONLY_HEADERS);\n\t\t\tmappings.put(PREFIX + \"endpoint.no-auto-startup\", IntegrationProperties.ENDPOINTS_NO_AUTO_STARTUP);\n\t\t\tKEYS_MAPPING = Collections.unmodifiableMap(mappings);\n\t\t}\n\n\t\tprivate final OriginTrackedMapPropertySource delegate;\n\n\t\tIntegrationPropertiesPropertySource(OriginTrackedMapPropertySource delegate) {\n\t\t\tsuper(\"META-INF/spring.integration.properties\", delegate.getSource());\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\tString mapped = KEYS_MAPPING.get(name);\n\t\t\treturn (mapped != null) ? this.delegate.getProperty(mapped) : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Origin getOrigin(String key) {\n\t\t\tString mapped = KEYS_MAPPING.get(key);\n\t\t\treturn (mapped != null) ? this.delegate.getOrigin(mapped) : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/PollerMetadataCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport org.springframework.integration.scheduling.PollerMetadata;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link PollerMetadata} to fine-tune its auto-configuration.\n *\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface PollerMetadataCustomizer {\n\n\t/**\n\t * Customize the {@link PollerMetadata}.\n\t * @param pollerMetadata the {@code PollerMetadata} to customize\n\t */\n\tvoid customize(PollerMetadata pollerMetadata);\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/metrics/IntegrationMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Integration's metrics.\n * Orders auto-configuration classes to ensure that the {@link MeterRegistry} bean has\n * been defined before Spring Integration's Micrometer support queries the bean factory\n * for it.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(before = IntegrationAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\npublic final class IntegrationMetricsAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Integration metrics.\n */\n@NullMarked\npackage org.springframework.boot.integration.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/java/org/springframework/boot/integration/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Integration.\n */\n@NullMarked\npackage org.springframework.boot.integration.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration\norg.springframework.boot.integration.autoconfigure.IntegrationGraphEndpointAutoConfiguration\norg.springframework.boot.integration.autoconfigure.metrics.IntegrationMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-integration/src/main/resources/META-INF/spring.factories",
    "content": "# Environment Post Processors\norg.springframework.boot.EnvironmentPostProcessor=\\\norg.springframework.boot.integration.autoconfigure.IntegrationPropertiesEnvironmentPostProcessor\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/actuate/endpoint/IntegrationGraphEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.integration.actuate.endpoint.IntegrationGraphEndpoint.GraphDescriptor;\nimport org.springframework.integration.graph.Graph;\nimport org.springframework.integration.graph.IntegrationGraphServer;\nimport org.springframework.integration.graph.IntegrationNode;\nimport org.springframework.integration.graph.LinkNode;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link IntegrationGraphEndpoint}.\n *\n * @author Tim Ysewyn\n * @author Moritz Halbritter\n */\nclass IntegrationGraphEndpointTests {\n\n\tprivate final IntegrationGraphServer server = mock(IntegrationGraphServer.class);\n\n\tprivate final IntegrationGraphEndpoint endpoint = new IntegrationGraphEndpoint(this.server);\n\n\t@Test\n\tvoid readOperationShouldReturnGraph() {\n\t\tGraph graph = mock(Graph.class);\n\t\tMap<String, Object> contentDescriptor = new LinkedHashMap<>();\n\t\tCollection<IntegrationNode> nodes = new ArrayList<>();\n\t\tCollection<LinkNode> links = new ArrayList<>();\n\t\tgiven(graph.contentDescriptor()).willReturn(contentDescriptor);\n\t\tgiven(graph.nodes()).willReturn(nodes);\n\t\tgiven(graph.links()).willReturn(links);\n\t\tgiven(this.server.getGraph()).willReturn(graph);\n\t\tGraphDescriptor descriptor = this.endpoint.graph();\n\t\tthen(this.server).should().getGraph();\n\t\tassertThat(descriptor.getContentDescriptor()).isSameAs(contentDescriptor);\n\t\tassertThat(descriptor.getNodes()).isSameAs(nodes);\n\t\tassertThat(descriptor.getLinks()).isSameAs(links);\n\t}\n\n\t@Test\n\tvoid writeOperationShouldRebuildGraph() {\n\t\tthis.endpoint.rebuild();\n\t\tthen(this.server).should().rebuild();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/actuate/endpoint/IntegrationGraphEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.actuate.endpoint;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.integration.config.EnableIntegration;\nimport org.springframework.integration.graph.IntegrationGraphServer;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link IntegrationGraphEndpoint} exposed by Jersey, Spring MVC,\n * and WebFlux.\n *\n * @author Tim Ysewyn\n */\nclass IntegrationGraphEndpointWebIntegrationTests {\n\n\t@WebEndpointTest\n\tvoid graph(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/integrationgraph\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"contentDescriptor.providerVersion\")\n\t\t\t.isNotEmpty()\n\t\t\t.jsonPath(\"contentDescriptor.providerFormatVersion\")\n\t\t\t.isEqualTo(1.2f)\n\t\t\t.jsonPath(\"contentDescriptor.provider\")\n\t\t\t.isEqualTo(\"spring-integration\");\n\t}\n\n\t@WebEndpointTest\n\tvoid rebuild(WebTestClient client) {\n\t\tclient.post()\n\t\t\t.uri(\"/actuator/integrationgraph\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableIntegration\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tIntegrationGraphEndpoint endpoint(IntegrationGraphServer integrationGraphServer) {\n\t\t\treturn new IntegrationGraphEndpoint(integrationGraphServer);\n\t\t}\n\n\t\t@Bean\n\t\tIntegrationGraphServer integrationGraphServer() {\n\t\t\treturn new IntegrationGraphServer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/autoconfigure/IntegrationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.beans.PropertyDescriptor;\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Stream;\n\nimport javax.management.MBeanServer;\nimport javax.sql.DataSource;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.rsocket.transport.ClientTransport;\nimport io.rsocket.transport.netty.client.TcpClientTransport;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.DirectFieldAccessor;\nimport org.springframework.beans.PropertyAccessorFactory;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;\nimport org.springframework.boot.context.annotation.UserConfigurations;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration.IntegrationComponentScanConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketRequesterAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketServerAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.assertj.SimpleAsyncTaskExecutorAssert;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.core.task.SyncTaskExecutor;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.integration.annotation.IntegrationComponentScan;\nimport org.springframework.integration.annotation.MessagingGateway;\nimport org.springframework.integration.annotation.ServiceActivator;\nimport org.springframework.integration.channel.DirectChannel;\nimport org.springframework.integration.channel.QueueChannel;\nimport org.springframework.integration.config.IntegrationManagementConfigurer;\nimport org.springframework.integration.context.IntegrationContextUtils;\nimport org.springframework.integration.core.MessageSource;\nimport org.springframework.integration.endpoint.MessageProcessorMessageSource;\nimport org.springframework.integration.gateway.RequestReplyExchanger;\nimport org.springframework.integration.handler.BridgeHandler;\nimport org.springframework.integration.handler.LoggingHandler;\nimport org.springframework.integration.handler.MessageProcessor;\nimport org.springframework.integration.jmx.config.EnableIntegrationMBeanExport;\nimport org.springframework.integration.monitor.IntegrationMBeanExporter;\nimport org.springframework.integration.rsocket.ClientRSocketConnector;\nimport org.springframework.integration.rsocket.IntegrationRSocketEndpoint;\nimport org.springframework.integration.rsocket.ServerRSocketConnector;\nimport org.springframework.integration.rsocket.ServerRSocketMessageHandler;\nimport org.springframework.integration.scheduling.PollerMetadata;\nimport org.springframework.integration.support.channel.HeaderChannelRegistry;\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jmx.export.MBeanExporter;\nimport org.springframework.messaging.Message;\nimport org.springframework.messaging.MessageHandler;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.messaging.support.GenericMessage;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;\nimport org.springframework.scheduling.support.CronTrigger;\nimport org.springframework.scheduling.support.PeriodicTrigger;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link IntegrationAutoConfiguration}.\n *\n * @author Artem Bilan\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Yong-Hyun Kim\n * @author Yanming Zhou\n */\nclass IntegrationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class));\n\n\t@Test\n\tvoid integrationIsAvailable() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TestGateway.class);\n\t\t\tassertThat(context).hasSingleBean(IntegrationComponentScanConfiguration.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid explicitIntegrationComponentScan() {\n\t\tthis.contextRunner.withUserConfiguration(CustomIntegrationComponentScanConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TestGateway.class);\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationComponentScanConfiguration.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid noMBeanServerAvailable() {\n\t\tApplicationContextRunner contextRunnerWithoutJmx = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(IntegrationAutoConfiguration.class));\n\t\tcontextRunnerWithoutJmx.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TestGateway.class);\n\t\t\tassertThat(context).hasSingleBean(IntegrationComponentScanConfiguration.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid parentContext() {\n\t\tthis.contextRunner.run((context) -> this.contextRunner.withParent(context)\n\t\t\t.withPropertyValues(\"spring.jmx.default_domain=org.foo\")\n\t\t\t.run((child) -> assertThat(child).hasSingleBean(HeaderChannelRegistry.class)));\n\t}\n\n\t@Test\n\tvoid enableJmxIntegration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jmx.enabled=true\").run((context) -> {\n\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\tassertThat(mBeanServer.getDomains()).contains(\"org.springframework.integration\",\n\t\t\t\t\t\"org.springframework.boot.integration.autoconfigure\");\n\t\t\tassertThat(context).hasBean(IntegrationManagementConfigurer.MANAGEMENT_CONFIGURER_NAME);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jmxIntegrationIsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(MBeanServer.class);\n\t\t\tassertThat(context).hasSingleBean(IntegrationManagementConfigurer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customizeJmxDomain() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.jmx.default_domain=org.foo\")\n\t\t\t.run((context) -> {\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tassertThat(mBeanServer.getDomains()).contains(\"org.foo\")\n\t\t\t\t\t.doesNotContain(\"org.springframework.integration\", \"org.springframework.integration.monitor\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customJmxDomainUsingEnableIntegrationMBeanExport() {\n\t\tthis.contextRunner.withConfiguration(UserConfigurations.of(CustomJmxDomainConfiguration.class))\n\t\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(IntegrationMBeanExporter.class);\n\t\t\t\tIntegrationMBeanExporter exporter = context.getBean(IntegrationMBeanExporter.class);\n\t\t\t\tassertThat(exporter).hasFieldOrPropertyWithValue(\"domain\", \"foo.my\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid primaryExporterIsAllowed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jmx.enabled=true\")\n\t\t\t.withUserConfiguration(CustomMBeanExporter.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(MBeanExporter.class).hasSize(2);\n\t\t\t\tassertThat(context.getBean(MBeanExporter.class)).isSameAs(context.getBean(\"myMBeanExporter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid integrationJdbcDataSourceInitializerEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class,\n\t\t\t\t\tJdbcTemplateAutoConfiguration.class, IntegrationAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.integration.jdbc.initialize-schema=always\")\n\t\t\t.run((context) -> {\n\t\t\t\tIntegrationJdbcProperties properties = context.getBean(IntegrationJdbcProperties.class);\n\t\t\t\tassertThat(properties.getInitializeSchema()).isEqualTo(DatabaseInitializationMode.ALWAYS);\n\t\t\t\tJdbcOperations jdbc = context.getBean(JdbcOperations.class);\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_MESSAGE\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_GROUP_TO_MESSAGE\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_MESSAGE_GROUP\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_LOCK\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_CHANNEL_MESSAGE\")).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenIntegrationJdbcDataSourceInitializerIsEnabledThenFlywayCanBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class,\n\t\t\t\t\tJdbcTemplateAutoConfiguration.class, IntegrationAutoConfiguration.class,\n\t\t\t\t\tFlywayAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.integration.jdbc.initialize-schema=always\")\n\t\t\t.run((context) -> {\n\t\t\t\tIntegrationJdbcProperties properties = context.getBean(IntegrationJdbcProperties.class);\n\t\t\t\tassertThat(properties.getInitializeSchema()).isEqualTo(DatabaseInitializationMode.ALWAYS);\n\t\t\t\tJdbcOperations jdbc = context.getBean(JdbcOperations.class);\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_MESSAGE\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_GROUP_TO_MESSAGE\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_MESSAGE_GROUP\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_LOCK\")).isEmpty();\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_CHANNEL_MESSAGE\")).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid integrationJdbcDataSourceInitializerDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class,\n\t\t\t\t\tJdbcTemplateAutoConfiguration.class, IntegrationAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\t\"spring.integration.jdbc.initialize-schema=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(IntegrationDataSourceScriptDatabaseInitializer.class);\n\t\t\t\tIntegrationJdbcProperties properties = context.getBean(IntegrationJdbcProperties.class);\n\t\t\t\tassertThat(properties.getInitializeSchema()).isEqualTo(DatabaseInitializationMode.NEVER);\n\t\t\t\tJdbcOperations jdbc = context.getBean(JdbcOperations.class);\n\t\t\t\tassertThatExceptionOfType(BadSqlGrammarException.class)\n\t\t\t\t\t.isThrownBy(() -> jdbc.queryForList(\"select * from INT_MESSAGE\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid integrationJdbcDataSourceInitializerEnabledByDefaultWithEmbeddedDb() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceTransactionManagerAutoConfiguration.class,\n\t\t\t\t\tJdbcTemplateAutoConfiguration.class, IntegrationAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tIntegrationJdbcProperties properties = context.getBean(IntegrationJdbcProperties.class);\n\t\t\t\tassertThat(properties.getInitializeSchema()).isEqualTo(DatabaseInitializationMode.EMBEDDED);\n\t\t\t\tJdbcOperations jdbc = context.getBean(JdbcOperations.class);\n\t\t\t\tassertThat(jdbc.queryForList(\"select * from INT_MESSAGE\")).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid integrationJdbcDataSourceInitializerBacksOffWithoutSpringBootJdbc() {\n\t\tthis.contextRunner.withBean(DataSource.class, IntegrationAutoConfigurationTests::createTestDataSource)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.boot.jdbc\"))\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(IntegrationDataSourceScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid integrationJdbcDataSourceInitializerBacksOffWithoutSpringBootJdbcAndSql() {\n\t\tthis.contextRunner.withBean(DataSource.class, IntegrationAutoConfigurationTests::createTestDataSource)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.boot.jdbc\", \"org.springframework.boot.sql\"))\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(IntegrationDataSourceScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid rsocketSupportEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(RSocketServerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(RSocketServerAutoConfiguration.class,\n\t\t\t\t\tRSocketStrategiesAutoConfiguration.class, RSocketMessagingAutoConfiguration.class,\n\t\t\t\t\tRSocketRequesterAutoConfiguration.class, IntegrationAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\", \"spring.integration.rsocket.client.port=0\",\n\t\t\t\t\t\"spring.integration.rsocket.client.host=localhost\",\n\t\t\t\t\t\"spring.integration.rsocket.server.message-mapping-enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ClientRSocketConnector.class)\n\t\t\t\t\t.hasBean(\"clientRSocketConnector\")\n\t\t\t\t\t.hasSingleBean(ServerRSocketConnector.class)\n\t\t\t\t\t.hasSingleBean(ServerRSocketMessageHandler.class)\n\t\t\t\t\t.hasSingleBean(RSocketMessageHandler.class);\n\n\t\t\t\tServerRSocketMessageHandler serverRSocketMessageHandler = context\n\t\t\t\t\t.getBean(ServerRSocketMessageHandler.class);\n\t\t\t\tassertThat(context).getBean(RSocketMessageHandler.class).isSameAs(serverRSocketMessageHandler);\n\n\t\t\t\tClientRSocketConnector clientRSocketConnector = context.getBean(ClientRSocketConnector.class);\n\t\t\t\tClientTransport clientTransport = (ClientTransport) new DirectFieldAccessor(clientRSocketConnector)\n\t\t\t\t\t.getPropertyValue(\"clientTransport\");\n\n\t\t\t\tassertThat(clientTransport).isInstanceOf(TcpClientTransport.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskSchedulerIsNotOverridden() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.task.scheduling.thread-name-prefix=integration-scheduling-\",\n\t\t\t\t\t\"spring.task.scheduling.pool.size=3\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TaskScheduler.class);\n\t\t\t\tassertThat(context).getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"threadNamePrefix\", \"integration-scheduling-\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"scheduledExecutor.corePoolSize\", 3);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskSchedulerCanBeCustomized() {\n\t\tTaskScheduler customTaskScheduler = mock(TaskScheduler.class);\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.withBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class, () -> customTaskScheduler)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TaskScheduler.class);\n\t\t\t\tassertThat(context).getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME)\n\t\t\t\t\t.isSameAs(customTaskScheduler);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid integrationGlobalPropertiesAutoConfigured() {\n\t\tString[] propertyValues = { \"spring.integration.channel.auto-create=false\",\n\t\t\t\t\"spring.integration.channel.max-unicast-subscribers=2\",\n\t\t\t\t\"spring.integration.channel.max-broadcast-subscribers=3\",\n\t\t\t\t\"spring.integration.error.require-subscribers=false\", \"spring.integration.error.ignore-failures=false\",\n\t\t\t\t\"spring.integration.endpoint.defaultTimeout=60s\",\n\t\t\t\t\"spring.integration.endpoint.throw-exception-on-late-reply=true\",\n\t\t\t\t\"spring.integration.endpoint.read-only-headers=ignoredHeader\",\n\t\t\t\t\"spring.integration.endpoint.no-auto-startup=notStartedEndpoint,_org.springframework.integration.errorLogger\" };\n\t\tassertThat(propertyValues).hasSameSizeAs(globalIntegrationPropertyNames());\n\t\tthis.contextRunner.withPropertyValues(propertyValues).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\torg.springframework.integration.context.IntegrationProperties integrationProperties = context\n\t\t\t\t.getBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\tassertThat(integrationProperties.isChannelsAutoCreate()).isFalse();\n\t\t\tassertThat(integrationProperties.getChannelsMaxUnicastSubscribers()).isEqualTo(2);\n\t\t\tassertThat(integrationProperties.getChannelsMaxBroadcastSubscribers()).isEqualTo(3);\n\t\t\tassertThat(integrationProperties.isErrorChannelRequireSubscribers()).isFalse();\n\t\t\tassertThat(integrationProperties.isErrorChannelIgnoreFailures()).isFalse();\n\t\t\tassertThat(integrationProperties.getEndpointsDefaultTimeout()).isEqualTo(60000);\n\t\t\tassertThat(integrationProperties.isMessagingTemplateThrowExceptionOnLateReply()).isTrue();\n\t\t\tassertThat(integrationProperties.getReadOnlyHeaders()).containsOnly(\"ignoredHeader\");\n\t\t\tassertThat(integrationProperties.getNoAutoStartupEndpoints()).containsOnly(\"notStartedEndpoint\",\n\t\t\t\t\t\"_org.springframework.integration.errorLogger\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid integrationGlobalPropertiesUseConsistentDefault() {\n\t\tList<PropertyAccessor> properties = List\n\t\t\t.of(\"isChannelsAutoCreate\", \"getChannelsMaxUnicastSubscribers\", \"getChannelsMaxBroadcastSubscribers\",\n\t\t\t\t\t\"isErrorChannelRequireSubscribers\", \"isErrorChannelIgnoreFailures\", \"getEndpointsDefaultTimeout\",\n\t\t\t\t\t\"isMessagingTemplateThrowExceptionOnLateReply\", \"getReadOnlyHeaders\", \"getNoAutoStartupEndpoints\")\n\t\t\t.stream()\n\t\t\t.map(PropertyAccessor::new)\n\t\t\t.toList();\n\t\tassertThat(properties).hasSameSizeAs(globalIntegrationPropertyNames());\n\t\torg.springframework.integration.context.IntegrationProperties defaultIntegrationProperties = new org.springframework.integration.context.IntegrationProperties();\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\torg.springframework.integration.context.IntegrationProperties integrationProperties = context\n\t\t\t\t.getBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\tproperties.forEach((property) -> assertThat(property.get(integrationProperties))\n\t\t\t\t.isEqualTo(property.get(defaultIntegrationProperties)));\n\t\t});\n\t}\n\n\tprivate List<String> globalIntegrationPropertyNames() {\n\t\treturn Stream\n\t\t\t.of(PropertyAccessorFactory\n\t\t\t\t.forBeanPropertyAccess(new org.springframework.integration.context.IntegrationProperties())\n\t\t\t\t.getPropertyDescriptors())\n\t\t\t.map(PropertyDescriptor::getName)\n\t\t\t.filter((name) -> !\"class\".equals(name))\n\t\t\t.filter((name) -> !\"taskSchedulerPoolSize\".equals(name))\n\t\t\t.toList();\n\t}\n\n\t@Test\n\tvoid integrationGlobalPropertiesUserBeanOverridesAutoConfiguration() {\n\t\torg.springframework.integration.context.IntegrationProperties userIntegrationProperties = new org.springframework.integration.context.IntegrationProperties();\n\t\tthis.contextRunner.withPropertyValues()\n\t\t\t.withBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME,\n\t\t\t\t\torg.springframework.integration.context.IntegrationProperties.class,\n\t\t\t\t\t() -> userIntegrationProperties)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\t\tassertThat(context.getBean(org.springframework.integration.context.IntegrationProperties.class))\n\t\t\t\t\t.isSameAs(userIntegrationProperties);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.integration.properties\",\n\t\t\tcontent = \"spring.integration.endpoints.noAutoStartup=testService*\")\n\tvoid integrationGlobalPropertiesFromSpringIntegrationPropertiesFile() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.integration.channel.auto-create=false\",\n\t\t\t\t\t\"spring.integration.endpoint.read-only-headers=ignoredHeader\")\n\t\t\t.withInitializer((applicationContext) -> new IntegrationPropertiesEnvironmentPostProcessor()\n\t\t\t\t.postProcessEnvironment(applicationContext.getEnvironment(), new SpringApplication()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\t\torg.springframework.integration.context.IntegrationProperties integrationProperties = context\n\t\t\t\t\t.getBean(org.springframework.integration.context.IntegrationProperties.class);\n\t\t\t\tassertThat(integrationProperties.isChannelsAutoCreate()).isFalse();\n\t\t\t\tassertThat(integrationProperties.getReadOnlyHeaders()).containsOnly(\"ignoredHeader\");\n\t\t\t\t// See META-INF/spring.integration.properties\n\t\t\t\tassertThat(integrationProperties.getNoAutoStartupEndpoints()).containsOnly(\"testService*\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnIntegrationDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomIntegrationDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(IntegrationDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.doesNotHaveBean(\"integrationDataSourceScriptDatabaseInitializer\")\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredIntegrationInitializerRemains() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(IntegrationDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid defaultPoller() {\n\t\tthis.contextRunner.withUserConfiguration(PollingConsumerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(PollerMetadata.class);\n\t\t\tPollerMetadata metadata = context.getBean(PollerMetadata.DEFAULT_POLLER, PollerMetadata.class);\n\t\t\tassertThat(metadata.getMaxMessagesPerPoll()).isEqualTo(PollerMetadata.MAX_MESSAGES_UNBOUNDED);\n\t\t\tassertThat(metadata.getReceiveTimeout()).isEqualTo(PollerMetadata.DEFAULT_RECEIVE_TIMEOUT);\n\t\t\tassertThat(metadata.getTrigger()).isNull();\n\n\t\t\tGenericMessage<String> testMessage = new GenericMessage<>(\"test\");\n\t\t\tcontext.getBean(\"testChannel\", QueueChannel.class).send(testMessage);\n\t\t\tassertThat(context.getBean(\"sink\", BlockingQueue.class).poll(10, TimeUnit.SECONDS)).isSameAs(testMessage);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomPollerPropertiesAreSetThenTheyAreReflectedInPollerMetadata() {\n\t\tthis.contextRunner.withUserConfiguration(PollingConsumerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.integration.poller.cron=* * * ? * *\",\n\t\t\t\t\t\"spring.integration.poller.max-messages-per-poll=1\",\n\t\t\t\t\t\"spring.integration.poller.receive-timeout=10s\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PollerMetadata.class);\n\t\t\t\tPollerMetadata metadata = context.getBean(PollerMetadata.DEFAULT_POLLER, PollerMetadata.class);\n\t\t\t\tassertThat(metadata.getMaxMessagesPerPoll()).isOne();\n\t\t\t\tassertThat(metadata.getReceiveTimeout()).isEqualTo(10000L);\n\t\t\t\tassertThat(metadata.getTrigger()).asInstanceOf(InstanceOfAssertFactories.type(CronTrigger.class))\n\t\t\t\t\t.satisfies((trigger) -> assertThat(trigger.getExpression()).isEqualTo(\"* * * ? * *\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenPollerPropertiesForMultipleTriggerTypesAreSetThenRefreshFails() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.integration.poller.cron=* * * ? * *\",\n\t\t\t\t\t\"spring.integration.poller.fixed-delay=1s\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasRootCauseExactlyInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t\t.rootCause()\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(MutuallyExclusiveConfigurationPropertiesException.class))\n\t\t\t\t.satisfies((ex) -> {\n\t\t\t\t\tassertThat(ex.getConfiguredNames()).containsExactlyInAnyOrder(\"spring.integration.poller.cron\",\n\t\t\t\t\t\t\t\"spring.integration.poller.fixed-delay\");\n\t\t\t\t\tassertThat(ex.getMutuallyExclusiveNames()).containsExactlyInAnyOrder(\n\t\t\t\t\t\t\t\"spring.integration.poller.cron\", \"spring.integration.poller.fixed-delay\",\n\t\t\t\t\t\t\t\"spring.integration.poller.fixed-rate\");\n\t\t\t\t}));\n\n\t}\n\n\t@Test\n\tvoid whenFixedDelayPollerPropertyIsSetThenItIsReflectedAsFixedDelayPropertyOfPeriodicTrigger() {\n\t\tthis.contextRunner.withUserConfiguration(PollingConsumerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.integration.poller.fixed-delay=5000\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PollerMetadata.class);\n\t\t\t\tPollerMetadata metadata = context.getBean(PollerMetadata.DEFAULT_POLLER, PollerMetadata.class);\n\t\t\t\tassertThat(metadata.getTrigger()).asInstanceOf(InstanceOfAssertFactories.type(PeriodicTrigger.class))\n\t\t\t\t\t.satisfies((trigger) -> {\n\t\t\t\t\t\tassertThat(trigger.getPeriodDuration()).isEqualTo(Duration.ofSeconds(5));\n\t\t\t\t\t\tassertThat(trigger.isFixedRate()).isFalse();\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenFixedRatePollerPropertyIsSetThenItIsReflectedAsFixedRatePropertyOfPeriodicTrigger() {\n\t\tthis.contextRunner.withUserConfiguration(PollingConsumerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.integration.poller.fixed-rate=5000\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PollerMetadata.class);\n\t\t\t\tPollerMetadata metadata = context.getBean(PollerMetadata.DEFAULT_POLLER, PollerMetadata.class);\n\t\t\t\tassertThat(metadata.getTrigger()).asInstanceOf(InstanceOfAssertFactories.type(PeriodicTrigger.class))\n\t\t\t\t\t.satisfies((trigger) -> {\n\t\t\t\t\t\tassertThat(trigger.getPeriodDuration()).isEqualTo(Duration.ofSeconds(5));\n\t\t\t\t\t\tassertThat(trigger.isFixedRate()).isTrue();\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid integrationManagementLoggingIsEnabledByDefault() {\n\t\tthis.contextRunner.withBean(DirectChannel.class, DirectChannel::new)\n\t\t\t.run((context) -> assertThat(context).getBean(DirectChannel.class)\n\t\t\t\t.extracting(DirectChannel::isLoggingEnabled)\n\t\t\t\t.isEqualTo(true));\n\t}\n\n\t@Test\n\tvoid integrationManagementLoggingCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.integration.management.defaultLoggingEnabled=false\")\n\t\t\t.withBean(DirectChannel.class, DirectChannel::new)\n\t\t\t.run((context) -> assertThat(context).getBean(DirectChannel.class)\n\t\t\t\t.extracting(DirectChannel::isLoggingEnabled)\n\t\t\t\t.isEqualTo(false));\n\n\t}\n\n\t@Test\n\tvoid integrationManagementInstrumentedWithObservation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.integration.management.observation-patterns=testHandler\")\n\t\t\t.withBean(\"testHandler\", LoggingHandler.class, () -> new LoggingHandler(\"warn\"))\n\t\t\t.withBean(ObservationRegistry.class, ObservationRegistry::create)\n\t\t\t.withBean(BridgeHandler.class, BridgeHandler::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBean(\"testHandler\").extracting(\"observationRegistry\").isNotNull();\n\t\t\t\tassertThat(context).getBean(BridgeHandler.class)\n\t\t\t\t\t.extracting(\"observationRegistry\")\n\t\t\t\t\t.isEqualTo(ObservationRegistry.NOOP);\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid integrationVirtualThreadsEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(TaskScheduler.class)\n\t\t\t\t.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class)\n\t\t\t\t.isInstanceOf(SimpleAsyncTaskScheduler.class)\n\t\t\t\t.satisfies((taskScheduler) -> SimpleAsyncTaskExecutorAssert\n\t\t\t\t\t.assertThat((SimpleAsyncTaskExecutor) taskScheduler)\n\t\t\t\t\t.usesVirtualThreads()));\n\t}\n\n\t@Test\n\tvoid pollerMetadataCanBeCustomizedViaPollerMetadataCustomizer() {\n\t\tTaskExecutor taskExecutor = new SyncTaskExecutor();\n\t\tthis.contextRunner.withUserConfiguration(PollingConsumerConfiguration.class)\n\t\t\t.withBean(PollerMetadataCustomizer.class,\n\t\t\t\t\t() -> (pollerMetadata) -> pollerMetadata.setTaskExecutor(taskExecutor))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PollerMetadata.class);\n\t\t\t\tPollerMetadata metadata = context.getBean(PollerMetadata.DEFAULT_POLLER, PollerMetadata.class);\n\t\t\t\tassertThat(metadata.getTaskExecutor()).isSameAs(taskExecutor);\n\t\t\t});\n\t}\n\n\tprivate static DataSource createTestDataSource() {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setGenerateUniqueName(true);\n\t\ttry {\n\t\t\tproperties.afterPropertiesSet();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn properties.initializeDataSourceBuilder().build();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomMBeanExporter {\n\n\t\t@Bean\n\t\t@Primary\n\t\tMBeanExporter myMBeanExporter() {\n\t\t\treturn mock(MBeanExporter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@IntegrationComponentScan\n\tstatic class CustomIntegrationComponentScanConfiguration {\n\n\t}\n\n\t@MessagingGateway\n\tpublic interface TestGateway extends RequestReplyExchanger {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MessageSourceConfiguration {\n\n\t\t@Bean\n\t\tMessageSource<?> myMessageSource() {\n\t\t\treturn new MessageProcessorMessageSource(mock(MessageProcessor.class));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RSocketServerConfiguration {\n\n\t\t@Bean\n\t\tIntegrationRSocketEndpoint mockIntegrationRSocketEndpoint() {\n\t\t\treturn new IntegrationRSocketEndpoint() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Mono<Void> handleMessage(Message<?> message) {\n\t\t\t\t\treturn Mono.empty();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String[] getPath() {\n\t\t\t\t\treturn new String[] { \"/rsocketTestPath\" };\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomIntegrationDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tIntegrationDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource,\n\t\t\t\tIntegrationJdbcProperties properties) {\n\t\t\treturn new IntegrationDataSourceScriptDatabaseInitializer(dataSource, properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) {\n\t\t\treturn new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PollingConsumerConfiguration {\n\n\t\t@Bean\n\t\tQueueChannel testChannel() {\n\t\t\treturn new QueueChannel();\n\t\t}\n\n\t\t@Bean\n\t\tBlockingQueue<Message<?>> sink() {\n\t\t\treturn new LinkedBlockingQueue<>();\n\t\t}\n\n\t\t@ServiceActivator(inputChannel = \"testChannel\")\n\t\t@Bean\n\t\tMessageHandler handler(BlockingQueue<Message<?>> sink) {\n\t\t\treturn sink::add;\n\t\t}\n\n\t}\n\n\tstatic class PropertyAccessor {\n\n\t\tprivate final String name;\n\n\t\tPropertyAccessor(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Nullable Object get(org.springframework.integration.context.IntegrationProperties properties) {\n\t\t\treturn ReflectionTestUtils.invokeMethod(properties, this.name);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableIntegrationMBeanExport(defaultDomain = \"foo.my\")\n\tstatic class CustomJmxDomainConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/autoconfigure/IntegrationDataSourceScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.sql.init.ScriptDatabaseInitializerSettings;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link IntegrationDataSourceScriptDatabaseInitializer}.\n *\n * @author Stephane Nicoll\n */\nclass IntegrationDataSourceScriptDatabaseInitializerTests {\n\n\t@Test\n\tvoid getSettingsWithPlatformDoesNotTouchDataSource() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tIntegrationJdbcProperties properties = new IntegrationJdbcProperties();\n\t\tproperties.setPlatform(\"test\");\n\t\tDatabaseInitializationSettings settings = ScriptDatabaseInitializerSettings\n\t\t\t.get(new IntegrationDataSourceScriptDatabaseInitializer(dataSource, properties));\n\t\tassertThat(settings.getSchemaLocations())\n\t\t\t.containsOnly(\"classpath:org/springframework/integration/jdbc/schema-test.sql\");\n\t\tthen(dataSource).shouldHaveNoInteractions();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/autoconfigure/IntegrationGraphEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.integration.actuate.endpoint.IntegrationGraphEndpoint;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.integration.graph.IntegrationGraphServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IntegrationGraphEndpointAutoConfiguration}.\n *\n * @author Tim Ysewyn\n * @author Stephane Nicoll\n */\nclass IntegrationGraphEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, IntegrationAutoConfiguration.class,\n\t\t\t\tIntegrationGraphEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=integrationgraph\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(IntegrationGraphEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.integrationgraph.enabled:false\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class);\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationGraphServer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class);\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationGraphServer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenSpringIntegrationIsNotEnabledShouldNotHaveEndpointBean() {\n\t\tApplicationContextRunner noSpringIntegrationRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(IntegrationGraphEndpointAutoConfiguration.class));\n\t\tnoSpringIntegrationRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationGraphEndpoint.class);\n\t\t\tassertThat(context).doesNotHaveBean(IntegrationGraphServer.class);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/autoconfigure/IntegrationPropertiesEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure;\n\nimport java.io.FileNotFoundException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginLookup;\nimport org.springframework.boot.origin.TextResourceOrigin;\nimport org.springframework.boot.origin.TextResourceOrigin.Location;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.integration.context.IntegrationProperties;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link IntegrationPropertiesEnvironmentPostProcessor}.\n *\n * @author Stephane Nicoll\n */\nclass IntegrationPropertiesEnvironmentPostProcessorTests {\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.integration.properties\",\n\t\t\tcontent = \"spring.integration.endpoints.noAutoStartup=testService*\")\n\tvoid postProcessEnvironmentAddPropertySource() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tnew IntegrationPropertiesEnvironmentPostProcessor().postProcessEnvironment(environment,\n\t\t\t\tmock(SpringApplication.class));\n\t\tassertThat(environment.getPropertySources().contains(\"META-INF/spring.integration.properties\")).isTrue();\n\t\tassertThat(environment.getProperty(\"spring.integration.endpoint.no-auto-startup\")).isEqualTo(\"testService*\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.integration.properties\",\n\t\t\tcontent = \"spring.integration.endpoints.noAutoStartup=testService*\")\n\tvoid postProcessEnvironmentAddPropertySourceLast() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addLast(new MapPropertySource(\"test\",\n\t\t\t\t\tCollections.singletonMap(\"spring.integration.endpoint.no-auto-startup\", \"another*\")));\n\t\tnew IntegrationPropertiesEnvironmentPostProcessor().postProcessEnvironment(environment,\n\t\t\t\tmock(SpringApplication.class));\n\t\tassertThat(environment.getPropertySources().contains(\"META-INF/spring.integration.properties\")).isTrue();\n\t\tassertThat(environment.getProperty(\"spring.integration.endpoint.no-auto-startup\")).isEqualTo(\"another*\");\n\t}\n\n\t@Test\n\tvoid registerIntegrationPropertiesPropertySourceWithUnknownResourceThrowsException() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tClassPathResource unknown = new ClassPathResource(\"does-not-exist.properties\", getClass());\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new IntegrationPropertiesEnvironmentPostProcessor()\n\t\t\t\t.registerIntegrationPropertiesPropertySource(environment, unknown))\n\t\t\t.withCauseInstanceOf(FileNotFoundException.class)\n\t\t\t.withMessageContaining(unknown.toString());\n\t}\n\n\t@Test\n\tvoid registerIntegrationPropertiesPropertySourceWithResourceAddPropertySource() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tnew IntegrationPropertiesEnvironmentPostProcessor().registerIntegrationPropertiesPropertySource(environment,\n\t\t\t\tnew ClassPathResource(\"spring.integration.properties\", getClass()));\n\t\tassertThat(environment.getProperty(\"spring.integration.channel.auto-create\", Boolean.class)).isFalse();\n\t\tassertThat(environment.getProperty(\"spring.integration.channel.max-unicast-subscribers\", Integer.class))\n\t\t\t.isEqualTo(4);\n\t\tassertThat(environment.getProperty(\"spring.integration.channel.max-broadcast-subscribers\", Integer.class))\n\t\t\t.isEqualTo(6);\n\t\tassertThat(environment.getProperty(\"spring.integration.error.require-subscribers\", Boolean.class)).isFalse();\n\t\tassertThat(environment.getProperty(\"spring.integration.error.ignore-failures\", Boolean.class)).isFalse();\n\t\tassertThat(environment.getProperty(\"spring.integration.endpoint.throw-exception-on-late-reply\", Boolean.class))\n\t\t\t.isTrue();\n\t\tassertThat(environment.getProperty(\"spring.integration.endpoint.read-only-headers\", String.class))\n\t\t\t.isEqualTo(\"header1,header2\");\n\t\tassertThat(environment.getProperty(\"spring.integration.endpoint.no-auto-startup\", String.class))\n\t\t\t.isEqualTo(\"testService,anotherService\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid registerIntegrationPropertiesPropertySourceWithResourceCanRetrieveOrigin() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tClassPathResource resource = new ClassPathResource(\"spring.integration.properties\", getClass());\n\t\tnew IntegrationPropertiesEnvironmentPostProcessor().registerIntegrationPropertiesPropertySource(environment,\n\t\t\t\tresource);\n\t\tPropertySource<?> ps = environment.getPropertySources().get(\"META-INF/spring.integration.properties\");\n\t\tassertThat(ps).isInstanceOf(OriginLookup.class);\n\t\tOriginLookup<String> originLookup = (OriginLookup<String>) ps;\n\t\tassertThat(originLookup.getOrigin(\"spring.integration.channel.auto-create\"))\n\t\t\t.satisfies(textOrigin(resource, 0, 39));\n\t\tassertThat(originLookup.getOrigin(\"spring.integration.channel.max-unicast-subscribers\"))\n\t\t\t.satisfies(textOrigin(resource, 1, 50));\n\t\tassertThat(originLookup.getOrigin(\"spring.integration.channel.max-broadcast-subscribers\"))\n\t\t\t.satisfies(textOrigin(resource, 2, 52));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid hasMappingsForAllMappableProperties() throws Exception {\n\t\tClass<?> propertySource = ClassUtils.forName(\"%s.IntegrationPropertiesPropertySource\"\n\t\t\t.formatted(IntegrationPropertiesEnvironmentPostProcessor.class.getName()), getClass().getClassLoader());\n\t\tMap<String, String> mappings = (Map<String, String>) ReflectionTestUtils.getField(propertySource,\n\t\t\t\t\"KEYS_MAPPING\");\n\t\tassertThat(mappings).isNotNull();\n\t\tassertThat(mappings.values()).containsExactlyInAnyOrderElementsOf(integrationPropertyNames());\n\t}\n\n\tprivate static List<String> integrationPropertyNames() {\n\t\tList<String> propertiesToMap = new ArrayList<>();\n\t\tReflectionUtils.doWithFields(IntegrationProperties.class, (field) -> {\n\t\t\tString value = (String) ReflectionUtils.getField(field, null);\n\t\t\tassertThat(value).isNotNull();\n\t\t\tif (value.startsWith(IntegrationProperties.INTEGRATION_PROPERTIES_PREFIX)\n\t\t\t\t\t&& value.length() > IntegrationProperties.INTEGRATION_PROPERTIES_PREFIX.length()) {\n\t\t\t\tpropertiesToMap.add(value);\n\t\t\t}\n\t\t}, (field) -> Modifier.isStatic(field.getModifiers()) && field.getType().equals(String.class));\n\t\tpropertiesToMap.remove(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE);\n\t\treturn propertiesToMap;\n\t}\n\n\t@MethodSource(\"mappedConfigurationProperties\")\n\t@ParameterizedTest\n\tvoid mappedPropertiesExistOnBootsIntegrationProperties(String mapping) {\n\t\tBindable<org.springframework.boot.integration.autoconfigure.IntegrationProperties> bindable = Bindable\n\t\t\t.of(org.springframework.boot.integration.autoconfigure.IntegrationProperties.class);\n\t\tMockEnvironment environment = new MockEnvironment().withProperty(mapping,\n\t\t\t\t(mapping.contains(\"max\") || mapping.contains(\"timeout\")) ? \"1\" : \"true\");\n\t\tBindResult<org.springframework.boot.integration.autoconfigure.IntegrationProperties> result = Binder\n\t\t\t.get(environment)\n\t\t\t.bind(\"spring.integration\", bindable);\n\t\tassertThat(result.isBound()).isTrue();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static Collection<String> mappedConfigurationProperties() {\n\t\ttry {\n\t\t\tClass<?> propertySource = ClassUtils.forName(\"%s.IntegrationPropertiesPropertySource\"\n\t\t\t\t.formatted(IntegrationPropertiesEnvironmentPostProcessor.class.getName()), null);\n\t\t\tMap<String, String> mappings = (Map<String, String>) ReflectionTestUtils.getField(propertySource,\n\t\t\t\t\t\"KEYS_MAPPING\");\n\t\t\tassertThat(mappings).isNotNull();\n\t\t\treturn mappings.keySet();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate Consumer<Origin> textOrigin(Resource resource, int line, int column) {\n\t\treturn (origin) -> {\n\t\t\tassertThat(origin).isInstanceOf(TextResourceOrigin.class);\n\t\t\tTextResourceOrigin textOrigin = (TextResourceOrigin) origin;\n\t\t\tassertThat(textOrigin.getResource()).isEqualTo(resource);\n\t\t\tLocation location = textOrigin.getLocation();\n\t\t\tassertThat(location).isNotNull();\n\t\t\tassertThat(location.getLine()).isEqualTo(line);\n\t\t\tassertThat(location.getColumn()).isEqualTo(column);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/java/org/springframework/boot/integration/autoconfigure/metrics/IntegrationMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.integration.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.integration.autoconfigure.IntegrationAutoConfiguration;\nimport org.springframework.boot.integration.autoconfigure.IntegrationGraphEndpointAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link IntegrationMetricsAutoConfiguration}.\n *\n * @author Artem Bilan\n */\nclass IntegrationMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(IntegrationAutoConfiguration.class,\n\t\t\t\tIntegrationGraphEndpointAutoConfiguration.class, IntegrationMetricsAutoConfiguration.class,\n\t\t\t\tMetricsAutoConfiguration.class))\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withPropertyValues(\"management.metrics.tags.someTag=someValue\",\n\t\t\t\t\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid integrationMetersAreInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tGauge gauge = registry.get(\"spring.integration.channels\").tag(\"someTag\", \"someValue\").gauge();\n\t\t\tassertThat(gauge).isNotNull().extracting(Gauge::value).isEqualTo(2.0);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-integration/src/test/resources/org/springframework/boot/integration/autoconfigure/spring.integration.properties",
    "content": "spring.integration.channels.autoCreate=false\nspring.integration.channels.maxUnicastSubscribers=4\nspring.integration.channels.maxBroadcastSubscribers=6\nspring.integration.channels.error.requireSubscribers=false\nspring.integration.channels.error.ignoreFailures=false\nspring.integration.messagingTemplate.throwExceptionOnLateReply=true\nspring.integration.readOnly.headers=header1,header2\nspring.integration.endpoints.noAutoStartup=testService,anotherService\n"
  },
  {
    "path": "module/spring-boot-jackson/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Jackson\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"tools.jackson.core:jackson-databind\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\toptional(\"org.springframework:spring-web\")\n\toptional(\"tools.jackson.dataformat:jackson-dataformat-cbor\")\n\toptional(\"tools.jackson.dataformat:jackson-dataformat-xml\")\n\toptional(\"tools.jackson.module:jackson-module-jakarta-xmlbind-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"tools.jackson.module:jackson-module-kotlin\")\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/JacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport tools.jackson.databind.KeyDeserializer;\nimport tools.jackson.databind.ValueDeserializer;\nimport tools.jackson.databind.ValueSerializer;\n\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link Component @Component} that provides {@link ValueSerializer},\n * {@link ValueDeserializer} or {@link KeyDeserializer} implementations to be registered\n * with Jackson when {@link JacksonComponentModule} is in use. Can be used to annotate\n * implementations directly or a class that contains them as inner-classes. For example:\n * <pre class=\"code\">\n * &#064;JacksonComponent\n * public class CustomerJacksonComponent {\n *\n *     public static class Serializer extends ValueSerializer&lt;Customer&gt; {\n *\n *         // ...\n *\n *     }\n *\n *     public static class Deserializer extends ValueDeserializer&lt;Customer&gt; {\n *\n *         // ...\n *\n *     }\n *\n * }\n *\n * </pre>\n *\n * @see JacksonComponentModule\n * @since 4.0.0\n * @author Phillip Webb\n * @author Paul Aly\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Component\npublic @interface JacksonComponent {\n\n\t/**\n\t * The value may indicate a suggestion for a logical component name, to be turned into\n\t * a Spring bean in case of an auto-detected component.\n\t * @return the component name\n\t */\n\t@AliasFor(annotation = Component.class)\n\tString value() default \"\";\n\n\t/**\n\t * The types that are handled by the provided serializer/deserializer. This attribute\n\t * is mandatory for a {@link KeyDeserializer}, as the type cannot be inferred. For a\n\t * {@link ValueSerializer} or {@link ValueDeserializer} it can be used to limit\n\t * handling to a subclasses of type inferred from the generic.\n\t * @return the types that should be handled by the component\n\t */\n\tClass<?>[] type() default {};\n\n\t/**\n\t * The scope under which the serializer/deserializer should be registered with the\n\t * module.\n\t * @return the component's handle type\n\t */\n\tScope scope() default Scope.VALUES;\n\n\t/**\n\t * The various scopes under which a serializer/deserializer can be registered.\n\t */\n\tenum Scope {\n\n\t\t/**\n\t\t * A serializer/deserializer for regular value content.\n\t\t * @see ValueSerializer\n\t\t * @see ValueDeserializer\n\t\t */\n\t\tVALUES,\n\n\t\t/**\n\t\t * A serializer/deserializer for keys.\n\t\t * @see ValueSerializer\n\t\t * @see ValueDeserializer\n\t\t */\n\t\tKEYS\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/JacksonComponentModule.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JacksonModule;\nimport tools.jackson.databind.KeyDeserializer;\nimport tools.jackson.databind.ValueDeserializer;\nimport tools.jackson.databind.ValueSerializer;\nimport tools.jackson.databind.module.SimpleModule;\n\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.HierarchicalBeanFactory;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.jackson.JacksonComponent.Scope;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link JacksonModule} to register {@link JacksonComponent @JacksonComponent} annotated\n * beans.\n *\n * @author Phillip Webb\n * @author Paul Aly\n * @since 4.0.0\n * @see JacksonComponent\n */\npublic class JacksonComponentModule extends SimpleModule implements BeanFactoryAware, InitializingBean {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanFactory beanFactory;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tregisterJacksonComponents();\n\t}\n\n\tpublic void registerJacksonComponents() {\n\t\tBeanFactory beanFactory = this.beanFactory;\n\t\twhile (beanFactory != null) {\n\t\t\tif (beanFactory instanceof ListableBeanFactory listableBeanFactory) {\n\t\t\t\taddJacksonComponentBeans(listableBeanFactory);\n\t\t\t}\n\t\t\tbeanFactory = (beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory)\n\t\t\t\t\t? hierarchicalBeanFactory.getParentBeanFactory() : null;\n\t\t}\n\t}\n\n\tprivate void addJacksonComponentBeans(ListableBeanFactory beanFactory) {\n\t\tMap<String, Object> beans = beanFactory.getBeansWithAnnotation(JacksonComponent.class);\n\t\tfor (Object bean : beans.values()) {\n\t\t\taddJacksonComponentBean(bean);\n\t\t}\n\t}\n\n\tprivate void addJacksonComponentBean(Object bean) {\n\t\tMergedAnnotation<JacksonComponent> annotation = MergedAnnotations\n\t\t\t.from(bean.getClass(), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(JacksonComponent.class);\n\t\tClass<?>[] types = annotation.getClassArray(\"type\");\n\t\tScope scope = annotation.getEnum(\"scope\", JacksonComponent.Scope.class);\n\t\taddJacksonComponentBean(bean, types, scope);\n\t}\n\n\tprivate void addJacksonComponentBean(Object bean, Class<?>[] types, Scope scope) {\n\t\tif (bean instanceof ValueSerializer<?> jsonSerializer) {\n\t\t\taddValueSerializerBean(jsonSerializer, scope, types);\n\t\t}\n\t\telse if (bean instanceof ValueDeserializer<?> jsonDeserializer) {\n\t\t\taddValueDeserializerBean(jsonDeserializer, types);\n\t\t}\n\t\telse if (bean instanceof KeyDeserializer keyDeserializer) {\n\t\t\taddKeyDeserializerBean(keyDeserializer, types);\n\t\t}\n\t\tfor (Class<?> innerClass : bean.getClass().getDeclaredClasses()) {\n\t\t\tif (isSuitableInnerClass(innerClass)) {\n\t\t\t\tObject innerInstance = BeanUtils.instantiateClass(innerClass);\n\t\t\t\taddJacksonComponentBean(innerInstance, types, scope);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static boolean isSuitableInnerClass(Class<?> innerClass) {\n\t\treturn !Modifier.isAbstract(innerClass.getModifiers()) && (ValueSerializer.class.isAssignableFrom(innerClass)\n\t\t\t\t|| ValueDeserializer.class.isAssignableFrom(innerClass)\n\t\t\t\t|| KeyDeserializer.class.isAssignableFrom(innerClass));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> void addValueSerializerBean(ValueSerializer<T> serializer, JacksonComponent.Scope scope,\n\t\t\tClass<?>[] types) {\n\t\tClass<T> baseType = (Class<T>) ResolvableType.forClass(ValueSerializer.class, serializer.getClass())\n\t\t\t.resolveGeneric();\n\t\tAssert.state(baseType != null, \"'baseType' must not be null\");\n\t\taddBeanToModule(serializer, baseType, types,\n\t\t\t\t(scope == Scope.VALUES) ? this::addSerializer : this::addKeySerializer);\n\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> void addValueDeserializerBean(ValueDeserializer<T> deserializer, Class<?>[] types) {\n\t\tClass<T> baseType = (Class<T>) ResolvableType.forClass(ValueDeserializer.class, deserializer.getClass())\n\t\t\t.resolveGeneric();\n\t\tAssert.state(baseType != null, \"'baseType' must not be null\");\n\t\taddBeanToModule(deserializer, baseType, types, this::addDeserializer);\n\t}\n\n\tprivate void addKeyDeserializerBean(KeyDeserializer deserializer, Class<?>[] types) {\n\t\tAssert.notEmpty(types, \"'types' must not be empty\");\n\t\taddBeanToModule(deserializer, Object.class, types, this::addKeyDeserializer);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <E, T> void addBeanToModule(E element, Class<T> baseType, Class<?>[] types,\n\t\t\tBiConsumer<Class<T>, E> consumer) {\n\t\tif (ObjectUtils.isEmpty(types)) {\n\t\t\tconsumer.accept(baseType, element);\n\t\t\treturn;\n\t\t}\n\t\tfor (Class<?> type : types) {\n\t\t\tAssert.isAssignable(baseType, type);\n\t\t\tconsumer.accept((Class<T>) type, element);\n\t\t}\n\t}\n\n\tstatic class JacksonComponentBeanFactoryInitializationAotProcessor\n\t\t\timplements BeanFactoryInitializationAotProcessor {\n\n\t\t@Override\n\t\tpublic @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(\n\t\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\t\tString[] jacksonComponents = beanFactory.getBeanNamesForAnnotation(JacksonComponent.class);\n\t\t\tMap<Class<?>, List<Class<?>>> innerComponents = new HashMap<>();\n\t\t\tfor (String jacksonComponent : jacksonComponents) {\n\t\t\t\tClass<?> type = beanFactory.getType(jacksonComponent, true);\n\t\t\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\t\t\tfor (Class<?> declaredClass : type.getDeclaredClasses()) {\n\t\t\t\t\tif (isSuitableInnerClass(declaredClass)) {\n\t\t\t\t\t\tinnerComponents.computeIfAbsent(type, (t) -> new ArrayList<>()).add(declaredClass);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn innerComponents.isEmpty() ? null : new JacksonComponentAotContribution(innerComponents);\n\t\t}\n\n\t}\n\n\tprivate static final class JacksonComponentAotContribution implements BeanFactoryInitializationAotContribution {\n\n\t\tprivate final Map<Class<?>, List<Class<?>>> innerComponents;\n\n\t\tprivate JacksonComponentAotContribution(Map<Class<?>, List<Class<?>>> innerComponents) {\n\t\t\tthis.innerComponents = innerComponents;\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\tReflectionHints reflection = generationContext.getRuntimeHints().reflection();\n\t\t\tthis.innerComponents.forEach((outer, inners) -> {\n\t\t\t\treflection.registerType(outer);\n\t\t\t\tinners.forEach((inner) -> reflection.registerType(inner, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/JacksonMixin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Provides a mixin class implementation that registers with Jackson when using\n * {@link JacksonMixinModule}.\n *\n * @author Guirong Hu\n * @see JacksonMixinModule\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface JacksonMixin {\n\n\t/**\n\t * Alias for the {@link #type()} attribute. Allows for more concise annotation\n\t * declarations e.g.: {@code @JacksonMixin(MyType.class)} instead of\n\t * {@code @JacksonMixin(type=MyType.class)}.\n\t * @return the mixed-in classes\n\t */\n\t@AliasFor(\"type\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The types that are handled by the provided mixin class. {@link #value()} is an\n\t * alias for (and mutually exclusive with) this attribute.\n\t * @return the mixed-in classes\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] type() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/JacksonMixinModule.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.JacksonModule;\nimport tools.jackson.databind.module.SimpleModule;\n\n/**\n * {@link JacksonModule} to find and {@link SimpleModule#setMixInAnnotation(Class, Class)\n * register} {@link JacksonMixin @JacksonMixin}-annotated classes.\n *\n * @author Guirong Hu\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see JacksonMixin\n */\npublic class JacksonMixinModule extends SimpleModule {\n\n\t/**\n\t * Register the specified {@link JacksonMixinModuleEntries entries}.\n\t * @param entries the entries to register to this instance\n\t * @param classLoader the classloader to use\n\t */\n\tpublic void registerEntries(JacksonMixinModuleEntries entries, @Nullable ClassLoader classLoader) {\n\t\tentries.doWithEntry(classLoader, this::setMixInAnnotation);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/JacksonMixinModuleEntries.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provides the mapping of Jackson mixin classes to consider.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class JacksonMixinModuleEntries {\n\n\tprivate final Map<Object, Object> entries;\n\n\tprivate JacksonMixinModuleEntries(Builder builder) {\n\t\tthis.entries = new LinkedHashMap<>(builder.entries);\n\t}\n\n\t/**\n\t * Create an instance using the specified {@link Builder}.\n\t * @param mixins a consumer of the builder\n\t * @return an instance with the state of the customized builder.\n\t */\n\tpublic static JacksonMixinModuleEntries create(Consumer<Builder> mixins) {\n\t\tBuilder builder = new Builder();\n\t\tmixins.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\t/**\n\t * Scan the classpath for {@link JacksonMixin @JacksonMixin} in the specified\n\t * {@code basePackages}.\n\t * @param context the application context to use\n\t * @param basePackages the base packages to consider\n\t * @return an instance with the result of the scanning\n\t */\n\tpublic static JacksonMixinModuleEntries scan(ApplicationContext context, Collection<String> basePackages) {\n\t\treturn JacksonMixinModuleEntries.create((builder) -> {\n\t\t\tif (ObjectUtils.isEmpty(basePackages)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tJacksonMixinComponentScanner scanner = new JacksonMixinComponentScanner();\n\t\t\tscanner.setEnvironment(context.getEnvironment());\n\t\t\tscanner.setResourceLoader(context);\n\t\t\tfor (String basePackage : basePackages) {\n\t\t\t\tif (StringUtils.hasText(basePackage)) {\n\t\t\t\t\tfor (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {\n\t\t\t\t\t\tString beanClassName = candidate.getBeanClassName();\n\t\t\t\t\t\tAssert.state(beanClassName != null, \"'beanClassName' must not be null\");\n\t\t\t\t\t\tClass<?> mixinClass = ClassUtils.resolveClassName(beanClassName, context.getClassLoader());\n\t\t\t\t\t\tregisterMixinClass(builder, mixinClass);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static void registerMixinClass(Builder builder, Class<?> mixinClass) {\n\t\tMergedAnnotation<JacksonMixin> annotation = MergedAnnotations\n\t\t\t.from(mixinClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(JacksonMixin.class);\n\t\tClass<?>[] types = annotation.getClassArray(\"type\");\n\t\tAssert.state(!ObjectUtils.isEmpty(types),\n\t\t\t\t() -> \"@JacksonMixin annotation on class '\" + mixinClass.getName() + \"' does not specify any types\");\n\t\tfor (Class<?> type : types) {\n\t\t\tbuilder.and(type, mixinClass);\n\t\t}\n\t}\n\n\t/**\n\t * Perform an action on each entry defined by this instance. If a class needs to be\n\t * resolved from its class name, the specified {@link ClassLoader} is used.\n\t * @param classLoader the classloader to use to resolve class name if necessary\n\t * @param action the action to invoke on each type to mixin class entry\n\t */\n\tpublic void doWithEntry(@Nullable ClassLoader classLoader, BiConsumer<Class<?>, Class<?>> action) {\n\t\tthis.entries.forEach((type, mixin) -> action.accept(resolveClassNameIfNecessary(type, classLoader),\n\t\t\t\tresolveClassNameIfNecessary(mixin, classLoader)));\n\t}\n\n\tprivate Class<?> resolveClassNameIfNecessary(Object nameOrType, @Nullable ClassLoader classLoader) {\n\t\treturn (nameOrType instanceof Class<?> type) ? type\n\t\t\t\t: ClassUtils.resolveClassName((String) nameOrType, classLoader);\n\t}\n\n\t/**\n\t * Builder for {@link JacksonMixinModuleEntries}.\n\t */\n\tpublic static class Builder {\n\n\t\tprivate final Map<Object, Object> entries;\n\n\t\tBuilder() {\n\t\t\tthis.entries = new LinkedHashMap<>();\n\t\t}\n\n\t\t/**\n\t\t * Add a mapping for the specified class names.\n\t\t * @param typeClassName the type class name\n\t\t * @param mixinClassName the mixin class name\n\t\t * @return {@code this}, to facilitate method chaining\n\t\t */\n\t\tpublic Builder and(String typeClassName, String mixinClassName) {\n\t\t\tthis.entries.put(typeClassName, mixinClassName);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Add a mapping for the specified classes.\n\t\t * @param type the type class\n\t\t * @param mixinClass the mixin class\n\t\t * @return {@code this}, to facilitate method chaining\n\t\t */\n\t\tpublic Builder and(Class<?> type, Class<?> mixinClass) {\n\t\t\tthis.entries.put(type, mixinClass);\n\t\t\treturn this;\n\t\t}\n\n\t\tJacksonMixinModuleEntries build() {\n\t\t\treturn new JacksonMixinModuleEntries(this);\n\t\t}\n\n\t}\n\n\tstatic class JacksonMixinComponentScanner extends ClassPathScanningCandidateComponentProvider {\n\n\t\tJacksonMixinComponentScanner() {\n\t\t\taddIncludeFilter(new AnnotationTypeFilter(JacksonMixin.class));\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/JacksonMixinModuleEntriesBeanRegistrationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport javax.lang.model.element.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.AccessControl;\nimport org.springframework.aot.generate.GeneratedMethod;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.javapoet.CodeBlock;\n\n/**\n * {@link BeanRegistrationAotProcessor} that replaces any\n * {@link JacksonMixinModuleEntries} with a hard-coded equivalent. This has the effect of\n * disabling scanning at runtime.\n *\n * @author Stephane Nicoll\n */\nclass JacksonMixinModuleEntriesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {\n\n\t@Override\n\tpublic @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n\t\tif (registeredBean.getBeanClass().equals(JacksonMixinModuleEntries.class)) {\n\t\t\treturn BeanRegistrationAotContribution\n\t\t\t\t.withCustomCodeFragments((codeFragments) -> new AotContribution(codeFragments, registeredBean));\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic class AotContribution extends BeanRegistrationCodeFragmentsDecorator {\n\n\t\tprivate static final Class<?> BEAN_TYPE = JacksonMixinModuleEntries.class;\n\n\t\tprivate final RegisteredBean registeredBean;\n\n\t\tprivate final @Nullable ClassLoader classLoader;\n\n\t\tAotContribution(BeanRegistrationCodeFragments delegate, RegisteredBean registeredBean) {\n\t\t\tsuper(delegate);\n\t\t\tthis.registeredBean = registeredBean;\n\t\t\tthis.classLoader = registeredBean.getBeanFactory().getBeanClassLoader();\n\t\t}\n\n\t\t@Override\n\t\tpublic ClassName getTarget(RegisteredBean registeredBean) {\n\t\t\treturn ClassName.get(BEAN_TYPE);\n\t\t}\n\n\t\t@Override\n\t\tpublic CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,\n\t\t\t\tBeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {\n\t\t\tJacksonMixinModuleEntries entries = this.registeredBean.getBeanFactory()\n\t\t\t\t.getBean(this.registeredBean.getBeanName(), JacksonMixinModuleEntries.class);\n\t\t\tcontributeHints(generationContext.getRuntimeHints(), entries);\n\t\t\tGeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add(\"getInstance\", (method) -> {\n\t\t\t\tmethod.addJavadoc(\"Get the bean instance for '$L'.\", this.registeredBean.getBeanName());\n\t\t\t\tmethod.addModifiers(Modifier.PRIVATE, Modifier.STATIC);\n\t\t\t\tmethod.returns(BEAN_TYPE);\n\t\t\t\tCodeBlock.Builder code = CodeBlock.builder();\n\t\t\t\tcode.add(\"return $T.create(\", JacksonMixinModuleEntries.class).beginControlFlow(\"(mixins) ->\");\n\t\t\t\tentries.doWithEntry(this.classLoader, (type, mixin) -> addEntryCode(code, type, mixin));\n\t\t\t\tcode.endControlFlow(\")\");\n\t\t\t\tmethod.addCode(code.build());\n\t\t\t});\n\t\t\treturn generatedMethod.toMethodReference().toCodeBlock();\n\t\t}\n\n\t\tprivate void addEntryCode(CodeBlock.Builder code, Class<?> type, Class<?> mixin) {\n\t\t\tAccessControl accessForTypes = AccessControl.lowest(AccessControl.forClass(type),\n\t\t\t\t\tAccessControl.forClass(mixin));\n\t\t\tif (accessForTypes.isPublic()) {\n\t\t\t\tcode.addStatement(\"$L.and($T.class, $T.class)\", \"mixins\", type, mixin);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcode.addStatement(\"$L.and($S, $S)\", \"mixins\", type.getName(), mixin.getName());\n\t\t\t}\n\t\t}\n\n\t\tprivate void contributeHints(RuntimeHints runtimeHints, JacksonMixinModuleEntries entries) {\n\t\t\tSet<Class<?>> mixins = new LinkedHashSet<>();\n\t\t\tentries.doWithEntry(this.classLoader, (type, mixin) -> mixins.add(mixin));\n\t\t\tnew BindingReflectionHintsRegistrar().registerReflectionHints(runtimeHints.reflection(),\n\t\t\t\t\tmixins.toArray(Class<?>[]::new));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/ObjectValueDeserializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.core.TreeNode;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.ValueDeserializer;\nimport tools.jackson.databind.node.NullNode;\n\nimport org.springframework.util.Assert;\n\n/**\n * Helper base class for {@link ValueDeserializer} implementations that deserialize\n * objects.\n *\n * @param <T> the supported object type\n * @author Phillip Webb\n * @since 4.0.0\n * @see ObjectValueSerializer\n */\npublic abstract class ObjectValueDeserializer<T> extends ValueDeserializer<T> {\n\n\t@Override\n\tpublic final T deserialize(JsonParser jp, DeserializationContext ctxt) {\n\t\tTreeNode tree = jp.readValueAsTree();\n\t\tif (tree instanceof JsonNode jsonNode) {\n\t\t\treturn deserializeObject(jp, ctxt, jsonNode);\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"JsonParser \" + jp + \" produced \" + tree.getClass() + \" that is not a JsonNode\");\n\t}\n\n\t/**\n\t * Deserialize JSON content into the value type this serializer handles.\n\t * @param jsonParser the source parser used for reading JSON content\n\t * @param context context that can be used to access information about this\n\t * deserialization activity\n\t * @param tree deserialized JSON content as tree expressed using set of\n\t * {@link TreeNode} instances\n\t * @return the deserialized object\n\t * @see #deserialize(JsonParser, DeserializationContext)\n\t */\n\tprotected abstract T deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree);\n\n\t/**\n\t * Helper method to extract a value from the given {@code jsonNode} or return\n\t * {@code null} when the node itself is {@code null}.\n\t * @param jsonNode the source node (may be {@code null})\n\t * @param type the data type. May be {@link String}, {@link Boolean}, {@link Long},\n\t * {@link Integer}, {@link Short}, {@link Double}, {@link Float}, {@link BigDecimal}\n\t * or {@link BigInteger}.\n\t * @param <D> the data type requested\n\t * @param <R> the result type\n\t * @param mapper a mapper to convert the value when it is not {@code null}\n\t * @return the node value or {@code null}\n\t */\n\tprotected final <D, R> @Nullable R nullSafeValue(@Nullable JsonNode jsonNode, Class<D> type,\n\t\t\tFunction<D, R> mapper) {\n\t\tD value = nullSafeValue(jsonNode, type);\n\t\treturn (value != null) ? mapper.apply(value) : null;\n\t}\n\n\t/**\n\t * Helper method to extract a value from the given {@code jsonNode} or return\n\t * {@code null} when the node itself is {@code null}.\n\t * @param jsonNode the source node (may be {@code null})\n\t * @param type the data type. May be {@link String}, {@link Boolean}, {@link Long},\n\t * {@link Integer}, {@link Short}, {@link Double}, {@link Float}, {@link BigDecimal}\n\t * or {@link BigInteger}.\n\t * @param <D> the data type requested\n\t * @return the node value or {@code null}\n\t */\n\t@SuppressWarnings({ \"unchecked\" })\n\tprotected final <D> @Nullable D nullSafeValue(@Nullable JsonNode jsonNode, Class<D> type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tif (jsonNode == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (type == String.class) {\n\t\t\treturn (D) jsonNode.stringValue();\n\t\t}\n\t\tif (type == Boolean.class) {\n\t\t\treturn (D) Boolean.valueOf(jsonNode.booleanValue());\n\t\t}\n\t\tif (type == Long.class) {\n\t\t\treturn (D) Long.valueOf(jsonNode.longValue());\n\t\t}\n\t\tif (type == Integer.class) {\n\t\t\treturn (D) Integer.valueOf(jsonNode.intValue());\n\t\t}\n\t\tif (type == Short.class) {\n\t\t\treturn (D) Short.valueOf(jsonNode.shortValue());\n\t\t}\n\t\tif (type == Double.class) {\n\t\t\treturn (D) Double.valueOf(jsonNode.doubleValue());\n\t\t}\n\t\tif (type == Float.class) {\n\t\t\treturn (D) Float.valueOf(jsonNode.floatValue());\n\t\t}\n\t\tif (type == BigDecimal.class) {\n\t\t\treturn (D) jsonNode.decimalValue();\n\t\t}\n\t\tif (type == BigInteger.class) {\n\t\t\treturn (D) jsonNode.bigIntegerValue();\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Unsupported value type \" + type.getName());\n\t}\n\n\t/**\n\t * Helper method to return a {@link JsonNode} from the tree.\n\t * @param tree the source tree\n\t * @param fieldName the field name to extract\n\t * @return the {@link JsonNode}\n\t */\n\tprotected final JsonNode getRequiredNode(JsonNode tree, String fieldName) {\n\t\tAssert.notNull(tree, \"'tree' must not be null\");\n\t\tJsonNode node = tree.get(fieldName);\n\t\tAssert.state(node != null && !(node instanceof NullNode), () -> \"Missing JSON field '\" + fieldName + \"'\");\n\t\treturn node;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/ObjectValueSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.ValueSerializer;\n\n/**\n * Helper base class for {@link ValueSerializer} implementations that serialize objects.\n *\n * @param <T> the supported object type\n * @author Phillip Webb\n * @since 4.0.0\n * @see ObjectValueDeserializer\n */\npublic abstract class ObjectValueSerializer<T> extends ValueSerializer<T> {\n\n\t@Override\n\tpublic final void serialize(T value, JsonGenerator jgen, SerializationContext context) {\n\t\tjgen.writeStartObject();\n\t\tserializeObject(value, jgen, context);\n\t\tjgen.writeEndObject();\n\t}\n\n\t/**\n\t * Serialize JSON content into the value type this serializer handles.\n\t * @param value the source value\n\t * @param jgen the JSON generator\n\t * @param context the serialization context\n\t */\n\tprotected abstract void serializeObject(T value, JsonGenerator jgen, SerializationContext context);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/CborFactoryBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.dataformat.cbor.CBORFactory;\nimport tools.jackson.dataformat.cbor.CBORFactoryBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link CBORFactory} through {@link CBORFactoryBuilder} to fine-tune its\n * auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface CborFactoryBuilderCustomizer {\n\n\t/**\n\t * Customize the CBORFactoryBuilder.\n\t * @param cborFactoryBuilder the builder to customize\n\t */\n\tvoid customize(CBORFactoryBuilder cborFactoryBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/CborMapperBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.dataformat.cbor.CBORMapper;\nimport tools.jackson.dataformat.cbor.CBORMapper.Builder;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link CBORMapper} through {@link Builder CBORMapper.Builder} to fine-tune its\n * auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface CborMapperBuilderCustomizer {\n\n\t/**\n\t * Customize the CBORMapper.Builder.\n\t * @param cborMapperBuilder the builder to customize\n\t */\n\tvoid customize(CBORMapper.Builder cborMapperBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport java.lang.reflect.Field;\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TimeZone;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Stream;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonInclude.Include;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.StreamReadConstraints;\nimport tools.jackson.core.StreamWriteConstraints;\nimport tools.jackson.core.base.DecorableTSFactory.DecorableTSFBuilder;\nimport tools.jackson.core.json.JsonFactory;\nimport tools.jackson.core.json.JsonFactoryBuilder;\nimport tools.jackson.databind.JacksonModule;\nimport tools.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.PropertyNamingStrategies;\nimport tools.jackson.databind.PropertyNamingStrategy;\nimport tools.jackson.databind.cfg.ConstructorDetector;\nimport tools.jackson.databind.cfg.DateTimeFeature;\nimport tools.jackson.databind.cfg.HandlerInstantiator;\nimport tools.jackson.databind.cfg.MapperBuilder;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.dataformat.cbor.CBORFactory;\nimport tools.jackson.dataformat.cbor.CBORFactoryBuilder;\nimport tools.jackson.dataformat.cbor.CBORMapper;\nimport tools.jackson.dataformat.xml.XmlFactory;\nimport tools.jackson.dataformat.xml.XmlFactoryBuilder;\nimport tools.jackson.dataformat.xml.XmlMapper;\n\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.jackson.JacksonComponentModule;\nimport org.springframework.boot.jackson.JacksonMixinModule;\nimport org.springframework.boot.jackson.JacksonMixinModuleEntries;\nimport org.springframework.boot.jackson.autoconfigure.JacksonProperties.ConstructorDetectorStrategy;\nimport org.springframework.boot.jackson.autoconfigure.JacksonProperties.Factory.Constraints;\nimport org.springframework.boot.jackson.autoconfigure.JacksonProperties.Factory.Constraints.Read;\nimport org.springframework.boot.jackson.autoconfigure.JacksonProperties.Factory.Constraints.Write;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.ProblemDetail;\nimport org.springframework.http.converter.json.ProblemDetailJacksonMixin;\nimport org.springframework.http.converter.json.ProblemDetailJacksonXmlMixin;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Jackson.\n *\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Sebastien Deleuze\n * @author Johannes Edmeier\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Ralf Ueberfuhr\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(JsonMapper.class)\npublic final class JacksonAutoConfiguration {\n\n\t@Bean\n\tJacksonComponentModule jsonComponentModule() {\n\t\treturn new JacksonComponentModule();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJsonFactory jsonFactory(List<JsonFactoryBuilderCustomizer> customizers) {\n\t\tJsonFactoryBuilder builder = JsonFactory.builder();\n\t\tfor (JsonFactoryBuilderCustomizer customizer : customizers) {\n\t\t\tcustomizer.customize(builder);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnMissingBean\n\tJsonMapper.Builder jsonMapperBuilder(List<JsonMapperBuilderCustomizer> customizers, JsonFactory jsonFactory) {\n\t\tJsonMapper.Builder builder = JsonMapper.builder(jsonFactory);\n\t\tcustomize(builder, customizers);\n\t\treturn builder;\n\t}\n\n\tprivate void customize(JsonMapper.Builder builder, List<JsonMapperBuilderCustomizer> customizers) {\n\t\tfor (JsonMapperBuilderCustomizer customizer : customizers) {\n\t\t\tcustomizer.customize(builder);\n\t\t}\n\t}\n\n\t@Bean\n\t@Primary\n\t@ConditionalOnMissingBean\n\tJsonMapper jacksonJsonMapper(JsonMapper.Builder builder) {\n\t\treturn builder.build();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JacksonMixinConfiguration {\n\n\t\t@Bean\n\t\tstatic JacksonMixinModuleEntries jacksonMixinModuleEntries(ApplicationContext context) {\n\t\t\tList<String> packages = AutoConfigurationPackages.has(context) ? AutoConfigurationPackages.get(context)\n\t\t\t\t\t: Collections.emptyList();\n\t\t\treturn JacksonMixinModuleEntries.scan(context, packages);\n\t\t}\n\n\t\t@Bean\n\t\tJacksonMixinModule jacksonMixinModule(ApplicationContext context, JacksonMixinModuleEntries entries) {\n\t\t\tJacksonMixinModule jacksonMixinModule = new JacksonMixinModule();\n\t\t\tjacksonMixinModule.registerEntries(entries, context.getClassLoader());\n\t\t\treturn jacksonMixinModule;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(JacksonProperties.class)\n\tstatic class JacksonJsonCustomizerConfiguration {\n\n\t\tprivate final JacksonProperties jacksonProperties;\n\n\t\tJacksonJsonCustomizerConfiguration(JacksonProperties jacksonProperties) {\n\t\t\tthis.jacksonProperties = jacksonProperties;\n\t\t}\n\n\t\t@Bean\n\t\tStandardJsonFactoryBuilderCustomizer standardJsonFactoryBuilderCustomizer() {\n\t\t\treturn new StandardJsonFactoryBuilderCustomizer(this.jacksonProperties);\n\t\t}\n\n\t\t@Bean\n\t\tStandardJsonMapperBuilderCustomizer standardJsonMapperBuilderCustomizer(ObjectProvider<JacksonModule> modules,\n\t\t\t\tAutowireCapableBeanFactory beanFactory) {\n\t\t\treturn new StandardJsonMapperBuilderCustomizer(this.jacksonProperties, modules.stream().toList(),\n\t\t\t\t\tbeanFactory);\n\t\t}\n\n\t\tstatic final class StandardJsonFactoryBuilderCustomizer\n\t\t\t\textends AbstractFactoryBuilderCustomizer<JsonFactoryBuilder> implements JsonFactoryBuilderCustomizer {\n\n\t\t\tStandardJsonFactoryBuilderCustomizer(JacksonProperties jacksonProperties) {\n\t\t\t\tsuper(jacksonProperties);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(JsonFactoryBuilder jsonFactoryBuilder) {\n\t\t\t\tsuper.customize(jsonFactoryBuilder);\n\t\t\t}\n\n\t\t}\n\n\t\tstatic final class StandardJsonMapperBuilderCustomizer\n\t\t\t\textends AbstractMapperBuilderCustomizer<JsonMapper.Builder> implements JsonMapperBuilderCustomizer {\n\n\t\t\tStandardJsonMapperBuilderCustomizer(JacksonProperties jacksonProperties, Collection<JacksonModule> modules,\n\t\t\t\t\tAutowireCapableBeanFactory beanFactory) {\n\t\t\t\tsuper(jacksonProperties, modules, beanFactory);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(JsonMapper.Builder builder) {\n\t\t\t\tsuper.customize(builder);\n\t\t\t\tconfigureFeatures(builder, properties().getJson().getRead(), builder::configure);\n\t\t\t\tconfigureFeatures(builder, properties().getJson().getWrite(), builder::configure);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ProblemDetail.class)\n\tstatic class JsonProblemDetailsConfiguration {\n\n\t\t@Bean\n\t\tProblemDetailJsonMapperBuilderCustomizer problemDetailJsonMapperBuilderCustomizer() {\n\t\t\treturn new ProblemDetailJsonMapperBuilderCustomizer();\n\t\t}\n\n\t\tstatic final class ProblemDetailJsonMapperBuilderCustomizer implements JsonMapperBuilderCustomizer {\n\n\t\t\t@Override\n\t\t\tpublic void customize(JsonMapper.Builder builder) {\n\t\t\t\tbuilder.addMixIn(ProblemDetail.class, ProblemDetailJacksonMixin.class);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(CBORMapper.class)\n\t@EnableConfigurationProperties(JacksonCborProperties.class)\n\tstatic class CborConfiguration {\n\n\t\tprivate final JacksonProperties jacksonProperties;\n\n\t\tCborConfiguration(JacksonProperties jacksonProperties) {\n\t\t\tthis.jacksonProperties = jacksonProperties;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tCBORFactory cborFactory(List<CborFactoryBuilderCustomizer> customizers) {\n\t\t\tCBORFactoryBuilder builder = CBORFactory.builder();\n\t\t\tfor (CborFactoryBuilderCustomizer customizer : customizers) {\n\t\t\t\tcustomizer.customize(builder);\n\t\t\t}\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t\t@ConditionalOnMissingBean\n\t\tCBORMapper.Builder cborMapperBuilder(CBORFactory factory, List<CborMapperBuilderCustomizer> customizers) {\n\t\t\tCBORMapper.Builder builder = CBORMapper.builder(factory);\n\t\t\tcustomize(builder, customizers);\n\t\t\treturn builder;\n\t\t}\n\n\t\tprivate void customize(CBORMapper.Builder builder, List<CborMapperBuilderCustomizer> customizers) {\n\t\t\tfor (CborMapperBuilderCustomizer customizer : customizers) {\n\t\t\t\tcustomizer.customize(builder);\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tCBORMapper cborMapper(CBORMapper.Builder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\tStandardCborFactoryBuilderCustomizer standardCborFactoryBuilderCustomizer() {\n\t\t\treturn new StandardCborFactoryBuilderCustomizer(this.jacksonProperties);\n\t\t}\n\n\t\t@Bean\n\t\tStandardCborMapperBuilderCustomizer standardCborMapperBuilderCustomizer(ObjectProvider<JacksonModule> modules,\n\t\t\t\tJacksonCborProperties cborProperties, AutowireCapableBeanFactory beanFactory) {\n\t\t\treturn new StandardCborMapperBuilderCustomizer(this.jacksonProperties, modules.stream().toList(),\n\t\t\t\t\tcborProperties, beanFactory);\n\t\t}\n\n\t\tstatic final class StandardCborFactoryBuilderCustomizer\n\t\t\t\textends AbstractFactoryBuilderCustomizer<CBORFactoryBuilder> implements CborFactoryBuilderCustomizer {\n\n\t\t\tStandardCborFactoryBuilderCustomizer(JacksonProperties jacksonProperties) {\n\t\t\t\tsuper(jacksonProperties);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(CBORFactoryBuilder cborFactoryBuilder) {\n\t\t\t\tsuper.customize(cborFactoryBuilder);\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class StandardCborMapperBuilderCustomizer extends AbstractMapperBuilderCustomizer<CBORMapper.Builder>\n\t\t\t\timplements CborMapperBuilderCustomizer {\n\n\t\t\tprivate final JacksonCborProperties cborProperties;\n\n\t\t\tStandardCborMapperBuilderCustomizer(JacksonProperties jacksonProperties, Collection<JacksonModule> modules,\n\t\t\t\t\tJacksonCborProperties cborProperties, AutowireCapableBeanFactory beanFactory) {\n\t\t\t\tsuper(jacksonProperties, modules, beanFactory);\n\t\t\t\tthis.cborProperties = cborProperties;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(CBORMapper.Builder builder) {\n\t\t\t\tsuper.customize(builder);\n\t\t\t\tconfigureFeatures(builder, this.cborProperties.getRead(), builder::configure);\n\t\t\t\tconfigureFeatures(builder, this.cborProperties.getWrite(), builder::configure);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(XmlMapper.class)\n\t@EnableConfigurationProperties(JacksonXmlProperties.class)\n\tstatic class XmlConfiguration {\n\n\t\tprivate final JacksonProperties jacksonProperties;\n\n\t\tXmlConfiguration(JacksonProperties jacksonProperties) {\n\t\t\tthis.jacksonProperties = jacksonProperties;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tXmlFactory xmlFactory(List<XmlFactoryBuilderCustomizer> customizers) {\n\t\t\tXmlFactoryBuilder builder = XmlFactory.builder();\n\t\t\tfor (XmlFactoryBuilderCustomizer customizer : customizers) {\n\t\t\t\tcustomizer.customize(builder);\n\t\t\t}\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t\t@ConditionalOnMissingBean\n\t\tXmlMapper.Builder xmlMapperBuilder(XmlFactory xmlFactory, List<XmlMapperBuilderCustomizer> customizers) {\n\t\t\tXmlMapper.Builder builder = XmlMapper.builder(xmlFactory);\n\t\t\tcustomize(builder, customizers);\n\t\t\treturn builder;\n\t\t}\n\n\t\tprivate void customize(XmlMapper.Builder builder, List<XmlMapperBuilderCustomizer> customizers) {\n\t\t\tfor (XmlMapperBuilderCustomizer customizer : customizers) {\n\t\t\t\tcustomizer.customize(builder);\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tXmlMapper xmlMapper(XmlMapper.Builder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\tStandardXmlFactoryBuilderCustomizer standardXmlFactoryBuilderCustomizer() {\n\t\t\treturn new StandardXmlFactoryBuilderCustomizer(this.jacksonProperties);\n\t\t}\n\n\t\t@Bean\n\t\tStandardXmlMapperBuilderCustomizer standardXmlMapperBuilderCustomizer(ObjectProvider<JacksonModule> modules,\n\t\t\t\tJacksonXmlProperties xmlProperties, AutowireCapableBeanFactory beanFactory) {\n\t\t\treturn new StandardXmlMapperBuilderCustomizer(this.jacksonProperties, modules.stream().toList(),\n\t\t\t\t\txmlProperties, beanFactory);\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(ProblemDetail.class)\n\t\tstatic class XmlProblemDetailsConfiguration {\n\n\t\t\t@Bean\n\t\t\tProblemDetailXmlMapperBuilderCustomizer problemDetailXmlMapperBuilderCustomizer() {\n\t\t\t\treturn new ProblemDetailXmlMapperBuilderCustomizer();\n\t\t\t}\n\n\t\t\tstatic final class ProblemDetailXmlMapperBuilderCustomizer implements XmlMapperBuilderCustomizer {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void customize(XmlMapper.Builder builder) {\n\t\t\t\t\tbuilder.addMixIn(ProblemDetail.class, ProblemDetailJacksonXmlMixin.class);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tstatic final class StandardXmlFactoryBuilderCustomizer\n\t\t\t\textends AbstractFactoryBuilderCustomizer<XmlFactoryBuilder> implements XmlFactoryBuilderCustomizer {\n\n\t\t\tStandardXmlFactoryBuilderCustomizer(JacksonProperties jacksonProperties) {\n\t\t\t\tsuper(jacksonProperties);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(XmlFactoryBuilder xmlFactoryBuilder) {\n\t\t\t\tsuper.customize(xmlFactoryBuilder);\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class StandardXmlMapperBuilderCustomizer extends AbstractMapperBuilderCustomizer<XmlMapper.Builder>\n\t\t\t\timplements XmlMapperBuilderCustomizer {\n\n\t\t\tprivate final JacksonXmlProperties xmlProperties;\n\n\t\t\tStandardXmlMapperBuilderCustomizer(JacksonProperties jacksonProperties, Collection<JacksonModule> modules,\n\t\t\t\t\tJacksonXmlProperties xmlProperties, AutowireCapableBeanFactory beanFactory) {\n\t\t\t\tsuper(jacksonProperties, modules, beanFactory);\n\t\t\t\tthis.xmlProperties = xmlProperties;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(XmlMapper.Builder builder) {\n\t\t\t\tsuper.customize(builder);\n\t\t\t\tconfigureFeatures(builder, this.xmlProperties.getRead(), builder::configure);\n\t\t\t\tconfigureFeatures(builder, this.xmlProperties.getWrite(), builder::configure);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class JacksonAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tif (ClassUtils.isPresent(\"tools.jackson.databind.PropertyNamingStrategy\", classLoader)) {\n\t\t\t\tregisterPropertyNamingStrategyHints(hints.reflection());\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Register hints for the {@code configurePropertyNamingStrategyField} method to\n\t\t * use.\n\t\t * @param hints reflection hints\n\t\t */\n\t\tprivate void registerPropertyNamingStrategyHints(ReflectionHints hints) {\n\t\t\tregisterPropertyNamingStrategyHints(hints, PropertyNamingStrategies.class);\n\t\t}\n\n\t\tprivate void registerPropertyNamingStrategyHints(ReflectionHints hints, Class<?> type) {\n\t\t\tStream.of(type.getDeclaredFields())\n\t\t\t\t.filter(this::isPropertyNamingStrategyField)\n\t\t\t\t.forEach(hints::registerField);\n\t\t}\n\n\t\tprivate boolean isPropertyNamingStrategyField(Field candidate) {\n\t\t\treturn ReflectionUtils.isPublicStaticFinal(candidate)\n\t\t\t\t\t&& candidate.getType().isAssignableFrom(PropertyNamingStrategy.class);\n\t\t}\n\n\t}\n\n\tabstract static class AbstractFactoryBuilderCustomizer<B extends DecorableTSFBuilder<?, ?>> implements Ordered {\n\n\t\tprivate final JacksonProperties jacksonProperties;\n\n\t\tAbstractFactoryBuilderCustomizer(JacksonProperties jacksonProperties) {\n\t\t\tthis.jacksonProperties = jacksonProperties;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t\tprotected void customize(B builder) {\n\t\t\tConstraints constraints = this.jacksonProperties.getFactory().getConstraints();\n\t\t\tbuilder.streamReadConstraints(readConstraintsFrom(constraints.getRead()));\n\t\t\tbuilder.streamWriteConstraints(writeConstraintsFrom(constraints.getWrite()));\n\t\t}\n\n\t\tprivate StreamReadConstraints readConstraintsFrom(Read read) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tStreamReadConstraints.Builder constraintsBuilder = StreamReadConstraints.builder();\n\t\t\tmap.from(read::getMaxDocumentLength).to(constraintsBuilder::maxDocumentLength);\n\t\t\tmap.from(read::getMaxNameLength).to(constraintsBuilder::maxNameLength);\n\t\t\tmap.from(read::getMaxNestingDepth).to(constraintsBuilder::maxNestingDepth);\n\t\t\tmap.from(read::getMaxNumberLength).to(constraintsBuilder::maxNumberLength);\n\t\t\tmap.from(read::getMaxStringLength).to(constraintsBuilder::maxStringLength);\n\t\t\tmap.from(read::getMaxTokenCount).to(constraintsBuilder::maxTokenCount);\n\t\t\treturn constraintsBuilder.build();\n\t\t}\n\n\t\tprivate StreamWriteConstraints writeConstraintsFrom(Write write) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tStreamWriteConstraints.Builder constraintsBuilder = StreamWriteConstraints.builder();\n\t\t\tmap.from(write::getMaxNestingDepth).to(constraintsBuilder::maxNestingDepth);\n\t\t\treturn constraintsBuilder.build();\n\t\t}\n\n\t}\n\n\tabstract static class AbstractMapperBuilderCustomizer<B extends MapperBuilder<?, ?>> implements Ordered {\n\n\t\tprivate final JacksonProperties jacksonProperties;\n\n\t\tprivate final Collection<JacksonModule> modules;\n\n\t\tprivate final HandlerInstantiator handlerInstantiator;\n\n\t\tAbstractMapperBuilderCustomizer(JacksonProperties jacksonProperties, Collection<JacksonModule> modules,\n\t\t\t\tAutowireCapableBeanFactory beanFactory) {\n\t\t\tthis.jacksonProperties = jacksonProperties;\n\t\t\tthis.modules = modules;\n\t\t\tthis.handlerInstantiator = new SpringBeanHandlerInstantiator(beanFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t\tprotected JacksonProperties properties() {\n\t\t\treturn this.jacksonProperties;\n\t\t}\n\n\t\tprotected void customize(B builder) {\n\t\t\tif (this.jacksonProperties.isUseJackson2Defaults()) {\n\t\t\t\tbuilder.configureForJackson2()\n\t\t\t\t\t.disable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS, DateTimeFeature.WRITE_DURATIONS_AS_TIMESTAMPS);\n\t\t\t}\n\t\t\tif (this.jacksonProperties.isFindAndAddModules()) {\n\t\t\t\tbuilder.findAndAddModules(getClass().getClassLoader());\n\t\t\t}\n\t\t\tInclude propertyInclusion = this.jacksonProperties.getDefaultPropertyInclusion();\n\t\t\tif (propertyInclusion != null) {\n\t\t\t\tbuilder.changeDefaultPropertyInclusion((handler) -> handler.withValueInclusion(propertyInclusion)\n\t\t\t\t\t.withContentInclusion(propertyInclusion));\n\t\t\t}\n\t\t\tif (this.jacksonProperties.getTimeZone() != null) {\n\t\t\t\tbuilder.defaultTimeZone(this.jacksonProperties.getTimeZone());\n\t\t\t}\n\t\t\tbuilder.handlerInstantiator(this.handlerInstantiator);\n\t\t\tconfigureVisibility(builder, this.jacksonProperties.getVisibility());\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDeserialization(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getSerialization(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getMapper(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDatatype().getDatetime(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDatatype().getEnum(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDatatype().getJsonNode(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getRead(), builder::configure);\n\t\t\tconfigureFeatures(builder, this.jacksonProperties.getWrite(), builder::configure);\n\t\t\tconfigureDateFormat(builder);\n\t\t\tconfigurePropertyNamingStrategy(builder);\n\t\t\tconfigureModules(builder);\n\t\t\tconfigureLocale(builder);\n\t\t\tconfigureDefaultLeniency(builder);\n\t\t\tconfigureConstructorDetector(builder);\n\t\t}\n\n\t\tprotected <T> void configureFeatures(B builder, Map<T, Boolean> features, BiConsumer<T, Boolean> configure) {\n\t\t\tfeatures.forEach((feature, value) -> {\n\t\t\t\tif (value != null) {\n\t\t\t\t\tconfigure.accept(feature, value);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tprivate void configureVisibility(MapperBuilder<?, ?> builder,\n\t\t\t\tMap<PropertyAccessor, JsonAutoDetect.Visibility> visibilities) {\n\t\t\tbuilder.changeDefaultVisibility((visibilityChecker) -> {\n\t\t\t\tfor (Map.Entry<PropertyAccessor, JsonAutoDetect.Visibility> entry : visibilities.entrySet()) {\n\t\t\t\t\tvisibilityChecker = visibilityChecker.withVisibility(entry.getKey(), entry.getValue());\n\t\t\t\t}\n\t\t\t\treturn visibilityChecker;\n\t\t\t});\n\t\t}\n\n\t\tprivate void configureDateFormat(MapperBuilder<?, ?> builder) {\n\t\t\t// We support a fully qualified class name extending DateFormat or a date\n\t\t\t// pattern string value\n\t\t\tString dateFormat = this.jacksonProperties.getDateFormat();\n\t\t\tif (dateFormat != null) {\n\t\t\t\ttry {\n\t\t\t\t\tClass<?> dateFormatClass = ClassUtils.forName(dateFormat, null);\n\t\t\t\t\tbuilder.defaultDateFormat((DateFormat) BeanUtils.instantiateClass(dateFormatClass));\n\t\t\t\t}\n\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\tSimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);\n\t\t\t\t\t// Since Jackson 2.6.3 we always need to set a TimeZone (see\n\t\t\t\t\t// gh-4170). If none in our properties fallback to Jackson's\n\t\t\t\t\t// default\n\t\t\t\t\tTimeZone timeZone = this.jacksonProperties.getTimeZone();\n\t\t\t\t\tif (timeZone == null) {\n\t\t\t\t\t\ttimeZone = new ObjectMapper().serializationConfig().getTimeZone();\n\t\t\t\t\t}\n\t\t\t\t\tsimpleDateFormat.setTimeZone(timeZone);\n\t\t\t\t\tbuilder.defaultDateFormat(simpleDateFormat);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void configurePropertyNamingStrategy(MapperBuilder<?, ?> builder) {\n\t\t\t// We support a fully qualified class name extending Jackson's\n\t\t\t// PropertyNamingStrategy or a string value corresponding to the constant\n\t\t\t// names in PropertyNamingStrategy which hold default provided\n\t\t\t// implementations\n\t\t\tString strategy = this.jacksonProperties.getPropertyNamingStrategy();\n\t\t\tif (strategy != null) {\n\t\t\t\ttry {\n\t\t\t\t\tconfigurePropertyNamingStrategyClass(builder, ClassUtils.forName(strategy, null));\n\t\t\t\t}\n\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\tconfigurePropertyNamingStrategyField(builder, strategy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void configurePropertyNamingStrategyClass(MapperBuilder<?, ?> builder,\n\t\t\t\tClass<?> propertyNamingStrategyClass) {\n\t\t\tbuilder.propertyNamingStrategy(\n\t\t\t\t\t(PropertyNamingStrategy) BeanUtils.instantiateClass(propertyNamingStrategyClass));\n\t\t}\n\n\t\tprivate void configurePropertyNamingStrategyField(MapperBuilder<?, ?> builder, String fieldName) {\n\t\t\t// Find the field (this way we automatically support new constants\n\t\t\t// that may be added by Jackson in the future)\n\t\t\tField field = findPropertyNamingStrategyField(fieldName);\n\t\t\ttry {\n\t\t\t\tbuilder.propertyNamingStrategy((PropertyNamingStrategy) field.get(null));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate Field findPropertyNamingStrategyField(String fieldName) {\n\t\t\tField field = ReflectionUtils.findField(PropertyNamingStrategies.class, fieldName,\n\t\t\t\t\tPropertyNamingStrategy.class);\n\t\t\tAssert.state(field != null, () -> \"Constant named '\" + fieldName + \"' not found\");\n\t\t\treturn field;\n\t\t}\n\n\t\tprivate void configureModules(MapperBuilder<?, ?> builder) {\n\t\t\tbuilder.addModules(this.modules);\n\t\t}\n\n\t\tprivate void configureLocale(MapperBuilder<?, ?> builder) {\n\t\t\tLocale locale = this.jacksonProperties.getLocale();\n\t\t\tif (locale != null) {\n\t\t\t\tbuilder.defaultLocale(locale);\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureDefaultLeniency(MapperBuilder<?, ?> builder) {\n\t\t\tBoolean defaultLeniency = this.jacksonProperties.getDefaultLeniency();\n\t\t\tif (defaultLeniency != null) {\n\t\t\t\tbuilder.defaultLeniency(defaultLeniency);\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureConstructorDetector(MapperBuilder<?, ?> builder) {\n\t\t\tConstructorDetectorStrategy strategy = this.jacksonProperties.getConstructorDetector();\n\t\t\tswitch (strategy) {\n\t\t\t\tcase USE_PROPERTIES_BASED -> builder.constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED);\n\t\t\t\tcase USE_DELEGATING -> builder.constructorDetector(ConstructorDetector.USE_DELEGATING);\n\t\t\t\tcase EXPLICIT_ONLY -> builder.constructorDetector(ConstructorDetector.EXPLICIT_ONLY);\n\t\t\t\tdefault -> builder.constructorDetector(ConstructorDetector.DEFAULT);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer;\n\n/**\n * {@link BackgroundPreinitializer} for Jackson.\n *\n * @author Phillip Webb\n */\nfinal class JacksonBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tJsonMapper.builder().build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonCborProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport java.util.EnumMap;\nimport java.util.Map;\n\nimport tools.jackson.dataformat.cbor.CBORReadFeature;\nimport tools.jackson.dataformat.cbor.CBORWriteFeature;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties to configure Jackson's CBOR support.\n *\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Johannes Edmeier\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jackson.cbor\")\npublic class JacksonCborProperties {\n\n\t/**\n\t * Jackson on/off token reader features that are specific to CBOR.\n\t */\n\tprivate final Map<CBORReadFeature, Boolean> read = new EnumMap<>(CBORReadFeature.class);\n\n\t/**\n\t * Jackson on/off token writer features that are specific to CBOR.\n\t */\n\tprivate final Map<CBORWriteFeature, Boolean> write = new EnumMap<>(CBORWriteFeature.class);\n\n\tpublic Map<CBORReadFeature, Boolean> getRead() {\n\t\treturn this.read;\n\t}\n\n\tpublic Map<CBORWriteFeature, Boolean> getWrite() {\n\t\treturn this.write;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport java.util.EnumMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TimeZone;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.StreamReadFeature;\nimport tools.jackson.core.StreamWriteFeature;\nimport tools.jackson.core.json.JsonReadFeature;\nimport tools.jackson.core.json.JsonWriteFeature;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.cfg.DateTimeFeature;\nimport tools.jackson.databind.cfg.EnumFeature;\nimport tools.jackson.databind.cfg.JsonNodeFeature;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties to configure Jackson.\n *\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Johannes Edmeier\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jackson\")\npublic class JacksonProperties {\n\n\t/**\n\t * Date format string or a fully-qualified date format class name. For instance,\n\t * 'yyyy-MM-dd HH:mm:ss'.\n\t */\n\tprivate @Nullable String dateFormat;\n\n\t/**\n\t * One of the constants on Jackson's PropertyNamingStrategies. Can also be a\n\t * fully-qualified class name of a PropertyNamingStrategy implementation.\n\t */\n\tprivate @Nullable String propertyNamingStrategy;\n\n\t/**\n\t * Jackson visibility thresholds that can be used to limit which methods (and fields)\n\t * are auto-detected.\n\t */\n\tprivate final Map<PropertyAccessor, JsonAutoDetect.Visibility> visibility = new EnumMap<>(PropertyAccessor.class);\n\n\t/**\n\t * Jackson on/off features that affect the way Java objects are serialized.\n\t */\n\tprivate final Map<SerializationFeature, Boolean> serialization = new EnumMap<>(SerializationFeature.class);\n\n\t/**\n\t * Jackson on/off features that affect the way Java objects are deserialized.\n\t */\n\tprivate final Map<DeserializationFeature, Boolean> deserialization = new EnumMap<>(DeserializationFeature.class);\n\n\t/**\n\t * Jackson general purpose on/off features.\n\t */\n\tprivate final Map<MapperFeature, Boolean> mapper = new EnumMap<>(MapperFeature.class);\n\n\t/**\n\t * Controls the inclusion of properties during serialization. Configured with one of\n\t * the values in Jackson's JsonInclude.Include enumeration.\n\t */\n\tprivate JsonInclude.@Nullable Include defaultPropertyInclusion;\n\n\t/**\n\t * Global default setting (if any) for leniency.\n\t */\n\tprivate @Nullable Boolean defaultLeniency;\n\n\t/**\n\t * Strategy to use to auto-detect constructor, and in particular behavior with\n\t * single-argument constructors.\n\t */\n\tprivate ConstructorDetectorStrategy constructorDetector = ConstructorDetectorStrategy.DEFAULT;\n\n\t/**\n\t * Time zone used when formatting dates. For instance, \"America/Los_Angeles\" or\n\t * \"GMT+10\".\n\t */\n\tprivate @Nullable TimeZone timeZone;\n\n\t/**\n\t * Locale used for formatting.\n\t */\n\tprivate @Nullable Locale locale;\n\n\t/**\n\t * Whether to configure Jackson 3 with the same defaults as Spring Boot previously\n\t * used for Jackson 2.\n\t */\n\tprivate boolean useJackson2Defaults;\n\n\t/**\n\t * Whether to find and add modules to the auto-configured JsonMapper.Builder using\n\t * MapperBuilder.findAndAddModules(ClassLoader).\n\t */\n\tprivate boolean findAndAddModules = true;\n\n\tprivate final Datatype datatype = new Datatype();\n\n\t/**\n\t * Jackson on/off token reader features common to multiple formats.\n\t */\n\tprivate final Map<StreamReadFeature, Boolean> read = new EnumMap<>(StreamReadFeature.class);\n\n\t/**\n\t * Jackson on/off token writer features common to multiple formats.\n\t */\n\tprivate final Map<StreamWriteFeature, Boolean> write = new EnumMap<>(StreamWriteFeature.class);\n\n\tprivate final Json json = new Json();\n\n\tprivate final Factory factory = new Factory();\n\n\tpublic @Nullable String getDateFormat() {\n\t\treturn this.dateFormat;\n\t}\n\n\tpublic void setDateFormat(@Nullable String dateFormat) {\n\t\tthis.dateFormat = dateFormat;\n\t}\n\n\tpublic @Nullable String getPropertyNamingStrategy() {\n\t\treturn this.propertyNamingStrategy;\n\t}\n\n\tpublic void setPropertyNamingStrategy(@Nullable String propertyNamingStrategy) {\n\t\tthis.propertyNamingStrategy = propertyNamingStrategy;\n\t}\n\n\tpublic Map<PropertyAccessor, JsonAutoDetect.Visibility> getVisibility() {\n\t\treturn this.visibility;\n\t}\n\n\tpublic Map<SerializationFeature, Boolean> getSerialization() {\n\t\treturn this.serialization;\n\t}\n\n\tpublic Map<DeserializationFeature, Boolean> getDeserialization() {\n\t\treturn this.deserialization;\n\t}\n\n\tpublic Map<MapperFeature, Boolean> getMapper() {\n\t\treturn this.mapper;\n\t}\n\n\tpublic JsonInclude.@Nullable Include getDefaultPropertyInclusion() {\n\t\treturn this.defaultPropertyInclusion;\n\t}\n\n\tpublic void setDefaultPropertyInclusion(JsonInclude.@Nullable Include defaultPropertyInclusion) {\n\t\tthis.defaultPropertyInclusion = defaultPropertyInclusion;\n\t}\n\n\tpublic @Nullable Boolean getDefaultLeniency() {\n\t\treturn this.defaultLeniency;\n\t}\n\n\tpublic void setDefaultLeniency(@Nullable Boolean defaultLeniency) {\n\t\tthis.defaultLeniency = defaultLeniency;\n\t}\n\n\tpublic ConstructorDetectorStrategy getConstructorDetector() {\n\t\treturn this.constructorDetector;\n\t}\n\n\tpublic void setConstructorDetector(ConstructorDetectorStrategy constructorDetector) {\n\t\tthis.constructorDetector = constructorDetector;\n\t}\n\n\tpublic @Nullable TimeZone getTimeZone() {\n\t\treturn this.timeZone;\n\t}\n\n\tpublic void setTimeZone(@Nullable TimeZone timeZone) {\n\t\tthis.timeZone = timeZone;\n\t}\n\n\tpublic @Nullable Locale getLocale() {\n\t\treturn this.locale;\n\t}\n\n\tpublic void setLocale(@Nullable Locale locale) {\n\t\tthis.locale = locale;\n\t}\n\n\tpublic boolean isUseJackson2Defaults() {\n\t\treturn this.useJackson2Defaults;\n\t}\n\n\tpublic void setUseJackson2Defaults(boolean useJackson2Defaults) {\n\t\tthis.useJackson2Defaults = useJackson2Defaults;\n\t}\n\n\tpublic boolean isFindAndAddModules() {\n\t\treturn this.findAndAddModules;\n\t}\n\n\tpublic void setFindAndAddModules(boolean findModules) {\n\t\tthis.findAndAddModules = findModules;\n\t}\n\n\tpublic Datatype getDatatype() {\n\t\treturn this.datatype;\n\t}\n\n\tpublic Map<StreamReadFeature, Boolean> getRead() {\n\t\treturn this.read;\n\t}\n\n\tpublic Map<StreamWriteFeature, Boolean> getWrite() {\n\t\treturn this.write;\n\t}\n\n\tpublic Json getJson() {\n\t\treturn this.json;\n\t}\n\n\tpublic Factory getFactory() {\n\t\treturn this.factory;\n\t}\n\n\tpublic enum ConstructorDetectorStrategy {\n\n\t\t/**\n\t\t * Use heuristics to see if \"properties\" mode is to be used.\n\t\t */\n\t\tDEFAULT,\n\n\t\t/**\n\t\t * Assume \"properties\" mode if not explicitly annotated otherwise.\n\t\t */\n\t\tUSE_PROPERTIES_BASED,\n\n\t\t/**\n\t\t * Assume \"delegating\" mode if not explicitly annotated otherwise.\n\t\t */\n\t\tUSE_DELEGATING,\n\n\t\t/**\n\t\t * Refuse to decide implicit mode and instead throw an InvalidDefinitionException\n\t\t * for ambiguous cases.\n\t\t */\n\t\tEXPLICIT_ONLY\n\n\t}\n\n\tpublic static class Datatype {\n\n\t\t/**\n\t\t * Jackson on/off features for enums.\n\t\t */\n\t\tprivate final Map<EnumFeature, Boolean> enumFeatures = new EnumMap<>(EnumFeature.class);\n\n\t\t/**\n\t\t * Jackson on/off features for JsonNodes.\n\t\t */\n\t\tprivate final Map<JsonNodeFeature, Boolean> jsonNode = new EnumMap<>(JsonNodeFeature.class);\n\n\t\t/**\n\t\t * Jackson on/off features for DateTimes.\n\t\t */\n\t\tprivate final Map<DateTimeFeature, Boolean> datetime = new EnumMap<>(DateTimeFeature.class);\n\n\t\tpublic Map<EnumFeature, Boolean> getEnum() {\n\t\t\treturn this.enumFeatures;\n\t\t}\n\n\t\tpublic Map<JsonNodeFeature, Boolean> getJsonNode() {\n\t\t\treturn this.jsonNode;\n\t\t}\n\n\t\tpublic Map<DateTimeFeature, Boolean> getDatetime() {\n\t\t\treturn this.datetime;\n\t\t}\n\n\t}\n\n\tpublic static class Json {\n\n\t\t/**\n\t\t * Jackson on/off token reader features that are specific to JSON.\n\t\t */\n\t\tprivate final Map<JsonReadFeature, Boolean> read = new EnumMap<>(JsonReadFeature.class);\n\n\t\t/**\n\t\t * Jackson on/off token writer features that are specific to JSON.\n\t\t */\n\t\tprivate final Map<JsonWriteFeature, Boolean> write = new EnumMap<>(JsonWriteFeature.class);\n\n\t\tpublic Map<JsonReadFeature, Boolean> getRead() {\n\t\t\treturn this.read;\n\t\t}\n\n\t\tpublic Map<JsonWriteFeature, Boolean> getWrite() {\n\t\t\treturn this.write;\n\t\t}\n\n\t}\n\n\tpublic static class Factory {\n\n\t\tprivate final Constraints constraints = new Constraints();\n\n\t\tpublic Constraints getConstraints() {\n\t\t\treturn this.constraints;\n\t\t}\n\n\t\tpublic static class Constraints {\n\n\t\t\tprivate final Read read = new Read();\n\n\t\t\tprivate final Write write = new Write();\n\n\t\t\tpublic Read getRead() {\n\t\t\t\treturn this.read;\n\t\t\t}\n\n\t\t\tpublic Write getWrite() {\n\t\t\t\treturn this.write;\n\t\t\t}\n\n\t\t\tpublic static class Read {\n\n\t\t\t\t/**\n\t\t\t\t * Maximum nesting depth. The depth is a count of objects and arrays that\n\t\t\t\t * have not been closed.\n\t\t\t\t */\n\t\t\t\tprivate int maxNestingDepth = 500;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum allowed document length. A value less than or equal to zero\n\t\t\t\t * indicates that any length is acceptable.\n\t\t\t\t */\n\t\t\t\tprivate long maxDocumentLength = -1L;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum allowed token count. A value less than or equal to zero\n\t\t\t\t * indicates that any count is acceptable.\n\t\t\t\t */\n\t\t\t\tprivate long maxTokenCount = -1L;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum number length.\n\t\t\t\t */\n\t\t\t\tprivate int maxNumberLength = 1_000;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum string length.\n\t\t\t\t */\n\t\t\t\tprivate int maxStringLength = 100_000_000;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum name length.\n\t\t\t\t */\n\t\t\t\tprivate int maxNameLength = 50_000;\n\n\t\t\t\tpublic int getMaxNestingDepth() {\n\t\t\t\t\treturn this.maxNestingDepth;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxNestingDepth(int maxNestingDepth) {\n\t\t\t\t\tthis.maxNestingDepth = maxNestingDepth;\n\t\t\t\t}\n\n\t\t\t\tpublic long getMaxDocumentLength() {\n\t\t\t\t\treturn this.maxDocumentLength;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxDocumentLength(long maxDocumentLength) {\n\t\t\t\t\tthis.maxDocumentLength = maxDocumentLength;\n\t\t\t\t}\n\n\t\t\t\tpublic long getMaxTokenCount() {\n\t\t\t\t\treturn this.maxTokenCount;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxTokenCount(long maxTokenCount) {\n\t\t\t\t\tthis.maxTokenCount = maxTokenCount;\n\t\t\t\t}\n\n\t\t\t\tpublic int getMaxNumberLength() {\n\t\t\t\t\treturn this.maxNumberLength;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxNumberLength(int maxNumberLength) {\n\t\t\t\t\tthis.maxNumberLength = maxNumberLength;\n\t\t\t\t}\n\n\t\t\t\tpublic int getMaxStringLength() {\n\t\t\t\t\treturn this.maxStringLength;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxStringLength(int maxStringLength) {\n\t\t\t\t\tthis.maxStringLength = maxStringLength;\n\t\t\t\t}\n\n\t\t\t\tpublic int getMaxNameLength() {\n\t\t\t\t\treturn this.maxNameLength;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxNameLength(int maxNameLength) {\n\t\t\t\t\tthis.maxNameLength = maxNameLength;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tpublic static class Write {\n\n\t\t\t\t/**\n\t\t\t\t * Maximum nesting depth. The depth is a count of objects and arrays that\n\t\t\t\t * have not been closed.\n\t\t\t\t */\n\t\t\t\tprivate int maxNestingDepth = 500;\n\n\t\t\t\tpublic int getMaxNestingDepth() {\n\t\t\t\t\treturn this.maxNestingDepth;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxNestingDepth(int maxNestingDepth) {\n\t\t\t\t\tthis.maxNestingDepth = maxNestingDepth;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonTesterTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.test.autoconfigure.json.ConditionalOnJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonMarshalTesterRuntimeHints;\nimport org.springframework.boot.test.autoconfigure.json.JsonTesterFactoryBean;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.context.annotation.Scope;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link JacksonTester}.\n *\n * @author Phillip Webb\n */\n@AutoConfiguration(after = JacksonAutoConfiguration.class)\n@ConditionalOnJsonTesters\nfinal class JacksonTesterTestAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnBean(JsonMapper.class)\n\t@ImportRuntimeHints(JacksonTesterRuntimeHints.class)\n\tFactoryBean<JacksonTester<?>> jacksonTesterFactoryBean(JsonMapper mapper) {\n\t\treturn new JsonTesterFactoryBean<>(JacksonTester.class, mapper);\n\t}\n\n\tstatic class JacksonTesterRuntimeHints extends JsonMarshalTesterRuntimeHints {\n\n\t\tJacksonTesterRuntimeHints() {\n\t\t\tsuper(JacksonTester.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JacksonXmlProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport java.util.EnumMap;\nimport java.util.Map;\n\nimport tools.jackson.dataformat.xml.XmlReadFeature;\nimport tools.jackson.dataformat.xml.XmlWriteFeature;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties to configure Jackson's XML support.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jackson.xml\")\npublic class JacksonXmlProperties {\n\n\t/**\n\t * Jackson on/off token reader features that are specific to XML.\n\t */\n\tprivate final Map<XmlReadFeature, Boolean> read = new EnumMap<>(XmlReadFeature.class);\n\n\t/**\n\t * Jackson on/off token writer features that are specific to XML.\n\t */\n\tprivate final Map<XmlWriteFeature, Boolean> write = new EnumMap<>(XmlWriteFeature.class);\n\n\tpublic Map<XmlReadFeature, Boolean> getRead() {\n\t\treturn this.read;\n\t}\n\n\tpublic Map<XmlWriteFeature, Boolean> getWrite() {\n\t\treturn this.write;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JsonFactoryBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.core.json.JsonFactory;\nimport tools.jackson.core.json.JsonFactoryBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link JsonFactory} through {@link JsonFactoryBuilder} to fine-tune its\n * auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface JsonFactoryBuilderCustomizer {\n\n\t/**\n\t * Customize the JsonFactoryBuilder.\n\t * @param jsonFactoryBuilder the builder to customize\n\t */\n\tvoid customize(JsonFactoryBuilder jsonFactoryBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/JsonMapperBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.databind.json.JsonMapper;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link JsonMapper} through {@link tools.jackson.databind.json.JsonMapper.Builder} to\n * fine-tune its auto-configuration.\n *\n * @author Grzegorz Poznachowski\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface JsonMapperBuilderCustomizer {\n\n\t/**\n\t * Customize the JsonMapper.Builder.\n\t * @param jsonMapperBuilder the builder to customize\n\t */\n\tvoid customize(JsonMapper.Builder jsonMapperBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/SpringBeanHandlerInstantiator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport com.fasterxml.jackson.annotation.ObjectIdGenerator;\nimport com.fasterxml.jackson.annotation.ObjectIdResolver;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.DeserializationConfig;\nimport tools.jackson.databind.KeyDeserializer;\nimport tools.jackson.databind.PropertyNamingStrategy;\nimport tools.jackson.databind.SerializationConfig;\nimport tools.jackson.databind.ValueDeserializer;\nimport tools.jackson.databind.ValueSerializer;\nimport tools.jackson.databind.cfg.HandlerInstantiator;\nimport tools.jackson.databind.cfg.MapperConfig;\nimport tools.jackson.databind.deser.ValueInstantiator;\nimport tools.jackson.databind.introspect.Annotated;\nimport tools.jackson.databind.jsontype.TypeIdResolver;\nimport tools.jackson.databind.jsontype.TypeResolverBuilder;\nimport tools.jackson.databind.ser.VirtualBeanPropertyWriter;\nimport tools.jackson.databind.util.Converter;\n\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.util.Assert;\n\n/**\n * Package-private adaptation of Spring Framework's\n * {@link org.springframework.http.support.JacksonHandlerInstantiator}. Allows Spring Boot\n * to offer bean-based handler instantiation without requiring {@code spring-web}.\n *\n * @author Sebastien Deleuze\n * @author Andy Wilkinson\n * @see org.springframework.http.support.JacksonHandlerInstantiator\n */\nclass SpringBeanHandlerInstantiator extends HandlerInstantiator {\n\n\tprivate final AutowireCapableBeanFactory beanFactory;\n\n\tSpringBeanHandlerInstantiator(AutowireCapableBeanFactory beanFactory) {\n\t\tAssert.notNull(beanFactory, \"BeanFactory must not be null\");\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\t@Nullable public ValueDeserializer<?> deserializerInstance(DeserializationConfig config, Annotated annotated,\n\t\t\tClass<?> deserClass) {\n\t\treturn (ValueDeserializer<?>) this.beanFactory.createBean(deserClass);\n\t}\n\n\t@Override\n\tpublic KeyDeserializer keyDeserializerInstance(DeserializationConfig config, Annotated annotated,\n\t\t\tClass<?> keyDeserClass) {\n\t\treturn (KeyDeserializer) this.beanFactory.createBean(keyDeserClass);\n\t}\n\n\t@Override\n\tpublic ValueSerializer<?> serializerInstance(SerializationConfig config, Annotated annotated, Class<?> serClass) {\n\t\treturn (ValueSerializer<?>) this.beanFactory.createBean(serClass);\n\t}\n\n\t@Override\n\tpublic TypeResolverBuilder<?> typeResolverBuilderInstance(MapperConfig<?> config, Annotated annotated,\n\t\t\tClass<?> builderClass) {\n\t\treturn (TypeResolverBuilder<?>) this.beanFactory.createBean(builderClass);\n\t}\n\n\t@Override\n\tpublic TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated annotated, Class<?> resolverClass) {\n\t\treturn (TypeIdResolver) this.beanFactory.createBean(resolverClass);\n\t}\n\n\t@Override\n\tpublic ValueInstantiator valueInstantiatorInstance(MapperConfig<?> config, Annotated annotated,\n\t\t\tClass<?> implClass) {\n\t\treturn (ValueInstantiator) this.beanFactory.createBean(implClass);\n\t}\n\n\t@Override\n\tpublic ObjectIdGenerator<?> objectIdGeneratorInstance(MapperConfig<?> config, Annotated annotated,\n\t\t\tClass<?> implClass) {\n\t\treturn (ObjectIdGenerator<?>) this.beanFactory.createBean(implClass);\n\t}\n\n\t@Override\n\tpublic ObjectIdResolver resolverIdGeneratorInstance(MapperConfig<?> config, Annotated annotated,\n\t\t\tClass<?> implClass) {\n\t\treturn (ObjectIdResolver) this.beanFactory.createBean(implClass);\n\t}\n\n\t@Override\n\tpublic PropertyNamingStrategy namingStrategyInstance(MapperConfig<?> config, Annotated annotated,\n\t\t\tClass<?> implClass) {\n\t\treturn (PropertyNamingStrategy) this.beanFactory.createBean(implClass);\n\t}\n\n\t@Override\n\tpublic Converter<?, ?> converterInstance(MapperConfig<?> config, Annotated annotated, Class<?> implClass) {\n\t\treturn (Converter<?, ?>) this.beanFactory.createBean(implClass);\n\t}\n\n\t@Override\n\tpublic VirtualBeanPropertyWriter virtualPropertyWriterInstance(MapperConfig<?> config, Class<?> implClass) {\n\t\treturn (VirtualBeanPropertyWriter) this.beanFactory.createBean(implClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/XmlFactoryBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.dataformat.xml.XmlFactory;\nimport tools.jackson.dataformat.xml.XmlFactoryBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link XmlFactory} through {@link XmlFactoryBuilder} to fine-tune its\n * auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface XmlFactoryBuilderCustomizer {\n\n\t/**\n\t * Customize the XmlFactoryBuilder.\n\t * @param xmlFactoryBuilder the builder to customize\n\t */\n\tvoid customize(XmlFactoryBuilder xmlFactoryBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/XmlMapperBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport tools.jackson.dataformat.cbor.CBORMapper.Builder;\nimport tools.jackson.dataformat.xml.XmlMapper;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link XmlMapper} through {@link Builder XmlMapper.Builder} to fine-tune its\n * auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface XmlMapperBuilderCustomizer {\n\n\t/**\n\t * Customize the XmlMapper.Builder.\n\t * @param xmlMapperBuilder the builder to customize\n\t */\n\tvoid customize(XmlMapper.Builder xmlMapperBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jackson.\n */\n@NullMarked\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/java/org/springframework/boot/jackson/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom enhancements and support for the Jackson project.\n */\n@NullMarked\npackage org.springframework.boot.jackson;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.jackson.constructor-detector\",\n      \"defaultValue\": \"default\"\n    },\n    {\n      \"name\": \"spring.jackson.datatype.enum\",\n      \"description\": \"Jackson on/off features for enums.\"\n    },\n    {\n      \"name\": \"spring.jackson.generator\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Partially replaced by 'spring.jackson.json.write'.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.jackson.joda-date-time-format\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Joda date time format string. If not configured, \\\"date-format\\\" is used as a fallback if it is configured with a format string.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.jackson.parser\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Partially replaced by 'spring.jackson.json.read'.\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration$JacksonAutoConfigurationRuntimeHints\n\norg.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\\\norg.springframework.boot.jackson.JacksonComponentModule$JacksonComponentBeanFactoryInitializationAotProcessor\n\norg.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\\\norg.springframework.boot.jackson.JacksonMixinModuleEntriesBeanRegistrationAotProcessor\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJson.imports",
    "content": "org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters.imports",
    "content": "org.springframework.boot.jackson.autoconfigure.JacksonTesterTestAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.JsonTest.includes",
    "content": "org.springframework.boot.jackson.JacksonComponent\ntools.jackson.databind.JacksonModule\n"
  },
  {
    "path": "module/spring-boot-jackson/src/main/resources/META-INF/spring.factories",
    "content": "# Background Preinitializers\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer=\\\norg.springframework.boot.jackson.autoconfigure.JacksonBackgroundPreinitializer\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/JacksonComponentModuleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.JacksonException;\nimport tools.jackson.core.type.TypeReference;\nimport tools.jackson.databind.JacksonModule;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.jackson.JacksonComponentModule.JacksonComponentBeanFactoryInitializationAotProcessor;\nimport org.springframework.boot.jackson.JacksonComponentModuleTests.ComponentWithInnerAbstractClass.AbstractSerializer;\nimport org.springframework.boot.jackson.JacksonComponentModuleTests.ComponentWithInnerAbstractClass.ConcreteSerializer;\nimport org.springframework.boot.jackson.JacksonComponentModuleTests.ComponentWithInnerAbstractClass.NotSuitable;\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndAge;\nimport org.springframework.boot.jackson.types.NameAndCareer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JacksonComponentModule}.\n *\n * @author Phillip Webb\n * @author Vladimir Tsanev\n * @author Paul Aly\n */\nclass JacksonComponentModuleTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterSerializers() throws Exception {\n\t\tload(OnlySerializer.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertSerialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterDeserializers() throws Exception {\n\t\tload(OnlyDeserializer.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterInnerClasses() throws Exception {\n\t\tload(NameAndAgeJacksonComponent.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertSerialize(module);\n\t\tassertDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldAllowInnerAbstractClasses() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tJacksonComponentModule.class, ComponentWithInnerAbstractClass.class);\n\t\tJacksonComponentModule module = context.getBean(JacksonComponentModule.class);\n\t\tassertSerialize(module);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterKeySerializers() throws Exception {\n\t\tload(OnlyKeySerializer.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertKeySerialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterKeyDeserializers() throws Exception {\n\t\tload(OnlyKeyDeserializer.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertKeyDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterInnerClassesForKeyHandlers() throws Exception {\n\t\tload(NameAndAgeJacksonKeyComponent.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertKeySerialize(module);\n\t\tassertKeyDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterOnlyForSpecifiedClasses() throws Exception {\n\t\tload(NameAndCareerJacksonComponent.class);\n\t\tJacksonComponentModule module = getContext().getBean(JacksonComponentModule.class);\n\t\tassertSerialize(module, new NameAndCareer(\"spring\", \"developer\"), \"{\\\"name\\\":\\\"spring\\\"}\");\n\t\tassertSerialize(module, NameAndAge.create(\"spring\", 100), \"{\\\"age\\\":100,\\\"name\\\":\\\"spring\\\"}\");\n\t\tassertDeserializeForSpecifiedClasses(module);\n\t}\n\n\t@Test\n\tvoid aotContributionRegistersReflectionHintsForSuitableInnerClasses() {\n\t\tload(ComponentWithInnerAbstractClass.class);\n\t\tConfigurableListableBeanFactory beanFactory = getContext().getBeanFactory();\n\t\tBeanFactoryInitializationAotContribution contribution = new JacksonComponentBeanFactoryInitializationAotProcessor()\n\t\t\t.processAheadOfTime(beanFactory);\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tassertThat(contribution).isNotNull();\n\t\tcontribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ComponentWithInnerAbstractClass.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(ConcreteSerializer.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(AbstractSerializer.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)\n\t\t\t.negate()).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(NotSuitable.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)\n\t\t\t.negate()).accepts(runtimeHints);\n\t}\n\n\tprivate void load(Class<?>... configs) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(configs);\n\t\tcontext.register(JacksonComponentModule.class);\n\t\tcontext.refresh();\n\t\tthis.context = context;\n\t}\n\n\tprivate void assertSerialize(JacksonModule module, Name value, String expectedJson) throws Exception {\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tString json = mapper.writeValueAsString(value);\n\t\tassertThat(json).isEqualToIgnoringWhitespace(expectedJson);\n\t}\n\n\tprivate void assertSerialize(JacksonModule module) throws Exception {\n\t\tassertSerialize(module, NameAndAge.create(\"spring\", 100), \"{\\\"theName\\\":\\\"spring\\\",\\\"theAge\\\":100}\");\n\t}\n\n\tprivate void assertDeserialize(JacksonModule module) throws Exception {\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tNameAndAge nameAndAge = mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\", NameAndAge.class);\n\t\tassertThat(nameAndAge.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nameAndAge.getAge()).isEqualTo(100);\n\t}\n\n\tprivate void assertDeserializeForSpecifiedClasses(JacksonComponentModule module) {\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tassertThatExceptionOfType(JacksonException.class)\n\t\t\t.isThrownBy(() -> mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\", NameAndAge.class));\n\t\tNameAndCareer nameAndCareer = mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"career\\\":\\\"developer\\\"}\",\n\t\t\t\tNameAndCareer.class);\n\t\tassertThat(nameAndCareer.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nameAndCareer.getCareer()).isEqualTo(\"developer\");\n\t}\n\n\tprivate void assertKeySerialize(JacksonModule module) {\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tMap<NameAndAge, Boolean> map = new HashMap<>();\n\t\tmap.put(NameAndAge.create(\"spring\", 100), true);\n\t\tString json = mapper.writeValueAsString(map);\n\t\tassertThat(json).isEqualToIgnoringWhitespace(\"{\\\"spring is 100\\\":  true}\");\n\t}\n\n\tprivate void assertKeyDeserialize(JacksonModule module) {\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tTypeReference<Map<NameAndAge, Boolean>> typeRef = new TypeReference<>() {\n\t\t};\n\t\tMap<NameAndAge, Boolean> map = mapper.readValue(\"{\\\"spring is 100\\\":  true}\", typeRef);\n\t\tassertThat(map).containsEntry(NameAndAge.create(\"spring\", 100), true);\n\t}\n\n\tprivate AnnotationConfigApplicationContext getContext() {\n\t\tAnnotationConfigApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@JacksonComponent\n\tstatic class OnlySerializer extends NameAndAgeJacksonComponent.Serializer {\n\n\t}\n\n\t@JacksonComponent\n\tstatic class OnlyDeserializer extends NameAndAgeJacksonComponent.Deserializer {\n\n\t}\n\n\t@JacksonComponent\n\tstatic class ComponentWithInnerAbstractClass {\n\n\t\tabstract static class AbstractSerializer extends NameAndAgeJacksonComponent.Serializer {\n\n\t\t}\n\n\t\tstatic class ConcreteSerializer extends AbstractSerializer {\n\n\t\t}\n\n\t\tstatic class NotSuitable {\n\n\t\t}\n\n\t}\n\n\t@JacksonComponent(scope = JacksonComponent.Scope.KEYS)\n\tstatic class OnlyKeySerializer extends NameAndAgeJacksonKeyComponent.Serializer {\n\n\t}\n\n\t@JacksonComponent(scope = JacksonComponent.Scope.KEYS, type = NameAndAge.class)\n\tstatic class OnlyKeyDeserializer extends NameAndAgeJacksonKeyComponent.Deserializer {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/JacksonMixinModuleEntriesBeanRegistrationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.boot.jackson.scan.a.RenameMixInClass;\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndAge;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.Compiled;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link JacksonMixinModuleEntriesBeanRegistrationAotProcessor}.\n *\n * @author Stephane Nicoll\n */\n@CompileWithForkedClassLoader\nclass JacksonMixinModuleEntriesBeanRegistrationAotProcessorTests {\n\n\tprivate final TestGenerationContext generationContext = new TestGenerationContext();\n\n\tprivate final GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\n\t@Test\n\tvoid processAheadOfTimeShouldRegisterBindingHintsForMixins() {\n\t\tregisterEntries(RenameMixInClass.class);\n\t\tprocessAheadOfTime();\n\t\tRuntimeHints runtimeHints = this.generationContext.getRuntimeHints();\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(RenameMixInClass.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWhenPublicClassShouldRegisterClass() {\n\t\tregisterEntries(RenameMixInClass.class);\n\t\tcompile((freshContext, compiled) -> {\n\t\t\tassertThat(freshContext.getBean(TestConfiguration.class).scanningInvoked).isFalse();\n\t\t\tJacksonMixinModuleEntries jacksonMixinModuleEntries = freshContext.getBean(JacksonMixinModuleEntries.class);\n\t\t\tassertThat(jacksonMixinModuleEntries).extracting(\"entries\", InstanceOfAssertFactories.MAP)\n\t\t\t\t.containsExactly(entry(Name.class, RenameMixInClass.class),\n\t\t\t\t\t\tentry(NameAndAge.class, RenameMixInClass.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWhenNonAccessibleClassShouldRegisterClassName() {\n\t\tClass<?> privateMixinClass = ClassUtils\n\t\t\t.resolveClassName(\"org.springframework.boot.jackson.scan.e.PrivateMixInClass\", null);\n\t\tregisterEntries(privateMixinClass);\n\t\tcompile((freshContext, compiled) -> {\n\t\t\tassertThat(freshContext.getBean(TestConfiguration.class).scanningInvoked).isFalse();\n\t\t\tJacksonMixinModuleEntries jacksonMixinModuleEntries = freshContext.getBean(JacksonMixinModuleEntries.class);\n\t\t\tassertThat(jacksonMixinModuleEntries).extracting(\"entries\", InstanceOfAssertFactories.MAP)\n\t\t\t\t.containsExactly(entry(Name.class.getName(), privateMixinClass.getName()),\n\t\t\t\t\t\tentry(NameAndAge.class.getName(), privateMixinClass.getName()));\n\t\t});\n\t}\n\n\tprivate ClassName processAheadOfTime() {\n\t\tClassName className = new ApplicationContextAotGenerator().processAheadOfTime(this.applicationContext,\n\t\t\t\tthis.generationContext);\n\t\tthis.generationContext.writeGeneratedContent();\n\t\treturn className;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void compile(BiConsumer<GenericApplicationContext, Compiled> result) {\n\t\tClassName className = processAheadOfTime();\n\t\tTestCompiler.forSystem()\n\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t.with(this.generationContext)\n\t\t\t.compile((compiled) -> {\n\t\t\t\tGenericApplicationContext freshApplicationContext = new GenericApplicationContext();\n\t\t\t\tApplicationContextInitializer<GenericApplicationContext> initializer = compiled\n\t\t\t\t\t.getInstance(ApplicationContextInitializer.class, className.toString());\n\t\t\t\tinitializer.initialize(freshApplicationContext);\n\t\t\t\tfreshApplicationContext.refresh();\n\t\t\t\tresult.accept(freshApplicationContext, compiled);\n\t\t\t});\n\t}\n\n\tprivate void registerEntries(Class<?>... basePackageClasses) {\n\t\tList<String> packageNames = Arrays.stream(basePackageClasses).map(Class::getPackageName).toList();\n\t\tthis.applicationContext.registerBeanDefinition(\"configuration\",\n\t\t\t\tBeanDefinitionBuilder.rootBeanDefinition(TestConfiguration.class)\n\t\t\t\t\t.addConstructorArgValue(packageNames)\n\t\t\t\t\t.getBeanDefinition());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\tpublic boolean scanningInvoked;\n\n\t\tprivate final Collection<String> packageNames;\n\n\t\tTestConfiguration(Collection<String> packageNames) {\n\t\t\tthis.packageNames = packageNames;\n\t\t}\n\n\t\t@Bean\n\t\tJacksonMixinModuleEntries jacksonMixinModuleEntries(ApplicationContext applicationContext) {\n\t\t\tthis.scanningInvoked = true;\n\t\t\treturn JacksonMixinModuleEntries.scan(applicationContext, this.packageNames);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/JacksonMixinModuleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.JacksonModule;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.jackson.scan.a.RenameMixInClass;\nimport org.springframework.boot.jackson.scan.b.RenameMixInAbstractClass;\nimport org.springframework.boot.jackson.scan.c.RenameMixInInterface;\nimport org.springframework.boot.jackson.scan.d.EmptyMixInClass;\nimport org.springframework.boot.jackson.scan.f.EmptyMixIn;\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndAge;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link JacksonMixinModule}.\n *\n * @author Guirong Hu\n */\nclass JacksonMixinModuleTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid emptyMixInWithEmptyTypesShouldFail() {\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> load(EmptyMixIn.class))\n\t\t\t.withMessageContaining(\"Error creating bean with name 'jacksonMixinModule'\")\n\t\t\t.withStackTraceContaining(\"@JacksonMixin annotation on class \"\n\t\t\t\t\t+ \"'org.springframework.boot.jackson.scan.f.EmptyMixIn' does not specify any types\");\n\t}\n\n\t@Test\n\tvoid moduleWithRenameMixInClassShouldBeMixedIn() throws Exception {\n\t\tload(RenameMixInClass.class);\n\t\tJacksonMixinModule module = getContext().getBean(JacksonMixinModule.class);\n\t\tassertMixIn(module, new Name(\"spring\"), \"{\\\"username\\\":\\\"spring\\\"}\");\n\t\tassertMixIn(module, NameAndAge.create(\"spring\", 100), \"{\\\"age\\\":100,\\\"username\\\":\\\"spring\\\"}\");\n\t}\n\n\t@Test\n\tvoid moduleWithEmptyMixInClassShouldNotBeMixedIn() throws Exception {\n\t\tload(EmptyMixInClass.class);\n\t\tJacksonMixinModule module = getContext().getBean(JacksonMixinModule.class);\n\t\tassertMixIn(module, new Name(\"spring\"), \"{\\\"name\\\":\\\"spring\\\"}\");\n\t\tassertMixIn(module, NameAndAge.create(\"spring\", 100), \"{\\\"age\\\":100,\\\"name\\\":\\\"spring\\\"}\");\n\t}\n\n\t@Test\n\tvoid moduleWithRenameMixInAbstractClassShouldBeMixedIn() throws Exception {\n\t\tload(RenameMixInAbstractClass.class);\n\t\tJacksonMixinModule module = getContext().getBean(JacksonMixinModule.class);\n\t\tassertMixIn(module, NameAndAge.create(\"spring\", 100), \"{\\\"age\\\":100,\\\"username\\\":\\\"spring\\\"}\");\n\t}\n\n\t@Test\n\tvoid moduleWithRenameMixInInterfaceShouldBeMixedIn() throws Exception {\n\t\tload(RenameMixInInterface.class);\n\t\tJacksonMixinModule module = getContext().getBean(JacksonMixinModule.class);\n\t\tassertMixIn(module, NameAndAge.create(\"spring\", 100), \"{\\\"age\\\":100,\\\"username\\\":\\\"spring\\\"}\");\n\t}\n\n\tprivate AnnotationConfigApplicationContext getContext() {\n\t\tAnnotationConfigApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\tprivate void load(Class<?>... basePackageClasses) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.registerBean(JacksonMixinModule.class, () -> createJacksonMixinModule(context, basePackageClasses));\n\t\tcontext.refresh();\n\t\tthis.context = context;\n\t}\n\n\tprivate JacksonMixinModule createJacksonMixinModule(AnnotationConfigApplicationContext context,\n\t\t\tClass<?>... basePackageClasses) {\n\t\tList<String> basePackages = Arrays.stream(basePackageClasses).map(ClassUtils::getPackageName).toList();\n\t\tJacksonMixinModuleEntries entries = JacksonMixinModuleEntries.scan(context, basePackages);\n\t\tJacksonMixinModule jacksonMixinModule = new JacksonMixinModule();\n\t\tjacksonMixinModule.registerEntries(entries, context.getClassLoader());\n\t\treturn jacksonMixinModule;\n\t}\n\n\tprivate void assertMixIn(JacksonModule module, Name value, String expectedJson) throws Exception {\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tString json = mapper.writeValueAsString(value);\n\t\tassertThat(json).isEqualToIgnoringWhitespace(expectedJson);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/NameAndAgeJacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.SerializationContext;\n\nimport org.springframework.boot.jackson.types.NameAndAge;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Sample {@link JacksonComponent @JacksonComponent} used for tests.\n *\n * @author Phillip Webb\n */\n@JacksonComponent\npublic class NameAndAgeJacksonComponent {\n\n\tstatic class Serializer extends ObjectValueSerializer<NameAndAge> {\n\n\t\t@Override\n\t\tprotected void serializeObject(NameAndAge value, JsonGenerator jgen, SerializationContext context) {\n\t\t\tjgen.writeStringProperty(\"theName\", value.getName());\n\t\t\tjgen.writeNumberProperty(\"theAge\", value.getAge());\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends ObjectValueDeserializer<NameAndAge> {\n\n\t\t@Override\n\t\tprotected NameAndAge deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree) {\n\t\t\tString name = nullSafeValue(tree.get(\"name\"), String.class);\n\t\t\tInteger age = nullSafeValue(tree.get(\"age\"), Integer.class);\n\t\t\tassertThat(age).isNotNull();\n\t\t\treturn NameAndAge.create(name, age);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/NameAndAgeJacksonKeyComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.KeyDeserializer;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.ValueSerializer;\n\nimport org.springframework.boot.jackson.types.NameAndAge;\n\n/**\n * Sample {@link JacksonComponent @JacksonComponent} used for tests.\n *\n * @author Paul Aly\n */\n@JacksonComponent(type = NameAndAge.class, scope = JacksonComponent.Scope.KEYS)\npublic class NameAndAgeJacksonKeyComponent {\n\n\tstatic class Serializer extends ValueSerializer<NameAndAge> {\n\n\t\t@Override\n\t\tpublic void serialize(NameAndAge value, JsonGenerator jgen, SerializationContext serializers) {\n\t\t\tjgen.writeName(value.asKey());\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends KeyDeserializer {\n\n\t\t@Override\n\t\tpublic NameAndAge deserializeKey(String key, DeserializationContext ctxt) {\n\t\t\tString[] keys = key.split(\"is\");\n\t\t\treturn NameAndAge.create(keys[0].trim(), Integer.parseInt(keys[1].trim()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/NameAndCareerJacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.SerializationContext;\n\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndCareer;\n\n/**\n * Sample {@link JacksonComponent @JacksonComponent} used for tests.\n *\n * @author Paul Aly\n */\n@JacksonComponent(type = NameAndCareer.class)\npublic class NameAndCareerJacksonComponent {\n\n\tstatic class Serializer extends ObjectValueSerializer<Name> {\n\n\t\t@Override\n\t\tprotected void serializeObject(Name value, JsonGenerator jgen, SerializationContext context) {\n\t\t\tjgen.writeStringProperty(\"name\", value.getName());\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends ObjectValueDeserializer<Name> {\n\n\t\t@Override\n\t\tprotected Name deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree) {\n\t\t\tString name = nullSafeValue(tree.get(\"name\"), String.class);\n\t\t\tString career = nullSafeValue(tree.get(\"career\"), String.class);\n\t\t\treturn new NameAndCareer(name, career);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/ObjectValueDeserializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport java.io.InputStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.time.LocalDate;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.module.SimpleModule;\nimport tools.jackson.databind.node.NullNode;\n\nimport org.springframework.boot.jackson.NameAndAgeJacksonComponent.Deserializer;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ObjectValueDeserializer}.\n *\n * @author Phillip Webb\n */\nclass ObjectValueDeserializerTests {\n\n\tprivate final TestJsonObjectDeserializer<Object> testDeserializer = new TestJsonObjectDeserializer<>();\n\n\t@Test\n\tvoid deserializeObjectShouldReadJson() throws Exception {\n\t\tDeserializer deserializer = new NameAndAgeJacksonComponent.Deserializer();\n\t\tSimpleModule module = new SimpleModule();\n\t\tmodule.addDeserializer(NameAndAge.class, deserializer);\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tNameAndAge nameAndAge = mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\", NameAndAge.class);\n\t\tassertThat(nameAndAge.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nameAndAge.getAge()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenValueIsNullShouldReturnNull() {\n\t\tString value = this.testDeserializer.testNullSafeValue(null, String.class);\n\t\tassertThat(value).isNull();\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.testDeserializer.testNullSafeValue(mock(JsonNode.class), null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsStringShouldReturnString() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.stringValue()).willReturn(\"abc\");\n\t\tString value = this.testDeserializer.testNullSafeValue(node, String.class);\n\t\tassertThat(value).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsBooleanShouldReturnBoolean() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.booleanValue()).willReturn(true);\n\t\tBoolean value = this.testDeserializer.testNullSafeValue(node, Boolean.class);\n\t\tassertThat(value).isTrue();\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsLongShouldReturnLong() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.longValue()).willReturn(10L);\n\t\tLong value = this.testDeserializer.testNullSafeValue(node, Long.class);\n\t\tassertThat(value).isEqualTo(10L);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsIntegerShouldReturnInteger() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.intValue()).willReturn(10);\n\t\tInteger value = this.testDeserializer.testNullSafeValue(node, Integer.class);\n\t\tassertThat(value).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsShortShouldReturnShort() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.shortValue()).willReturn((short) 10);\n\t\tShort value = this.testDeserializer.testNullSafeValue(node, Short.class);\n\t\tassertThat(value).isEqualTo((short) 10);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsDoubleShouldReturnDouble() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.doubleValue()).willReturn(1.1D);\n\t\tDouble value = this.testDeserializer.testNullSafeValue(node, Double.class);\n\t\tassertThat(value).isEqualTo(1.1D);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsFloatShouldReturnFloat() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.floatValue()).willReturn(1.1F);\n\t\tFloat value = this.testDeserializer.testNullSafeValue(node, Float.class);\n\t\tassertThat(value).isEqualTo(1.1F);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsBigDecimalShouldReturnBigDecimal() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.decimalValue()).willReturn(BigDecimal.TEN);\n\t\tBigDecimal value = this.testDeserializer.testNullSafeValue(node, BigDecimal.class);\n\t\tassertThat(value).isEqualTo(BigDecimal.TEN);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsBigIntegerShouldReturnBigInteger() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.bigIntegerValue()).willReturn(BigInteger.TEN);\n\t\tBigInteger value = this.testDeserializer.testNullSafeValue(node, BigInteger.class);\n\t\tassertThat(value).isEqualTo(BigInteger.TEN);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWithMapperShouldTransformValue() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.stringValue()).willReturn(\"2023-12-01\");\n\t\tLocalDate result = this.testDeserializer.testNullSafeValue(node, String.class, LocalDate::parse);\n\t\tassertThat(result).isEqualTo(LocalDate.of(2023, 12, 1));\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsUnknownShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.testDeserializer.testNullSafeValue(mock(JsonNode.class), InputStream.class))\n\t\t\t.withMessageContaining(\"Unsupported value type java.io.InputStream\");\n\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenTreeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.testDeserializer.testGetRequiredNode(null, \"test\"))\n\t\t\t.withMessageContaining(\"'tree' must not be null\");\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenNodeIsNullShouldThrowException() {\n\t\tJsonNode tree = mock(JsonNode.class);\n\t\tgiven(tree.get(\"test\")).willReturn(null);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.testDeserializer.testGetRequiredNode(tree, \"test\"))\n\t\t\t.withMessageContaining(\"Missing JSON field 'test'\");\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenNodeIsNullNodeShouldThrowException() {\n\t\tJsonNode tree = mock(JsonNode.class);\n\t\tgiven(tree.get(\"test\")).willReturn(NullNode.instance);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.testDeserializer.testGetRequiredNode(tree, \"test\"))\n\t\t\t.withMessageContaining(\"Missing JSON field 'test'\");\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenNodeIsFoundShouldReturnNode() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.get(\"test\")).willReturn(node);\n\t\tassertThat(this.testDeserializer.testGetRequiredNode(node, \"test\")).isEqualTo(node);\n\t}\n\n\tstatic class TestJsonObjectDeserializer<T> extends ObjectValueDeserializer<T> {\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprotected T deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree) {\n\t\t\treturn (T) new Object();\n\t\t}\n\n\t\t<D, R> @Nullable R testNullSafeValue(JsonNode jsonNode, Class<D> type, Function<D, R> mapper) {\n\t\t\treturn nullSafeValue(jsonNode, type, mapper);\n\t\t}\n\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\t<D> @Nullable D testNullSafeValue(@Nullable JsonNode jsonNode, @Nullable Class<D> type) {\n\t\t\treturn nullSafeValue(jsonNode, type);\n\t\t}\n\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tJsonNode testGetRequiredNode(@Nullable JsonNode tree, String fieldName) {\n\t\t\treturn getRequiredNode(tree, fieldName);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/ObjectValueSerializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.module.SimpleModule;\n\nimport org.springframework.boot.jackson.NameAndAgeJacksonComponent.Serializer;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ObjectValueSerializer}.\n *\n * @author Phillip Webb\n */\nclass ObjectValueSerializerTests {\n\n\t@Test\n\tvoid serializeObjectShouldWriteJson() throws Exception {\n\t\tSerializer serializer = new NameAndAgeJacksonComponent.Serializer();\n\t\tSimpleModule module = new SimpleModule();\n\t\tmodule.addSerializer(NameAndAge.class, serializer);\n\t\tJsonMapper mapper = JsonMapper.builder().addModule(module).build();\n\t\tString json = mapper.writeValueAsString(NameAndAge.create(\"spring\", 100));\n\t\tassertThat(json).isEqualToIgnoringWhitespace(\"{\\\"theName\\\":\\\"spring\\\",\\\"theAge\\\":100}\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/JacksonAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.time.Duration;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.StreamReadConstraints;\nimport tools.jackson.core.StreamReadFeature;\nimport tools.jackson.core.StreamWriteConstraints;\nimport tools.jackson.core.StreamWriteFeature;\nimport tools.jackson.core.TokenStreamFactory;\nimport tools.jackson.core.json.JsonFactory;\nimport tools.jackson.core.json.JsonReadFeature;\nimport tools.jackson.core.json.JsonWriteFeature;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.JacksonModule;\nimport tools.jackson.databind.MapperFeature;\nimport tools.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.PropertyNamingStrategies;\nimport tools.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.SerializationFeature;\nimport tools.jackson.databind.ValueSerializer;\nimport tools.jackson.databind.cfg.ConstructorDetector;\nimport tools.jackson.databind.cfg.ConstructorDetector.SingleArgConstructor;\nimport tools.jackson.databind.cfg.DateTimeFeature;\nimport tools.jackson.databind.cfg.EnumFeature;\nimport tools.jackson.databind.cfg.JsonNodeFeature;\nimport tools.jackson.databind.cfg.MapperBuilder;\nimport tools.jackson.databind.exc.InvalidFormatException;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.json.JsonMapper.Builder;\nimport tools.jackson.databind.module.SimpleModule;\nimport tools.jackson.databind.util.StdDateFormat;\nimport tools.jackson.dataformat.cbor.CBORFactory;\nimport tools.jackson.dataformat.cbor.CBORMapper;\nimport tools.jackson.dataformat.xml.XmlFactory;\nimport tools.jackson.dataformat.xml.XmlMapper;\nimport tools.jackson.module.kotlin.KotlinModule;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.jackson.JacksonMixin;\nimport org.springframework.boot.jackson.JacksonMixinModule;\nimport org.springframework.boot.jackson.JacksonMixinModuleEntries;\nimport org.springframework.boot.jackson.ObjectValueSerializer;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.CborConfiguration.StandardCborFactoryBuilderCustomizer;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.CborConfiguration.StandardCborMapperBuilderCustomizer;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.JacksonAutoConfigurationRuntimeHints;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.JacksonJsonCustomizerConfiguration.StandardJsonFactoryBuilderCustomizer;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.JacksonJsonCustomizerConfiguration.StandardJsonMapperBuilderCustomizer;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.XmlConfiguration.StandardXmlFactoryBuilderCustomizer;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration.XmlConfiguration.StandardXmlMapperBuilderCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.ProblemDetail;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JacksonAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Sebastien Deleuze\n * @author Johannes Edmeier\n * @author Grzegorz Poznachowski\n * @author Ralf Ueberfuhr\n * @author Eddú Meléndez\n */\nclass JacksonAutoConfigurationTests {\n\n\tprotected final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class));\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid definesFactory(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(mapperType.factoryClass));\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid definesMapper(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(mapperType.mapperClass));\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid definesMapperBuilder(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(mapperType.builderClass));\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid factoryBacksOffWhenCustomFactoryIsDefined(MapperType mapperType) {\n\t\tthis.contextRunner.withBean(\"customFactory\", mapperType.factoryClass).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(mapperType.factoryClass);\n\t\t\tassertThat(context).hasBean(\"customFactory\");\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid mapperBacksOffWhenCustomMapperIsDefined(MapperType mapperType) {\n\t\tthis.contextRunner.withBean(\"customMapper\", mapperType.mapperClass).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(mapperType.mapperClass);\n\t\t\tassertThat(context).hasBean(\"customMapper\");\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid mapperDoesNotBackOffWhenObjectMapperIsDefined(MapperType mapperType) {\n\t\tthis.contextRunner.withBean(ObjectMapper.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(mapperType.mapperClass);\n\t\t\tassertThat(context.getBeansOfType(ObjectMapper.class)).hasSize(MapperType.values().length + 1);\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid mapperBuilderDoesNotBackOffWhenMapperIsDefined(MapperType mapperType) {\n\t\tthis.contextRunner.withBean(mapperType.mapperClass)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(mapperType.builderClass));\n\t}\n\n\t@Test\n\tvoid standardJsonMapperBuilderCustomizerDoesNotBackOffWhenCustomizerIsDefined() {\n\t\tthis.contextRunner.withBean(JsonMapperBuilderCustomizer.class, () -> mock(JsonMapperBuilderCustomizer.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StandardJsonMapperBuilderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid standardCborMapperBuilderCustomizerDoesNotBackOffWhenCustomizerIsDefined() {\n\t\tthis.contextRunner.withBean(CborMapperBuilderCustomizer.class, () -> mock(CborMapperBuilderCustomizer.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StandardCborMapperBuilderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid standardXmlMapperBuilderCustomizerDoesNotBackOffWhenCustomizerIsDefined() {\n\t\tthis.contextRunner.withBean(XmlMapperBuilderCustomizer.class, () -> mock(XmlMapperBuilderCustomizer.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StandardXmlMapperBuilderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid standardJsonFactoryBuilderCustomizerDoesNotBackOffWhenCustomizerIsDefined() {\n\t\tthis.contextRunner.withBean(JsonFactoryBuilderCustomizer.class, () -> mock(JsonFactoryBuilderCustomizer.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StandardJsonFactoryBuilderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid standardCborFactoryBuilderCustomizerDoesNotBackOffWhenCustomizerIsDefined() {\n\t\tthis.contextRunner.withBean(CborFactoryBuilderCustomizer.class, () -> mock(CborFactoryBuilderCustomizer.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StandardCborFactoryBuilderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid standardXmlFactoryBuilderCustomizerDoesNotBackOffWhenCustomizerIsDefined() {\n\t\tthis.contextRunner.withBean(XmlFactoryBuilderCustomizer.class, () -> mock(XmlFactoryBuilderCustomizer.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StandardXmlFactoryBuilderCustomizer.class));\n\t}\n\n\t@Test\n\tvoid doubleModuleRegistration() {\n\t\tthis.contextRunner.withUserConfiguration(DoubleModulesConfig.class).run((context) -> {\n\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\tassertThat(mapper.writeValueAsString(new Foo())).isEqualTo(\"{\\\"foo\\\":\\\"bar\\\"}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid jsonMixinModuleShouldBeAutoConfiguredWithBasePackages() {\n\t\tthis.contextRunner.withUserConfiguration(MixinConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JacksonMixinModule.class).hasSingleBean(JacksonMixinModuleEntries.class);\n\t\t\tJacksonMixinModuleEntries moduleEntries = context.getBean(JacksonMixinModuleEntries.class);\n\t\t\tassertThat(moduleEntries).extracting(\"entries\", InstanceOfAssertFactories.MAP)\n\t\t\t\t.contains(entry(Person.class, EmptyMixin.class));\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid noCustomDateFormat(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(mapper.serializationConfig().getDateFormat()).isInstanceOf(StdDateFormat.class);\n\t\t\tassertThat(mapper.deserializationConfig().getDateFormat()).isInstanceOf(StdDateFormat.class);\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customDateFormat(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.date-format:yyyyMMddHHmmss\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tDateFormat serializationDateFormat = mapper.serializationConfig().getDateFormat();\n\t\t\tassertThat(serializationDateFormat).isInstanceOf(SimpleDateFormat.class);\n\t\t\tassertThat(((SimpleDateFormat) serializationDateFormat).toPattern()).isEqualTo(\"yyyyMMddHHmmss\");\n\t\t\tDateFormat deserializationDateFormat = mapper.serializationConfig().getDateFormat();\n\t\t\tassertThat(deserializationDateFormat).isInstanceOf(SimpleDateFormat.class);\n\t\t\tassertThat(((SimpleDateFormat) deserializationDateFormat).toPattern()).isEqualTo(\"yyyyMMddHHmmss\");\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customDateFormatClass(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.date-format:\" + MyDateFormat.class.getName())\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(mapper.serializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t\tassertThat(mapper.deserializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid noCustomPropertyNamingStrategy(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(mapper.serializationConfig().getPropertyNamingStrategy()).isNull();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customPropertyNamingStrategyField(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.property-naming-strategy:SNAKE_CASE\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(mapper.serializationConfig().getPropertyNamingStrategy()).isInstanceOf(SnakeCaseStrategy.class);\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customPropertyNamingStrategyClass(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.jackson.property-naming-strategy:tools.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(mapper.serializationConfig().getPropertyNamingStrategy())\n\t\t\t\t\t.isInstanceOf(SnakeCaseStrategy.class);\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableSerializationFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.serialization.indent_output:true\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(SerializationFeature.INDENT_OUTPUT.enabledByDefault()).isFalse();\n\t\t\tassertThat(\n\t\t\t\t\tmapper.serializationConfig().hasSerializationFeatures(SerializationFeature.INDENT_OUTPUT.getMask()))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid disableSerializationFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.serialization.wrap_exceptions:false\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(SerializationFeature.WRAP_EXCEPTIONS.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.isEnabled(SerializationFeature.WRAP_EXCEPTIONS)).isFalse();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableDeserializationFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.deserialization.use_big_decimal_for_floats:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.deserializationConfig()\n\t\t\t\t\t.hasDeserializationFeatures(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS.getMask())).isTrue();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid disableDeserializationFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.deserialization.fail-on-null-for-primitives:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES.enabledByDefault()).isTrue();\n\t\t\t\tassertThat(mapper.deserializationConfig()\n\t\t\t\t\t.hasDeserializationFeatures(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES.getMask()))\n\t\t\t\t\t.isFalse();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableMapperFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.mapper.require_setters_for_getters:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS.enabledByDefault()).isFalse();\n\n\t\t\t\tassertThat(mapper.serializationConfig().isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS)).isTrue();\n\t\t\t\tassertThat(mapper.deserializationConfig().isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS))\n\t\t\t\t\t.isTrue();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid disableMapperFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.mapper.infer-property-mutators:false\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(MapperFeature.INFER_PROPERTY_MUTATORS.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.deserializationConfig().isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS)).isFalse();\n\t\t\tassertThat(mapper.serializationConfig().isEnabled(MapperFeature.INFER_PROPERTY_MUTATORS)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableJsonReadFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.json.read.allow_single_quotes:true\").run((context) -> {\n\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\tassertThat(JsonReadFeature.ALLOW_SINGLE_QUOTES.enabledByDefault()).isFalse();\n\t\t\tassertThat(mapper.isEnabled(JsonReadFeature.ALLOW_SINGLE_QUOTES)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableJsonWriteFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.json.write.write_numbers_as_strings:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\t\tJsonWriteFeature feature = JsonWriteFeature.WRITE_NUMBERS_AS_STRINGS;\n\t\t\t\tassertThat(feature.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.isEnabled(feature)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid disableJsonWriteFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.json.write.write_hex_upper_case:false\").run((context) -> {\n\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\tassertThat(JsonWriteFeature.WRITE_HEX_UPPER_CASE.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.isEnabled(JsonWriteFeature.WRITE_HEX_UPPER_CASE)).isFalse();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableDatetimeFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.datatype.datetime.write-dates-as-timestamps:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tDateTimeFeature feature = DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS;\n\t\t\t\tassertThat(feature.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.isEnabled(feature)).isTrue();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid disableDatetimeFeature(MapperType mapperType) {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jackson.datatype.datetime.adjust-dates-to-context-time-zone:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(DateTimeFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE.enabledByDefault()).isTrue();\n\t\t\t\tassertThat(mapper.isEnabled(DateTimeFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)).isFalse();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableEnumFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.datatype.enum.write-enums-to-lowercase=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(EnumFeature.WRITE_ENUMS_TO_LOWERCASE.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.serializationConfig().isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE)).isTrue();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid disableJsonNodeFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.datatype.json-node.write-null-properties:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tassertThat(JsonNodeFeature.WRITE_NULL_PROPERTIES.enabledByDefault()).isTrue();\n\t\t\t\tassertThat(mapper.deserializationConfig().isEnabled(JsonNodeFeature.WRITE_NULL_PROPERTIES)).isFalse();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableWriteFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.write.write-bigdecimal-as-plain:true\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN.enabledByDefault()).isFalse();\n\t\t\tassertThat(mapper.isEnabled(StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN)).isTrue();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableReadFeature(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.read.strict-duplicate-detection:true\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(StreamReadFeature.STRICT_DUPLICATE_DETECTION.enabledByDefault()).isFalse();\n\t\t\tassertThat(mapper.isEnabled(StreamReadFeature.STRICT_DUPLICATE_DETECTION)).isTrue();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid moduleBeansAndWellKnownModulesAreRegisteredWithTheMapperBuilder(MapperType mapperType) {\n\t\tthis.contextRunner.withUserConfiguration(ModuleConfig.class).run((context) -> {\n\t\t\tBuilder jsonMapperBuilder = context.getBean(JsonMapper.Builder.class);\n\t\t\tJsonMapper jsonMapper = jsonMapperBuilder.build();\n\t\t\tassertThat(context.getBean(CustomModule.class).getOwners()).contains(jsonMapperBuilder);\n\t\t\tassertThat(jsonMapper._serializationContext().findValueSerializer(Baz.class)).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customModulesRegisteredByJsonMapperBuilderCustomizerShouldBeRetained() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ModuleConfig.class, CustomModuleJsonMapperBuilderCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJsonMapper jsonMapper = context.getBean(JsonMapper.class);\n\t\t\t\tassertThat(jsonMapper.registeredModules()).extracting(JacksonModule::getModuleName)\n\t\t\t\t\t.contains(\"module-A\", \"module-B\", CustomModule.class.getName());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customModulesRegisteredByCborMapperBuilderCustomizerShouldBeRetained() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ModuleConfig.class, CustomModuleCborMapperBuilderCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tCBORMapper mapper = context.getBean(CBORMapper.class);\n\t\t\t\tassertThat(mapper.registeredModules()).extracting(JacksonModule::getModuleName)\n\t\t\t\t\t.contains(\"module-A\", \"module-B\", CustomModule.class.getName());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customModulesRegisteredByXmlMapperBuilderCustomizerShouldBeRetained() {\n\t\tthis.contextRunner.withUserConfiguration(ModuleConfig.class, CustomModuleXmlMapperBuilderCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tXmlMapper mapper = context.getBean(XmlMapper.class);\n\t\t\t\tassertThat(mapper.registeredModules()).extracting(JacksonModule::getModuleName)\n\t\t\t\t\t.contains(\"module-A\", \"module-B\", CustomModule.class.getName());\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid defaultPropertyInclusion(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(mapper.serializationConfig().getDefaultPropertyInclusion().getContentInclusion())\n\t\t\t\t.isEqualTo(JsonInclude.Include.USE_DEFAULTS);\n\t\t\tassertThat(mapper.serializationConfig().getDefaultPropertyInclusion().getValueInclusion())\n\t\t\t\t.isEqualTo(JsonInclude.Include.USE_DEFAULTS);\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customPropertyInclusion(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.default-property-inclusion:non_null\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tassertThat(mapper.serializationConfig().getDefaultPropertyInclusion().getContentInclusion())\n\t\t\t\t.isEqualTo(JsonInclude.Include.NON_NULL);\n\t\t\tassertThat(mapper.serializationConfig().getDefaultPropertyInclusion().getValueInclusion())\n\t\t\t\t.isEqualTo(JsonInclude.Include.NON_NULL);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeZoneFormattingADateToJson() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.time-zone:GMT+10\", \"spring.jackson.date-format:z\")\n\t\t\t.run((context) -> {\n\t\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\t\tDate date = new Date(1436966242231L);\n\t\t\t\tassertThat(mapper.writeValueAsString(date)).isEqualTo(\"\\\"GMT+10:00\\\"\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeZoneFormattingADateToCbor() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.time-zone:GMT+10\", \"spring.jackson.date-format:z\")\n\t\t\t.run((context) -> {\n\t\t\t\tCBORMapper mapper = context.getBean(CBORMapper.class);\n\t\t\t\tDate date = new Date(1436966242231L);\n\t\t\t\tassertThat(mapper.writeValueAsBytes(date))\n\t\t\t\t\t.isEqualTo(new byte[] { 105, 71, 77, 84, 43, 49, 48, 58, 48, 48 });\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeZoneFormattingADateToXml() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.time-zone:GMT+10\", \"spring.jackson.date-format:z\")\n\t\t\t.run((context) -> {\n\t\t\t\tXmlMapper mapper = context.getBean(XmlMapper.class);\n\t\t\t\tDate date = new Date(1436966242231L);\n\t\t\t\tassertThat(mapper.writeValueAsString(date)).isEqualTo(\"<Date>GMT+10:00</Date>\");\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid enableDefaultLeniency(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.default-leniency:true\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(mapperType.mapperClass);\n\t\t\tbyte[] source = mapper.writeValueAsBytes(Map.of(\"birthDate\", \"2010-12-30\"));\n\t\t\tPerson person = mapper.readValue(source, Person.class);\n\t\t\tassertThat(person.getBirthDate()).isNotNull();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid disableDefaultLeniency(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.default-leniency:false\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(mapperType.mapperClass);\n\t\t\tbyte[] source = mapper.writeValueAsBytes(Map.of(\"birthDate\", \"2010-12-30\"));\n\t\t\tassertThatExceptionOfType(InvalidFormatException.class)\n\t\t\t\t.isThrownBy(() -> mapper.readValue(source, Person.class))\n\t\t\t\t.withMessageContaining(\"expected format\")\n\t\t\t\t.withMessageContaining(\"yyyyMMdd\");\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid constructorDetectorWithNoStrategyUseDefault(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tConstructorDetector cd = mapper.deserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.HEURISTIC);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid constructorDetectorWithDefaultStrategy(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.constructor-detector=default\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tConstructorDetector cd = mapper.deserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.HEURISTIC);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid constructorDetectorWithUsePropertiesBasedStrategy(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.constructor-detector=use-properties-based\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\t\tConstructorDetector cd = mapper.deserializationConfig().getConstructorDetector();\n\t\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.PROPERTIES);\n\t\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid constructorDetectorWithUseDelegatingStrategy(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.constructor-detector=use-delegating\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tConstructorDetector cd = mapper.deserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.DELEGATING);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid constructorDetectorWithExplicitOnlyStrategy(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.constructor-detector=explicit-only\").run((context) -> {\n\t\t\tObjectMapper mapper = mapperType.getMapper(context);\n\t\t\tConstructorDetector cd = mapper.deserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.REQUIRE_MODE);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid additionalJsonMapperBuilderCustomization() {\n\t\tthis.contextRunner.withBean(JsonMapperBuilderCustomizer.class, () -> null)\n\t\t\t.withUserConfiguration(JsonMapperBuilderCustomConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\t\tassertThat(mapper.deserializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t\tassertThat(mapper.serializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid additionalCborMapperBuilderCustomization() {\n\t\tthis.contextRunner.withBean(CborMapperBuilderCustomizer.class, () -> null)\n\t\t\t.withUserConfiguration(CborMapperBuilderCustomConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tCBORMapper mapper = context.getBean(CBORMapper.class);\n\t\t\t\tassertThat(mapper.deserializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t\tassertThat(mapper.serializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid additionalXmlMapperBuilderCustomization() {\n\t\tthis.contextRunner.withBean(XmlMapperBuilderCustomizer.class, () -> null)\n\t\t\t.withUserConfiguration(XmlMapperBuilderCustomConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tXmlMapper mapper = context.getBean(XmlMapper.class);\n\t\t\t\tassertThat(mapper.deserializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t\tassertThat(mapper.serializationConfig().getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid writeDurationAsTimestampsDefault(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(mapperType.mapperClass);\n\t\t\tDuration duration = Duration.ofHours(2);\n\t\t\tString written = mapper.readerFor(String.class).readValue(mapper.writeValueAsBytes(duration));\n\t\t\tassertThat(written).isEqualTo(\"PT2H\");\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\t@SuppressWarnings(\"unchecked\")\n\tvoid writeWithVisibility(MapperType mapperType) {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jackson.visibility.getter:none\", \"spring.jackson.visibility.field:any\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(mapperType.mapperClass);\n\t\t\t\tMap<String, ?> written = mapper.readValue(mapper.writeValueAsBytes(new VisibilityBean()), Map.class);\n\t\t\t\tassertThat(written).containsOnlyKeys(\"property1\", \"property2\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jsonMapperBuilderIsNotSharedAcrossMultipleInjectionPoints() {\n\t\tthis.contextRunner.withUserConfiguration(JsonMapperBuilderConsumerConfig.class).run((context) -> {\n\t\t\tJsonMapperBuilderConsumerConfig consumer = context.getBean(JsonMapperBuilderConsumerConfig.class);\n\t\t\tassertThat(consumer.builderOne).isNotNull();\n\t\t\tassertThat(consumer.builderTwo).isNotNull();\n\t\t\tassertThat(consumer.builderOne).isNotSameAs(consumer.builderTwo);\n\t\t});\n\t}\n\n\t@Test\n\tvoid cborMapperBuilderIsNotSharedAcrossMultipleInjectionPoints() {\n\t\tthis.contextRunner.withUserConfiguration(CborMapperBuilderConsumerConfig.class).run((context) -> {\n\t\t\tCborMapperBuilderConsumerConfig consumer = context.getBean(CborMapperBuilderConsumerConfig.class);\n\t\t\tassertThat(consumer.builderOne).isNotNull();\n\t\t\tassertThat(consumer.builderTwo).isNotNull();\n\t\t\tassertThat(consumer.builderOne).isNotSameAs(consumer.builderTwo);\n\t\t});\n\t}\n\n\t@Test\n\tvoid xmlMapperBuilderIsNotSharedAcrossMultipleInjectionPoints() {\n\t\tthis.contextRunner.withUserConfiguration(XmlMapperBuilderConsumerConfig.class).run((context) -> {\n\t\t\tXmlMapperBuilderConsumerConfig consumer = context.getBean(XmlMapperBuilderConsumerConfig.class);\n\t\t\tassertThat(consumer.builderOne).isNotNull();\n\t\t\tassertThat(consumer.builderTwo).isNotNull();\n\t\t\tassertThat(consumer.builderOne).isNotSameAs(consumer.builderTwo);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jacksonComponentThatInjectsJsonMapperCausesBeanCurrentlyInCreationException() {\n\t\tthis.contextRunner.withUserConfiguration(CircularDependencySerializerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(BeanCurrentlyInCreationException.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterPropertyNamingStrategyHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew JacksonAutoConfigurationRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(PropertyNamingStrategies.class)).accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterProblemDetailsMixinWithJsonMapper() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJsonMapper mapper = context.getBean(JsonMapper.class);\n\t\t\tProblemDetail problemDetail = ProblemDetail.forStatus(404);\n\t\t\tproblemDetail.setProperty(\"spring\", \"boot\");\n\t\t\tString json = mapper.writeValueAsString(problemDetail);\n\t\t\tassertThat(json).isEqualTo(\"{\\\"status\\\":404,\\\"title\\\":\\\"Not Found\\\",\\\"spring\\\":\\\"boot\\\"}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterProblemDetailsMixinWithXmlMapper() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tXmlMapper mapper = context.getBean(XmlMapper.class);\n\t\t\tProblemDetail problemDetail = ProblemDetail.forStatus(404);\n\t\t\tproblemDetail.setProperty(\"spring\", \"boot\");\n\t\t\tString xml = mapper.writeValueAsString(problemDetail);\n\t\t\tassertThat(xml).isEqualTo(\n\t\t\t\t\t\"<problem xmlns=\\\"urn:ietf:rfc:7807\\\"><status>404</status><title>Not Found</title><spring>boot</spring></problem>\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUsingJackson2DefaultsJsonMapperShouldBeConfiguredUsingConfigureForJackson2() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.use-jackson2-defaults=true\").run((context) -> {\n\t\t\tJsonMapper jsonMapper = context.getBean(JsonMapper.class);\n\t\t\tJsonMapper jackson2ConfiguredJsonMapper = JsonMapper.builder().configureForJackson2().build();\n\t\t\tassertCommonFeatureConfiguration(jsonMapper, jackson2ConfiguredJsonMapper);\n\t\t\tfor (JsonReadFeature feature : JsonReadFeature.values()) {\n\t\t\t\tassertThat(jsonMapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t\t.isEqualTo(jackson2ConfiguredJsonMapper.isEnabled(feature));\n\t\t\t}\n\t\t\tfor (JsonWriteFeature feature : JsonWriteFeature.values()) {\n\t\t\t\tassertThat(jsonMapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t\t.isEqualTo(jackson2ConfiguredJsonMapper.isEnabled(feature));\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUsingJackson2DefaultsCborMapperShouldBeConfiguredUsingConfigureForJackson2() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.use-jackson2-defaults=true\").run((context) -> {\n\t\t\tCBORMapper cborMapper = context.getBean(CBORMapper.class);\n\t\t\tCBORMapper jackson2ConfiguredCborMapper = CBORMapper.builder().configureForJackson2().build();\n\t\t\tassertCommonFeatureConfiguration(cborMapper, jackson2ConfiguredCborMapper);\n\t\t\tassertThat(cborMapper.deserializationConfig().getFormatReadFeatures())\n\t\t\t\t.isEqualTo(jackson2ConfiguredCborMapper.deserializationConfig().getFormatReadFeatures());\n\t\t\tassertThat(cborMapper.serializationConfig().getFormatWriteFeatures())\n\t\t\t\t.isEqualTo(jackson2ConfiguredCborMapper.serializationConfig().getFormatWriteFeatures());\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUsingJackson2DefaultsXmlMapperShouldBeConfiguredUsingConfigureForJackson2() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.use-jackson2-defaults=true\").run((context) -> {\n\t\t\tXmlMapper xmlMapper = context.getBean(XmlMapper.class);\n\t\t\tXmlMapper jackson2ConfiguredXmlMapper = XmlMapper.builder().configureForJackson2().build();\n\t\t\tassertCommonFeatureConfiguration(xmlMapper, jackson2ConfiguredXmlMapper);\n\t\t\tassertThat(xmlMapper.deserializationConfig().getFormatReadFeatures())\n\t\t\t\t.isEqualTo(jackson2ConfiguredXmlMapper.deserializationConfig().getFormatReadFeatures());\n\t\t\tassertThat(xmlMapper.serializationConfig().getFormatWriteFeatures())\n\t\t\t\t.isEqualTo(jackson2ConfiguredXmlMapper.serializationConfig().getFormatWriteFeatures());\n\t\t});\n\t}\n\n\tprivate void assertCommonFeatureConfiguration(ObjectMapper mapper, ObjectMapper jackson2ConfiguredMapper) {\n\t\tfor (DateTimeFeature feature : DateTimeFeature.values()) {\n\t\t\tboolean expected = (feature == DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS\n\t\t\t\t\t|| feature == DateTimeFeature.WRITE_DURATIONS_AS_TIMESTAMPS) ? false\n\t\t\t\t\t\t\t: jackson2ConfiguredMapper.isEnabled(feature);\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name()).isEqualTo(expected);\n\t\t}\n\t\tfor (DeserializationFeature feature : DeserializationFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t\tfor (EnumFeature feature : EnumFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t\tfor (JsonNodeFeature feature : JsonNodeFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t\tfor (MapperFeature feature : MapperFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t\tfor (SerializationFeature feature : SerializationFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t\tfor (StreamReadFeature feature : StreamReadFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t\tfor (StreamWriteFeature feature : StreamWriteFeature.values()) {\n\t\t\tassertThat(mapper.isEnabled(feature)).as(feature.name())\n\t\t\t\t.isEqualTo(jackson2ConfiguredMapper.isEnabled(feature));\n\t\t}\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid shouldFindAndAddModulesByDefault(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> assertThat(mapperType.getMapper(context).registeredModules())\n\t\t\t.hasAtLeastOneElementOfType(KotlinModule.class));\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid shouldNotFindAndAddModulesWhenDisabled(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.find-and-add-modules=false\")\n\t\t\t.run((context) -> assertThat(mapperType.getMapper(context).registeredModules())\n\t\t\t\t.doesNotHaveAnyElementsOfTypes(KotlinModule.class));\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid defaultStreamReadConstraintsMatchJacksonDefaults(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tStreamReadConstraints streamReadConstraints = mapperType.getFactory(context).streamReadConstraints();\n\t\t\tassertThat(streamReadConstraints.getMaxDocumentLength())\n\t\t\t\t.isEqualTo(StreamReadConstraints.DEFAULT_MAX_DOC_LEN);\n\t\t\tassertThat(streamReadConstraints.getMaxNameLength()).isEqualTo(StreamReadConstraints.DEFAULT_MAX_NAME_LEN);\n\t\t\tassertThat(streamReadConstraints.getMaxNestingDepth()).isEqualTo(StreamReadConstraints.DEFAULT_MAX_DEPTH);\n\t\t\tassertThat(streamReadConstraints.getMaxNumberLength()).isEqualTo(StreamReadConstraints.DEFAULT_MAX_NUM_LEN);\n\t\t\tassertThat(streamReadConstraints.getMaxStringLength())\n\t\t\t\t.isEqualTo(StreamReadConstraints.DEFAULT_MAX_STRING_LEN);\n\t\t\tassertThat(streamReadConstraints.getMaxTokenCount())\n\t\t\t\t.isEqualTo(StreamReadConstraints.DEFAULT_MAX_TOKEN_COUNT);\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customStreamReadConstraintsAreAppliedToAutoConfiguredFactory(MapperType mapperType) {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jackson.factory.constraints.read.max-document-length=1000\",\n\t\t\t\t\t\"spring.jackson.factory.constraints.read.max-name-length=1001\",\n\t\t\t\t\t\"spring.jackson.factory.constraints.read.max-nesting-depth=1002\",\n\t\t\t\t\t\"spring.jackson.factory.constraints.read.max-number-length=1003\",\n\t\t\t\t\t\"spring.jackson.factory.constraints.read.max-string-length=1004\",\n\t\t\t\t\t\"spring.jackson.factory.constraints.read.max-token-count=1005\")\n\t\t\t.run((context) -> {\n\t\t\t\tStreamReadConstraints streamReadConstraints = mapperType.getFactory(context).streamReadConstraints();\n\t\t\t\tassertThat(streamReadConstraints.getMaxDocumentLength()).isEqualTo(1000);\n\t\t\t\tassertThat(streamReadConstraints.getMaxNameLength()).isEqualTo(1001);\n\t\t\t\tassertThat(streamReadConstraints.getMaxNestingDepth()).isEqualTo(1002);\n\t\t\t\tassertThat(streamReadConstraints.getMaxNumberLength()).isEqualTo(1003);\n\t\t\t\tassertThat(streamReadConstraints.getMaxStringLength()).isEqualTo(1004);\n\t\t\t\tassertThat(streamReadConstraints.getMaxTokenCount()).isEqualTo(1005);\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid customStreamWriteConstraintsAreAppliedToAutoConfiguredFactory(MapperType mapperType) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson.factory.constraints.write.max-nesting-depth=1000\")\n\t\t\t.run((context) -> {\n\t\t\t\tStreamWriteConstraints streamWriteConstraints = mapperType.getFactory(context).streamWriteConstraints();\n\t\t\t\tassertThat(streamWriteConstraints.getMaxNestingDepth()).isEqualTo(1000);\n\t\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid defaultStreamWriteConstraintsMatchJacksonDefaults(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tStreamWriteConstraints streamWriteConstraints = mapperType.getFactory(context).streamWriteConstraints();\n\t\t\tassertThat(streamWriteConstraints.getMaxNestingDepth()).isEqualTo(StreamReadConstraints.DEFAULT_MAX_DEPTH);\n\t\t});\n\t}\n\n\t@EnumSource\n\t@ParameterizedTest\n\tvoid mapperHasASpringBeanHandlerInstantiator(MapperType mapperType) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(mapperType.getMapper(context).deserializationConfig().getHandlerInstantiator())\n\t\t\t\t.isInstanceOf(SpringBeanHandlerInstantiator.class);\n\t\t\tassertThat(mapperType.getMapper(context).serializationConfig().getHandlerInstantiator())\n\t\t\t\t.isInstanceOf(SpringBeanHandlerInstantiator.class);\n\t\t});\n\t}\n\n\tstatic class MyDateFormat extends SimpleDateFormat {\n\n\t\tMyDateFormat() {\n\t\t\tsuper(\"yyyy-MM-dd HH:mm:ss\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockObjectMapperConfig {\n\n\t\t@Bean\n\t\t@Primary\n\t\tObjectMapper objectMapper() {\n\t\t\treturn mock(ObjectMapper.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BazSerializer.class)\n\tstatic class ModuleConfig {\n\n\t\t@Bean\n\t\tCustomModule jacksonModule() {\n\t\t\treturn new CustomModule();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class DoubleModulesConfig {\n\n\t\t@Bean\n\t\tJacksonModule jacksonModule() {\n\t\t\tSimpleModule module = new SimpleModule();\n\t\t\tmodule.addSerializer(Foo.class, new ValueSerializer<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void serialize(Foo value, JsonGenerator jgen, SerializationContext context) {\n\t\t\t\t\tjgen.writeStartObject();\n\t\t\t\t\tjgen.writeStringProperty(\"foo\", \"bar\");\n\t\t\t\t\tjgen.writeEndObject();\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn module;\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tJsonMapper jsonMapper() {\n\t\t\treturn JsonMapper.builder().addModule(jacksonModule()).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JsonMapperBuilderCustomConfig {\n\n\t\t@Bean\n\t\tJsonMapperBuilderCustomizer customDateFormat() {\n\t\t\treturn (builder) -> builder.defaultDateFormat(new MyDateFormat());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CborMapperBuilderCustomConfig {\n\n\t\t@Bean\n\t\tCborMapperBuilderCustomizer customDateFormat() {\n\t\t\treturn (builder) -> builder.defaultDateFormat(new MyDateFormat());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class XmlMapperBuilderCustomConfig {\n\n\t\t@Bean\n\t\tXmlMapperBuilderCustomizer customDateFormat() {\n\t\t\treturn (builder) -> builder.defaultDateFormat(new MyDateFormat());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomModuleJsonMapperBuilderCustomizerConfig {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tJsonMapperBuilderCustomizer highPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.addModule(new SimpleModule(\"module-A\"));\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tJsonMapperBuilderCustomizer lowPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.addModule(new SimpleModule(\"module-B\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomModuleCborMapperBuilderCustomizerConfig {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tCborMapperBuilderCustomizer highPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.addModule(new SimpleModule(\"module-A\"));\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tCborMapperBuilderCustomizer lowPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.addModule(new SimpleModule(\"module-B\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomModuleXmlMapperBuilderCustomizerConfig {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tXmlMapperBuilderCustomizer highPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.addModule(new SimpleModule(\"module-A\"));\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tXmlMapperBuilderCustomizer lowPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.addModule(new SimpleModule(\"module-B\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JsonMapperBuilderConsumerConfig {\n\n\t\tJsonMapper.@Nullable Builder builderOne;\n\n\t\tJsonMapper.@Nullable Builder builderTwo;\n\n\t\t@Bean\n\t\tString consumerOne(JsonMapper.Builder builder) {\n\t\t\tthis.builderOne = builder;\n\t\t\treturn \"one\";\n\t\t}\n\n\t\t@Bean\n\t\tString consumerTwo(JsonMapper.Builder builder) {\n\t\t\tthis.builderTwo = builder;\n\t\t\treturn \"two\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CborMapperBuilderConsumerConfig {\n\n\t\tCBORMapper.@Nullable Builder builderOne;\n\n\t\tCBORMapper.@Nullable Builder builderTwo;\n\n\t\t@Bean\n\t\tString consumerOne(CBORMapper.Builder builder) {\n\t\t\tthis.builderOne = builder;\n\t\t\treturn \"one\";\n\t\t}\n\n\t\t@Bean\n\t\tString consumerTwo(CBORMapper.Builder builder) {\n\t\t\tthis.builderTwo = builder;\n\t\t\treturn \"two\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class XmlMapperBuilderConsumerConfig {\n\n\t\tXmlMapper.@Nullable Builder builderOne;\n\n\t\tXmlMapper.@Nullable Builder builderTwo;\n\n\t\t@Bean\n\t\tString consumerOne(XmlMapper.Builder builder) {\n\t\t\tthis.builderOne = builder;\n\t\t\treturn \"one\";\n\t\t}\n\n\t\t@Bean\n\t\tString consumerTwo(XmlMapper.Builder builder) {\n\t\t\tthis.builderTwo = builder;\n\t\t\treturn \"two\";\n\t\t}\n\n\t}\n\n\tprotected static final class Foo {\n\n\t\tprivate @Nullable String name;\n\n\t\tprivate Foo() {\n\t\t}\n\n\t\tstatic Foo create() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\tstatic class Bar {\n\n\t\tprivate @Nullable String propertyName;\n\n\t\t@Nullable String getPropertyName() {\n\t\t\treturn this.propertyName;\n\t\t}\n\n\t\tvoid setPropertyName(@Nullable String propertyName) {\n\t\t\tthis.propertyName = propertyName;\n\t\t}\n\n\t}\n\n\t@JacksonComponent\n\tstatic class BazSerializer extends ObjectValueSerializer<Baz> {\n\n\t\t@Override\n\t\tprotected void serializeObject(Baz value, JsonGenerator jgen, SerializationContext context) {\n\t\t}\n\n\t}\n\n\tstatic class Baz {\n\n\t}\n\n\tstatic class CustomModule extends SimpleModule {\n\n\t\tprivate final Set<Object> owners = new HashSet<>();\n\n\t\t@Override\n\t\tpublic void setupModule(SetupContext context) {\n\t\t\tthis.owners.add(context.getOwner());\n\t\t}\n\n\t\tSet<Object> getOwners() {\n\t\t\treturn this.owners;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class VisibilityBean {\n\n\t\tprivate @Nullable String property1;\n\n\t\tpublic @Nullable String property2;\n\n\t\t@Nullable String getProperty3() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class Person {\n\n\t\t@JsonFormat(pattern = \"yyyyMMdd\")\n\t\tprivate @Nullable Date birthDate;\n\n\t\t@Nullable Date getBirthDate() {\n\t\t\treturn this.birthDate;\n\t\t}\n\n\t\tvoid setBirthDate(@Nullable Date birthDate) {\n\t\t\tthis.birthDate = birthDate;\n\t\t}\n\n\t}\n\n\t@JacksonMixin(type = Person.class)\n\tstatic class EmptyMixin {\n\n\t}\n\n\t@AutoConfigurationPackage\n\tstatic class MixinConfiguration {\n\n\t}\n\n\t@JacksonComponent\n\tstatic class CircularDependencySerializer extends ValueSerializer<String> {\n\n\t\tCircularDependencySerializer(JsonMapper jsonMapper) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void serialize(String value, JsonGenerator gen, SerializationContext context) {\n\n\t\t}\n\n\t}\n\n\t@Import(CircularDependencySerializer.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CircularDependencySerializerConfiguration {\n\n\t}\n\n\tenum MapperType {\n\n\t\tCBOR(CBORFactory.class, CBORMapper.class, CBORMapper.Builder.class),\n\t\tJSON(JsonFactory.class, JsonMapper.class, JsonMapper.Builder.class),\n\t\tXML(XmlFactory.class, XmlMapper.class, XmlMapper.Builder.class);\n\n\t\tprivate final Class<? extends TokenStreamFactory> factoryClass;\n\n\t\tprivate final Class<? extends ObjectMapper> mapperClass;\n\n\t\tprivate final Class<? extends MapperBuilder<?, ?>> builderClass;\n\n\t\t<F extends TokenStreamFactory, M extends ObjectMapper, B extends MapperBuilder<M, B>> MapperType(\n\t\t\t\tClass<F> factoryClass, Class<M> mapperClass, Class<B> builderClass) {\n\t\t\tthis.factoryClass = factoryClass;\n\t\t\tthis.mapperClass = mapperClass;\n\t\t\tthis.builderClass = builderClass;\n\t\t}\n\n\t\tObjectMapper getMapper(ApplicationContext context) {\n\t\t\treturn context.getBean(this.mapperClass);\n\t\t}\n\n\t\tTokenStreamFactory getFactory(ApplicationContext context) {\n\t\t\treturn context.getBean(this.mapperClass).tokenStreamFactory();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/JacksonTesterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.autoconfigure.json.JsonTestersAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonTestersAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass JacksonTesterAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JsonTestersAutoConfiguration.class, JacksonAutoConfiguration.class,\n\t\t\t\tJacksonTesterTestAutoConfiguration.class));\n\n\t@Test\n\tvoid hintsAreContributed() {\n\t\tthis.runner.withPropertyValues(\"spring.test.jsontesters.enabled=true\").prepare((context) -> {\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\t\tnew ApplicationContextAotGenerator().processAheadOfTime(\n\t\t\t\t\t(GenericApplicationContext) context.getSourceApplicationContext(), generationContext);\n\t\t\tReflectionHintsPredicates hints = RuntimeHintsPredicates.reflection();\n\t\t\tassertThat(hints.onType(JacksonTester.class)).accepts(generationContext.getRuntimeHints());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/SpringBeanHandlerInstantiatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport com.fasterxml.jackson.annotation.JsonTypeInfo;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DatabindContext;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JavaType;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.KeyDeserializer;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.ValueDeserializer;\nimport tools.jackson.databind.ValueSerializer;\nimport tools.jackson.databind.annotation.JsonDeserialize;\nimport tools.jackson.databind.annotation.JsonSerialize;\nimport tools.jackson.databind.annotation.JsonTypeIdResolver;\nimport tools.jackson.databind.annotation.JsonTypeResolver;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.jsontype.NamedType;\nimport tools.jackson.databind.jsontype.TypeDeserializer;\nimport tools.jackson.databind.jsontype.TypeIdResolver;\nimport tools.jackson.databind.jsontype.TypeSerializer;\nimport tools.jackson.databind.jsontype.impl.StdTypeResolverBuilder;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBeanHandlerInstantiator}. Adapted from Spring Framework's\n * <a href=\n * \"https://github.com/spring-projects/spring-framework/blob/b246fc881b2bc83daea0a333f1c2fea7212e569d/spring-web/src/test/java/org/springframework/http/support/JacksonHandlerInstantiatorTests.java\">JacksonHandlerInstantiatorTests</a>.\n *\n * @author Sebastien Deleuze\n * @author Andy Wilkinson\n */\nclass SpringBeanHandlerInstantiatorTests {\n\n\t@Test\n\tvoid autowiredSerializer() {\n\t\twithHandlerInstantiator((jsonMapper) -> {\n\t\t\tUser user = new User(\"bob\");\n\t\t\tString json = jsonMapper.writeValueAsString(user);\n\t\t\tassertThat(json).isEqualTo(\"{\\\"username\\\":\\\"BOB\\\"}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid autowiredDeserializer() {\n\t\twithHandlerInstantiator((jsonMapper) -> {\n\t\t\tString json = \"{\\\"username\\\":\\\"bob\\\"}\";\n\t\t\tUser user = jsonMapper.readValue(json, User.class);\n\t\t\tassertThat(user.getUsername()).isEqualTo(\"BOB\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid autowiredKeyDeserializer() {\n\t\twithHandlerInstantiator((jsonMapper) -> {\n\t\t\tString json = \"{\\\"credentials\\\":{\\\"bob\\\":\\\"admin\\\"}}\";\n\t\t\tSecurityRegistry registry = jsonMapper.readValue(json, SecurityRegistry.class);\n\t\t\tassertThat(registry.getCredentials()).containsKey(\"BOB\");\n\t\t\tassertThat(registry.getCredentials()).doesNotContainKey(\"bob\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid applicationContextAwaretypeResolverBuilder() {\n\t\twithHandlerInstantiator((jsonMapper) -> {\n\t\t\tjsonMapper.writeValueAsString(new Group());\n\t\t\tassertThat(CustomTypeResolverBuilder.autowiredFieldInitialized).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid applicationContextAwareTypeIdResolver() {\n\t\twithHandlerInstantiator((jsonMapper) -> {\n\t\t\tjsonMapper.writeValueAsString(new Group());\n\t\t\tassertThat(CustomTypeIdResolver.autowiredFieldInitialized).isTrue();\n\t\t});\n\t}\n\n\tprivate void withHandlerInstantiator(Consumer<JsonMapper> consumer) {\n\t\tnew ApplicationContextRunner().withBean(Capitalizer.class)\n\t\t\t.run((context) -> consumer.accept(JsonMapper.builder()\n\t\t\t\t.handlerInstantiator(new SpringBeanHandlerInstantiator(context.getBeanFactory()))\n\t\t\t\t.build()));\n\t}\n\n\tstatic class UserDeserializer extends ValueDeserializer<User> {\n\n\t\t@Autowired\n\t\tprivate Capitalizer capitalizer;\n\n\t\t@Override\n\t\tpublic User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {\n\t\t\tJsonNode node = jsonParser.readValueAsTree();\n\t\t\treturn new User(this.capitalizer.capitalize(node.get(\"username\").asString()));\n\t\t}\n\n\t}\n\n\tstatic class UserSerializer extends ValueSerializer<User> {\n\n\t\t@Autowired\n\t\tprivate Capitalizer capitalizer;\n\n\t\t@Override\n\t\tpublic void serialize(User user, JsonGenerator jsonGenerator, SerializationContext serializationContext) {\n\n\t\t\tjsonGenerator.writeStartObject();\n\t\t\tjsonGenerator.writeStringProperty(\"username\", this.capitalizer.capitalize(user.getUsername()));\n\t\t\tjsonGenerator.writeEndObject();\n\t\t}\n\n\t}\n\n\tstatic class UpperCaseKeyDeserializer extends KeyDeserializer {\n\n\t\t@Autowired\n\t\tprivate Capitalizer capitalizer;\n\n\t\t@Override\n\t\tpublic Object deserializeKey(String key, DeserializationContext context) {\n\t\t\treturn this.capitalizer.capitalize(key);\n\t\t}\n\n\t}\n\n\tstatic class CustomTypeResolverBuilder extends StdTypeResolverBuilder {\n\n\t\t@Autowired\n\t\tprivate Capitalizer capitalizer;\n\n\t\tstatic boolean autowiredFieldInitialized;\n\n\t\t@Override\n\t\tpublic TypeSerializer buildTypeSerializer(SerializationContext serializationContext, JavaType baseType,\n\t\t\t\tCollection<NamedType> subtypes) {\n\n\t\t\tautowiredFieldInitialized = (this.capitalizer != null);\n\t\t\treturn super.buildTypeSerializer(serializationContext, baseType, subtypes);\n\t\t}\n\n\t\t@Override\n\t\tpublic TypeDeserializer buildTypeDeserializer(DeserializationContext deserializationContext, JavaType baseType,\n\t\t\t\tCollection<NamedType> subtypes) {\n\n\t\t\treturn super.buildTypeDeserializer(deserializationContext, baseType, subtypes);\n\t\t}\n\n\t}\n\n\tstatic class CustomTypeIdResolver implements TypeIdResolver {\n\n\t\t@Autowired\n\t\tprivate Capitalizer capitalizer;\n\n\t\tstatic boolean autowiredFieldInitialized;\n\n\t\t@Override\n\t\tpublic String idFromValueAndType(DatabindContext ctxt, Object o, Class<?> type) {\n\t\t\treturn type.getClass().getName();\n\t\t}\n\n\t\t@Override\n\t\tpublic JsonTypeInfo.Id getMechanism() {\n\t\t\treturn JsonTypeInfo.Id.CUSTOM;\n\t\t}\n\n\t\t@Override\n\t\tpublic String idFromValue(DatabindContext databindContext, Object value) {\n\t\t\tautowiredFieldInitialized = (this.capitalizer != null);\n\t\t\treturn value.getClass().getName();\n\t\t}\n\n\t\t@Override\n\t\tpublic void init(JavaType type) {\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String idFromBaseType(DatabindContext ctxt) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable JavaType typeFromId(DatabindContext context, String id) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getDescForKnownTypeIds() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@JsonDeserialize(using = UserDeserializer.class)\n\t@JsonSerialize(using = UserSerializer.class)\n\tpublic static class User {\n\n\t\tprivate final String username;\n\n\t\tUser(String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t}\n\n\tpublic static class SecurityRegistry {\n\n\t\t@JsonDeserialize(keyUsing = UpperCaseKeyDeserializer.class)\n\t\tprivate Map<String, String> credentials = new HashMap<>();\n\n\t\tpublic void addCredential(String username, String credential) {\n\t\t\tthis.credentials.put(username, credential);\n\t\t}\n\n\t\tpublic Map<String, String> getCredentials() {\n\t\t\treturn this.credentials;\n\t\t}\n\n\t}\n\n\t@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, property = \"type\")\n\t@JsonTypeResolver(CustomTypeResolverBuilder.class)\n\t@JsonTypeIdResolver(CustomTypeIdResolver.class)\n\tpublic static class Group {\n\n\t\tpublic String getType() {\n\t\t\treturn Group.class.getName();\n\t\t}\n\n\t}\n\n\tstatic class Capitalizer {\n\n\t\tString capitalize(String text) {\n\t\t\treturn text.toUpperCase(Locale.ROOT);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/JacksonAutoConfigureJsonIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Integration tests for {@link AutoConfigureJson @AutoConfigureJson} with Jackson.\n *\n * @author Andy Wilkinson\n */\n@AutoConfigureJson\n@ExtendWith(SpringExtension.class)\nclass JacksonAutoConfigureJsonIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid jsonMapperIsAvailable() {\n\t\tassertThatNoException().isThrownBy(() -> this.context.getBean(JsonMapper.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/JsonTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest;\n\nimport java.util.Date;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleCustomObject;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleJsonObjectWithView;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.boot.test.json.JsonContent;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Eddú Meléndez\n */\n@JsonTest\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestIntegrationTests {\n\n\t@Autowired\n\tprivate JacksonTester<ExampleBasicObject> jacksonBasicJson;\n\n\t@Autowired\n\tprivate JacksonTester<ExampleJsonObjectWithView> jacksonWithViewJson;\n\n\t@Autowired\n\tprivate JacksonTester<ExampleCustomObject> jacksonCustomJson;\n\n\t@Test\n\tvoid jacksonBasic() throws Exception {\n\t\tExampleBasicObject object = new ExampleBasicObject();\n\t\tobject.setValue(\"spring\");\n\t\tassertThat(this.jacksonBasicJson.write(object)).isEqualToJson(\"example.json\");\n\t}\n\n\t@Test\n\tvoid jacksonCustom() throws Exception {\n\t\tExampleCustomObject object = new ExampleCustomObject(\"spring\", new Date(), UUID.randomUUID());\n\t\tassertThat(this.jacksonCustomJson.write(object)).isEqualToJson(\"example.json\");\n\t}\n\n\t@Test\n\tvoid customView() throws Exception {\n\t\tExampleJsonObjectWithView object = new ExampleJsonObjectWithView();\n\t\tobject.setValue(\"spring\");\n\t\tJsonContent<ExampleJsonObjectWithView> content = this.jacksonWithViewJson\n\t\t\t.forView(ExampleJsonObjectWithView.TestView.class)\n\t\t\t.write(object);\n\t\tassertThat(content).doesNotHaveJsonPathValue(\"id\");\n\t\tassertThat(content).isEqualToJson(\"example.json\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/JsonTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Phillip Webb\n */\n@JsonTest\n@AutoConfigureJsonTesters(enabled = false)\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired(required = false)\n\tprivate JacksonTester<ExampleBasicObject> jacksonTester;\n\n\t@Test\n\tvoid jackson() {\n\t\tassertThat(this.jacksonTester).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/SpringBootTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.jackson.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.json.JacksonTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureJsonTesters\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass SpringBootTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired\n\tprivate JacksonTester<ExampleBasicObject> jacksonTester;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.jacksonTester).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/app/ExampleBasicObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest.app;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Example object to read/write as JSON.\n *\n * @author Phillip Webb\n */\npublic class ExampleBasicObject {\n\n\tprivate @Nullable String value;\n\n\tpublic @Nullable String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj != null && obj.getClass() == getClass()) {\n\t\t\treturn Objects.equals(this.value, ((ExampleBasicObject) obj).value);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hashCode(this.value);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/app/ExampleCustomObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest.app;\n\nimport java.util.Date;\nimport java.util.UUID;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Example object to read/write as JSON through {@link ExampleJacksonComponent}.\n *\n * @author Phillip Webb\n * @param value the value\n * @param date a date\n * @param uuid a uuid\n */\npublic record ExampleCustomObject(@Nullable String value, @Nullable Date date, @Nullable UUID uuid) {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/app/ExampleJacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest.app;\n\nimport java.util.Date;\nimport java.util.UUID;\n\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.JsonNode;\nimport tools.jackson.databind.SerializationContext;\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.jackson.ObjectValueDeserializer;\nimport org.springframework.boot.jackson.ObjectValueSerializer;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Example {@link JacksonComponent @JacksonComponent} for use with\n * {@link JsonTest @JsonTest} tests.\n *\n * @author Phillip Webb\n */\n@JacksonComponent\npublic class ExampleJacksonComponent {\n\n\tstatic class Serializer extends ObjectValueSerializer<ExampleCustomObject> {\n\n\t\t@Override\n\t\tprotected void serializeObject(ExampleCustomObject value, JsonGenerator jgen, SerializationContext context) {\n\t\t\tjgen.writeStringProperty(\"value\", value.value());\n\t\t\t@Nullable Date date = value.date();\n\t\t\tif (date != null) {\n\t\t\t\tjgen.writeNumberProperty(\"date\", date.getTime());\n\t\t\t}\n\t\t\t@Nullable UUID uuid = value.uuid();\n\t\t\tif (uuid != null) {\n\t\t\t\tjgen.writeStringProperty(\"uuid\", uuid.toString());\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends ObjectValueDeserializer<ExampleCustomObject> {\n\n\t\t@Override\n\t\tprotected ExampleCustomObject deserializeObject(JsonParser jsonParser, DeserializationContext context,\n\t\t\t\tJsonNode tree) {\n\t\t\tString value = nullSafeValue(tree.get(\"value\"), String.class);\n\t\t\tDate date = nullSafeValue(tree.get(\"date\"), Long.class, Date::new);\n\t\t\tUUID uuid = nullSafeValue(tree.get(\"uuid\"), String.class, UUID::fromString);\n\t\t\treturn new ExampleCustomObject(value, date, uuid);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/app/ExampleJsonApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest.app;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link JsonTest @JsonTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleJsonApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/app/ExampleJsonObjectWithView.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.autoconfigure.jsontest.app;\n\nimport com.fasterxml.jackson.annotation.JsonView;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Example object to read/write as JSON with view\n *\n * @author Madhura Bhave\n */\npublic class ExampleJsonObjectWithView {\n\n\t@JsonView(TestView.class)\n\tprivate @Nullable String value;\n\n\tprivate int id;\n\n\tpublic @Nullable String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\tpublic int getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(int id) {\n\t\tthis.id = id;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tExampleJsonObjectWithView other = (ExampleJsonObjectWithView) obj;\n\t\treturn ObjectUtils.nullSafeEquals(this.value, other.value) && ObjectUtils.nullSafeEquals(this.id, other.id);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value + \" \" + this.id;\n\t}\n\n\tpublic static class TestView {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/app/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.autoconfigure.jsontest.app;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/autoconfigure/jsontest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.autoconfigure.jsontest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/a/RenameMixInClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.scan.a;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson.JacksonMixin;\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\n@JacksonMixin(type = { Name.class, NameAndAge.class })\npublic abstract class RenameMixInClass {\n\n\t@JsonProperty(\"username\")\n\tpublic abstract String getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/a/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.scan.a;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/b/RenameMixInAbstractClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.scan.b;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson.JacksonMixin;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\n@JacksonMixin(type = NameAndAge.class)\npublic abstract class RenameMixInAbstractClass {\n\n\t@JsonProperty(\"username\")\n\tabstract String getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/b/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.scan.b;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/c/RenameMixInInterface.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.scan.c;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson.JacksonMixin;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\n@JacksonMixin(type = NameAndAge.class)\npublic interface RenameMixInInterface {\n\n\t@JsonProperty(\"username\")\n\tString getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/c/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.scan.c;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/d/EmptyMixInClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.scan.d;\n\nimport org.springframework.boot.jackson.JacksonMixin;\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\n@JacksonMixin(type = { Name.class, NameAndAge.class })\npublic class EmptyMixInClass {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/d/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.scan.d;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/e/PrivateMixInClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.scan.e;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jackson.JacksonMixin;\nimport org.springframework.boot.jackson.types.Name;\nimport org.springframework.boot.jackson.types.NameAndAge;\n\n@JacksonMixin(type = { Name.class, NameAndAge.class })\nclass PrivateMixInClass {\n\n\t@JsonProperty(\"username\")\n\t@Nullable String getName() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/e/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.scan.e;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/f/EmptyMixIn.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.scan.f;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson.JacksonMixin;\n\n@JacksonMixin\npublic interface EmptyMixIn {\n\n\t@JsonProperty(\"username\")\n\tString getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/scan/f/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.scan.f;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/types/Name.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.types;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Sample object used for tests.\n *\n * @author Paul Aly\n */\npublic class Name {\n\n\tprotected final @Nullable String name;\n\n\tpublic Name(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/types/NameAndAge.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.types;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Sample object used for tests.\n *\n * @author Phillip Webb\n * @author Paul Aly\n */\npublic final class NameAndAge extends Name {\n\n\tprivate final int age;\n\n\tprivate NameAndAge(@Nullable String name, int age) {\n\t\tsuper(name);\n\t\tthis.age = age;\n\t}\n\n\tpublic int getAge() {\n\t\treturn this.age;\n\t}\n\n\tpublic String asKey() {\n\t\treturn this.name + \" is \" + this.age;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof NameAndAge other) {\n\t\t\tboolean rtn = true;\n\t\t\trtn = rtn && ObjectUtils.nullSafeEquals(this.name, other.name);\n\t\t\trtn = rtn && ObjectUtils.nullSafeEquals(this.age, other.age);\n\t\t\treturn rtn;\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.name);\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.age);\n\t\treturn result;\n\t}\n\n\tpublic static NameAndAge create(@Nullable String name, int age) {\n\t\treturn new NameAndAge(name, age);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/types/NameAndCareer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson.types;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Sample object used for tests.\n *\n * @author Paul Aly\n */\npublic class NameAndCareer extends Name {\n\n\tprivate final @Nullable String career;\n\n\tpublic NameAndCareer(@Nullable String name, @Nullable String career) {\n\t\tsuper(name);\n\t\tthis.career = career;\n\t}\n\n\tpublic @Nullable String getCareer() {\n\t\treturn this.career;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/java/org/springframework/boot/jackson/types/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson.types;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson/src/test/resources/org/springframework/boot/jackson/autoconfigure/jsontest/example.json",
    "content": "{\n   \"value\" : \"spring\"\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Jackson 2 (deprecated in favor of spring-boot-jackson)\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-web\")\n\tapi(\"com.fasterxml.jackson.core:jackson-databind\")\n\tapi(\"com.fasterxml.jackson.datatype:jackson-datatype-jdk8\")\n\tapi(\"com.fasterxml.jackson.datatype:jackson-datatype-jsr310\")\n\tapi(\"com.fasterxml.jackson.module:jackson-module-parameter-names\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson\")) {\n\t\texclude(group: \"tools.jackson.core\", module: \"jackson-databind\")\n\t}\n\toptional(\"com.fasterxml.jackson.dataformat:jackson-dataformat-cbor\")\n\toptional(\"com.fasterxml.jackson.dataformat:jackson-dataformat-xml\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.KeyDeserializer;\n\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link Component @Component} that provides {@link JsonSerializer},\n * {@link JsonDeserializer} or {@link KeyDeserializer} implementations to be registered\n * with Jackson when {@link JsonComponentModule} is in use. Can be used to annotate\n * implementations directly or a class that contains them as inner-classes. For example:\n * <pre class=\"code\">\n * &#064;JsonComponent\n * public class CustomerJsonComponent {\n *\n *     public static class Serializer extends JsonSerializer&lt;Customer&gt; {\n *\n *         // ...\n *\n *     }\n *\n *     public static class Deserializer extends JsonDeserializer&lt;Customer&gt; {\n *\n *         // ...\n *\n *     }\n *\n * }\n *\n * </pre>\n *\n * @see JsonComponentModule\n * @since 4.0.0\n * @author Phillip Webb\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link org.springframework.boot.jackson.JacksonComponent}.\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Component\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic @interface JsonComponent {\n\n\t/**\n\t * The value may indicate a suggestion for a logical component name, to be turned into\n\t * a Spring bean in case of an autodetected component.\n\t * @return the component name\n\t */\n\t@AliasFor(annotation = Component.class)\n\tString value() default \"\";\n\n\t/**\n\t * The types that are handled by the provided serializer/deserializer. This attribute\n\t * is mandatory for a {@link KeyDeserializer}, as the type cannot be inferred. For a\n\t * {@link JsonSerializer} or {@link JsonDeserializer} it can be used to limit handling\n\t * to a subclasses of type inferred from the generic.\n\t * @return the types that should be handled by the component\n\t */\n\tClass<?>[] type() default {};\n\n\t/**\n\t * The scope under which the serializer/deserializer should be registered with the\n\t * module.\n\t * @return the component's handle type\n\t */\n\tScope scope() default Scope.VALUES;\n\n\t/**\n\t * The various scopes under which a serializer/deserializer can be registered.\n\t */\n\tenum Scope {\n\n\t\t/**\n\t\t * A serializer/deserializer for regular value content.\n\t\t * @see JsonSerializer\n\t\t * @see JsonDeserializer\n\t\t */\n\t\tVALUES,\n\n\t\t/**\n\t\t * A serializer/deserializer for keys.\n\t\t * @see JsonSerializer\n\t\t * @see KeyDeserializer\n\t\t */\n\t\tKEYS\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonComponentModule.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.KeyDeserializer;\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.HierarchicalBeanFactory;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Spring Bean and Jackson {@link Module} to register {@link JsonComponent @JsonComponent}\n * annotated beans.\n *\n * @author Phillip Webb\n * @author Paul Aly\n * @since 4.0.0\n * @see JsonComponent\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link org.springframework.boot.jackson.JacksonComponentModule}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class JsonComponentModule extends SimpleModule implements BeanFactoryAware, InitializingBean {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate BeanFactory beanFactory;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tregisterJsonComponents();\n\t}\n\n\tpublic void registerJsonComponents() {\n\t\tBeanFactory beanFactory = this.beanFactory;\n\t\twhile (beanFactory != null) {\n\t\t\tif (beanFactory instanceof ListableBeanFactory listableBeanFactory) {\n\t\t\t\taddJsonBeans(listableBeanFactory);\n\t\t\t}\n\t\t\tbeanFactory = (beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory)\n\t\t\t\t\t? hierarchicalBeanFactory.getParentBeanFactory() : null;\n\t\t}\n\t}\n\n\tprivate void addJsonBeans(ListableBeanFactory beanFactory) {\n\t\tMap<String, Object> beans = beanFactory.getBeansWithAnnotation(JsonComponent.class);\n\t\tfor (Object bean : beans.values()) {\n\t\t\taddJsonBean(bean);\n\t\t}\n\t}\n\n\tprivate void addJsonBean(Object bean) {\n\t\tMergedAnnotation<JsonComponent> annotation = MergedAnnotations\n\t\t\t.from(bean.getClass(), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(JsonComponent.class);\n\t\tClass<?>[] types = annotation.getClassArray(\"type\");\n\t\tJsonComponent.Scope scope = annotation.getEnum(\"scope\", JsonComponent.Scope.class);\n\t\taddJsonBean(bean, types, scope);\n\t}\n\n\tprivate void addJsonBean(Object bean, Class<?>[] types, JsonComponent.Scope scope) {\n\t\tif (bean instanceof JsonSerializer<?> jsonSerializer) {\n\t\t\taddJsonSerializerBean(jsonSerializer, scope, types);\n\t\t}\n\t\telse if (bean instanceof JsonDeserializer<?> jsonDeserializer) {\n\t\t\taddJsonDeserializerBean(jsonDeserializer, types);\n\t\t}\n\t\telse if (bean instanceof KeyDeserializer keyDeserializer) {\n\t\t\taddKeyDeserializerBean(keyDeserializer, types);\n\t\t}\n\t\tfor (Class<?> innerClass : bean.getClass().getDeclaredClasses()) {\n\t\t\tif (isSuitableInnerClass(innerClass)) {\n\t\t\t\tObject innerInstance = BeanUtils.instantiateClass(innerClass);\n\t\t\t\taddJsonBean(innerInstance, types, scope);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static boolean isSuitableInnerClass(Class<?> innerClass) {\n\t\treturn !Modifier.isAbstract(innerClass.getModifiers()) && (JsonSerializer.class.isAssignableFrom(innerClass)\n\t\t\t\t|| JsonDeserializer.class.isAssignableFrom(innerClass)\n\t\t\t\t|| KeyDeserializer.class.isAssignableFrom(innerClass));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> void addJsonSerializerBean(JsonSerializer<T> serializer, JsonComponent.Scope scope, Class<?>[] types) {\n\t\tClass<T> baseType = (Class<T>) ResolvableType.forClass(JsonSerializer.class, serializer.getClass())\n\t\t\t.resolveGeneric();\n\t\tAssert.state(baseType != null, \"'baseType' must not be null\");\n\t\taddBeanToModule(serializer, baseType, types,\n\t\t\t\t(scope == JsonComponent.Scope.VALUES) ? this::addSerializer : this::addKeySerializer);\n\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> void addJsonDeserializerBean(JsonDeserializer<T> deserializer, Class<?>[] types) {\n\t\tClass<T> baseType = (Class<T>) ResolvableType.forClass(JsonDeserializer.class, deserializer.getClass())\n\t\t\t.resolveGeneric();\n\t\tAssert.state(baseType != null, \"'baseType' must not be null\");\n\t\taddBeanToModule(deserializer, baseType, types, this::addDeserializer);\n\t}\n\n\tprivate void addKeyDeserializerBean(KeyDeserializer deserializer, Class<?>[] types) {\n\t\tAssert.notEmpty(types, \"'types' must not be empty\");\n\t\taddBeanToModule(deserializer, Object.class, types, this::addKeyDeserializer);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <E, T> void addBeanToModule(E element, Class<T> baseType, Class<?>[] types,\n\t\t\tBiConsumer<Class<T>, E> consumer) {\n\t\tif (ObjectUtils.isEmpty(types)) {\n\t\t\tconsumer.accept(baseType, element);\n\t\t\treturn;\n\t\t}\n\t\tfor (Class<?> type : types) {\n\t\t\tAssert.isAssignable(baseType, type);\n\t\t\tconsumer.accept((Class<T>) type, element);\n\t\t}\n\t}\n\n\tstatic class JsonComponentBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor {\n\n\t\t@Override\n\t\tpublic @Nullable BeanFactoryInitializationAotContribution processAheadOfTime(\n\t\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\t\tString[] jsonComponents = beanFactory.getBeanNamesForAnnotation(JsonComponent.class);\n\t\t\tMap<Class<?>, List<Class<?>>> innerComponents = new HashMap<>();\n\t\t\tfor (String jsonComponent : jsonComponents) {\n\t\t\t\tClass<?> type = beanFactory.getType(jsonComponent, true);\n\t\t\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\t\t\tfor (Class<?> declaredClass : type.getDeclaredClasses()) {\n\t\t\t\t\tif (isSuitableInnerClass(declaredClass)) {\n\t\t\t\t\t\tinnerComponents.computeIfAbsent(type, (t) -> new ArrayList<>()).add(declaredClass);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn innerComponents.isEmpty() ? null : new JsonComponentAotContribution(innerComponents);\n\t\t}\n\n\t}\n\n\tprivate static final class JsonComponentAotContribution implements BeanFactoryInitializationAotContribution {\n\n\t\tprivate final Map<Class<?>, List<Class<?>>> innerComponents;\n\n\t\tprivate JsonComponentAotContribution(Map<Class<?>, List<Class<?>>> innerComponents) {\n\t\t\tthis.innerComponents = innerComponents;\n\t\t}\n\n\t\t@Override\n\t\tpublic void applyTo(GenerationContext generationContext,\n\t\t\t\tBeanFactoryInitializationCode beanFactoryInitializationCode) {\n\t\t\tReflectionHints reflection = generationContext.getRuntimeHints().reflection();\n\t\t\tthis.innerComponents.forEach((outer, inners) -> {\n\t\t\t\treflection.registerType(outer);\n\t\t\t\tinners.forEach((inner) -> reflection.registerType(inner, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonMixin.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Provides a mixin class implementation that registers with Jackson when using\n * {@link JsonMixinModule}.\n *\n * @author Guirong Hu\n * @see JsonMixinModule\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link org.springframework.boot.jackson.JacksonMixin}.\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic @interface JsonMixin {\n\n\t/**\n\t * Alias for the {@link #type()} attribute. Allows for more concise annotation\n\t * declarations e.g.: {@code @JsonMixin(MyType.class)} instead of\n\t * {@code @JsonMixin(type=MyType.class)}.\n\t * @return the mixed-in classes\n\t */\n\t@AliasFor(\"type\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * The types that are handled by the provided mix-in class. {@link #value()} is an\n\t * alias for (and mutually exclusive with) this attribute.\n\t * @return the mixed-in classes\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] type() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonMixinModule.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Spring Bean and Jackson {@link Module} to find and\n * {@link SimpleModule#setMixInAnnotation(Class, Class) register}\n * {@link JsonMixin @JsonMixin}-annotated classes.\n *\n * @author Guirong Hu\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see JsonMixin\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link org.springframework.boot.jackson.JacksonMixinModule}\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class JsonMixinModule extends SimpleModule {\n\n\t/**\n\t * Register the specified {@link JsonMixinModuleEntries entries}.\n\t * @param entries the entries to register to this instance\n\t * @param classLoader the classloader to use\n\t */\n\tpublic void registerEntries(JsonMixinModuleEntries entries, @Nullable ClassLoader classLoader) {\n\t\tentries.doWithEntry(classLoader, this::setMixInAnnotation);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonMixinModuleEntries.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Provide the mapping of JSON mixin class to consider.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link JsonMixinModuleEntries}\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic final class JsonMixinModuleEntries {\n\n\tprivate final Map<Object, Object> entries;\n\n\tprivate JsonMixinModuleEntries(Builder builder) {\n\t\tthis.entries = new LinkedHashMap<>(builder.entries);\n\t}\n\n\t/**\n\t * Create an instance using the specified {@link Builder}.\n\t * @param mixins a consumer of the builder\n\t * @return an instance with the state of the customized builder.\n\t */\n\tpublic static JsonMixinModuleEntries create(Consumer<Builder> mixins) {\n\t\tBuilder builder = new Builder();\n\t\tmixins.accept(builder);\n\t\treturn builder.build();\n\t}\n\n\t/**\n\t * Scan the classpath for {@link JsonMixin @JsonMixin} in the specified\n\t * {@code basePackages}.\n\t * @param context the application context to use\n\t * @param basePackages the base packages to consider\n\t * @return an instance with the result of the scanning\n\t */\n\tpublic static JsonMixinModuleEntries scan(ApplicationContext context, Collection<String> basePackages) {\n\t\treturn JsonMixinModuleEntries.create((builder) -> {\n\t\t\tif (ObjectUtils.isEmpty(basePackages)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tJsonMixinComponentScanner scanner = new JsonMixinComponentScanner();\n\t\t\tscanner.setEnvironment(context.getEnvironment());\n\t\t\tscanner.setResourceLoader(context);\n\t\t\tfor (String basePackage : basePackages) {\n\t\t\t\tif (StringUtils.hasText(basePackage)) {\n\t\t\t\t\tfor (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {\n\t\t\t\t\t\tString beanClassName = candidate.getBeanClassName();\n\t\t\t\t\t\tAssert.state(beanClassName != null, \"'beanClassName' must not be null\");\n\t\t\t\t\t\tClass<?> mixinClass = ClassUtils.resolveClassName(beanClassName, context.getClassLoader());\n\t\t\t\t\t\tregisterMixinClass(builder, mixinClass);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate static void registerMixinClass(Builder builder, Class<?> mixinClass) {\n\t\tMergedAnnotation<JsonMixin> annotation = MergedAnnotations\n\t\t\t.from(mixinClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(JsonMixin.class);\n\t\tClass<?>[] types = annotation.getClassArray(\"type\");\n\t\tAssert.state(!ObjectUtils.isEmpty(types),\n\t\t\t\t() -> \"@JsonMixin annotation on class '\" + mixinClass.getName() + \"' does not specify any types\");\n\t\tfor (Class<?> type : types) {\n\t\t\tbuilder.and(type, mixinClass);\n\t\t}\n\t}\n\n\t/**\n\t * Perform an action on each entry defined by this instance. If a class needs to be\n\t * resolved from its class name, the specified {@link ClassLoader} is used.\n\t * @param classLoader the classloader to use to resolve class name if necessary\n\t * @param action the action to invoke on each type to mixin class entry\n\t */\n\tpublic void doWithEntry(@Nullable ClassLoader classLoader, BiConsumer<Class<?>, Class<?>> action) {\n\t\tthis.entries.forEach((type, mixin) -> action.accept(resolveClassNameIfNecessary(type, classLoader),\n\t\t\t\tresolveClassNameIfNecessary(mixin, classLoader)));\n\t}\n\n\tprivate Class<?> resolveClassNameIfNecessary(Object nameOrType, @Nullable ClassLoader classLoader) {\n\t\treturn (nameOrType instanceof Class<?> type) ? type\n\t\t\t\t: ClassUtils.resolveClassName((String) nameOrType, classLoader);\n\t}\n\n\t/**\n\t * Builder for {@link JsonMixinModuleEntries}.\n\t */\n\tpublic static class Builder {\n\n\t\tprivate final Map<Object, Object> entries;\n\n\t\tBuilder() {\n\t\t\tthis.entries = new LinkedHashMap<>();\n\t\t}\n\n\t\t/**\n\t\t * Add a mapping for the specified class names.\n\t\t * @param typeClassName the type class name\n\t\t * @param mixinClassName the mixin class name\n\t\t * @return {@code this}, to facilitate method chaining\n\t\t */\n\t\tpublic Builder and(String typeClassName, String mixinClassName) {\n\t\t\tthis.entries.put(typeClassName, mixinClassName);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Add a mapping for the specified classes.\n\t\t * @param type the type class\n\t\t * @param mixinClass the mixin class\n\t\t * @return {@code this}, to facilitate method chaining\n\t\t */\n\t\tpublic Builder and(Class<?> type, Class<?> mixinClass) {\n\t\t\tthis.entries.put(type, mixinClass);\n\t\t\treturn this;\n\t\t}\n\n\t\tJsonMixinModuleEntries build() {\n\t\t\treturn new JsonMixinModuleEntries(this);\n\t\t}\n\n\t}\n\n\tstatic class JsonMixinComponentScanner extends ClassPathScanningCandidateComponentProvider {\n\n\t\tJsonMixinComponentScanner() {\n\t\t\taddIncludeFilter(new AnnotationTypeFilter(JsonMixin.class));\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonMixinModuleEntriesBeanRegistrationAotProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport javax.lang.model.element.Modifier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.generate.AccessControl;\nimport org.springframework.aot.generate.GeneratedMethod;\nimport org.springframework.aot.generate.GenerationContext;\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotContribution;\nimport org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;\nimport org.springframework.beans.factory.aot.BeanRegistrationCode;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragments;\nimport org.springframework.beans.factory.aot.BeanRegistrationCodeFragmentsDecorator;\nimport org.springframework.beans.factory.aot.CodeWarnings;\nimport org.springframework.beans.factory.support.RegisteredBean;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.javapoet.CodeBlock;\n\n/**\n * {@link BeanRegistrationAotProcessor} that replaces any {@link JsonMixinModuleEntries}\n * by a hard-coded equivalent. This has the effect of disabling scanning at runtime.\n *\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass JsonMixinModuleEntriesBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {\n\n\t@Override\n\tpublic @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {\n\t\tif (registeredBean.getBeanClass().equals(JsonMixinModuleEntries.class)) {\n\t\t\treturn BeanRegistrationAotContribution\n\t\t\t\t.withCustomCodeFragments((codeFragments) -> new AotContribution(codeFragments, registeredBean));\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic class AotContribution extends BeanRegistrationCodeFragmentsDecorator {\n\n\t\tprivate static final Class<?> BEAN_TYPE = JsonMixinModuleEntries.class;\n\n\t\tprivate final RegisteredBean registeredBean;\n\n\t\tprivate final @Nullable ClassLoader classLoader;\n\n\t\tAotContribution(BeanRegistrationCodeFragments delegate, RegisteredBean registeredBean) {\n\t\t\tsuper(delegate);\n\t\t\tthis.registeredBean = registeredBean;\n\t\t\tthis.classLoader = registeredBean.getBeanFactory().getBeanClassLoader();\n\t\t}\n\n\t\t@Override\n\t\tpublic ClassName getTarget(RegisteredBean registeredBean) {\n\t\t\treturn ClassName.get(BEAN_TYPE);\n\t\t}\n\n\t\t@Override\n\t\tpublic CodeBlock generateInstanceSupplierCode(GenerationContext generationContext,\n\t\t\t\tBeanRegistrationCode beanRegistrationCode, boolean allowDirectSupplierShortcut) {\n\t\t\tJsonMixinModuleEntries entries = this.registeredBean.getBeanFactory()\n\t\t\t\t.getBean(this.registeredBean.getBeanName(), JsonMixinModuleEntries.class);\n\t\t\tcontributeHints(generationContext.getRuntimeHints(), entries);\n\t\t\tGeneratedMethod generatedMethod = beanRegistrationCode.getMethods().add(\"getInstance\", (method) -> {\n\t\t\t\tmethod.addJavadoc(\"Get the bean instance for '$L'.\", this.registeredBean.getBeanName());\n\t\t\t\tmethod.addModifiers(Modifier.PRIVATE, Modifier.STATIC);\n\t\t\t\tmethod.returns(BEAN_TYPE);\n\t\t\t\tCodeBlock.Builder code = CodeBlock.builder();\n\t\t\t\tCodeWarnings codeWarnings = new CodeWarnings();\n\t\t\t\tcodeWarnings.detectDeprecation(BEAN_TYPE);\n\t\t\t\tcode.add(\"return $T.create(\", BEAN_TYPE).beginControlFlow(\"(mixins) ->\");\n\t\t\t\tentries.doWithEntry(this.classLoader, (type, mixin) -> {\n\t\t\t\t\tcodeWarnings.detectDeprecation(type, mixin);\n\t\t\t\t\taddEntryCode(code, type, mixin);\n\t\t\t\t});\n\t\t\t\tcode.endControlFlow(\")\");\n\t\t\t\tcodeWarnings.suppress(method);\n\t\t\t\tmethod.addCode(code.build());\n\t\t\t});\n\t\t\treturn generatedMethod.toMethodReference().toCodeBlock();\n\t\t}\n\n\t\tprivate void addEntryCode(CodeBlock.Builder code, Class<?> type, Class<?> mixin) {\n\t\t\tAccessControl accessForTypes = AccessControl.lowest(AccessControl.forClass(type),\n\t\t\t\t\tAccessControl.forClass(mixin));\n\t\t\tif (accessForTypes.isPublic()) {\n\t\t\t\tcode.addStatement(\"$L.and($T.class, $T.class)\", \"mixins\", type, mixin);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcode.addStatement(\"$L.and($S, $S)\", \"mixins\", type.getName(), mixin.getName());\n\t\t\t}\n\t\t}\n\n\t\tprivate void contributeHints(RuntimeHints runtimeHints, JsonMixinModuleEntries entries) {\n\t\t\tSet<Class<?>> mixins = new LinkedHashSet<>();\n\t\t\tentries.doWithEntry(this.classLoader, (type, mixin) -> mixins.add(mixin));\n\t\t\tnew BindingReflectionHintsRegistrar().registerReflectionHints(runtimeHints.reflection(),\n\t\t\t\t\tmixins.toArray(Class<?>[]::new));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonObjectDeserializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.IOException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.util.function.Function;\n\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.core.TreeNode;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonDeserializer;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.node.NullNode;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jackson.ObjectValueDeserializer;\nimport org.springframework.util.Assert;\n\n/**\n * Helper base class for {@link JsonDeserializer} implementations that deserialize\n * objects.\n *\n * @param <T> the supported object type\n * @author Phillip Webb\n * @since 4.0.0\n * @see JsonObjectSerializer\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link ObjectValueDeserializer}\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic abstract class JsonObjectDeserializer<T> extends com.fasterxml.jackson.databind.JsonDeserializer<T> {\n\n\t@Override\n\tpublic final T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {\n\t\ttry {\n\t\t\tObjectCodec codec = jp.getCodec();\n\t\t\tJsonNode tree = codec.readTree(jp);\n\t\t\treturn deserializeObject(jp, ctxt, codec, tree);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof IOException ioException) {\n\t\t\t\tthrow ioException;\n\t\t\t}\n\t\t\tthrow new JsonMappingException(jp, \"Object deserialize error\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Deserialize JSON content into the value type this serializer handles.\n\t * @param jsonParser the source parser used for reading JSON content\n\t * @param context context that can be used to access information about this\n\t * deserialization activity\n\t * @param codec the {@link ObjectCodec} associated with the parser\n\t * @param tree deserialized JSON content as tree expressed using set of\n\t * {@link TreeNode} instances\n\t * @return the deserialized object\n\t * @throws IOException on error\n\t * @see #deserialize(JsonParser, DeserializationContext)\n\t */\n\tprotected abstract T deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,\n\t\t\tJsonNode tree) throws IOException;\n\n\t/**\n\t * Helper method to extract a value from the given {@code jsonNode} or return\n\t * {@code null} when the node itself is {@code null}.\n\t * @param jsonNode the source node (may be {@code null})\n\t * @param type the data type. May be {@link String}, {@link Boolean}, {@link Long},\n\t * {@link Integer}, {@link Short}, {@link Double}, {@link Float}, {@link BigDecimal}\n\t * or {@link BigInteger}.\n\t * @param <D> the data type requested\n\t * @param <R> the result type\n\t * @param mapper a mapper to convert the value when it is not {@code null}\n\t * @return the node value or {@code null}\n\t */\n\tprotected final <D, R> @Nullable R nullSafeValue(JsonNode jsonNode, Class<D> type, Function<D, R> mapper) {\n\t\tD value = nullSafeValue(jsonNode, type);\n\t\treturn (value != null) ? mapper.apply(value) : null;\n\t}\n\n\t/**\n\t * Helper method to extract a value from the given {@code jsonNode} or return\n\t * {@code null} when the node itself is {@code null}.\n\t * @param jsonNode the source node (may be {@code null})\n\t * @param type the data type. May be {@link String}, {@link Boolean}, {@link Long},\n\t * {@link Integer}, {@link Short}, {@link Double}, {@link Float}, {@link BigDecimal}\n\t * or {@link BigInteger}.\n\t * @param <D> the data type requested\n\t * @return the node value or {@code null}\n\t */\n\t@SuppressWarnings({ \"unchecked\" })\n\tprotected final <D> @Nullable D nullSafeValue(JsonNode jsonNode, Class<D> type) {\n\t\tAssert.notNull(type, \"'type' must not be null\");\n\t\tif (jsonNode == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (type == String.class) {\n\t\t\treturn (D) jsonNode.textValue();\n\t\t}\n\t\tif (type == Boolean.class) {\n\t\t\treturn (D) Boolean.valueOf(jsonNode.booleanValue());\n\t\t}\n\t\tif (type == Long.class) {\n\t\t\treturn (D) Long.valueOf(jsonNode.longValue());\n\t\t}\n\t\tif (type == Integer.class) {\n\t\t\treturn (D) Integer.valueOf(jsonNode.intValue());\n\t\t}\n\t\tif (type == Short.class) {\n\t\t\treturn (D) Short.valueOf(jsonNode.shortValue());\n\t\t}\n\t\tif (type == Double.class) {\n\t\t\treturn (D) Double.valueOf(jsonNode.doubleValue());\n\t\t}\n\t\tif (type == Float.class) {\n\t\t\treturn (D) Float.valueOf(jsonNode.floatValue());\n\t\t}\n\t\tif (type == BigDecimal.class) {\n\t\t\treturn (D) jsonNode.decimalValue();\n\t\t}\n\t\tif (type == BigInteger.class) {\n\t\t\treturn (D) jsonNode.bigIntegerValue();\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Unsupported value type \" + type.getName());\n\t}\n\n\t/**\n\t * Helper method to return a {@link JsonNode} from the tree.\n\t * @param tree the source tree\n\t * @param fieldName the field name to extract\n\t * @return the {@link JsonNode}\n\t */\n\tprotected final JsonNode getRequiredNode(JsonNode tree, String fieldName) {\n\t\tAssert.notNull(tree, \"'tree' must not be null\");\n\t\tJsonNode node = tree.get(fieldName);\n\t\tAssert.state(node != null && !(node instanceof NullNode), () -> \"Missing JSON field '\" + fieldName + \"'\");\n\t\treturn node;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/JsonObjectSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson.ObjectValueSerializer;\n\n/**\n * Helper base class for {@link JsonSerializer} implementations that serialize objects.\n *\n * @param <T> the supported object type\n * @author Phillip Webb\n * @since 4.0.0\n * @see JsonObjectDeserializer\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3 and\n * {@link ObjectValueSerializer}\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic abstract class JsonObjectSerializer<T> extends JsonSerializer<T> {\n\n\t@Override\n\tpublic final void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException {\n\t\ttry {\n\t\t\tjgen.writeStartObject();\n\t\t\tserializeObject(value, jgen, provider);\n\t\t\tjgen.writeEndObject();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof IOException ioException) {\n\t\t\t\tthrow ioException;\n\t\t\t}\n\t\t\tthrow new JsonMappingException(jgen, \"Object serialize error\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Serialize JSON content into the value type this serializer handles.\n\t * @param value the source value\n\t * @param jgen the JSON generator\n\t * @param provider the serializer provider\n\t * @throws IOException on error\n\t */\n\tprotected abstract void serializeObject(T value, JsonGenerator jgen, SerializerProvider provider)\n\t\t\tthrows IOException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/autoconfigure/Jackson2AutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.autoconfigure;\n\nimport java.lang.reflect.Field;\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TimeZone;\nimport java.util.stream.Stream;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.PropertyNamingStrategies;\nimport com.fasterxml.jackson.databind.PropertyNamingStrategy;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.cfg.ConstructorDetector;\nimport com.fasterxml.jackson.module.paramnames.ParameterNamesModule;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jackson2.JsonComponentModule;\nimport org.springframework.boot.jackson2.JsonMixinModule;\nimport org.springframework.boot.jackson2.JsonMixinModuleEntries;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Auto configuration for Jackson. The following auto-configuration will get applied:\n * <ul>\n * <li>an {@link ObjectMapper} in case none is already configured.</li>\n * <li>a {@link org.springframework.http.converter.json.Jackson2ObjectMapperBuilder} in\n * case none is already configured.</li>\n * <li>auto-registration for all {@link Module} beans with all {@link ObjectMapper} beans\n * (including the defaulted ones).</li>\n * </ul>\n *\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Sebastien Deleuze\n * @author Johannes Edmeier\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Ralf Ueberfuhr\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@AutoConfiguration\n@ConditionalOnClass(ObjectMapper.class)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic final class Jackson2AutoConfiguration {\n\n\tprivate static final Map<?, Boolean> FEATURE_DEFAULTS;\n\n\tstatic {\n\t\tMap<Object, Boolean> featureDefaults = new HashMap<>();\n\t\tfeatureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);\n\t\tfeatureDefaults.put(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);\n\t\tFEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);\n\t}\n\n\t@Bean\n\tJsonComponentModule jackson2JsonComponentModule() {\n\t\treturn new JsonComponentModule();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JacksonMixinConfiguration {\n\n\t\t@Bean\n\t\tstatic JsonMixinModuleEntries jackson2JsonMixinModuleEntries(ApplicationContext context) {\n\t\t\tList<String> packages = AutoConfigurationPackages.has(context) ? AutoConfigurationPackages.get(context)\n\t\t\t\t\t: Collections.emptyList();\n\t\t\treturn JsonMixinModuleEntries.scan(context, packages);\n\t\t}\n\n\t\t@Bean\n\t\tJsonMixinModule jackson2JsonMixinModule(ApplicationContext context, JsonMixinModuleEntries entries) {\n\t\t\tJsonMixinModule jsonMixinModule = new JsonMixinModule();\n\t\t\tjsonMixinModule.registerEntries(entries, context.getClassLoader());\n\t\t\treturn jsonMixinModule;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class)\n\tstatic class JacksonObjectMapperConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\t@ConditionalOnMissingBean\n\t\tObjectMapper jackson2ObjectMapper(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\treturn builder.createXmlMapper(false).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ParameterNamesModule.class)\n\tstatic class ParameterNamesModuleConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tParameterNamesModule jackson2ParameterNamesModule() {\n\t\t\treturn new ParameterNamesModule(JsonCreator.Mode.DEFAULT);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class)\n\tstatic class JacksonObjectMapperBuilderConfiguration {\n\n\t\t@Bean\n\t\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t\t@ConditionalOnMissingBean\n\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(\n\t\t\t\tApplicationContext applicationContext, List<Jackson2ObjectMapperBuilderCustomizer> customizers) {\n\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder = new org.springframework.http.converter.json.Jackson2ObjectMapperBuilder();\n\t\t\tbuilder.applicationContext(applicationContext);\n\t\t\tcustomize(builder, customizers);\n\t\t\treturn builder;\n\t\t}\n\n\t\tprivate void customize(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder,\n\t\t\t\tList<Jackson2ObjectMapperBuilderCustomizer> customizers) {\n\t\t\tfor (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) {\n\t\t\t\tcustomizer.customize(builder);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class)\n\t@EnableConfigurationProperties(Jackson2Properties.class)\n\tstatic class Jackson2ObjectMapperBuilderCustomizerConfiguration {\n\n\t\t@Bean\n\t\tStandardJackson2ObjectMapperBuilderCustomizer standardJackson2ObjectMapperBuilderCustomizer(\n\t\t\t\tJackson2Properties jacksonProperties, ObjectProvider<Module> modules) {\n\t\t\treturn new StandardJackson2ObjectMapperBuilderCustomizer(jacksonProperties, modules.stream().toList());\n\t\t}\n\n\t\tstatic final class StandardJackson2ObjectMapperBuilderCustomizer\n\t\t\t\timplements Jackson2ObjectMapperBuilderCustomizer, Ordered {\n\n\t\t\tprivate final Jackson2Properties jacksonProperties;\n\n\t\t\tprivate final Collection<Module> modules;\n\n\t\t\tStandardJackson2ObjectMapperBuilderCustomizer(Jackson2Properties jacksonProperties,\n\t\t\t\t\tCollection<Module> modules) {\n\t\t\t\tthis.jacksonProperties = jacksonProperties;\n\t\t\t\tthis.modules = modules;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic int getOrder() {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void customize(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\tif (this.jacksonProperties.getDefaultPropertyInclusion() != null) {\n\t\t\t\t\tbuilder.serializationInclusion(this.jacksonProperties.getDefaultPropertyInclusion());\n\t\t\t\t}\n\t\t\t\tif (this.jacksonProperties.getTimeZone() != null) {\n\t\t\t\t\tbuilder.timeZone(this.jacksonProperties.getTimeZone());\n\t\t\t\t}\n\t\t\t\tconfigureFeatures(builder, FEATURE_DEFAULTS);\n\t\t\t\tconfigureVisibility(builder, this.jacksonProperties.getVisibility());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDeserialization());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getSerialization());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getMapper());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getParser());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getGenerator());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDatatype().getEnum());\n\t\t\t\tconfigureFeatures(builder, this.jacksonProperties.getDatatype().getJsonNode());\n\t\t\t\tconfigureDateFormat(builder);\n\t\t\t\tconfigurePropertyNamingStrategy(builder);\n\t\t\t\tconfigureModules(builder);\n\t\t\t\tconfigureLocale(builder);\n\t\t\t\tconfigureDefaultLeniency(builder);\n\t\t\t\tconfigureConstructorDetector(builder);\n\t\t\t}\n\n\t\t\tprivate void configureFeatures(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder,\n\t\t\t\t\tMap<?, Boolean> features) {\n\t\t\t\tfeatures.forEach((feature, value) -> {\n\t\t\t\t\tif (value != null) {\n\t\t\t\t\t\tif (value) {\n\t\t\t\t\t\t\tbuilder.featuresToEnable(feature);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbuilder.featuresToDisable(feature);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tprivate void configureVisibility(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder,\n\t\t\t\t\tMap<PropertyAccessor, JsonAutoDetect.Visibility> visibilities) {\n\t\t\t\tvisibilities.forEach(builder::visibility);\n\t\t\t}\n\n\t\t\tprivate void configureDateFormat(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\t// We support a fully qualified class name extending DateFormat or a date\n\t\t\t\t// pattern string value\n\t\t\t\tString dateFormat = this.jacksonProperties.getDateFormat();\n\t\t\t\tif (dateFormat != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tClass<?> dateFormatClass = ClassUtils.forName(dateFormat, null);\n\t\t\t\t\t\tbuilder.dateFormat((DateFormat) BeanUtils.instantiateClass(dateFormatClass));\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\t\tSimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);\n\t\t\t\t\t\t// Since Jackson 2.6.3 we always need to set a TimeZone (see\n\t\t\t\t\t\t// gh-4170). If none in our properties fallback to the Jackson's\n\t\t\t\t\t\t// default\n\t\t\t\t\t\tTimeZone timeZone = this.jacksonProperties.getTimeZone();\n\t\t\t\t\t\tif (timeZone == null) {\n\t\t\t\t\t\t\ttimeZone = new ObjectMapper().getSerializationConfig().getTimeZone();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsimpleDateFormat.setTimeZone(timeZone);\n\t\t\t\t\t\tbuilder.dateFormat(simpleDateFormat);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate void configurePropertyNamingStrategy(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\t// We support a fully qualified class name extending Jackson's\n\t\t\t\t// PropertyNamingStrategy or a string value corresponding to the constant\n\t\t\t\t// names in PropertyNamingStrategy which hold default provided\n\t\t\t\t// implementations\n\t\t\t\tString strategy = this.jacksonProperties.getPropertyNamingStrategy();\n\t\t\t\tif (strategy != null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconfigurePropertyNamingStrategyClass(builder, ClassUtils.forName(strategy, null));\n\t\t\t\t\t}\n\t\t\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\t\t\tconfigurePropertyNamingStrategyField(builder, strategy);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate void configurePropertyNamingStrategyClass(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder,\n\t\t\t\t\tClass<?> propertyNamingStrategyClass) {\n\t\t\t\tbuilder.propertyNamingStrategy(\n\t\t\t\t\t\t(PropertyNamingStrategy) BeanUtils.instantiateClass(propertyNamingStrategyClass));\n\t\t\t}\n\n\t\t\tprivate void configurePropertyNamingStrategyField(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder, String fieldName) {\n\t\t\t\t// Find the field (this way we automatically support new constants\n\t\t\t\t// that may be added by Jackson in the future)\n\t\t\t\tField field = findPropertyNamingStrategyField(fieldName);\n\t\t\t\tAssert.state(field != null, () -> \"Constant named '\" + fieldName + \"' not found\");\n\t\t\t\ttry {\n\t\t\t\t\tbuilder.propertyNamingStrategy((PropertyNamingStrategy) field.get(null));\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate Field findPropertyNamingStrategyField(String fieldName) {\n\t\t\t\tField field = ReflectionUtils.findField(com.fasterxml.jackson.databind.PropertyNamingStrategies.class,\n\t\t\t\t\t\tfieldName, PropertyNamingStrategy.class);\n\t\t\t\tAssert.state(field != null, () -> \"Constant named '\" + fieldName + \"' not found\");\n\t\t\t\treturn field;\n\t\t\t}\n\n\t\t\tprivate void configureModules(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\tbuilder.modulesToInstall((modules) -> modules.addAll(this.modules));\n\t\t\t}\n\n\t\t\tprivate void configureLocale(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\tLocale locale = this.jacksonProperties.getLocale();\n\t\t\t\tif (locale != null) {\n\t\t\t\t\tbuilder.locale(locale);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate void configureDefaultLeniency(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\tBoolean defaultLeniency = this.jacksonProperties.getDefaultLeniency();\n\t\t\t\tif (defaultLeniency != null) {\n\t\t\t\t\tbuilder.postConfigurer((objectMapper) -> objectMapper.setDefaultLeniency(defaultLeniency));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate void configureConstructorDetector(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\torg.springframework.boot.jackson2.autoconfigure.Jackson2Properties.ConstructorDetectorStrategy strategy = this.jacksonProperties\n\t\t\t\t\t.getConstructorDetector();\n\t\t\t\tbuilder.postConfigurer((objectMapper) -> {\n\t\t\t\t\tswitch (strategy) {\n\t\t\t\t\t\tcase USE_PROPERTIES_BASED ->\n\t\t\t\t\t\t\tobjectMapper.setConstructorDetector(ConstructorDetector.USE_PROPERTIES_BASED);\n\t\t\t\t\t\tcase USE_DELEGATING -> objectMapper.setConstructorDetector(ConstructorDetector.USE_DELEGATING);\n\t\t\t\t\t\tcase EXPLICIT_ONLY -> objectMapper.setConstructorDetector(ConstructorDetector.EXPLICIT_ONLY);\n\t\t\t\t\t\tdefault -> objectMapper.setConstructorDetector(ConstructorDetector.DEFAULT);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class Jackson2AutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tif (ClassUtils.isPresent(\"com.fasterxml.jackson.databind.PropertyNamingStrategy\", classLoader)) {\n\t\t\t\tregisterPropertyNamingStrategyHints(hints.reflection());\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Register hints for the {@code configurePropertyNamingStrategyField} method to\n\t\t * use.\n\t\t * @param hints reflection hints\n\t\t */\n\t\tprivate void registerPropertyNamingStrategyHints(ReflectionHints hints) {\n\t\t\tregisterPropertyNamingStrategyHints(hints, PropertyNamingStrategies.class);\n\t\t}\n\n\t\tprivate void registerPropertyNamingStrategyHints(ReflectionHints hints, Class<?> type) {\n\t\t\tStream.of(type.getDeclaredFields())\n\t\t\t\t.filter(this::isPropertyNamingStrategyField)\n\t\t\t\t.forEach(hints::registerField);\n\t\t}\n\n\t\tprivate boolean isPropertyNamingStrategyField(Field candidate) {\n\t\t\treturn ReflectionUtils.isPublicStaticFinal(candidate)\n\t\t\t\t\t&& candidate.getType().isAssignableFrom(PropertyNamingStrategy.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/autoconfigure/Jackson2BackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.autoconfigure;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport org.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer;\n\n/**\n * {@link BackgroundPreinitializer} for Jackson 2.\n *\n * @author Andy Wilkinson\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nfinal class Jackson2BackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tnew ObjectMapper();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/autoconfigure/Jackson2ObjectMapperBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.autoconfigure;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link ObjectMapper} through\n * {@link org.springframework.http.converter.json.Jackson2ObjectMapperBuilder} to\n * fine-tune its auto-configuration.\n *\n * @author Grzegorz Poznachowski\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@FunctionalInterface\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic interface Jackson2ObjectMapperBuilderCustomizer {\n\n\t/**\n\t * Customize the JacksonObjectMapperBuilder.\n\t * @param jacksonObjectMapperBuilder the JacksonObjectMapperBuilder to customize\n\t */\n\tvoid customize(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/autoconfigure/Jackson2Properties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.autoconfigure;\n\nimport java.util.EnumMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.TimeZone;\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.annotation.PropertyAccessor;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.MapperFeature;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.cfg.EnumFeature;\nimport com.fasterxml.jackson.databind.cfg.JsonNodeFeature;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.DeprecatedConfigurationProperty;\n\n/**\n * Configuration properties to configure Jackson 2.\n *\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Johannes Edmeier\n * @author Eddú Meléndez\n * @since 4.0.0\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@ConfigurationProperties(\"spring.jackson2\")\npublic class Jackson2Properties {\n\n\t/**\n\t * Date format string or a fully-qualified date format class name. For instance,\n\t * 'yyyy-MM-dd HH:mm:ss'.\n\t */\n\tprivate @Nullable String dateFormat;\n\n\t/**\n\t * One of the constants on Jackson's PropertyNamingStrategies. Can also be a\n\t * fully-qualified class name of a PropertyNamingStrategy implementation.\n\t */\n\tprivate @Nullable String propertyNamingStrategy;\n\n\t/**\n\t * Jackson visibility thresholds that can be used to limit which methods (and fields)\n\t * are auto-detected.\n\t */\n\tprivate final Map<PropertyAccessor, JsonAutoDetect.Visibility> visibility = new EnumMap<>(PropertyAccessor.class);\n\n\t/**\n\t * Jackson on/off features that affect the way Java objects are serialized.\n\t */\n\tprivate final Map<SerializationFeature, Boolean> serialization = new EnumMap<>(SerializationFeature.class);\n\n\t/**\n\t * Jackson on/off features that affect the way Java objects are deserialized.\n\t */\n\tprivate final Map<DeserializationFeature, Boolean> deserialization = new EnumMap<>(DeserializationFeature.class);\n\n\t/**\n\t * Jackson general purpose on/off features.\n\t */\n\tprivate final Map<MapperFeature, Boolean> mapper = new EnumMap<>(MapperFeature.class);\n\n\t/**\n\t * Jackson on/off features for parsers.\n\t */\n\tprivate final Map<JsonParser.Feature, Boolean> parser = new EnumMap<>(JsonParser.Feature.class);\n\n\t/**\n\t * Jackson on/off features for generators.\n\t */\n\tprivate final Map<JsonGenerator.Feature, Boolean> generator = new EnumMap<>(JsonGenerator.Feature.class);\n\n\t/**\n\t * Controls the inclusion of properties during serialization. Configured with one of\n\t * the values in Jackson's JsonInclude.Include enumeration.\n\t */\n\tprivate JsonInclude.@Nullable Include defaultPropertyInclusion;\n\n\t/**\n\t * Global default setting (if any) for leniency.\n\t */\n\tprivate @Nullable Boolean defaultLeniency;\n\n\t/**\n\t * Strategy to use to auto-detect constructor, and in particular behavior with\n\t * single-argument constructors.\n\t */\n\tprivate ConstructorDetectorStrategy constructorDetector = ConstructorDetectorStrategy.DEFAULT;\n\n\t/**\n\t * Time zone used when formatting dates. For instance, \"America/Los_Angeles\" or\n\t * \"GMT+10\".\n\t */\n\tprivate @Nullable TimeZone timeZone;\n\n\t/**\n\t * Locale used for formatting.\n\t */\n\tprivate @Nullable Locale locale;\n\n\tprivate final Datatype datatype = new Datatype();\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic @Nullable String getDateFormat() {\n\t\treturn this.dateFormat;\n\t}\n\n\tpublic void setDateFormat(@Nullable String dateFormat) {\n\t\tthis.dateFormat = dateFormat;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic @Nullable String getPropertyNamingStrategy() {\n\t\treturn this.propertyNamingStrategy;\n\t}\n\n\tpublic void setPropertyNamingStrategy(@Nullable String propertyNamingStrategy) {\n\t\tthis.propertyNamingStrategy = propertyNamingStrategy;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic Map<PropertyAccessor, JsonAutoDetect.Visibility> getVisibility() {\n\t\treturn this.visibility;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic Map<SerializationFeature, Boolean> getSerialization() {\n\t\treturn this.serialization;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic Map<DeserializationFeature, Boolean> getDeserialization() {\n\t\treturn this.deserialization;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic Map<MapperFeature, Boolean> getMapper() {\n\t\treturn this.mapper;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic Map<JsonParser.Feature, Boolean> getParser() {\n\t\treturn this.parser;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic Map<JsonGenerator.Feature, Boolean> getGenerator() {\n\t\treturn this.generator;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic JsonInclude.@Nullable Include getDefaultPropertyInclusion() {\n\t\treturn this.defaultPropertyInclusion;\n\t}\n\n\tpublic void setDefaultPropertyInclusion(JsonInclude.@Nullable Include defaultPropertyInclusion) {\n\t\tthis.defaultPropertyInclusion = defaultPropertyInclusion;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic @Nullable Boolean getDefaultLeniency() {\n\t\treturn this.defaultLeniency;\n\t}\n\n\tpublic void setDefaultLeniency(@Nullable Boolean defaultLeniency) {\n\t\tthis.defaultLeniency = defaultLeniency;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic ConstructorDetectorStrategy getConstructorDetector() {\n\t\treturn this.constructorDetector;\n\t}\n\n\tpublic void setConstructorDetector(ConstructorDetectorStrategy constructorDetector) {\n\t\tthis.constructorDetector = constructorDetector;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic @Nullable TimeZone getTimeZone() {\n\t\treturn this.timeZone;\n\t}\n\n\tpublic void setTimeZone(@Nullable TimeZone timeZone) {\n\t\tthis.timeZone = timeZone;\n\t}\n\n\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\tpublic @Nullable Locale getLocale() {\n\t\treturn this.locale;\n\t}\n\n\tpublic void setLocale(@Nullable Locale locale) {\n\t\tthis.locale = locale;\n\t}\n\n\tpublic Datatype getDatatype() {\n\t\treturn this.datatype;\n\t}\n\n\tpublic enum ConstructorDetectorStrategy {\n\n\t\t/**\n\t\t * Use heuristics to see if \"properties\" mode is to be used.\n\t\t */\n\t\tDEFAULT,\n\n\t\t/**\n\t\t * Assume \"properties\" mode if not explicitly annotated otherwise.\n\t\t */\n\t\tUSE_PROPERTIES_BASED,\n\n\t\t/**\n\t\t * Assume \"delegating\" mode if not explicitly annotated otherwise.\n\t\t */\n\t\tUSE_DELEGATING,\n\n\t\t/**\n\t\t * Refuse to decide implicit mode and instead throw an InvalidDefinitionException\n\t\t * for ambiguous cases.\n\t\t */\n\t\tEXPLICIT_ONLY\n\n\t}\n\n\tpublic static class Datatype {\n\n\t\t/**\n\t\t * Jackson on/off features for enums.\n\t\t */\n\t\tprivate final Map<EnumFeature, Boolean> enumFeatures = new EnumMap<>(EnumFeature.class);\n\n\t\t/**\n\t\t * Jackson on/off features for JsonNodes.\n\t\t */\n\t\tprivate final Map<JsonNodeFeature, Boolean> jsonNode = new EnumMap<>(JsonNodeFeature.class);\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\t\tpublic Map<EnumFeature, Boolean> getEnum() {\n\t\t\treturn this.enumFeatures;\n\t\t}\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Deprecated in favor of Jackson 3\", since = \"4.0.0\")\n\t\tpublic Map<JsonNodeFeature, Boolean> getJsonNode() {\n\t\t\treturn this.jsonNode;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/autoconfigure/Jackson2TesterTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.autoconfigure;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.test.autoconfigure.json.ConditionalOnJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonMarshalTesterRuntimeHints;\nimport org.springframework.boot.test.autoconfigure.json.JsonTesterFactoryBean;\nimport org.springframework.boot.test.json.GsonTester;\nimport org.springframework.boot.test.json.Jackson2Tester;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.context.annotation.Scope;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link GsonTester}.\n *\n * @author Phjllip Webb\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@AutoConfiguration(after = Jackson2AutoConfiguration.class)\n@ConditionalOnJsonTesters\n@SuppressWarnings(\"removal\")\nfinal class Jackson2TesterTestAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnBean(ObjectMapper.class)\n\t@ImportRuntimeHints(Jackson2TesterRuntimeHints.class)\n\tFactoryBean<Jackson2Tester<?>> jackson2TesterFactoryBean(ObjectMapper mapper) {\n\t\treturn new JsonTesterFactoryBean<>(Jackson2Tester.class, mapper);\n\t}\n\n\tstatic class Jackson2TesterRuntimeHints extends JsonMarshalTesterRuntimeHints {\n\n\t\tJackson2TesterRuntimeHints() {\n\t\t\tsuper(Jackson2Tester.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jackson 2.\n */\n@org.jspecify.annotations.NullMarked\npackage org.springframework.boot.jackson2.autoconfigure;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/java/org/springframework/boot/jackson2/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom enhancements and support for Jackson 2.\n */\n@org.jspecify.annotations.NullMarked\npackage org.springframework.boot.jackson2;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.jackson2.datatype.enum\",\n      \"description\": \"Jackson on/off features for enums.\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration$Jackson2AutoConfigurationRuntimeHints\n\norg.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\\\norg.springframework.boot.jackson2.JsonComponentModule$JsonComponentBeanFactoryInitializationAotProcessor\n\norg.springframework.beans.factory.aot.BeanRegistrationAotProcessor=\\\norg.springframework.boot.jackson2.JsonMixinModuleEntriesBeanRegistrationAotProcessor\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJson.imports",
    "content": "org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters.imports",
    "content": "org.springframework.boot.jackson2.autoconfigure.Jackson2TesterTestAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.JsonTest.includes",
    "content": "org.springframework.boot.jackson2.JsonComponent\ncom.fasterxml.jackson.databind.Module"
  },
  {
    "path": "module/spring-boot-jackson2/src/main/resources/META-INF/spring.factories",
    "content": "# Background Preinitializers\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer=\\\norg.springframework.boot.jackson2.autoconfigure.Jackson2BackgroundPreinitializer\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/AutoConfigureJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureJson} with Jackson 2.\n *\n * @author Moritz Halbritter\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@AutoConfigureJson\n@ExtendWith(SpringExtension.class)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass AutoConfigureJsonTests {\n\n\t@Autowired\n\tprivate ObjectProvider<ObjectMapper> objectMapper;\n\n\t@Test\n\tvoid shouldAutowireObjectMapper() {\n\t\tassertThat(this.objectMapper.getIfAvailable()).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/JsonComponentModuleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationCode;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndAge;\nimport org.springframework.boot.jackson2.types.NameAndCareer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JsonComponentModule}.\n *\n * @author Phillip Webb\n * @author Vladimir Tsanev\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass JsonComponentModuleTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tgetContext().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterSerializers() throws Exception {\n\t\tload(OnlySerializer.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertSerialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterDeserializers() throws Exception {\n\t\tload(OnlyDeserializer.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterInnerClasses() throws Exception {\n\t\tload(NameAndAgeJsonComponent.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertSerialize(module);\n\t\tassertDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldAllowInnerAbstractClasses() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JsonComponentModule.class,\n\t\t\t\tComponentWithInnerAbstractClass.class);\n\t\tJsonComponentModule module = context.getBean(JsonComponentModule.class);\n\t\tassertSerialize(module);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterKeySerializers() throws Exception {\n\t\tload(OnlyKeySerializer.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertKeySerialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterKeyDeserializers() throws Exception {\n\t\tload(OnlyKeyDeserializer.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertKeyDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterInnerClassesForKeyHandlers() throws Exception {\n\t\tload(NameAndAgeJsonKeyComponent.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertKeySerialize(module);\n\t\tassertKeyDeserialize(module);\n\t}\n\n\t@Test\n\tvoid moduleShouldRegisterOnlyForSpecifiedClasses() throws Exception {\n\t\tload(NameAndCareerJsonComponent.class);\n\t\tJsonComponentModule module = getContext().getBean(JsonComponentModule.class);\n\t\tassertSerialize(module, new NameAndCareer(\"spring\", \"developer\"), \"{\\\"name\\\":\\\"spring\\\"}\");\n\t\tassertSerialize(module);\n\t\tassertDeserializeForSpecifiedClasses(module);\n\t}\n\n\t@Test\n\tvoid aotContributionRegistersReflectionHintsForSuitableInnerClasses() {\n\t\tload(ComponentWithInnerAbstractClass.class);\n\t\tConfigurableListableBeanFactory beanFactory = getContext().getBeanFactory();\n\t\tBeanFactoryInitializationAotContribution contribution = new org.springframework.boot.jackson2.JsonComponentModule.JsonComponentBeanFactoryInitializationAotProcessor()\n\t\t\t.processAheadOfTime(beanFactory);\n\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\tassertThat(contribution).isNotNull();\n\t\tcontribution.applyTo(generationContext, mock(BeanFactoryInitializationCode.class));\n\t\tRuntimeHints runtimeHints = generationContext.getRuntimeHints();\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ComponentWithInnerAbstractClass.class))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(JsonComponentModuleTests.ComponentWithInnerAbstractClass.ConcreteSerializer.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(JsonComponentModuleTests.ComponentWithInnerAbstractClass.AbstractSerializer.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)\n\t\t\t.negate()).accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(JsonComponentModuleTests.ComponentWithInnerAbstractClass.NotSuitable.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)\n\t\t\t.negate()).accepts(runtimeHints);\n\t}\n\n\tprivate void load(Class<?>... configs) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(configs);\n\t\tcontext.register(JsonComponentModule.class);\n\t\tcontext.refresh();\n\t\tthis.context = context;\n\t}\n\n\tprivate void assertSerialize(Module module, Name value, String expectedJson) throws Exception {\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tString json = mapper.writeValueAsString(value);\n\t\tassertThat(json).isEqualToIgnoringWhitespace(expectedJson);\n\t}\n\n\tprivate void assertSerialize(Module module) throws Exception {\n\t\tassertSerialize(module, new NameAndAge(\"spring\", 100), \"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\");\n\t}\n\n\tprivate void assertDeserialize(Module module) throws Exception {\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tNameAndAge nameAndAge = mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\", NameAndAge.class);\n\t\tassertThat(nameAndAge.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nameAndAge.getAge()).isEqualTo(100);\n\t}\n\n\tprivate void assertDeserializeForSpecifiedClasses(JsonComponentModule module) throws IOException {\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tassertThatExceptionOfType(JsonMappingException.class)\n\t\t\t.isThrownBy(() -> mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\", NameAndAge.class));\n\t\tNameAndCareer nameAndCareer = mapper.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"career\\\":\\\"developer\\\"}\",\n\t\t\t\tNameAndCareer.class);\n\t\tassertThat(nameAndCareer.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nameAndCareer.getCareer()).isEqualTo(\"developer\");\n\t}\n\n\tprivate void assertKeySerialize(Module module) throws Exception {\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tMap<NameAndAge, Boolean> map = new HashMap<>();\n\t\tmap.put(new NameAndAge(\"spring\", 100), true);\n\t\tString json = mapper.writeValueAsString(map);\n\t\tassertThat(json).isEqualToIgnoringWhitespace(\"{\\\"spring is 100\\\":  true}\");\n\t}\n\n\tprivate void assertKeyDeserialize(Module module) throws IOException {\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tTypeReference<Map<NameAndAge, Boolean>> typeRef = new TypeReference<>() {\n\t\t};\n\t\tMap<NameAndAge, Boolean> map = mapper.readValue(\"{\\\"spring is 100\\\":  true}\", typeRef);\n\t\tassertThat(map).containsEntry(new NameAndAge(\"spring\", 100), true);\n\t}\n\n\tprivate AnnotationConfigApplicationContext getContext() {\n\t\tAnnotationConfigApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@JsonComponent\n\tstatic class OnlySerializer extends NameAndAgeJsonComponent.Serializer {\n\n\t}\n\n\t@JsonComponent\n\tstatic class OnlyDeserializer extends NameAndAgeJsonComponent.Deserializer {\n\n\t}\n\n\t@JsonComponent\n\tstatic class ComponentWithInnerAbstractClass {\n\n\t\tabstract static class AbstractSerializer extends NameAndAgeJsonComponent.Serializer {\n\n\t\t}\n\n\t\tstatic class ConcreteSerializer extends AbstractSerializer {\n\n\t\t}\n\n\t\tstatic class NotSuitable {\n\n\t\t}\n\n\t}\n\n\t@JsonComponent(scope = JsonComponent.Scope.KEYS)\n\tstatic class OnlyKeySerializer extends NameAndAgeJsonKeyComponent.Serializer {\n\n\t}\n\n\t@JsonComponent(scope = JsonComponent.Scope.KEYS, type = NameAndAge.class)\n\tstatic class OnlyKeyDeserializer extends NameAndAgeJsonKeyComponent.Deserializer {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/JsonMixinModuleEntriesBeanRegistrationAotProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.boot.jackson2.scan.a.RenameMixInClass;\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndAge;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.Compiled;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link JsonMixinModuleEntriesBeanRegistrationAotProcessor}.\n *\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@CompileWithForkedClassLoader\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass JsonMixinModuleEntriesBeanRegistrationAotProcessorTests {\n\n\tprivate final TestGenerationContext generationContext = new TestGenerationContext();\n\n\tprivate final GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\n\t@Test\n\tvoid processAheadOfTimeShouldRegisterBindingHintsForMixins() {\n\t\tregisterEntries(RenameMixInClass.class);\n\t\tprocessAheadOfTime();\n\t\tRuntimeHints runtimeHints = this.generationContext.getRuntimeHints();\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(RenameMixInClass.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWhenPublicClassShouldRegisterClass() {\n\t\tregisterEntries(RenameMixInClass.class);\n\t\tcompile((freshContext, compiled) -> {\n\t\t\tassertThat(freshContext.getBean(TestConfiguration.class).scanningInvoked).isFalse();\n\t\t\tJsonMixinModuleEntries jsonMixinModuleEntries = freshContext.getBean(JsonMixinModuleEntries.class);\n\t\t\tassertThat(jsonMixinModuleEntries).extracting(\"entries\", InstanceOfAssertFactories.MAP)\n\t\t\t\t.containsExactly(entry(Name.class, RenameMixInClass.class),\n\t\t\t\t\t\tentry(NameAndAge.class, RenameMixInClass.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeWhenNonAccessibleClassShouldRegisterClassName() {\n\t\tClass<?> privateMixinClass = ClassUtils\n\t\t\t.resolveClassName(\"org.springframework.boot.jackson2.scan.e.PrivateMixInClass\", null);\n\t\tregisterEntries(privateMixinClass);\n\t\tcompile((freshContext, compiled) -> {\n\t\t\tassertThat(freshContext.getBean(TestConfiguration.class).scanningInvoked).isFalse();\n\t\t\tJsonMixinModuleEntries jsonMixinModuleEntries = freshContext.getBean(JsonMixinModuleEntries.class);\n\t\t\tassertThat(jsonMixinModuleEntries).extracting(\"entries\", InstanceOfAssertFactories.MAP)\n\t\t\t\t.containsExactly(entry(Name.class.getName(), privateMixinClass.getName()),\n\t\t\t\t\t\tentry(NameAndAge.class.getName(), privateMixinClass.getName()));\n\t\t});\n\t}\n\n\tprivate ClassName processAheadOfTime() {\n\t\tClassName className = new ApplicationContextAotGenerator().processAheadOfTime(this.applicationContext,\n\t\t\t\tthis.generationContext);\n\t\tthis.generationContext.writeGeneratedContent();\n\t\treturn className;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void compile(BiConsumer<GenericApplicationContext, Compiled> result) {\n\t\tClassName className = processAheadOfTime();\n\t\tTestCompiler.forSystem()\n\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t.with(this.generationContext)\n\t\t\t.compile((compiled) -> {\n\t\t\t\tGenericApplicationContext freshApplicationContext = new GenericApplicationContext();\n\t\t\t\tApplicationContextInitializer<GenericApplicationContext> initializer = compiled\n\t\t\t\t\t.getInstance(ApplicationContextInitializer.class, className.toString());\n\t\t\t\tinitializer.initialize(freshApplicationContext);\n\t\t\t\tfreshApplicationContext.refresh();\n\t\t\t\tresult.accept(freshApplicationContext, compiled);\n\t\t\t});\n\t}\n\n\tprivate void registerEntries(Class<?>... basePackageClasses) {\n\t\tList<String> packageNames = Arrays.stream(basePackageClasses).map(Class::getPackageName).toList();\n\t\tthis.applicationContext.registerBeanDefinition(\"configuration\",\n\t\t\t\tBeanDefinitionBuilder.rootBeanDefinition(TestConfiguration.class)\n\t\t\t\t\t.addConstructorArgValue(packageNames)\n\t\t\t\t\t.getBeanDefinition());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\tpublic boolean scanningInvoked;\n\n\t\tprivate final Collection<String> packageNames;\n\n\t\tTestConfiguration(Collection<String> packageNames) {\n\t\t\tthis.packageNames = packageNames;\n\t\t}\n\n\t\t@Bean\n\t\tJsonMixinModuleEntries jsonMixinModuleEntries(ApplicationContext applicationContext) {\n\t\t\tthis.scanningInvoked = true;\n\t\t\treturn JsonMixinModuleEntries.scan(applicationContext, this.packageNames);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/JsonMixinModuleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.jackson2.scan.a.RenameMixInClass;\nimport org.springframework.boot.jackson2.scan.b.RenameMixInAbstractClass;\nimport org.springframework.boot.jackson2.scan.c.RenameMixInInterface;\nimport org.springframework.boot.jackson2.scan.d.EmptyMixInClass;\nimport org.springframework.boot.jackson2.scan.f.EmptyMixIn;\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndAge;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link JsonMixinModule}.\n *\n * @author Guirong Hu\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass JsonMixinModuleTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tgetContext().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid jsonWithModuleEmptyMixInWithEmptyTypesShouldFail() {\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> load(EmptyMixIn.class))\n\t\t\t.withMessageContaining(\"Error creating bean with name 'jsonMixinModule'\")\n\t\t\t.withStackTraceContaining(\"@JsonMixin annotation on class \"\n\t\t\t\t\t+ \"'org.springframework.boot.jackson2.scan.f.EmptyMixIn' does not specify any types\");\n\t}\n\n\t@Test\n\tvoid jsonWithModuleWithRenameMixInClassShouldBeMixedIn() throws Exception {\n\t\tload(RenameMixInClass.class);\n\t\tJsonMixinModule module = getContext().getBean(JsonMixinModule.class);\n\t\tassertMixIn(module, new Name(\"spring\"), \"{\\\"username\\\":\\\"spring\\\"}\");\n\t\tassertMixIn(module, new NameAndAge(\"spring\", 100), \"{\\\"age\\\":100,\\\"username\\\":\\\"spring\\\"}\");\n\t}\n\n\t@Test\n\tvoid jsonWithModuleWithEmptyMixInClassShouldNotBeMixedIn() throws Exception {\n\t\tload(EmptyMixInClass.class);\n\t\tJsonMixinModule module = getContext().getBean(JsonMixinModule.class);\n\t\tassertMixIn(module, new Name(\"spring\"), \"{\\\"name\\\":\\\"spring\\\"}\");\n\t\tassertMixIn(module, new NameAndAge(\"spring\", 100), \"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\");\n\t}\n\n\t@Test\n\tvoid jsonWithModuleWithRenameMixInAbstractClassShouldBeMixedIn() throws Exception {\n\t\tload(RenameMixInAbstractClass.class);\n\t\tJsonMixinModule module = getContext().getBean(JsonMixinModule.class);\n\t\tassertMixIn(module, new NameAndAge(\"spring\", 100), \"{\\\"age\\\":100,\\\"username\\\":\\\"spring\\\"}\");\n\t}\n\n\t@Test\n\tvoid jsonWithModuleWithRenameMixInInterfaceShouldBeMixedIn() throws Exception {\n\t\tload(RenameMixInInterface.class);\n\t\tJsonMixinModule module = getContext().getBean(JsonMixinModule.class);\n\t\tassertMixIn(module, new NameAndAge(\"spring\", 100), \"{\\\"age\\\":100,\\\"username\\\":\\\"spring\\\"}\");\n\t}\n\n\tprivate void load(Class<?>... basePackageClasses) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.registerBean(JsonMixinModule.class, () -> createJsonMixinModule(context, basePackageClasses));\n\t\tcontext.refresh();\n\t\tthis.context = context;\n\t}\n\n\tprivate JsonMixinModule createJsonMixinModule(AnnotationConfigApplicationContext context,\n\t\t\tClass<?>... basePackageClasses) {\n\t\tList<String> basePackages = Arrays.stream(basePackageClasses).map(ClassUtils::getPackageName).toList();\n\t\tJsonMixinModuleEntries entries = JsonMixinModuleEntries.scan(context, basePackages);\n\t\tJsonMixinModule jsonMixinModule = new JsonMixinModule();\n\t\tjsonMixinModule.registerEntries(entries, context.getClassLoader());\n\t\treturn jsonMixinModule;\n\t}\n\n\tprivate void assertMixIn(Module module, Name value, String expectedJson) throws Exception {\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tString json = mapper.writeValueAsString(value);\n\t\tassertThat(json).isEqualToIgnoringWhitespace(expectedJson);\n\t}\n\n\tprivate AnnotationConfigApplicationContext getContext() {\n\t\tAnnotationConfigApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/JsonObjectDeserializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.InputStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.time.LocalDate;\nimport java.util.function.Function;\n\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport com.fasterxml.jackson.databind.node.NullNode;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JsonObjectDeserializer}.\n *\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass JsonObjectDeserializerTests {\n\n\tprivate final TestJsonObjectDeserializer<Object> testDeserializer = new TestJsonObjectDeserializer<>();\n\n\t@Test\n\tvoid deserializeObjectShouldReadJson() throws Exception {\n\t\tNameAndAgeJsonComponent.Deserializer deserializer = new NameAndAgeJsonComponent.Deserializer();\n\t\tSimpleModule module = new SimpleModule();\n\t\tmodule.addDeserializer(org.springframework.boot.jackson2.types.NameAndAge.class, deserializer);\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\torg.springframework.boot.jackson2.types.NameAndAge nameAndAge = mapper\n\t\t\t.readValue(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\", org.springframework.boot.jackson2.types.NameAndAge.class);\n\t\tassertThat(nameAndAge.getName()).isEqualTo(\"spring\");\n\t\tassertThat(nameAndAge.getAge()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenValueIsNullShouldReturnNull() {\n\t\tString value = this.testDeserializer.testNullSafeValue(null, String.class);\n\t\tassertThat(value).isNull();\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.testDeserializer.testNullSafeValue(mock(JsonNode.class), null))\n\t\t\t.withMessageContaining(\"'type' must not be null\");\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsStringShouldReturnString() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.textValue()).willReturn(\"abc\");\n\t\tString value = this.testDeserializer.testNullSafeValue(node, String.class);\n\t\tassertThat(value).isEqualTo(\"abc\");\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsBooleanShouldReturnBoolean() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.booleanValue()).willReturn(true);\n\t\tBoolean value = this.testDeserializer.testNullSafeValue(node, Boolean.class);\n\t\tassertThat(value).isTrue();\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsLongShouldReturnLong() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.longValue()).willReturn(10L);\n\t\tLong value = this.testDeserializer.testNullSafeValue(node, Long.class);\n\t\tassertThat(value).isEqualTo(10L);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsIntegerShouldReturnInteger() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.intValue()).willReturn(10);\n\t\tInteger value = this.testDeserializer.testNullSafeValue(node, Integer.class);\n\t\tassertThat(value).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsShortShouldReturnShort() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.shortValue()).willReturn((short) 10);\n\t\tShort value = this.testDeserializer.testNullSafeValue(node, Short.class);\n\t\tassertThat(value).isEqualTo((short) 10);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsDoubleShouldReturnDouble() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.doubleValue()).willReturn(1.1D);\n\t\tDouble value = this.testDeserializer.testNullSafeValue(node, Double.class);\n\t\tassertThat(value).isEqualTo(1.1D);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsFloatShouldReturnFloat() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.floatValue()).willReturn(1.1F);\n\t\tFloat value = this.testDeserializer.testNullSafeValue(node, Float.class);\n\t\tassertThat(value).isEqualTo(1.1F);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsBigDecimalShouldReturnBigDecimal() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.decimalValue()).willReturn(BigDecimal.TEN);\n\t\tBigDecimal value = this.testDeserializer.testNullSafeValue(node, BigDecimal.class);\n\t\tassertThat(value).isEqualTo(BigDecimal.TEN);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsBigIntegerShouldReturnBigInteger() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.bigIntegerValue()).willReturn(BigInteger.TEN);\n\t\tBigInteger value = this.testDeserializer.testNullSafeValue(node, BigInteger.class);\n\t\tassertThat(value).isEqualTo(BigInteger.TEN);\n\t}\n\n\t@Test\n\tvoid nullSafeValueWithMapperShouldTransformValue() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.textValue()).willReturn(\"2023-12-01\");\n\t\tLocalDate result = this.testDeserializer.testNullSafeValue(node, String.class, LocalDate::parse);\n\t\tassertThat(result).isEqualTo(LocalDate.of(2023, 12, 1));\n\t}\n\n\t@Test\n\tvoid nullSafeValueWhenClassIsUnknownShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.testDeserializer.testNullSafeValue(mock(JsonNode.class), InputStream.class))\n\t\t\t.withMessageContaining(\"Unsupported value type java.io.InputStream\");\n\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenTreeIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.testDeserializer.testGetRequiredNode(null, \"test\"))\n\t\t\t.withMessageContaining(\"'tree' must not be null\");\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenNodeIsNullShouldThrowException() {\n\t\tJsonNode tree = mock(JsonNode.class);\n\t\tgiven(tree.get(\"test\")).willReturn(null);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.testDeserializer.testGetRequiredNode(tree, \"test\"))\n\t\t\t.withMessageContaining(\"Missing JSON field 'test'\");\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenNodeIsNullNodeShouldThrowException() {\n\t\tJsonNode tree = mock(JsonNode.class);\n\t\tgiven(tree.get(\"test\")).willReturn(NullNode.instance);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.testDeserializer.testGetRequiredNode(tree, \"test\"))\n\t\t\t.withMessageContaining(\"Missing JSON field 'test'\");\n\t}\n\n\t@Test\n\tvoid getRequiredNodeWhenNodeIsFoundShouldReturnNode() {\n\t\tJsonNode node = mock(JsonNode.class);\n\t\tgiven(node.get(\"test\")).willReturn(node);\n\t\tassertThat(this.testDeserializer.testGetRequiredNode(node, \"test\")).isEqualTo(node);\n\t}\n\n\tstatic class TestJsonObjectDeserializer<T> extends JsonObjectDeserializer<T> {\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprotected T deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,\n\t\t\t\tJsonNode tree) {\n\t\t\treturn (T) new Object();\n\t\t}\n\n\t\t<D, R> @Nullable R testNullSafeValue(JsonNode jsonNode, Class<D> type, Function<D, R> mapper) {\n\t\t\treturn nullSafeValue(jsonNode, type, mapper);\n\t\t}\n\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\t<D> D testNullSafeValue(@Nullable JsonNode jsonNode, @Nullable Class<D> type) {\n\t\t\treturn nullSafeValue(jsonNode, type);\n\t\t}\n\n\t\t@SuppressWarnings(\"NullAway\") // Test null check\n\t\tJsonNode testGetRequiredNode(@Nullable JsonNode tree, String fieldName) {\n\t\t\treturn getRequiredNode(tree, fieldName);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/JsonObjectSerializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonObjectSerializer}.\n *\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass JsonObjectSerializerTests {\n\n\t@Test\n\tvoid serializeObjectShouldWriteJson() throws Exception {\n\t\torg.springframework.boot.jackson2.NameAndAgeJsonComponent.Serializer serializer = new org.springframework.boot.jackson2.NameAndAgeJsonComponent.Serializer();\n\t\tSimpleModule module = new SimpleModule();\n\t\tmodule.addSerializer(org.springframework.boot.jackson2.types.NameAndAge.class, serializer);\n\t\tObjectMapper mapper = new ObjectMapper();\n\t\tmapper.registerModule(module);\n\t\tString json = mapper.writeValueAsString(new org.springframework.boot.jackson2.types.NameAndAge(\"spring\", 100));\n\t\tassertThat(json).isEqualToIgnoringWhitespace(\"{\\\"name\\\":\\\"spring\\\",\\\"age\\\":100}\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/NameAndAgeJsonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Sample {@link JsonComponent @JsonComponent} used for tests.\n *\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\n@JsonComponent\npublic class NameAndAgeJsonComponent {\n\n\tstatic class Serializer extends JsonObjectSerializer<NameAndAge> {\n\n\t\t@Override\n\t\tprotected void serializeObject(NameAndAge value, JsonGenerator jgen, SerializerProvider provider)\n\t\t\t\tthrows IOException {\n\t\t\tjgen.writeStringField(\"name\", value.getName());\n\t\t\tjgen.writeNumberField(\"age\", value.getAge());\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends JsonObjectDeserializer<NameAndAge> {\n\n\t\t@Override\n\t\tprotected NameAndAge deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,\n\t\t\t\tJsonNode tree) throws IOException {\n\t\t\tString name = nullSafeValue(tree.get(\"name\"), String.class);\n\t\t\tInteger age = nullSafeValue(tree.get(\"age\"), Integer.class);\n\t\t\tassertThat(age).isNotNull();\n\t\t\treturn new NameAndAge(name, age);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/NameAndAgeJsonKeyComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.KeyDeserializer;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\n/**\n * Sample {@link JsonComponent @JsonComponent} used for tests.\n *\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\n@JsonComponent(type = NameAndAge.class, scope = JsonComponent.Scope.KEYS)\npublic class NameAndAgeJsonKeyComponent {\n\n\tstatic class Serializer extends JsonSerializer<NameAndAge> {\n\n\t\t@Override\n\t\tpublic void serialize(NameAndAge value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {\n\t\t\tjgen.writeFieldName(value.asKey());\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends KeyDeserializer {\n\n\t\t@Override\n\t\tpublic NameAndAge deserializeKey(String key, DeserializationContext ctxt) throws IOException {\n\t\t\tString[] keys = key.split(\"is\");\n\t\t\treturn new NameAndAge(keys[0].trim(), Integer.parseInt(keys[1].trim()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/NameAndCareerJsonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.databind.DeserializationContext;\nimport com.fasterxml.jackson.databind.JsonNode;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndCareer;\n\n/**\n * Sample {@link JsonComponent @JsonComponent} used for tests.\n *\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\n@JsonComponent(type = NameAndCareer.class)\npublic class NameAndCareerJsonComponent {\n\n\tstatic class Serializer extends JsonObjectSerializer<Name> {\n\n\t\t@Override\n\t\tprotected void serializeObject(Name value, JsonGenerator jgen, SerializerProvider provider) throws IOException {\n\t\t\tjgen.writeStringField(\"name\", value.getName());\n\t\t}\n\n\t}\n\n\tstatic class Deserializer extends JsonObjectDeserializer<Name> {\n\n\t\t@Override\n\t\tprotected Name deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,\n\t\t\t\tJsonNode tree) throws IOException {\n\t\t\tString name = nullSafeValue(tree.get(\"name\"), String.class);\n\t\t\tString career = nullSafeValue(tree.get(\"career\"), String.class);\n\t\t\treturn new NameAndCareer(name, career);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/autoconfigure/Jackson2AutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.autoconfigure;\n\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.time.Duration;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonCreator.Mode;\nimport com.fasterxml.jackson.annotation.JsonFormat;\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.JsonParser;\nimport com.fasterxml.jackson.core.ObjectCodec;\nimport com.fasterxml.jackson.databind.AnnotationIntrospector;\nimport com.fasterxml.jackson.databind.DeserializationConfig;\nimport com.fasterxml.jackson.databind.DeserializationFeature;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.MapperFeature;\nimport com.fasterxml.jackson.databind.Module;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.PropertyNamingStrategies;\nimport com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;\nimport com.fasterxml.jackson.databind.SerializationFeature;\nimport com.fasterxml.jackson.databind.SerializerProvider;\nimport com.fasterxml.jackson.databind.cfg.ConstructorDetector;\nimport com.fasterxml.jackson.databind.cfg.ConstructorDetector.SingleArgConstructor;\nimport com.fasterxml.jackson.databind.cfg.EnumFeature;\nimport com.fasterxml.jackson.databind.cfg.JsonNodeFeature;\nimport com.fasterxml.jackson.databind.exc.InvalidFormatException;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;\nimport com.fasterxml.jackson.databind.util.StdDateFormat;\nimport com.fasterxml.jackson.module.paramnames.ParameterNamesModule;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.BeanCurrentlyInCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jackson2.JsonComponent;\nimport org.springframework.boot.jackson2.JsonMixin;\nimport org.springframework.boot.jackson2.JsonMixinModule;\nimport org.springframework.boot.jackson2.JsonMixinModuleEntries;\nimport org.springframework.boot.jackson2.JsonObjectSerializer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Jackson2AutoConfiguration}.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @author Marcel Overdijk\n * @author Sebastien Deleuze\n * @author Johannes Edmeier\n * @author Grzegorz Poznachowski\n * @author Ralf Ueberfuhr\n * @author Eddú Meléndez\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass Jackson2AutoConfigurationTests {\n\n\tprotected final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(Jackson2AutoConfiguration.class));\n\n\t// TODO reinstate\n\t// @Test\n\t// void doubleModuleRegistration() {\n\t// this.contextRunner.withUserConfiguration(DoubleModulesConfig.class)\n\t// .withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t// .run((context) -> {\n\t// ObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t// assertThat(mapper.writeValueAsString(new Foo())).isEqualTo(\"{\\\"foo\\\":\\\"bar\\\"}\");\n\t// });\n\t// }\n\n\t@Test\n\tvoid jsonMixinModuleShouldBeAutoConfiguredWithBasePackages() {\n\t\tthis.contextRunner.withUserConfiguration(MixinConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JsonMixinModule.class).hasSingleBean(JsonMixinModuleEntries.class);\n\t\t\tJsonMixinModuleEntries moduleEntries = context.getBean(JsonMixinModuleEntries.class);\n\t\t\tassertThat(moduleEntries).extracting(\"entries\", InstanceOfAssertFactories.MAP)\n\t\t\t\t.contains(entry(Person.class, EmptyMixin.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid noCustomDateFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(mapper.getDateFormat()).isInstanceOf(StdDateFormat.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.date-format:yyyyMMddHHmmss\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tDateFormat dateFormat = mapper.getDateFormat();\n\t\t\tassertThat(dateFormat).isInstanceOf(SimpleDateFormat.class);\n\t\t\tassertThat(((SimpleDateFormat) dateFormat).toPattern()).isEqualTo(\"yyyyMMddHHmmss\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateFormatClass() {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.jackson2.date-format:org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfigurationTests.MyDateFormat\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(mapper.getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid noCustomPropertyNamingStrategy() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(mapper.getPropertyNamingStrategy()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPropertyNamingStrategyField() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.property-naming-strategy:SNAKE_CASE\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(mapper.getPropertyNamingStrategy()).isInstanceOf(SnakeCaseStrategy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPropertyNamingStrategyClass() {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.jackson2.property-naming-strategy:com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(mapper.getPropertyNamingStrategy()).isInstanceOf(SnakeCaseStrategy.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableSerializationFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.serialization.indent_output:true\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(SerializationFeature.INDENT_OUTPUT.enabledByDefault()).isFalse();\n\t\t\tassertThat(mapper.getSerializationConfig()\n\t\t\t\t.hasSerializationFeatures(SerializationFeature.INDENT_OUTPUT.getMask())).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid disableSerializationFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.serialization.write_dates_as_timestamps:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.enabledByDefault()).isTrue();\n\t\t\t\tassertThat(mapper.getSerializationConfig()\n\t\t\t\t\t.hasSerializationFeatures(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS.getMask())).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableDeserializationFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.deserialization.use_big_decimal_for_floats:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.getDeserializationConfig()\n\t\t\t\t\t.hasDeserializationFeatures(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS.getMask())).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid disableDeserializationFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.deserialization.fail-on-unknown-properties:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.enabledByDefault()).isTrue();\n\t\t\t\tassertThat(mapper.getDeserializationConfig()\n\t\t\t\t\t.hasDeserializationFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.getMask())).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableMapperFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.mapper.require_setters_for_getters:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS.enabledByDefault()).isFalse();\n\n\t\t\t\tassertThat(mapper.getSerializationConfig().isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS))\n\t\t\t\t\t.isTrue();\n\t\t\t\tassertThat(mapper.getDeserializationConfig().isEnabled(MapperFeature.REQUIRE_SETTERS_FOR_GETTERS))\n\t\t\t\t\t.isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid disableMapperFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.mapper.use_annotations:false\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(MapperFeature.USE_ANNOTATIONS.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.getDeserializationConfig().isEnabled(MapperFeature.USE_ANNOTATIONS)).isFalse();\n\t\t\tassertThat(mapper.getSerializationConfig().isEnabled(MapperFeature.USE_ANNOTATIONS)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableParserFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.parser.allow_single_quotes:true\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(JsonParser.Feature.ALLOW_SINGLE_QUOTES.enabledByDefault()).isFalse();\n\t\t\tassertThat(mapper.getFactory().isEnabled(JsonParser.Feature.ALLOW_SINGLE_QUOTES)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid disableParserFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.parser.auto_close_source:false\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(JsonParser.Feature.AUTO_CLOSE_SOURCE.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.getFactory().isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableGeneratorFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.generator.strict_duplicate_detection:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tJsonGenerator.Feature feature = JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION;\n\t\t\t\tassertThat(feature.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.getFactory().isEnabled(feature)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid disableGeneratorFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.generator.auto_close_target:false\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(JsonGenerator.Feature.AUTO_CLOSE_TARGET.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.getFactory().isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultObjectMapperBuilder() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJackson2ObjectMapperBuilder builder = context.getBean(Jackson2ObjectMapperBuilder.class);\n\t\t\tObjectMapper mapper = builder.build();\n\t\t\tassertThat(MapperFeature.DEFAULT_VIEW_INCLUSION.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();\n\t\t\tassertThat(MapperFeature.DEFAULT_VIEW_INCLUSION.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.getDeserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();\n\t\t\tassertThat(mapper.getSerializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();\n\t\t\tassertThat(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES.enabledByDefault()).isTrue();\n\t\t\tassertThat(mapper.getDeserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES))\n\t\t\t\t.isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableEnumFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.datatype.enum.write-enums-to-lowercase=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(EnumFeature.WRITE_ENUMS_TO_LOWERCASE.enabledByDefault()).isFalse();\n\t\t\t\tassertThat(mapper.getSerializationConfig().isEnabled(EnumFeature.WRITE_ENUMS_TO_LOWERCASE)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid disableJsonNodeFeature() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.datatype.json-node.write-null-properties:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(JsonNodeFeature.WRITE_NULL_PROPERTIES.enabledByDefault()).isTrue();\n\t\t\t\tassertThat(mapper.getDeserializationConfig().isEnabled(JsonNodeFeature.WRITE_NULL_PROPERTIES))\n\t\t\t\t\t.isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid moduleBeansAndWellKnownModulesAreRegisteredWithTheObjectMapperBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(ModuleConfig.class).run((context) -> {\n\t\t\tObjectMapper objectMapper = context.getBean(Jackson2ObjectMapperBuilder.class).build();\n\t\t\tassertThat(context.getBean(CustomModule.class).getOwners()).contains(objectMapper);\n\t\t\tassertThat(((DefaultSerializerProvider) objectMapper.getSerializerProviderInstance())\n\t\t\t\t.hasSerializerFor(Baz.class, null)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customModulesRegisteredByBuilderCustomizerShouldBeRetained() {\n\t\tthis.contextRunner.withUserConfiguration(ModuleConfig.class, CustomModuleBuilderCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper objectMapper = context.getBean(Jackson2ObjectMapperBuilder.class).build();\n\t\t\t\tassertThat(context.getBean(CustomModule.class).getOwners()).contains(objectMapper);\n\t\t\t\tassertThat(objectMapper.getRegisteredModuleIds()).contains(\"module-A\", \"module-B\",\n\t\t\t\t\t\tCustomModule.class.getName());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultSerializationInclusion() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper objectMapper = context.getBean(Jackson2ObjectMapperBuilder.class).build();\n\t\t\tassertThat(objectMapper.getSerializationConfig().getDefaultPropertyInclusion().getValueInclusion())\n\t\t\t\t.isEqualTo(JsonInclude.Include.USE_DEFAULTS);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customSerializationInclusion() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.default-property-inclusion:non_null\").run((context) -> {\n\t\t\tObjectMapper objectMapper = context.getBean(Jackson2ObjectMapperBuilder.class).build();\n\t\t\tassertThat(objectMapper.getSerializationConfig().getDefaultPropertyInclusion().getValueInclusion())\n\t\t\t\t.isEqualTo(JsonInclude.Include.NON_NULL);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeZoneFormattingADate() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.time-zone:GMT+10\", \"spring.jackson2.date-format:z\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper objectMapper = context.getBean(Jackson2ObjectMapperBuilder.class).build();\n\t\t\t\tDate date = new Date(1436966242231L);\n\t\t\t\tassertThat(objectMapper.writeValueAsString(date)).isEqualTo(\"\\\"GMT+10:00\\\"\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableDefaultLeniency() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.default-leniency:true\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tPerson person = mapper.readValue(\"{\\\"birthDate\\\": \\\"2010-12-30\\\"}\", Person.class);\n\t\t\tassertThat(person.getBirthDate()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid disableDefaultLeniency() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.default-leniency:false\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThatExceptionOfType(InvalidFormatException.class)\n\t\t\t\t.isThrownBy(() -> mapper.readValue(\"{\\\"birthDate\\\": \\\"2010-12-30\\\"}\", Person.class))\n\t\t\t\t.withMessageContaining(\"expected format\")\n\t\t\t\t.withMessageContaining(\"yyyyMMdd\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorDetectorWithNoStrategyUseDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tConstructorDetector cd = mapper.getDeserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.HEURISTIC);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorDetectorWithDefaultStrategy() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.constructor-detector=default\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tConstructorDetector cd = mapper.getDeserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.HEURISTIC);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorDetectorWithUsePropertiesBasedStrategy() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.constructor-detector=use-properties-based\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tConstructorDetector cd = mapper.getDeserializationConfig().getConstructorDetector();\n\t\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.PROPERTIES);\n\t\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid constructorDetectorWithUseDelegatingStrategy() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.constructor-detector=use-delegating\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tConstructorDetector cd = mapper.getDeserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.DELEGATING);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid constructorDetectorWithExplicitOnlyStrategy() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jackson2.constructor-detector=explicit-only\").run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tConstructorDetector cd = mapper.getDeserializationConfig().getConstructorDetector();\n\t\t\tassertThat(cd.singleArgMode()).isEqualTo(SingleArgConstructor.REQUIRE_MODE);\n\t\t\tassertThat(cd.requireCtorAnnotation()).isFalse();\n\t\t\tassertThat(cd.allowJDKTypeConstructors()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid additionalJacksonBuilderCustomization() {\n\t\tthis.contextRunner.withUserConfiguration(ObjectMapperBuilderCustomConfig.class).run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tassertThat(mapper.getDateFormat()).isInstanceOf(MyDateFormat.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid parameterNamesModuleIsAutoConfigured() {\n\t\tassertParameterNamesModuleCreatorBinding(Mode.DEFAULT, Jackson2AutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid customParameterNamesModuleCanBeConfigured() {\n\t\tassertParameterNamesModuleCreatorBinding(Mode.DELEGATING, ParameterNamesModuleConfig.class,\n\t\t\t\tJackson2AutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid writeDurationAsTimestampsDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\tDuration duration = Duration.ofHours(2);\n\t\t\tassertThat(mapper.writeValueAsString(duration)).isEqualTo(\"\\\"PT2H\\\"\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid writeWithVisibility() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jackson2.visibility.getter:none\", \"spring.jackson2.visibility.field:any\")\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper mapper = context.getBean(ObjectMapper.class);\n\t\t\t\tString json = mapper.writeValueAsString(new VisibilityBean());\n\t\t\t\tassertThat(json).contains(\"property1\");\n\t\t\t\tassertThat(json).contains(\"property2\");\n\t\t\t\tassertThat(json).doesNotContain(\"property3\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid builderIsNotSharedAcrossMultipleInjectionPoints() {\n\t\tthis.contextRunner.withUserConfiguration(ObjectMapperBuilderConsumerConfig.class).run((context) -> {\n\t\t\tObjectMapperBuilderConsumerConfig consumer = context.getBean(ObjectMapperBuilderConsumerConfig.class);\n\t\t\tassertThat(consumer.builderOne).isNotNull();\n\t\t\tassertThat(consumer.builderTwo).isNotNull();\n\t\t\tassertThat(consumer.builderOne).isNotSameAs(consumer.builderTwo);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jsonComponentThatInjectsObjectMapperCausesBeanCurrentlyInCreationException() {\n\t\tthis.contextRunner.withUserConfiguration(CircularDependencySerializerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure().hasRootCauseInstanceOf(BeanCurrentlyInCreationException.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterPropertyNamingStrategyHints() {\n\t\tshouldRegisterPropertyNamingStrategyHints(PropertyNamingStrategies.class, \"LOWER_CAMEL_CASE\",\n\t\t\t\t\"UPPER_CAMEL_CASE\", \"SNAKE_CASE\", \"UPPER_SNAKE_CASE\", \"LOWER_CASE\", \"KEBAB_CASE\", \"LOWER_DOT_CASE\");\n\t}\n\n\tprivate void shouldRegisterPropertyNamingStrategyHints(Class<?> type, String... fieldNames) {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.Jackson2AutoConfigurationRuntimeHints()\n\t\t\t.registerHints(hints, getClass().getClassLoader());\n\t\tReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();\n\t\tStream.of(fieldNames)\n\t\t\t.map((name) -> reflection.onField(type, name))\n\t\t\t.forEach((predicate) -> assertThat(predicate).accepts(hints));\n\t}\n\n\tprivate void assertParameterNamesModuleCreatorBinding(Mode expectedMode, Class<?>... configClasses) {\n\t\tthis.contextRunner.withUserConfiguration(configClasses).run((context) -> {\n\t\t\tDeserializationConfig deserializationConfig = context.getBean(ObjectMapper.class)\n\t\t\t\t.getDeserializationConfig();\n\t\t\tAnnotationIntrospector annotationIntrospector = deserializationConfig.getAnnotationIntrospector()\n\t\t\t\t.allIntrospectors()\n\t\t\t\t.iterator()\n\t\t\t\t.next();\n\t\t\tassertThat(annotationIntrospector).hasFieldOrPropertyWithValue(\"creatorBinding\", expectedMode);\n\t\t});\n\t}\n\n\tstatic class MyDateFormat extends SimpleDateFormat {\n\n\t\tMyDateFormat() {\n\t\t\tsuper(\"yyyy-MM-dd HH:mm:ss\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockObjectMapperConfig {\n\n\t\t@Bean\n\t\t@Primary\n\t\tObjectMapper objectMapper() {\n\t\t\treturn mock(ObjectMapper.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BazSerializer.class)\n\tstatic class ModuleConfig {\n\n\t\t@Bean\n\t\tCustomModule jacksonModule() {\n\t\t\treturn new CustomModule();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class DoubleModulesConfig {\n\n\t\t@Bean\n\t\tModule jacksonModule() {\n\t\t\tSimpleModule module = new SimpleModule();\n\t\t\tmodule.addSerializer(Foo.class, new JsonSerializer<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void serialize(Foo value, JsonGenerator jgen, SerializerProvider provider) throws IOException {\n\t\t\t\t\tjgen.writeStartObject();\n\t\t\t\t\tjgen.writeStringField(\"foo\", \"bar\");\n\t\t\t\t\tjgen.writeEndObject();\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn module;\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tObjectMapper objectMapper() {\n\t\t\tObjectMapper mapper = new ObjectMapper();\n\t\t\tmapper.registerModule(jacksonModule());\n\t\t\treturn mapper;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParameterNamesModuleConfig {\n\n\t\t@Bean\n\t\tParameterNamesModule parameterNamesModule() {\n\t\t\treturn new ParameterNamesModule(JsonCreator.Mode.DELEGATING);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObjectMapperBuilderCustomConfig {\n\n\t\t@Bean\n\t\tJackson2ObjectMapperBuilderCustomizer customDateFormat() {\n\t\t\treturn (builder) -> builder.dateFormat(new MyDateFormat());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomModuleBuilderCustomizerConfig {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tJackson2ObjectMapperBuilderCustomizer highPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.modulesToInstall((modules) -> modules.add(new SimpleModule(\"module-A\")));\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tJackson2ObjectMapperBuilderCustomizer lowPrecedenceCustomizer() {\n\t\t\treturn (builder) -> builder.modulesToInstall((modules) -> modules.add(new SimpleModule(\"module-B\")));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObjectMapperBuilderConsumerConfig {\n\n\t\t@Nullable Jackson2ObjectMapperBuilder builderOne;\n\n\t\t@Nullable Jackson2ObjectMapperBuilder builderTwo;\n\n\t\t@Bean\n\t\tString consumerOne(Jackson2ObjectMapperBuilder builder) {\n\t\t\tthis.builderOne = builder;\n\t\t\treturn \"one\";\n\t\t}\n\n\t\t@Bean\n\t\tString consumerTwo(Jackson2ObjectMapperBuilder builder) {\n\t\t\tthis.builderTwo = builder;\n\t\t\treturn \"two\";\n\t\t}\n\n\t}\n\n\tprotected static final class Foo {\n\n\t\tprivate @Nullable String name;\n\n\t\tprivate Foo() {\n\t\t}\n\n\t\tstatic Foo create() {\n\t\t\treturn new Foo();\n\t\t}\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n\tstatic class Bar {\n\n\t\tprivate @Nullable String propertyName;\n\n\t\t@Nullable String getPropertyName() {\n\t\t\treturn this.propertyName;\n\t\t}\n\n\t\tvoid setPropertyName(@Nullable String propertyName) {\n\t\t\tthis.propertyName = propertyName;\n\t\t}\n\n\t}\n\n\t@JsonComponent\n\tstatic class BazSerializer extends JsonObjectSerializer<Baz> {\n\n\t\t@Override\n\t\tprotected void serializeObject(Baz value, JsonGenerator jgen, SerializerProvider provider) {\n\t\t}\n\n\t}\n\n\tstatic class Baz {\n\n\t}\n\n\tstatic class CustomModule extends SimpleModule {\n\n\t\tprivate final Set<ObjectCodec> owners = new HashSet<>();\n\n\t\t@Override\n\t\tpublic void setupModule(SetupContext context) {\n\t\t\tthis.owners.add(context.getOwner());\n\t\t}\n\n\t\tSet<ObjectCodec> getOwners() {\n\t\t\treturn this.owners;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class VisibilityBean {\n\n\t\tprivate @Nullable String property1;\n\n\t\tpublic @Nullable String property2;\n\n\t\t@Nullable String getProperty3() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tstatic class Person {\n\n\t\t@JsonFormat(pattern = \"yyyyMMdd\")\n\t\tprivate @Nullable Date birthDate;\n\n\t\t@Nullable Date getBirthDate() {\n\t\t\treturn this.birthDate;\n\t\t}\n\n\t\tvoid setBirthDate(@Nullable Date birthDate) {\n\t\t\tthis.birthDate = birthDate;\n\t\t}\n\n\t}\n\n\t@JsonMixin(type = Person.class)\n\tstatic class EmptyMixin {\n\n\t}\n\n\t@AutoConfigurationPackage\n\tstatic class MixinConfiguration {\n\n\t}\n\n\t@JsonComponent\n\tstatic class CircularDependencySerializer extends JsonSerializer<String> {\n\n\t\tCircularDependencySerializer(ObjectMapper objectMapper) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {\n\n\t\t}\n\n\t}\n\n\t@Import(CircularDependencySerializer.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CircularDependencySerializerConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/a/RenameMixInClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.scan.a;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson2.JsonMixin;\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\n@JsonMixin(type = { Name.class, NameAndAge.class })\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic abstract class RenameMixInClass {\n\n\t@JsonProperty(\"username\")\n\tpublic abstract String getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/a/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.scan.a;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/b/RenameMixInAbstractClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.scan.b;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson2.JsonMixin;\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\n@JsonMixin(type = NameAndAge.class)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic abstract class RenameMixInAbstractClass {\n\n\t@JsonProperty(\"username\")\n\tabstract String getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/b/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.scan.b;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/c/RenameMixInInterface.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.scan.c;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson2.JsonMixin;\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\n@JsonMixin(type = NameAndAge.class)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic interface RenameMixInInterface {\n\n\t@JsonProperty(\"username\")\n\tString getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/c/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.scan.c;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/d/EmptyMixInClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.scan.d;\n\nimport org.springframework.boot.jackson2.JsonMixin;\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\n@JsonMixin(type = { Name.class, NameAndAge.class })\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class EmptyMixInClass {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/d/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.scan.d;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/e/PrivateMixInClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.scan.e;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jackson2.JsonMixin;\nimport org.springframework.boot.jackson2.types.Name;\nimport org.springframework.boot.jackson2.types.NameAndAge;\n\n@JsonMixin(type = { Name.class, NameAndAge.class })\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass PrivateMixInClass {\n\n\t@JsonProperty(\"username\")\n\t@Nullable String getName() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/e/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.scan.e;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/f/EmptyMixIn.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.scan.f;\n\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\nimport org.springframework.boot.jackson2.JsonMixin;\n\n@JsonMixin\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic interface EmptyMixIn {\n\n\t@JsonProperty(\"username\")\n\tString getName();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/scan/f/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.scan.f;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/types/Name.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.types;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Sample object used for tests.\n *\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic class Name {\n\n\tprotected final @Nullable String name;\n\n\tpublic Name(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/types/NameAndAge.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.types;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Sample object used for tests.\n *\n * @author Phillip Webb\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic final class NameAndAge extends Name {\n\n\tprivate final int age;\n\n\tpublic NameAndAge(@Nullable String name, int age) {\n\t\tsuper(name);\n\t\tthis.age = age;\n\t}\n\n\tpublic int getAge() {\n\t\treturn this.age;\n\t}\n\n\tpublic String asKey() {\n\t\treturn this.name + \" is \" + this.age;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj instanceof NameAndAge other) {\n\t\t\tboolean rtn = true;\n\t\t\trtn = rtn && ObjectUtils.nullSafeEquals(this.name, other.name);\n\t\t\trtn = rtn && ObjectUtils.nullSafeEquals(this.age, other.age);\n\t\t\treturn rtn;\n\t\t}\n\t\treturn super.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int prime = 31;\n\t\tint result = 1;\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.name);\n\t\tresult = prime * result + ObjectUtils.nullSafeHashCode(this.age);\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/types/NameAndCareer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jackson2.types;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Sample object used for tests.\n *\n * @author Paul Aly\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class NameAndCareer extends Name {\n\n\tprivate final @Nullable String career;\n\n\tpublic NameAndCareer(@Nullable String name, @Nullable String career) {\n\t\tsuper(name);\n\t\tthis.career = career;\n\t}\n\n\tpublic @Nullable String getCareer() {\n\t\treturn this.career;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jackson2/src/test/java/org/springframework/boot/jackson2/types/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jackson2.types;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot JDBC\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-sql\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework:spring-jdbc\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"com.h2database:h2\")\n\toptional(\"com.mchange:c3p0\")\n\toptional(\"com.oracle.database.jdbc:ojdbc11\")\n\toptional(\"com.oracle.database.jdbc:ucp11\")\n\toptional(\"com.zaxxer:HikariCP\")\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"org.apache.commons:commons-dbcp2\")\n\toptional(\"org.apache.tomcat:tomcat-jdbc\")\n\toptional(\"org.postgresql:postgresql\")\n\toptional(\"org.testcontainers:testcontainers-jdbc\")\n\toptional(\"org.vibur:vibur-dbcp\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\n\tdockerTestRuntimeOnly(\"com.clickhouse:clickhouse-jdbc\")\n\tdockerTestRuntimeOnly(\"com.microsoft.sqlserver:mssql-jdbc\")\n\tdockerTestRuntimeOnly(\"org.lz4:lz4-java:1.8.0\")\n\tdockerTestRuntimeOnly(\"org.postgresql:postgresql\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-sql\")))\n\ttestImplementation(\"com.ibm.db2:jcc\")\n\ttestImplementation(\"com.microsoft.sqlserver:mssql-jdbc\")\n\ttestImplementation(\"io.r2dbc:r2dbc-spi\")\n\ttestImplementation(\"org.hsqldb:hsqldb\")\n\ttestImplementation(\"org.mariadb.jdbc:mariadb-java-client\") {\n\t\texclude group: \"org.slf4j\", module: \"jcl-over-slf4j\"\n\t}\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestCompileOnly(\"org.checkerframework:checker-qual\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.clickhouse:clickhouse-jdbc\")\n\ttestRuntimeOnly(\"com.mysql:mysql-connector-j\")\n\ttestRuntimeOnly(\"net.sourceforge.jtds:jtds\")\n\ttestRuntimeOnly(\"org.apache.derby:derby\")\n\ttestRuntimeOnly(\"org.apache.derby:derbytools\")\n\ttestRuntimeOnly(\"org.firebirdsql.jdbc:jaybird\") {\n\t\texclude group: \"javax.resource\", module: \"connector-api\"\n\t}\n\ttestRuntimeOnly(\"org.testcontainers:testcontainers-jdbc\") {\n\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t\texclude group: \"javax.xml.bind\", module: \"jaxb-api\"\n\t}\n\ttestRuntimeOnly(\"org.xerial:sqlite-jdbc\")\n\ttestRuntimeOnly(\"software.amazon.jdbc:aws-advanced-jdbc-wrapper\")\n}\n\ntasks.named(\"checkSpringConfigurationMetadata\").configure {\n\texclusions = [\n\t\t\"spring.datasource.dbcp2.*\",\n\t\t\"spring.datasource.hikari.*\",\n\t\t\"spring.datasource.oracleucp.*\",\n\t\t\"spring.datasource.tomcat.*\",\n\t]\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/ClickHouseJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.sql.Driver;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ClickHouseJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"clickhouse-compose.yaml\", image = TestImage.CLICKHOUSE)\n\tvoid runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:clickhouse://\").endsWith(\"/mydatabase\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),\n\t\t\t\tgetClass().getClassLoader()));\n\t\tJdbcTemplate template = new JdbcTemplate(dataSource);\n\t\tString validationQuery = DatabaseDriver.CLICKHOUSE.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tassertThat(template.queryForObject(validationQuery, Integer.class)).isEqualTo(1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/MariaDbJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MariaDbJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MariaDbJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mariadb-compose.yaml\", image = TestImage.MARIADB)\n\tvoid runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:mariadb://\").endsWith(\"/mydatabase\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/MySqlJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MySqlJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MySqlJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mysql-compose.yaml\", image = TestImage.MYSQL)\n\tvoid runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:mysql://\").endsWith(\"/mydatabase\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/OracleFreeJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.sql.Driver;\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OracleFreeJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass OracleFreeJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@SuppressWarnings(\"unchecked\")\n\t@DockerComposeTest(composeFile = \"oracle-compose.yaml\", image = TestImage.ORACLE_FREE)\n\tvoid runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)\n\t\t\tthrows Exception {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"app_user\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"app_user_secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:oracle:thin:@\").endsWith(\"/freepdb1\");\n\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),\n\t\t\t\tgetClass().getClassLoader()));\n\t\tAwaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().untilAsserted(() -> {\n\t\t\tJdbcTemplate template = new JdbcTemplate(dataSource);\n\t\t\tString validationQuery = DatabaseDriver.ORACLE.getValidationQuery();\n\t\t\tassertThat(validationQuery).isNotNull();\n\t\t\tassertThat(template.queryForObject(validationQuery, String.class)).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/OracleXeJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.sql.Driver;\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OracleXeJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\tdisabledReason = \"The Oracle image has no ARM support\")\nclass OracleXeJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@SuppressWarnings(\"unchecked\")\n\t@DockerComposeTest(composeFile = \"oracle-compose.yaml\", image = TestImage.ORACLE_XE)\n\tvoid runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)\n\t\t\tthrows Exception {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"app_user\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"app_user_secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:oracle:thin:@\").endsWith(\"/xepdb1\");\n\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),\n\t\t\t\tgetClass().getClassLoader()));\n\t\tAwaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().untilAsserted(() -> {\n\t\t\tJdbcTemplate template = new JdbcTemplate(dataSource);\n\t\t\tString validationQuery = DatabaseDriver.ORACLE.getValidationQuery();\n\t\t\tassertThat(validationQuery).isNotNull();\n\t\t\tassertThat(template.queryForObject(validationQuery, String.class)).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/PostgresJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.sql.Driver;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link PostgresJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author He Zean\n */\nclass PostgresJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"postgres-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"postgres-with-trust-host-auth-method-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetailsThatCanAccessDatabaseWhenHostAuthMethodIsTrust(\n\t\t\tJdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isNull();\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:postgresql://\").endsWith(\"/mydatabase\");\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"postgres-application-name-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetailsApplicationName(JdbcConnectionDetails connectionDetails)\n\t\t\tthrows ClassNotFoundException {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:postgresql://\")\n\t\t\t.endsWith(\"?ApplicationName=spring+boot\");\n\t\tassertThat(executeQuery(connectionDetails, \"select current_setting('application_name')\", String.class))\n\t\t\t.isEqualTo(\"spring boot\");\n\t}\n\n\tprivate void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:postgresql://\").endsWith(\"/mydatabase\");\n\t}\n\n\tprivate void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tString validationQuery = DatabaseDriver.POSTGRESQL.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tassertThat(executeQuery(connectionDetails, validationQuery, Integer.class)).isEqualTo(1);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T executeQuery(JdbcConnectionDetails connectionDetails, String sql, Class<T> resultClass)\n\t\t\tthrows ClassNotFoundException {\n\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),\n\t\t\t\tgetClass().getClassLoader()));\n\t\treturn new JdbcTemplate(dataSource).queryForObject(sql, resultClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/docker/compose/SqlServerJdbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.sql.Driver;\n\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SqlServerJdbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\tdisabledReason = \"The SQL server image has no ARM support\")\nclass SqlServerJdbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mssqlserver-compose.yaml\", image = TestImage.SQL_SERVER)\n\tvoid runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(JdbcConnectionDetails connectionDetails)\n\t\t\tthrows ClassNotFoundException, LinkageError {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"SA\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"verYs3cret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:sqlserver://\");\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"mssqlserver-with-jdbc-parameters-compose.yaml\", image = TestImage.SQL_SERVER)\n\tvoid runWithJdbcParametersCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(\n\t\t\tJdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"SA\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"verYs3cret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:sqlserver://\")\n\t\t\t.contains(\";sendStringParametersAsUnicode=false;\");\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {\n\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),\n\t\t\t\tgetClass().getClassLoader()));\n\t\tJdbcTemplate template = new JdbcTemplate(dataSource);\n\t\tString validationQuery = DatabaseDriver.SQLSERVER.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tassertThat(template.queryForObject(validationQuery, Integer.class)).isEqualTo(1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/java/org/springframework/boot/jdbc/testcontainers/JdbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.testcontainers;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link JdbcContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass JdbcContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final PostgreSQLContainer postgres = TestImage.container(PostgreSQLContainer.class);\n\n\t@Autowired(required = false)\n\tprivate JdbcConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid connectionCanBeMadeToJdbcContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tJdbcTemplate jdbc = new JdbcTemplate(this.dataSource);\n\t\tString validationQuery = DatabaseDriver.POSTGRESQL.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tassertThatNoException().isThrownBy(() -> jdbc.execute(validationQuery));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/clickhouse-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '8123'\n    environment:\n      - 'CLICKHOUSE_USER=myuser'\n      - 'CLICKHOUSE_PASSWORD=secret'\n      - 'CLICKHOUSE_DB=mydatabase'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/mariadb-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '3306'\n    environment:\n      - 'MARIADB_ROOT_PASSWORD=verysecret'\n      - 'MARIADB_USER=myuser'\n      - 'MARIADB_PASSWORD=secret'\n      - 'MARIADB_DATABASE=mydatabase'\n\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/mssqlserver-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '1433'\n    environment:\n      - 'MSSQL_PID=express'\n      - 'MSSQL_SA_PASSWORD=verYs3cret'\n      - 'ACCEPT_EULA=yes'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/mssqlserver-with-jdbc-parameters-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '1433'\n    environment:\n      - 'MSSQL_PID=express'\n      - 'MSSQL_SA_PASSWORD=verYs3cret'\n      - 'ACCEPT_EULA=yes'\n    labels:\n      org.springframework.boot.jdbc.parameters: sendStringParametersAsUnicode=false"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/mysql-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '3306'\n    environment:\n      - 'MYSQL_ROOT_PASSWORD=verysecret'\n      - 'MYSQL_USER=myuser'\n      - 'MYSQL_PASSWORD=secret'\n      - 'MYSQL_DATABASE=mydatabase'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/oracle-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '1521'\n    environment:\n      - 'APP_USER=app_user'\n      - 'APP_USER_PASSWORD=app_user_secret'\n      - 'ORACLE_PASSWORD=secret'\n    healthcheck:\n      test: [\"CMD-SHELL\", \"healthcheck.sh\"]\n      interval: 10s\n      timeout: 5s\n      retries: 10\n\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/otlp-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/postgres-application-name-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n    labels:\n      org.springframework.boot.jdbc.parameters: 'ApplicationName=spring+boot'\n      org.springframework.boot.r2dbc.parameters: 'applicationName=spring boot'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/postgres-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/org/springframework/boot/jdbc/docker/compose/postgres-with-trust-host-auth-method-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_HOST_AUTH_METHOD=trust'\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/DataSourceBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.beans.PropertyVetoException;\nimport java.lang.reflect.Method;\nimport java.sql.SQLException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport javax.sql.DataSource;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport com.zaxxer.hikari.HikariDataSource;\nimport oracle.jdbc.datasource.OracleDataSource;\nimport oracle.ucp.jdbc.PoolDataSource;\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.h2.jdbcx.JdbcDataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.postgresql.ds.PGSimpleDataSource;\nimport org.vibur.dbcp.ViburDBCPDataSource;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Convenience class for building a {@link DataSource}. Provides a limited subset of the\n * properties supported by a typical {@link DataSource} as well as detection logic to pick\n * the most suitable pooling {@link DataSource} implementation.\n * <p>\n * The following pooling {@link DataSource} implementations are supported by this builder.\n * When no {@link #type(Class) type} has been explicitly set, the first available pool\n * implementation will be picked:\n * <ul>\n * <li>Hikari ({@code com.zaxxer.hikari.HikariDataSource})</li>\n * <li>Tomcat JDBC Pool ({@code org.apache.tomcat.jdbc.pool.DataSource})</li>\n * <li>Apache DBCP2 ({@code org.apache.commons.dbcp2.BasicDataSource})</li>\n * <li>Oracle UCP ({@code oracle.ucp.jdbc.PoolDataSourceImpl})</li>\n * <li>C3P0 ({@code com.mchange.v2.c3p0.ComboPooledDataSource})</li>\n * <li>Vibur ({@code org.vibur.dbcp.ViburDBCPDataSource})</li>\n * </ul>\n * <p>\n * The following non-pooling {@link DataSource} implementations can be used when\n * explicitly set as a {@link #type(Class) type}:\n * <ul>\n * <li>Spring's {@code SimpleDriverDataSource}\n * ({@code org.springframework.jdbc.datasource.SimpleDriverDataSource})</li>\n * <li>Oracle ({@code oracle.jdbc.datasource.OracleDataSource})</li>\n * <li>H2 ({@code org.h2.jdbcx.JdbcDataSource})</li>\n * <li>Postgres ({@code org.postgresql.ds.PGSimpleDataSource})</li>\n * <li>Any {@code DataSource} implementation with appropriately named methods</li>\n * </ul>\n * <p>\n * This class is commonly used in an {@code @Bean} method and often combined with\n * {@code @ConfigurationProperties}.\n *\n * @param <T> the {@link DataSource} type being built\n * @author Dave Syer\n * @author Madhura Bhave\n * @author Fabio Grassi\n * @author Phillip Webb\n * @since 2.0.0\n * @see #create()\n * @see #create(ClassLoader)\n * @see #derivedFrom(DataSource)\n */\npublic final class DataSourceBuilder<T extends DataSource> {\n\n\tprivate final @Nullable ClassLoader classLoader;\n\n\tprivate final Map<DataSourceProperty, @Nullable String> values = new HashMap<>();\n\n\tprivate @Nullable Class<T> type;\n\n\tprivate final @Nullable DataSource deriveFrom;\n\n\tprivate DataSourceBuilder(@Nullable ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t\tthis.deriveFrom = null;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate DataSourceBuilder(T deriveFrom) {\n\t\tAssert.notNull(deriveFrom, \"'deriveFrom' must not be null\");\n\t\tthis.classLoader = deriveFrom.getClass().getClassLoader();\n\t\tthis.type = (Class<T>) deriveFrom.getClass();\n\t\tthis.deriveFrom = deriveFrom;\n\t}\n\n\t/**\n\t * Set the {@link DataSource} type that should be built.\n\t * @param <D> the datasource type\n\t * @param type the datasource type\n\t * @return this builder\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <D extends DataSource> DataSourceBuilder<D> type(@Nullable Class<D> type) {\n\t\tthis.type = (Class<T>) type;\n\t\treturn (DataSourceBuilder<D>) this;\n\t}\n\n\t/**\n\t * Set the URL that should be used when building the datasource.\n\t * @param url the JDBC url\n\t * @return this builder\n\t */\n\tpublic DataSourceBuilder<T> url(String url) {\n\t\tset(DataSourceProperty.URL, url);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the driver class name that should be used when building the datasource.\n\t * @param driverClassName the driver class name\n\t * @return this builder\n\t */\n\tpublic DataSourceBuilder<T> driverClassName(String driverClassName) {\n\t\tset(DataSourceProperty.DRIVER_CLASS_NAME, driverClassName);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the username that should be used when building the datasource.\n\t * @param username the user name\n\t * @return this builder\n\t */\n\tpublic DataSourceBuilder<T> username(@Nullable String username) {\n\t\tset(DataSourceProperty.USERNAME, username);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Set the password that should be used when building the datasource.\n\t * @param password the password\n\t * @return this builder\n\t */\n\tpublic DataSourceBuilder<T> password(@Nullable String password) {\n\t\tset(DataSourceProperty.PASSWORD, password);\n\t\treturn this;\n\t}\n\n\tprivate void set(DataSourceProperty property, @Nullable String value) {\n\t\tthis.values.put(property, value);\n\t}\n\n\t/**\n\t * Return a newly built {@link DataSource} instance.\n\t * @return the built datasource\n\t */\n\tpublic T build() {\n\t\tDataSourceProperties<T> properties = DataSourceProperties.forType(this.classLoader, this.type);\n\t\tDataSourceProperties<DataSource> deriveFromProperties = getDeriveFromProperties();\n\t\tClass<? extends T> instanceType = (this.type != null) ? this.type : properties.getDataSourceInstanceType();\n\t\tT dataSource = BeanUtils.instantiateClass(instanceType);\n\t\tSet<DataSourceProperty> applied = new HashSet<>();\n\t\tfor (DataSourceProperty property : DataSourceProperty.values()) {\n\t\t\tString value = this.values.get(property);\n\t\t\tif (value == null && deriveFromProperties != null && this.deriveFrom != null\n\t\t\t\t\t&& properties.canSet(property)) {\n\t\t\t\tvalue = deriveFromProperties.get(this.deriveFrom, property);\n\t\t\t}\n\t\t\tif (value != null) {\n\t\t\t\tproperties.set(dataSource, property, value);\n\t\t\t\tapplied.add(property);\n\t\t\t}\n\t\t}\n\t\tif (!applied.contains(DataSourceProperty.DRIVER_CLASS_NAME)\n\t\t\t\t&& properties.canSet(DataSourceProperty.DRIVER_CLASS_NAME)\n\t\t\t\t&& applied.contains(DataSourceProperty.URL)) {\n\t\t\tString url = properties.get(dataSource, DataSourceProperty.URL);\n\t\t\tDatabaseDriver driver = DatabaseDriver.fromJdbcUrl(url);\n\t\t\tString driverClassName = driver.getDriverClassName();\n\t\t\tif (driverClassName != null) {\n\t\t\t\tproperties.set(dataSource, DataSourceProperty.DRIVER_CLASS_NAME, driverClassName);\n\t\t\t}\n\t\t}\n\t\treturn dataSource;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate @Nullable DataSourceProperties<DataSource> getDeriveFromProperties() {\n\t\tif (this.deriveFrom == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn DataSourceProperties.forType(this.classLoader, (Class<DataSource>) this.deriveFrom.getClass());\n\t}\n\n\t/**\n\t * Create a new {@link DataSourceBuilder} instance.\n\t * @return a new datasource builder instance\n\t */\n\tpublic static DataSourceBuilder<?> create() {\n\t\treturn create(null);\n\t}\n\n\t/**\n\t * Create a new {@link DataSourceBuilder} instance.\n\t * @param classLoader the classloader used to discover preferred settings\n\t * @return a new {@link DataSource} builder instance\n\t */\n\tpublic static DataSourceBuilder<?> create(@Nullable ClassLoader classLoader) {\n\t\treturn new DataSourceBuilder<>(classLoader);\n\t}\n\n\t/**\n\t * Create a new {@link DataSourceBuilder} instance derived from the specified data\n\t * source. The returned builder can be used to build the same type of\n\t * {@link DataSource} with {@code username}, {@code password}, {@code url} and\n\t * {@code driverClassName} properties copied from the original when not specifically\n\t * set.\n\t * @param dataSource the source {@link DataSource}\n\t * @return a new {@link DataSource} builder\n\t */\n\tpublic static DataSourceBuilder<?> derivedFrom(DataSource dataSource) {\n\t\treturn new DataSourceBuilder<>(unwrap(dataSource));\n\t}\n\n\tprivate static DataSource unwrap(DataSource dataSource) {\n\t\ttry {\n\t\t\twhile (dataSource.isWrapperFor(DataSource.class)) {\n\t\t\t\tDataSource unwrapped = dataSource.unwrap(DataSource.class);\n\t\t\t\tif (unwrapped == dataSource) {\n\t\t\t\t\treturn unwrapped;\n\t\t\t\t}\n\t\t\t\tdataSource = unwrapped;\n\t\t\t}\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\t// Try to continue with the existing, potentially still wrapped, DataSource\n\t\t}\n\t\treturn dataSource;\n\t}\n\n\t/**\n\t * Find the {@link DataSource} type preferred for the given classloader.\n\t * @param classLoader the classloader used to discover preferred settings\n\t * @return the preferred {@link DataSource} type\n\t */\n\tpublic static @Nullable Class<? extends DataSource> findType(@Nullable ClassLoader classLoader) {\n\t\tMappedDataSourceProperties<?> mappings = MappedDataSourceProperties.forType(classLoader, null);\n\t\treturn (mappings != null) ? mappings.getDataSourceInstanceType() : null;\n\t}\n\n\t/**\n\t * An individual DataSource property supported by the builder.\n\t */\n\tprivate enum DataSourceProperty {\n\n\t\tURL(false, \"url\", \"URL\"),\n\n\t\tDRIVER_CLASS_NAME(true, \"driverClassName\"),\n\n\t\tUSERNAME(false, \"username\", \"user\"),\n\n\t\tPASSWORD(false, \"password\");\n\n\t\tprivate final boolean optional;\n\n\t\tprivate final String[] names;\n\n\t\tDataSourceProperty(boolean optional, String... names) {\n\t\t\tthis.optional = optional;\n\t\t\tthis.names = names;\n\t\t}\n\n\t\tboolean isOptional() {\n\t\t\treturn this.optional;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.names[0];\n\t\t}\n\n\t\t@Nullable Method findSetter(Class<?> type) {\n\t\t\treturn findMethod(\"set\", type, String.class);\n\t\t}\n\n\t\t@Nullable Method findGetter(Class<?> type) {\n\t\t\treturn findMethod(\"get\", type);\n\t\t}\n\n\t\tprivate @Nullable Method findMethod(String prefix, Class<?> type, Class<?>... paramTypes) {\n\t\t\tfor (String name : this.names) {\n\t\t\t\tString candidate = prefix + StringUtils.capitalize(name);\n\t\t\t\tMethod method = ReflectionUtils.findMethod(type, candidate, paramTypes);\n\t\t\t\tif (method != null) {\n\t\t\t\t\treturn method;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tprivate interface DataSourceProperties<T extends DataSource> {\n\n\t\tClass<? extends T> getDataSourceInstanceType();\n\n\t\tboolean canSet(DataSourceProperty property);\n\n\t\tvoid set(T dataSource, DataSourceProperty property, String value);\n\n\t\t@Nullable String get(T dataSource, DataSourceProperty property);\n\n\t\tstatic <T extends DataSource> DataSourceProperties<T> forType(@Nullable ClassLoader classLoader,\n\t\t\t\t@Nullable Class<T> type) {\n\t\t\tMappedDataSourceProperties<T> mapped = MappedDataSourceProperties.forType(classLoader, type);\n\t\t\tif (mapped != null) {\n\t\t\t\treturn mapped;\n\t\t\t}\n\t\t\tAssert.state(type != null, \"No supported DataSource type found\");\n\t\t\treturn new ReflectionDataSourceProperties<>(type);\n\t\t}\n\n\t}\n\n\tprivate static class MappedDataSourceProperties<T extends DataSource> implements DataSourceProperties<T> {\n\n\t\tprivate final Map<DataSourceProperty, MappedDataSourceProperty<T, ?>> mappedProperties = new HashMap<>();\n\n\t\tprivate final Class<T> dataSourceType;\n\n\t\tMappedDataSourceProperties() {\n\t\t\tthis.dataSourceType = getGeneric();\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate Class<T> getGeneric() {\n\t\t\tClass<T> generic = (Class<T>) ResolvableType.forClass(MappedDataSourceProperties.class, getClass())\n\t\t\t\t.resolveGeneric();\n\t\t\tAssert.state(generic != null, \"'generic' must not be null\");\n\t\t\treturn generic;\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<? extends T> getDataSourceInstanceType() {\n\t\t\treturn this.dataSourceType;\n\t\t}\n\n\t\tprotected void add(DataSourceProperty property, @Nullable Getter<T, String> getter, Setter<T, String> setter) {\n\t\t\tadd(property, String.class, getter, setter);\n\t\t}\n\n\t\tprotected <V> void add(DataSourceProperty property, Class<V> type, @Nullable Getter<T, V> getter,\n\t\t\t\tSetter<T, V> setter) {\n\t\t\tthis.mappedProperties.put(property, new MappedDataSourceProperty<>(property, type, getter, setter));\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canSet(DataSourceProperty property) {\n\t\t\treturn this.mappedProperties.containsKey(property);\n\t\t}\n\n\t\t@Override\n\t\tpublic void set(T dataSource, DataSourceProperty property, String value) {\n\t\t\tMappedDataSourceProperty<T, ?> mappedProperty = getMapping(property);\n\t\t\tif (mappedProperty != null) {\n\t\t\t\tmappedProperty.set(dataSource, value);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(T dataSource, DataSourceProperty property) {\n\t\t\tMappedDataSourceProperty<T, ?> mappedProperty = getMapping(property);\n\t\t\tif (mappedProperty != null) {\n\t\t\t\treturn mappedProperty.get(dataSource);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable MappedDataSourceProperty<T, ?> getMapping(DataSourceProperty property) {\n\t\t\tMappedDataSourceProperty<T, ?> mappedProperty = this.mappedProperties.get(property);\n\t\t\tUnsupportedDataSourcePropertyException.throwIf(!property.isOptional() && mappedProperty == null,\n\t\t\t\t\t() -> \"No mapping found for \" + property);\n\t\t\treturn mappedProperty;\n\t\t}\n\n\t\tstatic <T extends DataSource> @Nullable MappedDataSourceProperties<T> forType(@Nullable ClassLoader classLoader,\n\t\t\t\t@Nullable Class<T> type) {\n\t\t\tMappedDataSourceProperties<T> pooled = lookupPooled(classLoader, type);\n\t\t\tif (type == null || pooled != null) {\n\t\t\t\treturn pooled;\n\t\t\t}\n\t\t\treturn lookupBasic(classLoader, type);\n\t\t}\n\n\t\tprivate static <T extends DataSource> @Nullable MappedDataSourceProperties<T> lookupPooled(\n\t\t\t\t@Nullable ClassLoader classLoader, @Nullable Class<T> type) {\n\t\t\tMappedDataSourceProperties<T> result = null;\n\t\t\tresult = lookup(classLoader, type, result, \"com.zaxxer.hikari.HikariDataSource\",\n\t\t\t\t\tHikariDataSourceProperties::new);\n\t\t\tresult = lookup(classLoader, type, result, \"org.apache.tomcat.jdbc.pool.DataSource\",\n\t\t\t\t\tTomcatPoolDataSourceProperties::new);\n\t\t\tresult = lookup(classLoader, type, result, \"org.apache.commons.dbcp2.BasicDataSource\",\n\t\t\t\t\tMappedDbcp2DataSource::new);\n\t\t\tresult = lookup(classLoader, type, result, \"oracle.ucp.jdbc.PoolDataSourceImpl\",\n\t\t\t\t\tOraclePoolDataSourceProperties::new, \"oracle.jdbc.OracleConnection\");\n\t\t\tresult = lookup(classLoader, type, result, \"com.mchange.v2.c3p0.ComboPooledDataSource\",\n\t\t\t\t\tComboPooledDataSourceProperties::new);\n\t\t\tresult = lookup(classLoader, type, result, \"org.vibur.dbcp.ViburDBCPDataSource\",\n\t\t\t\t\tViburDataSourceProperties::new);\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate static <T extends DataSource> @Nullable MappedDataSourceProperties<T> lookupBasic(\n\t\t\t\t@Nullable ClassLoader classLoader, Class<T> dataSourceType) {\n\t\t\tMappedDataSourceProperties<T> result = null;\n\t\t\tresult = lookup(classLoader, dataSourceType, result,\n\t\t\t\t\t\"org.springframework.jdbc.datasource.SimpleDriverDataSource\", SimpleDataSourceProperties::new);\n\t\t\tresult = lookup(classLoader, dataSourceType, result, \"oracle.jdbc.datasource.OracleDataSource\",\n\t\t\t\t\tOracleDataSourceProperties::new);\n\t\t\tresult = lookup(classLoader, dataSourceType, result, \"org.h2.jdbcx.JdbcDataSource\",\n\t\t\t\t\tH2DataSourceProperties::new);\n\t\t\tresult = lookup(classLoader, dataSourceType, result, \"org.postgresql.ds.PGSimpleDataSource\",\n\t\t\t\t\tPostgresDataSourceProperties::new);\n\t\t\treturn result;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate static <T extends DataSource> @Nullable MappedDataSourceProperties<T> lookup(\n\t\t\t\t@Nullable ClassLoader classLoader, @Nullable Class<T> dataSourceType,\n\t\t\t\t@Nullable MappedDataSourceProperties<T> existing, String dataSourceClassName,\n\t\t\t\tSupplier<MappedDataSourceProperties<?>> propertyMappingsSupplier, String... requiredClassNames) {\n\t\t\tif (existing != null || !allPresent(classLoader, dataSourceClassName, requiredClassNames)) {\n\t\t\t\treturn existing;\n\t\t\t}\n\t\t\tMappedDataSourceProperties<?> propertyMappings = propertyMappingsSupplier.get();\n\t\t\treturn (dataSourceType == null\n\t\t\t\t\t|| propertyMappings.getDataSourceInstanceType().isAssignableFrom(dataSourceType))\n\t\t\t\t\t\t\t? (MappedDataSourceProperties<T>) propertyMappings : null;\n\t\t}\n\n\t\tprivate static boolean allPresent(@Nullable ClassLoader classLoader, String dataSourceClassName,\n\t\t\t\tString[] requiredClassNames) {\n\t\t\tboolean result = ClassUtils.isPresent(dataSourceClassName, classLoader);\n\t\t\tfor (String requiredClassName : requiredClassNames) {\n\t\t\t\tresult = result && ClassUtils.isPresent(requiredClassName, classLoader);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tprivate static class MappedDataSourceProperty<T extends DataSource, V> {\n\n\t\tprivate final DataSourceProperty property;\n\n\t\tprivate final Class<V> type;\n\n\t\tprivate final @Nullable Getter<T, V> getter;\n\n\t\tprivate final @Nullable Setter<T, V> setter;\n\n\t\tMappedDataSourceProperty(DataSourceProperty property, Class<V> type, @Nullable Getter<T, V> getter,\n\t\t\t\t@Nullable Setter<T, V> setter) {\n\t\t\tthis.property = property;\n\t\t\tthis.type = type;\n\t\t\tthis.getter = getter;\n\t\t\tthis.setter = setter;\n\t\t}\n\n\t\tvoid set(T dataSource, String value) {\n\t\t\ttry {\n\t\t\t\tif (this.setter == null) {\n\t\t\t\t\tUnsupportedDataSourcePropertyException.throwIf(!this.property.isOptional(),\n\t\t\t\t\t\t\t() -> \"No setter mapped for '\" + this.property + \"' property\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.setter.set(dataSource, convertFromString(value));\n\t\t\t}\n\t\t\tcatch (SQLException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Nullable String get(T dataSource) {\n\t\t\ttry {\n\t\t\t\tif (this.getter == null) {\n\t\t\t\t\tUnsupportedDataSourcePropertyException.throwIf(!this.property.isOptional(),\n\t\t\t\t\t\t\t() -> \"No getter mapped for '\" + this.property + \"' property\");\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\treturn convertToString(this.getter.get(dataSource));\n\t\t\t}\n\t\t\tcatch (SQLException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate V convertFromString(String value) {\n\t\t\tif (String.class.equals(this.type)) {\n\t\t\t\treturn (V) value;\n\t\t\t}\n\t\t\tif (Class.class.equals(this.type)) {\n\t\t\t\treturn (V) ClassUtils.resolveClassName(value, null);\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unsupported value type \" + this.type);\n\t\t}\n\n\t\t@Contract(\"!null -> !null\")\n\t\tprivate @Nullable String convertToString(@Nullable V value) {\n\t\t\tif (value == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (String.class.equals(this.type)) {\n\t\t\t\treturn (String) value;\n\t\t\t}\n\t\t\tif (Class.class.equals(this.type)) {\n\t\t\t\treturn ((Class<?>) value).getName();\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unsupported value type \" + this.type);\n\t\t}\n\n\t}\n\n\tprivate static class ReflectionDataSourceProperties<T extends DataSource> implements DataSourceProperties<T> {\n\n\t\tprivate final Map<DataSourceProperty, Method> getters;\n\n\t\tprivate final Map<DataSourceProperty, Method> setters;\n\n\t\tprivate final Class<T> dataSourceType;\n\n\t\tReflectionDataSourceProperties(Class<T> dataSourceType) {\n\t\t\tMap<DataSourceProperty, Method> getters = new HashMap<>();\n\t\t\tMap<DataSourceProperty, Method> setters = new HashMap<>();\n\t\t\tfor (DataSourceProperty property : DataSourceProperty.values()) {\n\t\t\t\tputIfNotNull(getters, property, property.findGetter(dataSourceType));\n\t\t\t\tputIfNotNull(setters, property, property.findSetter(dataSourceType));\n\t\t\t}\n\t\t\tthis.dataSourceType = dataSourceType;\n\t\t\tthis.getters = Collections.unmodifiableMap(getters);\n\t\t\tthis.setters = Collections.unmodifiableMap(setters);\n\t\t}\n\n\t\tprivate void putIfNotNull(Map<DataSourceProperty, Method> map, DataSourceProperty property,\n\t\t\t\t@Nullable Method method) {\n\t\t\tif (method != null) {\n\t\t\t\tmap.put(property, method);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<T> getDataSourceInstanceType() {\n\t\t\treturn this.dataSourceType;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean canSet(DataSourceProperty property) {\n\t\t\treturn this.setters.containsKey(property);\n\t\t}\n\n\t\t@Override\n\t\tpublic void set(T dataSource, DataSourceProperty property, String value) {\n\t\t\tMethod method = getMethod(property, this.setters);\n\t\t\tif (method != null) {\n\t\t\t\tReflectionUtils.invokeMethod(method, dataSource, value);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(T dataSource, DataSourceProperty property) {\n\t\t\tMethod method = getMethod(property, this.getters);\n\t\t\tif (method != null) {\n\t\t\t\treturn (String) ReflectionUtils.invokeMethod(method, dataSource);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable Method getMethod(DataSourceProperty property, Map<DataSourceProperty, Method> methods) {\n\t\t\tMethod method = methods.get(property);\n\t\t\tif (method == null) {\n\t\t\t\tUnsupportedDataSourcePropertyException.throwIf(!property.isOptional(),\n\t\t\t\t\t\t() -> \"Unable to find suitable method for \" + property);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tReflectionUtils.makeAccessible(method);\n\t\t\treturn method;\n\t\t}\n\n\t}\n\n\t@FunctionalInterface\n\tprivate interface Getter<T, V> {\n\n\t\t@Nullable V get(T instance) throws SQLException;\n\n\t}\n\n\t@FunctionalInterface\n\tprivate interface Setter<T, V> {\n\n\t\tvoid set(T instance, V value) throws SQLException;\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for Hikari.\n\t */\n\tprivate static class HikariDataSourceProperties extends MappedDataSourceProperties<HikariDataSource> {\n\n\t\tHikariDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, HikariDataSource::getJdbcUrl, HikariDataSource::setJdbcUrl);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, HikariDataSource::getDriverClassName,\n\t\t\t\t\tHikariDataSource::setDriverClassName);\n\t\t\tadd(DataSourceProperty.USERNAME, HikariDataSource::getUsername, HikariDataSource::setUsername);\n\t\t\tadd(DataSourceProperty.PASSWORD, HikariDataSource::getPassword, HikariDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for Tomcat Pool.\n\t */\n\tprivate static class TomcatPoolDataSourceProperties\n\t\t\textends MappedDataSourceProperties<org.apache.tomcat.jdbc.pool.DataSource> {\n\n\t\tTomcatPoolDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, org.apache.tomcat.jdbc.pool.DataSource::getUrl,\n\t\t\t\t\torg.apache.tomcat.jdbc.pool.DataSource::setUrl);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, org.apache.tomcat.jdbc.pool.DataSource::getDriverClassName,\n\t\t\t\t\torg.apache.tomcat.jdbc.pool.DataSource::setDriverClassName);\n\t\t\tadd(DataSourceProperty.USERNAME, org.apache.tomcat.jdbc.pool.DataSource::getUsername,\n\t\t\t\t\torg.apache.tomcat.jdbc.pool.DataSource::setUsername);\n\t\t\tadd(DataSourceProperty.PASSWORD, org.apache.tomcat.jdbc.pool.DataSource::getPassword,\n\t\t\t\t\torg.apache.tomcat.jdbc.pool.DataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for DBCP2.\n\t */\n\tprivate static class MappedDbcp2DataSource extends MappedDataSourceProperties<BasicDataSource> {\n\n\t\tMappedDbcp2DataSource() {\n\t\t\tadd(DataSourceProperty.URL, BasicDataSource::getUrl, BasicDataSource::setUrl);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, BasicDataSource::getDriverClassName,\n\t\t\t\t\tBasicDataSource::setDriverClassName);\n\t\t\tadd(DataSourceProperty.USERNAME, BasicDataSource::getUserName, BasicDataSource::setUsername);\n\t\t\tadd(DataSourceProperty.PASSWORD, null, BasicDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for Oracle Pool.\n\t */\n\tprivate static class OraclePoolDataSourceProperties extends MappedDataSourceProperties<PoolDataSource> {\n\n\t\t@Override\n\t\tpublic Class<? extends PoolDataSource> getDataSourceInstanceType() {\n\t\t\treturn PoolDataSourceImpl.class;\n\t\t}\n\n\t\tOraclePoolDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, PoolDataSource::getURL, PoolDataSource::setURL);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, PoolDataSource::getConnectionFactoryClassName,\n\t\t\t\t\tPoolDataSource::setConnectionFactoryClassName);\n\t\t\tadd(DataSourceProperty.USERNAME, PoolDataSource::getUser, PoolDataSource::setUser);\n\t\t\tadd(DataSourceProperty.PASSWORD, null, PoolDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for C3P0.\n\t */\n\tprivate static class ComboPooledDataSourceProperties extends MappedDataSourceProperties<ComboPooledDataSource> {\n\n\t\tComboPooledDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, ComboPooledDataSource::getJdbcUrl, ComboPooledDataSource::setJdbcUrl);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, ComboPooledDataSource::getDriverClass, this::setDriverClass);\n\t\t\tadd(DataSourceProperty.USERNAME, ComboPooledDataSource::getUser, ComboPooledDataSource::setUser);\n\t\t\tadd(DataSourceProperty.PASSWORD, ComboPooledDataSource::getPassword, ComboPooledDataSource::setPassword);\n\t\t}\n\n\t\tprivate void setDriverClass(ComboPooledDataSource dataSource, String driverClass) {\n\t\t\ttry {\n\t\t\t\tdataSource.setDriverClass(driverClass);\n\t\t\t}\n\t\t\tcatch (PropertyVetoException ex) {\n\t\t\t\tthrow new IllegalArgumentException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static class ViburDataSourceProperties extends MappedDataSourceProperties<ViburDBCPDataSource> {\n\n\t\tViburDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, ViburDBCPDataSource::getJdbcUrl, ViburDBCPDataSource::setJdbcUrl);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, ViburDBCPDataSource::getDriverClassName,\n\t\t\t\t\tViburDBCPDataSource::setDriverClassName);\n\t\t\tadd(DataSourceProperty.USERNAME, ViburDBCPDataSource::getUsername, ViburDBCPDataSource::setUsername);\n\t\t\tadd(DataSourceProperty.PASSWORD, ViburDBCPDataSource::getPassword, ViburDBCPDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for Spring's {@link SimpleDriverDataSource}.\n\t */\n\tprivate static class SimpleDataSourceProperties extends MappedDataSourceProperties<SimpleDriverDataSource> {\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tSimpleDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, SimpleDriverDataSource::getUrl, SimpleDriverDataSource::setUrl);\n\t\t\tadd(DataSourceProperty.DRIVER_CLASS_NAME, Class.class,\n\t\t\t\t\t(dataSource) -> (dataSource.getDriver() != null) ? dataSource.getDriver().getClass() : null,\n\t\t\t\t\tSimpleDriverDataSource::setDriverClass);\n\t\t\tadd(DataSourceProperty.USERNAME, SimpleDriverDataSource::getUsername, SimpleDriverDataSource::setUsername);\n\t\t\tadd(DataSourceProperty.PASSWORD, SimpleDriverDataSource::getPassword, SimpleDriverDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for Oracle.\n\t */\n\tprivate static class OracleDataSourceProperties extends MappedDataSourceProperties<OracleDataSource> {\n\n\t\tOracleDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, OracleDataSource::getURL, OracleDataSource::setURL);\n\t\t\tadd(DataSourceProperty.USERNAME, OracleDataSource::getUser, OracleDataSource::setUser);\n\t\t\tadd(DataSourceProperty.PASSWORD, null, OracleDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for H2.\n\t */\n\tprivate static class H2DataSourceProperties extends MappedDataSourceProperties<JdbcDataSource> {\n\n\t\tH2DataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, JdbcDataSource::getUrl, JdbcDataSource::setUrl);\n\t\t\tadd(DataSourceProperty.USERNAME, JdbcDataSource::getUser, JdbcDataSource::setUser);\n\t\t\tadd(DataSourceProperty.PASSWORD, JdbcDataSource::getPassword, JdbcDataSource::setPassword);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link DataSourceProperties} for Postgres.\n\t */\n\tprivate static class PostgresDataSourceProperties extends MappedDataSourceProperties<PGSimpleDataSource> {\n\n\t\tPostgresDataSourceProperties() {\n\t\t\tadd(DataSourceProperty.URL, PGSimpleDataSource::getUrl, PGSimpleDataSource::setUrl);\n\t\t\tadd(DataSourceProperty.USERNAME, PGSimpleDataSource::getUser, PGSimpleDataSource::setUser);\n\t\t\tadd(DataSourceProperty.PASSWORD, PGSimpleDataSource::getPassword, PGSimpleDataSource::setPassword);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/DataSourceBuilderRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * {@link RuntimeHintsRegistrar} implementation for {@link DataSource} types supported by\n * the {@link DataSourceBuilder}.\n *\n * @author Phillip Webb\n */\nclass DataSourceBuilderRuntimeHints implements RuntimeHintsRegistrar {\n\n\tprivate static final List<String> TYPE_NAMES;\n\tstatic {\n\t\tList<String> typeNames = new ArrayList<>();\n\t\ttypeNames.add(\"com.mchange.v2.c3p0.ComboPooledDataSource\");\n\t\ttypeNames.add(\"com.zaxxer.hikari.HikariDataSource\");\n\t\ttypeNames.add(\"oracle.jdbc.datasource.OracleDataSource\");\n\t\ttypeNames.add(\"oracle.ucp.jdbc.PoolDataSourceImpl\");\n\t\ttypeNames.add(\"org.apache.commons.dbcp2.BasicDataSource\");\n\t\ttypeNames.add(\"org.apache.tomcat.jdbc.pool.DataSource\");\n\t\ttypeNames.add(\"org.h2.jdbcx.JdbcDataSource\");\n\t\ttypeNames.add(\"org.postgresql.ds.PGSimpleDataSource\");\n\t\ttypeNames.add(\"org.springframework.jdbc.datasource.SimpleDriverDataSource\");\n\t\ttypeNames.add(\"org.vibur.dbcp.ViburDBCPDataSource\");\n\t\tTYPE_NAMES = Collections.unmodifiableList(typeNames);\n\t}\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\tfor (String typeName : TYPE_NAMES) {\n\t\t\thints.reflection()\n\t\t\t\t.registerTypeIfPresent(classLoader, typeName,\n\t\t\t\t\t\t(hint) -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/DataSourceUnwrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.sql.Wrapper;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.framework.AopProxyUtils;\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.jdbc.datasource.DelegatingDataSource;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Unwraps a {@link DataSource} that may have been proxied or wrapped in a custom\n * {@link Wrapper} such as {@link DelegatingDataSource}.\n *\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n * @since 2.0.7\n */\npublic final class DataSourceUnwrapper {\n\n\tprivate static final boolean DELEGATING_DATA_SOURCE_PRESENT = ClassUtils.isPresent(\n\t\t\t\"org.springframework.jdbc.datasource.DelegatingDataSource\", DataSourceUnwrapper.class.getClassLoader());\n\n\tprivate DataSourceUnwrapper() {\n\t}\n\n\t/**\n\t * Return an object that implements the given {@code target} type, unwrapping delegate\n\t * or proxy if necessary using the specified {@code unwrapInterface}.\n\t * @param dataSource the datasource to handle\n\t * @param unwrapInterface the interface that the target type must implement\n\t * @param target the type that the result must implement\n\t * @param <I> the interface that the target type must implement\n\t * @param <T> the target type\n\t * @return an object that implements the target type or {@code null}\n\t * @since 2.3.8\n\t * @see Wrapper#unwrap(Class)\n\t */\n\tpublic static <I, T extends I> @Nullable T unwrap(DataSource dataSource, Class<I> unwrapInterface,\n\t\t\tClass<T> target) {\n\t\tif (target.isInstance(dataSource)) {\n\t\t\treturn target.cast(dataSource);\n\t\t}\n\t\tI unwrapped = safeUnwrap(dataSource, unwrapInterface);\n\t\tif (unwrapped != null && unwrapInterface.isAssignableFrom(target)) {\n\t\t\treturn target.cast(unwrapped);\n\t\t}\n\t\tif (DELEGATING_DATA_SOURCE_PRESENT) {\n\t\t\tDataSource targetDataSource = DelegatingDataSourceUnwrapper.getTargetDataSource(dataSource);\n\t\t\tif (targetDataSource != null) {\n\t\t\t\treturn unwrap(targetDataSource, unwrapInterface, target);\n\t\t\t}\n\t\t}\n\t\tif (AopUtils.isAopProxy(dataSource)) {\n\t\t\tObject proxyTarget = AopProxyUtils.getSingletonTarget(dataSource);\n\t\t\tif (proxyTarget instanceof DataSource proxyDataSource) {\n\t\t\t\treturn unwrap(proxyDataSource, unwrapInterface, target);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return an object that implements the given {@code target} type, unwrapping delegate\n\t * or proxy if necessary. Consider using {@link #unwrap(DataSource, Class, Class)} as\n\t * {@link Wrapper#unwrap(Class) unwrapping} won't be considered if {@code target} is\n\t * not an interface.\n\t * @param dataSource the datasource to handle\n\t * @param target the type that the result must implement\n\t * @param <T> the target type\n\t * @return an object that implements the target type or {@code null}\n\t */\n\tpublic static <T> @Nullable T unwrap(DataSource dataSource, Class<T> target) {\n\t\treturn unwrap(dataSource, target, target);\n\t}\n\n\tprivate static <S> @Nullable S safeUnwrap(Wrapper wrapper, Class<S> target) {\n\t\ttry {\n\t\t\tif (target.isInterface() && wrapper.isWrapperFor(target)) {\n\t\t\t\treturn wrapper.unwrap(target);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Continue\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static final class DelegatingDataSourceUnwrapper {\n\n\t\tprivate static @Nullable DataSource getTargetDataSource(DataSource dataSource) {\n\t\t\tif (dataSource instanceof DelegatingDataSource delegatingDataSource) {\n\t\t\t\treturn delegatingDataSource.getTargetDataSource();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/DatabaseDriver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Enumeration of common database drivers.\n *\n * @author Phillip Webb\n * @author Maciej Walkowiak\n * @author Marten Deinum\n * @author Stephane Nicoll\n * @since 1.4.0\n */\npublic enum DatabaseDriver {\n\n\t/**\n\t * Unknown type.\n\t */\n\tUNKNOWN(null, null),\n\n\t/**\n\t * Apache Derby.\n\t * @deprecated since 4.1.0 for removal in 4.3.0 as Derby is EOL.\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tDERBY(\"Apache Derby\", \"org.apache.derby.jdbc.EmbeddedDriver\", \"org.apache.derby.jdbc.EmbeddedXADataSource\",\n\t\t\t\"SELECT 1 FROM SYSIBM.SYSDUMMY1\"),\n\n\t/**\n\t * H2.\n\t */\n\tH2(\"H2\", \"org.h2.Driver\", \"org.h2.jdbcx.JdbcDataSource\", \"SELECT 1\"),\n\n\t/**\n\t * HyperSQL DataBase.\n\t */\n\tHSQLDB(\"HSQL Database Engine\", \"org.hsqldb.jdbc.JDBCDriver\", \"org.hsqldb.jdbc.pool.JDBCXADataSource\",\n\t\t\t\"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SYSTEM_USERS\"),\n\n\t/**\n\t * SQLite.\n\t */\n\tSQLITE(\"SQLite\", \"org.sqlite.JDBC\"),\n\n\t/**\n\t * MySQL.\n\t */\n\tMYSQL(\"MySQL\", \"com.mysql.cj.jdbc.Driver\", \"com.mysql.cj.jdbc.MysqlXADataSource\", \"/* ping */ SELECT 1\"),\n\n\t/**\n\t * Maria DB.\n\t */\n\tMARIADB(\"MariaDB\", \"org.mariadb.jdbc.Driver\", \"org.mariadb.jdbc.MariaDbDataSource\", \"SELECT 1\"),\n\n\t/**\n\t * Oracle.\n\t */\n\tORACLE(\"Oracle\", \"oracle.jdbc.OracleDriver\", \"oracle.jdbc.xa.client.OracleXADataSource\",\n\t\t\t\"SELECT 'Hello' from DUAL\"),\n\n\t/**\n\t * Postgres.\n\t */\n\tPOSTGRESQL(\"PostgreSQL\", \"org.postgresql.Driver\", \"org.postgresql.xa.PGXADataSource\", \"SELECT 1\"),\n\n\t/**\n\t * Amazon Redshift.\n\t * @since 2.2.0\n\t */\n\tREDSHIFT(\"Redshift\", \"com.amazon.redshift.jdbc.Driver\", null, \"SELECT 1\"),\n\n\t/**\n\t * HANA - SAP HANA Database - HDB.\n\t * @since 2.1.0\n\t */\n\tHANA(\"HDB\", \"com.sap.db.jdbc.Driver\", \"com.sap.db.jdbcext.XADataSourceSAP\", \"SELECT 1 FROM SYS.DUMMY\") {\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Collections.singleton(\"sap\");\n\t\t}\n\n\t},\n\n\t/**\n\t * jTDS. As it can be used for several databases, there isn't a single product name we\n\t * could rely on.\n\t */\n\tJTDS(null, \"net.sourceforge.jtds.jdbc.Driver\"),\n\n\t/**\n\t * SQL Server.\n\t */\n\tSQLSERVER(\"Microsoft SQL Server\", \"com.microsoft.sqlserver.jdbc.SQLServerDriver\",\n\t\t\t\"com.microsoft.sqlserver.jdbc.SQLServerXADataSource\", \"SELECT 1\") {\n\n\t\t@Override\n\t\tprotected boolean matchProductName(String productName) {\n\t\t\treturn super.matchProductName(productName) || \"SQL SERVER\".equalsIgnoreCase(productName);\n\t\t}\n\n\t},\n\n\t/**\n\t * Firebird.\n\t */\n\tFIREBIRD(\"Firebird\", \"org.firebirdsql.jdbc.FBDriver\", \"org.firebirdsql.ds.FBXADataSource\",\n\t\t\t\"SELECT 1 FROM RDB$DATABASE\") {\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Arrays.asList(\"firebirdsql\", \"firebird\");\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matchProductName(String productName) {\n\t\t\treturn super.matchProductName(productName)\n\t\t\t\t\t|| productName.toLowerCase(Locale.ENGLISH).startsWith(\"firebird\");\n\t\t}\n\t},\n\n\t/**\n\t * DB2 Server.\n\t */\n\tDB2(\"DB2\", \"com.ibm.db2.jcc.DB2Driver\", \"com.ibm.db2.jcc.DB2XADataSource\", \"SELECT 1 FROM SYSIBM.SYSDUMMY1\") {\n\n\t\t@Override\n\t\tprotected boolean matchProductName(String productName) {\n\t\t\treturn super.matchProductName(productName) || productName.toLowerCase(Locale.ENGLISH).startsWith(\"db2/\");\n\t\t}\n\t},\n\n\t/**\n\t * DB2 AS400 Server.\n\t */\n\tDB2_AS400(\"DB2 UDB for AS/400\", \"com.ibm.as400.access.AS400JDBCDriver\",\n\t\t\t\"com.ibm.as400.access.AS400JDBCXADataSource\", \"SELECT 1 FROM SYSIBM.SYSDUMMY1\") {\n\n\t\t@Override\n\t\tpublic String getId() {\n\t\t\treturn \"db2\";\n\t\t}\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Collections.singleton(\"as400\");\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matchProductName(String productName) {\n\t\t\treturn super.matchProductName(productName) || productName.toLowerCase(Locale.ENGLISH).contains(\"as/400\");\n\t\t}\n\t},\n\n\t/**\n\t * Teradata.\n\t */\n\tTERADATA(\"Teradata\", \"com.teradata.jdbc.TeraDriver\"),\n\n\t/**\n\t * Informix.\n\t */\n\tINFORMIX(\"Informix Dynamic Server\", \"com.informix.jdbc.IfxDriver\", null, \"select count(*) from systables\") {\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Arrays.asList(\"informix-sqli\", \"informix-direct\");\n\t\t}\n\n\t},\n\n\t/**\n\t * Apache Phoenix.\n\t * @since 2.5.0\n\t */\n\tPHOENIX(\"Apache Phoenix\", \"org.apache.phoenix.jdbc.PhoenixDriver\", null, \"SELECT 1 FROM SYSTEM.CATALOG LIMIT 1\"),\n\n\t/**\n\t * Testcontainers.\n\t */\n\tTESTCONTAINERS(null, \"org.testcontainers.jdbc.ContainerDatabaseDriver\") {\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Collections.singleton(\"tc\");\n\t\t}\n\n\t},\n\n\t/**\n\t * ClickHouse.\n\t * @since 3.4.0\n\t */\n\tCLICKHOUSE(\"ClickHouse\", \"com.clickhouse.jdbc.ClickHouseDriver\", null, \"SELECT 1\") {\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Arrays.asList(\"ch\", \"clickhouse\");\n\t\t}\n\n\t},\n\n\t/**\n\t * AWS Advanced JDBC Wrapper.\n\t * @since 3.5.0\n\t */\n\tAWS_WRAPPER(null, \"software.amazon.jdbc.Driver\") {\n\n\t\t@Override\n\t\tprotected Collection<String> getUrlPrefixes() {\n\t\t\treturn Collections.singleton(\"aws-wrapper\");\n\t\t}\n\n\t};\n\n\tprivate final @Nullable String productName;\n\n\tprivate final @Nullable String driverClassName;\n\n\tprivate final @Nullable String xaDataSourceClassName;\n\n\tprivate final @Nullable String validationQuery;\n\n\tDatabaseDriver(@Nullable String productName, @Nullable String driverClassName) {\n\t\tthis(productName, driverClassName, null);\n\t}\n\n\tDatabaseDriver(@Nullable String productName, @Nullable String driverClassName,\n\t\t\t@Nullable String xaDataSourceClassName) {\n\t\tthis(productName, driverClassName, xaDataSourceClassName, null);\n\t}\n\n\tDatabaseDriver(@Nullable String productName, @Nullable String driverClassName,\n\t\t\t@Nullable String xaDataSourceClassName, @Nullable String validationQuery) {\n\t\tthis.productName = productName;\n\t\tthis.driverClassName = driverClassName;\n\t\tthis.xaDataSourceClassName = xaDataSourceClassName;\n\t\tthis.validationQuery = validationQuery;\n\t}\n\n\t/**\n\t * Return the identifier of this driver.\n\t * @return the identifier\n\t */\n\tpublic String getId() {\n\t\treturn name().toLowerCase(Locale.ENGLISH);\n\t}\n\n\t/**\n\t * Return the url prefixes of this driver.\n\t * @return the url prefixes\n\t */\n\tprotected Collection<String> getUrlPrefixes() {\n\t\treturn Collections.singleton(name().toLowerCase(Locale.ENGLISH));\n\t}\n\n\tprotected boolean matchProductName(String productName) {\n\t\treturn this.productName != null && this.productName.equalsIgnoreCase(productName);\n\t}\n\n\t/**\n\t * Return the driver class name.\n\t * @return the class name or {@code null}\n\t */\n\tpublic @Nullable String getDriverClassName() {\n\t\treturn this.driverClassName;\n\t}\n\n\t/**\n\t * Return the XA driver source class name.\n\t * @return the class name or {@code null}\n\t */\n\tpublic @Nullable String getXaDataSourceClassName() {\n\t\treturn this.xaDataSourceClassName;\n\t}\n\n\t/**\n\t * Return the validation query.\n\t * @return the validation query or {@code null}\n\t */\n\tpublic @Nullable String getValidationQuery() {\n\t\treturn this.validationQuery;\n\t}\n\n\t/**\n\t * Find a {@link DatabaseDriver} for the given URL.\n\t * @param url the JDBC URL\n\t * @return the database driver or {@link #UNKNOWN} if not found\n\t */\n\tpublic static DatabaseDriver fromJdbcUrl(@Nullable String url) {\n\t\tif (StringUtils.hasLength(url)) {\n\t\t\tAssert.isTrue(url.startsWith(\"jdbc\"), \"'url' must start with \\\"jdbc\\\"\");\n\t\t\tString urlWithoutPrefix = url.substring(\"jdbc\".length()).toLowerCase(Locale.ENGLISH);\n\t\t\tfor (DatabaseDriver driver : values()) {\n\t\t\t\tfor (String urlPrefix : driver.getUrlPrefixes()) {\n\t\t\t\t\tString prefix = \":\" + urlPrefix + \":\";\n\t\t\t\t\tif (driver != UNKNOWN && urlWithoutPrefix.startsWith(prefix)) {\n\t\t\t\t\t\treturn driver;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn UNKNOWN;\n\t}\n\n\t/**\n\t * Find a {@link DatabaseDriver} for the given product name.\n\t * @param productName product name\n\t * @return the database driver or {@link #UNKNOWN} if not found\n\t */\n\tpublic static DatabaseDriver fromProductName(@Nullable String productName) {\n\t\tif (StringUtils.hasLength(productName)) {\n\t\t\tfor (DatabaseDriver candidate : values()) {\n\t\t\t\tif (candidate.matchProductName(productName)) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn UNKNOWN;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/EmbeddedDatabaseConnection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\nimport java.util.Locale;\nimport java.util.stream.Stream;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.function.ThrowingFunction;\n\n/**\n * Connection details for {@link EmbeddedDatabaseType embedded databases}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Nidhi Desai\n * @author Moritz Halbritter\n * @since 1.0.0\n * @see #get(ClassLoader)\n */\npublic enum EmbeddedDatabaseConnection {\n\n\t/**\n\t * No Connection.\n\t */\n\tNONE(null),\n\n\t/**\n\t * H2 Database Connection.\n\t */\n\tH2(\"jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\"),\n\n\t/**\n\t * Derby Database Connection.\n\t * @deprecated since 4.1.0 for removal in 4.3.0 as Derby is EOL.\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tDERBY(\"jdbc:derby:memory:%s;create=true\"),\n\n\t/**\n\t * HSQL Database Connection.\n\t * @since 2.4.0\n\t */\n\tHSQLDB(\"org.hsqldb.jdbcDriver\", \"jdbc:hsqldb:mem:%s\");\n\n\tprivate final @Nullable String alternativeDriverClass;\n\n\tprivate final @Nullable String url;\n\n\tEmbeddedDatabaseConnection(@Nullable String url) {\n\t\tthis(null, url);\n\t}\n\n\tEmbeddedDatabaseConnection(@Nullable String fallbackDriverClass, @Nullable String url) {\n\t\tthis.alternativeDriverClass = fallbackDriverClass;\n\t\tthis.url = url;\n\t}\n\n\t/**\n\t * Returns the driver class name.\n\t * @return the driver class name\n\t */\n\t@SuppressWarnings(\"removal\")\n\tpublic @Nullable String getDriverClassName() {\n\t\t// See https://github.com/spring-projects/spring-boot/issues/32865\n\t\treturn switch (this) {\n\t\t\tcase NONE -> null;\n\t\t\tcase H2 -> DatabaseDriver.H2.getDriverClassName();\n\t\t\tcase DERBY -> DatabaseDriver.DERBY.getDriverClassName();\n\t\t\tcase HSQLDB -> DatabaseDriver.HSQLDB.getDriverClassName();\n\t\t};\n\t}\n\n\t/**\n\t * Returns the {@link EmbeddedDatabaseType} for the connection.\n\t * @return the database type\n\t */\n\tpublic @Nullable EmbeddedDatabaseType getType() {\n\t\t// See https://github.com/spring-projects/spring-boot/issues/32865\n\t\treturn switch (this) {\n\t\t\tcase NONE -> null;\n\t\t\tcase H2 -> EmbeddedDatabaseType.H2;\n\t\t\tcase DERBY -> EmbeddedDatabaseType.DERBY;\n\t\t\tcase HSQLDB -> EmbeddedDatabaseType.HSQL;\n\t\t};\n\t}\n\n\t/**\n\t * Returns the URL for the connection using the specified {@code databaseName}.\n\t * @param databaseName the name of the database\n\t * @return the connection URL\n\t */\n\tpublic @Nullable String getUrl(String databaseName) {\n\t\tAssert.hasText(databaseName, \"'databaseName' must not be empty\");\n\t\treturn (this.url != null) ? String.format(this.url, databaseName) : null;\n\t}\n\n\tboolean isEmbeddedUrl(String url) {\n\t\t// See https://github.com/spring-projects/spring-boot/issues/32865\n\t\treturn switch (this) {\n\t\t\tcase NONE -> false;\n\t\t\tcase H2 -> url.contains(\":h2:mem\");\n\t\t\tcase DERBY -> true;\n\t\t\tcase HSQLDB -> url.contains(\":hsqldb:mem:\");\n\t\t};\n\t}\n\n\tboolean isDriverCompatible(@Nullable String driverClass) {\n\t\treturn (driverClass != null\n\t\t\t\t&& (driverClass.equals(getDriverClassName()) || driverClass.equals(this.alternativeDriverClass)));\n\t}\n\n\t/**\n\t * Convenience method to determine if a given driver class name and url represent an\n\t * embedded database type.\n\t * @param driverClass the driver class\n\t * @param url the jdbc url (can be {@code null})\n\t * @return true if the driver class and url refer to an embedded database\n\t * @since 2.4.0\n\t */\n\tpublic static boolean isEmbedded(@Nullable String driverClass, @Nullable String url) {\n\t\tif (driverClass == null) {\n\t\t\treturn false;\n\t\t}\n\t\tEmbeddedDatabaseConnection connection = getEmbeddedDatabaseConnection(driverClass);\n\t\tif (connection == NONE) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (url == null || connection.isEmbeddedUrl(url));\n\t}\n\n\tprivate static EmbeddedDatabaseConnection getEmbeddedDatabaseConnection(String driverClass) {\n\t\treturn Stream.of(H2, HSQLDB, DERBY)\n\t\t\t.filter((connection) -> connection.isDriverCompatible(driverClass))\n\t\t\t.findFirst()\n\t\t\t.orElse(NONE);\n\t}\n\n\t/**\n\t * Convenience method to determine if a given data source represents an embedded\n\t * database type.\n\t * @param dataSource the data source to interrogate\n\t * @return true if the data source is one of the embedded types\n\t */\n\tpublic static boolean isEmbedded(DataSource dataSource) {\n\t\ttry (Connection connection = dataSource.getConnection()) {\n\t\t\treturn new IsEmbedded().apply(connection);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\t// Could not connect, which means it's not embedded\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the most suitable {@link EmbeddedDatabaseConnection} for the given class\n\t * loader.\n\t * @param classLoader the class loader used to check for classes\n\t * @return an {@link EmbeddedDatabaseConnection} or {@link #NONE}.\n\t */\n\tpublic static EmbeddedDatabaseConnection get(@Nullable ClassLoader classLoader) {\n\t\tfor (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) {\n\t\t\tif (candidate == NONE) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tString driverClassName = candidate.getDriverClassName();\n\t\t\tAssert.state(driverClassName != null, \"'driverClassName' must not be null\");\n\t\t\tif (ClassUtils.isPresent(driverClassName, classLoader)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn NONE;\n\t}\n\n\t/**\n\t * Determine if a {@link Connection} is embedded.\n\t */\n\tprivate static final class IsEmbedded implements ThrowingFunction<Connection, Boolean> {\n\n\t\t@Override\n\t\tpublic Boolean applyWithException(Connection connection) throws SQLException, DataAccessException {\n\t\t\tDatabaseMetaData metaData = connection.getMetaData();\n\t\t\tString productName = metaData.getDatabaseProductName();\n\t\t\tif (productName == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tproductName = productName.toUpperCase(Locale.ENGLISH);\n\t\t\tEmbeddedDatabaseConnection[] candidates = EmbeddedDatabaseConnection.values();\n\t\t\tfor (EmbeddedDatabaseConnection candidate : candidates) {\n\t\t\t\tif (candidate == NONE) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tEmbeddedDatabaseType type = candidate.getType();\n\t\t\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\t\t\tif (productName.contains(type.name())) {\n\t\t\t\t\tString url = metaData.getURL();\n\t\t\t\t\treturn (url == null || candidate.isEmbeddedUrl(url));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/HikariCheckpointRestoreLifecycle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.lang.reflect.Field;\nimport java.time.Duration;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariConfigMXBean;\nimport com.zaxxer.hikari.HikariDataSource;\nimport com.zaxxer.hikari.HikariPoolMXBean;\nimport com.zaxxer.hikari.pool.HikariPool;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.Lifecycle;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link Lifecycle} for a {@link HikariDataSource} allowing it to participate in\n * checkpoint-restore. When {@link #stop() stopped}, and the data source\n * {@link HikariDataSource#isAllowPoolSuspension() allows it}, its pool is suspended,\n * blocking any attempts to borrow connections. Open and idle connections are then\n * evicted. When subsequently {@link #start() started}, the pool is\n * {@link HikariPoolMXBean#resumePool() resumed} if necessary.\n *\n * @author Christoph Strobl\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @since 3.2.0\n */\npublic class HikariCheckpointRestoreLifecycle implements Lifecycle {\n\n\tprivate static final Log logger = LogFactory.getLog(HikariCheckpointRestoreLifecycle.class);\n\n\tprivate static final Field CLOSE_CONNECTION_EXECUTOR;\n\n\tstatic {\n\t\tField closeConnectionExecutor = ReflectionUtils.findField(HikariPool.class, \"closeConnectionExecutor\");\n\t\tAssert.state(closeConnectionExecutor != null, \"Unable to locate closeConnectionExecutor for HikariPool\");\n\t\tAssert.state(ThreadPoolExecutor.class.isAssignableFrom(closeConnectionExecutor.getType()),\n\t\t\t\t() -> \"Expected ThreadPoolExecutor for closeConnectionExecutor but found %s\"\n\t\t\t\t\t.formatted(closeConnectionExecutor.getType()));\n\t\tReflectionUtils.makeAccessible(closeConnectionExecutor);\n\t\tCLOSE_CONNECTION_EXECUTOR = closeConnectionExecutor;\n\t}\n\n\tprivate final Function<HikariPool, Boolean> hasOpenConnections;\n\n\tprivate final @Nullable HikariDataSource dataSource;\n\n\tprivate final ConfigurableApplicationContext applicationContext;\n\n\t/**\n\t * Creates a new {@code HikariCheckpointRestoreLifecycle} that will allow the given\n\t * {@code dataSource} to participate in checkpoint-restore. The {@code dataSource} is\n\t * {@link DataSourceUnwrapper#unwrap unwrapped} to a {@link HikariDataSource}. If such\n\t * unwrapping is not possible, the lifecycle will have no effect.\n\t * @param dataSource the checkpoint-restore participant\n\t * @param applicationContext the application context\n\t * @since 3.4.0\n\t */\n\tpublic HikariCheckpointRestoreLifecycle(DataSource dataSource, ConfigurableApplicationContext applicationContext) {\n\t\tthis.dataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class, HikariDataSource.class);\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.hasOpenConnections = (pool) -> {\n\t\t\tThreadPoolExecutor closeConnectionExecutor = (ThreadPoolExecutor) ReflectionUtils\n\t\t\t\t.getField(CLOSE_CONNECTION_EXECUTOR, pool);\n\t\t\tAssert.state(closeConnectionExecutor != null, \"'closeConnectionExecutor' was null\");\n\t\t\treturn closeConnectionExecutor.getActiveCount() > 0;\n\t\t};\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tif (this.dataSource == null || this.dataSource.isRunning()) {\n\t\t\treturn;\n\t\t}\n\t\tAssert.state(!this.dataSource.isClosed(), \"DataSource has been closed and cannot be restarted\");\n\t\tif (this.dataSource.isAllowPoolSuspension()) {\n\t\t\tlogger.info(\"Resuming Hikari pool\");\n\t\t\tthis.dataSource.getHikariPoolMXBean().resumePool();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tif (this.dataSource == null || !this.dataSource.isRunning()) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.dataSource.isAllowPoolSuspension()) {\n\t\t\tlogger.info(\"Suspending Hikari pool\");\n\t\t\tthis.dataSource.getHikariPoolMXBean().suspendPool();\n\t\t}\n\t\telse {\n\t\t\tif (this.applicationContext != null && !this.applicationContext.isClosed()) {\n\t\t\t\tlogger.warn(this.dataSource + \" is not configured to allow pool suspension. \"\n\t\t\t\t\t\t+ \"This will cause problems when the application is checkpointed. \"\n\t\t\t\t\t\t+ \"Please configure allow-pool-suspension to fix this!\");\n\t\t\t}\n\t\t}\n\t\tcloseConnections(this.dataSource, Duration.ofMillis(this.dataSource.getConnectionTimeout() + 250));\n\t}\n\n\tprivate void closeConnections(HikariDataSource dataSource, Duration shutdownTimeout) {\n\t\tlogger.info(\"Evicting Hikari connections\");\n\t\tdataSource.getHikariPoolMXBean().softEvictConnections();\n\t\tlogger.debug(LogMessage.format(\"Waiting %d seconds for Hikari connections to be closed\",\n\t\t\t\tshutdownTimeout.toSeconds()));\n\t\tCompletableFuture<Void> allConnectionsClosed = CompletableFuture\n\t\t\t.runAsync(() -> this.waitForConnectionsToClose(dataSource));\n\t\ttry {\n\t\t\tallConnectionsClosed.get(shutdownTimeout.toMillis(), TimeUnit.MILLISECONDS);\n\t\t\tlogger.debug(\"Hikari connections closed\");\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tlogger.warn(\"Interrupted while waiting for connections to be closed\", ex);\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t\tcatch (TimeoutException ex) {\n\t\t\tlogger.warn(LogMessage.format(\"Hikari connections could not be closed within %s\", shutdownTimeout), ex);\n\t\t}\n\t\tcatch (ExecutionException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to close Hikari connections\", ex);\n\t\t}\n\t}\n\n\tprivate void waitForConnectionsToClose(HikariDataSource dataSource) {\n\t\twhile (this.hasOpenConnections.apply((HikariPool) dataSource.getHikariPoolMXBean())) {\n\t\t\ttry {\n\t\t\t\tTimeUnit.MILLISECONDS.sleep(50);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tlogger.error(\"Interrupted while waiting for datasource connections to be closed\", ex);\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn this.dataSource != null && this.dataSource.isRunning();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/SchemaManagement.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\n/**\n * An enumeration of the available schema management options.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic enum SchemaManagement {\n\n\t/**\n\t * The schema is managed and will be created at the appropriate time.\n\t */\n\tMANAGED,\n\n\t/**\n\t * The schema is not managed.\n\t */\n\tUNMANAGED\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/SchemaManagementProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport javax.sql.DataSource;\n\n/**\n * Strategy interface to determine the {@link SchemaManagement} of a {@link DataSource}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface SchemaManagementProvider {\n\n\t/**\n\t * Return the {@link SchemaManagement} for the specified {@link DataSource}.\n\t * @param dataSource the dataSource to handle\n\t * @return the {@link SchemaManagement} for the {@link DataSource}.\n\t */\n\tSchemaManagement getSchemaManagement(DataSource dataSource);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/SpringJdbcDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;\nimport org.springframework.jdbc.core.simple.JdbcClient;\n\n/**\n * {@link DependsOnDatabaseInitializationDetector} for Spring Framework's JDBC support.\n *\n * @author Andy Wilkinson\n */\nclass SpringJdbcDependsOnDatabaseInitializationDetector\n\t\textends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\treturn Set.of(JdbcClient.class, JdbcOperations.class, NamedParameterJdbcOperations.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/UnsupportedDataSourcePropertyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.util.function.Supplier;\n\n/**\n * {@link RuntimeException} thrown from {@link DataSourceBuilder} when an unsupported\n * property is used.\n *\n * @author Phillip Webb\n * @since 2.5.0\n */\npublic class UnsupportedDataSourcePropertyException extends RuntimeException {\n\n\tUnsupportedDataSourcePropertyException(String message) {\n\t\tsuper(message);\n\t}\n\n\tstatic void throwIf(boolean test, Supplier<String> message) {\n\t\tif (test) {\n\t\t\tthrow new UnsupportedDataSourcePropertyException(message.get());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/XADataSourceWrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport javax.sql.DataSource;\nimport javax.sql.XADataSource;\n\nimport jakarta.transaction.TransactionManager;\n\n/**\n * Strategy interface used to wrap an {@link XADataSource} enrolling it with a JTA\n * {@link TransactionManager}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface XADataSourceWrapper {\n\n\t/**\n\t * Wrap the specific {@link XADataSource} and enroll it with a JTA\n\t * {@link TransactionManager}.\n\t * @param dataSource the data source to wrap\n\t * @return the wrapped data source\n\t * @throws Exception if the data source cannot be wrapped\n\t */\n\tDataSource wrapDataSource(XADataSource dataSource) throws Exception;\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/ApplicationDataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.ApplicationScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.SqlInitializationProperties;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\n\n/**\n * {@link DataSourceScriptDatabaseInitializer} for the primary SQL database. May be\n * registered as a bean to override auto-configuration.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ApplicationDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer\n\t\timplements ApplicationScriptDatabaseInitializer {\n\n\t/**\n\t * Create a new {@link ApplicationDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the primary SQL data source\n\t * @param properties the SQL initialization properties\n\t */\n\tpublic ApplicationDataSourceScriptDatabaseInitializer(DataSource dataSource,\n\t\t\tSqlInitializationProperties properties) {\n\t\tthis(dataSource, ApplicationScriptDatabaseInitializer.getSettings(properties));\n\t}\n\n\t/**\n\t * Create a new {@link ApplicationDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the primary SQL data source\n\t * @param settings the database initialization settings\n\t */\n\tpublic ApplicationDataSourceScriptDatabaseInitializer(DataSource dataSource,\n\t\t\tDatabaseInitializationSettings settings) {\n\t\tsuper(dataSource, settings);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\nimport javax.sql.XADataSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Kazuki Shimizu\n * @author Olga Maciaszek-Sharma\n * @since 4.0.0\n */\n@AutoConfiguration(before = DataSourceInitializationAutoConfiguration.class)\n@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })\n@ConditionalOnMissingBean(type = \"io.r2dbc.spi.ConnectionFactory\")\n@EnableConfigurationProperties(DataSourceProperties.class)\n@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceCheckpointRestoreConfiguration.class })\npublic final class DataSourceAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(EmbeddedDatabaseCondition.class)\n\t@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\tprotected static class EmbeddedDatabaseConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(PooledDataSourceCondition.class)\n\t@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })\n\t@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,\n\t\t\tDataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,\n\t\t\tDataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })\n\tprotected static class PooledDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(JdbcConnectionDetails.class)\n\t\tPropertiesJdbcConnectionDetails jdbcConnectionDetails(DataSourceProperties properties) {\n\t\t\treturn new PropertiesJdbcConnectionDetails(properties);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link AnyNestedCondition} that checks that either {@code spring.datasource.type}\n\t * is set or {@link PooledDataSourceAvailableCondition} applies.\n\t */\n\tstatic class PooledDataSourceCondition extends AnyNestedCondition {\n\n\t\tPooledDataSourceCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.datasource.type\")\n\t\tstatic class ExplicitType {\n\n\t\t}\n\n\t\t@Conditional(PooledDataSourceAvailableCondition.class)\n\t\tstatic class PooledDataSourceAvailable {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Condition} to test if a supported connection pool is available.\n\t */\n\tstatic class PooledDataSourceAvailableCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"PooledDataSource\");\n\t\t\tif (DataSourceBuilder.findType(context.getClassLoader()) != null) {\n\t\t\t\treturn ConditionOutcome.match(message.foundExactly(\"supported DataSource\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"supported DataSource\").atAll());\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Condition} to detect when an embedded {@link DataSource} type can be used.\n\t * If a pooled {@link DataSource} is available, it will always be preferred to an\n\t * {@code EmbeddedDatabase}.\n\t */\n\tstatic class EmbeddedDatabaseCondition extends SpringBootCondition {\n\n\t\tprivate static final String DATASOURCE_URL_PROPERTY = \"spring.datasource.url\";\n\n\t\tprivate static final String EMBEDDED_DATABASE_TYPE = \"org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType\";\n\n\t\tprivate final SpringBootCondition pooledCondition = new PooledDataSourceCondition();\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"EmbeddedDataSource\");\n\t\t\tif (hasDataSourceUrlProperty(context)) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.because(DATASOURCE_URL_PROPERTY + \" is set\"));\n\t\t\t}\n\t\t\tif (anyMatches(context, metadata, this.pooledCondition)) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.foundExactly(\"supported pooled data source\"));\n\t\t\t}\n\t\t\tif (!ClassUtils.isPresent(EMBEDDED_DATABASE_TYPE, context.getClassLoader())) {\n\t\t\t\treturn ConditionOutcome\n\t\t\t\t\t.noMatch(message.didNotFind(\"required class\").items(Style.QUOTE, EMBEDDED_DATABASE_TYPE));\n\t\t\t}\n\t\t\tEmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();\n\t\t\tif (type == null) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"embedded database\").atAll());\n\t\t\t}\n\t\t\treturn ConditionOutcome.match(message.found(\"embedded database\").items(type));\n\t\t}\n\n\t\tprivate boolean hasDataSourceUrlProperty(ConditionContext context) {\n\t\t\tEnvironment environment = context.getEnvironment();\n\t\t\tif (environment.containsProperty(DATASOURCE_URL_PROPERTY)) {\n\t\t\t\ttry {\n\t\t\t\t\treturn StringUtils.hasText(environment.getProperty(DATASOURCE_URL_PROPERTY));\n\t\t\t\t}\n\t\t\t\tcatch (IllegalArgumentException ex) {\n\t\t\t\t\t// NOTE: This should be PlaceholderResolutionException\n\t\t\t\t\t// Ignore unresolvable placeholder errors\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceBeanCreationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties.DataSourceBeanCreationException;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link AbstractFailureAnalyzer} for failures caused by a\n * {@link DataSourceBeanCreationException}.\n *\n * @author Andy Wilkinson\n * @author Patryk Kostrzewa\n * @author Stephane Nicoll\n */\nclass DataSourceBeanCreationFailureAnalyzer extends AbstractFailureAnalyzer<DataSourceBeanCreationException> {\n\n\tprivate final Environment environment;\n\n\tDataSourceBeanCreationFailureAnalyzer(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, DataSourceBeanCreationException cause) {\n\t\treturn getFailureAnalysis(cause);\n\t}\n\n\tprivate FailureAnalysis getFailureAnalysis(DataSourceBeanCreationException cause) {\n\t\tString description = getDescription(cause);\n\t\tString action = getAction(cause);\n\t\treturn new FailureAnalysis(description, action, cause);\n\t}\n\n\tprivate String getDescription(DataSourceBeanCreationException cause) {\n\t\tStringBuilder description = new StringBuilder();\n\t\tdescription.append(\"Failed to configure a DataSource: \");\n\t\tif (!StringUtils.hasText(cause.getProperties().getUrl())) {\n\t\t\tdescription.append(\"'url' attribute is not specified and \");\n\t\t}\n\t\tdescription.append(String.format(\"no embedded datasource could be configured.%n\"));\n\t\tdescription.append(String.format(\"%nReason: %s%n\", cause.getMessage()));\n\t\treturn description.toString();\n\t}\n\n\tprivate String getAction(DataSourceBeanCreationException cause) {\n\t\tStringBuilder action = new StringBuilder();\n\t\taction.append(String.format(\"Consider the following:%n\"));\n\t\tif (EmbeddedDatabaseConnection.NONE == cause.getConnection()) {\n\t\t\taction.append(String\n\t\t\t\t.format(\"\\tIf you want an embedded database (H2, HSQL or Derby), please put it on the classpath.%n\"));\n\t\t}\n\t\telse {\n\t\t\taction.append(String.format(\"\\tReview the configuration of %s%n.\", cause.getConnection()));\n\t\t}\n\t\taction\n\t\t\t.append(\"\\tIf you have database settings to be loaded from a particular \"\n\t\t\t\t\t+ \"profile you may need to activate it\")\n\t\t\t.append(getActiveProfiles());\n\t\treturn action.toString();\n\t}\n\n\tprivate String getActiveProfiles() {\n\t\tStringBuilder message = new StringBuilder();\n\t\tString[] profiles = this.environment.getActiveProfiles();\n\t\tif (ObjectUtils.isEmpty(profiles)) {\n\t\t\tmessage.append(\" (no profiles are currently active).\");\n\t\t}\n\t\telse {\n\t\t\tmessage.append(\" (the profiles \");\n\t\t\tmessage.append(StringUtils.arrayToCommaDelimitedString(profiles));\n\t\t\tmessage.append(\" are currently active).\");\n\t\t}\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceCheckpointRestoreConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnCheckpointRestore;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.jdbc.HikariCheckpointRestoreLifecycle;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Checkpoint-restore specific configuration.\n *\n * @author Olga Maciaszek-Sharma\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnCheckpointRestore\n@ConditionalOnBean(DataSource.class)\nclass DataSourceCheckpointRestoreConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HikariDataSource.class)\n\tstatic class Hikari {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tHikariCheckpointRestoreLifecycle hikariCheckpointRestoreLifecycle(DataSource dataSource,\n\t\t\t\tConfigurableApplicationContext applicationContext) {\n\t\t\treturn new HikariCheckpointRestoreLifecycle(dataSource, applicationContext);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport oracle.jdbc.OracleConnection;\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * Actual DataSource configurations imported by {@link DataSourceAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Fabio Grassi\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nabstract class DataSourceConfiguration {\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <T> T createDataSource(JdbcConnectionDetails connectionDetails,\n\t\t\t@Nullable Class<? extends DataSource> type, ClassLoader classLoader) {\n\t\treturn createDataSource(connectionDetails, type, classLoader, true);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <T> T createDataSource(JdbcConnectionDetails connectionDetails,\n\t\t\t@Nullable Class<? extends DataSource> type, ClassLoader classLoader, boolean applyDriverClassName) {\n\t\tDataSourceBuilder<? extends DataSource> builder = DataSourceBuilder.create(classLoader).type(type);\n\t\tif (applyDriverClassName) {\n\t\t\tbuilder.driverClassName(connectionDetails.getDriverClassName());\n\t\t}\n\t\treturn (T) builder.url(connectionDetails.getJdbcUrl())\n\t\t\t.username(connectionDetails.getUsername())\n\t\t\t.password(connectionDetails.getPassword())\n\t\t\t.build();\n\t}\n\n\t/**\n\t * Tomcat Pool DataSource configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)\n\t@ConditionalOnMissingBean(DataSource.class)\n\t@ConditionalOnProperty(name = \"spring.datasource.type\", havingValue = \"org.apache.tomcat.jdbc.pool.DataSource\",\n\t\t\tmatchIfMissing = true)\n\tstatic class Tomcat {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(PropertiesJdbcConnectionDetails.class)\n\t\tstatic TomcatJdbcConnectionDetailsBeanPostProcessor tomcatJdbcConnectionDetailsBeanPostProcessor(\n\t\t\t\tObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\t\treturn new TomcatJdbcConnectionDetailsBeanPostProcessor(connectionDetailsProvider);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spring.datasource.tomcat\")\n\t\torg.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties,\n\t\t\t\tJdbcConnectionDetails connectionDetails) {\n\t\t\tClass<? extends DataSource> dataSourceType = org.apache.tomcat.jdbc.pool.DataSource.class;\n\t\t\torg.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(connectionDetails, dataSourceType,\n\t\t\t\t\tproperties.getClassLoader());\n\t\t\tString validationQuery;\n\t\t\tDatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(connectionDetails.getJdbcUrl());\n\t\t\tvalidationQuery = databaseDriver.getValidationQuery();\n\t\t\tif (validationQuery != null) {\n\t\t\t\tdataSource.setTestOnBorrow(true);\n\t\t\t\tdataSource.setValidationQuery(validationQuery);\n\t\t\t}\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t/**\n\t * Hikari DataSource configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HikariDataSource.class)\n\t@ConditionalOnMissingBean(DataSource.class)\n\t@ConditionalOnProperty(name = \"spring.datasource.type\", havingValue = \"com.zaxxer.hikari.HikariDataSource\",\n\t\t\tmatchIfMissing = true)\n\tstatic class Hikari {\n\n\t\t@Bean\n\t\tstatic HikariJdbcConnectionDetailsBeanPostProcessor jdbcConnectionDetailsHikariBeanPostProcessor(\n\t\t\t\tObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\t\treturn new HikariJdbcConnectionDetailsBeanPostProcessor(connectionDetailsProvider);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spring.datasource.hikari\")\n\t\tHikariDataSource dataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails,\n\t\t\t\tEnvironment environment) {\n\t\t\tString dataSourceClassName = environment.getProperty(\"spring.datasource.hikari.data-source-class-name\");\n\t\t\tHikariDataSource dataSource = createDataSource(connectionDetails, HikariDataSource.class,\n\t\t\t\t\tproperties.getClassLoader(), dataSourceClassName == null);\n\t\t\tif (StringUtils.hasText(properties.getName())) {\n\t\t\t\tdataSource.setPoolName(properties.getName());\n\t\t\t}\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t/**\n\t * DBCP DataSource configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)\n\t@ConditionalOnMissingBean(DataSource.class)\n\t@ConditionalOnProperty(name = \"spring.datasource.type\", havingValue = \"org.apache.commons.dbcp2.BasicDataSource\",\n\t\t\tmatchIfMissing = true)\n\tstatic class Dbcp2 {\n\n\t\t@Bean\n\t\tstatic Dbcp2JdbcConnectionDetailsBeanPostProcessor dbcp2JdbcConnectionDetailsBeanPostProcessor(\n\t\t\t\tObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\t\treturn new Dbcp2JdbcConnectionDetailsBeanPostProcessor(connectionDetailsProvider);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spring.datasource.dbcp2\")\n\t\torg.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties,\n\t\t\t\tJdbcConnectionDetails connectionDetails) {\n\t\t\tClass<? extends DataSource> dataSourceType = org.apache.commons.dbcp2.BasicDataSource.class;\n\t\t\treturn createDataSource(connectionDetails, dataSourceType, properties.getClassLoader());\n\t\t}\n\n\t}\n\n\t/**\n\t * Oracle UCP DataSource configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ PoolDataSourceImpl.class, OracleConnection.class })\n\t@ConditionalOnMissingBean(DataSource.class)\n\t@ConditionalOnProperty(name = \"spring.datasource.type\", havingValue = \"oracle.ucp.jdbc.PoolDataSource\",\n\t\t\tmatchIfMissing = true)\n\tstatic class OracleUcp {\n\n\t\t@Bean\n\t\tstatic OracleUcpJdbcConnectionDetailsBeanPostProcessor oracleUcpJdbcConnectionDetailsBeanPostProcessor(\n\t\t\t\tObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\t\treturn new OracleUcpJdbcConnectionDetailsBeanPostProcessor(connectionDetailsProvider);\n\t\t}\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spring.datasource.oracleucp\")\n\t\tPoolDataSourceImpl dataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails)\n\t\t\t\tthrows SQLException {\n\t\t\tPoolDataSourceImpl dataSource = createDataSource(connectionDetails, PoolDataSourceImpl.class,\n\t\t\t\t\tproperties.getClassLoader());\n\t\t\tif (StringUtils.hasText(properties.getName())) {\n\t\t\t\tdataSource.setConnectionPoolName(properties.getName());\n\t\t\t}\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t/**\n\t * Generic DataSource configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(DataSource.class)\n\t@ConditionalOnProperty(name = \"spring.datasource.type\")\n\tstatic class Generic {\n\n\t\t@Bean\n\t\tDataSource dataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails) {\n\t\t\treturn createDataSource(connectionDetails, properties.getType(), properties.getClassLoader());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceInitializationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.sql.autoconfigure.init.ApplicationScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.ConditionalOnSqlInitialization;\nimport org.springframework.boot.sql.autoconfigure.init.SqlInitializationProperties;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.datasource.init.DatabasePopulator;\nimport org.springframework.util.StringUtils;\n\n/**\n * Auto-configuration for {@link DataSource} initialization.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnMissingBean(ApplicationScriptDatabaseInitializer.class)\n@ConditionalOnSingleCandidate(DataSource.class)\n@ConditionalOnClass(DatabasePopulator.class)\n@Import(DatabaseInitializationDependencyConfigurer.class)\n@EnableConfigurationProperties(SqlInitializationProperties.class)\n@ConditionalOnSqlInitialization\npublic final class DataSourceInitializationAutoConfiguration {\n\n\t@Bean\n\tApplicationDataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource,\n\t\t\tSqlInitializationProperties properties) {\n\t\treturn new ApplicationDataSourceScriptDatabaseInitializer(\n\t\t\t\tdetermineDataSource(dataSource, properties.getUsername(), properties.getPassword()), properties);\n\t}\n\n\tprivate static DataSource determineDataSource(DataSource dataSource, @Nullable String username,\n\t\t\t@Nullable String password) {\n\t\tif (StringUtils.hasText(username) && StringUtils.hasText(password)) {\n\t\t\treturn DataSourceBuilder.derivedFrom(dataSource)\n\t\t\t\t.username(username)\n\t\t\t\t.password(password)\n\t\t\t\t.type(SimpleDriverDataSource.class)\n\t\t\t\t.build();\n\t\t}\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceJmxConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariConfigMXBean;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.tomcat.jdbc.pool.DataSourceProxy;\nimport org.apache.tomcat.jdbc.pool.PoolConfiguration;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.jdbc.DataSourceUnwrapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jmx.export.MBeanExporter;\n\n/**\n * Configures DataSource related MBeans.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBooleanProperty(\"spring.jmx.enabled\")\nclass DataSourceJmxConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(DataSourceJmxConfiguration.class);\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HikariDataSource.class)\n\t@ConditionalOnSingleCandidate(DataSource.class)\n\tstatic class Hikari {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprivate final ObjectProvider<MBeanExporter> mBeanExporter;\n\n\t\tHikari(DataSource dataSource, ObjectProvider<MBeanExporter> mBeanExporter) {\n\t\t\tthis.dataSource = dataSource;\n\t\t\tthis.mBeanExporter = mBeanExporter;\n\t\t\tvalidateMBeans();\n\t\t}\n\n\t\tprivate void validateMBeans() {\n\t\t\tHikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(this.dataSource, HikariConfigMXBean.class,\n\t\t\t\t\tHikariDataSource.class);\n\t\t\tif (hikariDataSource != null && hikariDataSource.isRegisterMbeans()) {\n\t\t\t\tthis.mBeanExporter.ifUnique((exporter) -> exporter.addExcludedBean(\"dataSource\"));\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(\"spring.datasource.tomcat.jmx-enabled\")\n\t@ConditionalOnClass(DataSourceProxy.class)\n\t@ConditionalOnSingleCandidate(DataSource.class)\n\tstatic class TomcatDataSourceJmxConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = \"dataSourceMBean\")\n\t\t@Nullable Object dataSourceMBean(DataSource dataSource) {\n\t\t\tDataSourceProxy dataSourceProxy = DataSourceUnwrapper.unwrap(dataSource, PoolConfiguration.class,\n\t\t\t\t\tDataSourceProxy.class);\n\t\t\tif (dataSourceProxy != null) {\n\t\t\t\ttry {\n\t\t\t\t\treturn dataSourceProxy.createPool().getJmxPool();\n\t\t\t\t}\n\t\t\t\tcatch (SQLException ex) {\n\t\t\t\t\tlogger.warn(\"Cannot expose DataSource to JMX (could not connect)\");\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourcePoolMetadataProvidersConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport com.zaxxer.hikari.HikariConfigMXBean;\nimport com.zaxxer.hikari.HikariDataSource;\nimport oracle.jdbc.OracleConnection;\nimport oracle.ucp.jdbc.PoolDataSource;\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.apache.commons.dbcp2.BasicDataSourceMXBean;\nimport org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.jdbc.DataSourceUnwrapper;\nimport org.springframework.boot.jdbc.metadata.CommonsDbcp2DataSourcePoolMetadata;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;\nimport org.springframework.boot.jdbc.metadata.OracleUcpDataSourcePoolMetadata;\nimport org.springframework.boot.jdbc.metadata.TomcatDataSourcePoolMetadata;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * Register the {@link DataSourcePoolMetadataProvider} instances for the supported data\n * sources.\n *\n * @author Stephane Nicoll\n * @author Fabio Grassi\n * @since 4.0.0\n */\n@Configuration(proxyBeanMethods = false)\npublic class DataSourcePoolMetadataProvidersConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)\n\tstatic class TomcatDataSourcePoolMetadataProviderConfiguration {\n\n\t\t@Bean\n\t\tDataSourcePoolMetadataProvider tomcatPoolDataSourceMetadataProvider() {\n\t\t\treturn (dataSource) -> {\n\t\t\t\torg.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = DataSourceUnwrapper.unwrap(dataSource,\n\t\t\t\t\t\tConnectionPoolMBean.class, org.apache.tomcat.jdbc.pool.DataSource.class);\n\t\t\t\tif (tomcatDataSource != null) {\n\t\t\t\t\treturn new TomcatDataSourcePoolMetadata(tomcatDataSource);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HikariDataSource.class)\n\t@ImportRuntimeHints(HikariDataSourcePoolMetadataRuntimeHints.class)\n\tstatic class HikariPoolDataSourceMetadataProviderConfiguration {\n\n\t\t@Bean\n\t\tDataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {\n\t\t\treturn (dataSource) -> {\n\t\t\t\tHikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class,\n\t\t\t\t\t\tHikariDataSource.class);\n\t\t\t\tif (hikariDataSource != null) {\n\t\t\t\t\treturn new HikariDataSourcePoolMetadata(hikariDataSource);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(BasicDataSource.class)\n\tstatic class CommonsDbcp2PoolDataSourceMetadataProviderConfiguration {\n\n\t\t@Bean\n\t\tDataSourcePoolMetadataProvider commonsDbcp2PoolDataSourceMetadataProvider() {\n\t\t\treturn (dataSource) -> {\n\t\t\t\tBasicDataSource dbcpDataSource = DataSourceUnwrapper.unwrap(dataSource, BasicDataSourceMXBean.class,\n\t\t\t\t\t\tBasicDataSource.class);\n\t\t\t\tif (dbcpDataSource != null) {\n\t\t\t\t\treturn new CommonsDbcp2DataSourcePoolMetadata(dbcpDataSource);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ PoolDataSource.class, OracleConnection.class })\n\tstatic class OracleUcpPoolDataSourceMetadataProviderConfiguration {\n\n\t\t@Bean\n\t\tDataSourcePoolMetadataProvider oracleUcpPoolDataSourceMetadataProvider() {\n\t\t\treturn (dataSource) -> {\n\t\t\t\tPoolDataSource ucpDataSource = DataSourceUnwrapper.unwrap(dataSource, PoolDataSource.class);\n\t\t\t\tif (ucpDataSource != null) {\n\t\t\t\t\treturn new OracleUcpDataSourcePoolMetadata(ucpDataSource);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class HikariDataSourcePoolMetadataRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(HikariDataSource.class, (builder) -> builder.withField(\"pool\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for configuration of a data source.\n *\n * @author Dave Syer\n * @author Maciej Walkowiak\n * @author Stephane Nicoll\n * @author Benedikt Ritter\n * @author Eddú Meléndez\n * @author Scott Frederick\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.datasource\")\npublic class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader classLoader;\n\n\t/**\n\t * Whether to generate a random datasource name.\n\t */\n\tprivate boolean generateUniqueName = true;\n\n\t/**\n\t * Datasource name to use if \"generate-unique-name\" is false. Defaults to \"testdb\"\n\t * when using an embedded database, otherwise null.\n\t */\n\tprivate @Nullable String name;\n\n\t/**\n\t * Fully qualified name of the DataSource implementation to use. By default, a\n\t * connection pool implementation is auto-detected from the classpath.\n\t */\n\tprivate @Nullable Class<? extends DataSource> type;\n\n\t/**\n\t * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.\n\t */\n\tprivate @Nullable String driverClassName;\n\n\t/**\n\t * JDBC URL of the database.\n\t */\n\tprivate @Nullable String url;\n\n\t/**\n\t * Login username of the database.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the database.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * JNDI location of the datasource. Class, url, username and password are ignored when\n\t * set.\n\t */\n\tprivate @Nullable String jndiName;\n\n\t/**\n\t * Connection details for an embedded database. Defaults to the most suitable embedded\n\t * database that is available on the classpath.\n\t */\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate EmbeddedDatabaseConnection embeddedDatabaseConnection;\n\n\tprivate Xa xa = new Xa();\n\n\tprivate @Nullable String uniqueName;\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (this.embeddedDatabaseConnection == null) {\n\t\t\tthis.embeddedDatabaseConnection = EmbeddedDatabaseConnection.get(this.classLoader);\n\t\t}\n\t}\n\n\t/**\n\t * Initialize a {@link DataSourceBuilder} with the state of this instance.\n\t * @return a {@link DataSourceBuilder} initialized with the customizations defined on\n\t * this instance\n\t */\n\tpublic DataSourceBuilder<?> initializeDataSourceBuilder() {\n\t\treturn DataSourceBuilder.create(getClassLoader())\n\t\t\t.type(getType())\n\t\t\t.driverClassName(determineDriverClassName())\n\t\t\t.url(determineUrl())\n\t\t\t.username(determineUsername())\n\t\t\t.password(determinePassword());\n\t}\n\n\tpublic boolean isGenerateUniqueName() {\n\t\treturn this.generateUniqueName;\n\t}\n\n\tpublic void setGenerateUniqueName(boolean generateUniqueName) {\n\t\tthis.generateUniqueName = generateUniqueName;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic @Nullable Class<? extends DataSource> getType() {\n\t\treturn this.type;\n\t}\n\n\tpublic void setType(@Nullable Class<? extends DataSource> type) {\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * Return the configured driver or {@code null} if none was configured.\n\t * @return the configured driver\n\t * @see #determineDriverClassName()\n\t */\n\tpublic @Nullable String getDriverClassName() {\n\t\treturn this.driverClassName;\n\t}\n\n\tpublic void setDriverClassName(@Nullable String driverClassName) {\n\t\tthis.driverClassName = driverClassName;\n\t}\n\n\t/**\n\t * Determine the driver to use based on this configuration and the environment.\n\t * @return the driver to use\n\t */\n\tpublic String determineDriverClassName() {\n\t\tString driverClassName = findDriverClassName();\n\t\tif (!StringUtils.hasText(driverClassName)) {\n\t\t\tthrow new DataSourceBeanCreationException(\"Failed to determine a suitable driver class\", this,\n\t\t\t\t\tthis.embeddedDatabaseConnection);\n\t\t}\n\t\treturn driverClassName;\n\t}\n\n\t@Nullable String findDriverClassName() {\n\t\tif (StringUtils.hasText(this.driverClassName)) {\n\t\t\tAssert.state(driverClassIsLoadable(this.driverClassName),\n\t\t\t\t\t() -> \"Cannot load driver class: \" + this.driverClassName);\n\t\t\treturn this.driverClassName;\n\t\t}\n\t\tString driverClassName = null;\n\t\tif (StringUtils.hasText(this.url)) {\n\t\t\tdriverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();\n\t\t}\n\t\tif (!StringUtils.hasText(driverClassName)) {\n\t\t\tdriverClassName = this.embeddedDatabaseConnection.getDriverClassName();\n\t\t}\n\t\treturn driverClassName;\n\t}\n\n\tprivate boolean driverClassIsLoadable(String driverClassName) {\n\t\ttry {\n\t\t\tClassUtils.forName(driverClassName, null);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (UnsupportedClassVersionError ex) {\n\t\t\t// Driver library has been compiled with a later JDK, propagate error\n\t\t\tthrow ex;\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Return the configured url or {@code null} if none was configured.\n\t * @return the configured url\n\t * @see #determineUrl()\n\t */\n\tpublic @Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\tpublic void setUrl(@Nullable String url) {\n\t\tthis.url = url;\n\t}\n\n\t/**\n\t * Determine the url to use based on this configuration and the environment.\n\t * @return the url to use\n\t */\n\tpublic String determineUrl() {\n\t\tif (StringUtils.hasText(this.url)) {\n\t\t\treturn this.url;\n\t\t}\n\t\tString databaseName = determineDatabaseName();\n\t\tString url = (databaseName != null) ? this.embeddedDatabaseConnection.getUrl(databaseName) : null;\n\t\tif (!StringUtils.hasText(url)) {\n\t\t\tthrow new DataSourceBeanCreationException(\"Failed to determine suitable jdbc url\", this,\n\t\t\t\t\tthis.embeddedDatabaseConnection);\n\t\t}\n\t\treturn url;\n\t}\n\n\t/**\n\t * Determine the name to used based on this configuration.\n\t * @return the database name to use or {@code null}\n\t */\n\tpublic @Nullable String determineDatabaseName() {\n\t\tif (this.generateUniqueName) {\n\t\t\tif (this.uniqueName == null) {\n\t\t\t\tthis.uniqueName = UUID.randomUUID().toString();\n\t\t\t}\n\t\t\treturn this.uniqueName;\n\t\t}\n\t\tif (StringUtils.hasLength(this.name)) {\n\t\t\treturn this.name;\n\t\t}\n\t\tif (this.embeddedDatabaseConnection != EmbeddedDatabaseConnection.NONE) {\n\t\t\treturn \"testdb\";\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the configured username or {@code null} if none was configured.\n\t * @return the configured username\n\t * @see #determineUsername()\n\t */\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\t/**\n\t * Determine the username to use based on this configuration and the environment.\n\t * @return the username to use\n\t */\n\tpublic @Nullable String determineUsername() {\n\t\tif (StringUtils.hasText(this.username)) {\n\t\t\treturn this.username;\n\t\t}\n\t\tif (EmbeddedDatabaseConnection.isEmbedded(findDriverClassName(), determineUrl())) {\n\t\t\treturn \"sa\";\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the configured password or {@code null} if none was configured.\n\t * @return the configured password\n\t * @see #determinePassword()\n\t */\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\t/**\n\t * Determine the password to use based on this configuration and the environment.\n\t * @return the password to use\n\t */\n\tpublic @Nullable String determinePassword() {\n\t\tif (StringUtils.hasText(this.password)) {\n\t\t\treturn this.password;\n\t\t}\n\t\tif (EmbeddedDatabaseConnection.isEmbedded(findDriverClassName(), determineUrl())) {\n\t\t\treturn \"\";\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic @Nullable String getJndiName() {\n\t\treturn this.jndiName;\n\t}\n\n\t/**\n\t * Allows the DataSource to be managed by the container and obtained through JNDI. The\n\t * {@code URL}, {@code driverClassName}, {@code username} and {@code password} fields\n\t * will be ignored when using JNDI lookups.\n\t * @param jndiName the JNDI name\n\t */\n\tpublic void setJndiName(@Nullable String jndiName) {\n\t\tthis.jndiName = jndiName;\n\t}\n\n\tpublic EmbeddedDatabaseConnection getEmbeddedDatabaseConnection() {\n\t\treturn this.embeddedDatabaseConnection;\n\t}\n\n\tpublic void setEmbeddedDatabaseConnection(EmbeddedDatabaseConnection embeddedDatabaseConnection) {\n\t\tthis.embeddedDatabaseConnection = embeddedDatabaseConnection;\n\t}\n\n\tpublic ClassLoader getClassLoader() {\n\t\treturn this.classLoader;\n\t}\n\n\tpublic Xa getXa() {\n\t\treturn this.xa;\n\t}\n\n\tpublic void setXa(Xa xa) {\n\t\tthis.xa = xa;\n\t}\n\n\t/**\n\t * XA Specific datasource settings.\n\t */\n\tpublic static class Xa {\n\n\t\t/**\n\t\t * XA datasource fully qualified name.\n\t\t */\n\t\tprivate @Nullable String dataSourceClassName;\n\n\t\t/**\n\t\t * Properties to pass to the XA data source.\n\t\t */\n\t\tprivate Map<String, String> properties = new LinkedHashMap<>();\n\n\t\tpublic @Nullable String getDataSourceClassName() {\n\t\t\treturn this.dataSourceClassName;\n\t\t}\n\n\t\tpublic void setDataSourceClassName(@Nullable String dataSourceClassName) {\n\t\t\tthis.dataSourceClassName = dataSourceClassName;\n\t\t}\n\n\t\tpublic Map<String, String> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tpublic void setProperties(Map<String, String> properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t}\n\n\tstatic class DataSourceBeanCreationException extends BeanCreationException {\n\n\t\tprivate final DataSourceProperties properties;\n\n\t\tprivate final EmbeddedDatabaseConnection connection;\n\n\t\tDataSourceBeanCreationException(String message, DataSourceProperties properties,\n\t\t\t\tEmbeddedDatabaseConnection connection) {\n\t\t\tsuper(message);\n\t\t\tthis.properties = properties;\n\t\t\tthis.connection = connection;\n\t\t}\n\n\t\tDataSourceProperties getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tEmbeddedDatabaseConnection getConnection() {\n\t\t\treturn this.connection;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/DataSourceTransactionManagerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizers;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.support.JdbcTransactionManager;\nimport org.springframework.transaction.TransactionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link JdbcTransactionManager}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n * @since 4.0.0\n */\n@AutoConfiguration(before = TransactionAutoConfiguration.class,\n\t\tafter = { DataSourceAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class })\n@ConditionalOnClass({ DataSource.class, JdbcTemplate.class, TransactionManager.class })\n@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)\npublic final class DataSourceTransactionManagerAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(DataSource.class)\n\tstatic class JdbcTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(TransactionManager.class)\n\t\tDataSourceTransactionManager transactionManager(Environment environment, DataSource dataSource,\n\t\t\t\tObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {\n\t\t\tDataSourceTransactionManager transactionManager = createTransactionManager(environment, dataSource);\n\t\t\ttransactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));\n\t\t\treturn transactionManager;\n\t\t}\n\n\t\tprivate DataSourceTransactionManager createTransactionManager(Environment environment, DataSource dataSource) {\n\t\t\treturn environment.getProperty(\"spring.dao.exceptiontranslation.enabled\", Boolean.class, Boolean.TRUE)\n\t\t\t\t\t? new JdbcTransactionManager(dataSource) : new DataSourceTransactionManager(dataSource);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/Dbcp2JdbcConnectionDetailsBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\n\nimport org.springframework.beans.factory.ObjectProvider;\n\n/**\n * Post-processes beans of type {@link BasicDataSource} and name 'dataSource' to apply the\n * values from {@link JdbcConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass Dbcp2JdbcConnectionDetailsBeanPostProcessor extends JdbcConnectionDetailsBeanPostProcessor<BasicDataSource> {\n\n\tDbcp2JdbcConnectionDetailsBeanPostProcessor(ObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\tsuper(BasicDataSource.class, connectionDetailsProvider);\n\t}\n\n\t@Override\n\tprotected Object processDataSource(BasicDataSource dataSource, JdbcConnectionDetails connectionDetails) {\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClassName(connectionDetails.getDriverClassName());\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/EmbeddedDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration for embedded data sources.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see DataSourceAutoConfiguration\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(DataSourceProperties.class)\npublic class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader classLoader;\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t@Bean(destroyMethod = \"shutdown\")\n\tEmbeddedDatabase dataSource(DataSourceProperties properties) {\n\t\tEmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(this.classLoader).getType();\n\t\tString databaseName = properties.determineDatabaseName();\n\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\tAssert.state(databaseName != null, \"'databaseName' must not be null\");\n\t\treturn new EmbeddedDatabaseBuilder().setType(type).setName(databaseName).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/HikariDriverConfigurationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.jdbc.CannotGetJdbcConnectionException;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of a Hikari configuration\n * failure caused by the use of the unsupported 'dataSourceClassName' property.\n *\n * @author Stephane Nicoll\n */\nclass HikariDriverConfigurationFailureAnalyzer extends AbstractFailureAnalyzer<CannotGetJdbcConnectionException> {\n\n\tprivate static final String EXPECTED_MESSAGE = \"cannot use driverClassName and dataSourceClassName together.\";\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, CannotGetJdbcConnectionException cause) {\n\t\tThrowable subCause = cause.getCause();\n\t\tif (subCause == null || !EXPECTED_MESSAGE.equals(subCause.getMessage())) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new FailureAnalysis(\n\t\t\t\t\"Configuration of the Hikari connection pool failed: 'dataSourceClassName' is not supported.\",\n\t\t\t\t\"Spring Boot auto-configures only a driver and can't specify a custom \"\n\t\t\t\t\t\t+ \"DataSource. Consider configuring the Hikari DataSource in your own configuration.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/HikariJdbcConnectionDetailsBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport org.springframework.beans.factory.ObjectProvider;\n\n/**\n * Post-processes beans of type {@link HikariDataSource} and name 'dataSource' to apply\n * the values from {@link JdbcConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass HikariJdbcConnectionDetailsBeanPostProcessor extends JdbcConnectionDetailsBeanPostProcessor<HikariDataSource> {\n\n\tHikariJdbcConnectionDetailsBeanPostProcessor(ObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\tsuper(HikariDataSource.class, connectionDetailsProvider);\n\t}\n\n\t@Override\n\tprotected Object processDataSource(HikariDataSource dataSource, JdbcConnectionDetails connectionDetails) {\n\t\tdataSource.setJdbcUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tString driverClassName = connectionDetails.getDriverClassName();\n\t\tif (driverClassName != null) {\n\t\t\tdataSource.setDriverClassName(driverClassName);\n\t\t}\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JdbcClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\nimport org.springframework.jdbc.core.simple.JdbcClient;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link JdbcClient}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = JdbcTemplateAutoConfiguration.class)\n@ConditionalOnSingleCandidate(NamedParameterJdbcTemplate.class)\n@ConditionalOnMissingBean(JdbcClient.class)\n@Import(DatabaseInitializationDependencyConfigurer.class)\npublic final class JdbcClientAutoConfiguration {\n\n\t@Bean\n\tJdbcClient jdbcClient(NamedParameterJdbcTemplate jdbcTemplate) {\n\t\treturn JdbcClient.create(jdbcTemplate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JdbcConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.util.Assert;\n\n/**\n * Details required to establish a connection to an SQL service using JDBC.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface JdbcConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Username for the database.\n\t * @return the username for the database\n\t */\n\t@Nullable String getUsername();\n\n\t/**\n\t * Password for the database.\n\t * @return the password for the database\n\t */\n\t@Nullable String getPassword();\n\n\t/**\n\t * JDBC url for the database.\n\t * @return the JDBC url for the database\n\t */\n\tString getJdbcUrl();\n\n\t/**\n\t * The name of the JDBC driver class. Defaults to the class name of the driver\n\t * specified in the JDBC URL.\n\t * @return the JDBC driver class name\n\t * @see #getJdbcUrl()\n\t * @see DatabaseDriver#fromJdbcUrl(String)\n\t * @see DatabaseDriver#getDriverClassName()\n\t */\n\tdefault String getDriverClassName() {\n\t\tString driverClassName = DatabaseDriver.fromJdbcUrl(getJdbcUrl()).getDriverClassName();\n\t\tAssert.state(driverClassName != null, \"'driverClassName' must not be null\");\n\t\treturn driverClassName;\n\t}\n\n\t/**\n\t * Returns the name of the XA DataSource class. Defaults to the class name from the\n\t * driver specified in the JDBC URL.\n\t * @return the XA DataSource class name\n\t * @see #getJdbcUrl()\n\t * @see DatabaseDriver#fromJdbcUrl(String)\n\t * @see DatabaseDriver#getXaDataSourceClassName()\n\t */\n\tdefault @Nullable String getXaDataSourceClassName() {\n\t\treturn DatabaseDriver.fromJdbcUrl(getJdbcUrl()).getXaDataSourceClassName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JdbcConnectionDetailsBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\n\n/**\n * Abstract base class for DataSource bean post processors which apply values from\n * {@link JdbcConnectionDetails}. Property-based connection details\n * ({@link PropertiesJdbcConnectionDetails} are ignored as the expectation is that they\n * will have already been applied by configuration property binding. Acts on beans named\n * 'dataSource' of type {@code T}.\n *\n * @param <T> type of the datasource\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nabstract class JdbcConnectionDetailsBeanPostProcessor<T> implements BeanPostProcessor, PriorityOrdered {\n\n\tprivate final Class<T> dataSourceClass;\n\n\tprivate final ObjectProvider<JdbcConnectionDetails> connectionDetailsProvider;\n\n\tJdbcConnectionDetailsBeanPostProcessor(Class<T> dataSourceClass,\n\t\t\tObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\tthis.dataSourceClass = dataSourceClass;\n\t\tthis.connectionDetailsProvider = connectionDetailsProvider;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (this.dataSourceClass.isAssignableFrom(bean.getClass()) && \"dataSource\".equals(beanName)) {\n\t\t\tJdbcConnectionDetails connectionDetails = this.connectionDetailsProvider.getObject();\n\t\t\tif (!(connectionDetails instanceof PropertiesJdbcConnectionDetails)) {\n\t\t\t\treturn processDataSource((T) bean, connectionDetails);\n\t\t\t}\n\t\t}\n\t\treturn bean;\n\t}\n\n\tprotected abstract Object processDataSource(T dataSource, JdbcConnectionDetails connectionDetails);\n\n\t@Override\n\tpublic int getOrder() {\n\t\t// Runs after ConfigurationPropertiesBindingPostProcessor\n\t\treturn Ordered.HIGHEST_PRECEDENCE + 2;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JdbcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\n\n/**\n * Configuration properties for JDBC.\n *\n * @author Kazuki Shimizu\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jdbc\")\npublic class JdbcProperties {\n\n\tprivate final Template template = new Template();\n\n\tpublic Template getTemplate() {\n\t\treturn this.template;\n\t}\n\n\t/**\n\t * {@code JdbcTemplate} settings.\n\t */\n\tpublic static class Template {\n\n\t\t/**\n\t\t * Whether to ignore JDBC statement warnings (SQLWarning). When set to false,\n\t\t * throw an SQLWarningException instead.\n\t\t */\n\t\tprivate boolean ignoreWarnings = true;\n\n\t\t/**\n\t\t * Number of rows that should be fetched from the database when more rows are\n\t\t * needed. Use -1 to use the JDBC driver's default configuration.\n\t\t */\n\t\tprivate int fetchSize = -1;\n\n\t\t/**\n\t\t * Maximum number of rows. Use -1 to use the JDBC driver's default configuration.\n\t\t */\n\t\tprivate int maxRows = -1;\n\n\t\t/**\n\t\t * Query timeout. Default is to use the JDBC driver's default configuration. If a\n\t\t * duration suffix is not specified, seconds will be used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate @Nullable Duration queryTimeout;\n\n\t\t/**\n\t\t * Whether results processing should be skipped. Can be used to optimize callable\n\t\t * statement processing when we know that no results are being passed back.\n\t\t */\n\t\tprivate boolean skipResultsProcessing;\n\n\t\t/**\n\t\t * Whether undeclared results should be skipped.\n\t\t */\n\t\tprivate boolean skipUndeclaredResults;\n\n\t\t/**\n\t\t * Whether execution of a CallableStatement will return the results in a Map that\n\t\t * uses case-insensitive names for the parameters.\n\t\t */\n\t\tprivate boolean resultsMapCaseInsensitive;\n\n\t\tpublic boolean isIgnoreWarnings() {\n\t\t\treturn this.ignoreWarnings;\n\t\t}\n\n\t\tpublic void setIgnoreWarnings(boolean ignoreWarnings) {\n\t\t\tthis.ignoreWarnings = ignoreWarnings;\n\t\t}\n\n\t\tpublic int getFetchSize() {\n\t\t\treturn this.fetchSize;\n\t\t}\n\n\t\tpublic void setFetchSize(int fetchSize) {\n\t\t\tthis.fetchSize = fetchSize;\n\t\t}\n\n\t\tpublic int getMaxRows() {\n\t\t\treturn this.maxRows;\n\t\t}\n\n\t\tpublic void setMaxRows(int maxRows) {\n\t\t\tthis.maxRows = maxRows;\n\t\t}\n\n\t\tpublic @Nullable Duration getQueryTimeout() {\n\t\t\treturn this.queryTimeout;\n\t\t}\n\n\t\tpublic void setQueryTimeout(@Nullable Duration queryTimeout) {\n\t\t\tthis.queryTimeout = queryTimeout;\n\t\t}\n\n\t\tpublic boolean isSkipResultsProcessing() {\n\t\t\treturn this.skipResultsProcessing;\n\t\t}\n\n\t\tpublic void setSkipResultsProcessing(boolean skipResultsProcessing) {\n\t\t\tthis.skipResultsProcessing = skipResultsProcessing;\n\t\t}\n\n\t\tpublic boolean isSkipUndeclaredResults() {\n\t\t\treturn this.skipUndeclaredResults;\n\t\t}\n\n\t\tpublic void setSkipUndeclaredResults(boolean skipUndeclaredResults) {\n\t\t\tthis.skipUndeclaredResults = skipUndeclaredResults;\n\t\t}\n\n\t\tpublic boolean isResultsMapCaseInsensitive() {\n\t\t\treturn this.resultsMapCaseInsensitive;\n\t\t}\n\n\t\tpublic void setResultsMapCaseInsensitive(boolean resultsMapCaseInsensitive) {\n\t\t\tthis.resultsMapCaseInsensitive = resultsMapCaseInsensitive;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JdbcTemplateAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link JdbcTemplate} and\n * {@link NamedParameterJdbcTemplate}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Kazuki Shimizu\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataSourceAutoConfiguration.class)\n@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })\n@ConditionalOnSingleCandidate(DataSource.class)\n@EnableConfigurationProperties(JdbcProperties.class)\n@Import({ DatabaseInitializationDependencyConfigurer.class, JdbcTemplateConfiguration.class,\n\t\tNamedParameterJdbcTemplateConfiguration.class })\npublic final class JdbcTemplateAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JdbcTemplateConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\n\n/**\n * Configuration for {@link JdbcTemplateConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Yanming Zhou\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(JdbcOperations.class)\nclass JdbcTemplateConfiguration {\n\n\t@Bean\n\t@Primary\n\tJdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties,\n\t\t\tObjectProvider<SQLExceptionTranslator> sqlExceptionTranslator) {\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tJdbcProperties.Template template = properties.getTemplate();\n\t\tjdbcTemplate.setIgnoreWarnings(template.isIgnoreWarnings());\n\t\tjdbcTemplate.setFetchSize(template.getFetchSize());\n\t\tjdbcTemplate.setMaxRows(template.getMaxRows());\n\t\tif (template.getQueryTimeout() != null) {\n\t\t\tjdbcTemplate.setQueryTimeout((int) template.getQueryTimeout().getSeconds());\n\t\t}\n\t\tjdbcTemplate.setSkipResultsProcessing(template.isSkipResultsProcessing());\n\t\tjdbcTemplate.setSkipUndeclaredResults(template.isSkipUndeclaredResults());\n\t\tjdbcTemplate.setResultsMapCaseInsensitive(template.isResultsMapCaseInsensitive());\n\t\tsqlExceptionTranslator.ifUnique(jdbcTemplate::setExceptionTranslator);\n\t\treturn jdbcTemplate;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/JndiDataSourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;\nimport org.springframework.jmx.export.MBeanExporter;\nimport org.springframework.jmx.support.JmxUtils;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a JNDI located\n * {@link DataSource}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(before = { XADataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class })\n@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })\n@ConditionalOnProperty(\"spring.datasource.jndi-name\")\n@EnableConfigurationProperties(DataSourceProperties.class)\npublic final class JndiDataSourceAutoConfiguration {\n\n\t@Bean(destroyMethod = \"\")\n\t@ConditionalOnMissingBean\n\tDataSource dataSource(DataSourceProperties properties, ApplicationContext context) {\n\t\tJndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();\n\t\tString jndiName = properties.getJndiName();\n\t\tAssert.state(jndiName != null, \"'jndiName' must not be null\");\n\t\tDataSource dataSource = dataSourceLookup.getDataSource(jndiName);\n\t\texcludeMBeanIfNecessary(dataSource, \"dataSource\", context);\n\t\treturn dataSource;\n\t}\n\n\tprivate void excludeMBeanIfNecessary(Object candidate, String beanName, ApplicationContext context) {\n\t\tfor (MBeanExporter mbeanExporter : context.getBeansOfType(MBeanExporter.class).values()) {\n\t\t\tif (JmxUtils.isMBean(candidate.getClass())) {\n\t\t\t\tmbeanExporter.addExcludedBean(beanName);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/NamedParameterJdbcTemplateConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\n\n/**\n * Configuration for {@link NamedParameterJdbcTemplate}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnSingleCandidate(JdbcTemplate.class)\n@ConditionalOnMissingBean(NamedParameterJdbcOperations.class)\nclass NamedParameterJdbcTemplateConfiguration {\n\n\t@Bean\n\t@Primary\n\tNamedParameterJdbcTemplate namedParameterJdbcTemplate(JdbcTemplate jdbcTemplate) {\n\t\treturn new NamedParameterJdbcTemplate(jdbcTemplate);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/OracleUcpJdbcConnectionDetailsBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.SQLException;\n\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\n\nimport org.springframework.beans.factory.ObjectProvider;\n\n/**\n * Post-processes beans of type {@link PoolDataSourceImpl} and name 'dataSource' to apply\n * the values from {@link JdbcConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass OracleUcpJdbcConnectionDetailsBeanPostProcessor\n\t\textends JdbcConnectionDetailsBeanPostProcessor<PoolDataSourceImpl> {\n\n\tOracleUcpJdbcConnectionDetailsBeanPostProcessor(ObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\tsuper(PoolDataSourceImpl.class, connectionDetailsProvider);\n\t}\n\n\t@Override\n\tprotected Object processDataSource(PoolDataSourceImpl dataSource, JdbcConnectionDetails connectionDetails) {\n\t\ttry {\n\t\t\tdataSource.setURL(connectionDetails.getJdbcUrl());\n\t\t\tdataSource.setUser(connectionDetails.getUsername());\n\t\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\t\tdataSource.setConnectionFactoryClassName(connectionDetails.getDriverClassName());\n\t\t\treturn dataSource;\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to set URL / user / password of datasource\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/PropertiesJdbcConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Adapts {@link DataSourceProperties} to {@link JdbcConnectionDetails}.\n *\n * @author Andy Wilkinson\n */\nfinal class PropertiesJdbcConnectionDetails implements JdbcConnectionDetails {\n\n\tprivate final DataSourceProperties properties;\n\n\tPropertiesJdbcConnectionDetails(DataSourceProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Override\n\tpublic @Nullable String getUsername() {\n\t\treturn this.properties.determineUsername();\n\t}\n\n\t@Override\n\tpublic @Nullable String getPassword() {\n\t\treturn this.properties.determinePassword();\n\t}\n\n\t@Override\n\tpublic String getJdbcUrl() {\n\t\treturn this.properties.determineUrl();\n\t}\n\n\t@Override\n\tpublic String getDriverClassName() {\n\t\treturn this.properties.determineDriverClassName();\n\t}\n\n\t@Override\n\tpublic @Nullable String getXaDataSourceClassName() {\n\t\treturn (this.properties.getXa().getDataSourceClassName() != null)\n\t\t\t\t? this.properties.getXa().getDataSourceClassName()\n\t\t\t\t: JdbcConnectionDetails.super.getXaDataSourceClassName();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/TomcatJdbcConnectionDetailsBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.apache.tomcat.jdbc.pool.DataSource;\n\nimport org.springframework.beans.factory.ObjectProvider;\n\n/**\n * Post-processes beans of type {@link DataSource} and name 'dataSource' to apply the\n * values from {@link JdbcConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass TomcatJdbcConnectionDetailsBeanPostProcessor extends JdbcConnectionDetailsBeanPostProcessor<DataSource> {\n\n\tTomcatJdbcConnectionDetailsBeanPostProcessor(ObjectProvider<JdbcConnectionDetails> connectionDetailsProvider) {\n\t\tsuper(DataSource.class, connectionDetailsProvider);\n\t}\n\n\t@Override\n\tprotected Object processDataSource(DataSource dataSource, JdbcConnectionDetails connectionDetails) {\n\t\tdataSource.setUrl(connectionDetails.getJdbcUrl());\n\t\tdataSource.setUsername(connectionDetails.getUsername());\n\t\tdataSource.setPassword(connectionDetails.getPassword());\n\t\tdataSource.setDriverClassName(connectionDetails.getDriverClassName());\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/XADataSourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\nimport javax.sql.XADataSource;\n\nimport jakarta.transaction.TransactionManager;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.BeanClassLoaderAware;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyNameAliases;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.jdbc.XADataSourceWrapper;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties.DataSourceBeanCreationException;\nimport org.springframework.boot.transaction.jta.autoconfigure.JtaAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource} with XA.\n *\n * @author Phillip Webb\n * @author Josh Long\n * @author Madhura Bhave\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(before = DataSourceAutoConfiguration.class, after = JtaAutoConfiguration.class)\n@EnableConfigurationProperties(DataSourceProperties.class)\n@ConditionalOnClass({ DataSource.class, TransactionManager.class, EmbeddedDatabaseType.class })\n@ConditionalOnBean(XADataSourceWrapper.class)\n@ConditionalOnMissingBean(DataSource.class)\npublic final class XADataSourceAutoConfiguration implements BeanClassLoaderAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClassLoader classLoader;\n\n\t@Bean\n\t@ConditionalOnMissingBean(JdbcConnectionDetails.class)\n\tPropertiesJdbcConnectionDetails jdbcConnectionDetails(DataSourceProperties properties) {\n\t\treturn new PropertiesJdbcConnectionDetails(properties);\n\t}\n\n\t@Bean\n\tDataSource dataSource(XADataSourceWrapper wrapper, DataSourceProperties properties,\n\t\t\tJdbcConnectionDetails connectionDetails, ObjectProvider<XADataSource> xaDataSource) throws Exception {\n\t\treturn wrapper\n\t\t\t.wrapDataSource(xaDataSource.getIfAvailable(() -> createXaDataSource(properties, connectionDetails)));\n\t}\n\n\t@Override\n\tpublic void setBeanClassLoader(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\tprivate XADataSource createXaDataSource(DataSourceProperties properties, JdbcConnectionDetails connectionDetails) {\n\t\tString className = connectionDetails.getXaDataSourceClassName();\n\t\tAssert.state(StringUtils.hasLength(className), \"No XA DataSource class name specified\");\n\t\tXADataSource dataSource = createXaDataSourceInstance(className);\n\t\tbindXaProperties(dataSource, properties, connectionDetails);\n\t\treturn dataSource;\n\t}\n\n\tprivate XADataSource createXaDataSourceInstance(String className) {\n\t\ttry {\n\t\t\tClass<?> dataSourceClass = ClassUtils.forName(className, this.classLoader);\n\t\t\tObject instance = BeanUtils.instantiateClass(dataSourceClass);\n\t\t\tAssert.state(instance instanceof XADataSource,\n\t\t\t\t\t() -> \"DataSource class \" + className + \" is not an XADataSource\");\n\t\t\treturn (XADataSource) instance;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create XADataSource instance from '\" + className + \"'\");\n\t\t}\n\t}\n\n\tprivate void bindXaProperties(XADataSource target, DataSourceProperties dataSourceProperties,\n\t\t\tJdbcConnectionDetails connectionDetails) {\n\t\tBinder binder = new Binder(getBinderSource(dataSourceProperties, connectionDetails));\n\t\tbinder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(target));\n\t}\n\n\tprivate ConfigurationPropertySource getBinderSource(DataSourceProperties dataSourceProperties,\n\t\t\tJdbcConnectionDetails connectionDetails) {\n\t\tMap<Object, Object> properties = new HashMap<>(dataSourceProperties.getXa().getProperties());\n\t\tproperties.computeIfAbsent(\"user\", (key) -> connectionDetails.getUsername());\n\t\tproperties.computeIfAbsent(\"password\", (key) -> connectionDetails.getPassword());\n\t\ttry {\n\t\t\tproperties.computeIfAbsent(\"url\", (key) -> connectionDetails.getJdbcUrl());\n\t\t}\n\t\tcatch (DataSourceBeanCreationException ex) {\n\t\t\t// Continue as not all XA DataSource's require a URL\n\t\t}\n\t\tMapConfigurationPropertySource source = new MapConfigurationPropertySource(properties);\n\t\tConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();\n\t\taliases.addAliases(\"user\", \"username\");\n\t\treturn source.withAliases(aliases);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/health/DataSourceHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure.health;\n\nimport java.sql.SQLException;\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.health.DataSourceHealthIndicator;\nimport org.springframework.boot.jdbc.metadata.CompositeDataSourcePoolMetadataProvider;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link DataSourceHealthIndicator}.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Arthur Kalimullin\n * @author Julio Gomez\n * @author Safeer Ansari\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataSourceAutoConfiguration.class)\n@ConditionalOnClass({ JdbcTemplate.class, AbstractRoutingDataSource.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(DataSource.class)\n@ConditionalOnEnabledHealthIndicator(\"db\")\n@EnableConfigurationProperties(DataSourceHealthIndicatorProperties.class)\npublic final class DataSourceHealthContributorAutoConfiguration implements InitializingBean {\n\n\tprivate final Collection<DataSourcePoolMetadataProvider> metadataProviders;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSourcePoolMetadataProvider poolMetadataProvider;\n\n\tDataSourceHealthContributorAutoConfiguration(ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {\n\t\tthis.metadataProviders = metadataProviders.orderedStream().toList();\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tthis.poolMetadataProvider = new CompositeDataSourcePoolMetadataProvider(this.metadataProviders);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"dbHealthIndicator\", \"dbHealthContributor\" })\n\tHealthContributor dbHealthContributor(ConfigurableListableBeanFactory beanFactory,\n\t\t\tDataSourceHealthIndicatorProperties dataSourceHealthIndicatorProperties) {\n\t\tMap<String, DataSource> dataSources = SimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory,\n\t\t\t\tDataSource.class, false, true);\n\t\tif (dataSourceHealthIndicatorProperties.isIgnoreRoutingDataSources()) {\n\t\t\tMap<String, DataSource> filteredDatasources = dataSources.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((e) -> !isRoutingDataSource(e.getValue()))\n\t\t\t\t.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n\t\t\treturn createContributor(filteredDatasources);\n\t\t}\n\t\treturn createContributor(dataSources);\n\t}\n\n\tprivate HealthContributor createContributor(Map<String, DataSource> beans) {\n\t\tAssert.notEmpty(beans, \"'beans' must not be empty\");\n\t\tif (beans.size() == 1) {\n\t\t\treturn createContributor(beans.values().iterator().next());\n\t\t}\n\t\treturn CompositeHealthContributor.fromMap(beans, this::createContributor);\n\t}\n\n\tprivate HealthContributor createContributor(DataSource source) {\n\t\tif (isRoutingDataSource(source)) {\n\t\t\treturn new RoutingDataSourceHealthContributor(extractRoutingDataSource(source), this::createContributor);\n\t\t}\n\t\treturn new DataSourceHealthIndicator(source, getValidationQuery(source));\n\t}\n\n\tprivate @Nullable String getValidationQuery(DataSource source) {\n\t\tDataSourcePoolMetadata poolMetadata = this.poolMetadataProvider.getDataSourcePoolMetadata(source);\n\t\treturn (poolMetadata != null) ? poolMetadata.getValidationQuery() : null;\n\t}\n\n\tprivate static boolean isRoutingDataSource(DataSource dataSource) {\n\t\tif (dataSource instanceof AbstractRoutingDataSource) {\n\t\t\treturn true;\n\t\t}\n\t\ttry {\n\t\t\treturn dataSource.isWrapperFor(AbstractRoutingDataSource.class);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate static AbstractRoutingDataSource extractRoutingDataSource(DataSource dataSource) {\n\t\tif (dataSource instanceof AbstractRoutingDataSource routingDataSource) {\n\t\t\treturn routingDataSource;\n\t\t}\n\t\ttry {\n\t\t\treturn dataSource.unwrap(AbstractRoutingDataSource.class);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to unwrap AbstractRoutingDataSource from \" + dataSource, ex);\n\t\t}\n\t}\n\n\t/**\n\t * {@link CompositeHealthContributor} used for {@link AbstractRoutingDataSource} beans\n\t * where the overall health is composed of a {@link DataSourceHealthIndicator} for\n\t * each routed datasource.\n\t */\n\tstatic class RoutingDataSourceHealthContributor implements CompositeHealthContributor {\n\n\t\tprivate final CompositeHealthContributor delegate;\n\n\t\tprivate static final String UNNAMED_DATASOURCE_KEY = \"unnamed\";\n\n\t\tRoutingDataSourceHealthContributor(AbstractRoutingDataSource routingDataSource,\n\t\t\t\tFunction<DataSource, HealthContributor> contributorFunction) {\n\t\t\tMap<String, DataSource> routedDataSources = routingDataSource.getResolvedDataSources()\n\t\t\t\t.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.collect(Collectors.toMap((e) -> Objects.toString(e.getKey(), UNNAMED_DATASOURCE_KEY),\n\t\t\t\t\t\tMap.Entry::getValue));\n\t\t\tthis.delegate = CompositeHealthContributor.fromMap(routedDataSources, contributorFunction);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable HealthContributor getContributor(String name) {\n\t\t\treturn this.delegate.getContributor(name);\n\t\t}\n\n\t\t@Override\n\t\tpublic Stream<HealthContributors.Entry> stream() {\n\t\t\treturn this.delegate.stream();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/health/DataSourceHealthIndicatorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure.health;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.health.DataSourceHealthIndicator;\n\n/**\n * External configuration properties for {@link DataSourceHealthIndicator}.\n *\n * @author Julio Gomez\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.health.db\")\npublic class DataSourceHealthIndicatorProperties {\n\n\t/**\n\t * Whether to ignore AbstractRoutingDataSources when creating database health\n\t * indicators.\n\t */\n\tprivate boolean ignoreRoutingDataSources;\n\n\tpublic boolean isIgnoreRoutingDataSources() {\n\t\treturn this.ignoreRoutingDataSources;\n\t}\n\n\tpublic void setIgnoreRoutingDataSources(boolean ignoreRoutingDataSources) {\n\t\tthis.ignoreRoutingDataSources = ignoreRoutingDataSources;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JDBC health.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/metrics/DataSourcePoolMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure.metrics;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariConfigMXBean;\nimport com.zaxxer.hikari.HikariDataSource;\nimport com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.jdbc.DataSourceUnwrapper;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.boot.jdbc.metrics.DataSourcePoolMetrics;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available\n * {@link DataSource datasources}.\n *\n * @author Stephane Nicoll\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataSourceAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnClass({ DataSource.class, MeterRegistry.class })\n@ConditionalOnBean({ DataSource.class, MeterRegistry.class })\npublic final class DataSourcePoolMetricsAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(DataSourcePoolMetadataProvider.class)\n\tstatic class DataSourcePoolMetadataMetricsConfiguration {\n\n\t\tprivate static final String DATASOURCE_SUFFIX = \"dataSource\";\n\n\t\t@Bean\n\t\tDataSourcePoolMetadataMeterBinder dataSourcePoolMetadataMeterBinder(ConfigurableListableBeanFactory beanFactory,\n\t\t\t\tObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {\n\t\t\treturn new DataSourcePoolMetadataMeterBinder(SimpleAutowireCandidateResolver\n\t\t\t\t.resolveAutowireCandidates(beanFactory, DataSource.class, false, true), metadataProviders);\n\t\t}\n\n\t\tstatic class DataSourcePoolMetadataMeterBinder implements MeterBinder {\n\n\t\t\tprivate final Map<String, DataSource> dataSources;\n\n\t\t\tprivate final ObjectProvider<DataSourcePoolMetadataProvider> metadataProviders;\n\n\t\t\tDataSourcePoolMetadataMeterBinder(Map<String, DataSource> dataSources,\n\t\t\t\t\tObjectProvider<DataSourcePoolMetadataProvider> metadataProviders) {\n\t\t\t\tthis.dataSources = dataSources;\n\t\t\t\tthis.metadataProviders = metadataProviders;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void bindTo(MeterRegistry registry) {\n\t\t\t\tList<DataSourcePoolMetadataProvider> metadataProvidersList = this.metadataProviders.stream().toList();\n\t\t\t\tthis.dataSources.forEach((name, dataSource) -> bindDataSourceToRegistry(name, dataSource,\n\t\t\t\t\t\tmetadataProvidersList, registry));\n\t\t\t}\n\n\t\t\tprivate void bindDataSourceToRegistry(String beanName, DataSource dataSource,\n\t\t\t\t\tCollection<DataSourcePoolMetadataProvider> metadataProviders, MeterRegistry registry) {\n\t\t\t\tString dataSourceName = getDataSourceName(beanName);\n\t\t\t\tnew DataSourcePoolMetrics(dataSource, metadataProviders, dataSourceName, Collections.emptyList())\n\t\t\t\t\t.bindTo(registry);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Get the name of a DataSource based on its {@code beanName}.\n\t\t\t * @param beanName the name of the data source bean\n\t\t\t * @return a name for the given data source\n\t\t\t */\n\t\t\tprivate String getDataSourceName(String beanName) {\n\t\t\t\tif (beanName.length() > DATASOURCE_SUFFIX.length()\n\t\t\t\t\t\t&& StringUtils.endsWithIgnoreCase(beanName, DATASOURCE_SUFFIX)) {\n\t\t\t\t\treturn beanName.substring(0, beanName.length() - DATASOURCE_SUFFIX.length());\n\t\t\t\t}\n\t\t\t\treturn beanName;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HikariDataSource.class)\n\tstatic class HikariDataSourceMetricsConfiguration {\n\n\t\t@Bean\n\t\tHikariDataSourceMeterBinder hikariDataSourceMeterBinder(ObjectProvider<DataSource> dataSources) {\n\t\t\treturn new HikariDataSourceMeterBinder(dataSources);\n\t\t}\n\n\t\tstatic class HikariDataSourceMeterBinder implements MeterBinder {\n\n\t\t\tprivate static final Log logger = LogFactory.getLog(HikariDataSourceMeterBinder.class);\n\n\t\t\tprivate final ObjectProvider<DataSource> dataSources;\n\n\t\t\tHikariDataSourceMeterBinder(ObjectProvider<DataSource> dataSources) {\n\t\t\t\tthis.dataSources = dataSources;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void bindTo(MeterRegistry registry) {\n\t\t\t\tthis.dataSources.stream(ObjectProvider.UNFILTERED, false).forEach((dataSource) -> {\n\t\t\t\t\tHikariDataSource hikariDataSource = DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class,\n\t\t\t\t\t\t\tHikariDataSource.class);\n\t\t\t\t\tif (hikariDataSource != null) {\n\t\t\t\t\t\tbindMetricsRegistryToHikariDataSource(hikariDataSource, registry);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tprivate void bindMetricsRegistryToHikariDataSource(HikariDataSource hikari, MeterRegistry registry) {\n\t\t\t\tif (hikari.getMetricRegistry() == null && hikari.getMetricsTrackerFactory() == null) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\thikari.setMetricsTrackerFactory(new MicrometerMetricsTrackerFactory(registry));\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t\tlogger.warn(LogMessage.format(\"Failed to bind Hikari metrics: %s\", ex.getMessage()));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JDBC metrics.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JDBC.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/ClickHouseEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * ClickHouse environment details.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tClickHouseEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env);\n\t}\n\n\tprivate static String extractDatabase(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"CLICKHOUSE_DB\");\n\t\treturn (result != null) ? result : \"default\";\n\t}\n\n\tprivate static String extractUsername(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"CLICKHOUSE_USER\");\n\t\treturn (result != null) ? result : \"default\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tboolean allowEmpty = env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tString password = env.get(\"CLICKHOUSE_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password) || allowEmpty, \"No ClickHouse password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/ClickHouseJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for a {@code clickhouse} service.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseJdbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {\n\n\tprotected ClickHouseJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"clickhouse/clickhouse-server\");\n\t}\n\n\t@Override\n\tprotected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ClickhouseJdbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by a {@code clickhouse}\n\t * {@link RunningService}.\n\t */\n\tstatic class ClickhouseJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements JdbcConnectionDetails {\n\n\t\tprivate static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder(\"clickhouse\", 8123);\n\n\t\tprivate final ClickHouseEnvironment environment;\n\n\t\tprivate final String jdbcUrl;\n\n\t\tClickhouseJdbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new ClickHouseEnvironment(service.env());\n\t\t\tthis.jdbcUrl = jdbcUrlBuilder.build(service, this.environment.getDatabase());\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/JdbcUrlBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility used to build a JDBC URL for a {@link RunningService}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass JdbcUrlBuilder {\n\n\tprivate static final String PARAMETERS_LABEL = \"org.springframework.boot.jdbc.parameters\";\n\n\tprivate final String driverProtocol;\n\n\tprivate final int containerPort;\n\n\t/**\n\t * Create a new {@link JdbcUrlBuilder} instance.\n\t * @param driverProtocol the driver protocol\n\t * @param containerPort the source container port\n\t */\n\tJdbcUrlBuilder(String driverProtocol, int containerPort) {\n\t\tAssert.notNull(driverProtocol, \"'driverProtocol' must not be null\");\n\t\tthis.driverProtocol = driverProtocol;\n\t\tthis.containerPort = containerPort;\n\t}\n\n\t/**\n\t * Build a JDBC URL for the given {@link RunningService}.\n\t * @param service the running service\n\t * @return a new JDBC URL\n\t */\n\tString build(RunningService service) {\n\t\treturn build(service, null);\n\t}\n\n\t/**\n\t * Build a JDBC URL for the given {@link RunningService} and database.\n\t * @param service the running service\n\t * @param database the database to connect to\n\t * @return a new JDBC URL\n\t */\n\tString build(RunningService service, @Nullable String database) {\n\t\treturn urlFor(service, database);\n\t}\n\n\tprivate String urlFor(RunningService service, @Nullable String database) {\n\t\tAssert.notNull(service, \"'service' must not be null\");\n\t\tStringBuilder url = new StringBuilder(\"jdbc:%s://%s:%d\".formatted(this.driverProtocol, service.host(),\n\t\t\t\tservice.ports().get(this.containerPort)));\n\t\tif (StringUtils.hasLength(database)) {\n\t\t\turl.append(\"/\");\n\t\t\turl.append(database);\n\t\t}\n\t\tString parameters = getParameters(service);\n\t\tif (StringUtils.hasLength(parameters)) {\n\t\t\tappendParameters(url, parameters);\n\t\t}\n\t\treturn url.toString();\n\t}\n\n\t/**\n\t * Appends to the given {@code url} the given {@code parameters}.\n\t * <p>\n\t * The default implementation appends a {@code ?} followed by the {@code parameters}.\n\t * @param url the url\n\t * @param parameters the parameters\n\t */\n\tprotected void appendParameters(StringBuilder url, String parameters) {\n\t\turl.append(\"?\").append(parameters);\n\t}\n\n\tprivate @Nullable String getParameters(RunningService service) {\n\t\treturn service.labels().get(PARAMETERS_LABEL);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/MariaDbEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * MariaDB environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MariaDbEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tMariaDbEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env);\n\t}\n\n\tprivate String extractUsername(Map<String, @Nullable String> env) {\n\t\tString user = env.get(\"MARIADB_USER\");\n\t\tif (user == null) {\n\t\t\tuser = env.get(\"MYSQL_USER\");\n\t\t}\n\t\treturn (user != null) ? user : \"root\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tAssert.state(!env.containsKey(\"MARIADB_RANDOM_ROOT_PASSWORD\"), \"MARIADB_RANDOM_ROOT_PASSWORD is not supported\");\n\t\tAssert.state(!env.containsKey(\"MYSQL_RANDOM_ROOT_PASSWORD\"), \"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t\tAssert.state(!env.containsKey(\"MARIADB_ROOT_PASSWORD_HASH\"), \"MARIADB_ROOT_PASSWORD_HASH is not supported\");\n\t\tboolean allowEmpty = env.containsKey(\"MARIADB_ALLOW_EMPTY_PASSWORD\")\n\t\t\t\t|| env.containsKey(\"MYSQL_ALLOW_EMPTY_PASSWORD\") || env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tString password = env.get(\"MARIADB_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MYSQL_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MARIADB_ROOT_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MYSQL_ROOT_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password) || allowEmpty, \"No MariaDB password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tprivate String extractDatabase(Map<String, @Nullable String> env) {\n\t\tString database = env.get(\"MARIADB_DATABASE\");\n\t\tdatabase = (database != null) ? database : env.get(\"MYSQL_DATABASE\");\n\t\tAssert.state(database != null, \"No MARIADB_DATABASE defined\");\n\t\treturn database;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/MariaDbJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for a {@code mariadb} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MariaDbJdbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {\n\n\tprotected MariaDbJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mariadb\");\n\t}\n\n\t@Override\n\tprotected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new MariaDbJdbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by a {@code mariadb} {@link RunningService}.\n\t */\n\tstatic class MariaDbJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements JdbcConnectionDetails {\n\n\t\tprivate static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder(\"mariadb\", 3306);\n\n\t\tprivate final MariaDbEnvironment environment;\n\n\t\tprivate final String jdbcUrl;\n\n\t\tMariaDbJdbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new MariaDbEnvironment(service.env());\n\t\t\tthis.jdbcUrl = jdbcUrlBuilder.build(service, this.environment.getDatabase());\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/MySqlEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * MySQL environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MySqlEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tMySqlEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env);\n\t}\n\n\tprivate static String extractUsername(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"MYSQL_USER\");\n\t\treturn (result != null) ? result : \"root\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tAssert.state(!env.containsKey(\"MYSQL_RANDOM_ROOT_PASSWORD\"), \"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t\tboolean allowEmpty = env.containsKey(\"MYSQL_ALLOW_EMPTY_PASSWORD\") || env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tString password = env.get(\"MYSQL_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MYSQL_ROOT_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password) || allowEmpty, \"No MySQL password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tprivate String extractDatabase(Map<String, @Nullable String> env) {\n\t\tString database = env.get(\"MYSQL_DATABASE\");\n\t\tAssert.state(database != null, \"No MYSQL_DATABASE defined\");\n\t\treturn database;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/MySqlJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for a {@code mysql} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MySqlJdbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {\n\n\tprotected MySqlJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mysql\");\n\t}\n\n\t@Override\n\tprotected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new MySqlJdbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by a {@code mysql} {@link RunningService}.\n\t */\n\tstatic class MySqlJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements JdbcConnectionDetails {\n\n\t\tprivate static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder(\"mysql\", 3306);\n\n\t\tprivate final MySqlEnvironment environment;\n\n\t\tprivate final String jdbcUrl;\n\n\t\tMySqlJdbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new MySqlEnvironment(service.env());\n\t\t\tthis.jdbcUrl = jdbcUrlBuilder.build(service, this.environment.getDatabase());\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/OracleContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\n/**\n * Enumeration of supported Oracle containers.\n *\n * @author Andy Wilkinson\n */\nenum OracleContainer {\n\n\tFREE(\"gvenzl/oracle-free\", \"freepdb1\"),\n\n\tXE(\"gvenzl/oracle-xe\", \"xepdb1\");\n\n\tprivate final String imageName;\n\n\tprivate final String defaultDatabase;\n\n\tOracleContainer(String imageName, String defaultDatabase) {\n\t\tthis.imageName = imageName;\n\t\tthis.defaultDatabase = defaultDatabase;\n\t}\n\n\tString getImageName() {\n\t\treturn this.imageName;\n\t}\n\n\tString getDefaultDatabase() {\n\t\treturn this.defaultDatabase;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/OracleEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Oracle Database environment details.\n *\n * @author Andy Wilkinson\n */\nclass OracleEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tOracleEnvironment(Map<String, @Nullable String> env, String defaultDatabase) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env, defaultDatabase);\n\t}\n\n\tprivate static String extractDatabase(Map<String, @Nullable String> env, String defaultDatabase) {\n\t\tString result = env.get(\"ORACLE_DATABASE\");\n\t\treturn (result != null) ? result : defaultDatabase;\n\t}\n\n\tprivate static String extractUsername(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"APP_USER\");\n\t\treturn (result != null) ? result : \"system\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tif (env.containsKey(\"APP_USER\")) {\n\t\t\tString password = env.get(\"APP_USER_PASSWORD\");\n\t\t\tAssert.state(StringUtils.hasLength(password), \"No Oracle app password found\");\n\t\t\treturn password;\n\t\t}\n\t\tAssert.state(!env.containsKey(\"ORACLE_RANDOM_PASSWORD\"),\n\t\t\t\t\"ORACLE_RANDOM_PASSWORD is not supported without APP_USER and APP_USER_PASSWORD\");\n\t\tString password = env.get(\"ORACLE_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password), \"No Oracle password found\");\n\t\treturn password;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/OracleFreeJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for an {@link OracleContainer#FREE} service.\n *\n * @author Andy Wilkinson\n */\nclass OracleFreeJdbcDockerComposeConnectionDetailsFactory extends OracleJdbcDockerComposeConnectionDetailsFactory {\n\n\tprotected OracleFreeJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OracleContainer.FREE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/OracleJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for a {@link DockerComposeConnectionDetailsFactory} to create\n * {@link JdbcConnectionDetails} for an {@code oracle-free} or {@code oracle-xe} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nabstract class OracleJdbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {\n\n\tprivate final String defaultDatabase;\n\n\tprotected OracleJdbcDockerComposeConnectionDetailsFactory(OracleContainer container) {\n\t\tsuper(container.getImageName());\n\t\tthis.defaultDatabase = container.getDefaultDatabase();\n\t}\n\n\t@Override\n\tprotected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new OracleJdbcDockerComposeConnectionDetails(source.getRunningService(), this.defaultDatabase);\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by an {@code oracle-xe} or {@code oracle-free}\n\t * {@link RunningService}.\n\t */\n\tstatic class OracleJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements JdbcConnectionDetails {\n\n\t\tprivate static final String PARAMETERS_LABEL = \"org.springframework.boot.jdbc.parameters\";\n\n\t\tprivate final OracleEnvironment environment;\n\n\t\tprivate final String jdbcUrl;\n\n\t\tOracleJdbcDockerComposeConnectionDetails(RunningService service, String defaultDatabase) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new OracleEnvironment(service.env(), defaultDatabase);\n\t\t\tthis.jdbcUrl = \"jdbc:oracle:thin:@\" + service.host() + \":\" + service.ports().get(1521) + \"/\"\n\t\t\t\t\t+ this.environment.getDatabase() + getParameters(service);\n\t\t}\n\n\t\tprivate String getParameters(RunningService service) {\n\t\t\tString parameters = service.labels().get(PARAMETERS_LABEL);\n\t\t\treturn (StringUtils.hasLength(parameters)) ? \"?\" + parameters : \"\";\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/OracleXeJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for an {@link OracleContainer#XE} service.\n *\n * @author Andy Wilkinson\n */\nclass OracleXeJdbcDockerComposeConnectionDetailsFactory extends OracleJdbcDockerComposeConnectionDetailsFactory {\n\n\tprotected OracleXeJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OracleContainer.XE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/PostgresEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Postgres environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Sidmar Theodoro\n * @author He Zean\n */\nclass PostgresEnvironment {\n\n\tprivate static final String[] USERNAME_KEYS = new String[] { \"POSTGRES_USER\", \"POSTGRESQL_USER\",\n\t\t\t\"POSTGRESQL_USERNAME\" };\n\n\tprivate static final String DEFAULT_USERNAME = \"postgres\";\n\n\tprivate static final String[] DATABASE_KEYS = new String[] { \"POSTGRES_DB\", \"POSTGRESQL_DB\",\n\t\t\t\"POSTGRESQL_DATABASE\" };\n\n\tprivate final String username;\n\n\tprivate final @Nullable String password;\n\n\tprivate final String database;\n\n\tPostgresEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extract(env, USERNAME_KEYS, DEFAULT_USERNAME);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extract(env, DATABASE_KEYS, this.username);\n\t}\n\n\tprivate String extract(Map<String, @Nullable String> env, String[] keys, String defaultValue) {\n\t\tfor (String key : keys) {\n\t\t\tString value = env.get(key);\n\t\t\tif (value != null) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n\tprivate @Nullable String extractPassword(Map<String, @Nullable String> env) {\n\t\tif (isUsingTrustHostAuthMethod(env)) {\n\t\t\treturn null;\n\t\t}\n\t\tString password = env.getOrDefault(\"POSTGRES_PASSWORD\", env.get(\"POSTGRESQL_PASSWORD\"));\n\t\tboolean allowEmpty = env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tAssert.state(allowEmpty || StringUtils.hasLength(password), \"No PostgreSQL password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tprivate boolean isUsingTrustHostAuthMethod(Map<String, @Nullable String> env) {\n\t\tString hostAuthMethod = env.get(\"POSTGRES_HOST_AUTH_METHOD\");\n\t\treturn \"trust\".equals(hostAuthMethod);\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/PostgresJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for a {@code postgres} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass PostgresJdbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {\n\n\tprotected PostgresJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"postgres\");\n\t}\n\n\t@Override\n\tprotected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new PostgresJdbcDockerComposeConnectionDetails(source.getRunningService(), source.getEnvironment());\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by a {@code postgres} {@link RunningService}.\n\t */\n\tstatic class PostgresJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements JdbcConnectionDetails {\n\n\t\tprivate static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder(\"postgresql\", 5432);\n\n\t\tprivate final PostgresEnvironment environment;\n\n\t\tprivate final String jdbcUrl;\n\n\t\tPostgresJdbcDockerComposeConnectionDetails(RunningService service, Environment environment) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new PostgresEnvironment(service.env());\n\t\t\tthis.jdbcUrl = addApplicationNameIfNecessary(jdbcUrlBuilder.build(service, this.environment.getDatabase()),\n\t\t\t\t\tenvironment);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t\tprivate static String addApplicationNameIfNecessary(String jdbcUrl, Environment environment) {\n\t\t\tif (jdbcUrl.contains(\"&ApplicationName=\") || jdbcUrl.contains(\"?ApplicationName=\")) {\n\t\t\t\treturn jdbcUrl;\n\t\t\t}\n\t\t\tString applicationName = environment.getProperty(\"spring.application.name\");\n\t\t\tif (!StringUtils.hasText(applicationName)) {\n\t\t\t\treturn jdbcUrl;\n\t\t\t}\n\t\t\tStringBuilder jdbcUrlBuilder = new StringBuilder(jdbcUrl);\n\t\t\tif (!jdbcUrl.contains(\"?\")) {\n\t\t\t\tjdbcUrlBuilder.append(\"?\");\n\t\t\t}\n\t\t\telse if (!jdbcUrl.endsWith(\"&\")) {\n\t\t\t\tjdbcUrlBuilder.append(\"&\");\n\t\t\t}\n\t\t\treturn jdbcUrlBuilder.append(\"ApplicationName\")\n\t\t\t\t.append('=')\n\t\t\t\t.append(URLEncoder.encode(applicationName, StandardCharsets.UTF_8))\n\t\t\t\t.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/SqlServerEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * MS SQL Server environment details.\n *\n * @author Andy Wilkinson\n */\nclass SqlServerEnvironment {\n\n\tprivate final String username = \"SA\";\n\n\tprivate final String password;\n\n\tSqlServerEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.password = extractPassword(env);\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tString password = env.get(\"MSSQL_SA_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"SA_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password), \"No MSSQL password found\");\n\t\treturn password;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/SqlServerJdbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}\n * for a {@code mssql/server} service.\n *\n * @author Andy Wilkinson\n */\nclass SqlServerJdbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {\n\n\tprotected SqlServerJdbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mssql/server\");\n\t}\n\n\t@Override\n\tprotected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new SqlServerJdbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by a {@code mssql/server}\n\t * {@link RunningService}.\n\t */\n\tstatic class SqlServerJdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements JdbcConnectionDetails {\n\n\t\tprivate static final JdbcUrlBuilder jdbcUrlBuilder = new SqlServerJdbcUrlBuilder(\"sqlserver\", 1433);\n\n\t\tprivate final SqlServerEnvironment environment;\n\n\t\tprivate final String jdbcUrl;\n\n\t\tSqlServerJdbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.environment = new SqlServerEnvironment(service.env());\n\t\t\tthis.jdbcUrl = disableEncryptionIfNecessary(jdbcUrlBuilder.build(service));\n\t\t}\n\n\t\tprivate String disableEncryptionIfNecessary(String jdbcUrl) {\n\t\t\tif (jdbcUrl.contains(\";encrypt=false;\")) {\n\t\t\t\treturn jdbcUrl;\n\t\t\t}\n\t\t\tStringBuilder jdbcUrlBuilder = new StringBuilder(jdbcUrl);\n\t\t\tif (!jdbcUrl.endsWith(\";\")) {\n\t\t\t\tjdbcUrlBuilder.append(\";\");\n\t\t\t}\n\t\t\tjdbcUrlBuilder.append(\"encrypt=false;\");\n\t\t\treturn jdbcUrlBuilder.toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.environment.getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.environment.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t\tprivate static final class SqlServerJdbcUrlBuilder extends JdbcUrlBuilder {\n\n\t\t\tprivate SqlServerJdbcUrlBuilder(String driverProtocol, int containerPort) {\n\t\t\t\tsuper(driverProtocol, containerPort);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected void appendParameters(StringBuilder url, String parameters) {\n\t\t\t\turl.append(\";\").append(parameters);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose JDBC service connections.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/health/DataSourceHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.health;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.dao.support.DataAccessUtils;\nimport org.springframework.jdbc.IncorrectResultSetColumnCountException;\nimport org.springframework.jdbc.core.ConnectionCallback;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.RowMapper;\nimport org.springframework.jdbc.support.JdbcUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link HealthIndicator} that tests the status of a {@link DataSource} and optionally\n * runs a test query.\n *\n * @author Dave Syer\n * @author Christian Dupuis\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Arthur Kalimullin\n * @since 4.0.0\n */\npublic class DataSourceHealthIndicator extends AbstractHealthIndicator implements InitializingBean {\n\n\tprivate @Nullable DataSource dataSource;\n\n\tprivate @Nullable String query;\n\n\tprivate @Nullable JdbcTemplate jdbcTemplate;\n\n\t/**\n\t * Create a new {@link DataSourceHealthIndicator} instance.\n\t */\n\tpublic DataSourceHealthIndicator() {\n\t\tthis(null, null);\n\t}\n\n\t/**\n\t * Create a new {@link DataSourceHealthIndicator} using the specified\n\t * {@link DataSource}.\n\t * @param dataSource the data source\n\t */\n\tpublic DataSourceHealthIndicator(@Nullable DataSource dataSource) {\n\t\tthis(dataSource, null);\n\t}\n\n\t/**\n\t * Create a new {@link DataSourceHealthIndicator} using the specified\n\t * {@link DataSource} and validation query.\n\t * @param dataSource the data source\n\t * @param query the validation query to use (can be {@code null})\n\t */\n\tpublic DataSourceHealthIndicator(@Nullable DataSource dataSource, @Nullable String query) {\n\t\tsuper(\"DataSource health check failed\");\n\t\tthis.dataSource = dataSource;\n\t\tthis.query = query;\n\t\tthis.jdbcTemplate = (dataSource != null) ? new JdbcTemplate(dataSource) : null;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tAssert.state(this.dataSource != null, \"DataSource for DataSourceHealthIndicator must be specified\");\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tif (this.dataSource == null) {\n\t\t\tbuilder.up().withDetail(\"database\", \"unknown\");\n\t\t}\n\t\telse {\n\t\t\tdoDataSourceHealthCheck(builder);\n\t\t}\n\t}\n\n\tprivate void doDataSourceHealthCheck(Health.Builder builder) {\n\t\tAssert.state(this.jdbcTemplate != null, \"'jdbcTemplate' must not be null\");\n\t\tbuilder.up().withDetail(\"database\", getProduct(this.jdbcTemplate));\n\t\tString validationQuery = this.query;\n\t\tif (StringUtils.hasText(validationQuery)) {\n\t\t\tbuilder.withDetail(\"validationQuery\", validationQuery);\n\t\t\t// Avoid calling getObject as it breaks MySQL on Java 7 and later\n\t\t\tList<Object> results = this.jdbcTemplate.query(validationQuery, new SingleColumnRowMapper());\n\t\t\tObject result = DataAccessUtils.requiredSingleResult(results);\n\t\t\tbuilder.withDetail(\"result\", result);\n\t\t}\n\t\telse {\n\t\t\tbuilder.withDetail(\"validationQuery\", \"isValid()\");\n\t\t\tboolean valid = isConnectionValid(this.jdbcTemplate);\n\t\t\tbuilder.status((valid) ? Status.UP : Status.DOWN);\n\t\t}\n\t}\n\n\tprivate String getProduct(JdbcTemplate jdbcTemplate) {\n\t\treturn jdbcTemplate.execute((ConnectionCallback<String>) this::getProduct);\n\t}\n\n\tprivate String getProduct(Connection connection) throws SQLException {\n\t\treturn connection.getMetaData().getDatabaseProductName();\n\t}\n\n\tprivate Boolean isConnectionValid(JdbcTemplate jdbcTemplate) {\n\t\treturn jdbcTemplate.execute((ConnectionCallback<Boolean>) this::isConnectionValid);\n\t}\n\n\tprivate Boolean isConnectionValid(Connection connection) throws SQLException {\n\t\treturn connection.isValid(0);\n\t}\n\n\t/**\n\t * Set the {@link DataSource} to use.\n\t * @param dataSource the data source\n\t */\n\tpublic void setDataSource(DataSource dataSource) {\n\t\tthis.dataSource = dataSource;\n\t\tthis.jdbcTemplate = new JdbcTemplate(dataSource);\n\t}\n\n\t/**\n\t * Set a specific validation query to use to validate a connection. If none is set, a\n\t * validation based on {@link Connection#isValid(int)} is used.\n\t * @param query the validation query to use\n\t */\n\tpublic void setQuery(String query) {\n\t\tthis.query = query;\n\t}\n\n\t/**\n\t * Return the validation query or {@code null}.\n\t * @return the query\n\t */\n\tpublic @Nullable String getQuery() {\n\t\treturn this.query;\n\t}\n\n\t/**\n\t * {@link RowMapper} that expects and returns results from a single column.\n\t */\n\tprivate static final class SingleColumnRowMapper implements RowMapper<Object> {\n\n\t\t@Override\n\t\tpublic Object mapRow(ResultSet rs, int rowNum) throws SQLException {\n\t\t\tResultSetMetaData metaData = rs.getMetaData();\n\t\t\tint columns = metaData.getColumnCount();\n\t\t\tif (columns != 1) {\n\t\t\t\tthrow new IncorrectResultSetColumnCountException(1, columns);\n\t\t\t}\n\t\t\tObject result = JdbcUtils.getResultSetValue(rs, 1);\n\t\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for JDBC.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.core.io.Resource;\nimport org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\n\n/**\n * {@link InitializingBean} that performs {@link DataSource} initialization using schema\n * (DDL) and data (DML) scripts.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic class DataSourceScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer {\n\n\tprivate static final Log logger = LogFactory.getLog(DataSourceScriptDatabaseInitializer.class);\n\n\tprivate final DataSource dataSource;\n\n\t/**\n\t * Creates a new {@link DataSourceScriptDatabaseInitializer} that will initialize the\n\t * given {@code DataSource} using the given settings.\n\t * @param dataSource data source to initialize\n\t * @param settings the initialization settings\n\t */\n\tpublic DataSourceScriptDatabaseInitializer(DataSource dataSource, DatabaseInitializationSettings settings) {\n\t\tsuper(settings);\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t/**\n\t * Returns the {@code DataSource} that will be initialized.\n\t * @return the initialization data source\n\t */\n\tprotected final DataSource getDataSource() {\n\t\treturn this.dataSource;\n\t}\n\n\t@Override\n\tprotected boolean isEmbeddedDatabase() {\n\t\ttry {\n\t\t\treturn EmbeddedDatabaseConnection.isEmbedded(this.dataSource);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.debug(\"Could not determine if datasource is embedded\", ex);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tprotected void runScripts(Scripts scripts) {\n\t\tResourceDatabasePopulator populator = new ResourceDatabasePopulator();\n\t\tpopulator.setContinueOnError(scripts.isContinueOnError());\n\t\tpopulator.setSeparator(scripts.getSeparator());\n\t\tif (scripts.getEncoding() != null) {\n\t\t\tpopulator.setSqlScriptEncoding(scripts.getEncoding().name());\n\t\t}\n\t\tfor (Resource resource : scripts) {\n\t\t\tpopulator.addScript(resource);\n\t\t}\n\t\tcustomize(populator);\n\t\tDatabasePopulatorUtils.execute(populator, this.dataSource);\n\t}\n\n\t/**\n\t * Customize the {@link ResourceDatabasePopulator}.\n\t * @param populator the configured database populator\n\t * @since 2.6.2\n\t */\n\tprotected void customize(ResourceDatabasePopulator populator) {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\nimport org.springframework.core.Ordered;\n\n/**\n * A {@link DatabaseInitializerDetector} for {@link DataSourceScriptDatabaseInitializer}.\n *\n * @author Andy Wilkinson\n */\nclass DataSourceScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\tstatic final int PRECEDENCE = Ordered.LOWEST_PRECEDENCE - 100;\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\treturn Collections.singleton(DataSourceScriptDatabaseInitializer.class);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/init/DatabaseInitializationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationPropertiesSource;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\n\n/**\n * Base configuration properties class for performing SQL database initialization.\n *\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationPropertiesSource\npublic abstract class DatabaseInitializationProperties {\n\n\t/**\n\t * Path to the SQL file to use to initialize the database schema.\n\t */\n\tprivate String schema = getDefaultSchemaLocation();\n\n\t/**\n\t * Platform to use in initialization scripts if the @@platform@@ placeholder is used.\n\t * Auto-detected by default.\n\t */\n\tprivate @Nullable String platform;\n\n\t/**\n\t * Database schema initialization mode.\n\t */\n\tprivate DatabaseInitializationMode initializeSchema = DatabaseInitializationMode.EMBEDDED;\n\n\t/**\n\t * Whether initialization should continue when an error occurs when applying a schema\n\t * script.\n\t */\n\tprivate boolean continueOnError = true;\n\n\tpublic String getSchema() {\n\t\treturn this.schema;\n\t}\n\n\tpublic void setSchema(String schema) {\n\t\tthis.schema = schema;\n\t}\n\n\tpublic @Nullable String getPlatform() {\n\t\treturn this.platform;\n\t}\n\n\tpublic void setPlatform(String platform) {\n\t\tthis.platform = platform;\n\t}\n\n\tpublic DatabaseInitializationMode getInitializeSchema() {\n\t\treturn this.initializeSchema;\n\t}\n\n\tpublic void setInitializeSchema(DatabaseInitializationMode initializeSchema) {\n\t\tthis.initializeSchema = initializeSchema;\n\t}\n\n\tpublic boolean isContinueOnError() {\n\t\treturn this.continueOnError;\n\t}\n\n\tpublic void setContinueOnError(boolean continueOnError) {\n\t\tthis.continueOnError = continueOnError;\n\t}\n\n\tpublic abstract String getDefaultSchemaLocation();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport java.sql.DatabaseMetaData;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.jdbc.support.JdbcUtils;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility class that can resolve placeholder text with the actual {@link DatabaseDriver}\n * platform.\n * <p>\n * By default, the name of the platform is the {@link DatabaseDriver#getId ID of the\n * driver}. This mapping can be customized by\n * {@link #withDriverPlatform(DatabaseDriver, String)} registering custom\n * {@code DatabaseDriver} to platform mappings.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 2.6.0\n */\npublic class PlatformPlaceholderDatabaseDriverResolver {\n\n\tprivate final String placeholder;\n\n\tprivate final Map<DatabaseDriver, String> driverMappings;\n\n\t/**\n\t * Creates a new resolver that will use the default {@code \"@@platform@@\"}\n\t * placeholder.\n\t */\n\tpublic PlatformPlaceholderDatabaseDriverResolver() {\n\t\tthis(\"@@platform@@\");\n\t}\n\n\t/**\n\t * Creates a new resolver that will use the given {@code placeholder}.\n\t * @param placeholder the placeholder to use\n\t */\n\tpublic PlatformPlaceholderDatabaseDriverResolver(String placeholder) {\n\t\tthis(placeholder, Collections.emptyMap());\n\t}\n\n\tprivate PlatformPlaceholderDatabaseDriverResolver(String placeholder, Map<DatabaseDriver, String> driverMappings) {\n\t\tthis.placeholder = placeholder;\n\t\tthis.driverMappings = driverMappings;\n\t}\n\n\t/**\n\t * Creates a new {@link PlatformPlaceholderDatabaseDriverResolver} that will map the\n\t * given {@code driver} to the given {@code platform}.\n\t * @param driver the driver\n\t * @param platform the platform\n\t * @return the new resolver\n\t */\n\tpublic PlatformPlaceholderDatabaseDriverResolver withDriverPlatform(DatabaseDriver driver, String platform) {\n\t\tMap<DatabaseDriver, String> driverMappings = new LinkedHashMap<>(this.driverMappings);\n\t\tdriverMappings.put(driver, platform);\n\t\treturn new PlatformPlaceholderDatabaseDriverResolver(this.placeholder, driverMappings);\n\t}\n\n\t/**\n\t * Resolves the placeholders in the given {@code values}, replacing them with the\n\t * platform derived from the {@link DatabaseDriver} of the given {@code dataSource}.\n\t * @param dataSource the DataSource from which the {@link DatabaseDriver} is derived\n\t * @param values the values in which placeholders are resolved\n\t * @return the values with their placeholders resolved\n\t */\n\tpublic List<String> resolveAll(DataSource dataSource, String... values) {\n\t\tAssert.notNull(dataSource, \"'dataSource' must not be null\");\n\t\treturn resolveAll(() -> determinePlatform(dataSource), values);\n\t}\n\n\t/**\n\t * Resolves the placeholders in the given {@code values}, replacing them with the\n\t * given platform.\n\t * @param platform the platform to use\n\t * @param values the values in which placeholders are resolved\n\t * @return the values with their placeholders resolved\n\t * @since 2.6.2\n\t */\n\tpublic List<String> resolveAll(String platform, String... values) {\n\t\tAssert.notNull(platform, \"'platform' must not be null\");\n\t\treturn resolveAll(() -> platform, values);\n\t}\n\n\tprivate List<String> resolveAll(Supplier<String> platformProvider, String... values) {\n\t\tif (ObjectUtils.isEmpty(values)) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<String> resolved = new ArrayList<>(values.length);\n\t\tString platform = null;\n\t\tfor (String value : values) {\n\t\t\tif (StringUtils.hasLength(value)) {\n\t\t\t\tif (value.contains(this.placeholder)) {\n\t\t\t\t\tplatform = (platform != null) ? platform : platformProvider.get();\n\t\t\t\t\tvalue = value.replace(this.placeholder, platform);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresolved.add(value);\n\t\t}\n\t\treturn Collections.unmodifiableList(resolved);\n\t}\n\n\tprivate String determinePlatform(DataSource dataSource) {\n\t\tDatabaseDriver databaseDriver = getDatabaseDriver(dataSource);\n\t\tAssert.state(databaseDriver != DatabaseDriver.UNKNOWN, \"Unable to detect database type\");\n\t\treturn this.driverMappings.getOrDefault(databaseDriver, databaseDriver.getId());\n\t}\n\n\tDatabaseDriver getDatabaseDriver(DataSource dataSource) {\n\t\ttry {\n\t\t\tString productName = JdbcUtils.commonDatabaseName(\n\t\t\t\t\tJdbcUtils.extractDatabaseMetaData(dataSource, DatabaseMetaData::getDatabaseProductName));\n\t\t\treturn DatabaseDriver.fromProductName(productName);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to determine DatabaseDriver\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/init/PropertiesBasedDataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.util.StringUtils;\n\n/**\n * Convenience class for construct {@link DataSourceScriptDatabaseInitializer} base on\n * {@link DatabaseInitializationProperties}.\n *\n * @param <T> the {@link DatabaseInitializationProperties} type being used\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class PropertiesBasedDataSourceScriptDatabaseInitializer<T extends DatabaseInitializationProperties>\n\t\textends DataSourceScriptDatabaseInitializer {\n\n\t/**\n\t * Create a new {@link PropertiesBasedDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the data source\n\t * @param properties the configuration properties\n\t * @see #getSettings\n\t */\n\tpublic PropertiesBasedDataSourceScriptDatabaseInitializer(DataSource dataSource, T properties) {\n\t\tthis(dataSource, properties, Collections.emptyMap());\n\t}\n\n\t/**\n\t * Create a new {@link PropertiesBasedDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the data source\n\t * @param properties the configuration properties\n\t * @param driverMappings the driver mappings\n\t * @see #getSettings\n\t */\n\tpublic PropertiesBasedDataSourceScriptDatabaseInitializer(DataSource dataSource, T properties,\n\t\t\tMap<DatabaseDriver, String> driverMappings) {\n\t\tsuper(dataSource, getSettings(dataSource, properties, driverMappings));\n\t}\n\n\t/**\n\t * Adapts {@link DatabaseInitializationProperties configuration properties} to\n\t * {@link DatabaseInitializationSettings} replacing any {@literal @@platform@@}\n\t * placeholders.\n\t * @param dataSource the data source\n\t * @param properties the configuration properties\n\t * @param driverMappings the driver mappings\n\t * @param <T> the {@link DatabaseInitializationProperties} type being used\n\t * @return a new {@link DatabaseInitializationSettings} instance\n\t */\n\tprivate static <T extends DatabaseInitializationProperties> DatabaseInitializationSettings getSettings(\n\t\t\tDataSource dataSource, T properties, Map<DatabaseDriver, String> driverMappings) {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(resolveSchemaLocations(dataSource, properties, driverMappings));\n\t\tsettings.setMode(properties.getInitializeSchema());\n\t\tsettings.setContinueOnError(properties.isContinueOnError());\n\t\treturn settings;\n\t}\n\n\tprivate static <T extends DatabaseInitializationProperties> List<String> resolveSchemaLocations(\n\t\t\tDataSource dataSource, T properties, Map<DatabaseDriver, String> driverMappings) {\n\t\tPlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver();\n\t\tfor (Map.Entry<DatabaseDriver, String> entry : driverMappings.entrySet()) {\n\t\t\tplatformResolver = platformResolver.withDriverPlatform(entry.getKey(), entry.getValue());\n\t\t}\n\t\tif (StringUtils.hasText(properties.getPlatform())) {\n\t\t\treturn platformResolver.resolveAll(properties.getPlatform(), properties.getSchema());\n\t\t}\n\t\treturn platformResolver.resolveAll(dataSource, properties.getSchema());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/init/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for initialization of an SQL database using a JDBC {@link javax.sql.DataSource\n * DataSource}.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.init;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A base {@link DataSourcePoolMetadata} implementation.\n *\n * @param <T> the data source type\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic abstract class AbstractDataSourcePoolMetadata<T extends DataSource> implements DataSourcePoolMetadata {\n\n\tprivate final T dataSource;\n\n\t/**\n\t * Create an instance with the data source to use.\n\t * @param dataSource the data source\n\t */\n\tprotected AbstractDataSourcePoolMetadata(T dataSource) {\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t@Override\n\tpublic @Nullable Float getUsage() {\n\t\tInteger maxSize = getMax();\n\t\tInteger currentSize = getActive();\n\t\tif (maxSize == null || currentSize == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (maxSize < 0) {\n\t\t\treturn -1f;\n\t\t}\n\t\tif (currentSize == 0) {\n\t\t\treturn 0f;\n\t\t}\n\t\treturn (float) currentSize / (float) maxSize;\n\t}\n\n\tprotected final T getDataSource() {\n\t\treturn this.dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link DataSourcePoolMetadata} for an Apache Commons DBCP2 {@link DataSource}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class CommonsDbcp2DataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<BasicDataSource> {\n\n\tpublic CommonsDbcp2DataSourcePoolMetadata(BasicDataSource dataSource) {\n\t\tsuper(dataSource);\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getActive() {\n\t\treturn getDataSource().getNumActive();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getIdle() {\n\t\treturn getDataSource().getNumIdle();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMax() {\n\t\treturn getDataSource().getMaxTotal();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMin() {\n\t\treturn getDataSource().getMinIdle();\n\t}\n\n\t@Override\n\tpublic @Nullable String getValidationQuery() {\n\t\treturn getDataSource().getValidationQuery();\n\t}\n\n\t@Override\n\tpublic @Nullable Boolean getDefaultAutoCommit() {\n\t\treturn getDataSource().getDefaultAutoCommit();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/CompositeDataSourcePoolMetadataProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@link DataSourcePoolMetadataProvider} implementation that returns the first\n * {@link DataSourcePoolMetadata} that is found by one of its delegate.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class CompositeDataSourcePoolMetadataProvider implements DataSourcePoolMetadataProvider {\n\n\tprivate final List<DataSourcePoolMetadataProvider> providers;\n\n\t/**\n\t * Create a {@link CompositeDataSourcePoolMetadataProvider} instance with an initial\n\t * collection of delegates to use.\n\t * @param providers the data source pool metadata providers\n\t */\n\tpublic CompositeDataSourcePoolMetadataProvider(\n\t\t\t@Nullable Collection<? extends DataSourcePoolMetadataProvider> providers) {\n\t\tthis.providers = (providers != null) ? List.copyOf(providers) : Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic @Nullable DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource) {\n\t\tfor (DataSourcePoolMetadataProvider provider : this.providers) {\n\t\t\tDataSourcePoolMetadata metadata = provider.getDataSourcePoolMetadata(dataSource);\n\t\t\tif (metadata != null) {\n\t\t\t\treturn metadata;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/DataSourcePoolMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides access meta-data that is commonly available from most pooled\n * {@link DataSource} implementations.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 2.0.0\n */\npublic interface DataSourcePoolMetadata {\n\n\t/**\n\t * Return the usage of the pool as value between 0 and 1 (or -1 if the pool is not\n\t * limited).\n\t * <ul>\n\t * <li>1 means that the maximum number of connections have been allocated</li>\n\t * <li>0 means that no connection is currently active</li>\n\t * <li>-1 means there is not limit to the number of connections that can be allocated\n\t * </li>\n\t * </ul>\n\t * This may also return {@code null} if the data source does not provide the necessary\n\t * information to compute the poll usage.\n\t * @return the usage value or {@code null}\n\t */\n\t@Nullable Float getUsage();\n\n\t/**\n\t * Return the current number of active connections that have been allocated from the\n\t * data source or {@code null} if that information is not available.\n\t * @return the number of active connections or {@code null}\n\t */\n\t@Nullable Integer getActive();\n\n\t/**\n\t * Return the number of established but idle connections. Can also return {@code null}\n\t * if that information is not available.\n\t * @return the number of established but idle connections or {@code null}\n\t * @since 2.2.0\n\t * @see #getActive()\n\t */\n\tdefault @Nullable Integer getIdle() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the maximum number of active connections that can be allocated at the same\n\t * time or {@code -1} if there is no limit. Can also return {@code null} if that\n\t * information is not available.\n\t * @return the maximum number of active connections or {@code null}\n\t */\n\t@Nullable Integer getMax();\n\n\t/**\n\t * Return the minimum number of idle connections in the pool or {@code null} if that\n\t * information is not available.\n\t * @return the minimum number of active connections or {@code null}\n\t */\n\t@Nullable Integer getMin();\n\n\t/**\n\t * Return the query to use to validate that a connection is valid or {@code null} if\n\t * that information is not available.\n\t * @return the validation query or {@code null}\n\t */\n\t@Nullable String getValidationQuery();\n\n\t/**\n\t * The default auto-commit state of connections created by this pool. If not set\n\t * ({@code null}), default is JDBC driver default (If set to null then the\n\t * java.sql.Connection.setAutoCommit(boolean) method will not be called.)\n\t * @return the default auto-commit state or {@code null}\n\t */\n\t@Nullable Boolean getDefaultAutoCommit();\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/DataSourcePoolMetadataProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provide a {@link DataSourcePoolMetadata} based on a {@link DataSource}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface DataSourcePoolMetadataProvider {\n\n\t/**\n\t * Return the {@link DataSourcePoolMetadata} instance able to manage the specified\n\t * {@link DataSource} or {@code null} if the given data source could not be handled.\n\t * @param dataSource the data source\n\t * @return the data source pool metadata\n\t */\n\t@Nullable DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport com.zaxxer.hikari.pool.HikariPool;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.DirectFieldAccessor;\n\n/**\n * {@link DataSourcePoolMetadata} for a Hikari {@link DataSource}.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class HikariDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<HikariDataSource> {\n\n\tpublic HikariDataSourcePoolMetadata(HikariDataSource dataSource) {\n\t\tsuper(dataSource);\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getActive() {\n\t\ttry {\n\t\t\tHikariPool hikariPool = getHikariPool();\n\t\t\treturn (hikariPool != null) ? hikariPool.getActiveConnections() : null;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getIdle() {\n\t\ttry {\n\t\t\tHikariPool hikariPool = getHikariPool();\n\t\t\treturn (hikariPool != null) ? hikariPool.getIdleConnections() : null;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable HikariPool getHikariPool() {\n\t\treturn (HikariPool) new DirectFieldAccessor(getDataSource()).getPropertyValue(\"pool\");\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMax() {\n\t\treturn getDataSource().getMaximumPoolSize();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMin() {\n\t\treturn getDataSource().getMinimumIdle();\n\t}\n\n\t@Override\n\tpublic @Nullable String getValidationQuery() {\n\t\treturn getDataSource().getConnectionTestQuery();\n\t}\n\n\t@Override\n\tpublic @Nullable Boolean getDefaultAutoCommit() {\n\t\treturn getDataSource().isAutoCommit();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/OracleUcpDataSourcePoolMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport oracle.ucp.jdbc.PoolDataSource;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link DataSourcePoolMetadata} for an Oracle UCP {@link DataSource}.\n *\n * @author Fabio Grassi\n * @since 2.4.0\n */\npublic class OracleUcpDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<PoolDataSource> {\n\n\tpublic OracleUcpDataSourcePoolMetadata(PoolDataSource dataSource) {\n\t\tsuper(dataSource);\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getActive() {\n\t\ttry {\n\t\t\treturn getDataSource().getBorrowedConnectionsCount();\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getIdle() {\n\t\ttry {\n\t\t\treturn getDataSource().getAvailableConnectionsCount();\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMax() {\n\t\treturn getDataSource().getMaxPoolSize();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMin() {\n\t\treturn getDataSource().getMinPoolSize();\n\t}\n\n\t@Override\n\tpublic @Nullable String getValidationQuery() {\n\t\treturn getDataSource().getSQLForValidateConnection();\n\t}\n\n\t@Override\n\tpublic @Nullable Boolean getDefaultAutoCommit() {\n\t\tString autoCommit = getDataSource().getConnectionProperty(\"autoCommit\");\n\t\treturn StringUtils.hasText(autoCommit) ? Boolean.valueOf(autoCommit) : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadata.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport org.apache.tomcat.jdbc.pool.ConnectionPool;\nimport org.apache.tomcat.jdbc.pool.DataSource;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * {@link DataSourcePoolMetadata} for a Tomcat DataSource.\n *\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class TomcatDataSourcePoolMetadata extends AbstractDataSourcePoolMetadata<DataSource> {\n\n\tpublic TomcatDataSourcePoolMetadata(DataSource dataSource) {\n\t\tsuper(dataSource);\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getActive() {\n\t\tConnectionPool pool = getDataSource().getPool();\n\t\treturn (pool != null) ? pool.getActive() : 0;\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getIdle() {\n\t\treturn getDataSource().getNumIdle();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMax() {\n\t\treturn getDataSource().getMaxActive();\n\t}\n\n\t@Override\n\tpublic @Nullable Integer getMin() {\n\t\treturn getDataSource().getMinIdle();\n\t}\n\n\t@Override\n\tpublic @Nullable String getValidationQuery() {\n\t\treturn getDataSource().getValidationQuery();\n\t}\n\n\t@Override\n\tpublic @Nullable Boolean getDefaultAutoCommit() {\n\t\treturn getDataSource().isDefaultAutoCommit();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metadata/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for accessing JDBC {@link javax.sql.DataSource} metadata.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.metadata;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metrics/DataSourcePoolMetrics.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metrics;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jdbc.metadata.CompositeDataSourcePoolMetadataProvider;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadata;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ConcurrentReferenceHashMap;\n\n/**\n * A {@link MeterBinder} for a {@link DataSource}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DataSourcePoolMetrics implements MeterBinder {\n\n\tprivate final DataSource dataSource;\n\n\tprivate final CachingDataSourcePoolMetadataProvider metadataProvider;\n\n\tprivate final Iterable<Tag> tags;\n\n\tpublic DataSourcePoolMetrics(DataSource dataSource, Collection<DataSourcePoolMetadataProvider> metadataProviders,\n\t\t\tString dataSourceName, Iterable<Tag> tags) {\n\t\tthis(dataSource, new CompositeDataSourcePoolMetadataProvider(metadataProviders), dataSourceName, tags);\n\t}\n\n\tpublic DataSourcePoolMetrics(DataSource dataSource, DataSourcePoolMetadataProvider metadataProvider, String name,\n\t\t\tIterable<Tag> tags) {\n\t\tAssert.notNull(dataSource, \"'dataSource' must not be null\");\n\t\tAssert.notNull(metadataProvider, \"'metadataProvider' must not be null\");\n\t\tthis.dataSource = dataSource;\n\t\tthis.metadataProvider = new CachingDataSourcePoolMetadataProvider(metadataProvider);\n\t\tthis.tags = Tags.concat(tags, \"name\", name);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"NullAway\") // Lambda isn't detected with the correct nullability\n\tpublic void bindTo(MeterRegistry registry) {\n\t\tif (this.metadataProvider.getDataSourcePoolMetadata(this.dataSource) != null) {\n\t\t\tbindPoolMetadata(registry, \"active\",\n\t\t\t\t\t\"Current number of active connections that have been allocated from the data source.\",\n\t\t\t\t\tDataSourcePoolMetadata::getActive);\n\t\t\tbindPoolMetadata(registry, \"idle\", \"Number of established but idle connections.\",\n\t\t\t\t\tDataSourcePoolMetadata::getIdle);\n\t\t\tbindPoolMetadata(registry, \"max\",\n\t\t\t\t\t\"Maximum number of active connections that can be allocated at the same time.\",\n\t\t\t\t\tDataSourcePoolMetadata::getMax);\n\t\t\tbindPoolMetadata(registry, \"min\", \"Minimum number of idle connections in the pool.\",\n\t\t\t\t\tDataSourcePoolMetadata::getMin);\n\t\t}\n\t}\n\n\tprivate <N extends Number> void bindPoolMetadata(MeterRegistry registry, String metricName, String description,\n\t\t\tFunction<DataSourcePoolMetadata, @Nullable N> function) {\n\t\tbindDataSource(registry, metricName, description, this.metadataProvider.getValueFunction(function));\n\t}\n\n\tprivate <N extends Number> void bindDataSource(MeterRegistry registry, String metricName, String description,\n\t\t\tFunction<DataSource, @Nullable N> function) {\n\t\tif (function.apply(this.dataSource) != null) {\n\t\t\tGauge.builder(\"jdbc.connections.\" + metricName, this.dataSource, (m) -> {\n\t\t\t\tNumber value = function.apply(m);\n\t\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\t\treturn value.doubleValue();\n\t\t\t}).tags(this.tags).description(description).register(registry);\n\t\t}\n\t}\n\n\tprivate static class CachingDataSourcePoolMetadataProvider implements DataSourcePoolMetadataProvider {\n\n\t\tprivate static final Map<DataSource, DataSourcePoolMetadata> cache = new ConcurrentReferenceHashMap<>();\n\n\t\tprivate final DataSourcePoolMetadataProvider metadataProvider;\n\n\t\tCachingDataSourcePoolMetadataProvider(DataSourcePoolMetadataProvider metadataProvider) {\n\t\t\tthis.metadataProvider = metadataProvider;\n\t\t}\n\n\t\t<N extends Number> Function<DataSource, @Nullable N> getValueFunction(\n\t\t\t\tFunction<DataSourcePoolMetadata, @Nullable N> function) {\n\t\t\treturn (dataSource) -> {\n\t\t\t\tDataSourcePoolMetadata dataSourcePoolMetadata = getDataSourcePoolMetadata(dataSource);\n\t\t\t\tAssert.state(dataSourcePoolMetadata != null, \"'dataSourcePoolMetadata' must not be null\");\n\t\t\t\treturn function.apply(dataSourcePoolMetadata);\n\t\t\t};\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable DataSourcePoolMetadata getDataSourcePoolMetadata(DataSource dataSource) {\n\t\t\treturn cache.computeIfAbsent(dataSource,\n\t\t\t\t\t(key) -> this.metadataProvider.getDataSourcePoolMetadata(dataSource));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Metrics for JDBC.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Java Database Connectivity (JDBC).\n */\n@NullMarked\npackage org.springframework.boot.jdbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/testcontainers/JdbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.testcontainers;\n\nimport org.testcontainers.containers.JdbcDatabaseContainer;\n\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link JdbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link JdbcDatabaseContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass JdbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<JdbcDatabaseContainer<?>, JdbcConnectionDetails> {\n\n\t@Override\n\tprotected JdbcConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\treturn new JdbcContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link JdbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class JdbcContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<JdbcDatabaseContainer<?>> implements JdbcConnectionDetails {\n\n\t\tprivate JdbcContainerConnectionDetails(ContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn getContainer().getJdbcUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDriverClassName() {\n\t\t\treturn getContainer().getDriverClassName();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/java/org/springframework/boot/jdbc/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers JDBC service connections.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"management.health.db.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable database health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.datasource.continue-on-error\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.continue-on-error\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.data\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.data-locations\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.data-password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.password\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.data-username\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.username\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.initialization-mode\",\n      \"type\": \"org.springframework.boot.jdbc.DataSourceInitializationMode\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.mode\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.jmx-enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JMX support (if provided by the underlying pool).\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.datasource.tomcat.jmx-enabled\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.platform\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.platform\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.schema\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.schema-locations\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.schema-password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.password\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.schema-username\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.username\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.separator\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.separator\",\n        \"since\": \"2.5.0\"\n      }\n    },\n    {\n      \"name\": \"spring.datasource.sql-script-encoding\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.sql.init.encoding\",\n        \"since\": \"2.5.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.datasource.data\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.util.List<org.springframework.core.io.Resource>\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.datasource.driver-class-name\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"java.sql.Driver\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.datasource.schema\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.util.List<org.springframework.core.io.Resource>\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.datasource.xa.data-source-class-name\",\n      \"providers\": [\n        {\n          \"name\": \"class-reference\",\n          \"parameters\": {\n            \"target\": \"javax.sql.XADataSource\"\n          }\n        }\n      ]\n    }\n  ],\n  \"ignored\": {\n    \"properties\": [\n      {\n        \"name\": \"spring.datasource.dbcp2.driver\"\n      },\n      {\n        \"name\": \"spring.datasource.hikari.credentials\"\n      },\n      {\n        \"name\": \"spring.datasource.hikari.credentials-provider\"\n      },\n      {\n        \"name\": \"spring.datasource.hikari.exception-override\"\n      },\n      {\n        \"name\": \"spring.datasource.hikari.metrics-tracker-factory\"\n      },\n      {\n        \"name\": \"spring.datasource.hikari.scheduled-executor\"\n      },\n      {\n        \"name\": \"spring.datasource.oracleucp.connection-wait-duration-in-millis\"\n      },\n      {\n        \"name\": \"spring.datasource.oracleucp.hostname-resolver\"\n      }\n    ]\n  }\n}"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.jdbc.DataSourceBuilderRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.JdbcClientAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.JndiDataSourceAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.XADataSourceAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.health.DataSourceHealthContributorAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.metrics.DataSourcePoolMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/main/resources/META-INF/spring.factories",
    "content": "# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.jdbc.autoconfigure.DataSourceBeanCreationFailureAnalyzer,\\\norg.springframework.boot.jdbc.autoconfigure.HikariDriverConfigurationFailureAnalyzer\n\n# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.jdbc.docker.compose.ClickHouseJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.docker.compose.MariaDbJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.docker.compose.MySqlJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.docker.compose.OracleFreeJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.docker.compose.OracleXeJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.docker.compose.PostgresJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.docker.compose.SqlServerJdbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.jdbc.testcontainers.JdbcContainerConnectionDetailsFactory\n\n# Database Initializer Detectors\norg.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\\\norg.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializerDetector\n\n# Depends On Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.jdbc.SpringJdbcDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderNoHikariTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourceBuilder} when Hikari is not on the classpath.\n *\n * @author Phillip Webb\n */\n@ClassPathExclusions(\"Hikari*.jar\")\nclass DataSourceBuilderNoHikariTests {\n\n\t@Test\n\tvoid findTypeReturnsTomcatDataSource() {\n\t\tassertThat(DataSourceBuilder.findType(null)).isEqualTo(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t}\n\n\t@Test\n\tvoid createAndBuildReturnsTomcatDataSource() {\n\t\tDataSource dataSource = DataSourceBuilder.create().build();\n\t\tassertThat(dataSource).isInstanceOf(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.ReflectionHints;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeHint;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourceBuilderRuntimeHints}.\n *\n * @author Phillip Webb\n */\nclass DataSourceBuilderRuntimeHintsTests {\n\n\t@Test\n\tvoid shouldRegisterDataSourceConstructors() {\n\t\tReflectionHints hints = registerHints();\n\t\tStream\n\t\t\t.of(com.mchange.v2.c3p0.ComboPooledDataSource.class, com.zaxxer.hikari.HikariDataSource.class,\n\t\t\t\t\toracle.jdbc.datasource.OracleDataSource.class, oracle.ucp.jdbc.PoolDataSourceImpl.class,\n\t\t\t\t\torg.apache.commons.dbcp2.BasicDataSource.class, org.apache.tomcat.jdbc.pool.DataSource.class,\n\t\t\t\t\torg.h2.jdbcx.JdbcDataSource.class, org.postgresql.ds.PGSimpleDataSource.class,\n\t\t\t\t\torg.springframework.jdbc.datasource.SimpleDriverDataSource.class,\n\t\t\t\t\torg.vibur.dbcp.ViburDBCPDataSource.class)\n\t\t\t.forEach((dataSourceType) -> {\n\t\t\t\tTypeHint typeHint = hints.getTypeHint(dataSourceType);\n\t\t\t\tassertThat(typeHint).withFailMessage(() -> \"No hints found for data source type \" + dataSourceType)\n\t\t\t\t\t.isNotNull();\n\t\t\t\tassertThat(typeHint).isNotNull();\n\t\t\t\tSet<MemberCategory> memberCategories = typeHint.getMemberCategories();\n\t\t\t\tassertThat(memberCategories).containsExactly(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t\t});\n\t}\n\n\tprivate ReflectionHints registerHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew DataSourceBuilderRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\treturn hints.reflection();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DataSourceBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.SQLFeatureNotSupportedException;\nimport java.util.Arrays;\nimport java.util.logging.Logger;\n\nimport javax.sql.DataSource;\n\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport com.microsoft.sqlserver.jdbc.SQLServerDataSource;\nimport com.zaxxer.hikari.HikariDataSource;\nimport oracle.jdbc.internal.OpaqueString;\nimport oracle.jdbc.pool.OracleDataSource;\nimport oracle.ucp.jdbc.PoolDataSource;\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.h2.Driver;\nimport org.h2.jdbcx.JdbcDataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.postgresql.ds.PGSimpleDataSource;\nimport org.vibur.dbcp.ViburDBCPDataSource;\n\nimport org.springframework.jdbc.datasource.AbstractDataSource;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link DataSourceBuilder}.\n *\n * @author Stephane Nicoll\n * @author Fabio Grassi\n * @author Phillip Webb\n */\nclass DataSourceBuilderTests {\n\n\tprivate @Nullable DataSource dataSource;\n\n\t@AfterEach\n\tvoid shutdownDataSource() throws IOException {\n\t\tif (this.dataSource instanceof Closeable closeable) {\n\t\t\tcloseable.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid buildWhenHikariAvailableReturnsHikariDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create().url(\"jdbc:h2:test\").build();\n\t\tassertThat(this.dataSource).isInstanceOf(HikariDataSource.class);\n\t\tHikariDataSource hikariDataSource = (HikariDataSource) this.dataSource;\n\t\tassertThat(hikariDataSource.getJdbcUrl()).isEqualTo(\"jdbc:h2:test\");\n\t}\n\n\t@Test // gh-26633\n\tvoid buildWhenHikariDataSourceWithNullPasswordReturnsHikariDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create().url(\"jdbc:h2:test\").username(\"test\").password(null).build();\n\t\tassertThat(this.dataSource).isInstanceOf(HikariDataSource.class);\n\t\tHikariDataSource hikariDataSource = (HikariDataSource) this.dataSource;\n\t\tassertThat(hikariDataSource.getJdbcUrl()).isEqualTo(\"jdbc:h2:test\");\n\t}\n\n\t@Test\n\tvoid buildWhenHikariNotAvailableReturnsTomcatDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create(new HidePackagesClassLoader(\"com.zaxxer.hikari\"))\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t}\n\n\t@Test // gh-26633\n\tvoid buildWhenTomcatDataSourceWithNullPasswordReturnsDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create(new HidePackagesClassLoader(\"com.zaxxer.hikari\"))\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.username(\"test\")\n\t\t\t.password(null)\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t}\n\n\t@Test\n\tvoid buildWhenHikariAndTomcatNotAvailableReturnsDbcp2DataSource() {\n\t\tthis.dataSource = DataSourceBuilder\n\t\t\t.create(new HidePackagesClassLoader(\"com.zaxxer.hikari\", \"org.apache.tomcat.jdbc.pool\"))\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(BasicDataSource.class);\n\t}\n\n\t@Test // gh-26633\n\tvoid buildWhenDbcp2DataSourceWithNullPasswordReturnsDbcp2DataSource() {\n\t\tthis.dataSource = DataSourceBuilder\n\t\t\t.create(new HidePackagesClassLoader(\"com.zaxxer.hikari\", \"org.apache.tomcat.jdbc.pool\"))\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.username(\"test\")\n\t\t\t.password(null)\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(BasicDataSource.class);\n\t}\n\n\t@Test\n\tvoid buildWhenHikariAndTomcatAndDbcpNotAvailableReturnsOracleUcpDataSource() {\n\t\tthis.dataSource = DataSourceBuilder\n\t\t\t.create(new HidePackagesClassLoader(\"com.zaxxer.hikari\", \"org.apache.tomcat.jdbc.pool\",\n\t\t\t\t\t\"org.apache.commons.dbcp2\"))\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(PoolDataSourceImpl.class);\n\t}\n\n\t@Test\n\tvoid buildWhenHikariTypeSpecifiedReturnsExpectedDataSource() {\n\t\tHikariDataSource hikariDataSource = DataSourceBuilder.create().type(HikariDataSource.class).build();\n\t\tassertThat(hikariDataSource).isInstanceOf(HikariDataSource.class);\n\t}\n\n\t@Test\n\tvoid buildWhenSimpleDriverTypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create().url(\"jdbc:h2:test\").type(SimpleDriverDataSource.class).build();\n\t\tassertThat(this.dataSource).isInstanceOf(SimpleDriverDataSource.class);\n\t\tSimpleDriverDataSource simpleDriverDataSource = (SimpleDriverDataSource) this.dataSource;\n\t\tassertThat(simpleDriverDataSource.getUrl()).isEqualTo(\"jdbc:h2:test\");\n\t\tassertThat(simpleDriverDataSource.getDriver()).isInstanceOf(Driver.class);\n\t}\n\n\t@Test\n\tvoid buildWhenOracleTypeSpecifiedReturnsExpectedDataSource() throws SQLException {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:oracle:thin:@localhost:1521:xe\")\n\t\t\t.type(OracleDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(OracleDataSource.class);\n\t\tOracleDataSource oracleDataSource = (OracleDataSource) this.dataSource;\n\t\tassertThat(oracleDataSource.getURL()).isEqualTo(\"jdbc:oracle:thin:@localhost:1521:xe\");\n\t\tassertThat(oracleDataSource.getUser()).isEqualTo(\"test\");\n\t}\n\n\t@Test // gh-26631\n\tvoid buildWhenOracleTypeSpecifiedWithDriverClassReturnsExpectedDataSource() throws SQLException {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:oracle:thin:@localhost:1521:xe\")\n\t\t\t.type(OracleDataSource.class)\n\t\t\t.driverClassName(\"oracle.jdbc.pool.OracleDataSource\")\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(OracleDataSource.class);\n\t\tOracleDataSource oracleDataSource = (OracleDataSource) this.dataSource;\n\t\tassertThat(oracleDataSource.getURL()).isEqualTo(\"jdbc:oracle:thin:@localhost:1521:xe\");\n\t\tassertThat(oracleDataSource.getUser()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid buildWhenOracleUcpTypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.driverClassName(\"org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t.type(PoolDataSourceImpl.class)\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(PoolDataSourceImpl.class);\n\t\tPoolDataSourceImpl upcDataSource = (PoolDataSourceImpl) this.dataSource;\n\t\tassertThat(upcDataSource.getConnectionFactoryClassName()).isEqualTo(\"org.hsqldb.jdbc.JDBCDriver\");\n\t\tassertThat(upcDataSource.getUser()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid buildWhenH2TypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.type(JdbcDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.password(\"secret\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(JdbcDataSource.class);\n\t\tJdbcDataSource h2DataSource = (JdbcDataSource) this.dataSource;\n\t\tassertThat(h2DataSource.getUser()).isEqualTo(\"test\");\n\t\tassertThat(h2DataSource.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test // gh-26631\n\tvoid buildWhenH2TypeSpecifiedWithDriverClassReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.type(JdbcDataSource.class)\n\t\t\t.driverClassName(\"org.h2.jdbcx.JdbcDataSource\")\n\t\t\t.username(\"test\")\n\t\t\t.password(\"secret\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(JdbcDataSource.class);\n\t\tJdbcDataSource h2DataSource = (JdbcDataSource) this.dataSource;\n\t\tassertThat(h2DataSource.getUser()).isEqualTo(\"test\");\n\t\tassertThat(h2DataSource.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid buildWhenPostgresTypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:postgresql://localhost/test\")\n\t\t\t.type(PGSimpleDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(PGSimpleDataSource.class);\n\t\tPGSimpleDataSource pgDataSource = (PGSimpleDataSource) this.dataSource;\n\t\tassertThat(pgDataSource.getUser()).isEqualTo(\"test\");\n\t}\n\n\t@Test // gh-26631\n\tvoid buildWhenPostgresTypeSpecifiedWithDriverClassReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:postgresql://localhost/test\")\n\t\t\t.type(PGSimpleDataSource.class)\n\t\t\t.driverClassName(\"org.postgresql.ds.PGSimpleDataSource\")\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(PGSimpleDataSource.class);\n\t\tPGSimpleDataSource pgDataSource = (PGSimpleDataSource) this.dataSource;\n\t\tassertThat(pgDataSource.getUser()).isEqualTo(\"test\");\n\t}\n\n\t@Test // gh-26647\n\tvoid buildWhenSqlServerTypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:sqlserver://localhost/test\")\n\t\t\t.type(SQLServerDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(SQLServerDataSource.class);\n\t\tSQLServerDataSource sqlServerDataSource = (SQLServerDataSource) this.dataSource;\n\t\tassertThat(sqlServerDataSource.getUser()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid buildWhenMappedTypeSpecifiedAndNoSuitableOptionalMappingBuilds() {\n\t\tassertThatNoException().isThrownBy(\n\t\t\t\t() -> DataSourceBuilder.create().type(OracleDataSource.class).driverClassName(\"com.example\").build());\n\t}\n\n\t@Test\n\tvoid buildWhenCustomSubclassTypeSpecifiedReturnsDataSourceWithOnlyBasePropertiesSet() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.type(CustomTomcatDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(CustomTomcatDataSource.class);\n\t\tCustomTomcatDataSource testDataSource = (CustomTomcatDataSource) this.dataSource;\n\t\tassertThat(testDataSource.getUrl()).isEqualTo(\"jdbc:h2:test\");\n\t\tassertThat(testDataSource.getJdbcUrl()).isNull();\n\t\tassertThat(testDataSource.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(testDataSource.getUser()).isNull();\n\t\tassertThat(testDataSource.getDriverClassName()).isEqualTo(Driver.class.getName());\n\t\tassertThat(testDataSource.getDriverClass()).isNull();\n\t}\n\n\t@Test\n\tvoid buildWhenCustomTypeSpecifiedReturnsDataSourceWithPropertiesSetViaReflection() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.type(CustomDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.password(\"secret\")\n\t\t\t.url(\"jdbc:h2:test\")\n\t\t\t.driverClassName(\"com.example\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(CustomDataSource.class);\n\t\tCustomDataSource testDataSource = (CustomDataSource) this.dataSource;\n\t\tassertThat(testDataSource.getUrl()).isEqualTo(\"jdbc:h2:test\");\n\t\tassertThat(testDataSource.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(testDataSource.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(testDataSource.getDriverClassName()).isEqualTo(\"com.example\");\n\t}\n\n\t@Test\n\tvoid buildWhenCustomTypeSpecifiedAndNoSuitableOptionalSetterBuilds() {\n\t\tassertThatNoException().isThrownBy(() -> DataSourceBuilder.create()\n\t\t\t.type(LimitedCustomDataSource.class)\n\t\t\t.driverClassName(\"com.example\")\n\t\t\t.build());\n\t}\n\n\t@Test\n\tvoid buildWhenCustomTypeSpecifiedAndNoSuitableMandatorySetterThrowsException() {\n\t\tassertThatExceptionOfType(UnsupportedDataSourcePropertyException.class).isThrownBy(\n\t\t\t\t() -> DataSourceBuilder.create().type(LimitedCustomDataSource.class).url(\"jdbc:com.example\").build());\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedWithNewUrlReturnsNewDataSource() {\n\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setJdbcUrl(\"jdbc:h2:test\");\n\t\tHikariDataSource built = (HikariDataSource) DataSourceBuilder.derivedFrom(dataSource)\n\t\t\t.url(\"jdbc:h2:test2\")\n\t\t\t.build();\n\t\tassertThat(built.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(built.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(built.getJdbcUrl()).isEqualTo(\"jdbc:h2:test2\");\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedWithNewUsernameAndPasswordReturnsNewDataSource() {\n\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setJdbcUrl(\"jdbc:h2:test\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource);\n\t\tHikariDataSource built = (HikariDataSource) builder.username(\"test2\").password(\"secret2\").build();\n\t\tassertThat(built.getUsername()).isEqualTo(\"test2\");\n\t\tassertThat(built.getPassword()).isEqualTo(\"secret2\");\n\t\tassertThat(built.getJdbcUrl()).isEqualTo(\"jdbc:h2:test\");\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromOracleDataSourceWithPasswordNotSetThrowsException() throws Exception {\n\t\toracle.jdbc.datasource.impl.OracleDataSource dataSource = new oracle.jdbc.datasource.impl.OracleDataSource();\n\t\tdataSource.setUser(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setURL(\"example.com\");\n\t\tassertThatExceptionOfType(UnsupportedDataSourcePropertyException.class)\n\t\t\t.isThrownBy(() -> DataSourceBuilder.derivedFrom(dataSource).url(\"example.org\").build());\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromOracleUcpWithPasswordNotSetThrowsException() throws Exception {\n\t\tPoolDataSource dataSource = new PoolDataSourceImpl();\n\t\tdataSource.setUser(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setURL(\"example.com\");\n\t\tassertThatExceptionOfType(UnsupportedDataSourcePropertyException.class)\n\t\t\t.isThrownBy(() -> DataSourceBuilder.derivedFrom(dataSource).url(\"example.org\").build());\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromSimpleDriverDataSourceAndDriverNotSetBuilds() {\n\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setUrl(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> DataSourceBuilder.derivedFrom(dataSource).type(SimpleDriverDataSource.class).build());\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromOracleDataSourceWithPasswordSetReturnsDataSource() throws Exception {\n\t\toracle.jdbc.datasource.impl.OracleDataSource dataSource = new oracle.jdbc.datasource.impl.OracleDataSource();\n\t\tdataSource.setUser(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setURL(\"example.com\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource);\n\t\toracle.jdbc.datasource.impl.OracleDataSource built = (oracle.jdbc.datasource.impl.OracleDataSource) builder\n\t\t\t.username(\"test2\")\n\t\t\t.password(\"secret2\")\n\t\t\t.build();\n\t\tassertThat(built.getUser()).isEqualTo(\"test2\");\n\t\tassertThat(built).extracting(\"password\")\n\t\t\t.extracting((opaque) -> ((OpaqueString) opaque).get())\n\t\t\t.isEqualTo(\"secret2\");\n\t\tassertThat(built.getURL()).isEqualTo(\"example.com\");\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromOracleUcpWithPasswordSetReturnsDataSource() throws SQLException {\n\t\tPoolDataSource dataSource = new PoolDataSourceImpl();\n\t\tdataSource.setUser(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setURL(\"example.com\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource);\n\t\tPoolDataSource built = (PoolDataSource) builder.username(\"test2\").password(\"secret2\").build();\n\t\tassertThat(built.getUser()).isEqualTo(\"test2\");\n\t\tassertThat(built).extracting(\"password\")\n\t\t\t.extracting((opaque) -> ((oracle.ucp.util.OpaqueString) opaque).get())\n\t\t\t.isEqualTo(\"secret2\");\n\t\tassertThat(built.getURL()).isEqualTo(\"example.com\");\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromEmbeddedDatabase() {\n\t\tEmbeddedDatabase database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build();\n\t\tSimpleDriverDataSource built = (SimpleDriverDataSource) DataSourceBuilder.derivedFrom(database)\n\t\t\t.username(\"test\")\n\t\t\t.password(\"secret\")\n\t\t\t.build();\n\t\tassertThat(built.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(built.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(built.getUrl()).startsWith(\"jdbc:hsqldb:mem\");\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromWrappedDataSource() {\n\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setJdbcUrl(\"jdbc:h2:test\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(wrap(wrap(dataSource)));\n\t\tHikariDataSource built = (HikariDataSource) builder.username(\"test2\").password(\"secret2\").build();\n\t\tassertThat(built.getUsername()).isEqualTo(\"test2\");\n\t\tassertThat(built.getPassword()).isEqualTo(\"secret2\");\n\t\tassertThat(built.getJdbcUrl()).isEqualTo(\"jdbc:h2:test\");\n\t}\n\n\t@Test // gh-26644\n\tvoid buildWhenDerivedFromExistingDatabaseWithTypeChange() {\n\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setJdbcUrl(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource).type(SimpleDriverDataSource.class);\n\t\tSimpleDriverDataSource built = (SimpleDriverDataSource) builder.username(\"test2\").password(\"secret2\").build();\n\t\tassertThat(built.getUsername()).isEqualTo(\"test2\");\n\t\tassertThat(built.getPassword()).isEqualTo(\"secret2\");\n\t\tassertThat(built.getUrl()).isEqualTo(\"jdbc:postgresql://localhost:5432/postgres\");\n\t}\n\n\t@Test // gh-27295\n\tvoid buildWhenDerivedFromCustomType() {\n\t\tCustomDataSource dataSource = new CustomDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setUrl(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource)\n\t\t\t.username(\"alice\")\n\t\t\t.password(\"confidential\");\n\t\tCustomDataSource testSource = (CustomDataSource) builder.build();\n\t\tassertThat(testSource).isNotSameAs(dataSource);\n\t\tassertThat(testSource.getUsername()).isEqualTo(\"alice\");\n\t\tassertThat(testSource.getUrl()).isEqualTo(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tassertThat(testSource.getPassword()).isEqualTo(\"confidential\");\n\t}\n\n\t@Test // gh-27295\n\tvoid buildWhenDerivedFromCustomTypeWithTypeChange() {\n\t\tCustomDataSource dataSource = new CustomDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setUrl(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource).type(SimpleDriverDataSource.class);\n\t\tSimpleDriverDataSource testSource = (SimpleDriverDataSource) builder.build();\n\t\tassertThat(testSource.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(testSource.getUrl()).isEqualTo(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tassertThat(testSource.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromCustomTypeDeriveDriverClassNameFromUrl() {\n\t\tNoDriverClassNameDataSource dataSource = new NoDriverClassNameDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setUrl(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource).type(SimpleDriverDataSource.class);\n\t\tSimpleDriverDataSource testSource = (SimpleDriverDataSource) builder.build();\n\t\tassertThat(testSource.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(testSource.getUrl()).isEqualTo(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tassertThat(testSource.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(testSource.getDriver()).isInstanceOf(org.postgresql.Driver.class);\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromCustomTypeDeriveDriverClassNameFromOverridenUrl() {\n\t\tNoDriverClassNameDataSource dataSource = new NoDriverClassNameDataSource();\n\t\tdataSource.setUsername(\"test\");\n\t\tdataSource.setPassword(\"secret\");\n\t\tdataSource.setUrl(\"jdbc:mysql://localhost:5432/mysql\");\n\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource)\n\t\t\t.type(SimpleDriverDataSource.class)\n\t\t\t.url(\"jdbc:mariadb://localhost:5432/mariadb\");\n\t\tSimpleDriverDataSource testSource = (SimpleDriverDataSource) builder.build();\n\t\tassertThat(testSource.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(testSource.getUrl()).isEqualTo(\"jdbc:mariadb://localhost:5432/mariadb\");\n\t\tassertThat(testSource.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(testSource.getDriver()).isInstanceOf(org.mariadb.jdbc.Driver.class);\n\t}\n\n\t@Test // gh-31920\n\tvoid buildWhenC3P0TypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:postgresql://localhost:5432/postgres\")\n\t\t\t.type(ComboPooledDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.password(\"secret\")\n\t\t\t.driverClassName(\"com.example.Driver\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(ComboPooledDataSource.class);\n\t\tComboPooledDataSource c3p0DataSource = (ComboPooledDataSource) this.dataSource;\n\t\tassertThat(c3p0DataSource.getJdbcUrl()).isEqualTo(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tassertThat(c3p0DataSource.getUser()).isEqualTo(\"test\");\n\t\tassertThat(c3p0DataSource.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(c3p0DataSource.getDriverClass()).isEqualTo(\"com.example.Driver\");\n\t}\n\n\t@Test // gh-42903\n\tvoid buildWhenViburTypeSpecifiedReturnsExpectedDataSource() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:postgresql://localhost:5432/postgres\")\n\t\t\t.type(ViburDBCPDataSource.class)\n\t\t\t.username(\"test\")\n\t\t\t.password(\"secret\")\n\t\t\t.driverClassName(\"com.example.Driver\")\n\t\t\t.build();\n\t\tassertThat(this.dataSource).isInstanceOf(ViburDBCPDataSource.class);\n\t\tViburDBCPDataSource viburDataSource = (ViburDBCPDataSource) this.dataSource;\n\t\tassertThat(viburDataSource.getJdbcUrl()).isEqualTo(\"jdbc:postgresql://localhost:5432/postgres\");\n\t\tassertThat(viburDataSource.getUsername()).isEqualTo(\"test\");\n\t\tassertThat(viburDataSource.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(viburDataSource.getDriverClassName()).isEqualTo(\"com.example.Driver\");\n\t}\n\n\t@Test\n\tvoid buildWhenJdbcUrlIsFromUnknownDriverLeavesDriverClassNameUnset() {\n\t\tthis.dataSource = DataSourceBuilder.create()\n\t\t\t.url(\"jdbc:example://localhost:1234/example\")\n\t\t\t.type(HikariDataSource.class)\n\t\t\t.build();\n\t\tassertThat(((HikariDataSource) this.dataSource).getDriverClassName()).isNull();\n\t}\n\n\tprivate DataSource wrap(DataSource target) {\n\t\treturn new DataSourceWrapper(target);\n\t}\n\n\tprivate static final class DataSourceWrapper implements DataSource {\n\n\t\tprivate final DataSource delegate;\n\n\t\tprivate DataSourceWrapper(DataSource delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic Logger getParentLogger() throws SQLFeatureNotSupportedException {\n\t\t\treturn this.delegate.getParentLogger();\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> T unwrap(Class<T> iface) throws SQLException {\n\t\t\treturn this.delegate.unwrap(iface);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isWrapperFor(Class<?> iface) throws SQLException {\n\t\t\treturn this.delegate.isWrapperFor(iface);\n\t\t}\n\n\t\t@Override\n\t\tpublic Connection getConnection() throws SQLException {\n\t\t\treturn this.delegate.getConnection();\n\t\t}\n\n\t\t@Override\n\t\tpublic Connection getConnection(String username, String password) throws SQLException {\n\t\t\treturn this.delegate.getConnection(username, password);\n\t\t}\n\n\t\t@Override\n\t\tpublic PrintWriter getLogWriter() throws SQLException {\n\t\t\treturn this.delegate.getLogWriter();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogWriter(PrintWriter out) throws SQLException {\n\t\t\tthis.delegate.setLogWriter(out);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLoginTimeout(int seconds) throws SQLException {\n\t\t\tthis.delegate.setLoginTimeout(seconds);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getLoginTimeout() throws SQLException {\n\t\t\treturn this.delegate.getLoginTimeout();\n\t\t}\n\n\t}\n\n\tfinal class HidePackagesClassLoader extends URLClassLoader {\n\n\t\tprivate final String[] hiddenPackages;\n\n\t\tHidePackagesClassLoader(String... hiddenPackages) {\n\t\t\tsuper(new URL[0], HidePackagesClassLoader.class.getClassLoader());\n\t\t\tthis.hiddenPackages = hiddenPackages;\n\t\t}\n\n\t\t@Override\n\t\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\t\tif (Arrays.stream(this.hiddenPackages).anyMatch(name::startsWith)) {\n\t\t\t\tthrow new ClassNotFoundException();\n\t\t\t}\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\n\t}\n\n\tstatic class CustomTomcatDataSource extends org.apache.tomcat.jdbc.pool.DataSource {\n\n\t\tprivate @Nullable String jdbcUrl;\n\n\t\tprivate @Nullable String user;\n\n\t\tprivate @Nullable String driverClass;\n\n\t\t@Nullable String getJdbcUrl() {\n\t\t\treturn this.jdbcUrl;\n\t\t}\n\n\t\tvoid setJdbcUrl(@Nullable String jdbcUrl) {\n\t\t\tthis.jdbcUrl = jdbcUrl;\n\t\t}\n\n\t\t@Nullable String getUser() {\n\t\t\treturn this.user;\n\t\t}\n\n\t\tvoid setUser(@Nullable String user) {\n\t\t\tthis.user = user;\n\t\t}\n\n\t\t@Nullable String getDriverClass() {\n\t\t\treturn this.driverClass;\n\t\t}\n\n\t\tvoid setDriverClass(@Nullable String driverClass) {\n\t\t\tthis.driverClass = driverClass;\n\t\t}\n\n\t}\n\n\tstatic class LimitedCustomDataSource extends AbstractDataSource {\n\n\t\tprivate @Nullable String username;\n\n\t\tprivate @Nullable String password;\n\n\t\t@Override\n\t\tpublic Connection getConnection() throws SQLException {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic Connection getConnection(String username, String password) throws SQLException {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tvoid setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\t@Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tvoid setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t}\n\n\tstatic class NoDriverClassNameDataSource extends LimitedCustomDataSource {\n\n\t\tprivate @Nullable String url;\n\n\t\t@Nullable String getUrl() {\n\t\t\treturn this.url;\n\t\t}\n\n\t\tvoid setUrl(@Nullable String url) {\n\t\t\tthis.url = url;\n\t\t}\n\n\t}\n\n\tstatic class CustomDataSource extends LimitedCustomDataSource {\n\n\t\tprivate @Nullable String driverClassName;\n\n\t\tprivate @Nullable String url;\n\n\t\t@Nullable String getDriverClassName() {\n\t\t\treturn this.driverClassName;\n\t\t}\n\n\t\tvoid setDriverClassName(@Nullable String driverClassName) {\n\t\t\tthis.driverClassName = driverClassName;\n\t\t}\n\n\t\t@Nullable String getUrl() {\n\t\t\treturn this.url;\n\t\t}\n\n\t\tvoid setUrl(@Nullable String url) {\n\t\t\tthis.url = url;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DataSourceUnwrapperNoSpringJdbcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariConfigMXBean;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.tomcat.jdbc.pool.DataSourceProxy;\nimport org.apache.tomcat.jdbc.pool.PoolConfiguration;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link DataSourceUnwrapper} when spring-jdbc is not available.\n *\n * @author Stephane Nicoll\n */\n@ClassPathExclusions(\"spring-jdbc-*.jar\")\nclass DataSourceUnwrapperNoSpringJdbcTests {\n\n\t@Test\n\tvoid unwrapWithProxy() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tDataSource actual = wrapInProxy(wrapInProxy(dataSource));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrapDataSourceProxy() {\n\t\torg.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();\n\t\tDataSource actual = wrapInProxy(wrapInProxy(dataSource));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, PoolConfiguration.class, DataSourceProxy.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\tprivate DataSource wrapInProxy(DataSource dataSource) {\n\t\treturn (DataSource) new ProxyFactory(dataSource).getProxy();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DataSourceUnwrapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.sql.SQLException;\nimport java.util.function.Consumer;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariConfigMXBean;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.tomcat.jdbc.pool.DataSourceProxy;\nimport org.apache.tomcat.jdbc.pool.PoolConfiguration;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.jdbc.datasource.DelegatingDataSource;\nimport org.springframework.jdbc.datasource.SingleConnectionDataSource;\nimport org.springframework.jdbc.datasource.SmartDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataSourceUnwrapper}.\n *\n * @author Stephane Nicoll\n */\nclass DataSourceUnwrapperTests {\n\n\t@Test\n\tvoid unwrapWithTarget() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tassertThat(DataSourceUnwrapper.unwrap(dataSource, HikariConfigMXBean.class, HikariDataSource.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrapWithWrongTarget() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tassertThat(DataSourceUnwrapper.unwrap(dataSource, SmartDataSource.class, SingleConnectionDataSource.class))\n\t\t\t.isNull();\n\t}\n\n\t@Test\n\tvoid unwrapWithDelegate() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tDataSource actual = wrapInDelegate(wrapInDelegate(dataSource));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrapWithProxy() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tDataSource actual = wrapInProxy(wrapInProxy(dataSource));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrapWithProxyAndDelegate() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tDataSource actual = wrapInProxy(wrapInDelegate(dataSource));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrapWithSeveralLevelOfWrapping() {\n\t\tDataSource dataSource = new HikariDataSource();\n\t\tDataSource actual = wrapInProxy(wrapInDelegate(wrapInDelegate(wrapInProxy(wrapInDelegate(dataSource)))));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, HikariConfigMXBean.class, HikariDataSource.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrapDataSourceProxy() {\n\t\torg.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();\n\t\tDataSource actual = wrapInDelegate(wrapInProxy(dataSource));\n\t\tassertThat(DataSourceUnwrapper.unwrap(actual, PoolConfiguration.class, DataSourceProxy.class))\n\t\t\t.isSameAs(dataSource);\n\t}\n\n\t@Test\n\tvoid unwrappingIsNotAttemptedWhenTargetIsNotAnInterface() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tassertThat(DataSourceUnwrapper.unwrap(dataSource, HikariDataSource.class)).isNull();\n\t\tthen(dataSource).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid unwrappingIsNotAttemptedWhenDataSourceIsNotWrapperForTarget() throws SQLException {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tassertThat(DataSourceUnwrapper.unwrap(dataSource, Consumer.class)).isNull();\n\t\tthen(dataSource).should().isWrapperFor(Consumer.class);\n\t\tthen(dataSource).shouldHaveNoMoreInteractions();\n\t}\n\n\tprivate DataSource wrapInProxy(DataSource dataSource) {\n\t\treturn (DataSource) new ProxyFactory(dataSource).getProxy();\n\t}\n\n\tprivate DataSource wrapInDelegate(DataSource dataSource) {\n\t\treturn new DelegatingDataSource(dataSource);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DatabaseDriverClassNameTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.io.IOException;\nimport java.sql.Driver;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\nimport javax.sql.XADataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.asm.ClassReader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the class names in the {@link DatabaseDriver} enumeration.\n *\n * @author Andy Wilkinson\n */\nclass DatabaseDriverClassNameTests {\n\n\tprivate static final Set<DatabaseDriver> EXCLUDED_DRIVERS = Collections\n\t\t.unmodifiableSet(EnumSet.of(DatabaseDriver.UNKNOWN, DatabaseDriver.DB2_AS400, DatabaseDriver.INFORMIX,\n\t\t\t\tDatabaseDriver.HANA, DatabaseDriver.PHOENIX, DatabaseDriver.TERADATA, DatabaseDriver.REDSHIFT));\n\n\t@ParameterizedTest(name = \"{0} {2}\")\n\t@MethodSource\n\tvoid databaseClassIsOfRequiredType(DatabaseDriver driver, String className, Class<?> requiredType)\n\t\t\tthrows Exception {\n\t\tassertThat(getInterfaceNames(className.replace('.', '/'))).contains(requiredType.getName().replace('.', '/'));\n\t}\n\n\tprivate List<String> getInterfaceNames(String className) throws IOException {\n\t\t// Use ASM to avoid unwanted side effects of loading JDBC drivers\n\t\tClassReader classReader = new ClassReader(getClass().getResourceAsStream(\"/\" + className + \".class\"));\n\t\tList<String> interfaceNames = new ArrayList<>();\n\t\tfor (String name : classReader.getInterfaces()) {\n\t\t\tinterfaceNames.add(name);\n\t\t\tinterfaceNames.addAll(getInterfaceNames(name));\n\t\t}\n\t\tString superName = classReader.getSuperName();\n\t\tif (superName != null) {\n\t\t\tinterfaceNames.addAll(getInterfaceNames(superName));\n\t\t}\n\t\treturn interfaceNames;\n\t}\n\n\tstatic Stream<? extends Arguments> databaseClassIsOfRequiredType() {\n\t\tFunction<DatabaseDriver, @Nullable String> getDriverClassName = DatabaseDriver::getDriverClassName;\n\t\treturn Stream.concat(argumentsForType(Driver.class, getDriverClassName),\n\t\t\t\targumentsForType(XADataSource.class,\n\t\t\t\t\t\t(databaseDriver) -> databaseDriver.getXaDataSourceClassName() != null,\n\t\t\t\t\t\tDatabaseDriver::getXaDataSourceClassName));\n\t}\n\n\tprivate static Stream<? extends Arguments> argumentsForType(Class<?> type,\n\t\t\tFunction<DatabaseDriver, @Nullable String> classNameExtractor) {\n\t\treturn argumentsForType(type, (databaseDriver) -> true, classNameExtractor);\n\t}\n\n\tprivate static Stream<? extends Arguments> argumentsForType(Class<?> type, Predicate<DatabaseDriver> predicate,\n\t\t\tFunction<DatabaseDriver, @Nullable String> classNameExtractor) {\n\t\treturn Stream.of(DatabaseDriver.values())\n\t\t\t.filter((databaseDriver) -> !EXCLUDED_DRIVERS.contains(databaseDriver))\n\t\t\t.filter(predicate)\n\t\t\t.map((databaseDriver) -> Arguments.of(databaseDriver, classNameExtractor.apply(databaseDriver), type));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/DatabaseDriverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DatabaseDriver}.\n *\n * @author Phillip Webb\n * @author Maciej Walkowiak\n * @author Stephane Nicoll\n */\nclass DatabaseDriverTests {\n\n\t@Test\n\tvoid classNameForKnownDatabase() {\n\t\tString driverClassName = DatabaseDriver.fromJdbcUrl(\"jdbc:postgresql://hostname/dbname\").getDriverClassName();\n\t\tassertThat(driverClassName).isEqualTo(\"org.postgresql.Driver\");\n\t}\n\n\t@Test\n\tvoid nullClassNameForUnknownDatabase() {\n\t\tString driverClassName = DatabaseDriver.fromJdbcUrl(\"jdbc:unknowndb://hostname/dbname\").getDriverClassName();\n\t\tassertThat(driverClassName).isNull();\n\t}\n\n\t@Test\n\tvoid unknownOnNullJdbcUrl() {\n\t\tDatabaseDriver actual = DatabaseDriver.fromJdbcUrl(null);\n\t\tassertThat(actual).isEqualTo(DatabaseDriver.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid failureOnMalformedJdbcUrl() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> DatabaseDriver.fromJdbcUrl(\"malformed:url\"))\n\t\t\t.withMessageContaining(\"'url' must start with\");\n\t}\n\n\t@Test\n\tvoid unknownOnNullProductName() {\n\t\tDatabaseDriver actual = DatabaseDriver.fromProductName(null);\n\t\tassertThat(actual).isEqualTo(DatabaseDriver.UNKNOWN);\n\t}\n\n\t@Test\n\tvoid databaseProductNameLookups() {\n\t\tassertThat(DatabaseDriver.fromProductName(\"newone\")).isEqualTo(DatabaseDriver.UNKNOWN);\n\t\tassertThat(DatabaseDriver.fromProductName(\"H2\")).isEqualTo(DatabaseDriver.H2);\n\t\tassertThat(DatabaseDriver.fromProductName(\"HDB\")).isEqualTo(DatabaseDriver.HANA);\n\t\tassertThat(DatabaseDriver.fromProductName(\"HSQL Database Engine\")).isEqualTo(DatabaseDriver.HSQLDB);\n\t\tassertThat(DatabaseDriver.fromProductName(\"SQLite\")).isEqualTo(DatabaseDriver.SQLITE);\n\t\tassertThat(DatabaseDriver.fromProductName(\"MySQL\")).isEqualTo(DatabaseDriver.MYSQL);\n\t\tassertThat(DatabaseDriver.fromProductName(\"MariaDB\")).isEqualTo(DatabaseDriver.MARIADB);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Oracle\")).isEqualTo(DatabaseDriver.ORACLE);\n\t\tassertThat(DatabaseDriver.fromProductName(\"PostgreSQL\")).isEqualTo(DatabaseDriver.POSTGRESQL);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Redshift\")).isEqualTo(DatabaseDriver.REDSHIFT);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Microsoft SQL Server\")).isEqualTo(DatabaseDriver.SQLSERVER);\n\t\tassertThat(DatabaseDriver.fromProductName(\"SQL SERVER\")).isEqualTo(DatabaseDriver.SQLSERVER);\n\t\tassertThat(DatabaseDriver.fromProductName(\"DB2\")).isEqualTo(DatabaseDriver.DB2);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Firebird 2.5.WI\")).isEqualTo(DatabaseDriver.FIREBIRD);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Firebird 2.1.LI\")).isEqualTo(DatabaseDriver.FIREBIRD);\n\t\tassertThat(DatabaseDriver.fromProductName(\"DB2/LINUXX8664\")).isEqualTo(DatabaseDriver.DB2);\n\t\tassertThat(DatabaseDriver.fromProductName(\"DB2 UDB for AS/400\")).isEqualTo(DatabaseDriver.DB2_AS400);\n\t\tassertThat(DatabaseDriver.fromProductName(\"DB3 XDB for AS/400\")).isEqualTo(DatabaseDriver.DB2_AS400);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Teradata\")).isEqualTo(DatabaseDriver.TERADATA);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Informix Dynamic Server\")).isEqualTo(DatabaseDriver.INFORMIX);\n\t\tassertThat(DatabaseDriver.fromProductName(\"Apache Phoenix\")).isEqualTo(DatabaseDriver.PHOENIX);\n\t\tassertThat(DatabaseDriver.fromProductName(\"ClickHouse\")).isEqualTo(DatabaseDriver.CLICKHOUSE);\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid deprecatedDatabaseProductNameLookups() {\n\t\tassertThat(DatabaseDriver.fromProductName(\"Apache Derby\")).isEqualTo(DatabaseDriver.DERBY);\n\t}\n\n\t@Test\n\tvoid databaseJdbcUrlLookups() {\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:newone://localhost\")).isEqualTo(DatabaseDriver.UNKNOWN);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:h2:~/sample\")).isEqualTo(DatabaseDriver.H2);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:hsqldb:hsql://localhost\")).isEqualTo(DatabaseDriver.HSQLDB);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:sqlite:sample.db\")).isEqualTo(DatabaseDriver.SQLITE);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:mysql://localhost:3306/sample\")).isEqualTo(DatabaseDriver.MYSQL);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:oracle:thin:@localhost:1521:orcl\"))\n\t\t\t.isEqualTo(DatabaseDriver.ORACLE);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:postgresql://127.0.0.1:5432/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.POSTGRESQL);\n\t\tassertThat(DatabaseDriver\n\t\t\t.fromJdbcUrl(\"jdbc:redshift://examplecluster.abc123xyz789.us-west-2.redshift.amazonaws.com:5439/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.REDSHIFT);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:jtds:sqlserver://127.0.0.1:1433/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.JTDS);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:sap:localhost\")).isEqualTo(DatabaseDriver.HANA);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:sqlserver://127.0.0.1:1433\")).isEqualTo(DatabaseDriver.SQLSERVER);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:firebirdsql://localhost/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.FIREBIRD);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:firebird://localhost/sample\")).isEqualTo(DatabaseDriver.FIREBIRD);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:db2://localhost:50000/sample \")).isEqualTo(DatabaseDriver.DB2);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:as400://localhost\")).isEqualTo(DatabaseDriver.DB2_AS400);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:teradata://localhost/SAMPLE\")).isEqualTo(DatabaseDriver.TERADATA);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:informix-sqli://localhost:1533/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.INFORMIX);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:informix-direct://sample\")).isEqualTo(DatabaseDriver.INFORMIX);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:phoenix:localhost\")).isEqualTo(DatabaseDriver.PHOENIX);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:tc:mysql://localhost:3306/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.TESTCONTAINERS);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:clickhouse://localhost:3306/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.CLICKHOUSE);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:ch://localhost:3306/sample\")).isEqualTo(DatabaseDriver.CLICKHOUSE);\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:aws-wrapper:postgresql://127.0.0.1:5432/sample\"))\n\t\t\t.isEqualTo(DatabaseDriver.AWS_WRAPPER);\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid deprecatedDatabaseJdbcUrlLookups() {\n\t\tassertThat(DatabaseDriver.fromJdbcUrl(\"jdbc:derby:sample\")).isEqualTo(DatabaseDriver.DERBY);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/EmbeddedDatabaseConnectionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EmbeddedDatabaseConnection}.\n *\n * @author Stephane Nicoll\n * @author Nidhi Desai\n */\nclass EmbeddedDatabaseConnectionTests {\n\n\t@Test\n\tvoid h2CustomDatabaseName() {\n\t\tassertThat(EmbeddedDatabaseConnection.H2.getUrl(\"mydb\"))\n\t\t\t.isEqualTo(\"jdbc:h2:mem:mydb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\");\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid derbyCustomDatabaseName() {\n\t\tassertThat(EmbeddedDatabaseConnection.DERBY.getUrl(\"myderbydb\"))\n\t\t\t.isEqualTo(\"jdbc:derby:memory:myderbydb;create=true\");\n\t}\n\n\t@Test\n\tvoid hsqldbCustomDatabaseName() {\n\t\tassertThat(EmbeddedDatabaseConnection.HSQLDB.getUrl(\"myhsqldb\")).isEqualTo(\"jdbc:hsqldb:mem:myhsqldb\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getUrlWithNullDatabaseNameForHsqldb() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EmbeddedDatabaseConnection.HSQLDB.getUrl(null))\n\t\t\t.withMessageContaining(\"'databaseName' must not be empty\");\n\t}\n\n\t@Test\n\tvoid getUrlWithEmptyDatabaseNameForHsqldb() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EmbeddedDatabaseConnection.HSQLDB.getUrl(\"  \"))\n\t\t\t.withMessageContaining(\"'databaseName' must not be empty\");\n\t}\n\n\t@ParameterizedTest(name = \"{0} - {1}\")\n\t@MethodSource(\"embeddedDriverAndUrlParameters\")\n\tvoid isEmbeddedWithDriverAndUrl(String driverClassName, String url, boolean embedded) {\n\t\tassertThat(EmbeddedDatabaseConnection.isEmbedded(driverClassName, url)).isEqualTo(embedded);\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tstatic Object[] embeddedDriverAndUrlParameters() {\n\t\treturn new Object[] {\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.H2.getDriverClassName(), \"jdbc:h2:~/test\", false },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.H2.getDriverClassName(), \"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1\",\n\t\t\t\t\t\ttrue },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.H2.getDriverClassName(), null, true },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.HSQLDB.getDriverClassName(), \"jdbc:hsqldb:hsql://localhost\",\n\t\t\t\t\t\tfalse },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.HSQLDB.getDriverClassName(), \"jdbc:hsqldb:mem:test\", true },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.HSQLDB.getDriverClassName(), null, true },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.DERBY.getDriverClassName(), \"jdbc:derby:memory:test\", true },\n\t\t\t\tnew Object[] { EmbeddedDatabaseConnection.DERBY.getDriverClassName(), null, true },\n\t\t\t\tnew Object[] { \"com.mysql.cj.jdbc.Driver\", \"jdbc:mysql:mem:test\", false },\n\t\t\t\tnew Object[] { \"com.mysql.cj.jdbc.Driver\", null, false },\n\t\t\t\tnew Object[] { null, \"jdbc:none:mem:test\", false }, new Object[] { null, null, false } };\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithH2DataSource() {\n\t\ttestEmbeddedDatabase(new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build());\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithHsqlDataSource() {\n\t\ttestEmbeddedDatabase(new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build());\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithDerbyDataSource() {\n\t\ttestEmbeddedDatabase(new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.DERBY).build());\n\t}\n\n\tvoid testEmbeddedDatabase(EmbeddedDatabase database) {\n\t\ttry {\n\t\t\tassertThat(EmbeddedDatabaseConnection.isEmbedded(database)).isTrue();\n\t\t}\n\t\tfinally {\n\t\t\tdatabase.shutdown();\n\t\t}\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithUnknownDataSource() throws SQLException {\n\t\tassertThat(EmbeddedDatabaseConnection.isEmbedded(mockDataSource(\"unknown-db\", null))).isFalse();\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithH2File() throws SQLException {\n\t\tassertThat(EmbeddedDatabaseConnection\n\t\t\t.isEmbedded(mockDataSource(EmbeddedDatabaseConnection.H2.getDriverClassName(), \"jdbc:h2:~/test\")))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithMissingDriverClassMetadata() throws SQLException {\n\t\tassertThat(EmbeddedDatabaseConnection.isEmbedded(mockDataSource(null, \"jdbc:h2:meme:test\"))).isFalse();\n\t}\n\n\t@Test\n\tvoid isEmbeddedWithMissingUrlMetadata() throws SQLException {\n\t\tassertThat(EmbeddedDatabaseConnection\n\t\t\t.isEmbedded(mockDataSource(EmbeddedDatabaseConnection.H2.getDriverClassName(), null))).isTrue();\n\t}\n\n\tDataSource mockDataSource(@Nullable String productName, @Nullable String connectionUrl) throws SQLException {\n\t\tDatabaseMetaData metaData = mock(DatabaseMetaData.class);\n\t\tgiven(metaData.getDatabaseProductName()).willReturn(productName);\n\t\tgiven(metaData.getURL()).willReturn(connectionUrl);\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.getMetaData()).willReturn(metaData);\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tgiven(dataSource.getConnection()).willReturn(connection);\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/HikariCheckpointRestoreLifecycleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc;\n\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariConfig;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HikariCheckpointRestoreLifecycle}.\n *\n * @author Christoph Strobl\n * @author Andy Wilkinson\n */\nclass HikariCheckpointRestoreLifecycleTests {\n\n\tprivate final HikariCheckpointRestoreLifecycle lifecycle;\n\n\tprivate final HikariDataSource dataSource;\n\n\tHikariCheckpointRestoreLifecycleTests() {\n\t\tHikariConfig config = new HikariConfig();\n\t\tconfig.setAllowPoolSuspension(true);\n\t\tconfig.setJdbcUrl(\"jdbc:hsqldb:mem:test-\" + UUID.randomUUID());\n\t\tconfig.setPoolName(\"lifecycle-tests\");\n\t\tthis.dataSource = new HikariDataSource(config);\n\t\tthis.lifecycle = new HikariCheckpointRestoreLifecycle(this.dataSource,\n\t\t\t\tmock(ConfigurableApplicationContext.class));\n\t}\n\n\t@Test\n\tvoid startedWhenStartedShouldSucceed() {\n\t\tassertThat(this.lifecycle.isRunning()).isTrue();\n\t\tthis.lifecycle.start();\n\t\tassertThat(this.lifecycle.isRunning()).isTrue();\n\t}\n\n\t@Test\n\tvoid stopWhenStoppedShouldSucceed() {\n\t\tassertThat(this.lifecycle.isRunning()).isTrue();\n\t\tthis.lifecycle.stop();\n\t\tassertThat(this.dataSource.isRunning()).isFalse();\n\t\tassertThatNoException().isThrownBy(this.lifecycle::stop);\n\t}\n\n\t@Test\n\tvoid whenStoppedAndStartedDataSourceShouldPauseAndResume() {\n\t\tassertThat(this.lifecycle.isRunning()).isTrue();\n\t\tthis.lifecycle.stop();\n\t\tassertThat(this.dataSource.isRunning()).isFalse();\n\t\tassertThat(this.dataSource.isClosed()).isFalse();\n\t\tassertThat(this.lifecycle.isRunning()).isFalse();\n\t\tassertThat(this.dataSource.getHikariPoolMXBean().getTotalConnections()).isZero();\n\t\tthis.lifecycle.start();\n\t\tassertThat(this.dataSource.isRunning()).isTrue();\n\t\tassertThat(this.dataSource.isClosed()).isFalse();\n\t\tassertThat(this.lifecycle.isRunning()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenDataSourceIsClosedThenStartShouldThrow() {\n\t\tthis.dataSource.close();\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(this.lifecycle::start);\n\t}\n\n\t@Test\n\tvoid startHasNoEffectWhenDataSourceIsNotAHikariDataSource() {\n\t\tHikariCheckpointRestoreLifecycle nonHikariLifecycle = new HikariCheckpointRestoreLifecycle(\n\t\t\t\tmock(DataSource.class), mock(ConfigurableApplicationContext.class));\n\t\tassertThat(nonHikariLifecycle.isRunning()).isFalse();\n\t\tnonHikariLifecycle.start();\n\t\tassertThat(nonHikariLifecycle.isRunning()).isFalse();\n\t}\n\n\t@Test\n\tvoid stopHasNoEffectWhenDataSourceIsNotAHikariDataSource() {\n\t\tHikariCheckpointRestoreLifecycle nonHikariLifecycle = new HikariCheckpointRestoreLifecycle(\n\t\t\t\tmock(DataSource.class), mock(ConfigurableApplicationContext.class));\n\t\tassertThat(nonHikariLifecycle.isRunning()).isFalse();\n\t\tnonHikariLifecycle.stop();\n\t\tassertThat(nonHikariLifecycle.isRunning()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.sql.Connection;\nimport java.sql.Driver;\nimport java.sql.DriverPropertyInfo;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.Random;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.logging.Logger;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport io.r2dbc.spi.ConnectionFactory;\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataSourceAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DataSourceAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.url:jdbc:hsqldb:mem:testdb-\" + new Random().nextInt());\n\n\t@Test\n\tvoid testDefaultDataSourceExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(DataSource.class));\n\t}\n\n\t@Test\n\tvoid testDataSourceHasEmbeddedDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHikariDataSource dataSource = context.getBean(HikariDataSource.class);\n\t\t\tassertThat(dataSource.getJdbcUrl()).isNotNull();\n\t\t\tassertThat(dataSource.getDriverClassName()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testBadUrl() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.url:jdbc:not-going-to-work\")\n\t\t\t.withClassLoader(new DisableEmbeddedDatabaseClassLoader())\n\t\t\t.run((context) -> assertThat(context).getFailure().isInstanceOf(BeanCreationException.class));\n\t}\n\n\t@Test\n\tvoid testBadDriverClass() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.driverClassName:org.none.jdbcDriver\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"org.none.jdbcDriver\"));\n\t}\n\n\t@Test\n\tvoid datasourceWhenConnectionFactoryPresentIsNotAutoConfigured() {\n\t\tthis.contextRunner.withBean(ConnectionFactory.class, () -> mock(ConnectionFactory.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSource.class));\n\t}\n\n\t@Test\n\tvoid hikariValidatesConnectionByDefault() {\n\t\tassertDataSource(HikariDataSource.class, Collections.singletonList(\"org.apache.tomcat\"), (dataSource) ->\n\t\t// Use Connection#isValid()\n\t\tassertThat(dataSource.getConnectionTestQuery()).isNull());\n\t}\n\n\t@Test\n\tvoid tomcatIsFallback() {\n\t\tassertDataSource(org.apache.tomcat.jdbc.pool.DataSource.class, Collections.singletonList(\"com.zaxxer.hikari\"),\n\t\t\t\t(dataSource) -> assertThat(dataSource.getUrl()).startsWith(\"jdbc:hsqldb:mem:testdb\"));\n\t}\n\n\t@Test\n\tvoid tomcatValidatesConnectionByDefault() {\n\t\tassertDataSource(org.apache.tomcat.jdbc.pool.DataSource.class, Collections.singletonList(\"com.zaxxer.hikari\"),\n\t\t\t\t(dataSource) -> {\n\t\t\t\t\tassertThat(dataSource.isTestOnBorrow()).isTrue();\n\t\t\t\t\tassertThat(dataSource.getValidationQuery()).isEqualTo(DatabaseDriver.HSQLDB.getValidationQuery());\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid commonsDbcp2IsFallback() {\n\t\tassertDataSource(BasicDataSource.class, Arrays.asList(\"com.zaxxer.hikari\", \"org.apache.tomcat\"),\n\t\t\t\t(dataSource) -> assertThat(dataSource.getUrl()).startsWith(\"jdbc:hsqldb:mem:testdb\"));\n\t}\n\n\t@Test\n\tvoid commonsDbcp2ValidatesConnectionByDefault() {\n\t\tassertDataSource(org.apache.commons.dbcp2.BasicDataSource.class,\n\t\t\t\tArrays.asList(\"com.zaxxer.hikari\", \"org.apache.tomcat\"), (dataSource) -> {\n\t\t\t\t\tassertThat(dataSource.getTestOnBorrow()).isTrue();\n\t\t\t\t\t// Use Connection#isValid()\n\t\t\t\t\tassertThat(dataSource.getValidationQuery()).isNull();\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid oracleUcpIsFallback() {\n\t\tassertDataSource(PoolDataSourceImpl.class,\n\t\t\t\tArrays.asList(\"com.zaxxer.hikari\", \"org.apache.tomcat\", \"org.apache.commons.dbcp2\"),\n\t\t\t\t(dataSource) -> assertThat(dataSource.getURL()).startsWith(\"jdbc:hsqldb:mem:testdb\"));\n\t}\n\n\t@Test\n\tvoid oracleUcpDoesNotValidateConnectionByDefault() {\n\t\tassertDataSource(PoolDataSourceImpl.class,\n\t\t\t\tArrays.asList(\"com.zaxxer.hikari\", \"org.apache.tomcat\", \"org.apache.commons.dbcp2\"), (dataSource) -> {\n\t\t\t\t\tassertThat(dataSource.getValidateConnectionOnBorrow()).isFalse();\n\t\t\t\t\t// Use an internal ping when using an Oracle JDBC driver\n\t\t\t\t\tassertThat(dataSource.getSQLForValidateConnection()).isNull();\n\t\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid testEmbeddedTypeDefaultsUsername() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.driverClassName:org.hsqldb.jdbcDriver\",\n\t\t\t\t\t\"spring.datasource.url:jdbc:hsqldb:mem:testdb\")\n\t\t\t.run((context) -> {\n\t\t\t\tDataSource bean = context.getBean(DataSource.class);\n\t\t\t\tHikariDataSource pool = (HikariDataSource) bean;\n\t\t\t\tassertThat(pool.getDriverClassName()).isEqualTo(\"org.hsqldb.jdbcDriver\");\n\t\t\t\tassertThat(pool.getUsername()).isEqualTo(\"sa\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid dataSourceWhenNoConnectionPoolsAreAvailableWithUrlDoesNotCreateDataSource() {\n\t\tthis.contextRunner.with(hideConnectionPools())\n\t\t\t.withPropertyValues(\"spring.datasource.url:jdbc:hsqldb:mem:testdb\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSource.class));\n\t}\n\n\t/**\n\t * This test makes sure that if no supported data source is present, a datasource is\n\t * still created if \"spring.datasource.type\" is present.\n\t */\n\t@Test\n\tvoid dataSourceWhenNoConnectionPoolsAreAvailableWithUrlAndTypeCreatesDataSource() {\n\t\tthis.contextRunner.with(hideConnectionPools())\n\t\t\t.withPropertyValues(\"spring.datasource.driverClassName:org.hsqldb.jdbcDriver\",\n\t\t\t\t\t\"spring.datasource.url:jdbc:hsqldb:mem:testdb\",\n\t\t\t\t\t\"spring.datasource.type:\" + SimpleDriverDataSource.class.getName())\n\t\t\t.run(this::containsOnlySimpleDriverDataSource);\n\t}\n\n\t@Test\n\tvoid explicitTypeSupportedDataSource() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.driverClassName:org.hsqldb.jdbcDriver\",\n\t\t\t\t\t\"spring.datasource.url:jdbc:hsqldb:mem:testdb\",\n\t\t\t\t\t\"spring.datasource.type:\" + SimpleDriverDataSource.class.getName())\n\t\t\t.run(this::containsOnlySimpleDriverDataSource);\n\t}\n\n\tprivate void containsOnlySimpleDriverDataSource(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\tassertThat(context).getBean(DataSource.class).isExactlyInstanceOf(SimpleDriverDataSource.class);\n\t}\n\n\t@Test\n\tvoid testExplicitDriverClassClearsUsername() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.driverClassName:\" + DatabaseTestDriver.class.getName(),\n\t\t\t\t\t\"spring.datasource.url:jdbc:foo://localhost\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\t\tHikariDataSource dataSource = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(dataSource.getDriverClassName()).isEqualTo(DatabaseTestDriver.class.getName());\n\t\t\t\tassertThat(dataSource.getUsername()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultDataSourceCanBeOverridden() {\n\t\tthis.contextRunner.withUserConfiguration(TestDataSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getBean(DataSource.class).isInstanceOf(BasicDataSource.class));\n\t}\n\n\t@Test\n\tvoid whenThereIsAUserProvidedDataSourceAnUnresolvablePlaceholderDoesNotCauseAProblem() {\n\t\tthis.contextRunner.withUserConfiguration(TestDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.url:${UNRESOLVABLE_PLACEHOLDER}\")\n\t\t\t.run((context) -> assertThat(context).getBean(DataSource.class).isInstanceOf(BasicDataSource.class));\n\t}\n\n\t@Test\n\tvoid whenThereIsAnEmptyUserProvidedDataSource() {\n\t\tthis.contextRunner.with(hideConnectionPools())\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.withPropertyValues(\"spring.datasource.url:\")\n\t\t\t.run((context) -> assertThat(context).getBean(DataSource.class).isInstanceOf(EmbeddedDatabase.class));\n\t}\n\n\t@Test\n\tvoid whenNoInitializationRelatedSpringDataSourcePropertiesAreConfiguredThenInitializationBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSourceScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesJdbcConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid dbcp2UsesCustomConnectionDetailsWhenDefined() {\n\t\tApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t\t.withPropertyValues(\"spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource\",\n\t\t\t\t\t\"spring.datasource.dbcp2.url=jdbc:broken\", \"spring.datasource.dbcp2.username=alice\",\n\t\t\t\t\t\"spring.datasource.dbcp2.password=secret\")\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withBean(JdbcConnectionDetails.class, TestJdbcConnectionDetails::new);\n\t\trunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesJdbcConnectionDetails.class);\n\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\tassertThat(dataSource).asInstanceOf(InstanceOfAssertFactories.type(BasicDataSource.class))\n\t\t\t\t.satisfies((dbcp2) -> {\n\t\t\t\t\tassertThat(dbcp2.getUserName()).isEqualTo(\"user-1\");\n\t\t\t\t\tassertThat(dbcp2).extracting(\"password\").isEqualTo(\"password-1\");\n\t\t\t\t\tassertThat(dbcp2.getDriverClassName()).isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t\t\t\t\tassertThat(dbcp2.getUrl()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid genericUsesCustomJdbcConnectionDetailsWhenAvailable() {\n\t\tApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t\t.withPropertyValues(\"spring.datasource.type=\" + TestDataSource.class.getName())\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withBean(JdbcConnectionDetails.class, TestJdbcConnectionDetails::new);\n\t\trunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesJdbcConnectionDetails.class);\n\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\tassertThat(dataSource).isInstanceOf(TestDataSource.class);\n\t\t\tTestDataSource source = (TestDataSource) dataSource;\n\t\t\tassertThat(source.getUsername()).isEqualTo(\"user-1\");\n\t\t\tassertThat(source.getPassword()).isEqualTo(\"password-1\");\n\t\t\tDriver driver = source.getDriver();\n\t\t\tassertThat(driver).isNotNull();\n\t\t\tassertThat(driver.getClass().getName()).isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t\t\tassertThat(source.getUrl()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\t});\n\t}\n\n\tprivate static Function<ApplicationContextRunner, ApplicationContextRunner> hideConnectionPools() {\n\t\treturn (runner) -> runner.withClassLoader(new FilteredClassLoader(\"org.apache.tomcat\", \"com.zaxxer.hikari\",\n\t\t\t\t\"org.apache.commons.dbcp2\", \"oracle.ucp.jdbc\", \"org.vibur.dbcp\", \"com.mchange\"));\n\t}\n\n\tprivate <T extends DataSource> void assertDataSource(Class<T> expectedType, List<String> hiddenPackages,\n\t\t\tConsumer<T> consumer) {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(StringUtils.toStringArray(hiddenPackages));\n\t\tthis.contextRunner.withClassLoader(classLoader).run((context) -> {\n\t\t\tDataSource bean = context.getBean(DataSource.class);\n\t\t\tassertThat(bean).isInstanceOf(expectedType);\n\t\t\tconsumer.accept(expectedType.cast(bean));\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tJdbcConnectionDetails sqlJdbcConnectionDetails() {\n\t\t\treturn new TestJdbcConnectionDetails();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestDataSourceConfiguration {\n\n\t\tprivate @Nullable BasicDataSource pool;\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tthis.pool = new BasicDataSource();\n\t\t\tthis.pool.setDriverClassName(\"org.hsqldb.jdbcDriver\");\n\t\t\tthis.pool.setUrl(\"jdbc:hsqldb:mem:overridedb\");\n\t\t\tthis.pool.setUsername(\"sa\");\n\t\t\treturn this.pool;\n\t\t}\n\n\t}\n\n\t// see testExplicitDriverClassClearsUsername\n\tpublic static class DatabaseTestDriver implements Driver {\n\n\t\t@Override\n\t\tpublic Connection connect(String url, Properties info) {\n\t\t\treturn mock(Connection.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean acceptsURL(String url) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic DriverPropertyInfo[] getPropertyInfo(String url, Properties info) {\n\t\t\treturn new DriverPropertyInfo[0];\n\t\t}\n\n\t\t@Override\n\t\tpublic int getMajorVersion() {\n\t\t\treturn 1;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getMinorVersion() {\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean jdbcCompliant() {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic Logger getParentLogger() {\n\t\t\treturn mock(Logger.class);\n\t\t}\n\n\t}\n\n\tstatic class DisableEmbeddedDatabaseClassLoader extends URLClassLoader {\n\n\t\tDisableEmbeddedDatabaseClassLoader() {\n\t\t\tsuper(new URL[0], DisableEmbeddedDatabaseClassLoader.class.getClassLoader());\n\t\t}\n\n\t\t@Override\n\t\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\t\tfor (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) {\n\t\t\t\tif (name.equals(candidate.getDriverClassName())) {\n\t\t\t\t\tthrow new ClassNotFoundException();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceAutoConfigurationWithoutSpringJdbcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.util.Random;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourceAutoConfiguration} without spring-jdbc on the classpath.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"spring-jdbc-*.jar\")\nclass DataSourceAutoConfigurationWithoutSpringJdbcTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class));\n\n\t@Test\n\tvoid pooledDataSourceCanBeAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHikariDataSource dataSource = context.getBean(HikariDataSource.class);\n\t\t\tassertThat(dataSource.getJdbcUrl()).isNotNull();\n\t\t\tassertThat(dataSource.getDriverClassName()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid withoutConnectionPoolsAutoConfigurationBacksOff() {\n\t\tthis.contextRunner.with(hideConnectionPools())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSource.class));\n\t}\n\n\t@Test\n\tvoid withUrlAndWithoutConnectionPoolsAutoConfigurationBacksOff() {\n\t\tthis.contextRunner.with(hideConnectionPools())\n\t\t\t.withPropertyValues(\"spring.datasource.url:jdbc:hsqldb:mem:testdb-\" + new Random().nextInt())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSource.class));\n\t}\n\n\tprivate static Function<ApplicationContextRunner, ApplicationContextRunner> hideConnectionPools() {\n\t\treturn (runner) -> runner.withClassLoader(new FilteredClassLoader(\"org.apache.tomcat\", \"com.zaxxer.hikari\",\n\t\t\t\t\"org.apache.commons.dbcp2\", \"oracle.ucp.jdbc\", \"com.mchange\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceBeanCreationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport com.mchange.util.AssertException;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourceBeanCreationFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@ClassPathExclusions({ \"derby-*.jar\", \"derbytools-*.jar\", \"h2-*.jar\", \"hsqldb-*.jar\" })\nclass DataSourceBeanCreationFailureAnalyzerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\tvoid failureAnalysisIsPerformed() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);\n\t\tassertThat(failureAnalysis.getDescription()).contains(\"'url' attribute is not specified\",\n\t\t\t\t\"no embedded datasource could be configured\", \"Failed to determine a suitable driver class\");\n\t\tassertThat(failureAnalysis.getAction()).contains(\n\t\t\t\t\"If you want an embedded database (H2, HSQL or Derby), please put it on the classpath\",\n\t\t\t\t\"If you have database settings to be loaded from a particular profile you may need to activate it\",\n\t\t\t\t\"(no profiles are currently active)\");\n\t}\n\n\t@Test\n\tvoid failureAnalysisIsPerformedWithActiveProfiles() {\n\t\tthis.environment.setActiveProfiles(\"first\", \"second\");\n\t\tFailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);\n\t\tassertThat(failureAnalysis.getAction()).contains(\"(the profiles first,second are currently active)\");\n\t}\n\n\tprivate FailureAnalysis performAnalysis(Class<?> configuration) {\n\t\tBeanCreationException failure = createFailure(configuration);\n\t\tassertThat(failure).isNotNull();\n\t\tDataSourceBeanCreationFailureAnalyzer failureAnalyzer = new DataSourceBeanCreationFailureAnalyzer(\n\t\t\t\tthis.environment);\n\t\tFailureAnalysis analysis = failureAnalyzer.analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\treturn analysis;\n\t}\n\n\tprivate BeanCreationException createFailure(Class<?> configuration) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tcontext.setEnvironment(this.environment);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\tthrow new AssertException(\"Shouldn't be reached!\");\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceInitializationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.ApplicationScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.init.DatabasePopulator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataSourceInitializationAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DataSourceInitializationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceInitializationAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name:true\");\n\n\t@Test\n\tvoid whenNoDataSourceIsAvailableThenAutoConfigurationBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid whenDataSourceIsAvailableThenDataSourceInitializerIsAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DataSourceScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid whenDataSourceIsAvailableAndModeIsNeverThenInitializerIsNotAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.sql.init.mode:never\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid whenAnApplicationInitializerIsDefinedThenInitializerIsNotAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ApplicationDatabaseInitializerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ApplicationScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenAnInitializerIsDefinedThenApplicationInitializerIsStillAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DatabaseInitializerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ApplicationDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenBeanIsAnnotatedAsDependingOnDatabaseInitializationThenItDependsOnDataSourceScriptDatabaseInitializer() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DependsOnInitializedDatabaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(\n\t\t\t\t\t\t\"dataSourceInitializationAutoConfigurationTests.DependsOnInitializedDatabaseConfiguration\");\n\t\t\t\tassertThat(beanDefinition.getDependsOn())\n\t\t\t\t\t.containsExactlyInAnyOrder(\"dataSourceScriptDatabaseInitializer\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenADataSourceIsAvailableAndSpringJdbcIsNotThenAutoConfigurationBacksOff() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(DatabasePopulator.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ApplicationDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tApplicationScriptDatabaseInitializer customInitializer() {\n\t\t\treturn mock(ApplicationScriptDatabaseInitializer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer customInitializer() {\n\t\t\treturn new DataSourceScriptDatabaseInitializer(mock(DataSource.class),\n\t\t\t\t\tnew DatabaseInitializationSettings()) {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void runScripts(Scripts scripts) {\n\t\t\t\t\t// No-op\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected boolean isEmbeddedDatabase() {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@DependsOnDatabaseInitialization\n\tstatic class DependsOnInitializedDatabaseConfiguration {\n\n\t\tDependsOnInitializedDatabaseConfiguration() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceJmxConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Set;\nimport java.util.UUID;\n\nimport javax.management.MBeanServer;\nimport javax.management.MalformedObjectNameException;\nimport javax.management.ObjectInstance;\nimport javax.management.ObjectName;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.tomcat.jdbc.pool.DataSource;\nimport org.apache.tomcat.jdbc.pool.DataSourceProxy;\nimport org.apache.tomcat.jdbc.pool.jmx.ConnectionPool;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DelegatingDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourceJmxConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Tadaya Tsuyukubo\n */\nclass DataSourceJmxConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.url=jdbc:hsqldb:mem:test-\" + UUID.randomUUID())\n\t\t.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, DataSourceAutoConfiguration.class));\n\n\t@Test\n\tvoid hikariAutoConfiguredCanUseRegisterMBeans() {\n\t\tString poolName = UUID.randomUUID().toString();\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.datasource.type=\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.name=\" + poolName, \"spring.datasource.hikari.register-mbeans=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HikariDataSource.class);\n\t\t\t\tHikariDataSource hikariDataSource = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(hikariDataSource.isRegisterMbeans()).isTrue();\n\t\t\t\t// Ensure that the pool has been initialized, triggering MBean\n\t\t\t\t// registration\n\t\t\t\thikariDataSource.getConnection().close();\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tvalidateHikariMBeansRegistration(mBeanServer, poolName, true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariAutoConfiguredWithoutDataSourceName() throws MalformedObjectNameException {\n\t\tMBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();\n\t\tSet<ObjectInstance> existingInstances = mBeanServer.queryMBeans(new ObjectName(\"com.zaxxer.hikari:type=*\"),\n\t\t\t\tnull);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.type=\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.hikari.register-mbeans=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HikariDataSource.class);\n\t\t\t\tHikariDataSource hikariDataSource = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(hikariDataSource.isRegisterMbeans()).isTrue();\n\t\t\t\t// Ensure that the pool has been initialized, triggering MBean\n\t\t\t\t// registration\n\t\t\t\thikariDataSource.getConnection().close();\n\t\t\t\t// We can't rely on the number of MBeans so we're checking that the\n\t\t\t\t// pool and pool config MBeans were registered\n\t\t\t\tassertThat(mBeanServer.queryMBeans(new ObjectName(\"com.zaxxer.hikari:type=*\"), null))\n\t\t\t\t\t.hasSize(existingInstances.size() + 2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariAutoConfiguredUsesJmxFlag() {\n\t\tString poolName = UUID.randomUUID().toString();\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.type=\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.jmx.enabled=false\", \"spring.datasource.name=\" + poolName,\n\t\t\t\t\t\"spring.datasource.hikari.register-mbeans=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HikariDataSource.class);\n\t\t\t\tHikariDataSource hikariDataSource = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(hikariDataSource.isRegisterMbeans()).isTrue();\n\t\t\t\t// Ensure that the pool has been initialized, triggering MBean\n\t\t\t\t// registration\n\t\t\t\thikariDataSource.getConnection().close();\n\t\t\t\t// Hikari can still register mBeans\n\t\t\t\tvalidateHikariMBeansRegistration(ManagementFactory.getPlatformMBeanServer(), poolName, true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariProxiedCanUseRegisterMBeans() {\n\t\tString poolName = UUID.randomUUID().toString();\n\t\tthis.contextRunner.withUserConfiguration(DataSourceProxyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.datasource.type=\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.name=\" + poolName, \"spring.datasource.hikari.register-mbeans=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(javax.sql.DataSource.class);\n\t\t\t\tHikariDataSource hikariDataSource = context.getBean(javax.sql.DataSource.class)\n\t\t\t\t\t.unwrap(HikariDataSource.class);\n\t\t\t\tassertThat(hikariDataSource.isRegisterMbeans()).isTrue();\n\t\t\t\t// Ensure that the pool has been initialized, triggering MBean\n\t\t\t\t// registration\n\t\t\t\thikariDataSource.getConnection().close();\n\t\t\t\tMBeanServer mBeanServer = context.getBean(MBeanServer.class);\n\t\t\t\tvalidateHikariMBeansRegistration(mBeanServer, poolName, true);\n\t\t\t});\n\t}\n\n\tprivate void validateHikariMBeansRegistration(MBeanServer mBeanServer, String poolName, boolean expected)\n\t\t\tthrows MalformedObjectNameException {\n\t\tassertThat(mBeanServer.isRegistered(new ObjectName(\"com.zaxxer.hikari:type=Pool (\" + poolName + \")\")))\n\t\t\t.isEqualTo(expected);\n\t\tassertThat(mBeanServer.isRegistered(new ObjectName(\"com.zaxxer.hikari:type=PoolConfig (\" + poolName + \")\")))\n\t\t\t.isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid tomcatDoesNotExposeMBeanPoolByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.type=\" + DataSource.class.getName())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConnectionPool.class));\n\t}\n\n\t@Test\n\tvoid tomcatAutoConfiguredCanExposeMBeanPool() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.datasource.type=\" + DataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.tomcat.jmx-enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"dataSourceMBean\");\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionPool.class);\n\t\t\t\tassertThat(context.getBean(DataSourceProxy.class).createPool().getJmxPool())\n\t\t\t\t\t.isSameAs(context.getBean(ConnectionPool.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatProxiedCanExposeMBeanPool() {\n\t\tthis.contextRunner.withUserConfiguration(DataSourceProxyConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.datasource.type=\" + DataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.tomcat.jmx-enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"dataSourceMBean\");\n\t\t\t\tassertThat(context).getBean(\"dataSourceMBean\").isInstanceOf(ConnectionPool.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatDelegateCanExposeMBeanPool() {\n\t\tthis.contextRunner.withUserConfiguration(DataSourceDelegateConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jmx.enabled=true\", \"spring.datasource.type=\" + DataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.tomcat.jmx-enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"dataSourceMBean\");\n\t\t\t\tassertThat(context).getBean(\"dataSourceMBean\").isInstanceOf(ConnectionPool.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceProxyConfiguration {\n\n\t\t@Bean\n\t\tstatic DataSourceBeanPostProcessor dataSourceBeanPostProcessor() {\n\t\t\treturn new DataSourceBeanPostProcessor();\n\t\t}\n\n\t}\n\n\tstatic class DataSourceBeanPostProcessor implements BeanPostProcessor {\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\tif (bean instanceof javax.sql.DataSource) {\n\t\t\t\treturn new ProxyFactory(bean).getProxy();\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceDelegateConfiguration {\n\n\t\t@Bean\n\t\tstatic DataSourceBeanPostProcessor dataSourceBeanPostProcessor() {\n\t\t\treturn new DataSourceBeanPostProcessor() {\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\t\t\treturn (bean instanceof javax.sql.DataSource)\n\t\t\t\t\t\t\t? new DelegatingDataSource((javax.sql.DataSource) bean) : bean;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceJsonSerializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.beans.PropertyDescriptor;\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.tomcat.jdbc.pool.DataSource;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.BeanDescription;\nimport tools.jackson.databind.SerializationConfig;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.ValueSerializer;\nimport tools.jackson.databind.annotation.JsonSerialize;\nimport tools.jackson.databind.introspect.AnnotatedMethod;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.ser.BeanPropertyWriter;\nimport tools.jackson.databind.ser.BeanSerializerFactory;\nimport tools.jackson.databind.ser.SerializerFactory;\nimport tools.jackson.databind.ser.ValueSerializerModifier;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.support.DefaultConversionService;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test that a {@link DataSource} can be exposed as JSON for actuator endpoints.\n *\n * @author Dave Syer\n */\nclass DataSourceJsonSerializationTests {\n\n\t@Test\n\tvoid serializerFactory() throws Exception {\n\t\tDataSource dataSource = new DataSource();\n\t\tSerializerFactory factory = BeanSerializerFactory.instance\n\t\t\t.withSerializerModifier(new GenericSerializerModifier());\n\t\tJsonMapper mapper = JsonMapper.builder().serializerFactory(factory).build();\n\t\tString value = mapper.writeValueAsString(dataSource);\n\t\tassertThat(value).contains(\"\\\"url\\\":\");\n\t}\n\n\t@Test\n\tvoid serializerWithMixin() throws Exception {\n\t\tDataSource dataSource = new DataSource();\n\t\tJsonMapper mapper = JsonMapper.builder().addMixIn(DataSource.class, DataSourceJson.class).build();\n\t\tString value = mapper.writeValueAsString(dataSource);\n\t\tassertThat(value).contains(\"\\\"url\\\":\");\n\t\tassertThat(StringUtils.countOccurrencesOf(value, \"\\\"url\\\"\")).isOne();\n\t}\n\n\t@JsonSerialize(using = TomcatDataSourceSerializer.class)\n\tinterface DataSourceJson {\n\n\t}\n\n\tstatic class TomcatDataSourceSerializer extends ValueSerializer<DataSource> {\n\n\t\tprivate final ConversionService conversionService = new DefaultConversionService();\n\n\t\t@Override\n\t\tpublic void serialize(DataSource value, JsonGenerator jgen, SerializationContext context) {\n\t\t\tjgen.writeStartObject();\n\t\t\tfor (PropertyDescriptor property : BeanUtils.getPropertyDescriptors(DataSource.class)) {\n\t\t\t\tMethod reader = property.getReadMethod();\n\t\t\t\tif (reader != null && property.getWriteMethod() != null\n\t\t\t\t\t\t&& this.conversionService.canConvert(String.class, property.getPropertyType())) {\n\t\t\t\t\tjgen.writePOJOProperty(property.getName(), ReflectionUtils.invokeMethod(reader, value));\n\t\t\t\t}\n\t\t\t}\n\t\t\tjgen.writeEndObject();\n\t\t}\n\n\t}\n\n\tstatic class GenericSerializerModifier extends ValueSerializerModifier {\n\n\t\tprivate final ConversionService conversionService = new DefaultConversionService();\n\n\t\t@Override\n\t\tpublic List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription.Supplier beanDesc,\n\t\t\t\tList<BeanPropertyWriter> beanProperties) {\n\t\t\tList<BeanPropertyWriter> result = new ArrayList<>();\n\t\t\tfor (BeanPropertyWriter writer : beanProperties) {\n\t\t\t\tAnnotatedMethod setter = beanDesc.get()\n\t\t\t\t\t.findMethod(\"set\" + StringUtils.capitalize(writer.getName()),\n\t\t\t\t\t\t\tnew Class<?>[] { writer.getType().getRawClass() });\n\t\t\t\tif (setter != null && this.conversionService.canConvert(String.class, writer.getType().getRawClass())) {\n\t\t\t\t\tresult.add(writer);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourcePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.test.context.FilteredClassLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link DataSourceProperties}.\n *\n * @author Maciej Walkowiak\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Scott Frederick\n */\nclass DataSourcePropertiesTests {\n\n\t@Test\n\tvoid determineDriver() {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUrl(\"jdbc:mysql://mydb\");\n\t\tassertThat(properties.getDriverClassName()).isNull();\n\t\tassertThat(properties.determineDriverClassName()).isEqualTo(\"com.mysql.cj.jdbc.Driver\");\n\t}\n\n\t@Test\n\tvoid determineDriverWithExplicitConfig() {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUrl(\"jdbc:mysql://mydb\");\n\t\tproperties.setDriverClassName(\"org.hsqldb.jdbcDriver\");\n\t\tassertThat(properties.getDriverClassName()).isEqualTo(\"org.hsqldb.jdbcDriver\");\n\t\tassertThat(properties.determineDriverClassName()).isEqualTo(\"org.hsqldb.jdbcDriver\");\n\t}\n\n\t@Test\n\tvoid determineUrlWithoutGenerateUniqueName() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setGenerateUniqueName(false);\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getUrl()).isNull();\n\t\tassertThat(properties.determineUrl()).isEqualTo(EmbeddedDatabaseConnection.H2.getUrl(\"testdb\"));\n\t}\n\n\t@Test\n\tvoid determineUrlWithNoEmbeddedSupport() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setBeanClassLoader(new FilteredClassLoader(\"org.h2\", \"org.apache.derby\", \"org.hsqldb\"));\n\t\tproperties.afterPropertiesSet();\n\t\tassertThatExceptionOfType(DataSourceProperties.DataSourceBeanCreationException.class)\n\t\t\t.isThrownBy(properties::determineUrl)\n\t\t\t.withMessageContaining(\"Failed to determine suitable jdbc url\");\n\t}\n\n\t@Test\n\tvoid determineUrlWithSpecificEmbeddedConnection() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setGenerateUniqueName(false);\n\t\tproperties.setEmbeddedDatabaseConnection(EmbeddedDatabaseConnection.HSQLDB);\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.determineUrl()).isEqualTo(EmbeddedDatabaseConnection.HSQLDB.getUrl(\"testdb\"));\n\t}\n\n\t@Test\n\tvoid whenEmbeddedConnectionIsNoneAndNoUrlIsConfiguredThenDetermineUrlThrows() {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setGenerateUniqueName(false);\n\t\tproperties.setEmbeddedDatabaseConnection(EmbeddedDatabaseConnection.NONE);\n\t\tassertThatExceptionOfType(DataSourceProperties.DataSourceBeanCreationException.class)\n\t\t\t.isThrownBy(properties::determineUrl)\n\t\t\t.withMessageContaining(\"Failed to determine suitable jdbc url\");\n\t}\n\n\t@Test\n\tvoid determineUrlWithExplicitConfig() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUrl(\"jdbc:mysql://mydb\");\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getUrl()).isEqualTo(\"jdbc:mysql://mydb\");\n\t\tassertThat(properties.determineUrl()).isEqualTo(\"jdbc:mysql://mydb\");\n\t}\n\n\t@Test\n\tvoid determineUrlWithGenerateUniqueName() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.determineUrl()).isEqualTo(properties.determineUrl());\n\n\t\tDataSourceProperties properties2 = new DataSourceProperties();\n\t\tproperties2.setGenerateUniqueName(true);\n\t\tproperties2.afterPropertiesSet();\n\t\tassertThat(properties.determineUrl()).isNotEqualTo(properties2.determineUrl());\n\t}\n\n\t@Test\n\tvoid determineUsername() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getUsername()).isNull();\n\t\tassertThat(properties.determineUsername()).isEqualTo(\"sa\");\n\t}\n\n\t@Test\n\tvoid determineUsernameWhenEmpty() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUsername(\"\");\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getUsername()).isEmpty();\n\t\tassertThat(properties.determineUsername()).isEqualTo(\"sa\");\n\t}\n\n\t@Test\n\tvoid determineUsernameWhenNull() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUsername(null);\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getUsername()).isNull();\n\t\tassertThat(properties.determineUsername()).isEqualTo(\"sa\");\n\t}\n\n\t@Test\n\tvoid determineUsernameWithExplicitConfig() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUsername(\"foo\");\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getUsername()).isEqualTo(\"foo\");\n\t\tassertThat(properties.determineUsername()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid determineUsernameWithNonEmbeddedUrl() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUrl(\"jdbc:h2:~/test\");\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getPassword()).isNull();\n\t\tassertThat(properties.determineUsername()).isNull();\n\t}\n\n\t@Test\n\tvoid determinePassword() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getPassword()).isNull();\n\t\tassertThat(properties.determinePassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid determinePasswordWithExplicitConfig() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setPassword(\"bar\");\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getPassword()).isEqualTo(\"bar\");\n\t\tassertThat(properties.determinePassword()).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid determinePasswordWithNonEmbeddedUrl() throws Exception {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setUrl(\"jdbc:h2:~/test\");\n\t\tproperties.afterPropertiesSet();\n\t\tassertThat(properties.getPassword()).isNull();\n\t\tassertThat(properties.determinePassword()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/DataSourceTransactionManagerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.support.JdbcTransactionManager;\nimport org.springframework.transaction.TransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataSourceTransactionManagerAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Kazuki Shimizu\n * @author Davin Byeon\n * @author Moritz Halbritter\n */\nclass DataSourceTransactionManagerAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(TransactionAutoConfiguration.class,\n\t\t\t\tTransactionManagerCustomizationAutoConfiguration.class,\n\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.url:jdbc:hsqldb:mem:test-\" + UUID.randomUUID());\n\n\t@Test\n\tvoid transactionManagerWithoutDataSourceIsNotConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(TransactionManager.class));\n\t}\n\n\t@Test\n\tvoid transactionManagerWithExistingDataSourceIsConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TransactionManager.class).hasSingleBean(JdbcTransactionManager.class);\n\t\t\t\tassertThat(context.getBean(JdbcTransactionManager.class).getDataSource())\n\t\t\t\t\t.isSameAs(context.getBean(DataSource.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid transactionManagerWithCustomizationIsConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.transaction.default-timeout=1m\",\n\t\t\t\t\t\"spring.transaction.rollback-on-commit-failure=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TransactionManager.class).hasSingleBean(JdbcTransactionManager.class);\n\t\t\t\tJdbcTransactionManager transactionManager = context.getBean(JdbcTransactionManager.class);\n\t\t\t\tassertThat(transactionManager.getDefaultTimeout()).isEqualTo(60);\n\t\t\t\tassertThat(transactionManager.isRollbackOnCommitFailure()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid transactionManagerWithExistingTransactionManagerIsNotOverridden() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withBean(\"myTransactionManager\", TransactionManager.class, () -> mock(TransactionManager.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DataSource.class)\n\t\t\t\t.hasSingleBean(TransactionManager.class)\n\t\t\t\t.hasBean(\"myTransactionManager\"));\n\t}\n\n\t@Test // gh-24321\n\tvoid transactionManagerWithDaoExceptionTranslationDisabled() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.dao.exceptiontranslation.enabled=false\")\n\t\t\t.run((context) -> assertThat(context.getBean(TransactionManager.class))\n\t\t\t\t.isExactlyInstanceOf(DataSourceTransactionManager.class));\n\t}\n\n\t@Test // gh-24321\n\tvoid transactionManagerWithDaoExceptionTranslationEnabled() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.dao.exceptiontranslation.enabled=true\")\n\t\t\t.run((context) -> assertThat(context.getBean(TransactionManager.class))\n\t\t\t\t.isExactlyInstanceOf(JdbcTransactionManager.class));\n\t}\n\n\t@Test // gh-24321\n\tvoid transactionManagerWithDaoExceptionTranslationDefault() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(TransactionManager.class))\n\t\t\t\t.isExactlyInstanceOf(JdbcTransactionManager.class));\n\t}\n\n\t@Test\n\tvoid transactionWithMultipleDataSourcesIsNotConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(MultiDataSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TransactionManager.class));\n\t}\n\n\t@Test\n\tvoid transactionWithMultipleDataSourcesAndPrimaryCandidateIsConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(MultiDataSourceUsingPrimaryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TransactionManager.class).hasSingleBean(JdbcTransactionManager.class);\n\t\t\tassertThat(context.getBean(JdbcTransactionManager.class).getDataSource())\n\t\t\t\t.isSameAs(context.getBean(\"test1DataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotUseDataSourcePropertiesIfDataSourceIsNotOnTheClasspath() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(DataSource.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSourceProperties.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/Dbcp2JdbcConnectionDetailsBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Dbcp2JdbcConnectionDetailsBeanPostProcessor}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass Dbcp2JdbcConnectionDetailsBeanPostProcessorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid setUsernamePasswordUrlAndDriverClassName() {\n\t\tBasicDataSource dataSource = new BasicDataSource();\n\t\tdataSource.setUrl(\"will-be-overwritten\");\n\t\tdataSource.setUsername(\"will-be-overwritten\");\n\t\tdataSource.setPassword(\"will-be-overwritten\");\n\t\tdataSource.setDriverClassName(\"will-be-overwritten\");\n\t\tnew Dbcp2JdbcConnectionDetailsBeanPostProcessor(mock(ObjectProvider.class)).processDataSource(dataSource,\n\t\t\t\tnew TestJdbcConnectionDetails());\n\t\tassertThat(dataSource.getUrl()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\tassertThat(dataSource.getUserName()).isEqualTo(\"user-1\");\n\t\tassertThat(dataSource).extracting(\"password\").isEqualTo(\"password-1\");\n\t\tassertThat(dataSource.getDriverClassName()).isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/EmbeddedDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EmbeddedDataSourceConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass EmbeddedDataSourceConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultEmbeddedDatabase() {\n\t\tthis.context = load();\n\t\tassertThat(this.context.getBean(DataSource.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid generateUniqueName() throws Exception {\n\t\tthis.context = load(\"spring.datasource.generate-unique-name=true\");\n\t\ttry (AnnotationConfigApplicationContext context2 = load(\"spring.datasource.generate-unique-name=true\")) {\n\t\t\tDataSource dataSource = this.context.getBean(DataSource.class);\n\t\t\tDataSource dataSource2 = context2.getBean(DataSource.class);\n\t\t\tassertThat(getDatabaseName(dataSource)).isNotEqualTo(getDatabaseName(dataSource2));\n\t\t}\n\t}\n\n\tprivate String getDatabaseName(DataSource dataSource) throws SQLException {\n\t\ttry (Connection connection = dataSource.getConnection()) {\n\t\t\tResultSet catalogs = connection.getMetaData().getCatalogs();\n\t\t\tif (catalogs.next()) {\n\t\t\t\treturn catalogs.getString(1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalStateException(\"Unable to get database name\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate AnnotationConfigApplicationContext load(String... environment) {\n\t\tAnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(environment).applyTo(ctx);\n\t\tctx.register(EmbeddedDataSourceConfiguration.class);\n\t\tctx.refresh();\n\t\treturn ctx;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/HikariDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.io.PrintWriter;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.SQLFeatureNotSupportedException;\nimport java.util.logging.Logger;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.HikariCheckpointRestoreLifecycle;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.DelegatingDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataSourceAutoConfiguration} with Hikari.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Olga Maciaszek-Sharma\n */\nclass HikariDataSourceConfigurationTests {\n\n\tprivate static final String PREFIX = \"spring.datasource.hikari.\";\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.type=\" + HikariDataSource.class.getName());\n\n\t@Test\n\tvoid testDataSourceExists() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(DataSource.class)).hasSize(1);\n\t\t\tassertThat(context.getBeansOfType(HikariDataSource.class)).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDataSourcePropertiesOverridden() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(PREFIX + \"jdbc-url=jdbc:foo//bar/spam\", \"spring.datasource.hikari.max-lifetime=1234\")\n\t\t\t.run((context) -> {\n\t\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(ds.getJdbcUrl()).isEqualTo(\"jdbc:foo//bar/spam\");\n\t\t\t\tassertThat(ds.getMaxLifetime()).isEqualTo(1234);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDataSourceGenericPropertiesOverridden() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(PREFIX + \"data-source-properties.dataSourceClassName=org.h2.JDBCDataSource\")\n\t\t\t.run((context) -> {\n\t\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(ds.getDataSourceProperties().getProperty(\"dataSourceClassName\"))\n\t\t\t\t\t.isEqualTo(\"org.h2.JDBCDataSource\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\t@ClassPathExclusions({ \"h2-*.jar\", \"hsqldb-*.jar\" })\n\tvoid configureDataSourceClassNameWithNoEmbeddedDatabaseAvailable() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.url=jdbc:example//\",\n\t\t\t\t\t\"spring.datasource.hikari.data-source-class-name=\" + MockDataSource.class.getName())\n\t\t\t.run((context) -> {\n\t\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(ds.getDataSourceClassName()).isEqualTo(MockDataSource.class.getName());\n\t\t\t\tassertThatNoException().isThrownBy(() -> ds.getConnection().close());\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid configureDataSourceClassNameToOverrideUseOfAnEmbeddedDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.url=jdbc:example//\",\n\t\t\t\t\t\"spring.datasource.hikari.data-source-class-name=\" + MockDataSource.class.getName())\n\t\t\t.run((context) -> {\n\t\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(ds.getDataSourceClassName()).isEqualTo(MockDataSource.class.getName());\n\t\t\t\tassertThatNoException().isThrownBy(() -> ds.getConnection().close());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDataSourceDefaultsPreserved() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\tassertThat(ds.getMaxLifetime()).isEqualTo(1800000);\n\t\t});\n\t}\n\n\t@Test\n\tvoid nameIsAliasedToPoolName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.name=myDS\").run((context) -> {\n\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\tassertThat(ds.getPoolName()).isEqualTo(\"myDS\");\n\n\t\t});\n\t}\n\n\t@Test\n\tvoid poolNameTakesPrecedenceOverName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.name=myDS\", PREFIX + \"pool-name=myHikariDS\")\n\t\t\t.run((context) -> {\n\t\t\t\tHikariDataSource ds = context.getBean(HikariDataSource.class);\n\t\t\t\tassertThat(ds.getPoolName()).isEqualTo(\"myHikariDS\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid usesCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(JdbcConnectionDetails.class, TestJdbcConnectionDetails::new)\n\t\t\t.withPropertyValues(PREFIX + \"url=jdbc:broken\", PREFIX + \"username=alice\", PREFIX + \"password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesJdbcConnectionDetails.class);\n\t\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\t\tassertThat(dataSource).asInstanceOf(InstanceOfAssertFactories.type(HikariDataSource.class))\n\t\t\t\t\t.satisfies((hikari) -> {\n\t\t\t\t\t\tassertThat(hikari.getUsername()).isEqualTo(\"user-1\");\n\t\t\t\t\t\tassertThat(hikari.getPassword()).isEqualTo(\"password-1\");\n\t\t\t\t\t\tassertThat(hikari.getDriverClassName()).isEqualTo(\"org.postgresql.Driver\");\n\t\t\t\t\t\tassertThat(hikari.getJdbcUrl())\n\t\t\t\t\t\t\t.isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\t@ClassPathOverrides(\"org.crac:crac:1.3.0\")\n\tvoid whenCheckpointRestoreIsAvailableHikariAutoConfigRegistersLifecycleBean() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.type=\" + HikariDataSource.class.getName())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HikariCheckpointRestoreLifecycle.class));\n\t}\n\n\t@Test\n\t@ClassPathOverrides(\"org.crac:crac:1.3.0\")\n\tvoid whenCheckpointRestoreIsAvailableAndDataSourceHasBeenWrappedHikariAutoConfigRegistersLifecycleBean() {\n\t\tthis.contextRunner.withUserConfiguration(DataSourceWrapperConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HikariCheckpointRestoreLifecycle.class));\n\t}\n\n\t@Test\n\tvoid whenCheckpointRestoreIsNotAvailableHikariAutoConfigDoesNotRegisterLifecycleBean() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HikariCheckpointRestoreLifecycle.class));\n\t}\n\n\t@Test\n\t@ClassPathOverrides(\"org.crac:crac:1.3.0\")\n\tvoid whenCheckpointRestoreIsAvailableAndDataSourceIsFromUserConfigurationHikariAutoConfigRegistersLifecycleBean() {\n\t\tthis.contextRunner.withUserConfiguration(UserDataSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HikariCheckpointRestoreLifecycle.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tJdbcConnectionDetails sqlConnectionDetails() {\n\t\t\treturn new TestJdbcConnectionDetails();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceWrapperConfiguration {\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor dataSourceWrapper() {\n\t\t\treturn new BeanPostProcessor() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\t\t\t\tif (bean instanceof DataSource dataSource) {\n\t\t\t\t\t\treturn new DelegatingDataSource(dataSource);\n\t\t\t\t\t}\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn DataSourceBuilder.create()\n\t\t\t\t.driverClassName(\"org.postgresql.Driver\")\n\t\t\t\t.url(\"jdbc:postgresql://localhost:5432/database\")\n\t\t\t\t.username(\"user\")\n\t\t\t\t.password(\"password\")\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\tpublic static class MockDataSource implements DataSource {\n\n\t\t@Override\n\t\tpublic @Nullable Logger getParentLogger() throws SQLFeatureNotSupportedException {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic <T> @Nullable T unwrap(Class<T> iface) throws SQLException {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isWrapperFor(Class<?> iface) throws SQLException {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic Connection getConnection() throws SQLException {\n\t\t\treturn mock(Connection.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic Connection getConnection(String username, String password) throws SQLException {\n\t\t\treturn getConnection();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable PrintWriter getLogWriter() throws SQLException {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLogWriter(PrintWriter out) throws SQLException {\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLoginTimeout(int seconds) throws SQLException {\n\t\t}\n\n\t\t@Override\n\t\tpublic int getLoginTimeout() throws SQLException {\n\t\t\treturn -1;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/HikariDataSourcePoolMetadataRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.util.Optional;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourcePoolMetadataProvidersConfiguration.HikariDataSourcePoolMetadataRuntimeHints;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourcePoolMetadataProvidersConfiguration.HikariPoolDataSourceMetadataProviderConfiguration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.annotation.MergedAnnotations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HikariDataSourcePoolMetadataRuntimeHints}.\n *\n * @author Andy Wilkinson\n */\nclass HikariDataSourcePoolMetadataRuntimeHintsTests {\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid importsRegistrar() {\n\t\tOptional<Class[]> imported = MergedAnnotations.from(HikariPoolDataSourceMetadataProviderConfiguration.class)\n\t\t\t.get(ImportRuntimeHints.class)\n\t\t\t.getValue(\"value\", Class[].class);\n\t\tassertThat(imported).hasValue(new Class[] { HikariDataSourcePoolMetadataRuntimeHints.class });\n\t}\n\n\t@Test\n\tvoid registersHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew HikariDataSourcePoolMetadataRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(HikariDataSource.class).hasDeclaredFields(\"pool\");\n\t\tassertThat(RuntimeHintsPredicates.reflection().onFieldAccess(HikariDataSource.class, \"pool\"))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/HikariDriverConfigurationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport com.mchange.util.AssertException;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HikariDriverConfigurationFailureAnalyzer}.\n *\n * @author Stephane Nicoll\n */\nclass HikariDriverConfigurationFailureAnalyzerTests {\n\n\t@Test\n\t@WithResource(name = \"schema.sql\", content = \"\")\n\tvoid failureAnalysisIsPerformed() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);\n\t\tassertThat(failureAnalysis).isNotNull();\n\t\tassertThat(failureAnalysis.getDescription())\n\t\t\t.isEqualTo(\"Configuration of the Hikari connection pool failed: 'dataSourceClassName' is not supported.\");\n\t\tassertThat(failureAnalysis.getAction()).contains(\"Spring Boot auto-configures only a driver\");\n\t}\n\n\t@Test\n\tvoid unrelatedIllegalStateExceptionIsSkipped() {\n\t\tFailureAnalysis failureAnalysis = new HikariDriverConfigurationFailureAnalyzer()\n\t\t\t.analyze(new RuntimeException(\"foo\", new IllegalStateException(\"bar\")));\n\t\tassertThat(failureAnalysis).isNull();\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(Class<?> configuration) {\n\t\tBeanCreationException failure = createFailure(configuration);\n\t\tassertThat(failure).isNotNull();\n\t\treturn new HikariDriverConfigurationFailureAnalyzer().analyze(failure);\n\t}\n\n\tprivate BeanCreationException createFailure(Class<?> configuration) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues\n\t\t\t.of(\"spring.datasource.type=\" + HikariDataSource.class.getName(),\n\t\t\t\t\t\"spring.datasource.hikari.data-source-class-name=com.example.Foo\", \"spring.sql.init.mode=always\")\n\t\t\t.applyTo(context);\n\t\tcontext.register(configuration);\n\t\ttry {\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\tthrow new AssertException(\"Shouldn't be reached!\");\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ DataSourceAutoConfiguration.class, DataSourceInitializationAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/HikariJdbcConnectionDetailsBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HikariJdbcConnectionDetailsBeanPostProcessor}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass HikariJdbcConnectionDetailsBeanPostProcessorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid setUsernamePasswordAndUrl() {\n\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\tdataSource.setJdbcUrl(\"will-be-overwritten\");\n\t\tdataSource.setUsername(\"will-be-overwritten\");\n\t\tdataSource.setPassword(\"will-be-overwritten\");\n\t\tdataSource.setDriverClassName(DatabaseDriver.H2.getDriverClassName());\n\t\tnew HikariJdbcConnectionDetailsBeanPostProcessor(mock(ObjectProvider.class)).processDataSource(dataSource,\n\t\t\t\tnew TestJdbcConnectionDetails());\n\t\tassertThat(dataSource.getJdbcUrl()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\tassertThat(dataSource.getUsername()).isEqualTo(\"user-1\");\n\t\tassertThat(dataSource.getPassword()).isEqualTo(\"password-1\");\n\t\tassertThat(dataSource.getDriverClassName()).isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid toleratesConnectionDetailsWithNullDriverClassName() {\n\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\tdataSource.setDriverClassName(DatabaseDriver.H2.getDriverClassName());\n\t\tJdbcConnectionDetails connectionDetails = mock(JdbcConnectionDetails.class);\n\t\tnew HikariJdbcConnectionDetailsBeanPostProcessor(mock(ObjectProvider.class)).processDataSource(dataSource,\n\t\t\t\tconnectionDetails);\n\t\tassertThat(dataSource.getDriverClassName()).isEqualTo(DatabaseDriver.H2.getDriverClassName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/JdbcClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\nimport org.springframework.jdbc.core.simple.JdbcClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JdbcClientAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass JdbcClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,\n\t\t\t\tJdbcClientAutoConfiguration.class));\n\n\t@Test\n\tvoid jdbcClientWhenNoAvailableJdbcTemplateIsNotCreated() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(DataSourceAutoConfiguration.class, JdbcClientAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JdbcClient.class));\n\t}\n\n\t@Test\n\tvoid jdbcClientWhenExistingJdbcTemplateIsCreated() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcClient.class);\n\t\t\tNamedParameterJdbcTemplate namedParameterJdbcTemplate = context.getBean(NamedParameterJdbcTemplate.class);\n\t\t\tassertThat(namedParameterJdbcTemplate.getJdbcOperations()).isEqualTo(context.getBean(JdbcOperations.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid jdbcClientWithCustomJdbcClientIsNotCreated() {\n\t\tthis.contextRunner.withBean(\"customJdbcClient\", JdbcClient.class, () -> mock(JdbcClient.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcClient.class);\n\t\t\t\tassertThat(context.getBean(JdbcClient.class)).isEqualTo(context.getBean(\"customJdbcClient\"));\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/JdbcTemplateAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\nimport org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JdbcTemplateAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Kazuki Shimizu\n * @author Dan Zheng\n */\nclass JdbcTemplateAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(DataSourceAutoConfiguration.class, JdbcTemplateAutoConfiguration.class));\n\n\t@Test\n\tvoid testJdbcTemplateExists() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcOperations.class);\n\t\t\tJdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);\n\t\t\tassertThat(jdbcTemplate.getDataSource()).isEqualTo(context.getBean(DataSource.class));\n\t\t\tassertThat(jdbcTemplate.isIgnoreWarnings()).isEqualTo(true);\n\t\t\tassertThat(jdbcTemplate.getFetchSize()).isEqualTo(-1);\n\t\t\tassertThat(jdbcTemplate.getQueryTimeout()).isEqualTo(-1);\n\t\t\tassertThat(jdbcTemplate.getMaxRows()).isEqualTo(-1);\n\t\t\tassertThat(jdbcTemplate.isSkipResultsProcessing()).isEqualTo(false);\n\t\t\tassertThat(jdbcTemplate.isSkipUndeclaredResults()).isEqualTo(false);\n\t\t\tassertThat(jdbcTemplate.isResultsMapCaseInsensitive()).isEqualTo(false);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testJdbcTemplateWithCustomProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.jdbc.template.ignore-warnings:false\", \"spring.jdbc.template.fetch-size:100\",\n\t\t\t\t\t\"spring.jdbc.template.query-timeout:60\", \"spring.jdbc.template.max-rows:1000\",\n\t\t\t\t\t\"spring.jdbc.template.skip-results-processing:true\",\n\t\t\t\t\t\"spring.jdbc.template.skip-undeclared-results:true\",\n\t\t\t\t\t\"spring.jdbc.template.results-map-case-insensitive:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcOperations.class);\n\t\t\t\tJdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);\n\t\t\t\tassertThat(jdbcTemplate.getDataSource()).isNotNull();\n\t\t\t\tassertThat(jdbcTemplate.isIgnoreWarnings()).isEqualTo(false);\n\t\t\t\tassertThat(jdbcTemplate.getFetchSize()).isEqualTo(100);\n\t\t\t\tassertThat(jdbcTemplate.getQueryTimeout()).isEqualTo(60);\n\t\t\t\tassertThat(jdbcTemplate.getMaxRows()).isEqualTo(1000);\n\t\t\t\tassertThat(jdbcTemplate.isSkipResultsProcessing()).isEqualTo(true);\n\t\t\t\tassertThat(jdbcTemplate.isSkipUndeclaredResults()).isEqualTo(true);\n\t\t\t\tassertThat(jdbcTemplate.isResultsMapCaseInsensitive()).isEqualTo(true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testJdbcTemplateExistsWithCustomDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(TestDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcOperations.class);\n\t\t\tJdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);\n\t\t\tassertThat(jdbcTemplate.getDataSource()).isEqualTo(context.getBean(\"customDataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testNamedParameterJdbcTemplateExists() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(NamedParameterJdbcOperations.class);\n\t\t\tNamedParameterJdbcTemplate namedParameterJdbcTemplate = context.getBean(NamedParameterJdbcTemplate.class);\n\t\t\tassertThat(namedParameterJdbcTemplate.getJdbcOperations()).isEqualTo(context.getBean(JdbcOperations.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testMultiDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(MultiDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(JdbcOperations.class);\n\t\t\tassertThat(context).doesNotHaveBean(NamedParameterJdbcOperations.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testMultiJdbcTemplate() {\n\t\tthis.contextRunner.withUserConfiguration(MultiJdbcTemplateConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(NamedParameterJdbcOperations.class));\n\t}\n\n\t@Test\n\tvoid testMultiDataSourceUsingPrimary() {\n\t\tthis.contextRunner.withUserConfiguration(MultiDataSourceUsingPrimaryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcOperations.class);\n\t\t\tassertThat(context).hasSingleBean(NamedParameterJdbcOperations.class);\n\t\t\tassertThat(context.getBean(JdbcTemplate.class).getDataSource())\n\t\t\t\t.isEqualTo(context.getBean(\"test1DataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testMultiJdbcTemplateUsingPrimary() {\n\t\tthis.contextRunner.withUserConfiguration(MultiJdbcTemplateUsingPrimaryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(NamedParameterJdbcOperations.class);\n\t\t\tassertThat(context.getBean(NamedParameterJdbcTemplate.class).getJdbcOperations())\n\t\t\t\t.isEqualTo(context.getBean(\"test1Template\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testExistingCustomJdbcTemplate() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcOperations.class);\n\t\t\tassertThat(context.getBean(JdbcOperations.class)).isEqualTo(context.getBean(\"customJdbcOperations\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testExistingCustomNamedParameterJdbcTemplate() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(NamedParameterJdbcOperations.class);\n\t\t\tassertThat(context.getBean(NamedParameterJdbcOperations.class))\n\t\t\t\t.isEqualTo(context.getBean(\"customNamedParameterJdbcOperations\"));\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"schema.sql\", content = \"\"\"\n\t\t\tCREATE TABLE BAR (\n\t\t\t  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\t\t\t  name VARCHAR(30)\n\t\t\t);\n\t\t\t\"\"\")\n\t@WithResource(name = \"data.sql\", content = \"INSERT INTO BAR VALUES (1, 'Andy');\")\n\tvoid testDependencyToScriptBasedDataSourceInitialization() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceInitializationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DataSourceInitializationValidator.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context.getBean(DataSourceInitializationValidator.class).count).isOne();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureJdbcTemplateWithSQLExceptionTranslatorIfPresent() {\n\t\tSQLStateSQLExceptionTranslator sqlExceptionTranslator = new SQLStateSQLExceptionTranslator();\n\t\tthis.contextRunner.withBean(SQLExceptionTranslator.class, () -> sqlExceptionTranslator).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JdbcTemplate.class);\n\t\t\tJdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);\n\t\t\tassertThat(jdbcTemplate.getExceptionTranslator()).isSameAs(sqlExceptionTranslator);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureJdbcTemplateWithSQLExceptionTranslatorIfNotUnique() {\n\t\tSQLStateSQLExceptionTranslator sqlExceptionTranslator1 = new SQLStateSQLExceptionTranslator();\n\t\tSQLStateSQLExceptionTranslator sqlExceptionTranslator2 = new SQLStateSQLExceptionTranslator();\n\t\tthis.contextRunner\n\t\t\t.withBean(\"sqlExceptionTranslator1\", SQLExceptionTranslator.class, () -> sqlExceptionTranslator1)\n\t\t\t.withBean(\"sqlExceptionTranslator2\", SQLExceptionTranslator.class, () -> sqlExceptionTranslator2)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcTemplate.class);\n\t\t\t\tJdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);\n\t\t\t\tassertThat(jdbcTemplate.getExceptionTranslator()).isNotSameAs(sqlExceptionTranslator1)\n\t\t\t\t\t.isNotSameAs(sqlExceptionTranslator2);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConfiguration {\n\n\t\t@Bean\n\t\tJdbcOperations customJdbcOperations(DataSource dataSource) {\n\t\t\treturn new JdbcTemplate(dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tNamedParameterJdbcOperations customNamedParameterJdbcOperations(DataSource dataSource) {\n\t\t\treturn new NamedParameterJdbcTemplate(dataSource);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource customDataSource() {\n\t\t\treturn new TestDataSource();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultiJdbcTemplateConfiguration {\n\n\t\t@Bean\n\t\tJdbcTemplate test1Template() {\n\t\t\treturn mock(JdbcTemplate.class);\n\t\t}\n\n\t\t@Bean\n\t\tJdbcTemplate test2Template() {\n\t\t\treturn mock(JdbcTemplate.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultiJdbcTemplateUsingPrimaryConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tJdbcTemplate test1Template() {\n\t\t\treturn mock(JdbcTemplate.class);\n\t\t}\n\n\t\t@Bean\n\t\tJdbcTemplate test2Template() {\n\t\t\treturn mock(JdbcTemplate.class);\n\t\t}\n\n\t}\n\n\tstatic class DataSourceInitializationValidator {\n\n\t\tprivate final @Nullable Integer count;\n\n\t\tDataSourceInitializationValidator(JdbcTemplate jdbcTemplate) {\n\t\t\tthis.count = jdbcTemplate.queryForObject(\"SELECT COUNT(*) from BAR\", Integer.class);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"db/changelog/db.changelog-city.yaml\", content = \"\"\"\n\t\t\tdatabaseChangeLog:\n\t\t\t- changeSet:\n\t\t\t    id: 1\n\t\t\t    author: dsyer\n\t\t\t    changes:\n\t\t\t      - createSequence:\n\t\t\t          sequenceName: city_seq\n\t\t\t          incrementBy: 50\n\t\t\t      - createTable:\n\t\t\t          tableName: city\n\t\t\t          columns:\n\t\t\t            - column:\n\t\t\t                name: id\n\t\t\t                type: bigint\n\t\t\t                autoIncrement: true\n\t\t\t                constraints:\n\t\t\t                  primaryKey: true\n\t\t\t                  nullable: false\n\t\t\t            - column:\n\t\t\t                name: name\n\t\t\t                type: varchar(50)\n\t\t\t                constraints:\n\t\t\t                  nullable: false\n\t\t\t\"\"\")\n\t@interface WithDbChangelogCityYamlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/JndiDataSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.util.Set;\n\nimport javax.naming.Context;\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoader;\nimport org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jmx.export.MBeanExporter;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JndiDataSourceAutoConfiguration}\n *\n * @author Andy Wilkinson\n */\nclass JndiDataSourceAutoConfigurationTests {\n\n\tprivate ClassLoader threadContextClassLoader;\n\n\tprivate String initialContextFactory;\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@BeforeEach\n\tvoid setupJndi() {\n\t\tthis.initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, TestableInitialContextFactory.class.getName());\n\t}\n\n\t@BeforeEach\n\tvoid setupThreadContextClassLoader() {\n\t\tthis.threadContextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread().setContextClassLoader(new JndiPropertiesHidingClassLoader(getClass().getClassLoader()));\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tTestableInitialContextFactory.clearAll();\n\t\tif (this.initialContextFactory != null) {\n\t\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, this.initialContextFactory);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\t}\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tThread.currentThread().setContextClassLoader(this.threadContextClassLoader);\n\t}\n\n\t@Test\n\tvoid dataSourceIsAvailableFromJndi() {\n\t\tDataSource dataSource = new BasicDataSource();\n\t\tconfigureJndi(\"foo\", dataSource);\n\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.datasource.jndi-name:foo\").applyTo(this.context);\n\t\tthis.context.register(JndiDataSourceAutoConfiguration.class);\n\t\tthis.context.refresh();\n\n\t\tassertThat(this.context.getBean(DataSource.class)).isEqualTo(dataSource);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid mbeanDataSourceIsExcludedFromExport() {\n\t\tDataSource dataSource = new BasicDataSource();\n\t\tconfigureJndi(\"foo\", dataSource);\n\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.datasource.jndi-name:foo\").applyTo(this.context);\n\t\tthis.context.register(JndiDataSourceAutoConfiguration.class, MBeanExporterConfiguration.class);\n\t\tthis.context.refresh();\n\n\t\tassertThat(this.context.getBean(DataSource.class)).isEqualTo(dataSource);\n\t\tMBeanExporter exporter = this.context.getBean(MBeanExporter.class);\n\t\tSet<String> excludedBeans = (Set<String>) ReflectionTestUtils.getField(exporter, \"excludedBeans\");\n\t\tassertThat(excludedBeans).containsExactly(\"dataSource\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid mbeanDataSourceIsExcludedFromExportByAllExporters() {\n\t\tDataSource dataSource = new BasicDataSource();\n\t\tconfigureJndi(\"foo\", dataSource);\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.datasource.jndi-name:foo\").applyTo(this.context);\n\t\tthis.context.register(JndiDataSourceAutoConfiguration.class, MBeanExporterConfiguration.class,\n\t\t\t\tAnotherMBeanExporterConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(DataSource.class)).isEqualTo(dataSource);\n\t\tfor (MBeanExporter exporter : this.context.getBeansOfType(MBeanExporter.class).values()) {\n\t\t\tSet<String> excludedBeans = (Set<String>) ReflectionTestUtils.getField(exporter, \"excludedBeans\");\n\t\t\tassertThat(excludedBeans).containsExactly(\"dataSource\");\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid standardDataSourceIsNotExcludedFromExport() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tconfigureJndi(\"foo\", dataSource);\n\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.datasource.jndi-name:foo\").applyTo(this.context);\n\t\tthis.context.register(JndiDataSourceAutoConfiguration.class, MBeanExporterConfiguration.class);\n\t\tthis.context.refresh();\n\n\t\tassertThat(this.context.getBean(DataSource.class)).isEqualTo(dataSource);\n\t\tMBeanExporter exporter = this.context.getBean(MBeanExporter.class);\n\t\tSet<String> excludedBeans = (Set<String>) ReflectionTestUtils.getField(exporter, \"excludedBeans\");\n\t\tassertThat(excludedBeans).isEmpty();\n\t}\n\n\tprivate void configureJndi(String name, DataSource dataSource) {\n\t\tTestableInitialContextFactory.bind(name, dataSource);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MBeanExporterConfiguration {\n\n\t\t@Bean\n\t\tMBeanExporter mbeanExporter() {\n\t\t\treturn new MBeanExporter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnotherMBeanExporterConfiguration {\n\n\t\t@Bean\n\t\tMBeanExporter anotherMbeanExporter() {\n\t\t\treturn new MBeanExporter();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/MultiDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for multiple {@link DataSource}.\n *\n * @author Phillip Webb\n * @author Kazuki Shimizu\n */\n@Configuration(proxyBeanMethods = false)\nclass MultiDataSourceConfiguration {\n\n\t@Bean\n\tDataSource test1DataSource() {\n\t\treturn new TestDataSource(\"test1\", false);\n\t}\n\n\t@Bean\n\tDataSource test2DataSource() {\n\t\treturn new TestDataSource(\"test2\", false);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/MultiDataSourceUsingPrimaryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Configuration for multiple {@link DataSource} (one being {@code @Primary}).\n *\n * @author Phillip Webb\n * @author Kazuki Shimizu\n */\n@Configuration(proxyBeanMethods = false)\nclass MultiDataSourceUsingPrimaryConfiguration {\n\n\t@Bean\n\t@Primary\n\tDataSource test1DataSource() {\n\t\treturn new TestDataSource(\"test1\", false);\n\t}\n\n\t@Bean\n\tDataSource test2DataSource() {\n\t\treturn new TestDataSource(\"test2\", false);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/OracleUcpDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.Connection;\nimport java.time.Duration;\n\nimport javax.sql.DataSource;\n\nimport oracle.ucp.jdbc.PoolDataSource;\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\nimport oracle.ucp.util.OpaqueString;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourceAutoConfiguration} with Oracle UCP.\n *\n * @author Fabio Grassi\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass OracleUcpDataSourceConfigurationTests {\n\n\tprivate static final String PREFIX = \"spring.datasource.oracleucp.\";\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.type=\" + PoolDataSource.class.getName());\n\n\t@Test\n\tvoid testDataSourceExists() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(DataSource.class)).hasSize(1);\n\t\t\tassertThat(context.getBeansOfType(PoolDataSourceImpl.class)).hasSize(1);\n\t\t\ttry (Connection connection = context.getBean(DataSource.class).getConnection()) {\n\t\t\t\tassertThat(connection.isValid(1000)).isTrue();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDataSourcePropertiesOverridden() {\n\t\tthis.contextRunner.withPropertyValues(PREFIX + \"url=jdbc:foo//bar/spam\", PREFIX + \"max-idle-time=1234\")\n\t\t\t.run((context) -> {\n\t\t\t\tPoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);\n\t\t\t\tassertThat(ds.getURL()).isEqualTo(\"jdbc:foo//bar/spam\");\n\t\t\t\tassertThat(ds.getMaxIdleTime()).isEqualTo(1234);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDataSourceConnectionPropertiesOverridden() {\n\t\tthis.contextRunner.withPropertyValues(PREFIX + \"connection-properties.autoCommit=false\").run((context) -> {\n\t\t\tPoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);\n\t\t\tassertThat(ds.getConnectionProperty(\"autoCommit\")).isEqualTo(\"false\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDataSourceDefaultsPreserved() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tPoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);\n\t\t\tassertThat(ds.getInitialPoolSize()).isZero();\n\t\t\tassertThat(ds.getMinPoolSize()).isOne();\n\t\t\tassertThat(ds.getMaxPoolSize()).isEqualTo(Integer.MAX_VALUE);\n\t\t\tassertThat(ds.getInactiveConnectionTimeout()).isZero();\n\t\t\tassertThat(ds.getConnectionWaitDuration()).isEqualTo(Duration.ofSeconds(3));\n\t\t\tassertThat(ds.getTimeToLiveConnectionTimeout()).isZero();\n\t\t\tassertThat(ds.getAbandonedConnectionTimeout()).isZero();\n\t\t\tassertThat(ds.getTimeoutCheckInterval()).isEqualTo(30);\n\t\t\tassertThat(ds.getFastConnectionFailoverEnabled()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid nameIsAliasedToPoolName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.name=myDS\").run((context) -> {\n\t\t\tPoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);\n\t\t\tassertThat(ds.getConnectionPoolName()).isEqualTo(\"myDS\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid poolNameTakesPrecedenceOverName() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.datasource.name=myDS\", PREFIX + \"connection-pool-name=myOracleUcpDS\")\n\t\t\t.run((context) -> {\n\t\t\t\tPoolDataSourceImpl ds = context.getBean(PoolDataSourceImpl.class);\n\t\t\t\tassertThat(ds.getConnectionPoolName()).isEqualTo(\"myOracleUcpDS\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid usesCustomJdbcConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(JdbcConnectionDetails.class, TestJdbcConnectionDetails::new)\n\t\t\t.withPropertyValues(PREFIX + \"url=jdbc:broken\", PREFIX + \"username=alice\", PREFIX + \"password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesJdbcConnectionDetails.class);\n\t\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\t\tassertThat(dataSource).isInstanceOf(PoolDataSourceImpl.class);\n\t\t\t\tPoolDataSourceImpl oracleUcp = (PoolDataSourceImpl) dataSource;\n\t\t\t\tassertThat(oracleUcp.getUser()).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(oracleUcp).extracting(\"password\")\n\t\t\t\t\t.extracting((o) -> ((OpaqueString) o).get())\n\t\t\t\t\t.isEqualTo(\"password-1\");\n\t\t\t\tassertThat(oracleUcp.getConnectionFactoryClassName())\n\t\t\t\t\t.isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t\t\t\tassertThat(oracleUcp.getURL()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/OracleUcpJdbcConnectionDetailsBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.SQLException;\n\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\nimport oracle.ucp.util.OpaqueString;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OracleUcpJdbcConnectionDetailsBeanPostProcessor}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass OracleUcpJdbcConnectionDetailsBeanPostProcessorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid setUsernamePasswordUrlAndDriverClassName() throws SQLException {\n\t\tPoolDataSourceImpl dataSource = new PoolDataSourceImpl();\n\t\tdataSource.setURL(\"will-be-overwritten\");\n\t\tdataSource.setUser(\"will-be-overwritten\");\n\t\tdataSource.setPassword(\"will-be-overwritten\");\n\t\tdataSource.setConnectionFactoryClassName(\"will-be-overwritten\");\n\t\tnew OracleUcpJdbcConnectionDetailsBeanPostProcessor(mock(ObjectProvider.class)).processDataSource(dataSource,\n\t\t\t\tnew TestJdbcConnectionDetails());\n\t\tassertThat(dataSource.getURL()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\tassertThat(dataSource.getUser()).isEqualTo(\"user-1\");\n\t\tassertThat(dataSource).extracting(\"password\")\n\t\t\t.extracting((password) -> ((OpaqueString) password).get())\n\t\t\t.isEqualTo(\"password-1\");\n\t\tassertThat(dataSource.getConnectionFactoryClassName())\n\t\t\t.isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/TestDataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.UUID;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\n\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\n\n/**\n * {@link BasicDataSource} used for testing.\n *\n * @author Phillip Webb\n * @author Kazuki Shimizu\n * @author Stephane Nicoll\n */\npublic class TestDataSource extends SimpleDriverDataSource {\n\n\t/**\n\t * Create an in-memory database with a random name.\n\t */\n\tpublic TestDataSource() {\n\t\tthis(false);\n\t}\n\n\t/**\n\t * Create an in-memory database with a random name.\n\t * @param addTestUser if a test user should be added\n\t */\n\tpublic TestDataSource(boolean addTestUser) {\n\t\tthis(UUID.randomUUID().toString(), addTestUser);\n\t}\n\n\t/**\n\t * Create an in-memory database with the specified name.\n\t * @param name the name of the database\n\t * @param addTestUser if a test user should be added\n\t */\n\tpublic TestDataSource(String name, boolean addTestUser) {\n\t\tsetDriverClass(org.hsqldb.jdbc.JDBCDriver.class);\n\t\tsetUrl(\"jdbc:hsqldb:mem:\" + name);\n\t\tsetUsername(\"sa\");\n\t\tsetupDatabase(addTestUser);\n\t\tsetUrl(getUrl() + \";create=false\");\n\t}\n\n\tprivate void setupDatabase(boolean addTestUser) {\n\t\ttry (Connection connection = getConnection()) {\n\t\t\tif (addTestUser) {\n\t\t\t\tconnection.prepareStatement(\"CREATE USER \\\"test\\\" password \\\"secret\\\" ADMIN\").execute();\n\t\t\t}\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/TestJdbcConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * {@link JdbcConnectionDetails} used in tests.\n *\n * @author Moritz Halbritter\n */\nclass TestJdbcConnectionDetails implements JdbcConnectionDetails {\n\n\t@Override\n\tpublic String getJdbcUrl() {\n\t\treturn \"jdbc:customdb://customdb.example.com:12345/database-1\";\n\t}\n\n\t@Override\n\tpublic String getUsername() {\n\t\treturn \"user-1\";\n\t}\n\n\t@Override\n\tpublic String getPassword() {\n\t\treturn \"password-1\";\n\t}\n\n\t@Override\n\tpublic String getDriverClassName() {\n\t\tString driverClassName = DatabaseDriver.POSTGRESQL.getDriverClassName();\n\t\tassertThat(driverClassName).isNotNull();\n\t\treturn driverClassName;\n\t}\n\n\t@Override\n\tpublic String getXaDataSourceClassName() {\n\t\tString xaDataSourceClassName = DatabaseDriver.POSTGRESQL.getXaDataSourceClassName();\n\t\tassertThat(xaDataSourceClassName).isNotNull();\n\t\treturn xaDataSourceClassName;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/TomcatDataSourceConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.apache.tomcat.jdbc.pool.DataSourceProxy;\nimport org.apache.tomcat.jdbc.pool.PoolProperties;\nimport org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableMBeanExport;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link TomcatDataSourceConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass TomcatDataSourceConfigurationTests {\n\n\tprivate static final String PREFIX = \"spring.datasource.tomcat.\";\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.type=\" + org.apache.tomcat.jdbc.pool.DataSource.class.getName());\n\n\t@BeforeEach\n\tvoid init() {\n\t\tTestPropertyValues.of(PREFIX + \"initialize:false\").applyTo(this.context);\n\t}\n\n\t@Test\n\tvoid testDataSourceExists() {\n\t\tthis.context.register(TomcatDataSourceConfiguration.class);\n\t\tTestPropertyValues.of(PREFIX + \"url:jdbc:h2:mem:testdb\").applyTo(this.context);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(DataSource.class)).isNotNull();\n\t\tassertThat(this.context.getBean(org.apache.tomcat.jdbc.pool.DataSource.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid testDataSourcePropertiesOverridden() throws Exception {\n\t\tthis.context.register(TomcatDataSourceConfiguration.class);\n\t\tTestPropertyValues\n\t\t\t.of(PREFIX + \"url:jdbc:h2:mem:testdb\", PREFIX + \"testWhileIdle:true\", PREFIX + \"testOnBorrow:true\",\n\t\t\t\t\tPREFIX + \"testOnReturn:true\", PREFIX + \"timeBetweenEvictionRunsMillis:10000\",\n\t\t\t\t\tPREFIX + \"minEvictableIdleTimeMillis:12345\", PREFIX + \"maxWait:1234\",\n\t\t\t\t\tPREFIX + \"jdbcInterceptors:SlowQueryReport\", PREFIX + \"validationInterval:9999\")\n\t\t\t.applyTo(this.context);\n\t\tthis.context.refresh();\n\t\torg.apache.tomcat.jdbc.pool.DataSource ds = this.context.getBean(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t\tassertThat(ds.getUrl()).isEqualTo(\"jdbc:h2:mem:testdb\");\n\t\tassertThat(ds.isTestWhileIdle()).isTrue();\n\t\tassertThat(ds.isTestOnBorrow()).isTrue();\n\t\tassertThat(ds.isTestOnReturn()).isTrue();\n\t\tassertThat(ds.getTimeBetweenEvictionRunsMillis()).isEqualTo(10000);\n\t\tassertThat(ds.getMinEvictableIdleTimeMillis()).isEqualTo(12345);\n\t\tassertThat(ds.getMaxWait()).isEqualTo(1234);\n\t\tassertThat(ds.getValidationInterval()).isEqualTo(9999L);\n\t\tassertDataSourceHasInterceptors(ds);\n\t}\n\n\tprivate void assertDataSourceHasInterceptors(DataSourceProxy ds) throws ClassNotFoundException {\n\t\tPoolProperties.InterceptorDefinition[] interceptors = ds.getJdbcInterceptorsAsArray();\n\t\tfor (PoolProperties.InterceptorDefinition interceptor : interceptors) {\n\t\t\tif (SlowQueryReport.class == interceptor.getInterceptorClass()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tfail(\"SlowQueryReport interceptor should have been set.\");\n\t}\n\n\t@Test\n\tvoid testDataSourceDefaultsPreserved() {\n\t\tthis.context.register(TomcatDataSourceConfiguration.class);\n\t\tTestPropertyValues.of(PREFIX + \"url:jdbc:h2:mem:testdb\").applyTo(this.context);\n\t\tthis.context.refresh();\n\t\torg.apache.tomcat.jdbc.pool.DataSource ds = this.context.getBean(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t\tassertThat(ds.getTimeBetweenEvictionRunsMillis()).isEqualTo(5000);\n\t\tassertThat(ds.getMinEvictableIdleTimeMillis()).isEqualTo(60000);\n\t\tassertThat(ds.getMaxWait()).isEqualTo(30000);\n\t\tassertThat(ds.getValidationInterval()).isEqualTo(3000L);\n\t}\n\n\t@Test\n\tvoid usesCustomJdbcConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(JdbcConnectionDetails.class, TestJdbcConnectionDetails::new)\n\t\t\t.withPropertyValues(PREFIX + \"url=jdbc:broken\", PREFIX + \"username=alice\", PREFIX + \"password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesJdbcConnectionDetails.class);\n\t\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\t\tassertThat(dataSource).isInstanceOf(org.apache.tomcat.jdbc.pool.DataSource.class);\n\t\t\t\torg.apache.tomcat.jdbc.pool.DataSource tomcat = (org.apache.tomcat.jdbc.pool.DataSource) dataSource;\n\t\t\t\tassertThat(tomcat.getPoolProperties().getUsername()).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(tomcat.getPoolProperties().getPassword()).isEqualTo(\"password-1\");\n\t\t\t\tassertThat(tomcat.getPoolProperties().getDriverClassName())\n\t\t\t\t\t.isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t\t\t\tassertThat(tomcat.getPoolProperties().getUrl())\n\t\t\t\t\t.isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\t@EnableMBeanExport\n\tstatic class TomcatDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spring.datasource.tomcat\")\n\t\tDataSource dataSource() {\n\t\t\treturn DataSourceBuilder.create().type(org.apache.tomcat.jdbc.pool.DataSource.class).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/TomcatJdbcConnectionDetailsBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport org.apache.tomcat.jdbc.pool.DataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatJdbcConnectionDetailsBeanPostProcessor}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass TomcatJdbcConnectionDetailsBeanPostProcessorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid setUsernamePasswordUrlAndDriverClassName() {\n\t\tDataSource dataSource = new DataSource();\n\t\tdataSource.setUrl(\"will-be-overwritten\");\n\t\tdataSource.setUsername(\"will-be-overwritten\");\n\t\tdataSource.setPassword(\"will-be-overwritten\");\n\t\tdataSource.setDriverClassName(\"will-be-overwritten\");\n\t\tnew TomcatJdbcConnectionDetailsBeanPostProcessor(mock(ObjectProvider.class)).processDataSource(dataSource,\n\t\t\t\tnew TestJdbcConnectionDetails());\n\t\tassertThat(dataSource.getUrl()).isEqualTo(\"jdbc:customdb://customdb.example.com:12345/database-1\");\n\t\tassertThat(dataSource.getUsername()).isEqualTo(\"user-1\");\n\t\tassertThat(dataSource.getPoolProperties().getPassword()).isEqualTo(\"password-1\");\n\t\tassertThat(dataSource.getPoolProperties().getDriverClassName())\n\t\t\t.isEqualTo(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/XADataSourceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\nimport javax.sql.XADataSource;\n\nimport com.ibm.db2.jcc.DB2XADataSource;\nimport org.hsqldb.jdbc.pool.JDBCXADataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.postgresql.xa.PGXADataSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.XADataSourceWrapper;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link XADataSourceAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nclass XADataSourceAutoConfigurationTests {\n\n\t@Test\n\tvoid wrapExistingXaDataSource() {\n\t\tApplicationContext context = createContext(WrapExisting.class);\n\t\tcontext.getBean(DataSource.class);\n\t\tXADataSource source = context.getBean(XADataSource.class);\n\t\tMockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);\n\t\tassertThat(wrapper.getXaDataSource()).isEqualTo(source);\n\t}\n\n\t@Test\n\tvoid createFromUrl() {\n\t\tApplicationContext context = createContext(FromProperties.class, \"spring.datasource.url:jdbc:hsqldb:mem:test\",\n\t\t\t\t\"spring.datasource.username:un\");\n\t\tcontext.getBean(DataSource.class);\n\t\tMockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);\n\t\tJDBCXADataSource dataSource = (JDBCXADataSource) wrapper.getXaDataSource();\n\t\tassertThat(dataSource).isNotNull();\n\t\tassertThat(dataSource.getUrl()).isEqualTo(\"jdbc:hsqldb:mem:test\");\n\t\tassertThat(dataSource.getUser()).isEqualTo(\"un\");\n\t}\n\n\t@Test\n\tvoid createNonEmbeddedFromXAProperties() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(XADataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(FromProperties.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.h2.Driver\", \"org.hsqldb.jdbcDriver\"))\n\t\t\t.withPropertyValues(\"spring.datasource.xa.data-source-class-name:com.ibm.db2.jcc.DB2XADataSource\",\n\t\t\t\t\t\"spring.datasource.xa.properties.user:test\", \"spring.datasource.xa.properties.password:secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tMockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);\n\t\t\t\tXADataSource xaDataSource = wrapper.getXaDataSource();\n\t\t\t\tassertThat(xaDataSource).isInstanceOf(DB2XADataSource.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid createFromClass() throws Exception {\n\t\tApplicationContext context = createContext(FromProperties.class,\n\t\t\t\t\"spring.datasource.xa.data-source-class-name:org.hsqldb.jdbc.pool.JDBCXADataSource\",\n\t\t\t\t\"spring.datasource.xa.properties.login-timeout:123\");\n\t\tcontext.getBean(DataSource.class);\n\t\tMockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);\n\t\tJDBCXADataSource dataSource = (JDBCXADataSource) wrapper.getXaDataSource();\n\t\tassertThat(dataSource).isNotNull();\n\t\tassertThat(dataSource.getLoginTimeout()).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(XADataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(FromProperties.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesJdbcConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tJdbcConnectionDetails connectionDetails = mock(JdbcConnectionDetails.class);\n\t\tgiven(connectionDetails.getUsername()).willReturn(\"user-1\");\n\t\tgiven(connectionDetails.getPassword()).willReturn(\"password-1\");\n\t\tgiven(connectionDetails.getJdbcUrl()).willReturn(\"jdbc:postgresql://postgres.example.com:12345/database-1\");\n\t\tgiven(connectionDetails.getDriverClassName()).willReturn(DatabaseDriver.POSTGRESQL.getDriverClassName());\n\t\tgiven(connectionDetails.getXaDataSourceClassName())\n\t\t\t.willReturn(DatabaseDriver.POSTGRESQL.getXaDataSourceClassName());\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(XADataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(FromProperties.class)\n\t\t\t.withBean(JdbcConnectionDetails.class, () -> connectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JdbcConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesJdbcConnectionDetails.class);\n\t\t\t\tMockXADataSourceWrapper wrapper = context.getBean(MockXADataSourceWrapper.class);\n\t\t\t\tPGXADataSource dataSource = (PGXADataSource) wrapper.getXaDataSource();\n\t\t\t\tassertThat(dataSource).isNotNull();\n\t\t\t\tassertThat(dataSource.getUrl()).startsWith(\"jdbc:postgresql://postgres.example.com:12345/database-1\");\n\t\t\t\tassertThat(dataSource.getUser()).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(dataSource.getPassword()).isEqualTo(\"password-1\");\n\t\t\t});\n\t}\n\n\tprivate ApplicationContext createContext(Class<?> configuration, String... env) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(env).applyTo(context);\n\t\tcontext.register(configuration, XADataSourceAutoConfiguration.class);\n\t\tcontext.refresh();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WrapExisting {\n\n\t\t@Bean\n\t\tMockXADataSourceWrapper wrapper() {\n\t\t\treturn new MockXADataSourceWrapper();\n\t\t}\n\n\t\t@Bean\n\t\tXADataSource xaDataSource() {\n\t\t\treturn mock(XADataSource.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FromProperties {\n\n\t\t@Bean\n\t\tMockXADataSourceWrapper wrapper() {\n\t\t\treturn new MockXADataSourceWrapper();\n\t\t}\n\n\t}\n\n\tstatic class MockXADataSourceWrapper implements XADataSourceWrapper {\n\n\t\tprivate @Nullable XADataSource dataSource;\n\n\t\t@Override\n\t\tpublic DataSource wrapDataSource(XADataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t\t@Nullable XADataSource getXaDataSource() {\n\t\t\treturn this.dataSource;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/health/DataSourceHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure.health;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.HealthContributors;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourcePoolMetadataProvidersConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.health.DataSourceHealthContributorAutoConfiguration.RoutingDataSourceHealthContributor;\nimport org.springframework.boot.jdbc.health.DataSourceHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DataSourceHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Julio Gomez\n * @author Safeer Ansari\n */\nclass DataSourceHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class, DataSourceHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tcontext.getBean(DataSourceHealthIndicator.class);\n\t\t\tassertThat(context).hasSingleBean(DataSourceHealthIndicator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenMultipleDataSourceBeansShouldCreateCompositeIndicator() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, DataSourceConfig.class,\n\t\t\t\t\tNonStandardDataSourceConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(CompositeHealthContributor.class);\n\t\t\t\tCompositeHealthContributor contributor = context.getBean(CompositeHealthContributor.class);\n\t\t\t\tString[] names = contributor.stream().map(HealthContributors.Entry::name).toArray(String[]::new);\n\t\t\t\tassertThat(names).containsExactlyInAnyOrder(\"dataSource\", \"standardDataSource\", \"nonDefaultDataSource\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithRoutingAndEmbeddedDataSourceShouldIncludeRoutingDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, RoutingDataSourceConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tCompositeHealthContributor composite = context.getBean(CompositeHealthContributor.class);\n\t\t\t\tassertThat(composite.getContributor(\"dataSource\")).isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(composite.getContributor(\"routingDataSource\"))\n\t\t\t\t\t.isInstanceOf(RoutingDataSourceHealthContributor.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithProxyBeanPostProcessorRoutingAndEmbeddedDataSourceShouldIncludeRoutingDataSource() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ProxyDataSourceBeanPostProcessor.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tRoutingDataSourceConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tCompositeHealthContributor composite = context.getBean(CompositeHealthContributor.class);\n\t\t\t\tassertThat(composite.getContributor(\"dataSource\")).isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(composite.getContributor(\"routingDataSource\"))\n\t\t\t\t\t.isInstanceOf(RoutingDataSourceHealthContributor.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithRoutingAndEmbeddedDataSourceShouldNotIncludeRoutingDataSourceWhenIgnored() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, RoutingDataSourceConfig.class)\n\t\t\t.withPropertyValues(\"management.health.db.ignore-routing-datasources:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(CompositeHealthContributor.class);\n\t\t\t\tassertThat(context).hasSingleBean(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(RoutingDataSourceHealthContributor.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithProxyBeanPostProcessorAndRoutingAndEmbeddedDataSourceShouldNotIncludeRoutingDataSourceWhenIgnored() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ProxyDataSourceBeanPostProcessor.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tRoutingDataSourceConfig.class)\n\t\t\t.withPropertyValues(\"management.health.db.ignore-routing-datasources:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(CompositeHealthContributor.class);\n\t\t\t\tassertThat(context).hasSingleBean(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(RoutingDataSourceHealthContributor.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithOnlyRoutingDataSourceShouldIncludeRoutingDataSourceWithComposedIndicators() {\n\t\tthis.contextRunner.withUserConfiguration(RoutingDataSourceConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RoutingDataSourceHealthContributor.class);\n\t\t\tRoutingDataSourceHealthContributor routingHealthContributor = context\n\t\t\t\t.getBean(RoutingDataSourceHealthContributor.class);\n\t\t\tassertThat(routingHealthContributor.getContributor(\"one\")).isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\tassertThat(routingHealthContributor.getContributor(\"two\")).isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\tassertThat(routingHealthContributor.iterator()).toIterable()\n\t\t\t\t.extracting(\"name\")\n\t\t\t\t.containsExactlyInAnyOrder(\"one\", \"two\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid runWithProxyBeanPostProcessorAndRoutingDataSourceShouldIncludeRoutingDataSourceWithComposedIndicators() {\n\t\tthis.contextRunner.withUserConfiguration(ProxyDataSourceBeanPostProcessor.class, RoutingDataSourceConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RoutingDataSourceHealthContributor.class);\n\t\t\t\tRoutingDataSourceHealthContributor routingHealthContributor = context\n\t\t\t\t\t.getBean(RoutingDataSourceHealthContributor.class);\n\t\t\t\tassertThat(routingHealthContributor.getContributor(\"one\"))\n\t\t\t\t\t.isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(routingHealthContributor.getContributor(\"two\"))\n\t\t\t\t\t.isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(routingHealthContributor.iterator()).toIterable()\n\t\t\t\t\t.extracting(\"name\")\n\t\t\t\t\t.containsExactlyInAnyOrder(\"one\", \"two\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWithOnlyRoutingDataSourceShouldCrashWhenIgnored() {\n\t\tthis.contextRunner.withUserConfiguration(RoutingDataSourceConfig.class)\n\t\t\t.withPropertyValues(\"management.health.db.ignore-routing-datasources:true\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasRootCauseInstanceOf(IllegalArgumentException.class));\n\t}\n\n\t@Test\n\tvoid runWithProxyBeanPostProcessorAndOnlyRoutingDataSourceShouldCrashWhenIgnored() {\n\t\tthis.contextRunner.withUserConfiguration(ProxyDataSourceBeanPostProcessor.class, RoutingDataSourceConfig.class)\n\t\t\t.withPropertyValues(\"management.health.db.ignore-routing-datasources:true\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasRootCauseInstanceOf(IllegalArgumentException.class));\n\t}\n\n\t@Test\n\tvoid runWithValidationQueryPropertyShouldUseCustomQuery() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(DataSourceConfig.class, DataSourcePoolMetadataProvidersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.test.validation-query:SELECT from FOOBAR\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DataSourceHealthIndicator.class);\n\t\t\t\tDataSourceHealthIndicator indicator = context.getBean(DataSourceHealthIndicator.class);\n\t\t\t\tassertThat(indicator.getQuery()).isEqualTo(\"SELECT from FOOBAR\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"management.health.db.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DataSourceHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(CompositeHealthContributor.class));\n\t}\n\n\t@Test\n\tvoid runWhenDataSourceHasNullRoutingKeyShouldProduceUnnamedComposedIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(NullKeyRoutingDataSourceConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RoutingDataSourceHealthContributor.class);\n\t\t\tRoutingDataSourceHealthContributor routingHealthContributor = context\n\t\t\t\t.getBean(RoutingDataSourceHealthContributor.class);\n\t\t\tassertThat(routingHealthContributor.getContributor(\"unnamed\"))\n\t\t\t\t.isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\tassertThat(routingHealthContributor.getContributor(\"one\")).isInstanceOf(DataSourceHealthIndicator.class);\n\t\t\tassertThat(routingHealthContributor.iterator()).toIterable()\n\t\t\t\t.extracting(\"name\")\n\t\t\t\t.containsExactlyInAnyOrder(\"unnamed\", \"one\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid prototypeDataSourceIsIgnored() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, PrototypeDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(CompositeHealthContributor.class);\n\t\t\t\tassertThat(context.getBeansOfType(DataSourceHealthIndicator.class)).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class DataSourceConfig {\n\n\t\t@Bean\n\t\t@ConfigurationProperties(\"spring.datasource.test\")\n\t\tDataSource standardDataSource() {\n\t\t\treturn DataSourceBuilder.create()\n\t\t\t\t.type(org.apache.tomcat.jdbc.pool.DataSource.class)\n\t\t\t\t.driverClassName(\"org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t\t.url(\"jdbc:hsqldb:mem:test\")\n\t\t\t\t.username(\"sa\")\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties\n\tstatic class NonStandardDataSourceConfig {\n\n\t\t@Bean(defaultCandidate = false)\n\t\t@ConfigurationProperties(\"spring.datasource.non-default\")\n\t\tDataSource nonDefaultDataSource() {\n\t\t\treturn DataSourceBuilder.create()\n\t\t\t\t.type(org.apache.tomcat.jdbc.pool.DataSource.class)\n\t\t\t\t.driverClassName(\"org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t\t.url(\"jdbc:hsqldb:mem:non-default\")\n\t\t\t\t.username(\"sa\")\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\t@ConfigurationProperties(\"spring.datasource.non-autowire\")\n\t\tDataSource nonAutowireDataSource() {\n\t\t\treturn DataSourceBuilder.create()\n\t\t\t\t.type(org.apache.tomcat.jdbc.pool.DataSource.class)\n\t\t\t\t.driverClassName(\"org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t\t.url(\"jdbc:hsqldb:mem:non-autowire\")\n\t\t\t\t.username(\"sa\")\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RoutingDataSourceConfig {\n\n\t\t@Bean\n\t\tAbstractRoutingDataSource routingDataSource() throws SQLException {\n\t\t\tMap<Object, DataSource> dataSources = new HashMap<>();\n\t\t\tdataSources.put(\"one\", mock(DataSource.class));\n\t\t\tdataSources.put(\"two\", mock(DataSource.class));\n\t\t\tAbstractRoutingDataSource routingDataSource = mock(AbstractRoutingDataSource.class);\n\t\t\tgiven(routingDataSource.isWrapperFor(AbstractRoutingDataSource.class)).willReturn(true);\n\t\t\tgiven(routingDataSource.unwrap(AbstractRoutingDataSource.class)).willReturn(routingDataSource);\n\t\t\tgiven(routingDataSource.getResolvedDataSources()).willReturn(dataSources);\n\t\t\treturn routingDataSource;\n\t\t}\n\n\t}\n\n\tstatic class ProxyDataSourceBeanPostProcessor implements BeanPostProcessor {\n\n\t\t@Override\n\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tif (bean instanceof DataSource dataSource) {\n\t\t\t\treturn proxyDataSource(dataSource);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate static DataSource proxyDataSource(DataSource dataSource) {\n\t\t\ttry {\n\t\t\t\tDataSource mock = mock(DataSource.class);\n\t\t\t\tgiven(mock.isWrapperFor(AbstractRoutingDataSource.class))\n\t\t\t\t\t.willReturn(dataSource instanceof AbstractRoutingDataSource);\n\t\t\t\tgiven(mock.unwrap(AbstractRoutingDataSource.class)).willAnswer((invocation) -> dataSource);\n\t\t\t\treturn mock;\n\t\t\t}\n\t\t\tcatch (SQLException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NullKeyRoutingDataSourceConfig {\n\n\t\t@Bean\n\t\tAbstractRoutingDataSource routingDataSource() throws Exception {\n\t\t\tMap<Object, DataSource> dataSources = new HashMap<>();\n\t\t\tdataSources.put(null, mock(DataSource.class));\n\t\t\tdataSources.put(\"one\", mock(DataSource.class));\n\t\t\tAbstractRoutingDataSource routingDataSource = mock(AbstractRoutingDataSource.class);\n\t\t\tgiven(routingDataSource.isWrapperFor(AbstractRoutingDataSource.class)).willReturn(true);\n\t\t\tgiven(routingDataSource.unwrap(AbstractRoutingDataSource.class)).willReturn(routingDataSource);\n\t\t\tgiven(routingDataSource.getResolvedDataSources()).willReturn(dataSources);\n\t\t\treturn routingDataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrototypeDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@Scope(BeanDefinition.SCOPE_PROTOTYPE)\n\t\tDataSource dataSourcePrototype(String username, String password) {\n\t\t\treturn createHikariDataSource(username, password);\n\t\t}\n\n\t\tprivate HikariDataSource createHikariDataSource(String username, String password) {\n\t\t\tString url = \"jdbc:hsqldb:mem:test-\" + UUID.randomUUID();\n\t\t\tHikariDataSource hikariDataSource = DataSourceBuilder.create()\n\t\t\t\t.url(url)\n\t\t\t\t.type(HikariDataSource.class)\n\t\t\t\t.username(username)\n\t\t\t\t.password(password)\n\t\t\t\t.build();\n\t\t\treturn hikariDataSource;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/autoconfigure/metrics/DataSourcePoolMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.autoconfigure.metrics;\n\nimport java.sql.SQLException;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.PriorityOrdered;\nimport org.springframework.jdbc.datasource.DelegatingDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DataSourcePoolMetricsAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Tommy Ludwig\n * @author Yanming Zhou\n */\nclass DataSourcePoolMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\",\n\t\t\t\t\"management.metrics.use-global-registry=false\")\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, DataSourcePoolMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguredDataSourceIsInstrumented() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(DataSource.class).getConnection().getMetaData();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"jdbc.connections.max\").tags(\"name\", \"dataSource\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid dataSourceInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.enable.jdbc=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(DataSource.class).getConnection().getMetaData();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jdbc.connections.max\").tags(\"name\", \"dataSource\").meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allDataSourcesCanBeInstrumented() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TwoDataSourcesConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"nonDefaultDataSource\", DataSource.class).getConnection().getMetaData();\n\t\t\t\tcontext.getBean(\"nonAutowireDataSource\", DataSource.class).getConnection().getMetaData();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jdbc.connections.max\").meters()).map((meter) -> meter.getId().getTag(\"name\"))\n\t\t\t\t\t.containsOnly(\"dataSource\", \"nonDefault\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allDataSourcesCanBeInstrumentedWithLazyInitialization() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withInitializer(\n\t\t\t\t\t(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))\n\t\t\t.withUserConfiguration(TwoDataSourcesConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"nonDefaultDataSource\", DataSource.class).getConnection().getMetaData();\n\t\t\t\tcontext.getBean(\"nonAutowireDataSource\", DataSource.class).getConnection().getMetaData();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jdbc.connections.max\").meters()).map((meter) -> meter.getId().getTag(\"name\"))\n\t\t\t\t\t.containsOnly(\"dataSource\", \"nonDefault\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredHikariDataSourceIsInstrumented() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"hikaricp.connections\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredHikariDataSourceIsInstrumentedWhenUsingDataSourceInitialization() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.sql.init.schema:db/create-custom-schema.sql\")\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceInitializationAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"hikaricp.connections\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariCanBeInstrumentedAfterThePoolHasBeenSealed() {\n\t\tthis.contextRunner.withUserConfiguration(HikariSealingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tcontext.getBean(DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hikaricp.connections\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariDataSourceInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.enable.hikaricp=false\")\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hikaricp.connections\").meter()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allHikariDataSourcesCanBeInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleHikariDataSourcesConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"standardDataSource\", DataSource.class).getConnection();\n\t\t\t\tcontext.getBean(\"nonDefault\", DataSource.class).getConnection();\n\t\t\t\tcontext.getBean(\"nonAutowire\", DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hikaricp.connections\").meters()).map((meter) -> meter.getId().getTag(\"pool\"))\n\t\t\t\t\t.containsOnly(\"standardDataSource\", \"nonDefault\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid someHikariDataSourcesCanBeInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(MixedDataSourcesConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"firstDataSource\", DataSource.class).getConnection();\n\t\t\t\tcontext.getBean(\"secondOne\", DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.get(\"hikaricp.connections\").meter().getId().getTags())\n\t\t\t\t\t.containsExactly(Tag.of(\"pool\", \"firstDataSource\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allHikariDataSourcesCanBeInstrumentedWhenUsingLazyInitialization() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleHikariDataSourcesConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withInitializer(\n\t\t\t\t\t(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"standardDataSource\", DataSource.class).getConnection();\n\t\t\t\tcontext.getBean(\"nonDefault\", DataSource.class).getConnection();\n\t\t\t\tcontext.getBean(\"nonAutowire\", DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"hikaricp.connections\").meters()).map((meter) -> meter.getId().getTag(\"pool\"))\n\t\t\t\t\t.containsOnly(\"standardDataSource\", \"nonDefault\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariProxiedDataSourceCanBeInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(ProxiedHikariDataSourcesConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"proxiedDataSource\", DataSource.class).getConnection();\n\t\t\t\tcontext.getBean(\"delegateDataSource\", DataSource.class).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.get(\"hikaricp.connections\").tags(\"pool\", \"firstDataSource\").meter();\n\t\t\t\tregistry.get(\"hikaricp.connections\").tags(\"pool\", \"secondOne\").meter();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hikariDataSourceIsInstrumentedWithoutMetadataProvider() {\n\t\tthis.contextRunner.withUserConfiguration(OneHikariDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(DataSourcePoolMetadataProvider.class);\n\t\t\tcontext.getBean(\"hikariDataSource\", DataSource.class).getConnection();\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.get(\"hikaricp.connections\").meter().getId().getTags())\n\t\t\t\t.containsExactly(Tag.of(\"pool\", \"hikariDataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid prototypeDataSourceIsIgnored() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(OneHikariDataSourceConfiguration.class, PrototypeDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(\"hikariDataSource\", DataSource.class).getConnection();\n\t\t\t\t((DataSource) context.getBean(\"prototypeDataSource\", \"\", \"\")).getConnection();\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.get(\"hikaricp.connections\").meter().getId().getTags())\n\t\t\t\t\t.containsExactly(Tag.of(\"pool\", \"hikariDataSource\"));\n\t\t\t});\n\t}\n\n\tprivate static HikariDataSource createHikariDataSource(String poolName) {\n\t\tString url = \"jdbc:hsqldb:mem:test-\" + UUID.randomUUID();\n\t\tHikariDataSource hikariDataSource = DataSourceBuilder.create().url(url).type(HikariDataSource.class).build();\n\t\thikariDataSource.setPoolName(poolName);\n\t\treturn hikariDataSource;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TwoDataSourcesConfiguration {\n\n\t\t@Bean(defaultCandidate = false)\n\t\tDataSource nonDefaultDataSource() {\n\t\t\treturn createDataSource();\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tDataSource nonAutowireDataSource() {\n\t\t\treturn createDataSource();\n\t\t}\n\n\t\tprivate DataSource createDataSource() {\n\t\t\tString url = \"jdbc:hsqldb:mem:test-\" + UUID.randomUUID();\n\t\t\treturn DataSourceBuilder.create().url(url).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleHikariDataSourcesConfiguration {\n\n\t\t@Bean\n\t\tDataSource standardDataSource() {\n\t\t\treturn createHikariDataSource(\"standardDataSource\");\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tDataSource nonDefault() {\n\t\t\treturn createHikariDataSource(\"nonDefault\");\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tDataSource nonAutowire() {\n\t\t\treturn createHikariDataSource(\"nonAutowire\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ProxiedHikariDataSourcesConfiguration {\n\n\t\t@Bean\n\t\tDataSource proxiedDataSource() {\n\t\t\treturn (DataSource) new ProxyFactory(createHikariDataSource(\"firstDataSource\")).getProxy();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource delegateDataSource() {\n\t\t\treturn new DelegatingDataSource(createHikariDataSource(\"secondOne\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OneHikariDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource hikariDataSource() {\n\t\t\treturn createHikariDataSource(\"hikariDataSource\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MixedDataSourcesConfiguration {\n\n\t\t@Bean\n\t\tDataSource firstDataSource() {\n\t\t\treturn createHikariDataSource(\"firstDataSource\");\n\t\t}\n\n\t\t@Bean\n\t\tDataSource secondOne() {\n\t\t\treturn createTomcatDataSource();\n\t\t}\n\n\t\tprivate HikariDataSource createHikariDataSource(String poolName) {\n\t\t\tString url = \"jdbc:hsqldb:mem:test-\" + UUID.randomUUID();\n\t\t\tHikariDataSource hikariDataSource = DataSourceBuilder.create()\n\t\t\t\t.url(url)\n\t\t\t\t.type(HikariDataSource.class)\n\t\t\t\t.build();\n\t\t\thikariDataSource.setPoolName(poolName);\n\t\t\treturn hikariDataSource;\n\t\t}\n\n\t\tprivate org.apache.tomcat.jdbc.pool.DataSource createTomcatDataSource() {\n\t\t\tString url = \"jdbc:hsqldb:mem:test-\" + UUID.randomUUID();\n\t\t\treturn DataSourceBuilder.create().url(url).type(org.apache.tomcat.jdbc.pool.DataSource.class).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrototypeDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@Scope(BeanDefinition.SCOPE_PROTOTYPE)\n\t\tDataSource prototypeDataSource(String username, String password) {\n\t\t\treturn createHikariDataSource(username, password);\n\t\t}\n\n\t\tprivate HikariDataSource createHikariDataSource(String username, String password) {\n\t\t\tString url = \"jdbc:hsqldb:mem:test-\" + UUID.randomUUID();\n\t\t\tHikariDataSource hikariDataSource = DataSourceBuilder.create()\n\t\t\t\t.url(url)\n\t\t\t\t.type(HikariDataSource.class)\n\t\t\t\t.username(username)\n\t\t\t\t.password(password)\n\t\t\t\t.build();\n\t\t\treturn hikariDataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HikariSealingConfiguration {\n\n\t\t@Bean\n\t\tstatic HikariSealer hikariSealer() {\n\t\t\treturn new HikariSealer();\n\t\t}\n\n\t\tstatic class HikariSealer implements BeanPostProcessor, PriorityOrdered {\n\n\t\t\t@Override\n\t\t\tpublic int getOrder() {\n\t\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\t\tif (bean instanceof HikariDataSource dataSource) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tdataSource.getConnection().close();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (SQLException ex) {\n\t\t\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn bean;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/ClickHouseEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ClickHouseEnvironment}.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseEnvironmentTests {\n\n\t@Test\n\tvoid createWhenNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new ClickHouseEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No ClickHouse password found\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPassword() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"ALLOW_EMPTY_PASSWORD\", \"true\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPasswordIsYes() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"ALLOW_EMPTY_PASSWORD\", \"yes\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoUser() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"default\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasUser() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(\n\t\t\t\tMap.of(\"CLICKHOUSE_USER\", \"me\", \"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoDatabase() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"default\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasDatabase() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(\n\t\t\t\tMap.of(\"CLICKHOUSE_DB\", \"db\", \"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/JdbcUrlBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.ConnectionPorts;\nimport org.springframework.boot.docker.compose.core.RunningService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JdbcUrlBuilder}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass JdbcUrlBuilderTests {\n\n\tprivate final JdbcUrlBuilder builder = new JdbcUrlBuilder(\"mydb\", 1234);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenDriverProtocolIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new JdbcUrlBuilder(null, 123))\n\t\t\t.withMessage(\"'driverProtocol' must not be null\");\n\t}\n\n\t@Test\n\tvoid buildBuildsUrlForService() {\n\t\tRunningService service = mockService(456);\n\t\tString url = this.builder.build(service);\n\t\tassertThat(url).isEqualTo(\"jdbc:mydb://myhost:456\");\n\t}\n\n\t@Test\n\tvoid buildBuildsUrlForServiceAndDatabase() {\n\t\tRunningService service = mockService(456);\n\t\tString url = this.builder.build(service, \"mydb\");\n\t\tassertThat(url).isEqualTo(\"jdbc:mydb://myhost:456/mydb\");\n\t}\n\n\t@Test\n\tvoid buildWhenHasParamsLabelBuildsUrl() {\n\t\tRunningService service = mockService(456, Map.of(\"org.springframework.boot.jdbc.parameters\", \"foo=bar\"));\n\t\tString url = this.builder.build(service, \"mydb\");\n\t\tassertThat(url).isEqualTo(\"jdbc:mydb://myhost:456/mydb?foo=bar\");\n\t}\n\n\t@Test\n\tvoid buildWithCustomAppendParametersWhenHasParamsLabelBuildsUrl() {\n\t\tRunningService service = mockService(456, Map.of(\"org.springframework.boot.jdbc.parameters\", \"foo=bar\"));\n\t\tString url = new JdbcUrlBuilder(\"mydb\", 1234) {\n\n\t\t\t@Override\n\t\t\tprotected void appendParameters(StringBuilder url, String parameters) {\n\t\t\t\turl.append(\";\").append(parameters);\n\t\t\t}\n\n\t\t}.build(service, \"mydb\");\n\t\tassertThat(url).isEqualTo(\"jdbc:mydb://myhost:456/mydb;foo=bar\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid buildWhenServiceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(null, \"mydb\"))\n\t\t\t.withMessage(\"'service' must not be null\");\n\t}\n\n\tprivate RunningService mockService(int mappedPort) {\n\t\treturn mockService(mappedPort, Collections.emptyMap());\n\t}\n\n\tprivate RunningService mockService(int mappedPort, Map<String, String> labels) {\n\t\tRunningService service = mock(RunningService.class);\n\t\tConnectionPorts ports = mock(ConnectionPorts.class);\n\t\tgiven(ports.get(1234)).willReturn(mappedPort);\n\t\tgiven(service.host()).willReturn(\"myhost\");\n\t\tgiven(service.ports()).willReturn(ports);\n\t\tgiven(service.labels()).willReturn(labels);\n\t\treturn service;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/MariaDbEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MariaDbEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Jinseong Hwang\n * @author Scott Frederick\n */\nclass MariaDbEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasMariadbRandomRootPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MARIADB_RANDOM_ROOT_PASSWORD\", \"true\")))\n\t\t\t.withMessage(\"MARIADB_RANDOM_ROOT_PASSWORD is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasMysqlRandomRootPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MYSQL_RANDOM_ROOT_PASSWORD\", \"true\")))\n\t\t\t.withMessage(\"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasMariadbRootPasswordHashThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MARIADB_ROOT_PASSWORD_HASH\", \"0FF\")))\n\t\t\t.withMessage(\"MARIADB_ROOT_PASSWORD_HASH is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MariaDbEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No MariaDB password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoDatabaseThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MARIADB_PASSWORD\", \"secret\")))\n\t\t\t.withMessage(\"No MARIADB_DATABASE defined\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMariadbUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_USER\", \"myself\", \"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMysqlUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_USER\", \"myself\", \"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMariadbUserAndMysqlUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(Map.of(\"MARIADB_USER\", \"myself\", \"MYSQL_USER\", \"me\",\n\t\t\t\t\"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMariadbUserOrMysqlUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"root\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMariadbPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlRootPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ROOT_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMariadbPasswordAndMysqlPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MYSQL_PASSWORD\", \"donttell\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMariadbPasswordAndMysqlRootPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MYSQL_ROOT_PASSWORD\", \"donttell\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndMariadbAllowEmptyPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndMysqlAllowEmptyPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMariadbDatabase() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMysqlDatabase() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMariadbAndMysqlDatabase() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\", \"MYSQL_DATABASE\", \"otherdb\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/MySqlEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MySqlEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Jinseong Hwang\n * @author Scott Frederick\n */\nclass MySqlEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasMysqlRandomRootPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MySqlEnvironment(Map.of(\"MYSQL_RANDOM_ROOT_PASSWORD\", \"true\")))\n\t\t\t.withMessage(\"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MySqlEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No MySQL password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoDatabaseThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MySqlEnvironment(Map.of(\"MYSQL_PASSWORD\", \"secret\")))\n\t\t\t.withMessage(\"No MYSQL_DATABASE defined\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMysqlUser() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_USER\", \"myself\", \"MYSQL_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMysqlUser() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(Map.of(\"MYSQL_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"root\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(Map.of(\"MYSQL_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlRootPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ROOT_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndMysqlAllowEmptyPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMysqlDatabase() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/OracleEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link OracleEnvironment}.\n *\n * @author Andy Wilkinson\n */\nclass OracleEnvironmentTests {\n\n\t@Test\n\tvoid getUsernameWhenHasAppUser() {\n\t\tOracleEnvironment environment = new OracleEnvironment(\n\t\t\t\tMap.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getUsername()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoAppUser() {\n\t\tOracleEnvironment environment = new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getUsername()).isEqualTo(\"system\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasAppPassword() {\n\t\tOracleEnvironment environment = new OracleEnvironment(\n\t\t\t\tMap.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasOraclePassword() {\n\t\tOracleEnvironment environment = new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid createWhenRandomPasswordAndAppPasswordDoesNotThrow() {\n\t\tassertThatNoException().isThrownBy(() -> new OracleEnvironment(\n\t\t\t\tMap.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"secret\", \"ORACLE_RANDOM_PASSWORD\", \"true\"),\n\t\t\t\t\"defaultDb\"));\n\t}\n\n\t@Test\n\tvoid createWhenRandomPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"ORACLE_RANDOM_PASSWORD\", \"true\"), \"defaultDb\"))\n\t\t\t.withMessage(\"ORACLE_RANDOM_PASSWORD is not supported without APP_USER and APP_USER_PASSWORD\");\n\t}\n\n\t@Test\n\tvoid createWhenAppUserAndNoAppPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"APP_USER\", \"alice\"), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle app password found\");\n\t}\n\n\t@Test\n\tvoid createWhenAppUserAndEmptyAppPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"\"), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle app password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new OracleEnvironment(Collections.emptyMap(), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasEmptyPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"\"), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle password found\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasNoOracleDatabase() {\n\t\tOracleEnvironment environment = new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"defaultDb\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasOracleDatabase() {\n\t\tOracleEnvironment environment = new OracleEnvironment(\n\t\t\t\tMap.of(\"ORACLE_PASSWORD\", \"secret\", \"ORACLE_DATABASE\", \"db\"), \"defaultDb\");\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/PostgresEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link PostgresEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Sidmar Theodoro\n * @author He Zean\n */\nclass PostgresEnvironmentTests {\n\n\t@Test\n\tvoid createWhenNoPostgresPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new PostgresEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No PostgreSQL password found\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoPostgresqlUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRES_USER\", \"me\", \"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasPostgresqlUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USER\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasPostgresqlUsername() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USERNAME\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPostgresPassword() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPostgresqlPassword() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasTrustHostAuthMethod() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_HOST_AUTH_METHOD\", \"trust\"));\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"ALLOW_EMPTY_PASSWORD\", \"yes\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresDbOrPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresqlDbOrPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresDbAndPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRES_USER\", \"me\", \"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresqlDbAndPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USER\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresqlDatabaseAndPostgresqlUsername() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USERNAME\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasPostgresDb() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRES_DB\", \"db\", \"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasPostgresqlDb() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_DB\", \"db\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasPostgresqlDatabase() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_DATABASE\", \"db\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/PostgresJdbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.ConnectionPorts;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for\n * {@link PostgresJdbcDockerComposeConnectionDetailsFactory.PostgresJdbcDockerComposeConnectionDetails}.\n *\n * @author Dmytro Nosan\n */\nclass PostgresJdbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests {\n\n\tprivate final RunningService service = mock(RunningService.class);\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final Map<String, String> labels = new LinkedHashMap<>();\n\n\tPostgresJdbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests() {\n\t\tgiven(this.service.env())\n\t\t\t.willReturn(Map.of(\"POSTGRES_USER\", \"user\", \"POSTGRES_PASSWORD\", \"password\", \"POSTGRES_DB\", \"database\"));\n\t\tgiven(this.service.labels()).willReturn(this.labels);\n\t\tConnectionPorts connectionPorts = mock(ConnectionPorts.class);\n\t\tgiven(this.service.ports()).willReturn(connectionPorts);\n\t\tgiven(this.service.host()).willReturn(\"localhost\");\n\t\tgiven(connectionPorts.get(5432)).willReturn(30001);\n\t}\n\n\t@Test\n\tvoid createConnectionDetails() {\n\t\tJdbcConnectionDetails connectionDetails = getConnectionDetails();\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getJdbcUrl()).endsWith(\"/database\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsWithLabels() {\n\t\tthis.labels.put(\"org.springframework.boot.jdbc.parameters\", \"connectTimeout=30&ApplicationName=spring-boot\");\n\t\tJdbcConnectionDetails connectionDetails = getConnectionDetails();\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getJdbcUrl()).endsWith(\"?connectTimeout=30&ApplicationName=spring-boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsWithApplicationNameLabelTakesPrecedence() {\n\t\tthis.labels.put(\"org.springframework.boot.jdbc.parameters\", \"ApplicationName=spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"my-app\");\n\t\tJdbcConnectionDetails connectionDetails = getConnectionDetails();\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getJdbcUrl()).endsWith(\"?ApplicationName=spring-boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsWithSpringApplicationName() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring boot\");\n\t\tJdbcConnectionDetails connectionDetails = getConnectionDetails();\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getJdbcUrl()).endsWith(\"?ApplicationName=spring+boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsAppendSpringApplicationName() {\n\t\tthis.labels.put(\"org.springframework.boot.jdbc.parameters\", \"connectTimeout=30\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring boot\");\n\t\tJdbcConnectionDetails connectionDetails = getConnectionDetails();\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getJdbcUrl()).endsWith(\"?connectTimeout=30&ApplicationName=spring+boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsAppendSpringApplicationNameParametersEndedWithAmpersand() {\n\t\tthis.labels.put(\"org.springframework.boot.jdbc.parameters\", \"connectTimeout=30&\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring boot\");\n\t\tJdbcConnectionDetails connectionDetails = getConnectionDetails();\n\t\tassertConnectionDetails(connectionDetails);\n\t\tassertThat(connectionDetails.getJdbcUrl()).endsWith(\"?connectTimeout=30&ApplicationName=spring+boot\");\n\n\t}\n\n\tprivate void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"password\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:postgresql://localhost:30001/database\");\n\t\tassertThat(connectionDetails.getDriverClassName()).isEqualTo(\"org.postgresql.Driver\");\n\t}\n\n\tprivate JdbcConnectionDetails getConnectionDetails() {\n\t\treturn new PostgresJdbcDockerComposeConnectionDetailsFactory.PostgresJdbcDockerComposeConnectionDetails(\n\t\t\t\tthis.service, this.environment);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/docker/compose/SqlServerEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SqlServerEnvironment}.\n *\n * @author Andy Wilkinson\n */\nclass SqlServerEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new SqlServerEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No MSSQL password found\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMsSqlUser() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(Map.of(\"MSSQL_SA_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"SA\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMsSqlSaPassword() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(Map.of(\"MSSQL_SA_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasSaPassword() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(Map.of(\"SA_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMsSqlSaPasswordAndSaPasswordPrefersMsSqlSaPassword() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(\n\t\t\t\tMap.of(\"MSSQL_SA_PASSWORD\", \"secret\", \"SA_PASSWORD\", \"not used\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/health/DataSourceHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.health;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SingleConnectionDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link DataSourceHealthIndicator}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\nclass DataSourceHealthIndicatorTests {\n\n\tprivate final DataSourceHealthIndicator indicator = new DataSourceHealthIndicator();\n\n\tprivate SingleConnectionDataSource dataSource;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tEmbeddedDatabaseConnection db = EmbeddedDatabaseConnection.HSQLDB;\n\t\tthis.dataSource = new SingleConnectionDataSource(db.getUrl(\"testdb\") + \";shutdown=true\", \"sa\", \"\", false);\n\t\tString driverClassName = db.getDriverClassName();\n\t\tassertThat(driverClassName).isNotNull();\n\t\tthis.dataSource.setDriverClassName(driverClassName);\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.dataSource != null) {\n\t\t\tthis.dataSource.destroy();\n\t\t}\n\t}\n\n\t@Test\n\tvoid healthIndicatorWithDefaultSettings() {\n\t\tthis.indicator.setDataSource(this.dataSource);\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"database\", \"HSQL Database Engine\"),\n\t\t\t\tentry(\"validationQuery\", \"isValid()\"));\n\t}\n\n\t@Test\n\tvoid healthIndicatorWithCustomValidationQuery() {\n\t\tString customValidationQuery = \"SELECT COUNT(*) from FOO\";\n\t\tnew JdbcTemplate(this.dataSource).execute(\"CREATE TABLE FOO (id INTEGER IDENTITY PRIMARY KEY)\");\n\t\tthis.indicator.setDataSource(this.dataSource);\n\t\tthis.indicator.setQuery(customValidationQuery);\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"database\", \"HSQL Database Engine\"), entry(\"result\", 0L),\n\t\t\t\tentry(\"validationQuery\", customValidationQuery));\n\t}\n\n\t@Test\n\tvoid healthIndicatorWithInvalidValidationQuery() {\n\t\tString invalidValidationQuery = \"SELECT COUNT(*) from BAR\";\n\t\tthis.indicator.setDataSource(this.dataSource);\n\t\tthis.indicator.setQuery(invalidValidationQuery);\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).contains(entry(\"database\", \"HSQL Database Engine\"),\n\t\t\t\tentry(\"validationQuery\", invalidValidationQuery));\n\t\tassertThat(health.getDetails()).containsOnlyKeys(\"database\", \"error\", \"validationQuery\");\n\t}\n\n\t@Test\n\tvoid healthIndicatorCloseConnection() throws Exception {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.getMetaData()).willReturn(this.dataSource.getConnection().getMetaData());\n\t\tgiven(dataSource.getConnection()).willReturn(connection);\n\t\tthis.indicator.setDataSource(dataSource);\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getDetails()).containsKey(\"database\");\n\t\tthen(connection).should(times(2)).close();\n\t}\n\n\t@Test\n\tvoid healthIndicatorWithConnectionValidationFailure() throws SQLException {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.isValid(0)).willReturn(false);\n\t\tgiven(connection.getMetaData()).willReturn(this.dataSource.getConnection().getMetaData());\n\t\tgiven(dataSource.getConnection()).willReturn(connection);\n\t\tthis.indicator.setDataSource(dataSource);\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsOnly(entry(\"database\", \"HSQL Database Engine\"),\n\t\t\t\tentry(\"validationQuery\", \"isValid()\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/init/DataSourceScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport java.util.Collections;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializerTests;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.jdbc.datasource.init.ScriptStatementFailedException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link DataSourceScriptDatabaseInitializer}.\n *\n * @author Andy Wilkinson\n */\nclass DataSourceScriptDatabaseInitializerTests\n\t\textends AbstractScriptDatabaseInitializerTests<DataSourceScriptDatabaseInitializer> {\n\n\tprivate final HikariDataSource embeddedDataSource = DataSourceBuilder.create()\n\t\t.type(HikariDataSource.class)\n\t\t.url(\"jdbc:h2:mem:\" + UUID.randomUUID())\n\t\t.build();\n\n\tprivate final HikariDataSource standaloneDataSource = DataSourceBuilder.create()\n\t\t.type(HikariDataSource.class)\n\t\t.url(\"jdbc:h2:file:\"\n\t\t\t\t+ new BuildOutput(DataSourceScriptDatabaseInitializerTests.class).getRootLocation().getAbsolutePath()\n\t\t\t\t+ \"/\" + UUID.randomUUID())\n\t\t.build();\n\n\t@AfterEach\n\tvoid closeDataSource() {\n\t\tthis.embeddedDataSource.close();\n\t\tthis.standaloneDataSource.close();\n\t}\n\n\t@Test\n\tvoid whenDatabaseIsInaccessibleThenItIsAssumedNotToBeEmbedded() {\n\t\tDataSourceScriptDatabaseInitializer initializer = new DataSourceScriptDatabaseInitializer(\n\t\t\t\tnew HikariDataSource(), new DatabaseInitializationSettings());\n\t\tassertThat(initializer.isEmbeddedDatabase()).isFalse();\n\t}\n\n\t@Test\n\t@WithDataSqlResource\n\tvoid whenCustomizeIsOverriddenThenDatabasePopulatorIsConfiguredAccordingly() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setContinueOnError(true);\n\t\tsettings.setDataLocations(Collections.singletonList(\"data.sql\"));\n\t\tDataSourceScriptDatabaseInitializer initializer = new DataSourceScriptDatabaseInitializer(\n\t\t\t\tthis.embeddedDataSource, settings) {\n\t\t\t@Override\n\t\t\tprotected void customize(ResourceDatabasePopulator populator) {\n\t\t\t\tassertThat(populator).hasFieldOrPropertyWithValue(\"continueOnError\", true);\n\t\t\t\tpopulator.setContinueOnError(false);\n\t\t\t}\n\t\t};\n\t\tassertThatExceptionOfType(ScriptStatementFailedException.class).isThrownBy(initializer::initializeDatabase);\n\t}\n\n\t@Override\n\tprotected DataSourceScriptDatabaseInitializer createEmbeddedDatabaseInitializer(\n\t\t\tDatabaseInitializationSettings settings) {\n\t\treturn new DataSourceScriptDatabaseInitializer(this.embeddedDataSource, settings);\n\t}\n\n\t@Override\n\tprotected DataSourceScriptDatabaseInitializer createStandaloneDatabaseInitializer(\n\t\t\tDatabaseInitializationSettings settings) {\n\t\treturn new DataSourceScriptDatabaseInitializer(this.standaloneDataSource, settings);\n\t}\n\n\t@Override\n\tprotected int numberOfEmbeddedRows(String sql) {\n\t\treturn numberOfRows(this.embeddedDataSource, sql);\n\t}\n\n\t@Override\n\tprotected int numberOfStandaloneRows(String sql) {\n\t\treturn numberOfRows(this.standaloneDataSource, sql);\n\t}\n\n\tprivate int numberOfRows(DataSource dataSource, String sql) {\n\t\tInteger rows = new JdbcTemplate(dataSource).queryForObject(sql, Integer.class);\n\t\tassertThat(rows).isNotNull();\n\t\treturn rows;\n\t}\n\n\t@Override\n\tprotected void assertDatabaseAccessed(boolean accessed, DataSourceScriptDatabaseInitializer initializer) {\n\t\tassertThat(((HikariDataSource) initializer.getDataSource()).isRunning()).isEqualTo(accessed);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/init/PlatformPlaceholderDatabaseDriverResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.init;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PlatformPlaceholderDatabaseDriverResolver}\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass PlatformPlaceholderDatabaseDriverResolverTests {\n\n\t@Test\n\tvoid resolveAllWithPlatformWhenThereAreNoValuesShouldReturnEmptyList() {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(\"test\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid resolveAllWithPlatformWhenValueDoesNotContainPlaceholderShouldReturnValueUnchanged() {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(\"test\", \"schema.sql\"))\n\t\t\t.containsExactly(\"schema.sql\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithPlatformWhenValuesContainPlaceholdersShouldReturnValuesWithPlaceholdersReplaced() {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(\"postgresql\", \"schema.sql\",\n\t\t\t\t\"schema-@@platform@@.sql\", \"data-@@platform@@.sql\"))\n\t\t\t.containsExactly(\"schema.sql\", \"schema-postgresql.sql\", \"data-postgresql.sql\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenThereAreNoValuesShouldReturnEmptyList() {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(mock(DataSource.class))).isEmpty();\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenValueDoesNotContainPlaceholderShouldReturnValueUnchanged() {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(mock(DataSource.class), \"schema.sql\"))\n\t\t\t.containsExactly(\"schema.sql\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenValueDoesNotContainPlaceholderShouldNotInteractWithDataSource() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tnew PlatformPlaceholderDatabaseDriverResolver().resolveAll(dataSource, \"schema.sql\");\n\t\tthen(dataSource).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid resolveAllWithFailingDataSourceWhenValuesContainPlaceholdersShouldThrowNestedCause() throws SQLException {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tgiven(dataSource.getConnection()).willThrow(new IllegalStateException(\"Test: invalid password\"));\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new PlatformPlaceholderDatabaseDriverResolver().resolveAll(dataSource, \"schema.sql\",\n\t\t\t\t\t\"schema-@@platform@@.sql\", \"data-@@platform@@.sql\"))\n\t\t\t.withMessage(\"Failed to determine DatabaseDriver\")\n\t\t\t.withStackTraceContaining(\"Test: invalid password\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenValuesContainPlaceholdersShouldReturnValuesWithPlaceholdersReplaced()\n\t\t\tthrows SQLException {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(dataSourceWithProductName(\"PostgreSQL\"),\n\t\t\t\t\"schema.sql\", \"schema-@@platform@@.sql\", \"data-@@platform@@.sql\"))\n\t\t\t.containsExactly(\"schema.sql\", \"schema-postgresql.sql\", \"data-postgresql.sql\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenDriverMappingsAreCustomizedShouldResolvePlaceholderUsingCustomMapping()\n\t\t\tthrows SQLException {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver()\n\t\t\t.withDriverPlatform(DatabaseDriver.POSTGRESQL, \"postgres\")\n\t\t\t.resolveAll(dataSourceWithProductName(\"PostgreSQL\"), \"schema-@@platform@@.sql\"))\n\t\t\t.containsExactly(\"schema-postgres.sql\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenValueIsAnEmptyStringShouldReturnValueUnchanged() {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver().resolveAll(mock(DataSource.class), \"\"))\n\t\t\t.containsExactly(\"\");\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenDriverIsUnknownShouldThrow() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new PlatformPlaceholderDatabaseDriverResolver()\n\t\t\t.resolveAll(dataSourceWithProductName(\"CustomDB\"), \"schema-@@platform@@.sql\"));\n\t}\n\n\t@Test\n\tvoid resolveAllWithDataSourceWhenPlaceholderIsCustomizedShouldResolvePlaceholders() throws SQLException {\n\t\tassertThat(new PlatformPlaceholderDatabaseDriverResolver(\"##platform##\")\n\t\t\t.resolveAll(dataSourceWithProductName(\"PostgreSQL\"), \"schema-##platform##.sql\", \"schema-@@platform@@.sql\"))\n\t\t\t.containsExactly(\"schema-postgresql.sql\", \"schema-@@platform@@.sql\");\n\t}\n\n\tprivate DataSource dataSourceWithProductName(String productName) throws SQLException {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(dataSource.getConnection()).willReturn(connection);\n\t\tDatabaseMetaData metadata = mock(DatabaseMetaData.class);\n\t\tgiven(connection.getMetaData()).willReturn(metadata);\n\t\tgiven(metadata.getDatabaseProductName()).willReturn(productName);\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metadata/AbstractDataSourcePoolMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.jdbc.core.ConnectionCallback;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for {@link DataSourcePoolMetadata} tests.\n *\n * @param <D> the data source pool metadata type\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n */\nabstract class AbstractDataSourcePoolMetadataTests<D extends AbstractDataSourcePoolMetadata<?>> {\n\n\t/**\n\t * Return a data source metadata instance with a min size of 0 and max size of 2. Idle\n\t * connections are not reclaimed immediately.\n\t * @return the data source metadata\n\t */\n\tprotected abstract D getDataSourceMetadata();\n\n\t@Test\n\tvoid getMaxPoolSize() {\n\t\tassertThat(getDataSourceMetadata().getMax()).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid getMinPoolSize() {\n\t\tassertThat(getDataSourceMetadata().getMin()).isZero();\n\t}\n\n\t@Test\n\tvoid getPoolSizeNoConnection() {\n\t\t// Make sure the pool is initialized\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());\n\t\tjdbcTemplate.execute((ConnectionCallback<Object>) (connection) -> new Object());\n\t\tassertThat(getDataSourceMetadata().getActive()).isZero();\n\t\tassertThat(getDataSourceMetadata().getUsage()).isZero();\n\t}\n\n\t@Test\n\tvoid getPoolSizeOneConnection() {\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());\n\t\tjdbcTemplate.execute((ConnectionCallback<Object>) (connection) -> {\n\t\t\tassertThat(getDataSourceMetadata().getActive()).isOne();\n\t\t\tassertThat(getDataSourceMetadata().getUsage()).isEqualTo(0.5f);\n\t\t\treturn new Object();\n\t\t});\n\t}\n\n\t@Test\n\tvoid getIdle() {\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());\n\t\tjdbcTemplate.execute((ConnectionCallback<Object>) (connection) -> new Object());\n\t\tassertThat(getDataSourceMetadata().getIdle()).isOne();\n\t}\n\n\t@Test\n\tvoid getPoolSizeTwoConnections() {\n\t\tfinal JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSourceMetadata().getDataSource());\n\t\tjdbcTemplate.execute((ConnectionCallback<Object>) (connection) -> {\n\t\t\tjdbcTemplate.execute((ConnectionCallback<Object>) (connection1) -> {\n\t\t\t\tassertThat(getDataSourceMetadata().getActive()).isEqualTo(2);\n\t\t\t\tassertThat(getDataSourceMetadata().getUsage()).isOne();\n\t\t\t\treturn new Object();\n\t\t\t});\n\t\t\treturn new Object();\n\t\t});\n\t}\n\n\t@Test\n\tabstract void getValidationQuery() throws Exception;\n\n\t@Test\n\tabstract void getDefaultAutoCommit() throws Exception;\n\n\tprotected DataSourceBuilder<?> initializeBuilder() {\n\t\treturn DataSourceBuilder.create()\n\t\t\t.driverClassName(\"org.hsqldb.jdbc.JDBCDriver\")\n\t\t\t.url(\"jdbc:hsqldb:mem:test\")\n\t\t\t.username(\"sa\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metadata/CommonsDbcp2DataSourcePoolMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport java.time.Duration;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CommonsDbcp2DataSourcePoolMetadata}.\n *\n * @author Stephane Nicoll\n */\nclass CommonsDbcp2DataSourcePoolMetadataTests\n\t\textends AbstractDataSourcePoolMetadataTests<CommonsDbcp2DataSourcePoolMetadata> {\n\n\tprivate final CommonsDbcp2DataSourcePoolMetadata dataSourceMetadata = createDataSourceMetadata(0, 2);\n\n\t@Override\n\tprotected CommonsDbcp2DataSourcePoolMetadata getDataSourceMetadata() {\n\t\treturn this.dataSourceMetadata;\n\t}\n\n\t@Test\n\tvoid getPoolUsageWithNoCurrent() {\n\t\tCommonsDbcp2DataSourcePoolMetadata dsm = new CommonsDbcp2DataSourcePoolMetadata(createDataSource()) {\n\t\t\t@Override\n\t\t\tpublic @Nullable Integer getActive() {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t};\n\t\tassertThat(dsm.getUsage()).isNull();\n\t}\n\n\t@Test\n\tvoid getPoolUsageWithNoMax() {\n\t\tCommonsDbcp2DataSourcePoolMetadata dsm = new CommonsDbcp2DataSourcePoolMetadata(createDataSource()) {\n\t\t\t@Override\n\t\t\tpublic @Nullable Integer getMax() {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t};\n\t\tassertThat(dsm.getUsage()).isNull();\n\t}\n\n\t@Test\n\tvoid getPoolUsageWithUnlimitedPool() {\n\t\tDataSourcePoolMetadata unlimitedDataSource = createDataSourceMetadata(0, -1);\n\t\tassertThat(unlimitedDataSource.getUsage()).isEqualTo(-1f);\n\t}\n\n\t@Override\n\tpublic void getValidationQuery() {\n\t\tBasicDataSource dataSource = createDataSource();\n\t\tdataSource.setValidationQuery(\"SELECT FROM FOO\");\n\t\tassertThat(new CommonsDbcp2DataSourcePoolMetadata(dataSource).getValidationQuery())\n\t\t\t.isEqualTo(\"SELECT FROM FOO\");\n\t}\n\n\t@Override\n\tpublic void getDefaultAutoCommit() {\n\t\tBasicDataSource dataSource = createDataSource();\n\t\tdataSource.setDefaultAutoCommit(false);\n\t\tassertThat(new CommonsDbcp2DataSourcePoolMetadata(dataSource).getDefaultAutoCommit()).isFalse();\n\t}\n\n\tprivate CommonsDbcp2DataSourcePoolMetadata createDataSourceMetadata(int minSize, int maxSize) {\n\t\tBasicDataSource dataSource = createDataSource();\n\t\tdataSource.setMinIdle(minSize);\n\t\tdataSource.setMaxTotal(maxSize);\n\t\tdataSource.setMinEvictableIdle(Duration.ofSeconds(5));\n\t\treturn new CommonsDbcp2DataSourcePoolMetadata(dataSource);\n\t}\n\n\tprivate BasicDataSource createDataSource() {\n\t\treturn initializeBuilder().type(BasicDataSource.class).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metadata/CompositeDataSourcePoolMetadataProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport java.util.Arrays;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link CompositeDataSourcePoolMetadataProvider}.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(MockitoExtension.class)\nclass CompositeDataSourcePoolMetadataProviderTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSourcePoolMetadataProvider firstProvider;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSourcePoolMetadata first;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSource firstDataSource;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSourcePoolMetadataProvider secondProvider;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSourcePoolMetadata second;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSource secondDataSource;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate DataSource unknownDataSource;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tgiven(this.firstProvider.getDataSourcePoolMetadata(this.firstDataSource)).willReturn(this.first);\n\t\tgiven(this.firstProvider.getDataSourcePoolMetadata(this.secondDataSource)).willReturn(this.second);\n\t}\n\n\t@Test\n\tvoid createWithProviders() {\n\t\tCompositeDataSourcePoolMetadataProvider provider = new CompositeDataSourcePoolMetadataProvider(\n\t\t\t\tArrays.asList(this.firstProvider, this.secondProvider));\n\t\tassertThat(provider.getDataSourcePoolMetadata(this.firstDataSource)).isSameAs(this.first);\n\t\tassertThat(provider.getDataSourcePoolMetadata(this.secondDataSource)).isSameAs(this.second);\n\t\tassertThat(provider.getDataSourcePoolMetadata(this.unknownDataSource)).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metadata/HikariDataSourcePoolMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport com.zaxxer.hikari.HikariDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HikariDataSourcePoolMetadata}.\n *\n * @author Stephane Nicoll\n */\npublic class HikariDataSourcePoolMetadataTests\n\t\textends AbstractDataSourcePoolMetadataTests<HikariDataSourcePoolMetadata> {\n\n\tprivate final HikariDataSourcePoolMetadata dataSourceMetadata = new HikariDataSourcePoolMetadata(\n\t\t\tcreateDataSource(0, 2));\n\n\t@Override\n\tprotected HikariDataSourcePoolMetadata getDataSourceMetadata() {\n\t\treturn this.dataSourceMetadata;\n\t}\n\n\t@Override\n\tpublic void getValidationQuery() {\n\t\tHikariDataSource dataSource = createDataSource(0, 4);\n\t\tdataSource.setConnectionTestQuery(\"SELECT FROM FOO\");\n\t\tassertThat(new HikariDataSourcePoolMetadata(dataSource).getValidationQuery()).isEqualTo(\"SELECT FROM FOO\");\n\t}\n\n\t@Override\n\tpublic void getDefaultAutoCommit() {\n\t\tHikariDataSource dataSource = createDataSource(0, 4);\n\t\tdataSource.setAutoCommit(false);\n\t\tassertThat(new HikariDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()).isFalse();\n\t}\n\n\tprivate HikariDataSource createDataSource(int minSize, int maxSize) {\n\t\tHikariDataSource dataSource = initializeBuilder().type(HikariDataSource.class).build();\n\t\tdataSource.setMinimumIdle(minSize);\n\t\tdataSource.setMaximumPoolSize(maxSize);\n\t\tdataSource.setIdleTimeout(5000);\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metadata/OracleUcpDataSourcePoolMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport java.sql.SQLException;\n\nimport oracle.ucp.jdbc.PoolDataSource;\nimport oracle.ucp.jdbc.PoolDataSourceImpl;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OracleUcpDataSourcePoolMetadata}.\n *\n * @author Fabio Grassi\n */\nclass OracleUcpDataSourcePoolMetadataTests\n\t\textends AbstractDataSourcePoolMetadataTests<OracleUcpDataSourcePoolMetadata> {\n\n\tprivate final OracleUcpDataSourcePoolMetadata dataSourceMetadata = new OracleUcpDataSourcePoolMetadata(\n\t\t\tcreateDataSource(0, 2));\n\n\t@Override\n\tprotected OracleUcpDataSourcePoolMetadata getDataSourceMetadata() {\n\t\treturn this.dataSourceMetadata;\n\t}\n\n\t@Override\n\tvoid getValidationQuery() throws SQLException {\n\t\tPoolDataSource dataSource = createDataSource(0, 4);\n\t\tdataSource.setSQLForValidateConnection(\"SELECT NULL FROM DUAL\");\n\t\tassertThat(new OracleUcpDataSourcePoolMetadata(dataSource).getValidationQuery())\n\t\t\t.isEqualTo(\"SELECT NULL FROM DUAL\");\n\t}\n\n\t@Override\n\tvoid getDefaultAutoCommit() throws SQLException {\n\t\tPoolDataSource dataSource = createDataSource(0, 4);\n\t\tdataSource.setConnectionProperty(\"autoCommit\", \"false\");\n\t\tassertThat(new OracleUcpDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()).isFalse();\n\t}\n\n\tprivate PoolDataSource createDataSource(int minSize, int maxSize) {\n\t\ttry {\n\t\t\tPoolDataSource dataSource = initializeBuilder().type(PoolDataSourceImpl.class).build();\n\t\t\tdataSource.setInitialPoolSize(minSize);\n\t\t\tdataSource.setMinPoolSize(minSize);\n\t\t\tdataSource.setMaxPoolSize(maxSize);\n\t\t\treturn dataSource;\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new IllegalStateException(\"Error while configuring PoolDataSource\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metadata/TomcatDataSourcePoolMetadataTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metadata;\n\nimport org.apache.tomcat.jdbc.pool.DataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TomcatDataSourcePoolMetadata}.\n *\n * @author Stephane Nicoll\n */\npublic class TomcatDataSourcePoolMetadataTests\n\t\textends AbstractDataSourcePoolMetadataTests<TomcatDataSourcePoolMetadata> {\n\n\tprivate final TomcatDataSourcePoolMetadata dataSourceMetadata = new TomcatDataSourcePoolMetadata(\n\t\t\tcreateDataSource(0, 2));\n\n\t@Override\n\tprotected TomcatDataSourcePoolMetadata getDataSourceMetadata() {\n\t\treturn this.dataSourceMetadata;\n\t}\n\n\t@Override\n\tpublic void getValidationQuery() {\n\t\tDataSource dataSource = createDataSource(0, 4);\n\t\tdataSource.setValidationQuery(\"SELECT FROM FOO\");\n\t\tassertThat(new TomcatDataSourcePoolMetadata(dataSource).getValidationQuery()).isEqualTo(\"SELECT FROM FOO\");\n\t}\n\n\t@Override\n\tpublic void getDefaultAutoCommit() {\n\t\tDataSource dataSource = createDataSource(0, 4);\n\t\tdataSource.setDefaultAutoCommit(false);\n\t\tassertThat(new TomcatDataSourcePoolMetadata(dataSource).getDefaultAutoCommit()).isFalse();\n\t}\n\n\tprivate DataSource createDataSource(int minSize, int maxSize) {\n\t\tDataSource dataSource = initializeBuilder().type(DataSource.class).build();\n\t\tdataSource.setMinIdle(minSize);\n\t\tdataSource.setMaxActive(maxSize);\n\t\tdataSource.setMinEvictableIdleTimeMillis(5000);\n\n\t\t// Avoid warnings\n\t\tdataSource.setInitialSize(minSize);\n\t\tdataSource.setMaxIdle(maxSize);\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc/src/test/java/org/springframework/boot/jdbc/metrics/DataSourcePoolMetricsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.metrics;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport javax.sql.DataSource;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.metadata.DataSourcePoolMetadataProvider;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Tests for {@link DataSourcePoolMetrics}.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n */\nclass DataSourcePoolMetricsTests {\n\n\t@Test\n\tvoid dataSourceIsInstrumented() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(DataSourceConfig.class, MetricsApp.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\", \"metrics.use-global-registry=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(DataSource.class).getConnection().getMetaData();\n\t\t\t\tcontext.getBean(MeterRegistry.class).get(\"jdbc.connections.max\").meter();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsApp {\n\n\t\t@Bean\n\t\tMeterRegistry registry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceConfig {\n\n\t\tDataSourceConfig(DataSource dataSource, Collection<DataSourcePoolMetadataProvider> metadataProviders,\n\t\t\t\tMeterRegistry registry) {\n\t\t\tnew DataSourcePoolMetrics(dataSource, metadataProviders, \"data.source\", Collections.emptyList())\n\t\t\t\t.bindTo(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot JDBC Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-docker-compose\"))\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"com.h2database:h2\")\n\tdockerTestImplementation(\"com.zaxxer:HikariCP\")\n\tdockerTestImplementation(\"org.assertj:assertj-core\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.postgresql:postgresql\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-transaction\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/dockerTest/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseDockerComposeIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabaseDockerComposeIntegrationTests.SetupDockerCompose;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigureTestDatabase} with Docker Compose.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@ContextConfiguration(initializers = SetupDockerCompose.class)\n@AutoConfigureTestDatabase\n@OverrideAutoConfiguration(enabled = false)\n@DisabledIfDockerUnavailable\nclass AutoConfigureTestDatabaseDockerComposeIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid dataSourceIsNotReplaced() {\n\t\tassertThat(this.dataSource).isInstanceOf(HikariDataSource.class).isNotInstanceOf(EmbeddedDatabase.class);\n\t}\n\n\t@Configuration\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class Config {\n\n\t}\n\n\tstatic class SetupDockerCompose implements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\ttry {\n\t\t\t\tPath composeFile = Files.createTempFile(\"\", \"-postgres-compose\");\n\t\t\t\tString composeFileContent = new ClassPathResource(\"postgres-compose.yaml\")\n\t\t\t\t\t.getContentAsString(StandardCharsets.UTF_8)\n\t\t\t\t\t.replace(\"{imageName}\", TestImage.POSTGRESQL.toString());\n\t\t\t\tFiles.writeString(composeFile, composeFileContent);\n\t\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,\n\t\t\t\t\t\t\"spring.docker.compose.skip.in-tests=false\", \"spring.docker.compose.stop.command=down\",\n\t\t\t\t\t\t\"spring.docker.compose.file=\" + composeFile.toAbsolutePath());\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/dockerTest/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseDynamicPropertySourceIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigureTestDatabase} with Testcontainers and a\n * {@link DynamicPropertySource @DynamicPropertySource}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@AutoConfigureTestDatabase\n@Testcontainers(disabledWithoutDocker = true)\n@OverrideAutoConfiguration(enabled = false)\nclass AutoConfigureTestDatabaseDynamicPropertySourceIntegrationTests {\n\n\t@Container\n\tstatic PostgreSQLContainer postgres = TestImage.container(PostgreSQLContainer.class);\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@DynamicPropertySource\n\tstatic void jdbcProperties(DynamicPropertyRegistry registry) {\n\t\tregistry.add(\"spring.datasource.url\", postgres::getJdbcUrl);\n\t}\n\n\t@Test\n\tvoid dataSourceIsNotReplaced() {\n\t\tassertThat(this.dataSource).isInstanceOf(HikariDataSource.class).isNotInstanceOf(EmbeddedDatabase.class);\n\t}\n\n\t@Configuration\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/dockerTest/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseNonTestDatabaseIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabaseNonTestDatabaseIntegrationTests.SetupDatabase;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.DisabledIfDockerUnavailable;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigureTestDatabase} with Docker Compose.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@ContextConfiguration(initializers = SetupDatabase.class)\n@AutoConfigureTestDatabase\n@OverrideAutoConfiguration(enabled = false)\n@DisabledIfDockerUnavailable\nclass AutoConfigureTestDatabaseNonTestDatabaseIntegrationTests {\n\n\t@Container\n\tstatic PostgreSQLContainer postgres = TestImage.container(PostgreSQLContainer.class);\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid dataSourceIsReplaced() {\n\t\tassertThat(this.dataSource).isInstanceOf(EmbeddedDatabase.class);\n\t}\n\n\t@Configuration\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class Config {\n\n\t}\n\n\tstatic class SetupDatabase implements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tpostgres.start();\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,\n\t\t\t\t\t\"spring.datasource.url=\" + postgres.getJdbcUrl());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/dockerTest/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseServiceConnectionIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for {@link AutoConfigureTestDatabase} with Testcontainers and a\n * {@link ServiceConnection @ServiceConnection}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@AutoConfigureTestDatabase(replace = Replace.NON_TEST)\n@Testcontainers(disabledWithoutDocker = true)\n@OverrideAutoConfiguration(enabled = false)\nclass AutoConfigureTestDatabaseServiceConnectionIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic PostgreSQLContainer postgres = TestImage.container(PostgreSQLContainer.class);\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid dataSourceIsNotReplaced() {\n\t\tassertThat(this.dataSource).isInstanceOf(HikariDataSource.class).isNotInstanceOf(EmbeddedDatabase.class);\n\t}\n\n\t@Configuration\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/dockerTest/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseTestcontainersJdbcUrlIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabaseTestcontainersJdbcUrlIntegrationTests.InitializeDatasourceUrl;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for {@link AutoConfigureTestDatabase} with Testcontainers and a\n * {@link ServiceConnection @ServiceConnection}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@ContextConfiguration(initializers = InitializeDatasourceUrl.class)\n@AutoConfigureTestDatabase(replace = Replace.NON_TEST)\n@Testcontainers(disabledWithoutDocker = true)\n@OverrideAutoConfiguration(enabled = false)\nclass AutoConfigureTestDatabaseTestcontainersJdbcUrlIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid dataSourceIsNotReplaced() {\n\t\tassertThat(this.dataSource).isInstanceOf(HikariDataSource.class).isNotInstanceOf(EmbeddedDatabase.class);\n\t}\n\n\t@Configuration\n\t@ImportAutoConfiguration(DataSourceAutoConfiguration.class)\n\tstatic class Config {\n\n\t}\n\n\tstatic class InitializeDatasourceUrl implements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,\n\t\t\t\t\t\"spring.datasource.url=jdbc:tc:postgis:\" + TestImage.POSTGRESQL.getTag() + \":///\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/dockerTest/resources/postgres-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureJdbc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical JDBC tests. Most\n * tests should consider using {@link JdbcTest @JdbcTest} rather than using this\n * annotation directly.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see JdbcTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@AutoConfigureDataSourceInitialization\npublic @interface AutoConfigureJdbc {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabase.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.container.ContainerImageMetadata;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.boot.test.context.PropertyMapping.Skip;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.test.context.DynamicPropertySource;\n\n/**\n * Annotation that can be applied to a test class to configure a test database to use\n * instead of the application-defined or auto-configured {@link DataSource}. In the case\n * of multiple {@code DataSource} beans, only the {@link Primary @Primary}\n * {@code DataSource} is considered.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see TestDatabaseAutoConfiguration\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.database\")\npublic @interface AutoConfigureTestDatabase {\n\n\t/**\n\t * Determines what type of existing DataSource bean can be replaced.\n\t * @return the type of existing DataSource to replace\n\t */\n\t@PropertyMapping(skip = Skip.ON_DEFAULT_VALUE)\n\tReplace replace() default Replace.NON_TEST;\n\n\t/**\n\t * The type of connection to be established when {@link #replace() replacing} the\n\t * DataSource. By default, will attempt to detect the connection based on the\n\t * classpath.\n\t * @return the type of connection to use\n\t */\n\tEmbeddedDatabaseConnection connection() default EmbeddedDatabaseConnection.NONE;\n\n\t/**\n\t * What the test database can replace.\n\t */\n\tenum Replace {\n\n\t\t/**\n\t\t * Replace the DataSource bean unless it is auto-configured and connecting to a\n\t\t * test database. The following types of connections are considered test\n\t\t * databases:\n\t\t * <ul>\n\t\t * <li>Any bean definition that includes {@link ContainerImageMetadata} (including\n\t\t * {@code @ServiceConnection} annotated Testcontainers databases, and connections\n\t\t * created using Docker Compose)</li>\n\t\t * <li>Any connection configured using a {@code spring.datasource.url} backed by a\n\t\t * {@link DynamicPropertySource @DynamicPropertySource}</li>\n\t\t * <li>Any connection configured using a {@code spring.datasource.url} with the\n\t\t * Testcontainers JDBC syntax</li>\n\t\t * </ul>\n\t\t */\n\t\tNON_TEST,\n\n\t\t/**\n\t\t * Replace the DataSource bean whether it was auto-configured or manually defined.\n\t\t */\n\t\tANY,\n\n\t\t/**\n\t\t * Only replace the DataSource if it was auto-configured.\n\t\t */\n\t\tAUTO_CONFIGURED,\n\n\t\t/**\n\t\t * Don't replace the application default DataSource.\n\t\t */\n\t\tNONE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Annotation for a JDBC test that focuses <strong>only</strong> on JDBC-based components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to JDBC tests.\n * Similarly, component scanning is configured to skip regular components and\n * configuration properties.\n * <p>\n * By default, tests annotated with {@code @JdbcTest} are transactional and roll back at\n * the end of each test. They also use an embedded in-memory database (replacing any\n * explicit or usually auto-configured DataSource). The\n * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} annotation can be used to\n * override these settings.\n * <p>\n * If you are looking to load your full application configuration, but use an embedded\n * database, you should consider {@link SpringBootTest @SpringBootTest} combined with\n * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} rather than this\n * annotation.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n * @see AutoConfigureJdbc\n * @see AutoConfigureTestDatabase\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(JdbcTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(JdbcTypeExcludeFilter.class)\n@Transactional\n@AutoConfigureJdbc\n@AutoConfigureTestDatabase\n@ImportAutoConfiguration\npublic @interface JdbcTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link JdbcTest @JdbcTest} support.\n *\n * @author Artsiom Yudovin\n * @author Yanming Zhou\n */\nclass JdbcTestContextBootstrapper extends TestSliceTestContextBootstrapper<JdbcTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link JdbcTest @JdbcTest}.\n *\n * @author Stephane Nicoll\n */\nclass JdbcTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<JdbcTest> {\n\n\tJdbcTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/TestDatabaseAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.container.ContainerImageMetadata;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.bind.BoundPropertiesTrackingBindHandler;\nimport org.springframework.boot.context.properties.source.ConfigurationProperty;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertyName;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;\nimport org.springframework.boot.origin.PropertySourceOrigin;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.type.MethodMetadata;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Auto-configuration for a test database.\n *\n * @author Phillip Webb\n * @since 1.4.0\n * @see AutoConfigureTestDatabase\n */\n@AutoConfiguration(before = DataSourceAutoConfiguration.class)\npublic final class TestDatabaseAutoConfiguration {\n\n\t@Bean\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t@ConditionalOnProperty(name = \"spring.test.database.replace\", havingValue = \"NON_TEST\", matchIfMissing = true)\n\tstatic EmbeddedDataSourceBeanFactoryPostProcessor nonTestEmbeddedDataSourceBeanFactoryPostProcessor(\n\t\t\tEnvironment environment) {\n\t\treturn new EmbeddedDataSourceBeanFactoryPostProcessor(environment, Replace.NON_TEST);\n\t}\n\n\t@Bean\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t@ConditionalOnProperty(name = \"spring.test.database.replace\", havingValue = \"ANY\")\n\tstatic EmbeddedDataSourceBeanFactoryPostProcessor embeddedDataSourceBeanFactoryPostProcessor(\n\t\t\tEnvironment environment) {\n\t\treturn new EmbeddedDataSourceBeanFactoryPostProcessor(environment, Replace.ANY);\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.test.database.replace\", havingValue = \"AUTO_CONFIGURED\")\n\t@ConditionalOnMissingBean\n\tDataSource dataSource(Environment environment) {\n\t\treturn new EmbeddedDataSourceFactory(environment).getEmbeddedDatabase();\n\t}\n\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class EmbeddedDataSourceBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {\n\n\t\tprivate static final ConfigurationPropertyName DATASOURCE_URL_PROPERTY = ConfigurationPropertyName\n\t\t\t.of(\"spring.datasource.url\");\n\n\t\tprivate static final Bindable<String> BINDABLE_STRING = Bindable.of(String.class);\n\n\t\tprivate static final String DYNAMIC_VALUES_PROPERTY_SOURCE_CLASS = \"org.springframework.test.context.support.DynamicValuesPropertySource\";\n\n\t\tprivate static final Log logger = LogFactory.getLog(EmbeddedDataSourceBeanFactoryPostProcessor.class);\n\n\t\tprivate final Environment environment;\n\n\t\tprivate final Replace replace;\n\n\t\tEmbeddedDataSourceBeanFactoryPostProcessor(Environment environment, Replace replace) {\n\t\t\tthis.environment = environment;\n\t\t\tthis.replace = replace;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n\t\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tAssert.isTrue(registry instanceof ConfigurableListableBeanFactory,\n\t\t\t\t\t\"'registry' must be a ConfigurableListableBeanFactory\");\n\t\t\tprocess(registry, (ConfigurableListableBeanFactory) registry);\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t}\n\n\t\tprivate void process(BeanDefinitionRegistry registry, ConfigurableListableBeanFactory beanFactory) {\n\t\t\tBeanDefinitionHolder holder = getDataSourceBeanDefinition(beanFactory);\n\t\t\tif (holder != null && isReplaceable(beanFactory, holder)) {\n\t\t\t\tString beanName = holder.getBeanName();\n\t\t\t\tboolean primary = holder.getBeanDefinition().isPrimary();\n\t\t\t\tlogger.info(\"Replacing '\" + beanName + \"' DataSource bean with \" + (primary ? \"primary \" : \"\")\n\t\t\t\t\t\t+ \"embedded version\");\n\t\t\t\tregistry.removeBeanDefinition(beanName);\n\t\t\t\tregistry.registerBeanDefinition(beanName, createEmbeddedBeanDefinition(primary));\n\t\t\t}\n\t\t}\n\n\t\tprivate BeanDefinition createEmbeddedBeanDefinition(boolean primary) {\n\t\t\tBeanDefinition beanDefinition = new RootBeanDefinition(EmbeddedDataSourceFactoryBean.class);\n\t\t\tbeanDefinition.setPrimary(primary);\n\t\t\treturn beanDefinition;\n\t\t}\n\n\t\tprivate @Nullable BeanDefinitionHolder getDataSourceBeanDefinition(\n\t\t\t\tConfigurableListableBeanFactory beanFactory) {\n\t\t\tString[] beanNames = beanFactory.getBeanNamesForType(DataSource.class);\n\t\t\tif (ObjectUtils.isEmpty(beanNames)) {\n\t\t\t\tlogger.warn(\"No DataSource beans found, embedded version will not be used\");\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (beanNames.length == 1) {\n\t\t\t\tString beanName = beanNames[0];\n\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\treturn new BeanDefinitionHolder(beanDefinition, beanName);\n\t\t\t}\n\t\t\tfor (String beanName : beanNames) {\n\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\tif (beanDefinition.isPrimary()) {\n\t\t\t\t\treturn new BeanDefinitionHolder(beanDefinition, beanName);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlogger.warn(\"No primary DataSource found, embedded version will not be used\");\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate boolean isReplaceable(ConfigurableListableBeanFactory beanFactory, BeanDefinitionHolder holder) {\n\t\t\tif (this.replace == Replace.NON_TEST) {\n\t\t\t\treturn !isAutoConfigured(holder) || !isConnectingToTestDatabase(beanFactory);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tprivate boolean isAutoConfigured(BeanDefinitionHolder holder) {\n\t\t\tif (holder.getBeanDefinition() instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {\n\t\t\t\tMethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();\n\t\t\t\treturn (factoryMethodMetadata != null) && (factoryMethodMetadata.getDeclaringClassName()\n\t\t\t\t\t.startsWith(\"org.springframework.boot.jdbc.autoconfigure.\"));\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate boolean isConnectingToTestDatabase(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn isUsingTestServiceConnection(beanFactory) || isUsingTestDatasourceUrl();\n\t\t}\n\n\t\tprivate boolean isUsingTestServiceConnection(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tfor (String beanName : beanFactory.getBeanNamesForType(JdbcConnectionDetails.class)) {\n\t\t\t\ttry {\n\t\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\t\tif (ContainerImageMetadata.isPresent(beanDefinition)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate boolean isUsingTestDatasourceUrl() {\n\t\t\tList<ConfigurationProperty> bound = new ArrayList<>();\n\t\t\tBinder.get(this.environment, new BoundPropertiesTrackingBindHandler(bound::add))\n\t\t\t\t.bind(DATASOURCE_URL_PROPERTY, BINDABLE_STRING);\n\t\t\treturn !bound.isEmpty() && isUsingTestDatasourceUrl(bound.get(0));\n\t\t}\n\n\t\tprivate boolean isUsingTestDatasourceUrl(ConfigurationProperty configurationProperty) {\n\t\t\treturn isBoundToDynamicValuesPropertySource(configurationProperty)\n\t\t\t\t\t|| isTestcontainersUrl(configurationProperty);\n\t\t}\n\n\t\tprivate boolean isBoundToDynamicValuesPropertySource(ConfigurationProperty configurationProperty) {\n\t\t\tif (configurationProperty.getOrigin() instanceof PropertySourceOrigin origin) {\n\t\t\t\treturn isDynamicValuesPropertySource(origin.getPropertySource());\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tprivate boolean isDynamicValuesPropertySource(@Nullable PropertySource<?> propertySource) {\n\t\t\treturn propertySource != null\n\t\t\t\t\t&& DYNAMIC_VALUES_PROPERTY_SOURCE_CLASS.equals(propertySource.getClass().getName());\n\t\t}\n\n\t\tprivate boolean isTestcontainersUrl(ConfigurationProperty configurationProperty) {\n\t\t\tObject value = configurationProperty.getValue();\n\t\t\treturn (value != null) && value.toString().startsWith(\"jdbc:tc:\");\n\t\t}\n\n\t}\n\n\tstatic class EmbeddedDataSourceFactoryBean implements FactoryBean<DataSource>, EnvironmentAware, InitializingBean {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate EmbeddedDataSourceFactory factory;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate EmbeddedDatabase embeddedDatabase;\n\n\t\t@Override\n\t\tpublic void setEnvironment(Environment environment) {\n\t\t\tthis.factory = new EmbeddedDataSourceFactory(environment);\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterPropertiesSet() throws Exception {\n\t\t\tthis.embeddedDatabase = this.factory.getEmbeddedDatabase();\n\t\t}\n\n\t\t@Override\n\t\tpublic DataSource getObject() throws Exception {\n\t\t\treturn this.embeddedDatabase;\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn EmbeddedDatabase.class;\n\t\t}\n\n\t}\n\n\tstatic class EmbeddedDataSourceFactory {\n\n\t\tprivate final Environment environment;\n\n\t\tEmbeddedDataSourceFactory(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t\tif (environment instanceof ConfigurableEnvironment configurableEnvironment) {\n\t\t\t\tMap<String, Object> source = new HashMap<>();\n\t\t\t\tsource.put(\"spring.datasource.schema-username\", \"\");\n\t\t\t\tsource.put(\"spring.sql.init.username\", \"\");\n\t\t\t\tconfigurableEnvironment.getPropertySources().addFirst(new MapPropertySource(\"testDatabase\", source));\n\t\t\t}\n\t\t}\n\n\t\tEmbeddedDatabase getEmbeddedDatabase() {\n\t\t\tEmbeddedDatabaseConnection connection = this.environment.getProperty(\"spring.test.database.connection\",\n\t\t\t\t\tEmbeddedDatabaseConnection.class, EmbeddedDatabaseConnection.NONE);\n\t\t\tif (EmbeddedDatabaseConnection.NONE.equals(connection)) {\n\t\t\t\tconnection = EmbeddedDatabaseConnection.get(getClass().getClassLoader());\n\t\t\t}\n\t\t\tAssert.state(connection != EmbeddedDatabaseConnection.NONE,\n\t\t\t\t\t\"Failed to replace DataSource with an embedded database for tests. If \"\n\t\t\t\t\t\t\t+ \"you want an embedded database please put a supported one \"\n\t\t\t\t\t\t\t+ \"on the classpath or tune the replace attribute of @AutoConfigureTestDatabase.\");\n\t\t\tEmbeddedDatabaseType type = connection.getType();\n\t\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(type).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/java/org/springframework/boot/jdbc/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JDBC tests.\n */\n@NullMarked\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.database.replace\",\n      \"type\": \"org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase$Replace\",\n      \"description\": \"Type of existing DataSource to replace.\",\n      \"defaultValue\": \"any\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/resources/META-INF/spring/org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureJdbc.imports",
    "content": "org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.JdbcClientAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/resources/META-INF/spring/org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.imports",
    "content": "org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\norg.springframework.boot.jdbc.test.autoconfigure.TestDatabaseAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization.imports",
    "content": "org.springframework.boot.jdbc.autoconfigure.DataSourceInitializationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseWithMultipleDatasourcesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} when\n * there are multiple datasources.\n *\n * @author Greg Potter\n */\n@JdbcTest\n@AutoConfigureTestDatabase\nclass AutoConfigureTestDatabaseWithMultipleDatasourcesIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithExplicit() throws Exception {\n\t\t// Look that the datasource is replaced with an H2 DB.\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"H2\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration\n\tstatic class Config {\n\n\t\t@Bean\n\t\t@Primary\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource secondaryDataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/AutoConfigureTestDatabaseWithNoDatabaseIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} when\n * there is no database.\n *\n * @author Phillip Webb\n */\n@ExtendWith(SpringExtension.class)\n@AutoConfigureTestDatabase\nclass AutoConfigureTestDatabaseWithNoDatabaseIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid testContextLoads() {\n\t\t// gh-6897\n\t\tassertThat(this.context).isNotNull();\n\t\tassertThat(this.context.getBeanNamesForType(DataSource.class)).isNotEmpty();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/ExampleEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Example entity used with {@link JdbcTest @JdbcTest} tests.\n *\n * @author Stephane Nicoll\n */\npublic class ExampleEntity {\n\n\tprivate final int id;\n\n\tprivate @Nullable String name;\n\n\tpublic ExampleEntity(int id, @Nullable String name) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t}\n\n\tpublic ExampleEntity(int id) {\n\t\tthis(id, null);\n\t}\n\n\tpublic int getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/ExampleEntityRowMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport org.springframework.jdbc.core.RowMapper;\n\n/**\n * @author Stephane Nicoll\n */\nclass ExampleEntityRowMapper implements RowMapper<ExampleEntity> {\n\n\t@Override\n\tpublic ExampleEntity mapRow(ResultSet rs, int rowNum) throws SQLException {\n\t\tint id = rs.getInt(\"id\");\n\t\tString name = rs.getString(\"name\");\n\t\treturn new ExampleEntity(id, name);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/ExampleJdbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link JdbcTest @JdbcTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleJdbcApplication {\n\n\t@Bean\n\tpublic DataSource dataSource() {\n\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/ExampleJdbcClientRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.springframework.jdbc.core.simple.JdbcClient;\n\n/**\n * Example repository used with {@link JdbcClient JdbcClient} and\n * {@link JdbcTest @JdbcTest} tests.\n *\n * @author Yanming Zhou\n */\nclass ExampleJdbcClientRepository {\n\n\tprivate static final ExampleEntityRowMapper ROW_MAPPER = new ExampleEntityRowMapper();\n\n\tprivate final JdbcClient jdbcClient;\n\n\tExampleJdbcClientRepository(JdbcClient jdbcClient) {\n\t\tthis.jdbcClient = jdbcClient;\n\t}\n\n\tvoid save(ExampleEntity entity) {\n\t\tthis.jdbcClient.sql(\"insert into example (id, name) values (:id, :name)\")\n\t\t\t.param(\"id\", entity.getId())\n\t\t\t.param(\"name\", entity.getName())\n\t\t\t.update();\n\t}\n\n\tExampleEntity findById(int id) {\n\t\treturn this.jdbcClient.sql(\"select id, name from example where id = :id\")\n\t\t\t.param(\"id\", id)\n\t\t\t.query(ROW_MAPPER)\n\t\t\t.single();\n\t}\n\n\tCollection<ExampleEntity> findAll() {\n\t\treturn this.jdbcClient.sql(\"select id, name from example\").query(ROW_MAPPER).list();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/ExampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Example repository used with {@link JdbcTest @JdbcTest} tests.\n *\n * @author Stephane Nicoll\n */\n@Repository\nclass ExampleRepository {\n\n\tprivate static final ExampleEntityRowMapper ROW_MAPPER = new ExampleEntityRowMapper();\n\n\tprivate final JdbcTemplate jdbcTemplate;\n\n\tExampleRepository(JdbcTemplate jdbcTemplate) {\n\t\tthis.jdbcTemplate = jdbcTemplate;\n\t}\n\n\t@Transactional\n\tvoid save(ExampleEntity entity) {\n\t\tthis.jdbcTemplate.update(\"insert into example (id, name) values (?, ?)\", entity.getId(), entity.getName());\n\t}\n\n\tExampleEntity findById(int id) {\n\t\treturn this.jdbcTemplate.queryForObject(\"select id, name from example where id =?\", ROW_MAPPER, id);\n\t}\n\n\tCollection<ExampleEntity> findAll() {\n\t\treturn this.jdbcTemplate.query(\"select id, name from example\", ROW_MAPPER);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport java.util.Collection;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.simple.JdbcClient;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Stephane Nicoll\n * @author Yanming Zhou\n */\n@JdbcTest\n@TestPropertySource(\n\t\tproperties = \"spring.sql.init.schemaLocations=classpath:org/springframework/boot/jdbc/test/autoconfigure/schema.sql\")\nclass JdbcTestIntegrationTests {\n\n\t@Autowired\n\tprivate JdbcClient jdbcClient;\n\n\t@Autowired\n\tprivate JdbcTemplate jdbcTemplate;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testJdbcClient() {\n\t\tExampleJdbcClientRepository repository = new ExampleJdbcClientRepository(this.jdbcClient);\n\t\trepository.save(new ExampleEntity(1, \"John\"));\n\t\tExampleEntity entity = repository.findById(1);\n\t\tassertThat(entity.getId()).isOne();\n\t\tassertThat(entity.getName()).isEqualTo(\"John\");\n\t\tCollection<ExampleEntity> entities = repository.findAll();\n\t\tassertThat(entities).hasSize(1);\n\t\tentity = entities.iterator().next();\n\t\tassertThat(entity.getId()).isOne();\n\t\tassertThat(entity.getName()).isEqualTo(\"John\");\n\t}\n\n\t@Test\n\tvoid testJdbcTemplate() {\n\t\tExampleRepository repository = new ExampleRepository(this.jdbcTemplate);\n\t\trepository.save(new ExampleEntity(1, \"John\"));\n\t\tExampleEntity entity = repository.findById(1);\n\t\tassertThat(entity.getId()).isOne();\n\t\tassertThat(entity.getName()).isEqualTo(\"John\");\n\t\tCollection<ExampleEntity> entities = repository.findAll();\n\t\tassertThat(entities).hasSize(1);\n\t\tentity = entities.iterator().next();\n\t\tassertThat(entity.getId()).isOne();\n\t\tassertThat(entity.getName()).isEqualTo(\"John\");\n\t}\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithEmbeddedDefault() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).isEqualTo(\"H2\");\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleRepository() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleRepository.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link JdbcTest#properties properties} attribute of\n * {@link JdbcTest @JdbcTest}.\n *\n * @author Artsiom Yudovin\n */\n@JdbcTest(properties = \"spring.profiles.active=test\")\nclass JdbcTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(JdbcTestPropertiesIntegrationTests.this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.AUTO_CONFIGURED,\n\t\tconnection = EmbeddedDatabaseConnection.HSQLDB)\nclass JdbcTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesAutoConfiguredDataSource() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration // Will auto-configure H2\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredWithoutOverrideIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.AUTO_CONFIGURED)\nclass JdbcTestWithAutoConfigureTestDatabaseReplaceAutoConfiguredWithoutOverrideIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid usesDefaultEmbeddedDatabase() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\t// @AutoConfigureTestDatabase would use H2 but HSQL is manually defined\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplaceExplicitIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.HSQLDB)\nclass JdbcTestWithAutoConfigureTestDatabaseReplaceExplicitIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithExplicit() throws Exception {\n\t\t// H2 is explicitly defined but HSQL is the override.\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration\n\tstatic class Config {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplaceNoneIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)\nclass JdbcTestWithAutoConfigureTestDatabaseReplaceNoneIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid usesDefaultEmbeddedDatabase() throws Exception {\n\t\t// HSQL is explicitly defined and should not be replaced\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplacePropertyAnyIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.HSQLDB)\n@TestPropertySource(properties = \"spring.test.database.replace=ANY\")\nclass JdbcTestWithAutoConfigureTestDatabaseReplacePropertyAnyIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesDefinedDataSourceWithExplicit() throws Exception {\n\t\t// H2 is explicitly defined but HSQL is the override.\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration\n\tstatic class Config {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplacePropertyAutoConfiguredIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.HSQLDB)\n@TestPropertySource(properties = \"spring.test.database.replace=AUTO_CONFIGURED\")\nclass JdbcTestWithAutoConfigureTestDatabaseReplacePropertyAutoConfiguredIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesAutoConfiguredDataSource() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration // Will auto-configure H2\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithAutoConfigureTestDatabaseReplacePropertyNoneIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcTest @JdbcTest}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@JdbcTest\n@TestPropertySource(properties = \"spring.test.database.replace=NONE\")\nclass JdbcTestWithAutoConfigureTestDatabaseReplacePropertyNoneIntegrationTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid usesDefaultEmbeddedDatabase() throws Exception {\n\t\t// HSQL is explicitly defined and should not be replaced\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/JdbcTestWithIncludeFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test with custom include filter for {@link JdbcTest @JdbcTest}.\n *\n * @author Stephane Nicoll\n */\n@JdbcTest(includeFilters = @Filter(Repository.class))\n@TestPropertySource(\n\t\tproperties = \"spring.sql.init.schemaLocations=classpath:org/springframework/boot/jdbc/test/autoconfigure/schema.sql\")\nclass JdbcTestWithIncludeFilterIntegrationTests {\n\n\t@Autowired\n\tprivate ExampleRepository repository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tthis.repository.save(new ExampleEntity(42, \"Smith\"));\n\t\tExampleEntity entity = this.repository.findById(42);\n\t\tassertThat(entity).isNotNull();\n\t\tassertThat(entity.getName()).isEqualTo(\"Smith\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/TestDatabaseAutoConfigurationNoEmbeddedTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Specific tests for {@link TestDatabaseAutoConfiguration} when no embedded database is\n * available.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\n@ClassPathExclusions({ \"h2-*.jar\", \"hsqldb-*.jar\", \"derby-*.jar\" })\nclass TestDatabaseAutoConfigurationNoEmbeddedTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(ExistingDataSourceConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(TestDatabaseAutoConfiguration.class));\n\n\t@Test\n\tvoid applyAnyReplace() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getFailure()\n\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t.hasMessageContaining(\"Failed to replace DataSource with an embedded database for tests.\")\n\t\t\t.hasMessageContaining(\"If you want an embedded database please put a supported one on the classpath\")\n\t\t\t.hasMessageContaining(\"or tune the replace attribute of @AutoConfigureTestDatabase.\"));\n\t}\n\n\t@Test\n\tvoid applyNoReplace() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.test.database.replace=NONE\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DataSource.class);\n\t\t\tassertThat(context).getBean(DataSource.class).isSameAs(context.getBean(\"myCustomDataSource\"));\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExistingDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource myCustomDataSource() {\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/java/org/springframework/boot/jdbc/test/autoconfigure/TestDatabaseAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jdbc.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.test.autoconfigure.TestDatabaseAutoConfiguration.EmbeddedDataSourceFactoryBean;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestDatabaseAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass TestDatabaseAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(TestDatabaseAutoConfiguration.class));\n\n\t@Test\n\tvoid replaceWithNoDataSourceAvailable() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(DataSource.class));\n\t}\n\n\t@Test\n\tvoid replaceWithUniqueDatabase() {\n\t\tthis.contextRunner.withUserConfiguration(ExistingDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(EmbeddedDataSourceFactoryBean.class);\n\t\t\tDataSource datasource = context.getBean(DataSource.class);\n\t\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(datasource);\n\t\t\tjdbcTemplate.execute(\"create table example (id int, name varchar);\");\n\t\t\tthis.contextRunner.withUserConfiguration(ExistingDataSourceConfiguration.class).run((secondContext) -> {\n\t\t\t\tDataSource anotherDatasource = secondContext.getBean(DataSource.class);\n\t\t\t\tJdbcTemplate anotherJdbcTemplate = new JdbcTemplate(anotherDatasource);\n\t\t\t\tanotherJdbcTemplate.execute(\"create table example (id int, name varchar);\");\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUsingAotGeneratedArtifactsEmbeddedDataSourceFactoryBeanIsNotDefined() {\n\t\tthis.contextRunner.withUserConfiguration(ExistingDataSourceConfiguration.class)\n\t\t\t.withSystemProperties(\"spring.aot.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(EmbeddedDataSourceFactoryBean.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExistingDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jdbc-test/src/test/resources/org/springframework/boot/jdbc/test/autoconfigure/schema.sql",
    "content": "create table example (id int, name varchar);\n"
  },
  {
    "path": "module/spring-boot-jersey/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Jersey\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-servlet\"))\n\tapi(\"org.glassfish.jersey.containers:jersey-container-servlet\")\n\tapi(\"org.glassfish.jersey.core:jersey-server\")\n\tapi(\"org.glassfish.jersey.ext:jersey-spring6\")\n\tapi(\"org.glassfish.jersey.media:jersey-media-json-jackson\")\n\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\timplementation(\"org.springframework:spring-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"org.glassfish.jersey.ext:jersey-micrometer\")\n\n\ttestFixturesApi(testFixtures(project(\":module:spring-boot-actuator\")))\n\ttestFixturesImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestFixturesRuntimeOnly(project(\":module:spring-boot-jackson2\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-actuator-autoconfigure\")))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/actuate/endpoint/web/JerseyEndpointResourceFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.actuate.endpoint.web;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.security.Principal;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport jakarta.ws.rs.HttpMethod;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.core.MultivaluedMap;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\nimport org.glassfish.jersey.process.Inflector;\nimport org.glassfish.jersey.server.ContainerRequest;\nimport org.glassfish.jersey.server.model.Resource;\nimport org.glassfish.jersey.server.model.Resource.Builder;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A factory for creating Jersey {@link Resource Resources} for {@link WebOperation web\n * endpoint operations}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class JerseyEndpointResourceFactory {\n\n\t/**\n\t * Creates {@link Resource Resources} for the operations of the given\n\t * {@code webEndpoints}.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param endpointMediaTypes media types consumed and produced by the endpoints\n\t * @param linksResolver resolver for determining links to available endpoints\n\t * @param shouldRegisterLinks should register links\n\t * @return the resources for the operations\n\t */\n\tpublic Collection<Resource> createEndpointResources(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,\n\t\t\tEndpointLinksResolver linksResolver, boolean shouldRegisterLinks) {\n\t\tList<Resource> resources = new ArrayList<>();\n\t\tendpoints.stream()\n\t\t\t.flatMap((endpoint) -> endpoint.getOperations().stream())\n\t\t\t.map((operation) -> createResource(endpointMapping, operation))\n\t\t\t.forEach(resources::add);\n\t\tif (shouldRegisterLinks) {\n\t\t\tResource resource = createEndpointLinksResource(endpointMapping.getPath(), endpointMediaTypes,\n\t\t\t\t\tlinksResolver);\n\t\t\tresources.add(resource);\n\t\t}\n\t\treturn resources;\n\t}\n\n\tprotected Resource createResource(EndpointMapping endpointMapping, WebOperation operation) {\n\t\tWebOperationRequestPredicate requestPredicate = operation.getRequestPredicate();\n\t\tString path = requestPredicate.getPath();\n\t\tString matchAllRemainingPathSegmentsVariable = requestPredicate.getMatchAllRemainingPathSegmentsVariable();\n\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\tpath = path.replace(\"{*\" + matchAllRemainingPathSegmentsVariable + \"}\",\n\t\t\t\t\t\"{\" + matchAllRemainingPathSegmentsVariable + \": .*}\");\n\t\t}\n\t\treturn getResource(endpointMapping, operation, requestPredicate, path, null, null);\n\t}\n\n\tprotected Resource getResource(EndpointMapping endpointMapping, WebOperation operation,\n\t\t\tWebOperationRequestPredicate requestPredicate, String path, @Nullable WebServerNamespace serverNamespace,\n\t\t\t@Nullable JerseyRemainingPathSegmentProvider remainingPathSegmentProvider) {\n\t\tBuilder resourceBuilder = Resource.builder()\n\t\t\t.path(endpointMapping.getPath())\n\t\t\t.path(endpointMapping.createSubPath(path));\n\t\tresourceBuilder.addMethod(requestPredicate.getHttpMethod().name())\n\t\t\t.consumes(StringUtils.toStringArray(requestPredicate.getConsumes()))\n\t\t\t.produces(StringUtils.toStringArray(requestPredicate.getProduces()))\n\t\t\t.handledBy(new OperationInflector(operation, !requestPredicate.getConsumes().isEmpty(), serverNamespace,\n\t\t\t\t\tremainingPathSegmentProvider));\n\t\treturn resourceBuilder.build();\n\t}\n\n\tprivate Resource createEndpointLinksResource(String endpointPath, EndpointMediaTypes endpointMediaTypes,\n\t\t\tEndpointLinksResolver linksResolver) {\n\t\tBuilder resourceBuilder = Resource.builder().path(endpointPath);\n\t\tresourceBuilder.addMethod(\"GET\")\n\t\t\t.produces(StringUtils.toStringArray(endpointMediaTypes.getProduced()))\n\t\t\t.handledBy(new EndpointLinksInflector(linksResolver));\n\t\treturn resourceBuilder.build();\n\t}\n\n\t/**\n\t * {@link Inflector} to invoke the {@link WebOperation}.\n\t */\n\tprivate static final class OperationInflector implements Inflector<ContainerRequestContext, Object> {\n\n\t\tprivate static final String PATH_SEPARATOR = AntPathMatcher.DEFAULT_PATH_SEPARATOR;\n\n\t\tprivate static final List<Function<@Nullable Object, @Nullable Object>> BODY_CONVERTERS;\n\n\t\tstatic {\n\t\t\tList<Function<@Nullable Object, @Nullable Object>> converters = new ArrayList<>();\n\t\t\tconverters.add(new ResourceBodyConverter());\n\t\t\tif (ClassUtils.isPresent(\"reactor.core.publisher.Mono\", OperationInflector.class.getClassLoader())) {\n\t\t\t\tconverters.add(new FluxBodyConverter());\n\t\t\t\tconverters.add(new MonoBodyConverter());\n\t\t\t}\n\t\t\tBODY_CONVERTERS = Collections.unmodifiableList(converters);\n\t\t}\n\n\t\tprivate final WebOperation operation;\n\n\t\tprivate final boolean readBody;\n\n\t\tprivate final @Nullable WebServerNamespace serverNamespace;\n\n\t\tprivate final @Nullable JerseyRemainingPathSegmentProvider remainingPathSegmentProvider;\n\n\t\tprivate OperationInflector(WebOperation operation, boolean readBody,\n\t\t\t\t@Nullable WebServerNamespace serverNamespace,\n\t\t\t\t@Nullable JerseyRemainingPathSegmentProvider remainingPathSegments) {\n\t\t\tthis.operation = operation;\n\t\t\tthis.readBody = readBody;\n\t\t\tthis.serverNamespace = serverNamespace;\n\t\t\tthis.remainingPathSegmentProvider = remainingPathSegments;\n\t\t}\n\n\t\t@Override\n\t\tpublic Response apply(ContainerRequestContext data) {\n\t\t\tMap<String, Object> arguments = new HashMap<>();\n\t\t\tif (this.readBody) {\n\t\t\t\targuments.putAll(extractBodyArguments(data));\n\t\t\t}\n\t\t\targuments.putAll(extractPathParameters(data));\n\t\t\targuments.putAll(extractQueryParameters(data));\n\t\t\ttry {\n\t\t\t\tJerseySecurityContext securityContext = new JerseySecurityContext(data.getSecurityContext());\n\t\t\t\tOperationArgumentResolver serverNamespaceArgumentResolver = OperationArgumentResolver\n\t\t\t\t\t.of(WebServerNamespace.class, () -> this.serverNamespace);\n\t\t\t\tInvocationContext invocationContext = new InvocationContext(securityContext, arguments,\n\t\t\t\t\t\tserverNamespaceArgumentResolver,\n\t\t\t\t\t\tnew ProducibleOperationArgumentResolver(() -> data.getHeaders().get(\"Accept\")));\n\t\t\t\tObject response = this.operation.invoke(invocationContext);\n\t\t\t\treturn convertToJaxRsResponse(response, data.getRequest().getMethod());\n\t\t\t}\n\t\t\tcatch (InvalidEndpointRequestException ex) {\n\t\t\t\treturn Response.status(Status.BAD_REQUEST).build();\n\t\t\t}\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate Map<String, String> extractBodyArguments(ContainerRequestContext data) {\n\t\t\tMap<String, String> entity = ((ContainerRequest) data).readEntity(Map.class,\n\t\t\t\t\tnew ParameterizedTypeReference<Map<String, String>>() {\n\t\t\t\t\t}.getType());\n\t\t\treturn (entity != null) ? entity : Collections.emptyMap();\n\t\t}\n\n\t\tprivate Map<String, Object> extractPathParameters(ContainerRequestContext requestContext) {\n\t\t\tMap<String, Object> pathParameters = extract(requestContext.getUriInfo().getPathParameters());\n\t\t\tString matchAllRemainingPathSegmentsVariable = this.operation.getRequestPredicate()\n\t\t\t\t.getMatchAllRemainingPathSegmentsVariable();\n\t\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\t\tString remainingPathSegments = getRemainingPathSegments(requestContext, pathParameters,\n\t\t\t\t\t\tmatchAllRemainingPathSegmentsVariable);\n\t\t\t\tpathParameters.put(matchAllRemainingPathSegmentsVariable, tokenizePathSegments(remainingPathSegments));\n\t\t\t}\n\t\t\treturn pathParameters;\n\t\t}\n\n\t\tprivate @Nullable String getRemainingPathSegments(ContainerRequestContext requestContext,\n\t\t\t\tMap<String, Object> pathParameters, String matchAllRemainingPathSegmentsVariable) {\n\t\t\tif (this.remainingPathSegmentProvider != null) {\n\t\t\t\treturn this.remainingPathSegmentProvider.get(requestContext, matchAllRemainingPathSegmentsVariable);\n\t\t\t}\n\t\t\treturn (String) pathParameters.get(matchAllRemainingPathSegmentsVariable);\n\t\t}\n\n\t\tprivate String[] tokenizePathSegments(@Nullable String path) {\n\t\t\tString[] segments = StringUtils.tokenizeToStringArray(path, PATH_SEPARATOR, false, true);\n\t\t\tfor (int i = 0; i < segments.length; i++) {\n\t\t\t\tif (segments[i].contains(\"%\")) {\n\t\t\t\t\tsegments[i] = StringUtils.uriDecode(segments[i], StandardCharsets.UTF_8);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn segments;\n\t\t}\n\n\t\tprivate Map<String, Object> extractQueryParameters(ContainerRequestContext requestContext) {\n\t\t\treturn extract(requestContext.getUriInfo().getQueryParameters());\n\t\t}\n\n\t\tprivate Map<String, Object> extract(MultivaluedMap<String, String> multivaluedMap) {\n\t\t\tMap<String, Object> result = new HashMap<>();\n\t\t\tmultivaluedMap.forEach((name, values) -> {\n\t\t\t\tif (!CollectionUtils.isEmpty(values)) {\n\t\t\t\t\tresult.put(name, (values.size() != 1) ? values : values.get(0));\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate Response convertToJaxRsResponse(@Nullable Object response, String httpMethod) {\n\t\t\tif (response == null) {\n\t\t\t\tboolean isGet = HttpMethod.GET.equals(httpMethod);\n\t\t\t\tStatus status = isGet ? Status.NOT_FOUND : Status.NO_CONTENT;\n\t\t\t\treturn Response.status(status).build();\n\t\t\t}\n\t\t\tif (!(response instanceof WebEndpointResponse<?> webEndpointResponse)) {\n\t\t\t\treturn Response.status(Status.OK).entity(convertIfNecessary(response)).build();\n\t\t\t}\n\t\t\treturn Response.status(webEndpointResponse.getStatus())\n\t\t\t\t.header(\"Content-Type\", webEndpointResponse.getContentType())\n\t\t\t\t.entity(convertIfNecessary(webEndpointResponse.getBody()))\n\t\t\t\t.build();\n\t\t}\n\n\t\tprivate @Nullable Object convertIfNecessary(@Nullable Object body) {\n\t\t\tfor (Function<@Nullable Object, @Nullable Object> converter : BODY_CONVERTERS) {\n\t\t\t\tbody = converter.apply(body);\n\t\t\t}\n\t\t\treturn body;\n\t\t}\n\n\t}\n\n\t/**\n\t * Body converter from {@link org.springframework.core.io.Resource} to\n\t * {@link InputStream}.\n\t */\n\tprivate static final class ResourceBodyConverter implements Function<Object, Object> {\n\n\t\t@Override\n\t\tpublic Object apply(Object body) {\n\t\t\tif (body instanceof org.springframework.core.io.Resource) {\n\t\t\t\ttry {\n\t\t\t\t\treturn ((org.springframework.core.io.Resource) body).getInputStream();\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\tthrow new IllegalStateException();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn body;\n\t\t}\n\n\t}\n\n\t/**\n\t * Body converter from {@link Mono} to {@link Mono#block()}.\n\t */\n\tprivate static final class MonoBodyConverter implements Function<@Nullable Object, @Nullable Object> {\n\n\t\t@Override\n\t\tpublic @Nullable Object apply(@Nullable Object body) {\n\t\t\tif (body instanceof Mono) {\n\t\t\t\treturn ((Mono<?>) body).block();\n\t\t\t}\n\t\t\treturn body;\n\t\t}\n\n\t}\n\n\t/**\n\t * Body converter from {@link Flux} to {@link Flux#collectList Mono&lt;List&gt;}.\n\t */\n\tprivate static final class FluxBodyConverter implements Function<@Nullable Object, @Nullable Object> {\n\n\t\t@Override\n\t\tpublic @Nullable Object apply(@Nullable Object body) {\n\t\t\tif (body instanceof Flux) {\n\t\t\t\treturn ((Flux<?>) body).collectList();\n\t\t\t}\n\t\t\treturn body;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Inflector} to for endpoint links.\n\t */\n\tprivate static final class EndpointLinksInflector implements Inflector<ContainerRequestContext, Response> {\n\n\t\tprivate final EndpointLinksResolver linksResolver;\n\n\t\tprivate EndpointLinksInflector(EndpointLinksResolver linksResolver) {\n\t\t\tthis.linksResolver = linksResolver;\n\t\t}\n\n\t\t@Override\n\t\tpublic Response apply(ContainerRequestContext request) {\n\t\t\tMap<String, Link> links = this.linksResolver\n\t\t\t\t.resolveLinks(request.getUriInfo().getAbsolutePath().toString());\n\t\t\tMap<String, Map<String, Link>> entity = OperationResponseBody.of(Collections.singletonMap(\"_links\", links));\n\t\t\treturn Response.ok(entity).build();\n\t\t}\n\n\t}\n\n\tprivate static final class JerseySecurityContext implements SecurityContext {\n\n\t\tprivate final jakarta.ws.rs.core.SecurityContext securityContext;\n\n\t\tprivate JerseySecurityContext(jakarta.ws.rs.core.SecurityContext securityContext) {\n\t\t\tthis.securityContext = securityContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic Principal getPrincipal() {\n\t\t\treturn this.securityContext.getUserPrincipal();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isUserInRole(String role) {\n\t\t\treturn this.securityContext.isUserInRole(role);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/actuate/endpoint/web/JerseyHealthEndpointAdditionalPathResourceFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.actuate.endpoint.web;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport org.glassfish.jersey.server.model.Resource;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\n\n/**\n * A factory for creating Jersey {@link Resource Resources} for health groups with\n * additional path.\n *\n * @author Madhura Bhave\n * @since 2.6.0\n */\npublic final class JerseyHealthEndpointAdditionalPathResourceFactory {\n\n\tprivate final JerseyEndpointResourceFactory delegate = new JerseyEndpointResourceFactory();\n\n\tprivate final Set<HealthEndpointGroup> groups;\n\n\tprivate final WebServerNamespace serverNamespace;\n\n\tpublic JerseyHealthEndpointAdditionalPathResourceFactory(WebServerNamespace serverNamespace,\n\t\t\tHealthEndpointGroups groups) {\n\t\tthis.serverNamespace = serverNamespace;\n\t\tthis.groups = groups.getAllWithAdditionalPath(serverNamespace);\n\t}\n\n\tpublic Collection<Resource> createEndpointResources(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints) {\n\t\treturn endpoints.stream()\n\t\t\t.flatMap((endpoint) -> endpoint.getOperations().stream())\n\t\t\t.flatMap((operation) -> createResources(endpointMapping, operation))\n\t\t\t.toList();\n\t}\n\n\tprivate Stream<Resource> createResources(EndpointMapping endpointMapping, WebOperation operation) {\n\t\tWebOperationRequestPredicate requestPredicate = operation.getRequestPredicate();\n\t\tString matchAllRemainingPathSegmentsVariable = requestPredicate.getMatchAllRemainingPathSegmentsVariable();\n\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\tList<Resource> resources = new ArrayList<>();\n\t\t\tfor (HealthEndpointGroup group : this.groups) {\n\t\t\t\tAdditionalHealthEndpointPath additionalPath = group.getAdditionalPath();\n\t\t\t\tif (additionalPath != null) {\n\t\t\t\t\tresources.add(this.delegate.getResource(endpointMapping, operation, requestPredicate,\n\t\t\t\t\t\t\tadditionalPath.getValue(), this.serverNamespace,\n\t\t\t\t\t\t\t(data, pathSegmentsVariable) -> data.getUriInfo().getPath()));\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resources.stream();\n\t\t}\n\t\treturn Stream.empty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/actuate/endpoint/web/JerseyRemainingPathSegmentProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.actuate.endpoint.web;\n\nimport jakarta.ws.rs.container.ContainerRequestContext;\n\n/**\n * Strategy interface used to provide the remaining path segments for a Jersey actuator\n * endpoint.\n *\n * @author Madhura Bhave\n */\ninterface JerseyRemainingPathSegmentProvider {\n\n\tString get(ContainerRequestContext requestContext, String matchAllRemainingPathSegmentsVariable);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Jersey support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.jersey.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/DefaultJerseyApplicationPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.StringUtils;\n\n/**\n * Default implementation of {@link JerseyApplicationPath} that derives the path from\n * {@link JerseyProperties} or the {@code @ApplicationPath} annotation.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class DefaultJerseyApplicationPath implements JerseyApplicationPath {\n\n\tprivate final @Nullable String applicationPath;\n\n\tprivate final ResourceConfig config;\n\n\tpublic DefaultJerseyApplicationPath(@Nullable String applicationPath, ResourceConfig config) {\n\t\tthis.applicationPath = applicationPath;\n\t\tthis.config = config;\n\t}\n\n\t@Override\n\tpublic String getPath() {\n\t\treturn resolveApplicationPath();\n\t}\n\n\tprivate String resolveApplicationPath() {\n\t\tif (StringUtils.hasLength(this.applicationPath)) {\n\t\t\treturn this.applicationPath;\n\t\t}\n\t\t// Jersey doesn't like to be the default servlet, so map to /* as a fallback\n\t\treturn MergedAnnotations.from(this.config.getApplication().getClass(), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(ApplicationPath.class)\n\t\t\t.getValue(MergedAnnotation.VALUE, String.class)\n\t\t\t.orElse(\"/*\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/JerseyApplicationPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\n\n/**\n * Interface that can be used by auto-configurations that need path details Jersey's\n * application path that serves as the base URI for the application.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface JerseyApplicationPath {\n\n\t/**\n\t * Returns the configured path of the application.\n\t * @return the configured path\n\t */\n\tString getPath();\n\n\t/**\n\t * Return a form of the given path that's relative to the Jersey application path.\n\t * @param path the path to make relative\n\t * @return the relative path\n\t */\n\tdefault String getRelativePath(String path) {\n\t\tString prefix = getPrefix();\n\t\tif (!path.startsWith(\"/\")) {\n\t\t\tpath = \"/\" + path;\n\t\t}\n\t\treturn prefix + path;\n\t}\n\n\t/**\n\t * Return a cleaned up version of the path that can be used as a prefix for URLs. The\n\t * resulting path will have path will not have a trailing slash.\n\t * @return the prefix\n\t * @see #getRelativePath(String)\n\t */\n\tdefault String getPrefix() {\n\t\tString result = getPath();\n\t\tint index = result.indexOf('*');\n\t\tif (index != -1) {\n\t\t\tresult = result.substring(0, index);\n\t\t}\n\t\tif (result.endsWith(\"/\")) {\n\t\t\tresult = result.substring(0, result.length() - 1);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return a URL mapping pattern that can be used with a\n\t * {@link ServletRegistrationBean} to map Jersey's servlet.\n\t * @return the path as a servlet URL mapping\n\t */\n\tdefault String getUrlMapping() {\n\t\tString path = getPath();\n\t\tif (!path.startsWith(\"/\")) {\n\t\t\tpath = \"/\" + path;\n\t\t}\n\t\tif (path.equals(\"/\")) {\n\t\t\treturn \"/*\";\n\t\t}\n\t\tif (path.contains(\"*\")) {\n\t\t\treturn path;\n\t\t}\n\t\tif (path.endsWith(\"/\")) {\n\t\t\treturn path + \"*\";\n\t\t}\n\t\treturn path + \"/*\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration;\nimport jakarta.ws.rs.ext.ContextResolver;\nimport jakarta.xml.bind.annotation.XmlElement;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.glassfish.jersey.jackson.JacksonFeature;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.server.spring.SpringComponentProvider;\nimport org.glassfish.jersey.servlet.ServletContainer;\nimport org.glassfish.jersey.servlet.ServletProperties;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.DynamicRegistrationBean;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.WebApplicationInitializer;\nimport org.springframework.web.context.ServletContextAware;\nimport org.springframework.web.filter.RequestContextFilter;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Jersey.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\" })\n@ConditionalOnClass({ SpringComponentProvider.class, ServletRegistration.class })\n@ConditionalOnBean(type = \"org.glassfish.jersey.server.ResourceConfig\")\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)\n@EnableConfigurationProperties(JerseyProperties.class)\npublic final class JerseyAutoConfiguration implements ServletContextAware {\n\n\tprivate static final Log logger = LogFactory.getLog(JerseyAutoConfiguration.class);\n\n\tprivate final JerseyProperties jersey;\n\n\tprivate final ResourceConfig config;\n\n\tJerseyAutoConfiguration(JerseyProperties jersey, ResourceConfig config,\n\t\t\tObjectProvider<ResourceConfigCustomizer> customizers) {\n\t\tthis.jersey = jersey;\n\t\tthis.config = config;\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(this.config));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingFilterBean\n\tFilterRegistrationBean<RequestContextFilter> requestContextFilter() {\n\t\tFilterRegistrationBean<RequestContextFilter> registration = new FilterRegistrationBean<>();\n\t\tregistration.setFilter(new RequestContextFilter());\n\t\tregistration.setOrder(this.jersey.getFilter().getOrder() - 1);\n\t\tregistration.setName(\"requestContextFilter\");\n\t\treturn registration;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJerseyApplicationPath jerseyApplicationPath() {\n\t\treturn new DefaultJerseyApplicationPath(this.jersey.getApplicationPath(), this.config);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"jerseyFilterRegistration\")\n\t@ConditionalOnProperty(name = \"spring.jersey.type\", havingValue = \"filter\")\n\tFilterRegistrationBean<ServletContainer> jerseyFilterRegistration(JerseyApplicationPath applicationPath) {\n\t\tFilterRegistrationBean<ServletContainer> registration = new FilterRegistrationBean<>();\n\t\tregistration.setFilter(new ServletContainer(this.config));\n\t\tregistration.setUrlPatterns(Collections.singletonList(applicationPath.getUrlMapping()));\n\t\tregistration.setOrder(this.jersey.getFilter().getOrder());\n\t\tregistration.addInitParameter(ServletProperties.FILTER_CONTEXT_PATH, stripPattern(applicationPath.getPath()));\n\t\taddInitParameters(registration);\n\t\tregistration.setName(\"jerseyFilter\");\n\t\tregistration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));\n\t\treturn registration;\n\t}\n\n\tprivate String stripPattern(String path) {\n\t\tif (path.endsWith(\"/*\")) {\n\t\t\tpath = path.substring(0, path.lastIndexOf(\"/*\"));\n\t\t}\n\t\treturn path;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"jerseyServletRegistration\")\n\t@ConditionalOnProperty(name = \"spring.jersey.type\", havingValue = \"servlet\", matchIfMissing = true)\n\tServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplicationPath applicationPath) {\n\t\tServletRegistrationBean<ServletContainer> registration = new ServletRegistrationBean<>(\n\t\t\t\tnew ServletContainer(this.config), applicationPath.getUrlMapping());\n\t\taddInitParameters(registration);\n\t\tregistration.setName(getServletRegistrationName());\n\t\tregistration.setLoadOnStartup(this.jersey.getServlet().getLoadOnStartup());\n\t\tregistration.setIgnoreRegistrationFailure(true);\n\t\treturn registration;\n\t}\n\n\tprivate String getServletRegistrationName() {\n\t\treturn ClassUtils.getUserClass(this.config.getClass()).getName();\n\t}\n\n\tprivate void addInitParameters(DynamicRegistrationBean<?> registration) {\n\t\tthis.jersey.getInit().forEach(registration::addInitParameter);\n\t}\n\n\t@Override\n\tpublic void setServletContext(ServletContext servletContext) {\n\t\tString servletRegistrationName = getServletRegistrationName();\n\t\tServletRegistration registration = servletContext.getServletRegistration(servletRegistrationName);\n\t\tif (registration != null) {\n\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\tlogger.info(\"Configuring existing registration for Jersey servlet '\" + servletRegistrationName + \"'\");\n\t\t\t}\n\t\t\tregistration.setInitParameters(this.jersey.getInit());\n\t\t}\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tpublic static final class JerseyWebApplicationInitializer implements WebApplicationInitializer {\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) throws ServletException {\n\t\t\tif (ClassUtils.isPresent(\"org.glassfish.jersey.server.spring.SpringWebApplicationInitializer\",\n\t\t\t\t\tgetClass().getClassLoader())) {\n\t\t\t\t// We need to switch *off* the Jersey WebApplicationInitializer because it\n\t\t\t\t// will try and register a ContextLoaderListener which we don't need\n\t\t\t\tservletContext.setInitParameter(\"contextConfigLocation\", \"<NONE>\");\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JacksonFeature.class)\n\t@ConditionalOnSingleCandidate(com.fasterxml.jackson.databind.ObjectMapper.class)\n\tstatic class Jackson2ResourceConfigCustomizerConfiguration {\n\n\t\t@Bean\n\t\tResourceConfigCustomizer jacksonResourceConfigCustomizer(\n\t\t\t\tcom.fasterxml.jackson.databind.ObjectMapper objectMapper) {\n\t\t\treturn (ResourceConfig config) -> {\n\t\t\t\tconfig.register(JacksonFeature.class);\n\t\t\t\tconfig.register(new ObjectMapperContextResolver(objectMapper), ContextResolver.class);\n\t\t\t};\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass({ com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector.class,\n\t\t\t\tXmlElement.class })\n\t\tstatic class JaxbJackson2ObjectMapperCustomizerConfiguration {\n\n\t\t\t@Autowired\n\t\t\tvoid addJaxbAnnotationIntrospector(com.fasterxml.jackson.databind.ObjectMapper objectMapper) {\n\t\t\t\tcom.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector = new com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector(\n\t\t\t\t\t\tobjectMapper.getTypeFactory());\n\t\t\t\tobjectMapper.setAnnotationIntrospectors(\n\t\t\t\t\t\tcreatePair(objectMapper.getSerializationConfig(), jaxbAnnotationIntrospector),\n\t\t\t\t\t\tcreatePair(objectMapper.getDeserializationConfig(), jaxbAnnotationIntrospector));\n\t\t\t}\n\n\t\t\tprivate com.fasterxml.jackson.databind.AnnotationIntrospector createPair(\n\t\t\t\t\tcom.fasterxml.jackson.databind.cfg.MapperConfig<?> config,\n\t\t\t\t\tcom.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector jaxbAnnotationIntrospector) {\n\t\t\t\treturn com.fasterxml.jackson.databind.AnnotationIntrospector.pair(config.getAnnotationIntrospector(),\n\t\t\t\t\t\tjaxbAnnotationIntrospector);\n\t\t\t}\n\n\t\t}\n\n\t\tprivate static final class ObjectMapperContextResolver\n\t\t\t\timplements ContextResolver<com.fasterxml.jackson.databind.ObjectMapper> {\n\n\t\t\tprivate final com.fasterxml.jackson.databind.ObjectMapper objectMapper;\n\n\t\t\tprivate ObjectMapperContextResolver(com.fasterxml.jackson.databind.ObjectMapper objectMapper) {\n\t\t\t\tthis.objectMapper = objectMapper;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic com.fasterxml.jackson.databind.ObjectMapper getContext(Class<?> type) {\n\t\t\t\treturn this.objectMapper;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/JerseyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for Jersey.\n *\n * @author Dave Syer\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jersey\")\npublic class JerseyProperties {\n\n\t/**\n\t * Jersey integration type.\n\t */\n\tprivate Type type = Type.SERVLET;\n\n\t/**\n\t * Init parameters to pass to Jersey through the servlet or filter.\n\t */\n\tprivate Map<String, String> init = new HashMap<>();\n\n\tprivate final Filter filter = new Filter();\n\n\tprivate final Servlet servlet = new Servlet();\n\n\t/**\n\t * Path that serves as the base URI for the application. If specified, overrides the\n\t * value of \"@ApplicationPath\".\n\t */\n\tprivate @Nullable String applicationPath;\n\n\tpublic Filter getFilter() {\n\t\treturn this.filter;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic Type getType() {\n\t\treturn this.type;\n\t}\n\n\tpublic void setType(Type type) {\n\t\tthis.type = type;\n\t}\n\n\tpublic Map<String, String> getInit() {\n\t\treturn this.init;\n\t}\n\n\tpublic void setInit(Map<String, String> init) {\n\t\tthis.init = init;\n\t}\n\n\tpublic @Nullable String getApplicationPath() {\n\t\treturn this.applicationPath;\n\t}\n\n\tpublic void setApplicationPath(@Nullable String applicationPath) {\n\t\tthis.applicationPath = applicationPath;\n\t}\n\n\tpublic enum Type {\n\n\t\tSERVLET, FILTER\n\n\t}\n\n\tpublic static class Filter {\n\n\t\t/**\n\t\t * Jersey filter chain order.\n\t\t */\n\t\tprivate int order;\n\n\t\tpublic int getOrder() {\n\t\t\treturn this.order;\n\t\t}\n\n\t\tpublic void setOrder(int order) {\n\t\t\tthis.order = order;\n\t\t}\n\n\t}\n\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Load on startup priority of the Jersey servlet.\n\t\t */\n\t\tprivate int loadOnStartup = -1;\n\n\t\tpublic int getLoadOnStartup() {\n\t\t\treturn this.loadOnStartup;\n\t\t}\n\n\t\tpublic void setLoadOnStartup(int loadOnStartup) {\n\t\t\tthis.loadOnStartup = loadOnStartup;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/ResourceConfigCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize Jersey's\n * {@link ResourceConfig} before it is used.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ResourceConfigCustomizer {\n\n\t/**\n\t * Customize the resource config.\n\t * @param config the {@link ResourceConfig} to customize\n\t */\n\tvoid customize(ResourceConfig config);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/HealthEndpointJerseyExtensionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Objects;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.server.model.Resource;\nimport org.glassfish.jersey.servlet.ServletContainer;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.jersey.actuate.endpoint.web.JerseyHealthEndpointAdditionalPathResourceFactory;\nimport org.springframework.boot.jersey.autoconfigure.DefaultJerseyApplicationPath;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.jersey.autoconfigure.JerseyProperties;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Auto-Configuration for {@link HealthEndpoint} Jersey extension.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 4.0.0\n * @see HealthEndpointAutoConfiguration\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnBean(HealthEndpoint.class)\n@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\n@ConditionalOnMissingClass(\"org.springframework.web.servlet.DispatcherServlet\")\npublic final class HealthEndpointJerseyExtensionAutoConfiguration {\n\n\t@Bean\n\tJerseyAdditionalHealthEndpointPathsResourcesRegistrar jerseyAdditionalHealthEndpointPathsResourcesRegistrar(\n\t\t\tWebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {\n\t\tExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);\n\t\treturn new JerseyAdditionalHealthEndpointPathsResourcesRegistrar(health, healthEndpointGroups);\n\t}\n\n\tprivate static @Nullable ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {\n\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\treturn webEndpoints.stream()\n\t\t\t.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(ResourceConfig.class)\n\t@EnableConfigurationProperties(JerseyProperties.class)\n\tstatic class JerseyInfrastructureConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tJerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {\n\t\t\treturn new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);\n\t\t}\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig(ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {\n\t\t\tResourceConfig resourceConfig = new ResourceConfig();\n\t\t\tresourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));\n\t\t\treturn resourceConfig;\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplicationPath jerseyApplicationPath,\n\t\t\t\tResourceConfig resourceConfig) {\n\t\t\treturn new ServletRegistrationBean<>(new ServletContainer(resourceConfig),\n\t\t\t\t\tjerseyApplicationPath.getUrlMapping());\n\t\t}\n\n\t}\n\n\tstatic class JerseyAdditionalHealthEndpointPathsResourcesRegistrar implements ResourceConfigCustomizer {\n\n\t\tprivate final @Nullable ExposableWebEndpoint endpoint;\n\n\t\tprivate final HealthEndpointGroups groups;\n\n\t\tJerseyAdditionalHealthEndpointPathsResourcesRegistrar(@Nullable ExposableWebEndpoint endpoint,\n\t\t\t\tHealthEndpointGroups groups) {\n\t\t\tthis.endpoint = endpoint;\n\t\t\tthis.groups = groups;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ResourceConfig config) {\n\t\t\tregister(config);\n\t\t}\n\n\t\tprivate void register(ResourceConfig config) {\n\t\t\tEndpointMapping mapping = new EndpointMapping(\"\");\n\t\t\tJerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(\n\t\t\t\t\tWebServerNamespace.SERVER, this.groups);\n\t\t\tCollection<Resource> endpointResources = resourceFactory\n\t\t\t\t.createEndpointResources(mapping,\n\t\t\t\t\t\t(this.endpoint != null) ? Collections.singletonList(this.endpoint) : Collections.emptyList())\n\t\t\t\t.stream()\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.toList();\n\t\t\tregister(endpointResources, config);\n\t\t}\n\n\t\tprivate void register(Collection<Resource> resources, ResourceConfig config) {\n\t\t\tconfig.registerResources(new HashSet<>(resources));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jersey actuator web endpoint support.\n */\n@NullMarked\npackage org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyChildManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey\n * infrastructure when a separate management context with a web server running on a\n * different port is required.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\n@Import(JerseyManagementContextConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ JerseyApplicationPath.class, ResourceConfig.class })\n@ConditionalOnMissingClass(\"org.springframework.web.servlet.DispatcherServlet\")\npublic class JerseyChildManagementContextConfiguration {\n\n\t@Bean\n\tpublic JerseyApplicationPath jerseyApplicationPath() {\n\t\treturn () -> \"/\";\n\t}\n\n\t@Bean\n\tResourceConfig resourceConfig(ObjectProvider<ManagementContextResourceConfigCustomizer> customizers) {\n\t\tResourceConfig resourceConfig = new ResourceConfig();\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));\n\t\treturn resourceConfig;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyEndpointManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jetty\n * endpoints.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ManagementContextConfiguration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnMissingClass(\"org.springframework.web.servlet.DispatcherServlet\")\npublic class JerseyEndpointManagementContextConfiguration {\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\tpublic org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar servletEndpointRegistrar(\n\t\t\tWebEndpointProperties properties,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,\n\t\t\tJerseyApplicationPath jerseyApplicationPath, EndpointAccessResolver endpointAccessResolver) {\n\t\treturn new org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar(\n\t\t\t\tjerseyApplicationPath.getRelativePath(properties.getBasePath()),\n\t\t\t\tservletEndpointsSupplier.getEndpoints(), endpointAccessResolver);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.servlet.ServletContainer;\n\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Shared configuration for Jersey-based actuators regardless of management context type.\n *\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\nclass JerseyManagementContextConfiguration {\n\n\t@Bean\n\tServletRegistrationBean<ServletContainer> jerseyServletRegistration(JerseyApplicationPath jerseyApplicationPath,\n\t\t\tResourceConfig resourceConfig) {\n\t\treturn new ServletRegistrationBean<>(new ServletContainer(resourceConfig),\n\t\t\t\tjerseyApplicationPath.getUrlMapping());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseySameManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jersey.autoconfigure.DefaultJerseyApplicationPath;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.jersey.autoconfigure.JerseyProperties;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey\n * infrastructure when the management context is the same as the main application context.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ManagementContextConfiguration(value = ManagementContextType.SAME, proxyBeanMethods = false)\n@EnableConfigurationProperties(JerseyProperties.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ JerseyApplicationPath.class, ResourceConfig.class })\n@ConditionalOnMissingClass(\"org.springframework.web.servlet.DispatcherServlet\")\npublic class JerseySameManagementContextConfiguration {\n\n\t@Bean\n\tResourceConfigCustomizer managementResourceConfigCustomizerAdapter(\n\t\t\tObjectProvider<ManagementContextResourceConfigCustomizer> customizers) {\n\t\treturn (config) -> customizers.orderedStream().forEach((customizer) -> customizer.customize(config));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(JerseyManagementContextConfiguration.class)\n\t@ConditionalOnMissingBean(ResourceConfig.class)\n\tstatic class JerseyInfrastructureConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tJerseyApplicationPath jerseyApplicationPath(JerseyProperties properties, ResourceConfig config) {\n\t\t\treturn new DefaultJerseyApplicationPath(properties.getApplicationPath(), config);\n\t\t}\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig(ObjectProvider<ResourceConfigCustomizer> resourceConfigCustomizers) {\n\t\t\tResourceConfig resourceConfig = new ResourceConfig();\n\t\t\tresourceConfigCustomizers.orderedStream().forEach((customizer) -> customizer.customize(resourceConfig));\n\t\t\treturn resourceConfig;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyWebEndpointManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport jakarta.annotation.Priority;\nimport jakarta.ws.rs.Priorities;\nimport jakarta.ws.rs.ext.ContextResolver;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.server.model.Resource;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;\nimport org.springframework.boot.jersey.actuate.endpoint.web.JerseyHealthEndpointAdditionalPathResourceFactory;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jersey\n * {@link Endpoint @Endpoint} concerns.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Michael Simons\n * @author Madhura Bhave\n * @author HaiTao Zhang\n */\n@ManagementContextConfiguration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(ResourceConfig.class)\n@ConditionalOnBean(WebEndpointsSupplier.class)\n@ConditionalOnMissingBean(type = \"org.springframework.web.servlet.DispatcherServlet\")\nclass JerseyWebEndpointManagementContextConfiguration {\n\n\tprivate static final EndpointId HEALTH_ENDPOINT_ID = EndpointId.of(\"health\");\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\tJerseyWebEndpointsResourcesRegistrar jerseyWebEndpointsResourcesRegistrar(Environment environment,\n\t\t\tWebEndpointsSupplier webEndpointsSupplier,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,\n\t\t\tEndpointMediaTypes endpointMediaTypes, WebEndpointProperties webEndpointProperties) {\n\t\tString basePath = webEndpointProperties.getBasePath();\n\t\tboolean shouldRegisterLinks = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);\n\t\treturn new JerseyWebEndpointsResourcesRegistrar(webEndpointsSupplier, servletEndpointsSupplier,\n\t\t\t\tendpointMediaTypes, basePath, shouldRegisterLinks);\n\t}\n\n\t@Bean\n\t@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\n\t@ConditionalOnBean(HealthEndpoint.class)\n\t@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\n\tJerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar jerseyDifferentPortAdditionalHealthEndpointPathsResourcesRegistrar(\n\t\t\tWebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups healthEndpointGroups) {\n\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\tExposableWebEndpoint healthEndpoint = webEndpoints.stream()\n\t\t\t.filter((endpoint) -> endpoint.getEndpointId().equals(HEALTH_ENDPOINT_ID))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t\treturn new JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(healthEndpoint,\n\t\t\t\thealthEndpointGroups);\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)\n\t@SuppressWarnings(\"removal\")\n\tResourceConfigCustomizer endpointJackson2ObjectMapperResourceConfigCustomizer(\n\t\t\torg.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper endpointJackson2ObjectMapper) {\n\t\treturn (config) -> config.register(\n\t\t\t\tnew EndpointJackson2ObjectMapperContextResolver(endpointJackson2ObjectMapper), ContextResolver.class);\n\t}\n\n\tprivate boolean shouldRegisterLinksMapping(WebEndpointProperties properties, Environment environment,\n\t\t\tString basePath) {\n\t\treturn properties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)\n\t\t\t\t|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));\n\t}\n\n\t/**\n\t * Register endpoints with the {@link ResourceConfig} for the management context.\n\t */\n\t@SuppressWarnings(\"removal\")\n\tstatic class JerseyWebEndpointsResourcesRegistrar implements ManagementContextResourceConfigCustomizer {\n\n\t\tprivate final WebEndpointsSupplier webEndpointsSupplier;\n\n\t\tprivate final org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier;\n\n\t\tprivate final EndpointMediaTypes mediaTypes;\n\n\t\tprivate final String basePath;\n\n\t\tprivate final boolean shouldRegisterLinks;\n\n\t\tJerseyWebEndpointsResourcesRegistrar(WebEndpointsSupplier webEndpointsSupplier,\n\t\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,\n\t\t\t\tEndpointMediaTypes endpointMediaTypes, String basePath, boolean shouldRegisterLinks) {\n\t\t\tthis.webEndpointsSupplier = webEndpointsSupplier;\n\t\t\tthis.servletEndpointsSupplier = servletEndpointsSupplier;\n\t\t\tthis.mediaTypes = endpointMediaTypes;\n\t\t\tthis.basePath = basePath;\n\t\t\tthis.shouldRegisterLinks = shouldRegisterLinks;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ResourceConfig config) {\n\t\t\tregister(config);\n\t\t}\n\n\t\tprivate void register(ResourceConfig config) {\n\t\t\tCollection<ExposableWebEndpoint> webEndpoints = this.webEndpointsSupplier.getEndpoints();\n\t\t\tCollection<org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint> servletEndpoints = this.servletEndpointsSupplier\n\t\t\t\t.getEndpoints();\n\t\t\tEndpointLinksResolver linksResolver = getLinksResolver(webEndpoints, servletEndpoints);\n\t\t\tEndpointMapping mapping = new EndpointMapping(this.basePath);\n\t\t\tCollection<Resource> endpointResources = new JerseyEndpointResourceFactory().createEndpointResources(\n\t\t\t\t\tmapping, webEndpoints, this.mediaTypes, linksResolver, this.shouldRegisterLinks);\n\t\t\tregister(endpointResources, config);\n\t\t}\n\n\t\tprivate EndpointLinksResolver getLinksResolver(Collection<ExposableWebEndpoint> webEndpoints,\n\t\t\t\tCollection<org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint> servletEndpoints) {\n\t\t\tList<ExposableEndpoint<?>> endpoints = new ArrayList<>(webEndpoints.size() + servletEndpoints.size());\n\t\t\tendpoints.addAll(webEndpoints);\n\t\t\tendpoints.addAll(servletEndpoints);\n\t\t\treturn new EndpointLinksResolver(endpoints, this.basePath);\n\t\t}\n\n\t\tprivate void register(Collection<Resource> resources, ResourceConfig config) {\n\t\t\tconfig.registerResources(new HashSet<>(resources));\n\t\t}\n\n\t}\n\n\tclass JerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar\n\t\t\timplements ManagementContextResourceConfigCustomizer {\n\n\t\tprivate final @Nullable ExposableWebEndpoint healthEndpoint;\n\n\t\tprivate final HealthEndpointGroups groups;\n\n\t\tJerseyAdditionalHealthEndpointPathsManagementResourcesRegistrar(@Nullable ExposableWebEndpoint healthEndpoint,\n\t\t\t\tHealthEndpointGroups groups) {\n\t\t\tthis.healthEndpoint = healthEndpoint;\n\t\t\tthis.groups = groups;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ResourceConfig config) {\n\t\t\tif (this.healthEndpoint != null) {\n\t\t\t\tregister(config, this.healthEndpoint);\n\t\t\t}\n\t\t}\n\n\t\tprivate void register(ResourceConfig config, ExposableWebEndpoint healthEndpoint) {\n\t\t\tEndpointMapping mapping = new EndpointMapping(\"\");\n\t\t\tJerseyHealthEndpointAdditionalPathResourceFactory resourceFactory = new JerseyHealthEndpointAdditionalPathResourceFactory(\n\t\t\t\t\tWebServerNamespace.MANAGEMENT, this.groups);\n\t\t\tCollection<Resource> endpointResources = resourceFactory\n\t\t\t\t.createEndpointResources(mapping, Collections.singletonList(healthEndpoint))\n\t\t\t\t.stream()\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.toList();\n\t\t\tregister(endpointResources, config);\n\t\t}\n\n\t\tprivate void register(Collection<Resource> resources, ResourceConfig config) {\n\t\t\tconfig.registerResources(new HashSet<>(resources));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ContextResolver} used to obtain the {@link ObjectMapper} that should be used\n\t * for {@link OperationResponseBody} instances.\n\t */\n\t@SuppressWarnings(\"removal\")\n\t@Priority(Priorities.USER - 100)\n\tprivate static final class EndpointJackson2ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {\n\n\t\tprivate final org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper mapper;\n\n\t\tprivate EndpointJackson2ObjectMapperContextResolver(\n\t\t\t\torg.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper mapper) {\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable ObjectMapper getContext(Class<?> type) {\n\t\t\treturn OperationResponseBody.class.isAssignableFrom(type) ? this.mapper.get() : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/ManagementContextResourceConfigCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize Jersey's\n * {@link ResourceConfig} in the management context before it is used.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface ManagementContextResourceConfigCustomizer {\n\n\t/**\n\t * Customize the resource config.\n\t * @param config the {@link ResourceConfig} to customize\n\t */\n\tvoid customize(ResourceConfig config);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/actuate/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jersey actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/metrics/JerseyServerMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.metrics;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport org.glassfish.jersey.micrometer.server.JerseyObservationConvention;\nimport org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Jersey server instrumentation.\n *\n * @author Michael Weirauch\n * @author Michael Simons\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ ResourceConfig.class, ObservationApplicationEventListener.class })\n@ConditionalOnBean({ ResourceConfig.class, ObservationRegistry.class })\n@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })\npublic final class JerseyServerMetricsAutoConfiguration {\n\n\tprivate final ObservationProperties observationProperties;\n\n\tJerseyServerMetricsAutoConfiguration(ObservationProperties observationProperties) {\n\t\tthis.observationProperties = observationProperties;\n\t}\n\n\t@Bean\n\tResourceConfigCustomizer jerseyServerObservationResourceConfigCustomizer(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<JerseyObservationConvention> jerseyObservationConvention) {\n\t\tString metricName = this.observationProperties.getHttp().getServer().getRequests().getName();\n\t\treturn (config) -> config.register(new ObservationApplicationEventListener(observationRegistry, metricName,\n\t\t\t\tjerseyObservationConvention.getIfAvailable()));\n\t}\n\n\t@Bean\n\t@Order(0)\n\tMaximumAllowableTagsMeterFilter jerseyMetricsUriTagFilter(MetricsProperties metricsProperties) {\n\t\tString meterNamePrefix = this.observationProperties.getHttp().getServer().getRequests().getName();\n\t\tint maxUriTags = metricsProperties.getWeb().getServer().getMaxUriTags();\n\t\treturn new MaximumAllowableTagsMeterFilter(meterNamePrefix, \"uri\", maxUriTags);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jersey metrics.\n */\n@NullMarked\npackage org.springframework.boot.jersey.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/java/org/springframework/boot/jersey/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jersey.\n */\n@NullMarked\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.jersey.autoconfigure.actuate.web.JerseyChildManagementContextConfiguration\norg.springframework.boot.jersey.autoconfigure.actuate.web.JerseyEndpointManagementContextConfiguration\norg.springframework.boot.jersey.autoconfigure.actuate.web.JerseySameManagementContextConfiguration\norg.springframework.boot.jersey.autoconfigure.actuate.web.JerseyWebEndpointManagementContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-jersey/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration\norg.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration\norg.springframework.boot.jersey.autoconfigure.metrics.JerseyServerMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyApplicationPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyApplicationPath}.\n *\n * @author Madhura Bhave\n */\nclass JerseyApplicationPathTests {\n\n\t@Test\n\tvoid getRelativePathReturnsRelativePath() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring\").getRelativePath(\"boot\")).isEqualTo(\"spring/boot\");\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring/\").getRelativePath(\"boot\")).isEqualTo(\"spring/boot\");\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring\").getRelativePath(\"/boot\")).isEqualTo(\"spring/boot\");\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring/*\").getRelativePath(\"/boot\")).isEqualTo(\"spring/boot\");\n\t}\n\n\t@Test\n\tvoid getPrefixWhenHasSimplePathReturnPath() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring\").getPrefix()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getPrefixWhenHasPatternRemovesPattern() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring/*.do\").getPrefix()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getPrefixWhenPathEndsWithSlashRemovesSlash() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring/\").getPrefix()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingWhenPathIsEmptyReturnsSlash() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"\").getUrlMapping()).isEqualTo(\"/*\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingWhenPathIsSlashReturnsSlash() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"/\").getUrlMapping()).isEqualTo(\"/*\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingWhenPathContainsStarReturnsPath() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"/spring/*.do\").getUrlMapping()).isEqualTo(\"/spring/*.do\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingWhenHasPathNotEndingSlashReturnsSlashStarPattern() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"/spring/boot\").getUrlMapping()).isEqualTo(\"/spring/boot/*\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingWhenHasPathDoesNotStartWithSlashPrependsSlash() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"spring/boot\").getUrlMapping()).isEqualTo(\"/spring/boot/*\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingWhenHasPathEndingWithSlashReturnsSlashStarPattern() {\n\t\tassertThat(((JerseyApplicationPath) () -> \"/spring/boot/\").getUrlMapping()).isEqualTo(\"/spring/boot/*\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.core.Application;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using a custom {@link Application}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationCustomApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/test/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@ApplicationPath(\"/test\")\n\tstatic class TestApplication extends Application {\n\n\t}\n\n\t@Path(\"/hello\")\n\tpublic static class TestController {\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tpublic class JerseyConfiguration {\n\n\t\t\t@Bean\n\t\t\tpublic TestApplication testApplication() {\n\t\t\t\treturn new TestApplication();\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\tpublic ResourceConfig conf(TestApplication app) {\n\t\t\t\tResourceConfig config = ResourceConfig.forApplication(app);\n\t\t\t\tconfig.register(TestController.class);\n\t\t\t\treturn config;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomFilterContextPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.jersey.type=filter\", \"server.servlet.context-path=/app\",\n\t\t\t\t\"server.servlet.register-default-servlet=true\" })\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationCustomFilterContextPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/rest/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@ApplicationPath(\"/rest\")\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomFilterPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.jersey.type=filter\", \"server.servlet.register-default-servlet=true\" })\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationCustomFilterPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/rest/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@ApplicationPath(\"rest\")\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomLoadOnStartupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom load on startup.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.jersey.servlet.load-on-startup=5\")\n@DirtiesContext\nclass JerseyAutoConfigurationCustomLoadOnStartupTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.context.getBean(\"jerseyServletRegistration\")).hasFieldOrPropertyWithValue(\"loadOnStartup\", 5);\n\t}\n\n\t@MinimalWebConfiguration\n\tstatic class Application extends ResourceConfig {\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ JerseyAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomObjectMapperProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom ObjectMapper.\n *\n * @author Eddú Meléndez\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.jackson2.default-property-inclusion=non_null\")\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationCustomObjectMapperProviderTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> response = this.restTemplate.getForEntity(\"/rest/message\", String.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(\"{\\\"subject\\\":\\\"Jersey\\\"}\").isEqualTo(response.getBody());\n\t}\n\n\t@MinimalWebConfiguration\n\t@ApplicationPath(\"/rest\")\n\t@Path(\"/message\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic Message message() {\n\t\t\treturn new Message(\"Jersey\", null);\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\tpublic static class Message {\n\n\t\tprivate String subject;\n\n\t\tprivate String body;\n\n\t\tMessage(String subject, String body) {\n\t\t\tthis.subject = subject;\n\t\t\tthis.body = body;\n\t\t}\n\n\t\tpublic String getSubject() {\n\t\t\treturn this.subject;\n\t\t}\n\n\t\tpublic void setSubject(String subject) {\n\t\t\tthis.subject = subject;\n\t\t}\n\n\t\tpublic String getBody() {\n\t\t\treturn this.body;\n\t\t}\n\n\t\tpublic void setBody(String body) {\n\t\t\tthis.body = body;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class,\n\t\t\torg.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class,\n\t\t\tJerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomServletContextPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"server.servlet.contextPath=/app\")\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationCustomServletContextPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/rest/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@ApplicationPath(\"/rest\")\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationCustomServletPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationCustomServletPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/rest/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@ApplicationPath(\"/rest\")\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationDefaultFilterPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom servlet paths.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.jersey.type=filter\", \"server.servlet.register-default-servlet=true\" })\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationDefaultFilterPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationDefaultServletPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using default servlet paths.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationDefaultServletPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationObjectMapperProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.ApplicationPath;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.xml.bind.annotation.XmlTransient;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} with an ObjectMapper.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.jackson2.default-property-inclusion:non-null\")\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationObjectMapperProviderTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid responseIsSerializedUsingAutoConfiguredObjectMapper() {\n\t\tResponseEntity<String> response = this.restTemplate.getForEntity(\"/rest/message\", String.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(response.getBody()).isEqualTo(\"{\\\"subject\\\":\\\"Jersey\\\"}\");\n\t}\n\n\t@MinimalWebConfiguration\n\t@ApplicationPath(\"/rest\")\n\t@Path(\"/message\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic Message message() {\n\t\t\treturn new Message(\"Jersey\", null);\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\tpublic static class Message {\n\n\t\tprivate String subject;\n\n\t\tprivate String body;\n\n\t\tMessage() {\n\t\t}\n\n\t\tMessage(String subject, String body) {\n\t\t\tthis.subject = subject;\n\t\t\tthis.body = body;\n\t\t}\n\n\t\tpublic String getSubject() {\n\t\t\treturn this.subject;\n\t\t}\n\n\t\tpublic void setSubject(String subject) {\n\t\t\tthis.subject = subject;\n\t\t}\n\n\t\tpublic String getBody() {\n\t\t\treturn this.body;\n\t\t}\n\n\t\tpublic void setBody(String body) {\n\t\t\tthis.body = body;\n\t\t}\n\n\t\t@XmlTransient\n\t\tpublic String getFoo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@SuppressWarnings(\"removal\")\n\t@Import({ TomcatServletWebServerAutoConfiguration.class,\n\t\t\torg.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class,\n\t\t\tJerseyAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationServletContainerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Wrapper;\nimport org.apache.tomcat.util.buf.UDecoder;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.servlet.ServletContainer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfigurationServletContainerTests.Application;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests that verify the behavior when deployed to a Servlet container where Jersey may\n * have already initialized itself.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT)\n@DirtiesContext\n@ExtendWith(OutputCaptureExtension.class)\nclass JerseyAutoConfigurationServletContainerTests {\n\n\t@Test\n\tvoid existingJerseyServletIsAmended(CapturedOutput output) {\n\t\tassertThat(output).contains(\"Configuring existing registration for Jersey servlet\");\n\t\tassertThat(output).contains(\"Servlet \" + Application.class.getName() + \" was not registered\");\n\t}\n\n\t@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\t@Import(ContainerConfiguration.class)\n\t@Path(\"/hello\")\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ContainerConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void postProcessContext(Context context) {\n\t\t\t\t\tWrapper jerseyServlet = context.createWrapper();\n\t\t\t\t\tString servletName = Application.class.getName();\n\t\t\t\t\tjerseyServlet.setName(servletName);\n\t\t\t\t\tjerseyServlet.setServletClass(ServletContainer.class.getName());\n\t\t\t\t\tjerseyServlet.setServlet(new ServletContainer());\n\t\t\t\t\tjerseyServlet.setOverridable(false);\n\t\t\t\t\tcontext.addChild(jerseyServlet);\n\t\t\t\t\tString pattern = UDecoder.URLDecode(\"/*\", StandardCharsets.UTF_8);\n\t\t\t\t\tcontext.addServletMappingDecoded(pattern, servletName);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.util.Collections;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration.JerseyWebApplicationInitializer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.filter.RequestContextFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass JerseyAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class))\n\t\t.withUserConfiguration(ResourceConfigConfiguration.class);\n\n\t@Test\n\tvoid requestContextFilterRegistrationIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\t\tFilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);\n\t\t\tassertThat(registration.getFilter()).isInstanceOf(RequestContextFilter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUserDefinesARequestContextFilterTheAutoConfiguredRegistrationBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(RequestContextFilterConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(FilterRegistrationBean.class);\n\t\t\tassertThat(context).hasSingleBean(RequestContextFilter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUserDefinesARequestContextFilterRegistrationTheAutoConfiguredRegistrationBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(RequestContextFilterRegistrationConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\t\tassertThat(context).hasBean(\"customRequestContextFilterRegistration\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid whenJaxbIsAvailableTheObjectMapperIsCustomizedWithAnAnnotationIntrospector() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper objectMapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(objectMapper.getSerializationConfig()\n\t\t\t\t\t.getAnnotationIntrospector()\n\t\t\t\t\t.allIntrospectors()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid whenJaxbIsNotAvailableTheObjectMapperCustomizationBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(\"jakarta.xml.bind.annotation\"))\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper objectMapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(objectMapper.getSerializationConfig()\n\t\t\t\t\t.getAnnotationIntrospector()\n\t\t\t\t\t.allIntrospectors()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid whenJacksonJaxbModuleIsNotAvailableTheObjectMapperCustomizationBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(JakartaXmlBindAnnotationIntrospector.class))\n\t\t\t.run((context) -> {\n\t\t\t\tObjectMapper objectMapper = context.getBean(ObjectMapper.class);\n\t\t\t\tassertThat(objectMapper.getSerializationConfig()\n\t\t\t\t\t.getAnnotationIntrospector()\n\t\t\t\t\t.allIntrospectors()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter(JakartaXmlBindAnnotationIntrospector.class::isInstance)).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid webApplicationInitializerDisablesJerseyWebApplicationInitializer() throws ServletException {\n\t\tServletContext context = new MockServletContext();\n\t\tnew JerseyWebApplicationInitializer().onStartup(context);\n\t\tassertThat(context.getInitParameter(\"contextConfigLocation\")).isEqualTo(\"<NONE>\");\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"jersey-spring6-*.jar\")\n\tvoid webApplicationInitializerHasNoEffectWhenJerseyIsAbsent() throws ServletException {\n\t\tServletContext context = new MockServletContext();\n\t\tnew JerseyWebApplicationInitializer().onStartup(context);\n\t\tassertThat(Collections.list(context.getInitParameterNames())).isEmpty();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceConfigConfiguration {\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig() {\n\t\t\treturn new ResourceConfig();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestContextFilterConfiguration {\n\n\t\t@Bean\n\t\tRequestContextFilter requestContextFilter() {\n\t\t\treturn new RequestContextFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestContextFilterRegistrationConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<RequestContextFilter> customRequestContextFilterRegistration() {\n\t\t\treturn new FilterRegistrationBean<>(new RequestContextFilter());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/JerseyAutoConfigurationWithoutApplicationPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyAutoConfiguration} when using custom application path.\n *\n * @author Eddú Meléndez\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.jersey.application-path=/api\")\n@AutoConfigureTestRestTemplate\n@DirtiesContext\nclass JerseyAutoConfigurationWithoutApplicationPathTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/api/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@MinimalWebConfiguration\n\t@Path(\"/hello\")\n\tpublic static class Application extends ResourceConfig {\n\n\t\t@Value(\"${message:World}\")\n\t\tprivate String msg;\n\n\t\tApplication() {\n\t\t\tregister(Application.class);\n\t\t}\n\n\t\t@GET\n\t\tpublic String message() {\n\t\t\treturn \"Hello \" + this.msg;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Configuration\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/HealthEndpointJerseyExtensionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration.JerseyAdditionalHealthEndpointPathsResourcesRegistrar;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HealthEndpointJerseyExtensionAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass HealthEndpointJerseyExtensionAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tHealthEndpointJerseyExtensionAutoConfiguration.class));\n\n\t@Test\n\t@WithTestEndpointOutcomeExposureContributor\n\tvoid additionalJerseyHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.exclude=*\",\n\t\t\t\t\t\"management.endpoints.test.exposure.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).hasSingleBean(HealthEndpoint.class);\n\t\t\t\tassertThat(context).hasSingleBean(HealthEndpointWebExtension.class);\n\t\t\t\tassertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();\n\t\t\t\tassertThat(context).hasSingleBean(JerseyAdditionalHealthEndpointPathsResourcesRegistrar.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthIndicatorsConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator simpleHealthIndicator() {\n\t\t\treturn () -> Health.up().withDetail(\"counter\", 42).build();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator additionalHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t\t@Bean\n\t\tReactiveHealthIndicator reactiveHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/JerseyEndpointAccessIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.reactive.server.EntityExchangeResult;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.function.client.ExchangeStrategies;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for controlling access to endpoints exposed by Jersey.\n *\n * @author Andy Wilkinson\n */\nclass JerseyEndpointAccessIntegrationTests {\n\n\t@SuppressWarnings(\"removal\")\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class,\n\t\t\t\t\t\tJerseyAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\t\tManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(CustomServletEndpoint.class)\n\t\t.withPropertyValues(\"server.port:0\");\n\n\t@Test\n\tvoid accessIsUnrestrictedByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\").run((context) -> {\n\t\t\tWebTestClient client = createClient(context);\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeReadOnlyByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeNoneByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessForOneEndpointCanOverrideTheDefaultAccess() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\", \"management.endpoint.customservlet.access=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtReadOnly() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\",\n\t\t\t\t\t\"management.endpoints.access.max-permitted=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtNone() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\", \"management.endpoints.access.max-permitted=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\tprivate WebTestClient createClient(AssertableWebApplicationContext context) {\n\t\tint port = context.getSourceApplicationContext(ServletWebServerApplicationContext.class)\n\t\t\t.getWebServer()\n\t\t\t.getPort();\n\t\tExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()\n\t\t\t.codecs((configurer) -> configurer.defaultCodecs().maxInMemorySize(-1))\n\t\t\t.build();\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t.exchangeStrategies(exchangeStrategies)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\tprivate boolean isAccessible(WebTestClient client, HttpMethod method, String path) {\n\t\tpath = \"/actuator/\" + path;\n\t\tEntityExchangeResult<byte[]> result = client.method(method).uri(path).exchange().expectBody().returnResult();\n\t\tif (result.getStatus() == HttpStatus.OK) {\n\t\t\treturn true;\n\t\t}\n\t\tif (result.getStatus() == HttpStatus.NOT_FOUND || result.getStatus() == HttpStatus.METHOD_NOT_ALLOWED) {\n\t\t\treturn false;\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\tString.format(\"Unexpected %s HTTP status for endpoint %s\", result.getStatus(), path));\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"customservlet\")\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic class CustomServletEndpoint\n\t\t\timplements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {\n\n\t\t@Override\n\t\tpublic org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {\n\t\t\treturn new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/endpoint/web/JerseyEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.databind.SerializerProvider;\nimport com.fasterxml.jackson.databind.jsontype.TypeSerializer;\nimport com.fasterxml.jackson.databind.module.SimpleModule;\nimport com.fasterxml.jackson.databind.ser.std.StdScalarSerializer;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Jersey actuator endpoints.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass JerseyEndpointIntegrationTests {\n\n\t@Test\n\tvoid linksAreProvidedToAllEndpointTypes() {\n\t\ttestJerseyEndpoints(new Class<?>[] { EndpointsConfiguration.class, ResourceConfigConfiguration.class });\n\t}\n\n\t@Test\n\tvoid linksPageIsNotAvailableWhenDisabled() {\n\t\tgetContextRunner(new Class<?>[] { EndpointsConfiguration.class, ResourceConfigConfiguration.class })\n\t\t\t.withPropertyValues(\"management.endpoints.web.discovery.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tint port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)\n\t\t\t\t\t.getWebServer()\n\t\t\t\t\t.getPort();\n\t\t\t\tWebTestClient client = WebTestClient.bindToServer()\n\t\t\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t\t\t.build();\n\t\t\t\tclient.get().uri(\"/actuator\").exchange().expectStatus().isNotFound();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid actuatorEndpointsWhenUserProvidedResourceConfigBeanNotAvailable() {\n\t\ttestJerseyEndpoints(new Class<?>[] { EndpointsConfiguration.class });\n\t}\n\n\t@Test\n\tvoid endpointObjectMapperCanBeApplied() {\n\t\tWebApplicationContextRunner contextRunner = getContextRunner(new Class<?>[] { EndpointsConfiguration.class,\n\t\t\t\tResourceConfigConfiguration.class, EndpointObjectMapperConfiguration.class });\n\t\tcontextRunner.run((context) -> {\n\t\t\tint port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)\n\t\t\t\t.getWebServer()\n\t\t\t\t.getPort();\n\t\t\tWebTestClient client = WebTestClient.bindToServer()\n\t\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t\t.build();\n\t\t\tclient.get().uri(\"/actuator/beans\").exchange().expectStatus().isOk().expectBody().consumeWith((result) -> {\n\t\t\t\tString json = new String(result.getResponseBody(), StandardCharsets.UTF_8);\n\t\t\t\tassertThat(json).contains(\"\\\"scope\\\":\\\"notelgnis\\\"\");\n\t\t\t});\n\t\t});\n\t}\n\n\tprotected void testJerseyEndpoints(Class<?>[] userConfigurations) {\n\t\tgetContextRunner(userConfigurations).run((context) -> {\n\t\t\tint port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)\n\t\t\t\t.getWebServer()\n\t\t\t\t.getPort();\n\t\t\tWebTestClient client = WebTestClient.bindToServer()\n\t\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t\t.build();\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/actuator\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"_links.beans\")\n\t\t\t\t.isNotEmpty()\n\t\t\t\t.jsonPath(\"_links.restcontroller\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"_links.controller\")\n\t\t\t\t.doesNotExist();\n\t\t});\n\t}\n\n\tWebApplicationContextRunner getContextRunner(Class<?>[] userConfigurations,\n\t\t\tClass<?>... additionalAutoConfigurations) {\n\t\treturn new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(getAutoconfigurations(additionalAutoConfigurations)))\n\t\t\t.withUserConfiguration(userConfigurations)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include:*\", \"server.port:0\");\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate Class<?>[] getAutoconfigurations(Class<?>... additional) {\n\t\tList<Class<?>> autoconfigurations = new ArrayList<>(\n\t\t\t\tArrays.asList(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class,\n\t\t\t\t\t\tJerseyAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\t\tManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class));\n\t\tautoconfigurations.addAll(Arrays.asList(additional));\n\t\treturn autoconfigurations.toArray(new Class<?>[0]);\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint(id = \"controller\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestControllerEndpoint {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"restcontroller\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestRestControllerEndpoint {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointsConfiguration {\n\n\t\t@Bean\n\t\tTestControllerEndpoint testControllerEndpoint() {\n\t\t\treturn new TestControllerEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestRestControllerEndpoint testRestControllerEndpoint() {\n\t\t\treturn new TestRestControllerEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceConfigConfiguration {\n\n\t\t@Bean\n\t\tResourceConfig testResourceConfig() {\n\t\t\treturn new ResourceConfig();\n\t\t}\n\n\t}\n\n\t@Configuration\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic class EndpointObjectMapperConfiguration {\n\n\t\t@Bean\n\t\torg.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper endpointJackson2ObjectMapper() {\n\t\t\tSimpleModule module = new SimpleModule();\n\t\t\tmodule.addSerializer(String.class, new ReverseStringSerializer());\n\t\t\tObjectMapper objectMapper = new ObjectMapper();\n\t\t\tobjectMapper.registerModule(module);\n\t\t\treturn () -> objectMapper;\n\t\t}\n\n\t\tstatic class ReverseStringSerializer extends StdScalarSerializer<Object> {\n\n\t\t\tReverseStringSerializer() {\n\t\t\t\tsuper(String.class, false);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isEmpty(SerializerProvider provider, Object value) {\n\t\t\t\treturn ((String) value).isEmpty();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {\n\t\t\t\tserialize(value, gen);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic final void serializeWithType(Object value, JsonGenerator gen, SerializerProvider provider,\n\t\t\t\t\tTypeSerializer typeSer) throws IOException {\n\t\t\t\tserialize(value, gen);\n\t\t\t}\n\n\t\t\tprivate void serialize(Object value, JsonGenerator gen) throws IOException {\n\t\t\t\tStringBuilder builder = new StringBuilder((String) value);\n\t\t\t\tgen.writeString(builder.reverse().toString());\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyChildManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.servlet.ServletContainer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JerseyChildManagementContextConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\n@ClassPathExclusions(\"spring-webmvc-*\")\nclass JerseyChildManagementContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(JerseyChildManagementContextConfiguration.class);\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnServletWebApplication() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));\n\t\tcontextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnClassResourceConfig() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ResourceConfig.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));\n\t}\n\n\t@Test\n\tvoid jerseyApplicationPathIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJerseyApplicationPath bean = context.getBean(JerseyApplicationPath.class);\n\t\t\tassertThat(bean.getPath()).isEqualTo(\"/\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid servletRegistrationBeanIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tServletRegistrationBean<ServletContainer> bean = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(bean.getUrlMappings()).containsExactly(\"/*\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid resourceConfigCustomizerBeanIsNotRequired() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ResourceConfig.class));\n\t}\n\n\t@Test\n\tvoid resourceConfigIsCustomizedWithResourceConfigCustomizerBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ResourceConfig.class);\n\t\t\tResourceConfig config = context.getBean(ResourceConfig.class);\n\t\t\tManagementContextResourceConfigCustomizer customizer = context\n\t\t\t\t.getBean(ManagementContextResourceConfigCustomizer.class);\n\t\t\tthen(customizer).should().customize(config);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tManagementContextResourceConfigCustomizer resourceConfigCustomizer() {\n\t\t\treturn mock(ManagementContextResourceConfigCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyEndpointManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyEndpointManagementContextConfiguration}.\n *\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"removal\")\nclass JerseyEndpointManagementContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfig.class);\n\n\t@Test\n\tvoid contextShouldContainServletEndpointRegistrar() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ServletEndpointRegistrar.class);\n\t\t\tServletEndpointRegistrar bean = context.getBean(ServletEndpointRegistrar.class);\n\t\t\tassertThat(bean).hasFieldOrPropertyWithValue(\"basePath\", \"/test/actuator\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextWhenNotServletBasedShouldNotContainServletEndpointRegistrar() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(TestConfig.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServletEndpointRegistrar.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(JerseyEndpointManagementContextConfiguration.class)\n\t@EnableConfigurationProperties(WebEndpointProperties.class)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tServletEndpointsSupplier servletEndpointsSupplier() {\n\t\t\treturn Collections::emptyList;\n\t\t}\n\n\t\t@Bean\n\t\tJerseyApplicationPath jerseyApplicationPath() {\n\t\t\treturn () -> \"/test\";\n\t\t}\n\n\t\t@Bean\n\t\tEndpointAccessResolver endpointAccessResolver() {\n\t\t\treturn (endpointId, defaultAccess) -> Access.UNRESTRICTED;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyHealthEndpointAdditionalPathIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.integrationtest.AbstractHealthEndpointAdditionalPathIntegrationTests;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.application.DiskSpaceHealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.jersey.autoconfigure.actuate.endpoint.web.HealthEndpointJerseyExtensionAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementContextAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\n\n/**\n * Integration tests for health groups on an additional path on Jersey.\n *\n * @author Madhura Bhave\n */\nclass JerseyHealthEndpointAdditionalPathIntegrationTests extends\n\t\tAbstractHealthEndpointAdditionalPathIntegrationTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {\n\n\t@SuppressWarnings(\"removal\")\n\tJerseyHealthEndpointAdditionalPathIntegrationTests() {\n\t\tsuper(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(\n\t\t\t\t\torg.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class,\n\t\t\t\t\tJerseyAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class,\n\t\t\t\t\tTomcatServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\tJerseyAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\t\tServletManagementContextAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class,\n\t\t\t\t\tHealthEndpointJerseyExtensionAutoConfiguration.class,\n\t\t\t\t\tDiskSpaceHealthContributorAutoConfiguration.class))\n\t\t\t.withInitializer(new ServerPortInfoApplicationContextInitializer())\n\t\t\t.withPropertyValues(\"server.port=0\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseySameManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.servlet.ServletContainer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.DefaultJerseyApplicationPath;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JerseySameManagementContextConfiguration}.\n *\n * @author Madhura Bhave\n */\n@ClassPathExclusions(\"spring-webmvc-*\")\nclass JerseySameManagementContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnServletWebApplication() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));\n\t\tcontextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnClassResourceConfig() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ResourceConfig.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));\n\t}\n\n\t@Test\n\tvoid jerseyApplicationPathIsAutoConfiguredWhenNeeded() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(DefaultJerseyApplicationPath.class));\n\t}\n\n\t@Test\n\tvoid jerseyApplicationPathIsConditionalOnMissingBean() {\n\t\tthis.contextRunner.withUserConfiguration(ConfigWithJerseyApplicationPath.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JerseyApplicationPath.class);\n\t\t\tassertThat(context).hasBean(\"testJerseyApplicationPath\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid existingResourceConfigBeanShouldNotAutoConfigureRelatedBeans() {\n\t\tthis.contextRunner.withUserConfiguration(ConfigWithResourceConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ResourceConfig.class);\n\t\t\tassertThat(context).doesNotHaveBean(JerseyApplicationPath.class);\n\t\t\tassertThat(context).doesNotHaveBean(ServletRegistrationBean.class);\n\t\t\tassertThat(context).hasBean(\"customResourceConfig\");\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid servletRegistrationBeanIsAutoConfiguredWhenNeeded() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jersey.application-path=/jersey\").run((context) -> {\n\t\t\tServletRegistrationBean<ServletContainer> bean = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(bean.getUrlMappings()).containsExactly(\"/jersey/*\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid resourceConfigIsCustomizedWithResourceConfigCustomizerBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ResourceConfig.class);\n\t\t\tResourceConfig config = context.getBean(ResourceConfig.class);\n\t\t\tManagementContextResourceConfigCustomizer customizer = context\n\t\t\t\t.getBean(ManagementContextResourceConfigCustomizer.class);\n\t\t\tthen(customizer).should().customize(config);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigWithJerseyApplicationPath {\n\n\t\t@Bean\n\t\tJerseyApplicationPath testJerseyApplicationPath() {\n\t\t\treturn mock(JerseyApplicationPath.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigWithResourceConfig {\n\n\t\t@Bean\n\t\tResourceConfig customResourceConfig() {\n\t\t\treturn new ResourceConfig();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tManagementContextResourceConfigCustomizer resourceConfigCustomizer() {\n\t\t\treturn mock(ManagementContextResourceConfigCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyWebEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport java.util.Set;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.server.model.Resource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for web endpoints running on Jersey.\n *\n * @author Andy Wilkinson\n */\nclass JerseyWebEndpointIntegrationTests {\n\n\t@Test\n\tvoid whenJerseyIsConfiguredToUseAFilterThenResourceRegistrationSucceeds() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(JerseySameManagementContextConfiguration.class, JerseyAutoConfiguration.class,\n\t\t\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\t\t\t\tWebEndpointAutoConfiguration.class, JerseyWebEndpointManagementContextConfiguration.class))\n\t\t\t.withUserConfiguration(ResourceConfigConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jersey.type=filter\", \"server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tSet<Resource> resources = context.getBean(ResourceConfig.class).getResources();\n\t\t\t\tassertThat(resources).hasSize(1);\n\t\t\t\tResource resource = resources.iterator().next();\n\t\t\t\tassertThat(resource.getPath()).isEqualTo(\"/actuator\");\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceConfigConfiguration {\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig() {\n\t\t\treturn new ResourceConfig();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/actuate/web/JerseyWebEndpointManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.actuate.web;\n\nimport java.util.Collections;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.actuate.web.JerseyWebEndpointManagementContextConfiguration.JerseyWebEndpointsResourcesRegistrar;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyWebEndpointManagementContextConfiguration}.\n *\n * @author Michael Simons\n * @author Madhura Bhave\n */\nclass JerseyWebEndpointManagementContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner runner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebEndpointAutoConfiguration.class,\n\t\t\t\tJerseyWebEndpointManagementContextConfiguration.class))\n\t\t.withBean(WebEndpointsSupplier.class, () -> Collections::emptyList)\n\t\t.withBean(EndpointAccessResolver.class, () -> (endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\n\t@Test\n\tvoid jerseyWebEndpointsResourcesRegistrarForEndpointsIsAutoConfigured() {\n\t\tthis.runner.run((context) -> assertThat(context).hasSingleBean(JerseyWebEndpointsResourcesRegistrar.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnServletWebApplication() {\n\t\tApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(JerseySameManagementContextConfiguration.class));\n\t\tcontextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnClassResourceConfig() {\n\t\tthis.runner.withClassLoader(new FilteredClassLoader(ResourceConfig.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JerseySameManagementContextConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/test/java/org/springframework/boot/jersey/autoconfigure/metrics/JerseyServerMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.autoconfigure.metrics;\n\nimport java.net.URI;\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Timer;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.Observation.Context;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.PathParam;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.awaitility.Awaitility;\nimport org.glassfish.jersey.micrometer.server.ObservationApplicationEventListener;\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JerseyServerMetricsAutoConfiguration}.\n *\n * @author Michael Weirauch\n * @author Michael Simons\n * @author Moritz Halbritter\n */\nclass JerseyServerMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JerseyServerMetricsAutoConfiguration.class));\n\n\tprivate final WebApplicationContextRunner webContextRunner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class,\n\t\t\t\tJerseyServerMetricsAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,\n\t\t\t\tTomcatServletWebServerAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class,\n\t\t\t\tObservationAutoConfiguration.class, MetricsAutoConfiguration.class))\n\t\t.withUserConfiguration(ResourceConfiguration.class)\n\t\t.withPropertyValues(\"server.port:0\");\n\n\t@Test\n\tvoid shouldOnlyBeActiveInWebApplicationContext() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ResourceConfigCustomizer.class));\n\t}\n\n\t@Test\n\tvoid shouldProvideAllNecessaryBeans() {\n\t\tthis.webContextRunner.run((context) -> assertThat(context).hasBean(\"jerseyMetricsUriTagFilter\")\n\t\t\t.hasSingleBean(ResourceConfigCustomizer.class));\n\t}\n\n\t@Test\n\tvoid httpRequestsAreTimed() {\n\t\tthis.webContextRunner.withUserConfiguration(MetricsConfiguration.class).run((context) -> {\n\t\t\tdoRequest(context);\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t// Response is sent before the timer is registered which triggers a race\n\t\t\t// condition.\n\t\t\t// https://github.com/apache/tomcat/commit/69eff83577f7c00cbaaca9384ab4b1989f516797\n\t\t\tAwaitility.await().atMost(Duration.ofSeconds(5)).untilAsserted(() -> {\n\t\t\t\tTimer timer = registry.find(\"http.server.requests\").tag(\"uri\", \"/users/{id}\").timer();\n\t\t\t\tassertThat(timer).isNotNull().extracting(Timer::count, InstanceOfAssertFactories.LONG).isOne();\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid noHttpRequestsTimedWhenJerseyInstrumentationMissingFromClasspath() {\n\t\tthis.webContextRunner.withClassLoader(new FilteredClassLoader(ObservationApplicationEventListener.class))\n\t\t\t.run((context) -> {\n\t\t\t\tdoRequest(context);\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"http.server.requests\").timer()).isNull();\n\t\t\t});\n\t}\n\n\tprivate static void doRequest(AssertableWebApplicationContext context) {\n\t\tint port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)\n\t\t\t.getWebServer()\n\t\t\t.getPort();\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\trestTemplate.getForEntity(URI.create(\"http://localhost:\" + port + \"/users/3\"), String.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceConfiguration {\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig() {\n\t\t\treturn new ResourceConfig().register(new TestResource());\n\t\t}\n\n\t\t@Path(\"/users\")\n\t\tpublic static class TestResource {\n\n\t\t\t@GET\n\t\t\t@Path(\"/{id}\")\n\t\t\tpublic String getUser(@PathParam(\"id\") String id) {\n\t\t\t\treturn id;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsConfiguration {\n\n\t\t@Bean\n\t\tMeterObservationHandler<Context> meterObservationHandler(MeterRegistry registry) {\n\t\t\treturn new DefaultMeterObservationHandler(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/testFixtures/java/org/springframework/boot/jersey/actuate/endpoint/web/test/JerseyEndpointConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.actuate.endpoint.web.test;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.glassfish.jersey.server.model.Resource;\n\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jersey.actuate.endpoint.web.JerseyEndpointResourceFactory;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Endpoint configuration for Jersey.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@SuppressWarnings(\"removal\")\n@Configuration(proxyBeanMethods = false)\n@ImportAutoConfiguration({ org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class,\n\t\tJerseyAutoConfiguration.class })\nclass JerseyEndpointConfiguration {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tJerseyEndpointConfiguration(ApplicationContext applicationContext) {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Bean\n\tTomcatServletWebServerFactory tomcat() {\n\t\treturn new TomcatServletWebServerFactory(0);\n\t}\n\n\t@Bean\n\tResourceConfig resourceConfig() {\n\t\treturn new ResourceConfig();\n\t}\n\n\t@Bean\n\tResourceConfigCustomizer webEndpointRegistrar() {\n\t\treturn this::customize;\n\t}\n\n\tprivate void customize(ResourceConfig config) {\n\t\tEndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;\n\t\tWebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,\n\t\t\t\tnew ConversionServiceParameterValueMapper(), endpointMediaTypes, null, Collections.emptyList(),\n\t\t\t\tCollections.emptyList(), Collections.emptyList(), Collections.emptyList());\n\t\tCollection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(\n\t\t\t\tnew EndpointMapping(\"/actuator\"), discoverer.getEndpoints(), endpointMediaTypes,\n\t\t\t\tnew EndpointLinksResolver(discoverer.getEndpoints()), true);\n\t\tconfig.registerResources(new HashSet<>(resources));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/testFixtures/java/org/springframework/boot/jersey/actuate/endpoint/web/test/JerseyWebEndpointInfrastructureProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jersey.actuate.endpoint.web.test;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\n\n/**\n * {@link WebEndpointInfrastructureProvider} for Jersey.\n *\n * @author Stephane Nicoll\n */\nclass JerseyWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {\n\n\t@Override\n\tpublic boolean supports(Infrastructure infrastructure) {\n\t\treturn infrastructure == Infrastructure.JERSEY;\n\t}\n\n\t@Override\n\tpublic List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {\n\t\treturn List.of(JerseyEndpointConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jersey/src/testFixtures/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\\\norg.springframework.boot.jersey.actuate.endpoint.web.test.JerseyWebEndpointInfrastructureProvider\n"
  },
  {
    "path": "module/spring-boot-jetty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Jetty\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-web-server\"))\n\tapi(\"org.eclipse.jetty.ee11:jetty-ee11-webapp\")\n\n\timplementation(\"org.eclipse.jetty.compression:jetty-compression-server\")\n\timplementation(\"org.eclipse.jetty.compression:jetty-compression-gzip\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-web-server-test\"))\n\toptional(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\toptional(\"org.eclipse.jetty:jetty-alpn-conscrypt-server\")\n\toptional(\"org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jakarta-server\")\n\toptional(\"org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jetty-server\")\n\toptional(\"org.eclipse.jetty.http2:jetty-http2-server\")\n\toptional(\"org.springframework:spring-webflux\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.projectreactor:reactor-test\")\n\ttestRuntimeOnly(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestRuntimeOnly(\"org.eclipse.jetty:jetty-client\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.http2:jetty-http2-client\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.http2:jetty-http2-client-transport\")\n\ttestRuntimeOnly(\"org.springframework:spring-webmvc\")\n}\n\ntest {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/ConfigurableJettyWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.util.thread.ThreadPool;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\n\n/**\n * {@link ConfigurableWebServerFactory} for Jetty-specific features.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic interface ConfigurableJettyWebServerFactory extends ConfigurableWebServerFactory {\n\n\t/**\n\t * Set the number of acceptor threads to use.\n\t * @param acceptors the number of acceptor threads to use\n\t */\n\tvoid setAcceptors(int acceptors);\n\n\t/**\n\t * Set the {@link ThreadPool} that should be used by the {@link Server}. If set to\n\t * {@code null} (default), the {@link Server} creates a {@link ThreadPool} implicitly.\n\t * @param threadPool the ThreadPool to be used\n\t */\n\tvoid setThreadPool(@Nullable ThreadPool threadPool);\n\n\t/**\n\t * Set the number of selector threads to use.\n\t * @param selectors the number of selector threads to use\n\t */\n\tvoid setSelectors(int selectors);\n\n\t/**\n\t * Set if x-forward-* headers should be processed.\n\t * @param useForwardHeaders if x-forward headers should be used\n\t */\n\tvoid setUseForwardHeaders(boolean useForwardHeaders);\n\n\t/**\n\t * Add {@link JettyServerCustomizer}s that will be applied to the {@link Server}\n\t * before it is started.\n\t * @param customizers the customizers to add\n\t */\n\tvoid addServerCustomizers(JettyServerCustomizer... customizers);\n\n\t/**\n\t * Sets the maximum number of concurrent connections.\n\t * @param maxConnections the maximum number of concurrent connections\n\t */\n\tvoid setMaxConnections(int maxConnections);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/ForwardHeadersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport org.eclipse.jetty.server.ConnectionFactory;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.ForwardedRequestCustomizer;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.Server;\n\n/**\n * {@link JettyServerCustomizer} to add {@link ForwardedRequestCustomizer}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ForwardHeadersCustomizer implements JettyServerCustomizer {\n\n\t@Override\n\tpublic void customize(Server server) {\n\t\tForwardedRequestCustomizer customizer = new ForwardedRequestCustomizer();\n\t\tfor (Connector connector : server.getConnectors()) {\n\t\t\tfor (ConnectionFactory connectionFactory : connector.getConnectionFactories()) {\n\t\t\t\tif (connectionFactory instanceof HttpConfiguration.ConnectionFactory jettyConnectionFactory) {\n\t\t\t\t\tjettyConnectionFactory.getHttpConfiguration().addCustomizer(customizer);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/GracefulShutdown.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport java.lang.reflect.Method;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Handles Jetty graceful shutdown.\n *\n * @author Andy Wilkinson\n * @author Onur Kagan Ozcan\n */\nfinal class GracefulShutdown {\n\n\tprivate static final Log logger = LogFactory.getLog(GracefulShutdown.class);\n\n\tprivate final Server server;\n\n\tprivate final Supplier<Integer> activeRequests;\n\n\tprivate volatile boolean aborted;\n\n\tGracefulShutdown(Server server, Supplier<Integer> activeRequests) {\n\t\tthis.server = server;\n\t\tthis.activeRequests = activeRequests;\n\t}\n\n\tvoid shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tlogger.info(\"Commencing graceful shutdown. Waiting for active requests to complete\");\n\t\tnew Thread(() -> awaitShutdown(callback), \"jetty-shutdown\").start();\n\t\tboolean jetty10 = isJetty10();\n\t\tfor (Connector connector : this.server.getConnectors()) {\n\t\t\tshutdown(connector, !jetty10);\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void shutdown(Connector connector, boolean getResult) {\n\t\tFuture<Void> result;\n\t\ttry {\n\t\t\tresult = connector.shutdown();\n\t\t}\n\t\tcatch (NoSuchMethodError ex) {\n\t\t\tMethod shutdown = ReflectionUtils.findMethod(connector.getClass(), \"shutdown\");\n\t\t\tAssert.state(shutdown != null, \"'shutdown' must not be null\");\n\t\t\tresult = (Future<Void>) ReflectionUtils.invokeMethod(shutdown, connector);\n\t\t}\n\t\tif (getResult) {\n\t\t\ttry {\n\t\t\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\t\t\tresult.get();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t\tcatch (ExecutionException ex) {\n\t\t\t\t// Continue\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean isJetty10() {\n\t\ttry {\n\t\t\treturn CompletableFuture.class.equals(Connector.class.getMethod(\"shutdown\").getReturnType());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate void awaitShutdown(GracefulShutdownCallback callback) {\n\t\twhile (!this.aborted && this.activeRequests.get() > 0) {\n\t\t\tsleep(100);\n\t\t}\n\t\tif (this.aborted) {\n\t\t\tlogger.info(\"Graceful shutdown aborted with one or more requests still active\");\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE);\n\t\t}\n\t\telse {\n\t\t\tlogger.info(\"Graceful shutdown complete\");\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.IDLE);\n\t\t}\n\t}\n\n\tprivate void sleep(long millis) {\n\t\ttry {\n\t\t\tThread.sleep(millis);\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n\tvoid abort() {\n\t\tthis.aborted = true;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/JettyHandlerWrappers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport org.eclipse.jetty.compression.gzip.GzipCompression;\nimport org.eclipse.jetty.compression.server.CompressionConfig;\nimport org.eclipse.jetty.compression.server.CompressionConfig.Builder;\nimport org.eclipse.jetty.compression.server.CompressionHandler;\nimport org.eclipse.jetty.http.HttpFields.Mutable;\nimport org.eclipse.jetty.http.HttpMethod;\nimport org.eclipse.jetty.http.pathmap.PathSpec;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.Request;\nimport org.eclipse.jetty.server.Response;\nimport org.eclipse.jetty.util.Callback;\n\nimport org.springframework.boot.web.server.Compression;\n\n/**\n * Jetty {@code HandlerWrapper} static factory.\n *\n * @author Brian Clozel\n */\nfinal class JettyHandlerWrappers {\n\n\tprivate JettyHandlerWrappers() {\n\t}\n\n\tstatic Handler.Wrapper createGzipHandlerWrapper(Compression compression) {\n\t\tCompressionHandler compressionHandler = new CompressionHandler();\n\t\tGzipCompression gzip = new GzipCompression();\n\t\tgzip.setMinCompressSize((int) compression.getMinResponseSize().toBytes());\n\t\tcompressionHandler.putCompression(gzip);\n\t\tBuilder configBuilder = CompressionConfig.builder();\n\t\tfor (String mimeType : compression.getAllMimeTypes()) {\n\t\t\tconfigBuilder.compressIncludeMimeType(mimeType);\n\t\t}\n\t\tfor (HttpMethod httpMethod : HttpMethod.values()) {\n\t\t\tconfigBuilder.compressIncludeMethod(httpMethod.name());\n\t\t}\n\t\tcompressionHandler.putConfiguration(PathSpec.from(\"/\"), configBuilder.build());\n\t\treturn compressionHandler;\n\t}\n\n\tstatic Handler.Wrapper createServerHeaderHandlerWrapper(String header) {\n\t\treturn new ServerHeaderHandler(header);\n\t}\n\n\t/**\n\t * {@link Handler.Wrapper} to add a custom {@code server} header.\n\t */\n\tprivate static class ServerHeaderHandler extends Handler.Wrapper {\n\n\t\tprivate static final String SERVER_HEADER = \"server\";\n\n\t\tprivate final String value;\n\n\t\tServerHeaderHandler(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean handle(Request request, Response response, Callback callback) throws Exception {\n\t\t\tMutable headers = response.getHeaders();\n\t\t\tif (!headers.contains(SERVER_HEADER)) {\n\t\t\t\theaders.add(SERVER_HEADER, this.value);\n\t\t\t}\n\t\t\treturn super.handle(request, response, callback);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/JettyServerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\n\n/**\n * Callback interface that can be used to customize a Jetty {@link Server}.\n *\n * @author Dave Syer\n * @since 4.0.0\n * @see JettyServletWebServerFactory\n */\n@FunctionalInterface\npublic interface JettyServerCustomizer {\n\n\t/**\n\t * Customize the server.\n\t * @param server the server to customize\n\t */\n\tvoid customize(Server server);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/JettyWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.ee11.servlet.ServletHolder;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.NetworkConnector;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.handler.ContextHandler;\nimport org.eclipse.jetty.server.handler.StatisticsHandler;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.http.server.reactive.ServletHttpHandlerAdapter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link WebServer} that can be used to control a Jetty web server.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author David Liu\n * @author Eddú Meléndez\n * @author Brian Clozel\n * @author Kristine Jetzke\n * @since 4.0.0\n * @see JettyReactiveWebServerFactory\n */\npublic class JettyWebServer implements WebServer {\n\n\tprivate static final Log logger = LogFactory.getLog(JettyWebServer.class);\n\n\tprivate final Object monitor = new Object();\n\n\tprivate final Server server;\n\n\tprivate final boolean autoStart;\n\n\tprivate final @Nullable GracefulShutdown gracefulShutdown;\n\n\tprivate Connector[] connectors;\n\n\tprivate volatile boolean started;\n\n\t/**\n\t * Create a new {@link JettyWebServer} instance.\n\t * @param server the underlying Jetty server\n\t */\n\tpublic JettyWebServer(Server server) {\n\t\tthis(server, true);\n\t}\n\n\t/**\n\t * Create a new {@link JettyWebServer} instance.\n\t * @param server the underlying Jetty server\n\t * @param autoStart if auto-starting the server\n\t */\n\tpublic JettyWebServer(Server server, boolean autoStart) {\n\t\tthis.autoStart = autoStart;\n\t\tAssert.notNull(server, \"'server' must not be null\");\n\t\tthis.server = server;\n\t\tthis.gracefulShutdown = createGracefulShutdown(server);\n\t\tinitialize();\n\t}\n\n\tprivate @Nullable GracefulShutdown createGracefulShutdown(Server server) {\n\t\tStatisticsHandler statisticsHandler = findStatisticsHandler(server);\n\t\tif (statisticsHandler == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new GracefulShutdown(server, statisticsHandler::getRequestsActive);\n\t}\n\n\tprivate @Nullable StatisticsHandler findStatisticsHandler(Server server) {\n\t\treturn findStatisticsHandler(server.getHandler());\n\t}\n\n\tprivate @Nullable StatisticsHandler findStatisticsHandler(Handler handler) {\n\t\tif (handler instanceof StatisticsHandler statisticsHandler) {\n\t\t\treturn statisticsHandler;\n\t\t}\n\t\tif (handler instanceof Handler.Wrapper handlerWrapper) {\n\t\t\treturn findStatisticsHandler(handlerWrapper.getHandler());\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void initialize() {\n\t\tsynchronized (this.monitor) {\n\t\t\ttry {\n\t\t\t\t// Cache the connectors and then remove them to prevent requests being\n\t\t\t\t// handled before the application context is ready.\n\t\t\t\tthis.connectors = this.server.getConnectors();\n\t\t\t\tJettyWebServer.this.server.setConnectors(null);\n\t\t\t\t// Start the server so that the ServletContext is available\n\t\t\t\tthis.server.start();\n\t\t\t\tthis.server.setStopAtShutdown(false);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\t// Ensure process isn't left running\n\t\t\t\tstopSilently();\n\t\t\t\tthrow new WebServerException(\"Unable to start embedded Jetty web server\", ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void stopSilently() {\n\t\ttry {\n\t\t\tthis.server.stop();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t@Override\n\tpublic void start() throws WebServerException {\n\t\tsynchronized (this.monitor) {\n\t\t\tif (this.started) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.server.setConnectors(this.connectors);\n\t\t\tif (!this.autoStart) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tthis.server.start();\n\t\t\t\thandleDeferredInitialize(this.server);\n\t\t\t\tConnector[] connectors = this.server.getConnectors();\n\t\t\t\tfor (Connector connector : connectors) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconnector.start();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t\tif (connector instanceof NetworkConnector networkConnector) {\n\t\t\t\t\t\t\tPortInUseException.throwIfPortBindingException(ex, networkConnector::getPort);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow ex;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.started = true;\n\t\t\t\tlogger.info(getStartedLogMessage());\n\t\t\t}\n\t\t\tcatch (WebServerException ex) {\n\t\t\t\tstopSilently();\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tstopSilently();\n\t\t\t\tthrow new WebServerException(\"Unable to start embedded Jetty server\", ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tString getStartedLogMessage() {\n\t\tString contextPath = getContextPath();\n\t\treturn \"Jetty started on \" + getActualPortsDescription()\n\t\t\t\t+ ((contextPath != null) ? \" with context path '\" + contextPath + \"'\" : \"\");\n\t}\n\n\tprivate String getActualPortsDescription() {\n\t\tStringBuilder description = new StringBuilder(\"port\");\n\t\tConnector[] connectors = this.server.getConnectors();\n\t\tif (connectors.length != 1) {\n\t\t\tdescription.append(\"s\");\n\t\t}\n\t\tdescription.append(\" \");\n\t\tfor (int i = 0; i < connectors.length; i++) {\n\t\t\tif (i != 0) {\n\t\t\t\tdescription.append(\", \");\n\t\t\t}\n\t\t\tConnector connector = connectors[i];\n\t\t\tdescription.append(getLocalPort(connector)).append(getProtocols(connector));\n\t\t}\n\t\treturn description.toString();\n\t}\n\n\tprivate String getProtocols(Connector connector) {\n\t\tList<String> protocols = connector.getProtocols();\n\t\treturn \" (\" + StringUtils.collectionToDelimitedString(protocols, \", \") + \")\";\n\t}\n\n\tprivate @Nullable String getContextPath() {\n\t\tList<ContextHandler> imperativeContextHandlers = this.server.getHandlers()\n\t\t\t.stream()\n\t\t\t.map(this::findContextHandler)\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.filter(this::isImperative)\n\t\t\t.toList();\n\t\tif (imperativeContextHandlers.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn imperativeContextHandlers.stream().map(ContextHandler::getContextPath).collect(Collectors.joining(\" \"));\n\t}\n\n\tprivate @Nullable ContextHandler findContextHandler(Handler handler) {\n\t\twhile (handler instanceof Handler.Wrapper handlerWrapper) {\n\t\t\tif (handler instanceof ContextHandler contextHandler) {\n\t\t\t\treturn contextHandler;\n\t\t\t}\n\t\t\thandler = handlerWrapper.getHandler();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isImperative(ContextHandler contextHandler) {\n\t\tif (contextHandler instanceof ServletContextHandler servletContextHandler) {\n\t\t\tCollection<ServletHolder> servletHolders = servletContextHandler.getServletHandler()\n\t\t\t\t.getBeans(ServletHolder.class);\n\t\t\tfor (ServletHolder servletHolder : servletHolders) {\n\t\t\t\tif (ServletHttpHandlerAdapter.class.getName().equals(servletHolder.getClassName())) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Performs any necessary handling of deferred initialization.\n\t * @param server the server that has been started\n\t * @throws Exception if a failure occurs during the deferred initialization\n\t */\n\tprotected void handleDeferredInitialize(Server server) throws Exception {\n\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.started = false;\n\t\t\tif (this.gracefulShutdown != null) {\n\t\t\t\tthis.gracefulShutdown.abort();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tfor (Connector connector : this.server.getConnectors()) {\n\t\t\t\t\tconnector.stop();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new WebServerException(\"Unable to stop embedded Jetty server\", ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t\tsynchronized (this.monitor) {\n\t\t\ttry {\n\t\t\t\tthis.server.stop();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new WebServerException(\"Unable to destroy embedded Jetty server\", ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getPort() {\n\t\tConnector[] connectors = this.server.getConnectors();\n\t\tfor (Connector connector : connectors) {\n\t\t\tint localPort = getLocalPort(connector);\n\t\t\tif (localPort > 0) {\n\t\t\t\treturn localPort;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\tprivate int getLocalPort(Connector connector) {\n\t\tif (connector instanceof NetworkConnector networkConnector) {\n\t\t\treturn networkConnector.getLocalPort();\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Initiates a graceful shutdown of the Jetty web server. Handling of new requests is\n\t * prevented and the given {@code callback} is invoked at the end of the attempt. The\n\t * attempt can be explicitly ended by invoking {@link #stop}.\n\t * <p>\n\t * Once shutdown has been initiated Jetty will reject any new connections. Requests on\n\t * existing connections will be accepted, however, a {@code Connection: close} header\n\t * will be returned in the response.\n\t */\n\t@Override\n\tpublic void shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tif (this.gracefulShutdown == null) {\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);\n\t\t\treturn;\n\t\t}\n\t\tthis.gracefulShutdown.shutDownGracefully(callback);\n\t}\n\n\t/**\n\t * Returns access to the underlying Jetty Server.\n\t * @return the Jetty server\n\t */\n\tpublic Server getServer() {\n\t\treturn this.server;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/JettyWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Executor;\n\nimport org.eclipse.jetty.ee11.webapp.Configuration;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;\nimport org.eclipse.jetty.io.ByteBufferPool;\nimport org.eclipse.jetty.server.AbstractConnector;\nimport org.eclipse.jetty.server.ConnectionFactory;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.HttpConnectionFactory;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\nimport org.eclipse.jetty.util.thread.Scheduler;\nimport org.eclipse.jetty.util.thread.ThreadPool;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for factories that produce a {@link JettyWebServer}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class JettyWebServerFactory extends AbstractConfigurableWebServerFactory\n\t\timplements ConfigurableJettyWebServerFactory {\n\n\tprivate int acceptors = -1;\n\n\tprivate @Nullable ThreadPool threadPool;\n\n\tprivate int selectors = -1;\n\n\tprivate List<Configuration> configurations = new ArrayList<>();\n\n\tprivate boolean useForwardHeaders;\n\n\tprivate Set<JettyServerCustomizer> jettyServerCustomizers = new LinkedHashSet<>();\n\n\tprivate int maxConnections = -1;\n\n\tpublic JettyWebServerFactory() {\n\n\t}\n\n\tpublic JettyWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\tpublic int getAcceptors() {\n\t\treturn this.acceptors;\n\t}\n\n\t@Override\n\tpublic void setAcceptors(int acceptors) {\n\t\tthis.acceptors = acceptors;\n\t}\n\n\tpublic int getSelectors() {\n\t\treturn this.selectors;\n\t}\n\n\t@Override\n\tpublic void setSelectors(int selectors) {\n\t\tthis.selectors = selectors;\n\t}\n\n\tpublic int getMaxConnections() {\n\t\treturn this.maxConnections;\n\t}\n\n\t@Override\n\tpublic void setMaxConnections(int maxConnections) {\n\t\tthis.maxConnections = maxConnections;\n\t}\n\n\t/**\n\t * Returns a mutable collection of Jetty {@link JettyServerCustomizer}s that will be\n\t * applied to the {@link Server} before it is created.\n\t * @return the {@link JettyServerCustomizer}s\n\t */\n\tpublic Collection<JettyServerCustomizer> getServerCustomizers() {\n\t\treturn this.jettyServerCustomizers;\n\t}\n\n\t/**\n\t * Sets {@link JettyServerCustomizer}s that will be applied to the {@link Server}\n\t * before it is started. Calling this method will replace any existing customizers.\n\t * @param customizers the Jetty customizers to apply\n\t */\n\tpublic void setServerCustomizers(Collection<? extends JettyServerCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tthis.jettyServerCustomizers = new LinkedHashSet<>(customizers);\n\t}\n\n\t@Override\n\tpublic void addServerCustomizers(JettyServerCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tthis.jettyServerCustomizers.addAll(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Returns a mutable collection of Jetty {@link Configuration}s that will be applied\n\t * to the {@link WebAppContext} before the server is created.\n\t * @return the Jetty {@link Configuration}s\n\t */\n\tpublic Collection<Configuration> getConfigurations() {\n\t\treturn this.configurations;\n\t}\n\n\t/**\n\t * Sets Jetty {@link Configuration}s that will be applied to the {@link WebAppContext}\n\t * before the server is created. Calling this method will replace any existing\n\t * configurations.\n\t * @param configurations the Jetty configurations to apply\n\t */\n\tpublic void setConfigurations(Collection<? extends Configuration> configurations) {\n\t\tAssert.notNull(configurations, \"'configurations' must not be null\");\n\t\tthis.configurations = new ArrayList<>(configurations);\n\t}\n\n\t/**\n\t * Add {@link Configuration}s that will be applied to the {@link WebAppContext} before\n\t * the server is started.\n\t * @param configurations the configurations to add\n\t */\n\tpublic void addConfigurations(Configuration... configurations) {\n\t\tAssert.notNull(configurations, \"'configurations' must not be null\");\n\t\tthis.configurations.addAll(Arrays.asList(configurations));\n\t}\n\n\t/**\n\t * Returns a Jetty {@link ThreadPool} that should be used by the {@link Server}.\n\t * @return a Jetty {@link ThreadPool} or {@code null}\n\t */\n\tpublic @Nullable ThreadPool getThreadPool() {\n\t\treturn this.threadPool;\n\t}\n\n\t@Override\n\tpublic void setThreadPool(@Nullable ThreadPool threadPool) {\n\t\tthis.threadPool = threadPool;\n\t}\n\n\tpublic boolean isUseForwardHeaders() {\n\t\treturn this.useForwardHeaders;\n\t}\n\n\t@Override\n\tpublic void setUseForwardHeaders(boolean useForwardHeaders) {\n\t\tthis.useForwardHeaders = useForwardHeaders;\n\t}\n\n\tprotected AbstractConnector createConnector(InetSocketAddress address, Server server) {\n\t\treturn this.createConnector(address, server, null, null, null);\n\t}\n\n\tprotected AbstractConnector createConnector(InetSocketAddress address, Server server, @Nullable Executor executor,\n\t\t\t@Nullable Scheduler scheduler, @Nullable ByteBufferPool pool) {\n\t\tHttpConfiguration httpConfiguration = new HttpConfiguration();\n\t\thttpConfiguration.setSendServerVersion(false);\n\t\tList<ConnectionFactory> connectionFactories = new ArrayList<>();\n\t\tconnectionFactories.add(new HttpConnectionFactory(httpConfiguration));\n\t\tif (getHttp2() != null && getHttp2().isEnabled()) {\n\t\t\tconnectionFactories.add(new HTTP2CServerConnectionFactory(httpConfiguration));\n\t\t}\n\t\tServerConnector connector = new ServerConnector(server, executor, scheduler, pool, this.getAcceptors(),\n\t\t\t\tthis.getSelectors(), connectionFactories.toArray(new ConnectionFactory[0]));\n\n\t\tconnector.setHost(address.getHostString());\n\t\tconnector.setPort(address.getPort());\n\t\treturn connector;\n\t}\n\n\tprotected void customizeSsl(Server server, InetSocketAddress address) {\n\t\tSsl ssl = getSsl();\n\t\tAssert.state(ssl != null, \"'ssl' must not be null\");\n\t\tAssert.state(ssl.getServerNameBundles().isEmpty(), \"Server name SSL bundles are not supported with Jetty\");\n\t\tnew SslServerCustomizer(getHttp2(), address, ssl.getClientAuth(), getSslBundle()).customize(server);\n\t}\n\n\tprotected Handler addHandlerWrappers(Handler handler) {\n\t\tif (getCompression() != null && getCompression().getEnabled()) {\n\t\t\thandler = applyWrapper(handler, JettyHandlerWrappers.createGzipHandlerWrapper(getCompression()));\n\t\t}\n\t\tif (StringUtils.hasText(getServerHeader())) {\n\t\t\thandler = applyWrapper(handler, JettyHandlerWrappers.createServerHeaderHandlerWrapper(getServerHeader()));\n\t\t}\n\t\treturn handler;\n\t}\n\n\tprotected Handler applyWrapper(Handler handler, Handler.Wrapper wrapper) {\n\t\twrapper.setHandler(handler);\n\t\treturn wrapper;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/SslServerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport java.net.InetSocketAddress;\n\nimport org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;\nimport org.eclipse.jetty.http.HttpVersion;\nimport org.eclipse.jetty.http2.HTTP2Cipher;\nimport org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;\nimport org.eclipse.jetty.server.ConnectionFactory;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.HttpConnectionFactory;\nimport org.eclipse.jetty.server.SecureRequestCustomizer;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\nimport org.eclipse.jetty.server.SslConnectionFactory;\nimport org.eclipse.jetty.util.ssl.SslContextFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.web.server.Http2;\nimport org.springframework.boot.web.server.Ssl.ClientAuth;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link JettyServerCustomizer} that configures SSL on the given Jetty server instance.\n *\n * @author Brian Clozel\n * @author Olivier Lamy\n * @author Chris Bono\n * @author Cyril Dangerville\n * @author Scott Frederick\n */\nclass SslServerCustomizer implements JettyServerCustomizer {\n\n\tprivate final @Nullable Http2 http2;\n\n\tprivate final InetSocketAddress address;\n\n\tprivate final @Nullable ClientAuth clientAuth;\n\n\tprivate final SslBundle sslBundle;\n\n\tSslServerCustomizer(@Nullable Http2 http2, InetSocketAddress address, @Nullable ClientAuth clientAuth,\n\t\t\tSslBundle sslBundle) {\n\t\tthis.address = address;\n\t\tthis.clientAuth = clientAuth;\n\t\tthis.sslBundle = sslBundle;\n\t\tthis.http2 = http2;\n\t}\n\n\t@Override\n\tpublic void customize(Server server) {\n\t\tSslContextFactory.Server sslContextFactory = new SslContextFactory.Server();\n\t\tsslContextFactory.setEndpointIdentificationAlgorithm(null);\n\t\tconfigureSsl(sslContextFactory, this.clientAuth);\n\t\tServerConnector connector = createConnector(server, sslContextFactory);\n\t\tserver.setConnectors(new Connector[] { connector });\n\t}\n\n\tprivate ServerConnector createConnector(Server server, SslContextFactory.Server sslContextFactory) {\n\t\tHttpConfiguration config = new HttpConfiguration();\n\t\tconfig.setSendServerVersion(false);\n\t\tconfig.setSecureScheme(\"https\");\n\t\tconfig.setSecurePort(this.address.getPort());\n\t\tconfig.addCustomizer(new SecureRequestCustomizer());\n\t\tServerConnector connector = createServerConnector(server, sslContextFactory, config);\n\t\tconnector.setPort(this.address.getPort());\n\t\tconnector.setHost(this.address.getHostString());\n\t\treturn connector;\n\t}\n\n\tprivate ServerConnector createServerConnector(Server server, SslContextFactory.Server sslContextFactory,\n\t\t\tHttpConfiguration config) {\n\t\tif (this.http2 == null || !this.http2.isEnabled()) {\n\t\t\treturn createHttp11ServerConnector(config, sslContextFactory, server);\n\t\t}\n\t\tAssert.state(isJettyAlpnPresent(),\n\t\t\t\t() -> \"An 'org.eclipse.jetty:jetty-alpn-*-server' dependency is required for HTTP/2 support.\");\n\t\tAssert.state(isJettyHttp2Present(),\n\t\t\t\t() -> \"The 'org.eclipse.jetty.http2:jetty-http2-server' dependency is required for HTTP/2 support.\");\n\t\treturn createHttp2ServerConnector(config, sslContextFactory, server);\n\t}\n\n\tprivate ServerConnector createHttp11ServerConnector(HttpConfiguration config,\n\t\t\tSslContextFactory.Server sslContextFactory, Server server) {\n\t\tSslConnectionFactory sslConnectionFactory = createSslConnectionFactory(sslContextFactory,\n\t\t\t\tHttpVersion.HTTP_1_1.asString());\n\t\tHttpConnectionFactory connectionFactory = new HttpConnectionFactory(config);\n\t\treturn new SslValidatingServerConnector(this.sslBundle.getKey(), sslContextFactory, server,\n\t\t\t\tsslConnectionFactory, connectionFactory);\n\t}\n\n\tprivate SslConnectionFactory createSslConnectionFactory(SslContextFactory.Server sslContextFactory,\n\t\t\tString protocol) {\n\t\treturn new SslConnectionFactory(sslContextFactory, protocol);\n\t}\n\n\tprivate boolean isJettyAlpnPresent() {\n\t\treturn ClassUtils.isPresent(\"org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory\", null);\n\t}\n\n\tprivate boolean isJettyHttp2Present() {\n\t\treturn ClassUtils.isPresent(\"org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory\", null);\n\t}\n\n\tprivate ServerConnector createHttp2ServerConnector(HttpConfiguration config,\n\t\t\tSslContextFactory.Server sslContextFactory, Server server) {\n\t\tHttpConnectionFactory http = new HttpConnectionFactory(config);\n\t\tHTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(config);\n\t\tALPNServerConnectionFactory alpn = createAlpnServerConnectionFactory();\n\t\tsslContextFactory.setCipherComparator(HTTP2Cipher.COMPARATOR);\n\t\tif (isConscryptPresent()) {\n\t\t\tsslContextFactory.setProvider(\"Conscrypt\");\n\t\t}\n\t\tSslConnectionFactory sslConnectionFactory = createSslConnectionFactory(sslContextFactory, alpn.getProtocol());\n\t\treturn new SslValidatingServerConnector(this.sslBundle.getKey(), sslContextFactory, server,\n\t\t\t\tsslConnectionFactory, alpn, h2, http);\n\t}\n\n\tprivate ALPNServerConnectionFactory createAlpnServerConnectionFactory() {\n\t\ttry {\n\t\t\treturn new ALPNServerConnectionFactory();\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"An 'org.eclipse.jetty:jetty-alpn-*-server' dependency is required for HTTP/2 support.\", ex);\n\t\t}\n\t}\n\n\tprivate boolean isConscryptPresent() {\n\t\treturn ClassUtils.isPresent(\"org.conscrypt.Conscrypt\", null)\n\t\t\t\t&& ClassUtils.isPresent(\"org.eclipse.jetty.alpn.conscrypt.server.ConscryptServerALPNProcessor\", null);\n\t}\n\n\t/**\n\t * Configure the SSL connection.\n\t * @param factory the Jetty {@link Server SslContextFactory.Server}.\n\t * @param clientAuth the client authentication mode\n\t */\n\tprotected void configureSsl(SslContextFactory.Server factory, @Nullable ClientAuth clientAuth) {\n\t\tSslBundleKey key = this.sslBundle.getKey();\n\t\tSslOptions options = this.sslBundle.getOptions();\n\t\tSslStoreBundle stores = this.sslBundle.getStores();\n\t\tfactory.setProtocol(this.sslBundle.getProtocol());\n\t\tconfigureSslClientAuth(factory, clientAuth);\n\t\tif (stores.getKeyStorePassword() != null) {\n\t\t\tfactory.setKeyStorePassword(stores.getKeyStorePassword());\n\t\t}\n\t\tfactory.setCertAlias(key.getAlias());\n\t\tif (options.getCiphers() != null) {\n\t\t\tfactory.setIncludeCipherSuites(options.getCiphers());\n\t\t\tfactory.setExcludeCipherSuites();\n\t\t}\n\t\tif (options.getEnabledProtocols() != null) {\n\t\t\tfactory.setIncludeProtocols(options.getEnabledProtocols());\n\t\t\tfactory.setExcludeProtocols();\n\t\t}\n\t\ttry {\n\t\t\tif (key.getPassword() != null) {\n\t\t\t\tfactory.setKeyManagerPassword(key.getPassword());\n\t\t\t}\n\t\t\tfactory.setKeyStore(stores.getKeyStore());\n\t\t\tfactory.setTrustStore(stores.getTrustStore());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to set SSL store: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate void configureSslClientAuth(SslContextFactory.Server factory, @Nullable ClientAuth clientAuth) {\n\t\tfactory.setWantClientAuth(clientAuth == ClientAuth.WANT || clientAuth == ClientAuth.NEED);\n\t\tfactory.setNeedClientAuth(clientAuth == ClientAuth.NEED);\n\t}\n\n\t/**\n\t * A {@link ServerConnector} that validates the ssl key alias on server startup.\n\t */\n\tstatic class SslValidatingServerConnector extends ServerConnector {\n\n\t\tprivate final SslBundleKey key;\n\n\t\tprivate final SslContextFactory sslContextFactory;\n\n\t\tSslValidatingServerConnector(SslBundleKey key, SslContextFactory sslContextFactory, Server server,\n\t\t\t\tSslConnectionFactory sslConnectionFactory, HttpConnectionFactory connectionFactory) {\n\t\t\tsuper(server, sslConnectionFactory, connectionFactory);\n\t\t\tthis.key = key;\n\t\t\tthis.sslContextFactory = sslContextFactory;\n\t\t}\n\n\t\tSslValidatingServerConnector(SslBundleKey keyAlias, SslContextFactory sslContextFactory, Server server,\n\t\t\t\tConnectionFactory... factories) {\n\t\t\tsuper(server, factories);\n\t\t\tthis.key = keyAlias;\n\t\t\tthis.sslContextFactory = sslContextFactory;\n\t\t}\n\n\t\t@Override\n\t\tprotected void doStart() throws Exception {\n\t\t\tsuper.doStart();\n\t\t\tthis.key.assertContainsAlias(this.sslContextFactory.getKeyStore());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/JettyServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Jetty server properties.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Ivan Sopov\n * @author Marcos Barbero\n * @author Eddú Meléndez\n * @author Quinten De Swaef\n * @author Venil Noronha\n * @author Aurélien Leboulanger\n * @author Brian Clozel\n * @author Olivier Lamy\n * @author Chentao Qu\n * @author Artsiom Yudovin\n * @author Andrew McGhie\n * @author Rafiullah Hamedy\n * @author Dirk Deyne\n * @author HaiTao Zhang\n * @author Victor Mandujano\n * @author Chris Bono\n * @author Parviz Rozikov\n * @author Florian Storz\n * @author Michael Weidmann\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@ConfigurationProperties(\"server.jetty\")\npublic class JettyServerProperties {\n\n\t/**\n\t * Maximum size of the form content in any HTTP post request.\n\t */\n\tprivate DataSize maxHttpFormPostSize = DataSize.ofBytes(200000);\n\n\t/**\n\t * Maximum number of form keys.\n\t */\n\tprivate int maxFormKeys = 1000;\n\n\t/**\n\t * Time that the connection can be idle before it is closed.\n\t */\n\tprivate @Nullable Duration connectionIdleTimeout;\n\n\t/**\n\t * Maximum size of the HTTP response header.\n\t */\n\tprivate DataSize maxHttpResponseHeaderSize = DataSize.ofKilobytes(16);\n\n\t/**\n\t * Maximum number of connections that the server accepts and processes at any given\n\t * time.\n\t */\n\tprivate int maxConnections = -1;\n\n\t/**\n\t * Access log configuration.\n\t */\n\tprivate final Accesslog accesslog = new Accesslog();\n\n\t/**\n\t * Thread related configuration.\n\t */\n\tprivate final Threads threads = new Threads();\n\n\tpublic Accesslog getAccesslog() {\n\t\treturn this.accesslog;\n\t}\n\n\tpublic Threads getThreads() {\n\t\treturn this.threads;\n\t}\n\n\tpublic DataSize getMaxHttpFormPostSize() {\n\t\treturn this.maxHttpFormPostSize;\n\t}\n\n\tpublic void setMaxHttpFormPostSize(DataSize maxHttpFormPostSize) {\n\t\tthis.maxHttpFormPostSize = maxHttpFormPostSize;\n\t}\n\n\tpublic int getMaxFormKeys() {\n\t\treturn this.maxFormKeys;\n\t}\n\n\tpublic void setMaxFormKeys(int maxFormKeys) {\n\t\tthis.maxFormKeys = maxFormKeys;\n\t}\n\n\tpublic @Nullable Duration getConnectionIdleTimeout() {\n\t\treturn this.connectionIdleTimeout;\n\t}\n\n\tpublic void setConnectionIdleTimeout(@Nullable Duration connectionIdleTimeout) {\n\t\tthis.connectionIdleTimeout = connectionIdleTimeout;\n\t}\n\n\tpublic DataSize getMaxHttpResponseHeaderSize() {\n\t\treturn this.maxHttpResponseHeaderSize;\n\t}\n\n\tpublic void setMaxHttpResponseHeaderSize(DataSize maxHttpResponseHeaderSize) {\n\t\tthis.maxHttpResponseHeaderSize = maxHttpResponseHeaderSize;\n\t}\n\n\tpublic int getMaxConnections() {\n\t\treturn this.maxConnections;\n\t}\n\n\tpublic void setMaxConnections(int maxConnections) {\n\t\tthis.maxConnections = maxConnections;\n\t}\n\n\t/**\n\t * Jetty access log properties.\n\t */\n\tpublic static class Accesslog {\n\n\t\t/**\n\t\t * Enable access log.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Log format.\n\t\t */\n\t\tprivate Accesslog.Format format = Format.NCSA;\n\n\t\t/**\n\t\t * Custom log format, see org.eclipse.jetty.server.CustomRequestLog. If defined,\n\t\t * overrides the \"format\" configuration key.\n\t\t */\n\t\tprivate @Nullable String customFormat;\n\n\t\t/**\n\t\t * Log filename. If not specified, logs redirect to \"System.err\".\n\t\t */\n\t\tprivate @Nullable String filename;\n\n\t\t/**\n\t\t * Date format to place in log file name.\n\t\t */\n\t\tprivate @Nullable String fileDateFormat;\n\n\t\t/**\n\t\t * Number of days before rotated log files are deleted.\n\t\t */\n\t\tprivate int retentionPeriod = 31; // no days\n\n\t\t/**\n\t\t * Append to log.\n\t\t */\n\t\tprivate boolean append;\n\n\t\t/**\n\t\t * Request paths that should not be logged.\n\t\t */\n\t\tprivate @Nullable List<String> ignorePaths;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic Accesslog.Format getFormat() {\n\t\t\treturn this.format;\n\t\t}\n\n\t\tpublic void setFormat(Accesslog.Format format) {\n\t\t\tthis.format = format;\n\t\t}\n\n\t\tpublic @Nullable String getCustomFormat() {\n\t\t\treturn this.customFormat;\n\t\t}\n\n\t\tpublic void setCustomFormat(@Nullable String customFormat) {\n\t\t\tthis.customFormat = customFormat;\n\t\t}\n\n\t\tpublic @Nullable String getFilename() {\n\t\t\treturn this.filename;\n\t\t}\n\n\t\tpublic void setFilename(@Nullable String filename) {\n\t\t\tthis.filename = filename;\n\t\t}\n\n\t\tpublic @Nullable String getFileDateFormat() {\n\t\t\treturn this.fileDateFormat;\n\t\t}\n\n\t\tpublic void setFileDateFormat(@Nullable String fileDateFormat) {\n\t\t\tthis.fileDateFormat = fileDateFormat;\n\t\t}\n\n\t\tpublic int getRetentionPeriod() {\n\t\t\treturn this.retentionPeriod;\n\t\t}\n\n\t\tpublic void setRetentionPeriod(int retentionPeriod) {\n\t\t\tthis.retentionPeriod = retentionPeriod;\n\t\t}\n\n\t\tpublic boolean isAppend() {\n\t\t\treturn this.append;\n\t\t}\n\n\t\tpublic void setAppend(boolean append) {\n\t\t\tthis.append = append;\n\t\t}\n\n\t\tpublic @Nullable List<String> getIgnorePaths() {\n\t\t\treturn this.ignorePaths;\n\t\t}\n\n\t\tpublic void setIgnorePaths(@Nullable List<String> ignorePaths) {\n\t\t\tthis.ignorePaths = ignorePaths;\n\t\t}\n\n\t\t/**\n\t\t * Log format for Jetty access logs.\n\t\t */\n\t\tpublic enum Format {\n\n\t\t\t/**\n\t\t\t * NCSA format, as defined in CustomRequestLog#NCSA_FORMAT.\n\t\t\t */\n\t\t\tNCSA,\n\n\t\t\t/**\n\t\t\t * Extended NCSA format, as defined in CustomRequestLog#EXTENDED_NCSA_FORMAT.\n\t\t\t */\n\t\t\tEXTENDED_NCSA\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Jetty thread properties.\n\t */\n\tpublic static class Threads {\n\n\t\t/**\n\t\t * Number of acceptor threads to use. When the value is -1, the default, the\n\t\t * number of acceptors is derived from the operating environment.\n\t\t */\n\t\tprivate Integer acceptors = -1;\n\n\t\t/**\n\t\t * Number of selector threads to use. When the value is -1, the default, the\n\t\t * number of selectors is derived from the operating environment.\n\t\t */\n\t\tprivate Integer selectors = -1;\n\n\t\t/**\n\t\t * Maximum number of threads.\n\t\t */\n\t\tprivate Integer max = 200;\n\n\t\t/**\n\t\t * Minimum number of threads. Doesn't have an effect if virtual threads are\n\t\t * enabled.\n\t\t */\n\t\tprivate Integer min = 8;\n\n\t\t/**\n\t\t * Maximum capacity of the thread pool's backing queue. A default is computed\n\t\t * based on the threading configuration.\n\t\t */\n\t\tprivate @Nullable Integer maxQueueCapacity;\n\n\t\t/**\n\t\t * Maximum thread idle time.\n\t\t */\n\t\tprivate Duration idleTimeout = Duration.ofMillis(60000);\n\n\t\tpublic Integer getAcceptors() {\n\t\t\treturn this.acceptors;\n\t\t}\n\n\t\tpublic void setAcceptors(Integer acceptors) {\n\t\t\tthis.acceptors = acceptors;\n\t\t}\n\n\t\tpublic Integer getSelectors() {\n\t\t\treturn this.selectors;\n\t\t}\n\n\t\tpublic void setSelectors(Integer selectors) {\n\t\t\tthis.selectors = selectors;\n\t\t}\n\n\t\tpublic void setMin(Integer min) {\n\t\t\tthis.min = min;\n\t\t}\n\n\t\tpublic Integer getMin() {\n\t\t\treturn this.min;\n\t\t}\n\n\t\tpublic void setMax(Integer max) {\n\t\t\tthis.max = max;\n\t\t}\n\n\t\tpublic Integer getMax() {\n\t\t\treturn this.max;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxQueueCapacity() {\n\t\t\treturn this.maxQueueCapacity;\n\t\t}\n\n\t\tpublic void setMaxQueueCapacity(@Nullable Integer maxQueueCapacity) {\n\t\t\tthis.maxQueueCapacity = maxQueueCapacity;\n\t\t}\n\n\t\tpublic void setIdleTimeout(Duration idleTimeout) {\n\t\t\tthis.idleTimeout = idleTimeout;\n\t\t}\n\n\t\tpublic Duration getIdleTimeout() {\n\t\t\treturn this.idleTimeout;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/JettyThreadPool.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.SynchronousQueue;\n\nimport org.eclipse.jetty.util.BlockingArrayQueue;\nimport org.eclipse.jetty.util.thread.QueuedThreadPool;\nimport org.eclipse.jetty.util.thread.ThreadPool;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.lang.Contract;\n\n/**\n * Creates a {@link ThreadPool} for Jetty, applying\n * {@link org.springframework.boot.jetty.autoconfigure.JettyServerProperties.Threads\n * ServerProperties.Jetty.Threads Jetty thread properties}.\n *\n * @author Moritz Halbritter\n */\nfinal class JettyThreadPool {\n\n\tprivate JettyThreadPool() {\n\t}\n\n\tstatic QueuedThreadPool create(JettyServerProperties.Threads properties) {\n\t\tBlockingQueue<Runnable> queue = determineBlockingQueue(properties.getMaxQueueCapacity());\n\t\tint maxThreadCount = (properties.getMax() > 0) ? properties.getMax() : 200;\n\t\tint minThreadCount = (properties.getMin() > 0) ? properties.getMin() : 8;\n\t\tint threadIdleTimeout = (properties.getIdleTimeout() != null) ? (int) properties.getIdleTimeout().toMillis()\n\t\t\t\t: 60000;\n\t\treturn new QueuedThreadPool(maxThreadCount, minThreadCount, threadIdleTimeout, queue);\n\t}\n\n\t@Contract(\"!null -> !null\")\n\tprivate static @Nullable BlockingQueue<Runnable> determineBlockingQueue(@Nullable Integer maxQueueCapacity) {\n\t\tif (maxQueueCapacity == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (maxQueueCapacity == 0) {\n\t\t\treturn new SynchronousQueue<>();\n\t\t}\n\t\treturn new BlockingArrayQueue<>(maxQueueCapacity);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/JettyVirtualThreadsWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport org.eclipse.jetty.util.VirtualThreads;\nimport org.eclipse.jetty.util.thread.VirtualThreadPool;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Activates virtual threads on the {@link ConfigurableJettyWebServerFactory}.\n *\n * @author Moritz Halbritter\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class JettyVirtualThreadsWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory>, Ordered {\n\n\tprivate final @Nullable JettyServerProperties serverProperties;\n\n\t/**\n\t * Create a new JettyVirtualThreadsWebServerFactoryCustomizer.\n\t * @deprecated since 4.0.3 for removal in 4.3.0 in favor of\n\t * {@link #JettyVirtualThreadsWebServerFactoryCustomizer(JettyServerProperties)}\n\t */\n\t@Deprecated(since = \"4.0.3\", forRemoval = true)\n\t// Suppress the null passing here as we don't want to put @Nullable on the\n\t// JettyServerProperties in the other constructor\n\t@SuppressWarnings(\"NullAway\")\n\tpublic JettyVirtualThreadsWebServerFactoryCustomizer() {\n\t\tthis(null);\n\t}\n\n\t/**\n\t * Create a new JettyVirtualThreadsWebServerFactoryCustomizer.\n\t * @param serverProperties the server properties\n\t */\n\tpublic JettyVirtualThreadsWebServerFactoryCustomizer(JettyServerProperties serverProperties) {\n\t\tthis.serverProperties = serverProperties;\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableJettyWebServerFactory factory) {\n\t\tAssert.state(VirtualThreads.areSupported(), \"Virtual threads are not supported\");\n\t\tInteger maxTasks = getMaxTasks();\n\t\tVirtualThreadPool virtualThreadPool = (maxTasks != null) ? new VirtualThreadPool(maxTasks)\n\t\t\t\t: new VirtualThreadPool();\n\t\tvirtualThreadPool.setName(\"jetty-\");\n\t\tfactory.setThreadPool(virtualThreadPool);\n\t}\n\n\tprivate @Nullable Integer getMaxTasks() {\n\t\tif (this.serverProperties == null) {\n\t\t\treturn null;\n\t\t}\n\t\tInteger maxThreads = this.serverProperties.getThreads().getMax();\n\t\treturn (maxThreads > 0) ? maxThreads : null;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn JettyWebServerFactoryCustomizer.ORDER + 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/JettyWebServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.jetty.autoconfigure.reactive.JettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.jetty.autoconfigure.servlet.JettyServletWebServerAutoConfiguration;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link Configuration Configuration} for a Jetty-based reactive or servlet web server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see JettyReactiveWebServerAutoConfiguration\n * @see JettyServletWebServerAutoConfiguration\n */\n@ConditionalOnNotWarDeployment\n@Configuration(proxyBeanMethods = false)\npublic class JettyWebServerConfiguration {\n\n\tprivate final JettyServerProperties jettyProperties;\n\n\tJettyWebServerConfiguration(JettyServerProperties jettyProperties) {\n\t\tthis.jettyProperties = jettyProperties;\n\t}\n\n\t@Bean\n\tJettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment,\n\t\t\tServerProperties serverProperties) {\n\t\treturn new JettyWebServerFactoryCustomizer(environment, serverProperties, this.jettyProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tJettyVirtualThreadsWebServerFactoryCustomizer jettyVirtualThreadsWebServerFactoryCustomizer() {\n\t\treturn new JettyVirtualThreadsWebServerFactoryCustomizer(this.jettyProperties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/JettyWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.server.AbstractConnector;\nimport org.eclipse.jetty.server.ConnectionFactory;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.CustomRequestLog;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.RequestLogWriter;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\nimport org.springframework.boot.jetty.autoconfigure.JettyServerProperties.Accesslog;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Customization for Jetty-specific features common for both Servlet and Reactive servers.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @author HaiTao Zhang\n * @author Rafiullah Hamedy\n * @author Florian Storz\n * @author Michael Weidmann\n * @since 4.0.0\n */\npublic class JettyWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory>, Ordered {\n\n\tstatic final int ORDER = 0;\n\n\tprivate final Environment environment;\n\n\tprivate final ServerProperties serverProperties;\n\n\tprivate final JettyServerProperties jettyProperties;\n\n\tpublic JettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties,\n\t\t\tJettyServerProperties jettyProperties) {\n\t\tthis.environment = environment;\n\t\tthis.serverProperties = serverProperties;\n\t\tthis.jettyProperties = jettyProperties;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableJettyWebServerFactory factory) {\n\t\tfactory.setUseForwardHeaders(getOrDeduceUseForwardHeaders());\n\t\tJettyServerProperties.Threads threadProperties = this.jettyProperties.getThreads();\n\t\tfactory.setThreadPool(JettyThreadPool.create(this.jettyProperties.getThreads()));\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.jettyProperties::getMaxConnections).to(factory::setMaxConnections);\n\t\tmap.from(threadProperties::getAcceptors).to(factory::setAcceptors);\n\t\tmap.from(threadProperties::getSelectors).to(factory::setSelectors);\n\t\tmap.from(this.serverProperties::getMaxHttpRequestHeaderSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.when(this::isPositive)\n\t\t\t.to(customizeHttpConfigurations(factory, HttpConfiguration::setRequestHeaderSize));\n\t\tmap.from(this.jettyProperties::getMaxHttpResponseHeaderSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.when(this::isPositive)\n\t\t\t.to(customizeHttpConfigurations(factory, HttpConfiguration::setMaxResponseHeaderSize));\n\t\tmap.from(this.jettyProperties::getMaxHttpFormPostSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.when(this::isPositive)\n\t\t\t.to(customizeServletContextHandler(factory, ServletContextHandler::setMaxFormContentSize));\n\t\tmap.from(this.jettyProperties::getMaxFormKeys)\n\t\t\t.when(this::isPositive)\n\t\t\t.to(customizeServletContextHandler(factory, ServletContextHandler::setMaxFormKeys));\n\t\tmap.from(this.jettyProperties::getConnectionIdleTimeout)\n\t\t\t.as(Duration::toMillis)\n\t\t\t.to(customizeAbstractConnectors(factory, AbstractConnector::setIdleTimeout));\n\t\tmap.from(this.jettyProperties::getAccesslog)\n\t\t\t.when(JettyServerProperties.Accesslog::isEnabled)\n\t\t\t.to((accesslog) -> customizeAccessLog(factory, accesslog));\n\t}\n\n\tprivate boolean isPositive(Integer value) {\n\t\treturn value > 0;\n\t}\n\n\tprivate boolean getOrDeduceUseForwardHeaders() {\n\t\tif (this.serverProperties.getForwardHeadersStrategy() == null) {\n\t\t\tCloudPlatform platform = CloudPlatform.getActive(this.environment);\n\t\t\treturn platform != null && platform.isUsingForwardHeaders();\n\t\t}\n\t\treturn this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NATIVE);\n\t}\n\n\tprivate <T> Consumer<T> customizeHttpConfigurations(ConfigurableJettyWebServerFactory factory,\n\t\t\tBiConsumer<HttpConfiguration, T> action) {\n\t\treturn customizeConnectionFactories(factory, HttpConfiguration.ConnectionFactory.class,\n\t\t\t\t(connectionFactory, value) -> action.accept(connectionFactory.getHttpConfiguration(), value));\n\t}\n\n\tprivate <V, F> Consumer<V> customizeConnectionFactories(ConfigurableJettyWebServerFactory factory,\n\t\t\tClass<F> connectionFactoryType, BiConsumer<F, V> action) {\n\t\treturn customizeConnectors(factory, Connector.class, (connector, value) -> {\n\t\t\tStream<ConnectionFactory> connectionFactories = connector.getConnectionFactories().stream();\n\t\t\tforEach(connectionFactories, connectionFactoryType, action, value);\n\t\t});\n\t}\n\n\tprivate <V> Consumer<V> customizeAbstractConnectors(ConfigurableJettyWebServerFactory factory,\n\t\t\tBiConsumer<AbstractConnector, V> action) {\n\t\treturn customizeConnectors(factory, AbstractConnector.class, action);\n\t}\n\n\tprivate <V, C> Consumer<V> customizeConnectors(ConfigurableJettyWebServerFactory factory, Class<C> connectorType,\n\t\t\tBiConsumer<C, V> action) {\n\t\treturn (value) -> factory.addServerCustomizers((server) -> {\n\t\t\tStream<Connector> connectors = Arrays.stream(server.getConnectors());\n\t\t\tforEach(connectors, connectorType, action, value);\n\t\t});\n\t}\n\n\tprivate <V> Consumer<V> customizeServletContextHandler(ConfigurableJettyWebServerFactory factory,\n\t\t\tBiConsumer<ServletContextHandler, V> action) {\n\t\treturn customizeHandlers(factory, ServletContextHandler.class, action);\n\t}\n\n\tprivate <V, H> Consumer<V> customizeHandlers(ConfigurableJettyWebServerFactory factory, Class<H> handlerType,\n\t\t\tBiConsumer<H, V> action) {\n\t\treturn (value) -> factory.addServerCustomizers((server) -> {\n\t\t\tList<Handler> handlers = server.getHandlers();\n\t\t\tforEachHandler(handlers, handlerType, action, value);\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <V, H> void forEachHandler(List<Handler> handlers, Class<H> handlerType, BiConsumer<H, V> action, V value) {\n\t\tfor (Handler handler : handlers) {\n\t\t\tif (handlerType.isInstance(handler)) {\n\t\t\t\taction.accept((H) handler, value);\n\t\t\t}\n\t\t\tif (handler instanceof Handler.Wrapper wrapper) {\n\t\t\t\tforEachHandler(wrapper.getHandlers(), handlerType, action, value);\n\t\t\t}\n\t\t\tif (handler instanceof Handler.Collection collection) {\n\t\t\t\tforEachHandler(collection.getHandlers(), handlerType, action, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate <T, V> void forEach(Stream<?> elements, Class<T> type, BiConsumer<T, V> action, V value) {\n\t\telements.filter(type::isInstance).map(type::cast).forEach((element) -> action.accept(element, value));\n\t}\n\n\tprivate void customizeAccessLog(ConfigurableJettyWebServerFactory factory,\n\t\t\tJettyServerProperties.Accesslog properties) {\n\t\tfactory.addServerCustomizers((server) -> {\n\t\t\tRequestLogWriter logWriter = new RequestLogWriter();\n\t\t\tString format = getLogFormat(properties);\n\t\t\tCustomRequestLog log = new CustomRequestLog(logWriter, format);\n\t\t\tif (!CollectionUtils.isEmpty(properties.getIgnorePaths())) {\n\t\t\t\tlog.setIgnorePaths(properties.getIgnorePaths().toArray(new String[0]));\n\t\t\t}\n\t\t\tif (properties.getFilename() != null) {\n\t\t\t\tlogWriter.setFilename(properties.getFilename());\n\t\t\t}\n\t\t\tif (properties.getFileDateFormat() != null) {\n\t\t\t\tlogWriter.setFilenameDateFormat(properties.getFileDateFormat());\n\t\t\t}\n\t\t\tlogWriter.setRetainDays(properties.getRetentionPeriod());\n\t\t\tlogWriter.setAppend(properties.isAppend());\n\t\t\tserver.setRequestLog(log);\n\t\t});\n\t}\n\n\tprivate String getLogFormat(JettyServerProperties.Accesslog properties) {\n\t\tif (properties.getCustomFormat() != null) {\n\t\t\treturn properties.getCustomFormat();\n\t\t}\n\t\tif (Accesslog.Format.EXTENDED_NCSA.equals(properties.getFormat())) {\n\t\t\treturn CustomRequestLog.EXTENDED_NCSA_FORMAT;\n\t\t}\n\t\treturn CustomRequestLog.NCSA_FORMAT;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyAccessLogCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport java.io.File;\n\nimport org.eclipse.jetty.server.CustomRequestLog;\nimport org.eclipse.jetty.server.RequestLog;\nimport org.eclipse.jetty.server.RequestLogWriter;\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.actuate.autoconfigure.web.server.AccessLogCustomizer;\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link AccessLogCustomizer} for Jetty.\n *\n * @author Andy Wilkinson\n */\nclass JettyAccessLogCustomizer extends AccessLogCustomizer<ConfigurableJettyWebServerFactory>\n\t\timplements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory> {\n\n\tJettyAccessLogCustomizer(JettyManagementServerProperties properties) {\n\t\tsuper(properties.getAccesslog().getPrefix());\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableJettyWebServerFactory factory) {\n\t\tfactory.addServerCustomizers(this::customizeServer);\n\t}\n\n\tprivate void customizeServer(Server server) {\n\t\tRequestLog requestLog = server.getRequestLog();\n\t\tif (requestLog instanceof CustomRequestLog customRequestLog) {\n\t\t\tcustomizeRequestLog(customRequestLog);\n\t\t}\n\t}\n\n\tprivate void customizeRequestLog(CustomRequestLog requestLog) {\n\t\tif (requestLog.getWriter() instanceof RequestLogWriter requestLogWriter) {\n\t\t\tcustomizeRequestLogWriter(requestLogWriter);\n\t\t}\n\t}\n\n\tprivate void customizeRequestLogWriter(RequestLogWriter writer) {\n\t\tString filename = writer.getFileName();\n\t\tif (StringUtils.hasLength(filename)) {\n\t\t\tFile file = new File(filename);\n\t\t\tfile = new File(file.getParentFile(), customizePrefix(file.getName()));\n\t\t\twriter.setFilename(file.getPath());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyManagementServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties for a Jetty-based management server.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.server.jetty\")\npublic class JettyManagementServerProperties {\n\n\tprivate final Accesslog accesslog = new Accesslog();\n\n\tpublic Accesslog getAccesslog() {\n\t\treturn this.accesslog;\n\t}\n\n\tpublic static class Accesslog {\n\n\t\t/**\n\t\t * Management log file name prefix.\n\t\t */\n\t\tprivate String prefix = \"management_\";\n\n\t\tpublic String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic void setPrefix(String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyReactiveManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jetty-based\n * reactive web endpoint infrastructure when a separate management context running on a\n * different port is required.\n *\n * @author Andy Wilkinson\n */\n@ConditionalOnClass(Server.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(JettyManagementServerProperties.class)\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\nclass JettyReactiveManagementChildContextConfiguration {\n\n\t@Bean\n\tJettyAccessLogCustomizer jettyManagementAccessLogCustomizer(JettyManagementServerProperties properties) {\n\t\treturn new JettyAccessLogCustomizer(properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyReactiveManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.jetty.autoconfigure.reactive.JettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for a Jetty-based reactive management context.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Server.class, ManagementContextFactory.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\npublic final class JettyReactiveManagementContextAutoConfiguration {\n\n\t@Bean\n\tstatic ManagementContextFactory reactiveWebChildContextFactory() {\n\t\treturn new ManagementContextFactory(WebApplicationType.REACTIVE, ReactiveWebServerFactory.class,\n\t\t\t\tJettyReactiveWebServerAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyServletManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Jetty-based\n * servlet web endpoint infrastructure when a separate management context running on a\n * different port is required.\n *\n * @author Andy Wilkinson\n */\n@ConditionalOnClass(Server.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(JettyManagementServerProperties.class)\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\nclass JettyServletManagementChildContextConfiguration {\n\n\t@Bean\n\tJettyAccessLogCustomizer jettyManagementAccessLogCustomizer(JettyManagementServerProperties properties) {\n\t\treturn new JettyAccessLogCustomizer(properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyServletManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.jetty.autoconfigure.servlet.JettyServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for a Jetty-based servlet management context.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Server.class, ManagementContextFactory.class })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\npublic final class JettyServletManagementContextAutoConfiguration {\n\n\t@Bean\n\tstatic ManagementContextFactory servletWebChildContextFactory() {\n\t\treturn new ManagementContextFactory(WebApplicationType.SERVLET, ServletWebServerFactory.class,\n\t\t\t\tJettyServletWebServerAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jetty actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/metrics/JettyMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.jetty.JettyConnectionMetrics;\nimport io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics;\nimport io.micrometer.core.instrument.binder.jetty.JettySslHandshakeMetrics;\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.jetty.metrics.JettyConnectionMetricsBinder;\nimport org.springframework.boot.jetty.metrics.JettyServerThreadPoolMetricsBinder;\nimport org.springframework.boot.jetty.metrics.JettySslHandshakeMetricsBinder;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Jetty metrics.\n *\n * @author Andy Wilkinson\n * @author Chris Bono\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnWebApplication\n@ConditionalOnClass({ JettyServerThreadPoolMetrics.class, Server.class, MeterRegistry.class })\n@ConditionalOnBean(MeterRegistry.class)\npublic final class JettyMetricsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean({ JettyServerThreadPoolMetrics.class, JettyServerThreadPoolMetricsBinder.class })\n\tJettyServerThreadPoolMetricsBinder jettyServerThreadPoolMetricsBinder(MeterRegistry meterRegistry) {\n\t\treturn new JettyServerThreadPoolMetricsBinder(meterRegistry);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean({ JettyConnectionMetrics.class, JettyConnectionMetricsBinder.class })\n\tJettyConnectionMetricsBinder jettyConnectionMetricsBinder(MeterRegistry meterRegistry) {\n\t\treturn new JettyConnectionMetricsBinder(meterRegistry);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean({ JettySslHandshakeMetrics.class, JettySslHandshakeMetricsBinder.class })\n\t@ConditionalOnBooleanProperty(\"server.ssl.enabled\")\n\tJettySslHandshakeMetricsBinder jettySslHandshakeMetricsBinder(MeterRegistry meterRegistry) {\n\t\treturn new JettySslHandshakeMetricsBinder(meterRegistry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jetty metrics.\n */\n@NullMarked\npackage org.springframework.boot.jetty.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Jetty.\n */\n@NullMarked\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/reactive/JettyReactiveWebServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.reactive;\n\nimport org.eclipse.jetty.ee11.servlet.ServletHolder;\nimport org.eclipse.jetty.ee11.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.autoconfigure.JettyServerProperties;\nimport org.springframework.boot.jetty.autoconfigure.JettyWebServerConfiguration;\nimport org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.autoconfigure.reactive.ReactiveWebServerConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.ReactiveHttpInputMessage;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Jetty-based reactive web\n * server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Server.class, ServletHolder.class, ReactiveHttpInputMessage.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(JettyServerProperties.class)\n@Import({ JettyWebServerConfiguration.class, ReactiveWebServerConfiguration.class })\npublic final class JettyReactiveWebServerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveWebServerFactory.class)\n\tJettyReactiveWebServerFactory jettyReactiveWebServerFactory(\n\t\t\tObjectProvider<JettyServerCustomizer> serverCustomizers) {\n\t\tJettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory();\n\t\tserverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());\n\t\treturn serverFactory;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JakartaWebSocketServletContainerInitializer.class)\n\tstatic class JettyWebSocketConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = \"websocketReactiveWebServerCustomizer\")\n\t\tWebSocketJettyReactiveWebServerFactoryCustomizer websocketServletWebServerCustomizer() {\n\t\t\treturn new WebSocketJettyReactiveWebServerFactoryCustomizer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/reactive/WebSocketJettyReactiveWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.reactive;\n\nimport jakarta.servlet.ServletContext;\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.ee11.websocket.jakarta.server.JakartaWebSocketServerContainer;\nimport org.eclipse.jetty.ee11.websocket.server.JettyWebSocketServerContainer;\nimport org.eclipse.jetty.ee11.websocket.servlet.WebSocketUpgradeFilter;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.websocket.core.server.WebSocketMappings;\nimport org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.core.Ordered;\n\n/**\n * WebSocket customizer for {@link JettyReactiveWebServerFactory}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class WebSocketJettyReactiveWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<JettyReactiveWebServerFactory>, Ordered {\n\n\t@Override\n\tpublic void customize(JettyReactiveWebServerFactory factory) {\n\t\tfactory.addServerCustomizers((server) -> {\n\t\t\tServletContextHandler servletContextHandler = findServletContextHandler(server);\n\t\t\tif (servletContextHandler != null) {\n\t\t\t\tServletContext servletContext = servletContextHandler.getServletContext();\n\t\t\t\tif (JettyWebSocketServerContainer.getContainer(servletContext) == null) {\n\t\t\t\t\tWebSocketServerComponents.ensureWebSocketComponents(server, servletContextHandler);\n\t\t\t\t\tJettyWebSocketServerContainer.ensureContainer(servletContext);\n\t\t\t\t}\n\t\t\t\tif (JakartaWebSocketServerContainer.getContainer(servletContext) == null) {\n\t\t\t\t\tWebSocketServerComponents.ensureWebSocketComponents(server, servletContextHandler);\n\t\t\t\t\tWebSocketUpgradeFilter.ensureFilter(servletContext);\n\t\t\t\t\tWebSocketMappings.ensureMappings(servletContextHandler);\n\t\t\t\t\tJakartaWebSocketServerContainer.ensureContainer(servletContext);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate @Nullable ServletContextHandler findServletContextHandler(Handler handler) {\n\t\tif (handler instanceof ServletContextHandler servletContextHandler) {\n\t\t\treturn servletContextHandler;\n\t\t}\n\t\tif (handler instanceof Handler.Wrapper handlerWrapper) {\n\t\t\treturn findServletContextHandler(handlerWrapper.getHandler());\n\t\t}\n\t\tif (handler instanceof Handler.Collection handlerCollection) {\n\t\t\tfor (Handler contained : handlerCollection.getHandlers()) {\n\t\t\t\tServletContextHandler servletContextHandler = findServletContextHandler(contained);\n\t\t\t\tif (servletContextHandler != null) {\n\t\t\t\t\treturn servletContextHandler;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a reactive web server using Jetty.\n */\n@NullMarked\npackage org.springframework.boot.jetty.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/servlet/JettyServletWebServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.servlet;\n\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.FilterRegistration.Dynamic;\nimport jakarta.servlet.ServletRequest;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.ee11.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;\nimport org.eclipse.jetty.ee11.websocket.servlet.WebSocketUpgradeFilter;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.util.Loader;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.autoconfigure.JettyServerProperties;\nimport org.springframework.boot.jetty.autoconfigure.JettyWebServerConfiguration;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.servlet.ServletWebServerConfiguration;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Jetty-based servlet web\n * server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ServletRequest.class, Server.class, Loader.class, WebAppContext.class })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(JettyServerProperties.class)\n@Import({ JettyWebServerConfiguration.class, ServletWebServerConfiguration.class })\npublic final class JettyServletWebServerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)\n\tJettyServletWebServerFactory jettyServletWebServerFactory(ObjectProvider<JettyServerCustomizer> serverCustomizers) {\n\t\tJettyServletWebServerFactory factory = new JettyServletWebServerFactory();\n\t\tfactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());\n\t\treturn factory;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JakartaWebSocketServletContainerInitializer.class)\n\tstatic class JettyWebSocketConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = \"websocketServletWebServerCustomizer\")\n\t\tWebSocketJettyServletWebServerFactoryCustomizer websocketServletWebServerCustomizer() {\n\t\t\treturn new WebSocketJettyServletWebServerFactoryCustomizer();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnNotWarDeployment\n\t\t@Order(Ordered.LOWEST_PRECEDENCE)\n\t\t@ConditionalOnMissingBean(name = \"websocketUpgradeFilterWebServerCustomizer\")\n\t\tWebServerFactoryCustomizer<JettyServletWebServerFactory> websocketUpgradeFilterWebServerCustomizer() {\n\t\t\treturn (factory) -> {\n\t\t\t\tfactory.addInitializers((servletContext) -> {\n\t\t\t\t\tDynamic registration = servletContext.addFilter(WebSocketUpgradeFilter.class.getName(),\n\t\t\t\t\t\t\tnew WebSocketUpgradeFilter());\n\t\t\t\t\tregistration.setAsyncSupported(true);\n\t\t\t\t\tregistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, \"/*\");\n\t\t\t\t});\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/servlet/WebSocketJettyServletWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.servlet;\n\nimport org.eclipse.jetty.ee11.webapp.AbstractConfiguration;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.ee11.websocket.jakarta.server.JakartaWebSocketServerContainer;\nimport org.eclipse.jetty.ee11.websocket.server.JettyWebSocketServerContainer;\nimport org.eclipse.jetty.ee11.websocket.servlet.WebSocketUpgradeFilter;\nimport org.eclipse.jetty.websocket.core.server.WebSocketMappings;\nimport org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;\n\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.core.Ordered;\n\n/**\n * WebSocket customizer for {@link JettyServletWebServerFactory}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class WebSocketJettyServletWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<JettyServletWebServerFactory>, Ordered {\n\n\t@Override\n\tpublic void customize(JettyServletWebServerFactory factory) {\n\t\tfactory.addConfigurations(new AbstractConfiguration(new AbstractConfiguration.Builder()) {\n\n\t\t\t@Override\n\t\t\tpublic void configure(WebAppContext context) throws Exception {\n\t\t\t\tif (JettyWebSocketServerContainer.getContainer(context.getServletContext()) == null) {\n\t\t\t\t\tWebSocketServerComponents.ensureWebSocketComponents(context.getServer(),\n\t\t\t\t\t\t\tcontext.getContext().getContextHandler());\n\t\t\t\t\tJettyWebSocketServerContainer.ensureContainer(context.getServletContext());\n\t\t\t\t}\n\t\t\t\tif (JakartaWebSocketServerContainer.getContainer(context.getServletContext()) == null) {\n\t\t\t\t\tWebSocketServerComponents.ensureWebSocketComponents(context.getServer(),\n\t\t\t\t\t\t\tcontext.getContext().getContextHandler());\n\t\t\t\t\tWebSocketUpgradeFilter.ensureFilter(context.getServletContext());\n\t\t\t\t\tWebSocketMappings.ensureMappings(context.getContext().getContextHandler());\n\t\t\t\t\tJakartaWebSocketServerContainer.ensureContainer(context.getServletContext());\n\t\t\t\t}\n\t\t\t}\n\n\t\t});\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a servlet web server using Jetty.\n */\n@NullMarked\npackage org.springframework.boot.jetty.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/metrics/AbstractJettyMetricsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.metrics;\n\nimport org.eclipse.jetty.server.Server;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\n\n/**\n * Base class for binding Jetty metrics in response to an {@link ApplicationStartedEvent}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic abstract class AbstractJettyMetricsBinder implements ApplicationListener<ApplicationStartedEvent> {\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationStartedEvent event) {\n\t\tServer server = findServer(event.getApplicationContext());\n\t\tif (server != null) {\n\t\t\tbindMetrics(server);\n\t\t}\n\t}\n\n\tprivate @Nullable Server findServer(ApplicationContext applicationContext) {\n\t\tif (applicationContext instanceof WebServerApplicationContext webServerApplicationContext) {\n\t\t\tWebServer webServer = webServerApplicationContext.getWebServer();\n\t\t\tif (webServer instanceof JettyWebServer jettyWebServer) {\n\t\t\t\treturn jettyWebServer.getServer();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprotected abstract void bindMetrics(Server server);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/metrics/JettyConnectionMetricsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.jetty.JettyConnectionMetrics;\nimport org.eclipse.jetty.server.Server;\n\n/**\n * {@link AbstractJettyMetricsBinder} for {@link JettyConnectionMetrics}.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\npublic class JettyConnectionMetricsBinder extends AbstractJettyMetricsBinder {\n\n\tprivate final MeterRegistry meterRegistry;\n\n\tprivate final Iterable<Tag> tags;\n\n\tpublic JettyConnectionMetricsBinder(MeterRegistry meterRegistry) {\n\t\tthis(meterRegistry, Collections.emptyList());\n\t}\n\n\tpublic JettyConnectionMetricsBinder(MeterRegistry meterRegistry, Iterable<Tag> tags) {\n\t\tthis.meterRegistry = meterRegistry;\n\t\tthis.tags = tags;\n\t}\n\n\t@Override\n\tprotected void bindMetrics(Server server) {\n\t\tJettyConnectionMetrics.addToAllConnectors(server, this.meterRegistry, this.tags);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/metrics/JettyServerThreadPoolMetricsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.jetty.JettyServerThreadPoolMetrics;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.util.thread.ThreadPool;\n\n/**\n * {@link AbstractJettyMetricsBinder} for {@link JettyServerThreadPoolMetrics}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class JettyServerThreadPoolMetricsBinder extends AbstractJettyMetricsBinder {\n\n\tprivate final MeterRegistry meterRegistry;\n\n\tprivate final Iterable<Tag> tags;\n\n\tpublic JettyServerThreadPoolMetricsBinder(MeterRegistry meterRegistry) {\n\t\tthis(meterRegistry, Collections.emptyList());\n\t}\n\n\tpublic JettyServerThreadPoolMetricsBinder(MeterRegistry meterRegistry, Iterable<Tag> tags) {\n\t\tthis.meterRegistry = meterRegistry;\n\t\tthis.tags = tags;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"resource\")\n\tprotected void bindMetrics(Server server) {\n\t\tThreadPool threadPool = server.getThreadPool();\n\t\tif (threadPool != null) {\n\t\t\tnew JettyServerThreadPoolMetrics(threadPool, this.tags).bindTo(this.meterRegistry);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/metrics/JettySslHandshakeMetricsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.jetty.JettySslHandshakeMetrics;\nimport org.eclipse.jetty.server.Server;\n\n/**\n * {@link AbstractJettyMetricsBinder} for {@link JettySslHandshakeMetrics}.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\npublic class JettySslHandshakeMetricsBinder extends AbstractJettyMetricsBinder {\n\n\tprivate final MeterRegistry meterRegistry;\n\n\tprivate final Iterable<Tag> tags;\n\n\tpublic JettySslHandshakeMetricsBinder(MeterRegistry meterRegistry) {\n\t\tthis(meterRegistry, Collections.emptyList());\n\t}\n\n\tpublic JettySslHandshakeMetricsBinder(MeterRegistry meterRegistry, Iterable<Tag> tags) {\n\t\tthis.meterRegistry = meterRegistry;\n\t\tthis.tags = tags;\n\t}\n\n\t@Override\n\tprotected void bindMetrics(Server server) {\n\t\tJettySslHandshakeMetrics.addToAllConnectors(server, this.meterRegistry, this.tags);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator support for Jetty metrics.\n */\n@NullMarked\npackage org.springframework.boot.jetty.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive and servlet web server implementations backed by Jetty.\n *\n * @see org.springframework.boot.jetty.servlet.JettyServletWebServerFactory\n * @see org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory\n */\n@NullMarked\npackage org.springframework.boot.jetty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/reactive/JettyReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.reactive;\n\nimport java.net.InetSocketAddress;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.ee11.servlet.ServletHolder;\nimport org.eclipse.jetty.server.NetworkConnectionLimit;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.handler.StatisticsHandler;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\nimport org.springframework.boot.jetty.ForwardHeadersCustomizer;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.jetty.JettyWebServerFactory;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.http.client.reactive.JettyResourceFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.ServletHttpHandlerAdapter;\n\n/**\n * {@link ReactiveWebServerFactory} that can be used to create {@link JettyWebServer}s.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class JettyReactiveWebServerFactory extends JettyWebServerFactory\n\t\timplements ConfigurableJettyWebServerFactory, ConfigurableReactiveWebServerFactory {\n\n\tprivate static final Log logger = LogFactory.getLog(JettyReactiveWebServerFactory.class);\n\n\tprivate @Nullable JettyResourceFactory resourceFactory;\n\n\t/**\n\t * Create a new {@link JettyServletWebServerFactory} instance.\n\t */\n\tpublic JettyReactiveWebServerFactory() {\n\t}\n\n\t/**\n\t * Create a new {@link JettyServletWebServerFactory} that listens for requests using\n\t * the specified port.\n\t * @param port the port to listen on\n\t */\n\tpublic JettyReactiveWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\t@Override\n\tpublic WebServer getWebServer(HttpHandler httpHandler) {\n\t\tServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);\n\t\tServer server = createJettyServer(servlet);\n\t\treturn new JettyWebServer(server, getPort() >= 0);\n\t}\n\n\t/**\n\t * Set the {@link JettyResourceFactory} to get the shared resources from.\n\t * @param resourceFactory the server resources\n\t */\n\tpublic void setResourceFactory(@Nullable JettyResourceFactory resourceFactory) {\n\t\tthis.resourceFactory = resourceFactory;\n\t}\n\n\tprotected @Nullable JettyResourceFactory getResourceFactory() {\n\t\treturn this.resourceFactory;\n\t}\n\n\tprotected Server createJettyServer(ServletHttpHandlerAdapter servlet) {\n\t\tint port = Math.max(getPort(), 0);\n\t\tInetSocketAddress address = new InetSocketAddress(getAddress(), port);\n\t\tServer server = new Server(getThreadPool());\n\t\tif (this.resourceFactory == null) {\n\t\t\tserver.addConnector(createConnector(address, server));\n\t\t}\n\t\telse {\n\t\t\tserver.addConnector(createConnector(address, server, this.resourceFactory.getExecutor(),\n\t\t\t\t\tthis.resourceFactory.getScheduler(), this.resourceFactory.getByteBufferPool()));\n\t\t}\n\t\tserver.setStopTimeout(0);\n\t\tServletHolder servletHolder = new ServletHolder(servlet);\n\t\tservletHolder.setAsyncSupported(true);\n\t\tServletContextHandler contextHandler = new ServletContextHandler(\"/\", false, false);\n\t\tcontextHandler.addServlet(servletHolder, \"/\");\n\t\tserver.setHandler(addHandlerWrappers(contextHandler));\n\t\tlogger.info(\"Server initialized with port: \" + port);\n\t\tif (this.getMaxConnections() > -1) {\n\t\t\tserver.addBean(new NetworkConnectionLimit(this.getMaxConnections(), server));\n\t\t}\n\t\tif (Ssl.isEnabled(getSsl())) {\n\t\t\tcustomizeSsl(server, address);\n\t\t}\n\t\tfor (JettyServerCustomizer customizer : getServerCustomizers()) {\n\t\t\tcustomizer.customize(server);\n\t\t}\n\t\tif (this.isUseForwardHeaders()) {\n\t\t\tnew ForwardHeadersCustomizer().customize(server);\n\t\t}\n\t\tif (getShutdown() == Shutdown.GRACEFUL) {\n\t\t\tStatisticsHandler statisticsHandler = new StatisticsHandler();\n\t\t\tstatisticsHandler.setHandler(server.getHandler());\n\t\t\tserver.setHandler(statisticsHandler);\n\t\t}\n\t\treturn server;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive web server implementation backed by Jetty.\n */\n@NullMarked\npackage org.springframework.boot.jetty.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JasperInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLStreamHandler;\nimport java.net.URLStreamHandlerFactory;\n\nimport jakarta.servlet.ServletContainerInitializer;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.util.component.AbstractLifeCycle;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.ClassUtils;\n\n/**\n * Jetty {@link AbstractLifeCycle} to initialize Jasper.\n *\n * @author Vladimir Tsanev\n * @author Phillip Webb\n */\nclass JasperInitializer extends AbstractLifeCycle {\n\n\tprivate static final String[] INITIALIZER_CLASSES = { \"org.eclipse.jetty.apache.jsp.JettyJasperInitializer\",\n\t\t\t\"org.apache.jasper.servlet.JasperInitializer\" };\n\n\tprivate final WebAppContext context;\n\n\tprivate final @Nullable ServletContainerInitializer initializer;\n\n\tJasperInitializer(WebAppContext context) {\n\t\tthis.context = context;\n\t\tthis.initializer = newInitializer();\n\t}\n\n\tprivate @Nullable ServletContainerInitializer newInitializer() {\n\t\tfor (String className : INITIALIZER_CLASSES) {\n\t\t\ttry {\n\t\t\t\tClass<?> initializerClass = ClassUtils.forName(className, null);\n\t\t\t\treturn (ServletContainerInitializer) initializerClass.getDeclaredConstructor().newInstance();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected void doStart() throws Exception {\n\t\tif (this.initializer == null) {\n\t\t\treturn;\n\t\t}\n\t\tif (ClassUtils.isPresent(\"org.apache.catalina.webresources.TomcatURLStreamHandlerFactory\",\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\torg.apache.catalina.webresources.TomcatURLStreamHandlerFactory.register();\n\t\t}\n\t\telse {\n\t\t\ttry {\n\t\t\t\tURL.setURLStreamHandlerFactory(new WarUrlStreamHandlerFactory());\n\t\t\t}\n\t\t\tcatch (Error ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n\t\ttry {\n\t\t\tThread.currentThread().setContextClassLoader(this.context.getClassLoader());\n\t\t\ttry {\n\t\t\t\tthis.context.getContext().setExtendedListenerTypes(true);\n\t\t\t\tthis.initializer.onStartup(null, this.context.getServletContext());\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tthis.context.getContext().setExtendedListenerTypes(false);\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\t}\n\t}\n\n\t/**\n\t * {@link URLStreamHandlerFactory} to support {@literal war} protocol.\n\t */\n\tprivate static final class WarUrlStreamHandlerFactory implements URLStreamHandlerFactory {\n\n\t\t@Override\n\t\tpublic @Nullable URLStreamHandler createURLStreamHandler(String protocol) {\n\t\t\tif (\"war\".equals(protocol)) {\n\t\t\t\treturn new WarUrlStreamHandler();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link URLStreamHandler} for {@literal war} protocol compatible with jasper's\n\t * {@link URL urls} produced by\n\t * {@link org.apache.tomcat.util.scan.JarFactory#getJarEntryURL(URL, String)}.\n\t */\n\tprivate static final class WarUrlStreamHandler extends URLStreamHandler {\n\n\t\t@Override\n\t\tprotected void parseURL(URL u, String spec, int start, int limit) {\n\t\t\tString path = \"jar:\" + spec.substring(\"war:\".length());\n\t\t\tint separator = path.indexOf(\"*/\");\n\t\t\tif (separator >= 0) {\n\t\t\t\tpath = path.substring(0, separator) + \"!/\" + path.substring(separator + 2);\n\t\t\t}\n\t\t\tsetURL(u, u.getProtocol(), \"\", -1, null, null, path, null, null);\n\t\t}\n\n\t\t@Override\n\t\tprotected URLConnection openConnection(URL u) throws IOException {\n\t\t\treturn new WarURLConnection(u);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link URLConnection} to support {@literal war} protocol.\n\t */\n\tprivate static class WarURLConnection extends URLConnection {\n\n\t\tprivate final URLConnection connection;\n\n\t\tprotected WarURLConnection(URL url) throws IOException {\n\t\t\tsuper(url);\n\t\t\tthis.connection = new URL(url.getFile()).openConnection();\n\t\t}\n\n\t\t@Override\n\t\tpublic void connect() throws IOException {\n\t\t\tif (!this.connected) {\n\t\t\t\tthis.connection.connect();\n\t\t\t\tthis.connected = true;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic InputStream getInputStream() throws IOException {\n\t\t\tconnect();\n\t\t\treturn this.connection.getInputStream();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyEmbeddedErrorHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport org.eclipse.jetty.ee11.servlet.ErrorPageErrorHandler;\nimport org.eclipse.jetty.http.HttpMethod;\n\n/**\n * Variation of Jetty's {@link ErrorPageErrorHandler} that supports all {@link HttpMethod\n * HttpMethods} rather than just {@code GET}, {@code POST} and {@code HEAD}. By default\n * Jetty <a href=\"https://bugs.eclipse.org/bugs/show_bug.cgi?id=446039\">intentionally only\n * supports a limited set of HTTP methods</a> for error pages, however, Spring Boot\n * prefers Tomcat and Jetty to all behave in the same way.\n *\n * @author Phillip Webb\n * @author Christoph Dreis\n */\nclass JettyEmbeddedErrorHandler extends ErrorPageErrorHandler {\n\n\t@Override\n\tpublic boolean errorPageForMethod(String method) {\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyEmbeddedWebAppContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport org.eclipse.jetty.ee11.servlet.ServletHandler;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.util.ClassMatcher;\n\nimport org.springframework.boot.jetty.JettyWebServer;\n\n/**\n * Jetty {@link WebAppContext} used by {@link JettyWebServer} to support deferred\n * initialization.\n *\n * @author Phillip Webb\n */\nclass JettyEmbeddedWebAppContext extends WebAppContext {\n\n\tJettyEmbeddedWebAppContext() {\n\t\tsetHiddenClassMatcher(new ClassMatcher(\"org.springframework.boot.loader.\"));\n\t}\n\n\t@Override\n\tprotected ServletHandler newServletHandler() {\n\t\treturn new JettyEmbeddedServletHandler();\n\t}\n\n\tvoid deferredInitialize() throws Exception {\n\t\tJettyEmbeddedServletHandler handler = (JettyEmbeddedServletHandler) getServletHandler();\n\t\tgetContext().call(handler::deferredInitialize, null);\n\t}\n\n\t@Override\n\tpublic String getCanonicalNameForTmpDir() {\n\t\treturn super.getCanonicalNameForTmpDir();\n\t}\n\n\tprivate static final class JettyEmbeddedServletHandler extends ServletHandler {\n\n\t\t@Override\n\t\tpublic void initialize() throws Exception {\n\t\t}\n\n\t\tvoid deferredInitialize() throws Exception {\n\t\t\tsuper.initialize();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyServletWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport java.util.List;\n\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.Server;\n\nimport org.springframework.boot.jetty.JettyWebServer;\n\n/**\n * Servlet-specific {@link JettyWebServer}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class JettyServletWebServer extends JettyWebServer {\n\n\tpublic JettyServletWebServer(Server server) {\n\t\tsuper(server);\n\t}\n\n\tpublic JettyServletWebServer(Server server, boolean autoStart) {\n\t\tsuper(server, autoStart);\n\t}\n\n\t@Override\n\tprotected void handleDeferredInitialize(Server server) throws Exception {\n\t\thandleDeferredInitialize(server.getHandlers());\n\t}\n\n\tprotected void handleDeferredInitialize(List<Handler> handlers) throws Exception {\n\t\tfor (Handler handler : handlers) {\n\t\t\thandleDeferredInitialize(handler);\n\t\t}\n\t}\n\n\tprivate void handleDeferredInitialize(Handler handler) throws Exception {\n\t\tif (handler instanceof JettyEmbeddedWebAppContext jettyEmbeddedWebAppContext) {\n\t\t\tjettyEmbeddedWebAppContext.deferredInitialize();\n\t\t}\n\t\telse if (handler instanceof Handler.Wrapper handlerWrapper) {\n\t\t\thandleDeferredInitialize(handlerWrapper.getHandler());\n\t\t}\n\t\telse if (handler instanceof Handler.Collection handlerCollection) {\n\t\t\thandleDeferredInitialize(handlerCollection.getHandlers());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/JettyServletWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport java.io.File;\nimport java.net.InetSocketAddress;\nimport java.net.URL;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.EventListener;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.UUID;\n\nimport jakarta.servlet.http.Cookie;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.eclipse.jetty.ee11.servlet.ErrorHandler;\nimport org.eclipse.jetty.ee11.servlet.ErrorPageErrorHandler;\nimport org.eclipse.jetty.ee11.servlet.ListenerHolder;\nimport org.eclipse.jetty.ee11.servlet.ServletHandler;\nimport org.eclipse.jetty.ee11.servlet.ServletHolder;\nimport org.eclipse.jetty.ee11.servlet.ServletMapping;\nimport org.eclipse.jetty.ee11.servlet.SessionHandler;\nimport org.eclipse.jetty.ee11.servlet.Source;\nimport org.eclipse.jetty.ee11.webapp.AbstractConfiguration;\nimport org.eclipse.jetty.ee11.webapp.Configuration;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.ee11.webapp.WebInfConfiguration;\nimport org.eclipse.jetty.http.CookieCompliance;\nimport org.eclipse.jetty.http.HttpCookie;\nimport org.eclipse.jetty.http.HttpField;\nimport org.eclipse.jetty.http.HttpFields;\nimport org.eclipse.jetty.http.HttpFields.Mutable;\nimport org.eclipse.jetty.http.HttpHeader;\nimport org.eclipse.jetty.http.MimeTypes;\nimport org.eclipse.jetty.http.SetCookieParser;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.HttpCookieUtils;\nimport org.eclipse.jetty.server.NetworkConnectionLimit;\nimport org.eclipse.jetty.server.Request;\nimport org.eclipse.jetty.server.Response;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.handler.StatisticsHandler;\nimport org.eclipse.jetty.session.DefaultSessionCache;\nimport org.eclipse.jetty.session.FileSessionDataStore;\nimport org.eclipse.jetty.session.SessionConfig;\nimport org.eclipse.jetty.util.Callback;\nimport org.eclipse.jetty.util.component.LifeCycle;\nimport org.eclipse.jetty.util.resource.Resource;\nimport org.eclipse.jetty.util.resource.ResourceFactory;\nimport org.eclipse.jetty.util.resource.URLResourceFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\nimport org.springframework.boot.jetty.ForwardHeadersCustomizer;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.jetty.JettyWebServerFactory;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.server.Cookie.SameSite;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ContextPath;\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;\nimport org.springframework.boot.web.server.servlet.DocumentRoot;\nimport org.springframework.boot.web.server.servlet.ServletContextInitializers;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerSettings;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ServletWebServerFactory} that can be used to create a {@link JettyWebServer}.\n * Can be initialized using Spring's {@link ServletContextInitializer}s or Jetty\n * {@link Configuration}s.\n * <p>\n * Unless explicitly configured otherwise this factory will create servers that listen for\n * HTTP requests on port 8080.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andrey Hihlovskiy\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Venil Noronha\n * @author Henri Kerola\n * @author Moritz Halbritter\n * @author Onur Kagan Ozcan\n * @since 4.0.0\n * @see #setPort(int)\n * @see #setConfigurations(Collection)\n * @see JettyWebServer\n */\npublic class JettyServletWebServerFactory extends JettyWebServerFactory\n\t\timplements ConfigurableJettyWebServerFactory, ConfigurableServletWebServerFactory, ResourceLoaderAware {\n\n\tprivate static final Log logger = LogFactory.getLog(JettyServletWebServerFactory.class);\n\n\tprivate final ServletWebServerSettings settings = new ServletWebServerSettings();\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ResourceLoader resourceLoader;\n\n\t/**\n\t * Create a new {@link JettyServletWebServerFactory} instance.\n\t */\n\tpublic JettyServletWebServerFactory() {\n\t}\n\n\t/**\n\t * Create a new {@link JettyServletWebServerFactory} that listens for requests using\n\t * the specified port.\n\t * @param port the port to listen on\n\t */\n\tpublic JettyServletWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\t/**\n\t * Create a new {@link JettyServletWebServerFactory} with the specified context path\n\t * and port.\n\t * @param contextPath the root context path\n\t * @param port the port to listen on\n\t */\n\tpublic JettyServletWebServerFactory(String contextPath, int port) {\n\t\tsuper(port);\n\t\tgetSettings().setContextPath(ContextPath.of(contextPath));\n\t}\n\n\t@Override\n\tpublic WebServer getWebServer(ServletContextInitializer... initializers) {\n\t\tJettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext();\n\t\tcontext.getContext().getServletContext().setExtendedListenerTypes(true);\n\t\tint port = Math.max(getPort(), 0);\n\t\tInetSocketAddress address = new InetSocketAddress(getAddress(), port);\n\t\tServer server = createServer(address);\n\t\tcontext.setServer(server);\n\t\tTempDirs tempDirs = new TempDirs(port);\n\t\tserver.addEventListener(new CleanTempDirsListener(tempDirs));\n\t\tconfigureWebAppContext(context, tempDirs, initializers);\n\t\tserver.setHandler(addHandlerWrappers(context));\n\t\tlogger.info(\"Server initialized with port: \" + port);\n\t\tif (this.getMaxConnections() > -1) {\n\t\t\tserver.addBean(new NetworkConnectionLimit(this.getMaxConnections(), server.getConnectors()));\n\t\t}\n\t\tif (Ssl.isEnabled(getSsl())) {\n\t\t\tcustomizeSsl(server, address);\n\t\t}\n\t\tfor (JettyServerCustomizer customizer : getServerCustomizers()) {\n\t\t\tcustomizer.customize(server);\n\t\t}\n\t\tif (this.isUseForwardHeaders()) {\n\t\t\tnew ForwardHeadersCustomizer().customize(server);\n\t\t}\n\t\tif (getShutdown() == Shutdown.GRACEFUL) {\n\t\t\tStatisticsHandler statisticsHandler = new StatisticsHandler();\n\t\t\tstatisticsHandler.setHandler(server.getHandler());\n\t\t\tserver.setHandler(statisticsHandler);\n\t\t}\n\t\treturn getJettyWebServer(server);\n\t}\n\n\tprivate Server createServer(InetSocketAddress address) {\n\t\tServer server = new Server(getThreadPool());\n\t\tserver.setConnectors(new Connector[] { createConnector(address, server) });\n\t\tserver.setStopTimeout(0);\n\t\tMimeTypes.Mutable mimeTypes = server.getMimeTypes();\n\t\tfor (MimeMappings.Mapping mapping : getSettings().getMimeMappings()) {\n\t\t\tmimeTypes.addMimeMapping(mapping.getExtension(), mapping.getMimeType());\n\t\t}\n\t\treturn server;\n\t}\n\n\t@Override\n\tprotected Handler addHandlerWrappers(Handler handler) {\n\t\thandler = super.addHandlerWrappers(handler);\n\t\tif (!CollectionUtils.isEmpty(getSettings().getCookieSameSiteSuppliers())) {\n\t\t\thandler = applyWrapper(handler, new SuppliedSameSiteCookieHandlerWrapper(getSessionCookieName(),\n\t\t\t\t\tgetSettings().getCookieSameSiteSuppliers()));\n\t\t}\n\t\treturn handler;\n\t}\n\n\tprivate String getSessionCookieName() {\n\t\tString name = getSettings().getSession().getCookie().getName();\n\t\treturn (name != null) ? name : SessionConfig.__DefaultSessionCookie;\n\t}\n\n\t/**\n\t * Configure the given Jetty {@link WebAppContext} for use.\n\t * @param context the context to configure\n\t * @param initializers the set of initializers to apply\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #configureWebAppContext(WebAppContext, TempDirs, ServletContextInitializer...)}\n\t */\n\t@Deprecated(forRemoval = true, since = \"4.1.0\")\n\tprotected final void configureWebAppContext(WebAppContext context, ServletContextInitializer... initializers) {\n\t\tconfigureWebAppContext(context, new TempDirs(getPort()), initializers);\n\t}\n\n\t/**\n\t * Configure the given Jetty {@link WebAppContext} for use.\n\t * @param context the context to configure\n\t * @param tempDirs to manage temporary directories\n\t * @param initializers the set of initializers to apply\n\t * @since 4.1.0\n\t */\n\tprotected final void configureWebAppContext(WebAppContext context, TempDirs tempDirs,\n\t\t\tServletContextInitializer... initializers) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tcontext.clearAliasChecks();\n\t\tif (this.resourceLoader != null) {\n\t\t\tcontext.setClassLoader(this.resourceLoader.getClassLoader());\n\t\t}\n\t\tString contextPath = getSettings().getContextPath().toString();\n\t\tcontext.setContextPath(StringUtils.hasLength(contextPath) ? contextPath : \"/\");\n\t\tcontext.setDisplayName(getSettings().getDisplayName());\n\t\tconfigureDocumentRoot(context, tempDirs);\n\t\tif (getSettings().isRegisterDefaultServlet()) {\n\t\t\taddDefaultServlet(context);\n\t\t}\n\t\tif (shouldRegisterJspServlet()) {\n\t\t\taddJspServlet(context);\n\t\t\tcontext.addBean(new JasperInitializer(context), true);\n\t\t}\n\t\taddLocaleMappings(context);\n\t\tServletContextInitializers initializersToUse = ServletContextInitializers.from(this.settings, initializers);\n\t\tConfiguration[] configurations = getWebAppContextConfigurations(context, initializersToUse);\n\t\tcontext.setConfigurations(configurations);\n\t\tcontext.setThrowUnavailableOnStartupException(true);\n\t\tconfigureSession(context);\n\t\tcontext.setTempDirectory(getTempDirectory(context));\n\t\tpostProcessWebAppContext(context);\n\t}\n\n\tprivate boolean shouldRegisterJspServlet() {\n\t\treturn this.settings.getJsp() != null && this.settings.getJsp().getRegistered()\n\t\t\t\t&& ClassUtils.isPresent(this.settings.getJsp().getClassName(), getClass().getClassLoader());\n\t}\n\n\tprivate void configureSession(WebAppContext context) {\n\t\tSessionHandler handler = context.getSessionHandler();\n\t\tSameSite sessionSameSite = getSettings().getSession().getCookie().getSameSite();\n\t\tif (sessionSameSite != null && sessionSameSite != SameSite.OMITTED) {\n\t\t\thandler.setSameSite(HttpCookie.SameSite.valueOf(sessionSameSite.name()));\n\t\t}\n\t\tDuration sessionTimeout = getSettings().getSession().getTimeout();\n\t\thandler.setMaxInactiveInterval(isNegative(sessionTimeout) ? -1 : (int) sessionTimeout.getSeconds());\n\t\tif (getSettings().getSession().isPersistent()) {\n\t\t\tDefaultSessionCache cache = new DefaultSessionCache(handler);\n\t\t\tFileSessionDataStore store = new FileSessionDataStore();\n\t\t\tstore.setStoreDir(getSettings().getSession().getSessionStoreDirectory().getValidDirectory(true));\n\t\t\tcache.setSessionDataStore(store);\n\t\t\thandler.setSessionCache(cache);\n\t\t}\n\t}\n\n\t@Contract(\"null -> true\")\n\tprivate boolean isNegative(@Nullable Duration sessionTimeout) {\n\t\treturn sessionTimeout == null || sessionTimeout.isNegative();\n\t}\n\n\tprivate void addLocaleMappings(WebAppContext context) {\n\t\tgetSettings().getLocaleCharsetMappings()\n\t\t\t.forEach((locale, charset) -> context.addLocaleEncoding(locale.toString(), charset.toString()));\n\t}\n\n\tprivate @Nullable File getTempDirectory(WebAppContext context) {\n\t\tString temp = System.getProperty(\"java.io.tmpdir\");\n\t\treturn (temp != null) ? new File(temp, getTempDirectoryPrefix(context) + UUID.randomUUID()) : null;\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tprivate String getTempDirectoryPrefix(WebAppContext context) {\n\t\ttry {\n\t\t\treturn ((JettyEmbeddedWebAppContext) context).getCanonicalNameForTmpDir();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context);\n\t\t}\n\t}\n\n\tprivate void configureDocumentRoot(WebAppContext handler, TempDirs tempDirs) {\n\t\tDocumentRoot documentRoot = new DocumentRoot(logger);\n\t\tdocumentRoot.setDirectory(this.settings.getDocumentRoot());\n\t\tFile root = documentRoot.getValidDirectory();\n\t\tFile docBase = (root != null) ? root : tempDirs.createTempDir(\"jetty-docbase\").toFile();\n\t\ttry {\n\t\t\tResourceFactory resourceFactory = handler.getResourceFactory();\n\t\t\tList<Resource> resources = new ArrayList<>();\n\t\t\tResource rootResource = (docBase.isDirectory()\n\t\t\t\t\t? resourceFactory.newResource(docBase.getCanonicalFile().toURI())\n\t\t\t\t\t: resourceFactory.newJarFileResource(docBase.toURI()));\n\t\t\tresources.add((root != null) ? new LoaderHidingResource(rootResource, rootResource) : rootResource);\n\t\t\tURLResourceFactory urlResourceFactory = new URLResourceFactory();\n\t\t\tfor (URL resourceJarUrl : getSettings().getStaticResourceUrls()) {\n\t\t\t\tResource resource = createResource(resourceJarUrl, resourceFactory, urlResourceFactory);\n\t\t\t\tif (resource != null) {\n\t\t\t\t\tresources.add(resource);\n\t\t\t\t}\n\t\t\t}\n\t\t\thandler.setBaseResource(ResourceFactory.combine(resources));\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate @Nullable Resource createResource(URL url, ResourceFactory resourceFactory,\n\t\t\tURLResourceFactory urlResourceFactory) throws Exception {\n\t\tif (\"file\".equals(url.getProtocol())) {\n\t\t\tFile file = new File(url.toURI());\n\t\t\tif (file.isFile()) {\n\t\t\t\treturn resourceFactory.newResource(\"jar:\" + url + \"!/META-INF/resources/\");\n\t\t\t}\n\t\t\tif (file.isDirectory()) {\n\t\t\t\treturn resourceFactory.newResource(url).resolve(\"META-INF/resources/\");\n\t\t\t}\n\t\t}\n\t\treturn urlResourceFactory.newResource(url + \"META-INF/resources/\");\n\t}\n\n\t/**\n\t * Add Jetty's {@code DefaultServlet} to the given {@link WebAppContext}.\n\t * @param context the jetty {@link WebAppContext}\n\t */\n\tprotected final void addDefaultServlet(WebAppContext context) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tServletHolder holder = new ServletHolder();\n\t\tholder.setName(\"default\");\n\t\tholder.setClassName(\"org.eclipse.jetty.ee11.servlet.DefaultServlet\");\n\t\tholder.setInitParameter(\"dirAllowed\", \"false\");\n\t\tholder.setInitOrder(1);\n\t\tcontext.getServletHandler().addServletWithMapping(holder, \"/\");\n\t\tServletMapping servletMapping = context.getServletHandler().getServletMapping(\"/\");\n\t\tservletMapping.setFromDefaultDescriptor(true);\n\t}\n\n\t/**\n\t * Add Jetty's {@code JspServlet} to the given {@link WebAppContext}.\n\t * @param context the jetty {@link WebAppContext}\n\t */\n\tprotected final void addJspServlet(WebAppContext context) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tServletHolder holder = new ServletHolder();\n\t\tholder.setName(\"jsp\");\n\t\tholder.setClassName(this.settings.getJsp().getClassName());\n\t\tholder.setInitParameter(\"fork\", \"false\");\n\t\tholder.setInitParameters(this.settings.getJsp().getInitParameters());\n\t\tholder.setInitOrder(3);\n\t\tcontext.getServletHandler().addServlet(holder);\n\t\tServletMapping mapping = new ServletMapping();\n\t\tmapping.setServletName(\"jsp\");\n\t\tmapping.setPathSpecs(new String[] { \"*.jsp\", \"*.jspx\" });\n\t\tcontext.getServletHandler().addServletMapping(mapping);\n\t}\n\n\t/**\n\t * Return the Jetty {@link Configuration}s that should be applied to the server.\n\t * @param webAppContext the Jetty {@link WebAppContext}\n\t * @param initializers the {@link ServletContextInitializer}s to apply\n\t * @return configurations to apply\n\t */\n\tprotected Configuration[] getWebAppContextConfigurations(WebAppContext webAppContext,\n\t\t\tServletContextInitializers initializers) {\n\t\tList<Configuration> configurations = new ArrayList<>();\n\t\tconfigurations.add(getServletContextInitializerConfiguration(webAppContext, initializers));\n\t\tconfigurations.add(getErrorPageConfiguration());\n\t\tconfigurations.add(getMimeTypeConfiguration());\n\t\tconfigurations.add(new WebListenersConfiguration(getSettings().getWebListenerClassNames()));\n\t\tconfigurations.addAll(getConfigurations());\n\t\treturn configurations.toArray(new Configuration[0]);\n\t}\n\n\t/**\n\t * Create a configuration object that adds error handlers.\n\t * @return a configuration object for adding error pages\n\t */\n\tprivate Configuration getErrorPageConfiguration() {\n\t\treturn new AbstractConfiguration(new AbstractConfiguration.Builder()) {\n\n\t\t\t@Override\n\t\t\tpublic void configure(WebAppContext context) throws Exception {\n\t\t\t\tJettyEmbeddedErrorHandler errorHandler = new JettyEmbeddedErrorHandler();\n\t\t\t\tcontext.setErrorHandler(errorHandler);\n\t\t\t\taddJettyErrorPages(errorHandler, getErrorPages());\n\t\t\t}\n\n\t\t};\n\t}\n\n\t/**\n\t * Create a configuration object that adds mime type mappings.\n\t * @return a configuration object for adding mime type mappings\n\t */\n\tprivate Configuration getMimeTypeConfiguration() {\n\t\treturn new AbstractConfiguration(new AbstractConfiguration.Builder()) {\n\n\t\t\t@Override\n\t\t\tpublic void configure(WebAppContext context) throws Exception {\n\t\t\t\tMimeTypes.Mutable mimeTypes = context.getMimeTypes();\n\t\t\t\tmimeTypes.clear();\n\t\t\t\tfor (MimeMappings.Mapping mapping : getSettings().getMimeMappings()) {\n\t\t\t\t\tmimeTypes.addMimeMapping(mapping.getExtension(), mapping.getMimeType());\n\t\t\t\t}\n\t\t\t}\n\n\t\t};\n\t}\n\n\t/**\n\t * Return a Jetty {@link Configuration} that will invoke the specified\n\t * {@link ServletContextInitializer}s. By default this method will return a\n\t * {@link ServletContextInitializerConfiguration}.\n\t * @param webAppContext the Jetty {@link WebAppContext}\n\t * @param initializers the {@link ServletContextInitializer}s to apply\n\t * @return the {@link Configuration} instance\n\t */\n\tprotected Configuration getServletContextInitializerConfiguration(WebAppContext webAppContext,\n\t\t\tServletContextInitializers initializers) {\n\t\treturn new ServletContextInitializerConfiguration(initializers);\n\t}\n\n\t/**\n\t * Post process the Jetty {@link WebAppContext} before it's used with the Jetty\n\t * Server. Subclasses can override this method to apply additional processing to the\n\t * {@link WebAppContext}.\n\t * @param webAppContext the Jetty {@link WebAppContext}\n\t */\n\tprotected void postProcessWebAppContext(WebAppContext webAppContext) {\n\t}\n\n\t/**\n\t * Factory method called to create the {@link JettyWebServer}. Subclasses can override\n\t * this method to return a different {@link JettyWebServer} or apply additional\n\t * processing to the Jetty server.\n\t * @param server the Jetty server.\n\t * @return a new {@link JettyWebServer} instance\n\t */\n\tprotected JettyWebServer getJettyWebServer(Server server) {\n\t\treturn new JettyServletWebServer(server, getPort() >= 0);\n\t}\n\n\t@Override\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\tprivate void addJettyErrorPages(ErrorHandler errorHandler, Collection<ErrorPage> errorPages) {\n\t\tif (errorHandler instanceof ErrorPageErrorHandler handler) {\n\t\t\tfor (ErrorPage errorPage : errorPages) {\n\t\t\t\tif (errorPage.isGlobal()) {\n\t\t\t\t\thandler.addErrorPage(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE, errorPage.getPath());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (errorPage.getExceptionName() != null) {\n\t\t\t\t\t\thandler.addErrorPage(errorPage.getExceptionName(), errorPage.getPath());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\thandler.addErrorPage(errorPage.getStatusCode(), errorPage.getPath());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic ServletWebServerSettings getSettings() {\n\t\treturn this.settings;\n\t}\n\n\t/**\n\t * {@link AbstractConfiguration} to apply {@code @WebListener} classes.\n\t */\n\tprivate static class WebListenersConfiguration extends AbstractConfiguration {\n\n\t\tprivate final Set<String> classNames;\n\n\t\tWebListenersConfiguration(Set<String> webListenerClassNames) {\n\t\t\tsuper(new AbstractConfiguration.Builder());\n\t\t\tthis.classNames = webListenerClassNames;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configure(WebAppContext context) throws Exception {\n\t\t\tServletHandler servletHandler = context.getServletHandler();\n\t\t\tfor (String className : this.classNames) {\n\t\t\t\tconfigure(context, servletHandler, className);\n\t\t\t}\n\t\t}\n\n\t\tprivate void configure(WebAppContext context, ServletHandler servletHandler, String className)\n\t\t\t\tthrows ClassNotFoundException {\n\t\t\tListenerHolder holder = servletHandler.newListenerHolder(new Source(Source.Origin.ANNOTATION, className));\n\t\t\tholder.setHeldClass(loadClass(context, className));\n\t\t\tservletHandler.addListener(holder);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate Class<? extends EventListener> loadClass(WebAppContext context, String className)\n\t\t\t\tthrows ClassNotFoundException {\n\t\t\tClassLoader classLoader = context.getClassLoader();\n\t\t\tclassLoader = (classLoader != null) ? classLoader : getClass().getClassLoader();\n\t\t\treturn (Class<? extends EventListener>) classLoader.loadClass(className);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Handler.Wrapper} to apply {@link CookieSameSiteSupplier supplied}\n\t * {@link SameSite} cookie values.\n\t */\n\tprivate static class SuppliedSameSiteCookieHandlerWrapper extends Handler.Wrapper {\n\n\t\tprivate static final SetCookieParser setCookieParser = SetCookieParser.newInstance();\n\n\t\tprivate final String sessionCookieName;\n\n\t\tprivate final List<? extends CookieSameSiteSupplier> suppliers;\n\n\t\tSuppliedSameSiteCookieHandlerWrapper(String sessionCookieName,\n\t\t\t\tList<? extends CookieSameSiteSupplier> suppliers) {\n\t\t\tthis.sessionCookieName = sessionCookieName;\n\t\t\tthis.suppliers = suppliers;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean handle(Request request, Response response, Callback callback) throws Exception {\n\t\t\tSuppliedSameSiteCookieResponse wrappedResponse = new SuppliedSameSiteCookieResponse(request, response);\n\t\t\treturn super.handle(request, wrappedResponse, callback);\n\t\t}\n\n\t\tprivate class SuppliedSameSiteCookieResponse extends Response.Wrapper {\n\n\t\t\tprivate final HttpFields.Mutable wrappedHeaders;\n\n\t\t\tSuppliedSameSiteCookieResponse(Request request, Response wrapped) {\n\t\t\t\tsuper(request, wrapped);\n\t\t\t\tthis.wrappedHeaders = new SuppliedSameSiteCookieHeaders(\n\t\t\t\t\t\trequest.getConnectionMetaData().getHttpConfiguration().getResponseCookieCompliance(),\n\t\t\t\t\t\twrapped.getHeaders());\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Mutable getHeaders() {\n\t\t\t\treturn this.wrappedHeaders;\n\t\t\t}\n\n\t\t}\n\n\t\tprivate class SuppliedSameSiteCookieHeaders extends HttpFields.Mutable.Wrapper {\n\n\t\t\tprivate final CookieCompliance compliance;\n\n\t\t\tSuppliedSameSiteCookieHeaders(CookieCompliance compliance, HttpFields.Mutable fields) {\n\t\t\t\tsuper(fields);\n\t\t\t\tthis.compliance = compliance;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic HttpField onAddField(HttpField field) {\n\t\t\t\treturn (field.getHeader() != HttpHeader.SET_COOKIE) ? field : onAddSetCookieField(field);\n\t\t\t}\n\n\t\t\tprivate HttpField onAddSetCookieField(HttpField field) {\n\t\t\t\tHttpCookie cookie = setCookieParser.parse(field.getValue());\n\t\t\t\tif (cookie == null || isSessionCookie(cookie)) {\n\t\t\t\t\treturn field;\n\t\t\t\t}\n\t\t\t\tSameSite sameSite = getSameSite(cookie);\n\t\t\t\tif (sameSite == null) {\n\t\t\t\t\treturn field;\n\t\t\t\t}\n\t\t\t\tHttpCookie updatedCookie = buildCookieWithUpdatedSameSite(cookie, sameSite);\n\t\t\t\treturn new HttpCookieUtils.SetCookieHttpField(updatedCookie, this.compliance);\n\t\t\t}\n\n\t\t\tprivate boolean isSessionCookie(HttpCookie cookie) {\n\t\t\t\treturn SuppliedSameSiteCookieHandlerWrapper.this.sessionCookieName.equals(cookie.getName());\n\t\t\t}\n\n\t\t\tprivate HttpCookie buildCookieWithUpdatedSameSite(HttpCookie cookie, SameSite sameSite) {\n\t\t\t\treturn HttpCookie.build(cookie)\n\t\t\t\t\t.sameSite(org.eclipse.jetty.http.HttpCookie.SameSite.from(sameSite.name()))\n\t\t\t\t\t.build();\n\t\t\t}\n\n\t\t\tprivate @Nullable SameSite getSameSite(HttpCookie cookie) {\n\t\t\t\treturn getSameSite(asServletCookie(cookie));\n\t\t\t}\n\n\t\t\tprivate @Nullable SameSite getSameSite(Cookie cookie) {\n\t\t\t\treturn SuppliedSameSiteCookieHandlerWrapper.this.suppliers.stream()\n\t\t\t\t\t.map((supplier) -> supplier.getSameSite(cookie))\n\t\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.orElse(null);\n\t\t\t}\n\n\t\t\tprivate Cookie asServletCookie(HttpCookie cookie) {\n\t\t\t\tCookie servletCookie = new Cookie(cookie.getName(), cookie.getValue());\n\t\t\t\tcookie.getAttributes().forEach(servletCookie::setAttribute);\n\t\t\t\treturn servletCookie;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tprivate static class CleanTempDirsListener implements LifeCycle.Listener {\n\n\t\tprivate final TempDirs tempDirs;\n\n\t\tCleanTempDirsListener(TempDirs tempDirs) {\n\t\t\tthis.tempDirs = tempDirs;\n\t\t}\n\n\t\t@Override\n\t\tpublic void lifeCycleStopped(LifeCycle event) {\n\t\t\tthis.tempDirs.cleanup();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/LoaderHidingResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URI;\nimport java.nio.channels.ReadableByteChannel;\nimport java.nio.file.Path;\nimport java.time.Instant;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Spliterator;\nimport java.util.function.Consumer;\n\nimport org.eclipse.jetty.util.resource.CombinedResource;\nimport org.eclipse.jetty.util.resource.Resource;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A custom {@link Resource} that hides Spring Boot's loader classes, preventing them from\n * being served over HTTP.\n *\n * @author Andy Wilkinson\n */\nfinal class LoaderHidingResource extends Resource {\n\n\tprivate static final String LOADER_RESOURCE_PATH_PREFIX = \"/org/springframework/boot/\";\n\n\tprivate final Path loaderBasePath;\n\n\tprivate final Resource base;\n\n\tprivate final Resource delegate;\n\n\tLoaderHidingResource(Resource base, Resource delegate) {\n\t\tthis.base = base;\n\t\tthis.delegate = delegate;\n\t\tthis.loaderBasePath = base.getPath().getFileSystem().getPath(\"/\", \"org\", \"springframework\", \"boot\");\n\t}\n\n\t@Override\n\tpublic void forEach(Consumer<? super Resource> action) {\n\t\tthis.delegate.forEach(action);\n\t}\n\n\t@Override\n\tpublic Path getPath() {\n\t\treturn this.delegate.getPath();\n\t}\n\n\t@Override\n\tpublic boolean isContainedIn(Resource r) {\n\t\treturn this.delegate.isContainedIn(r);\n\t}\n\n\t@Override\n\tpublic Iterator<Resource> iterator() {\n\t\tif (this.delegate instanceof CombinedResource) {\n\t\t\treturn list().iterator();\n\t\t}\n\t\treturn List.<Resource>of(this).iterator();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\treturn this.delegate.equals(obj);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.delegate.hashCode();\n\t}\n\n\t@Override\n\tpublic boolean exists() {\n\t\treturn this.delegate.exists();\n\t}\n\n\t@Override\n\tpublic Spliterator<Resource> spliterator() {\n\t\treturn this.delegate.spliterator();\n\t}\n\n\t@Override\n\tpublic boolean isDirectory() {\n\t\treturn this.delegate.isDirectory();\n\t}\n\n\t@Override\n\tpublic boolean isReadable() {\n\t\treturn this.delegate.isReadable();\n\t}\n\n\t@Override\n\tpublic Instant lastModified() {\n\t\treturn this.delegate.lastModified();\n\t}\n\n\t@Override\n\tpublic long length() {\n\t\treturn this.delegate.length();\n\t}\n\n\t@Override\n\tpublic URI getURI() {\n\t\treturn this.delegate.getURI();\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn this.delegate.getName();\n\t}\n\n\t@Override\n\tpublic String getFileName() {\n\t\treturn this.delegate.getFileName();\n\t}\n\n\t@Override\n\tpublic InputStream newInputStream() throws IOException {\n\t\treturn this.delegate.newInputStream();\n\t}\n\n\t@Override\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tpublic ReadableByteChannel newReadableByteChannel() throws IOException {\n\t\treturn this.delegate.newReadableByteChannel();\n\t}\n\n\t@Override\n\tpublic List<Resource> list() {\n\t\treturn asLoaderHidingResources(this.delegate.list());\n\t}\n\n\tprivate boolean nonLoaderResource(Resource resource) {\n\t\treturn !resource.getPath().startsWith(this.loaderBasePath);\n\t}\n\n\tprivate List<Resource> asLoaderHidingResources(Collection<Resource> resources) {\n\t\treturn resources.stream().filter(this::nonLoaderResource).map(this::asLoaderHidingResource).toList();\n\t}\n\n\tprivate Resource asLoaderHidingResource(Resource resource) {\n\t\treturn (resource instanceof LoaderHidingResource) ? resource : new LoaderHidingResource(this.base, resource);\n\t}\n\n\t@Override\n\tpublic @Nullable Resource resolve(String subUriPath) {\n\t\tif (subUriPath.startsWith(LOADER_RESOURCE_PATH_PREFIX)) {\n\t\t\treturn null;\n\t\t}\n\t\tResource resolved = this.delegate.resolve(subUriPath);\n\t\treturn (resolved != null) ? new LoaderHidingResource(this.base, resolved) : null;\n\t}\n\n\t@Override\n\tpublic boolean isAlias() {\n\t\treturn this.delegate.isAlias();\n\t}\n\n\t@Override\n\tpublic URI getRealURI() {\n\t\treturn this.delegate.getRealURI();\n\t}\n\n\t@Override\n\tpublic void copyTo(Path destination) throws IOException {\n\t\tthis.delegate.copyTo(destination);\n\t}\n\n\t@Override\n\tpublic Collection<Resource> getAllResources() {\n\t\treturn asLoaderHidingResources(this.delegate.getAllResources());\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.delegate.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/ServletContextInitializerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport jakarta.servlet.ServletException;\nimport org.eclipse.jetty.ee11.webapp.AbstractConfiguration;\nimport org.eclipse.jetty.ee11.webapp.Configuration;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\n\nimport org.springframework.boot.web.server.servlet.ServletContextInitializers;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.util.Assert;\n\n/**\n * Jetty {@link Configuration} that calls {@link ServletContextInitializer}s.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ServletContextInitializerConfiguration extends AbstractConfiguration {\n\n\tprivate final ServletContextInitializers initializers;\n\n\t/**\n\t * Create a new {@link ServletContextInitializerConfiguration}.\n\t * @param initializers the initializers that should be invoked\n\t */\n\tServletContextInitializerConfiguration(ServletContextInitializers initializers) {\n\t\tsuper(new AbstractConfiguration.Builder());\n\t\tAssert.notNull(initializers, \"'initializers' must not be null\");\n\t\tthis.initializers = initializers;\n\t}\n\n\t@Override\n\tpublic void configure(WebAppContext context) throws Exception {\n\t\tClassLoader classLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread().setContextClassLoader(context.getClassLoader());\n\t\ttry {\n\t\t\tcallInitializers(context);\n\t\t}\n\t\tfinally {\n\t\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t\t}\n\t}\n\n\tprivate void callInitializers(WebAppContext context) throws ServletException {\n\t\ttry {\n\t\t\tcontext.getContext().setExtendedListenerTypes(true);\n\t\t\tfor (ServletContextInitializer initializer : this.initializers) {\n\t\t\t\tinitializer.onStartup(context.getServletContext());\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tcontext.getContext().setExtendedListenerTypes(false);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/java/org/springframework/boot/jetty/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Servlet web server implementation backed by Jetty.\n */\n@NullMarked\npackage org.springframework.boot.jetty.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"server.jetty.accesslog.date-format\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.custom-format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.accesslog.extended-format\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.accesslog.locale\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.custom-format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.accesslog.log-cookies\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.custom-format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.accesslog.log-latency\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.custom-format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.accesslog.log-server\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.custom-format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.accesslog.time-zone\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.accesslog.custom-format\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"server.jetty.max-http-post-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"deprecation\": {\n        \"replacement\": \"server.jetty.max-http-form-post-size\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.jetty.autoconfigure.actuate.web.server.JettyReactiveManagementChildContextConfiguration\norg.springframework.boot.jetty.autoconfigure.actuate.web.server.JettyServletManagementChildContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jetty.autoconfigure.actuate.web.server.JettyReactiveManagementContextAutoConfiguration\norg.springframework.boot.jetty.autoconfigure.actuate.web.server.JettyServletManagementContextAutoConfiguration\norg.springframework.boot.jetty.autoconfigure.metrics.JettyMetricsAutoConfiguration\norg.springframework.boot.jetty.autoconfigure.reactive.JettyReactiveWebServerAutoConfiguration\norg.springframework.boot.jetty.autoconfigure.servlet.JettyServletWebServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jetty/src/main/resources/META-INF/spring/org.springframework.boot.web.server.test.AutoConfigureWebServer.imports",
    "content": "org.springframework.boot.jetty.autoconfigure.reactive.JettyReactiveWebServerAutoConfiguration\norg.springframework.boot.jetty.autoconfigure.servlet.JettyServletWebServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/JettyAccess.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\n/**\n * Helper class to provide public access to package-private methods for testing purposes.\n *\n * @author Andy Wilkinson\n */\npublic final class JettyAccess {\n\n\tprivate JettyAccess() {\n\n\t}\n\n\tpublic static String getStartedLogMessage(JettyWebServer jettyWebServer) {\n\t\treturn jettyWebServer.getStartedLogMessage();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/SslServerCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty;\n\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;\nimport org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;\nimport org.eclipse.jetty.server.ConnectionFactory;\nimport org.eclipse.jetty.server.HttpConnectionFactory;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.SslConnectionFactory;\nimport org.eclipse.jetty.util.ssl.SslContextFactory;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11Security;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11SecurityProvider;\nimport org.springframework.boot.web.server.Http2;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServerSslBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link SslServerCustomizer}.\n *\n * @author Andy Wilkinson\n * @author Cyril Dangerville\n * @author Scott Frederick\n */\n@MockPkcs11Security\nclass SslServerCustomizerTests {\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHttp2IsNotEnabledServerConnectorHasSslAndHttpConnectionFactories() {\n\t\tServer server = createCustomizedServer();\n\t\tassertThat(server.getConnectors()).hasSize(1);\n\t\tList<ConnectionFactory> factories = new ArrayList<>(server.getConnectors()[0].getConnectionFactories());\n\t\tassertThat(factories).extracting((factory) -> (Class) factory.getClass())\n\t\t\t.containsExactly(SslConnectionFactory.class, HttpConnectionFactory.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\t@WithPackageResources(\"test.jks\")\n\t@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\t\tdisabledReason = \"conscrypt doesn't support Linux/macOS aarch64, see https://github.com/google/conscrypt/issues/1051\")\n\tvoid whenHttp2IsEnabledServerConnectorsHasSslAlpnH2AndHttpConnectionFactories() {\n\t\tHttp2 http2 = new Http2();\n\t\thttp2.setEnabled(true);\n\t\tServer server = createCustomizedServer(http2);\n\t\tassertThat(server.getConnectors()).hasSize(1);\n\t\tList<ConnectionFactory> factories = new ArrayList<>(server.getConnectors()[0].getConnectionFactories());\n\t\tassertThat(factories).extracting((factory) -> (Class) factory.getClass())\n\t\t\t.containsExactly(SslConnectionFactory.class, ALPNServerConnectionFactory.class,\n\t\t\t\t\tHTTP2ServerConnectionFactory.class, HttpConnectionFactory.class);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\t@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\t\tdisabledReason = \"conscrypt doesn't support Linux/macOS aarch64, see https://github.com/google/conscrypt/issues/1051\")\n\tvoid alpnConnectionFactoryHasNullDefaultProtocolToAllowNegotiationToHttp11() {\n\t\tHttp2 http2 = new Http2();\n\t\thttp2.setEnabled(true);\n\t\tServer server = createCustomizedServer(http2);\n\t\tassertThat(server.getConnectors()).hasSize(1);\n\t\tList<ConnectionFactory> factories = new ArrayList<>(server.getConnectors()[0].getConnectionFactories());\n\t\tassertThat(((ALPNServerConnectionFactory) factories.get(1)).getDefaultProtocol()).isNull();\n\t}\n\n\t@Test\n\tvoid configureSslWhenSslIsEnabledWithNoKeyStoreAndNotPkcs11ThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tSslServerCustomizer customizer = new SslServerCustomizer(null, new InetSocketAddress(0), null,\n\t\t\t\t\tWebServerSslBundle.get(ssl));\n\t\t\tcustomizer.configureSsl(new SslContextFactory.Server(), ssl.getClientAuth());\n\t\t}).withMessageContaining(\"SSL is enabled but no trust material is configured\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid configureSslWhenSslIsEnabledWithPkcs11AndKeyStoreThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStoreType(\"PKCS11\");\n\t\tssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tSslServerCustomizer customizer = new SslServerCustomizer(null, new InetSocketAddress(0), null,\n\t\t\t\t\tWebServerSslBundle.get(ssl));\n\t\t\tcustomizer.configureSsl(new SslContextFactory.Server(), ssl.getClientAuth());\n\t\t}).withMessageContaining(\"must be empty or null for PKCS11 hardware key stores\");\n\t}\n\n\t@Test\n\tvoid customizeWhenSslIsEnabledWithPkcs11AndKeyStoreProvider() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStoreType(\"PKCS11\");\n\t\tssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setKeyStorePassword(\"1234\");\n\t\tassertThatNoException().isThrownBy(() -> {\n\t\t\tSslServerCustomizer customizer = new SslServerCustomizer(null, new InetSocketAddress(0), null,\n\t\t\t\t\tWebServerSslBundle.get(ssl));\n\t\t\tcustomizer.configureSsl(new SslContextFactory.Server(), ssl.getClientAuth());\n\t\t});\n\t}\n\n\tprivate Server createCustomizedServer() {\n\t\treturn createCustomizedServer(new Http2());\n\t}\n\n\tprivate Server createCustomizedServer(Http2 http2) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\treturn createCustomizedServer(ssl, http2);\n\t}\n\n\tprivate Server createCustomizedServer(Ssl ssl, Http2 http2) {\n\t\tServer server = new Server();\n\t\tnew SslServerCustomizer(http2, new InetSocketAddress(0), ssl.getClientAuth(), WebServerSslBundle.get(ssl))\n\t\t\t.customize(server);\n\t\treturn server;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/AutoConfigureWebServerJettyReactiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.jetty.autoconfigure.AutoConfigureWebServerJettyReactiveTests.ReactiveConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureWebServer @AutoConfigureWebServer} with Jetty.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(classes = ReactiveConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.main.web-application-type=reactive\")\n@AutoConfigureWebServer\nclass AutoConfigureWebServerJettyReactiveTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid startsTestServer() {\n\t\tRestTestClient restClient = RestTestClient.bindToServer().baseUrl(\"http://localhost:\" + this.port).build();\n\t\tassertThat(RestTestClientResponse.from(restClient.get().exchange())).bodyText().isEqualTo(\"hello\");\n\t}\n\n\t@Configuration\n\tstatic class ReactiveConfiguration {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn (request, response) -> {\n\t\t\t\tresponse.setStatusCode(HttpStatus.OK);\n\t\t\t\tDataBuffer dataBuffer = new DefaultDataBufferFactory().wrap(\"hello\".getBytes(StandardCharsets.UTF_8));\n\t\t\t\treturn response.writeWith(Mono.just(dataBuffer));\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/AutoConfigureWebServerJettyServletTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jetty.autoconfigure.AutoConfigureWebServerJettyServletTests.ServletConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureWebServer @AutoConfigureWebServer} with Jetty.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(classes = ServletConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebServer\nclass AutoConfigureWebServerJettyServletTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid startsTestServer() {\n\t\tRestTestClient restClient = RestTestClient.bindToServer().baseUrl(\"http://localhost:\" + this.port).build();\n\t\tassertThat(RestTestClientResponse.from(restClient.get().exchange())).bodyText().isEqualTo(\"hello\");\n\t}\n\n\t@Configuration\n\tstatic class ServletConfiguration {\n\n\t\t@Bean\n\t\tServlet servlet() {\n\t\t\treturn new GenericServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void service(ServletRequest request, ServletResponse response)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t\tresponse.getWriter().append(\"hello\").flush();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/JettyServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.util.thread.QueuedThreadPool;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JettyServerProperties}.\n *\n * @author Andy Wilkinson\n */\nclass JettyServerPropertiesTests {\n\n\tprivate final JettyServerProperties properties = new JettyServerProperties();\n\n\t@Test\n\tvoid testCustomizeJettyAcceptors() {\n\t\tbind(\"server.jetty.threads.acceptors\", \"10\");\n\t\tassertThat(this.properties.getThreads().getAcceptors()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid testCustomizeJettySelectors() {\n\t\tbind(\"server.jetty.threads.selectors\", \"10\");\n\t\tassertThat(this.properties.getThreads().getSelectors()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid testCustomizeJettyMaxThreads() {\n\t\tbind(\"server.jetty.threads.max\", \"10\");\n\t\tassertThat(this.properties.getThreads().getMax()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid testCustomizeJettyMinThreads() {\n\t\tbind(\"server.jetty.threads.min\", \"10\");\n\t\tassertThat(this.properties.getThreads().getMin()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid testCustomizeJettyIdleTimeout() {\n\t\tbind(\"server.jetty.threads.idle-timeout\", \"10s\");\n\t\tassertThat(this.properties.getThreads().getIdleTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t}\n\n\t@Test\n\tvoid testCustomizeJettyMaxQueueCapacity() {\n\t\tbind(\"server.jetty.threads.max-queue-capacity\", \"5150\");\n\t\tassertThat(this.properties.getThreads().getMaxQueueCapacity()).isEqualTo(5150);\n\t}\n\n\t@Test\n\tvoid testCustomizeJettyAccessLog() {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"server.jetty.accesslog.enabled\", \"true\");\n\t\tmap.put(\"server.jetty.accesslog.filename\", \"foo.txt\");\n\t\tmap.put(\"server.jetty.accesslog.file-date-format\", \"yyyymmdd\");\n\t\tmap.put(\"server.jetty.accesslog.retention-period\", \"4\");\n\t\tmap.put(\"server.jetty.accesslog.append\", \"true\");\n\t\tmap.put(\"server.jetty.accesslog.custom-format\", \"{client}a - %u %t \\\"%r\\\" %s %O\");\n\t\tmap.put(\"server.jetty.accesslog.ignore-paths\", \"/a/path,/b/path\");\n\t\tbind(map);\n\t\tassertThat(this.properties.getAccesslog().isEnabled()).isTrue();\n\t\tassertThat(this.properties.getAccesslog().getFilename()).isEqualTo(\"foo.txt\");\n\t\tassertThat(this.properties.getAccesslog().getFileDateFormat()).isEqualTo(\"yyyymmdd\");\n\t\tassertThat(this.properties.getAccesslog().getRetentionPeriod()).isEqualTo(4);\n\t\tassertThat(this.properties.getAccesslog().isAppend()).isTrue();\n\t\tassertThat(this.properties.getAccesslog().getCustomFormat()).isEqualTo(\"{client}a - %u %t \\\"%r\\\" %s %O\");\n\t\tassertThat(this.properties.getAccesslog().getIgnorePaths()).containsExactly(\"/a/path\", \"/b/path\");\n\t}\n\n\t@Test\n\tvoid jettyThreadPoolPropertyDefaultsShouldMatchServerDefault() {\n\t\tJettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0);\n\t\tJettyWebServer jetty = (JettyWebServer) jettyFactory.getWebServer();\n\t\tServer server = jetty.getServer();\n\t\tQueuedThreadPool threadPool = (QueuedThreadPool) server.getThreadPool();\n\t\tint idleTimeout = threadPool.getIdleTimeout();\n\t\tint maxThreads = threadPool.getMaxThreads();\n\t\tint minThreads = threadPool.getMinThreads();\n\t\tassertThat(this.properties.getThreads().getIdleTimeout().toMillis()).isEqualTo(idleTimeout);\n\t\tassertThat(this.properties.getThreads().getMax()).isEqualTo(maxThreads);\n\t\tassertThat(this.properties.getThreads().getMin()).isEqualTo(minThreads);\n\t}\n\n\t@Test\n\tvoid jettyMaxHttpFormPostSizeMatchesDefault() {\n\t\tJettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0);\n\t\tJettyWebServer jetty = (JettyWebServer) jettyFactory.getWebServer();\n\t\tServer server = jetty.getServer();\n\t\tassertThat(this.properties.getMaxHttpFormPostSize().toBytes())\n\t\t\t.isEqualTo(((ServletContextHandler) server.getHandler()).getMaxFormContentSize());\n\t}\n\n\t@Test\n\tvoid jettyMaxFormKeysMatchesDefault() {\n\t\tJettyServletWebServerFactory jettyFactory = new JettyServletWebServerFactory(0);\n\t\tJettyWebServer jetty = (JettyWebServer) jettyFactory.getWebServer();\n\t\tServer server = jetty.getServer();\n\t\tassertThat(this.properties.getMaxFormKeys())\n\t\t\t.isEqualTo(((ServletContextHandler) server.getHandler()).getMaxFormKeys());\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"server.jetty\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/JettyVirtualThreadsWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport org.eclipse.jetty.util.thread.VirtualThreadPool;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JettyVirtualThreadsWebServerFactoryCustomizer}.\n *\n * @author Moritz Halbritter\n */\nclass JettyVirtualThreadsWebServerFactoryCustomizerTests {\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldConfigureVirtualThreads() {\n\t\tJettyServerProperties serverProperties = new JettyServerProperties();\n\t\tserverProperties.getThreads().setMax(100);\n\t\tJettyVirtualThreadsWebServerFactoryCustomizer customizer = new JettyVirtualThreadsWebServerFactoryCustomizer(\n\t\t\t\tserverProperties);\n\t\tConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);\n\t\tcustomizer.customize(factory);\n\t\tthen(factory).should().setThreadPool(assertArg((threadPool) -> {\n\t\t\tassertThat(threadPool).isInstanceOf(VirtualThreadPool.class);\n\t\t\tVirtualThreadPool virtualThreadPool = (VirtualThreadPool) threadPool;\n\t\t\tassertThat(virtualThreadPool.getName()).isEqualTo(\"jetty-\");\n\t\t\tassertThat(virtualThreadPool.getMaxConcurrentTasks()).isEqualTo(100);\n\t\t}));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/JettyWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.SynchronousQueue;\nimport java.util.function.Function;\n\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.server.AbstractConnector;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.CustomRequestLog;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.HttpConfiguration.ConnectionFactory;\nimport org.eclipse.jetty.server.RequestLog;\nimport org.eclipse.jetty.server.RequestLogWriter;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.util.BlockingArrayQueue;\nimport org.eclipse.jetty.util.thread.QueuedThreadPool;\nimport org.eclipse.jetty.util.thread.ThreadPool;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties.ForwardHeadersStrategy;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JettyWebServerFactoryCustomizer}.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @author HaiTao Zhang\n */\n// @DirtiesUrlFactories\nclass JettyWebServerFactoryCustomizerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final ServerProperties serverProperties = new ServerProperties();\n\n\tprivate final JettyServerProperties jettyProperties = new JettyServerProperties();\n\n\tprivate JettyWebServerFactoryCustomizer customizer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tthis.customizer = new JettyWebServerFactoryCustomizer(this.environment, this.serverProperties,\n\t\t\t\tthis.jettyProperties);\n\t}\n\n\t@Test\n\tvoid deduceUseForwardHeaders() {\n\t\tthis.environment.setProperty(\"DYNO\", \"-\");\n\t\tConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(true);\n\t}\n\n\t@Test\n\tvoid defaultUseForwardHeaders() {\n\t\tConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(false);\n\t}\n\n\t@Test\n\tvoid forwardHeadersWhenStrategyIsNativeShouldConfigureValve() {\n\t\tthis.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NATIVE);\n\t\tConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(true);\n\t}\n\n\t@Test\n\tvoid forwardHeadersWhenStrategyIsNoneShouldNotConfigureValve() {\n\t\tthis.environment.setProperty(\"DYNO\", \"-\");\n\t\tthis.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NONE);\n\t\tConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(false);\n\t}\n\n\t@Test\n\tvoid accessLogCanBeCustomized() throws IOException {\n\t\tFile logFile = File.createTempFile(\"jetty_log\", \".log\");\n\t\tbind(\"server.jetty.accesslog.enabled=true\", \"server.jetty.accesslog.format=extended_ncsa\",\n\t\t\t\t\"server.jetty.accesslog.filename=\" + logFile.getAbsolutePath().replace(\"\\\\\", \"\\\\\\\\\"),\n\t\t\t\t\"server.jetty.accesslog.file-date-format=yyyy-MM-dd\", \"server.jetty.accesslog.retention-period=42\",\n\t\t\t\t\"server.jetty.accesslog.append=true\", \"server.jetty.accesslog.ignore-paths=/a/path,/b/path\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tCustomRequestLog requestLog = getRequestLog(server);\n\t\tassertThat(requestLog.getFormatString()).isEqualTo(CustomRequestLog.EXTENDED_NCSA_FORMAT);\n\t\tassertThat(requestLog.getIgnorePaths()).hasSize(2);\n\t\tassertThat(requestLog.getIgnorePaths()).containsExactly(\"/a/path\", \"/b/path\");\n\t\tRequestLogWriter logWriter = getLogWriter(requestLog);\n\t\tassertThat(logWriter.getFileName()).isEqualTo(logFile.getAbsolutePath());\n\t\tassertThat(logWriter.getFilenameDateFormat()).isEqualTo(\"yyyy-MM-dd\");\n\t\tassertThat(logWriter.getRetainDays()).isEqualTo(42);\n\t\tassertThat(logWriter.isAppend()).isTrue();\n\t}\n\n\t@Test\n\tvoid accessLogCanBeEnabled() {\n\t\tbind(\"server.jetty.accesslog.enabled=true\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tCustomRequestLog requestLog = getRequestLog(server);\n\t\tassertThat(requestLog.getFormatString()).isEqualTo(CustomRequestLog.NCSA_FORMAT);\n\t\tassertThat(requestLog.getIgnorePaths()).isNull();\n\t\tRequestLogWriter logWriter = getLogWriter(requestLog);\n\t\tassertThat(logWriter.getFileName()).isNull();\n\t\tassertThat(logWriter.isAppend()).isFalse();\n\t}\n\n\t@Test\n\tvoid threadPoolMatchesJettyDefaults() {\n\t\tThreadPool defaultThreadPool = new Server(0).getThreadPool();\n\t\tThreadPool configuredThreadPool = customizeAndGetServer().getServer().getThreadPool();\n\t\tassertThat(defaultThreadPool).isInstanceOf(QueuedThreadPool.class);\n\t\tassertThat(configuredThreadPool).isInstanceOf(QueuedThreadPool.class);\n\t\tQueuedThreadPool defaultQueuedThreadPool = (QueuedThreadPool) defaultThreadPool;\n\t\tQueuedThreadPool configuredQueuedThreadPool = (QueuedThreadPool) configuredThreadPool;\n\t\tassertThat(configuredQueuedThreadPool.getMinThreads()).isEqualTo(defaultQueuedThreadPool.getMinThreads());\n\t\tassertThat(configuredQueuedThreadPool.getMaxThreads()).isEqualTo(defaultQueuedThreadPool.getMaxThreads());\n\t\tassertThat(configuredQueuedThreadPool.getIdleTimeout()).isEqualTo(defaultQueuedThreadPool.getIdleTimeout());\n\t\tBlockingQueue<?> defaultQueue = getQueue(defaultThreadPool);\n\t\tBlockingQueue<?> configuredQueue = getQueue(configuredThreadPool);\n\t\tassertThat(defaultQueue).isInstanceOf(BlockingArrayQueue.class);\n\t\tassertThat(configuredQueue).isInstanceOf(BlockingArrayQueue.class);\n\t\tassertThat(((BlockingArrayQueue<?>) defaultQueue).getMaxCapacity())\n\t\t\t.isEqualTo(((BlockingArrayQueue<?>) configuredQueue).getMaxCapacity());\n\t}\n\n\t@Test\n\tvoid threadPoolMaxThreadsCanBeCustomized() {\n\t\tbind(\"server.jetty.threads.max=100\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tQueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();\n\t\tassertThat(threadPool.getMaxThreads()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid threadPoolMinThreadsCanBeCustomized() {\n\t\tbind(\"server.jetty.threads.min=100\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tQueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();\n\t\tassertThat(threadPool.getMinThreads()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid threadPoolIdleTimeoutCanBeCustomized() {\n\t\tbind(\"server.jetty.threads.idle-timeout=100s\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tQueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();\n\t\tassertThat(threadPool.getIdleTimeout()).isEqualTo(100000);\n\t}\n\n\t@Test\n\tvoid threadPoolWithMaxQueueCapacityEqualToZeroCreateSynchronousQueue() {\n\t\tbind(\"server.jetty.threads.max-queue-capacity=0\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tThreadPool threadPool = server.getServer().getThreadPool();\n\t\tBlockingQueue<?> queue = getQueue(threadPool);\n\t\tassertThat(queue).isInstanceOf(SynchronousQueue.class);\n\t\tassertDefaultThreadPoolSettings(threadPool);\n\t}\n\n\t@Test\n\tvoid threadPoolWithMaxQueueCapacityEqualToZeroCustomizesThreadPool() {\n\t\tbind(\"server.jetty.threads.max-queue-capacity=0\", \"server.jetty.threads.min=100\",\n\t\t\t\t\"server.jetty.threads.max=100\", \"server.jetty.threads.idle-timeout=6s\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tQueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();\n\t\tassertThat(threadPool.getMinThreads()).isEqualTo(100);\n\t\tassertThat(threadPool.getMaxThreads()).isEqualTo(100);\n\t\tassertThat(threadPool.getIdleTimeout()).isEqualTo(Duration.ofSeconds(6).toMillis());\n\t}\n\n\t@Test\n\tvoid threadPoolWithMaxQueueCapacityPositiveCreateBlockingArrayQueue() {\n\t\tbind(\"server.jetty.threads.max-queue-capacity=1234\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tThreadPool threadPool = server.getServer().getThreadPool();\n\t\tBlockingQueue<?> queue = getQueue(threadPool);\n\t\tassertThat(queue).isInstanceOf(BlockingArrayQueue.class);\n\t\tassertThat(((BlockingArrayQueue<?>) queue).getMaxCapacity()).isEqualTo(1234);\n\t\tassertDefaultThreadPoolSettings(threadPool);\n\t}\n\n\t@Test\n\tvoid threadPoolWithMaxQueueCapacityPositiveCustomizesThreadPool() {\n\t\tbind(\"server.jetty.threads.max-queue-capacity=1234\", \"server.jetty.threads.min=10\",\n\t\t\t\t\"server.jetty.threads.max=150\", \"server.jetty.threads.idle-timeout=3s\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tQueuedThreadPool threadPool = (QueuedThreadPool) server.getServer().getThreadPool();\n\t\tassertThat(threadPool.getMinThreads()).isEqualTo(10);\n\t\tassertThat(threadPool.getMaxThreads()).isEqualTo(150);\n\t\tassertThat(threadPool.getIdleTimeout()).isEqualTo(Duration.ofSeconds(3).toMillis());\n\t}\n\n\tprivate void assertDefaultThreadPoolSettings(ThreadPool threadPool) {\n\t\tassertThat(threadPool).isInstanceOf(QueuedThreadPool.class);\n\t\tQueuedThreadPool queuedThreadPool = (QueuedThreadPool) threadPool;\n\t\tJettyServerProperties defaultProperties = new JettyServerProperties();\n\t\tassertThat(queuedThreadPool.getMinThreads()).isEqualTo(defaultProperties.getThreads().getMin());\n\t\tassertThat(queuedThreadPool.getMaxThreads()).isEqualTo(defaultProperties.getThreads().getMax());\n\t\tassertThat(queuedThreadPool.getIdleTimeout())\n\t\t\t.isEqualTo(defaultProperties.getThreads().getIdleTimeout().toMillis());\n\t}\n\n\tprivate CustomRequestLog getRequestLog(JettyWebServer server) {\n\t\tRequestLog requestLog = server.getServer().getRequestLog();\n\t\tassertThat(requestLog).isInstanceOf(CustomRequestLog.class);\n\t\treturn (CustomRequestLog) requestLog;\n\t}\n\n\tprivate RequestLogWriter getLogWriter(CustomRequestLog requestLog) {\n\t\tRequestLog.Writer writer = requestLog.getWriter();\n\t\tassertThat(writer).isInstanceOf(RequestLogWriter.class);\n\t\treturn (RequestLogWriter) requestLog.getWriter();\n\t}\n\n\t@Test\n\tvoid setUseForwardHeaders() {\n\t\tthis.serverProperties.setForwardHeadersStrategy(ForwardHeadersStrategy.NATIVE);\n\t\tConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(true);\n\t}\n\n\t@Test\n\tvoid customizeMaxRequestHttpHeaderSize() {\n\t\tbind(\"server.max-http-request-header-size=2048\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> requestHeaderSizes = getRequestHeaderSizes(server);\n\t\tassertThat(requestHeaderSizes).containsOnly(2048);\n\t}\n\n\t@Test\n\tvoid customMaxHttpRequestHeaderSizeIgnoredIfNegative() {\n\t\tbind(\"server.max-http-request-header-size=-1\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> requestHeaderSizes = getRequestHeaderSizes(server);\n\t\tassertThat(requestHeaderSizes).containsOnly(8192);\n\t}\n\n\t@Test\n\tvoid customMaxHttpRequestHeaderSizeIgnoredIfZero() {\n\t\tbind(\"server.max-http-request-header-size=0\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> requestHeaderSizes = getRequestHeaderSizes(server);\n\t\tassertThat(requestHeaderSizes).containsOnly(8192);\n\t}\n\n\t@Test\n\tvoid defaultMaxHttpResponseHeaderSize() {\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> responseHeaderSizes = getMaxResponseHeaderSizes(server);\n\t\tassertThat(responseHeaderSizes).containsOnly(16384);\n\t}\n\n\t@Test\n\tvoid customizeMaxHttpResponseHeaderSize() {\n\t\tbind(\"server.jetty.max-http-response-header-size=2KB\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> responseHeaderSizes = getMaxResponseHeaderSizes(server);\n\t\tassertThat(responseHeaderSizes).containsOnly(2048);\n\t}\n\n\t@Test\n\tvoid customMaxHttpResponseHeaderSizeIgnoredIfNegative() {\n\t\tbind(\"server.jetty.max-http-response-header-size=-1\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> responseHeaderSizes = getMaxResponseHeaderSizes(server);\n\t\tassertThat(responseHeaderSizes).containsOnly(16384);\n\t}\n\n\t@Test\n\tvoid customMaxHttpResponseHeaderSizeIgnoredIfZero() {\n\t\tbind(\"server.jetty.max-http-response-header-size=0\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Integer> responseHeaderSizes = getMaxResponseHeaderSizes(server);\n\t\tassertThat(responseHeaderSizes).containsOnly(16384);\n\t}\n\n\t@Test\n\tvoid customIdleTimeout() {\n\t\tbind(\"server.jetty.connection-idle-timeout=60s\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tList<Long> timeouts = connectorsIdleTimeouts(server);\n\t\tassertThat(timeouts).containsOnly(60000L);\n\t}\n\n\t@Test\n\tvoid customMaxFormKeys() {\n\t\tbind(\"server.jetty.max-form-keys=2048\");\n\t\tJettyWebServer server = customizeAndGetServer();\n\t\tstartAndStopToMakeInternalsAvailable(server);\n\t\tList<Integer> maxFormKeys = server.getServer()\n\t\t\t.getHandlers()\n\t\t\t.stream()\n\t\t\t.filter(ServletContextHandler.class::isInstance)\n\t\t\t.map(ServletContextHandler.class::cast)\n\t\t\t.map(ServletContextHandler::getMaxFormKeys)\n\t\t\t.toList();\n\t\tassertThat(maxFormKeys).containsOnly(2048);\n\t}\n\n\tprivate List<Long> connectorsIdleTimeouts(JettyWebServer server) {\n\t\tstartAndStopToMakeInternalsAvailable(server);\n\t\treturn Arrays.stream(server.getServer().getConnectors())\n\t\t\t.filter((connector) -> connector instanceof AbstractConnector)\n\t\t\t.map(Connector::getIdleTimeout)\n\t\t\t.toList();\n\t}\n\n\tprivate List<Integer> getRequestHeaderSizes(JettyWebServer server) {\n\t\treturn getHeaderSizes(server, HttpConfiguration::getRequestHeaderSize);\n\t}\n\n\tprivate List<Integer> getMaxResponseHeaderSizes(JettyWebServer server) {\n\t\treturn getHeaderSizes(server, HttpConfiguration::getMaxResponseHeaderSize);\n\t}\n\n\tprivate List<Integer> getHeaderSizes(JettyWebServer server, Function<HttpConfiguration, Integer> provider) {\n\t\tList<Integer> requestHeaderSizes = new ArrayList<>();\n\t\tstartAndStopToMakeInternalsAvailable(server);\n\t\tConnector[] connectors = server.getServer().getConnectors();\n\t\tfor (Connector connector : connectors) {\n\t\t\tconnector.getConnectionFactories()\n\t\t\t\t.stream()\n\t\t\t\t.filter((factory) -> factory instanceof ConnectionFactory)\n\t\t\t\t.forEach((cf) -> {\n\t\t\t\t\tConnectionFactory factory = (ConnectionFactory) cf;\n\t\t\t\t\tHttpConfiguration configuration = factory.getHttpConfiguration();\n\t\t\t\t\trequestHeaderSizes.add(provider.apply(configuration));\n\t\t\t\t});\n\t\t}\n\t\treturn requestHeaderSizes;\n\t}\n\n\tprivate void startAndStopToMakeInternalsAvailable(JettyWebServer server) {\n\t\tserver.start();\n\t\tserver.stop();\n\t}\n\n\tprivate BlockingQueue<?> getQueue(ThreadPool threadPool) {\n\t\tBlockingQueue<?> queue = ReflectionTestUtils.invokeMethod(threadPool, \"getQueue\");\n\t\tassertThat(queue).isNotNull();\n\t\treturn queue;\n\t}\n\n\tprivate void bind(String... inlinedProperties) {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties);\n\t\tBinder binder = new Binder(ConfigurationPropertySources.get(this.environment));\n\t\tbinder.bind(\"server\", Bindable.ofInstance(this.serverProperties));\n\t\tbinder.bind(\"server.jetty\", Bindable.ofInstance(this.jettyProperties));\n\t}\n\n\tprivate JettyWebServer customizeAndGetServer() {\n\t\tJettyServletWebServerFactory factory = customizeAndGetFactory();\n\t\treturn (JettyWebServer) factory.getWebServer();\n\t}\n\n\tprivate JettyServletWebServerFactory customizeAndGetFactory() {\n\t\tJettyServletWebServerFactory factory = new JettyServletWebServerFactory(0);\n\t\tthis.customizer.customize(factory);\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/actuate/web/server/JettyManagementServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.actuate.web.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JettyManagementServerProperties}.\n *\n * @author Andy Wilkinson\n */\nclass JettyManagementServerPropertiesTests {\n\n\t@Test\n\tvoid accessLogsArePrefixedByDefault() {\n\t\tJettyManagementServerProperties properties = new JettyManagementServerProperties();\n\t\tassertThat(properties.getAccesslog().getPrefix()).isEqualTo(\"management_\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/metrics/JettyMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.boot.jetty.autoconfigure.reactive.JettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.jetty.autoconfigure.servlet.JettyServletWebServerAutoConfiguration;\nimport org.springframework.boot.jetty.metrics.JettyConnectionMetricsBinder;\nimport org.springframework.boot.jetty.metrics.JettyServerThreadPoolMetricsBinder;\nimport org.springframework.boot.jetty.metrics.JettySslHandshakeMetricsBinder;\nimport org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.reactive.HttpHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JettyMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Chris Bono\n */\nclass JettyMetricsAutoConfigurationTests {\n\n\t@Test\n\tvoid autoConfiguresThreadPoolMetricsWithEmbeddedServletJetty() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tassertThat(context).hasSingleBean(JettyServerThreadPoolMetricsBinder.class);\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.threads.config.min\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresThreadPoolMetricsWithEmbeddedReactiveJetty() {\n\t\tnew ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyReactiveWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ReactiveWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.threads.config.min\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allowsCustomJettyServerThreadPoolMetricsBinderToBeUsed() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomJettyServerThreadPoolMetricsBinder.class, MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JettyServerThreadPoolMetricsBinder.class)\n\t\t\t\t.hasBean(\"customJettyServerThreadPoolMetricsBinder\"));\n\t}\n\n\t@Test\n\tvoid autoConfiguresConnectionMetricsWithEmbeddedServletJetty() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tassertThat(context).hasSingleBean(JettyConnectionMetricsBinder.class);\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.connections.messages.in\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresConnectionMetricsWithEmbeddedReactiveJetty() {\n\t\tnew ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyReactiveWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ReactiveWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.connections.messages.in\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allowsCustomJettyConnectionMetricsBinderToBeUsed() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, CustomJettyConnectionMetricsBinder.class,\n\t\t\t\t\tMeterRegistryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tassertThat(context).hasSingleBean(JettyConnectionMetricsBinder.class)\n\t\t\t\t\t.hasBean(\"customJettyConnectionMetricsBinder\");\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.connections.messages.in\")\n\t\t\t\t\t.tag(\"custom-tag-name\", \"custom-tag-value\")\n\t\t\t\t\t.meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid autoConfiguresSslHandshakeMetricsWithEmbeddedServletJetty() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.ssl.enabled=true\", \"server.ssl.key-store=classpath:test.jks\",\n\t\t\t\t\t\"server.ssl.key-store-password=secret\", \"server.ssl.key-password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tassertThat(context).hasSingleBean(JettySslHandshakeMetricsBinder.class);\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.ssl.handshakes\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid autoConfiguresSslHandshakeMetricsWithEmbeddedReactiveJetty() {\n\t\tnew ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyReactiveWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ReactiveWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.ssl.enabled=true\", \"server.ssl.key-store=classpath:test.jks\",\n\t\t\t\t\t\"server.ssl.key-store-password=secret\", \"server.ssl.key-password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.ssl.handshakes\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid allowsCustomJettySslHandshakeMetricsBinderToBeUsed() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, CustomJettySslHandshakeMetricsBinder.class,\n\t\t\t\t\tMeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.ssl.enabled=true\", \"server.ssl.key-store=classpath:test.jks\",\n\t\t\t\t\t\"server.ssl.key-store-password=secret\", \"server.ssl.key-password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tassertThat(context).hasSingleBean(JettySslHandshakeMetricsBinder.class)\n\t\t\t\t\t.hasBean(\"customJettySslHandshakeMetricsBinder\");\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"jetty.ssl.handshakes\").tag(\"custom-tag-name\", \"custom-tag-value\").meter())\n\t\t\t\t\t.isNotNull();\n\t\t\t});\n\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomJettySslHandshakeMetricsBinder.class, MeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.ssl.enabled: true\", \"server.ssl.key-store: src/test/resources/test.jks\",\n\t\t\t\t\t\"server.ssl.key-store-password: secret\", \"server.ssl.key-password: password\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JettySslHandshakeMetricsBinder.class)\n\t\t\t\t.hasBean(\"customJettySslHandshakeMetricsBinder\"));\n\t}\n\n\t@Test\n\tvoid doesNotAutoConfigureSslHandshakeMetricsWhenSslEnabledPropertyNotSpecified() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JettySslHandshakeMetricsBinder.class));\n\t}\n\n\t@Test\n\tvoid doesNotAutoConfigureSslHandshakeMetricsWhenSslEnabledPropertySetToFalse() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JettyMetricsAutoConfiguration.class,\n\t\t\t\t\tJettyServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.ssl.enabled: false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JettySslHandshakeMetricsBinder.class));\n\t}\n\n\tprivate ApplicationStartedEvent createApplicationStartedEvent(ConfigurableApplicationContext context) {\n\t\treturn new ApplicationStartedEvent(new SpringApplication(), new String[0], context, null);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MeterRegistryConfiguration {\n\n\t\t@Bean\n\t\tSimpleMeterRegistry meterRegistry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletWebServerConfiguration {\n\n\t\t@Bean\n\t\tJettyServletWebServerFactory jettyFactory() {\n\t\t\treturn new JettyServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveWebServerConfiguration {\n\n\t\t@Bean\n\t\tJettyReactiveWebServerFactory jettyFactory() {\n\t\t\treturn new JettyReactiveWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn mock(HttpHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJettyServerThreadPoolMetricsBinder {\n\n\t\t@Bean\n\t\tJettyServerThreadPoolMetricsBinder customJettyServerThreadPoolMetricsBinder(MeterRegistry meterRegistry) {\n\t\t\treturn new JettyServerThreadPoolMetricsBinder(meterRegistry);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJettyConnectionMetricsBinder {\n\n\t\t@Bean\n\t\tJettyConnectionMetricsBinder customJettyConnectionMetricsBinder(MeterRegistry meterRegistry) {\n\t\t\treturn new JettyConnectionMetricsBinder(meterRegistry, Tags.of(\"custom-tag-name\", \"custom-tag-value\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJettySslHandshakeMetricsBinder {\n\n\t\t@Bean\n\t\tJettySslHandshakeMetricsBinder customJettySslHandshakeMetricsBinder(MeterRegistry meterRegistry) {\n\t\t\treturn new JettySslHandshakeMetricsBinder(meterRegistry, Tags.of(\"custom-tag-name\", \"custom-tag-value\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/reactive/JettyReactiveWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.reactive;\n\nimport jakarta.websocket.server.ServerContainer;\nimport org.eclipse.jetty.ee11.servlet.ServletContextHandler;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.handler.StatisticsHandler;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.jetty.reactive.JettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.reactive.AbstractReactiveWebServerAutoConfigurationTests;\nimport org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JettyReactiveWebServerAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Raheela Aslam\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass JettyReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {\n\n\tJettyReactiveWebServerAutoConfigurationTests() {\n\t\tsuper(JettyReactiveWebServerAutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid jettyServerCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(JettyServerCustomizerConfiguration.class).run((context) -> {\n\t\t\tJettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);\n\t\t\tassertThat(factory.getServerCustomizers())\n\t\t\t\t.contains(context.getBean(\"serverCustomizer\", JettyServerCustomizer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationJettyServerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJettyReactiveWebServerFactory factory = context.getBean(JettyReactiveWebServerFactory.class);\n\t\t\t\tJettyServerCustomizer customizer = context.getBean(\"serverCustomizer\", JettyServerCustomizer.class);\n\t\t\t\tassertThat(factory.getServerCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any(Server.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid webSocketServerContainerIsAvailableFromServletContext() {\n\t\tthis.serverRunner.run((context) -> {\n\t\t\tWebServer webServer = ((ReactiveWebServerApplicationContext) context.getSourceApplicationContext())\n\t\t\t\t.getWebServer();\n\t\t\tassertThat(webServer).isNotNull();\n\t\t\tServletContextHandler servletContextHandler = (ServletContextHandler) ((StatisticsHandler) ((JettyWebServer) webServer)\n\t\t\t\t.getServer()\n\t\t\t\t.getHandler()).getHandler();\n\t\t\tObject serverContainer = servletContextHandler.getContext()\n\t\t\t\t.getAttribute(\"jakarta.websocket.server.ServerContainer\");\n\t\t\tassertThat(serverContainer).isInstanceOf(ServerContainer.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JettyServerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tJettyServerCustomizer serverCustomizer() {\n\t\t\treturn (server) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationJettyServerCustomizerConfiguration {\n\n\t\tprivate final JettyServerCustomizer customizer = mock(JettyServerCustomizer.class);\n\n\t\t@Bean\n\t\tJettyServerCustomizer serverCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<JettyReactiveWebServerFactory> jettyCustomizer() {\n\t\t\treturn (jetty) -> jetty.addServerCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/servlet/JettyServletWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.servlet;\n\nimport java.util.Map;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.ServletContext;\nimport org.eclipse.jetty.ee11.websocket.servlet.WebSocketUpgradeFilter;\nimport org.eclipse.jetty.server.Server;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.servlet.AbstractServletWebServerAutoConfigurationTests;\nimport org.springframework.boot.web.servlet.AbstractFilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Base class for testing sub-classes of {@link JettyServletWebServerAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Raheela Aslam\n * @author Madhura Bhave\n */\nclass JettyServletWebServerAutoConfigurationTests extends AbstractServletWebServerAutoConfigurationTests {\n\n\tprotected JettyServletWebServerAutoConfigurationTests() {\n\t\tsuper(JettyServletWebServerAutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid jettyServerCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(JettyServerCustomizerConfiguration.class).run((context) -> {\n\t\t\tJettyServletWebServerFactory factory = context.getBean(JettyServletWebServerFactory.class);\n\t\t\tassertThat(factory.getServerCustomizers())\n\t\t\t\t.contains(context.getBean(\"serverCustomizer\", JettyServerCustomizer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid jettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationJettyServerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJettyServletWebServerFactory factory = context.getBean(JettyServletWebServerFactory.class);\n\t\t\t\tJettyServerCustomizer customizer = context.getBean(\"serverCustomizer\", JettyServerCustomizer.class);\n\t\t\t\tassertThat(factory.getServerCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any(Server.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jettyWebSocketUpgradeFilterIsAddedToServletContex() {\n\t\tthis.serverRunner.run((context) -> {\n\t\t\tServletContext servletContext = context.getServletContext();\n\t\t\tassertThat(servletContext).isNotNull();\n\t\t\tassertThat(servletContext.getFilterRegistration(WebSocketUpgradeFilter.class.getName())).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid jettyWebSocketUpgradeFilterIsNotExposedAsABean() {\n\t\tthis.serverRunner.run((context) -> {\n\t\t\tMap<String, Filter> filters = context.getBeansOfType(Filter.class);\n\t\t\tassertThat(filters.values()).noneMatch(WebSocketUpgradeFilter.class::isInstance);\n\t\t\tMap<String, AbstractFilterRegistrationBean> filterRegistrations = context\n\t\t\t\t.getBeansOfType(AbstractFilterRegistrationBean.class);\n\t\t\tassertThat(filterRegistrations.values()).extracting(AbstractFilterRegistrationBean::getFilter)\n\t\t\t\t.noneMatch(WebSocketUpgradeFilter.class::isInstance);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jettyWebSocketUpgradeFilterServletContextInitializerBacksOffWhenBeanWithSameNameIsDefined() {\n\t\tthis.serverRunner\n\t\t\t.withUserConfiguration(CustomWebSocketUpgradeFilterServletContextInitializerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tBeanDefinition definition = context.getBeanFactory()\n\t\t\t\t\t.getBeanDefinition(\"websocketUpgradeFilterServletContextInitializer\");\n\t\t\t\tassertThat(definition.getFactoryBeanName())\n\t\t\t\t\t.contains(\"CustomWebSocketUpgradeFilterServletContextInitializerConfiguration\");\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JettyServerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tJettyServerCustomizer serverCustomizer() {\n\t\t\treturn (server) -> {\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationJettyServerCustomizerConfiguration {\n\n\t\tprivate final JettyServerCustomizer customizer = mock(JettyServerCustomizer.class);\n\n\t\t@Bean\n\t\tJettyServerCustomizer serverCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<JettyServletWebServerFactory> jettyCustomizer() {\n\t\t\treturn (jetty) -> jetty.addServerCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebSocketUpgradeFilterServletContextInitializerConfiguration {\n\n\t\t@Bean\n\t\tServletContextInitializer websocketUpgradeFilterServletContextInitializer() {\n\t\t\treturn (servletContext) -> {\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/autoconfigure/servlet/JettyServletWebServerServletContextListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.autoconfigure.servlet;\n\nimport jakarta.servlet.ServletContextListener;\n\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.AbstractServletWebServerServletContextListenerTests;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Tests for Jetty driving {@link ServletContextListener}s correctly.\n *\n * @author Andy Wilkinson\n */\nclass JettyServletWebServerServletContextListenerTests extends AbstractServletWebServerServletContextListenerTests {\n\n\tJettyServletWebServerServletContextListenerTests() {\n\t\tsuper(JettyConfiguration.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JettyConfiguration {\n\n\t\t@Bean\n\t\tJettyServletWebServerFactory webServerFactory() {\n\t\t\treturn new JettyServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/reactive/JettyReactiveWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.reactive;\n\nimport java.net.ConnectException;\nimport java.net.InetAddress;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.NetworkConnectionLimit;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.jetty.JettyAccess;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.Ssl.ServerNameSslBundle;\nimport org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactoryTests;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JettyReactiveWebServerFactory} and {@link JettyWebServer}.\n *\n * @author Brian Clozel\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\nclass JettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests {\n\n\t@Override\n\tprotected JettyReactiveWebServerFactory getFactory() {\n\t\treturn new JettyReactiveWebServerFactory(0);\n\t}\n\n\t@Test\n\t@Override\n\t@Disabled(\"Jetty 12 does not support User-Agent-based compression\")\n\t// TODO Is this true with Jetty 12?\n\tprotected void noCompressionForUserAgent() {\n\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setNullServerCustomizersShouldThrowException() {\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.setServerCustomizers(null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullServerCustomizersShouldThrowException() {\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.addServerCustomizers((JettyServerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid jettyCustomizersShouldBeInvoked() {\n\t\tHttpHandler handler = mock(HttpHandler.class);\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tJettyServerCustomizer[] configurations = new JettyServerCustomizer[4];\n\t\tArrays.setAll(configurations, (i) -> mock(JettyServerCustomizer.class));\n\t\tfactory.setServerCustomizers(Arrays.asList(configurations[0], configurations[1]));\n\t\tfactory.addServerCustomizers(configurations[2], configurations[3]);\n\t\tthis.webServer = factory.getWebServer(handler);\n\t\tInOrder ordered = inOrder((Object[]) configurations);\n\t\tfor (JettyServerCustomizer configuration : configurations) {\n\t\t\tordered.verify(configuration).customize(any(Server.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid specificIPAddressNotReverseResolved() throws Exception {\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tInetAddress localhost = InetAddress.getLocalHost();\n\t\tfactory.setAddress(InetAddress.getByAddress(localhost.getAddress()));\n\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\tthis.webServer.start();\n\t\tConnector connector = ((JettyWebServer) this.webServer).getServer().getConnectors()[0];\n\t\tassertThat(((ServerConnector) connector).getHost()).isEqualTo(localhost.getHostAddress());\n\t}\n\n\t@Test\n\tvoid useForwardedHeaders() {\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setUseForwardHeaders(true);\n\t\tassertForwardHeaderIsUsed(factory);\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() {\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tWebClient webClient = getWebClient(this.webServer.getPort()).build();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> {\n\t\t\tblockingHandler.stopBlocking();\n\t\t\ttry {\n\t\t\t\twebClient.get().retrieve().toBodilessEntity().block();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\treturn ex.getCause() instanceof ConnectException;\n\t\t\t}\n\t\t});\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\tvoid shouldApplyMaxConnections() {\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setMaxConnections(1);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tServer server = ((JettyWebServer) this.webServer).getServer();\n\t\tNetworkConnectionLimit connectionLimit = server.getBean(NetworkConnectionLimit.class);\n\t\tassertThat(connectionLimit).isNotNull();\n\t\tassertThat(connectionLimit.getMaxNetworkConnectionCount()).isOne();\n\t}\n\n\t@Test\n\tvoid sslServerNameBundlesConfigurationThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setBundle(\"test\");\n\t\tList<ServerNameSslBundle> bundles = List.of(new ServerNameSslBundle(\"first\", \"test1\"),\n\t\t\t\tnew ServerNameSslBundle(\"second\", \"test2\"));\n\t\tssl.setServerNameBundles(bundles);\n\t\tJettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(ssl);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.webServer = factory.getWebServer(new EchoHandler()))\n\t\t\t.withMessageContaining(\"Server name SSL bundles are not supported with Jetty\");\n\t}\n\n\t@Override\n\tprotected String startedLogMessage() {\n\t\treturn JettyAccess.getStartedLogMessage((JettyWebServer) this.webServer);\n\t}\n\n\t@Override\n\tprotected void addConnector(int port, ConfigurableReactiveWebServerFactory factory) {\n\t\t((JettyReactiveWebServerFactory) factory).addServerCustomizers((server) -> {\n\t\t\tServerConnector connector = new ServerConnector(server);\n\t\t\tconnector.setPort(port);\n\t\t\tserver.addConnector(connector);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/servlet/JettyServletWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport java.lang.reflect.Method;\nimport java.net.InetAddress;\nimport java.nio.charset.Charset;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EventListener;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.servlet.ServletRegistration.Dynamic;\nimport org.apache.hc.client5.http.HttpHostConnectException;\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.core5.http.Header;\nimport org.apache.hc.core5.http.HttpResponse;\nimport org.apache.jasper.servlet.JspServlet;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.awaitility.Awaitility;\nimport org.eclipse.jetty.ee11.servlet.ErrorPageErrorHandler;\nimport org.eclipse.jetty.ee11.servlet.ServletHolder;\nimport org.eclipse.jetty.ee11.webapp.AbstractConfiguration;\nimport org.eclipse.jetty.ee11.webapp.Configuration;\nimport org.eclipse.jetty.ee11.webapp.WebAppContext;\nimport org.eclipse.jetty.server.AbstractConnector;\nimport org.eclipse.jetty.server.Connector;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.NetworkConnectionLimit;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\nimport org.eclipse.jetty.server.SslConnectionFactory;\nimport org.eclipse.jetty.util.ClassMatcher;\nimport org.eclipse.jetty.util.ssl.SslContextFactory;\nimport org.eclipse.jetty.util.thread.QueuedThreadPool;\nimport org.eclipse.jetty.util.thread.ThreadPool;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.jetty.JettyAccess;\nimport org.springframework.boot.jetty.JettyServerCustomizer;\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.Ssl.ServerNameSslBundle;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.boot.web.server.servlet.AbstractServletWebServerFactoryTests;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JettyServletWebServerFactory}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Henri Kerola\n * @author Moritz Halbritter\n * @author Onur Kagan Ozcan\n */\nclass JettyServletWebServerFactoryTests extends AbstractServletWebServerFactoryTests {\n\n\t@Override\n\tprotected JettyServletWebServerFactory getFactory() {\n\t\treturn new JettyServletWebServerFactory(0);\n\t}\n\n\t@Override\n\tprotected void addConnector(int port, ConfigurableServletWebServerFactory factory) {\n\t\t((JettyServletWebServerFactory) factory).addServerCustomizers((server) -> {\n\t\t\tServerConnector connector = new ServerConnector(server);\n\t\t\tconnector.setPort(port);\n\t\t\tserver.addConnector(connector);\n\t\t});\n\t}\n\n\t@Override\n\tprotected @Nullable JspServlet getJspServlet() throws Exception {\n\t\tWebAppContext context = findWebAppContext((JettyWebServer) this.webServer);\n\t\tServletHolder holder = context.getServletHandler().getServlet(\"jsp\");\n\t\tif (holder == null) {\n\t\t\treturn null;\n\t\t}\n\t\tholder.start();\n\t\tholder.initialize();\n\t\treturn (JspServlet) holder.getServlet();\n\t}\n\n\t@Override\n\tprotected Map<String, String> getActualMimeMappings() {\n\t\tWebAppContext context = findWebAppContext((JettyWebServer) this.webServer);\n\t\treturn context.getMimeTypes().getMimeMap();\n\t}\n\n\t@Override\n\tprotected @Nullable Charset getCharset(Locale locale) {\n\t\tWebAppContext context = findWebAppContext((JettyWebServer) this.webServer);\n\t\tString charsetName = context.getLocaleEncoding(locale);\n\t\treturn (charsetName != null) ? Charset.forName(charsetName) : null;\n\t}\n\n\t@Override\n\tprotected void handleExceptionCausedByBlockedPortOnPrimaryConnector(RuntimeException ex, int blockedPort) {\n\t\tassertThat(ex).isInstanceOf(PortInUseException.class);\n\t\tassertThat(((PortInUseException) ex).getPort()).isEqualTo(blockedPort);\n\t}\n\n\t@Override\n\tprotected void handleExceptionCausedByBlockedPortOnSecondaryConnector(RuntimeException ex, int blockedPort) {\n\t\thandleExceptionCausedByBlockedPortOnPrimaryConnector(ex, blockedPort);\n\t}\n\n\t@Test\n\t@Override\n\t@Disabled(\"Jetty 12 does not support User-Agent-based compression\")\n\tprotected void noCompressionForUserAgent() {\n\t}\n\n\t@Test\n\t@Override\n\t@Disabled(\"Jetty 12 does not support SSL session tracking\")\n\tprotected void sslSessionTracking() {\n\n\t}\n\n\t@Test\n\tvoid contextPathIsLoggedOnStartupWhenCompressionIsEnabled(CapturedOutput output) {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setContextPath(\"/custom\");\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tfactory.setCompression(compression);\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(output).containsOnlyOnce(\"with context path '/custom'\");\n\t}\n\n\t@Test\n\tvoid jettyConfigurations() throws Exception {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tConfiguration[] configurations = new Configuration[] { mockConfiguration(Configuration1.class),\n\t\t\t\tmockConfiguration(Configuration2.class), mockConfiguration(Configuration3.class),\n\t\t\t\tmockConfiguration(Configuration4.class) };\n\t\tfactory.setConfigurations(Arrays.asList(configurations[0], configurations[1]));\n\t\tfactory.addConfigurations(configurations[2], configurations[3]);\n\t\tthis.webServer = factory.getWebServer();\n\t\tInOrder ordered = inOrder((Object[]) configurations);\n\t\tfor (Configuration configuration : configurations) {\n\t\t\tordered.verify(configuration).configure(any(WebAppContext.class));\n\t\t}\n\t}\n\n\tConfiguration mockConfiguration(Class<? extends Configuration> type) {\n\t\tConfiguration mock = mock(type);\n\t\tClassMatcher classMatcher = new ClassMatcher();\n\t\tgiven(mock.getProtectedClasses()).willReturn(classMatcher);\n\t\tgiven(mock.getHiddenClasses()).willReturn(classMatcher);\n\t\treturn mock;\n\t}\n\n\t@Test\n\tvoid jettyCustomizations() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tJettyServerCustomizer[] configurations = new JettyServerCustomizer[4];\n\t\tArrays.setAll(configurations, (i) -> mock(JettyServerCustomizer.class));\n\t\tfactory.setServerCustomizers(Arrays.asList(configurations[0], configurations[1]));\n\t\tfactory.addServerCustomizers(configurations[2], configurations[3]);\n\t\tthis.webServer = factory.getWebServer();\n\t\tInOrder ordered = inOrder((Object[]) configurations);\n\t\tfor (JettyServerCustomizer configuration : configurations) {\n\t\t\tordered.verify(configuration).customize(any(Server.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid sessionTimeout() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setTimeout(Duration.ofSeconds(10));\n\t\tassertTimeout(factory, 10);\n\t}\n\n\t@Test\n\tvoid sessionTimeoutInMinutes() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setTimeout(Duration.ofMinutes(1));\n\t\tassertTimeout(factory, 60);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslCiphersConfiguration(@ResourcePath(\"test.jks\") String keyStore) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setCiphers(new String[] { \"ALPHA\", \"BRAVO\", \"CHARLIE\" });\n\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(ssl);\n\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\n\t\tJettyWebServer jettyWebServer = (JettyWebServer) this.webServer;\n\t\tServerConnector connector = (ServerConnector) jettyWebServer.getServer().getConnectors()[0];\n\t\tSslConnectionFactory connectionFactory = connector.getConnectionFactory(SslConnectionFactory.class);\n\t\tSslContextFactory sslContextFactory = extractSslContextFactory(connectionFactory);\n\t\tassertThat(sslContextFactory.getIncludeCipherSuites()).containsExactly(\"ALPHA\", \"BRAVO\", \"CHARLIE\");\n\t\tassertThat(sslContextFactory.getExcludeCipherSuites()).isEmpty();\n\t}\n\n\t@Test\n\tvoid destroyCalledWithoutStart() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.destroy();\n\t\tServer server = ((JettyWebServer) this.webServer).getServer();\n\t\tassertThat(server.isStopped()).isTrue();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslEnabledMultiProtocolsConfiguration(@ResourcePath(\"test.jks\") String keyStore) {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(getSslSettings(keyStore, \"TLSv1.1\", \"TLSv1.2\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tJettyWebServer jettyWebServer = (JettyWebServer) this.webServer;\n\t\tServerConnector connector = (ServerConnector) jettyWebServer.getServer().getConnectors()[0];\n\t\tSslConnectionFactory connectionFactory = connector.getConnectionFactory(SslConnectionFactory.class);\n\t\tSslContextFactory sslContextFactory = extractSslContextFactory(connectionFactory);\n\t\tassertThat(sslContextFactory.getIncludeProtocols()).containsExactly(\"TLSv1.1\", \"TLSv1.2\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslEnabledProtocolsConfiguration(@ResourcePath(\"test.jks\") String keyStore) {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(getSslSettings(keyStore, \"TLSv1.1\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tJettyWebServer jettyWebServer = (JettyWebServer) this.webServer;\n\t\tServerConnector connector = (ServerConnector) jettyWebServer.getServer().getConnectors()[0];\n\t\tSslConnectionFactory connectionFactory = connector.getConnectionFactory(SslConnectionFactory.class);\n\t\tSslContextFactory sslContextFactory = extractSslContextFactory(connectionFactory);\n\t\tassertThat(sslContextFactory.getIncludeProtocols()).containsExactly(\"TLSv1.1\");\n\t}\n\n\t@Test\n\tvoid sslServerNameBundlesConfigurationThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setBundle(\"test\");\n\t\tList<ServerNameSslBundle> bundles = List.of(new ServerNameSslBundle(\"first\", \"test1\"),\n\t\t\t\tnew ServerNameSslBundle(\"second\", \"test2\"));\n\t\tssl.setServerNameBundles(bundles);\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(ssl);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.webServer = factory.getWebServer())\n\t\t\t.withMessageContaining(\"Server name SSL bundles are not supported with Jetty\");\n\t}\n\n\tprivate SslContextFactory extractSslContextFactory(SslConnectionFactory connectionFactory) {\n\t\ttry {\n\t\t\treturn connectionFactory.getSslContextFactory();\n\t\t}\n\t\tcatch (NoSuchMethodError ex) {\n\t\t\tMethod getSslContextFactory = ReflectionUtils.findMethod(connectionFactory.getClass(),\n\t\t\t\t\t\"getSslContextFactory\");\n\t\t\tassertThat(getSslContextFactory).isNotNull();\n\t\t\tSslContextFactory sslContextFactory = (SslContextFactory) ReflectionUtils.invokeMethod(getSslContextFactory,\n\t\t\t\t\tconnectionFactory);\n\t\t\tassertThat(sslContextFactory).isNotNull();\n\t\t\treturn sslContextFactory;\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingServlet);\n\t\t\tregistration.addMapping(\"/blocking\");\n\t\t\tregistration.setAsyncSupported(true);\n\t\t});\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tFuture<Object> request = initiateGetRequest(port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\tFuture<Object> unconnectableRequest = initiateGetRequest(port, \"/\");\n\t\tblockingServlet.admitOne();\n\t\tObject response = request.get();\n\t\tassertThat(response).isInstanceOf(HttpResponse.class);\n\t\tassertThat(unconnectableRequest.get()).isInstanceOf(HttpHostConnectException.class);\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownGracefullyThenResponseToRequestOnIdleConnectionWillHaveAConnectionCloseHeader()\n\t\t\tthrows Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingServlet);\n\t\t\tregistration.addMapping(\"/blocking\");\n\t\t\tregistration.setAsyncSupported(true);\n\t\t});\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tHttpClient client = HttpClients.createMinimal();\n\t\tFuture<Object> request = initiateGetRequest(client, port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tblockingServlet.admitOne();\n\t\tObject response = request.get();\n\t\tassertThat(response).isInstanceOf(HttpResponse.class);\n\t\tassertThat(((HttpResponse) response).getCode()).isEqualTo(200);\n\t\tassertThat(((HttpResponse) response).getFirstHeader(\"Connection\")).isNull();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\trequest = initiateGetRequest(client, port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tblockingServlet.admitOne();\n\t\tresponse = request.get();\n\t\tassertThat(response).isInstanceOf(HttpResponse.class);\n\t\tassertThat(((HttpResponse) response).getCode()).isEqualTo(200);\n\t\tassertThat(((HttpResponse) response).getFirstHeader(\"Connection\")).isNotNull()\n\t\t\t.extracting(Header::getValue)\n\t\t\t.isEqualTo(\"close\");\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\tvoid whenARequestCompletesAfterGracefulShutdownHasBegunThenItHasAConnectionCloseHeader()\n\t\t\tthrows InterruptedException, ExecutionException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingServlet);\n\t\t\tregistration.addMapping(\"/blocking\");\n\t\t\tregistration.setAsyncSupported(true);\n\t\t});\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tFuture<Object> request = initiateGetRequest(port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tblockingServlet.admitOne();\n\t\tAwaitility.await().atMost(Duration.ofSeconds(5)).until(() -> GracefulShutdownResult.IDLE == result.get());\n\t\tObject requestResult = request.get();\n\t\tassertThat(requestResult).isInstanceOf(HttpResponse.class);\n\t\tassertThat(((HttpResponse) requestResult).getFirstHeader(\"Connection\").getValue()).isEqualTo(\"close\");\n\t}\n\n\tprivate Ssl getSslSettings(String keyStore, String... enabledProtocols) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setCiphers(new String[] { \"ALPHA\", \"BRAVO\", \"CHARLIE\" });\n\t\tssl.setEnabledProtocols(enabledProtocols);\n\t\treturn ssl;\n\t}\n\n\tprivate void assertTimeout(ConfigurableServletWebServerFactory factory, int expected) {\n\t\tthis.webServer = factory.getWebServer();\n\t\tJettyWebServer jettyWebServer = (JettyWebServer) this.webServer;\n\t\tWebAppContext webAppContext = findWebAppContext(jettyWebServer);\n\t\tint actual = webAppContext.getSessionHandler().getMaxInactiveInterval();\n\t\tassertThat(actual).isEqualTo(expected);\n\t}\n\n\t@Test\n\tvoid wrappedHandlers() throws Exception {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setServerCustomizers(Collections.singletonList((server) -> {\n\t\t\tHandler handler = server.getHandler();\n\t\t\tHandler.Wrapper wrapper = new Handler.Wrapper();\n\t\t\twrapper.setHandler(handler);\n\t\t\tserver.setHandler(wrapper);\n\t\t}));\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid basicSslClasspathKeyStore() throws Exception {\n\t\ttestBasicSslWithKeyStore(\"classpath:test.jks\");\n\t}\n\n\t@Test\n\tvoid useForwardHeaders() throws Exception {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setUseForwardHeaders(true);\n\t\tassertForwardHeaderIsUsed(factory);\n\t}\n\n\t@Test\n\tvoid defaultThreadPool() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setThreadPool(null);\n\t\tassertThat(factory.getThreadPool()).isNull();\n\t\tthis.webServer = factory.getWebServer();\n\t\tassertThat(((JettyWebServer) this.webServer).getServer().getThreadPool()).isNotNull();\n\t}\n\n\t@Test\n\tvoid customThreadPool() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tThreadPool threadPool = mock(ThreadPool.class);\n\t\tfactory.setThreadPool(threadPool);\n\t\tthis.webServer = factory.getWebServer();\n\t\tassertThat(((JettyWebServer) this.webServer).getServer().getThreadPool()).isSameAs(threadPool);\n\t}\n\n\t@Test\n\tvoid startFailsWhenThreadPoolIsTooSmall() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.addServerCustomizers((server) -> {\n\t\t\tQueuedThreadPool threadPool = server.getBean(QueuedThreadPool.class);\n\t\t\tthreadPool.setMaxThreads(2);\n\t\t\tthreadPool.setMinThreads(2);\n\t\t});\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(factory.getWebServer()::start)\n\t\t\t.withCauseInstanceOf(IllegalStateException.class);\n\t}\n\n\t@Test\n\tvoid specificIPAddressNotReverseResolved() throws Exception {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tInetAddress localhost = InetAddress.getLocalHost();\n\t\tfactory.setAddress(InetAddress.getByAddress(localhost.getAddress()));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tConnector connector = ((JettyWebServer) this.webServer).getServer().getConnectors()[0];\n\t\tassertThat(((ServerConnector) connector).getHost()).isEqualTo(localhost.getHostAddress());\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid specificIPAddressWithSslIsNotReverseResolved() throws Exception {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tInetAddress localhost = InetAddress.getLocalHost();\n\t\tfactory.setAddress(InetAddress.getByAddress(localhost.getAddress()));\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tfactory.setSsl(ssl);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tConnector connector = ((JettyWebServer) this.webServer).getServer().getConnectors()[0];\n\t\tassertThat(((ServerConnector) connector).getHost()).isEqualTo(localhost.getHostAddress());\n\t}\n\n\t@Test\n\tvoid faultyListenerCausesStartFailure() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.addServerCustomizers((JettyServerCustomizer) (server) -> {\n\t\t\tCollection<WebAppContext> contexts = server.getBeans(WebAppContext.class);\n\t\t\tEventListener eventListener = new ServletContextListener() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void contextInitialized(ServletContextEvent event) {\n\t\t\t\t\tthrow new RuntimeException();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void contextDestroyed(ServletContextEvent event) {\n\t\t\t\t}\n\t\t\t};\n\t\t\tWebAppContext context = contexts.iterator().next();\n\t\t\ttry {\n\t\t\t\tcontext.addEventListener(eventListener);\n\t\t\t}\n\t\t\tcatch (NoSuchMethodError ex) {\n\t\t\t\t// Jetty 10\n\t\t\t\tMethod addEventListener = ReflectionUtils.findMethod(context.getClass(), \"addEventListener\",\n\t\t\t\t\t\tEventListener.class);\n\t\t\t\tassertThat(addEventListener).isNotNull();\n\t\t\t\tReflectionUtils.invokeMethod(addEventListener, context, eventListener);\n\t\t\t}\n\t\t});\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(() -> {\n\t\t\tJettyWebServer jettyWebServer = (JettyWebServer) factory.getWebServer();\n\t\t\ttry {\n\t\t\t\tjettyWebServer.start();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tQueuedThreadPool threadPool = (QueuedThreadPool) jettyWebServer.getServer().getThreadPool();\n\t\t\t\tassertThat(threadPool.isRunning()).isFalse();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid errorHandlerCanBeOverridden() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.addConfigurations(new AbstractConfiguration(new AbstractConfiguration.Builder()) {\n\n\t\t\t@Override\n\t\t\tpublic void configure(WebAppContext context) throws Exception {\n\t\t\t\tcontext.setErrorHandler(new CustomErrorHandler());\n\t\t\t}\n\n\t\t});\n\t\tJettyWebServer jettyWebServer = (JettyWebServer) factory.getWebServer();\n\t\tWebAppContext context = findWebAppContext(jettyWebServer);\n\t\tassertThat(context.getErrorHandler()).isInstanceOf(CustomErrorHandler.class);\n\t}\n\n\t@Test\n\tvoid shouldApplyMaxConnections() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setMaxConnections(1);\n\t\tthis.webServer = factory.getWebServer();\n\t\tServer server = ((JettyWebServer) this.webServer).getServer();\n\t\tNetworkConnectionLimit connectionLimit = server.getBean(NetworkConnectionLimit.class);\n\t\tassertThat(connectionLimit).isNotNull();\n\t\tassertThat(connectionLimit.getMaxNetworkConnectionCount()).isOne();\n\t}\n\n\t@Test\n\tvoid shouldApplyMaxConnectionsToConnectors() {\n\t\tJettyServletWebServerFactory factory = getFactory();\n\t\tfactory.setMaxConnections(1);\n\t\tthis.webServer = factory.getWebServer();\n\t\tServer server = ((JettyWebServer) this.webServer).getServer();\n\t\tassertThat(server.getConnectors()).isEmpty();\n\t\tNetworkConnectionLimit connectionLimit = server.getBean(NetworkConnectionLimit.class);\n\t\tassertThat(connectionLimit).extracting(\"_connectors\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(AbstractConnector.class))\n\t\t\t.hasSize(1);\n\t}\n\n\t@Override\n\tprotected String startedLogMessage() {\n\t\treturn JettyAccess.getStartedLogMessage((JettyWebServer) this.webServer);\n\t}\n\n\tprivate WebAppContext findWebAppContext(JettyWebServer webServer) {\n\t\treturn findWebAppContext(webServer.getServer().getHandler());\n\t}\n\n\tprivate WebAppContext findWebAppContext(Handler handler) {\n\t\tif (handler instanceof WebAppContext webAppContext) {\n\t\t\treturn webAppContext;\n\t\t}\n\t\tif (handler instanceof Handler.Wrapper wrapper) {\n\t\t\treturn findWebAppContext(wrapper.getHandler());\n\t\t}\n\t\tthrow new IllegalStateException(\"No WebAppContext found\");\n\t}\n\n\tprivate static final class CustomErrorHandler extends ErrorPageErrorHandler {\n\n\t}\n\n\tinterface Configuration1 extends Configuration {\n\n\t}\n\n\tinterface Configuration2 extends Configuration {\n\n\t}\n\n\tinterface Configuration3 extends Configuration {\n\n\t}\n\n\tinterface Configuration4 extends Configuration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/servlet/JettyServletWebServerMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport org.springframework.boot.jetty.JettyWebServer;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.context.AbstractServletWebServerMvcIntegrationTests;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Integration tests for {@link ServletWebServerApplicationContext} and\n * {@link JettyWebServer} running Spring MVC.\n */\nclass JettyServletWebServerMvcIntegrationTests extends AbstractServletWebServerMvcIntegrationTests {\n\n\tprotected JettyServletWebServerMvcIntegrationTests() {\n\t\tsuper(JettyConfig.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JettyConfig {\n\n\t\t@Bean\n\t\tJettyServletWebServerFactory webServerFactory() {\n\t\t\treturn new JettyServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jetty/src/test/java/org/springframework/boot/jetty/servlet/LoaderHidingResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jetty.servlet;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.nio.file.FileSystems;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.ZipEntry;\n\nimport org.eclipse.jetty.util.resource.PathResourceFactory;\nimport org.eclipse.jetty.util.resource.Resource;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LoaderHidingResource}.\n *\n * @author Andy Wilkinson\n */\nclass LoaderHidingResourceTests {\n\n\t@Test\n\tvoid listHidesLoaderResources(@TempDir File temp) throws IOException {\n\t\tURI warUri = createExampleWar(temp);\n\t\tResource resource = new PathResourceFactory().newResource(warUri);\n\t\tLoaderHidingResource loaderHidingResource = new LoaderHidingResource(resource, resource);\n\t\tassertThat(deepList(loaderHidingResource)).hasOnlyElementsOfType(LoaderHidingResource.class)\n\t\t\t.extracting(Resource::getName)\n\t\t\t.contains(\"/assets/image.jpg\")\n\t\t\t.doesNotContain(\"/org/springframework/boot/Loader.class\");\n\t}\n\n\t@Test\n\tvoid getAllResourcesHidesLoaderResources(@TempDir File temp) throws IOException {\n\t\tURI warUri = createExampleWar(temp);\n\t\tResource resource = new PathResourceFactory().newResource(warUri);\n\t\tLoaderHidingResource loaderHidingResource = new LoaderHidingResource(resource, resource);\n\t\tCollection<Resource> allResources = loaderHidingResource.getAllResources();\n\t\tassertThat(allResources).hasOnlyElementsOfType(LoaderHidingResource.class)\n\t\t\t.extracting(Resource::getName)\n\t\t\t.contains(\"/assets/image.jpg\")\n\t\t\t.doesNotContain(\"/org/springframework/boot/Loader.class\");\n\t}\n\n\t@Test\n\tvoid resolveHidesLoaderResources(@TempDir File temp) throws IOException {\n\t\tURI warUri = createExampleWar(temp);\n\t\tResource resource = new PathResourceFactory().newResource(warUri);\n\t\tLoaderHidingResource loaderHidingResource = new LoaderHidingResource(resource, resource);\n\t\tResource image = loaderHidingResource.resolve(\"/assets/image.jpg\");\n\t\tassertThat(image).isNotNull();\n\t\tassertThat(image.exists()).isTrue();\n\t\tassertThat(image).isInstanceOf(LoaderHidingResource.class);\n\t\tResource doesntExist = loaderHidingResource.resolve(\"/assets/non-existent.jpg\");\n\t\tassertThat(doesntExist).isNotNull();\n\t\tassertThat(doesntExist.exists()).isFalse();\n\t\tassertThat(doesntExist).isInstanceOf(LoaderHidingResource.class);\n\t\tassertThat(loaderHidingResource.resolve(\"/org/springframework/boot/Loader.class\")).isNull();\n\t}\n\n\tprivate URI createExampleWar(File temp) throws IOException {\n\t\tFile exampleWarFile = new File(temp, \"example.war\");\n\t\ttry (JarOutputStream out = new JarOutputStream(new FileOutputStream(exampleWarFile))) {\n\t\t\tout.putNextEntry(new ZipEntry(\"org/\"));\n\t\t\tout.putNextEntry(new ZipEntry(\"org/springframework/\"));\n\t\t\tout.putNextEntry(new ZipEntry(\"org/springframework/boot/\"));\n\t\t\tout.putNextEntry(new ZipEntry(\"org/springframework/boot/Loader.class\"));\n\t\t\tout.putNextEntry(new ZipEntry(\"assets/\"));\n\t\t\tout.putNextEntry(new ZipEntry(\"assets/image.jpg\"));\n\t\t}\n\t\tURI warUri = URI.create(\"jar:\" + exampleWarFile.toURI() + \"!/\");\n\t\tFileSystems.newFileSystem(warUri, Collections.emptyMap());\n\t\treturn warUri;\n\t}\n\n\tprivate List<Resource> deepList(Resource resource) {\n\t\tList<Resource> all = new ArrayList<>();\n\t\tfor (Resource listed : resource.list()) {\n\t\t\tall.add(listed);\n\t\t\tall.addAll(deepList(listed));\n\t\t}\n\t\treturn all;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot JMS\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"jakarta.jms:jakarta.jms-api\")\n\tapi(\"org.springframework:spring-jms\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(\"jakarta.transaction:jakarta.transaction-api\")\n\toptional(\"org.messaginghub:pooled-jms\") {\n\t\texclude group: \"org.apache.geronimo.specs\", module: \"geronimo-jms_2.0_spec\"\n\t}\n\toptional(\"org.springframework:spring-jdbc\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/ConnectionFactoryUnwrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\nimport org.springframework.jms.connection.CachingConnectionFactory;\n\n/**\n * Unwrap a {@link ConnectionFactory} that may have been wrapped to perform caching or\n * pooling.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class ConnectionFactoryUnwrapper {\n\n\tprivate ConnectionFactoryUnwrapper() {\n\t}\n\n\t/**\n\t * Return the native {@link ConnectionFactory} by unwrapping from a\n\t * {@link CachingConnectionFactory}. Return the given {@link ConnectionFactory} if no\n\t * {@link CachingConnectionFactory} wrapper has been detected.\n\t * @param connectionFactory a connection factory\n\t * @return the native connection factory that a {@link CachingConnectionFactory}\n\t * wraps, if any\n\t */\n\tpublic static ConnectionFactory unwrapCaching(ConnectionFactory connectionFactory) {\n\t\tif (connectionFactory instanceof CachingConnectionFactory cachingConnectionFactory) {\n\t\t\tConnectionFactory unwrapedConnectionFactory = cachingConnectionFactory.getTargetConnectionFactory();\n\t\t\treturn (unwrapedConnectionFactory != null) ? unwrapCaching(unwrapedConnectionFactory) : connectionFactory;\n\t\t}\n\t\treturn connectionFactory;\n\t}\n\n\t/**\n\t * Return the native {@link ConnectionFactory} by unwrapping it from a cache or pool\n\t * connection factory. Return the given {@link ConnectionFactory} if no caching\n\t * wrapper has been detected.\n\t * @param connectionFactory a connection factory\n\t * @return the native connection factory that it wraps, if any\n\t */\n\tpublic static @Nullable ConnectionFactory unwrap(@Nullable ConnectionFactory connectionFactory) {\n\t\tif (connectionFactory instanceof CachingConnectionFactory cachingConnectionFactory) {\n\t\t\treturn unwrap(cachingConnectionFactory.getTargetConnectionFactory());\n\t\t}\n\t\tConnectionFactory unwrapedConnectionFactory = unwrapFromJmsPoolConnectionFactory(connectionFactory);\n\t\treturn (unwrapedConnectionFactory != null) ? unwrap(unwrapedConnectionFactory) : connectionFactory;\n\t}\n\n\tprivate static @Nullable ConnectionFactory unwrapFromJmsPoolConnectionFactory(\n\t\t\t@Nullable ConnectionFactory connectionFactory) {\n\t\ttry {\n\t\t\tif (connectionFactory instanceof JmsPoolConnectionFactory jmsPoolConnectionFactory) {\n\t\t\t\treturn (ConnectionFactory) jmsPoolConnectionFactory.getConnectionFactory();\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\t// ignore\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/XAConnectionFactoryWrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms;\n\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.XAConnectionFactory;\nimport jakarta.transaction.TransactionManager;\n\n/**\n * Strategy interface used to wrap a JMS {@link XAConnectionFactory} enrolling it with a\n * JTA {@link TransactionManager}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@FunctionalInterface\npublic interface XAConnectionFactoryWrapper {\n\n\t/**\n\t * Wrap the specific {@link XAConnectionFactory} and enroll it with a JTA\n\t * {@link TransactionManager}.\n\t * @param connectionFactory the connection factory to wrap\n\t * @return the wrapped connection factory\n\t * @throws Exception if the connection factory cannot be wrapped\n\t */\n\tConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory) throws Exception;\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/AbstractJmsListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.ExceptionListener;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties.Listener.Session;\nimport org.springframework.jms.config.AbstractJmsListenerContainerFactory;\nimport org.springframework.jms.config.JmsListenerContainerFactory;\nimport org.springframework.jms.support.converter.MessageConverter;\nimport org.springframework.jms.support.destination.DestinationResolver;\nimport org.springframework.util.Assert;\n\n/**\n * Configure common {@link JmsListenerContainerFactory} settings with sensible defaults.\n * <p>\n * This includes:\n * <li>A {@link DestinationResolver} is such a component is present.</li>\n * <li>A {@link MessageConverter} is such a component is present.</li>\n * <li>An {@link ExceptionListener} is such a component is present.</li>\n * <li>An {@link ObservationRegistry} is such a component is present.</li>\n * <li>Configuration properties of the {@code spring.jms} namespace that are common to all\n * implementations.</li>\n *\n * @param <T> the connection factory type.\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Vedran Pavic\n * @author Lasse Wulff\n * @since 4.1.0\n */\npublic abstract class AbstractJmsListenerContainerFactoryConfigurer<T extends AbstractJmsListenerContainerFactory<?>> {\n\n\tprivate @Nullable DestinationResolver destinationResolver;\n\n\tprivate @Nullable MessageConverter messageConverter;\n\n\tprivate @Nullable ExceptionListener exceptionListener;\n\n\tprivate @Nullable ObservationRegistry observationRegistry;\n\n\tprivate @Nullable JmsProperties jmsProperties;\n\n\t/**\n\t * Set the {@link DestinationResolver} to use or {@code null} if no destination\n\t * resolver should be associated with the factory by default.\n\t * @param destinationResolver the {@link DestinationResolver}\n\t */\n\tvoid setDestinationResolver(@Nullable DestinationResolver destinationResolver) {\n\t\tthis.destinationResolver = destinationResolver;\n\t}\n\n\t/**\n\t * Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box\n\t * converter should be used.\n\t * @param messageConverter the {@link MessageConverter}\n\t */\n\tvoid setMessageConverter(@Nullable MessageConverter messageConverter) {\n\t\tthis.messageConverter = messageConverter;\n\t}\n\n\t/**\n\t * Set the {@link ExceptionListener} to use or {@code null} if no exception listener\n\t * should be associated by default.\n\t * @param exceptionListener the {@link ExceptionListener}\n\t */\n\tvoid setExceptionListener(@Nullable ExceptionListener exceptionListener) {\n\t\tthis.exceptionListener = exceptionListener;\n\t}\n\n\t/**\n\t * Set the {@link JmsProperties} to use.\n\t * @param jmsProperties the {@link JmsProperties}\n\t */\n\tvoid setJmsProperties(@Nullable JmsProperties jmsProperties) {\n\t\tthis.jmsProperties = jmsProperties;\n\t}\n\n\t/**\n\t * Set the {@link ObservationRegistry} to use.\n\t * @param observationRegistry the {@link ObservationRegistry}\n\t */\n\tvoid setObservationRegistry(@Nullable ObservationRegistry observationRegistry) {\n\t\tthis.observationRegistry = observationRegistry;\n\t}\n\n\t/**\n\t * Return the {@link JmsProperties}.\n\t * @return the jms properties\n\t */\n\tprotected JmsProperties getJmsProperties() {\n\t\tAssert.state(this.jmsProperties != null, \"'jmsProperties' must not be null\");\n\t\treturn this.jmsProperties;\n\t}\n\n\t/**\n\t * Configure the specified jms listener container factory. The factory can be further\n\t * tuned and default settings can be overridden.\n\t * @param factory the {@link AbstractJmsListenerContainerFactory} instance to\n\t * configure\n\t * @param connectionFactory the {@link ConnectionFactory} to use\n\t */\n\tpublic void configure(T factory, ConnectionFactory connectionFactory) {\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\tAssert.notNull(connectionFactory, \"'connectionFactory' must not be null\");\n\t\tJmsProperties properties = getJmsProperties();\n\t\tJmsProperties.Listener listenerProperties = properties.getListener();\n\t\tSession sessionProperties = listenerProperties.getSession();\n\t\tfactory.setConnectionFactory(connectionFactory);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::isPubSubDomain).to(factory::setPubSubDomain);\n\t\tmap.from(properties::isSubscriptionDurable).to(factory::setSubscriptionDurable);\n\t\tmap.from(properties::getClientId).to(factory::setClientId);\n\t\tmap.from(this.destinationResolver).to(factory::setDestinationResolver);\n\t\tmap.from(this.messageConverter).to(factory::setMessageConverter);\n\t\tmap.from(this.exceptionListener).to(factory::setExceptionListener);\n\t\tmap.from(sessionProperties.getAcknowledgeMode()::getMode).to(factory::setSessionAcknowledgeMode);\n\t\tmap.from(this.observationRegistry).to(factory::setObservationRegistry);\n\t\tmap.from(sessionProperties::getTransacted).to(factory::setSessionTransacted);\n\t\tmap.from(listenerProperties::isAutoStartup).to(factory::setAutoStartup);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/AcknowledgeMode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport jakarta.jms.Session;\n\nimport org.springframework.jms.support.JmsAccessor;\n\n/**\n * Acknowledge modes for a JMS Session. Supports the acknowledge modes defined by\n * {@link jakarta.jms.Session} as well as other, non-standard modes.\n *\n * <p>\n * Note that {@link jakarta.jms.Session#SESSION_TRANSACTED} is not defined. It should be\n * handled through a call to {@link JmsAccessor#setSessionTransacted(boolean)}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic final class AcknowledgeMode {\n\n\tprivate static final Map<String, AcknowledgeMode> knownModes = new HashMap<>(3);\n\n\t/**\n\t * Messages sent or received from the session are automatically acknowledged. This is\n\t * the simplest mode and enables once-only message delivery guarantee.\n\t */\n\tpublic static final AcknowledgeMode AUTO = new AcknowledgeMode(Session.AUTO_ACKNOWLEDGE);\n\n\t/**\n\t * Messages are acknowledged once the message listener implementation has called\n\t * {@link jakarta.jms.Message#acknowledge()}. This mode gives the application (rather\n\t * than the JMS provider) complete control over message acknowledgement.\n\t */\n\tpublic static final AcknowledgeMode CLIENT = new AcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);\n\n\t/**\n\t * Similar to auto acknowledgment except that said acknowledgment is lazy. As a\n\t * consequence, the messages might be delivered more than once. This mode enables\n\t * at-least-once message delivery guarantee.\n\t */\n\tpublic static final AcknowledgeMode DUPS_OK = new AcknowledgeMode(Session.DUPS_OK_ACKNOWLEDGE);\n\n\tstatic {\n\t\tknownModes.put(\"auto\", AUTO);\n\t\tknownModes.put(\"client\", CLIENT);\n\t\tknownModes.put(\"dupsok\", DUPS_OK);\n\t}\n\n\tprivate final int mode;\n\n\tprivate AcknowledgeMode(int mode) {\n\t\tthis.mode = mode;\n\t}\n\n\tpublic int getMode() {\n\t\treturn this.mode;\n\t}\n\n\t/**\n\t * Creates an {@code AcknowledgeMode} of the given {@code mode}. The mode may be\n\t * {@code auto}, {@code client}, {@code dupsok} or a non-standard acknowledge mode\n\t * that can be {@link Integer#parseInt parsed as an integer}.\n\t * @param mode the mode\n\t * @return the acknowledge mode\n\t */\n\tpublic static AcknowledgeMode of(String mode) {\n\t\tString canonicalMode = canonicalize(mode);\n\t\tAcknowledgeMode knownMode = knownModes.get(canonicalMode);\n\t\ttry {\n\t\t\treturn (knownMode != null) ? knownMode : new AcknowledgeMode(Integer.parseInt(canonicalMode));\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\tthrow new IllegalArgumentException(\"'\" + mode\n\t\t\t\t\t+ \"' is neither a known acknowledge mode (auto, client, or dups_ok) nor an integer value\");\n\t\t}\n\t}\n\n\tprivate static String canonicalize(String input) {\n\t\tStringBuilder canonicalName = new StringBuilder(input.length());\n\t\tinput.chars()\n\t\t\t.filter(Character::isLetterOrDigit)\n\t\t\t.map(Character::toLowerCase)\n\t\t\t.forEach((c) -> canonicalName.append((char) c));\n\t\treturn canonicalName.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/DefaultJmsListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.time.Duration;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties.Listener.Session;\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\n/**\n * Configure {@link DefaultJmsListenerContainerFactory} with sensible defaults tuned using\n * configuration properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code DefaultJmsListenerContainerFactory} whose configuration is based upon that\n * produced by auto-configuration.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Vedran Pavic\n * @author Lasse Wulff\n * @since 4.0.0\n * @see SimpleJmsListenerContainerFactoryConfigurer\n */\npublic final class DefaultJmsListenerContainerFactoryConfigurer\n\t\textends AbstractJmsListenerContainerFactoryConfigurer<DefaultJmsListenerContainerFactory> {\n\n\tprivate @Nullable JtaTransactionManager transactionManager;\n\n\t/**\n\t * Set the {@link JtaTransactionManager} to use or {@code null} if the JTA support\n\t * should not be used.\n\t * @param transactionManager the {@link JtaTransactionManager}\n\t */\n\tvoid setTransactionManager(@Nullable JtaTransactionManager transactionManager) {\n\t\tthis.transactionManager = transactionManager;\n\t}\n\n\t@Override\n\tpublic void configure(DefaultJmsListenerContainerFactory factory, ConnectionFactory connectionFactory) {\n\t\tsuper.configure(factory, connectionFactory);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tJmsProperties.Listener listenerProperties = getJmsProperties().getListener();\n\t\tSession sessionProperties = listenerProperties.getSession();\n\t\tmap.from(this.transactionManager).to(factory::setTransactionManager);\n\t\tif (this.transactionManager == null && sessionProperties.getTransacted() == null) {\n\t\t\tfactory.setSessionTransacted(true);\n\t\t}\n\t\tmap.from(listenerProperties::formatConcurrency).to(factory::setConcurrency);\n\t\tmap.from(listenerProperties::getReceiveTimeout).as(Duration::toMillis).to(factory::setReceiveTimeout);\n\t\tmap.from(listenerProperties::getMaxMessagesPerTask).to(factory::setMaxMessagesPerTask);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsAnnotationDrivenConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.ExceptionListener;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.jms.ConnectionFactoryUnwrapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.annotation.EnableJms;\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory;\nimport org.springframework.jms.config.JmsListenerConfigUtils;\nimport org.springframework.jms.support.converter.MessageConverter;\nimport org.springframework.jms.support.destination.DestinationResolver;\nimport org.springframework.jms.support.destination.JndiDestinationResolver;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\n/**\n * Configuration for Spring 4.1 annotation driven JMS.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Vedran Pavic\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(EnableJms.class)\nclass JmsAnnotationDrivenConfiguration {\n\n\tprivate final ObjectProvider<DestinationResolver> destinationResolver;\n\n\tprivate final ObjectProvider<JtaTransactionManager> transactionManager;\n\n\tprivate final ObjectProvider<MessageConverter> messageConverter;\n\n\tprivate final ObjectProvider<ExceptionListener> exceptionListener;\n\n\tprivate final ObjectProvider<ObservationRegistry> observationRegistry;\n\n\tprivate final JmsProperties properties;\n\n\tJmsAnnotationDrivenConfiguration(ObjectProvider<DestinationResolver> destinationResolver,\n\t\t\tObjectProvider<JtaTransactionManager> transactionManager, ObjectProvider<MessageConverter> messageConverter,\n\t\t\tObjectProvider<ExceptionListener> exceptionListener,\n\t\t\tObjectProvider<ObservationRegistry> observationRegistry, JmsProperties properties) {\n\t\tthis.destinationResolver = destinationResolver;\n\t\tthis.transactionManager = transactionManager;\n\t\tthis.messageConverter = messageConverter;\n\t\tthis.exceptionListener = exceptionListener;\n\t\tthis.observationRegistry = observationRegistry;\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDefaultJmsListenerContainerFactoryConfigurer defaultJmsListenerContainerFactoryConfigurer() {\n\t\tDefaultJmsListenerContainerFactoryConfigurer configurer = new DefaultJmsListenerContainerFactoryConfigurer();\n\t\tconfigurer.setDestinationResolver(this.destinationResolver.getIfUnique());\n\t\tconfigurer.setTransactionManager(this.transactionManager.getIfUnique());\n\t\tconfigurer.setMessageConverter(this.messageConverter.getIfUnique());\n\t\tconfigurer.setExceptionListener(this.exceptionListener.getIfUnique());\n\t\tconfigurer.setObservationRegistry(this.observationRegistry.getIfUnique());\n\t\tconfigurer.setJmsProperties(this.properties);\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSimpleJmsListenerContainerFactoryConfigurer simpleJmsListenerContainerFactoryConfigurer() {\n\t\tSimpleJmsListenerContainerFactoryConfigurer configurer = new SimpleJmsListenerContainerFactoryConfigurer();\n\t\tconfigurer.setDestinationResolver(this.destinationResolver.getIfUnique());\n\t\tconfigurer.setMessageConverter(this.messageConverter.getIfUnique());\n\t\tconfigurer.setExceptionListener(this.exceptionListener.getIfUnique());\n\t\tconfigurer.setObservationRegistry(this.observationRegistry.getIfUnique());\n\t\tconfigurer.setJmsProperties(this.properties);\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\t@ConditionalOnSingleCandidate(ConnectionFactory.class)\n\t@ConditionalOnMissingBean(name = \"jmsListenerContainerFactory\")\n\tDefaultJmsListenerContainerFactory jmsListenerContainerFactory(\n\t\t\tDefaultJmsListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {\n\t\tDefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();\n\t\tconfigurer.configure(factory, ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory));\n\t\treturn factory;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableJms\n\t@ConditionalOnMissingBean(name = JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)\n\tstatic class EnableJmsConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnJndi\n\tstatic class JndiConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(DestinationResolver.class)\n\t\tJndiDestinationResolver destinationResolver() {\n\t\t\tJndiDestinationResolver resolver = new JndiDestinationResolver();\n\t\t\tresolver.setFallbackToDynamicDestination(true);\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.util.List;\n\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.Message;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.ExecutableMode;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration.JmsRuntimeHints;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.jms.core.JmsTemplate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring JMS.\n *\n * @author Greg Turnquist\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Message.class, JmsTemplate.class })\n@ConditionalOnBean(ConnectionFactory.class)\n@EnableConfigurationProperties(JmsProperties.class)\n@Import({ JmsClientConfigurations.JmsTemplateConfiguration.class,\n\t\tJmsClientConfigurations.MessagingTemplateConfiguration.class,\n\t\tJmsClientConfigurations.JmsClientConfiguration.class, JmsAnnotationDrivenConfiguration.class })\n@ImportRuntimeHints(JmsRuntimeHints.class)\npublic final class JmsAutoConfiguration {\n\n\tstatic class JmsRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerType(TypeReference.of(AcknowledgeMode.class), (type) -> type.withMethod(\"of\",\n\t\t\t\t\t\tList.of(TypeReference.of(String.class)), ExecutableMode.INVOKE));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsClientConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties.DeliveryMode;\nimport org.springframework.boot.jms.autoconfigure.JmsProperties.Template;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.jms.core.JmsMessageOperations;\nimport org.springframework.jms.core.JmsMessagingTemplate;\nimport org.springframework.jms.core.JmsOperations;\nimport org.springframework.jms.core.JmsTemplate;\nimport org.springframework.jms.support.converter.MessageConverter;\nimport org.springframework.jms.support.destination.DestinationResolver;\n\n/**\n * Configurations for JMS client infrastructure.\n *\n * @author Stephane Nicoll\n * @see JmsAutoConfiguration\n */\nabstract class JmsClientConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JmsTemplateConfiguration {\n\n\t\tprivate final JmsProperties properties;\n\n\t\tprivate final ObjectProvider<DestinationResolver> destinationResolver;\n\n\t\tprivate final ObjectProvider<MessageConverter> messageConverter;\n\n\t\tprivate final ObjectProvider<ObservationRegistry> observationRegistry;\n\n\t\tJmsTemplateConfiguration(JmsProperties properties, ObjectProvider<DestinationResolver> destinationResolver,\n\t\t\t\tObjectProvider<MessageConverter> messageConverter,\n\t\t\t\tObjectProvider<ObservationRegistry> observationRegistry) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.destinationResolver = destinationResolver;\n\t\t\tthis.messageConverter = messageConverter;\n\t\t\tthis.observationRegistry = observationRegistry;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(JmsOperations.class)\n\t\t@ConditionalOnSingleCandidate(ConnectionFactory.class)\n\t\tJmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tJmsTemplate template = new JmsTemplate(connectionFactory);\n\t\t\ttemplate.setPubSubDomain(this.properties.isPubSubDomain());\n\t\t\tmap.from(this.destinationResolver::getIfUnique).to(template::setDestinationResolver);\n\t\t\tmap.from(this.messageConverter::getIfUnique).to(template::setMessageConverter);\n\t\t\tmap.from(this.observationRegistry::getIfUnique).to(template::setObservationRegistry);\n\t\t\tmapTemplateProperties(this.properties.getTemplate(), template);\n\t\t\treturn template;\n\t\t}\n\n\t\tprivate void mapTemplateProperties(Template properties, JmsTemplate template) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties.getSession().getAcknowledgeMode()::getMode).to(template::setSessionAcknowledgeMode);\n\t\t\tmap.from(properties.getSession()::isTransacted).to(template::setSessionTransacted);\n\t\t\tmap.from(properties::getDefaultDestination).to(template::setDefaultDestinationName);\n\t\t\tmap.from(properties::getDeliveryDelay).as(Duration::toMillis).to(template::setDeliveryDelay);\n\t\t\tmap.from(properties::determineQosEnabled).to(template::setExplicitQosEnabled);\n\t\t\tmap.from(properties::getDeliveryMode).as(DeliveryMode::getValue).to(template::setDeliveryMode);\n\t\t\tmap.from(properties::getPriority).to(template::setPriority);\n\t\t\tmap.from(properties::getTimeToLive).as(Duration::toMillis).to(template::setTimeToLive);\n\t\t\tmap.from(properties::getReceiveTimeout).as(Duration::toMillis).to(template::setReceiveTimeout);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JmsMessagingTemplate.class)\n\tstatic class MessagingTemplateConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(JmsMessageOperations.class)\n\t\t@ConditionalOnSingleCandidate(JmsTemplate.class)\n\t\tJmsMessagingTemplate jmsMessagingTemplate(JmsProperties properties, JmsTemplate jmsTemplate) {\n\t\t\tJmsMessagingTemplate messagingTemplate = new JmsMessagingTemplate(jmsTemplate);\n\t\t\tmapTemplateProperties(properties.getTemplate(), messagingTemplate);\n\t\t\treturn messagingTemplate;\n\t\t}\n\n\t\tprivate void mapTemplateProperties(Template properties, JmsMessagingTemplate messagingTemplate) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getDefaultDestination).to(messagingTemplate::setDefaultDestinationName);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JmsClient.class)\n\tstatic class JmsClientConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnSingleCandidate(JmsTemplate.class)\n\t\tJmsClient jmsClient(JmsTemplate jmsTemplate) {\n\t\t\treturn JmsClient.create(jmsTemplate);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsPoolConnectionFactoryFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\n/**\n * Factory to create a {@link JmsPoolConnectionFactory} from properties defined in\n * {@link JmsPoolConnectionFactoryProperties}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class JmsPoolConnectionFactoryFactory {\n\n\tprivate final JmsPoolConnectionFactoryProperties properties;\n\n\tpublic JmsPoolConnectionFactoryFactory(JmsPoolConnectionFactoryProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t/**\n\t * Create a {@link JmsPoolConnectionFactory} based on the specified\n\t * {@link ConnectionFactory}.\n\t * @param connectionFactory the connection factory to wrap\n\t * @return a pooled connection factory\n\t */\n\tpublic JmsPoolConnectionFactory createPooledConnectionFactory(ConnectionFactory connectionFactory) {\n\t\tJmsPoolConnectionFactory pooledConnectionFactory = new JmsPoolConnectionFactory();\n\t\tpooledConnectionFactory.setConnectionFactory(connectionFactory);\n\n\t\tpooledConnectionFactory.setBlockIfSessionPoolIsFull(this.properties.isBlockIfFull());\n\t\tif (this.properties.getBlockIfFullTimeout() != null) {\n\t\t\tpooledConnectionFactory\n\t\t\t\t.setBlockIfSessionPoolIsFullTimeout(this.properties.getBlockIfFullTimeout().toMillis());\n\t\t}\n\t\tif (this.properties.getIdleTimeout() != null) {\n\t\t\tpooledConnectionFactory.setConnectionIdleTimeout((int) this.properties.getIdleTimeout().toMillis());\n\t\t}\n\t\tpooledConnectionFactory.setMaxConnections(this.properties.getMaxConnections());\n\t\tpooledConnectionFactory.setMaxSessionsPerConnection(this.properties.getMaxSessionsPerConnection());\n\t\tif (this.properties.getTimeBetweenExpirationCheck() != null) {\n\t\t\tpooledConnectionFactory\n\t\t\t\t.setConnectionCheckInterval(this.properties.getTimeBetweenExpirationCheck().toMillis());\n\t\t}\n\t\tpooledConnectionFactory.setUseAnonymousProducers(this.properties.isUseAnonymousProducers());\n\t\treturn pooledConnectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsPoolConnectionFactoryProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.time.Duration;\n\n/**\n * Configuration properties for connection factory pooling.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class JmsPoolConnectionFactoryProperties {\n\n\t/**\n\t * Whether a JmsPoolConnectionFactory should be created, instead of a regular\n\t * ConnectionFactory.\n\t */\n\tprivate boolean enabled;\n\n\t/**\n\t * Whether to block when a connection is requested and the pool is full. Set it to\n\t * false to throw a \"JMSException\" instead.\n\t */\n\tprivate boolean blockIfFull = true;\n\n\t/**\n\t * Blocking period before throwing an exception if the pool is still full.\n\t */\n\tprivate Duration blockIfFullTimeout = Duration.ofMillis(-1);\n\n\t/**\n\t * Connection idle timeout.\n\t */\n\tprivate Duration idleTimeout = Duration.ofSeconds(30);\n\n\t/**\n\t * Maximum number of pooled connections.\n\t */\n\tprivate int maxConnections = 1;\n\n\t/**\n\t * Maximum number of pooled sessions per connection in the pool.\n\t */\n\tprivate int maxSessionsPerConnection = 500;\n\n\t/**\n\t * Time to sleep between runs of the idle connection eviction thread. When negative,\n\t * no idle connection eviction thread runs.\n\t */\n\tprivate Duration timeBetweenExpirationCheck = Duration.ofMillis(-1);\n\n\t/**\n\t * Whether to use only one anonymous \"MessageProducer\" instance. Set it to false to\n\t * create one \"MessageProducer\" every time one is required.\n\t */\n\tprivate boolean useAnonymousProducers = true;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic boolean isBlockIfFull() {\n\t\treturn this.blockIfFull;\n\t}\n\n\tpublic void setBlockIfFull(boolean blockIfFull) {\n\t\tthis.blockIfFull = blockIfFull;\n\t}\n\n\tpublic Duration getBlockIfFullTimeout() {\n\t\treturn this.blockIfFullTimeout;\n\t}\n\n\tpublic void setBlockIfFullTimeout(Duration blockIfFullTimeout) {\n\t\tthis.blockIfFullTimeout = blockIfFullTimeout;\n\t}\n\n\tpublic Duration getIdleTimeout() {\n\t\treturn this.idleTimeout;\n\t}\n\n\tpublic void setIdleTimeout(Duration idleTimeout) {\n\t\tthis.idleTimeout = idleTimeout;\n\t}\n\n\tpublic int getMaxConnections() {\n\t\treturn this.maxConnections;\n\t}\n\n\tpublic void setMaxConnections(int maxConnections) {\n\t\tthis.maxConnections = maxConnections;\n\t}\n\n\tpublic int getMaxSessionsPerConnection() {\n\t\treturn this.maxSessionsPerConnection;\n\t}\n\n\tpublic void setMaxSessionsPerConnection(int maxSessionsPerConnection) {\n\t\tthis.maxSessionsPerConnection = maxSessionsPerConnection;\n\t}\n\n\tpublic Duration getTimeBetweenExpirationCheck() {\n\t\treturn this.timeBetweenExpirationCheck;\n\t}\n\n\tpublic void setTimeBetweenExpirationCheck(Duration timeBetweenExpirationCheck) {\n\t\tthis.timeBetweenExpirationCheck = timeBetweenExpirationCheck;\n\t}\n\n\tpublic boolean isUseAnonymousProducers() {\n\t\treturn this.useAnonymousProducers;\n\t}\n\n\tpublic void setUseAnonymousProducers(boolean useAnonymousProducers) {\n\t\tthis.useAnonymousProducers = useAnonymousProducers;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JmsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for JMS.\n *\n * @author Greg Turnquist\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Lasse Wulff\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jms\")\npublic class JmsProperties {\n\n\t/**\n\t * Whether the default destination type is topic.\n\t */\n\tprivate boolean pubSubDomain;\n\n\t/**\n\t * Connection factory JNDI name. When set, takes precedence to others connection\n\t * factory auto-configurations.\n\t */\n\tprivate @Nullable String jndiName;\n\n\t/**\n\t * Whether the subscription is durable.\n\t */\n\tprivate boolean subscriptionDurable;\n\n\t/**\n\t * Client id of the connection.\n\t */\n\tprivate @Nullable String clientId;\n\n\tprivate final Cache cache = new Cache();\n\n\tprivate final Listener listener = new Listener();\n\n\tprivate final Template template = new Template();\n\n\tpublic boolean isPubSubDomain() {\n\t\treturn this.pubSubDomain;\n\t}\n\n\tpublic void setPubSubDomain(boolean pubSubDomain) {\n\t\tthis.pubSubDomain = pubSubDomain;\n\t}\n\n\tpublic boolean isSubscriptionDurable() {\n\t\treturn this.subscriptionDurable;\n\t}\n\n\tpublic void setSubscriptionDurable(boolean subscriptionDurable) {\n\t\tthis.subscriptionDurable = subscriptionDurable;\n\t}\n\n\tpublic @Nullable String getClientId() {\n\t\treturn this.clientId;\n\t}\n\n\tpublic void setClientId(@Nullable String clientId) {\n\t\tthis.clientId = clientId;\n\t}\n\n\tpublic @Nullable String getJndiName() {\n\t\treturn this.jndiName;\n\t}\n\n\tpublic void setJndiName(@Nullable String jndiName) {\n\t\tthis.jndiName = jndiName;\n\t}\n\n\tpublic Cache getCache() {\n\t\treturn this.cache;\n\t}\n\n\tpublic Listener getListener() {\n\t\treturn this.listener;\n\t}\n\n\tpublic Template getTemplate() {\n\t\treturn this.template;\n\t}\n\n\tpublic static class Cache {\n\n\t\t/**\n\t\t * Whether to cache sessions.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\t/**\n\t\t * Whether to cache message consumers.\n\t\t */\n\t\tprivate boolean consumers;\n\n\t\t/**\n\t\t * Whether to cache message producers.\n\t\t */\n\t\tprivate boolean producers = true;\n\n\t\t/**\n\t\t * Size of the session cache (per JMS Session type).\n\t\t */\n\t\tprivate int sessionCacheSize = 1;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic boolean isConsumers() {\n\t\t\treturn this.consumers;\n\t\t}\n\n\t\tpublic void setConsumers(boolean consumers) {\n\t\t\tthis.consumers = consumers;\n\t\t}\n\n\t\tpublic boolean isProducers() {\n\t\t\treturn this.producers;\n\t\t}\n\n\t\tpublic void setProducers(boolean producers) {\n\t\t\tthis.producers = producers;\n\t\t}\n\n\t\tpublic int getSessionCacheSize() {\n\t\t\treturn this.sessionCacheSize;\n\t\t}\n\n\t\tpublic void setSessionCacheSize(int sessionCacheSize) {\n\t\t\tthis.sessionCacheSize = sessionCacheSize;\n\t\t}\n\n\t}\n\n\tpublic static class Listener {\n\n\t\t/**\n\t\t * Start the container automatically on startup.\n\t\t */\n\t\tprivate boolean autoStartup = true;\n\n\t\t/**\n\t\t * Minimum number of concurrent consumers. When max-concurrency is not specified\n\t\t * the minimum will also be used as the maximum.\n\t\t */\n\t\tprivate @Nullable Integer minConcurrency;\n\n\t\t/**\n\t\t * Maximum number of concurrent consumers.\n\t\t */\n\t\tprivate @Nullable Integer maxConcurrency;\n\n\t\t/**\n\t\t * Timeout to use for receive calls. Use -1 for a no-wait receive or 0 for no\n\t\t * timeout at all. The latter is only feasible if not running within a transaction\n\t\t * manager and is generally discouraged since it prevents clean shutdown.\n\t\t */\n\t\tprivate Duration receiveTimeout = Duration.ofSeconds(1);\n\n\t\t/**\n\t\t * Maximum number of messages to process in one task. By default, unlimited unless\n\t\t * a SchedulingTaskExecutor is configured on the listener (10 messages), as it\n\t\t * indicates a preference for short-lived tasks.\n\t\t */\n\t\tprivate @Nullable Integer maxMessagesPerTask;\n\n\t\tprivate final Session session = new Session();\n\n\t\tpublic boolean isAutoStartup() {\n\t\t\treturn this.autoStartup;\n\t\t}\n\n\t\tpublic void setAutoStartup(boolean autoStartup) {\n\t\t\tthis.autoStartup = autoStartup;\n\t\t}\n\n\t\tpublic @Nullable Integer getMinConcurrency() {\n\t\t\treturn this.minConcurrency;\n\t\t}\n\n\t\tpublic void setMinConcurrency(@Nullable Integer minConcurrency) {\n\t\t\tthis.minConcurrency = minConcurrency;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxConcurrency() {\n\t\t\treturn this.maxConcurrency;\n\t\t}\n\n\t\tpublic void setMaxConcurrency(@Nullable Integer maxConcurrency) {\n\t\t\tthis.maxConcurrency = maxConcurrency;\n\t\t}\n\n\t\tpublic @Nullable String formatConcurrency() {\n\t\t\tif (this.minConcurrency == null) {\n\t\t\t\treturn (this.maxConcurrency != null) ? \"1-\" + this.maxConcurrency : null;\n\t\t\t}\n\t\t\treturn this.minConcurrency + \"-\"\n\t\t\t\t\t+ ((this.maxConcurrency != null) ? this.maxConcurrency : this.minConcurrency);\n\t\t}\n\n\t\tpublic Duration getReceiveTimeout() {\n\t\t\treturn this.receiveTimeout;\n\t\t}\n\n\t\tpublic void setReceiveTimeout(Duration receiveTimeout) {\n\t\t\tthis.receiveTimeout = receiveTimeout;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxMessagesPerTask() {\n\t\t\treturn this.maxMessagesPerTask;\n\t\t}\n\n\t\tpublic void setMaxMessagesPerTask(@Nullable Integer maxMessagesPerTask) {\n\t\t\tthis.maxMessagesPerTask = maxMessagesPerTask;\n\t\t}\n\n\t\tpublic Session getSession() {\n\t\t\treturn this.session;\n\t\t}\n\n\t\tpublic static class Session {\n\n\t\t\t/**\n\t\t\t * Acknowledge mode of the listener container.\n\t\t\t */\n\t\t\tprivate AcknowledgeMode acknowledgeMode = AcknowledgeMode.AUTO;\n\n\t\t\t/**\n\t\t\t * Whether the listener container should use transacted JMS sessions. Defaults\n\t\t\t * to false in the presence of a JtaTransactionManager and true otherwise.\n\t\t\t */\n\t\t\tprivate @Nullable Boolean transacted;\n\n\t\t\tpublic AcknowledgeMode getAcknowledgeMode() {\n\t\t\t\treturn this.acknowledgeMode;\n\t\t\t}\n\n\t\t\tpublic void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {\n\t\t\t\tthis.acknowledgeMode = acknowledgeMode;\n\t\t\t}\n\n\t\t\tpublic @Nullable Boolean getTransacted() {\n\t\t\t\treturn this.transacted;\n\t\t\t}\n\n\t\t\tpublic void setTransacted(@Nullable Boolean transacted) {\n\t\t\t\tthis.transacted = transacted;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Template {\n\n\t\t/**\n\t\t * Default destination to use on send and receive operations that do not have a\n\t\t * destination parameter.\n\t\t */\n\t\tprivate @Nullable String defaultDestination;\n\n\t\t/**\n\t\t * Delivery delay to use for send calls.\n\t\t */\n\t\tprivate @Nullable Duration deliveryDelay;\n\n\t\t/**\n\t\t * Delivery mode. Enables QoS (Quality of Service) when set.\n\t\t */\n\t\tprivate @Nullable DeliveryMode deliveryMode;\n\n\t\t/**\n\t\t * Priority of a message when sending. Enables QoS (Quality of Service) when set.\n\t\t */\n\t\tprivate @Nullable Integer priority;\n\n\t\t/**\n\t\t * Time-to-live of a message when sending. Enables QoS (Quality of Service) when\n\t\t * set.\n\t\t */\n\t\tprivate @Nullable Duration timeToLive;\n\n\t\t/**\n\t\t * Whether to enable explicit QoS (Quality of Service) when sending a message.\n\t\t * When enabled, the delivery mode, priority and time-to-live properties will be\n\t\t * used when sending a message. QoS is automatically enabled when at least one of\n\t\t * those settings is customized.\n\t\t */\n\t\tprivate @Nullable Boolean qosEnabled;\n\n\t\t/**\n\t\t * Timeout to use for receive calls.\n\t\t */\n\t\tprivate @Nullable Duration receiveTimeout;\n\n\t\tprivate final Session session = new Session();\n\n\t\tpublic @Nullable String getDefaultDestination() {\n\t\t\treturn this.defaultDestination;\n\t\t}\n\n\t\tpublic void setDefaultDestination(@Nullable String defaultDestination) {\n\t\t\tthis.defaultDestination = defaultDestination;\n\t\t}\n\n\t\tpublic @Nullable Duration getDeliveryDelay() {\n\t\t\treturn this.deliveryDelay;\n\t\t}\n\n\t\tpublic void setDeliveryDelay(@Nullable Duration deliveryDelay) {\n\t\t\tthis.deliveryDelay = deliveryDelay;\n\t\t}\n\n\t\tpublic @Nullable DeliveryMode getDeliveryMode() {\n\t\t\treturn this.deliveryMode;\n\t\t}\n\n\t\tpublic void setDeliveryMode(@Nullable DeliveryMode deliveryMode) {\n\t\t\tthis.deliveryMode = deliveryMode;\n\t\t}\n\n\t\tpublic @Nullable Integer getPriority() {\n\t\t\treturn this.priority;\n\t\t}\n\n\t\tpublic void setPriority(@Nullable Integer priority) {\n\t\t\tthis.priority = priority;\n\t\t}\n\n\t\tpublic @Nullable Duration getTimeToLive() {\n\t\t\treturn this.timeToLive;\n\t\t}\n\n\t\tpublic void setTimeToLive(@Nullable Duration timeToLive) {\n\t\t\tthis.timeToLive = timeToLive;\n\t\t}\n\n\t\tpublic boolean determineQosEnabled() {\n\t\t\tif (this.qosEnabled != null) {\n\t\t\t\treturn this.qosEnabled;\n\t\t\t}\n\t\t\treturn (getDeliveryMode() != null || getPriority() != null || getTimeToLive() != null);\n\t\t}\n\n\t\tpublic @Nullable Boolean getQosEnabled() {\n\t\t\treturn this.qosEnabled;\n\t\t}\n\n\t\tpublic void setQosEnabled(@Nullable Boolean qosEnabled) {\n\t\t\tthis.qosEnabled = qosEnabled;\n\t\t}\n\n\t\tpublic @Nullable Duration getReceiveTimeout() {\n\t\t\treturn this.receiveTimeout;\n\t\t}\n\n\t\tpublic void setReceiveTimeout(@Nullable Duration receiveTimeout) {\n\t\t\tthis.receiveTimeout = receiveTimeout;\n\t\t}\n\n\t\tpublic Session getSession() {\n\t\t\treturn this.session;\n\t\t}\n\n\t\tpublic static class Session {\n\n\t\t\t/**\n\t\t\t * Acknowledge mode used when creating sessions.\n\t\t\t */\n\t\t\tprivate AcknowledgeMode acknowledgeMode = AcknowledgeMode.AUTO;\n\n\t\t\t/**\n\t\t\t * Whether to use transacted sessions.\n\t\t\t */\n\t\t\tprivate boolean transacted;\n\n\t\t\tpublic AcknowledgeMode getAcknowledgeMode() {\n\t\t\t\treturn this.acknowledgeMode;\n\t\t\t}\n\n\t\t\tpublic void setAcknowledgeMode(AcknowledgeMode acknowledgeMode) {\n\t\t\t\tthis.acknowledgeMode = acknowledgeMode;\n\t\t\t}\n\n\t\t\tpublic boolean isTransacted() {\n\t\t\t\treturn this.transacted;\n\t\t\t}\n\n\t\t\tpublic void setTransacted(boolean transacted) {\n\t\t\t\tthis.transacted = transacted;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic enum DeliveryMode {\n\n\t\t/**\n\t\t * Does not require that the message be logged to stable storage. This is the\n\t\t * lowest-overhead delivery mode but can lead to lost of message if the broker\n\t\t * goes down.\n\t\t */\n\t\tNON_PERSISTENT(1),\n\n\t\t/*\n\t\t * Instructs the JMS provider to log the message to stable storage as part of the\n\t\t * client's send operation.\n\t\t */\n\t\tPERSISTENT(2);\n\n\t\tprivate final int value;\n\n\t\tDeliveryMode(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/JndiConnectionFactoryAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.util.Arrays;\n\nimport javax.naming.NamingException;\n\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jms.autoconfigure.JndiConnectionFactoryAutoConfiguration.JndiOrPropertyCondition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.jms.core.JmsTemplate;\nimport org.springframework.jndi.JndiLocatorDelegate;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for JMS provided from JNDI.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(before = JmsAutoConfiguration.class)\n@ConditionalOnClass(JmsTemplate.class)\n@ConditionalOnMissingBean(ConnectionFactory.class)\n@Conditional(JndiOrPropertyCondition.class)\n@EnableConfigurationProperties(JmsProperties.class)\npublic final class JndiConnectionFactoryAutoConfiguration {\n\n\t// Keep these in sync with the condition below\n\tprivate static final String[] JNDI_LOCATIONS = { \"java:/JmsXA\", \"java:/XAConnectionFactory\" };\n\n\t@Bean\n\tConnectionFactory jmsConnectionFactory(JmsProperties properties) throws NamingException {\n\t\tJndiLocatorDelegate jndiLocatorDelegate = JndiLocatorDelegate.createDefaultResourceRefLocator();\n\t\tif (StringUtils.hasLength(properties.getJndiName())) {\n\t\t\treturn jndiLocatorDelegate.lookup(properties.getJndiName(), ConnectionFactory.class);\n\t\t}\n\t\treturn findJndiConnectionFactory(jndiLocatorDelegate);\n\t}\n\n\tprivate ConnectionFactory findJndiConnectionFactory(JndiLocatorDelegate jndiLocatorDelegate) {\n\t\tfor (String name : JNDI_LOCATIONS) {\n\t\t\ttry {\n\t\t\t\treturn jndiLocatorDelegate.lookup(name, ConnectionFactory.class);\n\t\t\t}\n\t\t\tcatch (NamingException ex) {\n\t\t\t\t// Swallow and continue\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Unable to find ConnectionFactory in JNDI locations \" + Arrays.asList(JNDI_LOCATIONS));\n\t}\n\n\t/**\n\t * Condition for JNDI name or a specific property.\n\t */\n\tstatic class JndiOrPropertyCondition extends AnyNestedCondition {\n\n\t\tJndiOrPropertyCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnJndi({ \"java:/JmsXA\", \"java:/XAConnectionFactory\" })\n\t\tstatic class Jndi {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.jms.jndi-name\")\n\t\tstatic class Property {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/SimpleJmsListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport org.springframework.jms.config.SimpleJmsListenerContainerFactory;\nimport org.springframework.jms.listener.DefaultMessageListenerContainer;\nimport org.springframework.jms.listener.SimpleMessageListenerContainer;\n\n/**\n * Configure {@link SimpleJmsListenerContainerFactory} with sensible defaults. In contrast\n * to {@link DefaultMessageListenerContainer} that uses a pull-based mechanism (polling)\n * to process messages, the {@link SimpleMessageListenerContainer} instances created by\n * this factory use a push-based mechanism that's very close to the spirit of the\n * standalone JMS specification.\n * <p>\n * As such, concurrency-related configuration properties from the {@code spring.jms}\n * namespace are not taken into account by this implementation.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code SimpleJmsListenerContainerFactory} whose configuration is based upon that\n * produced by auto-configuration.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see DefaultJmsListenerContainerFactoryConfigurer\n */\npublic final class SimpleJmsListenerContainerFactoryConfigurer\n\t\textends AbstractJmsListenerContainerFactoryConfigurer<SimpleJmsListenerContainerFactory> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/health/JmsHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure.health;\n\nimport jakarta.jms.ConnectionFactory;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration;\nimport org.springframework.boot.jms.health.JmsHealthIndicator;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link JmsHealthIndicator}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = JmsAutoConfiguration.class)\n@ConditionalOnClass({ ConnectionFactory.class, JmsHealthIndicator.class })\n@ConditionalOnBean(ConnectionFactory.class)\n@ConditionalOnEnabledHealthIndicator(\"jms\")\npublic final class JmsHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<JmsHealthIndicator, ConnectionFactory> {\n\n\tJmsHealthContributorAutoConfiguration() {\n\t\tsuper(JmsHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"jmsHealthIndicator\", \"jmsHealthContributor\" })\n\tHealthContributor jmsHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, ConnectionFactory.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JMS health.\n */\n@NullMarked\npackage org.springframework.boot.jms.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JMS.\n */\n@NullMarked\npackage org.springframework.boot.jms.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/health/JmsHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.health;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport jakarta.jms.Connection;\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.JMSException;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\n\n/**\n * {@link HealthIndicator} for a JMS {@link ConnectionFactory}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class JmsHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final Log logger = LogFactory.getLog(JmsHealthIndicator.class);\n\n\tprivate final ConnectionFactory connectionFactory;\n\n\tpublic JmsHealthIndicator(ConnectionFactory connectionFactory) {\n\t\tsuper(\"JMS health check failed\");\n\t\tthis.connectionFactory = connectionFactory;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\ttry (Connection connection = this.connectionFactory.createConnection()) {\n\t\t\tnew MonitoredConnection(connection).start();\n\t\t\tbuilder.up().withDetail(\"provider\", connection.getMetaData().getJMSProviderName());\n\t\t}\n\t}\n\n\tprivate final class MonitoredConnection {\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate final Connection connection;\n\n\t\tMonitoredConnection(Connection connection) {\n\t\t\tthis.connection = connection;\n\t\t}\n\n\t\tvoid start() throws JMSException {\n\t\t\tnew Thread(() -> {\n\t\t\t\ttry {\n\t\t\t\t\tif (!this.latch.await(5, TimeUnit.SECONDS)) {\n\t\t\t\t\t\tJmsHealthIndicator.this.logger\n\t\t\t\t\t\t\t.warn(\"Connection failed to start within 5 seconds and will be closed.\");\n\t\t\t\t\t\tcloseConnection();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\t}\n\t\t\t}, \"jms-health-indicator\").start();\n\t\t\tthis.connection.start();\n\t\t\tthis.latch.countDown();\n\t\t}\n\n\t\tprivate void closeConnection() {\n\t\t\ttry {\n\t\t\t\tthis.connection.close();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Continue\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for JMS.\n */\n@NullMarked\npackage org.springframework.boot.jms.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/java/org/springframework/boot/jms/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Java Message Service (JMS).\n */\n@NullMarked\npackage org.springframework.boot.jms;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.jms.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JMS health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.jms.listener.acknowledge-mode\",\n      \"deprecation\": {\n        \"replacement\": \"spring.jms.listener.session.acknowledge-mode\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.jms.listener.concurrency\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.jms.listener.min-concurrency\",\n        \"since\": \"3.2.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.jms.listener.session.acknowledge-mode\",\n      \"values\": [\n        {\n          \"value\": \"auto\",\n          \"description\": \"Messages sent or received from the session are automatically acknowledged. This is the simplest mode and enables once-only message delivery guarantee.\"\n        },\n        {\n          \"value\": \"client\",\n          \"description\": \"Messages are acknowledged once the message listener implementation has called \\\"jakarta.jms.Message#acknowledge()\\\". This mode gives the application (rather than the JMS provider) complete control over message acknowledgement.\"\n        },\n        {\n          \"value\": \"dups_ok\",\n          \"description\": \"Similar to auto acknowledgment except that said acknowledgment is lazy. As a consequence, the messages might be delivered more than once. This mode enables at-least-once message delivery guarantee.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.jms.template.session.acknowledge-mode\",\n      \"values\": [\n        {\n          \"value\": \"auto\",\n          \"description\": \"Messages sent or received from the session are automatically acknowledged. This is the simplest mode and enables once-only message delivery guarantee.\"\n        },\n        {\n          \"value\": \"client\",\n          \"description\": \"Messages are acknowledged once the message listener implementation has called \\\"jakarta.jms.Message#acknowledge()\\\". This mode gives the application (rather than the JMS provider) complete control over message acknowledgement.\"\n        },\n        {\n          \"value\": \"dups_ok\",\n          \"description\": \"Similar to auto acknowledgment except that said acknowledgment is lazy. As a consequence, the messages might be delivered more than once. This mode enables at-least-once message delivery guarantee.\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jms.autoconfigure.JmsAutoConfiguration\norg.springframework.boot.jms.autoconfigure.JndiConnectionFactoryAutoConfiguration\norg.springframework.boot.jms.autoconfigure.health.JmsHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/ConnectionFactoryUnwrapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.messaginghub.pooled.jms.JmsPoolConnectionFactory;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.jms.connection.CachingConnectionFactory;\nimport org.springframework.jms.connection.SingleConnectionFactory;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionFactoryUnwrapper}.\n *\n * @author Stephane Nicoll\n */\nclass ConnectionFactoryUnwrapperTests {\n\n\t@Nested\n\tclass UnwrapCaching {\n\n\t\t@Test\n\t\tvoid unwrapWithSingleConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = new SingleConnectionFactory();\n\t\t\tassertThat(unwrapCaching(connectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tassertThat(unwrapCaching(connectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithCachingConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tassertThat(unwrapCaching(new CachingConnectionFactory(connectionFactory))).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithNestedCachingConnectionFactories() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tCachingConnectionFactory firstCachingConnectionFactory = new CachingConnectionFactory(connectionFactory);\n\t\t\tCachingConnectionFactory secondCachingConnectionFactory = new CachingConnectionFactory(\n\t\t\t\t\tfirstCachingConnectionFactory);\n\t\t\tassertThat(unwrapCaching(secondCachingConnectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithJmsPoolConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tJmsPoolConnectionFactory poolConnectionFactory = new JmsPoolConnectionFactory();\n\t\t\tpoolConnectionFactory.setConnectionFactory(connectionFactory);\n\t\t\tassertThat(unwrapCaching(poolConnectionFactory)).isSameAs(poolConnectionFactory);\n\t\t}\n\n\t\tprivate ConnectionFactory unwrapCaching(ConnectionFactory connectionFactory) {\n\t\t\treturn ConnectionFactoryUnwrapper.unwrapCaching(connectionFactory);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass Unwrap {\n\n\t\t@Test\n\t\tvoid unwrapWithSingleConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = new SingleConnectionFactory();\n\t\t\tassertThat(unwrap(connectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tassertThat(unwrap(connectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithCachingConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tassertThat(unwrap(new CachingConnectionFactory(connectionFactory))).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithNestedCachingConnectionFactories() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tCachingConnectionFactory firstCachingConnectionFactory = new CachingConnectionFactory(connectionFactory);\n\t\t\tCachingConnectionFactory secondCachingConnectionFactory = new CachingConnectionFactory(\n\t\t\t\t\tfirstCachingConnectionFactory);\n\t\t\tassertThat(unwrap(secondCachingConnectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithJmsPoolConnectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tJmsPoolConnectionFactory poolConnectionFactory = new JmsPoolConnectionFactory();\n\t\t\tpoolConnectionFactory.setConnectionFactory(connectionFactory);\n\t\t\tassertThat(unwrap(poolConnectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\tvoid unwrapWithNestedJmsPoolConnectionFactories() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tJmsPoolConnectionFactory firstPooledConnectionFactory = new JmsPoolConnectionFactory();\n\t\t\tfirstPooledConnectionFactory.setConnectionFactory(connectionFactory);\n\t\t\tJmsPoolConnectionFactory secondPooledConnectionFactory = new JmsPoolConnectionFactory();\n\t\t\tsecondPooledConnectionFactory.setConnectionFactory(firstPooledConnectionFactory);\n\t\t\tassertThat(unwrap(secondPooledConnectionFactory)).isSameAs(connectionFactory);\n\t\t}\n\n\t\t@Test\n\t\t@ClassPathExclusions(\"pooled-jms-*\")\n\t\tvoid unwrapWithoutJmsPoolOnClasspath() {\n\t\t\tassertThat(ClassUtils.isPresent(\"org.messaginghub.pooled.jms.JmsPoolConnectionFactory\", null)).isFalse();\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tassertThat(unwrap(new CachingConnectionFactory(connectionFactory))).isSameAs(connectionFactory);\n\t\t}\n\n\t\tprivate ConnectionFactory unwrap(ConnectionFactory connectionFactory) {\n\t\t\tConnectionFactory unwrapped = ConnectionFactoryUnwrapper.unwrap(connectionFactory);\n\t\t\tassertThat(unwrapped).isNotNull();\n\t\t\treturn unwrapped;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/autoconfigure/AcknowledgeModeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport jakarta.jms.Session;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link AcknowledgeMode}.\n *\n * @author Andy Wilkinson\n */\nclass AcknowledgeModeTests {\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid stringIsMappedToInt(Mapping mapping) {\n\t\tassertThat(AcknowledgeMode.of(mapping.actual)).extracting(AcknowledgeMode::getMode).isEqualTo(mapping.expected);\n\t}\n\n\t@Test\n\tvoid mapShouldThrowWhenMapIsCalledWithUnknownNonIntegerString() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> AcknowledgeMode.of(\"some-string\"))\n\t\t\t.withMessage(\n\t\t\t\t\t\"'some-string' is neither a known acknowledge mode (auto, client, or dups_ok) nor an integer value\");\n\t}\n\n\tprivate enum Mapping {\n\n\t\tAUTO_LOWER_CASE(\"auto\", Session.AUTO_ACKNOWLEDGE),\n\n\t\tCLIENT_LOWER_CASE(\"client\", Session.CLIENT_ACKNOWLEDGE),\n\n\t\tDUPS_OK_LOWER_CASE(\"dups_ok\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tAUTO_UPPER_CASE(\"AUTO\", Session.AUTO_ACKNOWLEDGE),\n\n\t\tCLIENT_UPPER_CASE(\"CLIENT\", Session.CLIENT_ACKNOWLEDGE),\n\n\t\tDUPS_OK_UPPER_CASE(\"DUPS_OK\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tAUTO_MIXED_CASE(\"AuTo\", Session.AUTO_ACKNOWLEDGE),\n\n\t\tCLIENT_MIXED_CASE(\"CliEnT\", Session.CLIENT_ACKNOWLEDGE),\n\n\t\tDUPS_OK_MIXED_CASE(\"dUPs_Ok\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tDUPS_OK_KEBAB_CASE(\"DUPS-OK\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tDUPS_OK_NO_SEPARATOR_UPPER_CASE(\"DUPSOK\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tDUPS_OK_NO_SEPARATOR_LOWER_CASE(\"dupsok\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tDUPS_OK_NO_SEPARATOR_MIXED_CASE(\"duPSok\", Session.DUPS_OK_ACKNOWLEDGE),\n\n\t\tINTEGER(\"36\", 36);\n\n\t\tprivate final String actual;\n\n\t\tprivate final int expected;\n\n\t\tMapping(String actual, int expected) {\n\t\t\tthis.actual = actual;\n\t\t\tthis.expected = expected;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/autoconfigure/JmsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.ExceptionListener;\nimport jakarta.jms.Session;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jms.annotation.EnableJms;\nimport org.springframework.jms.config.DefaultJmsListenerContainerFactory;\nimport org.springframework.jms.config.JmsListenerConfigUtils;\nimport org.springframework.jms.config.JmsListenerContainerFactory;\nimport org.springframework.jms.config.JmsListenerEndpoint;\nimport org.springframework.jms.config.SimpleJmsListenerContainerFactory;\nimport org.springframework.jms.config.SimpleJmsListenerEndpoint;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.jms.core.JmsMessagingTemplate;\nimport org.springframework.jms.core.JmsTemplate;\nimport org.springframework.jms.listener.DefaultMessageListenerContainer;\nimport org.springframework.jms.listener.SimpleMessageListenerContainer;\nimport org.springframework.jms.support.converter.MessageConverter;\nimport org.springframework.jms.support.destination.DestinationResolver;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JmsAutoConfiguration}.\n *\n * @author Greg Turnquist\n * @author Stephane Nicoll\n * @author Aurélien Leboulanger\n * @author Eddú Meléndez\n * @author Vedran Pavic\n * @author Lasse Wulff\n */\nclass JmsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(ConnectionFactory.class, () -> mock(ConnectionFactory.class))\n\t\t.withConfiguration(AutoConfigurations.of(JmsAutoConfiguration.class));\n\n\t@Test\n\tvoid testNoConnectionFactoryJmsConfiguration() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(JmsAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JmsTemplate.class)\n\t\t\t\t.doesNotHaveBean(JmsMessagingTemplate.class)\n\t\t\t\t.doesNotHaveBean(JmsClient.class)\n\t\t\t\t.doesNotHaveBean(DefaultJmsListenerContainerFactoryConfigurer.class)\n\t\t\t\t.doesNotHaveBean(SimpleJmsListenerContainerFactoryConfigurer.class)\n\t\t\t\t.doesNotHaveBean(DefaultJmsListenerContainerFactory.class));\n\t}\n\n\t@Test\n\tvoid testDefaultJmsConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\tassertThat(context).hasSingleBean(JmsTemplate.class)\n\t\t\t\t.hasSingleBean(JmsMessagingTemplate.class)\n\t\t\t\t.hasSingleBean(JmsClient.class);\n\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\tassertThat(jmsTemplate.getConnectionFactory()).isEqualTo(connectionFactory);\n\t\t\tassertThat(context.getBean(JmsMessagingTemplate.class).getJmsTemplate()).isEqualTo(jmsTemplate);\n\t\t\tassertThat(context.getBean(JmsClient.class)).hasFieldOrPropertyWithValue(\"jmsTemplate\", jmsTemplate);\n\t\t\tassertThat(context.containsBean(\"jmsListenerContainerFactory\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsTemplateBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration3.class)\n\t\t\t.run((context) -> assertThat(context.getBean(JmsTemplate.class).getPriority()).isEqualTo(999));\n\t}\n\n\t@Test\n\tvoid testJmsMessagingTemplateBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration5.class)\n\t\t\t.run((context) -> assertThat(context.getBean(JmsMessagingTemplate.class).getDefaultDestinationName())\n\t\t\t\t.isEqualTo(\"fooBar\"));\n\t}\n\n\t@Test\n\tvoid testJmsClientBackOff() {\n\t\tJmsClient userJmsClient = mock(JmsClient.class);\n\t\tthis.contextRunner.withBean(\"userJmsClient\", JmsClient.class, () -> userJmsClient)\n\t\t\t.run((context) -> assertThat(context.getBean(JmsClient.class)).isEqualTo(userJmsClient));\n\t}\n\n\t@Test\n\tvoid testDefaultJmsListenerConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((loaded) -> {\n\t\t\tConnectionFactory connectionFactory = loaded.getBean(ConnectionFactory.class);\n\t\t\tassertThat(loaded).hasSingleBean(DefaultJmsListenerContainerFactory.class);\n\t\t\tDefaultJmsListenerContainerFactory containerFactory = loaded\n\t\t\t\t.getBean(DefaultJmsListenerContainerFactory.class);\n\t\t\tSimpleJmsListenerEndpoint jmsListenerEndpoint = new SimpleJmsListenerEndpoint();\n\t\t\tjmsListenerEndpoint.setMessageListener((message) -> {\n\t\t\t});\n\t\t\tDefaultMessageListenerContainer container = containerFactory.createListenerContainer(jmsListenerEndpoint);\n\t\t\tassertThat(container.getClientId()).isNull();\n\t\t\tassertThat(container.getConcurrentConsumers()).isEqualTo(1);\n\t\t\tassertThat(container.getConnectionFactory()).isSameAs(connectionFactory);\n\t\t\tassertThat(container.getMaxConcurrentConsumers()).isEqualTo(1);\n\t\t\tassertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.AUTO_ACKNOWLEDGE);\n\t\t\tassertThat(container.isAutoStartup()).isTrue();\n\t\t\tassertThat(container.isPubSubDomain()).isFalse();\n\t\t\tassertThat(container.isSubscriptionDurable()).isFalse();\n\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"receiveTimeout\", 1000L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testEnableJmsCreateDefaultContainerFactory() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.getBean(\"jmsListenerContainerFactory\", JmsListenerContainerFactory.class)\n\t\t\t\t.isExactlyInstanceOf(DefaultJmsListenerContainerFactory.class));\n\t}\n\n\t@Test\n\tvoid testJmsListenerContainerFactoryBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration6.class, EnableJmsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.getBean(\"jmsListenerContainerFactory\", JmsListenerContainerFactory.class)\n\t\t\t\t.isExactlyInstanceOf(SimpleJmsListenerContainerFactory.class));\n\t}\n\n\t@Test\n\tvoid jmsListenerContainerFactoryWhenMultipleConnectionFactoryBeansShouldBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration10.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JmsListenerContainerFactory.class));\n\t}\n\n\t@Test\n\tvoid testJmsListenerContainerFactoryWithCustomSettings() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.listener.autoStartup=false\",\n\t\t\t\t\t\"spring.jms.listener.session.acknowledgeMode=client\",\n\t\t\t\t\t\"spring.jms.listener.session.transacted=false\", \"spring.jms.listener.minConcurrency=2\",\n\t\t\t\t\t\"spring.jms.listener.receiveTimeout=2s\", \"spring.jms.listener.maxConcurrency=10\",\n\t\t\t\t\t\"spring.jms.subscription-durable=true\", \"spring.jms.client-id=exampleId\",\n\t\t\t\t\t\"spring.jms.listener.max-messages-per-task=5\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.isAutoStartup()).isFalse();\n\t\t\t\tassertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);\n\t\t\t\tassertThat(container.isSessionTransacted()).isFalse();\n\t\t\t\tassertThat(container.getConcurrentConsumers()).isEqualTo(2);\n\t\t\t\tassertThat(container.getMaxConcurrentConsumers()).isEqualTo(10);\n\t\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"receiveTimeout\", 2000L);\n\t\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"maxMessagesPerTask\", 5);\n\t\t\t\tassertThat(container.isSubscriptionDurable()).isTrue();\n\t\t\t\tassertThat(container.getClientId()).isEqualTo(\"exampleId\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testManualJmsListenerContainerFactoryWithCustomSettings() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration6.class, EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.listener.autoStartup=false\",\n\t\t\t\t\t\"spring.jms.listener.session.acknowledgeMode=client\",\n\t\t\t\t\t\"spring.jms.listener.session.transacted=false\", \"spring.jms.subscription-durable=true\",\n\t\t\t\t\t\"spring.jms.client-id=exampleId\")\n\t\t\t.run((context) -> {\n\t\t\t\tSimpleJmsListenerContainerFactory containerFactory = context.getBean(\"jmsListenerContainerFactory\",\n\t\t\t\t\t\tSimpleJmsListenerContainerFactory.class);\n\t\t\t\tSimpleMessageListenerContainer container = containerFactory\n\t\t\t\t\t.createListenerContainer(mock(JmsListenerEndpoint.class));\n\t\t\t\tassertThat(container.isAutoStartup()).isFalse();\n\t\t\t\tassertThat(container.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);\n\t\t\t\tassertThat(container.isSessionTransacted()).isFalse();\n\t\t\t\tassertThat(container.isSubscriptionDurable()).isTrue();\n\t\t\t\tassertThat(container.getClientId()).isEqualTo(\"exampleId\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsListenerContainerFactoryWithNonStandardAcknowledgeMode() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.listener.session.acknowledge-mode=9\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.getSessionAcknowledgeMode()).isEqualTo(9);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsListenerContainerFactoryWithDefaultSettings() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.run(this::testJmsListenerContainerFactoryWithDefaultSettings);\n\t}\n\n\tprivate void testJmsListenerContainerFactoryWithDefaultSettings(AssertableApplicationContext loaded) {\n\t\tDefaultMessageListenerContainer container = getContainer(loaded, \"jmsListenerContainerFactory\");\n\t\tassertThat(container).hasFieldOrPropertyWithValue(\"receiveTimeout\", 1000L);\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryWithJtaTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration7.class, EnableJmsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.isSessionTransacted()).isFalse();\n\t\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"transactionManager\",\n\t\t\t\t\t\tcontext.getBean(JtaTransactionManager.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryWithJtaTransactionManagerAndSessionTransactedEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration7.class, EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.listener.session.transacted=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.isSessionTransacted()).isTrue();\n\t\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"transactionManager\",\n\t\t\t\t\t\tcontext.getBean(JtaTransactionManager.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryNonJtaTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration8.class, EnableJmsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.isSessionTransacted()).isTrue();\n\t\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"transactionManager\", null);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryNoTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class).run((context) -> {\n\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\tassertThat(container.isSessionTransacted()).isTrue();\n\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"transactionManager\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryNoTransactionManagerAndSessionTransactedDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.listener.session.transacted=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.isSessionTransacted()).isFalse();\n\t\t\t\tassertThat(container).hasFieldOrPropertyWithValue(\"transactionManager\", null);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryWithMessageConverters() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class, EnableJmsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.getMessageConverter()).isSameAs(context.getBean(\"myMessageConverter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryWithExceptionListener() {\n\t\tExceptionListener exceptionListener = mock(ExceptionListener.class);\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withBean(ExceptionListener.class, () -> exceptionListener)\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.getExceptionListener()).isSameAs(exceptionListener);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultContainerFactoryWithObservationRegistry() {\n\t\tObservationRegistry observationRegistry = mock(ObservationRegistry.class);\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withBean(ObservationRegistry.class, () -> observationRegistry)\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"jmsListenerContainerFactory\");\n\t\t\t\tassertThat(container.getObservationRegistry()).isSameAs(observationRegistry);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testCustomContainerFactoryWithConfigurer() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration9.class, EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.listener.autoStartup=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMessageListenerContainer container = getContainer(context, \"customListenerContainerFactory\");\n\t\t\t\tassertThat(container.getCacheLevel()).isEqualTo(DefaultMessageListenerContainer.CACHE_CONSUMER);\n\t\t\t\tassertThat(container.isAutoStartup()).isFalse();\n\t\t\t});\n\t}\n\n\tprivate DefaultMessageListenerContainer getContainer(AssertableApplicationContext loaded, String name) {\n\t\tJmsListenerContainerFactory<?> factory = loaded.getBean(name, JmsListenerContainerFactory.class);\n\t\tassertThat(factory).isInstanceOf(DefaultJmsListenerContainerFactory.class);\n\t\treturn ((DefaultJmsListenerContainerFactory) factory).createListenerContainer(mock(JmsListenerEndpoint.class));\n\t}\n\n\t@Test\n\tvoid testJmsTemplateWithMessageConverter() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class).run((context) -> {\n\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\tassertThat(jmsTemplate.getMessageConverter()).isSameAs(context.getBean(\"myMessageConverter\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsTemplateWithDestinationResolver() {\n\t\tthis.contextRunner.withUserConfiguration(DestinationResolversConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(JmsTemplate.class).getDestinationResolver())\n\t\t\t\t.isSameAs(context.getBean(\"myDestinationResolver\")));\n\t}\n\n\t@Test\n\tvoid testJmsTemplateWithObservationRegistry() {\n\t\tObservationRegistry observationRegistry = mock(ObservationRegistry.class);\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withBean(ObservationRegistry.class, () -> observationRegistry)\n\t\t\t.run((context) -> {\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tassertThat(jmsTemplate).extracting(\"observationRegistry\").isSameAs(observationRegistry);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsTemplateFullCustomization() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConvertersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.template.session.acknowledge-mode=client\",\n\t\t\t\t\t\"spring.jms.template.session.transacted=true\", \"spring.jms.template.default-destination=testQueue\",\n\t\t\t\t\t\"spring.jms.template.delivery-delay=500\", \"spring.jms.template.delivery-mode=non-persistent\",\n\t\t\t\t\t\"spring.jms.template.priority=6\", \"spring.jms.template.time-to-live=6000\",\n\t\t\t\t\t\"spring.jms.template.receive-timeout=2000\")\n\t\t\t.run((context) -> {\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tassertThat(jmsTemplate.getMessageConverter()).isSameAs(context.getBean(\"myMessageConverter\"));\n\t\t\t\tassertThat(jmsTemplate.isPubSubDomain()).isFalse();\n\t\t\t\tassertThat(jmsTemplate.getSessionAcknowledgeMode()).isEqualTo(Session.CLIENT_ACKNOWLEDGE);\n\t\t\t\tassertThat(jmsTemplate.isSessionTransacted()).isTrue();\n\t\t\t\tassertThat(jmsTemplate.getDefaultDestinationName()).isEqualTo(\"testQueue\");\n\t\t\t\tassertThat(jmsTemplate.getDeliveryDelay()).isEqualTo(500);\n\t\t\t\tassertThat(jmsTemplate.getDeliveryMode()).isOne();\n\t\t\t\tassertThat(jmsTemplate.getPriority()).isEqualTo(6);\n\t\t\t\tassertThat(jmsTemplate.getTimeToLive()).isEqualTo(6000);\n\t\t\t\tassertThat(jmsTemplate.isExplicitQosEnabled()).isTrue();\n\t\t\t\tassertThat(jmsTemplate.getReceiveTimeout()).isEqualTo(2000);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsTemplateWithNonStandardAcknowledgeMode() {\n\t\tthis.contextRunner.withUserConfiguration(EnableJmsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.template.session.acknowledge-mode=7\")\n\t\t\t.run((context) -> {\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tassertThat(jmsTemplate.getSessionAcknowledgeMode()).isEqualTo(7);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testJmsMessagingTemplateUseConfiguredDefaultDestination() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jms.template.default-destination=testQueue\").run((context) -> {\n\t\t\tJmsMessagingTemplate messagingTemplate = context.getBean(JmsMessagingTemplate.class);\n\t\t\tassertThat(messagingTemplate.getDefaultDestinationName()).isEqualTo(\"testQueue\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testPubSubDisabledByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(JmsTemplate.class).isPubSubDomain()).isFalse());\n\t}\n\n\t@Test\n\tvoid testJmsTemplatePostProcessedSoThatPubSubIsTrue() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration4.class)\n\t\t\t.run((context) -> assertThat(context.getBean(JmsTemplate.class).isPubSubDomain()).isTrue());\n\t}\n\n\t@Test\n\tvoid testPubSubDomainActive() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.pubSubDomain:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tDefaultMessageListenerContainer defaultMessageListenerContainer = context\n\t\t\t\t\t.getBean(DefaultJmsListenerContainerFactory.class)\n\t\t\t\t\t.createListenerContainer(mock(JmsListenerEndpoint.class));\n\t\t\t\tassertThat(jmsTemplate.isPubSubDomain()).isTrue();\n\t\t\t\tassertThat(defaultMessageListenerContainer.isPubSubDomain()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testPubSubDomainOverride() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jms.pubSubDomain:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JmsTemplate.class);\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tJmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);\n\t\t\t\tConnectionFactory factory = context.getBean(ConnectionFactory.class);\n\t\t\t\tassertThat(jmsTemplate).isNotNull();\n\t\t\t\tassertThat(jmsTemplate.isPubSubDomain()).isFalse();\n\t\t\t\tassertThat(factory).isNotNull().isEqualTo(jmsTemplate.getConnectionFactory());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enableJmsAutomatically() {\n\t\tthis.contextRunner.withUserConfiguration(NoEnableJmsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasBean(JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)\n\t\t\t\t.hasBean(JmsListenerConfigUtils.JMS_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME));\n\t}\n\n\t@Test\n\tvoid runtimeHintsAreRegisteredForBindingOfAcknowledgeMode() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.register(TestConfiguration2.class, JmsAutoConfiguration.class);\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\t\tnew ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(AcknowledgeMode.class, \"of\"))\n\t\t\t\t.accepts(generationContext.getRuntimeHints());\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration2 {\n\n\t\t@Bean\n\t\tConnectionFactory customConnectionFactory() {\n\t\t\treturn mock(ConnectionFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration3 {\n\n\t\t@Bean\n\t\tJmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {\n\t\t\tJmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);\n\t\t\tjmsTemplate.setPriority(999);\n\t\t\treturn jmsTemplate;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration4 implements BeanPostProcessor {\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\tif (bean.getClass().isAssignableFrom(JmsTemplate.class)) {\n\t\t\t\tJmsTemplate jmsTemplate = (JmsTemplate) bean;\n\t\t\t\tjmsTemplate.setPubSubDomain(true);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) {\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration5 {\n\n\t\t@Bean\n\t\tJmsMessagingTemplate jmsMessagingTemplate(JmsTemplate jmsTemplate) {\n\t\t\tJmsMessagingTemplate messagingTemplate = new JmsMessagingTemplate(jmsTemplate);\n\t\t\tmessagingTemplate.setDefaultDestinationName(\"fooBar\");\n\t\t\treturn messagingTemplate;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration6 {\n\n\t\t@Bean\n\t\tJmsListenerContainerFactory<?> jmsListenerContainerFactory(\n\t\t\t\tSimpleJmsListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {\n\t\t\tSimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();\n\t\t\tconfigurer.configure(factory, connectionFactory);\n\t\t\treturn factory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration7 {\n\n\t\t@Bean\n\t\tJtaTransactionManager transactionManager() {\n\t\t\treturn mock(JtaTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration8 {\n\n\t\t@Bean\n\t\tDataSourceTransactionManager transactionManager() {\n\t\t\treturn mock(DataSourceTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MessageConvertersConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tMessageConverter myMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t\t@Bean\n\t\tMessageConverter anotherMessageConverter() {\n\t\t\treturn mock(MessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DestinationResolversConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tDestinationResolver myDestinationResolver() {\n\t\t\treturn mock(DestinationResolver.class);\n\t\t}\n\n\t\t@Bean\n\t\tDestinationResolver anotherDestinationResolver() {\n\t\t\treturn mock(DestinationResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration9 {\n\n\t\t@Bean\n\t\tJmsListenerContainerFactory<?> customListenerContainerFactory(\n\t\t\t\tDefaultJmsListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {\n\t\t\tDefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();\n\t\t\tconfigurer.configure(factory, connectionFactory);\n\t\t\tfactory.setCacheLevel(DefaultMessageListenerContainer.CACHE_CONSUMER);\n\t\t\treturn factory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration10 {\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactory1() {\n\t\t\treturn mock(ConnectionFactory.class);\n\t\t}\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactory2() {\n\t\t\treturn mock(ConnectionFactory.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableJms\n\tstatic class EnableJmsConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NoEnableJmsConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/autoconfigure/JmsPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.jms.listener.AbstractPollingMessageListenerContainer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JmsProperties}.\n *\n * @author Stephane Nicoll\n */\nclass JmsPropertiesTests {\n\n\t@Test\n\tvoid formatConcurrencyNull() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tassertThat(properties.getListener().formatConcurrency()).isNull();\n\t}\n\n\t@Test\n\tvoid formatConcurrencyOnlyLowerBound() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tproperties.getListener().setMinConcurrency(2);\n\t\tassertThat(properties.getListener().formatConcurrency()).isEqualTo(\"2-2\");\n\t}\n\n\t@Test\n\tvoid formatConcurrencyOnlyHigherBound() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tproperties.getListener().setMaxConcurrency(5);\n\t\tassertThat(properties.getListener().formatConcurrency()).isEqualTo(\"1-5\");\n\t}\n\n\t@Test\n\tvoid formatConcurrencyBothBounds() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tproperties.getListener().setMinConcurrency(2);\n\t\tproperties.getListener().setMaxConcurrency(10);\n\t\tassertThat(properties.getListener().formatConcurrency()).isEqualTo(\"2-10\");\n\t}\n\n\t@Test\n\tvoid setDeliveryModeEnablesQoS() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tproperties.getTemplate().setDeliveryMode(JmsProperties.DeliveryMode.PERSISTENT);\n\t\tassertThat(properties.getTemplate().determineQosEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid setPriorityEnablesQoS() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tproperties.getTemplate().setPriority(6);\n\t\tassertThat(properties.getTemplate().determineQosEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid setTimeToLiveEnablesQoS() {\n\t\tJmsProperties properties = new JmsProperties();\n\t\tproperties.getTemplate().setTimeToLive(Duration.ofSeconds(5));\n\t\tassertThat(properties.getTemplate().determineQosEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid defaultReceiveTimeoutMatchesListenerContainersDefault() {\n\t\tassertThat(new JmsProperties().getListener().getReceiveTimeout())\n\t\t\t.hasMillis(AbstractPollingMessageListenerContainer.DEFAULT_RECEIVE_TIMEOUT);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/autoconfigure/JndiConnectionFactoryAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure;\n\nimport javax.naming.Context;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoader;\nimport org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JndiConnectionFactoryAutoConfiguration}.\n * PersistenceExceptionTranslationAutoConfigurationTests\n *\n * @author Stephane Nicoll\n */\nclass JndiConnectionFactoryAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JndiConnectionFactoryAutoConfiguration.class));\n\n\tprivate ClassLoader threadContextClassLoader;\n\n\tprivate String initialContextFactory;\n\n\t@BeforeEach\n\tvoid setupJndi() {\n\t\tthis.initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, TestableInitialContextFactory.class.getName());\n\t\tthis.threadContextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread().setContextClassLoader(new JndiPropertiesHidingClassLoader(getClass().getClassLoader()));\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tTestableInitialContextFactory.clearAll();\n\t\tif (this.initialContextFactory != null) {\n\t\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, this.initialContextFactory);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\t}\n\t\tThread.currentThread().setContextClassLoader(this.threadContextClassLoader);\n\t}\n\n\t@Test\n\tvoid detectNoAvailableCandidates() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactory.class));\n\t}\n\n\t@Test\n\tvoid detectWithJmsXAConnectionFactory() {\n\t\tConnectionFactory connectionFactory = configureConnectionFactory(\"java:/JmsXA\");\n\t\tthis.contextRunner.run(assertConnectionFactory(connectionFactory));\n\t}\n\n\t@Test\n\tvoid detectWithXAConnectionFactory() {\n\t\tConnectionFactory connectionFactory = configureConnectionFactory(\"java:/XAConnectionFactory\");\n\t\tthis.contextRunner.run(assertConnectionFactory(connectionFactory));\n\t}\n\n\t@Test\n\tvoid jndiNamePropertySet() {\n\t\tConnectionFactory connectionFactory = configureConnectionFactory(\"java:comp/env/myCF\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.jms.jndi-name=java:comp/env/myCF\")\n\t\t\t.run(assertConnectionFactory(connectionFactory));\n\t}\n\n\t@Test\n\tvoid jndiNamePropertySetWithResourceRef() {\n\t\tConnectionFactory connectionFactory = configureConnectionFactory(\"java:comp/env/myCF\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.jms.jndi-name=myCF\")\n\t\t\t.run(assertConnectionFactory(connectionFactory));\n\t}\n\n\t@Test\n\tvoid jndiNamePropertySetWithWrongValue() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.jms.jndi-name=doesNotExistCF\").run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"doesNotExistCF\");\n\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertConnectionFactory(ConnectionFactory connectionFactory) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasBean(\"jmsConnectionFactory\");\n\t\t\tassertThat(context.getBean(ConnectionFactory.class)).isSameAs(connectionFactory)\n\t\t\t\t.isSameAs(context.getBean(\"jmsConnectionFactory\"));\n\t\t};\n\t}\n\n\tprivate ConnectionFactory configureConnectionFactory(String name) {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tTestableInitialContextFactory.bind(name, connectionFactory);\n\t\treturn connectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/autoconfigure/health/JmsHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.autoconfigure.health;\n\nimport jakarta.jms.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.jms.health.JmsHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JmsHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass JmsHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmsHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class))\n\t\t.withBean(ConnectionFactory.class, () -> mock(ConnectionFactory.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(JmsHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.jms.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JmsHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jms/src/test/java/org/springframework/boot/jms/health/JmsHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jms.health;\n\nimport jakarta.jms.Connection;\nimport jakarta.jms.ConnectionFactory;\nimport jakarta.jms.ConnectionMetaData;\nimport jakarta.jms.JMSException;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JmsHealthIndicator}.\n *\n * @author Stephane Nicoll\n */\nclass JmsHealthIndicatorTests {\n\n\t@Test\n\tvoid jmsBrokerIsUp() throws JMSException {\n\t\tConnectionMetaData connectionMetaData = mock(ConnectionMetaData.class);\n\t\tgiven(connectionMetaData.getJMSProviderName()).willReturn(\"JMS test provider\");\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.getMetaData()).willReturn(connectionMetaData);\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tgiven(connectionFactory.createConnection()).willReturn(connection);\n\t\tJmsHealthIndicator indicator = new JmsHealthIndicator(connectionFactory);\n\t\tHealth health = indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"provider\", \"JMS test provider\");\n\t\tthen(connection).should().close();\n\t}\n\n\t@Test\n\tvoid jmsBrokerIsDown() throws JMSException {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tgiven(connectionFactory.createConnection()).willThrow(new JMSException(\"test\", \"123\"));\n\t\tJmsHealthIndicator indicator = new JmsHealthIndicator(connectionFactory);\n\t\tHealth health = indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"provider\");\n\t}\n\n\t@Test\n\tvoid jmsBrokerCouldNotRetrieveProviderMetadata() throws JMSException {\n\t\tConnectionMetaData connectionMetaData = mock(ConnectionMetaData.class);\n\t\tgiven(connectionMetaData.getJMSProviderName()).willThrow(new JMSException(\"test\", \"123\"));\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.getMetaData()).willReturn(connectionMetaData);\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tgiven(connectionFactory.createConnection()).willReturn(connection);\n\t\tJmsHealthIndicator indicator = new JmsHealthIndicator(connectionFactory);\n\t\tHealth health = indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"provider\");\n\t\tthen(connection).should().close();\n\t}\n\n\t@Test\n\tvoid jmsBrokerUsesFailover() throws JMSException {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tConnectionMetaData connectionMetaData = mock(ConnectionMetaData.class);\n\t\tgiven(connectionMetaData.getJMSProviderName()).willReturn(\"JMS test provider\");\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.getMetaData()).willReturn(connectionMetaData);\n\t\twillThrow(new JMSException(\"Could not start\", \"123\")).given(connection).start();\n\t\tgiven(connectionFactory.createConnection()).willReturn(connection);\n\t\tJmsHealthIndicator indicator = new JmsHealthIndicator(connectionFactory);\n\t\tHealth health = indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"provider\");\n\t}\n\n\t@Test\n\tvoid whenConnectionStartIsUnresponsiveStatusIsDown() throws JMSException {\n\t\tConnectionMetaData connectionMetaData = mock(ConnectionMetaData.class);\n\t\tgiven(connectionMetaData.getJMSProviderName()).willReturn(\"JMS test provider\");\n\t\tConnection connection = mock(Connection.class);\n\t\tUnresponsiveStartAnswer unresponsiveStartAnswer = new UnresponsiveStartAnswer();\n\t\twillAnswer(unresponsiveStartAnswer).given(connection).start();\n\t\twillAnswer((invocation) -> {\n\t\t\tunresponsiveStartAnswer.connectionClosed();\n\t\t\treturn null;\n\t\t}).given(connection).close();\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tgiven(connectionFactory.createConnection()).willReturn(connection);\n\t\tJmsHealthIndicator indicator = new JmsHealthIndicator(connectionFactory);\n\t\tHealth health = indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat((String) health.getDetails().get(\"error\")).contains(\"Connection closed\");\n\t}\n\n\tprivate static final class UnresponsiveStartAnswer implements Answer<Void> {\n\n\t\tprivate boolean connectionClosed;\n\n\t\tprivate final Object monitor = new Object();\n\n\t\t@Override\n\t\tpublic Void answer(InvocationOnMock invocation) throws Throwable {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\twhile (!this.connectionClosed) {\n\t\t\t\t\tthis.monitor.wait();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new JMSException(\"Connection closed\");\n\t\t}\n\n\t\tprivate void connectionClosed() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.connectionClosed = true;\n\t\t\t\tthis.monitor.notifyAll();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot jOOQ\"\n\nsystemRequirements {\n\tjava {\n\t\tversion = 21\n\t}\n}\n\ndependencies {\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.jooq:jooq\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-r2dbc\"))\n\toptional(\"jakarta.xml.bind:jakarta.xml.bind-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\ttestRuntimeOnly(\"io.r2dbc:r2dbc-h2\")\n\ttestRuntimeOnly(\"org.glassfish.jaxb:jaxb-runtime\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/JooqDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jooq.DSLContext;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\n\n/**\n * {@link DependsOnDatabaseInitializationDetector} for jOOQ.\n *\n * @author Andy Wilkinson\n */\nclass JooqDependsOnDatabaseInitializationDetector extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\treturn Collections.singleton(DSLContext.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/DefaultConfigurationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.jooq.impl.DefaultConfiguration;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link DefaultConfiguration} to fine-tune its auto-configuration.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface DefaultConfigurationCustomizer {\n\n\t/**\n\t * Customize the {@link DefaultConfiguration jOOQ Configuration}.\n\t * @param configuration the configuration to customize\n\t */\n\tvoid customize(DefaultConfiguration configuration);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/DefaultExceptionTranslatorExecuteListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.sql.SQLException;\nimport java.util.function.Function;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jooq.ExecuteContext;\nimport org.jooq.SQLDialect;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;\nimport org.springframework.jdbc.support.SQLExceptionSubclassTranslator;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\nimport org.springframework.util.Assert;\n\n/**\n * Default implementation of {@link ExceptionTranslatorExecuteListener} that delegates to\n * an {@link SQLExceptionTranslator}.\n *\n * @author Lukas Eder\n * @author Andreas Ahlenstorf\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nfinal class DefaultExceptionTranslatorExecuteListener implements ExceptionTranslatorExecuteListener {\n\n\t// Based on the jOOQ-spring-example from https://github.com/jOOQ/jOOQ\n\n\tprivate static final Log defaultLogger = LogFactory.getLog(ExceptionTranslatorExecuteListener.class);\n\n\tprivate final Log logger;\n\n\tprivate Function<ExecuteContext, SQLExceptionTranslator> translatorFactory;\n\n\tDefaultExceptionTranslatorExecuteListener() {\n\t\tthis(defaultLogger, new DefaultTranslatorFactory());\n\t}\n\n\tDefaultExceptionTranslatorExecuteListener(Function<ExecuteContext, SQLExceptionTranslator> translatorFactory) {\n\t\tthis(defaultLogger, translatorFactory);\n\t}\n\n\tDefaultExceptionTranslatorExecuteListener(Log logger) {\n\t\tthis(logger, new DefaultTranslatorFactory());\n\t}\n\n\tprivate DefaultExceptionTranslatorExecuteListener(Log logger,\n\t\t\tFunction<ExecuteContext, SQLExceptionTranslator> translatorFactory) {\n\t\tAssert.notNull(translatorFactory, \"'translatorFactory' must not be null\");\n\t\tthis.logger = logger;\n\t\tthis.translatorFactory = translatorFactory;\n\t}\n\n\t@Override\n\tpublic void exception(ExecuteContext context) {\n\t\tSQLExceptionTranslator translator = this.translatorFactory.apply(context);\n\t\t// The exception() callback is not only triggered for SQL exceptions but also for\n\t\t// \"normal\" exceptions. In those cases sqlException() returns null.\n\t\tSQLException exception = context.sqlException();\n\t\twhile (exception != null) {\n\t\t\thandle(context, translator, exception);\n\t\t\texception = exception.getNextException();\n\t\t}\n\t}\n\n\t/**\n\t * Handle a single exception in the chain. SQLExceptions might be nested multiple\n\t * levels deep. The outermost exception is usually the least interesting one (\"Call\n\t * getNextException to see the cause.\"). Therefore the innermost exception is\n\t * propagated and all other exceptions are logged.\n\t * @param context the execute context\n\t * @param translator the exception translator\n\t * @param exception the exception\n\t */\n\tprivate void handle(ExecuteContext context, SQLExceptionTranslator translator, SQLException exception) {\n\t\tDataAccessException translated = translator.translate(\"jOOQ\", context.sql(), exception);\n\t\tif (exception.getNextException() != null) {\n\t\t\tthis.logger.error(\"Execution of SQL statement failed.\", (translated != null) ? translated : exception);\n\t\t\treturn;\n\t\t}\n\t\tif (translated != null) {\n\t\t\tcontext.exception(translated);\n\t\t}\n\t}\n\n\t/**\n\t * Default {@link SQLExceptionTranslator} factory that creates the translator based on\n\t * the Spring DB name.\n\t */\n\tprivate static final class DefaultTranslatorFactory implements Function<ExecuteContext, SQLExceptionTranslator> {\n\n\t\t@Override\n\t\tpublic SQLExceptionTranslator apply(ExecuteContext context) {\n\t\t\treturn apply(context.configuration().dialect());\n\t\t}\n\n\t\tprivate SQLExceptionTranslator apply(SQLDialect dialect) {\n\t\t\tString dbName = getSpringDbName(dialect);\n\t\t\treturn (dbName != null) ? new SQLErrorCodeSQLExceptionTranslator(dbName)\n\t\t\t\t\t: new SQLExceptionSubclassTranslator();\n\t\t}\n\n\t\tprivate @Nullable String getSpringDbName(@Nullable SQLDialect dialect) {\n\t\t\treturn (dialect != null && dialect.thirdParty() != null) ? dialect.thirdParty().springDbName() : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/ExceptionTranslatorExecuteListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.sql.SQLException;\nimport java.util.function.Function;\n\nimport org.jooq.ExecuteContext;\nimport org.jooq.ExecuteListener;\nimport org.jooq.impl.DefaultExecuteListenerProvider;\n\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\n\n/**\n * An {@link ExecuteListener} used by the auto-configured\n * {@link DefaultExecuteListenerProvider} to translate exceptions in the\n * {@link ExecuteContext}. Most commonly used to translate {@link SQLException\n * SQLExceptions} to Spring-specific {@link DataAccessException DataAccessExceptions} by\n * adapting an existing {@link SQLExceptionTranslator}.\n *\n * @author Dennis Melzer\n * @since 4.0.0\n * @see #DEFAULT\n * @see #of(Function)\n */\npublic interface ExceptionTranslatorExecuteListener extends ExecuteListener {\n\n\t/**\n\t * Default {@link ExceptionTranslatorExecuteListener} suitable for most applications.\n\t */\n\tExceptionTranslatorExecuteListener DEFAULT = new DefaultExceptionTranslatorExecuteListener();\n\n\t/**\n\t * Creates a new {@link ExceptionTranslatorExecuteListener} backed by an\n\t * {@link SQLExceptionTranslator}.\n\t * @param translatorFactory factory function used to create the\n\t * {@link SQLExceptionTranslator}\n\t * @return a new {@link ExceptionTranslatorExecuteListener} instance\n\t */\n\tstatic ExceptionTranslatorExecuteListener of(Function<ExecuteContext, SQLExceptionTranslator> translatorFactory) {\n\t\treturn new DefaultExceptionTranslatorExecuteListener(translatorFactory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/JaxbNotAvailableException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\n/**\n * Exception to be thrown if JAXB is not available.\n *\n * @author Moritz Halbritter\n */\nclass JaxbNotAvailableException extends RuntimeException {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/JaxbNotAvailableExceptionFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\n\n/**\n * {@link FailureAnalyzer} for {@link JaxbNotAvailableException}.\n *\n * @author Moritz Halbritter\n */\nclass JaxbNotAvailableExceptionFailureAnalyzer extends AbstractFailureAnalyzer<JaxbNotAvailableException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, JaxbNotAvailableException cause) {\n\t\treturn new FailureAnalysis(\"Unable to unmarshal jOOQ settings because JAXB is not available.\",\n\t\t\t\t\"Add JAXB to the classpath or remove the spring.jooq.config property.\", cause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/JooqAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.sql.DataSource;\nimport javax.xml.XMLConstants;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\nimport javax.xml.transform.Source;\nimport javax.xml.transform.sax.SAXSource;\n\nimport jakarta.xml.bind.JAXBContext;\nimport jakarta.xml.bind.JAXBException;\nimport org.jooq.ConnectionProvider;\nimport org.jooq.DSLContext;\nimport org.jooq.ExecuteListenerProvider;\nimport org.jooq.TransactionProvider;\nimport org.jooq.conf.Settings;\nimport org.jooq.impl.DataSourceConnectionProvider;\nimport org.jooq.impl.DefaultConfiguration;\nimport org.jooq.impl.DefaultDSLContext;\nimport org.jooq.impl.DefaultExecuteListenerProvider;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXNotRecognizedException;\nimport org.xml.sax.SAXNotSupportedException;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.Resource;\nimport org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for jOOQ.\n *\n * @author Andreas Ahlenstorf\n * @author Michael Simons\n * @author Dmytro Nosan\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(after = { DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class })\n@ConditionalOnClass(DSLContext.class)\n@ConditionalOnBean(DataSource.class)\n@EnableConfigurationProperties(JooqProperties.class)\npublic final class JooqAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ConnectionProvider.class)\n\tDataSourceConnectionProvider dataSourceConnectionProvider(DataSource dataSource) {\n\t\treturn new DataSourceConnectionProvider(new TransactionAwareDataSourceProxy(dataSource));\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(PlatformTransactionManager.class)\n\t@ConditionalOnMissingBean(TransactionProvider.class)\n\tSpringTransactionProvider transactionProvider(PlatformTransactionManager txManager) {\n\t\treturn new SpringTransactionProvider(txManager);\n\t}\n\n\t@Bean\n\t@Order(0)\n\tDefaultExecuteListenerProvider jooqExceptionTranslatorExecuteListenerProvider(\n\t\t\tExceptionTranslatorExecuteListener exceptionTranslatorExecuteListener) {\n\t\treturn new DefaultExecuteListenerProvider(exceptionTranslatorExecuteListener);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tExceptionTranslatorExecuteListener jooqExceptionTranslator() {\n\t\treturn ExceptionTranslatorExecuteListener.DEFAULT;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(DSLContext.class)\n\tDefaultDSLContext dslContext(org.jooq.Configuration configuration) {\n\t\treturn new DefaultDSLContext(configuration);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(org.jooq.Configuration.class)\n\tDefaultConfiguration jooqConfiguration(JooqProperties properties, ConnectionProvider connectionProvider,\n\t\t\tDataSource dataSource, ObjectProvider<TransactionProvider> transactionProvider,\n\t\t\tObjectProvider<ExecuteListenerProvider> executeListenerProviders,\n\t\t\tObjectProvider<DefaultConfigurationCustomizer> configurationCustomizers,\n\t\t\tObjectProvider<Settings> settingsProvider) {\n\t\tDefaultConfiguration configuration = new DefaultConfiguration();\n\t\tconfiguration.set(properties.determineSqlDialect(dataSource));\n\t\tconfiguration.set(connectionProvider);\n\t\ttransactionProvider.ifAvailable(configuration::set);\n\t\tsettingsProvider.ifAvailable(configuration::set);\n\t\tconfiguration.set(executeListenerProviders.orderedStream().toArray(ExecuteListenerProvider[]::new));\n\t\tconfigurationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configuration));\n\t\treturn configuration;\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(\"spring.jooq.config\")\n\t@ConditionalOnMissingBean\n\tSettings settings(JooqProperties properties) throws IOException {\n\t\tif (!ClassUtils.isPresent(\"jakarta.xml.bind.JAXBContext\", null)) {\n\t\t\tthrow new JaxbNotAvailableException();\n\t\t}\n\t\tResource resource = properties.getConfig();\n\t\tAssert.state(resource != null, \"'resource' must not be null\");\n\t\tAssert.state(resource.exists(),\n\t\t\t\t() -> \"Resource %s set in spring.jooq.config does not exist\".formatted(resource));\n\t\ttry (InputStream stream = resource.getInputStream()) {\n\t\t\treturn new JaxbSettingsLoader().load(stream);\n\t\t}\n\t}\n\n\t/**\n\t * Load {@link Settings} with <a href=\n\t * \"https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller\">\n\t * XML External Entity Prevention</a>.\n\t */\n\tprivate static final class JaxbSettingsLoader {\n\n\t\tprivate Settings load(InputStream inputStream) {\n\t\t\ttry {\n\t\t\t\tSAXParser parser = createParserFactory().newSAXParser();\n\t\t\t\tSource source = new SAXSource(parser.getXMLReader(), new InputSource(inputStream));\n\t\t\t\tJAXBContext context = JAXBContext.newInstance(Settings.class);\n\t\t\t\treturn context.createUnmarshaller().unmarshal(source, Settings.class).getValue();\n\t\t\t}\n\t\t\tcatch (ParserConfigurationException | JAXBException | SAXException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to unmarshal settings\", ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate SAXParserFactory createParserFactory()\n\t\t\t\tthrows ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException {\n\t\t\tSAXParserFactory factory = SAXParserFactory.newInstance();\n\t\t\tfactory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n\t\t\tfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);\n\t\t\tfactory.setNamespaceAware(true);\n\t\t\tfactory.setXIncludeAware(false);\n\t\t\treturn factory;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/JooqProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.jooq.SQLDialect;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\n\n/**\n * Configuration properties for the jOOQ database library.\n *\n * @author Andreas Ahlenstorf\n * @author Michael Simons\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jooq\")\npublic class JooqProperties {\n\n\t/**\n\t * SQL dialect to use. Auto-detected by default.\n\t */\n\tprivate @Nullable SQLDialect sqlDialect;\n\n\t/**\n\t * Location of the jOOQ config file.\n\t */\n\tprivate @Nullable Resource config;\n\n\tpublic @Nullable SQLDialect getSqlDialect() {\n\t\treturn this.sqlDialect;\n\t}\n\n\tpublic void setSqlDialect(@Nullable SQLDialect sqlDialect) {\n\t\tthis.sqlDialect = sqlDialect;\n\t}\n\n\tpublic @Nullable Resource getConfig() {\n\t\treturn this.config;\n\t}\n\n\tpublic void setConfig(@Nullable Resource config) {\n\t\tthis.config = config;\n\t}\n\n\t/**\n\t * Determine the {@link SQLDialect} to use based on this configuration and the primary\n\t * {@link DataSource}.\n\t * @param dataSource the data source\n\t * @return the {@code SQLDialect} to use for that {@link DataSource}\n\t */\n\tpublic SQLDialect determineSqlDialect(DataSource dataSource) {\n\t\tif (this.sqlDialect != null) {\n\t\t\treturn this.sqlDialect;\n\t\t}\n\t\treturn SqlDialectLookup.getDialect(dataSource);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/NoDslContextBeanFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.jooq.DSLContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.core.Ordered;\n\nclass NoDslContextBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>\n\t\timplements Ordered {\n\n\tprivate final BeanFactory beanFactory;\n\n\tNoDslContextBeanFailureAnalyzer(BeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {\n\t\tif (DSLContext.class.equals(cause.getBeanType()) && hasR2dbcAutoConfiguration()) {\n\t\t\treturn new FailureAnalysis(\n\t\t\t\t\t\"jOOQ has not been auto-configured as R2DBC has been auto-configured in favor of JDBC and jOOQ \"\n\t\t\t\t\t\t\t+ \"auto-configuration does not yet support R2DBC. \",\n\t\t\t\t\t\"To use jOOQ with JDBC, exclude R2dbcAutoConfiguration. To use jOOQ with R2DBC, define your own \"\n\t\t\t\t\t\t\t+ \"jOOQ configuration.\",\n\t\t\t\t\tcause);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean hasR2dbcAutoConfiguration() {\n\t\ttry {\n\t\t\tthis.beanFactory.getBean(R2dbcAutoConfiguration.class);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/SpringTransaction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.jooq.Transaction;\n\nimport org.springframework.transaction.TransactionStatus;\n\n/**\n * Adapts a Spring transaction for jOOQ.\n *\n * @author Lukas Eder\n * @author Andreas Ahlenstorf\n * @author Phillip Webb\n */\nclass SpringTransaction implements Transaction {\n\n\t// Based on the jOOQ-spring-example from https://github.com/jOOQ/jOOQ\n\n\tprivate final TransactionStatus transactionStatus;\n\n\tSpringTransaction(TransactionStatus transactionStatus) {\n\t\tthis.transactionStatus = transactionStatus;\n\t}\n\n\tTransactionStatus getTxStatus() {\n\t\treturn this.transactionStatus;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/SpringTransactionProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.jooq.TransactionContext;\nimport org.jooq.TransactionProvider;\n\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionDefinition;\nimport org.springframework.transaction.TransactionStatus;\nimport org.springframework.transaction.support.DefaultTransactionDefinition;\nimport org.springframework.util.Assert;\n\n/**\n * Allows Spring Transaction to be used with jOOQ.\n *\n * @author Lukas Eder\n * @author Andreas Ahlenstorf\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class SpringTransactionProvider implements TransactionProvider {\n\n\t// Based on the jOOQ-spring-example from https://github.com/jOOQ/jOOQ\n\n\tprivate final PlatformTransactionManager transactionManager;\n\n\tpublic SpringTransactionProvider(PlatformTransactionManager transactionManager) {\n\t\tthis.transactionManager = transactionManager;\n\t}\n\n\t@Override\n\tpublic void begin(TransactionContext context) {\n\t\tTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NESTED);\n\t\tTransactionStatus status = this.transactionManager.getTransaction(definition);\n\t\tcontext.transaction(new SpringTransaction(status));\n\t}\n\n\t@Override\n\tpublic void commit(TransactionContext ctx) {\n\t\tthis.transactionManager.commit(getTransactionStatus(ctx));\n\t}\n\n\t@Override\n\tpublic void rollback(TransactionContext ctx) {\n\t\tthis.transactionManager.rollback(getTransactionStatus(ctx));\n\t}\n\n\tprivate TransactionStatus getTransactionStatus(TransactionContext ctx) {\n\t\tSpringTransaction transaction = (SpringTransaction) ctx.transaction();\n\t\tAssert.state(transaction != null, \"'transaction' must not be null\");\n\t\treturn transaction.getTxStatus();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/SqlDialectLookup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jooq.SQLDialect;\nimport org.jooq.tools.jdbc.JDBCUtils;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Utility to lookup well known {@link SQLDialect SQLDialects} from a {@link DataSource}.\n *\n * @author Michael Simons\n * @author Lukas Eder\n * @author Ramil Saetov\n */\nfinal class SqlDialectLookup {\n\n\tprivate static final Log logger = LogFactory.getLog(SqlDialectLookup.class);\n\n\tprivate SqlDialectLookup() {\n\t}\n\n\t/**\n\t * Return the most suitable {@link SQLDialect} for the given {@link DataSource}.\n\t * @param dataSource the source {@link DataSource}\n\t * @return the most suitable {@link SQLDialect}\n\t */\n\tstatic SQLDialect getDialect(@Nullable DataSource dataSource) {\n\t\ttry (Connection connection = (dataSource != null) ? dataSource.getConnection() : null) {\n\t\t\treturn JDBCUtils.dialect(connection);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tlogger.warn(\"Unable to determine dialect from datasource\", ex);\n\t\t}\n\t\treturn SQLDialect.DEFAULT;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for jOOQ.\n */\n@NullMarked\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/java/org/springframework/boot/jooq/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for jOOQ.\n *\n * @see org.springframework.boot.json.JsonParser\n */\n@NullMarked\npackage org.springframework.boot.jooq;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jooq.autoconfigure.JooqAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jooq/src/main/resources/META-INF/spring.factories",
    "content": "# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.jooq.autoconfigure.JaxbNotAvailableExceptionFailureAnalyzer,\\\norg.springframework.boot.jooq.autoconfigure.NoDslContextBeanFailureAnalyzer\n\n# Depends On Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.jooq.JooqDependsOnDatabaseInitializationDetector\n\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/java/org/springframework/boot/jooq/autoconfigure/DefaultExceptionTranslatorExecuteListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.sql.SQLException;\nimport java.sql.SQLSyntaxErrorException;\nimport java.util.function.Function;\n\nimport org.jooq.Configuration;\nimport org.jooq.ExecuteContext;\nimport org.jooq.SQLDialect;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.support.SQLExceptionTranslator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link DefaultExceptionTranslatorExecuteListener}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DefaultExceptionTranslatorExecuteListenerTests {\n\n\tprivate final ExceptionTranslatorExecuteListener listener = new DefaultExceptionTranslatorExecuteListener();\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenTranslatorFactoryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DefaultExceptionTranslatorExecuteListener(\n\t\t\t\t\t(Function<ExecuteContext, SQLExceptionTranslator>) null))\n\t\t\t.withMessage(\"'translatorFactory' must not be null\");\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource\n\tvoid exceptionTranslatesSqlExceptions(SQLDialect dialect, SQLException sqlException) {\n\t\tExecuteContext context = mockContext(dialect, sqlException);\n\t\tthis.listener.exception(context);\n\t\tthen(context).should().exception(assertArg((ex) -> assertThat(ex).isInstanceOf(BadSqlGrammarException.class)));\n\t}\n\n\t@Test\n\tvoid exceptionWhenExceptionCannotBeTranslatedDoesNotCallExecuteContextException() {\n\t\tExecuteContext context = mockContext(SQLDialect.POSTGRES, new SQLException(null, null, 123456789));\n\t\tthis.listener.exception(context);\n\t\tthen(context).should(never()).exception(any());\n\t}\n\n\t@Test\n\tvoid exceptionWhenHasCustomTranslatorFactory() {\n\t\tSQLExceptionTranslator translator = (task, sql, ex) -> new BadSqlGrammarException(task, \"sql\", ex);\n\t\tExceptionTranslatorExecuteListener listener = new DefaultExceptionTranslatorExecuteListener(\n\t\t\t\t(context) -> translator);\n\t\tSQLException sqlException = sqlException(123);\n\t\tExecuteContext context = mockContext(SQLDialect.DUCKDB, sqlException);\n\t\tlistener.exception(context);\n\t\tthen(context).should().exception(assertArg((ex) -> assertThat(ex).isInstanceOf(BadSqlGrammarException.class)));\n\t}\n\n\tprivate ExecuteContext mockContext(SQLDialect dialect, SQLException sqlException) {\n\t\tExecuteContext context = mock(ExecuteContext.class);\n\t\tConfiguration configuration = mock(Configuration.class);\n\t\tgiven(context.configuration()).willReturn(configuration);\n\t\tgiven(configuration.dialect()).willReturn(dialect);\n\t\tgiven(context.sqlException()).willReturn(sqlException);\n\t\treturn context;\n\t}\n\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic Object[] exceptionTranslatesSqlExceptions() {\n\t\treturn new Object[] { new Object[] { SQLDialect.DERBY, sqlException(\"42802\") },\n\t\t\t\tnew Object[] { SQLDialect.DERBY, new SQLSyntaxErrorException() },\n\t\t\t\tnew Object[] { SQLDialect.H2, sqlException(42000) },\n\t\t\t\tnew Object[] { SQLDialect.H2, new SQLSyntaxErrorException() },\n\t\t\t\tnew Object[] { SQLDialect.HSQLDB, sqlException(-22) },\n\t\t\t\tnew Object[] { SQLDialect.HSQLDB, new SQLSyntaxErrorException() },\n\t\t\t\tnew Object[] { SQLDialect.MARIADB, sqlException(1054) },\n\t\t\t\tnew Object[] { SQLDialect.MARIADB, new SQLSyntaxErrorException() },\n\t\t\t\tnew Object[] { SQLDialect.MYSQL, sqlException(1054) },\n\t\t\t\tnew Object[] { SQLDialect.MYSQL, new SQLSyntaxErrorException() },\n\t\t\t\tnew Object[] { SQLDialect.POSTGRES, sqlException(\"03000\") },\n\t\t\t\tnew Object[] { SQLDialect.POSTGRES, new SQLSyntaxErrorException() },\n\t\t\t\tnew Object[] { SQLDialect.SQLITE, sqlException(\"21000\") },\n\t\t\t\tnew Object[] { SQLDialect.SQLITE, new SQLSyntaxErrorException() } };\n\t}\n\n\tprivate static SQLException sqlException(String sqlState) {\n\t\treturn new SQLException(null, sqlState);\n\t}\n\n\tprivate static SQLException sqlException(int vendorCode) {\n\t\treturn new SQLException(null, null, vendorCode);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/java/org/springframework/boot/jooq/autoconfigure/JooqAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.jooq.CharsetProvider;\nimport org.jooq.ConnectionProvider;\nimport org.jooq.ConverterProvider;\nimport org.jooq.DSLContext;\nimport org.jooq.ExecuteListener;\nimport org.jooq.ExecuteListenerProvider;\nimport org.jooq.SQLDialect;\nimport org.jooq.TransactionContext;\nimport org.jooq.TransactionProvider;\nimport org.jooq.TransactionalRunnable;\nimport org.jooq.conf.Settings;\nimport org.jooq.impl.DataSourceConnectionProvider;\nimport org.jooq.impl.DefaultDSLContext;\nimport org.jooq.impl.DefaultExecuteListenerProvider;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.dao.DataIntegrityViolationException;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JooqAutoConfiguration}.\n *\n * @author Andreas Ahlenstorf\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Dmytro Nosan\n * @author Dennis Melzer\n * @author Moritz Halbritter\n */\nclass JooqAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JooqAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.name:jooqtest\");\n\n\t@Test\n\tvoid noDataSource() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBeansOfType(DSLContext.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid jooqWithoutTx() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(PlatformTransactionManager.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpringTransactionProvider.class);\n\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\tdsl.execute(\"create table jooqtest (name varchar(255) primary key);\");\n\t\t\tdsl.transaction(new AssertFetch(dsl, \"select count(*) as total from jooqtest;\", \"0\"));\n\t\t\tdsl.transaction(new ExecuteSql(dsl, \"insert into jooqtest (name) values ('foo');\"));\n\t\t\tdsl.transaction(new AssertFetch(dsl, \"select count(*) as total from jooqtest;\", \"1\"));\n\t\t\tassertThatExceptionOfType(DataIntegrityViolationException.class)\n\t\t\t\t.isThrownBy(() -> dsl.transaction(new ExecuteSql(dsl, \"insert into jooqtest (name) values ('bar');\",\n\t\t\t\t\t\t\"insert into jooqtest (name) values ('foo');\")));\n\t\t\tdsl.transaction(new AssertFetch(dsl, \"select count(*) as total from jooqtest;\", \"2\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid jooqWithTx() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class, TxManagerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(PlatformTransactionManager.class);\n\t\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\t\tassertThat(dsl.configuration().dialect()).isEqualTo(SQLDialect.HSQLDB);\n\t\t\t\tdsl.execute(\"create table jooqtest_tx (name varchar(255) primary key);\");\n\t\t\t\tdsl.transaction(new AssertFetch(dsl, \"select count(*) as total from jooqtest_tx;\", \"0\"));\n\t\t\t\tdsl.transaction(new ExecuteSql(dsl, \"insert into jooqtest_tx (name) values ('foo');\"));\n\t\t\t\tdsl.transaction(new AssertFetch(dsl, \"select count(*) as total from jooqtest_tx;\", \"1\"));\n\t\t\t\tassertThatExceptionOfType(DataIntegrityViolationException.class)\n\t\t\t\t\t.isThrownBy(() -> dsl.transaction(new ExecuteSql(dsl, \"insert into jooqtest (name) values ('bar');\",\n\t\t\t\t\t\t\t\"insert into jooqtest (name) values ('foo');\")));\n\t\t\t\tdsl.transaction(new AssertFetch(dsl, \"select count(*) as total from jooqtest_tx;\", \"1\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jooqWithDefaultConnectionProvider() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> {\n\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\tConnectionProvider connectionProvider = dsl.configuration().connectionProvider();\n\t\t\tassertThat(connectionProvider).isInstanceOf(DataSourceConnectionProvider.class);\n\t\t\tDataSource connectionProviderDataSource = ((DataSourceConnectionProvider) connectionProvider).dataSource();\n\t\t\tassertThat(connectionProviderDataSource).isInstanceOf(TransactionAwareDataSourceProxy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jooqWithDefaultTransactionProvider() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class, TxManagerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\t\tTransactionProvider expectedTransactionProvider = context.getBean(TransactionProvider.class);\n\t\t\t\tTransactionProvider transactionProvider = dsl.configuration().transactionProvider();\n\t\t\t\tassertThat(transactionProvider).isSameAs(expectedTransactionProvider);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jooqWithDefaultExecuteListenerProvider() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> {\n\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\tassertThat(dsl.configuration().executeListenerProviders()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jooqWithSeveralExecuteListenerProviders() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class, TestExecuteListenerProvider.class)\n\t\t\t.run((context) -> {\n\t\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\t\tExecuteListenerProvider[] executeListenerProviders = dsl.configuration().executeListenerProviders();\n\t\t\t\tassertThat(executeListenerProviders).hasSize(2);\n\t\t\t\tassertThat(executeListenerProviders[0]).isInstanceOf(DefaultExecuteListenerProvider.class);\n\t\t\t\tassertThat(executeListenerProviders[1]).isInstanceOf(TestExecuteListenerProvider.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid dslContextWithConfigurationCustomizersAreApplied() {\n\t\tConverterProvider converterProvider = mock(ConverterProvider.class);\n\t\tCharsetProvider charsetProvider = mock(CharsetProvider.class);\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class)\n\t\t\t.withBean(\"configurationCustomizer1\", DefaultConfigurationCustomizer.class,\n\t\t\t\t\t() -> (configuration) -> configuration.set(converterProvider))\n\t\t\t.withBean(\"configurationCustomizer2\", DefaultConfigurationCustomizer.class,\n\t\t\t\t\t() -> (configuration) -> configuration.set(charsetProvider))\n\t\t\t.run((context) -> {\n\t\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\t\tassertThat(dsl.configuration().converterProvider()).isSameAs(converterProvider);\n\t\t\t\tassertThat(dsl.configuration().charsetProvider()).isSameAs(charsetProvider);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid relaxedBindingOfSqlDialect() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jooq.sql-dialect:PoSTGrES\")\n\t\t\t.run((context) -> assertThat(context.getBean(org.jooq.Configuration.class).dialect())\n\t\t\t\t.isEqualTo(SQLDialect.POSTGRES));\n\t}\n\n\t@Test\n\tvoid transactionProviderBacksOffOnExistingTransactionProvider() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(JooqDataSourceConfiguration.class, CustomTransactionProviderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTransactionProvider transactionProvider = context.getBean(TransactionProvider.class);\n\t\t\t\tassertThat(transactionProvider).isInstanceOf(CustomTransactionProvider.class);\n\t\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\t\tassertThat(dsl.configuration().transactionProvider()).isSameAs(transactionProvider);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jooqExceptionTranslatorProviderFromConfigurationCustomizerOverridesJooqExceptionTranslatorBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(JooqDataSourceConfiguration.class, CustomJooqExceptionTranslatorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(ExceptionTranslatorExecuteListener.class))\n\t\t\t\t\t.isInstanceOf(CustomJooqExceptionTranslator.class);\n\t\t\t\tassertThat(context.getBean(DefaultExecuteListenerProvider.class).provide())\n\t\t\t\t\t.isInstanceOf(CustomJooqExceptionTranslator.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jooqWithDefaultJooqExceptionTranslator() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class).run((context) -> {\n\t\t\tExceptionTranslatorExecuteListener translator = context.getBean(ExceptionTranslatorExecuteListener.class);\n\t\t\tassertThat(translator).isInstanceOf(DefaultExceptionTranslatorExecuteListener.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid transactionProviderFromConfigurationCustomizerOverridesTransactionProviderBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(JooqDataSourceConfiguration.class, TxManagerConfiguration.class,\n\t\t\t\t\tCustomTransactionProviderFromCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTransactionProvider transactionProvider = context.getBean(TransactionProvider.class);\n\t\t\t\tassertThat(transactionProvider).isInstanceOf(SpringTransactionProvider.class);\n\t\t\t\tDSLContext dsl = context.getBean(DSLContext.class);\n\t\t\t\tassertThat(dsl.configuration().transactionProvider()).isInstanceOf(CustomTransactionProvider.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredJooqConfigurationCanBeUsedToCreateCustomDslContext() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDslContextConfiguration.class, JooqDataSourceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DSLContext.class).hasBean(\"customDslContext\"));\n\t}\n\n\t@Test\n\tvoid shouldLoadSettingsFromConfigPropertyThroughJaxb() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jooq.config=classpath:org/springframework/boot/jooq/autoconfigure/settings.xml\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Settings.class);\n\t\t\t\tSettings settings = context.getBean(Settings.class);\n\t\t\t\tassertThat(settings.getBatchSize()).isEqualTo(100);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotProvideSettingsIfJaxbIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"jakarta.xml.bind\"))\n\t\t\t.withPropertyValues(\"spring.jooq.config=classpath:org/springframework/boot/autoconfigure/jooq/settings.xml\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasRootCauseInstanceOf(JaxbNotAvailableException.class));\n\t}\n\n\t@Test\n\tvoid shouldFailWithSensibleErrorMessageIfConfigIsNotFound() {\n\t\tthis.contextRunner.withUserConfiguration(JooqDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.jooq.config=classpath:does-not-exist.xml\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasMessageContaining(\"spring.jooq.config\")\n\t\t\t\t.hasMessageContaining(\"does-not-exist.xml\"));\n\t}\n\n\tstatic class AssertFetch implements TransactionalRunnable {\n\n\t\tprivate final DSLContext dsl;\n\n\t\tprivate final String sql;\n\n\t\tprivate final String expected;\n\n\t\tAssertFetch(DSLContext dsl, String sql, String expected) {\n\t\t\tthis.dsl = dsl;\n\t\t\tthis.sql = sql;\n\t\t\tthis.expected = expected;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run(org.jooq.Configuration configuration) {\n\t\t\tassertThat(this.dsl.fetch(this.sql).getValue(0, 0)).hasToString(this.expected);\n\t\t}\n\n\t}\n\n\tstatic class ExecuteSql implements TransactionalRunnable {\n\n\t\tprivate final DSLContext dsl;\n\n\t\tprivate final String[] sql;\n\n\t\tExecuteSql(DSLContext dsl, String... sql) {\n\t\t\tthis.dsl = dsl;\n\t\t\tthis.sql = sql;\n\t\t}\n\n\t\t@Override\n\t\tpublic void run(org.jooq.Configuration configuration) {\n\t\t\tfor (String statement : this.sql) {\n\t\t\t\tthis.dsl.execute(statement);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JooqDataSourceConfiguration {\n\n\t\t@Bean\n\t\tDataSource jooqDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:hsqldb:mem:jooqtest\").username(\"sa\").build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTransactionProviderConfiguration {\n\n\t\t@Bean\n\t\tTransactionProvider transactionProvider() {\n\t\t\treturn new CustomTransactionProvider();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJooqExceptionTranslatorConfiguration {\n\n\t\t@Bean\n\t\tExceptionTranslatorExecuteListener jooqExceptionTranslator() {\n\t\t\treturn new CustomJooqExceptionTranslator();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTransactionProviderFromCustomizerConfiguration {\n\n\t\t@Bean\n\t\tDefaultConfigurationCustomizer transactionProviderCustomizer() {\n\t\t\treturn (configuration) -> configuration.setTransactionProvider(new CustomTransactionProvider());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TxManagerConfiguration {\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager(DataSource dataSource) {\n\t\t\treturn new DataSourceTransactionManager(dataSource);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDslContextConfiguration {\n\n\t\t@Bean\n\t\tDSLContext customDslContext(org.jooq.Configuration configuration) {\n\t\t\treturn new DefaultDSLContext(configuration);\n\t\t}\n\n\t}\n\n\t@Order(100)\n\tstatic class TestExecuteListenerProvider implements ExecuteListenerProvider {\n\n\t\t@Override\n\t\tpublic ExecuteListener provide() {\n\t\t\treturn mock(ExecuteListener.class);\n\t\t}\n\n\t}\n\n\tstatic class CustomTransactionProvider implements TransactionProvider {\n\n\t\t@Override\n\t\tpublic void begin(TransactionContext ctx) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void commit(TransactionContext ctx) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void rollback(TransactionContext ctx) {\n\n\t\t}\n\n\t}\n\n\tstatic class CustomJooqExceptionTranslator implements ExceptionTranslatorExecuteListener {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/java/org/springframework/boot/jooq/autoconfigure/JooqFlywayDatabaseInitializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.flywaydb.core.Flyway;\nimport org.jooq.DSLContext;\nimport org.jooq.SQLDialect;\nimport org.jooq.impl.DefaultDSLContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.flyway.autoconfigure.FlywayMigrationInitializer;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for jOQQ when Flyway is being used for DB initialization.\n *\n * @author Andy Wilkinson\n */\nclass JooqFlywayDatabaseInitializationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JooqConfiguration.class)\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid whenFlywayIsAutoConfiguredThenJooqDslContextDependsOnFlywayBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tBeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(\"dslContext\");\n\t\t\tassertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder(\"flywayInitializer\", \"flyway\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomMigrationInitializerIsDefinedThenJooqDslContextDependsOnIt() {\n\t\tthis.contextRunner.withUserConfiguration(CustomFlywayMigrationInitializer.class).run((context) -> {\n\t\t\tBeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(\"dslContext\");\n\t\t\tassertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder(\"flywayMigrationInitializer\", \"flyway\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomFlywayIsDefinedThenJooqDslContextDependsOnIt() {\n\t\tthis.contextRunner.withUserConfiguration(CustomFlyway.class).run((context) -> {\n\t\t\tBeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(\"dslContext\");\n\t\t\tassertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder(\"customFlyway\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JooqConfiguration {\n\n\t\t@Bean\n\t\tDSLContext dslContext() {\n\t\t\treturn new DefaultDSLContext(SQLDialect.H2);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFlywayMigrationInitializer {\n\n\t\t@Bean\n\t\tFlywayMigrationInitializer flywayMigrationInitializer(Flyway flyway) {\n\t\t\tFlywayMigrationInitializer initializer = new FlywayMigrationInitializer(flyway);\n\t\t\tinitializer.setOrder(Ordered.HIGHEST_PRECEDENCE);\n\t\t\treturn initializer;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFlyway {\n\n\t\t@Bean\n\t\tFlyway customFlyway() {\n\t\t\treturn Flyway.configure().load();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/java/org/springframework/boot/jooq/autoconfigure/JooqPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.jooq.SQLDialect;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link JooqProperties}.\n *\n * @author Stephane Nicoll\n */\nclass JooqPropertiesTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid determineSqlDialectNoCheckIfDialectIsSet() throws SQLException {\n\t\tJooqProperties properties = load(\"spring.jooq.sql-dialect=postgres\");\n\t\tDataSource dataSource = mockStandaloneDataSource();\n\t\tSQLDialect sqlDialect = properties.determineSqlDialect(dataSource);\n\t\tassertThat(sqlDialect).isEqualTo(SQLDialect.POSTGRES);\n\t\tthen(dataSource).should(never()).getConnection();\n\t}\n\n\t@Test\n\tvoid determineSqlDialectWithKnownUrl() {\n\t\tJooqProperties properties = load();\n\t\tSQLDialect sqlDialect = properties.determineSqlDialect(mockDataSource(\"jdbc:h2:mem:testdb\"));\n\t\tassertThat(sqlDialect).isEqualTo(SQLDialect.H2);\n\t}\n\n\t@Test\n\tvoid determineSqlDialectWithKnownUrlAndUserConfig() {\n\t\tJooqProperties properties = load(\"spring.jooq.sql-dialect=mysql\");\n\t\tSQLDialect sqlDialect = properties.determineSqlDialect(mockDataSource(\"jdbc:h2:mem:testdb\"));\n\t\tassertThat(sqlDialect).isEqualTo(SQLDialect.MYSQL);\n\t}\n\n\t@Test\n\tvoid determineSqlDialectWithUnknownUrl() {\n\t\tJooqProperties properties = load();\n\t\tSQLDialect sqlDialect = properties.determineSqlDialect(mockDataSource(\"jdbc:unknown://localhost\"));\n\t\tassertThat(sqlDialect).isEqualTo(SQLDialect.DEFAULT);\n\t}\n\n\tprivate DataSource mockStandaloneDataSource() throws SQLException {\n\t\tDataSource ds = mock(DataSource.class);\n\t\tgiven(ds.getConnection()).willThrow(SQLException.class);\n\t\treturn ds;\n\t}\n\n\tprivate DataSource mockDataSource(String jdbcUrl) {\n\t\tDataSource ds = mock(DataSource.class);\n\t\ttry {\n\t\t\tDatabaseMetaData metadata = mock(DatabaseMetaData.class);\n\t\t\tgiven(metadata.getURL()).willReturn(jdbcUrl);\n\t\t\tConnection connection = mock(Connection.class);\n\t\t\tgiven(connection.getMetaData()).willReturn(metadata);\n\t\t\tgiven(ds.getConnection()).willReturn(connection);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\t// Do nothing\n\t\t}\n\t\treturn ds;\n\t}\n\n\tprivate JooqProperties load(String... environment) {\n\t\tAnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(environment).applyTo(ctx);\n\t\tctx.register(TestConfiguration.class);\n\t\tctx.refresh();\n\t\tthis.context = ctx;\n\t\treturn this.context.getBean(JooqProperties.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(JooqProperties.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/java/org/springframework/boot/jooq/autoconfigure/NoDslContextBeanFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport org.jooq.DSLContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoDslContextBeanFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n */\nclass NoDslContextBeanFailureAnalyzerTests {\n\n\t@Test\n\tvoid noAnalysisWithoutR2dbcAutoConfiguration() {\n\t\tnew ApplicationContextRunner().run((context) -> {\n\t\t\tNoDslContextBeanFailureAnalyzer failureAnalyzer = new NoDslContextBeanFailureAnalyzer(\n\t\t\t\t\tcontext.getBeanFactory());\n\t\t\tassertThat(failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class))).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid analysisWithR2dbcAutoConfiguration() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tNoDslContextBeanFailureAnalyzer failureAnalyzer = new NoDslContextBeanFailureAnalyzer(\n\t\t\t\t\t\tcontext.getBeanFactory());\n\t\t\t\tassertThat(failureAnalyzer.analyze(new NoSuchBeanDefinitionException(DSLContext.class))).isNotNull();\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/java/org/springframework/boot/jooq/autoconfigure/SqlDialectLookupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.autoconfigure;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\n\nimport javax.sql.DataSource;\n\nimport org.jooq.SQLDialect;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SqlDialectLookup}.\n *\n * @author Michael Simons\n * @author Stephane Nicoll\n */\nclass SqlDialectLookupTests {\n\n\t@Test\n\tvoid getSqlDialectWhenDataSourceIsNullShouldReturnDefault() {\n\t\tassertThat(SqlDialectLookup.getDialect(null)).isEqualTo(SQLDialect.DEFAULT);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenDataSourceIsUnknownShouldReturnDefault() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:idontexist:\", SQLDialect.DEFAULT);\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tvoid getSqlDialectWhenDerbyShouldReturnDerby() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:derby:\", SQLDialect.DERBY);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenH2ShouldReturnH2() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:h2:\", SQLDialect.H2);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenHsqldbShouldReturnHsqldb() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:hsqldb:\", SQLDialect.HSQLDB);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenMysqlShouldReturnMysql() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:mysql:\", SQLDialect.MYSQL);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenOracleShouldReturnDefault() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:oracle:\", SQLDialect.DEFAULT);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenPostgresShouldReturnPostgres() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:postgresql:\", SQLDialect.POSTGRES);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenSqlserverShouldReturnDefault() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:sqlserver:\", SQLDialect.DEFAULT);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenDb2ShouldReturnDefault() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:db2:\", SQLDialect.DEFAULT);\n\t}\n\n\t@Test\n\tvoid getSqlDialectWhenInformixShouldReturnDefault() throws Exception {\n\t\ttestGetSqlDialect(\"jdbc:informix-sqli:\", SQLDialect.DEFAULT);\n\t}\n\n\tprivate void testGetSqlDialect(String url, SQLDialect expected) throws Exception {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tConnection connection = mock(Connection.class);\n\t\tDatabaseMetaData metaData = mock(DatabaseMetaData.class);\n\t\tgiven(dataSource.getConnection()).willReturn(connection);\n\t\tgiven(connection.getMetaData()).willReturn(metaData);\n\t\tgiven(metaData.getURL()).willReturn(url);\n\t\tSQLDialect sqlDialect = SqlDialectLookup.getDialect(dataSource);\n\t\tassertThat(sqlDialect).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq/src/test/resources/org/springframework/boot/jooq/autoconfigure/settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<settings xmlns=\"http://www.jooq.org/xsd/jooq-runtime-3.21.0.xsd\">\n\t<batchSize>100</batchSize>\n</settings>\n"
  },
  {
    "path": "module/spring-boot-jooq-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot jOOQ Test\"\n\nsystemRequirements {\n\tjava {\n\t\tversion = 21\n\t}\n}\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-jdbc-test\"))\n\tapi(project(\":module:spring-boot-jooq\"))\n\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-liquibase\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/main/java/org/springframework/boot/jooq/test/autoconfigure/AutoConfigureJooq.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical jOOQ tests. Most\n * tests should consider using {@link JooqTest @JooqTest} rather than using this\n * annotation directly.\n *\n * @author Michael Simons\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureDataSourceInitialization\n@ImportAutoConfiguration\npublic @interface AutoConfigureJooq {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/main/java/org/springframework/boot/jooq/test/autoconfigure/JooqTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Annotation for a jOOQ test that focuses <strong>only</strong> on jOOQ-based components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to jOOQ tests.\n * Similarly, component scanning is configured to skip regular components and\n * configuration properties.\n * <p>\n * By default, tests annotated with {@code @JooqTest} use the configured database. If you\n * want to replace any explicit or usually auto-configured DataSource by an embedded\n * in-memory database, the {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase}\n * annotation can be used to override these settings.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Michael Simons\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(JooqTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(JooqTypeExcludeFilter.class)\n@Transactional\n@AutoConfigureJooq\n@ImportAutoConfiguration\npublic @interface JooqTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default no beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/main/java/org/springframework/boot/jooq/test/autoconfigure/JooqTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link JooqTest @JooqTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass JooqTestContextBootstrapper extends TestSliceTestContextBootstrapper<JooqTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/main/java/org/springframework/boot/jooq/test/autoconfigure/JooqTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link JooqTest @JooqTest}.\n *\n * @author Michael Simons\n */\nclass JooqTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<JooqTest> {\n\n\tJooqTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/main/java/org/springframework/boot/jooq/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for jOOQ tests.\n */\n@NullMarked\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/main/resources/META-INF/spring/org.springframework.boot.jooq.test.autoconfigure.AutoConfigureJooq.imports",
    "content": "org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\norg.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration\norg.springframework.boot.jooq.autoconfigure.JooqAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration\noptional:org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/test/java/org/springframework/boot/jooq/test/autoconfigure/ExampleComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport org.springframework.stereotype.Component;\n\n/**\n * Example component used with {@link JooqTest @JooqTest} tests.\n *\n * @author Phillip Webb\n */\n@Component\npublic class ExampleComponent {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/test/java/org/springframework/boot/jooq/test/autoconfigure/ExampleJooqApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link JooqTest @JooqTest} tests.\n *\n * @author Michael Simons\n */\n@SpringBootApplication\npublic class ExampleJooqApplication {\n\n\t@Bean\n\tpublic DataSource dataSource() {\n\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.HSQL).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/test/java/org/springframework/boot/jooq/test/autoconfigure/JooqTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.jooq.DSLContext;\nimport org.jooq.SQLDialect;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnectionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for {@link JooqTest @JooqTest}.\n *\n * @author Michael Simons\n */\n@JooqTest\n@TestPropertySource(properties = { \"spring.flyway.enabled=false\", \"spring.liquibase.enabled=false\" })\nclass JooqTestIntegrationTests {\n\n\t@Autowired\n\tprivate DSLContext dsl;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testDSLContext() {\n\t\tassertThat(this.dsl.selectCount().from(\"INFORMATION_SCHEMA.TABLES\").fetchOne(0, Integer.class))\n\t\t\t.isGreaterThan(0);\n\t}\n\n\t@Test\n\tvoid useDefinedDataSource() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"HSQL\");\n\t\tassertThat(this.dsl.configuration().dialect()).isEqualTo(SQLDialect.HSQLDB);\n\t}\n\n\t@Test\n\tvoid didNotInjectExampleComponent() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleComponent.class));\n\t}\n\n\t@Test\n\tvoid flywayAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(FlywayAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid liquibaseAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(LiquibaseAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid serviceConnectionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ServiceConnectionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid transactionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TransactionAutoConfiguration.class));\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(TransactionManagerCustomizationAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/test/java/org/springframework/boot/jooq/test/autoconfigure/JooqTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link JooqTest#properties properties} attribute of\n * {@link JooqTest @JooqTest}.\n *\n * @author Artsiom Yudovin\n */\n@JooqTest(\n\t\tproperties = { \"spring.profiles.active=test\", \"spring.flyway.enabled=false\", \"spring.liquibase.enabled=false\" })\nclass JooqTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(JooqTestPropertiesIntegrationTests.this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jooq-test/src/test/java/org/springframework/boot/jooq/test/autoconfigure/JooqTestWithAutoConfigureTestDatabaseIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jooq.test.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.jooq.DSLContext;\nimport org.jooq.SQLDialect;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JooqTest @JooqTest}.\n *\n * @author Stephane Nicoll\n */\n@JooqTest\n@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)\n@TestPropertySource(properties = { \"spring.flyway.enabled=false\", \"spring.liquibase.enabled=false\" })\nclass JooqTestWithAutoConfigureTestDatabaseIntegrationTests {\n\n\t@Autowired\n\tprivate DSLContext dsl;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tvoid replacesAutoConfiguredDataSource() throws Exception {\n\t\tString product = this.dataSource.getConnection().getMetaData().getDatabaseProductName();\n\t\tassertThat(product).startsWith(\"H2\");\n\t\tassertThat(this.dsl.configuration().dialect()).isEqualTo(SQLDialect.H2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot JPA\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"jakarta.persistence:jakarta.persistence-api\")\n\tapi(\"org.springframework:spring-orm\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework:spring-webmvc\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/EntityManagerFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa;\n\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.orm.jpa.JpaVendorAdapter;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.LocalEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Convenient builder for JPA EntityManagerFactory instances. Collects common\n * configuration when constructed and then allows you to create one or more\n * {@link LocalContainerEntityManagerFactoryBean} through a fluent builder pattern. The\n * most common options are covered in the builder, but you can always manipulate the\n * product of the builder if you need more control, before returning it from a\n * {@code @Bean} definition.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class EntityManagerFactoryBuilder {\n\n\tprivate final JpaVendorAdapter jpaVendorAdapter;\n\n\tprivate final @Nullable PersistenceUnitManager persistenceUnitManager;\n\n\tprivate final Function<DataSource, Map<String, ?>> jpaPropertiesFactory;\n\n\tprivate final @Nullable URL persistenceUnitRootLocation;\n\n\tprivate final @Nullable AsyncTaskExecutor fallbackBootstrapExecutor;\n\n\tprivate @Nullable AsyncTaskExecutor bootstrapExecutor;\n\n\tprivate @Nullable List<PersistenceUnitPostProcessor> persistenceUnitPostProcessors;\n\n\tprivate @Nullable Supplier<@Nullable ? extends RuntimeException> requireBootstrapExecutorExceptionSupplier;\n\n\t/**\n\t * Create a new instance passing in the common pieces that will be shared if multiple\n\t * EntityManagerFactory instances are created.\n\t * @param jpaVendorAdapter a vendor adapter\n\t * @param jpaPropertiesFactory the JPA properties to be passed to the persistence\n\t * provider, based on the {@linkplain #dataSource(DataSource) configured data source}\n\t * @param persistenceUnitManager optional source of persistence unit information (can\n\t * be null)\n\t */\n\tpublic EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,\n\t\t\tFunction<DataSource, Map<String, ?>> jpaPropertiesFactory,\n\t\t\t@Nullable PersistenceUnitManager persistenceUnitManager) {\n\t\tthis(jpaVendorAdapter, jpaPropertiesFactory, persistenceUnitManager, null);\n\t}\n\n\t/**\n\t * Create a new instance passing in the common pieces that will be shared if multiple\n\t * EntityManagerFactory instances are created.\n\t * @param jpaVendorAdapter a vendor adapter\n\t * @param jpaPropertiesFactory the JPA properties to be passed to the persistence\n\t * provider, based on the {@linkplain #dataSource(DataSource) configured data source}\n\t * @param persistenceUnitManager optional source of persistence unit information (can\n\t * be null)\n\t * @param persistenceUnitRootLocation the persistence unit root location to use as a\n\t * fallback or {@code null}\n\t */\n\tpublic EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,\n\t\t\tFunction<DataSource, Map<String, ?>> jpaPropertiesFactory,\n\t\t\t@Nullable PersistenceUnitManager persistenceUnitManager, @Nullable URL persistenceUnitRootLocation) {\n\t\tthis(jpaVendorAdapter, jpaPropertiesFactory, persistenceUnitManager, persistenceUnitRootLocation, null);\n\t}\n\n\t/**\n\t * Create a new instance passing in the common pieces that will be shared if multiple\n\t * EntityManagerFactory instances are created.\n\t * @param jpaVendorAdapter a vendor adapter\n\t * @param jpaPropertiesFactory the JPA properties to be passed to the persistence\n\t * provider, based on the {@linkplain #dataSource(DataSource) configured data source}\n\t * @param persistenceUnitManager optional source of persistence unit information (can\n\t * be null)\n\t * @param persistenceUnitRootLocation the persistence unit root location to use as a\n\t * fallback or {@code null}\n\t * @param fallbackBootstrapExecutor the fallback executor to use when background\n\t * bootstrapping is required but no explicit executor has been set\n\t * @since 4.1.0\n\t */\n\tpublic EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,\n\t\t\tFunction<DataSource, Map<String, ?>> jpaPropertiesFactory,\n\t\t\t@Nullable PersistenceUnitManager persistenceUnitManager, @Nullable URL persistenceUnitRootLocation,\n\t\t\t@Nullable AsyncTaskExecutor fallbackBootstrapExecutor) {\n\t\tthis.jpaVendorAdapter = jpaVendorAdapter;\n\t\tthis.persistenceUnitManager = persistenceUnitManager;\n\t\tthis.jpaPropertiesFactory = jpaPropertiesFactory;\n\t\tthis.persistenceUnitRootLocation = persistenceUnitRootLocation;\n\t\tthis.fallbackBootstrapExecutor = fallbackBootstrapExecutor;\n\t}\n\n\t/**\n\t * Create a new {@link Builder} for a {@code EntityManagerFactory} using the settings\n\t * of the given instance, and the given {@link DataSource}.\n\t * @param dataSource the data source to use\n\t * @return a builder to create an {@code EntityManagerFactory}\n\t */\n\tpublic Builder dataSource(DataSource dataSource) {\n\t\treturn new Builder(dataSource);\n\t}\n\n\t/**\n\t * Configure the bootstrap executor to be used by the\n\t * {@link LocalContainerEntityManagerFactoryBean}.\n\t * @param bootstrapExecutor the executor\n\t */\n\tpublic void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) {\n\t\tthis.bootstrapExecutor = bootstrapExecutor;\n\t}\n\n\t/**\n\t * Require a bootstrap executor to be configured when the\n\t * {@link LocalEntityManagerFactoryBean} is built. If no bootstrap executor is\n\t * {@link #setBootstrapExecutor(AsyncTaskExecutor) explicitly set} and no\n\t * {@link #EntityManagerFactoryBuilder(JpaVendorAdapter, Function, PersistenceUnitManager, URL, AsyncTaskExecutor)\n\t * fallbackBootstrapExecutor} is available then the supplied exception is thrown.\n\t * @param exceptionSupplier a supplier providing the exception to throw\n\t * @since 4.1.0\n\t */\n\tpublic void requireBootstrapExecutor(Supplier<@Nullable ? extends RuntimeException> exceptionSupplier) {\n\t\tAssert.notNull(exceptionSupplier, \"'exceptionSupplier' must not be null\");\n\t\tthis.requireBootstrapExecutorExceptionSupplier = exceptionSupplier;\n\t}\n\n\t/**\n\t * Set the {@linkplain PersistenceUnitPostProcessor persistence unit post processors}\n\t * to be applied to the PersistenceUnitInfo used for creating the\n\t * {@link LocalContainerEntityManagerFactoryBean}.\n\t * @param persistenceUnitPostProcessors the persistence unit post processors to use\n\t */\n\tpublic void setPersistenceUnitPostProcessors(PersistenceUnitPostProcessor... persistenceUnitPostProcessors) {\n\t\tthis.persistenceUnitPostProcessors = new ArrayList<>(Arrays.asList(persistenceUnitPostProcessors));\n\t}\n\n\t/**\n\t * Add {@linkplain PersistenceUnitPostProcessor persistence unit post processors} to\n\t * be applied to the PersistenceUnitInfo used for creating the\n\t * {@link LocalContainerEntityManagerFactoryBean}.\n\t * @param persistenceUnitPostProcessors the persistence unit post processors to add\n\t * @since 4.1.0\n\t */\n\tpublic void addPersistenceUnitPostProcessors(PersistenceUnitPostProcessor... persistenceUnitPostProcessors) {\n\t\tif (this.persistenceUnitPostProcessors != null) {\n\t\t\tthis.persistenceUnitPostProcessors.addAll(Arrays.asList(persistenceUnitPostProcessors));\n\t\t}\n\t\telse {\n\t\t\tsetPersistenceUnitPostProcessors(persistenceUnitPostProcessors);\n\t\t}\n\t}\n\n\t/**\n\t * A fluent builder for a LocalContainerEntityManagerFactoryBean.\n\t */\n\tpublic final class Builder {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprivate @Nullable PersistenceManagedTypes managedTypes;\n\n\t\tprivate String @Nullable [] packagesToScan;\n\n\t\tprivate @Nullable String persistenceUnit;\n\n\t\tprivate final Map<String, Object> properties = new HashMap<>();\n\n\t\tprivate String @Nullable [] mappingResources;\n\n\t\tprivate boolean jta;\n\n\t\tprivate Builder(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\t/**\n\t\t * The persistence managed types, providing both the managed entities and packages\n\t\t * the entity manager should consider.\n\t\t * @param managedTypes managed types.\n\t\t * @return the builder for fluent usage\n\t\t */\n\t\tpublic Builder managedTypes(@Nullable PersistenceManagedTypes managedTypes) {\n\t\t\tthis.managedTypes = managedTypes;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * The names of packages to scan for {@code @Entity} annotations.\n\t\t * @param packagesToScan packages to scan\n\t\t * @return the builder for fluent usage\n\t\t * @see #managedTypes(PersistenceManagedTypes)\n\t\t */\n\t\tpublic Builder packages(String @Nullable ... packagesToScan) {\n\t\t\tthis.packagesToScan = packagesToScan;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * The classes whose packages should be scanned for {@code @Entity} annotations.\n\t\t * @param basePackageClasses the classes to use\n\t\t * @return the builder for fluent usage\n\t\t * @see #managedTypes(PersistenceManagedTypes)\n\t\t */\n\t\tpublic Builder packages(Class<?>... basePackageClasses) {\n\t\t\tSet<String> packages = new HashSet<>();\n\t\t\tfor (Class<?> type : basePackageClasses) {\n\t\t\t\tpackages.add(ClassUtils.getPackageName(type));\n\t\t\t}\n\t\t\tthis.packagesToScan = StringUtils.toStringArray(packages);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * The name of the persistence unit. If only building one EntityManagerFactory you\n\t\t * can omit this, but if there are more than one in the same application you\n\t\t * should give them distinct names.\n\t\t * @param persistenceUnit the name of the persistence unit\n\t\t * @return the builder for fluent usage\n\t\t */\n\t\tpublic Builder persistenceUnit(@Nullable String persistenceUnit) {\n\t\t\tthis.persistenceUnit = persistenceUnit;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Generic properties for standard JPA or vendor-specific configuration. These\n\t\t * properties override any values provided in the constructor.\n\t\t * @param properties the properties to use\n\t\t * @return the builder for fluent usage\n\t\t */\n\t\tpublic Builder properties(Map<String, ?> properties) {\n\t\t\tthis.properties.putAll(properties);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * The mapping resources (equivalent to {@code <mapping-file>} entries in\n\t\t * {@code persistence.xml}) for the persistence unit.\n\t\t * <p>\n\t\t * Note that mapping resources must be relative to the classpath root, e.g.\n\t\t * \"META-INF/mappings.xml\" or \"com/mycompany/repository/mappings.xml\", so that\n\t\t * they can be loaded through {@code ClassLoader.getResource()}.\n\t\t * @param mappingResources the mapping resources to use\n\t\t * @return the builder for fluent usage\n\t\t */\n\t\tpublic Builder mappingResources(String @Nullable ... mappingResources) {\n\t\t\tthis.mappingResources = mappingResources;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Configure if using a JTA {@link DataSource}, i.e. if\n\t\t * {@link LocalContainerEntityManagerFactoryBean#setDataSource(DataSource)\n\t\t * setDataSource} or\n\t\t * {@link LocalContainerEntityManagerFactoryBean#setJtaDataSource(DataSource)\n\t\t * setJtaDataSource} should be called on the\n\t\t * {@link LocalContainerEntityManagerFactoryBean}.\n\t\t * @param jta if the data source is JTA\n\t\t * @return the builder for fluent usage\n\t\t */\n\t\tpublic Builder jta(boolean jta) {\n\t\t\tthis.jta = jta;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Build a new {@link LocalContainerEntityManagerFactoryBean} instance from this\n\t\t * builder.\n\t\t * @return the built {@link LocalContainerEntityManagerFactoryBean}\n\t\t */\n\t\tpublic LocalContainerEntityManagerFactoryBean build() {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tLocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();\n\t\t\tmap.from(EntityManagerFactoryBuilder.this.persistenceUnitManager).to(factory::setPersistenceUnitManager);\n\t\t\tmap.from(this.persistenceUnit).to(factory::setPersistenceUnitName);\n\t\t\tmap.from(EntityManagerFactoryBuilder.this.jpaVendorAdapter).to(factory::setJpaVendorAdapter);\n\t\t\tmap.from(this.dataSource).to((!this.jta) ? factory::setDataSource : factory::setJtaDataSource);\n\t\t\tmap.from(this.managedTypes).to(factory::setManagedTypes);\n\t\t\tmap.from(this.packagesToScan).to(factory::setPackagesToScan);\n\t\t\tmap.from(this::jpaPropertyMap).to(factory.getJpaPropertyMap()::putAll);\n\t\t\tmap.from(this.mappingResources).whenNot(ObjectUtils::isEmpty).to(factory::setMappingResources);\n\t\t\tmap.from(EntityManagerFactoryBuilder.this.persistenceUnitRootLocation)\n\t\t\t\t.as(Object::toString)\n\t\t\t\t.to(factory::setPersistenceUnitRootLocation);\n\t\t\tmap.from(this::bootstrapExecutor).to(factory::setBootstrapExecutor);\n\t\t\tmap.from(EntityManagerFactoryBuilder.this.persistenceUnitPostProcessors)\n\t\t\t\t.as((postProcessors) -> postProcessors.toArray(PersistenceUnitPostProcessor[]::new))\n\t\t\t\t.to(factory::setPersistenceUnitPostProcessors);\n\t\t\treturn factory;\n\t\t}\n\n\t\tprivate Map<String, Object> jpaPropertyMap() {\n\t\t\tMap<String, Object> jpaPropertyMap = new LinkedHashMap<>();\n\t\t\tjpaPropertyMap.putAll(EntityManagerFactoryBuilder.this.jpaPropertiesFactory.apply(this.dataSource));\n\t\t\tjpaPropertyMap.putAll(this.properties);\n\t\t\treturn jpaPropertyMap;\n\t\t}\n\n\t\tprivate @Nullable AsyncTaskExecutor bootstrapExecutor() {\n\t\t\tif (EntityManagerFactoryBuilder.this.bootstrapExecutor != null) {\n\t\t\t\treturn EntityManagerFactoryBuilder.this.bootstrapExecutor;\n\t\t\t}\n\t\t\tif (EntityManagerFactoryBuilder.this.requireBootstrapExecutorExceptionSupplier != null) {\n\t\t\t\tif (EntityManagerFactoryBuilder.this.fallbackBootstrapExecutor != null) {\n\t\t\t\t\treturn EntityManagerFactoryBuilder.this.fallbackBootstrapExecutor;\n\t\t\t\t}\n\t\t\t\tRuntimeException ex = EntityManagerFactoryBuilder.this.requireBootstrapExecutorExceptionSupplier.get();\n\t\t\t\tthrow (ex != null) ? ex : new IllegalStateException(\"A bootstrap executor is required\");\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/JpaDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Set;\n\nimport jakarta.persistence.EntityManagerFactory;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link DatabaseInitializerDetector} for JPA.\n *\n * @author Andy Wilkinson\n */\nclass JpaDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\tprivate final Environment environment;\n\n\tJpaDatabaseInitializerDetector(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\tboolean deferred = this.environment.getProperty(\"spring.jpa.defer-datasource-initialization\", boolean.class,\n\t\t\t\tfalse);\n\t\treturn deferred ? Collections.singleton(EntityManagerFactory.class) : Collections.emptySet();\n\t}\n\n\t@Override\n\tpublic void detectionComplete(ConfigurableListableBeanFactory beanFactory, Set<String> dataSourceInitializerNames) {\n\t\tconfigureOtherInitializersToDependOnJpaInitializers(beanFactory, dataSourceInitializerNames);\n\t}\n\n\tprivate void configureOtherInitializersToDependOnJpaInitializers(ConfigurableListableBeanFactory beanFactory,\n\t\t\tSet<String> dataSourceInitializerNames) {\n\t\tSet<String> jpaInitializers = new HashSet<>();\n\t\tSet<String> otherInitializers = new HashSet<>(dataSourceInitializerNames);\n\t\tIterator<String> iterator = otherInitializers.iterator();\n\t\twhile (iterator.hasNext()) {\n\t\t\tString initializerName = iterator.next();\n\t\t\tBeanDefinition initializerDefinition = beanFactory.getBeanDefinition(initializerName);\n\t\t\tif (JpaDatabaseInitializerDetector.class.getName()\n\t\t\t\t.equals(initializerDefinition.getAttribute(DatabaseInitializerDetector.class.getName()))) {\n\t\t\t\titerator.remove();\n\t\t\t\tjpaInitializers.add(initializerName);\n\t\t\t}\n\t\t}\n\t\tfor (String otherInitializerName : otherInitializers) {\n\t\t\tBeanDefinition definition = beanFactory.getBeanDefinition(otherInitializerName);\n\t\t\tString[] dependencies = definition.getDependsOn();\n\t\t\tfor (String dependencyName : jpaInitializers) {\n\t\t\t\tdependencies = StringUtils.addStringToArray(dependencies, dependencyName);\n\t\t\t}\n\t\t\tdefinition.setDependsOn(dependencies);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/JpaDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport jakarta.persistence.EntityManagerFactory;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\nimport org.springframework.core.env.Environment;\nimport org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;\n\n/**\n * {@link DependsOnDatabaseInitializationDetector} for JPA.\n *\n * @author Andy Wilkinson\n */\nclass JpaDependsOnDatabaseInitializationDetector extends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\tprivate final Environment environment;\n\n\tJpaDependsOnDatabaseInitializationDetector(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\tboolean postpone = this.environment.getProperty(\"spring.jpa.defer-datasource-initialization\", boolean.class,\n\t\t\t\tfalse);\n\t\treturn postpone ? Collections.emptySet()\n\t\t\t\t: new HashSet<>(Arrays.asList(EntityManagerFactory.class, AbstractEntityManagerFactoryBean.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/BootstrapExecutorRequiredException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.util.Assert;\n\n/**\n * Exception thrown then the auto-configured\n * {@link LocalContainerEntityManagerFactoryBean} is missing a required bootstrap\n * executor.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\npublic class BootstrapExecutorRequiredException extends IllegalStateException {\n\n\tprivate final @Nullable String propertyName;\n\n\tprivate final @Nullable String propertyValue;\n\n\tpublic BootstrapExecutorRequiredException(String message) {\n\t\tthis(message, null);\n\t}\n\n\tpublic BootstrapExecutorRequiredException(String message, @Nullable Throwable cause) {\n\t\tthis(message, null, null, cause);\n\t}\n\n\tprivate BootstrapExecutorRequiredException(String message, @Nullable String propertyName,\n\t\t\t@Nullable String propertyValue, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t\tthis.propertyName = propertyName;\n\t\tthis.propertyValue = propertyValue;\n\t}\n\n\t@Nullable String getPropertyName() {\n\t\treturn this.propertyName;\n\t}\n\n\t@Nullable String getPropertyValue() {\n\t\treturn this.propertyValue;\n\t}\n\n\tpublic static BootstrapExecutorRequiredException ofProperty(String name, String value) {\n\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\tAssert.hasText(value, \"'value' must not be empty\");\n\t\tString message = \"An EntityManagerFactoryBean bootstrap executor is required when '%s' is set to '%s'\"\n\t\t\t.formatted(name, value);\n\t\treturn new BootstrapExecutorRequiredException(message, name, value, null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/BootstrapExecutorRequiredFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\n\n/**\n * {@link FailureAnalyzer} for {@link BootstrapExecutorRequiredException}.\n *\n * @author Phillip Webb\n */\nclass BootstrapExecutorRequiredFailureAnalyzer extends AbstractFailureAnalyzer<BootstrapExecutorRequiredException> {\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, BootstrapExecutorRequiredException cause) {\n\t\tStringBuilder action = new StringBuilder();\n\t\taction.append(actionPreamble(cause.getPropertyName()));\n\t\taction.append(\"\\t- With an auto-configured task executor \"\n\t\t\t\t+ \"(you may need to set 'spring.task.execution.mode' to 'force').\\n\");\n\t\taction.append(\"\\t- With an AsyncTaskExecutor bean named 'applicationTaskExecutor'.\\n\");\n\t\taction.append(\"\\t- Using a EntityManagerFactoryBuilderCustomizer.\\n\");\n\t\treturn new FailureAnalysis(cause.getMessage(), action.toString(), cause);\n\t}\n\n\tprivate String actionPreamble(@Nullable String propertyName) {\n\t\treturn (propertyName != null)\n\t\t\t\t? \"Use a different '%s' value or provide a bootstrap executor using one of the following methods:\\n\"\n\t\t\t\t\t.formatted(propertyName)\n\t\t\t\t: \"Provide a bootstrap executor using one of the following methods:\\n\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/EntityManagerFactoryBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport org.springframework.boot.jpa.EntityManagerFactoryBuilder;\n\n/**\n * Callback interface that can be used to customize the\n * {@link EntityManagerFactoryBuilder} to fine-tune its auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface EntityManagerFactoryBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(EntityManagerFactoryBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/EntityManagerFactoryDependsOnPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport jakarta.persistence.EntityManagerFactory;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;\nimport org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;\n\n/**\n * {@link BeanFactoryPostProcessor} that can be used to dynamically declare that all\n * {@link EntityManagerFactory} beans should \"depend on\" one or more specific beans.\n *\n * @author Marcel Overdijk\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Andrii Hrytsiuk\n * @since 4.0.0\n * @see BeanDefinition#setDependsOn(String[])\n */\npublic class EntityManagerFactoryDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {\n\n\t/**\n\t * Creates a new {@code EntityManagerFactoryDependsOnPostProcessor} that will set up\n\t * dependencies upon beans with the given names.\n\t * @param dependsOn names of the beans to depend upon\n\t */\n\tpublic EntityManagerFactoryDependsOnPostProcessor(String... dependsOn) {\n\t\tsuper(EntityManagerFactory.class, AbstractEntityManagerFactoryBean.class, dependsOn);\n\t}\n\n\t/**\n\t * Creates a new {@code EntityManagerFactoryDependsOnPostProcessor} that will set up\n\t * dependencies upon beans with the given types.\n\t * @param dependsOn types of the beans to depend upon\n\t */\n\tpublic EntityManagerFactoryDependsOnPostProcessor(Class<?>... dependsOn) {\n\t\tsuper(EntityManagerFactory.class, AbstractEntityManagerFactoryBean.class, dependsOn);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/JpaBaseConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport jakarta.persistence.EntityManagerFactory;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jpa.EntityManagerFactoryBuilder;\nimport org.springframework.boot.jpa.autoconfigure.JpaProperties.Bootstrap;\nimport org.springframework.boot.persistence.autoconfigure.EntityScanPackages;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizers;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.orm.jpa.JpaVendorAdapter;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.persistenceunit.ManagedClassNameFilter;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypes;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceManagedTypesScanner;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;\nimport org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;\nimport org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;\nimport org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionManager;\nimport org.springframework.transaction.jta.JtaTransactionManager;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.servlet.config.annotation.InterceptorRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * Base {@link EnableAutoConfiguration Auto-configuration} for JPA.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n * @author Eddú Meléndez\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(JpaProperties.class)\npublic abstract class JpaBaseConfiguration {\n\n\tprivate final DataSource dataSource;\n\n\tprivate final JpaProperties properties;\n\n\tprivate final @Nullable JtaTransactionManager jtaTransactionManager;\n\n\tprotected JpaBaseConfiguration(DataSource dataSource, JpaProperties properties,\n\t\t\tObjectProvider<JtaTransactionManager> jtaTransactionManager) {\n\t\tthis.dataSource = dataSource;\n\t\tthis.properties = properties;\n\t\tthis.jtaTransactionManager = jtaTransactionManager.getIfAvailable();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(TransactionManager.class)\n\tpublic PlatformTransactionManager transactionManager(\n\t\t\tObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {\n\t\tJpaTransactionManager transactionManager = new JpaTransactionManager();\n\t\ttransactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));\n\t\treturn transactionManager;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic JpaVendorAdapter jpaVendorAdapter() {\n\t\tAbstractJpaVendorAdapter adapter = createJpaVendorAdapter();\n\t\tadapter.setShowSql(this.properties.isShowSql());\n\t\tif (this.properties.getDatabase() != null) {\n\t\t\tadapter.setDatabase(this.properties.getDatabase());\n\t\t}\n\t\tif (this.properties.getDatabasePlatform() != null) {\n\t\t\tadapter.setDatabasePlatform(this.properties.getDatabasePlatform());\n\t\t}\n\t\tadapter.setGenerateDdl(this.properties.isGenerateDdl());\n\t\treturn adapter;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic EntityManagerFactoryBuilder entityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,\n\t\t\tObjectProvider<PersistenceUnitManager> persistenceUnitManager,\n\t\t\tObjectProvider<EntityManagerFactoryBuilderCustomizer> customizers,\n\t\t\tMap<String, AsyncTaskExecutor> taskExecutors) {\n\t\t@Nullable AsyncTaskExecutor bootstrapExecutor = determineBootstrapExecutor(taskExecutors);\n\t\tEntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(jpaVendorAdapter,\n\t\t\t\tthis::buildJpaProperties, persistenceUnitManager.getIfAvailable(), null, bootstrapExecutor);\n\t\tif (this.properties.getBootstrap() == Bootstrap.ASYNC) {\n\t\t\tbuilder.requireBootstrapExecutor(\n\t\t\t\t\t() -> BootstrapExecutorRequiredException.ofProperty(\"spring.jpa.bootstrap\", \"async\"));\n\t\t}\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder;\n\t}\n\n\tprivate @Nullable AsyncTaskExecutor determineBootstrapExecutor(Map<String, AsyncTaskExecutor> taskExecutors) {\n\t\treturn (taskExecutors.size() == 1) ? taskExecutors.values().iterator().next()\n\t\t\t\t: taskExecutors.get(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);\n\t}\n\n\tprivate Map<String, ?> buildJpaProperties(DataSource dataSource) {\n\t\tMap<String, Object> properties = new HashMap<>(this.properties.getProperties());\n\t\tMap<String, Object> vendorProperties = getVendorProperties(dataSource);\n\t\tcustomizeVendorProperties(vendorProperties);\n\t\tproperties.putAll(vendorProperties);\n\t\treturn properties;\n\t}\n\n\t@Bean\n\t@Primary\n\t@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })\n\tpublic LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder,\n\t\t\tPersistenceManagedTypes persistenceManagedTypes) {\n\t\treturn factoryBuilder.dataSource(this.dataSource)\n\t\t\t.managedTypes(persistenceManagedTypes)\n\t\t\t.mappingResources(getMappingResources())\n\t\t\t.jta(isJta())\n\t\t\t.build();\n\t}\n\n\tprotected abstract AbstractJpaVendorAdapter createJpaVendorAdapter();\n\n\t/**\n\t * Return the vendor-specific properties for the given {@link DataSource}.\n\t * @param dataSource the data source\n\t * @return the vendor properties\n\t */\n\tprotected abstract Map<String, Object> getVendorProperties(DataSource dataSource);\n\n\t/**\n\t * Customize vendor properties before they are used. Allows for post-processing (for\n\t * example to configure JTA specific settings).\n\t * @param vendorProperties the vendor properties to customize\n\t */\n\tprotected void customizeVendorProperties(Map<String, Object> vendorProperties) {\n\t}\n\n\tprivate String @Nullable [] getMappingResources() {\n\t\tList<String> mappingResources = this.properties.getMappingResources();\n\t\treturn (!ObjectUtils.isEmpty(mappingResources) ? StringUtils.toStringArray(mappingResources) : null);\n\t}\n\n\t/**\n\t * Return the JTA transaction manager.\n\t * @return the transaction manager or {@code null}\n\t */\n\tprotected @Nullable JtaTransactionManager getJtaTransactionManager() {\n\t\treturn this.jtaTransactionManager;\n\t}\n\n\t/**\n\t * Returns if a JTA {@link PlatformTransactionManager} is being used.\n\t * @return if a JTA transaction manager is being used\n\t */\n\tprotected final boolean isJta() {\n\t\treturn (this.jtaTransactionManager != null);\n\t}\n\n\t/**\n\t * Return the {@link JpaProperties}.\n\t * @return the properties\n\t */\n\tprotected final JpaProperties getProperties() {\n\t\treturn this.properties;\n\t}\n\n\t/**\n\t * Return the {@link DataSource}.\n\t * @return the data source\n\t */\n\tprotected final DataSource getDataSource() {\n\t\treturn this.dataSource;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class })\n\tstatic class PersistenceManagedTypesConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\t@ConditionalOnMissingBean\n\t\tstatic PersistenceManagedTypes persistenceManagedTypes(BeanFactory beanFactory, ResourceLoader resourceLoader,\n\t\t\t\tObjectProvider<ManagedClassNameFilter> managedClassNameFilter) {\n\t\t\tString[] packagesToScan = getPackagesToScan(beanFactory);\n\t\t\treturn new PersistenceManagedTypesScanner(resourceLoader, managedClassNameFilter.getIfAvailable())\n\t\t\t\t.scan(packagesToScan);\n\t\t}\n\n\t\tprivate static String[] getPackagesToScan(BeanFactory beanFactory) {\n\t\t\tList<String> packages = EntityScanPackages.get(beanFactory).getPackageNames();\n\t\t\tif (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) {\n\t\t\t\tpackages = AutoConfigurationPackages.get(beanFactory);\n\t\t\t}\n\t\t\treturn StringUtils.toStringArray(packages);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\t@ConditionalOnClass(WebMvcConfigurer.class)\n\t@ConditionalOnMissingBean({ OpenEntityManagerInViewInterceptor.class, OpenEntityManagerInViewFilter.class })\n\t@ConditionalOnMissingFilterBean(OpenEntityManagerInViewFilter.class)\n\t@ConditionalOnBooleanProperty(name = \"spring.jpa.open-in-view\", matchIfMissing = true)\n\tprotected static class JpaWebConfiguration {\n\n\t\tprivate static final Log logger = LogFactory.getLog(JpaWebConfiguration.class);\n\n\t\tprivate final JpaProperties jpaProperties;\n\n\t\tprotected JpaWebConfiguration(JpaProperties jpaProperties) {\n\t\t\tthis.jpaProperties = jpaProperties;\n\t\t}\n\n\t\t@Bean\n\t\tpublic OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {\n\t\t\tif (this.jpaProperties.getOpenInView() == null) {\n\t\t\t\tlogger.warn(\"spring.jpa.open-in-view is enabled by default. \"\n\t\t\t\t\t\t+ \"Therefore, database queries may be performed during view \"\n\t\t\t\t\t\t+ \"rendering. Explicitly configure spring.jpa.open-in-view to disable this warning\");\n\t\t\t}\n\t\t\treturn new OpenEntityManagerInViewInterceptor();\n\t\t}\n\n\t\t@Bean\n\t\tpublic WebMvcConfigurer openEntityManagerInViewInterceptorConfigurer(\n\t\t\t\tOpenEntityManagerInViewInterceptor interceptor) {\n\t\t\treturn new WebMvcConfigurer() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addInterceptors(InterceptorRegistry registry) {\n\t\t\t\t\tregistry.addWebRequestInterceptor(interceptor);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/JpaProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.orm.jpa.vendor.Database;\n\n/**\n * External configuration properties for a JPA EntityManagerFactory created by Spring.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.jpa\")\npublic class JpaProperties {\n\n\t/**\n\t * Additional native properties to set on the JPA provider.\n\t */\n\tprivate Map<String, String> properties = new HashMap<>();\n\n\t/**\n\t * Mapping resources (equivalent to \"mapping-file\" entries in persistence.xml).\n\t */\n\tprivate final List<String> mappingResources = new ArrayList<>();\n\n\t/**\n\t * Name of the target database to operate on, auto-detected by default. Can be\n\t * alternatively set using the \"Database\" enum.\n\t */\n\tprivate @Nullable String databasePlatform;\n\n\t/**\n\t * Target database to operate on, auto-detected by default. Can be alternatively set\n\t * using the \"databasePlatform\" property.\n\t */\n\tprivate @Nullable Database database;\n\n\t/**\n\t * Whether to initialize the schema on startup.\n\t */\n\tprivate boolean generateDdl;\n\n\t/**\n\t * Whether to enable logging of SQL statements.\n\t */\n\tprivate boolean showSql;\n\n\t/**\n\t * Register OpenEntityManagerInViewInterceptor. Binds a JPA EntityManager to the\n\t * thread for the entire processing of the request.\n\t */\n\tprivate @Nullable Boolean openInView;\n\n\t/**\n\t * Bootstrap method to use.\n\t */\n\tprivate Bootstrap bootstrap = Bootstrap.DEFAULT;\n\n\tpublic Map<String, String> getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tpublic void setProperties(Map<String, String> properties) {\n\t\tthis.properties = properties;\n\t}\n\n\tpublic List<String> getMappingResources() {\n\t\treturn this.mappingResources;\n\t}\n\n\tpublic @Nullable String getDatabasePlatform() {\n\t\treturn this.databasePlatform;\n\t}\n\n\tpublic void setDatabasePlatform(@Nullable String databasePlatform) {\n\t\tthis.databasePlatform = databasePlatform;\n\t}\n\n\tpublic @Nullable Database getDatabase() {\n\t\treturn this.database;\n\t}\n\n\tpublic void setDatabase(@Nullable Database database) {\n\t\tthis.database = database;\n\t}\n\n\tpublic boolean isGenerateDdl() {\n\t\treturn this.generateDdl;\n\t}\n\n\tpublic void setGenerateDdl(boolean generateDdl) {\n\t\tthis.generateDdl = generateDdl;\n\t}\n\n\tpublic boolean isShowSql() {\n\t\treturn this.showSql;\n\t}\n\n\tpublic void setShowSql(boolean showSql) {\n\t\tthis.showSql = showSql;\n\t}\n\n\tpublic @Nullable Boolean getOpenInView() {\n\t\treturn this.openInView;\n\t}\n\n\tpublic void setOpenInView(@Nullable Boolean openInView) {\n\t\tthis.openInView = openInView;\n\t}\n\n\tpublic Bootstrap getBootstrap() {\n\t\treturn this.bootstrap;\n\t}\n\n\tpublic void setBootstrap(Bootstrap bootstrap) {\n\t\tthis.bootstrap = bootstrap;\n\t}\n\n\t/**\n\t * Bootstrap methods that can be used with JPA.\n\t */\n\tpublic enum Bootstrap {\n\n\t\t/**\n\t\t * Default JPA bootstrapping.\n\t\t */\n\t\tDEFAULT,\n\n\t\t/**\n\t\t * Asynchronous JPA bootstrapping. The ApplicationContext must either have a\n\t\t * single AsyncTaskExecutor bean, or an AsyncTaskExecutor bean named\n\t\t * 'applicationTaskExecutor'.\n\t\t */\n\t\tASYNC\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Base Auto-configuration for JPA and Spring ORM.\n */\n@NullMarked\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/java/org/springframework/boot/jpa/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * JPA Support classes.\n */\n@NullMarked\npackage org.springframework.boot.jpa;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.jpa.open-in-view\",\n      \"defaultValue\": true\n    }\n  ],\n  \"hints\": [\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/main/resources/META-INF/spring.factories",
    "content": "# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.jpa.autoconfigure.BootstrapExecutorRequiredFailureAnalyzer\n\n# Database Initializer Detectors\norg.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\\\norg.springframework.boot.jpa.JpaDatabaseInitializerDetector\n\n# Depends On Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.jpa.JpaDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "module/spring-boot-jpa/src/test/java/org/springframework/boot/jpa/EntityManagerFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport javax.sql.DataSource;\n\nimport jakarta.persistence.spi.PersistenceProvider;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;\nimport org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EntityManagerFactoryBuilder}.\n *\n * @author Stephane Nicoll\n */\nclass EntityManagerFactoryBuilderTests {\n\n\t@Test\n\tvoid setPersistenceUnitPostProcessorsWhenEmpty() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tPersistenceUnitPostProcessor postProcessor = mock();\n\t\tPersistenceUnitPostProcessor postProcessor2 = mock();\n\t\tbuilder.setPersistenceUnitPostProcessors(postProcessor, postProcessor2);\n\t\tassertThat(builder).extracting(\"persistenceUnitPostProcessors\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.containsExactly(postProcessor, postProcessor2);\n\t}\n\n\t@Test\n\tvoid addPersistenceUnitPostProcessorsWhenEmpty() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tPersistenceUnitPostProcessor postProcessor = mock();\n\t\tPersistenceUnitPostProcessor postProcessor2 = mock();\n\t\tbuilder.addPersistenceUnitPostProcessors(postProcessor, postProcessor2);\n\t\tassertThat(builder).extracting(\"persistenceUnitPostProcessors\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.containsExactly(postProcessor, postProcessor2);\n\t}\n\n\t@Test\n\tvoid setPersistenceUnitPostProcessorsWhenNotEmpty() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tPersistenceUnitPostProcessor postProcessor = mock();\n\t\tbuilder.addPersistenceUnitPostProcessors(postProcessor);\n\t\tPersistenceUnitPostProcessor postProcessor2 = mock();\n\t\tPersistenceUnitPostProcessor postProcessor3 = mock();\n\t\tbuilder.setPersistenceUnitPostProcessors(postProcessor2, postProcessor3);\n\t\tassertThat(builder).extracting(\"persistenceUnitPostProcessors\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.containsExactly(postProcessor2, postProcessor3);\n\t}\n\n\t@Test\n\tvoid addPersistenceUnitPostProcessorsWhenNotEmpty() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tPersistenceUnitPostProcessor postProcessor = mock();\n\t\tbuilder.addPersistenceUnitPostProcessors(postProcessor);\n\t\tPersistenceUnitPostProcessor postProcessor2 = mock();\n\t\tbuilder.addPersistenceUnitPostProcessors(postProcessor2);\n\t\tassertThat(builder).extracting(\"persistenceUnitPostProcessors\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.containsExactly(postProcessor, postProcessor2);\n\t}\n\n\t@Test\n\tvoid requireBootstrapExecutorWhenExecutorProvidedDoesNotThrow() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tbuilder.requireBootstrapExecutor(() -> new IllegalStateException(\"BAD\"));\n\t\tbuilder.setBootstrapExecutor(new SimpleAsyncTaskExecutor());\n\t\tDataSource dataSource = mock();\n\t\tassertThatNoException().isThrownBy(builder.dataSource(dataSource)::build);\n\t}\n\n\t@Test\n\tvoid requireBootstrapExecutorWhenFallbackExecutorProvidesExecutorDoesNotThrow() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder(new SimpleAsyncTaskExecutor());\n\t\tbuilder.requireBootstrapExecutor(() -> new IllegalStateException(\"BAD\"));\n\t\tDataSource dataSource = mock();\n\t\tassertThatNoException().isThrownBy(builder.dataSource(dataSource)::build);\n\t}\n\n\t@Test\n\tvoid requireBootstrapExecutorWhenExecutorAndNoFallbackExecutorThrowsException() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tbuilder.requireBootstrapExecutor(() -> new IllegalStateException(\"BAD\"));\n\t\tDataSource dataSource = mock();\n\t\tassertThatIllegalStateException().isThrownBy(builder.dataSource(dataSource)::build).withMessage(\"BAD\");\n\t}\n\n\t@Test\n\tvoid requireBootstrapExecutorWhenSupplierReturnsNullExecutorAndNoFallbackExecutorThrowsException() {\n\t\tEntityManagerFactoryBuilder builder = createEmptyBuilder();\n\t\tbuilder.requireBootstrapExecutor(() -> null);\n\t\tDataSource dataSource = mock();\n\t\tassertThatIllegalStateException().isThrownBy(builder.dataSource(dataSource)::build)\n\t\t\t.withMessage(\"A bootstrap executor is required\");\n\t}\n\n\tprivate EntityManagerFactoryBuilder createEmptyBuilder() {\n\t\treturn createEmptyBuilder(null);\n\t}\n\n\tprivate EntityManagerFactoryBuilder createEmptyBuilder(@Nullable AsyncTaskExecutor fallbackBootstrapExecutor) {\n\t\tFunction<DataSource, Map<String, ?>> jpaPropertiesFactory = (dataSource) -> Collections.emptyMap();\n\t\treturn new EntityManagerFactoryBuilder(new TestJpaVendorAdapter(), jpaPropertiesFactory, null, null,\n\t\t\t\tfallbackBootstrapExecutor);\n\t}\n\n\tstatic class TestJpaVendorAdapter extends AbstractJpaVendorAdapter {\n\n\t\t@Override\n\t\tpublic PersistenceProvider getPersistenceProvider() {\n\t\t\treturn mock();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa/src/test/java/org/springframework/boot/jpa/autoconfigure/BootstrapExecutorRequiredFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BootstrapExecutorRequiredFailureAnalyzer}.\n *\n * @author Phillip Webb\n */\nclass BootstrapExecutorRequiredFailureAnalyzerTests {\n\n\tprivate final BootstrapExecutorRequiredFailureAnalyzer analyzer = new BootstrapExecutorRequiredFailureAnalyzer();\n\n\t@Test\n\tvoid analyzeWhenBootstrapExecutorRequiredExceptionWithProperties() {\n\t\tBootstrapExecutorRequiredException exception = BootstrapExecutorRequiredException.ofProperty(\"testname\",\n\t\t\t\t\"testvalue\");\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription()).isEqualTo(\n\t\t\t\t\"An EntityManagerFactoryBean bootstrap executor is required when 'testname' is set to 'testvalue'\");\n\t\tassertThat(result.getAction()).isEqualTo(\n\t\t\t\t\"\"\"\n\t\t\t\t\t\tUse a different 'testname' value or provide a bootstrap executor using one of the following methods:\n\t\t\t\t\t\t\t- With an auto-configured task executor (you may need to set 'spring.task.execution.mode' to 'force').\n\t\t\t\t\t\t\t- With an AsyncTaskExecutor bean named 'applicationTaskExecutor'.\n\t\t\t\t\t\t\t- Using a EntityManagerFactoryBuilderCustomizer.\n\t\t\t\t\t\t\t\"\"\");\n\t}\n\n\t@Test\n\tvoid analyzeWhenBootstrapExecutorRequiredExceptionWithMessage() {\n\t\tBootstrapExecutorRequiredException exception = new BootstrapExecutorRequiredException(\"A custom message\");\n\t\tFailureAnalysis result = this.analyzer.analyze(exception);\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getDescription()).isEqualTo(\"A custom message\");\n\t\tassertThat(result.getAction()).isEqualTo(\n\t\t\t\t\"\"\"\n\t\t\t\t\t\tProvide a bootstrap executor using one of the following methods:\n\t\t\t\t\t\t\t- With an auto-configured task executor (you may need to set 'spring.task.execution.mode' to 'force').\n\t\t\t\t\t\t\t- With an AsyncTaskExecutor bean named 'applicationTaskExecutor'.\n\t\t\t\t\t\t\t- Using a EntityManagerFactoryBuilderCustomizer.\n\t\t\t\t\t\t\t\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot JPA Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-jdbc-test\"))\n\tapi(project(\":module:spring-boot-jpa\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.jetbrains.kotlin:kotlin-stdlib\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/main/java/org/springframework/boot/jpa/test/autoconfigure/AutoConfigureTestEntityManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration of a\n * {@link TestEntityManager}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see TestEntityManagerAutoConfiguration\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureTestEntityManager {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/main/java/org/springframework/boot/jpa/test/autoconfigure/TestEntityManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.test.autoconfigure;\n\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.PersistenceUnitUtil;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.orm.jpa.EntityManagerFactoryUtils;\nimport org.springframework.util.Assert;\n\n/**\n * Alternative to {@link EntityManager} for use in JPA tests. Provides a subset of\n * {@link EntityManager} methods that are useful for tests as well as helper methods for\n * common testing tasks such as {@link #persistFlushFind(Object) persist/flush/find}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class TestEntityManager {\n\n\tprivate final EntityManagerFactory entityManagerFactory;\n\n\t/**\n\t * Create a new {@link TestEntityManager} instance for the given\n\t * {@link EntityManagerFactory}.\n\t * @param entityManagerFactory the source entity manager factory\n\t */\n\tpublic TestEntityManager(EntityManagerFactory entityManagerFactory) {\n\t\tAssert.notNull(entityManagerFactory, \"'entityManagerFactory' must not be null\");\n\t\tthis.entityManagerFactory = entityManagerFactory;\n\t}\n\n\t/**\n\t * Make an instance managed and persistent then return its ID. Delegates to\n\t * {@link EntityManager#persist(Object)} then {@link #getId(Object)}.\n\t * <p>\n\t * Helpful when setting up test data in a test: <pre class=\"code\">\n\t * Object entityId = this.testEntityManager.persist(new MyEntity(\"Spring\"));\n\t * </pre>\n\t * @param entity the source entity\n\t * @return the ID of the newly persisted entity\n\t */\n\tpublic @Nullable Object persistAndGetId(Object entity) {\n\t\tpersist(entity);\n\t\treturn getId(entity);\n\t}\n\n\t/**\n\t * Make an instance managed and persistent then return its ID. Delegates to\n\t * {@link EntityManager#persist(Object)} then {@link #getId(Object, Class)}.\n\t * <p>\n\t * Helpful when setting up test data in a test: <pre class=\"code\">\n\t * Long entityId = this.testEntityManager.persist(new MyEntity(\"Spring\"), Long.class);\n\t * </pre>\n\t * @param <T> the ID type\n\t * @param entity the source entity\n\t * @param idType the ID type\n\t * @return the ID of the newly persisted entity\n\t */\n\tpublic <T> @Nullable T persistAndGetId(Object entity, Class<T> idType) {\n\t\tpersist(entity);\n\t\treturn getId(entity, idType);\n\t}\n\n\t/**\n\t * Make an instance managed and persistent. Delegates to\n\t * {@link EntityManager#persist(Object)} then returns the original source entity.\n\t * <p>\n\t * Helpful when setting up test data in a test: <pre class=\"code\">\n\t * MyEntity entity = this.testEntityManager.persist(new MyEntity(\"Spring\"));\n\t * </pre>\n\t * @param <E> the entity type\n\t * @param entity the entity to persist\n\t * @return the persisted entity\n\t */\n\tpublic <E> E persist(E entity) {\n\t\tgetEntityManager().persist(entity);\n\t\treturn entity;\n\t}\n\n\t/**\n\t * Make an instance managed and persistent, synchronize the persistence context to the\n\t * underlying database and finally find the persisted entity by its ID. Delegates to\n\t * {@link #persistAndFlush(Object)} then {@link #find(Class, Object)} with the\n\t * {@link #getId(Object) entity ID}.\n\t * <p>\n\t * Helpful when ensuring that entity data is actually written and read from the\n\t * underlying database correctly.\n\t * @param <E> the entity type\n\t * @param entity the entity to persist\n\t * @return the entity found using the ID of the persisted entity\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <E> E persistFlushFind(E entity) {\n\t\tEntityManager entityManager = getEntityManager();\n\t\tpersistAndFlush(entity);\n\t\tObject id = getId(entity);\n\t\tentityManager.detach(entity);\n\t\treturn (E) entityManager.find(entity.getClass(), id);\n\t}\n\n\t/**\n\t * Make an instance managed and persistent then synchronize the persistence context to\n\t * the underlying database. Delegates to {@link EntityManager#persist(Object)} then\n\t * {@link #flush()} and finally returns the original source entity.\n\t * <p>\n\t * Helpful when setting up test data in a test: <pre class=\"code\">\n\t * MyEntity entity = this.testEntityManager.persistAndFlush(new MyEntity(\"Spring\"));\n\t * </pre>\n\t * @param <E> the entity type\n\t * @param entity the entity to persist\n\t * @return the persisted entity\n\t */\n\tpublic <E> E persistAndFlush(E entity) {\n\t\tpersist(entity);\n\t\tflush();\n\t\treturn entity;\n\t}\n\n\t/**\n\t * Merge the state of the given entity into the current persistence context. Delegates\n\t * to {@link EntityManager#merge(Object)}\n\t * @param <E> the entity type\n\t * @param entity the entity to merge\n\t * @return the merged entity\n\t */\n\tpublic <E> E merge(E entity) {\n\t\treturn getEntityManager().merge(entity);\n\t}\n\n\t/**\n\t * Remove the entity instance. Delegates to {@link EntityManager#remove(Object)}\n\t * @param entity the entity to remove\n\t */\n\tpublic void remove(Object entity) {\n\t\tgetEntityManager().remove(entity);\n\t}\n\n\t/**\n\t * Find by primary key. Delegates to {@link EntityManager#find(Class, Object)}.\n\t * @param <E> the entity type\n\t * @param entityClass the entity class\n\t * @param primaryKey the entity primary key\n\t * @return the found entity or {@code null} if the entity does not exist\n\t * @see #getId(Object)\n\t */\n\tpublic <E> @Nullable E find(Class<E> entityClass, Object primaryKey) {\n\t\treturn getEntityManager().find(entityClass, primaryKey);\n\t}\n\n\t/**\n\t * Synchronize the persistence context to the underlying database. Delegates to\n\t * {@link EntityManager#flush()}.\n\t */\n\tpublic void flush() {\n\t\tgetEntityManager().flush();\n\t}\n\n\t/**\n\t * Refresh the state of the instance from the database, overwriting changes made to\n\t * the entity, if any. Delegates to {@link EntityManager#refresh(Object)}.\n\t * @param <E> the entity type\n\t * @param entity the entity to refresh\n\t * @return the refreshed entity\n\t */\n\tpublic <E> E refresh(E entity) {\n\t\tgetEntityManager().refresh(entity);\n\t\treturn entity;\n\t}\n\n\t/**\n\t * Clear the persistence context, causing all managed entities to become detached.\n\t * Delegates to {@link EntityManager#clear()}\n\t */\n\tpublic void clear() {\n\t\tgetEntityManager().clear();\n\t}\n\n\t/**\n\t * Remove the given entity from the persistence context, causing a managed entity to\n\t * become detached. Delegates to {@link EntityManager#detach(Object)}.\n\t * @param entity the entity to detach.\n\t */\n\tpublic void detach(Object entity) {\n\t\tgetEntityManager().detach(entity);\n\t}\n\n\t/**\n\t * Return the ID of the given entity. Delegates to\n\t * {@link PersistenceUnitUtil#getIdentifier(Object)}.\n\t * @param entity the source entity\n\t * @return the ID of the entity or {@code null}\n\t * @see #getId(Object, Class)\n\t */\n\tpublic @Nullable Object getId(Object entity) {\n\t\treturn this.entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity);\n\t}\n\n\t/**\n\t * Return the ID of the given entity cast to a specific type. Delegates to\n\t * {@link PersistenceUnitUtil#getIdentifier(Object)}.\n\t * @param <T> the ID type\n\t * @param entity the source entity\n\t * @param idType the expected ID type\n\t * @return the ID of the entity or {@code null}\n\t * @see #getId(Object)\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> @Nullable T getId(Object entity, Class<T> idType) {\n\t\tObject id = getId(entity);\n\t\tAssert.isInstanceOf(idType, id, \"ID mismatch:\");\n\t\treturn (T) id;\n\t}\n\n\t/**\n\t * Return the underlying {@link EntityManager} that's actually used to perform all\n\t * operations.\n\t * @return the entity manager\n\t */\n\tpublic final EntityManager getEntityManager() {\n\t\tEntityManager manager = EntityManagerFactoryUtils.getTransactionalEntityManager(this.entityManagerFactory);\n\t\tAssert.state(manager != null, \"No transactional EntityManager found, is your test running in a transaction?\");\n\t\treturn manager;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/main/java/org/springframework/boot/jpa/test/autoconfigure/TestEntityManagerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.test.autoconfigure;\n\nimport jakarta.persistence.EntityManagerFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for {@link TestEntityManager}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see AutoConfigureTestEntityManager\n */\n@AutoConfiguration(afterName = \"org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\")\n@ConditionalOnClass({ EntityManagerFactory.class })\npublic final class TestEntityManagerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tTestEntityManager testEntityManager(EntityManagerFactory entityManagerFactory) {\n\t\treturn new TestEntityManager(entityManagerFactory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/main/java/org/springframework/boot/jpa/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JPA tests.\n */\n@NullMarked\npackage org.springframework.boot.jpa.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/main/kotlin/org/springframework/boot/jpa/test/autoconfigure/TestEntityManagerExtensions.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.test.autoconfigure\n\n/**\n * Extension for [TestEntityManager.find] providing a `find<MyEntity>(...)`\n * variant leveraging Kotlin reified type parameters.\n *\n * @param primaryKey the primary key of the entity\n * @author Beom Su\n * @since 4.1.0\n */\ninline fun <reified E : Any> TestEntityManager.find(primaryKey: Any): E? =\n\t\tfind(E::class.java, primaryKey)\n\n/**\n * Extension for [TestEntityManager.persistAndGetId] providing a\n * `persistAndGetId<Long>(...)` variant leveraging Kotlin reified type parameters.\n *\n * @param entity the source entity\n * @author Beom Su\n * @since 4.1.0\n */\ninline fun <reified T : Any> TestEntityManager.persistAndGetId(entity: Any): T? =\n\t\tpersistAndGetId(entity, T::class.java)\n\n/**\n * Extension for [TestEntityManager.getId] providing a `getId<MyEntity>(...)`\n * variant leveraging Kotlin reified type parameters.\n *\n * @param entity the source entity\n * @author Beom Su\n * @since 4.1.0\n */\ninline fun <reified T : Any> TestEntityManager.getId(entity: Any): T? =\n\t\tgetId(entity, T::class.java)\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/main/resources/META-INF/spring/org.springframework.boot.jpa.test.autoconfigure.AutoConfigureTestEntityManager.imports",
    "content": "org.springframework.boot.jpa.test.autoconfigure.TestEntityManagerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/test/java/org/springframework/boot/jpa/test/autoconfigure/TestEntityManagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.test.autoconfigure;\n\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.PersistenceUnitUtil;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.orm.jpa.EntityManagerHolder;\nimport org.springframework.transaction.support.TransactionSynchronizationManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link TestEntityManager}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass TestEntityManagerTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate EntityManagerFactory entityManagerFactory;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate EntityManager entityManager;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate PersistenceUnitUtil persistenceUnitUtil;\n\n\tprivate TestEntityManager testEntityManager;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.testEntityManager = new TestEntityManager(this.entityManagerFactory);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenEntityManagerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TestEntityManager(null))\n\t\t\t.withMessageContaining(\"'entityManagerFactory' must not be null\");\n\t}\n\n\t@Test\n\tvoid persistAndGetIdShouldPersistAndGetId() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManagerFactory.getPersistenceUnitUtil()).willReturn(this.persistenceUnitUtil);\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);\n\t\tObject result = this.testEntityManager.persistAndGetId(entity);\n\t\tthen(this.entityManager).should().persist(entity);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid persistAndGetIdForTypeShouldPersistAndGetId() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManagerFactory.getPersistenceUnitUtil()).willReturn(this.persistenceUnitUtil);\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);\n\t\tInteger result = this.testEntityManager.persistAndGetId(entity, Integer.class);\n\t\tthen(this.entityManager).should().persist(entity);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid persistShouldPersist() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tTestEntity result = this.testEntityManager.persist(entity);\n\t\tthen(this.entityManager).should().persist(entity);\n\t\tassertThat(result).isSameAs(entity);\n\t}\n\n\t@Test\n\tvoid persistAndFlushShouldPersistAndFlush() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tTestEntity result = this.testEntityManager.persistAndFlush(entity);\n\t\tthen(this.entityManager).should().persist(entity);\n\t\tthen(this.entityManager).should().flush();\n\t\tassertThat(result).isSameAs(entity);\n\t}\n\n\t@Test\n\tvoid persistFlushFindShouldPersistAndFlushAndFind() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tTestEntity found = new TestEntity();\n\t\tgiven(this.entityManagerFactory.getPersistenceUnitUtil()).willReturn(this.persistenceUnitUtil);\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);\n\t\tgiven(this.entityManager.find(TestEntity.class, 123)).willReturn(found);\n\t\tTestEntity result = this.testEntityManager.persistFlushFind(entity);\n\t\tthen(this.entityManager).should().persist(entity);\n\t\tthen(this.entityManager).should().flush();\n\t\tassertThat(result).isSameAs(found);\n\t}\n\n\t@Test\n\tvoid mergeShouldMerge() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManager.merge(entity)).willReturn(entity);\n\t\tTestEntity result = this.testEntityManager.merge(entity);\n\t\tthen(this.entityManager).should().merge(entity);\n\t\tassertThat(result).isSameAs(entity);\n\t}\n\n\t@Test\n\tvoid removeShouldRemove() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tthis.testEntityManager.remove(entity);\n\t\tthen(this.entityManager).should().remove(entity);\n\t}\n\n\t@Test\n\tvoid findShouldFind() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManager.find(TestEntity.class, 123)).willReturn(entity);\n\t\tTestEntity result = this.testEntityManager.find(TestEntity.class, 123);\n\t\tassertThat(result).isSameAs(entity);\n\t}\n\n\t@Test\n\tvoid flushShouldFlush() {\n\t\tbindEntityManager();\n\t\tthis.testEntityManager.flush();\n\t\tthen(this.entityManager).should().flush();\n\t}\n\n\t@Test\n\tvoid refreshShouldRefresh() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tthis.testEntityManager.refresh(entity);\n\t\tthen(this.entityManager).should().refresh(entity);\n\t}\n\n\t@Test\n\tvoid clearShouldClear() {\n\t\tbindEntityManager();\n\t\tthis.testEntityManager.clear();\n\t\tthen(this.entityManager).should().clear();\n\t}\n\n\t@Test\n\tvoid detachShouldDetach() {\n\t\tbindEntityManager();\n\t\tTestEntity entity = new TestEntity();\n\t\tthis.testEntityManager.detach(entity);\n\t\tthen(this.entityManager).should().detach(entity);\n\t}\n\n\t@Test\n\tvoid getIdForTypeShouldGetId() {\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManagerFactory.getPersistenceUnitUtil()).willReturn(this.persistenceUnitUtil);\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);\n\t\tInteger result = this.testEntityManager.getId(entity, Integer.class);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid getIdForTypeWhenTypeIsWrongShouldThrowException() {\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManagerFactory.getPersistenceUnitUtil()).willReturn(this.persistenceUnitUtil);\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.testEntityManager.getId(entity, Long.class))\n\t\t\t.withMessageContaining(\"ID mismatch: Object of class [java.lang.Integer] \"\n\t\t\t\t\t+ \"must be an instance of class java.lang.Long\");\n\t}\n\n\t@Test\n\tvoid getIdShouldGetId() {\n\t\tTestEntity entity = new TestEntity();\n\t\tgiven(this.entityManagerFactory.getPersistenceUnitUtil()).willReturn(this.persistenceUnitUtil);\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123);\n\t\tObject result = this.testEntityManager.getId(entity);\n\t\tassertThat(result).isEqualTo(123);\n\t}\n\n\t@Test\n\tvoid getEntityManagerShouldGetEntityManager() {\n\t\tbindEntityManager();\n\t\tassertThat(this.testEntityManager.getEntityManager()).isEqualTo(this.entityManager);\n\t}\n\n\t@Test\n\tvoid getEntityManagerWhenNotSetShouldThrowException() {\n\t\tassertThatIllegalStateException().isThrownBy(this.testEntityManager::getEntityManager)\n\t\t\t.withMessageContaining(\"No transactional EntityManager found\");\n\t}\n\n\tprivate void bindEntityManager() {\n\t\tEntityManagerHolder holder = new EntityManagerHolder(this.entityManager);\n\t\tTransactionSynchronizationManager.bindResource(this.entityManagerFactory, holder);\n\t}\n\n\tstatic class TestEntity {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jpa-test/src/test/kotlin/org/springframework/boot/jpa/test/autoconfigure/TestEntityManagerExtensionsTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jpa.test.autoconfigure\n\nimport jakarta.persistence.EntityManager\nimport jakarta.persistence.EntityManagerFactory\nimport jakarta.persistence.PersistenceUnitUtil\nimport org.assertj.core.api.Assertions.assertThat\nimport org.junit.jupiter.api.BeforeEach\nimport org.junit.jupiter.api.Test\nimport org.junit.jupiter.api.extension.ExtendWith\nimport org.mockito.BDDMockito.given\nimport org.mockito.BDDMockito.then\nimport org.mockito.Mock\nimport org.mockito.junit.jupiter.MockitoExtension\nimport org.springframework.orm.jpa.EntityManagerHolder\nimport org.springframework.transaction.support.TransactionSynchronizationManager\n\n/**\n * Tests for [TestEntityManager] Kotlin extensions.\n *\n * @author Beom Su\n * @since 4.1.0\n */\n@ExtendWith(MockitoExtension::class)\nclass TestEntityManagerExtensionsTests {\n\n\t@Mock\n\tprivate lateinit var entityManagerFactory: EntityManagerFactory\n\n\t@Mock\n\tprivate lateinit var entityManager: EntityManager\n\n\t@Mock\n\tprivate lateinit var persistenceUnitUtil: PersistenceUnitUtil\n\n\tprivate lateinit var testEntityManager: TestEntityManager\n\n\t@BeforeEach\n\tfun setup() {\n\t\tthis.testEntityManager = TestEntityManager(this.entityManagerFactory)\n\t}\n\n\t@Test\n\tfun `find with reified type parameter`() {\n\t\tbindEntityManager()\n\t\tval entity = TestEntity()\n\t\tgiven(this.entityManager.find(TestEntity::class.java, 123)).willReturn(entity)\n\t\tval result = this.testEntityManager.find<TestEntity>(123)\n\t\tassertThat(result).isSameAs(entity)\n\t}\n\n\t@Test\n\tfun `persistAndGetId with reified type parameter`() {\n\t\tbindEntityManager()\n\t\tval entity = TestEntity()\n\t\tgiven(this.entityManagerFactory.persistenceUnitUtil).willReturn(this.persistenceUnitUtil)\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123)\n\t\tval result = this.testEntityManager.persistAndGetId<Int>(entity)\n\t\tthen(this.entityManager).should().persist(entity)\n\t\tassertThat(result).isEqualTo(123)\n\t}\n\n\t@Test\n\tfun `getId with reified type parameter`() {\n\t\tval entity = TestEntity()\n\t\tgiven(this.entityManagerFactory.persistenceUnitUtil).willReturn(this.persistenceUnitUtil)\n\t\tgiven(this.persistenceUnitUtil.getIdentifier(entity)).willReturn(123)\n\t\tval result = this.testEntityManager.getId<Int>(entity)\n\t\tassertThat(result).isEqualTo(123)\n\t}\n\n\tprivate fun bindEntityManager() {\n\t\tval holder = EntityManagerHolder(this.entityManager)\n\t\tTransactionSynchronizationManager.bindResource(this.entityManagerFactory, holder)\n\t}\n\n\tclass TestEntity\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot JSON-B\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"jakarta.json.bind:jakarta.json.bind-api\")\n\tapi(\"org.eclipse:yasson\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.eclipse:yasson\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/main/java/org/springframework/boot/jsonb/autoconfigure/JsonbAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport jakarta.json.bind.Jsonb;\nimport jakarta.json.bind.JsonbBuilder;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnResource;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for JSON-B.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Jsonb.class)\n@ConditionalOnResource(resources = { \"classpath:META-INF/services/jakarta.json.bind.spi.JsonbProvider\",\n\t\t\"classpath:META-INF/services/jakarta.json.spi.JsonProvider\" })\npublic final class JsonbAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJsonb jsonb() {\n\t\treturn JsonbBuilder.create();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/main/java/org/springframework/boot/jsonb/autoconfigure/JsonbTesterTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport jakarta.json.bind.Jsonb;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.test.autoconfigure.json.ConditionalOnJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonMarshalTesterRuntimeHints;\nimport org.springframework.boot.test.autoconfigure.json.JsonTesterFactoryBean;\nimport org.springframework.boot.test.json.JsonbTester;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.context.annotation.Scope;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link JsonbTester}.\n *\n * @author Phjllip Webb\n */\n@AutoConfiguration(after = JsonbAutoConfiguration.class)\n@ConditionalOnJsonTesters\nfinal class JsonbTesterTestAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnBean(Jsonb.class)\n\t@ImportRuntimeHints(JsonbJsonTesterRuntimeHints.class)\n\tFactoryBean<JsonbTester<?>> jsonbTesterFactoryBean(Jsonb jsonb) {\n\t\treturn new JsonTesterFactoryBean<>(JsonbTester.class, jsonb);\n\t}\n\n\tstatic class JsonbJsonTesterRuntimeHints extends JsonMarshalTesterRuntimeHints {\n\n\t\tJsonbJsonTesterRuntimeHints() {\n\t\t\tsuper(JsonbTester.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/main/java/org/springframework/boot/jsonb/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JSON-B.\n */\n@NullMarked\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.jsonb.autoconfigure.JsonbAutoConfiguration"
  },
  {
    "path": "module/spring-boot-jsonb/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJson.imports",
    "content": "org.springframework.boot.jsonb.autoconfigure.JsonbAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters.imports",
    "content": "org.springframework.boot.jsonb.autoconfigure.JsonbTesterTestAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/JsonTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Application for testing of {@link JsonTest @JsonTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\nclass JsonTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/JsonbAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport jakarta.json.bind.Jsonb;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonbAutoConfiguration}.\n *\n * @author Eddú Meléndez\n */\nclass JsonbAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class));\n\n\t@Test\n\tvoid jsonbRegistration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Jsonb.class);\n\t\t\tJsonb jsonb = context.getBean(Jsonb.class);\n\t\t\tassertThat(jsonb.toJson(new DataObject())).isEqualTo(\"{\\\"data\\\":\\\"hello\\\"}\");\n\t\t});\n\t}\n\n\tpublic class DataObject {\n\n\t\tprivate String data = \"hello\";\n\n\t\tpublic String getData() {\n\t\t\treturn this.data;\n\t\t}\n\n\t\tpublic void setData(String data) {\n\t\t\tthis.data = data;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/JsonbAutoConfigurationWithNoProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport jakarta.json.bind.Jsonb;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonbAutoConfiguration} when there is no provider available.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"yasson-*.jar\")\nclass JsonbAutoConfigurationWithNoProviderTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class));\n\n\t@Test\n\tvoid jsonbBacksOffWhenThereIsNoProvider() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Jsonb.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/JsonbTesterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.predicate.ReflectionHintsPredicates;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.autoconfigure.json.JsonTestersAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.json.JsonbTester;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JsonbTesterTestAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass JsonbTesterAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner().withConfiguration(AutoConfigurations\n\t\t.of(JsonTestersAutoConfiguration.class, JsonbAutoConfiguration.class, JsonbTesterTestAutoConfiguration.class));\n\n\t@Test\n\tvoid hintsAreContributed() {\n\t\tthis.runner.withPropertyValues(\"spring.test.jsontesters.enabled=true\").prepare((context) -> {\n\t\t\tTestGenerationContext generationContext = new TestGenerationContext();\n\t\t\tnew ApplicationContextAotGenerator().processAheadOfTime(\n\t\t\t\t\t(GenericApplicationContext) context.getSourceApplicationContext(), generationContext);\n\t\t\tReflectionHintsPredicates hints = RuntimeHintsPredicates.reflection();\n\t\t\tassertThat(hints.onType(JsonbTester.class)).accepts(generationContext.getRuntimeHints());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/JsonTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Application for testing of {@link JsonTest @JsonTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\nclass JsonTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/JsonTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jsonb.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.jsonb.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JsonbTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Eddú Meléndez\n */\n@JsonTest\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestIntegrationTests {\n\n\t@Autowired\n\tprivate JsonbTester<ExampleBasicObject> jsonbJson;\n\n\t@Test\n\tvoid jsonb() throws Exception {\n\t\tExampleBasicObject object = new ExampleBasicObject();\n\t\tobject.setValue(\"spring\");\n\t\tassertThat(this.jsonbJson.write(object)).isEqualToJson(\"example.json\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/JsonTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jsonb.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.jsonb.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JsonbTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JsonTest @JsonTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Phillip Webb\n */\n@JsonTest\n@AutoConfigureJsonTesters(enabled = false)\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass JsonTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired(required = false)\n\tprivate JsonbTester<ExampleBasicObject> jsonbTester;\n\n\t@Test\n\tvoid jsonb() {\n\t\tassertThat(this.jsonbTester).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/JsonbAutoConfigureJsonIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest;\n\nimport jakarta.json.bind.Jsonb;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Integration tests for {@link AutoConfigureJson @AutoConfigureJson} with JSON-B.\n *\n * @author Andy Wilkinson\n */\n@AutoConfigureJson\n@ExtendWith(SpringExtension.class)\nclass JsonbAutoConfigureJsonIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid jsonbIsAvailable() {\n\t\tassertThatNoException().isThrownBy(() -> this.context.getBean(Jsonb.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/SpringBootTestWithAutoConfigureJsonTestersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jsonb.autoconfigure.jsontest.app.ExampleBasicObject;\nimport org.springframework.boot.jsonb.autoconfigure.jsontest.app.ExampleJsonApplication;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.json.JsonbTester;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureJsonTesters @AutoConfigureJsonTesters}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureJsonTesters\n@ContextConfiguration(classes = ExampleJsonApplication.class)\nclass SpringBootTestWithAutoConfigureJsonTestersTests {\n\n\t@Autowired\n\tprivate JsonbTester<ExampleBasicObject> jsonbTester;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.jsonbTester).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/app/ExampleBasicObject.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest.app;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Example object to read/write as JSON.\n *\n * @author Phillip Webb\n */\npublic class ExampleBasicObject {\n\n\tprivate @Nullable String value;\n\n\tpublic @Nullable String getValue() {\n\t\treturn this.value;\n\t}\n\n\tpublic void setValue(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj != null && obj.getClass() == getClass()) {\n\t\t\treturn Objects.equals(this.value, ((ExampleBasicObject) obj).value);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hashCode(this.value);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/app/ExampleJsonApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.jsonb.autoconfigure.jsontest.app;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link JsonTest @JsonTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleJsonApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/app/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jsonb.autoconfigure.jsontest.app;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/java/org/springframework/boot/jsonb/autoconfigure/jsontest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.jsonb.autoconfigure.jsontest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-jsonb/src/test/resources/org/springframework/boot/jsonb/autoconfigure/jsontest/example.json",
    "content": "{\n   \"value\" : \"spring\"\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Kafka\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.kafka:spring-kafka\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"org.apache.kafka:kafka-streams\")\n\toptional(\"org.testcontainers:testcontainers-kafka\")\n\toptional(\"org.testcontainers:testcontainers-redpanda\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.springframework.kafka:spring-kafka-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/dockerTest/java/org/springframework/boot/kafka/testcontainers/ApacheKafkaContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.kafka.KafkaContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.kafka.autoconfigure.KafkaAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ApacheKafkaContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@TestPropertySource(properties = { \"spring.kafka.consumer.group-id=test-group\",\n\t\t\"spring.kafka.consumer.auto-offset-reset=earliest\" })\nclass ApacheKafkaContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final KafkaContainer kafka = TestImage.container(KafkaContainer.class);\n\n\t@Autowired\n\tprivate KafkaTemplate<String, String> kafkaTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToKafkaContainer() {\n\t\tthis.kafkaTemplate.send(\"test-topic\", \"test-data\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"test-data\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(KafkaAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@KafkaListener(topics = \"test-topic\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/dockerTest/java/org/springframework/boot/kafka/testcontainers/ConfluentKafkaContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.kafka.ConfluentKafkaContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.kafka.autoconfigure.KafkaAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConfluentKafkaContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@TestPropertySource(properties = { \"spring.kafka.consumer.group-id=test-group\",\n\t\t\"spring.kafka.consumer.auto-offset-reset=earliest\" })\nclass ConfluentKafkaContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ConfluentKafkaContainer kafka = TestImage.container(ConfluentKafkaContainer.class);\n\n\t@Autowired\n\tprivate KafkaTemplate<String, String> kafkaTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToKafkaContainer() {\n\t\tthis.kafkaTemplate.send(\"test-topic\", \"test-data\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(4))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"test-data\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(KafkaAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@KafkaListener(topics = \"test-topic\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/dockerTest/java/org/springframework/boot/kafka/testcontainers/RedpandaContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.redpanda.RedpandaContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.kafka.autoconfigure.KafkaAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RedpandaContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@TestPropertySource(properties = { \"spring.kafka.consumer.group-id=test-group\",\n\t\t\"spring.kafka.consumer.auto-offset-reset=earliest\" })\nclass RedpandaContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RedpandaContainer redpanda = TestImage.container(RedpandaContainer.class);\n\n\t@Autowired\n\tKafkaTemplate<String, String> kafkaTemplate;\n\n\t@Autowired\n\tTestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToRedpandaContainer() {\n\t\tthis.kafkaTemplate.send(\"test-topic\", \"test-data\");\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"test-data\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(KafkaAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@KafkaListener(topics = \"test-topic\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-kafka/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/ConcurrentKafkaListenerContainerFactoryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Listener;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;\nimport org.springframework.kafka.core.ConsumerFactory;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.listener.AfterRollbackProcessor;\nimport org.springframework.kafka.listener.BatchInterceptor;\nimport org.springframework.kafka.listener.CommonErrorHandler;\nimport org.springframework.kafka.listener.ConsumerAwareRebalanceListener;\nimport org.springframework.kafka.listener.ContainerProperties;\nimport org.springframework.kafka.listener.MessageListenerContainer;\nimport org.springframework.kafka.listener.RecordInterceptor;\nimport org.springframework.kafka.listener.adapter.RecordFilterStrategy;\nimport org.springframework.kafka.support.converter.BatchMessageConverter;\nimport org.springframework.kafka.support.converter.RecordMessageConverter;\nimport org.springframework.kafka.support.micrometer.KafkaListenerObservationConvention;\nimport org.springframework.kafka.transaction.KafkaAwareTransactionManager;\nimport org.springframework.util.Assert;\n\n/**\n * Configure {@link ConcurrentKafkaListenerContainerFactory} with sensible defaults tuned\n * using configuration properties.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code ConcurrentKafkaListenerContainerFactory} whose configuration is based upon that\n * produced by auto-configuration.\n *\n * @author Gary Russell\n * @author Eddú Meléndez\n * @author Thomas Kåsene\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class ConcurrentKafkaListenerContainerFactoryConfigurer {\n\n\tprivate @Nullable KafkaProperties properties;\n\n\tprivate @Nullable BatchMessageConverter batchMessageConverter;\n\n\tprivate @Nullable RecordMessageConverter recordMessageConverter;\n\n\tprivate @Nullable RecordFilterStrategy<Object, Object> recordFilterStrategy;\n\n\tprivate @Nullable KafkaTemplate<Object, Object> replyTemplate;\n\n\tprivate @Nullable KafkaAwareTransactionManager<Object, Object> transactionManager;\n\n\tprivate @Nullable ConsumerAwareRebalanceListener rebalanceListener;\n\n\tprivate @Nullable CommonErrorHandler commonErrorHandler;\n\n\tprivate @Nullable AfterRollbackProcessor<Object, Object> afterRollbackProcessor;\n\n\tprivate @Nullable RecordInterceptor<Object, Object> recordInterceptor;\n\n\tprivate @Nullable BatchInterceptor<Object, Object> batchInterceptor;\n\n\tprivate @Nullable Function<MessageListenerContainer, String> threadNameSupplier;\n\n\tprivate @Nullable SimpleAsyncTaskExecutor listenerTaskExecutor;\n\n\tprivate @Nullable KafkaListenerObservationConvention observationConvention;\n\n\t/**\n\t * Set the {@link KafkaProperties} to use.\n\t * @param properties the properties\n\t */\n\tvoid setKafkaProperties(@Nullable KafkaProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t/**\n\t * Set the {@link BatchMessageConverter} to use.\n\t * @param batchMessageConverter the message converter\n\t */\n\tvoid setBatchMessageConverter(@Nullable BatchMessageConverter batchMessageConverter) {\n\t\tthis.batchMessageConverter = batchMessageConverter;\n\t}\n\n\t/**\n\t * Set the {@link RecordMessageConverter} to use.\n\t * @param recordMessageConverter the message converter\n\t */\n\tvoid setRecordMessageConverter(@Nullable RecordMessageConverter recordMessageConverter) {\n\t\tthis.recordMessageConverter = recordMessageConverter;\n\t}\n\n\t/**\n\t * Set the {@link RecordFilterStrategy} to use to filter incoming records.\n\t * @param recordFilterStrategy the record filter strategy\n\t */\n\tvoid setRecordFilterStrategy(@Nullable RecordFilterStrategy<Object, Object> recordFilterStrategy) {\n\t\tthis.recordFilterStrategy = recordFilterStrategy;\n\t}\n\n\t/**\n\t * Set the {@link KafkaTemplate} to use to send replies.\n\t * @param replyTemplate the reply template\n\t */\n\tvoid setReplyTemplate(@Nullable KafkaTemplate<Object, Object> replyTemplate) {\n\t\tthis.replyTemplate = replyTemplate;\n\t}\n\n\t/**\n\t * Set the {@link KafkaAwareTransactionManager} to use.\n\t * @param transactionManager the transaction manager\n\t */\n\tvoid setTransactionManager(@Nullable KafkaAwareTransactionManager<Object, Object> transactionManager) {\n\t\tthis.transactionManager = transactionManager;\n\t}\n\n\t/**\n\t * Set the {@link ConsumerAwareRebalanceListener} to use.\n\t * @param rebalanceListener the rebalance listener.\n\t */\n\tvoid setRebalanceListener(@Nullable ConsumerAwareRebalanceListener rebalanceListener) {\n\t\tthis.rebalanceListener = rebalanceListener;\n\t}\n\n\t/**\n\t * Set the {@link CommonErrorHandler} to use.\n\t * @param commonErrorHandler the error handler.\n\t */\n\tpublic void setCommonErrorHandler(@Nullable CommonErrorHandler commonErrorHandler) {\n\t\tthis.commonErrorHandler = commonErrorHandler;\n\t}\n\n\t/**\n\t * Set the {@link AfterRollbackProcessor} to use.\n\t * @param afterRollbackProcessor the after rollback processor\n\t */\n\tvoid setAfterRollbackProcessor(@Nullable AfterRollbackProcessor<Object, Object> afterRollbackProcessor) {\n\t\tthis.afterRollbackProcessor = afterRollbackProcessor;\n\t}\n\n\t/**\n\t * Set the {@link RecordInterceptor} to use.\n\t * @param recordInterceptor the record interceptor.\n\t */\n\tvoid setRecordInterceptor(@Nullable RecordInterceptor<Object, Object> recordInterceptor) {\n\t\tthis.recordInterceptor = recordInterceptor;\n\t}\n\n\t/**\n\t * Set the {@link BatchInterceptor} to use.\n\t * @param batchInterceptor the batch interceptor.\n\t */\n\tvoid setBatchInterceptor(@Nullable BatchInterceptor<Object, Object> batchInterceptor) {\n\t\tthis.batchInterceptor = batchInterceptor;\n\t}\n\n\t/**\n\t * Set the thread name supplier to use.\n\t * @param threadNameSupplier the thread name supplier to use\n\t */\n\tvoid setThreadNameSupplier(@Nullable Function<MessageListenerContainer, String> threadNameSupplier) {\n\t\tthis.threadNameSupplier = threadNameSupplier;\n\t}\n\n\t/**\n\t * Set the executor for threads that poll the consumer.\n\t * @param listenerTaskExecutor task executor\n\t */\n\tvoid setListenerTaskExecutor(@Nullable SimpleAsyncTaskExecutor listenerTaskExecutor) {\n\t\tthis.listenerTaskExecutor = listenerTaskExecutor;\n\t}\n\n\t/**\n\t * Sets the observation convention.\n\t * @param observationConvention the observation convention\n\t */\n\tvoid setObservationConvention(@Nullable KafkaListenerObservationConvention observationConvention) {\n\t\tthis.observationConvention = observationConvention;\n\t}\n\n\t/**\n\t * Configure the specified Kafka listener container factory. The factory can be\n\t * further tuned and default settings can be overridden.\n\t * @param listenerFactory the {@link ConcurrentKafkaListenerContainerFactory} instance\n\t * to configure\n\t * @param consumerFactory the {@link ConsumerFactory} to use\n\t */\n\tpublic void configure(ConcurrentKafkaListenerContainerFactory<Object, Object> listenerFactory,\n\t\t\tConsumerFactory<Object, Object> consumerFactory) {\n\t\tlistenerFactory.setConsumerFactory(consumerFactory);\n\t\tconfigureListenerFactory(listenerFactory);\n\t\tconfigureContainer(listenerFactory.getContainerProperties());\n\t}\n\n\tprivate void configureListenerFactory(ConcurrentKafkaListenerContainerFactory<Object, Object> factory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tAssert.state(this.properties != null, \"'properties' must not be null\");\n\t\tListener properties = this.properties.getListener();\n\t\tmap.from(properties::getConcurrency).to(factory::setConcurrency);\n\t\tmap.from(properties::isAutoStartup).to(factory::setAutoStartup);\n\t\tmap.from(this.batchMessageConverter).to(factory::setBatchMessageConverter);\n\t\tmap.from(this.recordMessageConverter).to(factory::setRecordMessageConverter);\n\t\tmap.from(this.recordFilterStrategy).to(factory::setRecordFilterStrategy);\n\t\tmap.from(this.replyTemplate).to(factory::setReplyTemplate);\n\t\tif (properties.getType().equals(Listener.Type.BATCH)) {\n\t\t\tfactory.setBatchListener(true);\n\t\t}\n\t\tmap.from(this.commonErrorHandler).to(factory::setCommonErrorHandler);\n\t\tmap.from(this.afterRollbackProcessor).to(factory::setAfterRollbackProcessor);\n\t\tmap.from(this.recordInterceptor).to(factory::setRecordInterceptor);\n\t\tmap.from(this.batchInterceptor).to(factory::setBatchInterceptor);\n\t\tmap.from(this.threadNameSupplier).to(factory::setThreadNameSupplier);\n\t\tmap.from(properties::getChangeConsumerThreadName).to(factory::setChangeConsumerThreadName);\n\t}\n\n\tprivate void configureContainer(ContainerProperties container) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tAssert.state(this.properties != null, \"'properties' must not be null\");\n\t\tListener properties = this.properties.getListener();\n\t\tmap.from(properties::getAckMode).to(container::setAckMode);\n\t\tmap.from(properties::getAsyncAcks).to(container::setAsyncAcks);\n\t\tmap.from(properties::getClientId).to(container::setClientId);\n\t\tmap.from(properties::getAckCount).to(container::setAckCount);\n\t\tmap.from(properties::getAckTime).as(Duration::toMillis).to(container::setAckTime);\n\t\tmap.from(properties::getPollTimeout).as(Duration::toMillis).to(container::setPollTimeout);\n\t\tmap.from(properties::getNoPollThreshold).to(container::setNoPollThreshold);\n\t\tmap.from(properties.getIdleBetweenPolls()).as(Duration::toMillis).to(container::setIdleBetweenPolls);\n\t\tmap.from(properties::getIdleEventInterval).as(Duration::toMillis).to(container::setIdleEventInterval);\n\t\tmap.from(properties::getIdlePartitionEventInterval)\n\t\t\t.as(Duration::toMillis)\n\t\t\t.to(container::setIdlePartitionEventInterval);\n\t\tmap.from(properties::getMonitorInterval)\n\t\t\t.as(Duration::getSeconds)\n\t\t\t.as(Number::intValue)\n\t\t\t.to(container::setMonitorInterval);\n\t\tmap.from(properties::getLogContainerConfig).to(container::setLogContainerConfig);\n\t\tmap.from(properties::isMissingTopicsFatal).to(container::setMissingTopicsFatal);\n\t\tmap.from(properties::isImmediateStop).to(container::setStopImmediate);\n\t\tmap.from(properties::isObservationEnabled).to(container::setObservationEnabled);\n\t\tmap.from(properties::getAuthExceptionRetryInterval).to(container::setAuthExceptionRetryInterval);\n\t\tmap.from(this.transactionManager).to(container::setKafkaAwareTransactionManager);\n\t\tmap.from(this.rebalanceListener).to(container::setConsumerRebalanceListener);\n\t\tmap.from(this.listenerTaskExecutor).to(container::setListenerTaskExecutor);\n\t\tmap.from(this.observationConvention).to(container::setObservationConvention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/DefaultKafkaConsumerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\n\n/**\n * Callback interface for customizing {@code DefaultKafkaConsumerFactory} beans.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface DefaultKafkaConsumerFactoryCustomizer {\n\n\t/**\n\t * Customize the {@link DefaultKafkaConsumerFactory}.\n\t * @param consumerFactory the consumer factory to customize\n\t */\n\tvoid customize(DefaultKafkaConsumerFactory<?, ?> consumerFactory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/DefaultKafkaProducerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\n\n/**\n * Callback interface for customizing {@code DefaultKafkaProducerFactory} beans.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface DefaultKafkaProducerFactoryCustomizer {\n\n\t/**\n\t * Customize the {@link DefaultKafkaProducerFactory}.\n\t * @param producerFactory the producer factory to customize\n\t */\n\tvoid customize(DefaultKafkaProducerFactory<?, ?> producerFactory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/KafkaAnnotationDrivenConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.kafka.annotation.EnableKafka;\nimport org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;\nimport org.springframework.kafka.config.ContainerCustomizer;\nimport org.springframework.kafka.config.KafkaListenerConfigUtils;\nimport org.springframework.kafka.core.ConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.listener.AfterRollbackProcessor;\nimport org.springframework.kafka.listener.BatchInterceptor;\nimport org.springframework.kafka.listener.CommonErrorHandler;\nimport org.springframework.kafka.listener.ConcurrentMessageListenerContainer;\nimport org.springframework.kafka.listener.ConsumerAwareRebalanceListener;\nimport org.springframework.kafka.listener.MessageListenerContainer;\nimport org.springframework.kafka.listener.RecordInterceptor;\nimport org.springframework.kafka.listener.adapter.RecordFilterStrategy;\nimport org.springframework.kafka.support.converter.BatchMessageConverter;\nimport org.springframework.kafka.support.converter.BatchMessagingMessageConverter;\nimport org.springframework.kafka.support.converter.RecordMessageConverter;\nimport org.springframework.kafka.support.micrometer.KafkaListenerObservationConvention;\nimport org.springframework.kafka.transaction.KafkaAwareTransactionManager;\n\n/**\n * Configuration for Kafka annotation-driven support.\n *\n * @author Gary Russell\n * @author Eddú Meléndez\n * @author Thomas Kåsene\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(EnableKafka.class)\nclass KafkaAnnotationDrivenConfiguration {\n\n\tprivate final KafkaProperties properties;\n\n\tprivate final @Nullable RecordMessageConverter recordMessageConverter;\n\n\tprivate final @Nullable RecordFilterStrategy<Object, Object> recordFilterStrategy;\n\n\tprivate final BatchMessageConverter batchMessageConverter;\n\n\tprivate final @Nullable KafkaTemplate<Object, Object> kafkaTemplate;\n\n\tprivate final @Nullable KafkaAwareTransactionManager<Object, Object> transactionManager;\n\n\tprivate final @Nullable ConsumerAwareRebalanceListener rebalanceListener;\n\n\tprivate final @Nullable CommonErrorHandler commonErrorHandler;\n\n\tprivate final @Nullable AfterRollbackProcessor<Object, Object> afterRollbackProcessor;\n\n\tprivate final @Nullable RecordInterceptor<Object, Object> recordInterceptor;\n\n\tprivate final @Nullable BatchInterceptor<Object, Object> batchInterceptor;\n\n\tprivate final @Nullable Function<MessageListenerContainer, String> threadNameSupplier;\n\n\tprivate final @Nullable KafkaListenerObservationConvention observationConvention;\n\n\tKafkaAnnotationDrivenConfiguration(KafkaProperties properties,\n\t\t\tObjectProvider<RecordMessageConverter> recordMessageConverter,\n\t\t\tObjectProvider<RecordFilterStrategy<Object, Object>> recordFilterStrategy,\n\t\t\tObjectProvider<BatchMessageConverter> batchMessageConverter,\n\t\t\tObjectProvider<KafkaTemplate<Object, Object>> kafkaTemplate,\n\t\t\tObjectProvider<KafkaAwareTransactionManager<Object, Object>> kafkaTransactionManager,\n\t\t\tObjectProvider<ConsumerAwareRebalanceListener> rebalanceListener,\n\t\t\tObjectProvider<CommonErrorHandler> commonErrorHandler,\n\t\t\tObjectProvider<AfterRollbackProcessor<Object, Object>> afterRollbackProcessor,\n\t\t\tObjectProvider<RecordInterceptor<Object, Object>> recordInterceptor,\n\t\t\tObjectProvider<BatchInterceptor<Object, Object>> batchInterceptor,\n\t\t\tObjectProvider<Function<MessageListenerContainer, String>> threadNameSupplier,\n\t\t\tObjectProvider<KafkaListenerObservationConvention> observationConvention) {\n\t\tthis.properties = properties;\n\t\tthis.recordMessageConverter = recordMessageConverter.getIfUnique();\n\t\tthis.recordFilterStrategy = recordFilterStrategy.getIfUnique();\n\t\tthis.batchMessageConverter = batchMessageConverter\n\t\t\t.getIfUnique(() -> new BatchMessagingMessageConverter(this.recordMessageConverter));\n\t\tthis.kafkaTemplate = kafkaTemplate.getIfUnique();\n\t\tthis.transactionManager = kafkaTransactionManager.getIfUnique();\n\t\tthis.rebalanceListener = rebalanceListener.getIfUnique();\n\t\tthis.commonErrorHandler = commonErrorHandler.getIfUnique();\n\t\tthis.afterRollbackProcessor = afterRollbackProcessor.getIfUnique();\n\t\tthis.recordInterceptor = recordInterceptor.getIfUnique();\n\t\tthis.batchInterceptor = batchInterceptor.getIfUnique();\n\t\tthis.threadNameSupplier = threadNameSupplier.getIfUnique();\n\t\tthis.observationConvention = observationConvention.getIfUnique();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tConcurrentKafkaListenerContainerFactoryConfigurer kafkaListenerContainerFactoryConfigurer() {\n\t\treturn configurer();\n\t}\n\n\t@Bean(name = \"kafkaListenerContainerFactoryConfigurer\")\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tConcurrentKafkaListenerContainerFactoryConfigurer kafkaListenerContainerFactoryConfigurerVirtualThreads() {\n\t\tConcurrentKafkaListenerContainerFactoryConfigurer configurer = configurer();\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(\"kafka-\");\n\t\texecutor.setVirtualThreads(true);\n\t\tconfigurer.setListenerTaskExecutor(executor);\n\t\treturn configurer;\n\t}\n\n\tprivate ConcurrentKafkaListenerContainerFactoryConfigurer configurer() {\n\t\tConcurrentKafkaListenerContainerFactoryConfigurer configurer = new ConcurrentKafkaListenerContainerFactoryConfigurer();\n\t\tconfigurer.setKafkaProperties(this.properties);\n\t\tconfigurer.setBatchMessageConverter(this.batchMessageConverter);\n\t\tconfigurer.setRecordMessageConverter(this.recordMessageConverter);\n\t\tconfigurer.setRecordFilterStrategy(this.recordFilterStrategy);\n\t\tconfigurer.setReplyTemplate(this.kafkaTemplate);\n\t\tconfigurer.setTransactionManager(this.transactionManager);\n\t\tconfigurer.setRebalanceListener(this.rebalanceListener);\n\t\tconfigurer.setCommonErrorHandler(this.commonErrorHandler);\n\t\tconfigurer.setAfterRollbackProcessor(this.afterRollbackProcessor);\n\t\tconfigurer.setRecordInterceptor(this.recordInterceptor);\n\t\tconfigurer.setBatchInterceptor(this.batchInterceptor);\n\t\tconfigurer.setThreadNameSupplier(this.threadNameSupplier);\n\t\tconfigurer.setObservationConvention(this.observationConvention);\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"kafkaListenerContainerFactory\")\n\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory(\n\t\t\tConcurrentKafkaListenerContainerFactoryConfigurer configurer,\n\t\t\tObjectProvider<ConsumerFactory<Object, Object>> kafkaConsumerFactory,\n\t\t\tObjectProvider<ContainerCustomizer<Object, Object, ConcurrentMessageListenerContainer<Object, Object>>> kafkaContainerCustomizer) {\n\t\tConcurrentKafkaListenerContainerFactory<Object, Object> factory = new ConcurrentKafkaListenerContainerFactory<>();\n\t\tconfigurer.configure(factory, kafkaConsumerFactory\n\t\t\t.getIfAvailable(() -> new DefaultKafkaConsumerFactory<>(this.properties.buildConsumerProperties())));\n\t\tkafkaContainerCustomizer.ifAvailable(factory::setContainerCustomizer);\n\t\treturn factory;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableKafka\n\t@ConditionalOnMissingBean(name = KafkaListenerConfigUtils.KAFKA_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)\n\tstatic class EnableKafkaConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/KafkaAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.function.Predicate;\n\nimport org.apache.kafka.clients.CommonClientConfigs;\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.clients.producer.ProducerConfig;\nimport org.apache.kafka.common.config.SslConfigs;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.kafka.autoconfigure.KafkaConnectionDetails.Configuration;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Jaas;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Retry.Topic.Backoff;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.retry.RetryPolicy;\nimport org.springframework.kafka.core.ConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.KafkaAdmin;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.core.ProducerFactory;\nimport org.springframework.kafka.retrytopic.RetryTopicConfiguration;\nimport org.springframework.kafka.retrytopic.RetryTopicConfigurationBuilder;\nimport org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer;\nimport org.springframework.kafka.support.LoggingProducerListener;\nimport org.springframework.kafka.support.ProducerListener;\nimport org.springframework.kafka.support.converter.RecordMessageConverter;\nimport org.springframework.kafka.support.micrometer.KafkaTemplateObservationConvention;\nimport org.springframework.kafka.transaction.KafkaTransactionManager;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.backoff.BackOff;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Apache Kafka.\n *\n * @author Gary Russell\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Nakul Mishra\n * @author Tomaz Fernandes\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(KafkaTemplate.class)\n@EnableConfigurationProperties(KafkaProperties.class)\n@Import({ KafkaAnnotationDrivenConfiguration.class, KafkaStreamsAnnotationDrivenConfiguration.class })\n@ImportRuntimeHints(KafkaAutoConfiguration.KafkaRuntimeHints.class)\npublic final class KafkaAutoConfiguration {\n\n\tprivate final KafkaProperties properties;\n\n\tKafkaAutoConfiguration(KafkaProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(KafkaConnectionDetails.class)\n\tPropertiesKafkaConnectionDetails kafkaConnectionDetails(ObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesKafkaConnectionDetails(this.properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(KafkaTemplate.class)\n\tKafkaTemplate<?, ?> kafkaTemplate(ProducerFactory<Object, Object> kafkaProducerFactory,\n\t\t\tProducerListener<Object, Object> kafkaProducerListener,\n\t\t\tObjectProvider<RecordMessageConverter> messageConverter,\n\t\t\tObjectProvider<KafkaTemplateObservationConvention> observationConvention) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tKafkaTemplate<Object, Object> kafkaTemplate = new KafkaTemplate<>(kafkaProducerFactory);\n\t\tmessageConverter.ifUnique(kafkaTemplate::setMessageConverter);\n\t\tobservationConvention.ifUnique(kafkaTemplate::setObservationConvention);\n\t\tmap.from(kafkaProducerListener).to(kafkaTemplate::setProducerListener);\n\t\tmap.from(this.properties.getTemplate().getDefaultTopic()).to(kafkaTemplate::setDefaultTopic);\n\t\tmap.from(this.properties.getTemplate().getTransactionIdPrefix()).to(kafkaTemplate::setTransactionIdPrefix);\n\t\tmap.from(this.properties.getTemplate().isObservationEnabled()).to(kafkaTemplate::setObservationEnabled);\n\t\treturn kafkaTemplate;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ProducerListener.class)\n\tLoggingProducerListener<Object, Object> kafkaProducerListener() {\n\t\treturn new LoggingProducerListener<>();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ConsumerFactory.class)\n\tDefaultKafkaConsumerFactory<?, ?> kafkaConsumerFactory(KafkaConnectionDetails connectionDetails,\n\t\t\tObjectProvider<DefaultKafkaConsumerFactoryCustomizer> customizers) {\n\t\tMap<String, Object> properties = this.properties.buildConsumerProperties();\n\t\tapplyKafkaConnectionDetailsForConsumer(properties, connectionDetails);\n\t\tDefaultKafkaConsumerFactory<Object, Object> factory = new DefaultKafkaConsumerFactory<>(properties);\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\treturn factory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ProducerFactory.class)\n\tDefaultKafkaProducerFactory<?, ?> kafkaProducerFactory(KafkaConnectionDetails connectionDetails,\n\t\t\tObjectProvider<DefaultKafkaProducerFactoryCustomizer> customizers) {\n\t\tMap<String, Object> properties = this.properties.buildProducerProperties();\n\t\tapplyKafkaConnectionDetailsForProducer(properties, connectionDetails);\n\t\tDefaultKafkaProducerFactory<?, ?> factory = new DefaultKafkaProducerFactory<>(properties);\n\t\tString transactionIdPrefix = this.properties.getProducer().getTransactionIdPrefix();\n\t\tif (transactionIdPrefix != null) {\n\t\t\tfactory.setTransactionIdPrefix(transactionIdPrefix);\n\t\t}\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(factory));\n\t\treturn factory;\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.kafka.producer.transaction-id-prefix\")\n\t@ConditionalOnMissingBean\n\tKafkaTransactionManager<?, ?> kafkaTransactionManager(ProducerFactory<?, ?> producerFactory) {\n\t\treturn new KafkaTransactionManager<>(producerFactory);\n\t}\n\n\t@Bean\n\t@ConditionalOnBooleanProperty(\"spring.kafka.jaas.enabled\")\n\t@ConditionalOnMissingBean\n\tKafkaJaasLoginModuleInitializer kafkaJaasInitializer() throws IOException {\n\t\tKafkaJaasLoginModuleInitializer jaas = new KafkaJaasLoginModuleInitializer();\n\t\tJaas jaasProperties = this.properties.getJaas();\n\t\tif (jaasProperties.getControlFlag() != null) {\n\t\t\tjaas.setControlFlag(jaasProperties.getControlFlag());\n\t\t}\n\t\tif (jaasProperties.getLoginModule() != null) {\n\t\t\tjaas.setLoginModule(jaasProperties.getLoginModule());\n\t\t}\n\t\tjaas.setOptions(jaasProperties.getOptions());\n\t\treturn jaas;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tKafkaAdmin kafkaAdmin(KafkaConnectionDetails connectionDetails) {\n\t\tMap<String, Object> properties = this.properties.buildAdminProperties();\n\t\tapplyKafkaConnectionDetailsForAdmin(properties, connectionDetails);\n\t\tKafkaAdmin kafkaAdmin = new KafkaAdmin(properties);\n\t\tKafkaProperties.Admin admin = this.properties.getAdmin();\n\t\tif (admin.getCloseTimeout() != null) {\n\t\t\tkafkaAdmin.setCloseTimeout((int) admin.getCloseTimeout().getSeconds());\n\t\t}\n\t\tif (admin.getOperationTimeout() != null) {\n\t\t\tkafkaAdmin.setOperationTimeout((int) admin.getOperationTimeout().getSeconds());\n\t\t}\n\t\tkafkaAdmin.setFatalIfBrokerNotAvailable(admin.isFailFast());\n\t\tkafkaAdmin.setModifyTopicConfigs(admin.isModifyTopicConfigs());\n\t\tkafkaAdmin.setAutoCreate(admin.isAutoCreate());\n\t\treturn kafkaAdmin;\n\t}\n\n\t@Bean\n\t@ConditionalOnBooleanProperty(\"spring.kafka.retry.topic.enabled\")\n\t@ConditionalOnSingleCandidate(KafkaTemplate.class)\n\tRetryTopicConfiguration kafkaRetryTopicConfiguration(KafkaTemplate<?, ?> kafkaTemplate) {\n\t\tKafkaProperties.Retry.Topic retryTopic = this.properties.getRetry().getTopic();\n\t\tRetryTopicConfigurationBuilder builder = RetryTopicConfigurationBuilder.newInstance()\n\t\t\t.maxAttempts(retryTopic.getAttempts())\n\t\t\t.useSingleTopicForSameIntervals()\n\t\t\t.suffixTopicsWithIndexValues()\n\t\t\t.doNotAutoCreateRetryTopics()\n\t\t\t.customBackoff(getBackOff(retryTopic.getBackoff()));\n\t\treturn builder.create(kafkaTemplate);\n\t}\n\n\tprivate void applyKafkaConnectionDetailsForConsumer(Map<String, Object> properties,\n\t\t\tKafkaConnectionDetails connectionDetails) {\n\t\tConfiguration consumer = connectionDetails.getConsumer();\n\t\tproperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, consumer.getBootstrapServers());\n\t\tapplySecurityProtocol(properties, connectionDetails.getSecurityProtocol());\n\t\tapplySslBundle(properties, consumer.getSslBundle());\n\t}\n\n\tprivate void applyKafkaConnectionDetailsForProducer(Map<String, Object> properties,\n\t\t\tKafkaConnectionDetails connectionDetails) {\n\t\tConfiguration producer = connectionDetails.getProducer();\n\t\tproperties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, producer.getBootstrapServers());\n\t\tapplySecurityProtocol(properties, producer.getSecurityProtocol());\n\t\tapplySslBundle(properties, producer.getSslBundle());\n\t}\n\n\tprivate void applyKafkaConnectionDetailsForAdmin(Map<String, Object> properties,\n\t\t\tKafkaConnectionDetails connectionDetails) {\n\t\tConfiguration admin = connectionDetails.getAdmin();\n\t\tproperties.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, admin.getBootstrapServers());\n\t\tapplySecurityProtocol(properties, admin.getSecurityProtocol());\n\t\tapplySslBundle(properties, admin.getSslBundle());\n\t}\n\n\tstatic BackOff getBackOff(Backoff retryTopicBackoff) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRetryPolicy.Builder builder = RetryPolicy.builder().maxRetries(Long.MAX_VALUE);\n\t\tmap.from(retryTopicBackoff.getDelay()).to(builder::delay);\n\t\tmap.from(retryTopicBackoff.getMaxDelay()).when(Predicate.not(Duration::isZero)).to(builder::maxDelay);\n\t\tmap.from(retryTopicBackoff.getMultiplier()).to(builder::multiplier);\n\t\tmap.from(retryTopicBackoff.getJitter()).when((Predicate.not(Duration::isZero))).to(builder::jitter);\n\t\treturn builder.build().getBackOff();\n\t}\n\n\tstatic void applySslBundle(Map<String, Object> properties, @Nullable SslBundle sslBundle) {\n\t\tif (sslBundle != null) {\n\t\t\tproperties.put(SslConfigs.SSL_ENGINE_FACTORY_CLASS_CONFIG, SslBundleSslEngineFactory.class);\n\t\t\tproperties.put(SslBundle.class.getName(), sslBundle);\n\t\t}\n\t}\n\n\tstatic void applySecurityProtocol(Map<String, Object> properties, @Nullable String securityProtocol) {\n\t\tif (StringUtils.hasLength(securityProtocol)) {\n\t\t\tproperties.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, securityProtocol);\n\t\t}\n\t}\n\n\tstatic class KafkaRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(SslBundleSslEngineFactory.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/KafkaConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to a Kafka service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface KafkaConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Returns the list of bootstrap servers.\n\t * @return the list of bootstrap servers\n\t */\n\tList<String> getBootstrapServers();\n\n\t/**\n\t * Returns the SSL bundle.\n\t * @return the SSL bundle\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the security protocol.\n\t * @return the security protocol\n\t */\n\tdefault @Nullable String getSecurityProtocol() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the consumer configuration.\n\t * @return the consumer configuration\n\t */\n\tdefault Configuration getConsumer() {\n\t\treturn Configuration.of(getBootstrapServers(), getSslBundle(), getSecurityProtocol());\n\t}\n\n\t/**\n\t * Returns the producer configuration.\n\t * @return the producer configuration\n\t */\n\tdefault Configuration getProducer() {\n\t\treturn Configuration.of(getBootstrapServers(), getSslBundle(), getSecurityProtocol());\n\t}\n\n\t/**\n\t * Returns the admin configuration.\n\t * @return the admin configuration\n\t */\n\tdefault Configuration getAdmin() {\n\t\treturn Configuration.of(getBootstrapServers(), getSslBundle(), getSecurityProtocol());\n\t}\n\n\t/**\n\t * Returns the Kafka Streams configuration.\n\t * @return the Kafka Streams configuration\n\t */\n\tdefault Configuration getStreams() {\n\t\treturn Configuration.of(getBootstrapServers(), getSslBundle(), getSecurityProtocol());\n\t}\n\n\t/**\n\t * Kafka connection details configuration.\n\t */\n\tinterface Configuration {\n\n\t\t/**\n\t\t * Creates a new configuration with the given bootstrap servers.\n\t\t * @param bootstrapServers the bootstrap servers\n\t\t * @return the configuration\n\t\t */\n\t\tstatic Configuration of(List<String> bootstrapServers) {\n\t\t\treturn Configuration.of(bootstrapServers, null, null);\n\t\t}\n\n\t\t/**\n\t\t * Creates a new configuration with the given bootstrap servers and SSL bundle.\n\t\t * @param bootstrapServers the bootstrap servers\n\t\t * @param sslBundle the SSL bundle\n\t\t * @return the configuration\n\t\t */\n\t\tstatic Configuration of(List<String> bootstrapServers, SslBundle sslBundle) {\n\t\t\treturn Configuration.of(bootstrapServers, sslBundle, null);\n\t\t}\n\n\t\t/**\n\t\t * Creates a new configuration with the given bootstrap servers, SSL bundle and\n\t\t * security protocol.\n\t\t * @param bootstrapServers the bootstrap servers\n\t\t * @param sslBundle the SSL bundle\n\t\t * @param securityProtocol the security protocol\n\t\t * @return the configuration\n\t\t */\n\t\tstatic Configuration of(List<String> bootstrapServers, @Nullable SslBundle sslBundle,\n\t\t\t\t@Nullable String securityProtocol) {\n\t\t\treturn new Configuration() {\n\t\t\t\t@Override\n\t\t\t\tpublic List<String> getBootstrapServers() {\n\t\t\t\t\treturn bootstrapServers;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\t\t\treturn sslBundle;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable String getSecurityProtocol() {\n\t\t\t\t\treturn securityProtocol;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Returns the list of bootstrap servers.\n\t\t * @return the list of bootstrap servers\n\t\t */\n\t\tList<String> getBootstrapServers();\n\n\t\t/**\n\t\t * Returns the SSL bundle.\n\t\t * @return the SSL bundle\n\t\t */\n\t\tdefault @Nullable SslBundle getSslBundle() {\n\t\t\treturn null;\n\t\t}\n\n\t\t/**\n\t\t * Returns the security protocol.\n\t\t * @return the security protocol\n\t\t */\n\t\tdefault @Nullable String getSecurityProtocol() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/KafkaProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.apache.kafka.clients.CommonClientConfigs;\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.clients.producer.ProducerConfig;\nimport org.apache.kafka.common.config.SslConfigs;\nimport org.apache.kafka.common.serialization.StringDeserializer;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.core.io.Resource;\nimport org.springframework.kafka.listener.ContainerProperties.AckMode;\nimport org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Configuration properties for Spring for Apache Kafka.\n * <p>\n * Users should refer to Kafka documentation for complete descriptions of these\n * properties.\n *\n * @author Gary Russell\n * @author Stephane Nicoll\n * @author Artem Bilan\n * @author Nakul Mishra\n * @author Tomaz Fernandes\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.kafka\")\npublic class KafkaProperties {\n\n\t/**\n\t * List of host:port pairs to use for establishing the initial connections to the\n\t * Kafka cluster. Applies to all components unless overridden.\n\t */\n\tprivate List<String> bootstrapServers = new ArrayList<>(Collections.singletonList(\"localhost:9092\"));\n\n\t/**\n\t * ID to pass to the server when making requests. Used for server-side logging.\n\t */\n\tprivate @Nullable String clientId;\n\n\t/**\n\t * Additional properties, common to producers and consumers, used to configure the\n\t * client.\n\t */\n\tprivate final Map<String, String> properties = new HashMap<>();\n\n\tprivate final Consumer consumer = new Consumer();\n\n\tprivate final Producer producer = new Producer();\n\n\tprivate final Admin admin = new Admin();\n\n\tprivate final Streams streams = new Streams();\n\n\tprivate final Listener listener = new Listener();\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tprivate final Jaas jaas = new Jaas();\n\n\tprivate final Template template = new Template();\n\n\tprivate final Security security = new Security();\n\n\tprivate final Retry retry = new Retry();\n\n\tpublic List<String> getBootstrapServers() {\n\t\treturn this.bootstrapServers;\n\t}\n\n\tpublic void setBootstrapServers(List<String> bootstrapServers) {\n\t\tthis.bootstrapServers = bootstrapServers;\n\t}\n\n\tpublic @Nullable String getClientId() {\n\t\treturn this.clientId;\n\t}\n\n\tpublic void setClientId(@Nullable String clientId) {\n\t\tthis.clientId = clientId;\n\t}\n\n\tpublic Map<String, String> getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tpublic Consumer getConsumer() {\n\t\treturn this.consumer;\n\t}\n\n\tpublic Producer getProducer() {\n\t\treturn this.producer;\n\t}\n\n\tpublic Listener getListener() {\n\t\treturn this.listener;\n\t}\n\n\tpublic Admin getAdmin() {\n\t\treturn this.admin;\n\t}\n\n\tpublic Streams getStreams() {\n\t\treturn this.streams;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic Jaas getJaas() {\n\t\treturn this.jaas;\n\t}\n\n\tpublic Template getTemplate() {\n\t\treturn this.template;\n\t}\n\n\tpublic Security getSecurity() {\n\t\treturn this.security;\n\t}\n\n\tpublic Retry getRetry() {\n\t\treturn this.retry;\n\t}\n\n\tprivate Map<String, Object> buildCommonProperties() {\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tif (this.bootstrapServers != null) {\n\t\t\tproperties.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG, this.bootstrapServers);\n\t\t}\n\t\tif (this.clientId != null) {\n\t\t\tproperties.put(CommonClientConfigs.CLIENT_ID_CONFIG, this.clientId);\n\t\t}\n\t\tproperties.putAll(this.ssl.buildProperties());\n\t\tproperties.putAll(this.security.buildProperties());\n\t\tif (!CollectionUtils.isEmpty(this.properties)) {\n\t\t\tproperties.putAll(this.properties);\n\t\t}\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Create an initial map of consumer properties from the state of this instance.\n\t * <p>\n\t * This allows you to add additional properties, if necessary, and override the\n\t * default {@code kafkaConsumerFactory} bean.\n\t * @return the consumer properties initialized with the customizations defined on this\n\t * instance\n\t */\n\tpublic Map<String, Object> buildConsumerProperties() {\n\t\tMap<String, Object> properties = buildCommonProperties();\n\t\tproperties.putAll(this.consumer.buildProperties());\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Create an initial map of producer properties from the state of this instance.\n\t * <p>\n\t * This allows you to add additional properties, if necessary, and override the\n\t * default {@code kafkaProducerFactory} bean.\n\t * @return the producer properties initialized with the customizations defined on this\n\t * instance\n\t */\n\tpublic Map<String, Object> buildProducerProperties() {\n\t\tMap<String, Object> properties = buildCommonProperties();\n\t\tproperties.putAll(this.producer.buildProperties());\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Create an initial map of admin properties from the state of this instance.\n\t * <p>\n\t * This allows you to add additional properties, if necessary, and override the\n\t * default {@code kafkaAdmin} bean.\n\t * @return the admin properties initialized with the customizations defined on this\n\t * instance\n\t */\n\tpublic Map<String, Object> buildAdminProperties() {\n\t\tMap<String, Object> properties = buildCommonProperties();\n\t\tproperties.putAll(this.admin.buildProperties());\n\t\treturn properties;\n\t}\n\n\t/**\n\t * Create an initial map of streams properties from the state of this instance.\n\t * <p>\n\t * This allows you to add additional properties, if necessary.\n\t * @return the streams properties initialized with the customizations defined on this\n\t * instance\n\t */\n\tpublic Map<String, Object> buildStreamsProperties() {\n\t\tMap<String, Object> properties = buildCommonProperties();\n\t\tproperties.putAll(this.streams.buildProperties());\n\t\treturn properties;\n\t}\n\n\tpublic static class Consumer {\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tprivate final Security security = new Security();\n\n\t\t/**\n\t\t * Frequency with which the consumer offsets are auto-committed to Kafka if\n\t\t * 'enable.auto.commit' is set to true.\n\t\t */\n\t\tprivate @Nullable Duration autoCommitInterval;\n\n\t\t/**\n\t\t * What to do when there is no initial offset in Kafka or if the current offset no\n\t\t * longer exists on the server.\n\t\t */\n\t\tprivate @Nullable String autoOffsetReset;\n\n\t\t/**\n\t\t * List of host:port pairs to use for establishing the initial connections to the\n\t\t * Kafka cluster. Overrides the global property, for consumers.\n\t\t */\n\t\tprivate @Nullable List<String> bootstrapServers;\n\n\t\t/**\n\t\t * ID to pass to the server when making requests. Used for server-side logging.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Whether the consumer's offset is periodically committed in the background.\n\t\t */\n\t\tprivate @Nullable Boolean enableAutoCommit;\n\n\t\t/**\n\t\t * Maximum amount of time the server blocks before answering the fetch request if\n\t\t * there isn't sufficient data to immediately satisfy the requirement given by\n\t\t * \"fetch-min-size\".\n\t\t */\n\t\tprivate @Nullable Duration fetchMaxWait;\n\n\t\t/**\n\t\t * Minimum amount of data the server should return for a fetch request.\n\t\t */\n\t\tprivate @Nullable DataSize fetchMinSize;\n\n\t\t/**\n\t\t * Unique string that identifies the consumer group to which this consumer\n\t\t * belongs.\n\t\t */\n\t\tprivate @Nullable String groupId;\n\n\t\t/**\n\t\t * Expected time between heartbeats to the consumer coordinator.\n\t\t */\n\t\tprivate @Nullable Duration heartbeatInterval;\n\n\t\t/**\n\t\t * Isolation level for reading messages that have been written transactionally.\n\t\t */\n\t\tprivate IsolationLevel isolationLevel = IsolationLevel.READ_UNCOMMITTED;\n\n\t\t/**\n\t\t * Deserializer class for keys.\n\t\t */\n\t\tprivate Class<?> keyDeserializer = StringDeserializer.class;\n\n\t\t/**\n\t\t * Deserializer class for values.\n\t\t */\n\t\tprivate Class<?> valueDeserializer = StringDeserializer.class;\n\n\t\t/**\n\t\t * Maximum number of records returned in a single call to poll().\n\t\t */\n\t\tprivate @Nullable Integer maxPollRecords;\n\n\t\t/**\n\t\t * Maximum delay between invocations of poll() when using consumer group\n\t\t * management.\n\t\t */\n\t\tprivate @Nullable Duration maxPollInterval;\n\n\t\t/**\n\t\t * Additional consumer-specific properties used to configure the client.\n\t\t */\n\t\tprivate final Map<String, String> properties = new HashMap<>();\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic Security getSecurity() {\n\t\t\treturn this.security;\n\t\t}\n\n\t\tpublic @Nullable Duration getAutoCommitInterval() {\n\t\t\treturn this.autoCommitInterval;\n\t\t}\n\n\t\tpublic void setAutoCommitInterval(@Nullable Duration autoCommitInterval) {\n\t\t\tthis.autoCommitInterval = autoCommitInterval;\n\t\t}\n\n\t\tpublic @Nullable String getAutoOffsetReset() {\n\t\t\treturn this.autoOffsetReset;\n\t\t}\n\n\t\tpublic void setAutoOffsetReset(@Nullable String autoOffsetReset) {\n\t\t\tthis.autoOffsetReset = autoOffsetReset;\n\t\t}\n\n\t\tpublic @Nullable List<String> getBootstrapServers() {\n\t\t\treturn this.bootstrapServers;\n\t\t}\n\n\t\tpublic void setBootstrapServers(@Nullable List<String> bootstrapServers) {\n\t\t\tthis.bootstrapServers = bootstrapServers;\n\t\t}\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable Boolean getEnableAutoCommit() {\n\t\t\treturn this.enableAutoCommit;\n\t\t}\n\n\t\tpublic void setEnableAutoCommit(@Nullable Boolean enableAutoCommit) {\n\t\t\tthis.enableAutoCommit = enableAutoCommit;\n\t\t}\n\n\t\tpublic @Nullable Duration getFetchMaxWait() {\n\t\t\treturn this.fetchMaxWait;\n\t\t}\n\n\t\tpublic void setFetchMaxWait(@Nullable Duration fetchMaxWait) {\n\t\t\tthis.fetchMaxWait = fetchMaxWait;\n\t\t}\n\n\t\tpublic @Nullable DataSize getFetchMinSize() {\n\t\t\treturn this.fetchMinSize;\n\t\t}\n\n\t\tpublic void setFetchMinSize(@Nullable DataSize fetchMinSize) {\n\t\t\tthis.fetchMinSize = fetchMinSize;\n\t\t}\n\n\t\tpublic @Nullable String getGroupId() {\n\t\t\treturn this.groupId;\n\t\t}\n\n\t\tpublic void setGroupId(@Nullable String groupId) {\n\t\t\tthis.groupId = groupId;\n\t\t}\n\n\t\tpublic @Nullable Duration getHeartbeatInterval() {\n\t\t\treturn this.heartbeatInterval;\n\t\t}\n\n\t\tpublic void setHeartbeatInterval(@Nullable Duration heartbeatInterval) {\n\t\t\tthis.heartbeatInterval = heartbeatInterval;\n\t\t}\n\n\t\tpublic IsolationLevel getIsolationLevel() {\n\t\t\treturn this.isolationLevel;\n\t\t}\n\n\t\tpublic void setIsolationLevel(IsolationLevel isolationLevel) {\n\t\t\tthis.isolationLevel = isolationLevel;\n\t\t}\n\n\t\tpublic Class<?> getKeyDeserializer() {\n\t\t\treturn this.keyDeserializer;\n\t\t}\n\n\t\tpublic void setKeyDeserializer(Class<?> keyDeserializer) {\n\t\t\tthis.keyDeserializer = keyDeserializer;\n\t\t}\n\n\t\tpublic Class<?> getValueDeserializer() {\n\t\t\treturn this.valueDeserializer;\n\t\t}\n\n\t\tpublic void setValueDeserializer(Class<?> valueDeserializer) {\n\t\t\tthis.valueDeserializer = valueDeserializer;\n\t\t}\n\n\t\tpublic @Nullable Integer getMaxPollRecords() {\n\t\t\treturn this.maxPollRecords;\n\t\t}\n\n\t\tpublic void setMaxPollRecords(@Nullable Integer maxPollRecords) {\n\t\t\tthis.maxPollRecords = maxPollRecords;\n\t\t}\n\n\t\tpublic @Nullable Duration getMaxPollInterval() {\n\t\t\treturn this.maxPollInterval;\n\t\t}\n\n\t\tpublic void setMaxPollInterval(@Nullable Duration maxPollInterval) {\n\t\t\tthis.maxPollInterval = maxPollInterval;\n\t\t}\n\n\t\tpublic Map<String, String> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tpublic Map<String, Object> buildProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::getAutoCommitInterval)\n\t\t\t\t.asInt(Duration::toMillis)\n\t\t\t\t.to(properties.in(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG));\n\t\t\tmap.from(this::getAutoOffsetReset).to(properties.in(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG));\n\t\t\tmap.from(this::getBootstrapServers).to(properties.in(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG));\n\t\t\tmap.from(this::getClientId).to(properties.in(ConsumerConfig.CLIENT_ID_CONFIG));\n\t\t\tmap.from(this::getEnableAutoCommit).to(properties.in(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG));\n\t\t\tmap.from(this::getFetchMaxWait)\n\t\t\t\t.asInt(Duration::toMillis)\n\t\t\t\t.to(properties.in(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG));\n\t\t\tmap.from(this::getFetchMinSize)\n\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t.to(properties.in(ConsumerConfig.FETCH_MIN_BYTES_CONFIG));\n\t\t\tmap.from(this::getGroupId).to(properties.in(ConsumerConfig.GROUP_ID_CONFIG));\n\t\t\tmap.from(this::getHeartbeatInterval)\n\t\t\t\t.asInt(Duration::toMillis)\n\t\t\t\t.to(properties.in(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG));\n\t\t\tmap.from(() -> getIsolationLevel().name().toLowerCase(Locale.ROOT))\n\t\t\t\t.to(properties.in(ConsumerConfig.ISOLATION_LEVEL_CONFIG));\n\t\t\tmap.from(this::getKeyDeserializer).to(properties.in(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG));\n\t\t\tmap.from(this::getValueDeserializer).to(properties.in(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG));\n\t\t\tmap.from(this::getMaxPollRecords).to(properties.in(ConsumerConfig.MAX_POLL_RECORDS_CONFIG));\n\t\t\tmap.from(this::getMaxPollInterval)\n\t\t\t\t.asInt(Duration::toMillis)\n\t\t\t\t.to(properties.in(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG));\n\t\t\treturn properties.with(this.ssl, this.security, this.properties);\n\t\t}\n\n\t}\n\n\tpublic static class Producer {\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tprivate final Security security = new Security();\n\n\t\t/**\n\t\t * Number of acknowledgments the producer requires the leader to have received\n\t\t * before considering a request complete.\n\t\t */\n\t\tprivate @Nullable String acks;\n\n\t\t/**\n\t\t * Default batch size. A small batch size will make batching less common and may\n\t\t * reduce throughput (a batch size of zero disables batching entirely).\n\t\t */\n\t\tprivate @Nullable DataSize batchSize;\n\n\t\t/**\n\t\t * List of host:port pairs to use for establishing the initial connections to the\n\t\t * Kafka cluster. Overrides the global property, for producers.\n\t\t */\n\t\tprivate @Nullable List<String> bootstrapServers;\n\n\t\t/**\n\t\t * Total memory size the producer can use to buffer records waiting to be sent to\n\t\t * the server.\n\t\t */\n\t\tprivate @Nullable DataSize bufferMemory;\n\n\t\t/**\n\t\t * ID to pass to the server when making requests. Used for server-side logging.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Compression type for all data generated by the producer.\n\t\t */\n\t\tprivate @Nullable String compressionType;\n\n\t\t/**\n\t\t * Serializer class for keys.\n\t\t */\n\t\tprivate Class<?> keySerializer = StringSerializer.class;\n\n\t\t/**\n\t\t * Serializer class for values.\n\t\t */\n\t\tprivate Class<?> valueSerializer = StringSerializer.class;\n\n\t\t/**\n\t\t * When greater than zero, enables retrying of failed sends.\n\t\t */\n\t\tprivate @Nullable Integer retries;\n\n\t\t/**\n\t\t * When non empty, enables transaction support for producer.\n\t\t */\n\t\tprivate @Nullable String transactionIdPrefix;\n\n\t\t/**\n\t\t * Additional producer-specific properties used to configure the client.\n\t\t */\n\t\tprivate final Map<String, String> properties = new HashMap<>();\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic Security getSecurity() {\n\t\t\treturn this.security;\n\t\t}\n\n\t\tpublic @Nullable String getAcks() {\n\t\t\treturn this.acks;\n\t\t}\n\n\t\tpublic void setAcks(@Nullable String acks) {\n\t\t\tthis.acks = acks;\n\t\t}\n\n\t\tpublic @Nullable DataSize getBatchSize() {\n\t\t\treturn this.batchSize;\n\t\t}\n\n\t\tpublic void setBatchSize(@Nullable DataSize batchSize) {\n\t\t\tthis.batchSize = batchSize;\n\t\t}\n\n\t\tpublic @Nullable List<String> getBootstrapServers() {\n\t\t\treturn this.bootstrapServers;\n\t\t}\n\n\t\tpublic void setBootstrapServers(@Nullable List<String> bootstrapServers) {\n\t\t\tthis.bootstrapServers = bootstrapServers;\n\t\t}\n\n\t\tpublic @Nullable DataSize getBufferMemory() {\n\t\t\treturn this.bufferMemory;\n\t\t}\n\n\t\tpublic void setBufferMemory(@Nullable DataSize bufferMemory) {\n\t\t\tthis.bufferMemory = bufferMemory;\n\t\t}\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable String getCompressionType() {\n\t\t\treturn this.compressionType;\n\t\t}\n\n\t\tpublic void setCompressionType(@Nullable String compressionType) {\n\t\t\tthis.compressionType = compressionType;\n\t\t}\n\n\t\tpublic Class<?> getKeySerializer() {\n\t\t\treturn this.keySerializer;\n\t\t}\n\n\t\tpublic void setKeySerializer(Class<?> keySerializer) {\n\t\t\tthis.keySerializer = keySerializer;\n\t\t}\n\n\t\tpublic Class<?> getValueSerializer() {\n\t\t\treturn this.valueSerializer;\n\t\t}\n\n\t\tpublic void setValueSerializer(Class<?> valueSerializer) {\n\t\t\tthis.valueSerializer = valueSerializer;\n\t\t}\n\n\t\tpublic @Nullable Integer getRetries() {\n\t\t\treturn this.retries;\n\t\t}\n\n\t\tpublic void setRetries(@Nullable Integer retries) {\n\t\t\tthis.retries = retries;\n\t\t}\n\n\t\tpublic @Nullable String getTransactionIdPrefix() {\n\t\t\treturn this.transactionIdPrefix;\n\t\t}\n\n\t\tpublic void setTransactionIdPrefix(@Nullable String transactionIdPrefix) {\n\t\t\tthis.transactionIdPrefix = transactionIdPrefix;\n\t\t}\n\n\t\tpublic Map<String, String> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tpublic Map<String, Object> buildProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::getAcks).to(properties.in(ProducerConfig.ACKS_CONFIG));\n\t\t\tmap.from(this::getBatchSize).asInt(DataSize::toBytes).to(properties.in(ProducerConfig.BATCH_SIZE_CONFIG));\n\t\t\tmap.from(this::getBootstrapServers).to(properties.in(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG));\n\t\t\tmap.from(this::getBufferMemory)\n\t\t\t\t.as(DataSize::toBytes)\n\t\t\t\t.to(properties.in(ProducerConfig.BUFFER_MEMORY_CONFIG));\n\t\t\tmap.from(this::getClientId).to(properties.in(ProducerConfig.CLIENT_ID_CONFIG));\n\t\t\tmap.from(this::getCompressionType).to(properties.in(ProducerConfig.COMPRESSION_TYPE_CONFIG));\n\t\t\tmap.from(this::getKeySerializer).to(properties.in(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG));\n\t\t\tmap.from(this::getRetries).to(properties.in(ProducerConfig.RETRIES_CONFIG));\n\t\t\tmap.from(this::getValueSerializer).to(properties.in(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG));\n\t\t\treturn properties.with(this.ssl, this.security, this.properties);\n\t\t}\n\n\t}\n\n\tpublic static class Admin {\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tprivate final Security security = new Security();\n\n\t\t/**\n\t\t * ID to pass to the server when making requests. Used for server-side logging.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Additional admin-specific properties used to configure the client.\n\t\t */\n\t\tprivate final Map<String, String> properties = new HashMap<>();\n\n\t\t/**\n\t\t * Close timeout.\n\t\t */\n\t\tprivate @Nullable Duration closeTimeout;\n\n\t\t/**\n\t\t * Operation timeout.\n\t\t */\n\t\tprivate @Nullable Duration operationTimeout;\n\n\t\t/**\n\t\t * Whether to fail fast if the broker is not available on startup.\n\t\t */\n\t\tprivate boolean failFast;\n\n\t\t/**\n\t\t * Whether to enable modification of existing topic configuration.\n\t\t */\n\t\tprivate boolean modifyTopicConfigs;\n\n\t\t/**\n\t\t * Whether to automatically create topics during context initialization. When set\n\t\t * to false, disables automatic topic creation during context initialization.\n\t\t */\n\t\tprivate boolean autoCreate = true;\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic Security getSecurity() {\n\t\t\treturn this.security;\n\t\t}\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable Duration getCloseTimeout() {\n\t\t\treturn this.closeTimeout;\n\t\t}\n\n\t\tpublic void setCloseTimeout(@Nullable Duration closeTimeout) {\n\t\t\tthis.closeTimeout = closeTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getOperationTimeout() {\n\t\t\treturn this.operationTimeout;\n\t\t}\n\n\t\tpublic void setOperationTimeout(@Nullable Duration operationTimeout) {\n\t\t\tthis.operationTimeout = operationTimeout;\n\t\t}\n\n\t\tpublic boolean isFailFast() {\n\t\t\treturn this.failFast;\n\t\t}\n\n\t\tpublic void setFailFast(boolean failFast) {\n\t\t\tthis.failFast = failFast;\n\t\t}\n\n\t\tpublic boolean isModifyTopicConfigs() {\n\t\t\treturn this.modifyTopicConfigs;\n\t\t}\n\n\t\tpublic void setModifyTopicConfigs(boolean modifyTopicConfigs) {\n\t\t\tthis.modifyTopicConfigs = modifyTopicConfigs;\n\t\t}\n\n\t\tpublic boolean isAutoCreate() {\n\t\t\treturn this.autoCreate;\n\t\t}\n\n\t\tpublic void setAutoCreate(boolean autoCreate) {\n\t\t\tthis.autoCreate = autoCreate;\n\t\t}\n\n\t\tpublic Map<String, String> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tpublic Map<String, Object> buildProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::getClientId).to(properties.in(ProducerConfig.CLIENT_ID_CONFIG));\n\t\t\treturn properties.with(this.ssl, this.security, this.properties);\n\t\t}\n\n\t}\n\n\t/**\n\t * High (and some medium) priority Streams properties and a general properties bucket.\n\t */\n\tpublic static class Streams {\n\n\t\tprivate final Ssl ssl = new Ssl();\n\n\t\tprivate final Security security = new Security();\n\n\t\tprivate final Cleanup cleanup = new Cleanup();\n\n\t\t/**\n\t\t * Kafka streams application.id property; default spring.application.name.\n\t\t */\n\t\tprivate @Nullable String applicationId;\n\n\t\t/**\n\t\t * Whether to auto-start the streams factory bean.\n\t\t */\n\t\tprivate boolean autoStartup = true;\n\n\t\t/**\n\t\t * List of host:port pairs to use for establishing the initial connections to the\n\t\t * Kafka cluster. Overrides the global property, for streams.\n\t\t */\n\t\tprivate @Nullable List<String> bootstrapServers;\n\n\t\t/**\n\t\t * Maximum size of the in-memory state store cache across all threads.\n\t\t */\n\t\tprivate @Nullable DataSize stateStoreCacheMaxSize;\n\n\t\t/**\n\t\t * ID to pass to the server when making requests. Used for server-side logging.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * The replication factor for change log topics and repartition topics created by\n\t\t * the stream processing application.\n\t\t */\n\t\tprivate @Nullable Integer replicationFactor;\n\n\t\t/**\n\t\t * Directory location for the state store.\n\t\t */\n\t\tprivate @Nullable String stateDir;\n\n\t\t/**\n\t\t * Additional Kafka properties used to configure the streams.\n\t\t */\n\t\tprivate final Map<String, String> properties = new HashMap<>();\n\n\t\tpublic Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic Security getSecurity() {\n\t\t\treturn this.security;\n\t\t}\n\n\t\tpublic Cleanup getCleanup() {\n\t\t\treturn this.cleanup;\n\t\t}\n\n\t\tpublic @Nullable String getApplicationId() {\n\t\t\treturn this.applicationId;\n\t\t}\n\n\t\tpublic void setApplicationId(@Nullable String applicationId) {\n\t\t\tthis.applicationId = applicationId;\n\t\t}\n\n\t\tpublic boolean isAutoStartup() {\n\t\t\treturn this.autoStartup;\n\t\t}\n\n\t\tpublic void setAutoStartup(boolean autoStartup) {\n\t\t\tthis.autoStartup = autoStartup;\n\t\t}\n\n\t\tpublic @Nullable List<String> getBootstrapServers() {\n\t\t\treturn this.bootstrapServers;\n\t\t}\n\n\t\tpublic void setBootstrapServers(@Nullable List<String> bootstrapServers) {\n\t\t\tthis.bootstrapServers = bootstrapServers;\n\t\t}\n\n\t\tpublic @Nullable DataSize getStateStoreCacheMaxSize() {\n\t\t\treturn this.stateStoreCacheMaxSize;\n\t\t}\n\n\t\tpublic void setStateStoreCacheMaxSize(@Nullable DataSize stateStoreCacheMaxSize) {\n\t\t\tthis.stateStoreCacheMaxSize = stateStoreCacheMaxSize;\n\t\t}\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable Integer getReplicationFactor() {\n\t\t\treturn this.replicationFactor;\n\t\t}\n\n\t\tpublic void setReplicationFactor(@Nullable Integer replicationFactor) {\n\t\t\tthis.replicationFactor = replicationFactor;\n\t\t}\n\n\t\tpublic @Nullable String getStateDir() {\n\t\t\treturn this.stateDir;\n\t\t}\n\n\t\tpublic void setStateDir(@Nullable String stateDir) {\n\t\t\tthis.stateDir = stateDir;\n\t\t}\n\n\t\tpublic Map<String, String> getProperties() {\n\t\t\treturn this.properties;\n\t\t}\n\n\t\tpublic Map<String, Object> buildProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::getApplicationId).to(properties.in(\"application.id\"));\n\t\t\tmap.from(this::getBootstrapServers).to(properties.in(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG));\n\t\t\tmap.from(this::getStateStoreCacheMaxSize)\n\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t.to(properties.in(\"statestore.cache.max.bytes\"));\n\t\t\tmap.from(this::getClientId).to(properties.in(CommonClientConfigs.CLIENT_ID_CONFIG));\n\t\t\tmap.from(this::getReplicationFactor).to(properties.in(\"replication.factor\"));\n\t\t\tmap.from(this::getStateDir).to(properties.in(\"state.dir\"));\n\t\t\treturn properties.with(this.ssl, this.security, this.properties);\n\t\t}\n\n\t}\n\n\tpublic static class Template {\n\n\t\t/**\n\t\t * Default topic to which messages are sent.\n\t\t */\n\t\tprivate @Nullable String defaultTopic;\n\n\t\t/**\n\t\t * Transaction id prefix, override the transaction id prefix in the producer\n\t\t * factory.\n\t\t */\n\t\tprivate @Nullable String transactionIdPrefix;\n\n\t\t/**\n\t\t * Whether to enable observation.\n\t\t */\n\t\tprivate boolean observationEnabled;\n\n\t\tpublic @Nullable String getDefaultTopic() {\n\t\t\treturn this.defaultTopic;\n\t\t}\n\n\t\tpublic void setDefaultTopic(@Nullable String defaultTopic) {\n\t\t\tthis.defaultTopic = defaultTopic;\n\t\t}\n\n\t\tpublic @Nullable String getTransactionIdPrefix() {\n\t\t\treturn this.transactionIdPrefix;\n\t\t}\n\n\t\tpublic void setTransactionIdPrefix(@Nullable String transactionIdPrefix) {\n\t\t\tthis.transactionIdPrefix = transactionIdPrefix;\n\t\t}\n\n\t\tpublic boolean isObservationEnabled() {\n\t\t\treturn this.observationEnabled;\n\t\t}\n\n\t\tpublic void setObservationEnabled(boolean observationEnabled) {\n\t\t\tthis.observationEnabled = observationEnabled;\n\t\t}\n\n\t}\n\n\tpublic static class Listener {\n\n\t\tpublic enum Type {\n\n\t\t\t/**\n\t\t\t * Invokes the endpoint with one ConsumerRecord at a time.\n\t\t\t */\n\t\t\tSINGLE,\n\n\t\t\t/**\n\t\t\t * Invokes the endpoint with a batch of ConsumerRecords.\n\t\t\t */\n\t\t\tBATCH\n\n\t\t}\n\n\t\t/**\n\t\t * Listener type.\n\t\t */\n\t\tprivate Type type = Type.SINGLE;\n\n\t\t/**\n\t\t * Listener AckMode. See the spring-kafka documentation.\n\t\t */\n\t\tprivate @Nullable AckMode ackMode;\n\n\t\t/**\n\t\t * Support for asynchronous record acknowledgements. Only applies when\n\t\t * spring.kafka.listener.ack-mode is manual or manual-immediate.\n\t\t */\n\t\tprivate @Nullable Boolean asyncAcks;\n\n\t\t/**\n\t\t * Prefix for the listener's consumer client.id property.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Number of threads to run in the listener containers.\n\t\t */\n\t\tprivate @Nullable Integer concurrency;\n\n\t\t/**\n\t\t * Timeout to use when polling the consumer.\n\t\t */\n\t\tprivate @Nullable Duration pollTimeout;\n\n\t\t/**\n\t\t * Multiplier applied to \"pollTimeout\" to determine if a consumer is\n\t\t * non-responsive.\n\t\t */\n\t\tprivate @Nullable Float noPollThreshold;\n\n\t\t/**\n\t\t * Number of records between offset commits when ackMode is \"COUNT\" or\n\t\t * \"COUNT_TIME\".\n\t\t */\n\t\tprivate @Nullable Integer ackCount;\n\n\t\t/**\n\t\t * Time between offset commits when ackMode is \"TIME\" or \"COUNT_TIME\".\n\t\t */\n\t\tprivate @Nullable Duration ackTime;\n\n\t\t/**\n\t\t * Sleep interval between Consumer.poll(Duration) calls.\n\t\t */\n\t\tprivate Duration idleBetweenPolls = Duration.ZERO;\n\n\t\t/**\n\t\t * Time between publishing idle consumer events (no data received).\n\t\t */\n\t\tprivate @Nullable Duration idleEventInterval;\n\n\t\t/**\n\t\t * Time between publishing idle partition consumer events (no data received for\n\t\t * partition).\n\t\t */\n\t\tprivate @Nullable Duration idlePartitionEventInterval;\n\n\t\t/**\n\t\t * Time between checks for non-responsive consumers. If a duration suffix is not\n\t\t * specified, seconds will be used.\n\t\t */\n\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\tprivate @Nullable Duration monitorInterval;\n\n\t\t/**\n\t\t * Whether to log the container configuration during initialization (INFO level).\n\t\t */\n\t\tprivate @Nullable Boolean logContainerConfig;\n\n\t\t/**\n\t\t * Whether the container should fail to start if at least one of the configured\n\t\t * topics are not present on the broker.\n\t\t */\n\t\tprivate boolean missingTopicsFatal;\n\n\t\t/**\n\t\t * Whether the container stops after the current record is processed or after all\n\t\t * the records from the previous poll are processed.\n\t\t */\n\t\tprivate boolean immediateStop;\n\n\t\t/**\n\t\t * Whether to auto start the container.\n\t\t */\n\t\tprivate boolean autoStartup = true;\n\n\t\t/**\n\t\t * Whether to instruct the container to change the consumer thread name during\n\t\t * initialization.\n\t\t */\n\t\tprivate @Nullable Boolean changeConsumerThreadName;\n\n\t\t/**\n\t\t * Whether to enable observation.\n\t\t */\n\t\tprivate boolean observationEnabled;\n\n\t\t/**\n\t\t * Time between retries after authentication exceptions.\n\t\t */\n\t\tprivate @Nullable Duration authExceptionRetryInterval;\n\n\t\tpublic Type getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic void setType(Type type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic @Nullable AckMode getAckMode() {\n\t\t\treturn this.ackMode;\n\t\t}\n\n\t\tpublic void setAckMode(@Nullable AckMode ackMode) {\n\t\t\tthis.ackMode = ackMode;\n\t\t}\n\n\t\tpublic @Nullable Boolean getAsyncAcks() {\n\t\t\treturn this.asyncAcks;\n\t\t}\n\n\t\tpublic void setAsyncAcks(@Nullable Boolean asyncAcks) {\n\t\t\tthis.asyncAcks = asyncAcks;\n\t\t}\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable Integer getConcurrency() {\n\t\t\treturn this.concurrency;\n\t\t}\n\n\t\tpublic void setConcurrency(@Nullable Integer concurrency) {\n\t\t\tthis.concurrency = concurrency;\n\t\t}\n\n\t\tpublic @Nullable Duration getPollTimeout() {\n\t\t\treturn this.pollTimeout;\n\t\t}\n\n\t\tpublic void setPollTimeout(@Nullable Duration pollTimeout) {\n\t\t\tthis.pollTimeout = pollTimeout;\n\t\t}\n\n\t\tpublic @Nullable Float getNoPollThreshold() {\n\t\t\treturn this.noPollThreshold;\n\t\t}\n\n\t\tpublic void setNoPollThreshold(@Nullable Float noPollThreshold) {\n\t\t\tthis.noPollThreshold = noPollThreshold;\n\t\t}\n\n\t\tpublic @Nullable Integer getAckCount() {\n\t\t\treturn this.ackCount;\n\t\t}\n\n\t\tpublic void setAckCount(@Nullable Integer ackCount) {\n\t\t\tthis.ackCount = ackCount;\n\t\t}\n\n\t\tpublic @Nullable Duration getAckTime() {\n\t\t\treturn this.ackTime;\n\t\t}\n\n\t\tpublic void setAckTime(@Nullable Duration ackTime) {\n\t\t\tthis.ackTime = ackTime;\n\t\t}\n\n\t\tpublic Duration getIdleBetweenPolls() {\n\t\t\treturn this.idleBetweenPolls;\n\t\t}\n\n\t\tpublic void setIdleBetweenPolls(Duration idleBetweenPolls) {\n\t\t\tthis.idleBetweenPolls = idleBetweenPolls;\n\t\t}\n\n\t\tpublic @Nullable Duration getIdleEventInterval() {\n\t\t\treturn this.idleEventInterval;\n\t\t}\n\n\t\tpublic void setIdleEventInterval(@Nullable Duration idleEventInterval) {\n\t\t\tthis.idleEventInterval = idleEventInterval;\n\t\t}\n\n\t\tpublic @Nullable Duration getIdlePartitionEventInterval() {\n\t\t\treturn this.idlePartitionEventInterval;\n\t\t}\n\n\t\tpublic void setIdlePartitionEventInterval(@Nullable Duration idlePartitionEventInterval) {\n\t\t\tthis.idlePartitionEventInterval = idlePartitionEventInterval;\n\t\t}\n\n\t\tpublic @Nullable Duration getMonitorInterval() {\n\t\t\treturn this.monitorInterval;\n\t\t}\n\n\t\tpublic void setMonitorInterval(@Nullable Duration monitorInterval) {\n\t\t\tthis.monitorInterval = monitorInterval;\n\t\t}\n\n\t\tpublic @Nullable Boolean getLogContainerConfig() {\n\t\t\treturn this.logContainerConfig;\n\t\t}\n\n\t\tpublic void setLogContainerConfig(@Nullable Boolean logContainerConfig) {\n\t\t\tthis.logContainerConfig = logContainerConfig;\n\t\t}\n\n\t\tpublic boolean isMissingTopicsFatal() {\n\t\t\treturn this.missingTopicsFatal;\n\t\t}\n\n\t\tpublic void setMissingTopicsFatal(boolean missingTopicsFatal) {\n\t\t\tthis.missingTopicsFatal = missingTopicsFatal;\n\t\t}\n\n\t\tpublic boolean isImmediateStop() {\n\t\t\treturn this.immediateStop;\n\t\t}\n\n\t\tpublic void setImmediateStop(boolean immediateStop) {\n\t\t\tthis.immediateStop = immediateStop;\n\t\t}\n\n\t\tpublic boolean isAutoStartup() {\n\t\t\treturn this.autoStartup;\n\t\t}\n\n\t\tpublic void setAutoStartup(boolean autoStartup) {\n\t\t\tthis.autoStartup = autoStartup;\n\t\t}\n\n\t\tpublic @Nullable Boolean getChangeConsumerThreadName() {\n\t\t\treturn this.changeConsumerThreadName;\n\t\t}\n\n\t\tpublic void setChangeConsumerThreadName(@Nullable Boolean changeConsumerThreadName) {\n\t\t\tthis.changeConsumerThreadName = changeConsumerThreadName;\n\t\t}\n\n\t\tpublic boolean isObservationEnabled() {\n\t\t\treturn this.observationEnabled;\n\t\t}\n\n\t\tpublic void setObservationEnabled(boolean observationEnabled) {\n\t\t\tthis.observationEnabled = observationEnabled;\n\t\t}\n\n\t\tpublic @Nullable Duration getAuthExceptionRetryInterval() {\n\t\t\treturn this.authExceptionRetryInterval;\n\t\t}\n\n\t\tpublic void setAuthExceptionRetryInterval(@Nullable Duration authExceptionRetryInterval) {\n\t\t\tthis.authExceptionRetryInterval = authExceptionRetryInterval;\n\t\t}\n\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Name of the SSL bundle to use.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\t/**\n\t\t * Password of the private key in either key store key or key store file.\n\t\t */\n\t\tprivate @Nullable String keyPassword;\n\n\t\t/**\n\t\t * Certificate chain in PEM format with a list of X.509 certificates.\n\t\t */\n\t\tprivate @Nullable String keyStoreCertificateChain;\n\n\t\t/**\n\t\t * Private key in PEM format with PKCS#8 keys.\n\t\t */\n\t\tprivate @Nullable String keyStoreKey;\n\n\t\t/**\n\t\t * Location of the key store file.\n\t\t */\n\t\tprivate @Nullable Resource keyStoreLocation;\n\n\t\t/**\n\t\t * Store password for the key store file.\n\t\t */\n\t\tprivate @Nullable String keyStorePassword;\n\n\t\t/**\n\t\t * Type of the key store.\n\t\t */\n\t\tprivate @Nullable String keyStoreType;\n\n\t\t/**\n\t\t * Trusted certificates in PEM format with X.509 certificates.\n\t\t */\n\t\tprivate @Nullable String trustStoreCertificates;\n\n\t\t/**\n\t\t * Location of the trust store file.\n\t\t */\n\t\tprivate @Nullable Resource trustStoreLocation;\n\n\t\t/**\n\t\t * Store password for the trust store file.\n\t\t */\n\t\tprivate @Nullable String trustStorePassword;\n\n\t\t/**\n\t\t * Type of the trust store.\n\t\t */\n\t\tprivate @Nullable String trustStoreType;\n\n\t\t/**\n\t\t * SSL protocol to use.\n\t\t */\n\t\tprivate @Nullable String protocol;\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t\tpublic @Nullable String getKeyPassword() {\n\t\t\treturn this.keyPassword;\n\t\t}\n\n\t\tpublic void setKeyPassword(@Nullable String keyPassword) {\n\t\t\tthis.keyPassword = keyPassword;\n\t\t}\n\n\t\tpublic @Nullable String getKeyStoreCertificateChain() {\n\t\t\treturn this.keyStoreCertificateChain;\n\t\t}\n\n\t\tpublic void setKeyStoreCertificateChain(@Nullable String keyStoreCertificateChain) {\n\t\t\tthis.keyStoreCertificateChain = keyStoreCertificateChain;\n\t\t}\n\n\t\tpublic @Nullable String getKeyStoreKey() {\n\t\t\treturn this.keyStoreKey;\n\t\t}\n\n\t\tpublic void setKeyStoreKey(@Nullable String keyStoreKey) {\n\t\t\tthis.keyStoreKey = keyStoreKey;\n\t\t}\n\n\t\tpublic @Nullable Resource getKeyStoreLocation() {\n\t\t\treturn this.keyStoreLocation;\n\t\t}\n\n\t\tpublic void setKeyStoreLocation(@Nullable Resource keyStoreLocation) {\n\t\t\tthis.keyStoreLocation = keyStoreLocation;\n\t\t}\n\n\t\tpublic @Nullable String getKeyStorePassword() {\n\t\t\treturn this.keyStorePassword;\n\t\t}\n\n\t\tpublic void setKeyStorePassword(@Nullable String keyStorePassword) {\n\t\t\tthis.keyStorePassword = keyStorePassword;\n\t\t}\n\n\t\tpublic @Nullable String getKeyStoreType() {\n\t\t\treturn this.keyStoreType;\n\t\t}\n\n\t\tpublic void setKeyStoreType(@Nullable String keyStoreType) {\n\t\t\tthis.keyStoreType = keyStoreType;\n\t\t}\n\n\t\tpublic @Nullable String getTrustStoreCertificates() {\n\t\t\treturn this.trustStoreCertificates;\n\t\t}\n\n\t\tpublic void setTrustStoreCertificates(@Nullable String trustStoreCertificates) {\n\t\t\tthis.trustStoreCertificates = trustStoreCertificates;\n\t\t}\n\n\t\tpublic @Nullable Resource getTrustStoreLocation() {\n\t\t\treturn this.trustStoreLocation;\n\t\t}\n\n\t\tpublic void setTrustStoreLocation(@Nullable Resource trustStoreLocation) {\n\t\t\tthis.trustStoreLocation = trustStoreLocation;\n\t\t}\n\n\t\tpublic @Nullable String getTrustStorePassword() {\n\t\t\treturn this.trustStorePassword;\n\t\t}\n\n\t\tpublic void setTrustStorePassword(@Nullable String trustStorePassword) {\n\t\t\tthis.trustStorePassword = trustStorePassword;\n\t\t}\n\n\t\tpublic @Nullable String getTrustStoreType() {\n\t\t\treturn this.trustStoreType;\n\t\t}\n\n\t\tpublic void setTrustStoreType(@Nullable String trustStoreType) {\n\t\t\tthis.trustStoreType = trustStoreType;\n\t\t}\n\n\t\tpublic @Nullable String getProtocol() {\n\t\t\treturn this.protocol;\n\t\t}\n\n\t\tpublic void setProtocol(@Nullable String protocol) {\n\t\t\tthis.protocol = protocol;\n\t\t}\n\n\t\tpublic Map<String, Object> buildProperties() {\n\t\t\tvalidate();\n\t\t\tString bundleName = getBundle();\n\t\t\tProperties properties = new Properties();\n\t\t\tif (StringUtils.hasText(bundleName)) {\n\t\t\t\treturn properties;\n\t\t\t}\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::getKeyPassword).to(properties.in(SslConfigs.SSL_KEY_PASSWORD_CONFIG));\n\t\t\tmap.from(this::getKeyStoreCertificateChain)\n\t\t\t\t.to(properties.in(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG));\n\t\t\tmap.from(this::getKeyStoreKey).to(properties.in(SslConfigs.SSL_KEYSTORE_KEY_CONFIG));\n\t\t\tmap.from(this::getKeyStoreLocation)\n\t\t\t\t.as(this::resourceToPath)\n\t\t\t\t.to(properties.in(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG));\n\t\t\tmap.from(this::getKeyStorePassword).to(properties.in(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG));\n\t\t\tmap.from(this::getKeyStoreType).to(properties.in(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG));\n\t\t\tmap.from(this::getTrustStoreCertificates).to(properties.in(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG));\n\t\t\tmap.from(this::getTrustStoreLocation)\n\t\t\t\t.as(this::resourceToPath)\n\t\t\t\t.to(properties.in(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG));\n\t\t\tmap.from(this::getTrustStorePassword).to(properties.in(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG));\n\t\t\tmap.from(this::getTrustStoreType).to(properties.in(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG));\n\t\t\tmap.from(this::getProtocol).to(properties.in(SslConfigs.SSL_PROTOCOL_CONFIG));\n\t\t\treturn properties;\n\t\t}\n\n\t\t@SuppressWarnings(\"NullAway\") // Doesn't detect lambda with correct nullability\n\t\tprivate void validate() {\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.kafka.ssl.key-store-key\", getKeyStoreKey());\n\t\t\t\tentries.put(\"spring.kafka.ssl.key-store-location\", getKeyStoreLocation());\n\t\t\t}, this::hasValue);\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.kafka.ssl.trust-store-certificates\", getTrustStoreCertificates());\n\t\t\t\tentries.put(\"spring.kafka.ssl.trust-store-location\", getTrustStoreLocation());\n\t\t\t}, this::hasValue);\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.kafka.ssl.bundle\", getBundle());\n\t\t\t\tentries.put(\"spring.kafka.ssl.key-store-key\", getKeyStoreKey());\n\t\t\t}, this::hasValue);\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.kafka.ssl.bundle\", getBundle());\n\t\t\t\tentries.put(\"spring.kafka.ssl.key-store-location\", getKeyStoreLocation());\n\t\t\t}, this::hasValue);\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.kafka.ssl.bundle\", getBundle());\n\t\t\t\tentries.put(\"spring.kafka.ssl.trust-store-certificates\", getTrustStoreCertificates());\n\t\t\t}, this::hasValue);\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\t\tentries.put(\"spring.kafka.ssl.bundle\", getBundle());\n\t\t\t\tentries.put(\"spring.kafka.ssl.trust-store-location\", getTrustStoreLocation());\n\t\t\t}, this::hasValue);\n\t\t}\n\n\t\tprivate boolean hasValue(@Nullable Object value) {\n\t\t\treturn (value instanceof String string) ? StringUtils.hasText(string) : value != null;\n\t\t}\n\n\t\tprivate String resourceToPath(Resource resource) {\n\t\t\ttry {\n\t\t\t\treturn resource.getFile().getAbsolutePath();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Resource '\" + resource + \"' must be on a file system\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static class Jaas {\n\n\t\t/**\n\t\t * Whether to enable JAAS configuration.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Login module.\n\t\t */\n\t\tprivate String loginModule = \"com.sun.security.auth.module.Krb5LoginModule\";\n\n\t\t/**\n\t\t * Control flag for login configuration.\n\t\t */\n\t\tprivate KafkaJaasLoginModuleInitializer.ControlFlag controlFlag = KafkaJaasLoginModuleInitializer.ControlFlag.REQUIRED;\n\n\t\t/**\n\t\t * Additional JAAS options.\n\t\t */\n\t\tprivate final Map<String, String> options = new HashMap<>();\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic String getLoginModule() {\n\t\t\treturn this.loginModule;\n\t\t}\n\n\t\tpublic void setLoginModule(String loginModule) {\n\t\t\tthis.loginModule = loginModule;\n\t\t}\n\n\t\tpublic KafkaJaasLoginModuleInitializer.ControlFlag getControlFlag() {\n\t\t\treturn this.controlFlag;\n\t\t}\n\n\t\tpublic void setControlFlag(KafkaJaasLoginModuleInitializer.ControlFlag controlFlag) {\n\t\t\tthis.controlFlag = controlFlag;\n\t\t}\n\n\t\tpublic Map<String, String> getOptions() {\n\t\t\treturn this.options;\n\t\t}\n\n\t\tpublic void setOptions(Map<String, String> options) {\n\t\t\tif (options != null) {\n\t\t\t\tthis.options.putAll(options);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static class Security {\n\n\t\t/**\n\t\t * Security protocol used to communicate with brokers.\n\t\t */\n\t\tprivate @Nullable String protocol;\n\n\t\tpublic @Nullable String getProtocol() {\n\t\t\treturn this.protocol;\n\t\t}\n\n\t\tpublic void setProtocol(@Nullable String protocol) {\n\t\t\tthis.protocol = protocol;\n\t\t}\n\n\t\tpublic Map<String, Object> buildProperties() {\n\t\t\tProperties properties = new Properties();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(this::getProtocol).to(properties.in(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG));\n\t\t\treturn properties;\n\t\t}\n\n\t}\n\n\tpublic static class Retry {\n\n\t\tprivate final Topic topic = new Topic();\n\n\t\tpublic Topic getTopic() {\n\t\t\treturn this.topic;\n\t\t}\n\n\t\t/**\n\t\t * Properties for non-blocking, topic-based retries.\n\t\t */\n\t\tpublic static class Topic {\n\n\t\t\t/**\n\t\t\t * Whether to enable topic-based non-blocking retries.\n\t\t\t */\n\t\t\tprivate boolean enabled;\n\n\t\t\t/**\n\t\t\t * Total number of processing attempts made before sending the message to the\n\t\t\t * DLT.\n\t\t\t */\n\t\t\tprivate int attempts = 3;\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic int getAttempts() {\n\t\t\t\treturn this.attempts;\n\t\t\t}\n\n\t\t\tpublic void setAttempts(int attempts) {\n\t\t\t\tthis.attempts = attempts;\n\t\t\t}\n\n\t\t\tprivate final Backoff backoff = new Backoff();\n\n\t\t\tpublic Backoff getBackoff() {\n\t\t\t\treturn this.backoff;\n\t\t\t}\n\n\t\t\tpublic static class Backoff {\n\n\t\t\t\t/**\n\t\t\t\t * Base delay after the initial invocation. Can be combined with a\n\t\t\t\t * \"multiplier\" to use an exponential back off strategy.\n\t\t\t\t */\n\t\t\t\tprivate Duration delay = Duration.ofSeconds(1);\n\n\t\t\t\t/**\n\t\t\t\t * Multiplier for a delay for the next retry attempt, applied to the\n\t\t\t\t * previous delay, starting with the initial delay as well as to the\n\t\t\t\t * applicable jitter for each attempt. Fixed delay by default.\n\t\t\t\t */\n\t\t\t\tprivate double multiplier = 1.0;\n\n\t\t\t\t/**\n\t\t\t\t * Maximum delay for any retry attempt, limiting how far jitter and the\n\t\t\t\t * multiplier can increase the delay.\n\t\t\t\t */\n\t\t\t\tprivate Duration maxDelay = Duration.ofSeconds(30);\n\n\t\t\t\t/**\n\t\t\t\t * Jitter value for the base retry attempt, randomly subtracted or added\n\t\t\t\t * to the calculated delay, resulting in a value between 'delay - jitter'\n\t\t\t\t * and 'delay + jitter' but never below the base delay or above the max\n\t\t\t\t * delay.\n\t\t\t\t */\n\t\t\t\tprivate Duration jitter = Duration.ZERO;\n\n\t\t\t\tpublic Duration getDelay() {\n\t\t\t\t\treturn this.delay;\n\t\t\t\t}\n\n\t\t\t\tpublic void setDelay(Duration delay) {\n\t\t\t\t\tthis.delay = delay;\n\t\t\t\t}\n\n\t\t\t\tpublic double getMultiplier() {\n\t\t\t\t\treturn this.multiplier;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMultiplier(double multiplier) {\n\t\t\t\t\tthis.multiplier = multiplier;\n\t\t\t\t}\n\n\t\t\t\tpublic Duration getMaxDelay() {\n\t\t\t\t\treturn this.maxDelay;\n\t\t\t\t}\n\n\t\t\t\tpublic void setMaxDelay(Duration maxDelay) {\n\t\t\t\t\tthis.maxDelay = maxDelay;\n\t\t\t\t}\n\n\t\t\t\tpublic Duration getJitter() {\n\t\t\t\t\treturn this.jitter;\n\t\t\t\t}\n\n\t\t\t\tpublic void setJitter(Duration jitter) {\n\t\t\t\t\tthis.jitter = jitter;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Cleanup {\n\n\t\t/**\n\t\t * Cleanup the application’s local state directory on startup.\n\t\t */\n\t\tprivate boolean onStartup;\n\n\t\t/**\n\t\t * Cleanup the application’s local state directory on shutdown.\n\t\t */\n\t\tprivate boolean onShutdown;\n\n\t\tpublic boolean isOnStartup() {\n\t\t\treturn this.onStartup;\n\t\t}\n\n\t\tpublic void setOnStartup(boolean onStartup) {\n\t\t\tthis.onStartup = onStartup;\n\t\t}\n\n\t\tpublic boolean isOnShutdown() {\n\t\t\treturn this.onShutdown;\n\t\t}\n\n\t\tpublic void setOnShutdown(boolean onShutdown) {\n\t\t\tthis.onShutdown = onShutdown;\n\t\t}\n\n\t}\n\n\tpublic enum IsolationLevel {\n\n\t\t/**\n\t\t * Read everything including aborted transactions.\n\t\t */\n\t\tREAD_UNCOMMITTED((byte) 0),\n\n\t\t/**\n\t\t * Read records from committed transactions, in addition to records not part of\n\t\t * transactions.\n\t\t */\n\t\tREAD_COMMITTED((byte) 1);\n\n\t\tprivate final byte id;\n\n\t\tIsolationLevel(byte id) {\n\t\t\tthis.id = id;\n\t\t}\n\n\t\tpublic byte id() {\n\t\t\treturn this.id;\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"serial\")\n\tprivate static final class Properties extends HashMap<String, Object> {\n\n\t\t<V> java.util.function.Consumer<V> in(String key) {\n\t\t\treturn (value) -> put(key, value);\n\t\t}\n\n\t\tProperties with(Ssl ssl, Security security, Map<String, String> properties) {\n\t\t\tputAll(ssl.buildProperties());\n\t\t\tputAll(security.buildProperties());\n\t\t\tputAll(properties);\n\t\t\treturn this;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/KafkaStreamsAnnotationDrivenConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.util.Map;\n\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.streams.StreamsBuilder;\nimport org.apache.kafka.streams.StreamsConfig;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration;\nimport org.springframework.kafka.config.KafkaStreamsConfiguration;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBean;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBeanConfigurer;\nimport org.springframework.kafka.core.CleanupConfig;\n\n/**\n * Configuration for Kafka Streams annotation-driven support.\n *\n * @author Gary Russell\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(StreamsBuilder.class)\n@ConditionalOnBean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_BUILDER_BEAN_NAME)\nclass KafkaStreamsAnnotationDrivenConfiguration {\n\n\tprivate final KafkaProperties properties;\n\n\tKafkaStreamsAnnotationDrivenConfiguration(KafkaProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@ConditionalOnMissingBean\n\t@Bean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME)\n\tKafkaStreamsConfiguration defaultKafkaStreamsConfig(Environment environment,\n\t\t\tKafkaConnectionDetails connectionDetails) {\n\t\tMap<String, Object> properties = this.properties.buildStreamsProperties();\n\t\tapplyKafkaConnectionDetailsForStreams(properties, connectionDetails);\n\t\tif (this.properties.getStreams().getApplicationId() == null) {\n\t\t\tString applicationName = environment.getProperty(\"spring.application.name\");\n\t\t\tif (applicationName == null) {\n\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"spring.kafka.streams.application-id\", null,\n\t\t\t\t\t\t\"This property is mandatory and fallback 'spring.application.name' is not set either.\");\n\t\t\t}\n\t\t\tproperties.put(StreamsConfig.APPLICATION_ID_CONFIG, applicationName);\n\t\t}\n\t\treturn new KafkaStreamsConfiguration(properties);\n\t}\n\n\t@Bean\n\tStreamsBuilderFactoryBeanConfigurer kafkaPropertiesStreamsBuilderFactoryBeanConfigurer() {\n\t\treturn new KafkaPropertiesStreamsBuilderFactoryBeanConfigurer(this.properties);\n\t}\n\n\tprivate void applyKafkaConnectionDetailsForStreams(Map<String, Object> properties,\n\t\t\tKafkaConnectionDetails connectionDetails) {\n\t\tKafkaConnectionDetails.Configuration streams = connectionDetails.getStreams();\n\t\tproperties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, streams.getBootstrapServers());\n\t\tKafkaAutoConfiguration.applySecurityProtocol(properties, streams.getSecurityProtocol());\n\t\tKafkaAutoConfiguration.applySslBundle(properties, streams.getSslBundle());\n\t}\n\n\tstatic class KafkaPropertiesStreamsBuilderFactoryBeanConfigurer implements StreamsBuilderFactoryBeanConfigurer {\n\n\t\tprivate final KafkaProperties properties;\n\n\t\tKafkaPropertiesStreamsBuilderFactoryBeanConfigurer(KafkaProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configure(StreamsBuilderFactoryBean factoryBean) {\n\t\t\tfactoryBean.setAutoStartup(this.properties.getStreams().isAutoStartup());\n\t\t\tKafkaProperties.Cleanup cleanup = this.properties.getStreams().getCleanup();\n\t\t\tCleanupConfig cleanupConfig = new CleanupConfig(cleanup.isOnStartup(), cleanup.isOnShutdown());\n\t\t\tfactoryBean.setCleanupConfig(cleanupConfig);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/PropertiesKafkaConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Adapts {@link KafkaProperties} to {@link KafkaConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass PropertiesKafkaConnectionDetails implements KafkaConnectionDetails {\n\n\tprivate final KafkaProperties properties;\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\tPropertiesKafkaConnectionDetails(KafkaProperties properties, @Nullable SslBundles sslBundles) {\n\t\tthis.properties = properties;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic List<String> getBootstrapServers() {\n\t\treturn this.properties.getBootstrapServers();\n\t}\n\n\t@Override\n\tpublic Configuration getConsumer() {\n\t\tList<String> servers = this.properties.getConsumer().getBootstrapServers();\n\t\tSslBundle sslBundle = getBundle(this.properties.getConsumer().getSsl());\n\t\tString protocol = this.properties.getConsumer().getSecurity().getProtocol();\n\t\treturn Configuration.of((servers != null) ? servers : getBootstrapServers(),\n\t\t\t\t(sslBundle != null) ? sslBundle : getSslBundle(),\n\t\t\t\t(StringUtils.hasLength(protocol)) ? protocol : getSecurityProtocol());\n\t}\n\n\t@Override\n\tpublic Configuration getProducer() {\n\t\tList<String> servers = this.properties.getProducer().getBootstrapServers();\n\t\tSslBundle sslBundle = getBundle(this.properties.getProducer().getSsl());\n\t\tString protocol = this.properties.getProducer().getSecurity().getProtocol();\n\t\treturn Configuration.of((servers != null) ? servers : getBootstrapServers(),\n\t\t\t\t(sslBundle != null) ? sslBundle : getSslBundle(),\n\t\t\t\t(StringUtils.hasLength(protocol)) ? protocol : getSecurityProtocol());\n\t}\n\n\t@Override\n\tpublic Configuration getStreams() {\n\t\tList<String> servers = this.properties.getStreams().getBootstrapServers();\n\t\tSslBundle sslBundle = getBundle(this.properties.getStreams().getSsl());\n\t\tString protocol = this.properties.getStreams().getSecurity().getProtocol();\n\t\treturn Configuration.of((servers != null) ? servers : getBootstrapServers(),\n\t\t\t\t(sslBundle != null) ? sslBundle : getSslBundle(),\n\t\t\t\t(StringUtils.hasLength(protocol)) ? protocol : getSecurityProtocol());\n\t}\n\n\t@Override\n\tpublic Configuration getAdmin() {\n\t\tSslBundle sslBundle = getBundle(this.properties.getAdmin().getSsl());\n\t\tString protocol = this.properties.getAdmin().getSecurity().getProtocol();\n\t\treturn Configuration.of(getBootstrapServers(), (sslBundle != null) ? sslBundle : getSslBundle(),\n\t\t\t\t(StringUtils.hasLength(protocol)) ? protocol : getSecurityProtocol());\n\t}\n\n\t@Override\n\tpublic @Nullable SslBundle getSslBundle() {\n\t\treturn getBundle(this.properties.getSsl());\n\t}\n\n\t@Override\n\tpublic @Nullable String getSecurityProtocol() {\n\t\treturn this.properties.getSecurity().getProtocol();\n\t}\n\n\tprivate @Nullable SslBundle getBundle(Ssl ssl) {\n\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/SslBundleSslEngineFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.io.IOException;\nimport java.security.KeyStore;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.net.ssl.SSLEngine;\nimport javax.net.ssl.SSLParameters;\n\nimport org.apache.kafka.common.security.auth.SslEngineFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.util.Assert;\n\n/**\n * An {@link SslEngineFactory} that configures creates an {@link SSLEngine} from an\n * {@link SslBundle}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class SslBundleSslEngineFactory implements SslEngineFactory {\n\n\tprivate static final String SSL_BUNDLE_CONFIG_NAME = SslBundle.class.getName();\n\n\tprivate @Nullable Map<String, ?> configs;\n\n\tprivate volatile @Nullable SslBundle sslBundle;\n\n\t@Override\n\tpublic void configure(Map<String, ?> configs) {\n\t\tthis.configs = configs;\n\t\tthis.sslBundle = (SslBundle) configs.get(SSL_BUNDLE_CONFIG_NAME);\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\n\t}\n\n\t@Override\n\tpublic SSLEngine createClientSslEngine(String peerHost, int peerPort, String endpointIdentification) {\n\t\tSslBundle sslBundle = this.sslBundle;\n\t\tAssert.state(sslBundle != null, \"'sslBundle' must not be null\");\n\t\tSSLEngine sslEngine = sslBundle.createSslContext().createSSLEngine(peerHost, peerPort);\n\t\tsslEngine.setUseClientMode(true);\n\t\tSSLParameters sslParams = sslEngine.getSSLParameters();\n\t\tsslParams.setEndpointIdentificationAlgorithm(endpointIdentification);\n\t\tsslEngine.setSSLParameters(sslParams);\n\t\treturn sslEngine;\n\t}\n\n\t@Override\n\tpublic SSLEngine createServerSslEngine(String peerHost, int peerPort) {\n\t\tSslBundle sslBundle = this.sslBundle;\n\t\tAssert.state(sslBundle != null, \"'sslBundle' must not be null\");\n\t\tSSLEngine sslEngine = sslBundle.createSslContext().createSSLEngine(peerHost, peerPort);\n\t\tsslEngine.setUseClientMode(false);\n\t\treturn sslEngine;\n\t}\n\n\t@Override\n\tpublic boolean shouldBeRebuilt(Map<String, Object> nextConfigs) {\n\t\treturn !nextConfigs.equals(this.configs);\n\t}\n\n\t@Override\n\tpublic Set<String> reconfigurableConfigs() {\n\t\treturn Set.of(SSL_BUNDLE_CONFIG_NAME);\n\t}\n\n\t@Override\n\tpublic @Nullable KeyStore keystore() {\n\t\tSslBundle sslBundle = this.sslBundle;\n\t\tAssert.state(sslBundle != null, \"'sslBundle' must not be null\");\n\t\treturn sslBundle.getStores().getKeyStore();\n\t}\n\n\t@Override\n\tpublic @Nullable KeyStore truststore() {\n\t\tSslBundle sslBundle = this.sslBundle;\n\t\tAssert.state(sslBundle != null, \"'sslBundle' must not be null\");\n\t\treturn sslBundle.getStores().getTrustStore();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/metrics/KafkaMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.kafka.KafkaClientMetrics;\nimport io.micrometer.core.instrument.binder.kafka.KafkaStreamsMetrics;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.kafka.autoconfigure.DefaultKafkaConsumerFactoryCustomizer;\nimport org.springframework.boot.kafka.autoconfigure.DefaultKafkaProducerFactoryCustomizer;\nimport org.springframework.boot.kafka.autoconfigure.KafkaAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBean;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBeanConfigurer;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.MicrometerConsumerListener;\nimport org.springframework.kafka.core.MicrometerProducerListener;\nimport org.springframework.kafka.core.ProducerFactory;\nimport org.springframework.kafka.streams.KafkaStreamsMicrometerListener;\n\n/**\n * Auto-configuration for Kafka metrics.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration(before = KafkaAutoConfiguration.class,\n\t\tafterName = { \"org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\" })\n@ConditionalOnClass({ KafkaClientMetrics.class, ProducerFactory.class, MeterRegistry.class })\n@ConditionalOnBean(MeterRegistry.class)\npublic final class KafkaMetricsAutoConfiguration {\n\n\t@Bean\n\tDefaultKafkaProducerFactoryCustomizer kafkaProducerMetrics(MeterRegistry meterRegistry) {\n\t\treturn (producerFactory) -> addListener(producerFactory, meterRegistry);\n\t}\n\n\t@Bean\n\tDefaultKafkaConsumerFactoryCustomizer kafkaConsumerMetrics(MeterRegistry meterRegistry) {\n\t\treturn (consumerFactory) -> addListener(consumerFactory, meterRegistry);\n\t}\n\n\tprivate <K, V> void addListener(DefaultKafkaConsumerFactory<K, V> factory, MeterRegistry meterRegistry) {\n\t\tfactory.addListener(new MicrometerConsumerListener<>(meterRegistry));\n\t}\n\n\tprivate <K, V> void addListener(DefaultKafkaProducerFactory<K, V> factory, MeterRegistry meterRegistry) {\n\t\tfactory.addListener(new MicrometerProducerListener<>(meterRegistry));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ KafkaStreamsMetrics.class, StreamsBuilderFactoryBean.class })\n\tstatic class KafkaStreamsMetricsConfiguration {\n\n\t\t@Bean\n\t\tStreamsBuilderFactoryBeanConfigurer kafkaStreamsMetrics(MeterRegistry meterRegistry) {\n\t\t\treturn (factoryBean) -> factoryBean.addListener(new KafkaStreamsMicrometerListener(meterRegistry));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Apache Kafka metrics.\n */\n@NullMarked\npackage org.springframework.boot.kafka.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Apache Kafka.\n */\n@NullMarked\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/testcontainers/ApacheKafkaContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.testcontainers;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.kafka.KafkaContainer;\n\nimport org.springframework.boot.kafka.autoconfigure.KafkaConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link KafkaConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link KafkaContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Eddú Meléndez\n */\nclass ApacheKafkaContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<KafkaContainer, KafkaConnectionDetails> {\n\n\t@Override\n\tprotected KafkaConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<KafkaContainer> source) {\n\t\treturn new ApacheKafkaContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link KafkaConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class ApacheKafkaContainerConnectionDetails extends ContainerConnectionDetails<KafkaContainer>\n\t\t\timplements KafkaConnectionDetails {\n\n\t\tprivate ApacheKafkaContainerConnectionDetails(ContainerConnectionSource<KafkaContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> getBootstrapServers() {\n\t\t\treturn List.of(getContainer().getBootstrapServers());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getSecurityProtocol() {\n\t\t\treturn (getSslBundle() != null) ? \"SSL\" : \"PLAINTEXT\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/testcontainers/ConfluentKafkaContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.testcontainers;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.kafka.ConfluentKafkaContainer;\n\nimport org.springframework.boot.kafka.autoconfigure.KafkaConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link KafkaConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link ConfluentKafkaContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConfluentKafkaContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<ConfluentKafkaContainer, KafkaConnectionDetails> {\n\n\t@Override\n\tprotected KafkaConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<ConfluentKafkaContainer> source) {\n\t\treturn new ConfluentKafkaContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link KafkaConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class ConfluentKafkaContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<ConfluentKafkaContainer> implements KafkaConnectionDetails {\n\n\t\tprivate ConfluentKafkaContainerConnectionDetails(ContainerConnectionSource<ConfluentKafkaContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> getBootstrapServers() {\n\t\t\treturn List.of(getContainer().getBootstrapServers());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getSecurityProtocol() {\n\t\t\treturn (getSslBundle() != null) ? \"SSL\" : \"PLAINTEXT\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/testcontainers/RedpandaContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.testcontainers;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.redpanda.RedpandaContainer;\n\nimport org.springframework.boot.kafka.autoconfigure.KafkaConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link KafkaConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link RedpandaContainer}.\n *\n * @author Eddú Meléndez\n */\nclass RedpandaContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<RedpandaContainer, KafkaConnectionDetails> {\n\n\t@Override\n\tprotected KafkaConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<RedpandaContainer> source) {\n\t\treturn new RedpandaContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link KafkaConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class RedpandaContainerConnectionDetails extends ContainerConnectionDetails<RedpandaContainer>\n\t\t\timplements KafkaConnectionDetails {\n\n\t\tprivate RedpandaContainerConnectionDetails(ContainerConnectionSource<RedpandaContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> getBootstrapServers() {\n\t\t\treturn List.of(getContainer().getBootstrapServers());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getSecurityProtocol() {\n\t\t\treturn (getSslBundle() != null) ? \"SSL\" : \"PLAINTEXT\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/java/org/springframework/boot/kafka/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Kafka service connections.\n */\n@NullMarked\npackage org.springframework.boot.kafka.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n     {\n      \"name\": \"spring.kafka.admin.ssl.keystore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.admin.ssl.key-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.admin.ssl.keystore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.admin.ssl.key-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.admin.ssl.truststore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.admin.ssl.trust-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.admin.ssl.truststore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.admin.ssl.trust-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.consumer.ssl.keystore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.consumer.ssl.key-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.consumer.ssl.keystore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.consumer.ssl.key-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.consumer.ssl.truststore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.consumer.ssl.trust-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.consumer.ssl.truststore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.consumer.ssl.trust-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.listener.only-log-record-metadata\",\n      \"type\": \"java.lang.Boolean\",\n      \"defaultValue\": true,\n      \"description\": \"Whether to suppress the entire record from being written to the log when retries are being attempted.\",\n      \"deprecation\": {\n        \"reason\": \"Use KafkaUtils#setConsumerRecordFormatter instead.\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.producer.ssl.keystore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.producer.ssl.key-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.producer.ssl.keystore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.producer.ssl.key-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.producer.ssl.truststore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.producer.ssl.trust-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.producer.ssl.truststore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.producer.ssl.trust-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.retry.topic.backoff.random\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.retry.topic.backoff.jitter\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.retry.topic.delay\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.retry.topic.backoff.delay\",\n        \"since\": \"3.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.retry.topic.max-delay\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.retry.topic.backoff.max-delay\",\n        \"since\": \"3.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.retry.topic.multiplier\",\n      \"type\": \"java.lang.Double\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.retry.topic.backoff.multiplier\",\n        \"since\": \"3.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.retry.topic.random-back-off\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.retry.topic.backoff.random\",\n        \"since\": \"3.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.ssl.keystore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.ssl.key-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.ssl.keystore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the key store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.ssl.key-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.ssl.truststore-location\",\n      \"type\": \"org.springframework.core.io.Resource\",\n      \"description\": \"Location of the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.ssl.trust-store-location\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.ssl.truststore-password\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Store password for the trust store file.\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.ssl.trust-store-password\",\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.streams.cache-max-bytes-buffering\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.streams.state-store-cache-max-size\",\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.kafka.streams.cache-max-size-buffering\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"replacement\": \"spring.kafka.streams.state-store-cache-max-size\",\n        \"level\": \"error\",\n        \"since\": \"3.1.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.kafka.consumer.auto-offset-reset\",\n      \"values\": [\n        {\n          \"value\": \"earliest\",\n          \"description\": \"Automatically reset the offset to the earliest offset.\"\n        },\n        {\n          \"value\": \"latest\",\n          \"description\": \"Automatically reset the offset to the latest offset.\"\n        },\n        {\n          \"value\": \"none\",\n          \"description\": \"Throw exception to the consumer if no previous offset is found for the consumer's group.\"\n        },\n        {\n          \"value\": \"exception\",\n          \"description\": \"Throw exception to the consumer.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.kafka.consumer.key-deserializer\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"org.apache.kafka.common.serialization.Deserializer\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.kafka.consumer.value-deserializer\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"org.apache.kafka.common.serialization.Deserializer\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.kafka.producer.key-serializer\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"org.apache.kafka.common.serialization.Serializer\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.kafka.producer.value-serializer\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"org.apache.kafka.common.serialization.Serializer\"\n          }\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-kafka/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.kafka.autoconfigure.KafkaAutoConfiguration\norg.springframework.boot.kafka.autoconfigure.metrics.KafkaMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-kafka/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.kafka.testcontainers.ApacheKafkaContainerConnectionDetailsFactory,\\\norg.springframework.boot.kafka.testcontainers.ConfluentKafkaContainerConnectionDetailsFactory,\\\norg.springframework.boot.kafka.testcontainers.RedpandaContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-kafka/src/test/java/org/springframework/boot/kafka/autoconfigure/ConcurrentKafkaListenerContainerFactoryConfigurerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.function.Function;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;\nimport org.springframework.kafka.core.ConsumerFactory;\nimport org.springframework.kafka.listener.MessageListenerContainer;\nimport org.springframework.kafka.support.micrometer.KafkaListenerObservation.DefaultKafkaListenerObservationConvention;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link ConcurrentKafkaListenerContainerFactoryConfigurer}.\n *\n * @author Moritz Halbritter\n */\nclass ConcurrentKafkaListenerContainerFactoryConfigurerTests {\n\n\tprivate ConcurrentKafkaListenerContainerFactoryConfigurer configurer;\n\n\tprivate ConcurrentKafkaListenerContainerFactory<Object, Object> factory;\n\n\tprivate ConsumerFactory<Object, Object> consumerFactory;\n\n\tprivate KafkaProperties properties;\n\n\t@BeforeEach\n\t@SuppressWarnings(\"unchecked\")\n\tvoid setUp() {\n\t\tthis.configurer = new ConcurrentKafkaListenerContainerFactoryConfigurer();\n\t\tthis.properties = new KafkaProperties();\n\t\tthis.configurer.setKafkaProperties(this.properties);\n\t\tthis.factory = spy(new ConcurrentKafkaListenerContainerFactory<>());\n\t\tthis.consumerFactory = mock(ConsumerFactory.class);\n\n\t}\n\n\t@Test\n\tvoid shouldApplyThreadNameSupplier() {\n\t\tFunction<MessageListenerContainer, String> function = (container) -> \"thread-1\";\n\t\tthis.configurer.setThreadNameSupplier(function);\n\t\tthis.configurer.configure(this.factory, this.consumerFactory);\n\t\tthen(this.factory).should().setThreadNameSupplier(function);\n\t}\n\n\t@Test\n\tvoid shouldApplyChangeConsumerThreadName() {\n\t\tthis.properties.getListener().setChangeConsumerThreadName(true);\n\t\tthis.configurer.configure(this.factory, this.consumerFactory);\n\t\tthen(this.factory).should().setChangeConsumerThreadName(true);\n\t}\n\n\t@Test\n\tvoid shouldApplyListenerTaskExecutor() {\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();\n\t\tthis.configurer.setListenerTaskExecutor(executor);\n\t\tthis.configurer.configure(this.factory, this.consumerFactory);\n\t\tassertThat(this.factory.getContainerProperties().getListenerTaskExecutor()).isEqualTo(executor);\n\t}\n\n\t@Test\n\tvoid shouldApplyAuthExceptionRetryInterval() {\n\t\tthis.properties.getListener().setAuthExceptionRetryInterval(Duration.ofSeconds(10));\n\t\tthis.configurer.configure(this.factory, this.consumerFactory);\n\t\tassertThat(this.factory.getContainerProperties().getAuthExceptionRetryInterval())\n\t\t\t.isEqualTo(Duration.ofSeconds(10));\n\t}\n\n\t@Test\n\tvoid shouldApplyObservationConvention() {\n\t\tDefaultKafkaListenerObservationConvention convention = new DefaultKafkaListenerObservationConvention();\n\t\tthis.configurer.setObservationConvention(convention);\n\t\tthis.configurer.configure(this.factory, this.consumerFactory);\n\t\tassertThat(this.factory.getContainerProperties().getObservationConvention()).isSameAs(convention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/test/java/org/springframework/boot/kafka/autoconfigure/KafkaAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.regex.Pattern;\n\nimport org.apache.kafka.clients.admin.NewTopic;\nimport org.apache.kafka.clients.producer.Producer;\nimport org.apache.kafka.streams.StreamsBuilder;\nimport org.apache.kafka.streams.kstream.KStream;\nimport org.apache.kafka.streams.kstream.KTable;\nimport org.apache.kafka.streams.kstream.Materialized;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.EnableKafkaStreams;\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBean;\nimport org.springframework.kafka.config.TopicBuilder;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.retrytopic.DestinationTopic;\nimport org.springframework.kafka.retrytopic.RetryTopicConfiguration;\nimport org.springframework.kafka.support.KafkaHeaders;\nimport org.springframework.kafka.test.EmbeddedKafkaBroker;\nimport org.springframework.kafka.test.condition.EmbeddedKafkaCondition;\nimport org.springframework.kafka.test.context.EmbeddedKafka;\nimport org.springframework.messaging.handler.annotation.Header;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link KafkaAutoConfiguration}.\n *\n * @author Gary Russell\n * @author Stephane Nicoll\n * @author Tomaz Fernandes\n * @author Andy Wilkinson\n */\n@DisabledOnOs(OS.WINDOWS)\n@EmbeddedKafka(topics = KafkaAutoConfigurationIntegrationTests.TEST_TOPIC)\nclass KafkaAutoConfigurationIntegrationTests {\n\n\tstatic final String TEST_TOPIC = \"testTopic\";\n\tstatic final String TEST_RETRY_TOPIC = \"testRetryTopic\";\n\n\tprivate static final String ADMIN_CREATED_TOPIC = \"adminCreatedTopic\";\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\t@Test\n\tvoid testEndToEnd() throws Exception {\n\t\tload(KafkaConfig.class, \"spring.kafka.bootstrap-servers:\" + getEmbeddedKafkaBrokersAsString(),\n\t\t\t\t\"spring.kafka.consumer.group-id=testGroup\", \"spring.kafka.consumer.auto-offset-reset=earliest\");\n\t\tKafkaTemplate<String, String> template = getContext().getBean(KafkaTemplate.class);\n\t\ttemplate.send(TEST_TOPIC, \"foo\", \"bar\");\n\t\tListener listener = getContext().getBean(Listener.class);\n\t\tassertThat(listener.latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\tassertThat(listener.key).isEqualTo(\"foo\");\n\t\tassertThat(listener.received).isEqualTo(\"bar\");\n\n\t\tDefaultKafkaProducerFactory producerFactory = getContext().getBean(DefaultKafkaProducerFactory.class);\n\t\tProducer producer = producerFactory.createProducer();\n\t\tassertThat(producer.partitionsFor(ADMIN_CREATED_TOPIC)).hasSize(10);\n\t\tproducer.close();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid testEndToEndWithRetryTopics() throws Exception {\n\t\tload(KafkaConfig.class, \"spring.kafka.bootstrap-servers:\" + getEmbeddedKafkaBrokersAsString(),\n\t\t\t\t\"spring.kafka.consumer.group-id=testGroup\", \"spring.kafka.retry.topic.enabled=true\",\n\t\t\t\t\"spring.kafka.retry.topic.attempts=5\", \"spring.kafka.retry.topic.backoff.delay=100ms\",\n\t\t\t\t\"spring.kafka.retry.topic.backoff.multiplier=2\", \"spring.kafka.retry.topic.backoff.max-delay=300ms\",\n\t\t\t\t\"spring.kafka.consumer.auto-offset-reset=earliest\");\n\t\tRetryTopicConfiguration configuration = getContext().getBean(RetryTopicConfiguration.class);\n\t\tassertThat(configuration.getDestinationTopicProperties()).extracting(DestinationTopic.Properties::delay)\n\t\t\t.containsExactly(0L, 100L, 200L, 300L, 0L);\n\t\tKafkaTemplate<String, String> template = getContext().getBean(KafkaTemplate.class);\n\t\ttemplate.send(TEST_RETRY_TOPIC, \"foo\", \"bar\");\n\t\tRetryListener listener = getContext().getBean(RetryListener.class);\n\t\tassertThat(listener.latch.await(30, TimeUnit.SECONDS)).isTrue();\n\t\tassertThat(listener).extracting(RetryListener::getKey, RetryListener::getReceived)\n\t\t\t.containsExactly(\"foo\", \"bar\");\n\t\tassertThat(listener).extracting(RetryListener::getTopics)\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.hasSize(5)\n\t\t\t.containsSequence(\"testRetryTopic\", \"testRetryTopic-retry-0\", \"testRetryTopic-retry-1\",\n\t\t\t\t\t\"testRetryTopic-retry-2\");\n\t}\n\n\t@Test\n\tvoid testStreams() {\n\t\tload(KafkaStreamsConfig.class, \"spring.application.name:my-app\",\n\t\t\t\t\"spring.kafka.bootstrap-servers:\" + getEmbeddedKafkaBrokersAsString());\n\t\tassertThat(getContext().getBean(StreamsBuilderFactoryBean.class).isAutoStartup()).isTrue();\n\t}\n\n\tprivate void load(Class<?> config, String... environment) {\n\t\tthis.context = doLoad(new Class<?>[] { config }, environment);\n\t}\n\n\tprivate AnnotationConfigApplicationContext doLoad(Class<?>[] configs, String... environment) {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tapplicationContext.register(configs);\n\t\tapplicationContext.register(SslAutoConfiguration.class);\n\t\tapplicationContext.register(KafkaAutoConfiguration.class);\n\t\tTestPropertyValues.of(environment).applyTo(applicationContext);\n\t\tapplicationContext.refresh();\n\t\treturn applicationContext;\n\t}\n\n\tprivate String getEmbeddedKafkaBrokersAsString() {\n\t\tEmbeddedKafkaBroker broker = EmbeddedKafkaCondition.getBroker();\n\t\tassertThat(broker).isNotNull();\n\t\treturn broker.getBrokersAsString();\n\t}\n\n\tprivate AnnotationConfigApplicationContext getContext() {\n\t\tAnnotationConfigApplicationContext context = this.context;\n\t\tassertThat(context).isNotNull();\n\t\treturn context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class KafkaConfig {\n\n\t\t@Bean\n\t\tListener listener() {\n\t\t\treturn new Listener();\n\t\t}\n\n\t\t@Bean\n\t\tRetryListener retryListener() {\n\t\t\treturn new RetryListener();\n\t\t}\n\n\t\t@Bean\n\t\tNewTopic adminCreated() {\n\t\t\treturn TopicBuilder.name(ADMIN_CREATED_TOPIC).partitions(10).replicas(1).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableKafkaStreams\n\tstatic class KafkaStreamsConfig {\n\n\t\t@Bean\n\t\tKTable<?, ?> table(StreamsBuilder builder) {\n\t\t\tKStream<Object, Object> stream = builder.stream(Pattern.compile(\"test\"));\n\t\t\treturn stream.groupByKey().count(Materialized.as(\"store\"));\n\t\t}\n\n\t}\n\n\tstatic class Listener {\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate volatile @Nullable String received;\n\n\t\tprivate volatile @Nullable String key;\n\n\t\t@KafkaListener(topics = TEST_TOPIC)\n\t\tvoid listen(String foo, @Header(KafkaHeaders.RECEIVED_KEY) String key) {\n\t\t\tthis.received = foo;\n\t\t\tthis.key = key;\n\t\t\tthis.latch.countDown();\n\t\t}\n\n\t}\n\n\tstatic class RetryListener {\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(5);\n\n\t\tprivate final List<String> topics = new ArrayList<>();\n\n\t\tprivate volatile @Nullable String received;\n\n\t\tprivate volatile @Nullable String key;\n\n\t\t@KafkaListener(topics = TEST_RETRY_TOPIC)\n\t\tvoid listen(String foo, @Header(KafkaHeaders.RECEIVED_KEY) String key,\n\t\t\t\t@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {\n\t\t\tthis.received = foo;\n\t\t\tthis.key = key;\n\t\t\tthis.topics.add(topic);\n\t\t\tthis.latch.countDown();\n\t\t\tthrow new RuntimeException(\"Test exception\");\n\t\t}\n\n\t\tprivate List<String> getTopics() {\n\t\t\treturn this.topics;\n\t\t}\n\n\t\tprivate @Nullable String getReceived() {\n\t\t\treturn this.received;\n\t\t}\n\n\t\tprivate @Nullable String getKey() {\n\t\t\treturn this.key;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/test/java/org/springframework/boot/kafka/autoconfigure/KafkaAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.function.Consumer;\n\nimport javax.security.auth.login.AppConfigurationEntry;\n\nimport org.apache.kafka.clients.CommonClientConfigs;\nimport org.apache.kafka.clients.admin.AdminClientConfig;\nimport org.apache.kafka.clients.consumer.ConsumerConfig;\nimport org.apache.kafka.clients.producer.ProducerConfig;\nimport org.apache.kafka.common.config.SslConfigs;\nimport org.apache.kafka.common.serialization.IntegerDeserializer;\nimport org.apache.kafka.common.serialization.IntegerSerializer;\nimport org.apache.kafka.common.serialization.LongDeserializer;\nimport org.apache.kafka.common.serialization.LongSerializer;\nimport org.apache.kafka.streams.StreamsBuilder;\nimport org.apache.kafka.streams.StreamsConfig;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Retry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.assertj.SimpleAsyncTaskExecutorAssert;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.kafka.annotation.EnableKafkaStreams;\nimport org.springframework.kafka.annotation.KafkaStreamsDefaultConfiguration;\nimport org.springframework.kafka.config.AbstractKafkaListenerContainerFactory;\nimport org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;\nimport org.springframework.kafka.config.ContainerCustomizer;\nimport org.springframework.kafka.config.KafkaListenerContainerFactory;\nimport org.springframework.kafka.config.KafkaStreamsConfiguration;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBean;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBean.Listener;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBeanConfigurer;\nimport org.springframework.kafka.core.CleanupConfig;\nimport org.springframework.kafka.core.ConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.KafkaAdmin;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.listener.AfterRollbackProcessor;\nimport org.springframework.kafka.listener.BatchInterceptor;\nimport org.springframework.kafka.listener.CommonErrorHandler;\nimport org.springframework.kafka.listener.ConcurrentMessageListenerContainer;\nimport org.springframework.kafka.listener.ConsumerAwareRebalanceListener;\nimport org.springframework.kafka.listener.ContainerProperties;\nimport org.springframework.kafka.listener.ContainerProperties.AckMode;\nimport org.springframework.kafka.listener.RecordInterceptor;\nimport org.springframework.kafka.listener.adapter.RecordFilterStrategy;\nimport org.springframework.kafka.retrytopic.DestinationTopic;\nimport org.springframework.kafka.retrytopic.RetryTopicConfiguration;\nimport org.springframework.kafka.security.jaas.KafkaJaasLoginModuleInitializer;\nimport org.springframework.kafka.support.converter.BatchMessageConverter;\nimport org.springframework.kafka.support.converter.BatchMessagingMessageConverter;\nimport org.springframework.kafka.support.converter.MessagingMessageConverter;\nimport org.springframework.kafka.support.converter.RecordMessageConverter;\nimport org.springframework.kafka.support.micrometer.KafkaTemplateObservation.DefaultKafkaTemplateObservationConvention;\nimport org.springframework.kafka.support.micrometer.KafkaTemplateObservationConvention;\nimport org.springframework.kafka.transaction.KafkaAwareTransactionManager;\nimport org.springframework.kafka.transaction.KafkaTransactionManager;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.backoff.ExponentialBackOff;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.assertj.core.api.Assertions.tuple;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link KafkaAutoConfiguration}.\n *\n * @author Gary Russell\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Nakul Mishra\n * @author Tomaz Fernandes\n * @author Thomas Kåsene\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Yanming Zhou\n */\nclass KafkaAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\t@WithResource(name = \"ksLoc\")\n\t@WithResource(name = \"tsLoc\")\n\tvoid consumerProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.kafka.bootstrap-servers=foo:1234\",\n\t\t\t\t\"spring.kafka.properties.foo=bar\", \"spring.kafka.properties.baz=qux\",\n\t\t\t\t\"spring.kafka.properties.foo.bar.baz=qux.fiz.buz\", \"spring.kafka.ssl.key-password=p1\",\n\t\t\t\t\"spring.kafka.ssl.key-store-location=classpath:ksLoc\", \"spring.kafka.ssl.key-store-password=p2\",\n\t\t\t\t\"spring.kafka.ssl.key-store-type=PKCS12\", \"spring.kafka.ssl.trust-store-location=classpath:tsLoc\",\n\t\t\t\t\"spring.kafka.ssl.trust-store-password=p3\", \"spring.kafka.ssl.trust-store-type=PKCS12\",\n\t\t\t\t\"spring.kafka.ssl.protocol=TLSv1.2\", \"spring.kafka.consumer.auto-commit-interval=123\",\n\t\t\t\t\"spring.kafka.consumer.max-poll-records=42\", \"spring.kafka.consumer.max-poll-interval=30s\",\n\t\t\t\t\"spring.kafka.consumer.auto-offset-reset=earliest\", \"spring.kafka.consumer.client-id=ccid\",\n\t\t\t\t// test override common\n\t\t\t\t\"spring.kafka.consumer.enable-auto-commit=false\", \"spring.kafka.consumer.fetch-max-wait=456\",\n\t\t\t\t\"spring.kafka.consumer.properties.fiz.buz=fix.fox\", \"spring.kafka.consumer.fetch-min-size=1KB\",\n\t\t\t\t\"spring.kafka.consumer.group-id=bar\", \"spring.kafka.consumer.heartbeat-interval=234\",\n\t\t\t\t\"spring.kafka.consumer.isolation-level = read-committed\",\n\t\t\t\t\"spring.kafka.consumer.security.protocol = SSL\",\n\t\t\t\t\"spring.kafka.consumer.key-deserializer = org.apache.kafka.common.serialization.LongDeserializer\",\n\t\t\t\t\"spring.kafka.consumer.value-deserializer = org.apache.kafka.common.serialization.IntegerDeserializer\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultKafkaConsumerFactory<?, ?> consumerFactory = context.getBean(DefaultKafkaConsumerFactory.class);\n\t\t\t\tMap<String, Object> configs = consumerFactory.getConfigurationProperties();\n\t\t\t\t// common\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"foo:1234\"));\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEY_PASSWORD_CONFIG, \"p1\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"ksLoc\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, \"p2\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"tsLoc\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, \"p3\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_PROTOCOL_CONFIG, \"TLSv1.2\");\n\t\t\t\t// consumer\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.CLIENT_ID_CONFIG, \"ccid\"); // override\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, Boolean.FALSE);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 123);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, \"earliest\");\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, 456);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.FETCH_MIN_BYTES_CONFIG, 1024);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.GROUP_ID_CONFIG, \"bar\");\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG, 234);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.ISOLATION_LEVEL_CONFIG, \"read_committed\");\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, LongDeserializer.class);\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"SSL\");\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,\n\t\t\t\t\t\tIntegerDeserializer.class);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 42);\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, 30000);\n\t\t\t\tassertThat(configs).containsEntry(\"foo\", \"bar\");\n\t\t\t\tassertThat(configs).containsEntry(\"baz\", \"qux\");\n\t\t\t\tassertThat(configs).containsEntry(\"foo.bar.baz\", \"qux.fiz.buz\");\n\t\t\t\tassertThat(configs).containsEntry(\"fiz.buz\", \"fix.fox\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesKafkaConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid connectionDetailsAreAppliedToConsumer() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kafka.bootstrap-servers=foo:1234\",\n\t\t\t\t\t\"spring.kafka.consumer.bootstrap-servers=foo:1234\", \"spring.kafka.security.protocol=SSL\",\n\t\t\t\t\t\"spring.kafka.consumer.security.protocol=SSL\")\n\t\t\t.withBean(KafkaConnectionDetails.class, this::kafkaConnectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesKafkaConnectionDetails.class);\n\t\t\t\tDefaultKafkaConsumerFactory<?, ?> consumerFactory = context.getBean(DefaultKafkaConsumerFactory.class);\n\t\t\t\tMap<String, Object> configs = consumerFactory.getConfigurationProperties();\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t\tassertThat(configs).containsEntry(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsWithSslBundleAreAppliedToConsumer() {\n\t\tSslBundle sslBundle = SslBundle.of(SslStoreBundle.NONE);\n\t\tKafkaConnectionDetails connectionDetails = new KafkaConnectionDetails() {\n\t\t\t@Override\n\t\t\tpublic List<String> getBootstrapServers() {\n\t\t\t\treturn List.of(\"kafka.example.com:12345\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Configuration getConsumer() {\n\t\t\t\treturn Configuration.of(getBootstrapServers(), sslBundle);\n\t\t\t}\n\n\t\t};\n\t\tthis.contextRunner.withBean(KafkaConnectionDetails.class, () -> connectionDetails).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class);\n\t\t\tDefaultKafkaConsumerFactory<?, ?> consumerFactory = context.getBean(DefaultKafkaConsumerFactory.class);\n\t\t\tMap<String, Object> configs = consumerFactory.getConfigurationProperties();\n\t\t\tassertThat(configs).containsEntry(\"ssl.engine.factory.class\", SslBundleSslEngineFactory.class);\n\t\t\tassertThat(configs).containsEntry(\"org.springframework.boot.ssl.SslBundle\", sslBundle);\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"ksLocP\")\n\t@WithResource(name = \"tsLocP\")\n\tvoid producerProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.kafka.clientId=cid\",\n\t\t\t\t\"spring.kafka.properties.foo.bar.baz=qux.fiz.buz\", \"spring.kafka.producer.acks=all\",\n\t\t\t\t\"spring.kafka.producer.batch-size=2KB\", \"spring.kafka.producer.bootstrap-servers=bar:1234\", // test\n\t\t\t\t// override\n\t\t\t\t\"spring.kafka.producer.buffer-memory=4KB\", \"spring.kafka.producer.compression-type=gzip\",\n\t\t\t\t\"spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.LongSerializer\",\n\t\t\t\t\"spring.kafka.producer.retries=2\", \"spring.kafka.producer.properties.fiz.buz=fix.fox\",\n\t\t\t\t\"spring.kafka.producer.security.protocol=SSL\", \"spring.kafka.producer.ssl.key-password=p4\",\n\t\t\t\t\"spring.kafka.producer.ssl.key-store-location=classpath:ksLocP\",\n\t\t\t\t\"spring.kafka.producer.ssl.key-store-password=p5\", \"spring.kafka.producer.ssl.key-store-type=PKCS12\",\n\t\t\t\t\"spring.kafka.producer.ssl.trust-store-location=classpath:tsLocP\",\n\t\t\t\t\"spring.kafka.producer.ssl.trust-store-password=p6\",\n\t\t\t\t\"spring.kafka.producer.ssl.trust-store-type=PKCS12\", \"spring.kafka.producer.ssl.protocol=TLSv1.2\",\n\t\t\t\t\"spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.IntegerSerializer\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultKafkaProducerFactory<?, ?> producerFactory = context.getBean(DefaultKafkaProducerFactory.class);\n\t\t\t\tMap<String, Object> configs = producerFactory.getConfigurationProperties();\n\t\t\t\t// common\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.CLIENT_ID_CONFIG, \"cid\");\n\t\t\t\t// producer\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.ACKS_CONFIG, \"all\");\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.BATCH_SIZE_CONFIG, 2048);\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"bar:1234\")); // override\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.BUFFER_MEMORY_CONFIG, 4096L);\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.COMPRESSION_TYPE_CONFIG, \"gzip\");\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, LongSerializer.class);\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"SSL\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEY_PASSWORD_CONFIG, \"p4\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"ksLocP\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, \"p5\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"tsLocP\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, \"p6\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_PROTOCOL_CONFIG, \"TLSv1.2\");\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.RETRIES_CONFIG, 2);\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,\n\t\t\t\t\t\tIntegerSerializer.class);\n\t\t\t\tassertThat(context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)).isEmpty();\n\t\t\t\tassertThat(context.getBeansOfType(KafkaTransactionManager.class)).isEmpty();\n\t\t\t\tassertThat(configs).containsEntry(\"foo.bar.baz\", \"qux.fiz.buz\");\n\t\t\t\tassertThat(configs).containsEntry(\"fiz.buz\", \"fix.fox\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsAreAppliedToProducer() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kafka.bootstrap-servers=foo:1234\",\n\t\t\t\t\t\"spring.kafka.producer.bootstrap-servers=foo:1234\", \"spring.kafka.security.protocol=SSL\",\n\t\t\t\t\t\"spring.kafka.producer.security.protocol=SSL\")\n\t\t\t.withBean(KafkaConnectionDetails.class, this::kafkaConnectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesKafkaConnectionDetails.class);\n\t\t\t\tDefaultKafkaProducerFactory<?, ?> producerFactory = context.getBean(DefaultKafkaProducerFactory.class);\n\t\t\t\tMap<String, Object> configs = producerFactory.getConfigurationProperties();\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t\tassertThat(configs).containsEntry(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsWithSslBundleAreAppliedToProducer() {\n\t\tSslBundle sslBundle = SslBundle.of(SslStoreBundle.NONE);\n\t\tKafkaConnectionDetails connectionDetails = new KafkaConnectionDetails() {\n\t\t\t@Override\n\t\t\tpublic List<String> getBootstrapServers() {\n\t\t\t\treturn List.of(\"kafka.example.com:12345\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Configuration getProducer() {\n\t\t\t\treturn Configuration.of(getBootstrapServers(), sslBundle);\n\t\t\t}\n\n\t\t};\n\t\tthis.contextRunner.withBean(KafkaConnectionDetails.class, () -> connectionDetails).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class);\n\t\t\tDefaultKafkaProducerFactory<?, ?> producerFactory = context.getBean(DefaultKafkaProducerFactory.class);\n\t\t\tMap<String, Object> configs = producerFactory.getConfigurationProperties();\n\t\t\tassertThat(configs).containsEntry(\"ssl.engine.factory.class\", SslBundleSslEngineFactory.class);\n\t\t\tassertThat(configs).containsEntry(\"org.springframework.boot.ssl.SslBundle\", sslBundle);\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"ksLocP\")\n\t@WithResource(name = \"tsLocP\")\n\tvoid adminProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kafka.clientId=cid\", \"spring.kafka.properties.foo.bar.baz=qux.fiz.buz\",\n\t\t\t\t\t\"spring.kafka.admin.fail-fast=true\", \"spring.kafka.admin.properties.fiz.buz=fix.fox\",\n\t\t\t\t\t\"spring.kafka.admin.security.protocol=SSL\", \"spring.kafka.admin.ssl.key-password=p4\",\n\t\t\t\t\t\"spring.kafka.admin.ssl.key-store-location=classpath:ksLocP\",\n\t\t\t\t\t\"spring.kafka.admin.ssl.key-store-password=p5\", \"spring.kafka.admin.ssl.key-store-type=PKCS12\",\n\t\t\t\t\t\"spring.kafka.admin.ssl.trust-store-location=classpath:tsLocP\",\n\t\t\t\t\t\"spring.kafka.admin.ssl.trust-store-password=p6\", \"spring.kafka.admin.ssl.trust-store-type=PKCS12\",\n\t\t\t\t\t\"spring.kafka.admin.ssl.protocol=TLSv1.2\", \"spring.kafka.admin.close-timeout=35s\",\n\t\t\t\t\t\"spring.kafka.admin.operation-timeout=60s\", \"spring.kafka.admin.modify-topic-configs=true\",\n\t\t\t\t\t\"spring.kafka.admin.auto-create=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tKafkaAdmin admin = context.getBean(KafkaAdmin.class);\n\t\t\t\tMap<String, Object> configs = admin.getConfigurationProperties();\n\t\t\t\t// common\n\t\t\t\tassertThat(configs).containsEntry(AdminClientConfig.CLIENT_ID_CONFIG, \"cid\");\n\t\t\t\t// admin\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"SSL\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEY_PASSWORD_CONFIG, \"p4\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"ksLocP\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, \"p5\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"tsLocP\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, \"p6\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_PROTOCOL_CONFIG, \"TLSv1.2\");\n\t\t\t\tassertThat(context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)).isEmpty();\n\t\t\t\tassertThat(configs).containsEntry(\"foo.bar.baz\", \"qux.fiz.buz\");\n\t\t\t\tassertThat(configs).containsEntry(\"fiz.buz\", \"fix.fox\");\n\t\t\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"closeTimeout\", Duration.ofSeconds(35));\n\t\t\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"operationTimeout\", 60);\n\t\t\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"fatalIfBrokerNotAvailable\", true);\n\t\t\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"modifyTopicConfigs\", true);\n\t\t\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"autoCreate\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsAreAppliedToAdmin() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kafka.bootstrap-servers=foo:1234\", \"spring.kafka.security.protocol=SSL\",\n\t\t\t\t\t\"spring.kafka.admin.security.protocol=SSL\")\n\t\t\t.withBean(KafkaConnectionDetails.class, this::kafkaConnectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesKafkaConnectionDetails.class);\n\t\t\t\tKafkaAdmin admin = context.getBean(KafkaAdmin.class);\n\t\t\t\tMap<String, Object> configs = admin.getConfigurationProperties();\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t\tassertThat(configs).containsEntry(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsWithSslBundleAreAppliedToAdmin() {\n\t\tSslBundle sslBundle = SslBundle.of(SslStoreBundle.NONE);\n\t\tKafkaConnectionDetails connectionDetails = new KafkaConnectionDetails() {\n\t\t\t@Override\n\t\t\tpublic List<String> getBootstrapServers() {\n\t\t\t\treturn List.of(\"kafka.example.com:12345\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Configuration getAdmin() {\n\t\t\t\treturn Configuration.of(getBootstrapServers(), sslBundle);\n\t\t\t}\n\n\t\t};\n\t\tthis.contextRunner.withBean(KafkaConnectionDetails.class, () -> connectionDetails).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class);\n\t\t\tKafkaAdmin admin = context.getBean(KafkaAdmin.class);\n\t\t\tMap<String, Object> configs = admin.getConfigurationProperties();\n\t\t\tassertThat(configs).containsEntry(\"ssl.engine.factory.class\", SslBundleSslEngineFactory.class);\n\t\t\tassertThat(configs).containsEntry(\"org.springframework.boot.ssl.SslBundle\", sslBundle);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\t@WithResource(name = \"ksLocP\")\n\t@WithResource(name = \"tsLocP\")\n\tvoid streamsProperties() {\n\t\tthis.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.kafka.client-id=cid\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\", \"spring.application.name=appName\",\n\t\t\t\t\t\"spring.kafka.properties.foo.bar.baz=qux.fiz.buz\", \"spring.kafka.streams.auto-startup=false\",\n\t\t\t\t\t\"spring.kafka.streams.state-store-cache-max-size=1KB\", \"spring.kafka.streams.client-id=override\",\n\t\t\t\t\t\"spring.kafka.streams.properties.fiz.buz=fix.fox\", \"spring.kafka.streams.replication-factor=2\",\n\t\t\t\t\t\"spring.kafka.streams.state-dir=/tmp/state\", \"spring.kafka.streams.security.protocol=SSL\",\n\t\t\t\t\t\"spring.kafka.streams.ssl.key-password=p7\",\n\t\t\t\t\t\"spring.kafka.streams.ssl.key-store-location=classpath:ksLocP\",\n\t\t\t\t\t\"spring.kafka.streams.ssl.key-store-password=p8\", \"spring.kafka.streams.ssl.key-store-type=PKCS12\",\n\t\t\t\t\t\"spring.kafka.streams.ssl.trust-store-location=classpath:tsLocP\",\n\t\t\t\t\t\"spring.kafka.streams.ssl.trust-store-password=p9\",\n\t\t\t\t\t\"spring.kafka.streams.ssl.trust-store-type=PKCS12\", \"spring.kafka.streams.ssl.protocol=TLSv1.2\")\n\t\t\t.run((context) -> {\n\t\t\t\tProperties configs = context\n\t\t\t\t\t.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME,\n\t\t\t\t\t\t\tKafkaStreamsConfiguration.class)\n\t\t\t\t\t.asProperties();\n\t\t\t\tassertThat((List<String>) configs.get(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG))\n\t\t\t\t\t.containsExactly(\"localhost:9092\", \"localhost:9093\");\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.STATESTORE_CACHE_MAX_BYTES_CONFIG, 1024);\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.CLIENT_ID_CONFIG, \"override\");\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.REPLICATION_FACTOR_CONFIG, 2);\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"SSL\");\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.STATE_DIR_CONFIG, \"/tmp/state\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEY_PASSWORD_CONFIG, \"p7\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_KEYSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"ksLocP\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_PASSWORD_CONFIG, \"p8\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_KEYSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat((String) configs.get(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG))\n\t\t\t\t\t.endsWith(File.separator + \"tsLocP\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, \"p9\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG, \"PKCS12\");\n\t\t\t\tassertThat(configs).containsEntry(SslConfigs.SSL_PROTOCOL_CONFIG, \"TLSv1.2\");\n\t\t\t\tassertThat(context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)).isEmpty();\n\t\t\t\tassertThat(configs).containsEntry(\"foo.bar.baz\", \"qux.fiz.buz\");\n\t\t\t\tassertThat(configs).containsEntry(\"fiz.buz\", \"fix.fox\");\n\t\t\t\tassertThat(context.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_BUILDER_BEAN_NAME))\n\t\t\t\t\t.isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid streamsBuilderFactoryBeanConfigurerIsApplied() {\n\t\tListener listener = mock(Listener.class);\n\t\tthis.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t// user's StreamsBuilderFactoryBeanConfigurer must be invoked after the\n\t\t\t// default one\n\t\t\t.withBean(StreamsBuilderFactoryBeanConfigurer.class, () -> (factoryBean) -> {\n\t\t\t\tassertThat(factoryBean.isAutoStartup()).isFalse();\n\t\t\t\tassertThat(factoryBean).extracting(\"cleanupConfig.onStart\").isEqualTo(true);\n\t\t\t\tassertThat(factoryBean).extracting(\"cleanupConfig.onStop\").isEqualTo(true);\n\t\t\t\tfactoryBean.addListener(listener);\n\t\t\t})\n\t\t\t.withPropertyValues(\"spring.kafka.client-id=cid\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\", \"spring.application.name=appName\",\n\t\t\t\t\t\"spring.kafka.streams.auto-startup=false\", \"spring.kafka.streams.cleanup.on-shutdown=true\",\n\t\t\t\t\t\"spring.kafka.streams.cleanup.on-startup=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(StreamsBuilderFactoryBean.class);\n\t\t\t\tStreamsBuilderFactoryBean streamsBuilderFactoryBean = context.getBean(StreamsBuilderFactoryBean.class);\n\t\t\t\tassertThat(streamsBuilderFactoryBean.getListeners()).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsAreAppliedToStreams() {\n\t\tthis.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.kafka.streams.auto-startup=false\", \"spring.kafka.streams.application-id=test\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=foo:1234\", \"spring.kafka.streams.bootstrap-servers=foo:1234\",\n\t\t\t\t\t\"spring.kafka.security.protocol=SSL\", \"spring.kafka.streams.security.protocol=SSL\")\n\t\t\t.withBean(KafkaConnectionDetails.class, this::kafkaConnectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesKafkaConnectionDetails.class);\n\t\t\t\tProperties configs = context\n\t\t\t\t\t.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME,\n\t\t\t\t\t\t\tKafkaStreamsConfiguration.class)\n\t\t\t\t\t.asProperties();\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\tCollections.singletonList(\"kafka.example.com:12345\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionDetailsWithSslBundleAreAppliedToStreams() {\n\t\tSslBundle sslBundle = SslBundle.of(SslStoreBundle.NONE);\n\t\tKafkaConnectionDetails connectionDetails = new KafkaConnectionDetails() {\n\t\t\t@Override\n\t\t\tpublic List<String> getBootstrapServers() {\n\t\t\t\treturn List.of(\"kafka.example.com:12345\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Configuration getStreams() {\n\t\t\t\treturn Configuration.of(getBootstrapServers(), sslBundle);\n\t\t\t}\n\t\t};\n\t\tthis.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.kafka.streams.auto-startup=false\", \"spring.kafka.streams.application-id=test\")\n\t\t\t.withBean(KafkaConnectionDetails.class, () -> connectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(KafkaConnectionDetails.class);\n\t\t\t\tProperties configs = context\n\t\t\t\t\t.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME,\n\t\t\t\t\t\t\tKafkaStreamsConfiguration.class)\n\t\t\t\t\t.asProperties();\n\t\t\t\tassertThat(configs).containsEntry(\"ssl.engine.factory.class\", SslBundleSslEngineFactory.class);\n\t\t\t\tassertThat(configs).containsEntry(\"org.springframework.boot.ssl.SslBundle\", sslBundle);\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid streamsApplicationIdUsesMainApplicationNameByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\",\n\t\t\t\t\t\"spring.kafka.streams.auto-startup=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tProperties configs = context\n\t\t\t\t\t.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME,\n\t\t\t\t\t\t\tKafkaStreamsConfiguration.class)\n\t\t\t\t\t.asProperties();\n\t\t\t\tassertThat((List<String>) configs.get(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG))\n\t\t\t\t\t.containsExactly(\"localhost:9092\", \"localhost:9093\");\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.APPLICATION_ID_CONFIG, \"my-test-app\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid streamsWithCustomKafkaConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EnableKafkaStreamsConfiguration.class, TestKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\",\n\t\t\t\t\t\"spring.kafka.streams.auto-startup=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tProperties configs = context\n\t\t\t\t\t.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME,\n\t\t\t\t\t\t\tKafkaStreamsConfiguration.class)\n\t\t\t\t\t.asProperties();\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG,\n\t\t\t\t\t\t\"localhost:9094, localhost:9095\");\n\t\t\t\tassertThat(configs).containsEntry(StreamsConfig.APPLICATION_ID_CONFIG, \"test-id\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid getBackOffWithDefaultsMatchesMapping() {\n\t\tRetry.Topic.Backoff properties = new Retry.Topic.Backoff();\n\t\tassertThat(KafkaAutoConfiguration.getBackOff(properties)).isInstanceOfSatisfying(ExponentialBackOff.class,\n\t\t\t\t(backOff) -> {\n\t\t\t\t\tassertThat(backOff.getInitialInterval()).isEqualTo(properties.getDelay().toMillis());\n\t\t\t\t\tassertThat(backOff.getMultiplier()).isEqualTo(properties.getMultiplier());\n\t\t\t\t\tassertThat(backOff.getMaxInterval()).isEqualTo(properties.getMaxDelay().toMillis());\n\t\t\t\t\tassertThat(backOff.getJitter()).isEqualTo(properties.getJitter().toMillis());\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid retryTopicConfigurationIsNotEnabledByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RetryTopicConfiguration.class));\n\t}\n\n\t@Test\n\tvoid retryTopicConfigurationWithExponentialBackOff() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\", \"spring.kafka.retry.topic.enabled=true\",\n\t\t\t\t\"spring.kafka.retry.topic.attempts=5\", \"spring.kafka.retry.topic.backoff.delay=100ms\",\n\t\t\t\t\"spring.kafka.retry.topic.backoff.multiplier=2\", \"spring.kafka.retry.topic.backoff.max-delay=300ms\")\n\t\t\t.run((context) -> {\n\t\t\t\tRetryTopicConfiguration configuration = context.getBean(RetryTopicConfiguration.class);\n\t\t\t\tassertThat(configuration.getDestinationTopicProperties()).hasSize(5)\n\t\t\t\t\t.extracting(DestinationTopic.Properties::delay, DestinationTopic.Properties::suffix)\n\t\t\t\t\t.containsExactly(tuple(0L, \"\"), tuple(100L, \"-retry-0\"), tuple(200L, \"-retry-1\"),\n\t\t\t\t\t\t\ttuple(300L, \"-retry-2\"), tuple(0L, \"-dlt\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid retryTopicConfigurationWithDefaultProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\", \"spring.kafka.retry.topic.enabled=true\")\n\t\t\t.run(assertRetryTopicConfiguration((configuration) -> {\n\t\t\t\tassertThat(configuration.getDestinationTopicProperties()).hasSize(3)\n\t\t\t\t\t.extracting(DestinationTopic.Properties::delay, DestinationTopic.Properties::suffix)\n\t\t\t\t\t.containsExactly(tuple(0L, \"\"), tuple(1000L, \"-retry\"), tuple(0L, \"-dlt\"));\n\t\t\t\tassertThat(configuration.forKafkaTopicAutoCreation()).extracting(\"shouldCreateTopics\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.BOOLEAN)\n\t\t\t\t\t.isFalse();\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid retryTopicConfigurationWithFixedBackOff() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\", \"spring.kafka.retry.topic.enabled=true\",\n\t\t\t\t\"spring.kafka.retry.topic.attempts=4\", \"spring.kafka.retry.topic.backoff.delay=2s\")\n\t\t\t.run(assertRetryTopicConfiguration(\n\t\t\t\t\t(configuration) -> assertThat(configuration.getDestinationTopicProperties()).hasSize(3)\n\t\t\t\t\t\t.extracting(DestinationTopic.Properties::delay)\n\t\t\t\t\t\t.containsExactly(0L, 2000L, 0L)));\n\t}\n\n\t@Test\n\tvoid retryTopicConfigurationWithNoBackOff() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\", \"spring.kafka.retry.topic.enabled=true\",\n\t\t\t\t\"spring.kafka.retry.topic.attempts=4\", \"spring.kafka.retry.topic.backoff.delay=0\")\n\t\t\t.run(assertRetryTopicConfiguration(\n\t\t\t\t\t(configuration) -> assertThat(configuration.getDestinationTopicProperties()).hasSize(3)\n\t\t\t\t\t\t.extracting(DestinationTopic.Properties::delay)\n\t\t\t\t\t\t.containsExactly(0L, 0L, 0L)));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertRetryTopicConfiguration(\n\t\t\tConsumer<RetryTopicConfiguration> configuration) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(RetryTopicConfiguration.class);\n\t\t\tconfiguration.accept(context.getBean(RetryTopicConfiguration.class));\n\t\t};\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid streamsWithSeveralStreamsBuilderFactoryBeans() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EnableKafkaStreamsConfiguration.class,\n\t\t\t\t\tTestStreamsBuilderFactoryBeanConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\",\n\t\t\t\t\t\"spring.kafka.streams.auto-startup=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tProperties configs = context\n\t\t\t\t\t.getBean(KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME,\n\t\t\t\t\t\t\tKafkaStreamsConfiguration.class)\n\t\t\t\t\t.asProperties();\n\t\t\t\tassertThat((List<String>) configs.get(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG))\n\t\t\t\t\t.containsExactly(\"localhost:9092\", \"localhost:9093\");\n\t\t\t\tthen(context.getBean(\"&firstStreamsBuilderFactoryBean\", StreamsBuilderFactoryBean.class))\n\t\t\t\t\t.should(never())\n\t\t\t\t\t.setAutoStartup(false);\n\t\t\t\tthen(context.getBean(\"&secondStreamsBuilderFactoryBean\", StreamsBuilderFactoryBean.class))\n\t\t\t\t\t.should(never())\n\t\t\t\t\t.setAutoStartup(false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid streamsWithCleanupConfig() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(EnableKafkaStreamsConfiguration.class, TestKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\",\n\t\t\t\t\t\"spring.kafka.bootstrap-servers=localhost:9092,localhost:9093\",\n\t\t\t\t\t\"spring.kafka.streams.auto-startup=false\", \"spring.kafka.streams.cleanup.on-startup=true\",\n\t\t\t\t\t\"spring.kafka.streams.cleanup.on-shutdown=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tStreamsBuilderFactoryBean streamsBuilderFactoryBean = context.getBean(StreamsBuilderFactoryBean.class);\n\t\t\t\tassertThat(streamsBuilderFactoryBean)\n\t\t\t\t\t.extracting(\"cleanupConfig\", InstanceOfAssertFactories.type(CleanupConfig.class))\n\t\t\t\t\t.satisfies((cleanupConfig) -> {\n\t\t\t\t\t\tassertThat(cleanupConfig.cleanupOnStart()).isTrue();\n\t\t\t\t\t\tassertThat(cleanupConfig.cleanupOnStop()).isFalse();\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid streamsApplicationIdIsMandatory() {\n\t\tthis.contextRunner.withUserConfiguration(EnableKafkaStreamsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.hasMessageContaining(\"spring.kafka.streams.application-id\")\n\t\t\t\t.hasMessageContaining(\n\t\t\t\t\t\t\"This property is mandatory and fallback 'spring.application.name' is not set either.\");\n\n\t\t});\n\t}\n\n\t@Test\n\tvoid streamsApplicationIdIsNotMandatoryIfEnableKafkaStreamsIsNotSet() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasNotFailed();\n\t\t\tassertThat(context).doesNotHaveBean(StreamsBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUsePlatformThreadsByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).isNotNull();\n\t\t\tAsyncTaskExecutor listenerTaskExecutor = factory.getContainerProperties().getListenerTaskExecutor();\n\t\t\tassertThat(listenerTaskExecutor).isNull();\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldUseVirtualThreadsIfEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).isNotNull();\n\t\t\tAsyncTaskExecutor listenerTaskExecutor = factory.getContainerProperties().getListenerTaskExecutor();\n\t\t\tassertThat(listenerTaskExecutor).isInstanceOf(SimpleAsyncTaskExecutor.class);\n\t\t\tSimpleAsyncTaskExecutorAssert.assertThat((SimpleAsyncTaskExecutor) listenerTaskExecutor)\n\t\t\t\t.usesVirtualThreads();\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid listenerProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kafka.template.default-topic=testTopic\",\n\t\t\t\t\t\"spring.kafka.template.transaction-id-prefix=txOverride\", \"spring.kafka.listener.ack-mode=MANUAL\",\n\t\t\t\t\t\"spring.kafka.listener.client-id=client\", \"spring.kafka.listener.ack-count=123\",\n\t\t\t\t\t\"spring.kafka.listener.ack-time=456\", \"spring.kafka.listener.concurrency=3\",\n\t\t\t\t\t\"spring.kafka.listener.poll-timeout=2000\", \"spring.kafka.listener.no-poll-threshold=2.5\",\n\t\t\t\t\t\"spring.kafka.listener.type=batch\", \"spring.kafka.listener.idle-between-polls=1s\",\n\t\t\t\t\t\"spring.kafka.listener.idle-event-interval=1s\",\n\t\t\t\t\t\"spring.kafka.listener.idle-partition-event-interval=1s\",\n\t\t\t\t\t\"spring.kafka.listener.monitor-interval=45\", \"spring.kafka.listener.log-container-config=true\",\n\t\t\t\t\t\"spring.kafka.listener.missing-topics-fatal=true\", \"spring.kafka.jaas.enabled=true\",\n\t\t\t\t\t\"spring.kafka.listener.immediate-stop=true\", \"spring.kafka.producer.transaction-id-prefix=foo\",\n\t\t\t\t\t\"spring.kafka.jaas.login-module=foo\", \"spring.kafka.jaas.control-flag=REQUISITE\",\n\t\t\t\t\t\"spring.kafka.jaas.options.useKeyTab=true\", \"spring.kafka.listener.async-acks=true\",\n\t\t\t\t\t\"spring.kafka.template.observation-enabled=true\", \"spring.kafka.listener.observation-enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultKafkaProducerFactory<?, ?> producerFactory = context.getBean(DefaultKafkaProducerFactory.class);\n\t\t\t\tDefaultKafkaConsumerFactory<?, ?> consumerFactory = context.getBean(DefaultKafkaConsumerFactory.class);\n\t\t\t\tKafkaTemplate<?, ?> kafkaTemplate = context.getBean(KafkaTemplate.class);\n\t\t\t\tAbstractKafkaListenerContainerFactory<?, ?, ?> kafkaListenerContainerFactory = (AbstractKafkaListenerContainerFactory<?, ?, ?>) context\n\t\t\t\t\t.getBean(KafkaListenerContainerFactory.class);\n\t\t\t\tassertThat(kafkaTemplate.getMessageConverter()).isInstanceOf(MessagingMessageConverter.class);\n\t\t\t\tassertThat(kafkaTemplate).hasFieldOrPropertyWithValue(\"producerFactory\", producerFactory);\n\t\t\t\tassertThat(kafkaTemplate.getDefaultTopic()).isEqualTo(\"testTopic\");\n\t\t\t\tassertThat(kafkaTemplate).hasFieldOrPropertyWithValue(\"transactionIdPrefix\", \"txOverride\");\n\t\t\t\tassertThat(kafkaTemplate).hasFieldOrPropertyWithValue(\"observationEnabled\", true);\n\t\t\t\tassertThat(kafkaListenerContainerFactory.getConsumerFactory()).isEqualTo(consumerFactory);\n\t\t\t\tContainerProperties containerProperties = kafkaListenerContainerFactory.getContainerProperties();\n\t\t\t\tassertThat(containerProperties.getAckMode()).isEqualTo(AckMode.MANUAL);\n\t\t\t\tassertThat(containerProperties.isAsyncAcks()).isTrue();\n\t\t\t\tassertThat(containerProperties.getClientId()).isEqualTo(\"client\");\n\t\t\t\tassertThat(containerProperties.getAckCount()).isEqualTo(123);\n\t\t\t\tassertThat(containerProperties.getAckTime()).isEqualTo(456L);\n\t\t\t\tassertThat(containerProperties.getPollTimeout()).isEqualTo(2000L);\n\t\t\t\tassertThat(containerProperties.getNoPollThreshold()).isEqualTo(2.5f);\n\t\t\t\tassertThat(containerProperties.getIdleBetweenPolls()).isEqualTo(1000L);\n\t\t\t\tassertThat(containerProperties.getIdleEventInterval()).isEqualTo(1000L);\n\t\t\t\tassertThat(containerProperties.getIdlePartitionEventInterval()).isEqualTo(1000L);\n\t\t\t\tassertThat(containerProperties.getMonitorInterval()).isEqualTo(45);\n\t\t\t\tassertThat(containerProperties.isLogContainerConfig()).isTrue();\n\t\t\t\tassertThat(containerProperties.isMissingTopicsFatal()).isTrue();\n\t\t\t\tassertThat(containerProperties.isStopImmediate()).isTrue();\n\t\t\t\tassertThat(containerProperties.isObservationEnabled()).isTrue();\n\t\t\t\tassertThat(kafkaListenerContainerFactory).extracting(\"concurrency\").isEqualTo(3);\n\t\t\t\tassertThat(kafkaListenerContainerFactory.isBatchListener()).isTrue();\n\t\t\t\tassertThat(kafkaListenerContainerFactory).hasFieldOrPropertyWithValue(\"autoStartup\", true);\n\t\t\t\tassertThat(context.getBeansOfType(KafkaJaasLoginModuleInitializer.class)).hasSize(1);\n\t\t\t\tKafkaJaasLoginModuleInitializer jaas = context.getBean(KafkaJaasLoginModuleInitializer.class);\n\t\t\t\tassertThat(jaas).hasFieldOrPropertyWithValue(\"loginModule\", \"foo\");\n\t\t\t\tassertThat(jaas).hasFieldOrPropertyWithValue(\"controlFlag\",\n\t\t\t\t\t\tAppConfigurationEntry.LoginModuleControlFlag.REQUISITE);\n\t\t\t\tassertThat(context.getBeansOfType(KafkaTransactionManager.class)).hasSize(1);\n\t\t\t\tassertThat(((Map<String, String>) ReflectionTestUtils.getField(jaas, \"options\")))\n\t\t\t\t\t.containsExactly(entry(\"useKeyTab\", \"true\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testKafkaTemplateRecordMessageConverters() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConverterConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.kafka.producer.transaction-id-prefix=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tKafkaTemplate<?, ?> kafkaTemplate = context.getBean(KafkaTemplate.class);\n\t\t\t\tassertThat(kafkaTemplate.getMessageConverter()).isSameAs(context.getBean(\"myMessageConverter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomMessageConverter() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConverterConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(kafkaListenerContainerFactory).hasFieldOrPropertyWithValue(\"recordMessageConverter\",\n\t\t\t\t\tcontext.getBean(\"myMessageConverter\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryInBatchModeWithCustomMessageConverter() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(BatchMessageConverterConfiguration.class, MessageConverterConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.kafka.listener.type=batch\")\n\t\t\t.run((context) -> {\n\t\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\t\tassertThat(kafkaListenerContainerFactory).hasFieldOrPropertyWithValue(\"batchMessageConverter\",\n\t\t\t\t\t\tcontext.getBean(\"myBatchMessageConverter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryInBatchModeWrapsCustomMessageConverter() {\n\t\tthis.contextRunner.withUserConfiguration(MessageConverterConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.kafka.listener.type=batch\")\n\t\t\t.run((context) -> {\n\t\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\t\tObject messageConverter = ReflectionTestUtils.getField(kafkaListenerContainerFactory,\n\t\t\t\t\t\t\"batchMessageConverter\");\n\t\t\t\tassertThat(messageConverter).isInstanceOf(BatchMessagingMessageConverter.class);\n\t\t\t\tassertThat(((BatchMessageConverter) messageConverter).getRecordMessageConverter())\n\t\t\t\t\t.isSameAs(context.getBean(\"myMessageConverter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryInBatchModeWithNoMessageConverter() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.kafka.listener.type=batch\").run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tObject messageConverter = ReflectionTestUtils.getField(kafkaListenerContainerFactory,\n\t\t\t\t\t\"batchMessageConverter\");\n\t\t\tassertThat(messageConverter).isInstanceOf(BatchMessagingMessageConverter.class);\n\t\t\tassertThat(((BatchMessageConverter) messageConverter).getRecordMessageConverter()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithDefaultRecordFilterStrategy() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"recordFilterStrategy\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomRecordFilterStrategy() {\n\t\tthis.contextRunner.withUserConfiguration(RecordFilterStrategyConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"recordFilterStrategy\",\n\t\t\t\t\tcontext.getBean(\"recordFilterStrategy\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomCommonErrorHandler() {\n\t\tthis.contextRunner.withBean(\"errorHandler\", CommonErrorHandler.class, () -> mock(CommonErrorHandler.class))\n\t\t\t.run((context) -> {\n\t\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"commonErrorHandler\", context.getBean(\"errorHandler\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithDefaultTransactionManager() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.kafka.producer.transaction-id-prefix=test\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(KafkaAwareTransactionManager.class);\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory.getContainerProperties().getKafkaAwareTransactionManager())\n\t\t\t\t.isSameAs(context.getBean(KafkaAwareTransactionManager.class));\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomTransactionManager() {\n\t\tKafkaTransactionManager<Object, Object> customTransactionManager = mock(KafkaTransactionManager.class);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customTransactionManager\", KafkaTransactionManager.class, () -> customTransactionManager)\n\t\t\t.withPropertyValues(\"spring.kafka.producer.transaction-id-prefix=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\t\tassertThat(factory.getContainerProperties().getKafkaAwareTransactionManager())\n\t\t\t\t\t.isSameAs(context.getBean(\"customTransactionManager\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomAfterRollbackProcessor() {\n\t\tthis.contextRunner.withUserConfiguration(AfterRollbackProcessorConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"afterRollbackProcessor\",\n\t\t\t\t\tcontext.getBean(\"afterRollbackProcessor\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomRecordInterceptor() {\n\t\tthis.contextRunner.withUserConfiguration(RecordInterceptorConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"recordInterceptor\", context.getBean(\"recordInterceptor\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomBatchInterceptor() {\n\t\tthis.contextRunner.withUserConfiguration(BatchInterceptorConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"batchInterceptor\", context.getBean(\"batchInterceptor\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomRebalanceListener() {\n\t\tthis.contextRunner.withUserConfiguration(RebalanceListenerConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(factory.getContainerProperties()).hasFieldOrPropertyWithValue(\"consumerRebalanceListener\",\n\t\t\t\t\tcontext.getBean(\"rebalanceListener\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithKafkaTemplate() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(kafkaListenerContainerFactory).hasFieldOrPropertyWithValue(\"replyTemplate\",\n\t\t\t\t\tcontext.getBean(KafkaTemplate.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomConsumerFactory() {\n\t\tthis.contextRunner.withUserConfiguration(ConsumerFactoryConfiguration.class).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(kafkaListenerContainerFactory.getConsumerFactory())\n\t\t\t\t.isNotSameAs(context.getBean(ConsumerFactoryConfiguration.class).consumerFactory);\n\t\t});\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@ValueSource(booleans = { true, false })\n\tvoid testConcurrentKafkaListenerContainerFactoryAutoStartup(boolean autoStartup) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.kafka.listener.auto-startup=\" + autoStartup).run((context) -> {\n\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> kafkaListenerContainerFactory = context\n\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\tassertThat(kafkaListenerContainerFactory).hasFieldOrPropertyWithValue(\"autoStartup\", autoStartup);\n\t\t});\n\t}\n\n\t@Test\n\tvoid testConcurrentKafkaListenerContainerFactoryWithCustomContainerCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(ObservationEnabledContainerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConcurrentKafkaListenerContainerFactory<?, ?> factory = context\n\t\t\t\t\t.getBean(ConcurrentKafkaListenerContainerFactory.class);\n\t\t\t\tConcurrentMessageListenerContainer<?, ?> container = factory.createContainer(\"someTopic\");\n\t\t\t\tassertThat(container.getContainerProperties().isObservationEnabled()).isEqualTo(true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid specificSecurityProtocolOverridesCommonSecurityProtocol() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kafka.security.protocol=SSL\", \"spring.kafka.admin.security.protocol=PLAINTEXT\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultKafkaProducerFactory<?, ?> producerFactory = context.getBean(DefaultKafkaProducerFactory.class);\n\t\t\t\tMap<String, Object> producerConfigs = producerFactory.getConfigurationProperties();\n\t\t\t\tassertThat(producerConfigs).containsEntry(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"SSL\");\n\t\t\t\tKafkaAdmin admin = context.getBean(KafkaAdmin.class);\n\t\t\t\tMap<String, Object> configs = admin.getConfigurationProperties();\n\t\t\t\tassertThat(configs).containsEntry(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, \"PLAINTEXT\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew KafkaAutoConfiguration.KafkaRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(SslBundleSslEngineFactory.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid shouldConfigureObservationConvention() {\n\t\tKafkaTemplateObservationConvention convention = new DefaultKafkaTemplateObservationConvention();\n\t\tthis.contextRunner.withBean(KafkaTemplateObservationConvention.class, () -> convention).run((context) -> {\n\t\t\tKafkaTemplate<?, ?> template = context.getBean(KafkaTemplate.class);\n\t\t\tassertThat(template).hasFieldOrPropertyWithValue(\"observationConvention\", convention);\n\t\t});\n\t}\n\n\tprivate KafkaConnectionDetails kafkaConnectionDetails() {\n\t\treturn new KafkaConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic List<String> getBootstrapServers() {\n\t\t\t\treturn List.of(\"kafka.example.com:12345\");\n\t\t\t}\n\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MessageConverterConfiguration {\n\n\t\t@Bean\n\t\tRecordMessageConverter myMessageConverter() {\n\t\t\treturn mock(RecordMessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchMessageConverterConfiguration {\n\n\t\t@Bean\n\t\tBatchMessageConverter myBatchMessageConverter() {\n\t\t\treturn mock(BatchMessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RecordFilterStrategyConfiguration {\n\n\t\t@Bean\n\t\tRecordFilterStrategy<Object, Object> recordFilterStrategy() {\n\t\t\treturn (record) -> false;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AfterRollbackProcessorConfiguration {\n\n\t\t@Bean\n\t\tAfterRollbackProcessor<Object, Object> afterRollbackProcessor() {\n\t\t\treturn (records, consumer, container, ex, recoverable, eosMode) -> {\n\t\t\t\t// no-op\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConsumerFactoryConfiguration {\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate final ConsumerFactory<String, Object> consumerFactory = mock(ConsumerFactory.class);\n\n\t\t@Bean\n\t\tConsumerFactory<String, Object> myConsumerFactory() {\n\t\t\treturn this.consumerFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObservationEnabledContainerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tContainerCustomizer<Object, Object, ConcurrentMessageListenerContainer<Object, Object>> myContainerCustomizer() {\n\t\t\treturn (container) -> container.getContainerProperties().setObservationEnabled(true);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RecordInterceptorConfiguration {\n\n\t\t@Bean\n\t\tRecordInterceptor<Object, Object> recordInterceptor() {\n\t\t\treturn (record, consumer) -> record;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchInterceptorConfiguration {\n\n\t\t@Bean\n\t\tBatchInterceptor<Object, Object> batchInterceptor() {\n\t\t\treturn (batch, consumer) -> batch;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RebalanceListenerConfiguration {\n\n\t\t@Bean\n\t\tConsumerAwareRebalanceListener rebalanceListener() {\n\t\t\treturn mock(ConsumerAwareRebalanceListener.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableKafkaStreams\n\tstatic class EnableKafkaStreamsConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestKafkaStreamsConfiguration {\n\n\t\t@Bean(name = KafkaStreamsDefaultConfiguration.DEFAULT_STREAMS_CONFIG_BEAN_NAME)\n\t\tKafkaStreamsConfiguration kafkaStreamsConfiguration() {\n\t\t\tMap<String, Object> streamsProperties = new HashMap<>();\n\t\t\tstreamsProperties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, \"localhost:9094, localhost:9095\");\n\t\t\tstreamsProperties.put(StreamsConfig.APPLICATION_ID_CONFIG, \"test-id\");\n\n\t\t\treturn new KafkaStreamsConfiguration(streamsProperties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestStreamsBuilderFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tStreamsBuilderFactoryBean firstStreamsBuilderFactoryBean() {\n\t\t\treturn mock(StreamsBuilderFactoryBean.class);\n\t\t}\n\n\t\t@Bean\n\t\tStreamsBuilderFactoryBean secondStreamsBuilderFactoryBean() {\n\t\t\treturn mock(StreamsBuilderFactoryBean.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/test/java/org/springframework/boot/kafka/autoconfigure/KafkaPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.apache.kafka.common.config.SslConfigs;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Admin;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Cleanup;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.IsolationLevel;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties.Listener;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.kafka.core.CleanupConfig;\nimport org.springframework.kafka.core.KafkaAdmin;\nimport org.springframework.kafka.listener.ContainerProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link KafkaProperties}.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass KafkaPropertiesTests {\n\n\t@Test\n\tvoid isolationLevelEnumConsistentWithKafkaVersion() {\n\t\torg.apache.kafka.common.IsolationLevel[] original = org.apache.kafka.common.IsolationLevel.values();\n\t\tassertThat(original).extracting(Enum::name)\n\t\t\t.containsExactly(IsolationLevel.READ_UNCOMMITTED.name(), IsolationLevel.READ_COMMITTED.name());\n\t\tassertThat(original).extracting(\"id\")\n\t\t\t.containsExactly(IsolationLevel.READ_UNCOMMITTED.id(), IsolationLevel.READ_COMMITTED.id());\n\t\tassertThat(original).hasSameSizeAs(IsolationLevel.values());\n\t}\n\n\t@Test\n\tvoid adminDefaultValuesAreConsistent() {\n\t\tKafkaAdmin admin = new KafkaAdmin(Collections.emptyMap());\n\t\tAdmin adminProperties = new KafkaProperties().getAdmin();\n\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"fatalIfBrokerNotAvailable\", adminProperties.isFailFast());\n\t\tassertThat(admin).hasFieldOrPropertyWithValue(\"modifyTopicConfigs\", adminProperties.isModifyTopicConfigs());\n\t}\n\n\t@Test\n\tvoid listenerDefaultValuesAreConsistent() {\n\t\tContainerProperties container = new ContainerProperties(\"test\");\n\t\tListener listenerProperties = new KafkaProperties().getListener();\n\t\tassertThat(listenerProperties.isMissingTopicsFatal()).isEqualTo(container.isMissingTopicsFatal());\n\t}\n\n\t@Test\n\tvoid sslPemConfiguration() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setKeyStoreKey(\"-----BEGINkey\");\n\t\tproperties.getSsl().setTrustStoreCertificates(\"-----BEGINtrust\");\n\t\tproperties.getSsl().setKeyStoreCertificateChain(\"-----BEGINchain\");\n\t\tMap<String, Object> consumerProperties = properties.buildConsumerProperties();\n\t\tassertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_KEY_CONFIG, \"-----BEGINkey\");\n\t\tassertThat(consumerProperties).containsEntry(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG, \"-----BEGINtrust\");\n\t\tassertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG,\n\t\t\t\t\"-----BEGINchain\");\n\t}\n\n\t@Test\n\tvoid sslPemConfigurationWithEmptyBundle() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setKeyStoreKey(\"-----BEGINkey\");\n\t\tproperties.getSsl().setTrustStoreCertificates(\"-----BEGINtrust\");\n\t\tproperties.getSsl().setKeyStoreCertificateChain(\"-----BEGINchain\");\n\t\tproperties.getSsl().setBundle(\"\");\n\t\tMap<String, Object> consumerProperties = properties.buildConsumerProperties();\n\t\tassertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_KEY_CONFIG, \"-----BEGINkey\");\n\t\tassertThat(consumerProperties).containsEntry(SslConfigs.SSL_TRUSTSTORE_CERTIFICATES_CONFIG, \"-----BEGINtrust\");\n\t\tassertThat(consumerProperties).containsEntry(SslConfigs.SSL_KEYSTORE_CERTIFICATE_CHAIN_CONFIG,\n\t\t\t\t\"-----BEGINchain\");\n\t}\n\n\t@Test\n\tvoid sslPropertiesWhenKeyStoreLocationAndKeySetShouldThrowException() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setKeyStoreKey(\"-----BEGIN\");\n\t\tproperties.getSsl().setKeyStoreLocation(new ClassPathResource(\"ksLoc\"));\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(properties::buildConsumerProperties);\n\t}\n\n\t@Test\n\tvoid sslPropertiesWhenTrustStoreLocationAndCertificatesSetShouldThrowException() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setTrustStoreLocation(new ClassPathResource(\"tsLoc\"));\n\t\tproperties.getSsl().setTrustStoreCertificates(\"-----BEGIN\");\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(properties::buildConsumerProperties);\n\t}\n\n\t@Test\n\tvoid sslPropertiesWhenKeyStoreLocationAndBundleSetShouldThrowException() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setBundle(\"myBundle\");\n\t\tproperties.getSsl().setKeyStoreLocation(new ClassPathResource(\"ksLoc\"));\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(properties::buildConsumerProperties);\n\t}\n\n\t@Test\n\tvoid sslPropertiesWhenKeyStoreKeyAndBundleSetShouldThrowException() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setBundle(\"myBundle\");\n\t\tproperties.getSsl().setKeyStoreKey(\"-----BEGIN\");\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(properties::buildConsumerProperties);\n\t}\n\n\t@Test\n\tvoid sslPropertiesWhenTrustStoreLocationAndBundleSetShouldThrowException() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setBundle(\"myBundle\");\n\t\tproperties.getSsl().setTrustStoreLocation(new ClassPathResource(\"tsLoc\"));\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(properties::buildConsumerProperties);\n\t}\n\n\t@Test\n\tvoid sslPropertiesWhenTrustStoreCertificatesAndBundleSetShouldThrowException() {\n\t\tKafkaProperties properties = new KafkaProperties();\n\t\tproperties.getSsl().setBundle(\"myBundle\");\n\t\tproperties.getSsl().setTrustStoreCertificates(\"-----BEGIN\");\n\t\tassertThatExceptionOfType(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t.isThrownBy(properties::buildConsumerProperties);\n\t}\n\n\t@Test\n\tvoid cleanupConfigDefaultValuesAreConsistent() {\n\t\tCleanupConfig cleanupConfig = new CleanupConfig();\n\t\tCleanup cleanup = new KafkaProperties().getStreams().getCleanup();\n\t\tassertThat(cleanup.isOnStartup()).isEqualTo(cleanupConfig.cleanupOnStart());\n\t\tassertThat(cleanup.isOnShutdown()).isEqualTo(cleanupConfig.cleanupOnStop());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kafka/src/test/java/org/springframework/boot/kafka/autoconfigure/metrics/KafkaMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kafka.autoconfigure.metrics;\n\nimport java.util.regex.Pattern;\n\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.apache.kafka.streams.StreamsBuilder;\nimport org.apache.kafka.streams.kstream.KStream;\nimport org.apache.kafka.streams.kstream.KTable;\nimport org.apache.kafka.streams.kstream.Materialized;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.kafka.autoconfigure.KafkaAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.annotation.EnableKafkaStreams;\nimport org.springframework.kafka.config.StreamsBuilderFactoryBean;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.MicrometerConsumerListener;\nimport org.springframework.kafka.core.MicrometerProducerListener;\nimport org.springframework.kafka.streams.KafkaStreamsMicrometerListener;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link KafkaMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass KafkaMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(KafkaMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid whenThereIsAMeterRegistryThenMetricsListenersAreAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(((DefaultKafkaProducerFactory<?, ?>) context.getBean(DefaultKafkaProducerFactory.class))\n\t\t\t\t\t.getListeners()).hasSize(1).hasOnlyElementsOfTypes(MicrometerProducerListener.class);\n\t\t\t\tassertThat(((DefaultKafkaConsumerFactory<?, ?>) context.getBean(DefaultKafkaConsumerFactory.class))\n\t\t\t\t\t.getListeners()).hasSize(1).hasOnlyElementsOfTypes(MicrometerConsumerListener.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMeterRegistryThenListenerCustomizationBacksOff() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class)).run((context) -> {\n\t\t\tassertThat(((DefaultKafkaProducerFactory<?, ?>) context.getBean(DefaultKafkaProducerFactory.class))\n\t\t\t\t.getListeners()).isEmpty();\n\t\t\tassertThat(((DefaultKafkaConsumerFactory<?, ?>) context.getBean(DefaultKafkaConsumerFactory.class))\n\t\t\t\t.getListeners()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenKafkaStreamsIsEnabledAndThereIsAMeterRegistryThenMetricsListenersAreAdded() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class))\n\t\t\t.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\")\n\t\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.run((context) -> {\n\t\t\t\tStreamsBuilderFactoryBean streamsBuilderFactoryBean = context.getBean(StreamsBuilderFactoryBean.class);\n\t\t\t\tassertThat(streamsBuilderFactoryBean.getListeners()).hasSize(1)\n\t\t\t\t\t.hasOnlyElementsOfTypes(KafkaStreamsMicrometerListener.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenKafkaStreamsIsEnabledAndThereIsNoMeterRegistryThenListenerCustomizationBacksOff() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(KafkaAutoConfiguration.class))\n\t\t\t.withUserConfiguration(EnableKafkaStreamsConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.application.name=my-test-app\")\n\t\t\t.run((context) -> {\n\t\t\t\tStreamsBuilderFactoryBean streamsBuilderFactoryBean = context.getBean(StreamsBuilderFactoryBean.class);\n\t\t\t\tassertThat(streamsBuilderFactoryBean.getListeners()).isEmpty();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableKafkaStreams\n\tstatic class EnableKafkaStreamsConfiguration {\n\n\t\t@Bean\n\t\tKTable<?, ?> table(StreamsBuilder builder) {\n\t\t\tKStream<Object, Object> stream = builder.stream(Pattern.compile(\"test\"));\n\t\t\treturn stream.groupByKey().count(Materialized.as(\"store\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"org.jetbrains.kotlin.plugin.serialization\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Kotlinx Serialization JSON\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.jetbrains.kotlinx:kotlinx-serialization-json\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.jetbrains.kotlin:kotlin-reflect\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kotlinx.serialization.json.autoconfigure;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport kotlin.Unit;\nimport kotlin.jvm.functions.Function1;\nimport kotlinx.serialization.json.Json;\nimport kotlinx.serialization.json.JsonBuilder;\nimport kotlinx.serialization.json.JsonKt;\nimport kotlinx.serialization.json.JsonNamingStrategy;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Kotlinx Serialization JSON.\n *\n * @author Dmitry Sulman\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Json.class)\n@EnableConfigurationProperties(KotlinxSerializationJsonProperties.class)\npublic final class KotlinxSerializationJsonAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJson kotlinSerializationJson(List<KotlinxSerializationJsonBuilderCustomizer> customizers) {\n\t\tFunction1<JsonBuilder, Unit> builderAction = (jsonBuilder) -> {\n\t\t\tcustomizers.forEach((c) -> c.customize(jsonBuilder));\n\t\t\treturn Unit.INSTANCE;\n\t\t};\n\t\treturn JsonKt.Json(Json.Default, builderAction);\n\t}\n\n\t@Bean\n\tStandardKotlinSerializationJsonBuilderCustomizer standardKotlinSerializationJsonBuilderCustomizer(\n\t\t\tKotlinxSerializationJsonProperties kotlinSerializationProperties) {\n\t\treturn new StandardKotlinSerializationJsonBuilderCustomizer(kotlinSerializationProperties);\n\t}\n\n\tstatic final class StandardKotlinSerializationJsonBuilderCustomizer\n\t\t\timplements KotlinxSerializationJsonBuilderCustomizer, Ordered {\n\n\t\tprivate final KotlinxSerializationJsonProperties properties;\n\n\t\tStandardKotlinSerializationJsonBuilderCustomizer(KotlinxSerializationJsonProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(JsonBuilder jsonBuilder) {\n\t\t\tKotlinxSerializationJsonProperties properties = this.properties;\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getNamingStrategy).to(setNamingStrategy(jsonBuilder));\n\t\t\tmap.from(properties::isPrettyPrint).to(jsonBuilder::setPrettyPrint);\n\t\t\tmap.from(properties::isLenient).to(jsonBuilder::setLenient);\n\t\t\tmap.from(properties::isIgnoreUnknownKeys).to(jsonBuilder::setIgnoreUnknownKeys);\n\t\t\tmap.from(properties::isEncodeDefaults).to(jsonBuilder::setEncodeDefaults);\n\t\t\tmap.from(properties::isExplicitNulls).to(jsonBuilder::setExplicitNulls);\n\t\t\tmap.from(properties::isCoerceInputValues).to(jsonBuilder::setCoerceInputValues);\n\t\t\tmap.from(properties::isAllowStructuredMapKeys).to(jsonBuilder::setAllowStructuredMapKeys);\n\t\t\tmap.from(properties::isAllowSpecialFloatingPointValues).to(jsonBuilder::setAllowSpecialFloatingPointValues);\n\t\t\tmap.from(properties::getClassDiscriminator).to(jsonBuilder::setClassDiscriminator);\n\t\t\tmap.from(properties::getClassDiscriminatorMode).to(jsonBuilder::setClassDiscriminatorMode);\n\t\t\tmap.from(properties::isDecodeEnumsCaseInsensitive).to(jsonBuilder::setDecodeEnumsCaseInsensitive);\n\t\t\tmap.from(properties::isUseAlternativeNames).to(jsonBuilder::setUseAlternativeNames);\n\t\t\tmap.from(properties::isAllowTrailingComma).to(jsonBuilder::setAllowTrailingComma);\n\t\t\tmap.from(properties::isAllowComments).to(jsonBuilder::setAllowComments);\n\t\t}\n\n\t\tprivate Consumer<KotlinxSerializationJsonProperties.JsonNamingStrategy> setNamingStrategy(JsonBuilder builder) {\n\t\t\treturn (strategy) -> {\n\t\t\t\tJsonNamingStrategy namingStrategy = switch (strategy) {\n\t\t\t\t\tcase SNAKE_CASE -> JsonNamingStrategy.Builtins.getSnakeCase();\n\t\t\t\t\tcase KEBAB_CASE -> JsonNamingStrategy.Builtins.getKebabCase();\n\t\t\t\t};\n\t\t\t\tbuilder.setNamingStrategy(namingStrategy);\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kotlinx.serialization.json.autoconfigure;\n\nimport kotlinx.serialization.json.Json;\nimport kotlinx.serialization.json.JsonBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to further customize the\n * {@link Json} through {@link JsonBuilder} retaining its default configuration.\n *\n * @author Dmitry Sulman\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface KotlinxSerializationJsonBuilderCustomizer {\n\n\t/**\n\t * Customize the Kotlin Serialization {@link Json} through {@link JsonBuilder}.\n\t * @param jsonBuilder the {@link JsonBuilder} to customize\n\t */\n\tvoid customize(JsonBuilder jsonBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kotlinx.serialization.json.autoconfigure;\n\nimport kotlinx.serialization.json.ClassDiscriminatorMode;\nimport kotlinx.serialization.json.Json;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties to configure Kotlinx Serialization {@link Json}.\n *\n * @author Dmitry Sulman\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.kotlinx.serialization.json\")\npublic class KotlinxSerializationJsonProperties {\n\n\t/**\n\t * Specifies JsonNamingStrategy that should be used for all properties in classes for\n\t * serialization and deserialization.\n\t */\n\tprivate @Nullable JsonNamingStrategy namingStrategy;\n\n\t/**\n\t * Whether resulting JSON should be pretty-printed.\n\t */\n\tprivate boolean prettyPrint;\n\n\t/**\n\t * Whether parser should operate in lenient mode, removing the JSON specification\n\t * restriction (RFC-4627) and being more liberal to malformed input.\n\t */\n\tprivate boolean lenient;\n\n\t/**\n\t * Whether encounters of unknown properties in the input JSON should be ignored\n\t * instead of throwing SerializationException.\n\t */\n\tprivate boolean ignoreUnknownKeys;\n\n\t/**\n\t * Whether default values of Kotlin properties should be encoded.\n\t */\n\tprivate boolean encodeDefaults;\n\n\t/**\n\t * Whether null values should be encoded for nullable properties and must be present\n\t * in JSON object during decoding.\n\t */\n\tprivate boolean explicitNulls = true;\n\n\t/**\n\t * Whether to coerce incorrect JSON values.\n\t */\n\tprivate boolean coerceInputValues;\n\n\t/**\n\t * Whether to allow structured objects to be serialized as map keys by changing the\n\t * serialized form of the map from JSON object (key-value pairs) to flat array like\n\t * [k1, v1, k2, v2].\n\t */\n\tprivate boolean allowStructuredMapKeys;\n\n\t/**\n\t * Whether to remove the JSON specification restriction on special floating-point\n\t * values such as 'NaN' and 'Infinity' and allow their serialization and\n\t * deserialization as float literals without quotes.\n\t */\n\tprivate boolean allowSpecialFloatingPointValues;\n\n\t/**\n\t * Name of the class descriptor property for polymorphic serialization.\n\t */\n\tprivate String classDiscriminator = \"type\";\n\n\t/**\n\t * Defines which classes and objects should have class discriminator added to the\n\t * output.\n\t */\n\tprivate ClassDiscriminatorMode classDiscriminatorMode = ClassDiscriminatorMode.POLYMORPHIC;\n\n\t/**\n\t * Whether enum values are decoded in a case-insensitive manner.\n\t */\n\tprivate boolean decodeEnumsCaseInsensitive;\n\n\t/**\n\t * Whether Json instance makes use of JsonNames annotation.\n\t */\n\tprivate boolean useAlternativeNames = true;\n\n\t/**\n\t * Whether to allow parser to accept trailing commas in JSON objects and arrays.\n\t */\n\tprivate boolean allowTrailingComma;\n\n\t/**\n\t * Whether to allow parser to accept C/Java-style comments in JSON input.\n\t */\n\tprivate boolean allowComments;\n\n\tpublic @Nullable JsonNamingStrategy getNamingStrategy() {\n\t\treturn this.namingStrategy;\n\t}\n\n\tpublic void setNamingStrategy(@Nullable JsonNamingStrategy namingStrategy) {\n\t\tthis.namingStrategy = namingStrategy;\n\t}\n\n\tpublic boolean isPrettyPrint() {\n\t\treturn this.prettyPrint;\n\t}\n\n\tpublic void setPrettyPrint(boolean prettyPrint) {\n\t\tthis.prettyPrint = prettyPrint;\n\t}\n\n\tpublic boolean isLenient() {\n\t\treturn this.lenient;\n\t}\n\n\tpublic void setLenient(boolean lenient) {\n\t\tthis.lenient = lenient;\n\t}\n\n\tpublic boolean isIgnoreUnknownKeys() {\n\t\treturn this.ignoreUnknownKeys;\n\t}\n\n\tpublic void setIgnoreUnknownKeys(boolean ignoreUnknownKeys) {\n\t\tthis.ignoreUnknownKeys = ignoreUnknownKeys;\n\t}\n\n\tpublic boolean isEncodeDefaults() {\n\t\treturn this.encodeDefaults;\n\t}\n\n\tpublic void setEncodeDefaults(boolean encodeDefaults) {\n\t\tthis.encodeDefaults = encodeDefaults;\n\t}\n\n\tpublic boolean isExplicitNulls() {\n\t\treturn this.explicitNulls;\n\t}\n\n\tpublic void setExplicitNulls(boolean explicitNulls) {\n\t\tthis.explicitNulls = explicitNulls;\n\t}\n\n\tpublic boolean isCoerceInputValues() {\n\t\treturn this.coerceInputValues;\n\t}\n\n\tpublic void setCoerceInputValues(boolean coerceInputValues) {\n\t\tthis.coerceInputValues = coerceInputValues;\n\t}\n\n\tpublic boolean isAllowStructuredMapKeys() {\n\t\treturn this.allowStructuredMapKeys;\n\t}\n\n\tpublic void setAllowStructuredMapKeys(boolean allowStructuredMapKeys) {\n\t\tthis.allowStructuredMapKeys = allowStructuredMapKeys;\n\t}\n\n\tpublic boolean isAllowSpecialFloatingPointValues() {\n\t\treturn this.allowSpecialFloatingPointValues;\n\t}\n\n\tpublic void setAllowSpecialFloatingPointValues(boolean allowSpecialFloatingPointValues) {\n\t\tthis.allowSpecialFloatingPointValues = allowSpecialFloatingPointValues;\n\t}\n\n\tpublic String getClassDiscriminator() {\n\t\treturn this.classDiscriminator;\n\t}\n\n\tpublic void setClassDiscriminator(String classDiscriminator) {\n\t\tthis.classDiscriminator = classDiscriminator;\n\t}\n\n\tpublic ClassDiscriminatorMode getClassDiscriminatorMode() {\n\t\treturn this.classDiscriminatorMode;\n\t}\n\n\tpublic void setClassDiscriminatorMode(ClassDiscriminatorMode classDiscriminatorMode) {\n\t\tthis.classDiscriminatorMode = classDiscriminatorMode;\n\t}\n\n\tpublic boolean isDecodeEnumsCaseInsensitive() {\n\t\treturn this.decodeEnumsCaseInsensitive;\n\t}\n\n\tpublic void setDecodeEnumsCaseInsensitive(boolean decodeEnumsCaseInsensitive) {\n\t\tthis.decodeEnumsCaseInsensitive = decodeEnumsCaseInsensitive;\n\t}\n\n\tpublic boolean isUseAlternativeNames() {\n\t\treturn this.useAlternativeNames;\n\t}\n\n\tpublic void setUseAlternativeNames(boolean useAlternativeNames) {\n\t\tthis.useAlternativeNames = useAlternativeNames;\n\t}\n\n\tpublic boolean isAllowTrailingComma() {\n\t\treturn this.allowTrailingComma;\n\t}\n\n\tpublic void setAllowTrailingComma(boolean allowTrailingComma) {\n\t\tthis.allowTrailingComma = allowTrailingComma;\n\t}\n\n\tpublic boolean isAllowComments() {\n\t\treturn this.allowComments;\n\t}\n\n\tpublic void setAllowComments(boolean allowComments) {\n\t\tthis.allowComments = allowComments;\n\t}\n\n\t/**\n\t * Enum representing strategies for JSON property naming. The values correspond to\n\t * {@link kotlinx.serialization.json.JsonNamingStrategy} implementations that cannot\n\t * be directly referenced.\n\t */\n\tpublic enum JsonNamingStrategy {\n\n\t\t/**\n\t\t * Snake case strategy.\n\t\t */\n\t\tSNAKE_CASE,\n\n\t\t/**\n\t\t * Kebab case strategy.\n\t\t */\n\t\tKEBAB_CASE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/main/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Kotlinx Serialization JSON.\n */\n@NullMarked\npackage org.springframework.boot.kotlinx.serialization.json.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.kotlinx.serialization.json.autoconfigure.KotlinxSerializationJsonAutoConfiguration"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.json.AutoConfigureJson.imports",
    "content": "optional:org.springframework.boot.kotlinx.serialization.json.autoconfigure.KotlinxSerializationJsonAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/test/java/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kotlinx.serialization.json.autoconfigure;\n\nimport kotlinx.serialization.json.Json;\nimport kotlinx.serialization.json.JsonBuilder;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link KotlinxSerializationJsonProperties}.\n *\n * @author Andy Wilkinson\n */\nclass KotlinxSerializationJsonPropertiesTests {\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid defaultsAreAligned(JsonBuilderSettings settings) {\n\t\tJsonBuilder jsonBuilder = new JsonBuilder(Json.Default);\n\t\tKotlinxSerializationJsonProperties properties = new KotlinxSerializationJsonProperties();\n\t\tassertThat(settings.propertyGetter.get(properties)).isEqualTo(settings.jsonBuilderGetter.get(jsonBuilder));\n\t}\n\n\tprivate enum JsonBuilderSettings {\n\n\t\tALLOW_COMMENTS(KotlinxSerializationJsonProperties::isAllowComments, JsonBuilder::getAllowComments),\n\n\t\tALLOW_SPECIAL_FLOATING_POINT_VALUES(KotlinxSerializationJsonProperties::isAllowSpecialFloatingPointValues,\n\t\t\t\tJsonBuilder::getAllowSpecialFloatingPointValues),\n\n\t\tALLOW_STRUCTURED_MAP_KEYS(KotlinxSerializationJsonProperties::isAllowStructuredMapKeys,\n\t\t\t\tJsonBuilder::getAllowStructuredMapKeys),\n\n\t\tALLOW_TRAILING_COMMA(KotlinxSerializationJsonProperties::isAllowTrailingComma,\n\t\t\t\tJsonBuilder::getAllowTrailingComma),\n\n\t\tCLASS_DISCRIMINATOR(KotlinxSerializationJsonProperties::getClassDiscriminator,\n\t\t\t\tJsonBuilder::getClassDiscriminator),\n\n\t\tCLASS_DISCRIMINATOR_MODE(KotlinxSerializationJsonProperties::getClassDiscriminatorMode,\n\t\t\t\tJsonBuilder::getClassDiscriminatorMode),\n\n\t\tCOERCE_INPUT_VALUES(KotlinxSerializationJsonProperties::isCoerceInputValues, JsonBuilder::getCoerceInputValues),\n\n\t\tDECODE_ENUMS_CASE_INSENSITIVE(KotlinxSerializationJsonProperties::isDecodeEnumsCaseInsensitive,\n\t\t\t\tJsonBuilder::getDecodeEnumsCaseInsensitive),\n\n\t\tENCODE_DEFAULTS(KotlinxSerializationJsonProperties::isEncodeDefaults, JsonBuilder::getEncodeDefaults),\n\n\t\tEXPLICIT_NULLS(KotlinxSerializationJsonProperties::isExplicitNulls, JsonBuilder::getExplicitNulls),\n\n\t\tIGNORE_UNKNOWN_KEYS(KotlinxSerializationJsonProperties::isIgnoreUnknownKeys, JsonBuilder::getIgnoreUnknownKeys),\n\n\t\tLENIENT(KotlinxSerializationJsonProperties::isLenient, JsonBuilder::isLenient),\n\n\t\tNAMING_STRATEGY(KotlinxSerializationJsonProperties::getNamingStrategy, JsonBuilder::getNamingStrategy),\n\n\t\tPRETTY_PRINT(KotlinxSerializationJsonProperties::isPrettyPrint, JsonBuilder::getPrettyPrint),\n\n\t\tUSE_ALTERNATIVE_NAMES(KotlinxSerializationJsonProperties::isUseAlternativeNames,\n\t\t\t\tJsonBuilder::getUseAlternativeNames);\n\n\t\tprivate final Accessor<KotlinxSerializationJsonProperties, ?> propertyGetter;\n\n\t\tprivate final Accessor<JsonBuilder, ?> jsonBuilderGetter;\n\n\t\tJsonBuilderSettings(Accessor<KotlinxSerializationJsonProperties, @Nullable Object> propertyGetter,\n\t\t\t\tAccessor<JsonBuilder, @Nullable Object> jsonBuilderGetter) {\n\t\t\tthis.propertyGetter = propertyGetter;\n\t\t\tthis.jsonBuilderGetter = jsonBuilderGetter;\n\t\t}\n\n\t\tprivate interface Accessor<S, @Nullable P extends @Nullable Object> {\n\n\t\t\t@Nullable P get(S source);\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-kotlinx-serialization-json/src/test/kotlin/org/springframework/boot/kotlinx/serialization/json/autoconfigure/KotlinxSerializationJsonAutoConfigurationTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.kotlinx.serialization.json.autoconfigure\n\nimport kotlinx.serialization.ExperimentalSerializationApi\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\nimport kotlinx.serialization.SerializationException\nimport kotlinx.serialization.json.Json\nimport kotlinx.serialization.json.JsonNames\nimport kotlinx.serialization.json.JsonNamingStrategy\nimport org.assertj.core.api.Assertions.assertThatExceptionOfType\nimport org.assertj.core.api.AssertionsForInterfaceTypes.assertThat\nimport org.junit.jupiter.api.Test\nimport org.springframework.boot.autoconfigure.AutoConfigurations\nimport org.springframework.boot.test.context.FilteredClassLoader\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.Configuration\n\n/**\n * Tests for [KotlinxSerializationJsonAutoConfiguration].\n *\n * @author Dmitry Sulman\n */\nclass KotlinxSerializationJsonAutoConfigurationTests {\n\tprivate val contextRunner = ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(KotlinxSerializationJsonAutoConfiguration::class.java))\n\n\t@Test\n\tfun shouldSupplyJsonBean() {\n\t\tthis.contextRunner.run { context ->\n\t\t\tassertThat(context).hasSingleBean(Json::class.java)\n\t\t}\n\t}\n\n\t@Test\n\tfun shouldNotSupplyJsonBean() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(FilteredClassLoader(Json::class.java))\n\t\t\t.run { context ->\n\t\t\t\tassertThat(context).doesNotHaveBean(Json::class.java)\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeToString() {\n\t\tthis.contextRunner.run { context ->\n\t\t\tval json = context.getBean(Json::class.java)\n\t\t\tassertThat(json.encodeToString(DataObject(\"hello\")))\n\t\t\t\t.isEqualTo(\"\"\"{\"stringField\":\"hello\"}\"\"\")\n\t\t}\n\t}\n\n\t@Test\n\tfun deserializeFromString() {\n\t\tthis.contextRunner.run { context ->\n\t\t\tval json = context.getBean(Json::class.java)\n\t\t\tassertThat(json.decodeFromString<DataObject>(\"\"\"{\"stringField\":\"hello\"}\"\"\"))\n\t\t\t\t.isEqualTo(DataObject(\"hello\"))\n\t\t}\n\t}\n\n\t@Test\n\tfun customJsonBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomKotlinSerializationConfig::class.java)\n\t\t\t.run { context ->\n\t\t\t\tassertThat(context).hasSingleBean(Json::class.java)\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObject(\"hello\")))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"string_field\":\"hello\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeSnakeCase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.naming-strategy=snake_case\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObject(\"hello\")))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"string_field\":\"hello\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeKebabCase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.naming-strategy=kebab_case\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObject(\"hello\")))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"string-field\":\"hello\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializePrettyPrint() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.pretty-print=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObject(\"hello\")))\n\t\t\t\t\t.isEqualTo(\n\t\t\t\t\t\t\"\"\"\n\t\t\t\t\t\t{\n\t\t\t\t\t\t    \"stringField\": \"hello\"\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\"\"\".trimIndent()\n\t\t\t\t\t)\n\t\t\t}\n\t}\n\n\t@Test\n\t@Suppress(\"JsonStandardCompliance\")\n\tfun deserializeLenient() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.lenient=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.decodeFromString<DataObject>(\"\"\"{\"stringField\":hello}\"\"\"))\n\t\t\t\t\t.isEqualTo(DataObject(\"hello\"))\n\t\t\t}\n\t}\n\n\t@Test\n\tfun deserializeIgnoreUnknownKeys() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.ignore-unknown-keys=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.decodeFromString<DataObject>(\"\"\"{\"stringField\":\"hello\", \"anotherField\":\"value\"}\"\"\"))\n\t\t\t\t\t.isEqualTo(DataObject(\"hello\"))\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeDefaults() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.encode-defaults=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObjectWithDefault(\"hello\")))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"stringField\":\"hello\",\"defaultField\":\"default\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeExplicitNullsFalse() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.explicit-nulls=false\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObjectWithDefault(null, \"hello\")))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"defaultField\":\"hello\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun deserializeCoerceInputValues() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.coerce-input-values=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.decodeFromString<DataObjectWithDefault>(\"\"\"{\"stringField\":\"hello\", \"defaultField\":null}\"\"\"))\n\t\t\t\t\t.isEqualTo(DataObjectWithDefault(\"hello\", \"default\"))\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeStructuredMapKeys() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.allow-structured-map-keys=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tval map = mapOf(\n\t\t\t\t\tDataObject(\"key1\") to \"value1\",\n\t\t\t\t\tDataObject(\"key2\") to \"value2\",\n\t\t\t\t)\n\t\t\t\tassertThat(json.encodeToString(map))\n\t\t\t\t\t.isEqualTo(\"\"\"[{\"stringField\":\"key1\"},\"value1\",{\"stringField\":\"key2\"},\"value2\"]\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeSpecialFloatingPointValues() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.allow-special-floating-point-values=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.encodeToString(DataObjectDouble(Double.NaN)))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"value\":NaN}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeClassDiscriminator() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.class-discriminator=class\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tval value: BaseClass = ChildClass(\"value\")\n\t\t\t\tassertThat(json.encodeToString(value))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"class\":\"child\",\"stringField\":\"value\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun serializeClassDiscriminatorNone() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.class-discriminator-mode=none\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tval value: BaseClass = ChildClass(\"value\")\n\t\t\t\tassertThat(json.encodeToString(value))\n\t\t\t\t\t.isEqualTo(\"\"\"{\"stringField\":\"value\"}\"\"\")\n\t\t\t}\n\t}\n\n\t@Test\n\tfun deserializeEnumsCaseInsensitive() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.decode-enums-case-insensitive=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.decodeFromString<DataObjectEnumValues>(\"\"\"{\"values\":[\"value_A\", \"alternative\"]}\"\"\"))\n\t\t\t\t\t.isEqualTo(DataObjectEnumValues(listOf(EnumValue.VALUE_A, EnumValue.VALUE_B)))\n\t\t\t}\n\t}\n\n\t@Test\n\tfun deserializeAlternativeNames() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.use-alternative-names=false\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThatExceptionOfType(SerializationException::class.java).isThrownBy {\n\t\t\t\t\tjson.decodeFromString<DataObject>(\"\"\"{\"alternative\":\"hello\"}\"\"\")\n\t\t\t\t}.withMessageContaining(\"Encountered an unknown key\")\n\t\t\t}\n\t}\n\n\t@Test\n\t@Suppress(\"JsonStandardCompliance\")\n\tfun deserializeTrailingComma() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.allow-trailing-comma=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.decodeFromString<DataObject>(\"\"\"{\"stringField\":\"hello\",}\"\"\"))\n\t\t\t\t\t.isEqualTo(DataObject(\"hello\"))\n\t\t\t}\n\t}\n\n\t@Test\n\t@Suppress(\"JsonStandardCompliance\")\n\tfun deserializeComments() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.kotlinx.serialization.json.allow-comments=true\")\n\t\t\t.run { context ->\n\t\t\t\tval json = context.getBean(Json::class.java)\n\t\t\t\tassertThat(json.decodeFromString<DataObject>(\"\"\"{\"stringField\":\"hello\" /*comment*/}\"\"\"))\n\t\t\t\t\t.isEqualTo(DataObject(\"hello\"))\n\t\t\t}\n\t}\n\n\t@Serializable\n\t@OptIn(ExperimentalSerializationApi::class)\n\tprivate data class DataObject(@JsonNames(\"alternative\") private val stringField: String)\n\n\t@Serializable\n\tprivate data class DataObjectWithDefault(\n\t\tprivate val stringField: String?,\n\t\tprivate val defaultField: String = \"default\",\n\t)\n\n\t@Serializable\n\tprivate data class DataObjectDouble(private val value: Double)\n\n\t@OptIn(ExperimentalSerializationApi::class)\n\tenum class EnumValue { VALUE_A, @JsonNames(\"Alternative\") VALUE_B }\n\n\t@Serializable\n\tprivate data class DataObjectEnumValues(private val values: List<EnumValue>)\n\n\t@Serializable\n\tsealed class BaseClass {\n\t\tabstract val stringField: String\n\t}\n\n\t@Serializable\n\t@SerialName(\"child\")\n\tclass ChildClass(override val stringField: String) : BaseClass()\n\n\t@Configuration(proxyBeanMethods = false)\n\tclass CustomKotlinSerializationConfig {\n\n\t\t@Bean\n\t\t@OptIn(ExperimentalSerializationApi::class)\n\t\tfun customKotlinSerializationJson(): Json {\n\t\t\treturn Json { namingStrategy = JsonNamingStrategy.SnakeCase }\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot LDAP\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.ldap:spring-ldap-core\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(\"com.unboundid:unboundid-ldapsdk\")\n\toptional(\"org.testcontainers:testcontainers-ldap\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.apache.commons:commons-pool2\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/java/org/springframework/boot/ldap/docker/compose/LLdapDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link LLdapDockerComposeConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\nclass LLdapDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"lldap-compose.yaml\", image = TestImage.LLDAP)\n\tvoid runCreatesConnectionDetails(LdapConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"cn=admin,ou=people,dc=springframework,dc=org\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"somepassword\");\n\t\tassertThat(connectionDetails.getBase()).isEqualTo(\"dc=springframework,dc=org\");\n\t\tassertThat(connectionDetails.getUrls()).hasSize(1);\n\t\tassertThat(connectionDetails.getUrls()[0]).startsWith(\"ldap://\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/java/org/springframework/boot/ldap/docker/compose/OpenLdapDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OpenLdapDockerComposeConnectionDetailsFactory}.\n *\n * @author Philipp Kessler\n */\nclass OpenLdapDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"ldap-compose.yaml\", image = TestImage.OPEN_LDAP)\n\tvoid runCreatesConnectionDetails(LdapConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"cn=admin,dc=ldap,dc=example,dc=org\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"somepassword\");\n\t\tassertThat(connectionDetails.getBase()).isEqualTo(\"dc=ldap,dc=example,dc=org\");\n\t\tassertThat(connectionDetails.getUrls()).hasSize(1);\n\t\tassertThat(connectionDetails.getUrls()[0]).startsWith(\"ldaps://\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/java/org/springframework/boot/ldap/testcontainers/LLdapContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.testcontainers;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.ldap.LLdapContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.ldap.core.AttributesMapper;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.query.LdapQueryBuilder;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LLdapContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass LLdapContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final LLdapContainer lldap = TestImage.container(LLdapContainer.class);\n\n\t@Autowired\n\tprivate LdapTemplate ldapTemplate;\n\n\t@Test\n\tvoid connectionCanBeMadeToLdapContainer() {\n\t\tList<String> cn = this.ldapTemplate.search(LdapQueryBuilder.query().where(\"objectClass\").is(\"inetOrgPerson\"),\n\t\t\t\t(AttributesMapper<String>) (attributes) -> attributes.get(\"cn\").get().toString());\n\t\tassertThat(cn).singleElement().isEqualTo(\"Administrator\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ LdapAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/java/org/springframework/boot/ldap/testcontainers/OpenLdapContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.testcontainers;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.OpenLdapContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.ldap.core.AttributesMapper;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.query.LdapQueryBuilder;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OpenLdapContainerConnectionDetailsFactory}.\n *\n * @author Philipp Kessler\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass OpenLdapContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final OpenLdapContainer openLdap = TestImage.container(OpenLdapContainer.class).withEnv(\"LDAP_TLS\", \"false\");\n\n\t@Autowired\n\tprivate LdapTemplate ldapTemplate;\n\n\t@Test\n\tvoid connectionCanBeMadeToLdapContainer() {\n\t\tList<String> cn = this.ldapTemplate.search(LdapQueryBuilder.query().where(\"objectclass\").is(\"dcObject\"),\n\t\t\t\t(AttributesMapper<String>) (attributes) -> attributes.get(\"dc\").get().toString());\n\t\tassertThat(cn).singleElement().isEqualTo(\"example\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ LdapAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/resources/org/springframework/boot/ldap/docker/compose/ldap-compose.yaml",
    "content": "services:\n  ldap:\n    image: '{imageName}'\n    environment:\n      - 'LDAP_DOMAIN=ldap.example.org'\n      - 'LDAP_ADMIN_PASSWORD=somepassword'\n      - 'LDAP_TLS=true'\n    hostname: ldap\n    ports:\n      - \"389\"\n      - \"636\"\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/resources/org/springframework/boot/ldap/docker/compose/lldap-compose.yaml",
    "content": "services:\n  ldap:\n    image: '{imageName}'\n    environment:\n      - 'LLDAP_LDAP_BASE_DN=dc=springframework,dc=org'\n      - 'LLDAP_LDAP_USER_PASS=somepassword'\n    ports:\n      - \"3890\"\n"
  },
  {
    "path": "module/spring-boot-ldap/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/LdapAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Locale;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.ldap.autoconfigure.LdapProperties.Template;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.ldap.convert.ConverterUtils;\nimport org.springframework.ldap.core.ContextSource;\nimport org.springframework.ldap.core.LdapOperations;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.core.support.DirContextAuthenticationStrategy;\nimport org.springframework.ldap.core.support.LdapContextSource;\nimport org.springframework.ldap.odm.core.ObjectDirectoryMapper;\nimport org.springframework.ldap.odm.core.impl.DefaultObjectDirectoryMapper;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for LDAP.\n *\n * @author Eddú Meléndez\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(ContextSource.class)\n@EnableConfigurationProperties(LdapProperties.class)\npublic final class LdapAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(LdapConnectionDetails.class)\n\tPropertiesLdapConnectionDetails propertiesLdapConnectionDetails(LdapProperties properties,\n\t\t\tEnvironment environment) {\n\t\treturn new PropertiesLdapConnectionDetails(properties, environment);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tLdapContextSource ldapContextSource(LdapConnectionDetails connectionDetails, LdapProperties properties,\n\t\t\tObjectProvider<DirContextAuthenticationStrategy> dirContextAuthenticationStrategy) {\n\t\tLdapContextSource source = new LdapContextSource();\n\t\tdirContextAuthenticationStrategy.ifUnique(source::setAuthenticationStrategy);\n\t\tPropertyMapper propertyMapper = PropertyMapper.get();\n\t\tpropertyMapper.from(connectionDetails.getUsername()).to(source::setUserDn);\n\t\tpropertyMapper.from(connectionDetails.getPassword()).to(source::setPassword);\n\t\tpropertyMapper.from(properties.getAnonymousReadOnly()).to(source::setAnonymousReadOnly);\n\t\tpropertyMapper.from(properties.getReferral())\n\t\t\t.as(((referral) -> referral.name().toLowerCase(Locale.ROOT)))\n\t\t\t.to(source::setReferral);\n\t\tpropertyMapper.from(connectionDetails.getBase()).to(source::setBase);\n\t\tpropertyMapper.from(connectionDetails.getUrls()).to(source::setUrls);\n\t\tpropertyMapper.from(properties.getBaseEnvironment())\n\t\t\t.to((baseEnvironment) -> source.setBaseEnvironmentProperties(Collections.unmodifiableMap(baseEnvironment)));\n\t\treturn source;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tObjectDirectoryMapper objectDirectoryMapper() {\n\t\tApplicationConversionService conversionService = new ApplicationConversionService();\n\t\tConverterUtils.addDefaultConverters(conversionService);\n\t\tDefaultObjectDirectoryMapper objectDirectoryMapper = new DefaultObjectDirectoryMapper();\n\t\tobjectDirectoryMapper.setConversionService(conversionService);\n\t\treturn objectDirectoryMapper;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(LdapOperations.class)\n\tLdapTemplate ldapTemplate(LdapProperties properties, ContextSource contextSource,\n\t\t\tObjectDirectoryMapper objectDirectoryMapper) {\n\t\tTemplate template = properties.getTemplate();\n\t\tPropertyMapper propertyMapper = PropertyMapper.get();\n\t\tLdapTemplate ldapTemplate = new LdapTemplate(contextSource);\n\t\tldapTemplate.setObjectDirectoryMapper(objectDirectoryMapper);\n\t\tpropertyMapper.from(template.isIgnorePartialResultException())\n\t\t\t.to(ldapTemplate::setIgnorePartialResultException);\n\t\tpropertyMapper.from(template.isIgnoreNameNotFoundException()).to(ldapTemplate::setIgnoreNameNotFoundException);\n\t\tpropertyMapper.from(template.isIgnoreSizeLimitExceededException())\n\t\t\t.to(ldapTemplate::setIgnoreSizeLimitExceededException);\n\t\treturn ldapTemplate;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/LdapConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to an LDAP service.\n *\n * @author Philipp Kessler\n * @since 4.0.0\n */\npublic interface LdapConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * LDAP URLs of the server.\n\t * @return the LDAP URLs to use\n\t */\n\tString[] getUrls();\n\n\t/**\n\t * Base suffix from which all operations should originate.\n\t * @return base suffix\n\t */\n\tdefault @Nullable String getBase() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Login username of the server.\n\t * @return login username\n\t */\n\tdefault @Nullable String getUsername() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Login password of the server.\n\t * @return login password\n\t */\n\tdefault @Nullable String getPassword() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/LdapProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.env.Environment;\nimport org.springframework.ldap.ReferralException;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Configuration properties for LDAP.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.ldap\")\npublic class LdapProperties {\n\n\tprivate static final int DEFAULT_PORT = 389;\n\n\t/**\n\t * LDAP URLs of the server.\n\t */\n\tprivate String @Nullable [] urls;\n\n\t/**\n\t * Base suffix from which all operations should originate.\n\t */\n\tprivate @Nullable String base;\n\n\t/**\n\t * Login username of the server.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the server.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Whether read-only operations should use an anonymous environment. Disabled by\n\t * default unless a username is set.\n\t */\n\tprivate @Nullable Boolean anonymousReadOnly;\n\n\t/**\n\t * Specify how referrals encountered by the service provider are to be processed. If\n\t * not specified, the default is determined by the provider.\n\t */\n\tprivate @Nullable Referral referral;\n\n\t/**\n\t * LDAP specification settings.\n\t */\n\tprivate final Map<String, String> baseEnvironment = new HashMap<>();\n\n\tprivate final Template template = new Template();\n\n\tpublic String @Nullable [] getUrls() {\n\t\treturn this.urls;\n\t}\n\n\tpublic void setUrls(String @Nullable [] urls) {\n\t\tthis.urls = urls;\n\t}\n\n\tpublic @Nullable String getBase() {\n\t\treturn this.base;\n\t}\n\n\tpublic void setBase(@Nullable String base) {\n\t\tthis.base = base;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable Boolean getAnonymousReadOnly() {\n\t\treturn this.anonymousReadOnly;\n\t}\n\n\tpublic void setAnonymousReadOnly(@Nullable Boolean anonymousReadOnly) {\n\t\tthis.anonymousReadOnly = anonymousReadOnly;\n\t}\n\n\tpublic @Nullable Referral getReferral() {\n\t\treturn this.referral;\n\t}\n\n\tpublic void setReferral(@Nullable Referral referral) {\n\t\tthis.referral = referral;\n\t}\n\n\tpublic Map<String, String> getBaseEnvironment() {\n\t\treturn this.baseEnvironment;\n\t}\n\n\tpublic Template getTemplate() {\n\t\treturn this.template;\n\t}\n\n\tpublic String[] determineUrls(Environment environment) {\n\t\tif (ObjectUtils.isEmpty(this.urls)) {\n\t\t\treturn new String[] { \"ldap://localhost:\" + determinePort(environment) };\n\t\t}\n\t\treturn this.urls;\n\t}\n\n\tprivate int determinePort(Environment environment) {\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tString localPort = environment.getProperty(\"local.ldap.port\");\n\t\tif (localPort != null) {\n\t\t\treturn Integer.parseInt(localPort);\n\t\t}\n\t\treturn DEFAULT_PORT;\n\t}\n\n\t/**\n\t * {@link LdapTemplate settings}.\n\t */\n\tpublic static class Template {\n\n\t\t/**\n\t\t * Whether PartialResultException should be ignored in searches through the\n\t\t * LdapTemplate.\n\t\t */\n\t\tprivate boolean ignorePartialResultException;\n\n\t\t/**\n\t\t * Whether NameNotFoundException should be ignored in searches through the\n\t\t * LdapTemplate.\n\t\t */\n\t\tprivate boolean ignoreNameNotFoundException;\n\n\t\t/**\n\t\t * Whether SizeLimitExceededException should be ignored in searches through the\n\t\t * LdapTemplate.\n\t\t */\n\t\tprivate boolean ignoreSizeLimitExceededException = true;\n\n\t\tpublic boolean isIgnorePartialResultException() {\n\t\t\treturn this.ignorePartialResultException;\n\t\t}\n\n\t\tpublic void setIgnorePartialResultException(boolean ignorePartialResultException) {\n\t\t\tthis.ignorePartialResultException = ignorePartialResultException;\n\t\t}\n\n\t\tpublic boolean isIgnoreNameNotFoundException() {\n\t\t\treturn this.ignoreNameNotFoundException;\n\t\t}\n\n\t\tpublic void setIgnoreNameNotFoundException(boolean ignoreNameNotFoundException) {\n\t\t\tthis.ignoreNameNotFoundException = ignoreNameNotFoundException;\n\t\t}\n\n\t\tpublic boolean isIgnoreSizeLimitExceededException() {\n\t\t\treturn this.ignoreSizeLimitExceededException;\n\t\t}\n\n\t\tpublic void setIgnoreSizeLimitExceededException(Boolean ignoreSizeLimitExceededException) {\n\t\t\tthis.ignoreSizeLimitExceededException = ignoreSizeLimitExceededException;\n\t\t}\n\n\t}\n\n\t/**\n\t * Define the methods to handle referrals.\n\t */\n\tpublic enum Referral {\n\n\t\t/**\n\t\t * Follow referrals automatically.\n\t\t */\n\t\tFOLLOW,\n\n\t\t/**\n\t\t * Ignore referrals.\n\t\t */\n\t\tIGNORE,\n\n\t\t/**\n\t\t * Throw {@link ReferralException} when a referral is encountered.\n\t\t */\n\t\tTHROW\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/PropertiesLdapConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\n\n/**\n * Adapts {@link LdapProperties} to {@link LdapConnectionDetails}.\n *\n * @author Philipp Kessler\n */\nclass PropertiesLdapConnectionDetails implements LdapConnectionDetails {\n\n\tprivate final LdapProperties properties;\n\n\tprivate final Environment environment;\n\n\tPropertiesLdapConnectionDetails(LdapProperties properties, Environment environment) {\n\t\tthis.properties = properties;\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic String[] getUrls() {\n\t\treturn this.properties.determineUrls(this.environment);\n\t}\n\n\t@Override\n\tpublic @Nullable String getBase() {\n\t\treturn this.properties.getBase();\n\t}\n\n\t@Override\n\tpublic @Nullable String getUsername() {\n\t\treturn this.properties.getUsername();\n\t}\n\n\t@Override\n\tpublic @Nullable String getPassword() {\n\t\treturn this.properties.getPassword();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure.embedded;\n\nimport java.io.InputStream;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLServerSocketFactory;\nimport javax.net.ssl.SSLSocketFactory;\n\nimport com.unboundid.ldap.listener.InMemoryDirectoryServer;\nimport com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;\nimport com.unboundid.ldap.listener.InMemoryListenerConfig;\nimport com.unboundid.ldap.sdk.LDAPException;\nimport com.unboundid.ldap.sdk.schema.Schema;\nimport com.unboundid.ldif.LDIFReader;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;\nimport org.springframework.boot.ldap.autoconfigure.LdapProperties;\nimport org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration.EmbeddedLdapAutoConfigurationRuntimeHints;\nimport org.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapProperties.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.DependsOn;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.ldap.core.ContextSource;\nimport org.springframework.ldap.core.support.LdapContextSource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Embedded LDAP.\n *\n * @author Eddú Meléndez\n * @author Mathieu Ouellet\n * @author Raja Kolli\n * @since 4.0.0\n */\n@AutoConfiguration(before = LdapAutoConfiguration.class)\n@EnableConfigurationProperties({ LdapProperties.class, EmbeddedLdapProperties.class })\n@ConditionalOnClass(InMemoryDirectoryServer.class)\n@Conditional(EmbeddedLdapAutoConfiguration.EmbeddedLdapCondition.class)\n@ImportRuntimeHints(EmbeddedLdapAutoConfigurationRuntimeHints.class)\npublic final class EmbeddedLdapAutoConfiguration implements DisposableBean {\n\n\tprivate static final String PROPERTY_SOURCE_NAME = \"ldap.ports\";\n\n\tprivate final EmbeddedLdapProperties embeddedProperties;\n\n\tprivate @Nullable InMemoryDirectoryServer server;\n\n\tEmbeddedLdapAutoConfiguration(EmbeddedLdapProperties embeddedProperties) {\n\t\tthis.embeddedProperties = embeddedProperties;\n\t}\n\n\t@Bean\n\tInMemoryDirectoryServer directoryServer(ApplicationContext applicationContext,\n\t\t\tObjectProvider<SslBundles> sslBundles) throws LDAPException {\n\t\tString[] baseDn = StringUtils.toStringArray(this.embeddedProperties.getBaseDn());\n\t\tInMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(baseDn);\n\t\tString username = this.embeddedProperties.getCredential().getUsername();\n\t\tString password = this.embeddedProperties.getCredential().getPassword();\n\t\tif (StringUtils.hasText(username) && StringUtils.hasText(password)) {\n\t\t\tconfig.addAdditionalBindCredentials(username, password);\n\t\t}\n\t\tconfig.setListenerConfigs(createListenerConfig(sslBundles));\n\t\tsetSchema(config);\n\t\tthis.server = new InMemoryDirectoryServer(config);\n\t\timportLdif(this.server, applicationContext);\n\t\tthis.server.startListening();\n\t\tsetPortProperty(applicationContext, this.server.getListenPort());\n\t\treturn this.server;\n\t}\n\n\tprivate InMemoryListenerConfig createListenerConfig(ObjectProvider<SslBundles> sslBundles) throws LDAPException {\n\t\tSslBundle sslBundle = getSslBundle(sslBundles.getIfAvailable());\n\t\tif (sslBundle != null) {\n\t\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\t\tSSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory();\n\t\t\tSSLSocketFactory clientSocketFactory = sslContext.getSocketFactory();\n\t\t\treturn InMemoryListenerConfig.createLDAPSConfig(\"LDAPS\", null, this.embeddedProperties.getPort(),\n\t\t\t\t\tserverSocketFactory, clientSocketFactory);\n\t\t}\n\t\treturn InMemoryListenerConfig.createLDAPConfig(\"LDAP\", this.embeddedProperties.getPort());\n\t}\n\n\tprivate @Nullable SslBundle getSslBundle(@Nullable SslBundles sslBundles) {\n\t\tSsl ssl = this.embeddedProperties.getSsl();\n\t\tif (ssl.isEnabled() && StringUtils.hasLength(ssl.getBundle())) {\n\t\t\tAssert.notNull(sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\treturn sslBundles.getBundle(ssl.getBundle());\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void setSchema(InMemoryDirectoryServerConfig config) {\n\t\tif (!this.embeddedProperties.getValidation().isEnabled()) {\n\t\t\tconfig.setSchema(null);\n\t\t\treturn;\n\t\t}\n\t\tResource schema = this.embeddedProperties.getValidation().getSchema();\n\t\tif (schema != null) {\n\t\t\tsetSchema(config, schema);\n\t\t}\n\t}\n\n\tprivate void setSchema(InMemoryDirectoryServerConfig config, Resource resource) {\n\t\ttry {\n\t\t\tSchema defaultSchema = Schema.getDefaultStandardSchema();\n\t\t\tSchema schema = Schema.getSchema(resource.getInputStream());\n\t\t\tif (schema == null) {\n\t\t\t\tconfig.setSchema(defaultSchema);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconfig.setSchema(Schema.mergeSchemas(defaultSchema, schema));\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load schema \" + resource.getDescription(), ex);\n\t\t}\n\t}\n\n\tprivate void importLdif(InMemoryDirectoryServer server, ApplicationContext applicationContext) {\n\t\tString location = this.embeddedProperties.getLdif();\n\t\tif (StringUtils.hasText(location)) {\n\t\t\ttry {\n\t\t\t\tResource resource = applicationContext.getResource(location);\n\t\t\t\tif (resource.exists()) {\n\t\t\t\t\ttry (InputStream inputStream = resource.getInputStream()) {\n\t\t\t\t\t\tserver.importFromLDIF(true, new LDIFReader(inputStream));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to load LDIF \" + location, ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void setPortProperty(ApplicationContext context, int port) {\n\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\tMutablePropertySources sources = configurableContext.getEnvironment().getPropertySources();\n\t\t\tgetLdapPorts(sources).put(\"local.ldap.port\", port);\n\t\t}\n\t\tif (context.getParent() != null) {\n\t\t\tsetPortProperty(context.getParent(), port);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, Object> getLdapPorts(MutablePropertySources sources) {\n\t\tPropertySource<?> propertySource = sources.get(PROPERTY_SOURCE_NAME);\n\t\tif (propertySource == null) {\n\t\t\tpropertySource = new MapPropertySource(PROPERTY_SOURCE_NAME, new HashMap<>());\n\t\t\tsources.addFirst(propertySource);\n\t\t}\n\t\treturn (Map<String, Object>) propertySource.getSource();\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tif (this.server != null) {\n\t\t\tthis.server.shutDown(true);\n\t\t}\n\t}\n\n\t/**\n\t * {@link SpringBootCondition} to determine when to apply embedded LDAP\n\t * auto-configuration.\n\t */\n\tstatic class EmbeddedLdapCondition extends SpringBootCondition {\n\n\t\tprivate static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tBuilder message = ConditionMessage.forCondition(\"Embedded LDAP\");\n\t\t\tEnvironment environment = context.getEnvironment();\n\t\t\tif (environment != null && !Binder.get(environment)\n\t\t\t\t.bind(\"spring.ldap.embedded.base-dn\", STRING_LIST)\n\t\t\t\t.orElseGet(Collections::emptyList)\n\t\t\t\t.isEmpty()) {\n\t\t\t\treturn ConditionOutcome.match(message.because(\"Found base-dn property\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(message.because(\"No base-dn property found\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ContextSource.class)\n\tstatic class EmbeddedLdapContextConfiguration {\n\n\t\t@Bean\n\t\t@DependsOn(\"directoryServer\")\n\t\t@ConditionalOnMissingBean\n\t\tLdapContextSource ldapContextSource(Environment environment, LdapProperties properties,\n\t\t\t\tEmbeddedLdapProperties embeddedProperties) {\n\t\t\tLdapContextSource source = new LdapContextSource();\n\t\t\tsource.setBase(properties.getBase());\n\t\t\tString username = embeddedProperties.getCredential().getUsername();\n\t\t\tString password = embeddedProperties.getCredential().getPassword();\n\t\t\tif (StringUtils.hasText(username) && StringUtils.hasText(password)) {\n\t\t\t\tsource.setUserDn(username);\n\t\t\t\tsource.setPassword(password);\n\t\t\t}\n\t\t\tsource.setUrls(properties.determineUrls(environment));\n\t\t\treturn source;\n\t\t}\n\n\t}\n\n\tstatic class EmbeddedLdapAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources()\n\t\t\t\t.registerPatternIfPresent(classLoader, \"schema.ldif\", (hint) -> hint.includes(\"schema.ldif\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure.embedded;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.Delimiter;\nimport org.springframework.core.io.Resource;\n\n/**\n * Configuration properties for Embedded LDAP.\n *\n * @author Eddú Meléndez\n * @author Mathieu Ouellet\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.ldap.embedded\")\npublic class EmbeddedLdapProperties {\n\n\t/**\n\t * Embedded LDAP port.\n\t */\n\tprivate int port;\n\n\t/**\n\t * Embedded LDAP credentials.\n\t */\n\tprivate Credential credential = new Credential();\n\n\t/**\n\t * List of base DNs.\n\t */\n\t@Delimiter(Delimiter.NONE)\n\tprivate List<String> baseDn = new ArrayList<>();\n\n\t/**\n\t * Schema (LDIF) script resource reference.\n\t */\n\tprivate String ldif = \"classpath:schema.ldif\";\n\n\t/**\n\t * Schema validation.\n\t */\n\tprivate final Validation validation = new Validation();\n\n\t/**\n\t * SSL configuration.\n\t */\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic Credential getCredential() {\n\t\treturn this.credential;\n\t}\n\n\tpublic void setCredential(Credential credential) {\n\t\tthis.credential = credential;\n\t}\n\n\tpublic List<String> getBaseDn() {\n\t\treturn this.baseDn;\n\t}\n\n\tpublic void setBaseDn(List<String> baseDn) {\n\t\tthis.baseDn = baseDn;\n\t}\n\n\tpublic String getLdif() {\n\t\treturn this.ldif;\n\t}\n\n\tpublic void setLdif(String ldif) {\n\t\tthis.ldif = ldif;\n\t}\n\n\tpublic Validation getValidation() {\n\t\treturn this.validation;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic static class Credential {\n\n\t\t/**\n\t\t * Embedded LDAP username.\n\t\t */\n\t\tprivate @Nullable String username;\n\n\t\t/**\n\t\t * Embedded LDAP password.\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support. Enabled automatically if \"bundle\" is provided\n\t\t * unless specified otherwise.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn (this.enabled != null) ? this.enabled : this.bundle != null;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\tpublic static class Validation {\n\n\t\t/**\n\t\t * Whether to enable LDAP schema validation.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\t/**\n\t\t * Path to the custom schema.\n\t\t */\n\t\tprivate @Nullable Resource schema;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable Resource getSchema() {\n\t\t\treturn this.schema;\n\t\t}\n\n\t\tpublic void setSchema(@Nullable Resource schema) {\n\t\t\tthis.schema = schema;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/embedded/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for embedded LDAP.\n */\n@NullMarked\npackage org.springframework.boot.ldap.autoconfigure.embedded;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/health/LdapHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure.health;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;\nimport org.springframework.boot.ldap.health.LdapHealthIndicator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.ldap.core.LdapOperations;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link LdapHealthIndicator}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = LdapAutoConfiguration.class)\n@ConditionalOnClass({ LdapOperations.class, LdapHealthIndicator.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(LdapOperations.class)\n@ConditionalOnEnabledHealthIndicator(\"ldap\")\npublic final class LdapHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<LdapHealthIndicator, LdapOperations> {\n\n\tLdapHealthContributorAutoConfiguration() {\n\t\tsuper(LdapHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"ldapHealthIndicator\", \"ldapHealthContributor\" })\n\tHealthContributor ldapHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, LdapOperations.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for LDAP health.\n */\n@NullMarked\npackage org.springframework.boot.ldap.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for LDAP.\n */\n@NullMarked\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/docker/compose/LLdapDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link LdapConnectionDetails}\n * for an {@code ldap} service.\n *\n * @author Eddú Meléndez\n */\nclass LLdapDockerComposeConnectionDetailsFactory extends DockerComposeConnectionDetailsFactory<LdapConnectionDetails> {\n\n\tLLdapDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"lldap/lldap\");\n\t}\n\n\t@Override\n\tprotected LdapConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new LLdapDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link LdapConnectionDetails} backed by an {@code lldap} {@link RunningService}.\n\t */\n\tstatic class LLdapDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements LdapConnectionDetails {\n\n\t\tprivate final String[] urls;\n\n\t\tprivate final String base;\n\n\t\tprivate final String username;\n\n\t\tprivate final String password;\n\n\t\tLLdapDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tMap<String, @Nullable String> env = service.env();\n\t\t\tboolean usesTls = Boolean.parseBoolean(env.getOrDefault(\"LLDAP_LDAPS_OPTIONS__ENABLED\", \"false\"));\n\t\t\tString ldapPort = usesTls ? getFromEnv(env, \"LLDAP_LDAPS_OPTIONS__PORT\", \"6360\")\n\t\t\t\t\t: getFromEnv(env, \"LLDAP_LDAP_PORT\", \"3890\");\n\t\t\tthis.urls = new String[] { \"%s://%s:%d\".formatted(usesTls ? \"ldaps\" : \"ldap\", service.host(),\n\t\t\t\t\tservice.ports().get(Integer.parseInt(ldapPort))) };\n\t\t\tthis.base = getFromEnv(env, \"LLDAP_LDAP_BASE_DN\", \"dc=example,dc=com\");\n\t\t\tthis.password = getFromEnv(env, \"LLDAP_LDAP_USER_PASS\", \"password\");\n\t\t\tthis.username = \"cn=admin,ou=people,%s\".formatted(this.base);\n\t\t}\n\n\t\tprivate static String getFromEnv(Map<String, @Nullable String> env, String key, String defaultValue) {\n\t\t\tString result = env.get(key);\n\t\t\treturn (result != null) ? result : defaultValue;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getUrls() {\n\t\t\treturn this.urls;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBase() {\n\t\t\treturn this.base;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/docker/compose/OpenLdapDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.docker.compose;\n\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link LdapConnectionDetails}\n * for an {@code ldap} service.\n *\n * @author Philipp Kessler\n */\nclass OpenLdapDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<LdapConnectionDetails> {\n\n\tprotected OpenLdapDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"osixia/openldap\");\n\t}\n\n\t@Override\n\tprotected LdapConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new OpenLdapDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link LdapConnectionDetails} backed by an {@code openldap} {@link RunningService}.\n\t */\n\tstatic class OpenLdapDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements LdapConnectionDetails {\n\n\t\tprivate final String[] urls;\n\n\t\tprivate final String base;\n\n\t\tprivate final String username;\n\n\t\tprivate final String password;\n\n\t\tOpenLdapDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tMap<String, @Nullable String> env = service.env();\n\t\t\tboolean usesTls = Boolean.parseBoolean(env.getOrDefault(\"LDAP_TLS\", \"true\"));\n\t\t\tString ldapPort = usesTls ? getFromEnv(env, \"LDAPS_PORT\", \"636\") : getFromEnv(env, \"LDAP_PORT\", \"389\");\n\t\t\tthis.urls = new String[] { \"%s://%s:%d\".formatted(usesTls ? \"ldaps\" : \"ldap\", service.host(),\n\t\t\t\t\tservice.ports().get(Integer.parseInt(ldapPort))) };\n\t\t\tString baseDn = env.get(\"LDAP_BASE_DN\");\n\t\t\tif (baseDn != null) {\n\t\t\t\tthis.base = baseDn;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.base = Arrays.stream(getFromEnv(env, \"LDAP_DOMAIN\", \"example.org\").split(\"\\\\.\"))\n\t\t\t\t\t.map(\"dc=%s\"::formatted)\n\t\t\t\t\t.collect(Collectors.joining(\",\"));\n\t\t\t}\n\t\t\tthis.password = getFromEnv(env, \"LDAP_ADMIN_PASSWORD\", \"admin\");\n\t\t\tthis.username = \"cn=admin,%s\".formatted(this.base);\n\t\t}\n\n\t\tprivate static String getFromEnv(Map<String, @Nullable String> env, String key, String defaultValue) {\n\t\t\tString result = env.get(key);\n\t\t\treturn (result != null) ? result : defaultValue;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getUrls() {\n\t\t\treturn this.urls;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBase() {\n\t\t\treturn this.base;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose LDAP service connections.\n */\n@NullMarked\npackage org.springframework.boot.ldap.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/health/LdapHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.health;\n\nimport javax.naming.NamingException;\nimport javax.naming.directory.DirContext;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.ldap.core.ContextExecutor;\nimport org.springframework.ldap.core.LdapOperations;\nimport org.springframework.util.Assert;\n\n/**\n * {@link HealthIndicator} for configured LDAP server(s).\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class LdapHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate static final ContextExecutor<@Nullable String> versionContextExecutor = new VersionContextExecutor();\n\n\tprivate final LdapOperations ldapOperations;\n\n\tpublic LdapHealthIndicator(LdapOperations ldapOperations) {\n\t\tsuper(\"LDAP health check failed\");\n\t\tAssert.notNull(ldapOperations, \"'ldapOperations' must not be null\");\n\t\tthis.ldapOperations = ldapOperations;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tString version = this.ldapOperations.executeReadOnly(versionContextExecutor);\n\t\tif (version != null) {\n\t\t\tbuilder.up().withDetail(\"version\", version);\n\t\t}\n\t}\n\n\tprivate static final class VersionContextExecutor implements ContextExecutor<@Nullable String> {\n\n\t\t@Override\n\t\tpublic @Nullable String executeWithContext(DirContext ctx) throws NamingException {\n\t\t\tObject version = ctx.getEnvironment().get(\"java.naming.ldap.version\");\n\t\t\tif (version != null) {\n\t\t\t\treturn (String) version;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for LDAP.\n */\n@NullMarked\npackage org.springframework.boot.ldap.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/testcontainers/LLdapContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.testcontainers;\n\nimport org.testcontainers.ldap.LLdapContainer;\n\nimport org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link LdapConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link LLdapContainer}.\n *\n * @author Eddú Meléndez\n */\nclass LLdapContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<LLdapContainer, LdapConnectionDetails> {\n\n\t@Override\n\tprotected LdapConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<LLdapContainer> source) {\n\t\treturn new LLdapContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class LLdapContainerConnectionDetails extends ContainerConnectionDetails<LLdapContainer>\n\t\t\timplements LdapConnectionDetails {\n\n\t\tprivate LLdapContainerConnectionDetails(ContainerConnectionSource<LLdapContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getUrls() {\n\t\t\treturn new String[] { getContainer().getLdapUrl() };\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBase() {\n\t\t\treturn getContainer().getBaseDn();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/testcontainers/OpenLdapContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.testcontainers;\n\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.ldap.autoconfigure.LdapConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link LdapConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using\n * the {@code \"osixia/openldap\"} image.\n *\n * @author Philipp Kessler\n */\nclass OpenLdapContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, LdapConnectionDetails> {\n\n\tOpenLdapContainerConnectionDetailsFactory() {\n\t\tsuper(\"osixia/openldap\");\n\t}\n\n\t@Override\n\tprotected LdapConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\treturn new OpenLdapContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OpenLdapContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>\n\t\t\timplements LdapConnectionDetails {\n\n\t\tprivate OpenLdapContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getUrls() {\n\t\t\tMap<String, String> env = getContainer().getEnvMap();\n\t\t\tboolean usesTls = Boolean.parseBoolean(env.getOrDefault(\"LDAP_TLS\", \"true\"));\n\t\t\tString ldapPort = usesTls ? env.getOrDefault(\"LDAPS_PORT\", \"636\") : env.getOrDefault(\"LDAP_PORT\", \"389\");\n\t\t\treturn new String[] { \"%s://%s:%d\".formatted(usesTls ? \"ldaps\" : \"ldap\", getContainer().getHost(),\n\t\t\t\t\tgetContainer().getMappedPort(Integer.parseInt(ldapPort))) };\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBase() {\n\t\t\tMap<String, String> env = getContainer().getEnvMap();\n\t\t\tif (env.containsKey(\"LDAP_BASE_DN\")) {\n\t\t\t\treturn env.get(\"LDAP_BASE_DN\");\n\t\t\t}\n\t\t\treturn Arrays.stream(env.getOrDefault(\"LDAP_DOMAIN\", \"example.org\").split(\"\\\\.\"))\n\t\t\t\t.map(\"dc=%s\"::formatted)\n\t\t\t\t.collect(Collectors.joining(\",\"));\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn \"cn=admin,%s\".formatted(getBase());\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getEnvMap().getOrDefault(\"LDAP_ADMIN_PASSWORD\", \"admin\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/java/org/springframework/boot/ldap/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Ldap service connections.\n */\n@NullMarked\npackage org.springframework.boot.ldap.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"management.health.ldap.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable LDAP health check.\",\n      \"defaultValue\": true\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-ldap/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration\norg.springframework.boot.ldap.autoconfigure.embedded.EmbeddedLdapAutoConfiguration\norg.springframework.boot.ldap.autoconfigure.health.LdapHealthContributorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-ldap/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.ldap.docker.compose.LLdapDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.ldap.docker.compose.OpenLdapDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.ldap.testcontainers.LLdapContainerConnectionDetailsFactory,\\\norg.springframework.boot.ldap.testcontainers.OpenLdapContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/LdapAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport javax.naming.Name;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.core.support.DirContextAuthenticationStrategy;\nimport org.springframework.ldap.core.support.LdapContextSource;\nimport org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy;\nimport org.springframework.ldap.odm.core.ObjectDirectoryMapper;\nimport org.springframework.ldap.pool2.factory.PoolConfig;\nimport org.springframework.ldap.pool2.factory.PooledContextSource;\nimport org.springframework.ldap.support.LdapUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LdapAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Vedran Pavic\n */\nclass LdapAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LdapAutoConfiguration.class));\n\n\t@Test\n\tvoid contextSourceWithDefaultUrl() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource.getUrls()).containsExactly(\"ldap://localhost:389\");\n\t\t\tassertThat(contextSource.isAnonymousReadOnly()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithSingleUrl() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.urls:ldap://localhost:123\").run((context) -> {\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource.getUrls()).containsExactly(\"ldap://localhost:123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithSeveralUrls() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.urls:ldap://localhost:123,ldap://mycompany:123\")\n\t\t\t.run((context) -> {\n\t\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\t\tLdapProperties ldapProperties = context.getBean(LdapProperties.class);\n\t\t\t\tassertThat(contextSource.getUrls()).containsExactly(\"ldap://localhost:123\", \"ldap://mycompany:123\");\n\t\t\t\tassertThat(ldapProperties.getUrls()).hasSize(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithUserDoesNotEnableAnonymousReadOnly() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.username:root\").run((context) -> {\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource.getUserDn()).isEqualTo(\"root\");\n\t\t\tassertThat(contextSource.isAnonymousReadOnly()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithReferral() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.referral:ignore\").run((context) -> {\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource).hasFieldOrPropertyWithValue(\"referral\", \"ignore\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithExtraCustomization() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.ldap.urls:ldap://localhost:123\", \"spring.ldap.username:root\",\n\t\t\t\t\t\"spring.ldap.password:secret\", \"spring.ldap.anonymous-read-only:true\",\n\t\t\t\t\t\"spring.ldap.base:cn=SpringDevelopers\",\n\t\t\t\t\t\"spring.ldap.baseEnvironment.java.naming.security.authentication:DIGEST-MD5\")\n\t\t\t.run((context) -> {\n\t\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\t\tassertThat(contextSource.getUserDn()).isEqualTo(\"root\");\n\t\t\t\tassertThat(contextSource.getPassword()).isEqualTo(\"secret\");\n\t\t\t\tassertThat(contextSource.isAnonymousReadOnly()).isTrue();\n\t\t\t\tassertThat(contextSource.getBaseLdapPathAsString()).isEqualTo(\"cn=SpringDevelopers\");\n\t\t\t\tLdapProperties ldapProperties = context.getBean(LdapProperties.class);\n\t\t\t\tassertThat(ldapProperties.getBaseEnvironment()).containsEntry(\"java.naming.security.authentication\",\n\t\t\t\t\t\t\"DIGEST-MD5\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithNoCustomization() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource.getUserDn()).isEmpty();\n\t\t\tassertThat(contextSource.getPassword()).isEmpty();\n\t\t\tassertThat(contextSource.isAnonymousReadOnly()).isTrue();\n\t\t\tassertThat(contextSource.getBaseLdapPathAsString()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesLdapConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid usesCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(LdapContextSource.class)\n\t\t\t\t.hasSingleBean(LdapConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesLdapConnectionDetails.class);\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource.getUrls()).isEqualTo(new String[] { \"ldaps://ldap.example.com\" });\n\t\t\tassertThat(contextSource.getBaseLdapName()).isEqualTo(LdapUtils.newLdapName(\"dc=base\"));\n\t\t\tassertThat(contextSource.getUserDn()).isEqualTo(\"ldap-user\");\n\t\t\tassertThat(contextSource.getPassword()).isEqualTo(\"ldap-password\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid objectDirectoryMapperExists() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.urls:ldap://localhost:389\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ObjectDirectoryMapper.class);\n\t\t\tObjectDirectoryMapper objectDirectoryMapper = context.getBean(ObjectDirectoryMapper.class);\n\t\t\tassertThat(objectDirectoryMapper).extracting(\"converterManager\")\n\t\t\t\t.extracting(\"conversionService\", InstanceOfAssertFactories.type(ApplicationConversionService.class))\n\t\t\t\t.satisfies((conversionService) -> {\n\t\t\t\t\tassertThat(conversionService.canConvert(String.class, Name.class)).isTrue();\n\t\t\t\t\tassertThat(conversionService.canConvert(Name.class, String.class)).isTrue();\n\t\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid templateExists() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.urls:ldap://localhost:389\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(LdapTemplate.class);\n\t\t\tLdapTemplate ldapTemplate = context.getBean(LdapTemplate.class);\n\t\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignorePartialResultException\", false);\n\t\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignoreNameNotFoundException\", false);\n\t\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignoreSizeLimitExceededException\", true);\n\t\t\tassertThat(ldapTemplate).extracting(\"objectDirectoryMapper\")\n\t\t\t\t.isSameAs(context.getBean(ObjectDirectoryMapper.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid templateCanBeConfiguredWithCustomObjectDirectoryMapper() {\n\t\tObjectDirectoryMapper objectDirectoryMapper = mock(ObjectDirectoryMapper.class);\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.urls:ldap://localhost:389\")\n\t\t\t.withBean(ObjectDirectoryMapper.class, () -> objectDirectoryMapper)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LdapTemplate.class);\n\t\t\t\tLdapTemplate ldapTemplate = context.getBean(LdapTemplate.class);\n\t\t\t\tassertThat(ldapTemplate).extracting(\"objectDirectoryMapper\").isSameAs(objectDirectoryMapper);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid templateConfigurationCanBeCustomized() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.ldap.urls:ldap://localhost:389\",\n\t\t\t\t\t\"spring.ldap.template.ignorePartialResultException=true\",\n\t\t\t\t\t\"spring.ldap.template.ignoreNameNotFoundException=true\",\n\t\t\t\t\t\"spring.ldap.template.ignoreSizeLimitExceededException=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LdapTemplate.class);\n\t\t\t\tLdapTemplate ldapTemplate = context.getBean(LdapTemplate.class);\n\t\t\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignorePartialResultException\", true);\n\t\t\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignoreNameNotFoundException\", true);\n\t\t\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignoreSizeLimitExceededException\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithUserProvidedPooledContextSource() {\n\t\tthis.contextRunner.withUserConfiguration(PooledContextSourceConfig.class).run((context) -> {\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource.getUrls()).containsExactly(\"ldap://localhost:389\");\n\t\t\tassertThat(contextSource.isAnonymousReadOnly()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithCustomUniqueDirContextAuthenticationStrategy() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDirContextAuthenticationStrategy.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DirContextAuthenticationStrategy.class);\n\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(contextSource).extracting(\"authenticationStrategy\")\n\t\t\t\t.isSameAs(context.getBean(\"customDirContextAuthenticationStrategy\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextSourceWithCustomNonUniqueDirContextAuthenticationStrategy() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomDirContextAuthenticationStrategy.class,\n\t\t\t\t\tAnotherCustomDirContextAuthenticationStrategy.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"customDirContextAuthenticationStrategy\")\n\t\t\t\t\t.hasBean(\"anotherCustomDirContextAuthenticationStrategy\");\n\t\t\t\tLdapContextSource contextSource = context.getBean(LdapContextSource.class);\n\t\t\t\tassertThat(contextSource).extracting(\"authenticationStrategy\")\n\t\t\t\t\t.isNotSameAs(context.getBean(\"customDirContextAuthenticationStrategy\"))\n\t\t\t\t\t.isNotSameAs(context.getBean(\"anotherCustomDirContextAuthenticationStrategy\"))\n\t\t\t\t\t.isInstanceOf(SimpleDirContextAuthenticationStrategy.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tLdapConnectionDetails ldapConnectionDetails() {\n\t\t\treturn new LdapConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String[] getUrls() {\n\t\t\t\t\treturn new String[] { \"ldaps://ldap.example.com\" };\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getBase() {\n\t\t\t\t\treturn \"dc=base\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"ldap-user\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"ldap-password\";\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PooledContextSourceConfig {\n\n\t\t@Bean\n\t\t@Primary\n\t\tPooledContextSource pooledContextSource(LdapContextSource ldapContextSource) {\n\t\t\treturn new PooledContextSource(ldapContextSource, new PoolConfig());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDirContextAuthenticationStrategy {\n\n\t\t@Bean\n\t\tDirContextAuthenticationStrategy customDirContextAuthenticationStrategy() {\n\t\t\treturn mock(DirContextAuthenticationStrategy.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnotherCustomDirContextAuthenticationStrategy {\n\n\t\t@Bean\n\t\tDirContextAuthenticationStrategy anotherCustomDirContextAuthenticationStrategy() {\n\t\t\treturn mock(DirContextAuthenticationStrategy.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/LdapPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ldap.autoconfigure.LdapProperties.Template;\nimport org.springframework.ldap.core.LdapTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LdapProperties}\n *\n * @author Filip Hrisafov\n */\nclass LdapPropertiesTests {\n\n\t@Test\n\tvoid ldapTemplatePropertiesUseConsistentLdapTemplateDefaultValues() {\n\t\tTemplate templateProperties = new LdapProperties().getTemplate();\n\t\tLdapTemplate ldapTemplate = new LdapTemplate();\n\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignorePartialResultException\",\n\t\t\t\ttemplateProperties.isIgnorePartialResultException());\n\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignoreNameNotFoundException\",\n\t\t\t\ttemplateProperties.isIgnoreNameNotFoundException());\n\t\tassertThat(ldapTemplate).hasFieldOrPropertyWithValue(\"ignoreSizeLimitExceededException\",\n\t\t\t\ttemplateProperties.isIgnoreSizeLimitExceededException());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/embedded/EmbeddedLdapAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure.embedded;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.unboundid.ldap.listener.InMemoryDirectoryServer;\nimport com.unboundid.ldap.listener.InMemoryListenerConfig;\nimport com.unboundid.ldap.sdk.BindResult;\nimport com.unboundid.ldap.sdk.DN;\nimport com.unboundid.ldap.sdk.LDAPConnection;\nimport com.unboundid.ldap.sdk.LDAPException;\nimport com.unboundid.ldap.sdk.schema.Schema;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.ldap.autoconfigure.LdapAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.ldap.core.ContextSource;\nimport org.springframework.ldap.core.LdapTemplate;\nimport org.springframework.ldap.core.support.LdapContextSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link EmbeddedLdapAutoConfiguration}\n *\n * @author Eddú Meléndez\n */\nclass EmbeddedLdapAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(EmbeddedLdapAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid testSetDefaultPort() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.ldap.embedded.port:1234\", \"spring.ldap.embedded.base-dn:dc=spring,dc=org\")\n\t\t\t.run((context) -> {\n\t\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\t\tassertThat(server.getListenPort()).isEqualTo(1234);\n\t\t\t\tInMemoryListenerConfig config = server.getConfig().getListenerConfigs().get(0);\n\t\t\t\tassertThat(config.getListenerName()).isEqualTo(\"LDAP\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testRandomPortWithEnvironment() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\").run((context) -> {\n\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\tassertThat(server.getListenPort())\n\t\t\t\t.isEqualTo(context.getEnvironment().getProperty(\"local.ldap.port\", Integer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid testRandomPortWithValueAnnotation() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\").applyTo(context);\n\t\tcontext.register(EmbeddedLdapAutoConfiguration.class, LdapClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\tcontext.refresh();\n\t\tLDAPConnection connection = context.getBean(LDAPConnection.class);\n\t\tassertThat(connection.getConnectedPort())\n\t\t\t.isEqualTo(context.getEnvironment().getProperty(\"local.ldap.port\", Integer.class));\n\t}\n\n\t@Test\n\tvoid testSetCredentials() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\",\n\t\t\t\t\"spring.ldap.embedded.credential.username:uid=root\", \"spring.ldap.embedded.credential.password:boot\")\n\t\t\t.run((context) -> {\n\t\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\t\tBindResult result = server.bind(\"uid=root\", \"boot\");\n\t\t\t\tassertThat(result).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testSetPartitionSuffix() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\").run((context) -> {\n\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\tassertThat(server.getBaseDNs()).containsExactly(new DN(\"dc=spring,dc=org\"));\n\t\t});\n\t}\n\n\t@Test\n\t@WithSchemaLdifResource\n\tvoid testSetLdifFile() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\").run((context) -> {\n\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\tassertThat(server.countEntriesBelow(\"ou=company1,c=Sweden,dc=spring,dc=org\")).isEqualTo(5);\n\t\t});\n\t}\n\n\t@Test\n\t@WithSchemaLdifResource\n\tvoid testQueryEmbeddedLdap() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\")\n\t\t\t.withConfiguration(AutoConfigurations.of(LdapAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LdapTemplate.class);\n\t\t\t\tLdapTemplate ldapTemplate = context.getBean(LdapTemplate.class);\n\t\t\t\tassertThat(ldapTemplate.list(\"ou=company1,c=Sweden,dc=spring,dc=org\")).hasSize(4);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testDisableSchemaValidation() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.ldap.embedded.validation.enabled:false\",\n\t\t\t\t\t\"spring.ldap.embedded.base-dn:dc=spring,dc=org\")\n\t\t\t.run((context) -> {\n\t\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\t\tassertThat(server.getSchema()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-schema.ldif\", content = \"\"\"\n\t\t\tdn: cn=schema\n\t\t\tattributeTypes: ( 1.3.6.1.4.1.32473.1.1.1\n\t\t\t  NAME 'exampleAttributeName'\n\t\t\t  DESC 'An example attribute type definition'\n\t\t\t  EQUALITY caseIgnoreMatch\n\t\t\t  ORDERING caseIgnoreOrderingMatch\n\t\t\t  SUBSTR caseIgnoreSubstringsMatch\n\t\t\t  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15\n\t\t\t  SINGLE-VALUE\n\t\t\t  X-ORIGIN 'Managing Schema Document' )\n\t\t\tobjectClasses: ( 1.3.6.1.4.1.32473.1.2.2\n\t\t\t  NAME 'exampleAuxiliaryClass'\n\t\t\t  DESC 'An example auxiliary object class definition'\n\t\t\t  SUP top\n\t\t\t  AUXILIARY\n\t\t\t  MAY exampleAttributeName\n\t\t\t  X-ORIGIN 'Managing Schema Document' )\n\t\t\t\"\"\")\n\t@WithResource(name = \"custom-schema-sample.ldif\", content = \"\"\"\n\t\t\tdn: dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: domain\n\t\t\tobjectclass: extensibleObject\n\t\t\tobjectClass: exampleAuxiliaryClass\n\t\t\tdc: spring\n\t\t\texampleAttributeName: exampleAttributeName\n\t\t\t\"\"\")\n\tvoid testCustomSchemaValidation() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.ldap.embedded.validation.schema:classpath:custom-schema.ldif\",\n\t\t\t\t\t\"spring.ldap.embedded.ldif:classpath:custom-schema-sample.ldif\",\n\t\t\t\t\t\"spring.ldap.embedded.base-dn:dc=spring,dc=org\")\n\t\t\t.run((context) -> {\n\t\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\t\tSchema schema = server.getSchema();\n\t\t\t\tassertThat(schema).isNotNull();\n\t\t\t\tassertThat(schema.getObjectClass(\"exampleAuxiliaryClass\")).isNotNull();\n\t\t\t\tassertThat(schema.getAttributeType(\"exampleAttributeName\")).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"schema-multi-basedn.ldif\", content = \"\"\"\n\t\t\tdn: dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: domain\n\t\t\tobjectclass: extensibleObject\n\t\t\tdc: spring\n\n\t\t\tdn: ou=groups,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: organizationalUnit\n\t\t\tou: groups\n\n\t\t\tdn: cn=ROLE_USER,ou=groups,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: groupOfUniqueNames\n\t\t\tcn: ROLE_USER\n\t\t\tuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tuniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org\n\n\t\t\tdn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: groupOfUniqueNames\n\t\t\tcn: ROLE_ADMIN\n\t\t\tuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\n\t\t\tdn: c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: country\n\t\t\tc: Sweden\n\t\t\tdescription: The country of Sweden\n\n\t\t\tdn: ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: organizationalUnit\n\t\t\tou: company1\n\t\t\tdescription: First company in Sweden\n\n\t\t\tdn: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person\n\t\t\tsn: Person\n\t\t\tdescription: Sweden, Company1, Some Person\n\t\t\ttelephoneNumber: +46 555-123456\n\n\t\t\tdn: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person2\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person2\n\t\t\tsn: Person2\n\t\t\tdescription: Sweden, Company1, Some Person2\n\t\t\ttelephoneNumber: +46 555-654321\n\n\t\t\tdn: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person3\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person3\n\t\t\tsn: Person3\n\t\t\tdescription: Sweden, Company1, Some Person3\n\t\t\ttelephoneNumber: +46 555-123654\n\n\t\t\tdn: cn=Some Person4,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person4\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person\n\t\t\tsn: Person\n\t\t\tdescription: Sweden, Company1, Some Person\n\t\t\ttelephoneNumber: +46 555-456321\n\n\t\t\tdn: dc=vmware,dc=com\n\t\t\tobjectclass: top\n\t\t\tobjectclass: domain\n\t\t\tobjectclass: extensibleObject\n\t\t\tdc: vmware\n\n\t\t\tdn: ou=groups,dc=vmware,dc=com\n\t\t\tobjectclass: top\n\t\t\tobjectclass: organizationalUnit\n\t\t\tou: groups\n\n\t\t\tdn: c=Sweden,dc=vmware,dc=com\n\t\t\tobjectclass: top\n\t\t\tobjectclass: country\n\t\t\tc: Sweden\n\t\t\tdescription:The country of Sweden\n\n\t\t\tdn: cn=Some Random Person,c=Sweden,dc=vmware,dc=com\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.random.person\n\t\t\tuserPassword: password\n\t\t\tcn: Some Random Person\n\t\t\tsn: Person\n\t\t\tdescription: Sweden, VMware, Some Random Person\n\t\t\ttelephoneNumber: +46 555-123456\n\t\t\t\"\"\")\n\tvoid testMultiBaseDn() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.ldif:classpath:schema-multi-basedn.ldif\",\n\t\t\t\t\"spring.ldap.embedded.base-dn[0]:dc=spring,dc=org\", \"spring.ldap.embedded.base-dn[1]:dc=vmware,dc=com\")\n\t\t\t.run((context) -> {\n\t\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\t\tassertThat(server.countEntriesBelow(\"ou=company1,c=Sweden,dc=spring,dc=org\")).isEqualTo(5);\n\t\t\t\tassertThat(server.countEntriesBelow(\"c=Sweden,dc=vmware,dc=com\")).isEqualTo(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid ldapContextSourceWithCredentialsIsCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\",\n\t\t\t\t\"spring.ldap.embedded.credential.username:uid=root\", \"spring.ldap.embedded.credential.password:boot\")\n\t\t\t.run((context) -> {\n\t\t\t\tLdapContextSource ldapContextSource = context.getBean(LdapContextSource.class);\n\t\t\t\tassertThat(ldapContextSource.getUrls()).isNotEmpty();\n\t\t\t\tassertThat(ldapContextSource.getUserDn()).isEqualTo(\"uid=root\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid ldapContextSourceWithoutCredentialsIsCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\").run((context) -> {\n\t\t\tLdapContextSource ldapContextSource = context.getBean(LdapContextSource.class);\n\t\t\tassertThat(ldapContextSource.getUrls()).isNotEmpty();\n\t\t\tassertThat(ldapContextSource.getUserDn()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid ldapContextWithoutSpringLdapIsNotCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\")\n\t\t\t.withClassLoader(new FilteredClassLoader(ContextSource.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).doesNotHaveBean(LdapContextSource.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid ldapContextIsCreatedWithBase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\", \"spring.ldap.base:dc=spring,dc=org\")\n\t\t\t.run((context) -> {\n\t\t\t\tLdapContextSource ldapContextSource = context.getBean(LdapContextSource.class);\n\t\t\t\tassertThat(ldapContextSource.getBaseLdapPathAsString()).isEqualTo(\"dc=spring,dc=org\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenSslBundleIsConfiguredLdapsListenerIsConfigured() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/ldap/autoconfigure/embedded/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.keystore.password=secret\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.keystore.location=\" + location + \"test.jks\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.truststore.location=\" + location + \"test.jks\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.protocol=TLSv1.2\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.port:0\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.ssl.bundle:test\");\n\t\tthis.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {\n\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\tassertThat(server.getConfig().getListenerConfigs().size()).isEqualTo(1);\n\t\t\tInMemoryListenerConfig config = server.getConfig().getListenerConfigs().get(0);\n\t\t\tassertThat(config.getListenerName()).isEqualTo(\"LDAPS\");\n\t\t\tassertThat(server.getConnection(\"LDAPS\").getSSLSession()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenSslBundleIsConfiguredButSslIsDisabledLdapListenerIsConfigured() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/ldap/autoconfigure/embedded/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.keystore.password=secret\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.keystore.location=\" + location + \"test.jks\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.truststore.location=\" + location + \"test.jks\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.protocol=TLSv1.2\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.port:0\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.ssl.enabled:false\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.ssl.bundle:test\");\n\t\tthis.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {\n\t\t\tInMemoryDirectoryServer server = context.getBean(InMemoryDirectoryServer.class);\n\t\t\tassertThat(server.getConfig().getListenerConfigs().size()).isEqualTo(1);\n\t\t\tInMemoryListenerConfig config = server.getConfig().getListenerConfigs().get(0);\n\t\t\tassertThat(config.getListenerName()).isEqualTo(\"LDAP\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenInvalidSslBundleIsConfiguredThenStartFails() {\n\t\tList<String> propertyValues = new ArrayList<>();\n\t\tString location = \"classpath:org/springframework/boot/ldap/autoconfigure/embedded/\";\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.keystore.password=secret\");\n\t\tpropertyValues.add(\"spring.ssl.bundle.jks.test.keystore.location=\" + location + \"test.jks\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.port:0\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.base-dn:dc=spring,dc=org\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.ssl.enabled:true\");\n\t\tpropertyValues.add(\"spring.ldap.embedded.ssl.bundle:foo\");\n\t\tthis.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure().hasMessageContaining(\"foo\");\n\t\t\tassertThat(context).getFailure().hasMessageContaining(\"cannot be found\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LdapClientConfiguration {\n\n\t\t@Bean\n\t\tLDAPConnection ldapConnection(@Value(\"${local.ldap.port}\") int port) throws LDAPException {\n\t\t\tLDAPConnection con = new LDAPConnection();\n\t\t\tcon.connect(\"localhost\", port);\n\t\t\treturn con;\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"schema.ldif\", content = \"\"\"\n\t\t\tdn: dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: domain\n\t\t\tobjectclass: extensibleObject\n\t\t\tdc: spring\n\n\t\t\tdn: ou=groups,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: organizationalUnit\n\t\t\tou: groups\n\n\t\t\tdn: cn=ROLE_USER,ou=groups,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: groupOfUniqueNames\n\t\t\tcn: ROLE_USER\n\t\t\tuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tuniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org\n\n\t\t\tdn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: groupOfUniqueNames\n\t\t\tcn: ROLE_ADMIN\n\t\t\tuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\n\t\t\tdn: c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: country\n\t\t\tc: Sweden\n\t\t\tdescription: The country of Sweden\n\n\t\t\tdn: ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: organizationalUnit\n\t\t\tou: company1\n\t\t\tdescription: First company in Sweden\n\n\t\t\tdn: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person\n\t\t\tsn: Person\n\t\t\tdescription: Sweden, Company1, Some Person\n\t\t\ttelephoneNumber: +46 555-123456\n\n\t\t\tdn: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person2\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person2\n\t\t\tsn: Person2\n\t\t\tdescription: Sweden, Company1, Some Person2\n\t\t\ttelephoneNumber: +46 555-654321\n\n\t\t\tdn: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person3\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person3\n\t\t\tsn: Person3\n\t\t\tdescription: Sweden, Company1, Some Person3\n\t\t\ttelephoneNumber: +46 555-123654\n\n\t\t\tdn: cn=Some Person4,ou=company1,c=Sweden,dc=spring,dc=org\n\t\t\tobjectclass: top\n\t\t\tobjectclass: person\n\t\t\tobjectclass: organizationalPerson\n\t\t\tobjectclass: inetOrgPerson\n\t\t\tuid: some.person4\n\t\t\tuserPassword: password\n\t\t\tcn: Some Person\n\t\t\tsn: Person\n\t\t\tdescription: Sweden, Company1, Some Person\n\t\t\ttelephoneNumber: +46 555-456321\n\t\t\t\"\"\")\n\t@interface WithSchemaLdifResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/autoconfigure/health/LdapHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.ldap.health.LdapHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.ldap.core.LdapOperations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LdapHealthContributorAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\nclass LdapHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(LdapOperations.class, () -> mock(LdapOperations.class))\n\t\t.withConfiguration(AutoConfigurations.of(LdapHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(LdapHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.ldap.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LdapHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-ldap/src/test/java/org/springframework/boot/ldap/health/LdapHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.ldap.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.ldap.CommunicationException;\nimport org.springframework.ldap.core.ContextExecutor;\nimport org.springframework.ldap.core.LdapTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LdapHealthIndicator}\n *\n * @author Eddú Meléndez\n */\nclass LdapHealthIndicatorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid ldapIsUp() {\n\t\tLdapTemplate ldapTemplate = mock(LdapTemplate.class);\n\t\tgiven(ldapTemplate.executeReadOnly((ContextExecutor<String>) any())).willReturn(\"3\");\n\t\tLdapHealthIndicator healthIndicator = new LdapHealthIndicator(ldapTemplate);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"version\", \"3\");\n\t\tthen(ldapTemplate).should().executeReadOnly((ContextExecutor<String>) any());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid ldapIsDown() {\n\t\tLdapTemplate ldapTemplate = mock(LdapTemplate.class);\n\t\tgiven(ldapTemplate.executeReadOnly((ContextExecutor<String>) any()))\n\t\t\t.willThrow(new CommunicationException(new javax.naming.CommunicationException(\"Connection failed\")));\n\t\tLdapHealthIndicator healthIndicator = new LdapHealthIndicator(ldapTemplate);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat((String) health.getDetails().get(\"error\")).contains(\"Connection failed\");\n\t\tthen(ldapTemplate).should().executeReadOnly((ContextExecutor<String>) any());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Liquibase\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(\"org.liquibase:liquibase-core\") {\n\t\texclude(group: \"javax.xml.bind\", module: \"jaxb-api\")\n\t}\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(\"org.testcontainers:testcontainers-jdbc\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\tdockerTestRuntimeOnly(\"org.postgresql:postgresql\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"com.h2database:h2\")\n\ttestImplementation(\"com.zaxxer:HikariCP\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.postgresql:postgresql\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/dockerTest/java/org/springframework/boot/liquibase/docker/compose/JdbcAdaptingLiquibaseConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JdbcAdaptingLiquibaseConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass JdbcAdaptingLiquibaseConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"liquibase-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetails(LiquibaseConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUsername()).isEqualTo(\"myuser\");\n\t\tassertThat(connectionDetails.getPassword()).isEqualTo(\"secret\");\n\t\tassertThat(connectionDetails.getJdbcUrl()).startsWith(\"jdbc:postgresql://\").endsWith(\"/mydatabase\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/dockerTest/java/org/springframework/boot/liquibase/testcontainers/LiquibaseContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.testcontainers;\n\nimport liquibase.integration.spring.SpringLiquibase;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link LiquibaseContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass LiquibaseContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final PostgreSQLContainer postgres = TestImage.container(PostgreSQLContainer.class);\n\n\t@Autowired(required = false)\n\tprivate JdbcConnectionDetails connectionDetails;\n\n\t@Autowired\n\tprivate SpringLiquibase liquibase;\n\n\t@Test\n\tvoid connectionCanBeMadeToJdbcContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tJdbcTemplate jdbc = new JdbcTemplate(this.liquibase.getDataSource());\n\t\tassertThatNoException().isThrownBy(() -> jdbc.execute(\"SELECT * from example\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(LiquibaseAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/dockerTest/resources/db/changelog/db.changelog-master.yaml",
    "content": "databaseChangeLog:\n  - changeSet:\n      id: 1\n      author: wilkinsona\n      changes:\n        - createTable:\n            tableName: example\n            columns:\n              - column:\n                  name: id\n                  type: int\n                  autoIncrement: true\n                  constraints:\n                    primaryKey: true\n                    nullable: false\n              - column:\n                  name: name\n                  type: varchar(50)\n                  constraints:\n                    nullable: false\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/dockerTest/resources/org/springframework/boot/liquibase/docker/compose/liquibase-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/LiquibaseChangelogMissingFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase;\n\nimport liquibase.exception.ChangeLogParseException;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that analyzes exceptions of type\n * {@link ChangeLogParseException} caused by a Liquibase changelog not being present.\n *\n * @author Sebastiaan Fernandez\n */\nclass LiquibaseChangelogMissingFailureAnalyzer extends AbstractFailureAnalyzer<ChangeLogParseException> {\n\n\tprivate static final String MESSAGE_SUFFIX = \" does not exist\";\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, ChangeLogParseException cause) {\n\t\tString message = cause.getMessage();\n\t\tif (message != null && message.endsWith(MESSAGE_SUFFIX)) {\n\t\t\tString changelogPath = extractChangelogPath(message);\n\t\t\treturn new FailureAnalysis(getDescription(changelogPath),\n\t\t\t\t\t\"Make sure a Liquibase changelog is present at the configured path.\", cause);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String extractChangelogPath(String message) {\n\t\treturn message.substring(0, message.length() - MESSAGE_SUFFIX.length());\n\t}\n\n\tprivate String getDescription(String changelogPath) {\n\t\treturn \"Liquibase failed to start because no changelog could be found at '\" + changelogPath + \"'.\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/LiquibaseDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport liquibase.integration.spring.SpringLiquibase;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\n\n/**\n * A {@link DatabaseInitializerDetector} for Liquibase.\n *\n * @author Andy Wilkinson\n */\nclass LiquibaseDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\treturn Collections.singleton(SpringLiquibase.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/actuate/endpoint/LiquibaseEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.actuate.endpoint;\n\nimport java.time.Instant;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport liquibase.changelog.ChangeSet.ExecType;\nimport liquibase.changelog.RanChangeSet;\nimport liquibase.changelog.StandardChangeLogHistoryService;\nimport liquibase.database.Database;\nimport liquibase.database.DatabaseFactory;\nimport liquibase.database.jvm.JdbcConnection;\nimport liquibase.integration.spring.SpringLiquibase;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Endpoint @Endpoint} to expose liquibase info.\n *\n * @author Eddú Meléndez\n * @author Nabil Fawwaz Elqayyim\n * @since 4.0.0\n */\n@Endpoint(id = \"liquibase\")\npublic class LiquibaseEndpoint {\n\n\tprivate final ApplicationContext context;\n\n\tpublic LiquibaseEndpoint(ApplicationContext context) {\n\t\tAssert.notNull(context, \"'context' must be specified\");\n\t\tthis.context = context;\n\t}\n\n\t@ReadOperation\n\tpublic LiquibaseBeansDescriptor liquibaseBeans() {\n\t\tApplicationContext target = this.context;\n\t\tMap<@Nullable String, ContextLiquibaseBeansDescriptor> contextBeans = new HashMap<>();\n\t\twhile (target != null) {\n\t\t\tMap<String, LiquibaseBeanDescriptor> liquibaseBeans = new HashMap<>();\n\t\t\tDatabaseFactory factory = DatabaseFactory.getInstance();\n\t\t\ttarget.getBeansOfType(SpringLiquibase.class)\n\t\t\t\t.forEach((name, liquibase) -> liquibaseBeans.put(name, createReport(liquibase, factory)));\n\t\t\tApplicationContext parent = target.getParent();\n\t\t\tcontextBeans.put(target.getId(),\n\t\t\t\t\tnew ContextLiquibaseBeansDescriptor(liquibaseBeans, (parent != null) ? parent.getId() : null));\n\t\t\ttarget = parent;\n\t\t}\n\t\treturn new LiquibaseBeansDescriptor(contextBeans);\n\t}\n\n\tprivate LiquibaseBeanDescriptor createReport(SpringLiquibase liquibase, DatabaseFactory factory) {\n\t\ttry {\n\t\t\tDataSource dataSource = liquibase.getDataSource();\n\t\t\tJdbcConnection connection = new JdbcConnection(dataSource.getConnection());\n\t\t\tDatabase database = null;\n\t\t\ttry {\n\t\t\t\tdatabase = factory.findCorrectDatabaseImplementation(connection);\n\t\t\t\tString schemaToUse = StringUtils.hasText(liquibase.getLiquibaseSchema())\n\t\t\t\t\t\t? liquibase.getLiquibaseSchema() : liquibase.getDefaultSchema();\n\t\t\t\tif (StringUtils.hasText(schemaToUse)) {\n\t\t\t\t\tdatabase.setDefaultSchemaName(schemaToUse);\n\t\t\t\t}\n\t\t\t\tdatabase.setDatabaseChangeLogTableName(liquibase.getDatabaseChangeLogTable());\n\t\t\t\tdatabase.setDatabaseChangeLogLockTableName(liquibase.getDatabaseChangeLogLockTable());\n\t\t\t\tStandardChangeLogHistoryService service = new StandardChangeLogHistoryService();\n\t\t\t\tservice.setDatabase(database);\n\t\t\t\treturn new LiquibaseBeanDescriptor(\n\t\t\t\t\t\tservice.getRanChangeSets().stream().map(ChangeSetDescriptor::new).toList());\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tif (database != null) {\n\t\t\t\t\tdatabase.close();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconnection.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to get Liquibase change sets\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Description of an application's {@link SpringLiquibase} beans.\n\t */\n\tpublic static final class LiquibaseBeansDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<@Nullable String, ContextLiquibaseBeansDescriptor> contexts;\n\n\t\tprivate LiquibaseBeansDescriptor(Map<@Nullable String, ContextLiquibaseBeansDescriptor> contexts) {\n\t\t\tthis.contexts = contexts;\n\t\t}\n\n\t\tpublic Map<@Nullable String, ContextLiquibaseBeansDescriptor> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of an application context's {@link SpringLiquibase} beans.\n\t */\n\tpublic static final class ContextLiquibaseBeansDescriptor {\n\n\t\tprivate final Map<String, LiquibaseBeanDescriptor> liquibaseBeans;\n\n\t\tprivate final @Nullable String parentId;\n\n\t\tprivate ContextLiquibaseBeansDescriptor(Map<String, LiquibaseBeanDescriptor> liquibaseBeans,\n\t\t\t\t@Nullable String parentId) {\n\t\t\tthis.liquibaseBeans = liquibaseBeans;\n\t\t\tthis.parentId = parentId;\n\t\t}\n\n\t\tpublic Map<String, LiquibaseBeanDescriptor> getLiquibaseBeans() {\n\t\t\treturn this.liquibaseBeans;\n\t\t}\n\n\t\tpublic @Nullable String getParentId() {\n\t\t\treturn this.parentId;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link SpringLiquibase} bean.\n\t */\n\tpublic static final class LiquibaseBeanDescriptor {\n\n\t\tprivate final List<ChangeSetDescriptor> changeSets;\n\n\t\tpublic LiquibaseBeanDescriptor(List<ChangeSetDescriptor> changeSets) {\n\t\t\tthis.changeSets = changeSets;\n\t\t}\n\n\t\tpublic List<ChangeSetDescriptor> getChangeSets() {\n\t\t\treturn this.changeSets;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a Liquibase change set.\n\t */\n\tpublic static class ChangeSetDescriptor {\n\n\t\tprivate final String author;\n\n\t\tprivate final String changeLog;\n\n\t\tprivate final String comments;\n\n\t\tprivate final Set<String> contexts;\n\n\t\tprivate final Instant dateExecuted;\n\n\t\tprivate final String deploymentId;\n\n\t\tprivate final String description;\n\n\t\tprivate final ExecType execType;\n\n\t\tprivate final String id;\n\n\t\tprivate final Set<String> labels;\n\n\t\tprivate final @Nullable String checksum;\n\n\t\tprivate final Integer orderExecuted;\n\n\t\tprivate final String tag;\n\n\t\tpublic ChangeSetDescriptor(RanChangeSet ranChangeSet) {\n\t\t\tthis.author = ranChangeSet.getAuthor();\n\t\t\tthis.changeLog = ranChangeSet.getChangeLog();\n\t\t\tthis.comments = ranChangeSet.getComments();\n\t\t\tthis.contexts = ranChangeSet.getContextExpression().getContexts();\n\t\t\tthis.dateExecuted = Instant.ofEpochMilli(ranChangeSet.getDateExecuted().getTime());\n\t\t\tthis.deploymentId = ranChangeSet.getDeploymentId();\n\t\t\tthis.description = ranChangeSet.getDescription();\n\t\t\tthis.execType = ranChangeSet.getExecType();\n\t\t\tthis.id = ranChangeSet.getId();\n\t\t\tthis.labels = ranChangeSet.getLabels().getLabels();\n\t\t\tthis.checksum = ((ranChangeSet.getLastCheckSum() != null) ? ranChangeSet.getLastCheckSum().toString()\n\t\t\t\t\t: null);\n\t\t\tthis.orderExecuted = ranChangeSet.getOrderExecuted();\n\t\t\tthis.tag = ranChangeSet.getTag();\n\t\t}\n\n\t\tpublic String getAuthor() {\n\t\t\treturn this.author;\n\t\t}\n\n\t\tpublic String getChangeLog() {\n\t\t\treturn this.changeLog;\n\t\t}\n\n\t\tpublic String getComments() {\n\t\t\treturn this.comments;\n\t\t}\n\n\t\tpublic Set<String> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t\tpublic Instant getDateExecuted() {\n\t\t\treturn this.dateExecuted;\n\t\t}\n\n\t\tpublic String getDeploymentId() {\n\t\t\treturn this.deploymentId;\n\t\t}\n\n\t\tpublic String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tpublic ExecType getExecType() {\n\t\t\treturn this.execType;\n\t\t}\n\n\t\tpublic String getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t\tpublic Set<String> getLabels() {\n\t\t\treturn this.labels;\n\t\t}\n\n\t\tpublic @Nullable String getChecksum() {\n\t\t\treturn this.checksum;\n\t\t}\n\n\t\tpublic Integer getOrderExecuted() {\n\t\t\treturn this.orderExecuted;\n\t\t}\n\n\t\tpublic String getTag() {\n\t\t\treturn this.tag;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a context expression in a {@link ChangeSetDescriptor}.\n\t */\n\tpublic static class ContextExpressionDescriptor {\n\n\t\tprivate final Set<String> contexts;\n\n\t\tpublic ContextExpressionDescriptor(Set<String> contexts) {\n\t\t\tthis.contexts = contexts;\n\t\t}\n\n\t\tpublic Set<String> getContexts() {\n\t\t\treturn this.contexts;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for Liquibase.\n */\n@NullMarked\npackage org.springframework.boot.liquibase.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/DataSourceClosingSpringLiquibase.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.lang.reflect.Method;\n\nimport javax.sql.DataSource;\n\nimport liquibase.exception.LiquibaseException;\nimport liquibase.integration.spring.SpringLiquibase;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * A custom {@link SpringLiquibase} extension that closes the underlying\n * {@link DataSource} once the database has been migrated.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class DataSourceClosingSpringLiquibase extends SpringLiquibase implements DisposableBean {\n\n\tprivate volatile boolean closeDataSourceOnceMigrated = true;\n\n\tpublic void setCloseDataSourceOnceMigrated(boolean closeDataSourceOnceMigrated) {\n\t\tthis.closeDataSourceOnceMigrated = closeDataSourceOnceMigrated;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws LiquibaseException {\n\t\tsuper.afterPropertiesSet();\n\t\tif (this.closeDataSourceOnceMigrated) {\n\t\t\tcloseDataSource();\n\t\t}\n\t}\n\n\tprivate void closeDataSource() {\n\t\tClass<?> dataSourceClass = getDataSource().getClass();\n\t\tMethod closeMethod = ReflectionUtils.findMethod(dataSourceClass, \"close\");\n\t\tif (closeMethod != null) {\n\t\t\tReflectionUtils.invokeMethod(closeMethod, getDataSource());\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tif (!this.closeDataSourceOnceMigrated) {\n\t\t\tcloseDataSource();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport liquibase.Liquibase;\nimport liquibase.UpdateSummaryEnum;\nimport liquibase.UpdateSummaryOutputEnum;\nimport liquibase.change.DatabaseChange;\nimport liquibase.integration.spring.Customizer;\nimport liquibase.integration.spring.SpringLiquibase;\nimport liquibase.ui.UIServiceEnum;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration.LiquibaseAutoConfigurationRuntimeHints;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration.LiquibaseDataSourceCondition;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.jdbc.core.ConnectionCallback;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Liquibase.\n *\n * @author Marcel Overdijk\n * @author Dave Syer\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n * @author Dominic Gunn\n * @author Dan Zheng\n * @author András Deák\n * @author Ferenc Gratzer\n * @author Evgeniy Cheban\n * @author Moritz Halbritter\n * @author Ahmed Ashour\n * @since 4.0.0\n */\n@AutoConfiguration(after = DataSourceAutoConfiguration.class)\n@ConditionalOnClass({ SpringLiquibase.class, DatabaseChange.class })\n@ConditionalOnBooleanProperty(name = \"spring.liquibase.enabled\", matchIfMissing = true)\n@Conditional(LiquibaseDataSourceCondition.class)\n@Import(DatabaseInitializationDependencyConfigurer.class)\n@ImportRuntimeHints(LiquibaseAutoConfigurationRuntimeHints.class)\npublic final class LiquibaseAutoConfiguration {\n\n\t@Bean\n\tLiquibaseSchemaManagementProvider liquibaseDefaultDdlModeProvider(ObjectProvider<SpringLiquibase> liquibases) {\n\t\treturn new LiquibaseSchemaManagementProvider(liquibases);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ConnectionCallback.class)\n\t@ConditionalOnMissingBean(SpringLiquibase.class)\n\t@EnableConfigurationProperties(LiquibaseProperties.class)\n\tstatic class LiquibaseConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(LiquibaseConnectionDetails.class)\n\t\tPropertiesLiquibaseConnectionDetails liquibaseConnectionDetails(LiquibaseProperties properties) {\n\t\t\treturn new PropertiesLiquibaseConnectionDetails(properties);\n\t\t}\n\n\t\t@Bean\n\t\tSpringLiquibase liquibase(ObjectProvider<DataSource> dataSource,\n\t\t\t\t@LiquibaseDataSource ObjectProvider<DataSource> liquibaseDataSource, LiquibaseProperties properties,\n\t\t\t\tObjectProvider<SpringLiquibaseCustomizer> customizers, LiquibaseConnectionDetails connectionDetails) {\n\t\t\tSpringLiquibase liquibase = createSpringLiquibase(liquibaseDataSource.getIfAvailable(),\n\t\t\t\t\tdataSource.getIfUnique(), connectionDetails);\n\t\t\tliquibase.setChangeLog(properties.getChangeLog());\n\t\t\tliquibase.setClearCheckSums(properties.isClearChecksums());\n\t\t\tif (!CollectionUtils.isEmpty(properties.getContexts())) {\n\t\t\t\tliquibase.setContexts(StringUtils.collectionToCommaDelimitedString(properties.getContexts()));\n\t\t\t}\n\t\t\tliquibase.setDefaultSchema(properties.getDefaultSchema());\n\t\t\tliquibase.setLiquibaseSchema(properties.getLiquibaseSchema());\n\t\t\tliquibase.setLiquibaseTablespace(properties.getLiquibaseTablespace());\n\t\t\tliquibase.setDatabaseChangeLogTable(properties.getDatabaseChangeLogTable());\n\t\t\tliquibase.setDatabaseChangeLogLockTable(properties.getDatabaseChangeLogLockTable());\n\t\t\tliquibase.setDropFirst(properties.isDropFirst());\n\t\t\tliquibase.setShouldRun(properties.isEnabled());\n\t\t\tif (!CollectionUtils.isEmpty(properties.getLabelFilter())) {\n\t\t\t\tliquibase.setLabelFilter(StringUtils.collectionToCommaDelimitedString(properties.getLabelFilter()));\n\t\t\t}\n\t\t\tliquibase.setChangeLogParameters(properties.getParameters());\n\t\t\tliquibase.setRollbackFile(properties.getRollbackFile());\n\t\t\tliquibase.setTestRollbackOnUpdate(properties.isTestRollbackOnUpdate());\n\t\t\tliquibase.setTag(properties.getTag());\n\t\t\tif (properties.getShowSummary() != null) {\n\t\t\t\tliquibase.setShowSummary(UpdateSummaryEnum.valueOf(properties.getShowSummary().name()));\n\t\t\t}\n\t\t\tif (properties.getShowSummaryOutput() != null) {\n\t\t\t\tliquibase\n\t\t\t\t\t.setShowSummaryOutput(UpdateSummaryOutputEnum.valueOf(properties.getShowSummaryOutput().name()));\n\t\t\t}\n\t\t\tif (properties.getUiService() != null) {\n\t\t\t\tliquibase.setUiService(UIServiceEnum.valueOf(properties.getUiService().name()));\n\t\t\t}\n\t\t\tif (properties.getAnalyticsEnabled() != null) {\n\t\t\t\tliquibase.setAnalyticsEnabled(properties.getAnalyticsEnabled());\n\t\t\t}\n\t\t\tif (properties.getLicenseKey() != null) {\n\t\t\t\tliquibase.setLicenseKey(properties.getLicenseKey());\n\t\t\t}\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(liquibase));\n\t\t\treturn liquibase;\n\t\t}\n\n\t\tprivate SpringLiquibase createSpringLiquibase(@Nullable DataSource liquibaseDataSource,\n\t\t\t\t@Nullable DataSource dataSource, LiquibaseConnectionDetails connectionDetails) {\n\t\t\tDataSource migrationDataSource = getMigrationDataSource(liquibaseDataSource, dataSource, connectionDetails);\n\t\t\tSpringLiquibase liquibase = (migrationDataSource == liquibaseDataSource\n\t\t\t\t\t|| migrationDataSource == dataSource) ? new SpringLiquibase()\n\t\t\t\t\t\t\t: new DataSourceClosingSpringLiquibase();\n\t\t\tliquibase.setDataSource(migrationDataSource);\n\t\t\treturn liquibase;\n\t\t}\n\n\t\tprivate DataSource getMigrationDataSource(@Nullable DataSource liquibaseDataSource,\n\t\t\t\t@Nullable DataSource dataSource, LiquibaseConnectionDetails connectionDetails) {\n\t\t\tif (liquibaseDataSource != null) {\n\t\t\t\treturn liquibaseDataSource;\n\t\t\t}\n\t\t\tString url = connectionDetails.getJdbcUrl();\n\t\t\tif (url != null) {\n\t\t\t\tDataSourceBuilder<?> builder = DataSourceBuilder.create().type(SimpleDriverDataSource.class);\n\t\t\t\tbuilder.url(url);\n\t\t\t\tapplyConnectionDetails(connectionDetails, builder);\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tString user = connectionDetails.getUsername();\n\t\t\tif (user != null && dataSource != null) {\n\t\t\t\tDataSourceBuilder<?> builder = DataSourceBuilder.derivedFrom(dataSource)\n\t\t\t\t\t.type(SimpleDriverDataSource.class);\n\t\t\t\tapplyConnectionDetails(connectionDetails, builder);\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tAssert.state(dataSource != null, \"Liquibase migration DataSource missing\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t\tprivate void applyConnectionDetails(LiquibaseConnectionDetails connectionDetails,\n\t\t\t\tDataSourceBuilder<?> builder) {\n\t\t\tbuilder.username(connectionDetails.getUsername());\n\t\t\tbuilder.password(connectionDetails.getPassword());\n\t\t\tString driverClassName = connectionDetails.getDriverClassName();\n\t\t\tif (StringUtils.hasText(driverClassName)) {\n\t\t\t\tbuilder.driverClassName(driverClassName);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@ConditionalOnClass(Customizer.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(Customizer.class)\n\t\tSpringLiquibaseCustomizer springLiquibaseCustomizer(Customizer<Liquibase> customizer) {\n\t\t\treturn (springLiquibase) -> springLiquibase.setCustomizer(customizer);\n\t\t}\n\n\t}\n\n\tstatic final class LiquibaseDataSourceCondition extends AnyNestedCondition {\n\n\t\tLiquibaseDataSourceCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnBean(DataSource.class)\n\t\tprivate static final class DataSourceBeanCondition {\n\n\t\t}\n\n\t\t@ConditionalOnBean(JdbcConnectionDetails.class)\n\t\tprivate static final class JdbcConnectionDetailsCondition {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.liquibase.url\")\n\t\tprivate static final class LiquibaseUrlCondition {\n\n\t\t}\n\n\t}\n\n\tstatic class LiquibaseAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources().registerPattern(\"db/changelog/**\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Adapts {@link LiquibaseProperties} to {@link LiquibaseConnectionDetails}.\n\t */\n\tstatic final class PropertiesLiquibaseConnectionDetails implements LiquibaseConnectionDetails {\n\n\t\tprivate final LiquibaseProperties properties;\n\n\t\tPropertiesLiquibaseConnectionDetails(LiquibaseProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.properties.getUser();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.properties.getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getJdbcUrl() {\n\t\t\treturn this.properties.getUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getDriverClassName() {\n\t\t\tString driverClassName = this.properties.getDriverClassName();\n\t\t\treturn (driverClassName != null) ? driverClassName : LiquibaseConnectionDetails.super.getDriverClassName();\n\t\t}\n\n\t}\n\n\t@FunctionalInterface\n\tinterface SpringLiquibaseCustomizer {\n\n\t\t/**\n\t\t * Customize the given {@link SpringLiquibase} instance.\n\t\t * @param springLiquibase the instance to configure\n\t\t */\n\t\tvoid customize(SpringLiquibase springLiquibase);\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.jdbc.DatabaseDriver;\n\n/**\n * Details required for Liquibase to establish a connection to an SQL service using JDBC.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface LiquibaseConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Username for the database or {@code null} if no Liquibase-specific configuration is\n\t * required.\n\t * @return the username for the database or {@code null}\n\t */\n\t@Nullable String getUsername();\n\n\t/**\n\t * Password for the database or {@code null} if no Liquibase-specific configuration is\n\t * required.\n\t * @return the password for the database or {@code null}\n\t */\n\t@Nullable String getPassword();\n\n\t/**\n\t * JDBC URL for the database or {@code null} if no Liquibase-specific configuration is\n\t * required.\n\t * @return the JDBC URL for the database or {@code null}\n\t */\n\t@Nullable String getJdbcUrl();\n\n\t/**\n\t * The name of the JDBC driver class. Defaults to the class name of the driver\n\t * specified in the JDBC URL or {@code null} when no JDBC URL is configured.\n\t * @return the JDBC driver class name or {@code null}\n\t * @see #getJdbcUrl()\n\t * @see DatabaseDriver#fromJdbcUrl(String)\n\t * @see DatabaseDriver#getDriverClassName()\n\t */\n\t@Nullable default String getDriverClassName() {\n\t\tString jdbcUrl = getJdbcUrl();\n\t\treturn (jdbcUrl != null) ? DatabaseDriver.fromJdbcUrl(jdbcUrl).getDriverClassName() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseDataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\n/**\n * Qualifier annotation for a DataSource to be injected into Liquibase. If used for a\n * second data source, the other (main) one would normally be marked as {@code @Primary}.\n *\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface LiquibaseDataSource {\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport liquibase.integration.spring.SpringLiquibase;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.liquibase.actuate.endpoint.LiquibaseEndpoint;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link LiquibaseEndpoint}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = LiquibaseAutoConfiguration.class)\n@ConditionalOnClass({ SpringLiquibase.class, LiquibaseEndpoint.class, ConditionalOnAvailableEndpoint.class })\n@ConditionalOnAvailableEndpoint(LiquibaseEndpoint.class)\npublic final class LiquibaseEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(SpringLiquibase.class)\n\t@ConditionalOnMissingBean\n\tLiquibaseEndpoint liquibaseEndpoint(ApplicationContext context) {\n\t\treturn new LiquibaseEndpoint(context);\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(SpringLiquibase.class)\n\tstatic BeanPostProcessor preventDataSourceCloseBeanPostProcessor() {\n\t\treturn new BeanPostProcessor() {\n\n\t\t\t@Override\n\t\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\t\t\tif (bean instanceof DataSourceClosingSpringLiquibase dataSource) {\n\t\t\t\t\tdataSource.setCloseDataSourceOnceMigrated(false);\n\t\t\t\t}\n\t\t\t\treturn bean;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\t\treturn bean;\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Map;\n\nimport liquibase.UpdateSummaryEnum;\nimport liquibase.UpdateSummaryOutputEnum;\nimport liquibase.integration.spring.SpringLiquibase;\nimport liquibase.ui.UIServiceEnum;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration properties to configure {@link SpringLiquibase}.\n *\n * @author Marcel Overdijk\n * @author Eddú Meléndez\n * @author Ferenc Gratzer\n * @author Evgeniy Cheban\n * @since 4.0.0\n */\n@ConfigurationProperties(prefix = \"spring.liquibase\", ignoreUnknownFields = false)\npublic class LiquibaseProperties {\n\n\t/**\n\t * Change log configuration path.\n\t */\n\tprivate String changeLog = \"classpath:/db/changelog/db.changelog-master.yaml\";\n\n\t/**\n\t * Whether to clear all checksums in the current changelog, so they will be\n\t * recalculated upon the next update.\n\t */\n\tprivate boolean clearChecksums;\n\n\t/**\n\t * List of runtime contexts to use.\n\t */\n\tprivate @Nullable List<String> contexts;\n\n\t/**\n\t * Default database schema.\n\t */\n\tprivate @Nullable String defaultSchema;\n\n\t/**\n\t * Schema to use for Liquibase objects.\n\t */\n\tprivate @Nullable String liquibaseSchema;\n\n\t/**\n\t * Tablespace to use for Liquibase objects.\n\t */\n\tprivate @Nullable String liquibaseTablespace;\n\n\t/**\n\t * Name of table to use for tracking change history.\n\t */\n\tprivate String databaseChangeLogTable = \"DATABASECHANGELOG\";\n\n\t/**\n\t * Name of table to use for tracking concurrent Liquibase usage.\n\t */\n\tprivate String databaseChangeLogLockTable = \"DATABASECHANGELOGLOCK\";\n\n\t/**\n\t * Whether to first drop the database schema.\n\t */\n\tprivate boolean dropFirst;\n\n\t/**\n\t * Whether to enable Liquibase support.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Login user of the database to migrate.\n\t */\n\tprivate @Nullable String user;\n\n\t/**\n\t * Login password of the database to migrate.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.\n\t */\n\tprivate @Nullable String driverClassName;\n\n\t/**\n\t * JDBC URL of the database to migrate. If not set, the primary configured data source\n\t * is used.\n\t */\n\tprivate @Nullable String url;\n\n\t/**\n\t * List of runtime labels to use.\n\t */\n\tprivate @Nullable List<String> labelFilter;\n\n\t/**\n\t * Change log parameters.\n\t */\n\tprivate @Nullable Map<String, String> parameters;\n\n\t/**\n\t * File to which rollback SQL is written when an update is performed.\n\t */\n\tprivate @Nullable File rollbackFile;\n\n\t/**\n\t * Whether rollback should be tested before update is performed.\n\t */\n\tprivate boolean testRollbackOnUpdate;\n\n\t/**\n\t * Tag name to use when applying database changes. Can also be used with\n\t * \"rollbackFile\" to generate a rollback script for all existing changes associated\n\t * with that tag.\n\t */\n\tprivate @Nullable String tag;\n\n\t/**\n\t * Whether to print a summary of the update operation.\n\t */\n\tprivate @Nullable ShowSummary showSummary;\n\n\t/**\n\t * Where to print a summary of the update operation.\n\t */\n\tprivate @Nullable ShowSummaryOutput showSummaryOutput;\n\n\t/**\n\t * Which UIService to use.\n\t */\n\tprivate @Nullable UiService uiService;\n\n\t/**\n\t * Whether to send product usage data and analytics to Liquibase.\n\t */\n\tprivate @Nullable Boolean analyticsEnabled;\n\n\t/**\n\t * Liquibase Pro license key.\n\t */\n\tprivate @Nullable String licenseKey;\n\n\tpublic String getChangeLog() {\n\t\treturn this.changeLog;\n\t}\n\n\tpublic void setChangeLog(String changeLog) {\n\t\tAssert.notNull(changeLog, \"'changeLog' must not be null\");\n\t\tthis.changeLog = changeLog;\n\t}\n\n\tpublic @Nullable List<String> getContexts() {\n\t\treturn this.contexts;\n\t}\n\n\tpublic void setContexts(@Nullable List<String> contexts) {\n\t\tthis.contexts = contexts;\n\t}\n\n\tpublic @Nullable String getDefaultSchema() {\n\t\treturn this.defaultSchema;\n\t}\n\n\tpublic void setDefaultSchema(@Nullable String defaultSchema) {\n\t\tthis.defaultSchema = defaultSchema;\n\t}\n\n\tpublic @Nullable String getLiquibaseSchema() {\n\t\treturn this.liquibaseSchema;\n\t}\n\n\tpublic void setLiquibaseSchema(@Nullable String liquibaseSchema) {\n\t\tthis.liquibaseSchema = liquibaseSchema;\n\t}\n\n\tpublic @Nullable String getLiquibaseTablespace() {\n\t\treturn this.liquibaseTablespace;\n\t}\n\n\tpublic void setLiquibaseTablespace(@Nullable String liquibaseTablespace) {\n\t\tthis.liquibaseTablespace = liquibaseTablespace;\n\t}\n\n\tpublic String getDatabaseChangeLogTable() {\n\t\treturn this.databaseChangeLogTable;\n\t}\n\n\tpublic void setDatabaseChangeLogTable(String databaseChangeLogTable) {\n\t\tthis.databaseChangeLogTable = databaseChangeLogTable;\n\t}\n\n\tpublic String getDatabaseChangeLogLockTable() {\n\t\treturn this.databaseChangeLogLockTable;\n\t}\n\n\tpublic void setDatabaseChangeLogLockTable(String databaseChangeLogLockTable) {\n\t\tthis.databaseChangeLogLockTable = databaseChangeLogLockTable;\n\t}\n\n\tpublic boolean isDropFirst() {\n\t\treturn this.dropFirst;\n\t}\n\n\tpublic void setDropFirst(boolean dropFirst) {\n\t\tthis.dropFirst = dropFirst;\n\t}\n\n\tpublic boolean isClearChecksums() {\n\t\treturn this.clearChecksums;\n\t}\n\n\tpublic void setClearChecksums(boolean clearChecksums) {\n\t\tthis.clearChecksums = clearChecksums;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic @Nullable String getUser() {\n\t\treturn this.user;\n\t}\n\n\tpublic void setUser(@Nullable String user) {\n\t\tthis.user = user;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable String getDriverClassName() {\n\t\treturn this.driverClassName;\n\t}\n\n\tpublic void setDriverClassName(@Nullable String driverClassName) {\n\t\tthis.driverClassName = driverClassName;\n\t}\n\n\tpublic @Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\tpublic void setUrl(@Nullable String url) {\n\t\tthis.url = url;\n\t}\n\n\tpublic @Nullable List<String> getLabelFilter() {\n\t\treturn this.labelFilter;\n\t}\n\n\tpublic void setLabelFilter(@Nullable List<String> labelFilter) {\n\t\tthis.labelFilter = labelFilter;\n\t}\n\n\tpublic @Nullable Map<String, String> getParameters() {\n\t\treturn this.parameters;\n\t}\n\n\tpublic void setParameters(@Nullable Map<String, String> parameters) {\n\t\tthis.parameters = parameters;\n\t}\n\n\tpublic @Nullable File getRollbackFile() {\n\t\treturn this.rollbackFile;\n\t}\n\n\tpublic void setRollbackFile(@Nullable File rollbackFile) {\n\t\tthis.rollbackFile = rollbackFile;\n\t}\n\n\tpublic boolean isTestRollbackOnUpdate() {\n\t\treturn this.testRollbackOnUpdate;\n\t}\n\n\tpublic void setTestRollbackOnUpdate(boolean testRollbackOnUpdate) {\n\t\tthis.testRollbackOnUpdate = testRollbackOnUpdate;\n\t}\n\n\tpublic @Nullable String getTag() {\n\t\treturn this.tag;\n\t}\n\n\tpublic void setTag(@Nullable String tag) {\n\t\tthis.tag = tag;\n\t}\n\n\tpublic @Nullable ShowSummary getShowSummary() {\n\t\treturn this.showSummary;\n\t}\n\n\tpublic void setShowSummary(@Nullable ShowSummary showSummary) {\n\t\tthis.showSummary = showSummary;\n\t}\n\n\tpublic @Nullable ShowSummaryOutput getShowSummaryOutput() {\n\t\treturn this.showSummaryOutput;\n\t}\n\n\tpublic void setShowSummaryOutput(@Nullable ShowSummaryOutput showSummaryOutput) {\n\t\tthis.showSummaryOutput = showSummaryOutput;\n\t}\n\n\tpublic @Nullable UiService getUiService() {\n\t\treturn this.uiService;\n\t}\n\n\tpublic void setUiService(@Nullable UiService uiService) {\n\t\tthis.uiService = uiService;\n\t}\n\n\tpublic @Nullable Boolean getAnalyticsEnabled() {\n\t\treturn this.analyticsEnabled;\n\t}\n\n\tpublic void setAnalyticsEnabled(@Nullable Boolean analyticsEnabled) {\n\t\tthis.analyticsEnabled = analyticsEnabled;\n\t}\n\n\tpublic @Nullable String getLicenseKey() {\n\t\treturn this.licenseKey;\n\t}\n\n\tpublic void setLicenseKey(@Nullable String licenseKey) {\n\t\tthis.licenseKey = licenseKey;\n\t}\n\n\t/**\n\t * Enumeration of types of summary to show. Values are the same as those on\n\t * {@link UpdateSummaryEnum}. To maximize backwards compatibility, the Liquibase enum\n\t * is not used directly.\n\t */\n\tpublic enum ShowSummary {\n\n\t\t/**\n\t\t * Do not show a summary.\n\t\t */\n\t\tOFF,\n\n\t\t/**\n\t\t * Show a summary.\n\t\t */\n\t\tSUMMARY,\n\n\t\t/**\n\t\t * Show a verbose summary.\n\t\t */\n\t\tVERBOSE\n\n\t}\n\n\t/**\n\t * Enumeration of destinations to which the summary should be output. Values are the\n\t * same as those on {@link UpdateSummaryOutputEnum}. To maximize backwards\n\t * compatibility, the Liquibase enum is not used directly.\n\t */\n\tpublic enum ShowSummaryOutput {\n\n\t\t/**\n\t\t * Log the summary.\n\t\t */\n\t\tLOG,\n\n\t\t/**\n\t\t * Output the summary to the console.\n\t\t */\n\t\tCONSOLE,\n\n\t\t/**\n\t\t * Log the summary and output it to the console.\n\t\t */\n\t\tALL\n\n\t}\n\n\t/**\n\t * Enumeration of types of UIService. Values are the same as those on\n\t * {@link UIServiceEnum}. To maximize backwards compatibility, the Liquibase enum is\n\t * not used directly.\n\t */\n\tpublic enum UiService {\n\n\t\t/**\n\t\t * Console-based UIService.\n\t\t */\n\t\tCONSOLE,\n\n\t\t/**\n\t\t * Logging-based UIService.\n\t\t */\n\t\tLOGGER\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseSchemaManagementProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.util.stream.StreamSupport;\n\nimport javax.sql.DataSource;\n\nimport liquibase.integration.spring.SpringLiquibase;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.jdbc.SchemaManagement;\nimport org.springframework.boot.jdbc.SchemaManagementProvider;\n\n/**\n * A Liquibase {@link SchemaManagementProvider} that determines if the schema is managed\n * by looking at available {@link SpringLiquibase} instances.\n *\n * @author Stephane Nicoll\n */\nclass LiquibaseSchemaManagementProvider implements SchemaManagementProvider {\n\n\tprivate final Iterable<SpringLiquibase> liquibaseInstances;\n\n\tLiquibaseSchemaManagementProvider(ObjectProvider<SpringLiquibase> liquibases) {\n\t\tthis.liquibaseInstances = liquibases;\n\t}\n\n\t@Override\n\tpublic SchemaManagement getSchemaManagement(DataSource dataSource) {\n\t\treturn StreamSupport.stream(this.liquibaseInstances.spliterator(), false)\n\t\t\t.map(SpringLiquibase::getDataSource)\n\t\t\t.filter(dataSource::equals)\n\t\t\t.findFirst()\n\t\t\t.map((managedDataSource) -> SchemaManagement.MANAGED)\n\t\t\t.orElse(SchemaManagement.UNMANAGED);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Liquibase.\n */\n@NullMarked\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/docker/compose/JdbcAdaptingLiquibaseConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseConnectionDetails;\n\n/**\n * {@link ConnectionDetailsFactory} that produces {@link LiquibaseConnectionDetails} by\n * adapting {@link JdbcConnectionDetails}.\n *\n * @author Andy Wilkinson\n */\nclass JdbcAdaptingLiquibaseConnectionDetailsFactory\n\t\timplements ConnectionDetailsFactory<JdbcConnectionDetails, LiquibaseConnectionDetails> {\n\n\t@Override\n\tpublic LiquibaseConnectionDetails getConnectionDetails(JdbcConnectionDetails input) {\n\t\treturn new LiquibaseConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getUsername() {\n\t\t\t\treturn input.getUsername();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String getPassword() {\n\t\t\t\treturn input.getPassword();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getJdbcUrl() {\n\t\t\t\treturn input.getJdbcUrl();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getDriverClassName() {\n\t\t\t\treturn input.getDriverClassName();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Liquibase service connections.\n */\n@NullMarked\npackage org.springframework.boot.liquibase.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom support for Liquibase database migration.\n */\n@NullMarked\npackage org.springframework.boot.liquibase;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/testcontainers/LiquibaseContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.testcontainers;\n\nimport org.testcontainers.containers.JdbcDatabaseContainer;\n\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link LiquibaseConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link JdbcDatabaseContainer}.\n *\n * @author Andy Wilkinson\n */\nclass LiquibaseContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<JdbcDatabaseContainer<?>, LiquibaseConnectionDetails> {\n\n\t@Override\n\tprotected LiquibaseConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\treturn new LiquibaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link LiquibaseConnectionDetails} backed by a {@link JdbcDatabaseContainer}.\n\t */\n\tprivate static final class LiquibaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<JdbcDatabaseContainer<?>> implements LiquibaseConnectionDetails {\n\n\t\tprivate LiquibaseContainerConnectionDetails(ContainerConnectionSource<JdbcDatabaseContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUsername() {\n\t\t\treturn getContainer().getUsername();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPassword() {\n\t\t\treturn getContainer().getPassword();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getJdbcUrl() {\n\t\t\treturn getContainer().getJdbcUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getDriverClassName() {\n\t\t\treturn getContainer().getDriverClassName();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/java/org/springframework/boot/liquibase/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Liquibase service connections.\n */\n@NullMarked\npackage org.springframework.boot.liquibase.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.liquibase.check-change-log-location\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Check the change log location exists.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"reason\": \"Liquibase has its own check that checks if the change log location exists making this property redundant.\",\n        \"level\": \"error\",\n        \"since\": \"2.1.7\"\n      }\n    },\n    {\n      \"name\": \"spring.liquibase.labels\",\n      \"deprecation\": {\n        \"replacement\": \"spring.liquibase.label-filter\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.liquibase.show-summary\",\n      \"defaultValue\": \"summary\"\n    },\n    {\n      \"name\": \"spring.liquibase.show-summary-output\",\n      \"defaultValue\": \"log\"\n    },\n    {\n      \"name\": \"spring.liquibase.ui-service\",\n      \"defaultValue\": \"logger\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.liquibase.change-log\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"org.springframework.core.io.Resource\"\n          }\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration\norg.springframework.boot.liquibase.autoconfigure.LiquibaseEndpointAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/resources/META-INF/spring/org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization.imports",
    "content": "org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.liquibase.docker.compose.JdbcAdaptingLiquibaseConnectionDetailsFactory,\\\norg.springframework.boot.liquibase.testcontainers.LiquibaseContainerConnectionDetailsFactory\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.liquibase.LiquibaseChangelogMissingFailureAnalyzer\n\n# Database Initializer Detectors\norg.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\\\norg.springframework.boot.liquibase.LiquibaseDatabaseInitializerDetector\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/LiquibaseChangelogMissingFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport liquibase.integration.spring.SpringLiquibase;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LiquibaseChangelogMissingFailureAnalyzer}\n *\n * @author Sebastiaan Fernandez\n */\nclass LiquibaseChangelogMissingFailureAnalyzerTests {\n\n\t@Test\n\tvoid changelogParseExceptionDueToChangelogNotPresent() {\n\t\tFailureAnalysis analysis = performAnalysis();\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription())\n\t\t\t.isEqualTo(\"Liquibase failed to start because no changelog could be found at '\"\n\t\t\t\t\t+ \"classpath:/db/changelog/db.changelog-master.yaml'.\");\n\t\tassertThat(analysis.getAction())\n\t\t\t.isEqualTo(\"Make sure a Liquibase changelog is present at the configured path.\");\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis() {\n\t\tBeanCreationException failure = createFailure();\n\t\tassertThat(failure).isNotNull();\n\t\treturn new LiquibaseChangelogMissingFailureAnalyzer().analyze(failure);\n\t}\n\n\tprivate @Nullable BeanCreationException createFailure() {\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(\n\t\t\t\tLiquibaseConfiguration.class)) {\n\t\t\treturn null;\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LiquibaseConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\t\tdataSource.setJdbcUrl(\"jdbc:h2:mem:test\");\n\t\t\tdataSource.setUsername(\"sa\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tSpringLiquibase springLiquibase(DataSource dataSource) {\n\t\t\tSpringLiquibase liquibase = new SpringLiquibase();\n\t\t\tliquibase.setChangeLog(\"classpath:/db/changelog/db.changelog-master.yaml\");\n\t\t\tliquibase.setDataSource(dataSource);\n\t\t\treturn liquibase;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/actuate/endpoint/LiquibaseEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.actuate.endpoint;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport liquibase.integration.spring.SpringLiquibase;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.liquibase.actuate.endpoint.LiquibaseEndpoint.ContextLiquibaseBeansDescriptor;\nimport org.springframework.boot.liquibase.actuate.endpoint.LiquibaseEndpoint.LiquibaseBeanDescriptor;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LiquibaseEndpoint}.\n *\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Leo Li\n */\n@WithResource(name = \"db/changelog/db.changelog-master.yaml\", content = \"\"\"\n\t\tdatabaseChangeLog:\n\t\t  - changeSet:\n\t\t      id: 1\n\t\t      author: test\n\t\t\"\"\")\nclass LiquibaseEndpointTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, LiquibaseAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid liquibaseReportIsReturned() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).run(hasEndpointWithInitializedSchema());\n\t}\n\n\t@Test\n\tvoid liquibaseReportIsReturnedForContextHierarchy() {\n\t\tthis.contextRunner.withUserConfiguration().run((parent) -> {\n\t\t\tthis.contextRunner.withUserConfiguration(Config.class).withParent(parent).run((context) -> {\n\t\t\t\tMap<@Nullable String, ContextLiquibaseBeansDescriptor> contexts = context\n\t\t\t\t\t.getBean(LiquibaseEndpoint.class)\n\t\t\t\t\t.liquibaseBeans()\n\t\t\t\t\t.getContexts();\n\t\t\t\tContextLiquibaseBeansDescriptor parentContext = contexts.get(parent.getId());\n\t\t\t\tassertThat(parentContext).isNotNull();\n\t\t\t\tMap<String, LiquibaseBeanDescriptor> liquibaseBeans = parentContext.getLiquibaseBeans();\n\t\t\t\tassertThat(liquibaseBeans).hasEntrySatisfying(\"liquibase\",\n\t\t\t\t\t\t(descriptor) -> assertThat(descriptor.getChangeSets()).hasSize(1));\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/create-custom-schema.sql\", content = \"CREATE SCHEMA ANOTHER_SCHEMA;\")\n\tvoid invokeWithCustomDefaultSchemaFailsIfItDoesNotExist() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class, DataSourceWithSchemaConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.default-schema=CUSTOM_DEFAULT_SCHEMA\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"CUSTOM_DEFAULT_SCHEMA\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/create-custom-schema.sql\", content = \"CREATE SCHEMA CUSTOM_SCHEMA;\")\n\tvoid invokeWithCustomDefaultSchema() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class, DataSourceWithSchemaConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.default-schema=CUSTOM_SCHEMA\")\n\t\t\t.run(hasEndpointWithInitializedSchema());\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/create-custom-schema.sql\", content = \"CREATE SCHEMA ANOTHER_SCHEMA;\")\n\tvoid invokeWithLiquibaseSchemaFailsIfItDoesNotExist() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class, DataSourceWithSchemaConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.liquibase-schema=CUSTOM_LIQUIBASE_SCHEMA\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"CUSTOM_LIQUIBASE_SCHEMA\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/create-custom-schema.sql\", content = \"CREATE SCHEMA LIQUIBASE_SCHEMA;\")\n\tvoid invokeWithLiquibaseSchema() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class, DataSourceWithSchemaConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.liquibase-schema=LIQUIBASE_SCHEMA\")\n\t\t\t.run(hasEndpointWithInitializedSchema());\n\t}\n\n\t@Test\n\tvoid invokeWithCustomTables() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.database-change-log-lock-table=liquibase_database_changelog_lock\",\n\t\t\t\t\t\"spring.liquibase.database-change-log-table=liquibase_database_changelog\")\n\t\t\t.run(hasEndpointWithInitializedSchema());\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> hasEndpointWithInitializedSchema() {\n\t\treturn (context) -> {\n\t\t\tContextLiquibaseBeansDescriptor contextDescriptor = context.getBean(LiquibaseEndpoint.class)\n\t\t\t\t.liquibaseBeans()\n\t\t\t\t.getContexts()\n\t\t\t\t.get(context.getId());\n\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\tMap<String, LiquibaseBeanDescriptor> liquibaseBeans = contextDescriptor.getLiquibaseBeans();\n\t\t\tassertThat(liquibaseBeans).hasEntrySatisfying(\"liquibase\",\n\t\t\t\t\t(descriptor) -> assertThat(descriptor.getChangeSets()).hasSize(1));\n\t\t};\n\t}\n\n\t@Test\n\tvoid connectionAutoCommitPropertyIsReset() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class).run((context) -> {\n\t\t\tDataSource dataSource = context.getBean(DataSource.class);\n\t\t\tassertThat(getAutoCommit(dataSource)).isTrue();\n\t\t\tcontext.getBean(LiquibaseEndpoint.class).liquibaseBeans();\n\t\t\tassertThat(getAutoCommit(dataSource)).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-master-backup.yaml\", content = \"\"\"\n\t\t\tdatabaseChangeLog:\n\t\t\t  - changeSet:\n\t\t\t      id: 1\n\t\t\t      author: test\n\t\t\t\"\"\")\n\tvoid whenMultipleLiquibaseBeansArePresentChangeSetsAreCorrectlyReportedForEachBean() {\n\t\tthis.contextRunner.withUserConfiguration(Config.class, MultipleDataSourceLiquibaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tContextLiquibaseBeansDescriptor contextDescriptor = context.getBean(LiquibaseEndpoint.class)\n\t\t\t\t\t.liquibaseBeans()\n\t\t\t\t\t.getContexts()\n\t\t\t\t\t.get(context.getId());\n\t\t\t\tassertThat(contextDescriptor).isNotNull();\n\t\t\t\tMap<String, LiquibaseBeanDescriptor> liquibaseBeans = contextDescriptor.getLiquibaseBeans();\n\t\t\t\tassertThat(liquibaseBeans).hasEntrySatisfying(\"liquibase\", (liquibase) -> {\n\t\t\t\t\tassertThat(liquibase.getChangeSets()).hasSize(1);\n\t\t\t\t\tassertThat(liquibase.getChangeSets().get(0).getChangeLog())\n\t\t\t\t\t\t.isEqualTo(\"db/changelog/db.changelog-master.yaml\");\n\t\t\t\t});\n\t\t\t\tassertThat(liquibaseBeans).hasEntrySatisfying(\"liquibaseBackup\", (liquibase) -> {\n\t\t\t\t\tassertThat(liquibase.getChangeSets()).hasSize(1);\n\t\t\t\t\tassertThat(liquibase.getChangeSets().get(0).getChangeLog())\n\t\t\t\t\t\t.isEqualTo(\"db/changelog/db.changelog-master-backup.yaml\");\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\tprivate boolean getAutoCommit(DataSource dataSource) throws SQLException {\n\t\ttry (Connection connection = dataSource.getConnection()) {\n\t\t\treturn connection.getAutoCommit();\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tLiquibaseEndpoint endpoint(ApplicationContext context) {\n\t\t\treturn new LiquibaseEndpoint(context);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceWithSchemaConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tDataSource dataSource = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.setName(UUID.randomUUID().toString())\n\t\t\t\t.build();\n\t\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\t\tsettings.setSchemaLocations(List.of(\"classpath:/db/create-custom-schema.sql\"));\n\t\t\tDataSourceScriptDatabaseInitializer initializer = new DataSourceScriptDatabaseInitializer(dataSource,\n\t\t\t\t\tsettings);\n\t\t\tinitializer.initializeDatabase();\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleDataSourceLiquibaseConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn createEmbeddedDatabase();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource dataSourceBackup() {\n\t\t\treturn createEmbeddedDatabase();\n\t\t}\n\n\t\t@Bean\n\t\tSpringLiquibase liquibase(DataSource dataSource) {\n\t\t\treturn createSpringLiquibase(\"db.changelog-master.yaml\", dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tSpringLiquibase liquibaseBackup(DataSource dataSourceBackup) {\n\t\t\treturn createSpringLiquibase(\"db.changelog-master-backup.yaml\", dataSourceBackup);\n\t\t}\n\n\t\tprivate DataSource createEmbeddedDatabase() {\n\t\t\treturn new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t\tprivate SpringLiquibase createSpringLiquibase(String changeLog, DataSource dataSource) {\n\t\t\tSpringLiquibase liquibase = new SpringLiquibase();\n\t\t\tliquibase.setChangeLog(\"classpath:/db/changelog/\" + changeLog);\n\t\t\tliquibase.setShouldRun(true);\n\t\t\tliquibase.setDataSource(dataSource);\n\t\t\treturn liquibase;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/autoconfigure/Liquibase423AutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport liquibase.integration.spring.SpringLiquibase;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LiquibaseAutoConfiguration} with Liquibase 4.23.\n *\n * @author Andy Wilkinson\n */\n@ClassPathOverrides(\"org.liquibase:liquibase-core:4.23.1\")\nclass Liquibase423AutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-master.yaml\", content = \"databaseChangeLog:\")\n\tvoid defaultSpringLiquibase() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tassertThat(liquibase.getChangeLog()).isEqualTo(\"classpath:/db/changelog/db.changelog-master.yaml\");\n\t\t\t\tassertThat(liquibase.getContexts()).isNull();\n\t\t\t\tassertThat(liquibase.getDefaultSchema()).isNull();\n\t\t\t\tassertThat(liquibase.isDropFirst()).isFalse();\n\t\t\t\tassertThat(liquibase.isClearCheckSums()).isFalse();\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertLiquibase(Consumer<SpringLiquibase> consumer) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpringLiquibase.class);\n\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\tconsumer.accept(liquibase);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.sql.Connection;\nimport java.sql.Driver;\nimport java.sql.SQLException;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport liquibase.Liquibase;\nimport liquibase.UpdateSummaryEnum;\nimport liquibase.UpdateSummaryOutputEnum;\nimport liquibase.command.core.helpers.ShowSummaryArgument;\nimport liquibase.integration.spring.Customizer;\nimport liquibase.integration.spring.SpringLiquibase;\nimport liquibase.ui.UIServiceEnum;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration.LiquibaseAutoConfigurationRuntimeHints;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\n\n/**\n * Tests for {@link LiquibaseAutoConfiguration}.\n *\n * @author Marcel Overdijk\n * @author Eddú Meléndez\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Dominic Gunn\n * @author András Deák\n * @author Andrii Hrytsiuk\n * @author Ferenc Gratzer\n * @author Evgeniy Cheban\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @author Ahmed Ashour\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass LiquibaseAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\n\t@Test\n\tvoid backsOffWithNoDataSourceBeanAndNoLiquibaseUrl() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(SpringLiquibase.class));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid createsDataSourceWithNoDataSourceBeanAndLiquibaseUrl() {\n\t\tString jdbcUrl = \"jdbc:h2:mem:liquibase\" + UUID.randomUUID();\n\t\tthis.contextRunner.withPropertyValues(\"spring.liquibase.url:\" + jdbcUrl).run(assertLiquibase((liquibase) -> {\n\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\tassertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid backsOffWithLiquibaseUrlAndNoSpringJdbc() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.liquibase.url:jdbc:h2:mem:\" + UUID.randomUUID())\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.jdbc\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringLiquibase.class));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid defaultSpringLiquibase() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tassertThat(liquibase.getChangeLog()).isEqualTo(\"classpath:/db/changelog/db.changelog-master.yaml\");\n\t\t\t\tassertThat(liquibase.getContexts()).isNull();\n\t\t\t\tassertThat(liquibase.getDefaultSchema()).isNull();\n\t\t\t\tassertThat(liquibase.isDropFirst()).isFalse();\n\t\t\t\tassertThat(liquibase.isClearCheckSums()).isFalse();\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid shouldUseMainDataSourceWhenThereIsNoLiquibaseSpecificConfiguration() {\n\t\tthis.contextRunner.withSystemProperties(\"shouldRun=false\")\n\t\t\t.withUserConfiguration(EmbeddedDataSourceConfiguration.class, JdbcConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\t\tassertThat(liquibase.getDataSource()).isSameAs(context.getBean(DataSource.class));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid liquibaseDataSourceIsUsedOverJdbcConnectionDetails() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(LiquibaseDataSourceConfiguration.class, JdbcConnectionDetailsConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tHikariDataSource dataSource = (HikariDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getJdbcUrl()).startsWith(\"jdbc:h2:mem:liquibasetest\");\n\t\t\t\tassertThat(dataSource.getUsername()).isEqualTo(\"sa\");\n\t\t\t\tassertThat(dataSource.getPassword()).isNull();\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid liquibaseDataSourceIsUsedOverLiquibaseConnectionDetails() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(LiquibaseDataSourceConfiguration.class,\n\t\t\t\t\tLiquibaseConnectionDetailsConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tHikariDataSource dataSource = (HikariDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getJdbcUrl()).startsWith(\"jdbc:h2:mem:liquibasetest\");\n\t\t\t\tassertThat(dataSource.getUsername()).isEqualTo(\"sa\");\n\t\t\t\tassertThat(dataSource.getPassword()).isNull();\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid liquibasePropertiesAreUsedOverJdbcConnectionDetails() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.liquibase.url=jdbc:h2:mem:liquibasetest\", \"spring.liquibase.user=some-user\",\n\t\t\t\t\t\"spring.liquibase.password=some-password\", \"spring.liquibase.driver-class-name=org.h2.Driver\")\n\t\t\t.withUserConfiguration(JdbcConnectionDetailsConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).startsWith(\"jdbc:h2:mem:liquibasetest\");\n\t\t\t\tassertThat(dataSource.getUsername()).isEqualTo(\"some-user\");\n\t\t\t\tassertThat(dataSource.getPassword()).isEqualTo(\"some-password\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid liquibaseConnectionDetailsAreUsedOverLiquibaseProperties() {\n\t\tthis.contextRunner.withSystemProperties(\"shouldRun=false\")\n\t\t\t.withPropertyValues(\"spring.liquibase.url=jdbc:h2:mem:liquibasetest\", \"spring.liquibase.user=some-user\",\n\t\t\t\t\t\"spring.liquibase.password=some-password\", \"spring.liquibase.driver-class-name=org.h2.Driver\")\n\t\t\t.withUserConfiguration(LiquibaseConnectionDetailsConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).isEqualTo(\"jdbc:postgresql://database.example.com:12345/database-1\");\n\t\t\t\tassertThat(dataSource.getUsername()).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(dataSource.getPassword()).isEqualTo(\"secret-1\");\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-override.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<databaseChangeLog\n\t\t\t\t\t        xmlns=\"http://www.liquibase.org/xml/ns/dbchangelog\"\n\t\t\t\t\t        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t\t        xmlns:ext=\"http://www.liquibase.org/xml/ns/dbchangelog-ext\"\n\t\t\t\t\t        xsi:schemaLocation=\"http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd\n\t\t\t\t\t        http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd\">\n\n\t\t\t\t\t</databaseChangeLog>\n\t\t\t\t\t\"\"\")\n\tvoid changelogXml() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.change-log:classpath:/db/changelog/db.changelog-override.xml\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getChangeLog())\n\t\t\t\t.isEqualTo(\"classpath:/db/changelog/db.changelog-override.xml\")));\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-override.json\", content = \"\"\"\n\t\t\t{\n\t\t\t    \"databaseChangeLog\": []\n\t\t\t}\n\t\t\t\"\"\")\n\tvoid changelogJson() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.change-log:classpath:/db/changelog/db.changelog-override.json\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getChangeLog())\n\t\t\t\t.isEqualTo(\"classpath:/db/changelog/db.changelog-override.json\")));\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-override.sql\", content = \"\"\"\n\t\t\t--liquibase formatted sql\n\n\t\t\t--changeset author:awilkinson\n\n\t\t\tCREATE TABLE customer (\n\t\t\t    id int AUTO_INCREMENT NOT NULL PRIMARY KEY,\n\t\t\t    name varchar(50) NOT NULL\n\t\t\t);\n\t\t\t\"\"\")\n\tvoid changelogSql() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.change-log:classpath:/db/changelog/db.changelog-override.sql\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getChangeLog())\n\t\t\t\t.isEqualTo(\"classpath:/db/changelog/db.changelog-override.sql\")));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid defaultValues() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tLiquibaseProperties properties = new LiquibaseProperties();\n\t\t\t\tassertThat(liquibase.getDatabaseChangeLogTable()).isEqualTo(properties.getDatabaseChangeLogTable());\n\t\t\t\tassertThat(liquibase.getDatabaseChangeLogLockTable())\n\t\t\t\t\t.isEqualTo(properties.getDatabaseChangeLogLockTable());\n\t\t\t\tassertThat(liquibase.isDropFirst()).isEqualTo(properties.isDropFirst());\n\t\t\t\tassertThat(liquibase.isClearCheckSums()).isEqualTo(properties.isClearChecksums());\n\t\t\t\tassertThat(liquibase.isTestRollbackOnUpdate()).isEqualTo(properties.isTestRollbackOnUpdate());\n\t\t\t\tassertThat(liquibase).extracting(\"showSummary\").isNull();\n\t\t\t\tassertThat(ShowSummaryArgument.SHOW_SUMMARY.getDefaultValue()).isEqualTo(UpdateSummaryEnum.SUMMARY);\n\t\t\t\tassertThat(liquibase).extracting(\"showSummaryOutput\").isEqualTo(UpdateSummaryOutputEnum.LOG);\n\t\t\t\tassertThat(liquibase).extracting(\"uiService\").isEqualTo(UIServiceEnum.LOGGER);\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideContexts() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.contexts:test, production\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getContexts()).isEqualTo(\"test,production\")));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideDefaultSchema() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.default-schema:public\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getDefaultSchema()).isEqualTo(\"public\")));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideLiquibaseInfrastructure() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.liquibase-schema:public\",\n\t\t\t\t\t\"spring.liquibase.liquibase-tablespace:infra\",\n\t\t\t\t\t\"spring.liquibase.database-change-log-table:LIQUI_LOG\",\n\t\t\t\t\t\"spring.liquibase.database-change-log-lock-table:LIQUI_LOCK\")\n\t\t\t.run((context) -> {\n\t\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\t\tassertThat(liquibase.getLiquibaseSchema()).isEqualTo(\"public\");\n\t\t\t\tassertThat(liquibase.getLiquibaseTablespace()).isEqualTo(\"infra\");\n\t\t\t\tassertThat(liquibase.getDatabaseChangeLogTable()).isEqualTo(\"LIQUI_LOG\");\n\t\t\t\tassertThat(liquibase.getDatabaseChangeLogLockTable()).isEqualTo(\"LIQUI_LOCK\");\n\t\t\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(DataSource.class));\n\t\t\t\tassertThat(jdbcTemplate.queryForObject(\"SELECT COUNT(*) FROM public.LIQUI_LOG\", Integer.class)).isOne();\n\t\t\t\tassertThat(jdbcTemplate.queryForObject(\"SELECT COUNT(*) FROM public.LIQUI_LOCK\", Integer.class))\n\t\t\t\t\t.isOne();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideDropFirst() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.drop-first:true\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.isDropFirst()).isTrue()));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideClearChecksums() {\n\t\tString jdbcUrl = \"jdbc:h2:mem:liquibase\" + UUID.randomUUID();\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.url:\" + jdbcUrl)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.clear-checksums:true\", \"spring.liquibase.url:\" + jdbcUrl)\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.isClearCheckSums()).isTrue()));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideDataSource() {\n\t\tString jdbcUrl = \"jdbc:h2:mem:liquibase\" + UUID.randomUUID();\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.url:\" + jdbcUrl)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);\n\t\t\t\tDriver driver = dataSource.getDriver();\n\t\t\t\tassertThat(driver).isNotNull();\n\t\t\t\tassertThat(driver.getClass().getName()).isEqualTo(\"org.h2.Driver\");\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideDataSourceAndDriverClassName() {\n\t\tString jdbcUrl = \"jdbc:h2:mem:liquibase\" + UUID.randomUUID();\n\t\tString driverClassName = \"org.h2.Driver\";\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.url:\" + jdbcUrl,\n\t\t\t\t\t\"spring.liquibase.driver-class-name:\" + driverClassName)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).isEqualTo(jdbcUrl);\n\t\t\t\tDriver driver = dataSource.getDriver();\n\t\t\t\tassertThat(driver).isNotNull();\n\t\t\t\tassertThat(driver.getClass().getName()).isEqualTo(driverClassName);\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideUser() {\n\t\tString databaseName = \"normal\" + UUID.randomUUID();\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name:false\",\n\t\t\t\t\t\"spring.datasource.name:\" + databaseName, \"spring.datasource.username:not-sa\",\n\t\t\t\t\t\"spring.liquibase.user:sa\")\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).contains(\"jdbc:h2:mem:\" + databaseName);\n\t\t\t\tassertThat(dataSource.getUsername()).isEqualTo(\"sa\");\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideUserWhenCustom() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.user:test\", \"spring.liquibase.password:secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tString expectedName = context.getBean(CustomDataSourceConfiguration.class).name;\n\t\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).contains(expectedName);\n\t\t\t\tassertThat(dataSource.getUsername()).isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid createDataSourceDoesNotFallbackToEmbeddedProperties() {\n\t\tString jdbcUrl = \"jdbc:h2:mem:liquibase\" + UUID.randomUUID();\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.url:\" + jdbcUrl)\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUsername()).isNull();\n\t\t\t\tassertThat(dataSource.getPassword()).isNull();\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideUserAndFallbackToEmbeddedProperties() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.user:sa\")\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tSimpleDriverDataSource dataSource = (SimpleDriverDataSource) liquibase.getDataSource();\n\t\t\t\tassertThat(dataSource.getUrl()).startsWith(\"jdbc:h2:mem:\");\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideTestRollbackOnUpdate() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.test-rollback-on-update:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\t\tassertThat(liquibase.isTestRollbackOnUpdate()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid changeLogDoesNotExist() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.change-log:classpath:/no-such-changelog.yaml\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure().isInstanceOf(BeanCreationException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid logging(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(output).doesNotContain(\": liquibase:\")));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideLabelFilter() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.label-filter:test, production\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getLabelFilter()).isEqualTo(\"test,production\")));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideShowSummary() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.show-summary=off\")\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tUpdateSummaryEnum showSummary = (UpdateSummaryEnum) ReflectionTestUtils.getField(liquibase,\n\t\t\t\t\t\t\"showSummary\");\n\t\t\t\tassertThat(showSummary).isEqualTo(UpdateSummaryEnum.OFF);\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideShowSummaryOutput() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.show-summary-output=all\")\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tUpdateSummaryOutputEnum showSummaryOutput = (UpdateSummaryOutputEnum) ReflectionTestUtils\n\t\t\t\t\t.getField(liquibase, \"showSummaryOutput\");\n\t\t\t\tassertThat(showSummaryOutput).isEqualTo(UpdateSummaryOutputEnum.ALL);\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideUiService() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.ui-service=console\")\n\t\t\t.run(assertLiquibase(\n\t\t\t\t\t(liquibase) -> assertThat(liquibase).extracting(\"uiService\").isEqualTo(UIServiceEnum.CONSOLE)));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testOverrideParameters() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.parameters.foo:bar\")\n\t\t\t.run(assertLiquibase((liquibase) -> {\n\t\t\t\tMap<String, String> parameters = (Map<String, String>) ReflectionTestUtils.getField(liquibase,\n\t\t\t\t\t\t\"parameters\");\n\t\t\t\tassertThat(parameters).containsKey(\"foo\");\n\t\t\t\tassertThat(parameters).containsEntry(\"foo\", \"bar\");\n\t\t\t}));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid rollbackFile(@TempDir Path temp) throws IOException {\n\t\tFile file = Files.createTempFile(temp, \"rollback-file\", \"sql\").toFile();\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.rollback-file:\" + file.getAbsolutePath())\n\t\t\t.run((context) -> {\n\t\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\t\tFile actualFile = (File) ReflectionTestUtils.getField(liquibase, \"rollbackFile\");\n\t\t\t\tassertThat(actualFile).isEqualTo(file).exists();\n\t\t\t\tassertThat(contentOf(file)).contains(\"DROP TABLE PUBLIC.customer;\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid liquibaseDataSource() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(LiquibaseDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\t\tassertThat(liquibase.getDataSource()).isEqualTo(context.getBean(\"liquibaseDataSource\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid liquibaseDataSourceWithoutDataSourceAutoConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(LiquibaseDataSourceConfiguration.class).run((context) -> {\n\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\tassertThat(liquibase.getDataSource()).isEqualTo(context.getBean(\"liquibaseDataSource\"));\n\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid userConfigurationBeans() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(LiquibaseUserConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"springLiquibase\");\n\t\t\t\tassertThat(context).doesNotHaveBean(\"liquibase\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid userConfigurationJdbcTemplateDependency() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(JdbcTemplateAutoConfiguration.class))\n\t\t\t.withUserConfiguration(LiquibaseUserConfiguration.class, EmbeddedDataSourceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tBeanDefinition beanDefinition = context.getBeanFactory().getBeanDefinition(\"jdbcTemplate\");\n\t\t\t\tassertThat(beanDefinition.getDependsOn()).containsExactly(\"springLiquibase\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid overrideTag() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.tag:1.0.0\")\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getTag()).isEqualTo(\"1.0.0\")));\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew LiquibaseAutoConfigurationRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"db/changelog/\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"db/changelog/db.changelog-master.yaml\"))\n\t\t\t.accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"db/changelog/tables/init.sql\")).accepts(hints);\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid whenCustomizerBeanIsDefinedThenItIsConfiguredOnSpringLiquibase() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class, CustomizerConfiguration.class)\n\t\t\t.run(assertLiquibase((liquibase) -> assertThat(liquibase.getCustomizer()).isNotNull()));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid whenAnalyticsEnabledIsFalseThenSpringLiquibaseHasAnalyticsDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.analytics-enabled=false\")\n\t\t\t.run((context) -> assertThat(context.getBean(SpringLiquibase.class))\n\t\t\t\t.extracting(SpringLiquibase::getAnalyticsEnabled)\n\t\t\t\t.isEqualTo(Boolean.FALSE));\n\t}\n\n\t@Test\n\t@WithDbChangelogMasterYamlResource\n\tvoid whenLicenseKeyIsSetThenSpringLiquibaseHasLicenseKey() {\n\t\tthis.contextRunner.withUserConfiguration(EmbeddedDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.liquibase.license-key=a1b2c3d4\")\n\t\t\t.run((context) -> assertThat(context.getBean(SpringLiquibase.class))\n\t\t\t\t.extracting(SpringLiquibase::getLicenseKey)\n\t\t\t\t.isEqualTo(\"a1b2c3d4\"));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertLiquibase(Consumer<SpringLiquibase> consumer) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpringLiquibase.class);\n\t\t\tSpringLiquibase liquibase = context.getBean(SpringLiquibase.class);\n\t\t\tconsumer.accept(liquibase);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LiquibaseDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tDataSource normalDataSource() {\n\t\t\treturn DataSourceBuilder.create().url(\"jdbc:h2:mem:normal\" + UUID.randomUUID()).username(\"sa\").build();\n\t\t}\n\n\t\t@LiquibaseDataSource\n\t\t@Bean\n\t\tDataSource liquibaseDataSource() {\n\t\t\treturn DataSourceBuilder.create()\n\t\t\t\t.url(\"jdbc:h2:mem:liquibasetest\" + UUID.randomUUID())\n\t\t\t\t.username(\"sa\")\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LiquibaseUserConfiguration {\n\n\t\t@Bean\n\t\tSpringLiquibase springLiquibase(DataSource dataSource) {\n\t\t\tSpringLiquibase liquibase = new SpringLiquibase();\n\t\t\tliquibase.setChangeLog(\"classpath:/db/changelog/db.changelog-master.yaml\");\n\t\t\tliquibase.setShouldRun(true);\n\t\t\tliquibase.setDataSource(dataSource);\n\t\t\treturn liquibase;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDataSourceConfiguration {\n\n\t\tprivate final String name = UUID.randomUUID().toString();\n\n\t\t@Bean(destroyMethod = \"shutdown\")\n\t\tEmbeddedDatabase dataSource() throws SQLException {\n\t\t\tEmbeddedDatabase database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.setName(this.name)\n\t\t\t\t.build();\n\t\t\tinsertUser(database);\n\t\t\treturn database;\n\t\t}\n\n\t\tprivate void insertUser(EmbeddedDatabase database) throws SQLException {\n\t\t\ttry (Connection connection = database.getConnection()) {\n\t\t\t\tconnection.prepareStatement(\"CREATE USER test password 'secret'\").execute();\n\t\t\t\tconnection.prepareStatement(\"ALTER USER test ADMIN TRUE\").execute();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDriverConfiguration {\n\n\t\tprivate final String name = UUID.randomUUID().toString();\n\n\t\t@Bean\n\t\tSimpleDriverDataSource dataSource() {\n\t\t\tSimpleDriverDataSource dataSource = new SimpleDriverDataSource();\n\t\t\tdataSource.setDriverClass(CustomH2Driver.class);\n\t\t\tdataSource.setUrl(String.format(\"jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false\", this.name));\n\t\t\tdataSource.setUsername(\"sa\");\n\t\t\tdataSource.setPassword(\"\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JdbcConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tJdbcConnectionDetails jdbcConnectionDetails() {\n\t\t\treturn new JdbcConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getJdbcUrl() {\n\t\t\t\t\treturn \"jdbc:postgresql://database.example.com:12345/database-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"secret-1\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LiquibaseConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tLiquibaseConnectionDetails liquibaseConnectionDetails() {\n\t\t\treturn new LiquibaseConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getJdbcUrl() {\n\t\t\t\t\treturn \"jdbc:postgresql://database.example.com:12345/database-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getUsername() {\n\t\t\t\t\treturn \"user-1\";\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String getPassword() {\n\t\t\t\t\treturn \"secret-1\";\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tCustomizer<Liquibase> customizer() {\n\t\t\treturn (liquibase) -> liquibase.setChangeLogParameter(\"some key\", \"some value\");\n\t\t}\n\n\t}\n\n\tstatic class CustomH2Driver extends org.h2.Driver {\n\n\t}\n\n\t@WithResource(name = \"db/changelog/db.changelog-master.yaml\", content = \"\"\"\n\t\t\tdatabaseChangeLog:\n\t\t\t  - changeSet:\n\t\t\t      id: 1\n\t\t\t      author: marceloverdijk\n\t\t\t      changes:\n\t\t\t        - createTable:\n\t\t\t            tableName: customer\n\t\t\t            columns:\n\t\t\t              - column:\n\t\t\t                  name: id\n\t\t\t                  type: int\n\t\t\t                  autoIncrement: true\n\t\t\t                  constraints:\n\t\t\t                    primaryKey: true\n\t\t\t                    nullable: false\n\t\t\t              - column:\n\t\t\t                  name: name\n\t\t\t                  type: varchar(50)\n\t\t\t                  constraints:\n\t\t\t                    nullable: false\n\t\t\t\"\"\")\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Target(ElementType.METHOD)\n\t@interface WithDbChangelogMasterYamlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseAutoConfigureDataSourceInitializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureDataSourceInitialization;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Tests for Liquibase using\n * {@link AutoConfigureDataSourceInitialization @AutoConfigureDataSourceInitialization}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureDataSourceInitialization\nclass LiquibaseAutoConfigureDataSourceInitializationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid liquibaseIsIncludedInAutoConfigureDataSourceInitialization() {\n\t\tassertThat(this.context).has(importedAutoConfiguration(LiquibaseAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/autoconfigure/LiquibaseEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport liquibase.integration.spring.SpringLiquibase;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.liquibase.actuate.endpoint.LiquibaseEndpoint;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LiquibaseEndpointAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass LiquibaseEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(LiquibaseEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldHaveEndpointBean() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=liquibase\")\n\t\t\t.withBean(SpringLiquibase.class, () -> mock(SpringLiquibase.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(LiquibaseEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.withBean(SpringLiquibase.class, () -> mock(SpringLiquibase.class))\n\t\t\t.withPropertyValues(\"management.endpoint.liquibase.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(LiquibaseEndpoint.class));\n\t}\n\n\t@Test\n\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(LiquibaseEndpoint.class));\n\t}\n\n\t@Test\n\tvoid disablesCloseOfDataSourceWhenEndpointIsEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(DataSourceClosingLiquibaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=liquibase\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LiquibaseEndpoint.class);\n\t\t\t\tassertThat(context.getBean(DataSourceClosingSpringLiquibase.class))\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"closeDataSourceOnceMigrated\", false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotDisableCloseOfDataSourceWhenEndpointIsDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(DataSourceClosingLiquibaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.liquibase.enabled:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(LiquibaseEndpoint.class);\n\t\t\t\tDataSourceClosingSpringLiquibase bean = context.getBean(DataSourceClosingSpringLiquibase.class);\n\t\t\t\tassertThat(bean).hasFieldOrPropertyWithValue(\"closeDataSourceOnceMigrated\", true);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DataSourceClosingLiquibaseConfiguration {\n\n\t\t@Bean\n\t\tSpringLiquibase liquibase() {\n\t\t\treturn new DataSourceClosingSpringLiquibase() {\n\n\t\t\t\tprivate boolean propertiesSet;\n\n\t\t\t\t@Override\n\t\t\t\tpublic void setCloseDataSourceOnceMigrated(boolean closeDataSourceOnceMigrated) {\n\t\t\t\t\tif (this.propertiesSet) {\n\t\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\t\"setCloseDataSourceOnceMigrated invoked after afterPropertiesSet\");\n\t\t\t\t\t}\n\t\t\t\t\tsuper.setCloseDataSourceOnceMigrated(closeDataSourceOnceMigrated);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void afterPropertiesSet() {\n\t\t\t\t\tthis.propertiesSet = true;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-liquibase/src/test/java/org/springframework/boot/liquibase/autoconfigure/LiquibasePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.liquibase.autoconfigure;\n\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport liquibase.UpdateSummaryEnum;\nimport liquibase.UpdateSummaryOutputEnum;\nimport liquibase.ui.UIServiceEnum;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseProperties.ShowSummary;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseProperties.ShowSummaryOutput;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseProperties.UiService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LiquibaseProperties}.\n *\n * @author Andy Wilkinson\n */\nclass LiquibasePropertiesTests {\n\n\t@Test\n\tvoid valuesOfShowSummaryMatchValuesOfUpdateSummaryEnum() {\n\t\tassertThat(namesOf(ShowSummary.values())).isEqualTo(namesOf(UpdateSummaryEnum.values()));\n\t}\n\n\t@Test\n\tvoid valuesOfShowSummaryOutputMatchValuesOfUpdateSummaryOutputEnum() {\n\t\tassertThat(namesOf(ShowSummaryOutput.values())).isEqualTo(namesOf(UpdateSummaryOutputEnum.values()));\n\t}\n\n\t@Test\n\tvoid valuesOfUiServiceMatchValuesOfUiServiceEnum() {\n\t\tassertThat(namesOf(UiService.values())).isEqualTo(namesOf(UIServiceEnum.values()));\n\t}\n\n\tprivate List<String> namesOf(Enum<?>[] input) {\n\t\treturn Stream.of(input).map(Enum::name).toList();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Mail\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-context-support\")\n\tapi(\"jakarta.mail:jakarta.mail-api\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\n\truntimeOnly(\"org.eclipse.angus:angus-mail\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/java/org/springframework/boot/mail/autoconfigure/MailSenderAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport java.net.SocketTimeoutException;\nimport java.security.cert.CertPathBuilderException;\nimport java.time.Duration;\nimport java.util.Arrays;\n\nimport javax.net.ssl.SSLException;\n\nimport jakarta.mail.Folder;\nimport jakarta.mail.Message;\nimport jakarta.mail.MessagingException;\nimport jakarta.mail.Session;\nimport jakarta.mail.Store;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.MountableFile;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.MailpitContainer;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Integration tests for {@link MailSenderAutoConfiguration}.\n *\n * @author Rui Figueira\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass MailSenderAutoConfigurationIntegrationTests {\n\n\tprivate SimpleMailMessage createMessage(String subject) {\n\t\tSimpleMailMessage msg = new SimpleMailMessage();\n\t\tmsg.setFrom(\"from@example.com\");\n\t\tmsg.setTo(\"to@example.com\");\n\t\tmsg.setSubject(subject);\n\t\tmsg.setText(\"Subject: \" + subject);\n\t\treturn msg;\n\t}\n\n\tprivate String getSubject(Message message) {\n\t\ttry {\n\t\t\treturn message.getSubject();\n\t\t}\n\t\tcatch (MessagingException ex) {\n\t\t\tthrow new RuntimeException(\"Failed to get message subject\", ex);\n\t\t}\n\t}\n\n\tprivate void assertMessagesContainSubject(Session session, String subject) throws MessagingException {\n\t\ttry (Store store = session.getStore(\"pop3\")) {\n\t\t\tString host = session.getProperty(\"mail.pop3.host\");\n\t\t\tint port = Integer.parseInt(session.getProperty(\"mail.pop3.port\"));\n\t\t\tstore.connect(host, port, \"user\", \"pass\");\n\t\t\ttry (Folder folder = store.getFolder(\"inbox\")) {\n\t\t\t\tfolder.open(Folder.READ_ONLY);\n\t\t\t\tAwaitility.await()\n\t\t\t\t\t.atMost(Duration.ofSeconds(5))\n\t\t\t\t\t.ignoreExceptions()\n\t\t\t\t\t.untilAsserted(() -> assertThat(Arrays.stream(folder.getMessages()).map(this::getSubject))\n\t\t\t\t\t\t.contains(subject));\n\t\t\t}\n\t\t}\n\t}\n\n\t@Nested\n\tclass ImplicitTlsTests {\n\n\t\t@Container\n\t\tprivate static final MailpitContainer mailpit = TestImage.container(MailpitContainer.class)\n\t\t\t.withSmtpRequireTls(true)\n\t\t\t.withSmtpTlsCert(MountableFile\n\t\t\t\t.forClasspathResource(\"/org/springframework/boot/mail/autoconfigure/ssl/test-server.crt\"))\n\t\t\t.withSmtpTlsKey(MountableFile\n\t\t\t\t.forClasspathResource(\"/org/springframework/boot/mail/autoconfigure/ssl/test-server.key\"))\n\t\t\t.withPop3Auth(\"user:pass\");\n\n\t\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t\t@Test\n\t\tvoid sendEmailWithSslEnabledAndCert() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.port:\" + mailpit.getSmtpPort(), \"spring.mail.ssl.enabled:true\",\n\t\t\t\t\t\"spring.mail.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key\",\n\t\t\t\t\t\"spring.mail.properties.mail.pop3.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.properties.mail.pop3.port:\" + mailpit.getPop3Port())\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\t\tmailSender.send(createMessage(\"Hello World!\"));\n\t\t\t\t\tassertMessagesContainSubject(mailSender.getSession(), \"Hello World!\");\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid sendEmailWithSslEnabledWithoutCert() {\n\t\t\tthis.contextRunner\n\t\t\t\t.withPropertyValues(\"spring.mail.host:\" + mailpit.getHost(),\n\t\t\t\t\t\t\"spring.mail.port:\" + mailpit.getSmtpPort(), \"spring.mail.ssl.enabled:true\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\t\tassertThatException().isThrownBy(() -> mailSender.send(createMessage(\"Should fail\")))\n\t\t\t\t\t\t.withRootCauseInstanceOf(CertPathBuilderException.class);\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid sendEmailWithoutSslWithCert() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.port:\" + mailpit.getSmtpPort(), \"spring.mail.properties.mail.smtp.timeout:1000\",\n\t\t\t\t\t\"spring.mail.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\t\tassertThatException().isThrownBy(() -> mailSender.send(createMessage(\"Should fail\")))\n\t\t\t\t\t\t.withRootCauseInstanceOf(SocketTimeoutException.class);\n\t\t\t\t});\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass StarttlsTests {\n\n\t\t@Container\n\t\tprivate static final MailpitContainer mailpit = TestImage.container(MailpitContainer.class)\n\t\t\t.withSmtpRequireStarttls(true)\n\t\t\t.withSmtpTlsCert(MountableFile\n\t\t\t\t.forClasspathResource(\"/org/springframework/boot/mail/autoconfigure/ssl/test-server.crt\"))\n\t\t\t.withSmtpTlsKey(MountableFile\n\t\t\t\t.forClasspathResource(\"/org/springframework/boot/mail/autoconfigure/ssl/test-server.key\"))\n\t\t\t.withPop3Auth(\"user:pass\");\n\n\t\tfinal ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t\t@Test\n\t\tvoid sendEmailWithStarttlsAndCertAndSslDisabled() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.port:\" + mailpit.getSmtpPort(),\n\t\t\t\t\t\"spring.mail.properties.mail.smtp.starttls.enable:true\",\n\t\t\t\t\t\"spring.mail.properties.mail.smtp.starttls.required:true\", \"spring.mail.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key\",\n\t\t\t\t\t\"spring.mail.properties.mail.pop3.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.properties.mail.pop3.port:\" + mailpit.getPop3Port())\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\t\tmailSender.send(createMessage(\"Sent with STARTTLS\"));\n\t\t\t\t\tassertMessagesContainSubject(mailSender.getSession(), \"Sent with STARTTLS\");\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid sendEmailWithStarttlsAndCertAndSslEnabled() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.port:\" + mailpit.getSmtpPort(), \"spring.mail.ssl.enabled:true\",\n\t\t\t\t\t\"spring.mail.properties.mail.smtp.starttls.enable:true\",\n\t\t\t\t\t\"spring.mail.properties.mail.smtp.starttls.required:true\", \"spring.mail.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.truststore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.certificate=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.crt\",\n\t\t\t\t\t\"spring.ssl.bundle.pem.test-bundle.keystore.private-key=classpath:org/springframework/boot/mail/autoconfigure/ssl/test-client.key\",\n\t\t\t\t\t\"spring.mail.properties.mail.pop3.host:\" + mailpit.getHost(),\n\t\t\t\t\t\"spring.mail.properties.mail.pop3.port:\" + mailpit.getPop3Port())\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\t\tassertThatException().isThrownBy(() -> mailSender.send(createMessage(\"Should fail\")))\n\t\t\t\t\t\t.withRootCauseInstanceOf(SSLException.class);\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid sendEmailWithStarttlsWithoutCert() {\n\t\t\tthis.contextRunner\n\t\t\t\t.withPropertyValues(\"spring.mail.host:\" + mailpit.getHost(),\n\t\t\t\t\t\t\"spring.mail.port:\" + mailpit.getSmtpPort(),\n\t\t\t\t\t\t\"spring.mail.properties.mail.smtp.starttls.enable:true\",\n\t\t\t\t\t\t\"spring.mail.properties.mail.smtp.starttls.required:true\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\t\tassertThatException().isThrownBy(() -> mailSender.send(createMessage(\"Should fail\")))\n\t\t\t\t\t\t.withRootCauseInstanceOf(CertPathBuilderException.class);\n\t\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/resources/org/springframework/boot/mail/autoconfigure/ssl/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/resources/org/springframework/boot/mail/autoconfigure/ssl/test-ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6w3YrNBBRTFlK\nIjdlm5miEXCrYpdJQ090nquAPf9go1MNJlcpk87neRg8/QNd/SybcIdzJZJZVpvK\nKZli49Z6drUwSVIvhmkn1bCRmg5Dds8UrW63PqQw7CuABRyTLwf+sgqPYkQGGRId\nQgavns2NQTAbXKBpJ6szxHNbDU+0yr4Lws67e/3irMTc0ODVBGnK9X06awuyMhJ3\nRmYAk2L2+aIQf3bcqc/KKqdCZYqliJx2BCZfUZfKVLbaNmoDBo6RgaNfxR17K+ui\nGRmQzSGf25pK59AYRbjIoAKfc+SMm3OLx2sEjKMiL1hwDMHFkH2hUqpdkyWW2A7Z\n8MyYgmLQ2C3QKLt8KgQypKhwrIMowvpguv1Ra3Hht+yuT6tU71D8P+/xEqCy2/t0\nJ/YpZFfdkkQLQgEdLmAs2rSqqpVwbHctxLKF2Iok61LACc2QcyH6NJDEtKUGNxKp\nM+IZNEr9F12X7GdT+YGCTtkEY2tQVoPkxwwWN11LsiHzZoeelDWB6RadQa/5Ob8b\nryHYG9nlTar5F944KBFb2L8BhbaOBPsgWd+PJReAFC95q4wByGiaoURUt73lmBWI\nXq+YffgQqjfD0vlNCLCT+vndiUztNI5PIOrHrq3jMZgOxUyJykqbOLjZGnwSkSsB\nFHJERQgpK9az07365Pf7tqs0uAd7kQIDAQABAoICAAthB10ggfICHdqXdRqavWST\nfXLjweXz1O59EGPy4xFnQhMmB99/ovaVeTWWENN0LniWBZqtalpJHZrWqALPcOzr\nOKTlgr1kihmkOmrUoRPZNErFOl6t0WEtsoTNSu1oyyrofB46VXytoF3p/PBMU6fM\nlfrEzP07LoIr8P9WM0oHpEahKulfZ5uc/S2bCGfSKgP0qxmZFhBYXqmnv2U/laMI\nmKg6q+pL6l4d9SzldOobBbVnEVNzbDUmrjFjaVgf2SXiaSrXnrE3ftbUgqtA5FCS\nF7eCojooXVbT8PT4Ia+zdPnKP6n6S6I0kkXZcSDxacYffEPRSFQFe/opYr3UC+Mk\n1/UmOnoI8X8+N9SPcVD9cbVQUzBuuXfTy+LMx9mg3QxFebRSRre22xSOSlM7MF9B\n6MPeNgwCk3Z0NTr+IedGfyA+d6+iHTMGnv0hF4b4UkcXbC3HdeR3K4hf+msGD2oG\n7JF423T/d7t+g883y4CZm7p096apR8cCLIe2HKSwcYbKhft7LkAdm8kpnqkr5ER1\nanI7RDmucrx3HgrXeuCz9Uai6EMU6jNU1MAEBVeu4jz1rlO4e9zS2Ak68AwIz0zI\ntl5el3paHjlRYY6YTslM5qjGerJt19IyHvZxXXIzF7JdF7w1nSK9bjvninALJl49\nYZAPRIbyQ8P6DLqiDNBFAoIBAQDvQoow86vNg6zHdb8eBC10l2Y6M5DAKTWPE8RJ\nn0td1TLwEHzKvkR25v6yGKABbBO1+7ABACCqA8rkcB7M5jugak/kR9vuDrFPAsqf\nlgckf1Up7ekDheTH8X1VSDiRZPv07UElO0M3aFeMVR/xi9Wae8C3WZo9dT2wKnM0\nd0Acr4Kt4SYm1Dw7kuh+Y1L/vvWuryPm1btxhfKO6JN5v2W8DTrqVkxuxYEM1VnR\n69LfauLVico2q8EGXmQTth/Iok5wj1qI6kmrlgQR+eSY1qgNk1qzwjJVsbSmAOL8\n6Y9Ksct53bEN6DIdYRE/SrEVCz/FY1Pry2DNTjdiwImaSOZ3AoIBAQDH1KRkqsET\nYUnPJxp9pHWlynicEVE/Y7FFhhtpUKzhY1nZ+NsNy91FrZiyx5Os7pSxhLNID8g5\nxKCOfYd7qdvZCg/5bMXhtagQ3gwa/wyuyamc29dKkCpHDz/GkoEkgVe6eYu1GNdR\niNpY5ye5T9fBE1s3odbDcnRVeHAP7vqz5z17JKrlqZVhbLYlR4qGHmAogq7vWlyd\nIR5qLoXMgyqq5OHl1GaaiqfViBpJeoEWYze0cARUWOcrJRblJYS03WHMuLDG5RZd\n5nmf2xwEcMgW5AX7+GB8CdXRVZy6OZcGn7TU9+xnBJA2LbzxJlHBXjWEd8Uma2Al\n+ohlDbGrd8g3AoIBAHsWzGlqstREDbt/xBb5Jzl4OktvA+UYTkmRbcZCgU+Aw3fl\nw426XRaeuCF/sbGJnIpfNakOG7/bu6HSXMYlHD/m8bsLjQXn4Sg4021OjdYk+/da\nQiph09VZU5VwVknWnhjfhkhVOLtknsW/dXOa8QVM7VRmcId1rYrYC/TN9NnNIXm6\n/xmyzloHtjxvdN/Fqjd4OwwioRBCTQtgc56K7RfV5p1wUFocmcu0Z0UsAYyXPKOH\nA9Ukf2V7YhkR9UAO4DPgTD9r6QKxZt6opQZMSKDTUjJwkdysU7ejdSOQNPvEhF3p\nw5DYCBA9Q9Y/4uJkqyYtd5szQlXdC3lufFw3bPkCggEBAKPA3GpmB0xjWEG6UJoP\nUB1pWwbBpivk/Rr097eI1fLpIHNf29plalE0HcK7i4eWByGllekCjdjRCaVattCe\n9DraZRbHjS0WWMBhxdfFk9YUCbsx6C4BD7QlieSmn8+TcpmsCtF/psr4870Qx9uy\n0yI0Q3bGV6DYRP7ZcDOOacFNSHOGK8mB+5jXpjfMdXbMo43u8X3RNb3JqwvmTdy2\nzBs47ukQ8nfIEhsIqkn2apw2+CoT9WhNZjpT7XwgD6zLEd7apnqGtpqCSL63pjD5\nXu5rM4A1HJPo11/w4Ts2AE38SAqRlBcjhS3wszmGZk6obgC8yUFfkm3s7SKqYyMZ\nSGcCggEBAO0IDB/h1meZ2y+6bSsCVaDSxdRl0JF0CDUYVTANQsJ+q7u7CpF9xOo8\nYNrSy8eM0K6RMY/3WbTm+4z9tOldxEV2dn+29oVeMKkgpJYo0k2Au3wTMI2xMyyl\nHZ+ZttsqSZsj2CPx83LMaPwKdzVjwA7alVx4P+AkQKn7jGJgidj5xyw0G3gnzdfT\nnGzuitQFlcrcPyrVHAAmRhIw+B5CsvMFlM8PAvojN7burGswjWGeZjkgqoLvKlgq\njRMGzLTzF9Pay7P/D/pWQwPVGiseJq+QVIA+iILpy9Zb9T6DnBFaPFGOKAduzVU9\nlTLiho2DATppaxNUQKh/5k70hzbipDg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/resources/org/springframework/boot/mail/autoconfigure/ssl/test-client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/resources/org/springframework/boot/mail/autoconfigure/ssl/test-client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/resources/org/springframework/boot/mail/autoconfigure/ssl/test-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-mail/src/dockerTest/resources/org/springframework/boot/mail/autoconfigure/ssl/test-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/MailHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.mail.health.MailHealthIndicator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link MailHealthIndicator}.\n *\n * @author Johannes Edmeier\n * @since 4.0.0\n */\n@AutoConfiguration(after = MailSenderAutoConfiguration.class)\n@ConditionalOnClass({ JavaMailSenderImpl.class, MailHealthIndicator.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(JavaMailSenderImpl.class)\n@ConditionalOnEnabledHealthIndicator(\"mail\")\npublic final class MailHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<MailHealthIndicator, JavaMailSenderImpl> {\n\n\tMailHealthContributorAutoConfiguration() {\n\t\tsuper(MailHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"mailHealthIndicator\", \"mailHealthContributor\" })\n\tHealthContributor mailHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, JavaMailSenderImpl.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/MailProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for email support.\n *\n * @author Oliver Gierke\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.mail\")\npublic class MailProperties {\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\t/**\n\t * SMTP server host. For instance, 'smtp.example.com'.\n\t */\n\tprivate @Nullable String host;\n\n\t/**\n\t * SMTP server port.\n\t */\n\tprivate @Nullable Integer port;\n\n\t/**\n\t * Login user of the SMTP server.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the SMTP server.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Protocol used by the SMTP server.\n\t */\n\tprivate String protocol = \"smtp\";\n\n\t/**\n\t * Default MimeMessage encoding.\n\t */\n\tprivate Charset defaultEncoding = DEFAULT_CHARSET;\n\n\t/**\n\t * Additional JavaMail Session properties.\n\t */\n\tprivate final Map<String, String> properties = new HashMap<>();\n\n\t/**\n\t * Session JNDI name. When set, takes precedence over other Session settings.\n\t */\n\tprivate @Nullable String jndiName;\n\n\t/**\n\t * SSL configuration.\n\t */\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic @Nullable String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(@Nullable String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic @Nullable Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(@Nullable Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\tpublic void setProtocol(String protocol) {\n\t\tthis.protocol = protocol;\n\t}\n\n\tpublic Charset getDefaultEncoding() {\n\t\treturn this.defaultEncoding;\n\t}\n\n\tpublic void setDefaultEncoding(Charset defaultEncoding) {\n\t\tthis.defaultEncoding = defaultEncoding;\n\t}\n\n\tpublic Map<String, String> getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tpublic @Nullable String getJndiName() {\n\t\treturn this.jndiName;\n\t}\n\n\tpublic void setJndiName(@Nullable String jndiName) {\n\t\tthis.jndiName = jndiName;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support. If enabled, 'mail.(protocol).ssl.enable'\n\t\t * property is set to 'true'.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name. If set, 'mail.(protocol).ssl.socketFactory' property is set to\n\t\t * an SSLSocketFactory obtained from the corresponding SSL bundle.\n\t\t * <p>\n\t\t * Note that the STARTTLS command can use the corresponding SSLSocketFactory, even\n\t\t * if the 'mail.(protocol).ssl.enable' property is not set.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/MailSenderAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport jakarta.activation.MimeType;\nimport jakarta.mail.internet.MimeMessage;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration.MailSenderCondition;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.mail.MailSender;\n\n/**\n * {@link EnableAutoConfiguration Auto configuration} for email support.\n *\n * @author Oliver Gierke\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ MimeMessage.class, MimeType.class, MailSender.class })\n@ConditionalOnMissingBean(MailSender.class)\n@Conditional(MailSenderCondition.class)\n@EnableConfigurationProperties(MailProperties.class)\n@Import({ MailSenderJndiConfiguration.class, MailSenderPropertiesConfiguration.class })\npublic final class MailSenderAutoConfiguration {\n\n\t/**\n\t * Condition to trigger the creation of a {@link MailSender}. This kicks in if either\n\t * the host or jndi name property is set.\n\t */\n\tstatic class MailSenderCondition extends AnyNestedCondition {\n\n\t\tMailSenderCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.mail.host\")\n\t\tstatic class HostProperty {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.mail.jndi-name\")\n\t\tstatic class JndiNameProperty {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/MailSenderJndiConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport javax.naming.NamingException;\n\nimport jakarta.mail.Session;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jndi.JndiLocatorDelegate;\nimport org.springframework.mail.MailSender;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\nimport org.springframework.util.Assert;\n\n/**\n * Auto-configure a {@link MailSender} based on a {@link Session} available on JNDI.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(Session.class)\n@ConditionalOnProperty(\"spring.mail.jndi-name\")\n@ConditionalOnJndi\nclass MailSenderJndiConfiguration {\n\n\tprivate final MailProperties properties;\n\n\tMailSenderJndiConfiguration(MailProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\tJavaMailSenderImpl mailSender(Session session) {\n\t\tJavaMailSenderImpl sender = new JavaMailSenderImpl();\n\t\tsender.setDefaultEncoding(this.properties.getDefaultEncoding().name());\n\t\tsender.setSession(session);\n\t\treturn sender;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSession session() {\n\t\tString jndiName = this.properties.getJndiName();\n\t\tAssert.state(jndiName != null, \"'jndiName' must not be null\");\n\t\ttry {\n\t\t\treturn JndiLocatorDelegate.createDefaultResourceRefLocator().lookup(jndiName, Session.class);\n\t\t}\n\t\tcatch (NamingException ex) {\n\t\t\tthrow new IllegalStateException(String.format(\"Unable to find Session in JNDI location %s\", jndiName), ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/MailSenderPropertiesConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.mail.autoconfigure.MailProperties.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mail.MailSender;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Auto-configure a {@link MailSender} based on properties configuration.\n *\n * @author Oliver Gierke\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnProperty(\"spring.mail.host\")\nclass MailSenderPropertiesConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(JavaMailSender.class)\n\tJavaMailSenderImpl mailSender(MailProperties properties, ObjectProvider<SslBundles> sslBundles) {\n\t\tJavaMailSenderImpl sender = new JavaMailSenderImpl();\n\t\tapplyProperties(properties, sender, sslBundles.getIfAvailable());\n\t\treturn sender;\n\t}\n\n\tprivate void applyProperties(MailProperties properties, JavaMailSenderImpl sender,\n\t\t\t@Nullable SslBundles sslBundles) {\n\t\tsender.setHost(properties.getHost());\n\t\tif (properties.getPort() != null) {\n\t\t\tsender.setPort(properties.getPort());\n\t\t}\n\t\tsender.setUsername(properties.getUsername());\n\t\tsender.setPassword(properties.getPassword());\n\t\tsender.setProtocol(properties.getProtocol());\n\t\tif (properties.getDefaultEncoding() != null) {\n\t\t\tsender.setDefaultEncoding(properties.getDefaultEncoding().name());\n\t\t}\n\t\tProperties javaMailProperties = asProperties(properties.getProperties());\n\t\tString protocol = properties.getProtocol();\n\t\tprotocol = (!StringUtils.hasLength(protocol)) ? \"smtp\" : protocol;\n\t\tSsl ssl = properties.getSsl();\n\t\tif (ssl.isEnabled()) {\n\t\t\tjavaMailProperties.setProperty(\"mail.\" + protocol + \".ssl.enable\", \"true\");\n\t\t}\n\t\tif (ssl.getBundle() != null) {\n\t\t\tAssert.state(sslBundles != null, \"'sslBundles' must not be null\");\n\t\t\tSslBundle sslBundle = sslBundles.getBundle(ssl.getBundle());\n\t\t\tjavaMailProperties.put(\"mail.\" + protocol + \".ssl.socketFactory\",\n\t\t\t\t\tsslBundle.createSslContext().getSocketFactory());\n\t\t}\n\t\tif (!javaMailProperties.isEmpty()) {\n\t\t\tsender.setJavaMailProperties(javaMailProperties);\n\t\t}\n\t}\n\n\tprivate Properties asProperties(Map<String, String> source) {\n\t\tProperties properties = new Properties();\n\t\tproperties.putAll(source);\n\t\treturn properties;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/MailSenderValidatorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport jakarta.mail.MessagingException;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\n\n/**\n * {@link EnableAutoConfiguration Auto configuration} for testing mail service\n * connectivity on startup.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = MailSenderAutoConfiguration.class)\n@ConditionalOnBooleanProperty(\"spring.mail.test-connection\")\n@ConditionalOnSingleCandidate(JavaMailSenderImpl.class)\npublic final class MailSenderValidatorAutoConfiguration {\n\n\tprivate final JavaMailSenderImpl mailSender;\n\n\tMailSenderValidatorAutoConfiguration(JavaMailSenderImpl mailSender) {\n\t\tthis.mailSender = mailSender;\n\t\tvalidateConnection();\n\t}\n\n\tprivate void validateConnection() {\n\t\ttry {\n\t\t\tthis.mailSender.testConnection();\n\t\t}\n\t\tcatch (MessagingException ex) {\n\t\t\tthrow new IllegalStateException(\"Mail server is not available\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/NoSuchMailSenderBeanFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration.MailSenderCondition;\nimport org.springframework.core.Ordered;\nimport org.springframework.mail.MailSender;\n\n/**\n * An {@link AbstractFailureAnalyzer} that improves missing {@link MailSender} guidance\n * when {@link MailSenderAutoConfiguration} is present but did not match.\n *\n * @author MJY (answndud)\n * @author Andy Wilkinson\n */\nclass NoSuchMailSenderBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>\n\t\timplements Ordered {\n\n\tprivate static final String MAIL_HOST_PROPERTY = \"spring.mail.host\";\n\n\tprivate static final String MAIL_JNDI_NAME_PROPERTY = \"spring.mail.jndi-name\";\n\n\tprivate final BeanFactory beanFactory;\n\n\tNoSuchMailSenderBeanFailureAnalyzer(BeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {\n\t\tif (!isMissingMailSenderBean(cause)) {\n\t\t\treturn null;\n\t\t}\n\t\tConditionAndOutcome conditionAndOutcome = findMailSenderConditionOutcome();\n\t\tif (conditionAndOutcome == null || conditionAndOutcome.getOutcome().isMatch()) {\n\t\t\treturn null;\n\t\t}\n\t\tString description = \"A MailSender bean could not be found because MailSenderAutoConfiguration \"\n\t\t\t\t+ \"did not match. Neither '\" + MAIL_HOST_PROPERTY + \"' nor '\" + MAIL_JNDI_NAME_PROPERTY\n\t\t\t\t+ \"' is configured.\";\n\t\tString action = \"Consider configuring '\" + MAIL_HOST_PROPERTY + \"' or '\" + MAIL_JNDI_NAME_PROPERTY\n\t\t\t\t+ \"' to enable auto-configuration. If you want to use a custom mail sender, define a MailSender \"\n\t\t\t\t+ \"bean in your configuration.\";\n\t\treturn new FailureAnalysis(description, action, cause);\n\t}\n\n\tprivate @Nullable ConditionAndOutcome findMailSenderConditionOutcome() {\n\t\tConditionEvaluationReport conditionEvaluationReport = ConditionEvaluationReport.find(this.beanFactory);\n\t\tif (conditionEvaluationReport != null) {\n\t\t\tMap<String, ConditionAndOutcomes> conditionAndOutcomesBySource = conditionEvaluationReport\n\t\t\t\t.getConditionAndOutcomesBySource();\n\t\t\tConditionAndOutcomes conditionAndOutcomes = conditionAndOutcomesBySource\n\t\t\t\t.get(MailSenderAutoConfiguration.class.getName());\n\t\t\tif (conditionAndOutcomes != null) {\n\t\t\t\treturn conditionAndOutcomes.stream()\n\t\t\t\t\t.filter((candidate) -> candidate.getCondition() instanceof MailSenderCondition)\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.orElse(null);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isMissingMailSenderBean(NoSuchBeanDefinitionException cause) {\n\t\tClass<?> beanType = cause.getBeanType();\n\t\tif (beanType == null && cause.getResolvableType() != null) {\n\t\t\tbeanType = cause.getResolvableType().resolve();\n\t\t}\n\t\treturn (beanType != null) && MailSender.class.isAssignableFrom(beanType);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for email support.\n */\n@NullMarked\npackage org.springframework.boot.mail.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/health/MailHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.health;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link HealthIndicator} for configured smtp server(s).\n *\n * @author Johannes Edmeier\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class MailHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate final JavaMailSenderImpl mailSender;\n\n\tpublic MailHealthIndicator(JavaMailSenderImpl mailSender) {\n\t\tsuper(\"Mail health check failed\");\n\t\tthis.mailSender = mailSender;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tString host = this.mailSender.getHost();\n\t\tint port = this.mailSender.getPort();\n\t\tStringBuilder location = new StringBuilder((host != null) ? host : \"\");\n\t\tif (port != JavaMailSenderImpl.DEFAULT_PORT) {\n\t\t\tlocation.append(\":\").append(port);\n\t\t}\n\t\tif (StringUtils.hasLength(location)) {\n\t\t\tbuilder.withDetail(\"location\", location.toString());\n\t\t}\n\t\tthis.mailSender.testConnection();\n\t\tbuilder.up();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/java/org/springframework/boot/mail/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for JavaMail.\n */\n@NullMarked\npackage org.springframework.boot.mail.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.mail.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Mail health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.mail.test-connection\",\n      \"description\": \"Whether to test that the mail server is available on startup.\",\n      \"sourceType\": \"org.springframework.boot.autoconfigure.mail.MailProperties\",\n      \"type\": \"java.lang.Boolean\",\n      \"defaultValue\": false\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.mail.autoconfigure.MailHealthContributorAutoConfiguration\norg.springframework.boot.mail.autoconfigure.MailSenderAutoConfiguration\norg.springframework.boot.mail.autoconfigure.MailSenderValidatorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-mail/src/main/resources/META-INF/spring.factories",
    "content": "# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.mail.autoconfigure.NoSuchMailSenderBeanFailureAnalyzer\n"
  },
  {
    "path": "module/spring-boot-mail/src/test/java/org/springframework/boot/mail/autoconfigure/MailHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.mail.health.MailHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MailHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n */\nclass MailHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class,\n\t\t\t\tMailHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.mail.host:smtp.example.com\");\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MailHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.mail.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MailHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/test/java/org/springframework/boot/mail/autoconfigure/MailSenderAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport java.util.Properties;\n\nimport javax.naming.Context;\nimport javax.net.ssl.SSLSocketFactory;\n\nimport jakarta.mail.Session;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.jndi.JndiPropertiesHidingClassLoader;\nimport org.springframework.boot.autoconfigure.jndi.TestableInitialContextFactory;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mail.MailSender;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link MailSenderAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass MailSenderAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class,\n\t\t\t\tMailSenderValidatorAutoConfiguration.class, SslAutoConfiguration.class));\n\n\tprivate ClassLoader threadContextClassLoader;\n\n\tprivate String initialContextFactory;\n\n\t@BeforeEach\n\tvoid setupJndi() {\n\t\tthis.initialContextFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, TestableInitialContextFactory.class.getName());\n\t\tthis.threadContextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread()\n\t\t\t.setContextClassLoader(new JndiPropertiesHidingClassLoader(Thread.currentThread().getContextClassLoader()));\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tTestableInitialContextFactory.clearAll();\n\t\tif (this.initialContextFactory != null) {\n\t\t\tSystem.setProperty(Context.INITIAL_CONTEXT_FACTORY, this.initialContextFactory);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(Context.INITIAL_CONTEXT_FACTORY);\n\t\t}\n\t\tThread.currentThread().setContextClassLoader(this.threadContextClassLoader);\n\t}\n\n\t@Test\n\tvoid smtpHostSet() {\n\t\tString host = \"192.168.1.234\";\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:\" + host).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\tassertThat(mailSender.getHost()).isEqualTo(host);\n\t\t\tassertThat(mailSender.getPort()).isEqualTo(JavaMailSenderImpl.DEFAULT_PORT);\n\t\t\tassertThat(mailSender.getProtocol()).isEqualTo(JavaMailSenderImpl.DEFAULT_PROTOCOL);\n\t\t});\n\t}\n\n\t@Test\n\tvoid smtpHostWithSettings() {\n\t\tString host = \"192.168.1.234\";\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mail.host:\" + host, \"spring.mail.port:42\", \"spring.mail.username:john\",\n\t\t\t\t\t\"spring.mail.password:secret\", \"spring.mail.default-encoding:US-ASCII\",\n\t\t\t\t\t\"spring.mail.protocol:smtps\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getHost()).isEqualTo(host);\n\t\t\t\tassertThat(mailSender.getPort()).isEqualTo(42);\n\t\t\t\tassertThat(mailSender.getUsername()).isEqualTo(\"john\");\n\t\t\t\tassertThat(mailSender.getPassword()).isEqualTo(\"secret\");\n\t\t\t\tassertThat(mailSender.getDefaultEncoding()).isEqualTo(\"US-ASCII\");\n\t\t\t\tassertThat(mailSender.getProtocol()).isEqualTo(\"smtps\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid smtpHostWithJavaMailProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mail.host:localhost\", \"spring.mail.properties.mail.smtp.auth:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getJavaMailProperties()).containsEntry(\"mail.smtp.auth\", \"true\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid smtpHostNotSet() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(MailSender.class));\n\t}\n\n\t@Test\n\tvoid mailSenderBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(ManualMailConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.mail.host:smtp.acme.org\", \"spring.mail.user:user\",\n\t\t\t\t\t\"spring.mail.password:secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getUsername()).isNull();\n\t\t\t\tassertThat(mailSender.getPassword()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jndiSessionAvailable() {\n\t\tSession session = configureJndiSession(\"java:comp/env/foo\");\n\t\ttestJndiSessionLookup(session, \"java:comp/env/foo\");\n\t}\n\n\t@Test\n\tvoid jndiSessionAvailableWithResourceRef() {\n\t\tSession session = configureJndiSession(\"java:comp/env/foo\");\n\t\ttestJndiSessionLookup(session, \"foo\");\n\t}\n\n\tprivate void testJndiSessionLookup(Session session, String jndiName) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.jndi-name:\" + jndiName).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Session.class);\n\t\t\tSession sessionBean = context.getBean(Session.class);\n\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\tassertThat(sessionBean).isEqualTo(session);\n\t\t\tassertThat(context.getBean(JavaMailSenderImpl.class).getSession()).isEqualTo(sessionBean);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jndiSessionIgnoredIfJndiNameNotSet() {\n\t\tconfigureJndiSession(\"foo\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:smtp.acme.org\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(Session.class);\n\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jndiSessionNotUsedIfJndiNameNotSet() {\n\t\tconfigureJndiSession(\"foo\");\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(Session.class);\n\t\t\tassertThat(context).doesNotHaveBean(MailSender.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jndiSessionNotAvailableWithJndiName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.jndi-name:foo\").run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context.getStartupFailure()).isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"Unable to find Session in JNDI location foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid jndiSessionTakesPrecedenceOverProperties() {\n\t\tSession session = configureJndiSession(\"foo\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.jndi-name:foo\", \"spring.mail.host:localhost\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Session.class);\n\t\t\t\tSession sessionBean = context.getBean(Session.class);\n\t\t\t\tassertThat(sessionBean).isEqualTo(session);\n\t\t\t\tassertThat(context.getBean(JavaMailSenderImpl.class).getSession()).isEqualTo(sessionBean);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultEncodingWithProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:localhost\", \"spring.mail.default-encoding:UTF-16\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getDefaultEncoding()).isEqualTo(\"UTF-16\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultEncodingWithJndi() {\n\t\tconfigureJndiSession(\"foo\");\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.jndi-name:foo\", \"spring.mail.default-encoding:UTF-16\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getDefaultEncoding()).isEqualTo(\"UTF-16\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionOnStartup() {\n\t\tthis.contextRunner.withUserConfiguration(MockMailConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.mail.host:10.0.0.23\", \"spring.mail.test-connection:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tthen(mailSender).should().testConnection();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionOnStartupNotCalled() {\n\t\tthis.contextRunner.withUserConfiguration(MockMailConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.mail.host:10.0.0.23\", \"spring.mail.test-connection:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tthen(mailSender).should(never()).testConnection();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid smtpSslEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mail.host:localhost\", \"spring.mail.ssl.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getJavaMailProperties()).containsEntry(\"mail.smtp.ssl.enable\", \"true\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid smtpSslBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mail.host:localhost\", \"spring.mail.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location:classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password:secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password:password\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getJavaMailProperties()).doesNotContainKey(\"mail.smtp.ssl.enable\");\n\t\t\t\tObject property = mailSender.getJavaMailProperties().get(\"mail.smtp.ssl.socketFactory\");\n\t\t\t\tassertThat(property).isInstanceOf(SSLSocketFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid smtpsSslEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mail.host:localhost\", \"spring.mail.protocol:smtps\",\n\t\t\t\t\t\"spring.mail.ssl.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getJavaMailProperties()).containsEntry(\"mail.smtps.ssl.enable\", \"true\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid smtpsSslBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mail.host:localhost\", \"spring.mail.protocol:smtps\",\n\t\t\t\t\t\"spring.mail.ssl.bundle:test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location:classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password:secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password:password\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JavaMailSenderImpl.class);\n\t\t\t\tJavaMailSenderImpl mailSender = context.getBean(JavaMailSenderImpl.class);\n\t\t\t\tassertThat(mailSender.getJavaMailProperties()).doesNotContainKey(\"mail.smtps.ssl.enable\");\n\t\t\t\tObject property = mailSender.getJavaMailProperties().get(\"mail.smtps.ssl.socketFactory\");\n\t\t\t\tassertThat(property).isInstanceOf(SSLSocketFactory.class);\n\t\t\t});\n\t}\n\n\tprivate Session configureJndiSession(String name) {\n\t\tProperties properties = new Properties();\n\t\tSession session = Session.getDefaultInstance(properties);\n\t\tTestableInitialContextFactory.bind(name, session);\n\t\treturn session;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ManualMailConfiguration {\n\n\t\t@Bean\n\t\tJavaMailSender customMailSender() {\n\t\t\treturn new JavaMailSenderImpl();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockMailConfiguration {\n\n\t\t@Bean\n\t\tJavaMailSenderImpl mockMailSender() {\n\t\t\treturn mock(JavaMailSenderImpl.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/test/java/org/springframework/boot/mail/autoconfigure/NoSuchMailSenderBeanFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.mail.MailSender;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\n\n/**\n * Tests for {@link NoSuchMailSenderBeanFailureAnalyzer}.\n *\n * @author MJY (answndud)\n * @author Andy Wilkinson\n */\nclass NoSuchMailSenderBeanFailureAnalyzerTests {\n\n\t@Test\n\tvoid analyzeWhenNotNoSuchBeanDefinitionExceptionShouldReturnNull() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tFailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory)\n\t\t\t\t\t.analyze(new Exception());\n\t\t\t\tassertThat(analysis).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid analyzeWhenNoSuchBeanDefinitionExceptionForDifferentTypeShouldReturnNull() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tassertThatException().isThrownBy(() -> context.getBean(String.class)).satisfies((ex) -> {\n\t\t\t\t\tFailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory).analyze(ex);\n\t\t\t\t\tassertThat(analysis).isNull();\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid analyzeWithoutMailSenderAutoConfigurationShouldReturnNull() {\n\t\tnew ApplicationContextRunner().run((context) -> {\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tassertThatException().isThrownBy(() -> context.getBean(MailSender.class)).satisfies((ex) -> {\n\t\t\t\tFailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory).analyze(ex);\n\t\t\t\tassertThat(analysis).isNull();\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid analyzeWhenMailSenderBeanIsMissingAndMailSenderConditionDidNotMatchShouldProvideGuidance() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MailSenderAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tassertThatException().isThrownBy(() -> context.getBean(MailSender.class)).satisfies((ex) -> {\n\t\t\t\t\tFailureAnalysis analysis = new NoSuchMailSenderBeanFailureAnalyzer(beanFactory).analyze(ex);\n\t\t\t\t\tassertThat(analysis).isNotNull();\n\t\t\t\t\tassertThat(analysis.getDescription()).contains(\"A MailSender bean could not be found\")\n\t\t\t\t\t\t.contains(\"spring.mail.host\")\n\t\t\t\t\t\t.contains(\"spring.mail.jndi-name\");\n\t\t\t\t\tassertThat(analysis.getAction()).contains(\"spring.mail.host\")\n\t\t\t\t\t\t.contains(\"spring.mail.jndi-name\")\n\t\t\t\t\t\t.contains(\"MailSender bean\");\n\t\t\t\t});\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mail/src/test/java/org/springframework/boot/mail/health/MailHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mail.health;\n\nimport java.util.Properties;\n\nimport jakarta.mail.Address;\nimport jakarta.mail.Message;\nimport jakarta.mail.MessagingException;\nimport jakarta.mail.Provider;\nimport jakarta.mail.Provider.Type;\nimport jakarta.mail.Session;\nimport jakarta.mail.Transport;\nimport jakarta.mail.URLName;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MailHealthIndicator}.\n *\n * @author Johannes Edmeier\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass MailHealthIndicatorTests {\n\n\tprivate JavaMailSenderImpl mailSender;\n\n\tprivate MailHealthIndicator indicator;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tSession session = Session.getDefaultInstance(new Properties());\n\t\tsession.addProvider(new Provider(Type.TRANSPORT, \"success\", SuccessTransport.class.getName(), \"Test\", \"1.0.0\"));\n\t\tthis.mailSender = mock(JavaMailSenderImpl.class);\n\t\tgiven(this.mailSender.getHost()).willReturn(\"smtp.acme.org\");\n\t\tgiven(this.mailSender.getSession()).willReturn(session);\n\t\tthis.indicator = new MailHealthIndicator(this.mailSender);\n\t}\n\n\t@Test\n\tvoid smtpOnDefaultHostAndPortIsUp() {\n\t\tgiven(this.mailSender.getHost()).willReturn(null);\n\t\tgiven(this.mailSender.getPort()).willReturn(-1);\n\t\tgiven(this.mailSender.getProtocol()).willReturn(\"success\");\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"location\");\n\t}\n\n\t@Test\n\tvoid smtpOnDefaultHostAndPortIsDown() throws MessagingException {\n\t\tgiven(this.mailSender.getHost()).willReturn(null);\n\t\tgiven(this.mailSender.getPort()).willReturn(-1);\n\t\twillThrow(new MessagingException(\"A test exception\")).given(this.mailSender).testConnection();\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"location\");\n\t\tObject errorMessage = health.getDetails().get(\"error\");\n\t\tassertThat(errorMessage).isNotNull();\n\t\tassertThat(errorMessage.toString()).contains(\"A test exception\");\n\t}\n\n\t@Test\n\tvoid smtpOnDefaultHostAndCustomPortIsUp() {\n\t\tgiven(this.mailSender.getHost()).willReturn(null);\n\t\tgiven(this.mailSender.getPort()).willReturn(1234);\n\t\tgiven(this.mailSender.getProtocol()).willReturn(\"success\");\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails().get(\"location\")).isEqualTo(\":1234\");\n\t}\n\n\t@Test\n\tvoid smtpOnDefaultHostAndCustomPortIsDown() throws MessagingException {\n\t\tgiven(this.mailSender.getHost()).willReturn(null);\n\t\tgiven(this.mailSender.getPort()).willReturn(1234);\n\t\twillThrow(new MessagingException(\"A test exception\")).given(this.mailSender).testConnection();\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails().get(\"location\")).isEqualTo(\":1234\");\n\t\tObject errorMessage = health.getDetails().get(\"error\");\n\t\tassertThat(errorMessage).isNotNull();\n\t\tassertThat(errorMessage.toString()).contains(\"A test exception\");\n\t}\n\n\t@Test\n\tvoid smtpOnDefaultPortIsUp() {\n\t\tgiven(this.mailSender.getPort()).willReturn(-1);\n\t\tgiven(this.mailSender.getProtocol()).willReturn(\"success\");\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"location\", \"smtp.acme.org\");\n\t}\n\n\t@Test\n\tvoid smtpOnDefaultPortIsDown() throws MessagingException {\n\t\tgiven(this.mailSender.getPort()).willReturn(-1);\n\t\twillThrow(new MessagingException(\"A test exception\")).given(this.mailSender).testConnection();\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"location\", \"smtp.acme.org\");\n\t\tObject errorMessage = health.getDetails().get(\"error\");\n\t\tassertThat(errorMessage).isNotNull();\n\t\tassertThat(errorMessage.toString()).contains(\"A test exception\");\n\t}\n\n\t@Test\n\tvoid smtpOnCustomPortIsUp() {\n\t\tgiven(this.mailSender.getPort()).willReturn(1234);\n\t\tgiven(this.mailSender.getProtocol()).willReturn(\"success\");\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"location\", \"smtp.acme.org:1234\");\n\t}\n\n\t@Test\n\tvoid smtpOnCustomPortIsDown() throws MessagingException {\n\t\tgiven(this.mailSender.getPort()).willReturn(1234);\n\t\twillThrow(new MessagingException(\"A test exception\")).given(this.mailSender).testConnection();\n\t\tHealth health = this.indicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsEntry(\"location\", \"smtp.acme.org:1234\");\n\t\tObject errorMessage = health.getDetails().get(\"error\");\n\t\tassertThat(errorMessage).isNotNull();\n\t\tassertThat(errorMessage.toString()).contains(\"A test exception\");\n\t}\n\n\tstatic class SuccessTransport extends Transport {\n\n\t\tSuccessTransport(Session session, URLName urlName) {\n\t\t\tsuper(session, urlName);\n\t\t}\n\n\t\t@Override\n\t\tpublic void connect(String host, int port, String user, String password) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void sendMessage(Message msg, Address[] addresses) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Metrics\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-micrometer-observation\"))\n\tapi(\"io.micrometer:micrometer-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-opentelemetry\"))\n\toptional(\"ch.qos.logback:logback-classic\")\n\toptional(\"io.micrometer:micrometer-java21\")\n\toptional(\"io.micrometer:micrometer-registry-appoptics\")\n\toptional(\"io.micrometer:micrometer-registry-atlas\") {\n\t\texclude group: \"javax.inject\", module: \"javax.inject\"\n\t}\n\toptional(\"io.micrometer:micrometer-registry-datadog\")\n\toptional(\"io.micrometer:micrometer-registry-dynatrace\")\n\toptional(\"io.micrometer:micrometer-registry-elastic\")\n\toptional(\"io.micrometer:micrometer-registry-ganglia\")\n\toptional(\"io.micrometer:micrometer-registry-graphite\")\n\toptional(\"io.micrometer:micrometer-registry-humio\")\n\toptional(\"io.micrometer:micrometer-registry-influx\")\n\toptional(\"io.micrometer:micrometer-registry-jmx\")\n\toptional(\"io.micrometer:micrometer-registry-kairos\")\n\toptional(\"io.micrometer:micrometer-registry-new-relic\")\n\toptional(\"io.micrometer:micrometer-registry-otlp\")\n\toptional(\"io.micrometer:micrometer-registry-prometheus\")\n\toptional(\"io.micrometer:micrometer-registry-stackdriver\") {\n\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t}\n\toptional(\"io.micrometer:micrometer-registry-statsd\")\n\toptional(\"io.prometheus:prometheus-metrics-exporter-pushgateway\")\n\toptional(\"org.apache.kafka:kafka-streams\")\n\toptional(\"org.apache.logging.log4j:log4j-core\")\n\toptional(\"org.aspectj:aspectjweaver\")\n\toptional(\"org.testcontainers:testcontainers-grafana\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\tdockerTestImplementation(\"org.springframework:spring-web\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestFixturesImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"io.micrometer:micrometer-registry-atlas\")\n\ttestImplementation(\"io.micrometer:micrometer-registry-new-relic\")\n\ttestImplementation(\"io.micrometer:micrometer-registry-prometheus\")\n\ttestImplementation(\"org.apache.logging.log4j:log4j-to-slf4j\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/java/org/springframework/boot/micrometer/metrics/docker/compose/otlp/GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.docker.compose.otlp;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory}\n * using {@link TestImage#GRAFANA_OTEL_LGTM}.\n *\n * @author Eddú Meléndez\n */\nclass GrafanaOpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"otlp-compose.yaml\", image = TestImage.GRAFANA_OTEL_LGTM)\n\tvoid runCreatesConnectionDetails(OtlpMetricsConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl()).startsWith(\"http://\").endsWith(\"/v1/metrics\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"otlp-ssl-compose.yaml\", image = TestImage.GRAFANA_OTEL_LGTM,\n\t\t\tadditionalResources = \"ca.crt\")\n\tvoid runWithSslCreatesConnectionDetails(OtlpMetricsConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl()).startsWith(\"https://\").endsWith(\"/v1/metrics\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/java/org/springframework/boot/micrometer/metrics/docker/compose/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.docker.compose.otlp;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OpenTelemetryMetricsDockerComposeConnectionDetailsFactory}\n * using {@link TestImage#OTEL_COLLECTOR}.\n *\n * @author Eddú Meléndez\n */\nclass OpenTelemetryMetricsDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"otlp-compose.yaml\", image = TestImage.OTEL_COLLECTOR)\n\tvoid runCreatesConnectionDetails(OtlpMetricsConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl()).startsWith(\"http://\").endsWith(\"/v1/metrics\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"otlp-ssl-compose.yaml\", image = TestImage.OTEL_COLLECTOR,\n\t\t\tadditionalResources = \"ca.crt\")\n\tvoid runWithSslCreatesConnectionDetails(OtlpMetricsConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl()).startsWith(\"https://\").endsWith(\"/v1/metrics\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/java/org/springframework/boot/micrometer/metrics/testcontainers/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.testcontainers.otlp;\n\nimport java.net.URI;\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Counter;\nimport io.micrometer.core.instrument.DistributionSummary;\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Timer;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.grafana.LgtmStackContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@TestPropertySource(properties = { \"management.opentelemetry.resource-attributes.service.name=test\",\n\t\t\"management.otlp.metrics.export.step=1s\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class);\n\n\t@Autowired\n\tprivate MeterRegistry meterRegistry;\n\n\t@Autowired\n\tprivate OtlpMetricsConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToOpenTelemetryCollectorContainer() {\n\t\tassertThat(this.connectionDetails.getSslBundle()).isNull();\n\t\tCounter.builder(\"test.counter\").register(this.meterRegistry).increment(42);\n\t\tGauge.builder(\"test.gauge\", () -> 12).register(this.meterRegistry);\n\t\tTimer.builder(\"test.timer\").register(this.meterRegistry).record(Duration.ofMillis(123));\n\t\tDistributionSummary.builder(\"test.distributionsummary\").register(this.meterRegistry).record(24);\n\t\tAwaitility.given()\n\t\t\t.pollInterval(Duration.ofSeconds(2))\n\t\t\t.atMost(Duration.ofSeconds(10))\n\t\t\t.ignoreExceptions()\n\t\t\t.untilAsserted(() -> {\n\t\t\t\tRestTestClient restClient = RestTestClient.bindToServer().build();\n\t\t\t\trestClient.get()\n\t\t\t\t\t.uri(URI.create(container.getPrometheusHttpUrl() + \"/api/v1/query?query=%7Bjob=%22test%22%7D\"))\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_counter_total\", \"42\"))\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_timer_milliseconds_count\", \"1\"))\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_timer_milliseconds_sum\", \"123\"))\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_timer_milliseconds_bucket\", \"1\"))\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_distributionsummary_count\", \"1\"))\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_distributionsummary_sum\", \"24\"))\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(metricWithValue(\"test_distributionsummary_bucket\", \"1\"))\n\t\t\t\t\t.exists();\n\t\t\t});\n\t}\n\n\tprivate String metricWithValue(String metric, String value) {\n\t\treturn \"$.data.result[?(@.metric.__name__==\\\"%s\\\" && \\\"%s\\\" in @.value)]\".formatted(metric, value);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(OtlpMetricsExportAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tClock customClock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/java/org/springframework/boot/micrometer/metrics/testcontainers/otlp/OpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.testcontainers.otlp;\n\nimport java.time.Duration;\nimport java.util.function.Consumer;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Counter;\nimport io.micrometer.core.instrument.DistributionSummary;\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Timer;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.MountableFile;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OpenTelemetryMetricsContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n * @author Jonatan Ivanov\n */\n@SpringJUnitConfig\n@TestPropertySource(properties = { \"management.opentelemetry.resource-attributes.service.name=test\",\n\t\t\"management.otlp.metrics.export.step=1s\" })\n@Testcontainers(disabledWithoutDocker = true)\nclass OpenTelemetryMetricsContainerConnectionDetailsFactoryIntegrationTests {\n\n\tprivate static final MediaType OPENMETRICS_001 = MediaType\n\t\t.parseMediaType(\"application/openmetrics-text; version=0.0.1; charset=utf-8\");\n\n\tprivate static final String CONFIG_FILE_NAME = \"collector-config.yml\";\n\n\t@Container\n\t@ServiceConnection\n\tstatic final GenericContainer<?> container = TestImage.OTEL_COLLECTOR.genericContainer()\n\t\t.withCommand(\"--config=/etc/\" + CONFIG_FILE_NAME)\n\t\t.withCopyToContainer(MountableFile.forClasspathResource(CONFIG_FILE_NAME), \"/etc/\" + CONFIG_FILE_NAME)\n\t\t.withExposedPorts(4318, 9090);\n\n\t@Autowired\n\tprivate MeterRegistry meterRegistry;\n\n\t@Autowired\n\tprivate OtlpMetricsConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToOpenTelemetryCollectorContainer() {\n\t\tassertThat(this.connectionDetails.getSslBundle()).isNull();\n\t\tCounter.builder(\"test.counter\").register(this.meterRegistry).increment(42);\n\t\tGauge.builder(\"test.gauge\", () -> 12).register(this.meterRegistry);\n\t\tTimer.builder(\"test.timer\").register(this.meterRegistry).record(Duration.ofMillis(123));\n\t\tDistributionSummary.builder(\"test.distributionsummary\").register(this.meterRegistry).record(24);\n\t\tAwaitility.await()\n\t\t\t.atMost(Duration.ofSeconds(30))\n\t\t\t.untilAsserted(() -> whenPrometheusScraped().expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(OPENMETRICS_001)\n\t\t\t\t.expectBody(String.class)\n\t\t\t\t.value((Consumer<@Nullable String>) (body) -> assertThat(body).endsWith(\"# EOF\\n\")\n\t\t\t\t\t.contains(\n\t\t\t\t\t\t\t\"{job=\\\"test\\\",service_name=\\\"test\\\",telemetry_sdk_language=\\\"java\\\",telemetry_sdk_name=\\\"io.micrometer\\\"\")\n\t\t\t\t\t.matches(\"(?s)^.*test_counter\\\\{.+} 42\\\\.0\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_gauge\\\\{.+} 12\\\\.0\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_timer_count\\\\{.+} 1\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_timer_sum\\\\{.+} 123\\\\.0\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_timer_bucket\\\\{.+,le=\\\"\\\\+Inf\\\"} 1\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_distributionsummary_count\\\\{.+} 1\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_distributionsummary_sum\\\\{.+} 24\\\\.0\\\\n.*$\")\n\t\t\t\t\t.matches(\"(?s)^.*test_distributionsummary_bucket\\\\{.+,le=\\\"\\\\+Inf\\\"} 1\\\\n.*$\")));\n\n\t}\n\n\tprivate ResponseSpec whenPrometheusScraped() {\n\t\treturn RestTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://\" + container.getHost() + \":\" + container.getMappedPort(9090))\n\t\t\t.build()\n\t\t\t.get()\n\t\t\t.uri(\"/metrics\")\n\t\t\t.accept(OPENMETRICS_001)\n\t\t\t.exchange();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(OtlpMetricsExportAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tClock customClock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/resources/collector-config.yml",
    "content": "receivers:\n  otlp:\n    protocols:\n      grpc:\n      http:\n\nexporters:\n  # https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/prometheusexporter\n  prometheus:\n    endpoint: '0.0.0.0:9090'\n    metric_expiration: 1m\n    enable_open_metrics: true\n    resource_to_telemetry_conversion:\n      enabled: true\n\nservice:\n  pipelines:\n    metrics:\n      receivers: [otlp]\n      exporters: [prometheus]"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/resources/org/springframework/boot/micrometer/metrics/docker/compose/otlp/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/resources/org/springframework/boot/micrometer/metrics/docker/compose/otlp/otlp-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/dockerTest/resources/org/springframework/boot/micrometer/metrics/docker/compose/otlp/otlp-ssl-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/MaximumAllowableTagsMeterFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics;\n\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Supplier;\n\nimport io.micrometer.core.instrument.Meter.Id;\nimport io.micrometer.core.instrument.config.MeterFilter;\nimport io.micrometer.core.instrument.config.MeterFilterReply;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * {@link MeterFilter} to log a single warning message and deny a {@link Id Meter.Id}\n * after a number of attempts for a given tag.\n *\n * @author Jon Schneider\n * @author Dmytro Nosan\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class MaximumAllowableTagsMeterFilter implements MeterFilter {\n\n\tprivate final Log logger;\n\n\tprivate final AtomicBoolean alreadyWarned = new AtomicBoolean();\n\n\tprivate final String meterNamePrefix;\n\n\tprivate final int maximumTagValues;\n\n\tprivate final String tagKey;\n\n\tprivate final Supplier<String> message;\n\n\tprivate final Set<String> observedTagValues = ConcurrentHashMap.newKeySet();\n\n\t/**\n\t * Create a new {@link MaximumAllowableTagsMeterFilter} with an upper bound on the\n\t * number of tags produced by matching metrics.\n\t * @param meterNamePrefix the prefix of the meter name to apply the filter to\n\t * @param tagKey the tag to place an upper bound on\n\t * @param maximumTagValues the total number of tag values that are allowable\n\t */\n\tpublic MaximumAllowableTagsMeterFilter(String meterNamePrefix, String tagKey, int maximumTagValues) {\n\t\tthis(meterNamePrefix, tagKey, maximumTagValues, (String) null);\n\t}\n\n\t/**\n\t * Create a new {@link MaximumAllowableTagsMeterFilter} with an upper bound on the\n\t * number of tags produced by matching metrics.\n\t * @param meterNamePrefix the prefix of the meter name to apply the filter to\n\t * @param tagKey the tag to place an upper bound on\n\t * @param maximumTagValues the total number of tag values that are allowable\n\t * @param hint an additional hint to add to the logged message or {@code null}\n\t */\n\tpublic MaximumAllowableTagsMeterFilter(String meterNamePrefix, String tagKey, int maximumTagValues,\n\t\t\t@Nullable String hint) {\n\t\tthis(null, meterNamePrefix, tagKey, maximumTagValues,\n\t\t\t\t() -> String.format(\"Reached the maximum number of '%s' tags for '%s'.%s\", tagKey, meterNamePrefix,\n\t\t\t\t\t\t(hint != null) ? \" \" + hint : \"\"));\n\t}\n\n\tprivate MaximumAllowableTagsMeterFilter(@Nullable Log logger, String meterNamePrefix, String tagKey,\n\t\t\tint maximumTagValues, Supplier<String> message) {\n\t\tAssert.notNull(message, \"'message' must not be null\");\n\t\tAssert.isTrue(maximumTagValues >= 0, \"'maximumTagValues' must be positive\");\n\t\tthis.logger = (logger != null) ? logger : LogFactory.getLog(MaximumAllowableTagsMeterFilter.class);\n\t\tthis.meterNamePrefix = meterNamePrefix;\n\t\tthis.maximumTagValues = maximumTagValues;\n\t\tthis.tagKey = tagKey;\n\t\tthis.message = message;\n\t}\n\n\t@Override\n\tpublic MeterFilterReply accept(Id id) {\n\t\tif (this.meterNamePrefix == null) {\n\t\t\treturn logAndDeny();\n\t\t}\n\t\tString tagValue = id.getName().startsWith(this.meterNamePrefix) ? id.getTag(this.tagKey) : null;\n\t\tif (tagValue != null && !this.observedTagValues.contains(tagValue)) {\n\t\t\tif (this.observedTagValues.size() >= this.maximumTagValues) {\n\t\t\t\treturn logAndDeny();\n\t\t\t}\n\t\t\tthis.observedTagValues.add(tagValue);\n\t\t}\n\t\treturn MeterFilterReply.NEUTRAL;\n\t}\n\n\tprivate MeterFilterReply logAndDeny() {\n\t\tif (this.logger.isWarnEnabled() && this.alreadyWarned.compareAndSet(false, true)) {\n\t\t\tthis.logger.warn(this.message.get());\n\t\t}\n\t\treturn MeterFilterReply.DENY;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/ValidationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics;\n\nimport io.micrometer.core.instrument.config.validate.Validated.Invalid;\nimport io.micrometer.core.instrument.config.validate.ValidationException;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} that performs analysis of failures caused by a\n * {@link ValidationException}.\n *\n * @author Andy Wilkinson\n */\nclass ValidationFailureAnalyzer extends AbstractFailureAnalyzer<ValidationException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, ValidationException cause) {\n\t\tStringBuilder description = new StringBuilder(String.format(\"Invalid Micrometer configuration detected:%n\"));\n\t\tfor (Invalid<?> failure : cause.getValidation().failures()) {\n\t\t\tdescription.append(String.format(\"%n  - %s was '%s' but it %s\", failure.getProperty(), failure.getValue(),\n\t\t\t\t\tfailure.getMessage()));\n\t\t}\n\t\treturn new FailureAnalysis(description.toString(),\n\t\t\t\t\"Update your application to correct the invalid configuration.\", cause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/actuate/endpoint/MetricsEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.actuate.endpoint;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.function.BiFunction;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Statistic;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\n\n/**\n * An {@link Endpoint @Endpoint} for exposing the metrics held by a {@link MeterRegistry}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n * @since 4.0.0\n */\n@Endpoint(id = \"metrics\")\npublic class MetricsEndpoint {\n\n\tprivate final MeterRegistry registry;\n\n\tpublic MetricsEndpoint(MeterRegistry registry) {\n\t\tthis.registry = registry;\n\t}\n\n\t@ReadOperation\n\tpublic MetricNamesDescriptor listNames() {\n\t\tSet<String> names = new TreeSet<>();\n\t\tcollectNames(names, this.registry);\n\t\treturn new MetricNamesDescriptor(names);\n\t}\n\n\tprivate void collectNames(Set<String> names, MeterRegistry registry) {\n\t\tif (registry instanceof CompositeMeterRegistry compositeMeterRegistry) {\n\t\t\tcompositeMeterRegistry.getRegistries().forEach((member) -> collectNames(names, member));\n\t\t}\n\t\telse {\n\t\t\tregistry.getMeters().stream().map(this::getName).forEach(names::add);\n\t\t}\n\t}\n\n\tprivate String getName(Meter meter) {\n\t\treturn meter.getId().getName();\n\t}\n\n\t@ReadOperation\n\tpublic @Nullable MetricDescriptor metric(@Selector String requiredMetricName, @Nullable List<String> tag) {\n\t\tList<Tag> tags = parseTags(tag);\n\t\tCollection<Meter> meters = findFirstMatchingMeters(this.registry, requiredMetricName, tags);\n\t\tif (meters.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<Statistic, Double> samples = getSamples(meters);\n\t\tMap<String, Set<String>> availableTags = getAvailableTags(meters);\n\t\ttags.forEach((t) -> availableTags.remove(t.getKey()));\n\t\tMeter.Id meterId = meters.iterator().next().getId();\n\t\treturn new MetricDescriptor(requiredMetricName, meterId.getDescription(), meterId.getBaseUnit(),\n\t\t\t\tasList(samples, Sample::new), asList(availableTags, AvailableTag::new));\n\t}\n\n\tprivate List<Tag> parseTags(@Nullable List<String> tags) {\n\t\treturn (tags != null) ? tags.stream().map(this::parseTag).toList() : Collections.emptyList();\n\t}\n\n\tprivate Tag parseTag(String tag) {\n\t\tString[] parts = tag.split(\":\", 2);\n\t\tif (parts.length != 2) {\n\t\t\tthrow new InvalidEndpointRequestException(\n\t\t\t\t\t\"Each tag parameter must be in the form 'key:value' but was: \" + tag,\n\t\t\t\t\t\"Each tag parameter must be in the form 'key:value'\");\n\t\t}\n\t\treturn Tag.of(parts[0], parts[1]);\n\t}\n\n\tprivate Collection<Meter> findFirstMatchingMeters(MeterRegistry registry, String name, Iterable<Tag> tags) {\n\t\tif (registry instanceof CompositeMeterRegistry compositeMeterRegistry) {\n\t\t\treturn findFirstMatchingMeters(compositeMeterRegistry, name, tags);\n\t\t}\n\t\treturn registry.find(name).tags(tags).meters();\n\t}\n\n\tprivate Collection<Meter> findFirstMatchingMeters(CompositeMeterRegistry composite, String name,\n\t\t\tIterable<Tag> tags) {\n\t\treturn composite.getRegistries()\n\t\t\t.stream()\n\t\t\t.map((registry) -> findFirstMatchingMeters(registry, name, tags))\n\t\t\t.filter((matching) -> !matching.isEmpty())\n\t\t\t.findFirst()\n\t\t\t.orElse(Collections.emptyList());\n\t}\n\n\tprivate Map<Statistic, Double> getSamples(Collection<Meter> meters) {\n\t\tMap<Statistic, Double> samples = new LinkedHashMap<>();\n\t\tmeters.forEach((meter) -> mergeMeasurements(samples, meter));\n\t\treturn samples;\n\t}\n\n\tprivate void mergeMeasurements(Map<Statistic, Double> samples, Meter meter) {\n\t\tmeter.measure()\n\t\t\t.forEach((measurement) -> samples.merge(measurement.getStatistic(), measurement.getValue(),\n\t\t\t\t\tmergeFunction(measurement.getStatistic())));\n\t}\n\n\tprivate BiFunction<Double, Double, Double> mergeFunction(Statistic statistic) {\n\t\treturn Statistic.MAX.equals(statistic) ? Double::max : Double::sum;\n\t}\n\n\tprivate Map<String, Set<String>> getAvailableTags(Collection<Meter> meters) {\n\t\tMap<String, Set<String>> availableTags = new HashMap<>();\n\t\tmeters.forEach((meter) -> mergeAvailableTags(availableTags, meter));\n\t\treturn availableTags;\n\t}\n\n\tprivate void mergeAvailableTags(Map<String, Set<String>> availableTags, Meter meter) {\n\t\tmeter.getId().getTags().forEach((tag) -> {\n\t\t\tSet<String> value = Collections.singleton(tag.getValue());\n\t\t\tavailableTags.merge(tag.getKey(), value, this::merge);\n\t\t});\n\t}\n\n\tprivate <T> Set<T> merge(Set<T> set1, Set<T> set2) {\n\t\tSet<T> result = new HashSet<>(set1.size() + set2.size());\n\t\tresult.addAll(set1);\n\t\tresult.addAll(set2);\n\t\treturn result;\n\t}\n\n\tprivate <K, V, T> List<T> asList(Map<K, V> map, BiFunction<K, V, T> mapper) {\n\t\treturn map.entrySet().stream().map((entry) -> mapper.apply(entry.getKey(), entry.getValue())).toList();\n\t}\n\n\t/**\n\t * Description of metric names.\n\t */\n\tpublic static final class MetricNamesDescriptor implements OperationResponseBody {\n\n\t\tprivate final Set<String> names;\n\n\t\tMetricNamesDescriptor(Set<String> names) {\n\t\t\tthis.names = names;\n\t\t}\n\n\t\tpublic Set<String> getNames() {\n\t\t\treturn this.names;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a metric.\n\t */\n\tpublic static final class MetricDescriptor implements OperationResponseBody {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable String description;\n\n\t\tprivate final @Nullable String baseUnit;\n\n\t\tprivate final List<Sample> measurements;\n\n\t\tprivate final List<AvailableTag> availableTags;\n\n\t\tMetricDescriptor(String name, @Nullable String description, @Nullable String baseUnit,\n\t\t\t\tList<Sample> measurements, List<AvailableTag> availableTags) {\n\t\t\tthis.name = name;\n\t\t\tthis.description = description;\n\t\t\tthis.baseUnit = baseUnit;\n\t\t\tthis.measurements = measurements;\n\t\t\tthis.availableTags = availableTags;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic @Nullable String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tpublic @Nullable String getBaseUnit() {\n\t\t\treturn this.baseUnit;\n\t\t}\n\n\t\tpublic List<Sample> getMeasurements() {\n\t\t\treturn this.measurements;\n\t\t}\n\n\t\tpublic List<AvailableTag> getAvailableTags() {\n\t\t\treturn this.availableTags;\n\t\t}\n\n\t}\n\n\t/**\n\t * A set of tags for further dimensional drill-down and their potential values.\n\t */\n\tpublic static final class AvailableTag {\n\n\t\tprivate final String tag;\n\n\t\tprivate final Set<String> values;\n\n\t\tAvailableTag(String tag, Set<String> values) {\n\t\t\tthis.tag = tag;\n\t\t\tthis.values = values;\n\t\t}\n\n\t\tpublic String getTag() {\n\t\t\treturn this.tag;\n\t\t}\n\n\t\tpublic Set<String> getValues() {\n\t\t\treturn this.values;\n\t\t}\n\n\t}\n\n\t/**\n\t * A measurement sample combining a {@link Statistic statistic} and a value.\n\t */\n\tpublic static final class Sample {\n\n\t\tprivate final Statistic statistic;\n\n\t\tprivate final Double value;\n\n\t\tSample(Statistic statistic, Double value) {\n\t\t\tthis.statistic = statistic;\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic Statistic getStatistic() {\n\t\t\treturn this.statistic;\n\t\t}\n\n\t\tpublic Double getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"MeasurementSample{statistic=\" + this.statistic + \", value=\" + this.value + '}';\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/AutoConfiguredCompositeMeterRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\n\n/**\n * Specialization of {@link CompositeMeterRegistry} used to identify the auto-configured\n * composite.\n *\n * @author Andy Wilkinson\n */\nclass AutoConfiguredCompositeMeterRegistry extends CompositeMeterRegistry {\n\n\tAutoConfiguredCompositeMeterRegistry(Clock clock, List<MeterRegistry> registries) {\n\t\tsuper(clock, registries);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/CompositeMeterRegistryAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a\n * {@link CompositeMeterRegistry}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@Import({ NoOpMeterRegistryConfiguration.class, CompositeMeterRegistryConfiguration.class })\n@ConditionalOnClass(CompositeMeterRegistry.class)\npublic final class CompositeMeterRegistryAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/CompositeMeterRegistryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryConfiguration.MultipleNonPrimaryMeterRegistriesCondition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Configuration for a {@link CompositeMeterRegistry}.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@Conditional(MultipleNonPrimaryMeterRegistriesCondition.class)\nclass CompositeMeterRegistryConfiguration {\n\n\t@Bean\n\t@Primary\n\tAutoConfiguredCompositeMeterRegistry compositeMeterRegistry(Clock clock, List<MeterRegistry> registries) {\n\t\treturn new AutoConfiguredCompositeMeterRegistry(clock, registries);\n\t}\n\n\tstatic class MultipleNonPrimaryMeterRegistriesCondition extends NoneNestedConditions {\n\n\t\tMultipleNonPrimaryMeterRegistriesCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnMissingBean(MeterRegistry.class)\n\t\tstatic class NoMeterRegistryCondition {\n\n\t\t}\n\n\t\t@ConditionalOnSingleCandidate(MeterRegistry.class)\n\t\tstatic class SingleInjectableMeterRegistry {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.MeterRegistry;\n\n/**\n * Callback interface that can be used to customize auto-configured {@link MeterRegistry\n * MeterRegistries}.\n * <p>\n * Customizers are guaranteed to be applied before any {@link Meter} is registered with\n * the registry.\n *\n * @param <T> the registry type to customize\n * @author Jon Schneider\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface MeterRegistryCustomizer<T extends MeterRegistry> {\n\n\t/**\n\t * Customize the given {@code registry}.\n\t * @param registry the registry to customize\n\t */\n\tvoid customize(T registry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Metrics;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.config.MeterFilter;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * {@link BeanPostProcessor} for {@link MeterRegistry} beans.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass MeterRegistryPostProcessor implements BeanPostProcessor, SmartInitializingSingleton {\n\n\tprivate final CompositeMeterRegistries compositeMeterRegistries;\n\n\tprivate final ObjectProvider<MetricsProperties> properties;\n\n\tprivate final ObjectProvider<MeterRegistryCustomizer<?>> customizers;\n\n\tprivate final ObjectProvider<MeterFilter> filters;\n\n\tprivate final ObjectProvider<MeterBinder> binders;\n\n\tprivate volatile boolean deferBinding = true;\n\n\tprivate final Set<MeterRegistry> deferredBindings = new LinkedHashSet<>();\n\n\tMeterRegistryPostProcessor(ApplicationContext applicationContext,\n\t\t\tObjectProvider<MetricsProperties> metricsProperties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,\n\t\t\tObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {\n\t\tthis(CompositeMeterRegistries.of(applicationContext), metricsProperties, customizers, filters, binders);\n\t}\n\n\tMeterRegistryPostProcessor(CompositeMeterRegistries compositeMeterRegistries,\n\t\t\tObjectProvider<MetricsProperties> properties, ObjectProvider<MeterRegistryCustomizer<?>> customizers,\n\t\t\tObjectProvider<MeterFilter> filters, ObjectProvider<MeterBinder> binders) {\n\t\tthis.compositeMeterRegistries = compositeMeterRegistries;\n\t\tthis.properties = properties;\n\t\tthis.customizers = customizers;\n\t\tthis.filters = filters;\n\t\tthis.binders = binders;\n\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof MeterRegistry meterRegistry) {\n\t\t\tpostProcessMeterRegistry(meterRegistry);\n\t\t}\n\t\treturn bean;\n\t}\n\n\t@Override\n\tpublic void afterSingletonsInstantiated() {\n\t\tsynchronized (this.deferredBindings) {\n\t\t\tthis.deferBinding = false;\n\t\t\tthis.deferredBindings.forEach(this::applyBinders);\n\t\t}\n\t}\n\n\tprivate void postProcessMeterRegistry(MeterRegistry meterRegistry) {\n\t\t// Customizers must be applied before binders, as they may add custom tags or\n\t\t// alter timer or summary configuration.\n\t\tapplyCustomizers(meterRegistry);\n\t\tapplyFilters(meterRegistry);\n\t\taddToGlobalRegistryIfNecessary(meterRegistry);\n\t\tif (isBindable(meterRegistry)) {\n\t\t\tapplyBinders(meterRegistry);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void applyCustomizers(MeterRegistry meterRegistry) {\n\t\tList<MeterRegistryCustomizer<?>> customizers = this.customizers.orderedStream().toList();\n\t\tLambdaSafe.callbacks(MeterRegistryCustomizer.class, customizers, meterRegistry)\n\t\t\t.withLogger(MeterRegistryPostProcessor.class)\n\t\t\t.invoke((customizer) -> customizer.customize(meterRegistry));\n\t}\n\n\tprivate void applyFilters(MeterRegistry meterRegistry) {\n\t\tif (this.filters != null) {\n\t\t\tStream<MeterFilter> filters = this.filters.orderedStream();\n\t\t\tif (isAutoConfiguredComposite(meterRegistry)) {\n\t\t\t\tfilters = filters.filter(MaximumAllowableTagsMeterFilter.class::isInstance);\n\t\t\t}\n\t\t\tfilters.forEach(meterRegistry.config()::meterFilter);\n\t\t}\n\t}\n\n\tprivate void addToGlobalRegistryIfNecessary(MeterRegistry meterRegistry) {\n\t\tif (this.properties.getObject().isUseGlobalRegistry() && !isGlobalRegistry(meterRegistry)) {\n\t\t\tMetrics.addRegistry(meterRegistry);\n\t\t}\n\t}\n\n\tprivate boolean isGlobalRegistry(MeterRegistry meterRegistry) {\n\t\treturn meterRegistry == Metrics.globalRegistry;\n\t}\n\n\tprivate boolean isBindable(MeterRegistry meterRegistry) {\n\t\treturn isAutoConfiguredComposite(meterRegistry) || isCompositeWithOnlyUserDefinedComposites(meterRegistry)\n\t\t\t\t|| noCompositeMeterRegistries();\n\t}\n\n\tprivate boolean isAutoConfiguredComposite(MeterRegistry meterRegistry) {\n\t\treturn meterRegistry instanceof AutoConfiguredCompositeMeterRegistry;\n\t}\n\n\tprivate boolean isCompositeWithOnlyUserDefinedComposites(MeterRegistry meterRegistry) {\n\t\treturn this.compositeMeterRegistries == CompositeMeterRegistries.ONLY_USER_DEFINED\n\t\t\t\t&& meterRegistry instanceof CompositeMeterRegistry;\n\t}\n\n\tprivate boolean noCompositeMeterRegistries() {\n\t\treturn this.compositeMeterRegistries == CompositeMeterRegistries.NONE;\n\t}\n\n\tvoid applyBinders(MeterRegistry meterRegistry) {\n\t\tif (this.deferBinding) {\n\t\t\tsynchronized (this.deferredBindings) {\n\t\t\t\tif (this.deferBinding) {\n\t\t\t\t\tthis.deferredBindings.add(meterRegistry);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.binders.orderedStream().forEach((binder) -> binder.bindTo(meterRegistry));\n\t}\n\n\tenum CompositeMeterRegistries {\n\n\t\tNONE, AUTO_CONFIGURED, ONLY_USER_DEFINED;\n\n\t\tprivate static CompositeMeterRegistries of(ApplicationContext context) {\n\t\t\tif (hasBeansOfType(AutoConfiguredCompositeMeterRegistry.class, context)) {\n\t\t\t\treturn AUTO_CONFIGURED;\n\t\t\t}\n\t\t\treturn hasBeansOfType(CompositeMeterRegistry.class, context) ? ONLY_USER_DEFINED : NONE;\n\t\t}\n\n\t\tprivate static boolean hasBeansOfType(Class<?> type, ApplicationContext context) {\n\t\t\treturn context.getBeanNamesForType(type, false, false).length > 0;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterValue.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.Meter.Type;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.convert.DurationStyle;\n\n/**\n * A meter value that is used when configuring micrometer. Can be a String representation\n * of either a {@link Double} (applicable to timers and distribution summaries) or a\n * {@link Duration} (applicable to only timers).\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class MeterValue {\n\n\tprivate final Object value;\n\n\tMeterValue(double value) {\n\t\tthis.value = value;\n\t}\n\n\tMeterValue(Duration value) {\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Return the underlying value in form suitable to apply to the given meter type.\n\t * @param meterType the meter type\n\t * @return the value or {@code null} if the value cannot be applied\n\t */\n\tpublic @Nullable Double getValue(Type meterType) {\n\t\tif (meterType == Type.DISTRIBUTION_SUMMARY) {\n\t\t\treturn getDistributionSummaryValue();\n\t\t}\n\t\tif (meterType == Type.TIMER) {\n\t\t\tLong timerValue = getTimerValue();\n\t\t\tif (timerValue != null) {\n\t\t\t\treturn timerValue.doubleValue();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable Double getDistributionSummaryValue() {\n\t\tif (this.value instanceof Double doubleValue) {\n\t\t\treturn doubleValue;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable Long getTimerValue() {\n\t\tif (this.value instanceof Double doubleValue) {\n\t\t\treturn TimeUnit.MILLISECONDS.toNanos(doubleValue.longValue());\n\t\t}\n\t\tif (this.value instanceof Duration duration) {\n\t\t\treturn duration.toNanos();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return a new {@link MeterValue} instance for the given String value. The value may\n\t * contain a simple number, or a {@link DurationStyle duration style string}.\n\t * @param value the source value\n\t * @return a {@link MeterValue} instance\n\t */\n\tpublic static MeterValue valueOf(String value) {\n\t\tDuration duration = safeParseDuration(value);\n\t\tif (duration != null) {\n\t\t\treturn new MeterValue(duration);\n\t\t}\n\t\treturn new MeterValue(Double.parseDouble(value));\n\t}\n\n\t/**\n\t * Return a new {@link MeterValue} instance for the given double value.\n\t * @param value the source value\n\t * @return a {@link MeterValue} instance\n\t */\n\tpublic static MeterValue valueOf(double value) {\n\t\treturn new MeterValue(value);\n\t}\n\n\tprivate static @Nullable Duration safeParseDuration(String value) {\n\t\ttry {\n\t\t\treturn DurationStyle.detectAndParse(value);\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAspectsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport io.micrometer.core.aop.CountedAspect;\nimport io.micrometer.core.aop.CountedMeterTagAnnotationHandler;\nimport io.micrometer.core.aop.MeterTagAnnotationHandler;\nimport io.micrometer.core.aop.TimedAspect;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport org.aspectj.weaver.Advice;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics\n * aspects.\n *\n * @author Jonatan Ivanov\n * @author Dominique Villard\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class,\n\t\tObservationAutoConfiguration.class })\n@ConditionalOnClass({ MeterRegistry.class, Advice.class })\n@ConditionalOnBooleanProperty(\"management.observations.annotations.enabled\")\n@ConditionalOnBean(MeterRegistry.class)\npublic final class MetricsAspectsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCountedAspect countedAspect(MeterRegistry registry,\n\t\t\tObjectProvider<CountedMeterTagAnnotationHandler> countedMeterTagAnnotationHandler) {\n\t\tCountedAspect countedAspect = new CountedAspect(registry);\n\t\tcountedMeterTagAnnotationHandler.ifAvailable(countedAspect::setMeterTagAnnotationHandler);\n\t\treturn countedAspect;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tTimedAspect timedAspect(MeterRegistry registry,\n\t\t\tObjectProvider<MeterTagAnnotationHandler> meterTagAnnotationHandler) {\n\t\tTimedAspect timedAspect = new TimedAspect(registry);\n\t\tmeterTagAnnotationHandler.ifAvailable(timedAspect::setMeterTagAnnotationHandler);\n\t\treturn timedAspect;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ValueExpressionResolver.class)\n\tstatic class TagAnnotationHandlersConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tCountedMeterTagAnnotationHandler countedMeterTagAnnotationHandler(BeanFactory beanFactory,\n\t\t\t\tValueExpressionResolver valueExpressionResolver) {\n\t\t\treturn new CountedMeterTagAnnotationHandler(beanFactory::getBean, (ignored) -> valueExpressionResolver);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tMeterTagAnnotationHandler meterTagAnnotationHandler(BeanFactory beanFactory,\n\t\t\t\tValueExpressionResolver valueExpressionResolver) {\n\t\t\treturn new MeterTagAnnotationHandler(beanFactory::getBean, (ignored) -> valueExpressionResolver);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.annotation.Timed;\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.config.MeterFilter;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGroup;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Michael Berry\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class)\n@ConditionalOnClass(Timed.class)\n@EnableConfigurationProperties(MetricsProperties.class)\npublic final class MetricsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tClock micrometerClock() {\n\t\treturn Clock.SYSTEM;\n\t}\n\n\t@Bean\n\tstatic MeterRegistryPostProcessor meterRegistryPostProcessor(ApplicationContext applicationContext,\n\t\t\tObjectProvider<MetricsProperties> metricsProperties,\n\t\t\tObjectProvider<MeterRegistryCustomizer<?>> meterRegistryCustomizers,\n\t\t\tObjectProvider<MeterFilter> meterFilters, ObjectProvider<MeterBinder> meterBinders) {\n\t\treturn new MeterRegistryPostProcessor(applicationContext, metricsProperties, meterRegistryCustomizers,\n\t\t\t\tmeterFilters, meterBinders);\n\t}\n\n\t@Bean\n\t@Order(0)\n\tPropertiesMeterFilter propertiesMeterFilter(MetricsProperties properties) {\n\t\treturn new PropertiesMeterFilter(properties);\n\t}\n\n\t@Bean\n\tMeterRegistryCloser meterRegistryCloser(ApplicationContext context) {\n\t\treturn new MeterRegistryCloser(context);\n\t}\n\n\t@Bean\n\tObservationHandlerGroup metricsObservationHandlerGroup() {\n\t\treturn ObservationHandlerGroup.of(MeterObservationHandler.class);\n\t}\n\n\t@Bean\n\tDefaultMeterObservationHandler defaultMeterObservationHandler(ObjectProvider<MeterRegistry> meterRegistryProvider,\n\t\t\tClock clock, MetricsProperties properties) {\n\t\tMeterRegistry meterRegistry = meterRegistryProvider.getIfAvailable(() -> new CompositeMeterRegistry(clock));\n\t\treturn new DefaultMeterObservationHandler(meterRegistry,\n\t\t\t\tproperties.getObservations().getIgnoredMeters().toArray(IgnoredMeters[]::new));\n\t}\n\n\t/**\n\t * Ensures that {@link MeterRegistry meter registries} are closed early in the\n\t * shutdown process.\n\t */\n\tstatic class MeterRegistryCloser implements ApplicationListener<ContextClosedEvent> {\n\n\t\tprivate final ApplicationContext context;\n\n\t\tprivate final Iterable<MeterRegistry> meterRegistries;\n\n\t\tMeterRegistryCloser(ApplicationContext context) {\n\t\t\tthis.meterRegistries = context.getBeansOfType(MeterRegistry.class).values();\n\t\t\tthis.context = context;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ContextClosedEvent event) {\n\t\t\tif (this.context.equals(event.getApplicationContext())) {\n\t\t\t\tfor (MeterRegistry meterRegistry : this.meterRegistries) {\n\t\t\t\t\tif (!meterRegistry.isClosed()) {\n\t\t\t\t\t\tmeterRegistry.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.annotation.Timed;\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link MetricsEndpoint}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })\n@ConditionalOnClass({ ConditionalOnAvailableEndpoint.class, Timed.class })\n@ConditionalOnAvailableEndpoint(MetricsEndpoint.class)\npublic final class MetricsEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(MeterRegistry.class)\n\t@ConditionalOnMissingBean\n\tMetricsEndpoint metricsEndpoint(MeterRegistry registry) {\n\t\treturn new MetricsEndpoint(registry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring\n * Micrometer-based metrics.\n *\n * @author Jon Schneider\n * @author Alexander Abramov\n * @author Tadaya Tsuyukubo\n * @author Chris Bono\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.metrics\")\npublic class MetricsProperties {\n\n\t/**\n\t * Whether auto-configured MeterRegistry implementations should be bound to the global\n\t * static registry on Metrics. For testing, set this to 'false' to maximize test\n\t * independence.\n\t */\n\tprivate boolean useGlobalRegistry = true;\n\n\t/**\n\t * Whether meter IDs starting with the specified name should be enabled. The longest\n\t * match wins, the key 'all' can also be used to configure all meters.\n\t */\n\tprivate final Map<String, Boolean> enable = new LinkedHashMap<>();\n\n\t/**\n\t * Common tags that are applied to every meter.\n\t */\n\tprivate final Map<String, String> tags = new LinkedHashMap<>();\n\n\tprivate final Web web = new Web();\n\n\tprivate final System system = new System();\n\n\tprivate final Distribution distribution = new Distribution();\n\n\tprivate final Observations observations = new Observations();\n\n\tpublic boolean isUseGlobalRegistry() {\n\t\treturn this.useGlobalRegistry;\n\t}\n\n\tpublic void setUseGlobalRegistry(boolean useGlobalRegistry) {\n\t\tthis.useGlobalRegistry = useGlobalRegistry;\n\t}\n\n\tpublic Map<String, Boolean> getEnable() {\n\t\treturn this.enable;\n\t}\n\n\tpublic Map<String, String> getTags() {\n\t\treturn this.tags;\n\t}\n\n\tpublic Web getWeb() {\n\t\treturn this.web;\n\t}\n\n\tpublic System getSystem() {\n\t\treturn this.system;\n\t}\n\n\tpublic Distribution getDistribution() {\n\t\treturn this.distribution;\n\t}\n\n\tpublic Observations getObservations() {\n\t\treturn this.observations;\n\t}\n\n\tpublic static class Web {\n\n\t\tprivate final Client client = new Client();\n\n\t\tprivate final Server server = new Server();\n\n\t\tpublic Client getClient() {\n\t\t\treturn this.client;\n\t\t}\n\n\t\tpublic Server getServer() {\n\t\t\treturn this.server;\n\t\t}\n\n\t\tpublic static class Client {\n\n\t\t\t/**\n\t\t\t * Maximum number of unique URI tag values allowed. After the max number of\n\t\t\t * tag values is reached, metrics with additional tag values are denied by\n\t\t\t * filter.\n\t\t\t */\n\t\t\tprivate int maxUriTags = 100;\n\n\t\t\tpublic int getMaxUriTags() {\n\t\t\t\treturn this.maxUriTags;\n\t\t\t}\n\n\t\t\tpublic void setMaxUriTags(int maxUriTags) {\n\t\t\t\tthis.maxUriTags = maxUriTags;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Server {\n\n\t\t\t/**\n\t\t\t * Maximum number of unique URI tag values allowed. After the max number of\n\t\t\t * tag values is reached, metrics with additional tag values are denied by\n\t\t\t * filter.\n\t\t\t */\n\t\t\tprivate int maxUriTags = 100;\n\n\t\t\tpublic int getMaxUriTags() {\n\t\t\t\treturn this.maxUriTags;\n\t\t\t}\n\n\t\t\tpublic void setMaxUriTags(int maxUriTags) {\n\t\t\t\tthis.maxUriTags = maxUriTags;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class System {\n\n\t\tprivate final Diskspace diskspace = new Diskspace();\n\n\t\tpublic Diskspace getDiskspace() {\n\t\t\treturn this.diskspace;\n\t\t}\n\n\t\tpublic static class Diskspace {\n\n\t\t\t/**\n\t\t\t * List of paths to report disk metrics for.\n\t\t\t */\n\t\t\tprivate List<File> paths = new ArrayList<>(Collections.singletonList(new File(\".\")));\n\n\t\t\tpublic List<File> getPaths() {\n\t\t\t\treturn this.paths;\n\t\t\t}\n\n\t\t\tpublic void setPaths(List<File> paths) {\n\t\t\t\tthis.paths = paths;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Distribution {\n\n\t\t/**\n\t\t * Whether meter IDs starting with the specified name should publish percentile\n\t\t * histograms. For monitoring systems that support aggregable percentile\n\t\t * calculation based on a histogram, this can be set to true. For other systems,\n\t\t * this has no effect. The longest match wins, the key 'all' can also be used to\n\t\t * configure all meters.\n\t\t */\n\t\tprivate final Map<String, Boolean> percentilesHistogram = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Specific computed non-aggregable percentiles to ship to the backend for meter\n\t\t * IDs starting-with the specified name. The longest match wins, the key 'all' can\n\t\t * also be used to configure all meters.\n\t\t */\n\t\tprivate final Map<String, double[]> percentiles = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Specific service-level objective boundaries for meter IDs starting with the\n\t\t * specified name. The longest match wins. Counters will be published for each\n\t\t * specified boundary. Values can be specified as a double or as a Duration value\n\t\t * (for timer meters, defaulting to ms if no unit specified).\n\t\t */\n\t\tprivate final Map<String, ServiceLevelObjectiveBoundary[]> slo = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Minimum value that meter IDs starting with the specified name are expected to\n\t\t * observe. The longest match wins. Values can be specified as a double or as a\n\t\t * Duration value (for timer meters, defaulting to ms if no unit specified).\n\t\t */\n\t\tprivate final Map<String, String> minimumExpectedValue = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Maximum value that meter IDs starting with the specified name are expected to\n\t\t * observe. The longest match wins. Values can be specified as a double or as a\n\t\t * Duration value (for timer meters, defaulting to ms if no unit specified).\n\t\t */\n\t\tprivate final Map<String, String> maximumExpectedValue = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Maximum amount of time that samples for meter IDs starting with the specified\n\t\t * name are accumulated to decaying distribution statistics before they are reset\n\t\t * and rotated. The longest match wins, the key `all` can also be used to\n\t\t * configure all meters.\n\t\t */\n\t\tprivate final Map<String, Duration> expiry = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * Number of histograms for meter IDs starting with the specified name to keep in\n\t\t * the ring buffer. The longest match wins, the key `all` can also be used to\n\t\t * configure all meters.\n\t\t */\n\t\tprivate final Map<String, Integer> bufferLength = new LinkedHashMap<>();\n\n\t\tpublic Map<String, Boolean> getPercentilesHistogram() {\n\t\t\treturn this.percentilesHistogram;\n\t\t}\n\n\t\tpublic Map<String, double[]> getPercentiles() {\n\t\t\treturn this.percentiles;\n\t\t}\n\n\t\tpublic Map<String, ServiceLevelObjectiveBoundary[]> getSlo() {\n\t\t\treturn this.slo;\n\t\t}\n\n\t\tpublic Map<String, String> getMinimumExpectedValue() {\n\t\t\treturn this.minimumExpectedValue;\n\t\t}\n\n\t\tpublic Map<String, String> getMaximumExpectedValue() {\n\t\t\treturn this.maximumExpectedValue;\n\t\t}\n\n\t\tpublic Map<String, Duration> getExpiry() {\n\t\t\treturn this.expiry;\n\t\t}\n\n\t\tpublic Map<String, Integer> getBufferLength() {\n\t\t\treturn this.bufferLength;\n\t\t}\n\n\t}\n\n\tpublic static class Observations {\n\n\t\t/**\n\t\t * Meters that should be ignored when recoding observations.\n\t\t */\n\t\tprivate Set<IgnoredMeters> ignoredMeters = new LinkedHashSet<>();\n\n\t\tpublic Set<IgnoredMeters> getIgnoredMeters() {\n\t\t\treturn this.ignoredMeters;\n\t\t}\n\n\t\tpublic void setIgnoredMeters(Set<IgnoredMeters> ignoredMeters) {\n\t\t\tthis.ignoredMeters = ignoredMeters;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/NoOpMeterRegistryConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for a no-op meter registry when the context does not contain an\n * auto-configured {@link MeterRegistry}.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnMissingBean(MeterRegistry.class)\nclass NoOpMeterRegistryConfiguration {\n\n\t@Bean\n\tCompositeMeterRegistry noOpMeterRegistry(Clock clock) {\n\t\treturn new CompositeMeterRegistry(clock);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/PropertiesMeterFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Objects;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.Meter.Id;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.config.MeterFilter;\nimport io.micrometer.core.instrument.config.MeterFilterReply;\nimport io.micrometer.core.instrument.distribution.DistributionStatisticConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties.Distribution;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link MeterFilter} to apply settings from {@link MetricsProperties}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @author Alexander Abramov\n * @since 4.0.0\n */\npublic class PropertiesMeterFilter implements MeterFilter {\n\n\tprivate final MetricsProperties properties;\n\n\tprivate final MeterFilter mapFilter;\n\n\tpublic PropertiesMeterFilter(MetricsProperties properties) {\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tthis.properties = properties;\n\t\tthis.mapFilter = createMapFilter(properties.getTags());\n\t}\n\n\tprivate static MeterFilter createMapFilter(Map<String, String> tags) {\n\t\tif (tags.isEmpty()) {\n\t\t\treturn new MeterFilter() {\n\t\t\t};\n\t\t}\n\t\tTags commonTags = Tags.of(tags.entrySet().stream().map(PropertiesMeterFilter::asTag).toList());\n\t\treturn MeterFilter.commonTags(commonTags);\n\t}\n\n\tprivate static Tag asTag(Entry<String, String> entry) {\n\t\treturn Tag.of(entry.getKey(), entry.getValue());\n\t}\n\n\t@Override\n\tpublic MeterFilterReply accept(Meter.Id id) {\n\t\tboolean enabled = lookupWithFallbackToAll(this.properties.getEnable(), id, true);\n\t\treturn enabled ? MeterFilterReply.NEUTRAL : MeterFilterReply.DENY;\n\t}\n\n\t@Override\n\tpublic Id map(Id id) {\n\t\treturn this.mapFilter.map(id);\n\t}\n\n\t@Override\n\tpublic DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {\n\t\tDistribution distribution = this.properties.getDistribution();\n\t\treturn DistributionStatisticConfig.builder()\n\t\t\t.percentilesHistogram(lookupWithFallbackToAll(distribution.getPercentilesHistogram(), id, null))\n\t\t\t.percentiles(lookupWithFallbackToAll(distribution.getPercentiles(), id, null))\n\t\t\t.serviceLevelObjectives(convertServiceLevelObjectives(id.getType(), lookup(distribution.getSlo(), id)))\n\t\t\t.minimumExpectedValue(convertMeterValue(id.getType(), lookup(distribution.getMinimumExpectedValue(), id)))\n\t\t\t.maximumExpectedValue(convertMeterValue(id.getType(), lookup(distribution.getMaximumExpectedValue(), id)))\n\t\t\t.expiry(lookupWithFallbackToAll(distribution.getExpiry(), id, null))\n\t\t\t.bufferLength(lookupWithFallbackToAll(distribution.getBufferLength(), id, null))\n\t\t\t.build()\n\t\t\t.merge(config);\n\t}\n\n\tprivate double @Nullable [] convertServiceLevelObjectives(Meter.Type meterType,\n\t\t\tServiceLevelObjectiveBoundary @Nullable [] slo) {\n\t\tif (slo == null) {\n\t\t\treturn null;\n\t\t}\n\t\tdouble[] converted = Arrays.stream(slo)\n\t\t\t.map((candidate) -> candidate.getValue(meterType))\n\t\t\t.filter(Objects::nonNull)\n\t\t\t.mapToDouble(Double::doubleValue)\n\t\t\t.toArray();\n\t\treturn (converted.length != 0) ? converted : null;\n\t}\n\n\tprivate @Nullable Double convertMeterValue(Meter.Type meterType, @Nullable String value) {\n\t\treturn (value != null) ? MeterValue.valueOf(value).getValue(meterType) : null;\n\t}\n\n\tprivate <T> @Nullable T lookup(Map<String, T> values, Id id) {\n\t\tif (values.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn doLookup(values, id);\n\t}\n\n\t@Contract(\"_, _, !null -> !null\")\n\tprivate <T> @Nullable T lookupWithFallbackToAll(Map<String, T> values, Id id, @Nullable T defaultValue) {\n\t\tif (values.isEmpty()) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\t@Nullable T result = doLookup(values, id);\n\t\treturn (result != null) ? result : values.getOrDefault(\"all\", defaultValue);\n\t}\n\n\tprivate <T> @Nullable T doLookup(Map<String, T> values, Id id) {\n\t\tString name = id.getName();\n\t\twhile (StringUtils.hasLength(name)) {\n\t\t\tT result = values.get(name);\n\t\t\tif (result != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tint lastDot = name.lastIndexOf('.');\n\t\t\tname = (lastDot != -1) ? name.substring(0, lastDot) : \"\";\n\t\t}\n\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/ServiceLevelObjectiveBoundary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.Meter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * A boundary for a service-level objective (SLO) for use when configuring Micrometer. Can\n * be specified as either a {@link Double} (applicable to timers and distribution\n * summaries) or a {@link Duration} (applicable to only timers).\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class ServiceLevelObjectiveBoundary {\n\n\tprivate final MeterValue value;\n\n\tServiceLevelObjectiveBoundary(MeterValue value) {\n\t\tthis.value = value;\n\t}\n\n\t/**\n\t * Return the underlying value of the SLO in form suitable to apply to the given meter\n\t * type.\n\t * @param meterType the meter type\n\t * @return the value or {@code null} if the value cannot be applied\n\t */\n\tpublic @Nullable Double getValue(Meter.Type meterType) {\n\t\treturn this.value.getValue(meterType);\n\t}\n\n\t/**\n\t * Return a new {@link ServiceLevelObjectiveBoundary} instance for the given double\n\t * value.\n\t * @param value the source value\n\t * @return a {@link ServiceLevelObjectiveBoundary} instance\n\t */\n\tpublic static ServiceLevelObjectiveBoundary valueOf(double value) {\n\t\treturn new ServiceLevelObjectiveBoundary(MeterValue.valueOf(value));\n\t}\n\n\t/**\n\t * Return a new {@link ServiceLevelObjectiveBoundary} instance for the given String\n\t * value.\n\t * @param value the source value\n\t * @return a {@link ServiceLevelObjectiveBoundary} instance\n\t */\n\tpublic static ServiceLevelObjectiveBoundary valueOf(String value) {\n\t\treturn new ServiceLevelObjectiveBoundary(MeterValue.valueOf(value));\n\t}\n\n\tstatic class ServiceLevelObjectiveBoundaryHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(ServiceLevelObjectiveBoundary.class, MemberCategory.INVOKE_PUBLIC_METHODS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ConditionalOnEnabledMetricsExport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether a metrics exporter is enabled. If\n * the {@code management.<name>.metrics.export.enabled} property is configured then its\n * value is used to determine if it matches. Otherwise, matches if the value of the\n * {@code management.defaults.metrics.export.enabled} property is {@code true} or if it is\n * not configured.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnMetricsExportEnabledCondition.class)\npublic @interface ConditionalOnEnabledMetricsExport {\n\n\t/**\n\t * The name of the metrics exporter.\n\t * @return the name of the metrics exporter\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/OnMetricsExportEnabledCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Condition} that checks if a metrics exporter is enabled.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\nclass OnMetricsExportEnabledCondition extends SpringBootCondition {\n\n\tprivate static final String PROPERTY_TEMPLATE = \"management.%s.metrics.export.enabled\";\n\n\tprivate static final String DEFAULT_PROPERTY_NAME = \"management.defaults.metrics.export.enabled\";\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tAnnotationAttributes annotationAttributes = AnnotationAttributes\n\t\t\t.fromMap(metadata.getAnnotationAttributes(ConditionalOnEnabledMetricsExport.class.getName()));\n\t\tAssert.state(annotationAttributes != null, \"'annotationAttributes' must not be null\");\n\t\tString endpointName = annotationAttributes.getString(\"value\");\n\t\tConditionOutcome outcome = getProductOutcome(context, endpointName);\n\t\tif (outcome != null) {\n\t\t\treturn outcome;\n\t\t}\n\t\treturn getDefaultOutcome(context);\n\t}\n\n\tprivate @Nullable ConditionOutcome getProductOutcome(ConditionContext context, String productName) {\n\t\tEnvironment environment = context.getEnvironment();\n\t\tString enabledProperty = PROPERTY_TEMPLATE.formatted(productName);\n\t\tif (environment.containsProperty(enabledProperty)) {\n\t\t\tboolean match = environment.getProperty(enabledProperty, Boolean.class, true);\n\t\t\treturn new ConditionOutcome(match, ConditionMessage.forCondition(ConditionalOnEnabledMetricsExport.class)\n\t\t\t\t.because(enabledProperty + \" is \" + match));\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the default outcome that should be used if property is not set. By default\n\t * this method will use the {@link #DEFAULT_PROPERTY_NAME} property, matching if it is\n\t * {@code true} or if it is not configured.\n\t * @param context the condition context\n\t * @return the default outcome\n\t */\n\tprivate ConditionOutcome getDefaultOutcome(ConditionContext context) {\n\t\tboolean match = Boolean.parseBoolean(context.getEnvironment().getProperty(DEFAULT_PROPERTY_NAME, \"true\"));\n\t\treturn new ConditionOutcome(match, ConditionMessage.forCondition(ConditionalOnEnabledMetricsExport.class)\n\t\t\t.because(DEFAULT_PROPERTY_NAME + \" is considered \" + match));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/AppOpticsMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport io.micrometer.appoptics.AppOpticsConfig;\nimport io.micrometer.appoptics.AppOpticsMeterRegistry;\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to AppOptics.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(AppOpticsMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"appoptics\")\n@EnableConfigurationProperties(AppOpticsProperties.class)\npublic final class AppOpticsMetricsExportAutoConfiguration {\n\n\tprivate final AppOpticsProperties properties;\n\n\tAppOpticsMetricsExportAutoConfiguration(AppOpticsProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAppOpticsConfig appOpticsConfig() {\n\t\treturn new AppOpticsPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAppOpticsMeterRegistry appOpticsMeterRegistry(AppOpticsConfig config, Clock clock) {\n\t\treturn AppOpticsMeterRegistry.builder(config)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/AppOpticsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring AppOptics\n * metrics export.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.appoptics.metrics.export\")\npublic class AppOpticsProperties extends StepRegistryProperties {\n\n\t/**\n\t * URI to ship metrics to.\n\t */\n\tprivate String uri = \"https://api.appoptics.com/v1/measurements\";\n\n\t/**\n\t * AppOptics API token.\n\t */\n\tprivate @Nullable String apiToken;\n\n\t/**\n\t * Tag that will be mapped to \"@host\" when shipping metrics to AppOptics.\n\t */\n\tprivate String hostTag = \"instance\";\n\n\t/**\n\t * Whether to ship a floored time, useful when sending measurements from multiple\n\t * hosts to align them on a given time boundary.\n\t */\n\tprivate boolean floorTimes;\n\n\t/**\n\t * Number of measurements per request to use for this backend. If more measurements\n\t * are found, then multiple requests will be made.\n\t */\n\tprivate Integer batchSize = 500;\n\n\t/**\n\t * Connection timeout for requests to this backend.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(5);\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n\tpublic @Nullable String getApiToken() {\n\t\treturn this.apiToken;\n\t}\n\n\tpublic void setApiToken(@Nullable String apiToken) {\n\t\tthis.apiToken = apiToken;\n\t}\n\n\tpublic String getHostTag() {\n\t\treturn this.hostTag;\n\t}\n\n\tpublic void setHostTag(String hostTag) {\n\t\tthis.hostTag = hostTag;\n\t}\n\n\tpublic boolean isFloorTimes() {\n\t\treturn this.floorTimes;\n\t}\n\n\tpublic void setFloorTimes(boolean floorTimes) {\n\t\tthis.floorTimes = floorTimes;\n\t}\n\n\t@Override\n\tpublic Integer getBatchSize() {\n\t\treturn this.batchSize;\n\t}\n\n\t@Override\n\tpublic void setBatchSize(Integer batchSize) {\n\t\tthis.batchSize = batchSize;\n\t}\n\n\t@Override\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\t@Override\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/AppOpticsPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport io.micrometer.appoptics.AppOpticsConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link AppOpticsProperties} to an {@link AppOpticsConfig}.\n *\n * @author Stephane Nicoll\n */\nclass AppOpticsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<AppOpticsProperties>\n\t\timplements AppOpticsConfig {\n\n\tAppOpticsPropertiesConfigAdapter(AppOpticsProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.appoptics.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(AppOpticsProperties::getUri, AppOpticsConfig.super::uri);\n\t}\n\n\t@Override\n\tpublic String apiToken() {\n\t\treturn obtain(AppOpticsProperties::getApiToken, AppOpticsConfig.super::apiToken);\n\t}\n\n\t@Override\n\tpublic @Nullable String hostTag() {\n\t\treturn get(AppOpticsProperties::getHostTag, AppOpticsConfig.super::hostTag);\n\t}\n\n\t@Override\n\tpublic boolean floorTimes() {\n\t\treturn obtain(AppOpticsProperties::isFloorTimes, AppOpticsConfig.super::floorTimes);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to AppOptics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/AtlasMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport com.netflix.spectator.atlas.AtlasConfig;\nimport io.micrometer.atlas.AtlasMeterRegistry;\nimport io.micrometer.core.instrument.Clock;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Atlas.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(AtlasMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"atlas\")\n@EnableConfigurationProperties(AtlasProperties.class)\npublic final class AtlasMetricsExportAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAtlasConfig atlasConfig(AtlasProperties atlasProperties) {\n\t\treturn new AtlasPropertiesConfigAdapter(atlasProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAtlasMeterRegistry atlasMeterRegistry(AtlasConfig atlasConfig, Clock clock) {\n\t\treturn new AtlasMeterRegistry(atlasConfig, clock);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/AtlasProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Atlas metrics\n * export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.atlas.metrics.export\")\npublic class AtlasProperties {\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\t/**\n\t * Whether exporting of metrics to this backend is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Connection timeout for requests to this backend.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(1);\n\n\t/**\n\t * Read timeout for requests to this backend.\n\t */\n\tprivate Duration readTimeout = Duration.ofSeconds(10);\n\n\t/**\n\t * Number of threads to use with the metrics publishing scheduler.\n\t */\n\tprivate Integer numThreads = 4;\n\n\t/**\n\t * Number of measurements per request to use for this backend. If more measurements\n\t * are found, then multiple requests will be made.\n\t */\n\tprivate Integer batchSize = 10000;\n\n\t/**\n\t * URI of the Atlas server.\n\t */\n\tprivate String uri = \"http://localhost:7101/api/v1/publish\";\n\n\t/**\n\t * Time to live for meters that do not have any activity. After this period the meter\n\t * will be considered expired and will not get reported.\n\t */\n\tprivate Duration meterTimeToLive = Duration.ofMinutes(15);\n\n\t/**\n\t * Whether to enable streaming to Atlas LWC.\n\t */\n\tprivate boolean lwcEnabled;\n\n\t/**\n\t * Step size (reporting frequency) to use for streaming to Atlas LWC. This is the\n\t * highest supported resolution for getting an on-demand stream of the data. It must\n\t * be less than or equal to management.metrics.export.atlas.step and\n\t * management.metrics.export.atlas.step should be an even multiple of this value.\n\t */\n\tprivate Duration lwcStep = Duration.ofSeconds(5);\n\n\t/**\n\t * Whether expressions with the same step size as Atlas publishing should be ignored\n\t * for streaming. Used for cases where data being published to Atlas is also sent into\n\t * streaming from the backend.\n\t */\n\tprivate boolean lwcIgnorePublishStep = true;\n\n\t/**\n\t * Frequency for refreshing config settings from the LWC service.\n\t */\n\tprivate Duration configRefreshFrequency = Duration.ofSeconds(10);\n\n\t/**\n\t * Time to live for subscriptions from the LWC service.\n\t */\n\tprivate Duration configTimeToLive = Duration.ofSeconds(150);\n\n\t/**\n\t * URI for the Atlas LWC endpoint to retrieve current subscriptions.\n\t */\n\tprivate String configUri = \"http://localhost:7101/lwc/api/v1/expressions/local-dev\";\n\n\t/**\n\t * URI for the Atlas LWC endpoint to evaluate the data for a subscription.\n\t */\n\tprivate String evalUri = \"http://localhost:7101/lwc/api/v1/evaluate\";\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic Duration getReadTimeout() {\n\t\treturn this.readTimeout;\n\t}\n\n\tpublic void setReadTimeout(Duration readTimeout) {\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\tpublic Integer getNumThreads() {\n\t\treturn this.numThreads;\n\t}\n\n\tpublic void setNumThreads(Integer numThreads) {\n\t\tthis.numThreads = numThreads;\n\t}\n\n\tpublic Integer getBatchSize() {\n\t\treturn this.batchSize;\n\t}\n\n\tpublic void setBatchSize(Integer batchSize) {\n\t\tthis.batchSize = batchSize;\n\t}\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n\tpublic Duration getMeterTimeToLive() {\n\t\treturn this.meterTimeToLive;\n\t}\n\n\tpublic void setMeterTimeToLive(Duration meterTimeToLive) {\n\t\tthis.meterTimeToLive = meterTimeToLive;\n\t}\n\n\tpublic boolean isLwcEnabled() {\n\t\treturn this.lwcEnabled;\n\t}\n\n\tpublic void setLwcEnabled(boolean lwcEnabled) {\n\t\tthis.lwcEnabled = lwcEnabled;\n\t}\n\n\tpublic Duration getLwcStep() {\n\t\treturn this.lwcStep;\n\t}\n\n\tpublic void setLwcStep(Duration lwcStep) {\n\t\tthis.lwcStep = lwcStep;\n\t}\n\n\tpublic boolean isLwcIgnorePublishStep() {\n\t\treturn this.lwcIgnorePublishStep;\n\t}\n\n\tpublic void setLwcIgnorePublishStep(boolean lwcIgnorePublishStep) {\n\t\tthis.lwcIgnorePublishStep = lwcIgnorePublishStep;\n\t}\n\n\tpublic Duration getConfigRefreshFrequency() {\n\t\treturn this.configRefreshFrequency;\n\t}\n\n\tpublic void setConfigRefreshFrequency(Duration configRefreshFrequency) {\n\t\tthis.configRefreshFrequency = configRefreshFrequency;\n\t}\n\n\tpublic Duration getConfigTimeToLive() {\n\t\treturn this.configTimeToLive;\n\t}\n\n\tpublic void setConfigTimeToLive(Duration configTimeToLive) {\n\t\tthis.configTimeToLive = configTimeToLive;\n\t}\n\n\tpublic String getConfigUri() {\n\t\treturn this.configUri;\n\t}\n\n\tpublic void setConfigUri(String configUri) {\n\t\tthis.configUri = configUri;\n\t}\n\n\tpublic String getEvalUri() {\n\t\treturn this.evalUri;\n\t}\n\n\tpublic void setEvalUri(String evalUri) {\n\t\tthis.evalUri = evalUri;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/AtlasPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport java.time.Duration;\n\nimport com.netflix.spectator.atlas.AtlasConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link AtlasProperties} to an {@link AtlasConfig}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n */\nclass AtlasPropertiesConfigAdapter extends PropertiesConfigAdapter<AtlasProperties> implements AtlasConfig {\n\n\tAtlasPropertiesConfigAdapter(AtlasProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String key) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(AtlasProperties::getStep, AtlasConfig.super::step);\n\t}\n\n\t@Override\n\tpublic boolean enabled() {\n\t\treturn obtain(AtlasProperties::isEnabled, AtlasConfig.super::enabled);\n\t}\n\n\t@Override\n\tpublic Duration connectTimeout() {\n\t\treturn obtain(AtlasProperties::getConnectTimeout, AtlasConfig.super::connectTimeout);\n\t}\n\n\t@Override\n\tpublic Duration readTimeout() {\n\t\treturn obtain(AtlasProperties::getReadTimeout, AtlasConfig.super::readTimeout);\n\t}\n\n\t@Override\n\tpublic int numThreads() {\n\t\treturn obtain(AtlasProperties::getNumThreads, AtlasConfig.super::numThreads);\n\t}\n\n\t@Override\n\tpublic int batchSize() {\n\t\treturn obtain(AtlasProperties::getBatchSize, AtlasConfig.super::batchSize);\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(AtlasProperties::getUri, AtlasConfig.super::uri);\n\t}\n\n\t@Override\n\tpublic Duration meterTTL() {\n\t\treturn obtain(AtlasProperties::getMeterTimeToLive, AtlasConfig.super::meterTTL);\n\t}\n\n\t@Override\n\tpublic boolean lwcEnabled() {\n\t\treturn obtain(AtlasProperties::isLwcEnabled, AtlasConfig.super::lwcEnabled);\n\t}\n\n\t@Override\n\tpublic Duration lwcStep() {\n\t\treturn obtain(AtlasProperties::getLwcStep, AtlasConfig.super::lwcStep);\n\t}\n\n\t@Override\n\tpublic boolean lwcIgnorePublishStep() {\n\t\treturn obtain(AtlasProperties::isLwcIgnorePublishStep, AtlasConfig.super::lwcIgnorePublishStep);\n\t}\n\n\t@Override\n\tpublic Duration configRefreshFrequency() {\n\t\treturn obtain(AtlasProperties::getConfigRefreshFrequency, AtlasConfig.super::configRefreshFrequency);\n\t}\n\n\t@Override\n\tpublic Duration configTTL() {\n\t\treturn obtain(AtlasProperties::getConfigTimeToLive, AtlasConfig.super::configTTL);\n\t}\n\n\t@Override\n\tpublic String configUri() {\n\t\treturn obtain(AtlasProperties::getConfigUri, AtlasConfig.super::configUri);\n\t}\n\n\t@Override\n\tpublic String evalUri() {\n\t\treturn obtain(AtlasProperties::getEvalUri, AtlasConfig.super::evalUri);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Atlas.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/DatadogMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.datadog.DatadogConfig;\nimport io.micrometer.datadog.DatadogMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Datadog.\n *\n * @author Jon Schneider\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(DatadogMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"datadog\")\n@EnableConfigurationProperties(DatadogProperties.class)\npublic final class DatadogMetricsExportAutoConfiguration {\n\n\tprivate final DatadogProperties properties;\n\n\tDatadogMetricsExportAutoConfiguration(DatadogProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDatadogConfig datadogConfig() {\n\t\treturn new DatadogPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDatadogMeterRegistry datadogMeterRegistry(DatadogConfig datadogConfig, Clock clock) {\n\t\treturn DatadogMeterRegistry.builder(datadogConfig)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/DatadogProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Datadog\n * metrics export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.datadog.metrics.export\")\npublic class DatadogProperties extends StepRegistryProperties {\n\n\t/**\n\t * Datadog API key.\n\t */\n\tprivate @Nullable String apiKey;\n\n\t/**\n\t * Datadog application key. Not strictly required, but improves the Datadog experience\n\t * by sending meter descriptions, types, and base units to Datadog.\n\t */\n\tprivate @Nullable String applicationKey;\n\n\t/**\n\t * Whether to publish descriptions metadata to Datadog. Turn this off to minimize the\n\t * amount of metadata sent.\n\t */\n\tprivate boolean descriptions = true;\n\n\t/**\n\t * Tag that will be mapped to \"host\" when shipping metrics to Datadog.\n\t */\n\tprivate String hostTag = \"instance\";\n\n\t/**\n\t * URI to ship metrics to. Set this if you need to publish metrics to a Datadog site\n\t * other than US, or to an internal proxy en-route to Datadog.\n\t */\n\tprivate String uri = \"https://api.datadoghq.com\";\n\n\tpublic @Nullable String getApiKey() {\n\t\treturn this.apiKey;\n\t}\n\n\tpublic void setApiKey(@Nullable String apiKey) {\n\t\tthis.apiKey = apiKey;\n\t}\n\n\tpublic @Nullable String getApplicationKey() {\n\t\treturn this.applicationKey;\n\t}\n\n\tpublic void setApplicationKey(@Nullable String applicationKey) {\n\t\tthis.applicationKey = applicationKey;\n\t}\n\n\tpublic boolean isDescriptions() {\n\t\treturn this.descriptions;\n\t}\n\n\tpublic void setDescriptions(boolean descriptions) {\n\t\tthis.descriptions = descriptions;\n\t}\n\n\tpublic String getHostTag() {\n\t\treturn this.hostTag;\n\t}\n\n\tpublic void setHostTag(String hostTag) {\n\t\tthis.hostTag = hostTag;\n\t}\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/DatadogPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport io.micrometer.datadog.DatadogConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link DatadogProperties} to a {@link DatadogConfig}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n */\nclass DatadogPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<DatadogProperties>\n\t\timplements DatadogConfig {\n\n\tDatadogPropertiesConfigAdapter(DatadogProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.datadog.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String apiKey() {\n\t\treturn obtain(DatadogProperties::getApiKey, DatadogConfig.super::apiKey);\n\t}\n\n\t@Override\n\tpublic @Nullable String applicationKey() {\n\t\treturn get(DatadogProperties::getApplicationKey, DatadogConfig.super::applicationKey);\n\t}\n\n\t@Override\n\tpublic @Nullable String hostTag() {\n\t\treturn get(DatadogProperties::getHostTag, DatadogConfig.super::hostTag);\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(DatadogProperties::getUri, DatadogConfig.super::uri);\n\t}\n\n\t@Override\n\tpublic boolean descriptions() {\n\t\treturn obtain(DatadogProperties::isDescriptions, DatadogConfig.super::descriptions);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Datadog.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/DynatraceMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.dynatrace.DynatraceConfig;\nimport io.micrometer.dynatrace.DynatraceMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Dynatrace.\n *\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(DynatraceMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"dynatrace\")\n@EnableConfigurationProperties(DynatraceProperties.class)\npublic final class DynatraceMetricsExportAutoConfiguration {\n\n\tprivate final DynatraceProperties properties;\n\n\tDynatraceMetricsExportAutoConfiguration(DynatraceProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDynatraceConfig dynatraceConfig() {\n\t\treturn new DynatracePropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDynatraceMeterRegistry dynatraceMeterRegistry(DynatraceConfig dynatraceConfig, Clock clock) {\n\t\treturn DynatraceMeterRegistry.builder(dynatraceConfig)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/DynatraceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.DeprecatedConfigurationProperty;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Dynatrace\n * metrics export.\n *\n * @author Andy Wilkinson\n * @author Georg Pirklbauer\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.dynatrace.metrics.export\")\npublic class DynatraceProperties extends StepRegistryProperties {\n\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tprivate final V1 v1 = new V1();\n\n\tprivate final V2 v2 = new V2();\n\n\t/**\n\t * Dynatrace authentication token.\n\t */\n\tprivate @Nullable String apiToken;\n\n\t/**\n\t * URI to ship metrics to. Should be used for SaaS, self-managed instances or to\n\t * en-route through an internal proxy.\n\t */\n\tprivate @Nullable String uri;\n\n\tpublic @Nullable String getApiToken() {\n\t\treturn this.apiToken;\n\t}\n\n\tpublic void setApiToken(@Nullable String apiToken) {\n\t\tthis.apiToken = apiToken;\n\t}\n\n\tpublic @Nullable String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(@Nullable String uri) {\n\t\tthis.uri = uri;\n\t}\n\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic V1 getV1() {\n\t\treturn this.v1;\n\t}\n\n\tpublic V2 getV2() {\n\t\treturn this.v2;\n\t}\n\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic static class V1 {\n\n\t\t/**\n\t\t * ID of the custom device that is exporting metrics to Dynatrace.\n\t\t */\n\t\tprivate @Nullable String deviceId;\n\n\t\t/**\n\t\t * Group for exported metrics. Used to specify custom device group name in the\n\t\t * Dynatrace UI.\n\t\t */\n\t\tprivate @Nullable String group;\n\n\t\t/**\n\t\t * Technology type for exported metrics. Used to group metrics under a logical\n\t\t * technology name in the Dynatrace UI.\n\t\t */\n\t\tprivate String technologyType = \"java\";\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Dynatrace V1 API is deprecated, use the V2 API instead.\",\n\t\t\t\tsince = \"4.1.0\")\n\t\tpublic @Nullable String getDeviceId() {\n\t\t\treturn this.deviceId;\n\t\t}\n\n\t\tpublic void setDeviceId(@Nullable String deviceId) {\n\t\t\tthis.deviceId = deviceId;\n\t\t}\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Dynatrace V1 API is deprecated, use the V2 API instead.\",\n\t\t\t\tsince = \"4.1.0\")\n\t\tpublic @Nullable String getGroup() {\n\t\t\treturn this.group;\n\t\t}\n\n\t\tpublic void setGroup(@Nullable String group) {\n\t\t\tthis.group = group;\n\t\t}\n\n\t\t@DeprecatedConfigurationProperty(reason = \"Dynatrace V1 API is deprecated, use the V2 API instead.\",\n\t\t\t\tsince = \"4.1.0\")\n\t\tpublic String getTechnologyType() {\n\t\t\treturn this.technologyType;\n\t\t}\n\n\t\tpublic void setTechnologyType(String technologyType) {\n\t\t\tthis.technologyType = technologyType;\n\t\t}\n\n\t}\n\n\tpublic static class V2 {\n\n\t\t/**\n\t\t * Default dimensions that are added to all metrics in the form of key-value\n\t\t * pairs. These are overwritten by Micrometer tags if they use the same key.\n\t\t */\n\t\tprivate @Nullable Map<String, String> defaultDimensions;\n\n\t\t/**\n\t\t * Whether to enable Dynatrace metadata export.\n\t\t */\n\t\tprivate boolean enrichWithDynatraceMetadata = true;\n\n\t\t/**\n\t\t * Prefix string that is added to all exported metrics.\n\t\t */\n\t\tprivate @Nullable String metricKeyPrefix;\n\n\t\t/**\n\t\t * Whether to fall back to the built-in micrometer instruments for Timer and\n\t\t * DistributionSummary.\n\t\t */\n\t\tprivate boolean useDynatraceSummaryInstruments = true;\n\n\t\t/**\n\t\t * Whether to export meter metadata (unit and description) to the Dynatrace\n\t\t * backend.\n\t\t */\n\t\tprivate boolean exportMeterMetadata = true;\n\n\t\tpublic @Nullable Map<String, String> getDefaultDimensions() {\n\t\t\treturn this.defaultDimensions;\n\t\t}\n\n\t\tpublic void setDefaultDimensions(@Nullable Map<String, String> defaultDimensions) {\n\t\t\tthis.defaultDimensions = defaultDimensions;\n\t\t}\n\n\t\tpublic boolean isEnrichWithDynatraceMetadata() {\n\t\t\treturn this.enrichWithDynatraceMetadata;\n\t\t}\n\n\t\tpublic void setEnrichWithDynatraceMetadata(Boolean enrichWithDynatraceMetadata) {\n\t\t\tthis.enrichWithDynatraceMetadata = enrichWithDynatraceMetadata;\n\t\t}\n\n\t\tpublic @Nullable String getMetricKeyPrefix() {\n\t\t\treturn this.metricKeyPrefix;\n\t\t}\n\n\t\tpublic void setMetricKeyPrefix(@Nullable String metricKeyPrefix) {\n\t\t\tthis.metricKeyPrefix = metricKeyPrefix;\n\t\t}\n\n\t\tpublic boolean isUseDynatraceSummaryInstruments() {\n\t\t\treturn this.useDynatraceSummaryInstruments;\n\t\t}\n\n\t\tpublic void setUseDynatraceSummaryInstruments(boolean useDynatraceSummaryInstruments) {\n\t\t\tthis.useDynatraceSummaryInstruments = useDynatraceSummaryInstruments;\n\t\t}\n\n\t\tpublic boolean isExportMeterMetadata() {\n\t\t\treturn this.exportMeterMetadata;\n\t\t}\n\n\t\tpublic void setExportMeterMetadata(boolean exportMeterMetadata) {\n\t\t\tthis.exportMeterMetadata = exportMeterMetadata;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/DynatracePropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport java.util.Map;\n\nimport io.micrometer.dynatrace.DynatraceApiVersion;\nimport io.micrometer.dynatrace.DynatraceConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace.DynatraceProperties.V2;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link DynatraceProperties} to a {@link DynatraceConfig}.\n *\n * @author Andy Wilkinson\n * @author Georg Pirklbauer\n */\nclass DynatracePropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<DynatraceProperties>\n\t\timplements DynatraceConfig {\n\n\tDynatracePropertiesConfigAdapter(DynatraceProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.dynatrace.metrics.export\";\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"deprecation\")\n\tpublic String apiToken() {\n\t\treturn obtain(DynatraceProperties::getApiToken, DynatraceConfig.super::apiToken);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic String deviceId() {\n\t\treturn obtain(v1(DynatraceProperties.V1::getDeviceId), DynatraceConfig.super::deviceId);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic String technologyType() {\n\t\treturn obtain(v1(DynatraceProperties.V1::getTechnologyType), DynatraceConfig.super::technologyType);\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(DynatraceProperties::getUri, DynatraceConfig.super::uri);\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic @Nullable String group() {\n\t\treturn get(v1(DynatraceProperties.V1::getGroup), DynatraceConfig.super::group);\n\t}\n\n\t@Override\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tpublic DynatraceApiVersion apiVersion() {\n\t\treturn obtain((properties) -> (properties.getV1().getDeviceId() != null) ? DynatraceApiVersion.V1\n\t\t\t\t: DynatraceApiVersion.V2, DynatraceConfig.super::apiVersion);\n\t}\n\n\t@Override\n\tpublic String metricKeyPrefix() {\n\t\treturn obtain(v2(V2::getMetricKeyPrefix), DynatraceConfig.super::metricKeyPrefix);\n\t}\n\n\t@Override\n\tpublic Map<String, String> defaultDimensions() {\n\t\treturn obtain(v2(V2::getDefaultDimensions), DynatraceConfig.super::defaultDimensions);\n\t}\n\n\t@Override\n\tpublic boolean enrichWithDynatraceMetadata() {\n\t\treturn obtain(v2(V2::isEnrichWithDynatraceMetadata), DynatraceConfig.super::enrichWithDynatraceMetadata);\n\t}\n\n\t@Override\n\tpublic boolean useDynatraceSummaryInstruments() {\n\t\treturn obtain(v2(V2::isUseDynatraceSummaryInstruments), DynatraceConfig.super::useDynatraceSummaryInstruments);\n\t}\n\n\t@Override\n\tpublic boolean exportMeterMetadata() {\n\t\treturn obtain(v2(V2::isExportMeterMetadata), DynatraceConfig.super::exportMeterMetadata);\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tprivate <V> Getter<DynatraceProperties, V> v1(Getter<DynatraceProperties.V1, V> getter) {\n\t\treturn (properties) -> getter.get(properties.getV1());\n\t}\n\n\tprivate <V> Getter<DynatraceProperties, V> v2(Getter<V2, V> getter) {\n\t\treturn (properties) -> getter.get(properties.getV2());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Dynatrace.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/ElasticMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.elastic.ElasticConfig;\nimport io.micrometer.elastic.ElasticMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Elastic.\n *\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(ElasticMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"elastic\")\n@EnableConfigurationProperties(ElasticProperties.class)\npublic final class ElasticMetricsExportAutoConfiguration {\n\n\tprivate final ElasticProperties properties;\n\n\tElasticMetricsExportAutoConfiguration(ElasticProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tElasticConfig elasticConfig() {\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\tentries.put(\"api-key-credentials\", this.properties.getApiKeyCredentials());\n\t\t\tentries.put(\"user-name\", this.properties.getUserName());\n\t\t});\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\tentries.put(\"api-key-credentials\", this.properties.getApiKeyCredentials());\n\t\t\tentries.put(\"password\", this.properties.getPassword());\n\t\t});\n\t\treturn new ElasticPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tElasticMeterRegistry elasticMeterRegistry(ElasticConfig elasticConfig, Clock clock) {\n\t\treturn ElasticMeterRegistry.builder(elasticConfig)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/ElasticProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Elastic\n * metrics export.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.elastic.metrics.export\")\npublic class ElasticProperties extends StepRegistryProperties {\n\n\t/**\n\t * Host to export metrics to.\n\t */\n\tprivate String host = \"http://localhost:9200\";\n\n\t/**\n\t * Index to export metrics to.\n\t */\n\tprivate String index = \"micrometer-metrics\";\n\n\t/**\n\t * Index date format used for rolling indices. Appended to the index name.\n\t */\n\tprivate String indexDateFormat = \"yyyy-MM\";\n\n\t/**\n\t * Prefix to separate the index name from the date format used for rolling indices.\n\t */\n\tprivate String indexDateSeparator = \"-\";\n\n\t/**\n\t * Name of the timestamp field.\n\t */\n\tprivate String timestampFieldName = \"@timestamp\";\n\n\t/**\n\t * Whether to create the index automatically if it does not exist.\n\t */\n\tprivate boolean autoCreateIndex = true;\n\n\t/**\n\t * Login user of the Elastic server. Mutually exclusive with api-key-credentials.\n\t */\n\tprivate @Nullable String userName;\n\n\t/**\n\t * Login password of the Elastic server. Mutually exclusive with api-key-credentials.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Ingest pipeline name. By default, events are not pre-processed.\n\t */\n\tprivate @Nullable String pipeline;\n\n\t/**\n\t * Base64-encoded credentials string. Mutually exclusive with user-name and password.\n\t */\n\tprivate @Nullable String apiKeyCredentials;\n\n\t/**\n\t * Whether to enable _source in the default index template when auto-creating the\n\t * index.\n\t */\n\tprivate boolean enableSource;\n\n\tpublic String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic String getIndex() {\n\t\treturn this.index;\n\t}\n\n\tpublic void setIndex(String index) {\n\t\tthis.index = index;\n\t}\n\n\tpublic String getIndexDateFormat() {\n\t\treturn this.indexDateFormat;\n\t}\n\n\tpublic void setIndexDateFormat(String indexDateFormat) {\n\t\tthis.indexDateFormat = indexDateFormat;\n\t}\n\n\tpublic String getIndexDateSeparator() {\n\t\treturn this.indexDateSeparator;\n\t}\n\n\tpublic void setIndexDateSeparator(String indexDateSeparator) {\n\t\tthis.indexDateSeparator = indexDateSeparator;\n\t}\n\n\tpublic String getTimestampFieldName() {\n\t\treturn this.timestampFieldName;\n\t}\n\n\tpublic void setTimestampFieldName(String timestampFieldName) {\n\t\tthis.timestampFieldName = timestampFieldName;\n\t}\n\n\tpublic boolean isAutoCreateIndex() {\n\t\treturn this.autoCreateIndex;\n\t}\n\n\tpublic void setAutoCreateIndex(boolean autoCreateIndex) {\n\t\tthis.autoCreateIndex = autoCreateIndex;\n\t}\n\n\tpublic @Nullable String getUserName() {\n\t\treturn this.userName;\n\t}\n\n\tpublic void setUserName(@Nullable String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable String getPipeline() {\n\t\treturn this.pipeline;\n\t}\n\n\tpublic void setPipeline(@Nullable String pipeline) {\n\t\tthis.pipeline = pipeline;\n\t}\n\n\tpublic @Nullable String getApiKeyCredentials() {\n\t\treturn this.apiKeyCredentials;\n\t}\n\n\tpublic void setApiKeyCredentials(@Nullable String apiKeyCredentials) {\n\t\tthis.apiKeyCredentials = apiKeyCredentials;\n\t}\n\n\tpublic boolean isEnableSource() {\n\t\treturn this.enableSource;\n\t}\n\n\tpublic void setEnableSource(boolean enableSource) {\n\t\tthis.enableSource = enableSource;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/ElasticPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport io.micrometer.elastic.ElasticConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link ElasticProperties} to an {@link ElasticConfig}.\n *\n * @author Andy Wilkinson\n */\nclass ElasticPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<ElasticProperties>\n\t\timplements ElasticConfig {\n\n\tElasticPropertiesConfigAdapter(ElasticProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.elastic.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String host() {\n\t\treturn obtain(ElasticProperties::getHost, ElasticConfig.super::host);\n\t}\n\n\t@Override\n\tpublic String index() {\n\t\treturn obtain(ElasticProperties::getIndex, ElasticConfig.super::index);\n\t}\n\n\t@Override\n\tpublic String indexDateFormat() {\n\t\treturn obtain(ElasticProperties::getIndexDateFormat, ElasticConfig.super::indexDateFormat);\n\t}\n\n\t@Override\n\tpublic String indexDateSeparator() {\n\t\treturn obtain(ElasticProperties::getIndexDateSeparator, ElasticConfig.super::indexDateSeparator);\n\t}\n\n\t@Override\n\tpublic String timestampFieldName() {\n\t\treturn obtain(ElasticProperties::getTimestampFieldName, ElasticConfig.super::timestampFieldName);\n\t}\n\n\t@Override\n\tpublic boolean autoCreateIndex() {\n\t\treturn obtain(ElasticProperties::isAutoCreateIndex, ElasticConfig.super::autoCreateIndex);\n\t}\n\n\t@Override\n\tpublic @Nullable String userName() {\n\t\treturn get(ElasticProperties::getUserName, ElasticConfig.super::userName);\n\t}\n\n\t@Override\n\tpublic @Nullable String password() {\n\t\treturn get(ElasticProperties::getPassword, ElasticConfig.super::password);\n\t}\n\n\t@Override\n\tpublic @Nullable String pipeline() {\n\t\treturn get(ElasticProperties::getPipeline, ElasticConfig.super::pipeline);\n\t}\n\n\t@Override\n\tpublic @Nullable String apiKeyCredentials() {\n\t\treturn get(ElasticProperties::getApiKeyCredentials, ElasticConfig.super::apiKeyCredentials);\n\t}\n\n\t@Override\n\tpublic boolean enableSource() {\n\t\treturn obtain(ElasticProperties::isEnableSource, ElasticConfig.super::enableSource);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Elastic.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/GangliaMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.ganglia.GangliaConfig;\nimport io.micrometer.ganglia.GangliaMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Ganglia.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(GangliaMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"ganglia\")\n@EnableConfigurationProperties(GangliaProperties.class)\npublic final class GangliaMetricsExportAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGangliaConfig gangliaConfig(GangliaProperties gangliaProperties) {\n\t\treturn new GangliaPropertiesConfigAdapter(gangliaProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGangliaMeterRegistry gangliaMeterRegistry(GangliaConfig gangliaConfig, Clock clock) {\n\t\treturn new GangliaMeterRegistry(gangliaConfig, clock);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/GangliaProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport info.ganglia.gmetric4j.gmetric.GMetric;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Ganglia\n * metrics export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.ganglia.metrics.export\")\npublic class GangliaProperties {\n\n\t/**\n\t * Whether exporting of metrics to Ganglia is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\t/**\n\t * Base time unit used to report durations.\n\t */\n\tprivate TimeUnit durationUnits = TimeUnit.MILLISECONDS;\n\n\t/**\n\t * UDP addressing mode, either unicast or multicast.\n\t */\n\tprivate GMetric.UDPAddressingMode addressingMode = GMetric.UDPAddressingMode.MULTICAST;\n\n\t/**\n\t * Time to live for metrics on Ganglia. Set the multicast Time-To-Live to be one\n\t * greater than the number of hops (routers) between the hosts.\n\t */\n\tprivate Integer timeToLive = 1;\n\n\t/**\n\t * Host of the Ganglia server to receive exported metrics.\n\t */\n\tprivate String host = \"localhost\";\n\n\t/**\n\t * Port of the Ganglia server to receive exported metrics.\n\t */\n\tprivate Integer port = 8649;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic TimeUnit getDurationUnits() {\n\t\treturn this.durationUnits;\n\t}\n\n\tpublic void setDurationUnits(TimeUnit durationUnits) {\n\t\tthis.durationUnits = durationUnits;\n\t}\n\n\tpublic GMetric.UDPAddressingMode getAddressingMode() {\n\t\treturn this.addressingMode;\n\t}\n\n\tpublic void setAddressingMode(GMetric.UDPAddressingMode addressingMode) {\n\t\tthis.addressingMode = addressingMode;\n\t}\n\n\tpublic Integer getTimeToLive() {\n\t\treturn this.timeToLive;\n\t}\n\n\tpublic void setTimeToLive(Integer timeToLive) {\n\t\tthis.timeToLive = timeToLive;\n\t}\n\n\tpublic String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(Integer port) {\n\t\tthis.port = port;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/GangliaPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport info.ganglia.gmetric4j.gmetric.GMetric;\nimport io.micrometer.ganglia.GangliaConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link GangliaProperties} to a {@link GangliaConfig}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n */\nclass GangliaPropertiesConfigAdapter extends PropertiesConfigAdapter<GangliaProperties> implements GangliaConfig {\n\n\tGangliaPropertiesConfigAdapter(GangliaProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.ganglia.metrics.export\";\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String k) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean enabled() {\n\t\treturn obtain(GangliaProperties::isEnabled, GangliaConfig.super::enabled);\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(GangliaProperties::getStep, GangliaConfig.super::step);\n\t}\n\n\t@Override\n\tpublic TimeUnit durationUnits() {\n\t\treturn obtain(GangliaProperties::getDurationUnits, GangliaConfig.super::durationUnits);\n\t}\n\n\t@Override\n\tpublic GMetric.UDPAddressingMode addressingMode() {\n\t\treturn obtain(GangliaProperties::getAddressingMode, GangliaConfig.super::addressingMode);\n\t}\n\n\t@Override\n\tpublic int ttl() {\n\t\treturn obtain(GangliaProperties::getTimeToLive, GangliaConfig.super::ttl);\n\t}\n\n\t@Override\n\tpublic String host() {\n\t\treturn obtain(GangliaProperties::getHost, GangliaConfig.super::host);\n\t}\n\n\t@Override\n\tpublic int port() {\n\t\treturn obtain(GangliaProperties::getPort, GangliaConfig.super::port);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Ganglia.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/GraphiteMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.graphite.GraphiteConfig;\nimport io.micrometer.graphite.GraphiteMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Graphite.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(GraphiteMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"graphite\")\n@EnableConfigurationProperties(GraphiteProperties.class)\npublic final class GraphiteMetricsExportAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphiteConfig graphiteConfig(GraphiteProperties graphiteProperties) {\n\t\treturn new GraphitePropertiesConfigAdapter(graphiteProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tGraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig graphiteConfig, Clock clock) {\n\t\treturn new GraphiteMeterRegistry(graphiteConfig, clock);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/GraphiteProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.graphite.GraphiteProtocol;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Graphite\n * metrics export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.graphite.metrics.export\")\npublic class GraphiteProperties {\n\n\t/**\n\t * Whether exporting of metrics to Graphite is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\t/**\n\t * Base time unit used to report rates.\n\t */\n\tprivate TimeUnit rateUnits = TimeUnit.SECONDS;\n\n\t/**\n\t * Base time unit used to report durations.\n\t */\n\tprivate TimeUnit durationUnits = TimeUnit.MILLISECONDS;\n\n\t/**\n\t * Host of the Graphite server to receive exported metrics.\n\t */\n\tprivate String host = \"localhost\";\n\n\t/**\n\t * Port of the Graphite server to receive exported metrics.\n\t */\n\tprivate Integer port = 2004;\n\n\t/**\n\t * Protocol to use while shipping data to Graphite.\n\t */\n\tprivate GraphiteProtocol protocol = GraphiteProtocol.PICKLED;\n\n\t/**\n\t * Whether Graphite tags should be used, as opposed to a hierarchical naming\n\t * convention. Enabled by default unless \"tagsAsPrefix\" is set.\n\t */\n\tprivate @Nullable Boolean graphiteTagsEnabled;\n\n\t/**\n\t * For the hierarchical naming convention, turn the specified tag keys into part of\n\t * the metric prefix. Ignored if \"graphiteTagsEnabled\" is true.\n\t */\n\tprivate String[] tagsAsPrefix = new String[0];\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic TimeUnit getRateUnits() {\n\t\treturn this.rateUnits;\n\t}\n\n\tpublic void setRateUnits(TimeUnit rateUnits) {\n\t\tthis.rateUnits = rateUnits;\n\t}\n\n\tpublic TimeUnit getDurationUnits() {\n\t\treturn this.durationUnits;\n\t}\n\n\tpublic void setDurationUnits(TimeUnit durationUnits) {\n\t\tthis.durationUnits = durationUnits;\n\t}\n\n\tpublic String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic GraphiteProtocol getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\tpublic void setProtocol(GraphiteProtocol protocol) {\n\t\tthis.protocol = protocol;\n\t}\n\n\tpublic Boolean getGraphiteTagsEnabled() {\n\t\treturn (this.graphiteTagsEnabled != null) ? this.graphiteTagsEnabled : ObjectUtils.isEmpty(this.tagsAsPrefix);\n\t}\n\n\tpublic void setGraphiteTagsEnabled(Boolean graphiteTagsEnabled) {\n\t\tthis.graphiteTagsEnabled = graphiteTagsEnabled;\n\t}\n\n\tpublic String[] getTagsAsPrefix() {\n\t\treturn this.tagsAsPrefix;\n\t}\n\n\tpublic void setTagsAsPrefix(String[] tagsAsPrefix) {\n\t\tthis.tagsAsPrefix = tagsAsPrefix;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/GraphitePropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.graphite.GraphiteConfig;\nimport io.micrometer.graphite.GraphiteProtocol;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link GraphiteProperties} to a {@link GraphiteConfig}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n */\nclass GraphitePropertiesConfigAdapter extends PropertiesConfigAdapter<GraphiteProperties> implements GraphiteConfig {\n\n\tGraphitePropertiesConfigAdapter(GraphiteProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.graphite.metrics.export\";\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String k) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean enabled() {\n\t\treturn obtain(GraphiteProperties::isEnabled, GraphiteConfig.super::enabled);\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(GraphiteProperties::getStep, GraphiteConfig.super::step);\n\t}\n\n\t@Override\n\tpublic TimeUnit rateUnits() {\n\t\treturn obtain(GraphiteProperties::getRateUnits, GraphiteConfig.super::rateUnits);\n\t}\n\n\t@Override\n\tpublic TimeUnit durationUnits() {\n\t\treturn obtain(GraphiteProperties::getDurationUnits, GraphiteConfig.super::durationUnits);\n\t}\n\n\t@Override\n\tpublic String host() {\n\t\treturn obtain(GraphiteProperties::getHost, GraphiteConfig.super::host);\n\t}\n\n\t@Override\n\tpublic int port() {\n\t\treturn obtain(GraphiteProperties::getPort, GraphiteConfig.super::port);\n\t}\n\n\t@Override\n\tpublic GraphiteProtocol protocol() {\n\t\treturn obtain(GraphiteProperties::getProtocol, GraphiteConfig.super::protocol);\n\t}\n\n\t@Override\n\tpublic boolean graphiteTagsEnabled() {\n\t\treturn obtain(GraphiteProperties::getGraphiteTagsEnabled, GraphiteConfig.super::graphiteTagsEnabled);\n\t}\n\n\t@Override\n\tpublic String[] tagsAsPrefix() {\n\t\treturn obtain(GraphiteProperties::getTagsAsPrefix, GraphiteConfig.super::tagsAsPrefix);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Graphite.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/HumioMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.humio.HumioConfig;\nimport io.micrometer.humio.HumioMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Humio.\n *\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(HumioMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"humio\")\n@EnableConfigurationProperties(HumioProperties.class)\npublic final class HumioMetricsExportAutoConfiguration {\n\n\tprivate final HumioProperties properties;\n\n\tHumioMetricsExportAutoConfiguration(HumioProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHumioConfig humioConfig() {\n\t\treturn new HumioPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHumioMeterRegistry humioMeterRegistry(HumioConfig humioConfig, Clock clock) {\n\t\treturn HumioMeterRegistry.builder(humioConfig)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/HumioProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Humio metrics\n * export.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.humio.metrics.export\")\npublic class HumioProperties extends StepRegistryProperties {\n\n\t/**\n\t * Humio API token.\n\t */\n\tprivate @Nullable String apiToken;\n\n\t/**\n\t * Connection timeout for requests to this backend.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(5);\n\n\t/**\n\t * Humio tags describing the data source in which metrics will be stored. Humio tags\n\t * are a distinct concept from Micrometer's tags. Micrometer's tags are used to divide\n\t * metrics along dimensional boundaries.\n\t */\n\tprivate Map<String, String> tags = new HashMap<>();\n\n\t/**\n\t * URI to ship metrics to. If you need to publish metrics to an internal proxy\n\t * en-route to Humio, you can define the location of the proxy with this.\n\t */\n\tprivate String uri = \"https://cloud.humio.com\";\n\n\tpublic @Nullable String getApiToken() {\n\t\treturn this.apiToken;\n\t}\n\n\tpublic void setApiToken(@Nullable String apiToken) {\n\t\tthis.apiToken = apiToken;\n\t}\n\n\t@Override\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\t@Override\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic Map<String, String> getTags() {\n\t\treturn this.tags;\n\t}\n\n\tpublic void setTags(Map<String, String> tags) {\n\t\tthis.tags = tags;\n\t}\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/HumioPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport java.util.Map;\n\nimport io.micrometer.humio.HumioConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link HumioProperties} to a {@link HumioConfig}.\n *\n * @author Andy Wilkinson\n */\nclass HumioPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<HumioProperties> implements HumioConfig {\n\n\tHumioPropertiesConfigAdapter(HumioProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.humio.metrics.export\";\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String k) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(HumioProperties::getUri, HumioConfig.super::uri);\n\t}\n\n\t@Override\n\tpublic @Nullable Map<String, String> tags() {\n\t\treturn get(HumioProperties::getTags, HumioConfig.super::tags);\n\t}\n\n\t@Override\n\tpublic @Nullable String apiToken() {\n\t\treturn get(HumioProperties::getApiToken, HumioConfig.super::apiToken);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Humio.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/InfluxMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.influx.InfluxConfig;\nimport io.micrometer.influx.InfluxMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Influx.\n *\n * @author Jon Schneider\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(InfluxMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"influx\")\n@EnableConfigurationProperties(InfluxProperties.class)\npublic final class InfluxMetricsExportAutoConfiguration {\n\n\tprivate final InfluxProperties properties;\n\n\tInfluxMetricsExportAutoConfiguration(InfluxProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tInfluxConfig influxConfig() {\n\t\treturn new InfluxPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tInfluxMeterRegistry influxMeterRegistry(InfluxConfig influxConfig, Clock clock) {\n\t\treturn InfluxMeterRegistry.builder(influxConfig)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/InfluxProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport io.micrometer.influx.InfluxApiVersion;\nimport io.micrometer.influx.InfluxConsistency;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Influx metrics\n * export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.influx.metrics.export\")\npublic class InfluxProperties extends StepRegistryProperties {\n\n\t/**\n\t * Database to send metrics to. InfluxDB v1 only.\n\t */\n\tprivate String db = \"mydb\";\n\n\t/**\n\t * Write consistency for each point.\n\t */\n\tprivate InfluxConsistency consistency = InfluxConsistency.ONE;\n\n\t/**\n\t * Login user of the Influx server. InfluxDB v1 only.\n\t */\n\tprivate @Nullable String userName;\n\n\t/**\n\t * Login password of the Influx server. InfluxDB v1 only.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Retention policy to use (Influx writes to the DEFAULT retention policy if one is\n\t * not specified). InfluxDB v1 only.\n\t */\n\tprivate @Nullable String retentionPolicy;\n\n\t/**\n\t * Time period for which Influx should retain data in the current database. For\n\t * instance 7d, check the influx documentation for more details on the duration\n\t * format. InfluxDB v1 only.\n\t */\n\tprivate @Nullable String retentionDuration;\n\n\t/**\n\t * How many copies of the data are stored in the cluster. Must be 1 for a single node\n\t * instance. InfluxDB v1 only.\n\t */\n\tprivate @Nullable Integer retentionReplicationFactor;\n\n\t/**\n\t * Time range covered by a shard group. For instance 2w, check the influx\n\t * documentation for more details on the duration format. InfluxDB v1 only.\n\t */\n\tprivate @Nullable String retentionShardDuration;\n\n\t/**\n\t * URI of the Influx server.\n\t */\n\tprivate String uri = \"http://localhost:8086\";\n\n\t/**\n\t * Whether to enable GZIP compression of metrics batches published to Influx.\n\t */\n\tprivate boolean compressed = true;\n\n\t/**\n\t * Whether to create the Influx database if it does not exist before attempting to\n\t * publish metrics to it. InfluxDB v1 only.\n\t */\n\tprivate boolean autoCreateDb = true;\n\n\t/**\n\t * API version of InfluxDB to use. Defaults to 'v1' unless an org is configured. If an\n\t * org is configured, defaults to 'v2'.\n\t */\n\tprivate @Nullable InfluxApiVersion apiVersion;\n\n\t/**\n\t * Org to write metrics to. InfluxDB v2 only.\n\t */\n\tprivate @Nullable String org;\n\n\t/**\n\t * Bucket for metrics. Use either the bucket name or ID. Defaults to the value of the\n\t * db property if not set. InfluxDB v2 only.\n\t */\n\tprivate @Nullable String bucket;\n\n\t/**\n\t * Authentication token to use with calls to the InfluxDB backend. For InfluxDB v1,\n\t * the Bearer scheme is used. For v2, the Token scheme is used.\n\t */\n\tprivate @Nullable String token;\n\n\tpublic String getDb() {\n\t\treturn this.db;\n\t}\n\n\tpublic void setDb(String db) {\n\t\tthis.db = db;\n\t}\n\n\tpublic InfluxConsistency getConsistency() {\n\t\treturn this.consistency;\n\t}\n\n\tpublic void setConsistency(InfluxConsistency consistency) {\n\t\tthis.consistency = consistency;\n\t}\n\n\tpublic @Nullable String getUserName() {\n\t\treturn this.userName;\n\t}\n\n\tpublic void setUserName(@Nullable String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable String getRetentionPolicy() {\n\t\treturn this.retentionPolicy;\n\t}\n\n\tpublic void setRetentionPolicy(@Nullable String retentionPolicy) {\n\t\tthis.retentionPolicy = retentionPolicy;\n\t}\n\n\tpublic @Nullable String getRetentionDuration() {\n\t\treturn this.retentionDuration;\n\t}\n\n\tpublic void setRetentionDuration(@Nullable String retentionDuration) {\n\t\tthis.retentionDuration = retentionDuration;\n\t}\n\n\tpublic @Nullable Integer getRetentionReplicationFactor() {\n\t\treturn this.retentionReplicationFactor;\n\t}\n\n\tpublic void setRetentionReplicationFactor(@Nullable Integer retentionReplicationFactor) {\n\t\tthis.retentionReplicationFactor = retentionReplicationFactor;\n\t}\n\n\tpublic @Nullable String getRetentionShardDuration() {\n\t\treturn this.retentionShardDuration;\n\t}\n\n\tpublic void setRetentionShardDuration(@Nullable String retentionShardDuration) {\n\t\tthis.retentionShardDuration = retentionShardDuration;\n\t}\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n\tpublic boolean isCompressed() {\n\t\treturn this.compressed;\n\t}\n\n\tpublic void setCompressed(boolean compressed) {\n\t\tthis.compressed = compressed;\n\t}\n\n\tpublic boolean isAutoCreateDb() {\n\t\treturn this.autoCreateDb;\n\t}\n\n\tpublic void setAutoCreateDb(boolean autoCreateDb) {\n\t\tthis.autoCreateDb = autoCreateDb;\n\t}\n\n\tpublic @Nullable InfluxApiVersion getApiVersion() {\n\t\treturn this.apiVersion;\n\t}\n\n\tpublic void setApiVersion(@Nullable InfluxApiVersion apiVersion) {\n\t\tthis.apiVersion = apiVersion;\n\t}\n\n\tpublic @Nullable String getOrg() {\n\t\treturn this.org;\n\t}\n\n\tpublic void setOrg(@Nullable String org) {\n\t\tthis.org = org;\n\t}\n\n\tpublic @Nullable String getBucket() {\n\t\treturn this.bucket;\n\t}\n\n\tpublic void setBucket(@Nullable String bucket) {\n\t\tthis.bucket = bucket;\n\t}\n\n\tpublic @Nullable String getToken() {\n\t\treturn this.token;\n\t}\n\n\tpublic void setToken(@Nullable String token) {\n\t\tthis.token = token;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/InfluxPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport io.micrometer.influx.InfluxApiVersion;\nimport io.micrometer.influx.InfluxConfig;\nimport io.micrometer.influx.InfluxConsistency;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link InfluxProperties} to an {@link InfluxConfig}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n */\nclass InfluxPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<InfluxProperties>\n\t\timplements InfluxConfig {\n\n\tInfluxPropertiesConfigAdapter(InfluxProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.influx.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String db() {\n\t\treturn obtain(InfluxProperties::getDb, InfluxConfig.super::db);\n\t}\n\n\t@Override\n\tpublic InfluxConsistency consistency() {\n\t\treturn obtain(InfluxProperties::getConsistency, InfluxConfig.super::consistency);\n\t}\n\n\t@Override\n\tpublic @Nullable String userName() {\n\t\treturn get(InfluxProperties::getUserName, InfluxConfig.super::userName);\n\t}\n\n\t@Override\n\tpublic @Nullable String password() {\n\t\treturn get(InfluxProperties::getPassword, InfluxConfig.super::password);\n\t}\n\n\t@Override\n\tpublic @Nullable String retentionPolicy() {\n\t\treturn get(InfluxProperties::getRetentionPolicy, InfluxConfig.super::retentionPolicy);\n\t}\n\n\t@Override\n\tpublic @Nullable Integer retentionReplicationFactor() {\n\t\treturn get(InfluxProperties::getRetentionReplicationFactor, InfluxConfig.super::retentionReplicationFactor);\n\t}\n\n\t@Override\n\tpublic @Nullable String retentionDuration() {\n\t\treturn get(InfluxProperties::getRetentionDuration, InfluxConfig.super::retentionDuration);\n\t}\n\n\t@Override\n\tpublic @Nullable String retentionShardDuration() {\n\t\treturn get(InfluxProperties::getRetentionShardDuration, InfluxConfig.super::retentionShardDuration);\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(InfluxProperties::getUri, InfluxConfig.super::uri);\n\t}\n\n\t@Override\n\tpublic boolean compressed() {\n\t\treturn obtain(InfluxProperties::isCompressed, InfluxConfig.super::compressed);\n\t}\n\n\t@Override\n\tpublic boolean autoCreateDb() {\n\t\treturn obtain(InfluxProperties::isAutoCreateDb, InfluxConfig.super::autoCreateDb);\n\t}\n\n\t@Override\n\tpublic InfluxApiVersion apiVersion() {\n\t\treturn obtain(InfluxProperties::getApiVersion, InfluxConfig.super::apiVersion);\n\t}\n\n\t@Override\n\tpublic @Nullable String org() {\n\t\treturn get(InfluxProperties::getOrg, InfluxConfig.super::org);\n\t}\n\n\t@Override\n\tpublic String bucket() {\n\t\treturn obtain(InfluxProperties::getBucket, InfluxConfig.super::bucket);\n\t}\n\n\t@Override\n\tpublic @Nullable String token() {\n\t\treturn get(InfluxProperties::getToken, InfluxConfig.super::token);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to InfluxDB.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/JmxMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.jmx.JmxConfig;\nimport io.micrometer.jmx.JmxMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to JMX.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(JmxMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"jmx\")\n@EnableConfigurationProperties(JmxProperties.class)\npublic final class JmxMetricsExportAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJmxConfig jmxConfig(JmxProperties jmxProperties) {\n\t\treturn new JmxPropertiesConfigAdapter(jmxProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJmxMeterRegistry jmxMeterRegistry(JmxConfig jmxConfig, Clock clock) {\n\t\treturn new JmxMeterRegistry(jmxConfig, clock);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/JmxProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring JMX metrics\n * export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.jmx.metrics.export\")\npublic class JmxProperties {\n\n\t/**\n\t * Whether exporting of metrics to this backend is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Metrics JMX domain name.\n\t */\n\tprivate String domain = \"metrics\";\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\tpublic String getDomain() {\n\t\treturn this.domain;\n\t}\n\n\tpublic void setDomain(String domain) {\n\t\tthis.domain = domain;\n\t}\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/JmxPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport java.time.Duration;\n\nimport io.micrometer.jmx.JmxConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link JmxProperties} to a {@link JmxConfig}.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n */\nclass JmxPropertiesConfigAdapter extends PropertiesConfigAdapter<JmxProperties> implements JmxConfig {\n\n\tJmxPropertiesConfigAdapter(JmxProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.jmx.metrics.export\";\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String key) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic String domain() {\n\t\treturn obtain(JmxProperties::getDomain, JmxConfig.super::domain);\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(JmxProperties::getStep, JmxConfig.super::step);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to JMX.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/KairosMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.kairos.KairosConfig;\nimport io.micrometer.kairos.KairosMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to KairosDB.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(KairosMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"kairos\")\n@EnableConfigurationProperties(KairosProperties.class)\npublic final class KairosMetricsExportAutoConfiguration {\n\n\tprivate final KairosProperties properties;\n\n\tKairosMetricsExportAutoConfiguration(KairosProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tKairosConfig kairosConfig() {\n\t\treturn new KairosPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tKairosMeterRegistry kairosMeterRegistry(KairosConfig kairosConfig, Clock clock) {\n\t\treturn KairosMeterRegistry.builder(kairosConfig)\n\t\t\t.clock(clock)\n\t\t\t.httpClient(\n\t\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()))\n\t\t\t.build();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/KairosProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring KairosDB\n * metrics export.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.kairos.metrics.export\")\npublic class KairosProperties extends StepRegistryProperties {\n\n\t/**\n\t * URI of the KairosDB server.\n\t */\n\tprivate String uri = \"http://localhost:8080/api/v1/datapoints\";\n\n\t/**\n\t * Login user of the KairosDB server.\n\t */\n\tprivate @Nullable String userName;\n\n\t/**\n\t * Login password of the KairosDB server.\n\t */\n\tprivate @Nullable String password;\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n\tpublic @Nullable String getUserName() {\n\t\treturn this.userName;\n\t}\n\n\tpublic void setUserName(@Nullable String userName) {\n\t\tthis.userName = userName;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/KairosPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport io.micrometer.kairos.KairosConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link KairosProperties} to a {@link KairosConfig}.\n *\n * @author Stephane Nicoll\n */\nclass KairosPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<KairosProperties>\n\t\timplements KairosConfig {\n\n\tKairosPropertiesConfigAdapter(KairosProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.kairos.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(KairosProperties::getUri, KairosConfig.super::uri);\n\t}\n\n\t@Override\n\tpublic @Nullable String userName() {\n\t\treturn get(KairosProperties::getUserName, KairosConfig.super::userName);\n\t}\n\n\t@Override\n\tpublic @Nullable String password() {\n\t\treturn get(KairosProperties::getPassword, KairosConfig.super::password);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to KairosDB.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/NewRelicMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.ipc.http.HttpUrlConnectionSender;\nimport io.micrometer.newrelic.ClientProviderType;\nimport io.micrometer.newrelic.NewRelicClientProvider;\nimport io.micrometer.newrelic.NewRelicConfig;\nimport io.micrometer.newrelic.NewRelicInsightsAgentClientProvider;\nimport io.micrometer.newrelic.NewRelicInsightsApiClientProvider;\nimport io.micrometer.newrelic.NewRelicMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to New Relic.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(NewRelicMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"newrelic\")\n@EnableConfigurationProperties(NewRelicProperties.class)\npublic final class NewRelicMetricsExportAutoConfiguration {\n\n\tprivate final NewRelicProperties properties;\n\n\tNewRelicMetricsExportAutoConfiguration(NewRelicProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tNewRelicConfig newRelicConfig() {\n\t\treturn new NewRelicPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tNewRelicClientProvider newRelicClientProvider(NewRelicConfig newRelicConfig) {\n\t\tif (newRelicConfig.clientProviderType() == ClientProviderType.INSIGHTS_AGENT) {\n\t\t\treturn new NewRelicInsightsAgentClientProvider(newRelicConfig);\n\t\t}\n\t\treturn new NewRelicInsightsApiClientProvider(newRelicConfig,\n\t\t\t\tnew HttpUrlConnectionSender(this.properties.getConnectTimeout(), this.properties.getReadTimeout()));\n\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tNewRelicMeterRegistry newRelicMeterRegistry(NewRelicConfig newRelicConfig, Clock clock,\n\t\t\tNewRelicClientProvider newRelicClientProvider) {\n\t\treturn NewRelicMeterRegistry.builder(newRelicConfig)\n\t\t\t.clock(clock)\n\t\t\t.clientProvider(newRelicClientProvider)\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/NewRelicProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport io.micrometer.newrelic.ClientProviderType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring New Relic\n * metrics export.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Neil Powell\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.newrelic.metrics.export\")\npublic class NewRelicProperties extends StepRegistryProperties {\n\n\t/**\n\t * Whether to send the meter name as the event type instead of using the 'event-type'\n\t * configuration property value. Can be set to 'true' if New Relic guidelines are not\n\t * being followed or event types consistent with previous Spring Boot releases are\n\t * required.\n\t */\n\tprivate boolean meterNameEventTypeEnabled;\n\n\t/**\n\t * The event type that should be published. This property will be ignored if\n\t * 'meter-name-event-type-enabled' is set to 'true'.\n\t */\n\tprivate String eventType = \"SpringBootSample\";\n\n\t/**\n\t * Client provider type to use.\n\t */\n\tprivate ClientProviderType clientProviderType = ClientProviderType.INSIGHTS_API;\n\n\t/**\n\t * New Relic API key.\n\t */\n\tprivate @Nullable String apiKey;\n\n\t/**\n\t * New Relic account ID.\n\t */\n\tprivate @Nullable String accountId;\n\n\t/**\n\t * URI to ship metrics to.\n\t */\n\tprivate String uri = \"https://insights-collector.newrelic.com\";\n\n\tpublic boolean isMeterNameEventTypeEnabled() {\n\t\treturn this.meterNameEventTypeEnabled;\n\t}\n\n\tpublic void setMeterNameEventTypeEnabled(boolean meterNameEventTypeEnabled) {\n\t\tthis.meterNameEventTypeEnabled = meterNameEventTypeEnabled;\n\t}\n\n\tpublic String getEventType() {\n\t\treturn this.eventType;\n\t}\n\n\tpublic void setEventType(String eventType) {\n\t\tthis.eventType = eventType;\n\t}\n\n\tpublic ClientProviderType getClientProviderType() {\n\t\treturn this.clientProviderType;\n\t}\n\n\tpublic void setClientProviderType(ClientProviderType clientProviderType) {\n\t\tthis.clientProviderType = clientProviderType;\n\t}\n\n\tpublic @Nullable String getApiKey() {\n\t\treturn this.apiKey;\n\t}\n\n\tpublic void setApiKey(@Nullable String apiKey) {\n\t\tthis.apiKey = apiKey;\n\t}\n\n\tpublic @Nullable String getAccountId() {\n\t\treturn this.accountId;\n\t}\n\n\tpublic void setAccountId(@Nullable String accountId) {\n\t\tthis.accountId = accountId;\n\t}\n\n\tpublic String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(String uri) {\n\t\tthis.uri = uri;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/NewRelicPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport io.micrometer.newrelic.ClientProviderType;\nimport io.micrometer.newrelic.NewRelicConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link NewRelicProperties} to a {@link NewRelicConfig}.\n *\n * @author Jon Schneider\n * @author Neil Powell\n * @since 4.0.0\n */\npublic class NewRelicPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<NewRelicProperties>\n\t\timplements NewRelicConfig {\n\n\tpublic NewRelicPropertiesConfigAdapter(NewRelicProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.newrelic.metrics.export\";\n\t}\n\n\t@Override\n\tpublic boolean meterNameEventTypeEnabled() {\n\t\treturn obtain(NewRelicProperties::isMeterNameEventTypeEnabled, NewRelicConfig.super::meterNameEventTypeEnabled);\n\t}\n\n\t@Override\n\tpublic String eventType() {\n\t\treturn obtain(NewRelicProperties::getEventType, NewRelicConfig.super::eventType);\n\t}\n\n\t@Override\n\tpublic ClientProviderType clientProviderType() {\n\t\treturn obtain(NewRelicProperties::getClientProviderType, NewRelicConfig.super::clientProviderType);\n\t}\n\n\t@Override\n\tpublic @Nullable String apiKey() {\n\t\treturn get(NewRelicProperties::getApiKey, NewRelicConfig.super::apiKey);\n\t}\n\n\t@Override\n\tpublic @Nullable String accountId() {\n\t\treturn get(NewRelicProperties::getAccountId, NewRelicConfig.super::accountId);\n\t}\n\n\t@Override\n\tpublic String uri() {\n\t\treturn obtain(NewRelicProperties::getUri, NewRelicConfig.super::uri);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to New Relic.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/JdkClientHttpSender.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpRequest.BodyPublishers;\nimport java.net.http.HttpResponse;\nimport java.net.http.HttpResponse.BodyHandlers;\nimport java.time.Duration;\n\nimport javax.net.ssl.SSLParameters;\n\nimport io.micrometer.core.ipc.http.HttpSender;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\n\n/**\n * {@link HttpSender} implementation using the JDK {@link HttpClient}.\n *\n * @author Moritz Halbritter\n */\nclass JdkClientHttpSender implements HttpSender {\n\n\tprivate final HttpClient httpClient;\n\n\tprivate final Duration timeout;\n\n\t/**\n\t * Creates a new {@link JdkClientHttpSender}.\n\t * @param connectTimeout the connect timeout\n\t * @param timeout the request timeout\n\t * @param sslBundle the SSL bundle to use for TLS configuration, or {@code null}\n\t */\n\tJdkClientHttpSender(Duration connectTimeout, Duration timeout, @Nullable SslBundle sslBundle) {\n\t\tthis.httpClient = buildHttpClient(connectTimeout, sslBundle);\n\t\tthis.timeout = timeout;\n\t}\n\n\tprivate static HttpClient buildHttpClient(Duration connectTimeout, @Nullable SslBundle sslBundle) {\n\t\tHttpClient.Builder builder = HttpClient.newBuilder().connectTimeout(connectTimeout);\n\t\tif (sslBundle != null) {\n\t\t\tbuilder.sslContext(sslBundle.createSslContext());\n\t\t\tbuilder.sslParameters(asSslParameters(sslBundle));\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\tprivate static SSLParameters asSslParameters(SslBundle sslBundle) {\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tSSLParameters parameters = new SSLParameters();\n\t\tparameters.setCipherSuites(options.getCiphers());\n\t\tparameters.setProtocols(options.getEnabledProtocols());\n\t\treturn parameters;\n\t}\n\n\t@Override\n\tpublic Response send(Request request) throws IOException {\n\t\tHttpRequest.Builder httpRequest = HttpRequest.newBuilder()\n\t\t\t.uri(URI.create(request.getUrl().toString()))\n\t\t\t.timeout(this.timeout);\n\t\trequest.getRequestHeaders().forEach(httpRequest::header);\n\t\thttpRequest.method(request.getMethod().name(), BodyPublishers.ofByteArray(request.getEntity()));\n\t\ttry {\n\t\t\tHttpResponse<String> response = this.httpClient.send(httpRequest.build(), BodyHandlers.ofString());\n\t\t\treturn new Response(response.statusCode(), response.body());\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new IOException(\"HTTP request interrupted\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to an OpenTelemetry Collector service.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic interface OtlpMetricsConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Address to where metrics will be published.\n\t * @return the address to where metrics will be published\n\t */\n\t@Nullable String getUrl();\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use or {@code null}\n\t * @since 4.1.0\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.registry.otlp.ExemplarContextProvider;\nimport io.micrometer.registry.otlp.OtlpConfig;\nimport io.micrometer.registry.otlp.OtlpHttpMetricsSender;\nimport io.micrometer.registry.otlp.OtlpMeterRegistry;\nimport io.micrometer.registry.otlp.OtlpMetricsSender;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryProperties;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to OTLP.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass({ OtlpMeterRegistry.class, OpenTelemetryProperties.class })\n@ConditionalOnEnabledMetricsExport(\"otlp\")\n@EnableConfigurationProperties({ OtlpMetricsProperties.class, OpenTelemetryProperties.class })\npublic final class OtlpMetricsExportAutoConfiguration {\n\n\tprivate final OtlpMetricsProperties properties;\n\n\tOtlpMetricsExportAutoConfiguration(OtlpMetricsProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tOtlpMetricsConnectionDetails otlpMetricsConnectionDetails(ObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesOtlpMetricsConnectionDetails(this.properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tOtlpConfig otlpConfig(OpenTelemetryProperties openTelemetryProperties,\n\t\t\tOtlpMetricsConnectionDetails connectionDetails, Environment environment) {\n\t\treturn new OtlpMetricsPropertiesConfigAdapter(this.properties, openTelemetryProperties, connectionDetails,\n\t\t\t\tenvironment);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(OtlpMetricsSender.class)\n\tOtlpHttpMetricsSender otlpMetricsSender(OtlpMetricsConnectionDetails connectionDetails) {\n\t\tDuration connectTimeout = this.properties.getConnectTimeout();\n\t\tDuration timeout = connectTimeout.plus(this.properties.getReadTimeout());\n\t\tJdkClientHttpSender httpSender = new JdkClientHttpSender(connectTimeout, timeout,\n\t\t\t\tconnectionDetails.getSslBundle());\n\t\treturn new OtlpHttpMetricsSender(httpSender);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.PLATFORM)\n\tOtlpMeterRegistry otlpMeterRegistry(OtlpConfig otlpConfig, Clock clock, OtlpMetricsSender metricsSender,\n\t\t\tObjectProvider<ExemplarContextProvider> exemplarContextProvider) {\n\t\treturn builder(otlpConfig, clock, metricsSender, exemplarContextProvider).build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tOtlpMeterRegistry otlpMeterRegistryVirtualThreads(OtlpConfig otlpConfig, Clock clock,\n\t\t\tOtlpMetricsSender metricsSender, ObjectProvider<ExemplarContextProvider> exemplarContextProvider) {\n\t\tVirtualThreadTaskExecutor executor = new VirtualThreadTaskExecutor(\"otlp-meter-registry-\");\n\t\treturn builder(otlpConfig, clock, metricsSender, exemplarContextProvider)\n\t\t\t.threadFactory(executor.getVirtualThreadFactory())\n\t\t\t.build();\n\t}\n\n\tprivate OtlpMeterRegistry.Builder builder(OtlpConfig otlpConfig, Clock clock, OtlpMetricsSender metricsSender,\n\t\t\tObjectProvider<ExemplarContextProvider> exemplarContextProvider) {\n\t\tOtlpMeterRegistry.Builder builder = OtlpMeterRegistry.builder(otlpConfig)\n\t\t\t.clock(clock)\n\t\t\t.metricsSender(metricsSender);\n\t\texemplarContextProvider.ifAvailable(builder::exemplarContextProvider);\n\t\treturn builder;\n\t}\n\n\t/**\n\t * Adapts {@link OtlpMetricsProperties} to {@link OtlpMetricsConnectionDetails}.\n\t */\n\tstatic class PropertiesOtlpMetricsConnectionDetails implements OtlpMetricsConnectionDetails {\n\n\t\tprivate final OtlpMetricsProperties properties;\n\n\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\tPropertiesOtlpMetricsConnectionDetails(OtlpMetricsProperties properties, @Nullable SslBundles sslBundles) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.sslBundles = sslBundles;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getUrl() {\n\t\t\treturn this.properties.getUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\tString bundleName = this.properties.getSsl().getBundle();\n\t\t\tif (StringUtils.hasLength(bundleName)) {\n\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\treturn this.sslBundles.getBundle(bundleName);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.registry.otlp.AggregationTemporality;\nimport io.micrometer.registry.otlp.CompressionMode;\nimport io.micrometer.registry.otlp.HistogramFlavor;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring OTLP metrics\n * export.\n *\n * @author Eddú Meléndez\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.otlp.metrics.export\")\npublic class OtlpMetricsProperties extends StepRegistryProperties {\n\n\t/**\n\t * URI of the OTLP server.\n\t */\n\tprivate @Nullable String url;\n\n\t/**\n\t * Aggregation temporality of sums. It defines the way additive values are expressed.\n\t * This setting depends on the backend you use, some only support one temporality.\n\t */\n\tprivate AggregationTemporality aggregationTemporality = AggregationTemporality.CUMULATIVE;\n\n\t/**\n\t * Compression mode to use when exporting metrics.\n\t */\n\tprivate CompressionMode compressionMode = CompressionMode.NONE;\n\n\t/**\n\t * Headers for the exported metrics.\n\t */\n\tprivate @Nullable Map<String, String> headers;\n\n\t/**\n\t * Default histogram type when histogram publishing is enabled.\n\t */\n\tprivate HistogramFlavor histogramFlavor = HistogramFlavor.EXPLICIT_BUCKET_HISTOGRAM;\n\n\t/**\n\t * Whether to publish a separate gauge for the max value of histogram-based meters.\n\t */\n\tprivate @Nullable Boolean publishMaxGaugeForHistograms;\n\n\t/**\n\t * Max scale to use for exponential histograms, if configured.\n\t */\n\tprivate int maxScale = 20;\n\n\t/**\n\t * Default maximum number of buckets to be used for exponential histograms, if\n\t * configured. This has no effect on explicit bucket histograms.\n\t */\n\tprivate int maxBucketCount = 160;\n\n\t/**\n\t * Time unit for exported metrics.\n\t */\n\tprivate TimeUnit baseTimeUnit = TimeUnit.MILLISECONDS;\n\n\t/**\n\t * Per-meter properties that can be used to override defaults.\n\t */\n\tprivate final Map<String, Meter> meter = new LinkedHashMap<>();\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic @Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\tpublic void setUrl(@Nullable String url) {\n\t\tthis.url = url;\n\t}\n\n\tpublic AggregationTemporality getAggregationTemporality() {\n\t\treturn this.aggregationTemporality;\n\t}\n\n\tpublic void setAggregationTemporality(AggregationTemporality aggregationTemporality) {\n\t\tthis.aggregationTemporality = aggregationTemporality;\n\t}\n\n\tpublic CompressionMode getCompressionMode() {\n\t\treturn this.compressionMode;\n\t}\n\n\tpublic void setCompressionMode(CompressionMode compressionMode) {\n\t\tthis.compressionMode = compressionMode;\n\t}\n\n\tpublic @Nullable Map<String, String> getHeaders() {\n\t\treturn this.headers;\n\t}\n\n\tpublic void setHeaders(@Nullable Map<String, String> headers) {\n\t\tthis.headers = headers;\n\t}\n\n\tpublic HistogramFlavor getHistogramFlavor() {\n\t\treturn this.histogramFlavor;\n\t}\n\n\tpublic void setHistogramFlavor(HistogramFlavor histogramFlavor) {\n\t\tthis.histogramFlavor = histogramFlavor;\n\t}\n\n\tpublic @Nullable Boolean getPublishMaxGaugeForHistograms() {\n\t\treturn this.publishMaxGaugeForHistograms;\n\t}\n\n\tpublic void setPublishMaxGaugeForHistograms(@Nullable Boolean publishMaxGaugeForHistograms) {\n\t\tthis.publishMaxGaugeForHistograms = publishMaxGaugeForHistograms;\n\t}\n\n\tpublic int getMaxScale() {\n\t\treturn this.maxScale;\n\t}\n\n\tpublic void setMaxScale(int maxScale) {\n\t\tthis.maxScale = maxScale;\n\t}\n\n\tpublic int getMaxBucketCount() {\n\t\treturn this.maxBucketCount;\n\t}\n\n\tpublic void setMaxBucketCount(int maxBucketCount) {\n\t\tthis.maxBucketCount = maxBucketCount;\n\t}\n\n\tpublic TimeUnit getBaseTimeUnit() {\n\t\treturn this.baseTimeUnit;\n\t}\n\n\tpublic void setBaseTimeUnit(TimeUnit baseTimeUnit) {\n\t\tthis.baseTimeUnit = baseTimeUnit;\n\t}\n\n\tpublic Map<String, Meter> getMeter() {\n\t\treturn this.meter;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\t/**\n\t * Per-meter settings.\n\t */\n\tpublic static class Meter {\n\n\t\t/**\n\t\t * Maximum number of buckets to be used for exponential histograms, if configured.\n\t\t * This has no effect on explicit bucket histograms.\n\t\t */\n\t\tprivate @Nullable Integer maxBucketCount;\n\n\t\t/**\n\t\t * Histogram type when histogram publishing is enabled.\n\t\t */\n\t\tprivate @Nullable HistogramFlavor histogramFlavor;\n\n\t\tpublic @Nullable Integer getMaxBucketCount() {\n\t\t\treturn this.maxBucketCount;\n\t\t}\n\n\t\tpublic void setMaxBucketCount(@Nullable Integer maxBucketCount) {\n\t\t\tthis.maxBucketCount = maxBucketCount;\n\t\t}\n\n\t\tpublic @Nullable HistogramFlavor getHistogramFlavor() {\n\t\t\treturn this.histogramFlavor;\n\t\t}\n\n\t\tpublic void setHistogramFlavor(@Nullable HistogramFlavor histogramFlavor) {\n\t\t\tthis.histogramFlavor = histogramFlavor;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.registry.otlp.AggregationTemporality;\nimport io.micrometer.registry.otlp.CompressionMode;\nimport io.micrometer.registry.otlp.HistogramFlavor;\nimport io.micrometer.registry.otlp.OtlpConfig;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsProperties.Meter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryProperties;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryResourceAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Adapter to convert {@link OtlpMetricsProperties} to an {@link OtlpConfig}.\n *\n * @author Eddú Meléndez\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n */\nclass OtlpMetricsPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<OtlpMetricsProperties>\n\t\timplements OtlpConfig {\n\n\tprivate final OpenTelemetryProperties openTelemetryProperties;\n\n\tprivate final OtlpMetricsConnectionDetails connectionDetails;\n\n\tprivate final Environment environment;\n\n\tOtlpMetricsPropertiesConfigAdapter(OtlpMetricsProperties properties,\n\t\t\tOpenTelemetryProperties openTelemetryProperties, OtlpMetricsConnectionDetails connectionDetails,\n\t\t\tEnvironment environment) {\n\t\tsuper(properties);\n\t\tthis.connectionDetails = connectionDetails;\n\t\tthis.openTelemetryProperties = openTelemetryProperties;\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.otlp.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String url() {\n\t\treturn obtain((properties) -> this.connectionDetails.getUrl(), OtlpConfig.super::url);\n\t}\n\n\t@Override\n\tpublic AggregationTemporality aggregationTemporality() {\n\t\treturn obtain(OtlpMetricsProperties::getAggregationTemporality, OtlpConfig.super::aggregationTemporality);\n\t}\n\n\t@Override\n\tpublic CompressionMode compressionMode() {\n\t\treturn obtain(OtlpMetricsProperties::getCompressionMode, OtlpConfig.super::compressionMode);\n\t}\n\n\t@Override\n\tpublic Map<String, String> resourceAttributes() {\n\t\tMap<String, String> resourceAttributes = new LinkedHashMap<>();\n\t\tnew OpenTelemetryResourceAttributes(this.environment, this.openTelemetryProperties.getResourceAttributes())\n\t\t\t.applyTo(resourceAttributes::put);\n\t\treturn Collections.unmodifiableMap(resourceAttributes);\n\t}\n\n\t@Override\n\tpublic Map<String, String> headers() {\n\t\treturn obtain(OtlpMetricsProperties::getHeaders, OtlpConfig.super::headers);\n\t}\n\n\t@Override\n\tpublic HistogramFlavor histogramFlavor() {\n\t\treturn obtain(OtlpMetricsProperties::getHistogramFlavor, OtlpConfig.super::histogramFlavor);\n\t}\n\n\t@Override\n\tpublic Map<String, HistogramFlavor> histogramFlavorPerMeter() {\n\t\treturn obtain(perMeter(Meter::getHistogramFlavor), OtlpConfig.super::histogramFlavorPerMeter);\n\t}\n\n\t@Override\n\tpublic Map<String, Integer> maxBucketsPerMeter() {\n\t\treturn obtain(perMeter(Meter::getMaxBucketCount), OtlpConfig.super::maxBucketsPerMeter);\n\t}\n\n\t@Override\n\tpublic boolean publishMaxGaugeForHistograms() {\n\t\treturn obtain(OtlpMetricsProperties::getPublishMaxGaugeForHistograms,\n\t\t\t\tOtlpConfig.super::publishMaxGaugeForHistograms);\n\t}\n\n\t@Override\n\tpublic int maxScale() {\n\t\treturn obtain(OtlpMetricsProperties::getMaxScale, OtlpConfig.super::maxScale);\n\t}\n\n\t@Override\n\tpublic int maxBucketCount() {\n\t\treturn obtain(OtlpMetricsProperties::getMaxBucketCount, OtlpConfig.super::maxBucketCount);\n\t}\n\n\t@Override\n\tpublic TimeUnit baseTimeUnit() {\n\t\treturn obtain(OtlpMetricsProperties::getBaseTimeUnit, OtlpConfig.super::baseTimeUnit);\n\t}\n\n\tprivate <V> Getter<OtlpMetricsProperties, Map<String, V>> perMeter(Getter<Meter, V> getter) {\n\t\treturn (properties) -> {\n\t\t\tif (CollectionUtils.isEmpty(properties.getMeter())) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tMap<String, V> perMeter = new LinkedHashMap<>();\n\t\t\tproperties.getMeter().forEach((key, meterProperties) -> {\n\t\t\t\tV value = getter.get(meterProperties);\n\t\t\t\tif (value != null) {\n\t\t\t\t\tperMeter.put(key, value);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn (!perMeter.isEmpty()) ? perMeter : null;\n\t\t};\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to OTLP.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for metrics exporter.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.prometheusmetrics.PrometheusConfig;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport io.prometheus.metrics.exporter.pushgateway.Format;\nimport io.prometheus.metrics.exporter.pushgateway.PushGateway;\nimport io.prometheus.metrics.exporter.pushgateway.PushGateway.Builder;\nimport io.prometheus.metrics.exporter.pushgateway.Scheme;\nimport io.prometheus.metrics.model.registry.PrometheusRegistry;\nimport io.prometheus.metrics.tracer.common.SpanContext;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to Prometheus.\n *\n * @author Jon Schneider\n * @author David J. M. Karlsen\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(PrometheusMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"prometheus\")\n@EnableConfigurationProperties(PrometheusProperties.class)\npublic final class PrometheusMetricsExportAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPrometheusConfig prometheusConfig(PrometheusProperties prometheusProperties) {\n\t\treturn new PrometheusPropertiesConfigAdapter(prometheusProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPrometheusMeterRegistry prometheusMeterRegistry(PrometheusConfig prometheusConfig,\n\t\t\tPrometheusRegistry prometheusRegistry, Clock clock, ObjectProvider<SpanContext> spanContext) {\n\t\treturn new PrometheusMeterRegistry(prometheusConfig, prometheusRegistry, clock, spanContext.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPrometheusRegistry prometheusRegistry() {\n\t\treturn new PrometheusRegistry();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ PrometheusScrapeEndpoint.class, ConditionalOnAvailableEndpoint.class })\n\t@ConditionalOnAvailableEndpoint(PrometheusScrapeEndpoint.class)\n\tstatic class PrometheusScrapeEndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tPrometheusScrapeEndpoint prometheusEndpoint(PrometheusRegistry prometheusRegistry,\n\t\t\t\tPrometheusConfig prometheusConfig) {\n\t\t\treturn new PrometheusScrapeEndpoint(prometheusRegistry, prometheusConfig.prometheusProperties());\n\t\t}\n\n\t}\n\n\t/**\n\t * Configuration for <a href=\"https://github.com/prometheus/pushgateway\">Prometheus\n\t * Pushgateway</a>.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ PushGateway.class, PrometheusPushGatewayManager.class })\n\t@ConditionalOnBooleanProperty(\"management.prometheus.metrics.export.pushgateway.enabled\")\n\tstatic class PrometheusPushGatewayConfiguration {\n\n\t\t/**\n\t\t * The fallback job name. We use 'spring' since there's a history of Prometheus\n\t\t * Spring integration defaulting to that name from when Prometheus integration\n\t\t * didn't exist in Spring itself.\n\t\t */\n\t\tprivate static final String FALLBACK_JOB = \"spring\";\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tPrometheusPushGatewayManager prometheusPushGatewayManager(PrometheusRegistry registry,\n\t\t\t\tPrometheusProperties prometheusProperties, Environment environment) {\n\t\t\tPrometheusProperties.Pushgateway properties = prometheusProperties.getPushgateway();\n\t\t\tPushGateway pushGateway = initializePushGateway(registry, properties, environment);\n\t\t\treturn new PrometheusPushGatewayManager(pushGateway, properties.getPushRate(),\n\t\t\t\t\tproperties.getShutdownOperation());\n\t\t}\n\n\t\tprivate PushGateway initializePushGateway(PrometheusRegistry registry,\n\t\t\t\tPrometheusProperties.Pushgateway properties, Environment environment) {\n\t\t\tBuilder builder = PushGateway.builder()\n\t\t\t\t.address(properties.getAddress())\n\t\t\t\t.scheme(scheme(properties))\n\t\t\t\t.format(format(properties))\n\t\t\t\t.job(getJob(properties, environment))\n\t\t\t\t.registry(registry);\n\t\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleNonNullValuesIn((entries) -> {\n\t\t\t\tentries.put(\"management.prometheus.metrics.export.pushgateway.token\", properties.getToken());\n\t\t\t\tentries.put(\"management.prometheus.metrics.export.pushgateway.username\", properties.getUsername());\n\t\t\t});\n\t\t\tif (StringUtils.hasText(properties.getToken())) {\n\t\t\t\tbuilder.bearerToken(properties.getToken());\n\t\t\t}\n\t\t\telse if (StringUtils.hasText(properties.getUsername())) {\n\t\t\t\tbuilder.basicAuth(properties.getUsername(), properties.getPassword());\n\t\t\t}\n\t\t\tproperties.getGroupingKey().forEach(builder::groupingKey);\n\t\t\treturn builder.build();\n\t\t}\n\n\t\tprivate Scheme scheme(PrometheusProperties.Pushgateway properties) {\n\t\t\treturn switch (properties.getScheme()) {\n\t\t\t\tcase HTTP -> Scheme.HTTP;\n\t\t\t\tcase HTTPS -> Scheme.HTTPS;\n\t\t\t};\n\t\t}\n\n\t\tprivate Format format(PrometheusProperties.Pushgateway properties) {\n\t\t\treturn switch (properties.getFormat()) {\n\t\t\t\tcase PROTOBUF -> Format.PROMETHEUS_PROTOBUF;\n\t\t\t\tcase TEXT -> Format.PROMETHEUS_TEXT;\n\t\t\t};\n\t\t}\n\n\t\tprivate String getJob(PrometheusProperties.Pushgateway properties, Environment environment) {\n\t\t\tString job = properties.getJob();\n\t\t\treturn (job != null) ? job : environment.getProperty(\"spring.application.name\", FALLBACK_JOB);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusOutputFormat.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport io.prometheus.metrics.expositionformats.ExpositionFormats;\nimport io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;\nimport io.prometheus.metrics.expositionformats.PrometheusProtobufWriter;\nimport io.prometheus.metrics.expositionformats.PrometheusTextFormatWriter;\nimport io.prometheus.metrics.model.snapshots.MetricSnapshots;\n\nimport org.springframework.boot.actuate.endpoint.Producible;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.MimeTypeUtils;\n\n/**\n * A {@link Producible} enum for supported Prometheus formats.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic enum PrometheusOutputFormat implements Producible<PrometheusOutputFormat> {\n\n\t/**\n\t * Prometheus text version 0.0.4.\n\t */\n\tCONTENT_TYPE_004(PrometheusTextFormatWriter.CONTENT_TYPE) {\n\n\t\t@Override\n\t\tvoid write(ExpositionFormats expositionFormats, OutputStream outputStream, MetricSnapshots snapshots)\n\t\t\t\tthrows IOException {\n\t\t\texpositionFormats.getPrometheusTextFormatWriter().write(outputStream, snapshots);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isDefault() {\n\t\t\treturn true;\n\t\t}\n\n\t},\n\n\t/**\n\t * OpenMetrics text version 1.0.0.\n\t */\n\tCONTENT_TYPE_OPENMETRICS_100(OpenMetricsTextFormatWriter.CONTENT_TYPE) {\n\n\t\t@Override\n\t\tvoid write(ExpositionFormats expositionFormats, OutputStream outputStream, MetricSnapshots snapshots)\n\t\t\t\tthrows IOException {\n\t\t\texpositionFormats.getOpenMetricsTextFormatWriter().write(outputStream, snapshots);\n\t\t}\n\n\t},\n\n\t/**\n\t * Prometheus metrics protobuf.\n\t */\n\tCONTENT_TYPE_PROTOBUF(PrometheusProtobufWriter.CONTENT_TYPE) {\n\n\t\t@Override\n\t\tvoid write(ExpositionFormats expositionFormats, OutputStream outputStream, MetricSnapshots snapshots)\n\t\t\t\tthrows IOException {\n\t\t\texpositionFormats.getPrometheusProtobufWriter().write(outputStream, snapshots);\n\t\t}\n\n\t};\n\n\tprivate final MimeType mimeType;\n\n\tPrometheusOutputFormat(String mimeType) {\n\t\tthis.mimeType = MimeTypeUtils.parseMimeType(mimeType);\n\t}\n\n\t@Override\n\tpublic MimeType getProducedMimeType() {\n\t\treturn this.mimeType;\n\t}\n\n\tabstract void write(ExpositionFormats expositionFormats, OutputStream outputStream, MetricSnapshots snapshots)\n\t\t\tthrows IOException;\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring metrics export\n * to Prometheus.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.prometheus.metrics.export\")\npublic class PrometheusProperties {\n\n\t/**\n\t * Whether exporting of metrics to this backend is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Whether to enable publishing descriptions as part of the scrape payload to\n\t * Prometheus. Turn this off to minimize the amount of data sent on each scrape.\n\t */\n\tprivate boolean descriptions = true;\n\n\t/**\n\t * Configuration options for using Prometheus Pushgateway, allowing metrics to be\n\t * pushed when they cannot be scraped.\n\t */\n\tprivate final Pushgateway pushgateway = new Pushgateway();\n\n\t/**\n\t * Additional properties to pass to the Prometheus client.\n\t */\n\tprivate final Map<String, String> properties = new HashMap<>();\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\tpublic boolean isDescriptions() {\n\t\treturn this.descriptions;\n\t}\n\n\tpublic void setDescriptions(boolean descriptions) {\n\t\tthis.descriptions = descriptions;\n\t}\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Pushgateway getPushgateway() {\n\t\treturn this.pushgateway;\n\t}\n\n\tpublic Map<String, String> getProperties() {\n\t\treturn this.properties;\n\t}\n\n\t/**\n\t * Configuration options for push-based interaction with Prometheus.\n\t */\n\tpublic static class Pushgateway {\n\n\t\t/**\n\t\t * Enable publishing over a Prometheus Pushgateway.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Address (host:port) for the Pushgateway.\n\t\t */\n\t\tprivate String address = \"localhost:9091\";\n\n\t\t/**\n\t\t * Scheme to use when pushing metrics.\n\t\t */\n\t\tprivate Scheme scheme = Scheme.HTTP;\n\n\t\t/**\n\t\t * Login user of the Prometheus Pushgateway.\n\t\t */\n\t\tprivate @Nullable String username;\n\n\t\t/**\n\t\t * Login password of the Prometheus Pushgateway.\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\t/**\n\t\t * Token to use for authentication with the Prometheus Pushgateway.\n\t\t */\n\t\tprivate @Nullable String token;\n\n\t\t/**\n\t\t * Format to use when pushing metrics.\n\t\t */\n\t\tprivate Format format = Format.PROTOBUF;\n\n\t\t/**\n\t\t * Frequency with which to push metrics.\n\t\t */\n\t\tprivate Duration pushRate = Duration.ofMinutes(1);\n\n\t\t/**\n\t\t * Job identifier for this application instance.\n\t\t */\n\t\tprivate @Nullable String job;\n\n\t\t/**\n\t\t * Grouping key for the pushed metrics.\n\t\t */\n\t\tprivate Map<String, String> groupingKey = new HashMap<>();\n\n\t\t/**\n\t\t * Operation that should be performed on shutdown.\n\t\t */\n\t\tprivate ShutdownOperation shutdownOperation = ShutdownOperation.NONE;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic String getAddress() {\n\t\t\treturn this.address;\n\t\t}\n\n\t\tpublic void setAddress(String address) {\n\t\t\tthis.address = address;\n\t\t}\n\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t\tpublic Duration getPushRate() {\n\t\t\treturn this.pushRate;\n\t\t}\n\n\t\tpublic void setPushRate(Duration pushRate) {\n\t\t\tthis.pushRate = pushRate;\n\t\t}\n\n\t\tpublic @Nullable String getJob() {\n\t\t\treturn this.job;\n\t\t}\n\n\t\tpublic void setJob(@Nullable String job) {\n\t\t\tthis.job = job;\n\t\t}\n\n\t\tpublic Map<String, String> getGroupingKey() {\n\t\t\treturn this.groupingKey;\n\t\t}\n\n\t\tpublic void setGroupingKey(Map<String, String> groupingKey) {\n\t\t\tthis.groupingKey = groupingKey;\n\t\t}\n\n\t\tpublic ShutdownOperation getShutdownOperation() {\n\t\t\treturn this.shutdownOperation;\n\t\t}\n\n\t\tpublic void setShutdownOperation(ShutdownOperation shutdownOperation) {\n\t\t\tthis.shutdownOperation = shutdownOperation;\n\t\t}\n\n\t\tpublic Scheme getScheme() {\n\t\t\treturn this.scheme;\n\t\t}\n\n\t\tpublic void setScheme(Scheme scheme) {\n\t\t\tthis.scheme = scheme;\n\t\t}\n\n\t\tpublic @Nullable String getToken() {\n\t\t\treturn this.token;\n\t\t}\n\n\t\tpublic void setToken(@Nullable String token) {\n\t\t\tthis.token = token;\n\t\t}\n\n\t\tpublic Format getFormat() {\n\t\t\treturn this.format;\n\t\t}\n\n\t\tpublic void setFormat(Format format) {\n\t\t\tthis.format = format;\n\t\t}\n\n\t\tpublic enum Format {\n\n\t\t\t/**\n\t\t\t * Push metrics in text format.\n\t\t\t */\n\t\t\tTEXT,\n\n\t\t\t/**\n\t\t\t * Push metrics in protobuf format.\n\t\t\t */\n\t\t\tPROTOBUF\n\n\t\t}\n\n\t\tpublic enum Scheme {\n\n\t\t\t/**\n\t\t\t * Use HTTP to push metrics.\n\t\t\t */\n\t\t\tHTTP,\n\n\t\t\t/**\n\t\t\t * Use HTTPS to push metrics.\n\t\t\t */\n\t\t\tHTTPS\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport java.time.Duration;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport io.micrometer.prometheusmetrics.PrometheusConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link PrometheusProperties} to a {@link PrometheusConfig}.\n *\n * @author Jon Schneider\n * @author Phillip Webb\n */\nclass PrometheusPropertiesConfigAdapter extends PropertiesConfigAdapter<PrometheusProperties>\n\t\timplements PrometheusConfig {\n\n\tPrometheusPropertiesConfigAdapter(PrometheusProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.prometheus.metrics.export\";\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String key) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean descriptions() {\n\t\treturn obtain(PrometheusProperties::isDescriptions, PrometheusConfig.super::descriptions);\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(PrometheusProperties::getStep, PrometheusConfig.super::step);\n\t}\n\n\t@Override\n\tpublic @Nullable Properties prometheusProperties() {\n\t\treturn get(this::fromPropertiesMap, PrometheusConfig.super::prometheusProperties);\n\t}\n\n\tprivate @Nullable Properties fromPropertiesMap(PrometheusProperties prometheusProperties) {\n\t\tMap<String, String> additionalProperties = prometheusProperties.getProperties();\n\t\tif (additionalProperties.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\tProperties properties = PrometheusConfig.super.prometheusProperties();\n\t\tif (properties == null) {\n\t\t\tproperties = new Properties();\n\t\t}\n\t\tproperties.putAll(additionalProperties);\n\t\treturn properties;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusScrapeEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport io.prometheus.metrics.config.PrometheusProperties;\nimport io.prometheus.metrics.config.PrometheusPropertiesLoader;\nimport io.prometheus.metrics.expositionformats.ExpositionFormats;\nimport io.prometheus.metrics.model.registry.PrometheusRegistry;\nimport io.prometheus.metrics.model.snapshots.MetricSnapshots;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;\n\n/**\n * {@link Endpoint @Endpoint} that outputs metrics in a format that can be scraped by the\n * Prometheus server.\n *\n * @author Jon Schneider\n * @author Johnny Lim\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@WebEndpoint(id = \"prometheus\")\npublic class PrometheusScrapeEndpoint {\n\n\tprivate static final int METRICS_SCRAPE_CHARS_EXTRA = 1024;\n\n\tprivate final PrometheusRegistry prometheusRegistry;\n\n\tprivate final ExpositionFormats expositionFormats;\n\n\tprivate volatile int nextMetricsScrapeSize = 16;\n\n\t/**\n\t * Creates a new {@link PrometheusScrapeEndpoint}.\n\t * @param prometheusRegistry the Prometheus registry to use\n\t * @param exporterProperties the properties used to configure Prometheus'\n\t * {@link ExpositionFormats}\n\t * @since 3.3.1\n\t */\n\tpublic PrometheusScrapeEndpoint(PrometheusRegistry prometheusRegistry, @Nullable Properties exporterProperties) {\n\t\tthis.prometheusRegistry = prometheusRegistry;\n\t\tPrometheusProperties prometheusProperties = (exporterProperties != null)\n\t\t\t\t? PrometheusPropertiesLoader.load(exporterProperties) : PrometheusPropertiesLoader.load();\n\t\tthis.expositionFormats = ExpositionFormats.init(prometheusProperties);\n\t}\n\n\t@ReadOperation(producesFrom = PrometheusOutputFormat.class)\n\tpublic WebEndpointResponse<byte[]> scrape(PrometheusOutputFormat format, @Nullable Set<String> includedNames) {\n\t\ttry {\n\t\t\tByteArrayOutputStream outputStream = new ByteArrayOutputStream(this.nextMetricsScrapeSize);\n\t\t\tMetricSnapshots metricSnapshots = (includedNames != null)\n\t\t\t\t\t? this.prometheusRegistry.scrape(includedNames::contains) : this.prometheusRegistry.scrape();\n\t\t\tformat.write(this.expositionFormats, outputStream, metricSnapshots);\n\t\t\tbyte[] content = outputStream.toByteArray();\n\t\t\tthis.nextMetricsScrapeSize = content.length + METRICS_SCRAPE_CHARS_EXTRA;\n\t\t\treturn new WebEndpointResponse<>(content, format);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Writing metrics failed\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Prometheus.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/PropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Base class for properties to config adapters.\n *\n * @param <T> the properties type\n * @author Phillip Webb\n * @author Nikolay Rybak\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class PropertiesConfigAdapter<T> {\n\n\tprotected final T properties;\n\n\t/**\n\t * Create a new {@link PropertiesConfigAdapter} instance.\n\t * @param properties the source properties\n\t */\n\tpublic PropertiesConfigAdapter(T properties) {\n\t\tAssert.notNull(properties, \"'properties' must not be null\");\n\t\tthis.properties = properties;\n\t}\n\n\t/**\n\t * Get the value from the properties or use a fallback from the {@code defaults}.\n\t * @param getter the getter for the properties\n\t * @param fallback the fallback method, usually super interface method reference\n\t * @param <V> the value type\n\t * @return the property or fallback value\n\t */\n\tprotected final <V> @Nullable V get(Getter<T, V> getter, Fallback<V> fallback) {\n\t\tV value = getter.get(this.properties);\n\t\treturn (value != null) ? value : fallback.get();\n\t}\n\n\t/**\n\t * Get the value from the properties or use a fallback from the {@code defaults}.\n\t * @param getter the getter for the properties\n\t * @param fallback the fallback method, usually super interface method reference\n\t * @param <V> the value type\n\t * @return the property or fallback value\n\t */\n\tprotected final <V> V obtain(Getter<T, V> getter, RequiredFallback<V> fallback) {\n\t\tV value = getter.get(this.properties);\n\t\tif (value != null) {\n\t\t\treturn value;\n\t\t}\n\t\tV fallbackValue = fallback.get();\n\t\tAssert.state(fallbackValue != null, \"'fallbackValue' must not be null\");\n\t\treturn fallbackValue;\n\t}\n\n\t/**\n\t * Gets a value from the given properties.\n\t *\n\t * @param <T> the type of the properties\n\t * @param <V> the type of the value\n\t */\n\t@FunctionalInterface\n\tprotected interface Getter<T, V> {\n\n\t\t/**\n\t\t * Gets a value from the given properties.\n\t\t * @param properties the properties\n\t\t * @return the value or {@code null}\n\t\t */\n\t\t@Nullable V get(T properties);\n\n\t}\n\n\t/**\n\t * Gets the fallback value, if any.\n\t *\n\t * @param <V> the type of the value\n\t */\n\t@FunctionalInterface\n\tprotected interface Fallback<V> {\n\n\t\t/**\n\t\t * Gets the fallback value, if any.\n\t\t * @return the value or {@code null}\n\t\t */\n\t\t@Nullable V get();\n\n\t}\n\n\t/**\n\t * Gets the fallback value.\n\t *\n\t * @param <V> the type of the value\n\t */\n\t@FunctionalInterface\n\tprotected interface RequiredFallback<V> {\n\n\t\t/**\n\t\t * Gets the fallback value.\n\t\t * @return the value\n\t\t */\n\t\tV get();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/PushRegistryProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport java.time.Duration;\n\n/**\n * Base class for properties that configure a metrics registry that pushes aggregated\n * metrics on a regular interval.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic abstract class PushRegistryProperties {\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\t/**\n\t * Whether exporting of metrics to this backend is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Connection timeout for requests to this backend.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(1);\n\n\t/**\n\t * Read timeout for requests to this backend.\n\t */\n\tprivate Duration readTimeout = Duration.ofSeconds(10);\n\n\t/**\n\t * Number of measurements per request to use for this backend. If more measurements\n\t * are found, then multiple requests will be made.\n\t */\n\tprivate Integer batchSize = 10000;\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic Duration getReadTimeout() {\n\t\treturn this.readTimeout;\n\t}\n\n\tpublic void setReadTimeout(Duration readTimeout) {\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\tpublic Integer getBatchSize() {\n\t\treturn this.batchSize;\n\t}\n\n\tpublic void setBatchSize(Integer batchSize) {\n\t\tthis.batchSize = batchSize;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/PushRegistryPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.push.PushRegistryConfig;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Base class for {@link PushRegistryProperties} to {@link PushRegistryConfig} adapters.\n *\n * @param <T> the properties type\n * @author Jon Schneider\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\npublic abstract class PushRegistryPropertiesConfigAdapter<T extends PushRegistryProperties>\n\t\textends PropertiesConfigAdapter<T> implements PushRegistryConfig {\n\n\tpublic PushRegistryPropertiesConfigAdapter(T properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String k) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(T::getStep, PushRegistryConfig.super::step);\n\t}\n\n\t@Override\n\tpublic boolean enabled() {\n\t\treturn obtain(T::isEnabled, PushRegistryConfig.super::enabled);\n\t}\n\n\t@Override\n\tpublic int batchSize() {\n\t\treturn obtain(T::getBatchSize, PushRegistryConfig.super::batchSize);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/StepRegistryProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\n/**\n * {@link PushRegistryProperties} extensions for registries that are step-normalized.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic abstract class StepRegistryProperties extends PushRegistryProperties {\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/StepRegistryPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport io.micrometer.core.instrument.step.StepRegistryConfig;\n\n/**\n * Base class for {@link StepRegistryProperties} to {@link StepRegistryConfig} adapters.\n *\n * @param <T> the properties type\n * @author Jon Schneider\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\npublic abstract class StepRegistryPropertiesConfigAdapter<T extends StepRegistryProperties>\n\t\textends PushRegistryPropertiesConfigAdapter<T> {\n\n\tpublic StepRegistryPropertiesConfigAdapter(T properties) {\n\t\tsuper(properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Base properties and adapters used when exporting actuator metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/SimpleMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to a\n * {@link SimpleMeterRegistry}. Auto-configured after all other {@link MeterRegistry}\n * beans and only used as a fallback.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\n@AutoConfiguration(before = CompositeMeterRegistryAutoConfiguration.class, after = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@EnableConfigurationProperties(SimpleProperties.class)\n@ConditionalOnMissingBean(MeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"simple\")\npublic final class SimpleMetricsExportAutoConfiguration {\n\n\t@Bean\n\tSimpleMeterRegistry simpleMeterRegistry(SimpleConfig config, Clock clock) {\n\t\treturn new SimpleMeterRegistry(config, clock);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSimpleConfig simpleConfig(SimpleProperties simpleProperties) {\n\t\treturn new SimplePropertiesConfigAdapter(simpleProperties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/SimpleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.simple.CountingMode;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring metrics export\n * to a {@link SimpleMeterRegistry}.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.simple.metrics.export\")\npublic class SimpleProperties {\n\n\t/**\n\t * Whether exporting of metrics to this backend is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Step size (i.e. reporting frequency) to use.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\t/**\n\t * Counting mode.\n\t */\n\tprivate CountingMode mode = CountingMode.CUMULATIVE;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic CountingMode getMode() {\n\t\treturn this.mode;\n\t}\n\n\tpublic void setMode(CountingMode mode) {\n\t\tthis.mode = mode;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/SimplePropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.simple.CountingMode;\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link SimpleProperties} to a {@link SimpleConfig}.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\npublic class SimplePropertiesConfigAdapter extends PropertiesConfigAdapter<SimpleProperties> implements SimpleConfig {\n\n\tpublic SimplePropertiesConfigAdapter(SimpleProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.simple.metrics.export\";\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String k) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(SimpleProperties::getStep, SimpleConfig.super::step);\n\t}\n\n\t@Override\n\tpublic CountingMode mode() {\n\t\treturn obtain(SimpleProperties::getMode, SimpleConfig.super::mode);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to a simple in-memory store.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/StackdriverMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.stackdriver.StackdriverConfig;\nimport io.micrometer.stackdriver.StackdriverMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to\n * Stackdriver.\n *\n * @author Johannes Graf\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(StackdriverMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"stackdriver\")\n@EnableConfigurationProperties(StackdriverProperties.class)\npublic final class StackdriverMetricsExportAutoConfiguration {\n\n\tprivate final StackdriverProperties properties;\n\n\tStackdriverMetricsExportAutoConfiguration(StackdriverProperties stackdriverProperties) {\n\t\tthis.properties = stackdriverProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStackdriverConfig stackdriverConfig() {\n\t\treturn new StackdriverPropertiesConfigAdapter(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStackdriverMeterRegistry stackdriverMeterRegistry(StackdriverConfig stackdriverConfig, Clock clock) {\n\t\treturn StackdriverMeterRegistry.builder(stackdriverConfig).clock(clock).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/StackdriverProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Stackdriver\n * metrics export.\n *\n * @author Johannes Graf\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.stackdriver.metrics.export\")\npublic class StackdriverProperties extends StepRegistryProperties {\n\n\t/**\n\t * Identifier of the Google Cloud project to monitor.\n\t */\n\tprivate @Nullable String projectId;\n\n\t/**\n\t * Monitored resource type.\n\t */\n\tprivate String resourceType = \"global\";\n\n\t/**\n\t * Monitored resource's labels.\n\t */\n\tprivate @Nullable Map<String, String> resourceLabels;\n\n\t/**\n\t * Whether to use semantically correct metric types. When false, counter metrics are\n\t * published as the GAUGE MetricKind. When true, counter metrics are published as the\n\t * CUMULATIVE MetricKind.\n\t */\n\tprivate boolean useSemanticMetricTypes;\n\n\t/**\n\t * Prefix for metric type. Valid prefixes are described in the Google Cloud\n\t * documentation (https://cloud.google.com/monitoring/custom-metrics#identifier).\n\t */\n\tprivate String metricTypePrefix = \"custom.googleapis.com/\";\n\n\t/**\n\t * Whether it should be attempted to create a metric descriptor before writing a time\n\t * series.\n\t */\n\tprivate boolean autoCreateMetricDescriptors = true;\n\n\tpublic @Nullable String getProjectId() {\n\t\treturn this.projectId;\n\t}\n\n\tpublic void setProjectId(@Nullable String projectId) {\n\t\tthis.projectId = projectId;\n\t}\n\n\tpublic String getResourceType() {\n\t\treturn this.resourceType;\n\t}\n\n\tpublic void setResourceType(String resourceType) {\n\t\tthis.resourceType = resourceType;\n\t}\n\n\tpublic @Nullable Map<String, String> getResourceLabels() {\n\t\treturn this.resourceLabels;\n\t}\n\n\tpublic void setResourceLabels(@Nullable Map<String, String> resourceLabels) {\n\t\tthis.resourceLabels = resourceLabels;\n\t}\n\n\tpublic boolean isUseSemanticMetricTypes() {\n\t\treturn this.useSemanticMetricTypes;\n\t}\n\n\tpublic void setUseSemanticMetricTypes(boolean useSemanticMetricTypes) {\n\t\tthis.useSemanticMetricTypes = useSemanticMetricTypes;\n\t}\n\n\tpublic String getMetricTypePrefix() {\n\t\treturn this.metricTypePrefix;\n\t}\n\n\tpublic void setMetricTypePrefix(String metricTypePrefix) {\n\t\tthis.metricTypePrefix = metricTypePrefix;\n\t}\n\n\tpublic boolean isAutoCreateMetricDescriptors() {\n\t\treturn this.autoCreateMetricDescriptors;\n\t}\n\n\tpublic void setAutoCreateMetricDescriptors(boolean autoCreateMetricDescriptors) {\n\t\tthis.autoCreateMetricDescriptors = autoCreateMetricDescriptors;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/StackdriverPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport java.util.Map;\n\nimport io.micrometer.stackdriver.StackdriverConfig;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link StackdriverProperties} to a {@link StackdriverConfig}.\n *\n * @author Johannes Graf\n * @since 4.0.0\n */\npublic class StackdriverPropertiesConfigAdapter extends StepRegistryPropertiesConfigAdapter<StackdriverProperties>\n\t\timplements StackdriverConfig {\n\n\tpublic StackdriverPropertiesConfigAdapter(StackdriverProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.stackdriver.metrics.export\";\n\t}\n\n\t@Override\n\tpublic String projectId() {\n\t\treturn obtain(StackdriverProperties::getProjectId, StackdriverConfig.super::projectId);\n\t}\n\n\t@Override\n\tpublic String resourceType() {\n\t\treturn obtain(StackdriverProperties::getResourceType, StackdriverConfig.super::resourceType);\n\t}\n\n\t@Override\n\tpublic Map<String, String> resourceLabels() {\n\t\treturn obtain(StackdriverProperties::getResourceLabels, StackdriverConfig.super::resourceLabels);\n\t}\n\n\t@Override\n\tpublic boolean useSemanticMetricTypes() {\n\t\treturn obtain(StackdriverProperties::isUseSemanticMetricTypes, StackdriverConfig.super::useSemanticMetricTypes);\n\t}\n\n\t@Override\n\tpublic String metricTypePrefix() {\n\t\treturn obtain(StackdriverProperties::getMetricTypePrefix, StackdriverConfig.super::metricTypePrefix);\n\t}\n\n\t@Override\n\tpublic boolean autoCreateMetricDescriptors() {\n\t\treturn obtain(StackdriverProperties::isAutoCreateMetricDescriptors,\n\t\t\t\tStackdriverConfig.super::autoCreateMetricDescriptors);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to Stackdriver.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/StatsdMetricsExportAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.statsd.StatsdConfig;\nimport io.micrometer.statsd.StatsdMeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.ConditionalOnEnabledMetricsExport;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting metrics to StatsD.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { CompositeMeterRegistryAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class },\n\t\tafter = MetricsAutoConfiguration.class)\n@ConditionalOnBean(Clock.class)\n@ConditionalOnClass(StatsdMeterRegistry.class)\n@ConditionalOnEnabledMetricsExport(\"statsd\")\n@EnableConfigurationProperties(StatsdProperties.class)\npublic final class StatsdMetricsExportAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStatsdConfig statsdConfig(StatsdProperties statsdProperties) {\n\t\treturn new StatsdPropertiesConfigAdapter(statsdProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStatsdMeterRegistry statsdMeterRegistry(StatsdConfig statsdConfig, Clock clock) {\n\t\treturn new StatsdMeterRegistry(statsdConfig, clock);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/StatsdProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport java.time.Duration;\n\nimport io.micrometer.statsd.StatsdFlavor;\nimport io.micrometer.statsd.StatsdProtocol;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring StatsD metrics\n * export.\n *\n * @author Jon Schneider\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.statsd.metrics.export\")\npublic class StatsdProperties {\n\n\t/**\n\t * Whether exporting of metrics to StatsD is enabled.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * StatsD line protocol to use.\n\t */\n\tprivate StatsdFlavor flavor = StatsdFlavor.DATADOG;\n\n\t/**\n\t * Host of the StatsD server to receive exported metrics.\n\t */\n\tprivate String host = \"localhost\";\n\n\t/**\n\t * Port of the StatsD server to receive exported metrics.\n\t */\n\tprivate Integer port = 8125;\n\n\t/**\n\t * Protocol of the StatsD server to receive exported metrics.\n\t */\n\tprivate StatsdProtocol protocol = StatsdProtocol.UDP;\n\n\t/**\n\t * Total length of a single payload should be kept within your network's MTU.\n\t */\n\tprivate Integer maxPacketLength = 1400;\n\n\t/**\n\t * How often gauges will be polled. When a gauge is polled, its value is recalculated\n\t * and if the value has changed (or publishUnchangedMeters is true), it is sent to the\n\t * StatsD server.\n\t */\n\tprivate Duration pollingFrequency = Duration.ofSeconds(10);\n\n\t/**\n\t * Step size to use in computing windowed statistics like max. To get the most out of\n\t * these statistics, align the step interval to be close to your scrape interval.\n\t */\n\tprivate Duration step = Duration.ofMinutes(1);\n\n\t/**\n\t * Whether to send unchanged meters to the StatsD server.\n\t */\n\tprivate boolean publishUnchangedMeters = true;\n\n\t/**\n\t * Whether measurements should be buffered before sending to the StatsD server.\n\t */\n\tprivate boolean buffered = true;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic StatsdFlavor getFlavor() {\n\t\treturn this.flavor;\n\t}\n\n\tpublic void setFlavor(StatsdFlavor flavor) {\n\t\tthis.flavor = flavor;\n\t}\n\n\tpublic String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic StatsdProtocol getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\tpublic void setProtocol(StatsdProtocol protocol) {\n\t\tthis.protocol = protocol;\n\t}\n\n\tpublic Integer getMaxPacketLength() {\n\t\treturn this.maxPacketLength;\n\t}\n\n\tpublic void setMaxPacketLength(Integer maxPacketLength) {\n\t\tthis.maxPacketLength = maxPacketLength;\n\t}\n\n\tpublic Duration getPollingFrequency() {\n\t\treturn this.pollingFrequency;\n\t}\n\n\tpublic void setPollingFrequency(Duration pollingFrequency) {\n\t\tthis.pollingFrequency = pollingFrequency;\n\t}\n\n\tpublic Duration getStep() {\n\t\treturn this.step;\n\t}\n\n\tpublic void setStep(Duration step) {\n\t\tthis.step = step;\n\t}\n\n\tpublic boolean isPublishUnchangedMeters() {\n\t\treturn this.publishUnchangedMeters;\n\t}\n\n\tpublic void setPublishUnchangedMeters(boolean publishUnchangedMeters) {\n\t\tthis.publishUnchangedMeters = publishUnchangedMeters;\n\t}\n\n\tpublic boolean isBuffered() {\n\t\treturn this.buffered;\n\t}\n\n\tpublic void setBuffered(boolean buffered) {\n\t\tthis.buffered = buffered;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/StatsdPropertiesConfigAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport java.time.Duration;\n\nimport io.micrometer.statsd.StatsdConfig;\nimport io.micrometer.statsd.StatsdFlavor;\nimport io.micrometer.statsd.StatsdProtocol;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\n\n/**\n * Adapter to convert {@link StatsdProperties} to a {@link StatsdConfig}.\n *\n * @author Jon Schneider\n * @since 4.0.0\n */\npublic class StatsdPropertiesConfigAdapter extends PropertiesConfigAdapter<StatsdProperties> implements StatsdConfig {\n\n\tpublic StatsdPropertiesConfigAdapter(StatsdProperties properties) {\n\t\tsuper(properties);\n\t}\n\n\t@Override\n\tpublic @Nullable String get(String s) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic String prefix() {\n\t\treturn \"management.statsd.metrics.export\";\n\t}\n\n\t@Override\n\tpublic StatsdFlavor flavor() {\n\t\treturn obtain(StatsdProperties::getFlavor, StatsdConfig.super::flavor);\n\t}\n\n\t@Override\n\tpublic boolean enabled() {\n\t\treturn obtain(StatsdProperties::isEnabled, StatsdConfig.super::enabled);\n\t}\n\n\t@Override\n\tpublic String host() {\n\t\treturn obtain(StatsdProperties::getHost, StatsdConfig.super::host);\n\t}\n\n\t@Override\n\tpublic int port() {\n\t\treturn obtain(StatsdProperties::getPort, StatsdConfig.super::port);\n\t}\n\n\t@Override\n\tpublic StatsdProtocol protocol() {\n\t\treturn obtain(StatsdProperties::getProtocol, StatsdConfig.super::protocol);\n\t}\n\n\t@Override\n\tpublic int maxPacketLength() {\n\t\treturn obtain(StatsdProperties::getMaxPacketLength, StatsdConfig.super::maxPacketLength);\n\t}\n\n\t@Override\n\tpublic Duration pollingFrequency() {\n\t\treturn obtain(StatsdProperties::getPollingFrequency, StatsdConfig.super::pollingFrequency);\n\t}\n\n\t@Override\n\tpublic Duration step() {\n\t\treturn obtain(StatsdProperties::getStep, StatsdConfig.super::step);\n\t}\n\n\t@Override\n\tpublic boolean publishUnchangedMeters() {\n\t\treturn obtain(StatsdProperties::isPublishUnchangedMeters, StatsdConfig.super::publishUnchangedMeters);\n\t}\n\n\t@Override\n\tpublic boolean buffered() {\n\t\treturn obtain(StatsdProperties::isBuffered, StatsdConfig.super::buffered);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting actuator metrics to StatsD.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.jvm;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmInfoMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmClassLoadingMeterConventions;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmThreadMeterConventions;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for JVM metrics.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })\n@ConditionalOnClass(MeterRegistry.class)\n@ConditionalOnBean(MeterRegistry.class)\npublic final class JvmMetricsAutoConfiguration {\n\n\tprivate static final String VIRTUAL_THREAD_METRICS_CLASS = \"io.micrometer.java21.instrument.binder.jdk.VirtualThreadMetrics\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJvmGcMetrics jvmGcMetrics() {\n\t\treturn new JvmGcMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJvmHeapPressureMetrics jvmHeapPressureMetrics() {\n\t\treturn new JvmHeapPressureMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJvmMemoryMetrics jvmMemoryMetrics(ObjectProvider<JvmMemoryMeterConventions> jvmMemoryMeterConventions) {\n\t\tJvmMemoryMeterConventions conventions = jvmMemoryMeterConventions.getIfAvailable();\n\t\treturn (conventions != null) ? new JvmMemoryMetrics(Collections.emptyList(), conventions)\n\t\t\t\t: new JvmMemoryMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJvmThreadMetrics jvmThreadMetrics(ObjectProvider<JvmThreadMeterConventions> jvmThreadMeterConventions) {\n\t\tJvmThreadMeterConventions conventions = jvmThreadMeterConventions.getIfAvailable();\n\t\treturn (conventions != null) ? new JvmThreadMetrics(Collections.emptyList(), conventions)\n\t\t\t\t: new JvmThreadMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tClassLoaderMetrics classLoaderMetrics(\n\t\t\tObjectProvider<JvmClassLoadingMeterConventions> jvmClassLoadingMeterConventions) {\n\t\tJvmClassLoadingMeterConventions conventions = jvmClassLoadingMeterConventions.getIfAvailable();\n\t\treturn (conventions != null) ? new ClassLoaderMetrics(conventions) : new ClassLoaderMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJvmInfoMetrics jvmInfoMetrics() {\n\t\treturn new JvmInfoMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tJvmCompilationMetrics jvmCompilationMetrics() {\n\t\treturn new JvmCompilationMetrics();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(name = VIRTUAL_THREAD_METRICS_CLASS)\n\tstatic class VirtualThreadMetricsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(type = VIRTUAL_THREAD_METRICS_CLASS)\n\t\t@ImportRuntimeHints(VirtualThreadMetricsRuntimeHintsRegistrar.class)\n\t\tMeterBinder virtualThreadMetrics() throws ClassNotFoundException {\n\t\t\tClass<?> virtualThreadMetricsClass = ClassUtils.forName(VIRTUAL_THREAD_METRICS_CLASS,\n\t\t\t\t\tgetClass().getClassLoader());\n\t\t\treturn (MeterBinder) BeanUtils.instantiateClass(virtualThreadMetricsClass);\n\t\t}\n\n\t}\n\n\tstatic final class VirtualThreadMetricsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerTypeIfPresent(classLoader, VIRTUAL_THREAD_METRICS_CLASS,\n\t\t\t\t\t\tMemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JVM metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.jvm;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/log4j2/Log4J2MetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.log4j2;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.logging.Log4j2Metrics;\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.spi.LoggerContext;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.logging.log4j2.Log4J2MetricsAutoConfiguration.Log4JCoreLoggerContextCondition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * Auto-configuration for Log4J2 metrics.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })\n@ConditionalOnClass(value = { Log4j2Metrics.class, LogManager.class },\n\t\tname = \"org.apache.logging.log4j.core.LoggerContext\")\n@ConditionalOnBean(MeterRegistry.class)\n@Conditional(Log4JCoreLoggerContextCondition.class)\npublic final class Log4J2MetricsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tLog4j2Metrics log4j2Metrics() {\n\t\treturn new Log4j2Metrics();\n\t}\n\n\tstatic class Log4JCoreLoggerContextCondition extends SpringBootCondition {\n\n\t\tprivate static final String LOGGER_CONTEXT_CLASS_NAME = \"org.apache.logging.log4j.core.LoggerContext\";\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tLoggerContext loggerContext = LogManager.getContext(false);\n\t\t\ttry {\n\t\t\t\tif (Class.forName(LOGGER_CONTEXT_CLASS_NAME).isInstance(loggerContext)) {\n\t\t\t\t\treturn ConditionOutcome.match(\"LoggerContext was an instance of \" + LOGGER_CONTEXT_CLASS_NAME);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\t// Continue with no match\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(\"LoggerContext was not an instance of \" + LOGGER_CONTEXT_CLASS_NAME);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/log4j2/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Log4J2 metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.log4j2;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/logback/LogbackMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.logback;\n\nimport ch.qos.logback.classic.LoggerContext;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.logging.LogbackMetrics;\nimport org.slf4j.ILoggerFactory;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.logging.logback.LogbackMetricsAutoConfiguration.LogbackLoggingCondition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Logback metrics.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })\n@ConditionalOnClass({ MeterRegistry.class, LoggerContext.class, LoggerFactory.class })\n@ConditionalOnBean(MeterRegistry.class)\n@Conditional(LogbackLoggingCondition.class)\npublic final class LogbackMetricsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tLogbackMetrics logbackMetrics() {\n\t\treturn new LogbackMetrics();\n\t}\n\n\tstatic class LogbackLoggingCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"LogbackLoggingCondition\");\n\t\t\tif (loggerFactory instanceof LoggerContext) {\n\t\t\t\treturn ConditionOutcome.match(message.because(\"ILoggerFactory is a Logback LoggerContext\"));\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(\n\t\t\t\t\tmessage.because(\"ILoggerFactory is an instance of \" + loggerFactory.getClass().getCanonicalName()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/logback/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Logback metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.logback;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for metrics with Micrometer.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/ssl/SslMeterBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.ssl;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.MultiGauge;\nimport io.micrometer.core.instrument.MultiGauge.Row;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.TimeGauge;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.info.SslInfo.BundleInfo;\nimport org.springframework.boot.info.SslInfo.CertificateChainInfo;\nimport org.springframework.boot.info.SslInfo.CertificateInfo;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\n\n/**\n * {@link MeterBinder} which registers the SSL chain expiry (soonest to expire certificate\n * in the chain) as a {@link TimeGauge}.\n *\n * @author Moritz Halbritter\n */\nclass SslMeterBinder implements MeterBinder {\n\n\tprivate static final String CHAIN_EXPIRY_METRIC_NAME = \"ssl.chain.expiry\";\n\n\tprivate final Clock clock;\n\n\tprivate final SslInfo sslInfo;\n\n\tprivate final BundleMetrics bundleMetrics = new BundleMetrics();\n\n\tprivate final Set<MeterRegistry> boundMeterRegistries = ConcurrentHashMap.newKeySet();\n\n\tSslMeterBinder(SslInfo sslInfo, SslBundles sslBundles) {\n\t\tthis(sslInfo, sslBundles, Clock.systemDefaultZone());\n\t}\n\n\tSslMeterBinder(SslInfo sslInfo, SslBundles sslBundles, Clock clock) {\n\t\tthis.clock = clock;\n\t\tthis.sslInfo = sslInfo;\n\t\tsslBundles.addBundleRegisterHandler((bundleName, ignored) -> {\n\t\t\tonBundleChange(bundleName);\n\t\t\tsslBundles.addBundleUpdateHandler(bundleName, (ignoredBundle) -> onBundleChange(bundleName));\n\t\t});\n\t\tfor (String bundleName : sslBundles.getBundleNames()) {\n\t\t\tsslBundles.addBundleUpdateHandler(bundleName, (ignored) -> onBundleChange(bundleName));\n\t\t}\n\t}\n\n\tprivate void onBundleChange(String bundleName) {\n\t\tBundleInfo bundle = this.sslInfo.getBundle(bundleName);\n\t\tthis.bundleMetrics.updateBundle(bundle);\n\t\tfor (MeterRegistry meterRegistry : this.boundMeterRegistries) {\n\t\t\tcreateOrUpdateBundleMetrics(meterRegistry, bundle);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void bindTo(MeterRegistry meterRegistry) {\n\t\tthis.boundMeterRegistries.add(meterRegistry);\n\t\tfor (BundleInfo bundle : this.sslInfo.getBundles()) {\n\t\t\tcreateOrUpdateBundleMetrics(meterRegistry, bundle);\n\t\t}\n\t}\n\n\tprivate void createOrUpdateBundleMetrics(MeterRegistry meterRegistry, BundleInfo bundle) {\n\t\tMultiGauge multiGauge = this.bundleMetrics.getGauge(bundle, meterRegistry);\n\t\tList<Row<CertificateInfo>> rows = new ArrayList<>();\n\t\tfor (CertificateChainInfo chain : bundle.getCertificateChains()) {\n\t\t\tRow<CertificateInfo> row = createRowForChain(bundle, chain);\n\t\t\tif (row != null) {\n\t\t\t\trows.add(row);\n\t\t\t}\n\t\t}\n\t\tmultiGauge.register(rows, true);\n\t}\n\n\tprivate @Nullable Row<CertificateInfo> createRowForChain(BundleInfo bundle, CertificateChainInfo chain) {\n\t\tCertificateInfo leastValidCertificate = chain.getCertificates()\n\t\t\t.stream()\n\t\t\t.filter((c) -> c.getValidityEnds() != null)\n\t\t\t.min(Comparator.comparing(this::getValidityEnds))\n\t\t\t.orElse(null);\n\t\tif (leastValidCertificate == null) {\n\t\t\treturn null;\n\t\t}\n\t\tString serialNumber = leastValidCertificate.getSerialNumber();\n\t\tTags tags = Tags.of(\"chain\", chain.getAlias(), \"bundle\", bundle.getName(), \"certificate\",\n\t\t\t\t(serialNumber != null) ? serialNumber : \"\");\n\t\treturn Row.of(tags, leastValidCertificate, this::getChainExpiry);\n\t}\n\n\tprivate long getChainExpiry(CertificateInfo certificate) {\n\t\tDuration valid = Duration.between(Instant.now(this.clock), getValidityEnds(certificate));\n\t\treturn valid.get(ChronoUnit.SECONDS);\n\t}\n\n\tprivate Instant getValidityEnds(CertificateInfo certificate) {\n\t\tInstant validityEnds = certificate.getValidityEnds();\n\t\tAssert.state(validityEnds != null, \"'validityEnds' must not be null\");\n\t\treturn validityEnds;\n\t}\n\n\t/**\n\t * Manages bundles and their metrics.\n\t */\n\tprivate static final class BundleMetrics {\n\n\t\tprivate final Map<String, Gauges> gauges = new ConcurrentHashMap<>();\n\n\t\t/**\n\t\t * Gets (or creates) a {@link MultiGauge} for the given bundle and meter registry.\n\t\t * @param bundleInfo the bundle\n\t\t * @param meterRegistry the meter registry\n\t\t * @return the {@link MultiGauge}\n\t\t */\n\t\tMultiGauge getGauge(BundleInfo bundleInfo, MeterRegistry meterRegistry) {\n\t\t\tGauges gauges = this.gauges.computeIfAbsent(bundleInfo.getName(),\n\t\t\t\t\t(ignored) -> Gauges.emptyGauges(bundleInfo));\n\t\t\treturn gauges.getGauge(meterRegistry);\n\t\t}\n\n\t\t/**\n\t\t * Updates the given bundle.\n\t\t * @param bundle the updated bundle\n\t\t */\n\t\tvoid updateBundle(BundleInfo bundle) {\n\t\t\tthis.gauges.computeIfPresent(bundle.getName(), (key, oldValue) -> oldValue.withBundle(bundle));\n\t\t}\n\n\t\t/**\n\t\t * Manages the {@link MultiGauge MultiGauges} associated to a bundle.\n\t\t *\n\t\t * @param bundle the bundle\n\t\t * @param multiGauges mapping from meter registry to {@link MultiGauge}\n\t\t */\n\t\tprivate record Gauges(BundleInfo bundle, Map<MeterRegistry, MultiGauge> multiGauges) {\n\n\t\t\t/**\n\t\t\t * Gets (or creates) the {@link MultiGauge} for the given meter registry.\n\t\t\t * @param meterRegistry the meter registry\n\t\t\t * @return the {@link MultiGauge}\n\t\t\t */\n\t\t\tMultiGauge getGauge(MeterRegistry meterRegistry) {\n\t\t\t\treturn this.multiGauges.computeIfAbsent(meterRegistry, (ignored) -> createGauge(meterRegistry));\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Returns a copy of this bundle with an updated {@link BundleInfo}.\n\t\t\t * @param bundle the updated {@link BundleInfo}\n\t\t\t * @return the copy of this bundle with an updated {@link BundleInfo}\n\t\t\t */\n\t\t\tGauges withBundle(BundleInfo bundle) {\n\t\t\t\treturn new Gauges(bundle, this.multiGauges);\n\t\t\t}\n\n\t\t\tprivate MultiGauge createGauge(MeterRegistry meterRegistry) {\n\t\t\t\treturn MultiGauge.builder(CHAIN_EXPIRY_METRIC_NAME)\n\t\t\t\t\t.baseUnit(\"seconds\")\n\t\t\t\t\t.description(\"SSL chain expiry\")\n\t\t\t\t\t.register(meterRegistry);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Creates an instance with an empty gauge mapping.\n\t\t\t * @param bundle the {@link BundleInfo} associated with the new instance\n\t\t\t * @return the new instance\n\t\t\t */\n\t\t\tstatic Gauges emptyGauges(BundleInfo bundle) {\n\t\t\t\treturn new Gauges(bundle, new ConcurrentHashMap<>());\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/ssl/SslMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.ssl;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for SSL metrics.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(after = { CompositeMeterRegistryAutoConfiguration.class, MetricsAutoConfiguration.class,\n\t\tSslAutoConfiguration.class })\n@ConditionalOnClass(MeterRegistry.class)\n@ConditionalOnBean({ MeterRegistry.class, SslBundles.class })\npublic final class SslMetricsAutoConfiguration {\n\n\t@Bean\n\tSslMeterBinder sslMeterBinder(SslBundles sslBundles, ObjectProvider<SslInfo> sslInfo) {\n\t\treturn new SslMeterBinder(sslInfo.getIfAvailable(() -> new SslInfo(sslBundles)), sslBundles);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for SSL metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/startup/StartupTimeMetricsListenerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.startup;\n\nimport io.micrometer.core.instrument.MeterRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.startup.StartupTimeMetricsListener;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for startup time metrics.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })\n@ConditionalOnClass(MeterRegistry.class)\n@ConditionalOnBean(MeterRegistry.class)\npublic final class StartupTimeMetricsListenerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tStartupTimeMetricsListener startupTimeMetrics(MeterRegistry meterRegistry) {\n\t\treturn new StartupTimeMetricsListener(meterRegistry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/startup/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator startup time metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.startup;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.system;\n\nimport java.io.File;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmCpuMeterConventions;\nimport io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;\nimport io.micrometer.core.instrument.binder.system.ProcessorMetrics;\nimport io.micrometer.core.instrument.binder.system.UptimeMetrics;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;\nimport org.springframework.boot.micrometer.metrics.system.DiskSpaceMetricsBinder;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for system metrics.\n *\n * @author Stephane Nicoll\n * @author Chris Bono\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })\n@ConditionalOnClass(MeterRegistry.class)\n@ConditionalOnBean(MeterRegistry.class)\n@EnableConfigurationProperties(MetricsProperties.class)\npublic final class SystemMetricsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tUptimeMetrics uptimeMetrics() {\n\t\treturn new UptimeMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tProcessorMetrics processorMetrics(ObjectProvider<JvmCpuMeterConventions> jvmCpuMeterConventions) {\n\t\tJvmCpuMeterConventions conventions = jvmCpuMeterConventions.getIfAvailable();\n\t\treturn (conventions != null) ? new ProcessorMetrics(Collections.emptyList(), conventions)\n\t\t\t\t: new ProcessorMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tFileDescriptorMetrics fileDescriptorMetrics() {\n\t\treturn new FileDescriptorMetrics();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDiskSpaceMetricsBinder diskSpaceMetrics(MetricsProperties properties) {\n\t\tList<File> paths = properties.getSystem().getDiskspace().getPaths();\n\t\treturn new DiskSpaceMetricsBinder(paths, Tags.empty());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for system metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.system;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/task/TaskExecutorMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.task;\n\nimport java.util.Collections;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ThreadPoolExecutor;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.jvm.ExecutorServiceMetrics;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available\n * {@link ThreadPoolTaskExecutor task executors} and {@link ThreadPoolTaskScheduler task\n * schedulers}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class,\n\t\tTaskExecutionAutoConfiguration.class, TaskSchedulingAutoConfiguration.class })\n@ConditionalOnClass(ExecutorServiceMetrics.class)\n@ConditionalOnBean({ Executor.class, MeterRegistry.class })\npublic final class TaskExecutorMetricsAutoConfiguration {\n\n\t@Autowired\n\tvoid bindTaskExecutorsToRegistry(ConfigurableListableBeanFactory beanFactory, MeterRegistry registry) {\n\t\tSimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, TaskExecutor.class)\n\t\t\t.forEach((beanName, executor) -> {\n\t\t\t\tif (executor instanceof ThreadPoolTaskExecutor threadPoolTaskExecutor) {\n\t\t\t\t\tmonitor(registry, safeGetThreadPoolExecutor(threadPoolTaskExecutor), beanName);\n\t\t\t\t}\n\t\t\t\telse if (executor instanceof ThreadPoolTaskScheduler threadPoolTaskScheduler) {\n\t\t\t\t\tmonitor(registry, safeGetThreadPoolExecutor(threadPoolTaskScheduler), beanName);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Bean\n\tstatic LazyInitializationExcludeFilter eagerTaskExecutorMetrics() {\n\t\treturn LazyInitializationExcludeFilter.forBeanTypes(TaskExecutorMetricsAutoConfiguration.class);\n\t}\n\n\tprivate void monitor(MeterRegistry registry, @Nullable ThreadPoolExecutor threadPoolExecutor, String name) {\n\t\tif (threadPoolExecutor != null) {\n\t\t\tnew ExecutorServiceMetrics(threadPoolExecutor, name, Collections.emptyList()).bindTo(registry);\n\t\t}\n\t}\n\n\tprivate @Nullable ThreadPoolExecutor safeGetThreadPoolExecutor(ThreadPoolTaskExecutor taskExecutor) {\n\t\ttry {\n\t\t\treturn taskExecutor.getThreadPoolExecutor();\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable ThreadPoolExecutor safeGetThreadPoolExecutor(ThreadPoolTaskScheduler taskScheduler) {\n\t\ttry {\n\t\t\treturn taskScheduler.getScheduledThreadPoolExecutor();\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/autoconfigure/task/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for task execution and scheduling metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.autoconfigure.task;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/docker/compose/otlp/OpenTelemetryMetricsDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.docker.compose.otlp;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link OtlpMetricsConnectionDetails} for an OTLP service.\n *\n * @author Eddú Meléndez\n */\nclass OpenTelemetryMetricsDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<OtlpMetricsConnectionDetails> {\n\n\tprivate static final String[] OPENTELEMETRY_IMAGE_NAMES = { \"otel/opentelemetry-collector-contrib\",\n\t\t\t\"grafana/otel-lgtm\" };\n\n\tprivate static final int OTLP_PORT = 4318;\n\n\tOpenTelemetryMetricsDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OPENTELEMETRY_IMAGE_NAMES,\n\t\t\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpMetricsConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new OpenTelemetryMetricsDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\tprivate static final class OpenTelemetryMetricsDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements OtlpMetricsConnectionDetails {\n\n\t\tprivate final String host;\n\n\t\tprivate final int port;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tprivate OpenTelemetryMetricsDockerComposeConnectionDetails(RunningService source) {\n\t\t\tsuper(source);\n\t\t\tthis.host = source.host();\n\t\t\tthis.port = source.ports().get(OTLP_PORT);\n\t\t\tthis.sslBundle = getSslBundle(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl() {\n\t\t\tString scheme = (this.sslBundle != null) ? \"https\" : \"http\";\n\t\t\treturn \"%s://%s:%d/v1/metrics\".formatted(scheme, this.host, this.port);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/docker/compose/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose OpenTelemetry metrics service connections.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.docker.compose.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/export/prometheus/PrometheusPushGatewayManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.export.prometheus;\n\nimport java.time.Duration;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\n\nimport io.prometheus.metrics.exporter.pushgateway.PushGateway;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\nimport org.springframework.util.Assert;\n\n/**\n * Class that can be used to manage the pushing of metrics to a {@link PushGateway\n * Prometheus PushGateway}. Handles the scheduling of push operations, error handling and\n * shutdown operations.\n *\n * @author David J. M. Karlsen\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class PrometheusPushGatewayManager {\n\n\tprivate static final Log logger = LogFactory.getLog(PrometheusPushGatewayManager.class);\n\n\tprivate final PushGateway pushGateway;\n\n\tprivate final ShutdownOperation shutdownOperation;\n\n\tprivate final TaskScheduler scheduler;\n\n\tprivate final ScheduledFuture<?> scheduled;\n\n\t/**\n\t * Create a new {@link PrometheusPushGatewayManager} instance.\n\t * @param pushGateway the source push gateway\n\t * @param pushRate the rate at which push operations occur\n\t * @param shutdownOperation the shutdown operation that should be performed when\n\t * context is closed\n\t */\n\tpublic PrometheusPushGatewayManager(PushGateway pushGateway, Duration pushRate,\n\t\t\tShutdownOperation shutdownOperation) {\n\t\tthis(pushGateway, new PushGatewayTaskScheduler(), pushRate, shutdownOperation);\n\t}\n\n\tPrometheusPushGatewayManager(PushGateway pushGateway, TaskScheduler scheduler, Duration pushRate,\n\t\t\t@Nullable ShutdownOperation shutdownOperation) {\n\t\tAssert.notNull(pushGateway, \"'pushGateway' must not be null\");\n\t\tAssert.notNull(scheduler, \"'scheduler' must not be null\");\n\t\tAssert.notNull(pushRate, \"'pushRate' must not be null\");\n\t\tthis.pushGateway = pushGateway;\n\t\tthis.shutdownOperation = (shutdownOperation != null) ? shutdownOperation : ShutdownOperation.NONE;\n\t\tthis.scheduler = scheduler;\n\t\tthis.scheduled = this.scheduler.scheduleAtFixedRate(this::post, pushRate);\n\t}\n\n\tprivate void post() {\n\t\ttry {\n\t\t\tthis.pushGateway.pushAdd();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tlogger.warn(\"Unexpected exception thrown by POST of metrics to Prometheus Pushgateway\", ex);\n\t\t}\n\t}\n\n\tprivate void put() {\n\t\ttry {\n\t\t\tthis.pushGateway.push();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tlogger.warn(\"Unexpected exception thrown by PUT of metrics to Prometheus Pushgateway\", ex);\n\t\t}\n\t}\n\n\tprivate void delete() {\n\t\ttry {\n\t\t\tthis.pushGateway.delete();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tlogger.warn(\"Unexpected exception thrown by DELETE of metrics from Prometheus Pushgateway\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Shutdown the manager, running any {@link ShutdownOperation}.\n\t */\n\tpublic void shutdown() {\n\t\tshutdown(this.shutdownOperation);\n\t}\n\n\tprivate void shutdown(ShutdownOperation shutdownOperation) {\n\t\tif (this.scheduler instanceof PushGatewayTaskScheduler pushGatewayTaskScheduler) {\n\t\t\tpushGatewayTaskScheduler.shutdown();\n\t\t}\n\t\tthis.scheduled.cancel(false);\n\t\tswitch (shutdownOperation) {\n\t\t\tcase POST -> post();\n\t\t\tcase PUT -> put();\n\t\t\tcase DELETE -> delete();\n\t\t}\n\t}\n\n\t/**\n\t * The operation that should be performed on shutdown.\n\t */\n\tpublic enum ShutdownOperation {\n\n\t\t/**\n\t\t * Don't perform any shutdown operation.\n\t\t */\n\t\tNONE,\n\n\t\t/**\n\t\t * Perform a POST before shutdown.\n\t\t */\n\t\tPOST,\n\n\t\t/**\n\t\t * Perform a PUT before shutdown.\n\t\t */\n\t\tPUT,\n\n\t\t/**\n\t\t * Perform a DELETE before shutdown.\n\t\t */\n\t\tDELETE\n\n\t}\n\n\t/**\n\t * {@link TaskScheduler} used when the user doesn't specify one.\n\t */\n\tstatic class PushGatewayTaskScheduler extends ThreadPoolTaskScheduler {\n\n\t\tPushGatewayTaskScheduler() {\n\t\t\tsetPoolSize(1);\n\t\t\tsetDaemon(true);\n\t\t\tsetThreadGroupName(\"prometheus-push-gateway\");\n\t\t}\n\n\t\t@Override\n\t\tpublic ScheduledExecutorService getScheduledExecutor() throws IllegalStateException {\n\t\t\treturn Executors.newSingleThreadScheduledExecutor(this);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/export/prometheus/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting metrics to Prometheus through a scrape endpoint.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.export.prometheus.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/export/prometheus/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for exporting metrics to Prometheus through a pushgateway.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.export.prometheus;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General metrics-related classes.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/startup/StartupTimeMetricsListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.startup;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.TimeGauge;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.event.SmartApplicationListener;\n\n/**\n * Binds application startup metrics in response to {@link ApplicationStartedEvent} and\n * {@link ApplicationReadyEvent}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class StartupTimeMetricsListener implements SmartApplicationListener {\n\n\t/**\n\t * The default name to use for the application started time metric.\n\t */\n\tpublic static final String APPLICATION_STARTED_TIME_METRIC_NAME = \"application.started.time\";\n\n\t/**\n\t * The default name to use for the application ready time metric.\n\t */\n\tpublic static final String APPLICATION_READY_TIME_METRIC_NAME = \"application.ready.time\";\n\n\tprivate final MeterRegistry meterRegistry;\n\n\tprivate final String startedTimeMetricName;\n\n\tprivate final String readyTimeMetricName;\n\n\tprivate final Tags tags;\n\n\t/**\n\t * Create a new instance using default metric names.\n\t * @param meterRegistry the registry to use\n\t * @see #APPLICATION_STARTED_TIME_METRIC_NAME\n\t * @see #APPLICATION_READY_TIME_METRIC_NAME\n\t */\n\tpublic StartupTimeMetricsListener(MeterRegistry meterRegistry) {\n\t\tthis(meterRegistry, APPLICATION_STARTED_TIME_METRIC_NAME, APPLICATION_READY_TIME_METRIC_NAME,\n\t\t\t\tCollections.emptyList());\n\t}\n\n\t/**\n\t * Create a new instance using the specified options.\n\t * @param meterRegistry the registry to use\n\t * @param startedTimeMetricName the name to use for the application started time\n\t * metric\n\t * @param readyTimeMetricName the name to use for the application ready time metric\n\t * @param tags the tags to associate to application startup metrics\n\t */\n\tpublic StartupTimeMetricsListener(MeterRegistry meterRegistry, String startedTimeMetricName,\n\t\t\tString readyTimeMetricName, Iterable<Tag> tags) {\n\t\tthis.meterRegistry = meterRegistry;\n\t\tthis.startedTimeMetricName = startedTimeMetricName;\n\t\tthis.readyTimeMetricName = readyTimeMetricName;\n\t\tthis.tags = Tags.of(tags);\n\t}\n\n\t@Override\n\tpublic boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {\n\t\treturn ApplicationStartedEvent.class.isAssignableFrom(eventType)\n\t\t\t\t|| ApplicationReadyEvent.class.isAssignableFrom(eventType);\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\tif (event instanceof ApplicationStartedEvent startedEvent) {\n\t\t\tonApplicationStarted(startedEvent);\n\t\t}\n\t\tif (event instanceof ApplicationReadyEvent readyEvent) {\n\t\t\tonApplicationReady(readyEvent);\n\t\t}\n\t}\n\n\tprivate void onApplicationStarted(ApplicationStartedEvent event) {\n\t\tregisterGauge(this.startedTimeMetricName, \"Time taken to start the application\", event.getTimeTaken(),\n\t\t\t\tevent.getSpringApplication());\n\t}\n\n\tprivate void onApplicationReady(ApplicationReadyEvent event) {\n\t\tregisterGauge(this.readyTimeMetricName, \"Time taken for the application to be ready to service requests\",\n\t\t\t\tevent.getTimeTaken(), event.getSpringApplication());\n\t}\n\n\tprivate void registerGauge(String name, String description, @Nullable Duration timeTaken,\n\t\t\tSpringApplication springApplication) {\n\t\tif (timeTaken != null) {\n\t\t\tIterable<Tag> tags = createTagsFrom(springApplication);\n\t\t\tTimeGauge.builder(name, timeTaken::toMillis, TimeUnit.MILLISECONDS)\n\t\t\t\t.tags(tags)\n\t\t\t\t.description(description)\n\t\t\t\t.register(this.meterRegistry);\n\t\t}\n\t}\n\n\tprivate Iterable<Tag> createTagsFrom(SpringApplication springApplication) {\n\t\tClass<?> mainClass = springApplication.getMainApplicationClass();\n\t\treturn (mainClass != null) ? this.tags.and(\"main.application.class\", mainClass.getName()) : this.tags;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/startup/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for startup metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.startup;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/system/DiskSpaceMetricsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.system;\n\nimport java.io.File;\nimport java.util.List;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.system.DiskSpaceMetrics;\n\nimport org.springframework.util.Assert;\n\n/**\n * A {@link MeterBinder} that binds one or more {@link DiskSpaceMetrics}.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\npublic class DiskSpaceMetricsBinder implements MeterBinder {\n\n\tprivate final List<File> paths;\n\n\tprivate final Iterable<Tag> tags;\n\n\tpublic DiskSpaceMetricsBinder(List<File> paths, Iterable<Tag> tags) {\n\t\tAssert.notEmpty(paths, \"'paths' must not be empty\");\n\t\tthis.paths = paths;\n\t\tthis.tags = tags;\n\t}\n\n\t@Override\n\tpublic void bindTo(MeterRegistry registry) {\n\t\tthis.paths.forEach((path) -> new DiskSpaceMetrics(path, this.tags).bindTo(registry));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * System metrics.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.system;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/testcontainers/otlp/GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.testcontainers.otlp;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.grafana.LgtmStackContainer;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link OtlpMetricsConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using\n * the {@code \"grafana/otel-lgtm\"} image.\n *\n * @author Eddú Meléndez\n */\nclass GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<LgtmStackContainer, OtlpMetricsConnectionDetails> {\n\n\tGrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME,\n\t\t\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpMetricsConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<LgtmStackContainer> source) {\n\t\treturn new OpenTelemetryMetricsContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OpenTelemetryMetricsContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<LgtmStackContainer> implements OtlpMetricsConnectionDetails {\n\n\t\tprivate OpenTelemetryMetricsContainerConnectionDetails(ContainerConnectionSource<LgtmStackContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl() {\n\t\t\tString url = getContainer().getOtlpHttpUrl();\n\t\t\tif (getSslBundle() != null) {\n\t\t\t\turl = url.replaceFirst(\"^http://\", \"https://\");\n\t\t\t}\n\t\t\treturn \"%s/v1/metrics\".formatted(url);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/testcontainers/otlp/OpenTelemetryMetricsContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.testcontainers.otlp;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link OtlpMetricsConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using\n * the {@code \"otel/opentelemetry-collector-contrib\"} image.\n *\n * @author Eddú Meléndez\n */\nclass OpenTelemetryMetricsContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, OtlpMetricsConnectionDetails> {\n\n\tOpenTelemetryMetricsContainerConnectionDetailsFactory() {\n\t\tsuper(\"otel/opentelemetry-collector-contrib\",\n\t\t\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpMetricsConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<Container<?>> source) {\n\t\treturn new OpenTelemetryMetricsContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OpenTelemetryMetricsContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<Container<?>> implements OtlpMetricsConnectionDetails {\n\n\t\tprivate OpenTelemetryMetricsContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl() {\n\t\t\tString scheme = (getSslBundle() != null) ? \"https\" : \"http\";\n\t\t\treturn \"%s://%s:%d/v1/metrics\".formatted(scheme, getContainer().getHost(),\n\t\t\t\t\tgetContainer().getMappedPort(4318));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/java/org/springframework/boot/micrometer/metrics/testcontainers/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Testcontainers OpenTelemetry metrics service connections.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.testcontainers.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.defaults.metrics.export.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable default metrics exporters.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.metrics.binders.files.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable files metrics.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Instead, filter 'process.files' metrics.\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.binders.jvm.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JVM metrics.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Instead, disable JvmMetricsAutoConfiguration or filter 'jvm' metrics.\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.binders.logback.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Logback metrics.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Instead, disable LogbackMetricsAutoConfiguration or filter 'logback' metrics.\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.binders.processor.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable processor metrics.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Instead, filter 'system.cpu' and 'process.cpu' metrics.\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.binders.uptime.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable uptime metrics.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Instead, filter 'process.uptime' and 'process.start.time' metrics.\",\n        \"since\": \"2.1.0\"\n      }\n    },\n        {\n      \"name\": \"management.metrics.export.appoptics.api-token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.api-token\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.floor-times\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.floor-times\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.host-tag\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.host-tag\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.appoptics.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.appoptics.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.config-refresh-frequency\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.config-refresh-frequency\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.config-time-to-live\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.config-time-to-live\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.config-uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.config-uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.eval-uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.eval-uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.lwc-enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.lwc-enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.meter-time-to-live\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.meter-time-to-live\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.atlas.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.atlas.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.api-key\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.api-key\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.application-key\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.application-key\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.descriptions\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.descriptions\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.host-tag\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.host-tag\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.datadog.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.datadog.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.defaults.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.defaults.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.api-token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.api-token\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.device-id\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v1.device-id\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.group\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v1.group\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.technology-type\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v1.technology-type\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.v1.device-id\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v1.device-id\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.v1.group\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v1.group\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.v1.technology-type\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v1.technology-type\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.v2.default-dimensions\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v2.default-dimensions\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.v2.enrich-with-dynatrace-metadata\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v2.enrich-with-dynatrace-metadata\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.dynatrace.v2.metric-key-prefix\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.dynatrace.metrics.export.v2.metric-key-prefix\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.api-key-credentials\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.api-key-credentials\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.auto-create-index\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.auto-create-index\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.host\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.host\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.index\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.index\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.index-date-format\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.index-date-format\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.index-date-separator\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.index-date-separator\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.password\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.pipeline\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.pipeline\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.timestamp-field-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.timestamp-field-name\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.elastic.user-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.elastic.metrics.export.user-name\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.addressing-mode\",\n      \"type\": \"info.ganglia.gmetric4j.gmetric.GMetric$UDPAddressingMode\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.addressing-mode\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.duration-units\",\n      \"type\": \"java.util.concurrent.TimeUnit\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.duration-units\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.host\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.host\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.port\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.port\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.rate-units\",\n      \"type\": \"java.util.concurrent.TimeUnit\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.ganglia.time-to-live\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.ganglia.metrics.export.time-to-live\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.duration-units\",\n      \"type\": \"java.util.concurrent.TimeUnit\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.duration-units\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.graphite-tags-enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.graphite-tags-enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.host\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.host\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.port\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.port\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.protocol\",\n      \"type\": \"io.micrometer.graphite.GraphiteProtocol\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.protocol\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.rate-units\",\n      \"type\": \"java.util.concurrent.TimeUnit\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.rate-units\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.graphite.tags-as-prefix\",\n      \"type\": \"java.lang.String[]\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.graphite.metrics.export.tags-as-prefix\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.api-token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.api-token\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.repository\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.tags\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.tags\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.humio.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.humio.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.api-version\",\n      \"type\": \"io.micrometer.influx.InfluxApiVersion\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.api-version\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.auto-create-db\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.auto-create-db\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.bucket\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.bucket\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.compressed\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.compressed\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.consistency\",\n      \"type\": \"io.micrometer.influx.InfluxConsistency\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.consistency\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.db\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.db\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.org\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.org\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.password\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.retention-duration\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.retention-duration\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.retention-policy\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.retention-policy\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.retention-replication-factor\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.retention-replication-factor\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.retention-shard-duration\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.retention-shard-duration\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.token\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.influx.user-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.influx.metrics.export.user-name\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.jmx.domain\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.jmx.metrics.export.domain\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.jmx.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.jmx.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.jmx.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.jmx.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.password\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.kairos.user-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.kairos.metrics.export.user-name\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.account-id\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.account-id\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.api-key\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.api-key\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.client-provider-type\",\n      \"type\": \"io.micrometer.newrelic.ClientProviderType\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.client-provider-type\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.event-type\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.event-type\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.meter-name-event-type-enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.meter-name-event-type-enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.newrelic.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.newrelic.metrics.export.uri\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.descriptions\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.descriptions\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.histogram-flavor\",\n      \"type\": \"io.micrometer.prometheus.HistogramFlavor\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"No longer supported by the Prometheus client.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.base-url\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.address\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.grouping-key\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.grouping-key\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.job\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.job\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.password\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.password\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.push-rate\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.push-rate\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.shutdown-operation\",\n      \"type\": \"org.springframework.boot.actuate.metrics.export.prometheus.PrometheusPushGatewayManager$ShutdownOperation\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.shutdown-operation\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.pushgateway.username\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.username\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.prometheus.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.access-token\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.published-histogram-type\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.source\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.signalfx.uri\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"SignalFX is no longer supported.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.simple.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.simple.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.simple.mode\",\n      \"type\": \"io.micrometer.core.instrument.simple.CountingMode\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.simple.metrics.export.mode\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.simple.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.simple.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.batch-size\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.batch-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.connect-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.connect-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.num-threads\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.project-id\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.project-id\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.read-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.read-timeout\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.resource-labels\",\n      \"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.resource-labels\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.resource-type\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.resource-type\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.step\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.step\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.stackdriver.use-semantic-metric-types\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.stackdriver.metrics.export.use-semantic-metric-types\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.enabled\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.flavor\",\n      \"type\": \"io.micrometer.statsd.StatsdFlavor\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.flavor\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.host\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.host\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.max-packet-length\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.max-packet-length\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.polling-frequency\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.polling-frequency\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.port\",\n      \"type\": \"java.lang.Integer\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.port\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.protocol\",\n      \"type\": \"io.micrometer.statsd.StatsdProtocol\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.protocol\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.publish-unchanged-meters\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.statsd.metrics.export.publish-unchanged-meters\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.export.statsd.queue-size\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.system.diskspace.paths\",\n      \"type\": \"java.util.List<java.io.File>\",\n      \"defaultValue\": [\n        \".\"\n      ]\n    },\n    {\n      \"name\": \"management.metrics.web.client.request.autotime.enabled\",\n      \"description\": \"Whether to automatically time web client requests.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Requests are timed automatically.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.client.request.autotime.percentiles\",\n      \"description\": \"Computed non-aggregable percentiles to publish.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Should be configured globally via management.metrics.distribution.percentiles.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.client.request.autotime.percentiles-histogram\",\n      \"description\": \"Whether percentile histograms should be published.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Should be configured globally via management.metrics.distribution.percentiles-histogram.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.client.request.metric-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"management.observations.http.client.requests.name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.client.requests-metric-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"management.observations.http.client.requests.name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n        {\n      \"name\": \"management.metrics.web.server.auto-time-requests\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"management.metrics.web.server.request.autotime.enabled\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.server.request.autotime.enabled\",\n      \"description\": \"Whether to automatically time web server requests.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Requests are timed automatically.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.server.request.autotime.percentiles\",\n      \"description\": \"Computed non-aggregable percentiles to publish.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Should be configured globally via management.metrics.distribution.percentiles.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.server.request.autotime.percentiles-histogram\",\n      \"description\": \"Whether percentile histograms should be published.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Should be configured globally via management.metrics.distribution.percentiles-histogram.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.server.request.ignore-trailing-slash\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Not needed anymore, direct instrumentation in Spring MVC.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.server.request.metric-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"management.observations.http.server.requests.name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.web.server.requests-metric-name\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"replacement\": \"management.observations.http.server.requests.name\",\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.promethus.metrics.export.pushgateway.base-url\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.prometheus.metrics.export.pushgateway.address\",\n        \"since\": \"3.5.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.micrometer.metrics.autoconfigure.ServiceLevelObjectiveBoundary$ServiceLevelObjectiveBoundaryHints\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.MetricsAspectsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.MetricsEndpointAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics.AppOpticsMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.atlas.AtlasMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.datadog.DatadogMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace.DynatraceMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.elastic.ElasticMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia.GangliaMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.graphite.GraphiteMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.humio.HumioMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.influx.InfluxMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.jmx.JmxMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.kairos.KairosMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic.NewRelicMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus.PrometheusMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver.StackdriverMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.statsd.StatsdMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.jvm.JvmMetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.logging.log4j2.Log4J2MetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.logging.logback.LogbackMetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.ssl.SslMetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.startup.StartupTimeMetricsListenerAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.system.SystemMetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.task.TaskExecutorMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.micrometer.metrics.docker.compose.otlp.OpenTelemetryMetricsDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.micrometer.metrics.testcontainers.otlp.GrafanaOpenTelemetryMetricsContainerConnectionDetailsFactory,\\\norg.springframework.boot.micrometer.metrics.testcontainers.otlp.OpenTelemetryMetricsContainerConnectionDetailsFactory\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.micrometer.metrics.ValidationFailureAnalyzer\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/MaximumAllowableTagsMeterFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.Meter.Type;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.config.MeterFilterReply;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MaximumAllowableTagsMeterFilter}.\n *\n * @author Phillip Webb\n */\nclass MaximumAllowableTagsMeterFilterTests {\n\n\t@Test\n\tvoid applyWhenNameDoesNotHavePrefixReturnsNeutral() {\n\t\tMaximumAllowableTagsMeterFilter filter = new MaximumAllowableTagsMeterFilter(\"test\", \"k\", 1);\n\t\tassertThat(filter.accept(meterId(\"tset\", \"k\", \"v\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t\tassertThat(filter).extracting(\"observedTagValues\").asInstanceOf(InstanceOfAssertFactories.COLLECTION).isEmpty();\n\t}\n\n\t@Test\n\tvoid applyWhenNameHasPrefixButNoTagKeyReturnsNeutral() {\n\t\tMaximumAllowableTagsMeterFilter filter = new MaximumAllowableTagsMeterFilter(\"test\", \"k\", 1);\n\t\tassertThat(filter.accept(meterId(\"test\", \"k\", \"v\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t\tassertThat(filter).extracting(\"observedTagValues\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.COLLECTION)\n\t\t\t.containsExactly(\"v\");\n\t}\n\n\t@Test\n\tvoid applyWhenNameHasPrefixAndTagKeyReturnsNeutralUntilLimit() {\n\t\tMaximumAllowableTagsMeterFilter filter = new MaximumAllowableTagsMeterFilter(\"test\", \"k\", 1);\n\t\tassertThat(filter.accept(meterId(\"test\", \"k\", \"v1\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t\tassertThat(filter.accept(meterId(\"test\", \"k\", \"v2\"))).isEqualTo(MeterFilterReply.DENY);\n\t\tassertThat(filter.accept(meterId(\"test\", \"k\", \"v3\"))).isEqualTo(MeterFilterReply.DENY);\n\t\tassertThat(filter).extracting(\"observedTagValues\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.COLLECTION)\n\t\t\t.containsExactly(\"v1\");\n\t}\n\n\tprivate Meter.Id meterId(String name, String tagKey, String tagValue) {\n\t\tMeterRegistry registry = new SimpleMeterRegistry();\n\t\tMeter meter = Meter.builder(name, Type.COUNTER, Collections.emptyList())\n\t\t\t.tag(tagKey, tagValue)\n\t\t\t.register(registry);\n\t\treturn meter.getId();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/ValidationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.newrelic.NewRelicConfig;\nimport io.micrometer.newrelic.NewRelicMeterRegistry;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link ValidationFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n */\nclass ValidationFailureAnalyzerTests {\n\n\t@Test\n\tvoid analyzesMissingRequiredConfiguration() {\n\t\tFailureAnalysis analysis = new ValidationFailureAnalyzer()\n\t\t\t.analyze(createFailure(MissingAccountIdAndApiKeyConfiguration.class));\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getCause().getMessage()).contains(\"newrelic.metrics.export.apiKey was 'null'\");\n\t\tassertThat(analysis.getDescription()).isEqualTo(String.format(\"Invalid Micrometer configuration detected:%n%n\"\n\t\t\t\t+ \"  - newrelic.metrics.export.apiKey was 'null' but it is required when publishing to Insights API%n\"\n\t\t\t\t+ \"  - newrelic.metrics.export.accountId was 'null' but it is required when publishing to Insights API\"));\n\t}\n\n\tprivate Exception createFailure(Class<?> configuration) {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(configuration)) {\n\t\t\tfail(\"Expected failure did not occur\");\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MissingAccountIdAndApiKeyConfiguration {\n\n\t\t@Bean\n\t\tNewRelicMeterRegistry meterRegistry() {\n\t\t\treturn new NewRelicMeterRegistry(new NewRelicConfig() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable String get(String key) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String prefix() {\n\t\t\t\t\treturn \"newrelic.metrics.export\";\n\t\t\t\t}\n\n\t\t\t}, Clock.SYSTEM);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/actuate/endpoint/MetricsEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Stream;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.MockClock;\nimport io.micrometer.core.instrument.Statistic;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint.MetricDescriptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link MetricsEndpoint}.\n *\n * @author Andy Wilkinson\n * @author Jon Schneider\n */\nclass MetricsEndpointTests {\n\n\tprivate final MeterRegistry registry = new SimpleMeterRegistry(SimpleConfig.DEFAULT, new MockClock());\n\n\tprivate final MetricsEndpoint endpoint = new MetricsEndpoint(this.registry);\n\n\t@Test\n\tvoid listNamesHandlesEmptyListOfMeters() {\n\t\tMetricsEndpoint.MetricNamesDescriptor result = this.endpoint.listNames();\n\t\tassertThat(result.getNames()).isEmpty();\n\t}\n\n\t@Test\n\tvoid listNamesProducesListOfUniqueMeterNames() {\n\t\tthis.registry.counter(\"com.example.alpha\");\n\t\tthis.registry.counter(\"com.example.charlie\");\n\t\tthis.registry.counter(\"com.example.bravo\");\n\t\tthis.registry.counter(\"com.example.delta\");\n\t\tthis.registry.counter(\"com.example.delta\");\n\t\tthis.registry.counter(\"com.example.echo\");\n\t\tthis.registry.counter(\"com.example.bravo\");\n\t\tMetricsEndpoint.MetricNamesDescriptor result = this.endpoint.listNames();\n\t\tassertThat(result.getNames()).containsExactly(\"com.example.alpha\", \"com.example.bravo\", \"com.example.charlie\",\n\t\t\t\t\"com.example.delta\", \"com.example.echo\");\n\t}\n\n\t@Test\n\tvoid listNamesResponseOverCompositeRegistries() {\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tSimpleMeterRegistry reg1 = new SimpleMeterRegistry();\n\t\tSimpleMeterRegistry reg2 = new SimpleMeterRegistry();\n\t\tcomposite.add(reg1);\n\t\tcomposite.add(reg2);\n\t\treg1.counter(\"counter1\").increment();\n\t\treg2.counter(\"counter2\").increment();\n\t\tMetricsEndpoint endpoint = new MetricsEndpoint(composite);\n\t\tassertThat(endpoint.listNames().getNames()).containsExactly(\"counter1\", \"counter2\");\n\t}\n\n\t@Test\n\tvoid metricValuesAreTheSumOfAllTimeSeriesMatchingTags() {\n\t\tthis.registry.counter(\"cache\", \"result\", \"hit\", \"host\", \"1\").increment(2);\n\t\tthis.registry.counter(\"cache\", \"result\", \"miss\", \"host\", \"1\").increment(2);\n\t\tthis.registry.counter(\"cache\", \"result\", \"hit\", \"host\", \"2\").increment(2);\n\t\tMetricsEndpoint.MetricDescriptor response = this.endpoint.metric(\"cache\", Collections.emptyList());\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getName()).isEqualTo(\"cache\");\n\t\tassertThat(availableTagKeys(response)).containsExactly(\"result\", \"host\");\n\t\tassertThat(getCount(response)).hasValue(6.0);\n\t\tresponse = this.endpoint.metric(\"cache\", Collections.singletonList(\"result:hit\"));\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(availableTagKeys(response)).containsExactly(\"host\");\n\t\tassertThat(getCount(response)).hasValue(4.0);\n\t}\n\n\t@Test\n\tvoid findFirstMatchingMetersFromNestedRegistries() {\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tSimpleMeterRegistry firstLevel0 = new SimpleMeterRegistry();\n\t\tCompositeMeterRegistry firstLevel1 = new CompositeMeterRegistry();\n\t\tSimpleMeterRegistry secondLevel = new SimpleMeterRegistry();\n\t\tcomposite.add(firstLevel0);\n\t\tcomposite.add(firstLevel1);\n\t\tfirstLevel1.add(secondLevel);\n\t\tsecondLevel.counter(\"cache\", \"result\", \"hit\", \"host\", \"1\").increment(2);\n\t\tsecondLevel.counter(\"cache\", \"result\", \"miss\", \"host\", \"1\").increment(2);\n\t\tsecondLevel.counter(\"cache\", \"result\", \"hit\", \"host\", \"2\").increment(2);\n\t\tMetricsEndpoint endpoint = new MetricsEndpoint(composite);\n\t\tMetricsEndpoint.MetricDescriptor response = endpoint.metric(\"cache\", Collections.emptyList());\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getName()).isEqualTo(\"cache\");\n\t\tassertThat(availableTagKeys(response)).containsExactly(\"result\", \"host\");\n\t\tassertThat(getCount(response)).hasValue(6.0);\n\t\tresponse = endpoint.metric(\"cache\", Collections.singletonList(\"result:hit\"));\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(availableTagKeys(response)).containsExactly(\"host\");\n\t\tassertThat(getCount(response)).hasValue(4.0);\n\t}\n\n\t@Test\n\tvoid matchingMeterNotFoundInNestedRegistries() {\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tCompositeMeterRegistry firstLevel = new CompositeMeterRegistry();\n\t\tSimpleMeterRegistry secondLevel = new SimpleMeterRegistry();\n\t\tcomposite.add(firstLevel);\n\t\tfirstLevel.add(secondLevel);\n\t\tMetricsEndpoint endpoint = new MetricsEndpoint(composite);\n\t\tMetricsEndpoint.MetricDescriptor response = endpoint.metric(\"invalid.metric.name\", Collections.emptyList());\n\t\tassertThat(response).isNull();\n\t}\n\n\t@Test\n\tvoid metricTagValuesAreDeduplicated() {\n\t\tthis.registry.counter(\"cache\", \"host\", \"1\", \"region\", \"east\", \"result\", \"hit\");\n\t\tthis.registry.counter(\"cache\", \"host\", \"1\", \"region\", \"east\", \"result\", \"miss\");\n\t\tMetricsEndpoint.MetricDescriptor response = this.endpoint.metric(\"cache\", Collections.singletonList(\"host:1\"));\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getAvailableTags()\n\t\t\t.stream()\n\t\t\t.filter((t) -> t.getTag().equals(\"region\"))\n\t\t\t.flatMap((t) -> t.getValues().stream())).containsExactly(\"east\");\n\t}\n\n\t@Test\n\tvoid metricWithSpaceInTagValue() {\n\t\tthis.registry.counter(\"counter\", \"key\", \"a space\").increment(2);\n\t\tMetricsEndpoint.MetricDescriptor response = this.endpoint.metric(\"counter\",\n\t\t\t\tCollections.singletonList(\"key:a space\"));\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getName()).isEqualTo(\"counter\");\n\t\tassertThat(availableTagKeys(response)).isEmpty();\n\t\tassertThat(getCount(response)).hasValue(2.0);\n\t}\n\n\t@Test\n\tvoid metricWithInvalidTag() {\n\t\tassertThatExceptionOfType(InvalidEndpointRequestException.class)\n\t\t\t.isThrownBy(() -> this.endpoint.metric(\"counter\", Collections.singletonList(\"key\")));\n\t}\n\n\t@Test\n\tvoid metricPresentInOneRegistryOfACompositeAndNotAnother() {\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tSimpleMeterRegistry reg1 = new SimpleMeterRegistry();\n\t\tSimpleMeterRegistry reg2 = new SimpleMeterRegistry();\n\t\tcomposite.add(reg1);\n\t\tcomposite.add(reg2);\n\t\treg1.counter(\"counter1\").increment();\n\t\treg2.counter(\"counter2\").increment();\n\t\tMetricsEndpoint endpoint = new MetricsEndpoint(composite);\n\t\tassertThat(endpoint.metric(\"counter1\", Collections.emptyList())).isNotNull();\n\t\tassertThat(endpoint.metric(\"counter2\", Collections.emptyList())).isNotNull();\n\t}\n\n\t@Test\n\tvoid nonExistentMetric() {\n\t\tMetricsEndpoint.MetricDescriptor response = this.endpoint.metric(\"does.not.exist\", Collections.emptyList());\n\t\tassertThat(response).isNull();\n\t}\n\n\t@Test\n\tvoid maxAggregation() {\n\t\tSimpleMeterRegistry reg = new SimpleMeterRegistry();\n\t\treg.timer(\"timer\", \"k\", \"v1\").record(1, TimeUnit.SECONDS);\n\t\treg.timer(\"timer\", \"k\", \"v2\").record(2, TimeUnit.SECONDS);\n\t\tassertMetricHasStatisticEqualTo(reg, \"timer\", Statistic.MAX, 2.0);\n\t}\n\n\t@Test\n\tvoid countAggregation() {\n\t\tSimpleMeterRegistry reg = new SimpleMeterRegistry();\n\t\treg.counter(\"counter\", \"k\", \"v1\").increment();\n\t\treg.counter(\"counter\", \"k\", \"v2\").increment();\n\t\tassertMetricHasStatisticEqualTo(reg, \"counter\", Statistic.COUNT, 2.0);\n\t}\n\n\tprivate void assertMetricHasStatisticEqualTo(MeterRegistry registry, String metricName, Statistic stat,\n\t\t\tDouble value) {\n\t\tMetricsEndpoint endpoint = new MetricsEndpoint(registry);\n\t\tMetricDescriptor metric = endpoint.metric(metricName, Collections.emptyList());\n\t\tassertThat(metric).isNotNull();\n\t\tassertThat(metric.getMeasurements().stream().filter((sample) -> sample.getStatistic().equals(stat)).findAny())\n\t\t\t.hasValueSatisfying((sample) -> assertThat(sample.getValue()).isEqualTo(value));\n\t}\n\n\tprivate Optional<Double> getCount(MetricsEndpoint.MetricDescriptor response) {\n\t\treturn response.getMeasurements()\n\t\t\t.stream()\n\t\t\t.filter((sample) -> sample.getStatistic().equals(Statistic.COUNT))\n\t\t\t.findAny()\n\t\t\t.map(MetricsEndpoint.Sample::getValue);\n\t}\n\n\tprivate Stream<String> availableTagKeys(MetricsEndpoint.MetricDescriptor response) {\n\t\treturn response.getAvailableTags().stream().map(MetricsEndpoint.AvailableTag::getTag);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/CompositeMeterRegistryAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompositeMeterRegistryAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass CompositeMeterRegistryAutoConfigurationTests {\n\n\tprivate static final String COMPOSITE_NAME = \"compositeMeterRegistry\";\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(BaseConfig.class)\n\t\t.withConfiguration(AutoConfigurations.of(CompositeMeterRegistryAutoConfiguration.class));\n\n\t@Test\n\tvoid registerWhenHasNoMeterRegistryShouldRegisterEmptyNoOpComposite() {\n\t\tthis.contextRunner.withUserConfiguration(NoMeterRegistryConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MeterRegistry.class);\n\t\t\tCompositeMeterRegistry registry = context.getBean(\"noOpMeterRegistry\", CompositeMeterRegistry.class);\n\t\t\tassertThat(registry.getRegistries()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid registerWhenHasSingleMeterRegistryShouldDoNothing() {\n\t\tthis.contextRunner.withUserConfiguration(SingleMeterRegistryConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MeterRegistry.class);\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry).isInstanceOf(TestMeterRegistry.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid registerWhenHasMultipleMeterRegistriesShouldAddPrimaryComposite() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleMeterRegistriesConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(MeterRegistry.class)).hasSize(3)\n\t\t\t\t.containsKeys(\"meterRegistryOne\", \"meterRegistryTwo\", COMPOSITE_NAME);\n\t\t\tMeterRegistry primary = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(primary).isInstanceOf(CompositeMeterRegistry.class);\n\t\t\tassertThat(((CompositeMeterRegistry) primary).getRegistries()).hasSize(2);\n\t\t\tassertThat(primary.config().clock()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid registerWhenHasMultipleRegistriesAndOneIsPrimaryShouldDoNothing() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleMeterRegistriesWithOnePrimaryConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(MeterRegistry.class)).hasSize(2)\n\t\t\t\t.containsKeys(\"meterRegistryOne\", \"meterRegistryTwo\");\n\t\t\tMeterRegistry primary = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(primary).isInstanceOf(TestMeterRegistry.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfig {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tClock micrometerClock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NoMeterRegistryConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SingleMeterRegistryConfig {\n\n\t\t@Bean\n\t\tMeterRegistry meterRegistry() {\n\t\t\treturn new TestMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleMeterRegistriesConfig {\n\n\t\t@Bean\n\t\tMeterRegistry meterRegistryOne() {\n\t\t\treturn new TestMeterRegistry();\n\t\t}\n\n\t\t@Bean\n\t\tMeterRegistry meterRegistryTwo() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleMeterRegistriesWithOnePrimaryConfig {\n\n\t\t@Bean\n\t\t@Primary\n\t\tMeterRegistry meterRegistryOne() {\n\t\t\treturn new TestMeterRegistry();\n\t\t}\n\n\t\t@Bean\n\t\tMeterRegistry meterRegistryTwo() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\tstatic class TestMeterRegistry extends SimpleMeterRegistry {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport com.netflix.spectator.atlas.AtlasConfig;\nimport io.micrometer.atlas.AtlasMeterRegistry;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.prometheusmetrics.PrometheusConfig;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.jvm.JvmMetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for applying {@link MeterRegistryCustomizer} beans.\n *\n * @author Jon Schneider\n * @author Andy Wilkinson\n */\nclass MeterRegistryCustomizerTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(AtlasMeterRegistry.class, () -> new AtlasMeterRegistry(new AtlasConfig() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String get(String k) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}))\n\t\t.withBean(PrometheusMeterRegistry.class, () -> new PrometheusMeterRegistry(new PrometheusConfig() {\n\n\t\t\t@Override\n\t\t\tpublic @Nullable String get(String key) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\")\n\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,\n\t\t\t\tCompositeMeterRegistryAutoConfiguration.class, JvmMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid commonTagsAreAppliedToAutoConfiguredBinders() {\n\t\tthis.contextRunner.withUserConfiguration(MeterRegistryCustomizerConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tregistry.get(\"jvm.memory.used\").tags(\"region\", \"us-east-1\").gauge();\n\t\t});\n\t}\n\n\t@Test\n\tvoid commonTagsAreAppliedBeforeRegistryIsInjectableElsewhere() {\n\t\tthis.contextRunner.withUserConfiguration(MeterRegistryCustomizerConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tregistry.get(\"my.thing\").tags(\"region\", \"us-east-1\").gauge();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customizersCanBeAppliedToSpecificRegistryTypes() {\n\t\tthis.contextRunner.withUserConfiguration(MeterRegistryCustomizerConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry prometheus = context.getBean(PrometheusMeterRegistry.class);\n\t\t\tprometheus.get(\"jvm.memory.used\").tags(\"job\", \"myjob\").gauge();\n\t\t\tMeterRegistry atlas = context.getBean(AtlasMeterRegistry.class);\n\t\t\tassertThat(atlas.find(\"jvm.memory.used\").tags(\"job\", \"myjob\").gauge()).isNull();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MeterRegistryCustomizerConfiguration {\n\n\t\t@Bean\n\t\tMeterRegistryCustomizer<MeterRegistry> commonTags() {\n\t\t\treturn (registry) -> registry.config().commonTags(\"region\", \"us-east-1\");\n\t\t}\n\n\t\t@Bean\n\t\tMeterRegistryCustomizer<PrometheusMeterRegistry> prometheusOnlyCommonTags() {\n\t\t\treturn (registry) -> registry.config().commonTags(\"job\", \"myjob\");\n\t\t}\n\n\t\t@Bean\n\t\tMyThing myThing(MeterRegistry registry) {\n\t\t\tregistry.gauge(\"my.thing\", 0);\n\t\t\treturn new MyThing();\n\t\t}\n\n\t\tclass MyThing {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterRegistryPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.MeterRegistry.Config;\nimport io.micrometer.core.instrument.Metrics;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.config.MeterFilter;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.InOrder;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MeterRegistryPostProcessor.CompositeMeterRegistries;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MeterRegistryPostProcessor}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(MockitoExtension.class)\nclass MeterRegistryPostProcessorTests {\n\n\tprivate final MetricsProperties properties = new MetricsProperties();\n\n\tprivate final List<MeterRegistryCustomizer<?>> customizers = new ArrayList<>();\n\n\tprivate final List<MeterFilter> filters = new ArrayList<>();\n\n\tprivate final List<MeterBinder> binders = new ArrayList<>();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MeterRegistryCustomizer<MeterRegistry> mockCustomizer;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MeterFilter mockFilter;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MeterBinder mockBinder;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MeterRegistry mockRegistry;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Config mockConfig;\n\n\tMeterRegistryPostProcessorTests() {\n\t\tthis.properties.setUseGlobalRegistry(false);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeWhenUserDefinedCompositeAppliesCustomizer() {\n\t\tthis.customizers.add(this.mockCustomizer);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(\n\t\t\t\tCompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),\n\t\t\t\tcreateObjectProvider(this.customizers), createObjectProvider(this.filters),\n\t\t\t\tcreateObjectProvider(this.binders));\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tpostProcessAndInitialize(processor, composite);\n\t\tthen(this.mockCustomizer).should().customize(composite);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeWhenAutoConfiguredCompositeAppliesCustomizer() {\n\t\tthis.customizers.add(this.mockCustomizer);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateEmptyObjectProvider(), createObjectProvider(this.binders));\n\t\tAutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,\n\t\t\t\tCollections.emptyList());\n\t\tpostProcessAndInitialize(processor, composite);\n\t\tthen(this.mockCustomizer).should().customize(composite);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeAppliesCustomizer() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tthis.customizers.add(this.mockCustomizer);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tthen(this.mockCustomizer).should().customize(this.mockRegistry);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeAppliesFilter() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tthis.filters.add(this.mockFilter);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tthen(this.mockConfig).should().meterFilter(this.mockFilter);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeOnlyAppliesLmiitedFiltersToAutoConfigured() {\n\t\tMaximumAllowableTagsMeterFilter onlyOnceFilter = mock();\n\t\tthis.filters.add(this.mockFilter);\n\t\tthis.filters.add(onlyOnceFilter);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tAutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,\n\t\t\t\tCollections.emptyList());\n\t\tpostProcessAndInitialize(processor, composite);\n\t\tassertThat(composite).extracting(\"filters\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.ARRAY)\n\t\t\t.containsExactly(onlyOnceFilter);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeBindsTo() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tthis.binders.add(this.mockBinder);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tthen(this.mockBinder).should().bindTo(this.mockRegistry);\n\t}\n\n\t@Test\n\tvoid whenUserDefinedCompositeThenPostProcessAndInitializeCompositeBindsTo() {\n\t\tthis.binders.add(this.mockBinder);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(\n\t\t\t\tCompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),\n\t\t\t\tcreateObjectProvider(this.customizers), createObjectProvider(this.filters),\n\t\t\t\tcreateObjectProvider(this.binders));\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tpostProcessAndInitialize(processor, composite);\n\t\tthen(this.mockBinder).should().bindTo(composite);\n\t}\n\n\t@Test\n\tvoid whenUserDefinedCompositeThenPostProcessAndInitializeStandardRegistryDoesNotBindTo() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(\n\t\t\t\tCompositeMeterRegistries.ONLY_USER_DEFINED, createObjectProvider(this.properties),\n\t\t\t\tcreateObjectProvider(this.customizers), createObjectProvider(this.filters),\n\t\t\t\tcreateEmptyObjectProvider());\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tthen(this.mockBinder).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid whenAutoConfiguredCompositeThenPostProcessAndInitializeAutoConfiguredCompositeBindsTo() {\n\t\tthis.binders.add(this.mockBinder);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateEmptyObjectProvider(), createObjectProvider(this.binders));\n\t\tAutoConfiguredCompositeMeterRegistry composite = new AutoConfiguredCompositeMeterRegistry(Clock.SYSTEM,\n\t\t\t\tCollections.emptyList());\n\t\tpostProcessAndInitialize(processor, composite);\n\t\tthen(this.mockBinder).should().bindTo(composite);\n\t}\n\n\t@Test\n\tvoid whenAutoConfiguredCompositeThenPostProcessAndInitializeCompositeDoesNotBindTo() {\n\t\tthis.binders.add(this.mockBinder);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createEmptyObjectProvider());\n\t\tCompositeMeterRegistry composite = new CompositeMeterRegistry();\n\t\tpostProcessAndInitialize(processor, composite);\n\t\tthen(this.mockBinder).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid whenAutoConfiguredCompositeThenPostProcessAndInitializeStandardRegistryDoesNotBindTo() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.AUTO_CONFIGURED,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createEmptyObjectProvider());\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tthen(this.mockBinder).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeIsOrderedCustomizerThenFilterThenBindTo() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tthis.customizers.add(this.mockCustomizer);\n\t\tthis.filters.add(this.mockFilter);\n\t\tthis.binders.add(this.mockBinder);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tInOrder ordered = inOrder(this.mockBinder, this.mockConfig, this.mockCustomizer);\n\t\tthen(this.mockCustomizer).should(ordered).customize(this.mockRegistry);\n\t\tthen(this.mockConfig).should(ordered).meterFilter(this.mockFilter);\n\t\tthen(this.mockBinder).should(ordered).bindTo(this.mockRegistry);\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeWhenUseGlobalRegistryTrueAddsToGlobalRegistry() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tthis.properties.setUseGlobalRegistry(true);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\ttry {\n\t\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\t\tassertThat(Metrics.globalRegistry.getRegistries()).contains(this.mockRegistry);\n\t\t}\n\t\tfinally {\n\t\t\tMetrics.removeRegistry(this.mockRegistry);\n\t\t}\n\t}\n\n\t@Test\n\tvoid postProcessAndInitializeWhenUseGlobalRegistryFalseDoesNotAddToGlobalRegistry() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tpostProcessAndInitialize(processor, this.mockRegistry);\n\t\tassertThat(Metrics.globalRegistry.getRegistries()).doesNotContain(this.mockRegistry);\n\t}\n\n\t@Test\n\tvoid postProcessDoesNotBindToUntilSingletonsInitialized() {\n\t\tgiven(this.mockRegistry.config()).willReturn(this.mockConfig);\n\t\tthis.binders.add(this.mockBinder);\n\t\tMeterRegistryPostProcessor processor = new MeterRegistryPostProcessor(CompositeMeterRegistries.NONE,\n\t\t\t\tcreateObjectProvider(this.properties), createObjectProvider(this.customizers),\n\t\t\t\tcreateObjectProvider(this.filters), createObjectProvider(this.binders));\n\t\tprocessor.postProcessAfterInitialization(this.mockRegistry, \"meterRegistry\");\n\t\tthen(this.mockBinder).shouldHaveNoInteractions();\n\t\tprocessor.afterSingletonsInstantiated();\n\t\tthen(this.mockBinder).should().bindTo(this.mockRegistry);\n\t}\n\n\tprivate void postProcessAndInitialize(MeterRegistryPostProcessor processor, MeterRegistry registry) {\n\t\tprocessor.postProcessAfterInitialization(registry, \"meterRegistry\");\n\t\tprocessor.afterSingletonsInstantiated();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> ObjectProvider<T> createObjectProvider(List<T> objects) {\n\t\tObjectProvider<T> objectProvider = mock(ObjectProvider.class);\n\t\tgiven(objectProvider.orderedStream()).willReturn(objects.stream());\n\t\treturn objectProvider;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> ObjectProvider<T> createObjectProvider(T object) {\n\t\tObjectProvider<T> objectProvider = mock(ObjectProvider.class);\n\t\tgiven(objectProvider.getObject()).willReturn(object);\n\t\treturn objectProvider;\n\t}\n\n\tprivate <T> ObjectProvider<T> createEmptyObjectProvider() {\n\t\treturn new ObjectProvider<>() {\n\n\t\t\t@Override\n\t\t\tpublic T getObject() throws BeansException {\n\t\t\t\tthrow new NoSuchBeanDefinitionException(\"No bean\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Stream<T> orderedStream() {\n\t\t\t\treturn Stream.empty();\n\t\t\t}\n\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MeterValueTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.instrument.Meter.Type;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MeterValue}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass MeterValueTests {\n\n\t@Test\n\tvoid getValueForDistributionSummaryWhenFromNumberShouldReturnDoubleValue() {\n\t\tMeterValue meterValue = MeterValue.valueOf(123.42);\n\t\tassertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42);\n\t}\n\n\t@Test\n\tvoid getValueForDistributionSummaryWhenFromNumberStringShouldReturnDoubleValue() {\n\t\tMeterValue meterValue = MeterValue.valueOf(\"123.42\");\n\t\tassertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42);\n\t}\n\n\t@Test\n\tvoid getValueForDistributionSummaryWhenFromDurationStringShouldReturnNull() {\n\t\tMeterValue meterValue = MeterValue.valueOf(\"123ms\");\n\t\tassertThat(meterValue.getValue(Type.DISTRIBUTION_SUMMARY)).isNull();\n\t}\n\n\t@Test\n\tvoid getValueForTimerWhenFromNumberShouldReturnMsToNanosValue() {\n\t\tMeterValue meterValue = MeterValue.valueOf(123d);\n\t\tassertThat(meterValue.getValue(Type.TIMER)).isEqualTo(123000000);\n\t}\n\n\t@Test\n\tvoid getValueForTimerWhenFromNumberStringShouldMsToNanosValue() {\n\t\tMeterValue meterValue = MeterValue.valueOf(\"123\");\n\t\tassertThat(meterValue.getValue(Type.TIMER)).isEqualTo(123000000);\n\t}\n\n\t@Test\n\tvoid getValueForTimerWhenFromDurationStringShouldReturnDurationNanos() {\n\t\tMeterValue meterValue = MeterValue.valueOf(\"123ms\");\n\t\tassertThat(meterValue.getValue(Type.TIMER)).isEqualTo(123000000);\n\t}\n\n\t@Test\n\tvoid getValueForOthersShouldReturnNull() {\n\t\tMeterValue meterValue = MeterValue.valueOf(\"123\");\n\t\tassertThat(meterValue.getValue(Type.COUNTER)).isNull();\n\t\tassertThat(meterValue.getValue(Type.GAUGE)).isNull();\n\t\tassertThat(meterValue.getValue(Type.LONG_TASK_TIMER)).isNull();\n\t\tassertThat(meterValue.getValue(Type.OTHER)).isNull();\n\t}\n\n\t@Test\n\tvoid valueOfShouldWorkInBinder() {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tTestPropertyValues.of(\"duration=10ms\", \"number=20.42\").applyTo(environment);\n\t\tassertThat(Binder.get(environment).bind(\"duration\", Bindable.of(MeterValue.class)).get().getValue(Type.TIMER))\n\t\t\t.isEqualTo(10000000);\n\t\tassertThat(Binder.get(environment)\n\t\t\t.bind(\"number\", Bindable.of(MeterValue.class))\n\t\t\t.get()\n\t\t\t.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(20.42);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAspectsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.function.Function;\n\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport io.micrometer.common.annotation.ValueResolver;\nimport io.micrometer.core.aop.CountedAspect;\nimport io.micrometer.core.aop.CountedMeterTagAnnotationHandler;\nimport io.micrometer.core.aop.MeterTagAnnotationHandler;\nimport io.micrometer.core.aop.TimedAspect;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.aspectj.weaver.Advice;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetricsAspectsAutoConfiguration}.\n *\n * @author Jonatan Ivanov\n */\nclass MetricsAspectsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t.withPropertyValues(\"management.observations.annotations.enabled=true\")\n\t\t.withConfiguration(AutoConfigurations.of(MetricsAspectsAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotConfigureAspectsByDefault() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MetricsAspectsAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(CountedAspect.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(TimedAspect.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureAspects() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CountedAspect.class);\n\t\t\tassertThat(context).hasSingleBean(TimedAspect.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldAutoConfigureMeterTagAnnotationHandlerWhenValueExpressionResolverIsAvailable() {\n\t\tthis.contextRunner.withBean(ValueExpressionResolver.class, () -> mock(ValueExpressionResolver.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TimedAspect.class).hasSingleBean(MeterTagAnnotationHandler.class);\n\t\t\t\tassertThat(context.getBean(TimedAspect.class)).extracting(\"meterTagAnnotationHandler\")\n\t\t\t\t\t.isSameAs(context.getBean(MeterTagAnnotationHandler.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseUserDefinedMeterTagAnnotationHandler() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customMeterTagAnnotationHandler\", MeterTagAnnotationHandler.class,\n\t\t\t\t\t() -> new MeterTagAnnotationHandler(getResolverProvider(), getExpressionResolverProvider()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TimedAspect.class).hasSingleBean(MeterTagAnnotationHandler.class);\n\t\t\t\tassertThat(context.getBean(TimedAspect.class)).extracting(\"meterTagAnnotationHandler\")\n\t\t\t\t\t.isSameAs(context.getBean(\"customMeterTagAnnotationHandler\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldAutoConfigureCountedMeterTagAnnotationHandlerWhenValueExpressionResolverIsAvailable() {\n\t\tthis.contextRunner.withBean(ValueExpressionResolver.class, () -> mock(ValueExpressionResolver.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(CountedAspect.class)\n\t\t\t\t\t.hasSingleBean(CountedMeterTagAnnotationHandler.class);\n\t\t\t\tassertThat(context.getBean(CountedAspect.class)).extracting(\"meterTagAnnotationHandler\")\n\t\t\t\t\t.isSameAs(context.getBean(CountedMeterTagAnnotationHandler.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseUserDefinedCountedMeterTagAnnotationHandler() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customCountedMeterTagAnnotationHandler\", CountedMeterTagAnnotationHandler.class,\n\t\t\t\t\t() -> new CountedMeterTagAnnotationHandler(getResolverProvider(), getExpressionResolverProvider()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(CountedAspect.class)\n\t\t\t\t\t.hasSingleBean(CountedMeterTagAnnotationHandler.class);\n\t\t\t\tassertThat(context.getBean(CountedAspect.class)).extracting(\"meterTagAnnotationHandler\")\n\t\t\t\t\t.isSameAs(context.getBean(CountedMeterTagAnnotationHandler.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureAspectsIfMicrometerIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(MeterRegistry.class)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(CountedAspect.class);\n\t\t\tassertThat(context).doesNotHaveBean(TimedAspect.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureAspectsIfAspectjIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(CountedAspect.class);\n\t\t\tassertThat(context).doesNotHaveBean(TimedAspect.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureAspectsIfMeterRegistryBeanIsMissing() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MetricsAspectsAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(MeterRegistry.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(CountedAspect.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(TimedAspect.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfAspectBeansExist() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAspectsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(CountedAspect.class).hasBean(\"customCountedAspect\");\n\t\t\tassertThat(context).hasSingleBean(TimedAspect.class).hasBean(\"customTimedAspect\");\n\t\t});\n\t}\n\n\tprivate Function<Class<? extends ValueExpressionResolver>, ValueExpressionResolver> getExpressionResolverProvider() {\n\t\treturn (clazz) -> mock(ValueExpressionResolver.class);\n\t}\n\n\tprivate Function<Class<? extends ValueResolver>, ValueResolver> getResolverProvider() {\n\t\treturn (clazz) -> mock(ValueResolver.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAspectsConfiguration {\n\n\t\t@Bean\n\t\tCountedAspect customCountedAspect(MeterRegistry registry) {\n\t\t\treturn new CountedAspect(registry);\n\t\t}\n\n\t\t@Bean\n\t\tTimedAspect customTimedAspect(MeterRegistry registry) {\n\t\t\treturn new TimedAspect(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Set;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.MockClock;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for metrics auto-configuration.\n *\n * @author Stephane Nicoll\n */\nclass MetricsAutoConfigurationIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid propertyBasedMeterFilteringIsAutoConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.enable.my.org=false\").run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tregistry.timer(\"my.org.timer\");\n\t\t\tassertThat(registry.find(\"my.org.timer\").timer()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid propertyBasedCommonTagsIsAutoConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.metrics.tags.region=test\", \"management.metrics.tags.origin=local\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tregistry.counter(\"my.counter\", \"env\", \"qa\");\n\t\t\t\tassertThat(registry.find(\"my.counter\")\n\t\t\t\t\t.tags(\"env\", \"qa\")\n\t\t\t\t\t.tags(\"region\", \"test\")\n\t\t\t\t\t.tags(\"origin\", \"local\")\n\t\t\t\t\t.counter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid emptyCompositeIsCreatedWhenNoMeterRegistriesAreAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry).isInstanceOf(CompositeMeterRegistry.class);\n\t\t\tassertThat(((CompositeMeterRegistry) registry).getRegistries()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid noCompositeIsCreatedWhenASingleMeterRegistryIsAutoConfigured() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.run((context) -> assertThat(context.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid noCompositeIsCreatedWithMultipleRegistriesAndOneThatIsPrimary() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"meterRegistry1\", SimpleMeterRegistry.class, SimpleMeterRegistry::new,\n\t\t\t\t\t(definition) -> definition.setPrimary(true))\n\t\t\t.withBean(\"meterRegistry2\", SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.run((context) -> assertThat(context.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid compositeCreatedWithMultipleRegistries() {\n\t\tthis.contextRunner.withBean(\"meterRegistry1\", SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.withBean(\"meterRegistry2\", SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry).isInstanceOf(CompositeMeterRegistry.class);\n\t\t\t\tassertThat(((CompositeMeterRegistry) registry).getRegistries()).hasSize(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredCompositeDoesNotHaveMeterFiltersApplied() {\n\t\tthis.contextRunner.withBean(\"meterRegistry1\", SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.withBean(\"meterRegistry2\", SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry composite = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(composite).extracting(\"filters\", InstanceOfAssertFactories.ARRAY).isEmpty();\n\t\t\t\tassertThat(composite).isInstanceOf(CompositeMeterRegistry.class);\n\t\t\t\tSet<MeterRegistry> registries = ((CompositeMeterRegistry) composite).getRegistries();\n\t\t\t\tassertThat(registries).hasSize(2);\n\t\t\t\tassertThat(registries).allSatisfy(\n\t\t\t\t\t\t(registry) -> assertThat(registry).extracting(\"filters\", InstanceOfAssertFactories.ARRAY)\n\t\t\t\t\t\t\t.hasSize(1));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid userConfiguredCompositeHasMeterFiltersApplied() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeMeterRegistryConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry composite = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(composite).extracting(\"filters\", InstanceOfAssertFactories.ARRAY).hasSize(1);\n\t\t\tassertThat(composite).isInstanceOf(CompositeMeterRegistry.class);\n\t\t\tSet<MeterRegistry> registries = ((CompositeMeterRegistry) composite).getRegistries();\n\t\t\tassertThat(registries).hasSize(2);\n\t\t\tassertThat(registries).hasOnlyElementsOfTypes(SimpleMeterRegistry.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CompositeMeterRegistryConfiguration {\n\n\t\t@Bean\n\t\tCompositeMeterRegistry compositeMeterRegistry() {\n\t\t\treturn new CompositeMeterRegistry(new MockClock(),\n\t\t\t\t\tArrays.asList(new SimpleMeterRegistry(), new SimpleMeterRegistry()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationMeterRegistryPostProcessorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.util.Map;\n\nimport ch.qos.logback.classic.Logger;\nimport ch.qos.logback.classic.LoggerContext;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.composite.CompositeMeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.jvm.JvmMetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.logging.logback.LogbackMetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MeterRegistryPostProcessor} configured by\n * {@link MetricsAutoConfiguration}.\n *\n * @author Jon Schneider\n */\nclass MetricsAutoConfigurationMeterRegistryPostProcessorIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid binderMetricsAreSearchableFromTheComposite() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(JvmMetricsAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tCompositeMeterRegistry composite = context.getBean(CompositeMeterRegistry.class);\n\t\t\t\tcomposite.get(\"jvm.memory.used\").gauge();\n\t\t\t\tcontext.getBeansOfType(MeterRegistry.class)\n\t\t\t\t\t.forEach((name, registry) -> registry.get(\"jvm.memory.used\").gauge());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customizersAreAppliedBeforeBindersAreCreated() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t});\n\t}\n\n\t@Test\n\tvoid counterIsIncrementedOncePerEventWithoutCompositeMeterRegistry() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tLogger logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger(\"test-logger\");\n\t\t\t\tlogger.error(\"Error.\");\n\t\t\t\tMap<String, MeterRegistry> registriesByName = context.getBeansOfType(MeterRegistry.class);\n\t\t\t\tassertThat(registriesByName).hasSize(1);\n\t\t\t\tMeterRegistry registry = registriesByName.values().iterator().next();\n\t\t\t\tassertThat(registry.get(\"logback.events\").tag(\"level\", \"error\").functionCounter().count()).isOne();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid counterIsIncrementedOncePerEventWithCompositeMeterRegistry() {\n\t\tthis.contextRunner.withBean(\"meterRegistry1\", SimpleMeterRegistry.class)\n\t\t\t.withBean(\"meterRegistry2\", SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tLogger logger = ((LoggerContext) LoggerFactory.getILoggerFactory()).getLogger(\"test-logger\");\n\t\t\t\tlogger.error(\"Error.\");\n\t\t\t\tMap<String, MeterRegistry> registriesByName = context.getBeansOfType(MeterRegistry.class);\n\t\t\t\tassertThat(registriesByName).hasSize(3);\n\t\t\t\tregistriesByName.forEach((name,\n\t\t\t\t\t\tregistry) -> assertThat(\n\t\t\t\t\t\t\t\tregistry.get(\"logback.events\").tag(\"level\", \"error\").functionCounter().count())\n\t\t\t\t\t\t\t.isOne());\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tMeterBinder testBinder(Alpha thing) {\n\t\t\treturn (registry) -> {\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tMeterRegistryCustomizer<?> testCustomizer() {\n\t\t\treturn (registry) -> registry.config().commonTags(\"testTag\", \"testValue\");\n\t\t}\n\n\t\t@Bean\n\t\tAlpha alpha() {\n\t\t\treturn new Alpha();\n\t\t}\n\n\t\t@Bean\n\t\tBravo bravo(Alpha alpha) {\n\t\t\treturn new Bravo(alpha);\n\t\t}\n\n\t\t@Bean\n\t\tstatic BeanPostProcessor testPostProcessor(ApplicationContext context) {\n\t\t\treturn new BeanPostProcessor() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\t\t\tif (bean instanceof Bravo) {\n\t\t\t\t\t\tMeterRegistry meterRegistry = context.getBean(MeterRegistry.class);\n\t\t\t\t\t\tmeterRegistry.gauge(\"test\", 1);\n\t\t\t\t\t}\n\t\t\t\t\treturn bean;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class Alpha {\n\n\t}\n\n\tstatic class Bravo {\n\n\t\tBravo(Alpha alpha) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/MetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Counter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.config.MeterFilter;\nimport io.micrometer.core.instrument.config.MeterFilterReply;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.micrometer.observation.ObservationHandler;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration.MeterRegistryCloser;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGroup;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Michael Berry\n * @author Phillip Webb\n */\nclass MetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(Clock.class));\n\t}\n\n\t@Test\n\tvoid allowsACustomClockToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomClockConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Clock.class).hasBean(\"customClock\"));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid configuresMeterRegistries() {\n\t\tthis.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry meterRegistry = context.getBean(MeterRegistry.class);\n\t\t\tMeterFilter[] filters = (MeterFilter[]) ReflectionTestUtils.getField(meterRegistry, \"filters\");\n\t\t\tassertThat(filters).hasSize(3);\n\t\t\tCounter counter = meterRegistry.counter(\"counter\");\n\t\t\tassertThat(filters[0].accept(counter.getId())).isEqualTo(MeterFilterReply.DENY);\n\t\t\tassertThat(filters[1]).isInstanceOf(PropertiesMeterFilter.class);\n\t\t\tassertThat(filters[2].accept(counter.getId())).isEqualTo(MeterFilterReply.ACCEPT);\n\t\t\tthen((MeterBinder) context.getBean(\"meterBinder\")).should().bindTo(meterRegistry);\n\t\t\tthen(context.getBean(MeterRegistryCustomizer.class)).should().customize(meterRegistry);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyMeterRegistryCloser() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MeterRegistryCloser.class));\n\t}\n\n\t@Test\n\tvoid meterRegistryCloserShouldCloseRegistryOnShutdown() {\n\t\tthis.contextRunner.withUserConfiguration(MeterRegistryConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry meterRegistry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(meterRegistry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(meterRegistry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid meterRegistryCloserShouldOnlyCloseRegistriesBelongingToContextBeingClosed() {\n\t\tMeterRegistry parentMeterRegistry = new SimpleMeterRegistry();\n\t\tMeterRegistry childMeterRegistry = new SimpleMeterRegistry();\n\t\tthis.contextRunner.withBean(MeterRegistry.class, () -> parentMeterRegistry).run((parent) -> {\n\t\t\tthis.contextRunner.withBean(MeterRegistry.class, () -> childMeterRegistry)\n\t\t\t\t.withParent(parent)\n\t\t\t\t.run((child) -> {\n\t\t\t\t\tassertThat(childMeterRegistry.isClosed()).isFalse();\n\t\t\t\t\tassertThat(parentMeterRegistry.isClosed()).isFalse();\n\t\t\t\t});\n\t\t\tassertThat(childMeterRegistry.isClosed()).isTrue();\n\t\t\tassertThat(parentMeterRegistry.isClosed()).isFalse();\n\t\t});\n\t\tassertThat(childMeterRegistry.isClosed()).isTrue();\n\t\tassertThat(parentMeterRegistry.isClosed()).isTrue();\n\t}\n\n\t@Test\n\tvoid supplyHandlerAndGroup() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ObservationHandlerGroup.class);\n\t\t\tassertThat(context).hasSingleBean(DefaultMeterObservationHandler.class);\n\t\t\tObservationHandlerGroup group = context.getBean(ObservationHandlerGroup.class);\n\t\t\tassertThat(group.isMember(mock(ObservationHandler.class))).isFalse();\n\t\t\tassertThat(group.isMember(mock(MeterObservationHandler.class))).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldEnableLongTaskTimerByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tDefaultMeterObservationHandler handler = context.getBean(DefaultMeterObservationHandler.class);\n\t\t\tassertThat(handler).hasFieldOrPropertyWithValue(\"shouldCreateLongTaskTimer\", true);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldDisableLongTaskTimerIfPropertyIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.observations.ignored-meters=long-task-timer\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultMeterObservationHandler handler = context.getBean(DefaultMeterObservationHandler.class);\n\t\t\t\tassertThat(handler).hasFieldOrPropertyWithValue(\"shouldCreateLongTaskTimer\", false);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomClockConfiguration {\n\n\t\t@Bean\n\t\tClock customClock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MeterRegistryConfiguration {\n\n\t\t@Bean\n\t\tMeterRegistry meterRegistry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tMeterRegistryCustomizer meterRegistryCustomizer() {\n\t\t\treturn mock(MeterRegistryCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\tMeterBinder meterBinder() {\n\t\t\treturn mock(MeterBinder.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tMeterFilter acceptMeterFilter() {\n\t\t\treturn MeterFilter.accept();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tMeterFilter denyMeterFilter() {\n\t\t\treturn MeterFilter.deny();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/PropertiesMeterFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.Meter.Id;\nimport io.micrometer.core.instrument.Meter.Type;\nimport io.micrometer.core.instrument.config.MeterFilterReply;\nimport io.micrometer.core.instrument.distribution.DistributionStatisticConfig;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link PropertiesMeterFilter}.\n *\n * @author Phillip Webb\n * @author Jon Schneider\n * @author Artsiom Yudovin\n * @author Leo Li\n */\nclass PropertiesMeterFilterTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPropertiesIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new PropertiesMeterFilter(null))\n\t\t\t.withMessageContaining(\"'properties' must not be null\");\n\t}\n\n\t@Test\n\tvoid acceptWhenHasNoEnabledPropertiesShouldReturnNeutral() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties());\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasNoMatchingEnabledPropertyShouldReturnNeutral() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"enable.something.else=false\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasEnableFalseShouldReturnDeny() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"enable.spring.boot=false\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.DENY);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasEnableTrueShouldReturnNeutral() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"enable.spring.boot=true\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasHigherEnableFalseShouldReturnDeny() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"enable.spring=false\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.DENY);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasHigherEnableTrueShouldReturnNeutral() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"enable.spring=true\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasHigherEnableFalseExactEnableTrueShouldReturnNeutral() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"enable.spring=false\", \"enable.spring.boot=true\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasHigherEnableTrueExactEnableFalseShouldReturnDeny() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"enable.spring=true\", \"enable.spring.boot=false\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.DENY);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasAllEnableFalseShouldReturnDeny() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"enable.all=false\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.DENY);\n\t}\n\n\t@Test\n\tvoid acceptWhenHasAllEnableFalseButHigherEnableTrueShouldReturnNeutral() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"enable.all=false\", \"enable.spring=true\"));\n\t\tassertThat(filter.accept(createMeterId(\"spring.boot\"))).isEqualTo(MeterFilterReply.NEUTRAL);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHistogramTrueShouldSetPercentilesHistogramToTrue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.spring.boot=true\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isTrue();\n\t}\n\n\t@Test\n\tvoid configureWhenHasHistogramFalseShouldSetPercentilesHistogramToFalse() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.spring.boot=false\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isFalse();\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherHistogramTrueShouldSetPercentilesHistogramToTrue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.spring=true\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isTrue();\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherHistogramFalseShouldSetPercentilesHistogramToFalse() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.spring=false\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isFalse();\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherHistogramTrueAndLowerFalseShouldSetPercentilesHistogramToFalse() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.spring=true\",\n\t\t\t\t\t\t\"distribution.percentiles-histogram.spring.boot=false\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isFalse();\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherHistogramFalseAndLowerTrueShouldSetPercentilesHistogramToFalse() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.spring=false\",\n\t\t\t\t\t\t\"distribution.percentiles-histogram.spring.boot=true\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isTrue();\n\t}\n\n\t@Test\n\tvoid configureWhenAllHistogramTrueSetPercentilesHistogramToTrue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles-histogram.all=true\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.isPercentileHistogram()).isTrue();\n\t}\n\n\t@Test\n\tvoid configureWhenHasPercentilesShouldSetPercentilesToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles.spring.boot=0.2,0.4,0.8\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getPercentiles())\n\t\t\t.containsExactly(0.2, 0.4, 0.8);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherPercentilesShouldSetPercentilesToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles.spring=0.2,0.4,0.8\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getPercentiles())\n\t\t\t.containsExactly(0.2, 0.4, 0.8);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherPercentilesAndLowerShouldSetPercentilesToLower() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\n\t\t\t\t\"distribution.percentiles.spring=0.2,0.4,0.8\", \"distribution.percentiles.spring.boot=0.85,0.9,0.95\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getPercentiles())\n\t\t\t.containsExactly(0.85, 0.9, 0.95);\n\t}\n\n\t@Test\n\tvoid configureWhenAllPercentilesSetShouldSetPercentilesToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.percentiles.all=0.2,0.4,0.8\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getPercentiles())\n\t\t\t.containsExactly(0.2, 0.4, 0.8);\n\t}\n\n\t@Test\n\tvoid configureWhenHasSloShouldSetSloToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.slo.spring.boot=1,2,3\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getServiceLevelObjectiveBoundaries()).containsExactly(1000000, 2000000, 3000000);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherSloShouldSetPercentilesToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"distribution.slo.spring=1,2,3\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getServiceLevelObjectiveBoundaries()).containsExactly(1000000, 2000000, 3000000);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherSloAndLowerShouldSetSloToLower() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.slo.spring=1,2,3\", \"distribution.slo.spring.boot=4,5,6\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getServiceLevelObjectiveBoundaries()).containsExactly(4000000, 5000000, 6000000);\n\t}\n\n\t@Test\n\tvoid configureWhenHasMinimumExpectedValueShouldSetMinimumExpectedToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.minimum-expected-value.spring.boot=10\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getMinimumExpectedValueAsDouble()).isEqualTo(Duration.ofMillis(10).toNanos());\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherMinimumExpectedValueShouldSetMinimumExpectedValueToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.minimum-expected-value.spring=10\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getMinimumExpectedValueAsDouble()).isEqualTo(Duration.ofMillis(10).toNanos());\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherMinimumExpectedValueAndLowerShouldSetMinimumExpectedValueToLower() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\n\t\t\t\t\"distribution.minimum-expected-value.spring=10\", \"distribution.minimum-expected-value.spring.boot=50\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getMinimumExpectedValueAsDouble()).isEqualTo(Duration.ofMillis(50).toNanos());\n\t}\n\n\t@Test\n\tvoid configureWhenHasMaximumExpectedValueShouldSetMaximumExpectedToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.maximum-expected-value.spring.boot=5000\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getMaximumExpectedValueAsDouble()).isEqualTo(Duration.ofMillis(5000).toNanos());\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherMaximumExpectedValueShouldSetMaximumExpectedValueToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.maximum-expected-value.spring=5000\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getMaximumExpectedValueAsDouble()).isEqualTo(Duration.ofMillis(5000).toNanos());\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherMaximumExpectedValueAndLowerShouldSetMaximumExpectedValueToLower() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.maximum-expected-value.spring=5000\",\n\t\t\t\t\t\t\"distribution.maximum-expected-value.spring.boot=10000\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT)\n\t\t\t.getMaximumExpectedValueAsDouble()).isEqualTo(Duration.ofMillis(10000).toNanos());\n\t}\n\n\t@Test\n\tvoid configureWhenHasExpiryShouldSetExpiryToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.expiry[spring.boot]=5ms\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getExpiry())\n\t\t\t.isEqualTo(Duration.ofMillis(5));\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherExpiryShouldSetExpiryToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"distribution.expiry.spring=5ms\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getExpiry())\n\t\t\t.isEqualTo(Duration.ofMillis(5));\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherExpiryAndLowerShouldSetExpiryToLower() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.expiry.spring=5ms\", \"distribution.expiry[spring.boot]=10ms\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getExpiry())\n\t\t\t.isEqualTo(Duration.ofMillis(10));\n\t}\n\n\t@Test\n\tvoid configureWhenAllExpirySetShouldSetExpiryToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"distribution.expiry.all=5ms\"));\n\t\tassertThat(filter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getExpiry())\n\t\t\t.isEqualTo(Duration.ofMillis(5));\n\t}\n\n\t@Test\n\tvoid configureWhenHasBufferLengthShouldSetBufferLengthToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.buffer-length.spring.boot=3\"));\n\t\tassertThat(\n\t\t\t\tfilter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getBufferLength())\n\t\t\t.isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherBufferLengthShouldSetBufferLengthToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.buffer-length.spring=3\"));\n\t\tassertThat(\n\t\t\t\tfilter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getBufferLength())\n\t\t\t.isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid configureWhenHasHigherBufferLengthAndLowerShouldSetBufferLengthToLower() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(\n\t\t\t\tcreateProperties(\"distribution.buffer-length.spring=2\", \"distribution.buffer-length.spring.boot=3\"));\n\t\tassertThat(\n\t\t\t\tfilter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getBufferLength())\n\t\t\t.isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid configureWhenAllBufferLengthSetShouldSetBufferLengthToValue() {\n\t\tPropertiesMeterFilter filter = new PropertiesMeterFilter(createProperties(\"distribution.buffer-length.all=3\"));\n\t\tassertThat(\n\t\t\t\tfilter.configure(createMeterId(\"spring.boot\"), DistributionStatisticConfig.DEFAULT).getBufferLength())\n\t\t\t.isEqualTo(3);\n\t}\n\n\tprivate Id createMeterId(String name) {\n\t\tMeter.Type meterType = Type.TIMER;\n\t\treturn createMeterId(name, meterType);\n\t}\n\n\tprivate Id createMeterId(String name, Meter.Type meterType) {\n\t\tTestMeterRegistry registry = new TestMeterRegistry();\n\t\treturn Meter.builder(name, meterType, Collections.emptyList()).register(registry).getId();\n\t}\n\n\tprivate MetricsProperties createProperties(String... properties) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tTestPropertyValues.of(properties).applyTo(environment);\n\t\tBinder binder = Binder.get(environment);\n\t\treturn binder.bind(\"\", Bindable.of(MetricsProperties.class)).orElseGet(MetricsProperties::new);\n\t}\n\n\tstatic class TestMeterRegistry extends SimpleMeterRegistry {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/ServiceLevelObjectiveBoundaryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.Meter.Type;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServiceLevelObjectiveBoundary}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass ServiceLevelObjectiveBoundaryTests {\n\n\t@Test\n\tvoid getValueForTimerWhenFromLongShouldReturnMsToNanosValue() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(123L);\n\t\tassertThat(slo.getValue(Type.TIMER)).isEqualTo(123000000);\n\t}\n\n\t@Test\n\tvoid getValueForTimerWhenFromNumberStringShouldMsToNanosValue() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(\"123\");\n\t\tassertThat(slo.getValue(Type.TIMER)).isEqualTo(123000000);\n\t}\n\n\t@Test\n\tvoid getValueForTimerWhenFromMillisecondDurationStringShouldReturnDurationNanos() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(\"123ms\");\n\t\tassertThat(slo.getValue(Type.TIMER)).isEqualTo(123000000);\n\t}\n\n\t@Test\n\tvoid getValueForTimerWhenFromDaysDurationStringShouldReturnDurationNanos() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(\"1d\");\n\t\tassertThat(slo.getValue(Type.TIMER)).isEqualTo(Duration.ofDays(1).toNanos());\n\t}\n\n\t@Test\n\tvoid getValueForDistributionSummaryWhenFromDoubleShouldReturnDoubleValue() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(123.42);\n\t\tassertThat(slo.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42);\n\t}\n\n\t@Test\n\tvoid getValueForDistributionSummaryWhenFromStringShouldReturnDoubleValue() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(\"123.42\");\n\t\tassertThat(slo.getValue(Type.DISTRIBUTION_SUMMARY)).isEqualTo(123.42);\n\t}\n\n\t@Test\n\tvoid getValueForDistributionSummaryWhenFromDurationShouldReturnNull() {\n\t\tServiceLevelObjectiveBoundary slo = ServiceLevelObjectiveBoundary.valueOf(\"123ms\");\n\t\tassertThat(slo.getValue(Type.DISTRIBUTION_SUMMARY)).isNull();\n\t}\n\n\t@Test\n\tvoid shouldRegisterRuntimeHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ServiceLevelObjectiveBoundary.ServiceLevelObjectiveBoundaryHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tReflectionUtils.doWithLocalMethods(ServiceLevelObjectiveBoundary.class, (method) -> {\n\t\t\tif (\"valueOf\".equals(method.getName())) {\n\t\t\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(method)).accepts(runtimeHints);\n\t\t\t}\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ConditionalOnEnabledMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConditionalOnEnabledMetricsExport}.\n *\n * @author Chris Bono\n */\nclass ConditionalOnEnabledMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, SimpleMetricsExportAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid exporterIsEnabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"simpleMeterRegistry\"));\n\t}\n\n\t@Test\n\tvoid exporterCanBeSpecificallyDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.simple.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"simpleMeterRegistry\"));\n\t}\n\n\t@Test\n\tvoid exporterCanBeGloballyDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"simpleMeterRegistry\"));\n\t}\n\n\t@Test\n\tvoid exporterCanBeGloballyDisabledWithSpecificOverride() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\",\n\t\t\t\t\t\"management.simple.metrics.export.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"simpleMeterRegistry\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/AppOpticsMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport io.micrometer.appoptics.AppOpticsConfig;\nimport io.micrometer.appoptics.AppOpticsMeterRegistry;\nimport io.micrometer.core.instrument.Clock;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AppOpticsMetricsExportAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass AppOpticsMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AppOpticsMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(AppOpticsMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withPropertyValues(\"management.appoptics.metrics.export.api-token=abcde\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AppOpticsMeterRegistry.class)\n\t\t\t\t.hasSingleBean(AppOpticsConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AppOpticsMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(AppOpticsConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.appoptics.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AppOpticsMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(AppOpticsConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AppOpticsMeterRegistry.class)\n\t\t\t\t.hasSingleBean(AppOpticsConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"management.appoptics.metrics.export.api-token=abcde\")\n\t\t\t.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AppOpticsMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(AppOpticsConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withPropertyValues(\"management.appoptics.metrics.export.api-token=abcde\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tAppOpticsMeterRegistry registry = context.getBean(AppOpticsMeterRegistry.class);\n\t\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tAppOpticsConfig customConfig() {\n\t\t\treturn (key) -> \"appoptics.apiToken\".equals(key) ? \"abcde\" : null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tAppOpticsMeterRegistry customRegistry(AppOpticsConfig config, Clock clock) {\n\t\t\treturn new AppOpticsMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/AppOpticsPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AppOpticsPropertiesConfigAdapter}.\n *\n * @author Stephane Nicoll\n */\nclass AppOpticsPropertiesConfigAdapterTests\n\t\textends StepRegistryPropertiesConfigAdapterTests<AppOpticsProperties, AppOpticsPropertiesConfigAdapter> {\n\n\tAppOpticsPropertiesConfigAdapterTests() {\n\t\tsuper(AppOpticsPropertiesConfigAdapter.class);\n\t}\n\n\t@Override\n\tprotected AppOpticsProperties createProperties() {\n\t\treturn new AppOpticsProperties();\n\t}\n\n\t@Override\n\tprotected AppOpticsPropertiesConfigAdapter createConfigAdapter(AppOpticsProperties properties) {\n\t\treturn new AppOpticsPropertiesConfigAdapter(properties);\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tAppOpticsProperties properties = createProperties();\n\t\tproperties.setUri(\"https://appoptics.example.com/v1/measurements\");\n\t\tassertThat(createConfigAdapter(properties).uri()).isEqualTo(\"https://appoptics.example.com/v1/measurements\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesApiTokenIsSetAdapterApiTokenReturnsIt() {\n\t\tAppOpticsProperties properties = createProperties();\n\t\tproperties.setApiToken(\"ABC123\");\n\t\tassertThat(createConfigAdapter(properties).apiToken()).isEqualTo(\"ABC123\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesHostTagIsSetAdapterHostTagReturnsIt() {\n\t\tAppOpticsProperties properties = createProperties();\n\t\tproperties.setHostTag(\"node\");\n\t\tassertThat(createConfigAdapter(properties).hostTag()).isEqualTo(\"node\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesFloorTimesIsSetAdapterFloorTimesReturnsIt() {\n\t\tAppOpticsProperties properties = createProperties();\n\t\tproperties.setFloorTimes(true);\n\t\tassertThat(createConfigAdapter(properties).floorTimes()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/appoptics/AppOpticsPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.appoptics;\n\nimport io.micrometer.appoptics.AppOpticsConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AppOpticsProperties}.\n *\n * @author Stephane Nicoll\n */\nclass AppOpticsPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tAppOpticsProperties properties = new AppOpticsProperties();\n\t\tAppOpticsConfig config = (key) -> null;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getUri()).isEqualToIgnoringWhitespace(config.uri());\n\t\tassertThat(properties.getHostTag()).isEqualToIgnoringWhitespace(config.hostTag());\n\t\tassertThat(properties.isFloorTimes()).isEqualTo(config.floorTimes());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/AtlasMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport com.netflix.spectator.atlas.AtlasConfig;\nimport io.micrometer.atlas.AtlasMeterRegistry;\nimport io.micrometer.core.instrument.Clock;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AtlasMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass AtlasMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(AtlasMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(AtlasMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AtlasMeterRegistry.class)\n\t\t\t\t.hasSingleBean(AtlasConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AtlasMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(AtlasConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.atlas.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AtlasMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(AtlasConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AtlasMeterRegistry.class)\n\t\t\t\t.hasSingleBean(AtlasConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AtlasMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(AtlasConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tAtlasMeterRegistry registry = context.getBean(AtlasMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tAtlasConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tAtlasMeterRegistry customRegistry(AtlasConfig config, Clock clock) {\n\t\t\treturn new AtlasMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/AtlasPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AtlasPropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass AtlasPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<AtlasProperties, AtlasPropertiesConfigAdapter> {\n\n\tAtlasPropertiesConfigAdapterTests() {\n\t\tsuper(AtlasPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setStep(Duration.ofMinutes(15));\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).step()).isEqualTo(Duration.ofMinutes(15));\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnabledIsSetAdapterEnabledReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setEnabled(false);\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).enabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesConnectTimeoutIsSetAdapterConnectTimeoutReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setConnectTimeout(Duration.ofSeconds(12));\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).connectTimeout()).isEqualTo(Duration.ofSeconds(12));\n\t}\n\n\t@Test\n\tvoid whenPropertiesReadTimeoutIsSetAdapterReadTimeoutReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setReadTimeout(Duration.ofSeconds(42));\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).readTimeout()).isEqualTo(Duration.ofSeconds(42));\n\t}\n\n\t@Test\n\tvoid whenPropertiesNumThreadsIsSetAdapterNumThreadsReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setNumThreads(8);\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).numThreads()).isEqualTo(8);\n\t}\n\n\t@Test\n\tvoid whenPropertiesBatchSizeIsSetAdapterBatchSizeReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setBatchSize(10042);\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).batchSize()).isEqualTo(10042);\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setUri(\"https://atlas.example.com\");\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).uri()).isEqualTo(\"https://atlas.example.com\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesLwcEnabledIsSetAdapterLwcEnabledReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setLwcEnabled(true);\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).lwcEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenPropertiesConfigRefreshFrequencyIsSetAdapterConfigRefreshFrequencyReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setConfigRefreshFrequency(Duration.ofMinutes(5));\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).configRefreshFrequency())\n\t\t\t.isEqualTo(Duration.ofMinutes(5));\n\t}\n\n\t@Test\n\tvoid whenPropertiesConfigTimeToLiveIsSetAdapterConfigTTLReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setConfigTimeToLive(Duration.ofMinutes(6));\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).configTTL()).isEqualTo(Duration.ofMinutes(6));\n\t}\n\n\t@Test\n\tvoid whenPropertiesConfigUriIsSetAdapterConfigUriReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setConfigUri(\"https://atlas.example.com/config\");\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).configUri())\n\t\t\t.isEqualTo(\"https://atlas.example.com/config\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesEvalUriIsSetAdapterEvalUriReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setEvalUri(\"https://atlas.example.com/evaluate\");\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).evalUri())\n\t\t\t.isEqualTo(\"https://atlas.example.com/evaluate\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesLwcStepIsSetAdapterLwcStepReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setLwcStep(Duration.ofSeconds(30));\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).lwcStep()).isEqualTo(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid whenPropertiesLwcIgnorePublishStepIsSetAdapterLwcIgnorePublishStepReturnsIt() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tproperties.setLwcIgnorePublishStep(false);\n\t\tassertThat(new AtlasPropertiesConfigAdapter(properties).lwcIgnorePublishStep()).isFalse();\n\t}\n\n\t@Test\n\t@Override\n\tprotected void adapterOverridesAllConfigMethods() {\n\t\tadapterOverridesAllConfigMethodsExcept(\"autoStart\", \"commonTags\", \"debugRegistry\", \"publisher\", \"rollupPolicy\",\n\t\t\t\t\"validTagCharacters\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/atlas/AtlasPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.atlas;\n\nimport com.netflix.spectator.atlas.AtlasConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AtlasProperties}.\n *\n * @author Stephane Nicoll\n */\nclass AtlasPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tAtlasProperties properties = new AtlasProperties();\n\t\tAtlasConfig config = (key) -> null;\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t\tassertThat(properties.isEnabled()).isEqualTo(config.enabled());\n\t\tassertThat(properties.getConnectTimeout()).isEqualTo(config.connectTimeout());\n\t\tassertThat(properties.getReadTimeout()).isEqualTo(config.readTimeout());\n\t\tassertThat(properties.getNumThreads()).isEqualTo(config.numThreads());\n\t\tassertThat(properties.getBatchSize()).isEqualTo(config.batchSize());\n\t\tassertThat(properties.getUri()).isEqualTo(config.uri());\n\t\tassertThat(properties.getMeterTimeToLive()).isEqualTo(config.meterTTL());\n\t\tassertThat(properties.isLwcEnabled()).isEqualTo(config.lwcEnabled());\n\t\tassertThat(properties.getLwcStep()).isEqualTo(config.lwcStep());\n\t\tassertThat(properties.isLwcIgnorePublishStep()).isEqualTo(config.lwcIgnorePublishStep());\n\t\tassertThat(properties.getConfigRefreshFrequency()).isEqualTo(config.configRefreshFrequency());\n\t\tassertThat(properties.getConfigTimeToLive()).isEqualTo(config.configTTL());\n\t\tassertThat(properties.getConfigUri()).isEqualTo(config.configUri());\n\t\tassertThat(properties.getEvalUri()).isEqualTo(config.evalUri());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/DatadogMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.datadog.DatadogConfig;\nimport io.micrometer.datadog.DatadogMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DatadogMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass DatadogMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DatadogMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(DatadogMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid failsWithoutAnApiKey() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.datadog.metrics.export.api-key=abcde\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DatadogMeterRegistry.class)\n\t\t\t\t.hasSingleBean(DatadogConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DatadogMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(DatadogConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.datadog.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DatadogMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(DatadogConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DatadogMeterRegistry.class)\n\t\t\t\t.hasSingleBean(DatadogConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.datadog.metrics.export.api-key=abcde\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DatadogMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(DatadogConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.datadog.metrics.export.api-key=abcde\")\n\t\t\t.run((context) -> {\n\t\t\t\tDatadogMeterRegistry registry = context.getBean(DatadogMeterRegistry.class);\n\t\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tDatadogConfig customConfig() {\n\t\t\treturn (key) -> {\n\t\t\t\tif (\"datadog.apiKey\".equals(key)) {\n\t\t\t\t\treturn \"12345\";\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tDatadogMeterRegistry customRegistry(DatadogConfig config, Clock clock) {\n\t\t\treturn new DatadogMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/DatadogPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DatadogPropertiesConfigAdapter}.\n *\n * @author Stephane Nicoll\n * @author Mirko Sobeck\n */\nclass DatadogPropertiesConfigAdapterTests\n\t\textends StepRegistryPropertiesConfigAdapterTests<DatadogProperties, DatadogPropertiesConfigAdapter> {\n\n\tDatadogPropertiesConfigAdapterTests() {\n\t\tsuper(DatadogPropertiesConfigAdapter.class);\n\t}\n\n\t@Override\n\tprotected DatadogProperties createProperties() {\n\t\treturn new DatadogProperties();\n\t}\n\n\t@Override\n\tprotected DatadogPropertiesConfigAdapter createConfigAdapter(DatadogProperties properties) {\n\t\treturn new DatadogPropertiesConfigAdapter(properties);\n\t}\n\n\t@Test\n\tvoid whenPropertiesApiKeyIsSetAdapterApiKeyReturnsIt() {\n\t\tDatadogProperties properties = createProperties();\n\t\tproperties.setApiKey(\"my-api-key\");\n\t\tassertThat(createConfigAdapter(properties).apiKey()).isEqualTo(\"my-api-key\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesApplicationKeyIsSetAdapterApplicationKeyReturnsIt() {\n\t\tDatadogProperties properties = createProperties();\n\t\tproperties.setApplicationKey(\"my-application-key\");\n\t\tassertThat(createConfigAdapter(properties).applicationKey()).isEqualTo(\"my-application-key\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesDescriptionsIsSetAdapterDescriptionsReturnsIt() {\n\t\tDatadogProperties properties = createProperties();\n\t\tproperties.setDescriptions(false);\n\t\tassertThat(createConfigAdapter(properties).descriptions()).isEqualTo(false);\n\t}\n\n\t@Test\n\tvoid whenPropertiesHostTagIsSetAdapterHostTagReturnsIt() {\n\t\tDatadogProperties properties = createProperties();\n\t\tproperties.setHostTag(\"waldo\");\n\t\tassertThat(createConfigAdapter(properties).hostTag()).isEqualTo(\"waldo\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tDatadogProperties properties = createProperties();\n\t\tproperties.setUri(\"https://app.example.com/api/v1/series\");\n\t\tassertThat(createConfigAdapter(properties).uri()).isEqualTo(\"https://app.example.com/api/v1/series\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/datadog/DatadogPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.datadog;\n\nimport io.micrometer.datadog.DatadogConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DatadogProperties}.\n *\n * @author Stephane Nicoll\n */\nclass DatadogPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tDatadogProperties properties = new DatadogProperties();\n\t\tDatadogConfig config = (key) -> null;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.isDescriptions()).isEqualTo(config.descriptions());\n\t\tassertThat(properties.getHostTag()).isEqualTo(config.hostTag());\n\t\tassertThat(properties.getUri()).isEqualTo(config.uri());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/DynatraceMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport java.util.function.Function;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.dynatrace.DynatraceConfig;\nimport io.micrometer.dynatrace.DynatraceMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DynatraceMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass DynatraceMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DynatraceMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(DynatraceMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid failsWithADeviceIdWithoutAUri() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.dynatrace.metrics.export.v1.device-id:dev-1\")\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.with(v1MandatoryProperties())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DynatraceMeterRegistry.class)\n\t\t\t\t.hasSingleBean(DynatraceConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DynatraceMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(DynatraceConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.dynatrace.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DynatraceMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(DynatraceConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DynatraceMeterRegistry.class)\n\t\t\t\t.hasSingleBean(DynatraceConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.with(v1MandatoryProperties())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DynatraceMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(DynatraceConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryForV1ApiWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.with(v1MandatoryProperties())\n\t\t\t.run((context) -> {\n\t\t\t\tDynatraceMeterRegistry registry = context.getBean(DynatraceMeterRegistry.class);\n\t\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryForV2ApiWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tDynatraceMeterRegistry registry = context.getBean(DynatraceMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\tprivate Function<ApplicationContextRunner, ApplicationContextRunner> v1MandatoryProperties() {\n\t\treturn (runner) -> runner.withPropertyValues(\n\t\t\t\t\"management.dynatrace.metrics.export.uri=https://dynatrace.example.com\",\n\t\t\t\t\"management.dynatrace.metrics.export.api-token=abcde\",\n\t\t\t\t\"management.dynatrace.metrics.export.device-id=test\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tDynatraceConfig customConfig() {\n\t\t\treturn (key) -> switch (key) {\n\t\t\t\tcase \"dynatrace.uri\" -> \"https://dynatrace.example.com\";\n\t\t\t\tcase \"dynatrace.apiToken\" -> \"abcde\";\n\t\t\t\tcase \"dynatrace.deviceId\" -> \"test\";\n\t\t\t\tdefault -> null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tDynatraceMeterRegistry customRegistry(DynatraceConfig config, Clock clock) {\n\t\t\treturn new DynatraceMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/DynatracePropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport java.util.HashMap;\n\nimport io.micrometer.dynatrace.DynatraceApiVersion;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DynatracePropertiesConfigAdapter}.\n *\n * @author Andy Wilkinson\n * @author Georg Pirklbauer\n */\nclass DynatracePropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<DynatraceProperties, DynatracePropertiesConfigAdapter> {\n\n\tDynatracePropertiesConfigAdapterTests() {\n\t\tsuper(DynatracePropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.setUri(\"https://dynatrace.example.com\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).uri()).isEqualTo(\"https://dynatrace.example.com\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesApiTokenIsSetAdapterApiTokenReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.setApiToken(\"123ABC\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).apiToken()).isEqualTo(\"123ABC\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid whenPropertiesV1DeviceIdIsSetAdapterDeviceIdReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV1().setDeviceId(\"dev-1\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).deviceId()).isEqualTo(\"dev-1\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid whenPropertiesV1TechnologyTypeIsSetAdapterTechnologyTypeReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV1().setTechnologyType(\"tech-1\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).technologyType()).isEqualTo(\"tech-1\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid whenPropertiesV1GroupIsSetAdapterGroupReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV1().setGroup(\"group-1\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).group()).isEqualTo(\"group-1\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid whenV1DeviceIdIsSetThenAdapterApiVersionIsV1() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV1().setDeviceId(\"dev-1\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).apiVersion()).isSameAs(DynatraceApiVersion.V1);\n\t}\n\n\t@Test\n\tvoid whenDeviceIdIsNotSetThenAdapterApiVersionIsV2() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).apiVersion()).isSameAs(DynatraceApiVersion.V2);\n\t}\n\n\t@Test\n\tvoid whenPropertiesMetricKeyPrefixIsSetAdapterMetricKeyPrefixReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV2().setMetricKeyPrefix(\"my.prefix\");\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).metricKeyPrefix()).isEqualTo(\"my.prefix\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnrichWithOneAgentMetadataIsSetAdapterEnrichWithOneAgentMetadataReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV2().setEnrichWithDynatraceMetadata(true);\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).enrichWithDynatraceMetadata()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenPropertiesUseDynatraceInstrumentsIsSetAdapterUseDynatraceInstrumentsReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tproperties.getV2().setUseDynatraceSummaryInstruments(false);\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).useDynatraceSummaryInstruments()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesDefaultDimensionsIsSetAdapterDefaultDimensionsReturnsIt() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tHashMap<String, String> defaultDimensions = new HashMap<>();\n\t\tdefaultDimensions.put(\"dim1\", \"value1\");\n\t\tdefaultDimensions.put(\"dim2\", \"value2\");\n\t\tproperties.getV2().setDefaultDimensions(defaultDimensions);\n\t\tassertThat(new DynatracePropertiesConfigAdapter(properties).defaultDimensions())\n\t\t\t.containsExactlyEntriesOf(defaultDimensions);\n\t}\n\n\t@Test\n\tvoid defaultValues() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tassertThat(properties.getApiToken()).isNull();\n\t\tassertThat(properties.getUri()).isNull();\n\t\tassertThat(properties.getV2().getMetricKeyPrefix()).isNull();\n\t\tassertThat(properties.getV2().isEnrichWithDynatraceMetadata()).isTrue();\n\t\tassertThat(properties.getV2().getDefaultDimensions()).isNull();\n\t\tassertThat(properties.getV2().isUseDynatraceSummaryInstruments()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(forRemoval = true, since = \"4.1.0\")\n\tvoid v1DefaultValues() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tassertThat(properties.getV1().getDeviceId()).isNull();\n\t\tassertThat(properties.getV1().getTechnologyType()).isEqualTo(\"java\");\n\t\tassertThat(properties.getV1().getGroup()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/dynatrace/DynatracePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.dynatrace;\n\nimport io.micrometer.dynatrace.DynatraceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DynatraceProperties}.\n *\n * @author Andy Wilkinson\n */\nclass DynatracePropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tDynatraceConfig config = (key) -> null;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getV2().isUseDynatraceSummaryInstruments())\n\t\t\t.isEqualTo(config.useDynatraceSummaryInstruments());\n\t\tassertThat(properties.getV2().isExportMeterMetadata()).isEqualTo(config.exportMeterMetadata());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tvoid v1DefaultValuesAreConsistent() {\n\t\tDynatraceProperties properties = new DynatraceProperties();\n\t\tDynatraceConfig config = (key) -> null;\n\t\tassertThat(properties.getV1().getTechnologyType()).isEqualTo(config.technologyType());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/ElasticMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.elastic.ElasticConfig;\nimport io.micrometer.elastic.ElasticMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ElasticMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ElasticMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ElasticMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ElasticMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticMeterRegistry.class)\n\t\t\t\t.hasSingleBean(ElasticConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ElasticMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(ElasticConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.elastic.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ElasticMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(ElasticConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticMeterRegistry.class)\n\t\t\t\t.hasSingleBean(ElasticConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ElasticMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(ElasticConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tElasticMeterRegistry registry = context.getBean(ElasticMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiKeyCredentialsIsMutuallyExclusiveWithUserName() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.elastic.metrics.export.api-key-credentials:secret\",\n\t\t\t\t\t\"management.elastic.metrics.export.user-name:alice\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Test\n\tvoid apiKeyCredentialsIsMutuallyExclusiveWithPassword() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.elastic.metrics.export.api-key-credentials:secret\",\n\t\t\t\t\t\"management.elastic.metrics.export.password:secret\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tElasticConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tElasticMeterRegistry customRegistry(ElasticConfig config, Clock clock) {\n\t\t\treturn new ElasticMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/ElasticPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ElasticPropertiesConfigAdapter}.\n *\n * @author Andy Wilkinson\n */\nclass ElasticPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<ElasticProperties, ElasticPropertiesConfigAdapter> {\n\n\tElasticPropertiesConfigAdapterTests() {\n\t\tsuper(ElasticPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesHostsIsSetAdapterHostsReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setHost(\"https://elastic.example.com\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).host()).isEqualTo(\"https://elastic.example.com\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesIndexIsSetAdapterIndexReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setIndex(\"test-metrics\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).index()).isEqualTo(\"test-metrics\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesIndexDateFormatIsSetAdapterIndexDateFormatReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setIndexDateFormat(\"yyyy\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).indexDateFormat()).isEqualTo(\"yyyy\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesIndexDateSeparatorIsSetAdapterIndexDateSeparatorReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setIndexDateSeparator(\"*\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).indexDateSeparator()).isEqualTo(\"*\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesTimestampFieldNameIsSetAdapterTimestampFieldNameReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setTimestampFieldName(\"@test\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).timestampFieldName()).isEqualTo(\"@test\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesAutoCreateIndexIsSetAdapterAutoCreateIndexReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setAutoCreateIndex(false);\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).autoCreateIndex()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesUserNameIsSetAdapterUserNameReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setUserName(\"alice\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).userName()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesPasswordIsSetAdapterPasswordReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setPassword(\"secret\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).password()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesPipelineIsSetAdapterPipelineReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setPipeline(\"testPipeline\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).pipeline()).isEqualTo(\"testPipeline\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesApiKeyCredentialsIsSetAdapterPipelineReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setApiKeyCredentials(\"secret\");\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).apiKeyCredentials()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnableSourceIsSetAdapterEnableSourceReturnsIt() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tproperties.setEnableSource(true);\n\t\tassertThat(new ElasticPropertiesConfigAdapter(properties).enableSource()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/elastic/ElasticPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.elastic;\n\nimport io.micrometer.elastic.ElasticConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ElasticProperties}.\n *\n * @author Andy Wilkinson\n */\nclass ElasticPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tElasticProperties properties = new ElasticProperties();\n\t\tElasticConfig config = ElasticConfig.DEFAULT;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getHost()).isEqualTo(config.host());\n\t\tassertThat(properties.getIndex()).isEqualTo(config.index());\n\t\tassertThat(properties.getIndexDateFormat()).isEqualTo(config.indexDateFormat());\n\t\tassertThat(properties.getIndexDateSeparator()).isEqualTo(config.indexDateSeparator());\n\t\tassertThat(properties.getPassword()).isEqualTo(config.password());\n\t\tassertThat(properties.getTimestampFieldName()).isEqualTo(config.timestampFieldName());\n\t\tassertThat(properties.getUserName()).isEqualTo(config.userName());\n\t\tassertThat(properties.isAutoCreateIndex()).isEqualTo(config.autoCreateIndex());\n\t\tassertThat(properties.getPipeline()).isEqualTo(config.pipeline());\n\t\tassertThat(properties.getApiKeyCredentials()).isEqualTo(config.apiKeyCredentials());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/GangliaMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.ganglia.GangliaConfig;\nimport io.micrometer.ganglia.GangliaMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GangliaMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass GangliaMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GangliaMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(GangliaMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GangliaMeterRegistry.class)\n\t\t\t\t.hasSingleBean(GangliaConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GangliaMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(GangliaConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.ganglia.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GangliaMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(GangliaConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GangliaMeterRegistry.class)\n\t\t\t\t.hasSingleBean(GangliaConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GangliaMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(GangliaConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tGangliaMeterRegistry registry = context.getBean(GangliaMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tGangliaConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tGangliaMeterRegistry customRegistry(GangliaConfig config, Clock clock) {\n\t\t\treturn new GangliaMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/GangliaPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport info.ganglia.gmetric4j.gmetric.GMetric.UDPAddressingMode;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GangliaPropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass GangliaPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<GangliaProperties, GangliaPropertiesConfigAdapter> {\n\n\tGangliaPropertiesConfigAdapterTests() {\n\t\tsuper(GangliaPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnabledIsSetAdapterEnabledReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setEnabled(false);\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).enabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setStep(Duration.ofMinutes(15));\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).step()).isEqualTo(Duration.ofMinutes(15));\n\t}\n\n\t@Test\n\tvoid whenPropertiesDurationUnitsIsSetAdapterDurationUnitsReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setDurationUnits(TimeUnit.MINUTES);\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).durationUnits()).isEqualTo(TimeUnit.MINUTES);\n\t}\n\n\t@Test\n\tvoid whenPropertiesAddressingModeIsSetAdapterAddressingModeReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setAddressingMode(UDPAddressingMode.UNICAST);\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).addressingMode())\n\t\t\t.isEqualTo(UDPAddressingMode.UNICAST);\n\t}\n\n\t@Test\n\tvoid whenPropertiesTimeToLiveIsSetAdapterTtlReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setTimeToLive(2);\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).ttl()).isEqualTo(2);\n\t}\n\n\t@Test\n\tvoid whenPropertiesHostIsSetAdapterHostReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setHost(\"node\");\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).host()).isEqualTo(\"node\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesPortIsSetAdapterPortReturnsIt() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tproperties.setPort(4242);\n\t\tassertThat(new GangliaPropertiesConfigAdapter(properties).port()).isEqualTo(4242);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/ganglia/GangliaPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.ganglia;\n\nimport io.micrometer.ganglia.GangliaConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GangliaProperties}.\n *\n * @author Stephane Nicoll\n */\nclass GangliaPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tGangliaProperties properties = new GangliaProperties();\n\t\tGangliaConfig config = GangliaConfig.DEFAULT;\n\t\tassertThat(properties.isEnabled()).isEqualTo(config.enabled());\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t\tassertThat(properties.getDurationUnits()).isEqualTo(config.durationUnits());\n\t\tassertThat(properties.getAddressingMode()).isEqualTo(config.addressingMode());\n\t\tassertThat(properties.getTimeToLive()).isEqualTo(config.ttl());\n\t\tassertThat(properties.getHost()).isEqualTo(config.host());\n\t\tassertThat(properties.getPort()).isEqualTo(config.port());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/GraphiteMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.graphite.GraphiteConfig;\nimport io.micrometer.graphite.GraphiteMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraphiteMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass GraphiteMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(GraphiteMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(GraphiteMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresUseTagsAsPrefix() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.graphite.metrics.export.tags-as-prefix=app\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GraphiteMeterRegistry.class);\n\t\t\t\tGraphiteMeterRegistry registry = context.getBean(GraphiteMeterRegistry.class);\n\t\t\t\tregistry.counter(\"test.count\", Tags.of(\"app\", \"myapp\"));\n\t\t\t\tassertThat(registry.getDropwizardRegistry().getMeters()).containsOnlyKeys(\"myapp.testCount\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresWithTagsAsPrefixCanBeDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.graphite.metrics.export.tags-as-prefix=app\",\n\t\t\t\t\t\"management.graphite.metrics.export.graphite-tags-enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(GraphiteMeterRegistry.class);\n\t\t\t\tGraphiteMeterRegistry registry = context.getBean(GraphiteMeterRegistry.class);\n\t\t\t\tregistry.counter(\"test.count\", Tags.of(\"app\", \"myapp\"));\n\t\t\t\tassertThat(registry.getDropwizardRegistry().getMeters()).containsOnlyKeys(\"test.count;app=myapp\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GraphiteMeterRegistry.class)\n\t\t\t\t.hasSingleBean(GraphiteConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GraphiteMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(GraphiteConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.graphite.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(GraphiteMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(GraphiteConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GraphiteMeterRegistry.class)\n\t\t\t\t.hasSingleBean(GraphiteConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(GraphiteMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(GraphiteConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tGraphiteMeterRegistry registry = context.getBean(GraphiteMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tGraphiteConfig customConfig() {\n\t\t\treturn (key) -> {\n\t\t\t\tif (\"Graphite.apiKey\".equals(key)) {\n\t\t\t\t\treturn \"12345\";\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tGraphiteMeterRegistry customRegistry(GraphiteConfig config, Clock clock) {\n\t\t\treturn new GraphiteMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/GraphitePropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.graphite.GraphiteProtocol;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraphitePropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass GraphitePropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<GraphiteProperties, GraphitePropertiesConfigAdapter> {\n\n\tGraphitePropertiesConfigAdapterTests() {\n\t\tsuper(GraphitePropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnabledIsSetAdapterEnabledReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setEnabled(false);\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).enabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setStep(Duration.ofMinutes(15));\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).step()).isEqualTo(Duration.ofMinutes(15));\n\t}\n\n\t@Test\n\tvoid whenPropertiesRateUnitsIsSetAdapterRateUnitsReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setRateUnits(TimeUnit.MINUTES);\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).rateUnits()).isEqualTo(TimeUnit.MINUTES);\n\t}\n\n\t@Test\n\tvoid whenPropertiesDurationUnitsIsSetAdapterDurationUnitsReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setDurationUnits(TimeUnit.MINUTES);\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).durationUnits()).isEqualTo(TimeUnit.MINUTES);\n\t}\n\n\t@Test\n\tvoid whenPropertiesHostIsSetAdapterHostReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setHost(\"node\");\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).host()).isEqualTo(\"node\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesPortIsSetAdapterPortReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setPort(4242);\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).port()).isEqualTo(4242);\n\t}\n\n\t@Test\n\tvoid whenPropertiesProtocolIsSetAdapterProtocolReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setProtocol(GraphiteProtocol.UDP);\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).protocol()).isEqualTo(GraphiteProtocol.UDP);\n\t}\n\n\t@Test\n\tvoid whenPropertiesGraphiteTagsEnabledIsSetAdapterGraphiteTagsEnabledReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setGraphiteTagsEnabled(true);\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).graphiteTagsEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenPropertiesTagsAsPrefixIsSetAdapterTagsAsPrefixReturnsIt() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setTagsAsPrefix(new String[] { \"worker\" });\n\t\tassertThat(new GraphitePropertiesConfigAdapter(properties).tagsAsPrefix()).isEqualTo(new String[] { \"worker\" });\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/graphite/GraphitePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.graphite;\n\nimport io.micrometer.graphite.GraphiteConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GraphiteProperties}.\n *\n * @author Stephane Nicoll\n */\nclass GraphitePropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tGraphiteConfig config = GraphiteConfig.DEFAULT;\n\t\tassertThat(properties.isEnabled()).isEqualTo(config.enabled());\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t\tassertThat(properties.getRateUnits()).isEqualTo(config.rateUnits());\n\t\tassertThat(properties.getDurationUnits()).isEqualTo(config.durationUnits());\n\t\tassertThat(properties.getHost()).isEqualTo(config.host());\n\t\tassertThat(properties.getPort()).isEqualTo(config.port());\n\t\tassertThat(properties.getProtocol()).isEqualTo(config.protocol());\n\t\tassertThat(properties.getGraphiteTagsEnabled()).isEqualTo(config.graphiteTagsEnabled());\n\t\tassertThat(properties.getTagsAsPrefix()).isEqualTo(config.tagsAsPrefix());\n\t}\n\n\t@Test\n\tvoid graphiteTagsAreDisabledIfTagsAsPrefixIsSet() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setTagsAsPrefix(new String[] { \"app\" });\n\t\tassertThat(properties.getGraphiteTagsEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid graphiteTagsCanBeEnabledEvenIfTagsAsPrefixIsSet() {\n\t\tGraphiteProperties properties = new GraphiteProperties();\n\t\tproperties.setGraphiteTagsEnabled(true);\n\t\tproperties.setTagsAsPrefix(new String[] { \"app\" });\n\t\tassertThat(properties.getGraphiteTagsEnabled()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/HumioMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.humio.HumioConfig;\nimport io.micrometer.humio.HumioMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HumioMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass HumioMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HumioMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HumioMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HumioMeterRegistry.class)\n\t\t\t\t.hasSingleBean(HumioConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HumioMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(HumioConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.humio.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HumioMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(HumioConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HumioMeterRegistry.class)\n\t\t\t\t.hasSingleBean(HumioConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HumioMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(HumioConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tHumioMeterRegistry registry = context.getBean(HumioMeterRegistry.class);\n\t\t\tnew JvmMemoryMetrics().bindTo(registry);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tHumioConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tHumioMeterRegistry customRegistry(HumioConfig config, Clock clock) {\n\t\t\treturn new HumioMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/HumioPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HumioPropertiesConfigAdapter}.\n *\n * @author Andy Wilkinson\n */\nclass HumioPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<HumioProperties, HumioPropertiesConfigAdapter> {\n\n\tHumioPropertiesConfigAdapterTests() {\n\t\tsuper(HumioPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenApiTokenIsSetAdapterApiTokenReturnsIt() {\n\t\tHumioProperties properties = new HumioProperties();\n\t\tproperties.setApiToken(\"ABC123\");\n\t\tassertThat(new HumioPropertiesConfigAdapter(properties).apiToken()).isEqualTo(\"ABC123\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesTagsIsSetAdapterTagsReturnsIt() {\n\t\tHumioProperties properties = new HumioProperties();\n\t\tproperties.setTags(Collections.singletonMap(\"name\", \"test\"));\n\t\tassertThat(new HumioPropertiesConfigAdapter(properties).tags())\n\t\t\t.isEqualTo(Collections.singletonMap(\"name\", \"test\"));\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tHumioProperties properties = new HumioProperties();\n\t\tproperties.setUri(\"https://humio.example.com\");\n\t\tassertThat(new HumioPropertiesConfigAdapter(properties).uri()).isEqualTo(\"https://humio.example.com\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/humio/HumioPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.humio;\n\nimport io.micrometer.humio.HumioConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link HumioProperties}.\n *\n * @author Andy Wilkinson\n */\nclass HumioPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tHumioProperties properties = new HumioProperties();\n\t\tHumioConfig config = (key) -> null;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getApiToken()).isEqualTo(config.apiToken());\n\t\tassertThat(properties.getTags()).isEmpty();\n\t\tassertThat(config.tags()).isNull();\n\t\tassertThat(properties.getUri()).isEqualTo(config.uri());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/InfluxMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.influx.InfluxConfig;\nimport io.micrometer.influx.InfluxMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InfluxMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass InfluxMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(InfluxMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(InfluxMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(InfluxMeterRegistry.class)\n\t\t\t\t.hasSingleBean(InfluxConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(InfluxMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(InfluxConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.influx.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(InfluxMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(InfluxConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(InfluxMeterRegistry.class)\n\t\t\t\t.hasSingleBean(InfluxConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(InfluxMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(InfluxConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tInfluxMeterRegistry registry = context.getBean(InfluxMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tInfluxConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tInfluxMeterRegistry customRegistry(InfluxConfig config, Clock clock) {\n\t\t\treturn new InfluxMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/InfluxPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport io.micrometer.influx.InfluxApiVersion;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InfluxPropertiesConfigAdapter}.\n *\n * @author Stephane Nicoll\n */\nclass InfluxPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<InfluxProperties, InfluxPropertiesConfigAdapter> {\n\n\tInfluxPropertiesConfigAdapterTests() {\n\t\tsuper(InfluxPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid adaptInfluxV1BasicConfig() {\n\t\tInfluxProperties properties = new InfluxProperties();\n\t\tproperties.setDb(\"test-db\");\n\t\tproperties.setUri(\"https://influx.example.com:8086\");\n\t\tproperties.setUserName(\"user\");\n\t\tproperties.setPassword(\"secret\");\n\t\tInfluxPropertiesConfigAdapter adapter = new InfluxPropertiesConfigAdapter(properties);\n\t\tassertThat(adapter.apiVersion()).isEqualTo(InfluxApiVersion.V1);\n\t\tassertThat(adapter.db()).isEqualTo(\"test-db\");\n\t\tassertThat(adapter.uri()).isEqualTo(\"https://influx.example.com:8086\");\n\t\tassertThat(adapter.userName()).isEqualTo(\"user\");\n\t\tassertThat(adapter.password()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid adaptInfluxV2BasicConfig() {\n\t\tInfluxProperties properties = new InfluxProperties();\n\t\tproperties.setOrg(\"test-org\");\n\t\tproperties.setBucket(\"test-bucket\");\n\t\tproperties.setUri(\"https://influx.example.com:8086\");\n\t\tproperties.setToken(\"token\");\n\t\tInfluxPropertiesConfigAdapter adapter = new InfluxPropertiesConfigAdapter(properties);\n\t\tassertThat(adapter.apiVersion()).isEqualTo(InfluxApiVersion.V2);\n\t\tassertThat(adapter.org()).isEqualTo(\"test-org\");\n\t\tassertThat(adapter.bucket()).isEqualTo(\"test-bucket\");\n\t\tassertThat(adapter.uri()).isEqualTo(\"https://influx.example.com:8086\");\n\t\tassertThat(adapter.token()).isEqualTo(\"token\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/influx/InfluxPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.influx;\n\nimport io.micrometer.influx.InfluxConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link InfluxProperties}.\n *\n * @author Stephane Nicoll\n */\nclass InfluxPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tInfluxProperties properties = new InfluxProperties();\n\t\tInfluxConfig config = InfluxConfig.DEFAULT;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getDb()).isEqualTo(config.db());\n\t\tassertThat(properties.getConsistency()).isEqualTo(config.consistency());\n\t\tassertThat(properties.getUserName()).isEqualTo(config.userName());\n\t\tassertThat(properties.getPassword()).isEqualTo(config.password());\n\t\tassertThat(properties.getRetentionPolicy()).isEqualTo(config.retentionPolicy());\n\t\tassertThat(properties.getRetentionDuration()).isEqualTo(config.retentionDuration());\n\t\tassertThat(properties.getRetentionReplicationFactor()).isEqualTo(config.retentionReplicationFactor());\n\t\tassertThat(properties.getRetentionShardDuration()).isEqualTo(config.retentionShardDuration());\n\t\tassertThat(properties.getUri()).isEqualTo(config.uri());\n\t\tassertThat(properties.isCompressed()).isEqualTo(config.compressed());\n\t\tassertThat(properties.isAutoCreateDb()).isEqualTo(config.autoCreateDb());\n\t\tassertThat(properties.getOrg()).isEqualTo(config.org());\n\t\tassertThat(properties.getToken()).isEqualTo(config.token());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/JmxMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.jmx.JmxConfig;\nimport io.micrometer.jmx.JmxMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JmxMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass JmxMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JmxMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(JmxMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JmxMeterRegistry.class).hasSingleBean(JmxConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JmxMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(JmxConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.jmx.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(JmxMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(JmxConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JmxMeterRegistry.class)\n\t\t\t\t.hasSingleBean(JmxConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JmxMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(JmxConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tJmxMeterRegistry registry = context.getBean(JmxMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tJmxConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tJmxMeterRegistry customRegistry(JmxConfig config, Clock clock) {\n\t\t\treturn new JmxMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/JmxPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JmxPropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass JmxPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<JmxProperties, JmxPropertiesConfigAdapter> {\n\n\tJmxPropertiesConfigAdapterTests() {\n\t\tsuper(JmxPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tJmxProperties properties = new JmxProperties();\n\t\tproperties.setStep(Duration.ofMinutes(15));\n\t\tassertThat(new JmxPropertiesConfigAdapter(properties).step()).isEqualTo(Duration.ofMinutes(15));\n\t}\n\n\t@Test\n\tvoid whenPropertiesDomainIsSetAdapterDomainReturnsIt() {\n\t\tJmxProperties properties = new JmxProperties();\n\t\tproperties.setDomain(\"abc\");\n\t\tassertThat(new JmxPropertiesConfigAdapter(properties).domain()).isEqualTo(\"abc\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/jmx/JmxPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.jmx;\n\nimport io.micrometer.jmx.JmxConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JmxProperties}.\n *\n * @author Stephane Nicoll\n */\nclass JmxPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tJmxProperties properties = new JmxProperties();\n\t\tJmxConfig config = JmxConfig.DEFAULT;\n\t\tassertThat(properties.getDomain()).isEqualTo(config.domain());\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/KairosMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.kairos.KairosConfig;\nimport io.micrometer.kairos.KairosMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link KairosMetricsExportAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass KairosMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(KairosMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(KairosMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(KairosMeterRegistry.class)\n\t\t\t\t.hasSingleBean(KairosConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(KairosMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(KairosConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.kairos.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(KairosMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(KairosConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(KairosMeterRegistry.class)\n\t\t\t\t.hasSingleBean(KairosConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(KairosMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(KairosConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tKairosMeterRegistry registry = context.getBean(KairosMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tKairosConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tKairosMeterRegistry customRegistry(KairosConfig config, Clock clock) {\n\t\t\treturn new KairosMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/KairosPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link KairosPropertiesConfigAdapter}.\n *\n * @author Stephane Nicoll\n */\nclass KairosPropertiesConfigAdapterTests\n\t\textends StepRegistryPropertiesConfigAdapterTests<KairosProperties, KairosPropertiesConfigAdapter> {\n\n\tKairosPropertiesConfigAdapterTests() {\n\t\tsuper(KairosPropertiesConfigAdapter.class);\n\t}\n\n\t@Override\n\tprotected KairosProperties createProperties() {\n\t\treturn new KairosProperties();\n\t}\n\n\t@Override\n\tprotected KairosPropertiesConfigAdapter createConfigAdapter(KairosProperties properties) {\n\t\treturn new KairosPropertiesConfigAdapter(properties);\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tKairosProperties properties = createProperties();\n\t\tproperties.setUri(\"https://kairos.example.com:8080/api/v1/datapoints\");\n\t\tassertThat(createConfigAdapter(properties).uri())\n\t\t\t.isEqualTo(\"https://kairos.example.com:8080/api/v1/datapoints\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesUserNameIsSetAdapterUserNameReturnsIt() {\n\t\tKairosProperties properties = createProperties();\n\t\tproperties.setUserName(\"alice\");\n\t\tassertThat(createConfigAdapter(properties).userName()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesPasswordIsSetAdapterPasswordReturnsIt() {\n\t\tKairosProperties properties = createProperties();\n\t\tproperties.setPassword(\"secret\");\n\t\tassertThat(createConfigAdapter(properties).password()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/kairos/KairosPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.kairos;\n\nimport io.micrometer.kairos.KairosConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link KairosProperties}.\n *\n * @author Stephane Nicoll\n */\nclass KairosPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tKairosProperties properties = new KairosProperties();\n\t\tKairosConfig config = KairosConfig.DEFAULT;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getUri()).isEqualToIgnoringWhitespace(config.uri());\n\t\tassertThat(properties.getUserName()).isEqualToIgnoringWhitespace(config.userName());\n\t\tassertThat(properties.getPassword()).isEqualToIgnoringWhitespace(config.password());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/NewRelicMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.newrelic.NewRelicClientProvider;\nimport io.micrometer.newrelic.NewRelicConfig;\nimport io.micrometer.newrelic.NewRelicMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n *\n * Tests for {@link NewRelicMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass NewRelicMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(NewRelicMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(NewRelicMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid failsWithoutAnApiKey() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.account-id=12345\")\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid failsWithoutAnAccountId() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\")\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid failsToAutoConfigureWithoutEventType() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\",\n\t\t\t\t\t\"management.newrelic.metrics.export.event-type=\")\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid autoConfiguresWithEventTypeOverridden() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\",\n\t\t\t\t\t\"management.newrelic.metrics.export.event-type=wxyz\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(NewRelicMeterRegistry.class)\n\t\t\t\t.hasSingleBean(Clock.class)\n\t\t\t\t.hasSingleBean(NewRelicConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresWithMeterNameEventTypeEnabledAndWithoutEventType() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\",\n\t\t\t\t\t\"management.newrelic.metrics.export.event-type=\",\n\t\t\t\t\t\"management.newrelic.metrics.export.meter-name-event-type-enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(NewRelicMeterRegistry.class)\n\t\t\t\t.hasSingleBean(Clock.class)\n\t\t\t\t.hasSingleBean(NewRelicConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresWithAccountIdAndApiKey() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(NewRelicMeterRegistry.class)\n\t\t\t\t.hasSingleBean(Clock.class)\n\t\t\t\t.hasSingleBean(NewRelicConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(NewRelicMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(NewRelicConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(NewRelicMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(NewRelicConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsConfigToBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(NewRelicConfig.class).hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsRegistryToBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(NewRelicMeterRegistry.class).hasBean(\"customRegistry\"));\n\t}\n\n\t@Test\n\tvoid allowsClientProviderToBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomClientProviderConfiguration.class)\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=12345\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(NewRelicMeterRegistry.class);\n\t\t\t\tassertThat(context.getBean(NewRelicMeterRegistry.class)).hasFieldOrPropertyWithValue(\"clientProvider\",\n\t\t\t\t\t\tcontext.getBean(\"customClientProvider\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.newrelic.metrics.export.api-key=abcde\",\n\t\t\t\t\t\"management.newrelic.metrics.export.account-id=abcde\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tNewRelicMeterRegistry registry = context.getBean(NewRelicMeterRegistry.class);\n\t\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock customClock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tNewRelicConfig customConfig() {\n\t\t\treturn (key) -> {\n\t\t\t\tif (\"newrelic.accountId\".equals(key)) {\n\t\t\t\t\treturn \"abcde\";\n\t\t\t\t}\n\t\t\t\tif (\"newrelic.apiKey\".equals(key)) {\n\t\t\t\t\treturn \"12345\";\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tNewRelicMeterRegistry customRegistry(NewRelicConfig config, Clock clock) {\n\t\t\treturn new NewRelicMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomClientProviderConfiguration {\n\n\t\t@Bean\n\t\tNewRelicClientProvider customClientProvider() {\n\t\t\treturn mock(NewRelicClientProvider.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/NewRelicPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport io.micrometer.newrelic.ClientProviderType;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NewRelicPropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass NewRelicPropertiesConfigAdapterTests\n\t\textends StepRegistryPropertiesConfigAdapterTests<NewRelicProperties, NewRelicPropertiesConfigAdapter> {\n\n\tNewRelicPropertiesConfigAdapterTests() {\n\t\tsuper(NewRelicPropertiesConfigAdapter.class);\n\t}\n\n\t@Override\n\tprotected NewRelicProperties createProperties() {\n\t\treturn new NewRelicProperties();\n\t}\n\n\t@Override\n\tprotected NewRelicPropertiesConfigAdapter createConfigAdapter(NewRelicProperties properties) {\n\t\treturn new NewRelicPropertiesConfigAdapter(properties);\n\t}\n\n\t@Test\n\tvoid whenPropertiesMeterNameEventTypeEnabledIsSetAdapterMeterNameEventTypeEnabledReturnsIt() {\n\t\tNewRelicProperties properties = createProperties();\n\t\tproperties.setMeterNameEventTypeEnabled(true);\n\t\tassertThat(createConfigAdapter(properties).meterNameEventTypeEnabled()).isEqualTo(true);\n\t}\n\n\t@Test\n\tvoid whenPropertiesEventTypeIsSetAdapterEventTypeReturnsIt() {\n\t\tNewRelicProperties properties = createProperties();\n\t\tproperties.setEventType(\"foo\");\n\t\tassertThat(createConfigAdapter(properties).eventType()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesClientProviderTypeIsSetAdapterClientProviderTypeReturnsIt() {\n\t\tNewRelicProperties properties = createProperties();\n\t\tproperties.setClientProviderType(ClientProviderType.INSIGHTS_AGENT);\n\t\tassertThat(createConfigAdapter(properties).clientProviderType()).isEqualTo(ClientProviderType.INSIGHTS_AGENT);\n\t}\n\n\t@Test\n\tvoid whenPropertiesApiKeyIsSetAdapterApiKeyReturnsIt() {\n\t\tNewRelicProperties properties = createProperties();\n\t\tproperties.setApiKey(\"my-key\");\n\t\tassertThat(createConfigAdapter(properties).apiKey()).isEqualTo(\"my-key\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesAccountIdIsSetAdapterAccountIdReturnsIt() {\n\t\tNewRelicProperties properties = createProperties();\n\t\tproperties.setAccountId(\"A38\");\n\t\tassertThat(createConfigAdapter(properties).accountId()).isEqualTo(\"A38\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesUriIsSetAdapterUriReturnsIt() {\n\t\tNewRelicProperties properties = createProperties();\n\t\tproperties.setUri(\"https://example.newrelic.com\");\n\t\tassertThat(createConfigAdapter(properties).uri()).isEqualTo(\"https://example.newrelic.com\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/newrelic/NewRelicPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.newrelic;\n\nimport io.micrometer.newrelic.NewRelicConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NewRelicProperties}.\n *\n * @author Stephane Nicoll\n */\nclass NewRelicPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tNewRelicProperties properties = new NewRelicProperties();\n\t\tNewRelicConfig config = (key) -> null;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getClientProviderType()).isEqualTo(config.clientProviderType());\n\t\t// apiKey and account are mandatory\n\t\tassertThat(properties.getUri()).isEqualTo(config.uri());\n\t\tassertThat(properties.isMeterNameEventTypeEnabled()).isEqualTo(config.meterNameEventTypeEnabled());\n\t}\n\n\t@Test\n\tvoid eventTypeDefaultValueIsOverridden() {\n\t\tNewRelicProperties properties = new NewRelicProperties();\n\t\tNewRelicConfig config = (key) -> null;\n\t\tassertThat(properties.getEventType()).isNotEqualTo(config.eventType());\n\t\tassertThat(properties.getEventType()).isEqualTo(\"SpringBootSample\");\n\t\tassertThat(config.eventType()).isEqualTo(\"MicrometerSample\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/JdkClientHttpSenderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.ipc.http.HttpSender.Response;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link JdkClientHttpSender}.\n *\n * @author Moritz Halbritter\n */\nclass JdkClientHttpSenderTests {\n\n\tprivate MockWebServer mockWebServer;\n\n\tprivate JdkClientHttpSender sender;\n\n\t@BeforeEach\n\tvoid setUp() throws IOException {\n\t\tthis.mockWebServer = new MockWebServer();\n\t\tthis.mockWebServer.start();\n\t\tthis.sender = new JdkClientHttpSender(Duration.ofSeconds(5), Duration.ofSeconds(5), null);\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws IOException {\n\t\tthis.mockWebServer.shutdown();\n\t}\n\n\t@Test\n\tvoid sendShouldSendGetRequest() throws Throwable {\n\t\tthis.mockWebServer.enqueue(new MockResponse().setBody(\"response-body\").setResponseCode(200));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tResponse response = this.sender.get(url).send();\n\t\tassertThat(response.code()).isEqualTo(200);\n\t\tassertThat(response.body()).isEqualTo(\"response-body\");\n\t\tRecordedRequest request = this.mockWebServer.takeRequest();\n\t\tassertThat(request.getMethod()).isEqualTo(\"GET\");\n\t\tassertThat(request.getPath()).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid sendShouldSendPostRequest() throws Throwable {\n\t\tthis.mockWebServer.enqueue(new MockResponse().setResponseCode(200));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tResponse response = this.sender.post(url).withJsonContent(\"{\\\"key\\\":\\\"value\\\"}\").send();\n\t\tassertThat(response.code()).isEqualTo(200);\n\t\tRecordedRequest request = this.mockWebServer.takeRequest();\n\t\tassertThat(request.getMethod()).isEqualTo(\"POST\");\n\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/json\");\n\t\tassertThat(request.getBody().readUtf8()).isEqualTo(\"{\\\"key\\\":\\\"value\\\"}\");\n\t}\n\n\t@Test\n\tvoid sendShouldIncludeHeaders() throws Throwable {\n\t\tthis.mockWebServer.enqueue(new MockResponse().setResponseCode(200));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tthis.sender.post(url).withHeader(\"X-Custom\", \"custom-value\").send();\n\t\tRecordedRequest request = this.mockWebServer.takeRequest();\n\t\tassertThat(request.getHeader(\"X-Custom\")).isEqualTo(\"custom-value\");\n\t}\n\n\t@Test\n\tvoid sendShouldHandleServerError() throws Throwable {\n\t\tthis.mockWebServer.enqueue(new MockResponse().setResponseCode(500).setBody(\"error\"));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tResponse response = this.sender.get(url).send();\n\t\tassertThat(response.code()).isEqualTo(500);\n\t\tassertThat(response.body()).isEqualTo(\"error\");\n\t}\n\n\t@Test\n\tvoid sendShouldTimeoutOnSlowResponse() {\n\t\tJdkClientHttpSender sender = new JdkClientHttpSender(Duration.ofSeconds(5), Duration.ofMillis(10), null);\n\t\tthis.mockWebServer.enqueue(new MockResponse().setResponseCode(200).setHeadersDelay(500, TimeUnit.MILLISECONDS));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tassertThatIOException().isThrownBy(() -> sender.get(url).send()).withMessageContaining(\"timed out\");\n\t}\n\n\t@Test\n\tvoid sendShouldSendPutRequest() throws Throwable {\n\t\tthis.mockWebServer.enqueue(new MockResponse().setResponseCode(200));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tthis.sender.put(url).withPlainText(\"data\").send();\n\t\tRecordedRequest request = this.mockWebServer.takeRequest();\n\t\tassertThat(request.getMethod()).isEqualTo(\"PUT\");\n\t\tassertThat(request.getBody().readUtf8()).isEqualTo(\"data\");\n\t}\n\n\t@Test\n\tvoid sendShouldSendDeleteRequest() throws Throwable {\n\t\tthis.mockWebServer.enqueue(new MockResponse().setResponseCode(204));\n\t\tString url = this.mockWebServer.url(\"/test\").toString();\n\t\tResponse response = this.sender.delete(url).send();\n\t\tassertThat(response.code()).isEqualTo(204);\n\t\tRecordedRequest request = this.mockWebServer.takeRequest();\n\t\tassertThat(request.getMethod()).isEqualTo(\"DELETE\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.net.http.HttpClient;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport javax.net.ssl.SSLContext;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.registry.otlp.ExemplarContextProvider;\nimport io.micrometer.registry.otlp.OtlpConfig;\nimport io.micrometer.registry.otlp.OtlpHttpMetricsSender;\nimport io.micrometer.registry.otlp.OtlpMeterRegistry;\nimport io.micrometer.registry.otlp.OtlpMetricsSender;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpMetricsConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.assertj.ScheduledExecutorServiceAssert;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OtlpMetricsExportAutoConfiguration}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass OtlpMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OtlpMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(OtlpMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OtlpMeterRegistry.class)\n\t\t\t\t.hasSingleBean(OtlpConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OtlpMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(OtlpConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.otlp.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OtlpMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(OtlpConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OtlpMeterRegistry.class)\n\t\t\t\t.hasSingleBean(OtlpConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsPlatformThreadsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OtlpMeterRegistry.class);\n\t\t\tOtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);\n\t\t\tassertThat(registry).extracting(\"scheduledExecutorService\")\n\t\t\t\t.satisfies((executor) -> ScheduledExecutorServiceAssert.assertThat((ScheduledExecutorService) executor)\n\t\t\t\t\t.usesPlatformThreads());\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid allowsVirtualThreadsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpMeterRegistry.class);\n\t\t\t\tOtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);\n\t\t\t\tassertThat(registry).extracting(\"scheduledExecutorService\")\n\t\t\t\t\t.satisfies(\n\t\t\t\t\t\t\t(executor) -> ScheduledExecutorServiceAssert.assertThat((ScheduledExecutorService) executor)\n\t\t\t\t\t\t\t\t.usesVirtualThreads());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allowsRegistryToBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OtlpMeterRegistry.class)\n\t\t\t\t.hasSingleBean(OtlpConfig.class)\n\t\t\t\t.hasBean(\"customRegistry\"));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesOtlpMetricsConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class, ConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpMetricsConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesOtlpMetricsConnectionDetails.class);\n\t\t\t\tOtlpConfig config = context.getBean(OtlpConfig.class);\n\t\t\t\tassertThat(config.url()).isEqualTo(\"http://localhost:12345/v1/metrics\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allowsCustomMetricsSenderToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class, CustomMetricsSenderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertHasCustomMetricsSender(context);\n\t\t\t\tassertThat(context).doesNotHaveBean(OtlpHttpMetricsSender.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid allowsCustomExemplarContextProviderToBeUsed() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(BaseConfiguration.class, CustomExemplarContextProviderConfiguration.class)\n\t\t\t.run(this::assertHasCustomExemplarContextProvider);\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid allowsCustomMetricsSenderToBeUsedWithVirtualThreads() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class, CustomMetricsSenderConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.run(this::assertHasCustomMetricsSender);\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid allowsCustomExemplarContextProviderToBeUsedWithVirtualThreads() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(BaseConfiguration.class, CustomExemplarContextProviderConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.run(this::assertHasCustomExemplarContextProvider);\n\t}\n\n\t@Test\n\tvoid exemplarContextProviderShouldBeMissingIfNoExemplarContextProviderBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ExemplarContextProvider.class);\n\t\t\tassertThat(context).hasSingleBean(OtlpMeterRegistry.class);\n\t\t\tOtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);\n\t\t\tassertThat(registry).extracting(\"exemplarSamplerFactory\").isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfSpringBootOpenTelemetryIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.boot.opentelemetry\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OtlpMetricsExportAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresOtlpHttpMetricsSender() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OtlpHttpMetricsSender.class));\n\t}\n\n\t@Test\n\tvoid whenNoSslBundleConfiguredConnectionDetailsReturnsNull() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OtlpMetricsConnectionDetails.class);\n\t\t\tOtlpMetricsConnectionDetails connectionDetails = context.getBean(OtlpMetricsConnectionDetails.class);\n\t\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenNoSslBundleDefaultHttpSenderHasDefaultSslContext() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OtlpHttpMetricsSender.class);\n\t\t\tOtlpHttpMetricsSender metricsSender = context.getBean(OtlpHttpMetricsSender.class);\n\t\t\tHttpClient httpClient = extractHttpClient(metricsSender);\n\t\t\tassertThat(httpClient.sslContext()).isSameAs(SSLContext.getDefault());\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasSslBundleConfiguresSslOnHttpSender() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.otlp.metrics.export.ssl.bundle=mybundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.mybundle.truststore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpMetricsSender.class);\n\t\t\t\tOtlpHttpMetricsSender metricsSender = context.getBean(OtlpHttpMetricsSender.class);\n\t\t\t\tHttpClient httpClient = extractHttpClient(metricsSender);\n\t\t\t\tassertThat(httpClient.sslContext()).isNotSameAs(SSLContext.getDefault());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomConnectionDetailsProvidesSslBundleConfiguresSslOnHttpSender() throws Exception {\n\t\tSSLContext customSslContext = SSLContext.getInstance(\"TLS\");\n\t\tcustomSslContext.init(null, null, null);\n\t\tSslBundle sslBundle = mock(SslBundle.class);\n\t\tgiven(sslBundle.createSslContext()).willReturn(customSslContext);\n\t\tgiven(sslBundle.getOptions()).willReturn(SslOptions.NONE);\n\t\tOtlpMetricsConnectionDetails connectionDetails = new OtlpMetricsConnectionDetails() {\n\t\t\t@Override\n\t\t\tpublic String getUrl() {\n\t\t\t\treturn \"https://localhost:4318/v1/metrics\";\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic SslBundle getSslBundle() {\n\t\t\t\treturn sslBundle;\n\t\t\t}\n\t\t};\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withBean(\"customOtlpMetricsConnectionDetails\", OtlpMetricsConnectionDetails.class, () -> connectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpMetricsSender.class);\n\t\t\t\tOtlpHttpMetricsSender metricsSender = context.getBean(OtlpHttpMetricsSender.class);\n\t\t\t\tHttpClient httpClient = extractHttpClient(metricsSender);\n\t\t\t\tassertThat(httpClient.sslContext()).isSameAs(customSslContext);\n\t\t\t});\n\t}\n\n\tprivate HttpClient extractHttpClient(OtlpHttpMetricsSender metricsSender) {\n\t\tObject field = ReflectionTestUtils.getField(metricsSender, \"httpSender\");\n\t\tassertThat(field).isNotNull();\n\t\tObject httpClient = ReflectionTestUtils.getField(field, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn (HttpClient) httpClient;\n\t}\n\n\tprivate void assertHasCustomMetricsSender(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(OtlpMeterRegistry.class);\n\t\tOtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);\n\t\tassertThat(registry).extracting(\"metricsSender\")\n\t\t\t.satisfies((sender) -> assertThat(sender).isSameAs(CustomMetricsSenderConfiguration.customMetricsSender));\n\t}\n\n\tprivate void assertHasCustomExemplarContextProvider(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(OtlpMeterRegistry.class);\n\t\tOtlpMeterRegistry registry = context.getBean(OtlpMeterRegistry.class);\n\t\tassertThat(registry).extracting(\"exemplarSamplerFactory\")\n\t\t\t.extracting(\"exemplarContextProvider\")\n\t\t\t.satisfies((provider) -> assertThat(provider)\n\t\t\t\t.isSameAs(CustomExemplarContextProviderConfiguration.customExemplarContextProvider));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock customClock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tOtlpConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tOtlpMeterRegistry customRegistry(OtlpConfig config, Clock clock) {\n\t\t\treturn new OtlpMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tOtlpMetricsConnectionDetails otlpConnectionDetails() {\n\t\t\treturn () -> \"http://localhost:12345/v1/metrics\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomMetricsSenderConfiguration {\n\n\t\tstatic OtlpMetricsSender customMetricsSender = (request) -> {\n\t\t};\n\n\t\t@Bean\n\t\tOtlpMetricsSender customMetricsSender() {\n\t\t\treturn customMetricsSender;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomExemplarContextProviderConfiguration {\n\n\t\tstatic ExemplarContextProvider customExemplarContextProvider = () -> null;\n\n\t\t@Bean\n\t\tExemplarContextProvider customExemplarContextProvider() {\n\t\t\treturn customExemplarContextProvider;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.registry.otlp.AggregationTemporality;\nimport io.micrometer.registry.otlp.CompressionMode;\nimport io.micrometer.registry.otlp.HistogramFlavor;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration.PropertiesOtlpMetricsConnectionDetails;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsProperties.Meter;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryProperties;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link OtlpMetricsPropertiesConfigAdapter}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass OtlpMetricsPropertiesConfigAdapterTests {\n\n\tprivate OtlpMetricsProperties properties;\n\n\tprivate OpenTelemetryProperties openTelemetryProperties;\n\n\tprivate MockEnvironment environment;\n\n\tprivate OtlpMetricsConnectionDetails connectionDetails;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new OtlpMetricsProperties();\n\t\tthis.openTelemetryProperties = new OpenTelemetryProperties();\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.connectionDetails = new PropertiesOtlpMetricsConnectionDetails(this.properties, null);\n\t}\n\n\t@Test\n\tvoid whenPropertiesUrlIsNotSetAdapterUrlReturnsDefault() {\n\t\tassertThat(this.properties.getUrl()).isNull();\n\t\tassertThat(createAdapter().url()).isEqualTo(\"http://localhost:4318/v1/metrics\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesUrlIsNotSetThenUseOtlpConfigUrlAsFallback() {\n\t\tassertThat(this.properties.getUrl()).isNull();\n\t\tOtlpMetricsPropertiesConfigAdapter adapter = spy(createAdapter());\n\t\tgiven(adapter.get(\"management.otlp.metrics.export.url\")).willReturn(\"https://my-endpoint/v1/metrics\");\n\t\tassertThat(adapter.url()).isEqualTo(\"https://my-endpoint/v1/metrics\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesUrlIsSetAdapterUrlReturnsIt() {\n\t\tthis.properties.setUrl(\"http://another-url:4318/v1/metrics\");\n\t\tassertThat(createAdapter().url()).isEqualTo(\"http://another-url:4318/v1/metrics\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesAggregationTemporalityIsNotSetAdapterAggregationTemporalityReturnsCumulative() {\n\t\tassertThat(createAdapter().aggregationTemporality()).isSameAs(AggregationTemporality.CUMULATIVE);\n\t}\n\n\t@Test\n\tvoid whenPropertiesAggregationTemporalityIsSetAdapterAggregationTemporalityReturnsIt() {\n\t\tthis.properties.setAggregationTemporality(AggregationTemporality.DELTA);\n\t\tassertThat(createAdapter().aggregationTemporality()).isSameAs(AggregationTemporality.DELTA);\n\t}\n\n\t@Test\n\tvoid whenPropertiesCompressionModeIsNotSetAdapterCompressionModeReturnsNone() {\n\t\tassertThat(createAdapter().compressionMode()).isSameAs(CompressionMode.NONE);\n\t}\n\n\t@Test\n\tvoid whenPropertiesCompressionModeIsSetAdapterCompressionModeReturnsIt() {\n\t\tthis.properties.setCompressionMode(CompressionMode.GZIP);\n\t\tassertThat(createAdapter().compressionMode()).isSameAs(CompressionMode.GZIP);\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryPropertiesResourceAttributesIsSetAdapterResourceAttributesReturnsIt() {\n\t\tthis.openTelemetryProperties.setResourceAttributes(Map.of(\"service.name\", \"boot-service\"));\n\t\tassertThat(createAdapter().resourceAttributes()).containsEntry(\"service.name\", \"boot-service\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesHeadersIsSetAdapterHeadersReturnsIt() {\n\t\tthis.properties.setHeaders(Map.of(\"header\", \"value\"));\n\t\tassertThat(createAdapter().headers()).containsEntry(\"header\", \"value\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesHistogramFlavorIsNotSetAdapterHistogramFlavorReturnsExplicitBucketHistogram() {\n\t\tassertThat(createAdapter().histogramFlavor()).isSameAs(HistogramFlavor.EXPLICIT_BUCKET_HISTOGRAM);\n\t}\n\n\t@Test\n\tvoid whenPropertiesHistogramFlavorIsSetAdapterHistogramFlavorReturnsIt() {\n\t\tthis.properties.setHistogramFlavor(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM);\n\t\tassertThat(createAdapter().histogramFlavor()).isSameAs(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM);\n\t}\n\n\t@Test\n\tvoid whenPropertiesHistogramFlavorPerMeterIsNotSetAdapterHistogramFlavorReturnsEmptyMap() {\n\t\tassertThat(createAdapter().histogramFlavorPerMeter()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenPropertiesHistogramFlavorPerMeterIsSetAdapterHistogramFlavorPerMeterReturnsIt() {\n\t\tMeter meterProperties = new Meter();\n\t\tmeterProperties.setHistogramFlavor(HistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM);\n\t\tthis.properties.getMeter().put(\"my.histograms\", meterProperties);\n\t\tassertThat(createAdapter().histogramFlavorPerMeter()).containsEntry(\"my.histograms\",\n\t\t\t\tHistogramFlavor.BASE2_EXPONENTIAL_BUCKET_HISTOGRAM);\n\t}\n\n\t@Test\n\tvoid useDefaultPublishMaxGaugeForHistogramsWhenNotSet() {\n\t\tassertThat(this.properties.getPublishMaxGaugeForHistograms()).isNull();\n\t\tassertThat(createAdapter().publishMaxGaugeForHistograms()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenDefaultPublishMaxGaugeForHistogramsIsSetAdapterUsesIt() {\n\t\tthis.properties.setPublishMaxGaugeForHistograms(false);\n\t\tassertThat(createAdapter().publishMaxGaugeForHistograms()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenAggregationTemporalityIsSetToDeltaThenPublishMaxGaugeForHistogramsDefaultChanges() {\n\t\tthis.properties.setAggregationTemporality(AggregationTemporality.DELTA);\n\t\tassertThat(createAdapter().publishMaxGaugeForHistograms()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxScaleIsNotSetAdapterMaxScaleReturns20() {\n\t\tassertThat(createAdapter().maxScale()).isEqualTo(20);\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxScaleIsSetAdapterMaxScaleReturnsIt() {\n\t\tthis.properties.setMaxScale(5);\n\t\tassertThat(createAdapter().maxScale()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxBucketCountIsNotSetAdapterMaxBucketCountReturns160() {\n\t\tassertThat(createAdapter().maxBucketCount()).isEqualTo(160);\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxBucketCountIsSetAdapterMaxBucketCountReturnsIt() {\n\t\tthis.properties.setMaxBucketCount(6);\n\t\tassertThat(createAdapter().maxBucketCount()).isEqualTo(6);\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxBucketsPerMeterIsNotSetAdapterMaxBucketsPerMeterReturnsEmptyMap() {\n\t\tassertThat(createAdapter().maxBucketsPerMeter()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxBucketsPerMeterIsSetAdapterMaxBucketsPerMeterReturnsIt() {\n\t\tMeter meterProperties = new Meter();\n\t\tmeterProperties.setMaxBucketCount(111);\n\t\tthis.properties.getMeter().put(\"my.histograms\", meterProperties);\n\t\tassertThat(createAdapter().maxBucketsPerMeter()).containsEntry(\"my.histograms\", 111);\n\t}\n\n\t@Test\n\tvoid whenPropertiesBaseTimeUnitIsNotSetAdapterBaseTimeUnitReturnsMillis() {\n\t\tassertThat(createAdapter().baseTimeUnit()).isSameAs(TimeUnit.MILLISECONDS);\n\t}\n\n\t@Test\n\tvoid whenPropertiesBaseTimeUnitIsSetAdapterBaseTimeUnitReturnsIt() {\n\t\tthis.properties.setBaseTimeUnit(TimeUnit.SECONDS);\n\t\tassertThat(createAdapter().baseTimeUnit()).isSameAs(TimeUnit.SECONDS);\n\t}\n\n\t@Test\n\tvoid serviceNameOverridesApplicationName() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"alpha\");\n\t\tthis.openTelemetryProperties.setResourceAttributes(Map.of(\"service.name\", \"beta\"));\n\t\tassertThat(createAdapter().resourceAttributes()).containsEntry(\"service.name\", \"beta\");\n\t}\n\n\t@Test\n\tvoid shouldUseApplicationNameIfServiceNameIsNotSet() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"alpha\");\n\t\tassertThat(createAdapter().resourceAttributes()).containsEntry(\"service.name\", \"alpha\");\n\t}\n\n\t@Test\n\tvoid shouldUseDefaultApplicationNameIfApplicationNameIsNotSet() {\n\t\tassertThat(createAdapter().resourceAttributes()).containsEntry(\"service.name\", \"unknown_service\");\n\t}\n\n\t@Test\n\tvoid serviceNamespaceOverridesApplicationGroup() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"alpha\");\n\t\tthis.openTelemetryProperties.setResourceAttributes(Map.of(\"service.namespace\", \"beta\"));\n\t\tassertThat(createAdapter().resourceAttributes()).containsEntry(\"service.namespace\", \"beta\");\n\t}\n\n\t@Test\n\tvoid shouldUseApplicationGroupIfServiceNamspaceIsNotSet() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"alpha\");\n\t\tassertThat(createAdapter().resourceAttributes()).containsEntry(\"service.namespace\", \"alpha\");\n\t}\n\n\t@Test\n\tvoid shouldUseDefaultApplicationGroupIfApplicationGroupIsNotSet() {\n\t\tassertThat(createAdapter().resourceAttributes()).doesNotContainKey(\"service.namespace\");\n\t}\n\n\tprivate OtlpMetricsPropertiesConfigAdapter createAdapter() {\n\t\treturn new OtlpMetricsPropertiesConfigAdapter(this.properties, this.openTelemetryProperties,\n\t\t\t\tthis.connectionDetails, this.environment);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/otlp/OtlpMetricsPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp;\n\nimport io.micrometer.registry.otlp.OtlpConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OtlpMetricsProperties}.\n *\n * @author Eddú Meléndez\n */\nclass OtlpMetricsPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tOtlpMetricsProperties properties = new OtlpMetricsProperties();\n\t\tOtlpConfig config = OtlpConfig.DEFAULT;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getAggregationTemporality()).isSameAs(config.aggregationTemporality());\n\t\tassertThat(properties.getCompressionMode()).isSameAs(config.compressionMode());\n\t\tassertThat(properties.getHistogramFlavor()).isSameAs(config.histogramFlavor());\n\t\tassertThat(properties.getMaxScale()).isEqualTo(config.maxScale());\n\t\tassertThat(properties.getMaxBucketCount()).isEqualTo(config.maxBucketCount());\n\t\tassertThat(properties.getBaseTimeUnit()).isSameAs(config.baseTimeUnit());\n\t\tassertThat(properties.getMeter()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport java.net.MalformedURLException;\nimport java.net.URI;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.prometheusmetrics.PrometheusConfig;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport io.prometheus.metrics.exporter.pushgateway.DefaultHttpConnectionFactory;\nimport io.prometheus.metrics.exporter.pushgateway.PushGateway;\nimport io.prometheus.metrics.expositionformats.PrometheusTextFormatWriter;\nimport io.prometheus.metrics.model.registry.PrometheusRegistry;\nimport io.prometheus.metrics.tracer.common.SpanContext;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PrometheusMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Jonatan Ivanov\n */\nclass PrometheusMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(PrometheusMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context)\n\t\t\t.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigCollectorRegistryAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)\n\t\t\t\t.hasSingleBean(PrometheusRegistry.class)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(PrometheusRegistry.class)\n\t\t\t\t.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(PrometheusRegistry.class)\n\t\t\t\t.doesNotHaveBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)\n\t\t\t\t.hasSingleBean(PrometheusRegistry.class)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(PrometheusRegistry.class)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomCollectorRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomPrometheusRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class)\n\t\t\t\t.hasBean(\"customPrometheusRegistry\")\n\t\t\t\t.hasSingleBean(PrometheusRegistry.class)\n\t\t\t\t.hasSingleBean(io.micrometer.prometheusmetrics.PrometheusConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresPrometheusMeterRegistryIfSpanContextIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(ExemplarsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SpanContext.class)\n\t\t\t\t.hasSingleBean(PrometheusMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid addsScrapeEndpointToManagementContext() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=prometheus\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PrometheusScrapeEndpoint.class));\n\t}\n\n\t@Test\n\tvoid scrapeEndpointNotAddedToManagementContextWhenNotExposed() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PrometheusScrapeEndpoint.class));\n\t}\n\n\t@Test\n\tvoid scrapeEndpointCanBeDisabled() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=prometheus\",\n\t\t\t\t\t\"management.endpoint.prometheus.enabled=false\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PrometheusScrapeEndpoint.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomScrapeEndpointToBeUsed() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomEndpointConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"customEndpoint\")\n\t\t\t\t.hasSingleBean(PrometheusScrapeEndpoint.class));\n\t}\n\n\t@Test\n\tvoid pushGatewayIsNotConfiguredWhenEnabledFlagIsNotSet() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PrometheusPushGatewayManager.class));\n\t}\n\n\t@Test\n\t@ExtendWith(OutputCaptureExtension.class)\n\tvoid withPushGatewayEnabled(CapturedOutput output) {\n\t\tthis.contextRunner.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(output).doesNotContain(\"Invalid PushGateway base url\");\n\t\t\t\thasGatewayUrl(context, \"http://localhost:9091/metrics/job/spring\");\n\t\t\t\tassertThat(getPushGateway(context)).extracting(\"connectionFactory\")\n\t\t\t\t\t.isInstanceOf(DefaultHttpConnectionFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withPushGatewayDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=false\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PrometheusPushGatewayManager.class));\n\t}\n\n\t@Test\n\tvoid withCustomPushGatewayAddress() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.address=localhost:8080\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> hasGatewayUrl(context, \"http://localhost:8080/metrics/job/spring\"));\n\t}\n\n\t@Test\n\tvoid withCustomScheme() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.scheme=https\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> hasGatewayUrl(context, \"https://localhost:9091/metrics/job/spring\"));\n\t}\n\n\t@Test\n\tvoid withCustomFormat() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.format=text\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(getPushGateway(context)).extracting(\"writer\")\n\t\t\t\t.isInstanceOf(PrometheusTextFormatWriter.class));\n\t}\n\n\t@Test\n\tvoid withPushGatewayBasicAuth() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.username=admin\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.password=secret\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(getPushGateway(context))\n\t\t\t\t.extracting(\"requestHeaders\", InstanceOfAssertFactories.map(String.class, String.class))\n\t\t\t\t.satisfies((headers) -> assertThat(headers.get(\"Authorization\")).startsWith(\"Basic \")));\n\n\t}\n\n\t@Test\n\tvoid withPushGatewayBearerToken() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.token=a1b2c3d4\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(getPushGateway(context))\n\t\t\t\t.extracting(\"requestHeaders\", InstanceOfAssertFactories.map(String.class, String.class))\n\t\t\t\t.satisfies((headers) -> assertThat(headers.get(\"Authorization\")).startsWith(\"Bearer \")));\n\t}\n\n\t@Test\n\tvoid failsFastWithBothBearerAndBasicAuthentication() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.prometheus.metrics.export.pushgateway.enabled=true\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.username=alice\",\n\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.token=a1b2c3d4\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.hasRootCauseInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class)\n\t\t\t\t.hasMessageContainingAll(\"management.prometheus.metrics.export.pushgateway.username\",\n\t\t\t\t\t\t\"management.prometheus.metrics.export.pushgateway.token\"));\n\t}\n\n\tprivate void hasGatewayUrl(AssertableApplicationContext context, String url) {\n\t\ttry {\n\t\t\tassertThat(getPushGateway(context)).hasFieldOrPropertyWithValue(\"url\", URI.create(url).toURL());\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tprivate PushGateway getPushGateway(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(PrometheusPushGatewayManager.class);\n\t\tPrometheusPushGatewayManager gatewayManager = context.getBean(PrometheusPushGatewayManager.class);\n\t\tObject field = ReflectionTestUtils.getField(gatewayManager, \"pushGateway\");\n\t\tassertThat(field).isNotNull();\n\t\treturn (PushGateway) field;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tio.micrometer.prometheusmetrics.PrometheusConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tio.micrometer.prometheusmetrics.PrometheusMeterRegistry customRegistry(\n\t\t\t\tio.micrometer.prometheusmetrics.PrometheusConfig config, PrometheusRegistry prometheusRegistry,\n\t\t\t\tClock clock) {\n\t\t\treturn new io.micrometer.prometheusmetrics.PrometheusMeterRegistry(config, prometheusRegistry, clock);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomPrometheusRegistryConfiguration {\n\n\t\t@Bean\n\t\tPrometheusRegistry customPrometheusRegistry() {\n\t\t\treturn new PrometheusRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomEndpointConfiguration {\n\n\t\t@Bean\n\t\tPrometheusScrapeEndpoint customEndpoint(PrometheusRegistry prometheusRegistry,\n\t\t\t\tPrometheusConfig prometheusConfig) {\n\t\t\treturn new PrometheusScrapeEndpoint(prometheusRegistry, prometheusConfig.prometheusProperties());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class ExemplarsConfiguration {\n\n\t\t@Bean\n\t\tSpanContext spanContext() {\n\t\t\treturn new SpanContext() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable String getCurrentTraceId() {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable String getCurrentSpanId() {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic boolean isCurrentSpanSampled() {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void markCurrentSpanAsExemplar() {\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PrometheusPropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass PrometheusPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<PrometheusProperties, PrometheusPropertiesConfigAdapter> {\n\n\tPrometheusPropertiesConfigAdapterTests() {\n\t\tsuper(PrometheusPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesDescriptionsIsSetAdapterDescriptionsReturnsIt() {\n\t\tPrometheusProperties properties = new PrometheusProperties();\n\t\tproperties.setDescriptions(false);\n\t\tassertThat(new PrometheusPropertiesConfigAdapter(properties).descriptions()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tPrometheusProperties properties = new PrometheusProperties();\n\t\tproperties.setStep(Duration.ofSeconds(30));\n\t\tassertThat(new PrometheusPropertiesConfigAdapter(properties).step()).isEqualTo(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/prometheus/PrometheusPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PrometheusProperties}.\n *\n * @author Stephane Nicoll\n */\nclass PrometheusPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tPrometheusProperties properties = new PrometheusProperties();\n\t\tio.micrometer.prometheusmetrics.PrometheusConfig config = io.micrometer.prometheusmetrics.PrometheusConfig.DEFAULT;\n\t\tassertThat(properties.isDescriptions()).isEqualTo(config.descriptions());\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/PushRegistryPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport io.micrometer.core.instrument.push.PushRegistryConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base tests for {@link PushRegistryProperties} implementation.\n *\n * @author Stephane Nicoll\n */\npublic abstract class PushRegistryPropertiesTests {\n\n\t@SuppressWarnings(\"deprecation\")\n\tprotected void assertStepRegistryDefaultValues(PushRegistryProperties properties, PushRegistryConfig config) {\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t\tassertThat(properties.isEnabled()).isEqualTo(config.enabled());\n\t\tassertThat(properties.getConnectTimeout()).isEqualTo(config.connectTimeout());\n\t\tassertThat(properties.getReadTimeout()).isEqualTo(config.readTimeout());\n\t\tassertThat(properties.getBatchSize()).isEqualTo(config.batchSize());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/StepRegistryPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PushRegistryPropertiesConfigAdapterTests;\n\n/**\n * Base test for {@link StepRegistryPropertiesConfigAdapter} implementations.\n *\n * @param <P> properties used by the tests\n * @param <A> adapter used by the tests\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n */\npublic abstract class StepRegistryPropertiesConfigAdapterTests<P extends StepRegistryProperties, A extends StepRegistryPropertiesConfigAdapter<P>>\n\t\textends PushRegistryPropertiesConfigAdapterTests<P, A> {\n\n\tprotected StepRegistryPropertiesConfigAdapterTests(Class<A> adapter) {\n\t\tsuper(adapter);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/properties/StepRegistryPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.properties;\n\nimport io.micrometer.core.instrument.step.StepRegistryConfig;\n\n/**\n * Base tests for {@link StepRegistryProperties} implementation.\n *\n * @author Stephane Nicoll\n */\npublic abstract class StepRegistryPropertiesTests extends PushRegistryPropertiesTests {\n\n\tprotected void assertStepRegistryDefaultValues(StepRegistryProperties properties, StepRegistryConfig config) {\n\t\tsuper.assertStepRegistryDefaultValues(properties, config);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/SimpleMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n *\n * Tests for {@link SimpleMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass SimpleMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SimpleMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SimpleMeterRegistry.class)\n\t\t\t\t.hasSingleBean(Clock.class)\n\t\t\t\t.hasSingleBean(SimpleConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SimpleMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(SimpleConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.simple.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SimpleMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(SimpleConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsConfigToBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SimpleConfig.class).hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid backsOffEntirelyWithCustomMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.doesNotHaveBean(SimpleConfig.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tSimpleConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tMeterRegistry customRegistry() {\n\t\t\treturn mock(MeterRegistry.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/SimplePropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport java.time.Duration;\n\nimport io.micrometer.core.instrument.simple.CountingMode;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SimplePropertiesConfigAdapter}.\n *\n * @author Mirko Sobeck\n */\nclass SimplePropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<SimpleProperties, SimplePropertiesConfigAdapter> {\n\n\tSimplePropertiesConfigAdapterTests() {\n\t\tsuper(SimplePropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tSimpleProperties properties = new SimpleProperties();\n\t\tproperties.setStep(Duration.ofSeconds(30));\n\t\tassertThat(new SimplePropertiesConfigAdapter(properties).step()).isEqualTo(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid whenPropertiesModeIsSetAdapterModeReturnsIt() {\n\t\tSimpleProperties properties = new SimpleProperties();\n\t\tproperties.setMode(CountingMode.STEP);\n\t\tassertThat(new SimplePropertiesConfigAdapter(properties).mode()).isEqualTo(CountingMode.STEP);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/simple/SimplePropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.simple;\n\nimport io.micrometer.core.instrument.simple.SimpleConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Stephane Nicoll\n */\nclass SimplePropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tSimpleProperties properties = new SimpleProperties();\n\t\tSimpleConfig config = SimpleConfig.DEFAULT;\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t\tassertThat(properties.getMode()).isEqualTo(config.mode());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/StackdriverMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.stackdriver.StackdriverConfig;\nimport io.micrometer.stackdriver.StackdriverMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StackdriverMetricsExportAutoConfiguration}.\n *\n * @author Johannes Graf\n */\nclass StackdriverMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(StackdriverMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid failsWithoutAProjectId() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasFailed());\n\t}\n\n\t@Test\n\tvoid autoConfiguresConfigAndMeterRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.stackdriver.metrics.export.project-id=test-project\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)\n\t\t\t\t.hasSingleBean(StackdriverConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(StackdriverConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.stackdriver.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(StackdriverMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(StackdriverConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)\n\t\t\t\t.hasSingleBean(StackdriverConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"management.stackdriver.metrics.export.project-id=test-project\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StackdriverMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(StackdriverConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"management.stackdriver.metrics.export.project-id=test-project\")\n\t\t\t.run((context) -> {\n\t\t\t\tStackdriverMeterRegistry registry = context.getBean(StackdriverMeterRegistry.class);\n\t\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\t\tcontext.close();\n\t\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tStackdriverConfig customConfig() {\n\t\t\treturn (key) -> {\n\t\t\t\tif (\"stackdriver.projectId\".equals(key)) {\n\t\t\t\t\treturn \"test-project\";\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tStackdriverMeterRegistry customRegistry(StackdriverConfig config, Clock clock) {\n\t\t\treturn new StackdriverMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/StackdriverPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StackdriverPropertiesConfigAdapter}.\n *\n * @author Johannes Graf\n */\nclass StackdriverPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<StackdriverProperties, StackdriverPropertiesConfigAdapter> {\n\n\tStackdriverPropertiesConfigAdapterTests() {\n\t\tsuper(StackdriverPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesProjectIdIsSetAdapterProjectIdReturnsIt() {\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tproperties.setProjectId(\"my-gcp-project-id\");\n\t\tassertThat(new StackdriverPropertiesConfigAdapter(properties).projectId()).isEqualTo(\"my-gcp-project-id\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesResourceTypeIsSetAdapterResourceTypeReturnsIt() {\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tproperties.setResourceType(\"my-resource-type\");\n\t\tassertThat(new StackdriverPropertiesConfigAdapter(properties).resourceType()).isEqualTo(\"my-resource-type\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesResourceLabelsAreSetAdapterResourceLabelsReturnsThem() {\n\t\tfinal Map<String, String> labels = new HashMap<>();\n\t\tlabels.put(\"labelOne\", \"valueOne\");\n\t\tlabels.put(\"labelTwo\", \"valueTwo\");\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tproperties.setResourceLabels(labels);\n\t\tassertThat(new StackdriverPropertiesConfigAdapter(properties).resourceLabels())\n\t\t\t.containsExactlyInAnyOrderEntriesOf(labels);\n\t}\n\n\t@Test\n\tvoid whenPropertiesUseSemanticMetricTypesIsSetAdapterUseSemanticMetricTypesReturnsIt() {\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tproperties.setUseSemanticMetricTypes(true);\n\t\tassertThat(new StackdriverPropertiesConfigAdapter(properties).useSemanticMetricTypes()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenPropertiesMetricTypePrefixIsSetAdapterMetricTypePrefixReturnsIt() {\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tproperties.setMetricTypePrefix(\"external.googleapis.com/prometheus\");\n\t\tassertThat(new StackdriverPropertiesConfigAdapter(properties).metricTypePrefix())\n\t\t\t.isEqualTo(\"external.googleapis.com/prometheus\");\n\t}\n\n\t@Test\n\tvoid whenPropertiesAutoCreateMetricDescriptorsIsSetAdapterAutoCreateMetricDescriptorsReturnsIt() {\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tproperties.setAutoCreateMetricDescriptors(false);\n\t\tassertThat(new StackdriverPropertiesConfigAdapter(properties).autoCreateMetricDescriptors()).isFalse();\n\t}\n\n\t@Test\n\t@Override\n\tprotected void adapterOverridesAllConfigMethods() {\n\t\tadapterOverridesAllConfigMethodsExcept(\"credentials\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/stackdriver/StackdriverPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.stackdriver;\n\nimport io.micrometer.stackdriver.StackdriverConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.StepRegistryPropertiesTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StackdriverProperties}.\n *\n * @author Johannes Graf\n */\nclass StackdriverPropertiesTests extends StepRegistryPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tStackdriverProperties properties = new StackdriverProperties();\n\t\tStackdriverConfig config = (key) -> null;\n\t\tassertStepRegistryDefaultValues(properties, config);\n\t\tassertThat(properties.getResourceType()).isEqualTo(config.resourceType());\n\t\tassertThat(properties.isUseSemanticMetricTypes()).isEqualTo(config.useSemanticMetricTypes());\n\t\tassertThat(properties.getMetricTypePrefix()).isEqualTo(config.metricTypePrefix());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/StatsdMetricsExportAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport io.micrometer.core.instrument.Clock;\nimport io.micrometer.statsd.StatsdConfig;\nimport io.micrometer.statsd.StatsdMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StatsdMetricsExportAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass StatsdMetricsExportAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(StatsdMetricsExportAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWithoutAClock() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(StatsdMeterRegistry.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresItsConfigMeterRegistryAndMetrics() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StatsdMeterRegistry.class)\n\t\t\t\t.hasSingleBean(StatsdConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithDefaultsEnabledProperty() {\n\t\tthis.contextRunner.withPropertyValues(\"management.defaults.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(StatsdMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(StatsdConfig.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationCanBeDisabledWithSpecificEnabledProperty() {\n\t\tthis.contextRunner.withPropertyValues(\"management.statsd.metrics.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(StatsdMeterRegistry.class)\n\t\t\t\t.doesNotHaveBean(StatsdConfig.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomConfigToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StatsdMeterRegistry.class)\n\t\t\t\t.hasSingleBean(StatsdConfig.class)\n\t\t\t\t.hasBean(\"customConfig\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomRegistryToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StatsdMeterRegistry.class)\n\t\t\t\t.hasBean(\"customRegistry\")\n\t\t\t\t.hasSingleBean(StatsdConfig.class));\n\t}\n\n\t@Test\n\tvoid stopsMeterRegistryWhenContextIsClosed() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tStatsdMeterRegistry registry = context.getBean(StatsdMeterRegistry.class);\n\t\t\tassertThat(registry.isClosed()).isFalse();\n\t\t\tcontext.close();\n\t\t\tassertThat(registry.isClosed()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tClock clock() {\n\t\t\treturn Clock.SYSTEM;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomConfigConfiguration {\n\n\t\t@Bean\n\t\tStatsdConfig customConfig() {\n\t\t\treturn (key) -> null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CustomRegistryConfiguration {\n\n\t\t@Bean\n\t\tStatsdMeterRegistry customRegistry(StatsdConfig config, Clock clock) {\n\t\t\treturn new StatsdMeterRegistry(config, clock);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/StatsdPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport java.time.Duration;\n\nimport io.micrometer.statsd.StatsdFlavor;\nimport io.micrometer.statsd.StatsdProtocol;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.metrics.export.properties.AbstractPropertiesConfigAdapterTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StatsdPropertiesConfigAdapter}.\n *\n * @author Johnny Lim\n */\nclass StatsdPropertiesConfigAdapterTests\n\t\textends AbstractPropertiesConfigAdapterTests<StatsdProperties, StatsdPropertiesConfigAdapter> {\n\n\tprotected StatsdPropertiesConfigAdapterTests() {\n\t\tsuper(StatsdPropertiesConfigAdapter.class);\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnabledIsSetAdapterEnabledReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setEnabled(false);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).enabled()).isEqualTo(properties.isEnabled());\n\t}\n\n\t@Test\n\tvoid whenPropertiesFlavorIsSetAdapterFlavorReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setFlavor(StatsdFlavor.ETSY);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).flavor()).isEqualTo(properties.getFlavor());\n\t}\n\n\t@Test\n\tvoid whenPropertiesHostIsSetAdapterHostReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setHost(\"my-host\");\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).host()).isEqualTo(properties.getHost());\n\t}\n\n\t@Test\n\tvoid whenPropertiesPortIsSetAdapterPortReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setPort(1234);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).port()).isEqualTo(properties.getPort());\n\t}\n\n\t@Test\n\tvoid whenPropertiesProtocolIsSetAdapterProtocolReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setProtocol(StatsdProtocol.TCP);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).protocol()).isEqualTo(properties.getProtocol());\n\t}\n\n\t@Test\n\tvoid whenPropertiesMaxPacketLengthIsSetAdapterMaxPacketLengthReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setMaxPacketLength(1234);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).maxPacketLength())\n\t\t\t.isEqualTo(properties.getMaxPacketLength());\n\t}\n\n\t@Test\n\tvoid whenPropertiesPollingFrequencyIsSetAdapterPollingFrequencyReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setPollingFrequency(Duration.ofSeconds(1));\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).pollingFrequency())\n\t\t\t.isEqualTo(properties.getPollingFrequency());\n\t}\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setStep(Duration.ofSeconds(1));\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).step()).isEqualTo(properties.getStep());\n\t}\n\n\t@Test\n\tvoid whenPropertiesPublishUnchangedMetersIsSetAdapterPublishUnchangedMetersReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setPublishUnchangedMeters(false);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).publishUnchangedMeters())\n\t\t\t.isEqualTo(properties.isPublishUnchangedMeters());\n\t}\n\n\t@Test\n\tvoid whenPropertiesBufferedIsSetAdapterBufferedReturnsIt() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tproperties.setBuffered(false);\n\t\tassertThat(new StatsdPropertiesConfigAdapter(properties).buffered()).isEqualTo(properties.isBuffered());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/export/statsd/StatsdPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.export.statsd;\n\nimport io.micrometer.statsd.StatsdConfig;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link StatsdProperties}.\n *\n * @author Stephane Nicoll\n */\nclass StatsdPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tStatsdProperties properties = new StatsdProperties();\n\t\tStatsdConfig config = StatsdConfig.DEFAULT;\n\t\tassertThat(properties.isEnabled()).isEqualTo(config.enabled());\n\t\tassertThat(properties.getFlavor()).isEqualTo(config.flavor());\n\t\tassertThat(properties.getHost()).isEqualTo(config.host());\n\t\tassertThat(properties.getPort()).isEqualTo(config.port());\n\t\tassertThat(properties.getProtocol()).isEqualTo(config.protocol());\n\t\tassertThat(properties.getMaxPacketLength()).isEqualTo(config.maxPacketLength());\n\t\tassertThat(properties.getPollingFrequency()).isEqualTo(config.pollingFrequency());\n\t\tassertThat(properties.getStep()).isEqualTo(config.step());\n\t\tassertThat(properties.isPublishUnchangedMeters()).isEqualTo(config.publishUnchangedMeters());\n\t\tassertThat(properties.isBuffered()).isEqualTo(config.buffered());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/jvm/JvmMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.jvm;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmGcMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmInfoMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;\nimport io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmClassLoadingMeterConventions;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmMemoryMeterConventions;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmThreadMeterConventions;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JvmMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n */\nclass JvmMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(MeterRegistry.class, () -> new SimpleMeterRegistry())\n\t\t.withConfiguration(AutoConfigurations.of(JvmMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresJvmMetrics() {\n\t\tthis.contextRunner.run(assertMetricsBeans());\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmGcMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJvmGcMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean(\"customJvmGcMetrics\")));\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmHeapPressureMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJvmHeapPressureMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans()\n\t\t\t\t.andThen((context) -> assertThat(context).hasBean(\"customJvmHeapPressureMetrics\")));\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmMemoryMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJvmMemoryMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean(\"customJvmMemoryMetrics\")));\n\t}\n\n\t@Test\n\tvoid allowCustomJvmMemoryMeterConventionsToBeUsed() {\n\t\tJvmMemoryMeterConventions jvmMemoryMeterConventions = mock(JvmMemoryMeterConventions.class);\n\t\tthis.contextRunner.withBean(JvmMemoryMeterConventions.class, () -> jvmMemoryMeterConventions)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JvmMemoryMetrics.class)\n\t\t\t\t.getBean(JvmMemoryMetrics.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"conventions\", jvmMemoryMeterConventions));\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmThreadMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJvmThreadMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean(\"customJvmThreadMetrics\")));\n\t}\n\n\t@Test\n\tvoid allowCustomJvmThreadMeterConventionsToBeUsed() {\n\t\tJvmThreadMeterConventions jvmThreadMeterConventions = mock(JvmThreadMeterConventions.class);\n\t\tthis.contextRunner.withBean(JvmThreadMeterConventions.class, () -> jvmThreadMeterConventions)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JvmThreadMetrics.class)\n\t\t\t\t.getBean(JvmThreadMetrics.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"conventions\", jvmThreadMeterConventions));\n\t}\n\n\t@Test\n\tvoid allowsCustomClassLoaderMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomClassLoaderMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean(\"customClassLoaderMetrics\")));\n\t}\n\n\t@Test\n\tvoid allowCustomJvmClassLoadingMeterConventionsToBeUsed() {\n\t\tJvmClassLoadingMeterConventions jvmClassLoadingMeterConventions = mock(JvmClassLoadingMeterConventions.class);\n\t\tthis.contextRunner.withBean(JvmClassLoadingMeterConventions.class, () -> jvmClassLoadingMeterConventions)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ClassLoaderMetrics.class)\n\t\t\t\t.getBean(ClassLoaderMetrics.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"conventions\", jvmClassLoadingMeterConventions));\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmInfoMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJvmInfoMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean(\"customJvmInfoMetrics\")));\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmCompilationMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJvmCompilationMetricsConfiguration.class)\n\t\t\t.run(assertMetricsBeans().andThen((context) -> assertThat(context).hasBean(\"customJvmCompilationMetrics\")));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid autoConfiguresJvmMetricsWithVirtualThreadsMetrics() {\n\t\tthis.contextRunner.run(assertMetricsBeans()\n\t\t\t.andThen((context) -> assertThat(context).hasSingleBean(getVirtualThreadMetricsClass())));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid allowCustomVirtualThreadMetricsToBeUsed() {\n\t\tClass<MeterBinder> virtualThreadMetricsClass = getVirtualThreadMetricsClass();\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customVirtualThreadMetrics\", virtualThreadMetricsClass,\n\t\t\t\t\t() -> BeanUtils.instantiateClass(virtualThreadMetricsClass))\n\t\t\t.run(assertMetricsBeans()\n\t\t\t\t.andThen((context) -> assertThat(context).hasSingleBean(getVirtualThreadMetricsClass())\n\t\t\t\t\t.hasBean(\"customVirtualThreadMetrics\")));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldRegisterVirtualThreadMetricsRuntimeHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew JvmMetricsAutoConfiguration.VirtualThreadMetricsRuntimeHintsRegistrar().registerHints(hints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference.of(getVirtualThreadMetricsClass()))\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)).accepts(hints);\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertMetricsBeans() {\n\t\treturn (context) -> assertThat(context).hasSingleBean(JvmGcMetrics.class)\n\t\t\t.hasSingleBean(JvmHeapPressureMetrics.class)\n\t\t\t.hasSingleBean(JvmMemoryMetrics.class)\n\t\t\t.hasSingleBean(JvmThreadMetrics.class)\n\t\t\t.hasSingleBean(ClassLoaderMetrics.class)\n\t\t\t.hasSingleBean(JvmInfoMetrics.class)\n\t\t\t.hasSingleBean(JvmCompilationMetrics.class);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static Class<MeterBinder> getVirtualThreadMetricsClass() {\n\t\treturn (Class<MeterBinder>) ClassUtils\n\t\t\t.resolveClassName(\"io.micrometer.java21.instrument.binder.jdk.VirtualThreadMetrics\", null);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJvmGcMetricsConfiguration {\n\n\t\t@Bean\n\t\tJvmGcMetrics customJvmGcMetrics() {\n\t\t\treturn new JvmGcMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJvmHeapPressureMetricsConfiguration {\n\n\t\t@Bean\n\t\tJvmHeapPressureMetrics customJvmHeapPressureMetrics() {\n\t\t\treturn new JvmHeapPressureMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJvmMemoryMetricsConfiguration {\n\n\t\t@Bean\n\t\tJvmMemoryMetrics customJvmMemoryMetrics() {\n\t\t\treturn new JvmMemoryMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJvmThreadMetricsConfiguration {\n\n\t\t@Bean\n\t\tJvmThreadMetrics customJvmThreadMetrics() {\n\t\t\treturn new JvmThreadMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomClassLoaderMetricsConfiguration {\n\n\t\t@Bean\n\t\tClassLoaderMetrics customClassLoaderMetrics() {\n\t\t\treturn new ClassLoaderMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJvmInfoMetricsConfiguration {\n\n\t\t@Bean\n\t\tJvmInfoMetrics customJvmInfoMetrics() {\n\t\t\treturn new JvmInfoMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJvmCompilationMetricsConfiguration {\n\n\t\t@Bean\n\t\tJvmCompilationMetrics customJvmCompilationMetrics() {\n\t\t\treturn new JvmCompilationMetrics();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/log4j2/Log4J2MetricsWithLog4jLoggerContextAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.log4j2;\n\nimport io.micrometer.core.instrument.binder.logging.Log4j2Metrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.apache.logging.log4j.LogManager;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.logging.ConfigureClasspathToPreferLog4j2;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Log4J2MetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\n@ConfigureClasspathToPreferLog4j2\nclass Log4J2MetricsWithLog4jLoggerContextAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t.withConfiguration(AutoConfigurations.of(Log4J2MetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresLog4J2Metrics() {\n\t\tassertThat(LogManager.getContext().getClass().getName())\n\t\t\t.isEqualTo(\"org.apache.logging.log4j.core.LoggerContext\");\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomLog4J2MetricsToBeUsed() {\n\t\tassertThat(LogManager.getContext().getClass().getName())\n\t\t\t.isEqualTo(\"org.apache.logging.log4j.core.LoggerContext\");\n\t\tthis.contextRunner.withUserConfiguration(CustomLog4J2MetricsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class).hasBean(\"customLog4J2Metrics\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomLog4J2MetricsConfiguration {\n\n\t\t@Bean\n\t\tLog4j2Metrics customLog4J2Metrics() {\n\t\t\treturn new Log4j2Metrics();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/log4j2/Log4J2MetricsWithSlf4jLoggerContextAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.log4j2;\n\nimport io.micrometer.core.instrument.binder.logging.Log4j2Metrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.slf4j.SLF4JLoggerContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Log4J2MetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass Log4J2MetricsWithSlf4jLoggerContextAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t.withConfiguration(AutoConfigurations.of(Log4J2MetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWhenLoggerContextIsBackedBySlf4j() {\n\t\tassertThat(LogManager.getContext()).isInstanceOf(SLF4JLoggerContext.class);\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Log4j2Metrics.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/logback/LogbackMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.logback;\n\nimport io.micrometer.core.instrument.binder.logging.LogbackMetrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LogbackMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass LogbackMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresLogbackMetrics() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(LogbackMetrics.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomLogbackMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomLogbackMetricsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(LogbackMetrics.class).hasBean(\"customLogbackMetrics\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomLogbackMetricsConfiguration {\n\n\t\t@Bean\n\t\tLogbackMetrics customLogbackMetrics() {\n\t\t\treturn new LogbackMetrics();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/logging/logback/LogbackMetricsAutoConfigurationWithLog4j2AndLogbackTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.logging.logback;\n\nimport io.micrometer.core.instrument.binder.logging.LogbackMetrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.logging.ConfigureClasspathToPreferLog4j2;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LogbackMetricsAutoConfiguration} when both Log4j2 and Logback are on\n * the classpath.\n *\n * @author Andy Wilkinson\n */\n@ConfigureClasspathToPreferLog4j2\nclass LogbackMetricsAutoConfigurationWithLog4j2AndLogbackTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t.withConfiguration(AutoConfigurations.of(LogbackMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid doesNotConfigureLogbackMetrics() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(LogbackMetrics.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/ssl/SslMeterBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.ssl;\n\nimport java.time.Clock;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.ZoneId;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.info.SslInfo;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslMeterBinder}.\n *\n * @author Moritz Halbritter\n */\nclass SslMeterBinderTests {\n\n\tprivate static final Clock CLOCK = Clock.fixed(Instant.parse(\"2024-10-21T13:51:40Z\"), ZoneId.of(\"UTC\"));\n\n\t@Test\n\tvoid shouldRegisterChainExpiryMetrics() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = createSslBundleRegistry(\"classpath:certificates/chains.p12\");\n\t\tMeterRegistry meterRegistry = bindToRegistry(sslBundleRegistry);\n\t\tassertThat(Duration.ofSeconds(findExpiryGauge(meterRegistry, \"ca\", \"419224ce190242b2c44069dd3c560192b3b669f3\")))\n\t\t\t.hasDays(1095);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"intermediary\", \"60f79365fc46bf69149754d377680192b3b6bcf5\")))\n\t\t\t.hasDays(730);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"server\", \"504c45129526ac050abb11459b1f0192b3b70fe9\")))\n\t\t\t.hasDays(365);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"expired\", \"562bc5dcf4f26bb179abb13068180192b3bb53dc\")))\n\t\t\t.hasDays(-386);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"not-yet-valid\", \"7df79335f274e2cfa7467fd5f9ce0192b3bcf4aa\")))\n\t\t\t.hasDays(36889);\n\t}\n\n\t@Test\n\tvoid shouldWatchUpdatesForBundlesRegisteredAfterConstruction() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tsslBundleRegistry.registerBundle(\"dummy\",\n\t\t\t\tSslBundle.of(createSslStoreBundle(\"classpath:certificates/chains2.p12\")));\n\t\tMeterRegistry meterRegistry = bindToRegistry(sslBundleRegistry);\n\t\tsslBundleRegistry.registerBundle(\"test-0\",\n\t\t\t\tSslBundle.of(createSslStoreBundle(\"classpath:certificates/chains2.p12\")));\n\t\tsslBundleRegistry.updateBundle(\"test-0\",\n\t\t\t\tSslBundle.of(createSslStoreBundle(\"classpath:certificates/chains.p12\")));\n\t\tassertThat(Duration.ofSeconds(findExpiryGauge(meterRegistry, \"ca\", \"419224ce190242b2c44069dd3c560192b3b669f3\")))\n\t\t\t.hasDays(1095);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"intermediary\", \"60f79365fc46bf69149754d377680192b3b6bcf5\")))\n\t\t\t.hasDays(730);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"server\", \"504c45129526ac050abb11459b1f0192b3b70fe9\")))\n\t\t\t.hasDays(365);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"expired\", \"562bc5dcf4f26bb179abb13068180192b3bb53dc\")))\n\t\t\t.hasDays(-386);\n\t\tassertThat(Duration\n\t\t\t.ofSeconds(findExpiryGauge(meterRegistry, \"not-yet-valid\", \"7df79335f274e2cfa7467fd5f9ce0192b3bcf4aa\")))\n\t\t\t.hasDays(36889);\n\t}\n\n\t@Test\n\tvoid shouldRegisterMetricsIfNoBundleExistsAtBindTime() {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tMeterRegistry meterRegistry = bindToRegistry(sslBundleRegistry);\n\t\tsslBundleRegistry.registerBundle(\"dummy\",\n\t\t\t\tSslBundle.of(createSslStoreBundle(\"classpath:certificates/chains.p12\")));\n\t\tassertThat(meterRegistry.getMeters()).isNotEmpty();\n\t}\n\n\tprivate long findExpiryGauge(MeterRegistry meterRegistry, String chain, String certificateSerialNumber) {\n\t\treturn (long) meterRegistry.get(\"ssl.chain.expiry\")\n\t\t\t.tag(\"bundle\", \"test-0\")\n\t\t\t.tag(\"chain\", chain)\n\t\t\t.tag(\"certificate\", certificateSerialNumber)\n\t\t\t.gauge()\n\t\t\t.value();\n\t}\n\n\tprivate SimpleMeterRegistry bindToRegistry(SslBundles sslBundles) {\n\t\tSslInfo sslInfo = new SslInfo(sslBundles);\n\t\tSslMeterBinder binder = new SslMeterBinder(sslInfo, sslBundles, CLOCK);\n\t\tSimpleMeterRegistry meterRegistry = new SimpleMeterRegistry();\n\t\tbinder.bindTo(meterRegistry);\n\t\treturn meterRegistry;\n\t}\n\n\tprivate SslStoreBundle createSslStoreBundle(String location) {\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(location).withPassword(\"secret\");\n\t\treturn new JksSslStoreBundle(keyStoreDetails, null);\n\t}\n\n\tprivate DefaultSslBundleRegistry createSslBundleRegistry(String... locations) {\n\t\tDefaultSslBundleRegistry sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tfor (int i = 0; i < locations.length; i++) {\n\t\t\tSslStoreBundle sslStoreBundle = createSslStoreBundle(locations[i]);\n\t\t\tsslBundleRegistry.registerBundle(\"test-%d\".formatted(i), SslBundle.of(sslStoreBundle));\n\t\t}\n\t\treturn sslBundleRegistry;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/ssl/SslMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.ssl;\n\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SslMetricsAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass SslMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SslMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyMeterBinder() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withBean(SimpleMeterRegistry.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SslMeterBinder.class));\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfSslBundlesIsMissing() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SslMeterBinder.class));\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfMeterRegistryIsMissing() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SslMeterBinder.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/startup/StartupTimeMetricsListenerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.startup;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.TimeGauge;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.startup.StartupTimeMetricsListener;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StartupTimeMetricsListenerAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Stephane Nicoll\n */\nclass StartupTimeMetricsListenerAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class,\n\t\t\t\tStartupTimeMetricsListenerAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid startupTimeMetricsAreRecorded() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(StartupTimeMetricsListener.class);\n\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\tcontext.publishEvent(new ApplicationStartedEvent(new SpringApplication(), new String[0],\n\t\t\t\t\tcontext.getSourceApplicationContext(), Duration.ofMillis(1500)));\n\t\t\tTimeGauge startedTimeGage = registry.find(\"application.started.time\").timeGauge();\n\t\t\tassertThat(startedTimeGage).isNotNull();\n\t\t\tassertThat(startedTimeGage.value(TimeUnit.MILLISECONDS)).isEqualTo(1500L);\n\t\t\tcontext.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0],\n\t\t\t\t\tcontext.getSourceApplicationContext(), Duration.ofMillis(2000)));\n\t\t\tTimeGauge readyTimeGage = registry.find(\"application.ready.time\").timeGauge();\n\t\t\tassertThat(readyTimeGage).isNotNull();\n\t\t\tassertThat(readyTimeGage.value(TimeUnit.MILLISECONDS)).isEqualTo(2000L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid startupTimeMetricsCanBeDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.metrics.enable.application.started.time:false\",\n\t\t\t\t\t\"management.metrics.enable.application.ready.time:false\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(new ApplicationStartedEvent(new SpringApplication(), new String[0],\n\t\t\t\t\t\tcontext.getSourceApplicationContext(), Duration.ofMillis(2500)));\n\t\t\t\tcontext.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0],\n\t\t\t\t\t\tcontext.getSourceApplicationContext(), Duration.ofMillis(3000)));\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"application.started.time\").timeGauge()).isNull();\n\t\t\t\tassertThat(registry.find(\"application.ready.time\").timeGauge()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customStartupTimeMetricsAreRespected() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customStartupTimeMetrics\", StartupTimeMetricsListener.class,\n\t\t\t\t\t() -> mock(StartupTimeMetricsListener.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(StartupTimeMetricsListener.class)\n\t\t\t\t.hasBean(\"customStartupTimeMetrics\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/system/SystemMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.system;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.binder.jvm.convention.JvmCpuMeterConventions;\nimport io.micrometer.core.instrument.binder.system.FileDescriptorMetrics;\nimport io.micrometer.core.instrument.binder.system.ProcessorMetrics;\nimport io.micrometer.core.instrument.binder.system.UptimeMetrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.system.DiskSpaceMetricsBinder;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SystemMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Chris Bono\n */\nclass SystemMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class, SimpleMeterRegistry::new)\n\t\t.withConfiguration(AutoConfigurations.of(SystemMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresUptimeMetrics() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(UptimeMetrics.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomUptimeMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomUptimeMetricsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(UptimeMetrics.class).hasBean(\"customUptimeMetrics\"));\n\t}\n\n\t@Test\n\tvoid autoConfiguresProcessorMetrics() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomProcessorMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomProcessorMetricsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class)\n\t\t\t\t.hasBean(\"customProcessorMetrics\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomJvmCpuMeterConventionsToBeUsed() {\n\t\tJvmCpuMeterConventions jvmCpuMeterConventions = mock(JvmCpuMeterConventions.class);\n\t\tthis.contextRunner.withBean(JvmCpuMeterConventions.class, () -> jvmCpuMeterConventions)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ProcessorMetrics.class)\n\t\t\t\t.getBean(ProcessorMetrics.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"conventions\", jvmCpuMeterConventions));\n\t}\n\n\t@Test\n\tvoid autoConfiguresFileDescriptorMetrics() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(FileDescriptorMetrics.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomFileDescriptorMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomFileDescriptorMetricsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(FileDescriptorMetrics.class)\n\t\t\t\t.hasBean(\"customFileDescriptorMetrics\"));\n\t}\n\n\t@Test\n\tvoid autoConfiguresDiskSpaceMetrics() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(DiskSpaceMetricsBinder.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomDiskSpaceMetricsToBeUsed() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDiskSpaceMetricsConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DiskSpaceMetricsBinder.class)\n\t\t\t\t.hasBean(\"customDiskSpaceMetrics\"));\n\t}\n\n\t@Test\n\tvoid diskSpaceMetricsUsesDefaultPath() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasBean(\"diskSpaceMetrics\")\n\t\t\t.getBean(DiskSpaceMetricsBinder.class)\n\t\t\t.hasFieldOrPropertyWithValue(\"paths\", Collections.singletonList(new File(\".\"))));\n\t}\n\n\t@Test\n\tvoid allowsDiskSpaceMetricsPathToBeConfiguredWithSinglePath() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.system.diskspace.paths:..\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"diskSpaceMetrics\")\n\t\t\t\t.getBean(DiskSpaceMetricsBinder.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"paths\", Collections.singletonList(new File(\"..\"))));\n\t}\n\n\t@Test\n\tvoid allowsDiskSpaceMetricsPathToBeConfiguredWithMultiplePaths() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.system.diskspace.paths:.,..\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"diskSpaceMetrics\")\n\t\t\t\t.getBean(DiskSpaceMetricsBinder.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"paths\", Arrays.asList(new File(\".\"), new File(\"..\"))));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomUptimeMetricsConfiguration {\n\n\t\t@Bean\n\t\tUptimeMetrics customUptimeMetrics() {\n\t\t\treturn new UptimeMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomProcessorMetricsConfiguration {\n\n\t\t@Bean\n\t\tProcessorMetrics customProcessorMetrics() {\n\t\t\treturn new ProcessorMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFileDescriptorMetricsConfiguration {\n\n\t\t@Bean\n\t\tFileDescriptorMetrics customFileDescriptorMetrics() {\n\t\t\treturn new FileDescriptorMetrics();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDiskSpaceMetricsConfiguration {\n\n\t\t@Bean\n\t\tDiskSpaceMetricsBinder customDiskSpaceMetrics() {\n\t\t\treturn new DiskSpaceMetricsBinder(Collections.singletonList(new File(System.getProperty(\"user.dir\"))),\n\t\t\t\t\tTags.empty());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/autoconfigure/task/TaskExecutorMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.autoconfigure.task;\n\nimport java.util.Collection;\n\nimport io.micrometer.core.instrument.FunctionCounter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.search.MeterNotFoundException;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TaskExecutorMetricsAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass TaskExecutorMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(TaskExecutorMetricsAutoConfiguration.class, MetricsAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.metrics.use-global-registry=false\");\n\n\t@Test\n\tvoid taskExecutorUsingAutoConfigurationIsInstrumented() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\t\tassertThat(meters).singleElement()\n\t\t\t\t\t.satisfies(\n\t\t\t\t\t\t\t(meter) -> assertThat(meter.getId().getTag(\"name\")).isEqualTo(\"applicationTaskExecutor\"));\n\t\t\t\tassertThatExceptionOfType(MeterNotFoundException.class)\n\t\t\t\t\t.isThrownBy(() -> registry.get(\"executor\").timer());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskExecutorIsInstrumentedWhenUsingLazyInitialization() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.withBean(LazyInitializationBeanFactoryPostProcessor.class)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\t\tassertThat(meters).singleElement()\n\t\t\t\t\t.satisfies(\n\t\t\t\t\t\t\t(meter) -> assertThat(meter.getId().getTag(\"name\")).isEqualTo(\"applicationTaskExecutor\"));\n\t\t\t\tassertThatExceptionOfType(MeterNotFoundException.class)\n\t\t\t\t\t.isThrownBy(() -> registry.get(\"executor\").timer());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskExecutorsWithCustomNamesAreInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleTaskExecutorsConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\tassertThat(meters).map((meter) -> meter.getId().getTag(\"name\"))\n\t\t\t\t.containsExactlyInAnyOrder(\"standardTaskExecutor\", \"nonDefault\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid threadPoolTaskExecutorWithNoTaskExecutorIsIgnored() {\n\t\tThreadPoolTaskExecutor unavailableTaskExecutor = mock(ThreadPoolTaskExecutor.class);\n\t\tgiven(unavailableTaskExecutor.getThreadPoolExecutor()).willThrow(new IllegalStateException(\"Test\"));\n\t\tthis.contextRunner.withBean(\"firstTaskExecutor\", ThreadPoolTaskExecutor.class, ThreadPoolTaskExecutor::new)\n\t\t\t.withBean(\"customName\", ThreadPoolTaskExecutor.class, () -> unavailableTaskExecutor)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\t\tassertThat(meters).singleElement()\n\t\t\t\t\t.satisfies((meter) -> assertThat(meter.getId().getTag(\"name\")).isEqualTo(\"firstTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskExecutorInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.enable.executor=false\")\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(\n\t\t\t\t\t\tregistry.find(\"executor.completed\").tags(\"name\", \"applicationTaskExecutor\").functionCounter())\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskSchedulerUsingAutoConfigurationIsInstrumented() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.withUserConfiguration(SchedulingTestConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\t\tassertThat(meters).singleElement()\n\t\t\t\t\t.satisfies((meter) -> assertThat(meter.getId().getTag(\"name\")).isEqualTo(\"taskScheduler\"));\n\t\t\t\tassertThatExceptionOfType(MeterNotFoundException.class)\n\t\t\t\t\t.isThrownBy(() -> registry.get(\"executor\").timer());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskSchedulersWithCustomNamesAreInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleTaskSchedulersConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\tassertThat(meters).map((meter) -> meter.getId().getTag(\"name\"))\n\t\t\t\t.containsExactlyInAnyOrder(\"standardTaskScheduler\", \"nonDefault\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid threadPoolTaskSchedulerWithNoTaskExecutorIsIgnored() {\n\t\tThreadPoolTaskScheduler unavailableTaskExecutor = mock(ThreadPoolTaskScheduler.class);\n\t\tgiven(unavailableTaskExecutor.getScheduledThreadPoolExecutor()).willThrow(new IllegalStateException(\"Test\"));\n\t\tthis.contextRunner.withBean(\"firstTaskScheduler\", ThreadPoolTaskScheduler.class, ThreadPoolTaskScheduler::new)\n\t\t\t.withBean(\"customName\", ThreadPoolTaskScheduler.class, () -> unavailableTaskExecutor)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tCollection<FunctionCounter> meters = registry.get(\"executor.completed\").functionCounters();\n\t\t\t\tassertThat(meters).singleElement()\n\t\t\t\t\t.satisfies((meter) -> assertThat(meter.getId().getTag(\"name\")).isEqualTo(\"firstTaskScheduler\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid taskSchedulerInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.metrics.enable.executor=false\")\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskSchedulingAutoConfiguration.class))\n\t\t\t.withUserConfiguration(SchedulingTestConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"executor.completed\").tags(\"name\", \"taskScheduler\").functionCounter())\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableScheduling\n\tstatic class SchedulingTestConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleTaskSchedulersConfiguration {\n\n\t\t@Bean\n\t\tThreadPoolTaskScheduler standardTaskScheduler() {\n\t\t\treturn new ThreadPoolTaskScheduler();\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tThreadPoolTaskScheduler nonDefault() {\n\t\t\treturn new ThreadPoolTaskScheduler();\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tThreadPoolTaskScheduler nonAutowire() {\n\t\t\treturn new ThreadPoolTaskScheduler();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleTaskExecutorsConfiguration {\n\n\t\t@Bean\n\t\tThreadPoolTaskExecutor standardTaskExecutor() {\n\t\t\treturn new ThreadPoolTaskExecutor();\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tThreadPoolTaskExecutor nonDefault() {\n\t\t\treturn new ThreadPoolTaskExecutor();\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tThreadPoolTaskExecutor nonAutowire() {\n\t\t\treturn new ThreadPoolTaskExecutor();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/export/prometheus/PrometheusPushGatewayManagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.export.prometheus;\n\nimport java.time.Duration;\nimport java.util.concurrent.ScheduledFuture;\n\nimport io.prometheus.metrics.exporter.pushgateway.PushGateway;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager.PushGatewayTaskScheduler;\nimport org.springframework.boot.micrometer.metrics.export.prometheus.PrometheusPushGatewayManager.ShutdownOperation;\nimport org.springframework.scheduling.TaskScheduler;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link PrometheusPushGatewayManager}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass PrometheusPushGatewayManagerTests {\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate PushGateway pushGateway;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate TaskScheduler scheduler;\n\n\tprivate final Duration pushRate = Duration.ofSeconds(1);\n\n\t@Captor\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ArgumentCaptor<Runnable> task;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ScheduledFuture<Object> future;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPushGatewayIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PrometheusPushGatewayManager(null, this.scheduler, this.pushRate, null))\n\t\t\t.withMessage(\"'pushGateway' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenSchedulerIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PrometheusPushGatewayManager(this.pushGateway, null, this.pushRate, null))\n\t\t\t.withMessage(\"'scheduler' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPushRateIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new PrometheusPushGatewayManager(this.pushGateway, this.scheduler, null, null))\n\t\t\t.withMessage(\"'pushRate' must not be null\");\n\t}\n\n\t@Test\n\tvoid createShouldSchedulePushAsFixedRate() throws Exception {\n\t\tnew PrometheusPushGatewayManager(this.pushGateway, this.scheduler, this.pushRate, null);\n\t\tthen(this.scheduler).should().scheduleAtFixedRate(this.task.capture(), eq(this.pushRate));\n\t\tthis.task.getValue().run();\n\t\tthen(this.pushGateway).should().pushAdd();\n\t}\n\n\t@Test\n\tvoid shutdownWhenOwnsSchedulerDoesShutDownScheduler() {\n\t\tPushGatewayTaskScheduler ownedScheduler = givenScheduleAtFixedRateWillReturnFuture(\n\t\t\t\tmock(PushGatewayTaskScheduler.class));\n\t\tPrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, ownedScheduler,\n\t\t\t\tthis.pushRate, null);\n\t\tmanager.shutdown();\n\t\tthen(ownedScheduler).should().shutdown();\n\t}\n\n\t@Test\n\tvoid shutdownWhenDoesNotOwnSchedulerDoesNotShutDownScheduler() {\n\t\tThreadPoolTaskScheduler otherScheduler = givenScheduleAtFixedRateWillReturnFuture(\n\t\t\t\tmock(ThreadPoolTaskScheduler.class));\n\t\tPrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, otherScheduler,\n\t\t\t\tthis.pushRate, null);\n\t\tmanager.shutdown();\n\t\tthen(otherScheduler).should(never()).shutdown();\n\t}\n\n\t@Test\n\tvoid shutdownWhenShutdownOperationIsPostPerformsPushAddOnShutdown() throws Exception {\n\t\tgivenScheduleAtFixedRateWithReturnFuture();\n\t\tPrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, this.scheduler,\n\t\t\t\tthis.pushRate, ShutdownOperation.POST);\n\t\tmanager.shutdown();\n\t\tthen(this.future).should().cancel(false);\n\t\tthen(this.pushGateway).should().pushAdd();\n\t}\n\n\t@Test\n\tvoid shutdownWhenShutdownOperationIsPutPerformsPushOnShutdown() throws Exception {\n\t\tgivenScheduleAtFixedRateWithReturnFuture();\n\t\tPrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, this.scheduler,\n\t\t\t\tthis.pushRate, ShutdownOperation.PUT);\n\t\tmanager.shutdown();\n\t\tthen(this.future).should().cancel(false);\n\t\tthen(this.pushGateway).should().push();\n\t}\n\n\t@Test\n\tvoid shutdownWhenShutdownOperationIsDeletePerformsDeleteOnShutdown() throws Exception {\n\t\tgivenScheduleAtFixedRateWithReturnFuture();\n\t\tPrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, this.scheduler,\n\t\t\t\tthis.pushRate, ShutdownOperation.DELETE);\n\t\tmanager.shutdown();\n\t\tthen(this.future).should().cancel(false);\n\t\tthen(this.pushGateway).should().delete();\n\t}\n\n\t@Test\n\tvoid shutdownWhenShutdownOperationIsNoneDoesNothing() {\n\t\tgivenScheduleAtFixedRateWithReturnFuture();\n\t\tPrometheusPushGatewayManager manager = new PrometheusPushGatewayManager(this.pushGateway, this.scheduler,\n\t\t\t\tthis.pushRate, ShutdownOperation.NONE);\n\t\tmanager.shutdown();\n\t\tthen(this.future).should().cancel(false);\n\t\tthen(this.pushGateway).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid pushDoesNotThrowException() throws Exception {\n\t\tnew PrometheusPushGatewayManager(this.pushGateway, this.scheduler, this.pushRate, null);\n\t\tthen(this.scheduler).should().scheduleAtFixedRate(this.task.capture(), eq(this.pushRate));\n\t\twillThrow(RuntimeException.class).given(this.pushGateway).pushAdd();\n\t\tthis.task.getValue().run();\n\t}\n\n\tprivate void givenScheduleAtFixedRateWithReturnFuture() {\n\t\tgivenScheduleAtFixedRateWillReturnFuture(this.scheduler);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate <T extends TaskScheduler> T givenScheduleAtFixedRateWillReturnFuture(T scheduler) {\n\t\tgiven(scheduler.scheduleAtFixedRate(isA(Runnable.class), isA(Duration.class)))\n\t\t\t.willReturn((ScheduledFuture) this.future);\n\t\treturn scheduler;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/startup/StartupTimeMetricsListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.startup;\n\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.TimeGauge;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StartupTimeMetricsListener}.\n *\n * @author Chris Bono\n */\nclass StartupTimeMetricsListenerTests {\n\n\tprivate MeterRegistry registry;\n\n\tprivate StartupTimeMetricsListener listener;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.registry = new SimpleMeterRegistry();\n\t\tthis.listener = new StartupTimeMetricsListener(this.registry);\n\t}\n\n\t@Test\n\tvoid metricsRecordedWithoutCustomTags() {\n\t\tthis.listener.onApplicationEvent(applicationStartedEvent(2000L));\n\t\tthis.listener.onApplicationEvent(applicationReadyEvent(2200L));\n\t\tassertMetricExistsWithValue(\"application.started.time\", 2000L);\n\t\tassertMetricExistsWithValue(\"application.ready.time\", 2200L);\n\t}\n\n\t@Test\n\tvoid metricsRecordedWithCustomTagsAndMetricNames() {\n\t\tTags tags = Tags.of(\"foo\", \"bar\");\n\t\tthis.listener = new StartupTimeMetricsListener(this.registry, \"m1\", \"m2\", tags);\n\t\tthis.listener.onApplicationEvent(applicationStartedEvent(1000L));\n\t\tthis.listener.onApplicationEvent(applicationReadyEvent(1050L));\n\t\tassertMetricExistsWithCustomTagsAndValue(\"m1\", tags, 1000L);\n\t\tassertMetricExistsWithCustomTagsAndValue(\"m2\", tags, 1050L);\n\t}\n\n\t@Test\n\tvoid metricRecordedWithoutMainAppClassTag() {\n\t\tSpringApplication application = mock(SpringApplication.class);\n\t\tthis.listener.onApplicationEvent(new ApplicationStartedEvent(application, new String[0],\n\t\t\t\tmock(ConfigurableApplicationContext.class), Duration.ofSeconds(2)));\n\t\tTimeGauge applicationStartedGauge = this.registry.find(\"application.started.time\").timeGauge();\n\t\tassertThat(applicationStartedGauge).isNotNull();\n\t\tassertThat(applicationStartedGauge.getId().getTags()).isEmpty();\n\t}\n\n\t@Test\n\tvoid metricRecordedWithoutMainAppClassTagAndAdditionalTags() {\n\t\tSpringApplication application = mock(SpringApplication.class);\n\t\tTags tags = Tags.of(\"foo\", \"bar\");\n\t\tthis.listener = new StartupTimeMetricsListener(this.registry, \"started\", \"ready\", tags);\n\t\tthis.listener.onApplicationEvent(new ApplicationReadyEvent(application, new String[0],\n\t\t\t\tmock(ConfigurableApplicationContext.class), Duration.ofSeconds(2)));\n\t\tTimeGauge applicationReadyGauge = this.registry.find(\"ready\").timeGauge();\n\t\tassertThat(applicationReadyGauge).isNotNull();\n\t\tassertThat(applicationReadyGauge.getId().getTags()).containsExactlyElementsOf(tags);\n\t}\n\n\t@Test\n\tvoid metricsNotRecordedWhenStartupTimeNotAvailable() {\n\t\tthis.listener.onApplicationEvent(applicationStartedEvent(null));\n\t\tthis.listener.onApplicationEvent(applicationReadyEvent(null));\n\t\tassertThat(this.registry.find(\"application.started.time\").timeGauge()).isNull();\n\t\tassertThat(this.registry.find(\"application.ready.time\").timeGauge()).isNull();\n\t}\n\n\tprivate ApplicationStartedEvent applicationStartedEvent(@Nullable Long startupTimeMs) {\n\t\tSpringApplication application = mock(SpringApplication.class);\n\t\tgiven(application.getMainApplicationClass()).willAnswer((invocation) -> TestMainApplication.class);\n\t\treturn new ApplicationStartedEvent(application, new String[0], mock(ConfigurableApplicationContext.class),\n\t\t\t\t(startupTimeMs != null) ? Duration.ofMillis(startupTimeMs) : null);\n\t}\n\n\tprivate ApplicationReadyEvent applicationReadyEvent(@Nullable Long startupTimeMs) {\n\t\tSpringApplication application = mock(SpringApplication.class);\n\t\tgiven(application.getMainApplicationClass()).willAnswer((invocation) -> TestMainApplication.class);\n\t\treturn new ApplicationReadyEvent(application, new String[0], mock(ConfigurableApplicationContext.class),\n\t\t\t\t(startupTimeMs != null) ? Duration.ofMillis(startupTimeMs) : null);\n\t}\n\n\tprivate void assertMetricExistsWithValue(String metricName, long expectedValueInMillis) {\n\t\tassertMetricExistsWithCustomTagsAndValue(metricName, Tags.empty(), expectedValueInMillis);\n\t}\n\n\tprivate void assertMetricExistsWithCustomTagsAndValue(String metricName, Tags expectedCustomTags,\n\t\t\tLong expectedValueInMillis) {\n\t\tassertThat(this.registry.find(metricName)\n\t\t\t.tags(Tags.concat(expectedCustomTags, \"main.application.class\", TestMainApplication.class.getName()))\n\t\t\t.timeGauge()).isNotNull()\n\t\t\t.extracting((m) -> m.value(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(expectedValueInMillis.doubleValue());\n\t}\n\n\tstatic class TestMainApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/test/java/org/springframework/boot/micrometer/metrics/system/DiskSpaceMetricsBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.system;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DiskSpaceMetricsBinder}.\n *\n * @author Chris Bono\n */\nclass DiskSpaceMetricsBinderTests {\n\n\t@Test\n\tvoid diskSpaceMetricsWithSinglePath() {\n\t\tMeterRegistry meterRegistry = new SimpleMeterRegistry();\n\t\tFile path = new File(\".\");\n\t\tDiskSpaceMetricsBinder metricsBinder = new DiskSpaceMetricsBinder(Collections.singletonList(path),\n\t\t\t\tTags.empty());\n\t\tmetricsBinder.bindTo(meterRegistry);\n\n\t\tTags tags = Tags.of(\"path\", path.getAbsolutePath());\n\t\tassertThat(meterRegistry.get(\"disk.free\").tags(tags).gauge()).isNotNull();\n\t\tassertThat(meterRegistry.get(\"disk.total\").tags(tags).gauge()).isNotNull();\n\t}\n\n\t@Test\n\tvoid diskSpaceMetricsWithMultiplePaths() {\n\t\tMeterRegistry meterRegistry = new SimpleMeterRegistry();\n\t\tFile path1 = new File(\".\");\n\t\tFile path2 = new File(\"..\");\n\t\tDiskSpaceMetricsBinder metricsBinder = new DiskSpaceMetricsBinder(Arrays.asList(path1, path2), Tags.empty());\n\t\tmetricsBinder.bindTo(meterRegistry);\n\n\t\tTags tags = Tags.of(\"path\", path1.getAbsolutePath());\n\t\tassertThat(meterRegistry.get(\"disk.free\").tags(tags).gauge()).isNotNull();\n\t\tassertThat(meterRegistry.get(\"disk.total\").tags(tags).gauge()).isNotNull();\n\t\ttags = Tags.of(\"path\", path2.getAbsolutePath());\n\t\tassertThat(meterRegistry.get(\"disk.free\").tags(tags).gauge()).isNotNull();\n\t\tassertThat(meterRegistry.get(\"disk.total\").tags(tags).gauge()).isNotNull();\n\t}\n\n\t@Test\n\tvoid diskSpaceMetricsWithCustomTags() {\n\t\tMeterRegistry meterRegistry = new SimpleMeterRegistry();\n\t\tFile path = new File(\".\");\n\t\tTags customTags = Tags.of(\"foo\", \"bar\");\n\t\tDiskSpaceMetricsBinder metricsBinder = new DiskSpaceMetricsBinder(Collections.singletonList(path), customTags);\n\t\tmetricsBinder.bindTo(meterRegistry);\n\n\t\tTags tags = Tags.of(\"path\", path.getAbsolutePath(), \"foo\", \"bar\");\n\t\tassertThat(meterRegistry.get(\"disk.free\").tags(tags).gauge()).isNotNull();\n\t\tassertThat(meterRegistry.get(\"disk.total\").tags(tags).gauge()).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/testFixtures/java/org/springframework/boot/actuate/autoconfigure/metrics/export/properties/AbstractPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.metrics.export.properties;\n\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport io.micrometer.core.instrument.config.validate.Validated;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\nimport org.springframework.core.annotation.AnnotatedElementUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for testing properties config adapters.\n *\n * @param <P> the properties used by the adapter\n * @param <A> the adapter under test\n * @author Andy Wilkinson\n * @author Mirko Sobeck\n */\npublic abstract class AbstractPropertiesConfigAdapterTests<P, A extends PropertiesConfigAdapter<P>> {\n\n\tprivate final Class<? extends A> adapter;\n\n\tprotected AbstractPropertiesConfigAdapterTests(Class<? extends A> adapter) {\n\t\tthis.adapter = adapter;\n\t}\n\n\t@Test\n\tprotected void adapterOverridesAllConfigMethods() {\n\t\tadapterOverridesAllConfigMethodsExcept();\n\t}\n\n\tprotected final void adapterOverridesAllConfigMethodsExcept(String... nonConfigMethods) {\n\t\tClass<?> config = findImplementedConfig();\n\t\tSet<String> expectedConfigMethodNames = Arrays.stream(config.getDeclaredMethods())\n\t\t\t.filter(Method::isDefault)\n\t\t\t.filter(this::hasNoParameters)\n\t\t\t.filter(this::isNotValidationMethod)\n\t\t\t.filter(this::isNotDeprecated)\n\t\t\t.map(Method::getName)\n\t\t\t.collect(Collectors.toCollection(TreeSet::new));\n\t\texpectedConfigMethodNames.removeAll(Arrays.asList(nonConfigMethods));\n\t\tSet<String> actualConfigMethodNames = new TreeSet<>();\n\t\tClass<?> currentClass = this.adapter;\n\t\twhile (!Object.class.equals(currentClass)) {\n\t\t\tactualConfigMethodNames.addAll(Arrays.stream(currentClass.getDeclaredMethods())\n\t\t\t\t.map(Method::getName)\n\t\t\t\t.filter(expectedConfigMethodNames::contains)\n\t\t\t\t.toList());\n\t\t\tcurrentClass = currentClass.getSuperclass();\n\t\t}\n\t\tassertThat(actualConfigMethodNames).containsExactlyInAnyOrderElementsOf(expectedConfigMethodNames);\n\t}\n\n\tprivate Class<?> findImplementedConfig() {\n\t\tClass<?>[] interfaces = this.adapter.getInterfaces();\n\t\tif (interfaces.length == 1) {\n\t\t\treturn interfaces[0];\n\t\t}\n\t\tthrow new IllegalStateException(this.adapter + \" is not a config implementation\");\n\t}\n\n\tprivate boolean isNotDeprecated(Method method) {\n\t\treturn !AnnotatedElementUtils.hasAnnotation(method, Deprecated.class);\n\t}\n\n\tprivate boolean hasNoParameters(Method method) {\n\t\treturn method.getParameterCount() == 0;\n\t}\n\n\tprivate boolean isNotValidationMethod(Method method) {\n\t\treturn !Validated.class.equals(method.getReturnType());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics/src/testFixtures/java/org/springframework/boot/actuate/autoconfigure/metrics/export/properties/PushRegistryPropertiesConfigAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.actuate.autoconfigure.metrics.export.properties;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PropertiesConfigAdapter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PushRegistryProperties;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.properties.PushRegistryPropertiesConfigAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base test for {@link PushRegistryPropertiesConfigAdapter} implementations.\n *\n * @param <P> properties used by the tests\n * @param <A> adapter used by the tests\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n */\npublic abstract class PushRegistryPropertiesConfigAdapterTests<P extends PushRegistryProperties, A extends PushRegistryPropertiesConfigAdapter<P>>\n\t\textends AbstractPropertiesConfigAdapterTests<P, PropertiesConfigAdapter<P>> {\n\n\tprotected PushRegistryPropertiesConfigAdapterTests(Class<A> adapter) {\n\t\tsuper(adapter);\n\t}\n\n\tprotected abstract P createProperties();\n\n\tprotected abstract A createConfigAdapter(P properties);\n\n\t@Test\n\tvoid whenPropertiesStepIsSetAdapterStepReturnsIt() {\n\t\tP properties = createProperties();\n\t\tproperties.setStep(Duration.ofSeconds(42));\n\t\tassertThat(createConfigAdapter(properties).step()).hasSeconds(42);\n\t}\n\n\t@Test\n\tvoid whenPropertiesEnabledIsSetAdapterEnabledReturnsIt() {\n\t\tP properties = createProperties();\n\t\tproperties.setEnabled(false);\n\t\tassertThat(createConfigAdapter(properties).enabled()).isFalse();\n\t}\n\n\t@Test\n\tprotected void whenPropertiesBatchSizeIsSetAdapterBatchSizeReturnsIt() {\n\t\tP properties = createProperties();\n\t\tproperties.setBatchSize(10042);\n\t\tassertThat(createConfigAdapter(properties).batchSize()).isEqualTo(10042);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-metadata\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Micrometer Metrics Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-micrometer-metrics\"))\n\tapi(\"io.micrometer:micrometer-observation-test\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-registry-prometheus\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/main/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/AutoConfigureMetrics.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration for\n * metrics.\n * <p>\n * If this annotation is applied to a sliced test, an in-memory {@link MeterRegistry} and\n * an {@link ObservationRegistry} are added to the application context.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureMetrics {\n\n\t/**\n\t * Whether metrics should be reported to external systems in the test.\n\t * @return whether metrics should be reported to external systems in the test\n\t */\n\tboolean export() default true;\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/main/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/MetricsContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextAnnotationUtils;\n\n/**\n * {@link ContextCustomizerFactory} that globally disables metrics export in tests. The\n * behaviour can be controlled with {@link AutoConfigureMetrics} on the test class or via\n * the {@value #AUTO_CONFIGURE_PROPERTY} property.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nclass MetricsContextCustomizerFactory implements ContextCustomizerFactory {\n\n\tstatic final String AUTO_CONFIGURE_PROPERTY = \"spring.test.metrics.export\";\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\tAutoConfigureMetrics annotation = TestContextAnnotationUtils.findMergedAnnotation(testClass,\n\t\t\t\tAutoConfigureMetrics.class);\n\t\treturn new DisableMetricsExportContextCustomizer(annotation);\n\t}\n\n\tprivate static class DisableMetricsExportContextCustomizer implements ContextCustomizer {\n\n\t\tprivate final @Nullable AutoConfigureMetrics annotation;\n\n\t\tDisableMetricsExportContextCustomizer(@Nullable AutoConfigureMetrics annotation) {\n\t\t\tthis.annotation = annotation;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customizeContext(ConfigurableApplicationContext context,\n\t\t\t\tMergedContextConfiguration mergedContextConfiguration) {\n\t\t\tif (areMetricsDisabled(context.getEnvironment())) {\n\t\t\t\tTestPropertyValues\n\t\t\t\t\t.of(\"management.defaults.metrics.export.enabled=false\",\n\t\t\t\t\t\t\t\"management.simple.metrics.export.enabled=true\")\n\t\t\t\t\t.applyTo(context);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean areMetricsDisabled(Environment environment) {\n\t\t\tif (this.annotation != null) {\n\t\t\t\treturn !this.annotation.export();\n\t\t\t}\n\t\t\treturn !environment.getProperty(AUTO_CONFIGURE_PROPERTY, Boolean.class, false);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object o) {\n\t\t\tif (this == o) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tDisableMetricsExportContextCustomizer that = (DisableMetricsExportContextCustomizer) o;\n\t\t\treturn Objects.equals(this.annotation, that.annotation);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Objects.hash(this.annotation);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/main/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for handling metrics in tests.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/main/resources/META-INF/spring/org.springframework.boot.micrometer.metrics.test.autoconfigure.AutoConfigureMetrics.imports",
    "content": "org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration\norg.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration\norg.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.metrics.export\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether metrics export should be auto-configured in tests.\",\n      \"defaultValue\": false\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Context Customizer Factories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.micrometer.metrics.test.autoconfigure.MetricsContextCustomizerFactory\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/test/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/AutoConfigureMetricsMissingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to verify behaviour when\n * {@link AutoConfigureMetrics @AutoConfigureMetrics} is not present on the test class.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@SpringBootTest\nclass AutoConfigureMetricsMissingIntegrationTests {\n\n\t@Test\n\tvoid customizerRunsAndOnlyEnablesSimpleMeterRegistryWhenNoAnnotationPresent(\n\t\t\t@Autowired ApplicationContext applicationContext) {\n\t\tassertThat(applicationContext.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class);\n\t\tassertThat(applicationContext.getBeansOfType(PrometheusMeterRegistry.class)).isEmpty();\n\t}\n\n\t@Test\n\tvoid customizerRunsAndSetsExclusionPropertiesWhenNoAnnotationPresent(@Autowired Environment environment) {\n\t\tassertThat(environment.getProperty(\"management.defaults.metrics.export.enabled\")).isEqualTo(\"false\");\n\t\tassertThat(environment.getProperty(\"management.simple.metrics.export.enabled\")).isEqualTo(\"true\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/test/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/AutoConfigureMetricsPresentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to verify behaviour when\n * {@link AutoConfigureMetrics @AutoConfigureMetrics} is present on the test class.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@SpringBootTest\n@AutoConfigureMetrics\nclass AutoConfigureMetricsPresentIntegrationTests {\n\n\t@Test\n\tvoid customizerDoesNotDisableAvailableMeterRegistriesWhenAnnotationPresent(\n\t\t\t@Autowired ApplicationContext applicationContext) {\n\t\tassertThat(applicationContext.getBeansOfType(io.micrometer.prometheusmetrics.PrometheusMeterRegistry.class))\n\t\t\t.hasSize(1);\n\t}\n\n\t@Test\n\tvoid customizerDoesNotSetExclusionPropertiesWhenAnnotationPresent(@Autowired Environment environment) {\n\t\tassertThat(environment.containsProperty(\"management.defaults.metrics.export.enabled\")).isFalse();\n\t\tassertThat(environment.containsProperty(\"management.simple.metrics.export.enabled\")).isFalse();\n\t\tassertThat(environment.containsProperty(\"management.tracing.export.enabled\")).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/test/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/AutoConfigureMetricsSlicedIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.micrometer.observation.ObservationRegistry;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureMetrics} when used on a sliced test.\n *\n * @author Moritz Halbritter\n */\n// TODO Test AutoConfigureMetrics in a sliced test\n// @WebMvcTest\n@Disabled\n@AutoConfigureMetrics\nclass AutoConfigureMetricsSlicedIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid shouldHaveMeterRegistry() {\n\t\tassertThat(this.context.getBean(MeterRegistry.class)).isInstanceOf(SimpleMeterRegistry.class);\n\t}\n\n\t@Test\n\tvoid shouldHaveObservationRegistry() {\n\t\tassertThat(this.context.getBean(ObservationRegistry.class)).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/test/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/AutoConfigureMetricsSpringBootApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link AutoConfigureMetrics @AutoConfigureMetrics} tests.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@SpringBootConfiguration\n@EnableAutoConfiguration\nclass AutoConfigureMetricsSpringBootApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-metrics-test/src/test/java/org/springframework/boot/micrometer/metrics/test/autoconfigure/MetricsContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.metrics.test.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextLoader;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AutoConfigureMetrics} and {@link MetricsContextCustomizerFactory}\n * working together.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nclass MetricsContextCustomizerFactoryTests {\n\n\tprivate final MetricsContextCustomizerFactory factory = new MetricsContextCustomizerFactory();\n\n\t@Test\n\tvoid whenNotAnnotatedMetricsExportIsDisabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(NoAnnotation.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreDisabled(context);\n\t}\n\n\t@Test\n\tvoid whenAnnotatedWithDefaultAttributeMetricsExportIsEnabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(MetricsExportDefault.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreEnabled(context);\n\t}\n\n\t@Test\n\tvoid whenAnnotatedWithFalseExportAttributeMetricsExportIsDisabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(MetricsExportDisabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreDisabled(context);\n\t}\n\n\t@Test\n\tvoid whenAnnotatedWithTrueExportAttributeMetricsExportIsEnabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(MetricsExportEnabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreEnabled(context);\n\t}\n\n\t@Test\n\tvoid notEquals() {\n\t\tContextCustomizer customizer1 = createContextCustomizer(MetricsExportEnabled.class);\n\t\tContextCustomizer customizer2 = createContextCustomizer(MetricsExportDisabled.class);\n\t\tassertThat(customizer1).isNotEqualTo(customizer2);\n\t}\n\n\t@Test\n\tvoid equals() {\n\t\tContextCustomizer customizer1 = createContextCustomizer(MetricsExportEnabled.class);\n\t\tContextCustomizer customizer2 = createContextCustomizer(MetricsExportEnabled.class);\n\t\tassertThat(customizer1).isEqualTo(customizer2);\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t}\n\n\t@Test\n\tvoid metricsExportCanBeEnabledViaProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(NoAnnotation.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.metrics.export\", \"true\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreEnabled(context);\n\t}\n\n\t@Test\n\tvoid metricsExportCanBeDisabledViaProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(NoAnnotation.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.metrics.export\", \"false\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreDisabled(context);\n\t}\n\n\t@Test\n\tvoid annotationTakesPrecedenceOverDisabledProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(MetricsExportEnabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.metrics.export\", \"false\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreEnabled(context);\n\t}\n\n\t@Test\n\tvoid annotationTakesPrecedenceOverEnabledProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(MetricsExportDisabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.metrics.export\", \"true\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatMetricsAreDisabled(context);\n\t}\n\n\tprivate void applyCustomizerToContext(ContextCustomizer customizer, ConfigurableApplicationContext context) {\n\t\tcustomizer.customizeContext(context,\n\t\t\t\tnew MergedContextConfiguration(getClass(), null, null, null, mock(ContextLoader.class)));\n\t}\n\n\tprivate ContextCustomizer createContextCustomizer(Class<?> testClass) {\n\t\tContextCustomizer contextCustomizer = this.factory.createContextCustomizer(testClass, Collections.emptyList());\n\t\tassertThat(contextCustomizer).as(\"contextCustomizer\").isNotNull();\n\t\treturn contextCustomizer;\n\t}\n\n\tprivate void assertThatMetricsAreDisabled(ConfigurableApplicationContext context) {\n\t\tassertThat(context.getEnvironment().getProperty(\"management.defaults.metrics.export.enabled\"))\n\t\t\t.isEqualTo(\"false\");\n\t\tassertThat(context.getEnvironment().getProperty(\"management.simple.metrics.export.enabled\")).isEqualTo(\"true\");\n\t}\n\n\tprivate void assertThatMetricsAreEnabled(ConfigurableApplicationContext context) {\n\t\tassertThat(context.getEnvironment().getProperty(\"management.defaults.metrics.export.enabled\")).isNull();\n\t\tassertThat(context.getEnvironment().getProperty(\"management.simple.metrics.export.enabled\")).isNull();\n\t}\n\n\tstatic class NoAnnotation {\n\n\t}\n\n\t@AutoConfigureMetrics\n\tstatic class MetricsExportDefault {\n\n\t}\n\n\t@AutoConfigureMetrics(export = false)\n\tstatic class MetricsExportDisabled {\n\n\t}\n\n\t@AutoConfigureMetrics(export = true)\n\tstatic class MetricsExportEnabled {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Observation\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"io.micrometer:micrometer-observation\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.aspectj:aspectjweaver\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport io.micrometer.observation.GlobalObservationConvention;\nimport io.micrometer.observation.ObservationFilter;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationPredicate;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.aop.ObservationKeyValueAnnotationHandler;\nimport io.micrometer.observation.aop.ObservedAspect;\nimport org.aspectj.weaver.Advice;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Observation API.\n *\n * @author Moritz Halbritter\n * @author Brian Clozel\n * @author Jonatan Ivanov\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(ObservationRegistry.class)\n@EnableConfigurationProperties(ObservationProperties.class)\npublic final class ObservationAutoConfiguration {\n\n\t@Bean\n\tstatic ObservationRegistryPostProcessor observationRegistryPostProcessor(\n\t\t\tObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,\n\t\t\tObjectProvider<ObservationPredicate> observationPredicates,\n\t\t\tObjectProvider<GlobalObservationConvention<?>> observationConventions,\n\t\t\tObjectProvider<ObservationHandler<?>> observationHandlers,\n\t\t\tObjectProvider<ObservationHandlerGroup> observationHandlerGroups,\n\t\t\tObjectProvider<ObservationFilter> observationFilters) {\n\t\treturn new ObservationRegistryPostProcessor(observationRegistryCustomizers, observationPredicates,\n\t\t\t\tobservationConventions, observationHandlers, observationHandlerGroups, observationFilters);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tObservationRegistry observationRegistry() {\n\t\treturn ObservationRegistry.create();\n\t}\n\n\t@Bean\n\t@Order(0)\n\tPropertiesObservationFilterPredicate propertiesObservationFilter(ObservationProperties properties) {\n\t\treturn new PropertiesObservationFilterPredicate(properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ValueExpressionResolver.class)\n\tSpelValueExpressionResolver spelValueExpressionResolver() {\n\t\treturn new SpelValueExpressionResolver();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Advice.class)\n\t@ConditionalOnBooleanProperty(\"management.observations.annotations.enabled\")\n\tstatic class ObservedAspectConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tObservedAspect observedAspect(ObservationRegistry observationRegistry,\n\t\t\t\tObjectProvider<ObservationKeyValueAnnotationHandler> observationKeyValueAnnotationHandler) {\n\t\t\tObservedAspect observedAspect = new ObservedAspect(observationRegistry);\n\t\t\tobservationKeyValueAnnotationHandler.ifAvailable(observedAspect::setObservationKeyValueAnnotationHandler);\n\t\t\treturn observedAspect;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tObservationKeyValueAnnotationHandler observationKeyValueAnnotationHandler(BeanFactory beanFactory,\n\t\t\t\tValueExpressionResolver valueExpressionResolver) {\n\t\t\treturn new ObservationKeyValueAnnotationHandler(beanFactory::getBean, (ignored) -> valueExpressionResolver);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationRegistry.ObservationConfig;\n\nimport org.springframework.util.Assert;\n\n/**\n * Group of {@link ObservationHandler ObservationHandlers} that can be registered\n * together. The first group claiming membership of a handler is responsible for\n * registering it. Groups are {@link Comparable} so that they can be ordered against each\n * other.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface ObservationHandlerGroup extends Comparable<ObservationHandlerGroup> {\n\n\t/**\n\t * Return if the given handler is a member of this group.\n\t * @param handler the handler to check\n\t * @return if the handler is a member\n\t */\n\tdefault boolean isMember(ObservationHandler<?> handler) {\n\t\treturn handlerType().isInstance(handler);\n\t}\n\n\t/**\n\t * Register group members against the given {@link ObservationConfig}.\n\t * @param config the config used to register members\n\t * @param members the group members to register\n\t */\n\tdefault void registerMembers(ObservationConfig config, List<ObservationHandler<?>> members) {\n\t\tconfig.observationHandler(new FirstMatchingCompositeObservationHandler(members));\n\t}\n\n\t@Override\n\tdefault int compareTo(ObservationHandlerGroup other) {\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Return the primary type of handler that this group accepts.\n\t * @return the accepted handler type\n\t */\n\tClass<?> handlerType();\n\n\t/**\n\t * Static factory method to create an {@link ObservationHandlerGroup} with members of\n\t * the given handler type.\n\t * @param <H> the handler type\n\t * @param handlerType the handler type\n\t * @return a new {@link ObservationHandlerGroup}\n\t */\n\tstatic <H extends ObservationHandler<?>> ObservationHandlerGroup of(Class<H> handlerType) {\n\t\tAssert.notNull(handlerType, \"'handlerType' must not be null\");\n\t\treturn () -> handlerType;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroups.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationRegistry.ObservationConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * A collection of {@link ObservationHandlerGroup} instances and supporting registration\n * logic.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass ObservationHandlerGroups {\n\n\tprivate final List<ObservationHandlerGroup> groups;\n\n\tObservationHandlerGroups(Collection<? extends ObservationHandlerGroup> groups) {\n\t\tthis.groups = Collections.unmodifiableList(sort(groups));\n\t}\n\n\tprivate static List<ObservationHandlerGroup> sort(Collection<? extends ObservationHandlerGroup> groups) {\n\t\tArrayList<ObservationHandlerGroup> sortedGroups = new ArrayList<>(groups);\n\t\tCollections.sort(sortedGroups);\n\t\treturn sortedGroups;\n\t}\n\n\tvoid register(ObservationConfig config, List<ObservationHandler<?>> handlers) {\n\t\tMultiValueMap<ObservationHandlerGroup, ObservationHandler<?>> grouped = new LinkedMultiValueMap<>();\n\t\tList<ObservationHandler<?>> unclaimed = new ArrayList<>();\n\t\tfor (ObservationHandler<?> handler : handlers) {\n\t\t\tObservationHandlerGroup group = findGroup(handler);\n\t\t\tif (group == null) {\n\t\t\t\tunclaimed.add(handler);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tgrouped.add(group, handler);\n\t\t\t}\n\t\t}\n\t\tfor (ObservationHandlerGroup group : this.groups) {\n\t\t\tList<ObservationHandler<?>> members = grouped.get(group);\n\t\t\tif (!CollectionUtils.isEmpty(members)) {\n\t\t\t\tgroup.registerMembers(config, members);\n\t\t\t}\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(unclaimed)) {\n\t\t\tfor (ObservationHandler<?> handler : unclaimed) {\n\t\t\t\tconfig.observationHandler(handler);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate @Nullable ObservationHandlerGroup findGroup(ObservationHandler<?> handler) {\n\t\tfor (ObservationHandlerGroup group : this.groups) {\n\t\t\tif (group.isMember(handler)) {\n\t\t\t\treturn group;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for configuring Micrometer\n * observations.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.observations\")\npublic class ObservationProperties {\n\n\tprivate final Http http = new Http();\n\n\t/**\n\t * Common key-values that are applied to every observation.\n\t */\n\tprivate Map<String, String> keyValues = new LinkedHashMap<>();\n\n\t/**\n\t * Whether observations starting with the specified name should be enabled. The\n\t * longest match wins, the key 'all' can also be used to configure all observations.\n\t */\n\tprivate Map<String, Boolean> enable = new LinkedHashMap<>();\n\n\tpublic Map<String, Boolean> getEnable() {\n\t\treturn this.enable;\n\t}\n\n\tpublic void setEnable(Map<String, Boolean> enable) {\n\t\tthis.enable = enable;\n\t}\n\n\tpublic Http getHttp() {\n\t\treturn this.http;\n\t}\n\n\tpublic Map<String, String> getKeyValues() {\n\t\treturn this.keyValues;\n\t}\n\n\tpublic void setKeyValues(Map<String, String> keyValues) {\n\t\tthis.keyValues = keyValues;\n\t}\n\n\tpublic static class Http {\n\n\t\tprivate final Client client = new Client();\n\n\t\tprivate final Server server = new Server();\n\n\t\tpublic Client getClient() {\n\t\t\treturn this.client;\n\t\t}\n\n\t\tpublic Server getServer() {\n\t\t\treturn this.server;\n\t\t}\n\n\t\tpublic static class Client {\n\n\t\t\tprivate final ClientRequests requests = new ClientRequests();\n\n\t\t\tpublic ClientRequests getRequests() {\n\t\t\t\treturn this.requests;\n\t\t\t}\n\n\t\t\tpublic static class ClientRequests {\n\n\t\t\t\t/**\n\t\t\t\t * Name of the observation for client requests.\n\t\t\t\t */\n\t\t\t\tprivate String name = \"http.client.requests\";\n\n\t\t\t\tpublic String getName() {\n\t\t\t\t\treturn this.name;\n\t\t\t\t}\n\n\t\t\t\tpublic void setName(String name) {\n\t\t\t\t\tthis.name = name;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Server {\n\n\t\t\tprivate final ServerRequests requests = new ServerRequests();\n\n\t\t\tpublic ServerRequests getRequests() {\n\t\t\t\treturn this.requests;\n\t\t\t}\n\n\t\t\tpublic static class ServerRequests {\n\n\t\t\t\t/**\n\t\t\t\t * Name of the observation for server requests.\n\t\t\t\t */\n\t\t\t\tprivate String name = \"http.server.requests\";\n\n\t\t\t\tpublic String getName() {\n\t\t\t\t\treturn this.name;\n\t\t\t\t}\n\n\t\t\t\tpublic void setName(String name) {\n\t\t\t\t\tthis.name = name;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.observation.GlobalObservationConvention;\nimport io.micrometer.observation.ObservationFilter;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationPredicate;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.util.LambdaSafe;\n\n/**\n * Configurer to apply {@link ObservationRegistryCustomizer customizers} to\n * {@link ObservationRegistry observation registries}. Installs\n * {@link ObservationPredicate observation predicates} and\n * {@link GlobalObservationConvention global observation conventions} into the\n * {@link ObservationRegistry}. Also uses a {@link ObservationHandlerGroups} to group\n * handlers, which are then added to the {@link ObservationRegistry}.\n *\n * @author Moritz Halbritter\n */\nclass ObservationRegistryConfigurer {\n\n\tprivate final ObjectProvider<ObservationRegistryCustomizer<?>> customizers;\n\n\tprivate final ObjectProvider<ObservationPredicate> observationPredicates;\n\n\tprivate final ObjectProvider<GlobalObservationConvention<?>> observationConventions;\n\n\tprivate final ObjectProvider<ObservationHandler<?>> observationHandlers;\n\n\tprivate final ObjectProvider<ObservationHandlerGroup> observationHandlerGroups;\n\n\tprivate final ObjectProvider<ObservationFilter> observationFilters;\n\n\tObservationRegistryConfigurer(ObjectProvider<ObservationRegistryCustomizer<?>> customizers,\n\t\t\tObjectProvider<ObservationPredicate> observationPredicates,\n\t\t\tObjectProvider<GlobalObservationConvention<?>> observationConventions,\n\t\t\tObjectProvider<ObservationHandler<?>> observationHandlers,\n\t\t\tObjectProvider<ObservationHandlerGroup> observationHandlerGroups,\n\t\t\tObjectProvider<ObservationFilter> observationFilters) {\n\t\tthis.customizers = customizers;\n\t\tthis.observationPredicates = observationPredicates;\n\t\tthis.observationConventions = observationConventions;\n\t\tthis.observationHandlers = observationHandlers;\n\t\tthis.observationHandlerGroups = observationHandlerGroups;\n\t\tthis.observationFilters = observationFilters;\n\t}\n\n\tvoid configure(ObservationRegistry registry) {\n\t\tregisterObservationPredicates(registry);\n\t\tregisterGlobalObservationConventions(registry);\n\t\tregisterHandlers(registry);\n\t\tregisterFilters(registry);\n\t\tcustomize(registry);\n\t}\n\n\tprivate void registerHandlers(ObservationRegistry registry) {\n\t\tObservationHandlerGroups groups = new ObservationHandlerGroups(this.observationHandlerGroups.stream().toList());\n\t\tList<ObservationHandler<?>> orderedHandlers = this.observationHandlers.orderedStream().toList();\n\t\tgroups.register(registry.observationConfig(), orderedHandlers);\n\t}\n\n\tprivate void registerObservationPredicates(ObservationRegistry registry) {\n\t\tthis.observationPredicates.orderedStream().forEach(registry.observationConfig()::observationPredicate);\n\t}\n\n\tprivate void registerGlobalObservationConventions(ObservationRegistry registry) {\n\t\tthis.observationConventions.orderedStream().forEach(registry.observationConfig()::observationConvention);\n\t}\n\n\tprivate void registerFilters(ObservationRegistry registry) {\n\t\tthis.observationFilters.orderedStream().forEach(registry.observationConfig()::observationFilter);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void customize(ObservationRegistry registry) {\n\t\tLambdaSafe.callbacks(ObservationRegistryCustomizer.class, this.customizers.orderedStream().toList(), registry)\n\t\t\t.withLogger(ObservationRegistryConfigurer.class)\n\t\t\t.invoke((customizer) -> customizer.customize(registry));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\n\n/**\n * Callback interface that can be used to customize auto-configured\n * {@link ObservationRegistry observation registries}.\n *\n * @param <T> the registry type to customize\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ObservationRegistryCustomizer<T extends ObservationRegistry> {\n\n\t/**\n\t * Customize the given {@code registry}.\n\t * @param registry the registry to customize\n\t */\n\tvoid customize(T registry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.observation.GlobalObservationConvention;\nimport io.micrometer.observation.ObservationFilter;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationPredicate;\nimport io.micrometer.observation.ObservationRegistry;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\n\n/**\n * {@link BeanPostProcessor} that delegates to a lazily created\n * {@link ObservationRegistryConfigurer} to post-process {@link ObservationRegistry}\n * beans.\n *\n * @author Moritz Halbritter\n */\nclass ObservationRegistryPostProcessor implements BeanPostProcessor {\n\n\tprivate final ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers;\n\n\tprivate final ObjectProvider<ObservationPredicate> observationPredicates;\n\n\tprivate final ObjectProvider<GlobalObservationConvention<?>> observationConventions;\n\n\tprivate final ObjectProvider<ObservationHandler<?>> observationHandlers;\n\n\tprivate final ObjectProvider<ObservationHandlerGroup> observationHandlerGroups;\n\n\tprivate final ObjectProvider<ObservationFilter> observationFilters;\n\n\tprivate volatile @Nullable ObservationRegistryConfigurer configurer;\n\n\tObservationRegistryPostProcessor(ObjectProvider<ObservationRegistryCustomizer<?>> observationRegistryCustomizers,\n\t\t\tObjectProvider<ObservationPredicate> observationPredicates,\n\t\t\tObjectProvider<GlobalObservationConvention<?>> observationConventions,\n\t\t\tObjectProvider<ObservationHandler<?>> observationHandlers,\n\t\t\tObjectProvider<ObservationHandlerGroup> observationHandlerGroups,\n\t\t\tObjectProvider<ObservationFilter> observationFilters) {\n\t\tthis.observationRegistryCustomizers = observationRegistryCustomizers;\n\t\tthis.observationPredicates = observationPredicates;\n\t\tthis.observationConventions = observationConventions;\n\t\tthis.observationHandlers = observationHandlers;\n\t\tthis.observationHandlerGroups = observationHandlerGroups;\n\t\tthis.observationFilters = observationFilters;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof ObservationRegistry registry) {\n\t\t\tgetConfigurer().configure(registry);\n\t\t}\n\t\treturn bean;\n\t}\n\n\tprivate ObservationRegistryConfigurer getConfigurer() {\n\t\tObservationRegistryConfigurer configurer = this.configurer;\n\t\tif (configurer == null) {\n\t\t\tconfigurer = new ObservationRegistryConfigurer(this.observationRegistryCustomizers,\n\t\t\t\t\tthis.observationPredicates, this.observationConventions, this.observationHandlers,\n\t\t\t\t\tthis.observationHandlerGroups, this.observationFilters);\n\t\t\tthis.configurer = configurer;\n\t\t}\n\t\treturn configurer;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.function.Supplier;\n\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationFilter;\nimport io.micrometer.observation.ObservationPredicate;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ObservationFilter} to apply settings from {@link ObservationProperties}.\n *\n * @author Moritz Halbritter\n */\nclass PropertiesObservationFilterPredicate implements ObservationFilter, ObservationPredicate {\n\n\tprivate final ObservationFilter commonKeyValuesFilter;\n\n\tprivate final ObservationProperties properties;\n\n\tPropertiesObservationFilterPredicate(ObservationProperties properties) {\n\t\tthis.properties = properties;\n\t\tthis.commonKeyValuesFilter = createCommonKeyValuesFilter(properties);\n\t}\n\n\t@Override\n\tpublic Context map(Context context) {\n\t\treturn this.commonKeyValuesFilter.map(context);\n\t}\n\n\t@Override\n\tpublic boolean test(String name, Context context) {\n\t\treturn lookupWithFallbackToAll(this.properties.getEnable(), name, true);\n\t}\n\n\tprivate static <T> T lookupWithFallbackToAll(Map<String, T> values, String name, T defaultValue) {\n\t\tif (values.isEmpty()) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\treturn doLookup(values, name, () -> values.getOrDefault(\"all\", defaultValue));\n\t}\n\n\tprivate static <T> T doLookup(Map<String, T> values, String name, Supplier<T> defaultValue) {\n\t\twhile (StringUtils.hasLength(name)) {\n\t\t\tT result = values.get(name);\n\t\t\tif (result != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tint lastDot = name.lastIndexOf('.');\n\t\t\tname = (lastDot != -1) ? name.substring(0, lastDot) : \"\";\n\t\t}\n\t\treturn defaultValue.get();\n\t}\n\n\tprivate static ObservationFilter createCommonKeyValuesFilter(ObservationProperties properties) {\n\t\tif (properties.getKeyValues().isEmpty()) {\n\t\t\treturn (context) -> context;\n\t\t}\n\t\tKeyValues keyValues = KeyValues.of(properties.getKeyValues().entrySet(), Entry::getKey, Entry::getValue);\n\t\treturn (context) -> context.addLowCardinalityKeyValues(keyValues);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/ScheduledTasksObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.scheduling.annotation.SchedulingConfigurer;\nimport org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;\nimport org.springframework.scheduling.config.ScheduledTaskRegistrar;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to enable observability for\n * scheduled tasks.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(after = ObservationAutoConfiguration.class)\n@ConditionalOnBean(ObservationRegistry.class)\n@ConditionalOnClass(ThreadPoolTaskScheduler.class)\npublic final class ScheduledTasksObservationAutoConfiguration {\n\n\t@Bean\n\tObservabilitySchedulingConfigurer observabilitySchedulingConfigurer(ObservationRegistry observationRegistry) {\n\t\treturn new ObservabilitySchedulingConfigurer(observationRegistry);\n\t}\n\n\tstatic final class ObservabilitySchedulingConfigurer implements SchedulingConfigurer {\n\n\t\tprivate final ObservationRegistry observationRegistry;\n\n\t\tObservabilitySchedulingConfigurer(ObservationRegistry observationRegistry) {\n\t\t\tthis.observationRegistry = observationRegistry;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n\t\t\ttaskRegistrar.setObservationRegistry(this.observationRegistry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/SpelValueExpressionResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.expression.Expression;\nimport org.springframework.expression.ExpressionParser;\nimport org.springframework.expression.spel.standard.SpelExpressionParser;\nimport org.springframework.expression.spel.support.SimpleEvaluationContext;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link Expression SpEL}-based {@link ValueExpressionResolver}.\n *\n * @author Dominique Villard\n */\nclass SpelValueExpressionResolver implements ValueExpressionResolver {\n\n\tprivate final ExpressionParser expressionParser = new SpelExpressionParser();\n\n\t@Override\n\tpublic String resolve(String expression, @Nullable Object parameter) {\n\t\ttry {\n\t\t\tSimpleEvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();\n\t\t\tExpression expressionToEvaluate = this.expressionParser.parseExpression(expression);\n\t\t\tString value = expressionToEvaluate.getValue(context, parameter, String.class);\n\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\treturn value;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to evaluate SpEL expression '%s'\".formatted(expression), ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/java/org/springframework/boot/micrometer/observation/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Micrometer Observation.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.observations.annotations.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether auto-configuration of Micrometer annotations is enabled.\",\n      \"defaultValue\": false\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\norg.springframework.boot.micrometer.observation.autoconfigure.ScheduledTasksObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.common.KeyValue;\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport io.micrometer.observation.GlobalObservationConvention;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationFilter;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationHandler.AllMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationPredicate;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.aop.ObservationKeyValueAnnotationHandler;\nimport io.micrometer.observation.aop.ObservedAspect;\nimport org.aspectj.weaver.Advice;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ObservationAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Jonatan Ivanov\n * @author Vedran Pavic\n */\nclass ObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"management.observations.annotations.enabled=true\")\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class))\n\t\t.withUserConfiguration(ObservationHandlers.class);\n\n\t@Test\n\tvoid beansShouldNotBeSuppliedWhenMicrometerObservationIsNotOnClassPath() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer.observation\")).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ObservationRegistry.class);\n\t\t\tassertThat(context).doesNotHaveBean(ObservedAspect.class);\n\t\t\tassertThat(context).doesNotHaveBean(ObservationKeyValueAnnotationHandler.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid supplyObservationRegistryAndAspect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation.start(\"test-observation\", observationRegistry).stop();\n\t\t\tassertThat(context).hasSingleBean(ObservedAspect.class);\n\t\t\tassertThat(context).hasSingleBean(ObservationKeyValueAnnotationHandler.class);\n\t\t\tassertThat(context.getBean(ObservedAspect.class)).extracting(\"observationKeyValueAnnotationHandler\")\n\t\t\t\t.isSameAs(context.getBean(ObservationKeyValueAnnotationHandler.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid allowsObservedAspectToBeDisabled() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Advice.class)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ObservedAspect.class);\n\t\t\tassertThat(context).doesNotHaveBean(ObservationKeyValueAnnotationHandler.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid allowsObservedAspectToBeDisabledWithProperty() {\n\t\tthis.contextRunner.withPropertyValues(\"management.observations.annotations.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ObservedAspect.class);\n\t\t\tassertThat(context).doesNotHaveBean(ObservationKeyValueAnnotationHandler.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid allowsObservedAspectToBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(CustomObservedAspectConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ObservedAspect.class)\n\t\t\t\t.getBean(ObservedAspect.class)\n\t\t\t\t.isSameAs(context.getBean(\"customObservedAspect\"));\n\t\t\tassertThat(context).hasSingleBean(ObservationKeyValueAnnotationHandler.class)\n\t\t\t\t.getBean(ObservationKeyValueAnnotationHandler.class)\n\t\t\t\t.isSameAs(context.getBean(\"customObservationKeyValueAnnotationHandler\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresObservationPredicates() {\n\t\tthis.contextRunner.withUserConfiguration(ObservationPredicates.class).run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\t// This is allowed by ObservationPredicates.customPredicate\n\t\t\tObservation observation = Observation.start(\"observation1\", observationRegistry);\n\t\t\tassertThat(observation.isNoop()).isFalse();\n\t\t\tobservation.stop();\n\t\t\t// This isn't allowed by ObservationPredicates.customPredicate\n\t\t\tobservation = Observation.start(\"observation2\", observationRegistry);\n\t\t\tassertThat(observation.isNoop()).isTrue();\n\t\t\tobservation.stop();\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresObservationFilters() {\n\t\tthis.contextRunner.withUserConfiguration(ObservationFilters.class).run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation observation = Observation.start(\"filtered\", observationRegistry);\n\t\t\tobservation.stop();\n\t\t\tobservation.getContext().getLowCardinalityKeyValues().forEach((kv) -> System.out.println(kv.getKey()));\n\t\t\tKeyValue filter = observation.getContext().getLowCardinalityKeyValue(\"filter\");\n\t\t\tassertThat(filter).isNotNull();\n\t\t\tassertThat(filter.getValue()).isEqualTo(\"one\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyPropertiesObservationFilterBean() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesObservationFilterPredicate.class));\n\t}\n\n\t@Test\n\tvoid shouldApplyCommonKeyValuesToObservations() {\n\t\tthis.contextRunner.withPropertyValues(\"management.observations.key-values.a=alpha\").run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation observation = Observation.start(\"keyvalues\", observationRegistry);\n\t\t\tobservation.stop();\n\t\t\tKeyValue a = observation.getContext().getLowCardinalityKeyValue(\"a\");\n\t\t\tassertThat(a).isNotNull();\n\t\t\tassertThat(a.getValue()).isEqualTo(\"alpha\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresGlobalObservationConventions() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGlobalObservationConvention.class).run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tContext micrometerContext = new Context();\n\t\t\tObservation.start(\"test-observation\", () -> micrometerContext, observationRegistry).stop();\n\t\t\tassertThat(micrometerContext.getAllKeyValues()).containsExactly(KeyValue.of(\"key1\", \"value1\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotDisableSpringSecurityObservationsByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation observation = Observation.start(\"spring.security.filterchains\", observationRegistry);\n\t\t\tassertThat(observation.isNoop()).isFalse();\n\t\t\tobservation.stop();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldDisableSpringSecurityObservationsIfPropertyIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"management.observations.enable.spring.security=false\").run((context) -> {\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation observation = Observation.start(\"spring.security.filterchains\", observationRegistry);\n\t\t\tassertThat(observation.isNoop()).isTrue();\n\t\t\tobservation.stop();\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresValueExpressionResolver() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(SpelValueExpressionResolver.class));\n\t}\n\n\t@Test\n\tvoid allowsUserDefinedValueExpressionResolver() {\n\t\tthis.contextRunner.withBean(ValueExpressionResolver.class, () -> mock(ValueExpressionResolver.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ValueExpressionResolver.class)\n\t\t\t\t.doesNotHaveBean(SpelValueExpressionResolver.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObservationPredicates {\n\n\t\t@Bean\n\t\tObservationPredicate customPredicate() {\n\t\t\treturn (s, context) -> s.equals(\"observation1\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObservationFilters {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tObservationFilter observationFilterOne() {\n\t\t\treturn (context) -> context.addLowCardinalityKeyValue(KeyValue.of(\"filter\", \"one\"));\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tObservationFilter observationFilterTwo() {\n\t\t\treturn (context) -> context.addLowCardinalityKeyValue(KeyValue.of(\"filter\", \"two\"));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomObservedAspectConfiguration {\n\n\t\t@Bean\n\t\tObservedAspect customObservedAspect(ObservationRegistry observationRegistry) {\n\t\t\treturn new ObservedAspect(observationRegistry);\n\t\t}\n\n\t\t@Bean\n\t\tObservationKeyValueAnnotationHandler customObservationKeyValueAnnotationHandler(BeanFactory beanFactory,\n\t\t\t\tValueExpressionResolver valueExpressionResolver) {\n\t\t\treturn new ObservationKeyValueAnnotationHandler(beanFactory::getBean, (ignored) -> valueExpressionResolver);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomGlobalObservationConvention {\n\n\t\t@Bean\n\t\tGlobalObservationConvention<?> customConvention() {\n\t\t\treturn new GlobalObservationConvention<>() {\n\t\t\t\t@Override\n\t\t\t\tpublic boolean supportsContext(Context context) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic KeyValues getLowCardinalityKeyValues(Context context) {\n\t\t\t\t\treturn KeyValues.of(\"key1\", \"value1\");\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ObservationHandlers {\n\n\t\t@Bean\n\t\t@Order(4)\n\t\tAllMatchingCompositeObservationHandler customAllMatchingCompositeObservationHandler() {\n\t\t\treturn new AllMatchingCompositeObservationHandler();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(3)\n\t\tFirstMatchingCompositeObservationHandler customFirstMatchingCompositeObservationHandler() {\n\t\t\treturn new FirstMatchingCompositeObservationHandler();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tObservationHandler<Context> customObservationHandler() {\n\t\t\treturn new CustomObservationHandler();\n\t\t}\n\n\t}\n\n\tprivate static final class CustomObservationHandler implements ObservationHandler<Context> {\n\n\t\t@Override\n\t\tpublic boolean supportsContext(Context context) {\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationRegistry.ObservationConfig;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ObservationHandlerGroup}.\n *\n * @author Phillip Webb\n */\nclass ObservationHandlerGroupTests {\n\n\t@Test\n\tvoid isMemberWhenHandlerIsInstanceOfHandlerTypeReturnsTrue() {\n\t\tObservationHandlerGroup group = ObservationHandlerGroup.of(TestObservationHandler.class);\n\t\tassertThat(group.isMember(mock(TestObservationHandler.class))).isTrue();\n\t\tassertThat(group.isMember(mock(TestObservationHandlerSubclass.class))).isTrue();\n\t}\n\n\t@Test\n\tvoid isMemberWhenHandlerIsNotInstanceOfHandlerTypeReturnsFalse() {\n\t\tObservationHandlerGroup group = ObservationHandlerGroup.of(TestObservationHandler.class);\n\t\tassertThat(group.isMember(mock(ObservationHandler.class))).isFalse();\n\t\tassertThat(group.isMember(mock(OtherObservationHandler.class))).isFalse();\n\t}\n\n\t@Test\n\tvoid registerMembersRegistersUsingFirstMatchingCompositeObservationHandler() {\n\t\tObservationHandlerGroup group = ObservationHandlerGroup.of(TestObservationHandler.class);\n\t\tTestObservationHandler handler1 = mock(TestObservationHandler.class);\n\t\tTestObservationHandler handler2 = mock(TestObservationHandler.class);\n\t\tObservationConfig config = mock(ObservationConfig.class);\n\t\tgroup.registerMembers(config, List.of(handler1, handler2));\n\t\tArgumentCaptor<ObservationHandler<?>> registeredHandler = ArgumentCaptor.captor();\n\t\tthen(config).should().observationHandler(registeredHandler.capture());\n\t\tassertThat(registeredHandler.getValue()).isInstanceOf(FirstMatchingCompositeObservationHandler.class)\n\t\t\t.extracting(\"handlers\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.containsExactly(handler1, handler2);\n\t}\n\n\t@Test\n\tvoid compareToReturnsZero() {\n\t\tObservationHandlerGroup group1 = ObservationHandlerGroup.of(TestObservationHandler.class);\n\t\tObservationHandlerGroup group2 = ObservationHandlerGroup.of(TestObservationHandler.class);\n\t\tassertThat(group1.compareTo(group1)).isZero();\n\t\tassertThat(group1.compareTo(group2)).isZero();\n\t\tassertThat(group2.compareTo(group1)).isZero();\n\t}\n\n\t@Test\n\tvoid ofCreatesHandlerGroup() {\n\t\tObservationHandlerGroup group = ObservationHandlerGroup.of(TestObservationHandler.class);\n\t\tassertThat(group.handlerType()).isEqualTo(TestObservationHandler.class);\n\t}\n\n\tinterface TestObservationHandler extends ObservationHandler<Context> {\n\n\t}\n\n\tinterface TestObservationHandlerSubclass extends TestObservationHandler {\n\n\t}\n\n\tinterface OtherObservationHandler extends ObservationHandler<Context> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationHandlerGroupsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationRegistry.ObservationConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ObservationHandlerGroups}.\n *\n * @author Moritz Halbritter\n */\nclass ObservationHandlerGroupsTests {\n\n\tprivate static final ObservationHandlerGroup GROUP_A = ObservationHandlerGroup.of(ObservationHandlerA.class);\n\n\tprivate static final ObservationHandlerGroup GROUP_B = ObservationHandlerGroup.of(ObservationHandlerB.class);\n\n\t@Test\n\tvoid shouldGroupCategoriesIntoFirstMatchingHandlerAndRespectCategoryOrder() {\n\t\tObservationHandlerGroups grouping = new ObservationHandlerGroups(List.of(GROUP_A, GROUP_B));\n\t\tObservationConfig config = new ObservationConfig();\n\t\tObservationHandlerA handlerA1 = new ObservationHandlerA(\"a1\");\n\t\tObservationHandlerA handlerA2 = new ObservationHandlerA(\"a2\");\n\t\tObservationHandlerB handlerB1 = new ObservationHandlerB(\"b1\");\n\t\tObservationHandlerB handlerB2 = new ObservationHandlerB(\"b2\");\n\t\tgrouping.register(config, List.of(handlerB1, handlerB2, handlerA1, handlerA2));\n\t\tList<ObservationHandler<?>> handlers = getObservationHandlers(config);\n\t\tassertThat(handlers).hasSize(2);\n\t\t// Category A is first\n\t\tassertThat(handlers.get(0)).isInstanceOf(FirstMatchingCompositeObservationHandler.class);\n\t\tFirstMatchingCompositeObservationHandler firstMatching0 = (FirstMatchingCompositeObservationHandler) handlers\n\t\t\t.get(0);\n\t\tassertThat(firstMatching0.getHandlers()).containsExactly(handlerA1, handlerA2);\n\t\t// Category B is second\n\t\tassertThat(handlers.get(1)).isInstanceOf(FirstMatchingCompositeObservationHandler.class);\n\t\tFirstMatchingCompositeObservationHandler firstMatching1 = (FirstMatchingCompositeObservationHandler) handlers\n\t\t\t.get(1);\n\t\tassertThat(firstMatching1.getHandlers()).containsExactly(handlerB1, handlerB2);\n\t}\n\n\t@Test\n\tvoid uncategorizedHandlersShouldBeOrderedAfterCategories() {\n\t\tObservationHandlerGroups grouping = new ObservationHandlerGroups(List.of(GROUP_A));\n\t\tObservationConfig config = new ObservationConfig();\n\t\tObservationHandlerA handlerA1 = new ObservationHandlerA(\"a1\");\n\t\tObservationHandlerA handlerA2 = new ObservationHandlerA(\"a2\");\n\t\tObservationHandlerB handlerB1 = new ObservationHandlerB(\"b1\");\n\t\tgrouping.register(config, List.of(handlerB1, handlerA1, handlerA2));\n\t\tList<ObservationHandler<?>> handlers = getObservationHandlers(config);\n\t\tassertThat(handlers).hasSize(2);\n\t\t// Category A is first\n\t\tassertThat(handlers.get(0)).isInstanceOf(FirstMatchingCompositeObservationHandler.class);\n\t\tFirstMatchingCompositeObservationHandler firstMatching0 = (FirstMatchingCompositeObservationHandler) handlers\n\t\t\t.get(0);\n\t\t// Uncategorized handlers follow\n\t\tassertThat(firstMatching0.getHandlers()).containsExactly(handlerA1, handlerA2);\n\t\tassertThat(handlers.get(1)).isEqualTo(handlerB1);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static List<ObservationHandler<?>> getObservationHandlers(ObservationConfig config) {\n\t\tMethod method = ReflectionUtils.findMethod(ObservationConfig.class, \"getObservationHandlers\");\n\t\tassertThat(method).isNotNull();\n\t\tReflectionUtils.makeAccessible(method);\n\t\tList<ObservationHandler<?>> observationHandlers = (List<ObservationHandler<?>>) ReflectionUtils\n\t\t\t.invokeMethod(method, config);\n\t\tassertThat(observationHandlers).isNotNull();\n\t\treturn observationHandlers;\n\t}\n\n\tprivate static class NamedObservationHandler implements ObservationHandler<Observation.Context> {\n\n\t\tprivate final String name;\n\n\t\tNamedObservationHandler(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsContext(Context context) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn getClass().getSimpleName() + \"{name='\" + this.name + \"'}\";\n\t\t}\n\n\t}\n\n\tprivate static class ObservationHandlerA extends NamedObservationHandler {\n\n\t\tObservationHandlerA(String name) {\n\t\t\tsuper(name);\n\t\t}\n\n\t}\n\n\tprivate static class ObservationHandlerB extends NamedObservationHandler {\n\n\t\tObservationHandlerB(String name) {\n\t\t\tsuper(name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ObservationRegistryConfigurerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport org.junit.jupiter.api.Order;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ObservationRegistryConfigurer} and\n * {@link ObservationRegistryPostProcessor}.\n *\n * @author Moritz Halbritter\n */\nclass ObservationRegistryConfigurerIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid customizersAreCalledInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(Customizers.class).run((context) -> {\n\t\t\tCalledCustomizers calledCustomizers = context.getBean(CalledCustomizers.class);\n\t\t\tCustomizer1 customizer1 = context.getBean(Customizer1.class);\n\t\t\tCustomizer2 customizer2 = context.getBean(Customizer2.class);\n\t\t\tassertThat(calledCustomizers.getCustomizers()).containsExactly(customizer1, customizer2);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Customizers {\n\n\t\t@Bean\n\t\tCalledCustomizers calledCustomizers() {\n\t\t\treturn new CalledCustomizers();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tCustomizer1 customizer1(CalledCustomizers calledCustomizers) {\n\t\t\treturn new Customizer1(calledCustomizers);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tCustomizer2 customizer2(CalledCustomizers calledCustomizers) {\n\t\t\treturn new Customizer2(calledCustomizers);\n\t\t}\n\n\t}\n\n\tprivate static final class CalledCustomizers {\n\n\t\tprivate final List<ObservationRegistryCustomizer<?>> customizers = new ArrayList<>();\n\n\t\tvoid onCalled(ObservationRegistryCustomizer<?> customizer) {\n\t\t\tthis.customizers.add(customizer);\n\t\t}\n\n\t\tList<ObservationRegistryCustomizer<?>> getCustomizers() {\n\t\t\treturn this.customizers;\n\t\t}\n\n\t}\n\n\tprivate static class Customizer1 implements ObservationRegistryCustomizer<ObservationRegistry> {\n\n\t\tprivate final CalledCustomizers calledCustomizers;\n\n\t\tCustomizer1(CalledCustomizers calledCustomizers) {\n\t\t\tthis.calledCustomizers = calledCustomizers;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ObservationRegistry registry) {\n\t\t\tthis.calledCustomizers.onCalled(this);\n\t\t}\n\n\t}\n\n\tprivate static class Customizer2 implements ObservationRegistryCustomizer<ObservationRegistry> {\n\n\t\tprivate final CalledCustomizers calledCustomizers;\n\n\t\tCustomizer2(CalledCustomizers calledCustomizers) {\n\t\t\tthis.calledCustomizers = calledCustomizers;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ObservationRegistry registry) {\n\t\t\tthis.calledCustomizers.onCalled(this);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/PropertiesObservationFilterPredicateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.common.KeyValue;\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.observation.Observation.Context;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesObservationFilterPredicate}.\n *\n * @author Moritz Halbritter\n */\nclass PropertiesObservationFilterPredicateTests {\n\n\t@Test\n\tvoid shouldDoNothingIfKeyValuesAreEmpty() {\n\t\tPropertiesObservationFilterPredicate filter = createFilter();\n\t\tContext mapped = mapContext(filter, \"a\", \"alpha\");\n\t\tassertThat(mapped.getLowCardinalityKeyValues()).containsExactly(KeyValue.of(\"a\", \"alpha\"));\n\t}\n\n\t@Test\n\tvoid shouldAddKeyValues() {\n\t\tPropertiesObservationFilterPredicate filter = createFilter(\"b\", \"beta\");\n\t\tContext mapped = mapContext(filter, \"a\", \"alpha\");\n\t\tassertThat(mapped.getLowCardinalityKeyValues()).containsExactly(KeyValue.of(\"a\", \"alpha\"),\n\t\t\t\tKeyValue.of(\"b\", \"beta\"));\n\t}\n\n\t@Test\n\tvoid shouldFilter() {\n\t\tPropertiesObservationFilterPredicate predicate = createPredicate(\"spring.security\");\n\t\tContext context = new Context();\n\t\tassertThat(predicate.test(\"spring.security.filterchains\", context)).isFalse();\n\t\tassertThat(predicate.test(\"spring.security\", context)).isFalse();\n\t\tassertThat(predicate.test(\"spring.data\", context)).isTrue();\n\t\tassertThat(predicate.test(\"spring\", context)).isTrue();\n\t}\n\n\t@Test\n\tvoid filterShouldFallbackToAll() {\n\t\tPropertiesObservationFilterPredicate predicate = createPredicate(\"all\");\n\t\tContext context = new Context();\n\t\tassertThat(predicate.test(\"spring.security.filterchains\", context)).isFalse();\n\t\tassertThat(predicate.test(\"spring.security\", context)).isFalse();\n\t\tassertThat(predicate.test(\"spring.data\", context)).isFalse();\n\t\tassertThat(predicate.test(\"spring\", context)).isFalse();\n\t}\n\n\t@Test\n\tvoid shouldNotFilterIfDisabledNamesIsEmpty() {\n\t\tPropertiesObservationFilterPredicate predicate = createPredicate();\n\t\tContext context = new Context();\n\t\tassertThat(predicate.test(\"spring.security.filterchains\", context)).isTrue();\n\t\tassertThat(predicate.test(\"spring.security\", context)).isTrue();\n\t\tassertThat(predicate.test(\"spring.data\", context)).isTrue();\n\t\tassertThat(predicate.test(\"spring\", context)).isTrue();\n\t}\n\n\tprivate static Context mapContext(PropertiesObservationFilterPredicate filter, String... initialKeyValues) {\n\t\tContext context = new Context();\n\t\tcontext.addLowCardinalityKeyValues(KeyValues.of(initialKeyValues));\n\t\treturn filter.map(context);\n\t}\n\n\tprivate static PropertiesObservationFilterPredicate createFilter(String... keyValues) {\n\t\tObservationProperties properties = new ObservationProperties();\n\t\tfor (int i = 0; i < keyValues.length; i += 2) {\n\t\t\tproperties.getKeyValues().put(keyValues[i], keyValues[i + 1]);\n\t\t}\n\t\treturn new PropertiesObservationFilterPredicate(properties);\n\t}\n\n\tprivate static PropertiesObservationFilterPredicate createPredicate(String... disabledNames) {\n\t\tObservationProperties properties = new ObservationProperties();\n\t\tfor (String name : disabledNames) {\n\t\t\tproperties.getEnable().put(name, false);\n\t\t}\n\t\treturn new PropertiesObservationFilterPredicate(properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/ScheduledTasksObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ScheduledTasksObservationAutoConfiguration.ObservabilitySchedulingConfigurer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.scheduling.config.ScheduledTaskRegistrar;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ScheduledTasksObservationAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass ScheduledTasksObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner().withConfiguration(AutoConfigurations\n\t\t.of(ObservationAutoConfiguration.class, ScheduledTasksObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldProvideObservabilitySchedulingConfigurer() {\n\t\tthis.runner.run((context) -> assertThat(context).hasSingleBean(ObservabilitySchedulingConfigurer.class));\n\t}\n\n\t@Test\n\tvoid observabilitySchedulingConfigurerShouldConfigureObservationRegistry() {\n\t\tObservationRegistry observationRegistry = ObservationRegistry.create();\n\t\tObservabilitySchedulingConfigurer configurer = new ObservabilitySchedulingConfigurer(observationRegistry);\n\t\tScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();\n\t\tconfigurer.configureTasks(registrar);\n\t\tassertThat(registrar.getObservationRegistry()).isEqualTo(observationRegistry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-observation/src/test/java/org/springframework/boot/micrometer/observation/autoconfigure/SpelValueExpressionResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.observation.autoconfigure;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SpelValueExpressionResolver}.\n *\n * @author Dominique Villard\n */\nclass SpelValueExpressionResolverTests {\n\n\tfinal SpelValueExpressionResolver resolver = new SpelValueExpressionResolver();\n\n\t@Test\n\tvoid checkValidExpression() {\n\t\tvar value = Map.of(\"foo\", Pair.of(1, 2));\n\t\tassertThat(this.resolver.resolve(\"['foo'].first\", value)).isEqualTo(\"1\");\n\t}\n\n\t@Test\n\tvoid checkInvalidExpression() {\n\t\tvar value = Map.of(\"foo\", Pair.of(1, 2));\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resolver.resolve(\"['bar'].first\", value));\n\t}\n\n\trecord Pair(int first, int second) {\n\n\t\tstatic Pair of(int first, int second) {\n\t\t\treturn new Pair(first, second);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Tracing\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-micrometer-observation\"))\n\tapi(\"io.micrometer:micrometer-tracing\") {\n\t\texclude(group: \"aopalliance\", module: \"aopalliance\")\n\t}\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(\"io.prometheus:prometheus-metrics-tracer-common\")\n\toptional(\"io.micrometer:micrometer-registry-otlp\")\n\toptional(\"org.aspectj:aspectjweaver\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/ConditionalOnEnabledTracingExport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether tracing is enabled. It matches if\n * the value of the {@code management.tracing.export.enabled} property is {@code true} or\n * if it is not configured. If the {@link #value() tracing exporter name} is set, the\n * {@code management.tracing.export.<name>.enabled} property can be used to control the\n * behavior for the specific tracing exporter. In that case, the exporter specific\n * property takes precedence over the global property.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnEnabledTracingExportCondition.class)\npublic @interface ConditionalOnEnabledTracingExport {\n\n\t/**\n\t * Name of the tracing exporter.\n\t * @return the name of the tracing exporter\n\t */\n\tString value() default \"\";\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/LogCorrelationEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnvironmentPostProcessor} to add a {@link PropertySource} to support log\n * correlation IDs when Micrometer Tracing is present. Adds support for the\n * {@value LoggingSystem#EXPECT_CORRELATION_ID_PROPERTY} property by delegating to\n * {@code management.tracing.export.enabled}.\n *\n * @author Jonatan Ivanov\n * @author Phillip Webb\n */\nclass LogCorrelationEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (ClassUtils.isPresent(\"io.micrometer.tracing.Tracer\", application.getClassLoader())) {\n\t\t\tenvironment.getPropertySources().addLast(new LogCorrelationPropertySource(this, environment));\n\t\t}\n\t}\n\n\t/**\n\t * Log correlation {@link PropertySource}.\n\t */\n\tprivate static class LogCorrelationPropertySource extends EnumerablePropertySource<Object> {\n\n\t\tprivate static final String NAME = \"logCorrelation\";\n\n\t\tprivate final Environment environment;\n\n\t\tLogCorrelationPropertySource(Object source, Environment environment) {\n\t\t\tsuper(NAME, source);\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getPropertyNames() {\n\t\t\treturn new String[] { LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY };\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object getProperty(String name) {\n\t\t\tif (name.equals(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY)) {\n\t\t\t\treturn this.environment.getProperty(\"management.tracing.export.enabled\", Boolean.class, Boolean.TRUE);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/MicrometerTracingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.annotation.DefaultNewSpanParser;\nimport io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor;\nimport io.micrometer.tracing.annotation.MethodInvocationProcessor;\nimport io.micrometer.tracing.annotation.NewSpanParser;\nimport io.micrometer.tracing.annotation.SpanAspect;\nimport io.micrometer.tracing.annotation.SpanTagAnnotationHandler;\nimport io.micrometer.tracing.handler.DefaultTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;\nimport io.micrometer.tracing.handler.TracingObservationHandler;\nimport io.micrometer.tracing.propagation.Propagator;\nimport org.aspectj.weaver.Advice;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGroup;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API.\n *\n * @author Moritz Halbritter\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@AutoConfiguration(after = ObservationAutoConfiguration.class)\n@ConditionalOnBean(Tracer.class)\npublic final class MicrometerTracingAutoConfiguration {\n\n\t/**\n\t * {@code @Order} value of {@link #defaultTracingObservationHandler(Tracer)}.\n\t */\n\tpublic static final int DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER = Ordered.LOWEST_PRECEDENCE - 1000;\n\n\t/**\n\t * {@code @Order} value of\n\t * {@link #propagatingReceiverTracingObservationHandler(Tracer, Propagator)}.\n\t */\n\tpublic static final int RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER = 1000;\n\n\t/**\n\t * {@code @Order} value of\n\t * {@link #propagatingSenderTracingObservationHandler(Tracer, Propagator)}.\n\t */\n\tpublic static final int SENDER_TRACING_OBSERVATION_HANDLER_ORDER = 2000;\n\n\t@Bean\n\tObservationHandlerGroup tracingObservationHandlerGroup(Tracer tracer) {\n\t\treturn ClassUtils.isPresent(\"io.micrometer.core.instrument.MeterRegistry\", null)\n\t\t\t\t? new TracingAndMeterObservationHandlerGroup(tracer)\n\t\t\t\t: ObservationHandlerGroup.of(TracingObservationHandler.class);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Order(DEFAULT_TRACING_OBSERVATION_HANDLER_ORDER)\n\tDefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {\n\t\treturn new DefaultTracingObservationHandler(tracer);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(Propagator.class)\n\t@Order(SENDER_TRACING_OBSERVATION_HANDLER_ORDER)\n\tPropagatingSenderTracingObservationHandler<?> propagatingSenderTracingObservationHandler(Tracer tracer,\n\t\t\tPropagator propagator) {\n\t\treturn new PropagatingSenderTracingObservationHandler<>(tracer, propagator);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(Propagator.class)\n\t@Order(RECEIVER_TRACING_OBSERVATION_HANDLER_ORDER)\n\tPropagatingReceiverTracingObservationHandler<?> propagatingReceiverTracingObservationHandler(Tracer tracer,\n\t\t\tPropagator propagator) {\n\t\treturn new PropagatingReceiverTracingObservationHandler<>(tracer, propagator);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Advice.class)\n\t@ConditionalOnBooleanProperty(\"management.observations.annotations.enabled\")\n\tstatic class SpanAspectConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(NewSpanParser.class)\n\t\tDefaultNewSpanParser newSpanParser() {\n\t\t\treturn new DefaultNewSpanParser();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnBean(ValueExpressionResolver.class)\n\t\tSpanTagAnnotationHandler spanTagAnnotationHandler(BeanFactory beanFactory,\n\t\t\t\tValueExpressionResolver valueExpressionResolver) {\n\t\t\treturn new SpanTagAnnotationHandler(beanFactory::getBean, (ignored) -> valueExpressionResolver);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(MethodInvocationProcessor.class)\n\t\tImperativeMethodInvocationProcessor imperativeMethodInvocationProcessor(NewSpanParser newSpanParser,\n\t\t\t\tTracer tracer, ObjectProvider<SpanTagAnnotationHandler> spanTagAnnotationHandler) {\n\t\t\treturn new ImperativeMethodInvocationProcessor(newSpanParser, tracer,\n\t\t\t\t\tspanTagAnnotationHandler.getIfAvailable());\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSpanAspect spanAspect(MethodInvocationProcessor methodInvocationProcessor) {\n\t\t\treturn new SpanAspect(methodInvocationProcessor);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/NoopTracerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport io.micrometer.tracing.Tracer;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a no-op implementation of\n * {@link Tracer}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(before = MicrometerTracingAutoConfiguration.class)\n@ConditionalOnClass(Tracer.class)\n@ConditionalOnMissingBean(Tracer.class)\npublic final class NoopTracerAutoConfiguration {\n\n\t@Bean\n\tTracer noopTracer() {\n\t\treturn Tracer.NOOP;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/OnEnabledTracingExportCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link SpringBootCondition} to check whether tracing is enabled.\n *\n * @author Moritz Halbritter\n * @see ConditionalOnEnabledTracingExport\n */\nclass OnEnabledTracingExportCondition extends SpringBootCondition {\n\n\tprivate static final String GLOBAL_PROPERTY = \"management.tracing.export.enabled\";\n\n\tprivate static final String EXPORTER_PROPERTY = \"management.tracing.export.%s.enabled\";\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tString tracingExporter = getExporterName(metadata);\n\t\tif (StringUtils.hasLength(tracingExporter)) {\n\t\t\tBoolean exporterTracingEnabled = context.getEnvironment()\n\t\t\t\t.getProperty(EXPORTER_PROPERTY.formatted(tracingExporter), Boolean.class);\n\t\t\tif (exporterTracingEnabled != null) {\n\t\t\t\treturn new ConditionOutcome(exporterTracingEnabled,\n\t\t\t\t\t\tConditionMessage.forCondition(ConditionalOnEnabledTracingExport.class)\n\t\t\t\t\t\t\t.because(EXPORTER_PROPERTY.formatted(tracingExporter) + \" is \" + exporterTracingEnabled));\n\t\t\t}\n\t\t}\n\t\tBoolean globalTracingEnabled = context.getEnvironment().getProperty(GLOBAL_PROPERTY, Boolean.class);\n\t\tif (globalTracingEnabled != null) {\n\t\t\treturn new ConditionOutcome(globalTracingEnabled,\n\t\t\t\t\tConditionMessage.forCondition(ConditionalOnEnabledTracingExport.class)\n\t\t\t\t\t\t.because(GLOBAL_PROPERTY + \" is \" + globalTracingEnabled));\n\t\t}\n\t\treturn ConditionOutcome.match(ConditionMessage.forCondition(ConditionalOnEnabledTracingExport.class)\n\t\t\t.because(\"tracing is enabled by default\"));\n\t}\n\n\tprivate static @Nullable String getExporterName(AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnEnabledTracingExport.class.getName());\n\t\tif (attributes == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (String) attributes.get(\"value\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/TracingAndMeterObservationHandlerGroup.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationRegistry.ObservationConfig;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;\nimport io.micrometer.tracing.handler.TracingObservationHandler;\n\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGroup;\n\n/**\n * {@link ObservationHandlerGroup} that considers both {@link TracingObservationHandler}\n * and {@link MeterObservationHandler} types as members. This group takes precedence over\n * any regular {@link MeterObservationHandler} group in order to ensure\n * {@link TracingAwareMeterObservationHandler} wrapping is applied during registration.\n *\n * @author Phillip Webb\n */\nclass TracingAndMeterObservationHandlerGroup implements ObservationHandlerGroup {\n\n\tprivate final Tracer tracer;\n\n\tTracingAndMeterObservationHandlerGroup(Tracer tracer) {\n\t\tthis.tracer = tracer;\n\t}\n\n\t@Override\n\tpublic boolean isMember(ObservationHandler<?> handler) {\n\t\treturn MeterObservationHandler.class.isInstance(handler) || TracingObservationHandler.class.isInstance(handler);\n\t}\n\n\t@Override\n\tpublic int compareTo(ObservationHandlerGroup other) {\n\t\tif (other instanceof TracingAndMeterObservationHandlerGroup) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn MeterObservationHandler.class.isAssignableFrom(other.handlerType()) ? -1 : 1;\n\t}\n\n\t@Override\n\tpublic void registerMembers(ObservationConfig config, List<ObservationHandler<?>> members) {\n\t\tList<ObservationHandler<?>> tracingHandlers = new ArrayList<>(members.size());\n\t\tList<ObservationHandler<?>> metricsHandlers = new ArrayList<>(members.size());\n\t\tfor (ObservationHandler<?> member : members) {\n\t\t\tif (member instanceof MeterObservationHandler<?> meterObservationHandler\n\t\t\t\t\t&& !(member instanceof TracingAwareMeterObservationHandler<?>)) {\n\t\t\t\tmetricsHandlers.add(new TracingAwareMeterObservationHandler<>(meterObservationHandler, this.tracer));\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttracingHandlers.add(member);\n\t\t\t}\n\t\t}\n\t\tregisterHandlers(config, tracingHandlers);\n\t\tregisterHandlers(config, metricsHandlers);\n\t}\n\n\tprivate void registerHandlers(ObservationConfig config, List<ObservationHandler<?>> handlers) {\n\t\tif (handlers.size() == 1) {\n\t\t\tconfig.observationHandler(handlers.get(0));\n\t\t}\n\t\telse if (!handlers.isEmpty()) {\n\t\t\tconfig.observationHandler(new FirstMatchingCompositeObservationHandler(handlers));\n\t\t}\n\t}\n\n\t@Override\n\tpublic Class<?> handlerType() {\n\t\treturn TracingObservationHandler.class;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/TracingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for tracing.\n *\n * @author Moritz Halbritter\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.tracing\")\npublic class TracingProperties {\n\n\t/**\n\t * Sampling configuration.\n\t */\n\tprivate final Sampling sampling = new Sampling();\n\n\t/**\n\t * Baggage configuration.\n\t */\n\tprivate final Baggage baggage = new Baggage();\n\n\t/**\n\t * Propagation configuration.\n\t */\n\tprivate final Propagation propagation = new Propagation();\n\n\t/**\n\t * Exemplars configuration.\n\t */\n\tprivate final Exemplars exemplars = new Exemplars();\n\n\tpublic Sampling getSampling() {\n\t\treturn this.sampling;\n\t}\n\n\tpublic Baggage getBaggage() {\n\t\treturn this.baggage;\n\t}\n\n\tpublic Propagation getPropagation() {\n\t\treturn this.propagation;\n\t}\n\n\tpublic Exemplars getExemplars() {\n\t\treturn this.exemplars;\n\t}\n\n\tpublic static class Sampling {\n\n\t\t/**\n\t\t * Probability in the range from 0.0 to 1.0 that a trace will be sampled.\n\t\t */\n\t\tprivate float probability = 0.10f;\n\n\t\tpublic float getProbability() {\n\t\t\treturn this.probability;\n\t\t}\n\n\t\tpublic void setProbability(float probability) {\n\t\t\tthis.probability = probability;\n\t\t}\n\n\t}\n\n\tpublic static class Baggage {\n\n\t\t/**\n\t\t * Whether to enable Micrometer Tracing baggage propagation.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\t/**\n\t\t * Correlation configuration.\n\t\t */\n\t\tprivate Correlation correlation = new Correlation();\n\n\t\t/**\n\t\t * List of fields that are referenced the same in-process as it is on the wire.\n\t\t * For example, the field \"x-vcap-request-id\" would be set as-is including the\n\t\t * prefix.\n\t\t */\n\t\tprivate List<String> remoteFields = new ArrayList<>();\n\n\t\t/**\n\t\t * List of fields that should be accessible within the JVM process but not\n\t\t * propagated over the wire. Local fields are not supported with OpenTelemetry.\n\t\t */\n\t\tprivate List<String> localFields = new ArrayList<>();\n\n\t\t/**\n\t\t * List of fields that should automatically become tags.\n\t\t */\n\t\tprivate List<String> tagFields = new ArrayList<>();\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic Correlation getCorrelation() {\n\t\t\treturn this.correlation;\n\t\t}\n\n\t\tpublic void setCorrelation(Correlation correlation) {\n\t\t\tthis.correlation = correlation;\n\t\t}\n\n\t\tpublic List<String> getRemoteFields() {\n\t\t\treturn this.remoteFields;\n\t\t}\n\n\t\tpublic List<String> getLocalFields() {\n\t\t\treturn this.localFields;\n\t\t}\n\n\t\tpublic List<String> getTagFields() {\n\t\t\treturn this.tagFields;\n\t\t}\n\n\t\tpublic void setRemoteFields(List<String> remoteFields) {\n\t\t\tthis.remoteFields = remoteFields;\n\t\t}\n\n\t\tpublic void setLocalFields(List<String> localFields) {\n\t\t\tthis.localFields = localFields;\n\t\t}\n\n\t\tpublic void setTagFields(List<String> tagFields) {\n\t\t\tthis.tagFields = tagFields;\n\t\t}\n\n\t\tpublic static class Correlation {\n\n\t\t\t/**\n\t\t\t * Whether to enable correlation of the baggage context with logging contexts.\n\t\t\t */\n\t\t\tprivate boolean enabled = true;\n\n\t\t\t/**\n\t\t\t * List of fields that should be correlated with the logging context. That\n\t\t\t * means that these fields would end up as key-value pairs in e.g. MDC.\n\t\t\t */\n\t\t\tprivate List<String> fields = new ArrayList<>();\n\n\t\t\tpublic boolean isEnabled() {\n\t\t\t\treturn this.enabled;\n\t\t\t}\n\n\t\t\tpublic void setEnabled(boolean enabled) {\n\t\t\t\tthis.enabled = enabled;\n\t\t\t}\n\n\t\t\tpublic List<String> getFields() {\n\t\t\t\treturn this.fields;\n\t\t\t}\n\n\t\t\tpublic void setFields(List<String> fields) {\n\t\t\t\tthis.fields = fields;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Propagation {\n\n\t\t/**\n\t\t * Tracing context propagation types produced and consumed by the application.\n\t\t * Setting this property overrides the more fine-grained propagation type\n\t\t * properties.\n\t\t */\n\t\tprivate @Nullable List<PropagationType> type;\n\n\t\t/**\n\t\t * Tracing context propagation types produced by the application.\n\t\t */\n\t\tprivate List<PropagationType> produce = List.of(PropagationType.W3C);\n\n\t\t/**\n\t\t * Tracing context propagation types consumed by the application.\n\t\t */\n\t\tprivate List<PropagationType> consume = List.of(PropagationType.values());\n\n\t\tpublic void setType(@Nullable List<PropagationType> type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tpublic void setProduce(List<PropagationType> produce) {\n\t\t\tthis.produce = produce;\n\t\t}\n\n\t\tpublic void setConsume(List<PropagationType> consume) {\n\t\t\tthis.consume = consume;\n\t\t}\n\n\t\tpublic @Nullable List<PropagationType> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tpublic List<PropagationType> getProduce() {\n\t\t\treturn this.produce;\n\t\t}\n\n\t\tpublic List<PropagationType> getConsume() {\n\t\t\treturn this.consume;\n\t\t}\n\n\t\t/**\n\t\t * Supported propagation types. The declared order of the values matter.\n\t\t */\n\t\tpublic enum PropagationType {\n\n\t\t\t/**\n\t\t\t * <a href=\"https://www.w3.org/TR/trace-context/\">W3C</a> propagation.\n\t\t\t */\n\t\t\tW3C,\n\n\t\t\t/**\n\t\t\t * <a href=\"https://github.com/openzipkin/b3-propagation#single-header\">B3\n\t\t\t * single header</a> propagation.\n\t\t\t */\n\t\t\tB3,\n\n\t\t\t/**\n\t\t\t * <a href=\"https://github.com/openzipkin/b3-propagation#multiple-headers\">B3\n\t\t\t * multiple headers</a> propagation.\n\t\t\t */\n\t\t\tB3_MULTI\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Exemplars configuration.\n\t */\n\tpublic static class Exemplars {\n\n\t\t/**\n\t\t * Traces to include as exemplars. 'all' is not supported when using Prometheus.\n\t\t */\n\t\tprivate Include include = Include.SAMPLED_TRACES;\n\n\t\tpublic Include getInclude() {\n\t\t\treturn this.include;\n\t\t}\n\n\t\tpublic void setInclude(Include include) {\n\t\t\tthis.include = include;\n\t\t}\n\n\t\tpublic enum Include {\n\n\t\t\t/**\n\t\t\t * Include all traces as exemplars, regardless of whether the span is sampled.\n\t\t\t */\n\t\t\tALL,\n\n\t\t\t/**\n\t\t\t * Don't include any traces as exemplars.\n\t\t\t */\n\t\t\tNONE,\n\n\t\t\t/**\n\t\t\t * Only include sampled traces as exemplars.\n\t\t\t */\n\t\t\tSAMPLED_TRACES\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/otlp/OtlpExemplarsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure.otlp;\n\nimport io.micrometer.registry.otlp.ExemplarContextProvider;\nimport io.micrometer.registry.otlp.OtlpExemplarContext;\nimport io.micrometer.tracing.Span;\nimport io.micrometer.tracing.TraceContext;\nimport io.micrometer.tracing.Tracer;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Exemplars.Include;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OTLP (OpenTelemetry Protocol)\n * Exemplars with Micrometer Tracing.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n * @since 4.1.0\n */\n@AutoConfiguration(\n\t\tbeforeName = \"org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration\",\n\t\tafter = MicrometerTracingAutoConfiguration.class)\n@ConditionalOnBean(Tracer.class)\n@ConditionalOnClass({ Tracer.class, ExemplarContextProvider.class })\n@EnableConfigurationProperties(TracingProperties.class)\npublic final class OtlpExemplarsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ExemplarContextProvider.class)\n\t@Conditional(ExemplarContextProviderNotDisabledCondition.class)\n\tLazyTracingExemplarContextProvider exemplarContextProvider(ObjectProvider<Tracer> tracerProvider,\n\t\t\tTracingProperties properties) {\n\t\treturn new LazyTracingExemplarContextProvider(tracerProvider, properties.getExemplars().getInclude());\n\t}\n\n\tstatic class ExemplarContextProviderNotDisabledCondition extends NoneNestedConditions {\n\n\t\tExemplarContextProviderNotDisabledCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(value = \"management.tracing.exemplars.include\", havingValue = \"none\")\n\t\tstatic class NoneIncluded {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the\n\t * {@link Tracer} can depend on the MeterRegistry (recording metrics), this\n\t * {@link ExemplarContextProvider} breaks the cycle by lazily loading the\n\t * {@link Tracer}.\n\t */\n\tstatic class LazyTracingExemplarContextProvider implements ExemplarContextProvider {\n\n\t\tprivate final SingletonSupplier<Tracer> tracer;\n\n\t\tprivate final Include include;\n\n\t\tLazyTracingExemplarContextProvider(ObjectProvider<Tracer> tracerProvider, Include include) {\n\t\t\tthis.tracer = SingletonSupplier.of(tracerProvider::getObject);\n\t\t\tthis.include = include;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable OtlpExemplarContext getExemplarContext() {\n\t\t\tSpan span = this.tracer.obtain().currentSpan();\n\t\t\tif (isExemplar(span)) {\n\t\t\t\tTraceContext context = span.context();\n\t\t\t\treturn new OtlpExemplarContext(context.traceId(), context.spanId());\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Contract(\"null -> false\")\n\t\tprivate boolean isExemplar(@Nullable Span span) {\n\t\t\tif (span == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn switch (this.include) {\n\t\t\t\tcase ALL -> true;\n\t\t\t\tcase NONE -> false;\n\t\t\t\tcase SAMPLED_TRACES -> isSampled(span);\n\t\t\t};\n\t\t}\n\n\t\tprivate boolean isSampled(Span span) {\n\t\t\tBoolean sampled = span.context().sampled();\n\t\t\treturn sampled != null && sampled;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for OTLP (OpenTelemetry Protocol) Exemplars with Micrometer Tracing.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.autoconfigure.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Micrometer Tracing.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/prometheus/PrometheusExemplarsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure.prometheus;\n\nimport io.micrometer.tracing.Span;\nimport io.micrometer.tracing.Tracer;\nimport io.prometheus.metrics.tracer.common.SpanContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Exemplars.Include;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.util.function.SingletonSupplier;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Prometheus Exemplars with\n * Micrometer Tracing.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbeforeName = \"org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus.PrometheusMetricsExportAutoConfiguration\",\n\t\tafter = MicrometerTracingAutoConfiguration.class)\n@ConditionalOnBean(Tracer.class)\n@ConditionalOnClass({ Tracer.class, SpanContext.class })\n@EnableConfigurationProperties(TracingProperties.class)\npublic final class PrometheusExemplarsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(SpanContext.class)\n\t@Conditional(SpanContextNotDisabledCondition.class)\n\tLazyTracingSpanContext spanContext(ObjectProvider<Tracer> tracerProvider, TracingProperties properties) {\n\t\treturn new LazyTracingSpanContext(tracerProvider, properties.getExemplars().getInclude());\n\t}\n\n\tstatic class SpanContextNotDisabledCondition extends NoneNestedConditions {\n\n\t\tSpanContextNotDisabledCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(value = \"management.tracing.exemplars.include\", havingValue = \"none\")\n\t\tstatic class NoneIncluded {\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Since the MeterRegistry can depend on the {@link Tracer} (Exemplars) and the\n\t * {@link Tracer} can depend on the MeterRegistry (recording metrics), this\n\t * {@link SpanContext} breaks the cycle by lazily loading the {@link Tracer}.\n\t */\n\tstatic class LazyTracingSpanContext implements SpanContext {\n\n\t\tprivate final SingletonSupplier<Tracer> tracer;\n\n\t\tprivate final Include include;\n\n\t\tLazyTracingSpanContext(ObjectProvider<Tracer> tracerProvider, Include include) {\n\t\t\tif (include == Include.ALL) {\n\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"management.tracing.exemplars.include\", \"all\",\n\t\t\t\t\t\t\"Prometheus doesn't support including 'all' traces as exemplars.\");\n\t\t\t}\n\t\t\tthis.tracer = SingletonSupplier.of(tracerProvider::getObject);\n\t\t\tthis.include = include;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getCurrentTraceId() {\n\t\t\tSpan currentSpan = currentSpan();\n\t\t\treturn (currentSpan != null) ? currentSpan.context().traceId() : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getCurrentSpanId() {\n\t\t\tSpan currentSpan = currentSpan();\n\t\t\treturn (currentSpan != null) ? currentSpan.context().spanId() : null;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isCurrentSpanSampled() {\n\t\t\tSpan currentSpan = currentSpan();\n\t\t\tif (currentSpan == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn switch (this.include) {\n\t\t\t\tcase ALL ->\n\t\t\t\t\tthrow new UnsupportedOperationException(\"Including 'all' traces as exemplars is not supported\");\n\t\t\t\tcase NONE -> false;\n\t\t\t\tcase SAMPLED_TRACES -> isSampled(currentSpan);\n\t\t\t};\n\t\t}\n\n\t\t@Override\n\t\tpublic void markCurrentSpanAsExemplar() {\n\t\t}\n\n\t\tprivate boolean isSampled(Span span) {\n\t\t\tBoolean sampled = span.context().sampled();\n\t\t\treturn sampled != null && sampled;\n\t\t}\n\n\t\tprivate @Nullable Span currentSpan() {\n\t\t\treturn this.tracer.obtain().currentSpan();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/java/org/springframework/boot/micrometer/tracing/autoconfigure/prometheus/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Prometheus Exemplars with Micrometer Tracing.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.autoconfigure.prometheus;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.tracing.enabled\",\n      \"deprecation\": {\n        \"replacement\": \"management.tracing.export.enabled\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.export.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether auto-configuration of tracing is enabled to export and propagate traces.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.tracing.propagation.consume\",\n      \"defaultValue\": [\n        \"W3C\",\n        \"B3\",\n        \"B3_MULTI\"\n      ]\n    },\n    {\n      \"name\": \"management.tracing.propagation.produce\",\n      \"defaultValue\": [\n        \"W3C\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration\norg.springframework.boot.micrometer.tracing.autoconfigure.NoopTracerAutoConfiguration\norg.springframework.boot.micrometer.tracing.autoconfigure.otlp.OtlpExemplarsAutoConfiguration\norg.springframework.boot.micrometer.tracing.autoconfigure.prometheus.PrometheusExemplarsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.management.tracing.sampling.probability=1.0\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/main/resources/META-INF/spring.factories",
    "content": "# Environment Post Processors\norg.springframework.boot.EnvironmentPostProcessor=\\\norg.springframework.boot.micrometer.tracing.autoconfigure.LogCorrelationEnvironmentPostProcessor\n\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/LogCorrelationEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LogCorrelationEnvironmentPostProcessor}.\n *\n * @author Jonatan Ivanov\n * @author Phillip Webb\n */\nclass LogCorrelationEnvironmentPostProcessorTests {\n\n\tprivate final ConfigurableEnvironment environment = new StandardEnvironment();\n\n\tprivate final SpringApplication application = new SpringApplication();\n\n\tprivate final LogCorrelationEnvironmentPostProcessor postProcessor = new LogCorrelationEnvironmentPostProcessor();\n\n\t@Test\n\tvoid getExpectCorrelationIdPropertyWhenMicrometerTracingPresentReturnsTrue() {\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tassertThat(this.environment.getProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, Boolean.class, false))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"micrometer-tracing-*.jar\")\n\tvoid getExpectCorrelationIdPropertyWhenMicrometerTracingMissingReturnsFalse() {\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tassertThat(this.environment.getProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, Boolean.class, false))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid getExpectCorrelationIdPropertyWhenTracingDisabledReturnsFalse() {\n\t\tTestPropertyValues.of(\"management.tracing.export.enabled=false\").applyTo(this.environment);\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tassertThat(this.environment.getProperty(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY, Boolean.class, false))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid postProcessEnvironmentAddsEnumerablePropertySource() {\n\t\tthis.postProcessor.postProcessEnvironment(this.environment, this.application);\n\t\tPropertySource<?> propertySource = this.environment.getPropertySources().get(\"logCorrelation\");\n\t\tassertThat(propertySource).isInstanceOf(EnumerablePropertySource.class);\n\t\tassertThat(((EnumerablePropertySource<?>) propertySource).getPropertyNames())\n\t\t\t.containsExactly(LoggingSystem.EXPECT_CORRELATION_ID_PROPERTY);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/MicrometerTracingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.common.annotation.ValueExpressionResolver;\nimport io.micrometer.common.annotation.ValueResolver;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.annotation.DefaultNewSpanParser;\nimport io.micrometer.tracing.annotation.ImperativeMethodInvocationProcessor;\nimport io.micrometer.tracing.annotation.MethodInvocationProcessor;\nimport io.micrometer.tracing.annotation.NewSpanParser;\nimport io.micrometer.tracing.annotation.SpanAspect;\nimport io.micrometer.tracing.annotation.SpanTagAnnotationHandler;\nimport io.micrometer.tracing.handler.DefaultTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;\nimport io.micrometer.tracing.handler.TracingObservationHandler;\nimport io.micrometer.tracing.propagation.Propagator;\nimport org.aspectj.weaver.Advice;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGroup;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MicrometerTracingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Jonatan Ivanov\n * @author Brian Clozel\n */\nclass MicrometerTracingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"management.observations.annotations.enabled=true\")\n\t\t.withBean(ValueExpressionResolver.class, () -> mock(ValueExpressionResolver.class))\n\t\t.withConfiguration(AutoConfigurations.of(MicrometerTracingAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class, PropagatorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasSingleBean(DefaultNewSpanParser.class);\n\t\t\t\tassertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);\n\t\t\t\tassertThat(context).hasSingleBean(SpanAspect.class);\n\t\t\t\tassertThat(context).hasSingleBean(SpanTagAnnotationHandler.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid shouldSupplyBeansInCorrectOrder() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class, PropagatorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tList<TracingObservationHandler> tracingObservationHandlers = context\n\t\t\t\t\t.getBeanProvider(TracingObservationHandler.class)\n\t\t\t\t\t.orderedStream()\n\t\t\t\t\t.toList();\n\t\t\t\tassertThat(tracingObservationHandlers).hasSize(3);\n\t\t\t\tassertThat(tracingObservationHandlers.get(0))\n\t\t\t\t\t.isInstanceOf(PropagatingReceiverTracingObservationHandler.class);\n\t\t\t\tassertThat(tracingObservationHandlers.get(1))\n\t\t\t\t\t.isInstanceOf(PropagatingSenderTracingObservationHandler.class);\n\t\t\t\tassertThat(tracingObservationHandlers.get(2)).isInstanceOf(DefaultTracingObservationHandler.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class, CustomConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"customDefaultTracingObservationHandler\");\n\t\t\t\tassertThat(context).hasSingleBean(DefaultTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasBean(\"customPropagatingReceiverTracingObservationHandler\");\n\t\t\t\tassertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasBean(\"customPropagatingSenderTracingObservationHandler\");\n\t\t\t\tassertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasBean(\"customDefaultNewSpanParser\");\n\t\t\t\tassertThat(context).hasSingleBean(DefaultNewSpanParser.class);\n\t\t\t\tassertThat(context).hasBean(\"customImperativeMethodInvocationProcessor\");\n\t\t\t\tassertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);\n\t\t\t\tassertThat(context).hasBean(\"customSpanAspect\");\n\t\t\t\tassertThat(context).hasSingleBean(SpanAspect.class);\n\t\t\t\tassertThat(context).hasBean(\"customSpanTagAnnotationHandler\");\n\t\t\t\tassertThat(context).hasSingleBean(SpanTagAnnotationHandler.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfMicrometerIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer\")).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);\n\t\t\tassertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanAspect.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfTracerIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(PropagatorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(DefaultTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);\n\t\t\tassertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanAspect.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyAspectBeansIfPropertyIsDisabled() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class, PropagatorConfiguration.class)\n\t\t\t.withPropertyValues(\"management.observations.annotations.enabled=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(SpanAspect.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfAspectjIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(Advice.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(DefaultNewSpanParser.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(ImperativeMethodInvocationProcessor.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(SpanAspect.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfPropagatorIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(PropagatingSenderTracingObservationHandler.class);\n\t\t\tassertThat(context).doesNotHaveBean(PropagatingReceiverTracingObservationHandler.class);\n\n\t\t\tassertThat(context).hasSingleBean(DefaultNewSpanParser.class);\n\t\t\tassertThat(context).hasSingleBean(ImperativeMethodInvocationProcessor.class);\n\t\t\tassertThat(context).hasSingleBean(SpanAspect.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureSpanTagAnnotationHandler() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class, SpanTagAnnotationHandlerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DefaultNewSpanParser.class);\n\t\t\t\tassertThat(context).hasSingleBean(SpanAspect.class);\n\t\t\t\tassertThat(context.getBean(ImperativeMethodInvocationProcessor.class)).hasFieldOrPropertyWithValue(\n\t\t\t\t\t\t\"spanTagAnnotationHandler\", context.getBean(SpanTagAnnotationHandler.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateTracingAndMeterObservationHandlerGroupWhenHasTracing() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ObservationHandlerGroup.class);\n\t\t\tObservationHandlerGroup group = context.getBean(ObservationHandlerGroup.class);\n\t\t\tassertThat(group).isInstanceOf(TracingAndMeterObservationHandlerGroup.class);\n\t\t\tassertThat(group.isMember(mock(ObservationHandler.class))).isFalse();\n\t\t\tassertThat(group.isMember(mock(TracingObservationHandler.class))).isTrue();\n\t\t\tassertThat(group.isMember(mock(MeterObservationHandler.class))).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateTracingObservationHandlerGroupWhenMetricsIsNotOnClassPath() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"io.micrometer.core\"))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ObservationHandlerGroup.class);\n\t\t\t\tObservationHandlerGroup group = context.getBean(ObservationHandlerGroup.class);\n\t\t\t\tassertThat(group).isNotInstanceOf(TracingAndMeterObservationHandlerGroup.class);\n\t\t\t\tassertThat(group.isMember(mock(ObservationHandler.class))).isFalse();\n\t\t\t\tassertThat(group.isMember(mock(TracingObservationHandler.class))).isTrue();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class TracerConfiguration {\n\n\t\t@Bean\n\t\tTracer tracer() {\n\t\t\treturn mock(Tracer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class PropagatorConfiguration {\n\n\t\t@Bean\n\t\tPropagator propagator() {\n\t\t\treturn mock(Propagator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\t@Bean\n\t\tDefaultTracingObservationHandler customDefaultTracingObservationHandler() {\n\t\t\treturn mock(DefaultTracingObservationHandler.class);\n\t\t}\n\n\t\t@Bean\n\t\tPropagatingReceiverTracingObservationHandler<?> customPropagatingReceiverTracingObservationHandler() {\n\t\t\treturn mock(PropagatingReceiverTracingObservationHandler.class);\n\t\t}\n\n\t\t@Bean\n\t\tPropagatingSenderTracingObservationHandler<?> customPropagatingSenderTracingObservationHandler() {\n\t\t\treturn mock(PropagatingSenderTracingObservationHandler.class);\n\t\t}\n\n\t\t@Bean\n\t\tDefaultNewSpanParser customDefaultNewSpanParser() {\n\t\t\treturn new DefaultNewSpanParser();\n\t\t}\n\n\t\t@Bean\n\t\tImperativeMethodInvocationProcessor customImperativeMethodInvocationProcessor(NewSpanParser newSpanParser,\n\t\t\t\tTracer tracer) {\n\t\t\treturn new ImperativeMethodInvocationProcessor(newSpanParser, tracer);\n\t\t}\n\n\t\t@Bean\n\t\tSpanAspect customSpanAspect(MethodInvocationProcessor methodInvocationProcessor) {\n\t\t\treturn new SpanAspect(methodInvocationProcessor);\n\t\t}\n\n\t\t@Bean\n\t\tSpanTagAnnotationHandler customSpanTagAnnotationHandler() {\n\t\t\treturn new SpanTagAnnotationHandler((aClass) -> mock(ValueResolver.class),\n\t\t\t\t\t(aClass) -> mock(ValueExpressionResolver.class));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class SpanTagAnnotationHandlerConfiguration {\n\n\t\t@Bean\n\t\tSpanTagAnnotationHandler spanTagAnnotationHandler() {\n\t\t\treturn new SpanTagAnnotationHandler((valueResolverClass) -> mock(ValueResolver.class),\n\t\t\t\t\t(valueExpressionResolverClass) -> mock(ValueExpressionResolver.class));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/NoopTracerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport io.micrometer.tracing.Tracer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NoopTracerAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass NoopTracerAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(NoopTracerAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyNoopTracer() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Tracer.class);\n\t\t\tTracer tracer = context.getBean(Tracer.class);\n\t\t\tassertThat(tracer).isEqualTo(Tracer.NOOP);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomTracer() {\n\t\tthis.contextRunner.withUserConfiguration(CustomTracerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Tracer.class);\n\t\t\tassertThat(context).hasBean(\"customTracer\");\n\t\t\tTracer tracer = context.getBean(Tracer.class);\n\t\t\tassertThat(tracer).isNotEqualTo(Tracer.NOOP);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfMicrometerTracingIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer.tracing\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Tracer.class));\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomTracerConfiguration {\n\n\t\t@Bean\n\t\tTracer customTracer() {\n\t\t\treturn mock(Tracer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/OnEnabledTracingExportConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OnEnabledTracingExportCondition}.\n *\n * @author Moritz Halbritter\n */\nclass OnEnabledTracingExportConditionTests {\n\n\t@Test\n\tvoid shouldMatchIfNoPropertyIsSet() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(), mockMetadata(\"\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"@ConditionalOnEnabledTracingExport tracing is enabled by default\");\n\t}\n\n\t@Test\n\tvoid shouldNotMatchIfGlobalPropertyIsFalse() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(Map.of(\"management.tracing.export.enabled\", \"false\")), mockMetadata(\"\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledTracingExport management.tracing.export.enabled is false\");\n\t}\n\n\t@Test\n\tvoid shouldMatchIfGlobalPropertyIsTrue() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(Map.of(\"management.tracing.export.enabled\", \"true\")), mockMetadata(\"\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledTracingExport management.tracing.export.enabled is true\");\n\t}\n\n\t@Test\n\tvoid shouldNotMatchIfExporterPropertyIsFalse() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(Map.of(\"management.tracing.export.zipkin.enabled\", \"false\")),\n\t\t\t\tmockMetadata(\"zipkin\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledTracingExport management.tracing.export.zipkin.enabled is false\");\n\t}\n\n\t@Test\n\tvoid shouldMatchIfExporterPropertyIsTrue() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(Map.of(\"management.tracing.export.zipkin.enabled\", \"true\")),\n\t\t\t\tmockMetadata(\"zipkin\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledTracingExport management.tracing.export.zipkin.enabled is true\");\n\t}\n\n\t@Test\n\tvoid exporterPropertyShouldOverrideGlobalPropertyIfTrue() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map\n\t\t\t.of(\"management.tracing.export.enabled\", \"false\", \"management.tracing.export.zipkin.enabled\", \"true\")),\n\t\t\t\tmockMetadata(\"zipkin\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledTracingExport management.tracing.export.zipkin.enabled is true\");\n\t}\n\n\t@Test\n\tvoid exporterPropertyShouldOverrideGlobalPropertyIfFalse() {\n\t\tOnEnabledTracingExportCondition condition = new OnEnabledTracingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map\n\t\t\t.of(\"management.tracing.export.enabled\", \"true\", \"management.tracing.export.zipkin.enabled\", \"false\")),\n\t\t\t\tmockMetadata(\"zipkin\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledTracingExport management.tracing.export.zipkin.enabled is false\");\n\t}\n\n\tprivate ConditionContext mockConditionContext() {\n\t\treturn mockConditionContext(Collections.emptyMap());\n\t}\n\n\tprivate ConditionContext mockConditionContext(Map<String, String> properties) {\n\t\tConditionContext context = mock(ConditionContext.class);\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tproperties.forEach(environment::setProperty);\n\t\tgiven(context.getEnvironment()).willReturn(environment);\n\t\treturn context;\n\t}\n\n\tprivate AnnotatedTypeMetadata mockMetadata(String exporter) {\n\t\tAnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);\n\t\tgiven(metadata.getAnnotationAttributes(ConditionalOnEnabledTracingExport.class.getName()))\n\t\t\t.willReturn(Map.of(\"value\", exporter));\n\t\treturn metadata;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/TracingAndMeterObservationHandlerGroupTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationHandler.FirstMatchingCompositeObservationHandler;\nimport io.micrometer.observation.ObservationRegistry.ObservationConfig;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;\nimport io.micrometer.tracing.handler.TracingObservationHandler;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationHandlerGroup;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link TracingAndMeterObservationHandlerGroup}.\n *\n * @author Phillip Webb\n */\nclass TracingAndMeterObservationHandlerGroupTests {\n\n\t@Test\n\tvoid compareToSortsBeforeMeterObservationHandlerGroup() {\n\t\tObservationHandlerGroup meterGroup = ObservationHandlerGroup.of(MeterObservationHandler.class);\n\t\tTracingAndMeterObservationHandlerGroup tracingAndMeterGroup = new TracingAndMeterObservationHandlerGroup(\n\t\t\t\tmock(Tracer.class));\n\t\tassertThat(sort(meterGroup, tracingAndMeterGroup)).containsExactly(tracingAndMeterGroup, meterGroup);\n\t\tassertThat(sort(tracingAndMeterGroup, meterGroup)).containsExactly(tracingAndMeterGroup, meterGroup);\n\t}\n\n\t@Test\n\tvoid isMemberAcceptsMeterObservationHandlerOrTracingObservationHandler() {\n\t\tTracingAndMeterObservationHandlerGroup group = new TracingAndMeterObservationHandlerGroup(mock(Tracer.class));\n\t\tassertThat(group.isMember(mock(ObservationHandler.class))).isFalse();\n\t\tassertThat(group.isMember(mock(MeterObservationHandler.class))).isTrue();\n\t\tassertThat(group.isMember(mock(TracingObservationHandler.class))).isTrue();\n\t}\n\n\t@Test\n\tvoid registerMembersWrapsMeterObservationHandlersAndRegistersDistinctGroups() {\n\t\tTracer tracer = mock(Tracer.class);\n\t\tTracingAndMeterObservationHandlerGroup group = new TracingAndMeterObservationHandlerGroup(tracer);\n\t\tTracingObservationHandler<?> tracingHandler1 = mock(TracingObservationHandler.class);\n\t\tTracingObservationHandler<?> tracingHandler2 = mock(TracingObservationHandler.class);\n\t\tMeterObservationHandler<?> meterHandler1 = mock(MeterObservationHandler.class);\n\t\tMeterObservationHandler<?> meterHandler2 = mock(MeterObservationHandler.class);\n\t\tObservationConfig config = mock(ObservationConfig.class);\n\t\tList<ObservationHandler<?>> members = List.of(tracingHandler1, meterHandler1, tracingHandler2, meterHandler2);\n\t\tgroup.registerMembers(config, members);\n\t\tArgumentCaptor<ObservationHandler<?>> handlerCaptor = ArgumentCaptor.captor();\n\t\tthen(config).should(times(2)).observationHandler(handlerCaptor.capture());\n\t\tList<ObservationHandler<?>> actualComposites = handlerCaptor.getAllValues();\n\t\tassertThat(actualComposites).hasSize(2);\n\t\tObservationHandler<?> tracingComposite = actualComposites.get(0);\n\t\tassertThat(tracingComposite).isInstanceOf(FirstMatchingCompositeObservationHandler.class)\n\t\t\t.extracting(\"handlers\", InstanceOfAssertFactories.LIST)\n\t\t\t.containsExactly(tracingHandler1, tracingHandler2);\n\t\tObservationHandler<?> metricsComposite = actualComposites.get(1);\n\t\tassertThat(metricsComposite).isInstanceOf(FirstMatchingCompositeObservationHandler.class)\n\t\t\t.extracting(\"handlers\", InstanceOfAssertFactories.LIST)\n\t\t\t.extracting(\"delegate\")\n\t\t\t.containsExactly(meterHandler1, meterHandler2);\n\t}\n\n\t@Test\n\tvoid registerMembersOnlyUsesCompositeWhenMoreThanOneHandler() {\n\t\tTracer tracer = mock(Tracer.class);\n\t\tTracingAndMeterObservationHandlerGroup group = new TracingAndMeterObservationHandlerGroup(tracer);\n\t\tTracingObservationHandler<?> tracingHandler1 = mock(TracingObservationHandler.class);\n\t\tTracingObservationHandler<?> tracingHandler2 = mock(TracingObservationHandler.class);\n\t\tMeterObservationHandler<?> meterHandler = mock(MeterObservationHandler.class);\n\t\tObservationConfig config = mock(ObservationConfig.class);\n\t\tList<ObservationHandler<?>> members = List.of(tracingHandler1, meterHandler, tracingHandler2);\n\t\tgroup.registerMembers(config, members);\n\t\tArgumentCaptor<ObservationHandler<?>> handlerCaptor = ArgumentCaptor.captor();\n\t\tthen(config).should(times(2)).observationHandler(handlerCaptor.capture());\n\t\tList<ObservationHandler<?>> actualComposites = handlerCaptor.getAllValues();\n\t\tassertThat(actualComposites).hasSize(2);\n\t\tassertThat(actualComposites.get(0)).isInstanceOf(FirstMatchingCompositeObservationHandler.class);\n\t\tassertThat(actualComposites.get(1)).isInstanceOf(TracingAwareMeterObservationHandler.class);\n\t}\n\n\tprivate List<ObservationHandlerGroup> sort(ObservationHandlerGroup... groups) {\n\t\tList<ObservationHandlerGroup> list = new ArrayList<>(List.of(groups));\n\t\tCollections.sort(list);\n\t\treturn list;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/otlp/LazyTracingExemplarContextProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure.otlp;\n\nimport io.micrometer.tracing.Span;\nimport io.micrometer.tracing.TraceContext;\nimport io.micrometer.tracing.Tracer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Exemplars.Include;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.otlp.OtlpExemplarsAutoConfiguration.LazyTracingExemplarContextProvider;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LazyTracingExemplarContextProvider}.\n *\n * @author Jonatan Ivanov\n */\nclass LazyTracingExemplarContextProviderTests {\n\n\tprivate final Tracer tracer = mock(Tracer.class);\n\n\tprivate final ObjectProvider<Tracer> objectProvider = new ObjectProvider<>() {\n\t\t@Override\n\t\tpublic Tracer getObject() throws BeansException {\n\t\t\treturn LazyTracingExemplarContextProviderTests.this.tracer;\n\t\t}\n\n\t\t@Override\n\t\tpublic Tracer getObject(@Nullable Object... args) throws BeansException {\n\t\t\treturn LazyTracingExemplarContextProviderTests.this.tracer;\n\t\t}\n\n\t\t@Override\n\t\tpublic Tracer getIfAvailable() throws BeansException {\n\t\t\treturn LazyTracingExemplarContextProviderTests.this.tracer;\n\t\t}\n\n\t\t@Override\n\t\tpublic Tracer getIfUnique() throws BeansException {\n\t\t\treturn LazyTracingExemplarContextProviderTests.this.tracer;\n\t\t}\n\n\t};\n\n\tprivate LazyTracingExemplarContextProvider contextProvider = new LazyTracingExemplarContextProvider(\n\t\t\tthis.objectProvider, Include.SAMPLED_TRACES);\n\n\t@Test\n\tvoid whenCurrentSpanIsNullThenExemplarContextIsNull() {\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasSpanIdThenSpanIdIsFromSpan() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(traceContext.spanId()).willReturn(\"span-id\");\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNotNull();\n\t\tassertThat(this.contextProvider.getExemplarContext().getSpanId()).isEqualTo(\"span-id\");\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasTraceIdThenTraceIdIsFromSpan() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(traceContext.traceId()).willReturn(\"trace-id\");\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNotNull();\n\t\tassertThat(this.contextProvider.getExemplarContext().getTraceId()).isEqualTo(\"trace-id\");\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasNoSpanIdThenSpanIdIsNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNotNull();\n\t\tassertThat(this.contextProvider.getExemplarContext().getSpanId()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasNoTraceIdThenTraceIdIsNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNotNull();\n\t\tassertThat(this.contextProvider.getExemplarContext().getTraceId()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanIsSampledThenExemplarContextIsNotNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanIsNotSampledThenExemplarContextIsNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(false);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasDeferredSamplingThenExemplarContextIsNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(null);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNull();\n\t}\n\n\t@Test\n\tvoid whenIncludeIsAllAndSpanIsNotSampledThenExemplarContextIsNotNull() {\n\t\tthis.contextProvider = new LazyTracingExemplarContextProvider(this.objectProvider, Include.ALL);\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(false);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenIncludeIsAllAndCurrentSpanIsNullThenExemplarContextIsNull() {\n\t\tthis.contextProvider = new LazyTracingExemplarContextProvider(this.objectProvider, Include.ALL);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNull();\n\t}\n\n\t@Test\n\tvoid whenIncludeIsNoneAndSpanIsSampledThenExemplarContextIsNull() {\n\t\tthis.contextProvider = new LazyTracingExemplarContextProvider(this.objectProvider, Include.NONE);\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.contextProvider.getExemplarContext()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/otlp/OtlpExemplarsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure.otlp;\n\nimport io.micrometer.registry.otlp.ExemplarContextProvider;\nimport io.micrometer.tracing.Tracer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.otlp.OtlpExemplarsAutoConfiguration.LazyTracingExemplarContextProvider;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OtlpExemplarsAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass OtlpExemplarsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OtlpExemplarsAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyExemplarContextProvider() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ExemplarContextProvider.class);\n\t\t\tassertThat(context).hasSingleBean(LazyTracingExemplarContextProvider.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomExemplarContextProvider() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(TracerConfiguration.class, CustomExemplarContextProviderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ExemplarContextProvider.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(LazyTracingExemplarContextProvider.class);\n\t\t\t\tassertThat(context).hasBean(\"customExemplarContextProvider\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyExemplarContextProviderWhenTracerBeanIsMissing() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyExemplarContextProviderWhenTracerClassIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Tracer.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyExemplarContextProviderWhenExemplarContextProviderClassIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(ExemplarContextProvider.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyExemplarContextProviderWhenIncludeIsNone() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyExemplarContextProviderWhenIncludeIsSampledTraces() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=sampled-traces\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyExemplarContextProviderWhenIncludeIsAll() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=all\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ExemplarContextProvider.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class TracerConfiguration {\n\n\t\t@Bean\n\t\tTracer tracer() {\n\t\t\treturn mock(Tracer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomExemplarContextProviderConfiguration {\n\n\t\t@Bean\n\t\tExemplarContextProvider customExemplarContextProvider() {\n\t\t\treturn mock(ExemplarContextProvider.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/prometheus/LazyTracingSpanContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure.prometheus;\n\nimport io.micrometer.tracing.Span;\nimport io.micrometer.tracing.TraceContext;\nimport io.micrometer.tracing.Tracer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Exemplars.Include;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.prometheus.PrometheusExemplarsAutoConfiguration.LazyTracingSpanContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LazyTracingSpanContext}.\n *\n * @author Andy Wilkinson\n */\nclass LazyTracingSpanContextTests {\n\n\tprivate final Tracer tracer = mock(Tracer.class);\n\n\tprivate final ObjectProvider<Tracer> objectProvider = new ObjectProvider<>() {\n\n\t\t@Override\n\t\tpublic Tracer getObject() throws BeansException {\n\t\t\treturn LazyTracingSpanContextTests.this.tracer;\n\t\t}\n\n\t\t@Override\n\t\tpublic Tracer getObject(@Nullable Object... args) throws BeansException {\n\t\t\treturn LazyTracingSpanContextTests.this.tracer;\n\t\t}\n\n\t\t@Override\n\t\tpublic Tracer getIfAvailable() throws BeansException {\n\t\t\treturn LazyTracingSpanContextTests.this.tracer;\n\t\t}\n\n\t\t@Override\n\t\tpublic Tracer getIfUnique() throws BeansException {\n\t\t\treturn LazyTracingSpanContextTests.this.tracer;\n\t\t}\n\n\t};\n\n\tprivate LazyTracingSpanContext spanContext = new LazyTracingSpanContext(this.objectProvider,\n\t\t\tInclude.SAMPLED_TRACES);\n\n\t@Test\n\tvoid whenCurrentSpanIsNullThenSpanIdIsNull() {\n\t\tassertThat(this.spanContext.getCurrentSpanId()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanIsNullThenTraceIdIsNull() {\n\t\tassertThat(this.spanContext.getCurrentTraceId()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanIsNullThenSampledIsFalse() {\n\t\tassertThat(this.spanContext.isCurrentSpanSampled()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasSpanIdThenSpanIdIsFromSpan() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.spanId()).willReturn(\"span-id\");\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.getCurrentSpanId()).isEqualTo(\"span-id\");\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasTraceIdThenTraceIdIsFromSpan() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.traceId()).willReturn(\"trace-id\");\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.getCurrentTraceId()).isEqualTo(\"trace-id\");\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasNoSpanIdThenSpanIdIsNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.getCurrentSpanId()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasNoTraceIdThenTraceIdIsNull() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.getCurrentTraceId()).isNull();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanIsSampledThenSampledIsTrue() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.isCurrentSpanSampled()).isTrue();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanIsNotSampledThenSampledIsFalse() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(false);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.isCurrentSpanSampled()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenCurrentSpanHasDeferredSamplingThenSampledIsFalse() {\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(null);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.isCurrentSpanSampled()).isFalse();\n\t}\n\n\t@Test\n\tvoid whenIncludeIsAllThenConstructorThrows() {\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)\n\t\t\t.isThrownBy(() -> new LazyTracingSpanContext(this.objectProvider, Include.ALL));\n\t}\n\n\t@Test\n\tvoid whenIncludeIsNoneAndSpanIsSampledThenSampledIsFalse() {\n\t\tthis.spanContext = new LazyTracingSpanContext(this.objectProvider, Include.NONE);\n\t\tSpan span = mock(Span.class);\n\t\tgiven(this.tracer.currentSpan()).willReturn(span);\n\t\tTraceContext traceContext = mock(TraceContext.class);\n\t\tgiven(traceContext.sampled()).willReturn(true);\n\t\tgiven(span.context()).willReturn(traceContext);\n\t\tassertThat(this.spanContext.isCurrentSpanSampled()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing/src/test/java/org/springframework/boot/micrometer/tracing/autoconfigure/prometheus/PrometheusExemplarsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.autoconfigure.prometheus;\n\nimport io.micrometer.tracing.Tracer;\nimport io.prometheus.metrics.tracer.common.SpanContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.prometheus.PrometheusExemplarsAutoConfiguration.LazyTracingSpanContext;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PrometheusExemplarsAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass PrometheusExemplarsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(PrometheusExemplarsAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplySpanContext() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpanContext.class);\n\t\t\tassertThat(context).hasSingleBean(LazyTracingSpanContext.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomSpanContext() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class, CustomSpanContextConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SpanContext.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(LazyTracingSpanContext.class);\n\t\t\t\tassertThat(context).hasBean(\"customSpanContext\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySpanContextWhenTracerBeanIsMissing() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySpanContextWhenTracerClassIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Tracer.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySpanContextWhenSpanContextClassIsMissing() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(SpanContext.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySpanContextWhenIncludeIsNone() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Test\n\tvoid shouldFailWhenIncludeIsAll() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=all\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(InvalidConfigurationPropertyValueException.class)\n\t\t\t\t.hasMessageContaining(\n\t\t\t\t\t\t\"Property management.tracing.exemplars.include with value 'all' is invalid: Prometheus doesn't support including 'all' traces as exemplars.\"));\n\t}\n\n\t@Test\n\tvoid shouldSupplySpanContextWhenIncludeIsSampledTraces() {\n\t\tthis.contextRunner.withUserConfiguration(TracerConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=sampled-traces\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SpanContext.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class TracerConfiguration {\n\n\t\t@Bean\n\t\tTracer tracer() {\n\t\t\treturn mock(Tracer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomSpanContextConfiguration {\n\n\t\t@Bean\n\t\tSpanContext customSpanContext() {\n\t\t\treturn mock(SpanContext.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Tracing Brave\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-micrometer-observation\"))\n\tapi(project(\":module:spring-boot-micrometer-tracing\"))\n\tapi(\"io.micrometer:micrometer-tracing\") {\n\t\texclude(group: \"aopalliance\", module: \"aopalliance\")\n\t}\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-zipkin\"))\n\toptional(\"io.micrometer:micrometer-tracing-bridge-brave\")\n\toptional(\"io.zipkin.reporter2:zipkin-reporter-brave\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-metrics\"))\n\ttestImplementation(project(\":module:spring-boot-opentelemetry\"))\n\ttestImplementation(\"io.micrometer:micrometer-registry-prometheus\")\n\ttestImplementation(\"io.prometheus:prometheus-metrics-exposition-formats\")\n\ttestImplementation(\"io.micrometer:micrometer-registry-otlp\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/BraveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.List;\n\nimport brave.CurrentSpanCustomizer;\nimport brave.SpanCustomizer;\nimport brave.Tracer;\nimport brave.Tracing;\nimport brave.Tracing.Builder;\nimport brave.TracingCustomizer;\nimport brave.handler.SpanHandler;\nimport brave.propagation.CurrentTraceContext;\nimport brave.propagation.CurrentTraceContextCustomizer;\nimport brave.propagation.Propagation.Factory;\nimport brave.propagation.ThreadLocalCurrentTraceContext;\nimport brave.sampler.Sampler;\nimport io.micrometer.tracing.brave.bridge.BraveBaggageManager;\nimport io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;\nimport io.micrometer.tracing.brave.bridge.BravePropagator;\nimport io.micrometer.tracing.brave.bridge.BraveSpanCustomizer;\nimport io.micrometer.tracing.brave.bridge.BraveTracer;\nimport io.micrometer.tracing.brave.bridge.CompositeSpanHandler;\nimport io.micrometer.tracing.exporter.SpanExportingPredicate;\nimport io.micrometer.tracing.exporter.SpanFilter;\nimport io.micrometer.tracing.exporter.SpanReporter;\nimport io.micrometer.tracing.propagation.Propagator;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.IncompatibleConfigurationException;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.NoopTracerAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Propagation.PropagationType;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Brave.\n *\n * @author Moritz Halbritter\n * @author Marcin Grzejszczak\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@AutoConfiguration(before = { MicrometerTracingAutoConfiguration.class, NoopTracerAutoConfiguration.class })\n@ConditionalOnClass({ Tracer.class, BraveTracer.class })\n@EnableConfigurationProperties({ TracingProperties.class, BraveTracingProperties.class })\n@Import({ BravePropagationConfigurations.PropagationWithoutBaggage.class,\n\t\tBravePropagationConfigurations.PropagationWithBaggage.class,\n\t\tBravePropagationConfigurations.NoPropagation.class })\npublic final class BraveAutoConfiguration {\n\n\t/**\n\t * Default value for application name if {@code spring.application.name} is not set.\n\t */\n\tprivate static final String DEFAULT_APPLICATION_NAME = \"application\";\n\n\tprivate final TracingProperties tracingProperties;\n\n\tprivate final BraveTracingProperties braveTracingProperties;\n\n\tBraveAutoConfiguration(TracingProperties tracingProperties, BraveTracingProperties braveTracingProperties) {\n\t\tthis.tracingProperties = tracingProperties;\n\t\tthis.braveTracingProperties = braveTracingProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tCompositeSpanHandler compositeSpanHandler(ObjectProvider<SpanExportingPredicate> predicates,\n\t\t\tObjectProvider<SpanReporter> reporters, ObjectProvider<SpanFilter> filters) {\n\t\treturn new CompositeSpanHandler(predicates.orderedStream().toList(), reporters.orderedStream().toList(),\n\t\t\t\tfilters.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tTracing braveTracing(Environment environment, List<SpanHandler> spanHandlers,\n\t\t\tList<TracingCustomizer> tracingCustomizers, CurrentTraceContext currentTraceContext,\n\t\t\tFactory propagationFactory, Sampler sampler) {\n\t\tif (this.braveTracingProperties.isSpanJoiningSupported()) {\n\t\t\tif (this.tracingProperties.getPropagation().getType() != null\n\t\t\t\t\t&& this.tracingProperties.getPropagation().getType().contains(PropagationType.W3C)) {\n\t\t\t\tthrow new IncompatibleConfigurationException(\"management.tracing.propagation.type\",\n\t\t\t\t\t\t\"management.brave.tracing.span-joining-supported\");\n\t\t\t}\n\t\t\tif (this.tracingProperties.getPropagation().getType() == null\n\t\t\t\t\t&& this.tracingProperties.getPropagation().getProduce().contains(PropagationType.W3C)) {\n\t\t\t\tthrow new IncompatibleConfigurationException(\"management.tracing.propagation.produce\",\n\t\t\t\t\t\t\"management.brave.tracing.span-joining-supported\");\n\t\t\t}\n\t\t\tif (this.tracingProperties.getPropagation().getType() == null\n\t\t\t\t\t&& this.tracingProperties.getPropagation().getConsume().contains(PropagationType.W3C)) {\n\t\t\t\tthrow new IncompatibleConfigurationException(\"management.tracing.propagation.consume\",\n\t\t\t\t\t\t\"management.brave.tracing.span-joining-supported\");\n\t\t\t}\n\t\t}\n\t\tString applicationName = environment.getProperty(\"spring.application.name\", DEFAULT_APPLICATION_NAME);\n\t\tBuilder builder = Tracing.newBuilder()\n\t\t\t.currentTraceContext(currentTraceContext)\n\t\t\t.traceId128Bit(true)\n\t\t\t.supportsJoin(this.braveTracingProperties.isSpanJoiningSupported())\n\t\t\t.propagationFactory(propagationFactory)\n\t\t\t.sampler(sampler)\n\t\t\t.localServiceName(applicationName);\n\t\tspanHandlers.forEach(builder::addSpanHandler);\n\t\tfor (TracingCustomizer tracingCustomizer : tracingCustomizers) {\n\t\t\ttracingCustomizer.customize(builder);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tbrave.Tracer braveTracer(Tracing tracing) {\n\t\treturn tracing.tracer();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCurrentTraceContext braveCurrentTraceContext(List<CurrentTraceContext.ScopeDecorator> scopeDecorators,\n\t\t\tList<CurrentTraceContextCustomizer> currentTraceContextCustomizers) {\n\t\tThreadLocalCurrentTraceContext.Builder builder = ThreadLocalCurrentTraceContext.newBuilder();\n\t\tscopeDecorators.forEach(builder::addScopeDecorator);\n\t\tfor (CurrentTraceContextCustomizer currentTraceContextCustomizer : currentTraceContextCustomizers) {\n\t\t\tcurrentTraceContextCustomizer.customize(builder);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSampler braveSampler() {\n\t\treturn Sampler.create(this.tracingProperties.getSampling().getProbability());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)\n\tBraveTracer braveTracerBridge(brave.Tracer tracer, CurrentTraceContext currentTraceContext) {\n\t\treturn new BraveTracer(tracer, new BraveCurrentTraceContext(currentTraceContext),\n\t\t\t\tnew BraveBaggageManager(this.tracingProperties.getBaggage().getTagFields(),\n\t\t\t\t\t\tthis.tracingProperties.getBaggage().getRemoteFields()));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(Propagator.class)\n\tBravePropagator bravePropagator(Tracing tracing) {\n\t\treturn new BravePropagator(tracing);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(SpanCustomizer.class)\n\tCurrentSpanCustomizer currentSpanCustomizer(Tracing tracing) {\n\t\treturn CurrentSpanCustomizer.create(tracing);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(io.micrometer.tracing.SpanCustomizer.class)\n\tBraveSpanCustomizer braveSpanCustomizer(SpanCustomizer spanCustomizer) {\n\t\treturn new BraveSpanCustomizer(spanCustomizer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/BravePropagationConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.List;\n\nimport brave.baggage.BaggageField;\nimport brave.baggage.BaggagePropagation;\nimport brave.baggage.BaggagePropagation.FactoryBuilder;\nimport brave.baggage.BaggagePropagationConfig;\nimport brave.baggage.BaggagePropagationCustomizer;\nimport brave.baggage.CorrelationScopeConfig.SingleCorrelationField;\nimport brave.baggage.CorrelationScopeCustomizer;\nimport brave.baggage.CorrelationScopeDecorator;\nimport brave.context.slf4j.MDCScopeDecorator;\nimport brave.propagation.CurrentTraceContext.ScopeDecorator;\nimport brave.propagation.Propagation;\nimport brave.propagation.Propagation.Factory;\nimport io.micrometer.tracing.brave.bridge.BraveBaggageManager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Baggage.Correlation;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Brave propagation configurations. They are imported by {@link BraveAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass BravePropagationConfigurations {\n\n\t/**\n\t * Propagates traces but no baggage.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"management.tracing.baggage.enabled\", havingValue = false)\n\tstatic class PropagationWithoutBaggage {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(Factory.class)\n\t\t@ConditionalOnEnabledTracingExport\n\t\tCompositePropagationFactory propagationFactory(TracingProperties properties) {\n\t\t\treturn CompositePropagationFactory.create(properties.getPropagation());\n\t\t}\n\n\t}\n\n\t/**\n\t * Propagates traces and baggage.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"management.tracing.baggage.enabled\", matchIfMissing = true)\n\t@EnableConfigurationProperties(TracingProperties.class)\n\tstatic class PropagationWithBaggage {\n\n\t\tprivate final TracingProperties tracingProperties;\n\n\t\tPropagationWithBaggage(TracingProperties tracingProperties) {\n\t\t\tthis.tracingProperties = tracingProperties;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tBaggagePropagation.FactoryBuilder propagationFactoryBuilder(\n\t\t\t\tObjectProvider<BaggagePropagationCustomizer> baggagePropagationCustomizers) {\n\t\t\t// There's a chicken-and-egg problem here: to create a builder, we need a\n\t\t\t// factory. But the CompositePropagationFactory needs data from the builder.\n\t\t\t// We create a throw-away builder with a throw-away factory, and then copy the\n\t\t\t// config to the real builder.\n\t\t\tFactoryBuilder throwAwayBuilder = BaggagePropagation.newFactoryBuilder(createThrowAwayFactory());\n\t\t\tbaggagePropagationCustomizers.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(throwAwayBuilder));\n\t\t\tCompositePropagationFactory propagationFactory = CompositePropagationFactory.create(\n\t\t\t\t\tthis.tracingProperties.getPropagation(),\n\t\t\t\t\tnew BraveBaggageManager(this.tracingProperties.getBaggage().getTagFields(),\n\t\t\t\t\t\t\tthis.tracingProperties.getBaggage().getRemoteFields()),\n\t\t\t\t\tLocalBaggageFields.extractFrom(throwAwayBuilder));\n\t\t\tFactoryBuilder builder = BaggagePropagation.newFactoryBuilder(propagationFactory);\n\t\t\tthrowAwayBuilder.configs().forEach(builder::add);\n\t\t\treturn builder;\n\t\t}\n\n\t\tprivate Factory createThrowAwayFactory() {\n\t\t\treturn new Factory() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic @Nullable Propagation<String> get() {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tBaggagePropagationCustomizer remoteFieldsBaggagePropagationCustomizer() {\n\t\t\treturn (builder) -> {\n\t\t\t\tList<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();\n\t\t\t\tfor (String fieldName : remoteFields) {\n\t\t\t\t\tbuilder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(fieldName)));\n\t\t\t\t}\n\t\t\t\tList<String> localFields = this.tracingProperties.getBaggage().getLocalFields();\n\t\t\t\tfor (String localFieldName : localFields) {\n\t\t\t\t\tbuilder.add(BaggagePropagationConfig.SingleBaggageField.local(BaggageField.create(localFieldName)));\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnEnabledTracingExport\n\t\tFactory propagationFactory(BaggagePropagation.FactoryBuilder factoryBuilder) {\n\t\t\treturn factoryBuilder.build();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tCorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(\n\t\t\t\tObjectProvider<CorrelationScopeCustomizer> correlationScopeCustomizers) {\n\t\t\tCorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder();\n\t\t\tcorrelationScopeCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\t@ConditionalOnBooleanProperty(name = \"management.tracing.baggage.correlation.enabled\", matchIfMissing = true)\n\t\tCorrelationScopeCustomizer correlationFieldsCorrelationScopeCustomizer() {\n\t\t\treturn (builder) -> {\n\t\t\t\tCorrelation correlationProperties = this.tracingProperties.getBaggage().getCorrelation();\n\t\t\t\tfor (String field : correlationProperties.getFields()) {\n\t\t\t\t\tBaggageField baggageField = BaggageField.create(field);\n\t\t\t\t\tSingleCorrelationField correlationField = SingleCorrelationField.newBuilder(baggageField)\n\t\t\t\t\t\t.flushOnUpdate()\n\t\t\t\t\t\t.build();\n\t\t\t\t\tbuilder.add(correlationField);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(CorrelationScopeDecorator.class)\n\t\tScopeDecorator correlationScopeDecorator(CorrelationScopeDecorator.Builder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\t/**\n\t * Propagates neither traces nor baggage.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NoPropagation {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(Factory.class)\n\t\tCompositePropagationFactory noopPropagationFactory() {\n\t\t\treturn CompositePropagationFactory.noop();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/BraveTracingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for tracing with Brave.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.brave.tracing\")\npublic class BraveTracingProperties {\n\n\t/**\n\t * Whether the propagation type and tracing backend support sharing the span ID\n\t * between client and server spans. Requires B3 propagation and a compatible backend.\n\t */\n\tprivate boolean spanJoiningSupported;\n\n\tpublic boolean isSpanJoiningSupported() {\n\t\treturn this.spanJoiningSupported;\n\t}\n\n\tpublic void setSpanJoiningSupported(boolean spanJoiningSupported) {\n\t\tthis.spanJoiningSupported = spanJoiningSupported;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/CompositePropagationFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.stream.Stream;\n\nimport brave.propagation.B3Propagation;\nimport brave.propagation.Propagation;\nimport brave.propagation.Propagation.Factory;\nimport brave.propagation.TraceContext;\nimport brave.propagation.TraceContextOrSamplingFlags;\nimport io.micrometer.tracing.BaggageManager;\nimport io.micrometer.tracing.brave.bridge.W3CPropagation;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Propagation.PropagationType;\n\n/**\n * {@link brave.propagation.Propagation.Factory Propagation factory} which supports\n * multiple tracing formats. It is able to configure different formats for injecting and\n * for extracting.\n *\n * @author Marcin Grzejszczak\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass CompositePropagationFactory extends Propagation.Factory {\n\n\tprivate final PropagationFactories injectors;\n\n\tprivate final PropagationFactories extractors;\n\n\tprivate final CompositePropagation propagation;\n\n\tCompositePropagationFactory(Collection<Factory> injectorFactories, Collection<Factory> extractorFactories) {\n\t\tthis.injectors = new PropagationFactories(injectorFactories);\n\t\tthis.extractors = new PropagationFactories(extractorFactories);\n\t\tthis.propagation = new CompositePropagation(this.injectors, this.extractors);\n\t}\n\n\tStream<Factory> getInjectors() {\n\t\treturn this.injectors.stream();\n\t}\n\n\t@Override\n\tpublic boolean supportsJoin() {\n\t\treturn this.injectors.supportsJoin() && this.extractors.supportsJoin();\n\t}\n\n\t@Override\n\tpublic boolean requires128BitTraceId() {\n\t\treturn this.injectors.requires128BitTraceId() || this.extractors.requires128BitTraceId();\n\t}\n\n\t@Override\n\tpublic Propagation<String> get() {\n\t\treturn this.propagation;\n\t}\n\n\t@Override\n\tpublic TraceContext decorate(TraceContext context) {\n\t\tfor (Propagation.Factory factory : this.injectors.factories) {\n\t\t\tTraceContext decorated = factory.decorate(context);\n\t\t\tif (decorated != context) {\n\t\t\t\treturn decorated;\n\t\t\t}\n\t\t}\n\t\tfor (Propagation.Factory factory : this.extractors.factories) {\n\t\t\tTraceContext decorated = factory.decorate(context);\n\t\t\tif (decorated != context) {\n\t\t\t\treturn decorated;\n\t\t\t}\n\t\t}\n\t\treturn context;\n\t}\n\n\t/**\n\t * Creates a new {@link CompositePropagationFactory} which doesn't do any propagation.\n\t * @return the {@link CompositePropagationFactory}\n\t */\n\tstatic CompositePropagationFactory noop() {\n\t\treturn new CompositePropagationFactory(Collections.emptyList(), Collections.emptyList());\n\t}\n\n\t/**\n\t * Creates a new {@link CompositePropagationFactory}.\n\t * @param properties the propagation properties\n\t * @return the {@link CompositePropagationFactory}\n\t */\n\tstatic CompositePropagationFactory create(TracingProperties.Propagation properties) {\n\t\treturn create(properties, null, null);\n\t}\n\n\t/**\n\t * Creates a new {@link CompositePropagationFactory}.\n\t * @param properties the propagation properties\n\t * @param baggageManager the baggage manager to use, or {@code null}\n\t * @param localFields the local fields, or {@code null}\n\t * @return the {@link CompositePropagationFactory}\n\t */\n\tstatic CompositePropagationFactory create(TracingProperties.Propagation properties,\n\t\t\t@Nullable BaggageManager baggageManager, @Nullable LocalBaggageFields localFields) {\n\t\tPropagationFactoryMapper mapper = new PropagationFactoryMapper(baggageManager, localFields);\n\t\tList<Factory> injectors = getEffectiveProducedTypes(properties).stream().map(mapper::map).toList();\n\t\tList<Factory> extractors = getEffectiveConsumedTypes(properties).stream().map(mapper::map).toList();\n\t\treturn new CompositePropagationFactory(injectors, extractors);\n\t}\n\n\tprivate static List<PropagationType> getEffectiveConsumedTypes(TracingProperties.Propagation properties) {\n\t\treturn (properties.getType() != null) ? properties.getType() : properties.getConsume();\n\t}\n\n\tprivate static List<PropagationType> getEffectiveProducedTypes(TracingProperties.Propagation properties) {\n\t\treturn (properties.getType() != null) ? properties.getType() : properties.getProduce();\n\t}\n\n\t/**\n\t * Mapper used to create a {@link brave.propagation.Propagation.Factory Propagation\n\t * factory} from a {@link PropagationType}.\n\t */\n\tprivate static class PropagationFactoryMapper {\n\n\t\tprivate final @Nullable BaggageManager baggageManager;\n\n\t\tprivate final LocalBaggageFields localFields;\n\n\t\tPropagationFactoryMapper(@Nullable BaggageManager baggageManager, @Nullable LocalBaggageFields localFields) {\n\t\t\tthis.baggageManager = baggageManager;\n\t\t\tthis.localFields = (localFields != null) ? localFields : LocalBaggageFields.empty();\n\t\t}\n\n\t\tPropagation.Factory map(PropagationType type) {\n\t\t\treturn switch (type) {\n\t\t\t\tcase B3 -> b3Single();\n\t\t\t\tcase B3_MULTI -> b3Multi();\n\t\t\t\tcase W3C -> w3c();\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Creates a new B3 propagation factory using a single B3 header.\n\t\t * @return the B3 propagation factory\n\t\t */\n\t\tprivate Propagation.Factory b3Single() {\n\t\t\treturn B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE).build();\n\t\t}\n\n\t\t/**\n\t\t * Creates a new B3 propagation factory using multiple B3 headers.\n\t\t * @return the B3 propagation factory\n\t\t */\n\t\tprivate Propagation.Factory b3Multi() {\n\t\t\treturn B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.MULTI).build();\n\t\t}\n\n\t\t/**\n\t\t * Creates a new W3C propagation factory.\n\t\t * @return the W3C propagation factory\n\t\t */\n\t\tprivate Propagation.Factory w3c() {\n\t\t\tif (this.baggageManager == null) {\n\t\t\t\treturn new W3CPropagation();\n\t\t\t}\n\t\t\treturn new W3CPropagation(this.baggageManager, this.localFields.asList());\n\t\t}\n\n\t}\n\n\t/**\n\t * A collection of propagation factories.\n\t */\n\tprivate static class PropagationFactories {\n\n\t\tprivate final List<Propagation.Factory> factories;\n\n\t\tPropagationFactories(Collection<Factory> factories) {\n\t\t\tthis.factories = List.copyOf(factories);\n\t\t}\n\n\t\tboolean requires128BitTraceId() {\n\t\t\tfor (Propagation.Factory factory : this.factories) {\n\t\t\t\tif (factory.requires128BitTraceId()) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tboolean supportsJoin() {\n\t\t\tfor (Propagation.Factory factory : this.factories) {\n\t\t\t\tif (!factory.supportsJoin()) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tList<Propagation<String>> get() {\n\t\t\treturn stream().map(Factory::get).toList();\n\t\t}\n\n\t\tStream<Factory> stream() {\n\t\t\treturn this.factories.stream();\n\t\t}\n\n\t}\n\n\t/**\n\t * A composite {@link Propagation}.\n\t */\n\tprivate static class CompositePropagation implements Propagation<String> {\n\n\t\tprivate final List<Propagation<String>> injectors;\n\n\t\tprivate final List<Propagation<String>> extractors;\n\n\t\tprivate final List<String> keys;\n\n\t\tCompositePropagation(PropagationFactories injectorFactories, PropagationFactories extractorFactories) {\n\t\t\tthis.injectors = injectorFactories.get();\n\t\t\tthis.extractors = extractorFactories.get();\n\t\t\tthis.keys = Stream.concat(keys(this.injectors), keys(this.extractors)).distinct().toList();\n\t\t}\n\n\t\tprivate Stream<String> keys(List<Propagation<String>> propagations) {\n\t\t\treturn propagations.stream().flatMap((propagation) -> propagation.keys().stream());\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> keys() {\n\t\t\treturn this.keys;\n\t\t}\n\n\t\t@Override\n\t\tpublic <R> TraceContext.Injector<R> injector(Setter<R, String> setter) {\n\t\t\treturn (traceContext, request) -> {\n\t\t\t\tfor (Propagation<String> propagation : this.injectors) {\n\t\t\t\t\tpropagation.injector(setter).inject(traceContext, request);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Override\n\t\tpublic <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) {\n\t\t\treturn (request) -> {\n\t\t\t\tfor (Propagation<String> propagation : this.extractors) {\n\t\t\t\t\tTraceContextOrSamplingFlags extracted = propagation.extractor(getter).extract(request);\n\t\t\t\t\tif (!TraceContextOrSamplingFlags.EMPTY.equals(extracted)) {\n\t\t\t\t\t\treturn extracted;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn TraceContextOrSamplingFlags.EMPTY;\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/LocalBaggageFields.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport brave.baggage.BaggagePropagation;\nimport brave.baggage.BaggagePropagationConfig;\nimport brave.baggage.BaggagePropagationConfig.SingleBaggageField;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Local baggage fields.\n *\n * @author Moritz Halbritter\n */\nclass LocalBaggageFields {\n\n\tprivate final List<String> fields;\n\n\tLocalBaggageFields(List<String> fields) {\n\t\tAssert.notNull(fields, \"'fields' must not be null\");\n\t\tthis.fields = fields;\n\t}\n\n\t/**\n\t * Returns the local fields as a list.\n\t * @return the list\n\t */\n\tList<String> asList() {\n\t\treturn Collections.unmodifiableList(this.fields);\n\t}\n\n\t/**\n\t * Extracts the local fields from the given propagation factory builder.\n\t * @param builder the propagation factory builder to extract the local fields from\n\t * @return the local fields\n\t */\n\tstatic LocalBaggageFields extractFrom(BaggagePropagation.FactoryBuilder builder) {\n\t\tList<String> localFields = new ArrayList<>();\n\t\tfor (BaggagePropagationConfig config : builder.configs()) {\n\t\t\tif (config instanceof SingleBaggageField field) {\n\t\t\t\tif (CollectionUtils.isEmpty(field.keyNames())) {\n\t\t\t\t\tlocalFields.add(field.field().name());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new LocalBaggageFields(localFields);\n\t}\n\n\t/**\n\t * Creates empty local fields.\n\t * @return the empty local fields\n\t */\n\tstatic LocalBaggageFields empty() {\n\t\treturn new LocalBaggageFields(Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Micrometer Tracing with Brave.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/zipkin/ZipkinWithBraveTracingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure.zipkin;\n\nimport brave.Tag;\nimport brave.Tags;\nimport brave.handler.MutableSpan;\nimport zipkin2.reporter.BytesEncoder;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.brave.AsyncZipkinSpanHandler;\nimport zipkin2.reporter.brave.MutableSpanBytesEncoder;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Zipkin tracing with Brave.\n *\n * @author Moritz Halbritter\n * @author Stefan Bratanov\n * @author Wick Dynex\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = \"org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration\")\n@ConditionalOnClass({ Encoding.class, AsyncZipkinSpanHandler.class })\npublic final class ZipkinWithBraveTracingAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(Encoding.class)\n\t@ConditionalOnMissingBean(value = MutableSpan.class, parameterizedContainer = BytesEncoder.class)\n\tBytesEncoder<MutableSpan> mutableSpanBytesEncoder(Encoding encoding,\n\t\t\tObjectProvider<Tag<Throwable>> throwableTagProvider) {\n\t\tTag<Throwable> throwableTag = throwableTagProvider.getIfAvailable(() -> Tags.ERROR);\n\t\treturn MutableSpanBytesEncoder.create(encoding, throwableTag);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(BytesMessageSender.class)\n\t@ConditionalOnEnabledTracingExport(\"zipkin\")\n\tAsyncZipkinSpanHandler asyncZipkinSpanHandler(BytesMessageSender sender,\n\t\t\tBytesEncoder<MutableSpan> mutableSpanBytesEncoder) {\n\t\treturn AsyncZipkinSpanHandler.newBuilder(sender).build(mutableSpanBytesEncoder);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/zipkin/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for tracing with Zipkin.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure.zipkin;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.tracing.brave.span-joining-supported\",\n      \"deprecation\": {\n        \"replacement\": \"management.brave.tracing.span-joining-supported\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.export.zipkin.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"defaultValue\": true,\n      \"description\": \"Whether auto-configuration of tracing is enabled to export Zipkin traces.\"\n    },\n    {\n      \"name\": \"management.zipkin.tracing.export.enabled\",\n      \"deprecation\": {\n        \"replacement\": \"management.tracing.export.zipkin.enabled\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.micrometer.tracing.brave.autoconfigure.BraveAutoConfiguration\norg.springframework.boot.micrometer.tracing.brave.autoconfigure.zipkin.ZipkinWithBraveTracingAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/BraveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport brave.Span;\nimport brave.SpanCustomizer;\nimport brave.Tracer;\nimport brave.Tracing;\nimport brave.baggage.BaggagePropagation;\nimport brave.baggage.CorrelationScopeConfig.SingleCorrelationField;\nimport brave.handler.SpanHandler;\nimport brave.propagation.CurrentTraceContext;\nimport brave.propagation.CurrentTraceContext.ScopeDecorator;\nimport brave.propagation.Propagation;\nimport brave.propagation.Propagation.Factory;\nimport brave.propagation.TraceContext;\nimport brave.sampler.Sampler;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.Observation.Scope;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.tracing.brave.bridge.BraveBaggageManager;\nimport io.micrometer.tracing.brave.bridge.BravePropagator;\nimport io.micrometer.tracing.brave.bridge.BraveSpanCustomizer;\nimport io.micrometer.tracing.brave.bridge.BraveTracer;\nimport io.micrometer.tracing.brave.bridge.CompositeSpanHandler;\nimport io.micrometer.tracing.brave.bridge.W3CPropagation;\nimport io.micrometer.tracing.exporter.SpanExportingPredicate;\nimport io.micrometer.tracing.exporter.SpanFilter;\nimport io.micrometer.tracing.exporter.SpanReporter;\nimport io.micrometer.tracing.propagation.Propagator;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.IncompatibleConfigurationException;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.brave.autoconfigure.BraveAutoConfigurationTests.SpanHandlerConfiguration.AdditionalSpanHandler;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link BraveAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Jonatan Ivanov\n */\nclass BraveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BraveAutoConfiguration.class);\n\t\t\tassertThat(context).hasSingleBean(Tracing.class);\n\t\t\tassertThat(context).hasSingleBean(Tracer.class);\n\t\t\tassertThat(context).hasSingleBean(CurrentTraceContext.class);\n\t\t\tassertThat(context).hasSingleBean(Factory.class);\n\t\t\tassertThat(context).hasSingleBean(Sampler.class);\n\t\t\tassertThat(context).hasSingleBean(BraveTracer.class);\n\t\t\tassertThat(context).hasSingleBean(Propagation.Factory.class);\n\t\t\tassertThat(context).hasSingleBean(BaggagePropagation.FactoryBuilder.class);\n\t\t\tassertThat(context).hasSingleBean(BraveTracer.class);\n\t\t\tassertThat(context).hasSingleBean(CompositeSpanHandler.class);\n\t\t\tassertThat(context).hasSingleBean(SpanCustomizer.class);\n\t\t\tassertThat(context).hasSingleBean(BraveSpanCustomizer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customTracing\");\n\t\t\tassertThat(context).hasSingleBean(Tracing.class);\n\t\t\tassertThat(context).hasBean(\"customTracer\");\n\t\t\tassertThat(context).hasSingleBean(Tracer.class);\n\t\t\tassertThat(context).hasBean(\"customCurrentTraceContext\");\n\t\t\tassertThat(context).hasSingleBean(CurrentTraceContext.class);\n\t\t\tassertThat(context).hasBean(\"customFactory\");\n\t\t\tassertThat(context).hasSingleBean(Factory.class);\n\t\t\tassertThat(context).hasBean(\"customSampler\");\n\t\t\tassertThat(context).hasSingleBean(Sampler.class);\n\t\t\tassertThat(context).hasBean(\"customMicrometerTracer\");\n\t\t\tassertThat(context).hasSingleBean(io.micrometer.tracing.Tracer.class);\n\t\t\tassertThat(context).hasBean(\"customBraveBaggageManager\");\n\t\t\tassertThat(context).hasSingleBean(BraveBaggageManager.class);\n\t\t\tassertThat(context).hasBean(\"customCompositeSpanHandler\");\n\t\t\tassertThat(context).hasSingleBean(CompositeSpanHandler.class);\n\t\t\tassertThat(context).hasBean(\"customSpanCustomizer\");\n\t\t\tassertThat(context).hasSingleBean(SpanCustomizer.class);\n\t\t\tassertThat(context).hasBean(\"customMicrometerSpanCustomizer\");\n\t\t\tassertThat(context).hasSingleBean(io.micrometer.tracing.SpanCustomizer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyMicrometerBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(BraveTracer.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBravePropagatorWhenPropagatorBeanIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(PropagatorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Propagator.class);\n\t\t\tassertThat(context).hasBean(\"customPropagator\");\n\t\t\tassertThat(context).doesNotHaveBean(BravePropagator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfBraveIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"brave\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BraveAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfMicrometerIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BraveAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyW3CPropagationFactoryByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasBean(\"propagationFactory\");\n\t\t\tFactory factory = context.getBean(Factory.class);\n\t\t\tStream<Class<?>> injectors = getInjectors(factory).stream().map(Object::getClass);\n\t\t\tassertThat(injectors).containsExactly(W3CPropagation.class);\n\t\t\tassertThat(context).hasSingleBean(BaggagePropagation.FactoryBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyB3PropagationFactoryViaProperty() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.propagation.type=B3\").run((context) -> {\n\t\t\tassertThat(context).hasBean(\"propagationFactory\");\n\t\t\tFactory factory = context.getBean(Factory.class);\n\t\t\tList<Factory> injectors = getInjectors(factory);\n\t\t\tassertThat(injectors).extracting(Factory::toString).containsExactly(\"B3Propagation\");\n\t\t\tassertThat(context).hasSingleBean(BaggagePropagation.FactoryBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseB3SingleWithParentWhenPropagationTypeIsB3() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3\", \"management.tracing.sampling.probability=1.0\")\n\t\t\t.run((context) -> {\n\t\t\t\tPropagation<String> propagation = context.getBean(Factory.class).get();\n\t\t\t\tTracer tracer = context.getBean(Tracing.class).tracer();\n\t\t\t\tSpan child;\n\t\t\t\tSpan parent = tracer.nextSpan().name(\"parent\");\n\t\t\t\ttry (Tracer.SpanInScope ignored = tracer.withSpanInScope(parent.start())) {\n\t\t\t\t\tchild = tracer.nextSpan().name(\"child\");\n\t\t\t\t\tchild.start().finish();\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tparent.finish();\n\t\t\t\t}\n\n\t\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\t\tTraceContext childContext = child.context();\n\t\t\t\tpropagation.injector(this::injectToMap).inject(childContext, map);\n\t\t\t\tassertThat(map).containsExactly(Map.entry(\"b3\", \"%s-%s-1-%s\".formatted(childContext.traceIdString(),\n\t\t\t\t\t\tchildContext.spanIdString(), childContext.parentIdString())));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyCorrelationScopeDecoratorIfBaggageDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"correlationScopeDecorator\"));\n\t}\n\n\t@Test\n\tvoid shouldSupplyW3CWithoutBaggageByDefaultIfBaggageDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).hasBean(\"propagationFactory\");\n\t\t\tFactory factory = context.getBean(Factory.class);\n\t\t\tStream<Class<?>> injectors = getInjectors(factory).stream().map(Object::getClass);\n\t\t\tassertThat(injectors).containsExactly(W3CPropagation.class);\n\t\t\tassertThat(context).doesNotHaveBean(BaggagePropagation.FactoryBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyB3WithoutBaggageIfBaggageDisabledAndB3Picked() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.baggage.enabled=false\", \"management.tracing.propagation.type=B3\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"propagationFactory\");\n\t\t\t\tFactory factory = context.getBean(Factory.class);\n\t\t\t\tList<Factory> injectors = getInjectors(factory);\n\t\t\t\tassertThat(injectors).extracting(Factory::toString).containsExactly(\"B3Propagation\");\n\t\t\t\tassertThat(context).doesNotHaveBean(BaggagePropagation.FactoryBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotApplyCorrelationFieldsIfBaggageCorrelationDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.baggage.correlation.enabled=false\",\n\t\t\t\t\t\"management.tracing.baggage.correlation.fields=alpha,bravo\")\n\t\t\t.run((context) -> {\n\t\t\t\tScopeDecorator scopeDecorator = context.getBean(ScopeDecorator.class);\n\t\t\t\tassertThat(scopeDecorator)\n\t\t\t\t\t.extracting(\"fields\", InstanceOfAssertFactories.array(SingleCorrelationField[].class))\n\t\t\t\t\t.hasSize(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldApplyCorrelationFieldsIfBaggageCorrelationEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.baggage.correlation.enabled=true\",\n\t\t\t\t\t\"management.tracing.baggage.correlation.fields=alpha,bravo\")\n\t\t\t.run((context) -> {\n\t\t\t\tScopeDecorator scopeDecorator = context.getBean(ScopeDecorator.class);\n\t\t\t\tassertThat(scopeDecorator)\n\t\t\t\t\t.extracting(\"fields\", InstanceOfAssertFactories.array(SingleCorrelationField[].class))\n\t\t\t\t\t.hasSize(4);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyMdcCorrelationScopeDecoratorIfBaggageCorrelationDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.correlation.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"mdcCorrelationScopeDecoratorBuilder\"));\n\t}\n\n\t@Test\n\tvoid shouldHave128BitTraceId() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTracing tracing = context.getBean(Tracing.class);\n\t\t\tSpan span = tracing.tracer().nextSpan();\n\t\t\tassertThat(span.context().traceIdString()).hasSize(32);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupportJoinedSpansByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTracing tracing = context.getBean(Tracing.class);\n\t\t\tSpan parentSpan = tracing.tracer().nextSpan();\n\t\t\tSpan childSpan = tracing.tracer().joinSpan(parentSpan.context());\n\t\t\tassertThat(childSpan.context().traceIdString()).isEqualTo(parentSpan.context().traceIdString());\n\t\t\tassertThat(childSpan.context().spanIdString()).isNotEqualTo(parentSpan.context().spanIdString());\n\t\t\tassertThat(childSpan.context().parentIdString()).isEqualTo(parentSpan.context().spanIdString());\n\t\t\tassertThat(parentSpan.context().parentIdString()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupportJoinedSpansIfB3UsedAndBackendSupportsIt() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3\",\n\t\t\t\t\t\"management.brave.tracing.span-joining-supported=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tTracing tracing = context.getBean(Tracing.class);\n\t\t\t\tSpan parentSpan = tracing.tracer().nextSpan();\n\t\t\t\tSpan childSpan = tracing.tracer().joinSpan(parentSpan.context());\n\t\t\t\tassertThat(childSpan.context().traceIdString()).isEqualTo(parentSpan.context().traceIdString());\n\t\t\t\tassertThat(childSpan.context().spanIdString()).isEqualTo(parentSpan.context().spanIdString());\n\t\t\t\tassertThat(childSpan.context().parentIdString()).isNull();\n\t\t\t\tassertThat(parentSpan.context().parentIdString()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailIfSupportJoinedSpansIsEnabledAndW3cIsChosenAsType() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.propagation.type=W3C\",\n\t\t\t\t\t\"management.brave.tracing.span-joining-supported=true\")\n\t\t\t.run((context) -> assertThatException().isThrownBy(() -> context.getBean(Tracing.class))\n\t\t\t\t.havingRootCause()\n\t\t\t\t.isExactlyInstanceOf(IncompatibleConfigurationException.class)\n\t\t\t\t.withMessage(\"The following configuration properties have incompatible values: \"\n\t\t\t\t\t\t+ \"[management.tracing.propagation.type, management.brave.tracing.span-joining-supported]\"));\n\t}\n\n\t@Test\n\tvoid shouldFailIfSupportJoinedSpansIsEnabledAndW3cIsChosenAsConsume() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.propagation.produce=B3\",\n\t\t\t\t\"management.tracing.propagation.consume=W3C\", \"management.brave.tracing.span-joining-supported=true\")\n\t\t\t.run((context) -> assertThatException().isThrownBy(() -> context.getBean(Tracing.class))\n\t\t\t\t.havingRootCause()\n\t\t\t\t.isExactlyInstanceOf(IncompatibleConfigurationException.class)\n\t\t\t\t.withMessage(\"The following configuration properties have incompatible values: \"\n\t\t\t\t\t\t+ \"[management.tracing.propagation.consume, management.brave.tracing.span-joining-supported]\"));\n\t}\n\n\t@Test\n\tvoid shouldFailIfSupportJoinedSpansIsEnabledAndW3cIsChosenAsProduce() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.propagation.consume=B3\",\n\t\t\t\t\"management.tracing.propagation.produce=W3C\", \"management.brave.tracing.span-joining-supported=true\")\n\t\t\t.run((context) -> assertThatException().isThrownBy(() -> context.getBean(Tracing.class))\n\t\t\t\t.havingRootCause()\n\t\t\t\t.isExactlyInstanceOf(IncompatibleConfigurationException.class)\n\t\t\t\t.withMessage(\"The following configuration properties have incompatible values: \"\n\t\t\t\t\t\t+ \"[management.tracing.propagation.produce, management.brave.tracing.span-joining-supported]\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid compositeSpanHandlerShouldBeFirstSpanHandler() {\n\t\tthis.contextRunner.withUserConfiguration(SpanHandlerConfiguration.class).run((context) -> {\n\t\t\tTracing tracing = context.getBean(Tracing.class);\n\t\t\tassertThat(tracing).extracting(\"tracer.spanHandler.delegate.handlers\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.array(SpanHandler[].class))\n\t\t\t\t.extracting((handler) -> (Class) handler.getClass())\n\t\t\t\t.containsExactly(CompositeSpanHandler.class, AdditionalSpanHandler.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid compositeSpanHandlerUsesFilterPredicateAndReportersInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(CompositeSpanHandlerComponentsConfiguration.class).run((context) -> {\n\t\t\tCompositeSpanHandlerComponentsConfiguration components = context\n\t\t\t\t.getBean(CompositeSpanHandlerComponentsConfiguration.class);\n\t\t\tCompositeSpanHandler composite = context.getBean(CompositeSpanHandler.class);\n\t\t\tassertThat(composite).extracting(\"spanFilters\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.containsExactly(components.filter1, components.filter2);\n\t\t\tassertThat(composite).extracting(\"filters\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.containsExactly(components.predicate2, components.predicate1);\n\t\t\tassertThat(composite).extracting(\"reporters\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.containsExactly(components.reporter1, components.reporter3, components.reporter2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldDisablePropagationIfTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Factory.class);\n\t\t\tFactory factory = context.getBean(Factory.class);\n\t\t\tPropagation<String> propagation = factory.get();\n\t\t\tassertThat(propagation.keys()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureTaggedFields() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.tag-fields=t1\").run((context) -> {\n\t\t\tBraveTracer braveTracer = context.getBean(BraveTracer.class);\n\t\t\tassertThat(braveTracer).extracting(\"braveBaggageManager.tagFields\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(String.class))\n\t\t\t\t.containsExactly(\"t1\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid keysAreSetInBaggage() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(ObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.tracing.baggage.remote-fields=f1,f2\")\n\t\t\t.run((context) -> {\n\t\t\t\tBraveTracer braveTracer = context.getBean(BraveTracer.class);\n\t\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\t\tObservation observation = Observation.start(\"o1\", observationRegistry)\n\t\t\t\t\t.lowCardinalityKeyValue(\"f1\", \"v1\")\n\t\t\t\t\t.highCardinalityKeyValue(\"f2\", \"v2\");\n\t\t\t\tMap<String, String> baggage = braveTracer.getAllBaggage();\n\t\t\t\tassertThat(baggage).isEmpty();\n\t\t\t\ttry (Scope ignore = observation.openScope()) {\n\t\t\t\t\tbaggage = braveTracer.getAllBaggage();\n\t\t\t\t\tassertThat(baggage).containsAllEntriesOf(Map.of(\"f1\", \"v1\", \"f2\", \"v2\"));\n\t\t\t\t}\n\t\t\t\tbaggage = braveTracer.getAllBaggage();\n\t\t\t\tassertThat(baggage).isEmpty();\n\t\t\t});\n\t}\n\n\tprivate void injectToMap(Map<String, String> map, String key, String value) {\n\t\tmap.put(key, value);\n\t}\n\n\tprivate List<Factory> getInjectors(Factory factory) {\n\t\tassertThat(factory).as(\"factory\").isNotNull();\n\t\tif (factory instanceof CompositePropagationFactory compositePropagationFactory) {\n\t\t\treturn compositePropagationFactory.getInjectors().toList();\n\t\t}\n\t\tfail(\"Expected CompositePropagationFactory, found %s\".formatted(factory.getClass()));\n\t\tthrow new AssertionError(\"Unreachable\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CompositeSpanHandlerComponentsConfiguration {\n\n\t\tprivate final SpanFilter filter1 = mock(SpanFilter.class);\n\n\t\tprivate final SpanFilter filter2 = mock(SpanFilter.class);\n\n\t\tprivate final SpanExportingPredicate predicate1 = mock(SpanExportingPredicate.class);\n\n\t\tprivate final SpanExportingPredicate predicate2 = mock(SpanExportingPredicate.class);\n\n\t\tprivate final SpanReporter reporter1 = mock(SpanReporter.class);\n\n\t\tprivate final SpanReporter reporter2 = mock(SpanReporter.class);\n\n\t\tprivate final SpanReporter reporter3 = mock(SpanReporter.class);\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSpanFilter filter1() {\n\t\t\treturn this.filter1;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tSpanFilter filter2() {\n\t\t\treturn this.filter2;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tSpanExportingPredicate predicate1() {\n\t\t\treturn this.predicate1;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSpanExportingPredicate predicate2() {\n\t\t\treturn this.predicate2;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSpanReporter reporter1() {\n\t\t\treturn this.reporter1;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(3)\n\t\tSpanReporter reporter2() {\n\t\t\treturn this.reporter2;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tSpanReporter reporter3() {\n\t\t\treturn this.reporter3;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SpanHandlerConfiguration {\n\n\t\t@Bean\n\t\tSpanHandler additionalSpanHandler() {\n\t\t\treturn new AdditionalSpanHandler();\n\t\t}\n\n\t\tstatic class AdditionalSpanHandler extends SpanHandler {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\t@Bean\n\t\tTracing customTracing() {\n\t\t\treturn mock(Tracing.class);\n\t\t}\n\n\t\t@Bean\n\t\tTracer customTracer() {\n\t\t\treturn mock(Tracer.class);\n\t\t}\n\n\t\t@Bean\n\t\tCurrentTraceContext customCurrentTraceContext() {\n\t\t\treturn mock(CurrentTraceContext.class);\n\t\t}\n\n\t\t@Bean\n\t\tFactory customFactory() {\n\t\t\treturn mock(Factory.class);\n\t\t}\n\n\t\t@Bean\n\t\tSampler customSampler() {\n\t\t\treturn mock(Sampler.class);\n\t\t}\n\n\t\t@Bean\n\t\tio.micrometer.tracing.Tracer customMicrometerTracer() {\n\t\t\treturn mock(io.micrometer.tracing.Tracer.class);\n\t\t}\n\n\t\t@Bean\n\t\tBraveBaggageManager customBraveBaggageManager() {\n\t\t\treturn mock(BraveBaggageManager.class);\n\t\t}\n\n\t\t@Bean\n\t\tCompositeSpanHandler customCompositeSpanHandler() {\n\t\t\treturn new CompositeSpanHandler(Collections.emptyList(), Collections.emptyList(), Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tSpanCustomizer customSpanCustomizer() {\n\t\t\treturn mock(SpanCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\tio.micrometer.tracing.SpanCustomizer customMicrometerSpanCustomizer() {\n\t\t\treturn mock(io.micrometer.tracing.SpanCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PropagatorConfiguration {\n\n\t\t@Bean\n\t\tPropagator customPropagator() {\n\t\t\treturn mock(Propagator.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/BraveBaggagePropagationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.function.Supplier;\n\nimport io.micrometer.tracing.BaggageInScope;\nimport io.micrometer.tracing.BaggageManager;\nimport io.micrometer.tracing.Span;\nimport io.micrometer.tracing.Tracer;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport org.slf4j.MDC;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for Baggage propagation with Brave using W3C and B3 propagation formats.\n *\n * @author Marcin Grzejszczak\n * @author Moritz Halbritter\n */\n@ForkedClassPath\nclass BraveBaggagePropagationIntegrationTests {\n\n\tprivate static final String COUNTRY_CODE = \"country-code\";\n\n\tprivate static final String BUSINESS_PROCESS = \"bp\";\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid setup() {\n\t\tMDC.clear();\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid shouldSetEntriesToMdcFromSpanWithBaggage(AutoConfig autoConfig) {\n\t\tautoConfig.get().run((context) -> {\n\t\t\tTracer tracer = tracer(context);\n\t\t\tSpan span = createSpan(tracer);\n\t\t\tBaggageManager baggageManager = baggageManager(context);\n\t\t\ttry (Tracer.SpanInScope scope = tracer.withSpan(span.start())) {\n\t\t\t\tassertMdcValue(\"traceId\", span.context().traceId());\n\t\t\t\ttry (BaggageInScope fo = baggageManager.createBaggageInScope(span.context(), COUNTRY_CODE, \"FO\");\n\t\t\t\t\t\tBaggageInScope alm = baggageManager.createBaggageInScope(span.context(), BUSINESS_PROCESS,\n\t\t\t\t\t\t\t\t\"ALM\")) {\n\t\t\t\t\tassertMdcValue(COUNTRY_CODE, \"FO\");\n\t\t\t\t\tassertMdcValue(BUSINESS_PROCESS, \"ALM\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t\tassertThatMdcContainsUnsetTraceId();\n\t\t\tassertUnsetMdc(COUNTRY_CODE);\n\t\t\tassertUnsetMdc(BUSINESS_PROCESS);\n\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid shouldRemoveEntriesFromMdcForNullSpan(AutoConfig autoConfig) {\n\t\tautoConfig.get().run((context) -> {\n\t\t\tTracer tracer = tracer(context);\n\t\t\tSpan span = createSpan(tracer);\n\t\t\tBaggageManager baggageManager = baggageManager(context);\n\t\t\ttry (Tracer.SpanInScope scope = tracer.withSpan(span.start())) {\n\t\t\t\tassertMdcValue(\"traceId\", span.context().traceId());\n\t\t\t\ttry (BaggageInScope fo = baggageManager.createBaggageInScope(span.context(), COUNTRY_CODE, \"FO\")) {\n\t\t\t\t\tassertMdcValue(COUNTRY_CODE, \"FO\");\n\t\t\t\t\ttry (Tracer.SpanInScope scope2 = tracer.withSpan(null)) {\n\t\t\t\t\t\tassertThatMdcContainsUnsetTraceId();\n\t\t\t\t\t\tassertUnsetMdc(COUNTRY_CODE);\n\t\t\t\t\t}\n\t\t\t\t\tassertMdcValue(\"traceId\", span.context().traceId());\n\t\t\t\t\tassertMdcValue(COUNTRY_CODE, \"FO\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t\tassertThatMdcContainsUnsetTraceId();\n\t\t\tassertUnsetMdc(COUNTRY_CODE);\n\t\t});\n\t}\n\n\tprivate Span createSpan(Tracer tracer) {\n\t\treturn tracer.nextSpan().name(\"span\");\n\t}\n\n\tprivate Tracer tracer(ApplicationContext context) {\n\t\treturn context.getBean(Tracer.class);\n\t}\n\n\tprivate BaggageManager baggageManager(ApplicationContext context) {\n\t\treturn context.getBean(BaggageManager.class);\n\t}\n\n\tprivate void assertThatMdcContainsUnsetTraceId() {\n\t\tassertThat(MDC.get(\"traceId\")).isNull();\n\t}\n\n\tprivate void assertUnsetMdc(String key) {\n\t\tassertThat(MDC.get(key)).as(\"MDC[%s]\", key).isNull();\n\t}\n\n\tprivate void assertMdcValue(String key, String expected) {\n\t\tassertThat(MDC.get(key)).as(\"MDC[%s]\", key).isEqualTo(expected);\n\t}\n\n\tenum AutoConfig implements Supplier<ApplicationContextRunner> {\n\n\t\tBRAVE_DEFAULT {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner()\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tBRAVE_W3C {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner()\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.propagation.type=W3C\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tBRAVE_B3 {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner()\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tBRAVE_B3_MULTI {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner()\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3_MULTI\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tBRAVE_LOCAL_FIELDS {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner()\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(BraveAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.baggage.local-fields=country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/CompositePropagationFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport brave.propagation.Propagation;\nimport brave.propagation.TraceContext;\nimport brave.propagation.TraceContextOrSamplingFlags;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link CompositePropagationFactory}.\n *\n * @author Moritz Halbritter\n */\nclass CompositePropagationFactoryTests {\n\n\t@Test\n\tvoid supportsJoin() {\n\t\tPropagation.Factory supported = Mockito.mock(Propagation.Factory.class);\n\t\tgiven(supported.supportsJoin()).willReturn(true);\n\t\tgiven(supported.get()).willReturn(new DummyPropagation(\"a\"));\n\t\tPropagation.Factory unsupported = Mockito.mock(Propagation.Factory.class);\n\t\tgiven(unsupported.supportsJoin()).willReturn(false);\n\t\tgiven(unsupported.get()).willReturn(new DummyPropagation(\"a\"));\n\t\tCompositePropagationFactory factory = new CompositePropagationFactory(List.of(supported), List.of(unsupported));\n\t\tassertThat(factory.supportsJoin()).isFalse();\n\t}\n\n\t@Test\n\tvoid requires128BitTraceId() {\n\t\tPropagation.Factory required = Mockito.mock(Propagation.Factory.class);\n\t\tgiven(required.requires128BitTraceId()).willReturn(true);\n\t\tgiven(required.get()).willReturn(new DummyPropagation(\"a\"));\n\t\tPropagation.Factory notRequired = Mockito.mock(Propagation.Factory.class);\n\t\tgiven(notRequired.requires128BitTraceId()).willReturn(false);\n\t\tgiven(notRequired.get()).willReturn(new DummyPropagation(\"a\"));\n\t\tCompositePropagationFactory factory = new CompositePropagationFactory(List.of(required), List.of(notRequired));\n\t\tassertThat(factory.requires128BitTraceId()).isTrue();\n\t}\n\n\t@Nested\n\tclass CompositePropagationTests {\n\n\t\t@Test\n\t\tvoid keys() {\n\t\t\tCompositePropagationFactory factory = new CompositePropagationFactory(List.of(field(\"a\")),\n\t\t\t\t\tList.of(field(\"b\")));\n\t\t\tPropagation<String> propagation = factory.get();\n\t\t\tassertThat(propagation.keys()).containsExactly(\"a\", \"b\");\n\t\t}\n\n\t\t@Test\n\t\tvoid inject() {\n\t\t\tCompositePropagationFactory factory = new CompositePropagationFactory(List.of(field(\"a\"), field(\"b\")),\n\t\t\t\t\tList.of(field(\"c\")));\n\t\t\tPropagation<String> propagation = factory.get();\n\t\t\tTraceContext context = context();\n\t\t\tMap<String, String> request = new HashMap<>();\n\t\t\tpropagation.injector(new MapSetter()).inject(context, request);\n\t\t\tassertThat(request).containsOnly(entry(\"a\", \"a-value\"), entry(\"b\", \"b-value\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid extractorWhenDelegateExtractsReturnsExtraction() {\n\t\t\tCompositePropagationFactory factory = new CompositePropagationFactory(Collections.emptyList(),\n\t\t\t\t\tList.of(field(\"a\"), field(\"b\")));\n\t\t\tPropagation<String> propagation = factory.get();\n\t\t\tMap<String, String> request = Map.of(\"a\", \"a-value\", \"b\", \"b-value\");\n\t\t\tTraceContextOrSamplingFlags context = propagation.extractor(new MapGetter()).extract(request);\n\t\t\tTraceContext traceContext = context.context();\n\t\t\tassertThat(traceContext).isNotNull();\n\t\t\tassertThat(traceContext.extra()).containsExactly(\"a\");\n\t\t}\n\n\t\t@Test\n\t\tvoid extractorWhenWhenNoExtractorMatchesReturnsEmptyContext() {\n\t\t\tCompositePropagationFactory factory = new CompositePropagationFactory(Collections.emptyList(),\n\t\t\t\t\tCollections.emptyList());\n\t\t\tPropagation<String> propagation = factory.get();\n\t\t\tMap<String, String> request = Collections.emptyMap();\n\t\t\tTraceContextOrSamplingFlags context = propagation.extractor(new MapGetter()).extract(request);\n\t\t\tassertThat(context.context()).isNull();\n\t\t}\n\n\t\tprivate static TraceContext context() {\n\t\t\treturn TraceContext.newBuilder().traceId(1).spanId(2).build();\n\t\t}\n\n\t\tprivate static DummyPropagation field(String field) {\n\t\t\treturn new DummyPropagation(field);\n\t\t}\n\n\t}\n\n\tprivate static final class MapSetter implements Propagation.Setter<Map<String, String>, String> {\n\n\t\t@Override\n\t\tpublic void put(Map<String, String> request, String key, String value) {\n\t\t\trequest.put(key, value);\n\t\t}\n\n\t}\n\n\tprivate static final class MapGetter implements Propagation.Getter<Map<String, String>, String> {\n\n\t\t@Override\n\t\tpublic @Nullable String get(Map<String, String> request, String key) {\n\t\t\treturn request.get(key);\n\t\t}\n\n\t}\n\n\tprivate static final class DummyPropagation extends Propagation.Factory implements Propagation<String> {\n\n\t\tprivate final String field;\n\n\t\tprivate DummyPropagation(String field) {\n\t\t\tthis.field = field;\n\t\t}\n\n\t\t@Override\n\t\tpublic Propagation<String> get() {\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> keys() {\n\t\t\treturn List.of(this.field);\n\t\t}\n\n\t\t@Override\n\t\tpublic <R> TraceContext.Injector<R> injector(Propagation.Setter<R, String> setter) {\n\t\t\treturn (traceContext, request) -> setter.put(request, this.field, this.field + \"-value\");\n\t\t}\n\n\t\t@Override\n\t\tpublic <R> TraceContext.Extractor<R> extractor(Propagation.Getter<R, String> getter) {\n\t\t\treturn (request) -> {\n\t\t\t\tTraceContext context = TraceContext.newBuilder().traceId(1).spanId(2).addExtra(this.field).build();\n\t\t\t\treturn TraceContextOrSamplingFlags.create(context);\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/LocalBaggageFieldsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport brave.baggage.BaggageField;\nimport brave.baggage.BaggagePropagation;\nimport brave.baggage.BaggagePropagation.FactoryBuilder;\nimport brave.baggage.BaggagePropagationConfig;\nimport brave.propagation.Propagation;\nimport brave.propagation.Propagation.Factory;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link LocalBaggageFields}.\n *\n * @author Moritz Halbritter\n */\nclass LocalBaggageFieldsTests {\n\n\t@Test\n\tvoid extractFromBuilder() {\n\t\tFactoryBuilder builder = createBuilder();\n\t\tbuilder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(\"remote-field-1\")));\n\t\tbuilder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(\"remote-field-2\")));\n\t\tbuilder.add(BaggagePropagationConfig.SingleBaggageField.local(BaggageField.create(\"local-field-1\")));\n\t\tbuilder.add(BaggagePropagationConfig.SingleBaggageField.local(BaggageField.create(\"local-field-2\")));\n\t\tLocalBaggageFields fields = LocalBaggageFields.extractFrom(builder);\n\t\tassertThat(fields.asList()).containsExactlyInAnyOrder(\"local-field-1\", \"local-field-2\");\n\t}\n\n\t@Test\n\tvoid empty() {\n\t\tassertThat(LocalBaggageFields.empty().asList()).isEmpty();\n\t}\n\n\tprivate static FactoryBuilder createBuilder() {\n\t\treturn BaggagePropagation.newFactoryBuilder(new Factory() {\n\t\t\t@Override\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tpublic Propagation<String> get() {\n\t\t\t\treturn mock(Propagation.class);\n\t\t\t}\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/OtlpExemplarsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.registry.otlp.ExemplarContextProvider;\nimport io.micrometer.registry.otlp.OtlpMeterRegistry;\nimport io.micrometer.registry.otlp.OtlpMetricsSender;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsExportAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.otlp.OtlpExemplarsAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OtlpExemplarsAutoConfiguration}.\n *\n * @author Jonatan Ivanov\n */\nclass OtlpExemplarsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"management.tracing.sampling.probability=1.0\",\n\t\t\t\t\"management.metrics.distribution.percentiles-histogram.all=true\",\n\t\t\t\t\"management.metrics.use-global-registry=false\")\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, OtlpMetricsExportAutoConfiguration.class,\n\t\t\t\t\t\tOtlpExemplarsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\t\tBraveAutoConfiguration.class, MicrometerTracingAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfOtlpSupportIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer.registry.otlp\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfMicrometerTracingIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer.tracing\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ExemplarContextProvider.class)\n\t\t\t\t.getBean(ExemplarContextProvider.class)\n\t\t\t\t.isSameAs(CustomConfiguration.CONTEXT_PROVIDER));\n\t}\n\n\t@Test\n\tvoid otlpOutputShouldContainExemplars() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ExemplarContextProvider.class);\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation.start(\"test.observation\", observationRegistry).stop();\n\t\t\tOtlpMeterRegistry otlpMeterRegistry = context.getBean(OtlpMeterRegistry.class);\n\t\t\tTestOtlpMetricsSender metricsSender = context.getBean(TestOtlpMetricsSender.class);\n\t\t\totlpMeterRegistry.close();\n\t\t\tassertThat(metricsSender.getOtlpRequest()).containsOnlyOnce(\"name: \\\"test.observation\\\"\")\n\t\t\t\t.containsOnlyOnce(\"exemplars\")\n\t\t\t\t.containsOnlyOnce(\"span_id\")\n\t\t\t\t.containsOnlyOnce(\"trace_id\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid otlpOutputShouldContainExemplarsWhenIncludeIsAllAndSpanIsNotSampled() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.sampling.probability=0.0\",\n\t\t\t\t\t\"management.tracing.exemplars.include=all\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ExemplarContextProvider.class);\n\t\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\t\tObservation.start(\"test.observation\", observationRegistry).stop();\n\t\t\t\tOtlpMeterRegistry otlpMeterRegistry = context.getBean(OtlpMeterRegistry.class);\n\t\t\t\tTestOtlpMetricsSender metricsSender = context.getBean(TestOtlpMetricsSender.class);\n\t\t\t\totlpMeterRegistry.close();\n\t\t\t\tassertThat(metricsSender.getOtlpRequest()).containsOnlyOnce(\"name: \\\"test.observation\\\"\")\n\t\t\t\t\t.containsOnlyOnce(\"exemplars\")\n\t\t\t\t\t.containsOnlyOnce(\"span_id\")\n\t\t\t\t\t.containsOnlyOnce(\"trace_id\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyExemplarContextProviderWhenIncludeIsNone() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ExemplarContextProvider.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\tstatic final ExemplarContextProvider CONTEXT_PROVIDER = mock(ExemplarContextProvider.class);\n\n\t\t@Bean\n\t\tExemplarContextProvider customContextProvider() {\n\t\t\treturn CONTEXT_PROVIDER;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TracingConfiguration {\n\n\t\t@Bean\n\t\tTracingAwareMeterObservationHandler<Context> tracingAwareMeterObservationHandler(MeterRegistry meterRegistry,\n\t\t\t\tTracer tracer) {\n\t\t\tDefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry);\n\t\t\treturn new TracingAwareMeterObservationHandler<>(delegate, tracer);\n\t\t}\n\n\t\t@Bean\n\t\tTestOtlpMetricsSender testOtlpMetricsSender() {\n\t\t\treturn new TestOtlpMetricsSender();\n\t\t}\n\n\t}\n\n\tstatic class TestOtlpMetricsSender implements OtlpMetricsSender {\n\n\t\tprivate String request = \"\";\n\n\t\t@Override\n\t\tpublic void send(Request request) throws Exception {\n\t\t\tthis.request = request.toString();\n\t\t}\n\n\t\tString getOtlpRequest() {\n\t\t\treturn this.request;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/PrometheusExemplarsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure;\n\nimport java.util.Optional;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.prometheusmetrics.PrometheusMeterRegistry;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;\nimport io.prometheus.metrics.expositionformats.OpenMetricsTextFormatWriter;\nimport io.prometheus.metrics.tracer.common.SpanContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.prometheus.PrometheusMetricsExportAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.prometheus.PrometheusExemplarsAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PrometheusExemplarsAutoConfiguration}.\n *\n * @author Jonatan Ivanov\n */\nclass PrometheusExemplarsAutoConfigurationTests {\n\n\tprivate static final Pattern BUCKET_TRACE_INFO_PATTERN = Pattern.compile(\n\t\t\t\"^test_observation_seconds_bucket\\\\{error=\\\"none\\\",le=\\\".+\\\"} 1 # \\\\{span_id=\\\"(\\\\p{XDigit}+)\\\",trace_id=\\\"(\\\\p{XDigit}+)\\\"} .+$\");\n\n\tprivate static final Pattern COUNT_TRACE_INFO_PATTERN = Pattern.compile(\n\t\t\t\"^test_observation_seconds_count\\\\{error=\\\"none\\\"} 1 # \\\\{span_id=\\\"(\\\\p{XDigit}+)\\\",trace_id=\\\"(\\\\p{XDigit}+)\\\"} .+$\");\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"management.tracing.sampling.probability=1.0\",\n\t\t\t\t\"management.metrics.distribution.percentiles-histogram.all=true\",\n\t\t\t\t\"management.metrics.use-global-registry=false\")\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(MetricsAutoConfiguration.class, PrometheusMetricsExportAutoConfiguration.class,\n\t\t\t\t\t\tPrometheusExemplarsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\t\tBraveAutoConfiguration.class, MicrometerTracingAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfPrometheusSupportIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.prometheus.metrics.tracer\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfMicrometerTracingIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer.tracing\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SpanContext.class)\n\t\t\t\t.getBean(SpanContext.class)\n\t\t\t\t.isSameAs(CustomConfiguration.SPAN_CONTEXT));\n\t}\n\n\t@Test\n\tvoid prometheusOpenMetricsOutputWithoutExemplarsOnHistogramCount() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class)\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"management.prometheus.metrics.export.properties.io.prometheus.exporter.exemplarsOnAllMetricTypes=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SpanContext.class);\n\t\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\t\tObservation.start(\"test.observation\", observationRegistry).stop();\n\t\t\t\tPrometheusMeterRegistry prometheusMeterRegistry = context.getBean(PrometheusMeterRegistry.class);\n\t\t\t\tString openMetricsOutput = prometheusMeterRegistry.scrape(OpenMetricsTextFormatWriter.CONTENT_TYPE);\n\n\t\t\t\tassertThat(openMetricsOutput).contains(\"test_observation_seconds_bucket\");\n\t\t\t\tassertThat(openMetricsOutput).containsOnlyOnce(\"test_observation_seconds_count\");\n\t\t\t\tassertThat(StringUtils.countOccurrencesOf(openMetricsOutput, \"span_id\")).isEqualTo(1);\n\t\t\t\tassertThat(StringUtils.countOccurrencesOf(openMetricsOutput, \"trace_id\")).isEqualTo(1);\n\n\t\t\t\tOptional<TraceInfo> bucketTraceInfo = openMetricsOutput.lines()\n\t\t\t\t\t.filter((line) -> line.contains(\"test_observation_seconds_bucket\") && line.contains(\"span_id\"))\n\t\t\t\t\t.map(BUCKET_TRACE_INFO_PATTERN::matcher)\n\t\t\t\t\t.flatMap(Matcher::results)\n\t\t\t\t\t.map((matchResult) -> new TraceInfo(matchResult.group(2), matchResult.group(1)))\n\t\t\t\t\t.findFirst();\n\n\t\t\t\tassertThat(bucketTraceInfo).isNotEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid prometheusOpenMetricsOutputShouldContainExemplars() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpanContext.class);\n\t\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\t\tObservation.start(\"test.observation\", observationRegistry).stop();\n\t\t\tPrometheusMeterRegistry prometheusMeterRegistry = context.getBean(PrometheusMeterRegistry.class);\n\t\t\tString openMetricsOutput = prometheusMeterRegistry.scrape(OpenMetricsTextFormatWriter.CONTENT_TYPE);\n\n\t\t\tassertThat(openMetricsOutput).contains(\"test_observation_seconds_bucket\");\n\t\t\tassertThat(openMetricsOutput).containsOnlyOnce(\"test_observation_seconds_count\");\n\t\t\tassertThat(StringUtils.countOccurrencesOf(openMetricsOutput, \"span_id\")).isEqualTo(2);\n\t\t\tassertThat(StringUtils.countOccurrencesOf(openMetricsOutput, \"trace_id\")).isEqualTo(2);\n\n\t\t\tOptional<TraceInfo> bucketTraceInfo = openMetricsOutput.lines()\n\t\t\t\t.filter((line) -> line.contains(\"test_observation_seconds_bucket\") && line.contains(\"span_id\"))\n\t\t\t\t.map(BUCKET_TRACE_INFO_PATTERN::matcher)\n\t\t\t\t.flatMap(Matcher::results)\n\t\t\t\t.map((matchResult) -> new TraceInfo(matchResult.group(2), matchResult.group(1)))\n\t\t\t\t.findFirst();\n\n\t\t\tOptional<TraceInfo> counterTraceInfo = openMetricsOutput.lines()\n\t\t\t\t.filter((line) -> line.contains(\"test_observation_seconds_count\") && line.contains(\"span_id\"))\n\t\t\t\t.map(COUNT_TRACE_INFO_PATTERN::matcher)\n\t\t\t\t.flatMap(Matcher::results)\n\t\t\t\t.map((matchResult) -> new TraceInfo(matchResult.group(2), matchResult.group(1)))\n\t\t\t\t.findFirst();\n\n\t\t\tassertThat(bucketTraceInfo).isNotEmpty().contains(counterTraceInfo.orElse(null));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailWhenIncludeIsAll() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=all\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(InvalidConfigurationPropertyValueException.class)\n\t\t\t\t.hasMessageContaining(\n\t\t\t\t\t\t\"Property management.tracing.exemplars.include with value 'all' is invalid: Prometheus doesn't support including 'all' traces as exemplars.\"));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySpanContextWhenIncludeIsNone() {\n\t\tthis.contextRunner.withUserConfiguration(TracingConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.exemplars.include=none\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanContext.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\tstatic final SpanContext SPAN_CONTEXT = mock(SpanContext.class);\n\n\t\t@Bean\n\t\tSpanContext customSpanContext() {\n\t\t\treturn SPAN_CONTEXT;\n\t\t}\n\n\t}\n\n\tprivate record TraceInfo(String traceId, String spanId) {\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TracingConfiguration {\n\n\t\t@Bean\n\t\tTracingAwareMeterObservationHandler<Observation.Context> tracingAwareMeterObservationHandler(\n\t\t\t\tMeterRegistry meterRegistry, Tracer tracer) {\n\t\t\tDefaultMeterObservationHandler delegate = new DefaultMeterObservationHandler(meterRegistry);\n\t\t\treturn new TracingAwareMeterObservationHandler<>(delegate, tracer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/zipkin/DefaultEncodingConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure.zipkin;\n\nimport zipkin2.reporter.Encoding;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Configures the bean {@linkplain ZipkinAutoConfiguration} would from properties.\n */\n@TestConfiguration(proxyBeanMethods = false)\nclass DefaultEncodingConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tEncoding zipkinReporterEncoding() {\n\t\treturn Encoding.JSON;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/zipkin/NoopSender.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure.zipkin;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\n\nclass NoopSender extends BytesMessageSender.Base {\n\n\tNoopSender(Encoding encoding) {\n\t\tsuper(encoding);\n\t}\n\n\t@Override\n\tpublic int messageMaxBytes() {\n\t\treturn 1024;\n\t}\n\n\t@Override\n\tpublic void send(List<byte[]> encodedSpans) {\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-brave/src/test/java/org/springframework/boot/micrometer/tracing/brave/autoconfigure/zipkin/ZipkinWithBraveTracingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.brave.autoconfigure.zipkin;\n\nimport java.nio.charset.StandardCharsets;\n\nimport brave.Tag;\nimport brave.handler.MutableSpan;\nimport brave.handler.SpanHandler;\nimport brave.propagation.TraceContext;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport zipkin2.reporter.BytesEncoder;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.brave.AsyncZipkinSpanHandler;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ZipkinWithBraveTracingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass ZipkinWithBraveTracingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(DefaultEncodingConfiguration.class, ZipkinWithBraveTracingAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AsyncZipkinSpanHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySpanHandlerIfReporterIsMissing() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(AsyncZipkinSpanHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyIfZipkinReporterBraveIsNotOnClasspath() {\n\t\t// Note: Technically, Brave can work without zipkin-reporter. We also need this\n\t\t// for any configuration that uses senders defined in the Spring Boot source tree,\n\t\t// such as HttpSender.\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"zipkin2.reporter.brave\"))\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AsyncZipkinSpanHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"customAsyncZipkinSpanHandler\");\n\t\t\t\tassertThat(context).hasSingleBean(AsyncZipkinSpanHandler.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyAsyncZipkinSpanHandlerWithCustomSpanHandler() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomSpanHandlerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"customSpanHandler\");\n\t\t\t\tassertThat(context).hasSingleBean(AsyncZipkinSpanHandler.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyAsyncZipkinSpanHandlerIfGlobalTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.enabled=false\")\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AsyncZipkinSpanHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyAsyncZipkinSpanHandlerIfZipkinTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.zipkin.enabled=false\")\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AsyncZipkinSpanHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomEncoderBean() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomEncoderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncZipkinSpanHandler.class);\n\t\t\t\tassertThat(context.getBean(AsyncZipkinSpanHandler.class)).extracting(\"spanReporter.encoder\")\n\t\t\t\t\t.isInstanceOf(CustomMutableSpanEncoder.class)\n\t\t\t\t\t.extracting(\"encoding\")\n\t\t\t\t\t.isEqualTo(Encoding.JSON);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomEncodingBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(SenderConfiguration.class, CustomEncodingConfiguration.class,\n\t\t\t\t\tCustomEncoderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncZipkinSpanHandler.class);\n\t\t\t\tassertThat(context.getBean(AsyncZipkinSpanHandler.class)).extracting(\"encoding\")\n\t\t\t\t\t.isEqualTo(Encoding.PROTO3);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseDefaultThrowableTagBean() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class).run((context) -> {\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tBytesEncoder<MutableSpan> encoder = context.getBean(BytesEncoder.class);\n\t\t\tMutableSpan span = createTestSpan();\n\t\t\t// default tag key name is \"error\", and doesn't overwrite\n\t\t\tassertThat(new String(encoder.encode(span), StandardCharsets.UTF_8)).isEqualTo(\n\t\t\t\t\t\"{\\\"traceId\\\":\\\"0000000000000001\\\",\\\"id\\\":\\\"0000000000000001\\\",\\\"tags\\\":{\\\"error\\\":\\\"true\\\"}}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomThrowableTagBean() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomThrowableTagConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tBytesEncoder<MutableSpan> encoder = context.getBean(BytesEncoder.class);\n\t\t\t\tMutableSpan span = createTestSpan();\n\t\t\t\t// The custom throwable parser doesn't use the key \"error\" we can see both\n\t\t\t\tassertThat(new String(encoder.encode(span), StandardCharsets.UTF_8)).isEqualTo(\n\t\t\t\t\t\t\"{\\\"traceId\\\":\\\"0000000000000001\\\",\\\"id\\\":\\\"0000000000000001\\\",\\\"tags\\\":{\\\"error\\\":\\\"true\\\",\\\"exception\\\":\\\"ice cream\\\"}}\");\n\t\t\t});\n\t}\n\n\tprivate MutableSpan createTestSpan() {\n\t\tMutableSpan span = new MutableSpan();\n\t\tspan.traceId(\"1\");\n\t\tspan.id(\"1\");\n\t\tspan.tag(\"error\", \"true\");\n\t\tspan.error(new RuntimeException(\"ice cream\"));\n\t\treturn span;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class SenderConfiguration {\n\n\t\t@Bean\n\t\tBytesMessageSender sender(Encoding encoding) {\n\t\t\treturn new NoopSender(encoding);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\t@Bean\n\t\tAsyncZipkinSpanHandler customAsyncZipkinSpanHandler() {\n\t\t\treturn AsyncZipkinSpanHandler.create(new NoopSender(Encoding.JSON));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomThrowableTagConfiguration {\n\n\t\t@Bean\n\t\tTag<Throwable> throwableTag() {\n\t\t\treturn new Tag<>(\"exception\") {\n\t\t\t\t@Override\n\t\t\t\tprotected @Nullable String parseValue(Throwable throwable, @Nullable TraceContext traceContext) {\n\t\t\t\t\treturn throwable.getMessage();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomSpanHandlerConfiguration {\n\n\t\t@Bean\n\t\tSpanHandler customSpanHandler() {\n\t\t\treturn mock(SpanHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomEncodingConfiguration {\n\n\t\t@Bean\n\t\tEncoding encoding() {\n\t\t\treturn Encoding.PROTO3;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomEncoderConfiguration {\n\n\t\t@Bean\n\t\tBytesEncoder<MutableSpan> encoder(Encoding encoding) {\n\t\t\treturn new CustomMutableSpanEncoder(encoding);\n\t\t}\n\n\t}\n\n\tprivate record CustomMutableSpanEncoder(Encoding encoding) implements BytesEncoder<MutableSpan> {\n\n\t\t@Override\n\t\tpublic int sizeInBytes(MutableSpan span) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic byte[] encode(MutableSpan span) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Tracing OpenTelemetry\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-micrometer-observation\"))\n\tapi(project(\":module:spring-boot-micrometer-tracing\"))\n\tapi(project(\":module:spring-boot-opentelemetry\"))\n\tapi(\"io.micrometer:micrometer-tracing\") {\n\t\texclude(group: \"aopalliance\", module: \"aopalliance\")\n\t}\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-zipkin\"))\n\toptional(\"io.micrometer:micrometer-tracing-bridge-otel\")\n\toptional(\"io.opentelemetry:opentelemetry-exporter-zipkin\")\n\toptional(\"io.opentelemetry:opentelemetry-exporter-otlp\")\n\toptional(\"org.junit.platform:junit-platform-launcher\")\n\toptional(\"org.testcontainers:testcontainers-grafana\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-tracing-brave\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-tracing-bridge-brave\")\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"io.micrometer:micrometer-registry-prometheus\")\n\ttestImplementation(\"io.opentelemetry:opentelemetry-exporter-common\")\n\ttestImplementation(\"io.prometheus:prometheus-metrics-exposition-formats\")\n\ttestImplementation(\"org.eclipse.jetty.ee11:jetty-ee11-webapp\")\n\ttestImplementation(\"org.eclipse.jetty.http2:jetty-http2-server\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.grpc:grpc-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/java/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.docker.compose.otlp;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory}\n * using {@link TestImage#GRAFANA_OTEL_LGTM}.\n *\n * @author Eddú Meléndez\n */\nclass GrafanaOpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"otlp-compose.yaml\", image = TestImage.GRAFANA_OTEL_LGTM)\n\tvoid runCreatesConnectionDetails(OtlpTracingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"http://\").endsWith(\"/v1/traces\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"http://\").endsWith(\"/v1/traces\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"otlp-ssl-compose.yaml\", image = TestImage.GRAFANA_OTEL_LGTM,\n\t\t\tadditionalResources = \"ca.crt\")\n\tvoid runWithSslCreatesConnectionDetails(OtlpTracingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"https://\").endsWith(\"/v1/traces\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"https://\").endsWith(\"/v1/traces\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/java/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.docker.compose.otlp;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OpenTelemetryTracingDockerComposeConnectionDetailsFactory}\n * using {@link TestImage#OTEL_COLLECTOR}.\n *\n * @author Eddú Meléndez\n */\nclass OpenTelemetryTracingDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"otlp-compose.yaml\", image = TestImage.OTEL_COLLECTOR)\n\tvoid runCreatesConnectionDetails(OtlpTracingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"http://\").endsWith(\"/v1/traces\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"http://\").endsWith(\"/v1/traces\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"otlp-ssl-compose.yaml\", image = TestImage.OTEL_COLLECTOR,\n\t\t\tadditionalResources = \"ca.crt\")\n\tvoid runWithSslCreatesConnectionDetails(OtlpTracingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"https://\").endsWith(\"/v1/traces\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"https://\").endsWith(\"/v1/traces\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/java/org/springframework/boot/micrometer/tracing/opentelemetry/testcontainers/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.grafana.LgtmStackContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass GrafanaOpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class);\n\n\t@Autowired\n\tprivate OtlpTracingConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToOpenTelemetryContainer() {\n\t\tassertThat(this.connectionDetails.getUrl(Transport.HTTP))\n\t\t\t.isEqualTo(\"%s/v1/traces\".formatted(container.getOtlpHttpUrl()));\n\t\tassertThat(this.connectionDetails.getUrl(Transport.GRPC))\n\t\t\t.isEqualTo(\"%s/v1/traces\".formatted(container.getOtlpGrpcUrl()));\n\t\tassertThat(this.connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(OtlpTracingAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/java/org/springframework/boot/micrometer/tracing/opentelemetry/testcontainers/otlp/OpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OpenTelemetryTracingContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass OpenTelemetryTracingContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final GenericContainer<?> container = TestImage.OTEL_COLLECTOR.genericContainer()\n\t\t.withExposedPorts(4317, 4318);\n\n\t@Autowired\n\tprivate OtlpTracingConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToOpenTelemetryContainer() {\n\t\tassertThat(this.connectionDetails.getUrl(Transport.HTTP))\n\t\t\t.isEqualTo(\"http://\" + container.getHost() + \":\" + container.getMappedPort(4318) + \"/v1/traces\");\n\t\tassertThat(this.connectionDetails.getUrl(Transport.GRPC))\n\t\t\t.isEqualTo(\"http://\" + container.getHost() + \":\" + container.getMappedPort(4317) + \"/v1/traces\");\n\t\tassertThat(this.connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(OtlpTracingAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/resources/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/resources/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/otlp-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/dockerTest/resources/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/otlp-ssl-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/CompositeTextMapPropagator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;\nimport io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;\nimport io.opentelemetry.context.Context;\nimport io.opentelemetry.context.propagation.TextMapGetter;\nimport io.opentelemetry.context.propagation.TextMapPropagator;\nimport io.opentelemetry.context.propagation.TextMapSetter;\nimport io.opentelemetry.extension.trace.propagation.B3Propagator;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Propagation;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Propagation.PropagationType;\n\n/**\n * {@link TextMapPropagator} which supports multiple tracing formats. It is able to\n * configure different formats for injecting and for extracting.\n *\n * @author Moritz Halbritter\n * @author Scott Frederick\n */\nclass CompositeTextMapPropagator implements TextMapPropagator {\n\n\tprivate final Collection<TextMapPropagator> injectors;\n\n\tprivate final Collection<TextMapPropagator> extractors;\n\n\tprivate final @Nullable TextMapPropagator baggagePropagator;\n\n\tprivate final Set<String> fields;\n\n\t/**\n\t * Creates a new {@link CompositeTextMapPropagator}.\n\t * @param injectors the injectors\n\t * @param mutuallyExclusiveExtractors the mutually exclusive extractors. They are\n\t * applied in order, and as soon as an extractor extracts a context, the other\n\t * extractors after it are no longer invoked\n\t * @param baggagePropagator the baggage propagator to use, or {@code null}\n\t */\n\tCompositeTextMapPropagator(Collection<TextMapPropagator> injectors,\n\t\t\tCollection<TextMapPropagator> mutuallyExclusiveExtractors, @Nullable TextMapPropagator baggagePropagator) {\n\t\tthis.injectors = injectors;\n\t\tthis.extractors = mutuallyExclusiveExtractors;\n\t\tthis.baggagePropagator = baggagePropagator;\n\t\tSet<String> fields = new LinkedHashSet<>();\n\t\tfields(this.injectors).forEach(fields::add);\n\t\tfields(this.extractors).forEach(fields::add);\n\t\tif (baggagePropagator != null) {\n\t\t\tfields.addAll(baggagePropagator.fields());\n\t\t}\n\t\tthis.fields = Collections.unmodifiableSet(fields);\n\t}\n\n\tprivate Stream<String> fields(Collection<TextMapPropagator> propagators) {\n\t\treturn propagators.stream().flatMap((propagator) -> propagator.fields().stream());\n\t}\n\n\tCollection<TextMapPropagator> getInjectors() {\n\t\treturn this.injectors;\n\t}\n\n\tCollection<TextMapPropagator> getExtractors() {\n\t\treturn this.extractors;\n\t}\n\n\t@Override\n\tpublic Collection<String> fields() {\n\t\treturn this.fields;\n\t}\n\n\t@Override\n\tpublic <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> setter) {\n\t\tif (context != null && setter != null) {\n\t\t\tthis.injectors.forEach((injector) -> injector.inject(context, carrier, setter));\n\t\t}\n\t}\n\n\t@Override\n\tpublic <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {\n\t\tif (context == null) {\n\t\t\treturn Context.root();\n\t\t}\n\t\tif (getter == null) {\n\t\t\treturn context;\n\t\t}\n\t\tContext result = context;\n\t\tfor (TextMapPropagator extractor : this.extractors) {\n\t\t\tContext extracted = extractor.extract(context, carrier, getter);\n\t\t\tif (extracted != context) {\n\t\t\t\tresult = extracted;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (this.baggagePropagator != null) {\n\t\t\tresult = this.baggagePropagator.extract(result, carrier, getter);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates a new {@link CompositeTextMapPropagator}.\n\t * @param properties the tracing properties\n\t * @param baggagePropagator the baggage propagator to use, or {@code null}\n\t * @return the {@link CompositeTextMapPropagator}\n\t */\n\tstatic TextMapPropagator create(TracingProperties.Propagation properties,\n\t\t\t@Nullable TextMapPropagator baggagePropagator) {\n\t\tTextMapPropagatorMapper mapper = new TextMapPropagatorMapper(baggagePropagator != null);\n\t\tList<TextMapPropagator> injectors = getEffectiveProducedTypes(properties).stream()\n\t\t\t.map(mapper::map)\n\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\tif (baggagePropagator != null) {\n\t\t\tinjectors.add(baggagePropagator);\n\t\t}\n\t\tList<TextMapPropagator> extractors = getEffectiveConsumedTypes(properties).stream().map(mapper::map).toList();\n\t\treturn new CompositeTextMapPropagator(injectors, extractors, baggagePropagator);\n\t}\n\n\tprivate static List<PropagationType> getEffectiveConsumedTypes(Propagation properties) {\n\t\treturn (properties.getType() != null) ? properties.getType() : properties.getConsume();\n\t}\n\n\tprivate static List<PropagationType> getEffectiveProducedTypes(Propagation properties) {\n\t\treturn (properties.getType() != null) ? properties.getType() : properties.getProduce();\n\t}\n\n\t/**\n\t * Mapper used to create a {@link TextMapPropagator} from a {@link PropagationType}.\n\t */\n\tprivate static class TextMapPropagatorMapper {\n\n\t\tprivate final boolean baggage;\n\n\t\tTextMapPropagatorMapper(boolean baggage) {\n\t\t\tthis.baggage = baggage;\n\t\t}\n\n\t\tTextMapPropagator map(PropagationType type) {\n\t\t\treturn switch (type) {\n\t\t\t\tcase B3 -> b3Single();\n\t\t\t\tcase B3_MULTI -> b3Multi();\n\t\t\t\tcase W3C -> w3c();\n\t\t\t};\n\t\t}\n\n\t\t/**\n\t\t * Creates a new B3 propagator using a single B3 header.\n\t\t * @return the B3 propagator\n\t\t */\n\t\tprivate TextMapPropagator b3Single() {\n\t\t\treturn B3Propagator.injectingSingleHeader();\n\t\t}\n\n\t\t/**\n\t\t * Creates a new B3 propagator using multiple B3 headers.\n\t\t * @return the B3 propagator\n\t\t */\n\t\tprivate TextMapPropagator b3Multi() {\n\t\t\treturn B3Propagator.injectingMultiHeaders();\n\t\t}\n\n\t\t/**\n\t\t * Creates a new W3C propagator.\n\t\t * @return the W3C propagator\n\t\t */\n\t\tprivate TextMapPropagator w3c() {\n\t\t\treturn (!this.baggage) ? W3CTraceContextPropagator.getInstance() : TextMapPropagator\n\t\t\t\t.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryEventPublisherBeansApplicationListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.micrometer.tracing.otel.bridge.EventPublishingContextWrapper;\nimport io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;\nimport io.opentelemetry.context.Context;\nimport io.opentelemetry.context.ContextStorage;\nimport io.opentelemetry.context.Scope;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.event.ApplicationStartingEvent;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.event.GenericApplicationListener;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\n/**\n * {@link ApplicationListener} to add an OpenTelemetry {@link ContextStorage} wrapper for\n * {@link EventPublisher} bean support. A single {@link ContextStorage} wrapper is added\n * on the {@link ApplicationStartingEvent} then updated with {@link EventPublisher} beans\n * as needed.\n * <p>\n * The {@link #addWrapper()} method may also be called directly if the\n * {@link ApplicationStartingEvent} isn't called early enough or isn't fired.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see OpenTelemetryEventPublisherBeansTestExecutionListener\n */\npublic class OpenTelemetryEventPublisherBeansApplicationListener implements GenericApplicationListener {\n\n\tprivate static final boolean OTEL_CONTEXT_PRESENT = ClassUtils.isPresent(\"io.opentelemetry.context.ContextStorage\",\n\t\t\tnull);\n\n\tprivate static final boolean MICROMETER_OTEL_PRESENT = ClassUtils\n\t\t.isPresent(\"io.micrometer.tracing.otel.bridge.OtelTracer\", null);\n\n\tprivate static final AtomicBoolean added = new AtomicBoolean();\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tpublic boolean supportsEventType(ResolvableType eventType) {\n\t\tClass<?> type = eventType.getRawClass();\n\t\treturn (type != null) && (ApplicationStartingEvent.class.isAssignableFrom(type)\n\t\t\t\t|| ContextRefreshedEvent.class.isAssignableFrom(type)\n\t\t\t\t|| ContextClosedEvent.class.isAssignableFrom(type));\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\tif (!isInstallable()) {\n\t\t\treturn;\n\t\t}\n\t\tif (event instanceof ApplicationStartingEvent) {\n\t\t\taddWrapper();\n\t\t}\n\t\tif (event instanceof ContextRefreshedEvent contextRefreshedEvent) {\n\t\t\tApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();\n\t\t\tList<EventPublishingContextWrapper> publishers = applicationContext\n\t\t\t\t.getBeansOfType(EventPublisher.class, true, false)\n\t\t\t\t.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(EventPublishingContextWrapper::new)\n\t\t\t\t.toList();\n\t\t\tWrapper.instance.put(applicationContext, publishers);\n\t\t}\n\t\tif (event instanceof ContextClosedEvent contextClosedEvent) {\n\t\t\tWrapper.instance.remove(contextClosedEvent.getApplicationContext());\n\t\t}\n\t}\n\n\t/**\n\t * {@link ContextStorage#addWrapper(java.util.function.Function) Add} the\n\t * {@link ContextStorage} wrapper to ensure that {@link EventPublisher\n\t * EventPublishers} are propagated correctly.\n\t */\n\tpublic static void addWrapper() {\n\t\tif (isInstallable() && added.compareAndSet(false, true)) {\n\t\t\tWrapper.instance.addWrapper();\n\t\t}\n\t}\n\n\tprivate static boolean isInstallable() {\n\t\treturn OTEL_CONTEXT_PRESENT && MICROMETER_OTEL_PRESENT;\n\t}\n\n\t/**\n\t * Single instance class used to add the wrapper and manage the {@link EventPublisher}\n\t * beans.\n\t */\n\tstatic final class Wrapper {\n\n\t\tstatic final Wrapper instance = new Wrapper();\n\n\t\tprivate final MultiValueMap<ApplicationContext, EventPublishingContextWrapper> beans = new LinkedMultiValueMap<>();\n\n\t\tprivate volatile @Nullable ContextStorage storageDelegate;\n\n\t\tprivate Wrapper() {\n\t\t}\n\n\t\tprivate void addWrapper() {\n\t\t\tContextStorage.addWrapper(Storage::new);\n\t\t}\n\n\t\tvoid put(ApplicationContext applicationContext, List<EventPublishingContextWrapper> publishers) {\n\t\t\tsynchronized (this) {\n\t\t\t\tthis.beans.addAll(applicationContext, publishers);\n\t\t\t\tthis.storageDelegate = null;\n\t\t\t}\n\t\t}\n\n\t\tvoid remove(ApplicationContext applicationContext) {\n\t\t\tsynchronized (this) {\n\t\t\t\tthis.beans.remove(applicationContext);\n\t\t\t\tthis.storageDelegate = null;\n\t\t\t}\n\t\t}\n\n\t\tContextStorage getStorageDelegate(ContextStorage parent) {\n\t\t\tContextStorage delegate = this.storageDelegate;\n\t\t\tif (delegate == null) {\n\t\t\t\tsynchronized (this) {\n\t\t\t\t\tdelegate = this.storageDelegate;\n\t\t\t\t\tif (delegate == null) {\n\t\t\t\t\t\tdelegate = parent;\n\t\t\t\t\t\tfor (List<EventPublishingContextWrapper> publishers : this.beans.values()) {\n\t\t\t\t\t\t\tfor (EventPublishingContextWrapper publisher : publishers) {\n\t\t\t\t\t\t\t\tdelegate = publisher.apply(delegate);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.storageDelegate = delegate;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn delegate;\n\t\t}\n\n\t\t/**\n\t\t * {@link ContextStorage} that delegates to the {@link EventPublisher} beans.\n\t\t */\n\t\tclass Storage implements ContextStorage {\n\n\t\t\tprivate final ContextStorage parent;\n\n\t\t\tStorage(ContextStorage parent) {\n\t\t\t\tthis.parent = parent;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Scope attach(Context toAttach) {\n\t\t\t\treturn getDelegate().attach(toAttach);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Context current() {\n\t\t\t\treturn getDelegate().current();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Context root() {\n\t\t\t\treturn getDelegate().root();\n\t\t\t}\n\n\t\t\tprivate ContextStorage getDelegate() {\n\t\t\t\treturn getStorageDelegate(this.parent);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryEventPublisherBeansTestExecutionListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport org.junit.platform.launcher.TestExecutionListener;\nimport org.junit.platform.launcher.TestIdentifier;\n\n/**\n * JUnit {@link TestExecutionListener} to ensure\n * {@link OpenTelemetryEventPublisherBeansApplicationListener#addWrapper()} is called as\n * early as possible.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see OpenTelemetryEventPublisherBeansApplicationListener\n */\npublic class OpenTelemetryEventPublisherBeansTestExecutionListener implements TestExecutionListener {\n\n\t@Override\n\tpublic void executionStarted(TestIdentifier testIdentifier) {\n\t\tOpenTelemetryEventPublisherBeansApplicationListener.addWrapper();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryPropagationConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.tracing.otel.bridge.OtelBaggageManager;\nimport io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;\nimport io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;\nimport io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;\nimport io.opentelemetry.context.propagation.TextMapPropagator;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * OpenTelemetry propagation configurations. They are imported by\n * {@link OpenTelemetryTracingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass OpenTelemetryPropagationConfigurations {\n\n\t/**\n\t * Propagates traces but no baggage.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"management.tracing.baggage.enabled\", havingValue = false)\n\t@EnableConfigurationProperties(TracingProperties.class)\n\tstatic class PropagationWithoutBaggage {\n\n\t\t@Bean\n\t\t@ConditionalOnEnabledTracingExport\n\t\tTextMapPropagator textMapPropagator(TracingProperties properties) {\n\t\t\treturn CompositeTextMapPropagator.create(properties.getPropagation(), null);\n\t\t}\n\n\t}\n\n\t/**\n\t * Propagates traces and baggage.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"management.tracing.baggage.enabled\", matchIfMissing = true)\n\t@EnableConfigurationProperties(TracingProperties.class)\n\tstatic class PropagationWithBaggage {\n\n\t\tprivate final TracingProperties tracingProperties;\n\n\t\tPropagationWithBaggage(TracingProperties tracingProperties) {\n\t\t\tthis.tracingProperties = tracingProperties;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnEnabledTracingExport\n\t\tTextMapPropagator textMapPropagatorWithBaggage(OtelCurrentTraceContext otelCurrentTraceContext) {\n\t\t\tList<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();\n\t\t\tList<String> tagFields = this.tracingProperties.getBaggage().getTagFields();\n\t\t\tBaggageTextMapPropagator baggagePropagator = new BaggageTextMapPropagator(remoteFields,\n\t\t\t\t\tnew OtelBaggageManager(otelCurrentTraceContext, remoteFields, tagFields));\n\t\t\treturn CompositeTextMapPropagator.create(this.tracingProperties.getPropagation(), baggagePropagator);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnBooleanProperty(name = \"management.tracing.baggage.correlation.enabled\", matchIfMissing = true)\n\t\tSlf4JBaggageEventListener otelSlf4JBaggageEventListener() {\n\t\t\treturn new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields());\n\t\t}\n\n\t}\n\n\t/**\n\t * Propagates neither traces nor baggage.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NoPropagation {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tTextMapPropagator noopTextMapPropagator() {\n\t\t\treturn TextMapPropagator.noop();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryTracingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.List;\n\nimport io.micrometer.tracing.SpanCustomizer;\nimport io.micrometer.tracing.exporter.SpanExportingPredicate;\nimport io.micrometer.tracing.exporter.SpanFilter;\nimport io.micrometer.tracing.exporter.SpanReporter;\nimport io.micrometer.tracing.otel.bridge.CompositeSpanExporter;\nimport io.micrometer.tracing.otel.bridge.EventListener;\nimport io.micrometer.tracing.otel.bridge.OtelBaggageManager;\nimport io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;\nimport io.micrometer.tracing.otel.bridge.OtelPropagator;\nimport io.micrometer.tracing.otel.bridge.OtelSpanCustomizer;\nimport io.micrometer.tracing.otel.bridge.OtelTracer;\nimport io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;\nimport io.micrometer.tracing.otel.bridge.Slf4JEventListener;\nimport io.micrometer.tracing.propagation.Propagator;\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.api.metrics.MeterProvider;\nimport io.opentelemetry.api.trace.Tracer;\nimport io.opentelemetry.context.propagation.ContextPropagators;\nimport io.opentelemetry.context.propagation.TextMapPropagator;\nimport io.opentelemetry.sdk.resources.Resource;\nimport io.opentelemetry.sdk.trace.SdkTracerProvider;\nimport io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;\nimport io.opentelemetry.sdk.trace.SpanLimits;\nimport io.opentelemetry.sdk.trace.SpanProcessor;\nimport io.opentelemetry.sdk.trace.export.BatchSpanProcessor;\nimport io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder;\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport io.opentelemetry.sdk.trace.samplers.Sampler;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.SpringBootVersion;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.NoopTracerAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryPropagationConfigurations.NoPropagation;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryPropagationConfigurations.PropagationWithBaggage;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryPropagationConfigurations.PropagationWithoutBaggage;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryTracingProperties.Export;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryTracingProperties.Limits;\nimport org.springframework.boot.opentelemetry.autoconfigure.ConditionalOnEnabledOpenTelemetry;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry tracing.\n *\n * @author Moritz Halbritter\n * @author Marcin Grzejszczak\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration(before = { MicrometerTracingAutoConfiguration.class, NoopTracerAutoConfiguration.class })\n@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class })\n@EnableConfigurationProperties({ TracingProperties.class, OpenTelemetryTracingProperties.class })\n@Import({ PropagationWithoutBaggage.class, PropagationWithBaggage.class, NoPropagation.class })\npublic final class OpenTelemetryTracingAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(OpenTelemetryTracingAutoConfiguration.class);\n\n\tprivate final TracingProperties tracingProperties;\n\n\tprivate final OpenTelemetryTracingProperties openTelemetryTracingProperties;\n\n\tOpenTelemetryTracingAutoConfiguration(TracingProperties tracingProperties,\n\t\t\tOpenTelemetryTracingProperties openTelemetryTracingProperties) {\n\t\tthis.tracingProperties = tracingProperties;\n\t\tif (!CollectionUtils.isEmpty(this.tracingProperties.getBaggage().getLocalFields())) {\n\t\t\tlogger.warn(\"Local fields are not supported when using OpenTelemetry!\");\n\t\t}\n\t\tthis.openTelemetryTracingProperties = openTelemetryTracingProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledOpenTelemetry\n\tSdkTracerProvider otelSdkTracerProvider(Resource resource, SpanProcessors spanProcessors, Sampler sampler,\n\t\t\tObjectProvider<SdkTracerProviderBuilderCustomizer> customizers, SpanLimits spanLimits) {\n\t\tSdkTracerProviderBuilder builder = SdkTracerProvider.builder()\n\t\t\t.setSampler(sampler)\n\t\t\t.setResource(resource)\n\t\t\t.setSpanLimits(spanLimits);\n\t\tspanProcessors.forEach(builder::addSpanProcessor);\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledOpenTelemetry\n\tSpanLimits otelSpanLimits() {\n\t\tLimits limits = this.openTelemetryTracingProperties.getLimits();\n\t\treturn SpanLimits.builder()\n\t\t\t.setMaxAttributeValueLength(limits.getMaxAttributeValueLength())\n\t\t\t.setMaxNumberOfAttributes(limits.getMaxAttributes())\n\t\t\t.setMaxNumberOfEvents(limits.getMaxEvents())\n\t\t\t.setMaxNumberOfLinks(limits.getMaxLinks())\n\t\t\t.setMaxNumberOfAttributesPerEvent(limits.getMaxAttributesPerEvent())\n\t\t\t.setMaxNumberOfAttributesPerLink(limits.getMaxAttributesPerLink())\n\t\t\t.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tContextPropagators otelContextPropagators(ObjectProvider<TextMapPropagator> textMapPropagators) {\n\t\treturn ContextPropagators.create(TextMapPropagator.composite(textMapPropagators.orderedStream().toList()));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledOpenTelemetry\n\tSampler otelSampler() {\n\t\treturn switch (this.openTelemetryTracingProperties.getSampler()) {\n\t\t\tcase ALWAYS_ON -> Sampler.alwaysOn();\n\t\t\tcase ALWAYS_OFF -> Sampler.alwaysOff();\n\t\t\tcase TRACE_ID_RATIO -> Sampler.traceIdRatioBased(this.tracingProperties.getSampling().getProbability());\n\t\t\tcase PARENT_BASED_ALWAYS_ON -> Sampler.parentBased(Sampler.alwaysOn());\n\t\t\tcase PARENT_BASED_ALWAYS_OFF -> Sampler.parentBased(Sampler.alwaysOff());\n\t\t\tcase PARENT_BASED_TRACE_ID_RATIO ->\n\t\t\t\tSampler.parentBased(Sampler.traceIdRatioBased(this.tracingProperties.getSampling().getProbability()));\n\t\t};\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledOpenTelemetry\n\tSpanProcessors spanProcessors(ObjectProvider<SpanProcessor> spanProcessors) {\n\t\treturn SpanProcessors.of(spanProcessors.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledOpenTelemetry\n\tBatchSpanProcessor otelSpanProcessor(SpanExporters spanExporters,\n\t\t\tObjectProvider<SpanExportingPredicate> spanExportingPredicates, ObjectProvider<SpanReporter> spanReporters,\n\t\t\tObjectProvider<SpanFilter> spanFilters, ObjectProvider<MeterProvider> meterProvider) {\n\t\tExport properties = this.openTelemetryTracingProperties.getExport();\n\t\tCompositeSpanExporter spanExporter = new CompositeSpanExporter(spanExporters.list(),\n\t\t\t\tspanExportingPredicates.orderedStream().toList(), spanReporters.orderedStream().toList(),\n\t\t\t\tspanFilters.orderedStream().toList());\n\t\tBatchSpanProcessorBuilder builder = BatchSpanProcessor.builder(spanExporter)\n\t\t\t.setExportUnsampledSpans(properties.isIncludeUnsampled())\n\t\t\t.setExporterTimeout(properties.getTimeout())\n\t\t\t.setMaxExportBatchSize(properties.getMaxBatchSize())\n\t\t\t.setMaxQueueSize(properties.getMaxQueueSize())\n\t\t\t.setScheduleDelay(properties.getScheduleDelay());\n\t\tmeterProvider.ifAvailable(builder::setMeterProvider);\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnEnabledOpenTelemetry\n\tSpanExporters spanExporters(ObjectProvider<SpanExporter> spanExporters) {\n\t\treturn SpanExporters.of(spanExporters.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tTracer otelTracer(OpenTelemetry openTelemetry) {\n\t\treturn openTelemetry.getTracer(\"org.springframework.boot\", SpringBootVersion.getVersion());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(io.micrometer.tracing.Tracer.class)\n\tOtelTracer micrometerOtelTracer(Tracer tracer, EventPublisher eventPublisher,\n\t\t\tOtelCurrentTraceContext otelCurrentTraceContext) {\n\t\tList<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();\n\t\tList<String> tagFields = this.tracingProperties.getBaggage().getTagFields();\n\t\treturn new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,\n\t\t\t\tnew OtelBaggageManager(otelCurrentTraceContext, remoteFields, tagFields));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(Propagator.class)\n\tOtelPropagator otelPropagator(ContextPropagators contextPropagators, Tracer tracer) {\n\t\treturn new OtelPropagator(contextPropagators, tracer);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tEventPublisher otelTracerEventPublisher(List<EventListener> eventListeners) {\n\t\treturn new OTelEventPublisher(eventListeners);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tOtelCurrentTraceContext otelCurrentTraceContext() {\n\t\treturn new OtelCurrentTraceContext();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSlf4JEventListener otelSlf4JEventListener() {\n\t\treturn new Slf4JEventListener();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(SpanCustomizer.class)\n\tOtelSpanCustomizer otelSpanCustomizer() {\n\t\treturn new OtelSpanCustomizer();\n\t}\n\n\tstatic class OTelEventPublisher implements EventPublisher {\n\n\t\tprivate final List<EventListener> listeners;\n\n\t\tOTelEventPublisher(List<EventListener> listeners) {\n\t\t\tthis.listeners = listeners;\n\t\t}\n\n\t\t@Override\n\t\tpublic void publishEvent(Object event) {\n\t\t\tfor (EventListener listener : this.listeners) {\n\t\t\t\tlistener.onEvent(event);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryTracingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for tracing with OpenTelemetry.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.opentelemetry.tracing\")\npublic class OpenTelemetryTracingProperties {\n\n\t/**\n\t * Span export configuration.\n\t */\n\tprivate final Export export = new Export();\n\n\t/**\n\t * Span limit configuration.\n\t */\n\tprivate final Limits limits = new Limits();\n\n\t/**\n\t * Sampler to use.\n\t */\n\tprivate Sampler sampler = Sampler.PARENT_BASED_TRACE_ID_RATIO;\n\n\tpublic Export getExport() {\n\t\treturn this.export;\n\t}\n\n\tpublic Limits getLimits() {\n\t\treturn this.limits;\n\t}\n\n\tpublic Sampler getSampler() {\n\t\treturn this.sampler;\n\t}\n\n\tpublic void setSampler(Sampler sampler) {\n\t\tthis.sampler = sampler;\n\t}\n\n\tpublic static class Export {\n\n\t\t/**\n\t\t * Whether unsampled spans should be exported.\n\t\t */\n\t\tprivate boolean includeUnsampled;\n\n\t\t/**\n\t\t * Maximum time an export will be allowed to run before being cancelled.\n\t\t */\n\t\tprivate Duration timeout = Duration.ofSeconds(30);\n\n\t\t/**\n\t\t * Maximum batch size for each export. This must be less than or equal to\n\t\t * 'maxQueueSize'.\n\t\t */\n\t\tprivate int maxBatchSize = 512;\n\n\t\t/**\n\t\t * Maximum number of spans that are kept in the queue before they will be dropped.\n\t\t */\n\t\tprivate int maxQueueSize = 2048;\n\n\t\t/**\n\t\t * The delay interval between two consecutive exports.\n\t\t */\n\t\tprivate Duration scheduleDelay = Duration.ofSeconds(5);\n\n\t\tpublic boolean isIncludeUnsampled() {\n\t\t\treturn this.includeUnsampled;\n\t\t}\n\n\t\tpublic void setIncludeUnsampled(boolean includeUnsampled) {\n\t\t\tthis.includeUnsampled = includeUnsampled;\n\t\t}\n\n\t\tpublic Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\tpublic int getMaxBatchSize() {\n\t\t\treturn this.maxBatchSize;\n\t\t}\n\n\t\tpublic void setMaxBatchSize(int maxBatchSize) {\n\t\t\tthis.maxBatchSize = maxBatchSize;\n\t\t}\n\n\t\tpublic int getMaxQueueSize() {\n\t\t\treturn this.maxQueueSize;\n\t\t}\n\n\t\tpublic void setMaxQueueSize(int maxQueueSize) {\n\t\t\tthis.maxQueueSize = maxQueueSize;\n\t\t}\n\n\t\tpublic Duration getScheduleDelay() {\n\t\t\treturn this.scheduleDelay;\n\t\t}\n\n\t\tpublic void setScheduleDelay(Duration scheduleDelay) {\n\t\t\tthis.scheduleDelay = scheduleDelay;\n\t\t}\n\n\t}\n\n\t/**\n\t * Span limits.\n\t */\n\tpublic static class Limits {\n\n\t\t/**\n\t\t * Maximum number of characters for string attribute values.\n\t\t */\n\t\tprivate int maxAttributeValueLength = Integer.MAX_VALUE;\n\n\t\t/**\n\t\t * Maximum number of attributes per span.\n\t\t */\n\t\tprivate int maxAttributes = 128;\n\n\t\t/**\n\t\t * Maximum number of events per span.\n\t\t */\n\t\tprivate int maxEvents = 128;\n\n\t\t/**\n\t\t * Maximum number of links per span.\n\t\t */\n\t\tprivate int maxLinks = 128;\n\n\t\t/**\n\t\t * Maximum number of attributes per event.\n\t\t */\n\t\tprivate int maxAttributesPerEvent = 128;\n\n\t\t/**\n\t\t * Maximum number of attributes per link.\n\t\t */\n\t\tprivate int maxAttributesPerLink = 128;\n\n\t\tpublic int getMaxAttributeValueLength() {\n\t\t\treturn this.maxAttributeValueLength;\n\t\t}\n\n\t\tpublic void setMaxAttributeValueLength(int maxAttributeValueLength) {\n\t\t\tthis.maxAttributeValueLength = maxAttributeValueLength;\n\t\t}\n\n\t\tpublic int getMaxAttributes() {\n\t\t\treturn this.maxAttributes;\n\t\t}\n\n\t\tpublic void setMaxAttributes(int maxAttributes) {\n\t\t\tthis.maxAttributes = maxAttributes;\n\t\t}\n\n\t\tpublic int getMaxEvents() {\n\t\t\treturn this.maxEvents;\n\t\t}\n\n\t\tpublic void setMaxEvents(int maxEvents) {\n\t\t\tthis.maxEvents = maxEvents;\n\t\t}\n\n\t\tpublic int getMaxLinks() {\n\t\t\treturn this.maxLinks;\n\t\t}\n\n\t\tpublic void setMaxLinks(int maxLinks) {\n\t\t\tthis.maxLinks = maxLinks;\n\t\t}\n\n\t\tpublic int getMaxAttributesPerEvent() {\n\t\t\treturn this.maxAttributesPerEvent;\n\t\t}\n\n\t\tpublic void setMaxAttributesPerEvent(int maxAttributesPerEvent) {\n\t\t\tthis.maxAttributesPerEvent = maxAttributesPerEvent;\n\t\t}\n\n\t\tpublic int getMaxAttributesPerLink() {\n\t\t\treturn this.maxAttributesPerLink;\n\t\t}\n\n\t\tpublic void setMaxAttributesPerLink(int maxAttributesPerLink) {\n\t\t\tthis.maxAttributesPerLink = maxAttributesPerLink;\n\t\t}\n\n\t}\n\n\t/**\n\t * Supported samplers.\n\t */\n\tpublic enum Sampler {\n\n\t\tALWAYS_ON, ALWAYS_OFF, TRACE_ID_RATIO, PARENT_BASED_ALWAYS_ON, PARENT_BASED_ALWAYS_OFF,\n\t\tPARENT_BASED_TRACE_ID_RATIO\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/SdkTracerProviderBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport io.opentelemetry.sdk.trace.SdkTracerProvider;\nimport io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;\n\n/**\n * Callback interface that can be used to customize the {@link SdkTracerProviderBuilder}\n * that is used to create the auto-configured {@link SdkTracerProvider}.\n *\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface SdkTracerProviderBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(SdkTracerProviderBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/SpanExporters.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Spliterator;\n\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\n\nimport org.springframework.util.Assert;\n\n/**\n * A collection of {@link SpanExporter span exporters}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface SpanExporters extends Iterable<SpanExporter> {\n\n\t/**\n\t * Returns the list of {@link SpanExporter span exporters}.\n\t * @return the list of span exporters\n\t */\n\tList<SpanExporter> list();\n\n\t@Override\n\tdefault Iterator<SpanExporter> iterator() {\n\t\treturn list().iterator();\n\t}\n\n\t@Override\n\tdefault Spliterator<SpanExporter> spliterator() {\n\t\treturn list().spliterator();\n\t}\n\n\t/**\n\t * Constructs a {@link SpanExporters} instance with the given {@link SpanExporter span\n\t * exporters}.\n\t * @param spanExporters the span exporters\n\t * @return the constructed {@link SpanExporters} instance\n\t */\n\tstatic SpanExporters of(SpanExporter... spanExporters) {\n\t\treturn of(Arrays.asList(spanExporters));\n\t}\n\n\t/**\n\t * Constructs a {@link SpanExporters} instance with the given list of\n\t * {@link SpanExporter span exporters}.\n\t * @param spanExporters the list of span exporters\n\t * @return the constructed {@link SpanExporters} instance\n\t */\n\tstatic SpanExporters of(Collection<? extends SpanExporter> spanExporters) {\n\t\tAssert.notNull(spanExporters, \"'spanExporters' must not be null\");\n\t\tList<SpanExporter> copy = List.copyOf(spanExporters);\n\t\treturn () -> copy;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/SpanProcessors.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Spliterator;\n\nimport io.opentelemetry.sdk.trace.SpanProcessor;\n\nimport org.springframework.util.Assert;\n\n/**\n * A collection of {@link SpanProcessor span processors}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface SpanProcessors extends Iterable<SpanProcessor> {\n\n\t/**\n\t * Returns the list of {@link SpanProcessor span processors}.\n\t * @return the list of span processors\n\t */\n\tList<SpanProcessor> list();\n\n\t@Override\n\tdefault Iterator<SpanProcessor> iterator() {\n\t\treturn list().iterator();\n\t}\n\n\t@Override\n\tdefault Spliterator<SpanProcessor> spliterator() {\n\t\treturn list().spliterator();\n\t}\n\n\t/**\n\t * Constructs a {@link SpanProcessors} instance with the given {@link SpanProcessor\n\t * span processors}.\n\t * @param spanProcessors the span processors\n\t * @return the constructed {@link SpanProcessors} instance\n\t */\n\tstatic SpanProcessors of(SpanProcessor... spanProcessors) {\n\t\treturn of(Arrays.asList(spanProcessors));\n\t}\n\n\t/**\n\t * Constructs a {@link SpanProcessors} instance with the given list of\n\t * {@link SpanProcessor span processors}.\n\t * @param spanProcessors the list of span processors\n\t * @return the constructed {@link SpanProcessors} instance\n\t */\n\tstatic SpanProcessors of(Collection<? extends SpanProcessor> spanProcessors) {\n\t\tAssert.notNull(spanProcessors, \"'spanProcessors' must not be null\");\n\t\tList<SpanProcessor> copy = List.copyOf(spanProcessors);\n\t\treturn () -> copy;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpGrpcSpanExporterBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link OtlpGrpcSpanExporterBuilder} to fine-tune its auto-configuration.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface OtlpGrpcSpanExporterBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link OtlpGrpcSpanExporterBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(OtlpGrpcSpanExporterBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpHttpSpanExporterBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link OtlpHttpSpanExporterBuilder} to fine-tune its auto-configuration.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface OtlpHttpSpanExporterBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link OtlpHttpSpanExporterBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(OtlpHttpSpanExporterBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpTracingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport io.micrometer.tracing.otel.bridge.OtelTracer;\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;\nimport io.opentelemetry.sdk.trace.SdkTracerProvider;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for exporting traces with OTLP.\n * Brave does not support OTLP, so we only configure it for OpenTelemetry. OTLP defines\n * three transports that are supported: gRPC (/protobuf), HTTP/protobuf, HTTP/JSON. From\n * these transports HTTP/JSON is not supported by the OTel Java SDK, and it seems there\n * are no plans supporting it in the future, see: <a href=\n * \"https://github.com/open-telemetry/opentelemetry-java/issues/3651\">opentelemetry-java#3651</a>.\n * Because this class configures components from the OTel SDK, it can't support HTTP/JSON.\n * By default, we auto-configure HTTP/protobuf. If you want to use gRPC, you need to set\n * {@code management.opentelemetry.tracing.export.otlp.transport=grpc}. If you define a\n * {@link OtlpHttpSpanExporter} or {@link OtlpGrpcSpanExporter}, this auto-configuration\n * will back off.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class, OtlpHttpSpanExporter.class })\n@EnableConfigurationProperties(OtlpTracingProperties.class)\n@Import({ OtlpTracingConfigurations.ConnectionDetails.class, OtlpTracingConfigurations.Exporters.class })\npublic final class OtlpTracingAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpTracingConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport java.util.Locale;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport io.opentelemetry.api.metrics.MeterProvider;\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporterBuilder;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configurations imported by {@link OtlpTracingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Eddú Meléndez\n */\nfinal class OtlpTracingConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetails {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@ConditionalOnProperty(\"management.opentelemetry.tracing.export.otlp.endpoint\")\n\t\tOtlpTracingConnectionDetails otlpTracingConnectionDetails(OtlpTracingProperties properties,\n\t\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\t\treturn new PropertiesOtlpTracingConnectionDetails(properties, sslBundles.getIfAvailable());\n\t\t}\n\n\t\t/**\n\t\t * Adapts {@link OtlpTracingProperties} to {@link OtlpTracingConnectionDetails}.\n\t\t */\n\t\tstatic class PropertiesOtlpTracingConnectionDetails implements OtlpTracingConnectionDetails {\n\n\t\t\tprivate final OtlpTracingProperties properties;\n\n\t\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\t\tPropertiesOtlpTracingConnectionDetails(OtlpTracingProperties properties, @Nullable SslBundles sslBundles) {\n\t\t\t\tthis.properties = properties;\n\t\t\t\tthis.sslBundles = sslBundles;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getUrl(Transport transport) {\n\t\t\t\tAssert.state(transport == this.properties.getTransport(),\n\t\t\t\t\t\t\"Requested transport %s doesn't match configured transport %s\".formatted(transport,\n\t\t\t\t\t\t\t\tthis.properties.getTransport()));\n\t\t\t\tString endpoint = this.properties.getEndpoint();\n\t\t\t\tAssert.state(endpoint != null, \"'endpoint' must not be null\");\n\t\t\t\treturn endpoint;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\t\tString bundleName = this.properties.getSsl().getBundle();\n\t\t\t\tif (StringUtils.hasLength(bundleName)) {\n\t\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\t\treturn this.sslBundles.getBundle(bundleName);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean({ OtlpGrpcSpanExporter.class, OtlpHttpSpanExporter.class })\n\t@ConditionalOnBean(OtlpTracingConnectionDetails.class)\n\t@ConditionalOnEnabledTracingExport(\"otlp\")\n\tstatic class Exporters {\n\n\t\t@Bean\n\t\t@ConditionalOnProperty(name = \"management.opentelemetry.tracing.export.otlp.transport\", havingValue = \"http\",\n\t\t\t\tmatchIfMissing = true)\n\t\tOtlpHttpSpanExporter otlpHttpSpanExporter(OtlpTracingProperties properties,\n\t\t\t\tOtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,\n\t\t\t\tObjectProvider<OtlpHttpSpanExporterBuilderCustomizer> customizers) {\n\t\t\tOtlpHttpSpanExporterBuilder builder = OtlpHttpSpanExporter.builder()\n\t\t\t\t.setEndpoint(connectionDetails.getUrl(Transport.HTTP))\n\t\t\t\t.setTimeout(properties.getTimeout())\n\t\t\t\t.setConnectTimeout(properties.getConnectTimeout())\n\t\t\t\t.setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT));\n\t\t\tproperties.getHeaders().forEach(builder::addHeader);\n\t\t\tmeterProvider.ifAvailable(builder::setMeterProvider);\n\t\t\tconfigureSsl(connectionDetails, builder::setSslContext);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnProperty(name = \"management.opentelemetry.tracing.export.otlp.transport\", havingValue = \"grpc\")\n\t\tOtlpGrpcSpanExporter otlpGrpcSpanExporter(OtlpTracingProperties properties,\n\t\t\t\tOtlpTracingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,\n\t\t\t\tObjectProvider<OtlpGrpcSpanExporterBuilderCustomizer> customizers) {\n\t\t\tOtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder()\n\t\t\t\t.setEndpoint(connectionDetails.getUrl(Transport.GRPC))\n\t\t\t\t.setTimeout(properties.getTimeout())\n\t\t\t\t.setConnectTimeout(properties.getConnectTimeout())\n\t\t\t\t.setCompression(properties.getCompression().name().toLowerCase(Locale.ROOT));\n\t\t\tproperties.getHeaders().forEach(builder::addHeader);\n\t\t\tmeterProvider.ifAvailable(builder::setMeterProvider);\n\t\t\tconfigureSsl(connectionDetails, builder::setSslContext);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder.build();\n\t\t}\n\n\t\tprivate void configureSsl(OtlpTracingConnectionDetails connectionDetails,\n\t\t\t\tSslContextConfigurer sslContextConfigurer) {\n\t\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\t\tif (sslBundle != null) {\n\t\t\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\t\t\tX509TrustManager trustManager = extractTrustManager(sslBundle);\n\t\t\t\tsslContextConfigurer.configure(sslContext, trustManager);\n\t\t\t}\n\t\t}\n\n\t\tprivate X509TrustManager extractTrustManager(SslBundle sslBundle) {\n\t\t\tfor (TrustManager trustManager : sslBundle.getManagers().getTrustManagers()) {\n\t\t\t\tif (trustManager instanceof X509TrustManager x509TrustManager) {\n\t\t\t\t\treturn x509TrustManager;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"No X509TrustManager found in the SSL bundle trust managers\");\n\t\t}\n\n\t\tprivate interface SslContextConfigurer {\n\n\t\t\tvoid configure(SSLContext sslContext, X509TrustManager trustManager);\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpTracingConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to an OpenTelemetry service.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic interface OtlpTracingConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Address to where tracing will be published.\n\t * @param transport the transport to use\n\t * @return the address to where tracing will be published\n\t */\n\tString getUrl(Transport transport);\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use or {@code null}\n\t * @since 4.1.0\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpTracingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for exporting traces using OTLP.\n *\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.opentelemetry.tracing.export.otlp\")\npublic class OtlpTracingProperties {\n\n\t/**\n\t * URL to the OTel collector's HTTP API.\n\t */\n\tprivate @Nullable String endpoint;\n\n\t/**\n\t * Call timeout for the OTel Collector to process an exported batch of data. This\n\t * timeout spans the entire call: resolving DNS, connecting, writing the request body,\n\t * server processing, and reading the response body. If the call requires redirects or\n\t * retries all must complete within one timeout period.\n\t */\n\tprivate Duration timeout = Duration.ofSeconds(10);\n\n\t/**\n\t * Connect timeout for the OTel collector connection.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(10);\n\n\t/**\n\t * Transport used to send the spans.\n\t */\n\tprivate Transport transport = Transport.HTTP;\n\n\t/**\n\t * Method used to compress the payload.\n\t */\n\tprivate Compression compression = Compression.NONE;\n\n\t/**\n\t * Custom HTTP headers you want to pass to the collector, for example auth headers.\n\t */\n\tprivate Map<String, String> headers = new HashMap<>();\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic @Nullable String getEndpoint() {\n\t\treturn this.endpoint;\n\t}\n\n\tpublic void setEndpoint(@Nullable String endpoint) {\n\t\tthis.endpoint = endpoint;\n\t}\n\n\tpublic Duration getTimeout() {\n\t\treturn this.timeout;\n\t}\n\n\tpublic void setTimeout(Duration timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic Transport getTransport() {\n\t\treturn this.transport;\n\t}\n\n\tpublic void setTransport(Transport transport) {\n\t\tthis.transport = transport;\n\t}\n\n\tpublic Compression getCompression() {\n\t\treturn this.compression;\n\t}\n\n\tpublic void setCompression(Compression compression) {\n\t\tthis.compression = compression;\n\t}\n\n\tpublic Map<String, String> getHeaders() {\n\t\treturn this.headers;\n\t}\n\n\tpublic void setHeaders(Map<String, String> headers) {\n\t\tthis.headers = headers;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\tpublic enum Compression {\n\n\t\t/**\n\t\t * Gzip compression.\n\t\t */\n\t\tGZIP,\n\n\t\t/**\n\t\t * No compression.\n\t\t */\n\t\tNONE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/Transport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\n/**\n * Transport used to send OTLP data.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic enum Transport {\n\n\t/**\n\t * HTTP transport.\n\t */\n\tHTTP,\n\n\t/**\n\t * gRPC transport.\n\t */\n\tGRPC\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for exporting traces with OTLP.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Micrometer Tracing with OpenTelemetry.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/zipkin/ZipkinWithOpenTelemetryTracingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.zipkin;\n\nimport io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;\nimport zipkin2.Span;\nimport zipkin2.reporter.BytesEncoder;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.SpanBytesEncoder;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.ConditionalOnEnabledTracingExport;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Zipkin tracing with\n * OpenTelemetry.\n *\n * @author Moritz Halbritter\n * @author Stefan Bratanov\n * @author Wick Dynex\n * @author Phillip Webb\n * @since 4.0.0\n * @deprecated since 4.0.4 for removal in 4.2.0\n */\n@SuppressWarnings(\"deprecation\")\n@AutoConfiguration(afterName = \"org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration\")\n@ConditionalOnClass({ ZipkinSpanExporter.class, Span.class })\n@Deprecated(since = \"4.0.4\", forRemoval = true)\npublic final class ZipkinWithOpenTelemetryTracingAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(Encoding.class)\n\t@ConditionalOnMissingBean(value = Span.class, parameterizedContainer = BytesEncoder.class)\n\tBytesEncoder<Span> spanBytesEncoder(Encoding encoding) {\n\t\treturn SpanBytesEncoder.forEncoding(encoding);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(BytesMessageSender.class)\n\t@ConditionalOnEnabledTracingExport(\"zipkin\")\n\tZipkinSpanExporter zipkinSpanExporter(BytesMessageSender sender, BytesEncoder<Span> spanBytesEncoder) {\n\t\treturn ZipkinSpanExporter.builder().setSender(sender).setEncoder(spanBytesEncoder).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/zipkin/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for tracing with Zipkin.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.zipkin;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/OpenTelemetryTracingDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.docker.compose.otlp;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link OtlpTracingConnectionDetails} for an OTLP service.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass OpenTelemetryTracingDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<OtlpTracingConnectionDetails> {\n\n\tprivate static final String[] OPENTELEMETRY_IMAGE_NAMES = { \"otel/opentelemetry-collector-contrib\",\n\t\t\t\"grafana/otel-lgtm\" };\n\n\tprivate static final int OTLP_GRPC_PORT = 4317;\n\n\tprivate static final int OTLP_HTTP_PORT = 4318;\n\n\tOpenTelemetryTracingDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OPENTELEMETRY_IMAGE_NAMES,\n\t\t\t\t\"org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpTracingConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new OpenTelemetryTracingDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\tprivate static final class OpenTelemetryTracingDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements OtlpTracingConnectionDetails {\n\n\t\tprivate final String host;\n\n\t\tprivate final int grpcPort;\n\n\t\tprivate final int httpPort;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tprivate OpenTelemetryTracingDockerComposeConnectionDetails(RunningService source) {\n\t\t\tsuper(source);\n\t\t\tthis.host = source.host();\n\t\t\tthis.grpcPort = source.ports().get(OTLP_GRPC_PORT);\n\t\t\tthis.httpPort = source.ports().get(OTLP_HTTP_PORT);\n\t\t\tthis.sslBundle = getSslBundle(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl(Transport transport) {\n\t\t\tint port = switch (transport) {\n\t\t\t\tcase HTTP -> this.httpPort;\n\t\t\t\tcase GRPC -> this.grpcPort;\n\t\t\t};\n\t\t\tString scheme = (this.sslBundle != null) ? \"https\" : \"http\";\n\t\t\treturn \"%s://%s:%d/v1/traces\".formatted(scheme, this.host, port);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/docker/compose/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose OpenTelemetry tracing service connections.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.opentelemetry.docker.compose.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/testcontainers/otlp/GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.grafana.LgtmStackContainer;\n\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link OtlpTracingConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using\n * the {@code \"grafana/otel-lgtm\"} image.\n *\n * @author Eddú Meléndez\n */\nclass GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<LgtmStackContainer, OtlpTracingConnectionDetails> {\n\n\tGrafanaOpenTelemetryTracingContainerConnectionDetailsFactory() {\n\t\tsuper(ContainerConnectionDetailsFactory.ANY_CONNECTION_NAME,\n\t\t\t\t\"org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpTracingConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<LgtmStackContainer> source) {\n\t\treturn new OpenTelemetryTracingContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OpenTelemetryTracingContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<LgtmStackContainer> implements OtlpTracingConnectionDetails {\n\n\t\tprivate OpenTelemetryTracingContainerConnectionDetails(ContainerConnectionSource<LgtmStackContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl(Transport transport) {\n\t\t\tString url = switch (transport) {\n\t\t\t\tcase HTTP -> getContainer().getOtlpHttpUrl();\n\t\t\t\tcase GRPC -> getContainer().getOtlpGrpcUrl();\n\t\t\t};\n\t\t\tif (getSslBundle() != null) {\n\t\t\t\turl = url.replaceFirst(\"^http://\", \"https://\");\n\t\t\t}\n\t\t\treturn \"%s/v1/traces\".formatted(url);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/testcontainers/otlp/OpenTelemetryTracingContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConnectionDetails;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link OtlpTracingConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using\n * the {@code \"otel/opentelemetry-collector-contrib\"} image.\n *\n * @author Eddú Meléndez\n */\nclass OpenTelemetryTracingContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, OtlpTracingConnectionDetails> {\n\n\tprivate static final int OTLP_GRPC_PORT = 4317;\n\n\tprivate static final int OTLP_HTTP_PORT = 4318;\n\n\tOpenTelemetryTracingContainerConnectionDetailsFactory() {\n\t\tsuper(\"otel/opentelemetry-collector-contrib\",\n\t\t\t\t\"org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpTracingConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<Container<?>> source) {\n\t\treturn new OpenTelemetryTracingContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OpenTelemetryTracingContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<Container<?>> implements OtlpTracingConnectionDetails {\n\n\t\tprivate OpenTelemetryTracingContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl(Transport transport) {\n\t\t\tint port = switch (transport) {\n\t\t\t\tcase HTTP -> OTLP_HTTP_PORT;\n\t\t\t\tcase GRPC -> OTLP_GRPC_PORT;\n\t\t\t};\n\t\t\tString scheme = (getSslBundle() != null) ? \"https\" : \"http\";\n\t\t\treturn \"%s://%s:%d/v1/traces\".formatted(scheme, getContainer().getHost(),\n\t\t\t\t\tgetContainer().getMappedPort(port));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/java/org/springframework/boot/micrometer/tracing/opentelemetry/testcontainers/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Testcontainers OpenTelemetry tracing service connections.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.otlp.tracing.compression\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.otlp.compression\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.otlp.tracing.connect-timeout\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.otlp.connect-timeout\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.otlp.tracing.endpoint\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.otlp.endpoint\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.otlp.tracing.export.enabled\",\n      \"deprecation\": {\n        \"replacement\": \"management.tracing.export.otlp.enabled\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.otlp.tracing.headers\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.otlp.headers\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.otlp.tracing.timeout\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.otlp.timeout\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.otlp.tracing.transport\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.otlp.transport\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.export.otlp.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"defaultValue\": true,\n      \"description\": \"Whether auto-configuration of tracing is enabled to export OTLP traces.\"\n    },\n    {\n      \"name\": \"management.tracing.opentelemetry.export.include-unsampled\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.include-unsampled\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.opentelemetry.export.max-batch-size\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.max-batch-size\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.opentelemetry.export.max-queue-size\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.max-queue-size\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.opentelemetry.export.schedule-delay\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.schedule-delay\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.tracing.opentelemetry.export.timeout\",\n      \"deprecation\": {\n        \"replacement\": \"management.opentelemetry.tracing.export.timeout\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener",
    "content": "org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryEventPublisherBeansTestExecutionListener\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryTracingAutoConfiguration\norg.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfiguration\norg.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.zipkin.ZipkinWithOpenTelemetryTracingAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.micrometer.tracing.opentelemetry.docker.compose.otlp.OpenTelemetryTracingDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp.GrafanaOpenTelemetryTracingContainerConnectionDetailsFactory,\\\norg.springframework.boot.micrometer.tracing.opentelemetry.testcontainers.otlp.OpenTelemetryTracingContainerConnectionDetailsFactory\n\n# Application Listeners\norg.springframework.context.ApplicationListener=\\\norg.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryEventPublisherBeansApplicationListener\n\n\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/CompositeTextMapPropagatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;\nimport io.opentelemetry.context.Context;\nimport io.opentelemetry.context.ContextKey;\nimport io.opentelemetry.context.propagation.TextMapGetter;\nimport io.opentelemetry.context.propagation.TextMapPropagator;\nimport io.opentelemetry.context.propagation.TextMapSetter;\nimport io.opentelemetry.extension.trace.propagation.B3Propagator;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Propagation;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.TracingProperties.Propagation.PropagationType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompositeTextMapPropagator}.\n *\n * @author Moritz Halbritter\n * @author Scott Frederick\n */\nclass CompositeTextMapPropagatorTests {\n\n\tprivate ContextKeyRegistry contextKeyRegistry;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.contextKeyRegistry = new ContextKeyRegistry();\n\t}\n\n\t@Test\n\tvoid collectsAllFields() {\n\t\tCompositeTextMapPropagator propagator = new CompositeTextMapPropagator(List.of(field(\"a\")), List.of(field(\"b\")),\n\t\t\t\tfield(\"c\"));\n\t\tassertThat(propagator.fields()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\tvoid injectAllFields() {\n\t\tCompositeTextMapPropagator propagator = new CompositeTextMapPropagator(List.of(field(\"a\"), field(\"b\")),\n\t\t\t\tCollections.emptyList(), null);\n\t\tTextMapSetter<Object> setter = setter();\n\t\tObject carrier = carrier();\n\t\tpropagator.inject(context(), carrier, setter);\n\t\tInOrder inOrder = Mockito.inOrder(setter);\n\t\tinOrder.verify(setter).set(carrier, \"a\", \"a-value\");\n\t\tinOrder.verify(setter).set(carrier, \"b\", \"b-value\");\n\t}\n\n\t@Test\n\tvoid extractWithoutBaggagePropagator() {\n\t\tCompositeTextMapPropagator propagator = new CompositeTextMapPropagator(Collections.emptyList(),\n\t\t\t\tList.of(field(\"a\"), field(\"b\")), null);\n\t\tContext context = context();\n\t\tMap<String, String> carrier = Map.of(\"a\", \"a-value\", \"b\", \"b-value\");\n\t\tcontext = propagator.extract(context, carrier, new MapTextMapGetter());\n\t\tObject a = context.get(getObjectContextKey(\"a\"));\n\t\tassertThat(a).isEqualTo(\"a-value\");\n\t\tObject b = context.get(getObjectContextKey(\"b\"));\n\t\tassertThat(b).isNull();\n\t}\n\n\t@Test\n\tvoid extractWithBaggagePropagator() {\n\t\tCompositeTextMapPropagator propagator = new CompositeTextMapPropagator(Collections.emptyList(),\n\t\t\t\tList.of(field(\"a\"), field(\"b\")), field(\"c\"));\n\t\tContext context = context();\n\t\tMap<String, String> carrier = Map.of(\"a\", \"a-value\", \"b\", \"b-value\", \"c\", \"c-value\");\n\t\tcontext = propagator.extract(context, carrier, new MapTextMapGetter());\n\t\tObject c = context.get(getObjectContextKey(\"c\"));\n\t\tassertThat(c).isEqualTo(\"c-value\");\n\t}\n\n\t@Test\n\tvoid createMapsInjectorsAndExtractors() {\n\t\tPropagation properties = new Propagation();\n\t\tproperties.setProduce(List.of(PropagationType.W3C));\n\t\tproperties.setConsume(List.of(PropagationType.B3));\n\t\tCompositeTextMapPropagator propagator = (CompositeTextMapPropagator) CompositeTextMapPropagator\n\t\t\t.create(properties, null);\n\t\tassertThat(propagator.getInjectors()).hasExactlyElementsOfTypes(W3CTraceContextPropagator.class);\n\t\tassertThat(propagator.getExtractors()).hasExactlyElementsOfTypes(B3Propagator.class);\n\t}\n\n\tprivate DummyTextMapPropagator field(String field) {\n\t\treturn new DummyTextMapPropagator(field, this.contextKeyRegistry);\n\t}\n\n\tprivate ContextKey<Object> getObjectContextKey(String name) {\n\t\treturn this.contextKeyRegistry.get(name);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <T> TextMapSetter<T> setter() {\n\t\treturn Mockito.mock(TextMapSetter.class);\n\t}\n\n\tprivate static Object carrier() {\n\t\treturn new Object();\n\t}\n\n\tprivate static Context context() {\n\t\treturn Context.current();\n\t}\n\n\tprivate static final class ContextKeyRegistry {\n\n\t\tprivate final Map<String, ContextKey<Object>> contextKeys = new HashMap<>();\n\n\t\tprivate ContextKey<Object> get(String name) {\n\t\t\treturn this.contextKeys.computeIfAbsent(name, (ignore) -> ContextKey.named(name));\n\t\t}\n\n\t}\n\n\tprivate static final class MapTextMapGetter implements TextMapGetter<Map<String, String>> {\n\n\t\t@Override\n\t\tpublic Iterable<String> keys(Map<String, String> carrier) {\n\t\t\treturn carrier.keySet();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(@Nullable Map<String, String> carrier, String key) {\n\t\t\tif (carrier == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn carrier.get(key);\n\t\t}\n\n\t}\n\n\tprivate static final class DummyTextMapPropagator implements TextMapPropagator {\n\n\t\tprivate final String field;\n\n\t\tprivate final ContextKeyRegistry contextKeyRegistry;\n\n\t\tprivate DummyTextMapPropagator(String field, ContextKeyRegistry contextKeyRegistry) {\n\t\t\tthis.field = field;\n\t\t\tthis.contextKeyRegistry = contextKeyRegistry;\n\t\t}\n\n\t\t@Override\n\t\tpublic Collection<String> fields() {\n\t\t\treturn List.of(this.field);\n\t\t}\n\n\t\t@Override\n\t\tpublic <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> setter) {\n\t\t\tsetter.set(carrier, this.field, this.field + \"-value\");\n\t\t}\n\n\t\t@Override\n\t\tpublic <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {\n\t\t\tString value = getter.get(carrier, this.field);\n\t\t\tif (value != null) {\n\t\t\t\treturn context.with(this.contextKeyRegistry.get(this.field), value);\n\t\t\t}\n\t\t\treturn context;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryBaggagePropagationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.function.Supplier;\n\nimport io.micrometer.tracing.BaggageInScope;\nimport io.micrometer.tracing.BaggageManager;\nimport io.micrometer.tracing.Span;\nimport io.micrometer.tracing.Tracer;\nimport io.opentelemetry.context.Context;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport org.slf4j.MDC;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for Baggage propagation with OpenTelemetry using W3C and B3 propagation formats.\n *\n * @author Marcin Grzejszczak\n * @author Moritz Halbritter\n */\n@ForkedClassPath\nclass OpenTelemetryBaggagePropagationIntegrationTests {\n\n\tprivate static final String COUNTRY_CODE = \"country-code\";\n\n\tprivate static final String BUSINESS_PROCESS = \"bp\";\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid setup() {\n\t\tMDC.clear();\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid shouldSetEntriesToMdcFromSpanWithBaggage(AutoConfig autoConfig) {\n\t\tautoConfig.get().run((context) -> {\n\t\t\tTracer tracer = tracer(context);\n\t\t\tSpan span = createSpan(tracer);\n\t\t\tBaggageManager baggageManager = baggageManager(context);\n\t\t\tassertThatTracingContextIsInitialized(autoConfig);\n\t\t\ttry (Tracer.SpanInScope scope = tracer.withSpan(span.start())) {\n\t\t\t\tassertMdcValue(\"traceId\", span.context().traceId());\n\t\t\t\ttry (BaggageInScope fo = baggageManager.createBaggageInScope(span.context(), COUNTRY_CODE, \"FO\");\n\t\t\t\t\t\tBaggageInScope alm = baggageManager.createBaggageInScope(span.context(), BUSINESS_PROCESS,\n\t\t\t\t\t\t\t\t\"ALM\")) {\n\t\t\t\t\tassertMdcValue(COUNTRY_CODE, \"FO\");\n\t\t\t\t\tassertMdcValue(BUSINESS_PROCESS, \"ALM\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t\tassertThatMdcContainsUnsetTraceId(autoConfig);\n\t\t\tassertUnsetMdc(COUNTRY_CODE);\n\t\t\tassertUnsetMdc(BUSINESS_PROCESS);\n\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid shouldRemoveEntriesFromMdcForNullSpan(AutoConfig autoConfig) {\n\t\tautoConfig.get().run((context) -> {\n\t\t\tTracer tracer = tracer(context);\n\t\t\tSpan span = createSpan(tracer);\n\t\t\tBaggageManager baggageManager = baggageManager(context);\n\t\t\tassertThatTracingContextIsInitialized(autoConfig);\n\t\t\ttry (Tracer.SpanInScope scope = tracer.withSpan(span.start())) {\n\t\t\t\tassertMdcValue(\"traceId\", span.context().traceId());\n\t\t\t\ttry (BaggageInScope fo = baggageManager.createBaggageInScope(span.context(), COUNTRY_CODE, \"FO\")) {\n\t\t\t\t\tassertMdcValue(COUNTRY_CODE, \"FO\");\n\t\t\t\t\ttry (Tracer.SpanInScope scope2 = tracer.withSpan(null)) {\n\t\t\t\t\t\tassertThatMdcContainsUnsetTraceId(autoConfig);\n\t\t\t\t\t\tassertUnsetMdc(COUNTRY_CODE);\n\t\t\t\t\t}\n\t\t\t\t\tassertMdcValue(\"traceId\", span.context().traceId());\n\t\t\t\t\tassertMdcValue(COUNTRY_CODE, \"FO\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tspan.end();\n\t\t\t}\n\t\t\tassertThatMdcContainsUnsetTraceId(autoConfig);\n\t\t\tassertUnsetMdc(COUNTRY_CODE);\n\t\t});\n\t}\n\n\tprivate Span createSpan(Tracer tracer) {\n\t\treturn tracer.nextSpan().name(\"span\");\n\t}\n\n\tprivate Tracer tracer(ApplicationContext context) {\n\t\treturn context.getBean(Tracer.class);\n\t}\n\n\tprivate BaggageManager baggageManager(ApplicationContext context) {\n\t\treturn context.getBean(BaggageManager.class);\n\t}\n\n\tprivate void assertThatTracingContextIsInitialized(AutoConfig autoConfig) {\n\t\tassertThat(Context.current()).isEqualTo(Context.root());\n\t}\n\n\tprivate void assertThatMdcContainsUnsetTraceId(AutoConfig autoConfig) {\n\t\tThrowingConsumer<String> isNull = (traceId) -> assertThat(traceId).isNull();\n\t\tThrowingConsumer<String> isZero = (traceId) -> assertThat(traceId)\n\t\t\t.isEqualTo(\"00000000000000000000000000000000\");\n\t\tassertThat(MDC.get(\"traceId\")).satisfiesAnyOf(isNull, isZero);\n\t}\n\n\tprivate void assertUnsetMdc(String key) {\n\t\tassertThat(MDC.get(key)).as(\"MDC[%s]\", key).isNull();\n\t}\n\n\tprivate void assertMdcValue(String key, String expected) {\n\t\tassertThat(MDC.get(key)).as(\"MDC[%s]\", key).isEqualTo(expected);\n\t}\n\n\tenum AutoConfig implements Supplier<ApplicationContextRunner> {\n\n\t\tOTEL_DEFAULT {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\t\t\t\tOpenTelemetryTracingAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tOTEL_W3C {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\t\t\t\tOpenTelemetryTracingAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.propagation.type=W3C\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tOTEL_B3 {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\t\t\t\tOpenTelemetryTracingAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t},\n\n\t\tOTEL_B3_MULTI {\n\n\t\t\t@Override\n\t\t\tpublic ApplicationContextRunner get() {\n\t\t\t\treturn new ApplicationContextRunner().withInitializer(new OtelApplicationContextInitializer())\n\t\t\t\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\t\t\t\tOpenTelemetryTracingAutoConfiguration.class))\n\t\t\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3_MULTI\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.remote-fields=x-vcap-request-id,country-code,bp\",\n\t\t\t\t\t\t\t\"management.tracing.baggage.correlation.fields=country-code,bp\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class OtelApplicationContextInitializer\n\t\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tapplicationContext.addApplicationListener(new OpenTelemetryEventPublisherBeansApplicationListener());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryEventPublishingContextWrapperBeansTestExecutionListenerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport io.opentelemetry.context.ContextStorage;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\n\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryEventPublisherBeansApplicationListener.Wrapper.Storage;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OpenTelemetryEventPublisherBeansTestExecutionListener}.\n *\n * @author Phillip Webb\n */\n@ForkedClassPath\nclass OpenTelemetryEventPublishingContextWrapperBeansTestExecutionListenerIntegrationTests {\n\n\tprivate final ContextStorage parent = Mockito.mock(ContextStorage.class);\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid wrapperIsInstalled() throws Exception {\n\t\tClass<?> wrappersClass = Class.forName(\"io.opentelemetry.context.ContextStorageWrappers\");\n\t\tMethod getWrappersMethod = wrappersClass.getDeclaredMethod(\"getWrappers\");\n\t\tgetWrappersMethod.setAccessible(true);\n\t\tList<Function> wrappers = (List<Function>) getWrappersMethod.invoke(null);\n\t\tassertThat(wrappers).anyMatch((function) -> function.apply(this.parent) instanceof Storage);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryTracingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.Supplier;\n\nimport io.micrometer.tracing.SpanCustomizer;\nimport io.micrometer.tracing.Tracer.SpanInScope;\nimport io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;\nimport io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;\nimport io.micrometer.tracing.otel.bridge.EventListener;\nimport io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;\nimport io.micrometer.tracing.otel.bridge.OtelPropagator;\nimport io.micrometer.tracing.otel.bridge.OtelSpanCustomizer;\nimport io.micrometer.tracing.otel.bridge.OtelTracer;\nimport io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;\nimport io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;\nimport io.micrometer.tracing.otel.bridge.Slf4JEventListener;\nimport io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;\nimport io.micrometer.tracing.propagation.Propagator;\nimport io.opentelemetry.api.common.AttributeKey;\nimport io.opentelemetry.api.common.Attributes;\nimport io.opentelemetry.api.metrics.MeterProvider;\nimport io.opentelemetry.api.trace.Span;\nimport io.opentelemetry.api.trace.Tracer;\nimport io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;\nimport io.opentelemetry.context.propagation.ContextPropagators;\nimport io.opentelemetry.context.propagation.TextMapPropagator;\nimport io.opentelemetry.extension.trace.propagation.B3Propagator;\nimport io.opentelemetry.sdk.common.CompletableResultCode;\nimport io.opentelemetry.sdk.resources.Resource;\nimport io.opentelemetry.sdk.trace.SdkTracerProvider;\nimport io.opentelemetry.sdk.trace.SpanLimits;\nimport io.opentelemetry.sdk.trace.SpanProcessor;\nimport io.opentelemetry.sdk.trace.data.SpanData;\nimport io.opentelemetry.sdk.trace.export.BatchSpanProcessor;\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport io.opentelemetry.sdk.trace.samplers.Sampler;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.brave.autoconfigure.BraveAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OpenTelemetryTracingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Yanming Zhou\n */\nclass OpenTelemetryTracingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\tOpenTelemetryTracingAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OtelTracer.class);\n\t\t\tassertThat(context).hasSingleBean(EventPublisher.class);\n\t\t\tassertThat(context).hasSingleBean(OtelCurrentTraceContext.class);\n\t\t\tassertThat(context).hasSingleBean(SdkTracerProvider.class);\n\t\t\tassertThat(context).hasSingleBean(ContextPropagators.class);\n\t\t\tassertThat(context).hasSingleBean(Sampler.class);\n\t\t\tassertThat(context).hasSingleBean(Tracer.class);\n\t\t\tassertThat(context).hasSingleBean(Slf4JEventListener.class);\n\t\t\tassertThat(context).hasSingleBean(Slf4JBaggageEventListener.class);\n\t\t\tassertThat(context).hasSingleBean(SpanProcessor.class);\n\t\t\tassertThat(context).hasSingleBean(OtelPropagator.class);\n\t\t\tassertThat(context).hasSingleBean(TextMapPropagator.class);\n\t\t\tassertThat(context).hasSingleBean(OtelSpanCustomizer.class);\n\t\t\tassertThat(context).hasSingleBean(SpanProcessors.class);\n\t\t\tassertThat(context).hasSingleBean(SpanExporters.class);\n\t\t\tassertThat(context).hasSingleBean(SpanLimits.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid samplerIsParentBasedTraceIdRatioByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\tassertThat(sampler.getDescription()).startsWith(\"ParentBased{root:TraceIdRatioBased{\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid samplerUsesCustomProbability() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.sampling.probability=0.5\").run((context) -> {\n\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\tassertThat(sampler.getDescription()).contains(\"0.5\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid samplerCanBeSetToAlwaysOn() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.tracing.sampler=always-on\").run((context) -> {\n\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\tassertThat(sampler.getDescription()).isEqualTo(\"AlwaysOnSampler\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid samplerCanBeSetToAlwaysOff() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.tracing.sampler=always-off\").run((context) -> {\n\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\tassertThat(sampler.getDescription()).isEqualTo(\"AlwaysOffSampler\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid samplerCanBeSetToTraceIdRatio() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.sampler=trace-id-ratio\",\n\t\t\t\t\t\"management.tracing.sampling.probability=0.3\")\n\t\t\t.run((context) -> {\n\t\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\t\tassertThat(sampler.getDescription()).startsWith(\"TraceIdRatioBased{\").contains(\"0.3\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid samplerCanBeSetToParentBasedAlwaysOn() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.tracing.sampler=parent-based-always-on\")\n\t\t\t.run((context) -> {\n\t\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\t\tassertThat(sampler.getDescription()).startsWith(\"ParentBased{root:AlwaysOnSampler\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid samplerCanBeSetToParentBasedAlwaysOff() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.tracing.sampler=parent-based-always-off\")\n\t\t\t.run((context) -> {\n\t\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\t\tassertThat(sampler.getDescription()).startsWith(\"ParentBased{root:AlwaysOffSampler\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid samplerCanBeSetToParentBasedTraceIdRatio() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.sampler=parent-based-trace-id-ratio\",\n\t\t\t\t\t\"management.tracing.sampling.probability=0.7\")\n\t\t\t.run((context) -> {\n\t\t\t\tSampler sampler = context.getBean(Sampler.class);\n\t\t\t\tassertThat(sampler.getDescription()).startsWith(\"ParentBased{root:TraceIdRatioBased{\").contains(\"0.7\");\n\t\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"io.micrometer.tracing.otel\", \"io.opentelemetry.sdk\", \"io.opentelemetry.api\" })\n\tvoid shouldNotSupplyBeansIfDependencyIsMissing(String packageName) {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(OtelTracer.class);\n\t\t\tassertThat(context).doesNotHaveBean(EventPublisher.class);\n\t\t\tassertThat(context).doesNotHaveBean(OtelCurrentTraceContext.class);\n\t\t\tassertThat(context).doesNotHaveBean(SdkTracerProvider.class);\n\t\t\tassertThat(context).doesNotHaveBean(ContextPropagators.class);\n\t\t\tassertThat(context).doesNotHaveBean(Sampler.class);\n\t\t\tassertThat(context).doesNotHaveBean(Tracer.class);\n\t\t\tassertThat(context).doesNotHaveBean(Slf4JEventListener.class);\n\t\t\tassertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanProcessor.class);\n\t\t\tassertThat(context).doesNotHaveBean(OtelPropagator.class);\n\t\t\tassertThat(context).doesNotHaveBean(TextMapPropagator.class);\n\t\t\tassertThat(context).doesNotHaveBean(OtelSpanCustomizer.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanProcessors.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanExporters.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customMicrometerTracer\");\n\t\t\tassertThat(context).hasSingleBean(io.micrometer.tracing.Tracer.class);\n\t\t\tassertThat(context).hasBean(\"customEventPublisher\");\n\t\t\tassertThat(context).hasSingleBean(EventPublisher.class);\n\t\t\tassertThat(context).hasBean(\"customOtelCurrentTraceContext\");\n\t\t\tassertThat(context).hasSingleBean(OtelCurrentTraceContext.class);\n\t\t\tassertThat(context).hasBean(\"customSdkTracerProvider\");\n\t\t\tassertThat(context).hasSingleBean(SdkTracerProvider.class);\n\t\t\tassertThat(context).hasBean(\"customContextPropagators\");\n\t\t\tassertThat(context).hasSingleBean(ContextPropagators.class);\n\t\t\tassertThat(context).hasBean(\"customSampler\");\n\t\t\tassertThat(context).hasSingleBean(Sampler.class);\n\t\t\tassertThat(context).hasBean(\"customTracer\");\n\t\t\tassertThat(context).hasSingleBean(Tracer.class);\n\t\t\tassertThat(context).hasBean(\"customSlf4jEventListener\");\n\t\t\tassertThat(context).hasSingleBean(Slf4JEventListener.class);\n\t\t\tassertThat(context).hasBean(\"customSlf4jBaggageEventListener\");\n\t\t\tassertThat(context).hasSingleBean(Slf4JBaggageEventListener.class);\n\t\t\tassertThat(context).hasBean(\"customOtelPropagator\");\n\t\t\tassertThat(context).hasSingleBean(OtelPropagator.class);\n\t\t\tassertThat(context).hasBean(\"customSpanCustomizer\");\n\t\t\tassertThat(context).hasSingleBean(SpanCustomizer.class);\n\t\t\tassertThat(context).hasBean(\"customSpanProcessors\");\n\t\t\tassertThat(context).hasSingleBean(SpanProcessors.class);\n\t\t\tassertThat(context).hasBean(\"customSpanExporters\");\n\t\t\tassertThat(context).hasSingleBean(SpanExporters.class);\n\t\t\tassertThat(context).hasBean(\"customBatchSpanProcessor\");\n\t\t\tassertThat(context).hasSingleBean(BatchSpanProcessor.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyOtelPropagatorWhenPropagatorBeanIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(PropagatorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Propagator.class);\n\t\t\tassertThat(context).hasBean(\"customPropagator\");\n\t\t\tassertThat(context).doesNotHaveBean(OtelPropagator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldWorkWithBraveAutoConfigurationWhenBothConfigurationsAreOnClasspath() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\t\tOpenTelemetryTracingAutoConfiguration.class, BraveAutoConfiguration.class,\n\t\t\t\t\tObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(io.micrometer.tracing.Tracer.class);\n\t\t\t\tassertThat(context).hasSingleBean(Propagator.class);\n\t\t\t\tassertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);\n\t\t\t\tassertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSetupDefaultResourceAttributes() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(ObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class))\n\t\t\t.withUserConfiguration(InMemoryRecordingSpanExporterConfiguration.class)\n\t\t\t.withPropertyValues(\"management.tracing.sampling.probability=1.0\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(io.micrometer.tracing.Tracer.class).nextSpan().name(\"test\").end();\n\t\t\t\tInMemoryRecordingSpanExporter exporter = context.getBean(InMemoryRecordingSpanExporter.class);\n\t\t\t\texporter.await(Duration.ofSeconds(10));\n\t\t\t\tSpanData spanData = exporter.getExportedSpans().get(0);\n\t\t\t\tMap<AttributeKey<?>, Object> expectedAttributes = Resource.getDefault()\n\t\t\t\t\t.merge(Resource.create(Attributes.of(AttributeKey.stringKey(\"service.name\"), \"unknown_service\")))\n\t\t\t\t\t.getAttributes()\n\t\t\t\t\t.asMap();\n\t\t\t\tassertThat(spanData.getResource().getAttributes().asMap()).isEqualTo(expectedAttributes);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldAllowMultipleSpanProcessors() {\n\t\tthis.contextRunner.withUserConfiguration(AdditionalSpanProcessorConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(SpanProcessor.class)).hasSize(2);\n\t\t\tassertThat(context).hasBean(\"customSpanProcessor\");\n\t\t\tSpanProcessors spanProcessors = context.getBean(SpanProcessors.class);\n\t\t\tassertThat(spanProcessors).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldAllowMultipleSpanExporters() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleSpanExporterConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(SpanExporter.class)).hasSize(2);\n\t\t\tassertThat(context).hasBean(\"spanExporter1\");\n\t\t\tassertThat(context).hasBean(\"spanExporter2\");\n\t\t\tSpanExporters spanExporters = context.getBean(SpanExporters.class);\n\t\t\tassertThat(spanExporters).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldAllowMultipleTextMapPropagators() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(TextMapPropagator.class)).hasSize(2);\n\t\t\tassertThat(context).hasBean(\"customTextMapPropagator\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySlf4jBaggageEventListenerWhenBaggageCorrelationDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.correlation.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplySlf4JBaggageEventListenerWhenBaggageDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyB3PropagationIfPropagationPropertySet() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.propagation.type=B3\").run((context) -> {\n\t\t\tTextMapPropagator propagator = context.getBean(TextMapPropagator.class);\n\t\t\tList<TextMapPropagator> injectors = getInjectors(propagator);\n\t\t\tassertThat(injectors).hasExactlyElementsOfTypes(B3Propagator.class, BaggageTextMapPropagator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyB3PropagationIfPropagationPropertySetAndBaggageDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.propagation.type=B3\", \"management.tracing.baggage.enabled=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tTextMapPropagator propagator = context.getBean(TextMapPropagator.class);\n\t\t\t\tList<TextMapPropagator> injectors = getInjectors(propagator);\n\t\t\t\tassertThat(injectors).hasExactlyElementsOfTypes(B3Propagator.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyW3CPropagationWithBaggageByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.remote-fields=foo\").run((context) -> {\n\t\t\tTextMapPropagator propagator = context.getBean(TextMapPropagator.class);\n\t\t\tList<TextMapPropagator> injectors = getInjectors(propagator);\n\t\t\tList<String> fields = new ArrayList<>();\n\t\t\tfor (TextMapPropagator injector : injectors) {\n\t\t\t\tfields.addAll(injector.fields());\n\t\t\t}\n\t\t\tassertThat(fields).containsExactly(\"traceparent\", \"tracestate\", \"baggage\", \"foo\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyW3CPropagationWithoutBaggageWhenDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.baggage.enabled=false\").run((context) -> {\n\t\t\tTextMapPropagator propagator = context.getBean(TextMapPropagator.class);\n\t\t\tList<TextMapPropagator> injectors = getInjectors(propagator);\n\t\t\tassertThat(injectors).hasExactlyElementsOfTypes(W3CTraceContextPropagator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureRemoteAndTaggedFields() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.tracing.baggage.remote-fields=r1\",\n\t\t\t\t\t\"management.tracing.baggage.tag-fields=t1\")\n\t\t\t.run((context) -> {\n\t\t\t\tCompositeTextMapPropagator propagator = context.getBean(CompositeTextMapPropagator.class);\n\t\t\t\tassertThat(propagator).extracting(\"baggagePropagator.baggageManager.remoteFields\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(String.class))\n\t\t\t\t\t.containsExactly(\"r1\");\n\t\t\t\tassertThat(propagator).extracting(\"baggagePropagator.baggageManager.tagFields\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(String.class))\n\t\t\t\t\t.containsExactly(\"t1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid spanLimitsShouldBeConfiguredWithCustomProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.limits.max-attribute-value-length=256\",\n\t\t\t\t\t\"management.opentelemetry.tracing.limits.max-attributes=64\",\n\t\t\t\t\t\"management.opentelemetry.tracing.limits.max-events=32\",\n\t\t\t\t\t\"management.opentelemetry.tracing.limits.max-links=16\",\n\t\t\t\t\t\"management.opentelemetry.tracing.limits.max-attributes-per-event=8\",\n\t\t\t\t\t\"management.opentelemetry.tracing.limits.max-attributes-per-link=4\")\n\t\t\t.run((context) -> {\n\t\t\t\tSpanLimits spanLimits = context.getBean(SpanLimits.class);\n\t\t\t\tassertThat(spanLimits.getMaxAttributeValueLength()).isEqualTo(256);\n\t\t\t\tassertThat(spanLimits.getMaxNumberOfAttributes()).isEqualTo(64);\n\t\t\t\tassertThat(spanLimits.getMaxNumberOfEvents()).isEqualTo(32);\n\t\t\t\tassertThat(spanLimits.getMaxNumberOfLinks()).isEqualTo(16);\n\t\t\t\tassertThat(spanLimits.getMaxNumberOfAttributesPerEvent()).isEqualTo(8);\n\t\t\t\tassertThat(spanLimits.getMaxNumberOfAttributesPerLink()).isEqualTo(4);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomSpanLimitsBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomSpanLimitsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpanLimits.class);\n\t\t\tassertThat(context).hasBean(\"customSpanLimits\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeSdkTracerProvider() {\n\t\tthis.contextRunner.withUserConfiguration(SdkTracerProviderCustomizationConfiguration.class).run((context) -> {\n\t\t\tSdkTracerProvider tracerProvider = context.getBean(SdkTracerProvider.class);\n\t\t\tassertThat(tracerProvider.getSpanLimits().getMaxNumberOfEvents()).isEqualTo(42);\n\t\t\tassertThat(tracerProvider.getSampler()).isEqualTo(Sampler.alwaysOn());\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid defaultSpanProcessorShouldUseMeterProviderIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(MeterProviderConfiguration.class).run((context) -> {\n\t\t\tMeterProvider meterProvider = context.getBean(MeterProvider.class);\n\t\t\tSpanProcessor spanProcessor = context.getBean(SpanProcessor.class);\n\t\t\tassertThat(spanProcessor).extracting(\"worker.spanProcessorInstrumentation.meterProvider\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t.extracting(Supplier::get)\n\t\t\t\t.isEqualTo(meterProvider);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldDisablePropagationIfTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TextMapPropagator.class);\n\t\t\tTextMapPropagator propagator = context.getBean(TextMapPropagator.class);\n\t\t\tassertThat(propagator.fields()).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid batchSpanProcessorShouldBeConfiguredWithCustomProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.timeout=45s\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.include-unsampled=true\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.max-batch-size=256\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.max-queue-size=4096\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.schedule-delay=15s\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(BatchSpanProcessor.class);\n\t\t\t\tBatchSpanProcessor batchSpanProcessor = context.getBean(BatchSpanProcessor.class);\n\t\t\t\tassertThat(batchSpanProcessor).hasFieldOrPropertyWithValue(\"exportUnsampledSpans\", true)\n\t\t\t\t\t.extracting(\"worker\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"exporterTimeoutNanos\", Duration.ofSeconds(45).toNanos())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"maxExportBatchSize\", 256)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"scheduleDelayNanos\", Duration.ofSeconds(15).toNanos())\n\t\t\t\t\t.extracting(\"queue\")\n\t\t\t\t\t.satisfies((queue) -> assertThat(ReflectionTestUtils.<Integer>invokeMethod(queue, \"capacity\"))\n\t\t\t\t\t\t.isEqualTo(4096));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid batchSpanProcessorShouldBeConfiguredWithDefaultProperties() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchSpanProcessor.class);\n\t\t\tBatchSpanProcessor batchSpanProcessor = context.getBean(BatchSpanProcessor.class);\n\t\t\tassertThat(batchSpanProcessor).hasFieldOrPropertyWithValue(\"exportUnsampledSpans\", false)\n\t\t\t\t.extracting(\"worker\")\n\t\t\t\t.hasFieldOrPropertyWithValue(\"exporterTimeoutNanos\", Duration.ofSeconds(30).toNanos())\n\t\t\t\t.hasFieldOrPropertyWithValue(\"maxExportBatchSize\", 512)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"scheduleDelayNanos\", Duration.ofSeconds(5).toNanos())\n\t\t\t\t.extracting(\"queue\")\n\t\t\t\t.satisfies((queue) -> assertThat(ReflectionTestUtils.<Integer>invokeMethod(queue, \"capacity\"))\n\t\t\t\t\t.isEqualTo(2048));\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledDoesNotProvideTracingSignalBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(SdkTracerProvider.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanLimits.class);\n\t\t\tassertThat(context).doesNotHaveBean(Sampler.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanProcessors.class);\n\t\t\tassertThat(context).doesNotHaveBean(SpanExporters.class);\n\t\t\tassertThat(context).doesNotHaveBean(BatchSpanProcessor.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledStillProvidesBridgeAndPropagationBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OtelTracer.class);\n\t\t\tassertThat(context).hasSingleBean(OtelPropagator.class);\n\t\t\tassertThat(context).hasSingleBean(OtelCurrentTraceContext.class);\n\t\t\tassertThat(context).hasSingleBean(Slf4JEventListener.class);\n\t\t\tassertThat(context).hasSingleBean(OtelSpanCustomizer.class);\n\t\t\tassertThat(context).hasSingleBean(ContextPropagators.class);\n\t\t\tassertThat(context).hasSingleBean(TextMapPropagator.class);\n\t\t});\n\t}\n\n\t@Test // gh-41439\n\t@ForkedClassPath\n\tvoid shouldPublishEventsWhenContextStorageIsInitializedEarly() {\n\t\tthis.contextRunner.withInitializer(this::initializeOpenTelemetry)\n\t\t\t.withUserConfiguration(OtelEventListener.class)\n\t\t\t.run((context) -> {\n\t\t\t\tOtelEventListener listener = context.getBean(OtelEventListener.class);\n\t\t\t\tio.micrometer.tracing.Tracer micrometerTracer = context.getBean(io.micrometer.tracing.Tracer.class);\n\t\t\t\tio.micrometer.tracing.Span span = micrometerTracer.nextSpan().name(\"test\");\n\t\t\t\ttry (SpanInScope scoped = micrometerTracer.withSpan(span.start())) {\n\t\t\t\t\tassertThat(listener.events).isNotEmpty();\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tspan.end();\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate void initializeOpenTelemetry(ConfigurableApplicationContext context) {\n\t\tcontext.addApplicationListener(new OpenTelemetryEventPublisherBeansApplicationListener());\n\t\tSpan.current();\n\t}\n\n\tprivate List<TextMapPropagator> getInjectors(TextMapPropagator propagator) {\n\t\tassertThat(propagator).as(\"propagator\").isNotNull();\n\t\tif (propagator instanceof CompositeTextMapPropagator compositePropagator) {\n\t\t\treturn compositePropagator.getInjectors().stream().toList();\n\t\t}\n\t\tfail(\"Expected CompositeTextMapPropagator, found %s\".formatted(propagator.getClass()));\n\t\tthrow new AssertionError(\"Unreachable\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class MeterProviderConfiguration {\n\n\t\t@Bean\n\t\tMeterProvider meterProvider() {\n\t\t\tMeterProvider mock = mock(MeterProvider.class);\n\t\t\tgiven(mock.meterBuilder(anyString()))\n\t\t\t\t.willAnswer((invocation) -> MeterProvider.noop().meterBuilder(invocation.getArgument(0, String.class)));\n\t\t\treturn mock;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class AdditionalSpanProcessorConfiguration {\n\n\t\t@Bean\n\t\tSpanProcessor customSpanProcessor() {\n\t\t\treturn mock(SpanProcessor.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class MultipleSpanExporterConfiguration {\n\n\t\t@Bean\n\t\tSpanExporter spanExporter1() {\n\t\t\treturn new DummySpanExporter();\n\t\t}\n\n\t\t@Bean\n\t\tSpanExporter spanExporter2() {\n\t\t\treturn new DummySpanExporter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\t@Bean\n\t\tBatchSpanProcessor customBatchSpanProcessor() {\n\t\t\treturn mock(BatchSpanProcessor.class);\n\t\t}\n\n\t\t@Bean\n\t\tSpanProcessors customSpanProcessors() {\n\t\t\treturn SpanProcessors.of(mock(SpanProcessor.class));\n\t\t}\n\n\t\t@Bean\n\t\tSpanExporters customSpanExporters() {\n\t\t\treturn SpanExporters.of(new DummySpanExporter());\n\t\t}\n\n\t\t@Bean\n\t\tio.micrometer.tracing.Tracer customMicrometerTracer() {\n\t\t\treturn mock(io.micrometer.tracing.Tracer.class);\n\t\t}\n\n\t\t@Bean\n\t\tEventPublisher customEventPublisher() {\n\t\t\treturn mock(EventPublisher.class);\n\t\t}\n\n\t\t@Bean\n\t\tOtelCurrentTraceContext customOtelCurrentTraceContext() {\n\t\t\treturn mock(OtelCurrentTraceContext.class);\n\t\t}\n\n\t\t@Bean\n\t\tSdkTracerProvider customSdkTracerProvider() {\n\t\t\treturn SdkTracerProvider.builder().build();\n\t\t}\n\n\t\t@Bean\n\t\tContextPropagators customContextPropagators() {\n\t\t\treturn mock(ContextPropagators.class);\n\t\t}\n\n\t\t@Bean\n\t\tSampler customSampler() {\n\t\t\treturn mock(Sampler.class);\n\t\t}\n\n\t\t@Bean\n\t\tSpanProcessor customSpanProcessor() {\n\t\t\treturn mock(SpanProcessor.class);\n\t\t}\n\n\t\t@Bean\n\t\tTracer customTracer() {\n\t\t\treturn mock(Tracer.class);\n\t\t}\n\n\t\t@Bean\n\t\tSlf4JEventListener customSlf4jEventListener() {\n\t\t\treturn new Slf4JEventListener();\n\t\t}\n\n\t\t@Bean\n\t\tSlf4JBaggageEventListener customSlf4jBaggageEventListener() {\n\t\t\treturn new Slf4JBaggageEventListener(List.of(\"alpha\"));\n\t\t}\n\n\t\t@Bean\n\t\tOtelPropagator customOtelPropagator(ContextPropagators propagators, Tracer tracer) {\n\t\t\treturn new OtelPropagator(propagators, tracer);\n\t\t}\n\n\t\t@Bean\n\t\tTextMapPropagator customTextMapPropagator() {\n\t\t\treturn mock(TextMapPropagator.class);\n\t\t}\n\n\t\t@Bean\n\t\tSpanCustomizer customSpanCustomizer() {\n\t\t\treturn mock(SpanCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PropagatorConfiguration {\n\n\t\t@Bean\n\t\tPropagator customPropagator() {\n\t\t\treturn mock(Propagator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomSpanLimitsConfiguration {\n\n\t\t@Bean\n\t\tSpanLimits customSpanLimits() {\n\t\t\treturn SpanLimits.builder().setMaxNumberOfEvents(99).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class SdkTracerProviderCustomizationConfiguration {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSdkTracerProviderBuilderCustomizer sdkTracerProviderBuilderCustomizerOne() {\n\t\t\treturn (builder) -> {\n\t\t\t\tSpanLimits spanLimits = SpanLimits.builder().setMaxNumberOfEvents(42).build();\n\t\t\t\tbuilder.setSpanLimits(spanLimits);\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tSdkTracerProviderBuilderCustomizer sdkTracerProviderBuilderCustomizerTwo() {\n\t\t\treturn (builder) -> {\n\t\t\t\tSpanLimits spanLimits = SpanLimits.builder().setMaxNumberOfEvents(21).build();\n\t\t\t\tbuilder.setSpanLimits(spanLimits).setSampler(Sampler.alwaysOn());\n\t\t\t};\n\t\t}\n\n\t}\n\n\tprivate static final class DummySpanExporter implements SpanExporter {\n\n\t\t@Override\n\t\tpublic CompletableResultCode export(Collection<SpanData> spans) {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\t@Override\n\t\tpublic CompletableResultCode flush() {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\t@Override\n\t\tpublic CompletableResultCode shutdown() {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class InMemoryRecordingSpanExporterConfiguration {\n\n\t\t@Bean\n\t\tInMemoryRecordingSpanExporter spanExporter() {\n\t\t\treturn new InMemoryRecordingSpanExporter();\n\t\t}\n\n\t}\n\n\tprivate static final class InMemoryRecordingSpanExporter implements SpanExporter {\n\n\t\tprivate final List<SpanData> exportedSpans = new ArrayList<>();\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\t@Override\n\t\tpublic CompletableResultCode export(Collection<SpanData> spans) {\n\t\t\tthis.exportedSpans.addAll(spans);\n\t\t\tthis.latch.countDown();\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\t@Override\n\t\tpublic CompletableResultCode flush() {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\t@Override\n\t\tpublic CompletableResultCode shutdown() {\n\t\t\tthis.exportedSpans.clear();\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\tList<SpanData> getExportedSpans() {\n\t\t\treturn this.exportedSpans;\n\t\t}\n\n\t\tvoid await(Duration timeout) throws InterruptedException, TimeoutException {\n\t\t\tif (!this.latch.await(timeout.toMillis(), TimeUnit.MILLISECONDS)) {\n\t\t\t\tthrow new TimeoutException(\"Waiting for exporting spans timed out (%s)\".formatted(timeout));\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class OtelEventListener implements EventListener {\n\n\t\tprivate final List<Object> events = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic void onEvent(Object event) {\n\t\t\tthis.events.add(event);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/OpenTelemetryTracingPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport io.opentelemetry.sdk.trace.SpanLimits;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OpenTelemetryTracingProperties}.\n *\n * @author Moritz Halbritter\n */\nclass OpenTelemetryTracingPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tOpenTelemetryTracingProperties.Limits limits = new OpenTelemetryTracingProperties.Limits();\n\t\tSpanLimits defaults = SpanLimits.getDefault();\n\t\tassertThat(limits.getMaxAttributeValueLength()).isEqualTo(defaults.getMaxAttributeValueLength());\n\t\tassertThat(limits.getMaxAttributes()).isEqualTo(defaults.getMaxNumberOfAttributes());\n\t\tassertThat(limits.getMaxEvents()).isEqualTo(defaults.getMaxNumberOfEvents());\n\t\tassertThat(limits.getMaxLinks()).isEqualTo(defaults.getMaxNumberOfLinks());\n\t\tassertThat(limits.getMaxAttributesPerEvent()).isEqualTo(defaults.getMaxNumberOfAttributesPerEvent());\n\t\tassertThat(limits.getMaxAttributesPerLink()).isEqualTo(defaults.getMaxNumberOfAttributesPerLink());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/SpanExportersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.List;\n\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpanExporters}.\n *\n * @author Moritz Halbritter\n */\nclass SpanExportersTests {\n\n\t@Test\n\tvoid ofList() {\n\t\tSpanExporter spanExporter1 = mock(SpanExporter.class);\n\t\tSpanExporter spanExporter2 = mock(SpanExporter.class);\n\t\tSpanExporters spanExporters = SpanExporters.of(List.of(spanExporter1, spanExporter2));\n\t\tassertThat(spanExporters).containsExactly(spanExporter1, spanExporter2);\n\t\tassertThat(spanExporters.list()).containsExactly(spanExporter1, spanExporter2);\n\t}\n\n\t@Test\n\tvoid ofArray() {\n\t\tSpanExporter spanExporter1 = mock(SpanExporter.class);\n\t\tSpanExporter spanExporter2 = mock(SpanExporter.class);\n\t\tSpanExporters spanExporters = SpanExporters.of(spanExporter1, spanExporter2);\n\t\tassertThat(spanExporters).containsExactly(spanExporter1, spanExporter2);\n\t\tassertThat(spanExporters.list()).containsExactly(spanExporter1, spanExporter2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/SpanProcessorsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure;\n\nimport java.util.List;\n\nimport io.opentelemetry.sdk.trace.SpanProcessor;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SpanProcessors}.\n *\n * @author Moritz Halbritter\n */\nclass SpanProcessorsTests {\n\n\t@Test\n\tvoid ofList() {\n\t\tSpanProcessor spanProcessor1 = mock(SpanProcessor.class);\n\t\tSpanProcessor spanProcessor2 = mock(SpanProcessor.class);\n\t\tSpanProcessors spanProcessors = SpanProcessors.of(List.of(spanProcessor1, spanProcessor2));\n\t\tassertThat(spanProcessors).containsExactly(spanProcessor1, spanProcessor2);\n\t\tassertThat(spanProcessors.list()).containsExactly(spanProcessor1, spanProcessor2);\n\t}\n\n\t@Test\n\tvoid ofArray() {\n\t\tSpanProcessor spanProcessor1 = mock(SpanProcessor.class);\n\t\tSpanProcessor spanProcessor2 = mock(SpanProcessor.class);\n\t\tSpanProcessors spanProcessors = SpanProcessors.of(spanProcessor1, spanProcessor2);\n\t\tassertThat(spanProcessors).containsExactly(spanProcessor1, spanProcessor2);\n\t\tassertThat(spanProcessors.list()).containsExactly(spanProcessor1, spanProcessor2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpTracingAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport io.micrometer.tracing.Tracer;\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;\nimport io.opentelemetry.sdk.common.CompletableResultCode;\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport okio.Buffer;\nimport okio.GzipSource;\nimport org.eclipse.jetty.http.HttpFields;\nimport org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;\nimport org.eclipse.jetty.io.Content;\nimport org.eclipse.jetty.server.Handler;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.Request;\nimport org.eclipse.jetty.server.Response;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\nimport org.eclipse.jetty.util.Callback;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.OpenTelemetryTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingAutoConfigurationIntegrationTests.MockGrpcServer.RecordedGrpcRequest;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OtlpTracingAutoConfiguration}.\n *\n * @author Jonatan Ivanov\n */\nclass OtlpTracingAutoConfigurationIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"management.tracing.sampling.probability=1.0\")\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,\n\t\t\t\tMicrometerTracingAutoConfiguration.class, OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\tOpenTelemetryTracingAutoConfiguration.class, OtlpTracingAutoConfiguration.class));\n\n\tprivate final MockWebServer mockWebServer = new MockWebServer();\n\n\tprivate final MockGrpcServer mockGrpcServer = new MockGrpcServer();\n\n\t@BeforeEach\n\tvoid startServers() throws Exception {\n\t\tthis.mockWebServer.start();\n\t\tthis.mockGrpcServer.start();\n\t}\n\n\t@AfterEach\n\tvoid stopServers() throws Exception {\n\t\tthis.mockWebServer.close();\n\t\tthis.mockGrpcServer.close();\n\t}\n\n\t@Test\n\tvoid httpSpanExporterShouldUseProtobufAndNoCompressionByDefault() {\n\t\tthis.mockWebServer.enqueue(new MockResponse());\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:%d/v1/traces\"\n\t\t\t\t\t\t.formatted(this.mockWebServer.getPort()),\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.headers.custom=42\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(Tracer.class).nextSpan().name(\"test\").end();\n\t\t\t\tassertThat(context.getBean(OtlpHttpSpanExporter.class).flush())\n\t\t\t\t\t.isSameAs(CompletableResultCode.ofSuccess());\n\t\t\t\tRecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);\n\t\t\t\tassertThat(request).isNotNull();\n\t\t\t\tassertThat(request.getRequestLine()).contains(\"/v1/traces\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/x-protobuf\");\n\t\t\t\tassertThat(request.getHeader(\"custom\")).isEqualTo(\"42\");\n\t\t\t\tassertThat(request.getBodySize()).isPositive();\n\t\t\t\ttry (Buffer body = request.getBody()) {\n\t\t\t\t\tassertThat(body.readString(StandardCharsets.UTF_8)).contains(\"org.springframework.boot\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid httpSpanExporterCanBeConfiguredToUseGzipCompression() {\n\t\tthis.mockWebServer.enqueue(new MockResponse());\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.compression=gzip\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:%d/test\"\n\t\t\t\t\t\t.formatted(this.mockWebServer.getPort()))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpSpanExporter.class).hasSingleBean(SpanExporter.class);\n\t\t\t\tcontext.getBean(Tracer.class).nextSpan().name(\"test\").end();\n\t\t\t\tassertThat(context.getBean(OtlpHttpSpanExporter.class).flush())\n\t\t\t\t\t.isSameAs(CompletableResultCode.ofSuccess());\n\t\t\t\tRecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);\n\t\t\t\tassertThat(request).isNotNull();\n\t\t\t\tassertThat(request.getRequestLine()).contains(\"/test\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/x-protobuf\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Encoding\")).isEqualTo(\"gzip\");\n\t\t\t\tassertThat(request.getBodySize()).isPositive();\n\t\t\t\ttry (Buffer uncompressed = new Buffer(); Buffer body = request.getBody()) {\n\t\t\t\t\tuncompressed.writeAll(new GzipSource(body));\n\t\t\t\t\tassertThat(uncompressed.readString(StandardCharsets.UTF_8)).contains(\"org.springframework.boot\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid grpcSpanExporterShouldExportSpans() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:%d\"\n\t\t\t\t\t\t.formatted(this.mockGrpcServer.getPort()),\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.headers.custom=42\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(Tracer.class).nextSpan().name(\"test\").end();\n\t\t\t\tassertThat(context.getBean(OtlpGrpcSpanExporter.class).flush())\n\t\t\t\t\t.isSameAs(CompletableResultCode.ofSuccess());\n\t\t\t\tRecordedGrpcRequest request = this.mockGrpcServer.takeRequest(10, TimeUnit.SECONDS);\n\t\t\t\tassertThat(request).isNotNull();\n\t\t\t\tassertThat(request.headers().get(\"Content-Type\")).isEqualTo(\"application/grpc\");\n\t\t\t\tassertThat(request.headers().get(\"custom\")).isEqualTo(\"42\");\n\t\t\t\tassertThat(request.bodyAsString()).contains(\"org.springframework.boot\");\n\t\t\t});\n\t}\n\n\tstatic class MockGrpcServer {\n\n\t\tprivate final Server server = createServer();\n\n\t\tprivate final BlockingQueue<RecordedGrpcRequest> recordedRequests = new LinkedBlockingQueue<>();\n\n\t\tvoid start() throws Exception {\n\t\t\tthis.server.start();\n\t\t}\n\n\t\tvoid close() throws Exception {\n\t\t\tthis.server.stop();\n\t\t}\n\n\t\tint getPort() {\n\t\t\treturn this.server.getURI().getPort();\n\t\t}\n\n\t\tRecordedGrpcRequest takeRequest(int timeout, TimeUnit unit) throws InterruptedException {\n\t\t\treturn this.recordedRequests.poll(timeout, unit);\n\t\t}\n\n\t\tvoid recordRequest(RecordedGrpcRequest request) {\n\t\t\tthis.recordedRequests.add(request);\n\t\t}\n\n\t\tprivate Server createServer() {\n\t\t\tServer server = new Server();\n\t\t\tserver.addConnector(createConnector(server));\n\t\t\tserver.setHandler(new GrpcHandler());\n\t\t\treturn server;\n\t\t}\n\n\t\tprivate ServerConnector createConnector(Server server) {\n\t\t\tServerConnector connector = new ServerConnector(server,\n\t\t\t\t\tnew HTTP2CServerConnectionFactory(new HttpConfiguration()));\n\t\t\tconnector.setPort(0);\n\t\t\treturn connector;\n\t\t}\n\n\t\tclass GrpcHandler extends Handler.Abstract {\n\n\t\t\t@Override\n\t\t\tpublic boolean handle(Request request, Response response, Callback callback) throws Exception {\n\t\t\t\ttry (InputStream in = Content.Source.asInputStream(request)) {\n\t\t\t\t\trecordRequest(new RecordedGrpcRequest(request.getHeaders(), in.readAllBytes()));\n\t\t\t\t}\n\t\t\t\tresponse.getHeaders().add(\"Content-Type\", \"application/grpc\");\n\t\t\t\tresponse.getHeaders().add(\"Grpc-Status\", \"0\");\n\t\t\t\tcallback.succeeded();\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t}\n\n\t\trecord RecordedGrpcRequest(HttpFields headers, byte[] body) {\n\t\t\tString bodyAsString() {\n\t\t\t\treturn new String(this.body, StandardCharsets.UTF_8);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/otlp/OtlpTracingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport javax.net.ssl.X509TrustManager;\n\nimport io.opentelemetry.api.metrics.MeterProvider;\nimport io.opentelemetry.exporter.internal.compression.GzipCompressor;\nimport io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;\nimport io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport okhttp3.HttpUrl;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingConfigurations.ConnectionDetails.PropertiesOtlpTracingConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OtlpTracingAutoConfiguration}.\n *\n * @author Jonatan Ivanov\n * @author Moritz Halbritter\n * @author Eddú Meléndez\n */\nclass OtlpTracingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OtlpTracingAutoConfiguration.class));\n\n\tprivate final ApplicationContextRunner tracingDisabledContextRunner = this.contextRunner\n\t\t.withPropertyValues(\"management.tracing.export.enabled=false\");\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfPropertyIsNotSet() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(OtlpHttpSpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfGrpcTransportIsEnabledButPropertyIsNotSet() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OtlpGrpcSpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4318/v1/traces\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OtlpHttpSpanExporter.class)\n\t\t\t\t.hasSingleBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldCustomizeHttpTransportWithProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4317/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.timeout=10m\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.connect-timeout=20m\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.compression=GZIP\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.headers.spring=boot\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpSpanExporter.class).hasSingleBean(SpanExporter.class);\n\t\t\t\tOtlpHttpSpanExporter exporter = context.getBean(OtlpHttpSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"connectTimeoutMillis\", 1200000)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"callTimeoutMillis\", 600000);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.compressor\").isInstanceOf(GzipCompressor.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.headerSupplier\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t\t.satisfies((headerSupplier) -> assertThat(headerSupplier.get())\n\t\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.map(String.class, List.class))\n\t\t\t\t\t\t.containsEntry(\"spring\", List.of(\"boot\")));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyBeansIfGrpcTransportIsEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4317/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OtlpGrpcSpanExporter.class)\n\t\t\t\t.hasSingleBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldCustomizeGrpcTransportWithProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4317/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.transport=grpc\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.timeout=10m\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.connect-timeout=20m\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.compression=GZIP\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.headers.spring=boot\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpGrpcSpanExporter.class).hasSingleBean(SpanExporter.class);\n\t\t\t\tOtlpGrpcSpanExporter exporter = context.getBean(OtlpGrpcSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"connectTimeoutMillis\", 1200000)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"callTimeoutMillis\", 600000);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.compressor\").isInstanceOf(GzipCompressor.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.headersSupplier\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t\t.satisfies((headerSupplier) -> assertThat(headerSupplier.get())\n\t\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.map(String.class, List.class))\n\t\t\t\t\t\t.containsEntry(\"spring\", List.of(\"boot\")));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfGlobalTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfOtlpTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.otlp.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfTracingBridgeIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.micrometer.tracing\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfOtelSdkIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.opentelemetry.sdk\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfOtelApiIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.opentelemetry.api\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfExporterIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.opentelemetry.exporter\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldBackOffWhenCustomHttpExporterIsDefined() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"customOtlpHttpSpanExporter\")\n\t\t\t\t.hasSingleBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldBackOffWhenCustomGrpcExporterIsDefined() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGrpcExporterConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"customOtlpGrpcSpanExporter\")\n\t\t\t\t.hasSingleBean(SpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyOtlpHttpSpanExporterIfTracingIsDisabled() {\n\t\tthis.tracingDisabledContextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4318/v1/traces\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OtlpHttpSpanExporter.class));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4318/v1/traces\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(PropertiesOtlpTracingConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid testConnectionFactoryWithOverridesWhenUsingCustomConnectionDetails() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionDetailsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OtlpTracingConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesOtlpTracingConnectionDetails.class);\n\t\t\tOtlpHttpSpanExporter otlpHttpSpanExporter = context.getBean(OtlpHttpSpanExporter.class);\n\t\t\tassertThat(otlpHttpSpanExporter).extracting(\"delegate.httpSender.url\")\n\t\t\t\t.isEqualTo(HttpUrl.get(\"http://localhost:12345/v1/traces\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid httpShouldUseMeterProviderIfSet() {\n\t\tthis.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4318/v1/traces\")\n\t\t\t.run((context) -> {\n\t\t\t\tOtlpHttpSpanExporter otlpHttpSpanExporter = context.getBean(OtlpHttpSpanExporter.class);\n\t\t\t\tassertThat(otlpHttpSpanExporter.toBuilder())\n\t\t\t\t\t.extracting(\"delegate.meterProviderSupplier\", InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t\t.satisfies((meterProviderSupplier) -> assertThat(meterProviderSupplier.get())\n\t\t\t\t\t\t.isSameAs(MeterProviderConfiguration.meterProvider));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid grpcShouldUseMeterProviderIfSet() {\n\t\tthis.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4318/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> {\n\t\t\t\tOtlpGrpcSpanExporter otlpGrpcSpanExporter = context.getBean(OtlpGrpcSpanExporter.class);\n\t\t\t\tassertThat(otlpGrpcSpanExporter.toBuilder())\n\t\t\t\t\t.extracting(\"delegate.meterProviderSupplier\", InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t\t.satisfies((meterProviderSupplier) -> assertThat(meterProviderSupplier.get())\n\t\t\t\t\t\t.isSameAs(MeterProviderConfiguration.meterProvider));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeHttpTransportWithOtlpHttpSpanExporterBuilderCustomizer() {\n\t\tDuration connectTimeout = Duration.ofMinutes(20);\n\t\tDuration timeout = Duration.ofMinutes(10);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"httpCustomizer1\", OtlpHttpSpanExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setConnectTimeout(connectTimeout))\n\t\t\t.withBean(\"httpCustomizer2\", OtlpHttpSpanExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setTimeout(timeout))\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4317/v1/traces\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpSpanExporter.class).hasSingleBean(SpanExporter.class);\n\t\t\t\tOtlpHttpSpanExporter exporter = context.getBean(OtlpHttpSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"connectTimeoutMillis\", (int) connectTimeout.toMillis())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"callTimeoutMillis\", (int) timeout.toMillis());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeGrpcTransportWhenEnabledWithOtlpGrpcSpanExporterBuilderCustomizer() {\n\t\tDuration timeout = Duration.ofMinutes(10);\n\t\tDuration connectTimeout = Duration.ofMinutes(20);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"grpcCustomizer1\", OtlpGrpcSpanExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setConnectTimeout(connectTimeout))\n\t\t\t.withBean(\"grpcCustomizer2\", OtlpGrpcSpanExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setTimeout(timeout))\n\t\t\t.withPropertyValues(\"management.opentelemetry.tracing.export.otlp.endpoint=http://localhost:4317/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpGrpcSpanExporter.class).hasSingleBean(SpanExporter.class);\n\t\t\t\tOtlpGrpcSpanExporter exporter = context.getBean(OtlpGrpcSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"connectTimeoutMillis\", (int) connectTimeout.toMillis())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"callTimeoutMillis\", (int) timeout.toMillis());\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasSslBundleConfiguresHttpExporter() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.endpoint=https://localhost:4318/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.ssl.bundle=mybundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.mybundle.truststore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpSpanExporter.class);\n\t\t\t\tOtlpHttpSpanExporter exporter = context.getBean(OtlpHttpSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.sslSocketFactoryOrNull\").isNotNull();\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.x509TrustManager\")\n\t\t\t\t\t.isInstanceOf(X509TrustManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasSslBundleConfiguresGrpcExporter() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.endpoint=https://localhost:4318/v1/traces\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.transport=grpc\",\n\t\t\t\t\t\"management.opentelemetry.tracing.export.otlp.ssl.bundle=mybundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.mybundle.truststore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpGrpcSpanExporter.class);\n\t\t\t\tOtlpGrpcSpanExporter exporter = context.getBean(OtlpGrpcSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client.sslSocketFactoryOrNull\").isNotNull();\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client.x509TrustManager\")\n\t\t\t\t\t.isInstanceOf(X509TrustManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomConnectionDetailsProvidesSslBundleConfiguresHttpExporter() {\n\t\tSslBundle sslBundle = SslBundle.systemDefault();\n\t\tOtlpTracingConnectionDetails connectionDetails = mock(OtlpTracingConnectionDetails.class);\n\t\tgiven(connectionDetails.getUrl(Transport.HTTP)).willReturn(\"https://localhost:4318/v1/traces\");\n\t\tgiven(connectionDetails.getSslBundle()).willReturn(sslBundle);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customOtlpTracingConnectionDetails\", OtlpTracingConnectionDetails.class, () -> connectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpSpanExporter.class);\n\t\t\t\tOtlpHttpSpanExporter exporter = context.getBean(OtlpHttpSpanExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.sslSocketFactoryOrNull\").isNotNull();\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.x509TrustManager\")\n\t\t\t\t\t.isInstanceOf(X509TrustManager.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class MeterProviderConfiguration {\n\n\t\tstatic final MeterProvider meterProvider = (instrumentationScopeName) -> null;\n\n\t\t@Bean\n\t\tMeterProvider meterProvider() {\n\t\t\treturn meterProvider;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomHttpExporterConfiguration {\n\n\t\t@Bean\n\t\tOtlpHttpSpanExporter customOtlpHttpSpanExporter() {\n\t\t\treturn OtlpHttpSpanExporter.builder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomGrpcExporterConfiguration {\n\n\t\t@Bean\n\t\tOtlpGrpcSpanExporter customOtlpGrpcSpanExporter() {\n\t\t\treturn OtlpGrpcSpanExporter.builder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tOtlpTracingConnectionDetails otlpTracingConnectionDetails() {\n\t\t\treturn (transport) -> \"http://localhost:12345/v1/traces\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/zipkin/DefaultEncodingConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.zipkin;\n\nimport zipkin2.reporter.Encoding;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Configures the bean {@linkplain ZipkinAutoConfiguration} would from properties.\n */\n@TestConfiguration(proxyBeanMethods = false)\nclass DefaultEncodingConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tEncoding zipkinReporterEncoding() {\n\t\treturn Encoding.JSON;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/zipkin/NoopSender.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.zipkin;\n\nimport java.io.IOException;\nimport java.util.List;\n\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\n\nclass NoopSender extends BytesMessageSender.Base {\n\n\tNoopSender(Encoding encoding) {\n\t\tsuper(encoding);\n\t}\n\n\t@Override\n\tpublic int messageMaxBytes() {\n\t\treturn 1024;\n\t}\n\n\t@Override\n\tpublic void send(List<byte[]> encodedSpans) {\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-opentelemetry/src/test/java/org/springframework/boot/micrometer/tracing/opentelemetry/autoconfigure/zipkin/ZipkinWithOpenTelemetryTracingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.zipkin;\n\nimport io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;\nimport io.opentelemetry.sdk.trace.export.SpanExporter;\nimport org.junit.jupiter.api.Test;\nimport zipkin2.Span;\nimport zipkin2.reporter.BytesEncoder;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipkinWithOpenTelemetryTracingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\n@SuppressWarnings({ \"removal\", \"deprecation\" })\nclass ZipkinWithOpenTelemetryTracingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ZipkinWithOpenTelemetryTracingAutoConfiguration.class,\n\t\t\t\tDefaultEncodingConfiguration.class));\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfInfrastructureIsNotAvailable() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(ZipkinWithOpenTelemetryTracingAutoConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BytesEncoder.class)\n\t\t\t\t.doesNotHaveBean(SpanExporter.class)\n\t\t\t\t.doesNotHaveBean(ZipkinSpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldSupplyBeansIfInfrastructureIsAvailable() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ZipkinAutoConfiguration.class)).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SpanExporter.class);\n\t\t\tassertThat(context).hasSingleBean(ZipkinSpanExporter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.enabled=false\")\n\t\t\t.withConfiguration(AutoConfigurations.of(ZipkinAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(SpanExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffWithoutEncoding() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(ZipkinWithOpenTelemetryTracingAutoConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(BytesEncoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomEncoderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ZipkinSpanExporter.class);\n\t\t\t\tassertThat(context).hasBean(\"customSpanEncoder\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyZipkinSpanExporterIfSenderIsMissing() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);\n\t\t\tassertThat(context).hasBean(\"spanBytesEncoder\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyZipkinSpanExporterIfNotOnClasspath() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.opentelemetry.exporter.zipkin\"))\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(\"spanBytesEncoder\");\n\t\t\t});\n\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfZipkinIsNotOnClasspath() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"zipkin2.Span\"))\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(ZipkinSpanExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(\"spanBytesEncoder\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customZipkinSpanExporter\");\n\t\t\tassertThat(context).hasSingleBean(ZipkinSpanExporter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyZipkinSpanExporterIfGlobalTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.enabled=false\")\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyZipkinSpanExporterIfZipkinTracingIsDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.tracing.export.zipkin.enabled=false\")\n\t\t\t.withUserConfiguration(SenderConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ZipkinSpanExporter.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomEncoderBean() {\n\t\tthis.contextRunner.withUserConfiguration(SenderConfiguration.class, CustomEncoderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ZipkinSpanExporter.class);\n\t\t\t\tassertThat(context).hasBean(\"customSpanEncoder\");\n\t\t\t\tassertThat(context.getBean(ZipkinSpanExporter.class)).extracting(\"encoder\")\n\t\t\t\t\t.isInstanceOf(CustomSpanEncoder.class)\n\t\t\t\t\t.extracting(\"encoding\")\n\t\t\t\t\t.isEqualTo(Encoding.JSON);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomEncodingBean() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(SenderConfiguration.class, CustomEncodingConfiguration.class,\n\t\t\t\t\tCustomEncoderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ZipkinSpanExporter.class);\n\t\t\t\tassertThat(context).hasBean(\"customSpanEncoder\");\n\t\t\t\tassertThat(context.getBean(ZipkinSpanExporter.class)).extracting(\"encoder\")\n\t\t\t\t\t.isInstanceOf(CustomSpanEncoder.class)\n\t\t\t\t\t.extracting(\"encoding\")\n\t\t\t\t\t.isEqualTo(Encoding.PROTO3);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomEncodingConfiguration {\n\n\t\t@Bean\n\t\tEncoding encoding() {\n\t\t\treturn Encoding.PROTO3;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class SenderConfiguration {\n\n\t\t@Bean\n\t\tBytesMessageSender sender(Encoding encoding) {\n\t\t\treturn new NoopSender(encoding);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomConfiguration {\n\n\t\t@Bean\n\t\tZipkinSpanExporter customZipkinSpanExporter() {\n\t\t\treturn ZipkinSpanExporter.builder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomEncoderConfiguration {\n\n\t\t@Bean\n\t\tBytesEncoder<Span> customSpanEncoder(Encoding encoding) {\n\t\t\treturn new CustomSpanEncoder(encoding);\n\t\t}\n\n\t}\n\n\trecord CustomSpanEncoder(Encoding encoding) implements BytesEncoder<Span> {\n\n\t\t@Override\n\t\tpublic int sizeInBytes(Span span) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t\t@Override\n\t\tpublic byte[] encode(Span span) {\n\t\t\tthrow new UnsupportedOperationException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-metadata\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Micrometer Tracing Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-micrometer-tracing\"))\n\tapi(\"io.micrometer:micrometer-observation-test\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/main/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/AutoConfigureTracing.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.tracing.Tracer;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration for\n * tracing.\n * <p>\n * If this annotation is applied to a sliced test, a no-op {@link Tracer} and an\n * {@link ObservationRegistry} are added to the application context.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureTracing {\n\n\t/**\n\t * Whether traces should be reported to external systems in the test.\n\t * @return whether traces should be reported to external systems in the test\n\t */\n\tboolean export() default true;\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/main/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/TracingContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextAnnotationUtils;\n\n/**\n * {@link ContextCustomizerFactory} that globally disables metrics export in tests. The\n * behaviour can be controlled with {@link AutoConfigureTracing} on the test class or via\n * the {@value #AUTO_CONFIGURE_PROPERTY} property.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n */\nclass TracingContextCustomizerFactory implements ContextCustomizerFactory {\n\n\tstatic final String AUTO_CONFIGURE_PROPERTY = \"spring.test.tracing.export\";\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\tAutoConfigureTracing annotation = TestContextAnnotationUtils.findMergedAnnotation(testClass,\n\t\t\t\tAutoConfigureTracing.class);\n\t\treturn new DisableTracingExportContextCustomizer(annotation);\n\t}\n\n\tprivate static class DisableTracingExportContextCustomizer implements ContextCustomizer {\n\n\t\tprivate final @Nullable AutoConfigureTracing annotation;\n\n\t\tDisableTracingExportContextCustomizer(@Nullable AutoConfigureTracing annotation) {\n\t\t\tthis.annotation = annotation;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customizeContext(ConfigurableApplicationContext context,\n\t\t\t\tMergedContextConfiguration mergedContextConfiguration) {\n\t\t\tif (isTracingDisabled(context.getEnvironment())) {\n\t\t\t\tTestPropertyValues.of(\"management.tracing.export.enabled=false\").applyTo(context);\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isTracingDisabled(Environment environment) {\n\t\t\tif (this.annotation != null) {\n\t\t\t\treturn !this.annotation.export();\n\t\t\t}\n\t\t\treturn !environment.getProperty(AUTO_CONFIGURE_PROPERTY, Boolean.class, false);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(@Nullable Object o) {\n\t\t\tif (this == o) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tDisableTracingExportContextCustomizer that = (DisableTracingExportContextCustomizer) o;\n\t\t\treturn Objects.equals(this.annotation, that.annotation);\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn Objects.hash(this.annotation);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/main/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for handling metrics in tests.\n */\n@NullMarked\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/main/resources/META-INF/spring/org.springframework.boot.micrometer.tracing.test.autoconfigure.AutoConfigureTracing.imports",
    "content": "org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\norg.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration\norg.springframework.boot.micrometer.tracing.autoconfigure.NoopTracerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.tracing.export\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether tracing export should be auto-configured in tests.\",\n      \"defaultValue\": false\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Context Customizer Factories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.micrometer.tracing.test.autoconfigure.TracingContextCustomizerFactory\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/test/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/AutoConfigureTracingMissingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to verify behaviour when\n * {@link AutoConfigureTracing @AutoConfigureTracing} is not present on the test class.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@SpringBootTest\nclass AutoConfigureTracingMissingIntegrationTests {\n\n\t@Test\n\tvoid customizerRunsAndDisablesExportWhenNoAnnotationPresent(@Autowired Environment environment) {\n\t\tassertThat(environment.getProperty(\"management.tracing.export.enabled\")).isEqualTo(\"false\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/test/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/AutoConfigureTracingPresentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport io.micrometer.tracing.Tracer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to verify behaviour when\n * {@link AutoConfigureTracing @AutoConfigureTracing} is present on the test class.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@SpringBootTest\n@AutoConfigureTracing\nclass AutoConfigureTracingPresentIntegrationTests {\n\n\t@Test\n\tvoid customizerDoesNotDisableAvailableMeterRegistriesWhenAnnotationPresent(\n\t\t\t@Autowired ApplicationContext applicationContext) {\n\t\tassertThat(applicationContext.getBean(Tracer.class)).isEqualTo(Tracer.NOOP);\n\t}\n\n\t@Test\n\tvoid customizerDoesNotSetExportDisabledPropertyWhenAnnotationPresent(@Autowired Environment environment) {\n\t\tassertThat(environment.containsProperty(\"management.tracing.export.enabled\")).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/test/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/AutoConfigureTracingSlicedIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.tracing.Tracer;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureTracing @AutoConfigureTracing} when used on a sliced\n * test.\n *\n * @author Moritz Halbritter\n */\n// TODO Test AutoConfigureTracing in a sliced test\n// @WebMvcTest\n@Disabled\n@AutoConfigureTracing\nclass AutoConfigureTracingSlicedIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid shouldHaveTracer() {\n\t\tassertThat(this.context.getBean(Tracer.class)).isEqualTo(Tracer.NOOP);\n\t}\n\n\t@Test\n\tvoid shouldHaveObservationRegistry() {\n\t\tassertThat(this.context.getBean(ObservationRegistry.class)).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/test/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/AutoConfigureTracingSpringBootApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} for use with\n * {@link AutoConfigureTracing @AutoConfigureTracing} tests.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\n@SpringBootConfiguration\n@EnableAutoConfiguration\nclass AutoConfigureTracingSpringBootApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-micrometer-tracing-test/src/test/java/org/springframework/boot/micrometer/tracing/test/autoconfigure/TracingContextCustomizerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.micrometer.tracing.test.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextLoader;\nimport org.springframework.test.context.MergedContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AutoConfigureTracing} and {@link TracingContextCustomizerFactory}\n * working together.\n *\n * @author Chris Bono\n * @author Moritz Halbritter\n */\nclass TracingContextCustomizerFactoryTests {\n\n\tprivate final TracingContextCustomizerFactory factory = new TracingContextCustomizerFactory();\n\n\t@Test\n\tvoid whenNotAnnotatedTracingExportIsDisabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(NoAnnotation.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsDisabled(context);\n\t}\n\n\t@Test\n\tvoid whenAnnotatedWithDefaultAttributeTracingExportIsEnabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(TracingExportDefault.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsEnabled(context);\n\t}\n\n\t@Test\n\tvoid whenAnnotatedWithFalseExportAttributeTracingExportIsDisabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(TracingExportDisabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsDisabled(context);\n\t}\n\n\t@Test\n\tvoid whenAnnotatedWithTrueExportAttributeTracingExportIsEnabled() {\n\t\tContextCustomizer customizer = createContextCustomizer(TracingExportEnabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsEnabled(context);\n\t}\n\n\t@Test\n\tvoid notEquals() {\n\t\tContextCustomizer customizer1 = createContextCustomizer(TracingExportEnabled.class);\n\t\tContextCustomizer customizer2 = createContextCustomizer(TracingExportDisabled.class);\n\t\tassertThat(customizer1).isNotEqualTo(customizer2);\n\t}\n\n\t@Test\n\tvoid equals() {\n\t\tContextCustomizer customizer1 = createContextCustomizer(TracingExportEnabled.class);\n\t\tContextCustomizer customizer2 = createContextCustomizer(TracingExportEnabled.class);\n\t\tassertThat(customizer1).isEqualTo(customizer2);\n\t\tassertThat(customizer1).hasSameHashCodeAs(customizer2);\n\t}\n\n\t@Test\n\tvoid tracingExportCanBeEnabledViaProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(NoAnnotation.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.tracing.export\", \"true\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsEnabled(context);\n\t}\n\n\t@Test\n\tvoid tracingExportCanBeDisabledViaProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(NoAnnotation.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.tracing.export\", \"false\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsDisabled(context);\n\t}\n\n\t@Test\n\tvoid annotationTakesPrecedenceOverDisabledProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(TracingExportEnabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.tracing.export\", \"false\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsEnabled(context);\n\t}\n\n\t@Test\n\tvoid annotationTakesPrecedenceOverEnabledProperty() {\n\t\tContextCustomizer customizer = createContextCustomizer(TracingExportDisabled.class);\n\t\tConfigurableApplicationContext context = new GenericApplicationContext();\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.test.tracing.export\", \"true\");\n\t\tcontext.setEnvironment(environment);\n\t\tapplyCustomizerToContext(customizer, context);\n\t\tassertThatTracingExportIsDisabled(context);\n\t}\n\n\tprivate void applyCustomizerToContext(ContextCustomizer customizer, ConfigurableApplicationContext context) {\n\t\tcustomizer.customizeContext(context,\n\t\t\t\tnew MergedContextConfiguration(getClass(), null, null, null, mock(ContextLoader.class)));\n\t}\n\n\tprivate ContextCustomizer createContextCustomizer(Class<?> testClass) {\n\t\tContextCustomizer contextCustomizer = this.factory.createContextCustomizer(testClass, Collections.emptyList());\n\t\tassertThat(contextCustomizer).as(\"contextCustomizer\").isNotNull();\n\t\treturn contextCustomizer;\n\t}\n\n\tprivate void assertThatTracingExportIsDisabled(ConfigurableApplicationContext context) {\n\t\tassertThat(context.getEnvironment().getProperty(\"management.tracing.export.enabled\")).isEqualTo(\"false\");\n\t}\n\n\tprivate void assertThatTracingExportIsEnabled(ConfigurableApplicationContext context) {\n\t\tassertThat(context.getEnvironment().getProperty(\"management.tracing.export.enabled\")).isNull();\n\t}\n\n\tstatic class NoAnnotation {\n\n\t}\n\n\t@AutoConfigureTracing\n\tstatic class TracingExportDefault {\n\n\t}\n\n\t@AutoConfigureTracing(export = false)\n\tstatic class TracingExportDisabled {\n\n\t}\n\n\t@AutoConfigureTracing(export = true)\n\tstatic class TracingExportEnabled {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot MongoDB\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(\"io.netty:netty-transport\")\n\toptional(\"org.mongodb:mongodb-driver-reactivestreams\")\n\toptional(\"org.mongodb:mongodb-driver-sync\")\n\toptional(\"org.testcontainers:testcontainers-mongodb\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.mongodb:mongodb-driver-sync\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-testcontainers\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"org.springframework.data:spring-data-mongodb\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.netty:netty-handler\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/docker/compose/MongoDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.docker.compose;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.MongoCredential;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MongoDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MongoDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mongo-compose.yaml\", image = TestImage.MONGODB)\n\tvoid runCreatesConnectionDetails(MongoConnectionDetails connectionDetails) {\n\t\tassertConnectionDetailsWithDatabase(connectionDetails, \"mydatabase\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"mongo-ssl-compose.yaml\", image = TestImage.MONGODB,\n\t\t\tadditionalResources = { \"ca.crt\", \"client.crt\", \"client.key\", \"mongo.pem\" })\n\tvoid runWithSslCreatesConnectionDetails(MongoConnectionDetails connectionDetails) {\n\t\tassertConnectionDetailsWithDatabase(connectionDetails, \"mydatabase\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\tprivate void assertConnectionDetailsWithDatabase(MongoConnectionDetails connectionDetails, String database) {\n\t\tConnectionString connectionString = connectionDetails.getConnectionString();\n\t\tMongoCredential credential = connectionString.getCredential();\n\t\tassertThat(credential).isNotNull();\n\t\tassertThat(credential.getUserName()).isEqualTo(\"root\");\n\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\tassertThat(credential.getSource()).isEqualTo(\"admin\");\n\t\tassertThat(connectionString.getDatabase()).isEqualTo(database);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/health/MongoHealthIndicatorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.health;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.MongoClientSettings.Builder;\nimport com.mongodb.ServerApi;\nimport com.mongodb.ServerApiVersion;\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoClients;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MongoHealthIndicator}.\n *\n * @author Andy Wilkinson\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass MongoHealthIndicatorIntegrationTests {\n\n\t@Container\n\tstatic MongoDBContainer mongo = TestImage.container(MongoDBContainer.class);\n\n\t@Test\n\tvoid standardApi() {\n\t\tHealth health = mongoHealth();\n\t\tassertHealth(health);\n\t}\n\n\t@Test\n\tvoid strictV1Api() {\n\t\tHealth health = mongoHealth(ServerApi.builder().strict(true).version(ServerApiVersion.V1).build());\n\t\tassertHealth(health);\n\t}\n\n\tprivate void assertHealth(Health health) {\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsKey(\"maxWireVersion\");\n\t\tassertThat(health.getDetails()).hasEntrySatisfying(\"databases\",\n\t\t\t\t(databases) -> assertThat(databases).asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.containsExactlyInAnyOrder(\"local\", \"admin\", \"config\"));\n\t}\n\n\tprivate Health mongoHealth() {\n\t\treturn mongoHealth(null);\n\t}\n\n\tprivate Health mongoHealth(@Nullable ServerApi serverApi) {\n\t\tBuilder settingsBuilder = MongoClientSettings.builder()\n\t\t\t.applyConnectionString(new ConnectionString(mongo.getConnectionString()));\n\t\tif (serverApi != null) {\n\t\t\tsettingsBuilder.serverApi(serverApi);\n\t\t}\n\t\tMongoClientSettings settings = settingsBuilder.build();\n\t\tMongoClient mongoClient = MongoClients.create(settings);\n\t\tMongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoClient);\n\t\tHealth health = healthIndicator.health(true);\n\t\tassertThat(health).isNotNull();\n\t\treturn health;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/health/MongoReactiveHealthIndicatorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.health;\n\nimport java.time.Duration;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.MongoClientSettings.Builder;\nimport com.mongodb.ServerApi;\nimport com.mongodb.ServerApiVersion;\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport com.mongodb.reactivestreams.client.MongoClients;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MongoReactiveHealthIndicator}.\n *\n * @author Andy Wilkinson\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass MongoReactiveHealthIndicatorIntegrationTests {\n\n\t@Container\n\tstatic MongoDBContainer mongo = TestImage.container(MongoDBContainer.class);\n\n\t@Test\n\tvoid standardApi() {\n\t\tHealth health = mongoHealth();\n\t\tassertHealth(health);\n\t}\n\n\t@Test\n\tvoid strictV1Api() {\n\t\tHealth health = mongoHealth(ServerApi.builder().strict(true).version(ServerApiVersion.V1).build());\n\t\tassertHealth(health);\n\t}\n\n\tprivate Health mongoHealth() {\n\t\treturn mongoHealth(null);\n\t}\n\n\tprivate Health mongoHealth(@Nullable ServerApi serverApi) {\n\t\tBuilder settingsBuilder = MongoClientSettings.builder()\n\t\t\t.applyConnectionString(new ConnectionString(mongo.getConnectionString()));\n\t\tif (serverApi != null) {\n\t\t\tsettingsBuilder.serverApi(serverApi);\n\t\t}\n\t\tMongoClientSettings settings = settingsBuilder.build();\n\t\tMongoClient mongoClient = MongoClients.create(settings);\n\t\tMongoReactiveHealthIndicator healthIndicator = new MongoReactiveHealthIndicator(mongoClient);\n\t\tHealth health = healthIndicator.health(true).block(Duration.ofSeconds(30));\n\t\tassertThat(health).isNotNull();\n\t\treturn health;\n\t}\n\n\tprivate void assertHealth(Health health) {\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsKey(\"maxWireVersion\");\n\t\tassertThat(health.getDetails()).hasEntrySatisfying(\"databases\",\n\t\t\t\t(databases) -> assertThat(databases).asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.containsExactlyInAnyOrder(\"local\", \"admin\", \"config\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/testcontainers/DeprecatedMongoDbContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoClients;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.MongoDBContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link DeprecatedMongoDbContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link MongoDbContainerConnectionDetailsFactory}.\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedMongoDbContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class);\n\n\t@Autowired(required = false)\n\tprivate MongoConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tMongoClient client = MongoClients.create(this.connectionDetails.getConnectionString());\n\t\tassertThat(client.listDatabaseNames()).containsExactly(\"admin\", \"config\", \"local\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoClients;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBAtlasLocalContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MongoDbAtlasLocalContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass MongoDbAtlasLocalContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final MongoDBAtlasLocalContainer mongoDb = TestImage.container(MongoDBAtlasLocalContainer.class);\n\n\t@Autowired(required = false)\n\tprivate MongoConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tMongoClient client = MongoClients.create(this.connectionDetails.getConnectionString());\n\t\tassertThat(client.listDatabaseNames()).containsExactly(\"admin\", \"config\", \"local\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/resources/org/springframework/boot/mongodb/docker/compose/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/resources/org/springframework/boot/mongodb/docker/compose/client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/resources/org/springframework/boot/mongodb/docker/compose/client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/resources/org/springframework/boot/mongodb/docker/compose/mongo-compose.yaml",
    "content": "services:\n  mongo:\n    image: '{imageName}'\n    ports:\n      - '27017'\n    environment:\n      MONGO_INITDB_ROOT_USERNAME: 'root'\n      MONGO_INITDB_ROOT_PASSWORD: 'secret'\n      MONGO_INITDB_DATABASE: 'mydatabase'\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/resources/org/springframework/boot/mongodb/docker/compose/mongo-ssl-compose.yaml",
    "content": "services:\n  mongo:\n    image: '{imageName}'\n    ports:\n      - '27017'\n    secrets:\n      - ssl-ca\n      - ssl-cert\n    environment:\n      MONGO_INITDB_ROOT_USERNAME: 'root'\n      MONGO_INITDB_ROOT_PASSWORD: 'secret'\n      MONGO_INITDB_DATABASE: 'mydatabase'\n    command: >\n      mongod\n        --auth\n        --tlsMode requireTLS\n        --tlsCertificateKeyFile /run/secrets/ssl-cert\n        --tlsCAFile /run/secrets/ssl-ca\n        --bind_ip_all\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'\n      - 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\nsecrets:\n  ssl-ca:\n    file: 'ca.crt'\n  ssl-cert:\n    file: 'mongo.pem'"
  },
  {
    "path": "module/spring-boot-mongodb/src/dockerTest/resources/org/springframework/boot/mongodb/docker/compose/mongo.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.client.MongoClient;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Mongo.\n *\n * @author Dave Syer\n * @author Oliver Gierke\n * @author Phillip Webb\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(MongoClient.class)\n@EnableConfigurationProperties(MongoProperties.class)\n@ConditionalOnMissingBean(type = \"org.springframework.data.mongodb.MongoDatabaseFactory\")\npublic final class MongoAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(MongoConnectionDetails.class)\n\tPropertiesMongoConnectionDetails mongoConnectionDetails(MongoProperties properties,\n\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesMongoConnectionDetails(properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMongoClient mongo(ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers,\n\t\t\tMongoClientSettings settings) {\n\t\treturn new MongoClientFactory(builderCustomizers.orderedStream().toList()).createMongoClient(settings);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(MongoClientSettings.class)\n\tstatic class MongoClientSettingsConfiguration {\n\n\t\t@Bean\n\t\tMongoClientSettings mongoClientSettings() {\n\t\t\treturn MongoClientSettings.builder().build();\n\t\t}\n\n\t\t@Bean\n\t\tStandardMongoClientSettingsBuilderCustomizer standardMongoSettingsCustomizer(MongoProperties properties,\n\t\t\t\tMongoConnectionDetails connectionDetails) {\n\t\t\treturn new StandardMongoClientSettingsBuilderCustomizer(connectionDetails,\n\t\t\t\t\tproperties.getRepresentation().getUuid());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoClientFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.List;\n\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoClients;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A factory for a blocking {@link MongoClient}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Josh Long\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Nasko Vasilev\n * @author Mark Paluch\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class MongoClientFactory extends MongoClientFactorySupport<MongoClient> {\n\n\t/**\n\t * Construct a factory for creating a blocking {@link MongoClient}.\n\t * @param builderCustomizers a list of configuration settings customizers\n\t */\n\tpublic MongoClientFactory(@Nullable List<MongoClientSettingsBuilderCustomizer> builderCustomizers) {\n\t\tsuper(builderCustomizers, MongoClients::create);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoClientFactorySupport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiFunction;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.MongoClientSettings.Builder;\nimport com.mongodb.MongoDriverInformation;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Base class for setup that is common to MongoDB client factories.\n *\n * @param <T> the mongo client type\n * @author Christoph Strobl\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic abstract class MongoClientFactorySupport<T> {\n\n\tprivate final List<MongoClientSettingsBuilderCustomizer> builderCustomizers;\n\n\tprivate final BiFunction<MongoClientSettings, MongoDriverInformation, T> clientCreator;\n\n\tprotected MongoClientFactorySupport(@Nullable List<MongoClientSettingsBuilderCustomizer> builderCustomizers,\n\t\t\tBiFunction<MongoClientSettings, MongoDriverInformation, T> clientCreator) {\n\t\tthis.builderCustomizers = (builderCustomizers != null) ? builderCustomizers : Collections.emptyList();\n\t\tthis.clientCreator = clientCreator;\n\t}\n\n\tpublic T createMongoClient(MongoClientSettings settings) {\n\t\tBuilder targetSettings = MongoClientSettings.builder(settings);\n\t\tcustomize(targetSettings);\n\t\treturn this.clientCreator.apply(targetSettings.build(), driverInformation());\n\t}\n\n\tprivate void customize(Builder builder) {\n\t\tfor (MongoClientSettingsBuilderCustomizer customizer : this.builderCustomizers) {\n\t\t\tcustomizer.customize(builder);\n\t\t}\n\t}\n\n\tprivate MongoDriverInformation driverInformation() {\n\t\treturn MongoDriverInformation.builder(MongoDriverInformation.builder().build())\n\t\t\t.driverName(\"spring-boot\")\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoClientSettingsBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport com.mongodb.MongoClientSettings.Builder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Builder MongoClientSettings.Builder} to fine-tune its auto-configuration. before\n * it creates a {@link com.mongodb.MongoClientSettings}.\n *\n * @author Mark Paluch\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface MongoClientSettingsBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link Builder}.\n\t * @param clientSettingsBuilder the builder to customize\n\t */\n\tvoid customize(Builder clientSettingsBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport com.mongodb.ConnectionString;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to a MongoDB service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface MongoConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * The {@link ConnectionString} for MongoDB.\n\t * @return the connection string\n\t */\n\tConnectionString getConnectionString();\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.List;\n\nimport com.mongodb.ConnectionString;\nimport org.bson.UuidRepresentation;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Mongo.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Josh Long\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Nasko Vasilev\n * @author Mark Paluch\n * @author Artsiom Yudovin\n * @author Safeer Ansari\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.mongodb\")\npublic class MongoProperties {\n\n\t/**\n\t * Default port used when the configured port is {@code null}.\n\t */\n\tpublic static final int DEFAULT_PORT = 27017;\n\n\t/**\n\t * Default URI used when the configured URI is {@code null}.\n\t */\n\tpublic static final String DEFAULT_URI = \"mongodb://localhost/test\";\n\n\t/**\n\t * Protocol to be used for the MongoDB connection. Ignored if 'uri' is set.\n\t */\n\tprivate String protocol = \"mongodb\";\n\n\t/**\n\t * Mongo server host. Ignored if 'uri' is set.\n\t */\n\tprivate @Nullable String host;\n\n\t/**\n\t * Mongo server port. Ignored if 'uri' is set.\n\t */\n\tprivate @Nullable Integer port;\n\n\t/**\n\t * Additional server hosts. Ignored if 'uri' is set or if 'host' is omitted.\n\t * Additional hosts will use the default mongo port of 27017. If you want to use a\n\t * different port you can use the \"host:port\" syntax.\n\t */\n\tprivate @Nullable List<String> additionalHosts;\n\n\t/**\n\t * Mongo database URI. Overrides host, port, username, and password.\n\t */\n\tprivate @Nullable String uri;\n\n\t/**\n\t * Database name. Overrides database in URI.\n\t */\n\tprivate @Nullable String database;\n\n\t/**\n\t * Authentication database name.\n\t */\n\tprivate @Nullable String authenticationDatabase;\n\n\t/**\n\t * Login user of the mongo server. Ignored if 'uri' is set.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the mongo server. Ignored if 'uri' is set.\n\t */\n\tprivate char @Nullable [] password;\n\n\t/**\n\t * Required replica set name for the cluster. Ignored if 'uri' is set.\n\t */\n\tprivate @Nullable String replicaSetName;\n\n\tprivate final Representation representation = new Representation();\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic void setProtocol(String protocol) {\n\t\tthis.protocol = protocol;\n\t}\n\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\tpublic @Nullable String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(@Nullable String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic @Nullable String getDatabase() {\n\t\treturn this.database;\n\t}\n\n\tpublic void setDatabase(@Nullable String database) {\n\t\tthis.database = database;\n\t}\n\n\tpublic @Nullable String getAuthenticationDatabase() {\n\t\treturn this.authenticationDatabase;\n\t}\n\n\tpublic void setAuthenticationDatabase(@Nullable String authenticationDatabase) {\n\t\tthis.authenticationDatabase = authenticationDatabase;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic char @Nullable [] getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(char @Nullable [] password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic @Nullable String getReplicaSetName() {\n\t\treturn this.replicaSetName;\n\t}\n\n\tpublic void setReplicaSetName(@Nullable String replicaSetName) {\n\t\tthis.replicaSetName = replicaSetName;\n\t}\n\n\tpublic @Nullable String getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic String determineUri() {\n\t\treturn (this.uri != null) ? this.uri : DEFAULT_URI;\n\t}\n\n\tpublic void setUri(@Nullable String uri) {\n\t\tthis.uri = uri;\n\t}\n\n\tpublic @Nullable Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(@Nullable Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable String getMongoClientDatabase() {\n\t\tif (this.database != null) {\n\t\t\treturn this.database;\n\t\t}\n\t\treturn new ConnectionString(determineUri()).getDatabase();\n\t}\n\n\tpublic @Nullable List<String> getAdditionalHosts() {\n\t\treturn this.additionalHosts;\n\t}\n\n\tpublic void setAdditionalHosts(@Nullable List<String> additionalHosts) {\n\t\tthis.additionalHosts = additionalHosts;\n\t}\n\n\tpublic Representation getRepresentation() {\n\t\treturn this.representation;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic static class Representation {\n\n\t\t/**\n\t\t * Representation to use when converting a UUID to a BSON binary value.\n\t\t */\n\t\tprivate UuidRepresentation uuid = UuidRepresentation.UNSPECIFIED;\n\n\t\tpublic UuidRepresentation getUuid() {\n\t\t\treturn this.uuid;\n\t\t}\n\n\t\tpublic void setUuid(UuidRepresentation uuid) {\n\t\t\tthis.uuid = uuid;\n\t\t}\n\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * Whether to enable SSL support. Enabled automatically if \"bundle\" is provided\n\t\t * unless specified otherwise.\n\t\t */\n\t\tprivate @Nullable Boolean enabled;\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn (this.enabled != null) ? this.enabled : this.bundle != null;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/MongoReactiveAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.MongoClientSettings.Builder;\nimport com.mongodb.connection.TransportSettings;\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.MultiThreadIoEventLoopGroup;\nimport io.netty.channel.nio.NioIoHandler;\nimport io.netty.channel.socket.SocketChannel;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Reactive Mongo.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ MongoClient.class, Flux.class })\n@EnableConfigurationProperties(MongoProperties.class)\npublic final class MongoReactiveAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(MongoConnectionDetails.class)\n\tPropertiesMongoConnectionDetails mongoConnectionDetails(MongoProperties properties,\n\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\treturn new PropertiesMongoConnectionDetails(properties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMongoClient reactiveStreamsMongoClient(ObjectProvider<MongoClientSettingsBuilderCustomizer> builderCustomizers,\n\t\t\tMongoClientSettings settings) {\n\t\tReactiveMongoClientFactory factory = new ReactiveMongoClientFactory(\n\t\t\t\tbuilderCustomizers.orderedStream().toList());\n\t\treturn factory.createMongoClient(settings);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(MongoClientSettings.class)\n\tstatic class MongoClientSettingsConfiguration {\n\n\t\t@Bean\n\t\tMongoClientSettings mongoClientSettings() {\n\t\t\treturn MongoClientSettings.builder().build();\n\t\t}\n\n\t\t@Bean\n\t\tStandardMongoClientSettingsBuilderCustomizer standardMongoSettingsCustomizer(MongoProperties properties,\n\t\t\t\tMongoConnectionDetails connectionDetails) {\n\t\t\treturn new StandardMongoClientSettingsBuilderCustomizer(connectionDetails,\n\t\t\t\t\tproperties.getRepresentation().getUuid());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ SocketChannel.class, NioIoHandler.class })\n\tstatic class NettyDriverConfiguration {\n\n\t\t@Bean\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tNettyDriverMongoClientSettingsBuilderCustomizer nettyDriverCustomizer(\n\t\t\t\tObjectProvider<MongoClientSettings> settings) {\n\t\t\treturn new NettyDriverMongoClientSettingsBuilderCustomizer(settings);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link MongoClientSettingsBuilderCustomizer} to apply Mongo client settings.\n\t */\n\tstatic final class NettyDriverMongoClientSettingsBuilderCustomizer\n\t\t\timplements MongoClientSettingsBuilderCustomizer, DisposableBean {\n\n\t\tprivate final ObjectProvider<MongoClientSettings> settings;\n\n\t\tprivate volatile @Nullable EventLoopGroup eventLoopGroup;\n\n\t\tNettyDriverMongoClientSettingsBuilderCustomizer(ObjectProvider<MongoClientSettings> settings) {\n\t\t\tthis.settings = settings;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(Builder builder) {\n\t\t\tif (!isCustomTransportConfiguration(this.settings.getIfAvailable())) {\n\t\t\t\tEventLoopGroup eventLoopGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());\n\t\t\t\tthis.eventLoopGroup = eventLoopGroup;\n\t\t\t\tbuilder.transportSettings(TransportSettings.nettyBuilder().eventLoopGroup(eventLoopGroup).build());\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroy() {\n\t\t\tEventLoopGroup eventLoopGroup = this.eventLoopGroup;\n\t\t\tif (eventLoopGroup != null) {\n\t\t\t\teventLoopGroup.shutdownGracefully().awaitUninterruptibly();\n\t\t\t\tthis.eventLoopGroup = null;\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean isCustomTransportConfiguration(@Nullable MongoClientSettings settings) {\n\t\t\treturn settings != null && settings.getTransportSettings() != null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/PropertiesMongoConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport com.mongodb.ConnectionString;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.mongodb.autoconfigure.MongoProperties.Ssl;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Adapts {@link MongoProperties} to {@link MongoConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class PropertiesMongoConnectionDetails implements MongoConnectionDetails {\n\n\tprivate final MongoProperties properties;\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\tpublic PropertiesMongoConnectionDetails(MongoProperties properties, @Nullable SslBundles sslBundles) {\n\t\tthis.properties = properties;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic ConnectionString getConnectionString() {\n\t\t// protocol://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database.collection][?options]]\n\t\tif (this.properties.getUri() != null) {\n\t\t\treturn new ConnectionString(this.properties.getUri());\n\t\t}\n\t\tStringBuilder builder = new StringBuilder(getProtocol()).append(\"://\");\n\t\tif (this.properties.getUsername() != null) {\n\t\t\tbuilder.append(encode(this.properties.getUsername()));\n\t\t\tbuilder.append(\":\");\n\t\t\tif (this.properties.getPassword() != null) {\n\t\t\t\tbuilder.append(encode(this.properties.getPassword()));\n\t\t\t}\n\t\t\tbuilder.append(\"@\");\n\t\t}\n\t\tbuilder.append((this.properties.getHost() != null) ? this.properties.getHost() : \"localhost\");\n\t\tif (this.properties.getPort() != null) {\n\t\t\tbuilder.append(\":\");\n\t\t\tbuilder.append(this.properties.getPort());\n\t\t}\n\t\tif (this.properties.getAdditionalHosts() != null) {\n\t\t\tbuilder.append(\",\");\n\t\t\tbuilder.append(String.join(\",\", this.properties.getAdditionalHosts()));\n\t\t}\n\t\tbuilder.append(\"/\");\n\t\tbuilder.append(this.properties.getMongoClientDatabase());\n\t\tList<String> options = getOptions();\n\t\tif (!options.isEmpty()) {\n\t\t\tbuilder.append(\"?\");\n\t\t\tbuilder.append(String.join(\"&\", options));\n\t\t}\n\t\treturn new ConnectionString(builder.toString());\n\t}\n\n\tprivate String getProtocol() {\n\t\tString protocol = this.properties.getProtocol();\n\t\tif (StringUtils.hasText(protocol)) {\n\t\t\treturn protocol;\n\t\t}\n\t\treturn \"mongodb\";\n\t}\n\n\tprivate String encode(String input) {\n\t\treturn URLEncoder.encode(input, StandardCharsets.UTF_8);\n\t}\n\n\tprivate char[] encode(char[] input) {\n\t\treturn URLEncoder.encode(new String(input), StandardCharsets.UTF_8).toCharArray();\n\t}\n\n\t@Override\n\tpublic @Nullable SslBundle getSslBundle() {\n\t\tSsl ssl = this.properties.getSsl();\n\t\tif (!ssl.isEnabled()) {\n\t\t\treturn null;\n\t\t}\n\t\tif (StringUtils.hasLength(ssl.getBundle())) {\n\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\treturn this.sslBundles.getBundle(ssl.getBundle());\n\t\t}\n\t\treturn SslBundle.systemDefault();\n\t}\n\n\tprivate List<String> getOptions() {\n\t\tList<String> options = new ArrayList<>();\n\t\tif (StringUtils.hasText(this.properties.getReplicaSetName())) {\n\t\t\toptions.add(\"replicaSet=\" + this.properties.getReplicaSetName());\n\t\t}\n\t\tif (this.properties.getUsername() != null && this.properties.getAuthenticationDatabase() != null) {\n\t\t\toptions.add(\"authSource=\" + this.properties.getAuthenticationDatabase());\n\t\t}\n\t\treturn options;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/ReactiveMongoClientFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.List;\n\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport com.mongodb.reactivestreams.client.MongoClients;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A factory for a reactive {@link MongoClient}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class ReactiveMongoClientFactory extends MongoClientFactorySupport<MongoClient> {\n\n\t/**\n\t * Construct a factory for creating a {@link MongoClient}.\n\t * @param builderCustomizers a list of configuration settings customizers\n\t */\n\tpublic ReactiveMongoClientFactory(@Nullable List<MongoClientSettingsBuilderCustomizer> builderCustomizers) {\n\t\tsuper(builderCustomizers, MongoClients::create);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/StandardMongoClientSettingsBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.connection.SslSettings;\nimport org.bson.UuidRepresentation;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link MongoClientSettingsBuilderCustomizer} that applies standard settings to a\n * {@link MongoClientSettings}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class StandardMongoClientSettingsBuilderCustomizer implements MongoClientSettingsBuilderCustomizer, Ordered {\n\n\tprivate final UuidRepresentation uuidRepresentation;\n\n\tprivate final MongoConnectionDetails connectionDetails;\n\n\tprivate int order;\n\n\tpublic StandardMongoClientSettingsBuilderCustomizer(MongoConnectionDetails connectionDetails,\n\t\t\tUuidRepresentation uuidRepresentation) {\n\t\tthis.connectionDetails = connectionDetails;\n\t\tthis.uuidRepresentation = uuidRepresentation;\n\t}\n\n\t@Override\n\tpublic void customize(MongoClientSettings.Builder settingsBuilder) {\n\t\tsettingsBuilder.uuidRepresentation(this.uuidRepresentation);\n\t\tsettingsBuilder.applyConnectionString(this.connectionDetails.getConnectionString());\n\t\tsettingsBuilder.applyToSslSettings(this::configureSslIfNeeded);\n\t}\n\n\tprivate void configureSslIfNeeded(SslSettings.Builder settings) {\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tif (sslBundle != null) {\n\t\t\tsettings.enabled(true);\n\t\t\tAssert.state(!sslBundle.getOptions().isSpecified(), \"SSL options cannot be specified with MongoDB\");\n\t\t\tsettings.context(sslBundle.createSslContext());\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order value of this object.\n\t * @param order the new order value\n\t * @see #getOrder()\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/health/MongoHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure.health;\n\nimport com.mongodb.client.MongoClient;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.health.MongoHealthIndicator;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link MongoHealthIndicator}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = { MongoReactiveHealthContributorAutoConfiguration.class, MongoAutoConfiguration.class })\n@ConditionalOnClass({ MongoClient.class, MongoHealthIndicator.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(MongoClient.class)\n@ConditionalOnEnabledHealthIndicator(\"mongodb\")\npublic final class MongoHealthContributorAutoConfiguration\n\t\textends CompositeHealthContributorConfiguration<MongoHealthIndicator, MongoClient> {\n\n\tMongoHealthContributorAutoConfiguration() {\n\t\tsuper(MongoHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"mongoHealthIndicator\", \"mongoHealthContributor\" })\n\tHealthContributor mongoHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, MongoClient.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/health/MongoReactiveHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure.health;\n\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration;\nimport org.springframework.boot.mongodb.health.MongoReactiveHealthIndicator;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link MongoReactiveHealthIndicator}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = MongoReactiveAutoConfiguration.class)\n@ConditionalOnClass({ MongoClient.class, Flux.class, MongoReactiveHealthIndicator.class,\n\t\tConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(MongoClient.class)\n@ConditionalOnEnabledHealthIndicator(\"mongodb\")\npublic final class MongoReactiveHealthContributorAutoConfiguration\n\t\textends CompositeReactiveHealthContributorConfiguration<MongoReactiveHealthIndicator, MongoClient> {\n\n\tMongoReactiveHealthContributorAutoConfiguration() {\n\t\tsuper(MongoReactiveHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"mongoHealthIndicator\", \"mongoHealthContributor\" })\n\tReactiveHealthContributor mongoHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, MongoClient.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Data MongoDB health.\n */\n@NullMarked\npackage org.springframework.boot.mongodb.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/metrics/MongoMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure.metrics;\n\nimport com.mongodb.MongoClientSettings;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.mongodb.DefaultMongoCommandTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.DefaultMongoConnectionPoolTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;\nimport io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoClientSettingsBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Mongo metrics.\n *\n * @author Chris Bono\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@AutoConfiguration(before = MongoAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnClass({ MongoClientSettings.class, MeterRegistry.class })\n@ConditionalOnBean(MeterRegistry.class)\npublic final class MongoMetricsAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(MongoMetricsCommandListener.class)\n\t@ConditionalOnBooleanProperty(name = \"management.metrics.mongodb.command.enabled\", matchIfMissing = true)\n\tstatic class MongoCommandMetricsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tMongoMetricsCommandListener mongoMetricsCommandListener(MeterRegistry meterRegistry,\n\t\t\t\tMongoCommandTagsProvider mongoCommandTagsProvider) {\n\t\t\treturn new MongoMetricsCommandListener(meterRegistry, mongoCommandTagsProvider);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tMongoCommandTagsProvider mongoCommandTagsProvider() {\n\t\t\treturn new DefaultMongoCommandTagsProvider();\n\t\t}\n\n\t\t@Bean\n\t\tMongoClientSettingsBuilderCustomizer mongoMetricsCommandListenerClientSettingsBuilderCustomizer(\n\t\t\t\tMongoMetricsCommandListener mongoMetricsCommandListener) {\n\t\t\treturn (clientSettingsBuilder) -> clientSettingsBuilder.addCommandListener(mongoMetricsCommandListener);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(MongoMetricsConnectionPoolListener.class)\n\t@ConditionalOnBooleanProperty(name = \"management.metrics.mongodb.connectionpool.enabled\", matchIfMissing = true)\n\tstatic class MongoConnectionPoolMetricsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tMongoMetricsConnectionPoolListener mongoMetricsConnectionPoolListener(MeterRegistry meterRegistry,\n\t\t\t\tMongoConnectionPoolTagsProvider mongoConnectionPoolTagsProvider) {\n\t\t\treturn new MongoMetricsConnectionPoolListener(meterRegistry, mongoConnectionPoolTagsProvider);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tMongoConnectionPoolTagsProvider mongoConnectionPoolTagsProvider() {\n\t\t\treturn new DefaultMongoConnectionPoolTagsProvider();\n\t\t}\n\n\t\t@Bean\n\t\tMongoClientSettingsBuilderCustomizer mongoMetricsConnectionPoolListenerClientSettingsBuilderCustomizer(\n\t\t\t\tMongoMetricsConnectionPoolListener mongoMetricsConnectionPoolListener) {\n\t\t\treturn (clientSettingsBuilder) -> clientSettingsBuilder\n\t\t\t\t.applyToConnectionPoolSettings((connectionPoolSettingsBuilder) -> connectionPoolSettingsBuilder\n\t\t\t\t\t.addConnectionPoolListener(mongoMetricsConnectionPoolListener));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for MongoDB metrics.\n */\n@NullMarked\npackage org.springframework.boot.mongodb.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for MongoDB.\n */\n@NullMarked\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/docker/compose/MongoDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.docker.compose;\n\nimport com.mongodb.ConnectionString;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link MongoConnectionDetails}\n * for a {@code mongo} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MongoDockerComposeConnectionDetailsFactory extends DockerComposeConnectionDetailsFactory<MongoConnectionDetails> {\n\n\tprivate static final int MONGODB_PORT = 27017;\n\n\tprotected MongoDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mongo\", \"com.mongodb.ConnectionString\");\n\t}\n\n\t@Override\n\tprotected MongoDockerComposeConnectionDetails getDockerComposeConnectionDetails(\n\t\t\tDockerComposeConnectionSource source) {\n\t\treturn new MongoDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link MongoConnectionDetails} backed by a {@code mongo} {@link RunningService}.\n\t */\n\tstatic class MongoDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements MongoConnectionDetails {\n\n\t\tprivate final ConnectionString connectionString;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tMongoDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tthis.sslBundle = getSslBundle(service);\n\t\t\tthis.connectionString = buildConnectionString(service);\n\n\t\t}\n\n\t\tprivate ConnectionString buildConnectionString(RunningService service) {\n\t\t\tMongoEnvironment environment = new MongoEnvironment(service.env());\n\t\t\tStringBuilder builder = new StringBuilder(\"mongodb://\");\n\t\t\tif (environment.getUsername() != null) {\n\t\t\t\tbuilder.append(environment.getUsername());\n\t\t\t\tbuilder.append(\":\");\n\t\t\t\tbuilder.append((environment.getPassword() != null) ? environment.getPassword() : \"\");\n\t\t\t\tbuilder.append(\"@\");\n\t\t\t}\n\t\t\tbuilder.append(service.host());\n\t\t\tbuilder.append(\":\");\n\t\t\tbuilder.append(service.ports().get(MONGODB_PORT));\n\t\t\tbuilder.append(\"/\");\n\t\t\tbuilder.append((environment.getDatabase() != null) ? environment.getDatabase() : \"test\");\n\t\t\tif (environment.getUsername() != null) {\n\t\t\t\tbuilder.append(\"?authSource=admin\");\n\t\t\t}\n\t\t\treturn new ConnectionString(builder.toString());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionString getConnectionString() {\n\t\t\treturn this.connectionString;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/docker/compose/MongoEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * MongoDB environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MongoEnvironment {\n\n\tprivate final @Nullable String username;\n\n\tprivate final @Nullable String password;\n\n\tprivate final @Nullable String database;\n\n\tMongoEnvironment(Map<String, @Nullable String> env) {\n\t\tAssert.state(!env.containsKey(\"MONGO_INITDB_ROOT_USERNAME_FILE\"),\n\t\t\t\t\"MONGO_INITDB_ROOT_USERNAME_FILE is not supported\");\n\t\tAssert.state(!env.containsKey(\"MONGO_INITDB_ROOT_PASSWORD_FILE\"),\n\t\t\t\t\"MONGO_INITDB_ROOT_PASSWORD_FILE is not supported\");\n\t\tthis.username = env.getOrDefault(\"MONGO_INITDB_ROOT_USERNAME\", env.get(\"MONGODB_ROOT_USERNAME\"));\n\t\tthis.password = env.getOrDefault(\"MONGO_INITDB_ROOT_PASSWORD\", env.get(\"MONGODB_ROOT_PASSWORD\"));\n\t\tthis.database = env.getOrDefault(\"MONGO_INITDB_DATABASE\", env.get(\"MONGODB_DATABASE\"));\n\t}\n\n\t@Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\t@Nullable String getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose MongoDB service connections.\n */\n@NullMarked\npackage org.springframework.boot.mongodb.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/health/MongoHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.health;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.mongodb.client.MongoClient;\nimport org.bson.Document;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.util.Assert;\n\n/**\n * Simple implementation of a {@link HealthIndicator} returning status information for\n * MongoDB.\n *\n * @author Christian Dupuis\n * @since 4.0.0\n */\npublic class MongoHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate static final Document HELLO_COMMAND = Document.parse(\"{ hello: 1 }\");\n\n\tprivate final MongoClient mongoClient;\n\n\tpublic MongoHealthIndicator(MongoClient mongoClient) {\n\t\tsuper(\"MongoDB health check failed\");\n\t\tAssert.notNull(mongoClient, \"'mongoClient' must not be null\");\n\t\tthis.mongoClient = mongoClient;\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) throws Exception {\n\t\tMap<String, Object> details = new LinkedHashMap<>();\n\t\tList<String> databases = new ArrayList<>();\n\t\tdetails.put(\"databases\", databases);\n\t\tthis.mongoClient.listDatabaseNames().forEach((database) -> {\n\t\t\tDocument result = this.mongoClient.getDatabase(database).runCommand(HELLO_COMMAND);\n\t\t\tdatabases.add(database);\n\t\t\tdetails.putIfAbsent(\"maxWireVersion\", result.getInteger(\"maxWireVersion\"));\n\t\t});\n\t\tbuilder.up().withDetails(details);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/health/MongoReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.health;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport org.bson.Document;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link ReactiveHealthIndicator} for Mongo.\n *\n * @author Yulin Qin\n * @since 4.0.0\n */\npublic class MongoReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate static final Document HELLO_COMMAND = Document.parse(\"{ hello: 1 }\");\n\n\tprivate final MongoClient mongoClient;\n\n\tpublic MongoReactiveHealthIndicator(MongoClient mongoClient) {\n\t\tsuper(\"Mongo health check failed\");\n\t\tAssert.notNull(mongoClient, \"'mongoClient' must not be null\");\n\t\tthis.mongoClient = mongoClient;\n\t}\n\n\t@Override\n\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\tMono<Map<String, Object>> healthDetails = Flux.from(this.mongoClient.listDatabaseNames())\n\t\t\t.flatMap((database) -> Mono.from(this.mongoClient.getDatabase(database).runCommand(HELLO_COMMAND))\n\t\t\t\t.map((document) -> new HelloResponse(database, document)))\n\t\t\t.collectList()\n\t\t\t.map((responses) -> {\n\t\t\t\tMap<String, Object> databaseDetails = new LinkedHashMap<>();\n\t\t\t\tList<String> databases = new ArrayList<>();\n\t\t\t\tdatabaseDetails.put(\"databases\", databases);\n\t\t\t\tfor (HelloResponse response : responses) {\n\t\t\t\t\tdatabases.add(response.database());\n\t\t\t\t\tdatabaseDetails.putIfAbsent(\"maxWireVersion\", response.document().getInteger(\"maxWireVersion\"));\n\t\t\t\t}\n\t\t\t\treturn databaseDetails;\n\t\t\t});\n\t\treturn healthDetails.map((details) -> builder.up().withDetails(details).build());\n\t}\n\n\tprivate record HelloResponse(String database, Document document) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * MongoDB health integration using Spring Data MongoDB.\n */\n@NullMarked\npackage org.springframework.boot.mongodb.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport java.util.function.Function;\n\nimport com.mongodb.ConnectionString;\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * Abstract {@link ContainerConnectionDetailsFactory} to create\n * {@link MongoConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated MongoDB container.\n *\n * @param <T> type of MongoDB container supported by the factory\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Wouter Blancquaert\n */\nabstract class AbstractMongoContainerConnectionDetailsFactory<T extends GenericContainer<T>>\n\t\textends ContainerConnectionDetailsFactory<T, MongoConnectionDetails> {\n\n\tprivate final Function<T, String> connectionStringFunction;\n\n\tAbstractMongoContainerConnectionDetailsFactory(Function<T, String> connectionStringFunction) {\n\t\tsuper(ANY_CONNECTION_NAME, \"com.mongodb.ConnectionString\");\n\t\tthis.connectionStringFunction = connectionStringFunction;\n\t}\n\n\t@Override\n\tprotected MongoConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<T> source) {\n\t\treturn new MongoContainerConnectionDetails<>(source, this.connectionStringFunction);\n\t}\n\n\t/**\n\t * {@link MongoConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MongoContainerConnectionDetails<T extends GenericContainer<T>>\n\t\t\textends ContainerConnectionDetails<T> implements MongoConnectionDetails {\n\n\t\tprivate final Function<T, String> connectionStringFunction;\n\n\t\tprivate MongoContainerConnectionDetails(ContainerConnectionSource<T> source,\n\t\t\t\tFunction<T, String> connectionStringFunction) {\n\t\t\tsuper(source);\n\t\t\tthis.connectionStringFunction = connectionStringFunction;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionString getConnectionString() {\n\t\t\treturn new ConnectionString(this.connectionStringFunction.apply(getContainer()));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/DeprecatedMongoDbContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport org.testcontainers.containers.MongoDBContainer;\n\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MongoDBContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link MongoDbContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedMongoDbContainerConnectionDetailsFactory\n\t\textends AbstractMongoContainerConnectionDetailsFactory<MongoDBContainer> {\n\n\tDeprecatedMongoDbContainerConnectionDetailsFactory() {\n\t\tsuper(MongoDBContainer::getReplicaSetUrl);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport org.testcontainers.mongodb.MongoDBAtlasLocalContainer;\n\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated\n * {@link MongoDBAtlasLocalContainer}.\n *\n * @author Wouter Blancquaert\n */\nclass MongoDbAtlasLocalContainerConnectionDetailsFactory\n\t\textends AbstractMongoContainerConnectionDetailsFactory<MongoDBAtlasLocalContainer> {\n\n\tMongoDbAtlasLocalContainerConnectionDetailsFactory() {\n\t\tsuper(MongoDBAtlasLocalContainer::getDatabaseConnectionString);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MongoDBContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass MongoDbContainerConnectionDetailsFactory\n\t\textends AbstractMongoContainerConnectionDetailsFactory<MongoDBContainer> {\n\n\tMongoDbContainerConnectionDetailsFactory() {\n\t\tsuper(MongoDBContainer::getReplicaSetUrl);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers MongoDB service connections.\n */\n@NullMarked\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.metrics.mongo.command.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.metrics.mongodb.command.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.mongo.connectionpool.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.metrics.mongodb.connectionpool.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"management.metrics.mongodb.command.enabled\",\n      \"description\": \"Whether to enable Mongo client command metrics.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"management.metrics.mongodb.connectionpool.enabled\",\n      \"description\": \"Whether to enable Mongo connection pool metrics.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.data.mongodb.additional-hosts\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.additional-hosts\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.authentication-database\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.authentication-database\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.database\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.database\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.host\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.host\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.password\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.password\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.port\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.port\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.protocol\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.protocol\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.replica-set-name\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.replica-set-name\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.ssl.bundle\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.ssl.bundle\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.ssl.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.ssl.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.uri\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.uri\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.username\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.username\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.data.mongodb.uuid-representation\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mongodb.representation.uuid\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mongodb.uri\",\n      \"defaultValue\": \"mongodb://localhost/test\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.mongodb.protocol\",\n      \"values\": [\n        {\n          \"value\": \"mongodb\"\n        },\n        {\n          \"value\": \"mongodb+srv\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration\norg.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration\norg.springframework.boot.mongodb.autoconfigure.health.MongoHealthContributorAutoConfiguration\norg.springframework.boot.mongodb.autoconfigure.health.MongoReactiveHealthContributorAutoConfiguration\norg.springframework.boot.mongodb.autoconfigure.metrics.MongoMetricsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.mongodb.docker.compose.MongoDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.mongodb.testcontainers.DeprecatedMongoDbContainerConnectionDetailsFactory,\\\norg.springframework.boot.mongodb.testcontainers.MongoDbAtlasLocalContainerConnectionDetailsFactory,\\\norg.springframework.boot.mongodb.testcontainers.MongoDbContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/MongoAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.concurrent.TimeUnit;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.MongoCredential;\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoClients;\nimport com.mongodb.client.internal.MongoClientImpl;\nimport com.mongodb.connection.ClusterConnectionMode;\nimport com.mongodb.connection.SslSettings;\nimport org.bson.UuidRepresentation;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MongoAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass MongoAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid clientExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));\n\t}\n\n\t@Test\n\tvoid settingsAdded() {\n\t\tthis.contextRunner.withUserConfiguration(SettingsConfig.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tgetSettings(context).getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS))\n\t\t\t\t.isEqualTo(300));\n\t}\n\n\t@Test\n\tvoid settingsAddedButNoHost() {\n\t\tthis.contextRunner.withUserConfiguration(SettingsConfig.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tgetSettings(context).getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS))\n\t\t\t\t.isEqualTo(300));\n\t}\n\n\t@Test\n\tvoid settingsSslConfig() {\n\t\tthis.contextRunner.withUserConfiguration(SslSettingsConfig.class)\n\t\t\t.run((context) -> assertThat(getSettings(context).getSslSettings().isEnabled()).isTrue());\n\t}\n\n\t@Test\n\tvoid configuresSslWhenEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.ssl.enabled=true\").run((context) -> {\n\t\t\tSslSettings sslSettings = getSettings(context).getSslSettings();\n\t\t\tassertThat(sslSettings.isEnabled()).isTrue();\n\t\t\tassertThat(sslSettings.getContext()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid configuresSslWithBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.ssl.bundle=test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password=secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tSslSettings sslSettings = getSettings(context).getSslSettings();\n\t\t\t\tassertThat(sslSettings.isEnabled()).isTrue();\n\t\t\t\tassertThat(sslSettings.getContext()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresProtocol() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.protocol=mongodb+srv\").run((context) -> {\n\t\t\tMongoClientSettings settings = getSettings(context);\n\t\t\tassertThat(settings.getClusterSettings().getMode()).isEqualTo(ClusterConnectionMode.MULTIPLE);\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultProtocol() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMongoClientSettings settings = getSettings(context);\n\t\t\tassertThat(settings.getClusterSettings().getMode()).isEqualTo(ClusterConnectionMode.SINGLE);\n\t\t});\n\t}\n\n\t@Test\n\tvoid configuresWithoutSslWhenDisabledWithBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.ssl.enabled=false\", \"spring.mongodb.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tSslSettings sslSettings = getSettings(context).getSslSettings();\n\t\t\t\tassertThat(sslSettings.isEnabled()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotConfigureCredentialsWithoutUsername() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.password=secret\", \"spring.mongodb.authentication-database=authdb\")\n\t\t\t.run((context) -> assertThat(getSettings(context).getCredential()).isNull());\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithDefaultDatabase() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.username=user\", \"spring.mongodb.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.username=user\", \"spring.mongodb.password=secret\",\n\t\t\t\t\t\"spring.mongodb.database=mydb\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithAuthDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.username=user\", \"spring.mongodb.password=secret\",\n\t\t\t\t\t\"spring.mongodb.database=mydb\", \"spring.mongodb.authentication-database=authdb\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"authdb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithSpecialCharacters() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.username=us:er\", \"spring.mongodb.password=sec@ret\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"us:er\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"sec@ret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotConfigureCredentialsWithoutUsernameInUri() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://localhost/mydb?authSource=authdb\")\n\t\t\t.run((context) -> assertThat(getSettings(context).getCredential()).isNull());\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromUriPropertyWithDefaultDatabase() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://user:secret@localhost/\").run((context) -> {\n\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\tassertThat(credential).isNotNull();\n\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\tassertThat(credential.getSource()).isEqualTo(\"admin\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromUriPropertyWithDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://user:secret@localhost/mydb\",\n\t\t\t\t\t\"spring.mongodb.database=notused\", \"spring.mongodb.authentication-database=notused\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromUriPropertyWithAuthDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://user:secret@localhost/mydb?authSource=authdb\",\n\t\t\t\t\t\"spring.mongodb.database=notused\", \"spring.mongodb.authentication-database=notused\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"authdb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureUuidRepresentation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.representation.uuid=standard\")\n\t\t\t.run((context) -> assertThat(getSettings(context).getUuidRepresentation())\n\t\t\t\t.isEqualTo(UuidRepresentation.STANDARD));\n\t}\n\n\t@Test\n\tvoid configuresSingleClient() {\n\t\tthis.contextRunner.withUserConfiguration(FallbackMongoClientConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));\n\t}\n\n\t@Test\n\tvoid customizerOverridesAutoConfig() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri:mongodb://localhost/test?appname=auto-config\")\n\t\t\t.withUserConfiguration(SimpleCustomizerConfig.class)\n\t\t\t.run((context) -> assertThat(getSettings(context).getApplicationName()).isEqualTo(\"overridden-name\"));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesMongoConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(MongoConnectionDetails.class, () -> new MongoConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic ConnectionString getConnectionString() {\n\t\t\t\treturn new ConnectionString(\"mongodb://localhost\");\n\t\t\t}\n\n\t\t})\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesMongoConnectionDetails.class));\n\t}\n\n\tprivate MongoClientSettings getSettings(AssertableApplicationContext context) {\n\t\tassertThat(context).hasSingleBean(MongoClient.class);\n\t\tMongoClientImpl client = (MongoClientImpl) context.getBean(MongoClient.class);\n\t\treturn client.getSettings();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SettingsConfig {\n\n\t\t@Bean\n\t\tMongoClientSettings mongoClientSettings() {\n\t\t\treturn MongoClientSettings.builder()\n\t\t\t\t.applyToSocketSettings((socketSettings) -> socketSettings.connectTimeout(300, TimeUnit.MILLISECONDS))\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SslSettingsConfig {\n\n\t\t@Bean\n\t\tMongoClientSettings mongoClientSettings() {\n\t\t\treturn MongoClientSettings.builder().applyToSslSettings((ssl) -> ssl.enabled(true)).build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FallbackMongoClientConfig {\n\n\t\t@Bean\n\t\tMongoClient fallbackMongoClient() {\n\t\t\treturn MongoClients.create();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleCustomizerConfig {\n\n\t\t@Bean\n\t\tMongoClientSettingsBuilderCustomizer customizer() {\n\t\t\treturn (clientSettingsBuilder) -> clientSettingsBuilder.applicationName(\"overridden-name\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/MongoClientFactorySupportTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport com.mongodb.MongoClientSettings;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MongoClientFactorySupport}.\n *\n * @param <T> the mongo client type\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Artsiom Yudovin\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nabstract class MongoClientFactorySupportTests<T> {\n\n\t@Test\n\tvoid allMongoClientSettingsCanBeSet() {\n\t\tMongoClientSettings.Builder builder = MongoClientSettings.builder();\n\t\tbuilder.applyToSocketSettings((settings) -> {\n\t\t\tsettings.connectTimeout(1000, TimeUnit.MILLISECONDS);\n\t\t\tsettings.readTimeout(1000, TimeUnit.MILLISECONDS);\n\t\t}).applyToServerSettings((settings) -> {\n\t\t\tsettings.heartbeatFrequency(10001, TimeUnit.MILLISECONDS);\n\t\t\tsettings.minHeartbeatFrequency(501, TimeUnit.MILLISECONDS);\n\t\t}).applyToConnectionPoolSettings((settings) -> {\n\t\t\tsettings.maxWaitTime(120001, TimeUnit.MILLISECONDS);\n\t\t\tsettings.maxConnectionLifeTime(60000, TimeUnit.MILLISECONDS);\n\t\t\tsettings.maxConnectionIdleTime(60000, TimeUnit.MILLISECONDS);\n\t\t}).applyToSslSettings((settings) -> settings.enabled(true)).applicationName(\"test\");\n\n\t\tMongoClientSettings settings = builder.build();\n\t\tT client = createMongoClient(settings);\n\t\tMongoClientSettings wrapped = getClientSettings(client);\n\t\tassertThat(wrapped.getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getSocketSettings().getConnectTimeout(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getSocketSettings().getReadTimeout(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getSocketSettings().getReadTimeout(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getServerSettings().getHeartbeatFrequency(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getServerSettings().getHeartbeatFrequency(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getServerSettings().getMinHeartbeatFrequency(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getServerSettings().getMinHeartbeatFrequency(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getApplicationName()).isEqualTo(settings.getApplicationName());\n\t\tassertThat(wrapped.getConnectionPoolSettings().getMaxWaitTime(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getConnectionPoolSettings().getMaxWaitTime(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getConnectionPoolSettings().getMaxConnectionLifeTime(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getConnectionPoolSettings().getMaxConnectionLifeTime(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getConnectionPoolSettings().getMaxConnectionIdleTime(TimeUnit.MILLISECONDS))\n\t\t\t.isEqualTo(settings.getConnectionPoolSettings().getMaxConnectionIdleTime(TimeUnit.MILLISECONDS));\n\t\tassertThat(wrapped.getSslSettings().isEnabled()).isEqualTo(settings.getSslSettings().isEnabled());\n\t}\n\n\t@Test\n\tvoid customizerIsInvoked() {\n\t\tMongoClientSettingsBuilderCustomizer customizer = mock(MongoClientSettingsBuilderCustomizer.class);\n\t\tcreateMongoClient(customizer);\n\t\tthen(customizer).should().customize(any(MongoClientSettings.Builder.class));\n\t}\n\n\tprotected T createMongoClient(MongoClientSettings settings) {\n\t\treturn createMongoClient(null, settings);\n\t}\n\n\tprotected void createMongoClient(MongoClientSettingsBuilderCustomizer... customizers) {\n\t\tcreateMongoClient((customizers != null) ? Arrays.asList(customizers) : null,\n\t\t\t\tMongoClientSettings.builder().build());\n\t}\n\n\tprotected abstract T createMongoClient(@Nullable List<MongoClientSettingsBuilderCustomizer> customizers,\n\t\t\tMongoClientSettings settings);\n\n\tprotected abstract MongoClientSettings getClientSettings(T client);\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(MongoProperties.class)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/MongoClientFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.List;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.internal.MongoClientImpl;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Tests for {@link MongoClientFactory}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Mark Paluch\n * @author Scott Frederick\n */\nclass MongoClientFactoryTests extends MongoClientFactorySupportTests<MongoClient> {\n\n\t@Override\n\tprotected MongoClient createMongoClient(@Nullable List<MongoClientSettingsBuilderCustomizer> customizers,\n\t\t\tMongoClientSettings settings) {\n\t\treturn new MongoClientFactory(customizers).createMongoClient(settings);\n\t}\n\n\t@Override\n\tprotected MongoClientSettings getClientSettings(MongoClient client) {\n\t\treturn ((MongoClientImpl) client).getSettings();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/MongoPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport org.bson.UuidRepresentation;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.data.mongodb.config.MongoConfigurationSupport;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MongoProperties}.\n *\n * @author Andy Wilkinson\n */\nclass MongoPropertiesTests {\n\n\t@Test\n\tvoid defaultUuidRepresentationIsAlignedWithSpringData() {\n\t\tUuidRepresentation springDataDefault = springDataDefaultUuidRepresentation();\n\t\tUuidRepresentation springBootDefault = new MongoProperties().getRepresentation().getUuid();\n\t\tassertThat(springBootDefault).isEqualTo(springDataDefault);\n\t}\n\n\t@Test\n\tvoid canBindCharArrayPassword() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.mongodb.password:word\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoProperties properties = context.getBean(MongoProperties.class);\n\t\t\t\tassertThat(properties.getPassword()).isEqualTo(\"word\".toCharArray());\n\t\t\t});\n\t}\n\n\tprivate UuidRepresentation springDataDefaultUuidRepresentation() {\n\t\treturn new MongoConfigurationSupport() {\n\n\t\t\t@Override\n\t\t\tprotected String getDatabaseName() {\n\t\t\t\treturn \"test\";\n\t\t\t}\n\n\t\t\tUuidRepresentation defaultUuidRepresentation() {\n\t\t\t\treturn mongoClientSettings().getUuidRepresentation();\n\t\t\t}\n\n\t\t}.defaultUuidRepresentation();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/MongoReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.MongoCredential;\nimport com.mongodb.ReadPreference;\nimport com.mongodb.connection.NettyTransportSettings;\nimport com.mongodb.connection.SslSettings;\nimport com.mongodb.connection.TransportSettings;\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport com.mongodb.reactivestreams.client.internal.MongoClientImpl;\nimport io.netty.channel.EventLoopGroup;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MongoReactiveAutoConfiguration}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n */\nclass MongoReactiveAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoReactiveAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid clientExists() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoClient.class));\n\t}\n\n\t@Test\n\tvoid settingsAdded() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.host:localhost\")\n\t\t\t.withUserConfiguration(SettingsConfig.class)\n\t\t\t.run((context) -> assertThat(getSettings(context).getSocketSettings().getReadTimeout(TimeUnit.SECONDS))\n\t\t\t\t.isEqualTo(300));\n\t}\n\n\t@Test\n\tvoid settingsAddedButNoHost() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri:mongodb://localhost/test\")\n\t\t\t.withUserConfiguration(SettingsConfig.class)\n\t\t\t.run((context) -> assertThat(getSettings(context).getReadPreference()).isEqualTo(ReadPreference.nearest()));\n\t}\n\n\t@Test\n\tvoid settingsSslConfig() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri:mongodb://localhost/test\")\n\t\t\t.withUserConfiguration(SslSettingsConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(MongoClient.class);\n\t\t\t\tMongoClientSettings settings = getSettings(context);\n\t\t\t\tassertThat(settings.getApplicationName()).isEqualTo(\"test-config\");\n\t\t\t\tassertThat(settings.getTransportSettings()).isSameAs(context.getBean(\"myTransportSettings\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresSslWhenEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.ssl.enabled=true\").run((context) -> {\n\t\t\tSslSettings sslSettings = getSettings(context).getSslSettings();\n\t\t\tassertThat(sslSettings.isEnabled()).isTrue();\n\t\t\tassertThat(sslSettings.getContext()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid configuresSslWithBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.ssl.bundle=test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.password=secret\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tSslSettings sslSettings = getSettings(context).getSslSettings();\n\t\t\t\tassertThat(sslSettings.isEnabled()).isTrue();\n\t\t\t\tassertThat(sslSettings.getContext()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresWithoutSslWhenDisabledWithBundle() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.ssl.enabled=false\", \"spring.mongodb.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tSslSettings sslSettings = getSettings(context).getSslSettings();\n\t\t\t\tassertThat(sslSettings.isEnabled()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotConfigureCredentialsWithoutUsername() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.password=secret\", \"spring.mongodb.authentication-database=authdb\")\n\t\t\t.run((context) -> assertThat(getSettings(context).getCredential()).isNull());\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithDefaultDatabase() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.username=user\", \"spring.mongodb.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.username=user\", \"spring.mongodb.password=secret\",\n\t\t\t\t\t\"spring.mongodb.database=mydb\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromPropertiesWithAuthDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.username=user\", \"spring.mongodb.password=secret\",\n\t\t\t\t\t\"spring.mongodb.database=mydb\", \"spring.mongodb.authentication-database=authdb\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"authdb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotConfigureCredentialsWithoutUsernameInUri() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://localhost/mydb?authSource=authdb\")\n\t\t\t.run((context) -> assertThat(getSettings(context).getCredential()).isNull());\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromUriPropertyWithDefaultDatabase() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri=mongodb://user:secret@localhost/\").run((context) -> {\n\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\tassertThat(credential).isNotNull();\n\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\tassertThat(credential.getSource()).isEqualTo(\"admin\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromUriPropertyWithDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://user:secret@localhost/mydb\",\n\t\t\t\t\t\"spring.mongodb.database=notused\", \"spring.mongodb.authentication-database=notused\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"mydb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configuresCredentialsFromUriPropertyWithAuthDatabase() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mongodb.uri=mongodb://user:secret@localhost/mydb?authSource=authdb\",\n\t\t\t\t\t\"spring.mongodb.database=notused\", \"spring.mongodb.authentication-database=notused\")\n\t\t\t.run((context) -> {\n\t\t\t\tMongoCredential credential = getSettings(context).getCredential();\n\t\t\t\tassertThat(credential).isNotNull();\n\t\t\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\t\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\t\t\tassertThat(credential.getSource()).isEqualTo(\"authdb\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid nettyTransportSettingsAreConfiguredAutomatically() {\n\t\tAtomicReference<EventLoopGroup> eventLoopGroupReference = new AtomicReference<>();\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MongoClient.class);\n\t\t\tTransportSettings transportSettings = getSettings(context).getTransportSettings();\n\t\t\tassertThat(transportSettings).isInstanceOf(NettyTransportSettings.class);\n\t\t\tEventLoopGroup eventLoopGroup = ((NettyTransportSettings) transportSettings).getEventLoopGroup();\n\t\t\tassertThat(eventLoopGroup).isNotNull();\n\t\t\tassertThat(eventLoopGroup.isShutdown()).isFalse();\n\t\t\teventLoopGroupReference.set(eventLoopGroup);\n\t\t});\n\t\tEventLoopGroup eventLoopGroup = eventLoopGroupReference.get();\n\t\tassertThat(eventLoopGroup).isNotNull();\n\t\tassertThat(eventLoopGroup.isShutdown()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"deprecation\")\n\tvoid customizerWithTransportSettingsOverridesAutoConfig() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mongodb.uri:mongodb://localhost/test?appname=auto-config\")\n\t\t\t.withUserConfiguration(SimpleTransportSettingsCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(MongoClient.class);\n\t\t\t\tMongoClientSettings settings = getSettings(context);\n\t\t\t\tassertThat(settings.getApplicationName()).isEqualTo(\"custom-transport-settings\");\n\t\t\t\tassertThat(settings.getTransportSettings())\n\t\t\t\t\t.isSameAs(SimpleTransportSettingsCustomizerConfig.transportSettings);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesMongoConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(MongoConnectionDetails.class, () -> new MongoConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic ConnectionString getConnectionString() {\n\t\t\t\treturn new ConnectionString(\"mongodb://localhost\");\n\t\t\t}\n\n\t\t})\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesMongoConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid uuidRepresentationDefaultsAreAligned() {\n\t\tthis.contextRunner.run((context) -> assertThat(getSettings(context).getUuidRepresentation())\n\t\t\t.isEqualTo(new MongoProperties().getRepresentation().getUuid()));\n\t}\n\n\tprivate MongoClientSettings getSettings(ApplicationContext context) {\n\t\tMongoClientImpl client = (MongoClientImpl) context.getBean(MongoClient.class);\n\t\treturn client.getSettings();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SettingsConfig {\n\n\t\t@Bean\n\t\tMongoClientSettings mongoClientSettings() {\n\t\t\treturn MongoClientSettings.builder()\n\t\t\t\t.readPreference(ReadPreference.nearest())\n\t\t\t\t.applyToSocketSettings((socket) -> socket.readTimeout(300, TimeUnit.SECONDS))\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SslSettingsConfig {\n\n\t\t@Bean\n\t\tMongoClientSettings mongoClientSettings(TransportSettings transportSettings) {\n\t\t\treturn MongoClientSettings.builder()\n\t\t\t\t.applicationName(\"test-config\")\n\t\t\t\t.transportSettings(transportSettings)\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tTransportSettings myTransportSettings() {\n\t\t\treturn TransportSettings.nettyBuilder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SimpleTransportSettingsCustomizerConfig {\n\n\t\tprivate static final TransportSettings transportSettings = TransportSettings.nettyBuilder().build();\n\n\t\t@Bean\n\t\tMongoClientSettingsBuilderCustomizer customizer() {\n\t\t\treturn (clientSettingsBuilder) -> clientSettingsBuilder.applicationName(\"custom-transport-settings\")\n\t\t\t\t.transportSettings(transportSettings);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/PropertiesMongoConnectionDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.List;\n\nimport com.mongodb.ConnectionString;\nimport com.mongodb.MongoCredential;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PropertiesMongoConnectionDetails}.\n *\n * @author Christoph Dreis\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\nclass PropertiesMongoConnectionDetailsTests {\n\n\tprivate MongoProperties properties;\n\n\tprivate DefaultSslBundleRegistry sslBundleRegistry;\n\n\tprivate PropertiesMongoConnectionDetails connectionDetails;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new MongoProperties();\n\t\tthis.sslBundleRegistry = new DefaultSslBundleRegistry();\n\t\tthis.connectionDetails = new PropertiesMongoConnectionDetails(this.properties, this.sslBundleRegistry);\n\t}\n\n\t@Test\n\tvoid credentialsCanBeConfiguredWithUsername() {\n\t\tthis.properties.setUsername(\"user\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(connectionString.getPassword()).isEmpty();\n\t\tMongoCredential credential = connectionString.getCredential();\n\t\tassertThat(credential).isNotNull();\n\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\tassertThat(credential.getPassword()).isEmpty();\n\t\tassertThat(credential.getSource()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid credentialsCanBeConfiguredWithUsernameAndPassword() {\n\t\tthis.properties.setUsername(\"user\");\n\t\tthis.properties.setPassword(\"secret\".toCharArray());\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getUsername()).isEqualTo(\"user\");\n\t\tassertThat(connectionString.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\tMongoCredential credential = connectionString.getCredential();\n\t\tassertThat(credential).isNotNull();\n\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t\tassertThat(credential.getPassword()).isEqualTo(\"secret\".toCharArray());\n\t\tassertThat(credential.getSource()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid databaseCanBeConfigured() {\n\t\tthis.properties.setDatabase(\"db\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid databaseHasDefaultWhenNotConfigured() {\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getDatabase()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid protocolCanBeConfigured() {\n\t\tthis.properties.setProtocol(\"mongodb+srv\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getConnectionString()).startsWith(\"mongodb+srv://\");\n\t}\n\n\t@Test\n\tvoid authenticationDatabaseCanBeConfigured() {\n\t\tthis.properties.setUsername(\"user\");\n\t\tthis.properties.setDatabase(\"db\");\n\t\tthis.properties.setAuthenticationDatabase(\"authdb\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getDatabase()).isEqualTo(\"db\");\n\t\tMongoCredential credential = connectionString.getCredential();\n\t\tassertThat(credential).isNotNull();\n\t\tassertThat(credential.getSource()).isEqualTo(\"authdb\");\n\t\tassertThat(credential.getUserName()).isEqualTo(\"user\");\n\t}\n\n\t@Test\n\tvoid authenticationDatabaseIsNotConfiguredWhenUsernameIsNotConfigured() {\n\t\tthis.properties.setAuthenticationDatabase(\"authdb\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getCredential()).isNull();\n\t}\n\n\t@Test\n\tvoid replicaSetCanBeConfigured() {\n\t\tthis.properties.setReplicaSetName(\"test\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getRequiredReplicaSetName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid replicaSetCanBeConfiguredWithDatabase() {\n\t\tthis.properties.setUsername(\"user\");\n\t\tthis.properties.setDatabase(\"db\");\n\t\tthis.properties.setReplicaSetName(\"test\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getDatabase()).isEqualTo(\"db\");\n\t\tassertThat(connectionString.getRequiredReplicaSetName()).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid replicaSetCanBeNull() {\n\t\tthis.properties.setReplicaSetName(null);\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getRequiredReplicaSetName()).isNull();\n\t}\n\n\t@Test\n\tvoid replicaSetCanBeBlank() {\n\t\tthis.properties.setReplicaSetName(\"\");\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getRequiredReplicaSetName()).isNull();\n\t}\n\n\t@Test\n\tvoid whenAdditionalHostsAreConfiguredThenTheyAreIncludedInHostsOfConnectionString() {\n\t\tthis.properties.setHost(\"mongo1.example.com\");\n\t\tthis.properties.setAdditionalHosts(List.of(\"mongo2.example.com\", \"mongo3.example.com\"));\n\t\tConnectionString connectionString = this.connectionDetails.getConnectionString();\n\t\tassertThat(connectionString.getHosts()).containsExactly(\"mongo1.example.com\", \"mongo2.example.com\",\n\t\t\t\t\"mongo3.example.com\");\n\t}\n\n\t@Test\n\tvoid shouldReturnSslBundle() {\n\t\tSslBundle bundle1 = mock(SslBundle.class);\n\t\tthis.sslBundleRegistry.registerBundle(\"bundle-1\", bundle1);\n\t\tthis.properties.getSsl().setBundle(\"bundle-1\");\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isSameAs(bundle1);\n\t}\n\n\t@Test\n\tvoid shouldReturnSystemDefaultBundleIfSslIsEnabledButBundleNotSet() {\n\t\tthis.properties.getSsl().setEnabled(true);\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n\t@Test\n\tvoid shouldReturnNullIfSslIsNotEnabled() {\n\t\tthis.properties.getSsl().setEnabled(false);\n\t\tSslBundle sslBundle = this.connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/ReactiveMongoClientFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure;\n\nimport java.util.List;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport com.mongodb.reactivestreams.client.internal.MongoClientImpl;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Tests for {@link ReactiveMongoClientFactory}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass ReactiveMongoClientFactoryTests extends MongoClientFactorySupportTests<MongoClient> {\n\n\t@Override\n\tprotected MongoClient createMongoClient(@Nullable List<MongoClientSettingsBuilderCustomizer> customizers,\n\t\t\tMongoClientSettings settings) {\n\t\treturn new ReactiveMongoClientFactory(customizers).createMongoClient(settings);\n\t}\n\n\t@Override\n\tprotected MongoClientSettings getClientSettings(MongoClient client) {\n\t\treturn ((MongoClientImpl) client).getSettings();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/health/MongoHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.health.MongoHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MongoHealthContributorAutoConfiguration}\n *\n * @author Phillip Webb\n */\nclass MongoHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class,\n\t\t\t\tMongoHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.mongodb.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MongoHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/health/MongoReactiveHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.mongodb.autoconfigure.MongoReactiveAutoConfiguration;\nimport org.springframework.boot.mongodb.health.MongoHealthIndicator;\nimport org.springframework.boot.mongodb.health.MongoReactiveHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MongoReactiveHealthContributorAutoConfiguration}.\n *\n * @author Yulin Qin\n */\nclass MongoReactiveHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, MongoReactiveAutoConfiguration.class,\n\t\t\t\tMongoReactiveHealthContributorAutoConfiguration.class, HealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MongoReactiveHealthIndicator.class)\n\t\t\t.hasBean(\"mongoHealthContributor\"));\n\t}\n\n\t@Test\n\tvoid runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(MongoHealthContributorAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MongoReactiveHealthIndicator.class)\n\t\t\t\t.hasBean(\"mongoHealthContributor\")\n\t\t\t\t.doesNotHaveBean(MongoHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withPropertyValues(\"management.health.mongodb.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MongoReactiveHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(\"mongoHealthContributor\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/autoconfigure/metrics/MongoMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.autoconfigure.metrics;\n\nimport java.util.List;\n\nimport com.mongodb.MongoClientSettings;\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.internal.MongoClientImpl;\nimport com.mongodb.connection.ConnectionPoolSettings;\nimport com.mongodb.event.ConnectionPoolListener;\nimport io.micrometer.core.instrument.binder.mongodb.DefaultMongoCommandTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.DefaultMongoConnectionPoolTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.MongoCommandTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.MongoConnectionPoolTagsProvider;\nimport io.micrometer.core.instrument.binder.mongodb.MongoMetricsCommandListener;\nimport io.micrometer.core.instrument.binder.mongodb.MongoMetricsConnectionPoolListener;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.mongodb.autoconfigure.MongoAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MongoMetricsAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Johnny Lim\n */\nclass MongoMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MongoMetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid whenThereIsAMeterRegistryThenMetricsCommandListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(MongoMetricsCommandListener.class);\n\t\t\t\tassertThat(getActualMongoClientSettingsUsedToConstructClient(context))\n\t\t\t\t\t.extracting(MongoClientSettings::getCommandListeners)\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.containsExactly(context.getBean(MongoMetricsCommandListener.class));\n\t\t\t\tassertThat(getMongoCommandTagsProviderUsedToConstructListener(context))\n\t\t\t\t\t.isInstanceOf(DefaultMongoCommandTagsProvider.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenThereIsAMeterRegistryThenMetricsConnectionPoolListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(MongoMetricsConnectionPoolListener.class);\n\t\t\t\tassertThat(getConnectionPoolListenersFromClient(context))\n\t\t\t\t\t.containsExactly(context.getBean(MongoMetricsConnectionPoolListener.class));\n\t\t\t\tassertThat(getMongoConnectionPoolTagsProviderUsedToConstructListener(context))\n\t\t\t\t\t.isInstanceOf(DefaultMongoConnectionPoolTagsProvider.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMeterRegistryThenNoMetricsCommandListenerIsAdded() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.run(assertThatMetricsCommandListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMeterRegistryThenNoMetricsConnectionPoolListenerIsAdded() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.run(assertThatMetricsConnectionPoolListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenThereIsACustomMetricsCommandTagsProviderItIsUsed() {\n\t\tfinal MongoCommandTagsProvider customTagsProvider = mock(MongoCommandTagsProvider.class);\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withBean(\"customMongoCommandTagsProvider\", MongoCommandTagsProvider.class, () -> customTagsProvider)\n\t\t\t.run((context) -> assertThat(getMongoCommandTagsProviderUsedToConstructListener(context))\n\t\t\t\t.isSameAs(customTagsProvider));\n\t}\n\n\t@Test\n\tvoid whenThereIsACustomMetricsConnectionPoolTagsProviderItIsUsed() {\n\t\tfinal MongoConnectionPoolTagsProvider customTagsProvider = mock(MongoConnectionPoolTagsProvider.class);\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withBean(\"customMongoConnectionPoolTagsProvider\", MongoConnectionPoolTagsProvider.class,\n\t\t\t\t\t() -> customTagsProvider)\n\t\t\t.run((context) -> assertThat(getMongoConnectionPoolTagsProviderUsedToConstructListener(context))\n\t\t\t\t.isSameAs(customTagsProvider));\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMongoClientSettingsOnClasspathThenNoMetricsCommandListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(MongoClientSettings.class))\n\t\t\t.run(assertThatMetricsCommandListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMongoClientSettingsOnClasspathThenNoMetricsConnectionPoolListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(MongoClientSettings.class))\n\t\t\t.run(assertThatMetricsConnectionPoolListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMongoMetricsCommandListenerOnClasspathThenNoMetricsCommandListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(MongoMetricsCommandListener.class))\n\t\t\t.run(assertThatMetricsCommandListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenThereIsNoMongoMetricsConnectionPoolListenerOnClasspathThenNoMetricsConnectionPoolListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(MongoMetricsConnectionPoolListener.class))\n\t\t\t.run(assertThatMetricsConnectionPoolListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenMetricsCommandListenerEnabledPropertyFalseThenNoMetricsCommandListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.mongodb.command.enabled:false\")\n\t\t\t.run(assertThatMetricsCommandListenerNotAdded());\n\t}\n\n\t@Test\n\tvoid whenMetricsConnectionPoolListenerEnabledPropertyFalseThenNoMetricsConnectionPoolListenerIsAdded() {\n\t\tthis.contextRunner.withBean(SimpleMeterRegistry.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.mongodb.connectionpool.enabled:false\")\n\t\t\t.run(assertThatMetricsConnectionPoolListenerNotAdded());\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertThatMetricsCommandListenerNotAdded() {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(MongoMetricsCommandListener.class);\n\t\t\tassertThat(getActualMongoClientSettingsUsedToConstructClient(context))\n\t\t\t\t.extracting(MongoClientSettings::getCommandListeners)\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.isEmpty();\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertThatMetricsConnectionPoolListenerNotAdded() {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(MongoMetricsConnectionPoolListener.class);\n\t\t\tassertThat(getConnectionPoolListenersFromClient(context)).isEmpty();\n\t\t};\n\t}\n\n\tprivate MongoClientSettings getActualMongoClientSettingsUsedToConstructClient(\n\t\t\tfinal AssertableApplicationContext context) {\n\t\tfinal MongoClientImpl mongoClient = (MongoClientImpl) context.getBean(MongoClient.class);\n\t\treturn mongoClient.getSettings();\n\t}\n\n\tprivate List<ConnectionPoolListener> getConnectionPoolListenersFromClient(\n\t\t\tfinal AssertableApplicationContext context) {\n\t\tMongoClientSettings mongoClientSettings = getActualMongoClientSettingsUsedToConstructClient(context);\n\t\tConnectionPoolSettings connectionPoolSettings = mongoClientSettings.getConnectionPoolSettings();\n\t\treturn connectionPoolSettings.getConnectionPoolListeners();\n\t}\n\n\tprivate MongoCommandTagsProvider getMongoCommandTagsProviderUsedToConstructListener(\n\t\t\tfinal AssertableApplicationContext context) {\n\t\tMongoMetricsCommandListener listener = context.getBean(MongoMetricsCommandListener.class);\n\t\tMongoCommandTagsProvider tagsProvider = (MongoCommandTagsProvider) ReflectionTestUtils.getField(listener,\n\t\t\t\t\"tagsProvider\");\n\t\tassertThat(tagsProvider).isNotNull();\n\t\treturn tagsProvider;\n\t}\n\n\tprivate MongoConnectionPoolTagsProvider getMongoConnectionPoolTagsProviderUsedToConstructListener(\n\t\t\tfinal AssertableApplicationContext context) {\n\t\tMongoMetricsConnectionPoolListener listener = context.getBean(MongoMetricsConnectionPoolListener.class);\n\t\tMongoConnectionPoolTagsProvider tagsProvider = (MongoConnectionPoolTagsProvider) ReflectionTestUtils\n\t\t\t.getField(listener, \"tagsProvider\");\n\t\tassertThat(tagsProvider).isNotNull();\n\t\treturn tagsProvider;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/docker/compose/MongoEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MongoEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass MongoEnvironmentTests {\n\n\t@Test\n\tvoid createWhenMonoInitdbRootUsernameFileSetThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MongoEnvironment(Map.of(\"MONGO_INITDB_ROOT_USERNAME_FILE\", \"file\")))\n\t\t\t.withMessage(\"MONGO_INITDB_ROOT_USERNAME_FILE is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenMonoInitdbRootPasswordFileSetThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MongoEnvironment(Map.of(\"MONGO_INITDB_ROOT_PASSWORD_FILE\", \"file\")))\n\t\t\t.withMessage(\"MONGO_INITDB_ROOT_PASSWORD_FILE is not supported\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMongoInitdbRootUsernameSet() {\n\t\tMongoEnvironment environment = new MongoEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getUsername()).isNull();\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMongoInitdbRootUsernameSet() {\n\t\tMongoEnvironment environment = new MongoEnvironment(Map.of(\"MONGO_INITDB_ROOT_USERNAME\", \"user\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"user\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoMongoInitdbRootPasswordSet() {\n\t\tMongoEnvironment environment = new MongoEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMongoInitdbRootPasswordSet() {\n\t\tMongoEnvironment environment = new MongoEnvironment(Map.of(\"MONGO_INITDB_ROOT_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasNoMongoInitdbDatabaseSet() {\n\t\tMongoEnvironment environment = new MongoEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getDatabase()).isNull();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMongoInitdbDatabaseSet() {\n\t\tMongoEnvironment environment = new MongoEnvironment(Map.of(\"MONGO_INITDB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/health/MongoHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.health;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport com.mongodb.MongoException;\nimport com.mongodb.client.MongoClient;\nimport com.mongodb.client.MongoDatabase;\nimport com.mongodb.client.MongoIterable;\nimport org.bson.Document;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willAnswer;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MongoHealthIndicator}.\n *\n * @author Christian Dupuis\n * @author Andy Wilkinson\n */\nclass MongoHealthIndicatorTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid mongoIsUp() {\n\t\tDocument commandResult = mock(Document.class);\n\t\tgiven(commandResult.getInteger(\"maxWireVersion\")).willReturn(10);\n\t\tMongoClient mongoClient = mock(MongoClient.class);\n\t\tMongoIterable<String> databaseNames = mock(MongoIterable.class);\n\t\twillAnswer((invocation) -> {\n\t\t\t((Consumer<String>) invocation.getArgument(0)).accept(\"db\");\n\t\t\treturn null;\n\t\t}).given(databaseNames).forEach(any());\n\t\tgiven(mongoClient.listDatabaseNames()).willReturn(databaseNames);\n\t\tMongoDatabase mongoDatabase = mock(MongoDatabase.class);\n\t\tgiven(mongoClient.getDatabase(\"db\")).willReturn(mongoDatabase);\n\t\tgiven(mongoDatabase.runCommand(Document.parse(\"{ hello: 1 }\"))).willReturn(commandResult);\n\t\tMongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoClient);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"maxWireVersion\", 10);\n\t\tassertThat(health.getDetails()).containsEntry(\"databases\", List.of(\"db\"));\n\t\tthen(commandResult).should().getInteger(\"maxWireVersion\");\n\t}\n\n\t@Test\n\tvoid mongoIsDown() {\n\t\tMongoClient mongoClient = mock(MongoClient.class);\n\t\tgiven(mongoClient.listDatabaseNames()).willThrow(new MongoException(\"Connection failed\"));\n\t\tMongoHealthIndicator healthIndicator = new MongoHealthIndicator(mongoClient);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat((String) health.getDetails().get(\"error\")).contains(\"Connection failed\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/health/MongoReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.health;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport com.mongodb.MongoException;\nimport com.mongodb.reactivestreams.client.MongoClient;\nimport com.mongodb.reactivestreams.client.MongoDatabase;\nimport org.bson.Document;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MongoReactiveHealthIndicator}.\n *\n * @author Yulin Qin\n */\nclass MongoReactiveHealthIndicatorTests {\n\n\t@Test\n\tvoid mongoIsUp() {\n\t\tMongoClient mongoClient = mock(MongoClient.class);\n\t\tgiven(mongoClient.listDatabaseNames()).willReturn(Mono.just(\"db\"));\n\t\tMongoDatabase mongoDatabase = mock(MongoDatabase.class);\n\t\tgiven(mongoClient.getDatabase(\"db\")).willReturn(mongoDatabase);\n\t\tDocument commandResult = mock(Document.class);\n\t\tgiven(mongoDatabase.runCommand(Document.parse(\"{ hello: 1 }\"))).willReturn(Mono.just(commandResult));\n\t\tgiven(commandResult.getInteger(\"maxWireVersion\")).willReturn(10);\n\t\tMongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(mongoClient);\n\t\tMono<Health> health = mongoReactiveHealthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(h.getDetails()).containsOnlyKeys(\"maxWireVersion\", \"databases\");\n\t\t\tassertThat(h.getDetails()).containsEntry(\"maxWireVersion\", 10);\n\t\t\tassertThat(h.getDetails()).containsEntry(\"databases\", List.of(\"db\"));\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid mongoIsDown() {\n\t\tMongoClient mongoClient = mock(MongoClient.class);\n\t\tgiven(mongoClient.listDatabaseNames()).willThrow(new MongoException(\"Connection failed\"));\n\t\tMongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(mongoClient);\n\t\tMono<Health> health = mongoReactiveHealthIndicator.health();\n\t\tStepVerifier.create(health).consumeNextWith((h) -> {\n\t\t\tassertThat(h.getStatus()).isEqualTo(Status.DOWN);\n\t\t\tassertThat(h.getDetails()).containsOnlyKeys(\"error\");\n\t\t\tassertThat(h.getDetails()).containsEntry(\"error\", MongoException.class.getName() + \": Connection failed\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mongodb.testcontainers;\n\nimport com.mongodb.ConnectionString;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractMongoContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass AbstractMongoContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionString.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Mustache\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"com.samskivert:jmustache\")\n\tapi(\"org.springframework:spring-web\")\n\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework:spring-webmvc\")\n\toptional(\"org.springframework:spring-webflux\")\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":module:spring-boot-webflux-test\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/MustacheAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport com.samskivert.mustache.Mustache;\nimport com.samskivert.mustache.Mustache.TemplateLoader;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.template.TemplateLocation;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Mustache.\n *\n * @author Dave Syer\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Mustache.class)\n@EnableConfigurationProperties(MustacheProperties.class)\n@Import({ MustacheServletWebConfiguration.class, MustacheReactiveWebConfiguration.class })\npublic final class MustacheAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(MustacheAutoConfiguration.class);\n\n\tprivate final MustacheProperties mustache;\n\n\tprivate final ApplicationContext applicationContext;\n\n\tMustacheAutoConfiguration(MustacheProperties mustache, ApplicationContext applicationContext) {\n\t\tthis.mustache = mustache;\n\t\tthis.applicationContext = applicationContext;\n\t\tcheckTemplateLocationExists();\n\t}\n\n\tprivate void checkTemplateLocationExists() {\n\t\tif (this.mustache.isCheckTemplateLocation()) {\n\t\t\tTemplateLocation location = new TemplateLocation(this.mustache.getPrefix());\n\t\t\tif (!location.exists(this.applicationContext) && logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(\"Cannot find template location: \" + location\n\t\t\t\t\t\t+ \" (please add some templates, check your Mustache configuration, or set spring.mustache.\"\n\t\t\t\t\t\t+ \"check-template-location=false)\");\n\t\t\t}\n\t\t}\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMustache.Compiler mustacheCompiler(TemplateLoader mustacheTemplateLoader) {\n\t\treturn Mustache.compiler().withLoader(mustacheTemplateLoader);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(TemplateLoader.class)\n\tMustacheResourceTemplateLoader mustacheTemplateLoader() {\n\t\tMustacheResourceTemplateLoader loader = new MustacheResourceTemplateLoader(this.mustache.getPrefix(),\n\t\t\t\tthis.mustache.getSuffix());\n\t\tloader.setCharset(this.mustache.getCharset());\n\t\treturn loader;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/MustacheProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.MimeType;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for Mustache.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.mustache\")\npublic class MustacheProperties {\n\n\tprivate static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf(\"text/html\");\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\tpublic static final String DEFAULT_PREFIX = \"classpath:/templates/\";\n\n\tpublic static final String DEFAULT_SUFFIX = \".mustache\";\n\n\tprivate final Servlet servlet = new Servlet(this::getCharset);\n\n\tprivate final Reactive reactive = new Reactive();\n\n\t/**\n\t * View names that can be resolved.\n\t */\n\tprivate String @Nullable [] viewNames;\n\n\t/**\n\t * Name of the RequestContext attribute for all views.\n\t */\n\tprivate @Nullable String requestContextAttribute;\n\n\t/**\n\t * Template encoding.\n\t */\n\tprivate Charset charset = DEFAULT_CHARSET;\n\n\t/**\n\t * Whether to check that the templates location exists.\n\t */\n\tprivate boolean checkTemplateLocation = true;\n\n\t/**\n\t * Prefix to apply to template names.\n\t */\n\tprivate String prefix = DEFAULT_PREFIX;\n\n\t/**\n\t * Suffix to apply to template names.\n\t */\n\tprivate String suffix = DEFAULT_SUFFIX;\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic Reactive getReactive() {\n\t\treturn this.reactive;\n\t}\n\n\tpublic String getPrefix() {\n\t\treturn this.prefix;\n\t}\n\n\tpublic void setPrefix(String prefix) {\n\t\tthis.prefix = prefix;\n\t}\n\n\tpublic String getSuffix() {\n\t\treturn this.suffix;\n\t}\n\n\tpublic void setSuffix(String suffix) {\n\t\tthis.suffix = suffix;\n\t}\n\n\tpublic String @Nullable [] getViewNames() {\n\t\treturn this.viewNames;\n\t}\n\n\tpublic void setViewNames(String @Nullable [] viewNames) {\n\t\tthis.viewNames = viewNames;\n\t}\n\n\tpublic @Nullable String getRequestContextAttribute() {\n\t\treturn this.requestContextAttribute;\n\t}\n\n\tpublic void setRequestContextAttribute(@Nullable String requestContextAttribute) {\n\t\tthis.requestContextAttribute = requestContextAttribute;\n\t}\n\n\tpublic Charset getCharset() {\n\t\treturn this.charset;\n\t}\n\n\t/**\n\t * Return name of the charset.\n\t * @return the charset name\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of {@link #getCharset()}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic String getCharsetName() {\n\t\treturn this.charset.name();\n\t}\n\n\tpublic void setCharset(Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\tpublic boolean isCheckTemplateLocation() {\n\t\treturn this.checkTemplateLocation;\n\t}\n\n\tpublic void setCheckTemplateLocation(boolean checkTemplateLocation) {\n\t\tthis.checkTemplateLocation = checkTemplateLocation;\n\t}\n\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Whether HttpServletRequest attributes are allowed to override (hide) controller\n\t\t * generated model attributes of the same name.\n\t\t */\n\t\tprivate boolean allowRequestOverride;\n\n\t\t/**\n\t\t * Whether HttpSession attributes are allowed to override (hide) controller\n\t\t * generated model attributes of the same name.\n\t\t */\n\t\tprivate boolean allowSessionOverride;\n\n\t\t/**\n\t\t * Whether to enable template caching.\n\t\t */\n\t\tprivate boolean cache;\n\n\t\t/**\n\t\t * Content-Type value.\n\t\t */\n\t\tprivate MimeType contentType = DEFAULT_CONTENT_TYPE;\n\n\t\t/**\n\t\t * Whether all request attributes should be added to the model prior to merging\n\t\t * with the template.\n\t\t */\n\t\tprivate boolean exposeRequestAttributes;\n\n\t\t/**\n\t\t * Whether all HttpSession attributes should be added to the model prior to\n\t\t * merging with the template.\n\t\t */\n\t\tprivate boolean exposeSessionAttributes;\n\n\t\t/**\n\t\t * Whether to expose a RequestContext for use by Spring's macro library, under the\n\t\t * name \"springMacroRequestContext\".\n\t\t */\n\t\tprivate boolean exposeSpringMacroHelpers = true;\n\n\t\tprivate final Supplier<@Nullable Charset> charset;\n\n\t\tpublic Servlet() {\n\t\t\tthis.charset = () -> null;\n\t\t}\n\n\t\tprivate Servlet(Supplier<@Nullable Charset> charset) {\n\t\t\tthis.charset = charset;\n\t\t}\n\n\t\tpublic boolean isAllowRequestOverride() {\n\t\t\treturn this.allowRequestOverride;\n\t\t}\n\n\t\tpublic void setAllowRequestOverride(boolean allowRequestOverride) {\n\t\t\tthis.allowRequestOverride = allowRequestOverride;\n\t\t}\n\n\t\tpublic boolean isAllowSessionOverride() {\n\t\t\treturn this.allowSessionOverride;\n\t\t}\n\n\t\tpublic void setAllowSessionOverride(boolean allowSessionOverride) {\n\t\t\tthis.allowSessionOverride = allowSessionOverride;\n\t\t}\n\n\t\tpublic boolean isCache() {\n\t\t\treturn this.cache;\n\t\t}\n\n\t\tpublic void setCache(boolean cache) {\n\t\t\tthis.cache = cache;\n\t\t}\n\n\t\tpublic MimeType getContentType() {\n\t\t\tif (this.contentType != null && this.contentType.getCharset() == null) {\n\t\t\t\tCharset charset = this.charset.get();\n\t\t\t\tif (charset != null) {\n\t\t\t\t\tMap<String, String> parameters = new LinkedHashMap<>();\n\t\t\t\t\tparameters.put(\"charset\", charset.name());\n\t\t\t\t\tparameters.putAll(this.contentType.getParameters());\n\t\t\t\t\treturn new MimeType(this.contentType, parameters);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn this.contentType;\n\t\t}\n\n\t\tpublic void setContentType(MimeType contentType) {\n\t\t\tthis.contentType = contentType;\n\t\t}\n\n\t\tpublic boolean isExposeRequestAttributes() {\n\t\t\treturn this.exposeRequestAttributes;\n\t\t}\n\n\t\tpublic void setExposeRequestAttributes(boolean exposeRequestAttributes) {\n\t\t\tthis.exposeRequestAttributes = exposeRequestAttributes;\n\t\t}\n\n\t\tpublic boolean isExposeSessionAttributes() {\n\t\t\treturn this.exposeSessionAttributes;\n\t\t}\n\n\t\tpublic void setExposeSessionAttributes(boolean exposeSessionAttributes) {\n\t\t\tthis.exposeSessionAttributes = exposeSessionAttributes;\n\t\t}\n\n\t\tpublic boolean isExposeSpringMacroHelpers() {\n\t\t\treturn this.exposeSpringMacroHelpers;\n\t\t}\n\n\t\tpublic void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {\n\t\t\tthis.exposeSpringMacroHelpers = exposeSpringMacroHelpers;\n\t\t}\n\n\t}\n\n\tpublic static class Reactive {\n\n\t\t/**\n\t\t * Media types supported by Mustache views.\n\t\t */\n\t\tprivate @Nullable List<MediaType> mediaTypes;\n\n\t\tpublic @Nullable List<MediaType> getMediaTypes() {\n\t\t\treturn this.mediaTypes;\n\t\t}\n\n\t\tpublic void setMediaTypes(@Nullable List<MediaType> mediaTypes) {\n\t\t\tthis.mediaTypes = mediaTypes;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/MustacheReactiveWebConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport com.samskivert.mustache.Mustache.Compiler;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.mustache.reactive.view.MustacheViewResolver;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\n\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\nclass MustacheReactiveWebConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMustacheViewResolver mustacheViewResolver(Compiler mustacheCompiler, MustacheProperties mustache) {\n\t\tMustacheViewResolver resolver = new MustacheViewResolver(mustacheCompiler);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(mustache::getPrefix).to(resolver::setPrefix);\n\t\tmap.from(mustache::getSuffix).to(resolver::setSuffix);\n\t\tmap.from(mustache::getViewNames).to(resolver::setViewNames);\n\t\tmap.from(mustache::getRequestContextAttribute).to(resolver::setRequestContextAttribute);\n\t\tmap.from(mustache::getCharset).to(resolver::setCharset);\n\t\tmap.from(mustache.getReactive()::getMediaTypes).to(resolver::setSupportedMediaTypes);\n\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);\n\t\treturn resolver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/MustacheResourceTemplateLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport com.samskivert.mustache.Mustache;\nimport com.samskivert.mustache.Mustache.Compiler;\nimport com.samskivert.mustache.Mustache.TemplateLoader;\n\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\n\n/**\n * Mustache TemplateLoader implementation that uses a prefix, suffix and the Spring\n * Resource abstraction to load a template from a file, classpath, URL etc. A\n * {@link TemplateLoader} is needed in the {@link Compiler} when you want to render\n * partials (i.e. tiles-like features).\n *\n * @author Dave Syer\n * @since 4.0.0\n * @see Mustache\n * @see Resource\n */\npublic class MustacheResourceTemplateLoader implements TemplateLoader, ResourceLoaderAware {\n\n\tprivate String prefix = \"\";\n\n\tprivate String suffix = \"\";\n\n\tprivate Charset charset = StandardCharsets.UTF_8;\n\n\tprivate ResourceLoader resourceLoader = new DefaultResourceLoader(null);\n\n\tpublic MustacheResourceTemplateLoader() {\n\t}\n\n\tpublic MustacheResourceTemplateLoader(String prefix, String suffix) {\n\t\tthis.prefix = prefix;\n\t\tthis.suffix = suffix;\n\t}\n\n\t/**\n\t * Set the {@link Charset} to use.\n\t * @param charset the charset\n\t * @since 4.1.0\n\t */\n\tpublic void setCharset(Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\t/**\n\t * Set the name of the charset to use.\n\t * @param charset the charset\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #setCharset(Charset)}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic void setCharset(String charset) {\n\t\tthis.charset = Charset.forName(charset);\n\t}\n\n\t/**\n\t * Set the resource loader.\n\t * @param resourceLoader the resource loader\n\t */\n\t@Override\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tpublic Reader getTemplate(String name) throws Exception {\n\t\treturn new InputStreamReader(this.resourceLoader.getResource(this.prefix + name + this.suffix).getInputStream(),\n\t\t\t\tthis.charset);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/MustacheServletWebConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport com.samskivert.mustache.Mustache.Compiler;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.mustache.servlet.view.MustacheViewResolver;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\n\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(MustacheViewResolver.class)\nclass MustacheServletWebConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMustacheViewResolver mustacheViewResolver(Compiler mustacheCompiler, MustacheProperties mustache) {\n\t\tMustacheViewResolver resolver = new MustacheViewResolver(mustacheCompiler);\n\t\tresolver.setPrefix(mustache.getPrefix());\n\t\tresolver.setSuffix(mustache.getSuffix());\n\t\tresolver.setCache(mustache.getServlet().isCache());\n\t\tif (mustache.getServlet().getContentType() != null) {\n\t\t\tresolver.setContentType(mustache.getServlet().getContentType().toString());\n\t\t}\n\t\tresolver.setViewNames(mustache.getViewNames());\n\t\tresolver.setExposeRequestAttributes(mustache.getServlet().isExposeRequestAttributes());\n\t\tresolver.setAllowRequestOverride(mustache.getServlet().isAllowRequestOverride());\n\t\tresolver.setAllowSessionOverride(mustache.getServlet().isAllowSessionOverride());\n\t\tresolver.setExposeSessionAttributes(mustache.getServlet().isExposeSessionAttributes());\n\t\tresolver.setExposeSpringMacroHelpers(mustache.getServlet().isExposeSpringMacroHelpers());\n\t\tresolver.setRequestContextAttribute(mustache.getRequestContextAttribute());\n\t\tresolver.setCharset(mustache.getCharset());\n\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);\n\t\treturn resolver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/MustacheTemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TemplateAvailabilityProvider} that provides availability information for\n * Mustache view templates.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class MustacheTemplateAvailabilityProvider implements TemplateAvailabilityProvider {\n\n\t@Override\n\tpublic boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\tResourceLoader resourceLoader) {\n\t\tif (ClassUtils.isPresent(\"com.samskivert.mustache.Template\", classLoader)) {\n\t\t\tString prefix = environment.getProperty(\"spring.mustache.prefix\", MustacheProperties.DEFAULT_PREFIX);\n\t\t\tString suffix = environment.getProperty(\"spring.mustache.suffix\", MustacheProperties.DEFAULT_SUFFIX);\n\t\t\treturn resourceLoader.getResource(prefix + view + suffix).exists();\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Mustache.\n */\n@NullMarked\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/reactive/view/MustacheView.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.reactive.view;\n\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.nio.charset.Charset;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport com.samskivert.mustache.Mustache.Compiler;\nimport com.samskivert.mustache.Template;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.core.io.buffer.DataBufferUtils;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.Assert;\nimport org.springframework.web.reactive.result.view.AbstractUrlBasedView;\nimport org.springframework.web.reactive.result.view.View;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Spring WebFlux {@link View} using the Mustache template engine.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class MustacheView extends AbstractUrlBasedView {\n\n\tprivate @Nullable Compiler compiler;\n\n\tprivate @Nullable Charset charset;\n\n\t/**\n\t * Set the JMustache compiler to be used by this view. Typically this property is not\n\t * set directly. Instead a single {@link Compiler} is expected in the Spring\n\t * application context which is used to compile Mustache templates.\n\t * @param compiler the Mustache compiler\n\t */\n\tpublic void setCompiler(Compiler compiler) {\n\t\tthis.compiler = compiler;\n\t}\n\n\t/**\n\t * Set the {@link Charset} used for reading Mustache template files.\n\t * @param charset the charset\n\t * @since 4.1.0\n\t */\n\tpublic void setCharset(@Nullable Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\t/**\n\t * Set the name of the charset used for reading Mustache template files.\n\t * @param charset the charset\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #setCharset(Charset)}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic void setCharset(@Nullable String charset) {\n\t\tsetCharset((charset != null) ? Charset.forName(charset) : null);\n\t}\n\n\t@Override\n\tpublic boolean checkResourceExists(Locale locale) throws Exception {\n\t\treturn resolveResource() != null;\n\t}\n\n\t@Override\n\tprotected Mono<Void> renderInternal(Map<String, Object> model, @Nullable MediaType contentType,\n\t\t\tServerWebExchange exchange) {\n\t\tResource resource = resolveResource();\n\t\tif (resource == null) {\n\t\t\treturn Mono\n\t\t\t\t.error(new IllegalStateException(\"Could not find Mustache template with URL [\" + getUrl() + \"]\"));\n\t\t}\n\t\tDataBuffer dataBuffer = exchange.getResponse()\n\t\t\t.bufferFactory()\n\t\t\t.allocateBuffer(DefaultDataBufferFactory.DEFAULT_INITIAL_CAPACITY);\n\t\ttry (Reader reader = getReader(resource)) {\n\t\t\tAssert.state(this.compiler != null, \"'compiler' must not be null\");\n\t\t\tTemplate template = this.compiler.compile(reader);\n\t\t\tCharset charset = getCharset(contentType).orElseGet(this::getDefaultCharset);\n\t\t\ttry (Writer writer = new OutputStreamWriter(dataBuffer.asOutputStream(), charset)) {\n\t\t\t\ttemplate.execute(model, writer);\n\t\t\t\twriter.flush();\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tDataBufferUtils.release(dataBuffer);\n\t\t\treturn Mono.error(ex);\n\t\t}\n\t\treturn exchange.getResponse().writeWith(Flux.just(dataBuffer));\n\t}\n\n\tprivate @Nullable Resource resolveResource() {\n\t\tApplicationContext applicationContext = getApplicationContext();\n\t\tString url = getUrl();\n\t\tif (applicationContext == null || url == null) {\n\t\t\treturn null;\n\t\t}\n\t\tResource resource = applicationContext.getResource(url);\n\t\tif (resource == null || !resource.exists()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn resource;\n\t}\n\n\tprivate Reader getReader(Resource resource) throws IOException {\n\t\tif (this.charset != null) {\n\t\t\treturn new InputStreamReader(resource.getInputStream(), this.charset);\n\t\t}\n\t\treturn new InputStreamReader(resource.getInputStream());\n\t}\n\n\tprivate Optional<Charset> getCharset(@Nullable MediaType mediaType) {\n\t\treturn Optional.ofNullable((mediaType != null) ? mediaType.getCharset() : null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/reactive/view/MustacheViewResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.reactive.view;\n\nimport java.nio.charset.Charset;\n\nimport com.samskivert.mustache.Mustache;\nimport com.samskivert.mustache.Mustache.Compiler;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.reactive.result.view.AbstractUrlBasedView;\nimport org.springframework.web.reactive.result.view.UrlBasedViewResolver;\nimport org.springframework.web.reactive.result.view.ViewResolver;\n\n/**\n * Spring WebFlux {@link ViewResolver} for Mustache.\n *\n * @author Brian Clozel\n * @author Marten Deinum\n * @since 4.0.0\n */\npublic class MustacheViewResolver extends UrlBasedViewResolver {\n\n\tprivate final Compiler compiler;\n\n\tprivate @Nullable Charset charset;\n\n\t/**\n\t * Create a {@code MustacheViewResolver} backed by a default instance of a\n\t * {@link Compiler}.\n\t */\n\tpublic MustacheViewResolver() {\n\t\tthis.compiler = Mustache.compiler();\n\t\tsetViewClass(requiredViewClass());\n\t}\n\n\t/**\n\t * Create a {@code MustacheViewResolver} backed by a custom instance of a\n\t * {@link Compiler}.\n\t * @param compiler the Mustache compiler used to compile templates\n\t */\n\tpublic MustacheViewResolver(Compiler compiler) {\n\t\tthis.compiler = compiler;\n\t\tsetViewClass(requiredViewClass());\n\t}\n\n\t/**\n\t * Set the {@link Charset} to use.\n\t * @param charset the charset\n\t * @since 4.1.0\n\t */\n\tpublic void setCharset(@Nullable Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\t/**\n\t * Set the name of the charset to use.\n\t * @param charset the charset\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #setCharset(Charset)}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic void setCharset(@Nullable String charset) {\n\t\tsetCharset((charset != null) ? Charset.forName(charset) : null);\n\t}\n\n\t@Override\n\tprotected Class<?> requiredViewClass() {\n\t\treturn MustacheView.class;\n\t}\n\n\t@Override\n\tprotected AbstractUrlBasedView createView(String viewName) {\n\t\tMustacheView view = (MustacheView) super.createView(viewName);\n\t\tview.setCompiler(this.compiler);\n\t\tview.setCharset(this.charset);\n\t\treturn view;\n\t}\n\n\t@Override\n\tprotected AbstractUrlBasedView instantiateView() {\n\t\treturn (getViewClass() == MustacheView.class) ? new MustacheView() : super.instantiateView();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/reactive/view/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Additional {@link org.springframework.web.reactive.result.view.View Views} for use with\n * WebFlux.\n */\n@NullMarked\npackage org.springframework.boot.mustache.reactive.view;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/servlet/view/MustacheView.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.servlet.view;\n\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.nio.charset.Charset;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport com.samskivert.mustache.Mustache.Compiler;\nimport com.samskivert.mustache.Template;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.view.AbstractTemplateView;\n\n/**\n * Spring MVC {@link View} using the Mustache template engine.\n *\n * @author Brian Clozel\n * @author Dave Syer\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class MustacheView extends AbstractTemplateView {\n\n\tprivate @Nullable Compiler compiler;\n\n\tprivate @Nullable Charset charset;\n\n\t/**\n\t * Set the Mustache compiler to be used by this view.\n\t * <p>\n\t * Typically this property is not set directly. Instead a single {@link Compiler} is\n\t * expected in the Spring application context which is used to compile Mustache\n\t * templates.\n\t * @param compiler the Mustache compiler\n\t */\n\tpublic void setCompiler(Compiler compiler) {\n\t\tthis.compiler = compiler;\n\t}\n\n\t/**\n\t * Set the {@link Charset} used for reading Mustache template files.\n\t * @param charset the charset\n\t * @since 4.1.0\n\t */\n\tpublic void setCharset(@Nullable Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\t/**\n\t * Set the name of the charset used for reading Mustache template files.\n\t * @param charset the charset\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #setCharset(Charset)}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic void setCharset(@Nullable String charset) {\n\t\tsetCharset((charset != null) ? Charset.forName(charset) : null);\n\t}\n\n\t@Override\n\tpublic boolean checkResource(Locale locale) throws Exception {\n\t\tResource resource = getResource();\n\t\treturn resource != null;\n\t}\n\n\t@Override\n\tprotected void renderMergedTemplateModel(Map<String, Object> model, HttpServletRequest request,\n\t\t\tHttpServletResponse response) throws Exception {\n\t\tResource resource = getResource();\n\t\tAssert.state(resource != null, \"'resource' must not be null\");\n\t\tTemplate template = createTemplate(resource);\n\t\tif (template != null) {\n\t\t\ttemplate.execute(model, response.getWriter());\n\t\t}\n\t}\n\n\tprivate @Nullable Resource getResource() {\n\t\tApplicationContext applicationContext = getApplicationContext();\n\t\tString url = getUrl();\n\t\tif (applicationContext == null || url == null) {\n\t\t\treturn null;\n\t\t}\n\t\tResource resource = applicationContext.getResource(url);\n\t\treturn (resource.exists()) ? resource : null;\n\t}\n\n\tprivate Template createTemplate(Resource resource) throws IOException {\n\t\ttry (Reader reader = getReader(resource)) {\n\t\t\tAssert.state(this.compiler != null, \"'compiler' must not be null\");\n\t\t\treturn this.compiler.compile(reader);\n\t\t}\n\t}\n\n\tprivate Reader getReader(Resource resource) throws IOException {\n\t\tif (this.charset != null) {\n\t\t\treturn new InputStreamReader(resource.getInputStream(), this.charset);\n\t\t}\n\t\treturn new InputStreamReader(resource.getInputStream());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/servlet/view/MustacheViewResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.servlet.view;\n\nimport java.nio.charset.Charset;\n\nimport com.samskivert.mustache.Mustache;\nimport com.samskivert.mustache.Mustache.Compiler;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.servlet.ViewResolver;\nimport org.springframework.web.servlet.view.AbstractTemplateViewResolver;\nimport org.springframework.web.servlet.view.AbstractUrlBasedView;\n\n/**\n * Spring MVC {@link ViewResolver} for Mustache.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class MustacheViewResolver extends AbstractTemplateViewResolver {\n\n\tprivate final Mustache.Compiler compiler;\n\n\tprivate @Nullable Charset charset;\n\n\t/**\n\t * Create a {@code MustacheViewResolver} backed by a default instance of a\n\t * {@link Compiler}.\n\t */\n\tpublic MustacheViewResolver() {\n\t\tthis.compiler = Mustache.compiler();\n\t\tsetViewClass(requiredViewClass());\n\t}\n\n\t/**\n\t * Create a {@code MustacheViewResolver} backed by a custom instance of a\n\t * {@link Compiler}.\n\t * @param compiler the Mustache compiler used to compile templates\n\t */\n\tpublic MustacheViewResolver(Compiler compiler) {\n\t\tthis.compiler = compiler;\n\t\tsetViewClass(requiredViewClass());\n\t}\n\n\t@Override\n\tprotected Class<?> requiredViewClass() {\n\t\treturn MustacheView.class;\n\t}\n\n\t/**\n\t * Set the {@link Charset} to use.\n\t * @param charset the charset\n\t * @since 4.1.0\n\t */\n\tpublic void setCharset(@Nullable Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\t/**\n\t * Set the name of the charset to use.\n\t * @param charset the charset\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #setCharset(Charset)}\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tpublic void setCharset(@Nullable String charset) {\n\t\tsetCharset((charset != null) ? Charset.forName(charset) : null);\n\t}\n\n\t@Override\n\tprotected AbstractUrlBasedView buildView(String viewName) throws Exception {\n\t\tMustacheView view = (MustacheView) super.buildView(viewName);\n\t\tview.setCompiler(this.compiler);\n\t\tview.setCharset(this.charset);\n\t\treturn view;\n\t}\n\n\t@Override\n\tprotected AbstractUrlBasedView instantiateView() {\n\t\treturn (getViewClass() == MustacheView.class) ? new MustacheView() : super.instantiateView();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/java/org/springframework/boot/mustache/servlet/view/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Additional {@link org.springframework.web.servlet.View Views} for use with Web MVC.\n */\n@NullMarked\npackage org.springframework.boot.mustache.servlet.view;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.mustache.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"No longer required. To use Mustache without auto-configuration, depend directly on Mustache instead of spring-boot-mustache.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mustache.prefix\",\n      \"defaultValue\": \"classpath:/templates/\"\n    },\n    {\n      \"name\": \"spring.mustache.reactive.media-types\",\n      \"defaultValue\": \"text/html;charset=UTF-8\"\n    },\n    {\n      \"name\": \"spring.mustache.suffix\",\n      \"defaultValue\": \".mustache\"\n    }\n  ],\n  \"hints\": [],\n  \"ignored\": {\n    \"properties\": []\n  }\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.mustache.autoconfigure.MustacheAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.AutoConfigureWebFlux.imports",
    "content": "org.springframework.boot.mustache.autoconfigure.MustacheAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.mustache.autoconfigure.MustacheAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.mustache.servlet.cache=false\n"
  },
  {
    "path": "module/spring-boot-mustache/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\\\norg.springframework.boot.mustache.autoconfigure.MustacheTemplateAvailabilityProvider\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheAutoConfigurationReactiveIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport java.util.Date;\n\nimport com.samskivert.mustache.Mustache;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.mustache.reactive.view.MustacheView;\nimport org.springframework.boot.mustache.reactive.view.MustacheViewResolver;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.reactive.config.ViewResolverRegistry;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration Tests for {@link MustacheAutoConfiguration}, {@link MustacheViewResolver}\n * and {@link MustacheView}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.main.web-application-type=reactive\")\n@AutoConfigureWebTestClient\nclass MustacheAutoConfigurationReactiveIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient client;\n\n\t@Test\n\tvoid testHomePage() {\n\t\tString result = this.client.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.returnResult()\n\t\t\t.getResponseBody();\n\t\tassertThat(result).contains(\"Hello App\").contains(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testPartialPage() {\n\t\tString result = this.client.get()\n\t\t\t.uri(\"/partial\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.returnResult()\n\t\t\t.getResponseBody();\n\t\tassertThat(result).contains(\"Hello App\").contains(\"Hello World\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ NettyReactiveWebServerAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\t@Controller\n\t@EnableWebFlux\n\tstatic class Application {\n\n\t\t@Bean\n\t\tWebFluxConfigurer registerViewResolvers(ObjectProvider<ViewResolver> viewResolvers) {\n\t\t\treturn new WebFluxConfigurer() {\n\t\t\t\t@Override\n\t\t\t\tpublic void configureViewResolvers(ViewResolverRegistry registry) {\n\t\t\t\t\tviewResolvers.orderedStream().forEach(registry::viewResolver);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ApplicationContext context) {\n\t\t\treturn WebHttpHandlerBuilder.applicationContext(context).build();\n\t\t}\n\n\t\t@RequestMapping(\"/\")\n\t\tString home(Model model) {\n\t\t\tmodel.addAttribute(\"time\", new Date());\n\t\t\tmodel.addAttribute(\"message\", \"Hello World\");\n\t\t\tmodel.addAttribute(\"title\", \"Hello App\");\n\t\t\treturn \"home\";\n\t\t}\n\n\t\t@RequestMapping(\"/partial\")\n\t\tString layout(Model model) {\n\t\t\tmodel.addAttribute(\"time\", new Date());\n\t\t\tmodel.addAttribute(\"message\", \"Hello World\");\n\t\t\tmodel.addAttribute(\"title\", \"Hello App\");\n\t\t\treturn \"partial\";\n\t\t}\n\n\t\t@Bean\n\t\tMustacheViewResolver viewResolver() {\n\t\t\tMustache.Compiler compiler = Mustache.compiler()\n\t\t\t\t.withLoader(new MustacheResourceTemplateLoader(\n\t\t\t\t\t\t\"classpath:/org/springframework/boot/mustache/autoconfigure/\", \".html\"));\n\t\t\tMustacheViewResolver resolver = new MustacheViewResolver(compiler);\n\t\t\tresolver.setPrefix(\"classpath:/org/springframework/boot/mustache/autoconfigure/\");\n\t\t\tresolver.setSuffix(\".html\");\n\t\t\treturn resolver;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication application = new SpringApplication(Application.class);\n\t\t\tapplication.setWebApplicationType(WebApplicationType.REACTIVE);\n\t\t\tapplication.run(args);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheAutoConfigurationServletIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport com.samskivert.mustache.Mustache;\nimport com.samskivert.mustache.Template;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.mustache.servlet.view.MustacheView;\nimport org.springframework.boot.mustache.servlet.view.MustacheViewResolver;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration Tests for {@link MustacheAutoConfiguration}, {@link MustacheViewResolver}\n * and {@link MustacheView}.\n *\n * @author Dave Syer\n * @author Moritz Halbritter\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\nclass MustacheAutoConfigurationServletIntegrationTests {\n\n\t@Autowired\n\tprivate ServletWebServerApplicationContext context;\n\n\tprivate int port;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tthis.port = webServer.getPort();\n\t}\n\n\t@Test\n\tvoid shouldRenderTemplate() {\n\t\tString source = \"Hello {{arg}}!\";\n\t\tTemplate tmpl = Mustache.compiler().compile(source);\n\t\tMap<String, String> context = new HashMap<>();\n\t\tcontext.put(\"arg\", \"world\");\n\t\tassertThat(tmpl.execute(context)).isEqualTo(\"Hello world!\");\n\t}\n\n\t@Test\n\tvoid testHomePage() {\n\t\tString body = new TestRestTemplate().getForObject(\"http://localhost:\" + this.port, String.class);\n\t\tassertThat(body).contains(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testPartialPage() {\n\t\tString body = new TestRestTemplate().getForObject(\"http://localhost:\" + this.port + \"/partial\", String.class);\n\t\tassertThat(body).contains(\"Hello World\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(MinimalWebConfiguration.class)\n\t@Controller\n\tstatic class Application {\n\n\t\t@RequestMapping(\"/\")\n\t\tString home(Map<String, Object> model) {\n\t\t\tmodel.put(\"time\", new Date());\n\t\t\tmodel.put(\"message\", \"Hello World\");\n\t\t\tmodel.put(\"title\", \"Hello App\");\n\t\t\treturn \"home\";\n\t\t}\n\n\t\t@RequestMapping(\"/partial\")\n\t\tString layout(Map<String, Object> model) {\n\t\t\tmodel.put(\"time\", new Date());\n\t\t\tmodel.put(\"message\", \"Hello World\");\n\t\t\tmodel.put(\"title\", \"Hello App\");\n\t\t\treturn \"partial\";\n\t\t}\n\n\t\t@Bean\n\t\tMustacheViewResolver viewResolver() {\n\t\t\tMustache.Compiler compiler = Mustache.compiler()\n\t\t\t\t.withLoader(new MustacheResourceTemplateLoader(\n\t\t\t\t\t\t\"classpath:/org/springframework/boot/mustache/autoconfigure/\", \".html\"));\n\t\t\tMustacheViewResolver resolver = new MustacheViewResolver(compiler);\n\t\t\tresolver.setPrefix(\"classpath:/org/springframework/boot/mustache/autoconfigure/\");\n\t\t\tresolver.setSuffix(\".html\");\n\t\t\treturn resolver;\n\t\t}\n\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(Application.class, args);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TomcatServletWebServerAutoConfiguration.class })\n\tstatic class MinimalWebConfiguration {\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.function.Supplier;\n\nimport com.samskivert.mustache.Mustache;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.mustache.servlet.view.MustacheViewResolver;\nimport org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MustacheAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n */\nclass MustacheAutoConfigurationTests {\n\n\t@Test\n\tvoid registerBeansForServletApp() {\n\t\tconfigure(new WebApplicationContextRunner()).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Mustache.Compiler.class);\n\t\t\tassertThat(context).hasSingleBean(MustacheResourceTemplateLoader.class);\n\t\t\tassertThat(context).hasSingleBean(MustacheViewResolver.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid registerCompilerForServletApp() {\n\t\tconfigure(new WebApplicationContextRunner()).withUserConfiguration(CustomCompilerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Mustache.Compiler.class);\n\t\t\t\tassertThat(context).hasSingleBean(MustacheResourceTemplateLoader.class);\n\t\t\t\tassertThat(context).hasSingleBean(MustacheViewResolver.class);\n\t\t\t\tassertThat(context.getBean(Mustache.Compiler.class).standardsMode).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registerBeansForReactiveApp() {\n\t\tconfigure(new ReactiveWebApplicationContextRunner()).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Mustache.Compiler.class);\n\t\t\tassertThat(context).hasSingleBean(MustacheResourceTemplateLoader.class);\n\t\t\tassertThat(context).doesNotHaveBean(MustacheViewResolver.class);\n\t\t\tassertThat(context)\n\t\t\t\t.hasSingleBean(org.springframework.boot.mustache.reactive.view.MustacheViewResolver.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid registerCompilerForReactiveApp() {\n\t\tconfigure(new ReactiveWebApplicationContextRunner()).withUserConfiguration(CustomCompilerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Mustache.Compiler.class);\n\t\t\t\tassertThat(context).hasSingleBean(MustacheResourceTemplateLoader.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(MustacheViewResolver.class);\n\t\t\t\tassertThat(context)\n\t\t\t\t\t.hasSingleBean(org.springframework.boot.mustache.reactive.view.MustacheViewResolver.class);\n\t\t\t\tassertThat(context.getBean(Mustache.Compiler.class).standardsMode).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultServletViewResolverConfiguration() {\n\t\tconfigure(new WebApplicationContextRunner()).run((context) -> {\n\t\t\tMustacheViewResolver viewResolver = context.getBean(MustacheViewResolver.class);\n\t\t\tassertThat(viewResolver).extracting(\"allowRequestOverride\", InstanceOfAssertFactories.BOOLEAN).isFalse();\n\t\t\tassertThat(viewResolver).extracting(\"allowSessionOverride\", InstanceOfAssertFactories.BOOLEAN).isFalse();\n\t\t\tassertThat(viewResolver).extracting(\"cache\", InstanceOfAssertFactories.BOOLEAN).isFalse();\n\t\t\tassertThat(viewResolver).extracting(\"charset\").isEqualTo(StandardCharsets.UTF_8);\n\t\t\tassertThat(viewResolver).extracting(\"contentType\").isEqualTo(\"text/html;charset=UTF-8\");\n\t\t\tassertThat(viewResolver).extracting(\"exposeRequestAttributes\", InstanceOfAssertFactories.BOOLEAN).isFalse();\n\t\t\tassertThat(viewResolver).extracting(\"exposeSessionAttributes\", InstanceOfAssertFactories.BOOLEAN).isFalse();\n\t\t\tassertThat(viewResolver).extracting(\"exposeSpringMacroHelpers\", InstanceOfAssertFactories.BOOLEAN).isTrue();\n\t\t\tassertThat(viewResolver).extracting(\"prefix\").isEqualTo(\"classpath:/templates/\");\n\t\t\tassertThat(viewResolver).extracting(\"requestContextAttribute\").isNull();\n\t\t\tassertThat(viewResolver).extracting(\"suffix\").isEqualTo(\".mustache\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultReactiveViewResolverConfiguration() {\n\t\tconfigure(new ReactiveWebApplicationContextRunner()).run((context) -> {\n\t\t\torg.springframework.boot.mustache.reactive.view.MustacheViewResolver viewResolver = context\n\t\t\t\t.getBean(org.springframework.boot.mustache.reactive.view.MustacheViewResolver.class);\n\t\t\tassertThat(viewResolver).extracting(\"charset\").isEqualTo(StandardCharsets.UTF_8);\n\t\t\tassertThat(viewResolver).extracting(\"prefix\").isEqualTo(\"classpath:/templates/\");\n\t\t\tassertThat(viewResolver).extracting(\"requestContextAttribute\").isNull();\n\t\t\tassertThat(viewResolver).extracting(\"suffix\").isEqualTo(\".mustache\");\n\t\t\tassertThat(viewResolver.getSupportedMediaTypes())\n\t\t\t\t.containsExactly(MediaType.parseMediaType(\"text/html;charset=UTF-8\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid allowRequestOverrideCanBeCustomizedOnServletViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.SERVLET, \"spring.mustache.servlet.allow-request-override=true\",\n\t\t\t\t\"allowRequestOverride\", true);\n\t}\n\n\t@Test\n\tvoid allowSessionOverrideCanBeCustomizedOnServletViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.SERVLET, \"spring.mustache.servlet.allow-session-override=true\",\n\t\t\t\t\"allowSessionOverride\", true);\n\t}\n\n\t@Test\n\tvoid cacheCanBeCustomizedOnServletViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.SERVLET, \"spring.mustache.servlet.cache=true\", \"cache\", true);\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid charsetCanBeCustomizedOnViewResolver(ViewResolverKind kind) {\n\t\tassertViewResolverProperty(kind, \"spring.mustache.charset=UTF-16\", \"charset\", StandardCharsets.UTF_16);\n\t\tif (kind == ViewResolverKind.SERVLET) {\n\t\t\tassertViewResolverProperty(kind, \"spring.mustache.charset=UTF-16\", \"contentType\",\n\t\t\t\t\t\"text/html;charset=UTF-16\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid exposeRequestAttributesCanBeCustomizedOnServletViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.SERVLET, \"spring.mustache.servlet.expose-request-attributes=true\",\n\t\t\t\t\"exposeRequestAttributes\", true);\n\t}\n\n\t@Test\n\tvoid exposeSessionAttributesCanBeCustomizedOnServletViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.SERVLET, \"spring.mustache.servlet.expose-session-attributes=true\",\n\t\t\t\t\"exposeSessionAttributes\", true);\n\t}\n\n\t@Test\n\tvoid exposeSpringMacroHelpersCanBeCustomizedOnServletViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.SERVLET, \"spring.mustache.servlet.expose-spring-macro-helpers=true\",\n\t\t\t\t\"exposeSpringMacroHelpers\", true);\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid prefixCanBeCustomizedOnViewResolver(ViewResolverKind kind) {\n\t\tassertViewResolverProperty(kind, \"spring.mustache.prefix=classpath:/mustache-templates/\", \"prefix\",\n\t\t\t\t\"classpath:/mustache-templates/\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid requestContextAttributeCanBeCustomizedOnViewResolver(ViewResolverKind kind) {\n\t\tassertViewResolverProperty(kind, \"spring.mustache.request-context-attribute=test\", \"requestContextAttribute\",\n\t\t\t\t\"test\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid suffixCanBeCustomizedOnViewResolver(ViewResolverKind kind) {\n\t\tassertViewResolverProperty(kind, \"spring.mustache.suffix=.tache\", \"suffix\", \".tache\");\n\t}\n\n\t@Test\n\tvoid mediaTypesCanBeCustomizedOnReactiveViewResolver() {\n\t\tassertViewResolverProperty(ViewResolverKind.REACTIVE,\n\t\t\t\t\"spring.mustache.reactive.media-types=text/xml;charset=UTF-8,text/plain;charset=UTF-16\", \"mediaTypes\",\n\t\t\t\tArrays.asList(MediaType.parseMediaType(\"text/xml;charset=UTF-8\"),\n\t\t\t\t\t\tMediaType.parseMediaType(\"text/plain;charset=UTF-16\")));\n\t}\n\n\tprivate void assertViewResolverProperty(ViewResolverKind kind, String property, String field,\n\t\t\tObject expectedValue) {\n\t\tkind.runner()\n\t\t\t.withConfiguration(AutoConfigurations.of(MustacheAutoConfiguration.class))\n\t\t\t.withPropertyValues(property)\n\t\t\t.run((context) -> assertThat(context.getBean(kind.viewResolverClass())).extracting(field)\n\t\t\t\t.isEqualTo(expectedValue));\n\t}\n\n\tprivate <T extends AbstractApplicationContextRunner<T, ?, ?>> T configure(T runner) {\n\t\treturn runner.withConfiguration(AutoConfigurations.of(MustacheAutoConfiguration.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomCompilerConfiguration {\n\n\t\t@Bean\n\t\tMustache.Compiler compiler(Mustache.TemplateLoader mustacheTemplateLoader) {\n\t\t\treturn Mustache.compiler().standardsMode(true).withLoader(mustacheTemplateLoader);\n\t\t}\n\n\t}\n\n\tprivate enum ViewResolverKind {\n\n\t\t/**\n\t\t * Servlet MustacheViewResolver\n\t\t */\n\t\tSERVLET(WebApplicationContextRunner::new, MustacheViewResolver.class),\n\n\t\t/**\n\t\t * Reactive MustacheViewResolver\n\t\t */\n\t\tREACTIVE(ReactiveWebApplicationContextRunner::new,\n\t\t\t\torg.springframework.boot.mustache.reactive.view.MustacheViewResolver.class);\n\n\t\tprivate final Supplier<AbstractApplicationContextRunner<?, ?, ?>> runner;\n\n\t\tprivate final Class<?> viewResolverClass;\n\n\t\tViewResolverKind(Supplier<AbstractApplicationContextRunner<?, ?, ?>> runner, Class<?> viewResolverClass) {\n\t\t\tthis.runner = runner;\n\t\t\tthis.viewResolverClass = viewResolverClass;\n\t\t}\n\n\t\tprivate AbstractApplicationContextRunner<?, ?, ?> runner() {\n\t\t\treturn this.runner.get();\n\t\t}\n\n\t\tprivate Class<?> viewResolverClass() {\n\t\t\treturn this.viewResolverClass;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheAutoConfigurationWithoutWebMvcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport com.samskivert.mustache.Mustache;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MustacheAutoConfiguration} without Spring MVC on the class path.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"spring-webmvc-*.jar\")\nclass MustacheAutoConfigurationWithoutWebMvcTests {\n\n\t@Test\n\tvoid registerBeansForServletAppWithoutMvc() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(MustacheAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Mustache.Compiler.class);\n\t\t\t\tassertThat(context).hasSingleBean(MustacheResourceTemplateLoader.class);\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheStandaloneIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport java.util.Collections;\n\nimport com.samskivert.mustache.Mustache;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration Tests for {@link MustacheAutoConfiguration} outside of a web application.\n *\n * @author Dave Syer\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = WebEnvironment.NONE)\nclass MustacheStandaloneIntegrationTests {\n\n\t@Autowired\n\tprivate Mustache.Compiler compiler;\n\n\t@Test\n\tvoid directCompilation() {\n\t\tassertThat(this.compiler.compile(\"Hello: {{world}}\").execute(Collections.singletonMap(\"world\", \"World\")))\n\t\t\t.isEqualTo(\"Hello: World\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ MustacheAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tstatic class Application {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheWebFluxTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Mustache with {@link WebFluxTest @WebFluxTest}.\n *\n * @author Andy Wilkinson\n */\n@WebFluxTest\nclass MustacheWebFluxTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid mustacheAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(MustacheAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/autoconfigure/MustacheWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Mustache with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass MustacheWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid mustacheAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(MustacheAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/reactive/view/MustacheViewResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.reactive.view;\n\nimport java.time.Duration;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.GenericApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MustacheViewResolver}.\n *\n * @author Brian Clozel\n */\nclass MustacheViewResolverTests {\n\n\tprivate final MustacheViewResolver resolver = new MustacheViewResolver();\n\n\t@BeforeEach\n\tvoid init() {\n\t\tGenericApplicationContext applicationContext = new GenericApplicationContext();\n\t\tapplicationContext.refresh();\n\t\tthis.resolver.setApplicationContext(applicationContext);\n\t\tthis.resolver.setPrefix(\"classpath:\");\n\t\tthis.resolver.setSuffix(\".html\");\n\t}\n\n\t@Test\n\tvoid resolveNonExistent() {\n\t\tassertThat(this.resolver.resolveViewName(\"bar\", Locale.ROOT).block(Duration.ofSeconds(30))).isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"template.html\", content = \"Hello {{World}}\")\n\tvoid resolveExisting() {\n\t\tassertThat(this.resolver.resolveViewName(\"template\", Locale.ROOT).block(Duration.ofSeconds(30))).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/reactive/view/MustacheViewTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.reactive.view;\n\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.Collections;\n\nimport com.samskivert.mustache.Mustache;\nimport org.junit.jupiter.api.Test;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MustacheView}.\n *\n * @author Brian Clozel\n */\nclass MustacheViewTests {\n\n\tprivate final StaticApplicationContext context = new StaticApplicationContext();\n\n\t@Test\n\t@WithResource(name = \"template.html\", content = \"Hello {{World}}\")\n\tvoid viewResolvesHandlebars() {\n\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/test\").build());\n\t\tMustacheView view = new MustacheView();\n\t\tview.setCompiler(Mustache.compiler());\n\t\tview.setUrl(\"classpath:template.html\");\n\t\tview.setCharset(StandardCharsets.UTF_8);\n\t\tview.setApplicationContext(this.context);\n\t\tview.render(Collections.singletonMap(\"World\", \"Spring\"), MediaType.TEXT_HTML, exchange)\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tStepVerifier.create(exchange.getResponse().getBodyAsString())\n\t\t\t.assertNext((body) -> assertThat(body).isEqualToIgnoringWhitespace(\"Hello Spring\"))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/servlet/view/MustacheViewResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.servlet.view;\n\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.servlet.View;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MustacheViewResolver}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass MustacheViewResolverTests {\n\n\tprivate final MustacheViewResolver resolver = new MustacheViewResolver();\n\n\t@BeforeEach\n\tvoid init() {\n\t\tGenericApplicationContext applicationContext = new GenericApplicationContext();\n\t\tapplicationContext.refresh();\n\t\tthis.resolver.setApplicationContext(applicationContext);\n\t\tthis.resolver.setServletContext(new MockServletContext());\n\t\tthis.resolver.setPrefix(\"classpath:\");\n\t\tthis.resolver.setSuffix(\".html\");\n\t}\n\n\t@Test\n\tvoid resolveNonExistent() throws Exception {\n\t\tassertThat(this.resolver.resolveViewName(\"bar\", Locale.ROOT)).isNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"template.html\", content = \"Hello {{World}}\")\n\tvoid resolveExisting() throws Exception {\n\t\tassertThat(this.resolver.resolveViewName(\"template\", Locale.ROOT)).isNotNull();\n\t}\n\n\t@Test\n\t@WithResource(name = \"template.html\", content = \"Hello {{World}}\")\n\tvoid setsContentType() throws Exception {\n\t\tthis.resolver.setContentType(\"application/octet-stream\");\n\t\tView view = this.resolver.resolveViewName(\"template\", Locale.ROOT);\n\t\tassertThat(view).isNotNull();\n\t\tassertThat(view.getContentType()).isEqualTo(\"application/octet-stream\");\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/java/org/springframework/boot/mustache/servlet/view/MustacheViewTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.mustache.servlet.view;\n\nimport java.util.Collections;\n\nimport com.samskivert.mustache.Mustache;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MustacheView}.\n *\n * @author Dave Syer\n */\nclass MustacheViewTests {\n\n\tprivate final MockHttpServletRequest request = new MockHttpServletRequest();\n\n\tprivate final MockHttpServletResponse response = new MockHttpServletResponse();\n\n\tprivate final AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.context.refresh();\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tthis.context.setServletContext(servletContext);\n\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t}\n\n\t@Test\n\t@WithResource(name = \"template.html\", content = \"Hello {{World}}\")\n\tvoid viewResolvesHandlebars() throws Exception {\n\t\tMustacheView view = new MustacheView();\n\t\tview.setCompiler(Mustache.compiler());\n\t\tview.setUrl(\"classpath:template.html\");\n\t\tview.setApplicationContext(this.context);\n\t\tview.render(Collections.singletonMap(\"World\", \"Spring\"), this.request, this.response);\n\t\tassertThat(this.response.getContentAsString().trim()).isEqualTo(\"Hello Spring\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/resources/org/springframework/boot/mustache/autoconfigure/content.html",
    "content": "<h2>A Message</h2>\n<div>{{message}} at {{time}}</div>\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/resources/org/springframework/boot/mustache/autoconfigure/foo.html",
    "content": "Hello {{World}}\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/resources/org/springframework/boot/mustache/autoconfigure/foo_de.html",
    "content": "\n\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/resources/org/springframework/boot/mustache/autoconfigure/home.html",
    "content": "<html>\n<head>\n<title>{{title}}</title>\n</head>\n<body>\n\t<h2>A Message</h2>\n\t<div>{{message}} at {{time}}</div>\n</body>\n</html>\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/resources/org/springframework/boot/mustache/autoconfigure/layout.html",
    "content": "<html>\n<head>\n<title>{{title}}</title>\n</head>\n<body>\n\t<div id=\"navbar\" class=\"navbar navbar-default\" role=\"navigation\">\n\t\t<div class=\"navbar-collapse collapse\">\n\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t<li><a href=\"/\"> Home </a></li>\n\t\t\t</ul>\n\t\t</div>\n\t</div>\n\t<div class=\"jumbotron\">{{#include}}{{body}}{{/include}}</div>\n</body>\n</html>\n"
  },
  {
    "path": "module/spring-boot-mustache/src/test/resources/org/springframework/boot/mustache/autoconfigure/partial.html",
    "content": "<html>\n<head>\n<title>{{title}}</title>\n</head>\n<body>\n\t<div id=\"navbar\" class=\"navbar navbar-default\" role=\"navigation\">\n\t\t<div class=\"navbar-collapse collapse\">\n\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t<li><a href=\"/\"> Home </a></li>\n\t\t\t</ul>\n\t\t</div>\n\t</div>\n\t<div class=\"jumbotron\">{{>content}}</div>\n</body>\n</html>\n"
  },
  {
    "path": "module/spring-boot-neo4j/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Neo4j\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.neo4j.driver:neo4j-java-driver\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(\"org.neo4j.driver:neo4j-java-driver-observation-micrometer\")\n\toptional(\"org.testcontainers:testcontainers-neo4j\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-neo4j\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-testcontainers\")))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/dockerTest/java/org/springframework/boot/neo4j/autoconfigure/Neo4jAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokenManager;\nimport org.neo4j.driver.AuthTokenManagers;\nimport org.neo4j.driver.AuthTokens;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Result;\nimport org.neo4j.driver.Session;\nimport org.neo4j.driver.Transaction;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link Neo4jAutoConfiguration}.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass Neo4jAutoConfigurationIntegrationTests {\n\n\t@Container\n\tprivate static final Neo4jContainer neo4j = TestImage.container(Neo4jContainer.class);\n\n\t@SpringBootTest\n\t@Nested\n\tclass DriverWithDefaultAuthToken {\n\n\t\t@DynamicPropertySource\n\t\tstatic void neo4jProperties(DynamicPropertyRegistry registry) {\n\t\t\tregistry.add(\"spring.neo4j.uri\", neo4j::getBoltUrl);\n\t\t\tregistry.add(\"spring.neo4j.authentication.username\", () -> \"neo4j\");\n\t\t\tregistry.add(\"spring.neo4j.authentication.password\", neo4j::getAdminPassword);\n\t\t}\n\n\t\t@Autowired\n\t\tprivate Driver driver;\n\n\t\t@Test\n\t\tvoid driverCanHandleRequest() {\n\t\t\ttry (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {\n\t\t\t\tResult statementResult = tx.run(\"MATCH (n:Thing) RETURN n LIMIT 1\");\n\t\t\t\tassertThat(statementResult.hasNext()).isFalse();\n\t\t\t\ttx.commit();\n\t\t\t}\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ImportAutoConfiguration(Neo4jAutoConfiguration.class)\n\t\tstatic class TestConfiguration {\n\n\t\t}\n\n\t}\n\n\t@SpringBootTest\n\t@Nested\n\tclass DriverWithDynamicAuthToken {\n\n\t\t@DynamicPropertySource\n\t\tstatic void neo4jProperties(DynamicPropertyRegistry registry) {\n\t\t\tregistry.add(\"spring.neo4j.uri\", neo4j::getBoltUrl);\n\t\t\tregistry.add(\"spring.neo4j.authentication.username\", () -> \"wrong\");\n\t\t\tregistry.add(\"spring.neo4j.authentication.password\", () -> \"alsowrong\");\n\t\t}\n\n\t\t@Autowired\n\t\tprivate Driver driver;\n\n\t\t@Test\n\t\tvoid driverCanHandleRequest() {\n\t\t\ttry (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {\n\t\t\t\tResult statementResult = tx.run(\"MATCH (n:Thing) RETURN n LIMIT 1\");\n\t\t\t\tassertThat(statementResult.hasNext()).isFalse();\n\t\t\t\ttx.commit();\n\t\t\t}\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ImportAutoConfiguration(Neo4jAutoConfiguration.class)\n\t\tstatic class TestConfiguration {\n\n\t\t\t@Bean\n\t\t\tAuthTokenManager authTokenManager() {\n\t\t\t\treturn AuthTokenManagers.bearer(() -> AuthTokens.basic(\"neo4j\", neo4j.getAdminPassword())\n\t\t\t\t\t.expiringAt(System.currentTimeMillis() + 5_000));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@SpringBootTest\n\t@Nested\n\tclass DriverWithCustomConnectionDetailsIgnoresAuthTokenManager {\n\n\t\t@DynamicPropertySource\n\t\tstatic void neo4jProperties(DynamicPropertyRegistry registry) {\n\t\t\tregistry.add(\"spring.neo4j.uri\", neo4j::getBoltUrl);\n\t\t\tregistry.add(\"spring.neo4j.authentication.username\", () -> \"wrong\");\n\t\t\tregistry.add(\"spring.neo4j.authentication.password\", () -> \"alsowrong\");\n\t\t}\n\n\t\t@Autowired\n\t\tprivate Driver driver;\n\n\t\t@Test\n\t\tvoid driverCanHandleRequest() {\n\t\t\ttry (Session session = this.driver.session(); Transaction tx = session.beginTransaction()) {\n\t\t\t\tResult statementResult = tx.run(\"MATCH (n:Thing) RETURN n LIMIT 1\");\n\t\t\t\tassertThat(statementResult.hasNext()).isFalse();\n\t\t\t\ttx.commit();\n\t\t\t}\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ImportAutoConfiguration(Neo4jAutoConfiguration.class)\n\t\tstatic class TestConfiguration {\n\n\t\t\t@Bean\n\t\t\tAuthTokenManager authTokenManager() {\n\t\t\t\treturn AuthTokenManagers.bearer(() -> AuthTokens.basic(\"wrongagain\", \"stillwrong\")\n\t\t\t\t\t.expiringAt(System.currentTimeMillis() + 5_000));\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\tNeo4jConnectionDetails connectionDetails() {\n\t\t\t\treturn new Neo4jConnectionDetails() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic URI getUri() {\n\t\t\t\t\t\treturn URI.create(neo4j.getBoltUrl());\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic AuthToken getAuthToken() {\n\t\t\t\t\t\treturn AuthTokens.basic(\"neo4j\", neo4j.getAdminPassword());\n\t\t\t\t\t}\n\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/dockerTest/java/org/springframework/boot/neo4j/docker/compose/Neo4jDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.docker.compose;\n\nimport org.neo4j.driver.AuthTokens;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.GraphDatabase;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Integration tests for {@link Neo4jDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass Neo4jDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"neo4j-compose.yaml\", image = TestImage.NEO4J)\n\tvoid runCreatesConnectionDetailsThatCanAccessNeo4j(Neo4jConnectionDetails connectionDetails) {\n\t\tassertConnectionDetailsWithPassword(connectionDetails, \"absolutelysecret\");\n\t}\n\n\tprivate void assertConnectionDetailsWithPassword(Neo4jConnectionDetails connectionDetails, String password) {\n\t\tassertThat(connectionDetails.getAuthToken()).isEqualTo(AuthTokens.basic(\"neo4j\", password));\n\t\ttry (Driver driver = GraphDatabase.driver(connectionDetails.getUri(), connectionDetails.getAuthToken())) {\n\t\t\tassertThatNoException().isThrownBy(driver::verifyConnectivity);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/dockerTest/java/org/springframework/boot/neo4j/health/Neo4jReactiveHealthIndicatorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link Neo4jReactiveHealthIndicator}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\nclass Neo4jReactiveHealthIndicatorIntegrationTests {\n\n\t// gh-33428\n\n\t@Container\n\tprivate static final Neo4jContainer neo4jServer = TestImage.container(Neo4jContainer.class);\n\n\t@DynamicPropertySource\n\tstatic void neo4jProperties(DynamicPropertyRegistry registry) {\n\t\tregistry.add(\"spring.neo4j.uri\", neo4jServer::getBoltUrl);\n\t\tregistry.add(\"spring.neo4j.authentication.username\", () -> \"neo4j\");\n\t\tregistry.add(\"spring.neo4j.authentication.password\", neo4jServer::getAdminPassword);\n\t}\n\n\t@Autowired\n\tprivate Neo4jReactiveHealthIndicator healthIndicator;\n\n\t@Test\n\tvoid health() {\n\t\tHealth health = this.healthIndicator.health(true).block(Duration.ofSeconds(20));\n\t\tassertThat(health).isNotNull();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"edition\", \"community\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(Neo4jAutoConfiguration.class)\n\t@Import(Neo4jReactiveHealthIndicator.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/dockerTest/java/org/springframework/boot/neo4j/testcontainers/DeprecatedNeo4jContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.testcontainers;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.GraphDatabase;\nimport org.testcontainers.containers.Neo4jContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link DeprecatedNeo4jContainerConnectionDetailsFactory}.\n *\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link Neo4jContainerConnectionDetailsFactory}.\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedNeo4jContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final Neo4jContainer<?> container = TestImage.container(Neo4jContainer.class);\n\n\t@Autowired(required = false)\n\tprivate Neo4jConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\ttry (Driver driver = GraphDatabase.driver(this.connectionDetails.getUri(),\n\t\t\t\tthis.connectionDetails.getAuthToken())) {\n\t\t\tdriver.verifyConnectivity();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/dockerTest/resources/org/springframework/boot/neo4j/docker/compose/neo4j-compose.yaml",
    "content": "services:\n  neo4j:\n    image: '{imageName}'\n    ports:\n      - '7687'\n    environment:\n      - 'NEO4J_AUTH=neo4j/absolutelysecret'\n\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/ConfigBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport org.neo4j.driver.Config;\nimport org.neo4j.driver.Config.ConfigBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the a\n * {@link ConfigBuilder} to fine-tune its auto-configuration before it creates a\n * {@link Config} instance.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ConfigBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link ConfigBuilder}.\n\t * @param configBuilder the {@link ConfigBuilder} to customize\n\t */\n\tvoid customize(ConfigBuilder configBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/Neo4jAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.concurrent.TimeUnit;\n\nimport org.jspecify.annotations.Nullable;\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokenManager;\nimport org.neo4j.driver.AuthTokens;\nimport org.neo4j.driver.Config;\nimport org.neo4j.driver.Config.TrustStrategy;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.GraphDatabase;\nimport org.neo4j.driver.internal.Scheme;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jProperties.Authentication;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jProperties.Pool;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jProperties.Security;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Neo4j.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Driver.class)\n@EnableConfigurationProperties(Neo4jProperties.class)\npublic final class Neo4jAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(Neo4jConnectionDetails.class)\n\tPropertiesNeo4jConnectionDetails neo4jConnectionDetails(Neo4jProperties properties,\n\t\t\tObjectProvider<AuthTokenManager> authTokenManager) {\n\t\treturn new PropertiesNeo4jConnectionDetails(properties, authTokenManager.getIfUnique());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDriver neo4jDriver(Neo4jProperties properties, Neo4jConnectionDetails connectionDetails,\n\t\t\tObjectProvider<ConfigBuilderCustomizer> configBuilderCustomizers) {\n\t\tConfig config = mapDriverConfig(properties, connectionDetails,\n\t\t\t\tconfigBuilderCustomizers.orderedStream().toList());\n\t\tAuthTokenManager authTokenManager = connectionDetails.getAuthTokenManager();\n\t\tif (authTokenManager != null) {\n\t\t\treturn GraphDatabase.driver(connectionDetails.getUri(), authTokenManager, config);\n\t\t}\n\t\tAuthToken authToken = connectionDetails.getAuthToken();\n\t\treturn GraphDatabase.driver(connectionDetails.getUri(), authToken, config);\n\t}\n\n\tConfig mapDriverConfig(Neo4jProperties properties, Neo4jConnectionDetails connectionDetails,\n\t\t\tList<ConfigBuilderCustomizer> customizers) {\n\t\tConfig.ConfigBuilder builder = Config.builder();\n\t\tconfigurePoolSettings(builder, properties.getPool());\n\t\tURI uri = connectionDetails.getUri();\n\t\tString scheme = (uri != null) ? uri.getScheme() : \"bolt\";\n\t\tconfigureDriverSettings(builder, properties, isSimpleScheme(scheme));\n\t\tcustomizers.forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate boolean isSimpleScheme(String scheme) {\n\t\tString lowerCaseScheme = scheme.toLowerCase(Locale.ENGLISH);\n\t\treturn !Scheme.isSecurityScheme(lowerCaseScheme);\n\t}\n\n\tprivate void configurePoolSettings(Config.ConfigBuilder builder, Pool pool) {\n\t\tif (pool.isLogLeakedSessions()) {\n\t\t\tbuilder.withLeakedSessionsLogging();\n\t\t}\n\t\tbuilder.withMaxConnectionPoolSize(pool.getMaxConnectionPoolSize());\n\t\tDuration idleTimeBeforeConnectionTest = pool.getIdleTimeBeforeConnectionTest();\n\t\tif (idleTimeBeforeConnectionTest != null) {\n\t\t\tbuilder.withConnectionLivenessCheckTimeout(idleTimeBeforeConnectionTest.toMillis(), TimeUnit.MILLISECONDS);\n\t\t}\n\t\tbuilder.withMaxConnectionLifetime(pool.getMaxConnectionLifetime().toMillis(), TimeUnit.MILLISECONDS);\n\t\tbuilder.withConnectionAcquisitionTimeout(pool.getConnectionAcquisitionTimeout().toMillis(),\n\t\t\t\tTimeUnit.MILLISECONDS);\n\t}\n\n\tprivate void configureDriverSettings(Config.ConfigBuilder builder, Neo4jProperties properties,\n\t\t\tboolean withEncryptionAndTrustSettings) {\n\t\tif (withEncryptionAndTrustSettings) {\n\t\t\tapplyEncryptionAndTrustSettings(builder, properties.getSecurity());\n\t\t}\n\t\tbuilder.withConnectionTimeout(properties.getConnectionTimeout().toMillis(), TimeUnit.MILLISECONDS);\n\t\tbuilder.withMaxTransactionRetryTime(properties.getMaxTransactionRetryTime().toMillis(), TimeUnit.MILLISECONDS);\n\t}\n\n\tprivate void applyEncryptionAndTrustSettings(Config.ConfigBuilder builder,\n\t\t\tNeo4jProperties.Security securityProperties) {\n\t\tif (securityProperties.isEncrypted()) {\n\t\t\tbuilder.withEncryption();\n\t\t}\n\t\telse {\n\t\t\tbuilder.withoutEncryption();\n\t\t}\n\t\tbuilder.withTrustStrategy(mapTrustStrategy(securityProperties));\n\t}\n\n\tprivate Config.TrustStrategy mapTrustStrategy(Neo4jProperties.Security securityProperties) {\n\t\tString propertyName = \"spring.neo4j.security.trust-strategy\";\n\t\tSecurity.TrustStrategy strategy = securityProperties.getTrustStrategy();\n\t\tTrustStrategy trustStrategy = createTrustStrategy(securityProperties, propertyName, strategy);\n\t\tif (securityProperties.isHostnameVerificationEnabled()) {\n\t\t\ttrustStrategy.withHostnameVerification();\n\t\t}\n\t\telse {\n\t\t\ttrustStrategy.withoutHostnameVerification();\n\t\t}\n\t\treturn trustStrategy;\n\t}\n\n\tprivate TrustStrategy createTrustStrategy(Neo4jProperties.Security securityProperties, String propertyName,\n\t\t\tSecurity.TrustStrategy strategy) {\n\t\treturn switch (strategy) {\n\t\t\tcase TRUST_ALL_CERTIFICATES -> TrustStrategy.trustAllCertificates();\n\t\t\tcase TRUST_SYSTEM_CA_SIGNED_CERTIFICATES -> TrustStrategy.trustSystemCertificates();\n\t\t\tcase TRUST_CUSTOM_CA_SIGNED_CERTIFICATES -> {\n\t\t\t\tFile certFile = securityProperties.getCertFile();\n\t\t\t\tif (certFile == null || !certFile.isFile()) {\n\t\t\t\t\tthrow new InvalidConfigurationPropertyValueException(propertyName, strategy.name(),\n\t\t\t\t\t\t\t\"Configured trust strategy requires a certificate file.\");\n\t\t\t\t}\n\t\t\t\tyield TrustStrategy.trustCustomCertificateSignedBy(certFile);\n\t\t\t}\n\t\t\tdefault -> throw new InvalidConfigurationPropertyValueException(propertyName, strategy.name(),\n\t\t\t\t\t\"Unknown strategy.\");\n\t\t};\n\t}\n\n\t/**\n\t * Adapts {@link Neo4jProperties} to {@link Neo4jConnectionDetails}.\n\t */\n\tstatic class PropertiesNeo4jConnectionDetails implements Neo4jConnectionDetails {\n\n\t\tprivate final Neo4jProperties properties;\n\n\t\tprivate final @Nullable AuthTokenManager authTokenManager;\n\n\t\tPropertiesNeo4jConnectionDetails(Neo4jProperties properties, @Nullable AuthTokenManager authTokenManager) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.authTokenManager = authTokenManager;\n\t\t}\n\n\t\t@Override\n\t\tpublic URI getUri() {\n\t\t\tURI uri = this.properties.getUri();\n\t\t\treturn (uri != null) ? uri : Neo4jConnectionDetails.super.getUri();\n\t\t}\n\n\t\t@Override\n\t\tpublic AuthToken getAuthToken() {\n\t\t\tAuthentication authentication = this.properties.getAuthentication();\n\t\t\tString username = authentication.getUsername();\n\t\t\tString kerberosTicket = authentication.getKerberosTicket();\n\t\t\tboolean hasUsername = StringUtils.hasText(username);\n\t\t\tboolean hasKerberosTicket = StringUtils.hasText(kerberosTicket);\n\t\t\tAssert.state(!(hasUsername && hasKerberosTicket),\n\t\t\t\t\t() -> \"Cannot specify both username ('%s') and kerberos ticket ('%s')\".formatted(username,\n\t\t\t\t\t\t\tkerberosTicket));\n\t\t\tString password = authentication.getPassword();\n\t\t\tif (hasUsername && StringUtils.hasText(password)) {\n\t\t\t\treturn AuthTokens.basic(username, password, authentication.getRealm());\n\t\t\t}\n\t\t\tif (hasKerberosTicket) {\n\t\t\t\treturn AuthTokens.kerberos(kerberosTicket);\n\t\t\t}\n\t\t\treturn AuthTokens.none();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable AuthTokenManager getAuthTokenManager() {\n\t\t\treturn this.authTokenManager;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/Neo4jConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport java.net.URI;\n\nimport org.jspecify.annotations.Nullable;\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokenManager;\nimport org.neo4j.driver.AuthTokens;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to a Neo4j service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface Neo4jConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Returns the URI of the Neo4j server. Defaults to {@code bolt://localhost:7687\"}.\n\t * @return the Neo4j server URI\n\t */\n\tdefault URI getUri() {\n\t\treturn URI.create(\"bolt://localhost:7687\");\n\t}\n\n\t/**\n\t * Returns the token to use for authentication. Defaults to {@link AuthTokens#none()}.\n\t * @return the auth token\n\t */\n\tdefault AuthToken getAuthToken() {\n\t\treturn AuthTokens.none();\n\t}\n\n\t/**\n\t * Returns the {@link AuthTokenManager} to use for authentication. Defaults to\n\t * {@code null} in which case the {@link #getAuthToken() auth token} should be used.\n\t * @return the auth token manager\n\t */\n\tdefault @Nullable AuthTokenManager getAuthTokenManager() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/Neo4jProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Neo4j.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.neo4j\")\npublic class Neo4jProperties {\n\n\t/**\n\t * URI used by the driver.\n\t */\n\tprivate @Nullable URI uri;\n\n\t/**\n\t * Timeout for borrowing connections from the pool.\n\t */\n\tprivate Duration connectionTimeout = Duration.ofSeconds(30);\n\n\t/**\n\t * Maximum time transactions are allowed to retry.\n\t */\n\tprivate Duration maxTransactionRetryTime = Duration.ofSeconds(30);\n\n\tprivate final Authentication authentication = new Authentication();\n\n\tprivate final Pool pool = new Pool();\n\n\tprivate final Security security = new Security();\n\n\tpublic @Nullable URI getUri() {\n\t\treturn this.uri;\n\t}\n\n\tpublic void setUri(@Nullable URI uri) {\n\t\tthis.uri = uri;\n\t}\n\n\tpublic Duration getConnectionTimeout() {\n\t\treturn this.connectionTimeout;\n\t}\n\n\tpublic void setConnectionTimeout(Duration connectionTimeout) {\n\t\tthis.connectionTimeout = connectionTimeout;\n\t}\n\n\tpublic Duration getMaxTransactionRetryTime() {\n\t\treturn this.maxTransactionRetryTime;\n\t}\n\n\tpublic void setMaxTransactionRetryTime(Duration maxTransactionRetryTime) {\n\t\tthis.maxTransactionRetryTime = maxTransactionRetryTime;\n\t}\n\n\tpublic Authentication getAuthentication() {\n\t\treturn this.authentication;\n\t}\n\n\tpublic Pool getPool() {\n\t\treturn this.pool;\n\t}\n\n\tpublic Security getSecurity() {\n\t\treturn this.security;\n\t}\n\n\tpublic static class Authentication {\n\n\t\t/**\n\t\t * Login user of the server.\n\t\t */\n\t\tprivate @Nullable String username;\n\n\t\t/**\n\t\t * Login password of the server.\n\t\t */\n\t\tprivate @Nullable String password;\n\n\t\t/**\n\t\t * Realm to connect to.\n\t\t */\n\t\tprivate @Nullable String realm;\n\n\t\t/**\n\t\t * Kerberos ticket for connecting to the database. Mutual exclusive with a given\n\t\t * username.\n\t\t */\n\t\tprivate @Nullable String kerberosTicket;\n\n\t\tpublic @Nullable String getUsername() {\n\t\t\treturn this.username;\n\t\t}\n\n\t\tpublic void setUsername(@Nullable String username) {\n\t\t\tthis.username = username;\n\t\t}\n\n\t\tpublic @Nullable String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(@Nullable String password) {\n\t\t\tthis.password = password;\n\t\t}\n\n\t\tpublic @Nullable String getRealm() {\n\t\t\treturn this.realm;\n\t\t}\n\n\t\tpublic void setRealm(@Nullable String realm) {\n\t\t\tthis.realm = realm;\n\t\t}\n\n\t\tpublic @Nullable String getKerberosTicket() {\n\t\t\treturn this.kerberosTicket;\n\t\t}\n\n\t\tpublic void setKerberosTicket(@Nullable String kerberosTicket) {\n\t\t\tthis.kerberosTicket = kerberosTicket;\n\t\t}\n\n\t}\n\n\tpublic static class Pool {\n\n\t\t/**\n\t\t * Whether to log leaked sessions.\n\t\t */\n\t\tprivate boolean logLeakedSessions;\n\n\t\t/**\n\t\t * Maximum amount of connections in the connection pool towards a single database.\n\t\t */\n\t\tprivate int maxConnectionPoolSize = 100;\n\n\t\t/**\n\t\t * Pooled connections that have been idle in the pool for longer than this\n\t\t * threshold will be tested before they are used again.\n\t\t */\n\t\tprivate @Nullable Duration idleTimeBeforeConnectionTest;\n\n\t\t/**\n\t\t * Pooled connections older than this threshold will be closed and removed from\n\t\t * the pool.\n\t\t */\n\t\tprivate Duration maxConnectionLifetime = Duration.ofHours(1);\n\n\t\t/**\n\t\t * Acquisition of new connections will be attempted for at most configured\n\t\t * timeout.\n\t\t */\n\t\tprivate Duration connectionAcquisitionTimeout = Duration.ofSeconds(60);\n\n\t\tpublic boolean isLogLeakedSessions() {\n\t\t\treturn this.logLeakedSessions;\n\t\t}\n\n\t\tpublic void setLogLeakedSessions(boolean logLeakedSessions) {\n\t\t\tthis.logLeakedSessions = logLeakedSessions;\n\t\t}\n\n\t\tpublic int getMaxConnectionPoolSize() {\n\t\t\treturn this.maxConnectionPoolSize;\n\t\t}\n\n\t\tpublic void setMaxConnectionPoolSize(int maxConnectionPoolSize) {\n\t\t\tthis.maxConnectionPoolSize = maxConnectionPoolSize;\n\t\t}\n\n\t\tpublic @Nullable Duration getIdleTimeBeforeConnectionTest() {\n\t\t\treturn this.idleTimeBeforeConnectionTest;\n\t\t}\n\n\t\tpublic void setIdleTimeBeforeConnectionTest(@Nullable Duration idleTimeBeforeConnectionTest) {\n\t\t\tthis.idleTimeBeforeConnectionTest = idleTimeBeforeConnectionTest;\n\t\t}\n\n\t\tpublic Duration getMaxConnectionLifetime() {\n\t\t\treturn this.maxConnectionLifetime;\n\t\t}\n\n\t\tpublic void setMaxConnectionLifetime(Duration maxConnectionLifetime) {\n\t\t\tthis.maxConnectionLifetime = maxConnectionLifetime;\n\t\t}\n\n\t\tpublic Duration getConnectionAcquisitionTimeout() {\n\t\t\treturn this.connectionAcquisitionTimeout;\n\t\t}\n\n\t\tpublic void setConnectionAcquisitionTimeout(Duration connectionAcquisitionTimeout) {\n\t\t\tthis.connectionAcquisitionTimeout = connectionAcquisitionTimeout;\n\t\t}\n\n\t}\n\n\tpublic static class Security {\n\n\t\t/**\n\t\t * Whether the driver should use encrypted traffic.\n\t\t */\n\t\tprivate boolean encrypted;\n\n\t\t/**\n\t\t * Trust strategy to use.\n\t\t */\n\t\tprivate TrustStrategy trustStrategy = TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES;\n\n\t\t/**\n\t\t * Path to the file that holds the trusted certificates.\n\t\t */\n\t\tprivate @Nullable File certFile;\n\n\t\t/**\n\t\t * Whether hostname verification is required.\n\t\t */\n\t\tprivate boolean hostnameVerificationEnabled = true;\n\n\t\tpublic boolean isEncrypted() {\n\t\t\treturn this.encrypted;\n\t\t}\n\n\t\tpublic void setEncrypted(boolean encrypted) {\n\t\t\tthis.encrypted = encrypted;\n\t\t}\n\n\t\tpublic TrustStrategy getTrustStrategy() {\n\t\t\treturn this.trustStrategy;\n\t\t}\n\n\t\tpublic void setTrustStrategy(TrustStrategy trustStrategy) {\n\t\t\tthis.trustStrategy = trustStrategy;\n\t\t}\n\n\t\tpublic @Nullable File getCertFile() {\n\t\t\treturn this.certFile;\n\t\t}\n\n\t\tpublic void setCertFile(@Nullable File certFile) {\n\t\t\tthis.certFile = certFile;\n\t\t}\n\n\t\tpublic boolean isHostnameVerificationEnabled() {\n\t\t\treturn this.hostnameVerificationEnabled;\n\t\t}\n\n\t\tpublic void setHostnameVerificationEnabled(boolean hostnameVerificationEnabled) {\n\t\t\tthis.hostnameVerificationEnabled = hostnameVerificationEnabled;\n\t\t}\n\n\t\tpublic enum TrustStrategy {\n\n\t\t\t/**\n\t\t\t * Trust all certificates.\n\t\t\t */\n\t\t\tTRUST_ALL_CERTIFICATES,\n\n\t\t\t/**\n\t\t\t * Trust certificates that are signed by a trusted certificate.\n\t\t\t */\n\t\t\tTRUST_CUSTOM_CA_SIGNED_CERTIFICATES,\n\n\t\t\t/**\n\t\t\t * Trust certificates that can be verified through the local system store.\n\t\t\t */\n\t\t\tTRUST_SYSTEM_CA_SIGNED_CERTIFICATES\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/health/Neo4jHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure.health;\n\nimport org.neo4j.driver.Driver;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.neo4j.autoconfigure.health.Neo4jHealthContributorConfigurations.Neo4jConfiguration;\nimport org.springframework.boot.neo4j.autoconfigure.health.Neo4jHealthContributorConfigurations.Neo4jReactiveConfiguration;\nimport org.springframework.boot.neo4j.health.Neo4jHealthIndicator;\nimport org.springframework.boot.neo4j.health.Neo4jReactiveHealthIndicator;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link Neo4jReactiveHealthIndicator} and {@link Neo4jHealthIndicator}.\n *\n * @author Eric Spiegelberg\n * @author Stephane Nicoll\n * @author Michael J. Simons\n * @since 4.0.0\n */\n@AutoConfiguration(after = Neo4jAutoConfiguration.class)\n@ConditionalOnClass({ Driver.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(Driver.class)\n@ConditionalOnEnabledHealthIndicator(\"neo4j\")\n@Import({ Neo4jReactiveConfiguration.class, Neo4jConfiguration.class })\npublic final class Neo4jHealthContributorAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/health/Neo4jHealthContributorConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure.health;\n\nimport org.neo4j.driver.Driver;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.neo4j.health.Neo4jHealthIndicator;\nimport org.springframework.boot.neo4j.health.Neo4jReactiveHealthIndicator;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Health contributor options for Neo4j.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n */\nclass Neo4jHealthContributorConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(Neo4jHealthIndicator.class)\n\tstatic class Neo4jConfiguration extends CompositeHealthContributorConfiguration<Neo4jHealthIndicator, Driver> {\n\n\t\tNeo4jConfiguration() {\n\t\t\tsuper(Neo4jHealthIndicator::new);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = { \"neo4jHealthIndicator\", \"neo4jHealthContributor\" })\n\t\tHealthContributor neo4jHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn createContributor(beanFactory, Driver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ Flux.class, Neo4jReactiveHealthIndicator.class })\n\tstatic class Neo4jReactiveConfiguration\n\t\t\textends CompositeReactiveHealthContributorConfiguration<Neo4jReactiveHealthIndicator, Driver> {\n\n\t\tNeo4jReactiveConfiguration() {\n\t\t\tsuper(Neo4jReactiveHealthIndicator::new);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = { \"neo4jHealthIndicator\", \"neo4jHealthContributor\" })\n\t\tReactiveHealthContributor neo4jHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn createContributor(beanFactory, Driver.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Neo4j health.\n */\n@NullMarked\npackage org.springframework.boot.neo4j.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/observation/Neo4jObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure.observation;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\nimport org.neo4j.driver.Config.ConfigBuilder;\nimport org.neo4j.driver.observation.micrometer.MicrometerObservationProvider;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.neo4j.autoconfigure.ConfigBuilderCustomizer;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\n\n/**\n * Auto-configuration for Neo4j observability.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(before = Neo4jAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnBean(ObservationRegistry.class)\n@ConditionalOnClass({ ConfigBuilder.class, MicrometerObservationProvider.class, Observation.class })\npublic final class Neo4jObservationAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(ObservationRegistry.class)\n\t@Order(0)\n\tConfigBuilderCustomizer neo4jObservationCustomizer(ObservationRegistry registry) {\n\t\treturn (builder) -> builder.withObservationProvider(MicrometerObservationProvider.builder(registry).build());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Neo4j observation.\n */\n@NullMarked\npackage org.springframework.boot.neo4j.autoconfigure.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Neo4j.\n */\n@NullMarked\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/docker/compose/Neo4jDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.docker.compose;\n\nimport java.net.URI;\n\nimport org.jspecify.annotations.Nullable;\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokens;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link Neo4jConnectionDetails}\n * for a {@code Neo4j} service.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass Neo4jDockerComposeConnectionDetailsFactory extends DockerComposeConnectionDetailsFactory<Neo4jConnectionDetails> {\n\n\tNeo4jDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"neo4j\");\n\t}\n\n\t@Override\n\tprotected Neo4jConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new Neo4jDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link Neo4jConnectionDetails} backed by a {@code Neo4j} {@link RunningService}.\n\t */\n\tstatic class Neo4jDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements Neo4jConnectionDetails {\n\n\t\tprivate static final int BOLT_PORT = 7687;\n\n\t\tprivate final @Nullable AuthToken authToken;\n\n\t\tprivate final URI uri;\n\n\t\tNeo4jDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tNeo4jEnvironment neo4jEnvironment = new Neo4jEnvironment(service.env());\n\t\t\tthis.authToken = neo4jEnvironment.getAuthToken();\n\t\t\tthis.uri = URI.create(\"neo4j://%s:%d\".formatted(service.host(), service.ports().get(BOLT_PORT)));\n\t\t}\n\n\t\t@Override\n\t\tpublic URI getUri() {\n\t\t\treturn this.uri;\n\t\t}\n\n\t\t@Override\n\t\tpublic AuthToken getAuthToken() {\n\t\t\treturn (this.authToken != null) ? this.authToken : AuthTokens.none();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/docker/compose/Neo4jEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokens;\n\n/**\n * Neo4j environment details.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass Neo4jEnvironment {\n\n\tprivate final @Nullable AuthToken authToken;\n\n\tNeo4jEnvironment(Map<String, @Nullable String> env) {\n\t\tAuthToken authToken = parse(env.get(\"NEO4J_AUTH\"));\n\t\tif (authToken == null && env.containsKey(\"NEO4J_PASSWORD\")) {\n\t\t\tauthToken = parse(\"neo4j/\" + env.get(\"NEO4J_PASSWORD\"));\n\t\t}\n\t\tthis.authToken = authToken;\n\t}\n\n\tprivate @Nullable AuthToken parse(@Nullable String neo4jAuth) {\n\t\tif (neo4jAuth == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (\"none\".equals(neo4jAuth)) {\n\t\t\treturn AuthTokens.none();\n\t\t}\n\t\tif (neo4jAuth.startsWith(\"neo4j/\")) {\n\t\t\treturn AuthTokens.basic(\"neo4j\", neo4jAuth.substring(6));\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Cannot extract auth token from NEO4J_AUTH environment variable with value '\" + neo4jAuth + \"'.\"\n\t\t\t\t\t\t+ \" Value should be 'none' to disable authentication or start with 'neo4j/' to specify\"\n\t\t\t\t\t\t+ \" the neo4j user's password\");\n\t}\n\n\t@Nullable AuthToken getAuthToken() {\n\t\treturn this.authToken;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Neo4J service connections.\n */\n@NullMarked\npackage org.springframework.boot.neo4j.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/health/Neo4jHealthDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport org.neo4j.driver.Record;\nimport org.neo4j.driver.summary.ResultSummary;\n\n/**\n * Health details for a Neo4j server.\n *\n * @author Andy Wilkinson\n */\nclass Neo4jHealthDetails {\n\n\tprivate final String version;\n\n\tprivate final String edition;\n\n\tprivate final ResultSummary summary;\n\n\tNeo4jHealthDetails(Record record, ResultSummary summary) {\n\t\tthis.version = record.get(\"version\").asString();\n\t\tthis.edition = record.get(\"edition\").asString();\n\t\tthis.summary = summary;\n\t}\n\n\tString getVersion() {\n\t\treturn this.version;\n\t}\n\n\tString getEdition() {\n\t\treturn this.edition;\n\t}\n\n\tResultSummary getSummary() {\n\t\treturn this.summary;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/health/Neo4jHealthDetailsHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport org.neo4j.driver.summary.DatabaseInfo;\nimport org.neo4j.driver.summary.ResultSummary;\nimport org.neo4j.driver.summary.ServerInfo;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.util.StringUtils;\n\n/**\n * Handle health check details for a Neo4j server.\n *\n * @author Stephane Nicoll\n */\nclass Neo4jHealthDetailsHandler {\n\n\t/**\n\t * Add health details for the specified {@link ResultSummary} and {@code edition}.\n\t * @param builder the builder to use\n\t * @param healthDetails the health details of the server\n\t */\n\tvoid addHealthDetails(Health.Builder builder, Neo4jHealthDetails healthDetails) {\n\t\tResultSummary summary = healthDetails.getSummary();\n\t\tServerInfo serverInfo = summary.server();\n\t\tbuilder.up()\n\t\t\t.withDetail(\"server\", healthDetails.getVersion() + \"@\" + serverInfo.address())\n\t\t\t.withDetail(\"edition\", healthDetails.getEdition());\n\t\tDatabaseInfo databaseInfo = summary.database();\n\t\tif (StringUtils.hasText(databaseInfo.name())) {\n\t\t\tbuilder.withDetail(\"database\", databaseInfo.name());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/health/Neo4jHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.neo4j.driver.AccessMode;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Record;\nimport org.neo4j.driver.Result;\nimport org.neo4j.driver.Session;\nimport org.neo4j.driver.SessionConfig;\nimport org.neo4j.driver.exceptions.SessionExpiredException;\nimport org.neo4j.driver.summary.ResultSummary;\n\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\n\n/**\n * {@link HealthIndicator} that tests the status of a Neo4j by executing a Cypher\n * statement and extracting server and database information.\n *\n * @author Eric Spiegelberg\n * @author Stephane Nicoll\n * @author Michael J. Simons\n * @since 4.0.0\n */\npublic class Neo4jHealthIndicator extends AbstractHealthIndicator {\n\n\tprivate static final Log logger = LogFactory.getLog(Neo4jHealthIndicator.class);\n\n\t/**\n\t * The Cypher statement used to verify Neo4j is up.\n\t */\n\tstatic final String CYPHER = \"CALL dbms.components() YIELD versions, name, edition WHERE name = 'Neo4j Kernel' RETURN edition, versions[0] as version\";\n\n\t/**\n\t * Message logged before retrying a health check.\n\t */\n\tstatic final String MESSAGE_SESSION_EXPIRED = \"Neo4j session has expired, retrying one single time to retrieve server health.\";\n\n\t/**\n\t * The default session config to use while connecting.\n\t */\n\tstatic final SessionConfig DEFAULT_SESSION_CONFIG = SessionConfig.builder()\n\t\t.withDefaultAccessMode(AccessMode.WRITE)\n\t\t.build();\n\n\tprivate final Driver driver;\n\n\tprivate final Neo4jHealthDetailsHandler healthDetailsHandler;\n\n\tpublic Neo4jHealthIndicator(Driver driver) {\n\t\tsuper(\"Neo4j health check failed\");\n\t\tthis.driver = driver;\n\t\tthis.healthDetailsHandler = new Neo4jHealthDetailsHandler();\n\t}\n\n\t@Override\n\tprotected void doHealthCheck(Health.Builder builder) {\n\t\ttry {\n\t\t\ttry {\n\t\t\t\trunHealthCheckQuery(builder);\n\t\t\t}\n\t\t\tcatch (SessionExpiredException ex) {\n\t\t\t\t// Retry one time when the session has been expired\n\t\t\t\tlogger.warn(MESSAGE_SESSION_EXPIRED);\n\t\t\t\trunHealthCheckQuery(builder);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tbuilder.down().withException(ex);\n\t\t}\n\t}\n\n\tprivate void runHealthCheckQuery(Health.Builder builder) {\n\t\t// We use WRITE here to make sure UP is returned for a server that supports\n\t\t// all possible workloads\n\t\ttry (Session session = this.driver.session(DEFAULT_SESSION_CONFIG)) {\n\t\t\tResult result = session.run(CYPHER);\n\t\t\tRecord record = result.single();\n\t\t\tResultSummary resultSummary = result.consume();\n\t\t\tthis.healthDetailsHandler.addHealthDetails(builder, new Neo4jHealthDetails(record, resultSummary));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/health/Neo4jReactiveHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Record;\nimport org.neo4j.driver.exceptions.SessionExpiredException;\nimport org.neo4j.driver.reactivestreams.ReactiveResult;\nimport org.neo4j.driver.reactivestreams.ReactiveSession;\nimport org.neo4j.driver.summary.ResultSummary;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\nimport reactor.util.retry.Retry;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ReactiveHealthIndicator} that tests the status of a Neo4j by executing a Cypher\n * statement and extracting server and database information.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class Neo4jReactiveHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate static final Log logger = LogFactory.getLog(Neo4jReactiveHealthIndicator.class);\n\n\tprivate final Driver driver;\n\n\tprivate final Neo4jHealthDetailsHandler healthDetailsHandler;\n\n\tpublic Neo4jReactiveHealthIndicator(Driver driver) {\n\t\tthis.driver = driver;\n\t\tthis.healthDetailsHandler = new Neo4jHealthDetailsHandler();\n\t}\n\n\t@Override\n\tprotected Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\treturn runHealthCheckQuery()\n\t\t\t.doOnError(SessionExpiredException.class, (ex) -> logger.warn(Neo4jHealthIndicator.MESSAGE_SESSION_EXPIRED))\n\t\t\t.retryWhen(Retry.max(1).filter(SessionExpiredException.class::isInstance))\n\t\t\t.map((healthDetails) -> {\n\t\t\t\tthis.healthDetailsHandler.addHealthDetails(builder, healthDetails);\n\t\t\t\treturn builder.build();\n\t\t\t});\n\t}\n\n\tMono<Neo4jHealthDetails> runHealthCheckQuery() {\n\t\treturn Mono.using(this::session, this::healthDetails, ReactiveSession::close);\n\t}\n\n\tprivate ReactiveSession session() {\n\t\treturn this.driver.session(ReactiveSession.class, Neo4jHealthIndicator.DEFAULT_SESSION_CONFIG);\n\t}\n\n\tprivate Mono<Neo4jHealthDetails> healthDetails(ReactiveSession session) {\n\t\treturn Mono.from(session.run(Neo4jHealthIndicator.CYPHER)).flatMap(this::healthDetails);\n\t}\n\n\tprivate Mono<? extends Neo4jHealthDetails> healthDetails(ReactiveResult result) {\n\t\tFlux<Record> records = Flux.from(result.records());\n\t\tMono<ResultSummary> summary = Mono.from(result.consume());\n\t\tNeo4jHealthDetailsBuilder builder = new Neo4jHealthDetailsBuilder();\n\t\treturn records.single().doOnNext(builder::record).then(summary).map(builder::build);\n\t}\n\n\t/**\n\t * Builder used to create a {@link Neo4jHealthDetails} from a {@link Record} and a\n\t * {@link ResultSummary}.\n\t */\n\tprivate static final class Neo4jHealthDetailsBuilder {\n\n\t\tprivate @Nullable Record record;\n\n\t\tvoid record(Record record) {\n\t\t\tthis.record = record;\n\t\t}\n\n\t\tprivate Neo4jHealthDetails build(ResultSummary summary) {\n\t\t\tAssert.state(this.record != null, \"'record' must not be null\");\n\t\t\treturn new Neo4jHealthDetails(this.record, summary);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for Neo4j.\n */\n@NullMarked\npackage org.springframework.boot.neo4j.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/testcontainers/DeprecatedNeo4jContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.testcontainers;\n\nimport java.net.URI;\n\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokens;\nimport org.testcontainers.containers.Neo4jContainer;\n\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link Neo4jConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link Neo4jContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link Neo4jContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedNeo4jContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Neo4jContainer<?>, Neo4jConnectionDetails> {\n\n\tDeprecatedNeo4jContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"org.neo4j.driver.AuthToken\");\n\t}\n\n\t@Override\n\tprotected Neo4jConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<Neo4jContainer<?>> source) {\n\t\treturn new Neo4jContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link Neo4jConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class Neo4jContainerConnectionDetails extends ContainerConnectionDetails<Neo4jContainer<?>>\n\t\t\timplements Neo4jConnectionDetails {\n\n\t\tprivate Neo4jContainerConnectionDetails(ContainerConnectionSource<Neo4jContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic URI getUri() {\n\t\t\treturn URI.create(getContainer().getBoltUrl());\n\t\t}\n\n\t\t@Override\n\t\tpublic AuthToken getAuthToken() {\n\t\t\tString password = getContainer().getAdminPassword();\n\t\t\treturn (password != null) ? AuthTokens.basic(\"neo4j\", password) : AuthTokens.none();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/testcontainers/Neo4jContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.testcontainers;\n\nimport java.net.URI;\n\nimport org.neo4j.driver.AuthToken;\nimport org.neo4j.driver.AuthTokens;\nimport org.testcontainers.neo4j.Neo4jContainer;\n\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link Neo4jConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link Neo4jContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass Neo4jContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Neo4jContainer, Neo4jConnectionDetails> {\n\n\tNeo4jContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"org.neo4j.driver.AuthToken\");\n\t}\n\n\t@Override\n\tprotected Neo4jConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Neo4jContainer> source) {\n\t\treturn new Neo4jContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link Neo4jConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class Neo4jContainerConnectionDetails extends ContainerConnectionDetails<Neo4jContainer>\n\t\t\timplements Neo4jConnectionDetails {\n\n\t\tprivate Neo4jContainerConnectionDetails(ContainerConnectionSource<Neo4jContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic URI getUri() {\n\t\t\treturn URI.create(getContainer().getBoltUrl());\n\t\t}\n\n\t\t@Override\n\t\tpublic AuthToken getAuthToken() {\n\t\t\tString password = getContainer().getAdminPassword();\n\t\t\treturn (password != null) ? AuthTokens.basic(\"neo4j\", password) : AuthTokens.none();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/java/org/springframework/boot/neo4j/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Neo4J service connections.\n */\n@NullMarked\npackage org.springframework.boot.neo4j.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.health.neo4j.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Neo4j health check.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.neo4j.pool.metrics-enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"reason\": \"Use 'management.metrics.enable' to restrict certain metrics.\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.neo4j.uri\",\n      \"defaultValue\": \"bolt://localhost:7687\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration\norg.springframework.boot.neo4j.autoconfigure.health.Neo4jHealthContributorAutoConfiguration\norg.springframework.boot.neo4j.autoconfigure.observation.Neo4jObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.neo4j.docker.compose.Neo4jDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.neo4j.testcontainers.DeprecatedNeo4jContainerConnectionDetailsFactory,\\\norg.springframework.boot.neo4j.testcontainers.Neo4jContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/autoconfigure/Neo4jAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport org.neo4j.driver.AuthTokenManagers;\nimport org.neo4j.driver.AuthTokens;\nimport org.neo4j.driver.Config;\nimport org.neo4j.driver.Config.ConfigBuilder;\nimport org.neo4j.driver.Driver;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration.PropertiesNeo4jConnectionDetails;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jProperties.Authentication;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jProperties.Security.TrustStrategy;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Neo4jAutoConfiguration}.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass Neo4jAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class));\n\n\t@Test\n\tvoid driverNotConfiguredWithoutDriverApi() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.neo4j.uri=bolt://localhost:4711\")\n\t\t\t.withClassLoader(new FilteredClassLoader(Driver.class))\n\t\t\t.run((ctx) -> assertThat(ctx).doesNotHaveBean(Driver.class));\n\t}\n\n\t@Test\n\tvoid driverShouldNotRequireUri() {\n\t\tthis.contextRunner.run((ctx) -> assertThat(ctx).hasSingleBean(Driver.class));\n\t}\n\n\t@Test\n\tvoid driverShouldInvokeConfigBuilderCustomizers() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.neo4j.uri=bolt://localhost:4711\")\n\t\t\t.withBean(ConfigBuilderCustomizer.class, () -> ConfigBuilder::withEncryption)\n\t\t\t.run((ctx) -> assertThat(ctx.getBean(Driver.class).isEncrypted()).isTrue());\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"bolt\", \"neo4j\" })\n\tvoid uriWithSimpleSchemeAreDetected(String scheme) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.neo4j.uri=\" + scheme + \"://localhost:4711\").run((ctx) -> {\n\t\t\tassertThat(ctx).hasSingleBean(Driver.class);\n\t\t\tassertThat(ctx.getBean(Driver.class).isEncrypted()).isFalse();\n\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"bolt+s\", \"bolt+ssc\", \"neo4j+s\", \"neo4j+ssc\" })\n\tvoid uriWithAdvancedSchemesAreDetected(String scheme) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.neo4j.uri=\" + scheme + \"://localhost:4711\").run((ctx) -> {\n\t\t\tassertThat(ctx).hasSingleBean(Driver.class);\n\t\t\tDriver driver = ctx.getBean(Driver.class);\n\t\t\tassertThat(driver.isEncrypted()).isTrue();\n\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"bolt+routing\", \"bolt+x\", \"neo4j+wth\" })\n\tvoid uriWithInvalidSchemesAreDetected(String invalidScheme) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.neo4j.uri=\" + invalidScheme + \"://localhost:4711\")\n\t\t\t.run((ctx) -> assertThat(ctx).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasMessageContaining(\"Unsupported scheme: %s\", invalidScheme));\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesNeo4jConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner.withBean(Neo4jConnectionDetails.class, () -> new Neo4jConnectionDetails() {\n\n\t\t\t@Override\n\t\t\tpublic URI getUri() {\n\t\t\t\treturn URI.create(\"bolt+ssc://localhost:12345\");\n\t\t\t}\n\n\t\t}).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Driver.class)\n\t\t\t\t.hasSingleBean(Neo4jConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesNeo4jConnectionDetails.class);\n\t\t\tDriver driver = context.getBean(Driver.class);\n\t\t\tassertThat(driver.isEncrypted()).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid connectionTimeout() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.setConnectionTimeout(Duration.ofMillis(500));\n\t\tassertThat(mapDriverConfig(properties).connectionTimeoutMillis()).isEqualTo(500);\n\t}\n\n\t@Test\n\tvoid maxTransactionRetryTime() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.setMaxTransactionRetryTime(Duration.ofSeconds(2));\n\t\tassertThat(mapDriverConfig(properties).maxTransactionRetryTimeMillis()).isEqualTo(2000L);\n\t}\n\n\t@Test\n\tvoid uriShouldDefaultToLocalhost() {\n\t\tassertThat(new PropertiesNeo4jConnectionDetails(new Neo4jProperties(), null).getUri())\n\t\t\t.isEqualTo(URI.create(\"bolt://localhost:7687\"));\n\t}\n\n\t@Test\n\tvoid determineServerUriWithCustomUriShouldOverrideDefault() {\n\t\tURI customUri = URI.create(\"bolt://localhost:4242\");\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.setUri(customUri);\n\t\tassertThat(new PropertiesNeo4jConnectionDetails(properties, null).getUri()).isEqualTo(customUri);\n\t}\n\n\t@Test\n\tvoid authenticationShouldDefaultToNone() {\n\t\tassertThat(new PropertiesNeo4jConnectionDetails(new Neo4jProperties(), null).getAuthToken())\n\t\t\t.isEqualTo(AuthTokens.none());\n\t}\n\n\t@Test\n\tvoid authenticationWithUsernameShouldEnableBasicAuth() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getAuthentication().setUsername(\"Farin\");\n\t\tproperties.getAuthentication().setPassword(\"Urlaub\");\n\t\tPropertiesNeo4jConnectionDetails connectionDetails = new PropertiesNeo4jConnectionDetails(properties, null);\n\t\tassertThat(connectionDetails.getAuthToken()).isEqualTo(AuthTokens.basic(\"Farin\", \"Urlaub\"));\n\t\tassertThat(connectionDetails.getAuthTokenManager()).isNull();\n\t}\n\n\t@Test\n\tvoid authenticationWithUsernameAndRealmShouldEnableBasicAuth() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tAuthentication authentication = properties.getAuthentication();\n\t\tauthentication.setUsername(\"Farin\");\n\t\tauthentication.setPassword(\"Urlaub\");\n\t\tauthentication.setRealm(\"Test Realm\");\n\t\tPropertiesNeo4jConnectionDetails connectionDetails = new PropertiesNeo4jConnectionDetails(properties, null);\n\t\tassertThat(connectionDetails.getAuthToken()).isEqualTo(AuthTokens.basic(\"Farin\", \"Urlaub\", \"Test Realm\"));\n\t\tassertThat(connectionDetails.getAuthTokenManager()).isNull();\n\t}\n\n\t@Test\n\tvoid authenticationWithAuthTokenManagerAndUsernameShouldProvideAuthTokenManger() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tAuthentication authentication = properties.getAuthentication();\n\t\tauthentication.setUsername(\"Farin\");\n\t\tauthentication.setPassword(\"Urlaub\");\n\t\tauthentication.setRealm(\"Test Realm\");\n\t\tassertThat(new PropertiesNeo4jConnectionDetails(properties,\n\t\t\t\tAuthTokenManagers.bearer(\n\t\t\t\t\t\t() -> AuthTokens.basic(\"username\", \"password\").expiringAt(System.currentTimeMillis() + 5000)))\n\t\t\t.getAuthTokenManager()).isNotNull();\n\t}\n\n\t@Test\n\tvoid authenticationWithKerberosTicketShouldEnableKerberos() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tAuthentication authentication = properties.getAuthentication();\n\t\tauthentication.setKerberosTicket(\"AABBCCDDEE\");\n\t\tassertThat(new PropertiesNeo4jConnectionDetails(properties, null).getAuthToken())\n\t\t\t.isEqualTo(AuthTokens.kerberos(\"AABBCCDDEE\"));\n\t}\n\n\t@Test\n\tvoid authenticationWithBothUsernameAndKerberosShouldNotBeAllowed() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tAuthentication authentication = properties.getAuthentication();\n\t\tauthentication.setUsername(\"Farin\");\n\t\tauthentication.setKerberosTicket(\"AABBCCDDEE\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new PropertiesNeo4jConnectionDetails(properties, null).getAuthToken())\n\t\t\t.withMessage(\"Cannot specify both username ('Farin') and kerberos ticket ('AABBCCDDEE')\");\n\t}\n\n\t@Test\n\tvoid poolWithLogLeakedSessions() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getPool().setLogLeakedSessions(true);\n\t\tassertThat(mapDriverConfig(properties).logLeakedSessions()).isTrue();\n\t}\n\n\t@Test\n\tvoid poolWithMaxConnectionPoolSize() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getPool().setMaxConnectionPoolSize(4711);\n\t\tassertThat(mapDriverConfig(properties).maxConnectionPoolSize()).isEqualTo(4711);\n\t}\n\n\t@Test\n\tvoid poolWithIdleTimeBeforeConnectionTest() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getPool().setIdleTimeBeforeConnectionTest(Duration.ofSeconds(23));\n\t\tassertThat(mapDriverConfig(properties).idleTimeBeforeConnectionTest()).isEqualTo(23000);\n\t}\n\n\t@Test\n\tvoid poolWithMaxConnectionLifetime() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getPool().setMaxConnectionLifetime(Duration.ofSeconds(30));\n\t\tassertThat(mapDriverConfig(properties).maxConnectionLifetimeMillis()).isEqualTo(30000);\n\t}\n\n\t@Test\n\tvoid poolWithConnectionAcquisitionTimeout() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getPool().setConnectionAcquisitionTimeout(Duration.ofSeconds(5));\n\t\tassertThat(mapDriverConfig(properties).connectionAcquisitionTimeoutMillis()).isEqualTo(5000);\n\t}\n\n\t@Test\n\tvoid securityWithEncrypted() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setEncrypted(true);\n\t\tassertThat(mapDriverConfig(properties).encrypted()).isTrue();\n\t}\n\n\t@Test\n\tvoid securityWithTrustSignedCertificates() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);\n\t\tassertThat(mapDriverConfig(properties).trustStrategy().strategy())\n\t\t\t.isEqualTo(Config.TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);\n\t}\n\n\t@Test\n\tvoid securityWithTrustAllCertificates() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_ALL_CERTIFICATES);\n\t\tassertThat(mapDriverConfig(properties).trustStrategy().strategy())\n\t\t\t.isEqualTo(Config.TrustStrategy.Strategy.TRUST_ALL_CERTIFICATES);\n\t}\n\n\t@Test\n\tvoid securityWitHostnameVerificationEnabled() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_ALL_CERTIFICATES);\n\t\tproperties.getSecurity().setHostnameVerificationEnabled(true);\n\t\tassertThat(mapDriverConfig(properties).trustStrategy().isHostnameVerificationEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid securityWithCustomCertificates(@TempDir File directory) throws IOException {\n\t\tFile certFile = new File(directory, \"neo4j-driver.cert\");\n\t\tassertThat(certFile.createNewFile()).isTrue();\n\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);\n\t\tproperties.getSecurity().setCertFile(certFile);\n\t\tConfig.TrustStrategy trustStrategy = mapDriverConfig(properties).trustStrategy();\n\t\tassertThat(trustStrategy.strategy())\n\t\t\t.isEqualTo(Config.TrustStrategy.Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);\n\t\tassertThat(trustStrategy.certFiles()).containsOnly(certFile);\n\t}\n\n\t@Test\n\tvoid securityWithCustomCertificatesShouldFailWithoutCertificate() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES);\n\t\tassertThatExceptionOfType(InvalidConfigurationPropertyValueException.class)\n\t\t\t.isThrownBy(() -> mapDriverConfig(properties))\n\t\t\t.withMessage(\n\t\t\t\t\t\"Property spring.neo4j.security.trust-strategy with value 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' is invalid: Configured trust strategy requires a certificate file.\");\n\t}\n\n\t@Test\n\tvoid securityWithTrustSystemCertificates() {\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tproperties.getSecurity().setTrustStrategy(TrustStrategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);\n\t\tassertThat(mapDriverConfig(properties).trustStrategy().strategy())\n\t\t\t.isEqualTo(Config.TrustStrategy.Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES);\n\t}\n\n\tprivate Config mapDriverConfig(Neo4jProperties properties, ConfigBuilderCustomizer... customizers) {\n\t\treturn new Neo4jAutoConfiguration().mapDriverConfig(properties,\n\t\t\t\tnew PropertiesNeo4jConnectionDetails(properties, null), Arrays.asList(customizers));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/autoconfigure/Neo4jPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Config;\nimport org.neo4j.driver.internal.retry.RetrySettings;\n\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jProperties.Pool;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Neo4jProperties}.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n */\nclass Neo4jPropertiesTests {\n\n\t@Test\n\tvoid poolSettingsHaveConsistentDefaults() {\n\t\tConfig defaultConfig = Config.defaultConfig();\n\t\tPool pool = new Neo4jProperties().getPool();\n\t\tassertThat(pool.isLogLeakedSessions()).isEqualTo(defaultConfig.logLeakedSessions());\n\t\tassertThat(pool.getMaxConnectionPoolSize()).isEqualTo(defaultConfig.maxConnectionPoolSize());\n\t\tassertDuration(pool.getIdleTimeBeforeConnectionTest(), defaultConfig.idleTimeBeforeConnectionTest());\n\t\tassertDuration(pool.getMaxConnectionLifetime(), defaultConfig.maxConnectionLifetimeMillis());\n\t\tassertDuration(pool.getConnectionAcquisitionTimeout(), defaultConfig.connectionAcquisitionTimeoutMillis());\n\t}\n\n\t@Test\n\tvoid securitySettingsHaveConsistentDefaults() {\n\t\tConfig defaultConfig = Config.defaultConfig();\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tassertThat(properties.getSecurity().isEncrypted()).isEqualTo(defaultConfig.encrypted());\n\t\tassertThat(properties.getSecurity().getTrustStrategy().name())\n\t\t\t.isEqualTo(defaultConfig.trustStrategy().strategy().name());\n\t\tassertThat(properties.getSecurity().isHostnameVerificationEnabled())\n\t\t\t.isEqualTo(defaultConfig.trustStrategy().isHostnameVerificationEnabled());\n\t}\n\n\t@Test\n\tvoid driverSettingsHaveConsistentDefaults() {\n\t\tConfig defaultConfig = Config.defaultConfig();\n\t\tNeo4jProperties properties = new Neo4jProperties();\n\t\tassertDuration(properties.getConnectionTimeout(), defaultConfig.connectionTimeoutMillis());\n\t\tassertDuration(properties.getMaxTransactionRetryTime(), RetrySettings.DEFAULT.maxRetryTimeMs());\n\t}\n\n\tprivate static void assertDuration(@Nullable Duration duration, long expectedValueInMillis) {\n\t\tif (expectedValueInMillis == -1) {\n\t\t\tassertThat(duration).isNull();\n\t\t}\n\t\telse {\n\t\t\tassertThat(duration).isNotNull();\n\t\t\tassertThat(duration.toMillis()).isEqualTo(expectedValueInMillis);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/autoconfigure/health/Neo4jHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.contributor.AbstractHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.neo4j.health.Neo4jHealthIndicator;\nimport org.springframework.boot.neo4j.health.Neo4jReactiveHealthIndicator;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Neo4jHealthContributorAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Michael J. Simons\n */\nclass Neo4jHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tNeo4jHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateHealthIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(Neo4jConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jReactiveHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(Neo4jHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWithoutReactorShouldCreateHealthIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(Neo4jConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(Flux.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(Neo4jHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(Neo4jReactiveHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withUserConfiguration(Neo4jConfiguration.class)\n\t\t\t.withPropertyValues(\"management.health.neo4j.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Neo4jHealthIndicator.class)\n\t\t\t\t.doesNotHaveBean(Neo4jReactiveHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid defaultIndicatorCanBeReplaced() {\n\t\tthis.contextRunner.withUserConfiguration(Neo4jConfiguration.class, CustomIndicatorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"neo4jHealthIndicator\");\n\t\t\t\tHealth health = context.getBean(\"neo4jHealthIndicator\", HealthIndicator.class).health();\n\t\t\t\tassertThat(health).isNotNull();\n\t\t\t\tassertThat(health.getDetails()).containsOnly(entry(\"test\", true));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRequireDriverBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(Neo4jHealthIndicator.class)\n\t\t\t.doesNotHaveBean(Neo4jReactiveHealthIndicator.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Neo4jConfiguration {\n\n\t\t@Bean\n\t\tDriver driver() {\n\t\t\treturn mock(Driver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomIndicatorConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator neo4jHealthIndicator() {\n\t\t\treturn new AbstractHealthIndicator() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doHealthCheck(Health.Builder builder) {\n\t\t\t\t\tbuilder.up().withDetail(\"test\", true);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/autoconfigure/observation/Neo4jObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.autoconfigure.observation;\n\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.internal.observation.NoopObservationProvider;\nimport org.neo4j.driver.observation.micrometer.MicrometerObservationProvider;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.neo4j.autoconfigure.Neo4jAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Neo4jObservationAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass Neo4jObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(Neo4jObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid whenThereIsAnObservationRegistryThenMicrometerObservationProviderIsAdded() {\n\t\tthis.contextRunner.withBean(TestObservationRegistry.class, TestObservationRegistry::create)\n\t\t\t.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(Driver.class)).extracting(\"observationProvider\")\n\t\t\t\t.isInstanceOf(MicrometerObservationProvider.class));\n\t}\n\n\t@Test\n\tvoid whenThereIsNoObservationRegistryThenConfigBuilderCustomizationBacksOff() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(Driver.class)).extracting(\"observationProvider\")\n\t\t\t\t.isInstanceOf(NoopObservationProvider.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/docker/compose/Neo4jEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.AuthTokens;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Neo4jEnvironment}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\nclass Neo4jEnvironmentTests {\n\n\t@Test\n\tvoid whenNeo4jAuthAndPasswordAreNullThenAuthTokenIsNull() {\n\t\tNeo4jEnvironment environment = new Neo4jEnvironment(Collections.emptyMap());\n\t\tassertThat(environment.getAuthToken()).isNull();\n\t}\n\n\t@Test\n\tvoid whenNeo4jAuthIsNoneThenAuthTokenIsNone() {\n\t\tNeo4jEnvironment environment = new Neo4jEnvironment(Map.of(\"NEO4J_AUTH\", \"none\"));\n\t\tassertThat(environment.getAuthToken()).isEqualTo(AuthTokens.none());\n\t}\n\n\t@Test\n\tvoid whenNeo4jAuthIsNeo4jSlashPasswordThenAuthTokenIsBasic() {\n\t\tNeo4jEnvironment environment = new Neo4jEnvironment(Map.of(\"NEO4J_AUTH\", \"neo4j/custom-password\"));\n\t\tassertThat(environment.getAuthToken()).isEqualTo(AuthTokens.basic(\"neo4j\", \"custom-password\"));\n\t}\n\n\t@Test\n\tvoid whenNeo4jAuthIsNeitherNoneNorNeo4jSlashPasswordEnvironmentCreationThrows() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new Neo4jEnvironment(Map.of(\"NEO4J_AUTH\", \"graphdb/custom-password\")));\n\t}\n\n\t@Test\n\tvoid whenNeo4jPasswordIsProvidedThenAuthTokenIsBasic() {\n\t\tNeo4jEnvironment environment = new Neo4jEnvironment(Map.of(\"NEO4J_PASSWORD\", \"custom-password\"));\n\t\tassertThat(environment.getAuthToken()).isEqualTo(AuthTokens.basic(\"neo4j\", \"custom-password\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/health/Neo4jHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Record;\nimport org.neo4j.driver.Result;\nimport org.neo4j.driver.Session;\nimport org.neo4j.driver.SessionConfig;\nimport org.neo4j.driver.Values;\nimport org.neo4j.driver.exceptions.ServiceUnavailableException;\nimport org.neo4j.driver.exceptions.SessionExpiredException;\nimport org.neo4j.driver.summary.ResultSummary;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link Neo4jHealthIndicator}.\n *\n * @author Eric Spiegelberg\n * @author Stephane Nicoll\n * @author Michael Simons\n */\nclass Neo4jHealthIndicatorTests {\n\n\t@Test\n\tvoid neo4jIsUp() {\n\t\tResultSummary resultSummary = ResultSummaryMock.createResultSummary(\"My Home\", \"test\");\n\t\tDriver driver = mockDriver(resultSummary, \"4711\", \"ultimate collectors edition\");\n\t\tHealth health = new Neo4jHealthIndicator(driver).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"server\", \"4711@My Home\");\n\t\tassertThat(health.getDetails()).containsEntry(\"database\", \"test\");\n\t\tassertThat(health.getDetails()).containsEntry(\"edition\", \"ultimate collectors edition\");\n\t}\n\n\t@Test\n\tvoid neo4jIsUpWithoutDatabaseName() {\n\t\tResultSummary resultSummary = ResultSummaryMock.createResultSummary(\"My Home\", null);\n\t\tDriver driver = mockDriver(resultSummary, \"4711\", \"some edition\");\n\t\tHealth health = new Neo4jHealthIndicator(driver).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"server\", \"4711@My Home\");\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"database\");\n\t\tassertThat(health.getDetails()).containsEntry(\"edition\", \"some edition\");\n\t}\n\n\t@Test\n\tvoid neo4jIsUpWithEmptyDatabaseName() {\n\t\tResultSummary resultSummary = ResultSummaryMock.createResultSummary(\"My Home\", \"\");\n\t\tDriver driver = mockDriver(resultSummary, \"4711\", \"some edition\");\n\t\tHealth health = new Neo4jHealthIndicator(driver).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"server\", \"4711@My Home\");\n\t\tassertThat(health.getDetails()).doesNotContainKey(\"database\");\n\t\tassertThat(health.getDetails()).containsEntry(\"edition\", \"some edition\");\n\t}\n\n\t@Test\n\tvoid neo4jIsUpWithOneSessionExpiredException() {\n\t\tResultSummary resultSummary = ResultSummaryMock.createResultSummary(\"My Home\", \"\");\n\t\tSession session = mock(Session.class);\n\t\tResult statementResult = mockStatementResult(resultSummary, \"4711\", \"some edition\");\n\t\tAtomicInteger count = new AtomicInteger();\n\t\tgiven(session.run(anyString())).will((invocation) -> {\n\t\t\tif (count.compareAndSet(0, 1)) {\n\t\t\t\tthrow new SessionExpiredException(\"Session expired\");\n\t\t\t}\n\t\t\treturn statementResult;\n\t\t});\n\t\tDriver driver = mock(Driver.class);\n\t\tgiven(driver.session(any(SessionConfig.class))).willReturn(session);\n\t\tNeo4jHealthIndicator healthIndicator = new Neo4jHealthIndicator(driver);\n\t\tHealth health = healthIndicator.health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\tassertThat(health.getDetails()).containsEntry(\"server\", \"4711@My Home\");\n\t\tthen(session).should(times(2)).close();\n\t}\n\n\t@Test\n\tvoid neo4jIsDown() {\n\t\tDriver driver = mock(Driver.class);\n\t\tgiven(driver.session(any(SessionConfig.class))).willThrow(ServiceUnavailableException.class);\n\t\tHealth health = new Neo4jHealthIndicator(driver).health();\n\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\tassertThat(health.getDetails()).containsKeys(\"error\");\n\t}\n\n\tprivate Result mockStatementResult(ResultSummary resultSummary, String version, String edition) {\n\t\tRecord record = mock(Record.class);\n\t\tgiven(record.get(\"edition\")).willReturn(Values.value(edition));\n\t\tgiven(record.get(\"version\")).willReturn(Values.value(version));\n\t\tResult statementResult = mock(Result.class);\n\t\tgiven(statementResult.single()).willReturn(record);\n\t\tgiven(statementResult.consume()).willReturn(resultSummary);\n\t\treturn statementResult;\n\t}\n\n\tprivate Driver mockDriver(ResultSummary resultSummary, String version, String edition) {\n\t\tResult statementResult = mockStatementResult(resultSummary, version, edition);\n\t\tSession session = mock(Session.class);\n\t\tgiven(session.run(anyString())).willReturn(statementResult);\n\t\tDriver driver = mock(Driver.class);\n\t\tgiven(driver.session(any(SessionConfig.class))).willReturn(session);\n\t\treturn driver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/health/Neo4jReactiveHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport java.time.Duration;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.Driver;\nimport org.neo4j.driver.Record;\nimport org.neo4j.driver.SessionConfig;\nimport org.neo4j.driver.Values;\nimport org.neo4j.driver.exceptions.ServiceUnavailableException;\nimport org.neo4j.driver.exceptions.SessionExpiredException;\nimport org.neo4j.driver.reactivestreams.ReactiveResult;\nimport org.neo4j.driver.reactivestreams.ReactiveSession;\nimport org.neo4j.driver.summary.ResultSummary;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link Neo4jReactiveHealthIndicator}.\n *\n * @author Michael J. Simons\n * @author Stephane Nicoll\n * @author Brian Clozel\n */\nclass Neo4jReactiveHealthIndicatorTests {\n\n\t@Test\n\tvoid neo4jIsUp() {\n\t\tResultSummary resultSummary = ResultSummaryMock.createResultSummary(\"My Home\", \"test\");\n\t\tDriver driver = mockDriver(resultSummary, \"4711\", \"ultimate collectors edition\");\n\t\tNeo4jReactiveHealthIndicator healthIndicator = new Neo4jReactiveHealthIndicator(driver);\n\t\thealthIndicator.health().as(StepVerifier::create).consumeNextWith((health) -> {\n\t\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(health.getDetails()).containsEntry(\"server\", \"4711@My Home\");\n\t\t\tassertThat(health.getDetails()).containsEntry(\"edition\", \"ultimate collectors edition\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid neo4jIsUpWithOneSessionExpiredException() {\n\t\tResultSummary resultSummary = ResultSummaryMock.createResultSummary(\"My Home\", \"\");\n\t\tReactiveSession session = mock(ReactiveSession.class);\n\t\tReactiveResult statementResult = mockStatementResult(resultSummary, \"4711\", \"some edition\");\n\t\tAtomicInteger count = new AtomicInteger();\n\t\tgiven(session.run(anyString())).will((invocation) -> {\n\t\t\tif (count.compareAndSet(0, 1)) {\n\t\t\t\treturn Flux.error(new SessionExpiredException(\"Session expired\"));\n\t\t\t}\n\t\t\treturn Flux.just(statementResult);\n\t\t});\n\t\tDriver driver = mock(Driver.class);\n\t\tgiven(driver.session(eq(ReactiveSession.class), any(SessionConfig.class))).willReturn(session);\n\t\tNeo4jReactiveHealthIndicator healthIndicator = new Neo4jReactiveHealthIndicator(driver);\n\t\thealthIndicator.health().as(StepVerifier::create).consumeNextWith((health) -> {\n\t\t\tassertThat(health.getStatus()).isEqualTo(Status.UP);\n\t\t\tassertThat(health.getDetails()).containsEntry(\"server\", \"4711@My Home\");\n\t\t\tassertThat(health.getDetails()).containsEntry(\"edition\", \"some edition\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\tthen(session).should(times(2)).close();\n\t}\n\n\t@Test\n\tvoid neo4jIsDown() {\n\t\tDriver driver = mock(Driver.class);\n\t\tgiven(driver.session(eq(ReactiveSession.class), any(SessionConfig.class)))\n\t\t\t.willThrow(ServiceUnavailableException.class);\n\t\tNeo4jReactiveHealthIndicator healthIndicator = new Neo4jReactiveHealthIndicator(driver);\n\t\thealthIndicator.health().as(StepVerifier::create).consumeNextWith((health) -> {\n\t\t\tassertThat(health.getStatus()).isEqualTo(Status.DOWN);\n\t\t\tassertThat(health.getDetails()).containsKeys(\"error\");\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\tprivate ReactiveResult mockStatementResult(ResultSummary resultSummary, String version, String edition) {\n\t\tRecord record = mock(Record.class);\n\t\tgiven(record.get(\"edition\")).willReturn(Values.value(edition));\n\t\tgiven(record.get(\"version\")).willReturn(Values.value(version));\n\t\tReactiveResult statementResult = mock(ReactiveResult.class);\n\t\tgiven(statementResult.records()).willReturn(Mono.just(record));\n\t\tgiven(statementResult.consume()).willReturn(Mono.just(resultSummary));\n\t\treturn statementResult;\n\t}\n\n\tprivate Driver mockDriver(ResultSummary resultSummary, String version, String edition) {\n\t\tReactiveResult statementResult = mockStatementResult(resultSummary, version, edition);\n\t\tReactiveSession session = mock(ReactiveSession.class);\n\t\tgiven(session.run(anyString())).willReturn(Mono.just(statementResult));\n\t\tDriver driver = mock(Driver.class);\n\t\tgiven(driver.session(eq(ReactiveSession.class), any(SessionConfig.class))).willReturn(session);\n\t\treturn driver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/health/ResultSummaryMock.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.health;\n\nimport org.jspecify.annotations.Nullable;\nimport org.neo4j.driver.summary.DatabaseInfo;\nimport org.neo4j.driver.summary.ResultSummary;\nimport org.neo4j.driver.summary.ServerInfo;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test utility to mock {@link ResultSummary}.\n *\n * @author Stephane Nicoll\n */\nfinal class ResultSummaryMock {\n\n\tprivate ResultSummaryMock() {\n\t}\n\n\tstatic ResultSummary createResultSummary(String serverAddress, @Nullable String databaseName) {\n\t\tServerInfo serverInfo = mock(ServerInfo.class);\n\t\tgiven(serverInfo.address()).willReturn(serverAddress);\n\t\tDatabaseInfo databaseInfo = mock(DatabaseInfo.class);\n\t\tgiven(databaseInfo.name()).willReturn(databaseName);\n\t\tResultSummary resultSummary = mock(ResultSummary.class);\n\t\tgiven(resultSummary.server()).willReturn(serverInfo);\n\t\tgiven(resultSummary.database()).willReturn(databaseInfo);\n\t\treturn resultSummary;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-neo4j/src/test/java/org/springframework/boot/neo4j/testcontainers/Neo4jContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.neo4j.testcontainers;\n\nimport org.junit.jupiter.api.Test;\nimport org.neo4j.driver.AuthToken;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Neo4jContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass Neo4jContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(AuthToken.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-netty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Netty\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\n\timplementation(\"io.netty:netty-common\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-netty/src/main/java/org/springframework/boot/netty/autoconfigure/NettyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.netty.autoconfigure;\n\nimport io.netty.util.NettyRuntime;\nimport io.netty.util.ResourceLeakDetector;\n\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Netty.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(NettyRuntime.class)\n@EnableConfigurationProperties(NettyProperties.class)\npublic final class NettyAutoConfiguration {\n\n\tNettyAutoConfiguration(NettyProperties properties) {\n\t\tif (properties.getLeakDetection() != null) {\n\t\t\tNettyProperties.LeakDetection leakDetection = properties.getLeakDetection();\n\t\t\tResourceLeakDetector.setLevel(ResourceLeakDetector.Level.valueOf(leakDetection.name()));\n\t\t}\n\t}\n\n\t@Bean\n\tstatic LazyInitializationExcludeFilter nettyAutoConfigurationLazyInitializationExcludeFilter() {\n\t\treturn LazyInitializationExcludeFilter.forBeanTypes(NettyAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-netty/src/main/java/org/springframework/boot/netty/autoconfigure/NettyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.netty.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for the Netty engine.\n * <p>\n * These properties apply globally to the Netty library, used as a client or a server.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.netty\")\npublic class NettyProperties {\n\n\t/**\n\t * Level of leak detection for reference-counted buffers. If not configured via\n\t * 'ResourceLeakDetector.setLevel' or the 'io.netty.leakDetection.level' system\n\t * property, default to 'simple'.\n\t */\n\tprivate @Nullable LeakDetection leakDetection;\n\n\tpublic @Nullable LeakDetection getLeakDetection() {\n\t\treturn this.leakDetection;\n\t}\n\n\tpublic void setLeakDetection(@Nullable LeakDetection leakDetection) {\n\t\tthis.leakDetection = leakDetection;\n\t}\n\n\tpublic enum LeakDetection {\n\n\t\t/**\n\t\t * Disable leak detection completely.\n\t\t */\n\t\tDISABLED,\n\n\t\t/**\n\t\t * Detect leaks for 1% of buffers.\n\t\t */\n\t\tSIMPLE,\n\n\t\t/**\n\t\t * Detect leaks for 1% of buffers and track where they were accessed.\n\t\t */\n\t\tADVANCED,\n\n\t\t/**\n\t\t * Detect leaks for 100% of buffers and track where they were accessed.\n\t\t */\n\t\tPARANOID\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-netty/src/main/java/org/springframework/boot/netty/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for the Netty library.\n */\n@NullMarked\npackage org.springframework.boot.netty.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-netty/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-netty/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.netty.autoconfigure.NettyAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-netty/src/test/java/org/springframework/boot/netty/autoconfigure/NettyAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.netty.autoconfigure;\n\nimport io.netty.util.ResourceLeakDetector;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NettyAutoConfiguration}.\n *\n * @author Brian Clozel\n */\nclass NettyAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(NettyAutoConfiguration.class));\n\n\t@AfterEach\n\tvoid resetResourceLeakDetector() {\n\t\tResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED);\n\t}\n\n\t@Test\n\tvoid leakDetectionShouldBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.netty.leak-detection=paranoid\")\n\t\t\t.run((context) -> assertThat(ResourceLeakDetector.getLevel())\n\t\t\t\t.isEqualTo(ResourceLeakDetector.Level.PARANOID));\n\t}\n\n\t@Test\n\tvoid leakDetectionShouldBeConfiguredWhenLazyInitializationIsEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withInitializer(\n\t\t\t\t\t(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))\n\t\t\t.withPropertyValues(\"spring.netty.leak-detection=advanced\")\n\t\t\t.run((context) -> assertThat(ResourceLeakDetector.getLevel())\n\t\t\t\t.isEqualTo(ResourceLeakDetector.Level.ADVANCED));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-netty/src/test/java/org/springframework/boot/netty/autoconfigure/NettyPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.netty.autoconfigure;\n\nimport io.netty.util.ResourceLeakDetector;\nimport io.netty.util.ResourceLeakDetector.Level;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NettyProperties}\n *\n * @author Brian Clozel\n */\nclass NettyPropertiesTests {\n\n\t@Test\n\tvoid defaultValueShouldBeConsistent() {\n\t\tResourceLeakDetector.Level defaultLevel = (Level) ReflectionTestUtils.getField(ResourceLeakDetector.class,\n\t\t\t\t\"DEFAULT_LEVEL\");\n\t\tassertThat(defaultLevel).isEqualTo(Level.SIMPLE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Open Telemetry\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"io.opentelemetry:opentelemetry-api\")\n\tapi(\"io.opentelemetry:opentelemetry-sdk\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"io.opentelemetry:opentelemetry-exporter-otlp\")\n\toptional(\"org.testcontainers:testcontainers-grafana\")\n\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.grpc:grpc-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/java/org/springframework/boot/opentelemetry/docker/compose/GrafanaOtlpLoggingDockerComposeConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OtlpLoggingDockerComposeConnectionDetailsFactory} using\n * {@link TestImage#GRAFANA_OTEL_LGTM}.\n *\n * @author Eddú Meléndez\n */\nclass GrafanaOtlpLoggingDockerComposeConnectionDetailsFactoryTests {\n\n\t@DockerComposeTest(composeFile = \"otlp-compose.yaml\", image = TestImage.GRAFANA_OTEL_LGTM)\n\tvoid runCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"http://\").endsWith(\"/v1/logs\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"http://\").endsWith(\"/v1/logs\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"otlp-ssl-compose.yaml\", image = TestImage.GRAFANA_OTEL_LGTM,\n\t\t\tadditionalResources = \"ca.crt\")\n\tvoid runWithSslCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"https://\").endsWith(\"/v1/logs\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"https://\").endsWith(\"/v1/logs\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/java/org/springframework/boot/opentelemetry/docker/compose/OtelCollectorOtlpLoggingDockerComposeConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OtlpLoggingDockerComposeConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\nclass OtelCollectorOtlpLoggingDockerComposeConnectionDetailsFactoryTests {\n\n\t@DockerComposeTest(composeFile = \"otlp-compose.yaml\", image = TestImage.OTEL_COLLECTOR)\n\tvoid runCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"http://\").endsWith(\"/v1/logs\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"http://\").endsWith(\"/v1/logs\");\n\t\tassertThat(connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@DockerComposeTest(composeFile = \"otlp-ssl-compose.yaml\", image = TestImage.OTEL_COLLECTOR,\n\t\t\tadditionalResources = \"ca.crt\")\n\tvoid runWithSslCreatesConnectionDetails(OtlpLoggingConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).startsWith(\"https://\").endsWith(\"/v1/logs\");\n\t\tassertThat(connectionDetails.getUrl(Transport.GRPC)).startsWith(\"https://\").endsWith(\"/v1/logs\");\n\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\tassertThat(sslBundle).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/java/org/springframework/boot/opentelemetry/testcontainers/GrafanaOtlpLoggingContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.testcontainers;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.grafana.LgtmStackContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link GrafanaOtlpLoggingContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass GrafanaOtlpLoggingContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final LgtmStackContainer container = TestImage.container(LgtmStackContainer.class);\n\n\t@Autowired\n\tprivate OtlpLoggingConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToOpenTelemetryContainer() {\n\t\tassertThat(this.connectionDetails.getUrl(Transport.GRPC))\n\t\t\t.isEqualTo(\"%s/v1/logs\".formatted(container.getOtlpGrpcUrl()));\n\t\tassertThat(this.connectionDetails.getUrl(Transport.HTTP))\n\t\t\t.isEqualTo(\"%s/v1/logs\".formatted(container.getOtlpHttpUrl()));\n\t\tassertThat(this.connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(OtlpLoggingAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/java/org/springframework/boot/opentelemetry/testcontainers/OtelCollectorOltpLoggingContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.testcontainers;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OtelCollectorOltpLoggingContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass OtelCollectorOltpLoggingContainerConnectionDetailsFactoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final GenericContainer<?> container = TestImage.OTEL_COLLECTOR.genericContainer()\n\t\t.withExposedPorts(4317, 4318);\n\n\t@Autowired\n\tprivate OtlpLoggingConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToOpenTelemetryContainer() {\n\t\tassertThat(this.connectionDetails.getUrl(Transport.HTTP))\n\t\t\t.isEqualTo(\"http://\" + container.getHost() + \":\" + container.getMappedPort(4318) + \"/v1/logs\");\n\t\tassertThat(this.connectionDetails.getUrl(Transport.GRPC))\n\t\t\t.isEqualTo(\"http://\" + container.getHost() + \":\" + container.getMappedPort(4317) + \"/v1/logs\");\n\t\tassertThat(this.connectionDetails.getSslBundle()).isNull();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(OtlpLoggingAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/resources/org/springframework/boot/opentelemetry/docker/compose/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/resources/org/springframework/boot/opentelemetry/docker/compose/otlp-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/dockerTest/resources/org/springframework/boot/opentelemetry/docker/compose/otlp-ssl-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n    labels:\n      - 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/ConditionalOnEnabledOpenTelemetry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether OpenTelemetry is enabled. It\n * matches if the value of the {@code management.opentelemetry.enabled} property is\n * {@code true} or if it is not configured.\n *\n * @author Moritz Halbritter\n * @since 4.1.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ConditionalOnBooleanProperty(name = \"management.opentelemetry.enabled\", matchIfMissing = true)\npublic @interface ConditionalOnEnabledOpenTelemetry {\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryEnvironmentVariableEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.env.OriginTrackedMapPropertySource;\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryEnvironmentVariables.EnvVariable;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Converts OpenTelemetry SDK environment variables into Spring Boot properties.\n * <p>\n * Can be disabled by setting {@code management.opentelemetry.map-environment-variables}\n * to {@code false}.\n *\n * @author Moritz Halbritter\n * @since 4.1.0\n */\npublic class OpenTelemetryEnvironmentVariableEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\tprivate static final String ENABLED_PROPERTY = \"management.opentelemetry.map-environment-variables\";\n\n\tprivate final Log logger;\n\n\tprivate final OpenTelemetryEnvironmentVariables environmentVariables;\n\n\tpublic OpenTelemetryEnvironmentVariableEnvironmentPostProcessor(DeferredLogFactory logFactory) {\n\t\tthis(logFactory, OpenTelemetryEnvironmentVariables.forSystemEnv(logFactory));\n\t}\n\n\tOpenTelemetryEnvironmentVariableEnvironmentPostProcessor(DeferredLogFactory logFactory,\n\t\t\tOpenTelemetryEnvironmentVariables environmentVariables) {\n\t\tthis.logger = logFactory.getLog(OpenTelemetryEnvironmentVariableEnvironmentPostProcessor.class);\n\t\tthis.environmentVariables = environmentVariables;\n\t}\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (!environment.getProperty(ENABLED_PROPERTY, Boolean.class, true)) {\n\t\t\treturn;\n\t\t}\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tmapEnabled(map);\n\t\tmapPropagators(map);\n\t\tmapSampler(map);\n\t\tmapMetricsEnvironmentVariables(map);\n\t\tmapTracesEnvironmentVariables(map);\n\t\tmapLogsEnvironmentVariables(map);\n\t\tif (map.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new OriginTrackedMapPropertySource(\"openTelemetryEnvironmentVariables\", map));\n\t}\n\n\tprivate void mapEnabled(Map<String, OriginTrackedValue> map) {\n\t\tthis.environmentVariables.getBoolean(\"OTEL_SDK_DISABLED\")\n\t\t\t.addToMap(map, \"management.opentelemetry.enabled\", this::mapDisabledFlag);\n\t}\n\n\tprivate void mapSampler(Map<String, OriginTrackedValue> map) {\n\t\tthis.environmentVariables.getString(\"OTEL_TRACES_SAMPLER\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.sampler\", this::mapSamplerType);\n\t\tthis.environmentVariables.getString(\"OTEL_TRACES_SAMPLER_ARG\")\n\t\t\t.addToMap(map, \"management.tracing.sampling.probability\", this::mapSamplerProbability);\n\t}\n\n\tprivate void mapPropagators(Map<String, OriginTrackedValue> map) {\n\t\tthis.environmentVariables.getString(\"OTEL_PROPAGATORS\")\n\t\t\t.addListToMap(map, \"management.tracing.propagation.type\", this::mapPropagationType);\n\t\tthis.environmentVariables.getString(\"OTEL_PROPAGATORS\")\n\t\t\t.addToMap(map, \"management.tracing.baggage.enabled\", this::mapBaggageEnabled);\n\t}\n\n\tprivate void mapMetricsEnvironmentVariables(Map<String, OriginTrackedValue> map) {\n\t\tthis.environmentVariables\n\t\t\t.getString(\"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT\", \"OTEL_EXPORTER_OTLP_ENDPOINT\",\n\t\t\t\t\t(value) -> combineUrl(value, \"v1/metrics\"))\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.url\");\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE\")\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.aggregation-temporality\", this::mapAggregationTemporality);\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION\")\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.histogram-flavor\", this::mapHistogramFlavor);\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_METRICS_COMPRESSION\", \"OTEL_EXPORTER_OTLP_COMPRESSION\")\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.compression-mode\", this::mapCompression);\n\t\tthis.environmentVariables.getTimeout(\"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT\", \"OTEL_EXPORTER_OTLP_TIMEOUT\")\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.read-timeout\");\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_METRICS_HEADERS\", \"OTEL_EXPORTER_OTLP_HEADERS\")\n\t\t\t.addMappingToMap(map, \"management.otlp.metrics.export.headers\", this::mapHeaders);\n\t\tthis.environmentVariables.getDuration(\"OTEL_METRIC_EXPORT_INTERVAL\")\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.step\");\n\t\tthis.environmentVariables.getString(\"OTEL_METRICS_EXPORTER\")\n\t\t\t.addToMap(map, \"management.otlp.metrics.export.enabled\", this::mapExportEnabled);\n\t\tEnvVariable certificate = this.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_CERTIFICATE\");\n\t\tEnvVariable clientKey = this.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_CLIENT_KEY\");\n\t\tEnvVariable clientCertificate = this.environmentVariables\n\t\t\t.getString(\"OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE\", \"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\");\n\t\taddSslBundle(map, \"management.otlp.metrics.export.ssl.bundle\", \"opentelemetry-metrics\", certificate, clientKey,\n\t\t\t\tclientCertificate);\n\t}\n\n\tprivate void mapTracesEnvironmentVariables(Map<String, OriginTrackedValue> map) {\n\t\tthis.environmentVariables\n\t\t\t.getString(\"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", \"OTEL_EXPORTER_OTLP_ENDPOINT\",\n\t\t\t\t\t(value) -> combineUrl(value, \"v1/traces\"))\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.otlp.endpoint\");\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_TRACES_COMPRESSION\", \"OTEL_EXPORTER_OTLP_COMPRESSION\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.otlp.compression\", this::mapCompression);\n\t\tthis.environmentVariables.getTimeout(\"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", \"OTEL_EXPORTER_OTLP_TIMEOUT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.otlp.timeout\");\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"OTEL_EXPORTER_OTLP_PROTOCOL\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.otlp.transport\", this::mapProtocol);\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", \"OTEL_EXPORTER_OTLP_HEADERS\")\n\t\t\t.addMappingToMap(map, \"management.opentelemetry.tracing.export.otlp.headers\", this::mapHeaders);\n\t\tthis.environmentVariables.getDuration(\"OTEL_BSP_SCHEDULE_DELAY\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.schedule-delay\");\n\t\tthis.environmentVariables.getTimeout(\"OTEL_BSP_EXPORT_TIMEOUT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.timeout\");\n\t\tthis.environmentVariables.getInt(\"OTEL_BSP_MAX_QUEUE_SIZE\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.max-queue-size\");\n\t\tthis.environmentVariables.getInt(\"OTEL_BSP_MAX_EXPORT_BATCH_SIZE\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.export.max-batch-size\");\n\t\tthis.environmentVariables.getString(\"OTEL_TRACES_EXPORTER\")\n\t\t\t.addToMap(map, \"management.tracing.export.otlp.enabled\", this::mapExportEnabled);\n\t\tthis.environmentVariables.getInt(\"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.limits.max-attribute-value-length\");\n\t\tthis.environmentVariables.getInt(\"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT\", \"OTEL_ATTRIBUTE_COUNT_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.limits.max-attributes\");\n\t\tthis.environmentVariables.getInt(\"OTEL_SPAN_EVENT_COUNT_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.limits.max-events\");\n\t\tthis.environmentVariables.getInt(\"OTEL_SPAN_LINK_COUNT_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.limits.max-links\");\n\t\tthis.environmentVariables.getInt(\"OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.limits.max-attributes-per-event\");\n\t\tthis.environmentVariables.getInt(\"OTEL_LINK_ATTRIBUTE_COUNT_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.tracing.limits.max-attributes-per-link\");\n\t\tthis.environmentVariables.getString(\"OTEL_METRICS_EXEMPLAR_FILTER\")\n\t\t\t.addToMap(map, \"management.tracing.exemplars.include\", this::mapExemplarsInclude);\n\t\tEnvVariable certificate = this.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_CERTIFICATE\");\n\t\tEnvVariable clientKey = this.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_CLIENT_KEY\");\n\t\tEnvVariable clientCertificate = this.environmentVariables\n\t\t\t.getString(\"OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE\", \"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\");\n\t\taddSslBundle(map, \"management.opentelemetry.tracing.export.otlp.ssl.bundle\", \"opentelemetry-tracing\",\n\t\t\t\tcertificate, clientKey, clientCertificate);\n\t}\n\n\tprivate void mapLogsEnvironmentVariables(Map<String, OriginTrackedValue> map) {\n\t\tthis.environmentVariables\n\t\t\t.getString(\"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\", \"OTEL_EXPORTER_OTLP_ENDPOINT\",\n\t\t\t\t\t(value) -> combineUrl(value, \"v1/logs\"))\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.otlp.endpoint\");\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_LOGS_COMPRESSION\", \"OTEL_EXPORTER_OTLP_COMPRESSION\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.otlp.compression\", this::mapCompression);\n\t\tthis.environmentVariables.getTimeout(\"OTEL_EXPORTER_OTLP_LOGS_TIMEOUT\", \"OTEL_EXPORTER_OTLP_TIMEOUT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.otlp.timeout\");\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL\", \"OTEL_EXPORTER_OTLP_PROTOCOL\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.otlp.transport\", this::mapProtocol);\n\t\tthis.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_LOGS_HEADERS\", \"OTEL_EXPORTER_OTLP_HEADERS\")\n\t\t\t.addMappingToMap(map, \"management.opentelemetry.logging.export.otlp.headers\", this::mapHeaders);\n\t\tthis.environmentVariables.getDuration(\"OTEL_BLRP_SCHEDULE_DELAY\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.schedule-delay\");\n\t\tthis.environmentVariables.getTimeout(\"OTEL_BLRP_EXPORT_TIMEOUT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.timeout\");\n\t\tthis.environmentVariables.getInt(\"OTEL_BLRP_MAX_QUEUE_SIZE\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.max-queue-size\");\n\t\tthis.environmentVariables.getInt(\"OTEL_BLRP_MAX_EXPORT_BATCH_SIZE\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.export.max-batch-size\");\n\t\tthis.environmentVariables.getString(\"OTEL_LOGS_EXPORTER\")\n\t\t\t.addToMap(map, \"management.logging.export.otlp.enabled\", this::mapExportEnabled);\n\t\tthis.environmentVariables\n\t\t\t.getInt(\"OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.limits.max-attribute-value-length\");\n\t\tthis.environmentVariables.getInt(\"OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT\", \"OTEL_ATTRIBUTE_COUNT_LIMIT\")\n\t\t\t.addToMap(map, \"management.opentelemetry.logging.limits.max-attributes\");\n\t\tEnvVariable certificate = this.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_CERTIFICATE\");\n\t\tEnvVariable clientKey = this.environmentVariables.getString(\"OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_CLIENT_KEY\");\n\t\tEnvVariable clientCertificate = this.environmentVariables\n\t\t\t.getString(\"OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE\", \"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\");\n\t\taddSslBundle(map, \"management.opentelemetry.logging.export.otlp.ssl.bundle\", \"opentelemetry-logging\",\n\t\t\t\tcertificate, clientKey, clientCertificate);\n\t}\n\n\tprivate void addSslBundle(Map<String, OriginTrackedValue> map, String bundleKey, String bundleName,\n\t\t\tEnvVariable certificateFile, EnvVariable clientKeyFile, EnvVariable clientCertificateFile) {\n\t\tEnvVariable firstPresent = this.environmentVariables.getFirstPresent(certificateFile, clientKeyFile,\n\t\t\t\tclientCertificateFile);\n\t\tif (firstPresent == null) {\n\t\t\treturn;\n\t\t}\n\t\tmap.put(bundleKey, OriginTrackedValue.of(bundleName, this.environmentVariables.getOrigin(firstPresent)));\n\t\tif (certificateFile.isPresent()) {\n\t\t\tString value = certificateFile.value();\n\t\t\tmap.put(\"spring.ssl.bundle.pem.%s.truststore.certificate\".formatted(bundleName), OriginTrackedValue\n\t\t\t\t.of(\"file:%s\".formatted(value), this.environmentVariables.getOrigin(certificateFile)));\n\t\t}\n\t\tif (clientKeyFile.isPresent()) {\n\t\t\tString value = clientKeyFile.value();\n\t\t\tmap.put(\"spring.ssl.bundle.pem.%s.keystore.private-key\".formatted(bundleName), OriginTrackedValue\n\t\t\t\t.of(\"file:%s\".formatted(value), this.environmentVariables.getOrigin(clientKeyFile)));\n\t\t}\n\t\tif (clientCertificateFile.isPresent()) {\n\t\t\tString value = clientCertificateFile.value();\n\t\t\tmap.put(\"spring.ssl.bundle.pem.%s.keystore.certificate\".formatted(bundleName), OriginTrackedValue\n\t\t\t\t.of(\"file:%s\".formatted(value), this.environmentVariables.getOrigin(clientCertificateFile)));\n\t\t}\n\t}\n\n\tprivate @Nullable String mapDisabledFlag(String name, String value) {\n\t\t// OTEL_SDK_DISABLED: true means disabled\n\t\t// management.opentelemetry.enabled: true means enabled\n\t\treturn switch (value) {\n\t\t\tcase \"true\" -> \"false\";\n\t\t\tcase \"false\" -> \"true\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate String mapBaggageEnabled(String name, String value) {\n\t\tSet<String> propagators = toSet(value);\n\t\tif (propagators.contains(\"none\")) {\n\t\t\tif (propagators.size() > 1) {\n\t\t\t\tthis.logger.warn(\"Environment variable '%s' contains 'none', but also contains more elements: '%s'\"\n\t\t\t\t\t.formatted(name, value));\n\t\t\t}\n\t\t\treturn \"false\";\n\t\t}\n\t\treturn Boolean.toString(propagators.contains(\"baggage\"));\n\t}\n\n\tprivate List<String> mapPropagationType(String name, String value) {\n\t\tSet<String> propagators = toSet(value);\n\t\tif (propagators.contains(\"none\")) {\n\t\t\tif (propagators.size() > 1) {\n\t\t\t\tthis.logger.warn(\"Environment variable '%s' contains 'none', but also contains more elements: '%s'\"\n\t\t\t\t\t.formatted(name, value));\n\t\t\t}\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<String> result = new ArrayList<>();\n\t\tfor (String propagator : propagators) {\n\t\t\tswitch (propagator) {\n\t\t\t\tcase \"tracecontext\" -> result.add(\"W3C\");\n\t\t\t\tcase \"b3\" -> result.add(\"B3\");\n\t\t\t\tcase \"b3multi\" -> result.add(\"B3_MULTI\");\n\t\t\t\tcase \"baggage\" -> {\n\t\t\t\t}\n\t\t\t\tdefault -> this.logger\n\t\t\t\t\t.warn(\"Unsupported propagator '%s' in environment variable '%s'\".formatted(propagator, name));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate Map<String, String> mapHeaders(String name, String value) {\n\t\treturn W3CHeaderParser.parse(value);\n\t}\n\n\tprivate String mapExportEnabled(String name, String value) {\n\t\tSet<String> exporters = toSet(value);\n\t\tif (exporters.contains(\"none\")) {\n\t\t\tif (exporters.size() > 1) {\n\t\t\t\tthis.logger.warn(\"Environment variable '%s' contains 'none', but also contains more elements: '%s'\"\n\t\t\t\t\t.formatted(name, value));\n\t\t\t}\n\t\t\treturn \"false\";\n\t\t}\n\t\tif (exporters.contains(\"otlp\")) {\n\t\t\treturn \"true\";\n\t\t}\n\t\treturn \"false\";\n\t}\n\n\tprivate @Nullable String mapProtocol(String name, String value) {\n\t\treturn switch (value.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"grpc\" -> \"GRPC\";\n\t\t\tcase \"http/protobuf\" -> \"HTTP\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate @Nullable String mapExemplarsInclude(String name, String value) {\n\t\treturn switch (value.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"always_on\" -> \"ALL\";\n\t\t\tcase \"always_off\" -> \"NONE\";\n\t\t\tcase \"trace_based\" -> \"SAMPLED_TRACES\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate @Nullable String mapSamplerType(String name, String value) {\n\t\treturn switch (value.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"always_on\" -> \"ALWAYS_ON\";\n\t\t\tcase \"always_off\" -> \"ALWAYS_OFF\";\n\t\t\tcase \"traceidratio\" -> \"TRACE_ID_RATIO\";\n\t\t\tcase \"parentbased_always_on\" -> \"PARENT_BASED_ALWAYS_ON\";\n\t\t\tcase \"parentbased_always_off\" -> \"PARENT_BASED_ALWAYS_OFF\";\n\t\t\tcase \"parentbased_traceidratio\" -> \"PARENT_BASED_TRACE_ID_RATIO\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate @Nullable String mapSamplerProbability(String name, String value) {\n\t\tEnvVariable sampler = this.environmentVariables.getString(\"OTEL_TRACES_SAMPLER\");\n\t\tif (!sampler.isPresent()) {\n\t\t\treturn null;\n\t\t}\n\t\tString samplerValue = sampler.value();\n\t\tAssert.state(samplerValue != null, \"'samplerValue' must not be null\");\n\t\treturn switch (samplerValue.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"traceidratio\", \"parentbased_traceidratio\" -> {\n\t\t\t\ttry {\n\t\t\t\t\tdouble probability = Double.parseDouble(value);\n\t\t\t\t\tif (probability < 0.0 || probability > 1.0) {\n\t\t\t\t\t\tthis.logger\n\t\t\t\t\t\t\t.warn(\"Invalid value for environment variable '%s'. Must be between 0.0 and 1.0: '%s'\"\n\t\t\t\t\t\t\t\t.formatted(name, value));\n\t\t\t\t\t\tyield null;\n\t\t\t\t\t}\n\t\t\t\t\tyield String.valueOf(probability);\n\t\t\t\t}\n\t\t\t\tcatch (NumberFormatException ex) {\n\t\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\t\tyield null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdefault -> {\n\t\t\t\tthis.logger\n\t\t\t\t\t.warn(\"Unsupported environment variable '%s' for sampler '%s' \".formatted(name, samplerValue));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate @Nullable String mapCompression(String name, String value) {\n\t\treturn switch (value.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"gzip\" -> \"GZIP\";\n\t\t\tcase \"none\" -> \"NONE\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate @Nullable String mapHistogramFlavor(String name, String value) {\n\t\treturn switch (value.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"explicit_bucket_histogram\" -> \"EXPLICIT_BUCKET_HISTOGRAM\";\n\t\t\tcase \"base2_exponential_bucket_histogram\" -> \"BASE2_EXPONENTIAL_BUCKET_HISTOGRAM\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate @Nullable String mapAggregationTemporality(String name, String value) {\n\t\treturn switch (value.toLowerCase(Locale.ROOT)) {\n\t\t\tcase \"cumulative\" -> \"CUMULATIVE\";\n\t\t\tcase \"delta\" -> \"DELTA\";\n\t\t\tdefault -> {\n\t\t\t\tthis.logger.warn(\"Invalid value for environment variable '%s': '%s'\".formatted(name, value));\n\t\t\t\tyield null;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate String combineUrl(String base, String path) {\n\t\tAssert.state(!path.startsWith(\"/\"), \"'path' must not start with '/'\");\n\t\tif (base.endsWith(\"/\")) {\n\t\t\treturn base + path;\n\t\t}\n\t\treturn base + \"/\" + path;\n\t}\n\n\tprivate Set<String> toSet(String value) {\n\t\tSet<String> result = new LinkedHashSet<>();\n\t\tfor (String entry : StringUtils.commaDelimitedListToStringArray(value)) {\n\t\t\tentry = entry.toLowerCase(Locale.ROOT).trim();\n\t\t\tif (entry.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult.add(entry);\n\t\t}\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryEnvironmentVariables.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.DeferredLogFactory;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Reads and transforms OpenTelemetry environment variables.\n *\n * @author Moritz Halbritter\n */\nclass OpenTelemetryEnvironmentVariables {\n\n\tprivate final Log logger;\n\n\tprivate final Function<String, @Nullable String> envLookup;\n\n\tOpenTelemetryEnvironmentVariables(DeferredLogFactory deferredLogFactory,\n\t\t\tFunction<String, @Nullable String> envLookup) {\n\t\tthis.logger = deferredLogFactory.getLog(OpenTelemetryEnvironmentVariables.class);\n\t\tthis.envLookup = envLookup;\n\t}\n\n\tEnvVariable getInt(String name) {\n\t\t// https://opentelemetry.io/docs/specs/otel/configuration/common/#integer\n\t\tString value = this.envLookup.apply(name);\n\t\tif (!StringUtils.hasLength(value)) {\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\ttry {\n\t\t\treturn EnvVariable.of(name, Integer.toString(Integer.parseInt(value)));\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\tthis.logger.warn(\"Invalid value for integer environment variable '%s': '%s'\".formatted(name, value));\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t}\n\n\tEnvVariable getInt(String name, String fallback) {\n\t\tEnvVariable envVariable = getInt(name);\n\t\treturn (envVariable.isPresent()) ? envVariable : getInt(fallback);\n\t}\n\n\tEnvVariable getBoolean(String name) {\n\t\t// https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#boolean\n\t\tString value = this.envLookup.apply(name);\n\t\tif (!StringUtils.hasLength(value)) {\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tif (value.equalsIgnoreCase(\"true\")) {\n\t\t\treturn EnvVariable.of(name, \"true\");\n\t\t}\n\t\tif (value.equalsIgnoreCase(\"false\")) {\n\t\t\treturn EnvVariable.of(name, \"false\");\n\t\t}\n\t\tthis.logger.warn(\"Invalid value for boolean environment variable '%s': '%s'\".formatted(name, value));\n\t\treturn EnvVariable.none();\n\t}\n\n\tEnvVariable getDuration(String name) {\n\t\t// https://opentelemetry.io/docs/specs/otel/configuration/common/#duration\n\t\tString value = this.envLookup.apply(name);\n\t\tif (!StringUtils.hasLength(value)) {\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tint intValue;\n\t\ttry {\n\t\t\tintValue = Integer.parseInt(value);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\tthis.logger.warn(\"Invalid value for duration environment variable '%s': '%s'\".formatted(name, value));\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tif (intValue < 0) {\n\t\t\tthis.logger\n\t\t\t\t.warn(\"Duration environment variable '%s' must be non-negative, but was: '%s'\".formatted(name, value));\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\treturn EnvVariable.of(name, Duration.ofMillis(intValue).toString());\n\t}\n\n\tEnvVariable getTimeout(String name) {\n\t\t// https://opentelemetry.io/docs/specs/otel/configuration/common/#timeout\n\t\tString value = this.envLookup.apply(name);\n\t\tif (!StringUtils.hasLength(value)) {\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tint intValue;\n\t\ttry {\n\t\t\tintValue = Integer.parseInt(value);\n\t\t}\n\t\tcatch (NumberFormatException ex) {\n\t\t\tthis.logger.warn(\"Invalid value for duration environment variable '%s': '%s'\".formatted(name, value));\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tif (intValue < 0) {\n\t\t\tthis.logger\n\t\t\t\t.warn(\"Duration environment variable '%s' must be non-negative, but was: '%s'\".formatted(name, value));\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tif (intValue == 0) {\n\t\t\treturn EnvVariable.of(name, Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t\t}\n\t\treturn EnvVariable.of(name, Duration.ofMillis(intValue).toString());\n\t}\n\n\tEnvVariable getTimeout(String name, String fallback) {\n\t\tEnvVariable envVariable = getTimeout(name);\n\t\treturn (envVariable.isPresent()) ? envVariable : getTimeout(fallback);\n\t}\n\n\tEnvVariable getString(String name) {\n\t\treturn getString(name, null, null);\n\t}\n\n\tEnvVariable getString(String name, String fallback) {\n\t\treturn getString(name, fallback, null);\n\t}\n\n\tEnvVariable getString(String name, @Nullable String fallback,\n\t\t\t@Nullable Function<String, String> fallbackTransformer) {\n\t\tString value = this.envLookup.apply(name);\n\t\tif (StringUtils.hasLength(value)) {\n\t\t\treturn EnvVariable.of(name, value);\n\t\t}\n\t\tif (fallback == null) {\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tvalue = this.envLookup.apply(fallback);\n\t\tif (!StringUtils.hasLength(value)) {\n\t\t\treturn EnvVariable.none();\n\t\t}\n\t\tif (fallbackTransformer != null) {\n\t\t\tvalue = fallbackTransformer.apply(value);\n\t\t}\n\t\treturn EnvVariable.of(fallback, value);\n\t}\n\n\t@Nullable Origin getOrigin(EnvVariable envVariable) {\n\t\treturn OpenTelemetryEnvironmentVariableOrigin.from(envVariable);\n\t}\n\n\t@Nullable EnvVariable getFirstPresent(EnvVariable... variables) {\n\t\tfor (EnvVariable variable : variables) {\n\t\t\tif (variable.isPresent()) {\n\t\t\t\treturn variable;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tstatic OpenTelemetryEnvironmentVariables forSystemEnv(DeferredLogFactory deferredLogFactory) {\n\t\treturn new OpenTelemetryEnvironmentVariables(deferredLogFactory, System::getenv);\n\t}\n\n\tstatic OpenTelemetryEnvironmentVariables forMap(DeferredLogFactory deferredLogFactory, Map<String, String> map) {\n\t\treturn new OpenTelemetryEnvironmentVariables(deferredLogFactory, map::get);\n\t}\n\n\trecord EnvVariable(@Nullable String name, @Nullable String value) {\n\t\tboolean isPresent() {\n\t\t\treturn this.name != null && this.value != null;\n\t\t}\n\n\t\tstatic EnvVariable of(String name, String value) {\n\t\t\treturn new EnvVariable(name, value);\n\t\t}\n\n\t\tstatic EnvVariable none() {\n\t\t\treturn new EnvVariable(null, null);\n\t\t}\n\n\t\tvoid addToMap(Map<String, OriginTrackedValue> map, String key) {\n\t\t\taddToMap(map, key, (ignore, value) -> value);\n\t\t}\n\n\t\tvoid addToMap(Map<String, OriginTrackedValue> map, String key, ValueTransformer valueTransformer) {\n\t\t\tif (this.name == null || this.value == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tAssert.state(!map.containsKey(key), \"Duplicate key '%s'\".formatted(key));\n\t\t\tString value = valueTransformer.transform(this.name, this.value);\n\t\t\tif (value == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmap.put(key, OriginTrackedValue.of(value, OpenTelemetryEnvironmentVariableOrigin.from(this)));\n\t\t}\n\n\t\tvoid addMappingToMap(Map<String, OriginTrackedValue> map, String key, MapValueTransformer valueTransformer) {\n\t\t\tif (this.name == null || this.value == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tMap<String, String> value = valueTransformer.transform(this.name, this.value);\n\t\t\tif (value == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tOrigin origin = OpenTelemetryEnvironmentVariableOrigin.from(this);\n\t\t\tfor (Map.Entry<String, String> entry : value.entrySet()) {\n\t\t\t\tString entryKey = \"%s[%s]\".formatted(key, entry.getKey());\n\t\t\t\tAssert.state(!map.containsKey(entryKey), \"Duplicate key '%s'\".formatted(entryKey));\n\t\t\t\tmap.put(entryKey, OriginTrackedValue.of(entry.getValue(), origin));\n\t\t\t}\n\t\t}\n\n\t\tvoid addListToMap(Map<String, OriginTrackedValue> map, String key, ListValueTransformer valueTransformer) {\n\t\t\tif (this.name == null || this.value == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tList<String> value = valueTransformer.transform(this.name, this.value);\n\t\t\tif (value == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tOrigin origin = OpenTelemetryEnvironmentVariableOrigin.from(this);\n\t\t\tif (value.isEmpty()) {\n\t\t\t\tAssert.state(!map.containsKey(key), \"Duplicate key '%s'\".formatted(key));\n\t\t\t\tmap.put(key, OriginTrackedValue.of(\"\", origin));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (int i = 0; i < value.size(); i++) {\n\t\t\t\tString entryKey = \"%s[%d]\".formatted(key, i);\n\t\t\t\tAssert.state(!map.containsKey(entryKey), \"Duplicate key '%s'\".formatted(entryKey));\n\t\t\t\tmap.put(entryKey, OriginTrackedValue.of(value.get(i), origin));\n\t\t\t}\n\t\t}\n\t}\n\n\t@FunctionalInterface\n\tinterface ValueTransformer {\n\n\t\t@Nullable String transform(String name, String value);\n\n\t}\n\n\t@FunctionalInterface\n\tinterface MapValueTransformer {\n\n\t\t@Nullable Map<String, String> transform(String name, String value);\n\n\t}\n\n\t@FunctionalInterface\n\tinterface ListValueTransformer {\n\n\t\t@Nullable List<String> transform(String name, String value);\n\n\t}\n\n\tprivate record OpenTelemetryEnvironmentVariableOrigin(String name) implements Origin {\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Converted OpenTelemetry environment variable '%s'\".formatted(this.name);\n\t\t}\n\n\t\tstatic @Nullable OpenTelemetryEnvironmentVariableOrigin from(EnvVariable envVariable) {\n\t\t\tif (!envVariable.isPresent()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tString name = envVariable.name();\n\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\treturn new OpenTelemetryEnvironmentVariableOrigin(name);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for OpenTelemetry.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.opentelemetry\")\npublic class OpenTelemetryProperties {\n\n\t/**\n\t * Whether OpenTelemetry should be enabled. If OpenTelemetry is disabled, only\n\t * propagators are configured. Metrics, traces, and logging will use no-op\n\t * implementations.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Resource attributes.\n\t */\n\tprivate Map<String, String> resourceAttributes = new HashMap<>();\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic Map<String, String> getResourceAttributes() {\n\t\treturn this.resourceAttributes;\n\t}\n\n\tpublic void setResourceAttributes(Map<String, String> resourceAttributes) {\n\t\tthis.resourceAttributes = resourceAttributes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryResourceAttributes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link OpenTelemetryResourceAttributes} retrieves information from the\n * {@code OTEL_RESOURCE_ATTRIBUTES} and {@code OTEL_SERVICE_NAME} environment variables\n * and merges it with the resource attributes provided by the user. User-provided resource\n * attributes take precedence. Additionally, {@code spring.application.*} related\n * properties can be applied as defaults.\n * <p>\n * <a href= \"https://opentelemetry.io/docs/specs/otel/resource/sdk/\">OpenTelemetry\n * Resource Specification</a>\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\npublic class OpenTelemetryResourceAttributes {\n\n\t/**\n\t * Default value for service name. Used if {@code service.name} is not set and no name\n\t * can be deduced from the running application.\n\t */\n\tprivate static final String DEFAULT_SERVICE_NAME = \"unknown_service\";\n\n\tprivate final Environment environment;\n\n\tprivate final Map<String, String> resourceAttributes;\n\n\tprivate final Function<String, @Nullable String> systemEnvironment;\n\n\t/**\n\t * Creates a new instance of {@link OpenTelemetryResourceAttributes}.\n\t * @param environment the environment\n\t * @param resourceAttributes user-provided resource attributes to be used\n\t */\n\tpublic OpenTelemetryResourceAttributes(Environment environment, @Nullable Map<String, String> resourceAttributes) {\n\t\tthis(environment, resourceAttributes, null);\n\t}\n\n\t/**\n\t * Creates a new {@link OpenTelemetryResourceAttributes} instance.\n\t * @param environment the environment\n\t * @param resourceAttributes user-provided resource attributes to be used\n\t * @param systemEnvironment a function to retrieve environment variables by name\n\t */\n\tOpenTelemetryResourceAttributes(Environment environment, @Nullable Map<String, String> resourceAttributes,\n\t\t\t@Nullable Function<String, @Nullable String> systemEnvironment) {\n\t\tAssert.notNull(environment, \"'environment' must not be null\");\n\t\tthis.environment = environment;\n\t\tthis.resourceAttributes = (resourceAttributes != null) ? resourceAttributes : Collections.emptyMap();\n\t\tthis.systemEnvironment = (systemEnvironment != null) ? systemEnvironment : System::getenv;\n\t}\n\n\t/**\n\t * Applies resource attributes to the provided {@link BiConsumer} after being combined\n\t * from environment variables and user-defined resource attributes.\n\t * <p>\n\t * If a key exists in both environment variables and user-defined resources, the value\n\t * from the user-defined resource takes precedence, even if it is empty.\n\t * <p>\n\t * Additionally, {@code spring.application.name} or {@code unknown_service} will be\n\t * used as the default for {@code service.name}, and {@code spring.application.group}\n\t * will serve as the default for {@code service.group} and {@code service.namespace}.\n\t * @param consumer the {@link BiConsumer} to apply\n\t */\n\tpublic void applyTo(BiConsumer<String, String> consumer) {\n\t\tAssert.notNull(consumer, \"'consumer' must not be null\");\n\t\tMap<String, String> attributes = getResourceAttributesFromEnv();\n\t\tthis.resourceAttributes.forEach((name, value) -> {\n\t\t\tif (StringUtils.hasLength(name) && value != null) {\n\t\t\t\tattributes.put(name, value);\n\t\t\t}\n\t\t});\n\t\tattributes.computeIfAbsent(\"service.name\", (key) -> getApplicationName());\n\t\tattributes.computeIfAbsent(\"service.namespace\", (key) -> getServiceNamespace());\n\t\tattributes.forEach(consumer);\n\t}\n\n\tprivate String getApplicationName() {\n\t\treturn this.environment.getProperty(\"spring.application.name\", DEFAULT_SERVICE_NAME);\n\t}\n\n\tprivate @Nullable String getServiceNamespace() {\n\t\treturn this.environment.getProperty(\"spring.application.group\");\n\t}\n\n\t/**\n\t * Parses resource attributes from the {@link System#getenv()}. This method fetches\n\t * attributes defined in the {@code OTEL_RESOURCE_ATTRIBUTES} and\n\t * {@code OTEL_SERVICE_NAME} environment variables and provides them as key-value\n\t * pairs.\n\t * <p>\n\t * If {@code service.name} is also provided in {@code OTEL_RESOURCE_ATTRIBUTES}, then\n\t * {@code OTEL_SERVICE_NAME} takes precedence.\n\t * @return resource attributes\n\t */\n\tprivate Map<String, String> getResourceAttributesFromEnv() {\n\t\tMap<String, String> attributes = new LinkedHashMap<>();\n\t\tfor (String attribute : StringUtils.tokenizeToStringArray(getEnv(\"OTEL_RESOURCE_ATTRIBUTES\"), \",\")) {\n\t\t\tint index = attribute.indexOf('=');\n\t\t\tif (index > 0) {\n\t\t\t\tString key = attribute.substring(0, index);\n\t\t\t\tString value = attribute.substring(index + 1);\n\t\t\t\tattributes.put(key.trim(), StringUtils.uriDecode(value.trim(), StandardCharsets.UTF_8));\n\t\t\t}\n\t\t}\n\t\tString otelServiceName = getEnv(\"OTEL_SERVICE_NAME\");\n\t\tif (otelServiceName != null) {\n\t\t\tattributes.put(\"service.name\", otelServiceName);\n\t\t}\n\t\treturn attributes;\n\t}\n\n\tprivate @Nullable String getEnv(String name) {\n\t\treturn this.systemEnvironment.apply(name);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.context.propagation.ContextPropagators;\nimport io.opentelemetry.sdk.OpenTelemetrySdk;\nimport io.opentelemetry.sdk.OpenTelemetrySdkBuilder;\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\nimport io.opentelemetry.sdk.metrics.SdkMeterProvider;\nimport io.opentelemetry.sdk.resources.Resource;\nimport io.opentelemetry.sdk.resources.ResourceBuilder;\nimport io.opentelemetry.sdk.trace.SdkTracerProvider;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the OpenTelemetry SDK.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ OpenTelemetry.class, OpenTelemetrySdk.class })\n@EnableConfigurationProperties(OpenTelemetryProperties.class)\npublic final class OpenTelemetrySdkAutoConfiguration {\n\n\tOpenTelemetrySdkAutoConfiguration() {\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(OpenTelemetry.class)\n\t@ConditionalOnEnabledOpenTelemetry\n\tOpenTelemetrySdk openTelemetrySdk(ObjectProvider<SdkTracerProvider> openTelemetrySdkTracerProvider,\n\t\t\tObjectProvider<ContextPropagators> openTelemetryContextPropagators,\n\t\t\tObjectProvider<SdkLoggerProvider> openTelemetrySdkLoggerProvider,\n\t\t\tObjectProvider<SdkMeterProvider> openTelemetrySdkMeterProvider) {\n\t\tOpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();\n\t\topenTelemetrySdkTracerProvider.ifAvailable(builder::setTracerProvider);\n\t\topenTelemetryContextPropagators.ifAvailable(builder::setPropagators);\n\t\topenTelemetrySdkLoggerProvider.ifAvailable(builder::setLoggerProvider);\n\t\topenTelemetrySdkMeterProvider.ifAvailable(builder::setMeterProvider);\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(OpenTelemetry.class)\n\t@Conditional(OnDisabledOpenTelemetryCondition.class)\n\tOpenTelemetrySdk disabledOpenTelemetrySdk(ObjectProvider<ContextPropagators> openTelemetryContextPropagators) {\n\t\tOpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();\n\t\topenTelemetryContextPropagators.ifAvailable(builder::setPropagators);\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tResource openTelemetryResource(Environment environment, OpenTelemetryProperties properties) {\n\t\treturn Resource.getDefault().merge(toResource(environment, properties));\n\t}\n\n\tprivate Resource toResource(Environment environment, OpenTelemetryProperties properties) {\n\t\tResourceBuilder builder = Resource.builder();\n\t\tnew OpenTelemetryResourceAttributes(environment, properties.getResourceAttributes()).applyTo(builder::put);\n\t\treturn builder.build();\n\t}\n\n\tstatic class OnDisabledOpenTelemetryCondition extends NoneNestedConditions {\n\n\t\tOnDisabledOpenTelemetryCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnEnabledOpenTelemetry\n\t\tstatic class EnabledCondition {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/W3CHeaderParser.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.net.URLDecoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * Parser for the W3C Baggage HTTP header as defined in the\n * <a href=\"https://www.w3.org/TR/baggage/#header-content\">W3C Baggage specification</a>.\n *\n * @author Moritz Halbritter\n */\nfinal class W3CHeaderParser {\n\n\tprivate W3CHeaderParser() {\n\t}\n\n\t/**\n\t * Parses a W3C Baggage header value into a map of key-value pairs. Properties\n\t * attached to list members are ignored. Values are percent-decoded.\n\t * @param header the baggage header string to parse\n\t * @return the baggage entries\n\t */\n\tstatic Map<String, String> parse(String header) {\n\t\tif (!StringUtils.hasLength(header)) {\n\t\t\treturn Collections.emptyMap();\n\t\t}\n\t\tMap<String, String> result = new LinkedHashMap<>();\n\t\tfor (String part : header.split(\",\", -1)) {\n\t\t\tpart = part.strip();\n\t\t\tif (part.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tint semicolon = part.indexOf(';');\n\t\t\tString keyValue = (semicolon != -1) ? part.substring(0, semicolon) : part;\n\t\t\tint equals = keyValue.indexOf('=');\n\t\t\tif (equals == -1) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tString key = keyValue.substring(0, equals).strip();\n\t\t\tString value = keyValue.substring(equals + 1).strip();\n\t\t\tif (key.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult.put(key, percentDecode(value));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static String percentDecode(String value) {\n\t\tif (value.indexOf('%') == -1) {\n\t\t\treturn value;\n\t\t}\n\t\treturn URLDecoder.decode(value, StandardCharsets.UTF_8);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/ConditionalOnEnabledLoggingExport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that checks whether logging export is enabled. It\n * matches if the value of the {@code management.logging.export.enabled} property is\n * {@code true} or if it is not configured. If the {@link #value() logging exporter name}\n * is set, the {@code management.logging.export.<name>.enabled} property can be used to\n * control the behavior for the specific logging exporter. In that case, the\n * exporter-specific property takes precedence over the global property.\n *\n * @author Moritz Halbritter\n * @author Dmytro Nosan\n * @since 3.4.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(OnEnabledLoggingExportCondition.class)\npublic @interface ConditionalOnEnabledLoggingExport {\n\n\t/**\n\t * Name of the logging exporter.\n\t * @return the name of the logging exporter\n\t */\n\tString value() default \"\";\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/OnEnabledLoggingExportCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link SpringBootCondition} to check whether logging exporter is enabled.\n *\n * @author Moritz Halbritter\n * @author Dmytro Nosan\n * @see ConditionalOnEnabledLoggingExport\n */\nclass OnEnabledLoggingExportCondition extends SpringBootCondition {\n\n\tprivate static final String GLOBAL_PROPERTY = \"management.logging.export.enabled\";\n\n\tprivate static final String EXPORTER_PROPERTY = \"management.logging.export.%s.enabled\";\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tString loggingExporter = getExporterName(metadata);\n\t\tif (StringUtils.hasLength(loggingExporter)) {\n\t\t\tString formattedExporterProperty = EXPORTER_PROPERTY.formatted(loggingExporter);\n\t\t\tBoolean exporterLoggingEnabled = context.getEnvironment()\n\t\t\t\t.getProperty(formattedExporterProperty, Boolean.class);\n\t\t\tif (exporterLoggingEnabled != null) {\n\t\t\t\treturn new ConditionOutcome(exporterLoggingEnabled,\n\t\t\t\t\t\tConditionMessage.forCondition(ConditionalOnEnabledLoggingExport.class)\n\t\t\t\t\t\t\t.because(formattedExporterProperty + \" is \" + exporterLoggingEnabled));\n\t\t\t}\n\t\t}\n\t\tBoolean globalLoggingEnabled = context.getEnvironment().getProperty(GLOBAL_PROPERTY, Boolean.class);\n\t\tif (globalLoggingEnabled != null) {\n\t\t\treturn new ConditionOutcome(globalLoggingEnabled,\n\t\t\t\t\tConditionMessage.forCondition(ConditionalOnEnabledLoggingExport.class)\n\t\t\t\t\t\t.because(GLOBAL_PROPERTY + \" is \" + globalLoggingEnabled));\n\t\t}\n\t\treturn ConditionOutcome.match(ConditionMessage.forCondition(ConditionalOnEnabledLoggingExport.class)\n\t\t\t.because(\"is enabled by default\"));\n\t}\n\n\tprivate static @Nullable String getExporterName(AnnotatedTypeMetadata metadata) {\n\t\tMap<String, @Nullable Object> attributes = metadata\n\t\t\t.getAnnotationAttributes(ConditionalOnEnabledLoggingExport.class.getName());\n\t\tif (attributes == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn (String) attributes.get(\"value\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/OpenTelemetryLoggingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport io.opentelemetry.sdk.logs.LogLimits;\nimport io.opentelemetry.sdk.logs.LogRecordProcessor;\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\nimport io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;\nimport io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;\nimport io.opentelemetry.sdk.logs.export.LogRecordExporter;\nimport io.opentelemetry.sdk.resources.Resource;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.opentelemetry.autoconfigure.ConditionalOnEnabledOpenTelemetry;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingProperties.Export;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingProperties.Limits;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry logging.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(after = OpenTelemetrySdkAutoConfiguration.class)\n@ConditionalOnClass(SdkLoggerProvider.class)\n@ConditionalOnEnabledOpenTelemetry\n@EnableConfigurationProperties(OpenTelemetryLoggingProperties.class)\npublic final class OpenTelemetryLoggingAutoConfiguration {\n\n\tprivate final OpenTelemetryLoggingProperties properties;\n\n\tOpenTelemetryLoggingAutoConfiguration(OpenTelemetryLoggingProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tBatchLogRecordProcessor openTelemetryBatchLogRecordProcessor(ObjectProvider<LogRecordExporter> logRecordExporters) {\n\t\tLogRecordExporter exporter = LogRecordExporter.composite(logRecordExporters.orderedStream().toList());\n\t\tExport export = this.properties.getExport();\n\t\treturn BatchLogRecordProcessor.builder(exporter)\n\t\t\t.setExporterTimeout(export.getTimeout())\n\t\t\t.setMaxQueueSize(export.getMaxQueueSize())\n\t\t\t.setScheduleDelay(export.getScheduleDelay())\n\t\t\t.setMaxExportBatchSize(export.getMaxBatchSize())\n\t\t\t.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(Resource.class)\n\tSdkLoggerProvider openTelemetrySdkLoggerProvider(Resource openTelemetryResource,\n\t\t\tObjectProvider<LogRecordProcessor> logRecordProcessors,\n\t\t\tObjectProvider<SdkLoggerProviderBuilderCustomizer> customizers, LogLimits logLimits) {\n\t\tSdkLoggerProviderBuilder builder = SdkLoggerProvider.builder()\n\t\t\t.setResource(openTelemetryResource)\n\t\t\t.setLogLimits(() -> logLimits);\n\t\tlogRecordProcessors.orderedStream().forEach(builder::addLogRecordProcessor);\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tLogLimits openTelemetryLogLimits() {\n\t\tLimits limits = this.properties.getLimits();\n\t\treturn LogLimits.builder()\n\t\t\t.setMaxAttributeValueLength(limits.getMaxAttributeValueLength())\n\t\t\t.setMaxNumberOfAttributes(limits.getMaxAttributes())\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/OpenTelemetryLoggingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for logging with OpenTelemetry.\n *\n * @author Moritz Halbritter\n * @since 4.1.0\n */\n@ConfigurationProperties(\"management.opentelemetry.logging\")\npublic class OpenTelemetryLoggingProperties {\n\n\t/**\n\t * Logs export configuration.\n\t */\n\tprivate final Export export = new Export();\n\n\t/**\n\t * Log limits configuration.\n\t */\n\tprivate final Limits limits = new Limits();\n\n\tpublic Export getExport() {\n\t\treturn this.export;\n\t}\n\n\tpublic Limits getLimits() {\n\t\treturn this.limits;\n\t}\n\n\tpublic static class Export {\n\n\t\t/**\n\t\t * Maximum time an export will be allowed to run before being cancelled.\n\t\t */\n\t\tprivate Duration timeout = Duration.ofSeconds(30);\n\n\t\t/**\n\t\t * Maximum batch size for each export. This must be less than or equal to\n\t\t * 'maxQueueSize'.\n\t\t */\n\t\tprivate int maxBatchSize = 512;\n\n\t\t/**\n\t\t * Maximum number of logs that are kept in the queue before they will be dropped.\n\t\t */\n\t\tprivate int maxQueueSize = 2048;\n\n\t\t/**\n\t\t * The delay interval between two consecutive exports.\n\t\t */\n\t\tprivate Duration scheduleDelay = Duration.ofSeconds(1);\n\n\t\tpublic Duration getTimeout() {\n\t\t\treturn this.timeout;\n\t\t}\n\n\t\tpublic void setTimeout(Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\tpublic int getMaxBatchSize() {\n\t\t\treturn this.maxBatchSize;\n\t\t}\n\n\t\tpublic void setMaxBatchSize(int maxBatchSize) {\n\t\t\tthis.maxBatchSize = maxBatchSize;\n\t\t}\n\n\t\tpublic int getMaxQueueSize() {\n\t\t\treturn this.maxQueueSize;\n\t\t}\n\n\t\tpublic void setMaxQueueSize(int maxQueueSize) {\n\t\t\tthis.maxQueueSize = maxQueueSize;\n\t\t}\n\n\t\tpublic Duration getScheduleDelay() {\n\t\t\treturn this.scheduleDelay;\n\t\t}\n\n\t\tpublic void setScheduleDelay(Duration scheduleDelay) {\n\t\t\tthis.scheduleDelay = scheduleDelay;\n\t\t}\n\n\t}\n\n\t/**\n\t * Log limits.\n\t */\n\tpublic static class Limits {\n\n\t\t/**\n\t\t * Maximum number of characters for string attribute values.\n\t\t */\n\t\tprivate int maxAttributeValueLength = Integer.MAX_VALUE;\n\n\t\t/**\n\t\t * Maximum number of attributes per log record.\n\t\t */\n\t\tprivate int maxAttributes = 128;\n\n\t\tpublic int getMaxAttributeValueLength() {\n\t\t\treturn this.maxAttributeValueLength;\n\t\t}\n\n\t\tpublic void setMaxAttributeValueLength(int maxAttributeValueLength) {\n\t\t\tthis.maxAttributeValueLength = maxAttributeValueLength;\n\t\t}\n\n\t\tpublic int getMaxAttributes() {\n\t\t\treturn this.maxAttributes;\n\t\t}\n\n\t\tpublic void setMaxAttributes(int maxAttributes) {\n\t\t\tthis.maxAttributes = maxAttributes;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/SdkLoggerProviderBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\nimport io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;\n\n/**\n * Callback interface that can be used to customize the {@link SdkLoggerProviderBuilder}\n * that is used to create the auto-configured {@link SdkLoggerProvider}.\n *\n * @author Toshiaki Maki\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface SdkLoggerProviderBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(SdkLoggerProviderBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpGrpcLogRecordExporterBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link OtlpGrpcLogRecordExporterBuilder} whilst retaining default auto-configuration.\n *\n * @author Joaquin Santana\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface OtlpGrpcLogRecordExporterBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link OtlpGrpcLogRecordExporterBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(OtlpGrpcLogRecordExporterBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpHttpLogRecordExporterBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link OtlpHttpLogRecordExporterBuilder} whilst retaining default auto-configuration.\n *\n * @author Joaquin Santana\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface OtlpHttpLogRecordExporterBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link OtlpHttpLogRecordExporterBuilder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(OtlpHttpLogRecordExporterBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpLoggingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConfigurations.ConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConfigurations.Exporters;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry logging exports.\n *\n * @author Toshiaki Maki\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ OpenTelemetry.class, SdkLoggerProvider.class })\n@EnableConfigurationProperties(OtlpLoggingProperties.class)\n@Import({ ConnectionDetails.class, Exporters.class })\npublic final class OtlpLoggingAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpLoggingConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport java.util.Locale;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport io.opentelemetry.api.metrics.MeterProvider;\nimport io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;\nimport io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder;\nimport io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;\nimport io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.ConditionalOnEnabledLoggingExport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configurations imported by {@link OtlpLoggingAutoConfiguration}.\n *\n * @author Toshiaki Maki\n * @author Moritz Halbritter\n */\nfinal class OtlpLoggingConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetails {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(OtlpLoggingConnectionDetails.class)\n\t\t@ConditionalOnProperty(\"management.opentelemetry.logging.export.otlp.endpoint\")\n\t\tPropertiesOtlpLoggingConnectionDetails openTelemetryLoggingConnectionDetails(OtlpLoggingProperties properties,\n\t\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\t\treturn new PropertiesOtlpLoggingConnectionDetails(properties, sslBundles.getIfAvailable());\n\t\t}\n\n\t\t/**\n\t\t * Adapts {@link OtlpLoggingProperties} to {@link OtlpLoggingConnectionDetails}.\n\t\t */\n\t\tstatic class PropertiesOtlpLoggingConnectionDetails implements OtlpLoggingConnectionDetails {\n\n\t\t\tprivate final OtlpLoggingProperties properties;\n\n\t\t\tprivate final @Nullable SslBundles sslBundles;\n\n\t\t\tPropertiesOtlpLoggingConnectionDetails(OtlpLoggingProperties properties, @Nullable SslBundles sslBundles) {\n\t\t\t\tthis.properties = properties;\n\t\t\t\tthis.sslBundles = sslBundles;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic String getUrl(Transport transport) {\n\t\t\t\tAssert.state(transport == this.properties.getTransport(),\n\t\t\t\t\t\t\"Requested transport %s doesn't match configured transport %s\".formatted(transport,\n\t\t\t\t\t\t\t\tthis.properties.getTransport()));\n\t\t\t\tString endpoint = this.properties.getEndpoint();\n\t\t\t\tAssert.state(endpoint != null, \"'endpoint' must not be null\");\n\t\t\t\treturn endpoint;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\t\tString bundleName = this.properties.getSsl().getBundle();\n\t\t\t\tif (StringUtils.hasLength(bundleName)) {\n\t\t\t\t\tAssert.notNull(this.sslBundles, \"SSL bundle name has been set but no SSL bundles found in context\");\n\t\t\t\t\treturn this.sslBundles.getBundle(bundleName);\n\t\t\t\t}\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(OtlpHttpLogRecordExporter.class)\n\t@ConditionalOnMissingBean({ OtlpGrpcLogRecordExporter.class, OtlpHttpLogRecordExporter.class })\n\t@ConditionalOnBean(OtlpLoggingConnectionDetails.class)\n\t@ConditionalOnEnabledLoggingExport(\"otlp\")\n\tstatic class Exporters {\n\n\t\t@Bean\n\t\t@ConditionalOnProperty(name = \"management.opentelemetry.logging.export.otlp.transport\", havingValue = \"http\",\n\t\t\t\tmatchIfMissing = true)\n\t\tOtlpHttpLogRecordExporter otlpHttpLogRecordExporter(OtlpLoggingProperties properties,\n\t\t\t\tOtlpLoggingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,\n\t\t\t\tObjectProvider<OtlpHttpLogRecordExporterBuilderCustomizer> customizers) {\n\t\t\tOtlpHttpLogRecordExporterBuilder builder = OtlpHttpLogRecordExporter.builder()\n\t\t\t\t.setEndpoint(connectionDetails.getUrl(Transport.HTTP))\n\t\t\t\t.setTimeout(properties.getTimeout())\n\t\t\t\t.setConnectTimeout(properties.getConnectTimeout())\n\t\t\t\t.setCompression(properties.getCompression().name().toLowerCase(Locale.US));\n\t\t\tproperties.getHeaders().forEach(builder::addHeader);\n\t\t\tmeterProvider.ifAvailable(builder::setMeterProvider);\n\t\t\tconfigureSsl(connectionDetails, builder::setSslContext);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnProperty(name = \"management.opentelemetry.logging.export.otlp.transport\", havingValue = \"grpc\")\n\t\tOtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter(OtlpLoggingProperties properties,\n\t\t\t\tOtlpLoggingConnectionDetails connectionDetails, ObjectProvider<MeterProvider> meterProvider,\n\t\t\t\tObjectProvider<OtlpGrpcLogRecordExporterBuilderCustomizer> customizers) {\n\t\t\tOtlpGrpcLogRecordExporterBuilder builder = OtlpGrpcLogRecordExporter.builder()\n\t\t\t\t.setEndpoint(connectionDetails.getUrl(Transport.GRPC))\n\t\t\t\t.setTimeout(properties.getTimeout())\n\t\t\t\t.setConnectTimeout(properties.getConnectTimeout())\n\t\t\t\t.setCompression(properties.getCompression().name().toLowerCase(Locale.US));\n\t\t\tproperties.getHeaders().forEach(builder::addHeader);\n\t\t\tmeterProvider.ifAvailable(builder::setMeterProvider);\n\t\t\tconfigureSsl(connectionDetails, builder::setSslContext);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder.build();\n\t\t}\n\n\t\tprivate void configureSsl(OtlpLoggingConnectionDetails connectionDetails,\n\t\t\t\tSslContextConfigurer sslContextConfigurer) {\n\t\t\tSslBundle sslBundle = connectionDetails.getSslBundle();\n\t\t\tif (sslBundle != null) {\n\t\t\t\tSSLContext sslContext = sslBundle.createSslContext();\n\t\t\t\tX509TrustManager trustManager = extractTrustManager(sslBundle);\n\t\t\t\tsslContextConfigurer.configure(sslContext, trustManager);\n\t\t\t}\n\t\t}\n\n\t\tprivate X509TrustManager extractTrustManager(SslBundle sslBundle) {\n\t\t\tfor (TrustManager trustManager : sslBundle.getManagers().getTrustManagers()) {\n\t\t\t\tif (trustManager instanceof X509TrustManager x509TrustManager) {\n\t\t\t\t\treturn x509TrustManager;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"No X509TrustManager found in the SSL bundle trust managers\");\n\t\t}\n\n\t\tprivate interface SslContextConfigurer {\n\n\t\t\tvoid configure(SSLContext sslContext, X509TrustManager trustManager);\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpLoggingConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * Details required to establish a connection to an OpenTelemetry logging service.\n *\n * @author Toshiaki Maki\n * @since 4.0.0\n */\npublic interface OtlpLoggingConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Address to where logs will be published.\n\t * @param transport the transport to use\n\t * @return the address to where logs will be published\n\t */\n\tString getUrl(Transport transport);\n\n\t/**\n\t * SSL bundle to use.\n\t * @return the SSL bundle to use or {@code null}\n\t * @since 4.1.0\n\t */\n\tdefault @Nullable SslBundle getSslBundle() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpLoggingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for exporting logs using OpenTelemetry.\n *\n * @author Jonatan Ivanov\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.opentelemetry.logging.export.otlp\")\npublic class OtlpLoggingProperties {\n\n\t/**\n\t * URL to the OTel collector's HTTP API.\n\t */\n\tprivate @Nullable String endpoint;\n\n\t/**\n\t * Call timeout for the OTel Collector to process an exported batch of data. This\n\t * timeout spans the entire call: resolving DNS, connecting, writing the request body,\n\t * server processing, and reading the response body. If the call requires redirects or\n\t * retries all must complete within one timeout period.\n\t */\n\tprivate Duration timeout = Duration.ofSeconds(10);\n\n\t/**\n\t * Connect timeout for the OTel collector connection.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(10);\n\n\t/**\n\t * Transport used to send the logs.\n\t */\n\tprivate Transport transport = Transport.HTTP;\n\n\t/**\n\t * Method used to compress the payload.\n\t */\n\tprivate Compression compression = Compression.NONE;\n\n\t/**\n\t * Custom HTTP headers you want to pass to the collector, for example auth headers.\n\t */\n\tprivate final Map<String, String> headers = new HashMap<>();\n\n\tprivate final Ssl ssl = new Ssl();\n\n\tpublic @Nullable String getEndpoint() {\n\t\treturn this.endpoint;\n\t}\n\n\tpublic void setEndpoint(@Nullable String endpoint) {\n\t\tthis.endpoint = endpoint;\n\t}\n\n\tpublic Duration getTimeout() {\n\t\treturn this.timeout;\n\t}\n\n\tpublic void setTimeout(Duration timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic Transport getTransport() {\n\t\treturn this.transport;\n\t}\n\n\tpublic void setTransport(Transport transport) {\n\t\tthis.transport = transport;\n\t}\n\n\tpublic Compression getCompression() {\n\t\treturn this.compression;\n\t}\n\n\tpublic void setCompression(Compression compression) {\n\t\tthis.compression = compression;\n\t}\n\n\tpublic Map<String, String> getHeaders() {\n\t\treturn this.headers;\n\t}\n\n\tpublic Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic static class Ssl {\n\n\t\t/**\n\t\t * SSL bundle name.\n\t\t */\n\t\tprivate @Nullable String bundle;\n\n\t\tpublic @Nullable String getBundle() {\n\t\t\treturn this.bundle;\n\t\t}\n\n\t\tpublic void setBundle(@Nullable String bundle) {\n\t\t\tthis.bundle = bundle;\n\t\t}\n\n\t}\n\n\tpublic enum Compression {\n\n\t\t/**\n\t\t * Gzip compression.\n\t\t */\n\t\tGZIP,\n\n\t\t/**\n\t\t * No compression.\n\t\t */\n\t\tNONE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/Transport.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\n/**\n * Transport used to send OTLP log data.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic enum Transport {\n\n\t/**\n\t * HTTP transport.\n\t */\n\tHTTP,\n\n\t/**\n\t * gRPC transport.\n\t */\n\tGRPC\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for exporting logs with OpenTelemetry via OTLP.\n */\n@NullMarked\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for OpenTelemetry logging.\n */\n@NullMarked\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for OpenTelemetry.\n */\n@NullMarked\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/docker/compose/OtlpLoggingDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.docker.compose;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create\n * {@link OtlpLoggingConnectionDetails} for an OTLP service.\n *\n * @author Eddú Meléndez\n */\nclass OtlpLoggingDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<OtlpLoggingConnectionDetails> {\n\n\tprivate static final String[] OPENTELEMETRY_IMAGE_NAMES = { \"otel/opentelemetry-collector-contrib\",\n\t\t\t\"grafana/otel-lgtm\" };\n\n\tprivate static final int OTLP_GRPC_PORT = 4317;\n\n\tprivate static final int OTLP_HTTP_PORT = 4318;\n\n\tOtlpLoggingDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OPENTELEMETRY_IMAGE_NAMES,\n\t\t\t\t\"org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected OtlpLoggingConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new OtlpLoggingDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\tprivate static final class OtlpLoggingDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements OtlpLoggingConnectionDetails {\n\n\t\tprivate final String host;\n\n\t\tprivate final int grpcPort;\n\n\t\tprivate final int httpPort;\n\n\t\tprivate final @Nullable SslBundle sslBundle;\n\n\t\tprivate OtlpLoggingDockerComposeConnectionDetails(RunningService source) {\n\t\t\tsuper(source);\n\t\t\tthis.host = source.host();\n\t\t\tthis.grpcPort = source.ports().get(OTLP_GRPC_PORT);\n\t\t\tthis.httpPort = source.ports().get(OTLP_HTTP_PORT);\n\t\t\tthis.sslBundle = getSslBundle(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl(Transport transport) {\n\t\t\tint port = switch (transport) {\n\t\t\t\tcase HTTP -> this.httpPort;\n\t\t\t\tcase GRPC -> this.grpcPort;\n\t\t\t};\n\t\t\tString scheme = (this.sslBundle != null) ? \"https\" : \"http\";\n\t\t\treturn \"%s://%s:%d/v1/logs\".formatted(scheme, this.host, port);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn this.sslBundle;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose OpenTelemetry logging service connections.\n */\n@NullMarked\npackage org.springframework.boot.opentelemetry.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/testcontainers/GrafanaOtlpLoggingContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.testcontainers;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.grafana.LgtmStackContainer;\n\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link OtlpLoggingConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link LgtmStackContainer} using\n * the {@code \"grafana/otel-lgtm\"} image.\n *\n * @author Eddú Meléndez\n */\nclass GrafanaOtlpLoggingContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<LgtmStackContainer, OtlpLoggingConnectionDetails> {\n\n\tGrafanaOtlpLoggingContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME);\n\t}\n\n\t@Override\n\tprotected OtlpLoggingConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<LgtmStackContainer> source) {\n\t\treturn new OtlpLoggingContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OtlpLoggingContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<LgtmStackContainer> implements OtlpLoggingConnectionDetails {\n\n\t\tprivate OtlpLoggingContainerConnectionDetails(ContainerConnectionSource<LgtmStackContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl(Transport transport) {\n\t\t\tString url = switch (transport) {\n\t\t\t\tcase HTTP -> getContainer().getOtlpHttpUrl();\n\t\t\t\tcase GRPC -> getContainer().getOtlpGrpcUrl();\n\t\t\t};\n\t\t\tif (getSslBundle() != null) {\n\t\t\t\turl = url.replaceFirst(\"^http://\", \"https://\");\n\t\t\t}\n\t\t\treturn \"%s/v1/logs\".formatted(url);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/testcontainers/OtelCollectorOltpLoggingContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.testcontainers;\n\nimport org.jspecify.annotations.Nullable;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConnectionDetails;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create\n * {@link OtlpLoggingConnectionDetails} from a\n * {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using\n * the {@code \"otel/opentelemetry-collector-contrib\"} image.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass OtelCollectorOltpLoggingContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, OtlpLoggingConnectionDetails> {\n\n\tprivate static final int OTLP_GRPC_PORT = 4317;\n\n\tprivate static final int OTLP_HTTP_PORT = 4318;\n\n\tOtelCollectorOltpLoggingContainerConnectionDetailsFactory() {\n\t\tsuper(\"otel/opentelemetry-collector-contrib\");\n\t}\n\n\t@Override\n\tprotected OtlpLoggingConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<Container<?>> source) {\n\t\treturn new OtlpLoggingContainerConnectionDetails(source);\n\t}\n\n\tprivate static final class OtlpLoggingContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>\n\t\t\timplements OtlpLoggingConnectionDetails {\n\n\t\tprivate OtlpLoggingContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getUrl(Transport transport) {\n\t\t\tint port = switch (transport) {\n\t\t\t\tcase HTTP -> OTLP_HTTP_PORT;\n\t\t\t\tcase GRPC -> OTLP_GRPC_PORT;\n\t\t\t};\n\t\t\tString scheme = (getSslBundle() != null) ? \"https\" : \"http\";\n\t\t\treturn \"%s://%s:%d/v1/logs\".formatted(scheme, getContainer().getHost(), getContainer().getMappedPort(port));\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable SslBundle getSslBundle() {\n\t\t\treturn super.getSslBundle();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Testcontainers OpenTelemetry logging service connections.\n */\n@NullMarked\npackage org.springframework.boot.opentelemetry.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n\t\"groups\": [],\n\t\"properties\": [\n\t\t{\n\t\t\t\"name\": \"management.logging.export.otlp.enabled\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"defaultValue\": true,\n\t\t\t\"description\": \"Whether auto-configuration of logging is enabled to export logs over OTLP.\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.opentelemetry.map-environment-variables\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"defaultValue\": true,\n\t\t\t\"description\": \"Whether to map OpenTelemetry SDK environment variables to Spring Boot configuration properties.\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.compression\",\n\t\t\t\"type\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties$Compression\",\n\t\t\t\"description\": \"Method used to compress the payload.\",\n\t\t\t\"sourceType\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties\",\n\t\t\t\"defaultValue\": \"none\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.opentelemetry.logging.export.otlp.compression\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.connect-timeout\",\n\t\t\t\"type\": \"java.time.Duration\",\n\t\t\t\"description\": \"Connect timeout for the OTel collector connection.\",\n\t\t\t\"sourceType\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties\",\n\t\t\t\"defaultValue\": \"10s\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.opentelemetry.logging.export.otlp.connect-timeout\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.endpoint\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"description\": \"URL to the OTel collector's HTTP API.\",\n\t\t\t\"sourceType\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.opentelemetry.logging.export.otlp.endpoint\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.export.enabled\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.logging.export.otlp.enabled\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.headers\",\n\t\t\t\"type\": \"java.util.Map<java.lang.String,java.lang.String>\",\n\t\t\t\"description\": \"Custom HTTP headers you want to pass to the collector, for example auth headers.\",\n\t\t\t\"sourceType\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.opentelemetry.logging.export.otlp.headers\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.timeout\",\n\t\t\t\"type\": \"java.time.Duration\",\n\t\t\t\"description\": \"Call timeout for the OTel Collector to process an exported batch of data. This timeout spans the entire call: resolving DNS, connecting, writing the request body, server processing, and reading the response body. If the call requires redirects or retries all must complete within one timeout period.\",\n\t\t\t\"sourceType\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties\",\n\t\t\t\"defaultValue\": \"10s\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.opentelemetry.logging.export.otlp.timeout\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"name\": \"management.otlp.logging.transport\",\n\t\t\t\"type\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.Transport\",\n\t\t\t\"description\": \"Transport used to send the logs.\",\n\t\t\t\"sourceType\": \"org.springframework.boot.opentelemetry.actuate.autoconfigure.logging.OpenTelemetryLoggingExportProperties\",\n\t\t\t\"defaultValue\": \"http\",\n\t\t\t\"deprecation\": {\n\t\t\t\t\"level\": \"error\",\n\t\t\t\t\"replacement\": \"management.opentelemetry.logging.export.otlp.transport\",\n\t\t\t\t\"since\": \"4.0.0\"\n\t\t\t}\n\t\t}\n\t],\n\t\"hints\": []\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration\norg.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration\norg.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.opentelemetry.docker.compose.OtlpLoggingDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.opentelemetry.testcontainers.GrafanaOtlpLoggingContainerConnectionDetailsFactory,\\\norg.springframework.boot.opentelemetry.testcontainers.OtelCollectorOltpLoggingContainerConnectionDetailsFactory\norg.springframework.boot.EnvironmentPostProcessor=\\\norg.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryEnvironmentVariableEnvironmentPostProcessor\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryEnvironmentVariableEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.logging.DeferredLogs;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.EnumerablePropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.StandardEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link OpenTelemetryEnvironmentVariableEnvironmentPostProcessor}.\n *\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass OpenTelemetryEnvironmentVariableEnvironmentPostProcessorTests {\n\n\t@Test\n\tvoid shouldMapOtelSdkEnabled(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.enabled\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SDK_DISABLED\", \"true\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SDK_DISABLED\", \"false\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.enabled\")).isEqualTo(\"true\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SDK_DISABLED\", \"invalid-value\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.enabled\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Invalid value for boolean environment variable 'OTEL_SDK_DISABLED': 'invalid-value'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelPropagators(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertHasNoList(environment, \"management.tracing.propagation.type\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"none\"));\n\t\tassertHasEmptyList(environment, \"management.tracing.propagation.type\");\n\t\tassertThat(environment.getProperty(\"management.tracing.baggage.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"tracecontext\"));\n\t\tassertHasList(environment, \"management.tracing.propagation.type\", \"W3C\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"b3\"));\n\t\tassertHasList(environment, \"management.tracing.propagation.type\", \"B3\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"b3multi\"));\n\t\tassertHasList(environment, \"management.tracing.propagation.type\", \"B3_MULTI\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"tracecontext,b3,b3multi\"));\n\t\tassertHasList(environment, \"management.tracing.propagation.type\", \"W3C\", \"B3\", \"B3_MULTI\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \" TraceContext , B3 , B3multi \"));\n\t\tassertHasList(environment, \"management.tracing.propagation.type\", \"W3C\", \"B3\", \"B3_MULTI\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"none,tracecontext,b3,b3multi\"));\n\t\tassertHasEmptyList(environment, \"management.tracing.propagation.type\");\n\t\tassertThat(environment.getProperty(\"management.tracing.baggage.enabled\")).isEqualTo(\"false\");\n\t\tassertThat(output).contains(\n\t\t\t\t\"Environment variable 'OTEL_PROPAGATORS' contains 'none', but also contains more elements: 'none,tracecontext,b3,b3multi'\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"baggage\"));\n\t\tassertHasEmptyList(environment, \"management.tracing.propagation.type\");\n\t\tassertThat(environment.getProperty(\"management.tracing.baggage.enabled\")).isEqualTo(\"true\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"jaeger\"));\n\t\tassertHasEmptyList(environment, \"management.tracing.propagation.type\");\n\t\tassertThat(output).contains(\"Unsupported propagator 'jaeger' in environment variable 'OTEL_PROPAGATORS'\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_PROPAGATORS\", \"tracecontext,xray,b3\"));\n\t\tassertHasList(environment, \"management.tracing.propagation.type\", \"W3C\", \"B3\");\n\t\tassertThat(output).contains(\"Unsupported propagator 'xray' in environment variable 'OTEL_PROPAGATORS'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsHeaders() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertHasNoMap(environment, \"management.otlp.metrics.export.headers\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_HEADERS\", \"a=b,c=d\"));\n\t\tassertHasMap(environment, \"management.otlp.metrics.export.headers\", Map.of(\"a\", \"b\", \"c\", \"d\"));\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsHeadersFallback() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_HEADERS\", \"x=y\"));\n\t\tassertHasMap(environment, \"management.otlp.metrics.export.headers\", Map.of(\"x\", \"y\"));\n\t}\n\n\t@Test\n\tvoid shouldMapOtelTracesSampler(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"always_on\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isEqualTo(\"ALWAYS_ON\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"always_off\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isEqualTo(\"ALWAYS_OFF\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"traceidratio\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isEqualTo(\"TRACE_ID_RATIO\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"parentbased_always_on\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\"))\n\t\t\t.isEqualTo(\"PARENT_BASED_ALWAYS_ON\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"parentbased_always_off\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\"))\n\t\t\t.isEqualTo(\"PARENT_BASED_ALWAYS_OFF\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"parentbased_traceidratio\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\"))\n\t\t\t.isEqualTo(\"PARENT_BASED_TRACE_ID_RATIO\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isNull();\n\t\tassertThat(output).contains(\"Invalid value for environment variable 'OTEL_TRACES_SAMPLER': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelTracesSamplerArg(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"traceidratio\", \"OTEL_TRACES_SAMPLER_ARG\", \"0.5\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isEqualTo(\"0.5\");\n\t\tenvironment = runProcessor(\n\t\t\t\tMap.of(\"OTEL_TRACES_SAMPLER\", \"parentbased_traceidratio\", \"OTEL_TRACES_SAMPLER_ARG\", \"0.25\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isEqualTo(\"0.25\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER_ARG\", \"0.5\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"always_on\", \"OTEL_TRACES_SAMPLER_ARG\", \"0.5\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Unsupported environment variable 'OTEL_TRACES_SAMPLER_ARG' for sampler 'always_on'\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"traceidratio\", \"OTEL_TRACES_SAMPLER_ARG\", \"2.0\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isNull();\n\t\tassertThat(output).contains(\n\t\t\t\t\"Invalid value for environment variable 'OTEL_TRACES_SAMPLER_ARG'. Must be between 0.0 and 1.0: '2.0'\");\n\t\tenvironment = runProcessor(\n\t\t\t\tMap.of(\"OTEL_TRACES_SAMPLER\", \"traceidratio\", \"OTEL_TRACES_SAMPLER_ARG\", \"not-a-number\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.sampling.probability\")).isNull();\n\t\tassertThat(output).contains(\"Invalid value for environment variable 'OTEL_TRACES_SAMPLER_ARG': 'not-a-number'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsEndpoint() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.url\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT\", \"http://metrics:4318/v1/metrics\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.url\"))\n\t\t\t.isEqualTo(\"http://metrics:4318/v1/metrics\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.url\"))\n\t\t\t.isEqualTo(\"http://collector:4318/v1/metrics\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsEndpointSpecificOverridesFallback() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT\",\n\t\t\t\t\"http://metrics:4318/v1/metrics\", \"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.url\"))\n\t\t\t.isEqualTo(\"http://metrics:4318/v1/metrics\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsTemporalityPreference(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.aggregation-temporality\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE\", \"cumulative\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.aggregation-temporality\"))\n\t\t\t.isEqualTo(\"CUMULATIVE\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE\", \"delta\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.aggregation-temporality\"))\n\t\t\t.isEqualTo(\"DELTA\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.aggregation-temporality\")).isNull();\n\t\tassertThat(output).contains(\n\t\t\t\t\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsDefaultHistogramAggregation(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.histogram-flavor\")).isNull();\n\t\tenvironment = runProcessor(\n\t\t\t\tMap.of(\"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION\", \"explicit_bucket_histogram\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.histogram-flavor\"))\n\t\t\t.isEqualTo(\"EXPLICIT_BUCKET_HISTOGRAM\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION\",\n\t\t\t\t\"base2_exponential_bucket_histogram\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.histogram-flavor\"))\n\t\t\t.isEqualTo(\"BASE2_EXPONENTIAL_BUCKET_HISTOGRAM\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.histogram-flavor\")).isNull();\n\t\tassertThat(output).contains(\n\t\t\t\t\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsCompression(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.compression-mode\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_COMPRESSION\", \"gzip\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.compression-mode\")).isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_COMPRESSION\", \"none\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.compression-mode\")).isEqualTo(\"NONE\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_COMPRESSION\", \"gzip\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.compression-mode\")).isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_COMPRESSION\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.compression-mode\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_METRICS_COMPRESSION': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsTimeout() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.read-timeout\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT\", \"5000\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.read-timeout\")).isEqualTo(\"PT5S\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TIMEOUT\", \"3000\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.read-timeout\")).isEqualTo(\"PT3S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelMetricExportInterval() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.step\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRIC_EXPORT_INTERVAL\", \"60000\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.step\")).isEqualTo(\"PT1M\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelMetricsExporter(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.enabled\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXPORTER\", \"otlp\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.enabled\")).isEqualTo(\"true\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXPORTER\", \"none\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXPORTER\", \"prometheus\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXPORTER\", \"none,otlp\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.enabled\")).isEqualTo(\"false\");\n\t\tassertThat(output).contains(\n\t\t\t\t\"Environment variable 'OTEL_METRICS_EXPORTER' contains 'none', but also contains more elements: 'none,otlp'\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXPORTER\", \" OTLP , prometheus \"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.enabled\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsSslBundle() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.ssl.bundle\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE\", \"/path/to/cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-metrics\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/cert.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY\", \"/path/to/key.pem\",\n\t\t\t\t\"OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE\", \"/path/to/client-cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-metrics\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/path/to/key.pem\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/client-cert.pem\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpMetricsSslBundleFallback() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"/path/to/cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-metrics\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/cert.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CLIENT_KEY\", \"/path/to/key.pem\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-metrics\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/path/to/key.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\", \"/path/to/client-cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-metrics\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/client-cert.pem\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesEndpoint() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.endpoint\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", \"http://traces:4318/v1/traces\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://traces:4318/v1/traces\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://collector:4318/v1/traces\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesCompression(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_COMPRESSION\", \"gzip\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_COMPRESSION\", \"none\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"NONE\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_COMPRESSION\", \"gzip\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_COMPRESSION\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_TRACES_COMPRESSION': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesTimeout() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.timeout\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", \"5000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.timeout\")).isEqualTo(\"PT5S\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TIMEOUT\", \"3000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.timeout\")).isEqualTo(\"PT3S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesProtocol(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"grpc\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isEqualTo(\"GRPC\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"http/protobuf\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isEqualTo(\"HTTP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_PROTOCOL\", \"grpc\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isEqualTo(\"GRPC\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_TRACES_PROTOCOL': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesHeaders() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertHasNoMap(environment, \"management.opentelemetry.tracing.export.otlp.headers\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", \"a=b,c=d\"));\n\t\tassertHasMap(environment, \"management.opentelemetry.tracing.export.otlp.headers\", Map.of(\"a\", \"b\", \"c\", \"d\"));\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_HEADERS\", \"x=y\"));\n\t\tassertHasMap(environment, \"management.opentelemetry.tracing.export.otlp.headers\", Map.of(\"x\", \"y\"));\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBspScheduleDelay() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.schedule-delay\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BSP_SCHEDULE_DELAY\", \"5000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.schedule-delay\")).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBspExportTimeout() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.timeout\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BSP_EXPORT_TIMEOUT\", \"30000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.timeout\")).isEqualTo(\"PT30S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBspMaxQueueSize() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.max-queue-size\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BSP_MAX_QUEUE_SIZE\", \"2048\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.max-queue-size\")).isEqualTo(\"2048\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBspMaxExportBatchSize() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.max-batch-size\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BSP_MAX_EXPORT_BATCH_SIZE\", \"512\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.max-batch-size\")).isEqualTo(\"512\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelTracesExporter(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.tracing.export.otlp.enabled\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_EXPORTER\", \"otlp\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.export.otlp.enabled\")).isEqualTo(\"true\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_EXPORTER\", \"none\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.export.otlp.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_EXPORTER\", \"zipkin\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.export.otlp.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_EXPORTER\", \"none,otlp\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.export.otlp.enabled\")).isEqualTo(\"false\");\n\t\tassertThat(output).contains(\n\t\t\t\t\"Environment variable 'OTEL_TRACES_EXPORTER' contains 'none', but also contains more elements: 'none,otlp'\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_EXPORTER\", \" OTLP , zipkin \"));\n\t\tassertThat(environment.getProperty(\"management.tracing.export.otlp.enabled\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelSpanAttributeValueLengthLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attribute-value-length\"))\n\t\t\t.isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"4096\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attribute-value-length\"))\n\t\t\t.isEqualTo(\"4096\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"2048\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attribute-value-length\"))\n\t\t\t.isEqualTo(\"2048\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelSpanAttributeCountLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT\", \"128\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes\")).isEqualTo(\"128\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_ATTRIBUTE_COUNT_LIMIT\", \"64\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes\")).isEqualTo(\"64\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelSpanEventCountLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-events\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SPAN_EVENT_COUNT_LIMIT\", \"128\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-events\")).isEqualTo(\"128\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelSpanLinkCountLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-links\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_SPAN_LINK_COUNT_LIMIT\", \"128\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-links\")).isEqualTo(\"128\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelEventAttributeCountLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes-per-event\"))\n\t\t\t.isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT\", \"128\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes-per-event\"))\n\t\t\t.isEqualTo(\"128\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelLinkAttributeCountLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes-per-link\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LINK_ATTRIBUTE_COUNT_LIMIT\", \"128\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes-per-link\"))\n\t\t\t.isEqualTo(\"128\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelMetricsExemplarFilter(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.tracing.exemplars.include\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXEMPLAR_FILTER\", \"always_on\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.exemplars.include\")).isEqualTo(\"ALL\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXEMPLAR_FILTER\", \"always_off\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.exemplars.include\")).isEqualTo(\"NONE\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXEMPLAR_FILTER\", \"trace_based\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.exemplars.include\")).isEqualTo(\"SAMPLED_TRACES\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXEMPLAR_FILTER\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.exemplars.include\")).isNull();\n\t\tassertThat(output).contains(\"Invalid value for environment variable 'OTEL_METRICS_EXEMPLAR_FILTER': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesSslBundle() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.ssl.bundle\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE\", \"/path/to/cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-tracing\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/cert.pem\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpTracesSslBundleFallback() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"/path/to/cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-tracing\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/cert.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CLIENT_KEY\", \"/path/to/key.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-tracing\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/path/to/key.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\", \"/path/to/client-cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-tracing\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/client-cert.pem\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsEndpoint() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.endpoint\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\", \"http://logs:4318/v1/logs\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://logs:4318/v1/logs\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://collector:4318/v1/logs\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsCompression(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.compression\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_COMPRESSION\", \"gzip\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_COMPRESSION\", \"none\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"NONE\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_COMPRESSION\", \"gzip\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_COMPRESSION\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.compression\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_LOGS_COMPRESSION': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsTimeout() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.timeout\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_TIMEOUT\", \"5000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.timeout\")).isEqualTo(\"PT5S\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TIMEOUT\", \"3000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.timeout\")).isEqualTo(\"PT3S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsProtocol(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.transport\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL\", \"grpc\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.transport\")).isEqualTo(\"GRPC\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL\", \"http/protobuf\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.transport\")).isEqualTo(\"HTTP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_PROTOCOL\", \"grpc\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.transport\")).isEqualTo(\"GRPC\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL\", \"invalid\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.transport\")).isNull();\n\t\tassertThat(output)\n\t\t\t.contains(\"Invalid value for environment variable 'OTEL_EXPORTER_OTLP_LOGS_PROTOCOL': 'invalid'\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsHeaders() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertHasNoMap(environment, \"management.opentelemetry.logging.export.otlp.headers\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_HEADERS\", \"a=b,c=d\"));\n\t\tassertHasMap(environment, \"management.opentelemetry.logging.export.otlp.headers\", Map.of(\"a\", \"b\", \"c\", \"d\"));\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_HEADERS\", \"x=y\"));\n\t\tassertHasMap(environment, \"management.opentelemetry.logging.export.otlp.headers\", Map.of(\"x\", \"y\"));\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBlrpScheduleDelay() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.schedule-delay\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BLRP_SCHEDULE_DELAY\", \"5000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.schedule-delay\")).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBlrpExportTimeout() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.timeout\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BLRP_EXPORT_TIMEOUT\", \"30000\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.timeout\")).isEqualTo(\"PT30S\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBlrpMaxQueueSize() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.max-queue-size\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BLRP_MAX_QUEUE_SIZE\", \"2048\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.max-queue-size\")).isEqualTo(\"2048\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelBlrpMaxExportBatchSize() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.max-batch-size\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BLRP_MAX_EXPORT_BATCH_SIZE\", \"512\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.max-batch-size\")).isEqualTo(\"512\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelLogsExporter(CapturedOutput output) {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.logging.export.otlp.enabled\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGS_EXPORTER\", \"otlp\"));\n\t\tassertThat(environment.getProperty(\"management.logging.export.otlp.enabled\")).isEqualTo(\"true\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGS_EXPORTER\", \"none\"));\n\t\tassertThat(environment.getProperty(\"management.logging.export.otlp.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGS_EXPORTER\", \"console\"));\n\t\tassertThat(environment.getProperty(\"management.logging.export.otlp.enabled\")).isEqualTo(\"false\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGS_EXPORTER\", \"none,otlp\"));\n\t\tassertThat(environment.getProperty(\"management.logging.export.otlp.enabled\")).isEqualTo(\"false\");\n\t\tassertThat(output).contains(\n\t\t\t\t\"Environment variable 'OTEL_LOGS_EXPORTER' contains 'none', but also contains more elements: 'none,otlp'\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGS_EXPORTER\", \" OTLP , console \"));\n\t\tassertThat(environment.getProperty(\"management.logging.export.otlp.enabled\")).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelLogrecordAttributeValueLengthLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attribute-value-length\"))\n\t\t\t.isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"4096\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attribute-value-length\"))\n\t\t\t.isEqualTo(\"4096\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"2048\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attribute-value-length\"))\n\t\t\t.isEqualTo(\"2048\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelLogrecordAttributeCountLimit() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attributes\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT\", \"128\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attributes\")).isEqualTo(\"128\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_ATTRIBUTE_COUNT_LIMIT\", \"64\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attributes\")).isEqualTo(\"64\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsSslBundle() {\n\t\tEnvironment environment = runProcessor(Collections.emptyMap());\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.ssl.bundle\")).isNull();\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE\", \"/path/to/cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-logging\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/cert.pem\");\n\t}\n\n\t@Test\n\tvoid shouldMapOtelExporterOtlpLogsSslBundleFallback() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"/path/to/cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-logging\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/cert.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CLIENT_KEY\", \"/path/to/key.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-logging\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/path/to/key.pem\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\", \"/path/to/client-cert.pem\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.ssl.bundle\"))\n\t\t\t.isEqualTo(\"opentelemetry-logging\");\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/path/to/client-cert.pem\");\n\t}\n\n\t@Test\n\tvoid enumValuesShouldBeCaseInsensitive() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"ALWAYS_ON\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isEqualTo(\"ALWAYS_ON\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_TRACES_SAMPLER\", \"Always_On\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.sampler\")).isEqualTo(\"ALWAYS_ON\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_COMPRESSION\", \"GZIP\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"GRPC\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isEqualTo(\"GRPC\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"HTTP/PROTOBUF\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isEqualTo(\"HTTP\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_METRICS_EXEMPLAR_FILTER\", \"TRACE_BASED\"));\n\t\tassertThat(environment.getProperty(\"management.tracing.exemplars.include\")).isEqualTo(\"SAMPLED_TRACES\");\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE\", \"CUMULATIVE\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.aggregation-temporality\"))\n\t\t\t.isEqualTo(\"CUMULATIVE\");\n\t\tenvironment = runProcessor(\n\t\t\t\tMap.of(\"OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION\", \"EXPLICIT_BUCKET_HISTOGRAM\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.histogram-flavor\"))\n\t\t\t.isEqualTo(\"EXPLICIT_BUCKET_HISTOGRAM\");\n\t}\n\n\t@Test\n\tvoid fallbackEndpointWithTrailingSlashShouldAppendPathCorrectly() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318/\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.url\"))\n\t\t\t.isEqualTo(\"http://collector:4318/v1/metrics\");\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://collector:4318/v1/traces\");\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://collector:4318/v1/logs\");\n\t}\n\n\t@Test\n\tvoid timeoutZeroShouldBeInterpretedAsInfinite() {\n\t\tEnvironment environment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", \"0\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.timeout\"))\n\t\t\t.isEqualTo(Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_LOGS_TIMEOUT\", \"0\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.timeout\"))\n\t\t\t.isEqualTo(Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t\tenvironment = runProcessor(Map.of(\"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT\", \"0\"));\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.read-timeout\"))\n\t\t\t.isEqualTo(Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BSP_EXPORT_TIMEOUT\", \"0\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.timeout\"))\n\t\t\t.isEqualTo(Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t\tenvironment = runProcessor(Map.of(\"OTEL_BLRP_EXPORT_TIMEOUT\", \"0\"));\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.timeout\"))\n\t\t\t.isEqualTo(Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t}\n\n\t@Test\n\tvoid shouldNotAddPropertySourceWhenNoEnvironmentVariablesAreSet() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tint sourceCountBefore = environment.getPropertySources().size();\n\t\tDeferredLogs logFactory = new DeferredLogs();\n\t\tOpenTelemetryEnvironmentVariableEnvironmentPostProcessor processor = new OpenTelemetryEnvironmentVariableEnvironmentPostProcessor(\n\t\t\t\tlogFactory, new OpenTelemetryEnvironmentVariables(logFactory, (name) -> null));\n\t\tprocessor.postProcessEnvironment(environment, new SpringApplication());\n\t\tassertThat(environment.getPropertySources()).hasSize(sourceCountBefore);\n\t}\n\n\t@Test\n\tvoid shouldNotMapWhenDisabledViaProperty() {\n\t\tDeferredLogs logFactory = new DeferredLogs();\n\t\tMap<String, String> envVars = Map.of(\"OTEL_SDK_DISABLED\", \"true\");\n\t\tOpenTelemetryEnvironmentVariableEnvironmentPostProcessor processor = new OpenTelemetryEnvironmentVariableEnvironmentPostProcessor(\n\t\t\t\tlogFactory, new OpenTelemetryEnvironmentVariables(logFactory, envVars::get));\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tenvironment.getPropertySources()\n\t\t\t.addFirst(new org.springframework.core.env.MapPropertySource(\"test\",\n\t\t\t\t\tMap.of(\"management.opentelemetry.map-environment-variables\", \"false\")));\n\t\tint sourceCountBefore = environment.getPropertySources().size();\n\t\tprocessor.postProcessEnvironment(environment, new SpringApplication());\n\t\tassertThat(environment.getPropertySources()).hasSize(sourceCountBefore);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.enabled\")).isNull();\n\t}\n\n\t@Test\n\tvoid specificMetricsCompressionShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_METRICS_COMPRESSION\", \"gzip\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_COMPRESSION\", \"none\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.compression-mode\")).isEqualTo(\"GZIP\");\n\t}\n\n\t@Test\n\tvoid specificMetricsTimeoutShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_METRICS_TIMEOUT\", \"5000\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TIMEOUT\", \"3000\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.otlp.metrics.export.read-timeout\")).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid specificMetricsHeadersShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_METRICS_HEADERS\", \"a=b\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_HEADERS\", \"x=y\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertHasMap(environment, \"management.otlp.metrics.export.headers\", Map.of(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid specificMetricsCertificateShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE\", \"/specific/cert.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"/generic/cert.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/specific/cert.pem\");\n\t}\n\n\t@Test\n\tvoid specificMetricsClientKeyShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY\", \"/specific/key.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CLIENT_KEY\", \"/generic/key.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/specific/key.pem\");\n\t}\n\n\t@Test\n\tvoid specificMetricsClientCertificateShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE\", \"/specific/client.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\", \"/generic/client.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-metrics.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/specific/client.pem\");\n\t}\n\n\t@Test\n\tvoid specificTracesEndpointShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", \"http://traces:4318/v1/traces\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://traces:4318/v1/traces\");\n\t}\n\n\t@Test\n\tvoid specificTracesCompressionShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_COMPRESSION\", \"gzip\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_COMPRESSION\", \"none\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t}\n\n\t@Test\n\tvoid specificTracesTimeoutShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", \"5000\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TIMEOUT\", \"3000\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.timeout\")).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid specificTracesProtocolShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_PROTOCOL\", \"http/protobuf\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_PROTOCOL\", \"grpc\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.export.otlp.transport\")).isEqualTo(\"HTTP\");\n\t}\n\n\t@Test\n\tvoid specificTracesHeadersShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", \"a=b\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_HEADERS\", \"x=y\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertHasMap(environment, \"management.opentelemetry.tracing.export.otlp.headers\", Map.of(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid specificTracesAttributeValueLengthLimitShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"4096\");\n\t\tenv.put(\"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"2048\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attribute-value-length\"))\n\t\t\t.isEqualTo(\"4096\");\n\t}\n\n\t@Test\n\tvoid specificTracesAttributeCountLimitShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT\", \"128\");\n\t\tenv.put(\"OTEL_ATTRIBUTE_COUNT_LIMIT\", \"64\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.tracing.limits.max-attributes\")).isEqualTo(\"128\");\n\t}\n\n\t@Test\n\tvoid specificTracesCertificateShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE\", \"/specific/cert.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"/generic/cert.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/specific/cert.pem\");\n\t}\n\n\t@Test\n\tvoid specificTracesClientKeyShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY\", \"/specific/key.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CLIENT_KEY\", \"/generic/key.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/specific/key.pem\");\n\t}\n\n\t@Test\n\tvoid specificTracesClientCertificateShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE\", \"/specific/client.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\", \"/generic/client.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-tracing.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/specific/client.pem\");\n\t}\n\n\t@Test\n\tvoid specificLogsEndpointShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\", \"http://logs:4318/v1/logs\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://collector:4318\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.endpoint\"))\n\t\t\t.isEqualTo(\"http://logs:4318/v1/logs\");\n\t}\n\n\t@Test\n\tvoid specificLogsCompressionShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_COMPRESSION\", \"gzip\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_COMPRESSION\", \"none\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.compression\"))\n\t\t\t.isEqualTo(\"GZIP\");\n\t}\n\n\t@Test\n\tvoid specificLogsTimeoutShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_TIMEOUT\", \"5000\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_TIMEOUT\", \"3000\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.timeout\")).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid specificLogsProtocolShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_PROTOCOL\", \"http/protobuf\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_PROTOCOL\", \"grpc\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.export.otlp.transport\")).isEqualTo(\"HTTP\");\n\t}\n\n\t@Test\n\tvoid specificLogsHeadersShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_HEADERS\", \"a=b\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_HEADERS\", \"x=y\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertHasMap(environment, \"management.opentelemetry.logging.export.otlp.headers\", Map.of(\"a\", \"b\"));\n\t}\n\n\t@Test\n\tvoid specificLogsAttributeValueLengthLimitShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"4096\");\n\t\tenv.put(\"OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT\", \"2048\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attribute-value-length\"))\n\t\t\t.isEqualTo(\"4096\");\n\t}\n\n\t@Test\n\tvoid specificLogsAttributeCountLimitShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT\", \"128\");\n\t\tenv.put(\"OTEL_ATTRIBUTE_COUNT_LIMIT\", \"64\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"management.opentelemetry.logging.limits.max-attributes\")).isEqualTo(\"128\");\n\t}\n\n\t@Test\n\tvoid specificLogsCertificateShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE\", \"/specific/cert.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"/generic/cert.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.truststore.certificate\"))\n\t\t\t.isEqualTo(\"file:/specific/cert.pem\");\n\t}\n\n\t@Test\n\tvoid specificLogsClientKeyShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY\", \"/specific/key.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CLIENT_KEY\", \"/generic/key.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.keystore.private-key\"))\n\t\t\t.isEqualTo(\"file:/specific/key.pem\");\n\t}\n\n\t@Test\n\tvoid specificLogsClientCertificateShouldOverrideFallback() {\n\t\tMap<String, String> env = new HashMap<>();\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE\", \"/specific/client.pem\");\n\t\tenv.put(\"OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE\", \"/generic/client.pem\");\n\t\tEnvironment environment = runProcessor(env);\n\t\tassertThat(environment.getProperty(\"spring.ssl.bundle.pem.opentelemetry-logging.keystore.certificate\"))\n\t\t\t.isEqualTo(\"file:/specific/client.pem\");\n\t}\n\n\tprivate Environment runProcessor(Map<String, String> environmentVariables) {\n\t\tDeferredLogs logFactory = new DeferredLogs();\n\t\tOpenTelemetryEnvironmentVariableEnvironmentPostProcessor processor = new OpenTelemetryEnvironmentVariableEnvironmentPostProcessor(\n\t\t\t\tlogFactory, new OpenTelemetryEnvironmentVariables(logFactory, environmentVariables::get));\n\t\tConfigurableEnvironment configurableEnvironment = new StandardEnvironment();\n\t\tprocessor.postProcessEnvironment(configurableEnvironment, new SpringApplication());\n\t\tlogFactory.switchOverAll();\n\t\treturn configurableEnvironment;\n\t}\n\n\tprivate void assertHasNoMap(Environment environment, String key) {\n\t\tenumerateAllProperties(environment, (name) -> assertThat(name).doesNotStartWith(key + \"[\"));\n\t}\n\n\tprivate void assertHasMap(Environment environment, String key, Map<String, String> map) {\n\t\tSet<String> ignoredProperties = new HashSet<>();\n\t\tfor (Entry<String, String> entry : map.entrySet()) {\n\t\t\tString property = \"%s[%s]\".formatted(key, entry.getKey());\n\t\t\tassertThat(environment.getProperty(property)).isEqualTo(entry.getValue());\n\t\t\tignoredProperties.add(property);\n\t\t}\n\t\tenumerateAllProperties(environment, ignoredProperties, (name) -> assertThat(name).doesNotStartWith(key + \"[\"));\n\t}\n\n\tprivate void assertHasList(Environment environment, String key, String... values) {\n\t\tSet<String> ignoredProperties = new HashSet<>();\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tString property = \"%s[%d]\".formatted(key, i);\n\t\t\tassertThat(environment.getProperty(property)).isEqualTo(values[i]);\n\t\t\tignoredProperties.add(property);\n\t\t}\n\t\tenumerateAllProperties(environment, ignoredProperties, (name) -> assertThat(name).doesNotStartWith(key + \"[\"));\n\t}\n\n\tprivate void assertHasEmptyList(Environment environment, String key) {\n\t\tassertThat(environment.getProperty(key)).isEqualTo(\"\");\n\t\tenumerateAllProperties(environment, (name) -> assertThat(name).doesNotStartWith(key + \"[\"));\n\t}\n\n\tprivate void assertHasNoList(Environment environment, String key) {\n\t\tenumerateAllProperties(environment, (name) -> assertThat(name).doesNotStartWith(key + \"[\"));\n\t}\n\n\tprivate void enumerateAllProperties(Environment environment, ThrowingConsumer<String> consumer) {\n\t\tenumerateAllProperties(environment, Collections.emptySet(), consumer::accept);\n\t}\n\n\tprivate void enumerateAllProperties(Environment environment, Set<String> ignoredProperties,\n\t\t\tThrowingConsumer<String> consumer) {\n\t\tConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment;\n\t\tconfigurableEnvironment.getPropertySources().forEach((source) -> {\n\t\t\tif (source instanceof EnumerablePropertySource<?> enumerablePropertySource) {\n\t\t\t\tassertThat(enumerablePropertySource.getPropertyNames()).allSatisfy((name) -> {\n\t\t\t\t\tif (!ignoredProperties.contains(name)) {\n\t\t\t\t\t\tconsumer.accept(name);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfail(\"Property source %s doesn't support enumerating properties\", source);\n\t\t\t}\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryEnvironmentVariablesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.DeferredLogs;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetryEnvironmentVariables.EnvVariable;\nimport org.springframework.boot.origin.Origin;\nimport org.springframework.boot.origin.OriginTrackedValue;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link OpenTelemetryEnvironmentVariables}.\n *\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass OpenTelemetryEnvironmentVariablesTests {\n\n\tprivate DeferredLogs logFactory;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.logFactory = new DeferredLogs();\n\t}\n\n\t@Test\n\tvoid getIntShouldReturnParsedValue() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"42\"));\n\t\tEnvVariable result = env.getInt(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"VAR\");\n\t\tassertThat(result.value()).isEqualTo(\"42\");\n\t}\n\n\t@Test\n\tvoid getIntShouldReturnNoneWhenMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getInt(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getIntShouldReturnNoneWhenEmpty() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"\"));\n\t\tEnvVariable result = env.getInt(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getIntShouldReturnNoneAndWarnWhenNotANumber(CapturedOutput output) {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"abc\"));\n\t\tEnvVariable result = env.getInt(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t\tassertThatLogContains(output, \"Invalid value for integer environment variable 'VAR': 'abc'\");\n\t}\n\n\t@Test\n\tvoid getIntWithFallbackShouldUsePrimaryWhenPresent() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"PRIMARY\", \"10\", \"FALLBACK\", \"20\"));\n\t\tEnvVariable result = env.getInt(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"PRIMARY\");\n\t\tassertThat(result.value()).isEqualTo(\"10\");\n\t}\n\n\t@Test\n\tvoid getIntWithFallbackShouldUseFallbackWhenPrimaryMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"FALLBACK\", \"20\"));\n\t\tEnvVariable result = env.getInt(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"FALLBACK\");\n\t\tassertThat(result.value()).isEqualTo(\"20\");\n\t}\n\n\t@Test\n\tvoid getIntWithFallbackShouldReturnNoneWhenBothMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getInt(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getBooleanShouldReturnTrueValue() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"true\"));\n\t\tEnvVariable result = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.value()).isEqualTo(\"true\");\n\t}\n\n\t@Test\n\tvoid getBooleanShouldReturnFalseValue() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"false\"));\n\t\tEnvVariable result = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.value()).isEqualTo(\"false\");\n\t}\n\n\t@Test\n\tvoid getBooleanShouldBeCaseInsensitive() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"TRUE\"));\n\t\tEnvVariable result = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.value()).isEqualTo(\"true\");\n\t\tenv = createEnv(Map.of(\"VAR\", \"False\"));\n\t\tresult = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.value()).isEqualTo(\"false\");\n\t}\n\n\t@Test\n\tvoid getBooleanShouldReturnNoneWhenMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getBooleanShouldReturnNoneWhenEmpty() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"\"));\n\t\tEnvVariable result = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getBooleanShouldReturnNoneAndWarnWhenInvalid(CapturedOutput output) {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"yes\"));\n\t\tEnvVariable result = env.getBoolean(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t\tassertThatLogContains(output, \"Invalid value for boolean environment variable 'VAR': 'yes'\");\n\t}\n\n\t@Test\n\tvoid getDurationShouldConvertMilliseconds() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"5000\"));\n\t\tEnvVariable result = env.getDuration(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"VAR\");\n\t\tassertThat(result.value()).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid getDurationShouldHandleZero() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"0\"));\n\t\tEnvVariable result = env.getDuration(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.value()).isEqualTo(\"PT0S\");\n\t}\n\n\t@Test\n\tvoid getDurationShouldReturnNoneWhenMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getDuration(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getDurationShouldReturnNoneWhenEmpty() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"\"));\n\t\tEnvVariable result = env.getDuration(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getDurationShouldReturnNoneAndWarnWhenNotANumber(CapturedOutput output) {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"abc\"));\n\t\tEnvVariable result = env.getDuration(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t\tassertThatLogContains(output, \"Invalid value for duration environment variable 'VAR': 'abc'\");\n\t}\n\n\t@Test\n\tvoid getDurationShouldReturnNoneAndWarnWhenNegative(CapturedOutput output) {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"-1\"));\n\t\tEnvVariable result = env.getDuration(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t\tassertThatLogContains(output, \"Duration environment variable 'VAR' must be non-negative, but was: '-1'\");\n\t}\n\n\t@Test\n\tvoid getTimeoutShouldConvertMilliseconds() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"10000\"));\n\t\tEnvVariable result = env.getTimeout(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"VAR\");\n\t\tassertThat(result.value()).isEqualTo(\"PT10S\");\n\t}\n\n\t@Test\n\tvoid getTimeoutShouldTreatZeroAsInfinity() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"0\"));\n\t\tEnvVariable result = env.getTimeout(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.value()).isEqualTo(Duration.ofSeconds(Long.MAX_VALUE).toString());\n\t}\n\n\t@Test\n\tvoid getTimeoutShouldReturnNoneWhenMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getTimeout(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getTimeoutShouldReturnNoneWhenEmpty() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"\"));\n\t\tEnvVariable result = env.getTimeout(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getTimeoutShouldReturnNoneAndWarnWhenNotANumber(CapturedOutput output) {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"abc\"));\n\t\tEnvVariable result = env.getTimeout(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t\tassertThatLogContains(output, \"Invalid value for duration environment variable 'VAR': 'abc'\");\n\t}\n\n\t@Test\n\tvoid getTimeoutShouldReturnNoneAndWarnWhenNegative(CapturedOutput output) {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"-5\"));\n\t\tEnvVariable result = env.getTimeout(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t\tassertThatLogContains(output, \"Duration environment variable 'VAR' must be non-negative, but was: '-5'\");\n\t}\n\n\t@Test\n\tvoid getTimeoutWithFallbackShouldUsePrimaryWhenPresent() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"PRIMARY\", \"5000\", \"FALLBACK\", \"3000\"));\n\t\tEnvVariable result = env.getTimeout(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"PRIMARY\");\n\t\tassertThat(result.value()).isEqualTo(\"PT5S\");\n\t}\n\n\t@Test\n\tvoid getTimeoutWithFallbackShouldUseFallbackWhenPrimaryMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"FALLBACK\", \"3000\"));\n\t\tEnvVariable result = env.getTimeout(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"FALLBACK\");\n\t\tassertThat(result.value()).isEqualTo(\"PT3S\");\n\t}\n\n\t@Test\n\tvoid getTimeoutWithFallbackShouldReturnNoneWhenBothMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getTimeout(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getStringShouldReturnValue() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"hello\"));\n\t\tEnvVariable result = env.getString(\"VAR\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"VAR\");\n\t\tassertThat(result.value()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid getStringShouldReturnNoneWhenMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getString(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getStringShouldReturnNoneWhenEmpty() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"VAR\", \"\"));\n\t\tEnvVariable result = env.getString(\"VAR\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getStringWithFallbackShouldUsePrimaryWhenPresent() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"PRIMARY\", \"a\", \"FALLBACK\", \"b\"));\n\t\tEnvVariable result = env.getString(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"PRIMARY\");\n\t\tassertThat(result.value()).isEqualTo(\"a\");\n\t}\n\n\t@Test\n\tvoid getStringWithFallbackShouldUseFallbackWhenPrimaryMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"FALLBACK\", \"b\"));\n\t\tEnvVariable result = env.getString(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"FALLBACK\");\n\t\tassertThat(result.value()).isEqualTo(\"b\");\n\t}\n\n\t@Test\n\tvoid getStringWithFallbackShouldReturnNoneWhenBothMissing() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getString(\"PRIMARY\", \"FALLBACK\");\n\t\tassertThat(result.isPresent()).isFalse();\n\t}\n\n\t@Test\n\tvoid getStringWithFallbackTransformerShouldApplyTransformerToFallbackValue() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"FALLBACK\", \"base\"));\n\t\tEnvVariable result = env.getString(\"PRIMARY\", \"FALLBACK\", (value) -> value + \"/appended\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"FALLBACK\");\n\t\tassertThat(result.value()).isEqualTo(\"base/appended\");\n\t}\n\n\t@Test\n\tvoid getStringWithFallbackTransformerShouldNotApplyTransformerToPrimaryValue() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Map.of(\"PRIMARY\", \"primary-value\", \"FALLBACK\", \"base\"));\n\t\tEnvVariable result = env.getString(\"PRIMARY\", \"FALLBACK\", (value) -> value + \"/appended\");\n\t\tassertThat(result.isPresent()).isTrue();\n\t\tassertThat(result.name()).isEqualTo(\"PRIMARY\");\n\t\tassertThat(result.value()).isEqualTo(\"primary-value\");\n\t}\n\n\t@Test\n\tvoid getFirstPresentShouldReturnFirstPresentVariable() {\n\t\tEnvVariable first = EnvVariable.of(\"A\", \"1\");\n\t\tEnvVariable second = EnvVariable.of(\"B\", \"2\");\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getFirstPresent(first, second);\n\t\tassertThat(result).isSameAs(first);\n\t}\n\n\t@Test\n\tvoid getFirstPresentShouldSkipAbsentVariables() {\n\t\tEnvVariable absent = EnvVariable.none();\n\t\tEnvVariable present = EnvVariable.of(\"B\", \"2\");\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getFirstPresent(absent, present);\n\t\tassertThat(result).isSameAs(present);\n\t}\n\n\t@Test\n\tvoid getFirstPresentShouldReturnNullWhenAllAbsent() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tEnvVariable result = env.getFirstPresent(EnvVariable.none(), EnvVariable.none());\n\t\tassertThat(result).isNull();\n\t}\n\n\t@Test\n\tvoid getOriginShouldReturnOriginForPresentVariable() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tOrigin origin = env.getOrigin(EnvVariable.of(\"MY_VAR\", \"value\"));\n\t\tassertThat(origin).isNotNull();\n\t\tassertThat(origin).hasToString(\"Converted OpenTelemetry environment variable 'MY_VAR'\");\n\t}\n\n\t@Test\n\tvoid getOriginShouldReturnNullForAbsentVariable() {\n\t\tOpenTelemetryEnvironmentVariables env = createEnv(Collections.emptyMap());\n\t\tOrigin origin = env.getOrigin(EnvVariable.none());\n\t\tassertThat(origin).isNull();\n\t}\n\n\t@Test\n\tvoid envVariableNoneShouldNotBePresent() {\n\t\tEnvVariable none = EnvVariable.none();\n\t\tassertThat(none.isPresent()).isFalse();\n\t\tassertThat(none.name()).isNull();\n\t\tassertThat(none.value()).isNull();\n\t}\n\n\t@Test\n\tvoid addToMapShouldAddValueWithOrigin() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"value\").addToMap(map, \"my.property\");\n\t\tassertThat(map).containsKey(\"my.property\");\n\t\tassertThat(map.get(\"my.property\")).satisfies((tracked) -> {\n\t\t\tassertThat(tracked.getValue()).isEqualTo(\"value\");\n\t\t\tassertThat(tracked.getOrigin()).hasToString(\"Converted OpenTelemetry environment variable 'VAR'\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid addToMapWithTransformerShouldTransformValue() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"input\").addToMap(map, \"my.property\", (name, value) -> value.toUpperCase(Locale.ROOT));\n\t\tassertThat(map).hasEntrySatisfying(\"my.property\",\n\t\t\t\t(tracked) -> assertThat(tracked.getValue()).isEqualTo(\"INPUT\"));\n\t}\n\n\t@Test\n\tvoid addToMapShouldNotAddWhenTransformerReturnsNull() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"input\").addToMap(map, \"my.property\", (name, value) -> null);\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid addToMapShouldBeNoOpForNoneVariable() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.none().addToMap(map, \"my.property\");\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid addToMapShouldThrowOnDuplicateKey() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR1\", \"value1\").addToMap(map, \"my.property\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> EnvVariable.of(\"VAR2\", \"value2\").addToMap(map, \"my.property\"))\n\t\t\t.withMessageContaining(\"Duplicate key 'my.property'\");\n\t}\n\n\t@Test\n\tvoid addMappingToMapShouldAddEntries() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"a=1,b=2\").addMappingToMap(map, \"my.headers\", (name, value) -> {\n\t\t\tMap<String, String> result = new LinkedHashMap<>();\n\t\t\tfor (String part : value.split(\",\")) {\n\t\t\t\tString[] keyValue = part.split(\"=\", 2);\n\t\t\t\tresult.put(keyValue[0], keyValue[1]);\n\t\t\t}\n\t\t\treturn result;\n\t\t});\n\t\tassertThat(map).hasEntrySatisfying(\"my.headers[a]\", (tracked) -> assertThat(tracked.getValue()).isEqualTo(\"1\"));\n\t\tassertThat(map).hasEntrySatisfying(\"my.headers[b]\", (tracked) -> assertThat(tracked.getValue()).isEqualTo(\"2\"));\n\t}\n\n\t@Test\n\tvoid addMappingToMapShouldBeNoOpForNoneVariable() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.none().addMappingToMap(map, \"my.headers\", (name, value) -> Map.of(\"a\", \"1\"));\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid addMappingToMapShouldBeNoOpWhenTransformerReturnsNull() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"value\").addMappingToMap(map, \"my.headers\", (name, value) -> null);\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid addMappingToMapShouldThrowOnDuplicateKey() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR1\", \"v\").addMappingToMap(map, \"my.headers\", (name, value) -> Map.of(\"a\", \"1\"));\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> EnvVariable.of(\"VAR2\", \"v\").addMappingToMap(map, \"my.headers\", (name, value) -> Map.of(\"a\", \"2\")))\n\t\t\t.withMessageContaining(\"Duplicate key 'my.headers[a]'\");\n\t}\n\n\t@Test\n\tvoid addListToMapShouldAddEntries() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"a,b,c\")\n\t\t\t.addListToMap(map, \"my.list\",\n\t\t\t\t\t(name, value) -> Stream.of(value.split(\",\")).map(String::toUpperCase).toList());\n\t\tassertThat(map).hasEntrySatisfying(\"my.list[0]\", (tracked) -> assertThat(tracked.getValue()).isEqualTo(\"A\"));\n\t\tassertThat(map).hasEntrySatisfying(\"my.list[1]\", (tracked) -> assertThat(tracked.getValue()).isEqualTo(\"B\"));\n\t\tassertThat(map).hasEntrySatisfying(\"my.list[2]\", (tracked) -> assertThat(tracked.getValue()).isEqualTo(\"C\"));\n\t}\n\n\t@Test\n\tvoid addListToMapShouldBeNoOpForNoneVariable() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.none().addListToMap(map, \"my.list\", (name, value) -> List.of(\"A\"));\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid addListToMapShouldBeNoOpWhenTransformerReturnsNull() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"value\").addListToMap(map, \"my.list\", (name, value) -> null);\n\t\tassertThat(map).isEmpty();\n\t}\n\n\t@Test\n\tvoid addListToMapShouldAddEmptyStringWhenListIsEmpty() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR\", \"value\").addListToMap(map, \"my.list\", (name, value) -> Collections.emptyList());\n\t\tassertThat(map).hasEntrySatisfying(\"my.list\", (tracked) -> assertThat(tracked.getValue()).isEqualTo(\"\"));\n\t}\n\n\t@Test\n\tvoid addListToMapShouldThrowOnDuplicateKey() {\n\t\tMap<String, OriginTrackedValue> map = new HashMap<>();\n\t\tEnvVariable.of(\"VAR1\", \"v\").addListToMap(map, \"my.list\", (name, value) -> List.of(\"A\"));\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> EnvVariable.of(\"VAR2\", \"v\").addListToMap(map, \"my.list\", (name, value) -> List.of(\"B\")))\n\t\t\t.withMessageContaining(\"Duplicate key 'my.list[0]'\");\n\t}\n\n\tprivate OpenTelemetryEnvironmentVariables createEnv(Map<String, String> map) {\n\t\treturn OpenTelemetryEnvironmentVariables.forMap(this.logFactory, map);\n\t}\n\n\tprivate void assertThatLogContains(CapturedOutput output, String message) {\n\t\tthis.logFactory.switchOverAll();\n\t\tassertThat(output).contains(message);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link OpenTelemetryProperties}.\n *\n * @author Moritz Halbritter\n */\nclass OpenTelemetryPropertiesTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner().withPropertyValues(\n\t\t\t\"management.opentelemetry.resource-attributes.a=alpha\",\n\t\t\t\"management.opentelemetry.resource-attributes.b=beta\");\n\n\t@Test\n\t@ClassPathExclusions(\"opentelemetry-sdk-*\")\n\tvoid shouldNotDependOnOpenTelemetrySdk() {\n\t\tthis.runner.withUserConfiguration(TestConfiguration.class).run((context) -> {\n\t\t\tOpenTelemetryProperties properties = context.getBean(OpenTelemetryProperties.class);\n\t\t\tassertThat(properties.getResourceAttributes()).containsOnly(entry(\"a\", \"alpha\"), entry(\"b\", \"beta\"));\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(OpenTelemetryProperties.class)\n\tprivate static final class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryResourceAttributesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.IntStream;\n\nimport io.opentelemetry.api.internal.PercentEscaper;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link OpenTelemetryResourceAttributes}.\n *\n * @author Dmytro Nosan\n */\nclass OpenTelemetryResourceAttributesTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final Map<String, String> environmentVariables = new LinkedHashMap<>();\n\n\tprivate final Map<String, String> resourceAttributes = new LinkedHashMap<>();\n\n\t@Test\n\tvoid otelServiceNameShouldTakePrecedenceOverOtelResourceAttributes() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"service.name=ignored\");\n\t\tthis.environmentVariables.put(\"OTEL_SERVICE_NAME\", \"otel-service\");\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"otel-service\");\n\t}\n\n\t@Test\n\tvoid otelServiceNameWhenEmptyShouldTakePrecedenceOverOtelResourceAttributes() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"service.name=ignored\");\n\t\tthis.environmentVariables.put(\"OTEL_SERVICE_NAME\", \"\");\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"\");\n\t}\n\n\t@Test\n\tvoid otelResourceAttributes() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\",\n\t\t\t\t\", ,,key1=value1,key2= value2, key3=value3,key4=,=value5,key6,=,key7=%20spring+boot%20,key8=ś\");\n\t\tassertThat(getAttributes()).hasSize(7)\n\t\t\t.containsEntry(\"key1\", \"value1\")\n\t\t\t.containsEntry(\"key2\", \"value2\")\n\t\t\t.containsEntry(\"key3\", \"value3\")\n\t\t\t.containsEntry(\"key4\", \"\")\n\t\t\t.containsEntry(\"key7\", \" spring+boot \")\n\t\t\t.containsEntry(\"key8\", \"ś\")\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\");\n\t}\n\n\t@Test\n\tvoid resourceAttributesShouldBeMergedWithEnvironmentVariablesAndTakePrecedence() {\n\t\tthis.resourceAttributes.put(\"service.group\", \"custom-group\");\n\t\tthis.resourceAttributes.put(\"key2\", \"\");\n\t\tthis.environmentVariables.put(\"OTEL_SERVICE_NAME\", \"custom-service\");\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key1=value1,key2=value2\");\n\t\tassertThat(getAttributes()).hasSize(4)\n\t\t\t.containsEntry(\"service.name\", \"custom-service\")\n\t\t\t.containsEntry(\"service.group\", \"custom-group\")\n\t\t\t.containsEntry(\"key1\", \"value1\")\n\t\t\t.containsEntry(\"key2\", \"\");\n\t}\n\n\t@Test\n\tvoid invalidResourceAttributesShouldBeIgnored() {\n\t\tthis.resourceAttributes.put(\"\", \"empty-key\");\n\t\tthis.resourceAttributes.put(null, \"null-key\");\n\t\tthis.resourceAttributes.put(\"null-value\", null);\n\t\tthis.resourceAttributes.put(\"empty-value\", \"\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"empty-value\", \"\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid systemGetEnvShouldBeUsedAsDefaultEnvFunction() {\n\t\tOpenTelemetryResourceAttributes attributes = new OpenTelemetryResourceAttributes(this.environment, null);\n\t\tFunction<String, String> getEnv = assertThat(attributes).extracting(\"systemEnvironment\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(Function.class))\n\t\t\t.actual();\n\t\tSystem.getenv().forEach((key, value) -> assertThat(getEnv.apply(key)).isEqualTo(value));\n\t}\n\n\t@Test\n\tvoid otelResourceAttributeValuesShouldBePercentDecoded() {\n\t\tPercentEscaper escaper = PercentEscaper.create();\n\t\tString value = IntStream.range(32, 127)\n\t\t\t.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)\n\t\t\t.toString();\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key=\" + escaper.escape(value));\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"key\", value);\n\t}\n\n\t@Test\n\tvoid otelResourceAttributeValuesShouldBePercentDecodedWhenStringContainsNonAscii() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key=%20\\u015bp\\u0159\\u00ec\\u0144\\u0121%20\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"key\", \" śpřìńġ \");\n\t}\n\n\t@Test\n\tvoid otelResourceAttributeValuesShouldBePercentDecodedWhenMultiByteSequences() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key=T%C5%8Dky%C5%8D\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"key\", \"Tōkyō\");\n\t}\n\n\t@Test\n\tvoid illegalArgumentExceptionShouldBeThrownWhenDecodingIllegalHexCharPercentEncodedValue() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key=abc%ß\");\n\t\tassertThatIllegalArgumentException().isThrownBy(this::getAttributes)\n\t\t\t.withMessage(\"Incomplete trailing escape (%) pattern\");\n\t}\n\n\t@Test\n\tvoid replacementCharShouldBeUsedWhenDecodingNonUtf8Character() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key=%a3%3e\");\n\t\tassertThat(getAttributes()).containsEntry(\"key\", \"\\ufffd>\");\n\t}\n\n\t@Test\n\tvoid illegalArgumentExceptionShouldBeThrownWhenDecodingInvalidPercentEncodedValue() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"key=%\");\n\t\tassertThatIllegalArgumentException().isThrownBy(this::getAttributes)\n\t\t\t.withMessage(\"Incomplete trailing escape (%) pattern\");\n\t}\n\n\t@Test\n\tvoid unknownServiceShouldBeUsedAsDefaultServiceName() {\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"unknown_service\");\n\t}\n\n\t@Test\n\tvoid springApplicationGroupNameShouldBeUsedAsDefaultServiceNamespace() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"spring-boot\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"service.namespace\", \"spring-boot\");\n\t}\n\n\t@Test\n\tvoid springApplicationNameShouldBeUsedAsDefaultServiceName() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring-boot-app\");\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"spring-boot-app\");\n\t}\n\n\t@Test\n\tvoid serviceNamespaceShouldNotBePresentByDefault() {\n\t\tassertThat(getAttributes()).hasSize(1).doesNotContainKey(\"service.namespace\");\n\t}\n\n\t@Test\n\tvoid resourceAttributesShouldTakePrecedenceOverSpringApplicationName() {\n\t\tthis.resourceAttributes.put(\"service.name\", \"spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring-boot-app\");\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"spring-boot\");\n\t}\n\n\t@Test\n\tvoid otelResourceAttributesShouldTakePrecedenceOverSpringApplicationName() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"service.name=spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring-boot-app\");\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"spring-boot\");\n\t}\n\n\t@Test\n\tvoid otelServiceNameShouldTakePrecedenceOverSpringApplicationName() {\n\t\tthis.environmentVariables.put(\"OTEL_SERVICE_NAME\", \"spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring-boot-app\");\n\t\tassertThat(getAttributes()).hasSize(1).containsEntry(\"service.name\", \"spring-boot\");\n\t}\n\n\t@Test\n\tvoid resourceAttributesShouldTakePrecedenceOverSpringApplicationGroupName() {\n\t\tthis.resourceAttributes.put(\"service.group\", \"spring-boot-app\");\n\t\tthis.environment.setProperty(\"spring.application.group\", \"spring-boot\");\n\t\tassertThat(getAttributes()).hasSize(3)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"service.group\", \"spring-boot-app\");\n\t}\n\n\t@Test\n\tvoid resourceAttributesShouldTakePrecedenceOverApplicationGroupNameForPopulatingServiceNamespace() {\n\t\tthis.resourceAttributes.put(\"service.namespace\", \"spring-boot-app\");\n\t\tthis.environment.setProperty(\"spring.application.group\", \"overridden\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"service.namespace\", \"spring-boot-app\");\n\t}\n\n\t@Test\n\tvoid otelResourceAttributesShouldTakePrecedenceOverSpringApplicationGroupName() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"service.namespace=spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.group\", \"spring-boot-app\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"service.namespace\", \"spring-boot\");\n\t}\n\n\t@Test\n\tvoid otelResourceAttributesShouldTakePrecedenceOverSpringApplicationGroupNameForServiceNamespace() {\n\t\tthis.environmentVariables.put(\"OTEL_RESOURCE_ATTRIBUTES\", \"service.namespace=spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.group\", \"overridden\");\n\t\tassertThat(getAttributes()).hasSize(2)\n\t\t\t.containsEntry(\"service.name\", \"unknown_service\")\n\t\t\t.containsEntry(\"service.namespace\", \"spring-boot\");\n\t}\n\n\t@Test\n\tvoid shouldUseServiceGroupForServiceNamespaceIfServiceGroupIsSet() {\n\t\tthis.environment.setProperty(\"spring.application.group\", \"alpha\");\n\t\tassertThat(getAttributes()).containsEntry(\"service.namespace\", \"alpha\");\n\t}\n\n\t@Test\n\tvoid shouldNotSetServiceNamespaceIfServiceGroupIsNotSet() {\n\t\tassertThat(getAttributes()).doesNotContainKey(\"service.namespace\");\n\t}\n\n\tprivate Map<String, String> getAttributes() {\n\t\tMap<String, String> attributes = new LinkedHashMap<>();\n\t\tnew OpenTelemetryResourceAttributes(this.environment, this.resourceAttributes, this.environmentVariables::get)\n\t\t\t.applyTo(attributes::put);\n\t\treturn attributes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport io.opentelemetry.api.OpenTelemetry;\nimport io.opentelemetry.api.common.AttributeKey;\nimport io.opentelemetry.context.propagation.ContextPropagators;\nimport io.opentelemetry.sdk.OpenTelemetrySdk;\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\nimport io.opentelemetry.sdk.metrics.SdkMeterProvider;\nimport io.opentelemetry.sdk.resources.Resource;\nimport io.opentelemetry.sdk.trace.SdkTracerProvider;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OpenTelemetrySdkAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Toshiaki Maki\n * @author Phillip Webb\n */\nclass OpenTelemetrySdkAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class));\n\n\t@Test\n\tvoid registeredInAutoConfigurationImports() {\n\t\tassertThat(ImportCandidates.load(AutoConfiguration.class, null).getCandidates())\n\t\t\t.contains(OpenTelemetrySdkAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid providesBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OpenTelemetrySdk.class);\n\t\t\tassertThat(context).hasSingleBean(Resource.class);\n\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"io.opentelemetry\", \"io.opentelemetry.api\" })\n\tvoid whenOpenTelemetryIsNotOnClasspathDoesNotProvideBeans(String packageName) {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(OpenTelemetrySdk.class);\n\t\t\tassertThat(context).doesNotHaveBean(Resource.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryLogsIsNotOnClasspathDoesNotProvideBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.opentelemetry.sdk.logs\")).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OpenTelemetrySdk.class);\n\t\t\tassertThat(context).hasSingleBean(Resource.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserSuppliedBeansDoesNotProvideBeans() {\n\t\tthis.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OpenTelemetry.class);\n\t\t\tassertThat(context).hasBean(\"customOpenTelemetry\");\n\t\t\tassertThat(context).hasSingleBean(Resource.class);\n\t\t\tassertThat(context).hasBean(\"customResource\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasApplicationNamePropertyProvidesServiceNameResourceAttribute() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.application.name=my-application\").run((context) -> {\n\t\t\tResource resource = context.getBean(Resource.class);\n\t\t\tassertThat(resource.getAttributes().asMap())\n\t\t\t\t.contains(entry(AttributeKey.stringKey(\"service.name\"), \"my-application\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasApplicationGroupPropertyProvidesServiceNamespaceResourceAttribute() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.application.group=my-group\").run((context) -> {\n\t\t\tResource resource = context.getBean(Resource.class);\n\t\t\tassertThat(resource.getAttributes().asMap()).containsEntry(AttributeKey.stringKey(\"service.namespace\"),\n\t\t\t\t\t\"my-group\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasNoApplicationGroupPropertyProvidesNoServiceGroupResourceAttribute() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tResource resource = context.getBean(Resource.class);\n\t\t\tassertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey(\"service.group\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasNoApplicationGroupPropertyProvidesNoServiceNamespaceResourceAttribute() {\n\t\tthis.contextRunner.run(((context) -> {\n\t\t\tResource resource = context.getBean(Resource.class);\n\t\t\tassertThat(resource.getAttributes().asMap()).doesNotContainKey(AttributeKey.stringKey(\"service.namespace\"));\n\t\t}));\n\t}\n\n\t@Test\n\tvoid whenHasNoApplicationNamePropertyProvidesDefaultApplicationName() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tResource resource = context.getBean(Resource.class);\n\t\t\tassertThat(resource.getAttributes().asMap())\n\t\t\t\t.contains(entry(AttributeKey.stringKey(\"service.name\"), \"unknown_service\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasResourceAttributesPropertyProvidesResourceAttributes() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.resource-attributes.region=us-west\")\n\t\t\t.run((context) -> {\n\t\t\t\tResource resource = context.getBean(Resource.class);\n\t\t\t\tassertThat(resource.getAttributes().asMap())\n\t\t\t\t\t.contains(entry(AttributeKey.stringKey(\"region\"), \"us-west\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasSdkTracerProviderBeanProvidesTracerProvider() {\n\t\tthis.contextRunner.withBean(SdkTracerProvider.class, () -> SdkTracerProvider.builder().build())\n\t\t\t.run((context) -> {\n\t\t\t\tOpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);\n\t\t\t\tassertThat(openTelemetry.getTracerProvider()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasContextPropagatorsBeanProvidesPropagators() {\n\t\tthis.contextRunner.withBean(ContextPropagators.class, ContextPropagators::noop).run((context) -> {\n\t\t\tOpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);\n\t\t\tassertThat(openTelemetry.getPropagators()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasSdkLoggerProviderBeanProvidesLogsBridge() {\n\t\tthis.contextRunner.withBean(SdkLoggerProvider.class, () -> SdkLoggerProvider.builder().build())\n\t\t\t.run((context) -> {\n\t\t\t\tOpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);\n\t\t\t\tassertThat(openTelemetry.getLogsBridge()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasSdkMeterProviderProvidesMeterProvider() {\n\t\tthis.contextRunner.withBean(SdkMeterProvider.class, () -> SdkMeterProvider.builder().build()).run((context) -> {\n\t\t\tOpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);\n\t\t\tassertThat(openTelemetry.getMeterProvider()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledStillProvidesOpenTelemetrySdk() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OpenTelemetrySdk.class);\n\t\t\tassertThat(context).hasBean(\"disabledOpenTelemetrySdk\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledStillConfiguresPropagators() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\")\n\t\t\t.withBean(ContextPropagators.class, ContextPropagators::noop)\n\t\t\t.run((context) -> {\n\t\t\t\tOpenTelemetry openTelemetry = context.getBean(OpenTelemetry.class);\n\t\t\t\tassertThat(openTelemetry.getPropagators()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledDoesNotUseTracerProvider() {\n\t\tSdkTracerProvider tracerProvider = SdkTracerProvider.builder().build();\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\")\n\t\t\t.withBean(SdkTracerProvider.class, () -> tracerProvider)\n\t\t\t.run((context) -> {\n\t\t\t\tOpenTelemetrySdk openTelemetry = context.getBean(OpenTelemetrySdk.class);\n\t\t\t\tassertThat(openTelemetry.getSdkTracerProvider()).isNotSameAs(tracerProvider);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledDoesNotUseLoggerProvider() {\n\t\tSdkLoggerProvider loggerProvider = SdkLoggerProvider.builder().build();\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\")\n\t\t\t.withBean(SdkLoggerProvider.class, () -> loggerProvider)\n\t\t\t.run((context) -> {\n\t\t\t\tOpenTelemetrySdk openTelemetry = context.getBean(OpenTelemetrySdk.class);\n\t\t\t\tassertThat(openTelemetry.getSdkLoggerProvider()).isNotSameAs(loggerProvider);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledDoesNotUseMeterProvider() {\n\t\tSdkMeterProvider meterProvider = SdkMeterProvider.builder().build();\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\")\n\t\t\t.withBean(SdkMeterProvider.class, () -> meterProvider)\n\t\t\t.run((context) -> {\n\t\t\t\tOpenTelemetrySdk openTelemetry = context.getBean(OpenTelemetrySdk.class);\n\t\t\t\tassertThat(openTelemetry.getSdkMeterProvider()).isNotSameAs(meterProvider);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserConfiguration {\n\n\t\t@Bean\n\t\tOpenTelemetry customOpenTelemetry() {\n\t\t\treturn mock(OpenTelemetry.class);\n\t\t}\n\n\t\t@Bean\n\t\tResource customResource() {\n\t\t\treturn Resource.getDefault();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/W3CHeaderParserTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link W3CHeaderParser}.\n *\n * @author Moritz Halbritter\n */\nclass W3CHeaderParserTests {\n\n\t@Test\n\tvoid shouldParseEmptyString() {\n\t\tassertThat(W3CHeaderParser.parse(\"\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid shouldParseSingleEntry() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1=value1\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"value1\"));\n\t}\n\n\t@Test\n\tvoid shouldParseMultipleEntries() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1=value1,key2=value2,key3=value3\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"value1\"), Map.entry(\"key2\", \"value2\"),\n\t\t\t\tMap.entry(\"key3\", \"value3\"));\n\t}\n\n\t@Test\n\tvoid shouldHandleWhitespaceAroundDelimiters() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1 = value1 , key2 = value2\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"value1\"), Map.entry(\"key2\", \"value2\"));\n\t}\n\n\t@Test\n\tvoid shouldPercentDecodeValues() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"serverNode=DF%2028,userId=Am%C3%A9lie\");\n\t\tassertThat(result).containsExactly(Map.entry(\"serverNode\", \"DF 28\"), Map.entry(\"userId\", \"Amélie\"));\n\t}\n\n\t@Test\n\tvoid shouldIgnoreProperties() {\n\t\tMap<String, String> result = W3CHeaderParser\n\t\t\t.parse(\"key1=value1;property1;property2,key2=value2;propKey=propVal\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"value1\"), Map.entry(\"key2\", \"value2\"));\n\t}\n\n\t@Test\n\tvoid shouldHandleEqualsSignInValue() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1=val=ue\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"val=ue\"));\n\t}\n\n\t@Test\n\tvoid shouldSkipEntriesWithoutEqualsSign() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1=value1,malformed,key2=value2\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"value1\"), Map.entry(\"key2\", \"value2\"));\n\t}\n\n\t@Test\n\tvoid shouldSkipEntriesWithEmptyKey() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"=value1,key2=value2\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key2\", \"value2\"));\n\t}\n\n\t@Test\n\tvoid shouldAllowEmptyValue() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1=\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"\"));\n\t}\n\n\t@Test\n\tvoid shouldParseSpecExample() {\n\t\tMap<String, String> result = W3CHeaderParser\n\t\t\t.parse(\"key1=value1;property1;property2, key2 = value2, key3=value3; propertyKey=propertyValue\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"value1\"), Map.entry(\"key2\", \"value2\"),\n\t\t\t\tMap.entry(\"key3\", \"value3\"));\n\t}\n\n\t@Test\n\tvoid shouldKeepLastValueForDuplicateKeys() {\n\t\tMap<String, String> result = W3CHeaderParser.parse(\"key1=first,key1=second\");\n\t\tassertThat(result).containsExactly(Map.entry(\"key1\", \"second\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/logging/OnEnabledLoggingExportConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OnEnabledLoggingExportCondition}.\n *\n * @author Moritz Halbritter\n * @author Dmytro Nosan\n */\nclass OnEnabledLoggingExportConditionTests {\n\n\tprivate static final String GLOBAL_PROPERTY_NAME = \"management.logging.export.enabled\";\n\n\tprivate static final String OTLP_PROPERTY_NAME = \"management.logging.export.otlp.enabled\";\n\n\t@Test\n\tvoid shouldMatchIfNoPropertyIsSet() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(), mockMetadata(\"\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"@ConditionalOnEnabledLoggingExport is enabled by default\");\n\t}\n\n\t@Test\n\tvoid shouldNotMatchIfGlobalPropertyIsFalse() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition\n\t\t\t.getMatchOutcome(mockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, \"false\")), mockMetadata(\"\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledLoggingExport management.logging.export.enabled is false\");\n\t}\n\n\t@Test\n\tvoid shouldMatchIfGlobalPropertyIsTrue() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, \"true\")),\n\t\t\t\tmockMetadata(\"\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledLoggingExport management.logging.export.enabled is true\");\n\t}\n\n\t@Test\n\tvoid shouldNotMatchIfExporterPropertyIsFalse() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map.of(OTLP_PROPERTY_NAME, \"false\")),\n\t\t\t\tmockMetadata(\"otlp\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledLoggingExport management.logging.export.otlp.enabled is false\");\n\t}\n\n\t@Test\n\tvoid shouldMatchIfExporterPropertyIsTrue() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(Map.of(OTLP_PROPERTY_NAME, \"true\")),\n\t\t\t\tmockMetadata(\"otlp\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledLoggingExport management.logging.export.otlp.enabled is true\");\n\t}\n\n\t@Test\n\tvoid exporterPropertyShouldOverrideGlobalPropertyIfTrue() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, \"false\", OTLP_PROPERTY_NAME, \"true\")),\n\t\t\t\tmockMetadata(\"otlp\"));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledLoggingExport management.logging.export.otlp.enabled is true\");\n\t}\n\n\t@Test\n\tvoid exporterPropertyShouldOverrideGlobalPropertyIfFalse() {\n\t\tOnEnabledLoggingExportCondition condition = new OnEnabledLoggingExportCondition();\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(Map.of(GLOBAL_PROPERTY_NAME, \"true\", OTLP_PROPERTY_NAME, \"false\")),\n\t\t\t\tmockMetadata(\"otlp\"));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t\tassertThat(outcome.getMessage())\n\t\t\t.isEqualTo(\"@ConditionalOnEnabledLoggingExport management.logging.export.otlp.enabled is false\");\n\t}\n\n\tprivate ConditionContext mockConditionContext() {\n\t\treturn mockConditionContext(Collections.emptyMap());\n\t}\n\n\tprivate ConditionContext mockConditionContext(Map<String, String> properties) {\n\t\tConditionContext context = mock(ConditionContext.class);\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tproperties.forEach(environment::setProperty);\n\t\tgiven(context.getEnvironment()).willReturn(environment);\n\t\treturn context;\n\t}\n\n\tprivate AnnotatedTypeMetadata mockMetadata(String exporter) {\n\t\tAnnotatedTypeMetadata metadata = mock(AnnotatedTypeMetadata.class);\n\t\tgiven(metadata.getAnnotationAttributes(ConditionalOnEnabledLoggingExport.class.getName()))\n\t\t\t.willReturn(Map.of(\"value\", exporter));\n\t\treturn metadata;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/logging/OpenTelemetryLoggingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.opentelemetry.context.Context;\nimport io.opentelemetry.sdk.common.CompletableResultCode;\nimport io.opentelemetry.sdk.logs.LogLimits;\nimport io.opentelemetry.sdk.logs.LogRecordProcessor;\nimport io.opentelemetry.sdk.logs.ReadWriteLogRecord;\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\nimport io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;\nimport io.opentelemetry.sdk.logs.data.LogRecordData;\nimport io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;\nimport io.opentelemetry.sdk.logs.export.LogRecordExporter;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OpenTelemetryLoggingAutoConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass OpenTelemetryLoggingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\tOpenTelemetryLoggingAutoConfiguration.class));\n\n\t@Test\n\tvoid registeredInAutoConfigurationImports() {\n\t\tassertThat(ImportCandidates.load(AutoConfiguration.class, null).getCandidates())\n\t\t\t.contains(OpenTelemetryLoggingAutoConfiguration.class.getName());\n\t}\n\n\t@Test\n\tvoid providesBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context).hasSingleBean(SdkLoggerProvider.class);\n\t\t\tassertThat(context).hasSingleBean(LogLimits.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryIsDisabledDoesNotProvideBeans() {\n\t\tthis.contextRunner.withPropertyValues(\"management.opentelemetry.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context).doesNotHaveBean(SdkLoggerProvider.class);\n\t\t\tassertThat(context).doesNotHaveBean(LogLimits.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryLogsIsNotOnClasspathDoesNotProvideBeans() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"io.opentelemetry.sdk.logs\")).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context).doesNotHaveBean(SdkLoggerProvider.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserSuppliedBeansDoesNotProvideBeans() {\n\t\tthis.contextRunner.withUserConfiguration(UserConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context).hasBean(\"customBatchLogRecordProcessor\").hasSingleBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context).hasSingleBean(LogRecordProcessor.class);\n\t\t\tassertThat(context).hasBean(\"customSdkLoggerProvider\").hasSingleBean(SdkLoggerProvider.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasMultipleLogRecordExportersProvidesBatchLogRecordProcessor() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleLogRecordExportersConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context.getBeansOfType(LogRecordExporter.class)).hasSize(2);\n\t\t\tassertThat(context).hasBean(\"customLogRecordExporter1\");\n\t\t\tassertThat(context).hasBean(\"customLogRecordExporter2\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasMultipleLogRecordProcessorsStillProvidesBatchLogRecordProcessor() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleLogRecordProcessorsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(BatchLogRecordProcessor.class);\n\t\t\tassertThat(context).hasSingleBean(SdkLoggerProvider.class);\n\t\t\tassertThat(context.getBeansOfType(LogRecordProcessor.class)).hasSize(3);\n\t\t\tassertThat(context).hasBean(\"openTelemetryBatchLogRecordProcessor\");\n\t\t\tassertThat(context).hasBean(\"customLogRecordProcessor1\");\n\t\t\tassertThat(context).hasBean(\"customLogRecordProcessor2\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasMultipleSdkLoggerProviderBuilderCustomizersCallsCustomizeMethod() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleSdkLoggerProviderBuilderCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SdkLoggerProvider.class);\n\t\t\t\tassertThat(context.getBeansOfType(SdkLoggerProviderBuilderCustomizer.class)).hasSize(2);\n\t\t\t\tassertThat(context).hasBean(\"customSdkLoggerProviderBuilderCustomizer1\");\n\t\t\t\tassertThat(context).hasBean(\"customSdkLoggerProviderBuilderCustomizer2\");\n\t\t\t\tassertThat(context\n\t\t\t\t\t.getBean(\"customSdkLoggerProviderBuilderCustomizer1\", NoopSdkLoggerProviderBuilderCustomizer.class)\n\t\t\t\t\t.called()).isEqualTo(1);\n\t\t\t\tassertThat(context\n\t\t\t\t\t.getBean(\"customSdkLoggerProviderBuilderCustomizer2\", NoopSdkLoggerProviderBuilderCustomizer.class)\n\t\t\t\t\t.called()).isEqualTo(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid logLimitsShouldBeConfiguredWithCustomProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.limits.max-attribute-value-length=256\",\n\t\t\t\t\t\"management.opentelemetry.logging.limits.max-attributes=64\")\n\t\t\t.run((context) -> {\n\t\t\t\tLogLimits logLimits = context.getBean(LogLimits.class);\n\t\t\t\tassertThat(logLimits.getMaxAttributeValueLength()).isEqualTo(256);\n\t\t\t\tassertThat(logLimits.getMaxNumberOfAttributes()).isEqualTo(64);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomLogLimitsBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomLogLimitsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(LogLimits.class);\n\t\t\tassertThat(context).hasBean(\"customLogLimits\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureBatchLogRecordProcessorWithProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.timeout=45s\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.max-batch-size=256\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.max-queue-size=4096\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.schedule-delay=15s\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(BatchLogRecordProcessor.class);\n\t\t\t\tBatchLogRecordProcessor processor = context.getBean(BatchLogRecordProcessor.class);\n\t\t\t\tassertThat(processor).extracting(\"worker\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"exporterTimeoutNanos\", Duration.ofSeconds(45).toNanos())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"maxExportBatchSize\", 256)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"scheduleDelayNanos\", Duration.ofSeconds(15).toNanos())\n\t\t\t\t\t.extracting(\"queue\")\n\t\t\t\t\t.isInstanceOfSatisfying(ArrayBlockingQueue.class,\n\t\t\t\t\t\t\t(queue) -> assertThat(queue.remainingCapacity()).isEqualTo(4096));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserConfiguration {\n\n\t\t@Bean\n\t\tBatchLogRecordProcessor customBatchLogRecordProcessor() {\n\t\t\treturn BatchLogRecordProcessor.builder(new NoopLogRecordExporter()).build();\n\t\t}\n\n\t\t@Bean\n\t\tSdkLoggerProvider customSdkLoggerProvider() {\n\t\t\treturn SdkLoggerProvider.builder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleLogRecordExportersConfiguration {\n\n\t\t@Bean\n\t\tLogRecordExporter customLogRecordExporter1() {\n\t\t\treturn new NoopLogRecordExporter();\n\t\t}\n\n\t\t@Bean\n\t\tLogRecordExporter customLogRecordExporter2() {\n\t\t\treturn new NoopLogRecordExporter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleLogRecordProcessorsConfiguration {\n\n\t\t@Bean\n\t\tLogRecordProcessor customLogRecordProcessor1() {\n\t\t\treturn new NoopLogRecordProcessor();\n\t\t}\n\n\t\t@Bean\n\t\tLogRecordProcessor customLogRecordProcessor2() {\n\t\t\treturn new NoopLogRecordProcessor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleSdkLoggerProviderBuilderCustomizersConfiguration {\n\n\t\t@Bean\n\t\tSdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer1() {\n\t\t\treturn new NoopSdkLoggerProviderBuilderCustomizer();\n\t\t}\n\n\t\t@Bean\n\t\tSdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer2() {\n\t\t\treturn new NoopSdkLoggerProviderBuilderCustomizer();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomLogLimitsConfiguration {\n\n\t\t@Bean\n\t\tLogLimits customLogLimits() {\n\t\t\treturn LogLimits.builder().setMaxNumberOfAttributes(99).build();\n\t\t}\n\n\t}\n\n\tstatic class NoopLogRecordExporter implements LogRecordExporter {\n\n\t\t@Override\n\t\tpublic CompletableResultCode export(Collection<LogRecordData> logs) {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\t@Override\n\t\tpublic CompletableResultCode flush() {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t\t@Override\n\t\tpublic CompletableResultCode shutdown() {\n\t\t\treturn CompletableResultCode.ofSuccess();\n\t\t}\n\n\t}\n\n\tstatic class NoopLogRecordProcessor implements LogRecordProcessor {\n\n\t\t@Override\n\t\tpublic void onEmit(Context context, ReadWriteLogRecord logRecord) {\n\t\t}\n\n\t}\n\n\tstatic class NoopSdkLoggerProviderBuilderCustomizer implements SdkLoggerProviderBuilderCustomizer {\n\n\t\tfinal AtomicInteger called = new AtomicInteger(0);\n\n\t\t@Override\n\t\tpublic void customize(SdkLoggerProviderBuilder builder) {\n\t\t\tthis.called.incrementAndGet();\n\t\t}\n\n\t\tint called() {\n\t\t\treturn this.called.get();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/logging/OpenTelemetryLoggingPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging;\n\nimport io.opentelemetry.sdk.logs.LogLimits;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OpenTelemetryLoggingProperties}.\n *\n * @author Moritz Halbritter\n */\nclass OpenTelemetryLoggingPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tOpenTelemetryLoggingProperties.Limits limits = new OpenTelemetryLoggingProperties.Limits();\n\t\tLogLimits defaults = LogLimits.getDefault();\n\t\tassertThat(limits.getMaxAttributeValueLength()).isEqualTo(defaults.getMaxAttributeValueLength());\n\t\tassertThat(limits.getMaxAttributes()).isEqualTo(defaults.getMaxNumberOfAttributes());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpLoggingAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Instant;\nimport java.util.concurrent.TimeUnit;\n\nimport io.opentelemetry.api.logs.Severity;\nimport io.opentelemetry.sdk.logs.SdkLoggerProvider;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport okio.Buffer;\nimport okio.GzipSource;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OtlpLoggingAutoConfiguration}.\n *\n * @author Toshiaki Maki\n */\nclass OtlpLoggingAutoConfigurationIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.application.name=otlp-logs-test\",\n\t\t\t\t\"management.opentelemetry.logging.export.otlp.headers.Authorization=Bearer my-token\")\n\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\tOpenTelemetryLoggingAutoConfiguration.class, OtlpLoggingAutoConfiguration.class));\n\n\tprivate final MockWebServer mockWebServer = new MockWebServer();\n\n\t@BeforeEach\n\tvoid setUp() throws IOException {\n\t\tthis.mockWebServer.start();\n\t}\n\n\t@AfterEach\n\tvoid tearDown() throws IOException {\n\t\tthis.mockWebServer.close();\n\t}\n\n\t@Test\n\tvoid httpLogRecordExporterShouldUseProtobufAndNoCompressionByDefault() {\n\t\tthis.mockWebServer.enqueue(new MockResponse());\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:%d/v1/logs\"\n\t\t\t\t.formatted(this.mockWebServer.getPort()))\n\t\t\t.run((context) -> {\n\t\t\t\tlogMessage(context);\n\t\t\t\tRecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);\n\t\t\t\tassertThat(request).isNotNull();\n\t\t\t\tassertThat(request.getRequestLine()).contains(\"/v1/logs\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/x-protobuf\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Encoding\")).isNull();\n\t\t\t\tassertThat(request.getBodySize()).isPositive();\n\t\t\t\ttry (Buffer body = request.getBody()) {\n\t\t\t\t\tassertLogMessage(body);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid httpLogRecordExporterCanBeConfiguredToUseGzipCompression() {\n\t\tthis.mockWebServer.enqueue(new MockResponse());\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:%d/v1/logs\"\n\t\t\t\t\t\t.formatted(this.mockWebServer.getPort()),\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.compression=gzip\")\n\t\t\t.run((context) -> {\n\t\t\t\tlogMessage(context);\n\t\t\t\tRecordedRequest request = this.mockWebServer.takeRequest(10, TimeUnit.SECONDS);\n\t\t\t\tassertThat(request).isNotNull();\n\t\t\t\tassertThat(request.getRequestLine()).contains(\"/v1/logs\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/x-protobuf\");\n\t\t\t\tassertThat(request.getHeader(\"Content-Encoding\")).isEqualTo(\"gzip\");\n\t\t\t\tassertThat(request.getBodySize()).isPositive();\n\t\t\t\ttry (Buffer uncompressed = new Buffer(); Buffer body = request.getBody()) {\n\t\t\t\t\tuncompressed.writeAll(new GzipSource(body));\n\t\t\t\t\tassertLogMessage(uncompressed);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate static void logMessage(ApplicationContext context) {\n\t\tSdkLoggerProvider loggerProvider = context.getBean(SdkLoggerProvider.class);\n\t\tloggerProvider.get(\"test\")\n\t\t\t.logRecordBuilder()\n\t\t\t.setSeverity(Severity.INFO)\n\t\t\t.setSeverityText(\"INFO\")\n\t\t\t.setBody(\"Hello\")\n\t\t\t.setTimestamp(Instant.now())\n\t\t\t.emit();\n\t}\n\n\tprivate static void assertLogMessage(Buffer body) {\n\t\tString string = body.readString(StandardCharsets.UTF_8);\n\t\tassertThat(string).contains(\"otlp-logs-test\");\n\t\tassertThat(string).contains(\"test\");\n\t\tassertThat(string).contains(\"INFO\");\n\t\tassertThat(string).contains(\"Hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/logging/otlp/OtlpLoggingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.opentelemetry.autoconfigure.logging.otlp;\n\nimport java.time.Duration;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Supplier;\n\nimport javax.net.ssl.X509TrustManager;\n\nimport io.opentelemetry.api.metrics.MeterProvider;\nimport io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;\nimport io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;\nimport io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;\nimport io.opentelemetry.sdk.logs.export.LogRecordExporter;\nimport okhttp3.HttpUrl;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.context.annotation.ImportCandidates;\nimport org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.OpenTelemetryLoggingAutoConfiguration;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.SdkLoggerProviderBuilderCustomizer;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingConfigurations.ConnectionDetails.PropertiesOtlpLoggingConnectionDetails;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OtlpLoggingAutoConfiguration}.\n *\n * @author Toshiaki Maki\n * @author Moritz Halbritter\n */\nclass OtlpLoggingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner;\n\n\tOtlpLoggingAutoConfigurationTests() {\n\t\tthis.contextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,\n\t\t\t\t\tOpenTelemetryLoggingAutoConfiguration.class, OtlpLoggingAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid registeredInAutoConfigurationImports() {\n\t\tassertThat(ImportCandidates.load(AutoConfiguration.class, null).getCandidates())\n\t\t\t.contains(OtlpLoggingAutoConfiguration.class.getName());\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"io.opentelemetry.sdk.logs\", \"io.opentelemetry.api\",\n\t\t\t\"io.opentelemetry.exporter.otlp.http.logs\" })\n\tvoid whenOpenTelemetryIsNotOnClasspathDoesNotProvideBeans(String packageName) {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(packageName)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(OtlpLoggingConnectionDetails.class);\n\t\t\tassertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasEndpointPropertyProvidesBeans() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);\n\t\t\t\tOtlpLoggingConnectionDetails connectionDetails = context.getBean(OtlpLoggingConnectionDetails.class);\n\t\t\t\tassertThat(connectionDetails.getUrl(Transport.HTTP)).isEqualTo(\"http://localhost:4318/v1/logs\");\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(context).hasSingleBean(LogRecordExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customConnectionDetailsReplacePropertyBasedConnectionDetails() {\n\t\tOtlpLoggingConnectionDetails details = mock(OtlpLoggingConnectionDetails.class);\n\t\tgiven(details.getUrl(Transport.HTTP)).willReturn(\"http://localhost:4318/v1/logs\");\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4319/v1/logs\")\n\t\t\t.withBean(\"customOtlpLoggingConnectionDetails\", OtlpLoggingConnectionDetails.class, () -> details)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);\n\t\t\t\tassertThat(context).hasBean(\"customOtlpLoggingConnectionDetails\");\n\t\t\t\tassertThat(context.getBean(OtlpLoggingConnectionDetails.class).getUrl(Transport.HTTP))\n\t\t\t\t\t.isEqualTo(\"http://localhost:4318/v1/logs\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasNoEndpointPropertyDoesNotProvideBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(OtlpLoggingConnectionDetails.class);\n\t\t\tassertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenOpenTelemetryLoggingExportEnabledPropertyIsFalseProvidesExpectedBeans() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.logging.export.otlp.enabled=false\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(LogRecordExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenLoggingExportEnabledPropertyIsFalseNoProvideExpectedBeans() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.logging.export.enabled=false\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(LogRecordExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasCustomHttpExporterDoesNotProvideExporterBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpExporterConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"customOtlpHttpLogRecordExporter\")\n\t\t\t\t.hasSingleBean(LogRecordExporter.class));\n\t}\n\n\t@Test\n\tvoid whenHasCustomGrpcExporterDoesNotProvideExporterBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomGrpcExporterConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"customOtlpGrpcLogRecordExporter\")\n\t\t\t\t.hasSingleBean(LogRecordExporter.class));\n\t}\n\n\t@Test\n\tvoid whenHasCustomLoggingConnectionDetailsDoesNotProvideExporterBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomOtlpLoggingConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpLoggingConnectionDetails.class)\n\t\t\t\t\t.doesNotHaveBean(PropertiesOtlpLoggingConnectionDetails.class);\n\t\t\t\tOtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(otlpHttpLogRecordExporter).extracting(\"delegate.httpSender.url\")\n\t\t\t\t\t.isEqualTo(HttpUrl.get(\"https://otel.example.com/v1/logs\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasNoTransportPropertySetUsesHttpExporter() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(context).hasSingleBean(LogRecordExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasTransportPropertySetToHttpUsesHttpExporter() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.transport=http\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(context).hasSingleBean(LogRecordExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasTransportPropertySetToGrpcUsesGrpcExporter() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t\tassertThat(context).hasSingleBean(LogRecordExporter.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(OtlpHttpLogRecordExporter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasMeterProviderBeanAddsItToHttpExporter() {\n\t\tthis.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\")\n\t\t\t.run((context) -> {\n\t\t\t\tOtlpHttpLogRecordExporter otlpHttpLogRecordExporter = context.getBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(otlpHttpLogRecordExporter.toBuilder())\n\t\t\t\t\t.extracting(\"delegate.meterProviderSupplier\", InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t\t.satisfies((meterProviderSupplier) -> assertThat(meterProviderSupplier.get())\n\t\t\t\t\t\t.isSameAs(MeterProviderConfiguration.meterProvider));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasMeterProviderBeanAddsItToGrpcExporter() {\n\t\tthis.contextRunner.withUserConfiguration(MeterProviderConfiguration.class)\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> {\n\t\t\t\tOtlpGrpcLogRecordExporter otlpGrpcLogRecordExporter = context.getBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t\tassertThat(otlpGrpcLogRecordExporter.toBuilder())\n\t\t\t\t\t.extracting(\"delegate.meterProviderSupplier\", InstanceOfAssertFactories.type(Supplier.class))\n\t\t\t\t\t.satisfies((meterProviderSupplier) -> assertThat(meterProviderSupplier.get())\n\t\t\t\t\t\t.isSameAs(MeterProviderConfiguration.meterProvider));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeHttpTransportWithOtlpHttpLogRecordExporterBuilderCustomizer() {\n\t\tDuration connectTimeout = Duration.ofMinutes(20);\n\t\tDuration timeout = Duration.ofMinutes(10);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"httpCustomizer1\", OtlpHttpLogRecordExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setConnectTimeout(connectTimeout))\n\t\t\t.withBean(\"httpCustomizer2\", OtlpHttpLogRecordExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setTimeout(timeout))\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class)\n\t\t\t\t\t.hasSingleBean(LogRecordExporter.class);\n\t\t\t\tOtlpHttpLogRecordExporter exporter = context.getBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"connectTimeoutMillis\", (int) connectTimeout.toMillis())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"callTimeoutMillis\", (int) timeout.toMillis());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeGrpcTransportWhenEnabledWithOtlpGrpcLogRecordExporterBuilderCustomizer() {\n\t\tDuration timeout = Duration.ofMinutes(10);\n\t\tDuration connectTimeout = Duration.ofMinutes(20);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"grpcCustomizer1\", OtlpGrpcLogRecordExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setConnectTimeout(connectTimeout))\n\t\t\t.withBean(\"grpcCustomizer2\", OtlpGrpcLogRecordExporterBuilderCustomizer.class,\n\t\t\t\t\t() -> (builder) -> builder.setTimeout(timeout))\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=http://localhost:4318/v1/logs\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.transport=grpc\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpGrpcLogRecordExporter.class)\n\t\t\t\t\t.hasSingleBean(LogRecordExporter.class);\n\t\t\t\tOtlpGrpcLogRecordExporter exporter = context.getBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"connectTimeoutMillis\", (int) connectTimeout.toMillis())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"callTimeoutMillis\", (int) timeout.toMillis());\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasSslBundleConfiguresHttpExporter() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=https://localhost:4318/v1/logs\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.ssl.bundle=mybundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.mybundle.truststore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tOtlpHttpLogRecordExporter exporter = context.getBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.sslSocketFactoryOrNull\").isNotNull();\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.x509TrustManager\")\n\t\t\t\t\t.isInstanceOf(X509TrustManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenHasSslBundleConfiguresGrpcExporter() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SslAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.opentelemetry.logging.export.otlp.endpoint=https://localhost:4318/v1/logs\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.transport=grpc\",\n\t\t\t\t\t\"management.opentelemetry.logging.export.otlp.ssl.bundle=mybundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.mybundle.truststore.location=classpath:test.jks\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t\tOtlpGrpcLogRecordExporter exporter = context.getBean(OtlpGrpcLogRecordExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client.sslSocketFactoryOrNull\").isNotNull();\n\t\t\t\tassertThat(exporter).extracting(\"delegate.grpcSender.client.x509TrustManager\")\n\t\t\t\t\t.isInstanceOf(X509TrustManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenCustomConnectionDetailsProvidesSslBundleConfiguresHttpExporter() {\n\t\tSslBundle sslBundle = SslBundle.systemDefault();\n\t\tOtlpLoggingConnectionDetails connectionDetails = mock(OtlpLoggingConnectionDetails.class);\n\t\tgiven(connectionDetails.getUrl(Transport.HTTP)).willReturn(\"https://localhost:4318/v1/logs\");\n\t\tgiven(connectionDetails.getSslBundle()).willReturn(sslBundle);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customOtlpLoggingConnectionDetails\", OtlpLoggingConnectionDetails.class, () -> connectionDetails)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tOtlpHttpLogRecordExporter exporter = context.getBean(OtlpHttpLogRecordExporter.class);\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.sslSocketFactoryOrNull\").isNotNull();\n\t\t\t\tassertThat(exporter).extracting(\"delegate.httpSender.client.x509TrustManager\")\n\t\t\t\t\t.isInstanceOf(X509TrustManager.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class MultipleSdkLoggerProviderBuilderCustomizersConfig {\n\n\t\t@Bean\n\t\tpublic SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer1() {\n\t\t\treturn new NoopSdkLoggerProviderBuilderCustomizer();\n\t\t}\n\n\t\t@Bean\n\t\tpublic SdkLoggerProviderBuilderCustomizer customSdkLoggerProviderBuilderCustomizer2() {\n\t\t\treturn new NoopSdkLoggerProviderBuilderCustomizer();\n\t\t}\n\n\t}\n\n\tstatic class NoopSdkLoggerProviderBuilderCustomizer implements SdkLoggerProviderBuilderCustomizer {\n\n\t\tfinal AtomicInteger called = new AtomicInteger(0);\n\n\t\t@Override\n\t\tpublic void customize(SdkLoggerProviderBuilder builder) {\n\t\t\tthis.called.incrementAndGet();\n\t\t}\n\n\t\tint called() {\n\t\t\treturn this.called.get();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class MeterProviderConfiguration {\n\n\t\tstatic final MeterProvider meterProvider = (instrumentationScopeName) -> null;\n\n\t\t@Bean\n\t\tMeterProvider meterProvider() {\n\t\t\treturn meterProvider;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomHttpExporterConfiguration {\n\n\t\t@Bean\n\t\tOtlpHttpLogRecordExporter customOtlpHttpLogRecordExporter() {\n\t\t\treturn OtlpHttpLogRecordExporter.builder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomGrpcExporterConfiguration {\n\n\t\t@Bean\n\t\tOtlpGrpcLogRecordExporter customOtlpGrpcLogRecordExporter() {\n\t\t\treturn OtlpGrpcLogRecordExporter.builder().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomOtlpLoggingConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tOtlpLoggingConnectionDetails customOtlpLoggingConnectionDetails() {\n\t\t\treturn (transport) -> \"https://otel.example.com/v1/logs\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Persistence\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-tx\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.zaxxer:HikariCP\")\n\ttestImplementation(\"jakarta.persistence:jakarta.persistence-api\")\n\ttestImplementation(\"org.hibernate.orm:hibernate-core\")\n\ttestImplementation(\"org.hsqldb:hsqldb\")\n\ttestImplementation(\"org.springframework:spring-jdbc\")\n\ttestImplementation(\"org.springframework:spring-orm\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/java/org/springframework/boot/persistence/autoconfigure/EntityScan.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Configures the base packages used by auto-configuration when scanning for entity\n * classes. Refer to the documentation of the data technology you are using for more\n * details.\n * <p>\n * One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias\n * {@link #value()} may be specified to define specific packages to scan. If specific\n * packages are not defined scanning will occur from the package of the class with this\n * annotation.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see EntityScanPackages\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(EntityScanPackages.Registrar.class)\npublic @interface EntityScan {\n\n\t/**\n\t * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation\n\t * declarations e.g.: {@code @EntityScan(\"org.my.pkg\")} instead of\n\t * {@code @EntityScan(basePackages=\"org.my.pkg\")}.\n\t * @return the base packages to scan\n\t */\n\t@AliasFor(\"basePackages\")\n\tString[] value() default {};\n\n\t/**\n\t * Base packages to scan for entities. {@link #value()} is an alias for (and mutually\n\t * exclusive with) this attribute.\n\t * <p>\n\t * Use {@link #basePackageClasses()} for a type-safe alternative to String-based\n\t * package names.\n\t * @return the base packages to scan\n\t */\n\t@AliasFor(\"value\")\n\tString[] basePackages() default {};\n\n\t/**\n\t * Type-safe alternative to {@link #basePackages()} for specifying the packages to\n\t * scan for entities. The package of each class specified will be scanned.\n\t * <p>\n\t * Consider creating a special no-op marker class or interface in each package that\n\t * serves no purpose other than being referenced by this attribute.\n\t * @return classes from the base packages to scan\n\t */\n\tClass<?>[] basePackageClasses() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/java/org/springframework/boot/persistence/autoconfigure/EntityScanPackages.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Class for storing {@link EntityScan @EntityScan} specified packages for reference later\n * (e.g. by JPA auto-configuration).\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see EntityScan\n * @see EntityScanner\n */\npublic class EntityScanPackages {\n\n\tprivate static final String BEAN = EntityScanPackages.class.getName();\n\n\tprivate static final EntityScanPackages NONE = new EntityScanPackages();\n\n\tprivate final List<String> packageNames;\n\n\tEntityScanPackages(String... packageNames) {\n\t\tList<String> packages = new ArrayList<>();\n\t\tfor (String name : packageNames) {\n\t\t\tif (StringUtils.hasText(name)) {\n\t\t\t\tpackages.add(name);\n\t\t\t}\n\t\t}\n\t\tthis.packageNames = Collections.unmodifiableList(packages);\n\t}\n\n\t/**\n\t * Return the package names specified from all {@link EntityScan @EntityScan}\n\t * annotations.\n\t * @return the entity scan package names\n\t */\n\tpublic List<String> getPackageNames() {\n\t\treturn this.packageNames;\n\t}\n\n\t/**\n\t * Return the {@link EntityScanPackages} for the given bean factory.\n\t * @param beanFactory the source bean factory\n\t * @return the {@link EntityScanPackages} for the bean factory (never {@code null})\n\t */\n\tpublic static EntityScanPackages get(BeanFactory beanFactory) {\n\t\t// Currently we only store a single base package, but we return a list to\n\t\t// allow this to change in the future if needed\n\t\ttry {\n\t\t\treturn beanFactory.getBean(BEAN, EntityScanPackages.class);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn NONE;\n\t\t}\n\t}\n\n\t/**\n\t * Register the specified entity scan packages with the system.\n\t * @param registry the source registry\n\t * @param packageNames the package names to register\n\t */\n\tpublic static void register(BeanDefinitionRegistry registry, String... packageNames) {\n\t\tAssert.notNull(registry, \"'registry' must not be null\");\n\t\tAssert.notNull(packageNames, \"'packageNames' must not be null\");\n\t\tregister(registry, Arrays.asList(packageNames));\n\t}\n\n\t/**\n\t * Register the specified entity scan packages with the system.\n\t * @param registry the source registry\n\t * @param packageNames the package names to register\n\t */\n\tpublic static void register(BeanDefinitionRegistry registry, Collection<String> packageNames) {\n\t\tAssert.notNull(registry, \"'registry' must not be null\");\n\t\tAssert.notNull(packageNames, \"'packageNames' must not be null\");\n\t\tif (registry.containsBeanDefinition(BEAN)) {\n\t\t\tEntityScanPackagesBeanDefinition beanDefinition = (EntityScanPackagesBeanDefinition) registry\n\t\t\t\t.getBeanDefinition(BEAN);\n\t\t\tbeanDefinition.addPackageNames(packageNames);\n\t\t}\n\t\telse {\n\t\t\tregistry.registerBeanDefinition(BEAN, new EntityScanPackagesBeanDefinition(packageNames));\n\t\t}\n\t}\n\n\t/**\n\t * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing\n\t * configuration.\n\t */\n\tstatic class Registrar implements ImportBeanDefinitionRegistrar {\n\n\t\tprivate final Environment environment;\n\n\t\tRegistrar(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {\n\t\t\tregister(registry, getPackagesToScan(metadata));\n\t\t}\n\n\t\tprivate Set<String> getPackagesToScan(AnnotationMetadata metadata) {\n\t\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t\t.fromMap(metadata.getAnnotationAttributes(EntityScan.class.getName()));\n\t\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\t\tSet<String> packagesToScan = new LinkedHashSet<>();\n\t\t\tfor (String basePackage : attributes.getStringArray(\"basePackages\")) {\n\t\t\t\tString[] tokenized = StringUtils.tokenizeToStringArray(\n\t\t\t\t\t\tthis.environment.resolvePlaceholders(basePackage),\n\t\t\t\t\t\tConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);\n\t\t\t\tCollections.addAll(packagesToScan, tokenized);\n\t\t\t}\n\t\t\tfor (Class<?> basePackageClass : attributes.getClassArray(\"basePackageClasses\")) {\n\t\t\t\tpackagesToScan.add(this.environment.resolvePlaceholders(ClassUtils.getPackageName(basePackageClass)));\n\t\t\t}\n\t\t\tif (packagesToScan.isEmpty()) {\n\t\t\t\tString packageName = ClassUtils.getPackageName(metadata.getClassName());\n\t\t\t\tAssert.state(StringUtils.hasLength(packageName), \"@EntityScan cannot be used with the default package\");\n\t\t\t\treturn Collections.singleton(packageName);\n\t\t\t}\n\t\t\treturn packagesToScan;\n\t\t}\n\n\t}\n\n\tstatic class EntityScanPackagesBeanDefinition extends RootBeanDefinition {\n\n\t\tprivate final Set<String> packageNames = new LinkedHashSet<>();\n\n\t\tEntityScanPackagesBeanDefinition(Collection<String> packageNames) {\n\t\t\tsetBeanClass(EntityScanPackages.class);\n\t\t\tsetRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\t\t\taddPackageNames(packageNames);\n\t\t}\n\n\t\tprivate void addPackageNames(Collection<String> additionalPackageNames) {\n\t\t\tthis.packageNames.addAll(additionalPackageNames);\n\t\t\tgetConstructorArgumentValues().addIndexedArgumentValue(0, StringUtils.toStringArray(this.packageNames));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/java/org/springframework/boot/persistence/autoconfigure/EntityScanner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport java.lang.annotation.Annotation;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurationPackages;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * An entity scanner that searches the classpath from an {@link EntityScan @EntityScan}\n * specified packages.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class EntityScanner {\n\n\tprivate final ApplicationContext context;\n\n\t/**\n\t * Create a new {@link EntityScanner} instance.\n\t * @param context the source application context\n\t */\n\tpublic EntityScanner(ApplicationContext context) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * Scan for entities with the specified annotations.\n\t * @param annotationTypes the annotation types used on the entities\n\t * @return a set of entity classes\n\t * @throws ClassNotFoundException if an entity class cannot be loaded\n\t */\n\t@SafeVarargs\n\tpublic final Set<Class<?>> scan(Class<? extends Annotation>... annotationTypes) throws ClassNotFoundException {\n\t\tList<String> packages = getPackages();\n\t\tif (packages.isEmpty()) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t\tClassPathScanningCandidateComponentProvider scanner = createClassPathScanningCandidateComponentProvider(\n\t\t\t\tthis.context);\n\t\tfor (Class<? extends Annotation> annotationType : annotationTypes) {\n\t\t\tscanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));\n\t\t}\n\t\tSet<Class<?>> entitySet = new HashSet<>();\n\t\tfor (String basePackage : packages) {\n\t\t\tif (StringUtils.hasText(basePackage)) {\n\t\t\t\tfor (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {\n\t\t\t\t\tString beanClassName = candidate.getBeanClassName();\n\t\t\t\t\tAssert.state(beanClassName != null, \"'beanClassName' must not be null\");\n\t\t\t\t\tentitySet.add(ClassUtils.forName(beanClassName, this.context.getClassLoader()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn entitySet;\n\t}\n\n\t/**\n\t * Create a {@link ClassPathScanningCandidateComponentProvider} to scan entities based\n\t * on the specified {@link ApplicationContext}.\n\t * @param context the {@link ApplicationContext} to use\n\t * @return a {@link ClassPathScanningCandidateComponentProvider} suitable to scan\n\t * entities\n\t */\n\tprotected ClassPathScanningCandidateComponentProvider createClassPathScanningCandidateComponentProvider(\n\t\t\tApplicationContext context) {\n\t\tClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);\n\t\tscanner.setEnvironment(context.getEnvironment());\n\t\tscanner.setResourceLoader(context);\n\t\treturn scanner;\n\t}\n\n\tprivate List<String> getPackages() {\n\t\tList<String> packages = EntityScanPackages.get(this.context).getPackageNames();\n\t\tif (packages.isEmpty() && AutoConfigurationPackages.has(this.context)) {\n\t\t\tpackages = AutoConfigurationPackages.get(this.context);\n\t\t}\n\t\treturn packages;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/java/org/springframework/boot/persistence/autoconfigure/PersistenceExceptionTranslationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring's persistence exception\n * translation.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(PersistenceExceptionTranslationPostProcessor.class)\npublic final class PersistenceExceptionTranslationAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBooleanProperty(name = \"spring.persistence.exceptiontranslation.enabled\", matchIfMissing = true)\n\tstatic PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(\n\t\t\tEnvironment environment) {\n\t\tPersistenceExceptionTranslationPostProcessor postProcessor = new PersistenceExceptionTranslationPostProcessor();\n\t\tboolean proxyTargetClass = environment.getProperty(\"spring.aop.proxy-target-class\", Boolean.class,\n\t\t\t\tBoolean.TRUE);\n\t\tpostProcessor.setProxyTargetClass(proxyTargetClass);\n\t\treturn postProcessor;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/java/org/springframework/boot/persistence/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General purpose domain annotations and classes.\n */\n@NullMarked\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.dao.exceptiontranslation.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"replacement\": \"spring.persistence.exceptiontranslation.enabled\",\n        \"level\": \"error\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.persistence.exceptiontranslation.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable the PersistenceExceptionTranslationPostProcessor.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.persistence.autoconfigure.PersistenceExceptionTranslationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/EntityScanPackagesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.Collections;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotationConfigurationException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link EntityScanPackages}.\n *\n * @author Phillip Webb\n */\nclass EntityScanPackagesTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getWhenNoneRegisteredShouldReturnNone() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.refresh();\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages).isNotNull();\n\t\tassertThat(packages.getPackageNames()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getShouldReturnRegisterPackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tEntityScanPackages.register(this.context, \"a\", \"b\");\n\t\tEntityScanPackages.register(this.context, \"b\", \"c\");\n\t\tthis.context.refresh();\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(\"a\", \"b\", \"c\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerFromArrayWhenRegistryIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> EntityScanPackages.register(null))\n\t\t\t.withMessageContaining(\"'registry' must not be null\");\n\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerFromArrayWhenPackageNamesIsNullShouldThrowException() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> EntityScanPackages.register(this.context, (String[]) null))\n\t\t\t.withMessageContaining(\"'packageNames' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerFromCollectionWhenRegistryIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> EntityScanPackages.register(null, Collections.emptyList()))\n\t\t\t.withMessageContaining(\"'registry' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid registerFromCollectionWhenPackageNamesIsNullShouldThrowException() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> EntityScanPackages.register(this.context, (Collection<String>) null))\n\t\t\t.withMessageContaining(\"'packageNames' must not be null\");\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenHasValueAttributeShouldSetupPackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext(EntityScanValueConfig.class);\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(\"a\");\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenHasValueAttributeShouldSetupPackagesAsm() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.registerBeanDefinition(\"entityScanValueConfig\",\n\t\t\t\tnew RootBeanDefinition(EntityScanValueConfig.class.getName()));\n\t\tthis.context.refresh();\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(\"a\");\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenHasBasePackagesAttributeShouldSetupPackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext(EntityScanBasePackagesConfig.class);\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(\"b\");\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenHasValueAndBasePackagesAttributeShouldThrow() {\n\t\tassertThatExceptionOfType(AnnotationConfigurationException.class)\n\t\t\t.isThrownBy(() -> this.context = new AnnotationConfigApplicationContext(\n\t\t\t\t\tEntityScanValueAndBasePackagesConfig.class));\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenHasBasePackageClassesAttributeShouldSetupPackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext(EntityScanBasePackageClassesConfig.class);\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(getClass().getPackage().getName());\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenNoAttributesShouldSetupPackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext(EntityScanNoAttributesConfig.class);\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(getClass().getPackage().getName());\n\t}\n\n\t@Test\n\tvoid entityScanAnnotationWhenLoadingFromMultipleConfigsShouldCombinePackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext(EntityScanValueConfig.class,\n\t\t\t\tEntityScanBasePackagesConfig.class);\n\t\tEntityScanPackages packages = EntityScanPackages.get(this.context);\n\t\tassertThat(packages.getPackageNames()).containsExactly(\"a\", \"b\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(\"a\")\n\tstatic class EntityScanValueConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(basePackages = \"b\")\n\tstatic class EntityScanBasePackagesConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(value = \"a\", basePackages = \"b\")\n\tstatic class EntityScanValueAndBasePackagesConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(basePackageClasses = EntityScanPackagesTests.class)\n\tstatic class EntityScanBasePackageClassesConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan\n\tstatic class EntityScanNoAttributesConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/EntityScannerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport jakarta.persistence.Embeddable;\nimport jakarta.persistence.Entity;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.persistence.autoconfigure.scan.a.EmbeddableA;\nimport org.springframework.boot.persistence.autoconfigure.scan.a.EntityA;\nimport org.springframework.boot.persistence.autoconfigure.scan.b.EmbeddableB;\nimport org.springframework.boot.persistence.autoconfigure.scan.b.EntityB;\nimport org.springframework.boot.persistence.autoconfigure.scan.c.EmbeddableC;\nimport org.springframework.boot.persistence.autoconfigure.scan.c.EntityC;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EntityScanner}.\n *\n * @author Phillip Webb\n */\nclass EntityScannerTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenContextIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new EntityScanner(null))\n\t\t\t.withMessageContaining(\"'context' must not be null\");\n\t}\n\n\t@Test\n\tvoid scanShouldScanFromSinglePackage() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScanConfig.class);\n\t\tEntityScanner scanner = new EntityScanner(context);\n\t\tSet<Class<?>> scanned = scanner.scan(Entity.class);\n\t\tassertThat(scanned).containsOnly(EntityA.class, EntityB.class, EntityC.class);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid scanShouldScanFromResolvedPlaceholderPackage() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"com.example.entity-package=org.springframework.boot.persistence.autoconfigure.scan\")\n\t\t\t.applyTo(context);\n\t\tcontext.register(ScanPlaceholderConfig.class);\n\t\tcontext.refresh();\n\t\tEntityScanner scanner = new EntityScanner(context);\n\t\tSet<Class<?>> scanned = scanner.scan(Entity.class);\n\t\tassertThat(scanned).containsOnly(EntityA.class, EntityB.class, EntityC.class);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid scanShouldScanFromMultiplePackages() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScanAConfig.class,\n\t\t\t\tScanBConfig.class);\n\t\tEntityScanner scanner = new EntityScanner(context);\n\t\tSet<Class<?>> scanned = scanner.scan(Entity.class);\n\t\tassertThat(scanned).containsOnly(EntityA.class, EntityB.class);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid scanShouldFilterOnAnnotation() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScanConfig.class);\n\t\tEntityScanner scanner = new EntityScanner(context);\n\t\tassertThat(scanner.scan(Entity.class)).containsOnly(EntityA.class, EntityB.class, EntityC.class);\n\t\tassertThat(scanner.scan(Embeddable.class)).containsOnly(EmbeddableA.class, EmbeddableB.class,\n\t\t\t\tEmbeddableC.class);\n\t\tassertThat(scanner.scan(Entity.class, Embeddable.class)).containsOnly(EntityA.class, EntityB.class,\n\t\t\t\tEntityC.class, EmbeddableA.class, EmbeddableB.class, EmbeddableC.class);\n\t\tcontext.close();\n\t}\n\n\t@Test\n\tvoid scanShouldUseCustomCandidateComponentProvider() throws ClassNotFoundException {\n\t\tClassPathScanningCandidateComponentProvider candidateComponentProvider = mock(\n\t\t\t\tClassPathScanningCandidateComponentProvider.class);\n\t\tgiven(candidateComponentProvider\n\t\t\t.findCandidateComponents(\"org.springframework.boot.persistence.autoconfigure.scan\"))\n\t\t\t.willReturn(Collections.emptySet());\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScanConfig.class);\n\t\tTestEntityScanner scanner = new TestEntityScanner(context, candidateComponentProvider);\n\t\tscanner.scan(Entity.class);\n\t\tthen(candidateComponentProvider).should()\n\t\t\t.addIncludeFilter(\n\t\t\t\t\tassertArg((typeFilter) -> assertThat(typeFilter).isInstanceOfSatisfying(AnnotationTypeFilter.class,\n\t\t\t\t\t\t\t(filter) -> assertThat(filter.getAnnotationType()).isEqualTo(Entity.class))));\n\t\tthen(candidateComponentProvider).should()\n\t\t\t.findCandidateComponents(\"org.springframework.boot.persistence.autoconfigure.scan\");\n\t\tthen(candidateComponentProvider).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid scanShouldScanCommaSeparatedPackagesInPlaceholderPackage() throws Exception {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues\n\t\t\t.of(\"com.example.entity-package=org.springframework.boot.persistence.autoconfigure.scan.a,org.springframework.boot.persistence.autoconfigure.scan.b\")\n\t\t\t.applyTo(context);\n\t\tcontext.register(ScanPlaceholderConfig.class);\n\t\tcontext.refresh();\n\t\tEntityScanner scanner = new EntityScanner(context);\n\t\tSet<Class<?>> scanned = scanner.scan(Entity.class);\n\t\tassertThat(scanned).containsOnly(EntityA.class, EntityB.class);\n\t\tcontext.close();\n\t}\n\n\tprivate static class TestEntityScanner extends EntityScanner {\n\n\t\tprivate final ClassPathScanningCandidateComponentProvider candidateComponentProvider;\n\n\t\tTestEntityScanner(ApplicationContext context,\n\t\t\t\tClassPathScanningCandidateComponentProvider candidateComponentProvider) {\n\t\t\tsuper(context);\n\t\t\tthis.candidateComponentProvider = candidateComponentProvider;\n\t\t}\n\n\t\t@Override\n\t\tprotected ClassPathScanningCandidateComponentProvider createClassPathScanningCandidateComponentProvider(\n\t\t\t\tApplicationContext context) {\n\t\t\treturn this.candidateComponentProvider;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(\"org.springframework.boot.persistence.autoconfigure.scan\")\n\tstatic class ScanConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(basePackageClasses = EntityA.class)\n\tstatic class ScanAConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(basePackageClasses = EntityB.class)\n\tstatic class ScanBConfig {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EntityScan(\"${com.example.entity-package}\")\n\tstatic class ScanPlaceholderConfig {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/PersistenceExceptionTranslationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure;\n\nimport java.io.Serializable;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.EntityManagerFactory;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.dao.InvalidDataAccessApiUsageException;\nimport org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;\nimport org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;\nimport org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;\nimport org.springframework.stereotype.Repository;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link PersistenceExceptionTranslationAutoConfiguration}\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass PersistenceExceptionTranslationAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid exceptionTranslationPostProcessorUsesCglibByDefault() {\n\t\tthis.context = new AnnotationConfigApplicationContext(PersistenceExceptionTranslationAutoConfiguration.class);\n\t\tMap<String, PersistenceExceptionTranslationPostProcessor> beans = this.context\n\t\t\t.getBeansOfType(PersistenceExceptionTranslationPostProcessor.class);\n\t\tassertThat(beans).hasSize(1);\n\t\tassertThat(beans.values().iterator().next().isProxyTargetClass()).isTrue();\n\t}\n\n\t@Test\n\tvoid exceptionTranslationPostProcessorCanBeConfiguredToUseJdkProxy() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.aop.proxy-target-class=false\").applyTo(this.context);\n\t\tthis.context.register(PersistenceExceptionTranslationAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tMap<String, PersistenceExceptionTranslationPostProcessor> beans = this.context\n\t\t\t.getBeansOfType(PersistenceExceptionTranslationPostProcessor.class);\n\t\tassertThat(beans).hasSize(1);\n\t\tassertThat(beans.values().iterator().next().isProxyTargetClass()).isFalse();\n\t}\n\n\t@Test\n\tvoid exceptionTranslationPostProcessorCanBeDisabled() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.persistence.exceptiontranslation.enabled=false\").applyTo(this.context);\n\t\tthis.context.register(PersistenceExceptionTranslationAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tMap<String, PersistenceExceptionTranslationPostProcessor> beans = this.context\n\t\t\t.getBeansOfType(PersistenceExceptionTranslationPostProcessor.class);\n\t\tassertThat(beans).isEmpty();\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid persistOfNullThrowsIllegalArgumentExceptionWithoutExceptionTranslation() {\n\t\tthis.context = new AnnotationConfigApplicationContext(JpaConfiguration.class, TestConfiguration.class);\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(TestRepository.class).doSomething();\n\t\t});\n\t}\n\n\t@Test\n\t@WithMetaInfPersistenceXmlResource\n\tvoid persistOfNullThrowsInvalidDataAccessApiUsageExceptionWithExceptionTranslation() {\n\t\tthis.context = new AnnotationConfigApplicationContext(JpaConfiguration.class, TestConfiguration.class,\n\t\t\t\tPersistenceExceptionTranslationAutoConfiguration.class);\n\t\tassertThatExceptionOfType(InvalidDataAccessApiUsageException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(TestRepository.class).doSomething();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestRepository testRepository(EntityManagerFactory entityManagerFactory) {\n\t\t\treturn new TestRepository(entityManagerFactory.createEntityManager());\n\t\t}\n\n\t}\n\n\t@Repository\n\tstatic class TestRepository {\n\n\t\tprivate final EntityManager entityManager;\n\n\t\tTestRepository(EntityManager entityManager) {\n\t\t\tthis.entityManager = entityManager;\n\t\t}\n\n\t\tvoid doSomething() {\n\t\t\tthis.entityManager.persist(null);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JpaConfiguration {\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\t\tdataSource.setDriverClassName(\"org.hsqldb.jdbc.JDBCDriver\");\n\t\t\tdataSource.setJdbcUrl(\"jdbc:hsqldb:mem:tx\");\n\t\t\tdataSource.setUsername(\"sa\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tLocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource) {\n\t\t\tLocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();\n\t\t\tlocalContainerEntityManagerFactoryBean.setDataSource(dataSource);\n\t\t\tlocalContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());\n\t\t\tlocalContainerEntityManagerFactoryBean.setJpaPropertyMap(configureJpaProperties());\n\t\t\treturn localContainerEntityManagerFactoryBean;\n\t\t}\n\n\t\tprivate static Map<String, ?> configureJpaProperties() {\n\t\t\tMap<String, Object> properties = new HashMap<>();\n\t\t\tproperties.put(\"configured\", \"manually\");\n\t\t\tproperties.put(\"hibernate.transaction.jta.platform\", NoJtaPlatform.INSTANCE);\n\t\t\treturn properties;\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"META-INF/persistence.xml\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t\t\t<persistence version=\"2.0\" xmlns=\"http://java.sun.com/xml/ns/persistence\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/persistence https://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">\n\t\t\t\t\t\t<persistence-unit name=\"manually-configured\">\n\t\t\t\t\t\t\t<class>org.springframework.boot.transaction.autoconfigure.PersistenceExceptionTranslationAutoConfigurationTests$City</class>\n\t\t\t\t\t\t\t<exclude-unlisted-classes>true</exclude-unlisted-classes>\n\t\t\t\t\t\t</persistence-unit>\n\t\t\t\t\t</persistence>\n\t\t\t\t\t\"\"\")\n\t@interface WithMetaInfPersistenceXmlResource {\n\n\t}\n\n\t@Entity\n\tpublic static class City implements Serializable {\n\n\t\tprivate static final long serialVersionUID = 1L;\n\n\t\t@Id\n\t\t@GeneratedValue\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate Long id;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String name;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String state;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String country;\n\n\t\t@Column(nullable = false)\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String map;\n\n\t\tprotected City() {\n\t\t}\n\n\t\tCity(String name, String state, String country, String map) {\n\t\t\tthis.name = name;\n\t\t\tthis.state = state;\n\t\t\tthis.country = country;\n\t\t\tthis.map = map;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getState() {\n\t\t\treturn this.state;\n\t\t}\n\n\t\tpublic String getCountry() {\n\t\t\treturn this.country;\n\t\t}\n\n\t\tpublic String getMap() {\n\t\t\treturn this.map;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/a/EmbeddableA.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure.scan.a;\n\nimport jakarta.persistence.Embeddable;\n\n@Embeddable\npublic class EmbeddableA {\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/a/EntityA.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure.scan.a;\n\nimport jakarta.persistence.Entity;\n\n@Entity\npublic class EntityA {\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/a/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.persistence.autoconfigure.scan.a;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/b/EmbeddableB.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure.scan.b;\n\nimport jakarta.persistence.Embeddable;\n\n@Embeddable\npublic class EmbeddableB {\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/b/EntityB.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure.scan.b;\n\nimport jakarta.persistence.Entity;\n\n@Entity\npublic class EntityB {\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/b/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.persistence.autoconfigure.scan.b;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/c/EmbeddableC.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure.scan.c;\n\nimport jakarta.persistence.Embeddable;\n\n@Embeddable\npublic class EmbeddableC {\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/c/EntityC.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.persistence.autoconfigure.scan.c;\n\nimport jakarta.persistence.Entity;\n\n@Entity\npublic class EntityC {\n\n}\n"
  },
  {
    "path": "module/spring-boot-persistence/src/test/java/org/springframework/boot/persistence/autoconfigure/scan/c/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.persistence.autoconfigure.scan.c;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-pulsar/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Pulsar\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework.pulsar:spring-pulsar\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"org.testcontainers:testcontainers-pulsar\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-pulsar\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.github.ben-manes.caffeine:caffeine\")\n\ttestImplementation(\"org.springframework.pulsar:spring-pulsar-cache-provider-caffeine\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/java/org/springframework/boot/pulsar/autoconfigure/PulsarAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.pulsar.PulsarContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.pulsar.annotation.PulsarListener;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.stereotype.Service;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link PulsarAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\nclass PulsarAutoConfigurationIntegrationTests {\n\n\t@Container\n\tstatic final PulsarContainer pulsar = TestImage.container(PulsarContainer.class);\n\n\tprivate static final CountDownLatch listenLatch = new CountDownLatch(1);\n\n\tprivate static final String TOPIC = \"pacit-hello-topic\";\n\n\t@DynamicPropertySource\n\tstatic void pulsarProperties(DynamicPropertyRegistry registry) {\n\t\tregistry.add(\"spring.pulsar.client.service-url\", pulsar::getPulsarBrokerUrl);\n\t\tregistry.add(\"spring.pulsar.admin.service-url\", pulsar::getHttpServiceUrl);\n\t}\n\n\t@Test\n\tvoid appStartsWithAutoConfiguredSpringPulsarComponents(\n\t\t\t@Autowired(required = false) PulsarTemplate<String> pulsarTemplate) {\n\t\tassertThat(pulsarTemplate).isNotNull();\n\t}\n\n\t@Test\n\tvoid sendAndReceive(@Autowired TestService testService) throws InterruptedException {\n\t\tassertThat(testService.sayHello()).startsWith(\"Hello World -> \");\n\t\tassertThat(listenLatch.await(5, TimeUnit.SECONDS)).isTrue();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(PulsarAutoConfiguration.class)\n\t@Import(TestService.class)\n\tstatic class TestConfiguration {\n\n\t\t@PulsarListener(subscriptionName = TOPIC + \"-sub\", topics = TOPIC)\n\t\tvoid listen(String ignored) {\n\t\t\tlistenLatch.countDown();\n\t\t}\n\n\t}\n\n\t@Service\n\tstatic class TestService {\n\n\t\tprivate final PulsarTemplate<String> pulsarTemplate;\n\n\t\tTestService(PulsarTemplate<String> pulsarTemplate) {\n\t\t\tthis.pulsarTemplate = pulsarTemplate;\n\t\t}\n\n\t\tString sayHello() {\n\t\t\treturn \"Hello World -> \" + this.pulsarTemplate.send(TOPIC, \"hello\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/java/org/springframework/boot/pulsar/docker/compose/PulsarDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for {@link PulsarDockerComposeConnectionDetailsFactory}.\n *\n * @author Chris Bono\n */\nclass PulsarDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"pulsar-compose.yaml\", image = TestImage.PULSAR)\n\tvoid runCreatesConnectionDetails(PulsarConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails).isNotNull();\n\t\tassertThat(connectionDetails.getBrokerUrl()).matches(\"^pulsar://\\\\S+:\\\\d+\");\n\t\tassertThat(connectionDetails.getAdminUrl()).matches(\"^http://\\\\S+:\\\\d+\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/java/org/springframework/boot/pulsar/testcontainers/DeprecatedPulsarContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.PulsarContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.pulsar.annotation.PulsarListener;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DeprecatedPulsarContainerConnectionDetailsFactory}.\n *\n * @author Chris Bono\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link PulsarContainerConnectionDetailsFactory}.\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@TestPropertySource(properties = { \"spring.pulsar.consumer.subscription.initial-position=earliest\" })\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedPulsarContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@SuppressWarnings(\"unused\")\n\tstatic final PulsarContainer pulsar = TestImage.container(PulsarContainer.class);\n\n\t@Autowired\n\tprivate PulsarTemplate<String> pulsarTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToPulsarContainer() {\n\t\tthis.pulsarTemplate.send(\"test-topic\", \"test-data\");\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"test-data\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(PulsarAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@PulsarListener(topics = \"test-topic\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/java/org/springframework/boot/pulsar/testcontainers/PulsarContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.testcontainers;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.pulsar.PulsarContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.pulsar.annotation.PulsarListener;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PulsarContainerConnectionDetailsFactory}.\n *\n * @author Chris Bono\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@TestPropertySource(properties = { \"spring.pulsar.consumer.subscription.initial-position=earliest\" })\nclass PulsarContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@SuppressWarnings(\"unused\")\n\tstatic final PulsarContainer pulsar = TestImage.container(PulsarContainer.class);\n\n\t@Autowired\n\tprivate PulsarTemplate<String> pulsarTemplate;\n\n\t@Autowired\n\tprivate TestListener listener;\n\n\t@Test\n\tvoid connectionCanBeMadeToPulsarContainer() {\n\t\tthis.pulsarTemplate.send(\"test-topic\", \"test-data\");\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30))\n\t\t\t.untilAsserted(() -> assertThat(this.listener.messages).containsExactly(\"test-data\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(PulsarAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tTestListener testListener() {\n\t\t\treturn new TestListener();\n\t\t}\n\n\t}\n\n\tstatic class TestListener {\n\n\t\tprivate final List<String> messages = new ArrayList<>();\n\n\t\t@PulsarListener(topics = \"test-topic\")\n\t\tvoid processMessage(String message) {\n\t\t\tthis.messages.add(message);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/resources/org/springframework/boot/pulsar/docker/compose/pulsar-compose.yaml",
    "content": "services:\n  pulsar:\n    image: '{imageName}'\n    ports:\n      - '8080'\n      - '6650'\n    command: bin/pulsar standalone\n    healthcheck:\n      test: curl http://127.0.0.1:8080/admin/v2/namespaces/public/default\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/dockerTest/resources/spring.properties",
    "content": "spring.test.context.cache.maxSize=1"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/DeadLetterPolicyMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport org.apache.pulsar.client.api.DeadLetterPolicy;\nimport org.apache.pulsar.client.api.DeadLetterPolicy.DeadLetterPolicyBuilder;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.util.Assert;\n\n/**\n * Helper class used to map {@link PulsarProperties.Consumer.DeadLetterPolicy dead letter\n * policy properties}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nfinal class DeadLetterPolicyMapper {\n\n\tprivate DeadLetterPolicyMapper() {\n\t}\n\n\tstatic DeadLetterPolicy map(PulsarProperties.Consumer.DeadLetterPolicy policy) {\n\t\tAssert.state(policy.getMaxRedeliverCount() > 0,\n\t\t\t\t\"Pulsar DeadLetterPolicy must have a positive 'max-redelivery-count' property value\");\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tDeadLetterPolicyBuilder builder = DeadLetterPolicy.builder();\n\t\tmap.from(policy::getMaxRedeliverCount).to(builder::maxRedeliverCount);\n\t\tmap.from(policy::getRetryLetterTopic).to(builder::retryLetterTopic);\n\t\tmap.from(policy::getDeadLetterTopic).to(builder::deadLetterTopic);\n\t\tmap.from(policy::getInitialSubscriptionName).to(builder::initialSubscriptionName);\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PropertiesPulsarConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\n/**\n * Adapts {@link PulsarProperties} to {@link PulsarConnectionDetails}.\n *\n * @author Chris Bono\n */\nclass PropertiesPulsarConnectionDetails implements PulsarConnectionDetails {\n\n\tprivate final PulsarProperties pulsarProperties;\n\n\tPropertiesPulsarConnectionDetails(PulsarProperties pulsarProperties) {\n\t\tthis.pulsarProperties = pulsarProperties;\n\t}\n\n\t@Override\n\tpublic String getBrokerUrl() {\n\t\treturn this.pulsarProperties.getClient().getServiceUrl();\n\t}\n\n\t@Override\n\tpublic String getAdminUrl() {\n\t\treturn this.pulsarProperties.getAdmin().getServiceUrl();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PulsarAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.pulsar.client.admin.PulsarAdminBuilder;\nimport org.apache.pulsar.client.api.ClientBuilder;\nimport org.apache.pulsar.client.api.ConsumerBuilder;\nimport org.apache.pulsar.client.api.ProducerBuilder;\nimport org.apache.pulsar.client.api.PulsarClient;\nimport org.apache.pulsar.client.api.ReaderBuilder;\nimport org.apache.pulsar.client.api.Schema;\nimport org.apache.pulsar.client.api.interceptor.ProducerInterceptor;\nimport org.apache.pulsar.common.naming.TopicDomain;\nimport org.apache.pulsar.common.schema.SchemaType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Defaults.SchemaInfo;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Defaults.TypeMapping;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.pulsar.annotation.EnablePulsar;\nimport org.springframework.pulsar.config.ConcurrentPulsarListenerContainerFactory;\nimport org.springframework.pulsar.config.DefaultPulsarReaderContainerFactory;\nimport org.springframework.pulsar.config.PulsarAnnotationSupportBeanNames;\nimport org.springframework.pulsar.core.CachingPulsarProducerFactory;\nimport org.springframework.pulsar.core.ConsumerBuilderCustomizer;\nimport org.springframework.pulsar.core.DefaultPulsarClientFactory;\nimport org.springframework.pulsar.core.DefaultPulsarConsumerFactory;\nimport org.springframework.pulsar.core.DefaultPulsarProducerFactory;\nimport org.springframework.pulsar.core.DefaultPulsarReaderFactory;\nimport org.springframework.pulsar.core.DefaultSchemaResolver;\nimport org.springframework.pulsar.core.DefaultTopicResolver;\nimport org.springframework.pulsar.core.ProducerBuilderCustomizer;\nimport org.springframework.pulsar.core.PulsarAdminBuilderCustomizer;\nimport org.springframework.pulsar.core.PulsarAdministration;\nimport org.springframework.pulsar.core.PulsarClientBuilderCustomizer;\nimport org.springframework.pulsar.core.PulsarClientFactory;\nimport org.springframework.pulsar.core.PulsarConsumerFactory;\nimport org.springframework.pulsar.core.PulsarProducerFactory;\nimport org.springframework.pulsar.core.PulsarReaderFactory;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.pulsar.core.PulsarTopicBuilder;\nimport org.springframework.pulsar.core.ReaderBuilderCustomizer;\nimport org.springframework.pulsar.core.SchemaResolver;\nimport org.springframework.pulsar.core.SchemaResolver.SchemaResolverCustomizer;\nimport org.springframework.pulsar.core.TopicResolver;\nimport org.springframework.pulsar.function.PulsarFunction;\nimport org.springframework.pulsar.function.PulsarFunctionAdministration;\nimport org.springframework.pulsar.function.PulsarSink;\nimport org.springframework.pulsar.function.PulsarSource;\nimport org.springframework.pulsar.listener.PulsarContainerProperties;\nimport org.springframework.pulsar.reader.PulsarReaderContainerProperties;\nimport org.springframework.pulsar.transaction.PulsarAwareTransactionManager;\nimport org.springframework.pulsar.transaction.PulsarTransactionManager;\nimport org.springframework.util.Assert;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Apache Pulsar.\n *\n * @author Chris Bono\n * @author Soby Chacko\n * @author Alexander Preuß\n * @author Phillip Webb\n * @author Jonas Geiregat\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ PulsarClient.class, PulsarTemplate.class })\n@EnableConfigurationProperties(PulsarProperties.class)\npublic final class PulsarAutoConfiguration {\n\n\tprivate final PulsarProperties properties;\n\n\tprivate final PulsarPropertiesMapper propertiesMapper;\n\n\tPulsarAutoConfiguration(PulsarProperties properties) {\n\t\tthis.properties = properties;\n\t\tthis.propertiesMapper = new PulsarPropertiesMapper(properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarConnectionDetails.class)\n\tPropertiesPulsarConnectionDetails pulsarConnectionDetails() {\n\t\treturn new PropertiesPulsarConnectionDetails(this.properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarClientFactory.class)\n\tDefaultPulsarClientFactory pulsarClientFactory(PulsarConnectionDetails connectionDetails,\n\t\t\tObjectProvider<PulsarClientBuilderCustomizer> customizersProvider) {\n\t\tList<PulsarClientBuilderCustomizer> allCustomizers = new ArrayList<>();\n\t\tallCustomizers.add((builder) -> this.propertiesMapper.customizeClientBuilder(builder, connectionDetails));\n\t\tallCustomizers.addAll(customizersProvider.orderedStream().toList());\n\t\tDefaultPulsarClientFactory clientFactory = new DefaultPulsarClientFactory(\n\t\t\t\t(clientBuilder) -> applyClientBuilderCustomizers(allCustomizers, clientBuilder));\n\t\treturn clientFactory;\n\t}\n\n\tprivate void applyClientBuilderCustomizers(List<PulsarClientBuilderCustomizer> customizers,\n\t\t\tClientBuilder clientBuilder) {\n\t\tcustomizers.forEach((customizer) -> customizer.customize(clientBuilder));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPulsarClient pulsarClient(PulsarClientFactory clientFactory) {\n\t\treturn clientFactory.createClient();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPulsarAdministration pulsarAdministration(PulsarConnectionDetails connectionDetails,\n\t\t\tObjectProvider<PulsarAdminBuilderCustomizer> pulsarAdminBuilderCustomizers) {\n\t\tList<PulsarAdminBuilderCustomizer> allCustomizers = new ArrayList<>();\n\t\tallCustomizers.add((builder) -> this.propertiesMapper.customizeAdminBuilder(builder, connectionDetails));\n\t\tallCustomizers.addAll(pulsarAdminBuilderCustomizers.orderedStream().toList());\n\t\treturn new PulsarAdministration((adminBuilder) -> applyAdminBuilderCustomizers(allCustomizers, adminBuilder));\n\t}\n\n\tprivate void applyAdminBuilderCustomizers(List<PulsarAdminBuilderCustomizer> customizers,\n\t\t\tPulsarAdminBuilder adminBuilder) {\n\t\tcustomizers.forEach((customizer) -> customizer.customize(adminBuilder));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(SchemaResolver.class)\n\tDefaultSchemaResolver pulsarSchemaResolver(ObjectProvider<SchemaResolverCustomizer<?>> schemaResolverCustomizers) {\n\t\tDefaultSchemaResolver schemaResolver = new DefaultSchemaResolver();\n\t\taddCustomSchemaMappings(schemaResolver, this.properties.getDefaults().getTypeMappings());\n\t\tapplySchemaResolverCustomizers(schemaResolverCustomizers.orderedStream().toList(), schemaResolver);\n\t\treturn schemaResolver;\n\t}\n\n\tprivate void addCustomSchemaMappings(DefaultSchemaResolver schemaResolver,\n\t\t\t@Nullable List<TypeMapping> typeMappings) {\n\t\tif (typeMappings != null) {\n\t\t\ttypeMappings.forEach((typeMapping) -> addCustomSchemaMapping(schemaResolver, typeMapping));\n\t\t}\n\t}\n\n\tprivate void addCustomSchemaMapping(DefaultSchemaResolver schemaResolver, TypeMapping typeMapping) {\n\t\tSchemaInfo schemaInfo = typeMapping.schemaInfo();\n\t\tif (schemaInfo != null) {\n\t\t\tClass<?> messageType = typeMapping.messageType();\n\t\t\tSchemaType schemaType = schemaInfo.schemaType();\n\t\t\tClass<?> messageKeyType = schemaInfo.messageKeyType();\n\t\t\tSchema<?> schema = getSchema(schemaResolver, schemaType, messageType, messageKeyType);\n\t\t\tschemaResolver.addCustomSchemaMapping(typeMapping.messageType(), schema);\n\t\t}\n\t}\n\n\tprivate Schema<Object> getSchema(DefaultSchemaResolver schemaResolver, SchemaType schemaType, Class<?> messageType,\n\t\t\t@Nullable Class<?> messageKeyType) {\n\t\tSchema<Object> schema = schemaResolver.resolveSchema(schemaType, messageType, messageKeyType).orElseThrow();\n\t\tAssert.state(schema != null, \"'schema' must not be null\");\n\t\treturn schema;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void applySchemaResolverCustomizers(List<SchemaResolverCustomizer<?>> customizers,\n\t\t\tDefaultSchemaResolver schemaResolver) {\n\t\tLambdaSafe.callbacks(SchemaResolverCustomizer.class, customizers, schemaResolver)\n\t\t\t.invoke((customizer) -> customizer.customize(schemaResolver));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(TopicResolver.class)\n\tDefaultTopicResolver pulsarTopicResolver() {\n\t\tDefaultTopicResolver topicResolver = new DefaultTopicResolver();\n\t\tList<TypeMapping> typeMappings = this.properties.getDefaults().getTypeMappings();\n\t\tif (typeMappings != null) {\n\t\t\ttypeMappings.forEach((typeMapping) -> addCustomTopicMapping(topicResolver, typeMapping));\n\t\t}\n\t\treturn topicResolver;\n\t}\n\n\tprivate void addCustomTopicMapping(DefaultTopicResolver topicResolver, TypeMapping typeMapping) {\n\t\tString topicName = typeMapping.topicName();\n\t\tif (topicName != null) {\n\t\t\ttopicResolver.addCustomTopicMapping(typeMapping.messageType(), topicName);\n\t\t}\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBooleanProperty(name = \"spring.pulsar.function.enabled\", matchIfMissing = true)\n\tPulsarFunctionAdministration pulsarFunctionAdministration(PulsarAdministration pulsarAdministration,\n\t\t\tObjectProvider<PulsarFunction> pulsarFunctions, ObjectProvider<PulsarSink> pulsarSinks,\n\t\t\tObjectProvider<PulsarSource> pulsarSources) {\n\t\tPulsarProperties.Function properties = this.properties.getFunction();\n\t\treturn new PulsarFunctionAdministration(pulsarAdministration, pulsarFunctions, pulsarSinks, pulsarSources,\n\t\t\t\tproperties.isFailFast(), properties.isPropagateFailures(), properties.isPropagateStopFailures());\n\t}\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBooleanProperty(name = \"spring.pulsar.defaults.topic.enabled\", matchIfMissing = true)\n\tPulsarTopicBuilder pulsarTopicBuilder() {\n\t\treturn new PulsarTopicBuilder(TopicDomain.persistent, this.properties.getDefaults().getTopic().getTenant(),\n\t\t\t\tthis.properties.getDefaults().getTopic().getNamespace());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPulsarContainerFactoryCustomizers pulsarContainerFactoryCustomizers(\n\t\t\tObjectProvider<PulsarContainerFactoryCustomizer<?>> customizers) {\n\t\treturn new PulsarContainerFactoryCustomizers(customizers.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarProducerFactory.class)\n\t@ConditionalOnBooleanProperty(name = \"spring.pulsar.producer.cache.enabled\", havingValue = false)\n\tDefaultPulsarProducerFactory<?> pulsarProducerFactory(PulsarClient pulsarClient, TopicResolver topicResolver,\n\t\t\tObjectProvider<ProducerBuilderCustomizer<?>> customizersProvider,\n\t\t\tObjectProvider<PulsarTopicBuilder> topicBuilderProvider) {\n\t\tList<ProducerBuilderCustomizer<Object>> lambdaSafeCustomizers = lambdaSafeProducerBuilderCustomizers(\n\t\t\t\tcustomizersProvider);\n\t\tDefaultPulsarProducerFactory<?> producerFactory = new DefaultPulsarProducerFactory<>(pulsarClient,\n\t\t\t\tthis.properties.getProducer().getTopicName(), lambdaSafeCustomizers, topicResolver);\n\t\ttopicBuilderProvider.ifAvailable(producerFactory::setTopicBuilder);\n\t\treturn producerFactory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarProducerFactory.class)\n\t@ConditionalOnBooleanProperty(name = \"spring.pulsar.producer.cache.enabled\", matchIfMissing = true)\n\tCachingPulsarProducerFactory<?> cachingPulsarProducerFactory(PulsarClient pulsarClient, TopicResolver topicResolver,\n\t\t\tObjectProvider<ProducerBuilderCustomizer<?>> customizersProvider,\n\t\t\tObjectProvider<PulsarTopicBuilder> topicBuilderProvider) {\n\t\tPulsarProperties.Producer.Cache cacheProperties = this.properties.getProducer().getCache();\n\t\tList<ProducerBuilderCustomizer<Object>> lambdaSafeCustomizers = lambdaSafeProducerBuilderCustomizers(\n\t\t\t\tcustomizersProvider);\n\t\tCachingPulsarProducerFactory<?> producerFactory = new CachingPulsarProducerFactory<>(pulsarClient,\n\t\t\t\tthis.properties.getProducer().getTopicName(), lambdaSafeCustomizers, topicResolver,\n\t\t\t\tcacheProperties.getExpireAfterAccess(), cacheProperties.getMaximumSize(),\n\t\t\t\tcacheProperties.getInitialCapacity());\n\t\ttopicBuilderProvider.ifAvailable(producerFactory::setTopicBuilder);\n\t\treturn producerFactory;\n\t}\n\n\tprivate List<ProducerBuilderCustomizer<Object>> lambdaSafeProducerBuilderCustomizers(\n\t\t\tObjectProvider<ProducerBuilderCustomizer<?>> customizersProvider) {\n\t\tList<ProducerBuilderCustomizer<?>> customizers = new ArrayList<>();\n\t\tcustomizers.add(this.propertiesMapper::customizeProducerBuilder);\n\t\tcustomizers.addAll(customizersProvider.orderedStream().toList());\n\t\treturn List.of((builder) -> applyProducerBuilderCustomizers(customizers, builder));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void applyProducerBuilderCustomizers(List<ProducerBuilderCustomizer<?>> customizers,\n\t\t\tProducerBuilder<?> builder) {\n\t\tLambdaSafe.callbacks(ProducerBuilderCustomizer.class, customizers, builder)\n\t\t\t.invoke((customizer) -> customizer.customize(builder));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tPulsarTemplate<?> pulsarTemplate(PulsarProducerFactory<?> pulsarProducerFactory,\n\t\t\tObjectProvider<ProducerInterceptor> producerInterceptors, SchemaResolver schemaResolver,\n\t\t\tTopicResolver topicResolver) {\n\t\tPulsarTemplate<?> template = new PulsarTemplate<>(pulsarProducerFactory,\n\t\t\t\tproducerInterceptors.orderedStream().toList(), schemaResolver, topicResolver,\n\t\t\t\tthis.properties.getTemplate().isObservationsEnabled());\n\t\tthis.propertiesMapper.customizeTemplate(template);\n\t\treturn template;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarConsumerFactory.class)\n\tDefaultPulsarConsumerFactory<?> pulsarConsumerFactory(PulsarClient pulsarClient,\n\t\t\tObjectProvider<ConsumerBuilderCustomizer<?>> customizersProvider,\n\t\t\tObjectProvider<PulsarTopicBuilder> topicBuilderProvider) {\n\t\tList<ConsumerBuilderCustomizer<?>> customizers = new ArrayList<>();\n\t\tcustomizers.add(this.propertiesMapper::customizeConsumerBuilder);\n\t\tcustomizers.addAll(customizersProvider.orderedStream().toList());\n\t\tList<ConsumerBuilderCustomizer<Object>> lambdaSafeCustomizers = List\n\t\t\t.of((builder) -> applyConsumerBuilderCustomizers(customizers, builder));\n\t\tDefaultPulsarConsumerFactory<?> consumerFactory = new DefaultPulsarConsumerFactory<>(pulsarClient,\n\t\t\t\tlambdaSafeCustomizers);\n\t\ttopicBuilderProvider.ifAvailable(consumerFactory::setTopicBuilder);\n\t\treturn consumerFactory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarAwareTransactionManager.class)\n\t@ConditionalOnBooleanProperty(\"spring.pulsar.transaction.enabled\")\n\tPulsarTransactionManager pulsarTransactionManager(PulsarClient pulsarClient) {\n\t\treturn new PulsarTransactionManager(pulsarClient);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void applyConsumerBuilderCustomizers(List<ConsumerBuilderCustomizer<?>> customizers,\n\t\t\tConsumerBuilder<?> builder) {\n\t\tLambdaSafe.callbacks(ConsumerBuilderCustomizer.class, customizers, builder)\n\t\t\t.invoke((customizer) -> customizer.customize(builder));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"pulsarListenerContainerFactory\")\n\tConcurrentPulsarListenerContainerFactory<?> pulsarListenerContainerFactory(\n\t\t\tPulsarConsumerFactory<Object> pulsarConsumerFactory, SchemaResolver schemaResolver,\n\t\t\tTopicResolver topicResolver, ObjectProvider<PulsarAwareTransactionManager> pulsarTransactionManager,\n\t\t\tEnvironment environment, PulsarContainerFactoryCustomizers containerFactoryCustomizers) {\n\t\tPulsarContainerProperties containerProperties = new PulsarContainerProperties();\n\t\tcontainerProperties.setSchemaResolver(schemaResolver);\n\t\tcontainerProperties.setTopicResolver(topicResolver);\n\t\tif (Threading.VIRTUAL.isActive(environment)) {\n\t\t\tcontainerProperties.setConsumerTaskExecutor(new VirtualThreadTaskExecutor(\"pulsar-consumer-\"));\n\t\t}\n\t\tpulsarTransactionManager.ifUnique(containerProperties.transactions()::setTransactionManager);\n\t\tthis.propertiesMapper.customizeContainerProperties(containerProperties);\n\t\tConcurrentPulsarListenerContainerFactory<?> containerFactory = new ConcurrentPulsarListenerContainerFactory<>(\n\t\t\t\tpulsarConsumerFactory, containerProperties);\n\t\tcontainerFactoryCustomizers.customize(containerFactory);\n\t\treturn containerFactory;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(PulsarReaderFactory.class)\n\tDefaultPulsarReaderFactory<?> pulsarReaderFactory(PulsarClient pulsarClient,\n\t\t\tObjectProvider<ReaderBuilderCustomizer<?>> customizersProvider,\n\t\t\tObjectProvider<PulsarTopicBuilder> topicBuilderProvider) {\n\t\tList<ReaderBuilderCustomizer<?>> customizers = new ArrayList<>();\n\t\tcustomizers.add(this.propertiesMapper::customizeReaderBuilder);\n\t\tcustomizers.addAll(customizersProvider.orderedStream().toList());\n\t\tList<ReaderBuilderCustomizer<Object>> lambdaSafeCustomizers = List\n\t\t\t.of((builder) -> applyReaderBuilderCustomizers(customizers, builder));\n\t\tDefaultPulsarReaderFactory<?> readerFactory = new DefaultPulsarReaderFactory<>(pulsarClient,\n\t\t\t\tlambdaSafeCustomizers);\n\t\ttopicBuilderProvider.ifAvailable(readerFactory::setTopicBuilder);\n\t\treturn readerFactory;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void applyReaderBuilderCustomizers(List<ReaderBuilderCustomizer<?>> customizers, ReaderBuilder<?> builder) {\n\t\tLambdaSafe.callbacks(ReaderBuilderCustomizer.class, customizers, builder)\n\t\t\t.invoke((customizer) -> customizer.customize(builder));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"pulsarReaderContainerFactory\")\n\tDefaultPulsarReaderContainerFactory<?> pulsarReaderContainerFactory(PulsarReaderFactory<?> pulsarReaderFactory,\n\t\t\tSchemaResolver schemaResolver, Environment environment,\n\t\t\tPulsarContainerFactoryCustomizers containerFactoryCustomizers) {\n\t\tPulsarReaderContainerProperties readerContainerProperties = new PulsarReaderContainerProperties();\n\t\treaderContainerProperties.setSchemaResolver(schemaResolver);\n\t\tif (Threading.VIRTUAL.isActive(environment)) {\n\t\t\treaderContainerProperties.setReaderTaskExecutor(new VirtualThreadTaskExecutor(\"pulsar-reader-\"));\n\t\t}\n\t\tthis.propertiesMapper.customizeReaderContainerProperties(readerContainerProperties);\n\t\tDefaultPulsarReaderContainerFactory<?> containerFactory = new DefaultPulsarReaderContainerFactory<>(\n\t\t\t\tpulsarReaderFactory, readerContainerProperties);\n\t\tcontainerFactoryCustomizers.customize(containerFactory);\n\t\treturn containerFactory;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnablePulsar\n\t@ConditionalOnMissingBean(name = { PulsarAnnotationSupportBeanNames.PULSAR_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME,\n\t\t\tPulsarAnnotationSupportBeanNames.PULSAR_READER_ANNOTATION_PROCESSOR_BEAN_NAME })\n\tstatic class EnablePulsarConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PulsarConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to a Pulsar service.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\npublic interface PulsarConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * URL used to connect to the broker.\n\t * @return the service URL\n\t */\n\tString getBrokerUrl();\n\n\t/**\n\t * URL user to connect to the admin endpoint.\n\t * @return the admin URL\n\t */\n\tString getAdminUrl();\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PulsarContainerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport org.springframework.pulsar.config.PulsarContainerFactory;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize a\n * {@link PulsarContainerFactory} to fine-tune its auto-configuration.\n *\n * @param <T> the type of the {@link PulsarContainerFactory}\n * @author Chris Bono\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface PulsarContainerFactoryCustomizer<T extends PulsarContainerFactory<?, ?>> {\n\n\t/**\n\t * Customize the container factory.\n\t * @param containerFactory the {@code PulsarContainerFactory} to customize\n\t */\n\tvoid customize(T containerFactory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PulsarContainerFactoryCustomizers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.pulsar.config.PulsarContainerFactory;\nimport org.springframework.pulsar.core.PulsarConsumerFactory;\n\n/**\n * Invokes the available {@link PulsarContainerFactoryCustomizer} instances in the context\n * for a given {@link PulsarConsumerFactory}.\n *\n * @author Chris Bono\n */\nclass PulsarContainerFactoryCustomizers {\n\n\tprivate final List<PulsarContainerFactoryCustomizer<?>> customizers;\n\n\tPulsarContainerFactoryCustomizers(@Nullable List<? extends PulsarContainerFactoryCustomizer<?>> customizers) {\n\t\tthis.customizers = (customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList();\n\t}\n\n\t/**\n\t * Customize the specified {@link PulsarContainerFactory}. Locates all\n\t * {@link PulsarContainerFactoryCustomizer} beans able to handle the specified\n\t * instance and invoke {@link PulsarContainerFactoryCustomizer#customize} on them.\n\t * @param <T> the type of container factory\n\t * @param containerFactory the container factory to customize\n\t * @return the customized container factory\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\t<T extends PulsarContainerFactory<?, ?>> T customize(T containerFactory) {\n\t\tLambdaSafe.callbacks(PulsarContainerFactoryCustomizer.class, this.customizers, containerFactory)\n\t\t\t.withLogger(PulsarContainerFactoryCustomizers.class)\n\t\t\t.invoke((customizer) -> customizer.customize(containerFactory));\n\t\treturn containerFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PulsarProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\nimport org.apache.pulsar.client.api.AutoClusterFailoverBuilder.FailoverPolicy;\nimport org.apache.pulsar.client.api.CompressionType;\nimport org.apache.pulsar.client.api.HashingScheme;\nimport org.apache.pulsar.client.api.MessageRoutingMode;\nimport org.apache.pulsar.client.api.ProducerAccessMode;\nimport org.apache.pulsar.client.api.RegexSubscriptionMode;\nimport org.apache.pulsar.client.api.SubscriptionInitialPosition;\nimport org.apache.pulsar.client.api.SubscriptionMode;\nimport org.apache.pulsar.client.api.SubscriptionType;\nimport org.apache.pulsar.common.schema.SchemaType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration properties Apache Pulsar.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @author Swamy Mavuri\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.pulsar\")\npublic class PulsarProperties {\n\n\tprivate final Client client = new Client();\n\n\tprivate final Admin admin = new Admin();\n\n\tprivate final Defaults defaults = new Defaults();\n\n\tprivate final Function function = new Function();\n\n\tprivate final Producer producer = new Producer();\n\n\tprivate final Consumer consumer = new Consumer();\n\n\tprivate final Listener listener = new Listener();\n\n\tprivate final Reader reader = new Reader();\n\n\tprivate final Template template = new Template();\n\n\tprivate final Transaction transaction = new Transaction();\n\n\tpublic Client getClient() {\n\t\treturn this.client;\n\t}\n\n\tpublic Admin getAdmin() {\n\t\treturn this.admin;\n\t}\n\n\tpublic Defaults getDefaults() {\n\t\treturn this.defaults;\n\t}\n\n\tpublic Producer getProducer() {\n\t\treturn this.producer;\n\t}\n\n\tpublic Consumer getConsumer() {\n\t\treturn this.consumer;\n\t}\n\n\tpublic Listener getListener() {\n\t\treturn this.listener;\n\t}\n\n\tpublic Reader getReader() {\n\t\treturn this.reader;\n\t}\n\n\tpublic Function getFunction() {\n\t\treturn this.function;\n\t}\n\n\tpublic Template getTemplate() {\n\t\treturn this.template;\n\t}\n\n\tpublic Transaction getTransaction() {\n\t\treturn this.transaction;\n\t}\n\n\tpublic static class Client {\n\n\t\t/**\n\t\t * Pulsar service URL in the format '(pulsar|pulsar+ssl)://host:port'.\n\t\t */\n\t\tprivate String serviceUrl = \"pulsar://localhost:6650\";\n\n\t\t/**\n\t\t * Client operation timeout.\n\t\t */\n\t\tprivate Duration operationTimeout = Duration.ofSeconds(30);\n\n\t\t/**\n\t\t * Client lookup timeout.\n\t\t */\n\t\tprivate @Nullable Duration lookupTimeout;\n\n\t\t/**\n\t\t * Duration to wait for a connection to a broker to be established.\n\t\t */\n\t\tprivate Duration connectionTimeout = Duration.ofSeconds(10);\n\n\t\t/**\n\t\t * Authentication settings.\n\t\t */\n\t\tprivate final Authentication authentication = new Authentication();\n\n\t\t/**\n\t\t * Thread related configuration.\n\t\t */\n\t\tprivate final Threads threads = new Threads();\n\n\t\t/**\n\t\t * Failover settings.\n\t\t */\n\t\tprivate final Failover failover = new Failover();\n\n\t\tpublic String getServiceUrl() {\n\t\t\treturn this.serviceUrl;\n\t\t}\n\n\t\tpublic void setServiceUrl(String serviceUrl) {\n\t\t\tthis.serviceUrl = serviceUrl;\n\t\t}\n\n\t\tpublic Duration getOperationTimeout() {\n\t\t\treturn this.operationTimeout;\n\t\t}\n\n\t\tpublic void setOperationTimeout(Duration operationTimeout) {\n\t\t\tthis.operationTimeout = operationTimeout;\n\t\t}\n\n\t\tpublic @Nullable Duration getLookupTimeout() {\n\t\t\treturn this.lookupTimeout;\n\t\t}\n\n\t\tpublic void setLookupTimeout(@Nullable Duration lookupTimeout) {\n\t\t\tthis.lookupTimeout = lookupTimeout;\n\t\t}\n\n\t\tpublic Duration getConnectionTimeout() {\n\t\t\treturn this.connectionTimeout;\n\t\t}\n\n\t\tpublic void setConnectionTimeout(Duration connectionTimeout) {\n\t\t\tthis.connectionTimeout = connectionTimeout;\n\t\t}\n\n\t\tpublic Authentication getAuthentication() {\n\t\t\treturn this.authentication;\n\t\t}\n\n\t\tpublic Threads getThreads() {\n\t\t\treturn this.threads;\n\t\t}\n\n\t\tpublic Failover getFailover() {\n\t\t\treturn this.failover;\n\t\t}\n\n\t}\n\n\tpublic static class Admin {\n\n\t\t/**\n\t\t * Pulsar web URL for the admin endpoint in the format '(http|https)://host:port'.\n\t\t */\n\t\tprivate String serviceUrl = \"http://localhost:8080\";\n\n\t\t/**\n\t\t * Duration to wait for a connection to server to be established.\n\t\t */\n\t\tprivate Duration connectionTimeout = Duration.ofMinutes(1);\n\n\t\t/**\n\t\t * Server response read time out for any request.\n\t\t */\n\t\tprivate Duration readTimeout = Duration.ofMinutes(1);\n\n\t\t/**\n\t\t * Server request time out for any request.\n\t\t */\n\t\tprivate Duration requestTimeout = Duration.ofMinutes(5);\n\n\t\t/**\n\t\t * Authentication settings.\n\t\t */\n\t\tprivate final Authentication authentication = new Authentication();\n\n\t\tpublic String getServiceUrl() {\n\t\t\treturn this.serviceUrl;\n\t\t}\n\n\t\tpublic void setServiceUrl(String serviceUrl) {\n\t\t\tthis.serviceUrl = serviceUrl;\n\t\t}\n\n\t\tpublic Duration getConnectionTimeout() {\n\t\t\treturn this.connectionTimeout;\n\t\t}\n\n\t\tpublic void setConnectionTimeout(Duration connectionTimeout) {\n\t\t\tthis.connectionTimeout = connectionTimeout;\n\t\t}\n\n\t\tpublic Duration getReadTimeout() {\n\t\t\treturn this.readTimeout;\n\t\t}\n\n\t\tpublic void setReadTimeout(Duration readTimeout) {\n\t\t\tthis.readTimeout = readTimeout;\n\t\t}\n\n\t\tpublic Duration getRequestTimeout() {\n\t\t\treturn this.requestTimeout;\n\t\t}\n\n\t\tpublic void setRequestTimeout(Duration requestTimeout) {\n\t\t\tthis.requestTimeout = requestTimeout;\n\t\t}\n\n\t\tpublic Authentication getAuthentication() {\n\t\t\treturn this.authentication;\n\t\t}\n\n\t}\n\n\tpublic static class Defaults {\n\n\t\t/**\n\t\t * List of mappings from message type to topic name and schema info to use as a\n\t\t * defaults when a topic name and/or schema is not explicitly specified when\n\t\t * producing or consuming messages of the mapped type.\n\t\t */\n\t\tprivate List<TypeMapping> typeMappings = new ArrayList<>();\n\n\t\tprivate final Topic topic = new Topic();\n\n\t\tpublic List<TypeMapping> getTypeMappings() {\n\t\t\treturn this.typeMappings;\n\t\t}\n\n\t\tpublic void setTypeMappings(List<TypeMapping> typeMappings) {\n\t\t\tthis.typeMappings = typeMappings;\n\t\t}\n\n\t\tpublic Topic getTopic() {\n\t\t\treturn this.topic;\n\t\t}\n\n\t\t/**\n\t\t * A mapping from message type to topic and/or schema info to use (at least one of\n\t\t * {@code topicName} or {@code schemaInfo} must be specified.\n\t\t *\n\t\t * @param messageType the message type\n\t\t * @param topicName the topic name\n\t\t * @param schemaInfo the schema info\n\t\t */\n\t\tpublic record TypeMapping(Class<?> messageType, @Nullable String topicName, @Nullable SchemaInfo schemaInfo) {\n\n\t\t\tpublic TypeMapping {\n\t\t\t\tAssert.notNull(messageType, \"'messageType' must not be null\");\n\t\t\t\tAssert.isTrue(topicName != null || schemaInfo != null,\n\t\t\t\t\t\t\"At least one of 'topicName' or 'schemaInfo' must not be null\");\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Represents a schema - holds enough information to construct an actual schema\n\t\t * instance.\n\t\t *\n\t\t * @param schemaType schema type\n\t\t * @param messageKeyType message key type (required for key value type)\n\t\t */\n\t\tpublic record SchemaInfo(SchemaType schemaType, @Nullable Class<?> messageKeyType) {\n\n\t\t\tpublic SchemaInfo {\n\t\t\t\tAssert.notNull(schemaType, \"'schemaType' must not be null\");\n\t\t\t\tAssert.isTrue(schemaType != SchemaType.NONE, \"'schemaType' must not be NONE\");\n\t\t\t\tAssert.isTrue(messageKeyType == null || schemaType == SchemaType.KEY_VALUE,\n\t\t\t\t\t\t\"'messageKeyType' can only be set when 'schemaType' is KEY_VALUE\");\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Topic {\n\n\t\t\t/**\n\t\t\t * Default tenant to use when producing or consuming messages against a\n\t\t\t * non-fully-qualified topic URL.\n\t\t\t */\n\t\t\tprivate String tenant = \"public\";\n\n\t\t\t/**\n\t\t\t * Default namespace to use when producing or consuming messages against a\n\t\t\t * non-fully-qualified topic URL.\n\t\t\t */\n\t\t\tprivate String namespace = \"default\";\n\n\t\t\tpublic String getTenant() {\n\t\t\t\treturn this.tenant;\n\t\t\t}\n\n\t\t\tpublic void setTenant(String tenant) {\n\t\t\t\tthis.tenant = tenant;\n\t\t\t}\n\n\t\t\tpublic String getNamespace() {\n\t\t\t\treturn this.namespace;\n\t\t\t}\n\n\t\t\tpublic void setNamespace(String namespace) {\n\t\t\t\tthis.namespace = namespace;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Function {\n\n\t\t/**\n\t\t * Whether to stop processing further function creates/updates when a failure\n\t\t * occurs.\n\t\t */\n\t\tprivate boolean failFast = true;\n\n\t\t/**\n\t\t * Whether to throw an exception if any failure is encountered during server\n\t\t * startup while creating/updating functions.\n\t\t */\n\t\tprivate boolean propagateFailures = true;\n\n\t\t/**\n\t\t * Whether to throw an exception if any failure is encountered during server\n\t\t * shutdown while enforcing stop policy on functions.\n\t\t */\n\t\tprivate boolean propagateStopFailures;\n\n\t\tpublic boolean isFailFast() {\n\t\t\treturn this.failFast;\n\t\t}\n\n\t\tpublic void setFailFast(boolean failFast) {\n\t\t\tthis.failFast = failFast;\n\t\t}\n\n\t\tpublic boolean isPropagateFailures() {\n\t\t\treturn this.propagateFailures;\n\t\t}\n\n\t\tpublic void setPropagateFailures(boolean propagateFailures) {\n\t\t\tthis.propagateFailures = propagateFailures;\n\t\t}\n\n\t\tpublic boolean isPropagateStopFailures() {\n\t\t\treturn this.propagateStopFailures;\n\t\t}\n\n\t\tpublic void setPropagateStopFailures(boolean propagateStopFailures) {\n\t\t\tthis.propagateStopFailures = propagateStopFailures;\n\t\t}\n\n\t}\n\n\tpublic static class Producer {\n\n\t\t/**\n\t\t * Name for the producer. If not assigned, a unique name is generated.\n\t\t */\n\t\tprivate @Nullable String name;\n\n\t\t/**\n\t\t * Topic the producer will publish to.\n\t\t */\n\t\tprivate @Nullable String topicName;\n\n\t\t/**\n\t\t * Time before a message has to be acknowledged by the broker.\n\t\t */\n\t\tprivate Duration sendTimeout = Duration.ofSeconds(30);\n\n\t\t/**\n\t\t * Message routing mode for a partitioned producer.\n\t\t */\n\t\tprivate MessageRoutingMode messageRoutingMode = MessageRoutingMode.RoundRobinPartition;\n\n\t\t/**\n\t\t * Message hashing scheme to choose the partition to which the message is\n\t\t * published.\n\t\t */\n\t\tprivate HashingScheme hashingScheme = HashingScheme.JavaStringHash;\n\n\t\t/**\n\t\t * Whether to automatically batch messages.\n\t\t */\n\t\tprivate boolean batchingEnabled = true;\n\n\t\t/**\n\t\t * Whether to split large-size messages into multiple chunks.\n\t\t */\n\t\tprivate boolean chunkingEnabled;\n\n\t\t/**\n\t\t * Message compression type.\n\t\t */\n\t\tprivate @Nullable CompressionType compressionType;\n\n\t\t/**\n\t\t * Type of access to the topic the producer requires.\n\t\t */\n\t\tprivate ProducerAccessMode accessMode = ProducerAccessMode.Shared;\n\n\t\tprivate final Cache cache = new Cache();\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic @Nullable String getTopicName() {\n\t\t\treturn this.topicName;\n\t\t}\n\n\t\tpublic void setTopicName(@Nullable String topicName) {\n\t\t\tthis.topicName = topicName;\n\t\t}\n\n\t\tpublic Duration getSendTimeout() {\n\t\t\treturn this.sendTimeout;\n\t\t}\n\n\t\tpublic void setSendTimeout(Duration sendTimeout) {\n\t\t\tthis.sendTimeout = sendTimeout;\n\t\t}\n\n\t\tpublic MessageRoutingMode getMessageRoutingMode() {\n\t\t\treturn this.messageRoutingMode;\n\t\t}\n\n\t\tpublic void setMessageRoutingMode(MessageRoutingMode messageRoutingMode) {\n\t\t\tthis.messageRoutingMode = messageRoutingMode;\n\t\t}\n\n\t\tpublic HashingScheme getHashingScheme() {\n\t\t\treturn this.hashingScheme;\n\t\t}\n\n\t\tpublic void setHashingScheme(HashingScheme hashingScheme) {\n\t\t\tthis.hashingScheme = hashingScheme;\n\t\t}\n\n\t\tpublic boolean isBatchingEnabled() {\n\t\t\treturn this.batchingEnabled;\n\t\t}\n\n\t\tpublic void setBatchingEnabled(boolean batchingEnabled) {\n\t\t\tthis.batchingEnabled = batchingEnabled;\n\t\t}\n\n\t\tpublic boolean isChunkingEnabled() {\n\t\t\treturn this.chunkingEnabled;\n\t\t}\n\n\t\tpublic void setChunkingEnabled(boolean chunkingEnabled) {\n\t\t\tthis.chunkingEnabled = chunkingEnabled;\n\t\t}\n\n\t\tpublic @Nullable CompressionType getCompressionType() {\n\t\t\treturn this.compressionType;\n\t\t}\n\n\t\tpublic void setCompressionType(@Nullable CompressionType compressionType) {\n\t\t\tthis.compressionType = compressionType;\n\t\t}\n\n\t\tpublic ProducerAccessMode getAccessMode() {\n\t\t\treturn this.accessMode;\n\t\t}\n\n\t\tpublic void setAccessMode(ProducerAccessMode accessMode) {\n\t\t\tthis.accessMode = accessMode;\n\t\t}\n\n\t\tpublic Cache getCache() {\n\t\t\treturn this.cache;\n\t\t}\n\n\t\tpublic static class Cache {\n\n\t\t\t/**\n\t\t\t * Time period to expire unused entries in the cache.\n\t\t\t */\n\t\t\tprivate Duration expireAfterAccess = Duration.ofMinutes(1);\n\n\t\t\t/**\n\t\t\t * Maximum size of cache (entries).\n\t\t\t */\n\t\t\tprivate long maximumSize = 1000L;\n\n\t\t\t/**\n\t\t\t * Initial size of cache.\n\t\t\t */\n\t\t\tprivate int initialCapacity = 50;\n\n\t\t\tpublic Duration getExpireAfterAccess() {\n\t\t\t\treturn this.expireAfterAccess;\n\t\t\t}\n\n\t\t\tpublic void setExpireAfterAccess(Duration expireAfterAccess) {\n\t\t\t\tthis.expireAfterAccess = expireAfterAccess;\n\t\t\t}\n\n\t\t\tpublic long getMaximumSize() {\n\t\t\t\treturn this.maximumSize;\n\t\t\t}\n\n\t\t\tpublic void setMaximumSize(long maximumSize) {\n\t\t\t\tthis.maximumSize = maximumSize;\n\t\t\t}\n\n\t\t\tpublic int getInitialCapacity() {\n\t\t\t\treturn this.initialCapacity;\n\t\t\t}\n\n\t\t\tpublic void setInitialCapacity(int initialCapacity) {\n\t\t\t\tthis.initialCapacity = initialCapacity;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Consumer {\n\n\t\t/**\n\t\t * Consumer name to identify a particular consumer from the topic stats.\n\t\t */\n\t\tprivate @Nullable String name;\n\n\t\t/**\n\t\t * Topics the consumer subscribes to.\n\t\t */\n\t\tprivate @Nullable List<String> topics;\n\n\t\t/**\n\t\t * Pattern for topics the consumer subscribes to.\n\t\t */\n\t\tprivate @Nullable Pattern topicsPattern;\n\n\t\t/**\n\t\t * Priority level for shared subscription consumers.\n\t\t */\n\t\tprivate int priorityLevel;\n\n\t\t/**\n\t\t * Whether to read messages from the compacted topic rather than the full message\n\t\t * backlog.\n\t\t */\n\t\tprivate boolean readCompacted;\n\n\t\t/**\n\t\t * Dead letter policy to use.\n\t\t */\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable DeadLetterPolicy deadLetterPolicy;\n\n\t\t/**\n\t\t * Consumer subscription properties.\n\t\t */\n\t\tprivate final Subscription subscription = new Subscription();\n\n\t\t/**\n\t\t * Whether to auto retry messages.\n\t\t */\n\t\tprivate boolean retryEnable;\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic Consumer.Subscription getSubscription() {\n\t\t\treturn this.subscription;\n\t\t}\n\n\t\tpublic @Nullable List<String> getTopics() {\n\t\t\treturn this.topics;\n\t\t}\n\n\t\tpublic void setTopics(@Nullable List<String> topics) {\n\t\t\tthis.topics = topics;\n\t\t}\n\n\t\tpublic @Nullable Pattern getTopicsPattern() {\n\t\t\treturn this.topicsPattern;\n\t\t}\n\n\t\tpublic void setTopicsPattern(@Nullable Pattern topicsPattern) {\n\t\t\tthis.topicsPattern = topicsPattern;\n\t\t}\n\n\t\tpublic int getPriorityLevel() {\n\t\t\treturn this.priorityLevel;\n\t\t}\n\n\t\tpublic void setPriorityLevel(int priorityLevel) {\n\t\t\tthis.priorityLevel = priorityLevel;\n\t\t}\n\n\t\tpublic boolean isReadCompacted() {\n\t\t\treturn this.readCompacted;\n\t\t}\n\n\t\tpublic void setReadCompacted(boolean readCompacted) {\n\t\t\tthis.readCompacted = readCompacted;\n\t\t}\n\n\t\tpublic @Nullable DeadLetterPolicy getDeadLetterPolicy() {\n\t\t\treturn this.deadLetterPolicy;\n\t\t}\n\n\t\tpublic void setDeadLetterPolicy(@Nullable DeadLetterPolicy deadLetterPolicy) {\n\t\t\tthis.deadLetterPolicy = deadLetterPolicy;\n\t\t}\n\n\t\tpublic boolean isRetryEnable() {\n\t\t\treturn this.retryEnable;\n\t\t}\n\n\t\tpublic void setRetryEnable(boolean retryEnable) {\n\t\t\tthis.retryEnable = retryEnable;\n\t\t}\n\n\t\tpublic static class Subscription {\n\n\t\t\t/**\n\t\t\t * Subscription name for the consumer.\n\t\t\t */\n\t\t\tprivate @Nullable String name;\n\n\t\t\t/**\n\t\t\t * Position where to initialize a newly created subscription.\n\t\t\t */\n\t\t\tprivate SubscriptionInitialPosition initialPosition = SubscriptionInitialPosition.Latest;\n\n\t\t\t/**\n\t\t\t * Subscription mode to be used when subscribing to the topic.\n\t\t\t */\n\t\t\tprivate SubscriptionMode mode = SubscriptionMode.Durable;\n\n\t\t\t/**\n\t\t\t * Determines which type of topics (persistent, non-persistent, or all) the\n\t\t\t * consumer should be subscribed to when using pattern subscriptions.\n\t\t\t */\n\t\t\tprivate RegexSubscriptionMode topicsMode = RegexSubscriptionMode.PersistentOnly;\n\n\t\t\t/**\n\t\t\t * Subscription type to be used when subscribing to a topic.\n\t\t\t */\n\t\t\tprivate SubscriptionType type = SubscriptionType.Exclusive;\n\n\t\t\tpublic @Nullable String getName() {\n\t\t\t\treturn this.name;\n\t\t\t}\n\n\t\t\tpublic void setName(@Nullable String name) {\n\t\t\t\tthis.name = name;\n\t\t\t}\n\n\t\t\tpublic SubscriptionInitialPosition getInitialPosition() {\n\t\t\t\treturn this.initialPosition;\n\t\t\t}\n\n\t\t\tpublic void setInitialPosition(SubscriptionInitialPosition initialPosition) {\n\t\t\t\tthis.initialPosition = initialPosition;\n\t\t\t}\n\n\t\t\tpublic SubscriptionMode getMode() {\n\t\t\t\treturn this.mode;\n\t\t\t}\n\n\t\t\tpublic void setMode(SubscriptionMode mode) {\n\t\t\t\tthis.mode = mode;\n\t\t\t}\n\n\t\t\tpublic RegexSubscriptionMode getTopicsMode() {\n\t\t\t\treturn this.topicsMode;\n\t\t\t}\n\n\t\t\tpublic void setTopicsMode(RegexSubscriptionMode topicsMode) {\n\t\t\t\tthis.topicsMode = topicsMode;\n\t\t\t}\n\n\t\t\tpublic SubscriptionType getType() {\n\t\t\t\treturn this.type;\n\t\t\t}\n\n\t\t\tpublic void setType(SubscriptionType type) {\n\t\t\t\tthis.type = type;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class DeadLetterPolicy {\n\n\t\t\t/**\n\t\t\t * Maximum number of times that a message will be redelivered before being\n\t\t\t * sent to the dead letter queue.\n\t\t\t */\n\t\t\tprivate int maxRedeliverCount;\n\n\t\t\t/**\n\t\t\t * Name of the retry topic where the failing messages will be sent.\n\t\t\t */\n\t\t\tprivate @Nullable String retryLetterTopic;\n\n\t\t\t/**\n\t\t\t * Name of the dead topic where the failing messages will be sent.\n\t\t\t */\n\t\t\tprivate @Nullable String deadLetterTopic;\n\n\t\t\t/**\n\t\t\t * Name of the initial subscription of the dead letter topic. When not set,\n\t\t\t * the initial subscription will not be created. However, when the property is\n\t\t\t * set then the broker's 'allowAutoSubscriptionCreation' must be enabled or\n\t\t\t * the DLQ producer will fail.\n\t\t\t */\n\t\t\tprivate @Nullable String initialSubscriptionName;\n\n\t\t\tpublic int getMaxRedeliverCount() {\n\t\t\t\treturn this.maxRedeliverCount;\n\t\t\t}\n\n\t\t\tpublic void setMaxRedeliverCount(int maxRedeliverCount) {\n\t\t\t\tthis.maxRedeliverCount = maxRedeliverCount;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getRetryLetterTopic() {\n\t\t\t\treturn this.retryLetterTopic;\n\t\t\t}\n\n\t\t\tpublic void setRetryLetterTopic(@Nullable String retryLetterTopic) {\n\t\t\t\tthis.retryLetterTopic = retryLetterTopic;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getDeadLetterTopic() {\n\t\t\t\treturn this.deadLetterTopic;\n\t\t\t}\n\n\t\t\tpublic void setDeadLetterTopic(@Nullable String deadLetterTopic) {\n\t\t\t\tthis.deadLetterTopic = deadLetterTopic;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getInitialSubscriptionName() {\n\t\t\t\treturn this.initialSubscriptionName;\n\t\t\t}\n\n\t\t\tpublic void setInitialSubscriptionName(@Nullable String initialSubscriptionName) {\n\t\t\t\tthis.initialSubscriptionName = initialSubscriptionName;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Listener {\n\n\t\t/**\n\t\t * SchemaType of the consumed messages.\n\t\t */\n\t\tprivate @Nullable SchemaType schemaType;\n\n\t\t/**\n\t\t * Number of threads used by listener container.\n\t\t */\n\t\tprivate @Nullable Integer concurrency;\n\n\t\t/**\n\t\t * Whether to record observations for when the Observations API is available and\n\t\t * the client supports it.\n\t\t */\n\t\tprivate boolean observationEnabled;\n\n\t\tpublic @Nullable SchemaType getSchemaType() {\n\t\t\treturn this.schemaType;\n\t\t}\n\n\t\tpublic void setSchemaType(@Nullable SchemaType schemaType) {\n\t\t\tthis.schemaType = schemaType;\n\t\t}\n\n\t\tpublic @Nullable Integer getConcurrency() {\n\t\t\treturn this.concurrency;\n\t\t}\n\n\t\tpublic void setConcurrency(@Nullable Integer concurrency) {\n\t\t\tthis.concurrency = concurrency;\n\t\t}\n\n\t\tpublic boolean isObservationEnabled() {\n\t\t\treturn this.observationEnabled;\n\t\t}\n\n\t\tpublic void setObservationEnabled(boolean observationEnabled) {\n\t\t\tthis.observationEnabled = observationEnabled;\n\t\t}\n\n\t}\n\n\tpublic static class Reader {\n\n\t\t/**\n\t\t * Reader name.\n\t\t */\n\t\tprivate @Nullable String name;\n\n\t\t/**\n\t\t * Topics the reader subscribes to.\n\t\t */\n\t\tprivate @Nullable List<String> topics;\n\n\t\t/**\n\t\t * Subscription name.\n\t\t */\n\t\tprivate @Nullable String subscriptionName;\n\n\t\t/**\n\t\t * Prefix of subscription role.\n\t\t */\n\t\tprivate @Nullable String subscriptionRolePrefix;\n\n\t\t/**\n\t\t * Whether to read messages from a compacted topic rather than a full message\n\t\t * backlog of a topic.\n\t\t */\n\t\tprivate boolean readCompacted;\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic @Nullable List<String> getTopics() {\n\t\t\treturn this.topics;\n\t\t}\n\n\t\tpublic void setTopics(@Nullable List<String> topics) {\n\t\t\tthis.topics = topics;\n\t\t}\n\n\t\tpublic @Nullable String getSubscriptionName() {\n\t\t\treturn this.subscriptionName;\n\t\t}\n\n\t\tpublic void setSubscriptionName(@Nullable String subscriptionName) {\n\t\t\tthis.subscriptionName = subscriptionName;\n\t\t}\n\n\t\tpublic @Nullable String getSubscriptionRolePrefix() {\n\t\t\treturn this.subscriptionRolePrefix;\n\t\t}\n\n\t\tpublic void setSubscriptionRolePrefix(@Nullable String subscriptionRolePrefix) {\n\t\t\tthis.subscriptionRolePrefix = subscriptionRolePrefix;\n\t\t}\n\n\t\tpublic boolean isReadCompacted() {\n\t\t\treturn this.readCompacted;\n\t\t}\n\n\t\tpublic void setReadCompacted(boolean readCompacted) {\n\t\t\tthis.readCompacted = readCompacted;\n\t\t}\n\n\t}\n\n\tpublic static class Template {\n\n\t\t/**\n\t\t * Whether to record observations for when the Observations API is available.\n\t\t */\n\t\tprivate boolean observationsEnabled;\n\n\t\tpublic boolean isObservationsEnabled() {\n\t\t\treturn this.observationsEnabled;\n\t\t}\n\n\t\tpublic void setObservationsEnabled(boolean observationsEnabled) {\n\t\t\tthis.observationsEnabled = observationsEnabled;\n\t\t}\n\n\t}\n\n\tpublic static class Transaction {\n\n\t\t/**\n\t\t * Whether transaction support is enabled.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\tpublic static class Authentication {\n\n\t\t/**\n\t\t * Fully qualified class name of the authentication plugin.\n\t\t */\n\t\tprivate @Nullable String pluginClassName;\n\n\t\t/**\n\t\t * Authentication parameter(s) as a map of parameter names to parameter values.\n\t\t */\n\t\tprivate Map<String, String> param = new LinkedHashMap<>();\n\n\t\tpublic @Nullable String getPluginClassName() {\n\t\t\treturn this.pluginClassName;\n\t\t}\n\n\t\tpublic void setPluginClassName(@Nullable String pluginClassName) {\n\t\t\tthis.pluginClassName = pluginClassName;\n\t\t}\n\n\t\tpublic Map<String, String> getParam() {\n\t\t\treturn this.param;\n\t\t}\n\n\t\tpublic void setParam(Map<String, String> param) {\n\t\t\tthis.param = param;\n\t\t}\n\n\t}\n\n\tpublic static class Threads {\n\n\t\t/**\n\t\t * Number of threads to be used for handling connections to brokers.\n\t\t */\n\t\tprivate @Nullable Integer io;\n\n\t\t/**\n\t\t * Number of threads to be used for message listeners.\n\t\t */\n\t\tprivate @Nullable Integer listener;\n\n\t\tpublic @Nullable Integer getIo() {\n\t\t\treturn this.io;\n\t\t}\n\n\t\tpublic void setIo(@Nullable Integer io) {\n\t\t\tthis.io = io;\n\t\t}\n\n\t\tpublic @Nullable Integer getListener() {\n\t\t\treturn this.listener;\n\t\t}\n\n\t\tpublic void setListener(@Nullable Integer listener) {\n\t\t\tthis.listener = listener;\n\t\t}\n\n\t}\n\n\tpublic static class Failover {\n\n\t\t/**\n\t\t * Cluster failover policy.\n\t\t */\n\t\tprivate FailoverPolicy policy = FailoverPolicy.ORDER;\n\n\t\t/**\n\t\t * Delay before the Pulsar client switches from the primary cluster to the backup\n\t\t * cluster.\n\t\t */\n\t\tprivate @Nullable Duration delay;\n\n\t\t/**\n\t\t * Delay before the Pulsar client switches from the backup cluster to the primary\n\t\t * cluster.\n\t\t */\n\t\tprivate @Nullable Duration switchBackDelay;\n\n\t\t/**\n\t\t * Frequency of performing a probe task.\n\t\t */\n\t\tprivate @Nullable Duration checkInterval;\n\n\t\t/**\n\t\t * List of backup clusters. The backup cluster is chosen in the sequence of the\n\t\t * given list. If all backup clusters are available, the Pulsar client chooses the\n\t\t * first backup cluster.\n\t\t */\n\t\tprivate List<BackupCluster> backupClusters = new ArrayList<>();\n\n\t\tpublic FailoverPolicy getPolicy() {\n\t\t\treturn this.policy;\n\t\t}\n\n\t\tpublic void setPolicy(FailoverPolicy policy) {\n\t\t\tthis.policy = policy;\n\t\t}\n\n\t\tpublic @Nullable Duration getDelay() {\n\t\t\treturn this.delay;\n\t\t}\n\n\t\tpublic void setDelay(@Nullable Duration delay) {\n\t\t\tthis.delay = delay;\n\t\t}\n\n\t\tpublic @Nullable Duration getSwitchBackDelay() {\n\t\t\treturn this.switchBackDelay;\n\t\t}\n\n\t\tpublic void setSwitchBackDelay(@Nullable Duration switchBackDelay) {\n\t\t\tthis.switchBackDelay = switchBackDelay;\n\t\t}\n\n\t\tpublic @Nullable Duration getCheckInterval() {\n\t\t\treturn this.checkInterval;\n\t\t}\n\n\t\tpublic void setCheckInterval(@Nullable Duration checkInterval) {\n\t\t\tthis.checkInterval = checkInterval;\n\t\t}\n\n\t\tpublic List<BackupCluster> getBackupClusters() {\n\t\t\treturn this.backupClusters;\n\t\t}\n\n\t\tpublic void setBackupClusters(List<BackupCluster> backupClusters) {\n\t\t\tthis.backupClusters = backupClusters;\n\t\t}\n\n\t\tpublic static class BackupCluster {\n\n\t\t\t/**\n\t\t\t * Pulsar service URL in the format '(pulsar|pulsar+ssl)://host:port'.\n\t\t\t */\n\t\t\tprivate String serviceUrl = \"pulsar://localhost:6650\";\n\n\t\t\t/**\n\t\t\t * Authentication settings.\n\t\t\t */\n\t\t\tprivate final Authentication authentication = new Authentication();\n\n\t\t\tpublic String getServiceUrl() {\n\t\t\t\treturn this.serviceUrl;\n\t\t\t}\n\n\t\t\tpublic void setServiceUrl(String serviceUrl) {\n\t\t\t\tthis.serviceUrl = serviceUrl;\n\t\t\t}\n\n\t\t\tpublic Authentication getAuthentication() {\n\t\t\t\treturn this.authentication;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/PulsarPropertiesMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.apache.pulsar.client.admin.PulsarAdminBuilder;\nimport org.apache.pulsar.client.api.Authentication;\nimport org.apache.pulsar.client.api.AuthenticationFactory;\nimport org.apache.pulsar.client.api.AutoClusterFailoverBuilder;\nimport org.apache.pulsar.client.api.ClientBuilder;\nimport org.apache.pulsar.client.api.ConsumerBuilder;\nimport org.apache.pulsar.client.api.ProducerBuilder;\nimport org.apache.pulsar.client.api.PulsarClientException.UnsupportedAuthenticationException;\nimport org.apache.pulsar.client.api.ReaderBuilder;\nimport org.apache.pulsar.client.api.ServiceUrlProvider;\nimport org.apache.pulsar.client.impl.AutoClusterFailover.AutoClusterFailoverBuilderImpl;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.json.JsonWriter;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.pulsar.listener.PulsarContainerProperties;\nimport org.springframework.pulsar.reader.PulsarReaderContainerProperties;\nimport org.springframework.util.StringUtils;\n\n/**\n * Helper class used to map {@link PulsarProperties} to various builder customizers.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @author Swamy Mavuri\n * @author Vedran Pavic\n */\nfinal class PulsarPropertiesMapper {\n\n\tprivate static final JsonWriter<Map<String, String>> jsonWriter = JsonWriter\n\t\t.of((members) -> members.add().as(TreeMap::new).usingPairs(Map::forEach));\n\n\tprivate final PulsarProperties properties;\n\n\tPulsarPropertiesMapper(PulsarProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\tvoid customizeClientBuilder(ClientBuilder clientBuilder, PulsarConnectionDetails connectionDetails) {\n\t\tPulsarProperties.Client properties = this.properties.getClient();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getConnectionTimeout).to(timeoutProperty(clientBuilder::connectionTimeout));\n\t\tmap.from(properties::getOperationTimeout).to(timeoutProperty(clientBuilder::operationTimeout));\n\t\tmap.from(properties::getLookupTimeout).to(timeoutProperty(clientBuilder::lookupTimeout));\n\t\tmap.from(properties.getThreads()::getIo).to(clientBuilder::ioThreads);\n\t\tmap.from(properties.getThreads()::getListener).to(clientBuilder::listenerThreads);\n\t\tmap.from(this.properties.getTransaction()::isEnabled).whenTrue().to(clientBuilder::enableTransaction);\n\t\tcustomizeAuthentication(properties.getAuthentication(), clientBuilder::authentication);\n\t\tcustomizeServiceUrlProviderBuilder(clientBuilder::serviceUrl, clientBuilder::serviceUrlProvider, properties,\n\t\t\t\tconnectionDetails);\n\t}\n\n\tprivate void customizeServiceUrlProviderBuilder(Consumer<String> serviceUrlConsumer,\n\t\t\tConsumer<ServiceUrlProvider> serviceUrlProviderConsumer, PulsarProperties.Client properties,\n\t\t\tPulsarConnectionDetails connectionDetails) {\n\t\tPulsarProperties.Failover failoverProperties = properties.getFailover();\n\t\tif (failoverProperties.getBackupClusters().isEmpty()) {\n\t\t\tserviceUrlConsumer.accept(connectionDetails.getBrokerUrl());\n\t\t\treturn;\n\t\t}\n\t\tMap<String, @Nullable Authentication> secondaryAuths = getSecondaryAuths(failoverProperties);\n\t\tAutoClusterFailoverBuilder autoClusterFailoverBuilder = new AutoClusterFailoverBuilderImpl();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(connectionDetails::getBrokerUrl).to(autoClusterFailoverBuilder::primary);\n\t\tmap.from(secondaryAuths::keySet).as(ArrayList::new).to(autoClusterFailoverBuilder::secondary);\n\t\tmap.from(failoverProperties::getPolicy).to(autoClusterFailoverBuilder::failoverPolicy);\n\t\tmap.from(failoverProperties::getDelay).to(timeoutProperty(autoClusterFailoverBuilder::failoverDelay));\n\t\tmap.from(failoverProperties::getSwitchBackDelay)\n\t\t\t.to(timeoutProperty(autoClusterFailoverBuilder::switchBackDelay));\n\t\tmap.from(failoverProperties::getCheckInterval).to(timeoutProperty(autoClusterFailoverBuilder::checkInterval));\n\t\tmap.from(secondaryAuths).to(autoClusterFailoverBuilder::secondaryAuthentication);\n\t\tserviceUrlProviderConsumer.accept(autoClusterFailoverBuilder.build());\n\t}\n\n\tprivate Map<String, @Nullable Authentication> getSecondaryAuths(PulsarProperties.Failover properties) {\n\t\tMap<String, @Nullable Authentication> secondaryAuths = new LinkedHashMap<>();\n\t\tproperties.getBackupClusters().forEach((backupCluster) -> {\n\t\t\tPulsarProperties.Authentication authenticationProperties = backupCluster.getAuthentication();\n\t\t\tif (authenticationProperties.getPluginClassName() == null) {\n\t\t\t\tsecondaryAuths.put(backupCluster.getServiceUrl(), null);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tcustomizeAuthentication(authenticationProperties, (authPluginClassName, authParams) -> {\n\t\t\t\t\tAuthentication authentication = AuthenticationFactory.create(authPluginClassName, authParams);\n\t\t\t\t\tsecondaryAuths.put(backupCluster.getServiceUrl(), authentication);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\treturn secondaryAuths;\n\t}\n\n\tvoid customizeAdminBuilder(PulsarAdminBuilder adminBuilder, PulsarConnectionDetails connectionDetails) {\n\t\tPulsarProperties.Admin properties = this.properties.getAdmin();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(connectionDetails::getAdminUrl).to(adminBuilder::serviceHttpUrl);\n\t\tmap.from(properties::getConnectionTimeout).to(timeoutProperty(adminBuilder::connectionTimeout));\n\t\tmap.from(properties::getReadTimeout).to(timeoutProperty(adminBuilder::readTimeout));\n\t\tmap.from(properties::getRequestTimeout).to(timeoutProperty(adminBuilder::requestTimeout));\n\t\tcustomizeAuthentication(properties.getAuthentication(), adminBuilder::authentication);\n\t}\n\n\tprivate void customizeAuthentication(PulsarProperties.Authentication properties, AuthenticationConsumer action) {\n\t\tString pluginClassName = properties.getPluginClassName();\n\t\tif (StringUtils.hasText(pluginClassName)) {\n\t\t\ttry {\n\t\t\t\taction.accept(pluginClassName, jsonWriter.writeToString(properties.getParam()));\n\t\t\t}\n\t\t\tcatch (UnsupportedAuthenticationException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to configure Pulsar authentication\", ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t<T> void customizeProducerBuilder(ProducerBuilder<T> producerBuilder) {\n\t\tPulsarProperties.Producer properties = this.properties.getProducer();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getName).to(producerBuilder::producerName);\n\t\tmap.from(properties::getTopicName).to(producerBuilder::topic);\n\t\tmap.from(properties::getSendTimeout).to(timeoutProperty(producerBuilder::sendTimeout));\n\t\tmap.from(properties::getMessageRoutingMode).to(producerBuilder::messageRoutingMode);\n\t\tmap.from(properties::getHashingScheme).to(producerBuilder::hashingScheme);\n\t\tmap.from(properties::isBatchingEnabled).to(producerBuilder::enableBatching);\n\t\tmap.from(properties::isChunkingEnabled).to(producerBuilder::enableChunking);\n\t\tmap.from(properties::getCompressionType).to(producerBuilder::compressionType);\n\t\tmap.from(properties::getAccessMode).to(producerBuilder::accessMode);\n\t}\n\n\t<T> void customizeTemplate(PulsarTemplate<T> template) {\n\t\ttemplate.transactions().setEnabled(this.properties.getTransaction().isEnabled());\n\t}\n\n\t<T> void customizeConsumerBuilder(ConsumerBuilder<T> consumerBuilder) {\n\t\tPulsarProperties.Consumer properties = this.properties.getConsumer();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getName).to(consumerBuilder::consumerName);\n\t\tmap.from(properties::getTopics).as(ArrayList::new).to(consumerBuilder::topics);\n\t\tmap.from(properties::getTopicsPattern).to(consumerBuilder::topicsPattern);\n\t\tmap.from(properties::getPriorityLevel).to(consumerBuilder::priorityLevel);\n\t\tmap.from(properties::isReadCompacted).to(consumerBuilder::readCompacted);\n\t\tmap.from(properties::getDeadLetterPolicy).as(DeadLetterPolicyMapper::map).to(consumerBuilder::deadLetterPolicy);\n\t\tmap.from(properties::isRetryEnable).to(consumerBuilder::enableRetry);\n\t\tcustomizeConsumerBuilderSubscription(consumerBuilder);\n\t}\n\n\tprivate void customizeConsumerBuilderSubscription(ConsumerBuilder<?> consumerBuilder) {\n\t\tPulsarProperties.Consumer.Subscription properties = this.properties.getConsumer().getSubscription();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getName).to(consumerBuilder::subscriptionName);\n\t\tmap.from(properties::getInitialPosition).to(consumerBuilder::subscriptionInitialPosition);\n\t\tmap.from(properties::getMode).to(consumerBuilder::subscriptionMode);\n\t\tmap.from(properties::getTopicsMode).to(consumerBuilder::subscriptionTopicsMode);\n\t\tmap.from(properties::getType).to(consumerBuilder::subscriptionType);\n\t}\n\n\tvoid customizeContainerProperties(PulsarContainerProperties containerProperties) {\n\t\tcustomizePulsarContainerConsumerSubscriptionProperties(containerProperties);\n\t\tcustomizePulsarContainerListenerProperties(containerProperties);\n\t\tcontainerProperties.transactions().setEnabled(this.properties.getTransaction().isEnabled());\n\t}\n\n\tprivate void customizePulsarContainerConsumerSubscriptionProperties(PulsarContainerProperties containerProperties) {\n\t\tPulsarProperties.Consumer.Subscription properties = this.properties.getConsumer().getSubscription();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getType).to(containerProperties::setSubscriptionType);\n\t\tmap.from(properties::getName).to(containerProperties::setSubscriptionName);\n\t}\n\n\tprivate void customizePulsarContainerListenerProperties(PulsarContainerProperties containerProperties) {\n\t\tPulsarProperties.Listener properties = this.properties.getListener();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getSchemaType).to(containerProperties::setSchemaType);\n\t\tmap.from(properties::getConcurrency).to(containerProperties::setConcurrency);\n\t\tmap.from(properties::isObservationEnabled).to(containerProperties::setObservationEnabled);\n\t}\n\n\t<T> void customizeReaderBuilder(ReaderBuilder<T> readerBuilder) {\n\t\tPulsarProperties.Reader properties = this.properties.getReader();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getName).to(readerBuilder::readerName);\n\t\tmap.from(properties::getTopics).to(readerBuilder::topics);\n\t\tmap.from(properties::getSubscriptionName).to(readerBuilder::subscriptionName);\n\t\tmap.from(properties::getSubscriptionRolePrefix).to(readerBuilder::subscriptionRolePrefix);\n\t\tmap.from(properties::isReadCompacted).to(readerBuilder::readCompacted);\n\t}\n\n\tvoid customizeReaderContainerProperties(PulsarReaderContainerProperties readerContainerProperties) {\n\t\tPulsarProperties.Reader properties = this.properties.getReader();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getTopics).to(readerContainerProperties::setTopics);\n\t}\n\n\tprivate Consumer<Duration> timeoutProperty(BiConsumer<Integer, TimeUnit> setter) {\n\t\treturn (duration) -> setter.accept((int) duration.toMillis(), TimeUnit.MILLISECONDS);\n\t}\n\n\tprivate interface AuthenticationConsumer {\n\n\t\tvoid accept(String authPluginClassName, String authParamString) throws UnsupportedAuthenticationException;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring for Apache Pulsar.\n */\n@NullMarked\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/docker/compose/PulsarDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.ConnectionPorts;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link PulsarConnectionDetails}\n * for a {@code pulsar} service.\n *\n * @author Chris Bono\n */\nclass PulsarDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<PulsarConnectionDetails> {\n\n\tprivate static final int BROKER_PORT = 6650;\n\n\tprivate static final int ADMIN_PORT = 8080;\n\n\tPulsarDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"apachepulsar/pulsar\");\n\t}\n\n\t@Override\n\tprotected PulsarConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new PulsarDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link PulsarConnectionDetails} backed by a {@code pulsar} {@link RunningService}.\n\t */\n\tstatic class PulsarDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements PulsarConnectionDetails {\n\n\t\tprivate final String brokerUrl;\n\n\t\tprivate final String adminUrl;\n\n\t\tPulsarDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tConnectionPorts ports = service.ports();\n\t\t\tthis.brokerUrl = \"pulsar://%s:%s\".formatted(service.host(), ports.get(BROKER_PORT));\n\t\t\tthis.adminUrl = \"http://%s:%s\".formatted(service.host(), ports.get(ADMIN_PORT));\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn this.brokerUrl;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getAdminUrl() {\n\t\t\treturn this.adminUrl;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Pulsar service connections.\n */\n@NullMarked\npackage org.springframework.boot.pulsar.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/testcontainers/DeprecatedPulsarContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.testcontainers;\n\nimport org.testcontainers.containers.PulsarContainer;\n\nimport org.springframework.boot.pulsar.autoconfigure.PulsarConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link PulsarConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link PulsarContainer}.\n *\n * @author Chris Bono\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link PulsarContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedPulsarContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<PulsarContainer, PulsarConnectionDetails> {\n\n\t@Override\n\tprotected PulsarConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<PulsarContainer> source) {\n\t\treturn new PulsarContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link PulsarConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class PulsarContainerConnectionDetails extends ContainerConnectionDetails<PulsarContainer>\n\t\t\timplements PulsarConnectionDetails {\n\n\t\tprivate PulsarContainerConnectionDetails(ContainerConnectionSource<PulsarContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn getContainer().getPulsarBrokerUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getAdminUrl() {\n\t\t\treturn getContainer().getHttpServiceUrl();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/testcontainers/PulsarContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.testcontainers;\n\nimport org.testcontainers.pulsar.PulsarContainer;\n\nimport org.springframework.boot.pulsar.autoconfigure.PulsarConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link PulsarConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link PulsarContainer}.\n *\n * @author Chris Bono\n */\nclass PulsarContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<PulsarContainer, PulsarConnectionDetails> {\n\n\t@Override\n\tprotected PulsarConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<PulsarContainer> source) {\n\t\treturn new PulsarContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link PulsarConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class PulsarContainerConnectionDetails extends ContainerConnectionDetails<PulsarContainer>\n\t\t\timplements PulsarConnectionDetails {\n\n\t\tprivate PulsarContainerConnectionDetails(ContainerConnectionSource<PulsarContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getBrokerUrl() {\n\t\t\treturn getContainer().getPulsarBrokerUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getAdminUrl() {\n\t\t\treturn getContainer().getHttpServiceUrl();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/java/org/springframework/boot/pulsar/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Pulsar service connections.\n */\n@NullMarked\npackage org.springframework.boot.pulsar.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.pulsar.defaults.topic.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable default tenant and namespace support for topics.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.pulsar.function.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable function support.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.pulsar.producer.cache.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable caching in the PulsarProducerFactory.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.pulsar.autoconfigure.PulsarAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.pulsar.docker.compose.PulsarDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.pulsar.testcontainers.DeprecatedPulsarContainerConnectionDetailsFactory,\\\norg.springframework.boot.pulsar.testcontainers.PulsarContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/Customizers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.util.List;\nimport java.util.function.BiConsumer;\n\nimport org.assertj.core.api.AssertDelegateTarget;\nimport org.mockito.InOrder;\n\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test utility used to check customizers are called correctly.\n *\n * @param <C> the customizer type\n * @param <T> the target class that is customized\n * @author Phillip Webb\n * @author Chris Bono\n */\nfinal class Customizers<C, T> {\n\n\tprivate final BiConsumer<C, T> customizeAction;\n\n\tprivate final Class<T> targetClass;\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Customizers(Class<?> targetClass, BiConsumer<C, T> customizeAction) {\n\t\tthis.customizeAction = customizeAction;\n\t\tthis.targetClass = (Class<T>) targetClass;\n\t}\n\n\t/**\n\t * Create an instance by getting the value from a field.\n\t * @param source the source to extract the customizers from\n\t * @param fieldName the field name\n\t * @return a new {@link CustomizersAssert} instance\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tCustomizersAssert fromField(Object source, String fieldName) {\n\t\tObject field = ReflectionTestUtils.getField(source, fieldName);\n\t\tassertThat(field).isNotNull();\n\t\treturn new CustomizersAssert(field);\n\t}\n\n\t/**\n\t * Create a new {@link Customizers} instance.\n\t * @param <C> the customizer class\n\t * @param <T> the target class that is customized\n\t * @param targetClass the target class that is customized\n\t * @param customizeAction the customizer action to take\n\t * @return a new {@link Customizers} instance\n\t */\n\tstatic <C, T> Customizers<C, T> of(Class<?> targetClass, BiConsumer<C, T> customizeAction) {\n\t\treturn new Customizers<>(targetClass, customizeAction);\n\t}\n\n\t/**\n\t * Assertions that can be applied to customizers.\n\t */\n\tfinal class CustomizersAssert implements AssertDelegateTarget {\n\n\t\tprivate final List<C> customizers;\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate CustomizersAssert(Object customizers) {\n\t\t\tthis.customizers = (customizers instanceof List) ? (List<C>) customizers : List.of((C) customizers);\n\t\t}\n\n\t\t/**\n\t\t * Assert that the customize method is called in a specified order. It is expected\n\t\t * that each customizer has set a unique value so the expected values can be used\n\t\t * as a verify step.\n\t\t * @param <V> the value type\n\t\t * @param call the call the customizer makes\n\t\t * @param expectedValues the expected values\n\t\t */\n\t\t@SuppressWarnings(\"unchecked\")\n\t\t<V> void callsInOrder(BiConsumer<T, V> call, V... expectedValues) {\n\t\t\tT target = mock(Customizers.this.targetClass);\n\t\t\tBiConsumer<C, T> customizeAction = Customizers.this.customizeAction;\n\t\t\tthis.customizers.forEach((customizer) -> customizeAction.accept(customizer, target));\n\t\t\tInOrder ordered = inOrder(target);\n\t\t\tfor (V expectedValue : expectedValues) {\n\t\t\t\tcall.accept(ordered.verify(target), expectedValue);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/DeadLetterPolicyMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport org.apache.pulsar.client.api.DeadLetterPolicy;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link DeadLetterPolicyMapper}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n */\nclass DeadLetterPolicyMapperTests {\n\n\t@Test\n\tvoid map() {\n\t\tPulsarProperties.Consumer.DeadLetterPolicy properties = new PulsarProperties.Consumer.DeadLetterPolicy();\n\t\tproperties.setMaxRedeliverCount(100);\n\t\tproperties.setRetryLetterTopic(\"my-retry-topic\");\n\t\tproperties.setDeadLetterTopic(\"my-dlt-topic\");\n\t\tproperties.setInitialSubscriptionName(\"my-initial-subscription\");\n\t\tDeadLetterPolicy policy = DeadLetterPolicyMapper.map(properties);\n\t\tassertThat(policy.getMaxRedeliverCount()).isEqualTo(100);\n\t\tassertThat(policy.getRetryLetterTopic()).isEqualTo(\"my-retry-topic\");\n\t\tassertThat(policy.getDeadLetterTopic()).isEqualTo(\"my-dlt-topic\");\n\t\tassertThat(policy.getInitialSubscriptionName()).isEqualTo(\"my-initial-subscription\");\n\t}\n\n\t@Test\n\tvoid mapWhenMaxRedeliverCountIsNotPositiveThrowsException() {\n\t\tPulsarProperties.Consumer.DeadLetterPolicy properties = new PulsarProperties.Consumer.DeadLetterPolicy();\n\t\tproperties.setMaxRedeliverCount(0);\n\t\tassertThatIllegalStateException().isThrownBy(() -> DeadLetterPolicyMapper.map(properties))\n\t\t\t.withMessage(\"Pulsar DeadLetterPolicy must have a positive 'max-redelivery-count' property value\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/MockAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.pulsar.client.api.Authentication;\nimport org.apache.pulsar.client.api.AuthenticationDataProvider;\nimport org.apache.pulsar.client.api.PulsarClientException;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test plugin-class-name for Authentication\n *\n * @author Swamy Mavuri\n */\n@SuppressWarnings(\"deprecation\")\npublic class MockAuthentication implements Authentication {\n\n\tpublic Map<String, String> authParamsMap = new HashMap<>();\n\n\t@Override\n\tpublic String getAuthMethodName() {\n\t\treturn \"\";\n\t}\n\n\t@Override\n\tpublic AuthenticationDataProvider getAuthData() {\n\t\treturn mock(AuthenticationDataProvider.class);\n\t}\n\n\t@Override\n\tpublic void configure(Map<String, String> authParams) {\n\t\tthis.authParamsMap = authParams;\n\t}\n\n\t@Override\n\tpublic void start() throws PulsarClientException {\n\n\t}\n\n\t@Override\n\tpublic void close() throws IOException {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/PropertiesPulsarConnectionDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PropertiesPulsarConnectionDetails}.\n *\n * @author Chris Bono\n */\nclass PropertiesPulsarConnectionDetailsTests {\n\n\t@Test\n\tvoid getClientServiceUrlReturnsValueFromProperties() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getClient().setServiceUrl(\"foo\");\n\t\tPulsarConnectionDetails connectionDetails = new PropertiesPulsarConnectionDetails(properties);\n\t\tassertThat(connectionDetails.getBrokerUrl()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tvoid getAdminServiceHttpUrlReturnsValueFromProperties() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getAdmin().setServiceUrl(\"foo\");\n\t\tPulsarConnectionDetails connectionDetails = new PropertiesPulsarConnectionDetails(properties);\n\t\tassertThat(connectionDetails.getAdminUrl()).isEqualTo(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/PulsarAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport com.github.benmanes.caffeine.cache.Caffeine;\nimport org.apache.pulsar.client.admin.PulsarAdminBuilder;\nimport org.apache.pulsar.client.api.ClientBuilder;\nimport org.apache.pulsar.client.api.ConsumerBuilder;\nimport org.apache.pulsar.client.api.ProducerBuilder;\nimport org.apache.pulsar.client.api.PulsarClient;\nimport org.apache.pulsar.client.api.ReaderBuilder;\nimport org.apache.pulsar.client.api.Schema;\nimport org.apache.pulsar.client.api.interceptor.ProducerInterceptor;\nimport org.apache.pulsar.client.impl.AutoClusterFailover;\nimport org.apache.pulsar.common.schema.KeyValueEncodingType;\nimport org.apache.pulsar.common.schema.SchemaType;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.InOrder;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.task.VirtualThreadTaskExecutor;\nimport org.springframework.pulsar.annotation.PulsarBootstrapConfiguration;\nimport org.springframework.pulsar.annotation.PulsarListenerAnnotationBeanPostProcessor;\nimport org.springframework.pulsar.annotation.PulsarReaderAnnotationBeanPostProcessor;\nimport org.springframework.pulsar.cache.provider.caffeine.CaffeineCacheProvider;\nimport org.springframework.pulsar.config.ConcurrentPulsarListenerContainerFactory;\nimport org.springframework.pulsar.config.DefaultPulsarReaderContainerFactory;\nimport org.springframework.pulsar.config.PulsarListenerContainerFactory;\nimport org.springframework.pulsar.config.PulsarListenerEndpointRegistry;\nimport org.springframework.pulsar.config.PulsarReaderEndpointRegistry;\nimport org.springframework.pulsar.core.CachingPulsarProducerFactory;\nimport org.springframework.pulsar.core.ConsumerBuilderCustomizer;\nimport org.springframework.pulsar.core.DefaultPulsarClientFactory;\nimport org.springframework.pulsar.core.DefaultPulsarConsumerFactory;\nimport org.springframework.pulsar.core.DefaultPulsarProducerFactory;\nimport org.springframework.pulsar.core.DefaultPulsarReaderFactory;\nimport org.springframework.pulsar.core.DefaultSchemaResolver;\nimport org.springframework.pulsar.core.DefaultTopicResolver;\nimport org.springframework.pulsar.core.ProducerBuilderCustomizer;\nimport org.springframework.pulsar.core.PulsarAdminBuilderCustomizer;\nimport org.springframework.pulsar.core.PulsarAdministration;\nimport org.springframework.pulsar.core.PulsarClientBuilderCustomizer;\nimport org.springframework.pulsar.core.PulsarClientFactory;\nimport org.springframework.pulsar.core.PulsarConsumerFactory;\nimport org.springframework.pulsar.core.PulsarProducerFactory;\nimport org.springframework.pulsar.core.PulsarReaderFactory;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.pulsar.core.PulsarTopicBuilder;\nimport org.springframework.pulsar.core.ReaderBuilderCustomizer;\nimport org.springframework.pulsar.core.SchemaResolver;\nimport org.springframework.pulsar.core.SchemaResolver.SchemaResolverCustomizer;\nimport org.springframework.pulsar.core.TopicResolver;\nimport org.springframework.pulsar.function.PulsarFunctionAdministration;\nimport org.springframework.pulsar.listener.PulsarContainerProperties.TransactionSettings;\nimport org.springframework.pulsar.transaction.PulsarAwareTransactionManager;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PulsarAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Alexander Preuß\n * @author Soby Chacko\n * @author Phillip Webb\n */\nclass PulsarAutoConfigurationTests {\n\n\tprivate static final String INTERNAL_PULSAR_LISTENER_ANNOTATION_PROCESSOR = \"org.springframework.pulsar.config.internalPulsarListenerAnnotationProcessor\";\n\n\tprivate static final String INTERNAL_PULSAR_READER_ANNOTATION_PROCESSOR = \"org.springframework.pulsar.config.internalPulsarReaderAnnotationProcessor\";\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(PulsarAutoConfiguration.class))\n\t\t.withBean(PulsarClient.class, () -> mock(PulsarClient.class));\n\n\t@Test\n\tvoid whenPulsarNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(PulsarAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(PulsarClient.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenSpringPulsarNotOnClasspathAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(PulsarTemplate.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenCustomPulsarListenerAnnotationProcessorDefinedAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withBean(INTERNAL_PULSAR_LISTENER_ANNOTATION_PROCESSOR, String.class, () -> \"bean\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarBootstrapConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenCustomPulsarReaderAnnotationProcessorDefinedAutoConfigurationIsSkipped() {\n\t\tthis.contextRunner.withBean(INTERNAL_PULSAR_READER_ANNOTATION_PROCESSOR, String.class, () -> \"bean\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarBootstrapConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PulsarConnectionDetails.class)\n\t\t\t.hasSingleBean(DefaultPulsarClientFactory.class)\n\t\t\t.hasSingleBean(PulsarClient.class)\n\t\t\t.hasSingleBean(PulsarTopicBuilder.class)\n\t\t\t.hasSingleBean(PulsarAdministration.class)\n\t\t\t.hasSingleBean(DefaultSchemaResolver.class)\n\t\t\t.hasSingleBean(DefaultTopicResolver.class)\n\t\t\t.hasSingleBean(CachingPulsarProducerFactory.class)\n\t\t\t.hasSingleBean(PulsarTemplate.class)\n\t\t\t.hasSingleBean(DefaultPulsarConsumerFactory.class)\n\t\t\t.hasSingleBean(ConcurrentPulsarListenerContainerFactory.class)\n\t\t\t.hasSingleBean(DefaultPulsarReaderFactory.class)\n\t\t\t.hasSingleBean(DefaultPulsarReaderContainerFactory.class)\n\t\t\t.hasSingleBean(PulsarListenerAnnotationBeanPostProcessor.class)\n\t\t\t.hasSingleBean(PulsarListenerEndpointRegistry.class)\n\t\t\t.hasSingleBean(PulsarReaderAnnotationBeanPostProcessor.class)\n\t\t\t.hasSingleBean(PulsarReaderEndpointRegistry.class));\n\t}\n\n\t@Test\n\tvoid topicDefaultsCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.defaults.topic.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarTopicBuilder.class));\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedConnectionDetailsBeanDoesNotAutoConfigureBean() {\n\t\tPulsarConnectionDetails customConnectionDetails = mock(PulsarConnectionDetails.class);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customPulsarConnectionDetails\", PulsarConnectionDetails.class, () -> customConnectionDetails)\n\t\t\t.run((context) -> assertThat(context).getBean(PulsarConnectionDetails.class)\n\t\t\t\t.isSameAs(customConnectionDetails));\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedContainerFactoryCustomizersBeanDoesNotAutoConfigureBean() {\n\t\tPulsarContainerFactoryCustomizers customizers = mock(PulsarContainerFactoryCustomizers.class);\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customContainerFactoryCustomizers\", PulsarContainerFactoryCustomizers.class, () -> customizers)\n\t\t\t.run((context) -> assertThat(context).getBean(PulsarContainerFactoryCustomizers.class)\n\t\t\t\t.isSameAs(customizers));\n\t}\n\n\t@Nested\n\tclass ClientTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedClientFactoryBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarClientFactory customFactory = mock(PulsarClientFactory.class);\n\t\t\tgiven(customFactory.createClient()).willReturn(mock(PulsarClient.class));\n\t\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(PulsarAutoConfiguration.class))\n\t\t\t\t.withBean(\"customPulsarClientFactory\", PulsarClientFactory.class, () -> customFactory)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarClientFactory.class).isSameAs(customFactory));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedClientBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarClient customClient = mock(PulsarClient.class);\n\t\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(PulsarAutoConfiguration.class))\n\t\t\t\t.withBean(\"customPulsarClient\", PulsarClient.class, () -> customClient)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarClient.class).isSameAs(customClient));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedCustomizersAppliesInCorrectOrder() {\n\t\t\tPulsarConnectionDetails connectionDetails = mock(PulsarConnectionDetails.class);\n\t\t\tgiven(connectionDetails.getBrokerUrl()).willReturn(\"connectiondetails\");\n\t\t\tthis.contextRunner.withUserConfiguration(ClientTests.PulsarClientBuilderCustomizersConfig.class)\n\t\t\t\t.withBean(PulsarConnectionDetails.class, () -> connectionDetails)\n\t\t\t\t.withPropertyValues(\"spring.pulsar.client.service-url=properties\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tDefaultPulsarClientFactory clientFactory = context.getBean(DefaultPulsarClientFactory.class);\n\t\t\t\t\tCustomizers<PulsarClientBuilderCustomizer, ClientBuilder> customizers = Customizers\n\t\t\t\t\t\t.of(ClientBuilder.class, PulsarClientBuilderCustomizer::customize);\n\t\t\t\t\tassertThat(customizers.fromField(clientFactory, \"customizer\")).callsInOrder(\n\t\t\t\t\t\t\tClientBuilder::serviceUrl, \"connectiondetails\", \"fromCustomizer1\", \"fromCustomizer2\");\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedFailoverPropertiesAddsToClient() {\n\t\t\tPulsarConnectionDetails connectionDetails = mock(PulsarConnectionDetails.class);\n\t\t\tgiven(connectionDetails.getBrokerUrl()).willReturn(\"connectiondetails\");\n\t\t\tthis.contextRunner.withBean(PulsarConnectionDetails.class, () -> connectionDetails)\n\t\t\t\t.withPropertyValues(\"spring.pulsar.client.service-url=properties\",\n\t\t\t\t\t\t\"spring.pulsar.client.failover.backup-clusters[0].service-url=backup-cluster-1\",\n\t\t\t\t\t\t\"spring.pulsar.client.failover.delay=15s\",\n\t\t\t\t\t\t\"spring.pulsar.client.failover.switch-back-delay=30s\",\n\t\t\t\t\t\t\"spring.pulsar.client.failover.check-interval=5s\",\n\t\t\t\t\t\t\"spring.pulsar.client.failover.backup-clusters[1].service-url=backup-cluster-2\",\n\t\t\t\t\t\t\"spring.pulsar.client.failover.backup-clusters[1].authentication.plugin-class-name=\"\n\t\t\t\t\t\t\t\t+ MockAuthentication.class.getName(),\n\t\t\t\t\t\t\"spring.pulsar.client.failover.backup-clusters[1].authentication.param.token=1234\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tDefaultPulsarClientFactory clientFactory = context.getBean(DefaultPulsarClientFactory.class);\n\t\t\t\t\tPulsarProperties pulsarProperties = context.getBean(PulsarProperties.class);\n\t\t\t\t\tClientBuilder target = mock(ClientBuilder.class);\n\t\t\t\t\tBiConsumer<PulsarClientBuilderCustomizer, ClientBuilder> customizeAction = PulsarClientBuilderCustomizer::customize;\n\t\t\t\t\tPulsarClientBuilderCustomizer pulsarClientBuilderCustomizer = (PulsarClientBuilderCustomizer) ReflectionTestUtils\n\t\t\t\t\t\t.getField(clientFactory, \"customizer\");\n\t\t\t\t\tcustomizeAction.accept(pulsarClientBuilderCustomizer, target);\n\t\t\t\t\tInOrder ordered = inOrder(target);\n\t\t\t\t\tordered.verify(target).serviceUrlProvider(ArgumentMatchers.any(AutoClusterFailover.class));\n\t\t\t\t\tassertThat(pulsarProperties.getClient().getFailover().getDelay()).isEqualTo(Duration.ofSeconds(15));\n\t\t\t\t\tassertThat(pulsarProperties.getClient().getFailover().getSwitchBackDelay())\n\t\t\t\t\t\t.isEqualTo(Duration.ofSeconds(30));\n\t\t\t\t\tassertThat(pulsarProperties.getClient().getFailover().getCheckInterval())\n\t\t\t\t\t\t.isEqualTo(Duration.ofSeconds(5));\n\t\t\t\t\tassertThat(pulsarProperties.getClient().getFailover().getBackupClusters().size()).isEqualTo(2);\n\t\t\t\t});\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class PulsarClientBuilderCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tPulsarClientBuilderCustomizer customizerFoo() {\n\t\t\t\treturn (builder) -> builder.serviceUrl(\"fromCustomizer2\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tPulsarClientBuilderCustomizer customizerBar() {\n\t\t\t\treturn (builder) -> builder.serviceUrl(\"fromCustomizer1\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass AdministrationTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarAdministration pulsarAdministration = mock(PulsarAdministration.class);\n\t\t\tthis.contextRunner\n\t\t\t\t.withBean(\"customPulsarAdministration\", PulsarAdministration.class, () -> pulsarAdministration)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarAdministration.class)\n\t\t\t\t\t.isSameAs(pulsarAdministration));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedCustomizersAppliesInCorrectOrder() {\n\t\t\tPulsarConnectionDetails connectionDetails = mock(PulsarConnectionDetails.class);\n\t\t\tgiven(connectionDetails.getAdminUrl()).willReturn(\"connectiondetails\");\n\t\t\tthis.contextRunner.withUserConfiguration(AdministrationTests.PulsarAdminBuilderCustomizersConfig.class)\n\t\t\t\t.withBean(PulsarConnectionDetails.class, () -> connectionDetails)\n\t\t\t\t.withPropertyValues(\"spring.pulsar.admin.service-url=property\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tPulsarAdministration pulsarAdmin = context.getBean(PulsarAdministration.class);\n\t\t\t\t\tCustomizers<PulsarAdminBuilderCustomizer, PulsarAdminBuilder> customizers = Customizers\n\t\t\t\t\t\t.of(PulsarAdminBuilder.class, PulsarAdminBuilderCustomizer::customize);\n\t\t\t\t\tassertThat(customizers.fromField(pulsarAdmin, \"adminCustomizers\")).callsInOrder(\n\t\t\t\t\t\t\tPulsarAdminBuilder::serviceHttpUrl, \"connectiondetails\", \"fromCustomizer1\",\n\t\t\t\t\t\t\t\"fromCustomizer2\");\n\t\t\t\t});\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class PulsarAdminBuilderCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tPulsarAdminBuilderCustomizer customizerFoo() {\n\t\t\t\treturn (builder) -> builder.serviceHttpUrl(\"fromCustomizer2\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tPulsarAdminBuilderCustomizer customizerBar() {\n\t\t\t\treturn (builder) -> builder.serviceHttpUrl(\"fromCustomizer1\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass SchemaResolverTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tSchemaResolver schemaResolver = mock(SchemaResolver.class);\n\t\t\tthis.contextRunner.withBean(\"customSchemaResolver\", SchemaResolver.class, () -> schemaResolver)\n\t\t\t\t.run((context) -> assertThat(context).getBean(SchemaResolver.class).isSameAs(schemaResolver));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedSchemaResolverCustomizer() {\n\t\t\tSchemaResolverCustomizer<DefaultSchemaResolver> customizer = (schemaResolver) -> schemaResolver\n\t\t\t\t.addCustomSchemaMapping(TestRecord.class, Schema.STRING);\n\t\t\tthis.contextRunner.withBean(\"schemaResolverCustomizer\", SchemaResolverCustomizer.class, () -> customizer)\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultSchemaResolver.class)\n\t\t\t\t\t.satisfies(customSchemaMappingOf(TestRecord.class, Schema.STRING)));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasDefaultsTypeMappingForPrimitiveAddsToSchemaResolver() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].message-type=\" + TestRecord.CLASS_NAME);\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type=STRING\");\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new))\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultSchemaResolver.class)\n\t\t\t\t\t.satisfies(customSchemaMappingOf(TestRecord.class, Schema.STRING)));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasDefaultsTypeMappingForStructAddsToSchemaResolver() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].message-type=\" + TestRecord.CLASS_NAME);\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type=JSON\");\n\t\t\tSchema<?> expectedSchema = Schema.JSON(TestRecord.class);\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new))\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultSchemaResolver.class)\n\t\t\t\t\t.satisfies(customSchemaMappingOf(TestRecord.class, expectedSchema)));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasDefaultsTypeMappingForKeyValueAddsToSchemaResolver() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].message-type=\" + TestRecord.CLASS_NAME);\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type=key-value\");\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type=java.lang.String\");\n\t\t\tSchema<?> expectedSchema = Schema.KeyValue(Schema.STRING, Schema.JSON(TestRecord.class),\n\t\t\t\t\tKeyValueEncodingType.INLINE);\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new))\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultSchemaResolver.class)\n\t\t\t\t\t.satisfies(customSchemaMappingOf(TestRecord.class, expectedSchema)));\n\t\t}\n\n\t\tprivate ThrowingConsumer<DefaultSchemaResolver> customSchemaMappingOf(Class<?> messageType,\n\t\t\t\tSchema<?> expectedSchema) {\n\t\t\treturn (resolver) -> assertThat(resolver.getCustomSchemaMapping(messageType))\n\t\t\t\t.hasValueSatisfying(schemaEqualTo(expectedSchema));\n\t\t}\n\n\t\tprivate Consumer<Schema<?>> schemaEqualTo(Schema<?> expected) {\n\t\t\treturn (actual) -> assertThat(actual.getSchemaInfo()).isEqualTo(expected.getSchemaInfo());\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass TopicResolverTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tTopicResolver topicResolver = mock(TopicResolver.class);\n\t\t\tthis.contextRunner.withBean(\"customTopicResolver\", TopicResolver.class, () -> topicResolver)\n\t\t\t\t.run((context) -> assertThat(context).getBean(TopicResolver.class).isSameAs(topicResolver));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasDefaultsTypeMappingAddsToSchemaResolver() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].message-type=\" + TestRecord.CLASS_NAME);\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[0].topic-name=foo-topic\");\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[1].message-type=java.lang.String\");\n\t\t\tproperties.add(\"spring.pulsar.defaults.type-mappings[1].topic-name=string-topic\");\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new))\n\t\t\t\t.run((context) -> assertThat(context).getBean(TopicResolver.class)\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(DefaultTopicResolver.class))\n\t\t\t\t\t.satisfies((resolver) -> {\n\t\t\t\t\t\tassertThat(resolver.getCustomTopicMapping(TestRecord.class)).hasValue(\"foo-topic\");\n\t\t\t\t\t\tassertThat(resolver.getCustomTopicMapping(String.class)).hasValue(\"string-topic\");\n\t\t\t\t\t}));\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass TopicBuilderTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarTopicBuilder topicBuilder = mock(PulsarTopicBuilder.class);\n\t\t\tthis.contextRunner.withBean(\"customPulsarTopicBuilder\", PulsarTopicBuilder.class, () -> topicBuilder)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarTopicBuilder.class).isSameAs(topicBuilder));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasDefaultsTopicDisabledPropertyDoesNotCreateBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.defaults.topic.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarTopicBuilder.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasDefaultsTenantAndNamespaceAppliedToTopicBuilder() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.defaults.topic.tenant=my-tenant\");\n\t\t\tproperties.add(\"spring.pulsar.defaults.topic.namespace=my-namespace\");\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new))\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarTopicBuilder.class)\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.type(PulsarTopicBuilder.class))\n\t\t\t\t\t.satisfies((topicBuilder) -> {\n\t\t\t\t\t\tassertThat(topicBuilder).hasFieldOrPropertyWithValue(\"defaultTenant\", \"my-tenant\");\n\t\t\t\t\t\tassertThat(topicBuilder).hasFieldOrPropertyWithValue(\"defaultNamespace\", \"my-namespace\");\n\t\t\t\t\t}));\n\t\t}\n\n\t\t@Test\n\t\tvoid beanHasScopePrototype() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(PulsarTopicBuilder.class))\n\t\t\t\t.isNotSameAs(context.getBean(PulsarTopicBuilder.class)));\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass FunctionAdministrationTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenNoPropertiesAddsFunctionAdministrationBean() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(PulsarFunctionAdministration.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"failFast\", Boolean.TRUE)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"propagateFailures\", Boolean.TRUE)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"propagateStopFailures\", Boolean.FALSE)\n\t\t\t\t.hasNoNullFieldsOrProperties() // ensures object providers set\n\t\t\t\t.extracting(\"pulsarAdministration\")\n\t\t\t\t.isSameAs(context.getBean(PulsarAdministration.class)));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasFunctionPropertiesAppliesPropertiesToBean() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.function.fail-fast=false\");\n\t\t\tproperties.add(\"spring.pulsar.function.propagate-failures=false\");\n\t\t\tproperties.add(\"spring.pulsar.function.propagate-stop-failures=true\");\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new))\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarFunctionAdministration.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"failFast\", Boolean.FALSE)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"propagateFailures\", Boolean.FALSE)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"propagateStopFailures\", Boolean.TRUE));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasFunctionDisabledPropertyDoesNotCreateBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.function.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarFunctionAdministration.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasCustomFunctionAdministrationBean() {\n\t\t\tPulsarFunctionAdministration functionAdministration = mock(PulsarFunctionAdministration.class);\n\t\t\tthis.contextRunner.withBean(PulsarFunctionAdministration.class, () -> functionAdministration)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarFunctionAdministration.class)\n\t\t\t\t\t.isSameAs(functionAdministration));\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ProducerFactoryTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarProducerFactory<String> producerFactory = mock(PulsarProducerFactory.class);\n\t\t\tthis.contextRunner\n\t\t\t\t.withBean(\"customPulsarProducerFactory\", PulsarProducerFactory.class, () -> producerFactory)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarProducerFactory.class).isSameAs(producerFactory));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNoPropertiesUsesCachingPulsarProducerFactory() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(PulsarProducerFactory.class)\n\t\t\t\t.isExactlyInstanceOf(CachingPulsarProducerFactory.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenCachingDisabledUsesDefaultPulsarProducerFactory() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.producer.cache.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarProducerFactory.class)\n\t\t\t\t\t.isExactlyInstanceOf(DefaultPulsarProducerFactory.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenCachingEnabledUsesCachingPulsarProducerFactory() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.producer.cache.enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarProducerFactory.class)\n\t\t\t\t\t.isExactlyInstanceOf(CachingPulsarProducerFactory.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenCachingEnabledAndCaffeineNotOnClasspathStillUsesCaffeine() {\n\t\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class))\n\t\t\t\t.withPropertyValues(\"spring.pulsar.producer.cache.enabled=true\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tassertThat(context).getBean(CachingPulsarProducerFactory.class)\n\t\t\t\t\t\t.extracting(\"producerCache\")\n\t\t\t\t\t\t.extracting(Object::getClass)\n\t\t\t\t\t\t.isEqualTo(CaffeineCacheProvider.class);\n\t\t\t\t\tassertThat(context).getBean(CachingPulsarProducerFactory.class)\n\t\t\t\t\t\t.extracting(\"producerCache.cache\")\n\t\t\t\t\t\t.extracting(Object::getClass)\n\t\t\t\t\t\t.extracting(Class::getName)\n\t\t\t\t\t\t.asString()\n\t\t\t\t\t\t.startsWith(\"org.springframework.pulsar.shade.com.github.benmanes.caffeine.cache.\");\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenCustomCachingPropertiesCreatesConfiguredBean() {\n\t\t\tthis.contextRunner\n\t\t\t\t.withPropertyValues(\"spring.pulsar.producer.cache.expire-after-access=100s\",\n\t\t\t\t\t\t\"spring.pulsar.producer.cache.maximum-size=5150\",\n\t\t\t\t\t\t\"spring.pulsar.producer.cache.initial-capacity=200\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(CachingPulsarProducerFactory.class)\n\t\t\t\t\t.extracting(\"producerCache.cache.cache\")\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"maximum\", 5150L)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"expiresAfterAccessNanos\", TimeUnit.SECONDS.toNanos(100)));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasTopicNamePropertyCreatesConfiguredBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.producer.topic-name=my-topic\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultPulsarProducerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"defaultTopic\", \"my-topic\"));\n\t\t}\n\n\t\t@Test\n\t\tvoid injectsExpectedBeans() {\n\t\t\tthis.contextRunner\n\t\t\t\t.withPropertyValues(\"spring.pulsar.producer.topic-name=my-topic\",\n\t\t\t\t\t\t\"spring.pulsar.producer.cache.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultPulsarProducerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"pulsarClient\", context.getBean(PulsarClient.class))\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"topicResolver\", context.getBean(TopicResolver.class))\n\t\t\t\t\t.extracting(\"topicBuilder\")\n\t\t\t\t\t.isNotNull());\n\t\t}\n\n\t\t@Test\n\t\tvoid hasNoTopicBuilderWhenTopicDefaultsAreDisabled() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.defaults.topic.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultPulsarProducerFactory.class)\n\t\t\t\t\t.extracting(\"topicBuilder\")\n\t\t\t\t\t.isNull());\n\t\t}\n\n\t\t@ParameterizedTest\n\t\t@ValueSource(booleans = { true, false })\n\t\t<T> void whenHasUserDefinedCustomizersAppliesInCorrectOrder(boolean cachingEnabled) {\n\t\t\tthis.contextRunner\n\t\t\t\t.withPropertyValues(\"spring.pulsar.producer.cache.enabled=\" + cachingEnabled,\n\t\t\t\t\t\t\"spring.pulsar.producer.name=fromPropsCustomizer\")\n\t\t\t\t.withUserConfiguration(ProducerBuilderCustomizersConfig.class)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tDefaultPulsarProducerFactory<?> producerFactory = context\n\t\t\t\t\t\t.getBean(DefaultPulsarProducerFactory.class);\n\t\t\t\t\tCustomizers<ProducerBuilderCustomizer<T>, ProducerBuilder<T>> customizers = Customizers\n\t\t\t\t\t\t.of(ProducerBuilder.class, ProducerBuilderCustomizer::customize);\n\t\t\t\t\tassertThat(customizers.fromField(producerFactory, \"defaultConfigCustomizers\")).callsInOrder(\n\t\t\t\t\t\t\tProducerBuilder::producerName, \"fromPropsCustomizer\", \"fromCustomizer1\", \"fromCustomizer2\");\n\t\t\t\t});\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class ProducerBuilderCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tProducerBuilderCustomizer<?> customizerFoo() {\n\t\t\t\treturn (builder) -> builder.producerName(\"fromCustomizer2\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tProducerBuilderCustomizer<?> customizerBar() {\n\t\t\t\treturn (builder) -> builder.producerName(\"fromCustomizer1\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass TemplateTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarTemplate<String> template = mock(PulsarTemplate.class);\n\t\t\tthis.contextRunner.withBean(\"customPulsarTemplate\", PulsarTemplate.class, () -> template)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarTemplate.class).isSameAs(template));\n\t\t}\n\n\t\t@Test\n\t\tvoid injectsExpectedBeans() {\n\t\t\tPulsarProducerFactory<?> producerFactory = mock(PulsarProducerFactory.class);\n\t\t\tSchemaResolver schemaResolver = mock(SchemaResolver.class);\n\t\t\tTopicResolver topicResolver = mock(TopicResolver.class);\n\t\t\tthis.contextRunner\n\t\t\t\t.withBean(\"customPulsarProducerFactory\", PulsarProducerFactory.class, () -> producerFactory)\n\t\t\t\t.withBean(\"schemaResolver\", SchemaResolver.class, () -> schemaResolver)\n\t\t\t\t.withBean(\"topicResolver\", TopicResolver.class, () -> topicResolver)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarTemplate.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"producerFactory\", producerFactory)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"schemaResolver\", schemaResolver)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"topicResolver\", topicResolver));\n\t\t}\n\n\t\t@Test\n\t\t<T> void whenHasUseDefinedProducerInterceptorInjectsBean() {\n\t\t\tProducerInterceptor interceptor = mock(ProducerInterceptor.class);\n\t\t\tthis.contextRunner.withBean(\"customProducerInterceptor\", ProducerInterceptor.class, () -> interceptor)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tPulsarTemplate<?> pulsarTemplate = context.getBean(PulsarTemplate.class);\n\t\t\t\t\tCustomizers<ProducerBuilderCustomizer<T>, ProducerBuilder<T>> customizers = Customizers\n\t\t\t\t\t\t.of(ProducerBuilder.class, ProducerBuilderCustomizer::customize);\n\t\t\t\t\tassertThat(customizers.fromField(pulsarTemplate, \"interceptorsCustomizers\"))\n\t\t\t\t\t\t.callsInOrder(ProducerBuilder::intercept, interceptor);\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\t<T> void whenHasUseDefinedProducerInterceptorsInjectsBeansInCorrectOrder() {\n\t\t\tthis.contextRunner.withUserConfiguration(InterceptorTestConfiguration.class).run((context) -> {\n\t\t\t\tProducerInterceptor interceptorFoo = context.getBean(\"interceptorFoo\", ProducerInterceptor.class);\n\t\t\t\tProducerInterceptor interceptorBar = context.getBean(\"interceptorBar\", ProducerInterceptor.class);\n\t\t\t\tPulsarTemplate<?> pulsarTemplate = context.getBean(PulsarTemplate.class);\n\t\t\t\tCustomizers<ProducerBuilderCustomizer<T>, ProducerBuilder<T>> customizers = Customizers\n\t\t\t\t\t.of(ProducerBuilder.class, ProducerBuilderCustomizer::customize);\n\t\t\t\tassertThat(customizers.fromField(pulsarTemplate, \"interceptorsCustomizers\"))\n\t\t\t\t\t.callsInOrder(ProducerBuilder::intercept, interceptorBar, interceptorFoo);\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNoPropertiesEnablesObservation() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(PulsarTemplate.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"observationEnabled\", false));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenObservationsEnabledEnablesObservation() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.template.observations-enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarTemplate.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"observationEnabled\", true));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenObservationsDisabledDoesNotEnableObservation() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.template.observations-enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarTemplate.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"observationEnabled\", false));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenTransactionEnabledTrueEnablesTransactions() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.transaction.enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context.getBean(PulsarTemplate.class).transactions().isEnabled())\n\t\t\t\t\t.isTrue());\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class InterceptorTestConfiguration {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tProducerInterceptor interceptorFoo() {\n\t\t\t\treturn mock(ProducerInterceptor.class);\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tProducerInterceptor interceptorBar() {\n\t\t\t\treturn mock(ProducerInterceptor.class);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ConsumerFactoryTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarConsumerFactory<String> consumerFactory = mock(PulsarConsumerFactory.class);\n\t\t\tthis.contextRunner\n\t\t\t\t.withBean(\"customPulsarConsumerFactory\", PulsarConsumerFactory.class, () -> consumerFactory)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarConsumerFactory.class).isSameAs(consumerFactory));\n\t\t}\n\n\t\t@Test\n\t\tvoid injectsExpectedBeans() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(DefaultPulsarConsumerFactory.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"pulsarClient\", context.getBean(PulsarClient.class))\n\t\t\t\t.extracting(\"topicBuilder\")\n\t\t\t\t.isNotNull());\n\t\t}\n\n\t\t@Test\n\t\tvoid hasNoTopicBuilderWhenTopicDefaultsAreDisabled() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.defaults.topic.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultPulsarConsumerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"pulsarClient\", context.getBean(PulsarClient.class))\n\t\t\t\t\t.extracting(\"topicBuilder\")\n\t\t\t\t\t.isNull());\n\t\t}\n\n\t\t@Test\n\t\t<T> void whenHasUserDefinedCustomizersAppliesInCorrectOrder() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.consumer.name=fromPropsCustomizer\")\n\t\t\t\t.withUserConfiguration(ConsumerBuilderCustomizersConfig.class)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tDefaultPulsarConsumerFactory<?> consumerFactory = context\n\t\t\t\t\t\t.getBean(DefaultPulsarConsumerFactory.class);\n\t\t\t\t\tCustomizers<ConsumerBuilderCustomizer<T>, ConsumerBuilder<T>> customizers = Customizers\n\t\t\t\t\t\t.of(ConsumerBuilder.class, ConsumerBuilderCustomizer::customize);\n\t\t\t\t\tassertThat(customizers.fromField(consumerFactory, \"defaultConfigCustomizers\")).callsInOrder(\n\t\t\t\t\t\t\tConsumerBuilder::consumerName, \"fromPropsCustomizer\", \"fromCustomizer1\", \"fromCustomizer2\");\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid injectsExpectedBeanWithExplicitGenericType() {\n\t\t\tthis.contextRunner.withBean(ExplicitGenericTypeConfig.class)\n\t\t\t\t.run((context) -> assertThat(context).getBean(ExplicitGenericTypeConfig.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"consumerFactory\", context.getBean(PulsarConsumerFactory.class))\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"containerFactory\",\n\t\t\t\t\t\t\tcontext.getBean(ConcurrentPulsarListenerContainerFactory.class)));\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class ConsumerBuilderCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tConsumerBuilderCustomizer<?> customizerFoo() {\n\t\t\t\treturn (builder) -> builder.consumerName(\"fromCustomizer2\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tConsumerBuilderCustomizer<?> customizerBar() {\n\t\t\t\treturn (builder) -> builder.consumerName(\"fromCustomizer1\");\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class ExplicitGenericTypeConfig {\n\n\t\t\t@Autowired\n\t\t\tPulsarConsumerFactory<TestType> consumerFactory;\n\n\t\t\t@Autowired\n\t\t\tConcurrentPulsarListenerContainerFactory<TestType> containerFactory;\n\n\t\t\tstatic class TestType {\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ListenerTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedListenerContainerFactoryBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarListenerContainerFactory listenerContainerFactory = mock(PulsarListenerContainerFactory.class);\n\t\t\tthis.contextRunner\n\t\t\t\t.withBean(\"pulsarListenerContainerFactory\", PulsarListenerContainerFactory.class,\n\t\t\t\t\t\t() -> listenerContainerFactory)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarListenerContainerFactory.class)\n\t\t\t\t\t.isSameAs(listenerContainerFactory));\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tvoid injectsExpectedBeans() {\n\t\t\tPulsarConsumerFactory<?> consumerFactory = mock(PulsarConsumerFactory.class);\n\t\t\tSchemaResolver schemaResolver = mock(SchemaResolver.class);\n\t\t\tTopicResolver topicResolver = mock(TopicResolver.class);\n\t\t\tthis.contextRunner.withBean(\"pulsarConsumerFactory\", PulsarConsumerFactory.class, () -> consumerFactory)\n\t\t\t\t.withBean(\"schemaResolver\", SchemaResolver.class, () -> schemaResolver)\n\t\t\t\t.withBean(\"topicResolver\", TopicResolver.class, () -> topicResolver)\n\t\t\t\t.run((context) -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"consumerFactory\", consumerFactory)\n\t\t\t\t\t.extracting(ConcurrentPulsarListenerContainerFactory::getContainerProperties)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"schemaResolver\", schemaResolver)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"topicResolver\", topicResolver));\n\t\t}\n\n\t\t@Test\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid whenHasUserDefinedListenerAnnotationBeanPostProcessorBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarListenerAnnotationBeanPostProcessor<String> listenerAnnotationBeanPostProcessor = mock(\n\t\t\t\t\tPulsarListenerAnnotationBeanPostProcessor.class);\n\t\t\tthis.contextRunner\n\t\t\t\t.withBean(\"org.springframework.pulsar.config.internalPulsarListenerAnnotationProcessor\",\n\t\t\t\t\t\tPulsarListenerAnnotationBeanPostProcessor.class, () -> listenerAnnotationBeanPostProcessor)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarListenerAnnotationBeanPostProcessor.class)\n\t\t\t\t\t.isSameAs(listenerAnnotationBeanPostProcessor));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasCustomProperties() {\n\t\t\tList<String> properties = new ArrayList<>();\n\t\t\tproperties.add(\"spring.pulsar.listener.schema-type=avro\");\n\t\t\tthis.contextRunner.withPropertyValues(properties.toArray(String[]::new)).run((context) -> {\n\t\t\t\tConcurrentPulsarListenerContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(ConcurrentPulsarListenerContainerFactory.class);\n\t\t\t\tassertThat(factory.getContainerProperties().getSchemaType()).isEqualTo(SchemaType.AVRO);\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNoPropertiesEnablesObservation() {\n\t\t\tthis.contextRunner\n\t\t\t\t.run((context) -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"containerProperties.observationEnabled\", false));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenObservationsEnabledEnablesObservation() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.listener.observation-enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"containerProperties.observationEnabled\", true));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenObservationsDisabledDoesNotEnableObservation() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.listener.observation-enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"containerProperties.observationEnabled\", false));\n\t\t}\n\n\t\t@Test\n\t\t@EnabledForJreRange(min = JRE.JAVA_21)\n\t\tvoid whenVirtualThreadsAreEnabledOnJava21AndLaterListenerContainerShouldUseVirtualThreads() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\t\tConcurrentPulsarListenerContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(ConcurrentPulsarListenerContainerFactory.class);\n\t\t\t\tassertThat(factory.getContainerProperties().getConsumerTaskExecutor())\n\t\t\t\t\t.isInstanceOf(VirtualThreadTaskExecutor.class);\n\t\t\t\tObject taskExecutor = factory.getContainerProperties().getConsumerTaskExecutor();\n\t\t\t\tObject virtualThread = ReflectionTestUtils.getField(taskExecutor, \"virtualThreadFactory\");\n\t\t\t\tassertThat(virtualThread).isNotNull();\n\t\t\t\tThread threadCreated = ((ThreadFactory) virtualThread).newThread(mock(Runnable.class));\n\t\t\t\tassertThat(threadCreated.getName()).containsPattern(\"pulsar-consumer-[0-9]+\");\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\t@EnabledForJreRange(max = JRE.JAVA_20)\n\t\tvoid whenVirtualThreadsAreEnabledOnJava20AndEarlierListenerContainerShouldNotUseVirtualThreads() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\t\tConcurrentPulsarListenerContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(ConcurrentPulsarListenerContainerFactory.class);\n\t\t\t\tassertThat(factory.getContainerProperties().getConsumerTaskExecutor()).isNull();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenTransactionEnabledTrueListenerContainerShouldUseTransactions() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.transaction.enabled=true\").run((context) -> {\n\t\t\t\tConcurrentPulsarListenerContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(ConcurrentPulsarListenerContainerFactory.class);\n\t\t\t\tTransactionSettings transactions = factory.getContainerProperties().transactions();\n\t\t\t\tassertThat(transactions.isEnabled()).isTrue();\n\t\t\t\tassertThat(transactions.getTransactionManager()).isNotNull();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenTransactionEnabledFalseListenerContainerShouldNotUseTransactions() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.transaction.enabled=false\").run((context) -> {\n\t\t\t\tConcurrentPulsarListenerContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(ConcurrentPulsarListenerContainerFactory.class);\n\t\t\t\tTransactionSettings transactions = factory.getContainerProperties().transactions();\n\t\t\t\tassertThat(transactions.isEnabled()).isFalse();\n\t\t\t\tassertThat(transactions.getTransactionManager()).isNull();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedCustomizersAppliesInCorrectOrder() {\n\t\t\tthis.contextRunner.withUserConfiguration(ListenerContainerFactoryCustomizersConfig.class)\n\t\t\t\t.run((context) -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"containerProperties.subscriptionName\", \":bar:foo\"));\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class ListenerContainerFactoryCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tPulsarContainerFactoryCustomizer<ConcurrentPulsarListenerContainerFactory<?>> customizerFoo() {\n\t\t\t\treturn (containerFactory) -> appendToSubscriptionName(containerFactory, \":foo\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tPulsarContainerFactoryCustomizer<ConcurrentPulsarListenerContainerFactory<?>> customizerBar() {\n\t\t\t\treturn (containerFactory) -> appendToSubscriptionName(containerFactory, \":bar\");\n\t\t\t}\n\n\t\t\tprivate void appendToSubscriptionName(ConcurrentPulsarListenerContainerFactory<?> containerFactory,\n\t\t\t\t\tString valueToAppend) {\n\t\t\t\tString subscriptionName = containerFactory.getContainerProperties().getSubscriptionName();\n\t\t\t\tString updatedValue = (subscriptionName != null) ? subscriptionName + valueToAppend : valueToAppend;\n\t\t\t\tcontainerFactory.getContainerProperties().setSubscriptionName(updatedValue);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ReaderFactoryTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid whenHasUserDefinedBeanDoesNotAutoConfigureBean() {\n\t\t\tPulsarReaderFactory<String> readerFactory = mock(PulsarReaderFactory.class);\n\t\t\tthis.contextRunner.withBean(\"customPulsarReaderFactory\", PulsarReaderFactory.class, () -> readerFactory)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarReaderFactory.class).isSameAs(readerFactory));\n\t\t}\n\n\t\t@Test\n\t\tvoid injectsExpectedBeans() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).getBean(DefaultPulsarReaderFactory.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"pulsarClient\", context.getBean(PulsarClient.class))\n\t\t\t\t.extracting(\"topicBuilder\")\n\t\t\t\t.isNotNull());\n\t\t}\n\n\t\t@Test\n\t\tvoid hasNoTopicBuilderWhenTopicDefaultsAreDisabled() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.defaults.topic.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultPulsarReaderFactory.class)\n\t\t\t\t\t.extracting(\"topicBuilder\")\n\t\t\t\t\t.isNull());\n\t\t}\n\n\t\t@Test\n\t\t<T> void whenHasUserDefinedReaderBuilderCustomizersAppliesInCorrectOrder() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.reader.name=fromPropsCustomizer\")\n\t\t\t\t.withUserConfiguration(ReaderBuilderCustomizersConfig.class)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tDefaultPulsarReaderFactory<?> readerFactory = context.getBean(DefaultPulsarReaderFactory.class);\n\t\t\t\t\tCustomizers<ReaderBuilderCustomizer<T>, ReaderBuilder<T>> customizers = Customizers\n\t\t\t\t\t\t.of(ReaderBuilder.class, ReaderBuilderCustomizer::customize);\n\t\t\t\t\tassertThat(customizers.fromField(readerFactory, \"defaultConfigCustomizers\")).callsInOrder(\n\t\t\t\t\t\t\tReaderBuilder::readerName, \"fromPropsCustomizer\", \"fromCustomizer1\", \"fromCustomizer2\");\n\t\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\t@EnabledForJreRange(min = JRE.JAVA_21)\n\t\tvoid whenVirtualThreadsAreEnabledOnJava21AndLaterReaderShouldUseVirtualThreads() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\t\tDefaultPulsarReaderContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(DefaultPulsarReaderContainerFactory.class);\n\t\t\t\tassertThat(factory.getContainerProperties().getReaderTaskExecutor())\n\t\t\t\t\t.isInstanceOf(VirtualThreadTaskExecutor.class);\n\t\t\t\tObject taskExecutor = factory.getContainerProperties().getReaderTaskExecutor();\n\t\t\t\tObject virtualThread = ReflectionTestUtils.getField(taskExecutor, \"virtualThreadFactory\");\n\t\t\t\tassertThat(virtualThread).isNotNull();\n\t\t\t\tThread threadCreated = ((ThreadFactory) virtualThread).newThread(mock(Runnable.class));\n\t\t\t\tassertThat(threadCreated.getName()).containsPattern(\"pulsar-reader-[0-9]+\");\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\t@EnabledForJreRange(max = JRE.JAVA_20)\n\t\tvoid whenVirtualThreadsAreEnabledOnJava20AndEarlierReaderShouldNotUseVirtualThreads() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\").run((context) -> {\n\t\t\t\tDefaultPulsarReaderContainerFactory<?> factory = context\n\t\t\t\t\t.getBean(DefaultPulsarReaderContainerFactory.class);\n\t\t\t\tassertThat(factory.getContainerProperties().getReaderTaskExecutor()).isNull();\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid whenHasUserDefinedFactoryCustomizersAppliesInCorrectOrder() {\n\t\t\tthis.contextRunner.withUserConfiguration(ReaderContainerFactoryCustomizersConfig.class)\n\t\t\t\t.run((context) -> assertThat(context).getBean(DefaultPulsarReaderContainerFactory.class)\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"containerProperties.readerListener\", \":bar:foo\"));\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class ReaderBuilderCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tReaderBuilderCustomizer<?> customizerFoo() {\n\t\t\t\treturn (builder) -> builder.readerName(\"fromCustomizer2\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tReaderBuilderCustomizer<?> customizerBar() {\n\t\t\t\treturn (builder) -> builder.readerName(\"fromCustomizer1\");\n\t\t\t}\n\n\t\t}\n\n\t\t@TestConfiguration(proxyBeanMethods = false)\n\t\tstatic class ReaderContainerFactoryCustomizersConfig {\n\n\t\t\t@Bean\n\t\t\t@Order(200)\n\t\t\tPulsarContainerFactoryCustomizer<DefaultPulsarReaderContainerFactory<?>> customizerFoo() {\n\t\t\t\treturn (containerFactory) -> appendToReaderListener(containerFactory, \":foo\");\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(100)\n\t\t\tPulsarContainerFactoryCustomizer<DefaultPulsarReaderContainerFactory<?>> customizerBar() {\n\t\t\t\treturn (containerFactory) -> appendToReaderListener(containerFactory, \":bar\");\n\t\t\t}\n\n\t\t\tprivate void appendToReaderListener(DefaultPulsarReaderContainerFactory<?> containerFactory,\n\t\t\t\t\tString valueToAppend) {\n\t\t\t\tObject readerListener = containerFactory.getContainerProperties().getReaderListener();\n\t\t\t\tString updatedValue = (readerListener != null) ? readerListener + valueToAppend : valueToAppend;\n\t\t\t\tcontainerFactory.getContainerProperties().setReaderListener(updatedValue);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass TransactionManagerTests {\n\n\t\tprivate final ApplicationContextRunner contextRunner = PulsarAutoConfigurationTests.this.contextRunner;\n\n\t\t@Test\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid whenUserHasDefinedATransactionManagerTheAutoConfigurationBacksOff() {\n\t\t\tPulsarAwareTransactionManager txnMgr = mock(PulsarAwareTransactionManager.class);\n\t\t\tthis.contextRunner.withBean(\"customTransactionManager\", PulsarAwareTransactionManager.class, () -> txnMgr)\n\t\t\t\t.run((context) -> assertThat(context).getBean(PulsarAwareTransactionManager.class).isSameAs(txnMgr));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenNoPropertiesAreSetTransactionManagerShouldNotBeDefined() {\n\t\t\tthis.contextRunner\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarAwareTransactionManager.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenTransactionEnabledFalseTransactionManagerIsNotAutoConfigured() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.transaction.enabled=false\")\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PulsarAwareTransactionManager.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid whenTransactionEnabledTrueTransactionManagerIsAutoConfigured() {\n\t\t\tthis.contextRunner.withPropertyValues(\"spring.pulsar.transaction.enabled=true\")\n\t\t\t\t.run((context) -> assertThat(context).hasSingleBean(PulsarAwareTransactionManager.class));\n\t\t}\n\n\t}\n\n\trecord TestRecord() {\n\n\t\tprivate static final String CLASS_NAME = TestRecord.class.getName();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/PulsarContainerFactoryCustomizersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.pulsar.config.ConcurrentPulsarListenerContainerFactory;\nimport org.springframework.pulsar.config.DefaultPulsarReaderContainerFactory;\nimport org.springframework.pulsar.config.ListenerContainerFactory;\nimport org.springframework.pulsar.config.PulsarContainerFactory;\nimport org.springframework.pulsar.core.PulsarConsumerFactory;\nimport org.springframework.pulsar.listener.PulsarContainerProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link PulsarContainerFactoryCustomizers}.\n *\n * @author Chris Bono\n */\nclass PulsarContainerFactoryCustomizersTests {\n\n\t@Test\n\tvoid customizeWithNullCustomizersShouldDoNothing() {\n\t\tPulsarContainerFactory<?, ?> containerFactory = mock(PulsarContainerFactory.class);\n\t\tnew PulsarContainerFactoryCustomizers(null).customize(containerFactory);\n\t\tthen(containerFactory).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid customizeSimplePulsarContainerFactory() {\n\t\tPulsarContainerFactoryCustomizers customizers = new PulsarContainerFactoryCustomizers(\n\t\t\t\tCollections.singletonList(new SimplePulsarContainerFactoryCustomizer()));\n\t\tPulsarContainerProperties containerProperties = new PulsarContainerProperties();\n\t\tConcurrentPulsarListenerContainerFactory<String> pulsarContainerFactory = new ConcurrentPulsarListenerContainerFactory<>(\n\t\t\t\tmock(PulsarConsumerFactory.class), containerProperties);\n\t\tcustomizers.customize(pulsarContainerFactory);\n\t\tassertThat(pulsarContainerFactory.getContainerProperties().getSubscriptionName()).isEqualTo(\"my-subscription\");\n\t}\n\n\t@Test\n\tvoid customizeShouldCheckGeneric() {\n\t\tList<TestCustomizer<?>> list = new ArrayList<>();\n\t\tlist.add(new TestCustomizer<>());\n\t\tlist.add(new TestPulsarListenersContainerFactoryCustomizer());\n\t\tlist.add(new TestConcurrentPulsarListenerContainerFactoryCustomizer());\n\t\tPulsarContainerFactoryCustomizers customizers = new PulsarContainerFactoryCustomizers(list);\n\n\t\tcustomizers.customize(mock(PulsarContainerFactory.class));\n\t\tassertThat(list.get(0).getCount()).isOne();\n\t\tassertThat(list.get(1).getCount()).isZero();\n\t\tassertThat(list.get(2).getCount()).isZero();\n\n\t\tcustomizers.customize(mock(ListenerContainerFactory.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t\tassertThat(list.get(2).getCount()).isZero();\n\n\t\tcustomizers.customize(mock(ConcurrentPulsarListenerContainerFactory.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(3);\n\t\tassertThat(list.get(1).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(2).getCount()).isOne();\n\n\t\tcustomizers.customize(mock(DefaultPulsarReaderContainerFactory.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(4);\n\t\tassertThat(list.get(1).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(2).getCount()).isOne();\n\t}\n\n\tstatic class SimplePulsarContainerFactoryCustomizer\n\t\t\timplements PulsarContainerFactoryCustomizer<ConcurrentPulsarListenerContainerFactory<?>> {\n\n\t\t@Override\n\t\tpublic void customize(ConcurrentPulsarListenerContainerFactory<?> containerFactory) {\n\t\t\tcontainerFactory.getContainerProperties().setSubscriptionName(\"my-subscription\");\n\t\t}\n\n\t}\n\n\t/**\n\t * Test customizer that will match all {@link PulsarContainerFactory}.\n\t *\n\t * @param <T> the container factory type\n\t */\n\tstatic class TestCustomizer<T extends PulsarContainerFactory<?, ?>> implements PulsarContainerFactoryCustomizer<T> {\n\n\t\tprivate int count;\n\n\t\t@Override\n\t\tpublic void customize(T pulsarContainerFactory) {\n\t\t\tthis.count++;\n\t\t}\n\n\t\tint getCount() {\n\t\t\treturn this.count;\n\t\t}\n\n\t}\n\n\t/**\n\t * Test customizer that will match all {@link ListenerContainerFactory}.\n\t */\n\tstatic class TestPulsarListenersContainerFactoryCustomizer extends TestCustomizer<ListenerContainerFactory<?, ?>> {\n\n\t}\n\n\t/**\n\t * Test customizer that will match only\n\t * {@link ConcurrentPulsarListenerContainerFactory}.\n\t */\n\tstatic class TestConcurrentPulsarListenerContainerFactoryCustomizer\n\t\t\textends TestCustomizer<ConcurrentPulsarListenerContainerFactory<?>> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/PulsarPropertiesMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.TimeUnit;\nimport java.util.regex.Pattern;\n\nimport org.apache.pulsar.client.admin.PulsarAdminBuilder;\nimport org.apache.pulsar.client.api.AutoClusterFailoverBuilder.FailoverPolicy;\nimport org.apache.pulsar.client.api.ClientBuilder;\nimport org.apache.pulsar.client.api.CompressionType;\nimport org.apache.pulsar.client.api.ConsumerBuilder;\nimport org.apache.pulsar.client.api.DeadLetterPolicy;\nimport org.apache.pulsar.client.api.HashingScheme;\nimport org.apache.pulsar.client.api.MessageRoutingMode;\nimport org.apache.pulsar.client.api.ProducerAccessMode;\nimport org.apache.pulsar.client.api.ProducerBuilder;\nimport org.apache.pulsar.client.api.PulsarClientException.UnsupportedAuthenticationException;\nimport org.apache.pulsar.client.api.ReaderBuilder;\nimport org.apache.pulsar.client.api.SubscriptionType;\nimport org.apache.pulsar.client.impl.AutoClusterFailover;\nimport org.apache.pulsar.common.schema.SchemaType;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Consumer;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Failover.BackupCluster;\nimport org.springframework.pulsar.core.PulsarProducerFactory;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.pulsar.listener.PulsarContainerProperties;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link PulsarPropertiesMapper}.\n *\n * @author Chris Bono\n * @author Phillip Webb\n * @author Swamy Mavuri\n * @author Vedran Pavic\n */\nclass PulsarPropertiesMapperTests {\n\n\t@Test\n\tvoid customizeClientBuilderWhenHasNoAuthentication() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getClient().setServiceUrl(\"https://example.com\");\n\t\tproperties.getClient().setConnectionTimeout(Duration.ofSeconds(1));\n\t\tproperties.getClient().setOperationTimeout(Duration.ofSeconds(2));\n\t\tproperties.getClient().setLookupTimeout(Duration.ofSeconds(3));\n\t\tproperties.getClient().getThreads().setIo(3);\n\t\tproperties.getClient().getThreads().setListener(10);\n\t\tClientBuilder builder = mock(ClientBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeClientBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should().serviceUrl(\"https://example.com\");\n\t\tthen(builder).should().connectionTimeout(1000, TimeUnit.MILLISECONDS);\n\t\tthen(builder).should().operationTimeout(2000, TimeUnit.MILLISECONDS);\n\t\tthen(builder).should().lookupTimeout(3000, TimeUnit.MILLISECONDS);\n\t\tthen(builder).should().ioThreads(3);\n\t\tthen(builder).should().listenerThreads(10);\n\t}\n\n\t@Test\n\tvoid customizeClientBuilderWhenHasAuthentication() throws UnsupportedAuthenticationException {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tMap<String, String> params = Map.of(\"simpleParam\", \"foo\", \"complexParam\",\n\t\t\t\t\"{\\n\\t\\\"k1\\\" : \\\"v1\\\",\\n\\t\\\"k2\\\":\\\"v2\\\"\\n}\");\n\t\tString authParamString = \"{\\\"complexParam\\\":\\\"{\\\\n\\\\t\\\\\\\"k1\\\\\\\" : \\\\\\\"v1\\\\\\\",\\\\n\\\\t\\\\\\\"k2\\\\\\\":\\\\\\\"v2\\\\\\\"\\\\n}\\\"\"\n\t\t\t\t+ \",\\\"simpleParam\\\":\\\"foo\\\"}\";\n\t\tproperties.getClient().getAuthentication().setPluginClassName(\"myclass\");\n\t\tproperties.getClient().getAuthentication().setParam(params);\n\t\tClientBuilder builder = mock(ClientBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeClientBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should().authentication(\"myclass\", authParamString);\n\t}\n\n\t@Test\n\tvoid customizeClientBuilderWhenTransactionEnabled() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getTransaction().setEnabled(true);\n\t\tClientBuilder builder = mock(ClientBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeClientBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should().enableTransaction(true);\n\t}\n\n\t@Test\n\tvoid customizeClientBuilderWhenTransactionDisabled() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getTransaction().setEnabled(false);\n\t\tClientBuilder builder = mock(ClientBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeClientBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should(never()).enableTransaction(anyBoolean());\n\t}\n\n\t@Test\n\tvoid customizeClientBuilderWhenHasConnectionDetails() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getClient().setServiceUrl(\"https://ignored.example.com\");\n\t\tClientBuilder builder = mock(ClientBuilder.class);\n\t\tPulsarConnectionDetails connectionDetails = mock(PulsarConnectionDetails.class);\n\t\tgiven(connectionDetails.getBrokerUrl()).willReturn(\"https://used.example.com\");\n\t\tnew PulsarPropertiesMapper(properties).customizeClientBuilder(builder, connectionDetails);\n\t\tthen(builder).should().serviceUrl(\"https://used.example.com\");\n\t}\n\n\t@Test\n\tvoid customizeClientBuilderWhenHasFailover() {\n\t\tBackupCluster backupCluster1 = new BackupCluster();\n\t\tbackupCluster1.setServiceUrl(\"backup-cluster-1\");\n\t\tMap<String, String> params = Map.of(\"param\", \"name\");\n\t\tbackupCluster1.getAuthentication().setPluginClassName(MockAuthentication.class.getName());\n\t\tbackupCluster1.getAuthentication().setParam(params);\n\t\tBackupCluster backupCluster2 = new BackupCluster();\n\t\tbackupCluster2.setServiceUrl(\"backup-cluster-2\");\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getClient().setServiceUrl(\"https://used.example.com\");\n\t\tproperties.getClient().getFailover().setPolicy(FailoverPolicy.ORDER);\n\t\tproperties.getClient().getFailover().setCheckInterval(Duration.ofSeconds(5));\n\t\tproperties.getClient().getFailover().setDelay(Duration.ofSeconds(30));\n\t\tproperties.getClient().getFailover().setSwitchBackDelay(Duration.ofSeconds(30));\n\t\tproperties.getClient().getFailover().setBackupClusters(List.of(backupCluster1, backupCluster2));\n\t\tPulsarConnectionDetails connectionDetails = mock(PulsarConnectionDetails.class);\n\t\tgiven(connectionDetails.getBrokerUrl()).willReturn(\"https://used.example.com\");\n\t\tClientBuilder builder = mock(ClientBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeClientBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should().serviceUrlProvider(any(AutoClusterFailover.class));\n\t}\n\n\t@Test\n\tvoid customizeAdminBuilderWhenHasNoAuthentication() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getAdmin().setServiceUrl(\"https://example.com\");\n\t\tproperties.getAdmin().setConnectionTimeout(Duration.ofSeconds(1));\n\t\tproperties.getAdmin().setReadTimeout(Duration.ofSeconds(2));\n\t\tproperties.getAdmin().setRequestTimeout(Duration.ofSeconds(3));\n\t\tPulsarAdminBuilder builder = mock(PulsarAdminBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeAdminBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should().serviceHttpUrl(\"https://example.com\");\n\t\tthen(builder).should().connectionTimeout(1000, TimeUnit.MILLISECONDS);\n\t\tthen(builder).should().readTimeout(2000, TimeUnit.MILLISECONDS);\n\t\tthen(builder).should().requestTimeout(3000, TimeUnit.MILLISECONDS);\n\t}\n\n\t@Test\n\tvoid customizeAdminBuilderWhenHasAuthentication() throws UnsupportedAuthenticationException {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tMap<String, String> params = Map.of(\"simpleParam\", \"foo\", \"complexParam\",\n\t\t\t\t\"{\\n\\t\\\"k1\\\" : \\\"v1\\\",\\n\\t\\\"k2\\\":\\\"v2\\\"\\n}\");\n\t\tString authParamString = \"{\\\"complexParam\\\":\\\"{\\\\n\\\\t\\\\\\\"k1\\\\\\\" : \\\\\\\"v1\\\\\\\",\\\\n\\\\t\\\\\\\"k2\\\\\\\":\\\\\\\"v2\\\\\\\"\\\\n}\\\"\"\n\t\t\t\t+ \",\\\"simpleParam\\\":\\\"foo\\\"}\";\n\t\tproperties.getAdmin().getAuthentication().setPluginClassName(\"myclass\");\n\t\tproperties.getAdmin().getAuthentication().setParam(params);\n\t\tPulsarAdminBuilder builder = mock(PulsarAdminBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeAdminBuilder(builder,\n\t\t\t\tnew PropertiesPulsarConnectionDetails(properties));\n\t\tthen(builder).should().authentication(\"myclass\", authParamString);\n\t}\n\n\t@Test\n\tvoid customizeAdminBuilderWhenHasConnectionDetails() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getAdmin().setServiceUrl(\"https://ignored.example.com\");\n\t\tPulsarAdminBuilder builder = mock(PulsarAdminBuilder.class);\n\t\tPulsarConnectionDetails connectionDetails = mock(PulsarConnectionDetails.class);\n\t\tgiven(connectionDetails.getAdminUrl()).willReturn(\"https://used.example.com\");\n\t\tnew PulsarPropertiesMapper(properties).customizeAdminBuilder(builder, connectionDetails);\n\t\tthen(builder).should().serviceHttpUrl(\"https://used.example.com\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeProducerBuilder() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getProducer().setName(\"name\");\n\t\tproperties.getProducer().setTopicName(\"topicname\");\n\t\tproperties.getProducer().setSendTimeout(Duration.ofSeconds(1));\n\t\tproperties.getProducer().setMessageRoutingMode(MessageRoutingMode.RoundRobinPartition);\n\t\tproperties.getProducer().setHashingScheme(HashingScheme.JavaStringHash);\n\t\tproperties.getProducer().setBatchingEnabled(false);\n\t\tproperties.getProducer().setChunkingEnabled(true);\n\t\tproperties.getProducer().setCompressionType(CompressionType.SNAPPY);\n\t\tproperties.getProducer().setAccessMode(ProducerAccessMode.Exclusive);\n\t\tProducerBuilder<Object> builder = mock(ProducerBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeProducerBuilder(builder);\n\t\tthen(builder).should().producerName(\"name\");\n\t\tthen(builder).should().topic(\"topicname\");\n\t\tthen(builder).should().sendTimeout(1000, TimeUnit.MILLISECONDS);\n\t\tthen(builder).should().messageRoutingMode(MessageRoutingMode.RoundRobinPartition);\n\t\tthen(builder).should().hashingScheme(HashingScheme.JavaStringHash);\n\t\tthen(builder).should().enableBatching(false);\n\t\tthen(builder).should().enableChunking(true);\n\t\tthen(builder).should().compressionType(CompressionType.SNAPPY);\n\t\tthen(builder).should().accessMode(ProducerAccessMode.Exclusive);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeTemplate() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getTransaction().setEnabled(true);\n\t\tPulsarTemplate<Object> template = new PulsarTemplate<>(mock(PulsarProducerFactory.class));\n\t\tnew PulsarPropertiesMapper(properties).customizeTemplate(template);\n\t\tassertThat(template.transactions().isEnabled()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeConsumerBuilder() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tList<String> topics = List.of(\"mytopic\");\n\t\tPattern topisPattern = Pattern.compile(\"my-pattern\");\n\t\tproperties.getConsumer().setName(\"name\");\n\t\tproperties.getConsumer().setTopics(topics);\n\t\tproperties.getConsumer().setTopicsPattern(topisPattern);\n\t\tproperties.getConsumer().setPriorityLevel(123);\n\t\tproperties.getConsumer().setReadCompacted(true);\n\t\tConsumer.DeadLetterPolicy deadLetterPolicy = new Consumer.DeadLetterPolicy();\n\t\tdeadLetterPolicy.setDeadLetterTopic(\"my-dlt\");\n\t\tdeadLetterPolicy.setMaxRedeliverCount(1);\n\t\tproperties.getConsumer().setDeadLetterPolicy(deadLetterPolicy);\n\t\tConsumerBuilder<Object> builder = mock(ConsumerBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeConsumerBuilder(builder);\n\t\tthen(builder).should().consumerName(\"name\");\n\t\tthen(builder).should().topics(topics);\n\t\tthen(builder).should().topicsPattern(topisPattern);\n\t\tthen(builder).should().priorityLevel(123);\n\t\tthen(builder).should().readCompacted(true);\n\t\tthen(builder).should().deadLetterPolicy(new DeadLetterPolicy(1, null, \"my-dlt\", null, null, null));\n\t}\n\n\t@Test\n\tvoid customizeContainerProperties() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tproperties.getConsumer().getSubscription().setType(SubscriptionType.Shared);\n\t\tproperties.getConsumer().getSubscription().setName(\"my-subscription\");\n\t\tproperties.getListener().setSchemaType(SchemaType.AVRO);\n\t\tproperties.getListener().setConcurrency(10);\n\t\tproperties.getListener().setObservationEnabled(true);\n\t\tproperties.getTransaction().setEnabled(true);\n\t\tPulsarContainerProperties containerProperties = new PulsarContainerProperties(\"my-topic-pattern\");\n\t\tnew PulsarPropertiesMapper(properties).customizeContainerProperties(containerProperties);\n\t\tassertThat(containerProperties.getSubscriptionType()).isEqualTo(SubscriptionType.Shared);\n\t\tassertThat(containerProperties.getSubscriptionName()).isEqualTo(\"my-subscription\");\n\t\tassertThat(containerProperties.getSchemaType()).isEqualTo(SchemaType.AVRO);\n\t\tassertThat(containerProperties.getConcurrency()).isEqualTo(10);\n\t\tassertThat(containerProperties.isObservationEnabled()).isTrue();\n\t\tassertThat(containerProperties.transactions().isEnabled()).isTrue();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customizeReaderBuilder() {\n\t\tPulsarProperties properties = new PulsarProperties();\n\t\tList<String> topics = List.of(\"mytopic\");\n\t\tproperties.getReader().setName(\"name\");\n\t\tproperties.getReader().setTopics(topics);\n\t\tproperties.getReader().setSubscriptionName(\"subname\");\n\t\tproperties.getReader().setSubscriptionRolePrefix(\"subroleprefix\");\n\t\tproperties.getReader().setReadCompacted(true);\n\t\tReaderBuilder<Object> builder = mock(ReaderBuilder.class);\n\t\tnew PulsarPropertiesMapper(properties).customizeReaderBuilder(builder);\n\t\tthen(builder).should().readerName(\"name\");\n\t\tthen(builder).should().topics(topics);\n\t\tthen(builder).should().subscriptionName(\"subname\");\n\t\tthen(builder).should().subscriptionRolePrefix(\"subroleprefix\");\n\t\tthen(builder).should().readCompacted(true);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-pulsar/src/test/java/org/springframework/boot/pulsar/autoconfigure/PulsarPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.pulsar.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\nimport org.apache.pulsar.client.api.CompressionType;\nimport org.apache.pulsar.client.api.HashingScheme;\nimport org.apache.pulsar.client.api.MessageRoutingMode;\nimport org.apache.pulsar.client.api.ProducerAccessMode;\nimport org.apache.pulsar.client.api.RegexSubscriptionMode;\nimport org.apache.pulsar.client.api.SubscriptionInitialPosition;\nimport org.apache.pulsar.client.api.SubscriptionMode;\nimport org.apache.pulsar.client.api.SubscriptionType;\nimport org.apache.pulsar.common.schema.SchemaType;\nimport org.assertj.core.extractor.Extractors;\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Defaults.SchemaInfo;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Defaults.TypeMapping;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Failover;\nimport org.springframework.boot.pulsar.autoconfigure.PulsarProperties.Failover.BackupCluster;\nimport org.springframework.pulsar.core.PulsarTopicBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link PulsarProperties}.\n *\n * @author Chris Bono\n * @author Christophe Bornet\n * @author Soby Chacko\n * @author Phillip Webb\n * @author Swamy Mavuri\n * @author Vedran Pavic\n */\nclass PulsarPropertiesTests {\n\n\tprivate PulsarProperties bindProperties(Map<String, String> map) {\n\t\treturn new Binder(new MapConfigurationPropertySource(map)).bind(\"spring.pulsar\", PulsarProperties.class).get();\n\t}\n\n\t@Nested\n\tclass ClientProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.client.service-url\", \"my-service-url\");\n\t\t\tmap.put(\"spring.pulsar.client.operation-timeout\", \"1s\");\n\t\t\tmap.put(\"spring.pulsar.client.lookup-timeout\", \"2s\");\n\t\t\tmap.put(\"spring.pulsar.client.connection-timeout\", \"12s\");\n\t\t\tPulsarProperties.Client properties = bindProperties(map).getClient();\n\t\t\tassertThat(properties.getServiceUrl()).isEqualTo(\"my-service-url\");\n\t\t\tassertThat(properties.getOperationTimeout()).isEqualTo(Duration.ofMillis(1000));\n\t\t\tassertThat(properties.getLookupTimeout()).isEqualTo(Duration.ofMillis(2000));\n\t\t\tassertThat(properties.getConnectionTimeout()).isEqualTo(Duration.ofMillis(12000));\n\t\t}\n\n\t\t@Test\n\t\tvoid bindAuthentication() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.client.authentication.plugin-class-name\", \"com.example.MyAuth\");\n\t\t\tmap.put(\"spring.pulsar.client.authentication.param.token\", \"1234\");\n\t\t\tPulsarProperties.Client properties = bindProperties(map).getClient();\n\t\t\tassertThat(properties.getAuthentication().getPluginClassName()).isEqualTo(\"com.example.MyAuth\");\n\t\t\tassertThat(properties.getAuthentication().getParam()).containsEntry(\"token\", \"1234\");\n\t\t}\n\n\t\t@Test\n\t\tvoid bindThread() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.client.threads.io\", \"3\");\n\t\t\tmap.put(\"spring.pulsar.client.threads.listener\", \"10\");\n\t\t\tPulsarProperties.Client properties = bindProperties(map).getClient();\n\t\t\tassertThat(properties.getThreads().getIo()).isEqualTo(3);\n\t\t\tassertThat(properties.getThreads().getListener()).isEqualTo(10);\n\t\t}\n\n\t\t@Test\n\t\tvoid bindFailover() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.client.service-url\", \"my-service-url\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.delay\", \"30s\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.switch-back-delay\", \"15s\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.check-interval\", \"1s\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.backup-clusters[0].service-url\", \"backup-service-url-1\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.backup-clusters[0].authentication.plugin-class-name\",\n\t\t\t\t\t\"com.example.MyAuth1\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.backup-clusters[0].authentication.param.token\", \"1234\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.backup-clusters[1].service-url\", \"backup-service-url-2\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.backup-clusters[1].authentication.plugin-class-name\",\n\t\t\t\t\t\"com.example.MyAuth2\");\n\t\t\tmap.put(\"spring.pulsar.client.failover.backup-clusters[1].authentication.param.token\", \"5678\");\n\t\t\tPulsarProperties.Client properties = bindProperties(map).getClient();\n\t\t\tFailover failoverProperties = properties.getFailover();\n\t\t\tList<BackupCluster> backupClusters = properties.getFailover().getBackupClusters();\n\t\t\tassertThat(properties.getServiceUrl()).isEqualTo(\"my-service-url\");\n\t\t\tassertThat(failoverProperties.getDelay()).isEqualTo(Duration.ofMillis(30000));\n\t\t\tassertThat(failoverProperties.getSwitchBackDelay()).isEqualTo(Duration.ofMillis(15000));\n\t\t\tassertThat(failoverProperties.getCheckInterval()).isEqualTo(Duration.ofMillis(1000));\n\t\t\tassertThat(backupClusters.get(0).getServiceUrl()).isEqualTo(\"backup-service-url-1\");\n\t\t\tassertThat(backupClusters.get(0).getAuthentication().getPluginClassName()).isEqualTo(\"com.example.MyAuth1\");\n\t\t\tassertThat(backupClusters.get(0).getAuthentication().getParam()).containsEntry(\"token\", \"1234\");\n\t\t\tassertThat(backupClusters.get(1).getServiceUrl()).isEqualTo(\"backup-service-url-2\");\n\t\t\tassertThat(backupClusters.get(1).getAuthentication().getPluginClassName()).isEqualTo(\"com.example.MyAuth2\");\n\t\t\tassertThat(backupClusters.get(1).getAuthentication().getParam()).containsEntry(\"token\", \"5678\");\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass AdminProperties {\n\n\t\tprivate final String authPluginClassName = \"org.apache.pulsar.client.impl.auth.AuthenticationToken\";\n\n\t\tprivate final String authToken = \"1234\";\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.admin.service-url\", \"my-service-url\");\n\t\t\tmap.put(\"spring.pulsar.admin.connection-timeout\", \"12s\");\n\t\t\tmap.put(\"spring.pulsar.admin.read-timeout\", \"13s\");\n\t\t\tmap.put(\"spring.pulsar.admin.request-timeout\", \"14s\");\n\t\t\tPulsarProperties.Admin properties = bindProperties(map).getAdmin();\n\t\t\tassertThat(properties.getServiceUrl()).isEqualTo(\"my-service-url\");\n\t\t\tassertThat(properties.getConnectionTimeout()).isEqualTo(Duration.ofSeconds(12));\n\t\t\tassertThat(properties.getReadTimeout()).isEqualTo(Duration.ofSeconds(13));\n\t\t\tassertThat(properties.getRequestTimeout()).isEqualTo(Duration.ofSeconds(14));\n\t\t}\n\n\t\t@Test\n\t\tvoid bindAuthentication() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.admin.authentication.plugin-class-name\", this.authPluginClassName);\n\t\t\tmap.put(\"spring.pulsar.admin.authentication.param.token\", this.authToken);\n\t\t\tPulsarProperties.Admin properties = bindProperties(map).getAdmin();\n\t\t\tassertThat(properties.getAuthentication().getPluginClassName()).isEqualTo(this.authPluginClassName);\n\t\t\tassertThat(properties.getAuthentication().getParam()).containsEntry(\"token\", this.authToken);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass DefaultsTypeMappingProperties {\n\n\t\t@Test\n\t\tvoid bindWhenNoTypeMappings() {\n\t\t\tassertThat(new PulsarProperties().getDefaults().getTypeMappings()).isEmpty();\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenTypeMappingsWithTopicsOnly() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].topic-name\", \"foo-topic\");\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[1].message-type\", String.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[1].topic-name\", \"string-topic\");\n\t\t\tPulsarProperties.Defaults properties = bindProperties(map).getDefaults();\n\t\t\tTypeMapping expectedTopic1 = new TypeMapping(TestMessage.class, \"foo-topic\", null);\n\t\t\tTypeMapping expectedTopic2 = new TypeMapping(String.class, \"string-topic\", null);\n\t\t\tassertThat(properties.getTypeMappings()).containsExactly(expectedTopic1, expectedTopic2);\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenTypeMappingsWithSchemaOnly() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type\", \"JSON\");\n\t\t\tPulsarProperties.Defaults properties = bindProperties(map).getDefaults();\n\t\t\tTypeMapping expected = new TypeMapping(TestMessage.class, null, new SchemaInfo(SchemaType.JSON, null));\n\t\t\tassertThat(properties.getTypeMappings()).containsExactly(expected);\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenTypeMappingsWithTopicAndSchema() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].topic-name\", \"foo-topic\");\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type\", \"JSON\");\n\t\t\tPulsarProperties.Defaults properties = bindProperties(map).getDefaults();\n\t\t\tTypeMapping expected = new TypeMapping(TestMessage.class, \"foo-topic\",\n\t\t\t\t\tnew SchemaInfo(SchemaType.JSON, null));\n\t\t\tassertThat(properties.getTypeMappings()).containsExactly(expected);\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenTypeMappingsWithKeyValueSchema() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type\", \"KEY_VALUE\");\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type\", String.class.getName());\n\t\t\tPulsarProperties.Defaults properties = bindProperties(map).getDefaults();\n\t\t\tTypeMapping expected = new TypeMapping(TestMessage.class, null,\n\t\t\t\t\tnew SchemaInfo(SchemaType.KEY_VALUE, String.class));\n\t\t\tassertThat(properties.getTypeMappings()).containsExactly(expected);\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenNoSchemaThrowsException() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type\", String.class.getName());\n\t\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bindProperties(map))\n\t\t\t\t.havingRootCause()\n\t\t\t\t.withMessageContaining(\"'schemaType' must not be null\");\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenSchemaTypeNoneThrowsException() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type\", \"NONE\");\n\t\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bindProperties(map))\n\t\t\t\t.havingRootCause()\n\t\t\t\t.withMessageContaining(\"'schemaType' must not be NONE\");\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenMessageKeyTypeSetOnNonKeyValueSchemaThrowsException() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].message-type\", TestMessage.class.getName());\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.schema-type\", \"JSON\");\n\t\t\tmap.put(\"spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type\", String.class.getName());\n\t\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bindProperties(map))\n\t\t\t\t.havingRootCause()\n\t\t\t\t.withMessageContaining(\"'messageKeyType' can only be set when 'schemaType' is KEY_VALUE\");\n\t\t}\n\n\t\trecord TestMessage(String value) {\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass DefaultsTenantNamespaceProperties {\n\n\t\t@Test\n\t\tvoid bindWhenValuesNotSpecified() {\n\t\t\tPulsarTopicBuilder defaultTopicBuilder = new PulsarTopicBuilder();\n\t\t\tassertThat(new PulsarProperties().getDefaults().getTopic()).satisfies((defaults) -> {\n\t\t\t\tassertThat(defaults.getTenant())\n\t\t\t\t\t.isEqualTo(Extractors.byName(\"defaultTenant\").apply(defaultTopicBuilder));\n\t\t\t\tassertThat(defaults.getNamespace())\n\t\t\t\t\t.isEqualTo(Extractors.byName(\"defaultNamespace\").apply(defaultTopicBuilder));\n\t\t\t});\n\t\t}\n\n\t\t@Test\n\t\tvoid bindWhenValuesSpecified() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.defaults.topic.tenant\", \"my-tenant\");\n\t\t\tmap.put(\"spring.pulsar.defaults.topic.namespace\", \"my-namespace\");\n\t\t\tPulsarProperties.Defaults.Topic properties = bindProperties(map).getDefaults().getTopic();\n\t\t\tassertThat(properties.getTenant()).isEqualTo(\"my-tenant\");\n\t\t\tassertThat(properties.getNamespace()).isEqualTo(\"my-namespace\");\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass FunctionProperties {\n\n\t\t@Test\n\t\tvoid defaults() {\n\t\t\tPulsarProperties.Function properties = new PulsarProperties.Function();\n\t\t\tassertThat(properties.isFailFast()).isTrue();\n\t\t\tassertThat(properties.isPropagateFailures()).isTrue();\n\t\t\tassertThat(properties.isPropagateStopFailures()).isFalse();\n\t\t}\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> props = new HashMap<>();\n\t\t\tprops.put(\"spring.pulsar.function.fail-fast\", \"false\");\n\t\t\tprops.put(\"spring.pulsar.function.propagate-failures\", \"false\");\n\t\t\tprops.put(\"spring.pulsar.function.propagate-stop-failures\", \"true\");\n\t\t\tPulsarProperties.Function properties = bindProperties(props).getFunction();\n\t\t\tassertThat(properties.isFailFast()).isFalse();\n\t\t\tassertThat(properties.isPropagateFailures()).isFalse();\n\t\t\tassertThat(properties.isPropagateStopFailures()).isTrue();\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ProducerProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.producer.name\", \"my-producer\");\n\t\t\tmap.put(\"spring.pulsar.producer.topic-name\", \"my-topic\");\n\t\t\tmap.put(\"spring.pulsar.producer.send-timeout\", \"2s\");\n\t\t\tmap.put(\"spring.pulsar.producer.message-routing-mode\", \"custompartition\");\n\t\t\tmap.put(\"spring.pulsar.producer.hashing-scheme\", \"murmur3_32hash\");\n\t\t\tmap.put(\"spring.pulsar.producer.batching-enabled\", \"false\");\n\t\t\tmap.put(\"spring.pulsar.producer.chunking-enabled\", \"true\");\n\t\t\tmap.put(\"spring.pulsar.producer.compression-type\", \"lz4\");\n\t\t\tmap.put(\"spring.pulsar.producer.access-mode\", \"exclusive\");\n\t\t\tmap.put(\"spring.pulsar.producer.cache.expire-after-access\", \"2s\");\n\t\t\tmap.put(\"spring.pulsar.producer.cache.maximum-size\", \"3\");\n\t\t\tmap.put(\"spring.pulsar.producer.cache.initial-capacity\", \"5\");\n\t\t\tPulsarProperties.Producer properties = bindProperties(map).getProducer();\n\t\t\tassertThat(properties.getName()).isEqualTo(\"my-producer\");\n\t\t\tassertThat(properties.getTopicName()).isEqualTo(\"my-topic\");\n\t\t\tassertThat(properties.getSendTimeout()).isEqualTo(Duration.ofSeconds(2));\n\t\t\tassertThat(properties.getMessageRoutingMode()).isEqualTo(MessageRoutingMode.CustomPartition);\n\t\t\tassertThat(properties.getHashingScheme()).isEqualTo(HashingScheme.Murmur3_32Hash);\n\t\t\tassertThat(properties.isBatchingEnabled()).isFalse();\n\t\t\tassertThat(properties.isChunkingEnabled()).isTrue();\n\t\t\tassertThat(properties.getCompressionType()).isEqualTo(CompressionType.LZ4);\n\t\t\tassertThat(properties.getAccessMode()).isEqualTo(ProducerAccessMode.Exclusive);\n\t\t\tassertThat(properties.getCache().getExpireAfterAccess()).isEqualTo(Duration.ofSeconds(2));\n\t\t\tassertThat(properties.getCache().getMaximumSize()).isEqualTo(3);\n\t\t\tassertThat(properties.getCache().getInitialCapacity()).isEqualTo(5);\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ConsumerPropertiesTests {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.consumer.name\", \"my-consumer\");\n\t\t\tmap.put(\"spring.pulsar.consumer.subscription.initial-position\", \"earliest\");\n\t\t\tmap.put(\"spring.pulsar.consumer.subscription.mode\", \"nondurable\");\n\t\t\tmap.put(\"spring.pulsar.consumer.subscription.name\", \"my-subscription\");\n\t\t\tmap.put(\"spring.pulsar.consumer.subscription.topics-mode\", \"all-topics\");\n\t\t\tmap.put(\"spring.pulsar.consumer.subscription.type\", \"shared\");\n\t\t\tmap.put(\"spring.pulsar.consumer.topics[0]\", \"my-topic\");\n\t\t\tmap.put(\"spring.pulsar.consumer.topics-pattern\", \"my-pattern\");\n\t\t\tmap.put(\"spring.pulsar.consumer.priority-level\", \"8\");\n\t\t\tmap.put(\"spring.pulsar.consumer.read-compacted\", \"true\");\n\t\t\tmap.put(\"spring.pulsar.consumer.dead-letter-policy.max-redeliver-count\", \"4\");\n\t\t\tmap.put(\"spring.pulsar.consumer.dead-letter-policy.retry-letter-topic\", \"my-retry-topic\");\n\t\t\tmap.put(\"spring.pulsar.consumer.dead-letter-policy.dead-letter-topic\", \"my-dlt-topic\");\n\t\t\tmap.put(\"spring.pulsar.consumer.dead-letter-policy.initial-subscription-name\", \"my-initial-subscription\");\n\t\t\tmap.put(\"spring.pulsar.consumer.retry-enable\", \"true\");\n\t\t\tPulsarProperties.Consumer properties = bindProperties(map).getConsumer();\n\t\t\tassertThat(properties.getName()).isEqualTo(\"my-consumer\");\n\t\t\tassertThat(properties.getSubscription()).satisfies((subscription) -> {\n\t\t\t\tassertThat(subscription.getName()).isEqualTo(\"my-subscription\");\n\t\t\t\tassertThat(subscription.getType()).isEqualTo(SubscriptionType.Shared);\n\t\t\t\tassertThat(subscription.getMode()).isEqualTo(SubscriptionMode.NonDurable);\n\t\t\t\tassertThat(subscription.getInitialPosition()).isEqualTo(SubscriptionInitialPosition.Earliest);\n\t\t\t\tassertThat(subscription.getTopicsMode()).isEqualTo(RegexSubscriptionMode.AllTopics);\n\t\t\t});\n\t\t\tassertThat(properties.getTopics()).containsExactly(\"my-topic\");\n\t\t\tPattern topicsPattern = properties.getTopicsPattern();\n\t\t\tassertThat(topicsPattern).isNotNull();\n\t\t\tassertThat(topicsPattern.toString()).isEqualTo(\"my-pattern\");\n\t\t\tassertThat(properties.getPriorityLevel()).isEqualTo(8);\n\t\t\tassertThat(properties.isReadCompacted()).isTrue();\n\t\t\tassertThat(properties.getDeadLetterPolicy()).satisfies((policy) -> {\n\t\t\t\tassertThat(policy.getMaxRedeliverCount()).isEqualTo(4);\n\t\t\t\tassertThat(policy.getRetryLetterTopic()).isEqualTo(\"my-retry-topic\");\n\t\t\t\tassertThat(policy.getDeadLetterTopic()).isEqualTo(\"my-dlt-topic\");\n\t\t\t\tassertThat(policy.getInitialSubscriptionName()).isEqualTo(\"my-initial-subscription\");\n\t\t\t});\n\t\t\tassertThat(properties.isRetryEnable()).isTrue();\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ListenerProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.listener.schema-type\", \"avro\");\n\t\t\tmap.put(\"spring.pulsar.listener.concurrency\", \"10\");\n\t\t\tmap.put(\"spring.pulsar.listener.observation-enabled\", \"true\");\n\t\t\tPulsarProperties.Listener properties = bindProperties(map).getListener();\n\t\t\tassertThat(properties.getSchemaType()).isEqualTo(SchemaType.AVRO);\n\t\t\tassertThat(properties.getConcurrency()).isEqualTo(10);\n\t\t\tassertThat(properties.isObservationEnabled()).isTrue();\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ReaderProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.reader.name\", \"my-reader\");\n\t\t\tmap.put(\"spring.pulsar.reader.topics\", \"my-topic\");\n\t\t\tmap.put(\"spring.pulsar.reader.subscription-name\", \"my-subscription\");\n\t\t\tmap.put(\"spring.pulsar.reader.subscription-role-prefix\", \"sub-role\");\n\t\t\tmap.put(\"spring.pulsar.reader.read-compacted\", \"true\");\n\t\t\tPulsarProperties.Reader properties = bindProperties(map).getReader();\n\t\t\tassertThat(properties.getName()).isEqualTo(\"my-reader\");\n\t\t\tassertThat(properties.getTopics()).containsExactly(\"my-topic\");\n\t\t\tassertThat(properties.getSubscriptionName()).isEqualTo(\"my-subscription\");\n\t\t\tassertThat(properties.getSubscriptionRolePrefix()).isEqualTo(\"sub-role\");\n\t\t\tassertThat(properties.isReadCompacted()).isTrue();\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass TemplateProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.template.observations-enabled\", \"true\");\n\t\t\tPulsarProperties.Template properties = bindProperties(map).getTemplate();\n\t\t\tassertThat(properties.isObservationsEnabled()).isTrue();\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass TransactionProperties {\n\n\t\t@Test\n\t\tvoid bind() {\n\t\t\tMap<String, String> map = new HashMap<>();\n\t\t\tmap.put(\"spring.pulsar.transaction.enabled\", \"true\");\n\t\t\tPulsarProperties.Transaction properties = bindProperties(map).getTransaction();\n\t\t\tassertThat(properties.isEnabled()).isTrue();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Quartz\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.quartz-scheduler:quartz\")\n\tapi(\"org.springframework:spring-context-support\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jdbc\"))\n\toptional(project(\":module:spring-boot-hibernate\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-liquibase\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-sql\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-jersey\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webflux\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webmvc\")))\n\ttestImplementation(\"net.minidev:json-smart\")\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.h2database:h2\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/actuate/endpoint/QuartzEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.LocalTime;\nimport java.time.temporal.ChronoUnit;\nimport java.time.temporal.TemporalUnit;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\nimport org.quartz.CalendarIntervalTrigger;\nimport org.quartz.CronTrigger;\nimport org.quartz.DailyTimeIntervalTrigger;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.TimeOfDay;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.utils.Key;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.SanitizableData;\nimport org.springframework.boot.actuate.endpoint.Sanitizer;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint} to expose Quartz Scheduler jobs and triggers.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Endpoint(id = \"quartz\")\npublic class QuartzEndpoint {\n\n\tprivate static final Comparator<Trigger> TRIGGER_COMPARATOR = Comparator\n\t\t.comparing(Trigger::getNextFireTime, Comparator.nullsLast(Comparator.naturalOrder()))\n\t\t.thenComparing(Comparator.comparingInt(Trigger::getPriority).reversed());\n\n\tprivate final Scheduler scheduler;\n\n\tprivate final Sanitizer sanitizer;\n\n\tpublic QuartzEndpoint(Scheduler scheduler, Iterable<SanitizingFunction> sanitizingFunctions) {\n\t\tAssert.notNull(scheduler, \"'scheduler' must not be null\");\n\t\tthis.scheduler = scheduler;\n\t\tthis.sanitizer = new Sanitizer(sanitizingFunctions);\n\t}\n\n\t/**\n\t * Return the available job and trigger group names.\n\t * @return a report of the available group names\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\t@ReadOperation\n\tpublic QuartzDescriptor quartzReport() throws SchedulerException {\n\t\treturn new QuartzDescriptor(new GroupNamesDescriptor(this.scheduler.getJobGroupNames()),\n\t\t\t\tnew GroupNamesDescriptor(this.scheduler.getTriggerGroupNames()));\n\t}\n\n\t/**\n\t * Return the available job names, identified by group name.\n\t * @return the available job names\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\tpublic QuartzGroupsDescriptor quartzJobGroups() throws SchedulerException {\n\t\tMap<String, Object> result = new LinkedHashMap<>();\n\t\tfor (String groupName : this.scheduler.getJobGroupNames()) {\n\t\t\tList<String> jobs = this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))\n\t\t\t\t.stream()\n\t\t\t\t.map(Key::getName)\n\t\t\t\t.toList();\n\t\t\tresult.put(groupName, Collections.singletonMap(\"jobs\", jobs));\n\t\t}\n\t\treturn new QuartzGroupsDescriptor(result);\n\t}\n\n\t/**\n\t * Return the available trigger names, identified by group name.\n\t * @return the available trigger names\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\tpublic QuartzGroupsDescriptor quartzTriggerGroups() throws SchedulerException {\n\t\tMap<String, Object> result = new LinkedHashMap<>();\n\t\tSet<String> pausedTriggerGroups = this.scheduler.getPausedTriggerGroups();\n\t\tfor (String groupName : this.scheduler.getTriggerGroupNames()) {\n\t\t\tMap<String, Object> groupDetails = new LinkedHashMap<>();\n\t\t\tgroupDetails.put(\"paused\", pausedTriggerGroups.contains(groupName));\n\t\t\tgroupDetails.put(\"triggers\",\n\t\t\t\t\tthis.scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(groupName))\n\t\t\t\t\t\t.stream()\n\t\t\t\t\t\t.map(Key::getName)\n\t\t\t\t\t\t.toList());\n\t\t\tresult.put(groupName, groupDetails);\n\t\t}\n\t\treturn new QuartzGroupsDescriptor(result);\n\t}\n\n\t/**\n\t * Return a summary of the jobs group with the specified name or {@code null} if no\n\t * such group exists.\n\t * @param group the name of a jobs group\n\t * @return a summary of the jobs in the given {@code group}\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\tpublic @Nullable QuartzJobGroupSummaryDescriptor quartzJobGroupSummary(String group) throws SchedulerException {\n\t\tList<JobDetail> jobs = findJobsByGroup(group);\n\t\tif (jobs.isEmpty() && !this.scheduler.getJobGroupNames().contains(group)) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<String, QuartzJobSummaryDescriptor> result = new LinkedHashMap<>();\n\t\tfor (JobDetail job : jobs) {\n\t\t\tresult.put(job.getKey().getName(), QuartzJobSummaryDescriptor.of(job));\n\t\t}\n\t\treturn new QuartzJobGroupSummaryDescriptor(group, result);\n\t}\n\n\tprivate List<JobDetail> findJobsByGroup(String group) throws SchedulerException {\n\t\tList<JobDetail> jobs = new ArrayList<>();\n\t\tSet<JobKey> jobKeys = this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group));\n\t\tfor (JobKey jobKey : jobKeys) {\n\t\t\tjobs.add(this.scheduler.getJobDetail(jobKey));\n\t\t}\n\t\treturn jobs;\n\t}\n\n\t/**\n\t * Return a summary of the triggers group with the specified name or {@code null} if\n\t * no such group exists.\n\t * @param group the name of a triggers group\n\t * @return a summary of the triggers in the given {@code group}\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\tpublic @Nullable QuartzTriggerGroupSummaryDescriptor quartzTriggerGroupSummary(String group)\n\t\t\tthrows SchedulerException {\n\t\tList<Trigger> triggers = findTriggersByGroup(group);\n\t\tif (triggers.isEmpty() && !this.scheduler.getTriggerGroupNames().contains(group)) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<TriggerType, Map<String, Object>> result = new LinkedHashMap<>();\n\t\ttriggers.forEach((trigger) -> {\n\t\t\tTriggerDescriptor triggerDescriptor = TriggerDescriptor.of(trigger);\n\t\t\tMap<String, Object> triggerTypes = result.computeIfAbsent(triggerDescriptor.getType(),\n\t\t\t\t\t(key) -> new LinkedHashMap<>());\n\t\t\ttriggerTypes.put(trigger.getKey().getName(), triggerDescriptor.buildSummary(true));\n\t\t});\n\t\tboolean paused = this.scheduler.getPausedTriggerGroups().contains(group);\n\t\treturn new QuartzTriggerGroupSummaryDescriptor(group, paused, result);\n\t}\n\n\tprivate List<Trigger> findTriggersByGroup(String group) throws SchedulerException {\n\t\tList<Trigger> triggers = new ArrayList<>();\n\t\tSet<TriggerKey> triggerKeys = this.scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(group));\n\t\tfor (TriggerKey triggerKey : triggerKeys) {\n\t\t\ttriggers.add(this.scheduler.getTrigger(triggerKey));\n\t\t}\n\t\treturn triggers;\n\t}\n\n\t/**\n\t * Return the {@link QuartzJobDetailsDescriptor details of the job} identified with\n\t * the given group name and job name.\n\t * @param groupName the name of the group\n\t * @param jobName the name of the job\n\t * @param showUnsanitized whether to sanitize values in data map\n\t * @return the details of the job or {@code null} if such job does not exist\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\tpublic @Nullable QuartzJobDetailsDescriptor quartzJob(String groupName, String jobName, boolean showUnsanitized)\n\t\t\tthrows SchedulerException {\n\t\tJobKey jobKey = JobKey.jobKey(jobName, groupName);\n\t\tJobDetail jobDetail = this.scheduler.getJobDetail(jobKey);\n\t\tif (jobDetail == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<? extends Trigger> triggers = this.scheduler.getTriggersOfJob(jobKey);\n\t\treturn new QuartzJobDetailsDescriptor(jobDetail, sanitizeJobDataMap(jobDetail.getJobDataMap(), showUnsanitized),\n\t\t\t\textractTriggersSummary(triggers));\n\t}\n\n\t/**\n\t * Triggers (execute it now) a Quartz job by its group and job name.\n\t * @param groupName the name of the job's group\n\t * @param jobName the name of the job\n\t * @return a description of the triggered job or {@code null} if the job does not\n\t * exist\n\t * @throws SchedulerException if there is an error triggering the job\n\t */\n\tpublic @Nullable QuartzJobTriggerDescriptor triggerQuartzJob(String groupName, String jobName)\n\t\t\tthrows SchedulerException {\n\t\treturn triggerQuartzJob(JobKey.jobKey(jobName, groupName));\n\t}\n\n\tprivate @Nullable QuartzJobTriggerDescriptor triggerQuartzJob(JobKey jobKey) throws SchedulerException {\n\t\tJobDetail jobDetail = this.scheduler.getJobDetail(jobKey);\n\t\tif (jobDetail == null) {\n\t\t\treturn null;\n\t\t}\n\t\tthis.scheduler.triggerJob(jobKey);\n\t\treturn new QuartzJobTriggerDescriptor(jobDetail);\n\t}\n\n\tprivate static List<Map<String, Object>> extractTriggersSummary(List<? extends Trigger> triggers) {\n\t\tList<Trigger> triggersToSort = new ArrayList<>(triggers);\n\t\ttriggersToSort.sort(TRIGGER_COMPARATOR);\n\t\tList<Map<String, Object>> result = new ArrayList<>();\n\t\ttriggersToSort.forEach((trigger) -> {\n\t\t\tMap<String, Object> triggerSummary = new LinkedHashMap<>();\n\t\t\ttriggerSummary.put(\"group\", trigger.getKey().getGroup());\n\t\t\ttriggerSummary.put(\"name\", trigger.getKey().getName());\n\t\t\ttriggerSummary.putAll(TriggerDescriptor.of(trigger).buildSummary(false));\n\t\t\tresult.add(triggerSummary);\n\t\t});\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return the details of the trigger identified by the given group name and trigger\n\t * name.\n\t * @param groupName the name of the group\n\t * @param triggerName the name of the trigger\n\t * @param showUnsanitized whether to sanitize values in data map\n\t * @return the details of the trigger or {@code null} if such trigger does not exist\n\t * @throws SchedulerException if retrieving the information from the scheduler failed\n\t */\n\t@Nullable Map<String, Object> quartzTrigger(String groupName, String triggerName, boolean showUnsanitized)\n\t\t\tthrows SchedulerException {\n\t\tTriggerKey triggerKey = TriggerKey.triggerKey(triggerName, groupName);\n\t\tTrigger trigger = this.scheduler.getTrigger(triggerKey);\n\t\tif (trigger == null) {\n\t\t\treturn null;\n\t\t}\n\t\tTriggerState triggerState = this.scheduler.getTriggerState(triggerKey);\n\t\tTriggerDescriptor triggerDescriptor = TriggerDescriptor.of(trigger);\n\t\tMap<String, Object> jobDataMap = sanitizeJobDataMap(trigger.getJobDataMap(), showUnsanitized);\n\t\treturn OperationResponseBody.of(triggerDescriptor.buildDetails(triggerState, jobDataMap));\n\t}\n\n\tprivate static Duration getIntervalDuration(long amount, IntervalUnit unit) {\n\t\treturn temporalUnit(unit).getDuration().multipliedBy(amount);\n\t}\n\n\tprivate static @Nullable LocalTime getLocalTime(@Nullable TimeOfDay timeOfDay) {\n\t\treturn (timeOfDay != null) ? LocalTime.of(timeOfDay.getHour(), timeOfDay.getMinute(), timeOfDay.getSecond())\n\t\t\t\t: null;\n\t}\n\n\t@Contract(\"!null, _ -> !null\")\n\tprivate @Nullable Map<String, Object> sanitizeJobDataMap(@Nullable JobDataMap dataMap, boolean showUnsanitized) {\n\t\tif (dataMap == null) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<String, Object> map = new LinkedHashMap<>(dataMap.getWrappedMap());\n\t\tmap.replaceAll((key, value) -> getSanitizedValue(showUnsanitized, key, value));\n\t\treturn map;\n\t}\n\n\tprivate @Nullable Object getSanitizedValue(boolean showUnsanitized, String key, @Nullable Object value) {\n\t\tSanitizableData data = new SanitizableData(null, key, value);\n\t\treturn this.sanitizer.sanitize(data, showUnsanitized);\n\t}\n\n\tprivate static TemporalUnit temporalUnit(IntervalUnit unit) {\n\t\treturn switch (unit) {\n\t\t\tcase DAY -> ChronoUnit.DAYS;\n\t\t\tcase HOUR -> ChronoUnit.HOURS;\n\t\t\tcase MINUTE -> ChronoUnit.MINUTES;\n\t\t\tcase MONTH -> ChronoUnit.MONTHS;\n\t\t\tcase SECOND -> ChronoUnit.SECONDS;\n\t\t\tcase MILLISECOND -> ChronoUnit.MILLIS;\n\t\t\tcase WEEK -> ChronoUnit.WEEKS;\n\t\t\tcase YEAR -> ChronoUnit.YEARS;\n\t\t};\n\t}\n\n\t/**\n\t * Description of available job and trigger group names.\n\t */\n\tpublic static final class QuartzDescriptor implements OperationResponseBody {\n\n\t\tprivate final GroupNamesDescriptor jobs;\n\n\t\tprivate final GroupNamesDescriptor triggers;\n\n\t\tQuartzDescriptor(GroupNamesDescriptor jobs, GroupNamesDescriptor triggers) {\n\t\t\tthis.jobs = jobs;\n\t\t\tthis.triggers = triggers;\n\t\t}\n\n\t\tpublic GroupNamesDescriptor getJobs() {\n\t\t\treturn this.jobs;\n\t\t}\n\n\t\tpublic GroupNamesDescriptor getTriggers() {\n\t\t\treturn this.triggers;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of group names.\n\t */\n\tpublic static class GroupNamesDescriptor {\n\n\t\tprivate final Set<String> groups;\n\n\t\tpublic GroupNamesDescriptor(List<String> groups) {\n\t\t\tthis.groups = new LinkedHashSet<>(groups);\n\t\t}\n\n\t\tpublic Set<String> getGroups() {\n\t\t\treturn this.groups;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of each group identified by name.\n\t */\n\tpublic static class QuartzGroupsDescriptor implements OperationResponseBody {\n\n\t\tprivate final Map<String, Object> groups;\n\n\t\tpublic QuartzGroupsDescriptor(Map<String, Object> groups) {\n\t\t\tthis.groups = groups;\n\t\t}\n\n\t\tpublic Map<String, Object> getGroups() {\n\t\t\treturn this.groups;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of the {@link JobDetail jobs} in a given group.\n\t */\n\tpublic static final class QuartzJobGroupSummaryDescriptor implements OperationResponseBody {\n\n\t\tprivate final String group;\n\n\t\tprivate final Map<String, QuartzJobSummaryDescriptor> jobs;\n\n\t\tQuartzJobGroupSummaryDescriptor(String group, Map<String, QuartzJobSummaryDescriptor> jobs) {\n\t\t\tthis.group = group;\n\t\t\tthis.jobs = jobs;\n\t\t}\n\n\t\tpublic String getGroup() {\n\t\t\treturn this.group;\n\t\t}\n\n\t\tpublic Map<String, QuartzJobSummaryDescriptor> getJobs() {\n\t\t\treturn this.jobs;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link Job Quartz Job}.\n\t */\n\tpublic static final class QuartzJobSummaryDescriptor {\n\n\t\tprivate final String className;\n\n\t\tQuartzJobSummaryDescriptor(JobDetail job) {\n\t\t\tthis.className = job.getJobClass().getName();\n\t\t}\n\n\t\tprivate static QuartzJobSummaryDescriptor of(JobDetail job) {\n\t\t\treturn new QuartzJobSummaryDescriptor(job);\n\t\t}\n\n\t\tpublic String getClassName() {\n\t\t\treturn this.className;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a triggered on-demand {@link Job Quartz Job}.\n\t */\n\tpublic static final class QuartzJobTriggerDescriptor implements OperationResponseBody {\n\n\t\tprivate final String group;\n\n\t\tprivate final String name;\n\n\t\tprivate final String className;\n\n\t\tprivate final Instant triggerTime;\n\n\t\tQuartzJobTriggerDescriptor(JobDetail jobDetail) {\n\t\t\tthis.group = jobDetail.getKey().getGroup();\n\t\t\tthis.name = jobDetail.getKey().getName();\n\t\t\tthis.className = jobDetail.getJobClass().getName();\n\t\t\tthis.triggerTime = Instant.now();\n\t\t}\n\n\t\tpublic String getGroup() {\n\t\t\treturn this.group;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getClassName() {\n\t\t\treturn this.className;\n\t\t}\n\n\t\tpublic Instant getTriggerTime() {\n\t\t\treturn this.triggerTime;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link Job Quartz Job}.\n\t */\n\tpublic static final class QuartzJobDetailsDescriptor implements OperationResponseBody {\n\n\t\tprivate final String group;\n\n\t\tprivate final String name;\n\n\t\tprivate final String description;\n\n\t\tprivate final String className;\n\n\t\tprivate final boolean durable;\n\n\t\tprivate final boolean requestRecovery;\n\n\t\tprivate final Map<String, Object> data;\n\n\t\tprivate final List<Map<String, Object>> triggers;\n\n\t\tQuartzJobDetailsDescriptor(JobDetail jobDetail, Map<String, Object> data, List<Map<String, Object>> triggers) {\n\t\t\tthis.group = jobDetail.getKey().getGroup();\n\t\t\tthis.name = jobDetail.getKey().getName();\n\t\t\tthis.description = jobDetail.getDescription();\n\t\t\tthis.className = jobDetail.getJobClass().getName();\n\t\t\tthis.durable = jobDetail.isDurable();\n\t\t\tthis.requestRecovery = jobDetail.requestsRecovery();\n\t\t\tthis.data = data;\n\t\t\tthis.triggers = triggers;\n\t\t}\n\n\t\tpublic String getGroup() {\n\t\t\treturn this.group;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic String getDescription() {\n\t\t\treturn this.description;\n\t\t}\n\n\t\tpublic String getClassName() {\n\t\t\treturn this.className;\n\t\t}\n\n\t\tpublic boolean isDurable() {\n\t\t\treturn this.durable;\n\t\t}\n\n\t\tpublic boolean isRequestRecovery() {\n\t\t\treturn this.requestRecovery;\n\t\t}\n\n\t\tpublic Map<String, Object> getData() {\n\t\t\treturn this.data;\n\t\t}\n\n\t\tpublic List<Map<String, Object>> getTriggers() {\n\t\t\treturn this.triggers;\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of the {@link Trigger triggers} in a given group.\n\t */\n\tpublic static final class QuartzTriggerGroupSummaryDescriptor implements OperationResponseBody {\n\n\t\tprivate final String group;\n\n\t\tprivate final boolean paused;\n\n\t\tprivate final Triggers triggers;\n\n\t\tQuartzTriggerGroupSummaryDescriptor(String group, boolean paused,\n\t\t\t\tMap<TriggerType, Map<String, Object>> descriptionsByType) {\n\t\t\tthis.group = group;\n\t\t\tthis.paused = paused;\n\t\t\tthis.triggers = new Triggers(descriptionsByType);\n\n\t\t}\n\n\t\tpublic String getGroup() {\n\t\t\treturn this.group;\n\t\t}\n\n\t\tpublic boolean isPaused() {\n\t\t\treturn this.paused;\n\t\t}\n\n\t\tpublic Triggers getTriggers() {\n\t\t\treturn this.triggers;\n\t\t}\n\n\t\tpublic static final class Triggers {\n\n\t\t\tprivate final Map<String, Object> cron;\n\n\t\t\tprivate final Map<String, Object> simple;\n\n\t\t\tprivate final Map<String, Object> dailyTimeInterval;\n\n\t\t\tprivate final Map<String, Object> calendarInterval;\n\n\t\t\tprivate final Map<String, Object> custom;\n\n\t\t\tTriggers(Map<TriggerType, Map<String, Object>> descriptionsByType) {\n\t\t\t\tthis.cron = descriptionsByType.getOrDefault(TriggerType.CRON, Collections.emptyMap());\n\t\t\t\tthis.dailyTimeInterval = descriptionsByType.getOrDefault(TriggerType.DAILY_INTERVAL,\n\t\t\t\t\t\tCollections.emptyMap());\n\t\t\t\tthis.calendarInterval = descriptionsByType.getOrDefault(TriggerType.CALENDAR_INTERVAL,\n\t\t\t\t\t\tCollections.emptyMap());\n\t\t\t\tthis.simple = descriptionsByType.getOrDefault(TriggerType.SIMPLE, Collections.emptyMap());\n\t\t\t\tthis.custom = descriptionsByType.getOrDefault(TriggerType.CUSTOM_TRIGGER, Collections.emptyMap());\n\t\t\t}\n\n\t\t\tpublic Map<String, Object> getCron() {\n\t\t\t\treturn this.cron;\n\t\t\t}\n\n\t\t\tpublic Map<String, Object> getSimple() {\n\t\t\t\treturn this.simple;\n\t\t\t}\n\n\t\t\tpublic Map<String, Object> getDailyTimeInterval() {\n\t\t\t\treturn this.dailyTimeInterval;\n\t\t\t}\n\n\t\t\tpublic Map<String, Object> getCalendarInterval() {\n\t\t\t\treturn this.calendarInterval;\n\t\t\t}\n\n\t\t\tpublic Map<String, Object> getCustom() {\n\t\t\t\treturn this.custom;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tprivate enum TriggerType {\n\n\t\tCRON(\"cron\"),\n\n\t\tCUSTOM_TRIGGER(\"custom\"),\n\n\t\tCALENDAR_INTERVAL(\"calendarInterval\"),\n\n\t\tDAILY_INTERVAL(\"dailyTimeInterval\"),\n\n\t\tSIMPLE(\"simple\");\n\n\t\tprivate final String id;\n\n\t\tTriggerType(String id) {\n\t\t\tthis.id = id;\n\t\t}\n\n\t\tpublic String getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t}\n\n\t/**\n\t * Base class for descriptions of a {@link Trigger}.\n\t */\n\tpublic abstract static class TriggerDescriptor {\n\n\t\tprivate static final Map<Class<? extends Trigger>, Function<Trigger, TriggerDescriptor>> DESCRIBERS;\n\n\t\tstatic {\n\t\t\tMap<Class<? extends Trigger>, Function<Trigger, TriggerDescriptor>> descriptors = new LinkedHashMap<>();\n\t\t\tdescriptors.put(CronTrigger.class, (trigger) -> new CronTriggerDescriptor((CronTrigger) trigger));\n\t\t\tdescriptors.put(SimpleTrigger.class, (trigger) -> new SimpleTriggerDescriptor((SimpleTrigger) trigger));\n\t\t\tdescriptors.put(DailyTimeIntervalTrigger.class,\n\t\t\t\t\t(trigger) -> new DailyTimeIntervalTriggerDescriptor((DailyTimeIntervalTrigger) trigger));\n\t\t\tdescriptors.put(CalendarIntervalTrigger.class,\n\t\t\t\t\t(trigger) -> new CalendarIntervalTriggerDescriptor((CalendarIntervalTrigger) trigger));\n\t\t\tDESCRIBERS = Map.copyOf(descriptors);\n\t\t}\n\n\t\tprivate final Trigger trigger;\n\n\t\tprivate final TriggerType type;\n\n\t\tprotected TriggerDescriptor(Trigger trigger, TriggerType type) {\n\t\t\tthis.trigger = trigger;\n\t\t\tthis.type = type;\n\t\t}\n\n\t\t/**\n\t\t * Build the summary of the trigger.\n\t\t * @param addTriggerSpecificSummary whether to add trigger-implementation specific\n\t\t * summary.\n\t\t * @return basic properties of the trigger\n\t\t */\n\t\tpublic Map<String, Object> buildSummary(boolean addTriggerSpecificSummary) {\n\t\t\tMap<String, Object> summary = new LinkedHashMap<>();\n\t\t\tputIfNoNull(summary, \"previousFireTime\", this.trigger.getPreviousFireTime());\n\t\t\tputIfNoNull(summary, \"nextFireTime\", this.trigger.getNextFireTime());\n\t\t\tsummary.put(\"priority\", this.trigger.getPriority());\n\t\t\tif (addTriggerSpecificSummary) {\n\t\t\t\tappendSummary(summary);\n\t\t\t}\n\t\t\treturn summary;\n\t\t}\n\n\t\t/**\n\t\t * Append trigger-implementation specific summary items to the specified\n\t\t * {@code content}.\n\t\t * @param content the summary of the trigger\n\t\t */\n\t\tprotected abstract void appendSummary(Map<String, Object> content);\n\n\t\t/**\n\t\t * Build the full details of the trigger.\n\t\t * @param triggerState the current state of the trigger\n\t\t * @param sanitizedDataMap a sanitized data map or {@code null}\n\t\t * @return all properties of the trigger\n\t\t */\n\t\tpublic Map<String, Object> buildDetails(TriggerState triggerState,\n\t\t\t\t@Nullable Map<String, Object> sanitizedDataMap) {\n\t\t\tMap<String, Object> details = new LinkedHashMap<>();\n\t\t\tdetails.put(\"group\", this.trigger.getKey().getGroup());\n\t\t\tdetails.put(\"name\", this.trigger.getKey().getName());\n\t\t\tputIfNoNull(details, \"description\", this.trigger.getDescription());\n\t\t\tdetails.put(\"state\", triggerState);\n\t\t\tdetails.put(\"type\", getType().getId());\n\t\t\tputIfNoNull(details, \"calendarName\", this.trigger.getCalendarName());\n\t\t\tputIfNoNull(details, \"startTime\", this.trigger.getStartTime());\n\t\t\tputIfNoNull(details, \"endTime\", this.trigger.getEndTime());\n\t\t\tputIfNoNull(details, \"previousFireTime\", this.trigger.getPreviousFireTime());\n\t\t\tputIfNoNull(details, \"nextFireTime\", this.trigger.getNextFireTime());\n\t\t\tputIfNoNull(details, \"priority\", this.trigger.getPriority());\n\t\t\tputIfNoNull(details, \"finalFireTime\", this.trigger.getFinalFireTime());\n\t\t\tputIfNoNull(details, \"data\", sanitizedDataMap);\n\t\t\tMap<String, Object> typeDetails = new LinkedHashMap<>();\n\t\t\tappendDetails(typeDetails);\n\t\t\tdetails.put(getType().getId(), typeDetails);\n\t\t\treturn details;\n\t\t}\n\n\t\t/**\n\t\t * Append trigger-implementation specific details to the specified\n\t\t * {@code content}.\n\t\t * @param content the details of the trigger\n\t\t */\n\t\tprotected abstract void appendDetails(Map<String, Object> content);\n\n\t\tprotected void putIfNoNull(Map<String, Object> content, String key, @Nullable Object value) {\n\t\t\tif (value != null) {\n\t\t\t\tcontent.put(key, value);\n\t\t\t}\n\t\t}\n\n\t\tprotected Trigger getTrigger() {\n\t\t\treturn this.trigger;\n\t\t}\n\n\t\tprotected TriggerType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\tstatic TriggerDescriptor of(Trigger trigger) {\n\t\t\treturn DESCRIBERS.entrySet()\n\t\t\t\t.stream()\n\t\t\t\t.filter((entry) -> entry.getKey().isInstance(trigger))\n\t\t\t\t.map((entry) -> entry.getValue().apply(trigger))\n\t\t\t\t.findFirst()\n\t\t\t\t.orElse(new CustomTriggerDescriptor(trigger));\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link CronTrigger}.\n\t */\n\tpublic static final class CronTriggerDescriptor extends TriggerDescriptor {\n\n\t\tprivate final CronTrigger trigger;\n\n\t\tpublic CronTriggerDescriptor(CronTrigger trigger) {\n\t\t\tsuper(trigger, TriggerType.CRON);\n\t\t\tthis.trigger = trigger;\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendSummary(Map<String, Object> content) {\n\t\t\tcontent.put(\"expression\", this.trigger.getCronExpression());\n\t\t\tputIfNoNull(content, \"timeZone\", this.trigger.getTimeZone());\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendDetails(Map<String, Object> content) {\n\t\t\tappendSummary(content);\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link SimpleTrigger}.\n\t */\n\tpublic static final class SimpleTriggerDescriptor extends TriggerDescriptor {\n\n\t\tprivate final SimpleTrigger trigger;\n\n\t\tpublic SimpleTriggerDescriptor(SimpleTrigger trigger) {\n\t\t\tsuper(trigger, TriggerType.SIMPLE);\n\t\t\tthis.trigger = trigger;\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendSummary(Map<String, Object> content) {\n\t\t\tcontent.put(\"interval\", this.trigger.getRepeatInterval());\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendDetails(Map<String, Object> content) {\n\t\t\tappendSummary(content);\n\t\t\tcontent.put(\"repeatCount\", this.trigger.getRepeatCount());\n\t\t\tcontent.put(\"timesTriggered\", this.trigger.getTimesTriggered());\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link DailyTimeIntervalTrigger}.\n\t */\n\tpublic static final class DailyTimeIntervalTriggerDescriptor extends TriggerDescriptor {\n\n\t\tprivate final DailyTimeIntervalTrigger trigger;\n\n\t\tpublic DailyTimeIntervalTriggerDescriptor(DailyTimeIntervalTrigger trigger) {\n\t\t\tsuper(trigger, TriggerType.DAILY_INTERVAL);\n\t\t\tthis.trigger = trigger;\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendSummary(Map<String, Object> content) {\n\t\t\tcontent.put(\"interval\",\n\t\t\t\t\tgetIntervalDuration(this.trigger.getRepeatInterval(), this.trigger.getRepeatIntervalUnit())\n\t\t\t\t\t\t.toMillis());\n\t\t\tputIfNoNull(content, \"daysOfWeek\", this.trigger.getDaysOfWeek());\n\t\t\tputIfNoNull(content, \"startTimeOfDay\", getLocalTime(this.trigger.getStartTimeOfDay()));\n\t\t\tputIfNoNull(content, \"endTimeOfDay\", getLocalTime(this.trigger.getEndTimeOfDay()));\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendDetails(Map<String, Object> content) {\n\t\t\tappendSummary(content);\n\t\t\tcontent.put(\"repeatCount\", this.trigger.getRepeatCount());\n\t\t\tcontent.put(\"timesTriggered\", this.trigger.getTimesTriggered());\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a {@link CalendarIntervalTrigger}.\n\t */\n\tpublic static final class CalendarIntervalTriggerDescriptor extends TriggerDescriptor {\n\n\t\tprivate final CalendarIntervalTrigger trigger;\n\n\t\tpublic CalendarIntervalTriggerDescriptor(CalendarIntervalTrigger trigger) {\n\t\t\tsuper(trigger, TriggerType.CALENDAR_INTERVAL);\n\t\t\tthis.trigger = trigger;\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendSummary(Map<String, Object> content) {\n\t\t\tcontent.put(\"interval\",\n\t\t\t\t\tgetIntervalDuration(this.trigger.getRepeatInterval(), this.trigger.getRepeatIntervalUnit())\n\t\t\t\t\t\t.toMillis());\n\t\t\tputIfNoNull(content, \"timeZone\", this.trigger.getTimeZone());\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendDetails(Map<String, Object> content) {\n\t\t\tappendSummary(content);\n\t\t\tcontent.put(\"timesTriggered\", this.trigger.getTimesTriggered());\n\t\t\tcontent.put(\"preserveHourOfDayAcrossDaylightSavings\",\n\t\t\t\t\tthis.trigger.isPreserveHourOfDayAcrossDaylightSavings());\n\t\t\tcontent.put(\"skipDayIfHourDoesNotExist\", this.trigger.isSkipDayIfHourDoesNotExist());\n\t\t}\n\n\t}\n\n\t/**\n\t * Description of a custom {@link Trigger}.\n\t */\n\tpublic static final class CustomTriggerDescriptor extends TriggerDescriptor {\n\n\t\tpublic CustomTriggerDescriptor(Trigger trigger) {\n\t\t\tsuper(trigger, TriggerType.CUSTOM_TRIGGER);\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendSummary(Map<String, Object> content) {\n\t\t\tcontent.put(\"trigger\", getTrigger().toString());\n\t\t}\n\n\t\t@Override\n\t\tprotected void appendDetails(Map<String, Object> content) {\n\t\t\tappendSummary(content);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/actuate/endpoint/QuartzEndpointWebExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.actuate.endpoint;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport org.quartz.SchedulerException;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzGroupsDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobDetailsDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobGroupSummaryDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzTriggerGroupSummaryDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpointWebExtension.QuartzEndpointWebExtensionRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * {@link EndpointWebExtension @EndpointWebExtension} for the {@link QuartzEndpoint}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@EndpointWebExtension(endpoint = QuartzEndpoint.class)\n@ImportRuntimeHints(QuartzEndpointWebExtensionRuntimeHints.class)\npublic class QuartzEndpointWebExtension {\n\n\tprivate final QuartzEndpoint delegate;\n\n\tprivate final Show showValues;\n\n\tprivate final Set<String> roles;\n\n\tpublic QuartzEndpointWebExtension(QuartzEndpoint delegate, Show showValues, Set<String> roles) {\n\t\tthis.delegate = delegate;\n\t\tthis.showValues = showValues;\n\t\tthis.roles = roles;\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<QuartzGroupsDescriptor> quartzJobOrTriggerGroups(@Selector String jobsOrTriggers)\n\t\t\tthrows SchedulerException {\n\t\treturn handle(jobsOrTriggers, this.delegate::quartzJobGroups, this.delegate::quartzTriggerGroups);\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<Object> quartzJobOrTriggerGroup(@Selector String jobsOrTriggers, @Selector String group)\n\t\t\tthrows SchedulerException {\n\t\treturn handle(jobsOrTriggers, () -> this.delegate.quartzJobGroupSummary(group),\n\t\t\t\t() -> this.delegate.quartzTriggerGroupSummary(group));\n\t}\n\n\t@ReadOperation\n\tpublic WebEndpointResponse<Object> quartzJobOrTrigger(SecurityContext securityContext,\n\t\t\t@Selector String jobsOrTriggers, @Selector String group, @Selector String name) throws SchedulerException {\n\t\tboolean showUnsanitized = this.showValues.isShown(securityContext, this.roles);\n\t\treturn handle(jobsOrTriggers, () -> this.delegate.quartzJob(group, name, showUnsanitized),\n\t\t\t\t() -> this.delegate.quartzTrigger(group, name, showUnsanitized));\n\t}\n\n\t/**\n\t * Trigger a Quartz job.\n\t * @param jobs path segment \"jobs\"\n\t * @param group job's group\n\t * @param name job name\n\t * @param state desired state\n\t * @return web endpoint response\n\t * @throws SchedulerException if there is an error triggering the job\n\t */\n\t@WriteOperation\n\tpublic WebEndpointResponse<Object> triggerQuartzJob(@Selector String jobs, @Selector String group,\n\t\t\t@Selector String name, String state) throws SchedulerException {\n\t\tif (\"jobs\".equals(jobs) && \"running\".equals(state)) {\n\t\t\treturn handleNull(this.delegate.triggerQuartzJob(group, name));\n\t\t}\n\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_BAD_REQUEST);\n\t}\n\n\tprivate <T> WebEndpointResponse<T> handle(String jobsOrTriggers, ResponseSupplier<T> jobAction,\n\t\t\tResponseSupplier<T> triggerAction) throws SchedulerException {\n\t\tif (\"jobs\".equals(jobsOrTriggers)) {\n\t\t\treturn handleNull(jobAction.get());\n\t\t}\n\t\tif (\"triggers\".equals(jobsOrTriggers)) {\n\t\t\treturn handleNull(triggerAction.get());\n\t\t}\n\t\treturn new WebEndpointResponse<>(WebEndpointResponse.STATUS_BAD_REQUEST);\n\t}\n\n\tprivate <T> WebEndpointResponse<T> handleNull(@Nullable T value) {\n\t\treturn (value != null) ? new WebEndpointResponse<>(value)\n\t\t\t\t: new WebEndpointResponse<>(WebEndpointResponse.STATUS_NOT_FOUND);\n\t}\n\n\t@FunctionalInterface\n\tprivate interface ResponseSupplier<T> {\n\n\t\t@Nullable T get() throws SchedulerException;\n\n\t}\n\n\tstatic class QuartzEndpointWebExtensionRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), QuartzGroupsDescriptor.class,\n\t\t\t\t\tQuartzJobDetailsDescriptor.class, QuartzJobGroupSummaryDescriptor.class,\n\t\t\t\t\tQuartzTriggerGroupSummaryDescriptor.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for Quartz Scheduler.\n */\n@NullMarked\npackage org.springframework.boot.quartz.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/JobStoreType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\n/**\n * Define the supported Quartz {@code JobStore}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic enum JobStoreType {\n\n\t/**\n\t * Store jobs in memory.\n\t */\n\tMEMORY,\n\n\t/**\n\t * Store jobs in the database.\n\t */\n\tJDBC\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\nimport org.quartz.Calendar;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.Trigger;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.OnDatabaseInitializationCondition;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\nimport org.springframework.scheduling.quartz.SpringBeanJobFactory;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Quartz Scheduler.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\",\n\t\t\"org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration\" })\n@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class, PlatformTransactionManager.class })\n@EnableConfigurationProperties(QuartzProperties.class)\npublic final class QuartzAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSchedulerFactoryBean quartzScheduler(QuartzProperties properties,\n\t\t\tObjectProvider<SchedulerFactoryBeanCustomizer> customizers, ObjectProvider<JobDetail> jobDetails,\n\t\t\tMap<String, Calendar> calendars, ObjectProvider<Trigger> triggers, ApplicationContext applicationContext) {\n\t\tSchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();\n\t\tSpringBeanJobFactory jobFactory = new SpringBeanJobFactory();\n\t\tjobFactory.setApplicationContext(applicationContext);\n\t\tschedulerFactoryBean.setJobFactory(jobFactory);\n\t\tif (properties.getSchedulerName() != null) {\n\t\t\tschedulerFactoryBean.setSchedulerName(properties.getSchedulerName());\n\t\t}\n\t\tschedulerFactoryBean.setAutoStartup(properties.isAutoStartup());\n\t\tschedulerFactoryBean.setStartupDelay((int) properties.getStartupDelay().getSeconds());\n\t\tschedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(properties.isWaitForJobsToCompleteOnShutdown());\n\t\tschedulerFactoryBean.setOverwriteExistingJobs(properties.isOverwriteExistingJobs());\n\t\tif (!properties.getProperties().isEmpty()) {\n\t\t\tschedulerFactoryBean.setQuartzProperties(asProperties(properties.getProperties()));\n\t\t}\n\t\tschedulerFactoryBean.setJobDetails(jobDetails.orderedStream().toArray(JobDetail[]::new));\n\t\tschedulerFactoryBean.setCalendars(calendars);\n\t\tschedulerFactoryBean.setTriggers(triggers.orderedStream().toArray(Trigger[]::new));\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(schedulerFactoryBean));\n\t\treturn schedulerFactoryBean;\n\t}\n\n\tprivate Properties asProperties(Map<String, String> source) {\n\t\tProperties properties = new Properties();\n\t\tproperties.putAll(source);\n\t\treturn properties;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(DataSource.class)\n\t@ConditionalOnProperty(name = \"spring.quartz.job-store-type\", havingValue = \"jdbc\")\n\t@Import(DatabaseInitializationDependencyConfigurer.class)\n\tprotected static class JdbcStoreTypeConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tSchedulerFactoryBeanCustomizer dataSourceCustomizer(QuartzProperties properties, DataSource dataSource,\n\t\t\t\t@QuartzDataSource ObjectProvider<DataSource> quartzDataSource,\n\t\t\t\tObjectProvider<PlatformTransactionManager> transactionManager,\n\t\t\t\t@QuartzTransactionManager ObjectProvider<PlatformTransactionManager> quartzTransactionManager) {\n\t\t\treturn (schedulerFactoryBean) -> {\n\t\t\t\tDataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);\n\t\t\t\tschedulerFactoryBean.setDataSource(dataSourceToUse);\n\t\t\t\tPlatformTransactionManager txManager = getTransactionManager(transactionManager,\n\t\t\t\t\t\tquartzTransactionManager);\n\t\t\t\tif (txManager != null) {\n\t\t\t\t\tschedulerFactoryBean.setTransactionManager(txManager);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tprivate static DataSource getDataSource(DataSource dataSource, ObjectProvider<DataSource> quartzDataSource) {\n\t\t\tDataSource dataSourceIfAvailable = quartzDataSource.getIfAvailable();\n\t\t\treturn (dataSourceIfAvailable != null) ? dataSourceIfAvailable : dataSource;\n\t\t}\n\n\t\tprivate @Nullable PlatformTransactionManager getTransactionManager(\n\t\t\t\tObjectProvider<PlatformTransactionManager> transactionManager,\n\t\t\t\tObjectProvider<PlatformTransactionManager> quartzTransactionManager) {\n\t\t\tPlatformTransactionManager transactionManagerIfAvailable = quartzTransactionManager.getIfAvailable();\n\t\t\treturn (transactionManagerIfAvailable != null) ? transactionManagerIfAvailable\n\t\t\t\t\t: transactionManager.getIfUnique();\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableConfigurationProperties(QuartzJdbcProperties.class)\n\t\t@ConditionalOnClass(DataSourceScriptDatabaseInitializer.class)\n\t\tstatic class QuartzDataSourceInitializationConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean\n\t\t\t@Conditional(OnQuartzDatasourceInitializationCondition.class)\n\t\t\tQuartzDataSourceScriptDatabaseInitializer quartzDataSourceScriptDatabaseInitializer(DataSource dataSource,\n\t\t\t\t\t@QuartzDataSource ObjectProvider<DataSource> quartzDataSource, QuartzJdbcProperties properties) {\n\t\t\t\tDataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);\n\t\t\t\treturn new QuartzDataSourceScriptDatabaseInitializer(dataSourceToUse, properties);\n\t\t\t}\n\n\t\t\tstatic class OnQuartzDatasourceInitializationCondition extends OnDatabaseInitializationCondition {\n\n\t\t\t\tOnQuartzDatasourceInitializationCondition() {\n\t\t\t\t\tsuper(\"Quartz\", \"spring.quartz.jdbc.initialize-schema\");\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzDataSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\n/**\n * Qualifier annotation for a DataSource to be injected into Quartz auto-configuration.\n * Can be used on a secondary data source, if there is another one marked as\n * {@code @Primary}.\n *\n * @author Madhura Bhave\n * @see QuartzDataSource\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface QuartzDataSource {\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzDataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link DataSourceScriptDatabaseInitializer} for the Quartz Scheduler database. May be\n * registered as a bean to override auto-configuration.\n *\n * @author Vedran Pavic\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class QuartzDataSourceScriptDatabaseInitializer\n\t\textends PropertiesBasedDataSourceScriptDatabaseInitializer<QuartzJdbcProperties> {\n\n\tprivate final @Nullable List<String> commentPrefixes;\n\n\t/**\n\t * Create a new {@link QuartzDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the Quartz Scheduler data source\n\t * @param properties the Quartz JDBC properties\n\t * @see #getSettings\n\t */\n\tpublic QuartzDataSourceScriptDatabaseInitializer(DataSource dataSource, QuartzJdbcProperties properties) {\n\t\tsuper(dataSource, properties,\n\t\t\t\tMap.of(DatabaseDriver.DB2, \"db2_v95\", DatabaseDriver.MYSQL, \"mysql_innodb\", DatabaseDriver.MARIADB,\n\t\t\t\t\t\t\"mysql_innodb\", DatabaseDriver.POSTGRESQL, \"postgres\", DatabaseDriver.SQLSERVER, \"sqlServer\"));\n\t\tthis.commentPrefixes = properties.getCommentPrefix();\n\t}\n\n\t@Override\n\tprotected void customize(ResourceDatabasePopulator populator) {\n\t\tif (!ObjectUtils.isEmpty(this.commentPrefixes)) {\n\t\t\tpopulator.setCommentPrefixes(this.commentPrefixes.toArray(new String[0]));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport org.quartz.Scheduler;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.SanitizingFunction;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpointWebExtension;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link QuartzEndpoint}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = QuartzAutoConfiguration.class)\n@ConditionalOnClass({ Scheduler.class, QuartzEndpoint.class, ConditionalOnAvailableEndpoint.class })\n@ConditionalOnAvailableEndpoint(QuartzEndpoint.class)\n@EnableConfigurationProperties(QuartzEndpointProperties.class)\npublic final class QuartzEndpointAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(Scheduler.class)\n\t@ConditionalOnMissingBean\n\tQuartzEndpoint quartzEndpoint(Scheduler scheduler, ObjectProvider<SanitizingFunction> sanitizingFunctions) {\n\t\treturn new QuartzEndpoint(scheduler, sanitizingFunctions.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(QuartzEndpoint.class)\n\t@ConditionalOnMissingBean\n\t@ConditionalOnAvailableEndpoint(exposure = EndpointExposure.WEB)\n\tQuartzEndpointWebExtension quartzEndpointWebExtension(QuartzEndpoint endpoint,\n\t\t\tQuartzEndpointProperties properties) {\n\t\treturn new QuartzEndpointWebExtension(endpoint, properties.getShowValues(), properties.getRoles());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzEndpointProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint;\n\n/**\n * Configuration properties for {@link QuartzEndpoint}.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.endpoint.quartz\")\npublic class QuartzEndpointProperties {\n\n\t/**\n\t * When to show unsanitized job or trigger values.\n\t */\n\tprivate Show showValues = Show.NEVER;\n\n\t/**\n\t * Roles used to determine whether a user is authorized to be shown unsanitized job or\n\t * trigger values. When empty, all authenticated users are authorized.\n\t */\n\tprivate final Set<String> roles = new HashSet<>();\n\n\tpublic Show getShowValues() {\n\t\treturn this.showValues;\n\t}\n\n\tpublic void setShowValues(Show showValues) {\n\t\tthis.showValues = showValues;\n\t}\n\n\tpublic Set<String> getRoles() {\n\t\treturn this.roles;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzJdbcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.init.DatabaseInitializationProperties;\n\n/**\n * Configuration properties for the Quartz Scheduler integration when using a JDBC job\n * store.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.quartz.jdbc\")\npublic class QuartzJdbcProperties extends DatabaseInitializationProperties {\n\n\tprivate static final String DEFAULT_SCHEMA_LOCATION = \"classpath:org/quartz/impl/\"\n\t\t\t+ \"jdbcjobstore/tables_@@platform@@.sql\";\n\n\t/**\n\t * Prefixes for single-line comments in SQL initialization scripts.\n\t */\n\tprivate List<String> commentPrefix = new ArrayList<>(Arrays.asList(\"#\", \"--\"));\n\n\tpublic List<String> getCommentPrefix() {\n\t\treturn this.commentPrefix;\n\t}\n\n\tpublic void setCommentPrefix(List<String> commentPrefix) {\n\t\tthis.commentPrefix = commentPrefix;\n\t}\n\n\t@Override\n\tpublic String getDefaultSchemaLocation() {\n\t\treturn DEFAULT_SCHEMA_LOCATION;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for the Quartz Scheduler integration.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.quartz\")\npublic class QuartzProperties {\n\n\t/**\n\t * Quartz job store type.\n\t */\n\tprivate JobStoreType jobStoreType = JobStoreType.MEMORY;\n\n\t/**\n\t * Name of the scheduler.\n\t */\n\tprivate @Nullable String schedulerName;\n\n\t/**\n\t * Whether to automatically start the scheduler after initialization.\n\t */\n\tprivate boolean autoStartup = true;\n\n\t/**\n\t * Delay after which the scheduler is started once initialization completes. Setting\n\t * this property makes sense if no jobs should be run before the entire application\n\t * has started up.\n\t */\n\tprivate Duration startupDelay = Duration.ofSeconds(0);\n\n\t/**\n\t * Whether to wait for running jobs to complete on shutdown.\n\t */\n\tprivate boolean waitForJobsToCompleteOnShutdown;\n\n\t/**\n\t * Whether configured jobs should overwrite existing job definitions.\n\t */\n\tprivate boolean overwriteExistingJobs;\n\n\t/**\n\t * Additional Quartz Scheduler properties.\n\t */\n\tprivate final Map<String, String> properties = new HashMap<>();\n\n\tpublic JobStoreType getJobStoreType() {\n\t\treturn this.jobStoreType;\n\t}\n\n\tpublic void setJobStoreType(JobStoreType jobStoreType) {\n\t\tthis.jobStoreType = jobStoreType;\n\t}\n\n\tpublic @Nullable String getSchedulerName() {\n\t\treturn this.schedulerName;\n\t}\n\n\tpublic void setSchedulerName(@Nullable String schedulerName) {\n\t\tthis.schedulerName = schedulerName;\n\t}\n\n\tpublic boolean isAutoStartup() {\n\t\treturn this.autoStartup;\n\t}\n\n\tpublic void setAutoStartup(boolean autoStartup) {\n\t\tthis.autoStartup = autoStartup;\n\t}\n\n\tpublic Duration getStartupDelay() {\n\t\treturn this.startupDelay;\n\t}\n\n\tpublic void setStartupDelay(Duration startupDelay) {\n\t\tthis.startupDelay = startupDelay;\n\t}\n\n\tpublic boolean isWaitForJobsToCompleteOnShutdown() {\n\t\treturn this.waitForJobsToCompleteOnShutdown;\n\t}\n\n\tpublic void setWaitForJobsToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {\n\t\tthis.waitForJobsToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;\n\t}\n\n\tpublic boolean isOverwriteExistingJobs() {\n\t\treturn this.overwriteExistingJobs;\n\t}\n\n\tpublic void setOverwriteExistingJobs(boolean overwriteExistingJobs) {\n\t\tthis.overwriteExistingJobs = overwriteExistingJobs;\n\t}\n\n\tpublic Map<String, String> getProperties() {\n\t\treturn this.properties;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/QuartzTransactionManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\n\n/**\n * Qualifier annotation for a TransactionManager to be injected into Quartz\n * auto-configuration. Can be used on a secondary transaction manager, if there is another\n * one marked as {@code @Primary}.\n *\n * @author Andy Wilkinson\n * @see QuartzDataSource\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Qualifier\npublic @interface QuartzTransactionManager {\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/SchedulerDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.quartz.Scheduler;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\n\n/**\n * A {@link DependsOnDatabaseInitializationDetector} for Quartz {@link Scheduler} and\n * {@link SchedulerFactoryBean}.\n *\n * @author Andy Wilkinson\n */\nclass SchedulerDependsOnDatabaseInitializationDetector\n\t\textends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\treturn new HashSet<>(Arrays.asList(Scheduler.class, SchedulerFactoryBean.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/SchedulerFactoryBeanCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the Quartz\n * {@link SchedulerFactoryBean} to fine-tune its auto-configuration.\n * <p>\n * For customization of the {@link DataSource} used by Quartz, use of\n * {@link QuartzDataSource @QuartzDataSource} is preferred. It will ensure consistent\n * customization of both the {@link SchedulerFactoryBean} and the\n * {@link QuartzDataSourceScriptDatabaseInitializer}.\n *\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface SchedulerFactoryBeanCustomizer {\n\n\t/**\n\t * Customize the {@link SchedulerFactoryBean}.\n\t * @param schedulerFactoryBean the scheduler to customize\n\t */\n\tvoid customize(SchedulerFactoryBean schedulerFactoryBean);\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/java/org/springframework/boot/quartz/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Quartz Scheduler.\n */\n@NullMarked\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.quartz.jdbc.comment-prefix\",\n      \"defaultValue\": [\n        \"#\",\n        \"--\"\n      ]\n    },\n    {\n      \"name\": \"spring.quartz.scheduler-name\",\n      \"defaultValue\": \"quartzScheduler\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.quartz.autoconfigure.QuartzAutoConfiguration\norg.springframework.boot.quartz.autoconfigure.QuartzEndpointAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-quartz/src/main/resources/META-INF/spring.factories",
    "content": "# Depends on Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.quartz.autoconfigure.SchedulerDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/java/org/springframework/boot/quartz/actuate/endpoint/QuartzEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.LocalTime;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Calendar;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.TimeZone;\nimport java.util.stream.Stream;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.InstanceOfAssertFactory;\nimport org.assertj.core.api.MapAssert;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.quartz.CalendarIntervalScheduleBuilder;\nimport org.quartz.CalendarIntervalTrigger;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.DailyTimeIntervalScheduleBuilder;\nimport org.quartz.DailyTimeIntervalTrigger;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.Job;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.TimeOfDay;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.matchers.GroupMatcher;\nimport org.quartz.spi.OperableTrigger;\n\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobDetailsDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobGroupSummaryDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobSummaryDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobTriggerDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzTriggerGroupSummaryDescriptor;\nimport org.springframework.scheduling.quartz.DelegatingJob;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.assertj.core.api.Assertions.within;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link QuartzEndpoint}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\nclass QuartzEndpointTests {\n\n\tprivate static final JobDetail jobOne = JobBuilder.newJob(Job.class).withIdentity(\"jobOne\").build();\n\n\tprivate static final JobDetail jobTwo = JobBuilder.newJob(DelegatingJob.class).withIdentity(\"jobTwo\").build();\n\n\tprivate static final JobDetail jobThree = JobBuilder.newJob(Job.class).withIdentity(\"jobThree\", \"samples\").build();\n\n\tprivate static final Trigger triggerOne = TriggerBuilder.newTrigger()\n\t\t.forJob(jobOne)\n\t\t.withIdentity(\"triggerOne\")\n\t\t.build();\n\n\tprivate static final Trigger triggerTwo = TriggerBuilder.newTrigger()\n\t\t.forJob(jobOne)\n\t\t.withIdentity(\"triggerTwo\")\n\t\t.build();\n\n\tprivate static final Trigger triggerThree = TriggerBuilder.newTrigger()\n\t\t.forJob(jobThree)\n\t\t.withIdentity(\"triggerThree\", \"samples\")\n\t\t.build();\n\n\tprivate final Scheduler scheduler;\n\n\tprivate final QuartzEndpoint endpoint;\n\n\tQuartzEndpointTests() {\n\t\tthis.scheduler = mock(Scheduler.class);\n\t\tthis.endpoint = new QuartzEndpoint(this.scheduler, Collections.emptyList());\n\t}\n\n\t@Test\n\tvoid quartzReport() throws SchedulerException {\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(Arrays.asList(\"jobSamples\", \"DEFAULT\"));\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(Collections.singletonList(\"triggerSamples\"));\n\t\tQuartzDescriptor quartzReport = this.endpoint.quartzReport();\n\t\tassertThat(quartzReport.getJobs().getGroups()).containsOnly(\"jobSamples\", \"DEFAULT\");\n\t\tassertThat(quartzReport.getTriggers().getGroups()).containsOnly(\"triggerSamples\");\n\t\tthen(this.scheduler).should().getJobGroupNames();\n\t\tthen(this.scheduler).should().getTriggerGroupNames();\n\t\tthen(this.scheduler).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid quartzReportWithNoJob() throws SchedulerException {\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(Collections.emptyList());\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(Arrays.asList(\"triggerSamples\", \"DEFAULT\"));\n\t\tQuartzDescriptor quartzReport = this.endpoint.quartzReport();\n\t\tassertThat(quartzReport.getJobs().getGroups()).isEmpty();\n\t\tassertThat(quartzReport.getTriggers().getGroups()).containsOnly(\"triggerSamples\", \"DEFAULT\");\n\t}\n\n\t@Test\n\tvoid quartzReportWithNoTrigger() throws SchedulerException {\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(Collections.singletonList(\"jobSamples\"));\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(Collections.emptyList());\n\t\tQuartzDescriptor quartzReport = this.endpoint.quartzReport();\n\t\tassertThat(quartzReport.getJobs().getGroups()).containsOnly(\"jobSamples\");\n\t\tassertThat(quartzReport.getTriggers().getGroups()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzJobGroupsWithExistingGroups() throws SchedulerException {\n\t\tmockJobs(jobOne, jobTwo, jobThree);\n\t\tMap<String, Object> jobGroups = this.endpoint.quartzJobGroups().getGroups();\n\t\tassertThat(jobGroups).containsOnlyKeys(\"DEFAULT\", \"samples\");\n\t\tassertThat(jobGroups).extractingByKey(\"DEFAULT\", nestedMap())\n\t\t\t.containsOnly(entry(\"jobs\", Arrays.asList(\"jobOne\", \"jobTwo\")));\n\t\tassertThat(jobGroups).extractingByKey(\"samples\", nestedMap())\n\t\t\t.containsOnly(entry(\"jobs\", Collections.singletonList(\"jobThree\")));\n\t}\n\n\t@Test\n\tvoid quartzJobGroupsWithNoGroup() throws SchedulerException {\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(Collections.emptyList());\n\t\tMap<String, Object> jobGroups = this.endpoint.quartzJobGroups().getGroups();\n\t\tassertThat(jobGroups).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupsWithExistingGroups() throws SchedulerException {\n\t\tmockTriggers(triggerOne, triggerTwo, triggerThree);\n\t\tgiven(this.scheduler.getPausedTriggerGroups()).willReturn(Collections.singleton(\"samples\"));\n\t\tMap<String, Object> triggerGroups = this.endpoint.quartzTriggerGroups().getGroups();\n\t\tassertThat(triggerGroups).containsOnlyKeys(\"DEFAULT\", \"samples\");\n\t\tassertThat(triggerGroups).extractingByKey(\"DEFAULT\", nestedMap())\n\t\t\t.containsOnly(entry(\"paused\", false), entry(\"triggers\", Arrays.asList(\"triggerOne\", \"triggerTwo\")));\n\t\tassertThat(triggerGroups).extractingByKey(\"samples\", nestedMap())\n\t\t\t.containsOnly(entry(\"paused\", true), entry(\"triggers\", Collections.singletonList(\"triggerThree\")));\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupsWithNoGroup() throws SchedulerException {\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(Collections.emptyList());\n\t\tMap<String, Object> triggerGroups = this.endpoint.quartzTriggerGroups().getGroups();\n\t\tassertThat(triggerGroups).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzJobGroupSummaryWithInvalidGroup() throws SchedulerException {\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(Collections.singletonList(\"DEFAULT\"));\n\t\tQuartzJobGroupSummaryDescriptor summary = this.endpoint.quartzJobGroupSummary(\"unknown\");\n\t\tassertThat(summary).isNull();\n\t}\n\n\t@Test\n\tvoid quartzJobGroupSummaryWithEmptyGroup() throws SchedulerException {\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(Collections.singletonList(\"samples\"));\n\t\tgiven(this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(\"samples\"))).willReturn(Collections.emptySet());\n\t\tQuartzJobGroupSummaryDescriptor summary = this.endpoint.quartzJobGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.getJobs()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzJobGroupSummaryWithJobs() throws SchedulerException {\n\t\tmockJobs(jobOne, jobTwo);\n\t\tQuartzJobGroupSummaryDescriptor summary = this.endpoint.quartzJobGroupSummary(\"DEFAULT\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"DEFAULT\");\n\t\tMap<String, QuartzJobSummaryDescriptor> jobSummaries = summary.getJobs();\n\t\tassertThat(jobSummaries).containsOnlyKeys(\"jobOne\", \"jobTwo\");\n\t\tQuartzJobSummaryDescriptor jobOne = jobSummaries.get(\"jobOne\");\n\t\tassertThat(jobOne).isNotNull();\n\t\tassertThat(jobOne.getClassName()).isEqualTo(Job.class.getName());\n\t\tQuartzJobSummaryDescriptor jobTwo = jobSummaries.get(\"jobTwo\");\n\t\tassertThat(jobTwo).isNotNull();\n\t\tassertThat(jobTwo.getClassName()).isEqualTo(DelegatingJob.class.getName());\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithInvalidGroup() throws SchedulerException {\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(Collections.singletonList(\"DEFAULT\"));\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"unknown\");\n\t\tassertThat(summary).isNull();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithEmptyGroup() throws SchedulerException {\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(Collections.singletonList(\"samples\"));\n\t\tgiven(this.scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(\"samples\")))\n\t\t\t.willReturn(Collections.emptySet());\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.isPaused()).isFalse();\n\t\tassertThat(summary.getTriggers().getCron()).isEmpty();\n\t\tassertThat(summary.getTriggers().getSimple()).isEmpty();\n\t\tassertThat(summary.getTriggers().getDailyTimeInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCalendarInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCustom()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithCronTrigger() throws SchedulerException {\n\t\tCronTrigger cronTrigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"3am-every-day\", \"samples\")\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t\t.build();\n\t\tmockTriggers(cronTrigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.isPaused()).isFalse();\n\t\tassertThat(summary.getTriggers().getCron()).containsOnlyKeys(\"3am-every-day\");\n\t\tassertThat(summary.getTriggers().getSimple()).isEmpty();\n\t\tassertThat(summary.getTriggers().getDailyTimeInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCalendarInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCustom()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithCronTriggerDetails() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tTimeZone timeZone = TimeZone.getTimeZone(\"Europe/Paris\");\n\t\tCronTrigger cronTrigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"3am-every-day\", \"samples\")\n\t\t\t.withPriority(3)\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0).inTimeZone(timeZone))\n\t\t\t.build();\n\t\t((OperableTrigger) cronTrigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) cronTrigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(cronTrigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tMap<String, Object> triggers = summary.getTriggers().getCron();\n\t\tassertThat(triggers).containsOnlyKeys(\"3am-every-day\");\n\t\tassertThat(triggers).extractingByKey(\"3am-every-day\", nestedMap())\n\t\t\t.containsOnly(entry(\"previousFireTime\", previousFireTime), entry(\"nextFireTime\", nextFireTime),\n\t\t\t\t\tentry(\"priority\", 3), entry(\"expression\", \"0 0 3 ? * *\"), entry(\"timeZone\", timeZone));\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithSimpleTrigger() throws SchedulerException {\n\t\tSimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"every-hour\", \"samples\")\n\t\t\t.withSchedule(SimpleScheduleBuilder.repeatHourlyForever(1))\n\t\t\t.build();\n\t\tmockTriggers(simpleTrigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.isPaused()).isFalse();\n\t\tassertThat(summary.getTriggers().getCron()).isEmpty();\n\t\tassertThat(summary.getTriggers().getSimple()).containsOnlyKeys(\"every-hour\");\n\t\tassertThat(summary.getTriggers().getDailyTimeInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCalendarInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCustom()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithSimpleTriggerDetails() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tSimpleTrigger simpleTrigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"every-hour\", \"samples\")\n\t\t\t.withPriority(7)\n\t\t\t.withSchedule(SimpleScheduleBuilder.repeatHourlyForever(1))\n\t\t\t.build();\n\t\t((OperableTrigger) simpleTrigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) simpleTrigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(simpleTrigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tMap<String, Object> triggers = summary.getTriggers().getSimple();\n\t\tassertThat(triggers).containsOnlyKeys(\"every-hour\");\n\t\tassertThat(triggers).extractingByKey(\"every-hour\", nestedMap())\n\t\t\t.containsOnly(entry(\"previousFireTime\", previousFireTime), entry(\"nextFireTime\", nextFireTime),\n\t\t\t\t\tentry(\"priority\", 7), entry(\"interval\", 3600000L));\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithDailyIntervalTrigger() throws SchedulerException {\n\t\tDailyTimeIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"every-hour-9am\", \"samples\")\n\t\t\t.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n\t\t\t\t.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))\n\t\t\t\t.withInterval(1, IntervalUnit.HOUR))\n\t\t\t.build();\n\t\tmockTriggers(trigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.isPaused()).isFalse();\n\t\tassertThat(summary.getTriggers().getCron()).isEmpty();\n\t\tassertThat(summary.getTriggers().getSimple()).isEmpty();\n\t\tassertThat(summary.getTriggers().getDailyTimeInterval()).containsOnlyKeys(\"every-hour-9am\");\n\t\tassertThat(summary.getTriggers().getCalendarInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCustom()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithDailyIntervalTriggerDetails() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tDailyTimeIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"every-hour-tue-thu\", \"samples\")\n\t\t\t.withPriority(4)\n\t\t\t.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n\t\t\t\t.onDaysOfTheWeek(Calendar.TUESDAY, Calendar.THURSDAY)\n\t\t\t\t.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))\n\t\t\t\t.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(18, 0))\n\t\t\t\t.withInterval(1, IntervalUnit.HOUR))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(trigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tMap<String, Object> triggers = summary.getTriggers().getDailyTimeInterval();\n\t\tassertThat(triggers).containsOnlyKeys(\"every-hour-tue-thu\");\n\t\tassertThat(triggers).extractingByKey(\"every-hour-tue-thu\", nestedMap())\n\t\t\t.containsOnly(entry(\"previousFireTime\", previousFireTime), entry(\"nextFireTime\", nextFireTime),\n\t\t\t\t\tentry(\"priority\", 4), entry(\"interval\", 3600000L), entry(\"startTimeOfDay\", LocalTime.of(9, 0)),\n\t\t\t\t\tentry(\"endTimeOfDay\", LocalTime.of(18, 0)),\n\t\t\t\t\tentry(\"daysOfWeek\", new LinkedHashSet<>(Arrays.asList(3, 5))));\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithCalendarIntervalTrigger() throws SchedulerException {\n\t\tCalendarIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"once-a-week\", \"samples\")\n\t\t\t.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInWeeks(1))\n\t\t\t.build();\n\t\tmockTriggers(trigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.isPaused()).isFalse();\n\t\tassertThat(summary.getTriggers().getCron()).isEmpty();\n\t\tassertThat(summary.getTriggers().getSimple()).isEmpty();\n\t\tassertThat(summary.getTriggers().getDailyTimeInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCalendarInterval()).containsOnlyKeys(\"once-a-week\");\n\t\tassertThat(summary.getTriggers().getCustom()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithCalendarIntervalTriggerDetails() throws SchedulerException {\n\t\tTimeZone timeZone = TimeZone.getTimeZone(\"Europe/Paris\");\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tCalendarIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"once-a-week\", \"samples\")\n\t\t\t.withPriority(8)\n\t\t\t.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()\n\t\t\t\t.withIntervalInWeeks(1)\n\t\t\t\t.inTimeZone(timeZone))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(trigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tMap<String, Object> triggers = summary.getTriggers().getCalendarInterval();\n\t\tassertThat(triggers).containsOnlyKeys(\"once-a-week\");\n\t\tassertThat(triggers).extractingByKey(\"once-a-week\", nestedMap())\n\t\t\t.containsOnly(entry(\"previousFireTime\", previousFireTime), entry(\"nextFireTime\", nextFireTime),\n\t\t\t\t\tentry(\"priority\", 8), entry(\"interval\", 604800000L), entry(\"timeZone\", timeZone));\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithCustomTrigger() throws SchedulerException {\n\t\tTrigger trigger = mock(Trigger.class);\n\t\tgiven(trigger.getKey()).willReturn(TriggerKey.triggerKey(\"custom\", \"samples\"));\n\t\tmockTriggers(trigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tassertThat(summary.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(summary.isPaused()).isFalse();\n\t\tassertThat(summary.getTriggers().getCron()).isEmpty();\n\t\tassertThat(summary.getTriggers().getSimple()).isEmpty();\n\t\tassertThat(summary.getTriggers().getDailyTimeInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCalendarInterval()).isEmpty();\n\t\tassertThat(summary.getTriggers().getCustom()).containsOnlyKeys(\"custom\");\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroupSummaryWithCustomTriggerDetails() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tTrigger trigger = mock(Trigger.class);\n\t\tgiven(trigger.getKey()).willReturn(TriggerKey.triggerKey(\"custom\", \"samples\"));\n\t\tgiven(trigger.getPreviousFireTime()).willReturn(previousFireTime);\n\t\tgiven(trigger.getNextFireTime()).willReturn(nextFireTime);\n\t\tgiven(trigger.getPriority()).willReturn(9);\n\t\tmockTriggers(trigger);\n\t\tQuartzTriggerGroupSummaryDescriptor summary = this.endpoint.quartzTriggerGroupSummary(\"samples\");\n\t\tassertThat(summary).isNotNull();\n\t\tMap<String, Object> triggers = summary.getTriggers().getCustom();\n\t\tassertThat(triggers).containsOnlyKeys(\"custom\");\n\t\tassertThat(triggers).extractingByKey(\"custom\", nestedMap())\n\t\t\t.containsOnly(entry(\"previousFireTime\", previousFireTime), entry(\"nextFireTime\", nextFireTime),\n\t\t\t\t\tentry(\"priority\", 9), entry(\"trigger\", trigger.toString()));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithCronTrigger() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tTimeZone timeZone = TimeZone.getTimeZone(\"Europe/Paris\");\n\t\tCronTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"3am-every-day\", \"samples\")\n\t\t\t.withPriority(3)\n\t\t\t.withDescription(\"Sample description\")\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0).inTimeZone(timeZone))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"3am-every-day\", \"samples\")))\n\t\t\t.willReturn(TriggerState.NORMAL);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"3am-every-day\", true);\n\t\tassertThat(triggerDetails).contains(entry(\"group\", \"samples\"), entry(\"name\", \"3am-every-day\"),\n\t\t\t\tentry(\"description\", \"Sample description\"), entry(\"type\", \"cron\"), entry(\"state\", TriggerState.NORMAL),\n\t\t\t\tentry(\"priority\", 3));\n\t\tassertThat(triggerDetails).contains(entry(\"previousFireTime\", previousFireTime),\n\t\t\t\tentry(\"nextFireTime\", nextFireTime));\n\t\tassertThat(triggerDetails).doesNotContainKeys(\"simple\", \"dailyTimeInterval\", \"calendarInterval\", \"custom\");\n\t\tassertThat(triggerDetails).extractingByKey(\"cron\", nestedMap())\n\t\t\t.containsOnly(entry(\"expression\", \"0 0 3 ? * *\"), entry(\"timeZone\", timeZone));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithSimpleTrigger() throws SchedulerException {\n\t\tDate startTime = Date.from(Instant.parse(\"2020-01-01T09:00:00Z\"));\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tDate endTime = Date.from(Instant.parse(\"2020-01-31T09:00:00Z\"));\n\t\tSimpleTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"every-hour\", \"samples\")\n\t\t\t.withPriority(20)\n\t\t\t.withDescription(\"Every hour\")\n\t\t\t.startAt(startTime)\n\t\t\t.endAt(endTime)\n\t\t\t.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(1).withRepeatCount(2000))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"every-hour\", \"samples\")))\n\t\t\t.willReturn(TriggerState.COMPLETE);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"every-hour\", true);\n\t\tassertThat(triggerDetails).contains(entry(\"group\", \"samples\"), entry(\"name\", \"every-hour\"),\n\t\t\t\tentry(\"description\", \"Every hour\"), entry(\"type\", \"simple\"), entry(\"state\", TriggerState.COMPLETE),\n\t\t\t\tentry(\"priority\", 20));\n\t\tassertThat(triggerDetails).contains(entry(\"startTime\", startTime), entry(\"previousFireTime\", previousFireTime),\n\t\t\t\tentry(\"nextFireTime\", nextFireTime), entry(\"endTime\", endTime));\n\t\tassertThat(triggerDetails).doesNotContainKeys(\"cron\", \"dailyTimeInterval\", \"calendarInterval\", \"custom\");\n\t\tassertThat(triggerDetails).extractingByKey(\"simple\", nestedMap())\n\t\t\t.containsOnly(entry(\"interval\", 3600000L), entry(\"repeatCount\", 2000), entry(\"timesTriggered\", 0));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithDailyTimeIntervalTrigger() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tDailyTimeIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"every-hour-mon-wed\", \"samples\")\n\t\t\t.withDescription(\"Every working hour Mon Wed\")\n\t\t\t.withPriority(4)\n\t\t\t.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n\t\t\t\t.onDaysOfTheWeek(Calendar.MONDAY, Calendar.WEDNESDAY)\n\t\t\t\t.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))\n\t\t\t\t.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(18, 0))\n\t\t\t\t.withInterval(1, IntervalUnit.HOUR))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"every-hour-mon-wed\", \"samples\")))\n\t\t\t.willReturn(TriggerState.NORMAL);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"every-hour-mon-wed\", true);\n\t\tassertThat(triggerDetails).contains(entry(\"group\", \"samples\"), entry(\"name\", \"every-hour-mon-wed\"),\n\t\t\t\tentry(\"description\", \"Every working hour Mon Wed\"), entry(\"type\", \"dailyTimeInterval\"),\n\t\t\t\tentry(\"state\", TriggerState.NORMAL), entry(\"priority\", 4));\n\t\tassertThat(triggerDetails).contains(entry(\"previousFireTime\", previousFireTime),\n\t\t\t\tentry(\"nextFireTime\", nextFireTime));\n\t\tassertThat(triggerDetails).doesNotContainKeys(\"cron\", \"simple\", \"calendarInterval\", \"custom\");\n\t\tassertThat(triggerDetails).extractingByKey(\"dailyTimeInterval\", nestedMap())\n\t\t\t.containsOnly(entry(\"interval\", 3600000L), entry(\"startTimeOfDay\", LocalTime.of(9, 0)),\n\t\t\t\t\tentry(\"endTimeOfDay\", LocalTime.of(18, 0)),\n\t\t\t\t\tentry(\"daysOfWeek\", new LinkedHashSet<>(Arrays.asList(2, 4))), entry(\"repeatCount\", -1),\n\t\t\t\t\tentry(\"timesTriggered\", 0));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithCalendarTimeIntervalTrigger() throws SchedulerException {\n\t\tTimeZone timeZone = TimeZone.getTimeZone(\"Europe/Paris\");\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tCalendarIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"once-a-week\", \"samples\")\n\t\t\t.withDescription(\"Once a week\")\n\t\t\t.withPriority(8)\n\t\t\t.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()\n\t\t\t\t.withIntervalInWeeks(1)\n\t\t\t\t.inTimeZone(timeZone)\n\t\t\t\t.preserveHourOfDayAcrossDaylightSavings(true))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"once-a-week\", \"samples\")))\n\t\t\t.willReturn(TriggerState.BLOCKED);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"once-a-week\", true);\n\t\tassertThat(triggerDetails).contains(entry(\"group\", \"samples\"), entry(\"name\", \"once-a-week\"),\n\t\t\t\tentry(\"description\", \"Once a week\"), entry(\"type\", \"calendarInterval\"),\n\t\t\t\tentry(\"state\", TriggerState.BLOCKED), entry(\"priority\", 8));\n\t\tassertThat(triggerDetails).contains(entry(\"previousFireTime\", previousFireTime),\n\t\t\t\tentry(\"nextFireTime\", nextFireTime));\n\t\tassertThat(triggerDetails).doesNotContainKeys(\"cron\", \"simple\", \"dailyTimeInterval\", \"custom\");\n\t\tassertThat(triggerDetails).extractingByKey(\"calendarInterval\", nestedMap())\n\t\t\t.containsOnly(entry(\"interval\", 604800000L), entry(\"timeZone\", timeZone),\n\t\t\t\t\tentry(\"preserveHourOfDayAcrossDaylightSavings\", true), entry(\"skipDayIfHourDoesNotExist\", false),\n\t\t\t\t\tentry(\"timesTriggered\", 0));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithCustomTrigger() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tTrigger trigger = mock(Trigger.class);\n\t\tgiven(trigger.getKey()).willReturn(TriggerKey.triggerKey(\"custom\", \"samples\"));\n\t\tgiven(trigger.getPreviousFireTime()).willReturn(previousFireTime);\n\t\tgiven(trigger.getNextFireTime()).willReturn(nextFireTime);\n\t\tgiven(trigger.getPriority()).willReturn(9);\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"custom\", \"samples\")))\n\t\t\t.willReturn(TriggerState.ERROR);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"custom\", true);\n\t\tassertThat(triggerDetails).contains(entry(\"group\", \"samples\"), entry(\"name\", \"custom\"), entry(\"type\", \"custom\"),\n\t\t\t\tentry(\"state\", TriggerState.ERROR), entry(\"priority\", 9));\n\t\tassertThat(triggerDetails).contains(entry(\"previousFireTime\", previousFireTime),\n\t\t\t\tentry(\"nextFireTime\", nextFireTime));\n\t\tassertThat(triggerDetails).doesNotContainKeys(\"cron\", \"simple\", \"calendarInterval\", \"dailyTimeInterval\");\n\t\tassertThat(triggerDetails).extractingByKey(\"custom\", nestedMap())\n\t\t\t.containsOnly(entry(\"trigger\", trigger.toString()));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithDataMap() throws SchedulerException {\n\t\tCronTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"3am-every-day\", \"samples\")\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t\t.usingJobData(\"user\", \"user\")\n\t\t\t.usingJobData(\"password\", \"secret\")\n\t\t\t.usingJobData(\"url\", \"https://user:secret@example.com\")\n\t\t\t.build();\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"3am-every-day\", \"samples\")))\n\t\t\t.willReturn(TriggerState.NORMAL);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"3am-every-day\", true);\n\t\tassertThat(triggerDetails).extractingByKey(\"data\", nestedMap())\n\t\t\t.containsOnly(entry(\"user\", \"user\"), entry(\"password\", \"secret\"),\n\t\t\t\t\tentry(\"url\", \"https://user:secret@example.com\"));\n\t}\n\n\t@Test\n\tvoid quartzTriggerWithDataMapAndShowUnsanitizedFalse() throws SchedulerException {\n\t\tCronTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"3am-every-day\", \"samples\")\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t\t.usingJobData(\"user\", \"user\")\n\t\t\t.usingJobData(\"password\", \"secret\")\n\t\t\t.usingJobData(\"url\", \"https://user:secret@example.com\")\n\t\t\t.build();\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggerState(TriggerKey.triggerKey(\"3am-every-day\", \"samples\")))\n\t\t\t.willReturn(TriggerState.NORMAL);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"3am-every-day\", false);\n\t\tassertThat(triggerDetails).extractingByKey(\"data\", nestedMap())\n\t\t\t.containsOnly(entry(\"user\", \"******\"), entry(\"password\", \"******\"), entry(\"url\", \"******\"));\n\t}\n\n\t@ParameterizedTest(name = \"unit {1}\")\n\t@MethodSource(\"intervalUnitParameters\")\n\tvoid canConvertIntervalUnit(int amount, IntervalUnit unit, Duration expectedDuration) throws SchedulerException {\n\t\tCalendarIntervalTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"trigger\", \"samples\")\n\t\t\t.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withInterval(amount, unit))\n\t\t\t.build();\n\t\tmockTriggers(trigger);\n\t\tMap<String, Object> triggerDetails = this.endpoint.quartzTrigger(\"samples\", \"trigger\", true);\n\t\tassertThat(triggerDetails).extractingByKey(\"calendarInterval\", nestedMap())\n\t\t\t.contains(entry(\"interval\", expectedDuration.toMillis()));\n\t}\n\n\tstatic Stream<Arguments> intervalUnitParameters() {\n\t\treturn Stream.of(Arguments.of(3, IntervalUnit.DAY, Duration.ofDays(3)),\n\t\t\t\tArguments.of(2, IntervalUnit.HOUR, Duration.ofHours(2)),\n\t\t\t\tArguments.of(5, IntervalUnit.MINUTE, Duration.ofMinutes(5)),\n\t\t\t\tArguments.of(1, IntervalUnit.MONTH, ChronoUnit.MONTHS.getDuration()),\n\t\t\t\tArguments.of(30, IntervalUnit.SECOND, Duration.ofSeconds(30)),\n\t\t\t\tArguments.of(1, IntervalUnit.WEEK, ChronoUnit.WEEKS.getDuration()),\n\t\t\t\tArguments.of(1, IntervalUnit.YEAR, ChronoUnit.YEARS.getDuration()));\n\t}\n\n\t@Test\n\tvoid quartzJobWithoutTrigger() throws SchedulerException {\n\t\tJobDetail job = JobBuilder.newJob(Job.class)\n\t\t\t.withIdentity(\"hello\", \"samples\")\n\t\t\t.withDescription(\"A sample job\")\n\t\t\t.storeDurably()\n\t\t\t.requestRecovery(false)\n\t\t\t.build();\n\t\tmockJobs(job);\n\t\tQuartzJobDetailsDescriptor jobDetails = this.endpoint.quartzJob(\"samples\", \"hello\", true);\n\t\tassertThat(jobDetails).isNotNull();\n\t\tassertThat(jobDetails.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(jobDetails.getName()).isEqualTo(\"hello\");\n\t\tassertThat(jobDetails.getDescription()).isEqualTo(\"A sample job\");\n\t\tassertThat(jobDetails.getClassName()).isEqualTo(Job.class.getName());\n\t\tassertThat(jobDetails.isDurable()).isTrue();\n\t\tassertThat(jobDetails.isRequestRecovery()).isFalse();\n\t\tassertThat(jobDetails.getData()).isEmpty();\n\t\tassertThat(jobDetails.getTriggers()).isEmpty();\n\t}\n\n\t@Test\n\tvoid quartzJobWithTrigger() throws SchedulerException {\n\t\tDate previousFireTime = Date.from(Instant.parse(\"2020-11-30T03:00:00Z\"));\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tJobDetail job = JobBuilder.newJob(Job.class).withIdentity(\"hello\", \"samples\").build();\n\t\tTimeZone timeZone = TimeZone.getTimeZone(\"Europe/Paris\");\n\t\tTrigger trigger = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"3am-every-day\", \"samples\")\n\t\t\t.withPriority(4)\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0).inTimeZone(timeZone))\n\t\t\t.build();\n\t\t((OperableTrigger) trigger).setPreviousFireTime(previousFireTime);\n\t\t((OperableTrigger) trigger).setNextFireTime(nextFireTime);\n\t\tmockJobs(job);\n\t\tmockTriggers(trigger);\n\t\tgiven(this.scheduler.getTriggersOfJob(JobKey.jobKey(\"hello\", \"samples\")))\n\t\t\t.willAnswer((invocation) -> Collections.singletonList(trigger));\n\t\tQuartzJobDetailsDescriptor jobDetails = this.endpoint.quartzJob(\"samples\", \"hello\", true);\n\t\tassertThat(jobDetails).isNotNull();\n\t\tassertThat(jobDetails.getTriggers()).hasSize(1);\n\t\tMap<String, Object> triggerDetails = jobDetails.getTriggers().get(0);\n\t\tassertThat(triggerDetails).containsOnly(entry(\"group\", \"samples\"), entry(\"name\", \"3am-every-day\"),\n\t\t\t\tentry(\"previousFireTime\", previousFireTime), entry(\"nextFireTime\", nextFireTime), entry(\"priority\", 4));\n\t}\n\n\t@Test\n\tvoid quartzJobOrdersTriggersAccordingToNextFireTime() throws SchedulerException {\n\t\tJobDetail job = JobBuilder.newJob(Job.class).withIdentity(\"hello\", \"samples\").build();\n\t\tmockJobs(job);\n\t\tDate triggerOneNextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tCronTrigger triggerOne = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"one\", \"samples\")\n\t\t\t.withPriority(5)\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t\t.build();\n\t\t((OperableTrigger) triggerOne).setNextFireTime(triggerOneNextFireTime);\n\t\tDate triggerTwoNextFireTime = Date.from(Instant.parse(\"2020-12-01T02:00:00Z\"));\n\t\tCronTrigger triggerTwo = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"two\", \"samples\")\n\t\t\t.withPriority(10)\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(2, 0))\n\t\t\t.build();\n\t\t((OperableTrigger) triggerTwo).setNextFireTime(triggerTwoNextFireTime);\n\t\tmockTriggers(triggerOne, triggerTwo);\n\t\tgiven(this.scheduler.getTriggersOfJob(JobKey.jobKey(\"hello\", \"samples\")))\n\t\t\t.willAnswer((invocation) -> Arrays.asList(triggerOne, triggerTwo));\n\t\tQuartzJobDetailsDescriptor jobDetails = this.endpoint.quartzJob(\"samples\", \"hello\", true);\n\t\tassertThat(jobDetails).isNotNull();\n\t\tassertThat(jobDetails.getTriggers()).hasSize(2);\n\t\tassertThat(jobDetails.getTriggers().get(0)).containsEntry(\"name\", \"two\");\n\t\tassertThat(jobDetails.getTriggers().get(1)).containsEntry(\"name\", \"one\");\n\t}\n\n\t@Test\n\tvoid quartzJobOrdersTriggersAccordingNextFireTimeAndPriority() throws SchedulerException {\n\t\tJobDetail job = JobBuilder.newJob(Job.class).withIdentity(\"hello\", \"samples\").build();\n\t\tmockJobs(job);\n\t\tDate nextFireTime = Date.from(Instant.parse(\"2020-12-01T03:00:00Z\"));\n\t\tCronTrigger triggerOne = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"one\", \"samples\")\n\t\t\t.withPriority(3)\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t\t.build();\n\t\t((OperableTrigger) triggerOne).setNextFireTime(nextFireTime);\n\t\tCronTrigger triggerTwo = TriggerBuilder.newTrigger()\n\t\t\t.withIdentity(\"two\", \"samples\")\n\t\t\t.withPriority(7)\n\t\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t\t.build();\n\t\t((OperableTrigger) triggerTwo).setNextFireTime(nextFireTime);\n\t\tmockTriggers(triggerOne, triggerTwo);\n\t\tgiven(this.scheduler.getTriggersOfJob(JobKey.jobKey(\"hello\", \"samples\")))\n\t\t\t.willAnswer((invocation) -> Arrays.asList(triggerOne, triggerTwo));\n\t\tQuartzJobDetailsDescriptor jobDetails = this.endpoint.quartzJob(\"samples\", \"hello\", true);\n\t\tassertThat(jobDetails).isNotNull();\n\t\tassertThat(jobDetails.getTriggers()).hasSize(2);\n\t\tassertThat(jobDetails.getTriggers().get(0)).containsEntry(\"name\", \"two\");\n\t\tassertThat(jobDetails.getTriggers().get(1)).containsEntry(\"name\", \"one\");\n\t}\n\n\t@Test\n\tvoid quartzJobWithDataMap() throws SchedulerException {\n\t\tJobDetail job = JobBuilder.newJob(Job.class)\n\t\t\t.withIdentity(\"hello\", \"samples\")\n\t\t\t.usingJobData(\"user\", \"user\")\n\t\t\t.usingJobData(\"password\", \"secret\")\n\t\t\t.usingJobData(\"url\", \"https://user:secret@example.com\")\n\t\t\t.build();\n\t\tmockJobs(job);\n\t\tQuartzJobDetailsDescriptor jobDetails = this.endpoint.quartzJob(\"samples\", \"hello\", true);\n\t\tassertThat(jobDetails).isNotNull();\n\t\tassertThat(jobDetails.getData()).containsOnly(entry(\"user\", \"user\"), entry(\"password\", \"secret\"),\n\t\t\t\tentry(\"url\", \"https://user:secret@example.com\"));\n\t}\n\n\t@Test\n\tvoid quartzJobWithDataMapAndShowUnsanitizedFalse() throws SchedulerException {\n\t\tJobDetail job = JobBuilder.newJob(Job.class)\n\t\t\t.withIdentity(\"hello\", \"samples\")\n\t\t\t.usingJobData(\"user\", \"user\")\n\t\t\t.usingJobData(\"password\", \"secret\")\n\t\t\t.usingJobData(\"url\", \"https://user:secret@example.com\")\n\t\t\t.build();\n\t\tmockJobs(job);\n\t\tQuartzJobDetailsDescriptor jobDetails = this.endpoint.quartzJob(\"samples\", \"hello\", false);\n\t\tassertThat(jobDetails).isNotNull();\n\t\tassertThat(jobDetails.getData()).containsOnly(entry(\"user\", \"******\"), entry(\"password\", \"******\"),\n\t\t\t\tentry(\"url\", \"******\"));\n\t}\n\n\t@Test\n\tvoid quartzJobShouldBeTriggered() throws SchedulerException {\n\t\tJobDetail job = JobBuilder.newJob(Job.class)\n\t\t\t.withIdentity(\"hello\", \"samples\")\n\t\t\t.withDescription(\"A sample job\")\n\t\t\t.storeDurably()\n\t\t\t.requestRecovery(false)\n\t\t\t.build();\n\t\tmockJobs(job);\n\t\tQuartzJobTriggerDescriptor quartzJobTriggerDescriptor = this.endpoint.triggerQuartzJob(\"samples\", \"hello\");\n\t\tassertThat(quartzJobTriggerDescriptor).isNotNull();\n\t\tassertThat(quartzJobTriggerDescriptor.getName()).isEqualTo(\"hello\");\n\t\tassertThat(quartzJobTriggerDescriptor.getGroup()).isEqualTo(\"samples\");\n\t\tassertThat(quartzJobTriggerDescriptor.getClassName()).isEqualTo(\"org.quartz.Job\");\n\t\tassertThat(quartzJobTriggerDescriptor.getTriggerTime()).isCloseTo(Instant.now(), within(5, ChronoUnit.SECONDS));\n\t\tthen(this.scheduler).should().triggerJob(new JobKey(\"hello\", \"samples\"));\n\t}\n\n\t@Test\n\tvoid quartzJobShouldNotBeTriggeredWhenJobDoesNotExist() throws SchedulerException {\n\t\tQuartzJobTriggerDescriptor quartzJobTriggerDescriptor = this.endpoint.triggerQuartzJob(\"samples\", \"hello\");\n\t\tassertThat(quartzJobTriggerDescriptor).isNull();\n\t\tthen(this.scheduler).should(never()).triggerJob(any());\n\t}\n\n\tprivate void mockJobs(JobDetail... jobs) throws SchedulerException {\n\t\tMultiValueMap<String, JobKey> jobKeys = new LinkedMultiValueMap<>();\n\t\tfor (JobDetail jobDetail : jobs) {\n\t\t\tJobKey key = jobDetail.getKey();\n\t\t\tgiven(this.scheduler.getJobDetail(key)).willReturn(jobDetail);\n\t\t\tjobKeys.add(key.getGroup(), key);\n\t\t}\n\t\tgiven(this.scheduler.getJobGroupNames()).willReturn(new ArrayList<>(jobKeys.keySet()));\n\t\tfor (Entry<String, List<JobKey>> entry : jobKeys.entrySet()) {\n\t\t\tgiven(this.scheduler.getJobKeys(GroupMatcher.jobGroupEquals(entry.getKey())))\n\t\t\t\t.willReturn(new LinkedHashSet<>(entry.getValue()));\n\t\t}\n\t}\n\n\tprivate void mockTriggers(Trigger... triggers) throws SchedulerException {\n\t\tMultiValueMap<String, TriggerKey> triggerKeys = new LinkedMultiValueMap<>();\n\t\tfor (Trigger trigger : triggers) {\n\t\t\tTriggerKey key = trigger.getKey();\n\t\t\tgiven(this.scheduler.getTrigger(key)).willReturn(trigger);\n\t\t\ttriggerKeys.add(key.getGroup(), key);\n\t\t}\n\t\tgiven(this.scheduler.getTriggerGroupNames()).willReturn(new ArrayList<>(triggerKeys.keySet()));\n\t\tfor (Entry<String, List<TriggerKey>> entry : triggerKeys.entrySet()) {\n\t\t\tgiven(this.scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(entry.getKey())))\n\t\t\t\t.willReturn(new LinkedHashSet<>(entry.getValue()));\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate static InstanceOfAssertFactory<Map, MapAssert<String, Object>> nestedMap() {\n\t\treturn InstanceOfAssertFactories.map(String.class, Object.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/java/org/springframework/boot/quartz/actuate/endpoint/QuartzEndpointWebExtensionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.actuate.endpoint;\n\nimport java.security.Principal;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzGroupsDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobDetailsDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzJobGroupSummaryDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint.QuartzTriggerGroupSummaryDescriptor;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpointWebExtension.QuartzEndpointWebExtensionRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link QuartzEndpointWebExtension}.\n *\n * @author Moritz Halbritter\n * @author Madhura Bhave\n */\nclass QuartzEndpointWebExtensionTests {\n\n\tprivate QuartzEndpoint delegate;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.delegate = mock(QuartzEndpoint.class);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsNever() throws Exception {\n\t\tQuartzEndpointWebExtension webExtension = new QuartzEndpointWebExtension(this.delegate, Show.NEVER,\n\t\t\t\tCollections.emptySet());\n\t\twebExtension.quartzJobOrTrigger(SecurityContext.NONE, \"jobs\", \"a\", \"b\");\n\t\twebExtension.quartzJobOrTrigger(SecurityContext.NONE, \"triggers\", \"a\", \"b\");\n\t\tthen(this.delegate).should().quartzJob(\"a\", \"b\", false);\n\t\tthen(this.delegate).should().quartzTrigger(\"a\", \"b\", false);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsAlways() throws Exception {\n\t\tQuartzEndpointWebExtension webExtension = new QuartzEndpointWebExtension(this.delegate, Show.ALWAYS,\n\t\t\t\tCollections.emptySet());\n\t\twebExtension.quartzJobOrTrigger(SecurityContext.NONE, \"a\", \"b\", \"c\");\n\t\twebExtension.quartzJobOrTrigger(SecurityContext.NONE, \"jobs\", \"a\", \"b\");\n\t\twebExtension.quartzJobOrTrigger(SecurityContext.NONE, \"triggers\", \"a\", \"b\");\n\t\tthen(this.delegate).should().quartzJob(\"a\", \"b\", true);\n\t\tthen(this.delegate).should().quartzTrigger(\"a\", \"b\", true);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsWhenAuthorizedAndSecurityContextIsAuthorized() throws Exception {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tgiven(securityContext.getPrincipal()).willReturn(mock(Principal.class));\n\t\tQuartzEndpointWebExtension webExtension = new QuartzEndpointWebExtension(this.delegate, Show.WHEN_AUTHORIZED,\n\t\t\t\tCollections.emptySet());\n\t\twebExtension.quartzJobOrTrigger(securityContext, \"jobs\", \"a\", \"b\");\n\t\twebExtension.quartzJobOrTrigger(securityContext, \"triggers\", \"a\", \"b\");\n\t\tthen(this.delegate).should().quartzJob(\"a\", \"b\", true);\n\t\tthen(this.delegate).should().quartzTrigger(\"a\", \"b\", true);\n\t}\n\n\t@Test\n\tvoid whenShowValuesIsWhenAuthorizedAndSecurityContextIsNotAuthorized() throws Exception {\n\t\tSecurityContext securityContext = mock(SecurityContext.class);\n\t\tQuartzEndpointWebExtension webExtension = new QuartzEndpointWebExtension(this.delegate, Show.WHEN_AUTHORIZED,\n\t\t\t\tCollections.emptySet());\n\t\twebExtension.quartzJobOrTrigger(securityContext, \"jobs\", \"a\", \"b\");\n\t\twebExtension.quartzJobOrTrigger(securityContext, \"triggers\", \"a\", \"b\");\n\t\tthen(this.delegate).should().quartzJob(\"a\", \"b\", false);\n\t\tthen(this.delegate).should().quartzTrigger(\"a\", \"b\", false);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew QuartzEndpointWebExtensionRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tSet<Class<?>> bindingTypes = Set.of(QuartzGroupsDescriptor.class, QuartzJobDetailsDescriptor.class,\n\t\t\t\tQuartzJobGroupSummaryDescriptor.class, QuartzTriggerGroupSummaryDescriptor.class);\n\t\tfor (Class<?> bindingType : bindingTypes) {\n\t\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t\t.onType(bindingType)\n\t\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/java/org/springframework/boot/quartz/actuate/endpoint/QuartzEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.actuate.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport net.minidev.json.JSONArray;\nimport org.quartz.CalendarIntervalScheduleBuilder;\nimport org.quartz.CalendarIntervalTrigger;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.Job;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.Trigger.TriggerState;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.matchers.GroupMatcher;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.scheduling.quartz.DelegatingJob;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link QuartzEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Stephane Nicoll\n */\nclass QuartzEndpointWebIntegrationTests {\n\n\tprivate static final JobDetail jobOne = JobBuilder.newJob(Job.class)\n\t\t.withIdentity(\"jobOne\", \"samples\")\n\t\t.usingJobData(new JobDataMap(Collections.singletonMap(\"name\", \"test\")))\n\t\t.withDescription(\"A sample job\")\n\t\t.build();\n\n\tprivate static final JobDetail jobTwo = JobBuilder.newJob(DelegatingJob.class)\n\t\t.withIdentity(\"jobTwo\", \"samples\")\n\t\t.build();\n\n\tprivate static final JobDetail jobThree = JobBuilder.newJob(Job.class).withIdentity(\"jobThree\").build();\n\n\tprivate static final CronTrigger triggerOne = TriggerBuilder.newTrigger()\n\t\t.withDescription(\"Once a day 3AM\")\n\t\t.withIdentity(\"triggerOne\")\n\t\t.withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(3, 0))\n\t\t.build();\n\n\tprivate static final SimpleTrigger triggerTwo = TriggerBuilder.newTrigger()\n\t\t.withDescription(\"Once a day\")\n\t\t.withIdentity(\"triggerTwo\", \"tests\")\n\t\t.withSchedule(SimpleScheduleBuilder.repeatHourlyForever(24))\n\t\t.build();\n\n\tprivate static final CalendarIntervalTrigger triggerThree = TriggerBuilder.newTrigger()\n\t\t.withDescription(\"Once a week\")\n\t\t.withIdentity(\"triggerThree\", \"tests\")\n\t\t.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInWeeks(1))\n\t\t.build();\n\n\t@WebEndpointTest\n\tvoid quartzReport(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"jobs.groups\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"samples\").appendElement(\"DEFAULT\"))\n\t\t\t.jsonPath(\"triggers.groups\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"DEFAULT\").appendElement(\"tests\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzJobNames(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz/jobs\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"groups.samples.jobs\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"jobOne\").appendElement(\"jobTwo\"))\n\t\t\t.jsonPath(\"groups.DEFAULT.jobs\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"jobThree\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerNames(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz/triggers\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"groups.DEFAULT.paused\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"groups.DEFAULT.triggers\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"triggerOne\"))\n\t\t\t.jsonPath(\"groups.tests.paused\")\n\t\t\t.isEqualTo(false)\n\t\t\t.jsonPath(\"groups.tests.triggers\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(\"triggerTwo\").appendElement(\"triggerThree\"));\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggersOrJobsAreAllowed(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/quartz/something-else\").exchange().expectStatus().isBadRequest();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzJobGroupSummary(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz/jobs/samples\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"group\")\n\t\t\t.isEqualTo(\"samples\")\n\t\t\t.jsonPath(\"jobs.jobOne.className\")\n\t\t\t.isEqualTo(Job.class.getName())\n\t\t\t.jsonPath(\"jobs.jobTwo.className\")\n\t\t\t.isEqualTo(DelegatingJob.class.getName());\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzJobGroupSummaryWithUnknownGroup(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/quartz/jobs/does-not-exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerGroupSummary(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz/triggers/tests\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"group\")\n\t\t\t.isEqualTo(\"tests\")\n\t\t\t.jsonPath(\"paused\")\n\t\t\t.isEqualTo(\"false\")\n\t\t\t.jsonPath(\"triggers.cron\")\n\t\t\t.isEmpty()\n\t\t\t.jsonPath(\"triggers.simple.triggerTwo.interval\")\n\t\t\t.isEqualTo(86400000)\n\t\t\t.jsonPath(\"triggers.dailyTimeInterval\")\n\t\t\t.isEmpty()\n\t\t\t.jsonPath(\"triggers.calendarInterval.triggerThree.interval\")\n\t\t\t.isEqualTo(604800000)\n\t\t\t.jsonPath(\"triggers.custom\")\n\t\t\t.isEmpty();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerGroupSummaryWithUnknownGroup(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/quartz/triggers/does-not-exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzJobDetail(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz/jobs/samples/jobOne\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"group\")\n\t\t\t.isEqualTo(\"samples\")\n\t\t\t.jsonPath(\"name\")\n\t\t\t.isEqualTo(\"jobOne\")\n\t\t\t.jsonPath(\"data.name\")\n\t\t\t.isEqualTo(\"test\");\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzJobDetailWithUnknownKey(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/quartz/jobs/samples/does-not-exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerDetail(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri(\"/actuator/quartz/triggers/DEFAULT/triggerOne\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"group\")\n\t\t\t.isEqualTo(\"DEFAULT\")\n\t\t\t.jsonPath(\"name\")\n\t\t\t.isEqualTo(\"triggerOne\")\n\t\t\t.jsonPath(\"description\")\n\t\t\t.isEqualTo(\"Once a day 3AM\")\n\t\t\t.jsonPath(\"state\")\n\t\t\t.isEqualTo(\"NORMAL\")\n\t\t\t.jsonPath(\"type\")\n\t\t\t.isEqualTo(\"cron\")\n\t\t\t.jsonPath(\"simple\")\n\t\t\t.doesNotExist()\n\t\t\t.jsonPath(\"calendarInterval\")\n\t\t\t.doesNotExist()\n\t\t\t.jsonPath(\"dailyInterval\")\n\t\t\t.doesNotExist()\n\t\t\t.jsonPath(\"custom\")\n\t\t\t.doesNotExist()\n\t\t\t.jsonPath(\"cron.expression\")\n\t\t\t.isEqualTo(\"0 0 3 ? * *\");\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerDetailWithUnknownKey(WebTestClient client) {\n\t\tclient.get().uri(\"/actuator/quartz/triggers/tests/does-not-exist\").exchange().expectStatus().isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerJob(WebTestClient client) {\n\t\tclient.post()\n\t\t\t.uri(\"/actuator/quartz/jobs/samples/jobOne\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.bodyValue(Map.of(\"state\", \"running\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"group\")\n\t\t\t.isEqualTo(\"samples\")\n\t\t\t.jsonPath(\"name\")\n\t\t\t.isEqualTo(\"jobOne\")\n\t\t\t.jsonPath(\"className\")\n\t\t\t.isEqualTo(\"org.quartz.Job\")\n\t\t\t.jsonPath(\"triggerTime\")\n\t\t\t.isNotEmpty();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerJobWithUnknownJobKey(WebTestClient client) {\n\t\tclient.post()\n\t\t\t.uri(\"/actuator/quartz/jobs/samples/does-not-exist\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.bodyValue(Map.of(\"state\", \"running\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNotFound();\n\t}\n\n\t@WebEndpointTest\n\tvoid quartzTriggerJobWithUnknownState(WebTestClient client) {\n\t\tclient.post()\n\t\t\t.uri(\"/actuator/quartz/jobs/samples/jobOne\")\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.bodyValue(Map.of(\"state\", \"unknown\"))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isBadRequest();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tScheduler scheduler() throws SchedulerException {\n\t\t\tScheduler scheduler = mock(Scheduler.class);\n\t\t\tmockJobs(scheduler, jobOne, jobTwo, jobThree);\n\t\t\tmockTriggers(scheduler, triggerOne, triggerTwo, triggerThree);\n\t\t\treturn scheduler;\n\t\t}\n\n\t\t@Bean\n\t\tQuartzEndpoint endpoint(Scheduler scheduler) {\n\t\t\treturn new QuartzEndpoint(scheduler, Collections.emptyList());\n\t\t}\n\n\t\t@Bean\n\t\tQuartzEndpointWebExtension quartzEndpointWebExtension(QuartzEndpoint endpoint) {\n\t\t\treturn new QuartzEndpointWebExtension(endpoint, Show.ALWAYS, Collections.emptySet());\n\t\t}\n\n\t\tprivate void mockJobs(Scheduler scheduler, JobDetail... jobs) throws SchedulerException {\n\t\t\tMultiValueMap<String, JobKey> jobKeys = new LinkedMultiValueMap<>();\n\t\t\tfor (JobDetail jobDetail : jobs) {\n\t\t\t\tJobKey key = jobDetail.getKey();\n\t\t\t\tgiven(scheduler.getJobDetail(key)).willReturn(jobDetail);\n\t\t\t\tjobKeys.add(key.getGroup(), key);\n\t\t\t}\n\t\t\tgiven(scheduler.getJobGroupNames()).willReturn(new ArrayList<>(jobKeys.keySet()));\n\t\t\tfor (Entry<String, List<JobKey>> entry : jobKeys.entrySet()) {\n\t\t\t\tgiven(scheduler.getJobKeys(GroupMatcher.jobGroupEquals(entry.getKey())))\n\t\t\t\t\t.willReturn(new LinkedHashSet<>(entry.getValue()));\n\t\t\t}\n\t\t}\n\n\t\tvoid mockTriggers(Scheduler scheduler, Trigger... triggers) throws SchedulerException {\n\t\t\tMultiValueMap<String, TriggerKey> triggerKeys = new LinkedMultiValueMap<>();\n\t\t\tfor (Trigger trigger : triggers) {\n\t\t\t\tTriggerKey key = trigger.getKey();\n\t\t\t\tgiven(scheduler.getTrigger(key)).willReturn(trigger);\n\t\t\t\tgiven(scheduler.getTriggerState(key)).willReturn(TriggerState.NORMAL);\n\t\t\t\ttriggerKeys.add(key.getGroup(), key);\n\t\t\t}\n\t\t\tgiven(scheduler.getTriggerGroupNames()).willReturn(new ArrayList<>(triggerKeys.keySet()));\n\t\t\tfor (Entry<String, List<TriggerKey>> entry : triggerKeys.entrySet()) {\n\t\t\t\tgiven(scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(entry.getKey())))\n\t\t\t\t\t.willReturn(new LinkedHashSet<>(entry.getValue()));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/java/org/springframework/boot/quartz/autoconfigure/QuartzAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.concurrent.Executor;\n\nimport javax.sql.DataSource;\n\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.quartz.Calendar;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SchedulerFactory;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.calendar.MonthlyCalendar;\nimport org.quartz.impl.calendar.WeeklyCalendar;\nimport org.quartz.simpl.RAMJobStore;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.scheduling.quartz.LocalDataSourceJobStore;\nimport org.springframework.scheduling.quartz.QuartzJobBean;\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link QuartzAutoConfiguration}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass QuartzAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\")\n\t\t.withConfiguration(AutoConfigurations.of(QuartzAutoConfiguration.class));\n\n\t@Test\n\tvoid withNoDataSource() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\tassertThat(scheduler.getMetaData().getJobStoreClass()).isAssignableFrom(RAMJobStore.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withDataSourceUseMemoryByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\t\tassertThat(scheduler.getMetaData().getJobStoreClass()).isAssignableFrom(RAMJobStore.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run(assertDataSourceInitializedByDataSourceDatabaseScriptInitializer(\"dataSource\"));\n\t}\n\n\t@Test\n\tvoid withDataSourceAndInMemoryStoreDoesNotInitializeDataSource() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=memory\")\n\t\t\t.run((context) -> {\n\t\t\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(\"dataSource\", DataSource.class));\n\t\t\t\tassertThat(jdbcTemplate.queryForList(\"SHOW TABLES\")\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map((table) -> (String) table.get(\"TABLE_NAME\"))).noneMatch((name) -> name.startsWith(\"QRTZ\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid dataSourceInitializationBacksOffWithoutSpringBootJdbc() {\n\t\tthis.contextRunner.withBean(DataSource.class, QuartzAutoConfigurationTests::createTestDataSource)\n\t\t\t.withBean(SchedulerFactoryBeanCustomizer.class, () -> (schedulerFactoryBean) -> {\n\t\t\t\t// Mock out the scheduler so that the context doesn't fail to start\n\t\t\t\t// due to missing tables that the JDBC job store requires.\n\t\t\t\ttry {\n\t\t\t\t\tSchedulerFactory factory = mock(SchedulerFactory.class);\n\t\t\t\t\tgiven(factory.getScheduler()).willReturn(mock(Scheduler.class));\n\t\t\t\t\tgiven(factory.getScheduler(anyString())).willReturn(mock(Scheduler.class));\n\t\t\t\t\tschedulerFactoryBean.setSchedulerFactory(factory);\n\t\t\t\t}\n\t\t\t\tcatch (SchedulerException ex) {\n\t\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.boot.jdbc\", \"org.springframework.boot.sql\") {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t\t\t\tEnumeration<URL> resources = super.getResources(name);\n\t\t\t\t\tif (!name.equals(\"META-INF/spring.factories\")) {\n\t\t\t\t\t\treturn resources;\n\t\t\t\t\t}\n\t\t\t\t\t// Hide META-INF/spring.factories files with entries from\n\t\t\t\t\t// org.springframework.boot.jdbc\n\t\t\t\t\treturn Collections.enumeration(Collections.list(resources).stream().filter((url) -> {\n\t\t\t\t\t\ttry (InputStream input = url.openStream()) {\n\t\t\t\t\t\t\tString content = StreamUtils.copyToString(input, StandardCharsets.UTF_8);\n\t\t\t\t\t\t\treturn !content.contains(\"org.springframework.boot.jdbc.\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}).toList());\n\t\t\t\t}\n\n\t\t\t})\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(QuartzDataSourceScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid withDataSourceNoTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run(assertDataSourceInitializedByDataSourceDatabaseScriptInitializer(\"dataSource\"));\n\t}\n\n\t@Test\n\tvoid dataSourceWithQuartzDataSourceQualifierUsedWhenMultiplePresent() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class, MultipleDataSourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run(assertDataSourceInitializedByDataSourceDatabaseScriptInitializer(\"quartzDataSource\"));\n\t}\n\n\t@Test\n\tvoid transactionManagerWithQuartzTransactionManagerUsedWhenMultiplePresent() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(QuartzJobsConfiguration.class, MultipleTransactionManagersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run((context) -> {\n\t\t\t\tSchedulerFactoryBean schedulerFactoryBean = context.getBean(SchedulerFactoryBean.class);\n\t\t\t\tassertThat(schedulerFactoryBean).extracting(\"transactionManager\")\n\t\t\t\t\t.isEqualTo(context.getBean(\"quartzTransactionManager\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withTaskExecutor() {\n\t\tthis.contextRunner.withUserConfiguration(MockExecutorConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.quartz.properties.org.quartz.threadPool.threadCount=50\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\t\tassertThat(scheduler.getMetaData().getThreadPoolSize()).isEqualTo(50);\n\t\t\t\tExecutor executor = context.getBean(Executor.class);\n\t\t\t\tthen(executor).shouldHaveNoInteractions();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withOverwriteExistingJobs() {\n\t\tthis.contextRunner.withUserConfiguration(OverwriteTriggerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.quartz.overwrite-existing-jobs=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\t\tTrigger fooTrigger = scheduler.getTrigger(TriggerKey.triggerKey(\"fooTrigger\"));\n\t\t\t\tassertThat(fooTrigger).isNotNull();\n\t\t\t\tassertThat(((SimpleTrigger) fooTrigger).getRepeatInterval()).isEqualTo(30000);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withConfiguredJobAndTrigger(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(QuartzFullConfiguration.class)\n\t\t\t.withPropertyValues(\"test-name=withConfiguredJobAndTrigger\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\t\tassertThat(scheduler.getJobDetail(JobKey.jobKey(\"fooJob\"))).isNotNull();\n\t\t\t\tassertThat(scheduler.getTrigger(TriggerKey.triggerKey(\"fooTrigger\"))).isNotNull();\n\t\t\t\tAwaitility.waitAtMost(Duration.ofSeconds(5))\n\t\t\t\t\t.untilAsserted(\n\t\t\t\t\t\t\t() -> assertThat(output).contains(\"withConfiguredJobAndTrigger\").contains(\"jobDataValue\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withConfiguredCalendars() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzCalendarsConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\tassertThat(scheduler.getCalendar(\"weekly\")).isNotNull();\n\t\t\tassertThat(scheduler.getCalendar(\"monthly\")).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid withQuartzProperties() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.quartz.properties.org.quartz.scheduler.instanceId=FOO\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\t\tassertThat(scheduler.getSchedulerInstanceId()).isEqualTo(\"FOO\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzCustomConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\tassertThat(scheduler.getSchedulerName()).isEqualTo(\"fooScheduler\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid validateDefaultProperties() {\n\t\tthis.contextRunner.withUserConfiguration(ManualSchedulerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(SchedulerFactoryBean.class);\n\t\t\tSchedulerFactoryBean schedulerFactory = context.getBean(SchedulerFactoryBean.class);\n\t\t\tQuartzProperties properties = new QuartzProperties();\n\t\t\tassertThat(properties.isAutoStartup()).isEqualTo(schedulerFactory.isAutoStartup());\n\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"startupDelay\",\n\t\t\t\t\t(int) properties.getStartupDelay().getSeconds());\n\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"waitForJobsToCompleteOnShutdown\",\n\t\t\t\t\tproperties.isWaitForJobsToCompleteOnShutdown());\n\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"overwriteExistingJobs\",\n\t\t\t\t\tproperties.isOverwriteExistingJobs());\n\n\t\t});\n\n\t}\n\n\t@Test\n\tvoid withCustomConfiguration() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.quartz.auto-startup=false\", \"spring.quartz.startup-delay=1m\",\n\t\t\t\t\t\"spring.quartz.wait-for-jobs-to-complete-on-shutdown=true\",\n\t\t\t\t\t\"spring.quartz.overwrite-existing-jobs=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SchedulerFactoryBean.class);\n\t\t\t\tSchedulerFactoryBean schedulerFactory = context.getBean(SchedulerFactoryBean.class);\n\t\t\t\tassertThat(schedulerFactory.isAutoStartup()).isFalse();\n\t\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"startupDelay\", 60);\n\t\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"waitForJobsToCompleteOnShutdown\", true);\n\t\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"overwriteExistingJobs\", true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withLiquibase() {\n\t\tthis.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class, LiquibaseAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\", \"spring.quartz.jdbc.initialize-schema=never\",\n\t\t\t\t\t\"spring.liquibase.change-log=classpath:org/quartz/impl/jdbcjobstore/liquibase.quartz.init.xml\")\n\t\t\t.run(assertDataSourceInitialized(\"dataSource\").andThen(\n\t\t\t\t\t(context) -> assertThat(context).doesNotHaveBean(QuartzDataSourceScriptDatabaseInitializer.class)));\n\t}\n\n\t@Test\n\tvoid withFlyway(@TempDir Path flywayLocation) throws Exception {\n\t\tClassPathResource tablesResource = new ClassPathResource(\"org/quartz/impl/jdbcjobstore/tables_h2.sql\");\n\t\ttry (InputStream stream = tablesResource.getInputStream()) {\n\t\t\tFiles.copy(stream, flywayLocation.resolve(\"V2__quartz.sql\"));\n\t\t}\n\t\tthis.contextRunner.withUserConfiguration(QuartzJobsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class, FlywayAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\", \"spring.quartz.jdbc.initialize-schema=never\",\n\t\t\t\t\t\"spring.flyway.locations=filesystem:\" + flywayLocation, \"spring.flyway.baseline-on-migrate=true\")\n\t\t\t.run(assertDataSourceInitialized(\"dataSource\").andThen(\n\t\t\t\t\t(context) -> assertThat(context).doesNotHaveBean(QuartzDataSourceScriptDatabaseInitializer.class)));\n\t}\n\n\t@Test\n\tvoid schedulerNameWithDedicatedProperty() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.quartz.scheduler-name=testScheduler\")\n\t\t\t.run(assertSchedulerName(\"testScheduler\"));\n\t}\n\n\t@Test\n\tvoid schedulerNameWithQuartzProperty() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.quartz.properties.org.quartz.scheduler.instanceName=testScheduler\")\n\t\t\t.run(assertSchedulerName(\"testScheduler\"));\n\t}\n\n\t@Test\n\tvoid schedulerNameWithDedicatedPropertyTakesPrecedence() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.quartz.scheduler-name=specificTestScheduler\",\n\t\t\t\t\t\"spring.quartz.properties.org.quartz.scheduler.instanceName=testScheduler\")\n\t\t\t.run(assertSchedulerName(\"specificTestScheduler\"));\n\t}\n\n\t@Test\n\tvoid schedulerNameUseBeanNameByDefault() {\n\t\tthis.contextRunner.withPropertyValues().run(assertSchedulerName(\"quartzScheduler\"));\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnQuartzDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomQuartzDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(QuartzDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.doesNotHaveBean(\"quartzDataSourceScriptDatabaseInitializer\")\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredQuartzInitializerRemains() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.quartz.job-store-type=jdbc\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(QuartzDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertDataSourceInitialized(String dataSourceName) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(Scheduler.class);\n\t\t\tScheduler scheduler = context.getBean(Scheduler.class);\n\t\t\tassertThat(scheduler.getMetaData().getJobStoreClass()).isAssignableFrom(LocalDataSourceJobStore.class);\n\t\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(context.getBean(dataSourceName, DataSource.class));\n\t\t\tassertThat(jdbcTemplate.queryForObject(\"SELECT COUNT(*) FROM QRTZ_JOB_DETAILS\", Integer.class))\n\t\t\t\t.isEqualTo(2);\n\t\t\tassertThat(jdbcTemplate.queryForObject(\"SELECT COUNT(*) FROM QRTZ_SIMPLE_TRIGGERS\", Integer.class))\n\t\t\t\t.isZero();\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertDataSourceInitializedByDataSourceDatabaseScriptInitializer(\n\t\t\tString dataSourceName) {\n\t\treturn assertDataSourceInitialized(dataSourceName).andThen((context) -> {\n\t\t\tassertThat(context).hasSingleBean(QuartzDataSourceScriptDatabaseInitializer.class);\n\t\t\tQuartzDataSourceScriptDatabaseInitializer initializer = context\n\t\t\t\t.getBean(QuartzDataSourceScriptDatabaseInitializer.class);\n\t\t\tassertThat(initializer).hasFieldOrPropertyWithValue(\"dataSource\", context.getBean(dataSourceName));\n\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertSchedulerName(String schedulerName) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(SchedulerFactoryBean.class);\n\t\t\tSchedulerFactoryBean schedulerFactory = context.getBean(SchedulerFactoryBean.class);\n\t\t\tassertThat(schedulerFactory).hasFieldOrPropertyWithValue(\"schedulerName\", schedulerName);\n\t\t};\n\t}\n\n\tprivate static DataSource createTestDataSource() {\n\t\tDataSourceProperties properties = new DataSourceProperties();\n\t\tproperties.setGenerateUniqueName(true);\n\t\ttry {\n\t\t\tproperties.afterPropertiesSet();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn properties.initializeDataSourceBuilder().build();\n\t}\n\n\t@Import(ComponentThatUsesScheduler.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseQuartzConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class QuartzJobsConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\tJobDetail fooJob() {\n\t\t\treturn JobBuilder.newJob().ofType(FooJob.class).withIdentity(\"fooJob\").storeDurably().build();\n\t\t}\n\n\t\t@Bean\n\t\tJobDetail barJob() {\n\t\t\treturn JobBuilder.newJob().ofType(FooJob.class).withIdentity(\"barJob\").storeDurably().build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class QuartzFullConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\tJobDetail fooJob() {\n\t\t\treturn JobBuilder.newJob()\n\t\t\t\t.ofType(FooJob.class)\n\t\t\t\t.withIdentity(\"fooJob\")\n\t\t\t\t.usingJobData(\"jobDataKey\", \"jobDataValue\")\n\t\t\t\t.storeDurably()\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tTrigger fooTrigger(JobDetail jobDetail) {\n\t\t\tSimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()\n\t\t\t\t.withIntervalInSeconds(10)\n\t\t\t\t.repeatForever();\n\n\t\t\treturn TriggerBuilder.newTrigger()\n\t\t\t\t.forJob(jobDetail)\n\t\t\t\t.withIdentity(\"fooTrigger\")\n\t\t\t\t.withSchedule(scheduleBuilder)\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(QuartzFullConfiguration.class)\n\tstatic class OverwriteTriggerConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\tTrigger anotherFooTrigger(JobDetail fooJob) {\n\t\t\tSimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()\n\t\t\t\t.withIntervalInSeconds(30)\n\t\t\t\t.repeatForever();\n\n\t\t\treturn TriggerBuilder.newTrigger()\n\t\t\t\t.forJob(fooJob)\n\t\t\t\t.withIdentity(\"fooTrigger\")\n\t\t\t\t.withSchedule(scheduleBuilder)\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class QuartzCalendarsConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\tCalendar weekly() {\n\t\t\treturn new WeeklyCalendar();\n\t\t}\n\n\t\t@Bean\n\t\tCalendar monthly() {\n\t\t\treturn new MonthlyCalendar();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockExecutorConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\tExecutor executor() {\n\t\t\treturn mock(Executor.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class QuartzCustomConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\tSchedulerFactoryBeanCustomizer customizer() {\n\t\t\treturn (schedulerFactoryBean) -> schedulerFactoryBean.setSchedulerName(\"fooScheduler\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ManualSchedulerConfiguration {\n\n\t\t@Bean\n\t\tSchedulerFactoryBean quartzScheduler() {\n\t\t\treturn new SchedulerFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleDataSourceConfiguration extends BaseQuartzConfiguration {\n\n\t\t@Bean\n\t\t@Primary\n\t\tDataSource applicationDataSource() {\n\t\t\treturn createTestDataSource();\n\t\t}\n\n\t\t@QuartzDataSource\n\t\t@Bean\n\t\tDataSource quartzDataSource() {\n\t\t\treturn createTestDataSource();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleTransactionManagersConfiguration extends BaseQuartzConfiguration {\n\n\t\tprivate final DataSource primaryDataSource = createTestDataSource();\n\n\t\tprivate final DataSource quartzDataSource = createTestDataSource();\n\n\t\t@Bean\n\t\t@Primary\n\t\tDataSource applicationDataSource() {\n\t\t\treturn this.primaryDataSource;\n\t\t}\n\n\t\t@Bean\n\t\t@QuartzDataSource\n\t\tDataSource quartzDataSource() {\n\t\t\treturn this.quartzDataSource;\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tPlatformTransactionManager applicationTransactionManager() {\n\t\t\treturn new DataSourceTransactionManager(this.primaryDataSource);\n\t\t}\n\n\t\t@Bean\n\t\t@QuartzTransactionManager\n\t\tPlatformTransactionManager quartzTransactionManager() {\n\t\t\treturn new DataSourceTransactionManager(this.quartzDataSource);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomQuartzDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tQuartzDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource,\n\t\t\t\tQuartzJdbcProperties properties) {\n\t\t\treturn new QuartzDataSourceScriptDatabaseInitializer(dataSource, properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) {\n\t\t\treturn new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings());\n\t\t}\n\n\t}\n\n\tstatic class ComponentThatUsesScheduler {\n\n\t\tComponentThatUsesScheduler(Scheduler scheduler) {\n\t\t\tAssert.notNull(scheduler, \"'scheduler' must not be null\");\n\t\t}\n\n\t}\n\n\tpublic static class FooJob extends QuartzJobBean {\n\n\t\t@Autowired\n\t\tprivate Environment env;\n\n\t\tprivate @Nullable String jobDataKey;\n\n\t\t@Override\n\t\tprotected void executeInternal(JobExecutionContext context) {\n\t\t\tSystem.out.println(this.env.getProperty(\"test-name\", \"unknown\") + \" - \" + this.jobDataKey);\n\t\t}\n\n\t\tpublic void setJobDataKey(@Nullable String jobDataKey) {\n\t\t\tthis.jobDataKey = jobDataKey;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/java/org/springframework/boot/quartz/autoconfigure/QuartzDataSourceScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.Arrays;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.sql.init.ScriptDatabaseInitializerSettings;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link QuartzDataSourceScriptDatabaseInitializer}.\n *\n * @author Stephane Nicoll\n */\nclass QuartzDataSourceScriptDatabaseInitializerTests {\n\n\t@Test\n\tvoid getSettingsWithPlatformDoesNotTouchDataSource() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tQuartzJdbcProperties properties = new QuartzJdbcProperties();\n\t\tproperties.setPlatform(\"test\");\n\t\tDatabaseInitializationSettings settings = ScriptDatabaseInitializerSettings\n\t\t\t.get(new QuartzDataSourceScriptDatabaseInitializer(dataSource, properties));\n\t\tassertThat(settings.getSchemaLocations())\n\t\t\t.containsOnly(\"classpath:org/quartz/impl/jdbcjobstore/tables_test.sql\");\n\t\tthen(dataSource).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\tvoid customizeSetCommentPrefixes() {\n\t\tQuartzJdbcProperties properties = new QuartzJdbcProperties();\n\t\tproperties.setPlatform(\"test\");\n\t\tproperties.setCommentPrefix(Arrays.asList(\"##\", \"--\"));\n\t\tQuartzDataSourceScriptDatabaseInitializer initializer = new QuartzDataSourceScriptDatabaseInitializer(\n\t\t\t\tmock(DataSource.class), properties);\n\t\tResourceDatabasePopulator populator = mock(ResourceDatabasePopulator.class);\n\t\tinitializer.customize(populator);\n\t\tthen(populator).should().setCommentPrefixes(\"##\", \"--\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/java/org/springframework/boot/quartz/autoconfigure/QuartzEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.quartz.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Scheduler;\n\nimport org.springframework.boot.actuate.endpoint.Show;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpoint;\nimport org.springframework.boot.quartz.actuate.endpoint.QuartzEndpointWebExtension;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link QuartzEndpointAutoConfiguration}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\nclass QuartzEndpointAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(QuartzEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid endpointIsAutoConfigured() {\n\t\tthis.contextRunner.withBean(Scheduler.class, () -> mock(Scheduler.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=quartz\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(QuartzEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointIsNotAutoConfiguredIfSchedulerIsNotAvailable() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=quartz\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(QuartzEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointNotAutoConfiguredWhenNotExposed() {\n\t\tthis.contextRunner.withBean(Scheduler.class, () -> mock(Scheduler.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(QuartzEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointCanBeDisabled() {\n\t\tthis.contextRunner.withBean(Scheduler.class, () -> mock(Scheduler.class))\n\t\t\t.withPropertyValues(\"management.endpoint.quartz.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(QuartzEndpoint.class));\n\t}\n\n\t@Test\n\tvoid endpointBacksOffWhenUserProvidedEndpointIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomEndpointConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(QuartzEndpoint.class).hasBean(\"customEndpoint\"));\n\t}\n\n\t@Test\n\tvoid runWhenOnlyExposedOverJmxShouldHaveEndpointBeanWithoutWebExtension() {\n\t\tthis.contextRunner.withBean(Scheduler.class, () -> mock(Scheduler.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=info\", \"spring.jmx.enabled=true\",\n\t\t\t\t\t\"management.endpoints.jmx.exposure.include=quartz\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(QuartzEndpoint.class)\n\t\t\t\t.doesNotHaveBean(QuartzEndpointWebExtension.class));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid rolesCanBeConfiguredViaTheEnvironment() {\n\t\tthis.contextRunner.withBean(Scheduler.class, () -> mock(Scheduler.class))\n\t\t\t.withPropertyValues(\"management.endpoint.quartz.roles: test\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=quartz\")\n\t\t\t.withSystemProperties(\"dbPassword=123456\", \"apiKey=123456\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(QuartzEndpointWebExtension.class);\n\t\t\t\tQuartzEndpointWebExtension endpoint = context.getBean(QuartzEndpointWebExtension.class);\n\t\t\t\tSet<String> roles = (Set<String>) ReflectionTestUtils.getField(endpoint, \"roles\");\n\t\t\t\tassertThat(roles).contains(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid showValuesCanBeConfiguredViaTheEnvironment() {\n\t\tthis.contextRunner.withBean(Scheduler.class, () -> mock(Scheduler.class))\n\t\t\t.withPropertyValues(\"management.endpoint.quartz.show-values: WHEN_AUTHORIZED\")\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=quartz\")\n\t\t\t.withSystemProperties(\"dbPassword=123456\", \"apiKey=123456\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(QuartzEndpointWebExtension.class);\n\t\t\t\tassertThat(context.getBean(QuartzEndpointWebExtension.class)).extracting(\"showValues\")\n\t\t\t\t\t.isEqualTo(Show.WHEN_AUTHORIZED);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomEndpointConfiguration {\n\n\t\t@Bean\n\t\tCustomEndpoint customEndpoint() {\n\t\t\treturn new CustomEndpoint();\n\t\t}\n\n\t}\n\n\tprivate static final class CustomEndpoint extends QuartzEndpoint {\n\n\t\tprivate CustomEndpoint() {\n\t\t\tsuper(mock(Scheduler.class), Collections.emptyList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/resources/org/springframework/boot/quartz/autoconfigure/tables_#_comments.sql",
    "content": "# This is a test script to check # is treated as a comment prefix by default\n\nCREATE TABLE QRTZ_TEST_TABLE (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR (200) NOT NULL\n);\n\n# Another comment\n\nCOMMIT;\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/resources/org/springframework/boot/quartz/autoconfigure/tables_--_comments.sql",
    "content": "-- This is a test script to check -- is treated as a comment prefix by default\n\nCREATE TABLE QRTZ_TEST_TABLE (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR (200) NOT NULL\n);\n\n-- Another comment\n\nCOMMIT;\n"
  },
  {
    "path": "module/spring-boot-quartz/src/test/resources/org/springframework/boot/quartz/autoconfigure/tables_custom_comment_prefix.sql",
    "content": "** This is a test script to check ** is treated as a comment prefix when prefix is customized\n\nCREATE TABLE QRTZ_TEST_TABLE (\n  SCHED_NAME VARCHAR(120) NOT NULL,\n  CALENDAR_NAME VARCHAR (200) NOT NULL\n);\n\n** Another comment\n\nCOMMIT;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot R2DBC\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-sql\"))\n\tapi(project(\":module:spring-boot-transaction\"))\n\tapi(\"org.springframework:spring-r2dbc\")\n\n\tcompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-jdbc\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"io.r2dbc:r2dbc-pool\")\n\toptional(\"io.r2dbc:r2dbc-proxy\")\n\toptional(\"io.r2dbc:r2dbc-spi\")\n\toptional(\"org.testcontainers:testcontainers-clickhouse\")\n\toptional(\"org.testcontainers:testcontainers-jdbc\")\n\toptional(\"org.testcontainers:testcontainers-mariadb\")\n\toptional(\"org.testcontainers:testcontainers-mssqlserver\")\n\toptional(\"org.testcontainers:testcontainers-mysql\")\n\toptional(\"org.testcontainers:testcontainers-oracle-xe\")\n\toptional(\"org.testcontainers:testcontainers-oracle-free\")\n\toptional(\"org.testcontainers:testcontainers-postgresql\")\n\toptional(\"org.testcontainers:testcontainers-r2dbc\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":module:spring-boot-jdbc\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\tdockerTestRuntimeOnly(\"com.clickhouse:clickhouse-r2dbc\")\n\tdockerTestRuntimeOnly(\"com.oracle.database.r2dbc:oracle-r2dbc\")\n\tdockerTestRuntimeOnly(\"io.r2dbc:r2dbc-mssql\")\n\tdockerTestRuntimeOnly(\"org.postgresql:r2dbc-postgresql\")\n\n\ttestCompileOnly(\"com.fasterxml.jackson.core:jackson-annotations\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-jdbc\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-testcontainers\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-sql\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"io.r2dbc:r2dbc-h2\")\n\ttestImplementation(\"org.postgresql:r2dbc-postgresql\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/ClickHouseR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactories;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ClickHouseR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"clickhouse-compose.yaml\", image = TestImage.CLICKHOUSE)\n\tvoid runCreatesConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.toString()).contains(\"database=mydatabase\", \"driver=clickhouse\",\n\t\t\t\t\"password=REDACTED\", \"user=myuser\");\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t}\n\n\tprivate void checkDatabaseAccess(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tConnectionFactory connectionFactory = ConnectionFactories.get(connectionFactoryOptions);\n\t\tString sql = DatabaseDriver.CLICKHOUSE.getValidationQuery();\n\t\tInteger result = Mono.from(connectionFactory.create())\n\t\t\t.flatMapMany((connection) -> connection.createStatement(sql).execute())\n\t\t\t.flatMap((r) -> r.map((row, rowMetadata) -> row.get(0, Integer.class)))\n\t\t\t.blockFirst(Duration.ofSeconds(30));\n\t\tassertThat(result).isEqualTo(1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/MariaDbR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MariaDbR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MariaDbR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mariadb-compose.yaml\", image = TestImage.MARIADB)\n\tvoid runCreatesConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.toString()).contains(\"database=mydatabase\", \"driver=mariadb\",\n\t\t\t\t\"password=REDACTED\", \"user=myuser\");\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/MySqlR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link MySqlR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass MySqlR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mysql-compose.yaml\", image = TestImage.MYSQL)\n\tvoid runCreatesConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t}\n\n\tprivate void assertConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.toString()).contains(\"database=mydatabase\", \"driver=mysql\",\n\t\t\t\t\"password=REDACTED\", \"user=myuser\");\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/OracleFreeR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactories;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.awaitility.Awaitility;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OracleFreeR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass OracleFreeR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"oracle-compose.yaml\", image = TestImage.ORACLE_FREE)\n\tvoid runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.toString()).contains(\"database=freepdb1\", \"driver=oracle\",\n\t\t\t\t\"password=REDACTED\", \"user=app_user\");\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD))\n\t\t\t.isEqualTo(\"app_user_secret\");\n\t\tAwaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().untilAsserted(() -> {\n\t\t\tString validationQuery = DatabaseDriver.ORACLE.getValidationQuery();\n\t\t\tassertThat(validationQuery).isNotNull();\n\t\t\tObject result = DatabaseClient.create(ConnectionFactories.get(connectionFactoryOptions))\n\t\t\t\t.sql(validationQuery)\n\t\t\t\t.map((row, metadata) -> row.get(0))\n\t\t\t\t.first()\n\t\t\t\t.block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/OracleXeR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactories;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link OracleXeR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\tdisabledReason = \"The Oracle image has no ARM support\")\nclass OracleXeR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"oracle-compose.yaml\", image = TestImage.ORACLE_XE)\n\tvoid runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.toString()).contains(\"database=xepdb1\", \"driver=oracle\",\n\t\t\t\t\"password=REDACTED\", \"user=app_user\");\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD))\n\t\t\t.isEqualTo(\"app_user_secret\");\n\t\tAwaitility.await().atMost(Duration.ofMinutes(1)).ignoreExceptions().untilAsserted(() -> {\n\t\t\tString validationQuery = DatabaseDriver.ORACLE.getValidationQuery();\n\t\t\tassertThat(validationQuery).isNotNull();\n\t\t\tObject result = DatabaseClient.create(ConnectionFactories.get(connectionFactoryOptions))\n\t\t\t\t.sql(validationQuery)\n\t\t\t\t.map((row, metadata) -> row.get(0))\n\t\t\t\t.first()\n\t\t\t\t.block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).isEqualTo(\"Hello\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/PostgresR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactories;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Option;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link PostgresR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author He Zean\n */\nclass PostgresR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"postgres-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"postgres-with-trust-host-auth-method-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetailsThatCanAccessDatabaseWhenHostAuthMethodIsTrust(\n\t\t\tR2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"myuser\");\n\t\tassertThat(connectionFactoryOptions.getValue(ConnectionFactoryOptions.PASSWORD)).isNull();\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.DATABASE))\n\t\t\t.isEqualTo(\"mydatabase\");\n\t\tcheckDatabaseAccess(connectionDetails);\n\t}\n\n\t@DockerComposeTest(composeFile = \"postgres-application-name-compose.yaml\", image = TestImage.POSTGRESQL)\n\tvoid runCreatesConnectionDetailsApplicationName(R2dbcConnectionDetails connectionDetails) {\n\t\tassertConnectionDetails(connectionDetails);\n\t\tConnectionFactoryOptions options = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(options.getValue(Option.valueOf(\"applicationName\"))).isEqualTo(\"spring boot\");\n\t\tassertThat(executeQuery(connectionDetails, \"select current_setting('application_name')\", String.class))\n\t\t\t.isEqualTo(\"spring boot\");\n\t}\n\n\tprivate void assertConnectionDetails(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions options = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.HOST)).isNotNull();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PORT)).isNotNull();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"mydatabase\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"myuser\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"postgresql\");\n\t}\n\n\tprivate void checkDatabaseAccess(R2dbcConnectionDetails connectionDetails) {\n\t\tString validationQuery = DatabaseDriver.POSTGRESQL.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tassertThat(executeQuery(connectionDetails, validationQuery, Integer.class)).isEqualTo(1);\n\t}\n\n\tprivate <T> T executeQuery(R2dbcConnectionDetails connectionDetails, String sql, Class<T> resultClass) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tT result = DatabaseClient.create(ConnectionFactories.get(connectionFactoryOptions))\n\t\t\t.sql(sql)\n\t\t\t.mapValue(resultClass)\n\t\t\t.first()\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(result).isNotNull();\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/docker/compose/SqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactories;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SqlServerR2dbcDockerComposeConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\tdisabledReason = \"The SQL server image has no ARM support\")\nclass SqlServerR2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"mssqlserver-compose.yaml\", image = TestImage.SQL_SERVER)\n\tvoid runCreatesConnectionDetailsThatCanBeUsedToAccessDatabase(R2dbcConnectionDetails connectionDetails) {\n\t\tConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();\n\t\tassertThat(connectionFactoryOptions.toString()).contains(\"driver=mssql\", \"password=REDACTED\", \"user=SA\");\n\t\tassertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD))\n\t\t\t.isEqualTo(\"verYs3cret\");\n\t\tString validationQuery = DatabaseDriver.SQLSERVER.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tObject result = DatabaseClient.create(ConnectionFactories.get(connectionFactoryOptions))\n\t\t\t.sql(validationQuery)\n\t\t\t.map((row, metadata) -> row.get(0))\n\t\t\t.first()\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(result).isEqualTo(1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/testcontainers/OracleFreeR2dbcContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.oracle.OracleContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.r2dbc.core.DatabaseClient;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OracleFreeR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass OracleFreeR2dbcContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final OracleContainer oracle = TestImage.container(OracleContainer.class);\n\n\t@Autowired\n\tConnectionFactory connectionFactory;\n\n\t@Test\n\tvoid connectionCanBeMadeToOracleContainer() {\n\t\tString validationQuery = DatabaseDriver.ORACLE.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tObject result = DatabaseClient.create(this.connectionFactory)\n\t\t\t.sql(validationQuery)\n\t\t\t.map((row, metadata) -> row.get(0))\n\t\t\t.first()\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(result).isEqualTo(\"Hello\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(R2dbcAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/java/org/springframework/boot/r2dbc/testcontainers/OracleXeR2dbcContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.OS;\nimport org.testcontainers.containers.OracleContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.junit.DisabledOnOs;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.r2dbc.core.DatabaseClient;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OracleXeR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\n@DisabledOnOs(os = { OS.LINUX, OS.MAC }, architecture = \"aarch64\",\n\t\tdisabledReason = \"The Oracle image has no ARM support\")\nclass OracleXeR2dbcContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final OracleContainer oracle = TestImage.container(OracleContainer.class);\n\n\t@Autowired\n\tConnectionFactory connectionFactory;\n\n\t@Test\n\tvoid connectionCanBeMadeToOracleContainer() {\n\t\tString validationQuery = DatabaseDriver.ORACLE.getValidationQuery();\n\t\tassertThat(validationQuery).isNotNull();\n\t\tObject result = DatabaseClient.create(this.connectionFactory)\n\t\t\t.sql(validationQuery)\n\t\t\t.map((row, metadata) -> row.get(0))\n\t\t\t.first()\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(result).isEqualTo(\"Hello\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(R2dbcAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/clickhouse-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '8123'\n    environment:\n      - 'CLICKHOUSE_USER=myuser'\n      - 'CLICKHOUSE_PASSWORD=secret'\n      - 'CLICKHOUSE_DB=mydatabase'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/mariadb-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '3306'\n    environment:\n      - 'MARIADB_ROOT_PASSWORD=verysecret'\n      - 'MARIADB_USER=myuser'\n      - 'MARIADB_PASSWORD=secret'\n      - 'MARIADB_DATABASE=mydatabase'\n\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/mssqlserver-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '1433'\n    environment:\n      - 'MSSQL_PID=express'\n      - 'MSSQL_SA_PASSWORD=verYs3cret'\n      - 'ACCEPT_EULA=yes'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/mssqlserver-with-jdbc-parameters-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '1433'\n    environment:\n      - 'MSSQL_PID=express'\n      - 'MSSQL_SA_PASSWORD=verYs3cret'\n      - 'ACCEPT_EULA=yes'\n    labels:\n      org.springframework.boot.jdbc.parameters: sendStringParametersAsUnicode=false"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/mysql-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '3306'\n    environment:\n      - 'MYSQL_ROOT_PASSWORD=verysecret'\n      - 'MYSQL_USER=myuser'\n      - 'MYSQL_PASSWORD=secret'\n      - 'MYSQL_DATABASE=mydatabase'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/oracle-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '1521'\n    environment:\n      - 'APP_USER=app_user'\n      - 'APP_USER_PASSWORD=app_user_secret'\n      - 'ORACLE_PASSWORD=secret'\n    healthcheck:\n      test: [\"CMD-SHELL\", \"healthcheck.sh\"]\n      interval: 10s\n      timeout: 5s\n      retries: 10\n\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/otlp-compose.yaml",
    "content": "services:\n  otlp:\n    image: '{imageName}'\n    ports:\n      - '4317'\n      - '4318'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/postgres-application-name-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n    labels:\n      org.springframework.boot.jdbc.parameters: 'ApplicationName=spring+boot'\n      org.springframework.boot.r2dbc.parameters: 'applicationName=spring boot'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/postgres-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_PASSWORD=secret'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/dockerTest/resources/org/springframework/boot/r2dbc/docker/compose/postgres-with-trust-host-auth-method-compose.yaml",
    "content": "services:\n  database:\n    image: '{imageName}'\n    ports:\n      - '5432'\n    environment:\n      - 'POSTGRES_USER=myuser'\n      - 'POSTGRES_DB=mydatabase'\n      - 'POSTGRES_HOST_AUTH_METHOD=trust'\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.ConnectionPoolConfiguration;\nimport io.r2dbc.pool.PoolingConnectionFactoryProvider;\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactories;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.ConnectionFactoryOptions.Builder;\nimport io.r2dbc.spi.ValidationDepth;\nimport org.jspecify.annotations.Nullable;\nimport org.reactivestreams.Publisher;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Builder for {@link ConnectionFactory}.\n *\n * @author Mark Paluch\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @since 2.5.0\n */\npublic final class ConnectionFactoryBuilder {\n\n\tprivate static final OptionsCapableWrapper optionsCapableWrapper;\n\n\tstatic {\n\t\tif (ClassUtils.isPresent(\"io.r2dbc.pool.ConnectionPool\", ConnectionFactoryBuilder.class.getClassLoader())) {\n\t\t\toptionsCapableWrapper = new PoolingAwareOptionsCapableWrapper();\n\t\t}\n\t\telse {\n\t\t\toptionsCapableWrapper = new OptionsCapableWrapper();\n\t\t}\n\t}\n\n\tprivate static final String COLON = \":\";\n\n\tprivate final Builder optionsBuilder;\n\n\tprivate final List<ConnectionFactoryDecorator> decorators = new ArrayList<>();\n\n\tprivate ConnectionFactoryBuilder(Builder optionsBuilder) {\n\t\tthis.optionsBuilder = optionsBuilder;\n\t}\n\n\t/**\n\t * Initialize a new {@link ConnectionFactoryBuilder} based on the specified R2DBC url.\n\t * @param url the url to use\n\t * @return a new builder initialized with the options exposed in the specified url\n\t * @see EmbeddedDatabaseConnection#getUrl(String)\n\t */\n\tpublic static ConnectionFactoryBuilder withUrl(String url) {\n\t\tAssert.hasText(url, () -> \"'url' must not be null\");\n\t\treturn withOptions(ConnectionFactoryOptions.parse(url).mutate());\n\t}\n\n\t/**\n\t * Initialize a new {@link ConnectionFactoryBuilder} based on the specified\n\t * {@link Builder options}.\n\t * @param options the options to use to initialize the builder\n\t * @return a new builder initialized with the settings defined in the given\n\t * {@link Builder options}\n\t */\n\tpublic static ConnectionFactoryBuilder withOptions(Builder options) {\n\t\treturn new ConnectionFactoryBuilder(options);\n\t}\n\n\t/**\n\t * Initialize a new {@link ConnectionFactoryBuilder} derived from the options of the\n\t * specified {@code connectionFactory}.\n\t * @param connectionFactory the connection factory whose options are to be used to\n\t * initialize the builder\n\t * @return a new builder initialized with the options from the connection factory\n\t * @since 2.5.1\n\t */\n\tpublic static ConnectionFactoryBuilder derivedFrom(ConnectionFactory connectionFactory) {\n\t\tConnectionFactoryOptions options = extractOptionsIfPossible(connectionFactory);\n\t\tif (options == null) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"ConnectionFactoryOptions could not be extracted from \" + connectionFactory);\n\t\t}\n\t\treturn withOptions(options.mutate());\n\t}\n\n\tprivate static @Nullable ConnectionFactoryOptions extractOptionsIfPossible(ConnectionFactory connectionFactory) {\n\t\tOptionsCapableConnectionFactory optionsCapable = OptionsCapableConnectionFactory.unwrapFrom(connectionFactory);\n\t\tif (optionsCapable != null) {\n\t\t\treturn optionsCapable.getOptions();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Configure additional options.\n\t * @param options a {@link Consumer} to customize the options\n\t * @return this for method chaining\n\t */\n\tpublic ConnectionFactoryBuilder configure(Consumer<Builder> options) {\n\t\toptions.accept(this.optionsBuilder);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Configure the {@linkplain ConnectionFactoryOptions#USER username}.\n\t * @param username the connection factory username\n\t * @return this for method chaining\n\t */\n\tpublic ConnectionFactoryBuilder username(String username) {\n\t\treturn configure((options) -> options.option(ConnectionFactoryOptions.USER, username));\n\t}\n\n\t/**\n\t * Configure the {@linkplain ConnectionFactoryOptions#PASSWORD password}.\n\t * @param password the connection factory password\n\t * @return this for method chaining\n\t */\n\tpublic ConnectionFactoryBuilder password(CharSequence password) {\n\t\treturn configure((options) -> options.option(ConnectionFactoryOptions.PASSWORD, password));\n\t}\n\n\t/**\n\t * Configure the {@linkplain ConnectionFactoryOptions#HOST host name}.\n\t * @param host the connection factory hostname\n\t * @return this for method chaining\n\t */\n\tpublic ConnectionFactoryBuilder hostname(String host) {\n\t\treturn configure((options) -> options.option(ConnectionFactoryOptions.HOST, host));\n\t}\n\n\t/**\n\t * Configure the {@linkplain ConnectionFactoryOptions#PORT port}.\n\t * @param port the connection factory port\n\t * @return this for method chaining\n\t */\n\tpublic ConnectionFactoryBuilder port(int port) {\n\t\treturn configure((options) -> options.option(ConnectionFactoryOptions.PORT, port));\n\t}\n\n\t/**\n\t * Configure the {@linkplain ConnectionFactoryOptions#DATABASE database}.\n\t * @param database the connection factory database\n\t * @return this for method chaining\n\t */\n\tpublic ConnectionFactoryBuilder database(String database) {\n\t\treturn configure((options) -> options.option(ConnectionFactoryOptions.DATABASE, database));\n\t}\n\n\t/**\n\t * Add a {@link ConnectionFactoryDecorator decorator}.\n\t * @param decorator the decorator to add\n\t * @return this for method chaining\n\t * @since 3.2.0\n\t */\n\tpublic ConnectionFactoryBuilder decorator(ConnectionFactoryDecorator decorator) {\n\t\tthis.decorators.add(decorator);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Add {@link ConnectionFactoryDecorator decorators}.\n\t * @param decorators the decorators to add\n\t * @return this for method chaining\n\t * @since 3.2.0\n\t */\n\tpublic ConnectionFactoryBuilder decorators(Iterable<ConnectionFactoryDecorator> decorators) {\n\t\tfor (ConnectionFactoryDecorator decorator : decorators) {\n\t\t\tthis.decorators.add(decorator);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Build a {@link ConnectionFactory} based on the state of this builder.\n\t * @return a connection factory\n\t */\n\tpublic ConnectionFactory build() {\n\t\tConnectionFactoryOptions options = buildOptions();\n\t\tConnectionFactory connectionFactory = optionsCapableWrapper.buildAndWrap(options);\n\t\tfor (ConnectionFactoryDecorator decorator : this.decorators) {\n\t\t\tconnectionFactory = decorator.decorate(connectionFactory);\n\t\t}\n\t\treturn connectionFactory;\n\t}\n\n\t/**\n\t * Build a {@link ConnectionFactoryOptions} based on the state of this builder.\n\t * @return the options\n\t */\n\tpublic ConnectionFactoryOptions buildOptions() {\n\t\treturn this.optionsBuilder.build();\n\t}\n\n\tprivate static class OptionsCapableWrapper {\n\n\t\tConnectionFactory buildAndWrap(ConnectionFactoryOptions options) {\n\t\t\tConnectionFactory connectionFactory = ConnectionFactories.get(options);\n\t\t\treturn new OptionsCapableConnectionFactory(options, connectionFactory);\n\t\t}\n\n\t}\n\n\tstatic final class PoolingAwareOptionsCapableWrapper extends OptionsCapableWrapper {\n\n\t\tprivate final PoolingConnectionFactoryProvider poolingProvider = new PoolingConnectionFactoryProvider();\n\n\t\t@Override\n\t\tConnectionFactory buildAndWrap(ConnectionFactoryOptions options) {\n\t\t\tif (!this.poolingProvider.supports(options)) {\n\t\t\t\treturn super.buildAndWrap(options);\n\t\t\t}\n\t\t\tConnectionFactoryOptions delegateOptions = delegateFactoryOptions(options);\n\t\t\tConnectionFactory connectionFactory = super.buildAndWrap(delegateOptions);\n\t\t\tConnectionPoolConfiguration poolConfiguration = connectionPoolConfiguration(delegateOptions,\n\t\t\t\t\tconnectionFactory);\n\t\t\treturn new ConnectionPool(poolConfiguration);\n\t\t}\n\n\t\tprivate ConnectionFactoryOptions delegateFactoryOptions(ConnectionFactoryOptions options) {\n\t\t\tString protocol = toString(options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL));\n\t\t\tif (protocol.trim().isEmpty()) {\n\t\t\t\tthrow new IllegalArgumentException(String.format(\"Protocol %s is not valid.\", protocol));\n\t\t\t}\n\t\t\tString[] protocols = protocol.split(COLON, 2);\n\t\t\tString driverDelegate = protocols[0];\n\t\t\tString protocolDelegate = (protocols.length != 2) ? \"\" : protocols[1];\n\t\t\treturn ConnectionFactoryOptions.builder()\n\t\t\t\t.from(options)\n\t\t\t\t.option(ConnectionFactoryOptions.DRIVER, driverDelegate)\n\t\t\t\t.option(ConnectionFactoryOptions.PROTOCOL, protocolDelegate)\n\t\t\t\t.build();\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tConnectionPoolConfiguration connectionPoolConfiguration(ConnectionFactoryOptions options,\n\t\t\t\tConnectionFactory connectionFactory) {\n\t\t\tConnectionPoolConfiguration.Builder builder = ConnectionPoolConfiguration.builder(connectionFactory);\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.BACKGROUND_EVICTION_INTERVAL))\n\t\t\t\t.as(this::toDuration)\n\t\t\t\t.to(builder::backgroundEvictionInterval);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.INITIAL_SIZE))\n\t\t\t\t.as(this::toInteger)\n\t\t\t\t.to(builder::initialSize);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MAX_SIZE))\n\t\t\t\t.as(this::toInteger)\n\t\t\t\t.to(builder::maxSize);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.ACQUIRE_RETRY))\n\t\t\t\t.as(this::toInteger)\n\t\t\t\t.to(builder::acquireRetry);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MAX_LIFE_TIME))\n\t\t\t\t.as(this::toDuration)\n\t\t\t\t.to(builder::maxLifeTime);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MAX_ACQUIRE_TIME))\n\t\t\t\t.as(this::toDuration)\n\t\t\t\t.to(builder::maxAcquireTime);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MAX_IDLE_TIME))\n\t\t\t\t.as(this::toDuration)\n\t\t\t\t.to(builder::maxIdleTime);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MAX_CREATE_CONNECTION_TIME))\n\t\t\t\t.as(this::toDuration)\n\t\t\t\t.to(builder::maxCreateConnectionTime);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MAX_VALIDATION_TIME))\n\t\t\t\t.as(this::toDuration)\n\t\t\t\t.to(builder::maxValidationTime);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.MIN_IDLE))\n\t\t\t\t.as(this::toInteger)\n\t\t\t\t.to(builder::minIdle);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.POOL_NAME)).as(this::toString).to(builder::name);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.PRE_RELEASE))\n\t\t\t\t.to((function) -> builder\n\t\t\t\t\t.preRelease((Function<? super Connection, ? extends Publisher<Void>>) function));\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.POST_ALLOCATE))\n\t\t\t\t.to((function) -> builder\n\t\t\t\t\t.postAllocate((Function<? super Connection, ? extends Publisher<Void>>) function));\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.REGISTER_JMX))\n\t\t\t\t.as(this::toBoolean)\n\t\t\t\t.to(builder::registerJmx);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.VALIDATION_QUERY))\n\t\t\t\t.as(this::toString)\n\t\t\t\t.to(builder::validationQuery);\n\t\t\tmap.from(options.getValue(PoolingConnectionFactoryProvider.VALIDATION_DEPTH))\n\t\t\t\t.as(this::toValidationDepth)\n\t\t\t\t.to(builder::validationDepth);\n\t\t\treturn builder.build();\n\t\t}\n\n\t\tprivate String toString(Object object) {\n\t\t\treturn toType(String.class, object, String::valueOf);\n\t\t}\n\n\t\tprivate Integer toInteger(Object object) {\n\t\t\treturn toType(Integer.class, object, Integer::valueOf);\n\t\t}\n\n\t\tprivate Duration toDuration(Object object) {\n\t\t\treturn toType(Duration.class, object, Duration::parse);\n\t\t}\n\n\t\tprivate Boolean toBoolean(Object object) {\n\t\t\treturn toType(Boolean.class, object, Boolean::valueOf);\n\t\t}\n\n\t\tprivate ValidationDepth toValidationDepth(Object object) {\n\t\t\treturn toType(ValidationDepth.class, object,\n\t\t\t\t\t(string) -> ValidationDepth.valueOf(string.toUpperCase(Locale.ENGLISH)));\n\t\t}\n\n\t\tprivate <T> T toType(Class<T> type, Object object, Function<String, T> converter) {\n\t\t\tif (type.isInstance(object)) {\n\t\t\t\treturn type.cast(object);\n\t\t\t}\n\t\t\tif (object instanceof String string) {\n\t\t\t\treturn converter.apply(string);\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"Cannot convert '\" + object + \"' to \" + type.getName());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/ConnectionFactoryDecorator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\n/**\n * Decorator for {@link ConnectionFactory connection factories}.\n *\n * @author Moritz Halbritter\n * @since 3.2.0\n * @see ConnectionFactoryBuilder\n */\n@FunctionalInterface\npublic interface ConnectionFactoryDecorator {\n\n\t/**\n\t * Decorates the given {@link ConnectionFactory}.\n\t * @param delegate the connection factory which should be decorated\n\t * @return the decorated connection factory\n\t */\n\tConnectionFactory decorate(ConnectionFactory delegate);\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/EmbeddedDatabaseConnection.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport java.util.function.Predicate;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Connection details for embedded databases compatible with R2DBC.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @since 2.5.0\n */\npublic enum EmbeddedDatabaseConnection {\n\n\t/**\n\t * No Connection.\n\t */\n\tNONE(null, null, (options) -> false),\n\n\t/**\n\t * H2 Database Connection.\n\t */\n\tH2(\"io.r2dbc.h2.H2ConnectionFactoryProvider\", \"r2dbc:h2:mem:///%s?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\",\n\t\t\t(options) -> \"h2\".equals(options.getValue(ConnectionFactoryOptions.DRIVER))\n\t\t\t\t\t&& \"mem\".equals(options.getValue(ConnectionFactoryOptions.PROTOCOL)));\n\n\tprivate final @Nullable String driverClassName;\n\n\tprivate final @Nullable String url;\n\n\tprivate final Predicate<ConnectionFactoryOptions> embedded;\n\n\tEmbeddedDatabaseConnection(@Nullable String driverClassName, @Nullable String url,\n\t\t\tPredicate<ConnectionFactoryOptions> embedded) {\n\t\tthis.driverClassName = driverClassName;\n\t\tthis.url = url;\n\t\tthis.embedded = embedded;\n\t}\n\n\t/**\n\t * Returns the driver class name.\n\t * @return the driver class name\n\t */\n\tpublic @Nullable String getDriverClassName() {\n\t\treturn this.driverClassName;\n\t}\n\n\t/**\n\t * Returns the R2DBC URL for the connection using the specified {@code databaseName}.\n\t * @param databaseName the name of the database\n\t * @return the connection URL\n\t */\n\tpublic @Nullable String getUrl(String databaseName) {\n\t\tAssert.hasText(databaseName, \"'databaseName' must not be empty\");\n\t\treturn (this.url != null) ? String.format(this.url, databaseName) : null;\n\t}\n\n\t/**\n\t * Returns the most suitable {@link EmbeddedDatabaseConnection} for the given class\n\t * loader.\n\t * @param classLoader the class loader used to check for classes\n\t * @return an {@link EmbeddedDatabaseConnection} or {@link #NONE}.\n\t */\n\tpublic static EmbeddedDatabaseConnection get(@Nullable ClassLoader classLoader) {\n\t\tfor (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) {\n\t\t\tString driverClassName = candidate.getDriverClassName();\n\t\t\tif (candidate != NONE && driverClassName != null && ClassUtils.isPresent(driverClassName, classLoader)) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t\treturn NONE;\n\t}\n\n\t/**\n\t * Convenience method to determine if a given connection factory represents an\n\t * embedded database type.\n\t * @param connectionFactory the connection factory to interrogate\n\t * @return true if the connection factory represents an embedded database\n\t * @since 2.5.1\n\t */\n\tpublic static boolean isEmbedded(ConnectionFactory connectionFactory) {\n\t\tOptionsCapableConnectionFactory optionsCapable = OptionsCapableConnectionFactory.unwrapFrom(connectionFactory);\n\t\tAssert.state(optionsCapable != null,\n\t\t\t\t() -> \"Cannot determine database's type as ConnectionFactory is not options-capable. To be \"\n\t\t\t\t\t\t+ \"options-capable, a ConnectionFactory should be created with \"\n\t\t\t\t\t\t+ ConnectionFactoryBuilder.class.getName());\n\t\tConnectionFactoryOptions options = optionsCapable.getOptions();\n\t\tfor (EmbeddedDatabaseConnection candidate : values()) {\n\t\t\tif (candidate.embedded.test(options)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/OptionsCapableConnectionFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryMetadata;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Wrapped;\nimport org.jspecify.annotations.Nullable;\nimport org.reactivestreams.Publisher;\n\n/**\n * {@link ConnectionFactory} capable of providing access to the\n * {@link ConnectionFactoryOptions} from which it was built.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic class OptionsCapableConnectionFactory implements Wrapped<ConnectionFactory>, ConnectionFactory {\n\n\tprivate final ConnectionFactoryOptions options;\n\n\tprivate final ConnectionFactory delegate;\n\n\t/**\n\t * Create a new {@code OptionsCapableConnectionFactory} that will provide access to\n\t * the given {@code options} that were used to build the given {@code delegate}\n\t * {@link ConnectionFactory}.\n\t * @param options the options from which the connection factory was built\n\t * @param delegate the delegate connection factory that was built with options\n\t */\n\tpublic OptionsCapableConnectionFactory(ConnectionFactoryOptions options, ConnectionFactory delegate) {\n\t\tthis.options = options;\n\t\tthis.delegate = delegate;\n\t}\n\n\tpublic ConnectionFactoryOptions getOptions() {\n\t\treturn this.options;\n\t}\n\n\t@Override\n\tpublic Publisher<? extends Connection> create() {\n\t\treturn this.delegate.create();\n\t}\n\n\t@Override\n\tpublic ConnectionFactoryMetadata getMetadata() {\n\t\treturn this.delegate.getMetadata();\n\t}\n\n\t@Override\n\tpublic ConnectionFactory unwrap() {\n\t\treturn this.delegate;\n\t}\n\n\t/**\n\t * Returns, if possible, an {@code OptionsCapableConnectionFactory} by unwrapping the\n\t * given {@code connectionFactory} as necessary. If the given\n\t * {@code connectionFactory} does not wrap an {@code OptionsCapableConnectionFactory}\n\t * and is not itself an {@code OptionsCapableConnectionFactory}, {@code null} is\n\t * returned.\n\t * @param connectionFactory the connection factory to unwrap\n\t * @return the {@code OptionsCapableConnectionFactory} or {@code null}\n\t * @since 2.5.1\n\t */\n\tpublic static @Nullable OptionsCapableConnectionFactory unwrapFrom(ConnectionFactory connectionFactory) {\n\t\tif (connectionFactory instanceof OptionsCapableConnectionFactory optionsCapableConnectionFactory) {\n\t\t\treturn optionsCapableConnectionFactory;\n\t\t}\n\t\tif (connectionFactory instanceof Wrapped<?> wrappedConnectionFactory) {\n\t\t\tObject unwrapped = wrappedConnectionFactory.unwrap();\n\t\t\tif (unwrapped instanceof ConnectionFactory unwrappedConnectionFactory) {\n\t\t\t\treturn unwrapFrom(unwrappedConnectionFactory);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ApplicationR2dbcScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.ApplicationScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.SqlInitializationProperties;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\n\n/**\n * {@link R2dbcScriptDatabaseInitializer} for the primary SQL database. May be registered\n * as a bean to override auto-configuration.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ApplicationR2dbcScriptDatabaseInitializer extends R2dbcScriptDatabaseInitializer\n\t\timplements ApplicationScriptDatabaseInitializer {\n\n\t/**\n\t * Create a new {@code ApplicationR2dbcScriptDatabaseInitializer} instance.\n\t * @param connectionFactory the primary SQL connection factory\n\t * @param properties the SQL initialization properties\n\t */\n\tpublic ApplicationR2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,\n\t\t\tSqlInitializationProperties properties) {\n\t\tsuper(connectionFactory, ApplicationScriptDatabaseInitializer.getSettings(properties));\n\t}\n\n\t/**\n\t * Create a new {@code ApplicationR2dbcScriptDatabaseInitializer} instance.\n\t * @param connectionFactory the primary SQL connection factory\n\t * @param settings the database initialization settings\n\t */\n\tpublic ApplicationR2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,\n\t\t\tDatabaseInitializationSettings settings) {\n\t\tsuper(connectionFactory, settings);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ConnectionFactoryBeanCreationFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryOptionsInitializer.ConnectionFactoryBeanCreationException;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link AbstractFailureAnalyzer} for failures caused by a\n * {@link ConnectionFactoryBeanCreationException}.\n *\n * @author Mark Paluch\n */\nclass ConnectionFactoryBeanCreationFailureAnalyzer\n\t\textends AbstractFailureAnalyzer<ConnectionFactoryBeanCreationException> {\n\n\tprivate final Environment environment;\n\n\tConnectionFactoryBeanCreationFailureAnalyzer(Environment environment) {\n\t\tthis.environment = environment;\n\t}\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, ConnectionFactoryBeanCreationException cause) {\n\t\treturn getFailureAnalysis(cause);\n\t}\n\n\tprivate FailureAnalysis getFailureAnalysis(ConnectionFactoryBeanCreationException cause) {\n\t\tString description = getDescription(cause);\n\t\tString action = getAction(cause);\n\t\treturn new FailureAnalysis(description, action, cause);\n\t}\n\n\tprivate String getDescription(ConnectionFactoryBeanCreationException cause) {\n\t\tStringBuilder description = new StringBuilder();\n\t\tdescription.append(\"Failed to configure a ConnectionFactory: \");\n\t\tif (!StringUtils.hasText(cause.getUrl())) {\n\t\t\tdescription.append(\"'url' attribute is not specified and \");\n\t\t}\n\t\tdescription.append(String.format(\"no embedded database could be configured.%n\"));\n\t\tdescription.append(String.format(\"%nReason: %s%n\", cause.getMessage()));\n\t\treturn description.toString();\n\t}\n\n\tprivate String getAction(ConnectionFactoryBeanCreationException cause) {\n\t\tStringBuilder action = new StringBuilder();\n\t\taction.append(String.format(\"Consider the following:%n\"));\n\t\tif (EmbeddedDatabaseConnection.NONE == cause.getEmbeddedDatabaseConnection()) {\n\t\t\taction.append(String.format(\"\\tIf you want an embedded database (H2), please put it on the classpath.%n\"));\n\t\t}\n\t\telse {\n\t\t\taction.append(String.format(\"\\tReview the configuration of %s%n.\", cause.getEmbeddedDatabaseConnection()));\n\t\t}\n\t\taction\n\t\t\t.append(\"\\tIf you have database settings to be loaded from a particular \"\n\t\t\t\t\t+ \"profile you may need to activate it\")\n\t\t\t.append(getActiveProfiles());\n\t\treturn action.toString();\n\t}\n\n\tprivate String getActiveProfiles() {\n\t\tStringBuilder message = new StringBuilder();\n\t\tString[] profiles = this.environment.getActiveProfiles();\n\t\tif (ObjectUtils.isEmpty(profiles)) {\n\t\t\tmessage.append(\" (no profiles are currently active).\");\n\t\t}\n\t\telse {\n\t\t\tmessage.append(\" (the profiles \");\n\t\t\tmessage.append(StringUtils.arrayToCommaDelimitedString(profiles));\n\t\t\tmessage.append(\" are currently active).\");\n\t\t}\n\t\treturn message.toString();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ConnectionFactoryConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.util.List;\n\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.ConnectionPoolConfiguration;\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.bind.BindResult;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.r2dbc.ConnectionFactoryDecorator;\nimport org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcProperties.Pool;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Actual {@link ConnectionFactory} configurations.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Rodolpho S. Couto\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nabstract class ConnectionFactoryConfigurations {\n\n\tprotected static ConnectionFactory createConnectionFactory(R2dbcProperties properties,\n\t\t\t@Nullable R2dbcConnectionDetails connectionDetails, @Nullable ClassLoader classLoader,\n\t\t\tList<ConnectionFactoryOptionsBuilderCustomizer> optionsCustomizers,\n\t\t\tList<ConnectionFactoryDecorator> decorators) {\n\t\ttry {\n\t\t\treturn org.springframework.boot.r2dbc.ConnectionFactoryBuilder\n\t\t\t\t.withOptions(new ConnectionFactoryOptionsInitializer().initialize(properties, connectionDetails,\n\t\t\t\t\t\t() -> EmbeddedDatabaseConnection.get(classLoader)))\n\t\t\t\t.configure((options) -> {\n\t\t\t\t\tfor (ConnectionFactoryOptionsBuilderCustomizer optionsCustomizer : optionsCustomizers) {\n\t\t\t\t\t\toptionsCustomizer.customize(options);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.decorators(decorators)\n\t\t\t\t.build();\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\tString message = ex.getMessage();\n\t\t\tif (message != null && message.contains(\"driver=pool\")\n\t\t\t\t\t&& !ClassUtils.isPresent(\"io.r2dbc.pool.ConnectionPool\", classLoader)) {\n\t\t\t\tthrow new MissingR2dbcPoolDependencyException();\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(PooledConnectionFactoryCondition.class)\n\t@ConditionalOnMissingBean(ConnectionFactory.class)\n\tstatic class PoolConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(ConnectionPool.class)\n\t\tstatic class PooledConnectionFactoryConfiguration {\n\n\t\t\t@Bean(destroyMethod = \"dispose\")\n\t\t\tConnectionPool connectionFactory(R2dbcProperties properties,\n\t\t\t\t\tObjectProvider<R2dbcConnectionDetails> connectionDetails, ResourceLoader resourceLoader,\n\t\t\t\t\tObjectProvider<ConnectionFactoryOptionsBuilderCustomizer> customizers,\n\t\t\t\t\tObjectProvider<ConnectionFactoryDecorator> decorators) {\n\t\t\t\tConnectionFactory connectionFactory = createConnectionFactory(properties,\n\t\t\t\t\t\tconnectionDetails.getIfAvailable(), resourceLoader.getClassLoader(),\n\t\t\t\t\t\tcustomizers.orderedStream().toList(), decorators.orderedStream().toList());\n\t\t\t\tR2dbcProperties.Pool pool = properties.getPool();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tConnectionPoolConfiguration.Builder builder = ConnectionPoolConfiguration.builder(connectionFactory);\n\t\t\t\tmap.from(pool.getMaxIdleTime()).to(builder::maxIdleTime);\n\t\t\t\tmap.from(pool.getMaxLifeTime()).to(builder::maxLifeTime);\n\t\t\t\tmap.from(pool.getMaxAcquireTime()).to(builder::maxAcquireTime);\n\t\t\t\tmap.from(pool.getAcquireRetry()).to(builder::acquireRetry);\n\t\t\t\tmap.from(pool.getMaxCreateConnectionTime()).to(builder::maxCreateConnectionTime);\n\t\t\t\tmap.from(pool.getInitialSize()).to(builder::initialSize);\n\t\t\t\tmap.from(pool.getMaxSize()).to(builder::maxSize);\n\t\t\t\tmap.from(pool.getValidationQuery()).whenHasText().to(builder::validationQuery);\n\t\t\t\tmap.from(pool.getValidationDepth()).to(builder::validationDepth);\n\t\t\t\tmap.from(pool.getMinIdle()).to(builder::minIdle);\n\t\t\t\tmap.from(pool.getMaxValidationTime()).to(builder::maxValidationTime);\n\t\t\t\treturn new ConnectionPool(builder.build());\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.r2dbc.pool.enabled\", havingValue = false, matchIfMissing = true)\n\t@ConditionalOnMissingBean(ConnectionFactory.class)\n\tstatic class GenericConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactory(R2dbcProperties properties,\n\t\t\t\tObjectProvider<R2dbcConnectionDetails> connectionDetails, ResourceLoader resourceLoader,\n\t\t\t\tObjectProvider<ConnectionFactoryOptionsBuilderCustomizer> customizers,\n\t\t\t\tObjectProvider<ConnectionFactoryDecorator> decorators) {\n\t\t\treturn createConnectionFactory(properties, connectionDetails.getIfAvailable(),\n\t\t\t\t\tresourceLoader.getClassLoader(), customizers.orderedStream().toList(),\n\t\t\t\t\tdecorators.orderedStream().toList());\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Condition} that checks that a {@link ConnectionPool} is requested. The\n\t * condition matches if pooling was opt-in through configuration. If any of the\n\t * spring.r2dbc.pool.* properties have been configured, an exception is thrown if the\n\t * URL also contains pooling-related options or io.r2dbc.pool.ConnectionPool is not on\n\t * the class path.\n\t */\n\tstatic class PooledConnectionFactoryCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tBindResult<Pool> pool = Binder.get(context.getEnvironment())\n\t\t\t\t.bind(\"spring.r2dbc.pool\", Bindable.of(Pool.class));\n\t\t\tif (hasPoolUrl(context.getEnvironment())) {\n\t\t\t\tif (pool.isBound()) {\n\t\t\t\t\tthrow new MultipleConnectionPoolConfigurationsException();\n\t\t\t\t}\n\t\t\t\treturn ConditionOutcome.noMatch(\"URL-based pooling has been configured\");\n\t\t\t}\n\t\t\tif (pool.isBound() && !ClassUtils.isPresent(\"io.r2dbc.pool.ConnectionPool\", context.getClassLoader())) {\n\t\t\t\tthrow new MissingR2dbcPoolDependencyException();\n\t\t\t}\n\t\t\tif (pool.orElseGet(Pool::new).isEnabled()) {\n\t\t\t\treturn ConditionOutcome.match(\"Property-based pooling is enabled\");\n\t\t\t}\n\t\t\treturn ConditionOutcome.noMatch(\"Property-based pooling is disabled\");\n\t\t}\n\n\t\tprivate boolean hasPoolUrl(Environment environment) {\n\t\t\tString url = environment.getProperty(\"spring.r2dbc.url\");\n\t\t\treturn StringUtils.hasText(url) && url.contains(\":pool:\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ConnectionFactoryDependentConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\n/**\n * Configuration of the R2DBC infrastructure based on a {@link ConnectionFactory}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(DatabaseClient.class)\n@ConditionalOnSingleCandidate(ConnectionFactory.class)\nclass ConnectionFactoryDependentConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDatabaseClient r2dbcDatabaseClient(ConnectionFactory connectionFactory) {\n\t\treturn DatabaseClient.builder().connectionFactory(connectionFactory).build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ConnectionFactoryOptionsBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.ConnectionFactoryOptions.Builder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Builder} to fine-tune its auto-configuration before it creates a\n * {@link ConnectionFactoryOptions}.\n *\n * @author Mark Paluch\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ConnectionFactoryOptionsBuilderCustomizer {\n\n\t/**\n\t * Customize the {@link Builder}.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ConnectionFactoryOptionsInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.util.function.Supplier;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.ConnectionFactoryOptions.Builder;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;\nimport org.springframework.util.StringUtils;\n\n/**\n * Initialize a {@link Builder} based on {@link R2dbcProperties}.\n *\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConnectionFactoryOptionsInitializer {\n\n\t/**\n\t * Initialize a {@link Builder ConnectionFactoryOptions.Builder} using the specified\n\t * properties.\n\t * @param properties the properties to use to initialize the builder\n\t * @param connectionDetails the connection details to use to initialize the builder\n\t * @param embeddedDatabaseConnection the embedded connection to use as a fallback\n\t * @return an initialized builder\n\t * @throws ConnectionFactoryBeanCreationException if no suitable connection could be\n\t * determined\n\t */\n\tConnectionFactoryOptions.Builder initialize(R2dbcProperties properties,\n\t\t\t@Nullable R2dbcConnectionDetails connectionDetails,\n\t\t\tSupplier<EmbeddedDatabaseConnection> embeddedDatabaseConnection) {\n\t\tif (connectionDetails != null) {\n\t\t\treturn connectionDetails.getConnectionFactoryOptions().mutate();\n\t\t}\n\t\tEmbeddedDatabaseConnection embeddedConnection = embeddedDatabaseConnection.get();\n\t\tif (embeddedConnection != EmbeddedDatabaseConnection.NONE) {\n\t\t\treturn initializeEmbeddedOptions(properties, embeddedConnection);\n\t\t}\n\t\tthrow connectionFactoryBeanCreationException(\"Failed to determine a suitable R2DBC Connection URL\", null,\n\t\t\t\tembeddedConnection);\n\t}\n\n\tprivate Builder initializeEmbeddedOptions(R2dbcProperties properties,\n\t\t\tEmbeddedDatabaseConnection embeddedDatabaseConnection) {\n\t\tString url = embeddedDatabaseConnection.getUrl(determineEmbeddedDatabaseName(properties));\n\t\tif (url == null) {\n\t\t\tthrow connectionFactoryBeanCreationException(\"Failed to determine a suitable R2DBC Connection URL\", url,\n\t\t\t\t\tembeddedDatabaseConnection);\n\t\t}\n\t\tBuilder builder = ConnectionFactoryOptions.parse(url).mutate();\n\t\tString username = determineEmbeddedUsername(properties);\n\t\tif (StringUtils.hasText(username)) {\n\t\t\tbuilder.option(ConnectionFactoryOptions.USER, username);\n\t\t}\n\t\tif (StringUtils.hasText(properties.getPassword())) {\n\t\t\tbuilder.option(ConnectionFactoryOptions.PASSWORD, properties.getPassword());\n\t\t}\n\t\treturn builder;\n\t}\n\n\tprivate String determineEmbeddedDatabaseName(R2dbcProperties properties) {\n\t\tString databaseName = determineDatabaseName(properties);\n\t\treturn (databaseName != null) ? databaseName : \"testdb\";\n\t}\n\n\tprivate @Nullable String determineDatabaseName(R2dbcProperties properties) {\n\t\tif (properties.isGenerateUniqueName()) {\n\t\t\treturn properties.determineUniqueName();\n\t\t}\n\t\tif (StringUtils.hasLength(properties.getName())) {\n\t\t\treturn properties.getName();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate String determineEmbeddedUsername(R2dbcProperties properties) {\n\t\tString username = ifHasText(properties.getUsername());\n\t\treturn (username != null) ? username : \"sa\";\n\t}\n\n\tprivate ConnectionFactoryBeanCreationException connectionFactoryBeanCreationException(String message,\n\t\t\t@Nullable String r2dbcUrl, EmbeddedDatabaseConnection embeddedDatabaseConnection) {\n\t\treturn new ConnectionFactoryBeanCreationException(message, r2dbcUrl, embeddedDatabaseConnection);\n\t}\n\n\tprivate @Nullable String ifHasText(@Nullable String candidate) {\n\t\treturn (StringUtils.hasText(candidate)) ? candidate : null;\n\t}\n\n\tstatic class ConnectionFactoryBeanCreationException extends BeanCreationException {\n\n\t\tprivate final @Nullable String url;\n\n\t\tprivate final EmbeddedDatabaseConnection embeddedDatabaseConnection;\n\n\t\tConnectionFactoryBeanCreationException(String message, @Nullable String url,\n\t\t\t\tEmbeddedDatabaseConnection embeddedDatabaseConnection) {\n\t\t\tsuper(message);\n\t\t\tthis.url = url;\n\t\t\tthis.embeddedDatabaseConnection = embeddedDatabaseConnection;\n\t\t}\n\n\t\t@Nullable String getUrl() {\n\t\t\treturn this.url;\n\t\t}\n\n\t\tEmbeddedDatabaseConnection getEmbeddedDatabaseConnection() {\n\t\t\treturn this.embeddedDatabaseConnection;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/MissingR2dbcPoolDependencyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\n/**\n * Exception thrown when R2DBC connection pooling has been configured but the\n * {@code io.r2dbc:r2dbc-pool} dependency is missing.\n *\n * @author Andy Wilkinson\n */\nclass MissingR2dbcPoolDependencyException extends RuntimeException {\n\n\tMissingR2dbcPoolDependencyException() {\n\t\tsuper(\"R2DBC connection pooling has been configured but the io.r2dbc.pool.ConnectionPool class is not \"\n\t\t\t\t+ \"present.\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/MissingR2dbcPoolDependencyFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\n\n/**\n * {@link FailureAnalyzer} for {@link MissingR2dbcPoolDependencyException}.\n *\n * @author Andy Wilkinson\n */\nclass MissingR2dbcPoolDependencyFailureAnalyzer extends AbstractFailureAnalyzer<MissingR2dbcPoolDependencyException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, MissingR2dbcPoolDependencyException cause) {\n\t\treturn new FailureAnalysis(cause.getMessage(),\n\t\t\t\t\"Update your application's build to depend on io.r2dbc:r2dbc-pool or your application's configuration \"\n\t\t\t\t\t\t+ \"to disable R2DBC connection pooling.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/MultipleConnectionPoolConfigurationsException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\n/**\n * Exception thrown when R2DBC connection pooling has been configured both by the URL\n * ({@code spring.r2dbc.url}) and the pool properties ({@code spring.r2dbc.pool.*}.\n *\n * @author Andy Wilkinson\n */\nclass MultipleConnectionPoolConfigurationsException extends RuntimeException {\n\n\tMultipleConnectionPoolConfigurationsException() {\n\t\tsuper(\"R2DBC connection pooling configuration should be provided by either the spring.r2dbc.pool.* \"\n\t\t\t\t+ \"properties or the spring.r2dbc.url property but both have been used.\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/MultipleConnectionPoolConfigurationsFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\n\n/**\n * {@link FailureAnalyzer} for {@link MultipleConnectionPoolConfigurationsException}.\n *\n * @author Andy Wilkinson\n */\nclass MultipleConnectionPoolConfigurationsFailureAnalyzer\n\t\textends AbstractFailureAnalyzer<MultipleConnectionPoolConfigurationsException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, MultipleConnectionPoolConfigurationsException cause) {\n\t\treturn new FailureAnalysis(cause.getMessage(),\n\t\t\t\t\"Update your configuration so that R2DBC connection pooling is configured using either the \"\n\t\t\t\t\t\t+ \"spring.r2dbc.url property or the spring.r2dbc.pool.* properties\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/NoConnectionFactoryBeanFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.core.Ordered;\n\n/**\n * An {@link AbstractFailureAnalyzer} that produces failure analysis when a\n * {@link NoSuchBeanDefinitionException} for a {@link ConnectionFactory} bean is thrown\n * and there is no {@code META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider}\n * resource on the classpath.\n *\n * @author Andy Wilkinson\n */\nclass NoConnectionFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchBeanDefinitionException>\n\t\timplements Ordered {\n\n\tprivate final ClassLoader classLoader;\n\n\tNoConnectionFactoryBeanFailureAnalyzer() {\n\t\tthis(NoConnectionFactoryBeanFailureAnalyzer.class.getClassLoader());\n\t}\n\n\tNoConnectionFactoryBeanFailureAnalyzer(ClassLoader classLoader) {\n\t\tthis.classLoader = classLoader;\n\t}\n\n\t@Override\n\tprotected @Nullable FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionException cause) {\n\t\tif (ConnectionFactory.class.equals(cause.getBeanType())\n\t\t\t\t&& this.classLoader.getResource(\"META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider\") == null) {\n\t\t\treturn new FailureAnalysis(\"No R2DBC ConnectionFactory bean is available \"\n\t\t\t\t\t+ \"and no /META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider resource could be found.\",\n\t\t\t\t\t\"Check that the R2DBC driver for your database is on the classpath.\", cause);\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/ProxyConnectionFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.proxy.ProxyConnectionFactory.Builder;\n\n/**\n * Callback interface that can be used to customize a {@link Builder}.\n *\n * @author Tadaya Tsuyukubo\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ProxyConnectionFactoryCustomizer {\n\n\t/**\n\t * Callback to customize a {@link Builder} instance.\n\t * @param builder the builder to customize\n\t */\n\tvoid customize(Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.util.function.Supplier;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.ConnectionFactoryOptions.Builder;\nimport io.r2dbc.spi.Option;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnResource;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for R2DBC.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(before = { R2dbcInitializationAutoConfiguration.class },\n\t\tbeforeName = \"org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration\")\n@ConditionalOnClass(ConnectionFactory.class)\n@ConditionalOnResource(resources = \"classpath:META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider\")\n@EnableConfigurationProperties(R2dbcProperties.class)\n@Import({ ConnectionFactoryConfigurations.PoolConfiguration.class,\n\t\tConnectionFactoryConfigurations.GenericConfiguration.class, ConnectionFactoryDependentConfiguration.class })\npublic final class R2dbcAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(R2dbcConnectionDetails.class)\n\t@ConditionalOnProperty(\"spring.r2dbc.url\")\n\tPropertiesR2dbcConnectionDetails propertiesR2dbcConnectionDetails(R2dbcProperties properties) {\n\t\treturn new PropertiesR2dbcConnectionDetails(properties);\n\t}\n\n\t/**\n\t * Adapts {@link R2dbcProperties} to {@link R2dbcConnectionDetails}.\n\t */\n\tstatic class PropertiesR2dbcConnectionDetails implements R2dbcConnectionDetails {\n\n\t\tprivate final R2dbcProperties properties;\n\n\t\tPropertiesR2dbcConnectionDetails(R2dbcProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\tString url = this.properties.getUrl();\n\t\t\tAssert.state(url != null, \"'url' must not be null\");\n\t\t\tConnectionFactoryOptions urlOptions = ConnectionFactoryOptions.parse(url);\n\t\t\tBuilder optionsBuilder = urlOptions.mutate();\n\t\t\tconfigureUser(optionsBuilder, urlOptions);\n\t\t\tconfigurePassword(optionsBuilder, urlOptions);\n\t\t\tconfigureDatabase(optionsBuilder, urlOptions);\n\t\t\tthis.properties.getProperties().forEach((key, value) -> optionsBuilder.option(Option.valueOf(key), value));\n\t\t\treturn optionsBuilder.build();\n\t\t}\n\n\t\tprivate void configureDatabase(Builder optionsBuilder, ConnectionFactoryOptions urlOptions) {\n\t\t\tSupplier<@Nullable String> getDatabaseName = () -> determineDatabaseName(this.properties);\n\t\t\tconfigureIf(optionsBuilder, urlOptions, ConnectionFactoryOptions.DATABASE, getDatabaseName);\n\t\t}\n\n\t\tprivate void configurePassword(Builder optionsBuilder, ConnectionFactoryOptions urlOptions) {\n\t\t\tSupplier<@Nullable CharSequence> getPassword = this.properties::getPassword;\n\t\t\tconfigureIf(optionsBuilder, urlOptions, ConnectionFactoryOptions.PASSWORD, getPassword);\n\t\t}\n\n\t\tprivate void configureUser(Builder optionsBuilder, ConnectionFactoryOptions urlOptions) {\n\t\t\tSupplier<@Nullable String> getUsername = this.properties::getUsername;\n\t\t\tconfigureIf(optionsBuilder, urlOptions, ConnectionFactoryOptions.USER, getUsername);\n\t\t}\n\n\t\tprivate <T extends CharSequence> void configureIf(Builder optionsBuilder,\n\t\t\t\tConnectionFactoryOptions originalOptions, Option<T> option, Supplier<@Nullable T> valueSupplier) {\n\t\t\tif (originalOptions.hasOption(option)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tT value = valueSupplier.get();\n\t\t\tif (StringUtils.hasText(value)) {\n\t\t\t\toptionsBuilder.option(option, value);\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable String determineDatabaseName(R2dbcProperties properties) {\n\t\t\tif (properties.isGenerateUniqueName()) {\n\t\t\t\treturn properties.determineUniqueName();\n\t\t\t}\n\t\t\tif (StringUtils.hasLength(properties.getName())) {\n\t\t\t\treturn properties.getName();\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to an SQL service using R2DBC.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface R2dbcConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * Connection factory options for connecting to the database.\n\t * @return the connection factory options\n\t */\n\tConnectionFactoryOptions getConnectionFactoryOptions();\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcInitializationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.r2dbc.ConnectionFactoryBuilder;\nimport org.springframework.boot.sql.autoconfigure.init.ConditionalOnSqlInitialization;\nimport org.springframework.boot.sql.autoconfigure.init.SqlInitializationProperties;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.r2dbc.connection.init.DatabasePopulator;\nimport org.springframework.util.StringUtils;\n\n/**\n * Auto-configuration for initializing an SQL database accessed through an R2DBC\n * {@link ConnectionFactory}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ConnectionFactory.class, DatabasePopulator.class })\n@ConditionalOnSingleCandidate(ConnectionFactory.class)\n@ConditionalOnMissingBean(value = ApplicationR2dbcScriptDatabaseInitializer.class,\n\t\ttype = \"org.springframework.boot.jdbc.autoconfigure.ApplicationDataSourceScriptDatabaseInitializer\")\n@ConditionalOnSqlInitialization\n@Import(DatabaseInitializationDependencyConfigurer.class)\n@EnableConfigurationProperties(SqlInitializationProperties.class)\npublic final class R2dbcInitializationAutoConfiguration {\n\n\t@Bean\n\tApplicationR2dbcScriptDatabaseInitializer r2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,\n\t\t\tSqlInitializationProperties properties) {\n\t\treturn new ApplicationR2dbcScriptDatabaseInitializer(\n\t\t\t\tdetermineConnectionFactory(connectionFactory, properties.getUsername(), properties.getPassword()),\n\t\t\t\tproperties);\n\t}\n\n\tprivate static ConnectionFactory determineConnectionFactory(ConnectionFactory connectionFactory,\n\t\t\t@Nullable String username, @Nullable String password) {\n\t\tif (StringUtils.hasText(username) && StringUtils.hasText(password)) {\n\t\t\treturn ConnectionFactoryBuilder.derivedFrom(connectionFactory)\n\t\t\t\t.username(username)\n\t\t\t\t.password(password)\n\t\t\t\t.build();\n\t\t}\n\t\treturn connectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport io.r2dbc.spi.ValidationDepth;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for R2DBC.\n *\n * @author Mark Paluch\n * @author Andreas Killaitis\n * @author Stephane Nicoll\n * @author Rodolpho S. Couto\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.r2dbc\")\npublic class R2dbcProperties {\n\n\t/**\n\t * Database name. Set if no name is specified in the url. Default to \"testdb\" when\n\t * using an embedded database.\n\t */\n\tprivate @Nullable String name;\n\n\t/**\n\t * Whether to generate a random database name. Ignore any configured name when\n\t * enabled.\n\t */\n\tprivate boolean generateUniqueName;\n\n\t/**\n\t * R2DBC URL of the database. database name, username, password and pooling options\n\t * specified in the url take precedence over individual options.\n\t */\n\tprivate @Nullable String url;\n\n\t/**\n\t * Login username of the database. Set if no username is specified in the url.\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Login password of the database. Set if no password is specified in the url.\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Additional R2DBC options.\n\t */\n\tprivate final Map<String, String> properties = new LinkedHashMap<>();\n\n\tprivate final Pool pool = new Pool();\n\n\tprivate @Nullable String uniqueName;\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic boolean isGenerateUniqueName() {\n\t\treturn this.generateUniqueName;\n\t}\n\n\tpublic void setGenerateUniqueName(boolean generateUniqueName) {\n\t\tthis.generateUniqueName = generateUniqueName;\n\t}\n\n\tpublic @Nullable String getUrl() {\n\t\treturn this.url;\n\t}\n\n\tpublic void setUrl(@Nullable String url) {\n\t\tthis.url = url;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic Map<String, String> getProperties() {\n\t\treturn this.properties;\n\t}\n\n\tpublic Pool getPool() {\n\t\treturn this.pool;\n\t}\n\n\t/**\n\t * Provide a unique name specific to this instance. Calling this method several times\n\t * return the same unique name.\n\t * @return a unique name for this instance\n\t */\n\tpublic String determineUniqueName() {\n\t\tif (this.uniqueName == null) {\n\t\t\tthis.uniqueName = UUID.randomUUID().toString();\n\t\t}\n\t\treturn this.uniqueName;\n\t}\n\n\tpublic static class Pool {\n\n\t\t/**\n\t\t * Minimal number of idle connections.\n\t\t */\n\t\tprivate int minIdle;\n\n\t\t/**\n\t\t * Maximum amount of time that a connection is allowed to sit idle in the pool.\n\t\t */\n\t\tprivate Duration maxIdleTime = Duration.ofMinutes(30);\n\n\t\t/**\n\t\t * Maximum lifetime of a connection in the pool. By default, connections have an\n\t\t * infinite lifetime.\n\t\t */\n\t\tprivate @Nullable Duration maxLifeTime;\n\n\t\t/**\n\t\t * Maximum time to acquire a connection from the pool. By default, wait\n\t\t * indefinitely.\n\t\t */\n\t\tprivate @Nullable Duration maxAcquireTime;\n\n\t\t/**\n\t\t * Number of acquire retries if the first acquire attempt fails.\n\t\t */\n\t\tprivate int acquireRetry = 1;\n\n\t\t/**\n\t\t * Maximum time to validate a connection from the pool. By default, wait\n\t\t * indefinitely.\n\t\t */\n\t\tprivate @Nullable Duration maxValidationTime;\n\n\t\t/**\n\t\t * Maximum time to wait to create a new connection. By default, wait indefinitely.\n\t\t */\n\t\tprivate @Nullable Duration maxCreateConnectionTime;\n\n\t\t/**\n\t\t * Initial connection pool size.\n\t\t */\n\t\tprivate int initialSize = 10;\n\n\t\t/**\n\t\t * Maximal connection pool size.\n\t\t */\n\t\tprivate int maxSize = 10;\n\n\t\t/**\n\t\t * Validation query.\n\t\t */\n\t\tprivate @Nullable String validationQuery;\n\n\t\t/**\n\t\t * Validation depth.\n\t\t */\n\t\tprivate ValidationDepth validationDepth = ValidationDepth.LOCAL;\n\n\t\t/**\n\t\t * Whether pooling is enabled. Requires r2dbc-pool.\n\t\t */\n\t\tprivate boolean enabled = true;\n\n\t\tpublic int getMinIdle() {\n\t\t\treturn this.minIdle;\n\t\t}\n\n\t\tpublic void setMinIdle(int minIdle) {\n\t\t\tthis.minIdle = minIdle;\n\t\t}\n\n\t\tpublic Duration getMaxIdleTime() {\n\t\t\treturn this.maxIdleTime;\n\t\t}\n\n\t\tpublic void setMaxIdleTime(Duration maxIdleTime) {\n\t\t\tthis.maxIdleTime = maxIdleTime;\n\t\t}\n\n\t\tpublic @Nullable Duration getMaxLifeTime() {\n\t\t\treturn this.maxLifeTime;\n\t\t}\n\n\t\tpublic void setMaxLifeTime(@Nullable Duration maxLifeTime) {\n\t\t\tthis.maxLifeTime = maxLifeTime;\n\t\t}\n\n\t\tpublic @Nullable Duration getMaxValidationTime() {\n\t\t\treturn this.maxValidationTime;\n\t\t}\n\n\t\tpublic void setMaxValidationTime(@Nullable Duration maxValidationTime) {\n\t\t\tthis.maxValidationTime = maxValidationTime;\n\t\t}\n\n\t\tpublic @Nullable Duration getMaxAcquireTime() {\n\t\t\treturn this.maxAcquireTime;\n\t\t}\n\n\t\tpublic void setMaxAcquireTime(@Nullable Duration maxAcquireTime) {\n\t\t\tthis.maxAcquireTime = maxAcquireTime;\n\t\t}\n\n\t\tpublic int getAcquireRetry() {\n\t\t\treturn this.acquireRetry;\n\t\t}\n\n\t\tpublic void setAcquireRetry(int acquireRetry) {\n\t\t\tthis.acquireRetry = acquireRetry;\n\t\t}\n\n\t\tpublic @Nullable Duration getMaxCreateConnectionTime() {\n\t\t\treturn this.maxCreateConnectionTime;\n\t\t}\n\n\t\tpublic void setMaxCreateConnectionTime(@Nullable Duration maxCreateConnectionTime) {\n\t\t\tthis.maxCreateConnectionTime = maxCreateConnectionTime;\n\t\t}\n\n\t\tpublic int getInitialSize() {\n\t\t\treturn this.initialSize;\n\t\t}\n\n\t\tpublic void setInitialSize(int initialSize) {\n\t\t\tthis.initialSize = initialSize;\n\t\t}\n\n\t\tpublic int getMaxSize() {\n\t\t\treturn this.maxSize;\n\t\t}\n\n\t\tpublic void setMaxSize(int maxSize) {\n\t\t\tthis.maxSize = maxSize;\n\t\t}\n\n\t\tpublic @Nullable String getValidationQuery() {\n\t\t\treturn this.validationQuery;\n\t\t}\n\n\t\tpublic void setValidationQuery(@Nullable String validationQuery) {\n\t\t\tthis.validationQuery = validationQuery;\n\t\t}\n\n\t\tpublic ValidationDepth getValidationDepth() {\n\t\t\treturn this.validationDepth;\n\t\t}\n\n\t\tpublic void setValidationDepth(ValidationDepth validationDepth) {\n\t\t\tthis.validationDepth = validationDepth;\n\t\t}\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcProxyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.proxy.ProxyConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.r2dbc.ConnectionFactoryDecorator;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link ProxyConnectionFactory}.\n *\n * @author Tadaya Tsuyukubo\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ConnectionFactory.class, ProxyConnectionFactory.class })\npublic final class R2dbcProxyAutoConfiguration {\n\n\t@Bean\n\tConnectionFactoryDecorator connectionFactoryDecorator(\n\t\t\tObjectProvider<ProxyConnectionFactoryCustomizer> customizers) {\n\t\treturn (connectionFactory) -> {\n\t\t\tProxyConnectionFactory.Builder builder = ProxyConnectionFactory.builder(connectionFactory);\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\t\treturn builder.build();\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcTransactionManagerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\nimport org.springframework.r2dbc.connection.R2dbcTransactionManager;\nimport org.springframework.transaction.ReactiveTransactionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link R2dbcTransactionManager}.\n *\n * @author Mark Paluch\n * @since 4.0.0\n */\n@AutoConfiguration(before = TransactionAutoConfiguration.class)\n@ConditionalOnClass({ R2dbcTransactionManager.class, ReactiveTransactionManager.class })\n@ConditionalOnSingleCandidate(ConnectionFactory.class)\n@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)\npublic final class R2dbcTransactionManagerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveTransactionManager.class)\n\tR2dbcTransactionManager connectionFactoryTransactionManager(ConnectionFactory connectionFactory) {\n\t\treturn new R2dbcTransactionManager(connectionFactory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/health/ConnectionFactoryHealthContributorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.health;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.health.autoconfigure.contributor.CompositeReactiveHealthContributorConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.ConditionalOnEnabledHealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthContributor;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.r2dbc.health.ConnectionFactoryHealthIndicator;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link ConnectionFactoryHealthIndicator}.\n *\n * @author Mark Paluch\n * @since 4.0.0\n */\n@AutoConfiguration(after = R2dbcAutoConfiguration.class)\n@ConditionalOnClass({ ConnectionFactory.class, ConditionalOnEnabledHealthIndicator.class })\n@ConditionalOnBean(ConnectionFactory.class)\n@ConditionalOnEnabledHealthIndicator(\"r2dbc\")\npublic final class ConnectionFactoryHealthContributorAutoConfiguration\n\t\textends CompositeReactiveHealthContributorConfiguration<ConnectionFactoryHealthIndicator, ConnectionFactory> {\n\n\tConnectionFactoryHealthContributorAutoConfiguration() {\n\t\tsuper(ConnectionFactoryHealthIndicator::new);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = { \"r2dbcHealthIndicator\", \"r2dbcHealthContributor\" })\n\tReactiveHealthContributor r2dbcHealthContributor(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn createContributor(beanFactory, ConnectionFactory.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for R2DBC health.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.autoconfigure.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/metrics/ConnectionPoolMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tags;\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.Wrapped;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.r2dbc.metrics.ConnectionPoolMetrics;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for metrics on all available\n * {@link ConnectionFactory R2DBC connection factories}.\n *\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = R2dbcAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnClass({ ConnectionPool.class, MeterRegistry.class })\n@ConditionalOnBean({ ConnectionFactory.class, MeterRegistry.class })\npublic final class ConnectionPoolMetricsAutoConfiguration {\n\n\t@Autowired\n\tvoid bindConnectionPoolsToRegistry(ConfigurableListableBeanFactory beanFactory, MeterRegistry registry) {\n\t\tSimpleAutowireCandidateResolver.resolveAutowireCandidates(beanFactory, ConnectionFactory.class)\n\t\t\t.forEach((beanName, connectionFactory) -> {\n\t\t\t\tConnectionPool pool = extractPool(connectionFactory);\n\t\t\t\tif (pool != null) {\n\t\t\t\t\tnew ConnectionPoolMetrics(pool, beanName, Tags.empty()).bindTo(registry);\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\tprivate @Nullable ConnectionPool extractPool(Object candidate) {\n\t\tif (candidate instanceof ConnectionPool connectionPool) {\n\t\t\treturn connectionPool;\n\t\t}\n\t\tif (candidate instanceof Wrapped) {\n\t\t\treturn extractPool(((Wrapped<?>) candidate).unwrap());\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for R2DBC metrics.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/observation/R2dbcObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.r2dbc.proxy.ProxyConnectionFactory;\nimport io.r2dbc.proxy.observation.ObservationProxyExecutionListener;\nimport io.r2dbc.proxy.observation.QueryObservationConvention;\nimport io.r2dbc.proxy.observation.QueryParametersTagProvider;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.r2dbc.OptionsCapableConnectionFactory;\nimport org.springframework.boot.r2dbc.autoconfigure.ProxyConnectionFactoryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for R2DBC observability support.\n *\n * @author Moritz Halbritter\n * @author Tadaya Tsuyukubo\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnClass({ ConnectionFactory.class, ProxyConnectionFactory.class, ObservationRegistry.class })\n@ConditionalOnBean(ObservationRegistry.class)\n@EnableConfigurationProperties(R2dbcObservationProperties.class)\npublic final class R2dbcObservationAutoConfiguration {\n\n\t/**\n\t * {@code @Order} value of the observation customizer.\n\t */\n\tpublic static final int R2DBC_PROXY_OBSERVATION_CUSTOMIZER_ORDER = 0;\n\n\t@Bean\n\t@Order(R2DBC_PROXY_OBSERVATION_CUSTOMIZER_ORDER)\n\t@ConditionalOnBean(ObservationRegistry.class)\n\tProxyConnectionFactoryCustomizer observationProxyConnectionFactoryCustomizer(R2dbcObservationProperties properties,\n\t\t\tObservationRegistry observationRegistry,\n\t\t\tObjectProvider<QueryObservationConvention> queryObservationConvention,\n\t\t\tObjectProvider<QueryParametersTagProvider> queryParametersTagProvider) {\n\t\treturn (builder) -> {\n\t\t\tConnectionFactory connectionFactory = builder.getConnectionFactory();\n\t\t\tHostAndPort hostAndPort = extractHostAndPort(connectionFactory);\n\t\t\tObservationProxyExecutionListener listener = new ObservationProxyExecutionListener(observationRegistry,\n\t\t\t\t\tconnectionFactory, hostAndPort.host(), hostAndPort.port());\n\t\t\tlistener.setIncludeParameterValues(properties.isIncludeParameterValues());\n\t\t\tqueryObservationConvention.ifAvailable(listener::setQueryObservationConvention);\n\t\t\tqueryParametersTagProvider.ifAvailable(listener::setQueryParametersTagProvider);\n\t\t\tbuilder.listener(listener);\n\t\t};\n\t}\n\n\tprivate HostAndPort extractHostAndPort(ConnectionFactory connectionFactory) {\n\t\tOptionsCapableConnectionFactory optionsCapableConnectionFactory = OptionsCapableConnectionFactory\n\t\t\t.unwrapFrom(connectionFactory);\n\t\tif (optionsCapableConnectionFactory == null) {\n\t\t\treturn HostAndPort.empty();\n\t\t}\n\t\tConnectionFactoryOptions options = optionsCapableConnectionFactory.getOptions();\n\t\tObject host = options.getValue(ConnectionFactoryOptions.HOST);\n\t\tObject port = options.getValue(ConnectionFactoryOptions.PORT);\n\t\tif (!(host instanceof String hostAsString) || !(port instanceof Integer portAsInt)) {\n\t\t\treturn HostAndPort.empty();\n\t\t}\n\t\treturn new HostAndPort(hostAsString, portAsInt);\n\t}\n\n\tprivate record HostAndPort(@Nullable String host, @Nullable Integer port) {\n\t\tstatic HostAndPort empty() {\n\t\t\treturn new HostAndPort(null, null);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/observation/R2dbcObservationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.observation;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for R2DBC observability.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.observations.r2dbc\")\npublic class R2dbcObservationProperties {\n\n\t/**\n\t * Whether to tag actual query parameter values.\n\t */\n\tprivate boolean includeParameterValues;\n\n\tpublic boolean isIncludeParameterValues() {\n\t\treturn this.includeParameterValues;\n\t}\n\n\tpublic void setIncludeParameterValues(boolean includeParameterValues) {\n\t\tthis.includeParameterValues = includeParameterValues;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for R2DBC observations.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.autoconfigure.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for R2DBC.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/ClickHouseEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * ClickHouse environment details.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tClickHouseEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env);\n\t}\n\n\tprivate static String extractDatabase(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"CLICKHOUSE_DB\");\n\t\treturn (result != null) ? result : \"default\";\n\t}\n\n\tprivate static String extractUsername(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"CLICKHOUSE_USER\");\n\t\treturn (result != null) ? result : \"default\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tboolean allowEmpty = env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tString password = env.get(\"CLICKHOUSE_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password) || allowEmpty, \"No ClickHouse password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/ClickHouseR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for a {@code clickhouse} service.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseR2dbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {\n\n\tClickHouseR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"clickhouse/clickhouse-server\", \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tprotected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ClickhouseDbR2dbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@code clickhouse}\n\t * {@link RunningService}.\n\t */\n\tstatic class ClickhouseDbR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements R2dbcConnectionDetails {\n\n\t\tprivate static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(\n\t\t\t\t\"clickhouse\", 8123);\n\n\t\tprivate final ConnectionFactoryOptions connectionFactoryOptions;\n\n\t\tClickhouseDbR2dbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(service.env());\n\t\t\tthis.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, environment.getDatabase(),\n\t\t\t\t\tenvironment.getUsername(), environment.getPassword());\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn this.connectionFactoryOptions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/ConnectionFactoryOptionsBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Option;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility used to build an R2DBC {@link ConnectionFactoryOptions} for a\n * {@link RunningService}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConnectionFactoryOptionsBuilder {\n\n\tprivate static final String PARAMETERS_LABEL = \"org.springframework.boot.r2dbc.parameters\";\n\n\tprivate final String driver;\n\n\tprivate final int sourcePort;\n\n\t/**\n\t * Create a new {@link ConnectionFactoryOptionsBuilder} instance.\n\t * @param driver the driver\n\t * @param containerPort the source container port\n\t */\n\tConnectionFactoryOptionsBuilder(String driver, int containerPort) {\n\t\tAssert.notNull(driver, \"'driver' must not be null\");\n\t\tthis.driver = driver;\n\t\tthis.sourcePort = containerPort;\n\t}\n\n\tConnectionFactoryOptions build(RunningService service, String database, @Nullable String user,\n\t\t\t@Nullable String password) {\n\t\tAssert.notNull(service, \"'service' must not be null\");\n\t\tAssert.notNull(database, \"'database' must not be null\");\n\t\tConnectionFactoryOptions.Builder builder = ConnectionFactoryOptions.builder()\n\t\t\t.option(ConnectionFactoryOptions.DRIVER, this.driver)\n\t\t\t.option(ConnectionFactoryOptions.HOST, service.host())\n\t\t\t.option(ConnectionFactoryOptions.PORT, service.ports().get(this.sourcePort))\n\t\t\t.option(ConnectionFactoryOptions.DATABASE, database);\n\t\tif (StringUtils.hasLength(user)) {\n\t\t\tbuilder.option(ConnectionFactoryOptions.USER, user);\n\t\t}\n\t\tif (StringUtils.hasLength(password)) {\n\t\t\tbuilder.option(ConnectionFactoryOptions.PASSWORD, password);\n\t\t}\n\t\tapplyParameters(service, builder);\n\t\treturn builder.build();\n\t}\n\n\tprivate void applyParameters(RunningService service, ConnectionFactoryOptions.Builder builder) {\n\t\tString parameters = service.labels().get(PARAMETERS_LABEL);\n\t\ttry {\n\t\t\tif (StringUtils.hasText(parameters)) {\n\t\t\t\tparseParameters(parameters).forEach((name, value) -> builder.option(Option.valueOf(name), value));\n\t\t\t}\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to apply R2DBC label parameters '%s' defined on service %s\".formatted(parameters, service));\n\t\t}\n\t}\n\n\tprivate Map<String, String> parseParameters(String parameters) {\n\t\tMap<String, String> result = new LinkedHashMap<>();\n\t\tfor (String parameter : StringUtils.commaDelimitedListToStringArray(parameters)) {\n\t\t\tString[] parts = parameter.split(\"=\");\n\t\t\tAssert.state(parts.length == 2, () -> \"'parameters' [%s] must contain parsable value\".formatted(parameter));\n\t\t\tresult.put(parts[0], parts[1]);\n\t\t}\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/MariaDbEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * MariaDB environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MariaDbEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tMariaDbEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env);\n\t}\n\n\tprivate String extractUsername(Map<String, @Nullable String> env) {\n\t\tString user = env.get(\"MARIADB_USER\");\n\t\tif (user == null) {\n\t\t\tuser = env.get(\"MYSQL_USER\");\n\t\t}\n\t\treturn (user != null) ? user : \"root\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tAssert.state(!env.containsKey(\"MARIADB_RANDOM_ROOT_PASSWORD\"), \"MARIADB_RANDOM_ROOT_PASSWORD is not supported\");\n\t\tAssert.state(!env.containsKey(\"MYSQL_RANDOM_ROOT_PASSWORD\"), \"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t\tAssert.state(!env.containsKey(\"MARIADB_ROOT_PASSWORD_HASH\"), \"MARIADB_ROOT_PASSWORD_HASH is not supported\");\n\t\tboolean allowEmpty = env.containsKey(\"MARIADB_ALLOW_EMPTY_PASSWORD\")\n\t\t\t\t|| env.containsKey(\"MYSQL_ALLOW_EMPTY_PASSWORD\") || env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tString password = env.get(\"MARIADB_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MYSQL_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MARIADB_ROOT_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MYSQL_ROOT_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password) || allowEmpty, \"No MariaDB password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tprivate String extractDatabase(Map<String, @Nullable String> env) {\n\t\tString database = env.get(\"MARIADB_DATABASE\");\n\t\tdatabase = (database != null) ? database : env.get(\"MYSQL_DATABASE\");\n\t\tAssert.state(database != null, \"No MARIADB_DATABASE defined\");\n\t\treturn database;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/MariaDbR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for a {@code mariadb} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MariaDbR2dbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {\n\n\tMariaDbR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mariadb\", \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tprotected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new MariaDbR2dbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@code mariadb} {@link RunningService}.\n\t */\n\tstatic class MariaDbR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements R2dbcConnectionDetails {\n\n\t\tprivate static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(\n\t\t\t\t\"mariadb\", 3306);\n\n\t\tprivate final ConnectionFactoryOptions connectionFactoryOptions;\n\n\t\tMariaDbR2dbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tMariaDbEnvironment environment = new MariaDbEnvironment(service.env());\n\t\t\tthis.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, environment.getDatabase(),\n\t\t\t\t\tenvironment.getUsername(), environment.getPassword());\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn this.connectionFactoryOptions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/MySqlEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * MySQL environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MySqlEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tMySqlEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env);\n\t}\n\n\tprivate static String extractUsername(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"MYSQL_USER\");\n\t\treturn (result != null) ? result : \"root\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tAssert.state(!env.containsKey(\"MYSQL_RANDOM_ROOT_PASSWORD\"), \"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t\tboolean allowEmpty = env.containsKey(\"MYSQL_ALLOW_EMPTY_PASSWORD\") || env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tString password = env.get(\"MYSQL_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"MYSQL_ROOT_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password) || allowEmpty, \"No MySQL password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tprivate String extractDatabase(Map<String, @Nullable String> env) {\n\t\tString database = env.get(\"MYSQL_DATABASE\");\n\t\tAssert.state(database != null, \"No MYSQL_DATABASE defined\");\n\t\treturn database;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/MySqlR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for a {@code mysql} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass MySqlR2dbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {\n\n\tMySqlR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mysql\", \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tprotected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new MySqlR2dbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@code mysql} {@link RunningService}.\n\t */\n\tstatic class MySqlR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements R2dbcConnectionDetails {\n\n\t\tprivate static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(\n\t\t\t\t\"mysql\", 3306);\n\n\t\tprivate final ConnectionFactoryOptions connectionFactoryOptions;\n\n\t\tMySqlR2dbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tMySqlEnvironment environment = new MySqlEnvironment(service.env());\n\t\t\tthis.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, environment.getDatabase(),\n\t\t\t\t\tenvironment.getUsername(), environment.getPassword());\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn this.connectionFactoryOptions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/OracleContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\n/**\n * Enumeration of supported Oracle containers.\n *\n * @author Andy Wilkinson\n */\nenum OracleContainer {\n\n\tFREE(\"gvenzl/oracle-free\", \"freepdb1\"),\n\n\tXE(\"gvenzl/oracle-xe\", \"xepdb1\");\n\n\tprivate final String imageName;\n\n\tprivate final String defaultDatabase;\n\n\tOracleContainer(String imageName, String defaultDatabase) {\n\t\tthis.imageName = imageName;\n\t\tthis.defaultDatabase = defaultDatabase;\n\t}\n\n\tString getImageName() {\n\t\treturn this.imageName;\n\t}\n\n\tString getDefaultDatabase() {\n\t\treturn this.defaultDatabase;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/OracleEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Oracle Database environment details.\n *\n * @author Andy Wilkinson\n */\nclass OracleEnvironment {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final String database;\n\n\tOracleEnvironment(Map<String, @Nullable String> env, String defaultDatabase) {\n\t\tthis.username = extractUsername(env);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extractDatabase(env, defaultDatabase);\n\t}\n\n\tprivate static String extractDatabase(Map<String, @Nullable String> env, String defaultDatabase) {\n\t\tString result = env.get(\"ORACLE_DATABASE\");\n\t\treturn (result != null) ? result : defaultDatabase;\n\t}\n\n\tprivate static String extractUsername(Map<String, @Nullable String> env) {\n\t\tString result = env.get(\"APP_USER\");\n\t\treturn (result != null) ? result : \"system\";\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tif (env.containsKey(\"APP_USER\")) {\n\t\t\tString password = env.get(\"APP_USER_PASSWORD\");\n\t\t\tAssert.state(StringUtils.hasLength(password), \"No Oracle app password found\");\n\t\t\treturn password;\n\t\t}\n\t\tAssert.state(!env.containsKey(\"ORACLE_RANDOM_PASSWORD\"),\n\t\t\t\t\"ORACLE_RANDOM_PASSWORD is not supported without APP_USER and APP_USER_PASSWORD\");\n\t\tString password = env.get(\"ORACLE_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password), \"No Oracle password found\");\n\t\treturn password;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/OracleFreeR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for an {@link OracleContainer#FREE} service.\n *\n * @author Andy Wilkinson\n */\nclass OracleFreeR2dbcDockerComposeConnectionDetailsFactory extends OracleR2dbcDockerComposeConnectionDetailsFactory {\n\n\tprotected OracleFreeR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OracleContainer.FREE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/OracleR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * Base class for a {@link DockerComposeConnectionDetailsFactory} to create\n * {@link R2dbcConnectionDetails} for an {@code oracle-free} or {@code oracle-xe} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nabstract class OracleR2dbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {\n\n\tprivate final String defaultDatabase;\n\n\tOracleR2dbcDockerComposeConnectionDetailsFactory(OracleContainer container) {\n\t\tsuper(container.getImageName(), \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t\tthis.defaultDatabase = container.getDefaultDatabase();\n\t}\n\n\t@Override\n\tprotected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new OracleDbR2dbcDockerComposeConnectionDetails(source.getRunningService(), this.defaultDatabase);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@code gvenzl/oracle-xe}\n\t * {@link RunningService}.\n\t */\n\tstatic class OracleDbR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements R2dbcConnectionDetails {\n\n\t\tprivate static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(\n\t\t\t\t\"oracle\", 1521);\n\n\t\tprivate final ConnectionFactoryOptions connectionFactoryOptions;\n\n\t\tOracleDbR2dbcDockerComposeConnectionDetails(RunningService service, String defaultDatabase) {\n\t\t\tsuper(service);\n\t\t\tOracleEnvironment environment = new OracleEnvironment(service.env(), defaultDatabase);\n\t\t\tthis.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, environment.getDatabase(),\n\t\t\t\t\tenvironment.getUsername(), environment.getPassword());\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn this.connectionFactoryOptions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/OracleXeR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for an {@link OracleContainer#XE} service.\n *\n * @author Andy Wilkinson\n */\nclass OracleXeR2dbcDockerComposeConnectionDetailsFactory extends OracleR2dbcDockerComposeConnectionDetailsFactory {\n\n\tprotected OracleXeR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(OracleContainer.XE);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/PostgresEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Postgres environment details.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Sidmar Theodoro\n * @author He Zean\n */\nclass PostgresEnvironment {\n\n\tprivate static final String[] USERNAME_KEYS = new String[] { \"POSTGRES_USER\", \"POSTGRESQL_USER\",\n\t\t\t\"POSTGRESQL_USERNAME\" };\n\n\tprivate static final String DEFAULT_USERNAME = \"postgres\";\n\n\tprivate static final String[] DATABASE_KEYS = new String[] { \"POSTGRES_DB\", \"POSTGRESQL_DB\",\n\t\t\t\"POSTGRESQL_DATABASE\" };\n\n\tprivate final String username;\n\n\tprivate final @Nullable String password;\n\n\tprivate final String database;\n\n\tPostgresEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.username = extract(env, USERNAME_KEYS, DEFAULT_USERNAME);\n\t\tthis.password = extractPassword(env);\n\t\tthis.database = extract(env, DATABASE_KEYS, this.username);\n\t}\n\n\tprivate String extract(Map<String, @Nullable String> env, String[] keys, String defaultValue) {\n\t\tfor (String key : keys) {\n\t\t\tString value = env.get(key);\n\t\t\tif (value != null) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n\tprivate @Nullable String extractPassword(Map<String, @Nullable String> env) {\n\t\tif (isUsingTrustHostAuthMethod(env)) {\n\t\t\treturn null;\n\t\t}\n\t\tString password = env.getOrDefault(\"POSTGRES_PASSWORD\", env.get(\"POSTGRESQL_PASSWORD\"));\n\t\tboolean allowEmpty = env.containsKey(\"ALLOW_EMPTY_PASSWORD\");\n\t\tAssert.state(allowEmpty || StringUtils.hasLength(password), \"No PostgreSQL password found\");\n\t\treturn (password != null) ? password : \"\";\n\t}\n\n\tprivate boolean isUsingTrustHostAuthMethod(Map<String, @Nullable String> env) {\n\t\tString hostAuthMethod = env.get(\"POSTGRES_HOST_AUTH_METHOD\");\n\t\treturn \"trust\".equals(hostAuthMethod);\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\t@Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tString getDatabase() {\n\t\treturn this.database;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/PostgresR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Option;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for a {@code postgres} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass PostgresR2dbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {\n\n\tPostgresR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"postgres\", \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tprotected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new PostgresDbR2dbcDockerComposeConnectionDetails(source.getRunningService(), source.getEnvironment());\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@code postgres} {@link RunningService}.\n\t */\n\tstatic class PostgresDbR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements R2dbcConnectionDetails {\n\n\t\tprivate static final Option<String> APPLICATION_NAME = Option.valueOf(\"applicationName\");\n\n\t\tprivate static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(\n\t\t\t\t\"postgresql\", 5432);\n\n\t\tprivate final ConnectionFactoryOptions connectionFactoryOptions;\n\n\t\tPostgresDbR2dbcDockerComposeConnectionDetails(RunningService service, Environment environment) {\n\t\t\tsuper(service);\n\t\t\tthis.connectionFactoryOptions = getConnectionFactoryOptions(service, environment);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn this.connectionFactoryOptions;\n\t\t}\n\n\t\tprivate static ConnectionFactoryOptions getConnectionFactoryOptions(RunningService service,\n\t\t\t\tEnvironment environment) {\n\t\t\tPostgresEnvironment env = new PostgresEnvironment(service.env());\n\t\t\tConnectionFactoryOptions connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service,\n\t\t\t\t\tenv.getDatabase(), env.getUsername(), env.getPassword());\n\t\t\treturn addApplicationNameIfNecessary(connectionFactoryOptions, environment);\n\t\t}\n\n\t\tprivate static ConnectionFactoryOptions addApplicationNameIfNecessary(\n\t\t\t\tConnectionFactoryOptions connectionFactoryOptions, Environment environment) {\n\t\t\tif (connectionFactoryOptions.hasOption(APPLICATION_NAME)) {\n\t\t\t\treturn connectionFactoryOptions;\n\t\t\t}\n\t\t\tString applicationName = environment.getProperty(\"spring.application.name\");\n\t\t\tif (!StringUtils.hasText(applicationName)) {\n\t\t\t\treturn connectionFactoryOptions;\n\t\t\t}\n\t\t\treturn connectionFactoryOptions.mutate().option(APPLICATION_NAME, applicationName).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/SqlServerEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * MS SQL Server environment details.\n *\n * @author Andy Wilkinson\n */\nclass SqlServerEnvironment {\n\n\tprivate final String username = \"SA\";\n\n\tprivate final String password;\n\n\tSqlServerEnvironment(Map<String, @Nullable String> env) {\n\t\tthis.password = extractPassword(env);\n\t}\n\n\tprivate String extractPassword(Map<String, @Nullable String> env) {\n\t\tString password = env.get(\"MSSQL_SA_PASSWORD\");\n\t\tpassword = (password != null) ? password : env.get(\"SA_PASSWORD\");\n\t\tAssert.state(StringUtils.hasLength(password), \"No MSSQL password found\");\n\t\treturn password;\n\t}\n\n\tString getUsername() {\n\t\treturn this.username;\n\t}\n\n\tString getPassword() {\n\t\treturn this.password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/SqlServerR2dbcDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}\n * for a {@code mssql} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass SqlServerR2dbcDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {\n\n\tSqlServerR2dbcDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"mssql/server\", \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tprotected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new SqlServerR2dbcDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@code mssql} {@link RunningService}.\n\t */\n\tstatic class SqlServerR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements R2dbcConnectionDetails {\n\n\t\tprivate static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(\n\t\t\t\t\"mssql\", 1433);\n\n\t\tprivate final ConnectionFactoryOptions connectionFactoryOptions;\n\n\t\tSqlServerR2dbcDockerComposeConnectionDetails(RunningService service) {\n\t\t\tsuper(service);\n\t\t\tSqlServerEnvironment environment = new SqlServerEnvironment(service.env());\n\t\t\tthis.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, \"\",\n\t\t\t\t\tenvironment.getUsername(), environment.getPassword());\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn this.connectionFactoryOptions;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose R2DBC service connections.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/health/ConnectionFactoryHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.health;\n\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.Row;\nimport io.r2dbc.spi.RowMetadata;\nimport io.r2dbc.spi.ValidationDepth;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.health.contributor.AbstractReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link HealthIndicator} to validate a R2DBC {@link ConnectionFactory}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class ConnectionFactoryHealthIndicator extends AbstractReactiveHealthIndicator {\n\n\tprivate final ConnectionFactory connectionFactory;\n\n\tprivate final @Nullable String validationQuery;\n\n\t/**\n\t * Create a new {@link ConnectionFactoryHealthIndicator} using the specified\n\t * {@link ConnectionFactory} and no validation query.\n\t * @param connectionFactory the connection factory\n\t * @see Connection#validate(ValidationDepth)\n\t */\n\tpublic ConnectionFactoryHealthIndicator(ConnectionFactory connectionFactory) {\n\t\tthis(connectionFactory, null);\n\t}\n\n\t/**\n\t * Create a new {@link ConnectionFactoryHealthIndicator} using the specified\n\t * {@link ConnectionFactory} and validation query.\n\t * @param connectionFactory the connection factory\n\t * @param validationQuery the validation query, can be {@code null} to use connection\n\t * validation\n\t */\n\tpublic ConnectionFactoryHealthIndicator(ConnectionFactory connectionFactory, @Nullable String validationQuery) {\n\t\tAssert.notNull(connectionFactory, \"'connectionFactory' must not be null\");\n\t\tthis.connectionFactory = connectionFactory;\n\t\tthis.validationQuery = validationQuery;\n\t}\n\n\t@Override\n\tprotected final Mono<Health> doHealthCheck(Health.Builder builder) {\n\t\treturn validate(builder).defaultIfEmpty(builder.build())\n\t\t\t.onErrorResume(Exception.class, (ex) -> Mono.just(builder.down(ex).build()));\n\t}\n\n\tprivate Mono<Health> validate(Health.Builder builder) {\n\t\tbuilder.withDetail(\"database\", this.connectionFactory.getMetadata().getName());\n\t\treturn (StringUtils.hasText(this.validationQuery)) ? validateWithQuery(builder)\n\t\t\t\t: validateWithConnectionValidation(builder);\n\t}\n\n\tprivate Mono<Health> validateWithQuery(Health.Builder builder) {\n\t\tAssert.state(this.validationQuery != null, \"'validationQuery' must not be null\");\n\t\tbuilder.withDetail(\"validationQuery\", this.validationQuery);\n\t\tMono<Object> connectionValidation = Mono.usingWhen(this.connectionFactory.create(),\n\t\t\t\t(conn) -> Flux.from(conn.createStatement(this.validationQuery).execute())\n\t\t\t\t\t.flatMap((it) -> it.map(this::extractResult))\n\t\t\t\t\t.next(),\n\t\t\t\tConnection::close, (o, throwable) -> o.close(), Connection::close);\n\t\treturn connectionValidation.map((result) -> builder.up().withDetail(\"result\", result).build());\n\t}\n\n\tprivate Mono<Health> validateWithConnectionValidation(Health.Builder builder) {\n\t\tbuilder.withDetail(\"validationQuery\", \"validate(REMOTE)\");\n\t\tMono<Boolean> connectionValidation = Mono.usingWhen(this.connectionFactory.create(),\n\t\t\t\t(connection) -> Mono.from(connection.validate(ValidationDepth.REMOTE)), Connection::close,\n\t\t\t\t(connection, ex) -> connection.close(), Connection::close);\n\t\treturn connectionValidation.map((valid) -> builder.status((valid) ? Status.UP : Status.DOWN).build());\n\t}\n\n\tprivate @Nullable Object extractResult(Row row, RowMetadata metadata) {\n\t\treturn row.get(metadata.getColumnMetadatas().iterator().next().getName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/health/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Health integration for R2DBC.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.health;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.init;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.core.io.Resource;\nimport org.springframework.r2dbc.connection.init.ResourceDatabasePopulator;\n\n/**\n * An {@link InitializingBean} that initializes a database represented by an R2DBC\n * {@link ConnectionFactory}.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic class R2dbcScriptDatabaseInitializer extends AbstractScriptDatabaseInitializer {\n\n\tprivate final ConnectionFactory connectionFactory;\n\n\t/**\n\t * Creates a new {@code R2dbcScriptDatabaseInitializer} that will initialize the\n\t * database recognized by the given {@code connectionFactory} using the given\n\t * {@code settings}.\n\t * @param connectionFactory connectionFactory for the database\n\t * @param settings initialization settings\n\t */\n\tpublic R2dbcScriptDatabaseInitializer(ConnectionFactory connectionFactory,\n\t\t\tDatabaseInitializationSettings settings) {\n\t\tsuper(settings);\n\t\tthis.connectionFactory = connectionFactory;\n\t}\n\n\t@Override\n\tprotected boolean isEmbeddedDatabase() {\n\t\treturn EmbeddedDatabaseConnection.isEmbedded(this.connectionFactory);\n\t}\n\n\t@Override\n\tprotected void runScripts(Scripts scripts) {\n\t\tResourceDatabasePopulator populator = new ResourceDatabasePopulator();\n\t\tpopulator.setContinueOnError(scripts.isContinueOnError());\n\t\tpopulator.setSeparator(scripts.getSeparator());\n\t\tif (scripts.getEncoding() != null) {\n\t\t\tpopulator.setSqlScriptEncoding(scripts.getEncoding().name());\n\t\t}\n\t\tfor (Resource script : scripts) {\n\t\t\tpopulator.addScript(script);\n\t\t}\n\t\tpopulator.populate(this.connectionFactory).block();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.init;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\n\n/**\n * A {@link DatabaseInitializerDetector} for {@link R2dbcScriptDatabaseInitializer}.\n *\n * @author Andy Wilkinson\n */\nclass R2dbcScriptDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\treturn Collections.singleton(R2dbcScriptDatabaseInitializer.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/init/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for initialization of an SQL database using an R2DBC\n * {@link io.r2dbc.spi.ConnectionFactory ConnectionFactory}.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.init;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/metrics/ConnectionPoolMetrics.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.metrics;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.Gauge.Builder;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.binder.MeterBinder;\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.PoolMetrics;\n\n/**\n * A {@link MeterBinder} for a {@link ConnectionPool}.\n *\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class ConnectionPoolMetrics implements MeterBinder {\n\n\tprivate static final String CONNECTIONS = \"connections\";\n\n\tprivate final ConnectionPool pool;\n\n\tprivate final Iterable<Tag> tags;\n\n\tpublic ConnectionPoolMetrics(ConnectionPool pool, String name, Iterable<Tag> tags) {\n\t\tthis.pool = pool;\n\t\tthis.tags = Tags.concat(tags, \"name\", name);\n\t}\n\n\t@Override\n\tpublic void bindTo(MeterRegistry registry) {\n\t\tthis.pool.getMetrics().ifPresent((poolMetrics) -> {\n\t\t\tbindConnectionPoolMetric(registry,\n\t\t\t\t\tGauge.builder(metricKey(\"acquired\"), poolMetrics, PoolMetrics::acquiredSize)\n\t\t\t\t\t\t.description(\"Size of successfully acquired connections which are in active use.\"));\n\t\t\tbindConnectionPoolMetric(registry,\n\t\t\t\t\tGauge.builder(metricKey(\"allocated\"), poolMetrics, PoolMetrics::allocatedSize)\n\t\t\t\t\t\t.description(\"Size of allocated connections in the pool which are in active use or idle.\"));\n\t\t\tbindConnectionPoolMetric(registry, Gauge.builder(metricKey(\"idle\"), poolMetrics, PoolMetrics::idleSize)\n\t\t\t\t.description(\"Size of idle connections in the pool.\"));\n\t\t\tbindConnectionPoolMetric(registry,\n\t\t\t\t\tGauge.builder(metricKey(\"pending\"), poolMetrics, PoolMetrics::pendingAcquireSize)\n\t\t\t\t\t\t.description(\"Size of pending to acquire connections from the underlying connection factory.\"));\n\t\t\tbindConnectionPoolMetric(registry,\n\t\t\t\t\tGauge.builder(metricKey(\"max.allocated\"), poolMetrics, PoolMetrics::getMaxAllocatedSize)\n\t\t\t\t\t\t.description(\"Maximum size of allocated connections that this pool allows.\"));\n\t\t\tbindConnectionPoolMetric(registry,\n\t\t\t\t\tGauge.builder(metricKey(\"max.pending\"), poolMetrics, PoolMetrics::getMaxPendingAcquireSize)\n\t\t\t\t\t\t.description(\"Maximum size of pending state to acquire connections that this pool allows.\"));\n\t\t});\n\t}\n\n\tprivate void bindConnectionPoolMetric(MeterRegistry registry, Builder<?> builder) {\n\t\tbuilder.tags(this.tags).baseUnit(CONNECTIONS).register(registry);\n\t}\n\n\tprivate static String metricKey(String name) {\n\t\treturn \"r2dbc.pool.\" + name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Metrics for R2DBC.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for R2DBC connectivity.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/ClickHouseR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.clickhouse.ClickHouseContainer;\nimport org.testcontainers.clickhouse.ClickHouseR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link ClickHouseContainer}.\n *\n * @author Eddú Meléndez\n */\nclass ClickHouseR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<ClickHouseContainer, R2dbcConnectionDetails> {\n\n\tClickHouseR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<ClickHouseContainer> source) {\n\t\treturn new ClickHouseR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class ClickHouseR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<ClickHouseContainer> implements R2dbcConnectionDetails {\n\n\t\tprivate ClickHouseR2dbcDatabaseContainerConnectionDetails(\n\t\t\t\tContainerConnectionSource<ClickHouseContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn ClickHouseR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/DeprecatedMariaDbR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.containers.MariaDBContainer;\nimport org.testcontainers.containers.MariaDBR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MariaDBContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link MariaDbR2dbcContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedMariaDbR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<MariaDBContainer<?>, R2dbcConnectionDetails> {\n\n\tDeprecatedMariaDbR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<MariaDBContainer<?>> source) {\n\t\treturn new MariaDbR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MariaDbR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<MariaDBContainer<?>> implements R2dbcConnectionDetails {\n\n\t\tprivate MariaDbR2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<MariaDBContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn MariaDBR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/DeprecatedMySqlR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.containers.MySQLContainer;\nimport org.testcontainers.containers.MySQLR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MySQLContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link MySqlR2dbcContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedMySqlR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<MySQLContainer<?>, R2dbcConnectionDetails> {\n\n\tDeprecatedMySqlR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<MySQLContainer<?>> source) {\n\t\treturn new MySqlR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MySqlR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<MySQLContainer<?>> implements R2dbcConnectionDetails {\n\n\t\tprivate MySqlR2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<MySQLContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn MySQLR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/DeprecatedPostgresR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.containers.PostgreSQLContainer;\nimport org.testcontainers.containers.PostgreSQLR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link PostgreSQLContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link PostgresR2dbcContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedPostgresR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<PostgreSQLContainer<?>, R2dbcConnectionDetails> {\n\n\tDeprecatedPostgresR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<PostgreSQLContainer<?>> source) {\n\t\treturn new PostgresR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class PostgresR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<PostgreSQLContainer<?>> implements R2dbcConnectionDetails {\n\n\t\tPostgresR2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<PostgreSQLContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn PostgreSQLR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/DeprecatedSqlServerR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.containers.MSSQLR2DBCDatabaseContainer;\nimport org.testcontainers.containers.MSSQLServerContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MSSQLServerContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n * {@link SqlServerR2dbcContainerConnectionDetailsFactory}.\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\nclass DeprecatedSqlServerR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<MSSQLServerContainer<?>, R2dbcConnectionDetails> {\n\n\tDeprecatedSqlServerR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<MSSQLServerContainer<?>> source) {\n\t\treturn new MsSqlServerR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MsSqlServerR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<MSSQLServerContainer<?>> implements R2dbcConnectionDetails {\n\n\t\tprivate MsSqlServerR2dbcDatabaseContainerConnectionDetails(\n\t\t\t\tContainerConnectionSource<MSSQLServerContainer<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn MSSQLR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/MariaDbR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.mariadb.MariaDBR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MariaDBContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass MariaDbR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<MariaDBContainer, R2dbcConnectionDetails> {\n\n\tMariaDbR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<MariaDBContainer> source) {\n\t\treturn new MariaDbR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MariaDbR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<MariaDBContainer> implements R2dbcConnectionDetails {\n\n\t\tprivate MariaDbR2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<MariaDBContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn MariaDBR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/MySqlR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.mysql.MySQLContainer;\nimport org.testcontainers.mysql.MySQLR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MySQLContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass MySqlR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<MySQLContainer, R2dbcConnectionDetails> {\n\n\tMySqlR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<MySQLContainer> source) {\n\t\treturn new MySqlR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MySqlR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<MySQLContainer> implements R2dbcConnectionDetails {\n\n\t\tprivate MySqlR2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<MySQLContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn MySQLR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/OracleFreeR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.oracle.OracleContainer;\nimport org.testcontainers.oracle.OracleR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link OracleContainer}.\n *\n * @author Eddú Meléndez\n */\nclass OracleFreeR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<OracleContainer, R2dbcConnectionDetails> {\n\n\tOracleFreeR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<OracleContainer> source) {\n\t\treturn new R2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class R2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<OracleContainer> implements R2dbcConnectionDetails {\n\n\t\tprivate R2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<OracleContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn OracleR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/OracleXeR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.containers.OracleContainer;\nimport org.testcontainers.containers.OracleR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link OracleContainer}.\n *\n * @author Eddú Meléndez\n */\nclass OracleXeR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<OracleContainer, R2dbcConnectionDetails> {\n\n\tOracleXeR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<OracleContainer> source) {\n\t\treturn new R2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class R2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<OracleContainer> implements R2dbcConnectionDetails {\n\n\t\tprivate R2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<OracleContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn OracleR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/PostgresR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\nimport org.testcontainers.postgresql.PostgreSQLR2DBCDatabaseContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link PostgreSQLContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass PostgresR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<PostgreSQLContainer, R2dbcConnectionDetails> {\n\n\tPostgresR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<PostgreSQLContainer> source) {\n\t\treturn new PostgresR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class PostgresR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<PostgreSQLContainer> implements R2dbcConnectionDetails {\n\n\t\tPostgresR2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource<PostgreSQLContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn PostgreSQLR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/SqlServerR2dbcContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.testcontainers.mssqlserver.MSSQLR2DBCDatabaseContainer;\nimport org.testcontainers.mssqlserver.MSSQLServerContainer;\n\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcConnectionDetails;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from\n * a {@link ServiceConnection @ServiceConnection}-annotated {@link MSSQLServerContainer}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass SqlServerR2dbcContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<MSSQLServerContainer, R2dbcConnectionDetails> {\n\n\tSqlServerR2dbcContainerConnectionDetailsFactory() {\n\t\tsuper(ANY_CONNECTION_NAME, \"io.r2dbc.spi.ConnectionFactoryOptions\");\n\t}\n\n\t@Override\n\tpublic R2dbcConnectionDetails getContainerConnectionDetails(\n\t\t\tContainerConnectionSource<MSSQLServerContainer> source) {\n\t\treturn new MsSqlServerR2dbcDatabaseContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static final class MsSqlServerR2dbcDatabaseContainerConnectionDetails\n\t\t\textends ContainerConnectionDetails<MSSQLServerContainer> implements R2dbcConnectionDetails {\n\n\t\tprivate MsSqlServerR2dbcDatabaseContainerConnectionDetails(\n\t\t\t\tContainerConnectionSource<MSSQLServerContainer> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\treturn MSSQLR2DBCDatabaseContainer.getOptions(getContainer());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/java/org/springframework/boot/r2dbc/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers R2DBC service connections.\n */\n@NullMarked\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.R2dbcInitializationAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.R2dbcProxyAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.R2dbcTransactionManagerAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.health.ConnectionFactoryHealthContributorAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.metrics.ConnectionPoolMetricsAutoConfiguration\norg.springframework.boot.r2dbc.autoconfigure.observation.R2dbcObservationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.r2dbc.docker.compose.ClickHouseR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.docker.compose.MariaDbR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.docker.compose.MySqlR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.docker.compose.OracleFreeR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.docker.compose.OracleXeR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.docker.compose.PostgresR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.docker.compose.SqlServerR2dbcDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.ClickHouseR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.DeprecatedMariaDbR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.DeprecatedMySqlR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.DeprecatedPostgresR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.DeprecatedSqlServerR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.MariaDbR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.MySqlR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.OracleFreeR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.OracleXeR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.PostgresR2dbcContainerConnectionDetailsFactory,\\\norg.springframework.boot.r2dbc.testcontainers.SqlServerR2dbcContainerConnectionDetailsFactory\n\n\n\n\n\n# Database Initializer Detectors\norg.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\\\norg.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializerDetector\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.r2dbc.autoconfigure.ConnectionFactoryBeanCreationFailureAnalyzer,\\\norg.springframework.boot.r2dbc.autoconfigure.MissingR2dbcPoolDependencyFailureAnalyzer,\\\norg.springframework.boot.r2dbc.autoconfigure.MultipleConnectionPoolConfigurationsFailureAnalyzer,\\\norg.springframework.boot.r2dbc.autoconfigure.NoConnectionFactoryBeanFailureAnalyzer\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/ConnectionFactoryBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Function;\n\nimport io.r2dbc.h2.H2ConnectionFactoryMetadata;\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.ConnectionPoolConfiguration;\nimport io.r2dbc.pool.PoolingConnectionFactoryProvider;\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryMetadata;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Option;\nimport io.r2dbc.spi.ValidationDepth;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.reactivestreams.Publisher;\n\nimport org.springframework.boot.r2dbc.ConnectionFactoryBuilder.PoolingAwareOptionsCapableWrapper;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.ReflectionUtils.FieldFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionFactoryBuilder}.\n *\n * @author Mark Paluch\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass ConnectionFactoryBuilderTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithNullUrlShouldFail() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ConnectionFactoryBuilder.withUrl(null));\n\t}\n\n\t@Test\n\tvoid createWithEmptyUrlShouldFail() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> ConnectionFactoryBuilder.withUrl(\"  \"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithEmbeddedConnectionNoneShouldFail() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> {\n\t\t\tString url = EmbeddedDatabaseConnection.NONE.getUrl(\"test\");\n\t\t\tConnectionFactoryBuilder.withUrl(url);\n\t\t});\n\t}\n\n\t@Test\n\tvoid buildOptionsWithBasicUrlShouldExposeOptions() {\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl(\"r2dbc:simple://:pool:\").buildOptions();\n\t\tassertThat(options.hasOption(ConnectionFactoryOptions.USER)).isFalse();\n\t\tassertThat(options.hasOption(ConnectionFactoryOptions.PASSWORD)).isFalse();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"simple\");\n\t}\n\n\t@Test\n\tvoid buildOptionsWithEmbeddedConnectionH2ShouldExposeOptions() {\n\t\tString url = EmbeddedDatabaseConnection.H2.getUrl(\"testdb\");\n\t\tassertThat(url).isNotNull();\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl(url).buildOptions();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"h2\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL)).isEqualTo(\"mem\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"testdb\");\n\t\tassertThat(options.hasOption(ConnectionFactoryOptions.HOST)).isFalse();\n\t\tassertThat(options.hasOption(ConnectionFactoryOptions.PORT)).isFalse();\n\t\tassertThat(options.hasOption(ConnectionFactoryOptions.USER)).isFalse();\n\t\tassertThat(options.hasOption(ConnectionFactoryOptions.PASSWORD)).isFalse();\n\t\tassertThat(options.getValue(Option.<String>valueOf(\"options\")))\n\t\t\t.isEqualTo(\"DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\");\n\t}\n\n\t@Test\n\tvoid buildOptionsWithCompleteUrlShouldExposeOptions() {\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder\n\t\t\t.withUrl(\"r2dbc:simple:proto://user:password@myhost:4711/mydatabase\")\n\t\t\t.buildOptions();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"simple\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL)).isEqualTo(\"proto\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"user\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"password\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.HOST)).isEqualTo(\"myhost\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PORT)).isEqualTo(4711);\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"mydatabase\");\n\t}\n\n\t@Test\n\tvoid buildOptionsWithSpecificSettingsShouldOverrideUrlOptions() {\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder\n\t\t\t.withUrl(\"r2dbc:simple://user:password@myhost/mydatabase\")\n\t\t\t.username(\"another-user\")\n\t\t\t.password(\"another-password\")\n\t\t\t.hostname(\"another-host\")\n\t\t\t.port(1234)\n\t\t\t.database(\"another-database\")\n\t\t\t.buildOptions();\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"another-user\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"another-password\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.HOST)).isEqualTo(\"another-host\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PORT)).isEqualTo(1234);\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"another-database\");\n\t}\n\n\t@Test\n\tvoid buildOptionsWithDriverPropertiesShouldExposeOptions() {\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl(\"r2dbc:simple://user:password@myhost\")\n\t\t\t.configure((o) -> o.option(Option.valueOf(\"simpleOne\"), \"one\").option(Option.valueOf(\"simpleTwo\"), \"two\"))\n\t\t\t.buildOptions();\n\t\tassertThat(options.getRequiredValue(Option.<String>valueOf(\"simpleOne\"))).isEqualTo(\"one\");\n\t\tassertThat(options.getRequiredValue(Option.<String>valueOf(\"simpleTwo\"))).isEqualTo(\"two\");\n\t}\n\n\t@Test\n\tvoid buildShouldExposeConnectionFactory() {\n\t\tString databaseName = UUID.randomUUID().toString();\n\t\tString url = EmbeddedDatabaseConnection.H2.getUrl(databaseName);\n\t\tassertThat(url).isNotNull();\n\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder.withUrl(url).build();\n\t\tassertThat(connectionFactory).isNotNull();\n\t\tassertThat(connectionFactory.getMetadata().getName()).isEqualTo(H2ConnectionFactoryMetadata.NAME);\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedWithNewDatabaseReturnsNewConnectionFactory() {\n\t\tString initialDatabaseName = UUID.randomUUID().toString();\n\t\tString url = EmbeddedDatabaseConnection.H2.getUrl(initialDatabaseName);\n\t\tassertThat(url).isNotNull();\n\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder.withUrl(url).build();\n\t\tConnectionFactoryOptions initialOptions = ((OptionsCapableConnectionFactory) connectionFactory).getOptions();\n\t\tString derivedDatabaseName = UUID.randomUUID().toString();\n\t\tConnectionFactory derived = ConnectionFactoryBuilder.derivedFrom(connectionFactory)\n\t\t\t.database(derivedDatabaseName)\n\t\t\t.build();\n\t\tConnectionFactoryOptions derivedOptions = ((OptionsCapableConnectionFactory) derived).getOptions();\n\t\tassertThat(derivedOptions.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(derivedDatabaseName);\n\t\tassertMatchingOptions(derivedOptions, initialOptions, ConnectionFactoryOptions.CONNECT_TIMEOUT,\n\t\t\t\tConnectionFactoryOptions.DRIVER, ConnectionFactoryOptions.HOST, ConnectionFactoryOptions.PASSWORD,\n\t\t\t\tConnectionFactoryOptions.PORT, ConnectionFactoryOptions.PROTOCOL, ConnectionFactoryOptions.SSL,\n\t\t\t\tConnectionFactoryOptions.USER);\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedWithNewCredentialsReturnsNewConnectionFactory() {\n\t\tString url = EmbeddedDatabaseConnection.H2.getUrl(UUID.randomUUID().toString());\n\t\tassertThat(url).isNotNull();\n\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder.withUrl(url).build();\n\t\tConnectionFactoryOptions initialOptions = ((OptionsCapableConnectionFactory) connectionFactory).getOptions();\n\t\tConnectionFactory derived = ConnectionFactoryBuilder.derivedFrom(connectionFactory)\n\t\t\t.username(\"admin\")\n\t\t\t.password(\"secret\")\n\t\t\t.build();\n\t\tConnectionFactoryOptions derivedOptions = ((OptionsCapableConnectionFactory) derived).getOptions();\n\t\tassertThat(derivedOptions.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"admin\");\n\t\tassertThat(derivedOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t\tassertMatchingOptions(derivedOptions, initialOptions, ConnectionFactoryOptions.CONNECT_TIMEOUT,\n\t\t\t\tConnectionFactoryOptions.DATABASE, ConnectionFactoryOptions.DRIVER, ConnectionFactoryOptions.HOST,\n\t\t\t\tConnectionFactoryOptions.PORT, ConnectionFactoryOptions.PROTOCOL, ConnectionFactoryOptions.SSL);\n\t}\n\n\t@Test\n\tvoid buildWhenDerivedFromPoolReturnsNewNonPooledConnectionFactory() {\n\t\tString url = EmbeddedDatabaseConnection.H2.getUrl(UUID.randomUUID().toString());\n\t\tassertThat(url).isNotNull();\n\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder.withUrl(url).build();\n\t\tConnectionFactoryOptions initialOptions = ((OptionsCapableConnectionFactory) connectionFactory).getOptions();\n\t\tConnectionPoolConfiguration poolConfiguration = ConnectionPoolConfiguration.builder(connectionFactory).build();\n\t\tConnectionPool pool = new ConnectionPool(poolConfiguration);\n\t\tConnectionFactory derived = ConnectionFactoryBuilder.derivedFrom(pool)\n\t\t\t.username(\"admin\")\n\t\t\t.password(\"secret\")\n\t\t\t.build();\n\t\tassertThat(derived).isNotInstanceOf(ConnectionPool.class).isInstanceOf(OptionsCapableConnectionFactory.class);\n\t\tConnectionFactoryOptions derivedOptions = ((OptionsCapableConnectionFactory) derived).getOptions();\n\t\tassertThat(derivedOptions.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"admin\");\n\t\tassertThat(derivedOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t\tassertMatchingOptions(derivedOptions, initialOptions, ConnectionFactoryOptions.CONNECT_TIMEOUT,\n\t\t\t\tConnectionFactoryOptions.DATABASE, ConnectionFactoryOptions.DRIVER, ConnectionFactoryOptions.HOST,\n\t\t\t\tConnectionFactoryOptions.PORT, ConnectionFactoryOptions.PROTOCOL, ConnectionFactoryOptions.SSL);\n\t}\n\n\t@ParameterizedTest\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\t@MethodSource(\"poolingConnectionProviderOptions\")\n\tvoid optionIsMappedWhenCreatingPoolConfiguration(Option option) {\n\t\tString url = \"r2dbc:pool:h2:mem:///\" + UUID.randomUUID();\n\t\tExpectedOption expectedOption = ExpectedOption.get(option);\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl(url)\n\t\t\t.configure((builder) -> builder.option(PoolingConnectionFactoryProvider.POOL_NAME, \"defaultName\")\n\t\t\t\t.option(option, expectedOption.value))\n\t\t\t.buildOptions();\n\t\tConnectionPoolConfiguration configuration = new PoolingAwareOptionsCapableWrapper()\n\t\t\t.connectionPoolConfiguration(options, mock(ConnectionFactory.class));\n\t\tassertThat(configuration).extracting(expectedOption.property).isEqualTo(expectedOption.value);\n\t}\n\n\tprivate static Iterable<Arguments> poolingConnectionProviderOptions() {\n\t\treturn extractPoolingConnectionProviderOptions((field) -> Option.class.equals(field.getType()));\n\t}\n\n\t@ParameterizedTest\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\t@MethodSource(\"primitivePoolingConnectionProviderOptions\")\n\tvoid stringlyTypedOptionIsMappedWhenCreatingPoolConfiguration(Option option) {\n\t\tString url = \"r2dbc:pool:h2:mem:///\" + UUID.randomUUID();\n\t\tExpectedOption expectedOption = ExpectedOption.get(option);\n\t\tConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl(url)\n\t\t\t.configure((builder) -> builder.option(PoolingConnectionFactoryProvider.POOL_NAME, \"defaultName\")\n\t\t\t\t.option(option, expectedOption.value.toString()))\n\t\t\t.buildOptions();\n\t\tConnectionPoolConfiguration configuration = new PoolingAwareOptionsCapableWrapper()\n\t\t\t.connectionPoolConfiguration(options, mock(ConnectionFactory.class));\n\t\tassertThat(configuration).extracting(expectedOption.property).isEqualTo(expectedOption.value);\n\t}\n\n\t@Test\n\tvoid shouldApplyDecorators() {\n\t\tString url = \"r2dbc:pool:h2:mem:///\" + UUID.randomUUID();\n\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder.withUrl(url)\n\t\t\t.decorator((ignored) -> new MyConnectionFactory())\n\t\t\t.build();\n\t\tassertThat(connectionFactory).isInstanceOf(MyConnectionFactory.class);\n\t}\n\n\tprivate static Iterable<Arguments> primitivePoolingConnectionProviderOptions() {\n\t\treturn extractPoolingConnectionProviderOptions((field) -> {\n\t\t\tResolvableType type = ResolvableType.forField(field);\n\t\t\tif (!type.toClass().equals(Option.class)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tClass<?> valueType = type.as(Option.class).getGenerics()[0].toClass();\n\t\t\treturn valueType.getPackage().getName().equals(\"java.lang\");\n\t\t});\n\t}\n\n\tprivate static Iterable<Arguments> extractPoolingConnectionProviderOptions(FieldFilter filter) {\n\t\tList<Arguments> arguments = new ArrayList<>();\n\t\tReflectionUtils.doWithFields(PoolingConnectionFactoryProvider.class,\n\t\t\t\t(field) -> arguments.add(Arguments.of(ReflectionUtils.getField(field, null))), filter);\n\t\treturn arguments;\n\t}\n\n\tprivate void assertMatchingOptions(ConnectionFactoryOptions actualOptions, ConnectionFactoryOptions expectedOptions,\n\t\t\tOption<?>... optionsToCheck) {\n\t\tfor (Option<?> option : optionsToCheck) {\n\t\t\tassertThat(actualOptions.getValue(option)).as(option.name()).isEqualTo(expectedOptions.getValue(option));\n\t\t}\n\t}\n\n\tprivate enum ExpectedOption {\n\n\t\tACQUIRE_RETRY(PoolingConnectionFactoryProvider.ACQUIRE_RETRY, 4, \"acquireRetry\"),\n\n\t\tBACKGROUND_EVICTION_INTERVAL(PoolingConnectionFactoryProvider.BACKGROUND_EVICTION_INTERVAL,\n\t\t\t\tDuration.ofSeconds(120), \"backgroundEvictionInterval\"),\n\n\t\tINITIAL_SIZE(PoolingConnectionFactoryProvider.INITIAL_SIZE, 2, \"initialSize\"),\n\n\t\tMAX_SIZE(PoolingConnectionFactoryProvider.MAX_SIZE, 8, \"maxSize\"),\n\n\t\tMAX_LIFE_TIME(PoolingConnectionFactoryProvider.MAX_LIFE_TIME, Duration.ofMinutes(2), \"maxLifeTime\"),\n\n\t\tMAX_ACQUIRE_TIME(PoolingConnectionFactoryProvider.MAX_ACQUIRE_TIME, Duration.ofSeconds(30), \"maxAcquireTime\"),\n\n\t\tMAX_IDLE_TIME(PoolingConnectionFactoryProvider.MAX_IDLE_TIME, Duration.ofMinutes(1), \"maxIdleTime\"),\n\n\t\tMAX_CREATE_CONNECTION_TIME(PoolingConnectionFactoryProvider.MAX_CREATE_CONNECTION_TIME, Duration.ofSeconds(10),\n\t\t\t\t\"maxCreateConnectionTime\"),\n\n\t\tMAX_VALIDATION_TIME(PoolingConnectionFactoryProvider.MAX_VALIDATION_TIME, Duration.ofMinutes(4),\n\t\t\t\t\"maxValidationTime\"),\n\n\t\tMIN_IDLE(PoolingConnectionFactoryProvider.MIN_IDLE, 5, \"minIdle\"),\n\n\t\tPOOL_NAME(PoolingConnectionFactoryProvider.POOL_NAME, \"testPool\", \"name\"),\n\n\t\tPOST_ALLOCATE(PoolingConnectionFactoryProvider.POST_ALLOCATE, mock(Function.class), \"postAllocate\"),\n\n\t\tPRE_RELEASE(PoolingConnectionFactoryProvider.PRE_RELEASE, mock(Function.class), \"preRelease\"),\n\n\t\tREGISTER_JMX(PoolingConnectionFactoryProvider.REGISTER_JMX, true, \"registerJmx\"),\n\n\t\tVALIDATION_QUERY(PoolingConnectionFactoryProvider.VALIDATION_QUERY, \"SELECT 1\", \"validationQuery\"),\n\n\t\tVALIDATION_DEPTH(PoolingConnectionFactoryProvider.VALIDATION_DEPTH, ValidationDepth.REMOTE, \"validationDepth\");\n\n\t\tprivate final Option<?> option;\n\n\t\tprivate final Object value;\n\n\t\tprivate final String property;\n\n\t\tExpectedOption(Option<?> option, Object value, String property) {\n\t\t\tthis.option = option;\n\t\t\tthis.value = value;\n\t\t\tthis.property = property;\n\t\t}\n\n\t\tstatic ExpectedOption get(Option<?> option) {\n\t\t\tfor (ExpectedOption expectedOption : values()) {\n\t\t\t\tif (expectedOption.option == option) {\n\t\t\t\t\treturn expectedOption;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new IllegalArgumentException(\"Unexpected option: '\" + option + \"'\");\n\t\t}\n\n\t}\n\n\tprivate static final class MyConnectionFactory implements ConnectionFactory {\n\n\t\t@Override\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tpublic Publisher<? extends Connection> create() {\n\t\t\treturn mock(Publisher.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryMetadata getMetadata() {\n\t\t\treturn mock(ConnectionFactoryMetadata.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/EmbeddedDatabaseConnectionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Arrays;\nimport java.util.UUID;\nimport java.util.stream.Stream;\n\nimport io.r2dbc.spi.ConnectionFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link EmbeddedDatabaseConnection}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass EmbeddedDatabaseConnectionTests {\n\n\t@ParameterizedTest\n\t@MethodSource(\"urlParameters\")\n\tvoid getUrlWithTestDatabase(EmbeddedDatabaseConnection connection, String expectUrl) {\n\t\tassertThat(connection.getUrl(\"test-database\")).isEqualTo(expectUrl);\n\t}\n\n\t@Test\n\tvoid getReturnsH2ByDefault() {\n\t\tassertThat(EmbeddedDatabaseConnection.get(EmbeddedDatabaseConnectionTests.class.getClassLoader()))\n\t\t\t.isEqualTo(EmbeddedDatabaseConnection.H2);\n\t}\n\n\t@Test\n\tvoid getWhenH2IsNotOnTheClasspathReturnsNone() {\n\t\tassertThat(EmbeddedDatabaseConnection.get(new HidePackagesClassLoader(\"io.r2dbc.h2\")))\n\t\t\t.isEqualTo(EmbeddedDatabaseConnection.NONE);\n\t}\n\n\t@Test\n\tvoid whenH2IsInMemoryThenIsEmbeddedReturnsTrue() {\n\t\tassertThat(EmbeddedDatabaseConnection\n\t\t\t.isEmbedded(ConnectionFactoryBuilder.withUrl(\"r2dbc:h2:mem:///\" + UUID.randomUUID()).build())).isTrue();\n\t}\n\n\t@Test\n\tvoid whenH2IsUsingFileStorageThenIsEmbeddedReturnsFalse() {\n\t\tassertThat(EmbeddedDatabaseConnection\n\t\t\t.isEmbedded(ConnectionFactoryBuilder.withUrl(\"r2dbc:h2:file:///\" + UUID.randomUUID()).build())).isFalse();\n\t}\n\n\t@Test\n\tvoid whenPoolIsBasedByH2InMemoryThenIsEmbeddedReturnsTrue() {\n\t\tassertThat(EmbeddedDatabaseConnection\n\t\t\t.isEmbedded(ConnectionFactoryBuilder.withUrl(\"r2dbc:pool:h2:mem:///\" + UUID.randomUUID()).build()))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid whenPoolIsBasedByH2WithFileStorageThenIsEmbeddedReturnsFalse() {\n\t\tassertThat(EmbeddedDatabaseConnection\n\t\t\t.isEmbedded(ConnectionFactoryBuilder.withUrl(\"r2dbc:pool:h2:file:///\" + UUID.randomUUID()).build()))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid whenConnectionFactoryIsNotOptionsCapableThenIsEmbeddedThrows() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> EmbeddedDatabaseConnection\n\t\t\t\t.isEmbedded(ConnectionFactories.get(\"r2dbc:pool:h2:mem:///\" + UUID.randomUUID())))\n\t\t\t.withMessage(\"Cannot determine database's type as ConnectionFactory is not options-capable. To be \"\n\t\t\t\t\t+ \"options-capable, a ConnectionFactory should be created with \"\n\t\t\t\t\t+ \"org.springframework.boot.r2dbc.ConnectionFactoryBuilder\");\n\t}\n\n\tstatic Stream<Arguments> urlParameters() {\n\t\treturn Stream.of(Arguments.arguments(EmbeddedDatabaseConnection.NONE, null),\n\t\t\t\tArguments.arguments(EmbeddedDatabaseConnection.H2,\n\t\t\t\t\t\t\"r2dbc:h2:mem:///test-database?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\"));\n\t}\n\n\tprivate static class HidePackagesClassLoader extends URLClassLoader {\n\n\t\tprivate final String[] hiddenPackages;\n\n\t\tHidePackagesClassLoader(String... hiddenPackages) {\n\t\t\tsuper(new URL[0], EmbeddedDatabaseConnectionTests.HidePackagesClassLoader.class.getClassLoader());\n\t\t\tthis.hiddenPackages = hiddenPackages;\n\t\t}\n\n\t\t@Override\n\t\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\t\tif (Arrays.stream(this.hiddenPackages).anyMatch(name::startsWith)) {\n\t\t\t\tthrow new ClassNotFoundException();\n\t\t\t}\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/ConnectionFactoryBeanCreationFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConnectionFactoryBeanCreationFailureAnalyzer}.\n *\n * @author Mark Paluch\n */\nclass ConnectionFactoryBeanCreationFailureAnalyzerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\tvoid failureAnalysisIsPerformed() {\n\t\tFailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);\n\t\tassertThat(failureAnalysis).isNotNull();\n\t\tassertThat(failureAnalysis.getDescription()).contains(\"'url' attribute is not specified\",\n\t\t\t\t\"no embedded database could be configured\");\n\t\tassertThat(failureAnalysis.getAction()).contains(\n\t\t\t\t\"If you want an embedded database (H2), please put it on the classpath\",\n\t\t\t\t\"If you have database settings to be loaded from a particular profile you may need to activate it\",\n\t\t\t\t\"(no profiles are currently active)\");\n\t}\n\n\t@Test\n\tvoid failureAnalysisIsPerformedWithActiveProfiles() {\n\t\tthis.environment.setActiveProfiles(\"first\", \"second\");\n\t\tFailureAnalysis failureAnalysis = performAnalysis(TestConfiguration.class);\n\t\tassertThat(failureAnalysis).isNotNull();\n\t\tassertThat(failureAnalysis.getAction()).contains(\"(the profiles first,second are currently active)\");\n\t}\n\n\tprivate @Nullable FailureAnalysis performAnalysis(Class<?> configuration) {\n\t\tBeanCreationException failure = createFailure(configuration);\n\t\tassertThat(failure).isNotNull();\n\t\tConnectionFactoryBeanCreationFailureAnalyzer failureAnalyzer = new ConnectionFactoryBeanCreationFailureAnalyzer(\n\t\t\t\tthis.environment);\n\t\treturn failureAnalyzer.analyze(failure);\n\t}\n\n\tprivate BeanCreationException createFailure(Class<?> configuration) {\n\t\ttry {\n\t\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\t\tcontext.setClassLoader(new FilteredClassLoader(\"io.r2dbc.h2\", \"io.r2dbc.pool\"));\n\t\t\tcontext.setEnvironment(this.environment);\n\t\t\tcontext.register(configuration);\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (BeanCreationException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(R2dbcAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/MissingR2dbcPoolDependencyFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MissingR2dbcPoolDependencyFailureAnalyzer}\n *\n * @author Andy Wilkinson\n */\nclass MissingR2dbcPoolDependencyFailureAnalyzerTests {\n\n\tprivate final MissingR2dbcPoolDependencyFailureAnalyzer failureAnalyzer = new MissingR2dbcPoolDependencyFailureAnalyzer();\n\n\t@Test\n\tvoid analyzeWhenDifferentFailureShouldReturnNull() {\n\t\tassertThat(this.failureAnalyzer.analyze(new Exception())).isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenMissingR2dbcPoolDependencyShouldReturnAnalysis() {\n\t\tassertThat(this.failureAnalyzer.analyze(new MissingR2dbcPoolDependencyException())).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/MultipleConnectionPoolConfigurationsFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MultipleConnectionPoolConfigurationsFailureAnalyzer}\n *\n * @author Andy Wilkinson\n */\nclass MultipleConnectionPoolConfigurationsFailureAnalyzerTests {\n\n\tprivate final MultipleConnectionPoolConfigurationsFailureAnalyzer failureAnalyzer = new MultipleConnectionPoolConfigurationsFailureAnalyzer();\n\n\t@Test\n\tvoid analyzeWhenDifferentFailureShouldReturnNull() {\n\t\tassertThat(this.failureAnalyzer.analyze(new Exception())).isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenMultipleConnectionPoolConfigurationsShouldReturnAnalysis() {\n\t\tassertThat(this.failureAnalyzer.analyze(new MultipleConnectionPoolConfigurationsException())).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/NoConnectionFactoryBeanFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryProvider;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.test.context.FilteredClassLoader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NoConnectionFactoryBeanFailureAnalyzer}.\n *\n * @author Andy Wilkinson\n */\nclass NoConnectionFactoryBeanFailureAnalyzerTests {\n\n\t@Test\n\tvoid analyzeWhenNotNoSuchBeanDefinitionExceptionShouldReturnNull() {\n\t\tassertThat(new NoConnectionFactoryBeanFailureAnalyzer().analyze(new Exception())).isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenNoSuchBeanDefinitionExceptionForDifferentTypeShouldReturnNull() {\n\t\tassertThat(\n\t\t\t\tnew NoConnectionFactoryBeanFailureAnalyzer().analyze(new NoSuchBeanDefinitionException(String.class)))\n\t\t\t.isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenNoSuchBeanDefinitionExceptionButProviderIsAvailableShouldReturnNull() {\n\t\tassertThat(new NoConnectionFactoryBeanFailureAnalyzer()\n\t\t\t.analyze(new NoSuchBeanDefinitionException(ConnectionFactory.class))).isNull();\n\t}\n\n\t@Test\n\tvoid analyzeWhenNoSuchBeanDefinitionExceptionAndNoProviderShouldAnalyze() {\n\t\tassertThat(new NoConnectionFactoryBeanFailureAnalyzer(\n\t\t\t\tnew FilteredClassLoader((\"META-INF/services/\" + ConnectionFactoryProvider.class.getName())::equals))\n\t\t\t.analyze(new NoSuchBeanDefinitionException(ConnectionFactory.class))).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.time.Duration;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport io.r2dbc.h2.H2ConnectionFactory;\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.PoolMetrics;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.ConnectionFactoryProvider;\nimport io.r2dbc.spi.Option;\nimport io.r2dbc.spi.Wrapped;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.InstanceOfAssertFactory;\nimport org.assertj.core.api.ObjectAssert;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;\nimport org.springframework.boot.r2dbc.OptionsCapableConnectionFactory;\nimport org.springframework.boot.r2dbc.SimpleConnectionFactoryProvider.SimpleTestConnectionFactory;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link R2dbcAutoConfiguration}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass R2dbcAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class));\n\n\t@Test\n\tvoid configureWithUrlCreateConnectionPoolByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class);\n\t\t\t\tassertThat(context.getBean(ConnectionPool.class)).extracting(ConnectionPool::unwrap)\n\t\t\t\t\t.satisfies((connectionFactory) -> assertThat(connectionFactory)\n\t\t\t\t\t\t.asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t\t.extracting(Wrapped::unwrap)\n\t\t\t\t\t\t.isExactlyInstanceOf(H2ConnectionFactory.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithUrlAndPoolPropertiesApplyProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName(),\n\t\t\t\t\t\"spring.r2dbc.pool.max-size=15\", \"spring.r2dbc.pool.max-acquire-time=3m\",\n\t\t\t\t\t\"spring.r2dbc.pool.acquire-retry=5\", \"spring.r2dbc.pool.min-idle=1\",\n\t\t\t\t\t\"spring.r2dbc.pool.max-validation-time=1s\", \"spring.r2dbc.pool.initial-size=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(ConnectionPool.class)\n\t\t\t\t\t.hasSingleBean(R2dbcProperties.class);\n\t\t\t\tConnectionPool connectionPool = context.getBean(ConnectionPool.class);\n\t\t\t\tconnectionPool.warmup().block();\n\t\t\t\ttry {\n\t\t\t\t\tPoolMetrics poolMetrics = connectionPool.getMetrics().get();\n\t\t\t\t\tassertThat(poolMetrics.idleSize()).isEqualTo(1);\n\t\t\t\t\tassertThat(poolMetrics.getMaxAllocatedSize()).isEqualTo(15);\n\t\t\t\t\tassertThat(connectionPool).hasFieldOrPropertyWithValue(\"maxAcquireTime\", Duration.ofMinutes(3));\n\t\t\t\t\tassertThat(connectionPool).hasFieldOrPropertyWithValue(\"maxValidationTime\", Duration.ofSeconds(1));\n\t\t\t\t\tassertThat(connectionPool).extracting(\"create\").satisfies((mono) -> {\n\t\t\t\t\t\tassertThat(mono.getClass().getName()).endsWith(\"MonoRetry\");\n\t\t\t\t\t\tassertThat(mono).hasFieldOrPropertyWithValue(\"times\", 5L);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tconnectionPool.close().block();\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithUrlAndDefaultDoNotOverrideDefaultTimeouts() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t\t.hasSingleBean(ConnectionPool.class)\n\t\t\t\t\t.hasSingleBean(R2dbcProperties.class);\n\t\t\t\tConnectionPool connectionPool = context.getBean(ConnectionPool.class);\n\t\t\t\tassertThat(connectionPool).hasFieldOrPropertyWithValue(\"maxAcquireTime\", Duration.ofMillis(-1));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithUrlPoolAndPoolPropertiesFails() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:pool:h2:mem:///\" + randomDatabaseName() + \"?maxSize=12\",\n\t\t\t\t\t\"spring.r2dbc.pool.max-size=15\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MultipleConnectionPoolConfigurationsException.class));\n\t}\n\n\t@Test\n\tvoid configureWithUrlPoolAndPropertyBasedPoolingDisabledFails() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:pool:h2:mem:///\" + randomDatabaseName() + \"?maxSize=12\",\n\t\t\t\t\t\"spring.r2dbc.pool.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MultipleConnectionPoolConfigurationsException.class));\n\t}\n\n\t@Test\n\tvoid configureWithUrlPoolAndNoPoolPropertiesCreatesPool() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:pool:h2:mem:///\" + randomDatabaseName() + \"?maxSize=12\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class);\n\t\t\t\tConnectionPool connectionPool = context.getBean(ConnectionPool.class);\n\t\t\t\tassertThat(connectionPool.getMetrics().get().getMaxAllocatedSize()).isEqualTo(12);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithPoolEnabledCreateConnectionPool() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=true\",\n\t\t\t\t\t\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName()\n\t\t\t\t\t\t\t+ \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t.hasSingleBean(ConnectionPool.class));\n\t}\n\n\t@Test\n\tvoid configureWithPoolDisabledCreateGenericConnectionFactory() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=false\",\n\t\t\t\t\t\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName()\n\t\t\t\t\t\t\t+ \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).doesNotHaveBean(ConnectionPool.class);\n\t\t\t\tassertThat(context.getBean(ConnectionFactory.class))\n\t\t\t\t\t.asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(Wrapped<ConnectionFactory>::unwrap)\n\t\t\t\t\t.isExactlyInstanceOf(H2ConnectionFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithoutPoolInvokeOptionCustomizer() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=false\", \"spring.r2dbc.url:r2dbc:simple://host/database\")\n\t\t\t.withUserConfiguration(CustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).doesNotHaveBean(ConnectionPool.class);\n\t\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory).asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(OptionsCapableConnectionFactory::getOptions)\n\t\t\t\t\t.satisfies((options) -> assertThat(options.getRequiredValue(Option.valueOf(\"customized\")))\n\t\t\t\t\t\t.isEqualTo(Boolean.TRUE));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithPoolInvokeOptionCustomizer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.url:r2dbc:simple://host/database\")\n\t\t\t.withUserConfiguration(CustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class);\n\t\t\t\tConnectionFactory pool = context.getBean(ConnectionFactory.class);\n\t\t\t\tConnectionFactory connectionFactory = ((ConnectionPool) pool).unwrap();\n\t\t\t\tassertThat(connectionFactory).asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(OptionsCapableConnectionFactory::getOptions)\n\t\t\t\t\t.satisfies((options) -> assertThat(options.getRequiredValue(Option.valueOf(\"customized\")))\n\t\t\t\t\t\t.isEqualTo(Boolean.TRUE));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithInvalidUrlThrowsAppropriateException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.url:r2dbc:not-going-to-work\")\n\t\t\t.run((context) -> assertThat(context).getFailure().isInstanceOf(BeanCreationException.class));\n\t}\n\n\t@Test\n\tvoid configureWithoutSpringJdbcCreateConnectionFactory() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.pool.enabled=false\", \"spring.r2dbc.url:r2dbc:simple://foo\")\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.jdbc\"))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(ConnectionFactory.class))\n\t\t\t\t\t.asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(Wrapped<ConnectionFactory>::unwrap)\n\t\t\t\t\t.isExactlyInstanceOf(SimpleTestConnectionFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithoutPoolShouldApplyAdditionalProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=false\", \"spring.r2dbc.url:r2dbc:simple://foo\",\n\t\t\t\t\t\"spring.r2dbc.properties.test=value\", \"spring.r2dbc.properties.another=2\")\n\t\t\t.run((context) -> {\n\t\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionFactory.class);\n\t\t\t\tassertThat(connectionFactory).asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(OptionsCapableConnectionFactory::getOptions)\n\t\t\t\t\t.satisfies((options) -> {\n\t\t\t\t\t\tassertThat(options.getRequiredValue(Option.<String>valueOf(\"test\"))).isEqualTo(\"value\");\n\t\t\t\t\t\tassertThat(options.getRequiredValue(Option.<String>valueOf(\"another\"))).isEqualTo(\"2\");\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider\",\n\t\t\tcontent = \"org.springframework.boot.autoconfigure.r2dbc.SimpleConnectionFactoryProvider\")\n\t@ForkedClassPath\n\tvoid configureWithPoolShouldApplyAdditionalProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:simple://foo\", \"spring.r2dbc.properties.test=value\",\n\t\t\t\t\t\"spring.r2dbc.properties.another=2\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(ConnectionPool.class);\n\t\t\t\tConnectionFactory connectionFactory = context.getBean(ConnectionPool.class).unwrap();\n\t\t\t\tassertThat(connectionFactory).asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(OptionsCapableConnectionFactory::getOptions)\n\t\t\t\t\t.satisfies((options) -> {\n\t\t\t\t\t\tassertThat(options.getRequiredValue(Option.<String>valueOf(\"test\"))).isEqualTo(\"value\");\n\t\t\t\t\t\tassertThat(options.getRequiredValue(Option.<String>valueOf(\"another\"))).isEqualTo(\"2\");\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithoutUrlShouldCreateEmbeddedConnectionPoolByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t.hasSingleBean(ConnectionPool.class));\n\t}\n\n\t@Test\n\tvoid configureWithoutUrlAndPollPoolDisabledCreateGenericConnectionFactory() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.pool.enabled=false\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).doesNotHaveBean(ConnectionPool.class);\n\t\t\tassertThat(context.getBean(ConnectionFactory.class))\n\t\t\t\t.asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t.extracting(Wrapped<ConnectionFactory>::unwrap)\n\t\t\t\t.isExactlyInstanceOf(H2ConnectionFactory.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithoutUrlAndSprigJdbcCreateEmbeddedConnectionFactory() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.jdbc\"))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t.hasSingleBean(ConnectionPool.class));\n\t}\n\n\t@Test\n\tvoid configureWithoutUrlAndEmbeddedCandidateFails() {\n\t\tthis.contextRunner.withClassLoader(new DisableEmbeddedDatabaseClassLoader()).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.hasMessageContaining(\"Failed to determine a suitable R2DBC Connection URL\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithoutUrlAndNoConnectionFactoryProviderBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(\n\t\t\t\t\tnew FilteredClassLoader((\"META-INF/services/\" + ConnectionFactoryProvider.class.getName())::equals))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(R2dbcAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid configureWithDataSourceAutoConfigurationDoesNotCreateDataSource() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t.doesNotHaveBean(DataSource.class));\n\t}\n\n\t@Test\n\tvoid databaseClientIsConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class).hasSingleBean(DatabaseClient.class);\n\t\t\t\tassertThat(context.getBean(DatabaseClient.class).getConnectionFactory())\n\t\t\t\t\t.isSameAs(context.getBean(ConnectionFactory.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid databaseClientBacksOffIfSpringR2dbcIsNotAvailable() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.r2dbc\"))\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConnectionFactory.class)\n\t\t\t\t.doesNotHaveBean(DatabaseClient.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsIfAvailable() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.r2dbc.pool.enabled=false\")\n\t\t\t.withUserConfiguration(ConnectionDetailsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tOptionsCapableConnectionFactory connectionFactory = context\n\t\t\t\t\t.getBean(OptionsCapableConnectionFactory.class);\n\t\t\t\tConnectionFactoryOptions options = connectionFactory.getOptions();\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"postgresql\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.HOST)).isEqualTo(\"postgres.example.com\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.PORT)).isEqualTo(12345);\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"database-1\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.USER)).isEqualTo(\"user-1\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"password-1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithUsernamePasswordAndUrlWithoutUserInfoUsesUsernameAndPassword() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=false\",\n\t\t\t\t\t\"spring.r2dbc.url:r2dbc:postgresql://postgres.example.com:4321/db\", \"spring.r2dbc.username=alice\",\n\t\t\t\t\t\"spring.r2dbc.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tOptionsCapableConnectionFactory connectionFactory = context\n\t\t\t\t\t.getBean(OptionsCapableConnectionFactory.class);\n\t\t\t\tConnectionFactoryOptions options = connectionFactory.getOptions();\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"postgresql\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.HOST)).isEqualTo(\"postgres.example.com\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.PORT)).isEqualTo(4321);\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"db\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.USER)).isEqualTo(\"alice\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithUsernamePasswordAndUrlWithUserInfoUsesUserInfo() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=false\",\n\t\t\t\t\t\"spring.r2dbc.url:r2dbc:postgresql://bob:password@postgres.example.com:9876/db\",\n\t\t\t\t\t\"spring.r2dbc.username=alice\", \"spring.r2dbc.password=secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tOptionsCapableConnectionFactory connectionFactory = context\n\t\t\t\t\t.getBean(OptionsCapableConnectionFactory.class);\n\t\t\t\tConnectionFactoryOptions options = connectionFactory.getOptions();\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"postgresql\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.HOST)).isEqualTo(\"postgres.example.com\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.PORT)).isEqualTo(9876);\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"db\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.USER)).isEqualTo(\"bob\");\n\t\t\t\tassertThat(options.getValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"password\");\n\t\t\t});\n\t}\n\n\tprivate <T> InstanceOfAssertFactory<T, ObjectAssert<T>> type(Class<T> type) {\n\t\treturn InstanceOfAssertFactories.type(type);\n\t}\n\n\tprivate String randomDatabaseName() {\n\t\treturn \"testdb-\" + UUID.randomUUID();\n\t}\n\n\tprivate static class DisableEmbeddedDatabaseClassLoader extends URLClassLoader {\n\n\t\tDisableEmbeddedDatabaseClassLoader() {\n\t\t\tsuper(new URL[0], DisableEmbeddedDatabaseClassLoader.class.getClassLoader());\n\t\t}\n\n\t\t@Override\n\t\tprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\t\tfor (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) {\n\t\t\t\tif (name.equals(candidate.getDriverClassName())) {\n\t\t\t\t\tthrow new ClassNotFoundException();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.loadClass(name, resolve);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactoryOptionsBuilderCustomizer customizer() {\n\t\t\treturn (builder) -> builder.option(Option.valueOf(\"customized\"), true);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionDetailsConfiguration {\n\n\t\t@Bean\n\t\tR2dbcConnectionDetails r2dbcConnectionDetails() {\n\t\t\treturn new R2dbcConnectionDetails() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\t\t\t\treturn ConnectionFactoryOptions\n\t\t\t\t\t\t.parse(\"r2dbc:postgresql://user-1:password-1@postgres.example.com:12345/database-1\");\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcAutoConfigurationWithoutConnectionPoolTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.util.UUID;\n\nimport io.r2dbc.h2.H2ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.Wrapped;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.InstanceOfAssertFactory;\nimport org.assertj.core.api.ObjectAssert;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.r2dbc.OptionsCapableConnectionFactory;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link R2dbcAutoConfiguration} without the {@code io.r2dbc:r2dbc-pool}\n * dependency.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"r2dbc-pool-*.jar\")\nclass R2dbcAutoConfigurationWithoutConnectionPoolTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class));\n\n\t@Test\n\tvoid configureWithoutR2dbcPoolCreateGenericConnectionFactory() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName()\n\t\t\t\t\t+ \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tassertThat(context.getBean(ConnectionFactory.class))\n\t\t\t\t\t.asInstanceOf(type(OptionsCapableConnectionFactory.class))\n\t\t\t\t\t.extracting(Wrapped<ConnectionFactory>::unwrap)\n\t\t\t\t\t.isExactlyInstanceOf(H2ConnectionFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configureWithoutR2dbcPoolAndPoolEnabledShouldFail() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.pool.enabled=true\",\n\t\t\t\t\t\"spring.r2dbc.url:r2dbc:h2:mem:///\" + randomDatabaseName()\n\t\t\t\t\t\t\t+ \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MissingR2dbcPoolDependencyException.class));\n\t}\n\n\t@Test\n\tvoid configureWithoutR2dbcPoolAndPoolUrlShouldFail() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.r2dbc.url:r2dbc:pool:h2:mem:///\" + randomDatabaseName()\n\t\t\t\t\t+ \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MissingR2dbcPoolDependencyException.class));\n\t}\n\n\tprivate <T> InstanceOfAssertFactory<T, ObjectAssert<T>> type(Class<T> type) {\n\t\treturn InstanceOfAssertFactories.type(type);\n\t}\n\n\tprivate String randomDatabaseName() {\n\t\treturn \"testdb-\" + UUID.randomUUID();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcInitializationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.r2dbc.init.R2dbcScriptDatabaseInitializer;\nimport org.springframework.boot.sql.autoconfigure.init.ApplicationScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.r2dbc.connection.init.DatabasePopulator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link R2dbcInitializationAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass R2dbcInitializationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(R2dbcInitializationAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.r2dbc.generate-unique-name:true\");\n\n\t@Test\n\tvoid whenNoConnectionFactoryIsAvailableThenAutoConfigurationBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid whenConnectionFactoryIsAvailableThenR2dbcInitializerIsAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(R2dbcScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid whenConnectionFactoryIsAvailableAndModeIsNeverThenInitializerIsNotAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.sql.init.mode:never\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class));\n\t}\n\n\t@Test\n\tvoid whenAnSqlInitializerIsDefinedThenInitializerIsNotAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(SqlDatabaseInitializerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(AbstractScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenAnInitializerIsDefinedThenSqlInitializerIsStillAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DatabaseInitializerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ApplicationScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenBeanIsAnnotatedAsDependingOnDatabaseInitializationThenItDependsOnR2dbcScriptDatabaseInitializer() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DependsOnInitializedDatabaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(\n\t\t\t\t\t\t\"r2dbcInitializationAutoConfigurationTests.DependsOnInitializedDatabaseConfiguration\");\n\t\t\t\tassertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder(\"r2dbcScriptDatabaseInitializer\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenBeanIsAnnotatedAsDependingOnDatabaseInitializationThenItDependsOnDataSourceScriptDatabaseInitializer() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(DependsOnInitializedDatabaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(\n\t\t\t\t\t\t\"r2dbcInitializationAutoConfigurationTests.DependsOnInitializedDatabaseConfiguration\");\n\t\t\t\tassertThat(beanDefinition.getDependsOn()).containsExactlyInAnyOrder(\"r2dbcScriptDatabaseInitializer\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenAConnectionFactoryIsAvailableAndSpringR2dbcIsNotThenAutoConfigurationBacksOff() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(DatabasePopulator.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ConnectionFactory.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(AbstractScriptDatabaseInitializer.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SqlDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tApplicationScriptDatabaseInitializer customInitializer() {\n\t\t\treturn mock(ApplicationScriptDatabaseInitializer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tR2dbcScriptDatabaseInitializer customInitializer() {\n\t\t\treturn new R2dbcScriptDatabaseInitializer(mock(ConnectionFactory.class),\n\t\t\t\t\tnew DatabaseInitializationSettings()) {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void runScripts(Scripts scripts) {\n\t\t\t\t\t// No-op\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected boolean isEmbeddedDatabase() {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@DependsOnDatabaseInitialization\n\tstatic class DependsOnInitializedDatabaseConfiguration {\n\n\t\tDependsOnInitializedDatabaseConfiguration() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcProxyAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.r2dbc.ConnectionFactoryBuilder;\nimport org.springframework.boot.r2dbc.ConnectionFactoryDecorator;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link R2dbcProxyAutoConfiguration}.\n *\n * @author Tadaya Tsuyukubo\n * @author Moritz Halbritter\n */\nclass R2dbcProxyAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(R2dbcProxyAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyConnectionFactoryDecorator() {\n\t\tthis.runner.run((context) -> assertThat(context).hasSingleBean(ConnectionFactoryDecorator.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfR2dbcSpiIsNotOnClasspath() {\n\t\tthis.runner.withClassLoader(new FilteredClassLoader(\"io.r2dbc.spi\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactoryDecorator.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfR2dbcProxyIsNotOnClasspath() {\n\t\tthis.runner.withClassLoader(new FilteredClassLoader(\"io.r2dbc.proxy\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactoryDecorator.class));\n\t}\n\n\t@Test\n\tvoid shouldApplyCustomizers() {\n\t\tthis.runner.withUserConfiguration(ProxyConnectionFactoryCustomizerConfig.class).run((context) -> {\n\t\t\tConnectionFactoryDecorator decorator = context.getBean(ConnectionFactoryDecorator.class);\n\t\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder\n\t\t\t\t.withUrl(\"r2dbc:h2:mem:///\" + UUID.randomUUID())\n\t\t\t\t.build();\n\t\t\tdecorator.decorate(connectionFactory);\n\t\t\tassertThat(context.getBean(ProxyConnectionFactoryCustomizerConfig.class).called).containsExactly(\"first\",\n\t\t\t\t\t\"second\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class ProxyConnectionFactoryCustomizerConfig {\n\n\t\tprivate final List<String> called = new ArrayList<>();\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tProxyConnectionFactoryCustomizer first() {\n\t\t\treturn (builder) -> this.called.add(\"first\");\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tProxyConnectionFactoryCustomizer second() {\n\t\t\treturn (builder) -> this.called.add(\"second\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/R2dbcTransactionManagerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.TransactionDefinition;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.ReactiveTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.reactive.TransactionSynchronizationManager;\nimport org.springframework.transaction.reactive.TransactionalOperator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link R2dbcTransactionManagerAutoConfiguration}.\n *\n * @author Mark Paluch\n * @author Oliver Drotbohm\n */\nclass R2dbcTransactionManagerAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(R2dbcTransactionManagerAutoConfiguration.class, TransactionAutoConfiguration.class));\n\n\t@Test\n\tvoid noTransactionManager() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveTransactionManager.class));\n\t}\n\n\t@Test\n\tvoid singleTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(SingleConnectionFactoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(TransactionalOperator.class)\n\t\t\t\t.hasSingleBean(ReactiveTransactionManager.class));\n\t}\n\n\t@Test\n\tvoid transactionManagerEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(SingleConnectionFactoryConfiguration.class, BaseConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTransactionalService bean = context.getBean(TransactionalService.class);\n\t\t\t\tbean.isTransactionActive()\n\t\t\t\t\t.as(StepVerifier::create)\n\t\t\t\t\t.expectNext(true)\n\t\t\t\t\t.expectComplete()\n\t\t\t\t\t.verify(Duration.ofSeconds(30));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SingleConnectionFactoryConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory connectionFactory() {\n\t\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\t\tConnection connection = mock(Connection.class);\n\t\t\tgiven(connectionFactory.create()).willAnswer((invocation) -> Mono.just(connection));\n\t\t\tgiven(connection.beginTransaction(any(TransactionDefinition.class))).willReturn(Mono.empty());\n\t\t\tgiven(connection.commitTransaction()).willReturn(Mono.empty());\n\t\t\tgiven(connection.close()).willReturn(Mono.empty());\n\t\t\treturn connectionFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableTransactionManagement\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tTransactionalService transactionalService() {\n\t\t\treturn new TransactionalServiceImpl();\n\t\t}\n\n\t}\n\n\tinterface TransactionalService {\n\n\t\t@Transactional\n\t\tMono<Boolean> isTransactionActive();\n\n\t}\n\n\tstatic class TransactionalServiceImpl implements TransactionalService {\n\n\t\t@Override\n\t\tpublic Mono<Boolean> isTransactionActive() {\n\t\t\treturn TransactionSynchronizationManager.forCurrentTransaction()\n\t\t\t\t.map(TransactionSynchronizationManager::isActualTransactionActive);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/health/ConnectionFactoryHealthContributorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.health;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.r2dbc.health.ConnectionFactoryHealthIndicator;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link ConnectionFactoryHealthContributorAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass ConnectionFactoryHealthContributorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ConnectionFactoryHealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class));\n\n\t@Test\n\tvoid runShouldCreateIndicator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ConnectionFactoryHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWithNoConnectionFactoryShouldNotCreateIndicator() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactoryHealthIndicator.class));\n\t}\n\n\t@Test\n\tvoid runWhenDisabledShouldNotCreateIndicator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.health.r2dbc.enabled:false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ConnectionFactoryHealthIndicator.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/metrics/ConnectionPoolMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.metrics;\n\nimport java.util.Collections;\nimport java.util.UUID;\n\nimport io.micrometer.core.instrument.Meter;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.r2dbc.h2.CloseableConnectionFactory;\nimport io.r2dbc.h2.H2ConnectionFactory;\nimport io.r2dbc.h2.H2ConnectionOption;\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.ConnectionPoolConfiguration;\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryMetadata;\nimport io.r2dbc.spi.Wrapped;\nimport org.junit.jupiter.api.Test;\nimport org.reactivestreams.Publisher;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConnectionPoolMetricsAutoConfiguration}.\n *\n * @author Tadaya Tsuyukubo\n * @author Stephane Nicoll\n */\nclass ConnectionPoolMetricsAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.r2dbc.generate-unique-name=true\", \"management.metrics.use-global-registry=false\")\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(ConnectionPoolMetricsAutoConfiguration.class, MetricsAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguredDataSourceIsInstrumented() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class)).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.find(\"r2dbc.pool.acquired\").gauges()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredDataSourceExposedAsConnectionFactoryTypeIsInstrumented() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.r2dbc.url:r2dbc:pool:h2:mem:///name?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t\t.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"r2dbc.pool.acquired\").gauges()).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionPoolInstrumentationCanBeDisabled() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(R2dbcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.enable.r2dbc=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"r2dbc.pool.acquired\").gauge()).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid connectionPoolExposedAsConnectionFactoryTypeIsInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(ConnectionFactoryConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.find(\"r2dbc.pool.acquired\").gauges()).extracting(Meter::getId)\n\t\t\t\t.extracting((id) -> id.getTag(\"name\"))\n\t\t\t\t.containsExactly(\"testConnectionPool\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid wrappedConnectionPoolExposedAsConnectionFactoryTypeIsInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(WrappedConnectionPoolConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.find(\"r2dbc.pool.acquired\").gauges()).extracting(Meter::getId)\n\t\t\t\t.extracting((id) -> id.getTag(\"name\"))\n\t\t\t\t.containsExactly(\"wrappedConnectionPool\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid allConnectionPoolsCanBeInstrumented() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleConnectionPoolsConfiguration.class).run((context) -> {\n\t\t\tMeterRegistry registry = context.getBean(MeterRegistry.class);\n\t\t\tassertThat(registry.find(\"r2dbc.pool.acquired\").meters()).map((meter) -> meter.getId().getTag(\"name\"))\n\t\t\t\t.containsOnly(\"standardPool\", \"nonDefaultPool\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tSimpleMeterRegistry registry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConnectionFactoryConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory testConnectionPool() {\n\t\t\treturn new ConnectionPool(\n\t\t\t\t\tConnectionPoolConfiguration.builder(H2ConnectionFactory.inMemory(\"db-\" + UUID.randomUUID(), \"sa\",\n\t\t\t\t\t\t\t\"\", Collections.singletonMap(H2ConnectionOption.DB_CLOSE_DELAY, \"-1\")))\n\t\t\t\t\t\t.build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WrappedConnectionPoolConfiguration {\n\n\t\t@Bean\n\t\tConnectionFactory wrappedConnectionPool() {\n\t\t\treturn new Wrapper(new ConnectionPool(\n\t\t\t\t\tConnectionPoolConfiguration.builder(H2ConnectionFactory.inMemory(\"db-\" + UUID.randomUUID(), \"sa\",\n\t\t\t\t\t\t\t\"\", Collections.singletonMap(H2ConnectionOption.DB_CLOSE_DELAY, \"-1\")))\n\t\t\t\t\t\t.build()));\n\t\t}\n\n\t\tstatic class Wrapper implements ConnectionFactory, Wrapped<ConnectionFactory> {\n\n\t\t\tprivate final ConnectionFactory delegate;\n\n\t\t\tWrapper(ConnectionFactory delegate) {\n\t\t\t\tthis.delegate = delegate;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic ConnectionFactory unwrap() {\n\t\t\t\treturn this.delegate;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Publisher<? extends Connection> create() {\n\t\t\t\treturn this.delegate.create();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic ConnectionFactoryMetadata getMetadata() {\n\t\t\t\treturn this.delegate.getMetadata();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipleConnectionPoolsConfiguration {\n\n\t\t@Bean\n\t\tCloseableConnectionFactory connectionFactory() {\n\t\t\treturn H2ConnectionFactory.inMemory(\"db-\" + UUID.randomUUID(), \"sa\", \"\",\n\t\t\t\t\tCollections.singletonMap(H2ConnectionOption.DB_CLOSE_DELAY, \"-1\"));\n\t\t}\n\n\t\t@Bean\n\t\tConnectionPool standardPool(ConnectionFactory connectionFactory) {\n\t\t\treturn new ConnectionPool(ConnectionPoolConfiguration.builder(connectionFactory).build());\n\t\t}\n\n\t\t@Bean(defaultCandidate = false)\n\t\tConnectionPool nonDefaultPool(ConnectionFactory connectionFactory) {\n\t\t\treturn new ConnectionPool(ConnectionPoolConfiguration.builder(connectionFactory).build());\n\t\t}\n\n\t\t@Bean(autowireCandidate = false)\n\t\tConnectionPool nonAutowirePool(ConnectionFactory connectionFactory) {\n\t\t\treturn new ConnectionPool(ConnectionPoolConfiguration.builder(connectionFactory).build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/autoconfigure/observation/R2dbcObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.autoconfigure.observation;\n\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.r2dbc.spi.ConnectionFactory;\nimport org.awaitility.Awaitility;\nimport org.hamcrest.Matchers;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.r2dbc.ConnectionFactoryBuilder;\nimport org.springframework.boot.r2dbc.ConnectionFactoryDecorator;\nimport org.springframework.boot.r2dbc.autoconfigure.ProxyConnectionFactoryCustomizer;\nimport org.springframework.boot.r2dbc.autoconfigure.R2dbcProxyAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link R2dbcObservationAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Tadaya Tsuyukubo\n */\nclass R2dbcObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner runnerWithoutObservationRegistry = new ApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(R2dbcProxyAutoConfiguration.class, R2dbcObservationAutoConfiguration.class));\n\n\tprivate final ApplicationContextRunner runner = this.runnerWithoutObservationRegistry\n\t\t.withBean(ObservationRegistry.class, ObservationRegistry::create);\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfObservationRegistryIsNotPresent() {\n\t\tthis.runnerWithoutObservationRegistry\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ProxyConnectionFactoryCustomizer.class));\n\t}\n\n\t@Test\n\tvoid decoratorShouldReportObservations() {\n\t\tthis.runner.run((context) -> {\n\t\t\tCapturingObservationHandler handler = registerCapturingObservationHandler(context);\n\t\t\tConnectionFactoryDecorator decorator = context.getBean(ConnectionFactoryDecorator.class);\n\t\t\tassertThat(decorator).isNotNull();\n\t\t\tConnectionFactory connectionFactory = ConnectionFactoryBuilder\n\t\t\t\t.withUrl(\"r2dbc:h2:mem:///\" + UUID.randomUUID())\n\t\t\t\t.build();\n\t\t\tConnectionFactory decorated = decorator.decorate(connectionFactory);\n\t\t\tMono.from(decorated.create())\n\t\t\t\t.flatMap((c) -> Mono.from(c.createStatement(\"SELECT 1;\").execute())\n\t\t\t\t\t.flatMap((ignore) -> Mono.from(c.close())))\n\t\t\t\t.block();\n\t\t\tassertThat(handler.awaitContext().getName()).as(\"context.getName()\").isEqualTo(\"r2dbc.query\");\n\t\t});\n\t}\n\n\tprivate static CapturingObservationHandler registerCapturingObservationHandler(\n\t\t\tAssertableApplicationContext context) {\n\t\tObservationRegistry observationRegistry = context.getBean(ObservationRegistry.class);\n\t\tassertThat(observationRegistry).isNotNull();\n\t\tCapturingObservationHandler handler = new CapturingObservationHandler();\n\t\tobservationRegistry.observationConfig().observationHandler(handler);\n\t\treturn handler;\n\t}\n\n\tprivate static final class CapturingObservationHandler implements ObservationHandler<Context> {\n\n\t\tprivate final AtomicReference<Context> context = new AtomicReference<>();\n\n\t\t@Override\n\t\tpublic boolean supportsContext(Context context) {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onStart(Context context) {\n\t\t\tthis.context.set(context);\n\t\t}\n\n\t\tContext awaitContext() {\n\t\t\treturn Awaitility.await().untilAtomic(this.context, Matchers.notNullValue());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/ClickHouseEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link ClickHouseEnvironment}.\n *\n * @author Stephane Nicoll\n */\nclass ClickHouseEnvironmentTests {\n\n\t@Test\n\tvoid createWhenNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new ClickHouseEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No ClickHouse password found\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPassword() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"ALLOW_EMPTY_PASSWORD\", \"true\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPasswordIsYes() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"ALLOW_EMPTY_PASSWORD\", \"yes\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoUser() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"default\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasUser() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(\n\t\t\t\tMap.of(\"CLICKHOUSE_USER\", \"me\", \"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoDatabase() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(Map.of(\"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"default\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasDatabase() {\n\t\tClickHouseEnvironment environment = new ClickHouseEnvironment(\n\t\t\t\tMap.of(\"CLICKHOUSE_DB\", \"db\", \"CLICKHOUSE_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/ConnectionFactoryOptionsBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Option;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.ConnectionPorts;\nimport org.springframework.boot.docker.compose.core.RunningService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionFactoryOptionsBuilder}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ConnectionFactoryOptionsBuilderTests {\n\n\tprivate final ConnectionFactoryOptionsBuilder builder = new ConnectionFactoryOptionsBuilder(\"mydb\", 1234);\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenDriverIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new ConnectionFactoryOptionsBuilder(null, 123))\n\t\t\t.withMessage(\"'driver' must not be null\");\n\t}\n\n\t@Test\n\tvoid buildBuildsOptions() {\n\t\tRunningService service = mockService(456);\n\t\tConnectionFactoryOptions options = this.builder.build(service, \"mydb\", \"user\", \"pass\");\n\t\tassertThat(options).isEqualTo(ConnectionFactoryOptions.builder()\n\t\t\t.option(ConnectionFactoryOptions.DATABASE, \"mydb\")\n\t\t\t.option(ConnectionFactoryOptions.HOST, \"myhost\")\n\t\t\t.option(ConnectionFactoryOptions.PORT, 456)\n\t\t\t.option(ConnectionFactoryOptions.DRIVER, \"mydb\")\n\t\t\t.option(ConnectionFactoryOptions.PASSWORD, \"pass\")\n\t\t\t.option(ConnectionFactoryOptions.USER, \"user\")\n\t\t\t.build());\n\t}\n\n\t@Test\n\tvoid buildWhenHasParamsLabelBuildsOptions() {\n\t\tRunningService service = mockService(456, Map.of(\"org.springframework.boot.r2dbc.parameters\", \"foo=bar\"));\n\t\tConnectionFactoryOptions options = this.builder.build(service, \"mydb\", \"user\", \"pass\");\n\t\tassertThat(options).isEqualTo(ConnectionFactoryOptions.builder()\n\t\t\t.option(ConnectionFactoryOptions.DATABASE, \"mydb\")\n\t\t\t.option(ConnectionFactoryOptions.HOST, \"myhost\")\n\t\t\t.option(ConnectionFactoryOptions.PORT, 456)\n\t\t\t.option(ConnectionFactoryOptions.DRIVER, \"mydb\")\n\t\t\t.option(ConnectionFactoryOptions.PASSWORD, \"pass\")\n\t\t\t.option(ConnectionFactoryOptions.USER, \"user\")\n\t\t\t.option(Option.valueOf(\"foo\"), \"bar\")\n\t\t\t.build());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid buildWhenServiceIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.builder.build(null, \"mydb\", \"user\", \"pass\"))\n\t\t\t.withMessage(\"'service' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid buildWhenDatabaseIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.build(mockService(456), null, \"user\", \"pass\"))\n\t\t\t.withMessage(\"'database' must not be null\");\n\t}\n\n\tprivate RunningService mockService(int mappedPort) {\n\t\treturn mockService(mappedPort, Collections.emptyMap());\n\t}\n\n\tprivate RunningService mockService(int mappedPort, Map<String, String> labels) {\n\t\tRunningService service = mock(RunningService.class);\n\t\tConnectionPorts ports = mock(ConnectionPorts.class);\n\t\tgiven(ports.get(1234)).willReturn(mappedPort);\n\t\tgiven(service.host()).willReturn(\"myhost\");\n\t\tgiven(service.ports()).willReturn(ports);\n\t\tgiven(service.labels()).willReturn(labels);\n\t\treturn service;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/MariaDbEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MariaDbEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Jinseong Hwang\n * @author Scott Frederick\n */\nclass MariaDbEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasMariadbRandomRootPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MARIADB_RANDOM_ROOT_PASSWORD\", \"true\")))\n\t\t\t.withMessage(\"MARIADB_RANDOM_ROOT_PASSWORD is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasMysqlRandomRootPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MYSQL_RANDOM_ROOT_PASSWORD\", \"true\")))\n\t\t\t.withMessage(\"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasMariadbRootPasswordHashThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MARIADB_ROOT_PASSWORD_HASH\", \"0FF\")))\n\t\t\t.withMessage(\"MARIADB_ROOT_PASSWORD_HASH is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MariaDbEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No MariaDB password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoDatabaseThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MariaDbEnvironment(Map.of(\"MARIADB_PASSWORD\", \"secret\")))\n\t\t\t.withMessage(\"No MARIADB_DATABASE defined\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMariadbUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_USER\", \"myself\", \"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMysqlUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_USER\", \"myself\", \"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMariadbUserAndMysqlUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(Map.of(\"MARIADB_USER\", \"myself\", \"MYSQL_USER\", \"me\",\n\t\t\t\t\"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMariadbUserOrMysqlUser() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"root\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMariadbPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlRootPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ROOT_PASSWORD\", \"secret\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMariadbPasswordAndMysqlPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MYSQL_PASSWORD\", \"donttell\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMariadbPasswordAndMysqlRootPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_PASSWORD\", \"secret\", \"MYSQL_ROOT_PASSWORD\", \"donttell\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndMariadbAllowEmptyPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndMysqlAllowEmptyPassword() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMariadbDatabase() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMysqlDatabase() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMariadbAndMysqlDatabase() {\n\t\tMariaDbEnvironment environment = new MariaDbEnvironment(\n\t\t\t\tMap.of(\"MARIADB_ALLOW_EMPTY_PASSWORD\", \"true\", \"MARIADB_DATABASE\", \"db\", \"MYSQL_DATABASE\", \"otherdb\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/MySqlEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link MySqlEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Jinseong Hwang\n * @author Scott Frederick\n */\nclass MySqlEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasMysqlRandomRootPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new MySqlEnvironment(Map.of(\"MYSQL_RANDOM_ROOT_PASSWORD\", \"true\")))\n\t\t\t.withMessage(\"MYSQL_RANDOM_ROOT_PASSWORD is not supported\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MySqlEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No MySQL password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoDatabaseThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new MySqlEnvironment(Map.of(\"MYSQL_PASSWORD\", \"secret\")))\n\t\t\t.withMessage(\"No MYSQL_DATABASE defined\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasMysqlUser() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_USER\", \"myself\", \"MYSQL_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"myself\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMysqlUser() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(Map.of(\"MYSQL_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"root\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(Map.of(\"MYSQL_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMysqlRootPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ROOT_PASSWORD\", \"secret\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndMysqlAllowEmptyPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasMysqlDatabase() {\n\t\tMySqlEnvironment environment = new MySqlEnvironment(\n\t\t\t\tMap.of(\"MYSQL_ALLOW_EMPTY_PASSWORD\", \"true\", \"MYSQL_DATABASE\", \"db\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/OracleEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link OracleEnvironment}.\n *\n * @author Andy Wilkinson\n */\nclass OracleEnvironmentTests {\n\n\t@Test\n\tvoid getUsernameWhenHasAppUser() {\n\t\tOracleEnvironment environment = new OracleEnvironment(\n\t\t\t\tMap.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getUsername()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoAppUser() {\n\t\tOracleEnvironment environment = new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getUsername()).isEqualTo(\"system\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasAppPassword() {\n\t\tOracleEnvironment environment = new OracleEnvironment(\n\t\t\t\tMap.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasOraclePassword() {\n\t\tOracleEnvironment environment = new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid createWhenRandomPasswordAndAppPasswordDoesNotThrow() {\n\t\tassertThatNoException().isThrownBy(() -> new OracleEnvironment(\n\t\t\t\tMap.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"secret\", \"ORACLE_RANDOM_PASSWORD\", \"true\"),\n\t\t\t\t\"defaultDb\"));\n\t}\n\n\t@Test\n\tvoid createWhenRandomPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"ORACLE_RANDOM_PASSWORD\", \"true\"), \"defaultDb\"))\n\t\t\t.withMessage(\"ORACLE_RANDOM_PASSWORD is not supported without APP_USER and APP_USER_PASSWORD\");\n\t}\n\n\t@Test\n\tvoid createWhenAppUserAndNoAppPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"APP_USER\", \"alice\"), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle app password found\");\n\t}\n\n\t@Test\n\tvoid createWhenAppUserAndEmptyAppPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"APP_USER\", \"alice\", \"APP_USER_PASSWORD\", \"\"), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle app password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new OracleEnvironment(Collections.emptyMap(), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle password found\");\n\t}\n\n\t@Test\n\tvoid createWhenHasEmptyPasswordThrowsException() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"\"), \"defaultDb\"))\n\t\t\t.withMessage(\"No Oracle password found\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasNoOracleDatabase() {\n\t\tOracleEnvironment environment = new OracleEnvironment(Map.of(\"ORACLE_PASSWORD\", \"secret\"), \"defaultDb\");\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"defaultDb\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasOracleDatabase() {\n\t\tOracleEnvironment environment = new OracleEnvironment(\n\t\t\t\tMap.of(\"ORACLE_PASSWORD\", \"secret\", \"ORACLE_DATABASE\", \"db\"), \"defaultDb\");\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/PostgresEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link PostgresEnvironment}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Sidmar Theodoro\n * @author He Zean\n */\nclass PostgresEnvironmentTests {\n\n\t@Test\n\tvoid createWhenNoPostgresPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new PostgresEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No PostgreSQL password found\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenNoPostgresqlUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRES_USER\", \"me\", \"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasPostgresqlUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USER\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasPostgresqlUsername() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USERNAME\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPostgresPassword() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasPostgresqlPassword() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasTrustHostAuthMethod() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_HOST_AUTH_METHOD\", \"trust\"));\n\t\tassertThat(environment.getPassword()).isNull();\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasNoPasswordAndAllowEmptyPassword() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"ALLOW_EMPTY_PASSWORD\", \"yes\"));\n\t\tassertThat(environment.getPassword()).isEmpty();\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresDbOrPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresqlDbOrPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(Map.of(\"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"postgres\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresDbAndPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRES_USER\", \"me\", \"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresqlDbAndPostgresUser() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USER\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenNoPostgresqlDatabaseAndPostgresqlUsername() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_USERNAME\", \"me\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"me\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasPostgresDb() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRES_DB\", \"db\", \"POSTGRES_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasPostgresqlDb() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_DB\", \"db\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n\t@Test\n\tvoid getDatabaseWhenHasPostgresqlDatabase() {\n\t\tPostgresEnvironment environment = new PostgresEnvironment(\n\t\t\t\tMap.of(\"POSTGRESQL_DATABASE\", \"db\", \"POSTGRESQL_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getDatabase()).isEqualTo(\"db\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/PostgresR2dbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.Option;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.docker.compose.core.ConnectionPorts;\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for\n * {@link PostgresR2dbcDockerComposeConnectionDetailsFactory.PostgresDbR2dbcDockerComposeConnectionDetails}.\n *\n * @author Dmytro Nosan\n */\nclass PostgresR2dbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests {\n\n\tprivate static final Option<String> APPLICATION_NAME = Option.valueOf(\"applicationName\");\n\n\tprivate final RunningService service = mock(RunningService.class);\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final Map<String, String> labels = new LinkedHashMap<>();\n\n\tPostgresR2dbcDockerComposeConnectionDetailsFactoryConnectionDetailsTests() {\n\t\tgiven(this.service.env())\n\t\t\t.willReturn(Map.of(\"POSTGRES_USER\", \"myuser\", \"POSTGRES_PASSWORD\", \"secret\", \"POSTGRES_DB\", \"mydatabase\"));\n\t\tgiven(this.service.labels()).willReturn(this.labels);\n\t\tConnectionPorts connectionPorts = mock(ConnectionPorts.class);\n\t\tgiven(this.service.ports()).willReturn(connectionPorts);\n\t\tgiven(this.service.host()).willReturn(\"localhost\");\n\t\tgiven(connectionPorts.get(5432)).willReturn(30001);\n\t}\n\n\t@Test\n\tvoid createConnectionDetails() {\n\t\tConnectionFactoryOptions options = getConnectionFactoryOptions();\n\t\tassertConnectionFactoryOptions(options);\n\t\tassertThat(options.getValue(APPLICATION_NAME)).isNull();\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsWithLabels() {\n\t\tthis.labels.put(\"org.springframework.boot.r2dbc.parameters\",\n\t\t\t\t\"connectTimeout=PT15S,applicationName=spring-boot\");\n\t\tConnectionFactoryOptions options = getConnectionFactoryOptions();\n\t\tassertConnectionFactoryOptions(options);\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.CONNECT_TIMEOUT)).isEqualTo(\"PT15S\");\n\t\tassertThat(options.getRequiredValue(APPLICATION_NAME)).isEqualTo(\"spring-boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsWithApplicationNameLabelTakesPrecedence() {\n\t\tthis.labels.put(\"org.springframework.boot.r2dbc.parameters\", \"applicationName=spring-boot\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"my-app\");\n\t\tConnectionFactoryOptions options = getConnectionFactoryOptions();\n\t\tassertConnectionFactoryOptions(options);\n\t\tassertThat(options.getRequiredValue(APPLICATION_NAME)).isEqualTo(\"spring-boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsWithSpringApplicationName() {\n\t\tthis.environment.setProperty(\"spring.application.name\", \"spring boot\");\n\t\tConnectionFactoryOptions options = getConnectionFactoryOptions();\n\t\tassertConnectionFactoryOptions(options);\n\t\tassertThat(options.getRequiredValue(APPLICATION_NAME)).isEqualTo(\"spring boot\");\n\t}\n\n\t@Test\n\tvoid createConnectionDetailsAppendSpringApplicationName() {\n\t\tthis.labels.put(\"org.springframework.boot.r2dbc.parameters\", \"connectTimeout=PT15S\");\n\t\tthis.environment.setProperty(\"spring.application.name\", \"my-app\");\n\t\tConnectionFactoryOptions options = getConnectionFactoryOptions();\n\t\tassertConnectionFactoryOptions(options);\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.CONNECT_TIMEOUT)).isEqualTo(\"PT15S\");\n\t\tassertThat(options.getRequiredValue(APPLICATION_NAME)).isEqualTo(\"my-app\");\n\t}\n\n\tprivate void assertConnectionFactoryOptions(ConnectionFactoryOptions options) {\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.HOST)).isEqualTo(\"localhost\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PORT)).isEqualTo(30001);\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo(\"mydatabase\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo(\"myuser\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo(\"secret\");\n\t\tassertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo(\"postgresql\");\n\t}\n\n\tprivate ConnectionFactoryOptions getConnectionFactoryOptions() {\n\t\treturn new PostgresR2dbcDockerComposeConnectionDetailsFactory.PostgresDbR2dbcDockerComposeConnectionDetails(\n\t\t\t\tthis.service, this.environment)\n\t\t\t.getConnectionFactoryOptions();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/docker/compose/SqlServerEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.docker.compose;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link SqlServerEnvironment}.\n *\n * @author Andy Wilkinson\n */\nclass SqlServerEnvironmentTests {\n\n\t@Test\n\tvoid createWhenHasNoPasswordThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> new SqlServerEnvironment(Collections.emptyMap()))\n\t\t\t.withMessage(\"No MSSQL password found\");\n\t}\n\n\t@Test\n\tvoid getUsernameWhenHasNoMsSqlUser() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(Map.of(\"MSSQL_SA_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getUsername()).isEqualTo(\"SA\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMsSqlSaPassword() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(Map.of(\"MSSQL_SA_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasSaPassword() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(Map.of(\"SA_PASSWORD\", \"secret\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n\t@Test\n\tvoid getPasswordWhenHasMsSqlSaPasswordAndSaPasswordPrefersMsSqlSaPassword() {\n\t\tSqlServerEnvironment environment = new SqlServerEnvironment(\n\t\t\t\tMap.of(\"MSSQL_SA_PASSWORD\", \"secret\", \"SA_PASSWORD\", \"not used\"));\n\t\tassertThat(environment.getPassword()).isEqualTo(\"secret\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/health/ConnectionFactoryHealthIndicatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.health;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.UUID;\n\nimport io.r2dbc.h2.CloseableConnectionFactory;\nimport io.r2dbc.h2.H2ConnectionFactory;\nimport io.r2dbc.h2.H2ConnectionOption;\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.Result;\nimport io.r2dbc.spi.ValidationDepth;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.health.contributor.Status;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ConnectionFactoryHealthIndicator}.\n *\n * @author Mark Paluch\n * @author Stephane Nicoll\n */\nclass ConnectionFactoryHealthIndicatorTests {\n\n\t@Test\n\tvoid healthIndicatorWhenDatabaseUpWithConnectionValidation() {\n\t\tCloseableConnectionFactory connectionFactory = createTestDatabase();\n\t\ttry {\n\t\t\tConnectionFactoryHealthIndicator healthIndicator = new ConnectionFactoryHealthIndicator(connectionFactory);\n\t\t\thealthIndicator.health().as(StepVerifier::create).assertNext((actual) -> {\n\t\t\t\tassertThat(actual.getStatus()).isEqualTo(Status.UP);\n\t\t\t\tassertThat(actual.getDetails()).containsOnly(entry(\"database\", \"H2\"),\n\t\t\t\t\t\tentry(\"validationQuery\", \"validate(REMOTE)\"));\n\t\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\t\tfinally {\n\t\t\tStepVerifier.create(connectionFactory.close()).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\t}\n\n\t@Test\n\tvoid healthIndicatorWhenDatabaseDownWithConnectionValidation() {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tgiven(connectionFactory.getMetadata()).willReturn(() -> \"mock\");\n\t\tRuntimeException exception = new RuntimeException(\"test\");\n\t\tgiven(connectionFactory.create()).willReturn(Mono.error(exception));\n\t\tConnectionFactoryHealthIndicator healthIndicator = new ConnectionFactoryHealthIndicator(connectionFactory);\n\t\thealthIndicator.health().as(StepVerifier::create).assertNext((actual) -> {\n\t\t\tassertThat(actual.getStatus()).isEqualTo(Status.DOWN);\n\t\t\tassertThat(actual.getDetails()).containsOnly(entry(\"database\", \"mock\"),\n\t\t\t\t\tentry(\"validationQuery\", \"validate(REMOTE)\"), entry(\"error\", \"java.lang.RuntimeException: test\"));\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthIndicatorWhenConnectionValidationFails() {\n\t\tConnectionFactory connectionFactory = mock(ConnectionFactory.class);\n\t\tgiven(connectionFactory.getMetadata()).willReturn(() -> \"mock\");\n\t\tConnection connection = mock(Connection.class);\n\t\tgiven(connection.validate(ValidationDepth.REMOTE)).willReturn(Mono.just(false));\n\t\tgiven(connection.close()).willReturn(Mono.empty());\n\t\tgiven(connectionFactory.create()).willAnswer((invocation) -> Mono.just(connection));\n\t\tConnectionFactoryHealthIndicator healthIndicator = new ConnectionFactoryHealthIndicator(connectionFactory);\n\t\thealthIndicator.health().as(StepVerifier::create).assertNext((actual) -> {\n\t\t\tassertThat(actual.getStatus()).isEqualTo(Status.DOWN);\n\t\t\tassertThat(actual.getDetails()).containsOnly(entry(\"database\", \"mock\"),\n\t\t\t\t\tentry(\"validationQuery\", \"validate(REMOTE)\"));\n\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid healthIndicatorWhenDatabaseUpWithSuccessValidationQuery() {\n\t\tCloseableConnectionFactory connectionFactory = createTestDatabase();\n\t\ttry {\n\t\t\tString customValidationQuery = \"SELECT COUNT(*) from HEALTH_TEST\";\n\t\t\tString createTableStatement = \"CREATE TABLE HEALTH_TEST (id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY)\";\n\t\t\tMono.from(connectionFactory.create())\n\t\t\t\t.flatMapMany((it) -> Flux.from(it.createStatement(createTableStatement).execute())\n\t\t\t\t\t.flatMap(Result::getRowsUpdated)\n\t\t\t\t\t.thenMany(it.close()))\n\t\t\t\t.as(StepVerifier::create)\n\t\t\t\t.expectComplete()\n\t\t\t\t.verify(Duration.ofSeconds(30));\n\t\t\tReactiveHealthIndicator healthIndicator = new ConnectionFactoryHealthIndicator(connectionFactory,\n\t\t\t\t\tcustomValidationQuery);\n\t\t\thealthIndicator.health().as(StepVerifier::create).assertNext((actual) -> {\n\t\t\t\tassertThat(actual.getStatus()).isEqualTo(Status.UP);\n\t\t\t\tassertThat(actual.getDetails()).containsOnly(entry(\"database\", \"H2\"), entry(\"result\", 0L),\n\t\t\t\t\t\tentry(\"validationQuery\", customValidationQuery));\n\t\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\t\tfinally {\n\t\t\tStepVerifier.create(connectionFactory.close()).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\n\t}\n\n\t@Test\n\tvoid healthIndicatorWhenDatabaseUpWithFailureValidationQuery() {\n\t\tCloseableConnectionFactory connectionFactory = createTestDatabase();\n\t\ttry {\n\t\t\tString invalidValidationQuery = \"SELECT COUNT(*) from DOES_NOT_EXIST\";\n\t\t\tReactiveHealthIndicator healthIndicator = new ConnectionFactoryHealthIndicator(connectionFactory,\n\t\t\t\t\tinvalidValidationQuery);\n\t\t\thealthIndicator.health().as(StepVerifier::create).assertNext((actual) -> {\n\t\t\t\tassertThat(actual.getStatus()).isEqualTo(Status.DOWN);\n\t\t\t\tassertThat(actual.getDetails()).contains(entry(\"database\", \"H2\"),\n\t\t\t\t\t\tentry(\"validationQuery\", invalidValidationQuery));\n\t\t\t\tassertThat(actual.getDetails()).containsOnlyKeys(\"database\", \"error\", \"validationQuery\");\n\t\t\t}).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\t\tfinally {\n\t\t\tStepVerifier.create(connectionFactory.close()).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\t}\n\n\tprivate CloseableConnectionFactory createTestDatabase() {\n\t\treturn H2ConnectionFactory.inMemory(\"db-\" + UUID.randomUUID(), \"sa\", \"\",\n\t\t\t\tCollections.singletonMap(H2ConnectionOption.DB_CLOSE_DELAY, \"-1\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/init/R2dbcScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.init;\n\nimport java.util.UUID;\n\nimport io.r2dbc.spi.ConnectionFactory;\n\nimport org.springframework.boot.r2dbc.ConnectionFactoryBuilder;\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializerTests;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.r2dbc.core.DatabaseClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link R2dbcScriptDatabaseInitializer}.\n *\n * @author Andy Wilkinson\n */\nclass R2dbcScriptDatabaseInitializerTests\n\t\textends AbstractScriptDatabaseInitializerTests<R2dbcScriptDatabaseInitializer> {\n\n\tprivate final ConnectionFactory embeddedConnectionFactory = ConnectionFactoryBuilder\n\t\t.withUrl(\"r2dbc:h2:mem:///\" + UUID.randomUUID() + \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t.build();\n\n\tprivate final ConnectionFactory standaloneConnectionFactory = ConnectionFactoryBuilder\n\t\t.withUrl(\n\t\t\t\t\"r2dbc:h2:file:///\"\n\t\t\t\t\t\t+ new BuildOutput(R2dbcScriptDatabaseInitializerTests.class).getRootLocation()\n\t\t\t\t\t\t\t.getAbsolutePath()\n\t\t\t\t\t\t\t.replace('\\\\', '/')\n\t\t\t\t\t\t+ \"/\" + UUID.randomUUID() + \"?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE\")\n\t\t.build();\n\n\t@Override\n\tprotected R2dbcScriptDatabaseInitializer createEmbeddedDatabaseInitializer(\n\t\t\tDatabaseInitializationSettings settings) {\n\t\treturn new R2dbcScriptDatabaseInitializer(this.embeddedConnectionFactory, settings);\n\t}\n\n\t@Override\n\tprotected R2dbcScriptDatabaseInitializer createStandaloneDatabaseInitializer(\n\t\t\tDatabaseInitializationSettings settings) {\n\t\treturn new R2dbcScriptDatabaseInitializer(this.standaloneConnectionFactory, settings);\n\t}\n\n\t@Override\n\tprotected int numberOfEmbeddedRows(String sql) {\n\t\treturn numberOfRows(this.embeddedConnectionFactory, sql);\n\t}\n\n\t@Override\n\tprotected int numberOfStandaloneRows(String sql) {\n\t\treturn numberOfRows(this.standaloneConnectionFactory, sql);\n\t}\n\n\tprivate int numberOfRows(ConnectionFactory connectionFactory, String sql) {\n\t\tInteger result = DatabaseClient.create(connectionFactory)\n\t\t\t.sql(sql)\n\t\t\t.map((row, metadata) -> row.get(0))\n\t\t\t.first()\n\t\t\t.map((number) -> ((Number) number).intValue())\n\t\t\t.block();\n\t\tassertThat(result).isNotNull();\n\t\treturn result;\n\t}\n\n\t@Override\n\tprotected void assertDatabaseAccessed(boolean accessed, R2dbcScriptDatabaseInitializer initializer) {\n\t\t// No-op as R2DBC does not need to access the database to determine its type\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/metrics/ConnectionPoolMetricsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.metrics;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.UUID;\n\nimport io.micrometer.core.instrument.Gauge;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.r2dbc.h2.CloseableConnectionFactory;\nimport io.r2dbc.h2.H2ConnectionFactory;\nimport io.r2dbc.h2.H2ConnectionOption;\nimport io.r2dbc.pool.ConnectionPool;\nimport io.r2dbc.pool.ConnectionPoolConfiguration;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.test.StepVerifier;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ConnectionPoolMetrics}.\n *\n * @author Tadaya Tsuyukubo\n * @author Mark Paluch\n * @author Stephane Nicoll\n */\nclass ConnectionPoolMetricsTests {\n\n\tprivate static final Tag testTag = Tag.of(\"test\", \"yes\");\n\n\tprivate static final Tag regionTag = Tag.of(\"region\", \"eu-2\");\n\n\tprivate CloseableConnectionFactory connectionFactory;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.connectionFactory = H2ConnectionFactory.inMemory(\"db-\" + UUID.randomUUID(), \"sa\", \"\",\n\t\t\t\tCollections.singletonMap(H2ConnectionOption.DB_CLOSE_DELAY, \"-1\"));\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.connectionFactory != null) {\n\t\t\tStepVerifier.create(this.connectionFactory.close()).expectComplete().verify(Duration.ofSeconds(30));\n\t\t}\n\t}\n\n\t@Test\n\tvoid connectionFactoryIsInstrumented() {\n\t\tSimpleMeterRegistry registry = new SimpleMeterRegistry();\n\t\tConnectionPool connectionPool = new ConnectionPool(\n\t\t\t\tConnectionPoolConfiguration.builder(this.connectionFactory).initialSize(3).maxSize(7).build());\n\t\tConnectionPoolMetrics metrics = new ConnectionPoolMetrics(connectionPool, \"test-pool\",\n\t\t\t\tTags.of(testTag, regionTag));\n\t\tmetrics.bindTo(registry);\n\t\tconnectionPool.warmup().as(StepVerifier::create).expectNext(3).expectComplete().verify(Duration.ofSeconds(30));\n\t\t// acquire two connections\n\t\tconnectionPool.create()\n\t\t\t.as(StepVerifier::create)\n\t\t\t.expectNextCount(1)\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tconnectionPool.create()\n\t\t\t.as(StepVerifier::create)\n\t\t\t.expectNextCount(1)\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tassertGauge(registry, \"r2dbc.pool.acquired\", 2);\n\t\tassertGauge(registry, \"r2dbc.pool.allocated\", 3);\n\t\tassertGauge(registry, \"r2dbc.pool.idle\", 1);\n\t\tassertGauge(registry, \"r2dbc.pool.pending\", 0);\n\t\tassertGauge(registry, \"r2dbc.pool.max.allocated\", 7);\n\t\tassertGauge(registry, \"r2dbc.pool.max.pending\", Integer.MAX_VALUE);\n\t}\n\n\tprivate void assertGauge(SimpleMeterRegistry registry, String metric, int expectedValue) {\n\t\tGauge gauge = registry.get(metric).gauge();\n\t\tassertThat(gauge.value()).isEqualTo(expectedValue);\n\t\tassertThat(gauge.getId().getTags()).containsExactlyInAnyOrder(Tag.of(\"name\", \"test-pool\"), testTag, regionTag);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/ClickHouseR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ClickHouseR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n */\nclass ClickHouseR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/MariaDbR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MariaDbR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass MariaDbR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/MySqlR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MySqlR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass MySqlR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/OracleFreeR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OracleFreeR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass OracleFreeR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/OracleXeR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OracleXeR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Andy Wilkinson\n */\nclass OracleXeR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/PostgresR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PostgresR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass PostgresR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/test/java/org/springframework/boot/r2dbc/testcontainers/SqlServerR2dbcContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc.testcontainers;\n\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SqlServerR2dbcContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass SqlServerR2dbcContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ConnectionFactoryOptions.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/testFixtures/java/org/springframework/boot/r2dbc/SimpleBindMarkerFactoryProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.Wrapped;\n\nimport org.springframework.boot.r2dbc.SimpleConnectionFactoryProvider.SimpleTestConnectionFactory;\nimport org.springframework.r2dbc.core.binding.BindMarkersFactory;\nimport org.springframework.r2dbc.core.binding.BindMarkersFactoryResolver.BindMarkerFactoryProvider;\n\n/**\n * Simple {@link BindMarkerFactoryProvider} for {@link SimpleConnectionFactoryProvider}.\n *\n * @author Stephane Nicoll\n */\npublic class SimpleBindMarkerFactoryProvider implements BindMarkerFactoryProvider {\n\n\t@Override\n\tpublic BindMarkersFactory getBindMarkers(ConnectionFactory connectionFactory) {\n\t\tif (unwrapIfNecessary(connectionFactory) instanceof SimpleTestConnectionFactory) {\n\t\t\treturn BindMarkersFactory.anonymous(\"?\");\n\t\t}\n\t\treturn null;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ConnectionFactory unwrapIfNecessary(ConnectionFactory connectionFactory) {\n\t\tif (connectionFactory instanceof Wrapped) {\n\t\t\treturn unwrapIfNecessary(((Wrapped<ConnectionFactory>) connectionFactory).unwrap());\n\t\t}\n\t\treturn connectionFactory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/testFixtures/java/org/springframework/boot/r2dbc/SimpleConnectionFactoryProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.r2dbc;\n\nimport io.r2dbc.spi.Connection;\nimport io.r2dbc.spi.ConnectionFactory;\nimport io.r2dbc.spi.ConnectionFactoryMetadata;\nimport io.r2dbc.spi.ConnectionFactoryOptions;\nimport io.r2dbc.spi.ConnectionFactoryProvider;\nimport org.reactivestreams.Publisher;\nimport reactor.core.publisher.Mono;\n\n/**\n * Simple driver for testing.\n *\n * @author Mark Paluch\n * @author Andy Wilkinson\n */\npublic class SimpleConnectionFactoryProvider implements ConnectionFactoryProvider {\n\n\t@Override\n\tpublic ConnectionFactory create(ConnectionFactoryOptions connectionFactoryOptions) {\n\t\treturn new SimpleTestConnectionFactory();\n\t}\n\n\t@Override\n\tpublic boolean supports(ConnectionFactoryOptions connectionFactoryOptions) {\n\t\treturn connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.DRIVER).equals(\"simple\");\n\t}\n\n\t@Override\n\tpublic String getDriver() {\n\t\treturn \"simple\";\n\t}\n\n\tpublic static class SimpleTestConnectionFactory implements ConnectionFactory {\n\n\t\t@Override\n\t\tpublic Publisher<? extends Connection> create() {\n\t\t\treturn Mono.error(new UnsupportedOperationException());\n\t\t}\n\n\t\t@Override\n\t\tpublic ConnectionFactoryMetadata getMetadata() {\n\t\t\treturn SimpleConnectionFactoryProvider.class::getName;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/testFixtures/resources/META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider",
    "content": "org.springframework.boot.r2dbc.SimpleConnectionFactoryProvider\n"
  },
  {
    "path": "module/spring-boot-r2dbc/src/testFixtures/resources/META-INF/spring.factories",
    "content": "org.springframework.r2dbc.core.binding.BindMarkersFactoryResolver$BindMarkerFactoryProvider=org.springframework.boot.r2dbc.SimpleBindMarkerFactoryProvider\n"
  },
  {
    "path": "module/spring-boot-reactor/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Reactor\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"io.projectreactor:reactor-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:context-propagation\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link EnvironmentPostProcessor} to enable the Reactor global features as early as\n * possible in the startup process.\n * <p>\n * If the \"reactor-tools\" dependency is available, the debug agent is enabled by default,\n * unless the {@code \"spring.reactor.debug-agent.enabled\"} configuration property is set\n * to false.\n * <p>\n * If the {@code \"spring.threads.virtual.enabled\"} property is enabled and the current JVM\n * is 21 or later, then the Reactor System property is set to configure the Bounded\n * Elastic Scheduler to use Virtual Threads globally.\n *\n * @author Brian Clozel\n * @since 3.2.0\n */\npublic class ReactorEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {\n\n\tprivate static final String REACTOR_DEBUGAGENT_CLASS = \"reactor.tools.agent.ReactorDebugAgent\";\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (ClassUtils.isPresent(REACTOR_DEBUGAGENT_CLASS, null)) {\n\t\t\tBoolean agentEnabled = environment.getProperty(\"spring.reactor.debug-agent.enabled\", Boolean.class);\n\t\t\tif (agentEnabled != Boolean.FALSE) {\n\t\t\t\ttry {\n\t\t\t\t\tClass<?> debugAgent = Class.forName(REACTOR_DEBUGAGENT_CLASS);\n\t\t\t\t\tdebugAgent.getMethod(\"init\").invoke(null);\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthrow new RuntimeException(\"Failed to init Reactor's debug agent\", ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (Threading.VIRTUAL.isActive(environment)) {\n\t\t\tSystem.setProperty(\"reactor.schedulers.defaultBoundedElasticOnVirtualThreads\", \"true\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/java/org/springframework/boot/reactor/autoconfigure/ReactorAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.autoconfigure;\n\nimport reactor.core.publisher.Hooks;\n\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Reactor.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Hooks.class)\n@EnableConfigurationProperties(ReactorProperties.class)\npublic final class ReactorAutoConfiguration {\n\n\tReactorAutoConfiguration(ReactorProperties properties) {\n\t\tif (properties.getContextPropagation() == ReactorProperties.ContextPropagationMode.AUTO) {\n\t\t\tHooks.enableAutomaticContextPropagation();\n\t\t}\n\t}\n\n\t@Bean\n\tstatic LazyInitializationExcludeFilter reactorAutoConfigurationLazyInitializationExcludeFilter() {\n\t\treturn LazyInitializationExcludeFilter.forBeanTypes(ReactorAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/java/org/springframework/boot/reactor/autoconfigure/ReactorProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Reactor.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.reactor\")\npublic class ReactorProperties {\n\n\t/**\n\t * Context Propagation support mode for Reactor operators.\n\t */\n\tprivate ContextPropagationMode contextPropagation = ContextPropagationMode.LIMITED;\n\n\tpublic ContextPropagationMode getContextPropagation() {\n\t\treturn this.contextPropagation;\n\t}\n\n\tpublic void setContextPropagation(ContextPropagationMode contextPropagation) {\n\t\tthis.contextPropagation = contextPropagation;\n\t}\n\n\tpublic enum ContextPropagationMode {\n\n\t\t/**\n\t\t * Context Propagation is applied to all Reactor operators.\n\t\t */\n\t\tAUTO,\n\n\t\t/**\n\t\t * Context Propagation is only applied to \"tap\" and \"handle\" Reactor operators.\n\t\t */\n\t\tLIMITED\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/java/org/springframework/boot/reactor/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Reactor.\n */\n@NullMarked\npackage org.springframework.boot.reactor.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/java/org/springframework/boot/reactor/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for Reactor integration.\n */\n@NullMarked\npackage org.springframework.boot.reactor;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n      {\n      \"name\": \"spring.reactor.stacktrace-mode.enabled\",\n      \"description\": \"Whether Reactor should collect stacktrace information at runtime.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"replacement\": \"spring.reactor.debug-agent.enabled\",\n        \"since\": \"2.2.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.reactor.autoconfigure.ReactorAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-reactor/src/main/resources/META-INF/spring.factories",
    "content": "# Environment Post Processors\norg.springframework.boot.EnvironmentPostProcessor=\\\norg.springframework.boot.reactor.ReactorEnvironmentPostProcessor\n"
  },
  {
    "path": "module/spring-boot-reactor/src/test/java/org/springframework/boot/reactor/InstrumentedFluxProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor;\n\nimport reactor.core.publisher.Flux;\n\n/**\n * Utility class that should be instrumented by the reactor debug agent.\n *\n * @author Brian Clozel\n * @see ReactorEnvironmentPostProcessorTests\n */\nclass InstrumentedFluxProvider {\n\n\tFlux<Integer> newFluxJust() {\n\t\treturn Flux.just(1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/test/java/org/springframework/boot/reactor/ReactorEnvironmentPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport reactor.core.Scannable;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactorEnvironmentPostProcessor}.\n *\n * @author Brian Clozel\n */\n\n@Disabled(\"Tests rely on static initialization and are flaky on CI\")\nclass ReactorEnvironmentPostProcessorTests {\n\n\tstatic {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tenvironment.setProperty(\"spring.threads.virtual.enabled\", \"true\");\n\t\tReactorEnvironmentPostProcessor postProcessor = new ReactorEnvironmentPostProcessor();\n\t\tpostProcessor.postProcessEnvironment(environment, new SpringApplication());\n\t}\n\n\t@Test\n\tvoid enablesReactorDebugAgent() {\n\t\tInstrumentedFluxProvider fluxProvider = new InstrumentedFluxProvider();\n\t\tFlux<Integer> flux = fluxProvider.newFluxJust();\n\t\tassertThat(Scannable.from(flux).stepName())\n\t\t\t.startsWith(\"Flux.just ⇢ at org.springframework.boot.reactor.InstrumentedFluxProvider.newFluxJust\");\n\t}\n\n\t@Test\n\t@EnabledForJreRange(max = JRE.JAVA_20)\n\tvoid shouldNotEnableVirtualThreads() {\n\t\tassertThat(System.getProperty(\"reactor.schedulers.defaultBoundedElasticOnVirtualThreads\")).isNotEqualTo(\"true\");\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldEnableVirtualThreads() {\n\t\tassertThat(System.getProperty(\"reactor.schedulers.defaultBoundedElasticOnVirtualThreads\")).isEqualTo(\"true\");\n\t}\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tSystem.setProperty(\"reactor.schedulers.defaultBoundedElasticOnVirtualThreads\", \"false\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor/src/test/java/org/springframework/boot/reactor/autoconfigure/ReactorAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.autoconfigure;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.micrometer.context.ContextRegistry;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Hooks;\nimport reactor.core.publisher.Mono;\nimport reactor.util.context.Context;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactorAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\nclass ReactorAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactorAutoConfiguration.class));\n\n\tprivate static final String THREADLOCAL_KEY = \"ReactorAutoConfigurationTests\";\n\n\tprivate static final ThreadLocal<String> THREADLOCAL_VALUE = ThreadLocal.withInitial(() -> \"initial\");\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid resetStaticState() {\n\t\tHooks.disableAutomaticContextPropagation();\n\t}\n\n\t@BeforeAll\n\tstatic void initializeThreadLocalAccessors() {\n\t\tContextRegistry globalRegistry = ContextRegistry.getInstance();\n\t\tglobalRegistry.registerThreadLocalAccessor(THREADLOCAL_KEY, THREADLOCAL_VALUE);\n\t}\n\n\t@AfterAll\n\tstatic void removeThreadLocalAccessors() {\n\t\tContextRegistry globalRegistry = ContextRegistry.getInstance();\n\t\tglobalRegistry.removeThreadLocalAccessor(THREADLOCAL_KEY);\n\t}\n\n\t@Test\n\tvoid shouldNotConfigurePropagationByDefault() {\n\t\tAtomicReference<String> threadLocalValue = new AtomicReference<>();\n\t\tthis.contextRunner.run((applicationContext) -> {\n\t\t\tMono.just(\"test\")\n\t\t\t\t.doOnNext((element) -> threadLocalValue.set(THREADLOCAL_VALUE.get()))\n\t\t\t\t.contextWrite(Context.of(THREADLOCAL_KEY, \"updated\"))\n\t\t\t\t.block();\n\t\t\tassertThat(threadLocalValue.get()).isEqualTo(\"initial\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigurePropagationIfSetToAuto() {\n\t\tAtomicReference<String> threadLocalValue = new AtomicReference<>();\n\t\tthis.contextRunner.withPropertyValues(\"spring.reactor.context-propagation=auto\")\n\t\t\t.run((applicationContext) -> assertThatPropagationIsWorking(threadLocalValue));\n\t}\n\n\t@Test\n\tvoid shouldConfigurePropagationIfSetToAutoAndLazyInitializationIsEnabled() {\n\t\tAtomicReference<String> threadLocalValue = new AtomicReference<>();\n\t\tthis.contextRunner\n\t\t\t.withInitializer(\n\t\t\t\t\t(context) -> context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()))\n\t\t\t.withPropertyValues(\"spring.reactor.context-propagation=auto\")\n\t\t\t.run((context) -> assertThatPropagationIsWorking(threadLocalValue));\n\t}\n\n\tprivate void assertThatPropagationIsWorking(AtomicReference<String> threadLocalValue) {\n\t\tMono.just(\"test\")\n\t\t\t.doOnNext((element) -> threadLocalValue.set(THREADLOCAL_VALUE.get()))\n\t\t\t.contextWrite(Context.of(THREADLOCAL_KEY, \"updated\"))\n\t\t\t.block();\n\t\tassertThat(threadLocalValue.get()).isEqualTo(\"updated\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Reactor Netty\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-web-server\"))\n\tapi(\"io.projectreactor.netty:reactor-netty-http\")\n\tapi(\"org.springframework:spring-web\")\n\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\timplementation(project(\":module:spring-boot-netty\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-web-server-test\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.eclipse.jetty:jetty-client\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.http2:jetty-http2-client\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.http2:jetty-http2-client-transport\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/CompressionCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.BiPredicate;\n\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.http.server.HttpServer;\nimport reactor.netty.http.server.HttpServerRequest;\nimport reactor.netty.http.server.HttpServerResponse;\n\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.util.InvalidMimeTypeException;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.MimeTypeUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configure the HTTP compression on a Reactor Netty request/response handler.\n *\n * @author Stephane Maldini\n * @author Phillip Webb\n * @author Brian Clozel\n */\nfinal class CompressionCustomizer implements NettyServerCustomizer {\n\n\tprivate static final CompressionPredicate ALWAYS_COMPRESS = (request, response) -> true;\n\n\tprivate final Compression compression;\n\n\tCompressionCustomizer(Compression compression) {\n\t\tthis.compression = compression;\n\t}\n\n\t@Override\n\tpublic HttpServer apply(HttpServer server) {\n\t\tif (!this.compression.getMinResponseSize().isNegative()) {\n\t\t\tserver = server.compress((int) this.compression.getMinResponseSize().toBytes());\n\t\t}\n\t\tCompressionPredicate mimeTypes = getMimeTypesPredicate(this.compression.getAllMimeTypes());\n\t\tCompressionPredicate excludedUserAgents = getExcludedUserAgentsPredicate(\n\t\t\t\tthis.compression.getExcludedUserAgents());\n\t\tserver = server.compress(mimeTypes.and(excludedUserAgents));\n\t\treturn server;\n\t}\n\n\tprivate CompressionPredicate getMimeTypesPredicate(String[] mimeTypeValues) {\n\t\tif (ObjectUtils.isEmpty(mimeTypeValues)) {\n\t\t\treturn ALWAYS_COMPRESS;\n\t\t}\n\t\tList<MimeType> mimeTypes = Arrays.stream(mimeTypeValues).map(MimeTypeUtils::parseMimeType).toList();\n\t\treturn (request, response) -> {\n\t\t\tString contentType = response.responseHeaders().get(HttpHeaderNames.CONTENT_TYPE);\n\t\t\tif (!StringUtils.hasLength(contentType)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tMimeType contentMimeType = MimeTypeUtils.parseMimeType(contentType);\n\t\t\t\treturn mimeTypes.stream().anyMatch((candidate) -> candidate.isCompatibleWith(contentMimeType));\n\t\t\t}\n\t\t\tcatch (InvalidMimeTypeException ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate CompressionPredicate getExcludedUserAgentsPredicate(String @Nullable [] excludedUserAgents) {\n\t\tif (ObjectUtils.isEmpty(excludedUserAgents)) {\n\t\t\treturn ALWAYS_COMPRESS;\n\t\t}\n\t\treturn (request, response) -> {\n\t\t\tHttpHeaders headers = request.requestHeaders();\n\t\t\treturn Arrays.stream(excludedUserAgents)\n\t\t\t\t.noneMatch((candidate) -> headers.contains(HttpHeaderNames.USER_AGENT, candidate, true));\n\t\t};\n\t}\n\n\tprivate interface CompressionPredicate extends BiPredicate<HttpServerRequest, HttpServerResponse> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/GracefulShutdown.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.time.Duration;\nimport java.util.function.Supplier;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.DisposableServer;\n\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\n\n/**\n * Handles Netty graceful shutdown.\n *\n * @author Andy Wilkinson\n */\nfinal class GracefulShutdown {\n\n\tprivate static final Log logger = LogFactory.getLog(GracefulShutdown.class);\n\n\tprivate final Supplier<@Nullable DisposableServer> disposableServer;\n\n\tprivate volatile @Nullable Thread shutdownThread;\n\n\tprivate volatile boolean shuttingDown;\n\n\tGracefulShutdown(Supplier<@Nullable DisposableServer> disposableServer) {\n\t\tthis.disposableServer = disposableServer;\n\t}\n\n\tvoid shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tDisposableServer server = this.disposableServer.get();\n\t\tif (server == null) {\n\t\t\treturn;\n\t\t}\n\t\tlogger.info(\"Commencing graceful shutdown. Waiting for active requests to complete\");\n\t\tThread shutdownThread = new Thread(() -> doShutdown(callback, server), \"netty-shutdown\");\n\t\tthis.shutdownThread = shutdownThread;\n\t\tshutdownThread.start();\n\t}\n\n\tprivate void doShutdown(GracefulShutdownCallback callback, DisposableServer server) {\n\t\tthis.shuttingDown = true;\n\t\ttry {\n\t\t\tserver.disposeNow(Duration.ofNanos(Long.MAX_VALUE));\n\t\t\tlogger.info(\"Graceful shutdown complete\");\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.IDLE);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.info(\"Graceful shutdown aborted with one or more requests still active\");\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE);\n\t\t}\n\t\tfinally {\n\t\t\tthis.shutdownThread = null;\n\t\t\tthis.shuttingDown = false;\n\t\t}\n\t}\n\n\tvoid abort() {\n\t\tThread shutdownThread = this.shutdownThread;\n\t\tif (shutdownThread != null) {\n\t\t\twhile (!this.shuttingDown) {\n\t\t\t\tsleep(50);\n\t\t\t}\n\t\t\tshutdownThread.interrupt();\n\t\t}\n\t}\n\n\tprivate void sleep(long millis) {\n\t\ttry {\n\t\t\tThread.sleep(millis);\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.net.InetSocketAddress;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.http.HttpProtocol;\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ReactiveWebServerFactory} that can be used to create {@link NettyWebServer}s.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory {\n\n\tprivate Set<NettyServerCustomizer> serverCustomizers = new LinkedHashSet<>();\n\n\tprivate final List<NettyRouteProvider> routeProviders = new ArrayList<>();\n\n\tprivate @Nullable Duration lifecycleTimeout;\n\n\tprivate boolean useForwardHeaders;\n\n\tprivate @Nullable ReactorResourceFactory resourceFactory;\n\n\tpublic NettyReactiveWebServerFactory() {\n\t}\n\n\tpublic NettyReactiveWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\t@Override\n\tpublic WebServer getWebServer(HttpHandler httpHandler) {\n\t\tHttpServer httpServer = createHttpServer();\n\t\tReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);\n\t\tNettyWebServer webServer = createNettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout,\n\t\t\t\tgetShutdown());\n\t\twebServer.setRouteProviders(this.routeProviders);\n\t\treturn webServer;\n\t}\n\n\tNettyWebServer createNettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter,\n\t\t\t@Nullable Duration lifecycleTimeout, Shutdown shutdown) {\n\t\treturn new NettyWebServer(httpServer, handlerAdapter, lifecycleTimeout, shutdown, this.resourceFactory);\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link NettyServerCustomizer}s that will be\n\t * applied to the Netty server builder.\n\t * @return the customizers that will be applied\n\t */\n\tpublic Collection<NettyServerCustomizer> getServerCustomizers() {\n\t\treturn this.serverCustomizers;\n\t}\n\n\t/**\n\t * Set {@link NettyServerCustomizer}s that should be applied to the Netty server\n\t * builder. Calling this method will replace any existing customizers.\n\t * @param serverCustomizers the customizers to set\n\t */\n\tpublic void setServerCustomizers(Collection<? extends NettyServerCustomizer> serverCustomizers) {\n\t\tAssert.notNull(serverCustomizers, \"'serverCustomizers' must not be null\");\n\t\tthis.serverCustomizers = new LinkedHashSet<>(serverCustomizers);\n\t}\n\n\t/**\n\t * Add {@link NettyServerCustomizer}s that should be applied while building the\n\t * server.\n\t * @param serverCustomizers the customizers to add\n\t */\n\tpublic void addServerCustomizers(NettyServerCustomizer... serverCustomizers) {\n\t\tAssert.notNull(serverCustomizers, \"'serverCustomizers' must not be null\");\n\t\tthis.serverCustomizers.addAll(Arrays.asList(serverCustomizers));\n\t}\n\n\t/**\n\t * Add {@link NettyRouteProvider}s that should be applied, in order, before the\n\t * handler for the Spring application.\n\t * @param routeProviders the route providers to add\n\t */\n\tpublic void addRouteProviders(NettyRouteProvider... routeProviders) {\n\t\tAssert.notNull(routeProviders, \"'routeProviders' must not be null\");\n\t\tthis.routeProviders.addAll(Arrays.asList(routeProviders));\n\t}\n\n\t/**\n\t * Set the maximum amount of time that should be waited when starting or stopping the\n\t * server.\n\t * @param lifecycleTimeout the lifecycle timeout\n\t */\n\tpublic void setLifecycleTimeout(@Nullable Duration lifecycleTimeout) {\n\t\tthis.lifecycleTimeout = lifecycleTimeout;\n\t}\n\n\t/**\n\t * Set if x-forward-* headers should be processed.\n\t * @param useForwardHeaders if x-forward headers should be used\n\t */\n\tpublic void setUseForwardHeaders(boolean useForwardHeaders) {\n\t\tthis.useForwardHeaders = useForwardHeaders;\n\t}\n\n\t/**\n\t * Set the {@link ReactorResourceFactory} to get the shared resources from.\n\t * @param resourceFactory the server resources\n\t */\n\tpublic void setResourceFactory(@Nullable ReactorResourceFactory resourceFactory) {\n\t\tthis.resourceFactory = resourceFactory;\n\t}\n\n\tprivate HttpServer createHttpServer() {\n\t\tHttpServer server = HttpServer.create().bindAddress(this::getListenAddress);\n\t\tSsl ssl = getSsl();\n\t\tif (Ssl.isEnabled(ssl)) {\n\t\t\tserver = customizeSslConfiguration(server, ssl);\n\t\t}\n\t\tif (getCompression() != null && getCompression().getEnabled()) {\n\t\t\tCompressionCustomizer compressionCustomizer = new CompressionCustomizer(getCompression());\n\t\t\tserver = compressionCustomizer.apply(server);\n\t\t}\n\t\tserver = server.protocol(listProtocols()).forwarded(this.useForwardHeaders);\n\t\treturn applyCustomizers(server);\n\t}\n\n\tprivate HttpServer customizeSslConfiguration(HttpServer httpServer, Ssl ssl) {\n\t\tSslServerCustomizer customizer = new SslServerCustomizer(getHttp2(), ssl.getClientAuth(), getSslBundle(),\n\t\t\t\tgetServerNameSslBundles());\n\t\taddBundleUpdateHandler(null, ssl.getBundle(), customizer);\n\t\tssl.getServerNameBundles()\n\t\t\t.forEach((serverNameSslBundle) -> addBundleUpdateHandler(serverNameSslBundle.serverName(),\n\t\t\t\t\tserverNameSslBundle.bundle(), customizer));\n\t\treturn customizer.apply(httpServer);\n\t}\n\n\tprivate void addBundleUpdateHandler(@Nullable String serverName, @Nullable String bundleName,\n\t\t\tSslServerCustomizer customizer) {\n\t\tif (StringUtils.hasText(bundleName)) {\n\t\t\tSslBundles sslBundles = getSslBundles();\n\t\t\tAssert.state(sslBundles != null, \"'sslBundles' must not be null\");\n\t\t\tsslBundles.addBundleUpdateHandler(bundleName,\n\t\t\t\t\t(sslBundle) -> customizer.updateSslBundle(serverName, sslBundle));\n\t\t}\n\t}\n\n\tprivate HttpProtocol[] listProtocols() {\n\t\tList<HttpProtocol> protocols = new ArrayList<>();\n\t\tprotocols.add(HttpProtocol.HTTP11);\n\t\tif (getHttp2() != null && getHttp2().isEnabled()) {\n\t\t\tif (getSsl() != null && getSsl().isEnabled()) {\n\t\t\t\tprotocols.add(HttpProtocol.H2);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tprotocols.add(HttpProtocol.H2C);\n\t\t\t}\n\t\t}\n\t\treturn protocols.toArray(new HttpProtocol[0]);\n\t}\n\n\tprivate InetSocketAddress getListenAddress() {\n\t\tif (getAddress() != null) {\n\t\t\treturn new InetSocketAddress(getAddress().getHostAddress(), getPort());\n\t\t}\n\t\treturn new InetSocketAddress(getPort());\n\t}\n\n\tprivate HttpServer applyCustomizers(HttpServer server) {\n\t\tfor (NettyServerCustomizer customizer : this.serverCustomizers) {\n\t\t\tserver = customizer.apply(server);\n\t\t}\n\t\treturn server;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyRouteProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.util.function.Function;\n\nimport reactor.netty.http.server.HttpServerRoutes;\n\n/**\n * Function that can add new routes to an {@link HttpServerRoutes} instance.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see NettyReactiveWebServerFactory\n */\n@FunctionalInterface\npublic interface NettyRouteProvider extends Function<HttpServerRoutes, HttpServerRoutes> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyServerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.util.function.Function;\n\nimport reactor.netty.http.server.HttpServer;\n\n/**\n * Mapping function that can be used to customize a Reactor Netty server instance.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see NettyReactiveWebServerFactory\n */\n@FunctionalInterface\npublic interface NettyServerCustomizer extends Function<HttpServer, HttpServer> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/NettyWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.BiFunction;\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\n\nimport io.netty.channel.group.DefaultChannelGroup;\nimport io.netty.channel.unix.Errors.NativeIoException;\nimport io.netty.util.concurrent.DefaultEventExecutor;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport org.reactivestreams.Publisher;\nimport reactor.netty.ChannelBindException;\nimport reactor.netty.DisposableServer;\nimport reactor.netty.http.server.HttpServer;\nimport reactor.netty.http.server.HttpServerRequest;\nimport reactor.netty.http.server.HttpServerResponse;\nimport reactor.netty.http.server.HttpServerRoutes;\nimport reactor.netty.resources.LoopResources;\n\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;\nimport org.springframework.util.Assert;\n\n/**\n * {@link WebServer} that can be used to control a Reactor Netty web server. Usually this\n * class should be created using the {@link NettyReactiveWebServerFactory} and not\n * directly.\n *\n * @author Brian Clozel\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class NettyWebServer implements WebServer {\n\n\t/**\n\t * Permission denied error code from {@code errno.h}.\n\t */\n\tprivate static final int ERROR_NO_EACCES = -13;\n\n\t/**\n\t * Address in use error code from {@code errno.h}.\n\t */\n\tprivate static final int ERROR_ADDR_IN_USE = -98;\n\n\tprivate static final Predicate<HttpServerRequest> ALWAYS = (request) -> true;\n\n\tprivate static final Log logger = LogFactory.getLog(NettyWebServer.class);\n\n\tprivate final HttpServer httpServer;\n\n\tprivate final BiFunction<? super HttpServerRequest, ? super HttpServerResponse, ? extends Publisher<Void>> handler;\n\n\tprivate final @Nullable Duration lifecycleTimeout;\n\n\tprivate final @Nullable GracefulShutdown gracefulShutdown;\n\n\tprivate final @Nullable ReactorResourceFactory resourceFactory;\n\n\tprivate List<NettyRouteProvider> routeProviders = Collections.emptyList();\n\n\tprivate volatile @Nullable DisposableServer disposableServer;\n\n\t/**\n\t * Creates a new {@code NettyWebServer} instance.\n\t * @param httpServer the HTTP server\n\t * @param handlerAdapter the handler adapter\n\t * @param lifecycleTimeout the lifecycle timeout, may be {@code null}\n\t * @param shutdown the shutdown, may be {@code null}\n\t * @param resourceFactory the factory for the server's {@link LoopResources loop\n\t * resources}, may be {@code null}\n\t * @since 4.0.0\n\t */\n\tpublic NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter,\n\t\t\t@Nullable Duration lifecycleTimeout, @Nullable Shutdown shutdown,\n\t\t\t@Nullable ReactorResourceFactory resourceFactory) {\n\t\tAssert.notNull(httpServer, \"'httpServer' must not be null\");\n\t\tAssert.notNull(handlerAdapter, \"'handlerAdapter' must not be null\");\n\t\tthis.lifecycleTimeout = lifecycleTimeout;\n\t\tthis.handler = handlerAdapter;\n\t\tthis.httpServer = httpServer.channelGroup(new DefaultChannelGroup(new DefaultEventExecutor()));\n\t\tthis.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(() -> this.disposableServer)\n\t\t\t\t: null;\n\t\tthis.resourceFactory = resourceFactory;\n\t}\n\n\tpublic void setRouteProviders(List<NettyRouteProvider> routeProviders) {\n\t\tthis.routeProviders = routeProviders;\n\t}\n\n\t@Override\n\tpublic void start() throws WebServerException {\n\t\tDisposableServer disposableServer = this.disposableServer;\n\t\tif (disposableServer == null) {\n\t\t\ttry {\n\t\t\t\tdisposableServer = startHttpServer();\n\t\t\t\tthis.disposableServer = disposableServer;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tPortInUseException.ifCausedBy(ex, ChannelBindException.class, (channelBindException) -> {\n\t\t\t\t\tif (channelBindException.localPort() > 0 && !isPermissionDenied(channelBindException.getCause())) {\n\t\t\t\t\t\tPortInUseException.throwIfPortBindingException(channelBindException,\n\t\t\t\t\t\t\t\tchannelBindException::localPort);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tif (ex instanceof ChannelBindException channelBindException) {\n\t\t\t\t\tPortInUseException.ifCausedBy(ex, NativeIoException.class, (nativeIoException) -> {\n\t\t\t\t\t\tif (nativeIoException.expectedErr() == ERROR_ADDR_IN_USE) {\n\t\t\t\t\t\t\tthrow new PortInUseException(channelBindException.localPort(), ex);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow new WebServerException(\"Unable to start Netty\", ex);\n\t\t\t}\n\t\t\tlogger.info(getStartedOnMessage(disposableServer));\n\t\t\tstartDaemonAwaitThread(disposableServer);\n\t\t}\n\t}\n\n\tprivate String getStartedOnMessage(DisposableServer server) {\n\t\tStringBuilder message = new StringBuilder();\n\t\ttryAppend(message, \"port %s\", () -> server.port()\n\t\t\t\t+ ((this.httpServer.configuration().sslProvider() != null) ? \" (https)\" : \" (http)\"));\n\t\ttryAppend(message, \"path %s\", server::path);\n\t\treturn (!message.isEmpty()) ? \"Netty started on \" + message : \"Netty started\";\n\t}\n\n\tprotected String getStartedLogMessage() {\n\t\tDisposableServer disposableServer = this.disposableServer;\n\t\tAssert.state(disposableServer != null, \"'disposableServer' must not be null\");\n\t\treturn getStartedOnMessage(disposableServer);\n\t}\n\n\tprivate void tryAppend(StringBuilder message, String format, Supplier<Object> supplier) {\n\t\ttry {\n\t\t\tObject value = supplier.get();\n\t\t\tmessage.append((!message.isEmpty()) ? \" \" : \"\");\n\t\t\tmessage.append(String.format(format, value));\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tDisposableServer startHttpServer() {\n\t\tHttpServer server = this.httpServer;\n\t\tif (this.routeProviders.isEmpty()) {\n\t\t\tserver = server.handle(this.handler);\n\t\t}\n\t\telse {\n\t\t\tserver = server.route(this::applyRouteProviders);\n\t\t}\n\t\tif (this.resourceFactory != null) {\n\t\t\tLoopResources resources = this.resourceFactory.getLoopResources();\n\t\t\tAssert.state(resources != null, \"No LoopResources: is ReactorResourceFactory not initialized yet?\");\n\t\t\tserver = server.runOn(resources);\n\t\t}\n\t\tif (this.lifecycleTimeout != null) {\n\t\t\treturn server.bindNow(this.lifecycleTimeout);\n\t\t}\n\t\treturn server.bindNow();\n\t}\n\n\tprivate boolean isPermissionDenied(@Nullable Throwable bindExceptionCause) {\n\t\ttry {\n\t\t\tif (bindExceptionCause instanceof NativeIoException nativeException) {\n\t\t\t\treturn nativeException.expectedErr() == ERROR_NO_EACCES;\n\t\t\t}\n\t\t}\n\t\tcatch (Throwable ignore) {\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Initiates a graceful shutdown of the Netty web server. Handling of new requests is\n\t * prevented and the given {@code callback} is invoked at the end of the attempt. The\n\t * attempt can be explicitly ended by invoking {@link #stop}.\n\t * <p>\n\t * Once shutdown has been initiated Netty will reject any new connections. Requests +\n\t * on existing idle connections will also be rejected.\n\t */\n\t@Override\n\tpublic void shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tif (this.gracefulShutdown == null) {\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);\n\t\t\treturn;\n\t\t}\n\t\tthis.gracefulShutdown.shutDownGracefully(callback);\n\t}\n\n\tprivate void applyRouteProviders(HttpServerRoutes routes) {\n\t\tfor (NettyRouteProvider provider : this.routeProviders) {\n\t\t\troutes = provider.apply(routes);\n\t\t}\n\t\troutes.route(ALWAYS, this.handler);\n\t}\n\n\tprivate void startDaemonAwaitThread(DisposableServer disposableServer) {\n\t\tThread awaitThread = new Thread(\"server\") {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tdisposableServer.onDispose().block();\n\t\t\t}\n\n\t\t};\n\t\tawaitThread.setContextClassLoader(getClass().getClassLoader());\n\t\tawaitThread.setDaemon(false);\n\t\tawaitThread.start();\n\t}\n\n\t@Override\n\tpublic void stop() throws WebServerException {\n\t\tDisposableServer disposableServer = this.disposableServer;\n\t\tif (disposableServer != null) {\n\t\t\tif (this.gracefulShutdown != null) {\n\t\t\t\tthis.gracefulShutdown.abort();\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tif (this.lifecycleTimeout != null) {\n\t\t\t\t\tdisposableServer.disposeNow(this.lifecycleTimeout);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdisposableServer.disposeNow();\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IllegalStateException ex) {\n\t\t\t\t// Continue\n\t\t\t}\n\t\t\tthis.disposableServer = null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getPort() {\n\t\tDisposableServer disposableServer = this.disposableServer;\n\t\tif (disposableServer != null) {\n\t\t\ttry {\n\t\t\t\treturn disposableServer.port();\n\t\t\t}\n\t\t\tcatch (UnsupportedOperationException ex) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/SslServerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.netty.handler.ssl.ClientAuth;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.netty.http.Http11SslContextSpec;\nimport reactor.netty.http.Http2SslContextSpec;\nimport reactor.netty.http.server.HttpServer;\nimport reactor.netty.tcp.AbstractProtocolSslContextSpec;\nimport reactor.netty.tcp.SslProvider;\nimport reactor.netty.tcp.SslProvider.GenericSslContextSpec;\nimport reactor.netty.tcp.SslProvider.SslContextSpec;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.web.server.Http2;\nimport org.springframework.boot.web.server.Ssl;\n\n/**\n * {@link NettyServerCustomizer} that configures SSL for the given Reactor Netty server\n * instance.\n *\n * @author Brian Clozel\n * @author Raheela Aslam\n * @author Chris Bono\n * @author Cyril Dangerville\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class SslServerCustomizer implements NettyServerCustomizer {\n\n\tprivate static final Log logger = LogFactory.getLog(SslServerCustomizer.class);\n\n\tprivate final @Nullable Http2 http2;\n\n\tprivate final ClientAuth clientAuth;\n\n\tprivate volatile SslProvider sslProvider;\n\n\tprivate final Map<String, SslProvider> serverNameSslProviders;\n\n\tpublic SslServerCustomizer(@Nullable Http2 http2, Ssl.@Nullable ClientAuth clientAuth, SslBundle sslBundle,\n\t\t\tMap<String, SslBundle> serverNameSslBundles) {\n\t\tthis.http2 = http2;\n\t\tthis.clientAuth = Ssl.ClientAuth.map(clientAuth, ClientAuth.NONE, ClientAuth.OPTIONAL, ClientAuth.REQUIRE);\n\t\tthis.sslProvider = createSslProvider(sslBundle);\n\t\tthis.serverNameSslProviders = createServerNameSslProviders(serverNameSslBundles);\n\t\tupdateSslBundle(null, sslBundle);\n\t}\n\n\t@Override\n\tpublic HttpServer apply(HttpServer server) {\n\t\treturn server.secure(this::applySecurity);\n\t}\n\n\tprivate void applySecurity(SslContextSpec spec) {\n\t\tspec.sslContext(this.sslProvider.getSslContext()).setSniAsyncMappings((serverName, promise) -> {\n\t\t\tSslProvider provider = (serverName != null) ? this.serverNameSslProviders.get(serverName)\n\t\t\t\t\t: this.sslProvider;\n\t\t\treturn promise.setSuccess(provider);\n\t\t});\n\t}\n\n\tvoid updateSslBundle(@Nullable String serverName, SslBundle sslBundle) {\n\t\tlogger.debug(\"SSL Bundle has been updated, reloading SSL configuration\");\n\t\tif (serverName == null) {\n\t\t\tthis.sslProvider = createSslProvider(sslBundle);\n\t\t}\n\t\telse {\n\t\t\tthis.serverNameSslProviders.put(serverName, createSslProvider(sslBundle));\n\t\t}\n\t}\n\n\tprivate Map<String, SslProvider> createServerNameSslProviders(Map<String, SslBundle> serverNameSslBundles) {\n\t\tMap<String, SslProvider> serverNameSslProviders = new HashMap<>();\n\t\tserverNameSslBundles\n\t\t\t.forEach((serverName, sslBundle) -> serverNameSslProviders.put(serverName, createSslProvider(sslBundle)));\n\t\treturn serverNameSslProviders;\n\t}\n\n\tprivate SslProvider createSslProvider(SslBundle sslBundle) {\n\t\treturn SslProvider.builder().sslContext((GenericSslContextSpec<?>) createSslContextSpec(sslBundle)).build();\n\t}\n\n\t/**\n\t * Create an {@link AbstractProtocolSslContextSpec} for a given {@link SslBundle}.\n\t * @param sslBundle the {@link SslBundle} to use\n\t * @return an {@link AbstractProtocolSslContextSpec} instance\n\t */\n\tprotected final AbstractProtocolSslContextSpec<?> createSslContextSpec(SslBundle sslBundle) {\n\t\tAbstractProtocolSslContextSpec<?> sslContextSpec = (this.http2 != null && this.http2.isEnabled())\n\t\t\t\t? Http2SslContextSpec.forServer(sslBundle.getManagers().getKeyManagerFactory())\n\t\t\t\t: Http11SslContextSpec.forServer(sslBundle.getManagers().getKeyManagerFactory());\n\t\treturn sslContextSpec.configure((builder) -> {\n\t\t\tbuilder.trustManager(sslBundle.getManagers().getTrustManagerFactory());\n\t\t\tSslOptions options = sslBundle.getOptions();\n\t\t\tbuilder.protocols(options.getEnabledProtocols());\n\t\t\tbuilder.ciphers(SslOptions.asSet(options.getCiphers()));\n\t\t\tbuilder.clientAuth(this.clientAuth);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.reactor.netty.NettyRouteProvider;\nimport org.springframework.boot.reactor.netty.NettyServerCustomizer;\nimport org.springframework.boot.reactor.netty.autoconfigure.ReactorNettyConfigurations.ReactorResourceFactoryConfiguration;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.autoconfigure.reactive.ReactiveWebServerConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.ReactiveHttpInputMessage;\nimport org.springframework.http.client.ReactorResourceFactory;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Netty-based reactive web\n * server.\n *\n * @author Andy Wilkinson\n * @author Daeho Kwon\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ReactiveHttpInputMessage.class, HttpServer.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(NettyServerProperties.class)\n@Import({ ReactiveWebServerConfiguration.class, ReactorResourceFactoryConfiguration.class })\npublic final class NettyReactiveWebServerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveWebServerFactory.class)\n\tNettyReactiveWebServerFactory nettyReactiveWebServerFactory(ReactorResourceFactory resourceFactory,\n\t\t\tObjectProvider<NettyRouteProvider> routes, ObjectProvider<NettyServerCustomizer> serverCustomizers) {\n\t\tNettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory();\n\t\tserverFactory.setResourceFactory(resourceFactory);\n\t\troutes.orderedStream().forEach(serverFactory::addRouteProviders);\n\t\tserverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList());\n\t\treturn serverFactory;\n\t}\n\n\t@Bean\n\tNettyReactiveWebServerFactoryCustomizer nettyWebServerFactoryCustomizer(Environment environment,\n\t\t\tServerProperties serverProperties, NettyServerProperties nettyProperties) {\n\t\treturn new NettyReactiveWebServerFactoryCustomizer(environment, serverProperties, nettyProperties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.netty.channel.ChannelOption;\n\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\n\n/**\n * Customization for Netty-specific features.\n *\n * @author Brian Clozel\n * @author Chentao Qu\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\npublic class NettyReactiveWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<NettyReactiveWebServerFactory>, Ordered {\n\n\tprivate final Environment environment;\n\n\tprivate final ServerProperties serverProperties;\n\n\tprivate final NettyServerProperties nettyProperties;\n\n\tpublic NettyReactiveWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties,\n\t\t\tNettyServerProperties nettyProperties) {\n\t\tthis.environment = environment;\n\t\tthis.serverProperties = serverProperties;\n\t\tthis.nettyProperties = nettyProperties;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void customize(NettyReactiveWebServerFactory factory) {\n\t\tfactory.setUseForwardHeaders(getOrDeduceUseForwardHeaders());\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.nettyProperties::getConnectionTimeout)\n\t\t\t.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));\n\t\tmap.from(this.nettyProperties::getIdleTimeout).to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout));\n\t\tmap.from(this.nettyProperties::getMaxKeepAliveRequests)\n\t\t\t.to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests));\n\t\tif (this.serverProperties.getHttp2().isEnabled()) {\n\t\t\tmap.from(this.serverProperties.getMaxHttpRequestHeaderSize())\n\t\t\t\t.to((size) -> customizeHttp2MaxHeaderSize(factory, size.toBytes()));\n\t\t}\n\t\tcustomizeRequestDecoder(factory, map);\n\t}\n\n\tprivate boolean getOrDeduceUseForwardHeaders() {\n\t\tif (this.serverProperties.getForwardHeadersStrategy() == null) {\n\t\t\tCloudPlatform platform = CloudPlatform.getActive(this.environment);\n\t\t\treturn platform != null && platform.isUsingForwardHeaders();\n\t\t}\n\t\treturn this.serverProperties.getForwardHeadersStrategy().equals(ServerProperties.ForwardHeadersStrategy.NATIVE);\n\t}\n\n\tprivate void customizeConnectionTimeout(NettyReactiveWebServerFactory factory, Duration connectionTimeout) {\n\t\tfactory.addServerCustomizers((httpServer) -> httpServer.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,\n\t\t\t\t(int) connectionTimeout.toMillis()));\n\t}\n\n\tprivate void customizeRequestDecoder(NettyReactiveWebServerFactory factory, PropertyMapper propertyMapper) {\n\t\tfactory.addServerCustomizers((httpServer) -> httpServer.httpRequestDecoder((httpRequestDecoderSpec) -> {\n\t\t\tpropertyMapper.from(this.serverProperties.getMaxHttpRequestHeaderSize())\n\t\t\t\t.to((maxHttpRequestHeader) -> httpRequestDecoderSpec\n\t\t\t\t\t.maxHeaderSize((int) maxHttpRequestHeader.toBytes()));\n\t\t\tpropertyMapper.from(this.nettyProperties.getMaxInitialLineLength())\n\t\t\t\t.to((maxInitialLineLength) -> httpRequestDecoderSpec\n\t\t\t\t\t.maxInitialLineLength((int) maxInitialLineLength.toBytes()));\n\t\t\tpropertyMapper.from(this.nettyProperties.getH2cMaxContentLength())\n\t\t\t\t.to((h2cMaxContentLength) -> httpRequestDecoderSpec\n\t\t\t\t\t.h2cMaxContentLength((int) h2cMaxContentLength.toBytes()));\n\t\t\tpropertyMapper.from(this.nettyProperties.getInitialBufferSize())\n\t\t\t\t.to((initialBufferSize) -> httpRequestDecoderSpec.initialBufferSize((int) initialBufferSize.toBytes()));\n\t\t\tpropertyMapper.from(this.nettyProperties.isValidateHeaders()).to(httpRequestDecoderSpec::validateHeaders);\n\t\t\treturn httpRequestDecoderSpec;\n\t\t}));\n\t}\n\n\tprivate void customizeIdleTimeout(NettyReactiveWebServerFactory factory, Duration idleTimeout) {\n\t\tfactory.addServerCustomizers((httpServer) -> httpServer.idleTimeout(idleTimeout));\n\t}\n\n\tprivate void customizeMaxKeepAliveRequests(NettyReactiveWebServerFactory factory, int maxKeepAliveRequests) {\n\t\tfactory.addServerCustomizers((httpServer) -> httpServer.maxKeepAliveRequests(maxKeepAliveRequests));\n\t}\n\n\tprivate void customizeHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long size) {\n\t\tfactory.addServerCustomizers(\n\t\t\t\t((httpServer) -> httpServer.http2Settings((settings) -> settings.maxHeaderListSize(size))));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Netty server properties.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Ivan Sopov\n * @author Marcos Barbero\n * @author Eddú Meléndez\n * @author Quinten De Swaef\n * @author Venil Noronha\n * @author Aurélien Leboulanger\n * @author Brian Clozel\n * @author Olivier Lamy\n * @author Chentao Qu\n * @author Artsiom Yudovin\n * @author Andrew McGhie\n * @author Rafiullah Hamedy\n * @author Dirk Deyne\n * @author HaiTao Zhang\n * @author Victor Mandujano\n * @author Chris Bono\n * @author Parviz Rozikov\n * @author Florian Storz\n * @author Michael Weidmann\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@ConfigurationProperties(\"server.netty\")\npublic class NettyServerProperties {\n\n\t/**\n\t * Connection timeout of the Netty channel.\n\t */\n\tprivate @Nullable Duration connectionTimeout;\n\n\t/**\n\t * Maximum content length of an H2C upgrade request.\n\t */\n\tprivate DataSize h2cMaxContentLength = DataSize.ofBytes(0);\n\n\t/**\n\t * Initial buffer size for HTTP request decoding.\n\t */\n\tprivate DataSize initialBufferSize = DataSize.ofBytes(128);\n\n\t/**\n\t * Maximum length that can be decoded for an HTTP request's initial line.\n\t */\n\tprivate DataSize maxInitialLineLength = DataSize.ofKilobytes(4);\n\n\t/**\n\t * Maximum number of requests that can be made per connection. By default, a\n\t * connection serves unlimited number of requests.\n\t */\n\tprivate @Nullable Integer maxKeepAliveRequests;\n\n\t/**\n\t * Whether to validate headers when decoding requests.\n\t */\n\tprivate boolean validateHeaders = true;\n\n\t/**\n\t * Idle timeout of the Netty channel. When not specified, an infinite timeout is used.\n\t */\n\tprivate @Nullable Duration idleTimeout;\n\n\tpublic @Nullable Duration getConnectionTimeout() {\n\t\treturn this.connectionTimeout;\n\t}\n\n\tpublic void setConnectionTimeout(@Nullable Duration connectionTimeout) {\n\t\tthis.connectionTimeout = connectionTimeout;\n\t}\n\n\tpublic DataSize getH2cMaxContentLength() {\n\t\treturn this.h2cMaxContentLength;\n\t}\n\n\tpublic void setH2cMaxContentLength(DataSize h2cMaxContentLength) {\n\t\tthis.h2cMaxContentLength = h2cMaxContentLength;\n\t}\n\n\tpublic DataSize getInitialBufferSize() {\n\t\treturn this.initialBufferSize;\n\t}\n\n\tpublic void setInitialBufferSize(DataSize initialBufferSize) {\n\t\tthis.initialBufferSize = initialBufferSize;\n\t}\n\n\tpublic DataSize getMaxInitialLineLength() {\n\t\treturn this.maxInitialLineLength;\n\t}\n\n\tpublic void setMaxInitialLineLength(DataSize maxInitialLineLength) {\n\t\tthis.maxInitialLineLength = maxInitialLineLength;\n\t}\n\n\tpublic @Nullable Integer getMaxKeepAliveRequests() {\n\t\treturn this.maxKeepAliveRequests;\n\t}\n\n\tpublic void setMaxKeepAliveRequests(@Nullable Integer maxKeepAliveRequests) {\n\t\tthis.maxKeepAliveRequests = maxKeepAliveRequests;\n\t}\n\n\tpublic boolean isValidateHeaders() {\n\t\treturn this.validateHeaders;\n\t}\n\n\tpublic void setValidateHeaders(boolean validateHeaders) {\n\t\tthis.validateHeaders = validateHeaders;\n\t}\n\n\tpublic @Nullable Duration getIdleTimeout() {\n\t\treturn this.idleTimeout;\n\t}\n\n\tpublic void setIdleTimeout(@Nullable Duration idleTimeout) {\n\t\tthis.idleTimeout = idleTimeout;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/NettyWebServerTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Jetty\n * {@link AutoConfigureWebServer @AutoConfigureWebServer} support.\n *\n * @author Phillip Webb\n */\nclass NettyWebServerTestAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/ReactorNettyConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.client.ReactorResourceFactory;\n\n/**\n * Configurations for Reactor Netty. Those should be {@code @Import} in a regular\n * auto-configuration class.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic final class ReactorNettyConfigurations {\n\n\tprivate ReactorNettyConfigurations() {\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(ReactorNettyProperties.class)\n\tpublic static class ReactorResourceFactoryConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tReactorResourceFactory reactorResourceFactory(ReactorNettyProperties configurationProperties) {\n\t\t\tReactorResourceFactory reactorResourceFactory = new ReactorResourceFactory();\n\t\t\tif (configurationProperties.getShutdownQuietPeriod() != null) {\n\t\t\t\treactorResourceFactory.setShutdownQuietPeriod(configurationProperties.getShutdownQuietPeriod());\n\t\t\t}\n\t\t\treturn reactorResourceFactory;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/ReactorNettyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Reactor Netty.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.reactor.netty\")\npublic class ReactorNettyProperties {\n\n\t/**\n\t * Amount of time to wait before shutting down resources.\n\t */\n\tprivate @Nullable Duration shutdownQuietPeriod;\n\n\tpublic @Nullable Duration getShutdownQuietPeriod() {\n\t\treturn this.shutdownQuietPeriod;\n\t}\n\n\tpublic void setShutdownQuietPeriod(@Nullable Duration shutdownQuietPeriod) {\n\t\tthis.shutdownQuietPeriod = shutdownQuietPeriod;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/NettyReactiveManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure.actuate.web.server;\n\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Netty-based\n * reactive web endpoint infrastructure when a separate management context running on a\n * different port is required.\n *\n * @author Andy Wilkinson\n */\n@ConditionalOnClass(HttpServer.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(ManagementServerProperties.class)\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\nclass NettyReactiveManagementChildContextConfiguration {\n\n\t@Bean\n\tstatic ManagementContextFactory reactiveWebChildContextFactory() {\n\t\treturn new ManagementContextFactory(WebApplicationType.REACTIVE, ReactiveWebServerFactory.class,\n\t\t\t\tNettyReactiveWebServerAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/NettyReactiveManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure.actuate.web.server;\n\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for a Netty-based reactive management context.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ HttpServer.class, ManagementContextFactory.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\npublic final class NettyReactiveManagementContextAutoConfiguration {\n\n\t@Bean\n\tstatic ManagementContextFactory reactiveWebChildContextFactory() {\n\t\treturn new ManagementContextFactory(WebApplicationType.REACTIVE, ReactiveWebServerFactory.class,\n\t\t\t\tNettyReactiveWebServerAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/actuate/web/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Reactor Netty actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.reactor.netty.autoconfigure.actuate.web.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Reactor Netty.\n */\n@NullMarked\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/java/org/springframework/boot/reactor/netty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive web server implementation backed by Netty.\n */\n@NullMarked\npackage org.springframework.boot.reactor.netty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"server.netty.max-chunk-size\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Deprecated for removal in Reactor Netty.\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.reactor.netty.autoconfigure.actuate.web.server.NettyReactiveManagementChildContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration\norg.springframework.boot.reactor.netty.autoconfigure.actuate.web.server.NettyReactiveManagementContextAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/resources/META-INF/spring/org.springframework.boot.web.server.test.AutoConfigureWebServer.imports",
    "content": "org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.reactor.netty.shutdown-quiet-period=0s\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/NettyReactiveWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty;\n\nimport java.net.ConnectException;\nimport java.net.InetAddress;\nimport java.net.SocketAddress;\nimport java.net.UnknownHostException;\nimport java.time.Duration;\nimport java.util.Arrays;\n\nimport io.netty.channel.Channel;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport reactor.core.CoreSubscriber;\nimport reactor.core.Disposable;\nimport reactor.core.publisher.Mono;\nimport reactor.netty.DisposableChannel;\nimport reactor.netty.DisposableServer;\nimport reactor.netty.http.server.HttpServer;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactoryTests;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NettyReactiveWebServerFactory}.\n *\n * @author Brian Clozel\n * @author Chris Bono\n * @author Moritz Halbritter\n */\nclass NettyReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests {\n\n\t@Test\n\tvoid portInUseExceptionIsThrownWhenPortIsAlreadyInUse() {\n\t\tAbstractReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setPort(0);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tfactory.setPort(this.webServer.getPort());\n\t\tassertThatExceptionOfType(PortInUseException.class).isThrownBy(factory.getWebServer(new EchoHandler())::start)\n\t\t\t.satisfies(this::portMatchesRequirement)\n\t\t\t.withCauseInstanceOf(Throwable.class);\n\t}\n\n\t@Test\n\tvoid webServerExceptionIsThrownWhenAddressCannotBeAssigned() throws UnknownHostException {\n\t\tAbstractReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setPort(8080);\n\t\tfactory.setAddress(InetAddress.getByName(\"1.2.3.4\"));\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(factory.getWebServer(new EchoHandler())::start);\n\t}\n\n\t@Test\n\tvoid getPortWhenDisposableServerPortOperationIsUnsupportedReturnsMinusOne() {\n\t\tNettyReactiveWebServerFactory factory = new NoPortNettyReactiveWebServerFactory(0);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tassertThat(this.webServer.getPort()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid resourceFactoryAndWebServerLifecycle() {\n\t\tNettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setPort(0);\n\t\tReactorResourceFactory resourceFactory = new ReactorResourceFactory();\n\t\tfactory.setResourceFactory(resourceFactory);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tassertThatNoException().isThrownBy(() -> {\n\t\t\tresourceFactory.start();\n\t\t\tthis.webServer.start();\n\t\t\tthis.webServer.stop();\n\t\t\tresourceFactory.stop();\n\t\t\tresourceFactory.start();\n\t\t\tthis.webServer.start();\n\t\t});\n\t}\n\n\tprivate void portMatchesRequirement(PortInUseException exception) {\n\t\tassertThat(exception.getPort()).isEqualTo(this.webServer.getPort());\n\t}\n\n\t@Test\n\tvoid nettyCustomizers() {\n\t\tNettyReactiveWebServerFactory factory = getFactory();\n\t\tNettyServerCustomizer[] customizers = new NettyServerCustomizer[2];\n\t\tfor (int i = 0; i < customizers.length; i++) {\n\t\t\tcustomizers[i] = mock(NettyServerCustomizer.class);\n\t\t\tgiven(customizers[i].apply(any(HttpServer.class))).will((invocation) -> invocation.getArgument(0));\n\t\t}\n\t\tfactory.setServerCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (NettyServerCustomizer customizer : customizers) {\n\t\t\tordered.verify(customizer).apply(any(HttpServer.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid useForwardedHeaders() {\n\t\tNettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setUseForwardHeaders(true);\n\t\tassertForwardHeaderIsUsed(factory);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenSslIsConfiguredWithAValidAliasARequestSucceeds() {\n\t\tMono<String> result = testSslWithAlias(\"test-alias\");\n\t\tStepVerifier.create(result).expectNext(\"Hello World\").expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"1.key\", \"1.crt\", \"2.key\", \"2.crt\" })\n\tvoid whenSslBundleIsUpdatedThenSslIsReloaded() {\n\t\tDefaultSslBundleRegistry bundles = new DefaultSslBundleRegistry(\"bundle1\", createSslBundle(\"1.key\", \"1.crt\"));\n\t\tMono<String> result = testSslWithBundle(bundles, \"bundle1\");\n\t\tStepVerifier.create(result).expectNext(\"Hello World\").expectComplete().verify(Duration.ofSeconds(30));\n\t\tbundles.updateBundle(\"bundle1\", createSslBundle(\"2.key\", \"2.crt\"));\n\t\tMono<String> result2 = executeSslRequest();\n\t\tStepVerifier.create(result2).expectNext(\"Hello World\").expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() {\n\t\tNettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tWebClient webClient = getWebClient(this.webServer.getPort()).build();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> {\n\t\t\tblockingHandler.stopBlocking();\n\t\t\ttry {\n\t\t\t\twebClient.get().retrieve().toBodilessEntity().block();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\treturn ex.getCause() instanceof ConnectException;\n\t\t\t}\n\t\t});\n\t\tthis.webServer.stop();\n\t}\n\n\t@Override\n\t@Test\n\t@Disabled(\"Reactor Netty does not support multiple ports\")\n\tprotected void startedLogMessageWithMultiplePorts() {\n\t}\n\n\tprivate Mono<String> testSslWithAlias(String alias) {\n\t\tString keyStore = \"classpath:test.jks\";\n\t\tString keyPassword = \"password\";\n\t\tNettyReactiveWebServerFactory factory = getFactory();\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyPassword(keyPassword);\n\t\tssl.setKeyAlias(alias);\n\t\tfactory.setSsl(ssl);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\treturn executeSslRequest();\n\t}\n\n\tprivate Mono<String> testSslWithBundle(SslBundles sslBundles, String bundle) {\n\t\tNettyReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setSslBundles(sslBundles);\n\t\tfactory.setSsl(Ssl.forBundle(bundle));\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\treturn executeSslRequest();\n\t}\n\n\tprivate Mono<String> executeSslRequest() {\n\t\tReactorClientHttpConnector connector = buildTrustAllSslConnector();\n\t\tWebClient client = WebClient.builder()\n\t\t\t.baseUrl(\"https://localhost:\" + this.webServer.getPort())\n\t\t\t.clientConnector(connector)\n\t\t\t.build();\n\t\treturn client.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t}\n\n\t@Override\n\tprotected NettyReactiveWebServerFactory getFactory() {\n\t\treturn new NettyReactiveWebServerFactory(0);\n\t}\n\n\t@Override\n\tprotected String startedLogMessage() {\n\t\treturn ((NettyWebServer) this.webServer).getStartedLogMessage();\n\t}\n\n\t@Override\n\tprotected void addConnector(int port, ConfigurableReactiveWebServerFactory factory) {\n\t\tthrow new UnsupportedOperationException(\"Reactor Netty does not support multiple ports\");\n\t}\n\n\tprivate static SslBundle createSslBundle(String key, String certificate) {\n\t\treturn SslBundle.of(new PemSslStoreBundle(\n\t\t\t\tnew PemSslStoreDetails(null, \"classpath:\" + certificate, \"classpath:\" + key), null));\n\t}\n\n\tstatic class NoPortNettyReactiveWebServerFactory extends NettyReactiveWebServerFactory {\n\n\t\tNoPortNettyReactiveWebServerFactory(int port) {\n\t\t\tsuper(port);\n\t\t}\n\n\t\t@Override\n\t\tNettyWebServer createNettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter,\n\t\t\t\t@Nullable Duration lifecycleTimeout, Shutdown shutdown) {\n\t\t\treturn new NoPortNettyWebServer(httpServer, handlerAdapter, lifecycleTimeout, shutdown);\n\t\t}\n\n\t}\n\n\tstatic class NoPortNettyWebServer extends NettyWebServer {\n\n\t\tNoPortNettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter,\n\t\t\t\t@Nullable Duration lifecycleTimeout, @Nullable Shutdown shutdown) {\n\t\t\tsuper(httpServer, handlerAdapter, lifecycleTimeout, shutdown, null);\n\t\t}\n\n\t\t@Override\n\t\tDisposableServer startHttpServer() {\n\t\t\treturn new NoPortDisposableServer(super.startHttpServer());\n\t\t}\n\n\t}\n\n\tstatic class NoPortDisposableServer implements DisposableServer {\n\n\t\tprivate final DisposableServer delegate;\n\n\t\tNoPortDisposableServer(DisposableServer delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic SocketAddress address() {\n\t\t\treturn this.delegate.address();\n\t\t}\n\n\t\t@Override\n\t\tpublic String host() {\n\t\t\treturn this.delegate.host();\n\t\t}\n\n\t\t@Override\n\t\tpublic String path() {\n\t\t\treturn this.delegate.path();\n\t\t}\n\n\t\t@Override\n\t\tpublic Channel channel() {\n\t\t\treturn this.delegate.channel();\n\t\t}\n\n\t\t@Override\n\t\tpublic void dispose() {\n\t\t\tthis.delegate.dispose();\n\t\t}\n\n\t\t@Override\n\t\tpublic void disposeNow() {\n\t\t\tthis.delegate.disposeNow();\n\t\t}\n\n\t\t@Override\n\t\tpublic void disposeNow(Duration timeout) {\n\t\t\tthis.delegate.disposeNow(timeout);\n\t\t}\n\n\t\t@Override\n\t\tpublic CoreSubscriber<Void> disposeSubscriber() {\n\t\t\treturn this.delegate.disposeSubscriber();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isDisposed() {\n\t\t\treturn this.delegate.isDisposed();\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> onDispose() {\n\t\t\treturn this.delegate.onDispose();\n\t\t}\n\n\t\t@Override\n\t\tpublic DisposableChannel onDispose(Disposable onDispose) {\n\t\t\treturn this.delegate.onDispose(onDispose);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/autoconfigure/AutoConfigureWebServerReactorNettyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.reactor.netty.autoconfigure.AutoConfigureWebServerReactorNettyTests.ReactiveConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureWebServer @AutoConfigureWebServer} with Reactor Netty.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(classes = ReactiveConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.main.web-application-type=reactive\")\n@AutoConfigureWebServer\nclass AutoConfigureWebServerReactorNettyTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid startsTestServer() {\n\t\tRestTestClient restClient = RestTestClient.bindToServer().baseUrl(\"http://localhost:\" + this.port).build();\n\t\tassertThat(RestTestClientResponse.from(restClient.get().exchange())).bodyText().isEqualTo(\"hello\");\n\t}\n\n\t@Configuration\n\tstatic class ReactiveConfiguration {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn (request, response) -> {\n\t\t\t\tresponse.setStatusCode(HttpStatus.OK);\n\t\t\t\tDataBuffer dataBuffer = new DefaultDataBufferFactory().wrap(\"hello\".getBytes(StandardCharsets.UTF_8));\n\t\t\t\treturn response.writeWith(Mono.just(dataBuffer));\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.reactor.netty.NettyServerCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.reactive.AbstractReactiveWebServerAutoConfigurationTests;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NettyReactiveWebServerAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Raheela Aslam\n * @author Madhura Bhave\n * @author Scott Frederick\n * @author Daeho Kwon\n */\n// @DirtiesUrlFactories\nclass NettyReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {\n\n\tNettyReactiveWebServerAutoConfigurationTests() {\n\t\tsuper(NettyReactiveWebServerAutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid nettyServerCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(NettyServerCustomizerConfiguration.class).run((context) -> {\n\t\t\tNettyReactiveWebServerFactory factory = context.getBean(NettyReactiveWebServerFactory.class);\n\t\t\tassertThat(factory.getServerCustomizers())\n\t\t\t\t.contains(context.getBean(\"serverCustomizer\", NettyServerCustomizer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid nettyServerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationNettyServerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tNettyReactiveWebServerFactory factory = context.getBean(NettyReactiveWebServerFactory.class);\n\t\t\t\tNettyServerCustomizer customizer = context.getBean(\"serverCustomizer\", NettyServerCustomizer.class);\n\t\t\t\tassertThat(factory.getServerCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().apply(any(HttpServer.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationDoesNotApplyToNonWebApplication() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(NettyReactiveWebServerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveWebServerFactory.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NettyServerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tNettyServerCustomizer serverCustomizer() {\n\t\t\treturn (server) -> server;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationNettyServerCustomizerConfiguration {\n\n\t\tprivate final NettyServerCustomizer customizer = mock(NettyServerCustomizer.class);\n\n\t\tDoubleRegistrationNettyServerCustomizerConfiguration() {\n\t\t\tgiven(this.customizer.apply(any(HttpServer.class))).willAnswer((invocation) -> invocation.getArgument(0));\n\t\t}\n\n\t\t@Bean\n\t\tNettyServerCustomizer serverCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<NettyReactiveWebServerFactory> nettyCustomizer() {\n\t\t\treturn (netty) -> netty.addServerCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/autoconfigure/NettyReactiveWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Map;\n\nimport io.netty.channel.ChannelOption;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport reactor.netty.http.Http2SettingsSpec;\nimport reactor.netty.http.server.HttpRequestDecoderSpec;\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.reactor.netty.NettyServerCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link NettyReactiveWebServerFactoryCustomizer}.\n *\n * @author Brian Clozel\n * @author Artsiom Yudovin\n * @author Leo Li\n */\n@ExtendWith(MockitoExtension.class)\nclass NettyReactiveWebServerFactoryCustomizerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final ServerProperties serverProperties = new ServerProperties();\n\n\tprivate final NettyServerProperties nettyProperties = new NettyServerProperties();\n\n\tprivate NettyReactiveWebServerFactoryCustomizer customizer;\n\n\t@Captor\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ArgumentCaptor<NettyServerCustomizer> customizerCaptor;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tthis.customizer = new NettyReactiveWebServerFactoryCustomizer(this.environment, this.serverProperties,\n\t\t\t\tthis.nettyProperties);\n\t}\n\n\t@Test\n\tvoid deduceUseForwardHeaders() {\n\t\tthis.environment.setProperty(\"DYNO\", \"-\");\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(true);\n\t}\n\n\t@Test\n\tvoid defaultUseForwardHeaders() {\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(false);\n\t}\n\n\t@Test\n\tvoid forwardHeadersWhenStrategyIsNativeShouldConfigureValve() {\n\t\tthis.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NATIVE);\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(true);\n\t}\n\n\t@Test\n\tvoid forwardHeadersWhenStrategyIsNoneShouldNotConfigureValve() {\n\t\tthis.environment.setProperty(\"DYNO\", \"-\");\n\t\tthis.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NONE);\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setUseForwardHeaders(false);\n\t}\n\n\t@Test\n\tvoid setConnectionTimeout() {\n\t\tthis.nettyProperties.setConnectionTimeout(Duration.ofSeconds(1));\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tverifyConnectionTimeout(factory, 1000);\n\t}\n\n\t@Test\n\tvoid setIdleTimeout() {\n\t\tthis.nettyProperties.setIdleTimeout(Duration.ofSeconds(1));\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tverifyIdleTimeout(factory, Duration.ofSeconds(1));\n\t}\n\n\t@Test\n\tvoid setMaxKeepAliveRequests() {\n\t\tthis.nettyProperties.setMaxKeepAliveRequests(100);\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tverifyMaxKeepAliveRequests(factory, 100);\n\t}\n\n\t@Test\n\tvoid setHttp2MaxRequestHeaderSize() {\n\t\tDataSize headerSize = DataSize.ofKilobytes(24);\n\t\tthis.serverProperties.getHttp2().setEnabled(true);\n\t\tthis.serverProperties.setMaxHttpRequestHeaderSize(headerSize);\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tverifyHttp2MaxHeaderSize(factory, headerSize.toBytes());\n\t}\n\n\t@Test\n\tvoid configureHttpRequestDecoder() {\n\t\tNettyServerProperties nettyProperties = this.nettyProperties;\n\t\tthis.serverProperties.setMaxHttpRequestHeaderSize(DataSize.ofKilobytes(24));\n\t\tnettyProperties.setValidateHeaders(false);\n\t\tnettyProperties.setInitialBufferSize(DataSize.ofBytes(512));\n\t\tnettyProperties.setH2cMaxContentLength(DataSize.ofKilobytes(1));\n\t\tnettyProperties.setMaxInitialLineLength(DataSize.ofKilobytes(32));\n\t\tNettyReactiveWebServerFactory factory = mock(NettyReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().addServerCustomizers(this.customizerCaptor.capture());\n\t\tNettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);\n\t\tHttpServer httpServer = serverCustomizer.apply(HttpServer.create());\n\t\tHttpRequestDecoderSpec decoder = httpServer.configuration().decoder();\n\t\tassertThat(decoder.validateHeaders()).isFalse();\n\t\tassertThat(decoder.maxHeaderSize()).isEqualTo(this.serverProperties.getMaxHttpRequestHeaderSize().toBytes());\n\t\tassertThat(decoder.initialBufferSize()).isEqualTo(nettyProperties.getInitialBufferSize().toBytes());\n\t\tassertThat(decoder.h2cMaxContentLength()).isEqualTo(nettyProperties.getH2cMaxContentLength().toBytes());\n\t\tassertThat(decoder.maxInitialLineLength()).isEqualTo(nettyProperties.getMaxInitialLineLength().toBytes());\n\t}\n\n\tprivate void verifyConnectionTimeout(NettyReactiveWebServerFactory factory, Integer expected) {\n\t\tif (expected == null) {\n\t\t\tthen(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class));\n\t\t\treturn;\n\t\t}\n\t\tthen(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());\n\t\tNettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);\n\t\tHttpServer httpServer = serverCustomizer.apply(HttpServer.create());\n\t\tMap<ChannelOption<?>, ?> options = httpServer.configuration().options();\n\t\tassertThat(options.get(ChannelOption.CONNECT_TIMEOUT_MILLIS)).isEqualTo(expected);\n\t}\n\n\tprivate void verifyIdleTimeout(NettyReactiveWebServerFactory factory, Duration expected) {\n\t\tif (expected == null) {\n\t\t\tthen(factory).should(never()).addServerCustomizers(any(NettyServerCustomizer.class));\n\t\t\treturn;\n\t\t}\n\t\tthen(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());\n\t\tNettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);\n\t\tHttpServer httpServer = serverCustomizer.apply(HttpServer.create());\n\t\tDuration idleTimeout = httpServer.configuration().idleTimeout();\n\t\tassertThat(idleTimeout).isEqualTo(expected);\n\t}\n\n\tprivate void verifyMaxKeepAliveRequests(NettyReactiveWebServerFactory factory, int expected) {\n\t\tthen(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());\n\t\tNettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);\n\t\tHttpServer httpServer = serverCustomizer.apply(HttpServer.create());\n\t\tint maxKeepAliveRequests = httpServer.configuration().maxKeepAliveRequests();\n\t\tassertThat(maxKeepAliveRequests).isEqualTo(expected);\n\t}\n\n\tprivate void verifyHttp2MaxHeaderSize(NettyReactiveWebServerFactory factory, long expected) {\n\t\tthen(factory).should(times(2)).addServerCustomizers(this.customizerCaptor.capture());\n\t\tNettyServerCustomizer serverCustomizer = this.customizerCaptor.getAllValues().get(0);\n\t\tHttpServer httpServer = serverCustomizer.apply(HttpServer.create());\n\t\tHttp2SettingsSpec decoder = httpServer.configuration().http2SettingsSpec();\n\t\tassertThat(decoder).isNotNull();\n\t\tassertThat(decoder.maxHeaderListSize()).isEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/java/org/springframework/boot/reactor/netty/autoconfigure/NettyServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.reactor.netty.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.netty.http.HttpDecoderSpec;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link NettyServerProperties}.\n *\n * @author Andy Wilkinson\n */\nclass NettyServerPropertiesTests {\n\n\tprivate final NettyServerProperties properties = new NettyServerProperties();\n\n\t@Test\n\tvoid testCustomizeNettyIdleTimeout() {\n\t\tbind(\"server.netty.idle-timeout\", \"10s\");\n\t\tassertThat(this.properties.getIdleTimeout()).isEqualTo(Duration.ofSeconds(10));\n\t}\n\n\t@Test\n\tvoid testCustomizeNettyMaxKeepAliveRequests() {\n\t\tbind(\"server.netty.max-keep-alive-requests\", \"100\");\n\t\tassertThat(this.properties.getMaxKeepAliveRequests()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid nettyMaxInitialLineLengthMatchesHttpDecoderSpecDefault() {\n\t\tassertThat(this.properties.getMaxInitialLineLength().toBytes())\n\t\t\t.isEqualTo(HttpDecoderSpec.DEFAULT_MAX_INITIAL_LINE_LENGTH);\n\t}\n\n\t@Test\n\tvoid nettyValidateHeadersMatchesHttpDecoderSpecDefault() {\n\t\tassertThat(this.properties.isValidateHeaders()).isTrue();\n\t}\n\n\t@Test\n\tvoid nettyH2cMaxContentLengthMatchesHttpDecoderSpecDefault() {\n\t\tassertThat(this.properties.getH2cMaxContentLength().toBytes()).isZero();\n\t}\n\n\t@Test\n\tvoid nettyInitialBufferSizeMatchesHttpDecoderSpecDefault() {\n\t\tassertThat(this.properties.getInitialBufferSize().toBytes())\n\t\t\t.isEqualTo(HttpDecoderSpec.DEFAULT_INITIAL_BUFFER_SIZE);\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"server.netty\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/resources/org/springframework/boot/reactor/netty/1.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBLjCB4aADAgECAhQ25wrNnapZEkFc8kgf5NDHXKxnTzAFBgMrZXAwDDEKMAgG\nA1UEAwwBMTAgFw0yMzEwMTAwODU1MTJaGA8yMTIzMDkxNjA4NTUxMlowDDEKMAgG\nA1UEAwwBMTAqMAUGAytlcAMhAOyxNxHzcNj7xTkcjVLI09sYUGUGIvdV5s0YWXT8\nXAiwo1MwUTAdBgNVHQ4EFgQUmm23oLIu5MgdBb/snZSuE+MrRZ0wHwYDVR0jBBgw\nFoAUmm23oLIu5MgdBb/snZSuE+MrRZ0wDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXAD\nQQA2KMpIyySC8u4onW2MVW1iK2dJJZbMRaNMLlQuE+ZIHQLwflYW4sH/Pp76pboc\nQhqKXcO7xH7f2tD5hE2izcUB\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/resources/org/springframework/boot/reactor/netty/1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIJb1A+i5bmilBD9mUbhk1oFVI6FAZQGnhduv7xV6WWEc\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/resources/org/springframework/boot/reactor/netty/2.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBLjCB4aADAgECAhR4TMDk3qg5sKREp16lEHR3bV3M9zAFBgMrZXAwDDEKMAgG\nA1UEAwwBMjAgFw0yMzEwMTAwODU1MjBaGA8yMTIzMDkxNjA4NTUyMFowDDEKMAgG\nA1UEAwwBMjAqMAUGAytlcAMhADPft6hzyCjHCe5wSprChuuO/CuPIJ2t+l4roS1D\n43/wo1MwUTAdBgNVHQ4EFgQUfrRibAWml4Ous4kpnBIggM2xnLcwHwYDVR0jBBgw\nFoAUfrRibAWml4Ous4kpnBIggM2xnLcwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXAD\nQQC/MOclal2Cp0B3kmaLbK0M8mapclIOJa78hzBkqPA3URClAF2GmF187wHqi7qV\n+xZ+KWv26pLJR46vk8Kc6ZIO\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-reactor-netty/src/test/resources/org/springframework/boot/reactor/netty/2.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICxhres2Z2lICm7/isnm+2iNR12GmgG7KK86BNDZDeIF\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-restclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot RestClient and RestTemplate\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-http-client\"))\n\n\timplementation(project(\":module:spring-boot-http-converter\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(\"io.projectreactor.netty:reactor-netty-http\")\n\toptional(\"org.apache.httpcomponents.client5:httpclient5\")\n\toptional(\"org.eclipse.jetty:jetty-client\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-metrics-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestRuntimeOnly(\"org.springframework:spring-webflux\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/BasicAuthentication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.nio.charset.Charset;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.util.Assert;\n\n/**\n * Basic authentication details to be applied to {@link HttpHeaders}.\n *\n * @author Dmytro Nosan\n * @author Ilya Lukyanovich\n */\nclass BasicAuthentication {\n\n\tprivate final String username;\n\n\tprivate final String password;\n\n\tprivate final @Nullable Charset charset;\n\n\tBasicAuthentication(String username, String password, @Nullable Charset charset) {\n\t\tAssert.notNull(username, \"'username' must not be null\");\n\t\tAssert.notNull(password, \"'password' must not be null\");\n\t\tthis.username = username;\n\t\tthis.password = password;\n\t\tthis.charset = charset;\n\t}\n\n\tvoid applyTo(HttpHeaders headers) {\n\t\tif (!headers.containsHeader(HttpHeaders.AUTHORIZATION)) {\n\t\t\theaders.setBasicAuth(this.username, this.password, this.charset);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RestClientCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport org.springframework.web.client.RestClient;\n\n/**\n * Callback interface that can be used to customize a\n * {@link org.springframework.web.client.RestClient.Builder RestClient.Builder}.\n *\n * @author Arjen Poutsma\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RestClientCustomizer {\n\n\t/**\n\t * Callback to customize a {@link org.springframework.web.client.RestClient.Builder\n\t * RestClient.Builder} instance.\n\t * @param restClientBuilder the client builder to customize\n\t */\n\tvoid customize(RestClient.Builder restClientBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RestTemplateBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.nio.charset.Charset;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpCookieHandling;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpRequestInterceptor;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.client.ResponseErrorHandler;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * Builder that can be used to configure and create a {@link RestTemplate}. Provides\n * convenience methods to register {@link #messageConverters(HttpMessageConverter...)\n * converters}, {@link #errorHandler(ResponseErrorHandler) error handlers} and\n * {@link #uriTemplateHandler(UriTemplateHandler) UriTemplateHandlers}.\n * <p>\n * By default, the built {@link RestTemplate} will attempt to use the most suitable\n * {@link ClientHttpRequestFactory}, call {@link #detectRequestFactory(boolean)\n * detectRequestFactory(false)} if you prefer to keep the default. In a typical\n * auto-configured Spring Boot application this builder is available as a bean and can be\n * injected whenever a {@link RestTemplate} is needed.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @author Dmytro Nosan\n * @author Kevin Strijbos\n * @author Ilya Lukyanovich\n * @author Scott Frederick\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class RestTemplateBuilder {\n\n\tprivate final HttpClientSettings clientSettings;\n\n\tprivate final boolean detectRequestFactory;\n\n\tprivate final @Nullable String rootUri;\n\n\tprivate final @Nullable Set<HttpMessageConverter<?>> messageConverters;\n\n\tprivate final Set<ClientHttpRequestInterceptor> interceptors;\n\n\tprivate final @Nullable ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder;\n\n\tprivate final @Nullable UriTemplateHandler uriTemplateHandler;\n\n\tprivate final @Nullable ResponseErrorHandler errorHandler;\n\n\tprivate final @Nullable BasicAuthentication basicAuthentication;\n\n\tprivate final Map<String, List<String>> defaultHeaders;\n\n\tprivate final Set<RestTemplateCustomizer> customizers;\n\n\tprivate final Set<RestTemplateRequestCustomizer<?>> requestCustomizers;\n\n\t/**\n\t * Create a new {@link RestTemplateBuilder} instance.\n\t * @param customizers any {@link RestTemplateCustomizer RestTemplateCustomizers} that\n\t * should be applied when the {@link RestTemplate} is built\n\t */\n\tpublic RestTemplateBuilder(RestTemplateCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\tthis.clientSettings = HttpClientSettings.defaults();\n\t\tthis.detectRequestFactory = true;\n\t\tthis.rootUri = null;\n\t\tthis.messageConverters = null;\n\t\tthis.interceptors = Collections.emptySet();\n\t\tthis.requestFactoryBuilder = null;\n\t\tthis.uriTemplateHandler = null;\n\t\tthis.errorHandler = null;\n\t\tthis.basicAuthentication = null;\n\t\tthis.defaultHeaders = Collections.emptyMap();\n\t\tthis.customizers = copiedSetOf(customizers);\n\t\tthis.requestCustomizers = Collections.emptySet();\n\t}\n\n\tprivate RestTemplateBuilder(HttpClientSettings clientSettings, boolean detectRequestFactory,\n\t\t\t@Nullable String rootUri, @Nullable Set<HttpMessageConverter<?>> messageConverters,\n\t\t\tSet<ClientHttpRequestInterceptor> interceptors,\n\t\t\t@Nullable ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder,\n\t\t\t@Nullable UriTemplateHandler uriTemplateHandler, @Nullable ResponseErrorHandler errorHandler,\n\t\t\t@Nullable BasicAuthentication basicAuthentication, Map<String, List<String>> defaultHeaders,\n\t\t\tSet<RestTemplateCustomizer> customizers, Set<RestTemplateRequestCustomizer<?>> requestCustomizers) {\n\t\tthis.clientSettings = clientSettings;\n\t\tthis.detectRequestFactory = detectRequestFactory;\n\t\tthis.rootUri = rootUri;\n\t\tthis.messageConverters = messageConverters;\n\t\tthis.interceptors = interceptors;\n\t\tthis.requestFactoryBuilder = requestFactoryBuilder;\n\t\tthis.uriTemplateHandler = uriTemplateHandler;\n\t\tthis.errorHandler = errorHandler;\n\t\tthis.basicAuthentication = basicAuthentication;\n\t\tthis.defaultHeaders = defaultHeaders;\n\t\tthis.customizers = customizers;\n\t\tthis.requestCustomizers = requestCustomizers;\n\t}\n\n\t/**\n\t * Set a base URL template that should be applied to each request that starts with\n\t * {@code '/'}. The base URL will only apply when {@code String} variants of the\n\t * {@link RestTemplate} methods are used for specifying the request URL.\n\t * <p>\n\t * This is a specialization of {@link #uriTemplateHandler(UriTemplateHandler)} and\n\t * will override any previously configured uri template handler.\n\t * @param baseUri the base URI\n\t * @return a new builder instance\n\t * @since 4.1.0\n\t */\n\tpublic RestTemplateBuilder baseUri(String baseUri) {\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tnew DefaultUriBuilderFactory(baseUri), this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set if the {@link ClientHttpRequestFactory} should be detected based on the\n\t * classpath. Default if {@code true}.\n\t * @param detectRequestFactory if the {@link ClientHttpRequestFactory} should be\n\t * detected\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) {\n\t\treturn new RestTemplateBuilder(this.clientSettings, detectRequestFactory, this.rootUri, this.messageConverters,\n\t\t\t\tthis.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler, this.errorHandler,\n\t\t\t\tthis.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set a root URL that should be applied to each request that starts with {@code '/'}.\n\t * The root URL will only apply when {@code String} variants of the\n\t * {@link RestTemplate} methods are used for specifying the request URL.\n\t * @param rootUri the root URI or {@code null}\n\t * @return a new builder instance\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of {@link #baseUri(String)}\n\t */\n\t@Deprecated(forRemoval = true, since = \"4.1.0\")\n\tpublic RestTemplateBuilder rootUri(@Nullable String rootUri) {\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, rootUri, this.messageConverters,\n\t\t\t\tthis.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler, this.errorHandler,\n\t\t\t\tthis.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with\n\t * the {@link RestTemplate}. Setting this value will replace any previously configured\n\t * converters and any converters configured on the builder will replace RestTemplate's\n\t * default converters.\n\t * @param messageConverters the converters to set\n\t * @return a new builder instance\n\t * @see #additionalMessageConverters(HttpMessageConverter...)\n\t */\n\tpublic RestTemplateBuilder messageConverters(HttpMessageConverter<?>... messageConverters) {\n\t\tAssert.notNull(messageConverters, \"'messageConverters' must not be null\");\n\t\treturn messageConverters(Arrays.asList(messageConverters));\n\t}\n\n\t/**\n\t * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with\n\t * the {@link RestTemplate}. Setting this value will replace any previously configured\n\t * converters and any converters configured on the builder will replace RestTemplate's\n\t * default converters.\n\t * @param messageConverters the converters to set\n\t * @return a new builder instance\n\t * @see #additionalMessageConverters(HttpMessageConverter...)\n\t */\n\tpublic RestTemplateBuilder messageConverters(Iterable<? extends HttpMessageConverter<?>> messageConverters) {\n\t\tAssert.notNull(messageConverters, \"'messageConverters' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tcopiedSetOf(messageConverters), this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,\n\t\t\t\tthis.requestCustomizers);\n\t}\n\n\t/**\n\t * Add additional {@link HttpMessageConverter HttpMessageConverters} that should be\n\t * used with the {@link RestTemplate}. Any converters configured on the builder will\n\t * replace RestTemplate's default converters.\n\t * @param messageConverters the converters to add\n\t * @return a new builder instance\n\t * @see #messageConverters(HttpMessageConverter...)\n\t */\n\tpublic RestTemplateBuilder additionalMessageConverters(HttpMessageConverter<?>... messageConverters) {\n\t\tAssert.notNull(messageConverters, \"'messageConverters' must not be null\");\n\t\treturn additionalMessageConverters(Arrays.asList(messageConverters));\n\t}\n\n\t/**\n\t * Add additional {@link HttpMessageConverter HttpMessageConverters} that should be\n\t * used with the {@link RestTemplate}. Any converters configured on the builder will\n\t * replace RestTemplate's default converters.\n\t * @param messageConverters the converters to add\n\t * @return a new builder instance\n\t * @see #messageConverters(HttpMessageConverter...)\n\t */\n\tpublic RestTemplateBuilder additionalMessageConverters(\n\t\t\tCollection<? extends HttpMessageConverter<?>> messageConverters) {\n\t\tAssert.notNull(messageConverters, \"'messageConverters' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tappend(this.messageConverters, messageConverters), this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with\n\t * the {@link RestTemplate} to the default set. Calling this method will replace any\n\t * previously defined converters.\n\t * @return a new builder instance\n\t * @see #messageConverters(HttpMessageConverter...)\n\t */\n\tpublic RestTemplateBuilder defaultMessageConverters() {\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tcopiedSetOf(new RestTemplate().getMessageConverters()), this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} that\n\t * should be used with the {@link RestTemplate}. Setting this value will replace any\n\t * previously defined interceptors.\n\t * @param interceptors the interceptors to set\n\t * @return a new builder instance\n\t * @see #additionalInterceptors(ClientHttpRequestInterceptor...)\n\t */\n\tpublic RestTemplateBuilder interceptors(ClientHttpRequestInterceptor... interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn interceptors(Arrays.asList(interceptors));\n\t}\n\n\t/**\n\t * Set the {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} that\n\t * should be used with the {@link RestTemplate}. Setting this value will replace any\n\t * previously defined interceptors.\n\t * @param interceptors the interceptors to set\n\t * @return a new builder instance\n\t * @see #additionalInterceptors(ClientHttpRequestInterceptor...)\n\t */\n\tpublic RestTemplateBuilder interceptors(Collection<ClientHttpRequestInterceptor> interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, copiedSetOf(interceptors), this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,\n\t\t\t\tthis.requestCustomizers);\n\t}\n\n\t/**\n\t * Add additional {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors}\n\t * that should be used with the {@link RestTemplate}.\n\t * @param interceptors the interceptors to add\n\t * @return a new builder instance\n\t * @see #interceptors(ClientHttpRequestInterceptor...)\n\t */\n\tpublic RestTemplateBuilder additionalInterceptors(ClientHttpRequestInterceptor... interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn additionalInterceptors(Arrays.asList(interceptors));\n\t}\n\n\t/**\n\t * Add additional {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors}\n\t * that should be used with the {@link RestTemplate}.\n\t * @param interceptors the interceptors to add\n\t * @return a new builder instance\n\t * @see #interceptors(ClientHttpRequestInterceptor...)\n\t */\n\tpublic RestTemplateBuilder additionalInterceptors(Collection<? extends ClientHttpRequestInterceptor> interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, append(this.interceptors, interceptors), this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link ClientHttpRequestFactory} class that should be used with the\n\t * {@link RestTemplate}.\n\t * @param requestFactoryType the request factory type to use\n\t * @return a new builder instance\n\t * @see ClientHttpRequestFactoryBuilder#of(Class)\n\t * @see #requestFactoryBuilder(ClientHttpRequestFactoryBuilder)\n\t */\n\tpublic RestTemplateBuilder requestFactory(Class<? extends ClientHttpRequestFactory> requestFactoryType) {\n\t\tAssert.notNull(requestFactoryType, \"'requestFactoryType' must not be null\");\n\t\treturn requestFactoryBuilder(ClientHttpRequestFactoryBuilder.of(requestFactoryType));\n\t}\n\n\t/**\n\t * Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called\n\t * each time we {@link #build()} a new {@link RestTemplate} instance.\n\t * @param requestFactorySupplier the supplier for the request factory\n\t * @return a new builder instance\n\t * @see ClientHttpRequestFactoryBuilder#of(Supplier)\n\t * @see #requestFactoryBuilder(ClientHttpRequestFactoryBuilder)\n\t */\n\tpublic RestTemplateBuilder requestFactory(Supplier<ClientHttpRequestFactory> requestFactorySupplier) {\n\t\tAssert.notNull(requestFactorySupplier, \"'requestFactorySupplier' must not be null\");\n\t\treturn requestFactoryBuilder(ClientHttpRequestFactoryBuilder.of(requestFactorySupplier));\n\t}\n\n\t/**\n\t * Set the {@link ClientHttpRequestFactoryBuilder} that should be used each time we\n\t * {@link #build()} a new {@link RestTemplate} instance.\n\t * @param requestFactoryBuilder the {@link ClientHttpRequestFactoryBuilder} to use\n\t * @return a new builder instance\n\t * @see ClientHttpRequestFactoryBuilder\n\t */\n\tpublic RestTemplateBuilder requestFactoryBuilder(ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder) {\n\t\tAssert.notNull(requestFactoryBuilder, \"'requestFactoryBuilder' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,\n\t\t\t\tthis.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link UriTemplateHandler} that should be used with the\n\t * {@link RestTemplate}.\n\t * <p>\n\t * This method will override any {@link #baseUri(String)} previously set.\n\t * @param uriTemplateHandler the URI template handler to use\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHandler) {\n\t\tAssert.notNull(uriTemplateHandler, \"'uriTemplateHandler' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,\n\t\t\t\tthis.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link ResponseErrorHandler} that should be used with the\n\t * {@link RestTemplate}.\n\t * @param errorHandler the error handler to use\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) {\n\t\tAssert.notNull(errorHandler, \"'errorHandler' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\terrorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Add HTTP Basic Authentication to requests with the given username/password pair,\n\t * unless a custom Authorization header has been set before.\n\t * @param username the user name\n\t * @param password the password\n\t * @return a new builder instance\n\t * @see #basicAuthentication(String, String, Charset)\n\t */\n\tpublic RestTemplateBuilder basicAuthentication(String username, String password) {\n\t\treturn basicAuthentication(username, password, null);\n\t}\n\n\t/**\n\t * Add HTTP Basic Authentication to requests with the given username/password pair,\n\t * unless a custom Authorization header has been set before.\n\t * @param username the user name\n\t * @param password the password\n\t * @param charset the charset to use\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder basicAuthentication(String username, String password, @Nullable Charset charset) {\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, new BasicAuthentication(username, password, charset), this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Add a default header that will be set if not already present on the outgoing\n\t * {@link ClientHttpRequest}.\n\t * @param name the name of the header\n\t * @param values the header values\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder defaultHeader(String name, String... values) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(values, \"'values' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, append(this.defaultHeaders, name, values),\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Sets the {@link HttpClientSettings}. This will replace any previously set\n\t * {@link #connectTimeout(Duration) connectTimeout}, {@link #readTimeout(Duration)\n\t * readTimeout} and {@link #sslBundle(SslBundle) sslBundle} values.\n\t * @param clientSettings the client settings\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder clientSettings(HttpClientSettings clientSettings) {\n\t\tAssert.notNull(clientSettings, \"'clientSettings' must not be null\");\n\t\treturn new RestTemplateBuilder(clientSettings, this.detectRequestFactory, this.rootUri, this.messageConverters,\n\t\t\t\tthis.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler, this.errorHandler,\n\t\t\t\tthis.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Update the {@link HttpClientSettings} using the given customizer.\n\t * @param clientSettingsCustomizer a {@link UnaryOperator} to update client factory\n\t * settings\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder clientSettings(UnaryOperator<HttpClientSettings> clientSettingsCustomizer) {\n\t\tAssert.notNull(clientSettingsCustomizer, \"'clientSettingsCustomizer' must not be null\");\n\t\treturn new RestTemplateBuilder(clientSettingsCustomizer.apply(this.clientSettings), this.detectRequestFactory,\n\t\t\t\tthis.rootUri, this.messageConverters, this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Sets the connection timeout on the underlying {@link ClientHttpRequestFactory}.\n\t * @param connectTimeout the connection timeout\n\t * @return a new builder instance.\n\t */\n\tpublic RestTemplateBuilder connectTimeout(Duration connectTimeout) {\n\t\treturn new RestTemplateBuilder(this.clientSettings.withConnectTimeout(connectTimeout),\n\t\t\t\tthis.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors,\n\t\t\t\tthis.requestFactoryBuilder, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication,\n\t\t\t\tthis.defaultHeaders, this.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Sets the read timeout on the underlying {@link ClientHttpRequestFactory}.\n\t * @param readTimeout the read timeout\n\t * @return a new builder instance.\n\t */\n\tpublic RestTemplateBuilder readTimeout(Duration readTimeout) {\n\t\treturn new RestTemplateBuilder(this.clientSettings.withReadTimeout(readTimeout), this.detectRequestFactory,\n\t\t\t\tthis.rootUri, this.messageConverters, this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Sets the cookie handling strategy on the underlying\n\t * {@link ClientHttpRequestFactory}.\n\t * @param cookieHandling the cookie handling strategy\n\t * @return a new builder instance.\n\t * @since 4.1.0\n\t */\n\tpublic RestTemplateBuilder cookieHandling(HttpCookieHandling cookieHandling) {\n\t\treturn new RestTemplateBuilder(this.clientSettings.withCookieHandling(cookieHandling),\n\t\t\t\tthis.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors,\n\t\t\t\tthis.requestFactoryBuilder, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication,\n\t\t\t\tthis.defaultHeaders, this.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Sets the redirect strategy on the underlying {@link ClientHttpRequestFactory}.\n\t * @param redirects the redirect strategy\n\t * @return a new builder instance.\n\t */\n\tpublic RestTemplateBuilder redirects(HttpRedirects redirects) {\n\t\treturn new RestTemplateBuilder(this.clientSettings.withRedirects(redirects), this.detectRequestFactory,\n\t\t\t\tthis.rootUri, this.messageConverters, this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Sets the SSL bundle on the underlying {@link ClientHttpRequestFactory}.\n\t * @param sslBundle the SSL bundle\n\t * @return a new builder instance\n\t */\n\tpublic RestTemplateBuilder sslBundle(SslBundle sslBundle) {\n\t\treturn new RestTemplateBuilder(this.clientSettings.withSslBundle(sslBundle), this.detectRequestFactory,\n\t\t\t\tthis.rootUri, this.messageConverters, this.interceptors, this.requestFactoryBuilder,\n\t\t\t\tthis.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,\n\t\t\t\tthis.customizers, this.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be\n\t * applied to the {@link RestTemplate}. Customizers are applied in the order that they\n\t * were added after builder configuration has been applied. Setting this value will\n\t * replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(RestTemplateCustomizer...)\n\t */\n\tpublic RestTemplateBuilder customizers(RestTemplateCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn customizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Set the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be\n\t * applied to the {@link RestTemplate}. Customizers are applied in the order that they\n\t * were added after builder configuration has been applied. Setting this value will\n\t * replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(RestTemplateCustomizer...)\n\t */\n\tpublic RestTemplateBuilder customizers(Collection<? extends RestTemplateCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, copiedSetOf(customizers),\n\t\t\t\tthis.requestCustomizers);\n\t}\n\n\t/**\n\t * Add {@link RestTemplateCustomizer RestTemplateCustomizers} that should be applied\n\t * to the {@link RestTemplate}. Customizers are applied in the order that they were\n\t * added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(RestTemplateCustomizer...)\n\t */\n\tpublic RestTemplateBuilder additionalCustomizers(RestTemplateCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn additionalCustomizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Add {@link RestTemplateCustomizer RestTemplateCustomizers} that should be applied\n\t * to the {@link RestTemplate}. Customizers are applied in the order that they were\n\t * added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(RestTemplateCustomizer...)\n\t */\n\tpublic RestTemplateBuilder additionalCustomizers(Collection<? extends RestTemplateCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, append(this.customizers, customizers),\n\t\t\t\tthis.requestCustomizers);\n\t}\n\n\t/**\n\t * Set the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that\n\t * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the\n\t * order that they were added. Setting this value will replace any previously\n\t * configured request customizers.\n\t * @param requestCustomizers the request customizers to set\n\t * @return a new builder instance\n\t * @see #additionalRequestCustomizers(RestTemplateRequestCustomizer...)\n\t */\n\tpublic RestTemplateBuilder requestCustomizers(RestTemplateRequestCustomizer<?>... requestCustomizers) {\n\t\tAssert.notNull(requestCustomizers, \"'requestCustomizers' must not be null\");\n\t\treturn requestCustomizers(Arrays.asList(requestCustomizers));\n\t}\n\n\t/**\n\t * Set the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that\n\t * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the\n\t * order that they were added. Setting this value will replace any previously\n\t * configured request customizers.\n\t * @param requestCustomizers the request customizers to set\n\t * @return a new builder instance\n\t * @see #additionalRequestCustomizers(RestTemplateRequestCustomizer...)\n\t */\n\tpublic RestTemplateBuilder requestCustomizers(\n\t\t\tCollection<? extends RestTemplateRequestCustomizer<?>> requestCustomizers) {\n\t\tAssert.notNull(requestCustomizers, \"'requestCustomizers' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,\n\t\t\t\tcopiedSetOf(requestCustomizers));\n\t}\n\n\t/**\n\t * Add the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that\n\t * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the\n\t * order that they were added.\n\t * @param requestCustomizers the request customizers to add\n\t * @return a new builder instance\n\t * @see #requestCustomizers(RestTemplateRequestCustomizer...)\n\t */\n\tpublic RestTemplateBuilder additionalRequestCustomizers(RestTemplateRequestCustomizer<?>... requestCustomizers) {\n\t\tAssert.notNull(requestCustomizers, \"'requestCustomizers' must not be null\");\n\t\treturn additionalRequestCustomizers(Arrays.asList(requestCustomizers));\n\t}\n\n\t/**\n\t * Add the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that\n\t * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the\n\t * order that they were added.\n\t * @param requestCustomizers the request customizers to add\n\t * @return a new builder instance\n\t * @see #requestCustomizers(Collection)\n\t */\n\tpublic RestTemplateBuilder additionalRequestCustomizers(\n\t\t\tCollection<? extends RestTemplateRequestCustomizer<?>> requestCustomizers) {\n\t\tAssert.notNull(requestCustomizers, \"'requestCustomizers' must not be null\");\n\t\treturn new RestTemplateBuilder(this.clientSettings, this.detectRequestFactory, this.rootUri,\n\t\t\t\tthis.messageConverters, this.interceptors, this.requestFactoryBuilder, this.uriTemplateHandler,\n\t\t\t\tthis.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,\n\t\t\t\tappend(this.requestCustomizers, requestCustomizers));\n\t}\n\n\t/**\n\t * Build a new {@link RestTemplate} instance and configure it using this builder.\n\t * @return a configured {@link RestTemplate} instance.\n\t * @see #build(Class)\n\t * @see #configure(RestTemplate)\n\t */\n\tpublic RestTemplate build() {\n\t\treturn configure(new RestTemplate());\n\t}\n\n\t/**\n\t * Build a new {@link RestTemplate} instance of the specified type and configure it\n\t * using this builder.\n\t * @param <T> the type of rest template\n\t * @param restTemplateClass the template type to create\n\t * @return a configured {@link RestTemplate} instance.\n\t * @see RestTemplateBuilder#build()\n\t * @see #configure(RestTemplate)\n\t */\n\tpublic <T extends RestTemplate> T build(Class<T> restTemplateClass) {\n\t\treturn configure(BeanUtils.instantiateClass(restTemplateClass));\n\t}\n\n\t/**\n\t * Configure the provided {@link RestTemplate} instance using this builder.\n\t * @param <T> the type of rest template\n\t * @param restTemplate the {@link RestTemplate} to configure\n\t * @return the rest template instance\n\t * @see RestTemplateBuilder#build()\n\t * @see RestTemplateBuilder#build(Class)\n\t */\n\t@SuppressWarnings(\"removal\")\n\tpublic <T extends RestTemplate> T configure(T restTemplate) {\n\t\tClientHttpRequestFactory requestFactory = buildRequestFactory();\n\t\tif (requestFactory != null) {\n\t\t\trestTemplate.setRequestFactory(requestFactory);\n\t\t}\n\t\taddClientHttpRequestInitializer(restTemplate);\n\t\tif (!CollectionUtils.isEmpty(this.messageConverters)) {\n\t\t\trestTemplate.setMessageConverters(new ArrayList<>(this.messageConverters));\n\t\t}\n\t\tif (this.uriTemplateHandler != null) {\n\t\t\trestTemplate.setUriTemplateHandler(this.uriTemplateHandler);\n\t\t}\n\t\tif (this.errorHandler != null) {\n\t\t\trestTemplate.setErrorHandler(this.errorHandler);\n\t\t}\n\t\tif (this.rootUri != null) {\n\t\t\tRootUriBuilderFactory.applyTo(restTemplate, this.rootUri);\n\t\t}\n\t\trestTemplate.getInterceptors().addAll(this.interceptors);\n\t\tif (!CollectionUtils.isEmpty(this.customizers)) {\n\t\t\tfor (RestTemplateCustomizer customizer : this.customizers) {\n\t\t\t\tcustomizer.customize(restTemplate);\n\t\t\t}\n\t\t}\n\t\treturn restTemplate;\n\t}\n\n\t/**\n\t * Build a new {@link ClientHttpRequestFactory} instance using the settings of this\n\t * builder.\n\t * @return a {@link ClientHttpRequestFactory} or {@code null}\n\t */\n\tpublic @Nullable ClientHttpRequestFactory buildRequestFactory() {\n\t\tClientHttpRequestFactoryBuilder<?> requestFactoryBuilder = requestFactoryBuilder();\n\t\treturn (requestFactoryBuilder != null) ? requestFactoryBuilder.build(this.clientSettings) : null;\n\t}\n\n\t/**\n\t * Return a {@link ClientHttpRequestFactoryBuilder} instance using the settings of\n\t * this builder.\n\t * @return a {@link ClientHttpRequestFactoryBuilder} or {@code null}\n\t */\n\tpublic @Nullable ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder() {\n\t\tif (this.requestFactoryBuilder != null) {\n\t\t\treturn this.requestFactoryBuilder;\n\t\t}\n\t\tif (this.detectRequestFactory) {\n\t\t\treturn ClientHttpRequestFactoryBuilder.detect();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void addClientHttpRequestInitializer(RestTemplate restTemplate) {\n\t\tif (this.basicAuthentication == null && this.defaultHeaders.isEmpty() && this.requestCustomizers.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\trestTemplate.getClientHttpRequestInitializers()\n\t\t\t.add(new RestTemplateBuilderClientHttpRequestInitializer(this.basicAuthentication, this.defaultHeaders,\n\t\t\t\t\tthis.requestCustomizers));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> Set<T> copiedSetOf(T... items) {\n\t\treturn copiedSetOf(Arrays.asList(items));\n\t}\n\n\tprivate <T> Set<T> copiedSetOf(Iterable<? extends T> collection) {\n\t\tLinkedHashSet<T> set = new LinkedHashSet<>();\n\t\tcollection.forEach(set::add);\n\t\treturn Collections.unmodifiableSet(set);\n\t}\n\n\tprivate static <T> List<T> copiedListOf(T[] items) {\n\t\treturn Collections.unmodifiableList(Arrays.asList(Arrays.copyOf(items, items.length)));\n\t}\n\n\tprivate static <T> Set<T> append(@Nullable Collection<? extends T> collection,\n\t\t\t@Nullable Collection<? extends T> additions) {\n\t\tSet<T> result = new LinkedHashSet<>((collection != null) ? collection : Collections.emptySet());\n\t\tif (additions != null) {\n\t\t\tresult.addAll(additions);\n\t\t}\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n\tprivate static <K, V> Map<K, List<V>> append(@Nullable Map<K, List<V>> map, K key, V @Nullable [] values) {\n\t\tMap<K, List<V>> result = new LinkedHashMap<>((map != null) ? map : Collections.emptyMap());\n\t\tif (values != null) {\n\t\t\tresult.put(key, copiedListOf(values));\n\t\t}\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RestTemplateBuilderClientHttpRequestInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestInitializer;\n\n/**\n * {@link ClientHttpRequestInitializer} to apply customizations from the\n * {@link RestTemplateBuilder}.\n *\n * @author Dmytro Nosan\n * @author Ilya Lukyanovich\n */\nclass RestTemplateBuilderClientHttpRequestInitializer implements ClientHttpRequestInitializer {\n\n\tprivate final @Nullable BasicAuthentication basicAuthentication;\n\n\tprivate final Map<String, List<String>> defaultHeaders;\n\n\tprivate final Set<RestTemplateRequestCustomizer<?>> requestCustomizers;\n\n\tRestTemplateBuilderClientHttpRequestInitializer(@Nullable BasicAuthentication basicAuthentication,\n\t\t\tMap<String, List<String>> defaultHeaders, Set<RestTemplateRequestCustomizer<?>> requestCustomizers) {\n\t\tthis.basicAuthentication = basicAuthentication;\n\t\tthis.defaultHeaders = defaultHeaders;\n\t\tthis.requestCustomizers = requestCustomizers;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void initialize(ClientHttpRequest request) {\n\t\tHttpHeaders headers = request.getHeaders();\n\t\tif (this.basicAuthentication != null) {\n\t\t\tthis.basicAuthentication.applyTo(headers);\n\t\t}\n\t\tthis.defaultHeaders.forEach(headers::putIfAbsent);\n\t\tLambdaSafe.callbacks(RestTemplateRequestCustomizer.class, this.requestCustomizers, request)\n\t\t\t.invoke((customizer) -> customizer.customize(request));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RestTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Callback interface that can be used to customize a {@link RestTemplate}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see RestTemplateBuilder\n */\n@FunctionalInterface\npublic interface RestTemplateCustomizer {\n\n\t/**\n\t * Callback to customize a {@link RestTemplate} instance.\n\t * @param restTemplate the template to customize\n\t */\n\tvoid customize(RestTemplate restTemplate);\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RestTemplateRequestCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestInitializer;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Callback interface that can be used to customize the {@link ClientHttpRequest} sent\n * from a {@link RestTemplate}.\n *\n * @param <T> the {@link ClientHttpRequest} type\n * @author Ilya Lukyanovich\n * @author Phillip Webb\n * @since 4.0.0\n * @see RestTemplateBuilder\n * @see ClientHttpRequestInitializer\n */\n@FunctionalInterface\npublic interface RestTemplateRequestCustomizer<T extends ClientHttpRequest> {\n\n\t/**\n\t * Customize the specified {@link ClientHttpRequest}.\n\t * @param request the request to customize\n\t */\n\tvoid customize(T request);\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RootUriBuilderFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriBuilder;\nimport org.springframework.web.util.UriBuilderFactory;\nimport org.springframework.web.util.UriComponentsBuilder;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * {@link UriBuilderFactory} to set the root for URI that starts with {@code '/'}.\n *\n * @author Scott Frederick\n * @since 4.0.0\n * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n * {@link DefaultUriBuilderFactory}.\n */\n@Deprecated(forRemoval = true, since = \"4.1.0\")\n@SuppressWarnings(\"removal\")\npublic class RootUriBuilderFactory extends RootUriTemplateHandler implements UriBuilderFactory {\n\n\t/**\n\t * Create an instance with the root URI to use.\n\t * @param rootUri the root URI\n\t * @param delegate the {@link UriTemplateHandler} to delegate to\n\t */\n\tpublic RootUriBuilderFactory(String rootUri, UriTemplateHandler delegate) {\n\t\tsuper(rootUri, delegate);\n\t}\n\n\t@Override\n\tpublic UriBuilder uriString(String uriTemplate) {\n\t\treturn UriComponentsBuilder.fromUriString(apply(uriTemplate));\n\t}\n\n\t@Override\n\tpublic UriBuilder builder() {\n\t\treturn UriComponentsBuilder.newInstance();\n\t}\n\n\t/**\n\t * Apply a {@link RootUriBuilderFactory} instance to the given {@link RestTemplate}.\n\t * @param restTemplate the {@link RestTemplate} to add the builder factory to\n\t * @param rootUri the root URI\n\t */\n\tstatic void applyTo(RestTemplate restTemplate, String rootUri) {\n\t\tAssert.notNull(restTemplate, \"'restTemplate' must not be null\");\n\t\tRootUriBuilderFactory handler = new RootUriBuilderFactory(rootUri, restTemplate.getUriTemplateHandler());\n\t\trestTemplate.setUriTemplateHandler(handler);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/RootUriTemplateHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.net.URI;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * {@link UriTemplateHandler} to set the root for URI that starts with {@code '/'}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n * {@link DefaultUriBuilderFactory}.\n */\n@Deprecated(forRemoval = true, since = \"4.1.0\")\npublic class RootUriTemplateHandler implements UriTemplateHandler {\n\n\tprivate final @Nullable String rootUri;\n\n\tprivate final UriTemplateHandler handler;\n\n\tprotected RootUriTemplateHandler(UriTemplateHandler handler) {\n\t\tAssert.notNull(handler, \"'handler' must not be null\");\n\t\tthis.rootUri = null;\n\t\tthis.handler = handler;\n\t}\n\n\tRootUriTemplateHandler(String rootUri, UriTemplateHandler handler) {\n\t\tAssert.notNull(rootUri, \"'rootUri' must not be null\");\n\t\tAssert.notNull(handler, \"'handler' must not be null\");\n\t\tthis.rootUri = rootUri;\n\t\tthis.handler = handler;\n\t}\n\n\t@Override\n\tpublic URI expand(String uriTemplate, Map<String, ?> uriVariables) {\n\t\treturn this.handler.expand(apply(uriTemplate), uriVariables);\n\t}\n\n\t@Override\n\tpublic URI expand(String uriTemplate, @Nullable Object... uriVariables) {\n\t\treturn this.handler.expand(apply(uriTemplate), uriVariables);\n\t}\n\n\tString apply(String uriTemplate) {\n\t\tString rootUri = getRootUri();\n\t\tif (rootUri != null && StringUtils.startsWithIgnoreCase(uriTemplate, \"/\")) {\n\t\t\treturn getRootUri() + uriTemplate;\n\t\t}\n\t\treturn uriTemplate;\n\t}\n\n\tpublic @Nullable String getRootUri() {\n\t\treturn this.rootUri;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/AutoConfiguredRestClientSsl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.web.client.RestClient;\n\n/**\n * An auto-configured {@link RestClientSsl} implementation.\n *\n * @author Phillip Webb\n * @author Dmytro Nosan\n */\nclass AutoConfiguredRestClientSsl implements RestClientSsl {\n\n\tprivate final ClientHttpRequestFactoryBuilder<?> builder;\n\n\tprivate final HttpClientSettings settings;\n\n\tprivate final SslBundles sslBundles;\n\n\tAutoConfiguredRestClientSsl(ClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder,\n\t\t\tHttpClientSettings settings, SslBundles sslBundles) {\n\t\tthis.builder = clientHttpRequestFactoryBuilder;\n\t\tthis.settings = settings;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic Consumer<RestClient.Builder> fromBundle(String bundleName) {\n\t\treturn fromBundle(this.sslBundles.getBundle(bundleName));\n\t}\n\n\t@Override\n\tpublic Consumer<RestClient.Builder> fromBundle(SslBundle bundle) {\n\t\treturn (builder) -> builder.requestFactory(requestFactory(bundle));\n\t}\n\n\tprivate ClientHttpRequestFactory requestFactory(SslBundle bundle) {\n\t\treturn this.builder.build(this.settings.withSslBundle(bundle));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/HttpMessageConvertersRestClientCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestClient;\n\n/**\n * {@link RestClientCustomizer} to apply {@link HttpMessageConverter\n * HttpMessageConverters}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class HttpMessageConvertersRestClientCustomizer implements RestClientCustomizer {\n\n\tprivate final List<ClientHttpMessageConvertersCustomizer> customizers;\n\n\tpublic HttpMessageConvertersRestClientCustomizer(ClientHttpMessageConvertersCustomizer... customizers) {\n\t\tthis(Arrays.asList(customizers));\n\t}\n\n\tpublic HttpMessageConvertersRestClientCustomizer(List<ClientHttpMessageConvertersCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"customizers must not be null\");\n\t\tthis.customizers = customizers;\n\t}\n\n\t@Override\n\tpublic void customize(RestClient.Builder restClientBuilder) {\n\t\trestClientBuilder.configureMessageConverters(\n\t\t\t\t(builder) -> this.customizers.forEach((customizer) -> customizer.customize(builder)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/NotReactiveWebApplicationCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\n\n/**\n * {@link SpringBootCondition} that applies only when running in a non-reactive web\n * application.\n *\n * @author Phillip Webb\n */\nclass NotReactiveWebApplicationCondition extends NoneNestedConditions {\n\n\tNotReactiveWebApplicationCondition() {\n\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t}\n\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\tprivate static final class ReactiveWebApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link RestClient}.\n * <p>\n * This will produce a {@link Builder RestClient.Builder} bean with the {@code prototype}\n * scope, meaning each injection point will receive a newly cloned instance of the\n * builder.\n *\n * @author Arjen Poutsma\n * @author Moritz Halbritter\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = { ImperativeHttpClientAutoConfiguration.class, TaskExecutionAutoConfiguration.class,\n\t\tSslAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class })\n@ConditionalOnClass(RestClient.class)\npublic final class RestClientAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(RestClientSsl.class)\n\t@ConditionalOnBean(SslBundles.class)\n\tAutoConfiguredRestClientSsl restClientSsl(ResourceLoader resourceLoader,\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings, SslBundles sslBundles) {\n\t\tClassLoader classLoader = resourceLoader.getClassLoader();\n\t\treturn new AutoConfiguredRestClientSsl(\n\t\t\t\tclientHttpRequestFactoryBuilder\n\t\t\t\t\t.getIfAvailable(() -> ClientHttpRequestFactoryBuilder.detect(classLoader)),\n\t\t\t\thttpClientSettings.getIfAvailable(HttpClientSettings::defaults), sslBundles);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tRestClientBuilderConfigurer restClientBuilderConfigurer(ResourceLoader resourceLoader,\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings,\n\t\t\tObjectProvider<RestClientCustomizer> customizerProvider) {\n\t\treturn new RestClientBuilderConfigurer(\n\t\t\t\tclientHttpRequestFactoryBuilder\n\t\t\t\t\t.getIfAvailable(() -> ClientHttpRequestFactoryBuilder.detect(resourceLoader.getClassLoader())),\n\t\t\t\thttpClientSettings.getIfAvailable(HttpClientSettings::defaults),\n\t\t\t\tcustomizerProvider.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnMissingBean\n\tRestClient.Builder restClientBuilder(RestClientBuilderConfigurer restClientBuilderConfigurer) {\n\t\treturn restClientBuilderConfigurer.configure(RestClient.builder());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HttpMessageConverters.class)\n\tstatic class HttpMessageConvertersConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnBean(ClientHttpMessageConvertersCustomizer.class)\n\t\t@Order(Ordered.LOWEST_PRECEDENCE)\n\t\tHttpMessageConvertersRestClientCustomizer httpMessageConvertersRestClientCustomizer(\n\t\t\t\tObjectProvider<ClientHttpMessageConvertersCustomizer> customizerProvider) {\n\t\t\treturn new HttpMessageConvertersRestClientCustomizer(customizerProvider.orderedStream().toList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestClientBuilderConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Configure {@link Builder RestClient.Builder} with sensible defaults.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code RestClient.Builder} whose configuration is based upon that produced by\n * auto-configuration.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class RestClientBuilderConfigurer {\n\n\tprivate final ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder;\n\n\tprivate final HttpClientSettings clientSettings;\n\n\tprivate final List<RestClientCustomizer> customizers;\n\n\tpublic RestClientBuilderConfigurer() {\n\t\tthis(ClientHttpRequestFactoryBuilder.detect(), HttpClientSettings.defaults(), Collections.emptyList());\n\t}\n\n\tRestClientBuilderConfigurer(ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder,\n\t\t\tHttpClientSettings clientSettings, List<RestClientCustomizer> customizers) {\n\t\tthis.requestFactoryBuilder = requestFactoryBuilder;\n\t\tthis.clientSettings = clientSettings;\n\t\tthis.customizers = customizers;\n\t}\n\n\t/**\n\t * Configure the specified {@link Builder RestClient.Builder}. The builder can be\n\t * further tuned and default settings can be overridden.\n\t * @param builder the {@link Builder RestClient.Builder} instance to configure\n\t * @return the configured builder\n\t */\n\tpublic RestClient.Builder configure(RestClient.Builder builder) {\n\t\tbuilder.requestFactory(this.requestFactoryBuilder.build(this.clientSettings));\n\t\tapplyCustomizers(builder);\n\t\treturn builder;\n\t}\n\n\tprivate void applyCustomizers(RestClient.Builder builder) {\n\t\tfor (RestClientCustomizer customizer : this.customizers) {\n\t\t\tcustomizer.customize(builder);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.boot.restclient.observation.ObservationRestClientCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.client.observation.ClientRequestObservationConvention;\nimport org.springframework.http.client.observation.DefaultClientRequestObservationConvention;\nimport org.springframework.web.client.RestClient;\n\n/**\n * Configure the instrumentation of {@link RestClient}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ RestClient.class, ObservationRestClientCustomizer.class, ObservationRegistry.class,\n\t\tObservationProperties.class })\n@ConditionalOnBean({ RestClient.Builder.class, ObservationRegistry.class })\n@EnableConfigurationProperties(ObservationProperties.class)\npublic final class RestClientObservationAutoConfiguration {\n\n\t@Bean\n\tRestClientCustomizer observationRestClientCustomizer(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<ClientRequestObservationConvention> customConvention,\n\t\t\tObservationProperties observationProperties) {\n\t\tString name = observationProperties.getHttp().getClient().getRequests().getName();\n\t\tClientRequestObservationConvention observationConvention = customConvention\n\t\t\t.getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));\n\t\treturn new ObservationRestClientCustomizer(observationRegistry, observationConvention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestClientSsl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.web.client.RestClient;\n\n/**\n * Interface that can be used to {@link RestClient.Builder#apply apply} SSL configuration\n * to a {@link org.springframework.web.client.RestClient.Builder RestClient.Builder}.\n * <p>\n * Typically used as follows: <pre class=\"code\">\n * &#064;Bean\n * public MyBean myBean(RestClient.Builder restClientBuilder, RestClientSsl ssl) {\n *     RestClient restClient = restClientBuilder.apply(ssl.fromBundle(\"mybundle\")).build();\n *     return new MyBean(restClient);\n * }\n * </pre> NOTE: Applying SSL configuration will replace any previously\n * {@link RestClient.Builder#requestFactory configured} {@link ClientHttpRequestFactory}.\n * The replacement {@link ClientHttpRequestFactory} will apply only configured\n * {@link HttpClientSettings} and the appropriate {@link SslBundle}.\n * <p>\n * If you need to configure {@link ClientHttpRequestFactory} with more than just SSL\n * consider using a {@link ClientHttpRequestFactoryBuilder}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface RestClientSsl {\n\n\t/**\n\t * Return a {@link Consumer} that will apply SSL configuration for the named\n\t * {@link SslBundle} to a {@link org.springframework.web.client.RestClient.Builder\n\t * RestClient.Builder}.\n\t * @param bundleName the name of the SSL bundle to apply\n\t * @return a {@link Consumer} to apply the configuration\n\t * @throws NoSuchSslBundleException if a bundle with the provided name does not exist\n\t */\n\tConsumer<RestClient.Builder> fromBundle(String bundleName) throws NoSuchSslBundleException;\n\n\t/**\n\t * Return a {@link Consumer} that will apply SSL configuration for the\n\t * {@link SslBundle} to a {@link org.springframework.web.client.RestClient.Builder\n\t * RestClient.Builder}.\n\t * @param bundle the SSL bundle to apply\n\t * @return a {@link Consumer} to apply the configuration\n\t */\n\tConsumer<RestClient.Builder> fromBundle(SslBundle bundle);\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestTemplateAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.RestTemplateCustomizer;\nimport org.springframework.boot.restclient.RestTemplateRequestCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link RestTemplate} (via\n * {@link RestTemplateBuilder}).\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = HttpClientAutoConfiguration.class)\n@ConditionalOnClass({ RestTemplate.class, HttpMessageConverters.class })\n@Conditional(NotReactiveWebApplicationCondition.class)\npublic final class RestTemplateAutoConfiguration {\n\n\t@Bean\n\t@Lazy\n\tRestTemplateBuilderConfigurer restTemplateBuilderConfigurer(\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings,\n\t\t\tObjectProvider<ClientHttpMessageConvertersCustomizer> convertersCustomizers,\n\t\t\tObjectProvider<RestTemplateCustomizer> restTemplateCustomizers,\n\t\t\tObjectProvider<RestTemplateRequestCustomizer<?>> restTemplateRequestCustomizers) {\n\t\tRestTemplateBuilderConfigurer configurer = new RestTemplateBuilderConfigurer();\n\t\tconfigurer.setRequestFactoryBuilder(clientHttpRequestFactoryBuilder.getIfAvailable());\n\t\tconfigurer.setClientSettings(httpClientSettings.getIfAvailable());\n\t\tconfigurer.setHttpMessageConvertersCustomizers(convertersCustomizers.orderedStream().toList());\n\t\tconfigurer.setRestTemplateCustomizers(restTemplateCustomizers.orderedStream().toList());\n\t\tconfigurer.setRestTemplateRequestCustomizers(restTemplateRequestCustomizers.orderedStream().toList());\n\t\treturn configurer;\n\t}\n\n\t@Bean\n\t@Lazy\n\t@ConditionalOnMissingBean\n\tRestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer restTemplateBuilderConfigurer) {\n\t\treturn restTemplateBuilderConfigurer.configure(new RestTemplateBuilder());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestTemplateBuilderConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.function.BiFunction;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.RestTemplateCustomizer;\nimport org.springframework.boot.restclient.RestTemplateRequestCustomizer;\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Configure {@link RestTemplateBuilder} with sensible defaults.\n * <p>\n * Can be injected into application code and used to define a custom\n * {@code RestTemplateBuilder} whose configuration is based upon that produced by\n * auto-configuration.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic final class RestTemplateBuilderConfigurer {\n\n\tprivate @Nullable ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder;\n\n\tprivate @Nullable HttpClientSettings clientSettings;\n\n\tprivate @Nullable List<ClientHttpMessageConvertersCustomizer> httpMessageConvertersCustomizers;\n\n\tprivate @Nullable List<RestTemplateCustomizer> restTemplateCustomizers;\n\n\tprivate @Nullable List<RestTemplateRequestCustomizer<?>> restTemplateRequestCustomizers;\n\n\tvoid setRequestFactoryBuilder(@Nullable ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder) {\n\t\tthis.requestFactoryBuilder = requestFactoryBuilder;\n\t}\n\n\tvoid setClientSettings(@Nullable HttpClientSettings clientSettings) {\n\t\tthis.clientSettings = clientSettings;\n\t}\n\n\tvoid setHttpMessageConvertersCustomizers(\n\t\t\t@Nullable List<ClientHttpMessageConvertersCustomizer> httpMessageConvertersCustomizers) {\n\t\tthis.httpMessageConvertersCustomizers = httpMessageConvertersCustomizers;\n\t}\n\n\tvoid setRestTemplateCustomizers(@Nullable List<RestTemplateCustomizer> restTemplateCustomizers) {\n\t\tthis.restTemplateCustomizers = restTemplateCustomizers;\n\t}\n\n\tvoid setRestTemplateRequestCustomizers(\n\t\t\t@Nullable List<RestTemplateRequestCustomizer<?>> restTemplateRequestCustomizers) {\n\t\tthis.restTemplateRequestCustomizers = restTemplateRequestCustomizers;\n\t}\n\n\t/**\n\t * Configure the specified {@link RestTemplateBuilder}. The builder can be further\n\t * tuned and default settings can be overridden.\n\t * @param builder the {@link RestTemplateBuilder} instance to configure\n\t * @return the configured builder\n\t */\n\tpublic RestTemplateBuilder configure(RestTemplateBuilder builder) {\n\t\tif (this.requestFactoryBuilder != null) {\n\t\t\tbuilder = builder.requestFactoryBuilder(this.requestFactoryBuilder);\n\t\t}\n\t\tif (this.clientSettings != null) {\n\t\t\tbuilder = builder.clientSettings(this.clientSettings);\n\t\t}\n\t\tif (this.httpMessageConvertersCustomizers != null) {\n\t\t\tClientBuilder clientBuilder = HttpMessageConverters.forClient();\n\t\t\tthis.httpMessageConvertersCustomizers.forEach((customizer) -> customizer.customize(clientBuilder));\n\t\t\tbuilder = builder.messageConverters(clientBuilder.build());\n\t\t}\n\t\tbuilder = addCustomizers(builder, this.restTemplateCustomizers, RestTemplateBuilder::customizers);\n\t\tbuilder = addCustomizers(builder, this.restTemplateRequestCustomizers, RestTemplateBuilder::requestCustomizers);\n\t\treturn builder;\n\t}\n\n\tprivate <T> RestTemplateBuilder addCustomizers(RestTemplateBuilder builder, @Nullable List<T> customizers,\n\t\t\tBiFunction<RestTemplateBuilder, Collection<T>, RestTemplateBuilder> method) {\n\t\tif (!ObjectUtils.isEmpty(customizers)) {\n\t\t\treturn method.apply(builder, customizers);\n\t\t}\n\t\treturn builder;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/RestTemplateObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.observation.ObservationRestTemplateCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.client.observation.ClientRequestObservationConvention;\nimport org.springframework.http.client.observation.DefaultClientRequestObservationConvention;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Configure the instrumentation of {@link RestTemplate}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ RestTemplate.class, ObservationRestTemplateCustomizer.class, ObservationRegistry.class,\n\t\tObservationProperties.class })\n@ConditionalOnBean({ ObservationRegistry.class, RestTemplateBuilder.class })\n@EnableConfigurationProperties(ObservationProperties.class)\npublic final class RestTemplateObservationAutoConfiguration {\n\n\t@Bean\n\tObservationRestTemplateCustomizer observationRestTemplateCustomizer(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<ClientRequestObservationConvention> customConvention,\n\t\t\tObservationProperties observationProperties) {\n\t\tString name = observationProperties.getHttp().getClient().getRequests().getName();\n\t\tClientRequestObservationConvention observationConvention = customConvention\n\t\t\t.getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));\n\t\treturn new ObservationRestTemplateCustomizer(observationRegistry, observationConvention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RestClient.\n */\n@NullMarked\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/service/HttpServiceClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure.service;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientPropertiesAutoConfiguration;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.support.RestClientAdapter;\nimport org.springframework.web.service.registry.HttpServiceProxyRegistry;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring HTTP Service clients\n * backed by {@link RestClient}.\n *\n * @author Olga Maciaszek-Sharma\n * @author Rossen Stoyanchev\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = { HttpServiceClientPropertiesAutoConfiguration.class,\n\t\tImperativeHttpClientAutoConfiguration.class, RestClientAutoConfiguration.class })\n@ConditionalOnClass(RestClientAdapter.class)\n@ConditionalOnBean(HttpServiceProxyRegistry.class)\npublic final class HttpServiceClientAutoConfiguration {\n\n\t@Bean\n\tPropertiesRestClientHttpServiceGroupConfigurer restClientPropertiesHttpServiceGroupConfigurer(\n\t\t\tResourceLoader resourceLoader, HttpServiceClientProperties properties,\n\t\t\tObjectProvider<SslBundles> sslBundles,\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilder<?>> requestFactoryBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings) {\n\t\treturn new PropertiesRestClientHttpServiceGroupConfigurer(resourceLoader.getClassLoader(), properties,\n\t\t\t\tsslBundles.getIfAvailable(), requestFactoryBuilder, httpClientSettings.getIfAvailable());\n\t}\n\n\t@Bean\n\tRestClientCustomizerHttpServiceGroupConfigurer restClientCustomizerHttpServiceGroupConfigurer(\n\t\t\tObjectProvider<RestClientCustomizer> customizers) {\n\t\treturn new RestClientCustomizerHttpServiceGroupConfigurer(customizers);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/service/PropertiesRestClientHttpServiceGroupConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure.service;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.ApiversionProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientSettingsProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientSettingsPropertyMapper;\nimport org.springframework.boot.http.client.autoconfigure.PropertiesApiVersionInserter;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;\nimport org.springframework.web.service.registry.HttpServiceGroup;\n\n/**\n * A {@link RestClientHttpServiceGroupConfigurer} that configures the group and its\n * underlying {@link RestClient} using {@link HttpClientSettingsProperties}.\n *\n * @author Olga Maciaszek-Sharma\n * @author Phillip Webb\n */\nclass PropertiesRestClientHttpServiceGroupConfigurer implements RestClientHttpServiceGroupConfigurer {\n\n\t/**\n\t * The default order for the PropertiesRestClientHttpServiceGroupConfigurer.\n\t */\n\tprivate static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;\n\n\tprivate final HttpServiceClientProperties properties;\n\n\tprivate final HttpClientSettingsPropertyMapper clientSettingsPropertyMapper;\n\n\tprivate final ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder;\n\n\tPropertiesRestClientHttpServiceGroupConfigurer(@Nullable ClassLoader classLoader,\n\t\t\tHttpServiceClientProperties properties, @Nullable SslBundles sslBundles,\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilder<?>> requestFactoryBuilder,\n\t\t\t@Nullable HttpClientSettings httpClientSettings) {\n\t\tthis.properties = properties;\n\t\tthis.clientSettingsPropertyMapper = new HttpClientSettingsPropertyMapper(sslBundles, httpClientSettings);\n\t\tthis.requestFactoryBuilder = requestFactoryBuilder\n\t\t\t.getIfAvailable(() -> ClientHttpRequestFactoryBuilder.detect(classLoader));\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn DEFAULT_ORDER;\n\t}\n\n\t@Override\n\tpublic void configureGroups(Groups<RestClient.Builder> groups) {\n\t\tgroups.forEachClient(this::configureClient);\n\t}\n\n\tprivate void configureClient(HttpServiceGroup group, RestClient.Builder builder) {\n\t\tHttpClientProperties clientProperties = this.properties.get(group.name());\n\t\tHttpClientSettings clientSettings = this.clientSettingsPropertyMapper.map(clientProperties);\n\t\tbuilder.requestFactory(this.requestFactoryBuilder.build(clientSettings));\n\t\tif (clientProperties != null) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(clientProperties::getBaseUrl).whenHasText().to(builder::baseUrl);\n\t\t\tmap.from(clientProperties::getDefaultHeader).as(this::putAllHeaders).to(builder::defaultHeaders);\n\t\t\tmap.from(clientProperties::getApiversion)\n\t\t\t\t.as(ApiversionProperties::getDefaultVersion)\n\t\t\t\t.to(builder::defaultApiVersion);\n\t\t\tmap.from(clientProperties::getApiversion)\n\t\t\t\t.as(ApiversionProperties::getInsert)\n\t\t\t\t.as(PropertiesApiVersionInserter::get)\n\t\t\t\t.to(builder::apiVersionInserter);\n\t\t}\n\t}\n\n\tprivate Consumer<HttpHeaders> putAllHeaders(Map<String, List<String>> defaultHeaders) {\n\t\treturn (httpHeaders) -> httpHeaders.putAll(defaultHeaders);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/service/RestClientCustomizerHttpServiceGroupConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure.service;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;\nimport org.springframework.web.service.registry.HttpServiceGroup;\n\n/**\n * A {@link RestClientHttpServiceGroupConfigurer} to apply auto-configured\n * {@link RestClientCustomizer} beans to the group's {@link RestClient}.\n *\n * @author Olga Maciaszek-Sharma\n * @author Phillip Webb\n */\nclass RestClientCustomizerHttpServiceGroupConfigurer implements RestClientHttpServiceGroupConfigurer {\n\n\t/**\n\t * Allow user defined configurers to apply before / after ours.\n\t */\n\tprivate static final int ORDER = 0;\n\n\tprivate final ObjectProvider<RestClientCustomizer> customizers;\n\n\tRestClientCustomizerHttpServiceGroupConfigurer(ObjectProvider<RestClientCustomizer> customizers) {\n\t\tthis.customizers = customizers;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tpublic void configureGroups(Groups<RestClient.Builder> groups) {\n\t\tgroups.forEachClient(this::configureClient);\n\t}\n\n\tprivate void configureClient(HttpServiceGroup group, RestClient.Builder builder) {\n\t\tthis.customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/autoconfigure/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for Spring's Blocking HTTP Service Interface Clients.\n */\n@NullMarked\npackage org.springframework.boot.restclient.autoconfigure.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/observation/ObservationRestClientCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.http.client.observation.ClientRequestObservationConvention;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * {@link RestClientCustomizer} that configures the {@link Builder RestClient builder} to\n * record request observations.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class ObservationRestClientCustomizer implements RestClientCustomizer {\n\n\tprivate final ObservationRegistry observationRegistry;\n\n\tprivate final ClientRequestObservationConvention observationConvention;\n\n\t/**\n\t * Create a new {@link ObservationRestClientCustomizer}.\n\t * @param observationRegistry the observation registry\n\t * @param observationConvention the observation convention\n\t */\n\tpublic ObservationRestClientCustomizer(ObservationRegistry observationRegistry,\n\t\t\tClientRequestObservationConvention observationConvention) {\n\t\tAssert.notNull(observationConvention, \"'observationConvention' must not be null\");\n\t\tAssert.notNull(observationRegistry, \"'observationRegistry' must not be null\");\n\t\tthis.observationRegistry = observationRegistry;\n\t\tthis.observationConvention = observationConvention;\n\t}\n\n\t@Override\n\tpublic void customize(Builder restClientBuilder) {\n\t\trestClientBuilder.observationRegistry(this.observationRegistry);\n\t\trestClientBuilder.observationConvention(this.observationConvention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/observation/ObservationRestTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.restclient.RestTemplateCustomizer;\nimport org.springframework.http.client.observation.ClientRequestObservationConvention;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * {@link RestTemplateCustomizer} that configures the {@link RestTemplate} to record\n * request observations.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class ObservationRestTemplateCustomizer implements RestTemplateCustomizer {\n\n\tprivate final ObservationRegistry observationRegistry;\n\n\tprivate final ClientRequestObservationConvention observationConvention;\n\n\t/**\n\t * Create a new {@code ObservationRestTemplateCustomizer}.\n\t * @param observationConvention the observation convention\n\t * @param observationRegistry the observation registry\n\t */\n\tpublic ObservationRestTemplateCustomizer(ObservationRegistry observationRegistry,\n\t\t\tClientRequestObservationConvention observationConvention) {\n\t\tthis.observationConvention = observationConvention;\n\t\tthis.observationRegistry = observationRegistry;\n\t}\n\n\t@Override\n\tpublic void customize(RestTemplate restTemplate) {\n\t\trestTemplate.setObservationConvention(this.observationConvention);\n\t\trestTemplate.setObservationRegistry(this.observationRegistry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Observation integration for RestClient and RestTemplate.\n */\n@NullMarked\npackage org.springframework.boot.restclient.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/java/org/springframework/boot/restclient/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Web client utilities.\n */\n@NullMarked\npackage org.springframework.boot.restclient;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restclient/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration\norg.springframework.boot.restclient.autoconfigure.RestClientObservationAutoConfiguration\norg.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration\norg.springframework.boot.restclient.autoconfigure.RestTemplateObservationAutoConfiguration\norg.springframework.boot.restclient.autoconfigure.service.HttpServiceClientAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RestClientWithRestTemplateBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for building a {@link RestClient} from a {@link RestTemplateBuilder}.\n *\n * @author Scott Frederick\n */\nclass RestClientWithRestTemplateBuilderTests {\n\n\t@Test\n\tvoid buildUsingRestTemplateBuilderRootUri() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().baseUri(\"https://resttemplate.example.com\").build();\n\t\tRestClient.Builder builder = RestClient.builder(restTemplate);\n\t\tRestClient client = buildMockedClient(builder, \"https://resttemplate.example.com/test\");\n\t\tassertThat(client.get().uri(\"/test\").retrieve().toBodilessEntity().getStatusCode().is2xxSuccessful()).isTrue();\n\t}\n\n\t@Test\n\tvoid buildUsingRestClientBuilderBaseUrl() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().build();\n\t\tRestClient.Builder builder = RestClient.builder(restTemplate).baseUrl(\"https://restclient.example.com\");\n\t\tRestClient client = buildMockedClient(builder, \"https://restclient.example.com/test\");\n\t\tassertThat(client.get().uri(\"/test\").retrieve().toBodilessEntity().getStatusCode().is2xxSuccessful()).isTrue();\n\t}\n\n\t@Test\n\tvoid buildRestTemplateBuilderRootUriAndRestClientBuilderBaseUrl() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().baseUri(\"https://resttemplate.example.com\").build();\n\t\tRestClient.Builder builder = RestClient.builder(restTemplate).baseUrl(\"https://restclient.example.com\");\n\t\tRestClient client = buildMockedClient(builder, \"https://resttemplate.example.com/test\");\n\t\tassertThat(client.get().uri(\"/test\").retrieve().toBodilessEntity().getStatusCode().is2xxSuccessful()).isTrue();\n\t}\n\n\tprivate RestClient buildMockedClient(Builder builder, String url) {\n\t\tMockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();\n\t\tserver.expect(requestTo(url)).andRespond(withSuccess());\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RestClientWithRestTemplateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for building a {@link RestClient} from a {@link RestTemplate}.\n *\n * @author Scott Frederick\n */\nclass RestClientWithRestTemplateTests {\n\n\t@Test\n\tvoid buildUsingRestTemplateUriTemplateHandler() {\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tDefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(\"https://resttemplate.example.com\");\n\t\trestTemplate.setUriTemplateHandler(uriBuilderFactory);\n\t\tBuilder builder = RestClient.builder(restTemplate);\n\t\tRestClient client = buildMockedClient(builder, \"https://resttemplate.example.com/test\");\n\t\tassertThat(client.get().uri(\"/test\").retrieve().toBodilessEntity().getStatusCode().is2xxSuccessful()).isTrue();\n\t}\n\n\t@Test\n\tvoid buildUsingRestClientBuilderBaseUrl() {\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tBuilder builder = RestClient.builder(restTemplate).baseUrl(\"https://restclient.example.com\");\n\t\tRestClient client = buildMockedClient(builder, \"https://restclient.example.com/test\");\n\t\tassertThat(client.get().uri(\"/test\").retrieve().toBodilessEntity().getStatusCode().is2xxSuccessful()).isTrue();\n\t}\n\n\t@Test\n\tvoid buildUsingRestTemplateUriTemplateHandlerAndRestClientBuilderBaseUrl() {\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tDefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(\"https://resttemplate.example.com\");\n\t\trestTemplate.setUriTemplateHandler(uriBuilderFactory);\n\t\tBuilder builder = RestClient.builder(restTemplate).baseUrl(\"https://restclient.example.com\");\n\t\tRestClient client = buildMockedClient(builder, \"https://resttemplate.example.com/test\");\n\t\tassertThat(client.get().uri(\"/test\").retrieve().toBodilessEntity().getStatusCode().is2xxSuccessful()).isTrue();\n\t}\n\n\tprivate RestClient buildMockedClient(Builder builder, String url) {\n\t\tMockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();\n\t\tserver.expect(requestTo(url)).andRespond(withSuccess());\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RestTemplateBuilderClientHttpRequestInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.mock.http.client.MockClientHttpRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RestTemplateBuilderClientHttpRequestInitializer}.\n *\n * @author Dmytro Nosan\n * @author Ilya Lukyanovich\n * @author Phillip Webb\n */\nclass RestTemplateBuilderClientHttpRequestInitializerTests {\n\n\tprivate final MockClientHttpRequest request = new MockClientHttpRequest();\n\n\t@Test\n\tvoid createRequestWhenHasBasicAuthAndNoAuthHeaderAddsHeader() {\n\t\tnew RestTemplateBuilderClientHttpRequestInitializer(new BasicAuthentication(\"spring\", \"boot\", null),\n\t\t\t\tCollections.emptyMap(), Collections.emptySet())\n\t\t\t.initialize(this.request);\n\t\tassertThat(this.request.getHeaders().get(HttpHeaders.AUTHORIZATION)).containsExactly(\"Basic c3ByaW5nOmJvb3Q=\");\n\t}\n\n\t@Test\n\tvoid createRequestWhenHasBasicAuthAndExistingAuthHeaderDoesNotAddHeader() {\n\t\tthis.request.getHeaders().setBasicAuth(\"boot\", \"spring\");\n\t\tnew RestTemplateBuilderClientHttpRequestInitializer(new BasicAuthentication(\"spring\", \"boot\", null),\n\t\t\t\tCollections.emptyMap(), Collections.emptySet())\n\t\t\t.initialize(this.request);\n\t\tassertThat(this.request.getHeaders().get(HttpHeaders.AUTHORIZATION)).doesNotContain(\"Basic c3ByaW5nOmJvb3Q=\");\n\t}\n\n\t@Test\n\tvoid createRequestWhenHasDefaultHeadersAddsMissing() {\n\t\tthis.request.getHeaders().add(\"one\", \"existing\");\n\t\tMap<String, List<String>> defaultHeaders = new LinkedHashMap<>();\n\t\tdefaultHeaders.put(\"one\", Collections.singletonList(\"1\"));\n\t\tdefaultHeaders.put(\"two\", Arrays.asList(\"2\", \"3\"));\n\t\tdefaultHeaders.put(\"three\", Collections.singletonList(\"4\"));\n\t\tnew RestTemplateBuilderClientHttpRequestInitializer(null, defaultHeaders, Collections.emptySet())\n\t\t\t.initialize(this.request);\n\t\tassertThat(this.request.getHeaders().get(\"one\")).containsExactly(\"existing\");\n\t\tassertThat(this.request.getHeaders().get(\"two\")).containsExactly(\"2\", \"3\");\n\t\tassertThat(this.request.getHeaders().get(\"three\")).containsExactly(\"4\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid createRequestWhenHasRequestCustomizersAppliesThemInOrder() {\n\t\tSet<RestTemplateRequestCustomizer<?>> customizers = new LinkedHashSet<>();\n\t\tcustomizers.add(mock(RestTemplateRequestCustomizer.class));\n\t\tcustomizers.add(mock(RestTemplateRequestCustomizer.class));\n\t\tcustomizers.add(mock(RestTemplateRequestCustomizer.class));\n\t\tnew RestTemplateBuilderClientHttpRequestInitializer(null, Collections.emptyMap(), customizers)\n\t\t\t.initialize(this.request);\n\t\tInOrder inOrder = inOrder(customizers.toArray());\n\t\tfor (RestTemplateRequestCustomizer<?> customizer : customizers) {\n\t\t\tinOrder.verify((RestTemplateRequestCustomizer<ClientHttpRequest>) customizer).customize(this.request);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RestTemplateBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.net.URI;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.apache.hc.client5.http.HttpRoute;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.core5.function.Resolver;\nimport org.apache.hc.core5.util.Timeout;\nimport org.assertj.core.extractor.Extractors;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.InOrder;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.client.BufferingClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpRequestInitializer;\nimport org.springframework.http.client.ClientHttpRequestInterceptor;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.InterceptingClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.ResourceHttpMessageConverter;\nimport org.springframework.http.converter.StringHttpMessageConverter;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.ResponseErrorHandler;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestTemplateBuilder}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Dmytro Nosan\n * @author Kevin Strijbos\n * @author Ilya Lukyanovich\n * @author Brian Clozel\n * @author Yanming Zhou\n */\n@ExtendWith(MockitoExtension.class)\nclass RestTemplateBuilderTests {\n\n\tprivate final RestTemplateBuilder builder = new RestTemplateBuilder();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate HttpMessageConverter<Object> messageConverter;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequestInterceptor interceptor;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenCustomizersAreNullShouldThrowException() {\n\t\tRestTemplateCustomizer[] customizers = null;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RestTemplateBuilder(customizers))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWithCustomizersShouldApplyCustomizers() {\n\t\tRestTemplateCustomizer customizer = mock(RestTemplateCustomizer.class);\n\t\tRestTemplate template = new RestTemplateBuilder(customizer).build();\n\t\tthen(customizer).should().customize(template);\n\t}\n\n\t@Test\n\tvoid buildShouldDetectRequestFactory() {\n\t\tRestTemplate restTemplate = this.builder.build();\n\t\tassertThat(restTemplate.getRequestFactory()).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid detectRequestFactoryWhenFalseShouldDisableDetection() {\n\t\tRestTemplate restTemplate = this.builder.detectRequestFactory(false).build();\n\t\tassertThat(restTemplate.getRequestFactory()).isInstanceOf(SimpleClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid baseUriShouldApply() {\n\t\tRestTemplate restTemplate = this.builder.baseUri(\"https://example.com\").build();\n\t\tMockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();\n\t\tserver.expect(requestTo(\"https://example.com/hello\")).andRespond(withSuccess());\n\t\trestTemplate.getForEntity(\"/hello\", String.class);\n\t\tserver.verify();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid rootUriShouldApplyAfterUriTemplateHandler() {\n\t\tUriTemplateHandler uriTemplateHandler = mock(UriTemplateHandler.class);\n\t\tRestTemplate template = this.builder.uriTemplateHandler(uriTemplateHandler)\n\t\t\t.rootUri(\"https://example.com\")\n\t\t\t.build();\n\t\tUriTemplateHandler handler = template.getUriTemplateHandler();\n\t\thandler.expand(\"/hello\");\n\t\tassertThat(handler).isInstanceOf(RootUriBuilderFactory.class);\n\t\tthen(uriTemplateHandler).should().expand(\"https://example.com/hello\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid messageConvertersWhenConvertersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.messageConverters((HttpMessageConverter<?>[]) null))\n\t\t\t.withMessageContaining(\"'messageConverters' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid messageConvertersCollectionWhenConvertersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.messageConverters((Set<HttpMessageConverter<?>>) null))\n\t\t\t.withMessageContaining(\"'messageConverters' must not be null\");\n\t}\n\n\t@Test\n\tvoid messageConvertersShouldApply() {\n\t\tRestTemplate template = this.builder.messageConverters(this.messageConverter).build();\n\t\tassertThat(template.getMessageConverters()).containsOnly(this.messageConverter);\n\t}\n\n\t@Test\n\tvoid messageConvertersShouldReplaceExisting() {\n\t\tRestTemplate template = this.builder.messageConverters(new ResourceHttpMessageConverter())\n\t\t\t.messageConverters(Collections.singleton(this.messageConverter))\n\t\t\t.build();\n\t\tassertThat(template.getMessageConverters()).containsOnly(this.messageConverter);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalMessageConvertersWhenConvertersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalMessageConverters((HttpMessageConverter<?>[]) null))\n\t\t\t.withMessageContaining(\"'messageConverters' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalMessageConvertersCollectionWhenConvertersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalMessageConverters((Set<HttpMessageConverter<?>>) null))\n\t\t\t.withMessageContaining(\"'messageConverters' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalMessageConvertersShouldAddToExisting() {\n\t\tHttpMessageConverter<?> resourceConverter = new ResourceHttpMessageConverter();\n\t\tRestTemplate template = this.builder.messageConverters(resourceConverter)\n\t\t\t.additionalMessageConverters(this.messageConverter)\n\t\t\t.build();\n\t\tassertThat(template.getMessageConverters()).containsOnly(resourceConverter, this.messageConverter);\n\t}\n\n\t@Test\n\tvoid defaultMessageConvertersShouldSetDefaultList() {\n\t\tRestTemplate template = new RestTemplate(Collections.singletonList(new StringHttpMessageConverter()));\n\t\tthis.builder.defaultMessageConverters().configure(template);\n\t\tassertThat(template.getMessageConverters()).hasSameSizeAs(new RestTemplate().getMessageConverters());\n\t}\n\n\t@Test\n\tvoid defaultMessageConvertersShouldClearExisting() {\n\t\tRestTemplate template = new RestTemplate(Collections.singletonList(new StringHttpMessageConverter()));\n\t\tthis.builder.additionalMessageConverters(this.messageConverter).defaultMessageConverters().configure(template);\n\t\tassertThat(template.getMessageConverters()).hasSameSizeAs(new RestTemplate().getMessageConverters());\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid interceptorsWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.interceptors((ClientHttpRequestInterceptor[]) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid interceptorsCollectionWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.interceptors((Set<ClientHttpRequestInterceptor>) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\tvoid interceptorsShouldApply() {\n\t\tRestTemplate template = this.builder.interceptors(this.interceptor).build();\n\t\tassertThat(template.getInterceptors()).containsOnly(this.interceptor);\n\t}\n\n\t@Test\n\tvoid interceptorsShouldReplaceExisting() {\n\t\tRestTemplate template = this.builder.interceptors(mock(ClientHttpRequestInterceptor.class))\n\t\t\t.interceptors(Collections.singleton(this.interceptor))\n\t\t\t.build();\n\t\tassertThat(template.getInterceptors()).containsOnly(this.interceptor);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalInterceptorsWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalInterceptors((ClientHttpRequestInterceptor[]) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalInterceptorsCollectionWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalInterceptors((Set<ClientHttpRequestInterceptor>) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalInterceptorsShouldAddToExisting() {\n\t\tClientHttpRequestInterceptor interceptor = mock(ClientHttpRequestInterceptor.class);\n\t\tRestTemplate template = this.builder.interceptors(interceptor).additionalInterceptors(this.interceptor).build();\n\t\tassertThat(template.getInterceptors()).containsOnly(interceptor, this.interceptor);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid requestFactoryClassWhenFactoryIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.requestFactory((Class<ClientHttpRequestFactory>) null))\n\t\t\t.withMessageContaining(\"'requestFactoryType' must not be null\");\n\t}\n\n\t@Test\n\tvoid requestFactoryClassShouldApply() {\n\t\tRestTemplate template = this.builder.requestFactory(SimpleClientHttpRequestFactory.class).build();\n\t\tassertThat(template.getRequestFactory()).isInstanceOf(SimpleClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid requestFactoryPackagePrivateClassShouldApply() {\n\t\tRestTemplate template = this.builder.requestFactory(TestClientHttpRequestFactory.class).build();\n\t\tassertThat(template.getRequestFactory()).isInstanceOf(TestClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid requestFactoryWhenSupplierIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.requestFactory((Supplier<ClientHttpRequestFactory>) null))\n\t\t\t.withMessageContaining(\"requestFactorySupplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid requestFactoryShouldApply() {\n\t\tClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);\n\t\tRestTemplate template = this.builder.requestFactory(() -> requestFactory).build();\n\t\tassertThat(template.getRequestFactory()).isSameAs(requestFactory);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid uriTemplateHandlerWhenHandlerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.builder.uriTemplateHandler(null))\n\t\t\t.withMessageContaining(\"'uriTemplateHandler' must not be null\");\n\t}\n\n\t@Test\n\tvoid uriTemplateHandlerShouldApply() {\n\t\tUriTemplateHandler uriTemplateHandler = mock(UriTemplateHandler.class);\n\t\tRestTemplate template = this.builder.uriTemplateHandler(uriTemplateHandler).build();\n\t\tassertThat(template.getUriTemplateHandler()).isSameAs(uriTemplateHandler);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid errorHandlerWhenHandlerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.builder.errorHandler(null))\n\t\t\t.withMessageContaining(\"'errorHandler' must not be null\");\n\t}\n\n\t@Test\n\tvoid errorHandlerShouldApply() {\n\t\tResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class);\n\t\tRestTemplate template = this.builder.errorHandler(errorHandler).build();\n\t\tassertThat(template.getErrorHandler()).isSameAs(errorHandler);\n\t}\n\n\t@Test\n\tvoid basicAuthenticationShouldApply() {\n\t\tRestTemplate template = this.builder.basicAuthentication(\"spring\", \"boot\", StandardCharsets.UTF_8).build();\n\t\tClientHttpRequest request = createRequest(template);\n\t\tassertThat(request.getHeaders().headerNames()).containsOnly(HttpHeaders.AUTHORIZATION);\n\t\tassertThat(request.getHeaders().get(HttpHeaders.AUTHORIZATION)).containsExactly(\"Basic c3ByaW5nOmJvb3Q=\");\n\t}\n\n\t@Test\n\tvoid defaultHeaderAddsHeader() {\n\t\tRestTemplate template = this.builder.defaultHeader(\"spring\", \"boot\").build();\n\t\tClientHttpRequest request = createRequest(template);\n\t\tassertThat(request.getHeaders().headerSet()).contains(entry(\"spring\", Collections.singletonList(\"boot\")));\n\t}\n\n\t@Test\n\tvoid defaultHeaderAddsHeaderValues() {\n\t\tString name = HttpHeaders.ACCEPT;\n\t\tString[] values = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE };\n\t\tRestTemplate template = this.builder.defaultHeader(name, values).build();\n\t\tClientHttpRequest request = createRequest(template);\n\t\tassertThat(request.getHeaders().headerSet()).contains(entry(name, Arrays.asList(values)));\n\t}\n\n\t@Test // gh-17885\n\tvoid defaultHeaderWhenUsingMockRestServiceServerAddsHeader() {\n\t\tRestTemplate template = this.builder.defaultHeader(\"spring\", \"boot\").build();\n\t\tMockRestServiceServer.bindTo(template).build();\n\t\tClientHttpRequest request = createRequest(template);\n\t\tassertThat(request.getHeaders().headerSet()).contains(entry(\"spring\", Collections.singletonList(\"boot\")));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid clientSettingsAppliesSettings() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults()\n\t\t\t.withConnectTimeout(Duration.ofSeconds(1))\n\t\t\t.withReadTimeout(Duration.ofSeconds(2));\n\t\tRestTemplate template = this.builder.clientSettings(settings).build();\n\t\tResolver<HttpRoute, ConnectionConfig> resolver = (Resolver<HttpRoute, ConnectionConfig>) Extractors\n\t\t\t.byName(\"httpClient.connManager.connectionConfigResolver\")\n\t\t\t.apply(template.getRequestFactory());\n\t\tConnectionConfig config = resolver.resolve(mock());\n\t\tassertThat(config.getConnectTimeout()).isEqualTo(Timeout.of(Duration.ofSeconds(1)));\n\t\tassertThat(config.getSocketTimeout()).isEqualTo(Timeout.of(Duration.ofSeconds(2)));\n\t}\n\n\t@Test\n\tvoid requestCustomizersAddsCustomizers() {\n\t\tRestTemplate template = this.builder\n\t\t\t.requestCustomizers((request) -> request.getHeaders().add(\"spring\", \"framework\"))\n\t\t\t.build();\n\t\tClientHttpRequest request = createRequest(template);\n\t\tassertThat(request.getHeaders().headerSet()).contains(entry(\"spring\", Collections.singletonList(\"framework\")));\n\t}\n\n\t@Test\n\tvoid additionalRequestCustomizersAddsCustomizers() {\n\t\tRestTemplate template = this.builder\n\t\t\t.requestCustomizers((request) -> request.getHeaders().add(\"spring\", \"framework\"))\n\t\t\t.additionalRequestCustomizers((request) -> request.getHeaders().add(\"for\", \"java\"))\n\t\t\t.build();\n\t\tClientHttpRequest request = createRequest(template);\n\t\tassertThat(request.getHeaders().headerSet()).contains(entry(\"spring\", Collections.singletonList(\"framework\")))\n\t\t\t.contains(entry(\"for\", Collections.singletonList(\"java\")));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.builder.customizers((RestTemplateCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((Set<RestTemplateCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid customizersShouldApply() {\n\t\tRestTemplateCustomizer customizer = mock(RestTemplateCustomizer.class);\n\t\tRestTemplate template = this.builder.customizers(customizer).build();\n\t\tthen(customizer).should().customize(template);\n\t}\n\n\t@Test\n\tvoid customizersShouldBeAppliedLast() {\n\t\tRestTemplate template = spy(new RestTemplate());\n\t\tthis.builder.additionalCustomizers(\n\t\t\t\t(restTemplate) -> then(restTemplate).should().setRequestFactory(any(ClientHttpRequestFactory.class)));\n\t\tthis.builder.configure(template);\n\t}\n\n\t@Test\n\tvoid customizersShouldReplaceExisting() {\n\t\tRestTemplateCustomizer customizer1 = mock(RestTemplateCustomizer.class);\n\t\tRestTemplateCustomizer customizer2 = mock(RestTemplateCustomizer.class);\n\t\tRestTemplate template = this.builder.customizers(customizer1)\n\t\t\t.customizers(Collections.singleton(customizer2))\n\t\t\t.build();\n\t\tthen(customizer1).shouldHaveNoInteractions();\n\t\tthen(customizer2).should().customize(template);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((RestTemplateCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((Set<RestTemplateCustomizer>) null))\n\t\t\t.withMessageContaining(\"customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalCustomizersShouldAddToExisting() {\n\t\tRestTemplateCustomizer customizer1 = mock(RestTemplateCustomizer.class);\n\t\tRestTemplateCustomizer customizer2 = mock(RestTemplateCustomizer.class);\n\t\tRestTemplate template = this.builder.customizers(customizer1).additionalCustomizers(customizer2).build();\n\t\tInOrder ordered = inOrder(customizer1, customizer2);\n\t\tordered.verify(customizer1).customize(template);\n\t\tordered.verify(customizer2).customize(template);\n\t}\n\n\t@Test\n\tvoid customizerShouldBeAppliedAtTheEnd() {\n\t\tResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class);\n\t\tClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();\n\t\tthis.builder.interceptors(this.interceptor)\n\t\t\t.messageConverters(this.messageConverter)\n\t\t\t.baseUri(\"http://localhost:8080\")\n\t\t\t.errorHandler(errorHandler)\n\t\t\t.basicAuthentication(\"spring\", \"boot\")\n\t\t\t.requestFactory(() -> requestFactory)\n\t\t\t.customizers((restTemplate) -> {\n\t\t\t\tassertThat(restTemplate.getInterceptors()).hasSize(1);\n\t\t\t\tassertThat(restTemplate.getMessageConverters()).contains(this.messageConverter);\n\t\t\t\tassertThat(restTemplate.getUriTemplateHandler()).isInstanceOf(DefaultUriBuilderFactory.class);\n\t\t\t\tassertThat(restTemplate.getErrorHandler()).isEqualTo(errorHandler);\n\t\t\t\tClientHttpRequestFactory actualRequestFactory = restTemplate.getRequestFactory();\n\t\t\t\tassertThat(actualRequestFactory).isInstanceOf(InterceptingClientHttpRequestFactory.class);\n\t\t\t\tClientHttpRequestInitializer initializer = restTemplate.getClientHttpRequestInitializers().get(0);\n\t\t\t\tassertThat(initializer).isInstanceOf(RestTemplateBuilderClientHttpRequestInitializer.class);\n\t\t\t})\n\t\t\t.build();\n\t}\n\n\t@Test\n\tvoid buildShouldReturnRestTemplate() {\n\t\tRestTemplate template = this.builder.build();\n\t\tassertThat(template.getClass()).isEqualTo(RestTemplate.class);\n\t}\n\n\t@Test\n\tvoid buildClassShouldReturnClassInstance() {\n\t\tRestTemplateSubclass template = this.builder.build(RestTemplateSubclass.class);\n\t\tassertThat(template.getClass()).isEqualTo(RestTemplateSubclass.class);\n\t}\n\n\t@Test\n\tvoid configureShouldApply() {\n\t\tRestTemplate template = new RestTemplate();\n\t\tthis.builder.configure(template);\n\t\tassertThat(template.getRequestFactory()).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {\n\t\tSimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();\n\t\tRestTemplate template = this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))\n\t\t\t.build();\n\t\tassertThat(template.getRequestFactory()).isInstanceOf(BufferingClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid configureRedirects() {\n\t\tassertThat(this.builder.redirects(HttpRedirects.DONT_FOLLOW)).extracting(\"clientSettings\")\n\t\t\t.extracting(\"redirects\")\n\t\t\t.isSameAs(HttpRedirects.DONT_FOLLOW);\n\t}\n\n\tprivate ClientHttpRequest createRequest(RestTemplate template) {\n\t\tClientHttpRequest request = ReflectionTestUtils.invokeMethod(template, \"createRequest\",\n\t\t\t\tURI.create(\"http://localhost\"), HttpMethod.GET);\n\t\tassertThat(request).isNotNull();\n\t\treturn request;\n\t}\n\n\tstatic class RestTemplateSubclass extends RestTemplate {\n\n\t}\n\n\tstatic class TestClientHttpRequestFactory extends SimpleClientHttpRequestFactory {\n\n\t}\n\n\tstatic class TestHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriBuilderFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.web.util.UriBuilder;\nimport org.springframework.web.util.UriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RootUriBuilderFactory}.\n *\n * @author Scott Frederick\n */\n@SuppressWarnings(\"removal\")\nclass RootUriBuilderFactoryTests {\n\n\t@Test\n\tvoid uriStringPrefixesRoot() throws URISyntaxException {\n\t\tUriBuilderFactory builderFactory = new RootUriBuilderFactory(\"https://example.com\",\n\t\t\t\tmock(UriTemplateHandler.class));\n\t\tUriBuilder builder = builderFactory.uriString(\"/hello\");\n\t\tassertThat(builder.build()).isEqualTo(new URI(\"https://example.com/hello\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/RootUriTemplateHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.web.util.UriTemplateHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RootUriTemplateHandler}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\n@SuppressWarnings(\"removal\")\nclass RootUriTemplateHandlerTests {\n\n\tprivate URI uri;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tpublic UriTemplateHandler delegate;\n\n\tpublic UriTemplateHandler handler;\n\n\t@BeforeEach\n\tvoid setup() throws URISyntaxException {\n\t\tthis.uri = new URI(\"https://example.com/hello\");\n\t\tthis.handler = new RootUriTemplateHandler(\"https://example.com\", this.delegate);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithNullRootUriShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new RootUriTemplateHandler((String) null, mock(UriTemplateHandler.class)))\n\t\t\t.withMessageContaining(\"'rootUri' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWithNullHandlerShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RootUriTemplateHandler(\"https://example.com\", null))\n\t\t\t.withMessageContaining(\"'handler' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid expandMapVariablesShouldPrefixRoot() {\n\t\tgiven(this.delegate.expand(anyString(), any(Map.class))).willReturn(this.uri);\n\t\tHashMap<String, Object> uriVariables = new HashMap<>();\n\t\tURI expanded = this.handler.expand(\"/hello\", uriVariables);\n\t\tthen(this.delegate).should().expand(\"https://example.com/hello\", uriVariables);\n\t\tassertThat(expanded).isEqualTo(this.uri);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid expandMapVariablesWhenPathDoesNotStartWithSlashShouldNotPrefixRoot() {\n\t\tgiven(this.delegate.expand(anyString(), any(Map.class))).willReturn(this.uri);\n\t\tHashMap<String, Object> uriVariables = new HashMap<>();\n\t\tURI expanded = this.handler.expand(\"https://spring.io/hello\", uriVariables);\n\t\tthen(this.delegate).should().expand(\"https://spring.io/hello\", uriVariables);\n\t\tassertThat(expanded).isEqualTo(this.uri);\n\t}\n\n\t@Test\n\tvoid expandArrayVariablesShouldPrefixRoot() {\n\t\tgiven(this.delegate.expand(anyString(), any(Object[].class))).willReturn(this.uri);\n\t\tObject[] uriVariables = new Object[0];\n\t\tURI expanded = this.handler.expand(\"/hello\", uriVariables);\n\t\tthen(this.delegate).should().expand(\"https://example.com/hello\", uriVariables);\n\t\tassertThat(expanded).isEqualTo(this.uri);\n\t}\n\n\t@Test\n\tvoid expandArrayVariablesWhenPathDoesNotStartWithSlashShouldNotPrefixRoot() {\n\t\tgiven(this.delegate.expand(anyString(), any(Object[].class))).willReturn(this.uri);\n\t\tObject[] uriVariables = new Object[0];\n\t\tURI expanded = this.handler.expand(\"https://spring.io/hello\", uriVariables);\n\t\tthen(this.delegate).should().expand(\"https://spring.io/hello\", uriVariables);\n\t\tassertThat(expanded).isEqualTo(this.uri);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/AutoConfiguredRestClientSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AutoConfiguredRestClientSsl}.\n *\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\nclass AutoConfiguredRestClientSslTests {\n\n\tprivate final HttpClientSettings settings = HttpClientSettings\n\t\t.ofSslBundle(mock(SslBundle.class, \"Default SslBundle\"))\n\t\t.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t.withReadTimeout(Duration.ofSeconds(10))\n\t\t.withConnectTimeout(Duration.ofSeconds(30));\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate SslBundles sslBundles;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequestFactoryBuilder<ClientHttpRequestFactory> factoryBuilder;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientHttpRequestFactory factory;\n\n\tprivate AutoConfiguredRestClientSsl restClientSsl;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tMockitoAnnotations.openMocks(this);\n\t\tthis.restClientSsl = new AutoConfiguredRestClientSsl(this.factoryBuilder, this.settings, this.sslBundles);\n\t}\n\n\t@Test\n\tvoid shouldConfigureRestClientUsingBundleName() {\n\t\tString bundleName = \"test\";\n\t\tSslBundle sslBundle = mock(SslBundle.class, \"SslBundle named '%s'\".formatted(bundleName));\n\t\tgiven(this.sslBundles.getBundle(bundleName)).willReturn(sslBundle);\n\t\tgiven(this.factoryBuilder.build(this.settings.withSslBundle(sslBundle))).willReturn(this.factory);\n\t\tRestClient restClient = build(this.restClientSsl.fromBundle(bundleName));\n\t\tassertThat(restClient).hasFieldOrPropertyWithValue(\"clientRequestFactory\", this.factory);\n\t}\n\n\t@Test\n\tvoid shouldConfigureRestClientUsingBundle() {\n\t\tSslBundle sslBundle = mock(SslBundle.class, \"Custom SslBundle\");\n\t\tgiven(this.factoryBuilder.build(this.settings.withSslBundle(sslBundle))).willReturn(this.factory);\n\t\tRestClient restClient = build(this.restClientSsl.fromBundle(sslBundle));\n\t\tassertThat(restClient).hasFieldOrPropertyWithValue(\"clientRequestFactory\", this.factory);\n\t}\n\n\tprivate RestClient build(Consumer<RestClient.Builder> customizer) {\n\t\tBuilder builder = RestClient.builder();\n\t\tcustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/HttpMessageConvertersRestClientCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpMessageConvertersRestClientCustomizer}\n *\n * @author Brian Clozel\n */\nclass HttpMessageConvertersRestClientCustomizerTests {\n\n\t@Test\n\tvoid customizeConfiguresMessageConverters() {\n\t\tHttpMessageConverter<?> c0 = mock();\n\t\tHttpMessageConverter<?> c1 = mock();\n\t\tClientHttpMessageConvertersCustomizer customizer = (clientBuilder) -> clientBuilder.addCustomConverter(c0)\n\t\t\t.addCustomConverter(c1);\n\n\t\tRestClient.Builder builder = RestClient.builder();\n\t\tnew HttpMessageConvertersRestClientCustomizer(customizer).customize(builder);\n\t\tassertThat(builder.build()).extracting(\"messageConverters\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.containsSubsequence(c0, c1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.http.converter.ByteArrayHttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RestClientAutoConfiguration}\n *\n * @author Arjen Poutsma\n * @author Moritz Halbritter\n * @author Dmytro Nosan\n * @author Dmitry Sulman\n */\nclass RestClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class, HttpClientAutoConfiguration.class,\n\t\t\t\tImperativeHttpClientAutoConfiguration.class, ReactiveHttpClientAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RestClientBuilderConfigurer.class);\n\t\t\tassertThat(context).hasSingleBean(RestClient.Builder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyRestClientSslIfSslBundlesIsThereWithCustomHttpSettingsAndBuilder() {\n\t\tSslBundles sslBundles = mock(SslBundles.class);\n\t\tHttpClientSettings clientSettings = HttpClientSettings.defaults()\n\t\t\t.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.withConnectTimeout(Duration.ofHours(1))\n\t\t\t.withReadTimeout(Duration.ofDays(1))\n\t\t\t.withSslBundle(mock(SslBundle.class));\n\t\tClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder = mock(\n\t\t\t\tClientHttpRequestFactoryBuilder.class);\n\t\tthis.contextRunner.withBean(SslBundles.class, () -> sslBundles)\n\t\t\t.withBean(HttpClientSettings.class, () -> clientSettings)\n\t\t\t.withBean(ClientHttpRequestFactoryBuilder.class, () -> clientHttpRequestFactoryBuilder)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestClientSsl.class);\n\t\t\t\tRestClientSsl restClientSsl = context.getBean(RestClientSsl.class);\n\t\t\t\tassertThat(restClientSsl).hasFieldOrPropertyWithValue(\"sslBundles\", sslBundles);\n\t\t\t\tassertThat(restClientSsl).hasFieldOrPropertyWithValue(\"builder\", clientHttpRequestFactoryBuilder);\n\t\t\t\tassertThat(restClientSsl).hasFieldOrPropertyWithValue(\"settings\", clientSettings);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyRestClientSslIfSslBundlesIsThereWithAutoConfiguredHttpSettingsAndBuilder() {\n\t\tSslBundles sslBundles = mock(SslBundles.class);\n\t\tthis.contextRunner.withBean(SslBundles.class, () -> sslBundles).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RestClientSsl.class)\n\t\t\t\t.hasSingleBean(HttpClientSettings.class)\n\t\t\t\t.hasSingleBean(ClientHttpRequestFactoryBuilder.class);\n\t\t\tRestClientSsl restClientSsl = context.getBean(RestClientSsl.class);\n\t\t\tassertThat(restClientSsl).hasFieldOrPropertyWithValue(\"sslBundles\", sslBundles);\n\t\t\tassertThat(restClientSsl).hasFieldOrPropertyWithValue(\"builder\",\n\t\t\t\t\tcontext.getBean(ClientHttpRequestFactoryBuilder.class));\n\t\t\tassertThat(restClientSsl).hasFieldOrPropertyWithValue(\"settings\",\n\t\t\t\t\tcontext.getBean(HttpClientSettings.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateBuilder() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRestClient.Builder builder = context.getBean(RestClient.Builder.class);\n\t\t\tRestClient restClient = builder.build();\n\t\t\tassertThat(restClient).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid configurerShouldCallCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientCustomizerConfig.class).run((context) -> {\n\t\t\tRestClientBuilderConfigurer configurer = context.getBean(RestClientBuilderConfigurer.class);\n\t\t\tRestClientCustomizer customizer = context.getBean(\"restClientCustomizer\", RestClientCustomizer.class);\n\t\t\tBuilder builder = RestClient.builder();\n\t\t\tconfigurer.configure(builder);\n\t\t\tthen(customizer).should().customize(builder);\n\t\t});\n\t}\n\n\t@Test\n\tvoid restClientShouldApplyCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientCustomizerConfig.class).run((context) -> {\n\t\t\tRestClient.Builder builder = context.getBean(RestClient.Builder.class);\n\t\t\tRestClientCustomizer customizer = context.getBean(\"restClientCustomizer\", RestClientCustomizer.class);\n\t\t\tbuilder.build();\n\t\t\tthen(customizer).should().customize(any(RestClient.Builder.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldGetPrototypeScopedBean() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientCustomizerConfig.class).run((context) -> {\n\t\t\tRestClient.Builder firstBuilder = context.getBean(RestClient.Builder.class);\n\t\t\tRestClient.Builder secondBuilder = context.getBean(RestClient.Builder.class);\n\t\t\tassertThat(firstBuilder).isNotEqualTo(secondBuilder);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotCreateClientBuilderIfAlreadyPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRestClientBuilderConfig.class).run((context) -> {\n\t\t\tRestClient.Builder builder = context.getBean(RestClient.Builder.class);\n\t\t\tassertThat(builder).isInstanceOf(MyRestClientBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid restClientWhenNoMessageConvertersDefinedShouldHaveDefaultMessageConverters() {\n\t\tthis.contextRunner.withUserConfiguration(RestClientConfig.class).run((context) -> {\n\t\t\tRestClient restClient = context.getBean(RestClient.class);\n\t\t\tRestClient defaultRestClient = RestClient.builder().build();\n\t\t\tList<HttpMessageConverter<?>> actualConverters = (List<HttpMessageConverter<?>>) ReflectionTestUtils\n\t\t\t\t.getField(restClient, \"messageConverters\");\n\t\t\tList<HttpMessageConverter<?>> expectedConverters = (List<HttpMessageConverter<?>>) ReflectionTestUtils\n\t\t\t\t.getField(defaultRestClient, \"messageConverters\");\n\t\t\tassertThat(actualConverters).hasSameSizeAs(expectedConverters);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid restClientWhenHasCustomMessageConvertersShouldHaveMessageConverters() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomHttpMessageConverter.class, RestClientConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient restClient = context.getBean(RestClient.class);\n\t\t\t\tList<HttpMessageConverter<?>> actualConverters = (List<HttpMessageConverter<?>>) ReflectionTestUtils\n\t\t\t\t\t.getField(restClient, \"messageConverters\");\n\t\t\t\tassertThat(actualConverters).extracting(HttpMessageConverter::getClass)\n\t\t\t\t\t.contains((Class) CustomHttpMessageConverter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasFactoryProperty() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestClientConfig.class)\n\t\t\t.withPropertyValues(\"spring.http.clients.imperative.factory=simple\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestClient.class);\n\t\t\t\tRestClient restClient = context.getBean(RestClient.class);\n\t\t\t\tassertThat(restClient).extracting(\"clientRequestFactory\")\n\t\t\t\t\t.isInstanceOf(SimpleClientHttpRequestFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyRestClientBuilderConfigurerWithCustomSettings() {\n\t\tHttpClientSettings clientSettings = HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\tClientHttpRequestFactoryBuilder<?> clientHttpRequestFactoryBuilder = mock(\n\t\t\t\tClientHttpRequestFactoryBuilder.class);\n\t\tRestClientCustomizer customizer1 = mock(RestClientCustomizer.class);\n\t\tRestClientCustomizer customizer2 = mock(RestClientCustomizer.class);\n\t\tHttpMessageConvertersRestClientCustomizer httpMessageConverterCustomizer = mock(\n\t\t\t\tHttpMessageConvertersRestClientCustomizer.class);\n\t\tthis.contextRunner.withBean(HttpClientSettings.class, () -> clientSettings)\n\t\t\t.withBean(ClientHttpRequestFactoryBuilder.class, () -> clientHttpRequestFactoryBuilder)\n\t\t\t.withBean(\"customizer1\", RestClientCustomizer.class, () -> customizer1)\n\t\t\t.withBean(\"customizer2\", RestClientCustomizer.class, () -> customizer2)\n\t\t\t.withBean(\"httpMessageConverterCustomizer\", HttpMessageConvertersRestClientCustomizer.class,\n\t\t\t\t\t() -> httpMessageConverterCustomizer)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestClientBuilderConfigurer.class)\n\t\t\t\t\t.hasSingleBean(HttpClientSettings.class)\n\t\t\t\t\t.hasSingleBean(ClientHttpRequestFactoryBuilder.class);\n\t\t\t\tRestClientBuilderConfigurer configurer = context.getBean(RestClientBuilderConfigurer.class);\n\t\t\t\tassertThat(configurer).hasFieldOrPropertyWithValue(\"requestFactoryBuilder\",\n\t\t\t\t\t\tclientHttpRequestFactoryBuilder);\n\t\t\t\tassertThat(configurer).hasFieldOrPropertyWithValue(\"clientSettings\", clientSettings);\n\t\t\t\tassertThat(configurer).hasFieldOrPropertyWithValue(\"customizers\",\n\t\t\t\t\t\tList.of(customizer1, customizer2, httpMessageConverterCustomizer));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyRestClientBuilderConfigurerWithAutoConfiguredHttpSettings() {\n\t\tRestClientCustomizer customizer1 = mock(RestClientCustomizer.class);\n\t\tRestClientCustomizer customizer2 = mock(RestClientCustomizer.class);\n\t\tthis.contextRunner.withBean(\"customizer1\", RestClientCustomizer.class, () -> customizer1)\n\t\t\t.withBean(\"customizer2\", RestClientCustomizer.class, () -> customizer2)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestClientBuilderConfigurer.class)\n\t\t\t\t\t.hasSingleBean(HttpClientSettings.class)\n\t\t\t\t\t.hasSingleBean(ClientHttpRequestFactoryBuilder.class);\n\t\t\t\tRestClientBuilderConfigurer configurer = context.getBean(RestClientBuilderConfigurer.class);\n\t\t\t\tassertThat(configurer).hasFieldOrPropertyWithValue(\"requestFactoryBuilder\",\n\t\t\t\t\t\tcontext.getBean(ClientHttpRequestFactoryBuilder.class));\n\t\t\t\tassertThat(configurer).hasFieldOrPropertyWithValue(\"clientSettings\",\n\t\t\t\t\t\tcontext.getBean(HttpClientSettings.class));\n\t\t\t\tassertThat(configurer).hasFieldOrPropertyWithValue(\"customizers\", List.of(customizer1, customizer2));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenServletWebApplicationRestClientIsConfigured() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestClientBuilderConfigurer.class);\n\t\t\t\tassertThat(context).hasSingleBean(RestClient.Builder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientHttpMessageConverterCustomizersAreAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(ClientHttpMessageConverterCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(RestClient.Builder.class).build();\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer1 = context.getBean(\"customizer1\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer2 = context.getBean(\"customizer2\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer3 = context.getBean(\"customizer3\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tInOrder inOrder = inOrder(customizer1, customizer2, customizer3);\n\t\t\t\tinOrder.verify(customizer3).customize(any(ClientBuilder.class));\n\t\t\t\tinOrder.verify(customizer1).customize(any(ClientBuilder.class));\n\t\t\t\tinOrder.verify(customizer2).customize(any(ClientBuilder.class));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestClientCustomizerConfig {\n\n\t\t@Bean\n\t\tRestClientCustomizer restClientCustomizer() {\n\t\t\treturn mock(RestClientCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRestClientBuilderConfig {\n\n\t\t@Bean\n\t\tMyRestClientBuilder myRestClientBuilder() {\n\t\t\treturn mock(MyRestClientBuilder.class);\n\t\t}\n\n\t}\n\n\tinterface MyRestClientBuilder extends RestClient.Builder {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestClientConfig {\n\n\t\t@Bean\n\t\tRestClient restClient(RestClient.Builder restClientBuilder) {\n\t\t\treturn restClientBuilder.build();\n\t\t}\n\n\t}\n\n\tstatic class CustomHttpMessageConverter extends ByteArrayHttpMessageConverter {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientHttpMessageConverterCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(-5)\n\t\tClientHttpMessageConvertersCustomizer customizer1() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tClientHttpMessageConvertersCustomizer customizer2() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(-10)\n\t\tClientHttpMessageConvertersCustomizer customizer3() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.restclient.observation.ObservationRestClientCustomizer;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.observation.ClientRequestObservationContext;\nimport org.springframework.http.client.observation.DefaultClientRequestObservationConvention;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;\n\n/**\n * Tests for {@link RestClientObservationAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass RestClientObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(ObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, RestClientAutoConfiguration.class,\n\t\t\t\tRestClientObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid contributesCustomizerBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationRestClientCustomizer.class));\n\t}\n\n\t@Test\n\tvoid restClientCreatedWithBuilderIsInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRestClient restClient = buildRestClient(context);\n\t\t\trestClient.get().uri(\"/projects/{project}\", \"spring-boot\").retrieve().toBodilessEntity();\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tassertThat(registry).hasObservationWithNameEqualToIgnoringCase(\"http.client.requests\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid restClientCreatedWithBuilderUsesCustomConventionName() {\n\t\tfinal String observationName = \"test.metric.name\";\n\t\tthis.contextRunner.withPropertyValues(\"management.observations.http.client.requests.name=\" + observationName)\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient restClient = buildRestClient(context);\n\t\t\t\trestClient.get().uri(\"/projects/{project}\", \"spring-boot\").retrieve().toBodilessEntity();\n\t\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\t\tassertThat(registry).hasObservationWithNameEqualToIgnoringCase(observationName);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid restClientCreatedWithBuilderUsesCustomConvention() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> {\n\t\t\tRestClient restClient = buildRestClient(context);\n\t\t\trestClient.get().uri(\"/projects/{project}\", \"spring-boot\").retrieve().toBodilessEntity();\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tassertThat(registry).hasObservationWithNameEqualTo(\"http.client.requests\")\n\t\t\t\t.that()\n\t\t\t\t.hasLowCardinalityKeyValue(\"project\", \"spring-boot\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffWhenRestClientBuilderIsMissing() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,\n\t\t\t\t\tRestClientObservationAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ObservationRestClientCustomizer.class));\n\t}\n\n\tprivate RestClient buildRestClient(AssertableApplicationContext context) {\n\t\tRestClientWithMockServer restClientWithMockServer = buildRestClientAndMockServer(context);\n\t\trestClientWithMockServer.mockServer()\n\t\t\t.expect(requestTo(\"/projects/spring-boot\"))\n\t\t\t.andRespond(withStatus(HttpStatus.OK));\n\t\treturn restClientWithMockServer.restClient();\n\t}\n\n\tprivate RestClientWithMockServer buildRestClientAndMockServer(AssertableApplicationContext context) {\n\t\tBuilder builder = context.getBean(Builder.class);\n\t\tMockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();\n\t\tserver.expect(requestTo(\"/projects/spring-boot\")).andRespond(withStatus(HttpStatus.OK));\n\t\treturn new RestClientWithMockServer(builder.build(), server);\n\t}\n\n\tprivate record RestClientWithMockServer(RestClient restClient, MockRestServiceServer mockServer) {\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConventionConfiguration {\n\n\t\t@Bean\n\t\tCustomConvention customConvention() {\n\t\t\treturn new CustomConvention();\n\t\t}\n\n\t}\n\n\tstatic class CustomConvention extends DefaultClientRequestObservationConvention {\n\n\t\t@Override\n\t\tpublic KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {\n\t\t\treturn super.getLowCardinalityKeyValues(context).and(\"project\", \"spring-boot\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsConfiguration {\n\n\t\t@Bean\n\t\tMeterObservationHandler<Context> meterObservationHandler(MeterRegistry registry) {\n\t\t\treturn new DefaultMeterObservationHandler(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestClientObservationAutoConfigurationWithoutMetricsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;\n\n/**\n * Tests for {@link RestClientObservationAutoConfiguration} without Micrometer Metrics.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathExclusions(\"micrometer-core-*.jar\")\nclass RestClientObservationAutoConfigurationWithoutMetricsTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(ObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, RestClientAutoConfiguration.class,\n\t\t\t\tRestClientObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid restClientCreatedWithBuilderIsInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRestClient restClient = buildRestClient(context);\n\t\t\trestClient.get().uri(\"/projects/{project}\", \"spring-boot\").retrieve().toBodilessEntity();\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tassertThat(registry).hasObservationWithNameEqualToIgnoringCase(\"http.client.requests\");\n\t\t});\n\t}\n\n\tprivate RestClient buildRestClient(AssertableApplicationContext context) {\n\t\tBuilder builder = context.getBean(Builder.class);\n\t\tMockRestServiceServer server = MockRestServiceServer.bindTo(builder).build();\n\t\tserver.expect(requestTo(\"/projects/spring-boot\")).andRespond(withStatus(HttpStatus.OK));\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestTemplateAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.beans.factory.support.BeanDefinitionOverrideException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.RestTemplateCustomizer;\nimport org.springframework.boot.restclient.RestTemplateRequestCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.http.converter.ByteArrayHttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.mock.http.client.MockClientHttpRequest;\nimport org.springframework.mock.http.client.MockClientHttpResponse;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RestTemplateAutoConfiguration}\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass RestTemplateAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class, HttpClientAutoConfiguration.class,\n\t\t\t\tImperativeHttpClientAutoConfiguration.class));\n\n\t@Test\n\tvoid restTemplateBuilderConfigurerShouldBeLazilyDefined() {\n\t\tthis.contextRunner.run((context) -> assertThat(\n\t\t\t\tcontext.getBeanFactory().getBeanDefinition(\"restTemplateBuilderConfigurer\").isLazyInit())\n\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid shouldFailOnCustomRestTemplateBuilderConfigurer() {\n\t\tthis.contextRunner.withUserConfiguration(RestTemplateBuilderConfigurerConfig.class)\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanDefinitionOverrideException.class)\n\t\t\t\t.hasMessageContaining(\"with name 'restTemplateBuilderConfigurer'\"));\n\t}\n\n\t@Test\n\tvoid restTemplateBuilderShouldBeLazilyDefined() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.getBeanFactory().getBeanDefinition(\"restTemplateBuilder\").isLazyInit())\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid restTemplateWhenNoMessageConvertersDefinedShouldHaveDefaultMessageConverters() {\n\t\tthis.contextRunner.withUserConfiguration(RestTemplateConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RestTemplate.class);\n\t\t\tRestTemplate restTemplate = context.getBean(RestTemplate.class);\n\t\t\tassertThat(restTemplate.getMessageConverters()).hasSameSizeAs(new RestTemplate().getMessageConverters());\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid restTemplateWhenHasCustomMessageConvertersShouldHaveMessageConverters() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomHttpMessageConverter.class, RestTemplateConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestTemplate.class);\n\t\t\t\tRestTemplate restTemplate = context.getBean(RestTemplate.class);\n\t\t\t\tassertThat(restTemplate.getMessageConverters()).extracting(HttpMessageConverter::getClass)\n\t\t\t\t\t.contains((Class) CustomHttpMessageConverter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid restTemplateShouldApplyCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(RestTemplateConfig.class, RestTemplateCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestTemplate.class);\n\t\t\t\tRestTemplate restTemplate = context.getBean(RestTemplate.class);\n\t\t\t\tRestTemplateCustomizer customizer = context.getBean(RestTemplateCustomizer.class);\n\t\t\t\tthen(customizer).should().customize(restTemplate);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid restTemplateWhenHasCustomBuilderShouldUseCustomBuilder() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(RestTemplateConfig.class, CustomRestTemplateBuilderConfig.class,\n\t\t\t\t\tRestTemplateCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestTemplate.class);\n\t\t\t\tRestTemplate restTemplate = context.getBean(RestTemplate.class);\n\t\t\t\tassertThat(restTemplate.getMessageConverters()).hasSize(1);\n\t\t\t\tassertThat(restTemplate.getMessageConverters().get(0)).isInstanceOf(CustomHttpMessageConverter.class);\n\t\t\t\tthen(context.getBean(RestTemplateCustomizer.class)).shouldHaveNoInteractions();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid restTemplateWhenHasCustomBuilderCouldReuseBuilderConfigurer() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(RestTemplateConfig.class, CustomRestTemplateBuilderWithConfigurerConfig.class,\n\t\t\t\t\tRestTemplateCustomizerConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestTemplate.class);\n\t\t\t\tRestTemplate restTemplate = context.getBean(RestTemplate.class);\n\t\t\t\tassertThat(restTemplate.getMessageConverters()).hasSize(1);\n\t\t\t\tassertThat(restTemplate.getMessageConverters().get(0)).isInstanceOf(CustomHttpMessageConverter.class);\n\t\t\t\tRestTemplateCustomizer customizer = context.getBean(RestTemplateCustomizer.class);\n\t\t\t\tthen(customizer).should().customize(restTemplate);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid restTemplateShouldApplyRequestCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(RestTemplateRequestCustomizerConfig.class).run((context) -> {\n\t\t\tRestTemplateBuilder builder = context.getBean(RestTemplateBuilder.class);\n\t\t\tClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);\n\t\t\tMockClientHttpRequest request = new MockClientHttpRequest();\n\t\t\trequest.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));\n\t\t\tgiven(requestFactory.createRequest(any(), any())).willReturn(request);\n\t\t\tRestTemplate restTemplate = builder.requestFactory(() -> requestFactory).build();\n\t\t\trestTemplate.getForEntity(\"http://localhost:8080/test\", String.class);\n\t\t\tassertThat(request.getHeaders().headerSet()).contains(entry(\"spring\", Collections.singletonList(\"boot\")));\n\t\t});\n\t}\n\n\t@Test\n\tvoid builderShouldBeFreshForEachUse() {\n\t\tthis.contextRunner.withUserConfiguration(DirtyRestTemplateConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid whenServletWebApplicationRestTemplateBuilderIsConfigured() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RestTemplateBuilder.class)\n\t\t\t\t.hasSingleBean(RestTemplateBuilderConfigurer.class));\n\t}\n\n\t@Test\n\tvoid whenReactiveWebApplicationRestTemplateBuilderIsNotConfigured() {\n\t\tnew ReactiveWebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RestTemplateBuilder.class)\n\t\t\t\t.doesNotHaveBean(RestTemplateBuilderConfigurer.class));\n\t}\n\n\t@Test\n\tvoid whenHasFactoryProperty() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class))\n\t\t\t.withUserConfiguration(RestTemplateConfig.class)\n\t\t\t.withPropertyValues(\"spring.http.clients.imperative.factory=simple\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RestTemplate.class);\n\t\t\t\tRestTemplate restTemplate = context.getBean(RestTemplate.class);\n\t\t\t\tassertThat(restTemplate.getRequestFactory()).isInstanceOf(SimpleClientHttpRequestFactory.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientHttpMessageConverterCustomizersAreAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(ClientHttpMessageConverterCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.getBean(RestTemplateBuilder.class).build();\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer1 = context.getBean(\"customizer1\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer2 = context.getBean(\"customizer2\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer3 = context.getBean(\"customizer3\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tInOrder inOrder = inOrder(customizer1, customizer2, customizer3);\n\t\t\t\tinOrder.verify(customizer3).customize(any(ClientBuilder.class));\n\t\t\t\tinOrder.verify(customizer1).customize(any(ClientBuilder.class));\n\t\t\t\tinOrder.verify(customizer2).customize(any(ClientBuilder.class));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestTemplateConfig {\n\n\t\t@Bean\n\t\tRestTemplate restTemplate(RestTemplateBuilder builder) {\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DirtyRestTemplateConfig {\n\n\t\t@Bean\n\t\tRestTemplate restTemplateOne(RestTemplateBuilder builder) {\n\t\t\ttry {\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tbreakBuilderOnNextCall(builder);\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tRestTemplate restTemplateTwo(RestTemplateBuilder builder) {\n\t\t\ttry {\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tbreakBuilderOnNextCall(builder);\n\t\t\t}\n\t\t}\n\n\t\tprivate void breakBuilderOnNextCall(RestTemplateBuilder builder) {\n\t\t\tbuilder.additionalCustomizers((restTemplate) -> {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t});\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRestTemplateBuilderConfig {\n\n\t\t@Bean\n\t\tRestTemplateBuilder restTemplateBuilder() {\n\t\t\treturn new RestTemplateBuilder().messageConverters(new CustomHttpMessageConverter());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRestTemplateBuilderWithConfigurerConfig {\n\n\t\t@Bean\n\t\tRestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {\n\t\t\treturn configurer.configure(new RestTemplateBuilder()).messageConverters(new CustomHttpMessageConverter());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestTemplateCustomizerConfig {\n\n\t\t@Bean\n\t\tRestTemplateCustomizer restTemplateCustomizer() {\n\t\t\treturn mock(RestTemplateCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestTemplateRequestCustomizerConfig {\n\n\t\t@Bean\n\t\tRestTemplateRequestCustomizer<?> restTemplateRequestCustomizer() {\n\t\t\treturn (request) -> request.getHeaders().add(\"spring\", \"boot\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestTemplateBuilderConfigurerConfig {\n\n\t\t@Bean\n\t\tRestTemplateBuilderConfigurer restTemplateBuilderConfigurer() {\n\t\t\treturn new RestTemplateBuilderConfigurer();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientHttpMessageConverterCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(-5)\n\t\tClientHttpMessageConvertersCustomizer customizer1() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tClientHttpMessageConvertersCustomizer customizer2() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(-10)\n\t\tClientHttpMessageConvertersCustomizer customizer3() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t}\n\n\tstatic class CustomHttpMessageConverter extends ByteArrayHttpMessageConverter {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestTemplateObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.observation.ObservationRestTemplateCustomizer;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.observation.ClientRequestObservationContext;\nimport org.springframework.http.client.observation.DefaultClientRequestObservationConvention;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;\n\n/**\n * Tests for {@link RestTemplateObservationAutoConfiguration}.\n *\n * @author Brian Clozel\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass RestTemplateObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(ObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,\n\t\t\t\tRestTemplateAutoConfiguration.class, RestTemplateObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid contributesCustomizerBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationRestTemplateCustomizer.class));\n\t}\n\n\t@Test\n\tvoid restTemplateCreatedWithBuilderIsInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRestTemplate restTemplate = buildRestTemplate(context);\n\t\t\trestTemplate.getForEntity(\"/projects/{project}\", Void.class, \"spring-boot\");\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tassertThat(registry).hasObservationWithNameEqualToIgnoringCase(\"http.client.requests\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid restTemplateCreatedWithBuilderUsesCustomConventionName() {\n\t\tfinal String observationName = \"test.metric.name\";\n\t\tthis.contextRunner.withPropertyValues(\"management.observations.http.client.requests.name=\" + observationName)\n\t\t\t.run((context) -> {\n\t\t\t\tRestTemplate restTemplate = buildRestTemplate(context);\n\t\t\t\trestTemplate.getForEntity(\"/projects/{project}\", Void.class, \"spring-boot\");\n\t\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\t\tassertThat(registry).hasObservationWithNameEqualToIgnoringCase(observationName);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid restTemplateCreatedWithBuilderUsesCustomConvention() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> {\n\t\t\tRestTemplate restTemplate = buildRestTemplate(context);\n\t\t\trestTemplate.getForEntity(\"/projects/{project}\", Void.class, \"spring-boot\");\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tassertThat(registry).hasObservationWithNameEqualTo(\"http.client.requests\")\n\t\t\t\t.that()\n\t\t\t\t.hasLowCardinalityKeyValue(\"project\", \"spring-boot\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffWhenRestTemplateBuilderIsMissing() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,\n\t\t\t\t\tRestTemplateObservationAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ObservationRestTemplateCustomizer.class));\n\t}\n\n\tprivate RestTemplate buildRestTemplate(AssertableApplicationContext context) {\n\t\tRestTemplate restTemplate = context.getBean(RestTemplateBuilder.class).build();\n\t\tMockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);\n\t\tserver.expect(requestTo(\"/projects/spring-boot\")).andRespond(withStatus(HttpStatus.OK));\n\t\treturn restTemplate;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConventionConfiguration {\n\n\t\t@Bean\n\t\tCustomConvention customConvention() {\n\t\t\treturn new CustomConvention();\n\t\t}\n\n\t}\n\n\tstatic class CustomConvention extends DefaultClientRequestObservationConvention {\n\n\t\t@Override\n\t\tpublic KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {\n\t\t\treturn super.getLowCardinalityKeyValues(context).and(\"project\", \"spring-boot\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsConfiguration {\n\n\t\t@Bean\n\t\tMeterObservationHandler<Context> meterObservationHandler(MeterRegistry registry) {\n\t\t\treturn new DefaultMeterObservationHandler(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/RestTemplateObservationAutoConfigurationWithoutMetricsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;\n\n/**\n * Tests for {@link RestTemplateObservationAutoConfiguration} without Micrometer Metrics.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\n@ClassPathExclusions(\"micrometer-core-*.jar\")\nclass RestTemplateObservationAutoConfigurationWithoutMetricsTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(ObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class,\n\t\t\t\tRestTemplateAutoConfiguration.class, RestTemplateObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid restTemplateCreatedWithBuilderIsInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRestTemplate restTemplate = buildRestTemplate(context);\n\t\t\trestTemplate.getForEntity(\"/projects/{project}\", Void.class, \"spring-boot\");\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tassertThat(registry).hasObservationWithNameEqualToIgnoringCase(\"http.client.requests\");\n\t\t});\n\t}\n\n\tprivate RestTemplate buildRestTemplate(AssertableApplicationContext context) {\n\t\tRestTemplate restTemplate = context.getBean(RestTemplateBuilder.class).build();\n\t\tMockRestServiceServer server = MockRestServiceServer.createServer(restTemplate);\n\t\tserver.expect(requestTo(\"/projects/spring-boot\")).andRespond(withStatus(HttpStatus.OK));\n\t\treturn restTemplate;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/autoconfigure/service/HttpServiceClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.autoconfigure.service;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Proxy;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpClient.Redirect;\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.hc.client5.http.HttpRoute;\nimport org.apache.hc.client5.http.config.ConnectionConfig;\nimport org.apache.hc.client5.http.impl.classic.CloseableHttpClient;\nimport org.apache.hc.core5.function.Resolver;\nimport org.apache.hc.core5.util.Timeout;\nimport org.assertj.core.extractor.Extractors;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.aop.Advisor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.imperative.ImperativeHttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientPropertiesAutoConfiguration;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\nimport org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;\nimport org.springframework.web.service.annotation.GetExchange;\nimport org.springframework.web.service.registry.HttpServiceGroup;\nimport org.springframework.web.service.registry.HttpServiceGroupConfigurer.ClientCallback;\nimport org.springframework.web.service.registry.HttpServiceGroupConfigurer.Groups;\nimport org.springframework.web.service.registry.HttpServiceProxyRegistry;\nimport org.springframework.web.service.registry.ImportHttpServices;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.header;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link HttpServiceClientPropertiesAutoConfiguration},\n * {@link PropertiesRestClientHttpServiceGroupConfigurer} and\n * {@link RestClientCustomizerHttpServiceGroupConfigurer}.\n *\n * @author Phillip Webb\n */\nclass HttpServiceClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpServiceClientPropertiesAutoConfiguration.class,\n\t\t\t\tHttpServiceClientAutoConfiguration.class, ImperativeHttpClientAutoConfiguration.class,\n\t\t\t\tRestClientAutoConfiguration.class));\n\n\t@Test\n\tvoid configuresClientFromProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.serviceclient.one.default-header.test=true\",\n\t\t\t\t\t\"spring.http.serviceclient.one.base-url=https://example.com/one\",\n\t\t\t\t\t\"spring.http.serviceclient.two.default-header.test=true\",\n\t\t\t\t\t\"spring.http.serviceclient.two.default-header.two=iam2\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, MockRestServiceServerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tHttpServiceProxyRegistry serviceProxyRegistry = context.getBean(HttpServiceProxyRegistry.class);\n\t\t\t\tassertThat(serviceProxyRegistry.getGroupNames()).containsOnly(\"one\", \"two\");\n\t\t\t\tMockRestServiceServerConfiguration mockServers = context\n\t\t\t\t\t.getBean(MockRestServiceServerConfiguration.class);\n\t\t\t\tMockRestServiceServer serverOne = mockServers.getMock(\"one\");\n\t\t\t\tserverOne.expect(requestTo(\"https://example.com/one/hello\"))\n\t\t\t\t\t.andExpect(header(\"test\", \"true\"))\n\t\t\t\t\t.andRespond(withSuccess().body(\"world!\"));\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(clientOne.hello()).isEqualTo(\"world!\");\n\t\t\t\tMockRestServiceServer serverTwo = mockServers.getMock(\"two\");\n\t\t\t\tserverTwo.expect((request) -> request.getURI().toString().equals(\"https://example.com/\"))\n\t\t\t\t\t.andExpect(header(\"test\", \"true\"))\n\t\t\t\t\t.andExpect(header(\"two\", \"iam2\"))\n\t\t\t\t\t.andRespond(withSuccess().body(\"boot!\"));\n\t\t\t\tTestClientTwo clientTwo = context.getBean(TestClientTwo.class);\n\t\t\t\tassertThat(clientTwo.there()).isEqualTo(\"boot!\");\n\t\t\t});\n\t}\n\n\t@Test // gh-46915\n\tvoid configuresClientFromPropertiesWhenHasHttpClientAutoConfiguration() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HttpClientAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.http.serviceclient.one.connect-timeout=5s\",\n\t\t\t\t\t\"spring.http.serviceclient.two.connect-timeout=10s\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, MockRestServiceServerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tPropertiesRestClientHttpServiceGroupConfigurer configurer = context\n\t\t\t\t\t.getBean(PropertiesRestClientHttpServiceGroupConfigurer.class);\n\t\t\t\tGroups<RestClient.Builder> groups = mock();\n\t\t\t\tconfigurer.configureGroups(groups);\n\t\t\t\tArgumentCaptor<ClientCallback<RestClient.Builder>> callbackCaptor = ArgumentCaptor.captor();\n\t\t\t\tthen(groups).should().forEachClient(callbackCaptor.capture());\n\t\t\t\tClientCallback<RestClient.Builder> callback = callbackCaptor.getValue();\n\t\t\t\tassertConnectTimeout(callback, \"one\", 5000);\n\t\t\t\tassertConnectTimeout(callback, \"two\", 10000);\n\t\t\t});\n\t}\n\n\tprivate void assertConnectTimeout(ClientCallback<RestClient.Builder> callback, String name,\n\t\t\tlong expectedReadTimeout) {\n\t\tHttpServiceGroup group = mock();\n\t\tgiven(group.name()).willReturn(name);\n\t\tRestClient.Builder builder = mock();\n\t\tcallback.withClient(group, builder);\n\t\tArgumentCaptor<ClientHttpRequestFactory> requestFactoryCaptor = ArgumentCaptor.captor();\n\t\tthen(builder).should().requestFactory(requestFactoryCaptor.capture());\n\t\tHttpComponentsClientHttpRequestFactory client = (HttpComponentsClientHttpRequestFactory) requestFactoryCaptor\n\t\t\t.getValue();\n\t\tassertThat(getConnectorConfig(client).getConnectTimeout())\n\t\t\t.isEqualTo(Timeout.of(Duration.ofMillis(expectedReadTimeout)));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ConnectionConfig getConnectorConfig(HttpComponentsClientHttpRequestFactory requestFactory) {\n\t\tCloseableHttpClient httpClient = (CloseableHttpClient) ReflectionTestUtils.getField(requestFactory,\n\t\t\t\t\"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tObject manager = ReflectionTestUtils.getField(httpClient, \"connManager\");\n\t\tassertThat(manager).isNotNull();\n\t\tResolver<HttpRoute, ConnectionConfig> resolver = (Resolver<HttpRoute, ConnectionConfig>) ReflectionTestUtils\n\t\t\t.getField(manager, \"connectionConfigResolver\");\n\t\tassertThat(resolver).isNotNull();\n\t\treturn resolver.resolve(null);\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedRequestFactoryBuilder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.client.service.base-url=https://example.com\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, RequestFactoryBuilderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(getJdkHttpClient(clientOne).followRedirects()).isEqualTo(Redirect.NEVER);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedRequestFactorySettings() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\",\n\t\t\t\t\t\"spring.http.clients.imperative.factory=jdk\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, RequestFactorySettingsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(getJdkHttpClient(clientOne).followRedirects()).isEqualTo(Redirect.NEVER);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedRestClientCustomizer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, MockRestServiceServerConfiguration.class,\n\t\t\t\t\tRestClientCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tMockRestServiceServerConfiguration mockServers = context\n\t\t\t\t\t.getBean(MockRestServiceServerConfiguration.class);\n\t\t\t\tMockRestServiceServer serverOne = mockServers.getMock(\"one\");\n\t\t\t\tserverOne.expect(requestTo(\"https://example.com/hello\"))\n\t\t\t\t\t.andExpect(header(\"customized\", \"true\"))\n\t\t\t\t\t.andRespond(withSuccess().body(\"world!\"));\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(clientOne.hello()).isEqualTo(\"world!\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedHttpServiceGroupConfigurer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, MockRestServiceServerConfiguration.class,\n\t\t\t\t\tHttpServiceGroupConfigurerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tMockRestServiceServerConfiguration mockServers = context\n\t\t\t\t\t.getBean(MockRestServiceServerConfiguration.class);\n\t\t\t\tMockRestServiceServer serverOne = mockServers.getMock(\"one\");\n\t\t\t\tserverOne.expect(requestTo(\"https://example.com/hello\"))\n\t\t\t\t\t.andExpect(header(\"customizedgroup\", \"true\"))\n\t\t\t\t\t.andRespond(withSuccess().body(\"world!\"));\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(clientOne.hello()).isEqualTo(\"world!\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasNoHttpServiceProxyRegistryBean() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.clients.service.base-url=https://example.com\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpServiceProxyRegistry.class));\n\t}\n\n\tprivate HttpClient getJdkHttpClient(Object proxy) {\n\t\treturn (HttpClient) Extractors.byName(\"clientRequestFactory.httpClient\").apply(getRestClient(proxy));\n\t}\n\n\tprivate RestClient getRestClient(Object proxy) {\n\t\tInvocationHandler handler = Proxy.getInvocationHandler(proxy);\n\t\tAdvisor[] advisors = (Advisor[]) Extractors.byName(\"advised.advisors\").apply(handler);\n\t\tMap<?, ?> serviceMethods = (Map<?, ?>) Extractors.byName(\"advice.httpServiceMethods\").apply(advisors[0]);\n\t\tObject serviceMethod = serviceMethods.values().iterator().next();\n\t\treturn (RestClient) Extractors.byName(\"responseFunction.responseFunction.arg$1.restClient\")\n\t\t\t.apply(serviceMethod);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockRestServiceServerConfiguration {\n\n\t\tprivate Map<String, MockRestServiceServer> mocks = new HashMap<>();\n\n\t\t@Bean\n\t\tRestClientHttpServiceGroupConfigurer mockServerConfigurer() {\n\t\t\treturn (groups) -> groups.forEachClient(this::addMock);\n\t\t}\n\n\t\tprivate MockRestServiceServer addMock(HttpServiceGroup group, Builder client) {\n\t\t\treturn this.mocks.put(group.name(), MockRestServiceServer.bindTo(client).build());\n\t\t}\n\n\t\tMockRestServiceServer getMock(String name) {\n\t\t\tMockRestServiceServer mock = this.mocks.get(name);\n\t\t\tassertThat(mock).isNotNull();\n\t\t\treturn mock;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportHttpServices(group = \"one\", types = TestClientOne.class)\n\t@ImportHttpServices(group = \"two\", types = TestClientTwo.class)\n\tstatic class HttpClientConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestFactoryBuilderConfiguration {\n\n\t\t@Bean\n\t\tClientHttpRequestFactoryBuilder<?> requestFactoryBuilder() {\n\t\t\treturn ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t\t.withHttpClientCustomizer((httpClient) -> httpClient.followRedirects(Redirect.NEVER));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestFactorySettingsConfiguration {\n\n\t\t@Bean\n\t\tHttpClientSettings httpClientSettings() {\n\t\t\treturn HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestClientCustomizerConfiguration {\n\n\t\t@Bean\n\t\tRestClientCustomizer restClientCustomizer() {\n\t\t\treturn (builder) -> builder.defaultHeader(\"customized\", \"true\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpServiceGroupConfigurerConfiguration {\n\n\t\t@Bean\n\t\tRestClientHttpServiceGroupConfigurer restClientHttpServiceGroupConfigurer() {\n\t\t\treturn (groups) -> groups.filterByName(\"one\")\n\t\t\t\t.forEachClient((group, builder) -> builder.defaultHeader(\"customizedgroup\", \"true\"));\n\t\t}\n\n\t}\n\n\tinterface TestClientOne {\n\n\t\t@GetExchange(\"/hello\")\n\t\tString hello();\n\n\t}\n\n\tinterface TestClientTwo {\n\n\t\t@GetExchange(\"/there\")\n\t\tString there();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/observation/ObservationRestClientCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.client.observation.DefaultClientRequestObservationConvention;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ObservationRestClientCustomizer}.\n *\n * @author Brian Clozel\n * @author Moritz Halbritter\n */\nclass ObservationRestClientCustomizerTests {\n\n\tprivate static final String TEST_METRIC_NAME = \"http.test.metric.name\";\n\n\tprivate final ObservationRegistry observationRegistry = TestObservationRegistry.create();\n\n\tprivate final RestClient.Builder restClientBuilder = RestClient.builder();\n\n\tprivate final ObservationRestClientCustomizer customizer = new ObservationRestClientCustomizer(\n\t\t\tthis.observationRegistry, new DefaultClientRequestObservationConvention(TEST_METRIC_NAME));\n\n\t@Test\n\tvoid shouldCustomizeObservationConfiguration() {\n\t\tthis.customizer.customize(this.restClientBuilder);\n\t\tassertThat(this.restClientBuilder).hasFieldOrPropertyWithValue(\"observationRegistry\", this.observationRegistry);\n\t\tassertThat(this.restClientBuilder).extracting(\"observationConvention\")\n\t\t\t.isInstanceOf(DefaultClientRequestObservationConvention.class)\n\t\t\t.hasFieldOrPropertyWithValue(\"name\", TEST_METRIC_NAME);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient/src/test/java/org/springframework/boot/restclient/observation/ObservationRestTemplateCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.client.observation.DefaultClientRequestObservationConvention;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ObservationRestTemplateCustomizer}.\n *\n * @author Brian Clozel\n */\nclass ObservationRestTemplateCustomizerTests {\n\n\tprivate static final String TEST_METRIC_NAME = \"http.test.metric.name\";\n\n\tprivate final ObservationRegistry observationRegistry = TestObservationRegistry.create();\n\n\tprivate final RestTemplate restTemplate = new RestTemplate();\n\n\tprivate final ObservationRestTemplateCustomizer customizer = new ObservationRestTemplateCustomizer(\n\t\t\tthis.observationRegistry, new DefaultClientRequestObservationConvention(TEST_METRIC_NAME));\n\n\t@Test\n\tvoid shouldCustomizeObservationConfiguration() {\n\t\tthis.customizer.customize(this.restTemplate);\n\t\tassertThat(this.restTemplate).hasFieldOrPropertyWithValue(\"observationRegistry\", this.observationRegistry);\n\t\tassertThat(this.restTemplate).extracting(\"observationConvention\")\n\t\t\t.isInstanceOf(DefaultClientRequestObservationConvention.class)\n\t\t\t.hasFieldOrPropertyWithValue(\"name\", TEST_METRIC_NAME);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-metadata\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot RestClient Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-restclient\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-restclient\"))\n\toptional(\"org.apache.httpcomponents.client5:httpclient5\")\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\toptional(\"org.springframework:spring-test\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-metrics\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/MockServerRestClientCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.restclient.RestClientCustomizer;\nimport org.springframework.http.client.BufferingClientHttpRequestFactory;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.test.web.client.MockRestServiceServer.MockRestServiceServerBuilder;\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.SimpleRequestExpectationManager;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * {@link RestClientCustomizer} that can be applied to {@link Builder RestClient.Builder}\n * instances to add {@link MockRestServiceServer} support.\n * <p>\n * Typically applied to an existing builder before it is used, for example:\n * <pre class=\"code\">\n * MockServerRestClientCustomizer customizer = new MockServerRestClientCustomizer();\n * RestClient.Builder builder = RestClient.builder();\n * customizer.customize(builder);\n * MyBean bean = new MyBean(client.build());\n * customizer.getServer().expect(requestTo(\"/hello\")).andRespond(withSuccess());\n * bean.makeRestCall();\n * </pre>\n * <p>\n * If the customizer is only used once, the {@link #getServer()} method can be used to\n * obtain the mock server. If the customizer has been used more than once the\n * {@link #getServer(RestClient.Builder)} or {@link #getServers()} method must be used to\n * access the related server.\n * <p>\n * If a mock server is used in more than one test case in a test class, it might be\n * necessary to reset the expectations on the server between tests using\n * {@code getServer().reset()} or {@code getServer(restClientBuilder).reset()}.\n *\n * @author Scott Frederick\n * @since 4.0.0\n * @see #getServer()\n * @see #getServer(RestClient.Builder)\n */\npublic class MockServerRestClientCustomizer implements RestClientCustomizer {\n\n\tprivate final Map<RestClient.Builder, RequestExpectationManager> expectationManagers = new ConcurrentHashMap<>();\n\n\tprivate final Map<RestClient.Builder, MockRestServiceServer> servers = new ConcurrentHashMap<>();\n\n\tprivate final Supplier<? extends RequestExpectationManager> expectationManagerSupplier;\n\n\tprivate boolean bufferContent;\n\n\tpublic MockServerRestClientCustomizer() {\n\t\tthis(SimpleRequestExpectationManager::new);\n\t}\n\n\t/**\n\t * Create a new {@link MockServerRestClientCustomizer} instance.\n\t * @param expectationManager the expectation manager class to use\n\t */\n\tpublic MockServerRestClientCustomizer(Class<? extends RequestExpectationManager> expectationManager) {\n\t\tthis(() -> BeanUtils.instantiateClass(expectationManager));\n\t\tAssert.notNull(expectationManager, \"'expectationManager' must not be null\");\n\t}\n\n\t/**\n\t * Create a new {@link MockServerRestClientCustomizer} instance.\n\t * @param expectationManagerSupplier a supplier that provides the\n\t * {@link RequestExpectationManager} to use\n\t */\n\tpublic MockServerRestClientCustomizer(Supplier<? extends RequestExpectationManager> expectationManagerSupplier) {\n\t\tAssert.notNull(expectationManagerSupplier, \"'expectationManagerSupplier' must not be null\");\n\t\tthis.expectationManagerSupplier = expectationManagerSupplier;\n\t}\n\n\t/**\n\t * Set if the {@link BufferingClientHttpRequestFactory} wrapper should be used to\n\t * buffer the input and output streams, and for example, allow multiple reads of the\n\t * response body.\n\t * @param bufferContent if request and response content should be buffered\n\t */\n\tpublic void setBufferContent(boolean bufferContent) {\n\t\tthis.bufferContent = bufferContent;\n\t}\n\n\t@Override\n\tpublic void customize(RestClient.Builder restClientBuilder) {\n\t\tRequestExpectationManager expectationManager = createExpectationManager();\n\t\tMockRestServiceServerBuilder serverBuilder = MockRestServiceServer.bindTo(restClientBuilder);\n\t\tif (this.bufferContent) {\n\t\t\tserverBuilder.bufferContent();\n\t\t}\n\t\tMockRestServiceServer server = serverBuilder.build(expectationManager);\n\t\tthis.expectationManagers.put(restClientBuilder, expectationManager);\n\t\tthis.servers.put(restClientBuilder, server);\n\t}\n\n\tprotected RequestExpectationManager createExpectationManager() {\n\t\treturn this.expectationManagerSupplier.get();\n\t}\n\n\tpublic MockRestServiceServer getServer() {\n\t\tAssert.state(!this.servers.isEmpty(), \"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t+ \"MockServerRestClientCustomizer has not been bound to a RestClient\");\n\t\tAssert.state(this.servers.size() == 1, \"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t+ \"MockServerRestClientCustomizer has been bound to more than one RestClient\");\n\t\treturn this.servers.values().iterator().next();\n\t}\n\n\tpublic Map<RestClient.Builder, RequestExpectationManager> getExpectationManagers() {\n\t\treturn this.expectationManagers;\n\t}\n\n\tpublic @Nullable MockRestServiceServer getServer(RestClient.Builder restClientBuilder) {\n\t\treturn this.servers.get(restClientBuilder);\n\t}\n\n\tpublic Map<RestClient.Builder, MockRestServiceServer> getServers() {\n\t\treturn Collections.unmodifiableMap(this.servers);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/MockServerRestTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.RestTemplateCustomizer;\nimport org.springframework.http.client.BufferingClientHttpRequestFactory;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.test.web.client.MockRestServiceServer.MockRestServiceServerBuilder;\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.SimpleRequestExpectationManager;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * {@link RestTemplateCustomizer} that can be applied to a {@link RestTemplateBuilder}\n * instances to add {@link MockRestServiceServer} support.\n * <p>\n * Typically applied to an existing builder before it is used, for example:\n * <pre class=\"code\">\n * MockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer();\n * MyBean bean = new MyBean(new RestTemplateBuilder(customizer));\n * customizer.getServer().expect(requestTo(\"/hello\")).andRespond(withSuccess());\n * bean.makeRestCall();\n * </pre>\n * <p>\n * If the customizer is only used once, the {@link #getServer()} method can be used to\n * obtain the mock server. If the customizer has been used more than once the\n * {@link #getServer(RestTemplate)} or {@link #getServers()} method must be used to access\n * the related server.\n * <p>\n * If a mock server is used in more than one test case in a test class, it might be\n * necessary to reset the expectations on the server between tests using\n * {@code getServer().reset()} or {@code getServer(restTemplate).reset()}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Chinmoy Chakraborty\n * @since 4.0.0\n * @see #getServer()\n * @see #getServer(RestTemplate)\n */\npublic class MockServerRestTemplateCustomizer implements RestTemplateCustomizer {\n\n\tprivate final Map<RestTemplate, RequestExpectationManager> expectationManagers = new ConcurrentHashMap<>();\n\n\tprivate final Map<RestTemplate, MockRestServiceServer> servers = new ConcurrentHashMap<>();\n\n\tprivate final Supplier<? extends RequestExpectationManager> expectationManagerSupplier;\n\n\tprivate boolean detectRootUri = true;\n\n\tprivate boolean bufferContent;\n\n\tpublic MockServerRestTemplateCustomizer() {\n\t\tthis(SimpleRequestExpectationManager::new);\n\t}\n\n\t/**\n\t * Create a new {@link MockServerRestTemplateCustomizer} instance.\n\t * @param expectationManager the expectation manager class to use\n\t */\n\tpublic MockServerRestTemplateCustomizer(Class<? extends RequestExpectationManager> expectationManager) {\n\t\tthis(() -> BeanUtils.instantiateClass(expectationManager));\n\t\tAssert.notNull(expectationManager, \"'expectationManager' must not be null\");\n\t}\n\n\t/**\n\t * Create a new {@link MockServerRestTemplateCustomizer} instance.\n\t * @param expectationManagerSupplier a supplier that provides the\n\t * {@link RequestExpectationManager} to use\n\t */\n\tpublic MockServerRestTemplateCustomizer(Supplier<? extends RequestExpectationManager> expectationManagerSupplier) {\n\t\tAssert.notNull(expectationManagerSupplier, \"'expectationManagerSupplier' must not be null\");\n\t\tthis.expectationManagerSupplier = expectationManagerSupplier;\n\t}\n\n\t/**\n\t * Set if root URIs from {@link RootUriRequestExpectationManager} should be detected\n\t * and applied to the {@link MockRestServiceServer}.\n\t * @param detectRootUri if root URIs should be detected\n\t */\n\tpublic void setDetectRootUri(boolean detectRootUri) {\n\t\tthis.detectRootUri = detectRootUri;\n\t}\n\n\t/**\n\t * Set if the {@link BufferingClientHttpRequestFactory} wrapper should be used to\n\t * buffer the input and output streams, and for example, allow multiple reads of the\n\t * response body.\n\t * @param bufferContent if request and response content should be buffered\n\t */\n\tpublic void setBufferContent(boolean bufferContent) {\n\t\tthis.bufferContent = bufferContent;\n\t}\n\n\t@Override\n\tpublic void customize(RestTemplate restTemplate) {\n\t\tRequestExpectationManager expectationManager = createExpectationManager();\n\t\tif (this.detectRootUri) {\n\t\t\texpectationManager = RootUriRequestExpectationManager.forRestTemplate(restTemplate, expectationManager);\n\t\t}\n\t\tMockRestServiceServerBuilder serverBuilder = MockRestServiceServer.bindTo(restTemplate);\n\t\tif (this.bufferContent) {\n\t\t\tserverBuilder.bufferContent();\n\t\t}\n\t\tMockRestServiceServer server = serverBuilder.build(expectationManager);\n\t\tthis.expectationManagers.put(restTemplate, expectationManager);\n\t\tthis.servers.put(restTemplate, server);\n\t}\n\n\tprotected RequestExpectationManager createExpectationManager() {\n\t\treturn this.expectationManagerSupplier.get();\n\t}\n\n\tpublic MockRestServiceServer getServer() {\n\t\tAssert.state(!this.servers.isEmpty(), \"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t+ \"MockServerRestTemplateCustomizer has not been bound to a RestTemplate\");\n\t\tAssert.state(this.servers.size() == 1, \"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t+ \"MockServerRestTemplateCustomizer has been bound to more than one RestTemplate\");\n\t\treturn this.servers.values().iterator().next();\n\t}\n\n\tpublic Map<RestTemplate, RequestExpectationManager> getExpectationManagers() {\n\t\treturn this.expectationManagers;\n\t}\n\n\tpublic @Nullable MockRestServiceServer getServer(RestTemplate restTemplate) {\n\t\treturn this.servers.get(restTemplate);\n\t}\n\n\tpublic Map<RestTemplate, MockRestServiceServer> getServers() {\n\t\treturn Collections.unmodifiableMap(this.servers);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/RootUriRequestExpectationManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.time.Duration;\n\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.http.client.support.HttpRequestWrapper;\nimport org.springframework.mock.http.client.MockClientHttpRequest;\nimport org.springframework.test.web.client.ExpectedCount;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.test.web.client.MockRestServiceServer.MockRestServiceServerBuilder;\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.RequestMatcher;\nimport org.springframework.test.web.client.ResponseActions;\nimport org.springframework.test.web.client.SimpleRequestExpectationManager;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * {@link RequestExpectationManager} that strips the specified root URI from the request\n * before verification. Can be used to simply test declarations when all REST calls start\n * the same way. For example: <pre class=\"code\">\n * RestTemplate restTemplate = new RestTemplateBuilder().baseUri(\"https://example.com\").build();\n * MockRestServiceServer server = RootUriRequestExpectationManager.bindTo(restTemplate);\n * server.expect(requestTo(\"/hello\")).andRespond(withSuccess());\n * restTemplate.getForEntity(\"/hello\", String.class);\n * </pre>\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see DefaultUriBuilderFactory\n * @see #bindTo(RestTemplate)\n * @see #forRestTemplate(RestTemplate, RequestExpectationManager)\n */\npublic class RootUriRequestExpectationManager implements RequestExpectationManager {\n\n\tprivate final String rootUri;\n\n\tprivate final RequestExpectationManager expectationManager;\n\n\tpublic RootUriRequestExpectationManager(String rootUri, RequestExpectationManager expectationManager) {\n\t\tAssert.notNull(rootUri, \"'rootUri' must not be null\");\n\t\tAssert.notNull(expectationManager, \"'expectationManager' must not be null\");\n\t\tthis.rootUri = rootUri;\n\t\tthis.expectationManager = expectationManager;\n\t}\n\n\t@Override\n\tpublic ResponseActions expectRequest(ExpectedCount count, RequestMatcher requestMatcher) {\n\t\treturn this.expectationManager.expectRequest(count, requestMatcher);\n\t}\n\n\t@Override\n\tpublic ClientHttpResponse validateRequest(ClientHttpRequest request) throws IOException {\n\t\tString uri = request.getURI().toString();\n\t\tif (uri.startsWith(this.rootUri)) {\n\t\t\trequest = replaceURI(request, uri.substring(this.rootUri.length()));\n\t\t}\n\t\ttry {\n\t\t\treturn this.expectationManager.validateRequest(request);\n\t\t}\n\t\tcatch (AssertionError ex) {\n\t\t\tString message = ex.getMessage();\n\t\t\tString prefix = \"Request URI expected:</\";\n\t\t\tif (message != null && message.startsWith(prefix)) {\n\t\t\t\tthrow new AssertionError(\n\t\t\t\t\t\t\"Request URI expected:<\" + this.rootUri + message.substring(prefix.length() - 1));\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\tprivate ClientHttpRequest replaceURI(ClientHttpRequest request, String replacementUri) {\n\t\tURI uri;\n\t\ttry {\n\t\t\turi = new URI(replacementUri);\n\t\t\tif (request instanceof MockClientHttpRequest mockClientHttpRequest) {\n\t\t\t\tmockClientHttpRequest.setURI(uri);\n\t\t\t\treturn mockClientHttpRequest;\n\t\t\t}\n\t\t\treturn new ReplaceUriClientHttpRequest(uri, request);\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void verify() {\n\t\tthis.expectationManager.verify();\n\t}\n\n\t@Override\n\tpublic void verify(Duration timeout) {\n\t\tthis.expectationManager.verify(timeout);\n\t}\n\n\t@Override\n\tpublic void reset() {\n\t\tthis.expectationManager.reset();\n\t}\n\n\t/**\n\t * Return a bound {@link MockRestServiceServer} for the given {@link RestTemplate},\n\t * configured with {@link RootUriRequestExpectationManager} when possible.\n\t * @param restTemplate the source REST template\n\t * @return a configured {@link MockRestServiceServer}\n\t */\n\tpublic static MockRestServiceServer bindTo(RestTemplate restTemplate) {\n\t\treturn bindTo(restTemplate, new SimpleRequestExpectationManager());\n\t}\n\n\t/**\n\t * Return a bound {@link MockRestServiceServer} for the given {@link RestTemplate},\n\t * configured with {@link RootUriRequestExpectationManager} when possible.\n\t * @param restTemplate the source REST template\n\t * @param expectationManager the source {@link RequestExpectationManager}\n\t * @return a configured {@link MockRestServiceServer}\n\t */\n\tpublic static MockRestServiceServer bindTo(RestTemplate restTemplate,\n\t\t\tRequestExpectationManager expectationManager) {\n\t\tMockRestServiceServerBuilder builder = MockRestServiceServer.bindTo(restTemplate);\n\t\treturn builder.build(forRestTemplate(restTemplate, expectationManager));\n\t}\n\n\t/**\n\t * Return {@link RequestExpectationManager} to be used for binding with the specified\n\t * {@link RestTemplate}. If the {@link RestTemplate} is using a\n\t * {@link org.springframework.boot.restclient.RootUriTemplateHandler} then a\n\t * {@link RootUriRequestExpectationManager} is returned, otherwise the source manager\n\t * is returned unchanged.\n\t * @param restTemplate the source REST template\n\t * @param expectationManager the source {@link RequestExpectationManager}\n\t * @return a {@link RequestExpectationManager} to be bound to the template\n\t */\n\t@SuppressWarnings(\"removal\")\n\tpublic static RequestExpectationManager forRestTemplate(RestTemplate restTemplate,\n\t\t\tRequestExpectationManager expectationManager) {\n\t\tAssert.notNull(restTemplate, \"'restTemplate' must not be null\");\n\t\tUriTemplateHandler templateHandler = restTemplate.getUriTemplateHandler();\n\t\tif (templateHandler instanceof org.springframework.boot.restclient.RootUriTemplateHandler rootHandler\n\t\t\t\t&& rootHandler.getRootUri() != null) {\n\t\t\treturn new RootUriRequestExpectationManager(rootHandler.getRootUri(), expectationManager);\n\t\t}\n\t\telse if (templateHandler instanceof DefaultUriBuilderFactory defaultHandler && defaultHandler.hasBaseUri()) {\n\t\t\treturn new RootUriRequestExpectationManager(defaultHandler.expand(\"\").toString(), expectationManager);\n\t\t}\n\t\treturn expectationManager;\n\t}\n\n\t/**\n\t * {@link ClientHttpRequest} wrapper to replace the request URI.\n\t */\n\tprivate static class ReplaceUriClientHttpRequest extends HttpRequestWrapper implements ClientHttpRequest {\n\n\t\tprivate final URI uri;\n\n\t\tReplaceUriClientHttpRequest(URI uri, ClientHttpRequest request) {\n\t\t\tsuper(request);\n\t\t\tthis.uri = uri;\n\t\t}\n\n\t\t@Override\n\t\tpublic URI getURI() {\n\t\t\treturn this.uri;\n\t\t}\n\n\t\t@Override\n\t\tpublic OutputStream getBody() throws IOException {\n\t\t\treturn getRequest().getBody();\n\t\t}\n\n\t\t@Override\n\t\tpublic ClientHttpResponse execute() throws IOException {\n\t\t\treturn getRequest().execute();\n\t\t}\n\n\t\t@Override\n\t\tpublic ClientHttpRequest getRequest() {\n\t\t\treturn (ClientHttpRequest) super.getRequest();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/AutoConfigureMockRestServiceServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.restclient.test.MockServerRestClientCustomizer;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of a single {@link MockRestServiceServer}. Only useful when a single\n * call is made to {@link RestTemplateBuilder} or {@link Builder RestClient.Builder}. If\n * multiple {@link org.springframework.web.client.RestTemplate RestTemplates} or\n * {@link org.springframework.web.client.RestClient RestClients} are in use, inject a\n * {@link MockServerRestTemplateCustomizer} and use\n * {@link MockServerRestTemplateCustomizer#getServer(org.springframework.web.client.RestTemplate)\n * getServer(RestTemplate)}, or inject a {@link MockServerRestClientCustomizer} and use\n * {@link MockServerRestClientCustomizer#getServer(org.springframework.web.client.RestClient.Builder)\n * * getServer(RestClient.Builder)}, or bind a {@link MockRestServiceServer} directly.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n * @see MockServerRestTemplateCustomizer\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.restclient.mockrestserviceserver\")\npublic @interface AutoConfigureMockRestServiceServer {\n\n\t/**\n\t * If {@link MockServerRestTemplateCustomizer} and\n\t * {@link MockServerRestClientCustomizer} should be enabled and\n\t * {@link MockRestServiceServer} beans should be registered. Defaults to {@code true}\n\t * @return if mock support is enabled\n\t */\n\tboolean enabled() default true;\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/AutoConfigureRestClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration of a\n * {@link Builder RestClient.Builder} and a {@link RestTemplateBuilder}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJson\n@ImportAutoConfiguration\npublic @interface AutoConfigureRestClient {\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/MockRestServiceServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.Map;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.restclient.test.MockServerRestClientCustomizer;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.test.web.client.ExpectedCount;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.RequestMatcher;\nimport org.springframework.test.web.client.ResponseActions;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Auto-configuration for {@link MockRestServiceServer} support.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n * @see AutoConfigureMockRestServiceServer\n */\n@AutoConfiguration\n@ConditionalOnClass(MockServerRestTemplateCustomizer.class)\n@ConditionalOnBooleanProperty(\"spring.test.restclient.mockrestserviceserver.enabled\")\npublic final class MockRestServiceServerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMockServerRestTemplateCustomizer mockServerRestTemplateCustomizer() {\n\t\treturn new MockServerRestTemplateCustomizer();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMockServerRestClientCustomizer mockServerRestClientCustomizer() {\n\t\treturn new MockServerRestClientCustomizer();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMockRestServiceServer mockRestServiceServer(MockServerRestTemplateCustomizer restTemplateCustomizer,\n\t\t\tMockServerRestClientCustomizer restClientCustomizer) {\n\t\ttry {\n\t\t\treturn createDeferredMockRestServiceServer(restTemplateCustomizer, restClientCustomizer);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate MockRestServiceServer createDeferredMockRestServiceServer(\n\t\t\tMockServerRestTemplateCustomizer restTemplateCustomizer,\n\t\t\tMockServerRestClientCustomizer restClientCustomizer) throws Exception {\n\t\tConstructor<MockRestServiceServer> constructor = MockRestServiceServer.class\n\t\t\t.getDeclaredConstructor(RequestExpectationManager.class);\n\t\tconstructor.setAccessible(true);\n\t\treturn constructor\n\t\t\t.newInstance(new DeferredRequestExpectationManager(restTemplateCustomizer, restClientCustomizer));\n\t}\n\n\t/**\n\t * {@link RequestExpectationManager} with the injected {@link MockRestServiceServer}\n\t * so that the bean can be created before the\n\t * {@link MockServerRestTemplateCustomizer#customize(RestTemplate)\n\t * MockServerRestTemplateCustomizer} has been called.\n\t */\n\tprivate static class DeferredRequestExpectationManager implements RequestExpectationManager {\n\n\t\tprivate final MockServerRestTemplateCustomizer restTemplateCustomizer;\n\n\t\tprivate final MockServerRestClientCustomizer restClientCustomizer;\n\n\t\tDeferredRequestExpectationManager(MockServerRestTemplateCustomizer restTemplateCustomizer,\n\t\t\t\tMockServerRestClientCustomizer restClientCustomizer) {\n\t\t\tthis.restTemplateCustomizer = restTemplateCustomizer;\n\t\t\tthis.restClientCustomizer = restClientCustomizer;\n\t\t}\n\n\t\t@Override\n\t\tpublic ResponseActions expectRequest(ExpectedCount count, RequestMatcher requestMatcher) {\n\t\t\treturn getDelegate().expectRequest(count, requestMatcher);\n\t\t}\n\n\t\t@Override\n\t\tpublic ClientHttpResponse validateRequest(ClientHttpRequest request) throws IOException {\n\t\t\treturn getDelegate().validateRequest(request);\n\t\t}\n\n\t\t@Override\n\t\tpublic void verify() {\n\t\t\tgetDelegate().verify();\n\t\t}\n\n\t\t@Override\n\t\tpublic void verify(Duration timeout) {\n\t\t\tgetDelegate().verify(timeout);\n\t\t}\n\n\t\t@Override\n\t\tpublic void reset() {\n\t\t\tresetExpectations(this.restTemplateCustomizer.getExpectationManagers().values());\n\t\t\tresetExpectations(this.restClientCustomizer.getExpectationManagers().values());\n\t\t}\n\n\t\tprivate void resetExpectations(Collection<RequestExpectationManager> expectationManagers) {\n\t\t\tif (expectationManagers.size() == 1) {\n\t\t\t\texpectationManagers.iterator().next().reset();\n\t\t\t}\n\t\t}\n\n\t\tprivate RequestExpectationManager getDelegate() {\n\t\t\tMap<RestTemplate, RequestExpectationManager> restTemplateExpectationManagers = this.restTemplateCustomizer\n\t\t\t\t.getExpectationManagers();\n\t\t\tMap<RestClient.Builder, RequestExpectationManager> restClientExpectationManagers = this.restClientCustomizer\n\t\t\t\t.getExpectationManagers();\n\t\t\tboolean neitherBound = restTemplateExpectationManagers.isEmpty() && restClientExpectationManagers.isEmpty();\n\t\t\tboolean bothBound = !restTemplateExpectationManagers.isEmpty() && !restClientExpectationManagers.isEmpty();\n\t\t\tAssert.state(!neitherBound, \"Unable to use auto-configured MockRestServiceServer since \"\n\t\t\t\t\t+ \"a mock server customizer has not been bound to a RestTemplate or RestClient\");\n\t\t\tAssert.state(!bothBound, \"Unable to use auto-configured MockRestServiceServer since \"\n\t\t\t\t\t+ \"mock server customizers have been bound to both a RestTemplate and a RestClient\");\n\t\t\tif (!restTemplateExpectationManagers.isEmpty()) {\n\t\t\t\tAssert.state(restTemplateExpectationManagers.size() == 1,\n\t\t\t\t\t\t\"Unable to use auto-configured MockRestServiceServer since \"\n\t\t\t\t\t\t\t\t+ \"MockServerRestTemplateCustomizer has been bound to more than one RestTemplate\");\n\t\t\t\treturn restTemplateExpectationManagers.values().iterator().next();\n\t\t\t}\n\t\t\tAssert.state(restClientExpectationManagers.size() == 1,\n\t\t\t\t\t\"Unable to use auto-configured MockRestServiceServer since \"\n\t\t\t\t\t\t\t+ \"MockServerRestClientCustomizer has been bound to more than one RestClient\");\n\t\t\treturn restClientExpectationManagers.values().iterator().next();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/MockRestServiceServerResetTestExecutionListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestExecutionListener;\nimport org.springframework.test.context.support.AbstractTestExecutionListener;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\n/**\n * {@link TestExecutionListener} to reset {@link MockRestServiceServer} beans.\n *\n * @author Phillip Webb\n */\nclass MockRestServiceServerResetTestExecutionListener extends AbstractTestExecutionListener {\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE - 100;\n\t}\n\n\t@Override\n\tpublic void afterTestMethod(TestContext testContext) throws Exception {\n\t\tApplicationContext applicationContext = testContext.getApplicationContext();\n\t\tString[] names = applicationContext.getBeanNamesForType(MockRestServiceServer.class, false, false);\n\t\tfor (String name : names) {\n\t\t\tapplicationContext.getBean(name, MockRestServiceServer.class).reset();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Annotation for a Spring rest client test that focuses <strong>only</strong> on beans\n * that use {@link RestTemplateBuilder} or {@link Builder RestClient.Builder}.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to rest client\n * tests. Similarly, component scanning is limited to beans annotated with:\n * <ul>\n * <li>{@code @JacksonComponent}</li>\n * <li>{@code @JsonComponent}(deprecated)</li>\n * </ul>\n * <p>\n * as well as beans that implement:\n * <ul>\n * <li>{@code JacksonModule}, if Jackson is available</li>\n * <li>{@code Module}, if Jackson 2 is available (deprecated)</li>\n * </ul>\n * <p>\n * By default, tests annotated with {@code RestClientTest} will also auto-configure a\n * {@link MockRestServiceServer}. For more fine-grained control the\n * {@link AutoConfigureMockRestServiceServer @AutoConfigureMockRestServiceServer}\n * annotation can be used.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(RestClientTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(RestClientTypeExcludeFilter.class)\n@AutoConfigureMockRestServiceServer\n@AutoConfigureRestClient\n@ImportAutoConfiguration\npublic @interface RestClientTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the components to test. This is an alias of {@link #components()} which\n\t * can be used for brevity if no other attributes are defined. See\n\t * {@link #components()} for details.\n\t * @see #components()\n\t * @return the components to test\n\t */\n\t@AliasFor(\"components\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the components to test. May be left blank if components will be manually\n\t * imported or created directly.\n\t * @see #value()\n\t * @return the components to test\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] components() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default, only\n\t * {@code @JacksonComponent} and {@code JacksonModule} beans are included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link RestClientTest @RestClientTest} support.\n *\n * @author Artsiom Yudovin\n */\nclass RestClientTestContextBootstrapper extends TestSliceTestContextBootstrapper<RestClientTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TypeExcludeFilter} for {@link RestClientTest @RestClientTest}.\n *\n * @author Stephane Nicoll\n */\nclass RestClientTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<RestClientTest> {\n\n\tprivate static final Class<?>[] NO_COMPONENTS = {};\n\n\tprivate static final String[] OPTIONAL_INCLUDES = { \"tools.jackson.databind.JacksonModule\",\n\t\t\t\"org.springframework.boot.jackson.JacksonComponent\", \"com.fasterxml.jackson.databind.Module\",\n\t\t\t\"org.springframework.boot.jackson2.JsonComponent\" };\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>();\n\t\tfor (String optionalInclude : OPTIONAL_INCLUDES) {\n\t\t\ttry {\n\t\t\t\tincludes.add(ClassUtils.forName(optionalInclude, null));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tKNOWN_INCLUDES = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate final Class<?>[] components;\n\n\tRestClientTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.components = getAnnotation().getValue(\"components\", Class[].class).orElse(NO_COMPONENTS);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.components));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for web clients.\n */\n@NullMarked\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/java/org/springframework/boot/restclient/test/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * RestClient and RestTemplate test utilities.\n */\n@NullMarked\npackage org.springframework.boot.restclient.test;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/resources/META-INF/spring/org.springframework.boot.restclient.test.autoconfigure.AutoConfigureMockRestServiceServer.imports",
    "content": "org.springframework.boot.restclient.test.autoconfigure.MockRestServiceServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/resources/META-INF/spring/org.springframework.boot.restclient.test.autoconfigure.AutoConfigureRestClient.imports",
    "content": "org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration\norg.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration\norg.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.restclient.mockrestserviceserver.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether a MockRestServiceServer should be auto-configured.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.test.webclient.mockrestserviceserver.enabled\",\n      \"deprecation\": {\n        \"level\":\"error\",\n        \"replacement\":\"spring.test.restclient.mockrestserviceserver.enabled\",\n        \"since\":\"4.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Execution Listeners\norg.springframework.test.context.TestExecutionListener=\\\norg.springframework.boot.restclient.test.autoconfigure.MockRestServiceServerResetTestExecutionListener\n\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/MockServerRestClientCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test;\n\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.SimpleRequestExpectationManager;\nimport org.springframework.test.web.client.UnorderedRequestExpectationManager;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link MockServerRestClientCustomizer}.\n *\n * @author Scott Frederick\n */\nclass MockServerRestClientCustomizerTests {\n\n\tprivate MockServerRestClientCustomizer customizer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.customizer = new MockServerRestClientCustomizer();\n\t}\n\n\t@Test\n\tvoid createShouldUseSimpleRequestExpectationManager() {\n\t\tMockServerRestClientCustomizer customizer = new MockServerRestClientCustomizer();\n\t\tcustomizer.customize(RestClient.builder());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(SimpleRequestExpectationManager.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenExpectationManagerClassIsNullShouldThrowException() {\n\t\tClass<? extends RequestExpectationManager> expectationManager = null;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new MockServerRestClientCustomizer(expectationManager))\n\t\t\t.withMessageContaining(\"'expectationManager' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenExpectationManagerSupplierIsNullShouldThrowException() {\n\t\tSupplier<? extends RequestExpectationManager> expectationManagerSupplier = null;\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new MockServerRestClientCustomizer(expectationManagerSupplier))\n\t\t\t.withMessageContaining(\"'expectationManagerSupplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid createShouldUseExpectationManagerClass() {\n\t\tMockServerRestClientCustomizer customizer = new MockServerRestClientCustomizer(\n\t\t\t\tUnorderedRequestExpectationManager.class);\n\t\tcustomizer.customize(RestClient.builder());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(UnorderedRequestExpectationManager.class);\n\t}\n\n\t@Test\n\tvoid createShouldUseSupplier() {\n\t\tMockServerRestClientCustomizer customizer = new MockServerRestClientCustomizer(\n\t\t\t\tUnorderedRequestExpectationManager::new);\n\t\tcustomizer.customize(RestClient.builder());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(UnorderedRequestExpectationManager.class);\n\t}\n\n\t@Test\n\tvoid customizeShouldBindServer() {\n\t\tBuilder builder = RestClient.builder();\n\t\tthis.customizer.customize(builder);\n\t\tthis.customizer.getServer().expect(requestTo(\"/test\")).andRespond(withSuccess());\n\t\tbuilder.build().get().uri(\"/test\").retrieve().toEntity(String.class);\n\t\tthis.customizer.getServer().verify();\n\t}\n\n\t@Test\n\tvoid getServerWhenNoServersAreBoundShouldThrowException() {\n\t\tassertThatIllegalStateException().isThrownBy(this.customizer::getServer)\n\t\t\t.withMessageContaining(\"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t\t+ \"MockServerRestClientCustomizer has not been bound to a RestClient\");\n\t}\n\n\t@Test\n\tvoid getServerWhenMultipleServersAreBoundShouldThrowException() {\n\t\tthis.customizer.customize(RestClient.builder());\n\t\tthis.customizer.customize(RestClient.builder());\n\t\tassertThatIllegalStateException().isThrownBy(this.customizer::getServer)\n\t\t\t.withMessageContaining(\"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t\t+ \"MockServerRestClientCustomizer has been bound to more than one RestClient\");\n\t}\n\n\t@Test\n\tvoid getServerWhenSingleServerIsBoundShouldReturnServer() {\n\t\tBuilder builder = RestClient.builder();\n\t\tthis.customizer.customize(builder);\n\t\tassertThat(this.customizer.getServer()).isEqualTo(this.customizer.getServer(builder));\n\t}\n\n\t@Test\n\tvoid getServerWhenRestClientBuilderIsFoundShouldReturnServer() {\n\t\tBuilder builder1 = RestClient.builder();\n\t\tBuilder builder2 = RestClient.builder();\n\t\tthis.customizer.customize(builder1);\n\t\tthis.customizer.customize(builder2);\n\t\tassertThat(this.customizer.getServer(builder1)).isNotNull();\n\t\tassertThat(this.customizer.getServer(builder2)).isNotNull().isNotSameAs(this.customizer.getServer(builder1));\n\t}\n\n\t@Test\n\tvoid getServerWhenRestClientBuilderIsNotFoundShouldReturnNull() {\n\t\tBuilder builder1 = RestClient.builder();\n\t\tBuilder builder2 = RestClient.builder();\n\t\tthis.customizer.customize(builder1);\n\t\tassertThat(this.customizer.getServer(builder1)).isNotNull();\n\t\tassertThat(this.customizer.getServer(builder2)).isNull();\n\t}\n\n\t@Test\n\tvoid getServersShouldReturnServers() {\n\t\tBuilder builder1 = RestClient.builder();\n\t\tBuilder builder2 = RestClient.builder();\n\t\tthis.customizer.customize(builder1);\n\t\tthis.customizer.customize(builder2);\n\t\tassertThat(this.customizer.getServers()).containsOnlyKeys(builder1, builder2);\n\t}\n\n\t@Test\n\tvoid getExpectationManagersShouldReturnExpectationManagers() {\n\t\tBuilder builder1 = RestClient.builder();\n\t\tBuilder builder2 = RestClient.builder();\n\t\tthis.customizer.customize(builder1);\n\t\tthis.customizer.customize(builder2);\n\t\tRequestExpectationManager manager1 = this.customizer.getExpectationManagers().get(builder1);\n\t\tRequestExpectationManager manager2 = this.customizer.getExpectationManagers().get(builder2);\n\t\tassertThat(this.customizer.getServer(builder1)).extracting(\"expectationManager\").isEqualTo(manager1);\n\t\tassertThat(this.customizer.getServer(builder2)).extracting(\"expectationManager\").isEqualTo(manager2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/MockServerRestTemplateCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test;\n\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.http.client.BufferingClientHttpRequestFactory;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.SimpleRequestExpectationManager;\nimport org.springframework.test.web.client.UnorderedRequestExpectationManager;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link MockServerRestTemplateCustomizer}.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass MockServerRestTemplateCustomizerTests {\n\n\tprivate MockServerRestTemplateCustomizer customizer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.customizer = new MockServerRestTemplateCustomizer();\n\t}\n\n\t@Test\n\tvoid createShouldUseSimpleRequestExpectationManager() {\n\t\tMockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer();\n\t\tcustomizer.customize(new RestTemplate());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(SimpleRequestExpectationManager.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenExpectationManagerClassIsNullShouldThrowException() {\n\t\tClass<? extends RequestExpectationManager> expectationManager = null;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new MockServerRestTemplateCustomizer(expectationManager))\n\t\t\t.withMessageContaining(\"'expectationManager' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenExpectationManagerSupplierIsNullShouldThrowException() {\n\t\tSupplier<? extends RequestExpectationManager> expectationManagerSupplier = null;\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new MockServerRestTemplateCustomizer(expectationManagerSupplier))\n\t\t\t.withMessageContaining(\"'expectationManagerSupplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid createShouldUseExpectationManagerClass() {\n\t\tMockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer(\n\t\t\t\tUnorderedRequestExpectationManager.class);\n\t\tcustomizer.customize(new RestTemplate());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(UnorderedRequestExpectationManager.class);\n\t}\n\n\t@Test\n\tvoid createShouldUseSupplier() {\n\t\tMockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer(\n\t\t\t\tUnorderedRequestExpectationManager::new);\n\t\tcustomizer.customize(new RestTemplate());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(UnorderedRequestExpectationManager.class);\n\t}\n\n\t@Test\n\tvoid detectRootUriShouldDefaultToTrue() {\n\t\tMockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer(\n\t\t\t\tUnorderedRequestExpectationManager.class);\n\t\tcustomizer.customize(new RestTemplateBuilder().baseUri(\"https://example.com\").build());\n\t\tassertThat(customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(RootUriRequestExpectationManager.class);\n\t}\n\n\t@Test\n\tvoid setDetectRootUriShouldDisableRootUriDetection() {\n\t\tthis.customizer.setDetectRootUri(false);\n\t\tthis.customizer.customize(new RestTemplateBuilder().baseUri(\"https://example.com\").build());\n\t\tassertThat(this.customizer.getServer()).extracting(\"expectationManager\")\n\t\t\t.isInstanceOf(SimpleRequestExpectationManager.class);\n\t}\n\n\t@Test\n\tvoid bufferContentShouldDefaultToFalse() {\n\t\tMockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer();\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tcustomizer.customize(restTemplate);\n\t\tassertThat(restTemplate.getRequestFactory()).isInstanceOf(ClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid setBufferContentShouldEnableContentBuffering() {\n\t\tMockServerRestTemplateCustomizer customizer = new MockServerRestTemplateCustomizer();\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tcustomizer.setBufferContent(true);\n\t\tcustomizer.customize(restTemplate);\n\t\tassertThat(restTemplate.getRequestFactory()).isInstanceOf(BufferingClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid customizeShouldBindServer() {\n\t\tRestTemplate template = new RestTemplateBuilder(this.customizer).build();\n\t\tthis.customizer.getServer().expect(requestTo(\"/test\")).andRespond(withSuccess());\n\t\ttemplate.getForEntity(\"/test\", String.class);\n\t\tthis.customizer.getServer().verify();\n\t}\n\n\t@Test\n\tvoid getServerWhenNoServersAreBoundShouldThrowException() {\n\t\tassertThatIllegalStateException().isThrownBy(this.customizer::getServer)\n\t\t\t.withMessageContaining(\"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t\t+ \"MockServerRestTemplateCustomizer has not been bound to a RestTemplate\");\n\t}\n\n\t@Test\n\tvoid getServerWhenMultipleServersAreBoundShouldThrowException() {\n\t\tthis.customizer.customize(new RestTemplate());\n\t\tthis.customizer.customize(new RestTemplate());\n\t\tassertThatIllegalStateException().isThrownBy(this.customizer::getServer)\n\t\t\t.withMessageContaining(\"Unable to return a single MockRestServiceServer since \"\n\t\t\t\t\t+ \"MockServerRestTemplateCustomizer has been bound to more than one RestTemplate\");\n\t}\n\n\t@Test\n\tvoid getServerWhenSingleServerIsBoundShouldReturnServer() {\n\t\tRestTemplate template = new RestTemplate();\n\t\tthis.customizer.customize(template);\n\t\tassertThat(this.customizer.getServer()).isEqualTo(this.customizer.getServer(template));\n\t}\n\n\t@Test\n\tvoid getServerWhenRestTemplateIsFoundShouldReturnServer() {\n\t\tRestTemplate template1 = new RestTemplate();\n\t\tRestTemplate template2 = new RestTemplate();\n\t\tthis.customizer.customize(template1);\n\t\tthis.customizer.customize(template2);\n\t\tassertThat(this.customizer.getServer(template1)).isNotNull();\n\t\tassertThat(this.customizer.getServer(template2)).isNotNull().isNotSameAs(this.customizer.getServer(template1));\n\t}\n\n\t@Test\n\tvoid getServerWhenRestTemplateIsNotFoundShouldReturnNull() {\n\t\tRestTemplate template1 = new RestTemplate();\n\t\tRestTemplate template2 = new RestTemplate();\n\t\tthis.customizer.customize(template1);\n\t\tassertThat(this.customizer.getServer(template1)).isNotNull();\n\t\tassertThat(this.customizer.getServer(template2)).isNull();\n\t}\n\n\t@Test\n\tvoid getServersShouldReturnServers() {\n\t\tRestTemplate template1 = new RestTemplate();\n\t\tRestTemplate template2 = new RestTemplate();\n\t\tthis.customizer.customize(template1);\n\t\tthis.customizer.customize(template2);\n\t\tassertThat(this.customizer.getServers()).containsOnlyKeys(template1, template2);\n\t}\n\n\t@Test\n\tvoid getExpectationManagersShouldReturnExpectationManagers() {\n\t\tRestTemplate template1 = new RestTemplate();\n\t\tRestTemplate template2 = new RestTemplate();\n\t\tthis.customizer.customize(template1);\n\t\tthis.customizer.customize(template2);\n\t\tRequestExpectationManager manager1 = this.customizer.getExpectationManagers().get(template1);\n\t\tRequestExpectationManager manager2 = this.customizer.getExpectationManagers().get(template2);\n\t\tassertThat(this.customizer.getServer(template1)).extracting(\"expectationManager\").isEqualTo(manager1);\n\t\tassertThat(this.customizer.getServer(template2)).extracting(\"expectationManager\").isEqualTo(manager2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/RootUriRequestExpectationManagerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.support.HttpRequestWrapper;\nimport org.springframework.test.web.client.ExpectedCount;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.test.web.client.RequestExpectationManager;\nimport org.springframework.test.web.client.RequestMatcher;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RootUriRequestExpectationManager}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass RootUriRequestExpectationManagerTests {\n\n\tprivate final String uri = \"https://example.com\";\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate RequestExpectationManager delegate;\n\n\tprivate RootUriRequestExpectationManager manager;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.manager = new RootUriRequestExpectationManager(this.uri, this.delegate);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenRootUriIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RootUriRequestExpectationManager(null, this.delegate))\n\t\t\t.withMessageContaining(\"'rootUri' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenExpectationManagerIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new RootUriRequestExpectationManager(this.uri, null))\n\t\t\t.withMessageContaining(\"'expectationManager' must not be null\");\n\t}\n\n\t@Test\n\tvoid expectRequestShouldDelegateToExpectationManager() {\n\t\tExpectedCount count = ExpectedCount.once();\n\t\tRequestMatcher requestMatcher = mock(RequestMatcher.class);\n\t\tthis.manager.expectRequest(count, requestMatcher);\n\t\tthen(this.delegate).should().expectRequest(count, requestMatcher);\n\t}\n\n\t@Test\n\tvoid validateRequestWhenUriDoesNotStartWithRootUriShouldDelegateToExpectationManager() throws Exception {\n\t\tClientHttpRequest request = mock(ClientHttpRequest.class);\n\t\tgiven(request.getURI()).willReturn(new URI(\"https://spring.io/test\"));\n\t\tthis.manager.validateRequest(request);\n\t\tthen(this.delegate).should().validateRequest(request);\n\t}\n\n\t@Test\n\tvoid validateRequestWhenUriStartsWithRootUriShouldReplaceUri() throws Exception {\n\t\tClientHttpRequest request = mock(ClientHttpRequest.class);\n\t\tgiven(request.getURI()).willReturn(new URI(this.uri + \"/hello\"));\n\t\tthis.manager.validateRequest(request);\n\t\tURI expectedURI = new URI(\"/hello\");\n\t\tthen(this.delegate).should()\n\t\t\t.validateRequest(assertArg((actual) -> assertThat(actual).isInstanceOfSatisfying(HttpRequestWrapper.class,\n\t\t\t\t\t(requestWrapper) -> {\n\t\t\t\t\t\tassertThat(requestWrapper.getRequest()).isSameAs(request);\n\t\t\t\t\t\tassertThat(requestWrapper.getURI()).isEqualTo(expectedURI);\n\t\t\t\t\t})));\n\n\t}\n\n\t@Test\n\tvoid validateRequestWhenRequestUriAssertionIsThrownShouldReplaceUriInMessage() throws Exception {\n\t\tClientHttpRequest request = mock(ClientHttpRequest.class);\n\t\tgiven(request.getURI()).willReturn(new URI(this.uri + \"/hello\"));\n\t\tgiven(this.delegate.validateRequest(any(ClientHttpRequest.class)))\n\t\t\t.willThrow(new AssertionError(\"Request URI expected:</hello> was:<https://example.com/bad>\"));\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> this.manager.validateRequest(request))\n\t\t\t.withMessageContaining(\"Request URI expected:<https://example.com/hello>\");\n\t}\n\n\t@Test\n\tvoid resetRequestShouldDelegateToExpectationManager() {\n\t\tthis.manager.reset();\n\t\tthen(this.delegate).should().reset();\n\t}\n\n\t@Test\n\tvoid bindToShouldReturnMockRestServiceServer() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().build();\n\t\tMockRestServiceServer bound = RootUriRequestExpectationManager.bindTo(restTemplate);\n\t\tassertThat(bound).isNotNull();\n\t}\n\n\t@Test\n\tvoid bindToWithExpectationManagerShouldReturnMockRestServiceServer() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().build();\n\t\tMockRestServiceServer bound = RootUriRequestExpectationManager.bindTo(restTemplate, this.delegate);\n\t\tassertThat(bound).isNotNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid forRestTemplateWhenUsingRootUriTemplateHandlerShouldReturnRootUriRequestExpectationManager() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().rootUri(this.uri).build();\n\t\tRequestExpectationManager actual = RootUriRequestExpectationManager.forRestTemplate(restTemplate,\n\t\t\t\tthis.delegate);\n\t\tassertThat(actual).isInstanceOf(RootUriRequestExpectationManager.class);\n\t\tassertThat(actual).extracting(\"rootUri\").isEqualTo(this.uri);\n\t}\n\n\t@Test\n\tvoid forRestTemplateWhenUsingBaseUriTemplateHandlerShouldReturnRootUriRequestExpectationManager() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().baseUri(this.uri).build();\n\t\tRequestExpectationManager actual = RootUriRequestExpectationManager.forRestTemplate(restTemplate,\n\t\t\t\tthis.delegate);\n\t\tassertThat(actual).isInstanceOf(RootUriRequestExpectationManager.class);\n\t\tassertThat(actual).extracting(\"rootUri\").isEqualTo(this.uri);\n\t}\n\n\t@Test\n\tvoid forRestTemplateWhenNotUsingRootUriTemplateHandlerShouldReturnOriginalRequestExpectationManager() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().build();\n\t\tRequestExpectationManager actual = RootUriRequestExpectationManager.forRestTemplate(restTemplate,\n\t\t\t\tthis.delegate);\n\t\tassertThat(actual).isSameAs(this.delegate);\n\t}\n\n\t@Test\n\tvoid boundRestTemplateShouldPrefixBaseUri() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().baseUri(\"https://example.com\").build();\n\t\tMockRestServiceServer server = RootUriRequestExpectationManager.bindTo(restTemplate);\n\t\tserver.expect(requestTo(\"/hello\")).andRespond(withSuccess());\n\t\trestTemplate.getForEntity(\"/hello\", String.class);\n\t}\n\n\t@Test\n\tvoid boundRestTemplateWhenUrlIncludesDomainShouldNotPrefixRootUri() {\n\t\tRestTemplate restTemplate = new RestTemplateBuilder().baseUri(\"https://example.com\").build();\n\t\tMockRestServiceServer server = RootUriRequestExpectationManager.bindTo(restTemplate);\n\t\tserver.expect(requestTo(\"/hello\")).andRespond(withSuccess());\n\t\tassertThatExceptionOfType(AssertionError.class)\n\t\t\t.isThrownBy(() -> restTemplate.getForEntity(\"https://spring.io/hello\", String.class))\n\t\t\t.withMessageContaining(\"expected:<https://example.com/hello> but was:<https://spring.io/hello>\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/AnotherExampleRestClientService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * A second example web client used with {@link RestClientTest @RestClientTest} tests.\n *\n * @author Scott Frederick\n */\n@Service\npublic class AnotherExampleRestClientService {\n\n\tprivate final Builder builder;\n\n\tprivate final RestClient restClient;\n\n\tpublic AnotherExampleRestClientService(RestClient.Builder builder) {\n\t\tthis.builder = builder;\n\t\tthis.restClient = builder.baseUrl(\"https://example.com\").build();\n\t}\n\n\tprotected Builder getRestClientBuilder() {\n\t\treturn this.builder;\n\t}\n\n\tpublic @Nullable String test() {\n\t\treturn this.restClient.get().uri(\"/test\").retrieve().toEntity(String.class).getBody();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/AnotherExampleRestTemplateService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * A second example web client used with {@link RestClientTest @RestClientTest} tests.\n *\n * @author Phillip Webb\n */\n@Service\npublic class AnotherExampleRestTemplateService {\n\n\tprivate final RestTemplate restTemplate;\n\n\tpublic AnotherExampleRestTemplateService(RestTemplateBuilder builder) {\n\t\tthis.restTemplate = builder.baseUri(\"https://example.com\").build();\n\t}\n\n\tprotected RestTemplate getRestTemplate() {\n\t\treturn this.restTemplate;\n\t}\n\n\tpublic @Nullable String test() {\n\t\treturn this.restTemplate.getForEntity(\"/test\", String.class).getBody();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/AutoConfigureMockRestServiceServerEnabledFalseIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.MockServerRestClientCustomizer;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for\n * {@link AutoConfigureMockRestServiceServer @AutoConfigureMockRestServiceServer} with\n * {@code enabled=false}.\n *\n * @author Phillip Webb\n */\n@RestClientTest\n@AutoConfigureMockRestServiceServer(enabled = false)\nclass AutoConfigureMockRestServiceServerEnabledFalseIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid mockServerRestTemplateCustomizerShouldNotBeRegistered() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(MockServerRestTemplateCustomizer.class));\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(MockServerRestClientCustomizer.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/AutoConfigureMockRestServiceServerWithRestClientIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for\n * {@link AutoConfigureMockRestServiceServer @AutoConfigureMockRestServiceServer} with a\n * {@link RestClient} configured with a base URL.\n *\n * @author Scott Frederick\n */\n@SpringBootTest\n@AutoConfigureMockRestServiceServer\nclass AutoConfigureMockRestServiceServerWithRestClientIntegrationTests {\n\n\t@Autowired\n\tprivate RestClient restClient;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid mockServerExpectationsAreMatched() {\n\t\tthis.server.expect(requestTo(\"/rest/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restClient.get().uri(\"/test\").retrieve().toEntity(String.class);\n\t\tassertThat(entity.getBody()).isEqualTo(\"hello\");\n\t}\n\n\t@EnableAutoConfiguration\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RootUriConfiguration {\n\n\t\t@Bean\n\t\tRestClient restClient(Builder restClientBuilder) {\n\t\t\treturn restClientBuilder.baseUrl(\"/rest\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/AutoConfigureMockRestServiceServerWithRestTemplateRootUriIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for\n * {@link AutoConfigureMockRestServiceServer @AutoConfigureMockRestServiceServer} with a\n * {@link RestTemplate} configured with a root URI.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureMockRestServiceServer\nclass AutoConfigureMockRestServiceServerWithRestTemplateRootUriIntegrationTests {\n\n\t@Autowired\n\tprivate RestTemplate restTemplate;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Autowired\n\tMeterRegistry meterRegistry;\n\n\t@Test\n\tvoid whenRestTemplateAppliesARootUriThenMockServerExpectationsAreStillMatched() {\n\t\tthis.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/test\", String.class);\n\t\tassertThat(entity.getBody()).isEqualTo(\"hello\");\n\t\tassertThat(this.meterRegistry.find(\"http.client.requests\").tag(\"uri\", \"/test\").timer()).isNotNull();\n\t}\n\n\t@EnableAutoConfiguration\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RootUriConfiguration {\n\n\t\t@Bean\n\t\tRestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {\n\t\t\treturn restTemplateBuilder.baseUri(\"/rest\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/ExampleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\n\n/**\n * Example {@link ConstructorBinding constructor-bound}\n * {@link ConfigurationProperties @ConfigurationProperties} used to test the use of\n * configuration properties scan with sliced test.\n *\n * @author Stephane Nicoll\n */\n@ConfigurationProperties(\"example\")\npublic class ExampleProperties {\n\n\tprivate final String name;\n\n\tpublic ExampleProperties(@DefaultValue(\"test\") String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/ExampleRestClientService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Example web client using {@code RestClient} with {@link RestClientTest @RestClientTest}\n * tests.\n *\n * @author Scott Frederick\n */\n@Service\npublic class ExampleRestClientService {\n\n\tprivate final Builder builder;\n\n\tprivate final RestClient restClient;\n\n\tpublic ExampleRestClientService(RestClient.Builder builder) {\n\t\tthis.builder = builder;\n\t\tthis.restClient = builder.baseUrl(\"https://example.com\").build();\n\t}\n\n\tprotected Builder getRestClientBuilder() {\n\t\treturn this.builder;\n\t}\n\n\tpublic @Nullable String test() {\n\t\treturn this.restClient.get().uri(\"/test\").retrieve().toEntity(String.class).getBody();\n\t}\n\n\tpublic void testPostWithBody(String body) {\n\t\tthis.restClient.post().uri(\"/test\").body(body).retrieve().toBodilessEntity();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/ExampleRestTemplateService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * Example web client using {@code RestTemplate} with\n * {@link RestClientTest @RestClientTest} tests.\n *\n * @author Phillip Webb\n */\n@Service\npublic class ExampleRestTemplateService {\n\n\tprivate final RestTemplate restTemplate;\n\n\tpublic ExampleRestTemplateService(RestTemplateBuilder builder) {\n\t\tthis.restTemplate = builder.baseUri(\"https://example.com\").build();\n\t}\n\n\tprotected RestTemplate getRestTemplate() {\n\t\treturn this.restTemplate;\n\t}\n\n\tpublic @Nullable String test() {\n\t\treturn this.restTemplate.getForEntity(\"/test\", String.class).getBody();\n\t}\n\n\tpublic void testPostWithBody(String body) {\n\t\tthis.restTemplate.postForObject(\"/test\", body, String.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/ExampleWebClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link RestClientTest @RestClientTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\n@ConfigurationPropertiesScan\npublic class ExampleWebClientApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/MockRestServiceServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.restclient.test.MockServerRestClientCustomizer;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.test.web.client.RequestExpectationManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MockRestServiceServerAutoConfiguration}.\n *\n * @author HuitaePark\n * @author Andy Wilkinson\n */\nclass MockRestServiceServerAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withPropertyValues(\"spring.test.restclient.mockrestserviceserver.enabled=true\")\n\t\t.withConfiguration(AutoConfigurations.of(MockRestServiceServerAutoConfiguration.class));\n\n\t@Test\n\tvoid registersMockServerRestClientCustomizer() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MockServerRestClientCustomizer.class));\n\t}\n\n\t@Test\n\tvoid registersMockServerRestTemplateCustomizer() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MockServerRestTemplateCustomizer.class));\n\t}\n\n\t@Test\n\tvoid registersMockRestServiceServer() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MockRestServiceServer.class));\n\t}\n\n\t@Test\n\tvoid backsOffWhenUserProvidesMockServerRestClientCustomizer() {\n\t\tthis.contextRunner.withBean(\"userMockServerRestClientCustomizer\", MockServerRestClientCustomizer.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MockServerRestClientCustomizer.class)\n\t\t\t\t.hasBean(\"userMockServerRestClientCustomizer\"));\n\t}\n\n\t@Test\n\tvoid backsOffWhenUserProvidesMockServerRestTemplateCustomizer() {\n\t\tthis.contextRunner.withBean(\"userMockServerRestTemplateCustomizer\", MockServerRestTemplateCustomizer.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MockServerRestTemplateCustomizer.class)\n\t\t\t\t.hasBean(\"userMockServerRestTemplateCustomizer\"));\n\t}\n\n\t@Test\n\tvoid backsOffWhenUserProvidesMockRestServiceServer() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"userMockRestServiceServer\", MockRestServiceServer.class, mock(RequestExpectationManager.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MockRestServiceServer.class)\n\t\t\t\t.hasBean(\"userMockRestServiceServer\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestNoComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with no specific client.\n *\n * @author Phillip Webb\n */\n@RestClientTest\nclass RestClientTestNoComponentIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate RestTemplateBuilder restTemplateBuilder;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid exampleRestClientIsNotInjected() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleRestTemplateService.class));\n\t}\n\n\t@Test\n\tvoid examplePropertiesIsNotInjected() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleProperties.class));\n\t}\n\n\t@Test\n\tvoid manuallyCreateBean() {\n\t\tExampleRestTemplateService client = new ExampleRestTemplateService(this.restTemplateBuilder);\n\t\tthis.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(client.test()).isEqualTo(\"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link RestClientTest#properties properties} attribute of\n * {@link RestClientTest @RestClientTest}.\n *\n * @author Artsiom Yudovin\n */\n@RestClientTest(properties = \"spring.profiles.active=test\")\nclass RestClientTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(RestClientTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestRestClientIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.content;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with a {@link RestClient}.\n *\n * @author Scott Frederick\n */\n@RestClientTest(ExampleRestClientService.class)\nclass RestClientTestRestClientIntegrationTests {\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Autowired\n\tprivate ExampleRestClientService client;\n\n\t@Test\n\tvoid mockServerCall1() {\n\t\tthis.server.expect(requestTo(uri(\"/test\"))).andRespond(withSuccess(\"1\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"1\");\n\t}\n\n\t@Test\n\tvoid mockServerCall2() {\n\t\tthis.server.expect(requestTo(uri(\"/test\"))).andRespond(withSuccess(\"2\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"2\");\n\t}\n\n\t@Test\n\tvoid mockServerCallWithContent() {\n\t\tthis.server.expect(requestTo(uri(\"/test\")))\n\t\t\t.andExpect(content().string(\"test\"))\n\t\t\t.andRespond(withSuccess(\"1\", MediaType.TEXT_HTML));\n\t\tthis.client.testPostWithBody(\"test\");\n\t}\n\n\tprivate static String uri(String path) {\n\t\treturn \"https://example.com\" + path;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestRestClientTwoComponentsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.MockServerRestClientCustomizer;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with two {@code RestClient} clients.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@RestClientTest({ ExampleRestClientService.class, AnotherExampleRestClientService.class })\nclass RestClientTestRestClientTwoComponentsIntegrationTests {\n\n\t@Autowired\n\tprivate ExampleRestClientService client1;\n\n\t@Autowired\n\tprivate AnotherExampleRestClientService client2;\n\n\t@Autowired\n\tprivate MockServerRestClientCustomizer customizer;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid serverShouldNotWork() {\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> this.server.expect(requestTo(uri(\"/test\"))).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML)))\n\t\t\t.withMessageContaining(\"Unable to use auto-configured\");\n\t}\n\n\t@Test\n\tvoid client1RestCallViaCustomizer() {\n\t\tMockRestServiceServer server = this.customizer.getServer(this.client1.getRestClientBuilder());\n\t\tassertThat(server).isNotNull();\n\t\tserver.expect(requestTo(uri(\"/test\"))).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client1.test()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid client2RestCallViaCustomizer() {\n\t\tMockRestServiceServer server = this.customizer.getServer(this.client2.getRestClientBuilder());\n\t\tassertThat(server).isNotNull();\n\t\tserver.expect(requestTo(uri(\"/test\"))).andRespond(withSuccess(\"there\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client2.test()).isEqualTo(\"there\");\n\t}\n\n\tprivate static String uri(String path) {\n\t\treturn \"https://example.com\" + path;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestRestTemplateAndRestClientTogetherIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.MockServerRestClientCustomizer;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with a {@code RestTemplate} and a\n * {@code RestClient} clients.\n *\n * @author Scott Frederick\n */\n@RestClientTest({ ExampleRestTemplateService.class, ExampleRestClientService.class })\nclass RestClientTestRestTemplateAndRestClientTogetherIntegrationTests {\n\n\t@Autowired\n\tprivate ExampleRestTemplateService restTemplateClient;\n\n\t@Autowired\n\tprivate ExampleRestClientService restClientClient;\n\n\t@Autowired\n\tprivate MockServerRestTemplateCustomizer templateCustomizer;\n\n\t@Autowired\n\tprivate MockServerRestClientCustomizer clientCustomizer;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid serverShouldNotWork() {\n\t\tassertThatIllegalStateException().isThrownBy(\n\t\t\t\t() -> this.server.expect(requestTo(uri(\"/test\"))).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML)))\n\t\t\t.withMessageContaining(\"Unable to use auto-configured\");\n\t}\n\n\t@Test\n\tvoid restTemplateClientRestCallViaCustomizer() {\n\t\tthis.templateCustomizer.getServer()\n\t\t\t.expect(requestTo(\"/test\"))\n\t\t\t.andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(this.restTemplateClient.test()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid restClientClientRestCallViaCustomizer() {\n\t\tthis.clientCustomizer.getServer()\n\t\t\t.expect(requestTo(uri(\"/test\")))\n\t\t\t.andRespond(withSuccess(\"there\", MediaType.TEXT_HTML));\n\t\tassertThat(this.restClientClient.test()).isEqualTo(\"there\");\n\t}\n\n\tprivate static String uri(String path) {\n\t\treturn \"https://example.com\" + path;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestRestTemplateIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.content;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} gets reset after test methods.\n *\n * @author Phillip Webb\n */\n@RestClientTest(ExampleRestTemplateService.class)\nclass RestClientTestRestTemplateIntegrationTests {\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Autowired\n\tprivate ExampleRestTemplateService client;\n\n\t@Test\n\tvoid mockServerCall1() {\n\t\tthis.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"1\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"1\");\n\t}\n\n\t@Test\n\tvoid mockServerCall2() {\n\t\tthis.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"2\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"2\");\n\t}\n\n\t@Test\n\tvoid mockServerCallWithContent() {\n\t\tthis.server.expect(requestTo(\"/test\"))\n\t\t\t.andExpect(content().string(\"test\"))\n\t\t\t.andRespond(withSuccess(\"1\", MediaType.TEXT_HTML));\n\t\tthis.client.testPostWithBody(\"test\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestRestTemplateTwoComponentsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.MockServerRestTemplateCustomizer;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with two {@code RestTemplate} clients.\n *\n * @author Phillip Webb\n */\n@RestClientTest({ ExampleRestTemplateService.class, AnotherExampleRestTemplateService.class })\nclass RestClientTestRestTemplateTwoComponentsIntegrationTests {\n\n\t@Autowired\n\tprivate ExampleRestTemplateService client1;\n\n\t@Autowired\n\tprivate AnotherExampleRestTemplateService client2;\n\n\t@Autowired\n\tprivate MockServerRestTemplateCustomizer customizer;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\tvoid serverShouldNotWork() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML)))\n\t\t\t.withMessageContaining(\"Unable to use auto-configured\");\n\t}\n\n\t@Test\n\tvoid client1RestCallViaCustomizer() {\n\t\tMockRestServiceServer server = this.customizer.getServer(this.client1.getRestTemplate());\n\t\tassertThat(server).isNotNull();\n\t\tserver.expect(requestTo(\"/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client1.test()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid client2RestCallViaCustomizer() {\n\t\tMockRestServiceServer server = this.customizer.getServer(this.client2.getRestTemplate());\n\t\tassertThat(server).isNotNull();\n\t\tserver.expect(requestTo(\"/test\")).andRespond(withSuccess(\"there\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client2.test()).isEqualTo(\"there\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestWithConfigurationPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with a\n * {@link ConfigurationProperties @ConfigurationProperties} annotated type.\n *\n * @author Stephane Nicoll\n */\n@RestClientTest(components = ExampleProperties.class, properties = \"example.name=Hello\")\nclass RestClientTestWithConfigurationPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid configurationPropertiesCanBeAddedAsComponent() {\n\t\tassertThat(this.applicationContext.getBeansOfType(ExampleProperties.class).keySet())\n\t\t\t.containsOnly(\"example-\" + ExampleProperties.class.getName());\n\t\tassertThat(this.applicationContext.getBean(ExampleProperties.class).getName()).isEqualTo(\"Hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestWithRestClientComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with a single client using\n * {@code RestClient}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\n@RestClientTest(ExampleRestClientService.class)\nclass RestClientTestWithRestClientComponentIntegrationTests {\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Autowired\n\tprivate ExampleRestClientService client;\n\n\t@Test\n\tvoid mockServerCall() {\n\t\tthis.server.expect(requestTo(\"https://example.com/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestWithRestTemplateComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} with a single client using\n * {@code RestTemplate}.\n *\n * @author Phillip Webb\n */\n@RestClientTest(ExampleRestTemplateService.class)\nclass RestClientTestWithRestTemplateComponentIntegrationTests {\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Autowired\n\tprivate ExampleRestTemplateService client;\n\n\t@Test\n\tvoid mockServerCall() {\n\t\tthis.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restclient-test/src/test/java/org/springframework/boot/restclient/test/autoconfigure/RestClientTestWithoutJacksonIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RestClientTest @RestClientTest} without Jackson.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"jackson-*.jar\")\n@RestClientTest(ExampleRestTemplateService.class)\nclass RestClientTestWithoutJacksonIntegrationTests {\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Autowired\n\tprivate ExampleRestTemplateService client;\n\n\t@Test\n\tvoid restClientTestCanBeUsedWhenJacksonIsNotOnTheClassPath() {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tassertThat(ClassUtils.isPresent(\"com.fasterxml.jackson.databind.Module\", classLoader)).isFalse();\n\t\tassertThat(ClassUtils.isPresent(\"tools.jackson.databind.JacksonModule\", classLoader)).isFalse();\n\t\tthis.server.expect(requestTo(\"/test\")).andRespond(withSuccess(\"hello\", MediaType.TEXT_HTML));\n\t\tassertThat(this.client.test()).isEqualTo(\"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot REST Docs\"\n\ndependencies {\n\tapi(\"org.springframework.restdocs:spring-restdocs-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\toptional(project(\":module:spring-boot-webflux-test\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(\"org.springframework.restdocs:spring-restdocs-mockmvc\")\n\toptional(\"org.springframework.restdocs:spring-restdocs-webtestclient\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-hateoas\"))\n\ttestImplementation(\"org.springframework.security:spring-security-test\")\n\n\ttestRuntimeOnly(project(\":module:spring-boot-tomcat\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/AutoConfigureRestDocs.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.test.web.servlet.MockMvc;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of Spring REST Docs. The auto-configuration sets up\n * {@link MockMvc}-based testing of a servlet web application or\n * {@link WebTestClient}-based testing of a reactive web application.\n * <p>\n * Allows configuration of the output directory and the host, scheme, and port of\n * generated URIs. When further configuration is required a\n * {@link RestDocsMockMvcConfigurationCustomizer} or\n * {@link RestDocsWebTestClientConfigurationCustomizer} bean can be used.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see RestDocsAutoConfiguration\n * @see RestDocsMockMvcConfigurationCustomizer\n * @see RestDocsWebTestClientConfigurationCustomizer\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@Import(RestDocumentationContextProviderRegistrar.class)\n@PropertyMapping(\"spring.test.restdocs\")\npublic @interface AutoConfigureRestDocs {\n\n\t/**\n\t * The output directory to which generated snippets will be written. An alias for\n\t * {@link #outputDir}.\n\t * @return the output directory\n\t */\n\t@AliasFor(\"outputDir\")\n\tString value() default \"\";\n\n\t/**\n\t * The output directory to which generated snippets will be written. An alias for\n\t * {@link #value}.\n\t * @return the output directory\n\t */\n\t@AliasFor(\"value\")\n\tString outputDir() default \"\";\n\n\t/**\n\t * The scheme (typically {@code http} or {@code https}) to be used in documented URIs.\n\t * Defaults to {@code http}.\n\t * @return the scheme\n\t */\n\tString uriScheme() default \"http\";\n\n\t/**\n\t * The host to be used in documented URIs. Defaults to {@code localhost}.\n\t * @return the host\n\t */\n\tString uriHost() default \"localhost\";\n\n\t/**\n\t * The port to be used in documented URIs. Defaults to {@code 8080}.\n\t * @return the port\n\t */\n\tint uriPort() default 8080;\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.restdocs.RestDocumentationContextProvider;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;\nimport org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation;\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring REST Docs.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Roman Zaynetdinov\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication\npublic final class RestDocsAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(MockMvcRestDocumentation.class)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\t@EnableConfigurationProperties(RestDocsProperties.class)\n\tstatic class RestDocsMockMvcConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tMockMvcRestDocumentationConfigurer restDocsMockMvcConfigurer(\n\t\t\t\tObjectProvider<RestDocsMockMvcConfigurationCustomizer> configurationCustomizers,\n\t\t\t\tRestDocumentationContextProvider contextProvider) {\n\t\t\tMockMvcRestDocumentationConfigurer configurer = MockMvcRestDocumentation\n\t\t\t\t.documentationConfiguration(contextProvider);\n\t\t\tconfigurationCustomizers.orderedStream()\n\t\t\t\t.forEach((configurationCustomizer) -> configurationCustomizer.customize(configurer));\n\t\t\treturn configurer;\n\t\t}\n\n\t\t@Bean\n\t\tRestDocsMockMvcBuilderCustomizer restDocumentationConfigurer(RestDocsProperties properties,\n\t\t\t\tMockMvcRestDocumentationConfigurer configurer,\n\t\t\t\tObjectProvider<RestDocumentationResultHandler> resultHandler) {\n\t\t\treturn new RestDocsMockMvcBuilderCustomizer(properties, configurer, resultHandler.getIfAvailable());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ WebTestClientRestDocumentation.class, WebTestClientBuilderCustomizer.class })\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t@EnableConfigurationProperties(RestDocsProperties.class)\n\tstatic class RestDocsWebTestClientConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tWebTestClientRestDocumentationConfigurer restDocsWebTestClientConfigurer(\n\t\t\t\tObjectProvider<RestDocsWebTestClientConfigurationCustomizer> configurationCustomizers,\n\t\t\t\tRestDocumentationContextProvider contextProvider) {\n\t\t\tWebTestClientRestDocumentationConfigurer configurer = WebTestClientRestDocumentation\n\t\t\t\t.documentationConfiguration(contextProvider);\n\t\t\tconfigurationCustomizers.orderedStream()\n\t\t\t\t.forEach((configurationCustomizer) -> configurationCustomizer.customize(configurer));\n\t\t\treturn configurer;\n\t\t}\n\n\t\t@Bean\n\t\tRestDocsWebTestClientBuilderCustomizer restDocumentationConfigurer(RestDocsProperties properties,\n\t\t\t\tWebTestClientRestDocumentationConfigurer configurer) {\n\t\t\treturn new RestDocsWebTestClientBuilderCustomizer(properties, configurer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsMockMvcBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.webmvc.test.autoconfigure.MockMvcBuilderCustomizer;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;\nimport org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;\nimport org.springframework.restdocs.mockmvc.UriConfigurer;\nimport org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;\n\n/**\n * A {@link MockMvcBuilderCustomizer} that configures Spring REST Docs.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class RestDocsMockMvcBuilderCustomizer implements InitializingBean, MockMvcBuilderCustomizer {\n\n\tprivate final RestDocsProperties properties;\n\n\tprivate final MockMvcRestDocumentationConfigurer delegate;\n\n\tprivate final @Nullable RestDocumentationResultHandler resultHandler;\n\n\tRestDocsMockMvcBuilderCustomizer(RestDocsProperties properties, MockMvcRestDocumentationConfigurer delegate,\n\t\t\t@Nullable RestDocumentationResultHandler resultHandler) {\n\t\tthis.properties = properties;\n\t\tthis.delegate = delegate;\n\t\tthis.resultHandler = resultHandler;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRestDocsProperties properties = this.properties;\n\t\tUriConfigurer uri = this.delegate.uris();\n\t\tmap.from(properties::getUriScheme).whenHasText().to(uri::withScheme);\n\t\tmap.from(properties::getUriHost).whenHasText().to(uri::withHost);\n\t\tmap.from(properties::getUriPort).to(uri::withPort);\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableMockMvcBuilder<?> builder) {\n\t\tbuilder.apply(this.delegate);\n\t\tif (this.resultHandler != null) {\n\t\t\tbuilder.alwaysDo(this.resultHandler);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsMockMvcConfigurationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentationConfigurer;\n\n/**\n * A customizer for {@link MockMvcRestDocumentationConfigurer}. If a\n * {@code RestDocsMockMvcConfigurationCustomizer} bean is found in the application context\n * it will be {@link #customize called} to customize the\n * {@code MockMvcRestDocumentationConfigurer} before it is applied. Intended for use only\n * when the attributes on {@link AutoConfigureRestDocs @AutoConfigureRestDocs} do not\n * provide sufficient customization.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RestDocsMockMvcConfigurationCustomizer {\n\n\t/**\n\t * Customize the given {@code configurer}.\n\t * @param configurer the configurer\n\t */\n\tvoid customize(MockMvcRestDocumentationConfigurer configurer);\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for Spring REST Docs.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.test.restdocs\")\npublic class RestDocsProperties {\n\n\t/**\n\t * The URI scheme for to use (for example http).\n\t */\n\tprivate @Nullable String uriScheme;\n\n\t/**\n\t * The URI host to use.\n\t */\n\tprivate @Nullable String uriHost;\n\n\t/**\n\t * The URI port to use.\n\t */\n\tprivate @Nullable Integer uriPort;\n\n\tpublic @Nullable String getUriScheme() {\n\t\treturn this.uriScheme;\n\t}\n\n\tpublic void setUriScheme(@Nullable String uriScheme) {\n\t\tthis.uriScheme = uriScheme;\n\t}\n\n\tpublic @Nullable String getUriHost() {\n\t\treturn this.uriHost;\n\t}\n\n\tpublic void setUriHost(@Nullable String uriHost) {\n\t\tthis.uriHost = uriHost;\n\t}\n\n\tpublic @Nullable Integer getUriPort() {\n\t\treturn this.uriPort;\n\t}\n\n\tpublic void setUriPort(@Nullable Integer uriPort) {\n\t\tthis.uriPort = uriPort;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsTestExecutionListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.core.Ordered;\nimport org.springframework.restdocs.ManualRestDocumentation;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestExecutionListener;\nimport org.springframework.test.context.support.AbstractTestExecutionListener;\nimport org.springframework.util.ClassUtils;\n\n/**\n * A {@link TestExecutionListener} for Spring REST Docs that removes the need for a\n * {@code @Rule} when using JUnit or manual before and after test calls when using TestNG.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class RestDocsTestExecutionListener extends AbstractTestExecutionListener {\n\n\tprivate static final boolean REST_DOCS_PRESENT = ClassUtils.isPresent(\n\t\t\t\"org.springframework.restdocs.ManualRestDocumentation\",\n\t\t\tRestDocsTestExecutionListener.class.getClassLoader());\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE - 100;\n\t}\n\n\t@Override\n\tpublic void beforeTestMethod(TestContext testContext) throws Exception {\n\t\tif (REST_DOCS_PRESENT) {\n\t\t\tnew DocumentationHandler().beforeTestMethod(testContext);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterTestMethod(TestContext testContext) throws Exception {\n\t\tif (REST_DOCS_PRESENT) {\n\t\t\tnew DocumentationHandler().afterTestMethod(testContext);\n\t\t}\n\t}\n\n\tprivate static final class DocumentationHandler {\n\n\t\tprivate void beforeTestMethod(TestContext testContext) {\n\t\t\tManualRestDocumentation restDocumentation = findManualRestDocumentation(testContext);\n\t\t\tif (restDocumentation != null) {\n\t\t\t\trestDocumentation.beforeTest(testContext.getTestClass(), testContext.getTestMethod().getName());\n\t\t\t}\n\t\t}\n\n\t\tprivate void afterTestMethod(TestContext testContext) {\n\t\t\tManualRestDocumentation restDocumentation = findManualRestDocumentation(testContext);\n\t\t\tif (restDocumentation != null) {\n\t\t\t\trestDocumentation.afterTest();\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable ManualRestDocumentation findManualRestDocumentation(TestContext testContext) {\n\t\t\ttry {\n\t\t\t\treturn testContext.getApplicationContext().getBean(ManualRestDocumentation.class);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsWebTestClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.webtestclient.autoconfigure.WebTestClientBuilderCustomizer;\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link WebTestClientBuilderCustomizer} that configures Spring REST Docs.\n *\n * @author Roman Zaynetdinov\n * @author Andy Wilkinson\n */\nclass RestDocsWebTestClientBuilderCustomizer implements WebTestClientBuilderCustomizer {\n\n\tprivate final RestDocsProperties properties;\n\n\tprivate final WebTestClientRestDocumentationConfigurer delegate;\n\n\tRestDocsWebTestClientBuilderCustomizer(RestDocsProperties properties,\n\t\t\tWebTestClientRestDocumentationConfigurer delegate) {\n\t\tthis.properties = properties;\n\t\tthis.delegate = delegate;\n\t}\n\n\t@Override\n\tpublic void customize(WebTestClient.Builder builder) {\n\t\tcustomizeBaseUrl(builder);\n\t\tbuilder.filter(this.delegate);\n\t}\n\n\tprivate void customizeBaseUrl(WebTestClient.Builder builder) {\n\t\tString scheme = this.properties.getUriScheme();\n\t\tString host = this.properties.getUriHost();\n\t\tString baseUrl = (StringUtils.hasText(scheme) ? scheme : \"http\") + \"://\"\n\t\t\t\t+ (StringUtils.hasText(host) ? host : \"localhost\");\n\t\tInteger port = this.properties.getUriPort();\n\t\tif (!isStandardPort(scheme, port)) {\n\t\t\tbaseUrl += \":\" + port;\n\t\t}\n\t\tbuilder.baseUrl(baseUrl);\n\t}\n\n\tprivate boolean isStandardPort(@Nullable String scheme, @Nullable Integer port) {\n\t\tif (port == null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (\"http\".equals(scheme) && port == 80) || (\"https\".equals(scheme) && port == 443);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsWebTestClientConfigurationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;\n\n/**\n * A customizer for {@link WebTestClientRestDocumentationConfigurer}. If a\n * {@code RestDocsWebTestClientConfigurationCustomizer} bean is found in the application\n * context it will be {@link #customize called} to customize the\n * {@code WebTestClientRestDocumentationConfigurer} before it is applied. Intended for use\n * only when the attributes on {@link AutoConfigureRestDocs @AutoConfigureRestDocs} do not\n * provide sufficient customization.\n *\n * @author Roman Zaynetdinov\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RestDocsWebTestClientConfigurationCustomizer {\n\n\t/**\n\t * Customize the given {@code configurer}.\n\t * @param configurer the configurer\n\t */\n\tvoid customize(WebTestClientRestDocumentationConfigurer configurer);\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocumentationContextProviderRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.restdocs.ManualRestDocumentation;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used by\n * {@link AutoConfigureRestDocs @AutoConfigureRestDocs}.\n *\n * @author Andy Wilkinson\n * @see AutoConfigureRestDocs\n */\nclass RestDocumentationContextProviderRegistrar implements ImportBeanDefinitionRegistrar {\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tMap<String, @Nullable Object> annotationAttributes = importingClassMetadata\n\t\t\t.getAnnotationAttributes(AutoConfigureRestDocs.class.getName());\n\t\tBeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder\n\t\t\t.rootBeanDefinition(ManualRestDocumentation.class);\n\t\tAssert.state(annotationAttributes != null, \"'annotationAttributes' must not be null\");\n\t\tString outputDir = (String) annotationAttributes.get(\"outputDir\");\n\t\tif (StringUtils.hasText(outputDir)) {\n\t\t\tdefinitionBuilder.addConstructorArgValue(outputDir);\n\t\t}\n\t\tregistry.registerBeanDefinition(ManualRestDocumentation.class.getName(), definitionBuilder.getBeanDefinition());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for tests using Spring REST Docs.\n */\n@NullMarked\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/resources/META-INF/spring/org.springframework.boot.restdocs.test.autoconfigure.AutoConfigureRestDocs.imports",
    "content": "org.springframework.boot.restdocs.test.autoconfigure.RestDocsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Execution Listeners\norg.springframework.test.context.TestExecutionListener=\\\norg.springframework.boot.restdocs.test.autoconfigure.RestDocsTestExecutionListener\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/test/java/org/springframework/boot/restdocs/test/autoconfigure/MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;\nimport org.springframework.restdocs.templates.TemplateFormats;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;\nimport static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\n\n/**\n * Integration tests for advanced configuration of\n * {@link AutoConfigureRestDocs @AutoConfigureRestDocs} with Mock MVC.\n *\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n */\n@WebMvcTest(controllers = RestDocsTestController.class)\n@WithMockUser\n@AutoConfigureRestDocs\nclass MockMvcRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Autowired\n\tprivate RestDocumentationResultHandler documentationHandler;\n\n\tprivate File generatedSnippets;\n\n\t@BeforeEach\n\tvoid deleteSnippets() {\n\t\tthis.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(), \"generated-snippets\");\n\t\tFileSystemUtils.deleteRecursively(this.generatedSnippets);\n\t}\n\n\t@Test\n\tvoid snippetGeneration() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).apply(this.documentationHandler\n\t\t\t.document(links(linkWithRel(\"self\").description(\"Canonical location of this resource\"))));\n\t\tFile defaultSnippetsDir = new File(this.generatedSnippets, \"snippet-generation\");\n\t\tassertThat(defaultSnippetsDir).exists();\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"curl-request.md\"))).contains(\"'http://localhost:8080/'\");\n\t\tassertThat(new File(defaultSnippetsDir, \"links.md\")).isFile();\n\t\tassertThat(new File(defaultSnippetsDir, \"response-fields.md\")).isFile();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class CustomizationConfiguration {\n\n\t\t@Bean\n\t\tRestDocumentationResultHandler restDocumentation() {\n\t\t\treturn MockMvcRestDocumentation.document(\"{method-name}\");\n\t\t}\n\n\t\t@Bean\n\t\tRestDocsMockMvcConfigurationCustomizer templateFormatCustomizer() {\n\t\t\treturn (configurer) -> configurer.snippets().withTemplateFormat(TemplateFormats.markdown());\n\t\t}\n\n\t\t@Bean\n\t\tRestDocsMockMvcConfigurationCustomizer defaultSnippetsCustomizer() {\n\t\t\treturn (configurer) -> configurer.snippets()\n\t\t\t\t.withAdditionalDefaults(responseFields(fieldWithPath(\"_links.self\").description(\"Main URL\")));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/test/java/org/springframework/boot/restdocs/test/autoconfigure/MockMvcRestDocsAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;\n\n/**\n * Integration tests for {@link RestDocsAutoConfiguration} with Mock MVC.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\n@AutoConfigureRestDocs(uriScheme = \"https\", uriHost = \"api.example.com\", uriPort = 443)\nclass MockMvcRestDocsAutoConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\tprivate File generatedSnippets;\n\n\t@BeforeEach\n\tvoid deleteSnippets() {\n\t\tthis.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(), \"generated-snippets\");\n\t\tFileSystemUtils.deleteRecursively(this.generatedSnippets);\n\t}\n\n\t@Test\n\tvoid defaultSnippetsAreWritten() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).apply(document(\"default-snippets\"));\n\t\tFile defaultSnippetsDir = new File(this.generatedSnippets, \"default-snippets\");\n\t\tassertThat(defaultSnippetsDir).exists();\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"curl-request.adoc\"))).contains(\"'https://api.example.com/'\");\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"http-request.adoc\"))).contains(\"api.example.com\");\n\t\tassertThat(new File(defaultSnippetsDir, \"http-response.adoc\")).isFile();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/test/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Test application used with {@link AutoConfigureRestDocs @AutoConfigureRestDocs} tests.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class RestDocsTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/test/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsTestController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.hateoas.MediaTypes;\nimport org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class RestDocsTestController {\n\n\t@ResponseBody\n\t@RequestMapping(path = \"/\", produces = MediaTypes.HAL_JSON_VALUE)\n\tpublic Map<String, Object> index() {\n\t\tMap<String, Object> response = new HashMap<>();\n\t\tMap<String, String> links = new HashMap<>();\n\t\tlinks.put(\"self\", WebMvcLinkBuilder.linkTo(getClass()).toUri().toString());\n\t\tresponse.put(\"_links\", links);\n\t\treturn response;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/test/java/org/springframework/boot/restdocs/test/autoconfigure/WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;\nimport org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;\nimport org.springframework.restdocs.templates.TemplateFormats;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;\nimport static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;\n\n/**\n * Integration tests for {@link RestDocsAutoConfiguration} with {@link WebTestClient}.\n *\n * @author Eddú Meléndez\n */\n@WebFluxTest\n@WithMockUser\n@AutoConfigureRestDocs(uriScheme = \"https\", uriHost = \"api.example.com\", uriPort = 443)\nclass WebTestClientRestDocsAutoConfigurationAdvancedConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webTestClient;\n\n\tprivate File generatedSnippets;\n\n\t@BeforeEach\n\tvoid deleteSnippets() {\n\t\tthis.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(), \"generated-snippets\");\n\t\tFileSystemUtils.deleteRecursively(this.generatedSnippets);\n\t}\n\n\t@Test\n\tvoid defaultSnippetsAreWritten() {\n\t\tthis.webTestClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.is2xxSuccessful()\n\t\t\t.expectBody()\n\t\t\t.consumeWith(document(\"default-snippets\"));\n\t\tFile defaultSnippetsDir = new File(this.generatedSnippets, \"default-snippets\");\n\t\tassertThat(defaultSnippetsDir).exists();\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"curl-request.md\"))).contains(\"'https://api.example.com/'\");\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"http-request.md\"))).contains(\"api.example.com\");\n\t\tassertThat(new File(defaultSnippetsDir, \"http-response.md\")).isFile();\n\t\tassertThat(new File(defaultSnippetsDir, \"response-fields.md\")).isFile();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class CustomizationConfiguration {\n\n\t\t@Bean\n\t\tRestDocumentationResultHandler restDocumentation() {\n\t\t\treturn MockMvcRestDocumentation.document(\"{method-name}\");\n\t\t}\n\n\t\t@Bean\n\t\tRestDocsWebTestClientConfigurationCustomizer templateFormatCustomizer() {\n\t\t\treturn (configurer) -> configurer.snippets().withTemplateFormat(TemplateFormats.markdown());\n\t\t}\n\n\t\t@Bean\n\t\tRestDocsWebTestClientConfigurationCustomizer defaultSnippetsCustomizer() {\n\t\t\treturn (configurer) -> configurer.snippets()\n\t\t\t\t.withAdditionalDefaults(responseFields(fieldWithPath(\"_links.self\").description(\"Main URL\")));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-restdocs/src/test/java/org/springframework/boot/restdocs/test/autoconfigure/WebTestClientRestDocsAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.restdocs.test.autoconfigure;\n\nimport java.io.File;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;\n\n/**\n * Integration tests for {@link RestDocsAutoConfiguration} with {@link WebTestClient}.\n *\n * @author Roman Zaynetdinov\n */\n@WebFluxTest\n@WithMockUser\n@AutoConfigureRestDocs(uriScheme = \"https\", uriHost = \"api.example.com\", uriPort = 443)\nclass WebTestClientRestDocsAutoConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webTestClient;\n\n\tprivate File generatedSnippets;\n\n\t@BeforeEach\n\tvoid deleteSnippets() {\n\t\tthis.generatedSnippets = new File(new BuildOutput(getClass()).getRootLocation(), \"generated-snippets\");\n\t\tFileSystemUtils.deleteRecursively(this.generatedSnippets);\n\t}\n\n\t@Test\n\tvoid defaultSnippetsAreWritten() {\n\t\tthis.webTestClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.is2xxSuccessful()\n\t\t\t.expectBody()\n\t\t\t.consumeWith(document(\"default-snippets\"));\n\t\tFile defaultSnippetsDir = new File(this.generatedSnippets, \"default-snippets\");\n\t\tassertThat(defaultSnippetsDir).exists();\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"curl-request.adoc\"))).contains(\"'https://api.example.com/'\");\n\t\tassertThat(contentOf(new File(defaultSnippetsDir, \"http-request.adoc\"))).contains(\"api.example.com\");\n\t\tassertThat(new File(defaultSnippetsDir, \"http-response.adoc\")).isFile();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"org.jetbrains.dokka\"\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot RestTestClient\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test\"))\n\tapi(project(\":module:spring-boot-http-converter\"))\n\tapi(\"org.springframework:spring-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-restclient\"))\n\toptional(\"org.apache.httpcomponents.client5:httpclient5\")\n\toptional(\"org.jetbrains.kotlin:kotlin-stdlib\")\n\toptional(\"org.jetbrains.kotlin:kotlin-reflect\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/TestRestTemplate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient;\n\nimport java.net.URI;\nimport java.security.KeyManagementException;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.X509Certificate;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Consumer;\nimport java.util.function.UnaryOperator;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.cookie.StandardCookieSpec;\nimport org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;\nimport org.apache.hc.client5.http.ssl.TlsSocketStrategy;\nimport org.apache.hc.core5.http.ssl.TLS;\nimport org.apache.hc.core5.ssl.SSLContextBuilder;\nimport org.apache.hc.core5.ssl.TrustStrategy;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpComponentsHttpClientBuilder.TlsSocketStrategyFactory;\nimport org.springframework.boot.http.client.HttpCookieHandling;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.RequestEntity.UriTemplateRequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.client.NoOpResponseErrorHandler;\nimport org.springframework.web.client.RequestCallback;\nimport org.springframework.web.client.ResponseExtractor;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\nimport org.springframework.web.util.UriTemplateHandler;\n\n/**\n * Convenient alternative of {@link RestTemplate} that is suitable for integration tests.\n * {@code TestRestTemplate} is fault-tolerant. This means that 4xx and 5xx do not result\n * in an exception being thrown and can instead be detected through the\n * {@link ResponseEntity response entity} and its {@link ResponseEntity#getStatusCode()\n * status code}.\n * <p>\n * A {@code TestRestTemplate} can optionally carry Basic authentication headers. If Apache\n * Http Client 4.3.2 or better is available (recommended) it will be used as the client.\n * <p>\n * Note: To prevent injection problems this class intentionally does not extend\n * {@link RestTemplate}. If you need access to the underlying {@link RestTemplate} use\n * {@link #getRestTemplate()}.\n * <p>\n * If you are using the {@code @SpringBootTest} annotation with an embedded server, a\n * {@link TestRestTemplate} can be auto-configured by adding\n * {@link AutoConfigureTestRestTemplate @AutoConfigureTestRestTemplate} to your test\n * class. It can then be {@code @Autowired} into your test. If you need customizations\n * (for example to adding additional message converters) use a {@link RestTemplateBuilder}\n * {@code @Bean}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Kristine Jetzke\n * @author Dmytro Nosan\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class TestRestTemplate {\n\n\tprivate final RestTemplateBuilder builder;\n\n\tprivate final RestTemplate restTemplate;\n\n\t/**\n\t * Create a new {@link TestRestTemplate} instance.\n\t * @param restTemplateBuilder builder used to configure underlying\n\t * {@link RestTemplate}\n\t */\n\tpublic TestRestTemplate(RestTemplateBuilder restTemplateBuilder) {\n\t\tthis(restTemplateBuilder, null, null);\n\t}\n\n\t/**\n\t * Create a new {@link TestRestTemplate} instance.\n\t * @param httpClientOptions client options to use if the Apache HTTP Client is used\n\t */\n\tpublic TestRestTemplate(HttpClientOption... httpClientOptions) {\n\t\tthis(null, null, httpClientOptions);\n\t}\n\n\t/**\n\t * Create a new {@link TestRestTemplate} instance with the specified credentials.\n\t * @param username the username to use (or {@code null})\n\t * @param password the password (or {@code null})\n\t * @param httpClientOptions client options to use if the Apache HTTP Client is used\n\t */\n\tpublic TestRestTemplate(@Nullable String username, @Nullable String password,\n\t\t\tHttpClientOption... httpClientOptions) {\n\t\tthis(new RestTemplateBuilder(), username, password, httpClientOptions);\n\t}\n\n\t/**\n\t * Create a new {@link TestRestTemplate} instance with the specified credentials.\n\t * @param builder builder used to configure underlying {@link RestTemplate}\n\t * @param username the username to use (or {@code null})\n\t * @param password the password (or {@code null})\n\t * @param httpClientOptions client options to use if the Apache HTTP Client is used\n\t */\n\tpublic TestRestTemplate(RestTemplateBuilder builder, @Nullable String username, @Nullable String password,\n\t\t\tHttpClientOption... httpClientOptions) {\n\t\tthis(createInitialBuilder(builder, username, password, httpClientOptions), null);\n\t}\n\n\tprivate TestRestTemplate(RestTemplateBuilder builder, @Nullable UriTemplateHandler uriTemplateHandler) {\n\t\tthis.builder = builder;\n\t\tthis.restTemplate = builder.build();\n\t\tif (uriTemplateHandler != null) {\n\t\t\tthis.restTemplate.setUriTemplateHandler(uriTemplateHandler);\n\t\t}\n\t\tthis.restTemplate.setErrorHandler(new NoOpResponseErrorHandler());\n\t}\n\n\tprivate static RestTemplateBuilder createInitialBuilder(RestTemplateBuilder builder, @Nullable String username,\n\t\t\t@Nullable String password, HttpClientOption... httpClientOptions) {\n\t\tAssert.notNull(builder, \"'builder' must not be null\");\n\t\tClientHttpRequestFactoryBuilder<?> requestFactoryBuilder = builder.requestFactoryBuilder();\n\t\tif (requestFactoryBuilder instanceof HttpComponentsClientHttpRequestFactoryBuilder) {\n\t\t\tbuilder = builder.requestFactoryBuilder(applyHttpClientOptions(\n\t\t\t\t\t(HttpComponentsClientHttpRequestFactoryBuilder) requestFactoryBuilder, httpClientOptions));\n\t\t}\n\t\tif (username != null && password != null) {\n\t\t\tbuilder = builder.basicAuthentication(username, password);\n\t\t}\n\t\treturn builder;\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static HttpComponentsClientHttpRequestFactoryBuilder applyHttpClientOptions(\n\t\t\tHttpComponentsClientHttpRequestFactoryBuilder builder, HttpClientOption[] httpClientOptions) {\n\t\tif (HttpClientOption.ENABLE_COOKIES.isPresent(httpClientOptions)) {\n\t\t\tbuilder = builder.withDefaultRequestConfigCustomizer(new CookieSpecCustomizer(true));\n\t\t}\n\t\tif (HttpClientOption.SSL.isPresent(httpClientOptions)) {\n\t\t\tbuilder = builder.withTlsSocketStrategyFactory(new SelfSignedTlsSocketStrategyFactory());\n\t\t}\n\t\treturn builder;\n\t}\n\n\t/**\n\t * Configure the {@link UriTemplateHandler} to use to expand URI templates. By default\n\t * the {@link DefaultUriBuilderFactory} is used which relies on Spring's URI template\n\t * support and exposes several useful properties that customize its behavior for\n\t * encoding and for prepending a common base URL. An alternative implementation may be\n\t * used to plug an external URI template library.\n\t * @param handler the URI template handler to use\n\t */\n\tpublic void setUriTemplateHandler(UriTemplateHandler handler) {\n\t\tthis.restTemplate.setUriTemplateHandler(handler);\n\t}\n\n\t/**\n\t * Returns the root URI applied by {@link RestTemplateBuilder#baseUri(String)} or\n\t * {@code \"\"} if the root URI has not been applied.\n\t * @return the root URI\n\t */\n\t@SuppressWarnings(\"removal\")\n\tpublic @Nullable String getRootUri() {\n\t\tUriTemplateHandler uriTemplateHandler = this.restTemplate.getUriTemplateHandler();\n\t\tif (uriTemplateHandler instanceof org.springframework.boot.restclient.RootUriTemplateHandler rootHandler) {\n\t\t\treturn rootHandler.getRootUri();\n\t\t}\n\t\treturn uriTemplateHandler.expand(\"\").toString();\n\t}\n\n\t/**\n\t * Retrieve a representation by doing a GET on the specified URL. The response (if\n\t * any) is converted and returned.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see RestTemplate#getForObject(String, Class, Object...)\n\t */\n\tpublic <T> @Nullable T getForObject(String url, Class<T> responseType, Object... urlVariables) {\n\t\treturn this.restTemplate.getForObject(url, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Retrieve a representation by doing a GET on the URI template. The response (if any)\n\t * is converted and returned.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * @param url the URL\n\t * @param responseType the type of the return value\n\t * @param urlVariables the map containing variables for the URI template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see RestTemplate#getForObject(String, Class, Object...)\n\t */\n\tpublic <T> @Nullable T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.getForObject(url, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Retrieve a representation by doing a GET on the URL . The response (if any) is\n\t * converted and returned.\n\t * @param url the URL\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see RestTemplate#getForObject(java.net.URI, java.lang.Class)\n\t */\n\tpublic <T> @Nullable T getForObject(URI url, Class<T> responseType) {\n\t\treturn this.restTemplate.getForObject(applyRootUriIfNecessary(url), responseType);\n\t}\n\n\t/**\n\t * Retrieve an entity by doing a GET on the specified URL. The response is converted\n\t * and stored in an {@link ResponseEntity}.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the entity\n\t * @see RestTemplate#getForEntity(java.lang.String, java.lang.Class,\n\t * java.lang.Object[])\n\t */\n\tpublic <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... urlVariables) {\n\t\treturn this.restTemplate.getForEntity(url, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Retrieve a representation by doing a GET on the URI template. The response is\n\t * converted and stored in an {@link ResponseEntity}.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * @param url the URL\n\t * @param responseType the type of the return value\n\t * @param urlVariables the map containing variables for the URI template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see RestTemplate#getForEntity(java.lang.String, java.lang.Class, java.util.Map)\n\t */\n\tpublic <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.getForEntity(url, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Retrieve a representation by doing a GET on the URL . The response is converted and\n\t * stored in an {@link ResponseEntity}.\n\t * @param url the URL\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see RestTemplate#getForEntity(java.net.URI, java.lang.Class)\n\t */\n\tpublic <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) {\n\t\treturn this.restTemplate.getForEntity(applyRootUriIfNecessary(url), responseType);\n\t}\n\n\t/**\n\t * Retrieve all headers of the resource specified by the URI template.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param urlVariables the variables to expand the template\n\t * @return all HTTP headers of that resource\n\t * @see RestTemplate#headForHeaders(java.lang.String, java.lang.Object[])\n\t */\n\tpublic HttpHeaders headForHeaders(String url, Object... urlVariables) {\n\t\treturn this.restTemplate.headForHeaders(url, urlVariables);\n\t}\n\n\t/**\n\t * Retrieve all headers of the resource specified by the URI template.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * @param url the URL\n\t * @param urlVariables the map containing variables for the URI template\n\t * @return all HTTP headers of that resource\n\t * @see RestTemplate#headForHeaders(java.lang.String, java.util.Map)\n\t */\n\tpublic HttpHeaders headForHeaders(String url, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.headForHeaders(url, urlVariables);\n\t}\n\n\t/**\n\t * Retrieve all headers of the resource specified by the URL.\n\t * @param url the URL\n\t * @return all HTTP headers of that resource\n\t * @see RestTemplate#headForHeaders(java.net.URI)\n\t */\n\tpublic HttpHeaders headForHeaders(URI url) {\n\t\treturn this.restTemplate.headForHeaders(applyRootUriIfNecessary(url));\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URI template, and returns\n\t * the value of the {@code Location} header. This header typically indicates where the\n\t * new resource is stored.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param urlVariables the variables to expand the template\n\t * @return the value for the {@code Location} header\n\t * @see HttpEntity\n\t * @see RestTemplate#postForLocation(java.lang.String, java.lang.Object,\n\t * java.lang.Object[])\n\t */\n\tpublic @Nullable URI postForLocation(String url, @Nullable Object request, Object... urlVariables) {\n\t\treturn this.restTemplate.postForLocation(url, request, urlVariables);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URI template, and returns\n\t * the value of the {@code Location} header. This header typically indicates where the\n\t * new resource is stored.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param urlVariables the variables to expand the template\n\t * @return the value for the {@code Location} header\n\t * @see HttpEntity\n\t * @see RestTemplate#postForLocation(java.lang.String, java.lang.Object,\n\t * java.util.Map)\n\t */\n\tpublic @Nullable URI postForLocation(String url, @Nullable Object request, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.postForLocation(url, request, urlVariables);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URL, and returns the value\n\t * of the {@code Location} header. This header typically indicates where the new\n\t * resource is stored.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @return the value for the {@code Location} header\n\t * @see HttpEntity\n\t * @see RestTemplate#postForLocation(java.net.URI, java.lang.Object)\n\t */\n\tpublic @Nullable URI postForLocation(URI url, @Nullable Object request) {\n\t\treturn this.restTemplate.postForLocation(applyRootUriIfNecessary(url), request);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URI template, and returns\n\t * the representation found in the response.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t * @see RestTemplate#postForObject(java.lang.String, java.lang.Object,\n\t * java.lang.Class, java.lang.Object[])\n\t */\n\tpublic <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType,\n\t\t\tObject... urlVariables) {\n\t\treturn this.restTemplate.postForObject(url, request, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URI template, and returns\n\t * the representation found in the response.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t * @see RestTemplate#postForObject(java.lang.String, java.lang.Object,\n\t * java.lang.Class, java.util.Map)\n\t */\n\tpublic <T> @Nullable T postForObject(String url, @Nullable Object request, Class<T> responseType,\n\t\t\tMap<String, ?> urlVariables) {\n\t\treturn this.restTemplate.postForObject(url, request, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URL, and returns the\n\t * representation found in the response.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t * @see RestTemplate#postForObject(java.net.URI, java.lang.Object, java.lang.Class)\n\t */\n\tpublic <T> @Nullable T postForObject(URI url, @Nullable Object request, Class<T> responseType) {\n\t\treturn this.restTemplate.postForObject(applyRootUriIfNecessary(url), request, responseType);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URI template, and returns\n\t * the response as {@link ResponseEntity}.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the response type to return\n\t * @param urlVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t * @see RestTemplate#postForEntity(java.lang.String, java.lang.Object,\n\t * java.lang.Class, java.lang.Object[])\n\t */\n\tpublic <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType,\n\t\t\tObject... urlVariables) {\n\t\treturn this.restTemplate.postForEntity(url, request, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URI template, and returns\n\t * the response as {@link HttpEntity}.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the response type to return\n\t * @param urlVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t * @see RestTemplate#postForEntity(java.lang.String, java.lang.Object,\n\t * java.lang.Class, java.util.Map)\n\t */\n\tpublic <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType,\n\t\t\tMap<String, ?> urlVariables) {\n\t\treturn this.restTemplate.postForEntity(url, request, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Create a new resource by POSTing the given object to the URL, and returns the\n\t * response as {@link ResponseEntity}.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the response type to return\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t * @see RestTemplate#postForEntity(java.net.URI, java.lang.Object, java.lang.Class)\n\t */\n\tpublic <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType) {\n\t\treturn this.restTemplate.postForEntity(applyRootUriIfNecessary(url), request, responseType);\n\t}\n\n\t/**\n\t * Create or update a resource by PUTting the given object to the URI.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * <p>\n\t * If you need to assert the request result consider using the\n\t * {@link TestRestTemplate#exchange exchange} method.\n\t * @param url the URL\n\t * @param request the Object to be PUT, may be {@code null}\n\t * @param urlVariables the variables to expand the template\n\t * @see HttpEntity\n\t * @see RestTemplate#put(java.lang.String, java.lang.Object, java.lang.Object[])\n\t */\n\tpublic void put(String url, @Nullable Object request, Object... urlVariables) {\n\t\tthis.restTemplate.put(url, request, urlVariables);\n\t}\n\n\t/**\n\t * Creates a new resource by PUTting the given object to URI template.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * <p>\n\t * If you need to assert the request result consider using the\n\t * {@link TestRestTemplate#exchange exchange} method.\n\t * @param url the URL\n\t * @param request the Object to be PUT, may be {@code null}\n\t * @param urlVariables the variables to expand the template\n\t * @see HttpEntity\n\t * @see RestTemplate#put(java.lang.String, java.lang.Object, java.util.Map)\n\t */\n\tpublic void put(String url, @Nullable Object request, Map<String, ?> urlVariables) {\n\t\tthis.restTemplate.put(url, request, urlVariables);\n\t}\n\n\t/**\n\t * Creates a new resource by PUTting the given object to URL.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * <p>\n\t * If you need to assert the request result consider using the\n\t * {@link TestRestTemplate#exchange exchange} method.\n\t * @param url the URL\n\t * @param request the Object to be PUT, may be {@code null}\n\t * @see HttpEntity\n\t * @see RestTemplate#put(java.net.URI, java.lang.Object)\n\t */\n\tpublic void put(URI url, @Nullable Object request) {\n\t\tthis.restTemplate.put(applyRootUriIfNecessary(url), request);\n\t}\n\n\t/**\n\t * Update a resource by PATCHing the given object to the URI template, and returns the\n\t * representation found in the response.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be PATCHed, may be {@code null}\n\t * @param responseType the type of the return value\n\t * @param uriVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t */\n\tpublic <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType,\n\t\t\tObject... uriVariables) {\n\t\treturn this.restTemplate.patchForObject(url, request, responseType, uriVariables);\n\t}\n\n\t/**\n\t * Update a resource by PATCHing the given object to the URI template, and returns the\n\t * representation found in the response.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be PATCHed, may be {@code null}\n\t * @param responseType the type of the return value\n\t * @param uriVariables the variables to expand the template\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t */\n\tpublic <T> @Nullable T patchForObject(String url, @Nullable Object request, Class<T> responseType,\n\t\t\tMap<String, ?> uriVariables) {\n\t\treturn this.restTemplate.patchForObject(url, request, responseType, uriVariables);\n\t}\n\n\t/**\n\t * Update a resource by PATCHing the given object to the URL, and returns the\n\t * representation found in the response.\n\t * <p>\n\t * The {@code request} parameter can be a {@link HttpEntity} in order to add\n\t * additional HTTP headers to the request.\n\t * @param url the URL\n\t * @param request the Object to be POSTed, may be {@code null}\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the converted object\n\t * @see HttpEntity\n\t */\n\tpublic <T> @Nullable T patchForObject(URI url, @Nullable Object request, Class<T> responseType) {\n\t\treturn this.restTemplate.patchForObject(applyRootUriIfNecessary(url), request, responseType);\n\t}\n\n\t/**\n\t * Delete the resources at the specified URI.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * <p>\n\t * If you need to assert the request result consider using the\n\t * {@link TestRestTemplate#exchange exchange} method.\n\t * @param url the URL\n\t * @param urlVariables the variables to expand in the template\n\t * @see RestTemplate#delete(java.lang.String, java.lang.Object[])\n\t */\n\tpublic void delete(String url, Object... urlVariables) {\n\t\tthis.restTemplate.delete(url, urlVariables);\n\t}\n\n\t/**\n\t * Delete the resources at the specified URI.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * <p>\n\t * If you need to assert the request result consider using the\n\t * {@link TestRestTemplate#exchange exchange} method.\n\t * @param url the URL\n\t * @param urlVariables the variables to expand the template\n\t * @see RestTemplate#delete(java.lang.String, java.util.Map)\n\t */\n\tpublic void delete(String url, Map<String, ?> urlVariables) {\n\t\tthis.restTemplate.delete(url, urlVariables);\n\t}\n\n\t/**\n\t * Delete the resources at the specified URL.\n\t * <p>\n\t * If you need to assert the request result consider using the\n\t * {@link TestRestTemplate#exchange exchange} method.\n\t * @param url the URL\n\t * @see RestTemplate#delete(java.net.URI)\n\t */\n\tpublic void delete(URI url) {\n\t\tthis.restTemplate.delete(applyRootUriIfNecessary(url));\n\t}\n\n\t/**\n\t * Return the value of the {@code Allow} header for the given URI.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param urlVariables the variables to expand in the template\n\t * @return the value of the {@code Allow} header\n\t * @see RestTemplate#optionsForAllow(java.lang.String, java.lang.Object[])\n\t */\n\tpublic Set<HttpMethod> optionsForAllow(String url, Object... urlVariables) {\n\t\treturn this.restTemplate.optionsForAllow(url, urlVariables);\n\t}\n\n\t/**\n\t * Return the value of the {@code Allow} header for the given URI.\n\t * <p>\n\t * URI Template variables are expanded using the given map.\n\t * @param url the URL\n\t * @param urlVariables the variables to expand in the template\n\t * @return the value of the {@code Allow} header\n\t * @see RestTemplate#optionsForAllow(java.lang.String, java.util.Map)\n\t */\n\tpublic Set<HttpMethod> optionsForAllow(String url, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.optionsForAllow(url, urlVariables);\n\t}\n\n\t/**\n\t * Return the value of the {@code Allow} header for the given URL.\n\t * @param url the URL\n\t * @return the value of the {@code Allow} header\n\t * @see RestTemplate#optionsForAllow(java.net.URI)\n\t */\n\tpublic Set<HttpMethod> optionsForAllow(URI url) {\n\t\treturn this.restTemplate.optionsForAllow(applyRootUriIfNecessary(url));\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, writing the given request entity\n\t * to the request, and returns the response as {@link ResponseEntity}.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestEntity the entity (headers and/or body) to write to the request, may\n\t * be {@code null}\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand in the template\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(java.lang.String, org.springframework.http.HttpMethod,\n\t * org.springframework.http.HttpEntity, java.lang.Class, java.lang.Object[])\n\t */\n\tpublic <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,\n\t\t\tClass<T> responseType, Object... urlVariables) {\n\t\treturn this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, writing the given request entity\n\t * to the request, and returns the response as {@link ResponseEntity}.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestEntity the entity (headers and/or body) to write to the request, may\n\t * be {@code null}\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand in the template\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(java.lang.String, org.springframework.http.HttpMethod,\n\t * org.springframework.http.HttpEntity, java.lang.Class, java.util.Map)\n\t */\n\tpublic <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,\n\t\t\tClass<T> responseType, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, writing the given request entity\n\t * to the request, and returns the response as {@link ResponseEntity}.\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestEntity the entity (headers and/or body) to write to the request, may\n\t * be {@code null}\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(java.net.URI, org.springframework.http.HttpMethod,\n\t * org.springframework.http.HttpEntity, java.lang.Class)\n\t */\n\tpublic <T> ResponseEntity<T> exchange(URI url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,\n\t\t\tClass<T> responseType) {\n\t\treturn this.restTemplate.exchange(applyRootUriIfNecessary(url), method, requestEntity, responseType);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, writing the given request entity\n\t * to the request, and returns the response as {@link ResponseEntity}. The given\n\t * {@link ParameterizedTypeReference} is used to pass generic type information:\n\t * <pre class=\"code\">\n\t * ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt; myBean = new ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt;() {};\n\t * ResponseEntity&lt;List&lt;MyBean&gt;&gt; response = template.exchange(&quot;https://example.com&quot;,HttpMethod.GET, null, myBean);\n\t * </pre>\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestEntity the entity (headers and/or body) to write to the request, may\n\t * be {@code null}\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand in the template\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(java.lang.String, org.springframework.http.HttpMethod,\n\t * org.springframework.http.HttpEntity,\n\t * org.springframework.core.ParameterizedTypeReference, java.lang.Object[])\n\t */\n\tpublic <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,\n\t\t\tParameterizedTypeReference<T> responseType, Object... urlVariables) {\n\t\treturn this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, writing the given request entity\n\t * to the request, and returns the response as {@link ResponseEntity}. The given\n\t * {@link ParameterizedTypeReference} is used to pass generic type information:\n\t * <pre class=\"code\">\n\t * ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt; myBean = new ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt;() {};\n\t * ResponseEntity&lt;List&lt;MyBean&gt;&gt; response = template.exchange(&quot;https://example.com&quot;,HttpMethod.GET, null, myBean);\n\t * </pre>\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestEntity the entity (headers and/or body) to write to the request, may\n\t * be {@code null}\n\t * @param responseType the type of the return value\n\t * @param urlVariables the variables to expand in the template\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(java.lang.String, org.springframework.http.HttpMethod,\n\t * org.springframework.http.HttpEntity,\n\t * org.springframework.core.ParameterizedTypeReference, java.util.Map)\n\t */\n\tpublic <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,\n\t\t\tParameterizedTypeReference<T> responseType, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.exchange(url, method, requestEntity, responseType, urlVariables);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, writing the given request entity\n\t * to the request, and returns the response as {@link ResponseEntity}. The given\n\t * {@link ParameterizedTypeReference} is used to pass generic type information:\n\t * <pre class=\"code\">\n\t * ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt; myBean = new ParameterizedTypeReference&lt;List&lt;MyBean&gt;&gt;() {};\n\t * ResponseEntity&lt;List&lt;MyBean&gt;&gt; response = template.exchange(&quot;https://example.com&quot;,HttpMethod.GET, null, myBean);\n\t * </pre>\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestEntity the entity (headers and/or body) to write to the request, may\n\t * be {@code null}\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(java.net.URI, org.springframework.http.HttpMethod,\n\t * org.springframework.http.HttpEntity,\n\t * org.springframework.core.ParameterizedTypeReference)\n\t */\n\tpublic <T> ResponseEntity<T> exchange(URI url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,\n\t\t\tParameterizedTypeReference<T> responseType) {\n\t\treturn this.restTemplate.exchange(applyRootUriIfNecessary(url), method, requestEntity, responseType);\n\t}\n\n\t/**\n\t * Execute the request specified in the given {@link RequestEntity} and return the\n\t * response as {@link ResponseEntity}. Typically used in combination with the static\n\t * builder methods on {@code RequestEntity}, for instance: <pre class=\"code\">\n\t * MyRequest body = ...\n\t * RequestEntity request = RequestEntity.post(new URI(&quot;https://example.com/foo&quot;)).accept(MediaType.APPLICATION_JSON).body(body);\n\t * ResponseEntity&lt;MyResponse&gt; response = template.exchange(request, MyResponse.class);\n\t * </pre>\n\t * @param requestEntity the entity to write to the request\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(org.springframework.http.RequestEntity, java.lang.Class)\n\t */\n\tpublic <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, Class<T> responseType) {\n\t\treturn this.restTemplate.exchange(createRequestEntityWithRootAppliedUri(requestEntity), responseType);\n\t}\n\n\t/**\n\t * Execute the request specified in the given {@link RequestEntity} and return the\n\t * response as {@link ResponseEntity}. The given {@link ParameterizedTypeReference} is\n\t * used to pass generic type information: <pre class=\"code\">\n\t * MyRequest body = ...\n\t * RequestEntity request = RequestEntity.post(new URI(&quot;https://example.com/foo&quot;)).accept(MediaType.APPLICATION_JSON).body(body);\n\t * ParameterizedTypeReference&lt;List&lt;MyResponse&gt;&gt; myBean = new ParameterizedTypeReference&lt;List&lt;MyResponse&gt;&gt;() {};\n\t * ResponseEntity&lt;List&lt;MyResponse&gt;&gt; response = template.exchange(request, myBean);\n\t * </pre>\n\t * @param requestEntity the entity to write to the request\n\t * @param responseType the type of the return value\n\t * @param <T> the type of the return value\n\t * @return the response as entity\n\t * @see RestTemplate#exchange(org.springframework.http.RequestEntity,\n\t * org.springframework.core.ParameterizedTypeReference)\n\t */\n\tpublic <T> ResponseEntity<T> exchange(RequestEntity<?> requestEntity, ParameterizedTypeReference<T> responseType) {\n\t\treturn this.restTemplate.exchange(createRequestEntityWithRootAppliedUri(requestEntity), responseType);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, preparing the request with the\n\t * {@link RequestCallback}, and reading the response with a {@link ResponseExtractor}.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables, if any.\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestCallback object that prepares the request\n\t * @param responseExtractor object that extracts the return value from the response\n\t * @param urlVariables the variables to expand in the template\n\t * @param <T> the type of the return value\n\t * @return an arbitrary object, as returned by the {@link ResponseExtractor}\n\t * @see RestTemplate#execute(java.lang.String, org.springframework.http.HttpMethod,\n\t * org.springframework.web.client.RequestCallback,\n\t * org.springframework.web.client.ResponseExtractor, java.lang.Object[])\n\t */\n\tpublic <T> @Nullable T execute(String url, HttpMethod method, RequestCallback requestCallback,\n\t\t\tResponseExtractor<T> responseExtractor, Object... urlVariables) {\n\t\treturn this.restTemplate.execute(url, method, requestCallback, responseExtractor, urlVariables);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URI template, preparing the request with the\n\t * {@link RequestCallback}, and reading the response with a {@link ResponseExtractor}.\n\t * <p>\n\t * URI Template variables are expanded using the given URI variables map.\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestCallback object that prepares the request\n\t * @param responseExtractor object that extracts the return value from the response\n\t * @param urlVariables the variables to expand in the template\n\t * @param <T> the type of the return value\n\t * @return an arbitrary object, as returned by the {@link ResponseExtractor}\n\t * @see RestTemplate#execute(java.lang.String, org.springframework.http.HttpMethod,\n\t * org.springframework.web.client.RequestCallback,\n\t * org.springframework.web.client.ResponseExtractor, java.util.Map)\n\t */\n\tpublic <T> @Nullable T execute(String url, HttpMethod method, RequestCallback requestCallback,\n\t\t\tResponseExtractor<T> responseExtractor, Map<String, ?> urlVariables) {\n\t\treturn this.restTemplate.execute(url, method, requestCallback, responseExtractor, urlVariables);\n\t}\n\n\t/**\n\t * Execute the HTTP method to the given URL, preparing the request with the\n\t * {@link RequestCallback}, and reading the response with a {@link ResponseExtractor}.\n\t * @param url the URL\n\t * @param method the HTTP method (GET, POST, etc.)\n\t * @param requestCallback object that prepares the request\n\t * @param responseExtractor object that extracts the return value from the response\n\t * @param <T> the type of the return value\n\t * @return an arbitrary object, as returned by the {@link ResponseExtractor}\n\t * @see RestTemplate#execute(java.net.URI, org.springframework.http.HttpMethod,\n\t * org.springframework.web.client.RequestCallback,\n\t * org.springframework.web.client.ResponseExtractor)\n\t */\n\tpublic <T> @Nullable T execute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback,\n\t\t\t@Nullable ResponseExtractor<T> responseExtractor) {\n\t\treturn this.restTemplate.execute(applyRootUriIfNecessary(url), method, requestCallback, responseExtractor);\n\t}\n\n\t/**\n\t * Returns the underlying {@link RestTemplate} that is actually used to perform the\n\t * REST operations.\n\t * @return the restTemplate\n\t */\n\tpublic RestTemplate getRestTemplate() {\n\t\treturn this.restTemplate;\n\t}\n\n\t/**\n\t * Creates a new {@code TestRestTemplate} with the same configuration as this one,\n\t * except that it will send basic authorization headers using the given\n\t * {@code username} and {@code password}. The request factory used is a new instance\n\t * of the underlying {@link RestTemplate}'s request factory type (when possible).\n\t * @param username the username\n\t * @param password the password\n\t * @return the new template\n\t */\n\tpublic TestRestTemplate withBasicAuth(@Nullable String username, @Nullable String password) {\n\t\tif (username == null || password == null) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new TestRestTemplate(this.builder.basicAuthentication(username, password),\n\t\t\t\tthis.restTemplate.getUriTemplateHandler());\n\t}\n\n\t/**\n\t * Creates a new {@code TestRestTemplate} with the same configuration as this one,\n\t * except that it will apply the given {@link HttpRedirects}. The request factory used\n\t * is a new instance of the underlying {@link RestTemplate}'s request factory type\n\t * (when possible).\n\t * @param redirects the new redirect settings\n\t * @return the new template\n\t */\n\tpublic TestRestTemplate withRedirects(HttpRedirects redirects) {\n\t\treturn withClientSettings((settings) -> settings.withRedirects(redirects));\n\t}\n\n\t/**\n\t * Creates a new {@code TestRestTemplate} with the same configuration as this one,\n\t * except that it will apply the given {@link HttpCookieHandling}. The request factory\n\t * used is a new instance of the underlying {@link RestTemplate}'s request factory\n\t * type (when possible).\n\t * @param cookieHandling the new cookie handling\n\t * @return the new template\n\t * @since 4.1.0\n\t */\n\tpublic TestRestTemplate withCookieHandling(HttpCookieHandling cookieHandling) {\n\t\treturn withClientSettings((settings) -> settings.withCookieHandling(cookieHandling));\n\t}\n\n\t/**\n\t * Creates a new {@code TestRestTemplate} with the same configuration as this one,\n\t * except that it will apply the given {@link HttpClientSettings}. The request factory\n\t * used is a new instance of the underlying {@link RestTemplate}'s request factory\n\t * type (when possible).\n\t * @param clientSettings the new client settings\n\t * @return the new template\n\t */\n\tpublic TestRestTemplate withClientSettings(HttpClientSettings clientSettings) {\n\t\treturn new TestRestTemplate(this.builder.clientSettings(clientSettings),\n\t\t\t\tthis.restTemplate.getUriTemplateHandler());\n\t}\n\n\t/**\n\t * Creates a new {@code TestRestTemplate} with the same configuration as this one,\n\t * except that it will customize the {@link HttpClientSettings}. The request factory\n\t * used is a new instance of the underlying {@link RestTemplate}'s request factory\n\t * type (when possible).\n\t * @param clientSettingsCustomizer a {@link UnaryOperator} to update the settings\n\t * @return the new template\n\t */\n\tpublic TestRestTemplate withClientSettings(UnaryOperator<HttpClientSettings> clientSettingsCustomizer) {\n\t\treturn new TestRestTemplate(this.builder.clientSettings(clientSettingsCustomizer),\n\t\t\t\tthis.restTemplate.getUriTemplateHandler());\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate RequestEntity<?> createRequestEntityWithRootAppliedUri(RequestEntity<?> requestEntity) {\n\t\treturn new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), requestEntity.getMethod(),\n\t\t\t\tapplyRootUriIfNecessary(resolveUri(requestEntity)), requestEntity.getType());\n\t}\n\n\tprivate URI applyRootUriIfNecessary(URI uri) {\n\t\tif (!uri.toString().startsWith(\"/\")) {\n\t\t\treturn uri;\n\t\t}\n\t\treturn URI.create(this.restTemplate.getUriTemplateHandler().expand(\"/\") + uri.toString().substring(1));\n\t}\n\n\tprivate URI resolveUri(RequestEntity<?> entity) {\n\t\tif (entity instanceof UriTemplateRequestEntity<?> templatedUriEntity) {\n\t\t\tif (templatedUriEntity.getVars() != null) {\n\t\t\t\treturn this.restTemplate.getUriTemplateHandler()\n\t\t\t\t\t.expand(templatedUriEntity.getUriTemplate(), templatedUriEntity.getVars());\n\t\t\t}\n\t\t\telse if (templatedUriEntity.getVarsMap() != null) {\n\t\t\t\treturn this.restTemplate.getUriTemplateHandler()\n\t\t\t\t\t.expand(templatedUriEntity.getUriTemplate(), templatedUriEntity.getVarsMap());\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"No variables specified for URI template: \" + templatedUriEntity.getUriTemplate());\n\t\t}\n\t\treturn entity.getUrl();\n\t}\n\n\t/**\n\t * Options used to customize the Apache HTTP Client.\n\t */\n\tpublic enum HttpClientOption {\n\n\t\t/**\n\t\t * Enable cookies.\n\t\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t\t * {@link TestRestTemplate#withCookieHandling(HttpCookieHandling)}\n\t\t */\n\t\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\t\tENABLE_COOKIES,\n\n\t\t/**\n\t\t * Use a {@link TlsSocketStrategy} that trusts self-signed certificates.\n\t\t */\n\t\tSSL;\n\n\t\tboolean isPresent(HttpClientOption[] options) {\n\t\t\treturn ObjectUtils.containsElement(options, this);\n\t\t}\n\n\t}\n\n\t/**\n\t * Factory used to create a {@link TlsSocketStrategy} supporting self-signed\n\t * certificates.\n\t */\n\tprivate static final class SelfSignedTlsSocketStrategyFactory implements TlsSocketStrategyFactory {\n\n\t\tprivate static final String[] SUPPORTED_PROTOCOLS = { TLS.V_1_3.getId(), TLS.V_1_2.getId() };\n\n\t\t@Override\n\t\tpublic TlsSocketStrategy getTlsSocketStrategy(@Nullable SslBundle sslBundle) {\n\t\t\ttry {\n\t\t\t\tTrustSelfSignedStrategy trustStrategy = new TrustSelfSignedStrategy();\n\t\t\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build();\n\t\t\t\treturn new DefaultClientTlsStrategy(sslContext, SUPPORTED_PROTOCOLS, null, null, null);\n\t\t\t}\n\t\t\tcatch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link TrustStrategy} supporting self-signed certificates.\n\t */\n\tprivate static final class TrustSelfSignedStrategy implements TrustStrategy {\n\n\t\t@Override\n\t\tpublic boolean isTrusted(X509Certificate[] chain, String authType) {\n\t\t\treturn chain.length == 1;\n\t\t}\n\n\t}\n\n\tprivate static class CookieSpecCustomizer implements Consumer<RequestConfig.Builder> {\n\n\t\tprivate final boolean enableCookies;\n\n\t\tCookieSpecCustomizer(boolean enableCookies) {\n\t\t\tthis.enableCookies = enableCookies;\n\t\t}\n\n\t\t@Override\n\t\tpublic void accept(RequestConfig.Builder builder) {\n\t\t\tbuilder.setCookieSpec(this.enableCookies ? StandardCookieSpec.STRICT : StandardCookieSpec.IGNORE);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/AutoConfigureRestTestClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\n/**\n * Annotation that can be applied to a test class to enable a {@link RestTestClient}.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureRestTestClient {\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/AutoConfigureTestRestTemplate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration of a\n * {@link TestRestTemplate}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureTestRestTemplate {\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.Builder;\n\n/**\n * A customizer that can be implemented by beans wishing to customize the {@link Builder\n * RestTestClient.Builder} to fine-tune its auto-configuration before a\n * {@link RestTestClient} is created.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RestTestClientBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@link Builder RestTestClient.Builder}.\n\t * @param builder the builder\n\t */\n\tvoid customize(RestTestClient.Builder<?> builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Test auto-configuration for {@link RestTestClient}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @see AutoConfigureRestTestClient\n */\n@AutoConfiguration\n@ConditionalOnClass({ RestClient.class, RestTestClient.class, ClientHttpMessageConvertersCustomizer.class })\nfinal class RestTestClientTestAutoConfiguration {\n\n\t@Bean\n\tSpringBootRestTestClientBuilderCustomizer springBootRestTestClientBuilderCustomizer(\n\t\t\tObjectProvider<ClientHttpMessageConvertersCustomizer> httpMessageConverterCustomizers) {\n\t\treturn new SpringBootRestTestClientBuilderCustomizer(httpMessageConverterCustomizers.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tRestTestClient restTestClient(WebApplicationContext applicationContext,\n\t\t\tList<RestTestClientBuilderCustomizer> customizers) {\n\t\tRestTestClient.Builder<?> builder = getBuilder(applicationContext);\n\t\tcustomizers.forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate RestTestClient.Builder<?> getBuilder(WebApplicationContext applicationContext) {\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.get(applicationContext);\n\t\tif (localTestWebServer != null) {\n\t\t\treturn RestTestClient.bindToServer().uriBuilderFactory(localTestWebServer.uriBuilderFactory());\n\t\t}\n\t\tif (hasBean(applicationContext, MockMvc.class)) {\n\t\t\treturn RestTestClient.bindTo(applicationContext.getBean(MockMvc.class));\n\t\t}\n\t\treturn RestTestClient.bindToApplicationContext(applicationContext);\n\t}\n\n\tprivate boolean hasBean(ApplicationContext applicationContext, Class<?> type) {\n\t\ttry {\n\t\t\tapplicationContext.getBean(type);\n\t\t\treturn true;\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/SpringBootRestTestClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\n/**\n * {@link RestTestClientBuilderCustomizer} for a typical Spring Boot application. Usually\n * applied automatically via\n * {@link AutoConfigureRestTestClient @AutoConfigureRestTestClient}, but may also be used\n * directly.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class SpringBootRestTestClientBuilderCustomizer implements RestTestClientBuilderCustomizer {\n\n\tprivate final Collection<ClientHttpMessageConvertersCustomizer> messageConverterCustomizers;\n\n\t/**\n\t * Create a new {@code SpringBootRestTestClientBuilderCustomizer} that will configure\n\t * the builder's message converters using the given\n\t * {@code messageConverterCustomizers}.\n\t * @param messageConverterCustomizers the message converter customizers\n\t */\n\tpublic SpringBootRestTestClientBuilderCustomizer(\n\t\t\tCollection<ClientHttpMessageConvertersCustomizer> messageConverterCustomizers) {\n\t\tthis.messageConverterCustomizers = messageConverterCustomizers;\n\n\t}\n\n\t@Override\n\tpublic void customize(RestTestClient.Builder<?> builder) {\n\t\tif (this.messageConverterCustomizers.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tbuilder.configureMessageConverters((configurer) -> this.messageConverterCustomizers\n\t\t\t.forEach((customizer) -> customizer.customize(configurer)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/TestRestTemplateTestAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.TestRestTemplate.HttpClientOption;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Test auto-configuration for {@link TestRestTemplate}.\n *\n * @author Andy Wilkinson\n * @see AutoConfigureTestRestTemplate\n */\n@AutoConfiguration\nfinal class TestRestTemplateTestAutoConfiguration {\n\n\t@Bean(name = \"org.springframework.boot.resttestclient.TestRestTemplate\")\n\t@ConditionalOnMissingBean\n\tTestRestTemplate testRestTemplate(ObjectProvider<RestTemplateBuilder> builderProvider,\n\t\t\tApplicationContext applicationContext) {\n\t\tRestTemplateBuilder builder = builderProvider.getIfAvailable(RestTemplateBuilder::new);\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.obtain(applicationContext);\n\t\tTestRestTemplate template = new TestRestTemplate(builder, null, null,\n\t\t\t\thttpClientOptions(localTestWebServer.scheme()));\n\t\ttemplate.setUriTemplateHandler(localTestWebServer.uriBuilderFactory());\n\t\treturn template;\n\t}\n\n\tprivate HttpClientOption[] httpClientOptions(Scheme scheme) {\n\t\treturn switch (scheme) {\n\t\t\tcase HTTP -> new HttpClientOption[] {};\n\t\t\tcase HTTPS -> new HttpClientOption[] { HttpClientOption.SSL };\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RestTestClient and TestRestTemplate.\n */\n@NullMarked\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Test support classes that use {@link org.springframework.web.client.RestClient} and\n * {@link org.springframework.web.client.RestTemplate}.\n */\n@NullMarked\npackage org.springframework.boot.resttestclient;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/kotlin/org/springframework/boot/resttestclient/TestRestTemplateExtensions.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient\n\nimport org.springframework.core.ParameterizedTypeReference\nimport org.springframework.http.HttpEntity\nimport org.springframework.http.HttpMethod\nimport org.springframework.http.RequestEntity\nimport org.springframework.http.ResponseEntity\nimport org.springframework.web.client.RestClientException\nimport java.net.URI\n\n/**\n * Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.getForObject(url: String, vararg uriVariables: Any): T? =\n\t\tgetForObject(url, T::class.java, *uriVariables)\n\n/**\n * Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.getForObject(url: String, uriVariables: Map<String, Any?>): T? =\n\t\tgetForObject(url, T::class.java, uriVariables)\n\n/**\n * Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.getForObject(url: URI): T? =\n\t\tgetForObject(url, T::class.java)\n\n/**\n * Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.getForEntity(url: URI): ResponseEntity<T> =\n\t\tgetForEntity(url, T::class.java)\n\n/**\n * Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.getForEntity(url: String, vararg uriVariables: Any): ResponseEntity<T> =\n\t\tgetForEntity(url, T::class.java, *uriVariables)\n\n/**\n * Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.getForEntity(url: String,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   uriVariables: Map<String, *>): ResponseEntity<T> =\n\t\tgetForEntity(url, T::class.java, uriVariables)\n\n/**\n * Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any? = null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t vararg uriVariables: Any): T? =\n\t\tpatchForObject(url, request, T::class.java, *uriVariables)\n\n/**\n * Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any? = null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t uriVariables: Map<String, *>): T? =\n\t\tpatchForObject(url, request, T::class.java, uriVariables)\n\n/**\n * Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.patchForObject(url: URI, request: Any? = null): T? =\n\t\tpatchForObject(url, request, T::class.java)\n\n/**\n * Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any? = null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvararg uriVariables: Any): T? =\n\t\tpostForObject(url, request, T::class.java, *uriVariables)\n\n/**\n * Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any? = null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\turiVariables: Map<String, *>): T? =\n\t\tpostForObject(url, request, T::class.java, uriVariables)\n\n/**\n * Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.postForObject(url: URI, request: Any? = null): T? =\n\t\tpostForObject(url, request, T::class.java)\n\n/**\n * Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any? = null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tvararg uriVariables: Any): ResponseEntity<T> =\n\t\tpostForEntity(url, request, T::class.java, *uriVariables)\n\n/**\n * Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any? = null,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\turiVariables: Map<String, *>): ResponseEntity<T> =\n\t\tpostForEntity(url, request, T::class.java, uriVariables)\n\n/**\n * Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. Like the original Java method, this\n * extension is subject to type erasure. Use [exchange] if you need to retain actual\n * generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.postForEntity(url: URI, request: Any? = null): ResponseEntity<T> =\n\t\tpostForEntity(url, request, T::class.java)\n\n/**\n * Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. This extension is not subject to\n * type erasure and retains actual generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod,\n\t\trequestEntity: HttpEntity<*>? = null, vararg uriVariables: Any): ResponseEntity<T> =\n\t\texchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, *uriVariables)\n\n/**\n * Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. This extension is not subject to\n * type erasure and retains actual generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod,\n\t\trequestEntity: HttpEntity<*>? = null, uriVariables: Map<String, *>): ResponseEntity<T> =\n\t\texchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, uriVariables)\n\n/**\n * Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. This extension is not subject to\n * type erasure and retains actual generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.exchange(url: URI, method: HttpMethod,\n\t\trequestEntity: HttpEntity<*>? = null): ResponseEntity<T> =\n\t\texchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {})\n\n/**\n * Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`\n * variant leveraging Kotlin reified type parameters. This extension is not subject to\n * type erasure and retains actual generic type arguments.\n *\n * @author Sebastien Deleuze\n * @since 4.0.0\n */\n@Throws(RestClientException::class)\ninline fun <reified T : Any> TestRestTemplate.exchange(requestEntity: RequestEntity<*>): ResponseEntity<T> =\n\t\texchange(requestEntity, object : ParameterizedTypeReference<T>() {})\n\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": ""
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/resources/META-INF/spring/org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient.imports",
    "content": "org.springframework.boot.resttestclient.autoconfigure.RestTestClientTestAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/main/resources/META-INF/spring/org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate.imports",
    "content": "org.springframework.boot.resttestclient.autoconfigure.TestRestTemplateTestAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/TestRestTemplateTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpClient.Redirect;\nimport java.util.Base64;\nimport java.util.stream.Stream;\n\nimport org.apache.hc.client5.http.config.RequestConfig;\nimport org.apache.hc.client5.http.cookie.StandardCookieSpec;\nimport org.apache.hc.client5.http.impl.DefaultRedirectStrategy;\nimport org.apache.hc.client5.http.impl.classic.RedirectExec;\nimport org.apache.hc.client5.http.protocol.RedirectStrategy;\nimport org.assertj.core.extractor.Extractors;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpCookieHandling;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate.HttpClientOption;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.mock.http.client.MockClientHttpRequest;\nimport org.springframework.mock.http.client.MockClientHttpResponse;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.ReflectionUtils.MethodCallback;\nimport org.springframework.web.client.NoOpResponseErrorHandler;\nimport org.springframework.web.client.ResponseErrorHandler;\nimport org.springframework.web.client.RestOperations;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TestRestTemplate}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Kristine Jetzke\n * @author Yanming Zhou\n */\nclass TestRestTemplateTests {\n\n\t@Test\n\tvoid fromRestTemplateBuilder() {\n\t\tRestTemplateBuilder builder = mock(RestTemplateBuilder.class);\n\t\tRestTemplate delegate = new RestTemplate();\n\t\tgiven(builder.build()).willReturn(delegate);\n\t\tassertThat(new TestRestTemplate(builder).getRestTemplate()).isEqualTo(delegate);\n\t}\n\n\t@Test\n\tvoid simple() {\n\t\t// The Apache client is on the classpath so we get the fully-fledged factory\n\t\tassertThat(new TestRestTemplate().getRestTemplate().getRequestFactory())\n\t\t\t.isInstanceOf(HttpComponentsClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid doNotReplaceCustomRequestFactory() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder().requestFactory(TestClientHttpRequestFactory.class);\n\t\tTestRestTemplate testRestTemplate = new TestRestTemplate(builder);\n\t\tassertThat(testRestTemplate.getRestTemplate().getRequestFactory())\n\t\t\t.isInstanceOf(TestClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid useTheSameRequestFactoryClassWithBasicAuth() {\n\t\tTestClientHttpRequestFactory customFactory = new TestClientHttpRequestFactory();\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder().requestFactory(() -> customFactory);\n\t\tTestRestTemplate testRestTemplate = new TestRestTemplate(builder).withBasicAuth(\"test\", \"test\");\n\t\tRestTemplate restTemplate = testRestTemplate.getRestTemplate();\n\t\tassertThat(restTemplate.getRequestFactory()).isEqualTo(customFactory).hasSameClassAs(customFactory);\n\t}\n\n\t@Test\n\tvoid getBaseUriRootUriSetViaRestTemplateBuilder() {\n\t\tString baseUri = \"https://example.com\";\n\t\tRestTemplateBuilder delegate = new RestTemplateBuilder().baseUri(baseUri);\n\t\tassertThat(new TestRestTemplate(delegate).getRootUri()).isEqualTo(baseUri);\n\t}\n\n\t@Test\n\tvoid getRootUriRootUriSetViaLocalTestWebServer() {\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.of(Scheme.HTTPS, 7070);\n\t\tRestTemplateBuilder delegate = new RestTemplateBuilder()\n\t\t\t.uriTemplateHandler(localTestWebServer.uriBuilderFactory());\n\t\tassertThat(new TestRestTemplate(delegate).getRootUri()).isEqualTo(\"https://localhost:7070\");\n\t}\n\n\t@Test\n\tvoid getRootUriRootUriNotSet() {\n\t\tassertThat(new TestRestTemplate().getRootUri()).isEmpty();\n\t}\n\n\t@Test\n\tvoid authenticated() {\n\t\tTestRestTemplate restTemplate = new TestRestTemplate(\"user\", \"password\");\n\t\tassertBasicAuthorizationCredentials(restTemplate, \"user\", \"password\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid options() {\n\t\tRequestConfig config = getRequestConfig(new TestRestTemplate(HttpClientOption.ENABLE_COOKIES));\n\t\tassertThat(config.getCookieSpec()).isEqualTo(\"strict\");\n\t}\n\n\t@Test\n\tvoid defaultCookieSpecMatchesRestTemplate() {\n\t\tRequestConfig config = getRequestConfig(new TestRestTemplate());\n\t\tassertThat(config.getCookieSpec()).isNull();\n\t}\n\n\t@Test\n\tvoid withCookieHandling() {\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\tassertThat(getRequestConfig(template).getCookieSpec()).isNull();\n\t\tassertThat(getRequestConfig(template.withCookieHandling(HttpCookieHandling.ENABLE)).getCookieSpec())\n\t\t\t.isEqualTo(StandardCookieSpec.STRICT);\n\t\tassertThat(\n\t\t\t\tgetRequestConfig(template.withCookieHandling(HttpCookieHandling.ENABLE_WHEN_POSSIBLE)).getCookieSpec())\n\t\t\t.isEqualTo(StandardCookieSpec.STRICT);\n\t\tassertThat(getRequestConfig(template.withCookieHandling(HttpCookieHandling.DISABLE)).getCookieSpec())\n\t\t\t.isEqualTo(StandardCookieSpec.IGNORE);\n\t}\n\n\t@Test\n\tvoid jdkBuilderCanBeSpecifiedWithSpecificRedirects() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder()\n\t\t\t.requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk());\n\t\tTestRestTemplate templateWithRedirects = new TestRestTemplate(builder.redirects(HttpRedirects.FOLLOW));\n\t\tassertThat(getJdkHttpClient(templateWithRedirects).followRedirects()).isEqualTo(Redirect.NORMAL);\n\t\tTestRestTemplate templateWithoutRedirects = new TestRestTemplate(builder.redirects(HttpRedirects.DONT_FOLLOW));\n\t\tassertThat(getJdkHttpClient(templateWithoutRedirects).followRedirects()).isEqualTo(Redirect.NEVER);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\tvoid httpComponentsAreBuiltConsideringSettingsInRestTemplateBuilder() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder()\n\t\t\t.requestFactoryBuilder(ClientHttpRequestFactoryBuilder.httpComponents());\n\t\tassertThat(getRedirectStrategy((RestTemplateBuilder) null)).matches(this::isFollowStrategy);\n\t\tassertThat(getRedirectStrategy(builder)).matches(this::isFollowStrategy);\n\t\tassertThat(getRedirectStrategy(builder.redirects(HttpRedirects.DONT_FOLLOW)))\n\t\t\t.matches(this::isDontFollowStrategy);\n\t}\n\n\t@Test\n\tvoid withClientSettingsRedirectsForHttpComponents() {\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\tassertThat(getRedirectStrategy(template)).matches(this::isFollowStrategy);\n\t\tassertThat(getRedirectStrategy(\n\t\t\t\ttemplate.withClientSettings(HttpClientSettings.defaults().withRedirects(HttpRedirects.FOLLOW))))\n\t\t\t.matches(this::isFollowStrategy);\n\t\tassertThat(getRedirectStrategy(\n\t\t\t\ttemplate.withClientSettings(HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW))))\n\t\t\t.matches(this::isDontFollowStrategy);\n\t}\n\n\t@Test\n\tvoid withRedirects() {\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\tassertThat(getRedirectStrategy(template)).matches(this::isFollowStrategy);\n\t\tassertThat(getRedirectStrategy(template.withRedirects(HttpRedirects.FOLLOW))).matches(this::isFollowStrategy);\n\t\tassertThat(getRedirectStrategy(template.withRedirects(HttpRedirects.DONT_FOLLOW)))\n\t\t\t.matches(this::isDontFollowStrategy);\n\t}\n\n\t@Test\n\tvoid withClientSettingsRedirectsForJdk() {\n\t\tTestRestTemplate template = new TestRestTemplate(\n\t\t\t\tnew RestTemplateBuilder().requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk()));\n\t\tassertThat(getJdkHttpClient(template).followRedirects()).isEqualTo(Redirect.NORMAL);\n\t\tassertThat(getJdkHttpClient(\n\t\t\t\ttemplate.withClientSettings(HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW)))\n\t\t\t.followRedirects()).isEqualTo(Redirect.NEVER);\n\t}\n\n\t@Test\n\tvoid withClientSettingsUpdateRedirectsForJdk() {\n\t\tTestRestTemplate template = new TestRestTemplate(\n\t\t\t\tnew RestTemplateBuilder().requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk()));\n\t\tassertThat(getJdkHttpClient(template).followRedirects()).isEqualTo(Redirect.NORMAL);\n\t\tassertThat(getJdkHttpClient(\n\t\t\t\ttemplate.withClientSettings((settings) -> settings.withRedirects(HttpRedirects.DONT_FOLLOW)))\n\t\t\t.followRedirects()).isEqualTo(Redirect.NEVER);\n\t}\n\n\tprivate RequestConfig getRequestConfig(TestRestTemplate template) {\n\t\tClientHttpRequestFactory requestFactory = template.getRestTemplate().getRequestFactory();\n\t\treturn (RequestConfig) Extractors.byName(\"httpClient.defaultConfig\").apply(requestFactory);\n\t}\n\n\tprivate @Nullable RedirectStrategy getRedirectStrategy(@Nullable RestTemplateBuilder builder,\n\t\t\tHttpClientOption... httpClientOptions) {\n\t\tbuilder = (builder != null) ? builder : new RestTemplateBuilder();\n\t\tTestRestTemplate template = new TestRestTemplate(builder, null, null, httpClientOptions);\n\t\treturn getRedirectStrategy(template);\n\t}\n\n\tprivate @Nullable RedirectStrategy getRedirectStrategy(TestRestTemplate template) {\n\t\tClientHttpRequestFactory requestFactory = template.getRestTemplate().getRequestFactory();\n\t\tObject chain = Extractors.byName(\"httpClient.execChain\").apply(requestFactory);\n\t\twhile (chain != null) {\n\t\t\tObject handler = Extractors.byName(\"handler\").apply(chain);\n\t\t\tif (handler instanceof RedirectExec) {\n\t\t\t\treturn (RedirectStrategy) Extractors.byName(\"redirectStrategy\").apply(handler);\n\t\t\t}\n\t\t\tchain = Extractors.byName(\"next\").apply(chain);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isFollowStrategy(RedirectStrategy redirectStrategy) {\n\t\treturn redirectStrategy instanceof DefaultRedirectStrategy;\n\t}\n\n\tprivate boolean isDontFollowStrategy(RedirectStrategy redirectStrategy) {\n\t\treturn redirectStrategy.getClass().getName().contains(\"NoFollow\");\n\t}\n\n\tprivate HttpClient getJdkHttpClient(TestRestTemplate template) {\n\t\tJdkClientHttpRequestFactory requestFactory = (JdkClientHttpRequestFactory) template.getRestTemplate()\n\t\t\t.getRequestFactory();\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(requestFactory, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\treturn httpClient;\n\t}\n\n\t@Test\n\tvoid restOperationsAreAvailable() {\n\t\tRestTemplate delegate = mock(RestTemplate.class);\n\t\tgiven(delegate.getRequestFactory()).willReturn(new SimpleClientHttpRequestFactory());\n\t\tgiven(delegate.getUriTemplateHandler()).willReturn(new DefaultUriBuilderFactory());\n\t\tRestTemplateBuilder builder = mock(RestTemplateBuilder.class);\n\t\tgiven(builder.build()).willReturn(delegate);\n\t\tTestRestTemplate restTemplate = new TestRestTemplate(builder);\n\t\tReflectionUtils.doWithMethods(RestOperations.class, new MethodCallback() {\n\n\t\t\t@Override\n\t\t\tpublic void doWith(Method method) {\n\t\t\t\tMethod equivalent = ReflectionUtils.findMethod(TestRestTemplate.class, method.getName(),\n\t\t\t\t\t\tmethod.getParameterTypes());\n\t\t\t\tassertThat(equivalent).as(\"Method %s not found\", method).isNotNull();\n\t\t\t\tassertThat(Modifier.isPublic(equivalent.getModifiers()))\n\t\t\t\t\t.as(\"Method %s should have been public\", equivalent)\n\t\t\t\t\t.isTrue();\n\t\t\t\ttry {\n\t\t\t\t\tequivalent.invoke(restTemplate, mockArguments(method.getParameterTypes()));\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprivate Object[] mockArguments(Class<?>[] parameterTypes) throws Exception {\n\t\t\t\tObject[] arguments = new Object[parameterTypes.length];\n\t\t\t\tfor (int i = 0; i < parameterTypes.length; i++) {\n\t\t\t\t\targuments[i] = mockArgument(parameterTypes[i]);\n\t\t\t\t}\n\t\t\t\treturn arguments;\n\t\t\t}\n\n\t\t\t@SuppressWarnings(\"rawtypes\")\n\t\t\tprivate Object mockArgument(Class<?> type) throws Exception {\n\t\t\t\tif (String.class.equals(type)) {\n\t\t\t\t\treturn \"String\";\n\t\t\t\t}\n\t\t\t\tif (Object[].class.equals(type)) {\n\t\t\t\t\treturn new Object[0];\n\t\t\t\t}\n\t\t\t\tif (URI.class.equals(type)) {\n\t\t\t\t\treturn new URI(\"http://localhost\");\n\t\t\t\t}\n\t\t\t\tif (HttpMethod.class.equals(type)) {\n\t\t\t\t\treturn HttpMethod.GET;\n\t\t\t\t}\n\t\t\t\tif (Class.class.equals(type)) {\n\t\t\t\t\treturn Object.class;\n\t\t\t\t}\n\t\t\t\tif (RequestEntity.class.equals(type)) {\n\t\t\t\t\treturn new RequestEntity(HttpMethod.GET, new URI(\"http://localhost\"));\n\t\t\t\t}\n\t\t\t\treturn mock(type);\n\t\t\t}\n\n\t\t}, (method) -> Modifier.isPublic(method.getModifiers()));\n\n\t}\n\n\t@Test\n\tvoid withBasicAuthAddsBasicAuthWhenNotAlreadyPresent() {\n\t\tTestRestTemplate original = new TestRestTemplate();\n\t\tTestRestTemplate basicAuth = original.withBasicAuth(\"user\", \"password\");\n\t\tassertThat(getConverterClasses(original)).containsExactlyElementsOf(getConverterClasses(basicAuth).toList());\n\t\tassertThat(basicAuth.getRestTemplate().getInterceptors()).isEmpty();\n\t\tassertBasicAuthorizationCredentials(original, null, null);\n\t\tassertBasicAuthorizationCredentials(basicAuth, \"user\", \"password\");\n\t}\n\n\t@Test\n\tvoid withBasicAuthReplacesBasicAuthWhenAlreadyPresent() {\n\t\tTestRestTemplate original = new TestRestTemplate(\"foo\", \"bar\").withBasicAuth(\"replace\", \"replace\");\n\t\tTestRestTemplate basicAuth = original.withBasicAuth(\"user\", \"password\");\n\t\tassertThat(getConverterClasses(basicAuth)).containsExactlyElementsOf(getConverterClasses(original).toList());\n\t\tassertBasicAuthorizationCredentials(original, \"replace\", \"replace\");\n\t\tassertBasicAuthorizationCredentials(basicAuth, \"user\", \"password\");\n\t}\n\n\tprivate Stream<Class<?>> getConverterClasses(TestRestTemplate testRestTemplate) {\n\t\treturn testRestTemplate.getRestTemplate().getMessageConverters().stream().map(Object::getClass);\n\t}\n\n\t@Test\n\tvoid withBasicAuthShouldUseNoOpErrorHandler() {\n\t\tTestRestTemplate originalTemplate = new TestRestTemplate(\"foo\", \"bar\");\n\t\tResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class);\n\t\toriginalTemplate.getRestTemplate().setErrorHandler(errorHandler);\n\t\tTestRestTemplate basicAuthTemplate = originalTemplate.withBasicAuth(\"user\", \"password\");\n\t\tassertThat(basicAuthTemplate.getRestTemplate().getErrorHandler()).isInstanceOf(NoOpResponseErrorHandler.class);\n\t}\n\n\t@Test\n\tvoid exchangeWithRelativeTemplatedUrlRequestEntity() throws Exception {\n\t\tRequestEntity<Void> entity = RequestEntity.get(\"/a/b/c.{ext}\", \"txt\").build();\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\tClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);\n\t\tMockClientHttpRequest request = new MockClientHttpRequest();\n\t\trequest.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));\n\t\tURI absoluteUri = URI.create(\"http://localhost:8080/a/b/c.txt\");\n\t\tgiven(requestFactory.createRequest(eq(absoluteUri), eq(HttpMethod.GET))).willReturn(request);\n\t\ttemplate.getRestTemplate().setRequestFactory(requestFactory);\n\t\ttemplate.setUriTemplateHandler(LocalTestWebServer.of(Scheme.HTTP, 8080).uriBuilderFactory());\n\t\ttemplate.exchange(entity, String.class);\n\t\tthen(requestFactory).should().createRequest(eq(absoluteUri), eq(HttpMethod.GET));\n\t}\n\n\t@Test\n\tvoid exchangeWithAbsoluteTemplatedUrlRequestEntity() throws Exception {\n\t\tRequestEntity<Void> entity = RequestEntity.get(\"https://api.example.com/a/b/c.{ext}\", \"txt\").build();\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\tClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);\n\t\tMockClientHttpRequest request = new MockClientHttpRequest();\n\t\trequest.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));\n\t\tURI absoluteUri = URI.create(\"https://api.example.com/a/b/c.txt\");\n\t\tgiven(requestFactory.createRequest(eq(absoluteUri), eq(HttpMethod.GET))).willReturn(request);\n\t\ttemplate.getRestTemplate().setRequestFactory(requestFactory);\n\t\ttemplate.exchange(entity, String.class);\n\t\tthen(requestFactory).should().createRequest(eq(absoluteUri), eq(HttpMethod.GET));\n\t}\n\n\t@Test\n\tvoid deleteHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(TestRestTemplate::delete);\n\t}\n\n\t@Test\n\tvoid exchangeWithRequestEntityAndClassHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate\n\t\t\t.exchange(new RequestEntity<>(HttpMethod.GET, relativeUri), String.class));\n\t}\n\n\t@Test\n\tvoid exchangeWithRequestEntityAndParameterizedTypeReferenceHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate\n\t\t\t.exchange(new RequestEntity<>(HttpMethod.GET, relativeUri), new ParameterizedTypeReference<String>() {\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid exchangeHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate.exchange(relativeUri,\n\t\t\t\tHttpMethod.GET, new HttpEntity<>(new byte[0]), String.class));\n\t}\n\n\t@Test\n\tvoid exchangeWithParameterizedTypeReferenceHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate.exchange(relativeUri,\n\t\t\t\tHttpMethod.GET, new HttpEntity<>(new byte[0]), new ParameterizedTypeReference<String>() {\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid executeHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.execute(relativeUri, HttpMethod.GET, null, null));\n\t}\n\n\t@Test\n\tvoid getForEntityHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.getForEntity(relativeUri, String.class));\n\t}\n\n\t@Test\n\tvoid getForObjectHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.getForObject(relativeUri, String.class));\n\t}\n\n\t@Test\n\tvoid headForHeadersHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(TestRestTemplate::headForHeaders);\n\t}\n\n\t@Test\n\tvoid optionsForAllowHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(TestRestTemplate::optionsForAllow);\n\t}\n\n\t@Test\n\tvoid patchForObjectHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.patchForObject(relativeUri, \"hello\", String.class));\n\t}\n\n\t@Test\n\tvoid postForEntityHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.postForEntity(relativeUri, \"hello\", String.class));\n\t}\n\n\t@Test\n\tvoid postForLocationHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.postForLocation(relativeUri, \"hello\"));\n\t}\n\n\t@Test\n\tvoid postForObjectHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling(\n\t\t\t\t(testRestTemplate, relativeUri) -> testRestTemplate.postForObject(relativeUri, \"hello\", String.class));\n\t}\n\n\t@Test\n\tvoid putHandlesRelativeUris() throws IOException {\n\t\tverifyRelativeUriHandling((testRestTemplate, relativeUri) -> testRestTemplate.put(relativeUri, \"hello\"));\n\t}\n\n\tprivate void verifyRelativeUriHandling(TestRestTemplateCallback callback) throws IOException {\n\t\tClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);\n\t\tMockClientHttpRequest request = new MockClientHttpRequest();\n\t\trequest.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK));\n\t\tURI absoluteUri = URI.create(\"http://localhost:8080/a/b/c.txt?param=%7Bsomething%7D\");\n\t\tgiven(requestFactory.createRequest(eq(absoluteUri), any(HttpMethod.class))).willReturn(request);\n\t\tTestRestTemplate template = new TestRestTemplate();\n\t\ttemplate.getRestTemplate().setRequestFactory(requestFactory);\n\t\ttemplate.setUriTemplateHandler(LocalTestWebServer.of(Scheme.HTTP, 8080).uriBuilderFactory());\n\t\tcallback.doWithTestRestTemplate(template, URI.create(\"/a/b/c.txt?param=%7Bsomething%7D\"));\n\t\tthen(requestFactory).should().createRequest(eq(absoluteUri), any(HttpMethod.class));\n\t}\n\n\tprivate void assertBasicAuthorizationCredentials(TestRestTemplate testRestTemplate, @Nullable String username,\n\t\t\t@Nullable String password) {\n\t\tClientHttpRequest request = ReflectionTestUtils.invokeMethod(testRestTemplate.getRestTemplate(),\n\t\t\t\t\"createRequest\", URI.create(\"http://localhost\"), HttpMethod.POST);\n\t\tassertThat(request).isNotNull();\n\t\tif (username == null) {\n\t\t\tassertThat(request.getHeaders().headerNames()).doesNotContain(HttpHeaders.AUTHORIZATION);\n\t\t}\n\t\telse {\n\t\t\tassertThat(request.getHeaders().headerNames()).contains(HttpHeaders.AUTHORIZATION);\n\t\t\tassertThat(request.getHeaders().get(HttpHeaders.AUTHORIZATION)).containsExactly(\"Basic \"\n\t\t\t\t\t+ Base64.getEncoder().encodeToString(String.format(\"%s:%s\", username, password).getBytes()));\n\t\t}\n\n\t}\n\n\tinterface TestRestTemplateCallback {\n\n\t\tvoid doWithTestRestTemplate(TestRestTemplate testRestTemplate, URI relativeUri);\n\n\t}\n\n\tstatic class TestClientHttpRequestFactory extends SimpleClientHttpRequestFactory {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientTestAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport org.assertj.core.extractor.Extractors;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.converter.HttpMessageConverters.ClientBuilder;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.util.UriBuilderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RestTestClientTestAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass RestTestClientTestAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RestTestClientTestAutoConfiguration.class));\n\n\t@Test\n\tvoid registersRestTestClient() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(RestTestClient.class));\n\t}\n\n\t@Test\n\tvoid shouldNotRegisterRestTestClientIfRestClientIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(RestClient.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RestTestClient.class));\n\t}\n\n\t@Test\n\tvoid shouldApplyRestTestClientCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(RestTestClientCustomConfig.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RestTestClient.class);\n\t\t\tassertThat(context).hasBean(\"myRestTestClientCustomizer\");\n\t\t\tthen(context.getBean(\"myRestTestClientCustomizer\", RestTestClientBuilderCustomizer.class)).should()\n\t\t\t\t.customize(any(RestTestClient.Builder.class));\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\t\t\torg.springframework.boot.resttestclient.autoconfigure.RestTestClientTestAutoConfigurationTests$TestLocalTestWebServerProvider\n\t\t\t\t\t\"\"\")\n\tvoid shouldDefineRestTestClientBoundToWebServer() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RestTestClient.class).hasBean(\"restTestClient\");\n\t\t\tRestTestClient client = context.getBean(RestTestClient.class);\n\t\t\tUriBuilderFactory uiBuilderFactory = (UriBuilderFactory) Extractors\n\t\t\t\t.byName(\"restTestClientBuilder.restClientBuilder.uriBuilderFactory\")\n\t\t\t\t.apply(client);\n\t\t\tassertThat(uiBuilderFactory.uriString(\"\").toUriString()).isEqualTo(\"https://localhost:8182\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid clientHttpMessageConverterCustomizersAreAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(ClientHttpMessageConverterCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer1 = context.getBean(\"customizer1\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer2 = context.getBean(\"customizer2\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tClientHttpMessageConvertersCustomizer customizer3 = context.getBean(\"customizer3\",\n\t\t\t\t\t\tClientHttpMessageConvertersCustomizer.class);\n\t\t\t\tInOrder inOrder = inOrder(customizer1, customizer2, customizer3);\n\t\t\t\tinOrder.verify(customizer3).customize(any(ClientBuilder.class));\n\t\t\t\tinOrder.verify(customizer1).customize(any(ClientBuilder.class));\n\t\t\t\tinOrder.verify(customizer2).customize(any(ClientBuilder.class));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RestTestClientCustomConfig {\n\n\t\t@Bean\n\t\tRestTestClientBuilderCustomizer myRestTestClientCustomizer() {\n\t\t\treturn mock(RestTestClientBuilderCustomizer.class);\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\treturn LocalTestWebServer.of(Scheme.HTTPS, 8182);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientHttpMessageConverterCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(-5)\n\t\tClientHttpMessageConvertersCustomizer customizer1() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tClientHttpMessageConvertersCustomizer customizer2() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(-10)\n\t\tClientHttpMessageConvertersCustomizer customizer3() {\n\t\t\treturn mock(ClientHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/autoconfigure/TestRestTemplateTestAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.resttestclient.autoconfigure;\n\nimport java.net.URI;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TestRestTemplateTestAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass TestRestTemplateTestAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(TestRestTemplateTestAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldFailTotRegisterTestRestTemplateWithoutWebServer() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasFailed()\n\t\t\t.getFailure()\n\t\t\t.hasMessageContaining(\" No local test web server available\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\t\t\torg.springframework.boot.resttestclient.autoconfigure.TestRestTemplateTestAutoConfigurationTests$TestLocalTestWebServerProvider\n\t\t\t\t\t\"\"\")\n\tvoid shouldDefineTestRestTemplateBoundToWebServer() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TestRestTemplate.class)\n\t\t\t\t.hasBean(\"org.springframework.boot.resttestclient.TestRestTemplate\");\n\t\t\tTestRestTemplate testRestTemplate = context.getBean(TestRestTemplate.class);\n\t\t\tassertThat(testRestTemplate.getRestTemplate().getUriTemplateHandler().expand(\"/\"))\n\t\t\t\t.isEqualTo(URI.create(\"https://localhost:8182/\"));\n\t\t});\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\treturn LocalTestWebServer.of(Scheme.HTTPS, 8182);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot RSocket\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"io.rsocket:rsocket-core\")\n\tapi(\"org.springframework:spring-messaging\")\n\n\tcompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-reactor-netty\"))\n\toptional(\"io.rsocket:rsocket-transport-netty\")\n\toptional(\"org.springframework:spring-web\")\n\toptional(\"tools.jackson.dataformat:jackson-dataformat-cbor\")\n\toptional(\"com.fasterxml.jackson.dataformat:jackson-dataformat-cbor\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"org.springframework:spring-webflux\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketMessageHandlerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\n\n/**\n * Callback interface that can be used to customize a {@link RSocketMessageHandler}.\n *\n * @author Aarti Gupta\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RSocketMessageHandlerCustomizer {\n\n\t/**\n\t * Customize the {@link RSocketMessageHandler}.\n\t * @param messageHandler the message handler to customize\n\t */\n\tvoid customize(RSocketMessageHandler messageHandler);\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketMessagingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport io.rsocket.transport.netty.server.TcpServerTransport;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.messaging.handler.MessagingAdviceBean;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.web.method.ControllerAdviceBean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring RSocket support in Spring\n * Messaging.\n *\n * @author Brian Clozel\n * @author Dmitry Sulman\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration(after = RSocketStrategiesAutoConfiguration.class)\n@ConditionalOnClass({ RSocketRequester.class, io.rsocket.RSocket.class, TcpServerTransport.class })\npublic final class RSocketMessagingAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tRSocketMessageHandler messageHandler(RSocketStrategies rSocketStrategies,\n\t\t\tObjectProvider<RSocketMessageHandlerCustomizer> customizers, ApplicationContext context) {\n\t\tRSocketMessageHandler messageHandler = new RSocketMessageHandler();\n\t\tmessageHandler.setRSocketStrategies(rSocketStrategies);\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(messageHandler));\n\n\t\treturn messageHandler;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ControllerAdviceBean.class)\n\tstatic class MessagingAdviceConfiguration {\n\n\t\t@Bean\n\t\tMessagingAdviceRSocketMessageHandlerCustomizer messagingAdviceRSocketMessageHandlerCustomizer(\n\t\t\t\tApplicationContext applicationContext) {\n\t\t\treturn new MessagingAdviceRSocketMessageHandlerCustomizer(applicationContext);\n\t\t}\n\n\t}\n\n\tstatic final class MessagingAdviceRSocketMessageHandlerCustomizer implements RSocketMessageHandlerCustomizer {\n\n\t\tprivate final ApplicationContext applicationContext;\n\n\t\tMessagingAdviceRSocketMessageHandlerCustomizer(ApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(RSocketMessageHandler messageHandler) {\n\t\t\tControllerAdviceBean.findAnnotatedBeans(this.applicationContext)\n\t\t\t\t.forEach((controllerAdviceBean) -> messageHandler\n\t\t\t\t\t.registerMessagingAdvice(new ControllerAdviceBeanWrapper(controllerAdviceBean)));\n\t\t}\n\n\t}\n\n\tprivate static final class ControllerAdviceBeanWrapper implements MessagingAdviceBean {\n\n\t\tprivate final ControllerAdviceBean adviceBean;\n\n\t\tprivate ControllerAdviceBeanWrapper(ControllerAdviceBean adviceBean) {\n\t\t\tthis.adviceBean = adviceBean;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Class<?> getBeanType() {\n\t\t\treturn this.adviceBean.getBeanType();\n\t\t}\n\n\t\t@Override\n\t\tpublic Object resolveBean() {\n\t\t\treturn this.adviceBean.resolveBean();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isApplicableToBeanType(Class<?> beanType) {\n\t\t\treturn this.adviceBean.isApplicableToBeanType(beanType);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn this.adviceBean.getOrder();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport java.net.InetAddress;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link ConfigurationProperties Properties} for RSocket support.\n *\n * @author Brian Clozel\n * @author Chris Bono\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.rsocket\")\npublic class RSocketProperties {\n\n\t@NestedConfigurationProperty\n\tprivate final Server server = new Server();\n\n\tpublic Server getServer() {\n\t\treturn this.server;\n\t}\n\n\tpublic static class Server {\n\n\t\t/**\n\t\t * Server port.\n\t\t */\n\t\tprivate @Nullable Integer port;\n\n\t\t/**\n\t\t * Network address to which the server should bind.\n\t\t */\n\t\tprivate @Nullable InetAddress address;\n\n\t\t/**\n\t\t * RSocket transport protocol.\n\t\t */\n\t\tprivate RSocketServer.Transport transport = RSocketServer.Transport.TCP;\n\n\t\t/**\n\t\t * Path under which RSocket handles requests (only works with websocket\n\t\t * transport).\n\t\t */\n\t\tprivate @Nullable String mappingPath;\n\n\t\t/**\n\t\t * Maximum transmission unit. Frames larger than the specified value are\n\t\t * fragmented.\n\t\t */\n\t\tprivate @Nullable DataSize fragmentSize;\n\n\t\t@NestedConfigurationProperty\n\t\tprivate @Nullable Ssl ssl;\n\n\t\tprivate final Spec spec = new Spec();\n\n\t\tpublic @Nullable Integer getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tpublic void setPort(@Nullable Integer port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t\tpublic @Nullable InetAddress getAddress() {\n\t\t\treturn this.address;\n\t\t}\n\n\t\tpublic void setAddress(@Nullable InetAddress address) {\n\t\t\tthis.address = address;\n\t\t}\n\n\t\tpublic RSocketServer.Transport getTransport() {\n\t\t\treturn this.transport;\n\t\t}\n\n\t\tpublic void setTransport(RSocketServer.Transport transport) {\n\t\t\tthis.transport = transport;\n\t\t}\n\n\t\tpublic @Nullable String getMappingPath() {\n\t\t\treturn this.mappingPath;\n\t\t}\n\n\t\tpublic void setMappingPath(@Nullable String mappingPath) {\n\t\t\tthis.mappingPath = mappingPath;\n\t\t}\n\n\t\tpublic @Nullable DataSize getFragmentSize() {\n\t\t\treturn this.fragmentSize;\n\t\t}\n\n\t\tpublic void setFragmentSize(@Nullable DataSize fragmentSize) {\n\t\t\tthis.fragmentSize = fragmentSize;\n\t\t}\n\n\t\tpublic @Nullable Ssl getSsl() {\n\t\t\treturn this.ssl;\n\t\t}\n\n\t\tpublic void setSsl(@Nullable Ssl ssl) {\n\t\t\tthis.ssl = ssl;\n\t\t}\n\n\t\tpublic Spec getSpec() {\n\t\t\treturn this.spec;\n\t\t}\n\n\t\tpublic static class Spec {\n\n\t\t\t/**\n\t\t\t * Sub-protocols to use in websocket handshake signature.\n\t\t\t */\n\t\t\tprivate @Nullable String protocols;\n\n\t\t\t/**\n\t\t\t * Maximum allowable frame payload length.\n\t\t\t */\n\t\t\tprivate DataSize maxFramePayloadLength = DataSize.ofBytes(65536);\n\n\t\t\t/**\n\t\t\t * Whether to proxy websocket ping frames or respond to them.\n\t\t\t */\n\t\t\tprivate boolean handlePing;\n\n\t\t\t/**\n\t\t\t * Whether the websocket compression extension is enabled.\n\t\t\t */\n\t\t\tprivate boolean compress;\n\n\t\t\tpublic @Nullable String getProtocols() {\n\t\t\t\treturn this.protocols;\n\t\t\t}\n\n\t\t\tpublic void setProtocols(@Nullable String protocols) {\n\t\t\t\tthis.protocols = protocols;\n\t\t\t}\n\n\t\t\tpublic DataSize getMaxFramePayloadLength() {\n\t\t\t\treturn this.maxFramePayloadLength;\n\t\t\t}\n\n\t\t\tpublic void setMaxFramePayloadLength(DataSize maxFramePayloadLength) {\n\t\t\t\tthis.maxFramePayloadLength = maxFramePayloadLength;\n\t\t\t}\n\n\t\t\tpublic boolean isHandlePing() {\n\t\t\t\treturn this.handlePing;\n\t\t\t}\n\n\t\t\tpublic void setHandlePing(boolean handlePing) {\n\t\t\t\tthis.handlePing = handlePing;\n\t\t\t}\n\n\t\t\tpublic boolean isCompress() {\n\t\t\t\treturn this.compress;\n\t\t\t}\n\n\t\t\tpublic void setCompress(boolean compress) {\n\t\t\t\tthis.compress = compress;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketRequesterAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport io.rsocket.transport.netty.server.TcpServerTransport;\nimport reactor.netty.http.server.HttpServer;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.messaging.rsocket.RSocketConnectorConfigurer;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.messaging.rsocket.RSocketRequester.Builder;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for\n * {@link org.springframework.messaging.rsocket.RSocketRequester}. This auto-configuration\n * creates {@link org.springframework.messaging.rsocket.RSocketRequester.Builder}\n * prototype beans, as the builders are stateful and should not be reused to build\n * requester instances with different configurations.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(after = RSocketStrategiesAutoConfiguration.class)\n@ConditionalOnClass({ RSocketRequester.class, io.rsocket.RSocket.class, HttpServer.class, TcpServerTransport.class })\npublic final class RSocketRequesterAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnMissingBean\n\tRSocketRequester.Builder rSocketRequesterBuilder(RSocketStrategies strategies,\n\t\t\tObjectProvider<RSocketConnectorConfigurer> connectorConfigurers) {\n\t\tBuilder builder = RSocketRequester.builder().rsocketStrategies(strategies);\n\t\tconnectorConfigurers.orderedStream().forEach(builder::rsocketConnector);\n\t\treturn builder;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport io.rsocket.core.RSocketServer;\nimport io.rsocket.frame.decoder.PayloadDecoder;\nimport io.rsocket.transport.netty.server.TcpServerTransport;\nimport reactor.netty.http.server.HttpServer;\nimport reactor.netty.http.server.WebsocketServerSpec.Builder;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AllNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.reactor.netty.autoconfigure.ReactorNettyConfigurations;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketProperties.Server.Spec;\nimport org.springframework.boot.rsocket.context.RSocketServerBootstrap;\nimport org.springframework.boot.rsocket.netty.NettyRSocketServerFactory;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\nimport org.springframework.boot.rsocket.server.RSocketServerFactory;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.io.buffer.NettyDataBufferFactory;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.util.Assert;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for RSocket servers. In the case of\n * {@link org.springframework.boot.WebApplicationType#REACTIVE}, the RSocket server is\n * added as a WebSocket endpoint on the existing\n * {@link org.springframework.boot.reactor.netty.NettyWebServer}. If a specific server\n * port is configured, a new standalone RSocket server is created.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(after = RSocketStrategiesAutoConfiguration.class)\n@ConditionalOnClass({ RSocketServer.class, RSocketStrategies.class, HttpServer.class, TcpServerTransport.class })\n@ConditionalOnBean(RSocketMessageHandler.class)\n@EnableConfigurationProperties(RSocketProperties.class)\npublic final class RSocketServerAutoConfiguration {\n\n\t@Conditional(OnRSocketWebServerCondition.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebFluxServerConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tRSocketWebSocketNettyRouteProvider rSocketWebsocketRouteProvider(RSocketProperties properties,\n\t\t\t\tRSocketMessageHandler messageHandler, ObjectProvider<RSocketServerCustomizer> customizers) {\n\t\t\tString mappingPath = properties.getServer().getMappingPath();\n\t\t\tAssert.state(mappingPath != null, \"'mappingPath' must not be null\");\n\t\t\treturn new RSocketWebSocketNettyRouteProvider(mappingPath, messageHandler.responder(),\n\t\t\t\t\tcustomizeWebsocketServerSpec(properties.getServer().getSpec()), customizers.orderedStream());\n\t\t}\n\n\t\tprivate Consumer<Builder> customizeWebsocketServerSpec(Spec spec) {\n\t\t\treturn (builder) -> {\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(spec.getProtocols()).to(builder::protocols);\n\t\t\t\tmap.from(spec.getMaxFramePayloadLength()).asInt(DataSize::toBytes).to(builder::maxFramePayloadLength);\n\t\t\t\tmap.from(spec.isHandlePing()).to(builder::handlePing);\n\t\t\t\tmap.from(spec.isCompress()).to(builder::compress);\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@ConditionalOnProperty(\"spring.rsocket.server.port\")\n\t@ConditionalOnClass(ReactorResourceFactory.class)\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ReactorNettyConfigurations.ReactorResourceFactoryConfiguration.class)\n\tstatic class EmbeddedServerConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tRSocketServerFactory rSocketServerFactory(RSocketProperties properties, ReactorResourceFactory resourceFactory,\n\t\t\t\tObjectProvider<RSocketServerCustomizer> customizers, ObjectProvider<SslBundles> sslBundles) {\n\t\t\tNettyRSocketServerFactory factory = new NettyRSocketServerFactory();\n\t\t\tfactory.setResourceFactory(resourceFactory);\n\t\t\tfactory.setTransport(properties.getServer().getTransport());\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties.getServer().getAddress()).to(factory::setAddress);\n\t\t\tmap.from(properties.getServer().getPort()).to(factory::setPort);\n\t\t\tmap.from(properties.getServer().getFragmentSize()).to(factory::setFragmentSize);\n\t\t\tmap.from(properties.getServer().getSsl()).to(factory::setSsl);\n\t\t\tfactory.setSslBundles(sslBundles.getIfAvailable());\n\t\t\tfactory.setRSocketServerCustomizers(customizers.orderedStream().toList());\n\t\t\treturn factory;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tRSocketServerBootstrap rSocketServerBootstrap(RSocketServerFactory rSocketServerFactory,\n\t\t\t\tRSocketMessageHandler rSocketMessageHandler) {\n\t\t\treturn new RSocketServerBootstrap(rSocketServerFactory, rSocketMessageHandler.responder());\n\t\t}\n\n\t\t@Bean\n\t\tRSocketServerCustomizer frameDecoderRSocketServerCustomizer(RSocketMessageHandler rSocketMessageHandler) {\n\t\t\treturn (server) -> {\n\t\t\t\tif (rSocketMessageHandler.getRSocketStrategies()\n\t\t\t\t\t.dataBufferFactory() instanceof NettyDataBufferFactory) {\n\t\t\t\t\tserver.payloadDecoder(PayloadDecoder.ZERO_COPY);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class OnRSocketWebServerCondition extends AllNestedConditions {\n\n\t\tOnRSocketWebServerCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t\tstatic class IsReactiveWebApplication {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = \"spring.rsocket.server.port\", havingValue = \"false\", matchIfMissing = true)\n\t\tstatic class HasNoPortConfigured {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.rsocket.server.mapping-path\")\n\t\tstatic class HasMappingPathConfigured {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = \"spring.rsocket.server.transport\", havingValue = \"websocket\")\n\t\tstatic class HasWebsocketTransportConfigured {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketStrategiesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport com.fasterxml.jackson.dataformat.cbor.CBORFactory;\nimport io.netty.buffer.PooledByteBufAllocator;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.dataformat.cbor.CBORMapper;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.rsocket.messaging.RSocketStrategiesCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.cbor.JacksonCborDecoder;\nimport org.springframework.http.codec.cbor.JacksonCborEncoder;\nimport org.springframework.http.codec.json.JacksonJsonDecoder;\nimport org.springframework.http.codec.json.JacksonJsonEncoder;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.util.pattern.PathPatternRouteMatcher;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link RSocketStrategies}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\",\n\t\t\"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\" })\n@ConditionalOnClass({ io.rsocket.RSocket.class, RSocketStrategies.class, PooledByteBufAllocator.class })\npublic final class RSocketStrategiesAutoConfiguration {\n\n\tprivate static final String PATHPATTERN_ROUTEMATCHER_CLASS = \"org.springframework.web.util.pattern.PathPatternRouteMatcher\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tRSocketStrategies rSocketStrategies(ObjectProvider<RSocketStrategiesCustomizer> customizers) {\n\t\tRSocketStrategies.Builder builder = RSocketStrategies.builder();\n\t\tif (ClassUtils.isPresent(PATHPATTERN_ROUTEMATCHER_CLASS, null)) {\n\t\t\tbuilder.routeMatcher(new PathPatternRouteMatcher());\n\t\t}\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(name = \"spring.rsocket.preferred-mapper\", havingValue = \"jackson\", matchIfMissing = true)\n\tstatic class JacksonStrategyConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(CBORMapper.class)\n\t\t@ConditionalOnBean(CBORMapper.class)\n\t\tstatic class JacksonCborStrategyConfiguration {\n\n\t\t\tprivate static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_CBOR };\n\n\t\t\t@Bean\n\t\t\t@Order(0)\n\t\t\tRSocketStrategiesCustomizer jacksonCborRSocketStrategyCustomizer(CBORMapper cborMapper) {\n\t\t\t\treturn (strategy) -> {\n\t\t\t\t\tstrategy.decoder(new JacksonCborDecoder(cborMapper, SUPPORTED_TYPES));\n\t\t\t\t\tstrategy.encoder(new JacksonCborEncoder(cborMapper, SUPPORTED_TYPES));\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(JsonMapper.class)\n\t\tstatic class JacksonJsonStrategyConfiguration {\n\n\t\t\tprivate static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_JSON,\n\t\t\t\t\tnew MediaType(\"application\", \"*+json\") };\n\n\t\t\t@Bean\n\t\t\t@Order(1)\n\t\t\t@ConditionalOnBean(JsonMapper.class)\n\t\t\tRSocketStrategiesCustomizer jacksonJsonRSocketStrategyCustomizer(JsonMapper jsonMapper) {\n\t\t\t\treturn (strategy) -> {\n\t\t\t\t\tstrategy.decoder(new JacksonJsonDecoder(jsonMapper, SUPPORTED_TYPES));\n\t\t\t\t\tstrategy.encoder(new JacksonJsonEncoder(jsonMapper, SUPPORTED_TYPES));\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(NoJacksonOrJackson2Preferred.class)\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tstatic class Jackson2StrategyConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass({ ObjectMapper.class, CBORFactory.class })\n\t\tstatic class Jackson2CborStrategyConfiguration {\n\n\t\t\tprivate static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_CBOR };\n\n\t\t\t@Bean\n\t\t\t@Order(0)\n\t\t\t@ConditionalOnBean(org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.class)\n\t\t\tRSocketStrategiesCustomizer jackson2CborRSocketStrategyCustomizer(\n\t\t\t\t\torg.springframework.http.converter.json.Jackson2ObjectMapperBuilder builder) {\n\t\t\t\treturn (strategy) -> {\n\t\t\t\t\tObjectMapper objectMapper = builder.createXmlMapper(false)\n\t\t\t\t\t\t.factory(new com.fasterxml.jackson.dataformat.cbor.CBORFactory())\n\t\t\t\t\t\t.build();\n\t\t\t\t\tstrategy.decoder(\n\t\t\t\t\t\t\tnew org.springframework.http.codec.cbor.Jackson2CborDecoder(objectMapper, SUPPORTED_TYPES));\n\t\t\t\t\tstrategy.encoder(\n\t\t\t\t\t\t\tnew org.springframework.http.codec.cbor.Jackson2CborEncoder(objectMapper, SUPPORTED_TYPES));\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t\t@ConditionalOnClass(ObjectMapper.class)\n\t\tstatic class Jackson2JsonStrategyConfiguration {\n\n\t\t\tprivate static final MediaType[] SUPPORTED_TYPES = { MediaType.APPLICATION_JSON,\n\t\t\t\t\tnew MediaType(\"application\", \"*+json\") };\n\n\t\t\t@Bean\n\t\t\t@Order(1)\n\t\t\t@ConditionalOnBean(ObjectMapper.class)\n\t\t\tRSocketStrategiesCustomizer jackson2JsonRSocketStrategyCustomizer(ObjectMapper objectMapper) {\n\t\t\t\treturn (strategy) -> {\n\t\t\t\t\tstrategy.decoder(\n\t\t\t\t\t\t\tnew org.springframework.http.codec.json.Jackson2JsonDecoder(objectMapper, SUPPORTED_TYPES));\n\t\t\t\t\tstrategy.encoder(\n\t\t\t\t\t\t\tnew org.springframework.http.codec.json.Jackson2JsonEncoder(objectMapper, SUPPORTED_TYPES));\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class NoJacksonOrJackson2Preferred extends AnyNestedCondition {\n\n\t\tNoJacksonOrJackson2Preferred() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnMissingClass(\"tools.jackson.databind.json.JsonMapper\")\n\t\tstatic class NoJackson {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = \"spring.rsocket.preferred-mapper\", havingValue = \"jackson2\")\n\t\tstatic class Jackson2Preferred {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/RSocketWebSocketNettyRouteProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.stream.Stream;\n\nimport io.rsocket.SocketAcceptor;\nimport io.rsocket.core.RSocketServer;\nimport io.rsocket.transport.ServerTransport;\nimport io.rsocket.transport.netty.server.WebsocketRouteTransport;\nimport reactor.netty.http.server.HttpServerRoutes;\nimport reactor.netty.http.server.WebsocketServerSpec;\nimport reactor.netty.http.server.WebsocketServerSpec.Builder;\n\nimport org.springframework.boot.reactor.netty.NettyRouteProvider;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\n\n/**\n * {@link NettyRouteProvider} that configures an RSocket Websocket endpoint.\n *\n * @author Brian Clozel\n * @author Leo Li\n */\nclass RSocketWebSocketNettyRouteProvider implements NettyRouteProvider {\n\n\tprivate final String mappingPath;\n\n\tprivate final SocketAcceptor socketAcceptor;\n\n\tprivate final List<RSocketServerCustomizer> customizers;\n\n\tprivate final Consumer<Builder> serverSpecCustomizer;\n\n\tRSocketWebSocketNettyRouteProvider(String mappingPath, SocketAcceptor socketAcceptor,\n\t\t\tConsumer<Builder> serverSpecCustomizer, Stream<RSocketServerCustomizer> customizers) {\n\t\tthis.mappingPath = mappingPath;\n\t\tthis.socketAcceptor = socketAcceptor;\n\t\tthis.serverSpecCustomizer = serverSpecCustomizer;\n\t\tthis.customizers = customizers.toList();\n\t}\n\n\t@Override\n\tpublic HttpServerRoutes apply(HttpServerRoutes httpServerRoutes) {\n\t\tRSocketServer server = RSocketServer.create(this.socketAcceptor);\n\t\tthis.customizers.forEach((customizer) -> customizer.customize(server));\n\t\tServerTransport.ConnectionAcceptor connectionAcceptor = server.asConnectionAcceptor();\n\t\treturn httpServerRoutes.ws(this.mappingPath, WebsocketRouteTransport.newHandler(connectionAcceptor),\n\t\t\t\tcreateWebsocketServerSpec());\n\t}\n\n\tprivate WebsocketServerSpec createWebsocketServerSpec() {\n\t\tWebsocketServerSpec.Builder builder = WebsocketServerSpec.builder();\n\t\tthis.serverSpecCustomizer.accept(builder);\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RSocket.\n */\n@NullMarked\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/context/RSocketPortInfoApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.context;\n\nimport java.net.InetSocketAddress;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\n\n/**\n * {@link ApplicationContextInitializer} that sets {@link Environment} properties for the\n * ports that {@link RSocketServer} servers are actually listening on. The property\n * {@literal \"local.rsocket.server.port\"} can be injected directly into tests using\n * {@link Value @Value} or obtained through the {@link Environment}.\n * <p>\n * Properties are automatically propagated up to any parent context.\n *\n * @author Verónica Vásquez\n * @author Eddú Meléndez\n * @since 2.2.0\n */\npublic class RSocketPortInfoApplicationContextInitializer\n\t\timplements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.addApplicationListener(new Listener(applicationContext));\n\t}\n\n\tprivate static class Listener implements ApplicationListener<RSocketServerInitializedEvent> {\n\n\t\tprivate static final String PROPERTY_NAME = \"local.rsocket.server.port\";\n\n\t\tprivate static final String PROPERTY_SOURCE_NAME = \"server.ports\";\n\n\t\tprivate final ConfigurableApplicationContext applicationContext;\n\n\t\tListener(ConfigurableApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(RSocketServerInitializedEvent event) {\n\t\t\tInetSocketAddress address = event.getServer().address();\n\t\t\tif (address != null) {\n\t\t\t\tsetPortProperty(this.applicationContext, address.getPort());\n\t\t\t}\n\t\t}\n\n\t\tprivate void setPortProperty(ApplicationContext context, int port) {\n\t\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\t\tsetPortProperty(configurableContext.getEnvironment(), port);\n\t\t\t}\n\t\t\tif (context.getParent() != null) {\n\t\t\t\tsetPortProperty(context.getParent(), port);\n\t\t\t}\n\t\t}\n\n\t\tprivate void setPortProperty(ConfigurableEnvironment environment, int port) {\n\t\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\t\tPropertySource<?> source = sources.get(PROPERTY_SOURCE_NAME);\n\t\t\tif (source == null) {\n\t\t\t\tsource = new MapPropertySource(PROPERTY_SOURCE_NAME, new HashMap<>());\n\t\t\t\tsources.addFirst(source);\n\t\t\t}\n\t\t\tsetPortProperty(port, source);\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate void setPortProperty(int port, PropertySource<?> source) {\n\t\t\t((Map<String, Object>) source.getSource()).put(PROPERTY_NAME, port);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/context/RSocketServerBootstrap.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.context;\n\nimport io.rsocket.SocketAcceptor;\n\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.boot.rsocket.server.RSocketServerFactory;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.util.Assert;\n\n/**\n * Bootstrap an {@link RSocketServer} and start it with the application context.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\npublic class RSocketServerBootstrap implements ApplicationEventPublisherAware, SmartLifecycle {\n\n\tprivate final RSocketServer server;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationEventPublisher eventPublisher;\n\n\tpublic RSocketServerBootstrap(RSocketServerFactory serverFactory, SocketAcceptor socketAcceptor) {\n\t\tAssert.notNull(serverFactory, \"'serverFactory' must not be null\");\n\t\tthis.server = serverFactory.create(socketAcceptor);\n\t}\n\n\t@Override\n\tpublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {\n\t\tthis.eventPublisher = applicationEventPublisher;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tthis.server.start();\n\t\tthis.eventPublisher.publishEvent(new RSocketServerInitializedEvent(this.server));\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.server.stop();\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn this.server.address() != null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/context/RSocketServerInitializedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.context;\n\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Event to be published after the application context is refreshed and the\n * {@link RSocketServer} is ready. Useful for obtaining the local port of a running\n * server.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\npublic class RSocketServerInitializedEvent extends ApplicationEvent {\n\n\tpublic RSocketServerInitializedEvent(RSocketServer server) {\n\t\tsuper(server);\n\t}\n\n\t/**\n\t * Access the {@link RSocketServer}.\n\t * @return the embedded RSocket server\n\t */\n\tpublic RSocketServer getServer() {\n\t\treturn getSource();\n\t}\n\n\t/**\n\t * Access the source of the event (an {@link RSocketServer}).\n\t * @return the embedded web server\n\t */\n\t@Override\n\tpublic RSocketServer getSource() {\n\t\treturn (RSocketServer) super.getSource();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * RSocket integrations with Spring Framework's\n * {@link org.springframework.context.ApplicationContext ApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.rsocket.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/messaging/RSocketStrategiesCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.messaging;\n\nimport org.springframework.messaging.rsocket.RSocketStrategies;\n\n/**\n * Callback interface that can be used to customize codecs configuration for an RSocket\n * client and/or server with {@link RSocketStrategies}.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\n@FunctionalInterface\npublic interface RSocketStrategiesCustomizer {\n\n\t/**\n\t * Callback to customize a {@link RSocketStrategies#builder()} instance.\n\t * @param strategies rSocket codec strategies to customize\n\t */\n\tvoid customize(RSocketStrategies.Builder strategies);\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/messaging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for RSocket-based messaging.\n */\n@NullMarked\npackage org.springframework.boot.rsocket.messaging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/netty/NettyRSocketServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.netty;\n\nimport java.net.InetSocketAddress;\nimport java.time.Duration;\n\nimport io.rsocket.transport.netty.server.CloseableChannel;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.boot.rsocket.server.RSocketServerException;\nimport org.springframework.util.Assert;\n\n/**\n * {@link RSocketServer} that is based on a Reactor Netty server. Usually this class\n * should be created using the {@link NettyRSocketServerFactory} and not directly.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\npublic class NettyRSocketServer implements RSocketServer {\n\n\tprivate static final Log logger = LogFactory.getLog(NettyRSocketServer.class);\n\n\tprivate final Mono<CloseableChannel> starter;\n\n\tprivate final @Nullable Duration lifecycleTimeout;\n\n\tprivate @Nullable CloseableChannel channel;\n\n\tpublic NettyRSocketServer(Mono<CloseableChannel> starter, @Nullable Duration lifecycleTimeout) {\n\t\tAssert.notNull(starter, \"'starter' must not be null\");\n\t\tthis.starter = starter;\n\t\tthis.lifecycleTimeout = lifecycleTimeout;\n\t}\n\n\t@Override\n\tpublic @Nullable InetSocketAddress address() {\n\t\tif (this.channel != null) {\n\t\t\treturn this.channel.address();\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void start() throws RSocketServerException {\n\t\tthis.channel = block(this.starter, this.lifecycleTimeout);\n\t\tInetSocketAddress address = address();\n\t\tAssert.state(address != null, \"'address' must not be null\");\n\t\tlogger.info(\"Netty RSocket started on port \" + address.getPort());\n\t\tstartDaemonAwaitThread(this.channel);\n\t}\n\n\tprivate void startDaemonAwaitThread(@Nullable CloseableChannel channel) {\n\t\tif (channel == null) {\n\t\t\treturn;\n\t\t}\n\t\tThread awaitThread = new Thread(() -> channel.onClose().block(), \"rsocket\");\n\t\tawaitThread.setContextClassLoader(getClass().getClassLoader());\n\t\tawaitThread.setDaemon(false);\n\t\tawaitThread.start();\n\t}\n\n\t@Override\n\tpublic void stop() throws RSocketServerException {\n\t\tif (this.channel != null) {\n\t\t\tthis.channel.dispose();\n\t\t\tthis.channel = null;\n\t\t}\n\t}\n\n\tprivate <T> @Nullable T block(Mono<T> mono, @Nullable Duration timeout) {\n\t\treturn (timeout != null) ? mono.block(timeout) : mono.block();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/netty/NettyRSocketServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.netty;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport io.netty.handler.ssl.ClientAuth;\nimport io.rsocket.SocketAcceptor;\nimport io.rsocket.transport.ServerTransport;\nimport io.rsocket.transport.netty.server.CloseableChannel;\nimport io.rsocket.transport.netty.server.TcpServerTransport;\nimport io.rsocket.transport.netty.server.WebsocketServerTransport;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\nimport reactor.netty.http.Http11SslContextSpec;\nimport reactor.netty.http.server.HttpServer;\nimport reactor.netty.tcp.AbstractProtocolSslContextSpec;\nimport reactor.netty.tcp.SslProvider;\nimport reactor.netty.tcp.SslProvider.GenericSslContextSpec;\nimport reactor.netty.tcp.SslProvider.SslContextSpec;\nimport reactor.netty.tcp.TcpServer;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.rsocket.server.ConfigurableRSocketServerFactory;\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\nimport org.springframework.boot.rsocket.server.RSocketServerFactory;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.Ssl.ServerNameSslBundle;\nimport org.springframework.boot.web.server.WebServerSslBundle;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link RSocketServerFactory} that can be used to create {@link RSocketServer}s backed\n * by Netty.\n *\n * @author Brian Clozel\n * @author Chris Bono\n * @author Scott Frederick\n * @since 2.2.0\n */\npublic class NettyRSocketServerFactory implements RSocketServerFactory, ConfigurableRSocketServerFactory {\n\n\tprivate int port = 9898;\n\n\tprivate @Nullable DataSize fragmentSize;\n\n\tprivate @Nullable InetAddress address;\n\n\tprivate RSocketServer.Transport transport = RSocketServer.Transport.TCP;\n\n\tprivate @Nullable ReactorResourceFactory resourceFactory;\n\n\tprivate @Nullable Duration lifecycleTimeout;\n\n\tprivate List<RSocketServerCustomizer> rSocketServerCustomizers = new ArrayList<>();\n\n\tprivate @Nullable Ssl ssl;\n\n\tprivate @Nullable SslBundles sslBundles;\n\n\t@Override\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\t@Override\n\tpublic void setFragmentSize(@Nullable DataSize fragmentSize) {\n\t\tthis.fragmentSize = fragmentSize;\n\t}\n\n\t@Override\n\tpublic void setAddress(@Nullable InetAddress address) {\n\t\tthis.address = address;\n\t}\n\n\t@Override\n\tpublic void setTransport(RSocketServer.Transport transport) {\n\t\tthis.transport = transport;\n\t}\n\n\t@Override\n\tpublic void setSsl(@Nullable Ssl ssl) {\n\t\tthis.ssl = ssl;\n\t}\n\n\t@Override\n\tpublic void setSslBundles(@Nullable SslBundles sslBundles) {\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t/**\n\t * Set the {@link ReactorResourceFactory} to get the shared resources from.\n\t * @param resourceFactory the server resources\n\t */\n\tpublic void setResourceFactory(@Nullable ReactorResourceFactory resourceFactory) {\n\t\tthis.resourceFactory = resourceFactory;\n\t}\n\n\t/**\n\t * Set {@link RSocketServerCustomizer}s that should be called to configure the\n\t * {@link io.rsocket.core.RSocketServer} while building the server. Calling this\n\t * method will replace any existing customizers.\n\t * @param rSocketServerCustomizers customizers to apply before the server starts\n\t * @since 2.2.7\n\t */\n\tpublic void setRSocketServerCustomizers(Collection<? extends RSocketServerCustomizer> rSocketServerCustomizers) {\n\t\tAssert.notNull(rSocketServerCustomizers, \"'rSocketServerCustomizers' must not be null\");\n\t\tthis.rSocketServerCustomizers = new ArrayList<>(rSocketServerCustomizers);\n\t}\n\n\t/**\n\t * Add {@link RSocketServerCustomizer}s that should be called to configure the\n\t * {@link io.rsocket.core.RSocketServer}.\n\t * @param rSocketServerCustomizers customizers to apply before the server starts\n\t * @since 2.2.7\n\t */\n\tpublic void addRSocketServerCustomizers(RSocketServerCustomizer... rSocketServerCustomizers) {\n\t\tAssert.notNull(rSocketServerCustomizers, \"'rSocketServerCustomizers' must not be null\");\n\t\tthis.rSocketServerCustomizers.addAll(Arrays.asList(rSocketServerCustomizers));\n\t}\n\n\t/**\n\t * Set the maximum amount of time that should be waited when starting or stopping the\n\t * server.\n\t * @param lifecycleTimeout the lifecycle timeout\n\t */\n\tpublic void setLifecycleTimeout(Duration lifecycleTimeout) {\n\t\tthis.lifecycleTimeout = lifecycleTimeout;\n\t}\n\n\t@Override\n\tpublic NettyRSocketServer create(SocketAcceptor socketAcceptor) {\n\t\tServerTransport<CloseableChannel> transport = createTransport();\n\t\tio.rsocket.core.RSocketServer server = io.rsocket.core.RSocketServer.create(socketAcceptor);\n\t\tconfigureServer(server);\n\t\tMono<CloseableChannel> starter = server.bind(transport);\n\t\treturn new NettyRSocketServer(starter, this.lifecycleTimeout);\n\t}\n\n\tprivate void configureServer(io.rsocket.core.RSocketServer server) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.fragmentSize).asInt(DataSize::toBytes).to(server::fragment);\n\t\tthis.rSocketServerCustomizers.forEach((customizer) -> customizer.customize(server));\n\t}\n\n\tprivate ServerTransport<CloseableChannel> createTransport() {\n\t\tif (this.transport == RSocketServer.Transport.WEBSOCKET) {\n\t\t\treturn createWebSocketTransport();\n\t\t}\n\t\treturn createTcpTransport();\n\t}\n\n\tprivate ServerTransport<CloseableChannel> createWebSocketTransport() {\n\t\tHttpServer httpServer = HttpServer.create();\n\t\tif (this.resourceFactory != null) {\n\t\t\thttpServer = httpServer.runOn(this.resourceFactory.getLoopResources());\n\t\t}\n\t\tif (Ssl.isEnabled(this.ssl)) {\n\t\t\thttpServer = customizeSslConfiguration(httpServer, this.ssl);\n\t\t}\n\t\treturn WebsocketServerTransport.create(httpServer.bindAddress(this::getListenAddress));\n\t}\n\n\tprivate HttpServer customizeSslConfiguration(HttpServer httpServer, Ssl ssl) {\n\t\treturn new HttpServerSslCustomizer(ssl.getClientAuth(), getSslBundle(), getServerNameSslBundles())\n\t\t\t.apply(httpServer);\n\t}\n\n\tprivate ServerTransport<CloseableChannel> createTcpTransport() {\n\t\tTcpServer tcpServer = TcpServer.create();\n\t\tif (this.resourceFactory != null) {\n\t\t\ttcpServer = tcpServer.runOn(this.resourceFactory.getLoopResources());\n\t\t}\n\t\tif (Ssl.isEnabled(this.ssl)) {\n\t\t\ttcpServer = new TcpServerSslCustomizer(this.ssl.getClientAuth(), getSslBundle(), getServerNameSslBundles())\n\t\t\t\t.apply(tcpServer);\n\t\t}\n\t\treturn TcpServerTransport.create(tcpServer.bindAddress(this::getListenAddress));\n\t}\n\n\tprivate SslBundle getSslBundle() {\n\t\treturn WebServerSslBundle.get(this.ssl, this.sslBundles);\n\t}\n\n\tprotected final Map<String, SslBundle> getServerNameSslBundles() {\n\t\tAssert.state(this.ssl != null, \"'ssl' must not be null\");\n\t\treturn this.ssl.getServerNameBundles()\n\t\t\t.stream()\n\t\t\t.collect(Collectors.toMap(Ssl.ServerNameSslBundle::serverName, this::getBundle));\n\t}\n\n\tprivate SslBundle getBundle(ServerNameSslBundle serverNameSslBundle) {\n\t\tAssert.state(this.sslBundles != null, \"'sslBundles' must not be null\");\n\t\treturn this.sslBundles.getBundle(serverNameSslBundle.bundle());\n\t}\n\n\tprivate InetSocketAddress getListenAddress() {\n\t\tif (this.address != null) {\n\t\t\treturn new InetSocketAddress(this.address.getHostAddress(), this.port);\n\t\t}\n\t\treturn new InetSocketAddress(this.port);\n\t}\n\n\tprivate abstract static class SslCustomizer {\n\n\t\tprivate final ClientAuth clientAuth;\n\n\t\tprotected SslCustomizer(ClientAuth clientAuth) {\n\t\t\tthis.clientAuth = clientAuth;\n\t\t}\n\n\t\tprotected final AbstractProtocolSslContextSpec<?> createSslContextSpec(SslBundle sslBundle) {\n\t\t\tAbstractProtocolSslContextSpec<?> sslContextSpec = Http11SslContextSpec\n\t\t\t\t.forServer(sslBundle.getManagers().getKeyManagerFactory());\n\t\t\treturn sslContextSpec.configure((builder) -> {\n\t\t\t\tbuilder.trustManager(sslBundle.getManagers().getTrustManagerFactory());\n\t\t\t\tSslOptions options = sslBundle.getOptions();\n\t\t\t\tbuilder.protocols(options.getEnabledProtocols());\n\t\t\t\tbuilder.ciphers(SslOptions.asSet(options.getCiphers()));\n\t\t\t\tbuilder.clientAuth(this.clientAuth);\n\t\t\t});\n\t\t}\n\n\t}\n\n\tprivate static final class TcpServerSslCustomizer extends SslCustomizer {\n\n\t\tprivate final SslBundle sslBundle;\n\n\t\tprivate TcpServerSslCustomizer(Ssl.@Nullable ClientAuth clientAuth, SslBundle sslBundle,\n\t\t\t\tMap<String, SslBundle> serverNameSslBundles) {\n\t\t\tsuper(Ssl.ClientAuth.map(clientAuth, ClientAuth.NONE, ClientAuth.OPTIONAL, ClientAuth.REQUIRE));\n\t\t\tthis.sslBundle = sslBundle;\n\t\t}\n\n\t\tprivate TcpServer apply(TcpServer server) {\n\t\t\tGenericSslContextSpec<?> sslContextSpec = createSslContextSpec(this.sslBundle);\n\t\t\treturn server.secure((spec) -> spec.sslContext(sslContextSpec));\n\t\t}\n\n\t}\n\n\tprivate static final class HttpServerSslCustomizer extends SslCustomizer {\n\n\t\tprivate final SslProvider sslProvider;\n\n\t\tprivate final Map<String, SslProvider> serverNameSslProviders;\n\n\t\tprivate HttpServerSslCustomizer(Ssl.@Nullable ClientAuth clientAuth, SslBundle sslBundle,\n\t\t\t\tMap<String, SslBundle> serverNameSslBundles) {\n\t\t\tsuper(Ssl.ClientAuth.map(clientAuth, ClientAuth.NONE, ClientAuth.OPTIONAL, ClientAuth.REQUIRE));\n\t\t\tthis.sslProvider = createSslProvider(sslBundle);\n\t\t\tthis.serverNameSslProviders = createServerNameSslProviders(serverNameSslBundles);\n\t\t}\n\n\t\tprivate HttpServer apply(HttpServer server) {\n\t\t\treturn server.secure(this::applySecurity);\n\t\t}\n\n\t\tprivate void applySecurity(SslContextSpec spec) {\n\t\t\tspec.sslContext(this.sslProvider.getSslContext()).setSniAsyncMappings((serverName, promise) -> {\n\t\t\t\tSslProvider provider = (serverName != null) ? this.serverNameSslProviders.get(serverName)\n\t\t\t\t\t\t: this.sslProvider;\n\t\t\t\treturn promise.setSuccess(provider);\n\t\t\t});\n\t\t}\n\n\t\tprivate Map<String, SslProvider> createServerNameSslProviders(Map<String, SslBundle> serverNameSslBundles) {\n\t\t\tMap<String, SslProvider> serverNameSslProviders = new HashMap<>();\n\t\t\tserverNameSslBundles.forEach(\n\t\t\t\t\t(serverName, sslBundle) -> serverNameSslProviders.put(serverName, createSslProvider(sslBundle)));\n\t\t\treturn serverNameSslProviders;\n\t\t}\n\n\t\tprivate SslProvider createSslProvider(SslBundle sslBundle) {\n\t\t\treturn SslProvider.builder().sslContext((GenericSslContextSpec<?>) createSslContextSpec(sslBundle)).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/netty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactor Netty based RSocket server implementation.\n */\n@NullMarked\npackage org.springframework.boot.rsocket.netty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/server/ConfigurableRSocketServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.server;\n\nimport java.net.InetAddress;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * A configurable {@link RSocketServerFactory}.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 2.2.0\n */\npublic interface ConfigurableRSocketServerFactory {\n\n\t/**\n\t * Set the port that the server should listen on. If not specified port '9898' will be\n\t * used.\n\t * @param port the port to set\n\t */\n\tvoid setPort(int port);\n\n\t/**\n\t * Specify the maximum transmission unit. Frames larger than the specified\n\t * {@code fragmentSize} are fragmented.\n\t * @param fragmentSize the fragment size\n\t * @since 2.4.0\n\t */\n\tvoid setFragmentSize(@Nullable DataSize fragmentSize);\n\n\t/**\n\t * Set the specific network address that the server should bind to.\n\t * @param address the address to set (defaults to {@code null})\n\t */\n\tvoid setAddress(@Nullable InetAddress address);\n\n\t/**\n\t * Set the transport that the RSocket server should use.\n\t * @param transport the transport protocol to use\n\t */\n\tvoid setTransport(RSocketServer.Transport transport);\n\n\t/**\n\t * Sets the SSL configuration that will be applied to the server's default connector.\n\t * @param ssl the SSL configuration\n\t */\n\tvoid setSsl(@Nullable Ssl ssl);\n\n\t/**\n\t * Sets an SSL bundle that can be used to get SSL configuration.\n\t * @param sslBundles the SSL bundles\n\t * @since 3.1.0\n\t */\n\tvoid setSslBundles(@Nullable SslBundles sslBundles);\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/server/RSocketServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.server;\n\nimport java.net.InetSocketAddress;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Simple interface that represents a fully configured RSocket server. Allows the server\n * to be {@link #start() started} and {@link #stop() stopped}.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\npublic interface RSocketServer {\n\n\t/**\n\t * Starts the RSocket server. Calling this method on an already started server has no\n\t * effect.\n\t * @throws RSocketServerException if the server cannot be started\n\t */\n\tvoid start() throws RSocketServerException;\n\n\t/**\n\t * Stops the RSocket server. Calling this method on an already stopped server has no\n\t * effect.\n\t * @throws RSocketServerException if the server cannot be stopped\n\t */\n\tvoid stop() throws RSocketServerException;\n\n\t/**\n\t * Return the address this server is listening on.\n\t * @return the address\n\t */\n\t@Nullable InetSocketAddress address();\n\n\t/**\n\t * Choice of transport protocol for the RSocket server.\n\t */\n\tenum Transport {\n\n\t\t/**\n\t\t * TCP transport protocol.\n\t\t */\n\t\tTCP,\n\n\t\t/**\n\t\t * WebSocket transport protocol.\n\t\t */\n\t\tWEBSOCKET\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/server/RSocketServerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.server;\n\nimport io.rsocket.core.RSocketServer;\n\n/**\n * Callback interface that can be used to customize a {@link RSocketServer}.\n *\n * @author Brian Clozel\n * @since 2.3.0\n * @see RSocketServer\n */\n@FunctionalInterface\npublic interface RSocketServerCustomizer {\n\n\t/**\n\t * Callback to customize a {@link RSocketServer} instance.\n\t * @param rSocketServer the RSocket server to customize\n\t */\n\tvoid customize(RSocketServer rSocketServer);\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/server/RSocketServerException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.server;\n\n/**\n * Exceptions thrown by an RSocket server.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\npublic class RSocketServerException extends RuntimeException {\n\n\tpublic RSocketServerException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/server/RSocketServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.server;\n\nimport io.rsocket.SocketAcceptor;\n\n/**\n * Factory interface that can be used to create a reactive {@link RSocketServer}.\n *\n * @author Brian Clozel\n * @since 2.2.0\n */\n@FunctionalInterface\npublic interface RSocketServerFactory {\n\n\t/**\n\t * Gets a new fully configured but paused {@link RSocketServer} instance. Clients\n\t * should not be able to connect to the returned server until\n\t * {@link RSocketServer#start()} is called (which happens when the\n\t * {@code ApplicationContext} has been fully refreshed).\n\t * @param socketAcceptor the socket acceptor\n\t * @return a fully configured and started {@link RSocketServer}\n\t * @see RSocketServer#stop()\n\t */\n\tRSocketServer create(SocketAcceptor socketAcceptor);\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/java/org/springframework/boot/rsocket/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for RSocket servers.\n */\n@NullMarked\npackage org.springframework.boot.rsocket.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.rsocket.preferred-mapper\",\n      \"type\": \"java.lang.String\",\n      \"defaultValue\": \"jackson\",\n      \"description\": \"Preferred JSON and CBOR mapper to use. By default, auto-detected according to the environment. Supported values are 'jackson' and 'jackson2' (deprecated).\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.rsocket.preferred-mapper\",\n      \"values\": [\n        {\n          \"value\": \"jackson\"\n        },\n        {\n          \"value\": \"jackson2\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration\norg.springframework.boot.rsocket.autoconfigure.RSocketRequesterAutoConfiguration\norg.springframework.boot.rsocket.autoconfigure.RSocketServerAutoConfiguration\norg.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/main/resources/META-INF/spring.factories",
    "content": "# Application Context Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/autoconfigure/RSocketMessagingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport io.rsocket.frame.FrameType;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.codec.CharSequenceEncoder;\nimport org.springframework.core.codec.StringDecoder;\nimport org.springframework.messaging.Message;\nimport org.springframework.messaging.handler.DestinationPatternsMessageCondition;\nimport org.springframework.messaging.handler.annotation.MessageExceptionHandler;\nimport org.springframework.messaging.handler.annotation.MessageMapping;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketFrameTypeMessageCondition;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.messaging.support.MessageBuilder;\nimport org.springframework.messaging.support.MessageHeaderAccessor;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.RouteMatcher;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RSocketMessagingAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Madhura Bhave\n */\nclass RSocketMessagingAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RSocketMessagingAutoConfiguration.class))\n\t\t.withUserConfiguration(BaseConfiguration.class);\n\n\t@Test\n\tvoid shouldCreateDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBeans(RSocketMessageHandler.class).hasSize(1));\n\t}\n\n\t@Test\n\tvoid shouldFailOnMissingStrategies() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(RSocketMessagingAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tThrowable startupFailure = context.getStartupFailure();\n\t\t\t\tassertThat(startupFailure).isNotNull();\n\t\t\t\tassertThat(startupFailure.getMessage()).contains(\"No qualifying bean of type \"\n\t\t\t\t\t\t+ \"'org.springframework.messaging.rsocket.RSocketStrategies' available\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomSocketAcceptor() {\n\t\tthis.contextRunner.withUserConfiguration(CustomMessageHandler.class)\n\t\t\t.run((context) -> assertThat(context).getBeanNames(RSocketMessageHandler.class)\n\t\t\t\t.containsOnly(\"customMessageHandler\"));\n\t}\n\n\t@Test\n\tvoid shouldApplyMessageHandlerCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizerConfiguration.class).run((context) -> {\n\t\t\tRSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);\n\t\t\tassertThat(handler.getDefaultDataMimeType()).isEqualTo(MimeType.valueOf(\"application/json\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterControllerAdvice() {\n\t\tthis.contextRunner.withBean(TestControllerAdvice.class).withBean(TestController.class).run((context) -> {\n\t\t\tRSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);\n\t\t\tMessageHeaderAccessor headers = new MessageHeaderAccessor();\n\t\t\tRouteMatcher routeMatcher = handler.getRouteMatcher();\n\t\t\tassertThat(routeMatcher).isNotNull();\n\t\t\tRouteMatcher.Route route = routeMatcher.parseRoute(\"exception\");\n\t\t\theaders.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, route);\n\t\t\theaders.setHeader(RSocketFrameTypeMessageCondition.FRAME_TYPE_HEADER, FrameType.REQUEST_FNF);\n\t\t\tMessage<?> message = MessageBuilder.createMessage(Mono.empty(), headers.getMessageHeaders());\n\n\t\t\tStepVerifier.create(handler.handleMessage(message)).expectComplete().verify();\n\t\t\tassertThat(context.getBean(TestControllerAdvice.class).isExceptionHandled()).isTrue();\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tRSocketStrategies rSocketStrategies() {\n\t\t\treturn RSocketStrategies.builder()\n\t\t\t\t.encoder(CharSequenceEncoder.textPlainOnly())\n\t\t\t\t.decoder(StringDecoder.allMimeTypes())\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomMessageHandler {\n\n\t\t@Bean\n\t\tRSocketMessageHandler customMessageHandler() {\n\t\t\tRSocketMessageHandler messageHandler = new RSocketMessageHandler();\n\t\t\tRSocketStrategies strategies = RSocketStrategies.builder()\n\t\t\t\t.encoder(CharSequenceEncoder.textPlainOnly())\n\t\t\t\t.decoder(StringDecoder.allMimeTypes())\n\t\t\t\t.build();\n\t\t\tmessageHandler.setRSocketStrategies(strategies);\n\t\t\treturn messageHandler;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tRSocketMessageHandlerCustomizer customizer() {\n\t\t\treturn (messageHandler) -> messageHandler.setDefaultDataMimeType(MimeType.valueOf(\"application/json\"));\n\t\t}\n\n\t}\n\n\t@Controller\n\tstatic final class TestController {\n\n\t\t@MessageMapping(\"exception\")\n\t\tvoid handleWithSimulatedException() {\n\t\t\tthrow new IllegalStateException(\"simulated exception\");\n\t\t}\n\n\t}\n\n\t@ControllerAdvice\n\tstatic final class TestControllerAdvice {\n\n\t\tboolean exceptionHandled;\n\n\t\tboolean isExceptionHandled() {\n\t\t\treturn this.exceptionHandled;\n\t\t}\n\n\t\t@MessageExceptionHandler\n\t\tvoid handleException(IllegalStateException ex) {\n\t\t\tthis.exceptionHandled = true;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/autoconfigure/RSocketPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.netty.http.server.WebsocketServerSpec;\n\nimport org.springframework.boot.rsocket.autoconfigure.RSocketProperties.Server.Spec;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RSocketProperties}.\n *\n * @author Stephane Nicoll\n */\nclass RSocketPropertiesTests {\n\n\t@Test\n\tvoid defaultServerSpecValuesAreConsistent() {\n\t\tWebsocketServerSpec spec = WebsocketServerSpec.builder().build();\n\t\tSpec properties = new RSocketProperties().getServer().getSpec();\n\t\tassertThat(properties.getProtocols()).isEqualTo(spec.protocols());\n\t\tassertThat(properties.getMaxFramePayloadLength().toBytes()).isEqualTo(spec.maxFramePayloadLength());\n\t\tassertThat(properties.isHandlePing()).isEqualTo(spec.handlePing());\n\t\tassertThat(properties.isCompress()).isEqualTo(spec.compress());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/autoconfigure/RSocketRequesterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.messaging.rsocket.RSocketConnectorConfigurer;\nimport org.springframework.messaging.rsocket.RSocketRequester;\n\nimport static org.assertj.core.api.Assertions.as;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RSocketRequesterAutoConfiguration}\n *\n * @author Brian Clozel\n * @author Nguyen Bao Sach\n */\nclass RSocketRequesterAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(RSocketStrategiesAutoConfiguration.class, RSocketRequesterAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldCreateBuilder() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(RSocketRequester.Builder.class));\n\t}\n\n\t@Test\n\tvoid shouldGetPrototypeScopedBean() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRSocketRequester.Builder first = context.getBean(RSocketRequester.Builder.class);\n\t\t\tRSocketRequester.Builder second = context.getBean(RSocketRequester.Builder.class);\n\t\t\tassertThat(first).isNotEqualTo(second);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotCreateBuilderIfAlreadyPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRSocketRequesterBuilder.class).run((context) -> {\n\t\t\tRSocketRequester.Builder builder = context.getBean(RSocketRequester.Builder.class);\n\t\t\tassertThat(builder).isInstanceOf(MyRSocketRequesterBuilder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateBuilderWithAvailableRSocketConnectorConfigurers() {\n\t\tRSocketConnectorConfigurer first = mock(RSocketConnectorConfigurer.class);\n\t\tRSocketConnectorConfigurer second = mock(RSocketConnectorConfigurer.class);\n\t\tthis.contextRunner.withBean(\"first\", RSocketConnectorConfigurer.class, () -> first)\n\t\t\t.withBean(\"second\", RSocketConnectorConfigurer.class, () -> second)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(RSocketConnectorConfigurer.class).hasSize(2);\n\t\t\t\tRSocketRequester.Builder builder = context.getBean(RSocketRequester.Builder.class);\n\t\t\t\tassertThat(builder).extracting(\"rsocketConnectorConfigurers\", as(InstanceOfAssertFactories.LIST))\n\t\t\t\t\t.containsExactly(first, second);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRSocketRequesterBuilder {\n\n\t\t@Bean\n\t\tMyRSocketRequesterBuilder myRSocketRequesterBuilder() {\n\t\t\treturn mock(MyRSocketRequesterBuilder.class);\n\t\t}\n\n\t}\n\n\tinterface MyRSocketRequesterBuilder extends RSocketRequester.Builder {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/autoconfigure/RSocketServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer;\nimport org.springframework.boot.rsocket.context.RSocketServerBootstrap;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\nimport org.springframework.boot.rsocket.server.RSocketServerFactory;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.codec.CharSequenceEncoder;\nimport org.springframework.core.codec.StringDecoder;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RSocketServerAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Verónica Vásquez\n * @author Scott Frederick\n */\nclass RSocketServerAutoConfigurationTests {\n\n\t@Test\n\tvoid shouldNotCreateBeansByDefault() {\n\t\tcontextRunner().run((context) -> assertThat(context).doesNotHaveBean(WebServerFactoryCustomizer.class)\n\t\t\t.doesNotHaveBean(RSocketServerFactory.class)\n\t\t\t.doesNotHaveBean(RSocketServerBootstrap.class));\n\t}\n\n\t@Test\n\tvoid shouldNotCreateDefaultBeansForReactiveWebAppWithoutMapping() {\n\t\treactiveWebContextRunner()\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(WebServerFactoryCustomizer.class)\n\t\t\t\t.doesNotHaveBean(RSocketServerFactory.class)\n\t\t\t\t.doesNotHaveBean(RSocketServerBootstrap.class));\n\t}\n\n\t@Test\n\tvoid shouldNotCreateDefaultBeansForReactiveWebAppWithWrongTransport() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.transport=tcp\", \"spring.rsocket.server.mapping-path=/rsocket\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(WebServerFactoryCustomizer.class)\n\t\t\t\t.doesNotHaveBean(RSocketServerFactory.class)\n\t\t\t\t.doesNotHaveBean(RSocketServerBootstrap.class));\n\t}\n\n\t@Test\n\tvoid shouldCreateDefaultBeansForReactiveWebApp() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.transport=websocket\",\n\t\t\t\t\t\"spring.rsocket.server.mapping-path=/rsocket\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RSocketWebSocketNettyRouteProvider.class));\n\t}\n\n\t@Test\n\tvoid shouldNotCreateWebSocketRouteProviderWhenDedicatedPortIsSet() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\", \"spring.rsocket.server.transport=websocket\",\n\t\t\t\t\t\"spring.rsocket.server.mapping-path=/rsocket\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RSocketServerFactory.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(RSocketWebSocketNettyRouteProvider.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateDefaultBeansForRSocketServerWhenPortIsSet() {\n\t\treactiveWebContextRunner().withPropertyValues(\"spring.rsocket.server.port=0\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RSocketServerFactory.class)\n\t\t\t\t.hasSingleBean(RSocketServerBootstrap.class)\n\t\t\t\t.hasSingleBean(RSocketServerCustomizer.class));\n\t}\n\n\t@Test\n\tvoid shouldSetLocalServerPortWhenRSocketServerPortIsSet() {\n\t\treactiveWebContextRunner().withPropertyValues(\"spring.rsocket.server.port=0\")\n\t\t\t.withInitializer(new RSocketPortInfoApplicationContextInitializer())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RSocketServerFactory.class)\n\t\t\t\t\t.hasSingleBean(RSocketServerBootstrap.class)\n\t\t\t\t\t.hasSingleBean(RSocketServerCustomizer.class);\n\t\t\t\tassertThat(context.getEnvironment().getProperty(\"local.rsocket.server.port\")).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSetFragmentWhenRSocketServerFragmentSizeIsSet() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\", \"spring.rsocket.server.fragment-size=12KB\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RSocketServerFactory.class);\n\t\t\t\tRSocketServerFactory factory = context.getBean(RSocketServerFactory.class);\n\t\t\t\tassertThat(factory).hasFieldOrPropertyWithValue(\"fragmentSize\", DataSize.ofKilobytes(12));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailToSetFragmentWhenRSocketServerFragmentSizeIsBelow64() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\", \"spring.rsocket.server.fragment-size=60B\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure())\n\t\t\t\t\t.hasMessageContaining(\"The smallest allowed mtu size is 64 bytes, provided: 60\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid shouldUseSslWhenRocketServerSslIsConfigured() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.ssl.keyStore=classpath:test.jks\",\n\t\t\t\t\t\"spring.rsocket.server.ssl.keyPassword=password\", \"spring.rsocket.server.port=0\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RSocketServerFactory.class)\n\t\t\t\t.hasSingleBean(RSocketServerBootstrap.class)\n\t\t\t\t.hasSingleBean(RSocketServerCustomizer.class)\n\t\t\t\t.getBean(RSocketServerFactory.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"ssl.keyStore\", \"classpath:test.jks\")\n\t\t\t\t.hasFieldOrPropertyWithValue(\"ssl.keyPassword\", \"password\"));\n\t}\n\n\t@Test\n\t@Disabled\n\t@WithPackageResources(\"test.jks\")\n\tvoid shouldUseSslWhenRocketServerSslIsConfiguredWithSslBundle() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\", \"spring.rsocket.server.ssl.bundle=test-bundle\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:test.jks\",\n\t\t\t\t\t\"spring.ssl.bundle.jks.test-bundle.key.password=password\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RSocketServerFactory.class)\n\t\t\t\t.hasSingleBean(RSocketServerBootstrap.class)\n\t\t\t\t.hasSingleBean(RSocketServerCustomizer.class)\n\t\t\t\t.getBean(RSocketServerFactory.class)\n\t\t\t\t.hasFieldOrPropertyWithValue(\"sslBundle.details.keyStore\", \"classpath:test.jks\")\n\t\t\t\t.hasFieldOrPropertyWithValue(\"sslBundle.details.keyPassword\", \"password\"));\n\t}\n\n\t@Test\n\tvoid shouldFailWhenSslIsConfiguredWithMissingBundle() {\n\t\treactiveWebContextRunner()\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\", \"spring.rsocket.server.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).hasRootCauseInstanceOf(NoSuchSslBundleException.class)\n\t\t\t\t\t.withFailMessage(\"SSL bundle name 'test-bundle' is not valid\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomServerBootstrap() {\n\t\tcontextRunner().withUserConfiguration(CustomServerBootstrapConfig.class)\n\t\t\t.run((context) -> assertThat(context).getBeanNames(RSocketServerBootstrap.class)\n\t\t\t\t.containsExactly(\"customServerBootstrap\"));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomNettyRouteProvider() {\n\t\treactiveWebContextRunner().withUserConfiguration(CustomNettyRouteProviderConfig.class)\n\t\t\t.withPropertyValues(\"spring.rsocket.server.transport=websocket\",\n\t\t\t\t\t\"spring.rsocket.server.mapping-path=/rsocket\")\n\t\t\t.run((context) -> assertThat(context).getBeanNames(RSocketWebSocketNettyRouteProvider.class)\n\t\t\t\t.containsExactly(\"customNettyRouteProvider\"));\n\t}\n\n\t@Test\n\tvoid whenSpringWebIsNotPresentThenEmbeddedServerConfigurationBacksOff() {\n\t\tcontextRunner().withClassLoader(new FilteredClassLoader(ReactorResourceFactory.class))\n\t\t\t.withPropertyValues(\"spring.rsocket.server.port=0\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RSocketServerFactory.class));\n\t}\n\n\tprivate ApplicationContextRunner contextRunner() {\n\t\treturn new ApplicationContextRunner().withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(RSocketServerAutoConfiguration.class));\n\t}\n\n\tprivate ReactiveWebApplicationContextRunner reactiveWebContextRunner() {\n\t\treturn new ReactiveWebApplicationContextRunner().withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(RSocketServerAutoConfiguration.class, SslAutoConfiguration.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tRSocketMessageHandler messageHandler() {\n\t\t\tRSocketMessageHandler messageHandler = new RSocketMessageHandler();\n\t\t\tmessageHandler.setRSocketStrategies(RSocketStrategies.builder()\n\t\t\t\t.encoder(CharSequenceEncoder.textPlainOnly())\n\t\t\t\t.decoder(StringDecoder.allMimeTypes())\n\t\t\t\t.build());\n\t\t\treturn messageHandler;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomServerBootstrapConfig {\n\n\t\t@Bean\n\t\tRSocketServerBootstrap customServerBootstrap() {\n\t\t\treturn mock(RSocketServerBootstrap.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomNettyRouteProviderConfig {\n\n\t\t@Bean\n\t\tRSocketWebSocketNettyRouteProvider customNettyRouteProvider() {\n\t\t\treturn mock(RSocketWebSocketNettyRouteProvider.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/autoconfigure/RSocketStrategiesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.dataformat.cbor.CBORMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.rsocket.messaging.RSocketStrategiesCustomizer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.codec.CharSequenceEncoder;\nimport org.springframework.core.codec.Decoder;\nimport org.springframework.core.codec.Encoder;\nimport org.springframework.core.codec.StringDecoder;\nimport org.springframework.http.codec.cbor.JacksonCborDecoder;\nimport org.springframework.http.codec.cbor.JacksonCborEncoder;\nimport org.springframework.http.codec.json.JacksonJsonDecoder;\nimport org.springframework.http.codec.json.JacksonJsonEncoder;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\nimport org.springframework.web.util.pattern.PathPatternRouteMatcher;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RSocketStrategiesAutoConfiguration}\n *\n * @author Brian Clozel\n */\nclass RSocketStrategiesAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RSocketStrategiesAutoConfiguration.class))\n\t\t.withBean(JsonMapper.class, () -> JsonMapper.builder().build())\n\t\t.withBean(CBORMapper.class, () -> CBORMapper.builder().build());\n\n\t@Test\n\tvoid shouldCreateDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).getBeans(RSocketStrategies.class).hasSize(1);\n\t\t\tRSocketStrategies strategies = context.getBean(RSocketStrategies.class);\n\t\t\tassertThat(strategies.decoders()).hasAtLeastOneElementOfType(JacksonCborDecoder.class)\n\t\t\t\t.hasAtLeastOneElementOfType(JacksonJsonDecoder.class);\n\t\t\tassertThat(strategies.encoders()).hasAtLeastOneElementOfType(JacksonCborEncoder.class)\n\t\t\t\t.hasAtLeastOneElementOfType(JacksonJsonEncoder.class);\n\t\t\tassertThat(strategies.routeMatcher()).isInstanceOf(PathPatternRouteMatcher.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomStrategies() {\n\t\tthis.contextRunner.withUserConfiguration(UserStrategies.class).run((context) -> {\n\t\t\tassertThat(context).getBeans(RSocketStrategies.class).hasSize(1);\n\t\t\tassertThat(context.getBeanNamesForType(RSocketStrategies.class)).contains(\"customRSocketStrategies\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseStrategiesCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(StrategiesCustomizer.class).run((context) -> {\n\t\t\tassertThat(context).getBeans(RSocketStrategies.class).hasSize(1);\n\t\t\tRSocketStrategies strategies = context.getBean(RSocketStrategies.class);\n\t\t\tassertThat(strategies.decoders()).hasAtLeastOneElementOfType(CustomDecoder.class);\n\t\t\tassertThat(strategies.encoders()).hasAtLeastOneElementOfType(CustomEncoder.class);\n\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid shouldUseJackson2WhenPreferred() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.rsocket.preferred-mapper=jackson2\")\n\t\t\t.run((context) -> {\n\t\t\t\tRSocketStrategies strategies = context.getBean(RSocketStrategies.class);\n\t\t\t\tassertThat(strategies.decoders())\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborDecoder.class)\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonDecoder.class);\n\t\t\t\tassertThat(strategies.encoders())\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborEncoder.class)\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonEncoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid shouldUseJackson2WhenJacksonIsAbsent() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(AutoConfigurations\n\t\t\t\t.of(org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(JsonMapper.class, CBORMapper.class))\n\t\t\t.run((context) -> {\n\t\t\t\tRSocketStrategies strategies = context.getBean(RSocketStrategies.class);\n\t\t\t\tassertThat(strategies.decoders())\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborDecoder.class)\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonDecoder.class);\n\t\t\t\tassertThat(strategies.encoders())\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.cbor.Jackson2CborEncoder.class)\n\t\t\t\t\t.hasAtLeastOneElementOfType(org.springframework.http.codec.json.Jackson2JsonEncoder.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserStrategies {\n\n\t\t@Bean\n\t\tRSocketStrategies customRSocketStrategies() {\n\t\t\treturn RSocketStrategies.builder()\n\t\t\t\t.encoder(CharSequenceEncoder.textPlainOnly())\n\t\t\t\t.decoder(StringDecoder.textPlainOnly())\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StrategiesCustomizer {\n\n\t\t@Bean\n\t\tRSocketStrategiesCustomizer myCustomizer() {\n\t\t\treturn (strategies) -> strategies.encoder(mock(CustomEncoder.class)).decoder(mock(CustomDecoder.class));\n\t\t}\n\n\t}\n\n\tinterface CustomEncoder extends Encoder<String> {\n\n\t}\n\n\tinterface CustomDecoder extends Decoder<String> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/autoconfigure/RSocketWebSocketNettyRouteProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.autoconfigure;\n\nimport java.net.URI;\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.dataformat.cbor.CBORMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;\nimport org.springframework.boot.logging.LogLevel;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.messaging.handler.annotation.MessageMapping;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RSocketWebSocketNettyRouteProvider}.\n *\n * @author Brian Clozel\n */\nclass RSocketWebSocketNettyRouteProviderTests {\n\n\t@Test\n\tvoid webEndpointsShouldWork() {\n\t\tnew ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tRSocketStrategiesAutoConfiguration.class, RSocketServerAutoConfiguration.class,\n\t\t\t\t\tRSocketMessagingAutoConfiguration.class, RSocketRequesterAutoConfiguration.class))\n\t\t\t.withUserConfiguration(WebConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.rsocket.server.transport=websocket\",\n\t\t\t\t\t\"spring.rsocket.server.mapping-path=/rsocket\")\n\t\t\t.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveWebServerApplicationContext serverContext = (ReactiveWebServerApplicationContext) context\n\t\t\t\t\t.getSourceApplicationContext();\n\t\t\t\tWebServer webServer = serverContext.getWebServer();\n\t\t\t\tassertThat(webServer).isNotNull();\n\t\t\t\tRSocketRequester requester = createRSocketRequester(context, webServer);\n\t\t\t\tTestProtocol rsocketResponse = requester.route(\"websocket\")\n\t\t\t\t\t.data(new TestProtocol(\"rsocket\"))\n\t\t\t\t\t.retrieveMono(TestProtocol.class)\n\t\t\t\t\t.block(Duration.ofSeconds(3));\n\t\t\t\tassertThat(rsocketResponse).isNotNull();\n\t\t\t\tassertThat(rsocketResponse.getName()).isEqualTo(\"rsocket\");\n\t\t\t\tWebTestClient client = createWebTestClient(webServer);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/protocol\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"name\")\n\t\t\t\t\t.isEqualTo(\"http\");\n\t\t\t});\n\t}\n\n\tprivate WebTestClient createWebTestClient(WebServer server) {\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://localhost:\" + server.getPort())\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\tprivate RSocketRequester createRSocketRequester(ApplicationContext context, WebServer server) {\n\t\tint port = server.getPort();\n\t\tRSocketRequester.Builder builder = context.getBean(RSocketRequester.Builder.class);\n\t\treturn builder.dataMimeType(MediaType.APPLICATION_CBOR)\n\t\t\t.websocket(URI.create(\"ws://localhost:\" + port + \"/rsocket\"));\n\t}\n\n\t@EnableWebFlux\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebConfiguration {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ApplicationContext context) {\n\t\t\treturn WebHttpHandlerBuilder.applicationContext(context).build();\n\t\t}\n\n\t\t@Bean\n\t\tWebController webController() {\n\t\t\treturn new WebController();\n\t\t}\n\n\t\t@Bean\n\t\tNettyReactiveWebServerFactory customServerFactory(RSocketWebSocketNettyRouteProvider routeProvider) {\n\t\t\tNettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory(0);\n\t\t\tserverFactory.addRouteProviders(routeProvider);\n\t\t\treturn serverFactory;\n\t\t}\n\n\t\t@Bean\n\t\tJsonMapper jsonMapper() {\n\t\t\treturn JsonMapper.builder().build();\n\t\t}\n\n\t\t@Bean\n\t\tCBORMapper cborMapper() {\n\t\t\treturn CBORMapper.builder().build();\n\t\t}\n\n\t}\n\n\t@Controller\n\tstatic class WebController {\n\n\t\t@GetMapping(path = \"/protocol\", produces = MediaType.APPLICATION_JSON_VALUE)\n\t\t@ResponseBody\n\t\tTestProtocol testWebEndpoint() {\n\t\t\treturn new TestProtocol(\"http\");\n\t\t}\n\n\t\t@MessageMapping(\"websocket\")\n\t\tTestProtocol testRSocketEndpoint() {\n\t\t\treturn new TestProtocol(\"rsocket\");\n\t\t}\n\n\t}\n\n\tpublic static class TestProtocol {\n\n\t\tprivate @Nullable String name;\n\n\t\tTestProtocol() {\n\t\t}\n\n\t\tTestProtocol(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic @Nullable String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(@Nullable String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/context/RSocketPortInfoApplicationContextInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.context;\n\nimport java.net.InetSocketAddress;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RSocketPortInfoApplicationContextInitializer}.\n *\n * @author Spencer Gibb\n * @author Andy Wilkinson\n */\nclass RSocketPortInfoApplicationContextInitializerTests {\n\n\t@Test\n\tvoid whenServerHasAddressThenInitializerSetsPortProperty() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class)) {\n\t\t\tcontext.getBean(RSocketPortInfoApplicationContextInitializer.class).initialize(context);\n\t\t\tRSocketServer server = mock(RSocketServer.class);\n\t\t\tgiven(server.address()).willReturn(new InetSocketAddress(65535));\n\t\t\tcontext.publishEvent(new RSocketServerInitializedEvent(server));\n\t\t\tassertThat(context.getEnvironment().getProperty(\"local.rsocket.server.port\")).isEqualTo(\"65535\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid whenServerHasNoAddressThenInitializerDoesNotSetPortProperty() {\n\t\ttry (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class)) {\n\t\t\tcontext.getBean(RSocketPortInfoApplicationContextInitializer.class).initialize(context);\n\t\t\tRSocketServer server = mock(RSocketServer.class);\n\t\t\tcontext.publishEvent(new RSocketServerInitializedEvent(server));\n\t\t\tthen(server).should().address();\n\t\t\tassertThat(context.getEnvironment().getProperty(\"local.rsocket.server.port\")).isNull();\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tRSocketPortInfoApplicationContextInitializer rSocketPortInfoApplicationContextInitializer() {\n\t\t\treturn new RSocketPortInfoApplicationContextInitializer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/java/org/springframework/boot/rsocket/netty/NettyRSocketServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.rsocket.netty;\n\nimport java.net.InetSocketAddress;\nimport java.nio.channels.ClosedChannelException;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.concurrent.Callable;\n\nimport io.netty.buffer.PooledByteBufAllocator;\nimport io.netty.handler.ssl.SslProvider;\nimport io.netty.handler.ssl.util.InsecureTrustManagerFactory;\nimport io.rsocket.ConnectionSetupPayload;\nimport io.rsocket.Payload;\nimport io.rsocket.RSocket;\nimport io.rsocket.SocketAcceptor;\nimport io.rsocket.transport.netty.client.TcpClientTransport;\nimport io.rsocket.transport.netty.client.WebsocketClientTransport;\nimport io.rsocket.util.DefaultPayload;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport reactor.core.publisher.Mono;\nimport reactor.netty.http.Http11SslContextSpec;\nimport reactor.netty.http.client.HttpClient;\nimport reactor.netty.tcp.SslProvider.GenericSslContextSpec;\nimport reactor.netty.tcp.TcpClient;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.rsocket.server.RSocketServer;\nimport org.springframework.boot.rsocket.server.RSocketServer.Transport;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.core.codec.CharSequenceEncoder;\nimport org.springframework.core.codec.StringDecoder;\nimport org.springframework.core.io.buffer.NettyDataBufferFactory;\nimport org.springframework.http.client.ReactorResourceFactory;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.messaging.rsocket.RSocketStrategies;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.will;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link NettyRSocketServerFactory}\n *\n * @author Brian Clozel\n * @author Leo Li\n * @author Chris Bono\n * @author Scott Frederick\n */\nclass NettyRSocketServerFactoryTests {\n\n\tprivate @Nullable NettyRSocketServer server;\n\n\tprivate @Nullable RSocketRequester requester;\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.requester != null) {\n\t\t\tthis.requester.rsocketClient().dispose();\n\t\t}\n\t\tif (this.server != null) {\n\t\t\ttry {\n\t\t\t\tthis.server.stop();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate NettyRSocketServerFactory getFactory() {\n\t\tNettyRSocketServerFactory factory = new NettyRSocketServerFactory();\n\t\tfactory.setPort(0);\n\t\treturn factory;\n\t}\n\n\t@Test\n\tvoid specificPort() {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tint specificPort = doWithRetry(() -> {\n\t\t\tfactory.setPort(0);\n\t\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\t\tthis.server.start();\n\t\t\tInetSocketAddress address = this.server.address();\n\t\t\tassertThat(address).isNotNull();\n\t\t\treturn address.getPort();\n\t\t});\n\t\tthis.requester = createRSocketTcpClient();\n\t\tassertThat(this.server).isNotNull();\n\t\tInetSocketAddress address = this.server.address();\n\t\tassertThat(address).isNotNull();\n\t\tassertThat(address.getPort()).isEqualTo(specificPort);\n\t\tcheckEchoRequest();\n\t}\n\n\t@Test\n\tvoid websocketTransport() {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(RSocketServer.Transport.WEBSOCKET);\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = createRSocketWebSocketClient();\n\t\tcheckEchoRequest();\n\t}\n\n\t@Test\n\tvoid websocketTransportWithReactorResource() {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(RSocketServer.Transport.WEBSOCKET);\n\t\tReactorResourceFactory resourceFactory = new ReactorResourceFactory();\n\t\tresourceFactory.afterPropertiesSet();\n\t\tfactory.setResourceFactory(resourceFactory);\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = createRSocketWebSocketClient();\n\t\tcheckEchoRequest();\n\t}\n\n\t@Test\n\tvoid serverCustomizers() {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tRSocketServerCustomizer[] customizers = new RSocketServerCustomizer[2];\n\t\tfor (int i = 0; i < customizers.length; i++) {\n\t\t\tcustomizers[i] = mock(RSocketServerCustomizer.class);\n\t\t\twill((invocation) -> invocation.getArgument(0)).given(customizers[i])\n\t\t\t\t.customize(any(io.rsocket.core.RSocketServer.class));\n\t\t}\n\t\tfactory.setRSocketServerCustomizers(Arrays.asList(customizers));\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (RSocketServerCustomizer customizer : customizers) {\n\t\t\tordered.verify(customizer).customize(any(io.rsocket.core.RSocketServer.class));\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid tcpTransportBasicSslFromClassPath() {\n\t\ttestBasicSslWithKeyStore(\"classpath:test.jks\", \"password\", Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid tcpTransportBasicSslFromFileSystem(@ResourcePath(\"test.jks\") String keyStore) {\n\t\ttestBasicSslWithKeyStore(keyStore, \"password\", Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid websocketTransportBasicSslFromClassPath() {\n\t\ttestBasicSslWithKeyStore(\"classpath:test.jks\", \"password\", Transport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid websocketTransportBasicSslFromFileSystem(@ResourcePath(\"test.jks\") String keyStore) {\n\t\ttestBasicSslWithKeyStore(keyStore, \"password\", Transport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid tcpTransportBasicSslCertificateFromClassPath() {\n\t\ttestBasicSslWithPemCertificate(\"classpath:test-cert.pem\", \"classpath:test-key.pem\", \"classpath:test-cert.pem\",\n\t\t\t\tTransport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid tcpTransportBasicSslCertificateFromFileSystem(@ResourcePath(\"test-cert.pem\") String testCert,\n\t\t\t@ResourcePath(\"test-key.pem\") String testKey) {\n\t\ttestBasicSslWithPemCertificate(testCert, testKey, testCert, Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid websocketTransportBasicSslCertificateFromClassPath() {\n\t\ttestBasicSslWithPemCertificate(\"classpath:test-cert.pem\", \"classpath:test-key.pem\", \"classpath:test-cert.pem\",\n\t\t\t\tTransport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid websocketTransportBasicSslCertificateFromFileSystem(@ResourcePath(\"test-cert.pem\") String testCert,\n\t\t\t@ResourcePath(\"test-key.pem\") String testKey) {\n\t\ttestBasicSslWithPemCertificate(testCert, testKey, testCert, Transport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid tcpTransportBasicSslFromClassPathWithBundle() {\n\t\ttestBasicSslWithKeyStoreFromBundle(\"classpath:test.jks\", \"password\", Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid tcpTransportBasicSslFromFileSystemWithBundle(@ResourcePath(\"test.jks\") String keyStore) {\n\t\ttestBasicSslWithKeyStoreFromBundle(keyStore, \"password\", Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid websocketTransportBasicSslFromClassPathWithBundle() {\n\t\ttestBasicSslWithKeyStoreFromBundle(\"classpath:test.jks\", \"password\", Transport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid websocketTransportBasicSslFromFileSystemWithBundle(@ResourcePath(\"test.jks\") String keyStore) {\n\t\ttestBasicSslWithKeyStoreFromBundle(keyStore, \"password\", Transport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid tcpTransportBasicSslCertificateFromClassPathWithBundle() {\n\t\ttestBasicSslWithPemCertificateFromBundle(\"classpath:test-cert.pem\", \"classpath:test-key.pem\",\n\t\t\t\t\"classpath:test-cert.pem\", Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid tcpTransportBasicSslCertificateFromFileSystemWithBundle(@ResourcePath(\"test-cert.pem\") String testCert,\n\t\t\t@ResourcePath(\"test-key.pem\") String testKey) {\n\t\ttestBasicSslWithPemCertificateFromBundle(testCert, testKey, testCert, Transport.TCP);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid websocketTransportBasicSslCertificateFromClassPathWithBundle() {\n\t\ttestBasicSslWithPemCertificateFromBundle(\"classpath:test-cert.pem\", \"classpath:test-key.pem\",\n\t\t\t\t\"classpath:test-cert.pem\", Transport.WEBSOCKET);\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\" })\n\tvoid websocketTransportBasicSslCertificateFromFileSystemWithBundle(@ResourcePath(\"test-cert.pem\") String testCert,\n\t\t\t@ResourcePath(\"test-key.pem\") String testKey) {\n\t\ttestBasicSslWithPemCertificateFromBundle(testCert, testKey, testCert, Transport.WEBSOCKET);\n\t}\n\n\tprivate void checkEchoRequest() {\n\t\tString payload = \"test payload\";\n\t\tassertThat(this.requester).isNotNull();\n\t\tMono<String> response = this.requester.route(\"test\").data(payload).retrieveMono(String.class);\n\t\tStepVerifier.create(response).expectNext(payload).expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\tprivate void testBasicSslWithKeyStore(String keyStore, String keyPassword, Transport transport) {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(transport);\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyPassword(keyPassword);\n\t\tfactory.setSsl(ssl);\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = (transport == Transport.TCP) ? createSecureRSocketTcpClient()\n\t\t\t\t: createSecureRSocketWebSocketClient();\n\t\tcheckEchoRequest();\n\t}\n\n\tprivate void testBasicSslWithPemCertificate(String certificate, String certificatePrivateKey,\n\t\t\tString trustCertificate, Transport transport) {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(transport);\n\t\tSsl ssl = new Ssl();\n\t\tssl.setCertificate(certificate);\n\t\tssl.setCertificatePrivateKey(certificatePrivateKey);\n\t\tssl.setTrustCertificate(trustCertificate);\n\t\tssl.setKeyStorePassword(\"\");\n\t\tfactory.setSsl(ssl);\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = (transport == Transport.TCP) ? createSecureRSocketTcpClient()\n\t\t\t\t: createSecureRSocketWebSocketClient();\n\t\tcheckEchoRequest();\n\t}\n\n\tprivate void testBasicSslWithKeyStoreFromBundle(String keyStore, String keyPassword, Transport transport) {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(transport);\n\t\tJksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(keyStore);\n\t\tJksSslStoreDetails trustStoreDetails = null;\n\t\tSslBundle sslBundle = SslBundle.of(new JksSslStoreBundle(keyStoreDetails, trustStoreDetails),\n\t\t\t\tSslBundleKey.of(keyPassword));\n\t\tfactory.setSsl(Ssl.forBundle(\"test\"));\n\t\tfactory.setSslBundles(new DefaultSslBundleRegistry(\"test\", sslBundle));\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = (transport == Transport.TCP) ? createSecureRSocketTcpClient()\n\t\t\t\t: createSecureRSocketWebSocketClient();\n\t\tcheckEchoRequest();\n\t}\n\n\tprivate void testBasicSslWithPemCertificateFromBundle(String certificate, String certificatePrivateKey,\n\t\t\tString trustCertificate, Transport transport) {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(transport);\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(certificate)\n\t\t\t.withPrivateKey(certificatePrivateKey);\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(trustCertificate);\n\t\tSslBundle sslBundle = SslBundle.of(new PemSslStoreBundle(keyStoreDetails, trustStoreDetails));\n\t\tfactory.setSsl(Ssl.forBundle(\"test\"));\n\t\tfactory.setSslBundles(new DefaultSslBundleRegistry(\"test\", sslBundle));\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = (transport == Transport.TCP) ? createSecureRSocketTcpClient()\n\t\t\t\t: createSecureRSocketWebSocketClient();\n\t\tcheckEchoRequest();\n\t}\n\n\t@Test\n\tvoid tcpTransportSslRejectsInsecureClient() {\n\t\tNettyRSocketServerFactory factory = getFactory();\n\t\tfactory.setTransport(Transport.TCP);\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:org/springframework/boot/rsocket/netty/test.jks\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tfactory.setSsl(ssl);\n\t\tthis.server = factory.create(new EchoRequestResponseAcceptor());\n\t\tthis.server.start();\n\t\tthis.requester = createRSocketTcpClient();\n\t\tString payload = \"test payload\";\n\t\tMono<String> responseMono = this.requester.route(\"test\").data(payload).retrieveMono(String.class);\n\t\tStepVerifier.create(responseMono)\n\t\t\t.verifyErrorSatisfies((ex) -> assertThat(ex).isInstanceOf(ClosedChannelException.class));\n\t}\n\n\tprivate RSocketRequester createRSocketTcpClient() {\n\t\treturn createRSocketRequesterBuilder().transport(TcpClientTransport.create(createTcpClient()));\n\t}\n\n\tprivate RSocketRequester createRSocketWebSocketClient() {\n\t\treturn createRSocketRequesterBuilder().transport(WebsocketClientTransport.create(createHttpClient(), \"/\"));\n\t}\n\n\tprivate RSocketRequester createSecureRSocketTcpClient() {\n\t\treturn createRSocketRequesterBuilder().transport(TcpClientTransport.create(createSecureTcpClient()));\n\t}\n\n\tprivate RSocketRequester createSecureRSocketWebSocketClient() {\n\t\treturn createRSocketRequesterBuilder()\n\t\t\t.transport(WebsocketClientTransport.create(createSecureHttpClient(), \"/\"));\n\t}\n\n\tprivate HttpClient createSecureHttpClient() {\n\t\tHttpClient httpClient = createHttpClient();\n\t\tGenericSslContextSpec<?> sslContextSpec = Http11SslContextSpec.forClient()\n\t\t\t.configure((builder) -> builder.sslProvider(SslProvider.JDK)\n\t\t\t\t.trustManager(InsecureTrustManagerFactory.INSTANCE));\n\t\treturn httpClient.secure((spec) -> spec.sslContext(sslContextSpec));\n\t}\n\n\tprivate HttpClient createHttpClient() {\n\t\tassertThat(this.server).isNotNull();\n\t\tInetSocketAddress address = this.server.address();\n\t\tassertThat(address).isNotNull();\n\t\treturn HttpClient.create().host(address.getHostName()).port(address.getPort());\n\t}\n\n\tprivate TcpClient createSecureTcpClient() {\n\t\tTcpClient tcpClient = createTcpClient();\n\t\tGenericSslContextSpec<?> sslContextSpec = Http11SslContextSpec.forClient()\n\t\t\t.configure((builder) -> builder.sslProvider(SslProvider.JDK)\n\t\t\t\t.trustManager(InsecureTrustManagerFactory.INSTANCE));\n\t\treturn tcpClient.secure((spec) -> spec.sslContext(sslContextSpec));\n\t}\n\n\tprivate TcpClient createTcpClient() {\n\t\tassertThat(this.server).isNotNull();\n\t\tInetSocketAddress address = this.server.address();\n\t\tassertThat(address).isNotNull();\n\t\treturn TcpClient.create().host(address.getHostName()).port(address.getPort());\n\t}\n\n\tprivate RSocketRequester.Builder createRSocketRequesterBuilder() {\n\t\tRSocketStrategies strategies = RSocketStrategies.builder()\n\t\t\t.decoder(StringDecoder.allMimeTypes())\n\t\t\t.encoder(CharSequenceEncoder.allMimeTypes())\n\t\t\t.dataBufferFactory(new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT))\n\t\t\t.build();\n\t\treturn RSocketRequester.builder().rsocketStrategies(strategies);\n\t}\n\n\tprivate <T> T doWithRetry(Callable<T> action) {\n\t\tException lastFailure = null;\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\ttry {\n\t\t\t\treturn action.call();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlastFailure = ex;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Action was not successful in 10 attempts\", lastFailure);\n\t}\n\n\tstatic class EchoRequestResponseAcceptor implements SocketAcceptor {\n\n\t\t@Override\n\t\tpublic Mono<RSocket> accept(ConnectionSetupPayload setupPayload, RSocket rSocket) {\n\t\t\treturn Mono.just(new RSocket() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Mono<Payload> requestResponse(Payload payload) {\n\t\t\t\t\treturn Mono.just(DefaultPayload.create(payload));\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/resources/org/springframework/boot/rsocket/netty/test-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-rsocket/src/test/resources/org/springframework/boot/rsocket/netty/test-key.pem",
    "content": "Bag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nKey Attributes: <No Attributes>\n-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD8B1saBN8Y0ZjX\nQ/pvnv2hZa+cBBkFHVkgw+tdzgdcO5Kjv2rnRKd3Oh8Qwdxj3BC9GpicF4GOgkDG\nLrMrYbmV/xGUnNh3YpUwbv+U/pm3VnuSZCk4aYgNEWHrnEHyrge87+MqYqGuMIke\nA5z7GV44PeThfKQs2BLLL/ME+Pb/jN6IVlIHxdBT5TBQkqNGFU7swdZoQ5Viqv44\nUNdVqU5pP3UF/perbOm2CHCbeLiLRvmuvGuBbrbko2XUwBNH+UjmEQaRh/epoy8B\nD31vGY87ym/YOEdpIrqD8bwg7NWP/Fdsryqi8p+U8fcfw4xZjotA0Sv04BC7zXHg\nm1AyZoVzAgMBAAECggEAfEqiZqANaF+BqXQIb4Dw42ZTJzWsIyYYnPySOGZRoe5t\nQJ03uwtULYv34xtANe1DQgd6SMyc46ugBzzjtprQ3ET5Jhn99U6kdcjf+dpf85dO\nhOEppP0CkDNI39nleinSfh6uIOqYgt/D143/nqQhn8oCdSOzkbwT9KnWh1bC9T7I\nvFjGfElvt1/xl88qYgrWgYLgXaencNGgiv/4/M0FNhiHEGsVC7SCu6kapC/WIQpE\n5IdV+HR+tiLoGZhXlhqorY7QC4xKC4wwafVSiFxqDOQAuK+SMD4TCEv0Aop+c+SE\nYBigVTmgVeJkjK7IkTEhKkAEFmRF5/5w+bZD9FhTNQKBgQD+4fNG1ChSU8RdizZT\n5dPlDyAxpETSCEXFFVGtPPh2j93HDWn7XugNyjn5FylTH507QlabC+5wZqltdIjK\nGRB5MIinQ9/nR2fuwGc9s+0BiSEwNOUB1MWm7wWL/JUIiKq6sTi6sJIfsYg79zco\nqxl5WE94aoINx9Utq1cdWhwJTQKBgQD9IjPksd4Jprz8zMrGLzR8k1gqHyhv24qY\nEJ7jiHKKAP6xllTUYwh1IBSL6w2j5lfZPpIkb4Jlk2KUoX6fN81pWkBC/fTBUSIB\nEHM9bL51+yKEYUbGIy/gANuRbHXsWg3sjUsFTNPN4hGTFk3w2xChCyl/f5us8Lo8\nZ633SNdpvwKBgQCGyDU9XzNzVZihXtx7wS0sE7OSjKtX5cf/UCbA1V0OVUWR3SYO\nJ0HPCQFfF0BjFHSwwYPKuaR9C8zMdLNhK5/qdh/NU7czNi9fsZ7moh7SkRFbzJzN\nOxbKD9t/CzJEMQEXeF/nWTfsSpUgILqqZtAxuuFLbAcaAnJYlCKdAumQgQKBgQCK\nmqjJh68pn7gJwGUjoYNe1xtGbSsqHI9F9ovZ0MPO1v6e5M7sQJHH+Fnnxzv/y8e8\nd6tz8e73iX1IHymDKv35uuZHCGF1XOR+qrA/KQUc+vcKf21OXsP/JtkTRs1HLoRD\nS5aRf2DWcfvniyYARSNU2xTM8GWgi2ueWbMDHUp+ZwKBgA/swC+K+Jg5DEWm6Sau\ne6y+eC6S+SoXEKkI3wf7m9aKoZo0y+jh8Gas6gratlc181pSM8O3vZG0n19b493I\napCFomMLE56zEzvyzfpsNhFhk5MBMCn0LPyzX6MiynRlGyWIj0c99fbHI3pOMufP\nWgmVLTZ8uDcSW1MbdUCwFSk5\n-----END PRIVATE KEY-----\nBag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nsubject=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\nissuer=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\n-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-rsocket-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot RSocket Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-rsocket\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket-test/src/main/java/org/springframework/boot/test/rsocket/server/LocalRSocketServerPort.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.rsocket.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Annotation at the field or method/constructor parameter level that injects the RSocket\n * port that was allocated at runtime. Provides a convenient alternative for\n * <code>&#064;Value(&quot;${local.rsocket.server.port}&quot;)</code>.\n *\n * @author Verónica Vásquez\n * @author Eddú Meléndez\n * @since 4.0.0\n */\n@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Value(\"${local.rsocket.server.port}\")\npublic @interface LocalRSocketServerPort {\n\n}\n"
  },
  {
    "path": "module/spring-boot-rsocket-test/src/main/java/org/springframework/boot/test/rsocket/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * RSocket server test utilities and support classes.\n */\n@NullMarked\npackage org.springframework.boot.test.rsocket.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-rsocket-test/src/test/java/org/springframework/boot/test/rsocket/server/LocalRSocketServerPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.test.rsocket.server;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link LocalRSocketServerPort @LocalRSocketServerPort}.\n *\n * @author Verónica Vásquez\n * @author Eddú Meléndez\n */\n@ExtendWith(SpringExtension.class)\n@TestPropertySource(properties = \"local.rsocket.server.port=8181\")\nclass LocalRSocketServerPortTests {\n\n\t@Value(\"${local.rsocket.server.port}\")\n\tprivate @Nullable String fromValue;\n\n\t@LocalRSocketServerPort\n\tprivate @Nullable String fromAnnotation;\n\n\t@Test\n\tvoid testLocalRSocketServerPortAnnotation() {\n\t\tassertThat(this.fromAnnotation).isNotNull().isEqualTo(this.fromValue);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Security\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.security:spring-security-config\")\n\tapi(\"org.springframework.security:spring-security-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-h2console\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-jersey\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(project(\":module:spring-boot-rsocket\"))\n\toptional(project(\":module:spring-boot-webflux\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework:spring-messaging\")\n\toptional(\"org.springframework:spring-webflux\")\n\toptional(\"org.springframework.security:spring-security-data\")\n\toptional(\"org.springframework.security:spring-security-messaging\")\n\toptional(\"org.springframework.security:spring-security-rsocket\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-hibernate\"))\n\ttestImplementation(project(\":module:spring-boot-http-converter\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":module:spring-boot-rsocket\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"org.springframework.security:spring-security-oauth2-client\")\n\ttestImplementation(\"org.springframework.security:spring-security-oauth2-jose\")\n\ttestImplementation(\"org.springframework.security:spring-security-oauth2-resource-server\")\n\ttestImplementation(\"org.springframework.security:spring-security-saml2-service-provider\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.zaxxer:HikariCP\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"test\") {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/MissingAlternativeUserDetailsManagerOrUserPropertiesConfigured.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Condition;\n\n/**\n * {@link Condition} used to check if security username or password properties have been\n * set or there are no alternatives to the user details manager available.\n *\n * @author Andy Wilkinson\n */\nfinal class MissingAlternativeUserDetailsManagerOrUserPropertiesConfigured extends AnyNestedCondition {\n\n\tMissingAlternativeUserDetailsManagerOrUserPropertiesConfigured() {\n\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t}\n\n\t@ConditionalOnMissingClass({ \"org.springframework.security.oauth2.client.registration.ClientRegistrationRepository\",\n\t\t\t\"org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector\",\n\t\t\t\"org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository\" })\n\tstatic final class MissingAlternative {\n\n\t}\n\n\t@ConditionalOnProperty(\"spring.security.user.name\")\n\tstatic final class NameConfigured {\n\n\t}\n\n\t@ConditionalOnProperty(\"spring.security.user.password\")\n\tstatic final class PasswordConfigured {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/ReactiveUserDetailsServiceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.ReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Spring Security in-memory\n * {@link ReactiveUserDetailsService}. Adds a {@link MapReactiveUserDetailsService} with a\n * default user and generated password.\n * <p>\n * This configuration backs-off completely if there is a bean of type\n * {@link ReactiveUserDetailsService}, {@link ReactiveAuthenticationManager}, or\n * {@link ReactiveAuthenticationManagerResolver}.\n * <p>\n * Note that the reactive application detection mechanism is limited to web applications\n * only. If you're writing a non-web application you will need to configure reactive\n * security yourself.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = \"org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration\")\n@ConditionalOnClass({ ReactiveAuthenticationManager.class })\n@ConditionalOnMissingBean(\n\t\tvalue = { ReactiveAuthenticationManager.class, ReactiveUserDetailsService.class,\n\t\t\t\tReactiveAuthenticationManagerResolver.class },\n\t\ttype = { \"org.springframework.security.oauth2.jwt.ReactiveJwtDecoder\" })\n@Conditional({ ReactiveUserDetailsServiceAutoConfiguration.RSocketEnabledOrReactiveWebApplication.class,\n\t\tMissingAlternativeUserDetailsManagerOrUserPropertiesConfigured.class })\n@EnableConfigurationProperties(SecurityProperties.class)\npublic final class ReactiveUserDetailsServiceAutoConfiguration {\n\n\tprivate static final String NOOP_PASSWORD_PREFIX = \"{noop}\";\n\n\tprivate static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile(\"^\\\\{.+}.*$\");\n\n\tprivate static final Log logger = LogFactory.getLog(ReactiveUserDetailsServiceAutoConfiguration.class);\n\n\t@Bean\n\tMapReactiveUserDetailsService reactiveUserDetailsService(SecurityProperties properties,\n\t\t\tObjectProvider<PasswordEncoder> passwordEncoder) {\n\t\tSecurityProperties.User user = properties.getUser();\n\t\tUserDetails userDetails = getUserDetails(user, getOrDeducePassword(user, passwordEncoder.getIfAvailable()));\n\t\treturn new MapReactiveUserDetailsService(userDetails);\n\t}\n\n\tprivate UserDetails getUserDetails(SecurityProperties.User user, String password) {\n\t\tList<String> roles = user.getRoles();\n\t\treturn User.withUsername(user.getName()).password(password).roles(StringUtils.toStringArray(roles)).build();\n\t}\n\n\tprivate String getOrDeducePassword(SecurityProperties.User user, @Nullable PasswordEncoder encoder) {\n\t\tString password = user.getPassword();\n\t\tif (user.isPasswordGenerated()) {\n\t\t\tlogger.info(String.format(\"%n%nUsing generated security password: %s%n\", user.getPassword()));\n\t\t}\n\t\tif (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {\n\t\t\treturn password;\n\t\t}\n\t\treturn NOOP_PASSWORD_PREFIX + password;\n\t}\n\n\tstatic class RSocketEnabledOrReactiveWebApplication extends AnyNestedCondition {\n\n\t\tRSocketEnabledOrReactiveWebApplication() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnBean(RSocketMessageHandler.class)\n\t\tstatic class RSocketSecurityEnabledCondition {\n\n\t\t}\n\n\t\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t\tstatic class ReactiveWebApplicationCondition {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/SecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.AuthenticationEventPublisher;\nimport org.springframework.security.authentication.DefaultAuthenticationEventPublisher;\nimport org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)\n@EnableConfigurationProperties(SecurityProperties.class)\npublic final class SecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(AuthenticationEventPublisher.class)\n\tDefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {\n\t\treturn new DefaultAuthenticationEventPublisher(publisher);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(SecurityEvaluationContextExtension.class)\n\tstatic class SecurityDataConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSecurityEvaluationContextExtension securityEvaluationContextExtension() {\n\t\t\treturn new SecurityEvaluationContextExtension();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/SecurityProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configuration properties for Spring Security.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.security\")\npublic class SecurityProperties {\n\n\tprivate final User user = new User();\n\n\tpublic User getUser() {\n\t\treturn this.user;\n\t}\n\n\tpublic static class User {\n\n\t\t/**\n\t\t * Default user name.\n\t\t */\n\t\tprivate String name = \"user\";\n\n\t\t/**\n\t\t * Password for the default user name.\n\t\t */\n\t\tprivate String password = UUID.randomUUID().toString();\n\n\t\t/**\n\t\t * Granted roles for the default user name.\n\t\t */\n\t\tprivate List<String> roles = new ArrayList<>();\n\n\t\tprivate boolean passwordGenerated = true;\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic String getPassword() {\n\t\t\treturn this.password;\n\t\t}\n\n\t\tpublic void setPassword(String password) {\n\t\t\tif (!StringUtils.hasLength(password)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.passwordGenerated = false;\n\t\t\tthis.password = password;\n\t\t}\n\n\t\tpublic List<String> getRoles() {\n\t\t\treturn this.roles;\n\t\t}\n\n\t\tpublic void setRoles(List<String> roles) {\n\t\t\tthis.roles = new ArrayList<>(roles);\n\t\t}\n\n\t\tpublic boolean isPasswordGenerated() {\n\t\t\treturn this.passwordGenerated;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/UserDetailsServiceAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.AuthenticationManagerResolver;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Spring Security in-memory\n * {@link AuthenticationManager}. Adds an {@link InMemoryUserDetailsManager} with a\n * default user and generated password.\n *\n * @author Dave Syer\n * @author Rob Winch\n * @author Madhura Bhave\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(AuthenticationManager.class)\n@Conditional(MissingAlternativeUserDetailsManagerOrUserPropertiesConfigured.class)\n@ConditionalOnMissingBean(value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class,\n\t\tAuthenticationManagerResolver.class }, type = \"org.springframework.security.oauth2.jwt.JwtDecoder\")\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic final class UserDetailsServiceAutoConfiguration {\n\n\tprivate static final String NOOP_PASSWORD_PREFIX = \"{noop}\";\n\n\tprivate static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile(\"^\\\\{.+}.*$\");\n\n\tprivate static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);\n\n\t@Bean\n\tInMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties,\n\t\t\tObjectProvider<PasswordEncoder> passwordEncoder) {\n\t\tSecurityProperties.User user = properties.getUser();\n\t\tList<String> roles = user.getRoles();\n\t\treturn new InMemoryUserDetailsManager(User.withUsername(user.getName())\n\t\t\t.password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))\n\t\t\t.roles(StringUtils.toStringArray(roles))\n\t\t\t.build());\n\t}\n\n\tprivate String getOrDeducePassword(SecurityProperties.User user, @Nullable PasswordEncoder encoder) {\n\t\tString password = user.getPassword();\n\t\tif (user.isPasswordGenerated()) {\n\t\t\tlogger.warn(String.format(\n\t\t\t\t\t\"%n%nUsing generated security password: %s%n%nThis generated password is for development use only. \"\n\t\t\t\t\t\t\t+ \"Your security configuration must be updated before running your application in \"\n\t\t\t\t\t\t\t+ \"production.%n\",\n\t\t\t\t\tuser.getPassword()));\n\t\t}\n\t\tif (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {\n\t\t\treturn password;\n\t\t}\n\t\treturn NOOP_PASSWORD_PREFIX + password;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/reactive/EndpointRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.reactive;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.security.web.reactive.ApplicationContextServerWebExchangeMatcher;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Factory that can be used to create a {@link ServerWebExchangeMatcher} for actuator\n * endpoint locations.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Chris Bono\n * @since 4.0.0\n */\npublic final class EndpointRequest {\n\n\tprivate static final ServerWebExchangeMatcher EMPTY_MATCHER = (request) -> MatchResult.notMatch();\n\n\tprivate EndpointRequest() {\n\t}\n\n\t/**\n\t * Returns a matcher that includes all {@link Endpoint actuator endpoints} and\n\t * everything beneath them. It also includes the links endpoint which is present at\n\t * the base path of the actuator endpoints. The\n\t * {@link EndpointServerWebExchangeMatcher#excluding(Class...) excluding} method can\n\t * be used to further remove specific endpoints if required. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toAnyEndpoint().excluding(ShutdownEndpoint.class)\n\t * </pre>\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic static EndpointServerWebExchangeMatcher toAnyEndpoint() {\n\t\treturn new EndpointServerWebExchangeMatcher(true);\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link Endpoint actuator endpoints}\n\t * everything beneath them. For example: <pre class=\"code\">\n\t * EndpointRequest.to(ShutdownEndpoint.class, HealthEndpoint.class)\n\t * </pre>\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic static EndpointServerWebExchangeMatcher to(Class<?>... endpoints) {\n\t\treturn new EndpointServerWebExchangeMatcher(endpoints, false);\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link Endpoint actuator endpoints}\n\t * everything beneath them. For example: <pre class=\"code\">\n\t * EndpointRequest.to(\"shutdown\", \"health\")\n\t * </pre>\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic static EndpointServerWebExchangeMatcher to(String... endpoints) {\n\t\treturn new EndpointServerWebExchangeMatcher(endpoints, false);\n\t}\n\n\t/**\n\t * Returns a matcher that matches only on the links endpoint. It can be used when\n\t * security configuration for the links endpoint is different from the other\n\t * {@link Endpoint actuator endpoints}. The\n\t * {@link EndpointServerWebExchangeMatcher#excludingLinks() excludingLinks} method can\n\t * be used in combination with this to remove the links endpoint from\n\t * {@link EndpointRequest#toAnyEndpoint() toAnyEndpoint}. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toLinks()\n\t * </pre>\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic static LinksServerWebExchangeMatcher toLinks() {\n\t\treturn new LinksServerWebExchangeMatcher();\n\t}\n\n\t/**\n\t * Returns a matcher that includes additional paths under a {@link WebServerNamespace}\n\t * for the specified {@link Endpoint actuator endpoints}. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, \"health\")\n\t * </pre>\n\t * @param webServerNamespace the web server namespace\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static AdditionalPathsEndpointServerWebExchangeMatcher toAdditionalPaths(\n\t\t\tWebServerNamespace webServerNamespace, Class<?>... endpoints) {\n\t\treturn new AdditionalPathsEndpointServerWebExchangeMatcher(webServerNamespace, endpoints);\n\t}\n\n\t/**\n\t * Returns a matcher that includes additional paths under a {@link WebServerNamespace}\n\t * for the specified {@link Endpoint actuator endpoints}. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, HealthEndpoint.class)\n\t * </pre>\n\t * @param webServerNamespace the web server namespace\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static AdditionalPathsEndpointServerWebExchangeMatcher toAdditionalPaths(\n\t\t\tWebServerNamespace webServerNamespace, String... endpoints) {\n\t\treturn new AdditionalPathsEndpointServerWebExchangeMatcher(webServerNamespace, endpoints);\n\t}\n\n\t/**\n\t * Base class for supported request matchers.\n\t */\n\tprivate abstract static class AbstractWebExchangeMatcher<C> extends ApplicationContextServerWebExchangeMatcher<C> {\n\n\t\tprivate volatile @Nullable ServerWebExchangeMatcher delegate;\n\n\t\tprivate volatile @Nullable ManagementPortType managementPortType;\n\n\t\tAbstractWebExchangeMatcher(Class<? extends C> contextClass) {\n\t\t\tsuper(contextClass);\n\t\t}\n\n\t\t@Override\n\t\tprotected void initialized(Supplier<C> supplier) {\n\t\t\tthis.delegate = createDelegate(supplier);\n\t\t}\n\n\t\tprivate ServerWebExchangeMatcher createDelegate(Supplier<C> context) {\n\t\t\ttry {\n\t\t\t\treturn createDelegate(context.get());\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn EMPTY_MATCHER;\n\t\t\t}\n\t\t}\n\n\t\tprotected abstract ServerWebExchangeMatcher createDelegate(C context);\n\n\t\tprotected final List<ServerWebExchangeMatcher> getDelegateMatchers(Set<String> paths,\n\t\t\t\t@Nullable HttpMethod httpMethod) {\n\t\t\treturn paths.stream()\n\t\t\t\t.map((path) -> getDelegateMatcher(path, httpMethod))\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t}\n\n\t\tprivate PathPatternParserServerWebExchangeMatcher getDelegateMatcher(String path,\n\t\t\t\t@Nullable HttpMethod httpMethod) {\n\t\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\t\treturn new PathPatternParserServerWebExchangeMatcher(path + \"/**\", httpMethod);\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<MatchResult> matches(ServerWebExchange exchange, Supplier<C> context) {\n\t\t\tServerWebExchangeMatcher delegate = this.delegate;\n\t\t\tAssert.state(delegate != null, \"'delegate' must not be null\");\n\t\t\treturn delegate.matches(exchange);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean ignoreApplicationContext(@Nullable ApplicationContext applicationContext) {\n\t\t\tManagementPortType managementPortType = this.managementPortType;\n\t\t\tif (managementPortType == null) {\n\t\t\t\tAssert.state(applicationContext != null, \"'applicationContext' must not be null\");\n\t\t\t\tmanagementPortType = ManagementPortType.get(applicationContext.getEnvironment());\n\t\t\t\tthis.managementPortType = managementPortType;\n\t\t\t}\n\t\t\treturn ignoreApplicationContext(applicationContext, managementPortType);\n\t\t}\n\n\t\tprotected boolean ignoreApplicationContext(@Nullable ApplicationContext applicationContext,\n\t\t\t\tManagementPortType managementPortType) {\n\t\t\treturn managementPortType == ManagementPortType.DIFFERENT\n\t\t\t\t\t&& !hasWebServerNamespace(applicationContext, WebServerNamespace.MANAGEMENT);\n\t\t}\n\n\t\tprotected final boolean hasWebServerNamespace(@Nullable ApplicationContext applicationContext,\n\t\t\t\tWebServerNamespace webServerNamespace) {\n\t\t\treturn hasServerNamespace(applicationContext, webServerNamespace.getValue())\n\t\t\t\t\t|| hasImplicitServerNamespace(applicationContext, webServerNamespace);\n\t\t}\n\n\t\tprivate boolean hasImplicitServerNamespace(@Nullable ApplicationContext applicationContext,\n\t\t\t\tWebServerNamespace webServerNamespace) {\n\t\t\treturn WebServerNamespace.SERVER.equals(webServerNamespace)\n\t\t\t\t\t&& getServerNamespace(applicationContext) == null\n\t\t\t\t\t&& getApplicationContextParent(applicationContext) == null;\n\t\t}\n\n\t\tprivate @Nullable ApplicationContext getApplicationContextParent(\n\t\t\t\t@Nullable ApplicationContext applicationContext) {\n\t\t\treturn (applicationContext != null) ? applicationContext.getParent() : null;\n\t\t}\n\n\t\tprotected final @Nullable String getLinksPath(String basePath) {\n\t\t\tif (StringUtils.hasText(basePath)) {\n\t\t\t\treturn basePath;\n\t\t\t}\n\t\t\treturn (this.managementPortType == ManagementPortType.DIFFERENT) ? \"/\" : null;\n\t\t}\n\n\t\tprotected final String toString(List<Object> endpoints, String emptyValue) {\n\t\t\treturn (!endpoints.isEmpty()) ? endpoints.stream()\n\t\t\t\t.map(this::getEndpointId)\n\t\t\t\t.map(Object::toString)\n\t\t\t\t.collect(Collectors.joining(\", \", \"[\", \"]\")) : emptyValue;\n\t\t}\n\n\t\tprotected final EndpointId getEndpointId(Object source) {\n\t\t\tif (source instanceof EndpointId endpointId) {\n\t\t\t\treturn endpointId;\n\t\t\t}\n\t\t\tif (source instanceof String string) {\n\t\t\t\treturn EndpointId.of(string);\n\t\t\t}\n\t\t\tif (source instanceof Class) {\n\t\t\t\treturn getEndpointId((Class<?>) source);\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unsupported source \" + source);\n\t\t}\n\n\t\tprivate EndpointId getEndpointId(Class<?> source) {\n\t\t\tMergedAnnotation<Endpoint> annotation = MergedAnnotations.from(source).get(Endpoint.class);\n\t\t\tAssert.state(annotation.isPresent(), () -> \"Class \" + source + \" is not annotated with @Endpoint\");\n\t\t\treturn EndpointId.of(annotation.getString(\"id\"));\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@link ServerWebExchangeMatcher} used to match against {@link Endpoint actuator\n\t * endpoints}.\n\t */\n\tpublic static final class EndpointServerWebExchangeMatcher extends AbstractWebExchangeMatcher<PathMappedEndpoints> {\n\n\t\tprivate final List<Object> includes;\n\n\t\tprivate final List<Object> excludes;\n\n\t\tprivate final boolean includeLinks;\n\n\t\tprivate final @Nullable HttpMethod httpMethod;\n\n\t\tprivate EndpointServerWebExchangeMatcher(boolean includeLinks) {\n\t\t\tthis(Collections.emptyList(), Collections.emptyList(), includeLinks, null);\n\t\t}\n\n\t\tprivate EndpointServerWebExchangeMatcher(Class<?>[] endpoints, boolean includeLinks) {\n\t\t\tthis(Arrays.asList((Object[]) endpoints), Collections.emptyList(), includeLinks, null);\n\t\t}\n\n\t\tprivate EndpointServerWebExchangeMatcher(String[] endpoints, boolean includeLinks) {\n\t\t\tthis(Arrays.asList((Object[]) endpoints), Collections.emptyList(), includeLinks, null);\n\t\t}\n\n\t\tprivate EndpointServerWebExchangeMatcher(List<Object> includes, List<Object> excludes, boolean includeLinks,\n\t\t\t\t@Nullable HttpMethod httpMethod) {\n\t\t\tsuper(PathMappedEndpoints.class);\n\t\t\tthis.includes = includes;\n\t\t\tthis.excludes = excludes;\n\t\t\tthis.includeLinks = includeLinks;\n\t\t\tthis.httpMethod = httpMethod;\n\t\t}\n\n\t\tpublic EndpointServerWebExchangeMatcher excluding(Class<?>... endpoints) {\n\t\t\tList<Object> excludes = new ArrayList<>(this.excludes);\n\t\t\texcludes.addAll(Arrays.asList((Object[]) endpoints));\n\t\t\treturn new EndpointServerWebExchangeMatcher(this.includes, excludes, this.includeLinks, null);\n\t\t}\n\n\t\tpublic EndpointServerWebExchangeMatcher excluding(String... endpoints) {\n\t\t\tList<Object> excludes = new ArrayList<>(this.excludes);\n\t\t\texcludes.addAll(Arrays.asList((Object[]) endpoints));\n\t\t\treturn new EndpointServerWebExchangeMatcher(this.includes, excludes, this.includeLinks, null);\n\t\t}\n\n\t\tpublic EndpointServerWebExchangeMatcher excludingLinks() {\n\t\t\treturn new EndpointServerWebExchangeMatcher(this.includes, this.excludes, false, null);\n\t\t}\n\n\t\t/**\n\t\t * Restricts the matcher to only consider requests with a particular http method.\n\t\t * @param httpMethod the http method to include\n\t\t * @return a copy of the matcher further restricted to only match requests with\n\t\t * the specified http method\n\t\t */\n\t\tpublic EndpointServerWebExchangeMatcher withHttpMethod(HttpMethod httpMethod) {\n\t\t\treturn new EndpointServerWebExchangeMatcher(this.includes, this.excludes, this.includeLinks, httpMethod);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchangeMatcher createDelegate(PathMappedEndpoints endpoints) {\n\t\t\tSet<String> paths = new LinkedHashSet<>();\n\t\t\tif (this.includes.isEmpty()) {\n\t\t\t\tpaths.addAll(endpoints.getAllPaths());\n\t\t\t}\n\t\t\tstreamPaths(this.includes, endpoints).forEach(paths::add);\n\t\t\tstreamPaths(this.excludes, endpoints).forEach(paths::remove);\n\t\t\tList<ServerWebExchangeMatcher> delegateMatchers = getDelegateMatchers(paths, this.httpMethod);\n\t\t\tString linksPath = getLinksPath(endpoints.getBasePath());\n\t\t\tif (this.includeLinks && linksPath != null) {\n\t\t\t\tdelegateMatchers.add(new LinksServerWebExchangeMatcher());\n\t\t\t}\n\t\t\tif (delegateMatchers.isEmpty()) {\n\t\t\t\treturn EMPTY_MATCHER;\n\t\t\t}\n\t\t\treturn new OrServerWebExchangeMatcher(delegateMatchers);\n\t\t}\n\n\t\tprivate Stream<String> streamPaths(List<Object> source, PathMappedEndpoints endpoints) {\n\t\t\treturn source.stream()\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.map(this::getEndpointId)\n\t\t\t\t.map(endpoints::getPath)\n\t\t\t\t.filter(Objects::nonNull);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"EndpointRequestMatcher includes=%s, excludes=%s, includeLinks=%s\",\n\t\t\t\t\ttoString(this.includes, \"[*]\"), toString(this.excludes, \"[]\"), this.includeLinks);\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@link ServerWebExchangeMatcher} used to match against the links endpoint.\n\t */\n\tpublic static final class LinksServerWebExchangeMatcher extends AbstractWebExchangeMatcher<WebEndpointProperties> {\n\n\t\tprivate LinksServerWebExchangeMatcher() {\n\t\t\tsuper(WebEndpointProperties.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchangeMatcher createDelegate(WebEndpointProperties properties) {\n\t\t\tString linksPath = getLinksPath(properties.getBasePath());\n\t\t\tif (linksPath != null) {\n\t\t\t\tList<ServerWebExchangeMatcher> linksMatchers = new ArrayList<>();\n\t\t\t\tlinksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath));\n\t\t\t\tif (!linksPath.endsWith(\"/\")) {\n\t\t\t\t\tlinksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath + \"/\"));\n\t\t\t\t}\n\t\t\t\treturn new OrServerWebExchangeMatcher(linksMatchers);\n\t\t\t}\n\t\t\treturn EMPTY_MATCHER;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"LinksServerWebExchangeMatcher\");\n\t\t}\n\n\t}\n\n\t/**\n\t * The {@link ServerWebExchangeMatcher} used to match against additional paths for\n\t * {@link Endpoint actuator endpoints}.\n\t */\n\tpublic static class AdditionalPathsEndpointServerWebExchangeMatcher\n\t\t\textends AbstractWebExchangeMatcher<PathMappedEndpoints> {\n\n\t\tprivate final WebServerNamespace webServerNamespace;\n\n\t\tprivate final List<Object> endpoints;\n\n\t\tprivate final @Nullable HttpMethod httpMethod;\n\n\t\tAdditionalPathsEndpointServerWebExchangeMatcher(WebServerNamespace webServerNamespace, String... endpoints) {\n\t\t\tthis(webServerNamespace, Arrays.asList((Object[]) endpoints), null);\n\t\t}\n\n\t\tAdditionalPathsEndpointServerWebExchangeMatcher(WebServerNamespace webServerNamespace, Class<?>... endpoints) {\n\t\t\tthis(webServerNamespace, Arrays.asList((Object[]) endpoints), null);\n\t\t}\n\n\t\tprivate AdditionalPathsEndpointServerWebExchangeMatcher(WebServerNamespace webServerNamespace,\n\t\t\t\tList<Object> endpoints, @Nullable HttpMethod httpMethod) {\n\t\t\tsuper(PathMappedEndpoints.class);\n\t\t\tAssert.notNull(webServerNamespace, \"'webServerNamespace' must not be null\");\n\t\t\tAssert.notNull(endpoints, \"'endpoints' must not be null\");\n\t\t\tAssert.notEmpty(endpoints, \"'endpoints' must not be empty\");\n\t\t\tthis.webServerNamespace = webServerNamespace;\n\t\t\tthis.endpoints = endpoints;\n\t\t\tthis.httpMethod = httpMethod;\n\t\t}\n\n\t\t/**\n\t\t * Restricts the matcher to only consider requests with a particular HTTP method.\n\t\t * @param httpMethod the HTTP method to include\n\t\t * @return a copy of the matcher further restricted to only match requests with\n\t\t * the specified HTTP method\n\t\t */\n\t\tpublic AdditionalPathsEndpointServerWebExchangeMatcher withHttpMethod(HttpMethod httpMethod) {\n\t\t\treturn new AdditionalPathsEndpointServerWebExchangeMatcher(this.webServerNamespace, this.endpoints,\n\t\t\t\t\thttpMethod);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean ignoreApplicationContext(@Nullable ApplicationContext applicationContext,\n\t\t\t\tManagementPortType managementPortType) {\n\t\t\treturn !hasWebServerNamespace(applicationContext, this.webServerNamespace);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchangeMatcher createDelegate(PathMappedEndpoints endpoints) {\n\t\t\tList<ServerWebExchangeMatcher> delegateMatchers = this.endpoints.stream()\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.map(this::getEndpointId)\n\t\t\t\t.flatMap((endpointId) -> streamAdditionalPaths(endpoints, endpointId))\n\t\t\t\t.map(PathPatternParserServerWebExchangeMatcher::new)\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t\treturn (!CollectionUtils.isEmpty(delegateMatchers)) ? new OrServerWebExchangeMatcher(delegateMatchers)\n\t\t\t\t\t: EMPTY_MATCHER;\n\t\t}\n\n\t\tprivate Stream<String> streamAdditionalPaths(PathMappedEndpoints pathMappedEndpoints, EndpointId endpointId) {\n\t\t\treturn pathMappedEndpoints.getAdditionalPaths(this.webServerNamespace, endpointId).stream();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"AdditionalPathsEndpointServerWebExchangeMatcher endpoints=%s, webServerNamespace=%s\",\n\t\t\t\t\ttoString(this.endpoints, \"\"), this.webServerNamespace);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/reactive/ReactiveManagementWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.reactive;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.SecurityWebFiltersOrder;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.core.userdetails.ReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterChainProxy;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.web.cors.reactive.PreFlightRequestHandler;\nimport org.springframework.web.cors.reactive.PreFlightRequestWebFilter;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Reactive Spring Security when\n * actuator is on the classpath. Specifically, it permits access to the health endpoint\n * while securing everything else.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(before = ReactiveWebSecurityAutoConfiguration.class,\n\t\tafterName = { \"org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration\" })\n@ConditionalOnClass({ EnableWebFluxSecurity.class, WebFilterChainProxy.class, WebEndpointAutoConfiguration.class })\n@ConditionalOnMissingBean({ SecurityWebFilterChain.class, WebFilterChainProxy.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\npublic final class ReactiveManagementWebSecurityAutoConfiguration {\n\n\t@Bean\n\tSecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, PreFlightRequestHandler handler) {\n\t\thttp.authorizeExchange((exchanges) -> {\n\t\t\texchanges.matchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll();\n\t\t\texchanges.anyExchange().authenticated();\n\t\t});\n\t\tPreFlightRequestWebFilter filter = new PreFlightRequestWebFilter(handler);\n\t\thttp.addFilterAt(filter, SecurityWebFiltersOrder.CORS);\n\t\thttp.httpBasic(withDefaults());\n\t\thttp.formLogin(withDefaults());\n\t\treturn http.build();\n\t}\n\n\tprivate ServerWebExchangeMatcher healthMatcher() {\n\t\treturn EndpointRequest.to(HealthEndpoint.class);\n\t}\n\n\tprivate ServerWebExchangeMatcher additionalHealthPathsMatcher() {\n\t\treturn EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, HealthEndpoint.class);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean({ ReactiveAuthenticationManager.class, ReactiveUserDetailsService.class })\n\tReactiveAuthenticationManager denyAllAuthenticationManager() {\n\t\treturn (authentication) -> Mono.error(new UsernameNotFoundException(authentication.getName()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator security using WebFlux.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.actuate.web.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/EndpointRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.security.web.util.matcher.OrRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Factory that can be used to create a {@link RequestMatcher} for actuator endpoint\n * locations.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Chris Bono\n * @since 4.0.0\n */\npublic final class EndpointRequest {\n\n\tprivate static final RequestMatcher EMPTY_MATCHER = (request) -> false;\n\n\tprivate EndpointRequest() {\n\t}\n\n\t/**\n\t * Returns a matcher that includes all {@link Endpoint actuator endpoints} and\n\t * everything beneath them. It also includes the links endpoint which is present at\n\t * the base path of the actuator endpoints. The\n\t * {@link EndpointRequestMatcher#excluding(Class...) excluding} method can be used to\n\t * further remove specific endpoints if required. For example: <pre class=\"code\">\n\t * EndpointRequest.toAnyEndpoint().excluding(ShutdownEndpoint.class)\n\t * </pre>\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static EndpointRequestMatcher toAnyEndpoint() {\n\t\treturn new EndpointRequestMatcher(true);\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link Endpoint actuator endpoints}\n\t * and everything beneath them. For example: <pre class=\"code\">\n\t * EndpointRequest.to(ShutdownEndpoint.class, HealthEndpoint.class)\n\t * </pre>\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static EndpointRequestMatcher to(Class<?>... endpoints) {\n\t\treturn new EndpointRequestMatcher(endpoints, false);\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link Endpoint actuator endpoints}\n\t * and everything beneath them. For example: <pre class=\"code\">\n\t * EndpointRequest.to(\"shutdown\", \"health\")\n\t * </pre>\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static EndpointRequestMatcher to(String... endpoints) {\n\t\treturn new EndpointRequestMatcher(endpoints, false);\n\t}\n\n\t/**\n\t * Returns a matcher that matches only on the links endpoint. It can be used when\n\t * security configuration for the links endpoint is different from the other\n\t * {@link Endpoint actuator endpoints}. The\n\t * {@link EndpointRequestMatcher#excludingLinks() excludingLinks} method can be used\n\t * in combination with this to remove the links endpoint from\n\t * {@link EndpointRequest#toAnyEndpoint() toAnyEndpoint}. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toLinks()\n\t * </pre>\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static LinksRequestMatcher toLinks() {\n\t\treturn new LinksRequestMatcher();\n\t}\n\n\t/**\n\t * Returns a matcher that includes additional paths under a {@link WebServerNamespace}\n\t * for the specified {@link Endpoint actuator endpoints}. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, \"health\")\n\t * </pre>\n\t * @param webServerNamespace the web server namespace\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static AdditionalPathsEndpointRequestMatcher toAdditionalPaths(WebServerNamespace webServerNamespace,\n\t\t\tClass<?>... endpoints) {\n\t\treturn new AdditionalPathsEndpointRequestMatcher(webServerNamespace, endpoints);\n\t}\n\n\t/**\n\t * Returns a matcher that includes additional paths under a {@link WebServerNamespace}\n\t * for the specified {@link Endpoint actuator endpoints}. For example:\n\t * <pre class=\"code\">\n\t * EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, HealthEndpoint.class)\n\t * </pre>\n\t * @param webServerNamespace the web server namespace\n\t * @param endpoints the endpoints to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static AdditionalPathsEndpointRequestMatcher toAdditionalPaths(WebServerNamespace webServerNamespace,\n\t\t\tString... endpoints) {\n\t\treturn new AdditionalPathsEndpointRequestMatcher(webServerNamespace, endpoints);\n\t}\n\n\t/**\n\t * Base class for supported request matchers.\n\t */\n\tprivate abstract static class AbstractRequestMatcher\n\t\t\textends ApplicationContextRequestMatcher<WebApplicationContext> {\n\n\t\tprivate volatile @Nullable RequestMatcher delegate;\n\n\t\tprivate volatile @Nullable ManagementPortType managementPortType;\n\n\t\tAbstractRequestMatcher() {\n\t\t\tsuper(WebApplicationContext.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {\n\t\t\tManagementPortType managementPortType = this.managementPortType;\n\t\t\tif (managementPortType == null) {\n\t\t\t\tmanagementPortType = ManagementPortType.get(applicationContext.getEnvironment());\n\t\t\t\tthis.managementPortType = managementPortType;\n\t\t\t}\n\t\t\treturn ignoreApplicationContext(applicationContext, managementPortType);\n\t\t}\n\n\t\tprotected boolean ignoreApplicationContext(WebApplicationContext applicationContext,\n\t\t\t\tManagementPortType managementPortType) {\n\t\t\treturn managementPortType == ManagementPortType.DIFFERENT\n\t\t\t\t\t&& !hasWebServerNamespace(applicationContext, WebServerNamespace.MANAGEMENT);\n\t\t}\n\n\t\tprotected final boolean hasWebServerNamespace(ApplicationContext applicationContext,\n\t\t\t\tWebServerNamespace webServerNamespace) {\n\t\t\treturn hasServerNamespace(applicationContext, webServerNamespace.getValue())\n\t\t\t\t\t|| hasImplicitServerNamespace(applicationContext, webServerNamespace);\n\t\t}\n\n\t\tprivate boolean hasImplicitServerNamespace(ApplicationContext applicationContext,\n\t\t\t\tWebServerNamespace webServerNamespace) {\n\t\t\treturn WebServerNamespace.SERVER.equals(webServerNamespace)\n\t\t\t\t\t&& getServerNamespace(applicationContext) == null && applicationContext.getParent() == null;\n\t\t}\n\n\t\t@Override\n\t\tprotected final void initialized(Supplier<WebApplicationContext> context) {\n\t\t\tthis.delegate = createDelegate(context.get());\n\t\t}\n\n\t\t@Override\n\t\tprotected final boolean matches(HttpServletRequest request, Supplier<WebApplicationContext> context) {\n\t\t\tRequestMatcher delegate = this.delegate;\n\t\t\tAssert.state(delegate != null, \"'delegate' must not be null\");\n\t\t\treturn delegate.matches(request);\n\t\t}\n\n\t\tprivate RequestMatcher createDelegate(WebApplicationContext context) {\n\t\t\ttry {\n\t\t\t\treturn createDelegate(context, new RequestMatcherFactory());\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn EMPTY_MATCHER;\n\t\t\t}\n\t\t}\n\n\t\tprotected abstract RequestMatcher createDelegate(WebApplicationContext context,\n\t\t\t\tRequestMatcherFactory requestMatcherFactory);\n\n\t\tprotected final List<RequestMatcher> getDelegateMatchers(RequestMatcherFactory requestMatcherFactory,\n\t\t\t\tRequestMatcherProvider matcherProvider, Set<String> paths, @Nullable HttpMethod httpMethod) {\n\t\t\treturn paths.stream()\n\t\t\t\t.map((path) -> requestMatcherFactory.antPath(matcherProvider, httpMethod, path, \"/**\"))\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t}\n\n\t\tprotected List<RequestMatcher> getLinksMatchers(RequestMatcherFactory requestMatcherFactory,\n\t\t\t\tRequestMatcherProvider matcherProvider, String linksPath) {\n\t\t\tList<RequestMatcher> linksMatchers = new ArrayList<>();\n\t\t\tlinksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, linksPath));\n\t\t\tif (!linksPath.endsWith(\"/\")) {\n\t\t\t\tlinksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, linksPath, \"/\"));\n\t\t\t}\n\t\t\treturn linksMatchers;\n\t\t}\n\n\t\tprotected @Nullable String getLinksPath(WebApplicationContext context, String basePath) {\n\t\t\tif (StringUtils.hasText(basePath)) {\n\t\t\t\treturn basePath;\n\t\t\t}\n\t\t\tManagementPortType managementPortType = this.managementPortType;\n\t\t\tif (managementPortType == null) {\n\t\t\t\tmanagementPortType = ManagementPortType.get(context.getEnvironment());\n\t\t\t\tthis.managementPortType = managementPortType;\n\t\t\t}\n\t\t\treturn (managementPortType == ManagementPortType.DIFFERENT) ? \"/\" : null;\n\t\t}\n\n\t\tprotected RequestMatcherProvider getRequestMatcherProvider(WebApplicationContext context) {\n\t\t\ttry {\n\t\t\t\treturn context.getBean(RequestMatcherProvider.class);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn (pattern, method) -> PathPatternRequestMatcher.withDefaults().matcher(method, pattern);\n\t\t\t}\n\t\t}\n\n\t\tprotected String toString(List<Object> endpoints, String emptyValue) {\n\t\t\treturn (!endpoints.isEmpty()) ? endpoints.stream()\n\t\t\t\t.map(this::getEndpointId)\n\t\t\t\t.map(Object::toString)\n\t\t\t\t.collect(Collectors.joining(\", \", \"[\", \"]\")) : emptyValue;\n\t\t}\n\n\t\tprotected EndpointId getEndpointId(Object source) {\n\t\t\tif (source instanceof EndpointId endpointId) {\n\t\t\t\treturn endpointId;\n\t\t\t}\n\t\t\tif (source instanceof String string) {\n\t\t\t\treturn EndpointId.of(string);\n\t\t\t}\n\t\t\tif (source instanceof Class<?> sourceClass) {\n\t\t\t\treturn getEndpointId(sourceClass);\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unsupported source \" + source);\n\t\t}\n\n\t\tprivate EndpointId getEndpointId(Class<?> source) {\n\t\t\tMergedAnnotation<Endpoint> annotation = MergedAnnotations.from(source).get(Endpoint.class);\n\t\t\tAssert.state(annotation.isPresent(), () -> \"Class \" + source + \" is not annotated with @Endpoint\");\n\t\t\treturn EndpointId.of(annotation.getString(\"id\"));\n\t\t}\n\n\t}\n\n\t/**\n\t * The request matcher used to match against {@link Endpoint actuator endpoints}.\n\t */\n\tpublic static final class EndpointRequestMatcher extends AbstractRequestMatcher {\n\n\t\tprivate final List<Object> includes;\n\n\t\tprivate final List<Object> excludes;\n\n\t\tprivate final boolean includeLinks;\n\n\t\tprivate final @Nullable HttpMethod httpMethod;\n\n\t\tprivate EndpointRequestMatcher(boolean includeLinks) {\n\t\t\tthis(Collections.emptyList(), Collections.emptyList(), includeLinks, null);\n\t\t}\n\n\t\tprivate EndpointRequestMatcher(Class<?>[] endpoints, boolean includeLinks) {\n\t\t\tthis(Arrays.asList((Object[]) endpoints), Collections.emptyList(), includeLinks, null);\n\t\t}\n\n\t\tprivate EndpointRequestMatcher(String[] endpoints, boolean includeLinks) {\n\t\t\tthis(Arrays.asList((Object[]) endpoints), Collections.emptyList(), includeLinks, null);\n\t\t}\n\n\t\tprivate EndpointRequestMatcher(List<Object> includes, List<Object> excludes, boolean includeLinks,\n\t\t\t\t@Nullable HttpMethod httpMethod) {\n\t\t\tthis.includes = includes;\n\t\t\tthis.excludes = excludes;\n\t\t\tthis.includeLinks = includeLinks;\n\t\t\tthis.httpMethod = httpMethod;\n\t\t}\n\n\t\tpublic EndpointRequestMatcher excluding(Class<?>... endpoints) {\n\t\t\tList<Object> excludes = new ArrayList<>(this.excludes);\n\t\t\texcludes.addAll(Arrays.asList((Object[]) endpoints));\n\t\t\treturn new EndpointRequestMatcher(this.includes, excludes, this.includeLinks, null);\n\t\t}\n\n\t\tpublic EndpointRequestMatcher excluding(String... endpoints) {\n\t\t\tList<Object> excludes = new ArrayList<>(this.excludes);\n\t\t\texcludes.addAll(Arrays.asList((Object[]) endpoints));\n\t\t\treturn new EndpointRequestMatcher(this.includes, excludes, this.includeLinks, null);\n\t\t}\n\n\t\tpublic EndpointRequestMatcher excludingLinks() {\n\t\t\treturn new EndpointRequestMatcher(this.includes, this.excludes, false, null);\n\t\t}\n\n\t\t/**\n\t\t * Restricts the matcher to only consider requests with a particular HTTP method.\n\t\t * @param httpMethod the HTTP method to include\n\t\t * @return a copy of the matcher further restricted to only match requests with\n\t\t * the specified HTTP method\n\t\t */\n\t\tpublic EndpointRequestMatcher withHttpMethod(HttpMethod httpMethod) {\n\t\t\treturn new EndpointRequestMatcher(this.includes, this.excludes, this.includeLinks, httpMethod);\n\t\t}\n\n\t\t@Override\n\t\tprotected RequestMatcher createDelegate(WebApplicationContext context,\n\t\t\t\tRequestMatcherFactory requestMatcherFactory) {\n\t\t\tPathMappedEndpoints endpoints = context.getBean(PathMappedEndpoints.class);\n\t\t\tRequestMatcherProvider matcherProvider = getRequestMatcherProvider(context);\n\t\t\tSet<String> paths = new LinkedHashSet<>();\n\t\t\tif (this.includes.isEmpty()) {\n\t\t\t\tpaths.addAll(endpoints.getAllPaths());\n\t\t\t}\n\t\t\tstreamPaths(this.includes, endpoints).forEach(paths::add);\n\t\t\tstreamPaths(this.excludes, endpoints).forEach(paths::remove);\n\t\t\tList<RequestMatcher> delegateMatchers = getDelegateMatchers(requestMatcherFactory, matcherProvider, paths,\n\t\t\t\t\tthis.httpMethod);\n\t\t\tString basePath = endpoints.getBasePath();\n\t\t\tString linksPath = getLinksPath(context, basePath);\n\t\t\tif (this.includeLinks && linksPath != null) {\n\t\t\t\tdelegateMatchers.addAll(getLinksMatchers(requestMatcherFactory, matcherProvider, linksPath));\n\t\t\t}\n\t\t\tif (delegateMatchers.isEmpty()) {\n\t\t\t\treturn EMPTY_MATCHER;\n\t\t\t}\n\t\t\treturn new OrRequestMatcher(delegateMatchers);\n\t\t}\n\n\t\tprivate Stream<String> streamPaths(List<Object> source, PathMappedEndpoints endpoints) {\n\t\t\treturn source.stream()\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.map(this::getEndpointId)\n\t\t\t\t.map(endpoints::getPath)\n\t\t\t\t.filter(Objects::nonNull);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"EndpointRequestMatcher includes=%s, excludes=%s, includeLinks=%s\",\n\t\t\t\t\ttoString(this.includes, \"[*]\"), toString(this.excludes, \"[]\"), this.includeLinks);\n\t\t}\n\n\t}\n\n\t/**\n\t * The request matcher used to match against the links endpoint.\n\t */\n\tpublic static final class LinksRequestMatcher extends AbstractRequestMatcher {\n\n\t\t@Override\n\t\tprotected RequestMatcher createDelegate(WebApplicationContext context,\n\t\t\t\tRequestMatcherFactory requestMatcherFactory) {\n\t\t\tWebEndpointProperties properties = context.getBean(WebEndpointProperties.class);\n\t\t\tString linksPath = getLinksPath(context, properties.getBasePath());\n\t\t\tif (linksPath != null) {\n\t\t\t\treturn new OrRequestMatcher(\n\t\t\t\t\t\tgetLinksMatchers(requestMatcherFactory, getRequestMatcherProvider(context), linksPath));\n\t\t\t}\n\t\t\treturn EMPTY_MATCHER;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"LinksRequestMatcher\");\n\t\t}\n\n\t}\n\n\t/**\n\t * The request matcher used to match against additional paths for {@link Endpoint\n\t * actuator endpoints}.\n\t */\n\tpublic static class AdditionalPathsEndpointRequestMatcher extends AbstractRequestMatcher {\n\n\t\tprivate final WebServerNamespace webServerNamespace;\n\n\t\tprivate final List<Object> endpoints;\n\n\t\tprivate final @Nullable HttpMethod httpMethod;\n\n\t\tAdditionalPathsEndpointRequestMatcher(WebServerNamespace webServerNamespace, String... endpoints) {\n\t\t\tthis(webServerNamespace, Arrays.asList((Object[]) endpoints), null);\n\t\t}\n\n\t\tAdditionalPathsEndpointRequestMatcher(WebServerNamespace webServerNamespace, Class<?>... endpoints) {\n\t\t\tthis(webServerNamespace, Arrays.asList((Object[]) endpoints), null);\n\t\t}\n\n\t\tprivate AdditionalPathsEndpointRequestMatcher(WebServerNamespace webServerNamespace, List<Object> endpoints,\n\t\t\t\t@Nullable HttpMethod httpMethod) {\n\t\t\tAssert.notNull(webServerNamespace, \"'webServerNamespace' must not be null\");\n\t\t\tAssert.notNull(endpoints, \"'endpoints' must not be null\");\n\t\t\tAssert.notEmpty(endpoints, \"'endpoints' must not be empty\");\n\t\t\tthis.webServerNamespace = webServerNamespace;\n\t\t\tthis.endpoints = endpoints;\n\t\t\tthis.httpMethod = httpMethod;\n\t\t}\n\n\t\t/**\n\t\t * Restricts the matcher to only consider requests with a particular HTTP method.\n\t\t * @param httpMethod the HTTP method to include\n\t\t * @return a copy of the matcher further restricted to only match requests with\n\t\t * the specified HTTP method\n\t\t */\n\t\tpublic AdditionalPathsEndpointRequestMatcher withHttpMethod(HttpMethod httpMethod) {\n\t\t\treturn new AdditionalPathsEndpointRequestMatcher(this.webServerNamespace, this.endpoints, httpMethod);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean ignoreApplicationContext(WebApplicationContext applicationContext,\n\t\t\t\tManagementPortType managementPortType) {\n\t\t\treturn !hasWebServerNamespace(applicationContext, this.webServerNamespace);\n\t\t}\n\n\t\t@Override\n\t\tprotected RequestMatcher createDelegate(WebApplicationContext context,\n\t\t\t\tRequestMatcherFactory requestMatcherFactory) {\n\t\t\tPathMappedEndpoints endpoints = context.getBean(PathMappedEndpoints.class);\n\t\t\tRequestMatcherProvider matcherProvider = getRequestMatcherProvider(context);\n\t\t\tList<RequestMatcher> delegateMatchers = this.endpoints.stream()\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.map(this::getEndpointId)\n\t\t\t\t.flatMap((endpointId) -> streamAdditionalPaths(endpoints, endpointId))\n\t\t\t\t.map((path) -> requestMatcherFactory.antPath(matcherProvider, this.httpMethod, path))\n\t\t\t\t.collect(Collectors.toCollection(ArrayList::new));\n\t\t\treturn (!CollectionUtils.isEmpty(delegateMatchers)) ? new OrRequestMatcher(delegateMatchers)\n\t\t\t\t\t: EMPTY_MATCHER;\n\t\t}\n\n\t\tprivate Stream<String> streamAdditionalPaths(PathMappedEndpoints pathMappedEndpoints, EndpointId endpointId) {\n\t\t\treturn pathMappedEndpoints.getAdditionalPaths(this.webServerNamespace, endpointId).stream();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn String.format(\"AdditionalPathsEndpointRequestMatcher endpoints=%s, webServerNamespace=%s\",\n\t\t\t\t\ttoString(this.endpoints, \"\"), this.webServerNamespace);\n\t\t}\n\n\t}\n\n\t/**\n\t * Factory used to create a {@link RequestMatcher}.\n\t */\n\tprivate static final class RequestMatcherFactory {\n\n\t\tRequestMatcher antPath(RequestMatcherProvider matcherProvider, @Nullable HttpMethod httpMethod,\n\t\t\t\tString... parts) {\n\t\t\tStringBuilder pattern = new StringBuilder();\n\t\t\tfor (String part : parts) {\n\t\t\t\tAssert.notNull(part, \"'part' must not be null\");\n\t\t\t\tpattern.append(part);\n\t\t\t}\n\t\t\treturn matcherProvider.getRequestMatcher(pattern.toString(), httpMethod);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/ManagementWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.ClassUtils;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security when actuator is\n * on the classpath. It allows unauthenticated access to the {@link HealthEndpoint}. If\n * the user specifies their own {@link SecurityFilterChain} bean, this will back-off\n * completely and the user should specify all the bits that they want to configure as part\n * of the custom security configuration.\n *\n * @author Madhura Bhave\n * @author Hatef Palizgar\n * @since 4.0.0\n */\n@AutoConfiguration(before = ServletWebSecurityAutoConfiguration.class,\n\t\tafterName = { \"org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration\" })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ RequestMatcher.class, WebEndpointAutoConfiguration.class })\n@ConditionalOnDefaultWebSecurity\npublic final class ManagementWebSecurityAutoConfiguration {\n\n\t@Bean\n\t@Order(SecurityFilterProperties.BASIC_AUTH_ORDER)\n\tSecurityFilterChain managementSecurityFilterChain(Environment environment, HttpSecurity http) {\n\t\tif (ClassUtils.isPresent(\"org.springframework.boot.health.actuate.endpoint.HealthEndpoint\",\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(healthMatcher(), additionalHealthPathsMatcher()).permitAll();\n\t\t\t\trequests.anyRequest().authenticated();\n\t\t\t});\n\t\t}\n\t\tif (ClassUtils.isPresent(\"org.springframework.web.servlet.DispatcherServlet\", null)) {\n\t\t\thttp.cors(withDefaults());\n\t\t}\n\t\thttp.formLogin(withDefaults());\n\t\thttp.httpBasic(withDefaults());\n\t\treturn http.build();\n\t}\n\n\tprivate RequestMatcher healthMatcher() {\n\t\treturn EndpointRequest.to(HealthEndpoint.class);\n\t}\n\n\tprivate RequestMatcher additionalHealthPathsMatcher() {\n\t\treturn EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, HealthEndpoint.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/PathPatternRequestMatcherProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\n\n/**\n * {@link RequestMatcherProvider} that provides an {@link PathPatternRequestMatcher}.\n *\n * @author Madhura Bhave\n * @author Chris Bono\n */\nclass PathPatternRequestMatcherProvider implements RequestMatcherProvider {\n\n\tprivate final Function<String, String> pathFactory;\n\n\tPathPatternRequestMatcherProvider(Function<String, String> pathFactory) {\n\t\tthis.pathFactory = pathFactory;\n\t}\n\n\t@Override\n\tpublic RequestMatcher getRequestMatcher(String pattern, @Nullable HttpMethod httpMethod) {\n\t\treturn PathPatternRequestMatcher.withDefaults().matcher(httpMethod, this.pathFactory.apply(pattern));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/RequestMatcherProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\n\n/**\n * Interface that can be used to provide a {@link RequestMatcher} that can be used with\n * Spring Security.\n *\n * @author Madhura Bhave\n * @author Chris Bono\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface RequestMatcherProvider {\n\n\t/**\n\t * Return the {@link RequestMatcher} to be used for the specified pattern and http\n\t * method.\n\t * @param pattern the request pattern\n\t * @param httpMethod the http method\n\t * @return a request matcher\n\t */\n\tRequestMatcher getRequestMatcher(String pattern, @Nullable HttpMethod httpMethod);\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/SecurityRequestMatchersManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * {@link ManagementContextConfiguration} that configures the appropriate\n * {@link RequestMatcherProvider}.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ManagementContextConfiguration(proxyBeanMethods = false)\n@ConditionalOnClass({ RequestMatcher.class })\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic class SecurityRequestMatchersManagementContextConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(DispatcherServlet.class)\n\t@ConditionalOnBean(DispatcherServletPath.class)\n\tpublic static class MvcRequestMatcherConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tpublic RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {\n\t\t\treturn new PathPatternRequestMatcherProvider(servletPath::getRelativePath);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(ResourceConfig.class)\n\t@ConditionalOnMissingClass(\"org.springframework.web.servlet.DispatcherServlet\")\n\t@ConditionalOnBean(JerseyApplicationPath.class)\n\tpublic static class JerseyRequestMatcherConfiguration {\n\n\t\t@Bean\n\t\tpublic RequestMatcherProvider requestMatcherProvider(JerseyApplicationPath applicationPath) {\n\t\t\treturn new PathPatternRequestMatcherProvider(applicationPath::getRelativePath);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for actuator security using Spring MVC.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/rsocket/RSocketSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.rsocket;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketMessageHandlerCustomizer;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.rsocket.EnableRSocketSecurity;\nimport org.springframework.security.messaging.handler.invocation.reactive.AuthenticationPrincipalArgumentResolver;\nimport org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security for an RSocket\n * server.\n *\n * @author Madhura Bhave\n * @author Brian Clozel\n * @author Guirong Hu\n * @since 4.0.0\n */\n@AutoConfiguration\n@EnableRSocketSecurity\n@ConditionalOnClass({ RSocketServerCustomizer.class, SecuritySocketAcceptorInterceptor.class })\npublic final class RSocketSecurityAutoConfiguration {\n\n\t@Bean\n\tRSocketServerCustomizer springSecurityRSocketSecurity(SecuritySocketAcceptorInterceptor interceptor) {\n\t\treturn (server) -> server.interceptors((registry) -> registry.forSocketAcceptor(interceptor));\n\t}\n\n\t@ConditionalOnClass(AuthenticationPrincipalArgumentResolver.class)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RSocketSecurityMessageHandlerConfiguration {\n\n\t\t@Bean\n\t\tRSocketMessageHandlerCustomizer rSocketAuthenticationPrincipalMessageHandlerCustomizer() {\n\t\t\treturn (messageHandler) -> messageHandler.getArgumentResolverConfigurer()\n\t\t\t\t.addCustomResolver(new AuthenticationPrincipalArgumentResolver());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/rsocket/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for RSocket support in Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.rsocket;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/StaticResourceLocation.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web;\n\nimport java.util.Arrays;\nimport java.util.stream.Stream;\n\n/**\n * Common locations for static resources.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic enum StaticResourceLocation {\n\n\t/**\n\t * Resources under {@code \"/css\"}.\n\t */\n\tCSS(\"/css/**\"),\n\n\t/**\n\t * Resources under {@code \"/js\"}.\n\t */\n\tJAVA_SCRIPT(\"/js/**\"),\n\n\t/**\n\t * Resources under {@code \"/images\"}.\n\t */\n\tIMAGES(\"/images/**\"),\n\n\t/**\n\t * Resources under {@code \"/webjars\"}.\n\t */\n\tWEB_JARS(\"/webjars/**\"),\n\n\t/**\n\t * The {@code \"favicon.ico\"} resource.\n\t */\n\tFAVICON(\"/favicon.*\", \"/*/icon-*\"),\n\n\t/**\n\t * Resources under {@code \"/fonts\"}.\n\t */\n\tFONTS(\"/fonts/**\");\n\n\tprivate final String[] patterns;\n\n\tStaticResourceLocation(String... patterns) {\n\t\tthis.patterns = patterns;\n\t}\n\n\tpublic Stream<String> getPatterns() {\n\t\treturn Arrays.stream(this.patterns);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for Spring Security web Auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/reactive/PathRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\n\n/**\n * Factory that can be used to create a {@link ServerWebExchangeMatcher} for commonly used\n * paths.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic final class PathRequest {\n\n\tprivate PathRequest() {\n\t}\n\n\t/**\n\t * Returns a {@link StaticResourceRequest} that can be used to create a matcher for\n\t * {@link StaticResourceLocation locations}.\n\t * @return a {@link StaticResourceRequest}\n\t */\n\tpublic static StaticResourceRequest toStaticResources() {\n\t\treturn StaticResourceRequest.INSTANCE;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/reactive/ReactiveWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.core.userdetails.ReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterChainProxy;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security in a reactive\n * application. Switches on {@link EnableWebFluxSecurity @EnableWebFluxSecurity} for a\n * reactive web application if this annotation has not been added by the user. It\n * delegates to Spring Security's content-negotiation mechanism for authentication. This\n * configuration also backs off if a bean of type {@link WebFilterChainProxy} has been\n * configured in any other way.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(after = ReactiveUserDetailsServiceAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration\")\n@EnableConfigurationProperties(SecurityProperties.class)\n@ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, WebFilterChainProxy.class, WebFluxConfigurer.class })\npublic final class ReactiveWebSecurityAutoConfiguration {\n\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SpringBootWebFluxSecurityConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean({ ReactiveAuthenticationManager.class, ReactiveUserDetailsService.class,\n\t\t\t\tSecurityWebFilterChain.class })\n\t\tReactiveAuthenticationManager denyAllAuthenticationManager() {\n\t\t\treturn (authentication) -> Mono.error(new UsernameNotFoundException(authentication.getName()));\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnMissingBean(WebFilterChainProxy.class)\n\t\t@EnableWebFluxSecurity\n\t\tstatic class EnableWebFluxSecurityConfiguration {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/reactive/StaticResourceRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport java.util.EnumSet;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.stream.Stream;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;\nimport org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Used to create a {@link ServerWebExchangeMatcher} for static resources in commonly used\n * locations. Returned by {@link PathRequest#toStaticResources()}.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n * @see PathRequest\n */\npublic final class StaticResourceRequest {\n\n\tstatic final StaticResourceRequest INSTANCE = new StaticResourceRequest();\n\n\tprivate StaticResourceRequest() {\n\t}\n\n\t/**\n\t * Returns a matcher that includes all commonly used {@link StaticResourceLocation\n\t * Locations}. The\n\t * {@link StaticResourceServerWebExchange#excluding(StaticResourceLocation, StaticResourceLocation...)\n\t * excluding} method can be used to remove specific locations if required. For\n\t * example: <pre class=\"code\">\n\t * PathRequest.toStaticResources().atCommonLocations().excluding(StaticResourceLocation.CSS)\n\t * </pre>\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic StaticResourceServerWebExchange atCommonLocations() {\n\t\treturn at(EnumSet.allOf(StaticResourceLocation.class));\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link StaticResourceLocation\n\t * Locations}. For example: <pre class=\"code\">\n\t * PathRequest.toStaticResources().at(StaticResourceLocation.CSS, StaticResourceLocation.JAVA_SCRIPT)\n\t * </pre>\n\t * @param first the first location to include\n\t * @param rest additional locations to include\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic StaticResourceServerWebExchange at(StaticResourceLocation first, StaticResourceLocation... rest) {\n\t\treturn at(EnumSet.of(first, rest));\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link StaticResourceLocation\n\t * Locations}. For example: <pre class=\"code\">\n\t * PathRequest.toStaticResources().at(locations)\n\t * </pre>\n\t * @param locations the locations to include\n\t * @return the configured {@link ServerWebExchangeMatcher}\n\t */\n\tpublic StaticResourceServerWebExchange at(Set<StaticResourceLocation> locations) {\n\t\tAssert.notNull(locations, \"'locations' must not be null\");\n\t\treturn new StaticResourceServerWebExchange(new LinkedHashSet<>(locations));\n\t}\n\n\t/**\n\t * The server web exchange matcher used to match against resource\n\t * {@link StaticResourceLocation locations}.\n\t */\n\tpublic static final class StaticResourceServerWebExchange implements ServerWebExchangeMatcher {\n\n\t\tprivate final Set<StaticResourceLocation> locations;\n\n\t\tprivate StaticResourceServerWebExchange(Set<StaticResourceLocation> locations) {\n\t\t\tthis.locations = locations;\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link StaticResourceServerWebExchange} based on this one but\n\t\t * excluding the specified locations.\n\t\t * @param first the first location to exclude\n\t\t * @param rest additional locations to exclude\n\t\t * @return a new {@link StaticResourceServerWebExchange}\n\t\t */\n\t\tpublic StaticResourceServerWebExchange excluding(StaticResourceLocation first, StaticResourceLocation... rest) {\n\t\t\treturn excluding(EnumSet.of(first, rest));\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link StaticResourceServerWebExchange} based on this one but\n\t\t * excluding the specified locations.\n\t\t * @param locations the locations to exclude\n\t\t * @return a new {@link StaticResourceServerWebExchange}\n\t\t */\n\t\tpublic StaticResourceServerWebExchange excluding(Set<StaticResourceLocation> locations) {\n\t\t\tAssert.notNull(locations, \"'locations' must not be null\");\n\t\t\tSet<StaticResourceLocation> subset = new LinkedHashSet<>(this.locations);\n\t\t\tsubset.removeAll(locations);\n\t\t\treturn new StaticResourceServerWebExchange(subset);\n\t\t}\n\n\t\tprivate Stream<String> getPatterns() {\n\t\t\treturn this.locations.stream().flatMap(StaticResourceLocation::getPatterns);\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<MatchResult> matches(ServerWebExchange exchange) {\n\t\t\treturn new OrServerWebExchangeMatcher(getDelegateMatchers().toList()).matches(exchange);\n\t\t}\n\n\t\tprivate Stream<ServerWebExchangeMatcher> getDelegateMatchers() {\n\t\t\treturn getPatterns().map(PathPatternParserServerWebExchangeMatcher::new);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for reactive Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/ConditionalOnDefaultWebSecurity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * {@link Conditional @Conditional} that only matches when web security is available and\n * the user has not defined their own configuration.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Conditional(DefaultWebSecurityCondition.class)\npublic @interface ConditionalOnDefaultWebSecurity {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/DefaultWebSecurityCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport org.springframework.boot.autoconfigure.condition.AllNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.context.annotation.Condition;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n/**\n * {@link Condition} for\n * {@link ConditionalOnDefaultWebSecurity @ConditionalOnDefaultWebSecurity}.\n *\n * @author Phillip Webb\n */\nclass DefaultWebSecurityCondition extends AllNestedConditions {\n\n\tDefaultWebSecurityCondition() {\n\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t}\n\n\t@ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })\n\tstatic class Classes {\n\n\t}\n\n\t@ConditionalOnMissingBean({ SecurityFilterChain.class })\n\tstatic class Beans {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/PathRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.h2console.autoconfigure.H2ConsoleProperties;\nimport org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;\nimport org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Factory that can be used to create a {@link RequestMatcher} for commonly used paths.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic final class PathRequest {\n\n\tprivate PathRequest() {\n\t}\n\n\t/**\n\t * Returns a {@link StaticResourceRequest} that can be used to create a matcher for\n\t * {@link StaticResourceLocation locations}.\n\t * @return a {@link StaticResourceRequest}\n\t */\n\tpublic static StaticResourceRequest toStaticResources() {\n\t\treturn StaticResourceRequest.INSTANCE;\n\t}\n\n\t/**\n\t * Returns a matcher that includes the H2 console location. For example:\n\t * <pre class=\"code\">\n\t * PathRequest.toH2Console()\n\t * </pre>\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic static H2ConsoleRequestMatcher toH2Console() {\n\t\treturn new H2ConsoleRequestMatcher();\n\t}\n\n\t/**\n\t * The request matcher used to match against h2 console path.\n\t */\n\tpublic static final class H2ConsoleRequestMatcher extends ApplicationContextRequestMatcher<ApplicationContext> {\n\n\t\tprivate volatile @Nullable RequestMatcher delegate;\n\n\t\tprivate H2ConsoleRequestMatcher() {\n\t\t\tsuper(ApplicationContext.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {\n\t\t\treturn hasServerNamespace(applicationContext, \"management\");\n\t\t}\n\n\t\t@Override\n\t\tprotected void initialized(Supplier<ApplicationContext> context) {\n\t\t\tString path = context.get().getBean(H2ConsoleProperties.class).getPath();\n\t\t\tAssert.hasText(path, \"'path' in H2ConsoleProperties must not be empty\");\n\t\t\tthis.delegate = PathPatternRequestMatcher.withDefaults().matcher(path + \"/**\");\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matches(HttpServletRequest request, Supplier<ApplicationContext> context) {\n\t\t\tRequestMatcher delegate = this.delegate;\n\t\t\tAssert.state(delegate != null, \"'delegate' must not be null\");\n\t\t\treturn delegate.matches(request);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/SecurityFilterAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.util.EnumSet;\nimport java.util.stream.Collectors;\n\nimport jakarta.servlet.DispatcherType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security's Filter.\n * Configured separately from {@link ServletWebSecurityAutoConfiguration} to ensure that\n * the filter's order is still configured when a user-provided\n * {@link WebSecurityConfiguration} exists.\n *\n * @author Rob Winch\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(after = ServletWebSecurityAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(SecurityFilterProperties.class)\n@ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })\npublic final class SecurityFilterAutoConfiguration {\n\n\tprivate static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;\n\n\t@Bean\n\t@ConditionalOnBean(name = DEFAULT_FILTER_NAME)\n\tDelegatingFilterProxyRegistrationBean securityFilterChainRegistration(\n\t\t\tSecurityFilterProperties securityFilterProperties) {\n\t\tDelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(\n\t\t\t\tDEFAULT_FILTER_NAME);\n\t\tregistration.setOrder(securityFilterProperties.getOrder());\n\t\tregistration.setDispatcherTypes(getDispatcherTypes(securityFilterProperties));\n\t\treturn registration;\n\t}\n\n\tprivate @Nullable EnumSet<DispatcherType> getDispatcherTypes(SecurityFilterProperties securityFilterProperties) {\n\t\tif (securityFilterProperties.getDispatcherTypes() == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn securityFilterProperties.getDispatcherTypes()\n\t\t\t.stream()\n\t\t\t.map((type) -> DispatcherType.valueOf(type.name()))\n\t\t\t.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/SecurityFilterProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.util.EnumSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.servlet.filter.OrderedFilter;\nimport org.springframework.boot.web.servlet.DispatcherType;\nimport org.springframework.core.Ordered;\n\n/**\n * Configuration properties for Spring Security Filter.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.security.filter\")\npublic class SecurityFilterProperties {\n\n\t/**\n\t * Order applied to the {@code SecurityFilterChain} that is used to configure basic\n\t * authentication for application endpoints. Create your own\n\t * {@code SecurityFilterChain} if you want to add your own authentication for all or\n\t * some of those endpoints.\n\t */\n\tpublic static final int BASIC_AUTH_ORDER = Ordered.LOWEST_PRECEDENCE - 5;\n\n\t/**\n\t * Default order of Spring Security's Filter in the servlet container (i.e. amongst\n\t * other filters registered with the container). There is no connection between this\n\t * and the {@code @Order} on a {@code SecurityFilterChain}.\n\t */\n\tpublic static final int DEFAULT_FILTER_ORDER = OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100;\n\n\t/**\n\t * Security filter chain order for Servlet-based web applications.\n\t */\n\tprivate int order = DEFAULT_FILTER_ORDER;\n\n\t/**\n\t * Security filter chain dispatcher types for Servlet-based web applications.\n\t */\n\tprivate Set<DispatcherType> dispatcherTypes = EnumSet.allOf(DispatcherType.class);\n\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\tpublic Set<DispatcherType> getDispatcherTypes() {\n\t\treturn this.dispatcherTypes;\n\t}\n\n\tpublic void setDispatcherTypes(Set<DispatcherType> dispatcherTypes) {\n\t\tthis.dispatcherTypes = dispatcherTypes;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/ServletWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(after = UserDetailsServiceAutoConfiguration.class,\n\t\tafterName = \"org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration\")\n@ConditionalOnClass(EnableWebSecurity.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic final class ServletWebSecurityAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(DispatcherServletPath.class)\n\t@ConditionalOnClass(DispatcherServletPath.class)\n\tstatic class PathPatternRequestMatcherBuilderConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tPathPatternRequestMatcher.Builder pathPatternRequestMatcherBuilder(\n\t\t\t\tDispatcherServletPath dispatcherServletPath) {\n\t\t\tPathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withDefaults();\n\t\t\tString path = dispatcherServletPath.getPath();\n\t\t\treturn (!path.equals(\"/\")) ? builder.basePath(path) : builder;\n\t\t}\n\n\t}\n\n\t/**\n\t * The default configuration for web security. It relies on Spring Security's\n\t * content-negotiation strategy to determine what sort of authentication to use. If\n\t * the user specifies their own {@link SecurityFilterChain} bean, this will back-off\n\t * completely and the users should specify all the bits that they want to configure as\n\t * part of the custom security configuration.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnDefaultWebSecurity\n\tstatic class SecurityFilterChainConfiguration {\n\n\t\t@Bean\n\t\t@Order(SecurityFilterProperties.BASIC_AUTH_ORDER)\n\t\tSecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\t\thttp.formLogin(withDefaults());\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\t/**\n\t * Adds the {@link EnableWebSecurity @EnableWebSecurity} annotation if Spring Security\n\t * is on the classpath. This will make sure that the annotation is present with\n\t * default security auto-configuration and also if the user adds custom security and\n\t * forgets to add the annotation. If {@link EnableWebSecurity @EnableWebSecurity} has\n\t * already been added or if a bean with name\n\t * {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been configured by the user, this\n\t * will back-off.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)\n\t@ConditionalOnClass(EnableWebSecurity.class)\n\t@EnableWebSecurity\n\tstatic class EnableWebSecurityConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/StaticResourceRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.util.EnumSet;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;\nimport org.springframework.boot.security.web.servlet.ApplicationContextRequestMatcher;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.security.web.util.matcher.OrRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Used to create a {@link RequestMatcher} for static resources in commonly used\n * locations. Returned by {@link PathRequest#toStaticResources()}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 4.0.0\n * @see PathRequest\n */\npublic final class StaticResourceRequest {\n\n\tstatic final StaticResourceRequest INSTANCE = new StaticResourceRequest();\n\n\tprivate StaticResourceRequest() {\n\t}\n\n\t/**\n\t * Returns a matcher that includes all commonly used {@link StaticResourceLocation\n\t * Locations}. The\n\t * {@link StaticResourceRequestMatcher#excluding(StaticResourceLocation, StaticResourceLocation...)\n\t * excluding} method can be used to remove specific locations if required. For\n\t * example: <pre class=\"code\">\n\t * PathRequest.toStaticResources().atCommonLocations().excluding(StaticResourceLocation.CSS)\n\t * </pre>\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic StaticResourceRequestMatcher atCommonLocations() {\n\t\treturn at(EnumSet.allOf(StaticResourceLocation.class));\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link StaticResourceLocation\n\t * Locations}. For example: <pre class=\"code\">\n\t * PathRequest.toStaticResources().at(StaticResourceLocation.CSS, StaticResourceLocation.JAVA_SCRIPT)\n\t * </pre>\n\t * @param first the first location to include\n\t * @param rest additional locations to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic StaticResourceRequestMatcher at(StaticResourceLocation first, StaticResourceLocation... rest) {\n\t\treturn at(EnumSet.of(first, rest));\n\t}\n\n\t/**\n\t * Returns a matcher that includes the specified {@link StaticResourceLocation\n\t * Locations}. For example: <pre class=\"code\">\n\t * PathRequest.toStaticResources().at(locations)\n\t * </pre>\n\t * @param locations the locations to include\n\t * @return the configured {@link RequestMatcher}\n\t */\n\tpublic StaticResourceRequestMatcher at(Set<StaticResourceLocation> locations) {\n\t\tAssert.notNull(locations, \"'locations' must not be null\");\n\t\treturn new StaticResourceRequestMatcher(new LinkedHashSet<>(locations));\n\t}\n\n\t/**\n\t * The request matcher used to match against resource {@link StaticResourceLocation\n\t * Locations}.\n\t */\n\tpublic static final class StaticResourceRequestMatcher\n\t\t\textends ApplicationContextRequestMatcher<DispatcherServletPath> {\n\n\t\tprivate final Set<StaticResourceLocation> locations;\n\n\t\tprivate volatile @Nullable RequestMatcher delegate;\n\n\t\tprivate StaticResourceRequestMatcher(Set<StaticResourceLocation> locations) {\n\t\t\tsuper(DispatcherServletPath.class);\n\t\t\tthis.locations = locations;\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link StaticResourceRequestMatcher} based on this one but\n\t\t * excluding the specified locations.\n\t\t * @param first the first location to exclude\n\t\t * @param rest additional locations to exclude\n\t\t * @return a new {@link StaticResourceRequestMatcher}\n\t\t */\n\t\tpublic StaticResourceRequestMatcher excluding(StaticResourceLocation first, StaticResourceLocation... rest) {\n\t\t\treturn excluding(EnumSet.of(first, rest));\n\t\t}\n\n\t\t/**\n\t\t * Return a new {@link StaticResourceRequestMatcher} based on this one but\n\t\t * excluding the specified locations.\n\t\t * @param locations the locations to exclude\n\t\t * @return a new {@link StaticResourceRequestMatcher}\n\t\t */\n\t\tpublic StaticResourceRequestMatcher excluding(Set<StaticResourceLocation> locations) {\n\t\t\tAssert.notNull(locations, \"'locations' must not be null\");\n\t\t\tSet<StaticResourceLocation> subset = new LinkedHashSet<>(this.locations);\n\t\t\tsubset.removeAll(locations);\n\t\t\treturn new StaticResourceRequestMatcher(subset);\n\t\t}\n\n\t\t@Override\n\t\tprotected void initialized(Supplier<DispatcherServletPath> dispatcherServletPath) {\n\t\t\tthis.delegate = new OrRequestMatcher(getDelegateMatchers(dispatcherServletPath.get()).toList());\n\t\t}\n\n\t\tprivate Stream<RequestMatcher> getDelegateMatchers(DispatcherServletPath dispatcherServletPath) {\n\t\t\treturn getPatterns(dispatcherServletPath).map(PathPatternRequestMatcher.withDefaults()::matcher);\n\t\t}\n\n\t\tprivate Stream<String> getPatterns(DispatcherServletPath dispatcherServletPath) {\n\t\t\treturn this.locations.stream()\n\t\t\t\t.flatMap(StaticResourceLocation::getPatterns)\n\t\t\t\t.map(dispatcherServletPath::getRelativePath);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean ignoreApplicationContext(WebApplicationContext applicationContext) {\n\t\t\treturn hasServerNamespace(applicationContext, \"management\");\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matches(HttpServletRequest request, Supplier<DispatcherServletPath> context) {\n\t\t\tRequestMatcher delegate = this.delegate;\n\t\t\tAssert.state(delegate != null, \"'delegate' must not be null\");\n\t\t\treturn delegate.matches(request);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/autoconfigure/web/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Servlet-based Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/web/reactive/ApplicationContextServerWebExchangeMatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.web.reactive;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * {@link ApplicationContext} backed {@link ServerWebExchangeMatcher}. Can work directly\n * with the {@link ApplicationContext}, obtain an existing bean or\n * {@link AutowireCapableBeanFactory#createBean(Class) create a new bean} that is\n * autowired in the usual way.\n *\n * @param <C> the type of the context that the match method actually needs to use. Can be\n * an {@link ApplicationContext} or a class of an {@link ApplicationContext#getBean(Class)\n * existing bean}.\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic abstract class ApplicationContextServerWebExchangeMatcher<C> implements ServerWebExchangeMatcher {\n\n\tprivate static final String WEB_SERVER_CONTEXT_CLASS = \"org.springframework.boot.web.server.context.WebServerApplicationContext\";\n\n\tprivate final Class<? extends C> contextClass;\n\n\tprivate volatile @Nullable Supplier<C> context;\n\n\tprivate final Object contextLock = new Object();\n\n\tpublic ApplicationContextServerWebExchangeMatcher(Class<? extends C> contextClass) {\n\t\tAssert.notNull(contextClass, \"'contextClass' must not be null\");\n\t\tthis.contextClass = contextClass;\n\t}\n\n\t@Override\n\tpublic final Mono<MatchResult> matches(ServerWebExchange exchange) {\n\t\tif (ignoreApplicationContext(exchange.getApplicationContext())) {\n\t\t\treturn MatchResult.notMatch();\n\t\t}\n\t\treturn matches(exchange, getContext(exchange));\n\t}\n\n\t/**\n\t * Decides whether the rule implemented by the strategy matches the supplied exchange.\n\t * @param exchange the source exchange\n\t * @param context a supplier for the initialized context (may throw an exception)\n\t * @return if the exchange matches\n\t */\n\tprotected abstract Mono<MatchResult> matches(ServerWebExchange exchange, Supplier<C> context);\n\n\t/**\n\t * Returns if the {@link ApplicationContext} should be ignored and not used for\n\t * matching. If this method returns {@code true} then the context will not be used and\n\t * the {@link #matches(ServerWebExchange) matches} method will return {@code false}.\n\t * @param applicationContext the candidate application context\n\t * @return if the application context should be ignored\n\t */\n\tprotected boolean ignoreApplicationContext(@Nullable ApplicationContext applicationContext) {\n\t\treturn false;\n\t}\n\n\tprotected Supplier<C> getContext(ServerWebExchange exchange) {\n\t\tSupplier<C> context = this.context;\n\t\tif (context == null) {\n\t\t\tsynchronized (this.contextLock) {\n\t\t\t\tcontext = this.context;\n\t\t\t\tif (context == null) {\n\t\t\t\t\tcontext = createContext(exchange);\n\t\t\t\t\tinitialized(context);\n\t\t\t\t\tthis.context = context;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn context;\n\t}\n\n\t/**\n\t * Called once the context has been initialized.\n\t * @param context a supplier for the initialized context (may throw an exception)\n\t */\n\tprotected void initialized(Supplier<C> context) {\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Supplier<C> createContext(ServerWebExchange exchange) {\n\t\tApplicationContext context = exchange.getApplicationContext();\n\t\tAssert.state(context != null, \"No ApplicationContext found on ServerWebExchange.\");\n\t\tif (this.contextClass.isInstance(context)) {\n\t\t\treturn () -> (C) context;\n\t\t}\n\t\treturn () -> context.getBean(this.contextClass);\n\t}\n\n\t/**\n\t * Returns {@code true} if the specified context is a\n\t * {@link WebServerApplicationContext} with a matching server namespace.\n\t * @param context the context to check\n\t * @param serverNamespace the server namespace to match against\n\t * @return {@code true} if the server namespace of the context matches\n\t * @since 4.0.1\n\t */\n\tprotected final boolean hasServerNamespace(@Nullable ApplicationContext context, String serverNamespace) {\n\t\tif (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn WebServerApplicationContext.hasServerNamespace(context, serverNamespace);\n\t}\n\n\t/**\n\t * Returns the server namespace if the specified context is a\n\t * {@link WebServerApplicationContext}.\n\t * @param context the context\n\t * @return the server namespace or {@code null} if the context is not a\n\t * {@link WebServerApplicationContext}\n\t * @since 4.0.1\n\t */\n\tprotected final @Nullable String getServerNamespace(@Nullable ApplicationContext context) {\n\t\tif (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn WebServerApplicationContext.getServerNamespace(context);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/web/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes and utilities for reactive Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.web.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/web/servlet/ApplicationContextRequestMatcher.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.web.servlet;\n\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\n\n/**\n * {@link ApplicationContext} backed {@link RequestMatcher}. Can work directly with the\n * {@link ApplicationContext}, obtain an existing bean or\n * {@link AutowireCapableBeanFactory#createBean(Class) create a new bean} that is\n * autowired in the usual way.\n *\n * @param <C> the type of the context that the match method actually needs to use. Can be\n * an {@link ApplicationContext} or a class of an {@link ApplicationContext#getBean(Class)\n * existing bean}.\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic abstract class ApplicationContextRequestMatcher<C> implements RequestMatcher {\n\n\tprivate static final String WEB_SERVER_CONTEXT_CLASS = \"org.springframework.boot.web.server.context.WebServerApplicationContext\";\n\n\tprivate final Class<? extends C> contextClass;\n\n\tprivate volatile boolean initialized;\n\n\tprivate final Object initializeLock = new Object();\n\n\tpublic ApplicationContextRequestMatcher(Class<? extends C> contextClass) {\n\t\tAssert.notNull(contextClass, \"'contextClass' must not be null\");\n\t\tthis.contextClass = contextClass;\n\t}\n\n\t@Override\n\tpublic final boolean matches(HttpServletRequest request) {\n\t\tWebApplicationContext webApplicationContext = WebApplicationContextUtils\n\t\t\t.getRequiredWebApplicationContext(request.getServletContext());\n\t\tif (ignoreApplicationContext(webApplicationContext)) {\n\t\t\treturn false;\n\t\t}\n\t\tSupplier<C> context = () -> getContext(webApplicationContext);\n\t\tif (!this.initialized) {\n\t\t\tsynchronized (this.initializeLock) {\n\t\t\t\tif (!this.initialized) {\n\t\t\t\t\tinitialized(context);\n\t\t\t\t\tthis.initialized = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn matches(request, context);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate C getContext(WebApplicationContext webApplicationContext) {\n\t\tif (this.contextClass.isInstance(webApplicationContext)) {\n\t\t\treturn (C) webApplicationContext;\n\t\t}\n\t\treturn webApplicationContext.getBean(this.contextClass);\n\t}\n\n\t/**\n\t * Returns if the {@link WebApplicationContext} should be ignored and not used for\n\t * matching. If this method returns {@code true} then the context will not be used and\n\t * the {@link #matches(HttpServletRequest) matches} method will return {@code false}.\n\t * @param webApplicationContext the candidate web application context\n\t * @return if the application context should be ignored\n\t */\n\tprotected boolean ignoreApplicationContext(WebApplicationContext webApplicationContext) {\n\t\treturn false;\n\t}\n\n\t/**\n\t * Method that can be implemented by subclasses that wish to initialize items the\n\t * first time that the matcher is called. This method will be called only once and\n\t * only if {@link #ignoreApplicationContext(WebApplicationContext)} returns\n\t * {@code false}. Note that the supplied context will be based on the\n\t * <strong>first</strong> request sent to the matcher.\n\t * @param context a supplier for the initialized context (may throw an exception)\n\t * @see #ignoreApplicationContext(WebApplicationContext)\n\t */\n\tprotected void initialized(Supplier<C> context) {\n\t}\n\n\t/**\n\t * Decides whether the rule implemented by the strategy matches the supplied request.\n\t * @param request the source request\n\t * @param context a supplier for the initialized context (may throw an exception)\n\t * @return if the request matches\n\t */\n\tprotected abstract boolean matches(HttpServletRequest request, Supplier<C> context);\n\n\t/**\n\t * Returns {@code true} if the specified context is a\n\t * {@link WebServerApplicationContext} with a matching server namespace.\n\t * @param context the context to check\n\t * @param serverNamespace the server namespace to match against\n\t * @return {@code true} if the server namespace of the context matches\n\t * @since 4.0.1\n\t */\n\tprotected final boolean hasServerNamespace(@Nullable ApplicationContext context, String serverNamespace) {\n\t\tif (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn WebServerApplicationContext.hasServerNamespace(context, serverNamespace);\n\t}\n\n\t/**\n\t * Returns the server namespace if the specified context is a\n\t * {@link WebServerApplicationContext}.\n\t * @param context the context\n\t * @return the server namespace or {@code null} if the context is not a\n\t * {@link WebServerApplicationContext}\n\t * @since 4.0.1\n\t */\n\tprotected final @Nullable String getServerNamespace(@Nullable ApplicationContext context) {\n\t\tif (!ClassUtils.isPresent(WEB_SERVER_CONTEXT_CLASS, null)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn WebServerApplicationContext.getServerNamespace(context);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/java/org/springframework/boot/security/web/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes and utilities for Servlet-based Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.web.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n  \t{\n      \"name\": \"spring.security.filter.dispatcher-types\",\n      \"defaultValue\": [\n        \"async\",\n        \"error\",\n        \"forward\",\n        \"include\",\n        \"request\"\n      ]\n    },\n    {\n      \"name\": \"spring.security.filter.order\",\n      \"defaultValue\": -100\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.security.autoconfigure.actuate.web.servlet.SecurityRequestMatchersManagementContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration\norg.springframework.boot.security.autoconfigure.SecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration\norg.springframework.boot.security.autoconfigure.actuate.web.reactive.ReactiveManagementWebSecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.rsocket.RSocketSecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterAutoConfiguration\norg.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/ReactiveUserDetailsServiceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;\nimport org.springframework.security.config.annotation.rsocket.EnableRSocketSecurity;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.ReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\nimport org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;\nimport org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveUserDetailsServiceAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author HaiTao Zhang\n */\nclass ReactiveUserDetailsServiceAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveUserDetailsServiceAutoConfiguration.class));\n\n\t@Test\n\tvoid configuresADefaultUser() {\n\t\tthis.contextRunner.withClassLoader(filterAlternativeUserDetailsManager())\n\t\t\t.withUserConfiguration(TestSecurityConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveUserDetailsService userDetailsService = context.getBean(ReactiveUserDetailsService.class);\n\t\t\t\tassertThat(userDetailsService.findByUsername(\"user\").block(Duration.ofSeconds(30))).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenRSocketConfigured() {\n\t\tnew ApplicationContextRunner().withClassLoader(filterAlternativeUserDetailsManager())\n\t\t\t.withConfiguration(AutoConfigurations.of(ReactiveUserDetailsServiceAutoConfiguration.class,\n\t\t\t\t\tRSocketMessagingAutoConfiguration.class, RSocketStrategiesAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestRSocketSecurityConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveUserDetailsService userDetailsService = context.getBean(ReactiveUserDetailsService.class);\n\t\t\t\tassertThat(userDetailsService.findByUsername(\"user\").block(Duration.ofSeconds(30))).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotConfigureDefaultUserIfUserDetailsServiceAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(UserConfig.class, TestSecurityConfiguration.class).run((context) -> {\n\t\t\tReactiveUserDetailsService userDetailsService = context.getBean(ReactiveUserDetailsService.class);\n\t\t\tassertThat(userDetailsService.findByUsername(\"user\").block(Duration.ofSeconds(30))).isNull();\n\t\t\tassertThat(userDetailsService.findByUsername(\"foo\").block(Duration.ofSeconds(30))).isNotNull();\n\t\t\tassertThat(userDetailsService.findByUsername(\"admin\").block(Duration.ofSeconds(30))).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid doesNotConfigureDefaultUserIfAuthenticationManagerAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(AuthenticationManagerConfig.class, TestSecurityConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(ReactiveWebSecurityAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).getBean(ReactiveUserDetailsService.class).isNull());\n\t}\n\n\t@Test\n\tvoid doesNotConfigureDefaultUserIfAuthenticationManagerResolverAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(AuthenticationManagerResolverConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveAuthenticationManagerResolver.class)\n\t\t\t\t.doesNotHaveBean(ReactiveUserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid doesNotConfigureDefaultUserIfResourceServerIsPresent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveUserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid configuresDefaultUserWhenResourceServerIsPresentAndUsernameIsConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.user.name=carol\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveUserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid configuresDefaultUserWhenResourceServerIsPresentAndPasswordIsConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.user.password=p4ssw0rd\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveUserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() {\n\t\tthis.contextRunner.withClassLoader(filterAlternativeUserDetailsManager())\n\t\t\t.withUserConfiguration(TestSecurityConfiguration.class)\n\t\t\t.run(((context) -> {\n\t\t\t\tMapReactiveUserDetailsService userDetailsService = context.getBean(MapReactiveUserDetailsService.class);\n\t\t\t\tUserDetails user = userDetailsService.findByUsername(\"user\").block(Duration.ofSeconds(30));\n\t\t\t\tassertThat(user).isNotNull();\n\t\t\t\tString password = user.getPassword();\n\t\t\t\tassertThat(password).startsWith(\"{noop}\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderAbsentAndRawPassword() {\n\t\ttestPasswordEncoding(TestSecurityConfiguration.class, \"secret\", \"{noop}secret\");\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderAbsentAndEncodedPassword() {\n\t\tString password = \"{bcrypt}$2a$10$sCBi9fy9814vUPf2ZRbtp.fR5/VgRk2iBFZ.ypu5IyZ28bZgxrVDa\";\n\t\ttestPasswordEncoding(TestSecurityConfiguration.class, password, password);\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderBeanPresent() {\n\t\ttestPasswordEncoding(TestConfigWithPasswordEncoder.class, \"secret\", \"secret\");\n\t}\n\n\tprivate void testPasswordEncoding(Class<?> configClass, String providedPassword, String expectedPassword) {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(\n\t\t\t\t\tnew FilteredClassLoader(ClientRegistrationRepository.class, ReactiveOpaqueTokenIntrospector.class))\n\t\t\t.withUserConfiguration(configClass)\n\t\t\t.withPropertyValues(\"spring.security.user.password=\" + providedPassword)\n\t\t\t.run(((context) -> {\n\t\t\t\tMapReactiveUserDetailsService userDetailsService = context.getBean(MapReactiveUserDetailsService.class);\n\t\t\t\tUserDetails user = userDetailsService.findByUsername(\"user\").block(Duration.ofSeconds(30));\n\t\t\t\tassertThat(user).isNotNull();\n\t\t\t\tString password = user.getPassword();\n\t\t\t\tassertThat(password).isEqualTo(expectedPassword);\n\t\t\t}));\n\t}\n\n\tprivate FilteredClassLoader filterAlternativeUserDetailsManager() {\n\t\treturn new FilteredClassLoader(ClientRegistrationRepository.class, ReactiveOpaqueTokenIntrospector.class,\n\t\t\t\tOpaqueTokenIntrospector.class, RelyingPartyRegistrationRepository.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFluxSecurity\n\t@EnableConfigurationProperties(SecurityProperties.class)\n\tstatic class TestSecurityConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableRSocketSecurity\n\t@EnableConfigurationProperties(SecurityProperties.class)\n\tstatic class TestRSocketSecurityConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserConfig {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\tUserDetails foo = User.withUsername(\"foo\").password(\"foo\").roles(\"USER\").build();\n\t\t\tUserDetails admin = User.withUsername(\"admin\").password(\"admin\").roles(\"USER\", \"ADMIN\").build();\n\t\t\treturn new MapReactiveUserDetailsService(foo, admin);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuthenticationManagerConfig {\n\n\t\t@Bean\n\t\tReactiveAuthenticationManager reactiveAuthenticationManager() {\n\t\t\treturn (authentication) -> Mono.empty();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuthenticationManagerResolverConfig {\n\n\t\t@Bean\n\t\tReactiveAuthenticationManagerResolver<?> reactiveAuthenticationManagerResolver() {\n\t\t\treturn mock(ReactiveAuthenticationManagerResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestSecurityConfiguration.class)\n\tstatic class TestConfigWithPasswordEncoder {\n\n\t\t@Bean\n\t\tPasswordEncoder passwordEncoder() {\n\t\t\treturn mock(PasswordEncoder.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/SecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.jpa.City;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.security.authentication.AuthenticationEventPublisher;\nimport org.springframework.security.authentication.DefaultAuthenticationEventPublisher;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SecurityAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Rob Winch\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass SecurityAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(SecurityAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid defaultAuthenticationEventPublisherRegistered() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(AuthenticationEventPublisher.class))\n\t\t\t.isInstanceOf(DefaultAuthenticationEventPublisher.class));\n\t}\n\n\t@Test\n\tvoid defaultAuthenticationEventPublisherIsConditionalOnMissingBean() {\n\t\tthis.contextRunner.withUserConfiguration(AuthenticationEventPublisherConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(AuthenticationEventPublisher.class))\n\t\t\t\t.isInstanceOf(AuthenticationEventPublisherConfiguration.TestAuthenticationEventPublisher.class));\n\t}\n\n\t@Test\n\tvoid testJpaCoexistsHappily() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.datasource.url:jdbc:hsqldb:mem:testsecdb\")\n\t\t\t.withUserConfiguration(EntityConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(JpaTransactionManager.class)).isNotNull());\n\t\t// This can fail if security @Conditionals force early instantiation of the\n\t\t// HibernateJpaAutoConfiguration (e.g. the EntityManagerFactory is not found)\n\t}\n\n\t@Test\n\tvoid testSecurityEvaluationContextExtensionSupport() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).getBean(SecurityEvaluationContextExtension.class).isNotNull());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TestAutoConfigurationPackage(City.class)\n\tstatic class EntityConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuthenticationEventPublisherConfiguration {\n\n\t\t@Bean\n\t\tAuthenticationEventPublisher authenticationEventPublisher() {\n\t\t\treturn new TestAuthenticationEventPublisher();\n\t\t}\n\n\t\tclass TestAuthenticationEventPublisher implements AuthenticationEventPublisher {\n\n\t\t\t@Override\n\t\t\tpublic void publishAuthenticationSuccess(Authentication authentication) {\n\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/SecurityPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SecurityProperties}.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n */\nclass SecurityPropertiesTests {\n\n\tprivate final SecurityProperties properties = new SecurityProperties();\n\n\tprivate Binder binder;\n\n\tprivate final MapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.binder = new Binder(this.source);\n\t}\n\n\t@Test\n\tvoid userWhenNotConfiguredShouldUseDefaultNameAndGeneratedPassword() {\n\t\tSecurityProperties.User user = this.properties.getUser();\n\t\tassertThat(user.getName()).isEqualTo(\"user\");\n\t\tassertThat(user.getPassword()).isNotNull();\n\t\tassertThat(user.isPasswordGenerated()).isTrue();\n\t\tassertThat(user.getRoles()).isEmpty();\n\t}\n\n\t@Test\n\tvoid userShouldBindProperly() {\n\t\tthis.source.put(\"spring.security.user.name\", \"foo\");\n\t\tthis.source.put(\"spring.security.user.password\", \"password\");\n\t\tthis.source.put(\"spring.security.user.roles\", \"ADMIN,USER\");\n\t\tthis.binder.bind(\"spring.security\", Bindable.ofInstance(this.properties));\n\t\tSecurityProperties.User user = this.properties.getUser();\n\t\tassertThat(user.getName()).isEqualTo(\"foo\");\n\t\tassertThat(user.getPassword()).isEqualTo(\"password\");\n\t\tassertThat(user.isPasswordGenerated()).isFalse();\n\t\tassertThat(user.getRoles()).containsExactly(\"ADMIN\", \"USER\");\n\t}\n\n\t@Test\n\tvoid passwordAutogeneratedIfEmpty() {\n\t\tthis.source.put(\"spring.security.user.password\", \"\");\n\t\tthis.binder.bind(\"spring.security\", Bindable.ofInstance(this.properties));\n\t\tassertThat(this.properties.getUser().isPasswordGenerated()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/UserDetailsServiceAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.authentication.AuthenticationManager;\nimport org.springframework.security.authentication.AuthenticationManagerResolver;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.ProviderManager;\nimport org.springframework.security.authentication.TestingAuthenticationProvider;\nimport org.springframework.security.authentication.TestingAuthenticationToken;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.crypto.password.PasswordEncoder;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link UserDetailsServiceAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author HaiTao Zhang\n * @author Lasse Wulff\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass UserDetailsServiceAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(TestSecurityConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyUserDetailsServiceInServletApp() {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(UserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyUserDetailsServiceInReactiveApp() {\n\t\tnew ReactiveWebApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class))\n\t\t\t.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyUserDetailsServiceInNonWebApp() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(TestSecurityConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(UserDetailsServiceAutoConfiguration.class))\n\t\t\t.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(UserDetailsService.class));\n\t}\n\n\t@Test\n\tvoid testDefaultUsernamePassword(CapturedOutput output) {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent()).run((context) -> {\n\t\t\tassertThat(outcomeOfMissingAlternativeCondition(context).isMatch()).isTrue();\n\t\t\tUserDetailsService manager = context.getBean(UserDetailsService.class);\n\t\t\tassertThat(output).contains(\"Using generated security password:\");\n\t\t\tassertThat(manager.loadUserByUsername(\"user\")).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultUserNotCreatedIfAuthenticationManagerBeanPresent(CapturedOutput output) {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(TestAuthenticationManagerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(outcomeOfMissingAlternativeCondition(context).isMatch()).isTrue();\n\t\t\t\tAuthenticationManager manager = context.getBean(AuthenticationManager.class);\n\t\t\t\tassertThat(manager)\n\t\t\t\t\t.isEqualTo(context.getBean(TestAuthenticationManagerConfiguration.class).authenticationManager);\n\t\t\t\tassertThat(output).doesNotContain(\"Using generated security password: \");\n\t\t\t\tTestingAuthenticationToken token = new TestingAuthenticationToken(\"foo\", \"bar\");\n\t\t\t\tassertThat(manager.authenticate(token)).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultUserNotCreatedIfAuthenticationManagerResolverBeanPresent(CapturedOutput output) {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(TestAuthenticationManagerResolverConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(outcomeOfMissingAlternativeCondition(context).isMatch()).isTrue();\n\t\t\t\tassertThat(output).doesNotContain(\"Using generated security password: \");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultUserNotCreatedIfUserDetailsServiceBeanPresent(CapturedOutput output) {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(TestUserDetailsServiceConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(outcomeOfMissingAlternativeCondition(context).isMatch()).isTrue();\n\t\t\t\tUserDetailsService userDetailsService = context.getBean(UserDetailsService.class);\n\t\t\t\tassertThat(output).doesNotContain(\"Using generated security password: \");\n\t\t\t\tassertThat(userDetailsService.loadUserByUsername(\"foo\")).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultUserNotCreatedIfAuthenticationProviderBeanPresent(CapturedOutput output) {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(TestAuthenticationProviderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(outcomeOfMissingAlternativeCondition(context).isMatch()).isTrue();\n\t\t\t\tAuthenticationProvider provider = context.getBean(AuthenticationProvider.class);\n\t\t\t\tassertThat(output).doesNotContain(\"Using generated security password: \");\n\t\t\t\tTestingAuthenticationToken token = new TestingAuthenticationToken(\"foo\", \"bar\");\n\t\t\t\tassertThat(provider.authenticate(token)).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultUserNotCreatedIfJwtDecoderBeanPresent() {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(TestConfigWithJwtDecoder.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(outcomeOfMissingAlternativeCondition(context).isMatch()).isTrue();\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(UserDetailsService.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderAbsentAndDefaultPassword() {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(TestSecurityConfiguration.class)\n\t\t\t.run(((context) -> {\n\t\t\t\tInMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class);\n\t\t\t\tString password = userDetailsService.loadUserByUsername(\"user\").getPassword();\n\t\t\t\tassertThat(password).startsWith(\"{noop}\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderAbsentAndRawPassword() {\n\t\ttestPasswordEncoding(TestSecurityConfiguration.class, \"secret\", \"{noop}secret\");\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderAbsentAndEncodedPassword() {\n\t\tString password = \"{bcrypt}$2a$10$sCBi9fy9814vUPf2ZRbtp.fR5/VgRk2iBFZ.ypu5IyZ28bZgxrVDa\";\n\t\ttestPasswordEncoding(TestSecurityConfiguration.class, password, password);\n\t}\n\n\t@Test\n\tvoid userDetailsServiceWhenPasswordEncoderBeanPresent() {\n\t\ttestPasswordEncoding(TestConfigWithPasswordEncoder.class, \"secret\", \"secret\");\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid whenClassOfAlternativeIsPresentUserDetailsServiceBacksOff(AlternativeFormOfAuthentication alternative) {\n\t\tthis.contextRunner.with(alternative.present())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(InMemoryUserDetailsManager.class));\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid whenAlternativeIsPresentAndUsernameIsConfiguredThenUserDetailsServiceIsAutoConfigured(\n\t\t\tAlternativeFormOfAuthentication alternative) {\n\t\tthis.contextRunner.with(alternative.present())\n\t\t\t.withPropertyValues(\"spring.security.user.name=alice\")\n\t\t\t.run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class)));\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource\n\tvoid whenAlternativeIsPresentAndPasswordIsConfiguredThenUserDetailsServiceIsAutoConfigured(\n\t\t\tAlternativeFormOfAuthentication alternative) {\n\t\tthis.contextRunner.with(alternative.present())\n\t\t\t.withPropertyValues(\"spring.security.user.password=secret\")\n\t\t\t.run(((context) -> assertThat(context).hasSingleBean(InMemoryUserDetailsManager.class)));\n\t}\n\n\tprivate void testPasswordEncoding(Class<?> configClass, String providedPassword, String expectedPassword) {\n\t\tthis.contextRunner.with(AlternativeFormOfAuthentication.nonPresent())\n\t\t\t.withUserConfiguration(configClass)\n\t\t\t.withPropertyValues(\"spring.security.user.password=\" + providedPassword)\n\t\t\t.run(((context) -> {\n\t\t\t\tInMemoryUserDetailsManager userDetailsService = context.getBean(InMemoryUserDetailsManager.class);\n\t\t\t\tString password = userDetailsService.loadUserByUsername(\"user\").getPassword();\n\t\t\t\tassertThat(password).isEqualTo(expectedPassword);\n\t\t\t}));\n\t}\n\n\tprivate ConditionOutcome outcomeOfMissingAlternativeCondition(ConfigurableApplicationContext context) {\n\t\tConditionAndOutcomes conditionAndOutcomes = ConditionEvaluationReport.get(context.getBeanFactory())\n\t\t\t.getConditionAndOutcomesBySource()\n\t\t\t.get(UserDetailsServiceAutoConfiguration.class.getName());\n\t\tassertThat(conditionAndOutcomes).isNotNull();\n\t\tfor (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {\n\t\t\tif (conditionAndOutcome\n\t\t\t\t.getCondition() instanceof MissingAlternativeUserDetailsManagerOrUserPropertiesConfigured) {\n\t\t\t\treturn conditionAndOutcome.getOutcome();\n\t\t\t}\n\t\t}\n\t\tfail(\"No outcome for MissingAlternativeUserDetailsManagerOrUserPropertiesConfigured found\");\n\t\tthrow new AssertionError(\"Should not be reached\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestAuthenticationManagerConfiguration {\n\n\t\tprivate @Nullable AuthenticationManager authenticationManager;\n\n\t\t@Bean\n\t\tAuthenticationManager myAuthenticationManager() {\n\t\t\tAuthenticationProvider authenticationProvider = new TestingAuthenticationProvider();\n\t\t\tthis.authenticationManager = new ProviderManager(Collections.singletonList(authenticationProvider));\n\t\t\treturn this.authenticationManager;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestUserDetailsServiceConfiguration {\n\n\t\t@Bean\n\t\tInMemoryUserDetailsManager myUserDetailsManager() {\n\t\t\treturn new InMemoryUserDetailsManager(User.withUsername(\"foo\").password(\"bar\").roles(\"USER\").build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestAuthenticationProviderConfiguration {\n\n\t\t@Bean\n\t\tAuthenticationProvider myAuthenticationProvider() {\n\t\t\treturn new TestingAuthenticationProvider();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\t@EnableConfigurationProperties(SecurityProperties.class)\n\tstatic class TestSecurityConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestSecurityConfiguration.class)\n\tstatic class TestConfigWithPasswordEncoder {\n\n\t\t@Bean\n\t\tPasswordEncoder passwordEncoder() {\n\t\t\treturn mock(PasswordEncoder.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestSecurityConfiguration.class)\n\tstatic class TestConfigWithClientRegistrationRepository {\n\n\t\t@Bean\n\t\tClientRegistrationRepository clientRegistrationRepository() {\n\t\t\treturn mock(ClientRegistrationRepository.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestSecurityConfiguration.class)\n\tstatic class TestConfigWithJwtDecoder {\n\n\t\t@Bean\n\t\tJwtDecoder jwtDecoder() {\n\t\t\treturn mock(JwtDecoder.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestSecurityConfiguration.class)\n\tstatic class TestConfigWithIntrospectionClient {\n\n\t\t@Bean\n\t\tOpaqueTokenIntrospector introspectionClient() {\n\t\t\treturn mock(OpaqueTokenIntrospector.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestAuthenticationManagerResolverConfiguration {\n\n\t\t@Bean\n\t\tAuthenticationManagerResolver<?> authenticationManagerResolver() {\n\t\t\treturn mock(AuthenticationManagerResolver.class);\n\t\t}\n\n\t}\n\n\tprivate enum AlternativeFormOfAuthentication {\n\n\t\tCLIENT_REGISTRATION_REPOSITORY(ClientRegistrationRepository.class),\n\n\t\tOPAQUE_TOKEN_INTROSPECTOR(OpaqueTokenIntrospector.class),\n\n\t\tRELYING_PARTY_REGISTRATION_REPOSITORY(RelyingPartyRegistrationRepository.class);\n\n\t\tprivate final Class<?> type;\n\n\t\tAlternativeFormOfAuthentication(Class<?> type) {\n\t\t\tthis.type = type;\n\t\t}\n\n\t\tprivate Class<?> getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate <T extends AbstractApplicationContextRunner<?, ?, ?>> Function<T, T> present() {\n\t\t\treturn (contextRunner) -> (T) contextRunner\n\t\t\t\t.withClassLoader(new FilteredClassLoader(Stream.of(AlternativeFormOfAuthentication.values())\n\t\t\t\t\t.filter(Predicate.not(this::equals))\n\t\t\t\t\t.map(AlternativeFormOfAuthentication::getType)\n\t\t\t\t\t.toArray(Class[]::new)));\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate static <T extends AbstractApplicationContextRunner<?, ?, ?>> Function<T, T> nonPresent() {\n\t\t\treturn (contextRunner) -> (T) contextRunner\n\t\t\t\t.withClassLoader(new FilteredClassLoader(Stream.of(AlternativeFormOfAuthentication.values())\n\t\t\t\t\t.map(AlternativeFormOfAuthentication::getType)\n\t\t\t\t\t.toArray(Class[]::new)));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/reactive/EndpointRequestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.reactive;\n\nimport java.time.Duration;\nimport java.util.Base64;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity.CsrfSpec;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link EndpointRequest}.\n *\n * @author Chris Bono\n */\nclass EndpointRequestIntegrationTests {\n\n\t@Test\n\tvoid toEndpointShouldMatch() {\n\t\tgetContextRunner().run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/actuator/e1\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toEndpointPostShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.security.user.password=password\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.post().uri(\"/actuator/e1\").exchange().expectStatus().isUnauthorized();\n\t\t\twebTestClient.post()\n\t\t\t\t.uri(\"/actuator/e1\")\n\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNoContent();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toAllEndpointsShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.security.user.password=password\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/actuator/e2\").exchange().expectStatus().isUnauthorized();\n\t\t\twebTestClient.get()\n\t\t\t\t.uri(\"/actuator/e2\")\n\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toLinksShouldMatch() {\n\t\tgetContextRunner().run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/actuator\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\tprotected final ReactiveWebApplicationContextRunner getContextRunner() {\n\t\treturn createContextRunner().withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class, SecurityConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(JacksonAutoConfiguration.class, ReactiveWebSecurityAutoConfiguration.class,\n\t\t\t\t\t\t\tReactiveUserDetailsServiceAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\t\t\t\tWebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class));\n\n\t}\n\n\tprotected ReactiveWebApplicationContextRunner createContextRunner() {\n\t\treturn new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withUserConfiguration(WebEndpointConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class,\n\t\t\t\t\tHttpMessageConvertersAutoConfiguration.class, WebFluxAutoConfiguration.class));\n\t}\n\n\tprotected WebTestClient getWebTestClient(AssertableReactiveWebApplicationContext context) {\n\t\tWebServer webServer = context\n\t\t\t.getSourceApplicationContext(AnnotationConfigReactiveWebServerApplicationContext.class)\n\t\t\t.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tint port = webServer.getPort();\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint1 endpoint1() {\n\t\t\treturn new TestEndpoint1();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint2 endpoint2() {\n\t\t\treturn new TestEndpoint2();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint3 endpoint3() {\n\t\t\treturn new TestEndpoint3();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"e1\")\n\tstatic class TestEndpoint1 {\n\n\t\t@ReadOperation\n\t\tObject getAll() {\n\t\t\treturn \"endpoint 1\";\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid setAll() {\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"e2\")\n\tstatic class TestEndpoint2 {\n\n\t\t@ReadOperation\n\t\tObject getAll() {\n\t\t\treturn \"endpoint 2\";\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"e3\")\n\tstatic class TestEndpoint3 {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WebEndpointProperties.class)\n\tstatic class WebEndpointConfiguration {\n\n\t\t@Bean\n\t\tTomcatReactiveWebServerFactory tomcat() {\n\t\t\treturn new TomcatReactiveWebServerFactory(0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@SuppressWarnings(\"deprecation\")\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t\t.username(\"user\")\n\t\t\t\t\t\t.password(\"password\")\n\t\t\t\t\t\t.authorities(\"ROLE_USER\")\n\t\t\t\t\t\t.build(),\n\t\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t\t.username(\"admin\")\n\t\t\t\t\t\t.password(\"admin\")\n\t\t\t\t\t\t.authorities(\"ROLE_ACTUATOR\", \"ROLE_USER\")\n\t\t\t\t\t\t.build());\n\t\t}\n\n\t\t@Bean\n\t\tSecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\t\thttp.authorizeExchange((exchanges) -> {\n\t\t\t\texchanges.matchers(EndpointRequest.toLinks()).permitAll();\n\t\t\t\texchanges.matchers(EndpointRequest.to(TestEndpoint1.class).withHttpMethod(HttpMethod.POST))\n\t\t\t\t\t.authenticated();\n\t\t\t\texchanges.matchers(EndpointRequest.to(TestEndpoint1.class)).permitAll();\n\t\t\t\texchanges.matchers(EndpointRequest.toAnyEndpoint()).authenticated();\n\t\t\t\texchanges.anyExchange().hasRole(\"ADMIN\");\n\t\t\t});\n\t\t\thttp.httpBasic(Customizer.withDefaults());\n\t\t\thttp.csrf(CsrfSpec::disable);\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/reactive/EndpointRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.reactive;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.assertj.core.api.AssertDelegateTarget;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.http.server.reactive.MockServerHttpResponse;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult;\nimport org.springframework.web.context.support.StaticWebApplicationContext;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebHandler;\nimport org.springframework.web.server.adapter.HttpWebHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EndpointRequest}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Chris Bono\n */\nclass EndpointRequestTests {\n\n\t@Test\n\tvoid toAnyEndpointShouldMatchEndpointPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWithHttpMethodShouldRespectRequestMethod() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().withHttpMethod(HttpMethod.POST);\n\t\tassertMatcher(matcher, \"/actuator\").matches(HttpMethod.POST, \"/actuator/foo\");\n\t\tassertMatcher(matcher, \"/actuator\").doesNotMatch(HttpMethod.GET, \"/actuator/foo\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher).matches(\"/actuator/foo/\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar/\");\n\t\tassertMatcher(matcher).matches(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenBasePathIsEmptyShouldNotMatchLinks() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, \"\");\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t\tassertMatcher.matches(\"/foo\");\n\t\tassertMatcher.matches(\"/bar\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenBasePathIsEmptyAndManagementPortDifferentShouldMatchLinks() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(\"\"),\n\t\t\t\tWebServerNamespace.MANAGEMENT);\n\t\tassertMatcher.matches(\"/\");\n\t\tassertMatcher.matches(\"/foo\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointShouldNotMatchOtherPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/baz\");\n\t}\n\n\t@Test\n\tvoid toEndpointClassShouldMatchEndpointPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(FooEndpoint.class);\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo/\");\n\t}\n\n\t@Test\n\tvoid toEndpointClassShouldNotMatchOtherPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(FooEndpoint.class);\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar/\");\n\t}\n\n\t@Test\n\tvoid toEndpointIdShouldMatchEndpointPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(\"foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo/\");\n\t}\n\n\t@Test\n\tvoid toEndpointIdShouldNotMatchOtherPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(\"foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar/\");\n\t}\n\n\t@Test\n\tvoid toLinksShouldOnlyMatchLinks() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toLinks();\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t\tassertMatcher(matcher).matches(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid toLinksWhenBasePathEmptyShouldNotMatch() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toLinks();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, \"\");\n\t\tassertMatcher.doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher.doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t}\n\n\t@Test\n\tvoid toLinksWhenBasePathEmptyAndManagementPortDifferentShouldMatchRoot() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toLinks();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(\"\"),\n\t\t\t\tWebServerNamespace.MANAGEMENT);\n\t\tassertMatcher.matches(\"/\");\n\t\tassertMatcher.doesNotMatch(\"/foo\");\n\t}\n\n\t@Test\n\tvoid excludeByClassShouldNotMatchExcluded() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint()\n\t\t\t.excluding(FooEndpoint.class, BazServletEndpoint.class);\n\t\tList<ExposableEndpoint<?>> endpoints = new ArrayList<>();\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"foo\"), \"foo\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"bar\"), \"bar\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"baz\"), \"baz\"));\n\t\tPathMappedEndpoints pathMappedEndpoints = new PathMappedEndpoints(\"/actuator\", () -> endpoints);\n\t\tassertMatcher(matcher, pathMappedEndpoints).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher, pathMappedEndpoints).doesNotMatch(\"/actuator/foo/\");\n\t\tassertMatcher(matcher, pathMappedEndpoints).doesNotMatch(\"/actuator/baz\");\n\t\tassertMatcher(matcher, pathMappedEndpoints).doesNotMatch(\"/actuator/baz/\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar/\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t\tassertMatcher(matcher).matches(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid excludeByClassShouldNotMatchLinksIfExcluded() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint()\n\t\t\t.excludingLinks()\n\t\t\t.excluding(FooEndpoint.class);\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo/\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid excludeByIdShouldNotMatchExcluded() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(\"foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo/\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar/\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t\tassertMatcher(matcher).matches(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid excludeByIdShouldNotMatchLinksIfExcluded() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks().excluding(\"foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo/\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid excludeLinksShouldNotMatchBasePath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks();\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo/\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar/\");\n\t}\n\n\t@Test\n\tvoid excludeLinksShouldNotMatchBasePathIfEmptyAndExcluded() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, \"\");\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t\tassertMatcher.matches(\"/foo\");\n\t\tassertMatcher.matches(\"/foo/\");\n\t\tassertMatcher.matches(\"/bar\");\n\t\tassertMatcher.matches(\"/bar/\");\n\t}\n\n\t@Test\n\tvoid noEndpointPathsBeansShouldNeverMatch() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch(\"/actuator/foo/\");\n\t\tassertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch(\"/actuator/bar/\");\n\t}\n\n\t@Test\n\tvoid toStringWhenIncludedEndpoints() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(\"foo\", \"bar\");\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[foo, bar], excludes=[], includeLinks=false\");\n\t}\n\n\t@Test\n\tvoid toStringWhenEmptyIncludedEndpoints() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[*], excludes=[], includeLinks=true\");\n\t}\n\n\t@Test\n\tvoid toStringWhenIncludedEndpointsClasses() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(FooEndpoint.class).excluding(\"bar\");\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[foo], excludes=[bar], includeLinks=false\");\n\t}\n\n\t@Test\n\tvoid toStringWhenIncludedExcludedEndpoints() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(\"bar\").excludingLinks();\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[*], excludes=[bar], includeLinks=false\");\n\t}\n\n\t@Test\n\tvoid toStringWhenToAdditionalPaths() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, \"test\");\n\t\tassertThat(matcher)\n\t\t\t.hasToString(\"AdditionalPathsEndpointServerWebExchangeMatcher endpoints=[test], webServerNamespace=server\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenEndpointPathMappedToRootIsExcludedShouldNotMatchRoot() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(\"root\");\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"/\", () -> List\n\t\t\t.of(mockEndpoint(EndpointId.of(\"root\"), \"/\"), mockEndpoint(EndpointId.of(\"alpha\"), \"alpha\"))));\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t\tassertMatcher.matches(\"/alpha\");\n\t\tassertMatcher.matches(\"/alpha/sub\");\n\t}\n\n\t@Test\n\tvoid toEndpointWhenEndpointPathMappedToRootShouldMatchRoot() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.to(\"root\");\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher,\n\t\t\t\tnew PathMappedEndpoints(\"/\", () -> List.of(mockEndpoint(EndpointId.of(\"root\"), \"/\"))));\n\t\tassertMatcher.matches(\"/\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointClassShouldMatchAdditionalPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\tFooEndpoint.class);\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))));\n\t\tassertMatcher.matches(\"/additional\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointIdShouldMatchAdditionalPath() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, \"foo\");\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))));\n\t\tassertMatcher.matches(\"/additional\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointClassShouldNotMatchOtherPaths() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\tFooEndpoint.class);\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))));\n\t\tassertMatcher.doesNotMatch(\"/additional/foo\");\n\t\tassertMatcher.doesNotMatch(\"/foo\");\n\t\tassertMatcher.doesNotMatch(\"/bar\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointClassShouldNotMatchOtherNamespace() {\n\t\tServerWebExchangeMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\tFooEndpoint.class);\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))),\n\t\t\t\tWebServerNamespace.MANAGEMENT);\n\t\tassertMatcher.doesNotMatch(\"/additional\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher) {\n\t\treturn assertMatcher(matcher, mockPathMappedEndpoints(\"/actuator\"));\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher, String basePath) {\n\t\treturn assertMatcher(matcher, mockPathMappedEndpoints(basePath));\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,\n\t\t\t@Nullable PathMappedEndpoints pathMappedEndpoints) {\n\t\treturn assertMatcher(matcher, pathMappedEndpoints, null);\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,\n\t\t\t@Nullable PathMappedEndpoints pathMappedEndpoints, @Nullable WebServerNamespace namespace) {\n\t\tStaticWebApplicationContext context;\n\t\tif (namespace != null && !WebServerNamespace.SERVER.equals(namespace)) {\n\t\t\tcontext = new NamedStaticWebApplicationContext(namespace);\n\t\t\tcontext.setParent(new StaticWebApplicationContext());\n\t\t\tTestPropertyValues.of(\"management.server.port=0\").applyTo(context);\n\t\t}\n\t\telse {\n\t\t\tcontext = new StaticWebApplicationContext();\n\t\t}\n\t\tcontext.registerBean(WebEndpointProperties.class);\n\t\tif (pathMappedEndpoints != null) {\n\t\t\tcontext.registerBean(PathMappedEndpoints.class, () -> pathMappedEndpoints);\n\t\t\tWebEndpointProperties properties = context.getBean(WebEndpointProperties.class);\n\t\t\tif (!properties.getBasePath().equals(pathMappedEndpoints.getBasePath())) {\n\t\t\t\tproperties.setBasePath(pathMappedEndpoints.getBasePath());\n\t\t\t}\n\t\t}\n\t\treturn assertThat(new RequestMatcherAssert(context, matcher));\n\t}\n\n\tprivate PathMappedEndpoints mockPathMappedEndpoints(String basePath) {\n\t\tList<ExposableEndpoint<?>> endpoints = new ArrayList<>();\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"foo\"), \"foo\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"bar\"), \"bar\"));\n\t\treturn new PathMappedEndpoints(basePath, () -> endpoints);\n\t}\n\n\tprivate TestEndpoint mockEndpoint(EndpointId id, String rootPath) {\n\t\treturn mockEndpoint(id, rootPath, WebServerNamespace.SERVER);\n\t}\n\n\tprivate TestEndpoint mockEndpoint(EndpointId id, String rootPath, WebServerNamespace webServerNamespace,\n\t\t\tString... additionalPaths) {\n\t\tTestEndpoint endpoint = mock(TestEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\tgiven(endpoint.getRootPath()).willReturn(rootPath);\n\t\tgiven(endpoint.getAdditionalPaths(webServerNamespace)).willReturn(Arrays.asList(additionalPaths));\n\t\treturn endpoint;\n\t}\n\n\tstatic class NamedStaticWebApplicationContext extends StaticWebApplicationContext\n\t\t\timplements WebServerApplicationContext {\n\n\t\tprivate final WebServerNamespace webServerNamespace;\n\n\t\tNamedStaticWebApplicationContext(WebServerNamespace webServerNamespace) {\n\t\t\tthis.webServerNamespace = webServerNamespace;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable WebServer getWebServer() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getServerNamespace() {\n\t\t\treturn (this.webServerNamespace != null) ? this.webServerNamespace.getValue() : null;\n\t\t}\n\n\t}\n\n\tstatic class RequestMatcherAssert implements AssertDelegateTarget {\n\n\t\tprivate final StaticApplicationContext context;\n\n\t\tprivate final ServerWebExchangeMatcher matcher;\n\n\t\tRequestMatcherAssert(StaticApplicationContext context, ServerWebExchangeMatcher matcher) {\n\t\t\tthis.context = context;\n\t\t\tthis.matcher = matcher;\n\t\t}\n\n\t\tvoid matches(String path) {\n\t\t\tServerWebExchange exchange = webHandler().createExchange(MockServerHttpRequest.get(path).build(),\n\t\t\t\t\tnew MockServerHttpResponse());\n\t\t\tmatches(exchange);\n\t\t}\n\n\t\tvoid matches(HttpMethod httpMethod, String path) {\n\t\t\tServerWebExchange exchange = webHandler()\n\t\t\t\t.createExchange(MockServerHttpRequest.method(httpMethod, path).build(), new MockServerHttpResponse());\n\t\t\tmatches(exchange);\n\t\t}\n\n\t\tprivate void matches(ServerWebExchange exchange) {\n\t\t\tMatchResult result = this.matcher.matches(exchange).block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).isNotNull();\n\t\t\tassertThat(result.isMatch()).as(\"Matches \" + getRequestPath(exchange)).isTrue();\n\t\t}\n\n\t\tvoid doesNotMatch(String path) {\n\t\t\tServerWebExchange exchange = webHandler().createExchange(MockServerHttpRequest.get(path).build(),\n\t\t\t\t\tnew MockServerHttpResponse());\n\t\t\tdoesNotMatch(exchange);\n\t\t}\n\n\t\tvoid doesNotMatch(HttpMethod httpMethod, String path) {\n\t\t\tServerWebExchange exchange = webHandler()\n\t\t\t\t.createExchange(MockServerHttpRequest.method(httpMethod, path).build(), new MockServerHttpResponse());\n\t\t\tdoesNotMatch(exchange);\n\t\t}\n\n\t\tprivate void doesNotMatch(ServerWebExchange exchange) {\n\t\t\tMatchResult result = this.matcher.matches(exchange).block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).isNotNull();\n\t\t\tassertThat(result.isMatch()).as(\"Does not match \" + getRequestPath(exchange)).isFalse();\n\t\t}\n\n\t\tprivate TestHttpWebHandlerAdapter webHandler() {\n\t\t\tTestHttpWebHandlerAdapter adapter = new TestHttpWebHandlerAdapter(mock(WebHandler.class));\n\t\t\tadapter.setApplicationContext(this.context);\n\t\t\treturn adapter;\n\t\t}\n\n\t\tprivate String getRequestPath(ServerWebExchange exchange) {\n\t\t\treturn exchange.getRequest().getPath().toString();\n\t\t}\n\n\t}\n\n\tstatic class TestHttpWebHandlerAdapter extends HttpWebHandlerAdapter {\n\n\t\tTestHttpWebHandlerAdapter(WebHandler delegate) {\n\t\t\tsuper(delegate);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\treturn super.createExchange(request, response);\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"foo\")\n\tstatic class FooEndpoint {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"baz\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class BazServletEndpoint {\n\n\t}\n\n\tinterface TestEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/reactive/ReactiveManagementWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.reactive;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.http.server.reactive.MockServerHttpResponse;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterChainProxy;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebHandler;\nimport org.springframework.web.server.adapter.HttpWebHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for {@link ReactiveManagementWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n */\nclass ReactiveManagementWebSecurityAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tInfoEndpointAutoConfiguration.class, WebFluxAutoConfiguration.class,\n\t\t\t\tEnvironmentEndpointAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, ReactiveWebSecurityAutoConfiguration.class,\n\t\t\t\tReactiveManagementWebSecurityAutoConfiguration.class));\n\n\t@Test\n\tvoid permitAllForHealth() {\n\t\tthis.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(getAuthenticateHeader(context, \"/actuator/health\")).isNull());\n\t}\n\n\t@Test\n\tvoid withAdditionalPathsOnSamePort() {\n\t\tthis.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.test1.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.test2.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.test1.additional-path=server:/check1\",\n\t\t\t\t\t\"management.endpoint.health.group.test2.additional-path=management:/check2\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getAuthenticateHeader(context, \"/check1\")).isNull();\n\t\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/check2\").get(0)).contains(\"Basic realm=\");\n\t\t\t\tassertThat(getAuthenticateHeader(context, \"/actuator/health\")).isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withAdditionalPathsOnDifferentPort() {\n\t\tthis.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.test1.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.test2.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.test1.additional-path=server:/check1\",\n\t\t\t\t\t\"management.endpoint.health.group.test2.additional-path=management:/check2\",\n\t\t\t\t\t\"management.server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getAuthenticateHeader(context, \"/check1\")).isNull();\n\t\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/check2\").get(0)).contains(\"Basic realm=\");\n\t\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/actuator/health\").get(0)).contains(\"Basic realm=\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid securesEverythingElse() {\n\t\tthis.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class).run((context) -> {\n\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/actuator\").get(0)).contains(\"Basic realm=\");\n\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/foo\").toString()).contains(\"Basic realm=\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid noExistingAuthenticationManagerOrUserDetailsService() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(getAuthenticateHeader(context, \"/actuator/health\")).isNull();\n\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/actuator\").get(0)).contains(\"Basic realm=\");\n\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/foo\").toString()).contains(\"Basic realm=\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid usesMatchersBasedOffConfiguredActuatorBasePath() {\n\t\tthis.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.base-path=/\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getAuthenticateHeader(context, \"/health\")).isNull();\n\t\t\t\tassertThat(getRequiredAuthenticateHeader(context, \"/foo\").get(0)).contains(\"Basic realm=\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffIfCustomSecurityIsAdded() {\n\t\tthis.contextRunner.withUserConfiguration(CustomSecurityConfiguration.class).run((context) -> {\n\t\t\tassertThat(getRequiredLocationHeader(context, \"/actuator/health\").toString()).contains(\"/login\");\n\t\t\tassertThat(getLocationHeader(context, \"/foo\")).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffWhenWebFilterChainProxyBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(WebFilterChainProxyConfiguration.class).run((context) -> {\n\t\t\tassertThat(getRequiredLocationHeader(context, \"/actuator/health\").toString()).contains(\"/login\");\n\t\t\tassertThat(getRequiredLocationHeader(context, \"/foo\").toString()).contains(\"/login\");\n\t\t});\n\t}\n\n\tprivate @Nullable List<String> getAuthenticateHeader(AssertableReactiveWebApplicationContext context, String path) {\n\t\tServerWebExchange exchange = performFilter(context, path);\n\t\treturn exchange.getResponse().getHeaders().get(HttpHeaders.WWW_AUTHENTICATE);\n\t}\n\n\tprivate List<String> getRequiredAuthenticateHeader(AssertableReactiveWebApplicationContext context, String path) {\n\t\tList<String> header = getAuthenticateHeader(context, path);\n\t\tassertThat(header).isNotNull();\n\t\treturn header;\n\t}\n\n\tprivate ServerWebExchange performFilter(AssertableReactiveWebApplicationContext context, String path) {\n\t\tServerWebExchange exchange = webHandler(context).createExchange(MockServerHttpRequest.get(path).build(),\n\t\t\t\tnew MockServerHttpResponse());\n\t\tWebFilterChainProxy proxy = context.getBean(WebFilterChainProxy.class);\n\t\tproxy.filter(exchange, (serverWebExchange) -> Mono.empty()).block(Duration.ofSeconds(30));\n\t\treturn exchange;\n\t}\n\n\tprivate @Nullable URI getLocationHeader(AssertableReactiveWebApplicationContext context, String path) {\n\t\tServerWebExchange exchange = performFilter(context, path);\n\t\treturn exchange.getResponse().getHeaders().getLocation();\n\t}\n\n\tprivate URI getRequiredLocationHeader(AssertableReactiveWebApplicationContext context, String path) {\n\t\tURI header = getLocationHeader(context, path);\n\t\tassertThat(header).isNotNull();\n\t\treturn header;\n\t}\n\n\tprivate TestHttpWebHandlerAdapter webHandler(AssertableReactiveWebApplicationContext context) {\n\t\tTestHttpWebHandlerAdapter adapter = new TestHttpWebHandlerAdapter(mock(WebHandler.class));\n\t\tadapter.setApplicationContext(context);\n\t\treturn adapter;\n\t}\n\n\tstatic class TestHttpWebHandlerAdapter extends HttpWebHandlerAdapter {\n\n\t\tTestHttpWebHandlerAdapter(WebHandler delegate) {\n\t\t\tsuper(delegate);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\treturn super.createExchange(request, response);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDetailsServiceConfiguration {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withUsername(\"alice\").password(\"secret\").roles(\"admin\").build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\t\thttp.authorizeExchange((exchanges) -> {\n\t\t\t\texchanges.pathMatchers(\"/foo\").permitAll();\n\t\t\t\texchanges.anyExchange().authenticated();\n\t\t\t});\n\t\t\thttp.formLogin(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t\t@Bean\n\t\tReactiveAuthenticationManager authenticationManager() {\n\t\t\treturn mock(ReactiveAuthenticationManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebFilterChainProxyConfiguration {\n\n\t\t@Bean\n\t\tReactiveAuthenticationManager authenticationManager() {\n\t\t\treturn mock(ReactiveAuthenticationManager.class);\n\t\t}\n\n\t\t@Bean\n\t\tWebFilterChainProxy webFilterChainProxy(ServerHttpSecurity http) {\n\t\t\treturn new WebFilterChainProxy(getFilterChains(http));\n\t\t}\n\n\t\t@Bean\n\t\tTestServerHttpSecurity http(ReactiveAuthenticationManager authenticationManager) {\n\t\t\tTestServerHttpSecurity httpSecurity = new TestServerHttpSecurity();\n\t\t\thttpSecurity.authenticationManager(authenticationManager);\n\t\t\treturn httpSecurity;\n\t\t}\n\n\t\tprivate List<SecurityWebFilterChain> getFilterChains(ServerHttpSecurity http) {\n\t\t\thttp.authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated());\n\t\t\thttp.formLogin(withDefaults());\n\t\t\treturn Collections.singletonList(http.build());\n\t\t}\n\n\t\tstatic class TestServerHttpSecurity extends ServerHttpSecurity implements ApplicationContextAware {\n\n\t\t\t@Override\n\t\t\tpublic void setApplicationContext(ApplicationContext applicationContext) {\n\t\t\t\tsuper.setApplicationContext(applicationContext);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/AbstractEndpointRequestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.Base64;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.WriteOperation;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Abstract base class for {@link EndpointRequest} tests.\n *\n * @author Madhura Bhave\n * @author Chris Bono\n */\nabstract class AbstractEndpointRequestIntegrationTests {\n\n\t@Test\n\tvoid toEndpointShouldMatch() {\n\t\tgetContextRunner().run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/actuator/e1\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toEndpointPostShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.security.user.password=password\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.post().uri(\"/actuator/e1\").exchange().expectStatus().isUnauthorized();\n\t\t\twebTestClient.post()\n\t\t\t\t.uri(\"/actuator/e1\")\n\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNoContent();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toAllEndpointsShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.security.user.password=password\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/actuator/e2\").exchange().expectStatus().isUnauthorized();\n\t\t\twebTestClient.get()\n\t\t\t\t.uri(\"/actuator/e2\")\n\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toLinksShouldMatch() {\n\t\tgetContextRunner().run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/actuator\").exchange().expectStatus().isOk();\n\t\t\twebTestClient.get()\n\t\t\t\t.uri(\"/actuator/\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(expectedStatusWithTrailingSlash());\n\t\t});\n\t}\n\n\tprotected HttpStatus expectedStatusWithTrailingSlash() {\n\t\treturn HttpStatus.NOT_FOUND;\n\t}\n\n\tprotected final WebApplicationContextRunner getContextRunner() {\n\t\treturn createContextRunner().withPropertyValues(\"management.endpoints.web.exposure.include=*\")\n\t\t\t.withUserConfiguration(BaseConfiguration.class, SecurityConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, SecurityAutoConfiguration.class,\n\t\t\t\t\tServletWebSecurityAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\t\tWebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class));\n\n\t}\n\n\tprotected abstract WebApplicationContextRunner createContextRunner();\n\n\tprotected WebTestClient getWebTestClient(AssertableWebApplicationContext context) {\n\t\tWebServer webServer = context\n\t\t\t.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)\n\t\t\t.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tint port = webServer.getPort();\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\tString getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tTestEndpoint1 endpoint1() {\n\t\t\treturn new TestEndpoint1();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint2 endpoint2() {\n\t\t\treturn new TestEndpoint2();\n\t\t}\n\n\t\t@Bean\n\t\tTestEndpoint3 endpoint3() {\n\t\t\treturn new TestEndpoint3();\n\t\t}\n\n\t\t@Bean\n\t\tTestServletEndpoint servletEndpoint() {\n\t\t\treturn new TestServletEndpoint();\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"e1\")\n\tstatic class TestEndpoint1 {\n\n\t\t@ReadOperation\n\t\tObject getAll() {\n\t\t\treturn \"endpoint 1\";\n\t\t}\n\n\t\t@WriteOperation\n\t\tvoid setAll() {\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"e2\")\n\tstatic class TestEndpoint2 {\n\n\t\t@ReadOperation\n\t\tObject getAll() {\n\t\t\treturn \"endpoint 2\";\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"e3\")\n\tstatic class TestEndpoint3 {\n\n\t\t@ReadOperation\n\t\t@Nullable Object getAll() {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"se1\")\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic class TestServletEndpoint\n\t\t\timplements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {\n\n\t\t@Override\n\t\tpublic org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {\n\t\t\treturn new org.springframework.boot.actuate.endpoint.web.EndpointServlet(ExampleServlet.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tInMemoryUserDetailsManager userDetailsManager() {\n\t\t\treturn new InMemoryUserDetailsManager(\n\t\t\t\t\tUser.withUsername(\"user\").password(\"{noop}password\").roles(\"admin\").build());\n\t\t}\n\n\t\t@Bean\n\t\tSecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(EndpointRequest.toLinks()).permitAll();\n\t\t\t\trequests.requestMatchers(EndpointRequest.to(TestEndpoint1.class).withHttpMethod(HttpMethod.POST))\n\t\t\t\t\t.authenticated();\n\t\t\t\trequests.requestMatchers(EndpointRequest.to(TestEndpoint1.class)).permitAll();\n\t\t\t\trequests.requestMatchers(EndpointRequest.toAnyEndpoint()).authenticated();\n\t\t\t\trequests.anyRequest().hasRole(\"ADMIN\");\n\t\t\t});\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\tstatic class ExampleServlet extends HttpServlet {\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/EndpointRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.assertj.core.api.AssertDelegateTarget;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.Operation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest.AdditionalPathsEndpointRequestMatcher;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest.EndpointRequestMatcher;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.StaticWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link EndpointRequest}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Chris Bono\n */\nclass EndpointRequestTests {\n\n\t@Test\n\tvoid toAnyEndpointShouldMatchEndpointPath() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/foo/zoo/\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/bar/baz\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWithHttpMethodShouldRespectRequestMethod() {\n\t\tEndpointRequest.EndpointRequestMatcher matcher = EndpointRequest.toAnyEndpoint()\n\t\t\t.withHttpMethod(HttpMethod.POST);\n\t\tassertMatcher(matcher, \"/actuator\").matches(HttpMethod.POST, \"/actuator/foo\");\n\t\tassertMatcher(matcher, \"/actuator\").doesNotMatch(HttpMethod.GET, \"/actuator/foo\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/foo/\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/bar/\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenBasePathIsEmptyShouldNotMatchLinks() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, \"\");\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t\tassertMatcher.matches(\"/foo\");\n\t\tassertMatcher.matches(\"/bar\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenBasePathIsEmptyAndManagementPortDifferentShouldMatchLinks() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(\"\"), null,\n\t\t\t\tWebServerNamespace.MANAGEMENT);\n\t\tassertMatcher.matches(\"/\");\n\t\tassertMatcher.matches(\"/foo\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointShouldNotMatchOtherPath() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/baz\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenDispatcherServletPathProviderNotAvailableUsesEmptyPath() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher, \"/actuator\").matches(\"/actuator\");\n\t\tassertMatcher(matcher, \"/actuator\").doesNotMatch(\"/actuator/baz\");\n\t}\n\n\t@Test\n\tvoid toEndpointClassShouldMatchEndpointPath() {\n\t\tRequestMatcher matcher = EndpointRequest.to(FooEndpoint.class);\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t}\n\n\t@Test\n\tvoid toEndpointClassShouldNotMatchOtherPath() {\n\t\tRequestMatcher matcher = EndpointRequest.to(FooEndpoint.class);\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid toEndpointIdShouldMatchEndpointPath() {\n\t\tRequestMatcher matcher = EndpointRequest.to(\"foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t}\n\n\t@Test\n\tvoid toEndpointIdShouldNotMatchOtherPath() {\n\t\tRequestMatcher matcher = EndpointRequest.to(\"foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid toLinksShouldOnlyMatchLinks() {\n\t\tRequestMatcher matcher = EndpointRequest.toLinks();\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t\tassertMatcher(matcher).matches(\"/actuator/\");\n\t}\n\n\t@Test\n\tvoid toLinksWhenBasePathEmptyShouldNotMatch() {\n\t\tRequestMatcher matcher = EndpointRequest.toLinks();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, \"\");\n\t\tassertMatcher.doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher.doesNotMatch(\"/actuator/bar\");\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t}\n\n\t@Test\n\tvoid toLinksWhenBasePathEmptyAndManagementPortDifferentShouldMatchRoot() {\n\t\tRequestMatcher matcher = EndpointRequest.toLinks();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(\"\"), null,\n\t\t\t\tWebServerNamespace.MANAGEMENT);\n\t\tassertMatcher.matches(\"/\");\n\t\tassertMatcher.doesNotMatch(\"/foo\");\n\t}\n\n\t@Test\n\tvoid excludeByClassShouldNotMatchExcluded() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(FooEndpoint.class, BazServletEndpoint.class);\n\t\tList<ExposableEndpoint<?>> endpoints = new ArrayList<>();\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"foo\"), \"foo\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"bar\"), \"bar\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"baz\"), \"baz\"));\n\t\tPathMappedEndpoints pathMappedEndpoints = new PathMappedEndpoints(\"/actuator\", () -> endpoints);\n\t\tassertMatcher(matcher, pathMappedEndpoints).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher, pathMappedEndpoints).doesNotMatch(\"/actuator/baz\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid excludeByClassShouldNotMatchLinksIfExcluded() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks().excluding(FooEndpoint.class);\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid excludeByIdShouldNotMatchExcluded() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(\"foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t\tassertMatcher(matcher).matches(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid excludeByIdShouldNotMatchLinksIfExcluded() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks().excluding(\"foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid excludeLinksShouldNotMatchBasePath() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks();\n\t\tassertMatcher(matcher).doesNotMatch(\"/actuator\");\n\t\tassertMatcher(matcher).matches(\"/actuator/foo\");\n\t\tassertMatcher(matcher).matches(\"/actuator/bar\");\n\t}\n\n\t@Test\n\tvoid excludeLinksShouldNotMatchBasePathIfEmptyAndExcluded() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excludingLinks();\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, \"\");\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t\tassertMatcher.matches(\"/foo\");\n\t\tassertMatcher.matches(\"/bar\");\n\t}\n\n\t@Test\n\tvoid endpointRequestMatcherShouldUseCustomRequestMatcherProvider() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tRequestMatcher mockRequestMatcher = (request) -> false;\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(\"\"),\n\t\t\t\t(pattern, method) -> mockRequestMatcher, null);\n\t\tassertMatcher.doesNotMatch(\"/foo\");\n\t\tassertMatcher.doesNotMatch(\"/bar\");\n\t}\n\n\t@Test\n\tvoid linksRequestMatcherShouldUseCustomRequestMatcherProvider() {\n\t\tRequestMatcher matcher = EndpointRequest.toLinks();\n\t\tRequestMatcher mockRequestMatcher = (request) -> false;\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(\"/actuator\"),\n\t\t\t\t(pattern, method) -> mockRequestMatcher, null);\n\t\tassertMatcher.doesNotMatch(\"/actuator\");\n\t}\n\n\t@Test\n\tvoid noEndpointPathsBeansShouldNeverMatch() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch(\"/actuator/foo\");\n\t\tassertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch(\"/actuator/bar\");\n\t}\n\n\t@Test\n\tvoid toStringWhenIncludedEndpoints() {\n\t\tRequestMatcher matcher = EndpointRequest.to(\"foo\", \"bar\");\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[foo, bar], excludes=[], includeLinks=false\");\n\t}\n\n\t@Test\n\tvoid toStringWhenEmptyIncludedEndpoints() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint();\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[*], excludes=[], includeLinks=true\");\n\t}\n\n\t@Test\n\tvoid toStringWhenIncludedEndpointsClasses() {\n\t\tRequestMatcher matcher = EndpointRequest.to(FooEndpoint.class).excluding(\"bar\");\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[foo], excludes=[bar], includeLinks=false\");\n\t}\n\n\t@Test\n\tvoid toStringWhenIncludedExcludedEndpoints() {\n\t\tRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(\"bar\").excludingLinks();\n\t\tassertThat(matcher).hasToString(\"EndpointRequestMatcher includes=[*], excludes=[bar], includeLinks=false\");\n\t}\n\n\t@Test\n\tvoid toStringWhenToAdditionalPaths() {\n\t\tRequestMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER, \"test\");\n\t\tassertThat(matcher)\n\t\t\t.hasToString(\"AdditionalPathsEndpointRequestMatcher endpoints=[test], webServerNamespace=server\");\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenEndpointPathMappedToRootIsExcludedShouldNotMatchRoot() {\n\t\tEndpointRequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(\"root\");\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\", () -> List\n\t\t\t.of(mockEndpoint(EndpointId.of(\"root\"), \"/\"), mockEndpoint(EndpointId.of(\"alpha\"), \"alpha\"))));\n\t\tassertMatcher.doesNotMatch(\"/\");\n\t\tassertMatcher.matches(\"/alpha\");\n\t\tassertMatcher.matches(\"/alpha/sub\");\n\t}\n\n\t@Test\n\tvoid toEndpointWhenEndpointPathMappedToRootShouldMatchRoot() {\n\t\tEndpointRequestMatcher matcher = EndpointRequest.to(\"root\");\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher,\n\t\t\t\tnew PathMappedEndpoints(\"\", () -> List.of(mockEndpoint(EndpointId.of(\"root\"), \"/\"))));\n\t\tassertMatcher.matches(\"/\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointClassShouldMatchAdditionalPath() {\n\t\tAdditionalPathsEndpointRequestMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\tFooEndpoint.class);\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))));\n\t\tassertMatcher.matches(\"/additional\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointIdShouldMatchAdditionalPath() {\n\t\tAdditionalPathsEndpointRequestMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\t\"foo\");\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))));\n\t\tassertMatcher.matches(\"/additional\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointClassShouldNotMatchOtherPaths() {\n\t\tAdditionalPathsEndpointRequestMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\tFooEndpoint.class);\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))));\n\t\tassertMatcher.doesNotMatch(\"/additional/foo\");\n\t\tassertMatcher.doesNotMatch(\"/foo\");\n\t\tassertMatcher.doesNotMatch(\"/bar\");\n\t}\n\n\t@Test\n\tvoid toAdditionalPathsWithEndpointClassShouldNotMatchOtherNamespace() {\n\t\tAdditionalPathsEndpointRequestMatcher matcher = EndpointRequest.toAdditionalPaths(WebServerNamespace.SERVER,\n\t\t\t\tFooEndpoint.class);\n\t\tRequestMatcherAssert assertMatcher = assertMatcher(matcher, new PathMappedEndpoints(\"\",\n\t\t\t\t() -> List.of(mockEndpoint(EndpointId.of(\"foo\"), \"test\", WebServerNamespace.SERVER, \"/additional\"))),\n\t\t\t\tnull, WebServerNamespace.MANAGEMENT);\n\t\tassertMatcher.doesNotMatch(\"/additional\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher) {\n\t\treturn assertMatcher(matcher, mockPathMappedEndpoints(\"/actuator\"));\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath) {\n\t\treturn assertMatcher(matcher, mockPathMappedEndpoints(basePath), null, null);\n\t}\n\n\tprivate PathMappedEndpoints mockPathMappedEndpoints(String basePath) {\n\t\tList<ExposableEndpoint<?>> endpoints = new ArrayList<>();\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"foo\"), \"foo\"));\n\t\tendpoints.add(mockEndpoint(EndpointId.of(\"bar\"), \"bar\"));\n\t\treturn new PathMappedEndpoints(basePath, () -> endpoints);\n\t}\n\n\tprivate TestEndpoint mockEndpoint(EndpointId id, String rootPath) {\n\t\treturn mockEndpoint(id, rootPath, WebServerNamespace.SERVER);\n\t}\n\n\tprivate TestEndpoint mockEndpoint(EndpointId id, String rootPath, WebServerNamespace webServerNamespace,\n\t\t\tString... additionalPaths) {\n\t\tTestEndpoint endpoint = mock(TestEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\tgiven(endpoint.getRootPath()).willReturn(rootPath);\n\t\tgiven(endpoint.getAdditionalPaths(webServerNamespace)).willReturn(Arrays.asList(additionalPaths));\n\t\treturn endpoint;\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher,\n\t\t\t@Nullable PathMappedEndpoints pathMappedEndpoints) {\n\t\treturn assertMatcher(matcher, pathMappedEndpoints, null, null);\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher,\n\t\t\t@Nullable PathMappedEndpoints pathMappedEndpoints, @Nullable RequestMatcherProvider matcherProvider,\n\t\t\t@Nullable WebServerNamespace namespace) {\n\t\tStaticWebApplicationContext context;\n\t\tif (namespace != null && !WebServerNamespace.SERVER.equals(namespace)) {\n\t\t\tcontext = new NamedStaticWebApplicationContext(namespace);\n\t\t\tcontext.setParent(new StaticWebApplicationContext());\n\t\t\tTestPropertyValues.of(\"management.server.port=0\").applyTo(context);\n\t\t}\n\t\telse {\n\t\t\tcontext = new StaticWebApplicationContext();\n\t\t}\n\t\tcontext.registerBean(WebEndpointProperties.class);\n\t\tif (pathMappedEndpoints != null) {\n\t\t\tcontext.registerBean(PathMappedEndpoints.class, () -> pathMappedEndpoints);\n\t\t\tWebEndpointProperties properties = context.getBean(WebEndpointProperties.class);\n\t\t\tif (!properties.getBasePath().equals(pathMappedEndpoints.getBasePath())) {\n\t\t\t\tproperties.setBasePath(pathMappedEndpoints.getBasePath());\n\t\t\t}\n\t\t}\n\t\tif (matcherProvider != null) {\n\t\t\tcontext.registerBean(RequestMatcherProvider.class, () -> matcherProvider);\n\t\t}\n\t\treturn assertThat(new RequestMatcherAssert(context, matcher));\n\t}\n\n\tstatic class NamedStaticWebApplicationContext extends StaticWebApplicationContext\n\t\t\timplements WebServerApplicationContext {\n\n\t\tprivate final WebServerNamespace webServerNamespace;\n\n\t\tNamedStaticWebApplicationContext(WebServerNamespace webServerNamespace) {\n\t\t\tthis.webServerNamespace = webServerNamespace;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable WebServer getWebServer() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getServerNamespace() {\n\t\t\treturn (this.webServerNamespace != null) ? this.webServerNamespace.getValue() : null;\n\t\t}\n\n\t}\n\n\tstatic class RequestMatcherAssert implements AssertDelegateTarget {\n\n\t\tprivate final WebApplicationContext context;\n\n\t\tprivate final RequestMatcher matcher;\n\n\t\tRequestMatcherAssert(WebApplicationContext context, RequestMatcher matcher) {\n\t\t\tthis.context = context;\n\t\t\tthis.matcher = matcher;\n\t\t}\n\n\t\tvoid matches(String servletPath) {\n\t\t\tmatches(mockRequest(null, servletPath));\n\t\t}\n\n\t\tvoid matches(HttpMethod httpMethod, String servletPath) {\n\t\t\tmatches(mockRequest(httpMethod, servletPath));\n\t\t}\n\n\t\tprivate void matches(HttpServletRequest request) {\n\t\t\tassertThat(this.matcher.matches(request)).as(\"Matches \" + getRequestPath(request)).isTrue();\n\t\t}\n\n\t\tvoid doesNotMatch(String requestUri) {\n\t\t\tdoesNotMatch(mockRequest(null, requestUri));\n\t\t}\n\n\t\tvoid doesNotMatch(HttpMethod httpMethod, String requestUri) {\n\t\t\tdoesNotMatch(mockRequest(httpMethod, requestUri));\n\t\t}\n\n\t\tprivate void doesNotMatch(HttpServletRequest request) {\n\t\t\tassertThat(this.matcher.matches(request)).as(\"Does not match \" + getRequestPath(request)).isFalse();\n\t\t}\n\n\t\tprivate MockHttpServletRequest mockRequest(@Nullable HttpMethod httpMethod, @Nullable String requestUri) {\n\t\t\tMockServletContext servletContext = new MockServletContext();\n\t\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest(servletContext);\n\t\t\tif (requestUri != null) {\n\t\t\t\trequest.setRequestURI(requestUri);\n\t\t\t}\n\t\t\tif (httpMethod != null) {\n\t\t\t\trequest.setMethod(httpMethod.name());\n\t\t\t}\n\t\t\treturn request;\n\t\t}\n\n\t\tprivate String getRequestPath(HttpServletRequest request) {\n\t\t\tString url = request.getServletPath();\n\t\t\tif (request.getPathInfo() != null) {\n\t\t\t\turl += request.getPathInfo();\n\t\t\t}\n\t\t\treturn url;\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"foo\")\n\tstatic class FooEndpoint {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"baz\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class BazServletEndpoint {\n\n\t}\n\n\tinterface TestEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/JerseyEndpointRequestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.glassfish.jersey.server.ResourceConfig;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jersey.autoconfigure.JerseyAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link EndpointRequest} with Jersey.\n *\n * @author Madhura Bhave\n */\nclass JerseyEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrationTests {\n\n\t@Test\n\tvoid toLinksWhenApplicationPathSetShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.jersey.application-path=/admin\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get()\n\t\t\t\t.uri(\"/admin/actuator/\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(expectedStatusWithTrailingSlash());\n\t\t\twebTestClient.get().uri(\"/admin/actuator\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toEndpointWhenApplicationPathSetShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.jersey.application-path=/admin\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/admin/actuator/e1\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenApplicationPathSetShouldMatch() {\n\t\tgetContextRunner()\n\t\t\t.withPropertyValues(\"spring.jersey.application-path=/admin\", \"spring.security.user.password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\t\twebTestClient.get().uri(\"/admin/actuator/e2\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/admin/actuator/e2\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid toAnyEndpointShouldMatchServletEndpoint() {\n\t\tgetContextRunner()\n\t\t\t.withPropertyValues(\"spring.security.user.password=password\",\n\t\t\t\t\t\"management.endpoints.web.exposure.include=se1\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\t\twebTestClient.get().uri(\"/actuator/se1\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/actuator/se1\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t\twebTestClient.get().uri(\"/actuator/se1/list\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/actuator/se1/list\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenApplicationPathSetShouldMatchServletEndpoint() {\n\t\tgetContextRunner()\n\t\t\t.withPropertyValues(\"spring.jersey.application-path=/admin\", \"spring.security.user.password=password\",\n\t\t\t\t\t\"management.endpoints.web.exposure.include=se1\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\t\twebTestClient.get().uri(\"/admin/actuator/se1\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/admin/actuator/se1\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t\twebTestClient.get().uri(\"/admin/actuator/se1/list\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/admin/actuator/se1/list\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t});\n\t}\n\n\t@Override\n\tprotected HttpStatus expectedStatusWithTrailingSlash() {\n\t\treturn HttpStatus.OK;\n\t}\n\n\t@Override\n\tprotected WebApplicationContextRunner createContextRunner() {\n\t\treturn new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.web.servlet.DispatcherServlet\"))\n\t\t\t.withUserConfiguration(JerseyEndpointConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class));\n\t}\n\n\t@Configuration\n\t@EnableConfigurationProperties(WebEndpointProperties.class)\n\tstatic class JerseyEndpointConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tResourceConfig resourceConfig() {\n\t\t\treturn new ResourceConfig();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/ManagementWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.web.MockFilterChain;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for {@link ManagementWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Hatef Palizgar\n */\nclass ManagementWebSecurityAutoConfigurationTests {\n\n\tprivate static final String MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN = \"managementSecurityFilterChain\";\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(contextSupplier(),\n\t\t\tWebServerApplicationContext.class)\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tInfoEndpointAutoConfiguration.class, EnvironmentEndpointAutoConfiguration.class,\n\t\t\t\tEndpointAutoConfiguration.class, WebMvcAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tSecurityAutoConfiguration.class, ServletWebSecurityAutoConfiguration.class,\n\t\t\t\tManagementWebSecurityAutoConfiguration.class));\n\n\tprivate static Supplier<ConfigurableWebApplicationContext> contextSupplier() {\n\t\treturn WebApplicationContextRunner.withMockServletContext(MockWebServerApplicationContext::new);\n\t}\n\n\t@Test\n\tvoid permitAllForHealth() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN);\n\t\t\tHttpStatus status = getResponseStatus(context, \"/actuator/health\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.OK);\n\t\t});\n\t}\n\n\t@Test\n\tvoid securesEverythingElse() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tHttpStatus status = getResponseStatus(context, \"/actuator\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t\tstatus = getResponseStatus(context, \"/foo\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigIsConditionalOnSecurityFilterChainClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class)).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class);\n\t\t\tHttpStatus status = getResponseStatus(context, \"/actuator/health\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t});\n\t}\n\n\t@Test\n\tvoid usesMatchersBasedOffConfiguredActuatorBasePath() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.base-path=/\").run((context) -> {\n\t\t\tHttpStatus status = getResponseStatus(context, \"/health\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.OK);\n\t\t});\n\t}\n\n\t@Test\n\tvoid backOffIfCustomSecurityIsAdded() {\n\t\tthis.contextRunner.withUserConfiguration(CustomSecurityConfiguration.class).run((context) -> {\n\t\t\tHttpStatus status = getResponseStatus(context, \"/actuator/health\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t\tstatus = getResponseStatus(context, \"/foo\");\n\t\t\tassertThat(status).isEqualTo(HttpStatus.OK);\n\t\t});\n\t}\n\n\t@Test\n\tvoid backsOffIfSecurityFilterChainBeanIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestSecurityFilterChainConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(SecurityFilterChain.class)).hasSize(1);\n\t\t\tassertThat(context.containsBean(\"testSecurityFilterChain\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid backOffIfRemoteDevToolsSecurityFilterChainIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestRemoteDevToolsSecurityFilterChainConfig.class).run((context) -> {\n\t\t\tSecurityFilterChain testSecurityFilterChain = context.getBean(\"testSecurityFilterChain\",\n\t\t\t\t\tSecurityFilterChain.class);\n\t\t\tSecurityFilterChain testRemoteDevToolsSecurityFilterChain = context\n\t\t\t\t.getBean(\"testRemoteDevToolsSecurityFilterChain\", SecurityFilterChain.class);\n\t\t\tList<SecurityFilterChain> orderedSecurityFilterChains = context.getBeanProvider(SecurityFilterChain.class)\n\t\t\t\t.orderedStream()\n\t\t\t\t.toList();\n\t\t\tassertThat(orderedSecurityFilterChains).containsExactly(testRemoteDevToolsSecurityFilterChain,\n\t\t\t\t\ttestSecurityFilterChain);\n\t\t\tassertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid withAdditionalPathsOnSamePort() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoint.health.group.test1.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.test2.include=*\",\n\t\t\t\t\t\"management.endpoint.health.group.test1.additional-path=server:/check1\",\n\t\t\t\t\t\"management.endpoint.health.group.test2.additional-path=management:/check2\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getResponseStatus(context, \"/check1\")).isEqualTo(HttpStatus.OK);\n\t\t\t\tassertThat(getResponseStatus(context, \"/check2\")).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t\t\tassertThat(getResponseStatus(context, \"/actuator/health\")).isEqualTo(HttpStatus.OK);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid withAdditionalPathsOnDifferentPort() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.health.group.test1.include=*\",\n\t\t\t\t\"management.endpoint.health.group.test2.include=*\",\n\t\t\t\t\"management.endpoint.health.group.test1.additional-path=server:/check1\",\n\t\t\t\t\"management.endpoint.health.group.test2.additional-path=management:/check2\", \"management.server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getResponseStatus(context, \"/check1\")).isEqualTo(HttpStatus.OK);\n\t\t\t\tassertThat(getResponseStatus(context, \"/check2\")).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t\t\tassertThat(getResponseStatus(context, \"/actuator/health\")).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t\t});\n\t}\n\n\tprivate HttpStatus getResponseStatus(AssertableWebApplicationContext context, String path)\n\t\t\tthrows IOException, jakarta.servlet.ServletException {\n\t\tFilterChainProxy filterChainProxy = context.getBean(FilterChainProxy.class);\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);\n\t\tMockHttpServletRequest request = new MockHttpServletRequest(servletContext);\n\t\trequest.setRequestURI(path);\n\t\trequest.setMethod(\"GET\");\n\t\tfilterChainProxy.doFilter(request, response, new MockFilterChain());\n\t\treturn HttpStatus.valueOf(response.getStatus());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(\"/foo\")).permitAll();\n\t\t\t\trequests.anyRequest().authenticated();\n\t\t\t});\n\t\t\thttp.formLogin(withDefaults());\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestSecurityFilterChainConfig {\n\n\t\t@Bean\n\t\tSecurityFilterChain testSecurityFilterChain(HttpSecurity http) {\n\t\t\treturn http.securityMatcher(\"/**\")\n\t\t\t\t.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestRemoteDevToolsSecurityFilterChainConfig extends TestSecurityFilterChainConfig {\n\n\t\t@Bean\n\t\t@Order(SecurityFilterProperties.BASIC_AUTH_ORDER - 1)\n\t\tSecurityFilterChain testRemoteDevToolsSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.securityMatcher(PathPatternRequestMatcher.withDefaults().matcher(\"/**\"));\n\t\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().anonymous());\n\t\t\thttp.csrf((csrf) -> csrf.disable());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\tstatic class MockWebServerApplicationContext extends AnnotationConfigServletWebApplicationContext\n\t\t\timplements WebServerApplicationContext {\n\n\t\t@Override\n\t\tpublic @Nullable WebServer getWebServer() {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getServerNamespace() {\n\t\t\treturn \"server\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/MvcEndpointRequestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for {@link EndpointRequest} with Spring MVC.\n *\n * @author Madhura Bhave\n */\nclass MvcEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrationTests {\n\n\t@Test\n\tvoid toLinksWhenServletPathSetShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.mvc.servlet.path=/admin\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/admin/actuator/\").exchange().expectStatus().isNotFound();\n\t\t\twebTestClient.get().uri(\"/admin/actuator\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toEndpointWhenServletPathSetShouldMatch() {\n\t\tgetContextRunner().withPropertyValues(\"spring.mvc.servlet.path=/admin\").run((context) -> {\n\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\twebTestClient.get().uri(\"/admin/actuator/e1\").exchange().expectStatus().isOk();\n\t\t});\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenServletPathSetShouldMatch() {\n\t\tgetContextRunner()\n\t\t\t.withPropertyValues(\"spring.mvc.servlet.path=/admin\", \"spring.security.user.password=password\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\t\twebTestClient.get().uri(\"/admin/actuator/e2\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/admin/actuator/e2\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid toAnyEndpointShouldMatchServletEndpoint() {\n\t\tgetContextRunner()\n\t\t\t.withPropertyValues(\"spring.security.user.password=password\",\n\t\t\t\t\t\"management.endpoints.web.exposure.include=se1\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\t\twebTestClient.get().uri(\"/actuator/se1\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/actuator/se1\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t\twebTestClient.get().uri(\"/actuator/se1/list\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/actuator/se1/list\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid toAnyEndpointWhenServletPathSetShouldMatchServletEndpoint() {\n\t\tgetContextRunner()\n\t\t\t.withPropertyValues(\"spring.mvc.servlet.path=/admin\", \"spring.security.user.password=password\",\n\t\t\t\t\t\"management.endpoints.web.exposure.include=se1\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = getWebTestClient(context);\n\t\t\t\twebTestClient.get().uri(\"/admin/actuator/se1\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/admin/actuator/se1\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t\twebTestClient.get().uri(\"/admin/actuator/se1/list\").exchange().expectStatus().isUnauthorized();\n\t\t\t\twebTestClient.get()\n\t\t\t\t\t.uri(\"/admin/actuator/se1/list\")\n\t\t\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk();\n\t\t\t});\n\t}\n\n\t@Override\n\tprotected WebApplicationContextRunner createContextRunner() {\n\t\treturn new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withUserConfiguration(InfrastructureTestConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,\n\t\t\t\t\tHttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WebEndpointProperties.class)\n\tstatic class InfrastructureTestConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/actuate/web/servlet/SecurityRequestMatchersManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.actuate.web.servlet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jersey.autoconfigure.JerseyApplicationPath;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.web.util.pattern.PathPatternParser;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SecurityRequestMatchersManagementContextConfiguration}.\n *\n * @author Madhura Bhave\n */\nclass SecurityRequestMatchersManagementContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class));\n\n\t@Test\n\tvoid configurationConditionalOnWebApplication() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))\n\t\t\t.withUserConfiguration(TestMvcConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RequestMatcherProvider.class));\n\t}\n\n\t@Test\n\tvoid configurationConditionalOnRequestMatcherClass() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.security.web.util.matcher.RequestMatcher\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RequestMatcherProvider.class));\n\t}\n\n\t@Test\n\tvoid registersRequestMatcherProviderIfMvcPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> {\n\t\t\tPathPatternRequestMatcherProvider matcherProvider = context\n\t\t\t\t.getBean(PathPatternRequestMatcherProvider.class);\n\t\t\tRequestMatcher requestMatcher = matcherProvider.getRequestMatcher(\"/example\", null);\n\t\t\tassertThat(requestMatcher).extracting(\"pattern\")\n\t\t\t\t.isEqualTo(PathPatternParser.defaultInstance.parse(\"/custom/example\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid registersRequestMatcherForJerseyProviderIfJerseyPresentAndMvcAbsent() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.web.servlet.DispatcherServlet\"))\n\t\t\t.withUserConfiguration(TestJerseyConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tPathPatternRequestMatcherProvider matcherProvider = context\n\t\t\t\t\t.getBean(PathPatternRequestMatcherProvider.class);\n\t\t\t\tRequestMatcher requestMatcher = matcherProvider.getRequestMatcher(\"/example\", null);\n\t\t\t\tassertThat(requestMatcher).extracting(\"pattern\")\n\t\t\t\t\t.isEqualTo(PathPatternParser.defaultInstance.parse(\"/admin/example\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid mvcRequestMatcherProviderConditionalOnDispatcherServletClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.web.servlet.DispatcherServlet\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));\n\t}\n\n\t@Test\n\tvoid mvcRequestMatcherProviderConditionalOnDispatcherServletPathBean() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));\n\t}\n\n\t@Test\n\tvoid jerseyRequestMatcherProviderConditionalOnResourceConfigClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.glassfish.jersey.server.ResourceConfig\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));\n\t}\n\n\t@Test\n\tvoid jerseyRequestMatcherProviderConditionalOnJerseyApplicationPathBean() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.web.servlet.DispatcherServlet\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(PathPatternRequestMatcherProvider.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestMvcConfiguration {\n\n\t\t@Bean\n\t\tDispatcherServletPath dispatcherServletPath() {\n\t\t\treturn () -> \"/custom\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestJerseyConfiguration {\n\n\t\t@Bean\n\t\tJerseyApplicationPath jerseyApplicationPath() {\n\t\t\treturn () -> \"/admin\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/jpa/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.jpa;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\n\n@Entity\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@GeneratedValue\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String state, String country, String map) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t\tthis.country = country;\n\t\tthis.map = map;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/jpa/JpaUserDetailsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.jpa;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.hibernate.autoconfigure.HibernateJpaAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootContextLoader;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\n\n/**\n * The EntityScanRegistrar can cause problems with Spring security and its eager\n * instantiation needs. This test is designed to fail if the Entities can't be scanned\n * because the registrar doesn't get a callback with the right beans (essentially because\n * their instantiation order was accelerated by Security).\n *\n * @author Dave Syer\n */\n@ContextConfiguration(classes = JpaUserDetailsTests.Main.class, loader = SpringBootContextLoader.class)\n@DirtiesContext\nclass JpaUserDetailsTests {\n\n\t@Test\n\tvoid contextLoads() {\n\t}\n\n\t@Import({ EmbeddedDataSourceConfiguration.class, DataSourceAutoConfiguration.class,\n\t\t\tHibernateJpaAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\tSecurityAutoConfiguration.class })\n\tstatic class Main {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/jpa/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.security.autoconfigure.jpa;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/rsocket/RSocketSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.rsocket;\n\nimport io.rsocket.core.RSocketServer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketMessagingAutoConfiguration;\nimport org.springframework.boot.rsocket.autoconfigure.RSocketStrategiesAutoConfiguration;\nimport org.springframework.boot.rsocket.server.RSocketServerCustomizer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;\nimport org.springframework.security.config.annotation.rsocket.RSocketSecurity;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.messaging.handler.invocation.reactive.AuthenticationPrincipalArgumentResolver;\nimport org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RSocketSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Brian Clozel\n */\nclass RSocketSecurityAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(RSocketSecurityAutoConfiguration.class,\n\t\t\t\tRSocketMessagingAutoConfiguration.class, RSocketStrategiesAutoConfiguration.class))\n\t\t.withUserConfiguration(UserDetailsServiceConfiguration.class);\n\n\t@Test\n\tvoid autoConfigurationEnablesRSocketSecurity() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(RSocketSecurity.class)).isNotNull());\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnSecuritySocketAcceptorInterceptorClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(SecuritySocketAcceptorInterceptor.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RSocketSecurity.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationAddsCustomizerForServerRSocketFactory() {\n\t\tRSocketServer server = RSocketServer.create();\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRSocketServerCustomizer customizer = context.getBean(RSocketServerCustomizer.class);\n\t\t\tcustomizer.customize(server);\n\t\t\tserver.interceptors((registry) -> registry.forSocketAcceptor((interceptors) -> {\n\t\t\t\tassertThat(interceptors).isNotEmpty();\n\t\t\t\tassertThat(interceptors)\n\t\t\t\t\t.anyMatch((interceptor) -> interceptor instanceof SecuritySocketAcceptorInterceptor);\n\t\t\t}));\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationAddsCustomizerForAuthenticationPrincipalArgumentResolver() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RSocketMessageHandler.class);\n\t\t\tRSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);\n\t\t\tassertThat(handler.getArgumentResolverConfigurer().getCustomResolvers())\n\t\t\t\t.anyMatch((customResolver) -> customResolver instanceof AuthenticationPrincipalArgumentResolver);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDetailsServiceConfiguration {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withUsername(\"alice\").password(\"secret\").roles(\"admin\").build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/reactive/PathRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link PathRequest}.\n *\n * @author Madhura Bhave\n */\nclass PathRequestTests {\n\n\t@Test\n\tvoid toStaticResourcesShouldReturnStaticResourceRequest() {\n\t\tassertThat(PathRequest.toStaticResources()).isInstanceOf(StaticResourceRequest.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/reactive/ReactiveWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.WebFilterChainProxy;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n */\nclass ReactiveWebSecurityAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveWebSecurityAutoConfiguration.class));\n\n\t@Test\n\tvoid backsOffWhenWebFilterChainProxyBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(WebFilterChainProxyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(WebFilterChainProxy.class));\n\t}\n\n\t@Test\n\tvoid autoConfiguresDenyAllReactiveAuthenticationManagerWhenNoAlternativeIsAvailable() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveWebSecurityAutoConfiguration.class)\n\t\t\t\t.hasBean(\"denyAllAuthenticationManager\"));\n\t}\n\n\t@Test\n\tvoid enablesWebFluxSecurityWhenUserDetailsServiceIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(WebFilterChainProxy.class);\n\t\t\tassertThat(context).doesNotHaveBean(\"denyAllAuthenticationManager\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid enablesWebFluxSecurityWhenReactiveAuthenticationManagerIsPresent() {\n\t\tthis.contextRunner\n\t\t\t.withBean(ReactiveAuthenticationManager.class, () -> mock(ReactiveAuthenticationManager.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(WebFilterChainProxy.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(\"denyAllAuthenticationManager\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid enablesWebFluxSecurityWhenSecurityWebFilterChainIsPresent() {\n\t\tthis.contextRunner.withBean(SecurityWebFilterChain.class, () -> mock(SecurityWebFilterChain.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(WebFilterChainProxy.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(\"denyAllAuthenticationManager\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnClass() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(Flux.class, EnableWebFluxSecurity.class, WebFilterChainProxy.class,\n\t\t\t\t\tWebFluxConfigurer.class))\n\t\t\t.withUserConfiguration(UserDetailsServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(WebFilterChainProxy.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebFilterChainProxyConfiguration {\n\n\t\t@Bean\n\t\tWebFilterChainProxy webFilterChainProxy() {\n\t\t\treturn mock(WebFilterChainProxy.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDetailsServiceConfiguration {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withUsername(\"alice\").password(\"secret\").roles(\"admin\").build());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/reactive/StaticResourceRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.reactive;\n\nimport java.time.Duration;\n\nimport org.assertj.core.api.AssertDelegateTarget;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.http.server.reactive.MockServerHttpResponse;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;\nimport org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult;\nimport org.springframework.web.context.support.StaticWebApplicationContext;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebHandler;\nimport org.springframework.web.server.adapter.HttpWebHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link StaticResourceRequest}.\n *\n * @author Madhura Bhave\n */\nclass StaticResourceRequestTests {\n\n\tprivate final StaticResourceRequest resourceRequest = StaticResourceRequest.INSTANCE;\n\n\t@Test\n\tvoid atCommonLocationsShouldMatchCommonLocations() {\n\t\tServerWebExchangeMatcher matcher = this.resourceRequest.atCommonLocations();\n\t\tassertMatcher(matcher).matches(\"/css/file.css\");\n\t\tassertMatcher(matcher).matches(\"/js/file.js\");\n\t\tassertMatcher(matcher).matches(\"/images/file.css\");\n\t\tassertMatcher(matcher).matches(\"/webjars/file.css\");\n\t\tassertMatcher(matcher).matches(\"/favicon.ico\");\n\t\tassertMatcher(matcher).matches(\"/favicon.png\");\n\t\tassertMatcher(matcher).matches(\"/icons/icon-48x48.png\");\n\t\tassertMatcher(matcher).matches(\"/fonts/font.woff2\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/bar\");\n\t}\n\n\t@Test\n\tvoid atCommonLocationsWithExcludeShouldNotMatchExcluded() {\n\t\tServerWebExchangeMatcher matcher = this.resourceRequest.atCommonLocations()\n\t\t\t.excluding(StaticResourceLocation.CSS);\n\t\tassertMatcher(matcher).doesNotMatch(\"/css/file.css\");\n\t\tassertMatcher(matcher).matches(\"/js/file.js\");\n\t}\n\n\t@Test\n\tvoid atLocationShouldMatchLocation() {\n\t\tServerWebExchangeMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS);\n\t\tassertMatcher(matcher).matches(\"/css/file.css\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/js/file.js\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid atLocationsFromSetWhenSetIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.resourceRequest.at(null))\n\t\t\t.withMessageContaining(\"'locations' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid excludeFromSetWhenSetIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.resourceRequest.atCommonLocations().excluding(null))\n\t\t\t.withMessageContaining(\"'locations' must not be null\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher) {\n\t\tStaticWebApplicationContext context = new StaticWebApplicationContext();\n\t\tcontext.registerBean(ServerProperties.class);\n\t\treturn assertThat(new RequestMatcherAssert(context, matcher));\n\t}\n\n\tstatic class RequestMatcherAssert implements AssertDelegateTarget {\n\n\t\tprivate final StaticApplicationContext context;\n\n\t\tprivate final ServerWebExchangeMatcher matcher;\n\n\t\tRequestMatcherAssert(StaticApplicationContext context, ServerWebExchangeMatcher matcher) {\n\t\t\tthis.context = context;\n\t\t\tthis.matcher = matcher;\n\t\t}\n\n\t\tvoid matches(String path) {\n\t\t\tServerWebExchange exchange = webHandler().createExchange(MockServerHttpRequest.get(path).build(),\n\t\t\t\t\tnew MockServerHttpResponse());\n\t\t\tmatches(exchange);\n\t\t}\n\n\t\tprivate void matches(ServerWebExchange exchange) {\n\t\t\tMatchResult result = this.matcher.matches(exchange).block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).isNotNull();\n\t\t\tassertThat(result.isMatch()).as(\"Matches \" + getRequestPath(exchange)).isTrue();\n\t\t}\n\n\t\tvoid doesNotMatch(String path) {\n\t\t\tServerWebExchange exchange = webHandler().createExchange(MockServerHttpRequest.get(path).build(),\n\t\t\t\t\tnew MockServerHttpResponse());\n\t\t\tdoesNotMatch(exchange);\n\t\t}\n\n\t\tprivate void doesNotMatch(ServerWebExchange exchange) {\n\t\t\tMatchResult result = this.matcher.matches(exchange).block(Duration.ofSeconds(30));\n\t\t\tassertThat(result).isNotNull();\n\t\t\tassertThat(result.isMatch()).as(\"Does not match \" + getRequestPath(exchange)).isFalse();\n\t\t}\n\n\t\tprivate TestHttpWebHandlerAdapter webHandler() {\n\t\t\tTestHttpWebHandlerAdapter adapter = new TestHttpWebHandlerAdapter(mock(WebHandler.class));\n\t\t\tadapter.setApplicationContext(this.context);\n\t\t\treturn adapter;\n\t\t}\n\n\t\tprivate String getRequestPath(ServerWebExchange exchange) {\n\t\t\treturn exchange.getRequest().getPath().toString();\n\t\t}\n\n\t}\n\n\tstatic class TestHttpWebHandlerAdapter extends HttpWebHandlerAdapter {\n\n\t\tTestHttpWebHandlerAdapter(WebHandler delegate) {\n\t\t\tsuper(delegate);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\treturn super.createExchange(request, response);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/PathRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.assertj.core.api.AssertDelegateTarget;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.h2console.autoconfigure.H2ConsoleProperties;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.StaticWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link PathRequest}.\n *\n * @author Madhura Bhave\n */\nclass PathRequestTests {\n\n\t@Test\n\tvoid toStaticResourcesShouldReturnStaticResourceRequest() {\n\t\tassertThat(PathRequest.toStaticResources()).isInstanceOf(StaticResourceRequest.class);\n\t}\n\n\t@Test\n\tvoid toH2ConsoleShouldMatchH2ConsolePath() {\n\t\tRequestMatcher matcher = PathRequest.toH2Console();\n\t\tassertMatcher(matcher).matches(\"/h2-console\");\n\t\tassertMatcher(matcher).matches(\"/h2-console/subpath\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/js/file.js\");\n\t}\n\n\t@Test\n\tvoid toH2ConsoleWhenManagementContextShouldNeverMatch() {\n\t\tRequestMatcher matcher = PathRequest.toH2Console();\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/h2-console\");\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/h2-console/subpath\");\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/js/file.js\");\n\t}\n\n\t@Test\n\t@ClassPathExclusions(packages = \"org.springframework.boot.web.server.context\")\n\tvoid toH2ConsoleWhenNoWebServerContextClassPresent() {\n\t\tassertThatExceptionOfType(NoClassDefFoundError.class)\n\t\t\t.isThrownBy(() -> WebServerApplicationContext.class.getName());\n\t\tRequestMatcher matcher = PathRequest.toH2Console();\n\t\tStaticWebApplicationContext context = new StaticWebApplicationContext();\n\t\tassertMatcher(matcher, context).matches(\"/h2-console\");\n\t\tassertMatcher(matcher, context).matches(\"/h2-console/subpath\");\n\t\tassertMatcher(matcher, context).doesNotMatch(\"/js/file.js\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher) {\n\t\treturn assertMatcher(matcher, (String) null);\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher, @Nullable String serverNamespace) {\n\t\tStaticWebApplicationContext context = new TestWebApplicationContext(serverNamespace);\n\t\treturn assertMatcher(matcher, context);\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher, WebApplicationContext context) {\n\t\tGenericApplicationContext genericContext = (GenericApplicationContext) context;\n\t\tgenericContext.registerBean(ServerProperties.class);\n\t\tgenericContext.registerBean(H2ConsoleProperties.class);\n\t\treturn assertThat(new RequestMatcherAssert(context, matcher));\n\t}\n\n\tstatic class RequestMatcherAssert implements AssertDelegateTarget {\n\n\t\tprivate final WebApplicationContext context;\n\n\t\tprivate final RequestMatcher matcher;\n\n\t\tRequestMatcherAssert(WebApplicationContext context, RequestMatcher matcher) {\n\t\t\tthis.context = context;\n\t\t\tthis.matcher = matcher;\n\t\t}\n\n\t\tvoid matches(String path) {\n\t\t\tmatches(mockRequest(path));\n\t\t}\n\n\t\tprivate void matches(HttpServletRequest request) {\n\t\t\tassertThat(this.matcher.matches(request)).as(\"Matches \" + getRequestPath(request)).isTrue();\n\t\t}\n\n\t\tvoid doesNotMatch(String path) {\n\t\t\tdoesNotMatch(mockRequest(path));\n\t\t}\n\n\t\tprivate void doesNotMatch(HttpServletRequest request) {\n\t\t\tassertThat(this.matcher.matches(request)).as(\"Does not match \" + getRequestPath(request)).isFalse();\n\t\t}\n\n\t\tprivate MockHttpServletRequest mockRequest(String path) {\n\t\t\tMockServletContext servletContext = new MockServletContext();\n\t\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest(servletContext);\n\t\t\trequest.setRequestURI(path);\n\t\t\treturn request;\n\t\t}\n\n\t\tprivate String getRequestPath(HttpServletRequest request) {\n\t\t\tString url = request.getServletPath();\n\t\t\tif (StringUtils.hasText(request.getRequestURI())) {\n\t\t\t\turl += request.getRequestURI();\n\t\t\t}\n\t\t\treturn url;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/SecurityFilterAutoConfigurationEarlyInitializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport tools.jackson.core.JsonParser;\nimport tools.jackson.databind.DeserializationContext;\nimport tools.jackson.databind.deser.std.StdDeserializer;\nimport tools.jackson.databind.module.SimpleModule;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to ensure {@link SecurityFilterAutoConfiguration} doesn't cause early\n * initialization.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\n@DirtiesUrlFactories\nclass SecurityFilterAutoConfigurationEarlyInitializationTests {\n\n\tprivate static final Pattern PASSWORD_PATTERN = Pattern.compile(\"^Using generated security password: (.*)$\",\n\t\t\tPattern.MULTILINE);\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-security-oauth2-client-*.jar\", \"spring-security-oauth2-resource-server-*.jar\",\n\t\t\t\"spring-security-saml2-service-provider-*.jar\" })\n\tvoid testSecurityFilterDoesNotCauseEarlyInitialization(CapturedOutput output) {\n\t\ttry (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext()) {\n\t\t\tTestPropertyValues.of(\"server.port:0\").applyTo(context);\n\t\t\tcontext.register(Config.class);\n\t\t\tcontext.refresh();\n\t\t\tWebServer webServer = context.getWebServer();\n\t\t\tassertThat(webServer).isNotNull();\n\t\t\tint port = webServer.getPort();\n\t\t\tMatcher password = PASSWORD_PATTERN.matcher(output);\n\t\t\tassertThat(password.find()).isTrue();\n\t\t\tnew TestRestTemplate(\"user\", password.group(1)).getForEntity(\"http://localhost:\" + port, Object.class);\n\t\t\t// If early initialization occurred a ConverterNotFoundException is thrown\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ DeserializerBean.class, JacksonModuleBean.class, ExampleController.class, ConverterBean.class })\n\t@ImportAutoConfiguration({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,\n\t\t\tHttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\tSecurityAutoConfiguration.class, ServletWebSecurityAutoConfiguration.class,\n\t\t\tUserDetailsServiceAutoConfiguration.class, SecurityFilterAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tstatic class Config {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory webServerFactory() {\n\t\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();\n\t\t\tfactory.setPort(0);\n\t\t\treturn factory;\n\t\t}\n\n\t}\n\n\tstatic class SourceType {\n\n\t\tpublic @Nullable String foo;\n\n\t}\n\n\tstatic class DestinationType {\n\n\t\tpublic @Nullable String bar;\n\n\t}\n\n\t@Component\n\tstatic class JacksonModuleBean extends SimpleModule {\n\n\t\tprivate static final long serialVersionUID = 1L;\n\n\t\tJacksonModuleBean(DeserializerBean myDeser) {\n\t\t\taddDeserializer(SourceType.class, myDeser);\n\t\t}\n\n\t}\n\n\t@Component\n\tstatic class DeserializerBean extends StdDeserializer<SourceType> {\n\n\t\t@Autowired\n\t\tConversionService conversionService;\n\n\t\tDeserializerBean() {\n\t\t\tsuper(SourceType.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic SourceType deserialize(JsonParser p, DeserializationContext ctxt) {\n\t\t\treturn new SourceType();\n\t\t}\n\n\t}\n\n\t@RestController\n\tstatic class ExampleController {\n\n\t\t@Autowired\n\t\tprivate ConversionService conversionService;\n\n\t\t@RequestMapping(\"/\")\n\t\tvoid convert() {\n\t\t\tthis.conversionService.convert(new SourceType(), DestinationType.class);\n\t\t}\n\n\t}\n\n\t@Component\n\tstatic class ConverterBean implements Converter<SourceType, DestinationType> {\n\n\t\t@Override\n\t\tpublic DestinationType convert(SourceType source) {\n\t\t\treturn new DestinationType();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/SecurityFilterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.ConverterBean;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.DeserializerBean;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.ExampleController;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterAutoConfigurationEarlyInitializationTests.JacksonModuleBean;\nimport org.springframework.boot.servlet.filter.OrderedRequestContextFilter;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.mock.web.MockServletContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.within;\n\n/**\n * Tests for {@link SecurityFilterAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass SecurityFilterAutoConfigurationTests {\n\n\t@Test\n\tvoid filterAutoConfigurationWorksWithoutSecurityAutoConfiguration() {\n\t\ttry (AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext()) {\n\t\t\tcontext.setServletContext(new MockServletContext());\n\t\t\tcontext.register(Config.class);\n\t\t\tcontext.refresh();\n\t\t}\n\t}\n\n\t@Test\n\tvoid filterIsOrderedShortlyAfterRequestContextFilter() {\n\t\ttry (AnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext()) {\n\t\t\tcontext.setServletContext(new MockServletContext());\n\t\t\tcontext.register(ServletWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class);\n\t\t\tcontext.register(Config.class);\n\t\t\tcontext.refresh();\n\t\t\tint securityFilterOrder = context.getBean(DelegatingFilterProxyRegistrationBean.class).getOrder();\n\t\t\tint requestContextFilterOrder = new OrderedRequestContextFilter().getOrder();\n\t\t\tassertThat(securityFilterOrder).isGreaterThan(requestContextFilterOrder)\n\t\t\t\t.isCloseTo(requestContextFilterOrder, within(5));\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ DeserializerBean.class, JacksonModuleBean.class, ExampleController.class, ConverterBean.class })\n\t@ImportAutoConfiguration({ WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,\n\t\t\tHttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\tSecurityFilterAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/SecurityFilterPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SecurityFilterProperties}.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n */\nclass SecurityFilterPropertiesTests {\n\n\tprivate final SecurityFilterProperties properties = new SecurityFilterProperties();\n\n\tprivate Binder binder;\n\n\tprivate final MapConfigurationPropertySource source = new MapConfigurationPropertySource();\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.binder = new Binder(this.source);\n\t}\n\n\t@Test\n\tvoid validateDefaultFilterOrderMatchesMetadata() {\n\t\tassertThat(this.properties.getOrder()).isEqualTo(-100);\n\t}\n\n\t@Test\n\tvoid filterOrderShouldBind() {\n\t\tthis.source.put(\"spring.security.filter.order\", \"55\");\n\t\tthis.binder.bind(\"spring.security.filter\", Bindable.ofInstance(this.properties));\n\t\tassertThat(this.properties.getOrder()).isEqualTo(55);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/ServletWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.security.interfaces.RSAPublicKey;\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesBinding;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.servlet.filter.OrderedFilter;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.web.PathPatternRequestMatcherBuilderFactoryBean;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServletWebSecurityAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Rob Winch\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass ServletWebSecurityAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,\n\t\t\t\tServletWebSecurityAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid testWebConfiguration() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBean(AuthenticationManagerBuilder.class)).isNotNull();\n\t\t\tassertThat(context.getBean(FilterChainProxy.class).getFilterChains()).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableWebSecurityIsConditionalOnClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.security.config\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(\"springSecurityFilterChain\"));\n\t}\n\n\t@Test\n\tvoid filterChainBeanIsConditionalOnClassSecurityFilterChain() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SecurityFilterChain.class));\n\t}\n\n\t@Test\n\tvoid securityConfigurerBacksOffWhenOtherSecurityFilterChainBeanPresent() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestSecurityFilterChainConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(SecurityFilterChain.class)).hasSize(1);\n\t\t\t\tassertThat(context.containsBean(\"testSecurityFilterChain\")).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testFilterIsNotRegisteredInNonWeb() {\n\t\ttry (AnnotationConfigApplicationContext customContext = new AnnotationConfigApplicationContext()) {\n\t\t\tcustomContext.register(SecurityAutoConfiguration.class, SecurityFilterAutoConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\t\tcustomContext.refresh();\n\t\t\tassertThat(customContext.containsBean(\"securityFilterChainRegistration\")).isFalse();\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultFilterOrder() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SecurityFilterAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(\"securityFilterChainRegistration\", DelegatingFilterProxyRegistrationBean.class)\n\t\t\t\t\t\t.getOrder())\n\t\t\t\t.isEqualTo(OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER - 100));\n\t}\n\n\t@Test\n\tvoid testCustomFilterOrder() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SecurityFilterAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.security.filter.order:12345\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(\"securityFilterChainRegistration\", DelegatingFilterProxyRegistrationBean.class)\n\t\t\t\t\t\t.getOrder())\n\t\t\t\t.isEqualTo(12345));\n\t}\n\n\t@Test\n\tvoid defaultFilterDispatcherTypes() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(SecurityFilterAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tDelegatingFilterProxyRegistrationBean bean = context.getBean(\"securityFilterChainRegistration\",\n\t\t\t\t\t\tDelegatingFilterProxyRegistrationBean.class);\n\t\t\t\tassertThat(bean).extracting(\"dispatcherTypes\", InstanceOfAssertFactories.iterable(DispatcherType.class))\n\t\t\t\t\t.containsExactlyInAnyOrderElementsOf(EnumSet.allOf(DispatcherType.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customFilterDispatcherTypes() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.filter.dispatcher-types:INCLUDE,ERROR\")\n\t\t\t.withConfiguration(AutoConfigurations.of(SecurityFilterAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tDelegatingFilterProxyRegistrationBean bean = context.getBean(\"securityFilterChainRegistration\",\n\t\t\t\t\t\tDelegatingFilterProxyRegistrationBean.class);\n\t\t\t\tassertThat(bean).extracting(\"dispatcherTypes\", InstanceOfAssertFactories.iterable(DispatcherType.class))\n\t\t\t\t\t.containsOnly(DispatcherType.INCLUDE, DispatcherType.ERROR);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid emptyFilterDispatcherTypesDoNotThrowException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.filter.dispatcher-types:\")\n\t\t\t.withConfiguration(AutoConfigurations.of(SecurityFilterAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tDelegatingFilterProxyRegistrationBean bean = context.getBean(\"securityFilterChainRegistration\",\n\t\t\t\t\t\tDelegatingFilterProxyRegistrationBean.class);\n\t\t\t\tassertThat(bean).extracting(\"dispatcherTypes\", InstanceOfAssertFactories.iterable(DispatcherType.class))\n\t\t\t\t\t.isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid whenAConfigurationPropertyBindingConverterIsDefinedThenBindingToAnRsaKeySucceeds() {\n\t\tthis.contextRunner.withUserConfiguration(ConverterConfiguration.class, PropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"jwt.public-key=classpath:public-key-location\")\n\t\t\t.run((context) -> assertThat(context.getBean(JwtProperties.class).getPublicKey()).isNotNull());\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid whenTheBeanFactoryHasAConversionServiceAndAConfigurationPropertyBindingConverterIsDefinedThenBindingToAnRsaKeySucceeds() {\n\t\tthis.contextRunner\n\t\t\t.withInitializer(\n\t\t\t\t\t(context) -> context.getBeanFactory().setConversionService(new ApplicationConversionService()))\n\t\t\t.withUserConfiguration(ConverterConfiguration.class, PropertiesConfiguration.class)\n\t\t\t.withPropertyValues(\"jwt.public-key=classpath:public-key-location\")\n\t\t\t.run((context) -> assertThat(context.getBean(JwtProperties.class).getPublicKey()).isNotNull());\n\t}\n\n\t@Test\n\tvoid whenDispatcherServletPathIsSetPathPatternRequestMatcherBuilderHasCustomBasePath() {\n\t\tthis.contextRunner.withBean(DispatcherServletPath.class, () -> () -> \"/dispatcher-servlet\").run((context) -> {\n\t\t\tPathPatternRequestMatcher.Builder builder = context.getBean(PathPatternRequestMatcher.Builder.class);\n\t\t\tassertThat(builder).extracting(\"basePath\").isEqualTo(\"/dispatcher-servlet\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid givenACustomPathPatternRequestMatcherBuilderWhenDispatcherServletPathIsSetBuilderBasePathIsNotCustomized() {\n\t\tthis.contextRunner.withBean(PathPatternRequestMatcherBuilderFactoryBean.class)\n\t\t\t.withBean(DispatcherServletPath.class, () -> () -> \"/dispatcher-servlet\")\n\t\t\t.run((context) -> {\n\t\t\t\tPathPatternRequestMatcher.Builder builder = context.getBean(PathPatternRequestMatcher.Builder.class);\n\t\t\t\tassertThat(builder).extracting(\"basePath\").isEqualTo(\"\");\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestSecurityFilterChainConfig {\n\n\t\t@Bean\n\t\tSecurityFilterChain testSecurityFilterChain(HttpSecurity http) {\n\t\t\treturn http.securityMatcher(\"/**\")\n\t\t\t\t.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())\n\t\t\t\t.build();\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConverterConfiguration {\n\n\t\t@Bean\n\t\t@ConfigurationPropertiesBinding\n\t\tstatic Converter<String, TargetType> targetTypeConverter() {\n\t\t\treturn new Converter<>() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic TargetType convert(String input) {\n\t\t\t\t\treturn new TargetType();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(JwtProperties.class)\n\tstatic class PropertiesConfiguration {\n\n\t}\n\n\t@ConfigurationProperties(\"jwt\")\n\tstatic class JwtProperties {\n\n\t\tprivate @Nullable RSAPublicKey publicKey;\n\n\t\t@Nullable RSAPublicKey getPublicKey() {\n\t\t\treturn this.publicKey;\n\t\t}\n\n\t\tvoid setPublicKey(@Nullable RSAPublicKey publicKey) {\n\t\t\tthis.publicKey = publicKey;\n\t\t}\n\n\t}\n\n\tstatic class TargetType {\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"public-key-location\", content = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\n\t\t\tUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\n\t\t\tHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\n\t\t\to2kQ+X5xK9cipRgEKwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\n\t\t\t\"\"\")\n\t@interface WithPublicKeyResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/StaticResourceRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.assertj.core.api.AssertDelegateTarget;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.security.autoconfigure.web.StaticResourceLocation;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link StaticResourceRequest}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass StaticResourceRequestTests {\n\n\tprivate final StaticResourceRequest resourceRequest = StaticResourceRequest.INSTANCE;\n\n\t@Test\n\tvoid atCommonLocationsShouldMatchCommonLocations() {\n\t\tRequestMatcher matcher = this.resourceRequest.atCommonLocations();\n\t\tassertMatcher(matcher).matches(\"/css/file.css\");\n\t\tassertMatcher(matcher).matches(\"/js/file.js\");\n\t\tassertMatcher(matcher).matches(\"/images/file.css\");\n\t\tassertMatcher(matcher).matches(\"/webjars/file.css\");\n\t\tassertMatcher(matcher).matches(\"/favicon.ico\");\n\t\tassertMatcher(matcher).matches(\"/favicon.png\");\n\t\tassertMatcher(matcher).matches(\"/icons/icon-48x48.png\");\n\t\tassertMatcher(matcher).matches(\"/fonts/font.woff2\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/bar\");\n\t}\n\n\t@Test\n\tvoid atCommonLocationsWhenManagementContextShouldNeverMatch() {\n\t\tRequestMatcher matcher = this.resourceRequest.atCommonLocations();\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/css/file.css\");\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/js/file.js\");\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/images/file.css\");\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/webjars/file.css\");\n\t\tassertMatcher(matcher, \"management\").doesNotMatch(\"/foo/favicon.ico\");\n\t}\n\n\t@Test\n\tvoid atCommonLocationsWithExcludeShouldNotMatchExcluded() {\n\t\tRequestMatcher matcher = this.resourceRequest.atCommonLocations().excluding(StaticResourceLocation.CSS);\n\t\tassertMatcher(matcher).doesNotMatch(\"/css/file.css\");\n\t\tassertMatcher(matcher).matches(\"/js/file.js\");\n\t}\n\n\t@Test\n\tvoid atLocationShouldMatchLocation() {\n\t\tRequestMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS);\n\t\tassertMatcher(matcher).matches(\"/css/file.css\");\n\t\tassertMatcher(matcher).doesNotMatch(\"/js/file.js\");\n\t}\n\n\t@Test\n\tvoid atLocationWhenHasServletPathShouldMatchLocation() {\n\t\tRequestMatcher matcher = this.resourceRequest.at(StaticResourceLocation.CSS);\n\t\tassertMatcher(matcher, null, \"/foo\").matches(\"/foo\", \"/css/file.css\");\n\t\tassertMatcher(matcher, null, \"/foo\").doesNotMatch(\"/foo\", \"/js/file.js\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid atLocationsFromSetWhenSetIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.resourceRequest.at(null))\n\t\t\t.withMessageContaining(\"'locations' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid excludeFromSetWhenSetIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.resourceRequest.atCommonLocations().excluding(null))\n\t\t\t.withMessageContaining(\"'locations' must not be null\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher) {\n\t\treturn assertMatcher(matcher, null, \"\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher, String serverNamespace) {\n\t\treturn assertMatcher(matcher, serverNamespace, \"\");\n\t}\n\n\tprivate RequestMatcherAssert assertMatcher(RequestMatcher matcher, @Nullable String serverNamespace, String path) {\n\t\tDispatcherServletPath dispatcherServletPath = () -> path;\n\t\tTestWebApplicationContext context = new TestWebApplicationContext(serverNamespace);\n\t\tcontext.registerBean(DispatcherServletPath.class, () -> dispatcherServletPath);\n\t\treturn assertThat(new RequestMatcherAssert(context, matcher));\n\t}\n\n\tstatic class RequestMatcherAssert implements AssertDelegateTarget {\n\n\t\tprivate final WebApplicationContext context;\n\n\t\tprivate final RequestMatcher matcher;\n\n\t\tRequestMatcherAssert(WebApplicationContext context, RequestMatcher matcher) {\n\t\t\tthis.context = context;\n\t\t\tthis.matcher = matcher;\n\t\t}\n\n\t\tvoid matches(String path) {\n\t\t\tmatches(mockRequest(path));\n\t\t}\n\n\t\tvoid matches(String servletPath, String path) {\n\t\t\tmatches(mockRequest(servletPath, path));\n\t\t}\n\n\t\tprivate void matches(HttpServletRequest request) {\n\t\t\tassertThat(this.matcher.matches(request)).as(\"Matches \" + getRequestPath(request)).isTrue();\n\t\t}\n\n\t\tvoid doesNotMatch(String path) {\n\t\t\tdoesNotMatch(mockRequest(path));\n\t\t}\n\n\t\tvoid doesNotMatch(String servletPath, String path) {\n\t\t\tdoesNotMatch(mockRequest(servletPath, path));\n\t\t}\n\n\t\tprivate void doesNotMatch(HttpServletRequest request) {\n\t\t\tassertThat(this.matcher.matches(request)).as(\"Does not match \" + getRequestPath(request)).isFalse();\n\t\t}\n\n\t\tprivate MockHttpServletRequest mockRequest(String path) {\n\t\t\treturn mockRequest(null, path);\n\t\t}\n\n\t\tprivate MockHttpServletRequest mockRequest(@Nullable String servletPath, String path) {\n\t\t\tMockServletContext servletContext = new MockServletContext();\n\t\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest(servletContext);\n\t\t\tif (servletPath != null) {\n\t\t\t\trequest.setServletPath(servletPath);\n\t\t\t\trequest.setRequestURI(servletPath + path);\n\t\t\t}\n\t\t\telse {\n\t\t\t\trequest.setRequestURI(path);\n\t\t\t}\n\t\t\treturn request;\n\t\t}\n\n\t\tprivate String getRequestPath(HttpServletRequest request) {\n\t\t\tString url = request.getServletPath();\n\t\t\tif (StringUtils.hasText(request.getRequestURI())) {\n\t\t\t\turl += request.getRequestURI();\n\t\t\t}\n\t\t\treturn url;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/autoconfigure/web/servlet/TestWebApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.autoconfigure.web.servlet;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.web.context.support.StaticWebApplicationContext;\n\n/**\n * Test {@link StaticWebApplicationContext} that also implements\n * {@link WebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass TestWebApplicationContext extends StaticWebApplicationContext implements WebServerApplicationContext {\n\n\tprivate final @Nullable String serverNamespace;\n\n\tTestWebApplicationContext(@Nullable String serverNamespace) {\n\t\tthis.serverNamespace = serverNamespace;\n\t}\n\n\t@Override\n\tpublic @Nullable WebServer getWebServer() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable String getServerNamespace() {\n\t\treturn this.serverNamespace;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/web/reactive/ApplicationContextServerWebExchangeMatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.web.reactive;\n\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.http.server.reactive.MockServerHttpResponse;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebHandler;\nimport org.springframework.web.server.adapter.HttpWebHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ApplicationContextServerWebExchangeMatcher}.\n *\n * @author Madhura Bhave\n */\nclass ApplicationContextServerWebExchangeMatcherTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenContextClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new TestApplicationContextServerWebExchangeMatcher<>(null))\n\t\t\t.withMessageContaining(\"'contextClass' must not be null\");\n\t}\n\n\t@Test\n\tvoid matchesWhenContextClassIsApplicationContextShouldProvideContext() {\n\t\tServerWebExchange exchange = createExchange();\n\t\tStaticApplicationContext context = (StaticApplicationContext) exchange.getApplicationContext();\n\t\tassertThat(new TestApplicationContextServerWebExchangeMatcher<>(ApplicationContext.class)\n\t\t\t.callMatchesAndReturnProvidedContext(exchange)\n\t\t\t.get()).isEqualTo(context);\n\t}\n\n\t@Test\n\tvoid matchesWhenContextClassIsExistingBeanShouldProvideBean() {\n\t\tServerWebExchange exchange = createExchange();\n\t\tStaticApplicationContext context = (StaticApplicationContext) exchange.getApplicationContext();\n\t\tassertThat(context).isNotNull();\n\t\tcontext.registerSingleton(\"existingBean\", ExistingBean.class);\n\t\tassertThat(new TestApplicationContextServerWebExchangeMatcher<>(ExistingBean.class)\n\t\t\t.callMatchesAndReturnProvidedContext(exchange)\n\t\t\t.get()).isEqualTo(context.getBean(ExistingBean.class));\n\t}\n\n\t@Test\n\tvoid matchesWhenContextClassIsMissingBeanShouldProvideException() {\n\t\tServerWebExchange exchange = createExchange();\n\t\tSupplier<ExistingBean> supplier = new TestApplicationContextServerWebExchangeMatcher<>(ExistingBean.class)\n\t\t\t.callMatchesAndReturnProvidedContext(exchange);\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(supplier::get);\n\t}\n\n\t@Test\n\tvoid matchesWhenContextIsNull() {\n\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/path\").build());\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new TestApplicationContextServerWebExchangeMatcher<>(ExistingBean.class)\n\t\t\t\t.callMatchesAndReturnProvidedContext(exchange))\n\t\t\t.withMessageContaining(\"No ApplicationContext found on ServerWebExchange.\");\n\t}\n\n\tprivate ServerWebExchange createExchange() {\n\t\tStaticApplicationContext context = new StaticApplicationContext();\n\t\tTestHttpWebHandlerAdapter adapter = new TestHttpWebHandlerAdapter(mock(WebHandler.class));\n\t\tadapter.setApplicationContext(context);\n\t\treturn adapter.createExchange(MockServerHttpRequest.get(\"/path\").build(), new MockServerHttpResponse());\n\t}\n\n\tstatic class TestHttpWebHandlerAdapter extends HttpWebHandlerAdapter {\n\n\t\tTestHttpWebHandlerAdapter(WebHandler delegate) {\n\t\t\tsuper(delegate);\n\t\t}\n\n\t\t@Override\n\t\tprotected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\treturn super.createExchange(request, response);\n\t\t}\n\n\t}\n\n\tstatic class ExistingBean {\n\n\t}\n\n\tstatic class NewBean {\n\n\t\tprivate final ExistingBean bean;\n\n\t\tNewBean(ExistingBean bean) {\n\t\t\tthis.bean = bean;\n\t\t}\n\n\t\tExistingBean getBean() {\n\t\t\treturn this.bean;\n\t\t}\n\n\t}\n\n\tstatic class TestApplicationContextServerWebExchangeMatcher<C>\n\t\t\textends ApplicationContextServerWebExchangeMatcher<C> {\n\n\t\tprivate @Nullable Supplier<C> providedContext;\n\n\t\tTestApplicationContextServerWebExchangeMatcher(Class<? extends C> context) {\n\t\t\tsuper(context);\n\t\t}\n\n\t\tSupplier<C> callMatchesAndReturnProvidedContext(ServerWebExchange exchange) {\n\t\t\tmatches(exchange);\n\t\t\tSupplier<C> context = getProvidedContext();\n\t\t\tassertThat(context).isNotNull();\n\t\t\treturn context;\n\t\t}\n\n\t\t@Override\n\t\tprotected Mono<MatchResult> matches(ServerWebExchange exchange, Supplier<C> context) {\n\t\t\tthis.providedContext = context;\n\t\t\treturn MatchResult.match();\n\t\t}\n\n\t\t@Nullable Supplier<C> getProvidedContext() {\n\t\t\treturn this.providedContext;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security/src/test/java/org/springframework/boot/security/web/servlet/ApplicationContextRequestMatcherTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.web.servlet;\n\nimport java.lang.Thread.UncaughtExceptionHandler;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.StaticWebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link ApplicationContextRequestMatcher}.\n *\n * @author Phillip Webb\n */\nclass ApplicationContextRequestMatcherTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenContextClassIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new TestApplicationContextRequestMatcher<>(null))\n\t\t\t.withMessageContaining(\"'contextClass' must not be null\");\n\t}\n\n\t@Test\n\tvoid matchesWhenContextClassIsApplicationContextShouldProvideContext() {\n\t\tStaticWebApplicationContext context = createWebApplicationContext();\n\t\tassertThat(new TestApplicationContextRequestMatcher<>(ApplicationContext.class)\n\t\t\t.callMatchesAndReturnProvidedContext(context)\n\t\t\t.get()).isEqualTo(context);\n\t}\n\n\t@Test\n\tvoid matchesWhenContextClassIsExistingBeanShouldProvideBean() {\n\t\tStaticWebApplicationContext context = createWebApplicationContext();\n\t\tcontext.registerSingleton(\"existingBean\", ExistingBean.class);\n\t\tassertThat(new TestApplicationContextRequestMatcher<>(ExistingBean.class)\n\t\t\t.callMatchesAndReturnProvidedContext(context)\n\t\t\t.get()).isEqualTo(context.getBean(ExistingBean.class));\n\t}\n\n\t@Test\n\tvoid matchesWhenContextClassIsBeanThatDoesNotExistShouldSupplyException() {\n\t\tStaticWebApplicationContext context = createWebApplicationContext();\n\t\tSupplier<ExistingBean> supplier = new TestApplicationContextRequestMatcher<>(ExistingBean.class)\n\t\t\t.callMatchesAndReturnProvidedContext(context);\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(supplier::get);\n\t}\n\n\t@Test // gh-18012\n\tvoid matchesWhenCalledWithDifferentApplicationContextDoesNotCache() {\n\t\tStaticWebApplicationContext context1 = createWebApplicationContext();\n\t\tStaticWebApplicationContext context2 = createWebApplicationContext();\n\t\tTestApplicationContextRequestMatcher<ApplicationContext> matcher = new TestApplicationContextRequestMatcher<>(\n\t\t\t\tApplicationContext.class);\n\t\tassertThat(matcher.callMatchesAndReturnProvidedContext(context1).get()).isEqualTo(context1);\n\t\tassertThat(matcher.callMatchesAndReturnProvidedContext(context2).get()).isEqualTo(context2);\n\t}\n\n\t@Test\n\tvoid initializeAndMatchesAreNotCalledIfContextIsIgnored() {\n\t\tStaticWebApplicationContext context = createWebApplicationContext();\n\t\tTestApplicationContextRequestMatcher<ApplicationContext> matcher = new TestApplicationContextRequestMatcher<>(\n\t\t\t\tApplicationContext.class) {\n\n\t\t\t@Override\n\t\t\tprotected boolean ignoreApplicationContext(WebApplicationContext webApplicationContext) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected void initialized(Supplier<ApplicationContext> context) {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tprotected boolean matches(HttpServletRequest request, Supplier<ApplicationContext> context) {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t}\n\n\t\t};\n\t\tMockHttpServletRequest request = new MockHttpServletRequest(context.getServletContext());\n\t\tassertThat(matcher.matches(request)).isFalse();\n\t}\n\n\t@Test // gh-18211\n\tvoid matchesWhenConcurrentlyCalledWaitsForInitialize() {\n\t\tConcurrentApplicationContextRequestMatcher matcher = new ConcurrentApplicationContextRequestMatcher();\n\t\tStaticWebApplicationContext context = createWebApplicationContext();\n\t\tRunnable target = () -> matcher.matches(new MockHttpServletRequest(context.getServletContext()));\n\t\tList<Thread> threads = new ArrayList<>();\n\t\tAssertingUncaughtExceptionHandler exceptionHandler = new AssertingUncaughtExceptionHandler();\n\t\tfor (int i = 0; i < 2; i++) {\n\t\t\tThread thread = new Thread(target);\n\t\t\tthread.setUncaughtExceptionHandler(exceptionHandler);\n\t\t\tthreads.add(thread);\n\t\t}\n\t\tthreads.forEach(Thread::start);\n\t\tthreads.forEach(this::join);\n\t\texceptionHandler.assertNoExceptions();\n\t}\n\n\tprivate void join(Thread thread) {\n\t\ttry {\n\t\t\tthread.join(1000);\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate StaticWebApplicationContext createWebApplicationContext() {\n\t\tStaticWebApplicationContext context = new StaticWebApplicationContext();\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tcontext.setServletContext(servletContext);\n\t\tservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);\n\t\treturn context;\n\t}\n\n\tstatic class ExistingBean {\n\n\t}\n\n\tstatic class NewBean {\n\n\t\tprivate final ExistingBean bean;\n\n\t\tNewBean(ExistingBean bean) {\n\t\t\tthis.bean = bean;\n\t\t}\n\n\t\tExistingBean getBean() {\n\t\t\treturn this.bean;\n\t\t}\n\n\t}\n\n\tstatic class TestApplicationContextRequestMatcher<C> extends ApplicationContextRequestMatcher<C> {\n\n\t\tprivate @Nullable Supplier<C> providedContext;\n\n\t\tTestApplicationContextRequestMatcher(Class<? extends C> context) {\n\t\t\tsuper(context);\n\t\t}\n\n\t\tSupplier<C> callMatchesAndReturnProvidedContext(WebApplicationContext context) {\n\t\t\treturn callMatchesAndReturnProvidedContext(new MockHttpServletRequest(context.getServletContext()));\n\t\t}\n\n\t\tSupplier<C> callMatchesAndReturnProvidedContext(HttpServletRequest request) {\n\t\t\tmatches(request);\n\t\t\tSupplier<C> context = getProvidedContext();\n\t\t\tassertThat(context).isNotNull();\n\t\t\treturn context;\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matches(HttpServletRequest request, Supplier<C> context) {\n\t\t\tthis.providedContext = context;\n\t\t\treturn false;\n\t\t}\n\n\t\t@Nullable Supplier<C> getProvidedContext() {\n\t\t\treturn this.providedContext;\n\t\t}\n\n\t}\n\n\tstatic class ConcurrentApplicationContextRequestMatcher extends ApplicationContextRequestMatcher<Object> {\n\n\t\tConcurrentApplicationContextRequestMatcher() {\n\t\t\tsuper(Object.class);\n\t\t}\n\n\t\tprivate final AtomicBoolean initialized = new AtomicBoolean();\n\n\t\t@Override\n\t\tprotected void initialized(Supplier<Object> context) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(200);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\tthis.initialized.set(true);\n\t\t}\n\n\t\t@Override\n\t\tprotected boolean matches(HttpServletRequest request, Supplier<Object> context) {\n\t\t\tassertThat(this.initialized.get()).isTrue();\n\t\t\treturn true;\n\t\t}\n\n\t}\n\n\tprivate static final class AssertingUncaughtExceptionHandler implements UncaughtExceptionHandler {\n\n\t\tprivate volatile @Nullable Throwable ex;\n\n\t\t@Override\n\t\tpublic void uncaughtException(Thread thread, Throwable ex) {\n\t\t\tthis.ex = ex;\n\t\t}\n\n\t\tvoid assertNoExceptions() {\n\t\t\tif (this.ex != null) {\n\t\t\t\tReflectionUtils.rethrowRuntimeException(this.ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Security OAuth2 Authorization Server\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.security:spring-security-oauth2-authorization-server\")\n\n\timplementation(project(\":module:spring-boot-security\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-security-oauth2-resource-server\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.oauth2.server.authorization.OAuth2Authorization;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OAuth2 authorization server\n * support.\n *\n * <p>\n * <strong>Note:</strong> This configuration and\n * {@link OAuth2AuthorizationServerJwtAutoConfiguration} work together to ensure that the\n * {@link org.springframework.security.config.ObjectPostProcessor} is defined\n * <strong>BEFORE</strong> {@link UserDetailsServiceAutoConfiguration} so that a\n * {@link org.springframework.security.core.userdetails.UserDetailsService} can be created\n * if necessary.\n *\n * @author Steve Riesenberg\n * @since 4.0.0\n * @see OAuth2AuthorizationServerJwtAutoConfiguration\n */\n@AutoConfiguration(before = { SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class },\n\t\tbeforeName = \"org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration\")\n@ConditionalOnClass(OAuth2Authorization.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@Import({ OAuth2AuthorizationServerConfiguration.class, OAuth2AuthorizationServerWebSecurityConfiguration.class })\npublic final class OAuth2AuthorizationServerAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\n\n/**\n * {@link Configuration @Configuration} used to map\n * {@link OAuth2AuthorizationServerProperties} to registered clients and settings.\n *\n * @author Steve Riesenberg\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(OAuth2AuthorizationServerProperties.class)\nclass OAuth2AuthorizationServerConfiguration {\n\n\tprivate final OAuth2AuthorizationServerPropertiesMapper propertiesMapper;\n\n\tOAuth2AuthorizationServerConfiguration(OAuth2AuthorizationServerProperties properties) {\n\t\tthis.propertiesMapper = new OAuth2AuthorizationServerPropertiesMapper(properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Conditional(RegisteredClientsConfiguredCondition.class)\n\tRegisteredClientRepository registeredClientRepository() {\n\t\treturn new InMemoryRegisteredClientRepository(this.propertiesMapper.asRegisteredClients());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tAuthorizationServerSettings authorizationServerSettings() {\n\t\treturn this.propertiesMapper.asAuthorizationServerSettings();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerJwtAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.util.UUID;\n\nimport com.nimbusds.jose.jwk.JWKSet;\nimport com.nimbusds.jose.jwk.RSAKey;\nimport com.nimbusds.jose.jwk.source.ImmutableJWKSet;\nimport com.nimbusds.jose.jwk.source.JWKSource;\nimport com.nimbusds.jose.proc.SecurityContext;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.authorization.OAuth2Authorization;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for JWT support for endpoints of the\n * OAuth2 authorization server that require it (e.g. User Info, Client Registration).\n *\n * @author Steve Riesenberg\n * @since 4.0.0\n */\n@AutoConfiguration(after = UserDetailsServiceAutoConfiguration.class)\n@ConditionalOnClass({ OAuth2Authorization.class, JWKSource.class })\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic final class OAuth2AuthorizationServerJwtAutoConfiguration {\n\n\t@Bean\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t@ConditionalOnMissingBean\n\tJWKSource<SecurityContext> jwkSource() {\n\t\tRSAKey rsaKey = getRsaKey();\n\t\tJWKSet jwkSet = new JWKSet(rsaKey);\n\t\treturn new ImmutableJWKSet<>(jwkSet);\n\t}\n\n\tprivate static RSAKey getRsaKey() {\n\t\tKeyPair keyPair = generateRsaKey();\n\t\tRSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();\n\t\tRSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();\n\t\tRSAKey rsaKey = new RSAKey.Builder(publicKey).privateKey(privateKey)\n\t\t\t.keyID(UUID.randomUUID().toString())\n\t\t\t.build();\n\t\treturn rsaKey;\n\t}\n\n\tprivate static KeyPair generateRsaKey() {\n\t\tKeyPair keyPair;\n\t\ttry {\n\t\t\tKeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"RSA\");\n\t\t\tkeyPairGenerator.initialize(2048);\n\t\t\tkeyPair = keyPairGenerator.generateKeyPair();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t\treturn keyPair;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(JwtDecoder.class)\n\tstatic class JwtDecoderConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tJwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {\n\t\t\treturn OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.time.Duration;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * OAuth 2.0 Authorization Server properties.\n *\n * @author Steve Riesenberg\n * @author Florian Lemaire\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.security.oauth2.authorizationserver\")\npublic class OAuth2AuthorizationServerProperties implements InitializingBean {\n\n\t/**\n\t * URL of the Authorization Server's Issuer Identifier.\n\t */\n\tprivate @Nullable String issuer;\n\n\t/**\n\t * Whether multiple issuers are allowed per host. Using path components in the URL of\n\t * the issuer identifier enables supporting multiple issuers per host in a\n\t * multi-tenant hosting configuration.\n\t */\n\tprivate boolean multipleIssuersAllowed;\n\n\t/**\n\t * Registered clients of the Authorization Server.\n\t */\n\tprivate final Map<String, Client> client = new HashMap<>();\n\n\t/**\n\t * Authorization Server endpoints.\n\t */\n\tprivate final Endpoint endpoint = new Endpoint();\n\n\tpublic boolean isMultipleIssuersAllowed() {\n\t\treturn this.multipleIssuersAllowed;\n\t}\n\n\tpublic void setMultipleIssuersAllowed(boolean multipleIssuersAllowed) {\n\t\tthis.multipleIssuersAllowed = multipleIssuersAllowed;\n\t}\n\n\tpublic @Nullable String getIssuer() {\n\t\treturn this.issuer;\n\t}\n\n\tpublic void setIssuer(@Nullable String issuer) {\n\t\tthis.issuer = issuer;\n\t}\n\n\tpublic Map<String, Client> getClient() {\n\t\treturn this.client;\n\t}\n\n\tpublic Endpoint getEndpoint() {\n\t\treturn this.endpoint;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tvalidate();\n\t}\n\n\tpublic void validate() {\n\t\tgetClient().values().forEach(this::validateClient);\n\t}\n\n\tprivate void validateClient(Client client) {\n\t\tif (!StringUtils.hasText(client.getRegistration().getClientId())) {\n\t\t\tthrow new IllegalStateException(\"Client id must not be empty.\");\n\t\t}\n\t\tif (CollectionUtils.isEmpty(client.getRegistration().getClientAuthenticationMethods())) {\n\t\t\tthrow new IllegalStateException(\"Client authentication methods must not be empty.\");\n\t\t}\n\t\tif (CollectionUtils.isEmpty(client.getRegistration().getAuthorizationGrantTypes())) {\n\t\t\tthrow new IllegalStateException(\"Authorization grant types must not be empty.\");\n\t\t}\n\t}\n\n\t/**\n\t * Authorization Server endpoints.\n\t */\n\tpublic static class Endpoint {\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Authorization Endpoint.\n\t\t */\n\t\tprivate String authorizationUri = \"/oauth2/authorize\";\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Device Authorization Endpoint.\n\t\t */\n\t\tprivate String deviceAuthorizationUri = \"/oauth2/device_authorization\";\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Device Verification Endpoint.\n\t\t */\n\t\tprivate String deviceVerificationUri = \"/oauth2/device_verification\";\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Token Endpoint.\n\t\t */\n\t\tprivate String tokenUri = \"/oauth2/token\";\n\n\t\t/**\n\t\t * Authorization Server's JWK Set Endpoint.\n\t\t */\n\t\tprivate String jwkSetUri = \"/oauth2/jwks\";\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Token Revocation Endpoint.\n\t\t */\n\t\tprivate String tokenRevocationUri = \"/oauth2/revoke\";\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Token Introspection Endpoint.\n\t\t */\n\t\tprivate String tokenIntrospectionUri = \"/oauth2/introspect\";\n\n\t\t/**\n\t\t * Authorization Server's OAuth 2.0 Pushed Authorization Request Endpoint.\n\t\t */\n\t\tprivate String pushedAuthorizationRequestUri = \"/oauth2/par\";\n\n\t\t/**\n\t\t * OpenID Connect 1.0 endpoints.\n\t\t */\n\t\t@NestedConfigurationProperty\n\t\tprivate final OidcEndpoint oidc = new OidcEndpoint();\n\n\t\tpublic String getAuthorizationUri() {\n\t\t\treturn this.authorizationUri;\n\t\t}\n\n\t\tpublic void setAuthorizationUri(String authorizationUri) {\n\t\t\tthis.authorizationUri = authorizationUri;\n\t\t}\n\n\t\tpublic String getDeviceAuthorizationUri() {\n\t\t\treturn this.deviceAuthorizationUri;\n\t\t}\n\n\t\tpublic void setDeviceAuthorizationUri(String deviceAuthorizationUri) {\n\t\t\tthis.deviceAuthorizationUri = deviceAuthorizationUri;\n\t\t}\n\n\t\tpublic String getDeviceVerificationUri() {\n\t\t\treturn this.deviceVerificationUri;\n\t\t}\n\n\t\tpublic void setDeviceVerificationUri(String deviceVerificationUri) {\n\t\t\tthis.deviceVerificationUri = deviceVerificationUri;\n\t\t}\n\n\t\tpublic String getTokenUri() {\n\t\t\treturn this.tokenUri;\n\t\t}\n\n\t\tpublic void setTokenUri(String tokenUri) {\n\t\t\tthis.tokenUri = tokenUri;\n\t\t}\n\n\t\tpublic String getJwkSetUri() {\n\t\t\treturn this.jwkSetUri;\n\t\t}\n\n\t\tpublic void setJwkSetUri(String jwkSetUri) {\n\t\t\tthis.jwkSetUri = jwkSetUri;\n\t\t}\n\n\t\tpublic String getTokenRevocationUri() {\n\t\t\treturn this.tokenRevocationUri;\n\t\t}\n\n\t\tpublic void setTokenRevocationUri(String tokenRevocationUri) {\n\t\t\tthis.tokenRevocationUri = tokenRevocationUri;\n\t\t}\n\n\t\tpublic String getTokenIntrospectionUri() {\n\t\t\treturn this.tokenIntrospectionUri;\n\t\t}\n\n\t\tpublic void setTokenIntrospectionUri(String tokenIntrospectionUri) {\n\t\t\tthis.tokenIntrospectionUri = tokenIntrospectionUri;\n\t\t}\n\n\t\tpublic String getPushedAuthorizationRequestUri() {\n\t\t\treturn this.pushedAuthorizationRequestUri;\n\t\t}\n\n\t\tpublic void setPushedAuthorizationRequestUri(String pushedAuthorizationRequestUri) {\n\t\t\tthis.pushedAuthorizationRequestUri = pushedAuthorizationRequestUri;\n\t\t}\n\n\t\tpublic OidcEndpoint getOidc() {\n\t\t\treturn this.oidc;\n\t\t}\n\n\t}\n\n\t/**\n\t * OpenID Connect 1.0 endpoints.\n\t */\n\tpublic static class OidcEndpoint {\n\n\t\t/**\n\t\t * Authorization Server's OpenID Connect 1.0 Logout Endpoint.\n\t\t */\n\t\tprivate String logoutUri = \"/connect/logout\";\n\n\t\t/**\n\t\t * Authorization Server's OpenID Connect 1.0 Client Registration Endpoint.\n\t\t */\n\t\tprivate String clientRegistrationUri = \"/connect/register\";\n\n\t\t/**\n\t\t * Authorization Server's OpenID Connect 1.0 UserInfo Endpoint.\n\t\t */\n\t\tprivate String userInfoUri = \"/userinfo\";\n\n\t\tpublic String getLogoutUri() {\n\t\t\treturn this.logoutUri;\n\t\t}\n\n\t\tpublic void setLogoutUri(String logoutUri) {\n\t\t\tthis.logoutUri = logoutUri;\n\t\t}\n\n\t\tpublic String getClientRegistrationUri() {\n\t\t\treturn this.clientRegistrationUri;\n\t\t}\n\n\t\tpublic void setClientRegistrationUri(String clientRegistrationUri) {\n\t\t\tthis.clientRegistrationUri = clientRegistrationUri;\n\t\t}\n\n\t\tpublic String getUserInfoUri() {\n\t\t\treturn this.userInfoUri;\n\t\t}\n\n\t\tpublic void setUserInfoUri(String userInfoUri) {\n\t\t\tthis.userInfoUri = userInfoUri;\n\t\t}\n\n\t}\n\n\t/**\n\t * A registered client of the Authorization Server.\n\t */\n\tpublic static class Client {\n\n\t\t/**\n\t\t * Client registration information.\n\t\t */\n\t\t@NestedConfigurationProperty\n\t\tprivate final Registration registration = new Registration();\n\n\t\t/**\n\t\t * Whether the client is required to provide a proof key challenge and verifier\n\t\t * when performing the Authorization Code Grant flow.\n\t\t */\n\t\tprivate boolean requireProofKey = true;\n\n\t\t/**\n\t\t * Whether authorization consent is required when the client requests access.\n\t\t */\n\t\tprivate boolean requireAuthorizationConsent;\n\n\t\t/**\n\t\t * URL for the client's JSON Web Key Set.\n\t\t */\n\t\tprivate @Nullable String jwkSetUri;\n\n\t\t/**\n\t\t * JWS algorithm that must be used for signing the JWT used to authenticate the\n\t\t * client at the Token Endpoint for the {@code private_key_jwt} and\n\t\t * {@code client_secret_jwt} authentication methods.\n\t\t */\n\t\tprivate @Nullable String tokenEndpointAuthenticationSigningAlgorithm;\n\n\t\t/**\n\t\t * Token settings of the registered client.\n\t\t */\n\t\t@NestedConfigurationProperty\n\t\tprivate final Token token = new Token();\n\n\t\tpublic Registration getRegistration() {\n\t\t\treturn this.registration;\n\t\t}\n\n\t\tpublic boolean isRequireProofKey() {\n\t\t\treturn this.requireProofKey;\n\t\t}\n\n\t\tpublic void setRequireProofKey(boolean requireProofKey) {\n\t\t\tthis.requireProofKey = requireProofKey;\n\t\t}\n\n\t\tpublic boolean isRequireAuthorizationConsent() {\n\t\t\treturn this.requireAuthorizationConsent;\n\t\t}\n\n\t\tpublic void setRequireAuthorizationConsent(boolean requireAuthorizationConsent) {\n\t\t\tthis.requireAuthorizationConsent = requireAuthorizationConsent;\n\t\t}\n\n\t\tpublic @Nullable String getJwkSetUri() {\n\t\t\treturn this.jwkSetUri;\n\t\t}\n\n\t\tpublic void setJwkSetUri(@Nullable String jwkSetUri) {\n\t\t\tthis.jwkSetUri = jwkSetUri;\n\t\t}\n\n\t\tpublic @Nullable String getTokenEndpointAuthenticationSigningAlgorithm() {\n\t\t\treturn this.tokenEndpointAuthenticationSigningAlgorithm;\n\t\t}\n\n\t\tpublic void setTokenEndpointAuthenticationSigningAlgorithm(\n\t\t\t\t@Nullable String tokenEndpointAuthenticationSigningAlgorithm) {\n\t\t\tthis.tokenEndpointAuthenticationSigningAlgorithm = tokenEndpointAuthenticationSigningAlgorithm;\n\t\t}\n\n\t\tpublic Token getToken() {\n\t\t\treturn this.token;\n\t\t}\n\n\t}\n\n\t/**\n\t * Client registration information.\n\t */\n\tpublic static class Registration {\n\n\t\t/**\n\t\t * Client ID of the registration.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Client secret of the registration. May be left blank for a public client.\n\t\t */\n\t\tprivate @Nullable String clientSecret;\n\n\t\t/**\n\t\t * Name of the client.\n\t\t */\n\t\tprivate @Nullable String clientName;\n\n\t\t/**\n\t\t * Client authentication method(s) that the client may use.\n\t\t */\n\t\tprivate Set<String> clientAuthenticationMethods = new HashSet<>();\n\n\t\t/**\n\t\t * Authorization grant type(s) that the client may use.\n\t\t */\n\t\tprivate Set<String> authorizationGrantTypes = new HashSet<>();\n\n\t\t/**\n\t\t * Redirect URI(s) that the client may use in redirect-based flows.\n\t\t */\n\t\tprivate Set<String> redirectUris = new HashSet<>();\n\n\t\t/**\n\t\t * Redirect URI(s) that the client may use for logout.\n\t\t */\n\t\tprivate Set<String> postLogoutRedirectUris = new HashSet<>();\n\n\t\t/**\n\t\t * Scope(s) that the client may use.\n\t\t */\n\t\tprivate Set<String> scopes = new HashSet<>();\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable String getClientSecret() {\n\t\t\treturn this.clientSecret;\n\t\t}\n\n\t\tpublic void setClientSecret(@Nullable String clientSecret) {\n\t\t\tthis.clientSecret = clientSecret;\n\t\t}\n\n\t\tpublic @Nullable String getClientName() {\n\t\t\treturn this.clientName;\n\t\t}\n\n\t\tpublic void setClientName(@Nullable String clientName) {\n\t\t\tthis.clientName = clientName;\n\t\t}\n\n\t\tpublic Set<String> getClientAuthenticationMethods() {\n\t\t\treturn this.clientAuthenticationMethods;\n\t\t}\n\n\t\tpublic void setClientAuthenticationMethods(Set<String> clientAuthenticationMethods) {\n\t\t\tthis.clientAuthenticationMethods = clientAuthenticationMethods;\n\t\t}\n\n\t\tpublic Set<String> getAuthorizationGrantTypes() {\n\t\t\treturn this.authorizationGrantTypes;\n\t\t}\n\n\t\tpublic void setAuthorizationGrantTypes(Set<String> authorizationGrantTypes) {\n\t\t\tthis.authorizationGrantTypes = authorizationGrantTypes;\n\t\t}\n\n\t\tpublic Set<String> getRedirectUris() {\n\t\t\treturn this.redirectUris;\n\t\t}\n\n\t\tpublic void setRedirectUris(Set<String> redirectUris) {\n\t\t\tthis.redirectUris = redirectUris;\n\t\t}\n\n\t\tpublic Set<String> getPostLogoutRedirectUris() {\n\t\t\treturn this.postLogoutRedirectUris;\n\t\t}\n\n\t\tpublic void setPostLogoutRedirectUris(Set<String> postLogoutRedirectUris) {\n\t\t\tthis.postLogoutRedirectUris = postLogoutRedirectUris;\n\t\t}\n\n\t\tpublic Set<String> getScopes() {\n\t\t\treturn this.scopes;\n\t\t}\n\n\t\tpublic void setScopes(Set<String> scopes) {\n\t\t\tthis.scopes = scopes;\n\t\t}\n\n\t}\n\n\t/**\n\t * Token settings of the registered client.\n\t */\n\tpublic static class Token {\n\n\t\t/**\n\t\t * Time-to-live for an authorization code.\n\t\t */\n\t\tprivate Duration authorizationCodeTimeToLive = Duration.ofMinutes(5);\n\n\t\t/**\n\t\t * Time-to-live for an access token.\n\t\t */\n\t\tprivate Duration accessTokenTimeToLive = Duration.ofMinutes(5);\n\n\t\t/**\n\t\t * Token format for an access token.\n\t\t */\n\t\tprivate String accessTokenFormat = \"self-contained\";\n\n\t\t/**\n\t\t * Time-to-live for a device code.\n\t\t */\n\t\tprivate Duration deviceCodeTimeToLive = Duration.ofMinutes(5);\n\n\t\t/**\n\t\t * Whether refresh tokens are reused or a new refresh token is issued when\n\t\t * returning the access token response.\n\t\t */\n\t\tprivate boolean reuseRefreshTokens = true;\n\n\t\t/**\n\t\t * Time-to-live for a refresh token.\n\t\t */\n\t\tprivate Duration refreshTokenTimeToLive = Duration.ofMinutes(60);\n\n\t\t/**\n\t\t * JWS algorithm for signing the ID Token.\n\t\t */\n\t\tprivate String idTokenSignatureAlgorithm = \"RS256\";\n\n\t\tpublic Duration getAuthorizationCodeTimeToLive() {\n\t\t\treturn this.authorizationCodeTimeToLive;\n\t\t}\n\n\t\tpublic void setAuthorizationCodeTimeToLive(Duration authorizationCodeTimeToLive) {\n\t\t\tthis.authorizationCodeTimeToLive = authorizationCodeTimeToLive;\n\t\t}\n\n\t\tpublic Duration getAccessTokenTimeToLive() {\n\t\t\treturn this.accessTokenTimeToLive;\n\t\t}\n\n\t\tpublic void setAccessTokenTimeToLive(Duration accessTokenTimeToLive) {\n\t\t\tthis.accessTokenTimeToLive = accessTokenTimeToLive;\n\t\t}\n\n\t\tpublic String getAccessTokenFormat() {\n\t\t\treturn this.accessTokenFormat;\n\t\t}\n\n\t\tpublic void setAccessTokenFormat(String accessTokenFormat) {\n\t\t\tthis.accessTokenFormat = accessTokenFormat;\n\t\t}\n\n\t\tpublic Duration getDeviceCodeTimeToLive() {\n\t\t\treturn this.deviceCodeTimeToLive;\n\t\t}\n\n\t\tpublic void setDeviceCodeTimeToLive(Duration deviceCodeTimeToLive) {\n\t\t\tthis.deviceCodeTimeToLive = deviceCodeTimeToLive;\n\t\t}\n\n\t\tpublic boolean isReuseRefreshTokens() {\n\t\t\treturn this.reuseRefreshTokens;\n\t\t}\n\n\t\tpublic void setReuseRefreshTokens(boolean reuseRefreshTokens) {\n\t\t\tthis.reuseRefreshTokens = reuseRefreshTokens;\n\t\t}\n\n\t\tpublic Duration getRefreshTokenTimeToLive() {\n\t\t\treturn this.refreshTokenTimeToLive;\n\t\t}\n\n\t\tpublic void setRefreshTokenTimeToLive(Duration refreshTokenTimeToLive) {\n\t\t\tthis.refreshTokenTimeToLive = refreshTokenTimeToLive;\n\t\t}\n\n\t\tpublic String getIdTokenSignatureAlgorithm() {\n\t\t\treturn this.idTokenSignatureAlgorithm;\n\t\t}\n\n\t\tpublic void setIdTokenSignatureAlgorithm(String idTokenSignatureAlgorithm) {\n\t\t\tthis.idTokenSignatureAlgorithm = idTokenSignatureAlgorithm;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerPropertiesMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet.OAuth2AuthorizationServerProperties.Client;\nimport org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet.OAuth2AuthorizationServerProperties.Registration;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.jose.jws.JwsAlgorithm;\nimport org.springframework.security.oauth2.jose.jws.MacAlgorithm;\nimport org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.ClientSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;\nimport org.springframework.security.oauth2.server.authorization.settings.TokenSettings;\nimport org.springframework.util.Assert;\n\n/**\n * Maps {@link OAuth2AuthorizationServerProperties} to Authorization Server types.\n *\n * @author Steve Riesenberg\n * @author Florian Lemaire\n */\nfinal class OAuth2AuthorizationServerPropertiesMapper {\n\n\tprivate final OAuth2AuthorizationServerProperties properties;\n\n\tOAuth2AuthorizationServerPropertiesMapper(OAuth2AuthorizationServerProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\tAuthorizationServerSettings asAuthorizationServerSettings() {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tOAuth2AuthorizationServerProperties.Endpoint endpoint = this.properties.getEndpoint();\n\t\tOAuth2AuthorizationServerProperties.OidcEndpoint oidc = endpoint.getOidc();\n\t\tAuthorizationServerSettings.Builder builder = AuthorizationServerSettings.builder();\n\t\tmap.from(this.properties::getIssuer).to(builder::issuer);\n\t\tmap.from(this.properties::isMultipleIssuersAllowed).to(builder::multipleIssuersAllowed);\n\t\tmap.from(endpoint::getAuthorizationUri).to(builder::authorizationEndpoint);\n\t\tmap.from(endpoint::getDeviceAuthorizationUri).to(builder::deviceAuthorizationEndpoint);\n\t\tmap.from(endpoint::getDeviceVerificationUri).to(builder::deviceVerificationEndpoint);\n\t\tmap.from(endpoint::getTokenUri).to(builder::tokenEndpoint);\n\t\tmap.from(endpoint::getJwkSetUri).to(builder::jwkSetEndpoint);\n\t\tmap.from(endpoint::getTokenRevocationUri).to(builder::tokenRevocationEndpoint);\n\t\tmap.from(endpoint::getTokenIntrospectionUri).to(builder::tokenIntrospectionEndpoint);\n\t\tmap.from(endpoint::getPushedAuthorizationRequestUri).to(builder::pushedAuthorizationRequestEndpoint);\n\t\tmap.from(oidc::getLogoutUri).to(builder::oidcLogoutEndpoint);\n\t\tmap.from(oidc::getClientRegistrationUri).to(builder::oidcClientRegistrationEndpoint);\n\t\tmap.from(oidc::getUserInfoUri).to(builder::oidcUserInfoEndpoint);\n\t\treturn builder.build();\n\t}\n\n\tList<RegisteredClient> asRegisteredClients() {\n\t\tList<RegisteredClient> registeredClients = new ArrayList<>();\n\t\tthis.properties.getClient()\n\t\t\t.forEach((registrationId, client) -> registeredClients.add(getRegisteredClient(registrationId, client)));\n\t\treturn registeredClients;\n\t}\n\n\tprivate RegisteredClient getRegisteredClient(String registrationId, Client client) {\n\t\tRegistration registration = client.getRegistration();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tRegisteredClient.Builder builder = RegisteredClient.withId(registrationId);\n\t\tmap.from(registration::getClientId).to(builder::clientId);\n\t\tmap.from(registration::getClientSecret).to(builder::clientSecret);\n\t\tmap.from(registration::getClientName).to(builder::clientName);\n\t\tregistration.getClientAuthenticationMethods()\n\t\t\t.forEach((clientAuthenticationMethod) -> map.from(clientAuthenticationMethod)\n\t\t\t\t.as(ClientAuthenticationMethod::new)\n\t\t\t\t.to(builder::clientAuthenticationMethod));\n\t\tregistration.getAuthorizationGrantTypes()\n\t\t\t.forEach((authorizationGrantType) -> map.from(authorizationGrantType)\n\t\t\t\t.as(AuthorizationGrantType::new)\n\t\t\t\t.to(builder::authorizationGrantType));\n\t\tregistration.getRedirectUris().forEach((redirectUri) -> map.from(redirectUri).to(builder::redirectUri));\n\t\tregistration.getPostLogoutRedirectUris()\n\t\t\t.forEach((redirectUri) -> map.from(redirectUri).to(builder::postLogoutRedirectUri));\n\t\tregistration.getScopes().forEach((scope) -> map.from(scope).to(builder::scope));\n\t\tbuilder.clientSettings(getClientSettings(client, map));\n\t\tbuilder.tokenSettings(getTokenSettings(client, map));\n\t\treturn builder.build();\n\t}\n\n\tprivate ClientSettings getClientSettings(Client client, PropertyMapper map) {\n\t\tClientSettings.Builder builder = ClientSettings.builder();\n\t\tmap.from(client::isRequireProofKey).to(builder::requireProofKey);\n\t\tmap.from(client::isRequireAuthorizationConsent).to(builder::requireAuthorizationConsent);\n\t\tmap.from(client::getJwkSetUri).to(builder::jwkSetUrl);\n\t\tmap.from(client::getTokenEndpointAuthenticationSigningAlgorithm)\n\t\t\t.as(this::jwsAlgorithm)\n\t\t\t.to(builder::tokenEndpointAuthenticationSigningAlgorithm);\n\t\treturn builder.build();\n\t}\n\n\tprivate TokenSettings getTokenSettings(Client client, PropertyMapper map) {\n\t\tOAuth2AuthorizationServerProperties.Token token = client.getToken();\n\t\tTokenSettings.Builder builder = TokenSettings.builder();\n\t\tmap.from(token::getAuthorizationCodeTimeToLive).to(builder::authorizationCodeTimeToLive);\n\t\tmap.from(token::getAccessTokenTimeToLive).to(builder::accessTokenTimeToLive);\n\t\tmap.from(token::getAccessTokenFormat).as(OAuth2TokenFormat::new).to(builder::accessTokenFormat);\n\t\tmap.from(token::getDeviceCodeTimeToLive).to(builder::deviceCodeTimeToLive);\n\t\tmap.from(token::isReuseRefreshTokens).to(builder::reuseRefreshTokens);\n\t\tmap.from(token::getRefreshTokenTimeToLive).to(builder::refreshTokenTimeToLive);\n\t\tmap.from(token::getIdTokenSignatureAlgorithm)\n\t\t\t.as(this::signatureAlgorithm)\n\t\t\t.to(builder::idTokenSignatureAlgorithm);\n\t\treturn builder.build();\n\t}\n\n\tprivate JwsAlgorithm jwsAlgorithm(String signingAlgorithm) {\n\t\tString name = signingAlgorithm.toUpperCase(Locale.ROOT);\n\t\tJwsAlgorithm jwsAlgorithm = SignatureAlgorithm.from(name);\n\t\tif (jwsAlgorithm == null) {\n\t\t\tjwsAlgorithm = MacAlgorithm.from(name);\n\t\t}\n\t\tAssert.notNull(jwsAlgorithm, \"JWS algorithm \" + name + \" is unknown\");\n\t\treturn jwsAlgorithm;\n\t}\n\n\tprivate SignatureAlgorithm signatureAlgorithm(String signatureAlgorithm) {\n\t\tSignatureAlgorithm algorithm = SignatureAlgorithm.from(signatureAlgorithm.toUpperCase(Locale.ROOT));\n\t\tAssert.notNull(algorithm, \"Signature algorithm \" + signatureAlgorithm + \" is unknown\");\n\t\treturn algorithm;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerWebSecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.util.Set;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity;\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;\nimport org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;\nimport org.springframework.security.web.util.matcher.RequestMatcher;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link Configuration @Configuration} for OAuth2 authorization server support.\n *\n * @author Steve Riesenberg\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnDefaultWebSecurity\n@ConditionalOnBean({ RegisteredClientRepository.class, AuthorizationServerSettings.class })\nclass OAuth2AuthorizationServerWebSecurityConfiguration {\n\n\t@Bean\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tSecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) {\n\t\thttp.oauth2AuthorizationServer((authorizationServer) -> {\n\t\t\thttp.securityMatcher(authorizationServer.getEndpointsMatcher());\n\t\t\tauthorizationServer.oidc(withDefaults());\n\t\t});\n\t\thttp.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());\n\t\thttp.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()));\n\t\thttp.exceptionHandling((exceptions) -> exceptions.defaultAuthenticationEntryPointFor(\n\t\t\t\tnew LoginUrlAuthenticationEntryPoint(\"/login\"), createRequestMatcher()));\n\t\treturn http.build();\n\t}\n\n\t@Bean\n\t@Order(SecurityFilterProperties.BASIC_AUTH_ORDER)\n\tSecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated()).formLogin(withDefaults());\n\t\treturn http.build();\n\t}\n\n\tprivate static RequestMatcher createRequestMatcher() {\n\t\tMediaTypeRequestMatcher requestMatcher = new MediaTypeRequestMatcher(MediaType.TEXT_HTML);\n\t\trequestMatcher.setIgnoredMediaTypes(Set.of(MediaType.ALL));\n\t\treturn requestMatcher;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/RegisteredClientsConfiguredCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * Condition that matches if any {@code spring.security.oauth2.authorizationserver.client}\n * properties are defined.\n *\n * @author Steve Riesenberg\n */\nclass RegisteredClientsConfiguredCondition extends SpringBootCondition {\n\n\tprivate static final Bindable<Map<String, OAuth2AuthorizationServerProperties.Client>> STRING_CLIENT_MAP = Bindable\n\t\t.mapOf(String.class, OAuth2AuthorizationServerProperties.Client.class);\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage\n\t\t\t.forCondition(\"OAuth2 Registered Clients Configured Condition\");\n\t\tMap<String, OAuth2AuthorizationServerProperties.Client> registrations = getRegistrations(\n\t\t\t\tcontext.getEnvironment());\n\t\tif (!registrations.isEmpty()) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"registered clients \" + registrations.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(OAuth2AuthorizationServerProperties.Client::getRegistration)\n\t\t\t\t.map(OAuth2AuthorizationServerProperties.Registration::getClientId)\n\t\t\t\t.collect(Collectors.joining(\", \"))));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.notAvailable(\"registered clients\"));\n\t}\n\n\tprivate Map<String, OAuth2AuthorizationServerProperties.Client> getRegistrations(Environment environment) {\n\t\treturn Binder.get(environment)\n\t\t\t.bind(\"spring.security.oauth2.authorizationserver.client\", STRING_CLIENT_MAP)\n\t\t\t.orElse(Collections.emptyMap());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Security's OAuth2 authorization server.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet.OAuth2AuthorizationServerAutoConfiguration\norg.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet.OAuth2AuthorizationServerJwtAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/test/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.server.authorization.OAuth2Authorization;\nimport org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link OAuth2AuthorizationServerAutoConfiguration}.\n *\n * @author Steve Riesenberg\n * @author Madhura Bhave\n * @author Florian Lemaire\n */\nclass OAuth2AuthorizationServerAutoConfigurationTests {\n\n\tprivate static final String PROPERTIES_PREFIX = \"spring.security.oauth2.authorizationserver\";\n\n\tprivate static final String CLIENT_PREFIX = PROPERTIES_PREFIX + \".client\";\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OAuth2AuthorizationServerAutoConfiguration.class,\n\t\t\t\tOAuth2AuthorizationServerJwtAutoConfiguration.class, SecurityAutoConfiguration.class,\n\t\t\t\tServletWebSecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationConditionalOnClassOauth2Authorization() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(OAuth2Authorization.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OAuth2AuthorizationServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-security-oauth2-client-*.jar\", \"spring-security-oauth2-resource-server-*.jar\",\n\t\t\t\"spring-security-saml2-service-provider-*.jar\" })\n\tvoid autoConfigurationDoesNotCauseUserDetailsServiceToBackOff() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(UserDetailsServiceAutoConfiguration.class)\n\t\t\t.hasBean(\"inMemoryUserDetailsManager\"));\n\t}\n\n\t@Test\n\tvoid registeredClientRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(RegisteredClientRepository.class));\n\t}\n\n\t@Test\n\tvoid registeredClientRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(CLIENT_PREFIX + \".foo.registration.client-id=abcd\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-secret=secret\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-authentication-methods=client_secret_basic\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.authorization-grant-types=client_credentials\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.scopes=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tRegisteredClientRepository registeredClientRepository = context\n\t\t\t\t\t.getBean(RegisteredClientRepository.class);\n\t\t\t\tRegisteredClient registeredClient = registeredClientRepository.findById(\"foo\");\n\t\t\t\tassertThat(registeredClient).isNotNull();\n\t\t\t\tassertThat(registeredClient.getClientId()).isEqualTo(\"abcd\");\n\t\t\t\tassertThat(registeredClient.getClientSecret()).isEqualTo(\"secret\");\n\t\t\t\tassertThat(registeredClient.getClientAuthenticationMethods())\n\t\t\t\t\t.containsOnly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);\n\t\t\t\tassertThat(registeredClient.getAuthorizationGrantTypes())\n\t\t\t\t\t.containsOnly(AuthorizationGrantType.CLIENT_CREDENTIALS);\n\t\t\t\tassertThat(registeredClient.getScopes()).containsOnly(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registeredClientRepositoryBacksOffWhenRegisteredClientRepositoryBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestRegisteredClientRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(CLIENT_PREFIX + \".foo.registration.client-id=abcd\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-secret=secret\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-authentication-methods=client_secret_basic\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.authorization-grant-types=client_credentials\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.scope=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tRegisteredClientRepository registeredClientRepository = context\n\t\t\t\t\t.getBean(RegisteredClientRepository.class);\n\t\t\t\tRegisteredClient registeredClient = registeredClientRepository.findById(\"test\");\n\t\t\t\tassertThat(registeredClient).isNotNull();\n\t\t\t\tassertThat(registeredClient.getClientId()).isEqualTo(\"abcd\");\n\t\t\t\tassertThat(registeredClient.getClientSecret()).isEqualTo(\"secret\");\n\t\t\t\tassertThat(registeredClient.getClientAuthenticationMethods())\n\t\t\t\t\t.containsOnly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);\n\t\t\t\tassertThat(registeredClient.getAuthorizationGrantTypes())\n\t\t\t\t\t.containsOnly(AuthorizationGrantType.CLIENT_CREDENTIALS);\n\t\t\t\tassertThat(registeredClient.getScopes()).containsOnly(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid authorizationServerSettingsBeanShouldBeCreatedWhenPropertiesAbsent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(AuthorizationServerSettings.class));\n\t}\n\n\t@Test\n\tvoid authorizationServerSettingsBeanShouldBeCreatedWhenPropertiesPresent() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(PROPERTIES_PREFIX + \".issuer=https://example.com\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.authorization-uri=/authorize\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.device-authorization-uri=/device_authorization\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.device-verification-uri=/device_verification\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.token-uri=/token\", PROPERTIES_PREFIX + \".endpoint.jwk-set-uri=/jwks\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.token-revocation-uri=/revoke\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.token-introspection-uri=/introspect\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.pushed-authorization-request-uri=/par\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.oidc.logout-uri=/logout\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.oidc.client-registration-uri=/register\",\n\t\t\t\t\tPROPERTIES_PREFIX + \".endpoint.oidc.user-info-uri=/user\")\n\t\t\t.run((context) -> {\n\t\t\t\tAuthorizationServerSettings settings = context.getBean(AuthorizationServerSettings.class);\n\t\t\t\tassertThat(settings.getIssuer()).isEqualTo(\"https://example.com\");\n\t\t\t\tassertThat(settings.getAuthorizationEndpoint()).isEqualTo(\"/authorize\");\n\t\t\t\tassertThat(settings.getDeviceAuthorizationEndpoint()).isEqualTo(\"/device_authorization\");\n\t\t\t\tassertThat(settings.getDeviceVerificationEndpoint()).isEqualTo(\"/device_verification\");\n\t\t\t\tassertThat(settings.getTokenEndpoint()).isEqualTo(\"/token\");\n\t\t\t\tassertThat(settings.getJwkSetEndpoint()).isEqualTo(\"/jwks\");\n\t\t\t\tassertThat(settings.getTokenRevocationEndpoint()).isEqualTo(\"/revoke\");\n\t\t\t\tassertThat(settings.getTokenIntrospectionEndpoint()).isEqualTo(\"/introspect\");\n\t\t\t\tassertThat(settings.getPushedAuthorizationRequestEndpoint()).isEqualTo(\"/par\");\n\t\t\t\tassertThat(settings.getOidcLogoutEndpoint()).isEqualTo(\"/logout\");\n\t\t\t\tassertThat(settings.getOidcClientRegistrationEndpoint()).isEqualTo(\"/register\");\n\t\t\t\tassertThat(settings.getOidcUserInfoEndpoint()).isEqualTo(\"/user\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid authorizationServerSettingsBacksOffWhenAuthorizationServerSettingsBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestAuthorizationServerSettingsConfiguration.class)\n\t\t\t.withPropertyValues(PROPERTIES_PREFIX + \".issuer=https://test.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tAuthorizationServerSettings settings = context.getBean(AuthorizationServerSettings.class);\n\t\t\t\tassertThat(settings.getIssuer()).isEqualTo(\"https://example.com\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid causesManagementWebSecurityAutoConfigurationToBackOff() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(CLIENT_PREFIX + \".foo.registration.client-id=abcd\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-secret=secret\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-authentication-methods=client_secret_basic\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.authorization-grant-types=client_credentials\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.scopes=test\")\n\t\t\t.withConfiguration(AutoConfigurations.of(ManagementWebSecurityAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class)\n\t\t\t\t.doesNotHaveBean(\"managementSecurityFilterChain\"));\n\t}\n\n\t@Configuration\n\tstatic class TestRegisteredClientRepositoryConfiguration {\n\n\t\t@Bean\n\t\tRegisteredClientRepository registeredClientRepository() {\n\t\t\tRegisteredClient registeredClient = RegisteredClient.withId(\"test\")\n\t\t\t\t.clientId(\"abcd\")\n\t\t\t\t.clientSecret(\"secret\")\n\t\t\t\t.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n\t\t\t\t.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)\n\t\t\t\t.scope(\"test\")\n\t\t\t\t.build();\n\t\t\treturn new InMemoryRegisteredClientRepository(registeredClient);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class TestAuthorizationServerSettingsConfiguration {\n\n\t\t@Bean\n\t\tAuthorizationServerSettings authorizationServerSettings() {\n\t\t\treturn AuthorizationServerSettings.builder().issuer(\"https://example.com\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/test/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerJwtAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport com.nimbusds.jose.jwk.source.ImmutableJWKSet;\nimport com.nimbusds.jose.jwk.source.JWKSource;\nimport com.nimbusds.jose.proc.SecurityContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder;\nimport org.springframework.security.oauth2.server.authorization.OAuth2Authorization;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OAuth2AuthorizationServerJwtAutoConfiguration}.\n *\n * @author Steve Riesenberg\n */\nclass OAuth2AuthorizationServerJwtAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OAuth2AuthorizationServerJwtAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationConditionalOnClassOAuth2Authorization() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(OAuth2Authorization.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OAuth2AuthorizationServerJwtAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationConditionalOnClassJWKSource() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JWKSource.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OAuth2AuthorizationServerJwtAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid jwtDecoderConditionalOnClassJwtDecoder() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(JwtDecoder.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizationServerJwtAutoConfiguration.class)\n\t\t\t\t.doesNotHaveBean(\"jwtDecoder\"));\n\t}\n\n\t@Test\n\tvoid jwtConfigurationConfiguresJwtDecoderWithGeneratedKey() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasBean(\"jwtDecoder\");\n\t\t\tassertThat(context.getBean(\"jwtDecoder\")).isInstanceOf(NimbusJwtDecoder.class);\n\t\t\tassertThat(context).hasBean(\"jwkSource\");\n\t\t\tassertThat(context.getBean(\"jwkSource\")).isInstanceOf(ImmutableJWKSet.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jwtDecoderBacksOffWhenBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestJwtDecoderConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"jwtDecoder\");\n\t\t\tassertThat(context.getBean(\"jwtDecoder\")).isNotInstanceOf(NimbusJwtDecoder.class);\n\t\t\tassertThat(context).hasBean(\"jwkSource\");\n\t\t\tassertThat(context.getBean(\"jwkSource\")).isInstanceOf(ImmutableJWKSet.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jwkSourceBacksOffWhenBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(TestJwkSourceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"jwtDecoder\");\n\t\t\tassertThat(context.getBean(\"jwtDecoder\")).isInstanceOf(NimbusJwtDecoder.class);\n\t\t\tassertThat(context).hasBean(\"jwkSource\");\n\t\t\tassertThat(context.getBean(\"jwkSource\")).isNotInstanceOf(ImmutableJWKSet.class);\n\t\t});\n\t}\n\n\t@Configuration\n\tstatic class TestJwtDecoderConfiguration {\n\n\t\t@Bean\n\t\tJwtDecoder jwtDecoder() {\n\t\t\treturn mock(JwtDecoder.class);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class TestJwkSourceConfiguration {\n\n\t\t@Bean\n\t\tJWKSource<SecurityContext> jwkSource() {\n\t\t\treturn (jwkSelector, context) -> null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/test/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerPropertiesMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.time.Duration;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OAuth2AuthorizationServerPropertiesMapper}.\n *\n * @author Steve Riesenberg\n * @author Florian Lemaire\n */\nclass OAuth2AuthorizationServerPropertiesMapperTests {\n\n\tprivate final OAuth2AuthorizationServerProperties properties = new OAuth2AuthorizationServerProperties();\n\n\tprivate final OAuth2AuthorizationServerPropertiesMapper mapper = new OAuth2AuthorizationServerPropertiesMapper(\n\t\t\tthis.properties);\n\n\t@Test\n\tvoid getRegisteredClientsWhenValidParametersShouldAdapt() {\n\t\tOAuth2AuthorizationServerProperties.Client client = createClient();\n\t\tthis.properties.getClient().put(\"foo\", client);\n\t\tList<RegisteredClient> registeredClients = this.mapper.asRegisteredClients();\n\t\tassertThat(registeredClients).hasSize(1);\n\t\tRegisteredClient registeredClient = registeredClients.get(0);\n\t\tassertThat(registeredClient.getClientId()).isEqualTo(\"foo\");\n\t\tassertThat(registeredClient.getClientSecret()).isEqualTo(\"secret\");\n\t\tassertThat(registeredClient.getClientAuthenticationMethods())\n\t\t\t.containsExactly(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);\n\t\tassertThat(registeredClient.getAuthorizationGrantTypes())\n\t\t\t.containsExactly(AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(registeredClient.getRedirectUris()).containsExactly(\"https://example.com/redirect\");\n\t\tassertThat(registeredClient.getPostLogoutRedirectUris()).containsExactly(\"https://example.com/logout\");\n\t\tassertThat(registeredClient.getScopes()).containsExactly(\"user.read\");\n\t\tassertThat(registeredClient.getClientSettings().isRequireProofKey()).isTrue();\n\t\tassertThat(registeredClient.getClientSettings().isRequireAuthorizationConsent()).isTrue();\n\t\tassertThat(registeredClient.getClientSettings().getJwkSetUrl()).isEqualTo(\"https://example.com/jwks\");\n\t\tassertThat(registeredClient.getClientSettings().getTokenEndpointAuthenticationSigningAlgorithm())\n\t\t\t.isEqualTo(SignatureAlgorithm.RS256);\n\t\tassertThat(registeredClient.getTokenSettings().getAccessTokenFormat()).isEqualTo(OAuth2TokenFormat.REFERENCE);\n\t\tassertThat(registeredClient.getTokenSettings().getAccessTokenTimeToLive()).isEqualTo(Duration.ofSeconds(300));\n\t\tassertThat(registeredClient.getTokenSettings().getRefreshTokenTimeToLive()).isEqualTo(Duration.ofHours(24));\n\t\tassertThat(registeredClient.getTokenSettings().getDeviceCodeTimeToLive()).isEqualTo(Duration.ofMinutes(30));\n\t\tassertThat(registeredClient.getTokenSettings().isReuseRefreshTokens()).isEqualTo(true);\n\t\tassertThat(registeredClient.getTokenSettings().getIdTokenSignatureAlgorithm())\n\t\t\t.isEqualTo(SignatureAlgorithm.RS512);\n\t}\n\n\tprivate OAuth2AuthorizationServerProperties.Client createClient() {\n\t\tOAuth2AuthorizationServerProperties.Client client = new OAuth2AuthorizationServerProperties.Client();\n\t\tclient.setRequireProofKey(true);\n\t\tclient.setRequireAuthorizationConsent(true);\n\t\tclient.setJwkSetUri(\"https://example.com/jwks\");\n\t\tclient.setTokenEndpointAuthenticationSigningAlgorithm(\"rs256\");\n\t\tOAuth2AuthorizationServerProperties.Registration registration = client.getRegistration();\n\t\tregistration.setClientId(\"foo\");\n\t\tregistration.setClientSecret(\"secret\");\n\t\tregistration.getClientAuthenticationMethods().add(\"client_secret_basic\");\n\t\tregistration.getAuthorizationGrantTypes().add(\"authorization_code\");\n\t\tregistration.getRedirectUris().add(\"https://example.com/redirect\");\n\t\tregistration.getPostLogoutRedirectUris().add(\"https://example.com/logout\");\n\t\tregistration.getScopes().add(\"user.read\");\n\t\tOAuth2AuthorizationServerProperties.Token token = client.getToken();\n\t\ttoken.setAccessTokenFormat(\"reference\");\n\t\ttoken.setAccessTokenTimeToLive(Duration.ofSeconds(300));\n\t\ttoken.setRefreshTokenTimeToLive(Duration.ofHours(24));\n\t\ttoken.setDeviceCodeTimeToLive(Duration.ofMinutes(30));\n\t\ttoken.setReuseRefreshTokens(true);\n\t\ttoken.setIdTokenSignatureAlgorithm(\"rs512\");\n\t\treturn client;\n\t}\n\n\t@Test\n\tvoid getAuthorizationServerSettingsWhenValidParametersShouldAdapt() {\n\t\tthis.properties.setIssuer(\"https://example.com\");\n\t\tOAuth2AuthorizationServerProperties.Endpoint endpoints = this.properties.getEndpoint();\n\t\tendpoints.setAuthorizationUri(\"/authorize\");\n\t\tendpoints.setDeviceAuthorizationUri(\"/device_authorization\");\n\t\tendpoints.setDeviceVerificationUri(\"/device_verification\");\n\t\tendpoints.setTokenUri(\"/token\");\n\t\tendpoints.setJwkSetUri(\"/jwks\");\n\t\tendpoints.setTokenRevocationUri(\"/revoke\");\n\t\tendpoints.setTokenIntrospectionUri(\"/introspect\");\n\t\tendpoints.setPushedAuthorizationRequestUri(\"/par\");\n\t\tOAuth2AuthorizationServerProperties.OidcEndpoint oidc = endpoints.getOidc();\n\t\toidc.setLogoutUri(\"/logout\");\n\t\toidc.setClientRegistrationUri(\"/register\");\n\t\toidc.setUserInfoUri(\"/user\");\n\t\tAuthorizationServerSettings settings = this.mapper.asAuthorizationServerSettings();\n\t\tassertThat(settings.getIssuer()).isEqualTo(\"https://example.com\");\n\t\tassertThat(settings.isMultipleIssuersAllowed()).isFalse();\n\t\tassertThat(settings.getAuthorizationEndpoint()).isEqualTo(\"/authorize\");\n\t\tassertThat(settings.getDeviceAuthorizationEndpoint()).isEqualTo(\"/device_authorization\");\n\t\tassertThat(settings.getDeviceVerificationEndpoint()).isEqualTo(\"/device_verification\");\n\t\tassertThat(settings.getTokenEndpoint()).isEqualTo(\"/token\");\n\t\tassertThat(settings.getJwkSetEndpoint()).isEqualTo(\"/jwks\");\n\t\tassertThat(settings.getTokenRevocationEndpoint()).isEqualTo(\"/revoke\");\n\t\tassertThat(settings.getTokenIntrospectionEndpoint()).isEqualTo(\"/introspect\");\n\t\tassertThat(settings.getPushedAuthorizationRequestEndpoint()).isEqualTo(\"/par\");\n\t\tassertThat(settings.getOidcLogoutEndpoint()).isEqualTo(\"/logout\");\n\t\tassertThat(settings.getOidcClientRegistrationEndpoint()).isEqualTo(\"/register\");\n\t\tassertThat(settings.getOidcUserInfoEndpoint()).isEqualTo(\"/user\");\n\t}\n\n\t@Test\n\tvoid getAuthorizationServerSettingsWhenMultipleIssuersAllowedShouldAdapt() {\n\t\tthis.properties.setMultipleIssuersAllowed(true);\n\t\tOAuth2AuthorizationServerProperties.Endpoint endpoints = this.properties.getEndpoint();\n\t\tendpoints.setAuthorizationUri(\"/authorize\");\n\t\tendpoints.setDeviceAuthorizationUri(\"/device_authorization\");\n\t\tendpoints.setDeviceVerificationUri(\"/device_verification\");\n\t\tendpoints.setTokenUri(\"/token\");\n\t\tendpoints.setJwkSetUri(\"/jwks\");\n\t\tendpoints.setTokenRevocationUri(\"/revoke\");\n\t\tendpoints.setTokenIntrospectionUri(\"/introspect\");\n\t\tendpoints.setPushedAuthorizationRequestUri(\"/par\");\n\t\tOAuth2AuthorizationServerProperties.OidcEndpoint oidc = endpoints.getOidc();\n\t\toidc.setLogoutUri(\"/logout\");\n\t\toidc.setClientRegistrationUri(\"/register\");\n\t\toidc.setUserInfoUri(\"/user\");\n\t\tAuthorizationServerSettings settings = this.mapper.asAuthorizationServerSettings();\n\t\tassertThat(settings.getIssuer()).isNull();\n\t\tassertThat(settings.isMultipleIssuersAllowed()).isTrue();\n\t\tassertThat(settings.getAuthorizationEndpoint()).isEqualTo(\"/authorize\");\n\t\tassertThat(settings.getDeviceAuthorizationEndpoint()).isEqualTo(\"/device_authorization\");\n\t\tassertThat(settings.getDeviceVerificationEndpoint()).isEqualTo(\"/device_verification\");\n\t\tassertThat(settings.getTokenEndpoint()).isEqualTo(\"/token\");\n\t\tassertThat(settings.getJwkSetEndpoint()).isEqualTo(\"/jwks\");\n\t\tassertThat(settings.getTokenRevocationEndpoint()).isEqualTo(\"/revoke\");\n\t\tassertThat(settings.getTokenIntrospectionEndpoint()).isEqualTo(\"/introspect\");\n\t\tassertThat(settings.getPushedAuthorizationRequestEndpoint()).isEqualTo(\"/par\");\n\t\tassertThat(settings.getOidcLogoutEndpoint()).isEqualTo(\"/logout\");\n\t\tassertThat(settings.getOidcClientRegistrationEndpoint()).isEqualTo(\"/register\");\n\t\tassertThat(settings.getOidcUserInfoEndpoint()).isEqualTo(\"/user\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/test/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.ClientSettings;\nimport org.springframework.security.oauth2.server.authorization.settings.TokenSettings;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link OAuth2AuthorizationServerProperties}.\n *\n * @author Steve Riesenberg\n * @author Florian Lemaire\n */\nclass OAuth2AuthorizationServerPropertiesTests {\n\n\tprivate final OAuth2AuthorizationServerProperties properties = new OAuth2AuthorizationServerProperties();\n\n\t@Test\n\tvoid clientIdAbsentThrowsException() {\n\t\tOAuth2AuthorizationServerProperties.Client client = new OAuth2AuthorizationServerProperties.Client();\n\t\tclient.getRegistration().getClientAuthenticationMethods().add(\"client_secret_basic\");\n\t\tclient.getRegistration().getAuthorizationGrantTypes().add(\"authorization_code\");\n\t\tthis.properties.getClient().put(\"foo\", client);\n\t\tassertThatIllegalStateException().isThrownBy(this.properties::validate)\n\t\t\t.withMessage(\"Client id must not be empty.\");\n\t}\n\n\t@Test\n\tvoid clientSecretAbsentShouldNotThrowException() {\n\t\tOAuth2AuthorizationServerProperties.Client client = new OAuth2AuthorizationServerProperties.Client();\n\t\tclient.getRegistration().setClientId(\"foo\");\n\t\tclient.getRegistration().getClientAuthenticationMethods().add(\"client_secret_basic\");\n\t\tclient.getRegistration().getAuthorizationGrantTypes().add(\"authorization_code\");\n\t\tthis.properties.getClient().put(\"foo\", client);\n\t\tthis.properties.validate();\n\t}\n\n\t@Test\n\tvoid clientAuthenticationMethodsEmptyThrowsException() {\n\t\tOAuth2AuthorizationServerProperties.Client client = new OAuth2AuthorizationServerProperties.Client();\n\t\tclient.getRegistration().setClientId(\"foo\");\n\t\tclient.getRegistration().getAuthorizationGrantTypes().add(\"authorization_code\");\n\t\tthis.properties.getClient().put(\"foo\", client);\n\t\tassertThatIllegalStateException().isThrownBy(this.properties::validate)\n\t\t\t.withMessage(\"Client authentication methods must not be empty.\");\n\t}\n\n\t@Test\n\tvoid authorizationGrantTypesEmptyThrowsException() {\n\t\tOAuth2AuthorizationServerProperties.Client client = new OAuth2AuthorizationServerProperties.Client();\n\t\tclient.getRegistration().setClientId(\"foo\");\n\t\tclient.getRegistration().getClientAuthenticationMethods().add(\"client_secret_basic\");\n\t\tthis.properties.getClient().put(\"foo\", client);\n\t\tassertThatIllegalStateException().isThrownBy(this.properties::validate)\n\t\t\t.withMessage(\"Authorization grant types must not be empty.\");\n\t}\n\n\t@Test\n\tvoid defaultEndpointPropertiesMatchBuilderDefaults() {\n\t\tOAuth2AuthorizationServerProperties.Endpoint properties = new OAuth2AuthorizationServerProperties.Endpoint();\n\t\tAuthorizationServerSettings defaults = AuthorizationServerSettings.builder().build();\n\t\tassertThat(properties.getAuthorizationUri()).isEqualTo(defaults.getAuthorizationEndpoint());\n\t\tassertThat(properties.getDeviceAuthorizationUri()).isEqualTo(defaults.getDeviceAuthorizationEndpoint());\n\t\tassertThat(properties.getDeviceVerificationUri()).isEqualTo(defaults.getDeviceVerificationEndpoint());\n\t\tassertThat(properties.getTokenUri()).isEqualTo(defaults.getTokenEndpoint());\n\t\tassertThat(properties.getJwkSetUri()).isEqualTo(defaults.getJwkSetEndpoint());\n\t\tassertThat(properties.getTokenRevocationUri()).isEqualTo(defaults.getTokenRevocationEndpoint());\n\t\tassertThat(properties.getTokenIntrospectionUri()).isEqualTo(defaults.getTokenIntrospectionEndpoint());\n\t\tassertThat(properties.getPushedAuthorizationRequestUri())\n\t\t\t.isEqualTo(defaults.getPushedAuthorizationRequestEndpoint());\n\t\tOAuth2AuthorizationServerProperties.OidcEndpoint oidc = properties.getOidc();\n\t\tassertThat(oidc.getLogoutUri()).isEqualTo(defaults.getOidcLogoutEndpoint());\n\t\tassertThat(oidc.getClientRegistrationUri()).isEqualTo(defaults.getOidcClientRegistrationEndpoint());\n\t\tassertThat(oidc.getUserInfoUri()).isEqualTo(defaults.getOidcUserInfoEndpoint());\n\t}\n\n\t@Test\n\tvoid defaultClientPropertiesMatchBuilderDefaults() {\n\t\tOAuth2AuthorizationServerProperties.Client properties = new OAuth2AuthorizationServerProperties.Client();\n\t\tClientSettings defaults = ClientSettings.builder().build();\n\t\tassertThat(properties.isRequireProofKey()).isEqualTo(defaults.isRequireProofKey());\n\t\tassertThat(properties.isRequireAuthorizationConsent()).isEqualTo(defaults.isRequireAuthorizationConsent());\n\t\tassertThat(properties.getJwkSetUri()).isEqualTo(defaults.getJwkSetUrl());\n\t\tassertThat(properties.getTokenEndpointAuthenticationSigningAlgorithm())\n\t\t\t.isEqualTo((defaults.getTokenEndpointAuthenticationSigningAlgorithm() != null)\n\t\t\t\t\t? defaults.getTokenEndpointAuthenticationSigningAlgorithm().getName() : null);\n\t}\n\n\t@Test\n\tvoid defaultTokenPropertiesMatchBuilderDefaults() {\n\t\tOAuth2AuthorizationServerProperties.Token properties = new OAuth2AuthorizationServerProperties.Token();\n\t\tTokenSettings defaults = TokenSettings.builder().build();\n\t\tassertThat(properties.getAuthorizationCodeTimeToLive()).isEqualTo(defaults.getAuthorizationCodeTimeToLive());\n\t\tassertThat(properties.getAccessTokenTimeToLive()).isEqualTo(defaults.getAccessTokenTimeToLive());\n\t\tassertThat(properties.getAccessTokenFormat()).isEqualTo(defaults.getAccessTokenFormat().getValue());\n\t\tassertThat(properties.getDeviceCodeTimeToLive()).isEqualTo(defaults.getDeviceCodeTimeToLive());\n\t\tassertThat(properties.isReuseRefreshTokens()).isEqualTo(defaults.isReuseRefreshTokens());\n\t\tassertThat(properties.getRefreshTokenTimeToLive()).isEqualTo(defaults.getRefreshTokenTimeToLive());\n\t\tassertThat(properties.getIdTokenSignatureAlgorithm())\n\t\t\t.isEqualTo(defaults.getIdTokenSignatureAlgorithm().getName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-authorization-server/src/test/java/org/springframework/boot/security/oauth2/server/authorization/autoconfigure/servlet/OAuth2AuthorizationServerWebSecurityConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.authorization.autoconfigure.servlet;\n\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClient;\nimport org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;\nimport org.springframework.security.oauth2.server.authorization.oidc.web.OidcClientRegistrationEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.oidc.web.OidcUserInfoEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;\nimport org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter;\nimport org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter;\nimport org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;\nimport org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for {@link OAuth2AuthorizationServerWebSecurityConfiguration}.\n *\n * @author Steve Riesenberg\n */\nclass OAuth2AuthorizationServerWebSecurityConfigurationTests {\n\n\tprivate static final String PROPERTIES_PREFIX = \"spring.security.oauth2.authorizationserver\";\n\n\tprivate static final String CLIENT_PREFIX = PROPERTIES_PREFIX + \".client\";\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner();\n\n\t@Test\n\tvoid webSecurityConfigurationConfiguresAuthorizationServerWithFormLogin() {\n\t\tthis.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)\n\t\t\t.withPropertyValues(CLIENT_PREFIX + \".foo.registration.client-id=abcd\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-secret=secret\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-authentication-methods=client_secret_basic\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.authorization-grant-types=client_credentials\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.scopes=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"authorizationServerSecurityFilterChain\");\n\t\t\t\tassertThat(context).hasBean(\"defaultSecurityFilterChain\");\n\t\t\t\tassertThat(context).hasBean(\"registeredClientRepository\");\n\t\t\t\tassertThat(context).hasBean(\"authorizationServerSettings\");\n\t\t\t\tassertThat(findFilter(context, OAuth2AuthorizationEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OAuth2TokenEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OAuth2TokenIntrospectionEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OAuth2TokenRevocationEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OAuth2AuthorizationServerMetadataEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OidcProviderConfigurationEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OidcUserInfoEndpointFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, BearerTokenAuthenticationFilter.class, 0)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, OidcClientRegistrationEndpointFilter.class, 0)).isNull();\n\t\t\t\tassertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 0)).isNull();\n\t\t\t\tassertThat(findFilter(context, DefaultLoginPageGeneratingFilter.class, 1)).isNotNull();\n\t\t\t\tassertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 1)).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid httpSecurityCustomizerCanRefineAuthorizationServerConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(TestOAuth2AuthorizationServerConfiguration.class)\n\t\t\t.withPropertyValues(CLIENT_PREFIX + \".foo.registration.client-id=abcd\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-secret=secret\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-authentication-methods=client_secret_basic\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.authorization-grant-types=client_credentials\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.scopes=test\")\n\t\t\t.withUserConfiguration(OAuth2AuthorizationServerCustomizationConfiguration.class)\n\t\t\t.run((context) -> assertThat(findFilter(context, OAuth2AuthorizationEndpointFilter.class, 0))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"consentPage\", \"https://example.com/custom-consent-page\"));\n\t}\n\n\t@Test\n\tvoid securityFilterChainsBackOffWhenSecurityFilterChainBeanPresent() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(TestSecurityFilterChainConfiguration.class,\n\t\t\t\t\tTestOAuth2AuthorizationServerConfiguration.class)\n\t\t\t.withPropertyValues(CLIENT_PREFIX + \".foo.registration.client-id=abcd\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-secret=secret\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.client-authentication-methods=client_secret_basic\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.authorization-grant-types=client_credentials\",\n\t\t\t\t\tCLIENT_PREFIX + \".foo.registration.scopes=test\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"authServerSecurityFilterChain\");\n\t\t\t\tassertThat(context).doesNotHaveBean(\"authorizationServerSecurityFilterChain\");\n\t\t\t\tassertThat(context).hasBean(\"securityFilterChain\");\n\t\t\t\tassertThat(context).doesNotHaveBean(\"defaultSecurityFilterChain\");\n\t\t\t\tassertThat(context).hasBean(\"registeredClientRepository\");\n\t\t\t\tassertThat(context).hasBean(\"authorizationServerSettings\");\n\t\t\t\tassertThat(findFilter(context, BearerTokenAuthenticationFilter.class, 0)).isNull();\n\t\t\t\tassertThat(findFilter(context, UsernamePasswordAuthenticationFilter.class, 1)).isNull();\n\t\t\t});\n\t}\n\n\tprivate @Nullable Filter findFilter(AssertableWebApplicationContext context, Class<? extends Filter> filter,\n\t\t\tint filterChainIndex) {\n\t\tFilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);\n\t\tList<SecurityFilterChain> filterChains = filterChain.getFilterChains();\n\t\tList<Filter> filters = filterChains.get(filterChainIndex).getFilters();\n\t\treturn filters.stream().filter(filter::isInstance).findFirst().orElse(null);\n\t}\n\n\t@Configuration\n\t@EnableWebSecurity\n\t@Import({ TestRegisteredClientRepositoryConfiguration.class,\n\t\t\tOAuth2AuthorizationServerWebSecurityConfiguration.class,\n\t\t\tOAuth2AuthorizationServerJwtAutoConfiguration.class })\n\tstatic class TestOAuth2AuthorizationServerConfiguration {\n\n\t}\n\n\t@Configuration\n\tstatic class TestRegisteredClientRepositoryConfiguration {\n\n\t\t@Bean\n\t\tRegisteredClientRepository registeredClientRepository() {\n\t\t\tRegisteredClient registeredClient = RegisteredClient.withId(\"test\")\n\t\t\t\t.clientId(\"abcd\")\n\t\t\t\t.clientSecret(\"secret\")\n\t\t\t\t.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n\t\t\t\t.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)\n\t\t\t\t.scope(\"test\")\n\t\t\t\t.build();\n\t\t\treturn new InMemoryRegisteredClientRepository(registeredClient);\n\t\t}\n\n\t\t@Bean\n\t\tAuthorizationServerSettings authorizationServerSettings() {\n\t\t\treturn AuthorizationServerSettings.builder().issuer(\"https://example.com\").build();\n\t\t}\n\n\t}\n\n\t@Configuration\n\t@EnableWebSecurity\n\tstatic class TestSecurityFilterChainConfiguration {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.oauth2AuthorizationServer(\n\t\t\t\t\t(authorizationServer) -> http.securityMatcher(authorizationServer.getEndpointsMatcher()));\n\t\t\thttp.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated());\n\t\t\treturn http.build();\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tSecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\t\treturn http.httpBasic(withDefaults()).build();\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OAuth2AuthorizationServerCustomizationConfiguration {\n\n\t\t@Bean\n\t\tCustomizer<HttpSecurity> oauth2AuthorizationServiceCustomizer() {\n\t\t\treturn (http) -> http.oauth2AuthorizationServer((authorizationServer) -> authorizationServer\n\t\t\t\t.authorizationEndpoint((endpoint) -> endpoint.consentPage(\"https://example.com/custom-consent-page\")));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Security OAuth2 Client\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.security:spring-security-oauth2-client\")\n\n\timplementation(project(\":module:spring-boot-security\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(project(\":module:spring-boot-webflux-test\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.springframework:spring-webflux\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/ClientsConfiguredCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * Condition that matches if any {@code spring.security.oauth2.client.registration}\n * properties are defined.\n *\n * @author Madhura Bhave\n */\nclass ClientsConfiguredCondition extends SpringBootCondition {\n\n\tprivate static final Bindable<Map<String, OAuth2ClientProperties.Registration>> STRING_REGISTRATION_MAP = Bindable\n\t\t.mapOf(String.class, OAuth2ClientProperties.Registration.class);\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"OAuth2 Clients Configured Condition\");\n\t\tMap<String, OAuth2ClientProperties.Registration> registrations = getRegistrations(context.getEnvironment());\n\t\tif (!registrations.isEmpty()) {\n\t\t\treturn ConditionOutcome.match(message.foundExactly(\"registered clients \" + registrations.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(OAuth2ClientProperties.Registration::getClientId)\n\t\t\t\t.collect(Collectors.joining(\", \"))));\n\t\t}\n\t\treturn ConditionOutcome.noMatch(message.notAvailable(\"registered clients\"));\n\t}\n\n\tprivate Map<String, OAuth2ClientProperties.Registration> getRegistrations(Environment environment) {\n\t\treturn Binder.get(environment)\n\t\t\t.bind(\"spring.security.oauth2.client.registration\", STRING_REGISTRATION_MAP)\n\t\t\t.orElse(Collections.emptyMap());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/ConditionalOnOAuth2ClientRegistrationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * Condition that matches if any {@code spring.security.oauth2.client.registration}\n * properties are defined.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@SuppressWarnings(\"removal\")\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(ClientsConfiguredCondition.class)\npublic @interface ConditionalOnOAuth2ClientRegistrationProperties {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientAutoConfiguration.NonReactiveWebApplicationCondition;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OAuth client support.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\n@Conditional(NonReactiveWebApplicationCondition.class)\n@ConditionalOnClass(ClientRegistration.class)\n@Import({ OAuth2ClientConfigurations.ClientRegistrationRepositoryConfiguration.class,\n\t\tOAuth2ClientConfigurations.OAuth2AuthorizedClientServiceConfiguration.class })\npublic final class OAuth2ClientAutoConfiguration {\n\n\tstatic class NonReactiveWebApplicationCondition extends NoneNestedConditions {\n\n\t\tNonReactiveWebApplicationCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t\tstatic class ReactiveWebApplicationCondition {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;\n\n/**\n * Configurations related to auto-configuration of OAuth2 client support.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass OAuth2ClientConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnOAuth2ClientRegistrationProperties\n\t@EnableConfigurationProperties(OAuth2ClientProperties.class)\n\t@ConditionalOnMissingBean(ClientRegistrationRepository.class)\n\tstatic class ClientRegistrationRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {\n\t\t\tList<ClientRegistration> registrations = new ArrayList<>(\n\t\t\t\t\tnew OAuth2ClientPropertiesMapper(properties).asClientRegistrations().values());\n\t\t\treturn new InMemoryClientRegistrationRepository(registrations);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ClientRegistrationRepository.class)\n\tstatic class OAuth2AuthorizedClientServiceConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tOAuth2AuthorizedClientService authorizedClientService(\n\t\t\t\tClientRegistrationRepository clientRegistrationRepository) {\n\t\t\treturn new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.StringUtils;\n\n/**\n * OAuth 2.0 client properties.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author MyeongHyeon Lee\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.security.oauth2.client\")\npublic class OAuth2ClientProperties implements InitializingBean {\n\n\t/**\n\t * OAuth provider details.\n\t */\n\tprivate final Map<String, Provider> provider = new HashMap<>();\n\n\t/**\n\t * OAuth client registrations.\n\t */\n\tprivate final Map<String, Registration> registration = new HashMap<>();\n\n\tpublic Map<String, Provider> getProvider() {\n\t\treturn this.provider;\n\t}\n\n\tpublic Map<String, Registration> getRegistration() {\n\t\treturn this.registration;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tvalidate();\n\t}\n\n\tpublic void validate() {\n\t\tgetRegistration().forEach(this::validateRegistration);\n\t}\n\n\tprivate void validateRegistration(String id, Registration registration) {\n\t\tif (!StringUtils.hasText(registration.getClientId())) {\n\t\t\tthrow new IllegalStateException(\"Client id of registration '%s' must not be empty.\".formatted(id));\n\t\t}\n\t}\n\n\t/**\n\t * A single client registration.\n\t */\n\tpublic static class Registration {\n\n\t\t/**\n\t\t * Reference to the OAuth 2.0 provider to use. May reference one of the common\n\t\t * providers (google, github, facebook, okta) or the ID of a custom provider\n\t\t * configured using 'spring.security.oauth2.client.provider.&lt;id&gt;.*'\n\t\t * properties. When not set, the ID of this registration is used to identify the\n\t\t * provider.\n\t\t */\n\t\tprivate @Nullable String provider;\n\n\t\t/**\n\t\t * Client ID for the registration.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Client secret of the registration.\n\t\t */\n\t\tprivate @Nullable String clientSecret;\n\n\t\t/**\n\t\t * Client authentication method. May be left blank when using a pre-defined\n\t\t * provider.\n\t\t */\n\t\tprivate @Nullable String clientAuthenticationMethod;\n\n\t\t/**\n\t\t * Authorization grant type. May be left blank when using a pre-defined provider.\n\t\t */\n\t\tprivate @Nullable String authorizationGrantType;\n\n\t\t/**\n\t\t * Redirect URI. May be left blank when using a pre-defined provider.\n\t\t */\n\t\tprivate @Nullable String redirectUri;\n\n\t\t/**\n\t\t * Authorization scopes. When left blank the provider's default scopes, if any,\n\t\t * will be used.\n\t\t */\n\t\tprivate @Nullable Set<String> scope;\n\n\t\t/**\n\t\t * Client name. May be left blank when using a pre-defined provider.\n\t\t */\n\t\tprivate @Nullable String clientName;\n\n\t\tpublic @Nullable String getProvider() {\n\t\t\treturn this.provider;\n\t\t}\n\n\t\tpublic void setProvider(@Nullable String provider) {\n\t\t\tthis.provider = provider;\n\t\t}\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable String getClientSecret() {\n\t\t\treturn this.clientSecret;\n\t\t}\n\n\t\tpublic void setClientSecret(@Nullable String clientSecret) {\n\t\t\tthis.clientSecret = clientSecret;\n\t\t}\n\n\t\tpublic @Nullable String getClientAuthenticationMethod() {\n\t\t\treturn this.clientAuthenticationMethod;\n\t\t}\n\n\t\tpublic void setClientAuthenticationMethod(@Nullable String clientAuthenticationMethod) {\n\t\t\tthis.clientAuthenticationMethod = clientAuthenticationMethod;\n\t\t}\n\n\t\tpublic @Nullable String getAuthorizationGrantType() {\n\t\t\treturn this.authorizationGrantType;\n\t\t}\n\n\t\tpublic void setAuthorizationGrantType(@Nullable String authorizationGrantType) {\n\t\t\tthis.authorizationGrantType = authorizationGrantType;\n\t\t}\n\n\t\tpublic @Nullable String getRedirectUri() {\n\t\t\treturn this.redirectUri;\n\t\t}\n\n\t\tpublic void setRedirectUri(@Nullable String redirectUri) {\n\t\t\tthis.redirectUri = redirectUri;\n\t\t}\n\n\t\tpublic @Nullable Set<String> getScope() {\n\t\t\treturn this.scope;\n\t\t}\n\n\t\tpublic void setScope(@Nullable Set<String> scope) {\n\t\t\tthis.scope = scope;\n\t\t}\n\n\t\tpublic @Nullable String getClientName() {\n\t\t\treturn this.clientName;\n\t\t}\n\n\t\tpublic void setClientName(@Nullable String clientName) {\n\t\t\tthis.clientName = clientName;\n\t\t}\n\n\t}\n\n\tpublic static class Provider {\n\n\t\t/**\n\t\t * Authorization URI for the provider.\n\t\t */\n\t\tprivate @Nullable String authorizationUri;\n\n\t\t/**\n\t\t * Token URI for the provider.\n\t\t */\n\t\tprivate @Nullable String tokenUri;\n\n\t\t/**\n\t\t * User info URI for the provider.\n\t\t */\n\t\tprivate @Nullable String userInfoUri;\n\n\t\t/**\n\t\t * User info authentication method for the provider.\n\t\t */\n\t\tprivate @Nullable String userInfoAuthenticationMethod;\n\n\t\t/**\n\t\t * Name of the attribute that will be used to extract the username from the call\n\t\t * to 'userInfoUri'.\n\t\t */\n\t\tprivate @Nullable String userNameAttribute;\n\n\t\t/**\n\t\t * JWK set URI for the provider.\n\t\t */\n\t\tprivate @Nullable String jwkSetUri;\n\n\t\t/**\n\t\t * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0\n\t\t * Authorization Server Metadata endpoint defined by RFC 8414.\n\t\t */\n\t\tprivate @Nullable String issuerUri;\n\n\t\tpublic @Nullable String getAuthorizationUri() {\n\t\t\treturn this.authorizationUri;\n\t\t}\n\n\t\tpublic void setAuthorizationUri(@Nullable String authorizationUri) {\n\t\t\tthis.authorizationUri = authorizationUri;\n\t\t}\n\n\t\tpublic @Nullable String getTokenUri() {\n\t\t\treturn this.tokenUri;\n\t\t}\n\n\t\tpublic void setTokenUri(@Nullable String tokenUri) {\n\t\t\tthis.tokenUri = tokenUri;\n\t\t}\n\n\t\tpublic @Nullable String getUserInfoUri() {\n\t\t\treturn this.userInfoUri;\n\t\t}\n\n\t\tpublic void setUserInfoUri(@Nullable String userInfoUri) {\n\t\t\tthis.userInfoUri = userInfoUri;\n\t\t}\n\n\t\tpublic @Nullable String getUserInfoAuthenticationMethod() {\n\t\t\treturn this.userInfoAuthenticationMethod;\n\t\t}\n\n\t\tpublic void setUserInfoAuthenticationMethod(@Nullable String userInfoAuthenticationMethod) {\n\t\t\tthis.userInfoAuthenticationMethod = userInfoAuthenticationMethod;\n\t\t}\n\n\t\tpublic @Nullable String getUserNameAttribute() {\n\t\t\treturn this.userNameAttribute;\n\t\t}\n\n\t\tpublic void setUserNameAttribute(@Nullable String userNameAttribute) {\n\t\t\tthis.userNameAttribute = userNameAttribute;\n\t\t}\n\n\t\tpublic @Nullable String getJwkSetUri() {\n\t\t\treturn this.jwkSetUri;\n\t\t}\n\n\t\tpublic void setJwkSetUri(@Nullable String jwkSetUri) {\n\t\t\tthis.jwkSetUri = jwkSetUri;\n\t\t}\n\n\t\tpublic @Nullable String getIssuerUri() {\n\t\t\treturn this.issuerUri;\n\t\t}\n\n\t\tpublic void setIssuerUri(@Nullable String issuerUri) {\n\t\t\tthis.issuerUri = issuerUri;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientPropertiesMapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientProperties.Provider;\nimport org.springframework.core.convert.ConversionException;\nimport org.springframework.security.config.oauth2.client.CommonOAuth2Provider;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrations;\nimport org.springframework.security.oauth2.core.AuthenticationMethod;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.util.StringUtils;\n\n/**\n * Maps {@link OAuth2ClientProperties} to {@link ClientRegistration ClientRegistrations}.\n *\n * @author Phillip Webb\n * @author Thiago Hirata\n * @author Madhura Bhave\n * @author MyeongHyeon Lee\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic final class OAuth2ClientPropertiesMapper {\n\n\tprivate final OAuth2ClientProperties properties;\n\n\t/**\n\t * Creates a new mapper for the given {@code properties}.\n\t * @param properties the properties to map\n\t */\n\tpublic OAuth2ClientPropertiesMapper(OAuth2ClientProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t/**\n\t * Maps the properties to {@link ClientRegistration ClientRegistrations}.\n\t * @return the mapped {@code ClientRegistrations}\n\t */\n\tpublic Map<String, ClientRegistration> asClientRegistrations() {\n\t\tMap<String, ClientRegistration> clientRegistrations = new HashMap<>();\n\t\tthis.properties.getRegistration()\n\t\t\t.forEach((key, value) -> clientRegistrations.put(key,\n\t\t\t\t\tgetClientRegistration(key, value, this.properties.getProvider())));\n\t\treturn clientRegistrations;\n\t}\n\n\tprivate static ClientRegistration getClientRegistration(String registrationId,\n\t\t\tOAuth2ClientProperties.Registration properties, Map<String, Provider> providers) {\n\t\tBuilder builder = getBuilderFromIssuerIfPossible(registrationId, properties.getProvider(), providers);\n\t\tif (builder == null) {\n\t\t\tbuilder = getBuilder(registrationId, properties.getProvider(), providers);\n\t\t}\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(properties::getClientId).to(builder::clientId);\n\t\tmap.from(properties::getClientSecret).to(builder::clientSecret);\n\t\tmap.from(properties::getClientAuthenticationMethod)\n\t\t\t.as(ClientAuthenticationMethod::new)\n\t\t\t.to(builder::clientAuthenticationMethod);\n\t\tmap.from(properties::getAuthorizationGrantType)\n\t\t\t.as(AuthorizationGrantType::new)\n\t\t\t.to(builder::authorizationGrantType);\n\t\tmap.from(properties::getRedirectUri).to(builder::redirectUri);\n\t\tmap.from(properties::getScope).as(StringUtils::toStringArray).to(builder::scope);\n\t\tmap.from(properties::getClientName).to(builder::clientName);\n\t\treturn builder.build();\n\t}\n\n\tprivate static @Nullable Builder getBuilderFromIssuerIfPossible(String registrationId,\n\t\t\t@Nullable String configuredProviderId, Map<String, Provider> providers) {\n\t\tString providerId = (configuredProviderId != null) ? configuredProviderId : registrationId;\n\t\tif (providers.containsKey(providerId)) {\n\t\t\tProvider provider = providers.get(providerId);\n\t\t\tString issuer = provider.getIssuerUri();\n\t\t\tif (issuer != null) {\n\t\t\t\tBuilder builder = ClientRegistrations.fromIssuerLocation(issuer).registrationId(registrationId);\n\t\t\t\treturn getBuilder(builder, provider);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static Builder getBuilder(String registrationId, @Nullable String configuredProviderId,\n\t\t\tMap<String, Provider> providers) {\n\t\tString providerId = (configuredProviderId != null) ? configuredProviderId : registrationId;\n\t\tCommonOAuth2Provider provider = getCommonProvider(providerId);\n\t\tif (provider == null && !providers.containsKey(providerId)) {\n\t\t\tthrow new IllegalStateException(getErrorMessage(configuredProviderId, registrationId));\n\t\t}\n\t\tBuilder builder = (provider != null) ? provider.getBuilder(registrationId)\n\t\t\t\t: ClientRegistration.withRegistrationId(registrationId);\n\t\tif (providers.containsKey(providerId)) {\n\t\t\treturn getBuilder(builder, providers.get(providerId));\n\t\t}\n\t\treturn builder;\n\t}\n\n\tprivate static String getErrorMessage(@Nullable String configuredProviderId, String registrationId) {\n\t\treturn ((configuredProviderId != null) ? \"Unknown provider ID '\" + configuredProviderId + \"'\"\n\t\t\t\t: \"Provider ID must be specified for client registration '\" + registrationId + \"'\");\n\t}\n\n\tprivate static Builder getBuilder(Builder builder, Provider provider) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(provider::getAuthorizationUri).to(builder::authorizationUri);\n\t\tmap.from(provider::getTokenUri).to(builder::tokenUri);\n\t\tmap.from(provider::getUserInfoUri).to(builder::userInfoUri);\n\t\tmap.from(provider::getUserInfoAuthenticationMethod)\n\t\t\t.as(AuthenticationMethod::new)\n\t\t\t.to(builder::userInfoAuthenticationMethod);\n\t\tmap.from(provider::getJwkSetUri).to(builder::jwkSetUri);\n\t\tmap.from(provider::getUserNameAttribute).to(builder::userNameAttributeName);\n\t\treturn builder;\n\t}\n\n\tprivate static @Nullable CommonOAuth2Provider getCommonProvider(String providerId) {\n\t\ttry {\n\t\t\treturn ApplicationConversionService.getSharedInstance().convert(providerId, CommonOAuth2Provider.class);\n\t\t}\n\t\tcatch (ConversionException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Spring Security's OAuth 2 client.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/ReactiveOAuth2ClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security's Reactive\n * OAuth2 client.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration\n@Conditional(ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.class)\n@ConditionalOnClass({ Flux.class, ClientRegistration.class })\n@Import({ ReactiveOAuth2ClientConfigurations.ReactiveClientRegistrationRepositoryConfiguration.class,\n\t\tReactiveOAuth2ClientConfigurations.ReactiveOAuth2AuthorizedClientServiceConfiguration.class })\npublic final class ReactiveOAuth2ClientAutoConfiguration {\n\n\tstatic class NonServletApplicationCondition extends NoneNestedConditions {\n\n\t\tNonServletApplicationCondition() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\t\tstatic class ServletApplicationCondition {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/ReactiveOAuth2ClientConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.ConditionalOnOAuth2ClientRegistrationProperties;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientProperties;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientPropertiesMapper;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;\n\n/**\n * Reactive OAuth2 Client configurations.\n *\n * @author Madhura Bhave\n */\nclass ReactiveOAuth2ClientConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(OAuth2ClientProperties.class)\n\t@ConditionalOnOAuth2ClientRegistrationProperties\n\t@ConditionalOnMissingBean(ReactiveClientRegistrationRepository.class)\n\tstatic class ReactiveClientRegistrationRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryReactiveClientRegistrationRepository reactiveClientRegistrationRepository(\n\t\t\t\tOAuth2ClientProperties properties) {\n\t\t\tList<ClientRegistration> registrations = new ArrayList<>(\n\t\t\t\t\tnew OAuth2ClientPropertiesMapper(properties).asClientRegistrations().values());\n\t\t\treturn new InMemoryReactiveClientRegistrationRepository(registrations);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(ReactiveClientRegistrationRepository.class)\n\tstatic class ReactiveOAuth2AuthorizedClientServiceConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tReactiveOAuth2AuthorizedClientService reactiveAuthorizedClientService(\n\t\t\t\tReactiveClientRegistrationRepository clientRegistrationRepository) {\n\t\t\treturn new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/ReactiveOAuth2ClientWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.actuate.web.reactive.ReactiveManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;\nimport org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Auto-configuration for reactive web security that uses an OAuth 2 client.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { ReactiveManagementWebSecurityAutoConfiguration.class, ReactiveWebSecurityAutoConfiguration.class },\n\t\tafter = ReactiveOAuth2ClientAutoConfiguration.class)\n@ConditionalOnClass({ Flux.class, EnableWebFluxSecurity.class, ServerOAuth2AuthorizedClientRepository.class })\n@ConditionalOnBean(ReactiveOAuth2AuthorizedClientService.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\npublic final class ReactiveOAuth2ClientWebSecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tServerOAuth2AuthorizedClientRepository authorizedClientRepository(\n\t\t\tReactiveOAuth2AuthorizedClientService authorizedClientService) {\n\t\treturn new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tSecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\thttp.authorizeExchange((exchange) -> exchange.anyExchange().authenticated());\n\t\thttp.oauth2Login(withDefaults());\n\t\thttp.oauth2Client(withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Security's Reactive OAuth 2 client.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/OAuth2ClientWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;\nimport org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Auto-configuration for web security that uses an OAuth 2 client.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(before = { ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class },\n\t\tafter = OAuth2ClientAutoConfiguration.class)\n@ConditionalOnClass({ EnableWebSecurity.class, OAuth2AuthorizedClientRepository.class })\n@ConditionalOnBean(OAuth2AuthorizedClientService.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic final class OAuth2ClientWebSecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tOAuth2AuthorizedClientRepository authorizedClientRepository(OAuth2AuthorizedClientService authorizedClientService) {\n\t\treturn new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnDefaultWebSecurity\n\tstatic class OAuth2SecurityFilterChainConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\t\thttp.oauth2Login(withDefaults());\n\t\t\thttp.oauth2Client(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Security's OAuth 2 client.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientAutoConfiguration\norg.springframework.boot.security.oauth2.client.autoconfigure.reactive.ReactiveOAuth2ClientAutoConfiguration\norg.springframework.boot.security.oauth2.client.autoconfigure.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration\norg.springframework.boot.security.oauth2.client.autoconfigure.servlet.OAuth2ClientWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.WebFluxTest.imports",
    "content": "org.springframework.boot.security.oauth2.client.autoconfigure.reactive.ReactiveOAuth2ClientAutoConfiguration"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest.imports",
    "content": "org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientAutoConfiguration\norg.springframework.boot.security.oauth2.client.autoconfigure.servlet.OAuth2ClientWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/main/resources/META-INF/spring/org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient.imports",
    "content": "org.springframework.boot.security.oauth2.client.autoconfigure.reactive.ReactiveOAuth2ClientAutoConfiguration\norg.springframework.boot.security.oauth2.client.autoconfigure.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OAuth2ClientAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass OAuth2ClientAutoConfigurationTests {\n\n\tprivate static final String REGISTRATION_PREFIX = \"spring.security.oauth2.client.registration\";\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OAuth2ClientAutoConfiguration.class));\n\n\t@Test\n\tvoid beansShouldNotBeCreatedWhenPropertiesAbsent() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ClientRegistrationRepository.class)\n\t\t\t.doesNotHaveBean(OAuth2AuthorizedClientService.class));\n\t}\n\n\t@Test\n\tvoid beansAreCreatedWhenPropertiesPresent() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(REGISTRATION_PREFIX + \".foo.client-id=abcd\",\n\t\t\t\t\tREGISTRATION_PREFIX + \".foo.client-secret=secret\", REGISTRATION_PREFIX + \".foo.provider=github\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ClientRegistrationRepository.class);\n\t\t\t\tassertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class);\n\t\t\t\tClientRegistrationRepository repository = context.getBean(ClientRegistrationRepository.class);\n\t\t\t\tClientRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\t\tassertThat(registration).isNotNull();\n\t\t\t\tassertThat(registration.getClientSecret()).isEqualTo(\"secret\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientServiceBeanIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"testAuthorizedClientService\", OAuth2AuthorizedClientService.class,\n\t\t\t\t\t() -> mock(OAuth2AuthorizedClientService.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class);\n\t\t\t\tassertThat(context).hasBean(\"testAuthorizedClientService\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientServiceBeanIsCreatedWithUserDefinedClientRegistrationRepository() {\n\t\tthis.contextRunner\n\t\t\t.withBean(ClientRegistrationRepository.class,\n\t\t\t\t\t() -> new InMemoryClientRegistrationRepository(getClientRegistration(\"test\", \"test\")))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class));\n\t}\n\n\tprivate ClientRegistration getClientRegistration(String id, String userInfoUri) {\n\t\tClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);\n\t\tbuilder.clientName(\"foo\")\n\t\t\t.clientId(\"foo\")\n\t\t\t.clientAuthenticationMethod(\n\t\t\t\t\torg.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n\t\t\t.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n\t\t\t.scope(\"read\")\n\t\t\t.clientSecret(\"secret\")\n\t\t\t.redirectUri(\"https://redirect-uri.com\")\n\t\t\t.authorizationUri(\"https://authorization-uri.com\")\n\t\t\t.tokenUri(\"https://token-uri.com\")\n\t\t\t.userInfoUri(userInfoUri)\n\t\t\t.userNameAttributeName(\"login\");\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientPropertiesMapperTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientProperties.Provider;\nimport org.springframework.boot.security.oauth2.client.autoconfigure.OAuth2ClientProperties.Registration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails.UserInfoEndpoint;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.ClientAuthenticationMethod;\nimport org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link OAuth2ClientPropertiesMapper}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Thiago Hirata\n * @author HaiTao Zhang\n */\nclass OAuth2ClientPropertiesMapperTests {\n\n\tprivate @Nullable MockWebServer server;\n\n\t@AfterEach\n\tvoid cleanup() throws Exception {\n\t\tif (this.server != null) {\n\t\t\tthis.server.shutdown();\n\t\t}\n\t}\n\n\t@Test\n\tvoid getClientRegistrationsWhenUsingDefinedProviderShouldAdapt() {\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tProvider provider = createProvider();\n\t\tprovider.setUserInfoAuthenticationMethod(\"form\");\n\t\tOAuth2ClientProperties.Registration registration = createRegistration(\"provider\");\n\t\tregistration.setClientName(\"clientName\");\n\t\tproperties.getRegistration().put(\"registration\", registration);\n\t\tproperties.getProvider().put(\"provider\", provider);\n\t\tMap<String, ClientRegistration> registrations = new OAuth2ClientPropertiesMapper(properties)\n\t\t\t.asClientRegistrations();\n\t\tClientRegistration adapted = registrations.get(\"registration\");\n\t\tassertThat(adapted).isNotNull();\n\t\tProviderDetails adaptedProvider = adapted.getProviderDetails();\n\t\tassertThat(adaptedProvider.getAuthorizationUri()).isEqualTo(\"https://example.com/auth\");\n\t\tassertThat(adaptedProvider.getTokenUri()).isEqualTo(\"https://example.com/token\");\n\t\tUserInfoEndpoint userInfoEndpoint = adaptedProvider.getUserInfoEndpoint();\n\t\tassertThat(userInfoEndpoint.getUri()).isEqualTo(\"https://example.com/info\");\n\t\tassertThat(userInfoEndpoint.getAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.FORM);\n\t\tassertThat(userInfoEndpoint.getUserNameAttributeName()).isEqualTo(\"sub\");\n\t\tassertThat(adaptedProvider.getJwkSetUri()).isEqualTo(\"https://example.com/jwk\");\n\t\tassertThat(adapted.getRegistrationId()).isEqualTo(\"registration\");\n\t\tassertThat(adapted.getClientId()).isEqualTo(\"clientId\");\n\t\tassertThat(adapted.getClientSecret()).isEqualTo(\"clientSecret\");\n\t\tassertThat(adapted.getClientAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_POST);\n\t\tassertThat(adapted.getAuthorizationGrantType())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(adapted.getRedirectUri()).isEqualTo(\"https://example.com/redirect\");\n\t\tassertThat(adapted.getScopes()).containsExactly(\"user\");\n\t\tassertThat(adapted.getClientName()).isEqualTo(\"clientName\");\n\t}\n\n\t@Test\n\tvoid getClientRegistrationsWhenUsingCommonProviderShouldAdapt() {\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tregistration.setProvider(\"google\");\n\t\tregistration.setClientId(\"clientId\");\n\t\tregistration.setClientSecret(\"clientSecret\");\n\t\tproperties.getRegistration().put(\"registration\", registration);\n\t\tMap<String, ClientRegistration> registrations = new OAuth2ClientPropertiesMapper(properties)\n\t\t\t.asClientRegistrations();\n\t\tClientRegistration adapted = registrations.get(\"registration\");\n\t\tassertThat(adapted).isNotNull();\n\t\tProviderDetails adaptedProvider = adapted.getProviderDetails();\n\t\tassertThat(adaptedProvider.getAuthorizationUri()).isEqualTo(\"https://accounts.google.com/o/oauth2/v2/auth\");\n\t\tassertThat(adaptedProvider.getTokenUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v4/token\");\n\t\tUserInfoEndpoint userInfoEndpoint = adaptedProvider.getUserInfoEndpoint();\n\t\tassertThat(userInfoEndpoint.getUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v3/userinfo\");\n\t\tassertThat(userInfoEndpoint.getUserNameAttributeName()).isEqualTo(IdTokenClaimNames.SUB);\n\t\tassertThat(adaptedProvider.getJwkSetUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v3/certs\");\n\t\tassertThat(adapted.getRegistrationId()).isEqualTo(\"registration\");\n\t\tassertThat(adapted.getClientId()).isEqualTo(\"clientId\");\n\t\tassertThat(adapted.getClientSecret()).isEqualTo(\"clientSecret\");\n\t\tassertThat(adapted.getClientAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC);\n\t\tassertThat(adapted.getAuthorizationGrantType())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(adapted.getRedirectUri()).isEqualTo(\"{baseUrl}/{action}/oauth2/code/{registrationId}\");\n\t\tassertThat(adapted.getScopes()).containsExactly(\"openid\", \"profile\", \"email\");\n\t\tassertThat(adapted.getClientName()).isEqualTo(\"Google\");\n\t}\n\n\t@Test\n\tvoid getClientRegistrationsWhenUsingCommonProviderWithOverrideShouldAdapt() {\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tOAuth2ClientProperties.Registration registration = createRegistration(\"google\");\n\t\tregistration.setClientName(\"clientName\");\n\t\tproperties.getRegistration().put(\"registration\", registration);\n\t\tMap<String, ClientRegistration> registrations = new OAuth2ClientPropertiesMapper(properties)\n\t\t\t.asClientRegistrations();\n\t\tClientRegistration adapted = registrations.get(\"registration\");\n\t\tassertThat(adapted).isNotNull();\n\t\tProviderDetails adaptedProvider = adapted.getProviderDetails();\n\t\tassertThat(adaptedProvider.getAuthorizationUri()).isEqualTo(\"https://accounts.google.com/o/oauth2/v2/auth\");\n\t\tassertThat(adaptedProvider.getTokenUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v4/token\");\n\t\tUserInfoEndpoint userInfoEndpoint = adaptedProvider.getUserInfoEndpoint();\n\t\tassertThat(userInfoEndpoint.getUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v3/userinfo\");\n\t\tassertThat(userInfoEndpoint.getUserNameAttributeName()).isEqualTo(IdTokenClaimNames.SUB);\n\t\tassertThat(userInfoEndpoint.getAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER);\n\t\tassertThat(adaptedProvider.getJwkSetUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v3/certs\");\n\t\tassertThat(adapted.getRegistrationId()).isEqualTo(\"registration\");\n\t\tassertThat(adapted.getClientId()).isEqualTo(\"clientId\");\n\t\tassertThat(adapted.getClientSecret()).isEqualTo(\"clientSecret\");\n\t\tassertThat(adapted.getClientAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_POST);\n\t\tassertThat(adapted.getAuthorizationGrantType())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(adapted.getRedirectUri()).isEqualTo(\"https://example.com/redirect\");\n\t\tassertThat(adapted.getScopes()).containsExactly(\"user\");\n\t\tassertThat(adapted.getClientName()).isEqualTo(\"clientName\");\n\t}\n\n\t@Test\n\tvoid getClientRegistrationsWhenUnknownProviderShouldThrowException() {\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tregistration.setProvider(\"missing\");\n\t\tproperties.getRegistration().put(\"registration\", registration);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OAuth2ClientPropertiesMapper(properties).asClientRegistrations())\n\t\t\t.withMessageContaining(\"Unknown provider ID 'missing'\");\n\t}\n\n\t@Test\n\tvoid getClientRegistrationsWhenProviderNotSpecifiedShouldUseRegistrationId() {\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tregistration.setClientId(\"clientId\");\n\t\tregistration.setClientSecret(\"clientSecret\");\n\t\tproperties.getRegistration().put(\"google\", registration);\n\t\tMap<String, ClientRegistration> registrations = new OAuth2ClientPropertiesMapper(properties)\n\t\t\t.asClientRegistrations();\n\t\tClientRegistration adapted = registrations.get(\"google\");\n\t\tassertThat(adapted).isNotNull();\n\t\tProviderDetails adaptedProvider = adapted.getProviderDetails();\n\t\tassertThat(adaptedProvider.getAuthorizationUri()).isEqualTo(\"https://accounts.google.com/o/oauth2/v2/auth\");\n\t\tassertThat(adaptedProvider.getTokenUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v4/token\");\n\t\tUserInfoEndpoint userInfoEndpoint = adaptedProvider.getUserInfoEndpoint();\n\t\tassertThat(userInfoEndpoint.getUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v3/userinfo\");\n\t\tassertThat(userInfoEndpoint.getAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER);\n\t\tassertThat(adaptedProvider.getJwkSetUri()).isEqualTo(\"https://www.googleapis.com/oauth2/v3/certs\");\n\t\tassertThat(adapted.getRegistrationId()).isEqualTo(\"google\");\n\t\tassertThat(adapted.getClientId()).isEqualTo(\"clientId\");\n\t\tassertThat(adapted.getClientSecret()).isEqualTo(\"clientSecret\");\n\t\tassertThat(adapted.getClientAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC);\n\t\tassertThat(adapted.getAuthorizationGrantType())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(adapted.getRedirectUri()).isEqualTo(\"{baseUrl}/{action}/oauth2/code/{registrationId}\");\n\t\tassertThat(adapted.getScopes()).containsExactly(\"openid\", \"profile\", \"email\");\n\t\tassertThat(adapted.getClientName()).isEqualTo(\"Google\");\n\t}\n\n\t@Test\n\tvoid getClientRegistrationsWhenProviderNotSpecifiedAndUnknownProviderShouldThrowException() {\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tproperties.getRegistration().put(\"missing\", registration);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> new OAuth2ClientPropertiesMapper(properties).asClientRegistrations())\n\t\t\t.withMessageContaining(\"Provider ID must be specified for client registration 'missing'\");\n\t}\n\n\t@Test\n\tvoid oidcProviderConfigurationWhenProviderNotSpecifiedOnRegistration() throws Exception {\n\t\tRegistration login = new OAuth2ClientProperties.Registration();\n\t\tlogin.setClientId(\"clientId\");\n\t\tlogin.setClientSecret(\"clientSecret\");\n\t\ttestIssuerConfiguration(login, \"okta\", 0, 1);\n\t}\n\n\t@Test\n\tvoid oidcProviderConfigurationWhenProviderSpecifiedOnRegistration() throws Exception {\n\t\tOAuth2ClientProperties.Registration login = new Registration();\n\t\tlogin.setProvider(\"okta-oidc\");\n\t\tlogin.setClientId(\"clientId\");\n\t\tlogin.setClientSecret(\"clientSecret\");\n\t\ttestIssuerConfiguration(login, \"okta-oidc\", 0, 1);\n\t}\n\n\t@Test\n\tvoid issuerUriConfigurationTriesOidcRfc8414UriSecond() throws Exception {\n\t\tOAuth2ClientProperties.Registration login = new Registration();\n\t\tlogin.setClientId(\"clientId\");\n\t\tlogin.setClientSecret(\"clientSecret\");\n\t\ttestIssuerConfiguration(login, \"okta\", 1, 2);\n\t}\n\n\t@Test\n\tvoid issuerUriConfigurationTriesOAuthMetadataUriThird() throws Exception {\n\t\tOAuth2ClientProperties.Registration login = new Registration();\n\t\tlogin.setClientId(\"clientId\");\n\t\tlogin.setClientSecret(\"clientSecret\");\n\t\ttestIssuerConfiguration(login, \"okta\", 2, 3);\n\t}\n\n\t@Test\n\tvoid oidcProviderConfigurationWithCustomConfigurationOverridesProviderDefaults() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tsetupMockResponse(issuer);\n\t\tOAuth2ClientProperties.Registration registration = createRegistration(\"okta-oidc\");\n\t\tProvider provider = createProvider();\n\t\tprovider.setIssuerUri(issuer);\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tproperties.getProvider().put(\"okta-oidc\", provider);\n\t\tproperties.getRegistration().put(\"okta\", registration);\n\t\tMap<String, ClientRegistration> registrations = new OAuth2ClientPropertiesMapper(properties)\n\t\t\t.asClientRegistrations();\n\t\tClientRegistration adapted = registrations.get(\"okta\");\n\t\tassertThat(adapted).isNotNull();\n\t\tProviderDetails providerDetails = adapted.getProviderDetails();\n\t\tassertThat(adapted.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_POST);\n\t\tassertThat(adapted.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(adapted.getRegistrationId()).isEqualTo(\"okta\");\n\t\tassertThat(adapted.getClientName()).isEqualTo(issuer);\n\t\tassertThat(adapted.getScopes()).containsOnly(\"user\");\n\t\tassertThat(adapted.getRedirectUri()).isEqualTo(\"https://example.com/redirect\");\n\t\tassertThat(providerDetails.getAuthorizationUri()).isEqualTo(\"https://example.com/auth\");\n\t\tassertThat(providerDetails.getTokenUri()).isEqualTo(\"https://example.com/token\");\n\t\tassertThat(providerDetails.getJwkSetUri()).isEqualTo(\"https://example.com/jwk\");\n\t\tUserInfoEndpoint userInfoEndpoint = providerDetails.getUserInfoEndpoint();\n\t\tassertThat(userInfoEndpoint.getUri()).isEqualTo(\"https://example.com/info\");\n\t\tassertThat(userInfoEndpoint.getUserNameAttributeName()).isEqualTo(\"sub\");\n\t}\n\n\tprivate Provider createProvider() {\n\t\tProvider provider = new Provider();\n\t\tprovider.setAuthorizationUri(\"https://example.com/auth\");\n\t\tprovider.setTokenUri(\"https://example.com/token\");\n\t\tprovider.setUserInfoUri(\"https://example.com/info\");\n\t\tprovider.setUserNameAttribute(\"sub\");\n\t\tprovider.setJwkSetUri(\"https://example.com/jwk\");\n\t\treturn provider;\n\t}\n\n\tprivate OAuth2ClientProperties.Registration createRegistration(String provider) {\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tregistration.setProvider(provider);\n\t\tregistration.setClientId(\"clientId\");\n\t\tregistration.setClientSecret(\"clientSecret\");\n\t\tregistration.setClientAuthenticationMethod(\"client_secret_post\");\n\t\tregistration.setRedirectUri(\"https://example.com/redirect\");\n\t\tregistration.setScope(Collections.singleton(\"user\"));\n\t\tregistration.setAuthorizationGrantType(\"authorization_code\");\n\t\treturn registration;\n\t}\n\n\tprivate void testIssuerConfiguration(OAuth2ClientProperties.Registration registration, String providerId,\n\t\t\tint errorResponseCount, int numberOfRequests) throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tsetupMockResponsesWithErrors(issuer, errorResponseCount);\n\t\tOAuth2ClientProperties properties = new OAuth2ClientProperties();\n\t\tProvider provider = new Provider();\n\t\tprovider.setIssuerUri(issuer);\n\t\tproperties.getProvider().put(providerId, provider);\n\t\tproperties.getRegistration().put(\"okta\", registration);\n\t\tMap<String, ClientRegistration> registrations = new OAuth2ClientPropertiesMapper(properties)\n\t\t\t.asClientRegistrations();\n\t\tClientRegistration adapted = registrations.get(\"okta\");\n\t\tassertThat(adapted).isNotNull();\n\t\tProviderDetails providerDetails = adapted.getProviderDetails();\n\t\tassertThat(adapted.getClientAuthenticationMethod()).isEqualTo(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);\n\t\tassertThat(adapted.getAuthorizationGrantType()).isEqualTo(AuthorizationGrantType.AUTHORIZATION_CODE);\n\t\tassertThat(adapted.getRegistrationId()).isEqualTo(\"okta\");\n\t\tassertThat(adapted.getClientName()).isEqualTo(issuer);\n\t\tassertThat(adapted.getScopes()).isNull();\n\t\tassertThat(providerDetails.getAuthorizationUri()).isEqualTo(\"https://example.com/o/oauth2/v2/auth\");\n\t\tassertThat(providerDetails.getTokenUri()).isEqualTo(\"https://example.com/oauth2/v4/token\");\n\t\tassertThat(providerDetails.getJwkSetUri()).isEqualTo(\"https://example.com/oauth2/v3/certs\");\n\t\tUserInfoEndpoint userInfoEndpoint = providerDetails.getUserInfoEndpoint();\n\t\tassertThat(userInfoEndpoint.getUri()).isEqualTo(\"https://example.com/oauth2/v3/userinfo\");\n\t\tassertThat(userInfoEndpoint.getAuthenticationMethod())\n\t\t\t.isEqualTo(org.springframework.security.oauth2.core.AuthenticationMethod.HEADER);\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(numberOfRequests);\n\t}\n\n\tprivate void setupMockResponse(String issuer) {\n\t\tMockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.OK.value())\n\t\t\t.setBody(new JsonMapper().writeValueAsString(getResponse(issuer)))\n\t\t\t.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);\n\t\tassertThat(this.server).isNotNull();\n\t\tthis.server.enqueue(mockResponse);\n\t}\n\n\tprivate void setupMockResponsesWithErrors(String issuer, int errorResponseCount) {\n\t\tassertThat(this.server).isNotNull();\n\t\tfor (int i = 0; i < errorResponseCount; i++) {\n\t\t\tMockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());\n\t\t\tthis.server.enqueue(emptyResponse);\n\t\t}\n\t\tsetupMockResponse(issuer);\n\t}\n\n\tprivate Map<String, Object> getResponse(String issuer) {\n\t\tMap<String, Object> response = new HashMap<>();\n\t\tresponse.put(\"authorization_endpoint\", \"https://example.com/o/oauth2/v2/auth\");\n\t\tresponse.put(\"claims_supported\", Collections.emptyList());\n\t\tresponse.put(\"code_challenge_methods_supported\", Collections.emptyList());\n\t\tresponse.put(\"id_token_signing_alg_values_supported\", Collections.emptyList());\n\t\tresponse.put(\"issuer\", issuer);\n\t\tresponse.put(\"jwks_uri\", \"https://example.com/oauth2/v3/certs\");\n\t\tresponse.put(\"response_types_supported\", Collections.emptyList());\n\t\tresponse.put(\"revocation_endpoint\", \"https://example.com/o/oauth2/revoke\");\n\t\tresponse.put(\"scopes_supported\", Collections.singletonList(\"openid\"));\n\t\tresponse.put(\"subject_types_supported\", Collections.singletonList(\"public\"));\n\t\tresponse.put(\"grant_types_supported\", Collections.singletonList(\"authorization_code\"));\n\t\tresponse.put(\"token_endpoint\", \"https://example.com/oauth2/v4/token\");\n\t\tresponse.put(\"token_endpoint_auth_methods_supported\", Collections.singletonList(\"client_secret_basic\"));\n\t\tresponse.put(\"userinfo_endpoint\", \"https://example.com/oauth2/v3/userinfo\");\n\t\treturn response;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link OAuth2ClientProperties}.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n */\nclass OAuth2ClientPropertiesTests {\n\n\tprivate final OAuth2ClientProperties properties = new OAuth2ClientProperties();\n\n\t@Test\n\tvoid clientIdAbsentThrowsException() {\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tregistration.setClientSecret(\"secret\");\n\t\tregistration.setProvider(\"google\");\n\t\tthis.properties.getRegistration().put(\"foo\", registration);\n\t\tassertThatIllegalStateException().isThrownBy(this.properties::validate)\n\t\t\t.withMessageContaining(\"Client id of registration 'foo' must not be empty.\");\n\t}\n\n\t@Test\n\tvoid clientSecretAbsentShouldNotThrowException() {\n\t\tOAuth2ClientProperties.Registration registration = new OAuth2ClientProperties.Registration();\n\t\tregistration.setClientId(\"foo\");\n\t\tregistration.setProvider(\"google\");\n\t\tthis.properties.getRegistration().put(\"foo\", registration);\n\t\tthis.properties.validate();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/OAuth2ClientWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Mustache with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass OAuth2ClientWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid oauth2ClientAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(OAuth2ClientAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveOAuth2ClientAutoConfiguration}.\n *\n * @author Madhura Bhave\n */\nclass ReactiveOAuth2ClientAutoConfigurationTests {\n\n\tprivate static final String REGISTRATION_PREFIX = \"spring.security.oauth2.client.registration\";\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class,\n\t\t\t\tReactiveWebSecurityAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationShouldBackOffForServletEnvironments() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid beansShouldNotBeCreatedWhenPropertiesAbsent() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveClientRegistrationRepository.class)\n\t\t\t\t.doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class));\n\t}\n\n\t@Test\n\tvoid beansAreCreatedWhenPropertiesPresent() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(REGISTRATION_PREFIX + \".foo.client-id=abcd\",\n\t\t\t\t\tREGISTRATION_PREFIX + \".foo.client-secret=secret\", REGISTRATION_PREFIX + \".foo.provider=github\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveClientRegistrationRepository.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveOAuth2AuthorizedClientService.class);\n\t\t\t\tReactiveClientRegistrationRepository repository = context\n\t\t\t\t\t.getBean(ReactiveClientRegistrationRepository.class);\n\t\t\t\tClientRegistration registration = repository.findByRegistrationId(\"foo\").block(Duration.ofSeconds(30));\n\t\t\t\tassertThat(registration).isNotNull();\n\t\t\t\tassertThat(registration.getClientSecret()).isEqualTo(\"secret\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientServiceBeanIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"testAuthorizedClientService\", ReactiveOAuth2AuthorizedClientService.class,\n\t\t\t\t\t() -> mock(ReactiveOAuth2AuthorizedClientService.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveOAuth2AuthorizedClientService.class);\n\t\t\t\tassertThat(context).hasBean(\"testAuthorizedClientService\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid clientServiceBeanIsCreatedWithUserDefinedClientRegistrationRepository() {\n\t\tthis.contextRunner\n\t\t\t.withBean(InMemoryReactiveClientRegistrationRepository.class,\n\t\t\t\t\t() -> new InMemoryReactiveClientRegistrationRepository(getClientRegistration(\"test\", \"test\")))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveOAuth2AuthorizedClientService.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationConditionalOnClassFlux() {\n\t\tassertWhenClassNotPresent(Flux.class);\n\t}\n\n\t@Test\n\tvoid autoConfigurationConditionalOnClassClientRegistration() {\n\t\tassertWhenClassNotPresent(ClientRegistration.class);\n\t}\n\n\tprivate void assertWhenClassNotPresent(Class<?> classToFilter) {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(classToFilter);\n\t\tthis.contextRunner.withClassLoader(classLoader)\n\t\t\t.withPropertyValues(REGISTRATION_PREFIX + \".foo.client-id=abcd\",\n\t\t\t\t\tREGISTRATION_PREFIX + \".foo.client-secret=secret\", REGISTRATION_PREFIX + \".foo.provider=github\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveOAuth2ClientAutoConfiguration.class));\n\t}\n\n\tprivate ClientRegistration getClientRegistration(String id, String userInfoUri) {\n\t\tClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);\n\t\tbuilder.clientName(\"foo\")\n\t\t\t.clientId(\"foo\")\n\t\t\t.clientAuthenticationMethod(\n\t\t\t\t\torg.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n\t\t\t.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n\t\t\t.scope(\"read\")\n\t\t\t.clientSecret(\"secret\")\n\t\t\t.redirectUri(\"https://redirect-uri.com\")\n\t\t\t.authorizationUri(\"https://authorization-uri.com\")\n\t\t\t.tokenUri(\"https://token-uri.com\")\n\t\t\t.userInfoUri(userInfoUri)\n\t\t\t.userNameAttributeName(\"login\");\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/ReactiveOAuth2ClientWebFluxTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for reactive OAuth2 client with {@link WebFluxTest @WebFluxTest}.\n *\n * @author Andy Wilkinson\n */\n@WebFluxTest\nclass ReactiveOAuth2ClientWebFluxTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid oauth2ClientAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ReactiveOAuth2ClientAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/reactive/ReactiveOAuth2ClientWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.reactive;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;\nimport org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationCodeGrantWebFilter;\nimport org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;\nimport org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.server.WebFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveOAuth2ClientWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass ReactiveOAuth2ClientWebSecurityAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class,\n\t\t\t\tReactiveWebSecurityAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationShouldBackOffForServletEnvironments() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnAuthorizedClientService() {\n\t\tthis.contextRunner.run((context) -> assertThat(context)\n\t\t\t.doesNotHaveBean(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid configurationRegistersAuthorizedClientRepositoryBean() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.hasSingleBean(AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.class));\n\t}\n\n\t@Test\n\tvoid authorizedClientRepositoryBeanIsConditionalOnMissingBean() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ServerOAuth2AuthorizedClientRepository.class);\n\t\t\t\tassertThat(context).hasBean(\"testAuthorizedClientRepository\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid configurationRegistersSecurityWebFilterChainBean() { // gh-17949\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(ReactiveOAuth2AuthorizedClientServiceConfiguration.class,\n\t\t\t\t\tServerHttpSecurityConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(hasFilter(context, OAuth2LoginAuthenticationWebFilter.class)).isTrue();\n\t\t\t\tassertThat(hasFilter(context, OAuth2AuthorizationCodeGrantWebFilter.class)).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid securityWebFilterChainBeanConditionalOnWebApplication() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ClientWebSecurityAutoConfiguration.class,\n\t\t\t\t\tReactiveWebSecurityAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ReactiveOAuth2AuthorizedClientRepositoryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SecurityWebFilterChain.class));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate boolean hasFilter(AssertableReactiveWebApplicationContext context, Class<? extends WebFilter> filter) {\n\t\tSecurityWebFilterChain filterChain = (SecurityWebFilterChain) context\n\t\t\t.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);\n\t\tList<WebFilter> filters = (List<WebFilter>) ReflectionTestUtils.getField(filterChain, \"filters\");\n\t\tassertThat(filters).isNotNull();\n\t\treturn filters.stream().anyMatch(filter::isInstance);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ReactiveClientRepositoryConfiguration.class)\n\tstatic class ReactiveOAuth2AuthorizedClientServiceConfiguration {\n\n\t\t@Bean\n\t\tInMemoryReactiveOAuth2AuthorizedClientService testAuthorizedClientService(\n\t\t\t\tReactiveClientRegistrationRepository clientRegistrationRepository) {\n\t\t\treturn new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ReactiveOAuth2AuthorizedClientServiceConfiguration.class)\n\tstatic class ReactiveOAuth2AuthorizedClientRepositoryConfiguration {\n\n\t\t@Bean\n\t\tServerOAuth2AuthorizedClientRepository testAuthorizedClientRepository(\n\t\t\t\tReactiveOAuth2AuthorizedClientService authorizedClientService) {\n\t\t\treturn new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveClientRepositoryConfiguration {\n\n\t\t@Bean\n\t\tReactiveClientRegistrationRepository clientRegistrationRepository() {\n\t\t\tList<ClientRegistration> registrations = new ArrayList<>();\n\t\t\tregistrations.add(getClientRegistration(\"first\", \"https://user-info-uri.com\"));\n\t\t\tregistrations.add(getClientRegistration(\"second\", \"https://other-user-info\"));\n\t\t\treturn new InMemoryReactiveClientRegistrationRepository(registrations);\n\t\t}\n\n\t\tprivate ClientRegistration getClientRegistration(String id, String userInfoUri) {\n\t\t\tClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);\n\t\t\tbuilder.clientName(\"foo\")\n\t\t\t\t.clientId(\"foo\")\n\t\t\t\t.clientAuthenticationMethod(\n\t\t\t\t\t\torg.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n\t\t\t\t.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n\t\t\t\t.scope(\"read\")\n\t\t\t\t.clientSecret(\"secret\")\n\t\t\t\t.redirectUri(\"https://redirect-uri.com\")\n\t\t\t\t.authorizationUri(\"https://authorization-uri.com\")\n\t\t\t\t.tokenUri(\"https://token-uri.com\")\n\t\t\t\t.userInfoUri(userInfoUri)\n\t\t\t\t.userNameAttributeName(\"login\");\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServerHttpSecurityConfiguration {\n\n\t\t@Bean\n\t\tServerHttpSecurity http() {\n\t\t\tTestServerHttpSecurity httpSecurity = new TestServerHttpSecurity();\n\t\t\treturn httpSecurity;\n\t\t}\n\n\t\tstatic class TestServerHttpSecurity extends ServerHttpSecurity implements ApplicationContextAware {\n\n\t\t\t@Override\n\t\t\tpublic void setApplicationContext(ApplicationContext applicationContext) {\n\t\t\t\tsuper.setApplicationContext(applicationContext);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/OAuth2ClientWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository;\nimport org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter;\nimport org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;\nimport org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.filter.CompositeFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OAuth2ClientWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass OAuth2ClientWebSecurityAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OAuth2ClientWebSecurityAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationIsConditionalOnAuthorizedClientService() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OAuth2ClientWebSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid configurationRegistersAuthorizedClientRepositoryBean() {\n\t\tthis.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OAuth2AuthorizedClientRepository.class));\n\t}\n\n\t@Test\n\tvoid authorizedClientRepositoryBeanIsConditionalOnMissingBean() {\n\t\tthis.contextRunner.withUserConfiguration(OAuth2AuthorizedClientRepositoryConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(OAuth2AuthorizedClientRepository.class);\n\t\t\tassertThat(context).hasBean(\"testAuthorizedClientRepository\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid securityConfigurerConfiguresOAuth2Login() {\n\t\tthis.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class).run((context) -> {\n\t\t\tClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);\n\t\t\tClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(\n\t\t\t\t\tgetSecurityFilters(context, OAuth2LoginAuthenticationFilter.class).get(0),\n\t\t\t\t\t\"clientRegistrationRepository\");\n\t\t\tassertThat(actual).isNotNull();\n\t\t\tassertThat(isEqual(expected.findByRegistrationId(\"first\"), actual.findByRegistrationId(\"first\"))).isTrue();\n\t\t\tassertThat(isEqual(expected.findByRegistrationId(\"second\"), actual.findByRegistrationId(\"second\")))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid securityConfigurerConfiguresAuthorizationCode() {\n\t\tthis.contextRunner.withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class).run((context) -> {\n\t\t\tClientRegistrationRepository expected = context.getBean(ClientRegistrationRepository.class);\n\t\t\tClientRegistrationRepository actual = (ClientRegistrationRepository) ReflectionTestUtils.getField(\n\t\t\t\t\tgetSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class).get(0),\n\t\t\t\t\t\"clientRegistrationRepository\");\n\t\t\tassertThat(actual).isNotNull();\n\t\t\tassertThat(isEqual(expected.findByRegistrationId(\"first\"), actual.findByRegistrationId(\"first\"))).isTrue();\n\t\t\tassertThat(isEqual(expected.findByRegistrationId(\"second\"), actual.findByRegistrationId(\"second\")))\n\t\t\t\t.isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid securityConfigurerBacksOffWhenClientRegistrationBeanAbsent() {\n\t\tthis.contextRunner.withUserConfiguration(TestConfig.class).run((context) -> {\n\t\t\tassertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();\n\t\t\tassertThat(getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid securityFilterChainConfigBacksOffWhenOtherSecurityFilterChainBeanPresent() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestSecurityFilterChainConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();\n\t\t\t\tassertThat(getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();\n\t\t\t\tassertThat(context).getBean(OAuth2AuthorizedClientService.class).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid securityFilterChainConfigConditionalOnSecurityFilterChainClass() {\n\t\tthis.contextRunner.withUserConfiguration(ClientRegistrationRepositoryConfiguration.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getSecurityFilters(context, OAuth2LoginAuthenticationFilter.class)).isEmpty();\n\t\t\t\tassertThat(getSecurityFilters(context, OAuth2AuthorizationCodeGrantFilter.class)).isEmpty();\n\t\t\t});\n\t}\n\n\tprivate List<Filter> getSecurityFilters(AssertableWebApplicationContext context, Class<? extends Filter> filter) {\n\t\treturn getSecurityFilterChain(context).getFilters().stream().filter(filter::isInstance).toList();\n\t}\n\n\tprivate SecurityFilterChain getSecurityFilterChain(AssertableWebApplicationContext context) {\n\t\tFilter springSecurityFilterChain = context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);\n\t\tFilterChainProxy filterChainProxy = getFilterChainProxy(springSecurityFilterChain);\n\t\treturn filterChainProxy.getFilterChains().get(0);\n\t}\n\n\tprivate FilterChainProxy getFilterChainProxy(Filter filter) {\n\t\tif (filter instanceof FilterChainProxy filterChainProxy) {\n\t\t\treturn filterChainProxy;\n\t\t}\n\t\tif (filter instanceof CompositeFilter) {\n\t\t\tList<?> filters = (List<?>) ReflectionTestUtils.getField(filter, \"filters\");\n\t\t\tassertThat(filters).isNotNull();\n\t\t\treturn (FilterChainProxy) filters.stream()\n\t\t\t\t.filter(FilterChainProxy.class::isInstance)\n\t\t\t\t.findFirst()\n\t\t\t\t.orElseThrow();\n\t\t}\n\t\tthrow new IllegalStateException(\"No FilterChainProxy found\");\n\t}\n\n\tprivate boolean isEqual(ClientRegistration reg1, ClientRegistration reg2) {\n\t\tboolean result = ObjectUtils.nullSafeEquals(reg1.getClientId(), reg2.getClientId());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getClientName(), reg2.getClientName());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getClientSecret(), reg2.getClientSecret());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getScopes(), reg2.getScopes());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getRedirectUri(), reg2.getRedirectUri());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getRegistrationId(), reg2.getRegistrationId());\n\t\tresult = result\n\t\t\t\t&& ObjectUtils.nullSafeEquals(reg1.getAuthorizationGrantType(), reg2.getAuthorizationGrantType());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getProviderDetails().getAuthorizationUri(),\n\t\t\t\treg2.getProviderDetails().getAuthorizationUri());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getProviderDetails().getUserInfoEndpoint(),\n\t\t\t\treg2.getProviderDetails().getUserInfoEndpoint());\n\t\tresult = result && ObjectUtils.nullSafeEquals(reg1.getProviderDetails().getTokenUri(),\n\t\t\t\treg2.getProviderDetails().getTokenUri());\n\t\treturn result;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(ClientRegistrationRepositoryConfiguration.class)\n\tstatic class OAuth2AuthorizedClientServiceConfiguration {\n\n\t\t@Bean\n\t\tInMemoryOAuth2AuthorizedClientService authorizedClientService(\n\t\t\t\tClientRegistrationRepository clientRegistrationRepository) {\n\t\t\treturn new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(OAuth2AuthorizedClientServiceConfiguration.class)\n\tstatic class OAuth2AuthorizedClientRepositoryConfiguration {\n\n\t\t@Bean\n\t\tOAuth2AuthorizedClientRepository testAuthorizedClientRepository(\n\t\t\t\tOAuth2AuthorizedClientService authorizedClientService) {\n\t\t\treturn new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(TestConfig.class)\n\tstatic class ClientRegistrationRepositoryConfiguration {\n\n\t\t@Bean\n\t\tClientRegistrationRepository clientRegistrationRepository() {\n\t\t\tList<ClientRegistration> registrations = new ArrayList<>();\n\t\t\tregistrations.add(getClientRegistration(\"first\", \"https://user-info-uri.com\"));\n\t\t\tregistrations.add(getClientRegistration(\"second\", \"https://other-user-info\"));\n\t\t\treturn new InMemoryClientRegistrationRepository(registrations);\n\t\t}\n\n\t\tprivate ClientRegistration getClientRegistration(String id, String userInfoUri) {\n\t\t\tClientRegistration.Builder builder = ClientRegistration.withRegistrationId(id);\n\t\t\tbuilder.clientName(\"foo\")\n\t\t\t\t.clientId(\"foo\")\n\t\t\t\t.clientAuthenticationMethod(\n\t\t\t\t\t\torg.springframework.security.oauth2.core.ClientAuthenticationMethod.CLIENT_SECRET_BASIC)\n\t\t\t\t.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n\t\t\t\t.scope(\"read\")\n\t\t\t\t.clientSecret(\"secret\")\n\t\t\t\t.redirectUri(\"https://redirect-uri.com\")\n\t\t\t\t.authorizationUri(\"https://authorization-uri.com\")\n\t\t\t\t.tokenUri(\"https://token-uri.com\")\n\t\t\t\t.userInfoUri(userInfoUri)\n\t\t\t\t.userNameAttributeName(\"login\");\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(OAuth2AuthorizedClientServiceConfiguration.class)\n\tstatic class TestSecurityFilterChainConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain testSecurityFilterChain(HttpSecurity http) {\n\t\t\treturn http.securityMatcher(\"/**\")\n\t\t\t\t.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())\n\t\t\t\t.build();\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/webmvc/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet.webmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@RestController\npublic class ExampleController {\n\n\t@GetMapping(\"/one\")\n\tpublic String one() {\n\t\treturn \"one\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/webmvc/OAuth2ClientWebMvcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet.webmvc;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\n\n/**\n * Test application for OAuth2 Client support with WebMvc.\n *\n * @author Andy Wilkinson\n */\n@EnableWebSecurity\n@SpringBootApplication\npublic class OAuth2ClientWebMvcApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/webmvc/OAuth2ClientWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet.webmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.MockMvc;\n\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with OAuth2.\n *\n * @author Dmytro Nosan\n */\n@WebMvcTest(controllers = ExampleController.class,\n\t\tproperties = { \"spring.security.oauth2.client.registration.test.client-id=test\",\n\t\t\t\t\"spring.security.oauth2.client.registration.test.authorization-grant-type=authorization-code\",\n\t\t\t\t\"spring.security.oauth2.client.provider.test.authorization-uri=https://auth.example.org\" })\nclass OAuth2ClientWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvc mockMvc;\n\n\t@Test\n\tvoid shouldRedirectToLogin() throws Exception {\n\t\tthis.mockMvc.perform(get(\"/one\")).andExpect(status().isFound()).andExpect(redirectedUrl(\"/login\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-client/src/test/java/org/springframework/boot/security/oauth2/client/autoconfigure/servlet/webmvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.security.oauth2.client.autoconfigure.servlet.webmvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Security OAuth2 Resource Server\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.security:spring-security-oauth2-jose\")\n\tapi(\"org.springframework.security:spring-security-oauth2-resource-server\")\n\n\timplementation(project(\":module:spring-boot-security\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-reactor\"))\n\toptional(project(\":module:spring-boot-webflux-test\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-actuator-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-health\"))\n\ttestImplementation(project(\":module:spring-boot-webflux\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\n\ttestCompileOnly(\"com.google.code.findbugs:jsr305\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.springframework:spring-webflux\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnIssuerLocationJwtDecoder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder;\n\n/**\n * Condition that matches when an {@link NimbusJwtDecoder#withIssuerLocation\n * issuer-location-based JWT decoder} should be used.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(IssuerUriCondition.class)\npublic @interface ConditionalOnIssuerLocationJwtDecoder {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/ConditionalOnPublicKeyJwtDecoder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder;\n\n/**\n * Condition that matches when a {@link NimbusJwtDecoder#withPublicKey public-key-based\n * JWT decoder} should be used.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@Conditional(KeyValueCondition.class)\npublic @interface ConditionalOnPublicKeyJwtDecoder {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/IssuerUriCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.util.StringUtils;\n\n/**\n * Condition for creating {@link JwtDecoder} by oidc issuer location.\n *\n * @author Artsiom Yudovin\n */\nclass IssuerUriCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"OpenID Connect Issuer URI Condition\");\n\t\tEnvironment environment = context.getEnvironment();\n\t\tString issuerUri = environment.getProperty(\"spring.security.oauth2.resourceserver.jwt.issuer-uri\");\n\t\tif (!StringUtils.hasText(issuerUri)) {\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"issuer-uri property\").atAll());\n\t\t}\n\t\tString jwkSetUri = environment.getProperty(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\");\n\t\tif (StringUtils.hasText(jwkSetUri)) {\n\t\t\treturn ConditionOutcome.noMatch(message.found(\"jwk-set-uri property\").items(jwkSetUri));\n\t\t}\n\t\treturn ConditionOutcome.match(message.foundExactly(\"issuer-uri property\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwkSetUriJwtDecoderBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder;\n\n/**\n * Callback interface for the customization of the {@link JwkSetUriJwtDecoderBuilder} used\n * to create the auto-configured {@link JwtDecoder} for a JWK set URI that has been\n * configured directly or obtained through an issuer URI.\n *\n * @author Andy Wilkinson\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface JwkSetUriJwtDecoderBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the {@code builder} to customize\n\t */\n\tvoid customize(JwkSetUriJwtDecoderBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtConverterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.OnPropertyListCondition;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.expression.spel.standard.SpelExpressionParser;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.resource.authentication.DelegatingJwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link Configuration @Configuration} for JWT converter beans.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author HaiTao Zhang\n * @author Mushtaq Ahmed\n * @author Roman Golovin\n * @author Yan Kardziyaka\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(JwtDecoder.class)\n@ConditionalOnMissingBean(JwtAuthenticationConverter.class)\n@Conditional(JwtConverterConfiguration.PropertiesCondition.class)\nclass JwtConverterConfiguration {\n\n\t@Bean\n\tJwtAuthenticationConverter jwtAuthenticationConverter(OAuth2ResourceServerProperties properties) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tOAuth2ResourceServerProperties.Jwt jwtProperties = properties.getJwt();\n\t\tJwtAuthenticationConverter converter = new JwtAuthenticationConverter();\n\t\tmap.from(jwtProperties::getPrincipalClaimName).to(converter::setPrincipalClaimName);\n\t\tmap.from(jwtProperties).as(this::grantedAuthoritiesConverter).to(converter::setJwtGrantedAuthoritiesConverter);\n\t\treturn converter;\n\t}\n\n\tprivate Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter(\n\t\t\tOAuth2ResourceServerProperties.Jwt properties) {\n\t\tList<String> authoritiesClaimExpressions = properties.getAuthoritiesClaimExpressions();\n\t\tif (CollectionUtils.isEmpty(authoritiesClaimExpressions)) {\n\t\t\treturn createJwtGrantedAuthoritiesConverter(properties);\n\t\t}\n\t\treturn createExpressionJwtGrantedAuthoritiesConverters(properties, authoritiesClaimExpressions);\n\t}\n\n\tprivate Converter<Jwt, Collection<GrantedAuthority>> createJwtGrantedAuthoritiesConverter(\n\t\t\tOAuth2ResourceServerProperties.Jwt properties) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tJwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();\n\t\tmap.from(properties::getAuthorityPrefix).to(converter::setAuthorityPrefix);\n\t\tmap.from(properties::getAuthoritiesClaimDelimiter).to(converter::setAuthoritiesClaimDelimiter);\n\t\tmap.from(properties::getAuthoritiesClaimName).to(converter::setAuthoritiesClaimName);\n\t\treturn converter;\n\t}\n\n\tprivate Converter<Jwt, Collection<GrantedAuthority>> createExpressionJwtGrantedAuthoritiesConverters(\n\t\t\tOAuth2ResourceServerProperties.Jwt properties, List<String> claimExpressions) {\n\t\tcheckMutualExclusivity(properties);\n\t\tList<Converter<Jwt, Collection<GrantedAuthority>>> converters = new ArrayList<>();\n\t\tSpelExpressionParser parser = new SpelExpressionParser();\n\t\tfor (String claimExpression : claimExpressions) {\n\t\t\tExpressionJwtGrantedAuthoritiesConverter converter = new ExpressionJwtGrantedAuthoritiesConverter(\n\t\t\t\t\tparser.parseExpression(claimExpression));\n\t\t\tif (properties.getAuthorityPrefix() != null) {\n\t\t\t\tconverter.setAuthorityPrefix(properties.getAuthorityPrefix());\n\t\t\t}\n\t\t\tconverters.add(converter);\n\t\t}\n\t\treturn (converters.size() == 1) ? converters.get(0) : new DelegatingJwtGrantedAuthoritiesConverter(converters);\n\t}\n\n\tprivate void checkMutualExclusivity(OAuth2ResourceServerProperties.Jwt properties) {\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions\",\n\t\t\t\t\tproperties.getAuthoritiesClaimExpressions());\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name\",\n\t\t\t\t\tproperties.getAuthoritiesClaimName());\n\t\t}, (value) -> !nullOrEmptyList(value));\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions\",\n\t\t\t\t\tproperties.getAuthoritiesClaimExpressions());\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter\",\n\t\t\t\t\tproperties.getAuthoritiesClaimDelimiter());\n\t\t}, (value) -> !nullOrEmptyList(value));\n\t}\n\n\tprivate boolean nullOrEmptyList(Object value) {\n\t\tif (value == null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (value instanceof List<?> list) ? list.isEmpty() : false;\n\t}\n\n\tstatic class PropertiesCondition extends AnyNestedCondition {\n\n\t\tPropertiesCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.security.oauth2.resourceserver.jwt.authority-prefix\")\n\t\tstatic class OnAuthorityPrefix {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.security.oauth2.resourceserver.jwt.principal-claim-name\")\n\t\tstatic class OnPrincipalClaimName {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name\")\n\t\tstatic class OnAuthoritiesClaimName {\n\n\t\t}\n\n\t\t@Conditional(OnAuthoritiesExpressionsCondition.class)\n\t\tstatic class OnAuthoritiesExpressions {\n\n\t\t}\n\n\t\tstatic class OnAuthoritiesExpressionsCondition extends OnPropertyListCondition {\n\n\t\t\tOnAuthoritiesExpressionsCondition() {\n\t\t\t\tsuper(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions\",\n\t\t\t\t\t\t() -> ConditionMessage.forCondition(\"Authorities claim expressions\"));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtDecoderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.security.KeyFactory;\nimport java.security.interfaces.RSAPublicKey;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.core.OAuth2TokenValidator;\nimport org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.JwtClaimNames;\nimport org.springframework.security.oauth2.jwt.JwtClaimValidator;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.jwt.JwtIssuerValidator;\nimport org.springframework.security.oauth2.jwt.JwtValidators;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder.PublicKeyJwtDecoderBuilder;\nimport org.springframework.security.oauth2.jwt.SupplierJwtDecoder;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Configuration @Configuration} for JWT decoder beans.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author HaiTao Zhang\n * @author Mushtaq Ahmed\n * @author Roman Golovin\n * @author Yan Kardziyaka\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(JwtDecoder.class)\n@ConditionalOnMissingBean(JwtDecoder.class)\nclass JwtDecoderConfiguration {\n\n\tprivate final OAuth2ResourceServerProperties.Jwt properties;\n\n\tprivate final List<OAuth2TokenValidator<Jwt>> additionalValidators;\n\n\tprivate final ObjectProvider<JwkSetUriJwtDecoderBuilderCustomizer> jwkSetUriJwtDecoderBuilderCustomizers;\n\n\tJwtDecoderConfiguration(OAuth2ResourceServerProperties properties,\n\t\t\tObjectProvider<OAuth2TokenValidator<Jwt>> additionalValidators,\n\t\t\tObjectProvider<JwkSetUriJwtDecoderBuilderCustomizer> jwkSetUriJwtDecoderBuilderCustomizers) {\n\t\tthis.properties = properties.getJwt();\n\t\tthis.additionalValidators = additionalValidators.orderedStream().toList();\n\t\tthis.jwkSetUriJwtDecoderBuilderCustomizers = jwkSetUriJwtDecoderBuilderCustomizers;\n\t}\n\n\t@Bean\n\t@ConditionalOnPublicKeyJwtDecoder\n\tJwtDecoder jwtDecoderByPublicKeyValue() throws Exception {\n\t\tPublicKeyJwtDecoderBuilder builder = NimbusJwtDecoder.withPublicKey(getReadPublicKey());\n\t\tbuilder.signatureAlgorithm(exactlyOneAlgorithm());\n\t\tNimbusJwtDecoder decoder = builder.build();\n\t\tdecoder.setJwtValidator(getValidator());\n\t\treturn decoder;\n\t}\n\n\tprivate RSAPublicKey getReadPublicKey() throws Exception {\n\t\tX509EncodedKeySpec spec = new X509EncodedKeySpec(decodeKeyProperty(this.properties.readPublicKey()));\n\t\treturn (RSAPublicKey) KeyFactory.getInstance(\"RSA\").generatePublic(spec);\n\t}\n\n\tprivate byte[] decodeKeyProperty(String value) {\n\t\treturn Base64.getMimeDecoder()\n\t\t\t.decode(value.replace(\"-----BEGIN PUBLIC KEY-----\", \"\").replace(\"-----END PUBLIC KEY-----\", \"\"));\n\t}\n\n\tprivate SignatureAlgorithm exactlyOneAlgorithm() {\n\t\tList<String> algorithms = this.properties.getJwsAlgorithms();\n\t\tAssert.state(algorithms != null && algorithms.size() == 1,\n\t\t\t\t() -> \"Creating a JWT decoder using a public key requires exactly one JWS algorithm but \"\n\t\t\t\t\t\t+ algorithms.size() + \" were configured\");\n\t\tSignatureAlgorithm algorithm = SignatureAlgorithm.from(algorithms.get(0));\n\t\tif (algorithm == null) {\n\t\t\tthrow new InvalidConfigurationPropertyValueException(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms\",\n\t\t\t\t\tStringUtils.collectionToCommaDelimitedString(algorithms), \"Unknown algorithm\");\n\t\t}\n\t\treturn algorithm;\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\")\n\tJwtDecoder jwtDecoderByJwkKeySetUri() {\n\t\tString jwkSetUri = this.properties.getJwkSetUri();\n\t\tAssert.state(jwkSetUri != null, \"No JWK Set URI property specified\");\n\t\tJwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri);\n\t\tbuilder.jwsAlgorithms(this::jwsAlgorithms);\n\t\treturn buildJwkSetUriJwtDecoder(builder);\n\t}\n\n\tprivate void jwsAlgorithms(Set<SignatureAlgorithm> signatureAlgorithms) {\n\t\tthis.properties.getJwsAlgorithms().stream().map(SignatureAlgorithm::from).forEach(signatureAlgorithms::add);\n\t}\n\n\t@Bean\n\t@ConditionalOnIssuerLocationJwtDecoder\n\tSupplierJwtDecoder jwtDecoderByIssuerUri() {\n\t\treturn new SupplierJwtDecoder(this::supplyJwtDecoderByIssuerUri);\n\t}\n\n\tprivate JwtDecoder supplyJwtDecoderByIssuerUri() {\n\t\tString issuerUri = this.properties.getIssuerUri();\n\t\tAssert.state(issuerUri != null, \"No JWT issuer URI propery specified\");\n\t\tJwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withIssuerLocation(issuerUri);\n\t\treturn buildJwkSetUriJwtDecoder(builder);\n\t}\n\n\tprivate JwtDecoder buildJwkSetUriJwtDecoder(JwkSetUriJwtDecoderBuilder builder) {\n\t\tthis.jwkSetUriJwtDecoderBuilderCustomizers.orderedStream()\n\t\t\t.forEach((customizer) -> customizer.customize(builder));\n\t\tNimbusJwtDecoder decoder = builder.build();\n\t\tdecoder.setJwtValidator(getValidator());\n\t\treturn decoder;\n\t}\n\n\tprivate OAuth2TokenValidator<Jwt> getValidator() {\n\t\tList<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();\n\t\tif (this.properties.getIssuerUri() != null) {\n\t\t\tvalidators.add(new JwtIssuerValidator(this.properties.getIssuerUri()));\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.properties.getAudiences())) {\n\t\t\tvalidators.add(audienceValidator(this.properties.getAudiences()));\n\t\t}\n\t\tvalidators.addAll(this.additionalValidators);\n\t\treturn validators.isEmpty() ? JwtValidators.createDefault()\n\t\t\t\t: JwtValidators.createDefaultWithValidators(validators);\n\t}\n\n\tprivate JwtClaimValidator<List<String>> audienceValidator(List<String> audiences) {\n\t\treturn new JwtClaimValidator<>(JwtClaimNames.AUD, (claim) -> hasElementsInCommon(claim, audiences));\n\t}\n\n\tprivate <E> boolean hasElementsInCommon(@Nullable List<E> c1, List<E> c2) {\n\t\treturn c1 != null && !Collections.disjoint(c1, c2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/KeyValueCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.StringUtils;\n\n/**\n * Condition for creating a jwt decoder using a public key value.\n *\n * @author Madhura Bhave\n */\nclass KeyValueCondition extends SpringBootCondition {\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Public Key Value Condition\");\n\t\tEnvironment environment = context.getEnvironment();\n\t\tString publicKeyLocation = environment\n\t\t\t.getProperty(\"spring.security.oauth2.resourceserver.jwt.public-key-location\");\n\t\tif (!StringUtils.hasText(publicKeyLocation)) {\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"public-key-location property\").atAll());\n\t\t}\n\t\tString jwkSetUri = environment.getProperty(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\");\n\t\tif (StringUtils.hasText(jwkSetUri)) {\n\t\t\treturn ConditionOutcome.noMatch(message.found(\"jwk-set-uri property\").items(jwkSetUri));\n\t\t}\n\t\tString issuerUri = environment.getProperty(\"spring.security.oauth2.resourceserver.jwt.issuer-uri\");\n\t\tif (StringUtils.hasText(issuerUri)) {\n\t\t\treturn ConditionOutcome.noMatch(message.found(\"issuer-uri property\").items(issuerUri));\n\t\t}\n\t\treturn ConditionOutcome.match(message.foundExactly(\"public key location property\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OAuth2 resource server support.\n *\n * @author Madhura Bhave\n * @since 4.1.0\n */\n@AutoConfiguration(before = { SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class })\n@EnableConfigurationProperties(OAuth2ResourceServerProperties.class)\n@ConditionalOnClass(BearerTokenAuthenticationToken.class)\n@Import({ JwtConverterConfiguration.class, JwtDecoderConfiguration.class, OpaqueTokenIntrospectionConfiguration.class })\npublic final class OAuth2ResourceServerAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.StreamUtils;\n\n/**\n * OAuth 2.0 resource server properties.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author Mushtaq Ahmed\n * @author Yan Kardziyaka\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.security.oauth2.resourceserver\")\npublic class OAuth2ResourceServerProperties {\n\n\tprivate final Jwt jwt = new Jwt();\n\n\tpublic Jwt getJwt() {\n\t\treturn this.jwt;\n\t}\n\n\tprivate final Opaquetoken opaquetoken = new Opaquetoken();\n\n\tpublic Opaquetoken getOpaquetoken() {\n\t\treturn this.opaquetoken;\n\t}\n\n\tpublic static class Jwt {\n\n\t\t/**\n\t\t * JSON Web Key URI to use to verify the JWT token.\n\t\t */\n\t\tprivate @Nullable String jwkSetUri;\n\n\t\t/**\n\t\t * JSON Web Algorithms used for verifying the digital signatures.\n\t\t */\n\t\tprivate List<String> jwsAlgorithms = Arrays.asList(\"RS256\");\n\n\t\t/**\n\t\t * URI that can either be an OpenID Connect discovery endpoint or an OAuth 2.0\n\t\t * Authorization Server Metadata endpoint defined by RFC 8414.\n\t\t */\n\t\tprivate @Nullable String issuerUri;\n\n\t\t/**\n\t\t * Location of the file containing the public key used to verify a JWT.\n\t\t */\n\t\tprivate @Nullable Resource publicKeyLocation;\n\n\t\t/**\n\t\t * Identifies the recipients that the JWT is intended for.\n\t\t */\n\t\tprivate List<String> audiences = new ArrayList<>();\n\n\t\t/**\n\t\t * Prefix to use for authorities mapped from JWT.\n\t\t */\n\t\tprivate @Nullable String authorityPrefix;\n\n\t\t/**\n\t\t * Regex to use for splitting the value of the authorities claim into authorities.\n\t\t */\n\t\tprivate @Nullable String authoritiesClaimDelimiter;\n\n\t\t/**\n\t\t * Name of token claim to use for mapping authorities from JWT.\n\t\t */\n\t\tprivate @Nullable String authoritiesClaimName;\n\n\t\t/**\n\t\t * List of expressions to use to extract authorities from a JWT. Mutually\n\t\t * exclusive with\n\t\t * 'spring.security.oauth2.resourceserver.jwt.authorities-claim-name' and\n\t\t * 'spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter'.\n\t\t */\n\t\tprivate List<String> authoritiesClaimExpressions = new ArrayList<>();\n\n\t\t/**\n\t\t * JWT principal claim name.\n\t\t */\n\t\tprivate @Nullable String principalClaimName;\n\n\t\tpublic @Nullable String getJwkSetUri() {\n\t\t\treturn this.jwkSetUri;\n\t\t}\n\n\t\tpublic void setJwkSetUri(@Nullable String jwkSetUri) {\n\t\t\tthis.jwkSetUri = jwkSetUri;\n\t\t}\n\n\t\tpublic List<String> getJwsAlgorithms() {\n\t\t\treturn this.jwsAlgorithms;\n\t\t}\n\n\t\tpublic void setJwsAlgorithms(List<String> jwsAlgorithms) {\n\t\t\tthis.jwsAlgorithms = jwsAlgorithms;\n\t\t}\n\n\t\tpublic @Nullable String getIssuerUri() {\n\t\t\treturn this.issuerUri;\n\t\t}\n\n\t\tpublic void setIssuerUri(@Nullable String issuerUri) {\n\t\t\tthis.issuerUri = issuerUri;\n\t\t}\n\n\t\tpublic @Nullable Resource getPublicKeyLocation() {\n\t\t\treturn this.publicKeyLocation;\n\t\t}\n\n\t\tpublic void setPublicKeyLocation(@Nullable Resource publicKeyLocation) {\n\t\t\tthis.publicKeyLocation = publicKeyLocation;\n\t\t}\n\n\t\tpublic List<String> getAudiences() {\n\t\t\treturn this.audiences;\n\t\t}\n\n\t\tpublic void setAudiences(List<String> audiences) {\n\t\t\tthis.audiences = audiences;\n\t\t}\n\n\t\tpublic @Nullable String getAuthorityPrefix() {\n\t\t\treturn this.authorityPrefix;\n\t\t}\n\n\t\tpublic void setAuthorityPrefix(@Nullable String authorityPrefix) {\n\t\t\tthis.authorityPrefix = authorityPrefix;\n\t\t}\n\n\t\tpublic @Nullable String getAuthoritiesClaimDelimiter() {\n\t\t\treturn this.authoritiesClaimDelimiter;\n\t\t}\n\n\t\tpublic void setAuthoritiesClaimDelimiter(@Nullable String authoritiesClaimDelimiter) {\n\t\t\tthis.authoritiesClaimDelimiter = authoritiesClaimDelimiter;\n\t\t}\n\n\t\tpublic @Nullable String getAuthoritiesClaimName() {\n\t\t\treturn this.authoritiesClaimName;\n\t\t}\n\n\t\tpublic void setAuthoritiesClaimName(@Nullable String authoritiesClaimName) {\n\t\t\tthis.authoritiesClaimName = authoritiesClaimName;\n\t\t}\n\n\t\tpublic List<String> getAuthoritiesClaimExpressions() {\n\t\t\treturn this.authoritiesClaimExpressions;\n\t\t}\n\n\t\tpublic void setAuthoritiesExpressions(List<String> authoritiesExpressions) {\n\t\t\tthis.authoritiesClaimExpressions = authoritiesExpressions;\n\t\t}\n\n\t\tpublic @Nullable String getPrincipalClaimName() {\n\t\t\treturn this.principalClaimName;\n\t\t}\n\n\t\tpublic void setPrincipalClaimName(@Nullable String principalClaimName) {\n\t\t\tthis.principalClaimName = principalClaimName;\n\t\t}\n\n\t\tpublic String readPublicKey() throws IOException {\n\t\t\tString key = \"spring.security.oauth2.resourceserver.jwt.public-key-location\";\n\t\t\tif (this.publicKeyLocation == null) {\n\t\t\t\tthrow new InvalidConfigurationPropertyValueException(key, this.publicKeyLocation,\n\t\t\t\t\t\t\"No public key location specified\");\n\t\t\t}\n\t\t\tif (!this.publicKeyLocation.exists()) {\n\t\t\t\tthrow new InvalidConfigurationPropertyValueException(key, this.publicKeyLocation,\n\t\t\t\t\t\t\"Public key location does not exist\");\n\t\t\t}\n\t\t\ttry (InputStream inputStream = this.publicKeyLocation.getInputStream()) {\n\t\t\t\treturn StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tpublic static class Opaquetoken {\n\n\t\t/**\n\t\t * Client id used to authenticate with the token introspection endpoint.\n\t\t */\n\t\tprivate @Nullable String clientId;\n\n\t\t/**\n\t\t * Client secret used to authenticate with the token introspection endpoint.\n\t\t */\n\t\tprivate @Nullable String clientSecret;\n\n\t\t/**\n\t\t * OAuth 2.0 endpoint through which token introspection is accomplished.\n\t\t */\n\t\tprivate @Nullable String introspectionUri;\n\n\t\tpublic @Nullable String getClientId() {\n\t\t\treturn this.clientId;\n\t\t}\n\n\t\tpublic void setClientId(@Nullable String clientId) {\n\t\t\tthis.clientId = clientId;\n\t\t}\n\n\t\tpublic @Nullable String getClientSecret() {\n\t\t\treturn this.clientSecret;\n\t\t}\n\n\t\tpublic void setClientSecret(@Nullable String clientSecret) {\n\t\t\tthis.clientSecret = clientSecret;\n\t\t}\n\n\t\tpublic @Nullable String getIntrospectionUri() {\n\t\t\treturn this.introspectionUri;\n\t\t}\n\n\t\tpublic void setIntrospectionUri(@Nullable String introspectionUri) {\n\t\t\tthis.introspectionUri = introspectionUri;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OpaqueTokenIntrospectionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;\nimport org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;\nimport org.springframework.util.Assert;\n\n/**\n * Configures an {@link OpaqueTokenIntrospector} when a token introspection endpoint is\n * available.\n *\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(OpaqueTokenIntrospector.class)\nclass OpaqueTokenIntrospectionConfiguration {\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri\")\n\tSpringOpaqueTokenIntrospector opaqueTokenIntrospector(OAuth2ResourceServerProperties properties,\n\t\t\tObjectProvider<SpringOpaqueTokenIntrospectorBuilderCustomizer> customizers) {\n\t\tOAuth2ResourceServerProperties.Opaquetoken token = properties.getOpaquetoken();\n\t\tAssert.state(token.getClientId() != null,\n\t\t\t\t\"No 'spring.security.oauth2.resourceserver.opaquetoken.client-id' property specified\");\n\t\tAssert.state(token.getClientSecret() != null,\n\t\t\t\t\"No 'spring.security.oauth2.resourceserver.opaquetoken.client-secret' property specified\");\n\t\tSpringOpaqueTokenIntrospector.Builder builder = SpringOpaqueTokenIntrospector\n\t\t\t.withIntrospectionUri(token.getIntrospectionUri())\n\t\t\t.clientId(token.getClientId())\n\t\t\t.clientSecret(token.getClientSecret());\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/SpringOpaqueTokenIntrospectorBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;\nimport org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector.Builder;\n\n/**\n * Callback interface for the customization of the {@link Builder\n * SpringOpaqueTokenIntrospector.Builder} used to create the auto-configured\n * {@link SpringOpaqueTokenIntrospector}.\n *\n * @author Vishnutheep B\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface SpringOpaqueTokenIntrospectorBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the {@code builder} to customize\n\t */\n\tvoid customize(SpringOpaqueTokenIntrospector.Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Spring Security's OAuth2 resource server.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/JwkSetUriReactiveJwtDecoderBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder;\nimport org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;\n\n/**\n * Callback interface for the customization of the\n * {@link JwkSetUriReactiveJwtDecoderBuilder} used to create the auto-configured\n * {@link ReactiveJwtDecoder} for a JWK set URI that has been configured directly or\n * obtained through an issuer URI.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface JwkSetUriReactiveJwtDecoderBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the {@code builder} to customize\n\t */\n\tvoid customize(JwkSetUriReactiveJwtDecoderBuilder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtConverterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.OnPropertyListCondition;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.expression.spel.standard.SpelExpressionParser;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;\nimport org.springframework.security.oauth2.server.resource.authentication.DelegatingJwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtGrantedAuthoritiesConverterAdapter;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link Configuration @Configuration} for JWT converter beans.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author HaiTao Zhang\n * @author Anastasiia Losieva\n * @author Mushtaq Ahmed\n * @author Roman Golovin\n * @author Yan Kardziyaka\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(ReactiveJwtDecoder.class)\n@ConditionalOnMissingBean(ReactiveJwtAuthenticationConverter.class)\n@Conditional(ReactiveJwtConverterConfiguration.PropertiesCondition.class)\nclass ReactiveJwtConverterConfiguration {\n\n\t@Bean\n\tReactiveJwtAuthenticationConverter reactiveJwtAuthenticationConverter(OAuth2ResourceServerProperties properties) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tOAuth2ResourceServerProperties.Jwt jwtProperties = properties.getJwt();\n\t\tReactiveJwtAuthenticationConverter jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();\n\t\tmap.from(jwtProperties::getPrincipalClaimName).to(jwtAuthenticationConverter::setPrincipalClaimName);\n\t\tmap.from(jwtProperties)\n\t\t\t.as(this::grantedAuthoritiesConverter)\n\t\t\t.as(ReactiveJwtGrantedAuthoritiesConverterAdapter::new)\n\t\t\t.to(jwtAuthenticationConverter::setJwtGrantedAuthoritiesConverter);\n\t\treturn jwtAuthenticationConverter;\n\t}\n\n\tprivate Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter(\n\t\t\tOAuth2ResourceServerProperties.Jwt properties) {\n\t\tList<String> authoritiesClaimExpressions = properties.getAuthoritiesClaimExpressions();\n\t\tif (CollectionUtils.isEmpty(authoritiesClaimExpressions)) {\n\t\t\treturn createJwtGrantedAuthoritiesConverter(properties);\n\t\t}\n\t\treturn createExpressionJwtGrantedAuthoritiesConverters(properties, authoritiesClaimExpressions);\n\t}\n\n\tprivate Converter<Jwt, Collection<GrantedAuthority>> createJwtGrantedAuthoritiesConverter(\n\t\t\tOAuth2ResourceServerProperties.Jwt properties) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tJwtGrantedAuthoritiesConverter converter = new JwtGrantedAuthoritiesConverter();\n\t\tmap.from(properties::getAuthorityPrefix).to(converter::setAuthorityPrefix);\n\t\tmap.from(properties::getAuthoritiesClaimDelimiter).to(converter::setAuthoritiesClaimDelimiter);\n\t\tmap.from(properties::getAuthoritiesClaimName).to(converter::setAuthoritiesClaimName);\n\t\treturn converter;\n\t}\n\n\tprivate Converter<Jwt, Collection<GrantedAuthority>> createExpressionJwtGrantedAuthoritiesConverters(\n\t\t\tOAuth2ResourceServerProperties.Jwt properties, List<String> claimExpressions) {\n\t\tcheckMutualExclusivity(properties);\n\t\tList<Converter<Jwt, Collection<GrantedAuthority>>> converters = new ArrayList<>();\n\t\tSpelExpressionParser parser = new SpelExpressionParser();\n\t\tfor (String claimExpression : claimExpressions) {\n\t\t\tExpressionJwtGrantedAuthoritiesConverter converter = new ExpressionJwtGrantedAuthoritiesConverter(\n\t\t\t\t\tparser.parseExpression(claimExpression));\n\t\t\tif (properties.getAuthorityPrefix() != null) {\n\t\t\t\tconverter.setAuthorityPrefix(properties.getAuthorityPrefix());\n\t\t\t}\n\t\t\tconverters.add(converter);\n\t\t}\n\t\treturn (converters.size() == 1) ? converters.get(0) : new DelegatingJwtGrantedAuthoritiesConverter(converters);\n\t}\n\n\tprivate void checkMutualExclusivity(OAuth2ResourceServerProperties.Jwt properties) {\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions\",\n\t\t\t\t\tproperties.getAuthoritiesClaimExpressions());\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name\",\n\t\t\t\t\tproperties.getAuthoritiesClaimName());\n\t\t}, (value) -> !nullOrEmptyList(value));\n\t\tMutuallyExclusiveConfigurationPropertiesException.throwIfMultipleMatchingValuesIn((entries) -> {\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions\",\n\t\t\t\t\tproperties.getAuthoritiesClaimExpressions());\n\t\t\tentries.put(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter\",\n\t\t\t\t\tproperties.getAuthoritiesClaimDelimiter());\n\t\t}, (value) -> !nullOrEmptyList(value));\n\t}\n\n\tprivate boolean nullOrEmptyList(Object value) {\n\t\tif (value == null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (value instanceof List<?> list) ? list.isEmpty() : false;\n\t}\n\n\tstatic class PropertiesCondition extends AnyNestedCondition {\n\n\t\tPropertiesCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.security.oauth2.resourceserver.jwt.authority-prefix\")\n\t\tstatic class OnAuthorityPrefix {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.security.oauth2.resourceserver.jwt.principal-claim-name\")\n\t\tstatic class OnPrincipalClaimName {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name\")\n\t\tstatic class OnAuthoritiesClaimName {\n\n\t\t}\n\n\t\t@Conditional(OnAuthoritiesExpressionsCondition.class)\n\t\tstatic class OnAuthoritiesExpressions {\n\n\t\t}\n\n\t\tstatic class OnAuthoritiesExpressionsCondition extends OnPropertyListCondition {\n\n\t\t\tOnAuthoritiesExpressionsCondition() {\n\t\t\t\tsuper(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions\",\n\t\t\t\t\t\t() -> ConditionMessage.forCondition(\"Authorities claim expressions\"));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveJwtDecoderConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport java.io.IOException;\nimport java.security.KeyFactory;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.interfaces.RSAPublicKey;\nimport java.security.spec.InvalidKeySpecException;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnIssuerLocationJwtDecoder;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.ConditionalOnPublicKeyJwtDecoder;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.core.OAuth2TokenValidator;\nimport org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.JwtClaimNames;\nimport org.springframework.security.oauth2.jwt.JwtClaimValidator;\nimport org.springframework.security.oauth2.jwt.JwtIssuerValidator;\nimport org.springframework.security.oauth2.jwt.JwtValidators;\nimport org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder;\nimport org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.PublicKeyReactiveJwtDecoderBuilder;\nimport org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;\nimport org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * {@link Configuration @Configuration} for reactive JWT decoder beans.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author HaiTao Zhang\n * @author Anastasiia Losieva\n * @author Mushtaq Ahmed\n * @author Roman Golovin\n * @author Yan Kardziyaka\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(WebClient.class)\n@ConditionalOnMissingBean(ReactiveJwtDecoder.class)\nclass ReactiveJwtDecoderConfiguration {\n\n\tprivate final OAuth2ResourceServerProperties.Jwt properties;\n\n\tprivate final List<OAuth2TokenValidator<Jwt>> additionalValidators;\n\n\tprivate final ObjectProvider<JwkSetUriReactiveJwtDecoderBuilderCustomizer> jwkSetUriReactiveJwtDecoderBuilderCustomizers;\n\n\tReactiveJwtDecoderConfiguration(OAuth2ResourceServerProperties properties,\n\t\t\tObjectProvider<OAuth2TokenValidator<Jwt>> additionalValidators,\n\t\t\tObjectProvider<JwkSetUriReactiveJwtDecoderBuilderCustomizer> jwkSetUriReactiveJwtDecoderBuilderCustomizers) {\n\t\tthis.properties = properties.getJwt();\n\t\tthis.additionalValidators = additionalValidators.orderedStream().toList();\n\t\tthis.jwkSetUriReactiveJwtDecoderBuilderCustomizers = jwkSetUriReactiveJwtDecoderBuilderCustomizers;\n\t}\n\n\t@Bean\n\t@ConditionalOnPublicKeyJwtDecoder\n\tNimbusReactiveJwtDecoder reactiveJwtDecoderByPublicKeyValue() throws Exception {\n\t\tRSAPublicKey publicKey = getReadPublicKey();\n\t\tPublicKeyReactiveJwtDecoderBuilder builder = NimbusReactiveJwtDecoder.withPublicKey(publicKey);\n\t\tbuilder.signatureAlgorithm(exactlyOneAlgorithm());\n\t\tNimbusReactiveJwtDecoder decoder = builder.build();\n\t\tdecoder.setJwtValidator(getValidator());\n\t\treturn decoder;\n\t}\n\n\tprivate RSAPublicKey getReadPublicKey() throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {\n\t\tX509EncodedKeySpec spec = new X509EncodedKeySpec(decodeKeyProperty(this.properties.readPublicKey()));\n\t\treturn (RSAPublicKey) KeyFactory.getInstance(\"RSA\").generatePublic(spec);\n\t}\n\n\tprivate byte[] decodeKeyProperty(String value) {\n\t\treturn Base64.getMimeDecoder()\n\t\t\t.decode(value.replace(\"-----BEGIN PUBLIC KEY-----\", \"\").replace(\"-----END PUBLIC KEY-----\", \"\"));\n\t}\n\n\tprivate SignatureAlgorithm exactlyOneAlgorithm() {\n\t\tList<String> algorithms = this.properties.getJwsAlgorithms();\n\t\tAssert.state(algorithms != null && algorithms.size() == 1,\n\t\t\t\t() -> \"Creating a JWT decoder using a public key requires exactly one JWS algorithm but \"\n\t\t\t\t\t\t+ algorithms.size() + \" were configured\");\n\t\tSignatureAlgorithm algorithm = SignatureAlgorithm.from(algorithms.get(0));\n\t\tif (algorithm == null) {\n\t\t\tthrow new InvalidConfigurationPropertyValueException(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms\", algorithms.get(0), \"Unknown algorithm\");\n\t\t}\n\t\treturn algorithm;\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\")\n\tReactiveJwtDecoder reactiveJwtDecoderByJwkKeySetUri() {\n\t\tString jwkSetUri = this.properties.getJwkSetUri();\n\t\tAssert.notNull(jwkSetUri, \"No JWK Set URI specified\");\n\t\tJwkSetUriReactiveJwtDecoderBuilder builder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri);\n\t\tbuilder.jwsAlgorithms(this::jwsAlgorithms);\n\t\treturn buildJwkSetUriJwtDecoder(builder);\n\t}\n\n\tprivate void jwsAlgorithms(Set<SignatureAlgorithm> signatureAlgorithms) {\n\t\tthis.properties.getJwsAlgorithms().stream().map(SignatureAlgorithm::from).forEach(signatureAlgorithms::add);\n\t}\n\n\t@Bean\n\t@ConditionalOnIssuerLocationJwtDecoder\n\tSupplierReactiveJwtDecoder reactiveJwtDecoderByIssuerUri() {\n\t\treturn new SupplierReactiveJwtDecoder(this::supplyJwtDecoderByIssuerUri);\n\t}\n\n\tprivate ReactiveJwtDecoder supplyJwtDecoderByIssuerUri() {\n\t\tString issuerUri = this.properties.getIssuerUri();\n\t\tAssert.state(issuerUri != null, \"No JWT issuer URI propery specified\");\n\t\tJwkSetUriReactiveJwtDecoderBuilder builder = NimbusReactiveJwtDecoder.withIssuerLocation(issuerUri);\n\t\treturn buildJwkSetUriJwtDecoder(builder);\n\t}\n\n\tprivate ReactiveJwtDecoder buildJwkSetUriJwtDecoder(JwkSetUriReactiveJwtDecoderBuilder builder) {\n\t\tthis.jwkSetUriReactiveJwtDecoderBuilderCustomizers.orderedStream()\n\t\t\t.forEach((customizer) -> customizer.customize(builder));\n\t\tNimbusReactiveJwtDecoder decoder = builder.build();\n\t\tdecoder.setJwtValidator(getValidator());\n\t\treturn decoder;\n\t}\n\n\tprivate OAuth2TokenValidator<Jwt> getValidator() {\n\t\tList<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();\n\t\tif (this.properties.getIssuerUri() != null) {\n\t\t\tvalidators.add(new JwtIssuerValidator(this.properties.getIssuerUri()));\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.properties.getAudiences())) {\n\t\t\tvalidators.add(audValidator(this.properties.getAudiences()));\n\t\t}\n\t\tvalidators.addAll(this.additionalValidators);\n\t\treturn validators.isEmpty() ? JwtValidators.createDefault()\n\t\t\t\t: JwtValidators.createDefaultWithValidators(validators);\n\t}\n\n\tprivate JwtClaimValidator<List<String>> audValidator(List<String> audiences) {\n\t\treturn new JwtClaimValidator<>(JwtClaimNames.AUD, (claim) -> hasElementsInCommon(claim, audiences));\n\t}\n\n\tprivate <E> boolean hasElementsInCommon(@Nullable List<E> c1, List<E> c2) {\n\t\treturn c1 != null && !Collections.disjoint(c1, c2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.reactive.ReactiveManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Reactive OAuth2 resource server\n * support.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(before = { ReactiveManagementWebSecurityAutoConfiguration.class,\n\t\tReactiveWebSecurityAutoConfiguration.class, ReactiveUserDetailsServiceAutoConfiguration.class })\n@ConditionalOnClass({ Mono.class, BearerTokenAuthenticationToken.class })\n@EnableConfigurationProperties(OAuth2ResourceServerProperties.class)\n@Import({ ReactiveJwtDecoderConfiguration.class, ReactiveJwtConverterConfiguration.class,\n\t\tReactiveOpaqueTokenIntrospectionClientConfiguration.class })\npublic final class ReactiveOAuth2ResourceServerAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOpaqueTokenIntrospectionClientConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;\nimport org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector;\nimport org.springframework.util.Assert;\n\n/**\n * Configures an {@link ReactiveOpaqueTokenIntrospector} when a token introspection\n * endpoint is available.\n *\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnMissingBean(ReactiveOpaqueTokenIntrospector.class)\nclass ReactiveOpaqueTokenIntrospectionClientConfiguration {\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri\")\n\tSpringReactiveOpaqueTokenIntrospector reactiveOpaqueTokenIntrospector(OAuth2ResourceServerProperties properties,\n\t\t\tObjectProvider<SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer> customizers) {\n\t\tOAuth2ResourceServerProperties.Opaquetoken token = properties.getOpaquetoken();\n\t\tAssert.state(token.getClientId() != null,\n\t\t\t\t\"No 'spring.security.oauth2.resourceserver.opaquetoken.client-id' property specified\");\n\t\tAssert.state(token.getClientSecret() != null,\n\t\t\t\t\"No 'spring.security.oauth2.resourceserver.opaquetoken.client-secret' property specified\");\n\t\tSpringReactiveOpaqueTokenIntrospector.Builder builder = SpringReactiveOpaqueTokenIntrospector\n\t\t\t.withIntrospectionUri(token.getIntrospectionUri())\n\t\t\t.clientId(token.getClientId())\n\t\t\t.clientSecret(token.getClientSecret());\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector;\nimport org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector.Builder;\n\n/**\n * Callback interface for the customization of the {@link Builder\n * SpringReactiveOpaqueTokenIntrospector.Builder} used to create the auto-configured\n * {@link SpringReactiveOpaqueTokenIntrospector}.\n *\n * @author Vishnutheep B\n * @since 4.1.0\n */\n@FunctionalInterface\npublic interface SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the {@code builder} to customize\n\t */\n\tvoid customize(SpringReactiveOpaqueTokenIntrospector.Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Security's Reactive OAuth2 resource server.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/JwkSetUriJwtDecoderBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.servlet;\n\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder;\n\n/**\n * Callback interface for the customization of the {@link JwkSetUriJwtDecoderBuilder} used\n * to create the auto-configured {@link JwtDecoder} for a JWK set URI that has been\n * configured directly or obtained through an issuer URI.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n * {@link org.springframework.boot.security.oauth2.server.resource.autoconfigure.JwkSetUriJwtDecoderBuilderCustomizer}\n */\n@FunctionalInterface\n@Deprecated(since = \"4.1.0\", forRemoval = true)\npublic interface JwkSetUriJwtDecoderBuilderCustomizer extends\n\t\torg.springframework.boot.security.oauth2.server.resource.autoconfigure.JwkSetUriJwtDecoderBuilderCustomizer {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Spring Security's OAuth2 resource server.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/OAuth2ResourceServerWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OAuth2 resource server servlet\n * based web security.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(before = { ManagementWebSecurityAutoConfiguration.class, SecurityAutoConfiguration.class,\n\t\tUserDetailsServiceAutoConfiguration.class }, after = OAuth2ResourceServerAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnDefaultWebSecurity\npublic final class OAuth2ResourceServerWebSecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(JwtDecoder.class)\n\tSecurityFilterChain jwtSecurityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\thttp.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()));\n\t\treturn http.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(OpaqueTokenIntrospector.class)\n\tSecurityFilterChain opaqueTokenSecurityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\thttp.oauth2ResourceServer((resourceServer) -> resourceServer.opaqueToken(withDefaults()));\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for OAuth2 resource server web security.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/reactive/ReactiveOAuth2ResourceServerWebSecurityAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web.reactive;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.reactive.ReactiveManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive.ReactiveOAuth2ResourceServerAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec.JwtSpec;\nimport org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;\nimport org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for OAuth2 resource server reactive\n * based web security.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @since 4.1.0\n */\n@AutoConfiguration(\n\t\tbefore = { ReactiveManagementWebSecurityAutoConfiguration.class, ReactiveWebSecurityAutoConfiguration.class,\n\t\t\t\tReactiveUserDetailsServiceAutoConfiguration.class },\n\t\tafter = ReactiveOAuth2ResourceServerAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnDefaultWebSecurity\n@ConditionalOnClass({ EnableWebFluxSecurity.class })\npublic final class ReactiveOAuth2ResourceServerWebSecurityAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(ReactiveJwtDecoder.class)\n\tSecurityWebFilterChain reactiveJwtSecurityFilterChain(ServerHttpSecurity http,\n\t\t\tReactiveJwtDecoder reactiveJwtDecoder) {\n\t\tCustomizer<JwtSpec> jwtCustomizer = (jwt) -> jwt.jwtDecoder(reactiveJwtDecoder);\n\t\thttp.authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated());\n\t\thttp.oauth2ResourceServer((server) -> server.jwt(jwtCustomizer));\n\t\treturn http.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(ReactiveOpaqueTokenIntrospector.class)\n\tSecurityWebFilterChain reactiveOpaqueTokenSecurityWebFilterChain(ServerHttpSecurity http) {\n\t\thttp.authorizeExchange((exchanges) -> exchanges.anyExchange().authenticated());\n\t\thttp.oauth2ResourceServer((resourceServer) -> resourceServer.opaqueToken(withDefaults()));\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for OAuth2 resource server reactive web security.\n */\n@NullMarked\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n  \t{\n      \"name\": \"spring.security.oauth2.resourceserver.jwt.jws-algorithm\",\n      \"type\": \"java.lang.String\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.security.oauth2.resourceserver.jwt.jws-algorithms\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration\norg.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive.ReactiveOAuth2ResourceServerAutoConfiguration\norg.springframework.boot.security.oauth2.server.resource.autoconfigure.web.OAuth2ResourceServerWebSecurityAutoConfiguration\norg.springframework.boot.security.oauth2.server.resource.autoconfigure.web.reactive.ReactiveOAuth2ResourceServerWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.WebFluxTest.imports",
    "content": "org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive.ReactiveOAuth2ResourceServerAutoConfiguration\norg.springframework.boot.security.oauth2.server.resource.autoconfigure.web.reactive.ReactiveOAuth2ResourceServerWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest.imports",
    "content": "org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration\norg.springframework.boot.security.oauth2.server.resource.autoconfigure.web.OAuth2ResourceServerWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/main/resources/META-INF/spring/org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient.imports",
    "content": "org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration\norg.springframework.boot.security.oauth2.server.resource.autoconfigure.web.OAuth2ResourceServerWebSecurityAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/JwtConverterCustomizationsArgumentsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.time.Instant;\nimport java.util.UUID;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.Named;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.ArgumentsProvider;\nimport org.junit.jupiter.params.support.ParameterDeclarations;\n\nimport org.springframework.security.oauth2.jwt.Jwt;\n\n/**\n * {@link ArgumentsProvider Arguments provider} supplying different Spring Boot properties\n * to customize JWT converter behavior, JWT token for conversion, expected principal name\n * and expected authorities.\n *\n * @author Yan Kardziyaka\n */\npublic final class JwtConverterCustomizationsArgumentsProvider implements ArgumentsProvider {\n\n\t@Override\n\tpublic Stream<? extends Arguments> provideArguments(ParameterDeclarations parameterDeclarations,\n\t\t\tExtensionContext extensionContext) {\n\t\tString customPrefix = \"CUSTOM_AUTHORITY_PREFIX_\";\n\t\tString customDelimiter = \"[~,#:]\";\n\t\tString customAuthoritiesClaim = \"custom_authorities\";\n\t\tString customPrincipalClaim = \"custom_principal\";\n\t\tString jwkSetUriProperty = \"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\";\n\t\tString authorityPrefixProperty = \"spring.security.oauth2.resourceserver.jwt.authority-prefix=\" + customPrefix;\n\t\tString authoritiesDelimiterProperty = \"spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter=\"\n\t\t\t\t+ customDelimiter;\n\t\tString authoritiesClaimProperty = \"spring.security.oauth2.resourceserver.jwt.authorities-claim-name=\"\n\t\t\t\t+ customAuthoritiesClaim;\n\t\tString principalClaimProperty = \"spring.security.oauth2.resourceserver.jwt.principal-claim-name=\"\n\t\t\t\t+ customPrincipalClaim;\n\t\tString[] customPrefixProps = { jwkSetUriProperty, authorityPrefixProperty };\n\t\tString[] customDelimiterProps = { jwkSetUriProperty, authorityPrefixProperty, authoritiesDelimiterProperty };\n\t\tString[] customAuthoritiesClaimProps = { jwkSetUriProperty, authoritiesClaimProperty };\n\t\tString[] customPrincipalClaimProps = { jwkSetUriProperty, principalClaimProperty };\n\t\tString[] allJwtConverterProps = { jwkSetUriProperty, authorityPrefixProperty, authoritiesDelimiterProperty,\n\t\t\t\tauthoritiesClaimProperty, principalClaimProperty };\n\t\tString[] jwtScopes = { \"custom_scope0\", \"custom_scope1\" };\n\t\tString subjectValue = UUID.randomUUID().toString();\n\t\tString customPrincipalValue = UUID.randomUUID().toString();\n\t\tJwt.Builder jwtBuilder = Jwt.withTokenValue(\"token\")\n\t\t\t.header(\"alg\", \"none\")\n\t\t\t.expiresAt(Instant.MAX)\n\t\t\t.issuedAt(Instant.MIN)\n\t\t\t.issuer(\"https://issuer.example.org\")\n\t\t\t.jti(\"jti\")\n\t\t\t.notBefore(Instant.MIN)\n\t\t\t.subject(subjectValue)\n\t\t\t.claim(customPrincipalClaim, customPrincipalValue);\n\t\tJwt noAuthoritiesCustomizationsJwt = jwtBuilder.claim(\"scp\", jwtScopes[0] + \" \" + jwtScopes[1]).build();\n\t\tJwt customAuthoritiesDelimiterJwt = jwtBuilder.claim(\"scp\", jwtScopes[0] + \"~\" + jwtScopes[1]).build();\n\t\tJwt customAuthoritiesClaimJwt = jwtBuilder.claim(\"scp\", \"value\")\n\t\t\t.claim(customAuthoritiesClaim, jwtScopes[0] + \" \" + jwtScopes[1])\n\t\t\t.build();\n\t\tJwt customAuthoritiesClaimAndDelimiterJwt = jwtBuilder.claim(\"scp\", \"value\")\n\t\t\t.claim(customAuthoritiesClaim, jwtScopes[0] + \"~\" + jwtScopes[1])\n\t\t\t.build();\n\t\tString[] customPrefixAuthorities = { customPrefix + jwtScopes[0], customPrefix + jwtScopes[1] };\n\t\tString[] defaultPrefixAuthorities = { \"SCOPE_\" + jwtScopes[0], \"SCOPE_\" + jwtScopes[1] };\n\t\treturn Stream.of(\n\t\t\t\tArguments.of(Named.named(\"Custom prefix for GrantedAuthority\", customPrefixProps),\n\t\t\t\t\t\tnoAuthoritiesCustomizationsJwt, subjectValue, customPrefixAuthorities),\n\t\t\t\tArguments.of(Named.named(\"Custom delimiter for JWT scopes\", customDelimiterProps),\n\t\t\t\t\t\tcustomAuthoritiesDelimiterJwt, subjectValue, customPrefixAuthorities),\n\t\t\t\tArguments.of(Named.named(\"Custom JWT authority claim name\", customAuthoritiesClaimProps),\n\t\t\t\t\t\tcustomAuthoritiesClaimJwt, subjectValue, defaultPrefixAuthorities),\n\t\t\t\tArguments.of(Named.named(\"Custom JWT principal claim name\", customPrincipalClaimProps),\n\t\t\t\t\t\tnoAuthoritiesCustomizationsJwt, customPrincipalValue, defaultPrefixAuthorities),\n\t\t\t\tArguments.of(Named.named(\"All JWT converter customizations\", allJwtConverterProps),\n\t\t\t\t\t\tcustomAuthoritiesClaimAndDelimiterJwt, customPrincipalValue, customPrefixAuthorities));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/OAuth2ResourceServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.net.URI;\nimport java.net.URL;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport com.nimbusds.jose.JWSAlgorithm;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ArgumentsSource;\nimport org.mockito.InOrder;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.FactorGrantedAuthority;\nimport org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;\nimport org.springframework.security.oauth2.core.OAuth2TokenValidator;\nimport org.springframework.security.oauth2.jwt.JoseHeaderNames;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.JwtClaimValidator;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.jwt.JwtIssuerValidator;\nimport org.springframework.security.oauth2.jwt.JwtTypeValidator;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder;\nimport org.springframework.security.oauth2.jwt.SupplierJwtDecoder;\nimport org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;\nimport org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;\nimport org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OAuth2ResourceServerAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author HaiTao Zhang\n * @author Mushtaq Ahmed\n * @author Roman Golovin\n * @author Yan Kardziyaka\n */\nclass OAuth2ResourceServerAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))\n\t\t.withUserConfiguration(TestConfig.class);\n\n\tprivate @Nullable MockWebServer server;\n\n\tprivate static final String JWK_SET = \"{\\\"keys\\\":[{\\\"kty\\\":\\\"RSA\\\",\\\"e\\\":\\\"AQAB\\\",\\\"use\\\":\\\"sig\\\",\"\n\t\t\t+ \"\\\"kid\\\":\\\"one\\\",\\\"n\\\":\\\"oXJ8OyOv_eRnce4akdanR4KYRfnC2zLV4uYNQpcFn6oHL0dj7D6kxQmsXoYgJV8ZVDn71KGm\"\n\t\t\t+ \"uLvolxsDncc2UrhyMBY6DVQVgMSVYaPCTgW76iYEKGgzTEw5IBRQL9w3SRJWd3VJTZZQjkXef48Ocz06PGF3lhbz4t5UEZtd\"\n\t\t\t+ \"F4rIe7u-977QwHuh7yRPBQ3sII-cVoOUMgaXB9SHcGF2iZCtPzL_IffDUcfhLQteGebhW8A6eUHgpD5A1PQ-JCw_G7UOzZAj\"\n\t\t\t+ \"jDjtNM2eqm8j-Ms_gqnm4MiCZ4E-9pDN77CAAPVN7kuX6ejs9KBXpk01z48i9fORYk9u7rAkh1HuQw\\\"}]}\";\n\n\t@AfterEach\n\tvoid cleanup() throws Exception {\n\t\tif (this.server != null) {\n\t\t\tthis.server.shutdown();\n\t\t}\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServer() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tassertJwkSetUriJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t}\n\n\tprivate void assertJwkSetUriJwtDecoderBuilderCustomization(AssertableWebApplicationContext context) {\n\t\tJwkSetUriJwtDecoderBuilderCustomizer customizer = context.getBean(\"decoderBuilderCustomizer\",\n\t\t\t\tJwkSetUriJwtDecoderBuilderCustomizer.class);\n\t\tJwkSetUriJwtDecoderBuilderCustomizer anotherCustomizer = context.getBean(\"anotherDecoderBuilderCustomizer\",\n\t\t\t\tJwkSetUriJwtDecoderBuilderCustomizer.class);\n\t\tInOrder inOrder = inOrder(customizer, anotherCustomizer);\n\t\tinOrder.verify(customizer).customize(any());\n\t\tinOrder.verify(anotherCustomizer).customize(any());\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldMatchDefaultJwsAlgorithm() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tassertThat(jwtDecoder).extracting(\"jwtProcessor.jwsKeySelector.jwsAlgs\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.collection(JWSAlgorithm.class))\n\t\t\t\t\t.containsExactlyInAnyOrder(JWSAlgorithm.RS256);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerWithSingleJwsAlgorithm() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RS384\")\n\t\t\t.run((context) -> {\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tassertThat(jwtDecoder).extracting(\"jwtProcessor.jwsKeySelector.jwsAlgs\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.collection(JWSAlgorithm.class))\n\t\t\t\t\t.containsExactlyInAnyOrder(JWSAlgorithm.RS384);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerWithMultipleJwsAlgorithms() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RS256, RS384, RS512\")\n\t\t\t.run((context) -> {\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tassertThat(jwtDecoder).extracting(\"jwtProcessor.jwsKeySelector.jwsAlgs\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.collection(JWSAlgorithm.class))\n\t\t\t\t\t.containsExactlyInAnyOrder(JWSAlgorithm.RS256, JWSAlgorithm.RS384, JWSAlgorithm.RS512);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationUsingPublicKeyValueShouldConfigureResourceServerUsingSingleJwsAlgorithm() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RS384\")\n\t\t\t.run((context) -> {\n\t\t\t\tNimbusJwtDecoder nimbusJwtDecoder = context.getBean(NimbusJwtDecoder.class);\n\t\t\t\tassertThat(nimbusJwtDecoder).extracting(\"jwtProcessor.jwsKeySelector.expectedJWSAlg\")\n\t\t\t\t\t.isEqualTo(JWSAlgorithm.RS384);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationUsingPublicKeyValueWithMultipleJwsAlgorithmsShouldFail() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RSA256,RS384\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).hasRootCauseMessage(\n\t\t\t\t\t\t\"Creating a JWT decoder using a public key requires exactly one JWS algorithm but 2 were \"\n\t\t\t\t\t\t\t\t+ \"configured\");\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\"\n\t\t\t\t\t+ this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"jwtDecoderByIssuerUri\")).isTrue();\n\t\t\t\tSupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);\n\t\t\t\tSupplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"delegate\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tjwtDecoderSupplier.get();\n\t\t\t\tassertJwkSetUriJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t\t// The last request is to the JWK Set endpoint to look up the algorithm\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(2);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponsesWithErrors(cleanIssuerPath, 1);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\"\n\t\t\t\t\t+ this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"jwtDecoderByIssuerUri\")).isTrue();\n\t\t\t\tSupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);\n\t\t\t\tSupplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"delegate\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tjwtDecoderSupplier.get();\n\t\t\t\tassertJwkSetUriJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t\t// The last request is to the JWK Set endpoint to look up the algorithm\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(3);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponsesWithErrors(cleanIssuerPath, 2);\n\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\"\n\t\t\t\t\t+ this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"jwtDecoderByIssuerUri\")).isTrue();\n\t\t\t\tSupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);\n\t\t\t\tSupplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"delegate\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tjwtDecoderSupplier.get();\n\t\t\t\tassertJwkSetUriJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t\t// The last request is to the JWK Set endpoint to look up the algorithm\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(4);\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationShouldConfigureResourceServerUsingPublicKeyValue() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JwtDecoder.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldFailIfPublicKeyLocationDoesNotExist() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:does-not-exist\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasMessageContaining(\"class path resource [does-not-exist]\")\n\t\t\t\t.hasMessageContaining(\"Public key location does not exist\"));\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationShouldFailIfAlgorithmIsInvalid() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=NOT_VALID\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasMessageContaining(\"Unknown algorithm\")\n\t\t\t\t.hasRootCauseExactlyInstanceOf(InvalidConfigurationPropertyValueException.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenSetUriKeyLocationAndIssuerUriPresentShouldUseSetUri() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://issuer-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"jwtDecoderByJwkKeySetUri\")).isTrue();\n\t\t\t\tassertThat(context.containsBean(\"jwtDecoderByIssuerUri\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenKeyLocationAndIssuerUriPresentShouldUseIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\" + this.server.getHostName() + \":\"\n\t\t\t\t\t\t\t+ this.server.getPort(),\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"jwtDecoderByIssuerUri\")).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenJwkSetUriNullShouldNotFail() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid jwtDecoderByJwkSetUriIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JwtDecoder.class));\n\t}\n\n\t@Test\n\tvoid jwtDecoderByOidcIssuerUriIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JwtDecoder.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldBeConditionalOnResourceServerClass() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OAuth2ResourceServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationForJwtShouldBeConditionalOnJwtDecoderClass() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(JwtDecoder.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OAuth2ResourceServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid jwtSecurityFilterShouldBeConditionalOnSecurityFilterChainClass() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OAuth2ResourceServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid opaqueTokenSecurityFilterShouldBeConditionalOnSecurityFilterChainClass() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.withClassLoader(new FilteredClassLoader(SecurityFilterChain.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OAuth2ResourceServerAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenJwkSetUriAndIntrospectionUriAvailable() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OpaqueTokenIntrospector.class);\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenIntrospectionUriAvailableShouldConfigureIntrospectionClient() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(OpaqueTokenIntrospector.class);\n\t\t\t\tassertSpringOpaqueTokenIntrospectorBuilderCustomization(context);\n\t\t\t});\n\t}\n\n\tprivate void assertSpringOpaqueTokenIntrospectorBuilderCustomization(AssertableWebApplicationContext context) {\n\t\tSpringOpaqueTokenIntrospectorBuilderCustomizer customizer = context\n\t\t\t.getBean(\"opaqueTokenIntrospectorBuilderCustomizer\", SpringOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\tSpringOpaqueTokenIntrospectorBuilderCustomizer anotherCustomizer = context.getBean(\n\t\t\t\t\"anotherOpaqueTokenIntrospectorBuilderCustomizer\",\n\t\t\t\tSpringOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\tInOrder inOrder = inOrder(customizer, anotherCustomizer);\n\t\tinOrder.verify(customizer).customize(any());\n\t\tinOrder.verify(anotherCustomizer).customize(any());\n\t}\n\n\t@Test\n\tvoid opaqueTokenIntrospectorIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\")\n\t\t\t.withUserConfiguration(OpaqueTokenIntrospectorConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OpaqueTokenIntrospector.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenIntrospectionUriAvailableShouldBeConditionalOnClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class))\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(OpaqueTokenIntrospector.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingJwkSetUriAndIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\" + this.server.getHostName() + \":\"\n\t\t\t\t\t\t\t+ this.server.getPort() + \"/\" + path)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tvalidate(jwt().claim(\"iss\", issuer), jwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasAtLeastOneElementOfType(JwtIssuerValidator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotConfigureIssuerUriAndAudienceJwtValidatorIfPropertyNotConfigured() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tvalidate(jwt(), jwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasSize(3).noneSatisfy(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureAudienceAndIssuerJwtValidatorIfPropertyProvided() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri,\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tvalidate(\n\t\t\t\t\t\tjwt().claim(\"iss\", URI.create(issuerUri).toURL())\n\t\t\t\t\t\t\t.claim(\"aud\", List.of(\"https://test-audience.com\")),\n\t\t\t\t\t\tjwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasAtLeastOneElementOfType(JwtIssuerValidator.class)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri,\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tSupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);\n\t\t\t\tSupplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"delegate\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tJwtDecoder jwtDecoder = jwtDecoderSupplier.get();\n\t\t\t\tvalidate(\n\t\t\t\t\t\tjwt().claim(\"iss\", URI.create(issuerUri).toURL())\n\t\t\t\t\t\t\t.claim(\"aud\", List.of(\"https://test-audience.com\")),\n\t\t\t\t\t\tjwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasAtLeastOneElementOfType(JwtIssuerValidator.class)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureCustomValidators() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri)\n\t\t\t.withUserConfiguration(CustomJwtClaimValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tSupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);\n\t\t\t\tSupplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"delegate\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tJwtDecoder jwtDecoder = jwtDecoderSupplier.get();\n\t\t\t\tassertThat(context).hasBean(\"customJwtClaimValidator\");\n\t\t\t\tOAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context\n\t\t\t\t\t.getBean(\"customJwtClaimValidator\");\n\t\t\t\tvalidate(jwt().claim(\"iss\", URI.create(issuerUri).toURL()).claim(\"custom_claim\", \"custom_claim_value\"),\n\t\t\t\t\t\tjwtDecoder, (validators) -> assertThat(validators).contains(customValidator)\n\t\t\t\t\t\t\t.hasAtLeastOneElementOfType(JwtIssuerValidator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndPublicKey() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,http://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tvalidate(jwt().claim(\"aud\", List.of(\"https://test-audience.com\")), jwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).satisfiesOnlyOnce(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid audienceValidatorWhenAudienceInvalid() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri,\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tDelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils\n\t\t\t\t\t.getField(jwtDecoder, \"jwtValidator\");\n\t\t\t\tassertThat(jwtValidator).isNotNull();\n\t\t\t\tJwt jwt = jwt().claim(\"iss\", new URL(issuerUri))\n\t\t\t\t\t.claim(\"aud\", Collections.singletonList(\"https://other-audience.com\"))\n\t\t\t\t\t.build();\n\t\t\t\tassertThat(jwtValidator.validate(jwt).hasErrors()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid jwtSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class, TestSecurityFilterChainConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SecurityFilterChain.class));\n\t}\n\n\t@Test\n\tvoid opaqueTokenSecurityConfigurerBacksOffWhenSecurityFilterChainBeanIsPresent() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestSecurityFilterChainConfig.class)\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(SecurityFilterChain.class));\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@ArgumentsSource(JwtConverterCustomizationsArgumentsProvider.class)\n\tvoid autoConfigurationShouldConfigureResourceServerWithJwtConverterCustomizations(String[] properties, Jwt jwt,\n\t\t\tString expectedPrincipal, String[] expectedAuthorities) {\n\t\tthis.contextRunner.withPropertyValues(properties).run((context) -> {\n\t\t\tJwtAuthenticationConverter converter = context.getBean(JwtAuthenticationConverter.class);\n\t\t\tAbstractAuthenticationToken token = converter.convert(jwt);\n\t\t\tassertThat(token).isNotNull().extracting(AbstractAuthenticationToken::getName).isEqualTo(expectedPrincipal);\n\t\t\tassertThat(token.getAuthorities()\n\t\t\t\t.stream()\n\t\t\t\t.filter((authority) -> !(authority instanceof FactorGrantedAuthority)))\n\t\t\t\t.extracting(GrantedAuthority::getAuthority)\n\t\t\t\t.containsExactlyInAnyOrder(expectedAuthorities);\n\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureJwtConverterIfNoPropertiesAreSet() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(JwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfPrincipalClaimNameIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.principal-claim-name=dummy\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthorityPrefixIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authority-prefix=dummy\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthorityClaimsNameIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name=dummy\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthoritiesExpressionIsSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions=zero\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtAuthenticationConverter.class);\n\t\t\t\tJwtAuthenticationConverter converter = context.getBean(JwtAuthenticationConverter.class);\n\t\t\t\tassertThat(converter).extracting(\"jwtGrantedAuthoritiesConverter\")\n\t\t\t\t\t.isInstanceOf(ExpressionJwtGrantedAuthoritiesConverter.class)\n\t\t\t\t\t.extracting(\"authorityPrefix\")\n\t\t\t\t\t.isEqualTo(\"SCOPE_\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthoritiesExpressionsAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[1]=one\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtAuthenticationConverter.class);\n\t\t\t\tJwtAuthenticationConverter converter = context.getBean(JwtAuthenticationConverter.class);\n\t\t\t\tassertThat(converter)\n\t\t\t\t\t.extracting(\"jwtGrantedAuthoritiesConverter.authoritiesConverters\", InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.hasSize(2)\n\t\t\t\t\t.extracting(\"authorityPrefix\")\n\t\t\t\t\t.containsOnly(\"SCOPE_\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldApplyCustomAuthorityPrefixIfAuthoritiesExpressionsAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[1]=one\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authority-prefix=CUSTOM_\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(JwtAuthenticationConverter.class);\n\t\t\t\tJwtAuthenticationConverter converter = context.getBean(JwtAuthenticationConverter.class);\n\t\t\t\tassertThat(converter)\n\t\t\t\t\t.extracting(\"jwtGrantedAuthoritiesConverter.authoritiesConverters\", InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.hasSize(2)\n\t\t\t\t\t.extracting(\"authorityPrefix\")\n\t\t\t\t\t.containsOnly(\"CUSTOM_\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailIfBothAuthoritiesExpressionsAndAuthoritiesClaimDelimiterAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter=delimiter\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Test\n\tvoid shouldFailIfBothAuthoritiesExpressionsAndAuthoritiesClaimNameAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name=name\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Test\n\tvoid jwtAuthenticationConverterByJwtConfigIsConditionalOnMissingBean() {\n\t\tString propertiesPrincipalClaim = \"principal_from_properties\";\n\t\tString propertiesPrincipalValue = \"from_props\";\n\t\tString userConfigPrincipalValue = \"from_user_config\";\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.principal-claim-name=\" + propertiesPrincipalClaim)\n\t\t\t.withUserConfiguration(CustomJwtConverterConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJwtAuthenticationConverter converter = context.getBean(JwtAuthenticationConverter.class);\n\t\t\t\tJwt jwt = jwt().claim(propertiesPrincipalClaim, propertiesPrincipalValue)\n\t\t\t\t\t.claim(CustomJwtConverterConfig.PRINCIPAL_CLAIM, userConfigPrincipalValue)\n\t\t\t\t\t.build();\n\t\t\t\tAbstractAuthenticationToken token = converter.convert(jwt);\n\t\t\t\tassertThat(token).isNotNull()\n\t\t\t\t\t.extracting(AbstractAuthenticationToken::getName)\n\t\t\t\t\t.isEqualTo(userConfigPrincipalValue)\n\t\t\t\t\t.isNotEqualTo(propertiesPrincipalValue);\n\t\t\t\tassertThat(context).hasSingleBean(JwtDecoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customTypeValidatorCanReplaceDefaultWhenUsingIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri)\n\t\t\t.withUserConfiguration(CustomJwtTypeValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tSupplierJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierJwtDecoder.class);\n\t\t\t\tSupplier<JwtDecoder> jwtDecoderSupplier = (Supplier<JwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"delegate\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tJwtDecoder jwtDecoder = jwtDecoderSupplier.get();\n\t\t\t\tassertThat(context).hasBean(\"customJwtTypeValidator\");\n\t\t\t\tOAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context\n\t\t\t\t\t.getBean(\"customJwtTypeValidator\");\n\t\t\t\tvalidate(jwt().claim(\"iss\", URI.create(issuerUri).toURL()).header(JoseHeaderNames.TYP, \"custom-type\"),\n\t\t\t\t\t\tjwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).contains(customValidator)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(\n\t\t\t\t\t\t\t\t\t(validator) -> assertThat(validator).isInstanceOf(JwtTypeValidator.class)));\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customTypeValidatorCanReplaceDefaultWhenUsingJwkSetUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(CustomJwtTypeValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tJwtDecoder jwtDecoder = context.getBean(JwtDecoder.class);\n\t\t\t\tassertThat(context).hasBean(\"customJwtTypeValidator\");\n\t\t\t\tOAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context\n\t\t\t\t\t.getBean(\"customJwtTypeValidator\");\n\t\t\t\tvalidate(jwt().header(JoseHeaderNames.TYP, \"custom-type\"), jwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).contains(customValidator)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(\n\t\t\t\t\t\t\t\t\t(validator) -> assertThat(validator).isInstanceOf(JwtTypeValidator.class)));\n\t\t\t});\n\t}\n\n\tprivate String cleanIssuerPath(String issuer) {\n\t\tif (issuer.endsWith(\"/\")) {\n\t\t\treturn issuer.substring(0, issuer.length() - 1);\n\t\t}\n\t\treturn issuer;\n\t}\n\n\tprivate void setupMockResponse(String issuer) {\n\t\tMockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.OK.value())\n\t\t\t.setBody(new JsonMapper().writeValueAsString(getResponse(issuer)))\n\t\t\t.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);\n\t\tassertThat(this.server).isNotNull();\n\t\tthis.server.enqueue(mockResponse);\n\t\tthis.server.enqueue(\n\t\t\t\tnew MockResponse().setResponseCode(200).setHeader(\"Content-Type\", \"application/json\").setBody(JWK_SET));\n\t}\n\n\tprivate void setupMockResponsesWithErrors(String issuer, int errorResponseCount) {\n\t\tassertThat(this.server).isNotNull();\n\t\tfor (int i = 0; i < errorResponseCount; i++) {\n\t\t\tMockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());\n\t\t\tthis.server.enqueue(emptyResponse);\n\t\t}\n\t\tsetupMockResponse(issuer);\n\t}\n\n\tprivate Map<String, Object> getResponse(String issuer) {\n\t\tMap<String, Object> response = new HashMap<>();\n\t\tresponse.put(\"authorization_endpoint\", \"https://example.com/o/oauth2/v2/auth\");\n\t\tresponse.put(\"claims_supported\", Collections.emptyList());\n\t\tresponse.put(\"code_challenge_methods_supported\", Collections.emptyList());\n\t\tresponse.put(\"id_token_signing_alg_values_supported\", Collections.emptyList());\n\t\tresponse.put(\"issuer\", issuer);\n\t\tresponse.put(\"jwks_uri\", issuer + \"/.well-known/jwks.json\");\n\t\tresponse.put(\"response_types_supported\", Collections.emptyList());\n\t\tresponse.put(\"revocation_endpoint\", \"https://example.com/o/oauth2/revoke\");\n\t\tresponse.put(\"scopes_supported\", Collections.singletonList(\"openid\"));\n\t\tresponse.put(\"subject_types_supported\", Collections.singletonList(\"public\"));\n\t\tresponse.put(\"grant_types_supported\", Collections.singletonList(\"authorization_code\"));\n\t\tresponse.put(\"token_endpoint\", \"https://example.com/oauth2/v4/token\");\n\t\tresponse.put(\"token_endpoint_auth_methods_supported\", Collections.singletonList(\"client_secret_basic\"));\n\t\tresponse.put(\"userinfo_endpoint\", \"https://example.com/oauth2/v3/userinfo\");\n\t\treturn response;\n\t}\n\n\tstatic Jwt.Builder jwt() {\n\t\treturn Jwt.withTokenValue(\"token\")\n\t\t\t.header(\"alg\", \"none\")\n\t\t\t.expiresAt(Instant.MAX)\n\t\t\t.issuedAt(Instant.MIN)\n\t\t\t.issuer(\"https://issuer.example.org\")\n\t\t\t.jti(\"jti\")\n\t\t\t.notBefore(Instant.MIN)\n\t\t\t.subject(\"mock-test-subject\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void validate(Jwt.Builder builder, JwtDecoder jwtDecoder,\n\t\t\tThrowingConsumer<List<OAuth2TokenValidator<Jwt>>> validatorsConsumer) {\n\t\tDelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils\n\t\t\t.getField(jwtDecoder, \"jwtValidator\");\n\t\tassertThat(jwtValidator).isNotNull();\n\t\tassertThat(jwtValidator.validate(builder.build()).getErrors()).isEmpty();\n\t\tvalidatorsConsumer.accept(extractValidators(jwtValidator));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate List<OAuth2TokenValidator<Jwt>> extractValidators(DelegatingOAuth2TokenValidator<Jwt> delegatingValidator) {\n\t\tCollection<OAuth2TokenValidator<Jwt>> delegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils\n\t\t\t.getField(delegatingValidator, \"tokenValidators\");\n\t\tassertThat(delegates).isNotNull();\n\t\tList<OAuth2TokenValidator<Jwt>> extracted = new ArrayList<>();\n\t\tfor (OAuth2TokenValidator<Jwt> delegate : delegates) {\n\t\t\tif (delegate instanceof DelegatingOAuth2TokenValidator<Jwt> delegatingDelegate) {\n\t\t\t\textracted.addAll(extractValidators(delegatingDelegate));\n\t\t\t}\n\t\t\telse {\n\t\t\t\textracted.add(delegate);\n\t\t\t}\n\t\t}\n\t\treturn extracted;\n\t}\n\n\tprivate Consumer<OAuth2TokenValidator<Jwt>> audClaimValidator() {\n\t\treturn (validator) -> assertThat(validator).isInstanceOf(JwtClaimValidator.class)\n\t\t\t.extracting(\"claim\")\n\t\t\t.isEqualTo(\"aud\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tJwkSetUriJwtDecoderBuilderCustomizer decoderBuilderCustomizer() {\n\t\t\treturn mock(JwkSetUriJwtDecoderBuilderCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tJwkSetUriJwtDecoderBuilderCustomizer anotherDecoderBuilderCustomizer() {\n\t\t\treturn mock(JwkSetUriJwtDecoderBuilderCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSpringOpaqueTokenIntrospectorBuilderCustomizer opaqueTokenIntrospectorBuilderCustomizer() {\n\t\t\treturn mock(SpringOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tSpringOpaqueTokenIntrospectorBuilderCustomizer anotherOpaqueTokenIntrospectorBuilderCustomizer() {\n\t\t\treturn mock(SpringOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class JwtDecoderConfig {\n\n\t\t@Bean\n\t\tJwtDecoder decoder() {\n\t\t\treturn mock(JwtDecoder.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class OpaqueTokenIntrospectorConfig {\n\n\t\t@Bean\n\t\tOpaqueTokenIntrospector decoder() {\n\t\t\treturn mock(OpaqueTokenIntrospector.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSecurity\n\tstatic class TestSecurityFilterChainConfig {\n\n\t\t@Bean\n\t\tSecurityFilterChain testSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.securityMatcher(\"/**\");\n\t\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJwtClaimValidatorConfig {\n\n\t\t@Bean\n\t\tJwtClaimValidator<String> customJwtClaimValidator() {\n\t\t\treturn new JwtClaimValidator<>(\"custom_claim\", \"custom_claim_value\"::equals);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJwtTypeValidatorConfig {\n\n\t\t@Bean\n\t\tJwtTypeValidator customJwtTypeValidator() {\n\t\t\treturn new JwtTypeValidator(\"custom-type\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJwtConverterConfig {\n\n\t\tstatic String PRINCIPAL_CLAIM = \"principal_from_user_configuration\";\n\n\t\t@Bean\n\t\tJwtAuthenticationConverter customJwtAuthenticationConverter() {\n\t\t\tJwtAuthenticationConverter converter = new JwtAuthenticationConverter();\n\t\t\tconverter.setPrincipalClaimName(PRINCIPAL_CLAIM);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"public-key-location\", content = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\n\t\t\tUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\n\t\t\tHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\n\t\t\to2kQ+X5xK9cipRgEKwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\n\t\t\t\"\"\")\n\t@interface WithPublicKeyResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive;\n\nimport java.io.IOException;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.net.URI;\nimport java.net.URL;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport com.nimbusds.jose.JWSAlgorithm;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ArgumentsSource;\nimport org.mockito.InOrder;\nimport reactor.core.publisher.Mono;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.JwtConverterCustomizationsArgumentsProvider;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.authentication.AbstractAuthenticationToken;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;\nimport org.springframework.security.oauth2.core.OAuth2TokenValidator;\nimport org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;\nimport org.springframework.security.oauth2.jwt.JoseHeaderNames;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.security.oauth2.jwt.JwtClaimValidator;\nimport org.springframework.security.oauth2.jwt.JwtIssuerValidator;\nimport org.springframework.security.oauth2.jwt.JwtTypeValidator;\nimport org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;\nimport org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;\nimport org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder;\nimport org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;\nimport org.springframework.security.oauth2.server.resource.authentication.ExpressionJwtGrantedAuthoritiesConverter;\nimport org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverter;\nimport org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for {@link ReactiveOAuth2ResourceServerAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Artsiom Yudovin\n * @author HaiTao Zhang\n * @author Anastasiia Losieva\n * @author Mushtaq Ahmed\n * @author Roman Golovin\n * @author Yan Kardziyaka\n */\nclass ReactiveOAuth2ResourceServerAutoConfigurationTests {\n\n\tprivate static final Duration TIMEOUT = Duration.ofSeconds(5000000);\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveOAuth2ResourceServerAutoConfiguration.class))\n\t\t.withUserConfiguration(TestConfig.class);\n\n\tprivate @Nullable MockWebServer server;\n\n\tprivate static final String JWK_SET = \"{\\\"keys\\\":[{\\\"kty\\\":\\\"RSA\\\",\\\"e\\\":\\\"AQAB\\\",\\\"use\\\":\\\"sig\\\",\"\n\t\t\t+ \"\\\"kid\\\":\\\"one\\\",\\\"n\\\":\\\"oXJ8OyOv_eRnce4akdanR4KYRfnC2zLV4uYNQpcFn6oHL0dj7D6kxQmsXoYgJV8ZVDn71KGm\"\n\t\t\t+ \"uLvolxsDncc2UrhyMBY6DVQVgMSVYaPCTgW76iYEKGgzTEw5IBRQL9w3SRJWd3VJTZZQjkXef48Ocz06PGF3lhbz4t5UEZtd\"\n\t\t\t+ \"F4rIe7u-977QwHuh7yRPBQ3sII-cVoOUMgaXB9SHcGF2iZCtPzL_IffDUcfhLQteGebhW8A6eUHgpD5A1PQ-JCw_G7UOzZAj\"\n\t\t\t+ \"jDjtNM2eqm8j-Ms_gqnm4MiCZ4E-9pDN77CAAPVN7kuX6ejs9KBXpk01z48i9fORYk9u7rAkh1HuQw\\\"}]}\";\n\n\t@AfterEach\n\tvoid cleanup() throws Exception {\n\t\tif (this.server != null) {\n\t\t\tthis.server.shutdown();\n\t\t}\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServer() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationUsingJwkSetUriShouldConfigureResourceServerUsingSingleJwsAlgorithm() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RS512\")\n\t\t\t.run((context) -> {\n\t\t\t\tNimbusReactiveJwtDecoder nimbusReactiveJwtDecoder = context.getBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(nimbusReactiveJwtDecoder).extracting(\"jwtProcessor.arg$1.signatureAlgorithms\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.collection(SignatureAlgorithm.class))\n\t\t\t\t\t.containsExactlyInAnyOrder(SignatureAlgorithm.RS512);\n\t\t\t\tassertJwkSetUriReactiveJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t}\n\n\tprivate void assertJwkSetUriReactiveJwtDecoderBuilderCustomization(\n\t\t\tAssertableReactiveWebApplicationContext context) {\n\t\tJwkSetUriReactiveJwtDecoderBuilderCustomizer customizer = context.getBean(\"decoderBuilderCustomizer\",\n\t\t\t\tJwkSetUriReactiveJwtDecoderBuilderCustomizer.class);\n\t\tJwkSetUriReactiveJwtDecoderBuilderCustomizer anotherCustomizer = context\n\t\t\t.getBean(\"anotherDecoderBuilderCustomizer\", JwkSetUriReactiveJwtDecoderBuilderCustomizer.class);\n\t\tInOrder inOrder = inOrder(customizer, anotherCustomizer);\n\t\tinOrder.verify(customizer).customize(any());\n\t\tinOrder.verify(anotherCustomizer).customize(any());\n\t}\n\n\t@Test\n\tvoid autoConfigurationUsingJwkSetUriShouldConfigureResourceServerUsingMultipleJwsAlgorithms() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RS256, RS384, RS512\")\n\t\t\t.run((context) -> {\n\t\t\t\tNimbusReactiveJwtDecoder nimbusReactiveJwtDecoder = context.getBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(nimbusReactiveJwtDecoder).extracting(\"jwtProcessor.arg$1.signatureAlgorithms\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.collection(SignatureAlgorithm.class))\n\t\t\t\t\t.containsExactlyInAnyOrder(SignatureAlgorithm.RS256, SignatureAlgorithm.RS384,\n\t\t\t\t\t\t\tSignatureAlgorithm.RS512);\n\t\t\t\tassertJwkSetUriReactiveJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationUsingPublicKeyValueShouldConfigureResourceServerUsingSingleJwsAlgorithm() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RS384\")\n\t\t\t.run((context) -> {\n\t\t\t\tNimbusReactiveJwtDecoder nimbusReactiveJwtDecoder = context.getBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(nimbusReactiveJwtDecoder).extracting(\"jwtProcessor.arg$1.jwsKeySelector.expectedJWSAlg\")\n\t\t\t\t\t.isEqualTo(JWSAlgorithm.RS384);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationUsingPublicKeyValueWithMultipleJwsAlgorithmsShouldFail() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jws-algorithms=RSA256,RS384\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure()).hasRootCauseMessage(\n\t\t\t\t\t\t\"Creating a JWT decoder using a public key requires exactly one JWS algorithm but 2 were \"\n\t\t\t\t\t\t\t\t+ \"configured\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingOidcIssuerUri() throws IOException {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\"\n\t\t\t\t\t+ this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"reactiveJwtDecoderByIssuerUri\")).isTrue();\n\t\t\t\t// Trigger calls to the issuer by decoding a token\n\t\t\t\tdecodeJwt(context);\n\t\t\t\tassertJwkSetUriReactiveJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t\t// The last request is to the JWK Set endpoint to look up the algorithm\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(2);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void decodeJwt(AssertableReactiveWebApplicationContext context) {\n\t\tSupplierReactiveJwtDecoder supplierReactiveJwtDecoder = context.getBean(SupplierReactiveJwtDecoder.class);\n\t\tMono<ReactiveJwtDecoder> reactiveJwtDecoderSupplier = (Mono<ReactiveJwtDecoder>) ReflectionTestUtils\n\t\t\t.getField(supplierReactiveJwtDecoder, \"jwtDecoderMono\");\n\t\tassertThat(reactiveJwtDecoderSupplier).isNotNull();\n\t\ttry {\n\t\t\treactiveJwtDecoderSupplier.flatMap((decoder) -> decoder.decode(\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.\"\n\t\t\t\t\t+ \"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.\"\n\t\t\t\t\t+ \"NHVaYe26MbtOYhSKkoKYdFVomg4i8ZJd8_-RU8VNbftc4TSMb4bXP3l3YlNWACwyXPGffz5aXHc6lty1Y2t4SWRqGteragsVdZufDn5BlnJl9pdR_kdVFUsra2rWKEofkZeIC4yWytE58sMIihvo9H1ScmmVwBcQP6XETqYd0aSHp1gOa9RdUPDvoXQ5oqygTqVtxaDr6wUFKrKItgBMzWIdNZ6y7O9E0DhEPTbE9rfBo6KTFsHAZnMg4k68CDp2woYIaXbmYTWcvbzIuHO7_37GT79XdIwkm95QJ7hYC9RiwrV7mesbY4PAahERJawntho0my942XheVLmGwLMBkQ\"))\n\t\t\t\t.block(TIMEOUT);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// This fails, but it's enough to check that the expected HTTP calls\n\t\t\t// are made\n\t\t}\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingOidcRfc8414IssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponsesWithErrors(cleanIssuerPath, 1);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\"\n\t\t\t\t\t+ this.server.getHostName() + \":\" + this.server.getPort())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"reactiveJwtDecoderByIssuerUri\")).isTrue();\n\t\t\t\t// Trigger calls to the issuer by decoding a token\n\t\t\t\tdecodeJwt(context);\n\t\t\t\t// assertJwkSetUriReactiveJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t\t// The last request is to the JWK Set endpoint to look up the algorithm\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(3);\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingOAuthIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponsesWithErrors(cleanIssuerPath, 2);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\"\n\t\t\t\t\t+ this.server.getHostName() + \":\" + this.server.getPort())\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"reactiveJwtDecoderByIssuerUri\")).isTrue();\n\t\t\t\t// Trigger calls to the issuer by decoding a token\n\t\t\t\tdecodeJwt(context);\n\t\t\t\tassertJwkSetUriReactiveJwtDecoderBuilderCustomization(context);\n\t\t\t});\n\t\t// The last request is to the JWK Set endpoint to look up the algorithm\n\t\tassertThat(this.server.getRequestCount()).isEqualTo(4);\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationShouldConfigureResourceServerUsingPublicKeyValue() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldBackOffIfWebClientIsNotAvailable() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(WebClient.class))\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> assertThat(context).hasNotFailed()\n\t\t\t\t.doesNotHaveBean(NimbusReactiveJwtDecoder.class)\n\t\t\t\t.doesNotHaveBean(ReactiveJwtDecoder.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldFailIfPublicKeyLocationDoesNotExist() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:does-not-exist\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.hasMessageContaining(\"class path resource [does-not-exist]\")\n\t\t\t\t.hasMessageContaining(\"Public key location does not exist\"));\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenSetUriKeyLocationIssuerUriPresentShouldUseSetUri() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"reactiveJwtDecoderByJwkKeySetUri\")).isTrue();\n\t\t\t\tassertThat(context.containsBean(\"reactiveJwtDecoderByIssuerUri\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenKeyLocationAndIssuerUriPresentShouldUseIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString issuer = this.server.url(\"\").toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\" + this.server.getHostName() + \":\"\n\t\t\t\t\t\t\t+ this.server.getPort(),\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SupplierReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context.containsBean(\"reactiveJwtDecoderByIssuerUri\")).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenJwkSetUriNullShouldNotFail() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN));\n\t}\n\n\t@Test\n\tvoid jwtDecoderBeanIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtDecoder.class));\n\t}\n\n\t@Test\n\tvoid jwtDecoderByIssuerUriBeanIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=https://jwk-oidc-issuer-location.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtDecoder.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldBeConditionalOnBearerTokenAuthenticationTokenClass() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldBeConditionalOnReactiveJwtDecoderClass() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(JwtDecoderConfig.class)\n\t\t\t.withClassLoader(new FilteredClassLoader(ReactiveJwtDecoder.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN));\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenSecurityWebFilterChainConfigPresentShouldNotAddOne() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(SecurityWebFilterChainConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SecurityWebFilterChain.class);\n\t\t\t\tassertThat(context).hasBean(\"testSpringSecurityFilterChain\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenIntrospectionUriAvailableShouldConfigureIntrospectionClient() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveOpaqueTokenIntrospector.class);\n\t\t\t\tassertSpringReactiveOpaqueTokenIntrospectorBuilderCustomization(context);\n\t\t\t});\n\t}\n\n\tprivate void assertSpringReactiveOpaqueTokenIntrospectorBuilderCustomization(\n\t\t\tAssertableReactiveWebApplicationContext context) {\n\t\tSpringReactiveOpaqueTokenIntrospectorBuilderCustomizer customizer = context.getBean(\n\t\t\t\t\"reactiveOpaqueTokenIntrospectorBuilderCustomizer\",\n\t\t\t\tSpringReactiveOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\tSpringReactiveOpaqueTokenIntrospectorBuilderCustomizer anotherCustomizer = context.getBean(\n\t\t\t\t\"anotherReactiveOpaqueTokenIntrospectorBuilderCustomizer\",\n\t\t\t\tSpringReactiveOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\tInOrder inOrder = inOrder(customizer, anotherCustomizer);\n\t\tinOrder.verify(customizer).customize(any());\n\t\tinOrder.verify(anotherCustomizer).customize(any());\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenJwkSetUriAndIntrospectionUriAvailable() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveOpaqueTokenIntrospector.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveOpaqueTokenIntrospector.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid opaqueTokenIntrospectorIsConditionalOnMissingBean() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\")\n\t\t\t.withUserConfiguration(OpaqueTokenIntrospectorConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveOpaqueTokenIntrospector.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationForOpaqueTokenWhenSecurityWebFilterChainConfigPresentShouldNotAddOne() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.withUserConfiguration(SecurityWebFilterChainConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(SecurityWebFilterChain.class);\n\t\t\t\tassertThat(context).hasBean(\"testSpringSecurityFilterChain\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationWhenIntrospectionUriAvailableShouldBeConditionalOnClass() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class))\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://check-token.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveOpaqueTokenIntrospector.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureResourceServerUsingJwkSetUriAndIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=http://\" + this.server.getHostName() + \":\"\n\t\t\t\t\t\t\t+ this.server.getPort() + \"/\" + path)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tvalidate(jwt().claim(\"iss\", issuer), reactiveJwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasAtLeastOneElementOfType(JwtIssuerValidator.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldNotConfigureIssuerUriAndAudienceJwtValidatorIfPropertyNotConfigured() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tvalidate(jwt(), reactiveJwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasSize(3).noneSatisfy(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldConfigureIssuerAndAudienceJwtValidatorIfPropertyProvided() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri,\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tvalidate(\n\t\t\t\t\t\tjwt().claim(\"iss\", URI.create(issuerUri).toURL())\n\t\t\t\t\t\t\t.claim(\"aud\", List.of(\"https://test-audience.com\")),\n\t\t\t\t\t\treactiveJwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasAtLeastOneElementOfType(JwtIssuerValidator.class)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri,\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tSupplierReactiveJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierReactiveJwtDecoder.class);\n\t\t\t\tMono<ReactiveJwtDecoder> jwtDecoderSupplier = (Mono<ReactiveJwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"jwtDecoderMono\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tReactiveJwtDecoder jwtDecoder = jwtDecoderSupplier.block();\n\t\t\t\tassertThat(jwtDecoder).isNotNull();\n\t\t\t\tvalidate(\n\t\t\t\t\t\tjwt().claim(\"iss\", URI.create(issuerUri).toURL())\n\t\t\t\t\t\t\t.claim(\"aud\", List.of(\"https://test-audience.com\")),\n\t\t\t\t\t\tjwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).hasAtLeastOneElementOfType(JwtIssuerValidator.class)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPublicKeyResource\n\tvoid autoConfigurationShouldConfigureAudienceValidatorIfPropertyProvidedAndPublicKey() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.public-key-location=classpath:public-key-location\",\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tvalidate(jwt().claim(\"aud\", List.of(\"https://test-audience.com\")), jwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).satisfiesOnlyOnce(audClaimValidator()));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid autoConfigurationShouldConfigureCustomValidators() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri)\n\t\t\t.withUserConfiguration(CustomJwtClaimValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder reactiveJwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tOAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context\n\t\t\t\t\t.getBean(\"customJwtClaimValidator\");\n\t\t\t\tvalidate(jwt().claim(\"iss\", URI.create(issuerUri).toURL()).claim(\"custom_claim\", \"custom_claim_value\"),\n\t\t\t\t\t\treactiveJwtDecoder, (validators) -> assertThat(validators).contains(customValidator)\n\t\t\t\t\t\t\t.hasAtLeastOneElementOfType(JwtIssuerValidator.class));\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid audienceValidatorWhenAudienceInvalid() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri,\n\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.audiences=https://test-audience.com,https://test-audience1.com\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tDelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils\n\t\t\t\t\t.getField(jwtDecoder, \"jwtValidator\");\n\t\t\t\tassertThat(jwtValidator).isNotNull();\n\t\t\t\tJwt jwt = jwt().claim(\"iss\", new URL(issuerUri))\n\t\t\t\t\t.claim(\"aud\", Collections.singletonList(\"https://other-audience.com\"))\n\t\t\t\t\t.build();\n\t\t\t\tassertThat(jwtValidator.validate(jwt).hasErrors()).isTrue();\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid customValidatorWhenInvalid() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri)\n\t\t\t.withUserConfiguration(CustomJwtClaimValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t\tReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tDelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils\n\t\t\t\t\t.getField(jwtDecoder, \"jwtValidator\");\n\t\t\t\tassertThat(jwtValidator).isNotNull();\n\t\t\t\tJwt jwt = jwt().claim(\"iss\", new URL(issuerUri)).claim(\"custom_claim\", \"invalid_value\").build();\n\t\t\t\tassertThat(jwtValidator.validate(jwt).hasErrors()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureJwtConverterIfNoPropertiesAreSet() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveJwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfPrincipalClaimNameIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.principal-claim-name=dummy\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthorityPrefixIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authority-prefix=dummy\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthorityClaimsNameIsSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name=dummy\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthoritiesExpressionIsSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions=zero\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tReactiveJwtAuthenticationConverter converter = context\n\t\t\t\t\t.getBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tassertThat(converter).extracting(\"jwtGrantedAuthoritiesConverter.grantedAuthoritiesConverter\")\n\t\t\t\t\t.isInstanceOf(ExpressionJwtGrantedAuthoritiesConverter.class)\n\t\t\t\t\t.extracting(\"authorityPrefix\")\n\t\t\t\t\t.isEqualTo(\"SCOPE_\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureJwtConverterIfAuthoritiesExpressionsAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[1]=one\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tReactiveJwtAuthenticationConverter converter = context\n\t\t\t\t\t.getBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tassertThat(converter)\n\t\t\t\t\t.extracting(\"jwtGrantedAuthoritiesConverter.grantedAuthoritiesConverter.authoritiesConverters\",\n\t\t\t\t\t\t\tInstanceOfAssertFactories.LIST)\n\t\t\t\t\t.hasSize(2)\n\t\t\t\t\t.extracting(\"authorityPrefix\")\n\t\t\t\t\t.containsOnly(\"SCOPE_\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldApplyCustomAuthorityPrefixIfAuthoritiesExpressionsAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[1]=one\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authority-prefix=CUSTOM_\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tReactiveJwtAuthenticationConverter converter = context\n\t\t\t\t\t.getBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tassertThat(converter)\n\t\t\t\t\t.extracting(\"jwtGrantedAuthoritiesConverter.grantedAuthoritiesConverter.authoritiesConverters\",\n\t\t\t\t\t\t\tInstanceOfAssertFactories.LIST)\n\t\t\t\t\t.hasSize(2)\n\t\t\t\t\t.extracting(\"authorityPrefix\")\n\t\t\t\t\t.containsOnly(\"CUSTOM_\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailIfBothAuthoritiesExpressionsAndAuthoritiesClaimDelimiterAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-delimiter=delimiter\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@Test\n\tvoid shouldFailIfBothAuthoritiesExpressionsAndAuthoritiesClaimNameAreSet() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.authorities-claim-expressions[0]=zero\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.authorities-claim-name=name\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(MutuallyExclusiveConfigurationPropertiesException.class));\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@ArgumentsSource(JwtConverterCustomizationsArgumentsProvider.class)\n\tvoid autoConfigurationShouldConfigureResourceServerWithJwtConverterCustomizations(String[] properties, Jwt jwt,\n\t\t\tString expectedPrincipal, String[] expectedAuthorities) {\n\t\tthis.contextRunner.withPropertyValues(properties).run((context) -> {\n\t\t\tReactiveJwtAuthenticationConverter converter = context.getBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\tAbstractAuthenticationToken token = converter.convert(jwt).block();\n\t\t\tassertThat(token).isNotNull().extracting(AbstractAuthenticationToken::getName).isEqualTo(expectedPrincipal);\n\t\t\tassertThat(token.getAuthorities()).extracting(GrantedAuthority::getAuthority)\n\t\t\t\t.containsExactlyInAnyOrder(expectedAuthorities);\n\t\t\tassertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);\n\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid jwtAuthenticationConverterByJwtConfigIsConditionalOnMissingBean() {\n\t\tString propertiesPrincipalClaim = \"principal_from_properties\";\n\t\tString propertiesPrincipalValue = \"from_props\";\n\t\tString userConfigPrincipalValue = \"from_user_config\";\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.jwt.principal-claim-name=\" + propertiesPrincipalClaim)\n\t\t\t.withUserConfiguration(CustomJwtConverterConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveJwtAuthenticationConverter converter = context\n\t\t\t\t\t.getBean(ReactiveJwtAuthenticationConverter.class);\n\t\t\t\tJwt jwt = jwt().claim(propertiesPrincipalClaim, propertiesPrincipalValue)\n\t\t\t\t\t.claim(CustomJwtConverterConfig.PRINCIPAL_CLAIM, userConfigPrincipalValue)\n\t\t\t\t\t.build();\n\t\t\t\tAbstractAuthenticationToken token = converter.convert(jwt).block();\n\t\t\t\tassertThat(token).isNotNull()\n\t\t\t\t\t.extracting(AbstractAuthenticationToken::getName)\n\t\t\t\t\t.isEqualTo(userConfigPrincipalValue)\n\t\t\t\t\t.isNotEqualTo(propertiesPrincipalValue);\n\t\t\t\tassertThat(context).hasSingleBean(NimbusReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveJwtDecoder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customTypeValidatorCanReplaceDefaultWhenUsingIssuerUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tString issuerUri = \"http://\" + this.server.getHostName() + \":\" + this.server.getPort() + \"/\" + path;\n\t\tthis.contextRunner.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.issuer-uri=\" + issuerUri)\n\t\t\t.withUserConfiguration(CustomJwtTypeValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tSupplierReactiveJwtDecoder supplierJwtDecoderBean = context.getBean(SupplierReactiveJwtDecoder.class);\n\t\t\t\tMono<ReactiveJwtDecoder> jwtDecoderSupplier = (Mono<ReactiveJwtDecoder>) ReflectionTestUtils\n\t\t\t\t\t.getField(supplierJwtDecoderBean, \"jwtDecoderMono\");\n\t\t\t\tassertThat(jwtDecoderSupplier).isNotNull();\n\t\t\t\tReactiveJwtDecoder jwtDecoder = jwtDecoderSupplier.block();\n\t\t\t\tassertThat(jwtDecoder).isNotNull();\n\t\t\t\tassertThat(context).hasBean(\"customJwtTypeValidator\");\n\t\t\t\tOAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context\n\t\t\t\t\t.getBean(\"customJwtTypeValidator\");\n\t\t\t\tvalidate(jwt().claim(\"iss\", URI.create(issuerUri).toURL()).header(JoseHeaderNames.TYP, \"custom-type\"),\n\t\t\t\t\t\tjwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).contains(customValidator)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(\n\t\t\t\t\t\t\t\t\t(validator) -> assertThat(validator).isInstanceOf(JwtTypeValidator.class)));\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid customTypeValidatorCanReplaceDefaultWhenUsingJwkSetUri() throws Exception {\n\t\tthis.server = new MockWebServer();\n\t\tthis.server.start();\n\t\tString path = \"test\";\n\t\tString issuer = this.server.url(path).toString();\n\t\tString cleanIssuerPath = cleanIssuerPath(issuer);\n\t\tsetupMockResponse(cleanIssuerPath);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://jwk-set-uri.com\")\n\t\t\t.withUserConfiguration(CustomJwtTypeValidatorConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveJwtDecoder jwtDecoder = context.getBean(ReactiveJwtDecoder.class);\n\t\t\t\tassertThat(context).hasBean(\"customJwtTypeValidator\");\n\t\t\t\tOAuth2TokenValidator<Jwt> customValidator = (OAuth2TokenValidator<Jwt>) context\n\t\t\t\t\t.getBean(\"customJwtTypeValidator\");\n\t\t\t\tvalidate(jwt().header(JoseHeaderNames.TYP, \"custom-type\"), jwtDecoder,\n\t\t\t\t\t\t(validators) -> assertThat(validators).contains(customValidator)\n\t\t\t\t\t\t\t.satisfiesOnlyOnce(\n\t\t\t\t\t\t\t\t\t(validator) -> assertThat(validator).isInstanceOf(JwtTypeValidator.class)));\n\t\t\t});\n\t}\n\n\tprivate String cleanIssuerPath(String issuer) {\n\t\tif (issuer.endsWith(\"/\")) {\n\t\t\treturn issuer.substring(0, issuer.length() - 1);\n\t\t}\n\t\treturn issuer;\n\t}\n\n\tprivate void setupMockResponse(String issuer) {\n\t\tMockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.OK.value())\n\t\t\t.setBody(new JsonMapper().writeValueAsString(getResponse(issuer)))\n\t\t\t.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);\n\t\tassertThat(this.server).isNotNull();\n\t\tthis.server.enqueue(mockResponse);\n\t\tthis.server.enqueue(\n\t\t\t\tnew MockResponse().setResponseCode(200).setHeader(\"Content-Type\", \"application/json\").setBody(JWK_SET));\n\t}\n\n\tprivate void setupMockResponsesWithErrors(String issuer, int errorResponseCount) {\n\t\tassertThat(this.server).isNotNull();\n\t\tfor (int i = 0; i < errorResponseCount; i++) {\n\t\t\tMockResponse emptyResponse = new MockResponse().setResponseCode(HttpStatus.NOT_FOUND.value());\n\t\t\tthis.server.enqueue(emptyResponse);\n\t\t}\n\t\tsetupMockResponse(issuer);\n\t}\n\n\tprivate Map<String, Object> getResponse(String issuer) {\n\t\tMap<String, Object> response = new HashMap<>();\n\t\tresponse.put(\"authorization_endpoint\", \"https://example.com/o/oauth2/v2/auth\");\n\t\tresponse.put(\"claims_supported\", Collections.emptyList());\n\t\tresponse.put(\"code_challenge_methods_supported\", Collections.emptyList());\n\t\tresponse.put(\"id_token_signing_alg_values_supported\", Collections.emptyList());\n\t\tresponse.put(\"issuer\", issuer);\n\t\tresponse.put(\"jwks_uri\", issuer + \"/.well-known/jwks.json\");\n\t\tresponse.put(\"response_types_supported\", Collections.emptyList());\n\t\tresponse.put(\"revocation_endpoint\", \"https://example.com/o/oauth2/revoke\");\n\t\tresponse.put(\"scopes_supported\", Collections.singletonList(\"openid\"));\n\t\tresponse.put(\"subject_types_supported\", Collections.singletonList(\"public\"));\n\t\tresponse.put(\"grant_types_supported\", Collections.singletonList(\"authorization_code\"));\n\t\tresponse.put(\"token_endpoint\", \"https://example.com/oauth2/v4/token\");\n\t\tresponse.put(\"token_endpoint_auth_methods_supported\", Collections.singletonList(\"client_secret_basic\"));\n\t\tresponse.put(\"userinfo_endpoint\", \"https://example.com/oauth2/v3/userinfo\");\n\t\treturn response;\n\t}\n\n\tstatic Jwt.Builder jwt() {\n\t\treturn Jwt.withTokenValue(\"token\")\n\t\t\t.header(\"alg\", \"none\")\n\t\t\t.expiresAt(Instant.MAX)\n\t\t\t.issuedAt(Instant.MIN)\n\t\t\t.issuer(\"https://issuer.example.org\")\n\t\t\t.jti(\"jti\")\n\t\t\t.notBefore(Instant.MIN)\n\t\t\t.subject(\"mock-test-subject\");\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void validate(Jwt.Builder builder, ReactiveJwtDecoder jwtDecoder,\n\t\t\tThrowingConsumer<List<OAuth2TokenValidator<Jwt>>> validatorsConsumer) {\n\t\tDelegatingOAuth2TokenValidator<Jwt> jwtValidator = (DelegatingOAuth2TokenValidator<Jwt>) ReflectionTestUtils\n\t\t\t.getField(jwtDecoder, \"jwtValidator\");\n\t\tassertThat(jwtValidator).isNotNull();\n\t\tassertThat(jwtValidator.validate(builder.build()).getErrors()).isEmpty();\n\t\tvalidatorsConsumer.accept(extractValidators(jwtValidator));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate List<OAuth2TokenValidator<Jwt>> extractValidators(DelegatingOAuth2TokenValidator<Jwt> delegatingValidator) {\n\t\tCollection<OAuth2TokenValidator<Jwt>> delegates = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils\n\t\t\t.getField(delegatingValidator, \"tokenValidators\");\n\t\tassertThat(delegates).isNotNull();\n\t\tList<OAuth2TokenValidator<Jwt>> extracted = new ArrayList<>();\n\t\tfor (OAuth2TokenValidator<Jwt> delegate : delegates) {\n\t\t\tif (delegate instanceof DelegatingOAuth2TokenValidator<Jwt> delegatingDelegate) {\n\t\t\t\textracted.addAll(extractValidators(delegatingDelegate));\n\t\t\t}\n\t\t\telse {\n\t\t\t\textracted.add(delegate);\n\t\t\t}\n\t\t}\n\t\treturn extracted;\n\t}\n\n\tprivate Consumer<OAuth2TokenValidator<Jwt>> audClaimValidator() {\n\t\treturn (validator) -> assertThat(validator).isInstanceOf(JwtClaimValidator.class)\n\t\t\t.extracting(\"claim\")\n\t\t\t.isEqualTo(\"aud\");\n\t}\n\n\t@EnableWebFluxSecurity\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn mock(MapReactiveUserDetailsService.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tJwkSetUriReactiveJwtDecoderBuilderCustomizer decoderBuilderCustomizer() {\n\t\t\treturn mock(JwkSetUriReactiveJwtDecoderBuilderCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tJwkSetUriReactiveJwtDecoderBuilderCustomizer anotherDecoderBuilderCustomizer() {\n\t\t\treturn mock(JwkSetUriReactiveJwtDecoderBuilderCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tSpringReactiveOpaqueTokenIntrospectorBuilderCustomizer reactiveOpaqueTokenIntrospectorBuilderCustomizer() {\n\t\t\treturn mock(SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tSpringReactiveOpaqueTokenIntrospectorBuilderCustomizer anotherReactiveOpaqueTokenIntrospectorBuilderCustomizer() {\n\t\t\treturn mock(SpringReactiveOpaqueTokenIntrospectorBuilderCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class JwtDecoderConfig {\n\n\t\t@Bean\n\t\tReactiveJwtDecoder decoder() {\n\t\t\treturn mock(ReactiveJwtDecoder.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OpaqueTokenIntrospectorConfig {\n\n\t\t@Bean\n\t\tReactiveOpaqueTokenIntrospector decoder() {\n\t\t\treturn mock(ReactiveOpaqueTokenIntrospector.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecurityWebFilterChainConfig {\n\n\t\t@Bean\n\t\tSecurityWebFilterChain testSpringSecurityFilterChain(ServerHttpSecurity http) {\n\t\t\thttp.authorizeExchange((exchanges) -> {\n\t\t\t\texchanges.pathMatchers(\"/message/**\").hasRole(\"ADMIN\");\n\t\t\t\texchanges.anyExchange().authenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJwtClaimValidatorConfig {\n\n\t\t@Bean\n\t\tJwtClaimValidator<String> customJwtClaimValidator() {\n\t\t\treturn new JwtClaimValidator<>(\"custom_claim\", \"custom_claim_value\"::equals);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJwtConverterConfig {\n\n\t\tstatic String PRINCIPAL_CLAIM = \"principal_from_user_configuration\";\n\n\t\t@Bean\n\t\tReactiveJwtAuthenticationConverter customReactiveJwtAuthenticationConverter() {\n\t\t\tReactiveJwtAuthenticationConverter converter = new ReactiveJwtAuthenticationConverter();\n\t\t\tconverter.setPrincipalClaimName(PRINCIPAL_CLAIM);\n\t\t\treturn converter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJwtTypeValidatorConfig {\n\n\t\t@Bean\n\t\tJwtTypeValidator customJwtTypeValidator() {\n\t\t\treturn new JwtTypeValidator(\"custom-type\");\n\t\t}\n\n\t}\n\n\t@Target(ElementType.METHOD)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@WithResource(name = \"public-key-location\", content = \"\"\"\n\t\t\t-----BEGIN PUBLIC KEY-----\n\t\t\tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd\n\t\t\tUWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs\n\t\t\tHUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D\n\t\t\to2kQ+X5xK9cipRgEKwIDAQAB\n\t\t\t-----END PUBLIC KEY-----\n\t\t\t\"\"\")\n\t@interface WithPublicKeyResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/OAuth2ResourceServerWebSecurityAutoConfigurationMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for reactive OAuth2 resource server with\n * {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass OAuth2ResourceServerWebSecurityAutoConfigurationMvcIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid oauth2ResourceServerAutoConfigurationWasImported() {\n\t\tassertThat(this.context).has(importedAutoConfiguration(OAuth2ResourceServerAutoConfiguration.class));\n\t\tassertThat(this.context).has(importedAutoConfiguration(OAuth2ResourceServerWebSecurityAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/OAuth2ResourceServerWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web;\n\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.OAuth2ResourceServerAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.security.authentication.AuthenticationManagerResolver;\nimport org.springframework.security.authentication.AuthenticationProvider;\nimport org.springframework.security.authentication.ProviderManager;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;\nimport org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;\nimport org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Test for {@link OAuth2ResourceServerWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass OAuth2ResourceServerWebSecurityAutoConfigurationTests {\n\n\tprivate static final String JWK_SET_URI_PROPERTY = \"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://authserver\";\n\n\tprivate static final String MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN = \"managementSecurityFilterChain\";\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ManagementWebSecurityAutoConfiguration.class,\n\t\t\t\tOAuth2ResourceServerAutoConfiguration.class, OAuth2ResourceServerWebSecurityAutoConfiguration.class,\n\t\t\t\tSecurityAutoConfiguration.class, ServletWebSecurityAutoConfiguration.class,\n\t\t\t\tWebMvcAutoConfiguration.class));\n\n\t@Test\n\tvoid causesManagementWebSecurityAutoConfigurationToBackOff() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ManagementWebSecurityAutoConfiguration.class));\n\t\tthis.contextRunner.withPropertyValues(JWK_SET_URI_PROPERTY)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class)\n\t\t\t\t.doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN));\n\t}\n\n\t@Test\n\tvoid whenNoJwtDecoderDoesNotAddFilterChain() {\n\t\tthis.contextRunner.run((context) -> assertThat(getBearerTokenFilter(context)).isNull());\n\t}\n\n\t@Test\n\tvoid whenHasJwtDecoderAddsFilterChain() {\n\t\tthis.contextRunner.withPropertyValues(JWK_SET_URI_PROPERTY).run((context) -> {\n\t\t\tFilter bearerTokenFilter = getBearerTokenFilter(context);\n\t\t\tassertThat(bearerTokenFilter).isNotNull();\n\t\t\tassertThat(getAuthenticationProviders(bearerTokenFilter))\n\t\t\t\t.hasAtLeastOneElementOfType(JwtAuthenticationProvider.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenNoOpaqueTokenIntrospectorDoesNotAddFilterChain() {\n\t\tthis.contextRunner.run((context) -> assertThat(getBearerTokenFilter(context)).isNull());\n\t}\n\n\t@Test\n\tvoid whenHasOpaqueTokenIntrospectorAddsFilterChain() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://authserver\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=test\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=shh\")\n\t\t\t.run((context) -> {\n\t\t\t\tFilter bearerTokenFilter = getBearerTokenFilter(context);\n\t\t\t\tassertThat(bearerTokenFilter).isNotNull();\n\t\t\t\tassertThat(getAuthenticationProviders(bearerTokenFilter))\n\t\t\t\t\t.hasAtLeastOneElementOfType(OpaqueTokenAuthenticationProvider.class);\n\t\t\t});\n\t}\n\n\tprivate @Nullable Filter getBearerTokenFilter(ApplicationContext context) {\n\t\treturn getFilters(context).stream()\n\t\t\t.filter(BearerTokenAuthenticationFilter.class::isInstance)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprivate List<Filter> getFilters(ApplicationContext context) {\n\t\tFilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);\n\t\tList<SecurityFilterChain> filterChains = filterChain.getFilterChains();\n\t\treturn filterChains.get(0).getFilters();\n\t}\n\n\tprivate List<AuthenticationProvider> getAuthenticationProviders(Filter bearerTokenFilter) {\n\t\tAuthenticationManagerResolver<?> resolver = (AuthenticationManagerResolver<?>) ReflectionTestUtils\n\t\t\t.getField(bearerTokenFilter, \"authenticationManagerResolver\");\n\t\tassertThat(resolver).isNotNull();\n\t\tProviderManager providerManager = (ProviderManager) resolver.resolve(mock());\n\t\treturn providerManager.getProviders();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/reactive/ReactiveOAuth2ResourceServerWebSecurityAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web.reactive;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.security.autoconfigure.actuate.web.reactive.ReactiveManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive.ReactiveOAuth2ResourceServerAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.security.authentication.ReactiveAuthenticationManager;\nimport org.springframework.security.authentication.ReactiveAuthenticationManagerResolver;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;\nimport org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenReactiveAuthenticationManager;\nimport org.springframework.security.web.server.MatcherSecurityWebFilterChain;\nimport org.springframework.security.web.server.authentication.AuthenticationWebFilter;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.server.ServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveOAuth2ResourceServerWebSecurityAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass ReactiveOAuth2ResourceServerWebSecurityAutoConfigurationTests {\n\n\tprivate static final Duration TIMEOUT = Duration.ofSeconds(5000000);\n\n\tprivate static final String JWK_SET_URI_PROPERTY = \"spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://authserver\";\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveManagementWebSecurityAutoConfiguration.class,\n\t\t\t\tReactiveOAuth2ResourceServerAutoConfiguration.class,\n\t\t\t\tReactiveOAuth2ResourceServerWebSecurityAutoConfiguration.class,\n\t\t\t\tReactiveWebSecurityAutoConfiguration.class, WebFluxAutoConfiguration.class));\n\n\t@Test\n\tvoid causesReactiveManagementWebSecurityAutoConfigurationToBackOff() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveManagementWebSecurityAutoConfiguration.class));\n\t\tthis.contextRunner.withPropertyValues(JWK_SET_URI_PROPERTY)\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(ReactiveManagementWebSecurityAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid whenNoReactiveJwtDecoderDoesNotAddFilterChain() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tReactiveAuthenticationManager authenticationManager = getAuthenticationManager(context);\n\t\t\tassertThatExceptionOfType(UsernameNotFoundException.class)\n\t\t\t\t.isThrownBy(authenticationManager.authenticate(mock())::block);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasReactiveJwtDecoderAddsFilterChain() {\n\t\tthis.contextRunner.withPropertyValues(JWK_SET_URI_PROPERTY).run((context) -> {\n\t\t\tReactiveAuthenticationManager authenticationManager = getAuthenticationManager(context);\n\t\t\tassertThat(authenticationManager).isInstanceOf(JwtReactiveAuthenticationManager.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenNoReactiveOpaqueTokenIntrospectorDoesNotAddFilterChain() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tReactiveAuthenticationManager authenticationManager = getAuthenticationManager(context);\n\t\t\tassertThatExceptionOfType(UsernameNotFoundException.class)\n\t\t\t\t.isThrownBy(authenticationManager.authenticate(mock())::block);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasReactiveOpaqueTokenIntrospectorAddsFilterChain() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://authserver\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-id=test\",\n\t\t\t\t\t\"spring.security.oauth2.resourceserver.opaquetoken.client-secret=shh\")\n\t\t\t.run((context) -> {\n\t\t\t\tReactiveAuthenticationManager authenticationManager = getAuthenticationManager(context);\n\t\t\t\tassertThat(authenticationManager).isInstanceOf(OpaqueTokenReactiveAuthenticationManager.class);\n\t\t\t});\n\t}\n\n\tprivate ReactiveAuthenticationManager getAuthenticationManager(AssertableReactiveWebApplicationContext context) {\n\t\tAuthenticationWebFilter authenticationWebFilter = getAuthenticationWebFilter(context);\n\t\tassertThat(authenticationWebFilter).isNotNull();\n\t\treturn getAuthenticationManager(authenticationWebFilter);\n\t}\n\n\tprivate @Nullable AuthenticationWebFilter getAuthenticationWebFilter(ApplicationContext context) {\n\t\tMatcherSecurityWebFilterChain filterChain = context.getBean(MatcherSecurityWebFilterChain.class);\n\t\treturn (AuthenticationWebFilter) filterChain.getWebFilters()\n\t\t\t.toStream()\n\t\t\t.filter(AuthenticationWebFilter.class::isInstance)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate ReactiveAuthenticationManager getAuthenticationManager(AuthenticationWebFilter webFilter) {\n\t\tReactiveAuthenticationManagerResolver<ServerWebExchange> authenticationManagerResolver = (ReactiveAuthenticationManagerResolver<ServerWebExchange>) ReflectionTestUtils\n\t\t\t.getField(webFilter, \"authenticationManagerResolver\");\n\t\tassertThat(authenticationManagerResolver).isNotNull();\n\t\tReactiveAuthenticationManager authenticationManager = authenticationManagerResolver\n\t\t\t.resolve(mock(ServerWebExchange.class))\n\t\t\t.block(TIMEOUT);\n\t\tassertThat(authenticationManager).isNotNull();\n\t\treturn authenticationManager;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-oauth2-resource-server/src/test/java/org/springframework/boot/security/oauth2/server/resource/autoconfigure/web/reactive/ReactiveOAuth2ResourceServerWebSecurityAutoConfigurationWebFluxIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.oauth2.server.resource.autoconfigure.web.reactive;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.security.oauth2.server.resource.autoconfigure.reactive.ReactiveOAuth2ResourceServerAutoConfiguration;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for reactive OAuth2 resource server with\n * {@link WebFluxTest @WebFluxTest}.\n *\n * @author Andy Wilkinson\n */\n@WebFluxTest\nclass ReactiveOAuth2ResourceServerWebSecurityAutoConfigurationWebFluxIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid oauth2ResourceServerAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext)\n\t\t\t.has(importedAutoConfiguration(ReactiveOAuth2ResourceServerAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Security SAML2\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.security:spring-security-saml2-service-provider\")\n\n\timplementation(project(\":module:spring-boot-security\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n    testImplementation(project(\":module:spring-boot-actuator-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-health\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"tools.jackson.core:jackson-databind\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/java/org/springframework/boot/security/saml2/autoconfigure/RegistrationConfiguredCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.Registration;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\n\n/**\n * Condition that matches if any {@code spring.security.saml2.relyingparty.registration}\n * properties are defined.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n */\nclass RegistrationConfiguredCondition extends SpringBootCondition {\n\n\tprivate static final String PROPERTY = \"spring.security.saml2.relyingparty.registration\";\n\n\tprivate static final Bindable<Map<String, Registration>> STRING_REGISTRATION_MAP = Bindable.mapOf(String.class,\n\t\t\tRegistration.class);\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Relying Party Registration Condition\");\n\t\tMap<String, Registration> registrations = getRegistrations(context.getEnvironment());\n\t\tif (registrations.isEmpty()) {\n\t\t\treturn ConditionOutcome.noMatch(message.didNotFind(\"any registrations\").atAll());\n\t\t}\n\t\treturn ConditionOutcome.match(message.found(\"registration\", \"registrations\").items(registrations.keySet()));\n\t}\n\n\tprivate Map<String, Registration> getRegistrations(Environment environment) {\n\t\treturn Binder.get(environment).bind(PROPERTY, STRING_REGISTRATION_MAP).orElse(Collections.emptyMap());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/java/org/springframework/boot/security/saml2/autoconfigure/Saml2LoginConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ConditionalOnDefaultWebSecurity;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * {@link SecurityFilterChain} configuration for Spring Security's relying party SAML\n * support.\n *\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnDefaultWebSecurity\n@ConditionalOnBean(RelyingPartyRegistrationRepository.class)\nclass Saml2LoginConfiguration {\n\n\t@Bean\n\tSecurityFilterChain samlSecurityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\thttp.saml2Login(withDefaults());\n\t\thttp.saml2Logout(withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/java/org/springframework/boot/security/saml2/autoconfigure/Saml2RelyingPartyAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Security's SAML 2.0\n * authentication support.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration(before = { SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class })\n@ConditionalOnClass(RelyingPartyRegistrationRepository.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@Import({ Saml2RelyingPartyRegistrationConfiguration.class, Saml2LoginConfiguration.class })\n@EnableConfigurationProperties(Saml2RelyingPartyProperties.class)\npublic final class Saml2RelyingPartyAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/java/org/springframework/boot/security/saml2/autoconfigure/Saml2RelyingPartyProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\nimport org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;\n\n/**\n * SAML2 relying party properties.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.security.saml2.relyingparty\")\npublic class Saml2RelyingPartyProperties {\n\n\t/**\n\t * SAML2 relying party registrations.\n\t */\n\tprivate final Map<String, Registration> registration = new LinkedHashMap<>();\n\n\tpublic Map<String, Registration> getRegistration() {\n\t\treturn this.registration;\n\t}\n\n\t/**\n\t * Represents a SAML Relying Party.\n\t */\n\tpublic static class Registration {\n\n\t\t/**\n\t\t * Relying party's entity ID. The value may contain a number of placeholders. They\n\t\t * are \"baseUrl\", \"registrationId\", \"baseScheme\", \"baseHost\", and \"basePort\".\n\t\t */\n\t\tprivate String entityId = \"{baseUrl}/saml2/service-provider-metadata/{registrationId}\";\n\n\t\t/**\n\t\t * Assertion Consumer Service.\n\t\t */\n\t\tprivate final Acs acs = new Acs();\n\n\t\tprivate final Signing signing = new Signing();\n\n\t\tprivate final Decryption decryption = new Decryption();\n\n\t\tprivate final Singlelogout singlelogout = new Singlelogout();\n\n\t\t/**\n\t\t * Remote SAML Identity Provider.\n\t\t */\n\t\tprivate final AssertingParty assertingparty = new AssertingParty();\n\n\t\t/**\n\t\t * Name ID format for a relying party registration.\n\t\t */\n\t\tprivate @Nullable String nameIdFormat;\n\n\t\tpublic String getEntityId() {\n\t\t\treturn this.entityId;\n\t\t}\n\n\t\tpublic void setEntityId(String entityId) {\n\t\t\tthis.entityId = entityId;\n\t\t}\n\n\t\tpublic Acs getAcs() {\n\t\t\treturn this.acs;\n\t\t}\n\n\t\tpublic Signing getSigning() {\n\t\t\treturn this.signing;\n\t\t}\n\n\t\tpublic Decryption getDecryption() {\n\t\t\treturn this.decryption;\n\t\t}\n\n\t\tpublic Singlelogout getSinglelogout() {\n\t\t\treturn this.singlelogout;\n\t\t}\n\n\t\tpublic AssertingParty getAssertingparty() {\n\t\t\treturn this.assertingparty;\n\t\t}\n\n\t\tpublic @Nullable String getNameIdFormat() {\n\t\t\treturn this.nameIdFormat;\n\t\t}\n\n\t\tpublic void setNameIdFormat(@Nullable String nameIdFormat) {\n\t\t\tthis.nameIdFormat = nameIdFormat;\n\t\t}\n\n\t\tpublic static class Acs {\n\n\t\t\t/**\n\t\t\t * Assertion Consumer Service location template. Can generate its location\n\t\t\t * based on possible variables of \"baseUrl\", \"registrationId\", \"baseScheme\",\n\t\t\t * \"baseHost\", and \"basePort\".\n\t\t\t */\n\t\t\tprivate String location = \"{baseUrl}/login/saml2/sso/{registrationId}\";\n\n\t\t\t/**\n\t\t\t * Assertion Consumer Service binding.\n\t\t\t */\n\t\t\tprivate Saml2MessageBinding binding = Saml2MessageBinding.POST;\n\n\t\t\tpublic String getLocation() {\n\t\t\t\treturn this.location;\n\t\t\t}\n\n\t\t\tpublic void setLocation(String location) {\n\t\t\t\tthis.location = location;\n\t\t\t}\n\n\t\t\tpublic Saml2MessageBinding getBinding() {\n\t\t\t\treturn this.binding;\n\t\t\t}\n\n\t\t\tpublic void setBinding(Saml2MessageBinding binding) {\n\t\t\t\tthis.binding = binding;\n\t\t\t}\n\n\t\t}\n\n\t\tpublic static class Signing {\n\n\t\t\t/**\n\t\t\t * Credentials used for signing the SAML authentication request.\n\t\t\t */\n\t\t\tprivate List<Credential> credentials = new ArrayList<>();\n\n\t\t\tpublic List<Credential> getCredentials() {\n\t\t\t\treturn this.credentials;\n\t\t\t}\n\n\t\t\tpublic void setCredentials(List<Credential> credentials) {\n\t\t\t\tthis.credentials = credentials;\n\t\t\t}\n\n\t\t\tpublic static class Credential {\n\n\t\t\t\t/**\n\t\t\t\t * Private key used for signing.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Resource privateKeyLocation;\n\n\t\t\t\t/**\n\t\t\t\t * Relying Party X509Certificate shared with the identity provider.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Resource certificateLocation;\n\n\t\t\t\tpublic @Nullable Resource getPrivateKeyLocation() {\n\t\t\t\t\treturn this.privateKeyLocation;\n\t\t\t\t}\n\n\t\t\t\tpublic void setPrivateKeyLocation(@Nullable Resource privateKey) {\n\t\t\t\t\tthis.privateKeyLocation = privateKey;\n\t\t\t\t}\n\n\t\t\t\tpublic @Nullable Resource getCertificateLocation() {\n\t\t\t\t\treturn this.certificateLocation;\n\t\t\t\t}\n\n\t\t\t\tpublic void setCertificateLocation(@Nullable Resource certificate) {\n\t\t\t\t\tthis.certificateLocation = certificate;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tpublic static class Decryption {\n\n\t\t/**\n\t\t * Credentials used for decrypting the SAML authentication request.\n\t\t */\n\t\tprivate List<Credential> credentials = new ArrayList<>();\n\n\t\tpublic List<Credential> getCredentials() {\n\t\t\treturn this.credentials;\n\t\t}\n\n\t\tpublic void setCredentials(List<Credential> credentials) {\n\t\t\tthis.credentials = credentials;\n\t\t}\n\n\t\tpublic static class Credential {\n\n\t\t\t/**\n\t\t\t * Private key used for decrypting.\n\t\t\t */\n\t\t\tprivate @Nullable Resource privateKeyLocation;\n\n\t\t\t/**\n\t\t\t * Relying Party X509Certificate shared with the identity provider.\n\t\t\t */\n\t\t\tprivate @Nullable Resource certificateLocation;\n\n\t\t\tpublic @Nullable Resource getPrivateKeyLocation() {\n\t\t\t\treturn this.privateKeyLocation;\n\t\t\t}\n\n\t\t\tpublic void setPrivateKeyLocation(@Nullable Resource privateKey) {\n\t\t\t\tthis.privateKeyLocation = privateKey;\n\t\t\t}\n\n\t\t\tpublic @Nullable Resource getCertificateLocation() {\n\t\t\t\treturn this.certificateLocation;\n\t\t\t}\n\n\t\t\tpublic void setCertificateLocation(@Nullable Resource certificate) {\n\t\t\t\tthis.certificateLocation = certificate;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Represents a remote Identity Provider.\n\t */\n\tpublic static class AssertingParty {\n\n\t\t/**\n\t\t * Unique identifier for the identity provider.\n\t\t */\n\t\tprivate @Nullable String entityId;\n\n\t\t/**\n\t\t * URI to the metadata endpoint for discovery-based configuration.\n\t\t */\n\t\tprivate @Nullable String metadataUri;\n\n\t\tprivate final Singlesignon singlesignon = new Singlesignon();\n\n\t\tprivate final Verification verification = new Verification();\n\n\t\tprivate final Singlelogout singlelogout = new Singlelogout();\n\n\t\tpublic @Nullable String getEntityId() {\n\t\t\treturn this.entityId;\n\t\t}\n\n\t\tpublic void setEntityId(@Nullable String entityId) {\n\t\t\tthis.entityId = entityId;\n\t\t}\n\n\t\tpublic @Nullable String getMetadataUri() {\n\t\t\treturn this.metadataUri;\n\t\t}\n\n\t\tpublic void setMetadataUri(@Nullable String metadataUri) {\n\t\t\tthis.metadataUri = metadataUri;\n\t\t}\n\n\t\tpublic Singlesignon getSinglesignon() {\n\t\t\treturn this.singlesignon;\n\t\t}\n\n\t\tpublic Verification getVerification() {\n\t\t\treturn this.verification;\n\t\t}\n\n\t\tpublic Singlelogout getSinglelogout() {\n\t\t\treturn this.singlelogout;\n\t\t}\n\n\t\t/**\n\t\t * Single sign on details for an Identity Provider.\n\t\t */\n\t\tpublic static class Singlesignon {\n\n\t\t\t/**\n\t\t\t * Remote endpoint to send authentication requests to.\n\t\t\t */\n\t\t\tprivate @Nullable String url;\n\n\t\t\t/**\n\t\t\t * Whether to redirect or post authentication requests.\n\t\t\t */\n\t\t\tprivate @Nullable Saml2MessageBinding binding;\n\n\t\t\t/**\n\t\t\t * Whether to sign authentication requests.\n\t\t\t */\n\t\t\tprivate @Nullable Boolean signRequest;\n\n\t\t\tpublic @Nullable String getUrl() {\n\t\t\t\treturn this.url;\n\t\t\t}\n\n\t\t\tpublic void setUrl(@Nullable String url) {\n\t\t\t\tthis.url = url;\n\t\t\t}\n\n\t\t\tpublic @Nullable Saml2MessageBinding getBinding() {\n\t\t\t\treturn this.binding;\n\t\t\t}\n\n\t\t\tpublic void setBinding(@Nullable Saml2MessageBinding binding) {\n\t\t\t\tthis.binding = binding;\n\t\t\t}\n\n\t\t\tpublic @Nullable Boolean getSignRequest() {\n\t\t\t\treturn this.signRequest;\n\t\t\t}\n\n\t\t\tpublic void setSignRequest(@Nullable Boolean signRequest) {\n\t\t\t\tthis.signRequest = signRequest;\n\t\t\t}\n\n\t\t}\n\n\t\t/**\n\t\t * Verification details for an Identity Provider.\n\t\t */\n\t\tpublic static class Verification {\n\n\t\t\t/**\n\t\t\t * Credentials used for verification of incoming SAML messages.\n\t\t\t */\n\t\t\tprivate List<Credential> credentials = new ArrayList<>();\n\n\t\t\tpublic List<Credential> getCredentials() {\n\t\t\t\treturn this.credentials;\n\t\t\t}\n\n\t\t\tpublic void setCredentials(List<Credential> credentials) {\n\t\t\t\tthis.credentials = credentials;\n\t\t\t}\n\n\t\t\tpublic static class Credential {\n\n\t\t\t\t/**\n\t\t\t\t * Locations of the X.509 certificate used for verification of incoming\n\t\t\t\t * SAML messages.\n\t\t\t\t */\n\t\t\t\tprivate @Nullable Resource certificate;\n\n\t\t\t\tpublic @Nullable Resource getCertificateLocation() {\n\t\t\t\t\treturn this.certificate;\n\t\t\t\t}\n\n\t\t\t\tpublic void setCertificateLocation(@Nullable Resource certificate) {\n\t\t\t\t\tthis.certificate = certificate;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Single logout details.\n\t */\n\tpublic static class Singlelogout {\n\n\t\t/**\n\t\t * Location where SAML2 LogoutRequest gets sent to.\n\t\t */\n\t\tprivate @Nullable String url;\n\n\t\t/**\n\t\t * Location where SAML2 LogoutResponse gets sent to.\n\t\t */\n\t\tprivate @Nullable String responseUrl;\n\n\t\t/**\n\t\t * Whether to redirect or post logout requests.\n\t\t */\n\t\tprivate @Nullable Saml2MessageBinding binding;\n\n\t\tpublic @Nullable String getUrl() {\n\t\t\treturn this.url;\n\t\t}\n\n\t\tpublic void setUrl(@Nullable String url) {\n\t\t\tthis.url = url;\n\t\t}\n\n\t\tpublic @Nullable String getResponseUrl() {\n\t\t\treturn this.responseUrl;\n\t\t}\n\n\t\tpublic void setResponseUrl(@Nullable String responseUrl) {\n\t\t\tthis.responseUrl = responseUrl;\n\t\t}\n\n\t\tpublic @Nullable Saml2MessageBinding getBinding() {\n\t\t\treturn this.binding;\n\t\t}\n\n\t\tpublic void setBinding(@Nullable Saml2MessageBinding binding) {\n\t\t\tthis.binding = binding;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/java/org/springframework/boot/security/saml2/autoconfigure/Saml2RelyingPartyRegistrationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport java.io.InputStream;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.AssertingParty;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.AssertingParty.Verification;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.Decryption;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.Registration;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.Registration.Signing;\nimport org.springframework.boot.ssl.pem.PemContent;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.Resource;\nimport org.springframework.security.saml2.core.Saml2X509Credential;\nimport org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;\nimport org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata;\nimport org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations;\nimport org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link Configuration @Configuration} used to map {@link Saml2RelyingPartyProperties} to\n * relying party registrations in a {@link RelyingPartyRegistrationRepository}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Moritz Halbritter\n * @author Lasse Lindqvist\n * @author Lasse Wulff\n * @author Scott Frederick\n */\n@Configuration(proxyBeanMethods = false)\n@Conditional(RegistrationConfiguredCondition.class)\n@ConditionalOnMissingBean(RelyingPartyRegistrationRepository.class)\nclass Saml2RelyingPartyRegistrationConfiguration {\n\n\t@Bean\n\tRelyingPartyRegistrationRepository relyingPartyRegistrationRepository(Saml2RelyingPartyProperties properties) {\n\t\tList<RelyingPartyRegistration> registrations = properties.getRegistration()\n\t\t\t.entrySet()\n\t\t\t.stream()\n\t\t\t.map(this::asRegistration)\n\t\t\t.toList();\n\t\treturn new InMemoryRelyingPartyRegistrationRepository(registrations);\n\t}\n\n\tprivate RelyingPartyRegistration asRegistration(Map.Entry<String, Registration> entry) {\n\t\treturn asRegistration(entry.getKey(), entry.getValue());\n\t}\n\n\tprivate RelyingPartyRegistration asRegistration(String id, Registration properties) {\n\t\tboolean usingMetadata = StringUtils.hasText(properties.getAssertingparty().getMetadataUri());\n\t\tBuilder builder = (!usingMetadata) ? RelyingPartyRegistration.withRegistrationId(id)\n\t\t\t\t: createBuilderUsingMetadata(properties.getAssertingparty()).registrationId(id);\n\t\tbuilder.assertionConsumerServiceLocation(properties.getAcs().getLocation());\n\t\tbuilder.assertionConsumerServiceBinding(properties.getAcs().getBinding());\n\t\tbuilder.assertingPartyMetadata(mapAssertingParty(properties.getAssertingparty()));\n\t\tbuilder.signingX509Credentials((credentials) -> properties.getSigning()\n\t\t\t.getCredentials()\n\t\t\t.stream()\n\t\t\t.map(this::asSigningCredential)\n\t\t\t.forEach(credentials::add));\n\t\tbuilder.decryptionX509Credentials((credentials) -> properties.getDecryption()\n\t\t\t.getCredentials()\n\t\t\t.stream()\n\t\t\t.map(this::asDecryptionCredential)\n\t\t\t.forEach(credentials::add));\n\t\tbuilder.assertingPartyMetadata(\n\t\t\t\t(details) -> details.verificationX509Credentials((credentials) -> properties.getAssertingparty()\n\t\t\t\t\t.getVerification()\n\t\t\t\t\t.getCredentials()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.map(this::asVerificationCredential)\n\t\t\t\t\t.forEach(credentials::add)));\n\t\tbuilder.singleLogoutServiceLocation(properties.getSinglelogout().getUrl());\n\t\tbuilder.singleLogoutServiceResponseLocation(properties.getSinglelogout().getResponseUrl());\n\t\t@Nullable Saml2MessageBinding binding = properties.getSinglelogout().getBinding();\n\t\tif (binding != null) {\n\t\t\tbuilder.singleLogoutServiceBinding(binding);\n\t\t}\n\t\tbuilder.entityId(properties.getEntityId());\n\t\tbuilder.nameIdFormat(properties.getNameIdFormat());\n\t\tRelyingPartyRegistration registration = builder.build();\n\t\tboolean signRequest = registration.getAssertingPartyMetadata().getWantAuthnRequestsSigned();\n\t\tvalidateSigningCredentials(properties, signRequest);\n\t\treturn registration;\n\t}\n\n\tprivate RelyingPartyRegistration.Builder createBuilderUsingMetadata(AssertingParty properties) {\n\t\tString requiredEntityId = properties.getEntityId();\n\t\tString metadataUri = properties.getMetadataUri();\n\t\tif (metadataUri != null) {\n\t\t\tCollection<Builder> candidates = RelyingPartyRegistrations.collectionFromMetadataLocation(metadataUri);\n\t\t\tfor (RelyingPartyRegistration.Builder candidate : candidates) {\n\t\t\t\tif (requiredEntityId == null || requiredEntityId.equals(getEntityId(candidate))) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"No relying party with Entity ID '\" + requiredEntityId + \"' found\");\n\t}\n\n\tprivate Object getEntityId(RelyingPartyRegistration.Builder candidate) {\n\t\tString[] result = new String[1];\n\t\tcandidate.assertingPartyMetadata((builder) -> result[0] = builder.build().getEntityId());\n\t\treturn result[0];\n\t}\n\n\tprivate Consumer<AssertingPartyMetadata.Builder<?>> mapAssertingParty(AssertingParty assertingParty) {\n\t\treturn (details) -> {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(assertingParty::getEntityId).to(details::entityId);\n\t\t\tmap.from(assertingParty.getSinglesignon()::getBinding).to(details::singleSignOnServiceBinding);\n\t\t\tmap.from(assertingParty.getSinglesignon()::getUrl).to(details::singleSignOnServiceLocation);\n\t\t\tmap.from(assertingParty.getSinglesignon()::getSignRequest).to(details::wantAuthnRequestsSigned);\n\t\t\tmap.from(assertingParty.getSinglelogout()::getUrl).to(details::singleLogoutServiceLocation);\n\t\t\tmap.from(assertingParty.getSinglelogout()::getResponseUrl).to(details::singleLogoutServiceResponseLocation);\n\t\t\tmap.from(assertingParty.getSinglelogout()::getBinding).to(details::singleLogoutServiceBinding);\n\t\t};\n\t}\n\n\tprivate void validateSigningCredentials(Registration properties, boolean signRequest) {\n\t\tif (signRequest) {\n\t\t\tAssert.state(!properties.getSigning().getCredentials().isEmpty(),\n\t\t\t\t\t\"Signing credentials must not be empty when authentication requests require signing.\");\n\t\t}\n\t}\n\n\tprivate Saml2X509Credential asSigningCredential(Signing.Credential properties) {\n\t\tRSAPrivateKey privateKey = readPrivateKey(properties.getPrivateKeyLocation());\n\t\tX509Certificate certificate = readCertificate(properties.getCertificateLocation());\n\t\treturn new Saml2X509Credential(privateKey, certificate, Saml2X509CredentialType.SIGNING);\n\t}\n\n\tprivate Saml2X509Credential asDecryptionCredential(Decryption.Credential properties) {\n\t\tRSAPrivateKey privateKey = readPrivateKey(properties.getPrivateKeyLocation());\n\t\tX509Certificate certificate = readCertificate(properties.getCertificateLocation());\n\t\treturn new Saml2X509Credential(privateKey, certificate, Saml2X509CredentialType.DECRYPTION);\n\t}\n\n\tprivate Saml2X509Credential asVerificationCredential(Verification.Credential properties) {\n\t\tX509Certificate certificate = readCertificate(properties.getCertificateLocation());\n\t\treturn new Saml2X509Credential(certificate, Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION,\n\t\t\t\tSaml2X509Credential.Saml2X509CredentialType.VERIFICATION);\n\t}\n\n\tprivate RSAPrivateKey readPrivateKey(@Nullable Resource location) {\n\t\tAssert.state(location != null, \"No private key location specified\");\n\t\tAssert.state(location.exists(), () -> \"Private key location '\" + location + \"' does not exist\");\n\t\ttry (InputStream inputStream = location.getInputStream()) {\n\t\t\tPemContent pemContent = PemContent.load(inputStream);\n\t\t\tPrivateKey privateKey = pemContent.getPrivateKey();\n\t\t\tAssert.state(privateKey instanceof RSAPrivateKey,\n\t\t\t\t\t() -> \"PrivateKey in resource '\" + location + \"' must be an RSAPrivateKey\");\n\t\t\treturn (RSAPrivateKey) privateKey;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalArgumentException(ex);\n\t\t}\n\t}\n\n\tprivate X509Certificate readCertificate(@Nullable Resource location) {\n\t\tAssert.state(location != null, \"No certificate location specified\");\n\t\tAssert.state(location.exists(), () -> \"Certificate  location '\" + location + \"' does not exist\");\n\t\ttry (InputStream inputStream = location.getInputStream()) {\n\t\t\tPemContent pemContent = PemContent.load(inputStream);\n\t\t\tList<X509Certificate> certificates = pemContent.getCertificates();\n\t\t\treturn certificates.get(0);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalArgumentException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/java/org/springframework/boot/security/saml2/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Security's SAML 2.0.\n */\n@NullMarked\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest.imports",
    "content": "org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/java/org/springframework/boot/security/saml2/autoconfigure/Saml2RelyingPartyAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport java.io.InputStream;\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okio.Buffer;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.ManagementWebSecurityAutoConfiguration;\nimport org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;\nimport org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;\nimport org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter;\nimport org.springframework.security.saml2.provider.service.web.authentication.logout.Saml2LogoutRequestFilter;\nimport org.springframework.security.web.FilterChainProxy;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.filter.CompositeFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link Saml2RelyingPartyAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Moritz Halbritter\n * @author Lasse Lindqvist\n * @author Scott Frederick\n */\nclass Saml2RelyingPartyAutoConfigurationTests {\n\n\tprivate static final String PREFIX = \"spring.security.saml2.relyingparty.registration\";\n\n\tprivate static final String MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN = \"managementSecurityFilterChain\";\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(Saml2RelyingPartyAutoConfiguration.class,\n\t\t\t\tSecurityAutoConfiguration.class, ServletWebSecurityAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationShouldBeConditionalOnRelyingPartyRegistrationRepositoryClass() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValues())\n\t\t\t.withClassLoader(new FilteredClassLoader(\n\t\t\t\t\t\"org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RelyingPartyRegistrationRepository.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationShouldBeConditionalOnServletWebApplication() {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(Saml2RelyingPartyAutoConfiguration.class))\n\t\t\t.withPropertyValues(getPropertyValues())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RelyingPartyRegistrationRepository.class));\n\t}\n\n\t@Test\n\tvoid relyingPartyRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(RelyingPartyRegistrationRepository.class));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid relyingPartyRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValues()).run((context) -> {\n\t\t\tRelyingPartyRegistrationRepository repository = context.getBean(RelyingPartyRegistrationRepository.class);\n\t\t\tRelyingPartyRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\tassertThat(registration).isNotNull();\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleSignOnServiceLocation())\n\t\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php\");\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getEntityId())\n\t\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\");\n\t\t\tassertThat(registration.getAssertionConsumerServiceLocation())\n\t\t\t\t.isEqualTo(\"{baseUrl}/login/saml2/foo-entity-id\");\n\t\t\tassertThat(registration.getAssertionConsumerServiceBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleSignOnServiceBinding())\n\t\t\t\t.isEqualTo(Saml2MessageBinding.POST);\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getWantAuthnRequestsSigned()).isFalse();\n\t\t\tassertThat(registration.getSigningX509Credentials()).hasSize(1);\n\t\t\tassertThat(registration.getDecryptionX509Credentials()).hasSize(1);\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getVerificationX509Credentials()).isNotNull();\n\t\t\tassertThat(registration.getEntityId()).isEqualTo(\"{baseUrl}/saml2/foo-entity-id\");\n\t\t\tassertThat(registration.getSingleLogoutServiceLocation())\n\t\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SLOService.php\");\n\t\t\tassertThat(registration.getSingleLogoutServiceResponseLocation())\n\t\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml.cfapps.io/\");\n\t\t\tassertThat(registration.getSingleLogoutServiceBinding()).isEqualTo(Saml2MessageBinding.POST);\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleLogoutServiceLocation())\n\t\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SLOService.php\");\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleLogoutServiceResponseLocation())\n\t\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml.cfapps.io/\");\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleLogoutServiceBinding())\n\t\t\t\t.isEqualTo(Saml2MessageBinding.POST);\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid autoConfigurationWhenSignRequestsTrueAndNoSigningCredentialsShouldThrowException() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValuesWithoutSigningCredentials(true)).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context.getStartupFailure()).hasMessageContaining(\n\t\t\t\t\t\"Signing credentials must not be empty when authentication requests require signing.\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid autoConfigurationWhenSignRequestsFalseAndNoSigningCredentialsShouldNotThrowException() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValuesWithoutSigningCredentials(false))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"idp-metadata\")\n\tvoid autoconfigurationShouldQueryAssertingPartyMetadataWhenMetadataUrlIsPresent() throws Exception {\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.start();\n\t\t\tString metadataUrl = server.url(\"\").toString();\n\t\t\tsetupMockResponse(server, new ClassPathResource(\"idp-metadata\"));\n\t\t\tthis.contextRunner.withPropertyValues(PREFIX + \".foo.assertingparty.metadata-uri=\" + metadataUrl)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tassertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\t\tassertThat(server.getRequestCount()).isOne();\n\t\t\t\t});\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources(\"idp-metadata\")\n\tvoid autoconfigurationShouldUseBindingFromMetadataUrlIfPresent() throws Exception {\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.start();\n\t\t\tString metadataUrl = server.url(\"\").toString();\n\t\t\tsetupMockResponse(server, new ClassPathResource(\"idp-metadata\"));\n\t\t\tthis.contextRunner.withPropertyValues(PREFIX + \".foo.assertingparty.metadata-uri=\" + metadataUrl)\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tRelyingPartyRegistrationRepository repository = context\n\t\t\t\t\t\t.getBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\t\tRelyingPartyRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\t\t\tassertThat(registration).isNotNull();\n\t\t\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleSignOnServiceBinding())\n\t\t\t\t\t\t.isEqualTo(Saml2MessageBinding.POST);\n\t\t\t\t});\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources(\"idp-metadata\")\n\tvoid autoconfigurationWhenMetadataUrlAndPropertyPresentShouldUseBindingFromProperty() throws Exception {\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.start();\n\t\t\tString metadataUrl = server.url(\"\").toString();\n\t\t\tsetupMockResponse(server, new ClassPathResource(\"idp-metadata\"));\n\t\t\tthis.contextRunner\n\t\t\t\t.withPropertyValues(PREFIX + \".foo.assertingparty.metadata-uri=\" + metadataUrl,\n\t\t\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.binding=redirect\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tRelyingPartyRegistrationRepository repository = context\n\t\t\t\t\t\t.getBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\t\tRelyingPartyRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\t\t\tassertThat(registration).isNotNull();\n\t\t\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleSignOnServiceBinding())\n\t\t\t\t\t\t.isEqualTo(Saml2MessageBinding.REDIRECT);\n\t\t\t\t});\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid autoconfigurationWhenNoMetadataUrlOrPropertyPresentShouldUseRedirectBinding() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValuesWithoutSsoBinding()).run((context) -> {\n\t\t\tRelyingPartyRegistrationRepository repository = context.getBean(RelyingPartyRegistrationRepository.class);\n\t\t\tRelyingPartyRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\tassertThat(registration).isNotNull();\n\t\t\tassertThat(registration.getAssertingPartyMetadata().getSingleSignOnServiceBinding())\n\t\t\t\t.isEqualTo(Saml2MessageBinding.REDIRECT);\n\t\t});\n\t}\n\n\t@Test\n\tvoid relyingPartyRegistrationRepositoryShouldBeConditionalOnMissingBean() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValues())\n\t\t\t.withUserConfiguration(RegistrationRepositoryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\tassertThat(context).hasBean(\"testRegistrationRepository\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid samlLoginShouldBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValues())\n\t\t\t.run((context) -> assertThat(hasSecurityFilter(context, Saml2WebSsoAuthenticationFilter.class)).isTrue());\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"private-key-location\", \"certificate-location\" })\n\tvoid samlLoginShouldBackOffWhenASecurityFilterChainBeanIsPresent() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebMvcAutoConfiguration.class))\n\t\t\t.withUserConfiguration(TestSecurityFilterChainConfig.class)\n\t\t\t.withPropertyValues(getPropertyValues())\n\t\t\t.run((context) -> assertThat(hasSecurityFilter(context, Saml2WebSsoAuthenticationFilter.class)).isFalse());\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid samlLoginShouldShouldBeConditionalOnSecurityWebFilterClass() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(\n\t\t\t\t\tnew FilteredClassLoader(Thread.currentThread().getContextClassLoader(), SecurityFilterChain.class))\n\t\t\t.withPropertyValues(getPropertyValues())\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SecurityFilterChain.class));\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"certificate-location\", \"private-key-location\" })\n\tvoid samlLogoutShouldBeConfigured() {\n\t\tthis.contextRunner.withPropertyValues(getPropertyValues())\n\t\t\t.run((context) -> assertThat(hasSecurityFilter(context, Saml2LogoutRequestFilter.class)).isTrue());\n\t}\n\n\tprivate String[] getPropertyValuesWithoutSigningCredentials(boolean signRequests) {\n\t\treturn new String[] { PREFIX\n\t\t\t\t+ \".foo.assertingparty.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.binding=post\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.sign-request=\" + signRequests,\n\t\t\t\tPREFIX + \".foo.assertingparty.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.verification.credentials[0].certificate-location=classpath:certificate-location\" };\n\t}\n\n\t@Test\n\t@WithPackageResources(\"idp-metadata-with-multiple-providers\")\n\tvoid autoconfigurationWhenMultipleProvidersAndNoSpecifiedEntityId() throws Exception {\n\t\ttestMultipleProviders(null, \"https://idp.example.com/idp/shibboleth\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"idp-metadata-with-multiple-providers\")\n\tvoid autoconfigurationWhenMultipleProvidersAndSpecifiedEntityId() throws Exception {\n\t\ttestMultipleProviders(\"https://idp.example.com/idp/shibboleth\", \"https://idp.example.com/idp/shibboleth\");\n\t\ttestMultipleProviders(\"https://idp2.example.com/idp/shibboleth\", \"https://idp2.example.com/idp/shibboleth\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"idp-metadata\")\n\tvoid signRequestShouldApplyIfMetadataUriIsSet() throws Exception {\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.start();\n\t\t\tString metadataUrl = server.url(\"\").toString();\n\t\t\tsetupMockResponse(server, new ClassPathResource(\"idp-metadata\"));\n\t\t\tthis.contextRunner.withPropertyValues(PREFIX + \".foo.assertingparty.metadata-uri=\" + metadataUrl,\n\t\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.sign-request=true\",\n\t\t\t\t\tPREFIX + \".foo.signing.credentials[0].private-key-location=classpath:org/springframework/boot/security/saml2/autoconfigure/rsa.key\",\n\t\t\t\t\tPREFIX + \".foo.signing.credentials[0].certificate-location=classpath:org/springframework/boot/security/saml2/autoconfigure/rsa.crt\")\n\t\t\t\t.run((context) -> {\n\t\t\t\t\tRelyingPartyRegistrationRepository repository = context\n\t\t\t\t\t\t.getBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\t\tRelyingPartyRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\t\t\tassertThat(registration).isNotNull();\n\t\t\t\t\tassertThat(registration.getAssertingPartyMetadata().getWantAuthnRequestsSigned()).isTrue();\n\t\t\t\t});\n\t\t}\n\t}\n\n\t@Test\n\t@WithPackageResources(\"certificate-location\")\n\tvoid autoconfigurationWithInvalidPrivateKeyShouldFail() {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\tPREFIX + \".foo.signing.credentials[0].private-key-location=classpath:certificate-location\",\n\t\t\t\tPREFIX + \".foo.signing.credentials[0].certificate-location=classpath:certificate-location\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.binding=post\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.sign-request=false\",\n\t\t\t\tPREFIX + \".foo.assertingparty.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.verification.credentials[0].certificate-location=classpath:certificate-location\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"Missing private key or unrecognized format\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"private-key-location\")\n\tvoid autoconfigurationWithInvalidCertificateShouldFail() {\n\t\tthis.contextRunner.withPropertyValues(\n\t\t\t\tPREFIX + \".foo.signing.credentials[0].private-key-location=classpath:private-key-location\",\n\t\t\t\tPREFIX + \".foo.signing.credentials[0].certificate-location=classpath:private-key-location\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.binding=post\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.sign-request=false\",\n\t\t\t\tPREFIX + \".foo.assertingparty.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.verification.credentials[0].certificate-location=classpath:private-key-location\")\n\t\t\t.run((context) -> assertThat(context).hasFailed()\n\t\t\t\t.getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"Missing certificates or unrecognized format\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"certificate-location\")\n\tvoid causesManagementWebSecurityAutoConfigurationToBackOff() {\n\t\tWebApplicationContextRunner contextRunner = this.contextRunner.withConfiguration(\n\t\t\t\tAutoConfigurations.of(ManagementWebSecurityAutoConfiguration.class, WebMvcAutoConfiguration.class));\n\t\tassertThat(contextRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ManagementWebSecurityAutoConfiguration.class)));\n\t\tcontextRunner.withPropertyValues(PREFIX\n\t\t\t\t+ \".simplesamlphp.assertingparty.single-sign-on.url=https://simplesaml-for-spring-saml/SSOService.php\",\n\t\t\t\tPREFIX + \".simplesamlphp.assertingparty.single-sign-on.sign-request=false\",\n\t\t\t\tPREFIX + \".simplesamlphp.assertingparty.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\",\n\t\t\t\tPREFIX + \".simplesamlphp.assertingparty.verification.credentials[0].certificate-location=classpath:certificate-location\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ManagementWebSecurityAutoConfiguration.class)\n\t\t\t\t.doesNotHaveBean(MANAGEMENT_SECURITY_FILTER_CHAIN_BEAN));\n\t}\n\n\tprivate void testMultipleProviders(@Nullable String specifiedEntityId, String expected) throws Exception {\n\t\ttry (MockWebServer server = new MockWebServer()) {\n\t\t\tserver.start();\n\t\t\tString metadataUrl = server.url(\"\").toString();\n\t\t\tsetupMockResponse(server, new ClassPathResource(\"idp-metadata-with-multiple-providers\"));\n\t\t\tWebApplicationContextRunner contextRunner = this.contextRunner\n\t\t\t\t.withPropertyValues(PREFIX + \".foo.assertingparty.metadata-uri=\" + metadataUrl);\n\t\t\tif (specifiedEntityId != null) {\n\t\t\t\tcontextRunner = contextRunner\n\t\t\t\t\t.withPropertyValues(PREFIX + \".foo.assertingparty.entity-id=\" + specifiedEntityId);\n\t\t\t}\n\t\t\tcontextRunner.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\tassertThat(server.getRequestCount()).isOne();\n\t\t\t\tRelyingPartyRegistrationRepository repository = context\n\t\t\t\t\t.getBean(RelyingPartyRegistrationRepository.class);\n\t\t\t\tRelyingPartyRegistration registration = repository.findByRegistrationId(\"foo\");\n\t\t\t\tassertThat(registration).isNotNull();\n\t\t\t\tassertThat(registration.getAssertingPartyMetadata().getEntityId()).isEqualTo(expected);\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate String[] getPropertyValuesWithoutSsoBinding() {\n\t\treturn new String[] { PREFIX\n\t\t\t\t+ \".foo.assertingparty.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.sign-request=false\",\n\t\t\t\tPREFIX + \".foo.assertingparty.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.verification.credentials[0].certificate-location=classpath:certificate-location\" };\n\t}\n\n\tprivate String[] getPropertyValues() {\n\t\treturn new String[] {\n\t\t\t\tPREFIX + \".foo.signing.credentials[0].private-key-location=classpath:private-key-location\",\n\t\t\t\tPREFIX + \".foo.signing.credentials[0].certificate-location=classpath:certificate-location\",\n\t\t\t\tPREFIX + \".foo.decryption.credentials[0].private-key-location=classpath:private-key-location\",\n\t\t\t\tPREFIX + \".foo.decryption.credentials[0].certificate-location=classpath:certificate-location\",\n\t\t\t\tPREFIX + \".foo.singlelogout.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SLOService.php\",\n\t\t\t\tPREFIX + \".foo.singlelogout.response-url=https://simplesaml-for-spring-saml.cfapps.io/\",\n\t\t\t\tPREFIX + \".foo.singlelogout.binding=post\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.binding=post\",\n\t\t\t\tPREFIX + \".foo.assertingparty.singlesignon.sign-request=false\",\n\t\t\t\tPREFIX + \".foo.assertingparty.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php\",\n\t\t\t\tPREFIX + \".foo.assertingparty.verification.credentials[0].certificate-location=classpath:certificate-location\",\n\t\t\t\tPREFIX + \".foo.asserting-party.singlelogout.url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SLOService.php\",\n\t\t\t\tPREFIX + \".foo.asserting-party.singlelogout.response-url=https://simplesaml-for-spring-saml.cfapps.io/\",\n\t\t\t\tPREFIX + \".foo.asserting-party.singlelogout.binding=post\",\n\t\t\t\tPREFIX + \".foo.entity-id={baseUrl}/saml2/foo-entity-id\",\n\t\t\t\tPREFIX + \".foo.acs.location={baseUrl}/login/saml2/foo-entity-id\",\n\t\t\t\tPREFIX + \".foo.acs.binding=redirect\" };\n\t}\n\n\tprivate boolean hasSecurityFilter(AssertableWebApplicationContext context, Class<? extends Filter> filter) {\n\t\treturn getSecurityFilterChain(context).getFilters().stream().anyMatch(filter::isInstance);\n\t}\n\n\tprivate SecurityFilterChain getSecurityFilterChain(AssertableWebApplicationContext context) {\n\t\tFilter springSecurityFilterChain = context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);\n\t\tFilterChainProxy filterChainProxy = getFilterChainProxy(springSecurityFilterChain);\n\t\tSecurityFilterChain securityFilterChain = filterChainProxy.getFilterChains().get(0);\n\t\treturn securityFilterChain;\n\t}\n\n\tprivate FilterChainProxy getFilterChainProxy(Filter filter) {\n\t\tif (filter instanceof FilterChainProxy filterChainProxy) {\n\t\t\treturn filterChainProxy;\n\t\t}\n\t\tif (filter instanceof CompositeFilter) {\n\t\t\tList<?> filters = (List<?>) ReflectionTestUtils.getField(filter, \"filters\");\n\t\t\tassertThat(filters).isNotNull();\n\t\t\treturn (FilterChainProxy) filters.stream()\n\t\t\t\t.filter(FilterChainProxy.class::isInstance)\n\t\t\t\t.findFirst()\n\t\t\t\t.orElseThrow();\n\t\t}\n\t\tthrow new IllegalStateException(\"No FilterChainProxy found\");\n\t}\n\n\tprivate void setupMockResponse(MockWebServer server, Resource resourceBody) throws Exception {\n\t\ttry (InputStream metadataSource = resourceBody.getInputStream()) {\n\t\t\ttry (Buffer metadataBuffer = new Buffer()) {\n\t\t\t\tmetadataBuffer.readFrom(metadataSource);\n\t\t\t\tMockResponse metadataResponse = new MockResponse().setBody(metadataBuffer);\n\t\t\t\tserver.enqueue(metadataResponse);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RegistrationRepositoryConfiguration {\n\n\t\t@Bean\n\t\tRelyingPartyRegistrationRepository testRegistrationRepository() {\n\t\t\treturn mock(RelyingPartyRegistrationRepository.class);\n\t\t}\n\n\t}\n\n\t@EnableWebSecurity\n\tstatic class EnableWebSecurityConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestSecurityFilterChainConfig {\n\n\t\t@Bean\n\t\tSecurityFilterChain testSecurityFilterChain(HttpSecurity http) {\n\t\t\treturn http.securityMatcher(\"/**\")\n\t\t\t\t.authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated())\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/java/org/springframework/boot/security/saml2/autoconfigure/Saml2RelyingPartyPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.security.saml2.autoconfigure.Saml2RelyingPartyProperties.Registration;\nimport org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;\nimport org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Saml2RelyingPartyProperties}.\n *\n * @author Madhura Bhave\n * @author Lasse Wulff\n */\nclass Saml2RelyingPartyPropertiesTests {\n\n\tprivate final Saml2RelyingPartyProperties properties = new Saml2RelyingPartyProperties();\n\n\t@Test\n\tvoid customizeSsoUrl() {\n\t\tbind(\"spring.security.saml2.relyingparty.registration.simplesamlphp.assertingparty.single-sign-on.url\",\n\t\t\t\t\"https://simplesaml-for-spring-saml/SSOService.php\");\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getAssertingparty().getSinglesignon().getUrl())\n\t\t\t.isEqualTo(\"https://simplesaml-for-spring-saml/SSOService.php\");\n\t}\n\n\t@Test\n\tvoid customizeSsoBinding() {\n\t\tbind(\"spring.security.saml2.relyingparty.registration.simplesamlphp.assertingparty.single-sign-on.binding\",\n\t\t\t\t\"post\");\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getAssertingparty().getSinglesignon().getBinding()).isEqualTo(Saml2MessageBinding.POST);\n\t}\n\n\t@Test\n\tvoid customizeSsoSignRequests() {\n\t\tbind(\"spring.security.saml2.relyingparty.registration.simplesamlphp.assertingparty.single-sign-on.sign-request\",\n\t\t\t\t\"false\");\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getAssertingparty().getSinglesignon().getSignRequest()).isFalse();\n\t}\n\n\t@Test\n\tvoid customizeRelyingPartyEntityId() {\n\t\tbind(\"spring.security.saml2.relyingparty.registration.simplesamlphp.entity-id\",\n\t\t\t\t\"{baseUrl}/saml2/custom-entity-id\");\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getEntityId()).isEqualTo(\"{baseUrl}/saml2/custom-entity-id\");\n\t}\n\n\t@Test\n\tvoid customizeRelyingPartyEntityIdDefaultsToServiceProviderMetadata() {\n\t\tassertThat(RelyingPartyRegistration.withRegistrationId(\"id\")).extracting(\"entityId\")\n\t\t\t.isEqualTo(new Saml2RelyingPartyProperties.Registration().getEntityId());\n\t}\n\n\t@Test\n\tvoid customizeAssertingPartyMetadataUri() {\n\t\tbind(\"spring.security.saml2.relyingparty.registration.simplesamlphp.assertingparty.metadata-uri\",\n\t\t\t\t\"https://idp.example.org/metadata\");\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getAssertingparty().getMetadataUri()).isEqualTo(\"https://idp.example.org/metadata\");\n\t}\n\n\t@Test\n\tvoid customizeSsoSignRequestsIsNullByDefault() {\n\t\tthis.properties.getRegistration().put(\"simplesamlphp\", new Saml2RelyingPartyProperties.Registration());\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getAssertingparty().getSinglesignon().getSignRequest()).isNull();\n\t}\n\n\t@Test\n\tvoid customizeNameIdFormat() {\n\t\tbind(\"spring.security.saml2.relyingparty.registration.simplesamlphp.name-id-format\", \"sampleNameIdFormat\");\n\t\tRegistration registration = this.properties.getRegistration().get(\"simplesamlphp\");\n\t\tassertThat(registration).isNotNull();\n\t\tassertThat(registration.getNameIdFormat()).isEqualTo(\"sampleNameIdFormat\");\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"spring.security.saml2.relyingparty\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/java/org/springframework/boot/security/saml2/autoconfigure/webmvc/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure.webmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@RestController\npublic class ExampleController {\n\n\t@GetMapping(\"/one\")\n\tpublic String one() {\n\t\treturn \"one\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/java/org/springframework/boot/security/saml2/autoconfigure/webmvc/Saml2RelyingPartyWebMvcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure.webmvc;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\n\n/**\n * Test application for SAML2 support with WebMvc.\n *\n * @author Andy Wilkinson\n */\n@EnableWebSecurity\n@SpringBootApplication\npublic class Saml2RelyingPartyWebMvcApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/java/org/springframework/boot/security/saml2/autoconfigure/webmvc/Saml2RelyingPartyWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.saml2.autoconfigure.webmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.MockMvc;\n\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with SAML2.\n *\n * @author Dmytro Nosan\n */\n@WebMvcTest(controllers = ExampleController.class, properties = {\n\t\t\"spring.security.saml2.relyingparty.registration.test.entity-id=relyingparty\",\n\t\t\"spring.security.saml2.relyingparty.registration.test.assertingparty.entity-id=assertingparty\",\n\t\t\"spring.security.saml2.relyingparty.registration.test.assertingparty.singlesignon.url=https://example.com\",\n\t\t\"spring.security.saml2.relyingparty.registration.test.assertingparty.singlesignon.sign-request=false\" })\nclass Saml2RelyingPartyWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvc mockMvc;\n\n\t@Test\n\tvoid shouldRedirectToLogin() throws Exception {\n\t\tthis.mockMvc.perform(get(\"/one\"))\n\t\t\t.andExpect(status().isFound())\n\t\t\t.andExpect(redirectedUrl(\"/saml2/authenticate?registrationId=test\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/java/org/springframework/boot/security/saml2/autoconfigure/webmvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.security.saml2.autoconfigure.webmvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/resources/org/springframework/boot/security/saml2/autoconfigure/certificate-location",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\nVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\nc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\naXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\nBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\nBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\nDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\nQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\nE1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\nRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\nnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\ncljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\niJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\nogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\nAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\nnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\nZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\nxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\nV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\nlx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n-----END CERTIFICATE-----"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/resources/org/springframework/boot/security/saml2/autoconfigure/idp-metadata",
    "content": "<md:EntityDescriptor entityID=\"https://idp.example.com/idp/shibboleth\"\n        xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"\n        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xmlns:shibmd=\"urn:mace:shibboleth:metadata:1.0\"\n        xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n        xmlns:mdui=\"urn:oasis:names:tc:SAML:metadata:ui\">\n    <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n\t\t<md:KeyDescriptor>\n            <ds:KeyInfo>\n                <ds:X509Data>\n                    <ds:X509Certificate>\n                        MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB\n                        BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe\n                        Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t\n                        cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP\n                        ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS\n                        v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN\n                        iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece\n                        byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz\n                        cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v\n                        dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX\n                        gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w\n                        dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW\n                        BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu\n                        9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL\n                        qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU\n                        duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU\n                        yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p\n                        V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e\n                        Cq53OZt9ISjHEw==\n                    </ds:X509Certificate>\n                </ds:X509Data>\n            </ds:KeyInfo>\n        </md:KeyDescriptor>\n        <md:SingleSignOnService\n                Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n                Location=\"https://idp.example.com/sso\"/>\n    </md:IDPSSODescriptor>\n    <md:ContactPerson contactType=\"technical\">\n        <md:EmailAddress>mailto:technical.contact@example.com</md:EmailAddress>\n    </md:ContactPerson>\n</md:EntityDescriptor>\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/resources/org/springframework/boot/security/saml2/autoconfigure/idp-metadata-with-multiple-providers",
    "content": "<EntitiesDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ID=\"virtu-20230614094100\" Name=\"virtu\" validUntil=\"2023-07-12T06:41:00Z\" xsi:schemaLocation=\"urn:oasis:names:tc:SAML:2.0:metadata saml-schema-metadata-2.0.xsd  http://www.w3.org/2000/09/xmldsig# xmldsig-core-schema.xsd\">\n\t<md:EntityDescriptor entityID=\"https://idp.example.com/idp/shibboleth\"\n\t        xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"\n\t        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t        xmlns:shibmd=\"urn:mace:shibboleth:metadata:1.0\"\n\t        xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n\t        xmlns:mdui=\"urn:oasis:names:tc:SAML:metadata:ui\">\n\t    <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n\t\t\t<md:KeyDescriptor>\n\t            <ds:KeyInfo>\n\t                <ds:X509Data>\n\t                    <ds:X509Certificate>\n\t                        MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB\n\t                        BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe\n\t                        Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t\n\t                        cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP\n\t                        ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS\n\t                        v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN\n\t                        iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece\n\t                        byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz\n\t                        cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v\n\t                        dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX\n\t                        gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w\n\t                        dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW\n\t                        BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu\n\t                        9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL\n\t                        qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU\n\t                        duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU\n\t                        yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p\n\t                        V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e\n\t                        Cq53OZt9ISjHEw==\n\t                    </ds:X509Certificate>\n\t                </ds:X509Data>\n\t            </ds:KeyInfo>\n\t        </md:KeyDescriptor>\n\t        <md:SingleSignOnService\n\t                Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n\t                Location=\"https://idp.example.com/sso\"/>\n\t    </md:IDPSSODescriptor>\n\t    <md:ContactPerson contactType=\"technical\">\n\t        <md:EmailAddress>mailto:technical.contact@example.com</md:EmailAddress>\n\t    </md:ContactPerson>\n\t</md:EntityDescriptor>\n\t<md:EntityDescriptor entityID=\"https://idp2.example.com/idp/shibboleth\"\n\t        xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"\n\t        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t        xmlns:shibmd=\"urn:mace:shibboleth:metadata:1.0\"\n\t        xmlns:md=\"urn:oasis:names:tc:SAML:2.0:metadata\"\n\t        xmlns:mdui=\"urn:oasis:names:tc:SAML:metadata:ui\">\n\t    <md:IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n\t\t\t<md:KeyDescriptor>\n\t            <ds:KeyInfo>\n\t                <ds:X509Data>\n\t                    <ds:X509Certificate>\n\t                        MIIDZjCCAk6gAwIBAgIVAL9O+PA7SXtlwZZY8MVSE9On1cVWMA0GCSqGSIb3DQEB\n\t                        BQUAMCkxJzAlBgNVBAMTHmlkZW0tcHVwYWdlbnQuZG16LWludC51bmltby5pdDAe\n\t                        Fw0xMzA3MjQwMDQ0MTRaFw0zMzA3MjQwMDQ0MTRaMCkxJzAlBgNVBAMTHmlkZW0t\n\t                        cHVwYWdlbnQuZG16LWludC51bmltby5pdDCCASIwDQYJKoZIhvcNAMIIDQADggEP\n\t                        ADCCAQoCggEBAIAcp/VyzZGXUF99kwj4NvL/Rwv4YvBgLWzpCuoxqHZ/hmBwJtqS\n\t                        v0y9METBPFbgsF3hCISnxbcmNVxf/D0MoeKtw1YPbsUmow/bFe+r72hZ+IVAcejN\n\t                        iDJ7t5oTjsRN1t1SqvVVk6Ryk5AZhpFW+W9pE9N6c7kJ16Rp2/mbtax9OCzxpece\n\t                        byi1eiLfIBmkcRawL/vCc2v6VLI18i6HsNVO3l2yGosKCbuSoGDx2fCdAOk/rgdz\n\t                        cWOvFsIZSKuD+FVbSS/J9GVs7yotsS4PRl4iX9UMnfDnOMfO7bcBgbXtDl4SCU1v\n\t                        dJrRw7IL/pLz34Rv9a8nYitrzrxtLOp3nYUCAwEAAaOBhDCBgTBgBgMIIDEEWTBX\n\t                        gh5pZGVtLXB1cGFnZW50LmRtei1pbnQudW5pbW8uaXSGNWh0dHBzOi8vaWRlbS1w\n\t                        dXBhZ2VudC5kbXotaW50LnVuaW1vLml0L2lkcC9zaGliYm9sZXRoMB0GA1UdDgQW\n\t                        BBT8PANzz+adGnTRe8ldcyxAwe4VnzANBgkqhkiG9w0BAQUFAAOCAQEAOEnO8Clu\n\t                        9z/Lf/8XOOsTdxJbV29DIF3G8KoQsB3dBsLwPZVEAQIP6ceS32Xaxrl6FMTDDNkL\n\t                        qUvvInUisw0+I5zZwYHybJQCletUWTnz58SC4C9G7FpuXHFZnOGtRcgGD1NOX4UU\n\t                        duus/4nVcGSLhDjszZ70Xtj0gw2Sn46oQPHTJ81QZ3Y9ih+Aj1c9OtUSBwtWZFkU\n\t                        yooAKoR8li68Yb21zN2N65AqV+ndL98M8xUYMKLONuAXStDeoVCipH6PJ09Z5U2p\n\t                        V5p4IQRV6QBsNw9CISJFuHzkVYTH5ZxzN80Ru46vh4y2M0Nu8GQ9I085KoZkrf5e\n\t                        Cq53OZt9ISjHEw==\n\t                    </ds:X509Certificate>\n\t                </ds:X509Data>\n\t            </ds:KeyInfo>\n\t        </md:KeyDescriptor>\n\t        <md:SingleSignOnService\n\t                Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\"\n\t                Location=\"https://idp2.example.com/sso\"/>\n\t    </md:IDPSSODescriptor>\n\t    <md:ContactPerson contactType=\"technical\">\n\t        <md:EmailAddress>mailto:technical.contact2@example.com</md:EmailAddress>\n\t    </md:ContactPerson>\n\t</md:EntityDescriptor>\n</EntitiesDescriptor>"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/resources/org/springframework/boot/security/saml2/autoconfigure/private-key-location",
    "content": "-----BEGIN PRIVATE KEY-----\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\nVUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\ncDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\nQ2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\nx7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\nwJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\nvwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\noPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\nEGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\nKkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\nYX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\nINrtuLp4YHbgk1mi\n-----END PRIVATE KEY-----"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/resources/org/springframework/boot/security/saml2/autoconfigure/rsa.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIID1zCCAr+gAwIBAgIUCzQeKBMTO0iHVW3iKmZC41haqCowDQYJKoZIhvcNAQEL\nBQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI\nQ2l0eU5hbWUxFDASBgNVBAoMC0NvbXBhbnlOYW1lMRswGQYDVQQLDBJDb21wYW55\nU2VjdGlvbk5hbWUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzA5MjAwODI5MDNa\nFw0zMzA5MTcwODI5MDNaMHsxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5h\nbWUxETAPBgNVBAcMCENpdHlOYW1lMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkG\nA1UECwwSQ29tcGFueVNlY3Rpb25OYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUfi4aaCotJZX6OSDjv6fxCCfc\nihSs91Z/mmN+yc1fsxVSs53SIbqUuo+Wzhv34kp8I/r03P9LWVTkFPbeDxAl75Oa\nPGggxK55US0Zfy9Hj1BwWIKV3330N61emID1GDEtFKL4yJbJdreQXnIXTBL2o76V\nnuV/tYozyZnb07IQ1WhUm5WDxgzM0yFudMynTczCBeZHfvharDtB8PFFhCZXW2/9\nTZVVfW4oOML8EAX3hvnvYBlFl/foxXekZSwq/odOkmWCZavT2+0sburHUlOnPGUh\nQj4tHwpMRczp7VX4ptV1D2UrxsK/2B+s9FK2QSLKQ9JzAYJ6WxQjHcvET9jvAgMB\nAAGjUzBRMB0GA1UdDgQWBBQjDr/1E/01pfLPD8uWF7gbaYL0TTAfBgNVHSMEGDAW\ngBQjDr/1E/01pfLPD8uWF7gbaYL0TTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\nDQEBCwUAA4IBAQAGjUuec0+0XNMCRDKZslbImdCAVsKsEWk6NpnUViDFAxL+KQuC\nNW131UeHb9SCzMqRwrY4QI3nAwJQCmilL/hFM3ss4acn3WHu1yci/iKPUKeL1ec5\nkCFUmqX1NpTiVaytZ/9TKEr69SMVqNfQiuW5U1bIIYTqK8xo46WpM6YNNHO3eJK6\nNH0MW79Wx5ryi4i4C6afqYbVbx7tqcmy8CFeNxgZ0bFQ87SiwYXIj77b6sVYbu32\ndoykBQgSHLcagWASPQ73m73CWUgo+7+EqSKIQqORbgmTLPmOUh99gFIx7jmjTyHm\nNBszx1ZVWuIv3mWmp626Kncyc+LLM9tvgymx\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-security-saml2/src/test/resources/org/springframework/boot/security/saml2/autoconfigure/rsa.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDUfi4aaCotJZX6\nOSDjv6fxCCfcihSs91Z/mmN+yc1fsxVSs53SIbqUuo+Wzhv34kp8I/r03P9LWVTk\nFPbeDxAl75OaPGggxK55US0Zfy9Hj1BwWIKV3330N61emID1GDEtFKL4yJbJdreQ\nXnIXTBL2o76VnuV/tYozyZnb07IQ1WhUm5WDxgzM0yFudMynTczCBeZHfvharDtB\n8PFFhCZXW2/9TZVVfW4oOML8EAX3hvnvYBlFl/foxXekZSwq/odOkmWCZavT2+0s\nburHUlOnPGUhQj4tHwpMRczp7VX4ptV1D2UrxsK/2B+s9FK2QSLKQ9JzAYJ6WxQj\nHcvET9jvAgMBAAECggEADdeRuZml1F65mDJm1enduaH+NWvEm1yEr3ecr0fbujYI\nbQ89+CVx/znvRvPH4aFwQwmgUZl12JrfS05MTectoPMBf/obDwtmPDPmsV2rdEi9\n2jEB11vW23T8X7L6hOdzCKHqrd8kkhzK1LuPnhHlaFipU8YlOBOuMYpv8eB78y79\nQkd5/ZEygFhqVGz96R7nT/xS21aPC7OPhicAauLLuguF4caCNhwkjLi3bizLemUn\n4i41q69drg7G8WX6BTxzem5FupKfI8rn2EkOjO/biVRknzGxAdqkM8SDHWkqeOuY\n8QVhc1kZsMkB0BGPlDPStUwEHSfUiND4GJTcngc++QKBgQD2lyeW3PoPjQ1qzjN4\nV/0XE77zpcPE5dW7chLtiWRY1dqk2uOJ32iOtxuqk9Q/YMSZyPJlTkfI5JePuC/B\nMB+QXzXuWN03Vn0ZrOpQlxcdA4A1o10NT1nEw8kZlf4+LyUk8GpMGUhjnxFZpZbf\n5S3fy0/2V8wGvOmXR65c8m6ASQKBgQDcmfCV5npu1HrtO8jmU9gBIhniNjB4IWue\nTSRt3ANDQaVBqsVaIMe/mUEQrZ6MdikMeA4bobOA6bUYwOiq8JGWSenAzGL22TbA\nW51q6A8hgDCuH1JnoagqUIbr61kwEVcfbRHEFpuxLURsjoDg/xBtwO96SxWPh5Wr\n+f1q8t5/dwKBgGWc+AVk3e6Wk1bVzcPjjjl6O4+vWTLD+wUZBs+3dBBfX4/bWzQv\nSai1r8Lk0+uh9qHgenJghZg1CneA0LztFbSqZ1DmcZIiI7720D+RY0bjcGup++hG\nMJmyjCXs9y2sw8OrBkKBkKDspXupjriIehTkdPjwSPTl1+Qs9575j6txAoGAT8n+\nErnCHsQLkjLFf0lkH0TOR9uBvHGaEy+jtXiWVYUw2IeDyg2BMfOkbPvfFL7IKhJi\nR+w8mKvvLHzZqrpIbitduLY0NURrYTfBwCEfF+bdtJzvmTwHLwbhRgNhxtj+wgcZ\nHetvdK4CyaDhTH/02T2nYHw32CoaIJHS7xPZFhECgYEAv7xRawjlrC4V0BLjP3Ej\npk8BbsRABxN1CrS6nJK+So4u2gKQDsL3WA0oJTS8v8AD5LvQUNr1d57FVlq9lwCd\nu623eOIuluCUZBVy1iYdkRXWz9pg5bCidCgEYUpF3SqpsuFou0XFzDD773UVQFVw\nVYriYasPwmzS2y2P7PKFzJs=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-security-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Security Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-security\"))\n\tapi(\"org.springframework.security:spring-security-test\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-webflux-test\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(\"org.seleniumhq.selenium:htmlunit3-driver\") {\n\t\texclude(group: \"com.sun.activation\", module: \"jakarta.activation\")\n\t}\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/main/java/org/springframework/boot/security/test/autoconfigure/webflux/SecurityWebTestClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webflux;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers;\nimport org.springframework.test.web.reactive.server.MockServerConfigurer;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Auto-configuration for Spring Security's {@link WebTestClient} integration.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(SecurityMockServerConfigurers.class)\npublic final class SecurityWebTestClientAutoConfiguration {\n\n\t@Bean\n\tMockServerConfigurer mockServerConfigurer() {\n\t\treturn SecurityMockServerConfigurers.springSecurity();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/main/java/org/springframework/boot/security/test/autoconfigure/webflux/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for tests involving WebFlux and Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.test.autoconfigure.webflux;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-test/src/main/java/org/springframework/boot/security/test/autoconfigure/webmvc/SecurityMockMvcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport java.util.concurrent.Executors;\n\nimport org.openqa.selenium.htmlunit.HtmlUnitDriver;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.webmvc.test.autoconfigure.MockMvcBuilderCustomizer;\nimport org.springframework.boot.webmvc.test.autoconfigure.MockMvcHtmlUnitDriverCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.concurrent.DelegatingSecurityContextExecutor;\nimport org.springframework.security.test.context.TestSecurityContextHolder;\nimport org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;\nimport org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.request.RequestPostProcessor;\nimport org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;\nimport org.springframework.test.web.servlet.setup.MockMvcConfigurerAdapter;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * Auto-configuration for Spring Security's MockMvc integration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(MockMvc.class)\npublic final class SecurityMockMvcAutoConfiguration {\n\n\tprivate static final String DEFAULT_SECURITY_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;\n\n\t@Bean\n\t@ConditionalOnBean(name = DEFAULT_SECURITY_FILTER_NAME)\n\tSecurityMockMvcBuilderCustomizer securityMockMvcBuilderCustomizer() {\n\t\treturn new SecurityMockMvcBuilderCustomizer();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HtmlUnitDriver.class)\n\tstatic class SecurityMockMvcHtmlUnitDriverConfiguration {\n\n\t\tMockMvcHtmlUnitDriverCustomizer securityDelegateMockMvcHtmlUnitDriverCustomizer() {\n\t\t\treturn (driver) -> driver\n\t\t\t\t.setExecutor(new DelegatingSecurityContextExecutor(Executors.newSingleThreadExecutor()));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link MockMvcBuilderCustomizer} that ensures that requests run with the user in\n\t * the {@link TestSecurityContextHolder}.\n\t *\n\t * @see SecurityMockMvcRequestPostProcessors#testSecurityContext\n\t */\n\tstatic class SecurityMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer {\n\n\t\t@Override\n\t\tpublic void customize(ConfigurableMockMvcBuilder<?> builder) {\n\t\t\tbuilder.apply(new MockMvcConfigurerAdapter() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder<?> builder,\n\t\t\t\t\t\tWebApplicationContext context) {\n\t\t\t\t\treturn SecurityMockMvcRequestPostProcessors.testSecurityContext();\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/main/java/org/springframework/boot/security/test/autoconfigure/webmvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for tests involving Spring MVC and Spring Security.\n */\n@NullMarked\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-security-test/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc.imports",
    "content": "org.springframework.boot.security.autoconfigure.SecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.UserDetailsServiceAutoConfiguration\norg.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterAutoConfiguration\norg.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration\norg.springframework.boot.security.test.autoconfigure.webmvc.SecurityMockMvcAutoConfiguration"
  },
  {
    "path": "module/spring-boot-security-test/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest.includes",
    "content": "org.springframework.security.config.annotation.web.WebSecurityConfigurer\norg.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer\norg.springframework.security.web.SecurityFilterChain\n"
  },
  {
    "path": "module/spring-boot-security-test/src/main/resources/META-INF/spring/org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient.imports",
    "content": "org.springframework.boot.security.autoconfigure.ReactiveUserDetailsServiceAutoConfiguration\norg.springframework.boot.security.autoconfigure.SecurityAutoConfiguration\norg.springframework.boot.security.autoconfigure.web.reactive.ReactiveWebSecurityAutoConfiguration\norg.springframework.boot.security.test.autoconfigure.webflux.SecurityWebTestClientAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webflux/WebTestClientSecurityIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webflux;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.webtestclient.autoconfigure.WebTestClientAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.server.WebFilter;\nimport org.springframework.web.server.WebHandler;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for mocked-infrastructure-backed WebTestClient security.\n *\n * @author Andy Wilkinson\n */\nclass WebTestClientSecurityIntegrationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(WebTestClientAutoConfiguration.class, SecurityWebTestClientAutoConfiguration.class));\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid shouldApplySpringSecurityConfigurer() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tWebTestClient webTestClient = context.getBean(WebTestClient.class);\n\t\t\tWebTestClient.Builder builder = (WebTestClient.Builder) ReflectionTestUtils.getField(webTestClient,\n\t\t\t\t\t\"builder\");\n\t\t\tassertThat(builder).isNotNull();\n\t\t\tWebHttpHandlerBuilder httpHandlerBuilder = (WebHttpHandlerBuilder) ReflectionTestUtils.getField(builder,\n\t\t\t\t\t\"httpHandlerBuilder\");\n\t\t\tassertThat(httpHandlerBuilder).isNotNull();\n\t\t\tList<WebFilter> filters = (List<WebFilter>) ReflectionTestUtils.getField(httpHandlerBuilder, \"filters\");\n\t\t\tassertThat(filters).isNotNull();\n\t\t\tassertThat(filters.get(0).getClass().getName()).isEqualTo(\n\t\t\t\t\t\"org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers$MutatorFilter\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tWebHandler webHandler() {\n\t\t\treturn mock(WebHandler.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/AfterSecurityFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport java.io.IOException;\nimport java.security.Principal;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link Filter} that is ordered to run after Spring Security's filter.\n *\n * @author Andy Wilkinson\n */\npublic class AfterSecurityFilter implements Filter, Ordered {\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn SecurityFilterProperties.DEFAULT_FILTER_ORDER + 1;\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tPrincipal principal = ((HttpServletRequest) request).getUserPrincipal();\n\t\tif (principal == null) {\n\t\t\tthrow new ServletException(\"No user principal\");\n\t\t}\n\t\tresponse.getWriter().write(principal.getName());\n\t\tresponse.getWriter().flush();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/AutoConfigureMockMvcSecurityFilterOrderingIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureMockMvc @AutoConfigureMockMvc} and the ordering of Spring\n * Security's filter\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\n@WithMockUser(username = \"user\", password = \"secret\")\n@Import(AfterSecurityFilter.class)\nclass AutoConfigureMockMvcSecurityFilterOrderingIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid afterSecurityFilterShouldFindAUserPrincipal() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"user\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/ExampleFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.core.Ordered;\nimport org.springframework.stereotype.Component;\n\n/**\n * Example filter used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\n@Component\npublic class ExampleFilter implements Filter, Ordered {\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tchain.doFilter(request, response);\n\t\t((HttpServletResponse) response).addHeader(\"x-test\", \"abc\");\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn SecurityFilterProperties.DEFAULT_FILTER_ORDER - 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/ExampleWebSecurityConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.security.config.annotation.web.WebSecurityConfigurer;\nimport org.springframework.security.config.annotation.web.builders.WebSecurity;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link WebSecurityConfigurer} used to test their inclusion in\n * {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@Component\nclass ExampleWebSecurityConfigurer implements WebSecurityConfigurer<WebSecurity> {\n\n\t@Override\n\tpublic void init(WebSecurity builder) {\n\t}\n\n\t@Override\n\tpublic void configure(WebSecurity builder) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/ExampleWebSecurityCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.security.config.annotation.web.builders.WebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link WebSecurityCustomizer} used to test their inclusion in\n * {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@Component\nclass ExampleWebSecurityCustomizer implements WebSecurityCustomizer {\n\n\t@Override\n\tpublic void customize(WebSecurity web) {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/MockMvcSecurityIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.test.context.support.WithMockUser;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for MockMvc security.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\n@TestPropertySource(properties = { \"debug=true\" })\nclass MockMvcSecurityIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\t@WithMockUser(username = \"test\", password = \"test\", roles = \"USER\")\n\tvoid okResponseWithMockUser() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).hasStatusOk();\n\t}\n\n\t@Test\n\tvoid unauthorizedResponseWithNoUser() {\n\t\tassertThat(this.mvc.get().uri(\"/\").accept(MediaType.APPLICATION_JSON)).hasStatus(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid okResponseWithBasicAuthCredentialsForKnownUser() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/\")\n\t\t\t.header(HttpHeaders.AUTHORIZATION, \"Basic \" + Base64.getEncoder().encodeToString(\"user:secret\".getBytes())))\n\t\t\t.hasStatusOk();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/SecurityTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.security.access.annotation.Secured;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Tests application for MockMvc Security.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class SecurityTestApplication {\n\n\t@RestController\n\tstatic class MyController {\n\n\t\t@RequestMapping(\"/\")\n\t\t@Secured(\"ROLE_USER\")\n\t\tString index() {\n\t\t\treturn \"Hello\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/java/org/springframework/boot/security/test/autoconfigure/webmvc/SecurityWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.security.test.autoconfigure.webmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for SpringSecurity with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass SecurityWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ConfigurableApplicationContext context;\n\n\t@Test\n\tvoid includesWebSecurityConfigurer() {\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context))\n\t\t\t.hasSingleBean(ExampleWebSecurityConfigurer.class);\n\t}\n\n\t@Test\n\tvoid includesWebSecurityCustomizer() {\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context))\n\t\t\t.hasSingleBean(ExampleWebSecurityCustomizer.class);\n\t}\n\n\t@Test\n\tvoid includesSecurityFilterChain() {\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context)).hasSingleBean(SecurityFilterChain.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-security-test/src/test/resources/application.properties",
    "content": "spring.security.user.name=user\nspring.security.user.password=secret\nspring.security.user.roles=USER\n"
  },
  {
    "path": "module/spring-boot-sendgrid/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot SendGrid\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"com.sendgrid:sendgrid-java\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-sendgrid/src/main/java/org/springframework/boot/sendgrid/autoconfigure/SendGridAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sendgrid.autoconfigure;\n\nimport com.sendgrid.Client;\nimport com.sendgrid.SendGrid;\nimport com.sendgrid.SendGridAPI;\nimport org.apache.http.HttpHost;\nimport org.apache.http.impl.client.HttpClientBuilder;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for SendGrid.\n *\n * @author Maciej Walkowiak\n * @author Patrick Bray\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(SendGrid.class)\n@ConditionalOnProperty(\"spring.sendgrid.api-key\")\n@EnableConfigurationProperties(SendGridProperties.class)\npublic final class SendGridAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(SendGridAPI.class)\n\tSendGrid sendGrid(SendGridProperties properties) {\n\t\tif (properties.getProxy() != null && properties.getProxy().getHost() != null\n\t\t\t\t&& properties.getProxy().getPort() != null) {\n\t\t\tHttpHost proxy = new HttpHost(properties.getProxy().getHost(), properties.getProxy().getPort());\n\t\t\treturn new SendGrid(properties.getApiKey(), new Client(HttpClientBuilder.create().setProxy(proxy).build()));\n\t\t}\n\t\treturn new SendGrid(properties.getApiKey());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sendgrid/src/main/java/org/springframework/boot/sendgrid/autoconfigure/SendGridProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sendgrid.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for SendGrid.\n *\n * @author Maciej Walkowiak\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.sendgrid\")\npublic class SendGridProperties {\n\n\t/**\n\t * SendGrid API key.\n\t */\n\tprivate @Nullable String apiKey;\n\n\t/**\n\t * Proxy configuration.\n\t */\n\tprivate @Nullable Proxy proxy;\n\n\tpublic @Nullable String getApiKey() {\n\t\treturn this.apiKey;\n\t}\n\n\tpublic void setApiKey(@Nullable String apiKey) {\n\t\tthis.apiKey = apiKey;\n\t}\n\n\tpublic @Nullable Proxy getProxy() {\n\t\treturn this.proxy;\n\t}\n\n\tpublic void setProxy(@Nullable Proxy proxy) {\n\t\tthis.proxy = proxy;\n\t}\n\n\tpublic static class Proxy {\n\n\t\t/**\n\t\t * SendGrid proxy host.\n\t\t */\n\t\tprivate @Nullable String host;\n\n\t\t/**\n\t\t * SendGrid proxy port.\n\t\t */\n\t\tprivate @Nullable Integer port;\n\n\t\tpublic @Nullable String getHost() {\n\t\t\treturn this.host;\n\t\t}\n\n\t\tpublic void setHost(@Nullable String host) {\n\t\t\tthis.host = host;\n\t\t}\n\n\t\tpublic @Nullable Integer getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t\tpublic void setPort(@Nullable Integer port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sendgrid/src/main/java/org/springframework/boot/sendgrid/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for SendGrid.\n */\n@NullMarked\npackage org.springframework.boot.sendgrid.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-sendgrid/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.sendgrid.autoconfigure.SendGridAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-sendgrid/src/test/java/org/springframework/boot/sendgrid/autoconfigure/SendGridAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sendgrid.autoconfigure;\n\nimport com.sendgrid.SendGrid;\nimport org.apache.http.impl.conn.DefaultProxyRoutePlanner;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link SendGridAutoConfiguration}.\n *\n * @author Maciej Walkowiak\n * @author Patrick Bray\n */\nclass SendGridAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid expectedSendGridBeanCreatedApiKey() {\n\t\tAnnotationConfigApplicationContext context = loadContext(\"spring.sendgrid.api-key:SG.SECRET-API-KEY\");\n\t\tSendGrid sendGrid = context.getBean(SendGrid.class);\n\t\tassertThat(sendGrid.getRequestHeaders()).containsEntry(\"Authorization\", \"Bearer SG.SECRET-API-KEY\");\n\t}\n\n\t@Test\n\tvoid autoConfigurationNotFiredWhenPropertiesNotSet() {\n\t\tAnnotationConfigApplicationContext context = loadContext();\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> context.getBean(SendGrid.class));\n\t}\n\n\t@Test\n\tvoid autoConfigurationNotFiredWhenBeanAlreadyCreated() {\n\t\tAnnotationConfigApplicationContext context = loadContext(ManualSendGridConfiguration.class,\n\t\t\t\t\"spring.sendgrid.api-key:SG.SECRET-API-KEY\");\n\t\tSendGrid sendGrid = context.getBean(SendGrid.class);\n\t\tassertThat(sendGrid.getRequestHeaders()).containsEntry(\"Authorization\", \"Bearer SG.CUSTOM_API_KEY\");\n\t}\n\n\t@Test\n\tvoid expectedSendGridBeanWithProxyCreated() {\n\t\tAnnotationConfigApplicationContext context = loadContext(\"spring.sendgrid.api-key:SG.SECRET-API-KEY\",\n\t\t\t\t\"spring.sendgrid.proxy.host:localhost\", \"spring.sendgrid.proxy.port:5678\");\n\t\tSendGrid sendGrid = context.getBean(SendGrid.class);\n\t\tassertThat(sendGrid).extracting(\"client.httpClient.routePlanner\").isInstanceOf(DefaultProxyRoutePlanner.class);\n\t}\n\n\tprivate AnnotationConfigApplicationContext loadContext(String... environment) {\n\t\treturn loadContext(null, environment);\n\t}\n\n\tprivate AnnotationConfigApplicationContext loadContext(@Nullable Class<?> additionalConfiguration,\n\t\t\tString... environment) {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(environment).applyTo(this.context);\n\t\tConfigurationPropertySources.attach(this.context.getEnvironment());\n\t\tthis.context.register(SendGridAutoConfiguration.class);\n\t\tif (additionalConfiguration != null) {\n\t\t\tthis.context.register(additionalConfiguration);\n\t\t}\n\t\tthis.context.refresh();\n\t\treturn this.context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ManualSendGridConfiguration {\n\n\t\t@Bean\n\t\tSendGrid sendGrid() {\n\t\t\treturn new SendGrid(\"SG.CUSTOM_API_KEY\", true);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Servlet\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework.security:spring-security-config\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-jetty\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"test\") {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/MultipartConfigFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Factory that can be used to create a {@link MultipartConfigElement}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class MultipartConfigFactory {\n\n\tprivate @Nullable String location;\n\n\tprivate @Nullable DataSize maxFileSize;\n\n\tprivate @Nullable DataSize maxRequestSize;\n\n\tprivate @Nullable DataSize fileSizeThreshold;\n\n\t/**\n\t * Sets the directory location where files will be stored.\n\t * @param location the location\n\t */\n\tpublic void setLocation(@Nullable String location) {\n\t\tthis.location = location;\n\t}\n\n\t/**\n\t * Sets the maximum {@link DataSize size} allowed for uploaded files.\n\t * @param maxFileSize the maximum file size\n\t */\n\tpublic void setMaxFileSize(@Nullable DataSize maxFileSize) {\n\t\tthis.maxFileSize = maxFileSize;\n\t}\n\n\t/**\n\t * Sets the maximum {@link DataSize} allowed for multipart/form-data requests.\n\t * @param maxRequestSize the maximum request size\n\t */\n\tpublic void setMaxRequestSize(@Nullable DataSize maxRequestSize) {\n\t\tthis.maxRequestSize = maxRequestSize;\n\t}\n\n\t/**\n\t * Sets the {@link DataSize size} threshold after which files will be written to disk.\n\t * @param fileSizeThreshold the file size threshold\n\t */\n\tpublic void setFileSizeThreshold(@Nullable DataSize fileSizeThreshold) {\n\t\tthis.fileSizeThreshold = fileSizeThreshold;\n\t}\n\n\t/**\n\t * Create a new {@link MultipartConfigElement} instance.\n\t * @return the multipart config element\n\t */\n\tpublic MultipartConfigElement createMultipartConfig() {\n\t\tlong maxFileSizeBytes = convertToBytes(this.maxFileSize, -1);\n\t\tlong maxRequestSizeBytes = convertToBytes(this.maxRequestSize, -1);\n\t\tlong fileSizeThresholdBytes = convertToBytes(this.fileSizeThreshold, 0);\n\t\treturn new MultipartConfigElement(this.location, maxFileSizeBytes, maxRequestSizeBytes,\n\t\t\t\t(int) fileSizeThresholdBytes);\n\t}\n\n\t/**\n\t * Return the amount of bytes from the specified {@link DataSize size}. If the size is\n\t * {@code null} or negative, returns {@code defaultValue}.\n\t * @param size the data size to handle\n\t * @param defaultValue the default value if the size is {@code null} or negative\n\t * @return the amount of bytes to use\n\t */\n\tprivate long convertToBytes(@Nullable DataSize size, int defaultValue) {\n\t\tif (size != null && !size.isNegative()) {\n\t\t\treturn size.toBytes();\n\t\t}\n\t\treturn defaultValue;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/exchanges/HttpExchangesFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.exchanges;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.util.Set;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpSession;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\n/**\n * Servlet {@link Filter} for recording {@link HttpExchange HTTP exchanges}.\n *\n * @author Dave Syer\n * @author Wallace Wadge\n * @author Andy Wilkinson\n * @author Venil Noronha\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class HttpExchangesFilter extends OncePerRequestFilter implements Ordered {\n\n\t// Not LOWEST_PRECEDENCE, but near the end, so it has a good chance of catching all\n\t// enriched headers, but users can add stuff after this if they want to\n\tprivate int order = Ordered.LOWEST_PRECEDENCE - 10;\n\n\tprivate final HttpExchangeRepository repository;\n\n\tprivate final Set<Include> includes;\n\n\t/**\n\t * Create a new {@link HttpExchangesFilter} instance.\n\t * @param repository the repository used to record events\n\t * @param includes the include options\n\t */\n\tpublic HttpExchangesFilter(HttpExchangeRepository repository, Set<Include> includes) {\n\t\tthis.repository = repository;\n\t\tthis.includes = includes;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)\n\t\t\tthrows ServletException, IOException {\n\t\tif (!isRequestValid(request)) {\n\t\t\tfilterChain.doFilter(request, response);\n\t\t\treturn;\n\t\t}\n\t\tRecordableServletHttpRequest sourceRequest = new RecordableServletHttpRequest(request);\n\t\tHttpExchange.Started startedHttpExchange = HttpExchange.start(sourceRequest);\n\t\tint status = HttpStatus.INTERNAL_SERVER_ERROR.value();\n\t\ttry {\n\t\t\tfilterChain.doFilter(request, response);\n\t\t\tstatus = response.getStatus();\n\t\t}\n\t\tfinally {\n\t\t\tRecordableServletHttpResponse sourceResponse = new RecordableServletHttpResponse(response, status);\n\t\t\tHttpExchange finishedExchange = startedHttpExchange.finish(sourceResponse, request::getUserPrincipal,\n\t\t\t\t\t() -> getSessionId(request), this.includes);\n\t\t\tthis.repository.add(finishedExchange);\n\t\t}\n\t}\n\n\tprivate boolean isRequestValid(HttpServletRequest request) {\n\t\ttry {\n\t\t\tnew URI(request.getRequestURL().toString());\n\t\t\treturn true;\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate @Nullable String getSessionId(HttpServletRequest request) {\n\t\tHttpSession session = request.getSession(false);\n\t\treturn (session != null) ? session.getId() : null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/exchanges/RecordableServletHttpRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.exchanges;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.springframework.boot.actuate.web.exchanges.RecordableHttpRequest;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.util.UriUtils;\n\n/**\n * An adapter that exposes an {@link HttpServletRequest} as a\n * {@link RecordableHttpRequest}.\n *\n * @author Andy Wilkinson\n */\nfinal class RecordableServletHttpRequest implements RecordableHttpRequest {\n\n\tprivate final HttpServletRequest request;\n\n\tRecordableServletHttpRequest(HttpServletRequest request) {\n\t\tthis.request = request;\n\t}\n\n\t@Override\n\tpublic String getMethod() {\n\t\treturn this.request.getMethod();\n\t}\n\n\t@Override\n\tpublic URI getUri() {\n\t\tString queryString = this.request.getQueryString();\n\t\tif (!StringUtils.hasText(queryString)) {\n\t\t\treturn URI.create(this.request.getRequestURL().toString());\n\t\t}\n\t\ttry {\n\t\t\tStringBuffer urlBuffer = appendQueryString(queryString);\n\t\t\treturn new URI(urlBuffer.toString());\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tString encoded = UriUtils.encodeQuery(queryString, StandardCharsets.UTF_8);\n\t\t\tStringBuffer urlBuffer = appendQueryString(encoded);\n\t\t\treturn URI.create(urlBuffer.toString());\n\t\t}\n\t}\n\n\tprivate StringBuffer appendQueryString(String queryString) {\n\t\treturn this.request.getRequestURL().append(\"?\").append(queryString);\n\t}\n\n\t@Override\n\tpublic Map<String, List<String>> getHeaders() {\n\t\treturn extractHeaders();\n\t}\n\n\t@Override\n\tpublic String getRemoteAddress() {\n\t\treturn this.request.getRemoteAddr();\n\t}\n\n\tprivate Map<String, List<String>> extractHeaders() {\n\t\tMap<String, List<String>> headers = new LinkedHashMap<>();\n\t\tEnumeration<String> names = this.request.getHeaderNames();\n\t\twhile (names.hasMoreElements()) {\n\t\t\tString name = names.nextElement();\n\t\t\theaders.put(name, Collections.list(this.request.getHeaders(name)));\n\t\t}\n\t\treturn headers;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/exchanges/RecordableServletHttpResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.exchanges;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.actuate.web.exchanges.RecordableHttpResponse;\n\n/**\n * An adapter that exposes an {@link HttpServletResponse} as a\n * {@link RecordableHttpResponse}.\n *\n * @author Andy Wilkinson\n */\nfinal class RecordableServletHttpResponse implements RecordableHttpResponse {\n\n\tprivate final HttpServletResponse delegate;\n\n\tprivate final int status;\n\n\tRecordableServletHttpResponse(HttpServletResponse response, int status) {\n\t\tthis.delegate = response;\n\t\tthis.status = status;\n\t}\n\n\t@Override\n\tpublic int getStatus() {\n\t\treturn this.status;\n\t}\n\n\t@Override\n\tpublic Map<String, List<String>> getHeaders() {\n\t\tMap<String, List<String>> headers = new LinkedHashMap<>();\n\t\tfor (String name : this.delegate.getHeaderNames()) {\n\t\t\theaders.put(name, new ArrayList<>(this.delegate.getHeaders(name)));\n\t\t}\n\t\treturn headers;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/exchanges/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator HTTP exchanges support for Servlet servers.\n *\n * @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository\n */\n@NullMarked\npackage org.springframework.boot.servlet.actuate.web.exchanges;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/mappings/FilterRegistrationMappingDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport java.util.Collection;\n\nimport jakarta.servlet.FilterRegistration;\n\n/**\n * A {@link RegistrationMappingDescription} derived from a {@link FilterRegistration}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class FilterRegistrationMappingDescription extends RegistrationMappingDescription<FilterRegistration> {\n\n\t/**\n\t * Creates a new {@code FilterRegistrationMappingDescription} derived from the given\n\t * {@code filterRegistration}.\n\t * @param filterRegistration the filter registration\n\t */\n\tpublic FilterRegistrationMappingDescription(FilterRegistration filterRegistration) {\n\t\tsuper(filterRegistration);\n\t}\n\n\t/**\n\t * Returns the servlet name mappings for the registered filter.\n\t * @return the mappings\n\t */\n\tpublic Collection<String> getServletNameMappings() {\n\t\treturn getRegistration().getServletNameMappings();\n\t}\n\n\t/**\n\t * Returns the URL pattern mappings for the registered filter.\n\t * @return the mappings\n\t */\n\tpublic Collection<String> getUrlPatternMappings() {\n\t\treturn getRegistration().getUrlPatternMappings();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/mappings/FiltersMappingDescriptionProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.servlet.actuate.web.mappings.FiltersMappingDescriptionProvider.FiltersMappingDescriptionProviderRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * A {@link MappingDescriptionProvider} that describes that mappings of any {@link Filter\n * Filters} registered with a {@link ServletContext}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ImportRuntimeHints(FiltersMappingDescriptionProviderRuntimeHints.class)\npublic class FiltersMappingDescriptionProvider implements MappingDescriptionProvider {\n\n\t@Override\n\tpublic List<FilterRegistrationMappingDescription> describeMappings(ApplicationContext context) {\n\t\tif (context instanceof WebApplicationContext webApplicationContext) {\n\t\t\tServletContext servletContext = webApplicationContext.getServletContext();\n\t\t\tAssert.state(servletContext != null, \"'servletContext' must not be null\");\n\t\t\treturn servletContext.getFilterRegistrations()\n\t\t\t\t.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(FilterRegistrationMappingDescription::new)\n\t\t\t\t.toList();\n\t\t}\n\t\treturn Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic String getMappingName() {\n\t\treturn \"servletFilters\";\n\t}\n\n\tstatic class FiltersMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(),\n\t\t\t\t\tFilterRegistrationMappingDescription.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/mappings/RegistrationMappingDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport jakarta.servlet.Registration;\n\n/**\n * A mapping description derived from a {@link Registration}.\n *\n * @param <T> type of the registration\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class RegistrationMappingDescription<T extends Registration> {\n\n\tprivate final T registration;\n\n\t/**\n\t * Creates a new {@link RegistrationMappingDescription} derived from the given\n\t * {@code registration} and with the given {@code predicate}.\n\t * @param registration the registration\n\t */\n\tpublic RegistrationMappingDescription(T registration) {\n\t\tthis.registration = registration;\n\t}\n\n\t/**\n\t * Returns the name of the registered Filter or Servlet.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.registration.getName();\n\t}\n\n\t/**\n\t * Returns the class name of the registered Filter or Servlet.\n\t * @return the class name\n\t */\n\tpublic String getClassName() {\n\t\treturn this.registration.getClassName();\n\t}\n\n\t/**\n\t * Returns the registration that is being described.\n\t * @return the registration\n\t */\n\tprotected final T getRegistration() {\n\t\treturn this.registration;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/mappings/ServletRegistrationMappingDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport java.util.Collection;\n\nimport jakarta.servlet.ServletRegistration;\n\n/**\n * A mapping description derived from a {@link ServletRegistration}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class ServletRegistrationMappingDescription extends RegistrationMappingDescription<ServletRegistration> {\n\n\t/**\n\t * Creates a new {@code ServletRegistrationMappingDescription} derived from the given\n\t * {@code servletRegistration}.\n\t * @param servletRegistration the servlet registration\n\t */\n\tpublic ServletRegistrationMappingDescription(ServletRegistration servletRegistration) {\n\t\tsuper(servletRegistration);\n\t}\n\n\t/**\n\t * Returns the mappings for the registered servlet.\n\t * @return the mappings\n\t */\n\tpublic Collection<String> getMappings() {\n\t\treturn getRegistration().getMappings();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/mappings/ServletsMappingDescriptionProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletsMappingDescriptionProvider.ServletsMappingDescriptionProviderRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * A {@link MappingDescriptionProvider} that describes that mappings of any {@link Servlet\n * Servlets} registered with a {@link ServletContext}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ImportRuntimeHints(ServletsMappingDescriptionProviderRuntimeHints.class)\npublic class ServletsMappingDescriptionProvider implements MappingDescriptionProvider {\n\n\t@Override\n\tpublic List<ServletRegistrationMappingDescription> describeMappings(ApplicationContext context) {\n\t\tif (context instanceof WebApplicationContext webApplicationContext) {\n\t\t\tServletContext servletContext = webApplicationContext.getServletContext();\n\t\t\tAssert.state(servletContext != null, \"'servletContext' must not be null\");\n\t\t\treturn servletContext.getServletRegistrations()\n\t\t\t\t.values()\n\t\t\t\t.stream()\n\t\t\t\t.map(ServletRegistrationMappingDescription::new)\n\t\t\t\t.toList();\n\t\t}\n\t\treturn Collections.emptyList();\n\t}\n\n\t@Override\n\tpublic String getMappingName() {\n\t\treturn \"servlets\";\n\t}\n\n\tstatic class ServletsMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(),\n\t\t\t\t\tServletRegistrationMappingDescription.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator servlet request mappings support.\n */\n@NullMarked\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/HttpEncodingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.servlet.filter.OrderedCharacterEncodingFilter;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.filter.CharacterEncodingFilter;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for configuring the encoding to use\n * in Servlet web applications.\n *\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@EnableConfigurationProperties(ServletEncodingProperties.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(CharacterEncodingFilter.class)\n@ConditionalOnBooleanProperty(name = \"spring.servlet.encoding.enabled\", matchIfMissing = true)\npublic final class HttpEncodingAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tCharacterEncodingFilter characterEncodingFilter(ServletEncodingProperties properties) {\n\t\tCharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();\n\t\tfilter.setEncoding(properties.getCharset().name());\n\t\tfilter.setForceRequestEncoding(properties.shouldForce(ServletEncodingProperties.HttpMessageType.REQUEST));\n\t\tfilter.setForceResponseEncoding(properties.shouldForce(ServletEncodingProperties.HttpMessageType.RESPONSE));\n\t\treturn filter;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/MultipartAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.Servlet;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.multipart.MultipartResolver;\nimport org.springframework.web.multipart.support.StandardServletMultipartResolver;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for multipart uploads. Adds a\n * {@link StandardServletMultipartResolver} if none is present, and adds a\n * {@link jakarta.servlet.MultipartConfigElement multipartConfigElement} if none is\n * otherwise defined.\n * <p>\n * The {@link jakarta.servlet.MultipartConfigElement} is a Servlet API that's used to\n * configure how the server handles file uploads.\n *\n * @author Greg Turnquist\n * @author Josh Long\n * @author Toshiaki Maki\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })\n@ConditionalOnBooleanProperty(name = \"spring.servlet.multipart.enabled\", matchIfMissing = true)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(MultipartProperties.class)\npublic final class MultipartAutoConfiguration {\n\n\t/**\n\t * Well-known name for the MultipartResolver object in the bean factory for this\n\t * namespace.\n\t */\n\tprivate static final String MULTIPART_RESOLVER_BEAN_NAME = \"multipartResolver\";\n\n\tprivate final MultipartProperties multipartProperties;\n\n\tMultipartAutoConfiguration(MultipartProperties multipartProperties) {\n\t\tthis.multipartProperties = multipartProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMultipartConfigElement multipartConfigElement() {\n\t\treturn this.multipartProperties.createMultipartConfig();\n\t}\n\n\t@Bean(name = MULTIPART_RESOLVER_BEAN_NAME)\n\t@ConditionalOnMissingBean(MultipartResolver.class)\n\tStandardServletMultipartResolver multipartResolver() {\n\t\tStandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();\n\t\tmultipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());\n\t\tmultipartResolver.setStrictServletCompliance(this.multipartProperties.isStrictServletCompliance());\n\t\treturn multipartResolver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/MultipartProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.servlet.MultipartConfigFactory;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Properties to be used in configuring a {@link MultipartConfigElement}.\n * <ul>\n * <li>{@link #getLocation() location} specifies the directory where uploaded files will\n * be stored. When not specified, a temporary directory will be used.</li>\n * <li>{@link #getMaxFileSize() max-file-size} specifies the maximum size permitted for\n * uploaded files. The default is 1MB</li>\n * <li>{@link #getMaxRequestSize() max-request-size} specifies the maximum size allowed\n * for {@literal multipart/form-data} requests. The default is 10MB.</li>\n * <li>{@link #getFileSizeThreshold() file-size-threshold} specifies the size threshold\n * after which files will be written to disk. The default is 0.</li>\n * </ul>\n * <p>\n * These properties are ultimately passed to {@link MultipartConfigFactory} which means\n * you may specify numeric values using {@literal long} values or using more readable\n * {@link DataSize} variants.\n *\n * @author Josh Long\n * @author Toshiaki Maki\n * @author Stephane Nicoll\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(prefix = \"spring.servlet.multipart\", ignoreUnknownFields = false)\npublic class MultipartProperties {\n\n\t/**\n\t * Whether to enable support of multipart uploads.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Intermediate location of uploaded files.\n\t */\n\tprivate @Nullable String location;\n\n\t/**\n\t * Max file size.\n\t */\n\tprivate DataSize maxFileSize = DataSize.ofMegabytes(1);\n\n\t/**\n\t * Max request size.\n\t */\n\tprivate DataSize maxRequestSize = DataSize.ofMegabytes(10);\n\n\t/**\n\t * Threshold after which files are written to disk.\n\t */\n\tprivate DataSize fileSizeThreshold = DataSize.ofBytes(0);\n\n\t/**\n\t * Whether to resolve the multipart request lazily at the time of file or parameter\n\t * access.\n\t */\n\tprivate boolean resolveLazily;\n\n\t/**\n\t * Whether to resolve the multipart request strictly complying with the Servlet\n\t * specification, only to be used for \"multipart/form-data\" requests.\n\t */\n\tprivate boolean strictServletCompliance;\n\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\tpublic @Nullable String getLocation() {\n\t\treturn this.location;\n\t}\n\n\tpublic void setLocation(@Nullable String location) {\n\t\tthis.location = location;\n\t}\n\n\tpublic DataSize getMaxFileSize() {\n\t\treturn this.maxFileSize;\n\t}\n\n\tpublic void setMaxFileSize(DataSize maxFileSize) {\n\t\tthis.maxFileSize = maxFileSize;\n\t}\n\n\tpublic DataSize getMaxRequestSize() {\n\t\treturn this.maxRequestSize;\n\t}\n\n\tpublic void setMaxRequestSize(DataSize maxRequestSize) {\n\t\tthis.maxRequestSize = maxRequestSize;\n\t}\n\n\tpublic DataSize getFileSizeThreshold() {\n\t\treturn this.fileSizeThreshold;\n\t}\n\n\tpublic void setFileSizeThreshold(DataSize fileSizeThreshold) {\n\t\tthis.fileSizeThreshold = fileSizeThreshold;\n\t}\n\n\tpublic boolean isResolveLazily() {\n\t\treturn this.resolveLazily;\n\t}\n\n\tpublic void setResolveLazily(boolean resolveLazily) {\n\t\tthis.resolveLazily = resolveLazily;\n\t}\n\n\tpublic boolean isStrictServletCompliance() {\n\t\treturn this.strictServletCompliance;\n\t}\n\n\tpublic void setStrictServletCompliance(boolean strictServletCompliance) {\n\t\tthis.strictServletCompliance = strictServletCompliance;\n\t}\n\n\t/**\n\t * Create a new {@link MultipartConfigElement} using the properties.\n\t * @return a new {@link MultipartConfigElement} configured using there properties\n\t */\n\tpublic MultipartConfigElement createMultipartConfig() {\n\t\tMultipartConfigFactory factory = new MultipartConfigFactory();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.fileSizeThreshold).to(factory::setFileSizeThreshold);\n\t\tmap.from(this.location).whenHasText().to(factory::setLocation);\n\t\tmap.from(this.maxRequestSize).to(factory::setMaxRequestSize);\n\t\tmap.from(this.maxFileSize).to(factory::setMaxFileSize);\n\t\treturn factory.createMultipartConfig();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/ServletEncodingProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for Servlet encoding.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.servlet.encoding\")\npublic class ServletEncodingProperties {\n\n\t/**\n\t * Default HTTP encoding for Servlet applications.\n\t */\n\tpublic static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\t/**\n\t * Charset of HTTP requests and responses. Added to the \"Content-Type\" header if not\n\t * set explicitly.\n\t */\n\tprivate Charset charset = DEFAULT_CHARSET;\n\n\t/**\n\t * Whether to force the encoding to the configured charset on HTTP requests and\n\t * responses.\n\t */\n\tprivate @Nullable Boolean force;\n\n\t/**\n\t * Whether to force the encoding to the configured charset on HTTP requests. Defaults\n\t * to true when \"force\" has not been specified.\n\t */\n\tprivate @Nullable Boolean forceRequest;\n\n\t/**\n\t * Whether to force the encoding to the configured charset on HTTP responses.\n\t */\n\tprivate @Nullable Boolean forceResponse;\n\n\tpublic Charset getCharset() {\n\t\treturn this.charset;\n\t}\n\n\tpublic void setCharset(Charset charset) {\n\t\tthis.charset = charset;\n\t}\n\n\tpublic boolean isForce() {\n\t\treturn Boolean.TRUE.equals(this.force);\n\t}\n\n\tpublic void setForce(boolean force) {\n\t\tthis.force = force;\n\t}\n\n\tpublic boolean isForceRequest() {\n\t\treturn Boolean.TRUE.equals(this.forceRequest);\n\t}\n\n\tpublic void setForceRequest(boolean forceRequest) {\n\t\tthis.forceRequest = forceRequest;\n\t}\n\n\tpublic boolean isForceResponse() {\n\t\treturn Boolean.TRUE.equals(this.forceResponse);\n\t}\n\n\tpublic void setForceResponse(boolean forceResponse) {\n\t\tthis.forceResponse = forceResponse;\n\t}\n\n\tpublic boolean shouldForce(HttpMessageType type) {\n\t\tBoolean force = (type != HttpMessageType.REQUEST) ? this.forceResponse : this.forceRequest;\n\t\tif (force == null) {\n\t\t\tforce = this.force;\n\t\t}\n\t\tif (force == null) {\n\t\t\tforce = (type == HttpMessageType.REQUEST);\n\t\t}\n\t\treturn force;\n\t}\n\n\t/**\n\t * Type of HTTP message to consider for encoding configuration.\n\t */\n\tpublic enum HttpMessageType {\n\n\t\t/**\n\t\t * HTTP request message.\n\t\t */\n\t\tREQUEST,\n\t\t/**\n\t\t * HTTP response message.\n\t\t */\n\t\tRESPONSE\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ManagementServletContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\n/**\n * Provides information about the management servlet context for MVC controllers to use.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ManagementServletContext {\n\n\t/**\n\t * Return the servlet path of the management server.\n\t * @return the servlet path\n\t */\n\tString getServletPath();\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ServletEndpointManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for servlet\n * endpoints.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 4.0.0\n */\n@ManagementContextConfiguration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic class ServletEndpointManagementContextConfiguration {\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\tpublic IncludeExcludeEndpointFilter<org.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint> servletExposeExcludePropertyEndpointFilter(\n\t\t\tWebEndpointProperties properties) {\n\t\tWebEndpointProperties.Exposure exposure = properties.getExposure();\n\t\treturn new IncludeExcludeEndpointFilter<>(\n\t\t\t\torg.springframework.boot.actuate.endpoint.web.ExposableServletEndpoint.class, exposure.getInclude(),\n\t\t\t\texposure.getExclude());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ServletManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport jakarta.servlet.Filter;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.HierarchicalBeanFactory;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.BeanIds;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Servlet web\n * endpoint infrastructure when a separate management context with a web server running on\n * a different port is required.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\nclass ServletManagementChildContextConfiguration {\n\n\t@Bean\n\tServletManagementWebServerFactoryCustomizer servletManagementWebServerFactoryCustomizer(\n\t\t\tListableBeanFactory beanFactory) {\n\t\treturn new ServletManagementWebServerFactoryCustomizer(beanFactory);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ EnableWebSecurity.class, Filter.class })\n\t@ConditionalOnBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN, search = SearchStrategy.ANCESTORS)\n\tstatic class ServletManagementContextSecurityConfiguration {\n\n\t\t@Bean\n\t\tFilter springSecurityFilterChain(HierarchicalBeanFactory beanFactory) {\n\t\t\tBeanFactory parent = beanFactory.getParentBeanFactory();\n\t\t\tAssert.state(parent != null, \"'parent' must not be null\");\n\t\t\treturn parent.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN, Filter.class);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBean(name = \"securityFilterChainRegistration\", search = SearchStrategy.ANCESTORS)\n\t\tDelegatingFilterProxyRegistrationBean securityFilterChainRegistration(HierarchicalBeanFactory beanFactory) {\n\t\t\tBeanFactory parent = beanFactory.getParentBeanFactory();\n\t\t\tAssert.state(parent != null, \"'parent' must not be null\");\n\t\t\treturn parent.getBean(\"securityFilterChainRegistration\", DelegatingFilterProxyRegistrationBean.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ServletManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport jakarta.servlet.Servlet;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.servlet.filter.ApplicationContextHeaderFilter;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Servlet-specific management\n * context concerns.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Servlet.class, WebEndpointProperties.class })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(WebEndpointProperties.class)\npublic final class ServletManagementContextAutoConfiguration {\n\n\t@Bean\n\tManagementServletContext managementServletContext(WebEndpointProperties properties) {\n\t\treturn properties::getBasePath;\n\t}\n\n\t// Put Servlets and Filters in their own nested class so they don't force early\n\t// instantiation of ManagementServerProperties.\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(\"management.server.add-application-context-header\")\n\tprotected static class ApplicationContextFilterConfiguration {\n\n\t\t@Bean\n\t\tApplicationContextHeaderFilter applicationContextIdFilter(ApplicationContext context) {\n\t\t\treturn new ApplicationContextHeaderFilter(context);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ServletManagementWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementWebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ManagementWebServerFactoryCustomizer} for a servlet web server.\n *\n * @author Andy Wilkinson\n */\nclass ServletManagementWebServerFactoryCustomizer\n\t\textends ManagementWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {\n\n\tServletManagementWebServerFactoryCustomizer(ListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t}\n\n\t@Override\n\tprotected void customize(ConfigurableServletWebServerFactory webServerFactory,\n\t\t\tManagementServerProperties managementServerProperties, ServerProperties serverProperties) {\n\t\tsuper.customize(webServerFactory, managementServerProperties, serverProperties);\n\t\twebServerFactory.setContextPath(getContextPath(managementServerProperties));\n\t}\n\n\tprivate String getContextPath(ManagementServerProperties managementServerProperties) {\n\t\tString basePath = managementServerProperties.getBasePath();\n\t\treturn StringUtils.hasText(basePath) ? basePath : \"\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/exchanges/ServletHttpExchangesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web.exchanges;\n\nimport org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesProperties;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.servlet.actuate.web.exchanges.HttpExchangesFilter;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to record {@link HttpExchange HTTP\n * exchanges}.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnBooleanProperty(name = \"management.httpexchanges.recording.enabled\", matchIfMissing = true)\n@ConditionalOnBean(HttpExchangeRepository.class)\n@EnableConfigurationProperties(HttpExchangesProperties.class)\npublic final class ServletHttpExchangesAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHttpExchangesFilter httpExchangesFilter(HttpExchangeRepository repository, HttpExchangesProperties properties) {\n\t\treturn new HttpExchangesFilter(repository, properties.getRecording().getInclude());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/exchanges/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator HTTP exchanges auto-configuration for Servlet servers.\n */\n@NullMarked\npackage org.springframework.boot.servlet.autoconfigure.actuate.web.exchanges;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/mappings/ServletMappingsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web.mappings;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.servlet.actuate.web.mappings.FiltersMappingDescriptionProvider;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletsMappingDescriptionProvider;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to describe Servlet-related\n * {@link MappingDescriptionProvider mappings}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ConditionalOnAvailableEndpoint.class, MappingsEndpoint.class })\n@ConditionalOnAvailableEndpoint(MappingsEndpoint.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic final class ServletMappingsAutoConfiguration {\n\n\t@Bean\n\tServletsMappingDescriptionProvider servletMappingDescriptionProvider() {\n\t\treturn new ServletsMappingDescriptionProvider();\n\t}\n\n\t@Bean\n\tFiltersMappingDescriptionProvider filterMappingDescriptionProvider() {\n\t\treturn new FiltersMappingDescriptionProvider();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator servlet request mappings auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.servlet.autoconfigure.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/actuate/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for {@code jakarta.servlet} actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for application support of the {@code jakarta.servlet}\n * specification.\n */\n@NullMarked\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/ApplicationContextHeaderFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\n/**\n * {@link OncePerRequestFilter} to add an {@literal X-Application-Context} header that\n * contains the {@link ApplicationContext#getId() ApplicationContext ID}.\n *\n * @author Phillip Webb\n * @author Venil Noronha\n * @since 4.0.0\n */\npublic class ApplicationContextHeaderFilter extends OncePerRequestFilter {\n\n\t/**\n\t * Public constant for {@literal X-Application-Context}.\n\t */\n\tpublic static final String HEADER_NAME = \"X-Application-Context\";\n\n\tprivate final ApplicationContext applicationContext;\n\n\tpublic ApplicationContextHeaderFilter(ApplicationContext context) {\n\t\tthis.applicationContext = context;\n\t}\n\n\t@Override\n\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)\n\t\t\tthrows ServletException, IOException {\n\t\tresponse.addHeader(HEADER_NAME, this.applicationContext.getId());\n\t\tfilterChain.doFilter(request, response);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/OrderedCharacterEncodingFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.web.filter.CharacterEncodingFilter;\n\n/**\n * {@link CharacterEncodingFilter} that also implements {@link Ordered}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class OrderedCharacterEncodingFilter extends CharacterEncodingFilter implements OrderedFilter {\n\n\tprivate int order = Ordered.HIGHEST_PRECEDENCE;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order for this filter.\n\t * @param order the order to set\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/OrderedFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport jakarta.servlet.Filter;\n\nimport org.springframework.core.Ordered;\n\n/**\n * An {@link Ordered} {@link jakarta.servlet.Filter}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface OrderedFilter extends Filter, Ordered {\n\n\t/**\n\t * Filters that wrap the servlet request should be ordered less than or equal to this.\n\t */\n\tint REQUEST_WRAPPER_FILTER_MAX_ORDER = 0;\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/OrderedFormContentFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.web.filter.FormContentFilter;\n\n/**\n * {@link FormContentFilter} that also implements {@link Ordered}.\n *\n * @author Joao Pedro Evangelista\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class OrderedFormContentFilter extends FormContentFilter implements OrderedFilter {\n\n\t/**\n\t * Higher order to ensure the filter is applied before Spring Security.\n\t */\n\tpublic static final int DEFAULT_ORDER = REQUEST_WRAPPER_FILTER_MAX_ORDER - 9900;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order for this filter.\n\t * @param order the order to set\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/OrderedHiddenHttpMethodFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.web.filter.HiddenHttpMethodFilter;\n\n/**\n * {@link HiddenHttpMethodFilter} that also implements {@link Ordered}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements OrderedFilter {\n\n\t/**\n\t * The default order is high to ensure the filter is applied before Spring Security.\n\t */\n\tpublic static final int DEFAULT_ORDER = REQUEST_WRAPPER_FILTER_MAX_ORDER - 10000;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order for this filter.\n\t * @param order the order to set\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/OrderedRequestContextFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.web.filter.RequestContextFilter;\n\n/**\n * {@link RequestContextFilter} that also implements {@link Ordered}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class OrderedRequestContextFilter extends RequestContextFilter implements OrderedFilter {\n\n\t// Order defaults to after Spring Session filter\n\tprivate int order = REQUEST_WRAPPER_FILTER_MAX_ORDER - 105;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order for this filter.\n\t * @param order the order to set\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/filter/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot specific {@link jakarta.servlet.Filter} implementations.\n */\n@NullMarked\npackage org.springframework.boot.servlet.filter;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/java/org/springframework/boot/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Application support for the {@code jakarta.servlet} specification.\n */\n@NullMarked\npackage org.springframework.boot.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.http.encoding.charset\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"description\": \"Charset of HTTP requests and responses. Added to the Content-Type header if not set explicitly.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.servlet.encoding.charset\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.encoding.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable http encoding support.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.servlet.encoding.enabled\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.encoding.force\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to force the encoding to the configured charset on HTTP requests and responses.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.servlet.encoding.force\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.encoding.force-request\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to force the encoding to the configured charset on HTTP requests. Defaults to true when force has not been specified.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.servlet.encoding.force-request\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.encoding.force-response\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to force the encoding to the configured charset on HTTP responses.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.servlet.encoding.force-response\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.encoding.mapping\",\n      \"type\": \"java.util.Map<java.util.Locale,java.nio.charset.Charset>\",\n      \"description\": \"Locale in which to encode mapping.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.servlet.encoding.mapping\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.http.log-request-details\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether logging of (potentially sensitive) request details at DEBUG and TRACE level is allowed.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mvc.log-request-details\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"spring.servlet.encoding.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Servlet HTTP encoding support.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.servlet.autoconfigure.actuate.web.ServletEndpointManagementContextConfiguration\norg.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementChildContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-servlet/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.servlet.autoconfigure.HttpEncodingAutoConfiguration\norg.springframework.boot.servlet.autoconfigure.MultipartAutoConfiguration\norg.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration\norg.springframework.boot.servlet.autoconfigure.actuate.web.exchanges.ServletHttpExchangesAutoConfiguration\norg.springframework.boot.servlet.autoconfigure.actuate.web.mappings.ServletMappingsAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/MultipartConfigFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MultipartConfigFactory}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass MultipartConfigFactoryTests {\n\n\t@Test\n\tvoid sensibleDefaults() {\n\t\tMultipartConfigFactory factory = new MultipartConfigFactory();\n\t\tMultipartConfigElement config = factory.createMultipartConfig();\n\t\tassertThat(config.getLocation()).isEmpty();\n\t\tassertThat(config.getMaxFileSize()).isEqualTo(-1L);\n\t\tassertThat(config.getMaxRequestSize()).isEqualTo(-1L);\n\t\tassertThat(config.getFileSizeThreshold()).isZero();\n\t}\n\n\t@Test\n\tvoid createWithDataSizes() {\n\t\tMultipartConfigFactory factory = new MultipartConfigFactory();\n\t\tfactory.setMaxFileSize(DataSize.ofBytes(1));\n\t\tfactory.setMaxRequestSize(DataSize.ofKilobytes(2));\n\t\tfactory.setFileSizeThreshold(DataSize.ofMegabytes(3));\n\t\tMultipartConfigElement config = factory.createMultipartConfig();\n\t\tassertThat(config.getMaxFileSize()).isOne();\n\t\tassertThat(config.getMaxRequestSize()).isEqualTo(2 * 1024L);\n\t\tassertThat(config.getFileSizeThreshold()).isEqualTo(3 * 1024 * 1024);\n\t}\n\n\t@Test\n\tvoid createWithNegativeDataSizes() {\n\t\tMultipartConfigFactory factory = new MultipartConfigFactory();\n\t\tfactory.setMaxFileSize(DataSize.ofBytes(-1));\n\t\tfactory.setMaxRequestSize(DataSize.ofKilobytes(-2));\n\t\tfactory.setFileSizeThreshold(DataSize.ofMegabytes(-3));\n\t\tMultipartConfigElement config = factory.createMultipartConfig();\n\t\tassertThat(config.getMaxFileSize()).isEqualTo(-1L);\n\t\tassertThat(config.getMaxRequestSize()).isEqualTo(-1);\n\t\tassertThat(config.getFileSizeThreshold()).isZero();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/actuate/web/exchanges/HttpExchangesFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.exchanges;\n\nimport java.io.IOException;\nimport java.security.Principal;\nimport java.util.EnumSet;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange.Session;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.mock.web.MockFilterChain;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpExchangesFilter}.\n *\n * @author Dave Syer\n * @author Wallace Wadge\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Venil Noronha\n * @author Stephane Nicoll\n * @author Madhura Bhave\n */\nclass HttpExchangesFilterTests {\n\n\tprivate final InMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();\n\n\tprivate final HttpExchangesFilter filter = new HttpExchangesFilter(this.repository, EnumSet.allOf(Include.class));\n\n\t@Test\n\tvoid filterRecordsExchange() throws ServletException, IOException {\n\t\tthis.filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain());\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t}\n\n\t@Test\n\tvoid filterRecordsSessionId() throws ServletException, IOException {\n\t\tthis.filter.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(),\n\t\t\t\tnew MockFilterChain(new HttpServlet() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tprotected void service(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t\t\treq.getSession(true);\n\t\t\t\t\t}\n\n\t\t\t\t}));\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t\tSession session = this.repository.findAll().get(0).getSession();\n\t\tassertThat(session).isNotNull();\n\t\tassertThat(session.getId()).isNotNull();\n\t}\n\n\t@Test\n\tvoid filterRecordsPrincipal() throws ServletException, IOException {\n\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\tPrincipal principal = mock(Principal.class);\n\t\tgiven(principal.getName()).willReturn(\"alice\");\n\t\trequest.setUserPrincipal(principal);\n\t\tthis.filter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t\torg.springframework.boot.actuate.web.exchanges.HttpExchange.Principal recordedPrincipal = this.repository\n\t\t\t.findAll()\n\t\t\t.get(0)\n\t\t\t.getPrincipal();\n\t\tassertThat(recordedPrincipal).isNotNull();\n\t\tassertThat(recordedPrincipal.getName()).isEqualTo(\"alice\");\n\t}\n\n\t@Test\n\tvoid statusIsAssumedToBe500WhenChainFails() {\n\t\tassertThatIOException().isThrownBy(() -> this.filter.doFilter(new MockHttpServletRequest(),\n\t\t\t\tnew MockHttpServletResponse(), new MockFilterChain(new HttpServlet() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tprotected void service(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t\t\tthrow new IOException();\n\t\t\t\t\t}\n\n\t\t\t\t})))\n\t\t\t.satisfies((ex) -> {\n\t\t\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t\t\t\tassertThat(this.repository.findAll().get(0).getResponse().getStatus()).isEqualTo(500);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid filterRejectsInvalidRequests() throws ServletException, IOException {\n\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\trequest.setServerName(\"<script>alert(document.domain)</script>\");\n\t\tthis.filter.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());\n\t\tassertThat(this.repository.findAll()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/actuate/web/exchanges/RecordableServletHttpRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.exchanges;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.mock.web.MockHttpServletRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link RecordableServletHttpRequest}.\n *\n * @author Madhura Bhave\n */\nclass RecordableServletHttpRequestTests {\n\n\tprivate MockHttpServletRequest request;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.request = new MockHttpServletRequest(\"GET\", \"/script\");\n\t}\n\n\t@Test\n\tvoid getUriWithoutQueryStringShouldReturnUri() {\n\t\tvalidate(\"http://localhost/script\");\n\t}\n\n\t@Test\n\tvoid getUriShouldReturnUriWithQueryString() {\n\t\tthis.request.setQueryString(\"a=b\");\n\t\tvalidate(\"http://localhost/script?a=b\");\n\t}\n\n\t@Test\n\tvoid getUriWithSpecialCharactersInQueryStringShouldEncode() {\n\t\tthis.request.setQueryString(\"a=${b}\");\n\t\tvalidate(\"http://localhost/script?a=$%7Bb%7D\");\n\t}\n\n\t@Test\n\tvoid getUriWithSpecialCharactersEncodedShouldNotDoubleEncode() {\n\t\tthis.request.setQueryString(\"a=$%7Bb%7D\");\n\t\tvalidate(\"http://localhost/script?a=$%7Bb%7D\");\n\t}\n\n\tprivate void validate(String expectedUri) {\n\t\tRecordableServletHttpRequest sourceRequest = new RecordableServletHttpRequest(this.request);\n\t\tassertThat(sourceRequest.getUri()).hasToString(expectedUri);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/actuate/web/mappings/FiltersMappingDescriptionProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.servlet.actuate.web.mappings.FiltersMappingDescriptionProvider.FiltersMappingDescriptionProviderRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FiltersMappingDescriptionProvider}.\n *\n * @author Moritz Halbritter\n */\nclass FiltersMappingDescriptionProviderTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew FiltersMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(FilterRegistrationMappingDescription.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/actuate/web/mappings/ServletsMappingDescriptionProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.actuate.web.mappings;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletsMappingDescriptionProvider.ServletsMappingDescriptionProviderRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServletsMappingDescriptionProvider}.\n *\n * @author Moritz Halbritter\n */\nclass ServletsMappingDescriptionProviderTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew ServletsMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(ServletRegistrationMappingDescription.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/HttpEncodingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.servlet.filter.OrderedFormContentFilter;\nimport org.springframework.boot.servlet.filter.OrderedHiddenHttpMethodFilter;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.web.filter.CharacterEncodingFilter;\nimport org.springframework.web.filter.HiddenHttpMethodFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link HttpEncodingAutoConfiguration}\n *\n * @author Stephane Nicoll\n */\nclass HttpEncodingAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class);\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"UTF-8\", true, false);\n\t}\n\n\t@Test\n\tvoid disableConfiguration() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.enabled:false\");\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> context.getBean(CharacterEncodingFilter.class));\n\t}\n\n\t@Test\n\tvoid customConfiguration() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.charset:ISO-8859-15\", \"spring.servlet.encoding.force:false\");\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"ISO-8859-15\", false, false);\n\t}\n\n\t@Test\n\tvoid customFilterConfiguration() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(FilterConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.charset:ISO-8859-15\", \"spring.servlet.encoding.force:false\");\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"US-ASCII\", false, false);\n\t}\n\n\t@Test\n\tvoid forceRequest() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.force-request:false\");\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"UTF-8\", false, false);\n\t}\n\n\t@Test\n\tvoid forceResponse() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.force-response:true\");\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"UTF-8\", true, true);\n\t}\n\n\t@Test\n\tvoid forceRequestOverridesForce() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.force:true\", \"spring.servlet.encoding.force-request:false\");\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"UTF-8\", false, true);\n\t}\n\n\t@Test\n\tvoid forceResponseOverridesForce() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(EmptyConfiguration.class,\n\t\t\t\t\"spring.servlet.encoding.force:true\", \"spring.servlet.encoding.force-response:false\");\n\t\tCharacterEncodingFilter filter = context.getBean(CharacterEncodingFilter.class);\n\t\tassertCharacterEncodingFilter(filter, \"UTF-8\", true, false);\n\t}\n\n\t@Test\n\tvoid filterIsOrderedHighest() {\n\t\tAnnotationConfigServletWebApplicationContext context = load(OrderedConfiguration.class);\n\t\tList<Filter> beans = new ArrayList<>(context.getBeansOfType(Filter.class).values());\n\t\tAnnotationAwareOrderComparator.sort(beans);\n\t\tassertThat(beans.get(0)).isInstanceOf(CharacterEncodingFilter.class);\n\t\tassertThat(beans.get(1)).isInstanceOf(HiddenHttpMethodFilter.class);\n\t}\n\n\tprivate void assertCharacterEncodingFilter(CharacterEncodingFilter actual, String encoding,\n\t\t\tboolean forceRequestEncoding, boolean forceResponseEncoding) {\n\t\tassertThat(actual.getEncoding()).isEqualTo(encoding);\n\t\tassertThat(actual.isForceRequestEncoding()).isEqualTo(forceRequestEncoding);\n\t\tassertThat(actual.isForceResponseEncoding()).isEqualTo(forceResponseEncoding);\n\t}\n\n\tprivate AnnotationConfigServletWebApplicationContext load(Class<?> config, String... environment) {\n\t\tthis.context = doLoad(new Class<?>[] { config }, environment);\n\t\treturn this.context;\n\t}\n\n\tprivate AnnotationConfigServletWebApplicationContext doLoad(Class<?>[] configs, String... environment) {\n\t\tAnnotationConfigServletWebApplicationContext applicationContext = new AnnotationConfigServletWebApplicationContext();\n\t\tTestPropertyValues.of(environment).applyTo(applicationContext);\n\t\tapplicationContext.register(configs);\n\t\tapplicationContext.register(HttpEncodingAutoConfiguration.class);\n\t\tapplicationContext.setServletContext(new MockServletContext());\n\t\tapplicationContext.refresh();\n\t\treturn applicationContext;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EmptyConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterConfiguration {\n\n\t\t@Bean\n\t\tCharacterEncodingFilter myCharacterEncodingFilter() {\n\t\t\tCharacterEncodingFilter filter = new CharacterEncodingFilter();\n\t\t\tfilter.setEncoding(\"US-ASCII\");\n\t\t\tfilter.setForceEncoding(false);\n\t\t\treturn filter;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class OrderedConfiguration {\n\n\t\t@Bean\n\t\tOrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {\n\t\t\treturn new OrderedHiddenHttpMethodFilter();\n\t\t}\n\n\t\t@Bean\n\t\tOrderedFormContentFilter formContentFilter() {\n\t\t\treturn new OrderedFormContentFilter();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/MultipartAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure;\n\nimport java.net.URI;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.multipart.MultipartResolver;\nimport org.springframework.web.multipart.support.StandardServletMultipartResolver;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MultipartAutoConfiguration}. Tests an empty configuration, no\n * multipart configuration, and a multipart configuration (with both Jetty and Tomcat).\n *\n * @author Greg Turnquist\n * @author Dave Syer\n * @author Josh Long\n * @author Ivan Sopov\n * @author Toshiaki Maki\n * @author Yanming Zhou\n */\n@DirtiesUrlFactories\nclass MultipartAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebServerApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid webServerWithNothing() throws Exception {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(WebServerWithNothing.class,\n\t\t\t\tBaseConfiguration.class);\n\t\tDispatcherServlet servlet = this.context.getBean(DispatcherServlet.class);\n\t\tverify404(this.context);\n\t\tassertThat(servlet.getMultipartResolver()).isNotNull();\n\t\tassertThat(this.context.getBeansOfType(StandardServletMultipartResolver.class)).hasSize(1);\n\t\tassertThat(this.context.getBeansOfType(MultipartResolver.class)).hasSize(1);\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"webServerWithNoMultipartConfigurationArguments\")\n\t@ForkedClassPath\n\tvoid webServerWithNoMultipartConfiguration(String server, Class<?> configuration) {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(configuration, BaseConfiguration.class);\n\t\tassertThat(this.context.getBeansOfType(StandardServletMultipartResolver.class)).hasSize(1);\n\t\tassertThat(this.context.getBeansOfType(MultipartResolver.class)).hasSize(1);\n\t\tverifyServletWorks(this.context);\n\t\tassertThat(this.context.getBean(StandardServletMultipartResolver.class))\n\t\t\t.isSameAs(this.context.getBean(DispatcherServlet.class).getMultipartResolver());\n\t}\n\n\tstatic Stream<Arguments> webServerWithNoMultipartConfigurationArguments() {\n\t\treturn Stream.of(Arguments.of(\"Jetty\", WebServerWithNoMultipartJetty.class),\n\t\t\t\tArguments.of(\"Tomcat\", WebServerWithNoMultipartTomcat.class));\n\t}\n\n\t@ParameterizedTest(name = \"{0}\")\n\t@MethodSource(\"webServerWithAutomatedMultipartConfigurationArguments\")\n\t@ForkedClassPath\n\tvoid webServerWithAutomatedMultipartConfiguration(String server, Class<?> configuration) {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(configuration, BaseConfiguration.class);\n\t\tthis.context.getBean(MultipartConfigElement.class);\n\t\tverifyServletWorks(this.context);\n\t\tassertThat(this.context.getBean(StandardServletMultipartResolver.class))\n\t\t\t.isSameAs(this.context.getBean(DispatcherServlet.class).getMultipartResolver());\n\t}\n\n\tstatic Stream<Arguments> webServerWithAutomatedMultipartConfigurationArguments() {\n\t\treturn Stream.of(Arguments.of(\"Jetty\", WebServerWithEverythingJetty.class),\n\t\t\t\tArguments.of(\"Tomcat\", WebServerWithEverythingTomcat.class));\n\t}\n\n\t@Test\n\tvoid webServerWithMultipartConfigDisabled() {\n\t\ttestWebServerWithCustomMultipartConfigEnabledSetting(\"false\", 0);\n\t}\n\n\t@Test\n\tvoid webServerWithMultipartConfigEnabled() {\n\t\ttestWebServerWithCustomMultipartConfigEnabledSetting(\"true\", 1);\n\t}\n\n\tprivate void testWebServerWithCustomMultipartConfigEnabledSetting(final String propertyValue,\n\t\t\tint expectedNumberOfMultipartConfigElementBeans) {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tTestPropertyValues.of(\"spring.servlet.multipart.enabled=\" + propertyValue).applyTo(this.context);\n\t\tthis.context.register(WebServerWithNoMultipartTomcat.class, BaseConfiguration.class);\n\t\tthis.context.refresh();\n\t\tthis.context.getBean(MultipartProperties.class);\n\t\tassertThat(this.context.getBeansOfType(MultipartConfigElement.class))\n\t\t\t.hasSize(expectedNumberOfMultipartConfigElementBeans);\n\t}\n\n\t@Test\n\tvoid webServerWithCustomMultipartResolver() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tWebServerWithCustomMultipartResolver.class, BaseConfiguration.class);\n\t\tMultipartResolver multipartResolver = this.context.getBean(MultipartResolver.class);\n\t\tassertThat(multipartResolver).isNotInstanceOf(StandardServletMultipartResolver.class);\n\t\tassertThat(this.context.getBeansOfType(MultipartConfigElement.class)).hasSize(1);\n\t}\n\n\t@Test\n\tvoid configureResolveLazily() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tTestPropertyValues.of(\"spring.servlet.multipart.resolve-lazily=true\").applyTo(this.context);\n\t\tthis.context.register(WebServerWithNothing.class, BaseConfiguration.class);\n\t\tthis.context.refresh();\n\t\tStandardServletMultipartResolver multipartResolver = this.context\n\t\t\t.getBean(StandardServletMultipartResolver.class);\n\t\tassertThat(multipartResolver).hasFieldOrPropertyWithValue(\"resolveLazily\", true);\n\t}\n\n\t@Test\n\tvoid configureStrictServletCompliance() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tTestPropertyValues.of(\"spring.servlet.multipart.strict-servlet-compliance=true\").applyTo(this.context);\n\t\tthis.context.register(WebServerWithNothing.class, BaseConfiguration.class);\n\t\tthis.context.refresh();\n\t\tStandardServletMultipartResolver multipartResolver = this.context\n\t\t\t.getBean(StandardServletMultipartResolver.class);\n\t\tassertThat(multipartResolver).hasFieldOrPropertyWithValue(\"strictServletCompliance\", true);\n\t}\n\n\t@Test\n\tvoid configureMultipartProperties() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tTestPropertyValues\n\t\t\t.of(\"spring.servlet.multipart.max-file-size=2048KB\", \"spring.servlet.multipart.max-request-size=15MB\")\n\t\t\t.applyTo(this.context);\n\t\tthis.context.register(WebServerWithNothing.class, BaseConfiguration.class);\n\t\tthis.context.refresh();\n\t\tMultipartConfigElement multipartConfigElement = this.context.getBean(MultipartConfigElement.class);\n\t\tassertThat(multipartConfigElement.getMaxFileSize()).isEqualTo(2048 * 1024);\n\t\tassertThat(multipartConfigElement.getMaxRequestSize()).isEqualTo(15 * 1024 * 1024);\n\t}\n\n\t@Test\n\tvoid configureMultipartPropertiesWithRawLongValues() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tTestPropertyValues\n\t\t\t.of(\"spring.servlet.multipart.max-file-size=512\", \"spring.servlet.multipart.max-request-size=2048\")\n\t\t\t.applyTo(this.context);\n\t\tthis.context.register(WebServerWithNothing.class, BaseConfiguration.class);\n\t\tthis.context.refresh();\n\t\tMultipartConfigElement multipartConfigElement = this.context.getBean(MultipartConfigElement.class);\n\t\tassertThat(multipartConfigElement.getMaxFileSize()).isEqualTo(512);\n\t\tassertThat(multipartConfigElement.getMaxRequestSize()).isEqualTo(2048);\n\t}\n\n\tprivate void verify404(AnnotationConfigServletWebServerApplicationContext context) throws Exception {\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();\n\t\tWebServer webServer = context.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tClientHttpRequest request = requestFactory\n\t\t\t.createRequest(new URI(\"http://localhost:\" + webServer.getPort() + \"/\"), HttpMethod.GET);\n\t\ttry (ClientHttpResponse response = request.execute()) {\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\t}\n\t}\n\n\tprivate void verifyServletWorks(AnnotationConfigServletWebServerApplicationContext context) {\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tWebServer webServer = context.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tString url = \"http://localhost:\" + webServer.getPort() + \"/\";\n\t\tassertThat(restTemplate.getForObject(url, String.class)).isEqualTo(\"Hello\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerWithNothing {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerWithNoMultipartJetty {\n\n\t\t@Bean\n\t\tJettyServletWebServerFactory webServerFactory() {\n\t\t\treturn new JettyServletWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tWebController controller() {\n\t\t\treturn new WebController();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, MultipartAutoConfiguration.class })\n\t@EnableConfigurationProperties(MultipartProperties.class)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tServerProperties serverProperties() {\n\t\t\tServerProperties properties = new ServerProperties();\n\t\t\tproperties.setPort(0);\n\t\t\treturn properties;\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerWithNoMultipartTomcat {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tWebController controller() {\n\t\t\treturn new WebController();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerWithEverythingJetty {\n\n\t\t@Bean\n\t\tMultipartConfigElement multipartConfigElement() {\n\t\t\treturn new MultipartConfigElement(\"\");\n\t\t}\n\n\t\t@Bean\n\t\tJettyServletWebServerFactory webServerFactory() {\n\t\t\treturn new JettyServletWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tWebController webController() {\n\t\t\treturn new WebController();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class WebServerWithEverythingTomcat {\n\n\t\t@Bean\n\t\tMultipartConfigElement multipartConfigElement() {\n\t\t\treturn new MultipartConfigElement(\"\");\n\t\t}\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tWebController webController() {\n\t\t\treturn new WebController();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerWithCustomMultipartResolver {\n\n\t\t@Bean\n\t\tMultipartResolver multipartResolver() {\n\t\t\treturn mock(MultipartResolver.class);\n\t\t}\n\n\t}\n\n\t@Controller\n\tstatic class WebController {\n\n\t\t@RequestMapping(\"/\")\n\t\t@ResponseBody\n\t\tString index() {\n\t\t\treturn \"Hello\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ServletManagementChildContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServletManagementChildContextConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass ServletManagementChildContextConfigurationTests {\n\n\t@Test // gh-45857\n\tvoid doesNotCreateManagementServerPropertiesInChildContext() {\n\t\tnew WebApplicationContextRunner().withBean(ManagementServerProperties.class)\n\t\t\t.run((parent) -> new WebApplicationContextRunner().withParent(parent)\n\t\t\t\t.withUserConfiguration(ServletManagementChildContextConfiguration.class)\n\t\t\t\t.run((context) -> assertThat(context.getBean(ManagementServerProperties.class))\n\t\t\t\t\t.isSameAs(parent.getBean(ManagementServerProperties.class))));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/actuate/web/ServletManagementContextAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.env.PropertySourceInfo;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementContextAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ServletManagementContextAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ServletManagementContextAutoConfigurationIntegrationTests {\n\n\t@Test\n\tvoid childManagementContextShouldStartForEmbeddedServer(CapturedOutput output) {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class,\n\t\t\t\t\tTomcatServletManagementContextAutoConfiguration.class,\n\t\t\t\t\tServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\tEndpointAutoConfiguration.class));\n\t\tcontextRunner.withPropertyValues(\"server.port=0\", \"management.server.port=0\")\n\t\t\t.run((context) -> assertThat(output).satisfies(numberOfOccurrences(\"Tomcat started on port\", 2)));\n\t}\n\n\t@Test\n\tvoid childManagementContextShouldNotStartWithoutEmbeddedServer(CapturedOutput output) {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class,\n\t\t\t\t\tTomcatServletManagementContextAutoConfiguration.class,\n\t\t\t\t\tServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\tEndpointAutoConfiguration.class));\n\t\tcontextRunner.withPropertyValues(\"server.port=0\", \"management.server.port=0\").run((context) -> {\n\t\t\tassertThat(context).hasNotFailed();\n\t\t\tassertThat(output).doesNotContain(\"Tomcat started\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid childManagementContextShouldRestartWhenParentIsStoppedThenStarted(CapturedOutput output) {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class,\n\t\t\t\t\tTomcatServletManagementContextAutoConfiguration.class,\n\t\t\t\t\tServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\tEndpointAutoConfiguration.class));\n\t\tcontextRunner.withPropertyValues(\"server.port=0\", \"management.server.port=0\").run((context) -> {\n\t\t\tassertThat(output).satisfies(numberOfOccurrences(\"Tomcat started on port\", 2));\n\t\t\tcontext.getSourceApplicationContext().stop();\n\t\t\tcontext.getSourceApplicationContext().start();\n\t\t\tassertThat(output).satisfies(numberOfOccurrences(\"Tomcat started on port\", 4));\n\t\t});\n\t}\n\n\t@Test\n\tvoid givenSamePortManagementServerWhenManagementServerAddressIsConfiguredThenContextRefreshFails() {\n\t\tWebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,\n\t\t\t\t\tWebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class));\n\t\tcontextRunner.withPropertyValues(\"server.port=0\", \"management.server.address=127.0.0.1\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.hasMessageStartingWith(\"Management-specific server address cannot be configured\"));\n\t}\n\n\t@Test // gh-45858\n\tvoid childEnvironmentShouldInheritPrefix() throws Exception {\n\t\tSpringApplication application = new SpringApplication(ChildEnvironmentConfiguration.class);\n\t\tMap<String, Object> properties = new LinkedHashMap<>();\n\t\tproperties.put(\"server.port\", \"0\");\n\t\tproperties.put(\"management.server.port\", \"0\");\n\t\tapplication.setDefaultProperties(properties);\n\t\tapplication.setEnvironmentPrefix(\"my\");\n\t\ttry (ConfigurableApplicationContext parentContext = application.run()) {\n\t\t\tClass<?> initializerClass = ClassUtils.forName(\n\t\t\t\t\t\"org.springframework.boot.actuate.autoconfigure.web.server.ChildManagementContextInitializer\",\n\t\t\t\t\tnull);\n\t\t\tObject initializer = parentContext.getBean(initializerClass);\n\t\t\tConfigurableApplicationContext managementContext = (ConfigurableApplicationContext) ReflectionTestUtils\n\t\t\t\t.getField(initializer, \"managementContext\");\n\t\t\tassertThat(managementContext).isNotNull();\n\t\t\tConfigurableEnvironment managementEnvironment = managementContext.getEnvironment();\n\t\t\tassertThat(managementEnvironment).isNotNull();\n\t\t\tPropertySource<?> systemEnvironmentPropertySource = managementEnvironment.getPropertySources()\n\t\t\t\t.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);\n\t\t\tassertThat(systemEnvironmentPropertySource).isNotNull();\n\t\t\tassertThat(((PropertySourceInfo) systemEnvironmentPropertySource).getPrefix()).isEqualTo(\"my\");\n\t\t}\n\t}\n\n\tprivate <T extends CharSequence> Consumer<T> numberOfOccurrences(String substring, int expectedCount) {\n\t\treturn (charSequence) -> {\n\t\t\tint count = StringUtils.countOccurrencesOf(charSequence.toString(), substring);\n\t\t\tassertThat(count).isEqualTo(expectedCount);\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration({ ManagementContextAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,\n\t\t\tTomcatServletManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,\n\t\t\tWebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class })\n\tstatic class ChildEnvironmentConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/actuate/web/exchanges/ServletHttpExchangesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web.exchanges;\n\nimport java.util.EnumSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.servlet.actuate.web.exchanges.HttpExchangesFilter;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServletHttpExchangesAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ServletHttpExchangesAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ServletHttpExchangesAutoConfiguration.class));\n\n\t@Test\n\tvoid whenRecordingIsDisabledThenFilterIsNotCreated() {\n\t\tthis.contextRunner.withBean(InMemoryHttpExchangeRepository.class)\n\t\t\t.withPropertyValues(\"management.httpexchanges.recording.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesFilter.class));\n\t}\n\n\t@Test\n\tvoid whenNoRepositoryIsDefinedThenFilterIsNotCreated() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesFilter.class));\n\t}\n\n\t@Test\n\tvoid filterIsCreated() {\n\t\tthis.contextRunner.withBean(InMemoryHttpExchangeRepository.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HttpExchangesFilter.class));\n\t}\n\n\t@Test\n\tvoid usesUserProvidedWebFilter() {\n\t\tInMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();\n\t\tthis.contextRunner.withBean(InMemoryHttpExchangeRepository.class, () -> repository)\n\t\t\t.withBean(CustomHttpExchangesFilter.class,\n\t\t\t\t\t() -> new CustomHttpExchangesFilter(repository, EnumSet.allOf(Include.class)))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpExchangesFilter.class);\n\t\t\t\tassertThat(context.getBean(HttpExchangesFilter.class)).isInstanceOf(CustomHttpExchangesFilter.class);\n\t\t\t});\n\t}\n\n\tprivate static final class CustomHttpExchangesFilter extends HttpExchangesFilter {\n\n\t\tprivate CustomHttpExchangesFilter(HttpExchangeRepository repository, Set<Include> includes) {\n\t\t\tsuper(repository, includes);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/autoconfigure/actuate/web/mappings/ServletMappingsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.autoconfigure.actuate.web.mappings;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.servlet.actuate.web.mappings.FiltersMappingDescriptionProvider;\nimport org.springframework.boot.servlet.actuate.web.mappings.ServletsMappingDescriptionProvider;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServletMappingsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass ServletMappingsAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ServletMappingsAutoConfiguration.class));\n\n\t@Test\n\tvoid whenEndpointIsUnavailableThenDescriptionProvidersAreNotCreated() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(FiltersMappingDescriptionProvider.class)\n\t\t\t.doesNotHaveBean(ServletsMappingDescriptionProvider.class));\n\t}\n\n\t@Test\n\tvoid whenEndpointIsAvailableThenDescriptionProvidersAreCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=mappings\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(FiltersMappingDescriptionProvider.class)\n\t\t\t\t.hasSingleBean(ServletsMappingDescriptionProvider.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-servlet/src/test/java/org/springframework/boot/servlet/filter/OrderedFilterOrderingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.servlet.filter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.within;\n\n/**\n * Tests for the ordering of various {@link OrderedFilter} implementations.\n *\n * @author Andy Wilkinson\n */\nclass OrderedFilterOrderingTests {\n\n\t@Test\n\tvoid ordering() {\n\t\tOrderedCharacterEncodingFilter characterEncoding = new OrderedCharacterEncodingFilter();\n\t\tOrderedFormContentFilter formContent = new OrderedFormContentFilter();\n\t\tOrderedHiddenHttpMethodFilter hiddenHttpMethod = new OrderedHiddenHttpMethodFilter();\n\t\tOrderedRequestContextFilter requestContext = new OrderedRequestContextFilter();\n\t\tList<OrderedFilter> filters = new ArrayList<>(\n\t\t\t\tList.of(characterEncoding, formContent, hiddenHttpMethod, requestContext));\n\t\tAnnotationAwareOrderComparator.sort(filters);\n\t\tassertThat(filters).containsExactly(characterEncoding, hiddenHttpMethod, formContent, requestContext);\n\t}\n\n\t@Test\n\tvoid requestContextOrderingIsCloseToRequestWrapperFilterMaxOrder() {\n\t\tassertThat(new OrderedRequestContextFilter().getOrder())\n\t\t\t.isCloseTo(OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER, within(105));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Session\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework.session:spring-session-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework.security:spring-security-web\")\n\n\ttestFixturesImplementation(project(\":core:spring-boot-test\"))\n\ttestFixturesImplementation(project(\":module:spring-boot-reactor\"))\n\ttestFixturesImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestFixturesImplementation(testFixtures(project(\":core:spring-boot\")))\n\ttestFixturesImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestFixturesImplementation(\"io.projectreactor:reactor-core\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-webflux\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-jersey\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webflux\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-webmvc\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(\"net.minidev:json-smart\")\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/actuate/endpoint/ReactiveSessionsEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;\nimport org.springframework.session.ReactiveFindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.Session;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose information about HTTP {@link Session}s on a\n * reactive stack.\n *\n * @author Vedran Pavic\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@Endpoint(id = \"sessions\")\npublic class ReactiveSessionsEndpoint {\n\n\tprivate final ReactiveSessionRepository<? extends Session> sessionRepository;\n\n\tprivate final @Nullable ReactiveFindByIndexNameSessionRepository<? extends Session> indexedSessionRepository;\n\n\t/**\n\t * Create a new {@link ReactiveSessionsEndpoint} instance.\n\t * @param sessionRepository the session repository\n\t * @param indexedSessionRepository the indexed session repository\n\t */\n\tpublic ReactiveSessionsEndpoint(ReactiveSessionRepository<? extends Session> sessionRepository,\n\t\t\t@Nullable ReactiveFindByIndexNameSessionRepository<? extends Session> indexedSessionRepository) {\n\t\tAssert.notNull(sessionRepository, \"'sessionRepository' must not be null\");\n\t\tthis.sessionRepository = sessionRepository;\n\t\tthis.indexedSessionRepository = indexedSessionRepository;\n\t}\n\n\t@ReadOperation\n\tpublic Mono<SessionsDescriptor> sessionsForUsername(String username) {\n\t\tif (this.indexedSessionRepository == null) {\n\t\t\treturn Mono.empty();\n\t\t}\n\t\treturn this.indexedSessionRepository.findByPrincipalName(username).map(SessionsDescriptor::new);\n\t}\n\n\t@ReadOperation\n\tpublic Mono<SessionDescriptor> getSession(@Selector String sessionId) {\n\t\treturn this.sessionRepository.findById(sessionId).map(SessionDescriptor::new);\n\t}\n\n\t@DeleteOperation\n\tpublic Mono<Void> deleteSession(@Selector String sessionId) {\n\t\treturn this.sessionRepository.deleteById(sessionId);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/actuate/endpoint/SessionsDescriptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport java.time.Instant;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.session.Session;\n\n/**\n * Description of user's {@link Session sessions}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic final class SessionsDescriptor implements OperationResponseBody {\n\n\tprivate final List<SessionDescriptor> sessions;\n\n\tpublic SessionsDescriptor(Map<String, ? extends Session> sessions) {\n\t\tthis.sessions = sessions.values().stream().map(SessionDescriptor::new).toList();\n\t}\n\n\tpublic List<SessionDescriptor> getSessions() {\n\t\treturn this.sessions;\n\t}\n\n\t/**\n\t * A description of user's {@link Session session} exposed by {@code sessions}\n\t * endpoint. Primarily intended for serialization to JSON.\n\t */\n\tpublic static final class SessionDescriptor {\n\n\t\tprivate final String id;\n\n\t\tprivate final Set<String> attributeNames;\n\n\t\tprivate final Instant creationTime;\n\n\t\tprivate final Instant lastAccessedTime;\n\n\t\tprivate final long maxInactiveInterval;\n\n\t\tprivate final boolean expired;\n\n\t\tSessionDescriptor(Session session) {\n\t\t\tthis.id = session.getId();\n\t\t\tthis.attributeNames = session.getAttributeNames();\n\t\t\tthis.creationTime = session.getCreationTime();\n\t\t\tthis.lastAccessedTime = session.getLastAccessedTime();\n\t\t\tthis.maxInactiveInterval = session.getMaxInactiveInterval().getSeconds();\n\t\t\tthis.expired = session.isExpired();\n\t\t}\n\n\t\tpublic String getId() {\n\t\t\treturn this.id;\n\t\t}\n\n\t\tpublic Set<String> getAttributeNames() {\n\t\t\treturn this.attributeNames;\n\t\t}\n\n\t\tpublic Instant getCreationTime() {\n\t\t\treturn this.creationTime;\n\t\t}\n\n\t\tpublic Instant getLastAccessedTime() {\n\t\t\treturn this.lastAccessedTime;\n\t\t}\n\n\t\tpublic long getMaxInactiveInterval() {\n\t\t\treturn this.maxInactiveInterval;\n\t\t}\n\n\t\tpublic boolean isExpired() {\n\t\t\treturn this.expired;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/actuate/endpoint/SessionsEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.actuate.endpoint.annotation.Selector;\nimport org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;\nimport org.springframework.session.FindByIndexNameSessionRepository;\nimport org.springframework.session.Session;\nimport org.springframework.session.SessionRepository;\nimport org.springframework.util.Assert;\n\n/**\n * {@link Endpoint @Endpoint} to expose information about HTTP {@link Session}s on a\n * Servlet stack.\n *\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@Endpoint(id = \"sessions\")\npublic class SessionsEndpoint {\n\n\tprivate final SessionRepository<? extends Session> sessionRepository;\n\n\tprivate final @Nullable FindByIndexNameSessionRepository<? extends Session> indexedSessionRepository;\n\n\t/**\n\t * Create a new {@link SessionsEndpoint} instance.\n\t * @param sessionRepository the session repository\n\t * @param indexedSessionRepository the indexed session repository\n\t */\n\tpublic SessionsEndpoint(SessionRepository<? extends Session> sessionRepository,\n\t\t\t@Nullable FindByIndexNameSessionRepository<? extends Session> indexedSessionRepository) {\n\t\tAssert.notNull(sessionRepository, \"'sessionRepository' must not be null\");\n\t\tthis.sessionRepository = sessionRepository;\n\t\tthis.indexedSessionRepository = indexedSessionRepository;\n\t}\n\n\t@ReadOperation\n\tpublic @Nullable SessionsDescriptor sessionsForUsername(String username) {\n\t\tif (this.indexedSessionRepository == null) {\n\t\t\treturn null;\n\t\t}\n\t\tMap<String, ? extends Session> sessions = this.indexedSessionRepository.findByPrincipalName(username);\n\t\treturn new SessionsDescriptor(sessions);\n\t}\n\n\t@ReadOperation\n\tpublic @Nullable SessionDescriptor getSession(@Selector String sessionId) {\n\t\tSession session = this.sessionRepository.findById(sessionId);\n\t\tif (session == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new SessionDescriptor(session);\n\t}\n\n\t@DeleteOperation\n\tpublic void deleteSession(@Selector String sessionId) {\n\t\tthis.sessionRepository.deleteById(sessionId);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/actuate/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator endpoint for Spring Session.\n */\n@NullMarked\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/DefaultCookieSerializerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport org.springframework.session.web.http.DefaultCookieSerializer;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link DefaultCookieSerializer} configuration.\n *\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface DefaultCookieSerializerCustomizer {\n\n\t/**\n\t * Customize the cookie serializer.\n\t * @param cookieSerializer the {@code DefaultCookieSerializer} to customize\n\t */\n\tvoid customize(DefaultCookieSerializer cookieSerializer);\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/SessionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.SessionCookieConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWarDeployment;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.web.server.Cookie;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.security.web.authentication.RememberMeServices;\nimport org.springframework.session.Session;\nimport org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;\nimport org.springframework.session.web.http.CookieHttpSessionIdResolver;\nimport org.springframework.session.web.http.CookieSerializer;\nimport org.springframework.session.web.http.DefaultCookieSerializer;\nimport org.springframework.session.web.http.HttpSessionIdResolver;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.ServletContextAware;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Session.\n *\n * @author Andy Wilkinson\n * @author Tommy Ludwig\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Weix Sun\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Session.class)\n@ConditionalOnWebApplication\n@EnableConfigurationProperties(SessionProperties.class)\npublic final class SessionAutoConfiguration {\n\n\tprivate static Duration determineTimeout(SessionProperties sessionProperties, Supplier<Duration> fallbackTimeout) {\n\t\tDuration timeout = sessionProperties.getTimeout();\n\t\treturn (timeout != null) ? timeout : fallbackTimeout.get();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\t@Import(SessionRepositoryFilterConfiguration.class)\n\tstatic class ServletSessionConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(RememberMeServices.class)\n\t\tstatic class RememberMeServicesConfiguration {\n\n\t\t\t@Bean\n\t\t\tDefaultCookieSerializerCustomizer rememberMeServicesCookieSerializerCustomizer() {\n\t\t\t\treturn (cookieSerializer) -> cookieSerializer\n\t\t\t\t\t.setRememberMeRequestAttribute(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);\n\t\t\t}\n\n\t\t}\n\n\t\t@ConditionalOnNotWarDeployment\n\t\t@EnableConfigurationProperties(ServerProperties.class)\n\t\tstatic class EmbeddedWebServerConfiguration {\n\n\t\t\t@Bean\n\t\t\tSessionTimeout embeddedWebServerSessionTimeout(SessionProperties sessionProperties,\n\t\t\t\t\tServerProperties serverProperties) {\n\t\t\t\treturn () -> determineTimeout(sessionProperties,\n\t\t\t\t\t\tserverProperties.getServlet().getSession()::getTimeout);\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Conditional(DefaultCookieSerializerCondition.class)\n\t\t\tDefaultCookieSerializer cookieSerializer(ServerProperties serverProperties,\n\t\t\t\t\tObjectProvider<DefaultCookieSerializerCustomizer> cookieSerializerCustomizers) {\n\t\t\t\tCookie cookie = serverProperties.getServlet().getSession().getCookie();\n\t\t\t\tDefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(cookie::getName).to(cookieSerializer::setCookieName);\n\t\t\t\tmap.from(cookie::getDomain).to(cookieSerializer::setDomainName);\n\t\t\t\tmap.from(cookie::getPath).to(cookieSerializer::setCookiePath);\n\t\t\t\tmap.from(cookie::getHttpOnly).to(cookieSerializer::setUseHttpOnlyCookie);\n\t\t\t\tmap.from(cookie::getSecure).to(cookieSerializer::setUseSecureCookie);\n\t\t\t\tmap.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(cookieSerializer::setCookieMaxAge);\n\t\t\t\tmap.from(cookie::getSameSite).to((sameSite) -> cookieSerializer.setSameSite(sameSite.attributeValue()));\n\t\t\t\tmap.from(cookie::getPartitioned).to(cookieSerializer::setPartitioned);\n\t\t\t\tcookieSerializerCustomizers.orderedStream()\n\t\t\t\t\t.forEach((customizer) -> customizer.customize(cookieSerializer));\n\t\t\t\treturn cookieSerializer;\n\t\t\t}\n\n\t\t}\n\n\t\t@ConditionalOnWarDeployment\n\t\tstatic class WarDepoymentConfiguration implements ServletContextAware {\n\n\t\t\tprivate @Nullable ServletContext servletContext;\n\n\t\t\t@Override\n\t\t\tpublic void setServletContext(ServletContext servletContext) {\n\t\t\t\tthis.servletContext = servletContext;\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\tSessionTimeout warDeplomentSessionTimeout(SessionProperties sessionProperties) {\n\t\t\t\treturn sessionProperties::getTimeout;\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Conditional(DefaultCookieSerializerCondition.class)\n\t\t\tDefaultCookieSerializer cookieSerializer(\n\t\t\t\t\tObjectProvider<DefaultCookieSerializerCustomizer> cookieSerializerCustomizers) {\n\t\t\t\tDefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tAssert.notNull(this.servletContext,\n\t\t\t\t\t\t\"ServletContext is required for session configuration in a war deployment\");\n\t\t\t\tSessionCookieConfig cookie = this.servletContext.getSessionCookieConfig();\n\t\t\t\tmap.from(cookie::getName).to(cookieSerializer::setCookieName);\n\t\t\t\tmap.from(cookie::getDomain).to(cookieSerializer::setDomainName);\n\t\t\t\tmap.from(cookie::getPath).to(cookieSerializer::setCookiePath);\n\t\t\t\tmap.from(cookie::isHttpOnly).to(cookieSerializer::setUseHttpOnlyCookie);\n\t\t\t\tmap.from(cookie::isSecure).to(cookieSerializer::setUseSecureCookie);\n\t\t\t\tmap.from(cookie::getMaxAge).to(cookieSerializer::setCookieMaxAge);\n\t\t\t\tmap.from(cookie.getAttribute(\"SameSite\")).always().to(cookieSerializer::setSameSite);\n\t\t\t\tmap.from(cookie.getAttribute(\"Partitioned\")).as(Boolean::valueOf).to(cookieSerializer::setPartitioned);\n\t\t\t\tcookieSerializerCustomizers.orderedStream()\n\t\t\t\t\t.forEach((customizer) -> customizer.customize(cookieSerializer));\n\t\t\t\treturn cookieSerializer;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\tstatic class ReactiveSessionConfiguration {\n\n\t\t@Bean\n\t\tSessionTimeout embeddedWebServerSessionTimeout(SessionProperties sessionProperties,\n\t\t\t\tServerProperties serverProperties) {\n\t\t\treturn () -> determineTimeout(sessionProperties, serverProperties.getReactive().getSession()::getTimeout);\n\t\t}\n\n\t}\n\n\t/**\n\t * Condition to trigger the creation of a {@link DefaultCookieSerializer}. This kicks\n\t * in if either no {@link HttpSessionIdResolver} and {@link CookieSerializer} beans\n\t * are registered, or if {@link CookieHttpSessionIdResolver} is registered but\n\t * {@link CookieSerializer} is not.\n\t */\n\tstatic class DefaultCookieSerializerCondition extends AnyNestedCondition {\n\n\t\tDefaultCookieSerializerCondition() {\n\t\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t\t}\n\n\t\t@ConditionalOnMissingBean({ HttpSessionIdResolver.class, CookieSerializer.class })\n\t\tstatic class NoComponentsAvailable {\n\n\t\t}\n\n\t\t@ConditionalOnBean(CookieHttpSessionIdResolver.class)\n\t\t@ConditionalOnMissingBean(CookieSerializer.class)\n\t\tstatic class CookieHttpSessionIdResolverAvailable {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/SessionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.boot.web.servlet.DispatcherType;\nimport org.springframework.session.web.http.SessionRepositoryFilter;\n\n/**\n * Configuration properties for Spring Session.\n *\n * @author Tommy Ludwig\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.session\")\npublic class SessionProperties {\n\n\t/**\n\t * Session timeout. If a duration suffix is not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate @Nullable Duration timeout;\n\n\tprivate Servlet servlet = new Servlet();\n\n\tpublic @Nullable Duration getTimeout() {\n\t\treturn this.timeout;\n\t}\n\n\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic void setServlet(Servlet servlet) {\n\t\tthis.servlet = servlet;\n\t}\n\n\t/**\n\t * Determine the session timeout. If no timeout is configured, the\n\t * {@code fallbackTimeout} is used.\n\t * @param fallbackTimeout a fallback timeout value if the timeout isn't configured\n\t * @return the session timeout\n\t * @deprecated since 4.0.1 for removal in 4.2.0 in favor of {@link SessionTimeout}\n\t */\n\t@Deprecated(since = \"4.0.1\", forRemoval = true)\n\tpublic Duration determineTimeout(Supplier<Duration> fallbackTimeout) {\n\t\treturn (this.timeout != null) ? this.timeout : fallbackTimeout.get();\n\t}\n\n\t/**\n\t * Servlet-related properties.\n\t */\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Session repository filter order.\n\t\t */\n\t\tprivate int filterOrder = SessionRepositoryFilter.DEFAULT_ORDER;\n\n\t\t/**\n\t\t * Session repository filter dispatcher types.\n\t\t */\n\t\tprivate Set<DispatcherType> filterDispatcherTypes = new HashSet<>(\n\t\t\t\tArrays.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));\n\n\t\tpublic int getFilterOrder() {\n\t\t\treturn this.filterOrder;\n\t\t}\n\n\t\tpublic void setFilterOrder(int filterOrder) {\n\t\t\tthis.filterOrder = filterOrder;\n\t\t}\n\n\t\tpublic Set<DispatcherType> getFilterDispatcherTypes() {\n\t\t\treturn this.filterDispatcherTypes;\n\t\t}\n\n\t\tpublic void setFilterDispatcherTypes(Set<DispatcherType> filterDispatcherTypes) {\n\t\t\tthis.filterDispatcherTypes = filterDispatcherTypes;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/SessionRepositoryFilterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.util.EnumSet;\nimport java.util.stream.Collectors;\n\nimport jakarta.servlet.DispatcherType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.web.http.SessionRepositoryFilter;\nimport org.springframework.util.Assert;\n\n/**\n * Configuration for customizing the registration of the {@link SessionRepositoryFilter}.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnBean(SessionRepositoryFilter.class)\n@EnableConfigurationProperties(SessionProperties.class)\nclass SessionRepositoryFilterConfiguration {\n\n\t@Bean\n\tDelegatingFilterProxyRegistrationBean sessionRepositoryFilterRegistration(SessionProperties sessionProperties,\n\t\t\tListableBeanFactory beanFactory) {\n\t\tString[] targetBeanNames = beanFactory.getBeanNamesForType(SessionRepositoryFilter.class, false, false);\n\t\tAssert.state(targetBeanNames.length == 1, \"Expected single SessionRepositoryFilter bean\");\n\t\tDelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(\n\t\t\t\ttargetBeanNames[0]);\n\t\tregistration.setDispatcherTypes(getDispatcherTypes(sessionProperties));\n\t\tregistration.setOrder(sessionProperties.getServlet().getFilterOrder());\n\t\treturn registration;\n\t}\n\n\tprivate @Nullable EnumSet<DispatcherType> getDispatcherTypes(SessionProperties sessionProperties) {\n\t\tSessionProperties.Servlet servletProperties = sessionProperties.getServlet();\n\t\tif (servletProperties.getFilterDispatcherTypes() == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn servletProperties.getFilterDispatcherTypes()\n\t\t\t.stream()\n\t\t\t.map((type) -> DispatcherType.valueOf(type.name()))\n\t\t\t.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/SessionTimeout.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Provides access to the configured session timeout. The timeout is available\n * irrespective of the deployment type:\n * <ul>\n * <li>a servlet web application\n * <ul>\n * <li>using an embedded web server\n * <li>deployed as a war file\n * </ul>\n * <li>a reactive web application\n * </ul>\n *\n * @author Andy Wilkinson\n * @since 4.0.1\n */\n@FunctionalInterface\npublic interface SessionTimeout {\n\n\t/**\n\t * Returns the session timeout or {@code null} if no timeout has been configured.\n\t * @return the timeout or {@code null}\n\t */\n\t@Nullable Duration getTimeout();\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/SessionsEndpointAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.session.actuate.endpoint.ReactiveSessionsEndpoint;\nimport org.springframework.boot.session.actuate.endpoint.SessionsEndpoint;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.FindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveFindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.Session;\nimport org.springframework.session.SessionRepository;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link SessionsEndpoint}.\n *\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@AutoConfiguration(after = SessionAutoConfiguration.class)\n@ConditionalOnClass({ Session.class, SessionsEndpoint.class, ConditionalOnAvailableEndpoint.class })\n@ConditionalOnAvailableEndpoint(SessionsEndpoint.class)\npublic final class SessionsEndpointAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\t@ConditionalOnBean(SessionRepository.class)\n\tstatic class ServletSessionEndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSessionsEndpoint sessionEndpoint(SessionRepository<?> sessionRepository,\n\t\t\t\tObjectProvider<FindByIndexNameSessionRepository<?>> indexedSessionRepository) {\n\t\t\treturn new SessionsEndpoint(sessionRepository, indexedSessionRepository.getIfAvailable());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t@ConditionalOnBean(ReactiveSessionRepository.class)\n\tstatic class ReactiveSessionEndpointConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tReactiveSessionsEndpoint sessionsEndpoint(ReactiveSessionRepository<?> sessionRepository,\n\t\t\t\tObjectProvider<ReactiveFindByIndexNameSessionRepository<?>> indexedSessionRepository) {\n\t\t\treturn new ReactiveSessionsEndpoint(sessionRepository, indexedSessionRepository.getIfAvailable());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/java/org/springframework/boot/session/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Session.\n */\n@NullMarked\npackage org.springframework.boot.session.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-session/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.session.servlet.filter-dispatcher-types\",\n      \"defaultValue\": [\n        \"async\",\n        \"error\",\n        \"request\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.session.autoconfigure.SessionAutoConfiguration\norg.springframework.boot.session.autoconfigure.SessionsEndpointAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/actuate/endpoint/ReactiveSessionsEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;\nimport org.springframework.session.MapSession;\nimport org.springframework.session.ReactiveFindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.Session;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveSessionsEndpoint}.\n *\n * @author Vedran Pavic\n * @author Moritz Halbritter\n */\nclass ReactiveSessionsEndpointTests {\n\n\tprivate static final Session session = new MapSession();\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate final ReactiveSessionRepository<Session> sessionRepository = mock(ReactiveSessionRepository.class);\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate final ReactiveFindByIndexNameSessionRepository<Session> indexedSessionRepository = mock(\n\t\t\tReactiveFindByIndexNameSessionRepository.class);\n\n\tprivate final ReactiveSessionsEndpoint endpoint = new ReactiveSessionsEndpoint(this.sessionRepository,\n\t\t\tthis.indexedSessionRepository);\n\n\t@Test\n\tvoid sessionsForUsername() {\n\t\tgiven(this.indexedSessionRepository.findByPrincipalName(\"user\"))\n\t\t\t.willReturn(Mono.just(Collections.singletonMap(session.getId(), session)));\n\t\tStepVerifier.create(this.endpoint.sessionsForUsername(\"user\")).consumeNextWith((sessions) -> {\n\t\t\tList<SessionDescriptor> result = sessions.getSessions();\n\t\t\tassertThat(result).hasSize(1);\n\t\t\tassertThat(result.get(0).getId()).isEqualTo(session.getId());\n\t\t\tassertThat(result.get(0).getAttributeNames()).isEqualTo(session.getAttributeNames());\n\t\t\tassertThat(result.get(0).getCreationTime()).isEqualTo(session.getCreationTime());\n\t\t\tassertThat(result.get(0).getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());\n\t\t\tassertThat(result.get(0).getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());\n\t\t\tassertThat(result.get(0).isExpired()).isEqualTo(session.isExpired());\n\t\t}).expectComplete().verify(Duration.ofSeconds(1));\n\t\tthen(this.indexedSessionRepository).should().findByPrincipalName(\"user\");\n\t}\n\n\t@Test\n\tvoid sessionsForUsernameWhenNoIndexedRepository() {\n\t\tReactiveSessionsEndpoint endpoint = new ReactiveSessionsEndpoint(this.sessionRepository, null);\n\t\tStepVerifier.create(endpoint.sessionsForUsername(\"user\")).expectComplete().verify(Duration.ofSeconds(1));\n\t}\n\n\t@Test\n\tvoid getSession() {\n\t\tgiven(this.sessionRepository.findById(session.getId())).willReturn(Mono.just(session));\n\t\tStepVerifier.create(this.endpoint.getSession(session.getId())).consumeNextWith((result) -> {\n\t\t\tassertThat(result.getId()).isEqualTo(session.getId());\n\t\t\tassertThat(result.getAttributeNames()).isEqualTo(session.getAttributeNames());\n\t\t\tassertThat(result.getCreationTime()).isEqualTo(session.getCreationTime());\n\t\t\tassertThat(result.getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());\n\t\t\tassertThat(result.getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());\n\t\t\tassertThat(result.isExpired()).isEqualTo(session.isExpired());\n\t\t}).expectComplete().verify(Duration.ofSeconds(1));\n\t\tthen(this.sessionRepository).should().findById(session.getId());\n\t}\n\n\t@Test\n\tvoid getSessionWithIdNotFound() {\n\t\tgiven(this.sessionRepository.findById(\"not-found\")).willReturn(Mono.empty());\n\t\tStepVerifier.create(this.endpoint.getSession(\"not-found\")).expectComplete().verify(Duration.ofSeconds(1));\n\t\tthen(this.sessionRepository).should().findById(\"not-found\");\n\t}\n\n\t@Test\n\tvoid deleteSession() {\n\t\tgiven(this.sessionRepository.deleteById(session.getId())).willReturn(Mono.empty());\n\t\tStepVerifier.create(this.endpoint.deleteSession(session.getId()))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(1));\n\t\tthen(this.sessionRepository).should().deleteById(session.getId());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/actuate/endpoint/ReactiveSessionsEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport java.util.Collections;\n\nimport net.minidev.json.JSONArray;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.MapSession;\nimport org.springframework.session.ReactiveFindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.Session;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link ReactiveSessionsEndpoint} exposed by WebFlux.\n *\n * @author Vedran Pavic\n * @author Moritz Halbritter\n */\nclass ReactiveSessionsEndpointWebIntegrationTests {\n\n\tprivate static final Session session = new MapSession();\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static final ReactiveSessionRepository<Session> sessionRepository = mock(ReactiveSessionRepository.class);\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static final ReactiveFindByIndexNameSessionRepository<Session> indexedSessionRepository = mock(\n\t\t\tReactiveFindByIndexNameSessionRepository.class);\n\n\t@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)\n\tvoid sessionsForUsernameWithoutUsernameParam(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.is4xxClientError();\n\t}\n\n\t@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)\n\tvoid sessionsForUsernameNoResults(WebTestClient client) {\n\t\tgiven(indexedSessionRepository.findByPrincipalName(\"user\")).willReturn(Mono.just(Collections.emptyMap()));\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions\").queryParam(\"username\", \"user\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"sessions\")\n\t\t\t.isEmpty();\n\t}\n\n\t@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)\n\tvoid sessionsForUsernameFound(WebTestClient client) {\n\t\tgiven(indexedSessionRepository.findByPrincipalName(\"user\"))\n\t\t\t.willReturn(Mono.just(Collections.singletonMap(session.getId(), session)));\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions\").queryParam(\"username\", \"user\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"sessions.[*].id\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(session.getId()));\n\t}\n\n\t@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)\n\tvoid sessionForIdFound(WebTestClient client) {\n\t\tgiven(sessionRepository.findById(session.getId())).willReturn(Mono.just(session));\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions/{id}\").build(session.getId()))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"id\")\n\t\t\t.isEqualTo(session.getId());\n\t}\n\n\t@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)\n\tvoid sessionForIdNotFound(WebTestClient client) {\n\t\tgiven(sessionRepository.findById(\"not-found\")).willReturn(Mono.empty());\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions/not-found\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNotFound();\n\t}\n\n\t@WebEndpointTest(infrastructure = Infrastructure.WEBFLUX)\n\tvoid deleteSession(WebTestClient client) {\n\t\tgiven(sessionRepository.deleteById(session.getId())).willReturn(Mono.empty());\n\t\tclient.delete()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions/{id}\").build(session.getId()))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tReactiveSessionsEndpoint sessionsEndpoint() {\n\t\t\treturn new ReactiveSessionsEndpoint(sessionRepository, indexedSessionRepository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/actuate/endpoint/SessionsEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.session.actuate.endpoint.SessionsDescriptor.SessionDescriptor;\nimport org.springframework.session.FindByIndexNameSessionRepository;\nimport org.springframework.session.MapSession;\nimport org.springframework.session.Session;\nimport org.springframework.session.SessionRepository;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SessionsEndpoint}.\n *\n * @author Vedran Pavic\n */\nclass SessionsEndpointTests {\n\n\tprivate static final Session session = new MapSession();\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate final SessionRepository<Session> sessionRepository = mock(SessionRepository.class);\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate final FindByIndexNameSessionRepository<Session> indexedSessionRepository = mock(\n\t\t\tFindByIndexNameSessionRepository.class);\n\n\tprivate final SessionsEndpoint endpoint = new SessionsEndpoint(this.sessionRepository,\n\t\t\tthis.indexedSessionRepository);\n\n\t@Test\n\tvoid sessionsForUsername() {\n\t\tgiven(this.indexedSessionRepository.findByPrincipalName(\"user\"))\n\t\t\t.willReturn(Collections.singletonMap(session.getId(), session));\n\t\tSessionsDescriptor sessions = this.endpoint.sessionsForUsername(\"user\");\n\t\tassertThat(sessions).isNotNull();\n\t\tList<SessionDescriptor> result = sessions.getSessions();\n\t\tassertThat(result).hasSize(1);\n\t\tassertThat(result.get(0).getId()).isEqualTo(session.getId());\n\t\tassertThat(result.get(0).getAttributeNames()).isEqualTo(session.getAttributeNames());\n\t\tassertThat(result.get(0).getCreationTime()).isEqualTo(session.getCreationTime());\n\t\tassertThat(result.get(0).getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());\n\t\tassertThat(result.get(0).getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());\n\t\tassertThat(result.get(0).isExpired()).isEqualTo(session.isExpired());\n\t\tthen(this.indexedSessionRepository).should().findByPrincipalName(\"user\");\n\t}\n\n\t@Test\n\tvoid sessionsForUsernameWhenNoIndexedRepository() {\n\t\tSessionsEndpoint endpoint = new SessionsEndpoint(this.sessionRepository, null);\n\t\tassertThat(endpoint.sessionsForUsername(\"user\")).isNull();\n\t}\n\n\t@Test\n\tvoid getSession() {\n\t\tgiven(this.sessionRepository.findById(session.getId())).willReturn(session);\n\t\tSessionDescriptor result = this.endpoint.getSession(session.getId());\n\t\tassertThat(result).isNotNull();\n\t\tassertThat(result.getId()).isEqualTo(session.getId());\n\t\tassertThat(result.getAttributeNames()).isEqualTo(session.getAttributeNames());\n\t\tassertThat(result.getCreationTime()).isEqualTo(session.getCreationTime());\n\t\tassertThat(result.getLastAccessedTime()).isEqualTo(session.getLastAccessedTime());\n\t\tassertThat(result.getMaxInactiveInterval()).isEqualTo(session.getMaxInactiveInterval().getSeconds());\n\t\tassertThat(result.isExpired()).isEqualTo(session.isExpired());\n\t\tthen(this.sessionRepository).should().findById(session.getId());\n\t}\n\n\t@Test\n\tvoid getSessionWithIdNotFound() {\n\t\tgiven(this.sessionRepository.findById(\"not-found\")).willReturn(null);\n\t\tassertThat(this.endpoint.getSession(\"not-found\")).isNull();\n\t\tthen(this.sessionRepository).should().findById(\"not-found\");\n\t}\n\n\t@Test\n\tvoid deleteSession() {\n\t\tthis.endpoint.deleteSession(session.getId());\n\t\tthen(this.sessionRepository).should().deleteById(session.getId());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/actuate/endpoint/SessionsEndpointWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.actuate.endpoint;\n\nimport java.util.Collections;\n\nimport net.minidev.json.JSONArray;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.FindByIndexNameSessionRepository;\nimport org.springframework.session.MapSession;\nimport org.springframework.session.Session;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link SessionsEndpoint} exposed by Jersey, Spring MVC, and\n * WebFlux.\n *\n * @author Vedran Pavic\n */\nclass SessionsEndpointWebIntegrationTests {\n\n\tprivate static final Session session = new MapSession();\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static final FindByIndexNameSessionRepository<Session> repository = mock(\n\t\t\tFindByIndexNameSessionRepository.class);\n\n\t@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })\n\tvoid sessionsForUsernameWithoutUsernameParam(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isBadRequest();\n\t}\n\n\t@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })\n\tvoid sessionsForUsernameNoResults(WebTestClient client) {\n\t\tgiven(repository.findByPrincipalName(\"user\")).willReturn(Collections.emptyMap());\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions\").queryParam(\"username\", \"user\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"sessions\")\n\t\t\t.isEmpty();\n\t}\n\n\t@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })\n\tvoid sessionsForUsernameFound(WebTestClient client) {\n\t\tgiven(repository.findByPrincipalName(\"user\")).willReturn(Collections.singletonMap(session.getId(), session));\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions\").queryParam(\"username\", \"user\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"sessions.[*].id\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(session.getId()));\n\t}\n\n\t@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })\n\tvoid sessionForIdNotFound(WebTestClient client) {\n\t\tclient.get()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions/session-id-not-found\").build())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNotFound();\n\t}\n\n\t@WebEndpointTest(infrastructure = { Infrastructure.JERSEY, Infrastructure.MVC })\n\tvoid deleteSession(WebTestClient client) {\n\t\tclient.delete()\n\t\t\t.uri((builder) -> builder.path(\"/actuator/sessions/{id}\").build(session.getId()))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNoContent();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tSessionsEndpoint sessionsEndpoint() {\n\t\t\treturn new SessionsEndpoint(repository, repository);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/autoconfigure/SessionAutoConfigurationEarlyInitializationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.util.LinkedHashMap;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.MapSessionRepository;\nimport org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;\nimport org.springframework.util.Assert;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests to ensure {@link SessionAutoConfiguration} and\n * {@link SessionRepositoryFilterConfiguration} does not cause early initialization.\n *\n * @author Phillip Webb\n */\nclass SessionAutoConfigurationEarlyInitializationIntegrationTests {\n\n\t@Test\n\tvoid configurationIsFrozenWhenSessionRepositoryAccessed() {\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withSystemProperties(\"spring.jndi.ignore=true\")\n\t\t\t.withPropertyValues(\"server.port=0\")\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(MapSessionRepository.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\t@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, SessionAutoConfiguration.class })\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tMapSessionRepository mapSessionRepository(ConfigurableApplicationContext context) {\n\t\t\tAssert.isTrue(context.getBeanFactory().isConfigurationFrozen(), \"'context' should be frozen\");\n\t\t\treturn new MapSessionRepository(new LinkedHashMap<>());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/autoconfigure/SessionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.util.Collections;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.SessionCookieConfig;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.servlet.AbstractFilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.session.MapSessionRepository;\nimport org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;\nimport org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;\nimport org.springframework.session.web.http.CookieHttpSessionIdResolver;\nimport org.springframework.session.web.http.DefaultCookieSerializer;\nimport org.springframework.session.web.http.HeaderHttpSessionIdResolver;\nimport org.springframework.session.web.http.HttpSessionIdResolver;\nimport org.springframework.session.web.http.SessionRepositoryFilter;\nimport org.springframework.web.filter.DelegatingFilterProxy;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SessionAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Vedran Pavic\n */\nclass SessionAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withInitializer((context) -> context.setServletContext(null)) // not a war\n\t\t.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));\n\n\t@Test\n\tvoid filterIsRegisteredWithAsyncErrorAndRequestDispatcherTypes() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class).run((context) -> {\n\t\t\tAbstractFilterRegistrationBean<?> registration = context.getBean(AbstractFilterRegistrationBean.class);\n\t\t\tDelegatingFilterProxy delegatingFilterProxy = (DelegatingFilterProxy) registration.getFilter();\n\t\t\tassertThat(delegatingFilterProxy).isNotNull();\n\t\t\ttry {\n\t\t\t\t// Trigger actual initialization\n\t\t\t\tdelegatingFilterProxy.doFilter(mock(ServletRequest.class), mock(ServletResponse.class),\n\t\t\t\t\t\tmock(FilterChain.class));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\tassertThat(delegatingFilterProxy).extracting(\"delegate\")\n\t\t\t\t.isSameAs(context.getBean(SessionRepositoryFilter.class));\n\t\t\tassertThat(registration)\n\t\t\t\t.extracting(\"dispatcherTypes\", InstanceOfAssertFactories.iterable(DispatcherType.class))\n\t\t\t\t.containsOnly(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST);\n\t\t});\n\t}\n\n\t@Test\n\tvoid filterOrderCanBeCustomizedWithCustomStore() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.session.servlet.filter-order=123\")\n\t\t\t.run((context) -> {\n\t\t\t\tAbstractFilterRegistrationBean<?> registration = context.getBean(AbstractFilterRegistrationBean.class);\n\t\t\t\tassertThat(registration.getOrder()).isEqualTo(123);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid filterDispatcherTypesCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.session.servlet.filter-dispatcher-types=error, request\")\n\t\t\t.run((context) -> {\n\t\t\t\tAbstractFilterRegistrationBean<?> registration = context.getBean(AbstractFilterRegistrationBean.class);\n\t\t\t\tassertThat(registration)\n\t\t\t\t\t.extracting(\"dispatcherTypes\", InstanceOfAssertFactories.iterable(DispatcherType.class))\n\t\t\t\t\t.containsOnly(DispatcherType.ERROR, DispatcherType.REQUEST);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid emptyFilterDispatcherTypesDoNotThrowException() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.session.servlet.filter-dispatcher-types=\")\n\t\t\t.run((context) -> {\n\t\t\t\tAbstractFilterRegistrationBean<?> registration = context.getBean(AbstractFilterRegistrationBean.class);\n\t\t\t\tassertThat(registration)\n\t\t\t\t\t.extracting(\"dispatcherTypes\", InstanceOfAssertFactories.iterable(DispatcherType.class))\n\t\t\t\t\t.isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid sessionCookieConfigurationIsAppliedToAutoConfiguredCookieSerializer() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.servlet.session.cookie.name=sid\", \"server.servlet.session.cookie.domain=spring\",\n\t\t\t\t\t\"server.servlet.session.cookie.path=/test\", \"server.servlet.session.cookie.httpOnly=false\",\n\t\t\t\t\t\"server.servlet.session.cookie.secure=false\", \"server.servlet.session.cookie.maxAge=10s\",\n\t\t\t\t\t\"server.servlet.session.cookie.sameSite=strict\", \"server.servlet.session.cookie.partitioned=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"cookieName\", \"sid\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"domainName\", \"spring\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"cookiePath\", \"/test\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"useHttpOnlyCookie\", false);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"useSecureCookie\", false);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"cookieMaxAge\", 10);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"sameSite\", \"Strict\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"partitioned\", true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid sessionCookieConfigIsAppliedToAutoConfiguredCookieSerializerInAWarDeployment() {\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tSessionCookieConfig cookie = servletContext.getSessionCookieConfig();\n\t\tcookie.setName(\"sid\");\n\t\tcookie.setDomain(\"spring\");\n\t\tcookie.setPath(\"/test\");\n\t\tcookie.setHttpOnly(false);\n\t\tcookie.setSecure(false);\n\t\tcookie.setMaxAge(10);\n\t\tcookie.setAttribute(\"SameSite\", \"Strict\");\n\t\tcookie.setAttribute(\"Partitioned\", \"true\");\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withInitializer((context) -> context.setServletContext(servletContext)) // war\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"cookieName\", \"sid\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"domainName\", \"spring\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"cookiePath\", \"/test\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"useHttpOnlyCookie\", false);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"useSecureCookie\", false);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"cookieMaxAge\", 10);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"sameSite\", \"Strict\");\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"partitioned\", true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid sessionCookieSameSiteOmittedIsAppliedToAutoConfiguredCookieSerializer() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.servlet.session.cookie.sameSite=omitted\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);\n\t\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"sameSite\", null);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredCookieSerializerIsUsedBySessionRepositoryFilter() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tSessionRepositoryFilter<?> filter = context.getBean(SessionRepositoryFilter.class);\n\t\t\t\tassertThat(filter).extracting(\"httpSessionIdResolver.cookieSerializer\")\n\t\t\t\t\t.isSameAs(context.getBean(DefaultCookieSerializer.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredCookieSerializerBacksOffWhenUserConfiguresACookieSerializer() {\n\t\tthis.contextRunner.withUserConfiguration(UserProvidedCookieSerializerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(DefaultCookieSerializer.class);\n\t\t\tassertThat(context).hasBean(\"myCookieSerializer\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid cookiesSerializerIsAutoConfiguredWhenUserConfiguresCookieHttpSessionIdResolver() {\n\t\tthis.contextRunner.withUserConfiguration(UserProvidedCookieHttpSessionStrategyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(DefaultCookieSerializer.class)).isNotEmpty());\n\t}\n\n\t@Test\n\tvoid autoConfiguredCookieSerializerBacksOffWhenUserConfiguresHeaderHttpSessionIdResolver() {\n\t\tthis.contextRunner.withUserConfiguration(UserProvidedHeaderHttpSessionStrategyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(DefaultCookieSerializer.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid autoConfiguredCookieSerializerBacksOffWhenUserConfiguresCustomHttpSessionIdResolver() {\n\t\tthis.contextRunner.withUserConfiguration(UserProvidedCustomHttpSessionStrategyConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBeansOfType(DefaultCookieSerializer.class)).isEmpty());\n\t}\n\n\t@Test\n\tvoid autoConfiguredCookieSerializerIsConfiguredWithRememberMeRequestAttribute() {\n\t\tthis.contextRunner.withBean(SpringSessionRememberMeServicesConfiguration.class).run((context) -> {\n\t\t\tDefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);\n\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"rememberMeRequestAttribute\",\n\t\t\t\t\tSpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);\n\t\t});\n\t}\n\n\t@Test\n\tvoid cookieSerializerCustomization() {\n\t\tthis.contextRunner.withBean(CookieSerializerCustomization.class).run((context) -> {\n\t\t\tCookieSerializerCustomization customization = context.getBean(CookieSerializerCustomization.class);\n\t\t\tInOrder inOrder = inOrder(customization.customizer1, customization.customizer2);\n\t\t\tinOrder.verify(customization.customizer1).customize(any());\n\t\t\tinOrder.verify(customization.customizer2).customize(any());\n\t\t});\n\t}\n\n\t@Test\n\tvoid cookieSerializerUsesLaxSameSitePolicyByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tDefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);\n\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"sameSite\", \"Lax\");\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tMapSessionRepository mySessionRepository() {\n\t\t\treturn new MapSessionRepository(Collections.emptyMap());\n\t\t}\n\n\t}\n\n\t@EnableConfigurationProperties(ServerProperties.class)\n\tstatic class ServerPropertiesConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class UserProvidedCookieSerializerConfiguration extends SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tDefaultCookieSerializer myCookieSerializer() {\n\t\t\treturn new DefaultCookieSerializer();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class UserProvidedCookieHttpSessionStrategyConfiguration extends SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tCookieHttpSessionIdResolver httpSessionStrategy() {\n\t\t\treturn new CookieHttpSessionIdResolver();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class UserProvidedHeaderHttpSessionStrategyConfiguration extends SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tHeaderHttpSessionIdResolver httpSessionStrategy() {\n\t\t\treturn HeaderHttpSessionIdResolver.xAuthToken();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class UserProvidedCustomHttpSessionStrategyConfiguration extends SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tHttpSessionIdResolver httpSessionStrategy() {\n\t\t\treturn mock(HttpSessionIdResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class SpringSessionRememberMeServicesConfiguration extends SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tSpringSessionRememberMeServices rememberMeServices() {\n\t\t\treturn new SpringSessionRememberMeServices();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class CookieSerializerCustomization extends SessionRepositoryConfiguration {\n\n\t\tprivate final DefaultCookieSerializerCustomizer customizer1 = mock(DefaultCookieSerializerCustomizer.class);\n\n\t\tprivate final DefaultCookieSerializerCustomizer customizer2 = mock(DefaultCookieSerializerCustomizer.class);\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tDefaultCookieSerializerCustomizer customizer1() {\n\t\t\treturn this.customizer1;\n\t\t}\n\n\t\t@Bean\n\t\t@Order(2)\n\t\tDefaultCookieSerializerCustomizer customizer2() {\n\t\t\treturn this.customizer2;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/autoconfigure/SessionAutoConfigurationWithoutSecurityTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.MapSessionRepository;\nimport org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;\nimport org.springframework.session.web.http.DefaultCookieSerializer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SessionAutoConfiguration} when Spring Security is not on the\n * classpath.\n *\n * @author Vedran Pavic\n */\n@ClassPathExclusions(\"spring-security-*\")\nclass SessionAutoConfigurationWithoutSecurityTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class));\n\n\t@Test\n\tvoid sessionCookieConfigurationIsAppliedToAutoConfiguredCookieSerializer() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class).run((context) -> {\n\t\t\tDefaultCookieSerializer cookieSerializer = context.getBean(DefaultCookieSerializer.class);\n\t\t\tassertThat(cookieSerializer).hasFieldOrPropertyWithValue(\"rememberMeRequestAttribute\", null);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringHttpSession\n\tstatic class SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tMapSessionRepository mySessionRepository() {\n\t\t\treturn new MapSessionRepository(Collections.emptyMap());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/autoconfigure/SessionPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.function.Supplier;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.Ordered;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.within;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SessionProperties}.\n *\n * @author Stephane Nicoll\n */\nclass SessionPropertiesTests {\n\n\tprivate final SessionProperties properties = new SessionProperties();\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"removal\" })\n\t@Deprecated(since = \"4.0.1\", forRemoval = true)\n\tvoid determineTimeoutWithTimeoutIgnoreFallback() {\n\t\tthis.properties.setTimeout(Duration.ofMinutes(1));\n\t\tSupplier<Duration> fallback = mock(Supplier.class);\n\t\tassertThat(this.properties.determineTimeout(fallback)).isEqualTo(Duration.ofMinutes(1));\n\t\tthen(fallback).shouldHaveNoInteractions();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"4.0.1\", forRemoval = true)\n\tvoid determineTimeoutWithNoTimeoutUseFallback() {\n\t\tthis.properties.setTimeout(null);\n\t\tDuration fallback = Duration.ofMinutes(2);\n\t\tassertThat(this.properties.determineTimeout(() -> fallback)).isSameAs(fallback);\n\t}\n\n\t@Test\n\tvoid defaultFilterOrderIsCloseToHighestPrecedence() {\n\t\tassertThat(this.properties.getServlet().getFilterOrder()).isCloseTo(Ordered.HIGHEST_PRECEDENCE, within(50));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/test/java/org/springframework/boot/session/autoconfigure/SessionsEndpointAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.session.actuate.endpoint.ReactiveSessionsEndpoint;\nimport org.springframework.boot.session.actuate.endpoint.SessionsEndpoint;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.FindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveFindByIndexNameSessionRepository;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.SessionRepository;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link SessionsEndpointAutoConfiguration}.\n *\n * @author Vedran Pavic\n * @author Moritz Halbritter\n */\nclass SessionsEndpointAutoConfigurationTests {\n\n\t@Nested\n\tclass ServletSessionEndpointConfigurationTests {\n\n\t\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SessionsEndpointAutoConfiguration.class))\n\t\t\t.withUserConfiguration(IndexedSessionRepositoryConfiguration.class);\n\n\t\t@Test\n\t\tvoid runShouldHaveEndpointBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=sessions\")\n\t\t\t\t.run((context) -> assertThat(context).hasSingleBean(SessionsEndpoint.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid runWhenNoIndexedSessionRepositoryShouldHaveEndpointBean() {\n\t\t\tnew WebApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(SessionsEndpointAutoConfiguration.class))\n\t\t\t\t.withUserConfiguration(SessionRepositoryConfiguration.class)\n\t\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=sessions\")\n\t\t\t\t.run((context) -> assertThat(context).hasSingleBean(SessionsEndpoint.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(SessionsEndpoint.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.sessions.enabled:false\")\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SessionsEndpoint.class));\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class IndexedSessionRepositoryConfiguration {\n\n\t\t\t@Bean\n\t\t\tFindByIndexNameSessionRepository<?> sessionRepository() {\n\t\t\t\treturn mock(FindByIndexNameSessionRepository.class);\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class SessionRepositoryConfiguration {\n\n\t\t\t@Bean\n\t\t\tSessionRepository<?> sessionRepository() {\n\t\t\t\treturn mock(SessionRepository.class);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Nested\n\tclass ReactiveSessionEndpointConfigurationTests {\n\n\t\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SessionsEndpointAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ReactiveSessionRepositoryConfiguration.class,\n\t\t\t\t\tReactiveIndexedSessionRepositoryConfiguration.class);\n\n\t\t@Test\n\t\tvoid runShouldHaveEndpointBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=sessions\")\n\t\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveSessionsEndpoint.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid runWhenNoIndexedSessionRepositoryShouldHaveEndpointBean() {\n\t\t\tnew ReactiveWebApplicationContextRunner()\n\t\t\t\t.withConfiguration(AutoConfigurations.of(SessionsEndpointAutoConfiguration.class))\n\t\t\t\t.withUserConfiguration(ReactiveSessionRepositoryConfiguration.class)\n\t\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=sessions\")\n\t\t\t\t.run((context) -> assertThat(context).hasSingleBean(ReactiveSessionsEndpoint.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid runWhenNotExposedShouldNotHaveEndpointBean() {\n\t\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveSessionsEndpoint.class));\n\t\t}\n\n\t\t@Test\n\t\tvoid runWhenEnabledPropertyIsFalseShouldNotHaveEndpointBean() {\n\t\t\tthis.contextRunner.withPropertyValues(\"management.endpoint.sessions.enabled:false\")\n\t\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ReactiveSessionsEndpoint.class));\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class ReactiveIndexedSessionRepositoryConfiguration {\n\n\t\t\t@Bean\n\t\t\tReactiveFindByIndexNameSessionRepository<?> indexedSessionRepository() {\n\t\t\t\treturn mock(ReactiveFindByIndexNameSessionRepository.class);\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class ReactiveSessionRepositoryConfiguration {\n\n\t\t\t@Bean\n\t\t\tReactiveSessionRepository<?> sessionRepository() {\n\t\t\t\treturn mock(ReactiveSessionRepository.class);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/testFixtures/java/org/springframework/boot/session/autoconfigure/AbstractSessionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.session.MapSessionRepository;\nimport org.springframework.session.SessionRepository;\nimport org.springframework.session.config.annotation.web.http.EnableSpringHttpSession;\nimport org.springframework.session.web.http.SessionRepositoryFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for Spring Session auto-configuration tests when the backing store cannot be\n * reactive.\n *\n * @author Stephane Nicoll\n * @author Weix Sun\n * @see AbstractSessionReactiveAutoConfigurationTests\n */\npublic abstract class AbstractSessionAutoConfigurationTests {\n\n\tprotected WebApplicationContextRunner contextRunner;\n\n\t@Test\n\tvoid backOffIfSessionRepositoryIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(SessionRepositoryConfiguration.class).run((context) -> {\n\t\t\tMapSessionRepository repository = validateSessionRepository(context, MapSessionRepository.class);\n\t\t\tassertThat(context).getBean(\"mySessionRepository\").isSameAs(repository);\n\t\t});\n\t}\n\n\tprotected <T extends SessionRepository<?>> T validateSessionRepository(AssertableWebApplicationContext context,\n\t\t\tClass<T> type) {\n\t\tassertThat(context).hasSingleBean(SessionRepositoryFilter.class);\n\t\tassertThat(context).hasSingleBean(SessionRepository.class);\n\t\tSessionRepository<?> repository = context.getBean(SessionRepository.class);\n\t\tassertThat(repository).as(\"Wrong session repository type\").isInstanceOf(type);\n\t\treturn type.cast(repository);\n\t}\n\n\t@Configuration\n\t@EnableSpringHttpSession\n\tstatic class SessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tMapSessionRepository mySessionRepository() {\n\t\t\treturn new MapSessionRepository(Collections.emptyMap());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session/src/testFixtures/java/org/springframework/boot/session/autoconfigure/AbstractSessionReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.session.ReactiveMapSessionRepository;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.config.annotation.web.server.EnableSpringWebSession;\nimport org.springframework.web.server.WebSession;\nimport org.springframework.web.server.session.WebSessionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for Spring Session auto-configuration tests when the backing store is\n * reactive.\n *\n * @author Andy Wilkinson\n */\npublic abstract class AbstractSessionReactiveAutoConfigurationTests {\n\n\tprivate static final MockReactiveWebServerFactory mockReactiveWebServerFactory = new MockReactiveWebServerFactory();\n\n\tprotected ReactiveWebApplicationContextRunner contextRunner;\n\n\t@Test\n\tvoid backOffIfReactiveSessionRepositoryIsPresent() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveSessionRepositoryConfiguration.class).run((context) -> {\n\t\t\tReactiveMapSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tReactiveMapSessionRepository.class);\n\t\t\tassertThat(context).getBean(\"mySessionRepository\").isSameAs(repository);\n\t\t});\n\t}\n\n\tprotected ContextConsumer<ReactiveWebApplicationContext> assertExchangeWithSession(\n\t\t\tConsumer<MockServerWebExchange> exchange) {\n\t\treturn (context) -> {\n\t\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/\").build();\n\t\t\tMockServerWebExchange webExchange = MockServerWebExchange.from(request);\n\t\t\tWebSessionManager webSessionManager = context.getBean(WebSessionManager.class);\n\t\t\tWebSession webSession = webSessionManager.getSession(webExchange).block();\n\t\t\twebSession.start();\n\t\t\twebExchange.getResponse().setComplete().block();\n\t\t\texchange.accept(webExchange);\n\t\t};\n\t}\n\n\tprotected <T extends ReactiveSessionRepository<?>> T validateSessionRepository(\n\t\t\tAssertableReactiveWebApplicationContext context, Class<T> type) {\n\t\tassertThat(context).hasSingleBean(WebSessionManager.class);\n\t\tassertThat(context).hasSingleBean(ReactiveSessionRepository.class);\n\t\tReactiveSessionRepository<?> repository = context.getBean(ReactiveSessionRepository.class);\n\t\tassertThat(repository).as(\"Wrong session repository type\").isInstanceOf(type);\n\t\treturn type.cast(repository);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class ReactiveWebServerConfiguration {\n\n\t\t@Bean\n\t\tMockReactiveWebServerFactory mockReactiveWebServerFactory() {\n\t\t\treturn mockReactiveWebServerFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableSpringWebSession\n\tstatic class ReactiveSessionRepositoryConfiguration {\n\n\t\t@Bean\n\t\tReactiveMapSessionRepository mySessionRepository() {\n\t\t\treturn new ReactiveMapSessionRepository(Collections.emptyMap());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Session Data Redis\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-session\"))\n\tapi(\"org.springframework.session:spring-session-data-redis\")\n\n\timplementation(project(\":module:spring-boot-data-redis\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-webflux\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\tdockerTestImplementation(testFixtures(project(\":module:spring-boot-session\")))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\tdockerTestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/dockerTest/java/org/springframework/boot/session/data/redis/autoconfigure/SessionDataRedisAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.data.redis.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Map;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.AbstractSessionAutoConfigurationTests;\nimport org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.session.FlushMode;\nimport org.springframework.session.SaveMode;\nimport org.springframework.session.config.SessionRepositoryCustomizer;\nimport org.springframework.session.data.redis.RedisIndexedSessionRepository;\nimport org.springframework.session.data.redis.RedisSessionRepository;\nimport org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;\nimport org.springframework.session.data.redis.config.ConfigureRedisAction;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link SessionDataRedisAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Vedran Pavic\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass SessionDataRedisAutoConfigurationTests extends AbstractSessionAutoConfigurationTests {\n\n\t@Container\n\tpublic static RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@BeforeEach\n\tvoid prepareContextRunner() {\n\t\tthis.contextRunner = new WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class,\n\t\t\t\t\tSessionDataRedisAutoConfiguration.class, DataRedisAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid defaultConfig() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class))\n\t\t\t.run(validateSpringSessionUsesDefaultRedis(\"spring:session:\", FlushMode.ON_SAVE,\n\t\t\t\t\tSaveMode.ON_SET_ATTRIBUTE));\n\t}\n\n\t@Test\n\tvoid invalidConfigurationPropertyValueWhenDefaultConfigIsUsedWithCustomCronCleanup() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort(),\n\t\t\t\t\t\"spring.session.data.redis.cleanup-cron=0 0 * * * *\")\n\t\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure())\n\t\t\t\t\t.hasRootCauseExactlyInstanceOf(InvalidConfigurationPropertyValueException.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultConfigWithCustomTimeout() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort(), \"spring.session.timeout=1m\")\n\t\t\t.run((context) -> {\n\t\t\t\tRedisSessionRepository repository = validateSessionRepository(context, RedisSessionRepository.class);\n\t\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\", Duration.ofMinutes(1));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultRedisSessionStoreWithCustomizations() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.namespace=foo\",\n\t\t\t\t\t\"spring.session.data.redis.flush-mode=immediate\",\n\t\t\t\t\t\"spring.session.data.redis.save-mode=on-get-attribute\", \"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateSpringSessionUsesDefaultRedis(\"foo:\", FlushMode.IMMEDIATE, SaveMode.ON_GET_ATTRIBUTE));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionDefaultConfig() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.withConfiguration(AutoConfigurations.of(DataRedisAutoConfiguration.class))\n\t\t\t.run(validateSpringSessionUsesIndexedRedis(\"spring:session:\", FlushMode.ON_SAVE, SaveMode.ON_SET_ATTRIBUTE,\n\t\t\t\t\t\"0 * * * * *\"));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionStoreWithCustomizations() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.session.data.redis.namespace=foo\", \"spring.session.data.redis.flush-mode=immediate\",\n\t\t\t\t\t\"spring.session.data.redis.save-mode=on-get-attribute\",\n\t\t\t\t\t\"spring.session.data.redis.cleanup-cron=0 0 12 * * *\", \"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateSpringSessionUsesIndexedRedis(\"foo:\", FlushMode.IMMEDIATE, SaveMode.ON_GET_ATTRIBUTE,\n\t\t\t\t\t\"0 0 12 * * *\"));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionWithConfigureActionNone() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.session.data.redis.configure-action=none\", \"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateStrategy(ConfigureRedisAction.NO_OP.getClass()));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionWithDefaultConfigureActionNone() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateStrategy(ConfigureNotifyKeyspaceEventsAction.class, entry(\"notify-keyspace-events\", \"gxE\")));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionWithCustomConfigureRedisActionBean() {\n\t\tthis.contextRunner.withUserConfiguration(MaxEntriesRedisAction.class)\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateStrategy(MaxEntriesRedisAction.class, entry(\"set-max-intset-entries\", \"1024\")));\n\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {\n\t\tthis.contextRunner.withUserConfiguration(CustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.session.data.redis.flush-mode=immediate\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run((context) -> {\n\t\t\t\tRedisSessionRepository repository = validateSessionRepository(context, RedisSessionRepository.class);\n\t\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"flushMode\", FlushMode.ON_SAVE);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenIndexedAndTheUserDefinesTheirOwnSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {\n\t\tthis.contextRunner.withUserConfiguration(IndexedCustomizerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.session.data.redis.flush-mode=immediate\", \"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run((context) -> {\n\t\t\t\tRedisIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\t\tRedisIndexedSessionRepository.class);\n\t\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"flushMode\", FlushMode.ON_SAVE);\n\t\t\t});\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesDefaultRedis(String keyNamespace,\n\t\t\tFlushMode flushMode, SaveMode saveMode) {\n\t\treturn (context) -> {\n\t\t\tRedisSessionRepository repository = validateSessionRepository(context, RedisSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\",\n\t\t\t\t\tnew ServerProperties().getServlet().getSession().getTimeout());\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"keyNamespace\", keyNamespace);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"flushMode\", flushMode);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"saveMode\", saveMode);\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> validateSpringSessionUsesIndexedRedis(String keyNamespace,\n\t\t\tFlushMode flushMode, SaveMode saveMode, String cleanupCron) {\n\t\treturn (context) -> {\n\t\t\tRedisIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tRedisIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\",\n\t\t\t\t\tnew ServerProperties().getServlet().getSession().getTimeout());\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"namespace\", keyNamespace);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"flushMode\", flushMode);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"saveMode\", saveMode);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"cleanupCron\", cleanupCron);\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> validateStrategy(\n\t\t\tClass<? extends ConfigureRedisAction> expectedConfigureRedisActionType, Map.Entry<?, ?>... expectedConfig) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConfigureRedisAction.class);\n\t\t\tassertThat(context).hasSingleBean(RedisConnectionFactory.class);\n\t\t\tassertThat(context.getBean(ConfigureRedisAction.class)).isInstanceOf(expectedConfigureRedisActionType);\n\t\t\tRedisConnection connection = context.getBean(RedisConnectionFactory.class).getConnection();\n\t\t\tif (expectedConfig.length > 0) {\n\t\t\t\tassertThat(connection.serverCommands().getConfig(\"*\")).contains(expectedConfig);\n\t\t\t}\n\t\t};\n\t}\n\n\tstatic class MaxEntriesRedisAction implements ConfigureRedisAction {\n\n\t\t@Override\n\t\tpublic void configure(RedisConnection connection) {\n\t\t\tconnection.serverCommands().setConfig(\"set-max-intset-entries\", \"1024\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomizerConfiguration {\n\n\t\t@Bean\n\t\tSessionRepositoryCustomizer<RedisSessionRepository> sessionRepositoryCustomizer() {\n\t\t\treturn (repository) -> repository.setFlushMode(FlushMode.ON_SAVE);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class IndexedCustomizerConfiguration {\n\n\t\t@Bean\n\t\tSessionRepositoryCustomizer<RedisIndexedSessionRepository> sessionRepositoryCustomizer() {\n\t\t\treturn (repository) -> repository.setFlushMode(FlushMode.ON_SAVE);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/dockerTest/java/org/springframework/boot/session/data/redis/autoconfigure/SessionDataRedisReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.data.redis.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisReactiveAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.AbstractSessionReactiveAutoConfigurationTests;\nimport org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.webflux.autoconfigure.WebSessionIdResolverAutoConfiguration;\nimport org.springframework.data.redis.connection.ReactiveRedisConnection;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.http.ResponseCookie;\nimport org.springframework.session.MapSession;\nimport org.springframework.session.SaveMode;\nimport org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository;\nimport org.springframework.session.data.redis.ReactiveRedisSessionRepository;\nimport org.springframework.session.data.redis.config.ConfigureReactiveRedisAction;\nimport org.springframework.session.data.redis.config.annotation.ConfigureNotifyKeyspaceEventsReactiveAction;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for the reactive support of {@link SessionDataRedisAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @author Weix Sun\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass SessionDataRedisReactiveAutoConfigurationTests extends AbstractSessionReactiveAutoConfigurationTests {\n\n\t@Container\n\tpublic static RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@BeforeEach\n\tvoid prepareRunner() {\n\t\tthis.contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class,\n\t\t\t\t\tWebSessionIdResolverAutoConfiguration.class, SessionDataRedisAutoConfiguration.class,\n\t\t\t\t\tDataRedisAutoConfiguration.class, DataRedisReactiveAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid defaultConfig() {\n\t\tthis.contextRunner.run(validateSpringSessionUsesRedis(\"spring:session:\", SaveMode.ON_SET_ATTRIBUTE));\n\t}\n\n\t@Test\n\tvoid defaultConfigWithCustomTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.timeout=1m\").run((context) -> {\n\t\t\tReactiveRedisSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tReactiveRedisSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\", Duration.ofMinutes(1));\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultConfigWithCustomWebFluxTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"server.reactive.session.timeout=1m\").run((context) -> {\n\t\t\tReactiveRedisSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tReactiveRedisSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\", Duration.ofMinutes(1));\n\t\t});\n\t}\n\n\t@Test\n\tvoid redisSessionStoreWithCustomizations() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.namespace=foo\",\n\t\t\t\t\t\"spring.session.data.redis.save-mode=on-get-attribute\")\n\t\t\t.run(validateSpringSessionUsesRedis(\"foo:\", SaveMode.ON_GET_ATTRIBUTE));\n\t}\n\n\t@Test\n\tvoid sessionCookieConfigurationIsAppliedToAutoConfiguredWebSessionIdResolver() {\n\t\tthis.contextRunner.withUserConfiguration(ReactiveWebServerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort(),\n\t\t\t\t\t\"server.reactive.session.cookie.name:JSESSIONID\",\n\t\t\t\t\t\"server.reactive.session.cookie.domain:.example.com\",\n\t\t\t\t\t\"server.reactive.session.cookie.path:/example\", \"server.reactive.session.cookie.max-age:60\",\n\t\t\t\t\t\"server.reactive.session.cookie.http-only:false\", \"server.reactive.session.cookie.secure:false\",\n\t\t\t\t\t\"server.reactive.session.cookie.same-site:strict\")\n\t\t\t.run(assertExchangeWithSession((exchange) -> {\n\t\t\t\tList<ResponseCookie> cookies = exchange.getResponse().getCookies().get(\"JSESSIONID\");\n\t\t\t\tassertThat(cookies).isNotEmpty();\n\t\t\t\tassertThat(cookies)\n\t\t\t\t\t.allMatch((cookie) -> cookie.getDomain() != null && cookie.getDomain().equals(\".example.com\"));\n\t\t\t\tassertThat(cookies)\n\t\t\t\t\t.allMatch((cookie) -> cookie.getPath() != null && cookie.getPath().equals(\"/example\"));\n\t\t\t\tassertThat(cookies).allMatch((cookie) -> cookie.getMaxAge().equals(Duration.ofSeconds(60)));\n\t\t\t\tassertThat(cookies).allMatch((cookie) -> !cookie.isHttpOnly());\n\t\t\t\tassertThat(cookies).allMatch((cookie) -> !cookie.isSecure());\n\t\t\t\tassertThat(cookies)\n\t\t\t\t\t.allMatch((cookie) -> cookie.getSameSite() != null && cookie.getSameSite().equals(\"Strict\"));\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionDefaultConfig() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateSpringSessionUsesIndexedRedis(\"spring:session:\", SaveMode.ON_SET_ATTRIBUTE));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionStoreWithCustomizations() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.session.data.redis.namespace=foo\", \"spring.session.data.redis.save-mode=on-get-attribute\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateSpringSessionUsesIndexedRedis(\"foo:\", SaveMode.ON_GET_ATTRIBUTE));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionWithConfigureActionNone() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.session.data.redis.configure-action=none\", \"spring.data.redis.host=\" + redis.getHost(),\n\t\t\t\t\t\"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateStrategy(ConfigureReactiveRedisAction.NO_OP.getClass()));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionWithDefaultConfigureActionNone() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateStrategy(ConfigureNotifyKeyspaceEventsReactiveAction.class,\n\t\t\t\t\tentry(\"notify-keyspace-events\", \"gxE\")));\n\t}\n\n\t@Test\n\tvoid indexedRedisSessionWithCustomConfigureReactiveRedisActionBean() {\n\t\tthis.contextRunner.withUserConfiguration(MaxEntriesReactiveRedisAction.class)\n\t\t\t.withPropertyValues(\"spring.session.data.redis.repository-type=indexed\",\n\t\t\t\t\t\"spring.data.redis.host=\" + redis.getHost(), \"spring.data.redis.port=\" + redis.getFirstMappedPort())\n\t\t\t.run(validateStrategy(MaxEntriesReactiveRedisAction.class, entry(\"set-max-intset-entries\", \"1024\")));\n\n\t}\n\n\tprivate ContextConsumer<AssertableReactiveWebApplicationContext> validateSpringSessionUsesRedis(String namespace,\n\t\t\tSaveMode saveMode) {\n\t\treturn (context) -> {\n\t\t\tReactiveRedisSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tReactiveRedisSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\",\n\t\t\t\t\tMapSession.DEFAULT_MAX_INACTIVE_INTERVAL);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"namespace\", namespace);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"saveMode\", saveMode);\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableReactiveWebApplicationContext> validateSpringSessionUsesIndexedRedis(\n\t\t\tString keyNamespace, SaveMode saveMode) {\n\t\treturn (context) -> {\n\t\t\tReactiveRedisIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tReactiveRedisIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\",\n\t\t\t\t\tnew ServerProperties().getReactive().getSession().getTimeout());\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"namespace\", keyNamespace);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"saveMode\", saveMode);\n\t\t};\n\t}\n\n\tprivate ContextConsumer<AssertableReactiveWebApplicationContext> validateStrategy(\n\t\t\tClass<? extends ConfigureReactiveRedisAction> expectedConfigureReactiveRedisActionType,\n\t\t\tMap.Entry<?, ?>... expectedConfig) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(ConfigureReactiveRedisAction.class);\n\t\t\tassertThat(context).hasSingleBean(RedisConnectionFactory.class);\n\t\t\tassertThat(context.getBean(ConfigureReactiveRedisAction.class))\n\t\t\t\t.isInstanceOf(expectedConfigureReactiveRedisActionType);\n\t\t\tReactiveRedisConnection connection = context.getBean(ReactiveRedisConnectionFactory.class)\n\t\t\t\t.getReactiveConnection();\n\t\t\tif (expectedConfig.length > 0) {\n\t\t\t\tassertThat(connection.serverCommands().getConfig(\"*\").block(Duration.ofSeconds(30)))\n\t\t\t\t\t.contains(expectedConfig);\n\t\t\t}\n\t\t};\n\t}\n\n\tstatic class MaxEntriesReactiveRedisAction implements ConfigureReactiveRedisAction {\n\n\t\t@Override\n\t\tpublic Mono<Void> configure(ReactiveRedisConnection connection) {\n\t\t\treturn Mono.when(connection.serverCommands().setConfig(\"set-max-intset-entries\", \"1024\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/main/java/org/springframework/boot/session/data/redis/autoconfigure/SessionDataRedisAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.data.redis.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;\nimport org.springframework.boot.data.redis.autoconfigure.DataRedisReactiveAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.SessionProperties;\nimport org.springframework.boot.session.autoconfigure.SessionTimeout;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;\nimport org.springframework.data.redis.connection.RedisConnectionFactory;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.session.ReactiveSessionRepository;\nimport org.springframework.session.Session;\nimport org.springframework.session.SessionRepository;\nimport org.springframework.session.config.ReactiveSessionRepositoryCustomizer;\nimport org.springframework.session.config.SessionRepositoryCustomizer;\nimport org.springframework.session.data.redis.ReactiveRedisIndexedSessionRepository;\nimport org.springframework.session.data.redis.ReactiveRedisSessionRepository;\nimport org.springframework.session.data.redis.RedisIndexedSessionRepository;\nimport org.springframework.session.data.redis.RedisSessionRepository;\nimport org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction;\nimport org.springframework.session.data.redis.config.ConfigureReactiveRedisAction;\nimport org.springframework.session.data.redis.config.ConfigureRedisAction;\nimport org.springframework.session.data.redis.config.annotation.ConfigureNotifyKeyspaceEventsReactiveAction;\nimport org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;\nimport org.springframework.session.data.redis.config.annotation.web.http.RedisIndexedHttpSessionConfiguration;\nimport org.springframework.session.data.redis.config.annotation.web.server.RedisIndexedWebSessionConfiguration;\nimport org.springframework.session.data.redis.config.annotation.web.server.RedisWebSessionConfiguration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Session Data Redis.\n *\n * @author Andy Wilkinson\n * @author Tommy Ludwig\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@AutoConfiguration(before = SessionAutoConfiguration.class,\n\t\tbeforeName = { \"org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration\",\n\t\t\t\t\"org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration\" },\n\t\tafter = { DataRedisAutoConfiguration.class, DataRedisReactiveAutoConfiguration.class },\n\t\tafterName = \"org.springframework.boot.webflux.autoconfigure.WebSessionIdResolverAutoConfiguration\")\n@ConditionalOnClass(Session.class)\n@EnableConfigurationProperties(SessionDataRedisProperties.class)\npublic final class SessionDataRedisAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ RedisTemplate.class, RedisIndexedSessionRepository.class })\n\t@ConditionalOnMissingBean(SessionRepository.class)\n\t@ConditionalOnBean(RedisConnectionFactory.class)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\tstatic class ServletRedisSessionConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnProperty(name = \"spring.session.data.redis.repository-type\", havingValue = \"default\",\n\t\t\t\tmatchIfMissing = true)\n\t\t@Import(RedisHttpSessionConfiguration.class)\n\t\tstatic class DefaultRedisSessionConfiguration {\n\n\t\t\t@Bean\n\t\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\t\tSessionRepositoryCustomizer<RedisSessionRepository> springBootSessionRepositoryCustomizer(\n\t\t\t\t\tSessionDataRedisProperties sessionDataRedisProperties, SessionTimeout sessionTimeout) {\n\t\t\t\tString cleanupCron = sessionDataRedisProperties.getCleanupCron();\n\t\t\t\tif (cleanupCron != null) {\n\t\t\t\t\tthrow new InvalidConfigurationPropertyValueException(\"spring.session.data.redis.cleanup-cron\",\n\t\t\t\t\t\t\tcleanupCron, \"Cron-based cleanup is only supported when \"\n\t\t\t\t\t\t\t\t\t+ \"spring.session.data.redis.repository-type is set to indexed.\");\n\t\t\t\t}\n\t\t\t\treturn (sessionRepository) -> {\n\t\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\t\tmap.from(sessionTimeout::getTimeout).to(sessionRepository::setDefaultMaxInactiveInterval);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getFlushMode).to(sessionRepository::setFlushMode);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getSaveMode).to(sessionRepository::setSaveMode);\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnProperty(name = \"spring.session.data.redis.repository-type\", havingValue = \"indexed\")\n\t\t@Import(RedisIndexedHttpSessionConfiguration.class)\n\t\tstatic class IndexedRedisSessionConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean\n\t\t\tConfigureRedisAction configureRedisAction(SessionDataRedisProperties sessionDataRedisProperties) {\n\t\t\t\treturn switch (sessionDataRedisProperties.getConfigureAction()) {\n\t\t\t\t\tcase NOTIFY_KEYSPACE_EVENTS -> new ConfigureNotifyKeyspaceEventsAction();\n\t\t\t\t\tcase NONE -> ConfigureRedisAction.NO_OP;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\t\tSessionRepositoryCustomizer<RedisIndexedSessionRepository> springBootSessionRepositoryCustomizer(\n\t\t\t\t\tSessionProperties sessionProperties, SessionDataRedisProperties sessionDataRedisProperties,\n\t\t\t\t\tSessionTimeout sessionTimeout) {\n\t\t\t\treturn (sessionRepository) -> {\n\t\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\t\tmap.from(sessionTimeout::getTimeout).to(sessionRepository::setDefaultMaxInactiveInterval);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getFlushMode).to(sessionRepository::setFlushMode);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getSaveMode).to(sessionRepository::setSaveMode);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getCleanupCron).to(sessionRepository::setCleanupCron);\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ ReactiveRedisConnectionFactory.class, ReactiveRedisSessionRepository.class })\n\t@ConditionalOnMissingBean(ReactiveSessionRepository.class)\n\t@ConditionalOnBean(ReactiveRedisConnectionFactory.class)\n\tclass ReactiveRedisSessionConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnProperty(name = \"spring.session.data.redis.repository-type\", havingValue = \"default\",\n\t\t\t\tmatchIfMissing = true)\n\t\t@Import(RedisWebSessionConfiguration.class)\n\t\tstatic class DefaultRedisSessionConfiguration {\n\n\t\t\t@Bean\n\t\t\tReactiveSessionRepositoryCustomizer<ReactiveRedisSessionRepository> springBootSessionRepositoryCustomizer(\n\t\t\t\t\tSessionProperties sessionProperties, SessionDataRedisProperties sessionDataRedisProperties,\n\t\t\t\t\tSessionTimeout sessionTimeout) {\n\t\t\t\treturn (sessionRepository) -> {\n\t\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\t\tmap.from(sessionTimeout::getTimeout).to(sessionRepository::setDefaultMaxInactiveInterval);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getSaveMode).to(sessionRepository::setSaveMode);\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnProperty(name = \"spring.session.data.redis.repository-type\", havingValue = \"indexed\")\n\t\t@Import(RedisIndexedWebSessionConfiguration.class)\n\t\tstatic class IndexedRedisSessionConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean\n\t\t\tConfigureReactiveRedisAction configureReactiveRedisAction(\n\t\t\t\t\tSessionDataRedisProperties sessionDataRedisProperties) {\n\t\t\t\treturn switch (sessionDataRedisProperties.getConfigureAction()) {\n\t\t\t\t\tcase NOTIFY_KEYSPACE_EVENTS -> new ConfigureNotifyKeyspaceEventsReactiveAction();\n\t\t\t\t\tcase NONE -> ConfigureReactiveRedisAction.NO_OP;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t@Bean\n\t\t\tReactiveSessionRepositoryCustomizer<ReactiveRedisIndexedSessionRepository> springBootSessionRepositoryCustomizer(\n\t\t\t\t\tSessionDataRedisProperties sessionDataRedisProperties, SessionTimeout sessionTimeout) {\n\t\t\t\treturn (sessionRepository) -> {\n\t\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\t\tmap.from(sessionTimeout::getTimeout).to(sessionRepository::setDefaultMaxInactiveInterval);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getNamespace).to(sessionRepository::setRedisKeyNamespace);\n\t\t\t\t\tmap.from(sessionDataRedisProperties::getSaveMode).to(sessionRepository::setSaveMode);\n\t\t\t\t};\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/main/java/org/springframework/boot/session/data/redis/autoconfigure/SessionDataRedisProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.data.redis.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.session.FlushMode;\nimport org.springframework.session.SaveMode;\n\n/**\n * Configuration properties for Spring Session Data Redis.\n *\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.session.data.redis\")\npublic class SessionDataRedisProperties {\n\n\t/**\n\t * Namespace for keys used to store sessions.\n\t */\n\tprivate String namespace = \"spring:session\";\n\n\t/**\n\t * Sessions flush mode. Determines when session changes are written to the session\n\t * store. Not supported with a reactive session repository.\n\t */\n\tprivate FlushMode flushMode = FlushMode.ON_SAVE;\n\n\t/**\n\t * Sessions save mode. Determines how session changes are tracked and saved to the\n\t * session store.\n\t */\n\tprivate SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;\n\n\t/**\n\t * The configure action to apply when no user-defined ConfigureRedisAction or\n\t * ConfigureReactiveRedisAction bean is present.\n\t */\n\tprivate ConfigureAction configureAction = ConfigureAction.NOTIFY_KEYSPACE_EVENTS;\n\n\t/**\n\t * Cron expression for expired session cleanup job. Only supported when\n\t * repository-type is set to indexed. Not supported with a reactive session\n\t * repository.\n\t */\n\tprivate @Nullable String cleanupCron;\n\n\t/**\n\t * Type of Redis session repository to configure.\n\t */\n\tprivate RepositoryType repositoryType = RepositoryType.DEFAULT;\n\n\tpublic String getNamespace() {\n\t\treturn this.namespace;\n\t}\n\n\tpublic void setNamespace(String namespace) {\n\t\tthis.namespace = namespace;\n\t}\n\n\tpublic FlushMode getFlushMode() {\n\t\treturn this.flushMode;\n\t}\n\n\tpublic void setFlushMode(FlushMode flushMode) {\n\t\tthis.flushMode = flushMode;\n\t}\n\n\tpublic SaveMode getSaveMode() {\n\t\treturn this.saveMode;\n\t}\n\n\tpublic void setSaveMode(SaveMode saveMode) {\n\t\tthis.saveMode = saveMode;\n\t}\n\n\tpublic @Nullable String getCleanupCron() {\n\t\treturn this.cleanupCron;\n\t}\n\n\tpublic void setCleanupCron(@Nullable String cleanupCron) {\n\t\tthis.cleanupCron = cleanupCron;\n\t}\n\n\tpublic ConfigureAction getConfigureAction() {\n\t\treturn this.configureAction;\n\t}\n\n\tpublic void setConfigureAction(ConfigureAction configureAction) {\n\t\tthis.configureAction = configureAction;\n\t}\n\n\tpublic RepositoryType getRepositoryType() {\n\t\treturn this.repositoryType;\n\t}\n\n\tpublic void setRepositoryType(RepositoryType repositoryType) {\n\t\tthis.repositoryType = repositoryType;\n\t}\n\n\t/**\n\t * Strategies for configuring and validating Redis.\n\t */\n\tpublic enum ConfigureAction {\n\n\t\t/**\n\t\t * Ensure that Redis Keyspace events for Generic commands and Expired events are\n\t\t * enabled.\n\t\t */\n\t\tNOTIFY_KEYSPACE_EVENTS,\n\n\t\t/**\n\t\t * No not attempt to apply any custom Redis configuration.\n\t\t */\n\t\tNONE\n\n\t}\n\n\t/**\n\t * Type of Redis session repository to auto-configure.\n\t */\n\tpublic enum RepositoryType {\n\n\t\t/**\n\t\t * Auto-configure a RedisSessionRepository or ReactiveRedisSessionRepository.\n\t\t */\n\t\tDEFAULT,\n\n\t\t/**\n\t\t * Auto-configure a RedisIndexedSessionRepository or\n\t\t * ReactiveRedisIndexedSessionRepository.\n\t\t */\n\t\tINDEXED\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/main/java/org/springframework/boot/session/data/redis/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Session Data Redis.\n */\n@NullMarked\npackage org.springframework.boot.session.data.redis.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.session.data.redis.cleanup-cron\",\n      \"defaultValue\": \"0 * * * * *\"\n    },\n    {\n      \"name\": \"spring.session.redis.cleanup-cron\",\n      \"description\": \"Cron expression for expired session cleanup job. Only supported when repository-type is set to indexed. Not supported with a reactive session repository.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.session.data.redis.cleanup-cron\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.session.redis.configure-action\",\n      \"description\": \"The configure action to apply when no user-defined ConfigureRedisAction or ConfigureReactiveRedisAction bean is present.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.session.data.redis.configure-action\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.session.redis.flush-mode\",\n      \"description\": \"Sessions flush mode. Determines when session changes are written to the session store. Not supported with a reactive session repository.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.session.data.redis.flush-mode\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.session.redis.namespace\",\n      \"description\": \"Namespace for keys used to store sessions.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.session.data.redis.namespace\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.session.redis.repository-type\",\n      \"description\": \"Type of Redis session repository to configure.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.session.data.redis.repository-type\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.session.redis.save-mode\",\n      \"description\": \"Sessions save mode. Determines how session changes are tracked and saved to the session store.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.session.data.redis.save-mode\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-session-data-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.session.data.redis.autoconfigure.SessionDataRedisAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Session JDBC\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-session\"))\n\tapi(\"org.springframework.session:spring-session-jdbc\")\n\n\timplementation(project(\":module:spring-boot-jdbc\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-flyway\"))\n\ttestImplementation(project(\":module:spring-boot-liquibase\"))\n\ttestImplementation(project(\":module:spring-boot-web-server\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-session\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-sql\")))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.apache.commons:commons-dbcp2\")\n\ttestImplementation(\"org.springframework:spring-web\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"org.flywaydb:flyway-database-hsqldb\")\n\ttestRuntimeOnly(\"org.hsqldb:hsqldb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/java/org/springframework/boot/session/jdbc/autoconfigure/JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\nimport org.springframework.session.jdbc.JdbcIndexedSessionRepository;\n\n/**\n *\n * {@link DependsOnDatabaseInitializationDetector} for\n * {@link JdbcIndexedSessionRepository}.\n *\n * @author Andy Wilkinson\n */\nclass JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector\n\t\textends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\treturn Collections.singleton(JdbcIndexedSessionRepository.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/java/org/springframework/boot/session/jdbc/autoconfigure/JdbcSessionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.SessionTimeout;\nimport org.springframework.boot.sql.autoconfigure.init.OnDatabaseInitializationCondition;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.session.Session;\nimport org.springframework.session.SessionRepository;\nimport org.springframework.session.config.SessionRepositoryCustomizer;\nimport org.springframework.session.jdbc.JdbcIndexedSessionRepository;\nimport org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;\nimport org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuraion} for Spring Session JDBC.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@AutoConfiguration(before = SessionAutoConfiguration.class, after = DataSourceAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ Session.class, JdbcTemplate.class, JdbcIndexedSessionRepository.class })\n@ConditionalOnMissingBean(SessionRepository.class)\n@ConditionalOnBean(DataSource.class)\n@EnableConfigurationProperties(JdbcSessionProperties.class)\n@Import({ DatabaseInitializationDependencyConfigurer.class, JdbcHttpSessionConfiguration.class })\npublic final class JdbcSessionAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@Conditional(OnJdbcSessionDatasourceInitializationCondition.class)\n\tJdbcSessionDataSourceScriptDatabaseInitializer jdbcSessionDataSourceScriptDatabaseInitializer(\n\t\t\t@SpringSessionDataSource ObjectProvider<DataSource> sessionDataSource,\n\t\t\tObjectProvider<DataSource> dataSource, JdbcSessionProperties properties) {\n\t\tDataSource dataSourceToInitialize = sessionDataSource.getIfAvailable(dataSource::getObject);\n\t\treturn new JdbcSessionDataSourceScriptDatabaseInitializer(dataSourceToInitialize, properties);\n\t}\n\n\t@Bean\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tSessionRepositoryCustomizer<JdbcIndexedSessionRepository> springBootSessionRepositoryCustomizer(\n\t\t\tJdbcSessionProperties jdbcSessionProperties, SessionTimeout sessionTimeout) {\n\t\treturn (sessionRepository) -> {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(sessionTimeout::getTimeout).to(sessionRepository::setDefaultMaxInactiveInterval);\n\t\t\tmap.from(jdbcSessionProperties::getTableName).to(sessionRepository::setTableName);\n\t\t\tmap.from(jdbcSessionProperties::getFlushMode).to(sessionRepository::setFlushMode);\n\t\t\tmap.from(jdbcSessionProperties::getSaveMode).to(sessionRepository::setSaveMode);\n\t\t\tmap.from(jdbcSessionProperties::getCleanupCron).to(sessionRepository::setCleanupCron);\n\t\t};\n\t}\n\n\tstatic class OnJdbcSessionDatasourceInitializationCondition extends OnDatabaseInitializationCondition {\n\n\t\tOnJdbcSessionDatasourceInitializationCondition() {\n\t\t\tsuper(\"Jdbc Session\", \"spring.session.jdbc.initialize-schema\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/java/org/springframework/boot/session/jdbc/autoconfigure/JdbcSessionDataSourceScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.boot.jdbc.DatabaseDriver;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.jdbc.init.PropertiesBasedDataSourceScriptDatabaseInitializer;\n\n/**\n * {@link DataSourceScriptDatabaseInitializer} for the Spring Session JDBC database. May\n * be registered as a bean to override auto-configuration.\n *\n * @author Dave Syer\n * @author Vedran Pavic\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Yanming Zhou\n * @since 4.0.0\n */\npublic class JdbcSessionDataSourceScriptDatabaseInitializer\n\t\textends PropertiesBasedDataSourceScriptDatabaseInitializer<JdbcSessionProperties> {\n\n\t/**\n\t * Create a new {@link JdbcSessionDataSourceScriptDatabaseInitializer} instance.\n\t * @param dataSource the Spring Session JDBC data source\n\t * @param properties the Spring Session JDBC properties\n\t * @see #getSettings\n\t */\n\tpublic JdbcSessionDataSourceScriptDatabaseInitializer(DataSource dataSource, JdbcSessionProperties properties) {\n\t\tsuper(dataSource, properties, Map.of(DatabaseDriver.MARIADB, \"mysql\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/java/org/springframework/boot/session/jdbc/autoconfigure/JdbcSessionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.init.DatabaseInitializationProperties;\nimport org.springframework.session.FlushMode;\nimport org.springframework.session.SaveMode;\n\n/**\n * Configuration properties for JDBC-backed Spring Session.\n *\n * @author Vedran Pavic\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.session.jdbc\")\npublic class JdbcSessionProperties extends DatabaseInitializationProperties {\n\n\tprivate static final String DEFAULT_SCHEMA_LOCATION = \"classpath:org/springframework/\"\n\t\t\t+ \"session/jdbc/schema-@@platform@@.sql\";\n\n\tprivate static final String DEFAULT_TABLE_NAME = \"SPRING_SESSION\";\n\n\tprivate static final String DEFAULT_CLEANUP_CRON = \"0 * * * * *\";\n\n\t/**\n\t * Name of the database table used to store sessions.\n\t */\n\tprivate String tableName = DEFAULT_TABLE_NAME;\n\n\t/**\n\t * Cron expression for expired session cleanup job.\n\t */\n\tprivate String cleanupCron = DEFAULT_CLEANUP_CRON;\n\n\t/**\n\t * Sessions flush mode. Determines when session changes are written to the session\n\t * store.\n\t */\n\tprivate FlushMode flushMode = FlushMode.ON_SAVE;\n\n\t/**\n\t * Sessions save mode. Determines how session changes are tracked and saved to the\n\t * session store.\n\t */\n\tprivate SaveMode saveMode = SaveMode.ON_SET_ATTRIBUTE;\n\n\tpublic String getTableName() {\n\t\treturn this.tableName;\n\t}\n\n\tpublic void setTableName(String tableName) {\n\t\tthis.tableName = tableName;\n\t}\n\n\tpublic String getCleanupCron() {\n\t\treturn this.cleanupCron;\n\t}\n\n\tpublic void setCleanupCron(String cleanupCron) {\n\t\tthis.cleanupCron = cleanupCron;\n\t}\n\n\tpublic FlushMode getFlushMode() {\n\t\treturn this.flushMode;\n\t}\n\n\tpublic void setFlushMode(FlushMode flushMode) {\n\t\tthis.flushMode = flushMode;\n\t}\n\n\tpublic SaveMode getSaveMode() {\n\t\treturn this.saveMode;\n\t}\n\n\tpublic void setSaveMode(SaveMode saveMode) {\n\t\tthis.saveMode = saveMode;\n\t}\n\n\t@Override\n\tpublic String getDefaultSchemaLocation() {\n\t\treturn DEFAULT_SCHEMA_LOCATION;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/java/org/springframework/boot/session/jdbc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Session JDBC.\n */\n@NullMarked\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": []\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.session.jdbc.autoconfigure.JdbcSessionAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/main/resources/META-INF/spring.factories",
    "content": "# Depends on Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.session.jdbc.autoconfigure.JdbcIndexedSessionRepositoryDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/test/java/org/springframework/boot/session/jdbc/autoconfigure/JdbcSessionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport java.time.Duration;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.dbcp2.BasicDataSource;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.liquibase.autoconfigure.LiquibaseAutoConfiguration;\nimport org.springframework.boot.session.autoconfigure.AbstractSessionAutoConfigurationTests;\nimport org.springframework.boot.session.autoconfigure.SessionAutoConfiguration;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.session.FlushMode;\nimport org.springframework.session.SaveMode;\nimport org.springframework.session.jdbc.JdbcIndexedSessionRepository;\nimport org.springframework.session.jdbc.PostgreSqlJdbcIndexedSessionRepositoryCustomizer;\nimport org.springframework.session.jdbc.config.annotation.SpringSessionDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link JdbcSessionAutoConfiguration}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n */\nclass JdbcSessionAutoConfigurationTests extends AbstractSessionAutoConfigurationTests {\n\n\t@BeforeEach\n\tvoid prepareRunner() {\n\t\tthis.contextRunner = new WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,\n\t\t\t\t\tSessionAutoConfiguration.class, JdbcSessionAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.datasource.generate-unique-name=true\");\n\t}\n\n\t@Test\n\tvoid defaultConfig() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\",\n\t\t\t\t\tnew ServerProperties().getServlet().getSession().getTimeout());\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"tableName\", \"SPRING_SESSION\");\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"cleanupCron\", \"0 * * * * *\");\n\t\t\tassertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())\n\t\t\t\t.isEqualTo(DatabaseInitializationMode.EMBEDDED);\n\t\t\tassertThat(context.getBean(JdbcOperations.class).queryForList(\"select * from SPRING_SESSION\")).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid disableDataSourceInitializer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.jdbc.initialize-schema=never\").run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(JdbcSessionDataSourceScriptDatabaseInitializer.class);\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"tableName\", \"SPRING_SESSION\");\n\t\t\tassertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())\n\t\t\t\t.isEqualTo(DatabaseInitializationMode.NEVER);\n\t\t\tassertThatExceptionOfType(BadSqlGrammarException.class)\n\t\t\t\t.isThrownBy(() -> context.getBean(JdbcOperations.class).queryForList(\"select * from SPRING_SESSION\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.timeout=1m\").run((context) -> {\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"defaultMaxInactiveInterval\", Duration.ofMinutes(1));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customTableName() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.jdbc.table-name=FOO_BAR\",\n\t\t\t\t\"spring.session.jdbc.schema=classpath:org/springframework/boot/session/jdbc/autoconfigure/custom-schema-h2.sql\")\n\t\t\t.run((context) -> {\n\t\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"tableName\", \"FOO_BAR\");\n\t\t\t\tassertThat(context.getBean(JdbcSessionProperties.class).getInitializeSchema())\n\t\t\t\t\t.isEqualTo(DatabaseInitializationMode.EMBEDDED);\n\t\t\t\tassertThat(context.getBean(JdbcOperations.class).queryForList(\"select * from FOO_BAR\")).isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customCleanupCron() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.jdbc.cleanup-cron=0 0 12 * * *\").run((context) -> {\n\t\t\tassertThat(context.getBean(JdbcSessionProperties.class).getCleanupCron()).isEqualTo(\"0 0 12 * * *\");\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"cleanupCron\", \"0 0 12 * * *\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customFlushMode() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.jdbc.flush-mode=immediate\").run((context) -> {\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"flushMode\", FlushMode.IMMEDIATE);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customSaveMode() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.session.jdbc.save-mode=on-get-attribute\").run((context) -> {\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"saveMode\", SaveMode.ON_GET_ATTRIBUTE);\n\t\t});\n\t}\n\n\t@Test\n\tvoid sessionDataSourceIsUsedWhenAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(SessionDataSourceConfiguration.class).run((context) -> {\n\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\tDataSource sessionDataSource = context.getBean(\"sessionDataSource\", DataSource.class);\n\t\t\tassertThat(repository).extracting(\"jdbcOperations.dataSource\").isEqualTo(sessionDataSource);\n\t\t\tassertThat(context.getBean(JdbcSessionDataSourceScriptDatabaseInitializer.class))\n\t\t\t\t.hasFieldOrPropertyWithValue(\"dataSource\", sessionDataSource);\n\t\t\tassertThatExceptionOfType(BadSqlGrammarException.class)\n\t\t\t\t.isThrownBy(() -> context.getBean(JdbcOperations.class).queryForList(\"select * from SPRING_SESSION\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid sessionRepositoryBeansDependOnJdbcSessionDataSourceInitializer() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tString[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class);\n\t\t\tassertThat(sessionRepositoryNames).isNotEmpty();\n\t\t\tfor (String sessionRepositoryName : sessionRepositoryNames) {\n\t\t\t\tassertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn())\n\t\t\t\t\t.contains(\"jdbcSessionDataSourceScriptDatabaseInitializer\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid sessionRepositoryBeansDependOnFlyway() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(FlywayAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.session.jdbc.initialize-schema=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tString[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class);\n\t\t\t\tassertThat(sessionRepositoryNames).isNotEmpty();\n\t\t\t\tfor (String sessionRepositoryName : sessionRepositoryNames) {\n\t\t\t\t\tassertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn()).contains(\"flyway\",\n\t\t\t\t\t\t\t\"flywayInitializer\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"db/changelog/db.changelog-master.yaml\", content = \"databaseChangeLog:\")\n\tvoid sessionRepositoryBeansDependOnLiquibase() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(LiquibaseAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.session.jdbc.initialize-schema=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\t\tString[] sessionRepositoryNames = beanFactory.getBeanNamesForType(JdbcIndexedSessionRepository.class);\n\t\t\t\tassertThat(sessionRepositoryNames).isNotEmpty();\n\t\t\t\tfor (String sessionRepositoryName : sessionRepositoryNames) {\n\t\t\t\t\tassertThat(beanFactory.getBeanDefinition(sessionRepositoryName).getDependsOn())\n\t\t\t\t\t\t.contains(\"liquibase\");\n\t\t\t\t}\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnJdbcSessionDatabaseInitializerThenTheAutoConfiguredInitializerBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJdbcSessionDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.doesNotHaveBean(\"jdbcSessionDataSourceScriptDatabaseInitializer\")\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnDatabaseInitializerThenTheAutoConfiguredJdbcSessionInitializerRemains() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDatabaseInitializerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,\n\t\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(JdbcSessionDataSourceScriptDatabaseInitializer.class)\n\t\t\t\t.hasBean(\"customInitializer\"));\n\t}\n\n\t@Test\n\tvoid whenTheUserDefinesTheirOwnJdbcIndexedSessionRepositoryCustomizerThenDefaultConfigurationIsOverwritten() {\n\t\tString expectedCreateSessionAttributeQuery = \"\"\"\n\t\t\t\tINSERT INTO SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES)\n\t\t\t\tVALUES (?, ?, ?)\n\t\t\t\tON CONFLICT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME)\n\t\t\t\tDO UPDATE SET ATTRIBUTE_BYTES = EXCLUDED.ATTRIBUTE_BYTES\n\t\t\t\t\"\"\";\n\t\tthis.contextRunner.withUserConfiguration(CustomJdbcIndexedSessionRepositoryCustomizerConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(SessionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tJdbcIndexedSessionRepository repository = validateSessionRepository(context,\n\t\t\t\t\t\tJdbcIndexedSessionRepository.class);\n\t\t\t\tassertThat(repository).hasFieldOrPropertyWithValue(\"createSessionAttributeQuery\",\n\t\t\t\t\t\texpectedCreateSessionAttributeQuery);\n\t\t\t});\n\t}\n\n\t@Configuration\n\tstatic class SessionDataSourceConfiguration {\n\n\t\t@Bean\n\t\t@SpringSessionDataSource\n\t\tDataSource sessionDataSource() {\n\t\t\tBasicDataSource dataSource = new BasicDataSource();\n\t\t\tdataSource.setDriverClassName(\"org.hsqldb.jdbcDriver\");\n\t\t\tdataSource.setUrl(\"jdbc:hsqldb:mem:sessiondb\");\n\t\t\tdataSource.setUsername(\"sa\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tDataSource mainDataSource() {\n\t\t\tBasicDataSource dataSource = new BasicDataSource();\n\t\t\tdataSource.setDriverClassName(\"org.hsqldb.jdbcDriver\");\n\t\t\tdataSource.setUrl(\"jdbc:hsqldb:mem:maindb\");\n\t\t\tdataSource.setUsername(\"sa\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJdbcSessionDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tJdbcSessionDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource,\n\t\t\t\tJdbcSessionProperties properties) {\n\t\t\treturn new JdbcSessionDataSourceScriptDatabaseInitializer(dataSource, properties);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDatabaseInitializerConfiguration {\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer customInitializer(DataSource dataSource) {\n\t\t\treturn new DataSourceScriptDatabaseInitializer(dataSource, new DatabaseInitializationSettings());\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CustomJdbcIndexedSessionRepositoryCustomizerConfiguration {\n\n\t\t@Bean\n\t\tPostgreSqlJdbcIndexedSessionRepositoryCustomizer postgreSqlJdbcIndexedSessionRepositoryCustomizer() {\n\t\t\treturn new PostgreSqlJdbcIndexedSessionRepositoryCustomizer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/test/java/org/springframework/boot/session/jdbc/autoconfigure/JdbcSessionDataSourceScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.session.jdbc.autoconfigure;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.sql.init.ScriptDatabaseInitializerSettings;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JdbcSessionDataSourceScriptDatabaseInitializer}.\n *\n * @author Stephane Nicoll\n */\nclass JdbcSessionDataSourceScriptDatabaseInitializerTests {\n\n\t@Test\n\tvoid getSettingsWithPlatformDoesNotTouchDataSource() {\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tJdbcSessionProperties properties = new JdbcSessionProperties();\n\t\tproperties.setPlatform(\"test\");\n\t\tDatabaseInitializationSettings settings = ScriptDatabaseInitializerSettings\n\t\t\t.get(new JdbcSessionDataSourceScriptDatabaseInitializer(dataSource, properties));\n\t\tassertThat(settings.getSchemaLocations())\n\t\t\t.containsOnly(\"classpath:org/springframework/session/jdbc/schema-test.sql\");\n\t\tthen(dataSource).shouldHaveNoInteractions();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-session-jdbc/src/test/resources/org/springframework/boot/session/jdbc/autoconfigure/custom-schema-h2.sql",
    "content": "CREATE TABLE FOO_BAR (\n\tSESSION_ID CHAR(36),\n\tCREATION_TIME BIGINT NOT NULL,\n\tLAST_ACCESS_TIME BIGINT NOT NULL,\n\tMAX_INACTIVE_INTERVAL INT NOT NULL,\n\tPRINCIPAL_NAME VARCHAR(100),\n\tCONSTRAINT FOO_BAR_PK PRIMARY KEY (SESSION_ID)\n);\n\nCREATE INDEX FOO_BAR_IX1 ON FOO_BAR (LAST_ACCESS_TIME);\n\nCREATE TABLE FOO_BAR_ATTRIBUTES (\n\tSESSION_ID CHAR(36),\n\tATTRIBUTE_NAME VARCHAR(100),\n\tATTRIBUTE_BYTES LONGVARBINARY,\n\tCONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),\n\tCONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES FOO_BAR(SESSION_ID) ON DELETE CASCADE\n);\n\nCREATE INDEX FOO_BAR_ATTRIBUTES_IX1 ON FOO_BAR_ATTRIBUTES (SESSION_ID);\n"
  },
  {
    "path": "module/spring-boot-sql/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot SQL\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestFixturesImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestFixturesImplementation(\"org.springframework:spring-tx\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/ApplicationScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.context.annotation.ImportRuntimeHints;\n\n/**\n * Marker interface for a script-based database initializer that initializes the\n * application's database.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n * @see AbstractScriptDatabaseInitializer\n */\n@ImportRuntimeHints(SqlInitializationScriptsRuntimeHints.class)\npublic interface ApplicationScriptDatabaseInitializer {\n\n\t/**\n\t * Adapts {@link SqlInitializationProperties} to\n\t * {@link DatabaseInitializationSettings}.\n\t * @param properties the properties to adapt\n\t * @return the settings\n\t */\n\tstatic DatabaseInitializationSettings getSettings(SqlInitializationProperties properties) {\n\t\treturn SettingsCreator.createFrom(properties);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/ConditionalOnSqlInitialization.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * Condition that matches when {@code spring.sql.init.mode} is set to a value other than\n * {@link DatabaseInitializationMode#NEVER}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Conditional(OnSqlInitializationCondition.class)\npublic @interface ConditionalOnSqlInitialization {\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/OnDatabaseInitializationCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport java.util.Locale;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.StringUtils;\n\n/**\n * Condition that checks if the database initialization of a particular component should\n * be considered.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see DatabaseInitializationMode\n */\npublic abstract class OnDatabaseInitializationCondition extends SpringBootCondition {\n\n\tprivate final String name;\n\n\tprivate final String[] propertyNames;\n\n\t/**\n\t * Create a new instance with the name of the component and the property names to\n\t * check, in order. If a property is set, its value is used to determine the outcome\n\t * and remaining properties are not tested.\n\t * @param name the name of the component\n\t * @param propertyNames the properties to check (in order)\n\t */\n\tprotected OnDatabaseInitializationCondition(String name, String... propertyNames) {\n\t\tthis.name = name;\n\t\tthis.propertyNames = propertyNames;\n\t}\n\n\t@Override\n\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\tEnvironment environment = context.getEnvironment();\n\t\tString propertyName = getConfiguredProperty(environment);\n\t\tDatabaseInitializationMode mode = getDatabaseInitializationMode(environment, propertyName);\n\t\tboolean match = match(mode);\n\t\tString messagePrefix = (propertyName != null) ? propertyName : \"default value\";\n\t\treturn new ConditionOutcome(match, ConditionMessage.forCondition(this.name + \"Database Initialization\")\n\t\t\t.because(messagePrefix + \" is \" + mode));\n\t}\n\n\tprivate boolean match(DatabaseInitializationMode mode) {\n\t\treturn !mode.equals(DatabaseInitializationMode.NEVER);\n\t}\n\n\tprivate DatabaseInitializationMode getDatabaseInitializationMode(Environment environment,\n\t\t\t@Nullable String propertyName) {\n\t\tif (StringUtils.hasText(propertyName)) {\n\t\t\tString candidate = environment.getProperty(propertyName, \"embedded\").toUpperCase(Locale.ENGLISH);\n\t\t\tif (StringUtils.hasText(candidate)) {\n\t\t\t\treturn DatabaseInitializationMode.valueOf(candidate);\n\t\t\t}\n\t\t}\n\t\treturn DatabaseInitializationMode.EMBEDDED;\n\t}\n\n\tprivate @Nullable String getConfiguredProperty(Environment environment) {\n\t\tfor (String propertyName : this.propertyNames) {\n\t\t\tif (environment.containsProperty(propertyName)) {\n\t\t\t\treturn propertyName;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/OnSqlInitializationCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport org.springframework.context.annotation.Condition;\n\n/**\n * {@link Condition} implementation for {@link ConditionalOnSqlInitialization}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass OnSqlInitializationCondition extends OnDatabaseInitializationCondition {\n\n\tOnSqlInitializationCondition() {\n\t\tsuper(\"SQL Initialization\", \"spring.sql.init.mode\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/SettingsCreator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\n\n/**\n * Helpers class for creating {@link DatabaseInitializationSettings} from\n * {@link SqlInitializationProperties}.\n *\n * @author Andy Wilkinson\n */\nfinal class SettingsCreator {\n\n\tprivate SettingsCreator() {\n\t}\n\n\tstatic DatabaseInitializationSettings createFrom(SqlInitializationProperties properties) {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings\n\t\t\t.setSchemaLocations(scriptLocations(properties.getSchemaLocations(), \"schema\", properties.getPlatform()));\n\t\tsettings.setDataLocations(scriptLocations(properties.getDataLocations(), \"data\", properties.getPlatform()));\n\t\tsettings.setContinueOnError(properties.isContinueOnError());\n\t\tsettings.setSeparator(properties.getSeparator());\n\t\tsettings.setEncoding(properties.getEncoding());\n\t\tsettings.setMode(properties.getMode());\n\t\treturn settings;\n\t}\n\n\tprivate static List<String> scriptLocations(@Nullable List<String> locations, String fallback, String platform) {\n\t\tif (locations != null) {\n\t\t\treturn locations;\n\t\t}\n\t\tList<String> fallbackLocations = new ArrayList<>();\n\t\tfallbackLocations.add(\"optional:classpath*:\" + fallback + \"-\" + platform + \".sql\");\n\t\tfallbackLocations.add(\"optional:classpath*:\" + fallback + \".sql\");\n\t\treturn fallbackLocations;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/SqlInitializationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport java.nio.charset.Charset;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.sql.init.DatabaseInitializationMode;\n\n/**\n * {@link ConfigurationProperties Configuration properties} for initializing an SQL\n * database.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.sql.init\")\npublic class SqlInitializationProperties {\n\n\t/**\n\t * Locations of the schema (DDL) scripts to apply to the database.\n\t */\n\tprivate @Nullable List<String> schemaLocations;\n\n\t/**\n\t * Locations of the data (DML) scripts to apply to the database.\n\t */\n\tprivate @Nullable List<String> dataLocations;\n\n\t/**\n\t * Platform to use in the default schema or data script locations,\n\t * schema-${platform}.sql and data-${platform}.sql.\n\t */\n\tprivate String platform = \"all\";\n\n\t/**\n\t * Username of the database to use when applying initialization scripts (if\n\t * different).\n\t */\n\tprivate @Nullable String username;\n\n\t/**\n\t * Password of the database to use when applying initialization scripts (if\n\t * different).\n\t */\n\tprivate @Nullable String password;\n\n\t/**\n\t * Whether initialization should continue when an error occurs.\n\t */\n\tprivate boolean continueOnError;\n\n\t/**\n\t * Statement separator in the schema and data scripts.\n\t */\n\tprivate String separator = \";\";\n\n\t/**\n\t * Encoding of the schema and data scripts.\n\t */\n\tprivate @Nullable Charset encoding;\n\n\t/**\n\t * Mode to apply when determining whether initialization should be performed.\n\t */\n\tprivate DatabaseInitializationMode mode = DatabaseInitializationMode.EMBEDDED;\n\n\tpublic @Nullable List<String> getSchemaLocations() {\n\t\treturn this.schemaLocations;\n\t}\n\n\tpublic void setSchemaLocations(@Nullable List<String> schemaLocations) {\n\t\tthis.schemaLocations = schemaLocations;\n\t}\n\n\tpublic @Nullable List<String> getDataLocations() {\n\t\treturn this.dataLocations;\n\t}\n\n\tpublic void setDataLocations(@Nullable List<String> dataLocations) {\n\t\tthis.dataLocations = dataLocations;\n\t}\n\n\tpublic String getPlatform() {\n\t\treturn this.platform;\n\t}\n\n\tpublic void setPlatform(String platform) {\n\t\tthis.platform = platform;\n\t}\n\n\tpublic @Nullable String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic void setUsername(@Nullable String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic @Nullable String getPassword() {\n\t\treturn this.password;\n\t}\n\n\tpublic void setPassword(@Nullable String password) {\n\t\tthis.password = password;\n\t}\n\n\tpublic boolean isContinueOnError() {\n\t\treturn this.continueOnError;\n\t}\n\n\tpublic void setContinueOnError(boolean continueOnError) {\n\t\tthis.continueOnError = continueOnError;\n\t}\n\n\tpublic String getSeparator() {\n\t\treturn this.separator;\n\t}\n\n\tpublic void setSeparator(String separator) {\n\t\tthis.separator = separator;\n\t}\n\n\tpublic @Nullable Charset getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\tpublic void setEncoding(@Nullable Charset encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\tpublic DatabaseInitializationMode getMode() {\n\t\treturn this.mode;\n\t}\n\n\tpublic void setMode(DatabaseInitializationMode mode) {\n\t\tthis.mode = mode;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/SqlInitializationScriptsRuntimeHints.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\n\n/**\n * {@link RuntimeHintsRegistrar} for SQL initialization scripts.\n *\n * @author Moritz Halbritter\n */\nclass SqlInitializationScriptsRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\thints.resources().registerPattern(\"schema.sql\").registerPattern(\"schema-*.sql\");\n\t\thints.resources().registerPattern(\"data.sql\").registerPattern(\"data-*.sql\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/autoconfigure/init/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for basic script-based initialization of an SQL database.\n */\n@NullMarked\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternUtils;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Base class for an {@link InitializingBean} that performs SQL database initialization\n * using schema (DDL) and data (DML) scripts.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic abstract class AbstractScriptDatabaseInitializer implements ResourceLoaderAware, InitializingBean {\n\n\tprivate static final String OPTIONAL_LOCATION_PREFIX = \"optional:\";\n\n\tprivate final DatabaseInitializationSettings settings;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate volatile ResourceLoader resourceLoader;\n\n\t/**\n\t * Creates a new {@link AbstractScriptDatabaseInitializer} that will initialize the\n\t * database using the given settings.\n\t * @param settings initialization settings\n\t */\n\tprotected AbstractScriptDatabaseInitializer(DatabaseInitializationSettings settings) {\n\t\tthis.settings = settings;\n\t}\n\n\t/**\n\t * Return the {@link DatabaseInitializationSettings} being used by the initializer.\n\t * @return the settings being used\n\t */\n\tDatabaseInitializationSettings getSettings() {\n\t\treturn this.settings;\n\t}\n\n\t@Override\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tinitializeDatabase();\n\t}\n\n\t/**\n\t * Initializes the database by applying schema and data scripts.\n\t * @return {@code true} if one or more scripts were applied to the database, otherwise\n\t * {@code false}\n\t */\n\tpublic boolean initializeDatabase() {\n\t\tScriptLocationResolver locationResolver = new ScriptLocationResolver(this.resourceLoader);\n\t\tboolean initialized = applySchemaScripts(locationResolver);\n\t\treturn applyDataScripts(locationResolver) || initialized;\n\t}\n\n\tprivate boolean isEnabled() {\n\t\tif (this.settings.getMode() == DatabaseInitializationMode.NEVER) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.settings.getMode() == DatabaseInitializationMode.ALWAYS || isEmbeddedDatabase();\n\t}\n\n\t/**\n\t * Returns whether the database that is to be initialized is embedded.\n\t * @return {@code true} if the database is embedded, otherwise {@code false}\n\t * @since 2.5.1\n\t */\n\tprotected boolean isEmbeddedDatabase() {\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Database initialization mode is '\" + this.settings.getMode() + \"' and database type is unknown\");\n\t}\n\n\tprivate boolean applySchemaScripts(ScriptLocationResolver locationResolver) {\n\t\treturn applyScripts(this.settings.getSchemaLocations(), \"schema\", locationResolver);\n\t}\n\n\tprivate boolean applyDataScripts(ScriptLocationResolver locationResolver) {\n\t\treturn applyScripts(this.settings.getDataLocations(), \"data\", locationResolver);\n\t}\n\n\tprivate boolean applyScripts(@Nullable List<String> locations, String type,\n\t\t\tScriptLocationResolver locationResolver) {\n\t\tList<Resource> scripts = getScripts(locations, type, locationResolver);\n\t\tif (!scripts.isEmpty() && isEnabled()) {\n\t\t\trunScripts(scripts);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate List<Resource> getScripts(@Nullable List<String> locations, String type,\n\t\t\tScriptLocationResolver locationResolver) {\n\t\tif (CollectionUtils.isEmpty(locations)) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\tList<Resource> resources = new ArrayList<>();\n\t\tfor (String location : locations) {\n\t\t\tboolean optional = location.startsWith(OPTIONAL_LOCATION_PREFIX);\n\t\t\tif (optional) {\n\t\t\t\tlocation = location.substring(OPTIONAL_LOCATION_PREFIX.length());\n\t\t\t}\n\t\t\tfor (Resource resource : doGetResources(location, locationResolver)) {\n\t\t\t\tif (resource.isReadable()) {\n\t\t\t\t\tresources.add(resource);\n\t\t\t\t}\n\t\t\t\telse if (!optional) {\n\t\t\t\t\tthrow new IllegalStateException(\"No \" + type + \" scripts found at location '\" + location + \"'\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn resources;\n\t}\n\n\tprivate List<Resource> doGetResources(String location, ScriptLocationResolver locationResolver) {\n\t\ttry {\n\t\t\treturn locationResolver.resolve(location);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to load resources from \" + location, ex);\n\t\t}\n\t}\n\n\tprivate void runScripts(List<Resource> resources) {\n\t\trunScripts(new Scripts(resources).continueOnError(this.settings.isContinueOnError())\n\t\t\t.separator(this.settings.getSeparator())\n\t\t\t.encoding(this.settings.getEncoding()));\n\t}\n\n\t/**\n\t * Initialize the database by running the given {@code scripts}.\n\t * @param scripts the scripts to run\n\t * @since 3.0.0\n\t */\n\tprotected abstract void runScripts(Scripts scripts);\n\n\tprivate static class ScriptLocationResolver {\n\n\t\tprivate final ResourcePatternResolver resourcePatternResolver;\n\n\t\tScriptLocationResolver(ResourceLoader resourceLoader) {\n\t\t\tthis.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);\n\t\t}\n\n\t\tprivate List<Resource> resolve(String location) throws IOException {\n\t\t\tList<Resource> resources = new ArrayList<>(\n\t\t\t\t\tArrays.asList(this.resourcePatternResolver.getResources(location)));\n\t\t\tresources.sort((r1, r2) -> {\n\t\t\t\ttry {\n\t\t\t\t\treturn r1.getURL().toString().compareTo(r2.getURL().toString());\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn resources;\n\t\t}\n\n\t}\n\n\t/**\n\t * Scripts to be used to initialize the database.\n\t *\n\t * @since 3.0.0\n\t */\n\tpublic static class Scripts implements Iterable<Resource> {\n\n\t\tprivate final List<Resource> resources;\n\n\t\tprivate boolean continueOnError;\n\n\t\tprivate String separator = \";\";\n\n\t\tprivate @Nullable Charset encoding;\n\n\t\tpublic Scripts(List<Resource> resources) {\n\t\t\tthis.resources = resources;\n\t\t}\n\n\t\t@Override\n\t\tpublic Iterator<Resource> iterator() {\n\t\t\treturn this.resources.iterator();\n\t\t}\n\n\t\tpublic Scripts continueOnError(boolean continueOnError) {\n\t\t\tthis.continueOnError = continueOnError;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic boolean isContinueOnError() {\n\t\t\treturn this.continueOnError;\n\t\t}\n\n\t\tpublic Scripts separator(String separator) {\n\t\t\tthis.separator = separator;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic String getSeparator() {\n\t\t\treturn this.separator;\n\t\t}\n\n\t\tpublic Scripts encoding(@Nullable Charset encoding) {\n\t\t\tthis.encoding = encoding;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic @Nullable Charset getEncoding() {\n\t\t\treturn this.encoding;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/DatabaseInitializationMode.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init;\n\n/**\n * Supported database initialization modes.\n *\n * @author Andy Wilkinson\n * @since 2.5.1\n * @see AbstractScriptDatabaseInitializer\n */\npublic enum DatabaseInitializationMode {\n\n\t/**\n\t * Always initialize the database.\n\t */\n\tALWAYS,\n\n\t/**\n\t * Only initialize an embedded database.\n\t */\n\tEMBEDDED,\n\n\t/**\n\t * Never initialize the database.\n\t */\n\tNEVER\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/DatabaseInitializationSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init;\n\nimport java.nio.charset.Charset;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Settings for initializing an SQL database.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic class DatabaseInitializationSettings {\n\n\tprivate @Nullable List<String> schemaLocations;\n\n\tprivate @Nullable List<String> dataLocations;\n\n\tprivate boolean continueOnError;\n\n\tprivate String separator = \";\";\n\n\tprivate @Nullable Charset encoding;\n\n\tprivate DatabaseInitializationMode mode = DatabaseInitializationMode.EMBEDDED;\n\n\t/**\n\t * Returns the locations of the schema (DDL) scripts to apply to the database.\n\t * @return the locations of the schema scripts\n\t */\n\tpublic @Nullable List<String> getSchemaLocations() {\n\t\treturn this.schemaLocations;\n\t}\n\n\t/**\n\t * Sets the locations of schema (DDL) scripts to apply to the database. By default,\n\t * initialization will fail if a location does not exist. To prevent a failure, a\n\t * location can be made optional by prefixing it with {@code optional:}.\n\t * @param schemaLocations locations of the schema scripts\n\t */\n\tpublic void setSchemaLocations(@Nullable List<String> schemaLocations) {\n\t\tthis.schemaLocations = schemaLocations;\n\t}\n\n\t/**\n\t * Returns the locations of data (DML) scripts to apply to the database.\n\t * @return the locations of the data scripts\n\t */\n\tpublic @Nullable List<String> getDataLocations() {\n\t\treturn this.dataLocations;\n\t}\n\n\t/**\n\t * Sets the locations of data (DML) scripts to apply to the database. By default,\n\t * initialization will fail if a location does not exist. To prevent a failure, a\n\t * location can be made optional by prefixing it with {@code optional:}.\n\t * @param dataLocations locations of the data scripts\n\t */\n\tpublic void setDataLocations(@Nullable List<String> dataLocations) {\n\t\tthis.dataLocations = dataLocations;\n\t}\n\n\t/**\n\t * Returns whether to continue when an error occurs while applying a schema or data\n\t * script.\n\t * @return whether to continue on error\n\t */\n\tpublic boolean isContinueOnError() {\n\t\treturn this.continueOnError;\n\t}\n\n\t/**\n\t * Sets whether initialization should continue when an error occurs when applying a\n\t * schema or data script.\n\t * @param continueOnError whether to continue when an error occurs.\n\t */\n\tpublic void setContinueOnError(boolean continueOnError) {\n\t\tthis.continueOnError = continueOnError;\n\t}\n\n\t/**\n\t * Returns the statement separator used in the schema and data scripts.\n\t * @return the statement separator\n\t */\n\tpublic String getSeparator() {\n\t\treturn this.separator;\n\t}\n\n\t/**\n\t * Sets the statement separator to use when reading the schema and data scripts.\n\t * @param separator statement separator used in the schema and data scripts\n\t */\n\tpublic void setSeparator(String separator) {\n\t\tthis.separator = separator;\n\t}\n\n\t/**\n\t * Returns the encoding to use when reading the schema and data scripts.\n\t * @return the script encoding\n\t */\n\tpublic @Nullable Charset getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\t/**\n\t * Sets the encoding to use when reading the schema and data scripts.\n\t * @param encoding encoding to use when reading the schema and data scripts\n\t */\n\tpublic void setEncoding(@Nullable Charset encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\t/**\n\t * Gets the mode to use when determining whether database initialization should be\n\t * performed.\n\t * @return the initialization mode\n\t * @since 2.5.1\n\t */\n\tpublic DatabaseInitializationMode getMode() {\n\t\treturn this.mode;\n\t}\n\n\t/**\n\t * Sets the mode the use when determining whether database initialization should be\n\t * performed.\n\t * @param mode the initialization mode\n\t * @since 2.5.1\n\t */\n\tpublic void setMode(DatabaseInitializationMode mode) {\n\t\tthis.mode = mode;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/AbstractBeansOfTypeDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n\n/**\n * Base class for {@link DatabaseInitializerDetector DatabaseInitializerDetectors} that\n * detect database initializer beans by type.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic abstract class AbstractBeansOfTypeDatabaseInitializerDetector implements DatabaseInitializerDetector {\n\n\t@Override\n\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\ttry {\n\t\t\tSet<Class<?>> types = getDatabaseInitializerBeanTypes();\n\t\t\treturn new BeansOfTypeDetector(types).detect(beanFactory);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the bean types that should be detected as being database initializers.\n\t * @return the database initializer bean types\n\t */\n\tprotected abstract Set<Class<?>> getDatabaseInitializerBeanTypes();\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/AbstractBeansOfTypeDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n\n/**\n * Base class for {@link DependsOnDatabaseInitializationDetector\n * DependsOnDatabaseInitializationDetectors} that detect by type beans that depend upon\n * database initialization.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic abstract class AbstractBeansOfTypeDependsOnDatabaseInitializationDetector\n\t\timplements DependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\ttry {\n\t\t\tSet<Class<?>> types = getDependsOnDatabaseInitializationBeanTypes();\n\t\t\treturn new BeansOfTypeDetector(types).detect(beanFactory);\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the bean types that should be detected as depending on database\n\t * initialization.\n\t * @return the database initialization dependent bean types\n\t */\n\tprotected abstract Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes();\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/AnnotationDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n\n/**\n * {@link DependsOnDatabaseInitializationDetector} that detects beans annotated with\n * {@link DependsOnDatabaseInitialization}.\n *\n * @author Andy Wilkinson\n */\nclass AnnotationDependsOnDatabaseInitializationDetector implements DependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\tSet<String> dependentBeans = new HashSet<>();\n\t\tfor (String beanName : beanFactory.getBeanDefinitionNames()) {\n\t\t\tif (beanFactory.findAnnotationOnBean(beanName, DependsOnDatabaseInitialization.class, false) != null) {\n\t\t\t\tdependentBeans.add(beanName);\n\t\t\t}\n\t\t}\n\t\treturn dependentBeans;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/BeansOfTypeDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.ListableBeanFactory;\n\n/**\n * Helper class for detecting beans of particular types in a bean factory.\n *\n * @author Andy Wilkinson\n */\nclass BeansOfTypeDetector {\n\n\tprivate final Set<Class<?>> types;\n\n\tBeansOfTypeDetector(Set<Class<?>> types) {\n\t\tthis.types = types;\n\t}\n\n\tSet<String> detect(ListableBeanFactory beanFactory) {\n\t\tSet<String> beanNames = new HashSet<>();\n\t\tfor (Class<?> type : this.types) {\n\t\t\ttry {\n\t\t\t\tString[] names = beanFactory.getBeanNamesForType(type, true, false);\n\t\t\t\tArrays.stream(names).map(BeanFactoryUtils::transformedBeanName).forEach(beanNames::add);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\t// Continue\n\t\t\t}\n\t\t}\n\t\treturn beanNames;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/DatabaseInitializationDependencyConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.EnvironmentAware;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.support.SpringFactoriesLoader;\nimport org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Configures beans that depend upon SQL database initialization with\n * {@link BeanDefinition#getDependsOn() dependencies} upon beans that perform database\n * initialization. Intended for {@link Import import} in configuration classes that define\n * database initialization beans or that define beans that require database initialization\n * to have completed before they are initialized.\n * <p>\n * Beans that initialize a database are identified by {@link DatabaseInitializerDetector\n * DatabaseInitializerDetectors}. Beans that depend upon database initialization are\n * identified by {@link DependsOnDatabaseInitializationDetector\n * DependsOnDatabaseInitializationDetectors}.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n * @see DatabaseInitializerDetector\n * @see DependsOnDatabaseInitializationDetector\n * @see DependsOnDatabaseInitialization\n */\npublic class DatabaseInitializationDependencyConfigurer implements ImportBeanDefinitionRegistrar {\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tString name = DependsOnDatabaseInitializationPostProcessor.class.getName();\n\t\tif (!registry.containsBeanDefinition(name)) {\n\t\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder\n\t\t\t\t.rootBeanDefinition(DependsOnDatabaseInitializationPostProcessor.class);\n\t\t\tregistry.registerBeanDefinition(name, builder.getBeanDefinition());\n\t\t}\n\t}\n\n\t/**\n\t * {@link BeanFactoryPostProcessor} used to configure database initialization\n\t * dependency relationships.\n\t */\n\tstatic class DependsOnDatabaseInitializationPostProcessor\n\t\t\timplements BeanFactoryPostProcessor, EnvironmentAware, Ordered {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate Environment environment;\n\n\t\t@Override\n\t\tpublic void setEnvironment(Environment environment) {\n\t\t\tthis.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tif (AotDetector.useGeneratedArtifacts()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tInitializerBeanNames initializerBeanNames = detectInitializerBeanNames(beanFactory);\n\t\t\tif (initializerBeanNames.isEmpty()) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tSet<String> previousInitializerBeanNamesBatch = null;\n\t\t\tfor (Set<String> initializerBeanNamesBatch : initializerBeanNames.batchedBeanNames()) {\n\t\t\t\tfor (String initializerBeanName : initializerBeanNamesBatch) {\n\t\t\t\t\tBeanDefinition beanDefinition = getBeanDefinition(initializerBeanName, beanFactory);\n\t\t\t\t\tbeanDefinition\n\t\t\t\t\t\t.setDependsOn(merge(beanDefinition.getDependsOn(), previousInitializerBeanNamesBatch));\n\t\t\t\t}\n\t\t\t\tpreviousInitializerBeanNamesBatch = initializerBeanNamesBatch;\n\t\t\t}\n\t\t\tfor (String dependsOnInitializationBeanNames : detectDependsOnInitializationBeanNames(beanFactory)) {\n\t\t\t\tBeanDefinition beanDefinition = getBeanDefinition(dependsOnInitializationBeanNames, beanFactory);\n\t\t\t\tbeanDefinition.setDependsOn(merge(beanDefinition.getDependsOn(), initializerBeanNames.beanNames()));\n\t\t\t}\n\t\t}\n\n\t\tprivate String @Nullable [] merge(String @Nullable [] source, @Nullable Set<String> additional) {\n\t\t\tif (CollectionUtils.isEmpty(additional)) {\n\t\t\t\treturn source;\n\t\t\t}\n\t\t\tSet<String> result = new LinkedHashSet<>((source != null) ? Arrays.asList(source) : Collections.emptySet());\n\t\t\tresult.addAll(additional);\n\t\t\treturn StringUtils.toStringArray(result);\n\t\t}\n\n\t\tprivate InitializerBeanNames detectInitializerBeanNames(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tList<DatabaseInitializerDetector> detectors = getDetectors(beanFactory, DatabaseInitializerDetector.class);\n\t\t\tInitializerBeanNames initializerBeanNames = new InitializerBeanNames();\n\t\t\tfor (DatabaseInitializerDetector detector : detectors) {\n\t\t\t\tfor (String beanName : detector.detect(beanFactory)) {\n\t\t\t\t\tBeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\t\tbeanDefinition.setAttribute(DatabaseInitializerDetector.class.getName(),\n\t\t\t\t\t\t\tdetector.getClass().getName());\n\t\t\t\t\tinitializerBeanNames.detected(detector, beanName);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (DatabaseInitializerDetector detector : detectors) {\n\t\t\t\tdetector.detectionComplete(beanFactory, initializerBeanNames.beanNames());\n\t\t\t}\n\t\t\treturn initializerBeanNames;\n\t\t}\n\n\t\tprivate Collection<String> detectDependsOnInitializationBeanNames(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tList<DependsOnDatabaseInitializationDetector> detectors = getDetectors(beanFactory,\n\t\t\t\t\tDependsOnDatabaseInitializationDetector.class);\n\t\t\tSet<String> beanNames = new HashSet<>();\n\t\t\tfor (DependsOnDatabaseInitializationDetector detector : detectors) {\n\t\t\t\tbeanNames.addAll(detector.detect(beanFactory));\n\t\t\t}\n\t\t\treturn beanNames;\n\t\t}\n\n\t\tprivate <T> List<T> getDetectors(ConfigurableListableBeanFactory beanFactory, Class<T> type) {\n\t\t\tArgumentResolver argumentResolver = ArgumentResolver.of(Environment.class, this.environment);\n\t\t\treturn SpringFactoriesLoader.forDefaultResourceLocation(beanFactory.getBeanClassLoader())\n\t\t\t\t.load(type, argumentResolver);\n\t\t}\n\n\t\tprivate static BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {\n\t\t\ttry {\n\t\t\t\treturn beanFactory.getBeanDefinition(beanName);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\tBeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();\n\t\t\t\tif (parentBeanFactory instanceof ConfigurableListableBeanFactory configurableBeanFactory) {\n\t\t\t\t\treturn getBeanDefinition(beanName, configurableBeanFactory);\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tstatic class InitializerBeanNames {\n\n\t\t\tprivate final Map<DatabaseInitializerDetector, Set<String>> byDetectorBeanNames = new LinkedHashMap<>();\n\n\t\t\tprivate final Set<String> beanNames = new LinkedHashSet<>();\n\n\t\t\tprivate void detected(DatabaseInitializerDetector detector, String beanName) {\n\t\t\t\tthis.byDetectorBeanNames.computeIfAbsent(detector, (key) -> new LinkedHashSet<>()).add(beanName);\n\t\t\t\tthis.beanNames.add(beanName);\n\t\t\t}\n\n\t\t\tprivate boolean isEmpty() {\n\t\t\t\treturn this.beanNames.isEmpty();\n\t\t\t}\n\n\t\t\tprivate Iterable<Set<String>> batchedBeanNames() {\n\t\t\t\treturn this.byDetectorBeanNames.values();\n\t\t\t}\n\n\t\t\tprivate Set<String> beanNames() {\n\t\t\t\treturn Collections.unmodifiableSet(this.beanNames);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/DatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.core.Ordered;\n\n/**\n * Detects beans that initialize an SQL database. Implementations should be registered in\n * {@code META-INF/spring.factories} under the key\n * {@code org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector}.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic interface DatabaseInitializerDetector extends Ordered {\n\n\t/**\n\t * Detect beans defined in the given {@code beanFactory} that initialize a\n\t * {@link DataSource}.\n\t * @param beanFactory bean factory to examine\n\t * @return names of the detected {@code DataSource} initializer beans, or an empty set\n\t * if none were detected.\n\t */\n\tSet<String> detect(ConfigurableListableBeanFactory beanFactory);\n\n\t/**\n\t * Callback indicating that all known {@code DataSourceInitializerDetectors} have been\n\t * called and detection of beans that initialize a {@link DataSource} is complete.\n\t * @param beanFactory bean factory that was examined\n\t * @param dataSourceInitializerNames names of the {@code DataSource} initializer beans\n\t * detected by all known detectors\n\t */\n\tdefault void detectionComplete(ConfigurableListableBeanFactory beanFactory,\n\t\t\tSet<String> dataSourceInitializerNames) {\n\t}\n\n\t@Override\n\tdefault int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/DependsOnDatabaseInitialization.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Indicate that a bean's creation and initialization depends upon database initialization\n * having completed. May be used on a bean's class or its {@link Bean @Bean} definition.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\npublic @interface DependsOnDatabaseInitialization {\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/DependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.util.Set;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\n\n/**\n * Detects beans that depend on database initialization. Implementations should be\n * registered in {@code META-INF/spring.factories} under the key\n * {@code org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector}.\n *\n * @author Andy Wilkinson\n * @since 2.5.0\n */\npublic interface DependsOnDatabaseInitializationDetector {\n\n\t/**\n\t * Detect beans defined in the given {@code beanFactory} that depend on database\n\t * initialization. If no beans are detected, an empty set is returned.\n\t * @param beanFactory bean factory to examine\n\t * @return names of any beans that depend upon database initialization\n\t */\n\tSet<String> detect(ConfigurableListableBeanFactory beanFactory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/dependency/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Infrastructure for establishing database initialization bean dependencies.\n */\n@NullMarked\npackage org.springframework.boot.sql.init.dependency;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/java/org/springframework/boot/sql/init/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for initialization of an SQL database.\n */\n@NullMarked\npackage org.springframework.boot.sql.init;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.sql.init.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether basic script-based initialization of an SQL database is enabled.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"warning\",\n        \"replacement\": \"spring.sql.init.mode\",\n        \"since\": \"2.5.1\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.sql.init.data-locations\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.util.List<org.springframework.core.io.Resource>\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.sql.init.schema-locations\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.util.List<org.springframework.core.io.Resource>\"\n          }\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/main/resources/META-INF/spring.factories",
    "content": "# Depends On Database Initialization Detectors\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.boot.sql.init.dependency.AnnotationDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "module/spring-boot-sql/src/test/java/org/springframework/boot/sql/autoconfigure/init/OnDatabaseInitializationConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link OnDatabaseInitializationCondition}.\n *\n * @author Stephane Nicoll\n */\nclass OnDatabaseInitializationConditionTests {\n\n\t@Test\n\tvoid getMatchOutcomeWithPropertyNoSetMatches() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.another\", \"noise\")),\n\t\t\t\tmock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeWithPropertySetToAlwaysMatches() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.init-mode=always\")),\n\t\t\t\tmock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeWithPropertySetToEmbeddedMatches() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.init-mode=embedded\")),\n\t\t\t\tmock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeWithPropertySetToNeverDoesNotMatch() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.init-mode=never\")), mock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.isMatch()).isFalse();\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeWithPropertySetToEmptyStringIsIgnored() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.init-mode\")), mock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeWithMultiplePropertiesUsesFirstSet() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\",\n\t\t\t\t\"test.schema-mode\", \"test.init-schema-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.init-schema-mode=embedded\")),\n\t\t\t\tmock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.isMatch()).isTrue();\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"TestDatabase Initialization test.init-schema-mode is EMBEDDED\");\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeHasDedicatedDescription() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(\n\t\t\t\tmockConditionContext(TestPropertyValues.of(\"test.init-mode=embedded\")),\n\t\t\t\tmock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"TestDatabase Initialization test.init-mode is EMBEDDED\");\n\t}\n\n\t@Test\n\tvoid getMatchOutcomeHasWhenPropertyIsNotSetHasDefaultDescription() {\n\t\tOnDatabaseInitializationCondition condition = new OnTestDatabaseInitializationCondition(\"test.init-mode\");\n\t\tConditionOutcome outcome = condition.getMatchOutcome(mockConditionContext(TestPropertyValues.empty()),\n\t\t\t\tmock(AnnotatedTypeMetadata.class));\n\t\tassertThat(outcome.getMessage()).isEqualTo(\"TestDatabase Initialization default value is EMBEDDED\");\n\t}\n\n\tprivate ConditionContext mockConditionContext(TestPropertyValues propertyValues) {\n\t\tMockEnvironment environment = new MockEnvironment();\n\t\tpropertyValues.applyTo(environment);\n\t\tConditionContext conditionContext = mock(ConditionContext.class);\n\t\tgiven(conditionContext.getEnvironment()).willReturn(environment);\n\t\treturn conditionContext;\n\t}\n\n\tstatic class OnTestDatabaseInitializationCondition extends OnDatabaseInitializationCondition {\n\n\t\tOnTestDatabaseInitializationCondition(String... properties) {\n\t\t\tsuper(\"Test\", properties);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/test/java/org/springframework/boot/sql/autoconfigure/init/SqlInitializationScriptsRuntimeHintsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.autoconfigure.init;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SqlInitializationScriptsRuntimeHints}.\n *\n * @author Moritz Halbritter\n */\nclass SqlInitializationScriptsRuntimeHintsTests {\n\n\t@Test\n\tvoid shouldRegisterSchemaHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew SqlInitializationScriptsRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"schema.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"schema-all.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"schema-mysql.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"schema-postgres.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"schema-oracle.sql\")).accepts(hints);\n\t}\n\n\t@Test\n\tvoid shouldRegisterDataHints() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew SqlInitializationScriptsRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"data.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"data-all.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"data-mysql.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"data-postgres.sql\")).accepts(hints);\n\t\tassertThat(RuntimeHintsPredicates.resource().forResource(\"data-oracle.sql\")).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/test/java/org/springframework/boot/sql/init/dependency/DatabaseInitializationDependencyConfigurerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init.dependency;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\n/**\n * Tests for {@link DatabaseInitializationDependencyConfigurer}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass DatabaseInitializationDependencyConfigurerTests {\n\n\tprivate final ConfigurableEnvironment environment = new MockEnvironment();\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@BeforeEach\n\tvoid resetMocks() {\n\t\treset(MockDatabaseInitializerDetector.instance, OrderedNearLowestMockDatabaseInitializerDetector.instance,\n\t\t\t\tOrderedLowestMockDatabaseInitializerDetector.instance,\n\t\t\t\tMockedDependsOnDatabaseInitializationDetector.instance);\n\t}\n\n\t@Test\n\tvoid beanFactoryPostProcessorHasOrderAllowingSubsequentPostProcessorsToFineTuneDependencies() {\n\t\tperformDetection(Arrays.asList(MockDatabaseInitializerDetector.class,\n\t\t\t\tMockedDependsOnDatabaseInitializationDetector.class), (context) -> {\n\t\t\t\t\tBeanDefinition alpha = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\t\t\t\tBeanDefinition bravo = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\t\t\t\tcontext.register(DependsOnCaptor.class);\n\t\t\t\t\tcontext.register(DependencyConfigurerConfiguration.class);\n\t\t\t\t\tcontext.registerBeanDefinition(\"alpha\", alpha);\n\t\t\t\t\tcontext.registerBeanDefinition(\"bravo\", bravo);\n\t\t\t\t\tgiven(MockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(Collections.singleton(\"alpha\"));\n\t\t\t\t\tgiven(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(Collections.singleton(\"bravo\"));\n\t\t\t\t\tcontext.refresh();\n\t\t\t\t\tassertThat(DependsOnCaptor.dependsOn).hasEntrySatisfying(\"bravo\",\n\t\t\t\t\t\t\t(dependencies) -> assertThat(dependencies).containsExactly(\"alpha\"));\n\t\t\t\t\tassertThat(DependsOnCaptor.dependsOn).doesNotContainKey(\"alpha\");\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenDetectorsAreCreatedThenTheEnvironmentCanBeInjected() {\n\t\tperformDetection(Arrays.asList(ConstructorInjectionDatabaseInitializerDetector.class,\n\t\t\t\tConstructorInjectionDependsOnDatabaseInitializationDetector.class), (context) -> {\n\t\t\t\t\tBeanDefinition alpha = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\t\t\t\tcontext.registerBeanDefinition(\"alpha\", alpha);\n\t\t\t\t\tcontext.register(DependencyConfigurerConfiguration.class);\n\t\t\t\t\tcontext.refresh();\n\t\t\t\t\tassertThat(ConstructorInjectionDatabaseInitializerDetector.environment).isEqualTo(this.environment);\n\t\t\t\t\tassertThat(ConstructorInjectionDependsOnDatabaseInitializationDetector.environment)\n\t\t\t\t\t\t.isEqualTo(this.environment);\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenDependenciesAreConfiguredThenBeansThatDependUponDatabaseInitializationDependUponDetectedDatabaseInitializers() {\n\t\tBeanDefinition alpha = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tBeanDefinition bravo = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tperformDetection(Arrays.asList(MockDatabaseInitializerDetector.class,\n\t\t\t\tMockedDependsOnDatabaseInitializationDetector.class), (context) -> {\n\t\t\t\t\tcontext.registerBeanDefinition(\"alpha\", alpha);\n\t\t\t\t\tcontext.registerBeanDefinition(\"bravo\", bravo);\n\t\t\t\t\tgiven(MockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(Collections.singleton(\"alpha\"));\n\t\t\t\t\tgiven(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(Collections.singleton(\"bravo\"));\n\t\t\t\t\tcontext.register(DependencyConfigurerConfiguration.class);\n\t\t\t\t\tcontext.refresh();\n\t\t\t\t\tassertThat(alpha.getAttribute(DatabaseInitializerDetector.class.getName()))\n\t\t\t\t\t\t.isEqualTo(MockDatabaseInitializerDetector.class.getName());\n\t\t\t\t\tassertThat(bravo.getAttribute(DatabaseInitializerDetector.class.getName())).isNull();\n\t\t\t\t\tthen(MockDatabaseInitializerDetector.instance).should()\n\t\t\t\t\t\t.detectionComplete(context.getBeanFactory(), Collections.singleton(\"alpha\"));\n\t\t\t\t\tassertThat(bravo.getDependsOn()).containsExactly(\"alpha\");\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenDependenciesAreConfiguredDetectedDatabaseInitializersAreInitializedInCorrectOrder() {\n\t\tBeanDefinition alpha = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tBeanDefinition bravo1 = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tBeanDefinition bravo2 = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tBeanDefinition charlie = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tBeanDefinition delta = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\tperformDetection(\n\t\t\t\tArrays.asList(MockDatabaseInitializerDetector.class, OrderedLowestMockDatabaseInitializerDetector.class,\n\t\t\t\t\t\tOrderedNearLowestMockDatabaseInitializerDetector.class,\n\t\t\t\t\t\tMockedDependsOnDatabaseInitializationDetector.class),\n\t\t\t\t(context) -> {\n\t\t\t\t\tgiven(MockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(Collections.singleton(\"alpha\"));\n\t\t\t\t\tgiven(OrderedNearLowestMockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(new LinkedHashSet<>(Arrays.asList(\"bravo1\", \"bravo2\")));\n\t\t\t\t\tgiven(OrderedLowestMockDatabaseInitializerDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(new LinkedHashSet<>(Arrays.asList(\"charlie\")));\n\t\t\t\t\tgiven(MockedDependsOnDatabaseInitializationDetector.instance.detect(context.getBeanFactory()))\n\t\t\t\t\t\t.willReturn(Collections.singleton(\"delta\"));\n\t\t\t\t\tcontext.registerBeanDefinition(\"alpha\", alpha);\n\t\t\t\t\tcontext.registerBeanDefinition(\"bravo1\", bravo1);\n\t\t\t\t\tcontext.registerBeanDefinition(\"bravo2\", bravo2);\n\t\t\t\t\tcontext.registerBeanDefinition(\"charlie\", charlie);\n\t\t\t\t\tcontext.registerBeanDefinition(\"delta\", delta);\n\t\t\t\t\tcontext.register(DependencyConfigurerConfiguration.class);\n\t\t\t\t\tcontext.refresh();\n\t\t\t\t\tassertThat(delta.getDependsOn()).containsExactlyInAnyOrder(\"alpha\", \"bravo1\", \"bravo2\", \"charlie\");\n\t\t\t\t\tassertThat(charlie.getDependsOn()).containsExactly(\"bravo1\", \"bravo2\");\n\t\t\t\t\tassertThat(bravo1.getDependsOn()).containsExactly(\"alpha\");\n\t\t\t\t\tassertThat(bravo2.getDependsOn()).containsExactly(\"alpha\");\n\t\t\t\t\tassertThat(alpha.getDependsOn()).isNullOrEmpty();\n\t\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenInAnAotProcessedContextDependsOnDatabaseInitializationPostProcessorDoesNothing() {\n\t\twithAotEnabled(() -> {\n\t\t\tBeanDefinition alpha = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\t\tBeanDefinition bravo = BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition();\n\t\t\tperformDetection(Arrays.asList(MockDatabaseInitializerDetector.class,\n\t\t\t\t\tMockedDependsOnDatabaseInitializationDetector.class), (context) -> {\n\t\t\t\t\t\tcontext.registerBeanDefinition(\"alpha\", alpha);\n\t\t\t\t\t\tcontext.registerBeanDefinition(\"bravo\", bravo);\n\t\t\t\t\t\tcontext.register(DependencyConfigurerConfiguration.class);\n\t\t\t\t\t\tcontext.refresh();\n\t\t\t\t\t\tassertThat(alpha.getAttribute(DatabaseInitializerDetector.class.getName())).isNull();\n\t\t\t\t\t\tassertThat(bravo.getAttribute(DatabaseInitializerDetector.class.getName())).isNull();\n\t\t\t\t\t\tthen(MockDatabaseInitializerDetector.instance).shouldHaveNoInteractions();\n\t\t\t\t\t\tassertThat(bravo.getDependsOn()).isNull();\n\t\t\t\t\t});\n\t\t});\n\t}\n\n\tprivate void withAotEnabled(Runnable action) {\n\t\tSystem.setProperty(\"spring.aot.enabled\", \"true\");\n\t\ttry {\n\t\t\taction.run();\n\t\t}\n\t\tfinally {\n\t\t\tSystem.clearProperty(\"spring.aot.enabled\");\n\t\t}\n\t}\n\n\tprivate void performDetection(Collection<Class<?>> detectors,\n\t\t\tConsumer<AnnotationConfigApplicationContext> contextCallback) {\n\t\tDetectorSpringFactoriesClassLoader detectorSpringFactories = new DetectorSpringFactoriesClassLoader(this.temp);\n\t\tdetectors.forEach(detectorSpringFactories::register);\n\t\ttry (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {\n\t\t\tcontext.setEnvironment(this.environment);\n\t\t\tcontext.setClassLoader(detectorSpringFactories);\n\t\t\tcontextCallback.accept(context);\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(DatabaseInitializationDependencyConfigurer.class)\n\tstatic class DependencyConfigurerConfiguration {\n\n\t}\n\n\tstatic class ConstructorInjectionDatabaseInitializerDetector implements DatabaseInitializerDetector {\n\n\t\tprivate static @Nullable Environment environment;\n\n\t\tConstructorInjectionDatabaseInitializerDetector(Environment environment) {\n\t\t\tConstructorInjectionDatabaseInitializerDetector.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn Collections.singleton(\"alpha\");\n\t\t}\n\n\t}\n\n\tstatic class ConstructorInjectionDependsOnDatabaseInitializationDetector\n\t\t\timplements DependsOnDatabaseInitializationDetector {\n\n\t\tprivate static @Nullable Environment environment;\n\n\t\tConstructorInjectionDependsOnDatabaseInitializationDetector(Environment environment) {\n\t\t\tConstructorInjectionDependsOnDatabaseInitializationDetector.environment = environment;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\n\t}\n\n\tstatic class MockDatabaseInitializerDetector implements DatabaseInitializerDetector {\n\n\t\tprivate static final DatabaseInitializerDetector instance = mock(DatabaseInitializerDetector.class);\n\n\t\t@Override\n\t\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn instance.detect(beanFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic void detectionComplete(ConfigurableListableBeanFactory beanFactory,\n\t\t\t\tSet<String> databaseInitializerNames) {\n\t\t\tinstance.detectionComplete(beanFactory, databaseInitializerNames);\n\t\t}\n\n\t}\n\n\tstatic class OrderedLowestMockDatabaseInitializerDetector implements DatabaseInitializerDetector {\n\n\t\tprivate static final DatabaseInitializerDetector instance = mock(DatabaseInitializerDetector.class);\n\n\t\t@Override\n\t\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn instance.detect(beanFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.LOWEST_PRECEDENCE;\n\t\t}\n\n\t}\n\n\tstatic class OrderedNearLowestMockDatabaseInitializerDetector implements DatabaseInitializerDetector {\n\n\t\tprivate static final DatabaseInitializerDetector instance = mock(DatabaseInitializerDetector.class);\n\n\t\t@Override\n\t\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn instance.detect(beanFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn Ordered.LOWEST_PRECEDENCE - 100;\n\t\t}\n\n\t}\n\n\tstatic class MockedDependsOnDatabaseInitializationDetector implements DependsOnDatabaseInitializationDetector {\n\n\t\tprivate static final DependsOnDatabaseInitializationDetector instance = mock(\n\t\t\t\tDependsOnDatabaseInitializationDetector.class);\n\n\t\t@Override\n\t\tpublic Set<String> detect(ConfigurableListableBeanFactory beanFactory) {\n\t\t\treturn instance.detect(beanFactory);\n\t\t}\n\n\t}\n\n\tstatic class DetectorSpringFactoriesClassLoader extends ClassLoader {\n\n\t\tprivate final Set<Class<DatabaseInitializerDetector>> databaseInitializerDetectors = new HashSet<>();\n\n\t\tprivate final Set<Class<DependsOnDatabaseInitializationDetector>> dependsOnDatabaseInitializationDetectors = new HashSet<>();\n\n\t\tprivate final File temp;\n\n\t\tDetectorSpringFactoriesClassLoader(File temp) {\n\t\t\tthis.temp = temp;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tvoid register(Class<?> detector) {\n\t\t\tif (DatabaseInitializerDetector.class.isAssignableFrom(detector)) {\n\t\t\t\tthis.databaseInitializerDetectors.add((Class<DatabaseInitializerDetector>) detector);\n\t\t\t}\n\t\t\telse if (DependsOnDatabaseInitializationDetector.class.isAssignableFrom(detector)) {\n\t\t\t\tthis.dependsOnDatabaseInitializationDetectors\n\t\t\t\t\t.add((Class<DependsOnDatabaseInitializationDetector>) detector);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalArgumentException(\"Unsupported detector type '\" + detector.getName() + \"'\");\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\t\tif (!\"META-INF/spring.factories\".equals(name)) {\n\t\t\t\treturn super.findResources(name);\n\t\t\t}\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.put(DatabaseInitializerDetector.class.getName(),\n\t\t\t\t\tString.join(\",\", this.databaseInitializerDetectors.stream().map(Class::getName).toList()));\n\t\t\tproperties.put(DependsOnDatabaseInitializationDetector.class.getName(), String.join(\",\",\n\t\t\t\t\tthis.dependsOnDatabaseInitializationDetectors.stream().map(Class::getName).toList()));\n\t\t\tFile springFactories = new File(this.temp, \"spring.factories\");\n\t\t\ttry (FileWriter writer = new FileWriter(springFactories)) {\n\t\t\t\tproperties.store(writer, \"\");\n\t\t\t}\n\t\t\treturn Collections.enumeration(Collections.singleton(springFactories.toURI().toURL()));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DependsOnCaptor {\n\n\t\tstatic final Map<String, List<String>> dependsOn = new HashMap<>();\n\n\t\t@Bean\n\t\tstatic BeanFactoryPostProcessor dependsOnCapturingPostProcessor() {\n\t\t\treturn (beanFactory) -> {\n\t\t\t\tdependsOn.clear();\n\t\t\t\tfor (String name : beanFactory.getBeanDefinitionNames()) {\n\t\t\t\t\tstoreDependsOn(name, beanFactory);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tprivate static void storeDependsOn(String name, ConfigurableListableBeanFactory beanFactory) {\n\t\t\tString[] dependsOn = beanFactory.getBeanDefinition(name).getDependsOn();\n\t\t\tif (dependsOn != null) {\n\t\t\t\tDependsOnCaptor.dependsOn.put(name, Arrays.asList(dependsOn));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/testFixtures/java/org/springframework/boot/sql/init/AbstractScriptDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.dao.DataAccessException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Base class for testing {@link AbstractScriptDatabaseInitializer} implementations.\n *\n * @param <T> type of the initializer being tested\n * @author Andy Wilkinson\n */\npublic abstract class AbstractScriptDatabaseInitializerTests<T extends AbstractScriptDatabaseInitializer> {\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenDatabaseIsInitializedThenSchemaAndDataScriptsAreApplied() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isTrue();\n\t\tassertThat(numberOfEmbeddedRows(\"SELECT COUNT(*) FROM EXAMPLE\")).isOne();\n\t}\n\n\t@Test\n\tvoid whenDatabaseIsInitializedWithDirectoryLocationsThenFailureIsHelpful() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"/org/springframework/boot/sql/init\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"/org/springframework/boot/sql/init\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThatIllegalStateException().isThrownBy(initializer::initializeDatabase)\n\t\t\t.withMessage(\"No schema scripts found at location '/org/springframework/boot/sql/init'\");\n\t}\n\n\t@Test\n\t@WithDataSqlResource\n\tvoid whenContinueOnErrorIsFalseThenInitializationFailsOnError() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThatExceptionOfType(DataAccessException.class).isThrownBy(initializer::initializeDatabase);\n\t\tassertThatDatabaseWasAccessed(initializer);\n\t}\n\n\t@Test\n\t@WithDataSqlResource\n\tvoid whenContinueOnErrorIsTrueThenInitializationDoesNotFailOnError() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setContinueOnError(true);\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isTrue();\n\t\tassertThatDatabaseWasAccessed(initializer);\n\t}\n\n\t@Test\n\tvoid whenNoScriptsExistAtASchemaLocationThenInitializationFails() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"does-not-exist.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThatIllegalStateException().isThrownBy(initializer::initializeDatabase)\n\t\t\t.withMessage(\"No schema scripts found at location 'does-not-exist.sql'\");\n\t\tassertThatDatabaseWasNotAccessed(initializer);\n\t}\n\n\t@Test\n\tvoid whenNoScriptsExistAtADataLocationThenInitializationFails() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setDataLocations(Arrays.asList(\"does-not-exist.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThatIllegalStateException().isThrownBy(initializer::initializeDatabase)\n\t\t\t.withMessage(\"No data scripts found at location 'does-not-exist.sql'\");\n\t\tassertThatDatabaseWasNotAccessed(initializer);\n\t}\n\n\t@Test\n\tvoid whenNoScriptsExistAtAnOptionalSchemaLocationThenDatabaseIsNotAccessed() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"optional:does-not-exist.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isFalse();\n\t\tassertThatDatabaseWasNotAccessed(initializer);\n\t}\n\n\t@Test\n\tvoid whenNoScriptsExistAtAnOptionalDataLocationThenDatabaseIsNotAccessed() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setDataLocations(Arrays.asList(\"optional:does-not-exist.sql\"));\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isFalse();\n\t\tassertThatDatabaseWasNotAccessed(initializer);\n\t}\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenModeIsNeverThenEmbeddedDatabaseIsNotInitialized() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tsettings.setMode(DatabaseInitializationMode.NEVER);\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isFalse();\n\t\tassertThatDatabaseWasNotAccessed(initializer);\n\t}\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenModeIsNeverThenStandaloneDatabaseIsNotInitialized() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tsettings.setMode(DatabaseInitializationMode.NEVER);\n\t\tT initializer = createStandaloneDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isFalse();\n\t\tassertThatDatabaseWasNotAccessed(initializer);\n\t}\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenModeIsEmbeddedThenEmbeddedDatabaseIsInitialized() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tsettings.setMode(DatabaseInitializationMode.EMBEDDED);\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isTrue();\n\t\tassertThat(numberOfEmbeddedRows(\"SELECT COUNT(*) FROM EXAMPLE\")).isOne();\n\t}\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenModeIsEmbeddedThenStandaloneDatabaseIsNotInitialized() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tsettings.setMode(DatabaseInitializationMode.EMBEDDED);\n\t\tT initializer = createStandaloneDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isFalse();\n\t\tassertThatDatabaseWasAccessed(initializer);\n\t}\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenModeIsAlwaysThenEmbeddedDatabaseIsInitialized() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tsettings.setMode(DatabaseInitializationMode.ALWAYS);\n\t\tT initializer = createEmbeddedDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isTrue();\n\t\tassertThat(numberOfEmbeddedRows(\"SELECT COUNT(*) FROM EXAMPLE\")).isOne();\n\t}\n\n\t@Test\n\t@WithSchemaSqlResource\n\t@WithDataSqlResource\n\tvoid whenModeIsAlwaysThenStandaloneDatabaseIsInitialized() {\n\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\tsettings.setSchemaLocations(Arrays.asList(\"schema.sql\"));\n\t\tsettings.setDataLocations(Arrays.asList(\"data.sql\"));\n\t\tsettings.setMode(DatabaseInitializationMode.ALWAYS);\n\t\tT initializer = createStandaloneDatabaseInitializer(settings);\n\t\tassertThat(initializer.initializeDatabase()).isTrue();\n\t\tassertThat(numberOfStandaloneRows(\"SELECT COUNT(*) FROM EXAMPLE\")).isOne();\n\t}\n\n\tprotected abstract T createStandaloneDatabaseInitializer(DatabaseInitializationSettings settings);\n\n\tprotected abstract T createEmbeddedDatabaseInitializer(DatabaseInitializationSettings settings);\n\n\tprotected abstract int numberOfEmbeddedRows(String sql);\n\n\tprotected abstract int numberOfStandaloneRows(String sql);\n\n\tprivate void assertThatDatabaseWasAccessed(T initializer) {\n\t\tassertDatabaseAccessed(true, initializer);\n\t}\n\n\tprivate void assertThatDatabaseWasNotAccessed(T initializer) {\n\t\tassertDatabaseAccessed(false, initializer);\n\t}\n\n\tprotected abstract void assertDatabaseAccessed(boolean accessed, T initializer);\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Target(ElementType.METHOD)\n\t@WithResource(name = \"schema.sql\", content = \"\"\"\n\t\t\tCREATE TABLE EXAMPLE (\n\t\t\t\tid INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\t\t\t\tname VARCHAR(30)\n\t\t\t);\n\t\t\t\"\"\")\n\tprotected @interface WithSchemaSqlResource {\n\n\t}\n\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Target(ElementType.METHOD)\n\t@WithResource(name = \"data.sql\", content = \"INSERT INTO EXAMPLE VALUES (1, 'Andy');\")\n\tprotected @interface WithDataSqlResource {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-sql/src/testFixtures/java/org/springframework/boot/sql/init/ScriptDatabaseInitializerSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.sql.init;\n\n/**\n * Helper to get the settings used by the {@link AbstractScriptDatabaseInitializer}.\n *\n * @author Phillip Webb\n */\npublic final class ScriptDatabaseInitializerSettings {\n\n\tprivate ScriptDatabaseInitializerSettings() {\n\t}\n\n\tpublic static DatabaseInitializationSettings get(AbstractScriptDatabaseInitializer initializer) {\n\t\treturn initializer.getSettings();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-test-classic-modules/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Test Classic Modules\"\n\n// NOTE: This module is broken out so that direct starter dependencies are\n// closer and will be resolved by Maven without the exclusions\n\ndependencies {\n\tapi(project(\":core:spring-boot-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":core:spring-boot-test-autoconfigure\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-cache-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-cassandra-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-couchbase-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-elasticsearch-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-jdbc-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-jpa-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-ldap-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-mongodb-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-neo4j-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-r2dbc-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-data-redis-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-graphql-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-grpc-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jdbc-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jooq-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-jpa-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-metrics-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-micrometer-tracing-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-restclient-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-rsocket-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-security-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-web-server-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webflux-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webmvc-test\")) {\n\t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-webservices-test\")) {\n\t\ttransitive = false\n\t}\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot Thymeleaf\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.thymeleaf:thymeleaf-spring6\")\n\tapi(\"org.springframework:spring-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-webflux\"))\n\toptional(project(\":module:spring-boot-webflux-test\"))\n\toptional(project(\":module:spring-boot-webmvc\"))\n\toptional(project(\":module:spring-boot-webmvc-test\"))\n\toptional(\"org.springframework.security:spring-security-web\")\n\toptional(\"org.thymeleaf:thymeleaf\")\n\toptional(\"org.thymeleaf.extras:thymeleaf-extras-springsecurity6\")\n\toptional(\"com.github.mxab.thymeleaf.extras:thymeleaf-extras-data-attribute\")\n\toptional(\"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test-autoconfigure\"))\n\ttestImplementation(project(\":module:spring-boot-webflux-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf/autoconfigure/TemplateEngineConfigurations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport org.thymeleaf.ITemplateEngine;\nimport org.thymeleaf.dialect.IDialect;\nimport org.thymeleaf.spring6.ISpringTemplateEngine;\nimport org.thymeleaf.spring6.ISpringWebFluxTemplateEngine;\nimport org.thymeleaf.spring6.SpringTemplateEngine;\nimport org.thymeleaf.spring6.SpringWebFluxTemplateEngine;\nimport org.thymeleaf.templateresolver.ITemplateResolver;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration classes for Thymeleaf's {@link ITemplateEngine}. Imported by\n * {@link ThymeleafAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass TemplateEngineConfigurations {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DefaultTemplateEngineConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ISpringTemplateEngine.class)\n\t\tSpringTemplateEngine templateEngine(ThymeleafProperties properties,\n\t\t\t\tObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {\n\t\t\tSpringTemplateEngine engine = new SpringTemplateEngine();\n\t\t\tengine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler());\n\t\t\tengine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes());\n\t\t\ttemplateResolvers.orderedStream().forEach(engine::addTemplateResolver);\n\t\t\tdialects.orderedStream().forEach(engine::addDialect);\n\t\t\treturn engine;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\tstatic class ReactiveTemplateEngineConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ISpringWebFluxTemplateEngine.class)\n\t\tSpringWebFluxTemplateEngine templateEngine(ThymeleafProperties properties,\n\t\t\t\tObjectProvider<ITemplateResolver> templateResolvers, ObjectProvider<IDialect> dialects) {\n\t\t\tSpringWebFluxTemplateEngine engine = new SpringWebFluxTemplateEngine();\n\t\t\tengine.setEnableSpringELCompiler(properties.isEnableSpringElCompiler());\n\t\t\tengine.setRenderHiddenMarkersBeforeCheckboxes(properties.isRenderHiddenMarkersBeforeCheckboxes());\n\t\t\ttemplateResolvers.orderedStream().forEach(engine::addTemplateResolver);\n\t\t\tdialects.orderedStream().forEach(engine::addDialect);\n\t\t\treturn engine;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport java.util.LinkedHashMap;\n\nimport com.github.mxab.thymeleaf.extras.dataattribute.dialect.DataAttributeDialect;\nimport jakarta.servlet.DispatcherType;\nimport nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;\nimport org.thymeleaf.spring6.ISpringWebFluxTemplateEngine;\nimport org.thymeleaf.spring6.SpringTemplateEngine;\nimport org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;\nimport org.thymeleaf.spring6.view.ThymeleafViewResolver;\nimport org.thymeleaf.spring6.view.reactive.ThymeleafReactiveViewResolver;\nimport org.thymeleaf.templatemode.TemplateMode;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.template.TemplateLocation;\nimport org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.thymeleaf.autoconfigure.ThymeleafProperties.Reactive;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.security.web.server.csrf.CsrfToken;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;\nimport org.springframework.web.servlet.view.AbstractCachingViewResolver;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Thymeleaf.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @author Eddú Meléndez\n * @author Daniel Fernández\n * @author Kazuki Shimizu\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration\",\n\t\t\"org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration\" })\n@EnableConfigurationProperties(ThymeleafProperties.class)\n@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class })\n@Import({ TemplateEngineConfigurations.ReactiveTemplateEngineConfiguration.class,\n\t\tTemplateEngineConfigurations.DefaultTemplateEngineConfiguration.class })\npublic final class ThymeleafAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnMissingBean(name = \"defaultTemplateResolver\")\n\tstatic class DefaultTemplateResolverConfiguration {\n\n\t\tprivate static final Log logger = LogFactory.getLog(DefaultTemplateResolverConfiguration.class);\n\n\t\tprivate final ThymeleafProperties properties;\n\n\t\tprivate final ApplicationContext applicationContext;\n\n\t\tDefaultTemplateResolverConfiguration(ThymeleafProperties properties, ApplicationContext applicationContext) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.applicationContext = applicationContext;\n\t\t\tcheckTemplateLocationExists();\n\t\t}\n\n\t\tprivate void checkTemplateLocationExists() {\n\t\t\tboolean checkTemplateLocation = this.properties.isCheckTemplateLocation();\n\t\t\tif (checkTemplateLocation) {\n\t\t\t\tTemplateLocation location = new TemplateLocation(this.properties.getPrefix());\n\t\t\t\tif (!location.exists(this.applicationContext)) {\n\t\t\t\t\tlogger.warn(\"Cannot find template location: \" + location\n\t\t\t\t\t\t\t+ \" (please add some templates, check your Thymeleaf configuration, or set spring.thymeleaf.\"\n\t\t\t\t\t\t\t+ \"check-template-location=false)\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tSpringResourceTemplateResolver defaultTemplateResolver() {\n\t\t\tSpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();\n\t\t\tresolver.setApplicationContext(this.applicationContext);\n\t\t\tresolver.setPrefix(this.properties.getPrefix());\n\t\t\tresolver.setSuffix(this.properties.getSuffix());\n\t\t\tresolver.setTemplateMode(this.properties.getMode());\n\t\t\tif (this.properties.getEncoding() != null) {\n\t\t\t\tresolver.setCharacterEncoding(this.properties.getEncoding().name());\n\t\t\t}\n\t\t\tresolver.setCacheable(this.properties.isCache());\n\t\t\tInteger order = this.properties.getTemplateResolverOrder();\n\t\t\tif (order != null) {\n\t\t\t\tresolver.setOrder(order);\n\t\t\t}\n\t\t\tresolver.setCheckExistence(this.properties.isCheckTemplate());\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.SERVLET)\n\tstatic class ThymeleafWebMvcConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnEnabledResourceChain\n\t\t@ConditionalOnMissingFilterBean\n\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> resourceUrlEncodingFilter() {\n\t\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> registration = new FilterRegistrationBean<>(\n\t\t\t\t\tnew ResourceUrlEncodingFilter());\n\t\t\tregistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);\n\t\t\treturn registration;\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@ConditionalOnClass(AbstractCachingViewResolver.class)\n\t\tstatic class ThymeleafViewResolverConfiguration {\n\n\t\t\t@Bean\n\t\t\t@ConditionalOnMissingBean(name = \"thymeleafViewResolver\")\n\t\t\tThymeleafViewResolver thymeleafViewResolver(ThymeleafProperties properties,\n\t\t\t\t\tSpringTemplateEngine templateEngine) {\n\t\t\t\tThymeleafViewResolver resolver = new ThymeleafViewResolver();\n\t\t\t\tresolver.setTemplateEngine(templateEngine);\n\t\t\t\tresolver.setCharacterEncoding(properties.getEncoding().name());\n\t\t\t\tresolver.setContentType(\n\t\t\t\t\t\tappendCharset(properties.getServlet().getContentType(), resolver.getCharacterEncoding()));\n\t\t\t\tresolver.setProducePartialOutputWhileProcessing(\n\t\t\t\t\t\tproperties.getServlet().isProducePartialOutputWhileProcessing());\n\t\t\t\tresolver.setExcludedViewNames(properties.getExcludedViewNames());\n\t\t\t\tresolver.setViewNames(properties.getViewNames());\n\t\t\t\t// This resolver acts as a fallback resolver (e.g. like a\n\t\t\t\t// InternalResourceViewResolver) so it needs to have low precedence\n\t\t\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);\n\t\t\t\tresolver.setCache(properties.isCache());\n\t\t\t\treturn resolver;\n\t\t\t}\n\n\t\t\tprivate String appendCharset(MimeType type, String charset) {\n\t\t\t\tif (type.getCharset() != null) {\n\t\t\t\t\treturn type.toString();\n\t\t\t\t}\n\t\t\t\tLinkedHashMap<String, String> parameters = new LinkedHashMap<>();\n\t\t\t\tparameters.put(\"charset\", charset);\n\t\t\t\tparameters.putAll(type.getParameters());\n\t\t\t\treturn new MimeType(type, parameters).toString();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnWebApplication(type = Type.REACTIVE)\n\tstatic class ThymeleafWebFluxConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = \"thymeleafReactiveViewResolver\")\n\t\tThymeleafReactiveViewResolver thymeleafViewResolver(ISpringWebFluxTemplateEngine templateEngine,\n\t\t\t\tThymeleafProperties properties) {\n\t\t\tThymeleafReactiveViewResolver resolver = new ThymeleafReactiveViewResolver();\n\t\t\tresolver.setTemplateEngine(templateEngine);\n\t\t\tmapProperties(properties, resolver);\n\t\t\tmapReactiveProperties(properties.getReactive(), resolver);\n\t\t\t// This resolver acts as a fallback resolver (e.g. like a\n\t\t\t// InternalResourceViewResolver) so it needs to have low precedence\n\t\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);\n\t\t\treturn resolver;\n\t\t}\n\n\t\tprivate void mapProperties(ThymeleafProperties properties, ThymeleafReactiveViewResolver resolver) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getEncoding).to(resolver::setDefaultCharset);\n\t\t\tresolver.setExcludedViewNames(properties.getExcludedViewNames());\n\t\t\tresolver.setViewNames(properties.getViewNames());\n\t\t}\n\n\t\tprivate void mapReactiveProperties(Reactive properties, ThymeleafReactiveViewResolver resolver) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(properties::getMediaTypes).to(resolver::setSupportedMediaTypes);\n\t\t\tmap.from(properties::getMaxChunkSize)\n\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t.when((size) -> size > 0)\n\t\t\t\t.to(resolver::setResponseMaxChunkSizeBytes);\n\t\t\tmap.from(properties::getFullModeViewNames).to(resolver::setFullModeViewNames);\n\t\t\tmap.from(properties::getChunkedModeViewNames).to(resolver::setChunkedModeViewNames);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(LayoutDialect.class)\n\tstatic class ThymeleafWebLayoutConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tLayoutDialect layoutDialect() {\n\t\t\treturn new LayoutDialect();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(DataAttributeDialect.class)\n\tstatic class DataAttributeDialectConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tDataAttributeDialect dialect() {\n\t\t\treturn new DataAttributeDialect();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ SpringSecurityDialect.class, CsrfToken.class })\n\tstatic class ThymeleafSecurityDialectConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tSpringSecurityDialect securityDialect() {\n\t\t\treturn new SpringSecurityDialect();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.MimeType;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Properties for Thymeleaf.\n *\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @author Daniel Fernández\n * @author Kazuki Shimizu\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.thymeleaf\")\npublic class ThymeleafProperties {\n\n\tprivate static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;\n\n\tpublic static final String DEFAULT_PREFIX = \"classpath:/templates/\";\n\n\tpublic static final String DEFAULT_SUFFIX = \".html\";\n\n\t/**\n\t * Whether to check that the template exists before rendering it.\n\t */\n\tprivate boolean checkTemplate = true;\n\n\t/**\n\t * Whether to check that the templates location exists.\n\t */\n\tprivate boolean checkTemplateLocation = true;\n\n\t/**\n\t * Prefix that gets prepended to view names when building a URL.\n\t */\n\tprivate String prefix = DEFAULT_PREFIX;\n\n\t/**\n\t * Suffix that gets appended to view names when building a URL.\n\t */\n\tprivate String suffix = DEFAULT_SUFFIX;\n\n\t/**\n\t * Template mode to be applied to templates. See also Thymeleaf's TemplateMode enum.\n\t */\n\tprivate String mode = \"HTML\";\n\n\t/**\n\t * Template files encoding.\n\t */\n\tprivate Charset encoding = DEFAULT_ENCODING;\n\n\t/**\n\t * Whether to enable template caching.\n\t */\n\tprivate boolean cache = true;\n\n\t/**\n\t * Order of the template resolver in the chain. By default, the template resolver is\n\t * first in the chain. Order start at 1 and should only be set if you have defined\n\t * additional \"TemplateResolver\" beans.\n\t */\n\tprivate @Nullable Integer templateResolverOrder;\n\n\t/**\n\t * List of view names (patterns allowed) that can be resolved.\n\t */\n\tprivate String @Nullable [] viewNames;\n\n\t/**\n\t * List of view names (patterns allowed) that should be excluded from resolution.\n\t */\n\tprivate String @Nullable [] excludedViewNames;\n\n\t/**\n\t * Enable the SpringEL compiler in SpringEL expressions.\n\t */\n\tprivate boolean enableSpringElCompiler;\n\n\t/**\n\t * Whether hidden form inputs acting as markers for checkboxes should be rendered\n\t * before the checkbox element itself.\n\t */\n\tprivate boolean renderHiddenMarkersBeforeCheckboxes;\n\n\tprivate final Servlet servlet = new Servlet();\n\n\tprivate final Reactive reactive = new Reactive();\n\n\tpublic boolean isCheckTemplate() {\n\t\treturn this.checkTemplate;\n\t}\n\n\tpublic void setCheckTemplate(boolean checkTemplate) {\n\t\tthis.checkTemplate = checkTemplate;\n\t}\n\n\tpublic boolean isCheckTemplateLocation() {\n\t\treturn this.checkTemplateLocation;\n\t}\n\n\tpublic void setCheckTemplateLocation(boolean checkTemplateLocation) {\n\t\tthis.checkTemplateLocation = checkTemplateLocation;\n\t}\n\n\tpublic String getPrefix() {\n\t\treturn this.prefix;\n\t}\n\n\tpublic void setPrefix(String prefix) {\n\t\tthis.prefix = prefix;\n\t}\n\n\tpublic String getSuffix() {\n\t\treturn this.suffix;\n\t}\n\n\tpublic void setSuffix(String suffix) {\n\t\tthis.suffix = suffix;\n\t}\n\n\tpublic String getMode() {\n\t\treturn this.mode;\n\t}\n\n\tpublic void setMode(String mode) {\n\t\tthis.mode = mode;\n\t}\n\n\tpublic Charset getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\tpublic void setEncoding(Charset encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\tpublic boolean isCache() {\n\t\treturn this.cache;\n\t}\n\n\tpublic void setCache(boolean cache) {\n\t\tthis.cache = cache;\n\t}\n\n\tpublic @Nullable Integer getTemplateResolverOrder() {\n\t\treturn this.templateResolverOrder;\n\t}\n\n\tpublic void setTemplateResolverOrder(@Nullable Integer templateResolverOrder) {\n\t\tthis.templateResolverOrder = templateResolverOrder;\n\t}\n\n\tpublic String @Nullable [] getExcludedViewNames() {\n\t\treturn this.excludedViewNames;\n\t}\n\n\tpublic void setExcludedViewNames(String @Nullable [] excludedViewNames) {\n\t\tthis.excludedViewNames = excludedViewNames;\n\t}\n\n\tpublic String @Nullable [] getViewNames() {\n\t\treturn this.viewNames;\n\t}\n\n\tpublic void setViewNames(String @Nullable [] viewNames) {\n\t\tthis.viewNames = viewNames;\n\t}\n\n\tpublic boolean isEnableSpringElCompiler() {\n\t\treturn this.enableSpringElCompiler;\n\t}\n\n\tpublic void setEnableSpringElCompiler(boolean enableSpringElCompiler) {\n\t\tthis.enableSpringElCompiler = enableSpringElCompiler;\n\t}\n\n\tpublic boolean isRenderHiddenMarkersBeforeCheckboxes() {\n\t\treturn this.renderHiddenMarkersBeforeCheckboxes;\n\t}\n\n\tpublic void setRenderHiddenMarkersBeforeCheckboxes(boolean renderHiddenMarkersBeforeCheckboxes) {\n\t\tthis.renderHiddenMarkersBeforeCheckboxes = renderHiddenMarkersBeforeCheckboxes;\n\t}\n\n\tpublic Reactive getReactive() {\n\t\treturn this.reactive;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Content-Type value written to HTTP responses.\n\t\t */\n\t\tprivate MimeType contentType = MimeType.valueOf(\"text/html\");\n\n\t\t/**\n\t\t * Whether Thymeleaf should start writing partial output as soon as possible or\n\t\t * buffer until template processing is finished.\n\t\t */\n\t\tprivate boolean producePartialOutputWhileProcessing = true;\n\n\t\tpublic MimeType getContentType() {\n\t\t\treturn this.contentType;\n\t\t}\n\n\t\tpublic void setContentType(MimeType contentType) {\n\t\t\tthis.contentType = contentType;\n\t\t}\n\n\t\tpublic boolean isProducePartialOutputWhileProcessing() {\n\t\t\treturn this.producePartialOutputWhileProcessing;\n\t\t}\n\n\t\tpublic void setProducePartialOutputWhileProcessing(boolean producePartialOutputWhileProcessing) {\n\t\t\tthis.producePartialOutputWhileProcessing = producePartialOutputWhileProcessing;\n\t\t}\n\n\t}\n\n\tpublic static class Reactive {\n\n\t\t/**\n\t\t * Maximum size of data buffers used for writing to the response. Templates will\n\t\t * execute in CHUNKED mode by default if this is set.\n\t\t */\n\t\tprivate DataSize maxChunkSize = DataSize.ofBytes(0);\n\n\t\t/**\n\t\t * Media types supported by the view technology.\n\t\t */\n\t\tprivate @Nullable List<MediaType> mediaTypes;\n\n\t\t/**\n\t\t * Comma-separated list of view names (patterns allowed) that should be executed\n\t\t * in FULL mode even if a max chunk size is set.\n\t\t */\n\t\tprivate String @Nullable [] fullModeViewNames;\n\n\t\t/**\n\t\t * Comma-separated list of view names (patterns allowed) that should be the only\n\t\t * ones executed in CHUNKED mode when a max chunk size is set.\n\t\t */\n\t\tprivate String @Nullable [] chunkedModeViewNames;\n\n\t\tpublic @Nullable List<MediaType> getMediaTypes() {\n\t\t\treturn this.mediaTypes;\n\t\t}\n\n\t\tpublic void setMediaTypes(@Nullable List<MediaType> mediaTypes) {\n\t\t\tthis.mediaTypes = mediaTypes;\n\t\t}\n\n\t\tpublic DataSize getMaxChunkSize() {\n\t\t\treturn this.maxChunkSize;\n\t\t}\n\n\t\tpublic void setMaxChunkSize(DataSize maxChunkSize) {\n\t\t\tthis.maxChunkSize = maxChunkSize;\n\t\t}\n\n\t\tpublic String @Nullable [] getFullModeViewNames() {\n\t\t\treturn this.fullModeViewNames;\n\t\t}\n\n\t\tpublic void setFullModeViewNames(String @Nullable [] fullModeViewNames) {\n\t\t\tthis.fullModeViewNames = fullModeViewNames;\n\t\t}\n\n\t\tpublic String @Nullable [] getChunkedModeViewNames() {\n\t\t\treturn this.chunkedModeViewNames;\n\t\t}\n\n\t\tpublic void setChunkedModeViewNames(String @Nullable [] chunkedModeViewNames) {\n\t\t\tthis.chunkedModeViewNames = chunkedModeViewNames;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafTemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TemplateAvailabilityProvider} that provides availability information for\n * Thymeleaf view templates.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class ThymeleafTemplateAvailabilityProvider implements TemplateAvailabilityProvider {\n\n\t@Override\n\tpublic boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\tResourceLoader resourceLoader) {\n\t\tif (ClassUtils.isPresent(\"org.thymeleaf.spring6.SpringTemplateEngine\", classLoader)) {\n\t\t\tString prefix = environment.getProperty(\"spring.thymeleaf.prefix\", ThymeleafProperties.DEFAULT_PREFIX);\n\t\t\tString suffix = environment.getProperty(\"spring.thymeleaf.suffix\", ThymeleafProperties.DEFAULT_SUFFIX);\n\t\t\treturn resourceLoader.getResource(prefix + view + suffix).exists();\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/java/org/springframework/boot/thymeleaf/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Thymeleaf.\n */\n@NullMarked\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.thymeleaf.enabled\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"No longer required. To use Thymeleaf without auto-configuration, depend directly on Thymeleaf instead of spring-boot-thymeleaf.\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.thymeleaf.prefix\",\n      \"defaultValue\": \"classpath:/templates/\"\n    },\n    {\n      \"name\": \"spring.thymeleaf.reactive.media-types\",\n      \"defaultValue\": [\n        \"text/html\",\n        \"application/xhtml+xml\",\n        \"application/xml\",\n        \"text/xml\",\n        \"application/rss+xml\",\n        \"application/atom+xml\",\n        \"application/javascript\",\n        \"application/ecmascript\",\n        \"text/javascript\",\n        \"text/ecmascript\",\n        \"application/json\",\n        \"text/css\",\n        \"text/plain\",\n        \"text/event-stream\"\n      ]\n    },\n    {\n      \"name\": \"spring.thymeleaf.suffix\",\n      \"defaultValue\": \".html\"\n    }\n  ],\n  \"hints\": [],\n  \"ignored\": {\n    \"properties\": [\n    ]\n  }\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.thymeleaf.autoconfigure.ThymeleafAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.AutoConfigureWebFlux.imports",
    "content": "org.springframework.boot.thymeleaf.autoconfigure.ThymeleafAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.WebFluxTest.includes",
    "content": "org.thymeleaf.dialect.IDialect\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.thymeleaf.autoconfigure.ThymeleafAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest.includes",
    "content": "org.thymeleaf.dialect.IDialect\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.thymeleaf.cache=false\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/main/resources/META-INF/spring.factories",
    "content": "# Template Availability Providers\norg.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\\\norg.springframework.boot.thymeleaf.autoconfigure.ThymeleafTemplateAvailabilityProvider\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafReactiveAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.Locale;\n\nimport nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;\nimport nz.net.ultraq.thymeleaf.layoutdialect.decorators.strategies.GroupingStrategy;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.thymeleaf.TemplateEngine;\nimport org.thymeleaf.context.Context;\nimport org.thymeleaf.context.WebContext;\nimport org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;\nimport org.thymeleaf.extras.springsecurity6.util.SpringSecurityContextUtils;\nimport org.thymeleaf.spring6.ISpringWebFluxTemplateEngine;\nimport org.thymeleaf.spring6.SpringWebFluxTemplateEngine;\nimport org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;\nimport org.thymeleaf.spring6.view.reactive.ThymeleafReactiveViewResolver;\nimport org.thymeleaf.spring6.web.webflux.SpringWebFluxWebApplication;\nimport org.thymeleaf.templateresolver.ITemplateResolver;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.security.authentication.TestingAuthenticationToken;\nimport org.springframework.security.core.context.SecurityContextImpl;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ThymeleafAutoConfiguration} in Reactive applications.\n *\n * @author Brian Clozel\n * @author Kazuki Shimizu\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ThymeleafReactiveAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class));\n\n\t@Test\n\t@WithResource(name = \"templates/template.html\", content = \"<html th:text=\\\"${foo}\\\">foo</html>\")\n\tvoid createFromConfigClass() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.suffix:.html\").run((context) -> {\n\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"foo\", \"bar\"));\n\t\t\tString result = engine.process(\"template\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html>bar</html>\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid overrideCharacterEncoding() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.encoding:UTF-16\").run((context) -> {\n\t\t\tITemplateResolver resolver = context.getBean(ITemplateResolver.class);\n\t\t\tassertThat(resolver).isInstanceOf(SpringResourceTemplateResolver.class);\n\t\t\tassertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding()).isEqualTo(\"UTF-16\");\n\t\t\tThymeleafReactiveViewResolver views = context.getBean(ThymeleafReactiveViewResolver.class);\n\t\t\tassertThat(views.getDefaultCharset().name()).isEqualTo(\"UTF-16\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultMediaTypes() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.getBean(ThymeleafReactiveViewResolver.class).getSupportedMediaTypes())\n\t\t\t\t.containsExactly(MediaType.TEXT_HTML, MediaType.APPLICATION_XHTML_XML, MediaType.APPLICATION_XML,\n\t\t\t\t\t\tMediaType.TEXT_XML, MediaType.APPLICATION_RSS_XML, MediaType.APPLICATION_ATOM_XML,\n\t\t\t\t\t\tnew MediaType(\"application\", \"javascript\"), new MediaType(\"application\", \"ecmascript\"),\n\t\t\t\t\t\tnew MediaType(\"text\", \"javascript\"), new MediaType(\"text\", \"ecmascript\"),\n\t\t\t\t\t\tMediaType.APPLICATION_JSON, new MediaType(\"text\", \"css\"), MediaType.TEXT_PLAIN,\n\t\t\t\t\t\tMediaType.TEXT_EVENT_STREAM));\n\t}\n\n\t@Test\n\tvoid overrideMediaTypes() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.reactive.media-types:text/html,text/plain\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThymeleafReactiveViewResolver.class).getSupportedMediaTypes())\n\t\t\t\t.containsExactly(MediaType.TEXT_HTML, MediaType.TEXT_PLAIN));\n\t}\n\n\t@Test\n\tvoid overrideTemplateResolverOrder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.templateResolverOrder:25\")\n\t\t\t.run((context) -> assertThat(context.getBean(ITemplateResolver.class).getOrder())\n\t\t\t\t.isEqualTo(Integer.valueOf(25)));\n\t}\n\n\t@Test\n\tvoid overrideViewNames() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.viewNames:foo,bar\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThymeleafReactiveViewResolver.class).getViewNames())\n\t\t\t\t.isEqualTo(new String[] { \"foo\", \"bar\" }));\n\t}\n\n\t@Test\n\tvoid overrideMaxChunkSize() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.reactive.maxChunkSize:8KB\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(ThymeleafReactiveViewResolver.class).getResponseMaxChunkSizeBytes())\n\t\t\t\t.isEqualTo(Integer.valueOf(8192)));\n\t}\n\n\t@Test\n\tvoid overrideFullModeViewNames() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.reactive.fullModeViewNames:foo,bar\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThymeleafReactiveViewResolver.class).getFullModeViewNames())\n\t\t\t\t.isEqualTo(new String[] { \"foo\", \"bar\" }));\n\t}\n\n\t@Test\n\tvoid overrideChunkedModeViewNames() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.reactive.chunkedModeViewNames:foo,bar\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThymeleafReactiveViewResolver.class).getChunkedModeViewNames())\n\t\t\t\t.isEqualTo(new String[] { \"foo\", \"bar\" }));\n\t}\n\n\t@Test\n\tvoid overrideEnableSpringElCompiler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.enable-spring-el-compiler:true\")\n\t\t\t.run((context) -> assertThat(context.getBean(SpringWebFluxTemplateEngine.class).getEnableSpringELCompiler())\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid enableSpringElCompilerIsDisabledByDefault() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.getBean(SpringWebFluxTemplateEngine.class).getEnableSpringELCompiler())\n\t\t\t\t.isFalse());\n\t}\n\n\t@Test\n\tvoid overrideRenderHiddenMarkersBeforeCheckboxes() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.render-hidden-markers-before-checkboxes:true\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(SpringWebFluxTemplateEngine.class).getRenderHiddenMarkersBeforeCheckboxes())\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(\n\t\t\t\tcontext.getBean(SpringWebFluxTemplateEngine.class).getRenderHiddenMarkersBeforeCheckboxes())\n\t\t\t.isFalse());\n\t}\n\n\t@Test\n\tvoid templateLocationDoesNotExist(CapturedOutput output) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.prefix:classpath:/no-such-directory/\")\n\t\t\t.run((context) -> assertThat(output).contains(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\tvoid templateLocationEmpty(CapturedOutput output, @TempDir Path tempDir) throws IOException {\n\t\tPath directory = tempDir.resolve(\"empty-templates/empty-directory\").toAbsolutePath();\n\t\tFiles.createDirectories(directory);\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.prefix:file:\" + directory)\n\t\t\t.run((context) -> assertThat(output).doesNotContain(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/data-dialect.html\", content = \"<html><body data:foo=\\\"${foo}\\\"></body></html>\")\n\tvoid useDataDialect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tISpringWebFluxTemplateEngine engine = context.getBean(ISpringWebFluxTemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"foo\", \"bar\"));\n\t\t\tString result = engine.process(\"data-dialect\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html><body data-foo=\\\"bar\\\"></body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/java8time-dialect.html\",\n\t\t\tcontent = \"<html><body th:text=\\\"${#temporals.create('2015','11','24')}\\\"></body></html>\")\n\tvoid useJava8TimeDialect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tISpringWebFluxTemplateEngine engine = context.getBean(ISpringWebFluxTemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK);\n\t\t\tString result = engine.process(\"java8time-dialect\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html><body>2015-11-24</body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/security-dialect.html\",\n\t\t\tcontent = \"<html><body><div sec:authentication=\\\"name\\\"></div></body></html>\")\n\tvoid useSecurityDialect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tISpringWebFluxTemplateEngine engine = context.getBean(ISpringWebFluxTemplateEngine.class);\n\t\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/test\").build());\n\t\t\texchange.getAttributes()\n\t\t\t\t.put(SpringSecurityContextUtils.SECURITY_CONTEXT_MODEL_ATTRIBUTE_NAME,\n\t\t\t\t\t\tnew SecurityContextImpl(new TestingAuthenticationToken(\"alice\", \"admin\")));\n\t\t\tWebContext attrs = new WebContext(SpringWebFluxWebApplication.buildApplication(null)\n\t\t\t\t.buildExchange(exchange, Locale.US, MediaType.TEXT_HTML, StandardCharsets.UTF_8));\n\t\t\tString result = engine.process(\"security-dialect\", attrs);\n\t\t\tassertThat(result).isEqualTo(\"<html><body><div>alice</div></body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid securityDialectAutoConfigurationBacksOffWithoutSpringSecurity() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.security\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringSecurityDialect.class));\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.html\", content = \"<html><body th:text=\\\"${foo}\\\">Home</body></html>\")\n\tvoid renderTemplate() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tISpringWebFluxTemplateEngine engine = context.getBean(ISpringWebFluxTemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"foo\", \"bar\"));\n\t\t\tString result = engine.process(\"home\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html><body>bar</body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid layoutDialectCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tReflectionTestUtils.getField(context.getBean(LayoutDialect.class), \"sortingStrategy\"))\n\t\t\t\t.isInstanceOf(GroupingStrategy.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LayoutDialectConfiguration {\n\n\t\t@Bean\n\t\tLayoutDialect layoutDialect() {\n\t\t\treturn new LayoutDialect().withSortingStrategy(new GroupingStrategy());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafServletAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.ServletContext;\nimport nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;\nimport nz.net.ultraq.thymeleaf.layoutdialect.decorators.strategies.GroupingStrategy;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.thymeleaf.TemplateEngine;\nimport org.thymeleaf.context.Context;\nimport org.thymeleaf.context.WebContext;\nimport org.thymeleaf.extras.springsecurity6.dialect.SpringSecurityDialect;\nimport org.thymeleaf.spring6.SpringTemplateEngine;\nimport org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;\nimport org.thymeleaf.spring6.view.ThymeleafView;\nimport org.thymeleaf.spring6.view.ThymeleafViewResolver;\nimport org.thymeleaf.templateresolver.ITemplateResolver;\nimport org.thymeleaf.web.servlet.JakartaServletWebApplication;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.servlet.filter.OrderedCharacterEncodingFilter;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.security.authentication.TestingAuthenticationToken;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.core.context.SecurityContextImpl;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.servlet.ViewResolver;\nimport org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;\nimport org.springframework.web.servlet.support.RequestContext;\nimport org.springframework.web.servlet.view.AbstractCachingViewResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ThymeleafAutoConfiguration} in Servlet-based applications.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Brian Clozel\n * @author Kazuki Shimizu\n * @author Artsiom Yudovin\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ThymeleafServletAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfigurationBackOffWithoutThymeleafSpring() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.thymeleaf.spring6\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TemplateEngine.class));\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/template.html\", content = \"<html th:text=\\\"${foo}\\\">foo</html>\")\n\tvoid createFromConfigClass() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.mode:HTML\", \"spring.thymeleaf.suffix:\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TemplateEngine.class);\n\t\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"foo\", \"bar\"));\n\t\t\t\tString result = engine.process(\"template.html\", attrs).trim();\n\t\t\t\tassertThat(result).isEqualTo(\"<html>bar</html>\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid overrideCharacterEncoding() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.encoding:UTF-16\").run((context) -> {\n\t\t\tITemplateResolver resolver = context.getBean(ITemplateResolver.class);\n\t\t\tassertThat(resolver).isInstanceOf(SpringResourceTemplateResolver.class);\n\t\t\tassertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding()).isEqualTo(\"UTF-16\");\n\t\t\tThymeleafViewResolver views = context.getBean(ThymeleafViewResolver.class);\n\t\t\tassertThat(views.getCharacterEncoding()).isEqualTo(\"UTF-16\");\n\t\t\tassertThat(views.getContentType()).isEqualTo(\"text/html;charset=UTF-16\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid overrideDisableProducePartialOutputWhileProcessing() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.servlet.produce-partial-output-while-processing:false\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(ThymeleafViewResolver.class).getProducePartialOutputWhileProcessing())\n\t\t\t\t.isFalse());\n\t}\n\n\t@Test\n\tvoid disableProducePartialOutputWhileProcessingIsEnabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(\n\t\t\t\tcontext.getBean(ThymeleafViewResolver.class).getProducePartialOutputWhileProcessing())\n\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid overrideTemplateResolverOrder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.templateResolverOrder:25\")\n\t\t\t.run((context) -> assertThat(context.getBean(ITemplateResolver.class).getOrder())\n\t\t\t\t.isEqualTo(Integer.valueOf(25)));\n\t}\n\n\t@Test\n\tvoid overrideViewNames() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.viewNames:foo,bar\")\n\t\t\t.run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class).getViewNames())\n\t\t\t\t.isEqualTo(new String[] { \"foo\", \"bar\" }));\n\t}\n\n\t@Test\n\tvoid overrideEnableSpringElCompiler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.enable-spring-el-compiler:true\")\n\t\t\t.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class).getEnableSpringELCompiler())\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid enableSpringElCompilerIsDisabledByDefault() {\n\t\tthis.contextRunner\n\t\t\t.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class).getEnableSpringELCompiler())\n\t\t\t\t.isFalse());\n\t}\n\n\t@Test\n\tvoid overrideRenderHiddenMarkersBeforeCheckboxes() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.render-hidden-markers-before-checkboxes:true\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(SpringTemplateEngine.class).getRenderHiddenMarkersBeforeCheckboxes())\n\t\t\t\t.isTrue());\n\t}\n\n\t@Test\n\tvoid enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(\n\t\t\t\tcontext.getBean(SpringTemplateEngine.class).getRenderHiddenMarkersBeforeCheckboxes())\n\t\t\t.isFalse());\n\t}\n\n\t@Test\n\tvoid templateLocationDoesNotExist(CapturedOutput output) {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.prefix:classpath:/no-such-directory/\")\n\t\t\t.run((context) -> assertThat(output).contains(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\tvoid templateLocationEmpty(CapturedOutput output, @TempDir Path tempDir) throws IOException {\n\t\tPath directory = tempDir.resolve(\"empty-templates/empty-directory\").toAbsolutePath();\n\t\tFiles.createDirectories(directory);\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.prefix:file:\" + directory)\n\t\t\t.run((context) -> assertThat(output).doesNotContain(\"Cannot find template location\"));\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/view.html\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\t<html xmlns:th=\"https://www.thymeleaf.org\" xmlns:layout=\"https://www.ultraq.net.nz/web/thymeleaf/layout\" layout:decorator=\"layout\">\n\t\t\t\t\t  <head>\n\t\t\t\t\t    <title layout:fragment=\"title\">Content</title>\n\t\t\t\t\t  </head>\n\t\t\t\t\t  <body>\n\t\t\t\t\t    <div layout:fragment=\"content\">\n\t\t\t\t\t    \t<span th:text=\"${foo}\">foo</span>\n\t\t\t\t\t    </div>\n\t\t\t\t\t  </body>\n\t\t\t\t\t</html>\n\t\t\t\t\t\"\"\")\n\tvoid createLayoutFromConfigClass() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tThymeleafView view = (ThymeleafView) context.getBean(ThymeleafViewResolver.class)\n\t\t\t\t.resolveViewName(\"view\", Locale.UK);\n\t\t\tassertThat(view).isNotNull();\n\t\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest(context.getBean(ServletContext.class));\n\t\t\trequest.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);\n\t\t\tview.render(Collections.singletonMap(\"foo\", \"bar\"), request, response);\n\t\t\tString result = response.getContentAsString();\n\t\t\tassertThat(result).contains(\"<title>Content</title>\");\n\t\t\tassertThat(result).contains(\"<span>bar</span>\");\n\t\t\tcontext.close();\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/data-dialect.html\", content = \"<html><body data:foo=\\\"${foo}\\\"></body></html>\")\n\tvoid useDataDialect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"foo\", \"bar\"));\n\t\t\tString result = engine.process(\"data-dialect\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html><body data-foo=\\\"bar\\\"></body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/java8time-dialect.html\",\n\t\t\tcontent = \"<html><body th:text=\\\"${#temporals.create('2015','11','24')}\\\"></body></html>\")\n\tvoid useJava8TimeDialect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK);\n\t\t\tString result = engine.process(\"java8time-dialect\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html><body>2015-11-24</body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/security-dialect.html\",\n\t\t\tcontent = \"<html><body><div sec:authentication=\\\"name\\\"></div></body></html>\")\n\tvoid useSecurityDialect() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\tMockServletContext servletContext = new MockServletContext();\n\t\t\tJakartaServletWebApplication webApplication = JakartaServletWebApplication.buildApplication(servletContext);\n\t\t\tWebContext attrs = new WebContext(webApplication.buildExchange(new MockHttpServletRequest(servletContext),\n\t\t\t\t\tnew MockHttpServletResponse()));\n\t\t\ttry {\n\t\t\t\tSecurityContextHolder\n\t\t\t\t\t.setContext(new SecurityContextImpl(new TestingAuthenticationToken(\"alice\", \"admin\")));\n\t\t\t\tString result = engine.process(\"security-dialect\", attrs);\n\t\t\t\tassertThat(result).isEqualTo(\"<html><body><div>alice</div></body></html>\");\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tSecurityContextHolder.clearContext();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid securityDialectAutoConfigurationBacksOffWithoutSpringSecurity() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"org.springframework.security\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(SpringSecurityDialect.class));\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/home.html\", content = \"<html><body th:text=\\\"${foo}\\\">Home</body></html>\")\n\tvoid renderTemplate() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"foo\", \"bar\"));\n\t\t\tString result = engine.process(\"home\", attrs).trim();\n\t\t\tassertThat(result).isEqualTo(\"<html><body>bar</body></html>\");\n\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/message.html\",\n\t\t\tcontent = \"<html><body>Message: <span th:text=\\\"${greeting}\\\">Hello</span></body></html>\")\n\tvoid renderNonWebAppTemplate() {\n\t\tnew ApplicationContextRunner().withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(ViewResolver.class);\n\t\t\t\tTemplateEngine engine = context.getBean(TemplateEngine.class);\n\t\t\t\tContext attrs = new Context(Locale.UK, Collections.singletonMap(\"greeting\", \"Hello World\"));\n\t\t\t\tString result = engine.process(\"message\", attrs);\n\t\t\t\tassertThat(result).contains(\"Hello World\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registerResourceHandlingFilterDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.chain.enabled:true\").run((context) -> {\n\t\t\tFilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);\n\t\t\tassertThat(registration.getFilter()).isInstanceOf(ResourceUrlEncodingFilter.class);\n\t\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\t\tEnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid registerResourceHandlingFilterWithOtherRegistrationBean() {\n\t\t// gh-14897\n\t\tthis.contextRunner.withUserConfiguration(FilterRegistrationOtherConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.web.resources.chain.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, FilterRegistrationBean> beans = context.getBeansOfType(FilterRegistrationBean.class);\n\t\t\t\tassertThat(beans).hasSize(2);\n\t\t\t\tFilterRegistrationBean registration = beans.values()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.get();\n\t\t\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\t\t\tEnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid registerResourceHandlingFilterWithResourceRegistrationBean() {\n\t\t// gh-14926\n\t\tthis.contextRunner.withUserConfiguration(FilterRegistrationResourceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.web.resources.chain.enabled:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<String, FilterRegistrationBean> beans = context.getBeansOfType(FilterRegistrationBean.class);\n\t\t\t\tassertThat(beans).hasSize(1);\n\t\t\t\tFilterRegistrationBean registration = beans.values()\n\t\t\t\t\t.stream()\n\t\t\t\t\t.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter)\n\t\t\t\t\t.findFirst()\n\t\t\t\t\t.get();\n\t\t\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\t\t\tEnumSet.of(DispatcherType.INCLUDE));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid layoutDialectCanBeCustomized() {\n\t\tthis.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tReflectionTestUtils.getField(context.getBean(LayoutDialect.class), \"sortingStrategy\"))\n\t\t\t\t.isInstanceOf(GroupingStrategy.class));\n\t}\n\n\t@Test\n\tvoid cachingCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.thymeleaf.cache:false\").run((context) -> {\n\t\t\tassertThat(context.getBean(ThymeleafViewResolver.class).isCache()).isFalse();\n\t\t\tSpringResourceTemplateResolver templateResolver = context.getBean(SpringResourceTemplateResolver.class);\n\t\t\tassertThat(templateResolver.isCacheable()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid missingAbstractCachingViewResolver() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(AbstractCachingViewResolver.class))\n\t\t\t.run((context) -> assertThat(context).hasNotFailed().doesNotHaveBean(\"thymeleafViewResolver\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LayoutDialectConfiguration {\n\n\t\t@Bean\n\t\tLayoutDialect layoutDialect() {\n\t\t\treturn new LayoutDialect().withSortingStrategy(new GroupingStrategy());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterRegistrationResourceConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> filterRegistration() {\n\t\t\tFilterRegistrationBean<ResourceUrlEncodingFilter> bean = new FilterRegistrationBean<>(\n\t\t\t\t\tnew ResourceUrlEncodingFilter());\n\t\t\tbean.setDispatcherTypes(EnumSet.of(DispatcherType.INCLUDE));\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterRegistrationOtherConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<OrderedCharacterEncodingFilter> filterRegistration() {\n\t\t\treturn new FilterRegistrationBean<>(new OrderedCharacterEncodingFilter());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafTemplateAvailabilityProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ThymeleafTemplateAvailabilityProvider}.\n *\n * @author Andy Wilkinson\n */\nclass ThymeleafTemplateAvailabilityProviderTests {\n\n\tprivate final TemplateAvailabilityProvider provider = new ThymeleafTemplateAvailabilityProvider();\n\n\tprivate final ResourceLoader resourceLoader = new DefaultResourceLoader();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\t@WithResource(name = \"templates/home.html\")\n\tvoid availabilityOfTemplateInDefaultLocation() {\n\t\tassertThat(this.provider.isTemplateAvailable(\"home\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tvoid availabilityOfTemplateThatDoesNotExist() {\n\t\tassertThat(this.provider.isTemplateAvailable(\"whatever\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.html\")\n\tvoid availabilityOfTemplateWithCustomPrefix() {\n\t\tthis.environment.setProperty(\"spring.thymeleaf.prefix\", \"classpath:/custom-templates/\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"custom\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"templates/suffixed.thymeleaf\")\n\tvoid availabilityOfTemplateWithCustomSuffix() {\n\t\tthis.environment.setProperty(\"spring.thymeleaf.suffix\", \".thymeleaf\");\n\t\tassertThat(this.provider.isTemplateAvailable(\"suffixed\", this.environment, getClass().getClassLoader(),\n\t\t\t\tthis.resourceLoader))\n\t\t\t.isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/ThymeleafWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Thymeleaf with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass ThymeleafWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid thymeleafAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ThymeleafAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webfluxtest/ExampleDialect.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure.webfluxtest;\n\nimport org.thymeleaf.dialect.IDialect;\n\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link IDialect} used to test their inclusion in {@link WebFluxTest @WebFluxTest}s.\n *\n * @author Andy Wilkinson\n */\n@Component\nclass ExampleDialect implements IDialect {\n\n\t@Override\n\tpublic String getName() {\n\t\treturn \"example\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webfluxtest/ThymeleafWebFluxTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure.webfluxtest;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\n\n/**\n * Application for testing Thymeleaf integration with {@link WebFluxTest @WebFluxTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class ThymeleafWebFluxTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webfluxtest/ThymeleafWebFluxTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure.webfluxtest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.thymeleaf.autoconfigure.ThymeleafAutoConfiguration;\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Thymeleaf with {@link WebFluxTest @WebFluxTest}.\n *\n * @author Andy Wilkinson\n */\n@WebFluxTest\nclass ThymeleafWebFluxTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid thymeleafAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ThymeleafAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid idialectIsIncluded() {\n\t\tassertThatNoException().isThrownBy(() -> this.applicationContext.getBean(ExampleDialect.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webfluxtest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.thymeleaf.autoconfigure.webfluxtest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webmvctest/ExampleDialect.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure.webmvctest;\n\nimport org.thymeleaf.dialect.IDialect;\n\nimport org.springframework.boot.webflux.test.autoconfigure.WebFluxTest;\nimport org.springframework.stereotype.Component;\n\n/**\n * {@link IDialect} used to test their inclusion in {@link WebFluxTest @WebFluxTest}s.\n *\n * @author Andy Wilkinson\n */\n@Component\nclass ExampleDialect implements IDialect {\n\n\t@Override\n\tpublic String getName() {\n\t\treturn \"example\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webmvctest/ThymeleafWebMvcTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure.webmvctest;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\n\n/**\n * Application for testing Thymeleaf integration with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class ThymeleafWebMvcTestApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webmvctest/ThymeleafWebMvcTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.thymeleaf.autoconfigure.webmvctest;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.thymeleaf.autoconfigure.ThymeleafAutoConfiguration;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for Thymeleaf with {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass ThymeleafWebMvcTestIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid thymeleafAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ThymeleafAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid idialectIsIncluded() {\n\t\tassertThatNoException().isThrownBy(() -> this.applicationContext.getBean(ExampleDialect.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-thymeleaf/src/test/java/org/springframework/boot/thymeleaf/autoconfigure/webmvctest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.thymeleaf.autoconfigure.webmvctest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Tomcat\"\n\ndef tomcatConfigProperties = layout.buildDirectory.dir(\"tomcat-config-properties\")\n\nconfigurations {\n\ttomcatDistribution\n}\n\ndependencies {\n\tapi(project(\":module:spring-boot-web-server\"))\n\tapi(\"org.apache.tomcat.embed:tomcat-embed-core\") {\n\t\texclude group: \"org.apache.tomcat\", module: \"tomcat-annotations-api\"\n\t}\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-web-server-test\"))\n\toptional(\"io.micrometer:micrometer-core\")\n\toptional(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\toptional(\"org.apache.tomcat.embed:tomcat-embed-websocket\") {\n\t\texclude group: \"org.apache.tomcat\", module: \"tomcat-annotations-api\"\n\t}\n\toptional(\"org.springframework:spring-webflux\")\n\n\truntimeOnly(\"jakarta.annotation:jakarta.annotation-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.projectreactor:reactor-test\")\n\ttestRuntimeOnly(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestRuntimeOnly(\"org.eclipse.jetty:jetty-client\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.http2:jetty-http2-client\")\n\ttestRuntimeOnly(\"org.eclipse.jetty.http2:jetty-http2-client-transport\")\n\ttestRuntimeOnly(\"org.springframework:spring-webmvc\")\n\n\ttomcatDistribution(\"org.apache.tomcat:tomcat:${tomcatVersion}@zip\")\n}\n\ntasks.register(\"extractTomcatConfigProperties\", Sync) {\n\tdestinationDir = file(tomcatConfigProperties)\n\tfrom {\n\t\tzipTree(configurations.tomcatDistribution.incoming.files.singleFile).matching {\n\t\t\tinclude '**/conf/catalina.properties'\n\t\t}.singleFile\n\t}\n}\n\nsourceSets {\n\ttest {\n\t\toutput.dir(tomcatConfigProperties, builtBy: \"extractTomcatConfigProperties\")\n\t}\n}\n\ntest {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/CompressionConnectorCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.connector.Connector;\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link TomcatConnectorCustomizer} that configures compression support on the given\n * Connector.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class CompressionConnectorCustomizer implements TomcatConnectorCustomizer {\n\n\tprivate final @Nullable Compression compression;\n\n\tpublic CompressionConnectorCustomizer(@Nullable Compression compression) {\n\t\tthis.compression = compression;\n\t}\n\n\t@Override\n\tpublic void customize(Connector connector) {\n\t\tif (this.compression != null && this.compression.getEnabled()) {\n\t\t\tProtocolHandler handler = connector.getProtocolHandler();\n\t\t\tif (handler instanceof AbstractHttp11Protocol<?> abstractHttp11Protocol) {\n\t\t\t\tcustomize(abstractHttp11Protocol, this.compression);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void customize(AbstractHttp11Protocol<?> protocol, Compression compression) {\n\t\tprotocol.setCompression(\"on\");\n\t\tprotocol.setCompressionMinSize(getMinResponseSize(compression));\n\t\tprotocol.setCompressibleMimeType(getMimeTypes(compression));\n\t\tif (compression.getExcludedUserAgents() != null) {\n\t\t\tprotocol.setNoCompressionUserAgents(getExcludedUserAgents(compression));\n\t\t}\n\t}\n\n\tprivate int getMinResponseSize(Compression compression) {\n\t\treturn (int) compression.getMinResponseSize().toBytes();\n\t}\n\n\tprivate String getMimeTypes(Compression compression) {\n\t\treturn StringUtils.arrayToCommaDelimitedString(compression.getAllMimeTypes());\n\t}\n\n\tprivate String getExcludedUserAgents(Compression compression) {\n\t\treturn StringUtils.arrayToCommaDelimitedString(compression.getExcludedUserAgents());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/ConfigurableTomcatWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.io.File;\nimport java.nio.charset.Charset;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Engine;\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.connector.Connector;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\n\n/**\n * {@link ConfigurableWebServerFactory} for Tomcat-specific features.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see TomcatServletWebServerFactory\n * @see TomcatReactiveWebServerFactory\n */\npublic interface ConfigurableTomcatWebServerFactory extends ConfigurableWebServerFactory {\n\n\t/**\n\t * Set the Tomcat base directory. If not specified a temporary directory will be used.\n\t * @param baseDirectory the tomcat base directory\n\t */\n\tvoid setBaseDirectory(@Nullable File baseDirectory);\n\n\t/**\n\t * Sets the background processor delay in seconds.\n\t * @param delay the delay in seconds\n\t */\n\tvoid setBackgroundProcessorDelay(int delay);\n\n\t/**\n\t * Add {@link Valve}s that should be applied to the Tomcat {@link Engine}.\n\t * @param engineValves the valves to add\n\t */\n\tvoid addEngineValves(Valve... engineValves);\n\n\t/**\n\t * Add {@link TomcatConnectorCustomizer}s that should be added to the Tomcat\n\t * {@link Connector}.\n\t * @param tomcatConnectorCustomizers the customizers to add\n\t */\n\tvoid addConnectorCustomizers(TomcatConnectorCustomizer... tomcatConnectorCustomizers);\n\n\t/**\n\t * Add {@link TomcatContextCustomizer}s that should be added to the Tomcat\n\t * {@link Context}.\n\t * @param tomcatContextCustomizers the customizers to add\n\t */\n\tvoid addContextCustomizers(TomcatContextCustomizer... tomcatContextCustomizers);\n\n\t/**\n\t * Add {@link TomcatProtocolHandlerCustomizer}s that should be added to the Tomcat\n\t * {@link Connector}.\n\t * @param tomcatProtocolHandlerCustomizers the customizers to add\n\t */\n\tvoid addProtocolHandlerCustomizers(TomcatProtocolHandlerCustomizer<?>... tomcatProtocolHandlerCustomizers);\n\n\t/**\n\t * Set the character encoding to use for URL decoding. If not specified 'UTF-8' will\n\t * be used.\n\t * @param uriEncoding the uri encoding to set\n\t */\n\tvoid setUriEncoding(Charset uriEncoding);\n\n\t/**\n\t * Whether to use APR.\n\t * @param useApr whether to use APR\n\t */\n\tvoid setUseApr(boolean useApr);\n\n\t/**\n\t * Set whether the factory should disable Tomcat's MBean registry prior to creating\n\t * the server.\n\t * @param disableMBeanRegistry whether to disable the MBean registry\n\t */\n\tvoid setDisableMBeanRegistry(boolean disableMBeanRegistry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/ConnectorStartFailedException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.connector.Connector;\n\nimport org.springframework.boot.web.server.WebServerException;\n\n/**\n * A {@code ConnectorStartFailedException} is thrown when a Tomcat {@link Connector} fails\n * to start, for example due to a port clash or incorrect SSL configuration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class ConnectorStartFailedException extends WebServerException {\n\n\tprivate final int port;\n\n\t/**\n\t * Creates a new {@code ConnectorStartFailedException} for a connector that's\n\t * configured to listen on the given {@code port}.\n\t * @param port the port\n\t */\n\tpublic ConnectorStartFailedException(int port) {\n\t\tsuper(\"Connector configured to listen on port \" + port + \" failed to start\", null);\n\t\tthis.port = port;\n\t}\n\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/ConnectorStartFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * An {@link AbstractFailureAnalyzer} for {@link ConnectorStartFailedException}.\n *\n * @author Andy Wilkinson\n */\nclass ConnectorStartFailureAnalyzer extends AbstractFailureAnalyzer<ConnectorStartFailedException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, ConnectorStartFailedException cause) {\n\t\treturn new FailureAnalysis(\n\t\t\t\t\"The Tomcat connector configured to listen on port \" + cause.getPort()\n\t\t\t\t\t\t+ \" failed to start. The port may already be in use or the connector may be misconfigured.\",\n\t\t\t\t\"Verify the connector's configuration, identify and stop any process that's listening on port \"\n\t\t\t\t\t\t+ cause.getPort() + \", or configure this application to listen on another port.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/DisableReferenceClearingContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.core.StandardContext;\n\n/**\n * A {@link TomcatContextCustomizer} that disables Tomcat's reflective reference clearing\n * to avoid reflective access warnings on Java 9 and later JVMs.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class DisableReferenceClearingContextCustomizer implements TomcatContextCustomizer {\n\n\t@Override\n\tpublic void customize(Context context) {\n\t\tif (!(context instanceof StandardContext standardContext)) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tstandardContext.setClearReferencesRmiTargets(false);\n\t\t\tstandardContext.setClearReferencesThreadLocals(false);\n\t\t}\n\t\tcatch (NoSuchMethodError ex) {\n\t\t\t// Earlier version of Tomcat (probably without\n\t\t\t// setClearReferencesThreadLocals). Continue.\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/GracefulShutdown.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Service;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.core.StandardWrapper;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\n\n/**\n * Handles Tomcat graceful shutdown.\n *\n * @author Andy Wilkinson\n */\nfinal class GracefulShutdown {\n\n\tprivate static final Log logger = LogFactory.getLog(GracefulShutdown.class);\n\n\tprivate final Tomcat tomcat;\n\n\tprivate volatile boolean aborted;\n\n\tGracefulShutdown(Tomcat tomcat) {\n\t\tthis.tomcat = tomcat;\n\t}\n\n\tvoid shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tlogger.info(\"Commencing graceful shutdown. Waiting for active requests to complete\");\n\t\tCountDownLatch shutdownUnderway = new CountDownLatch(1);\n\t\tnew Thread(() -> doShutdown(callback, shutdownUnderway), \"tomcat-shutdown\").start();\n\t\ttry {\n\t\t\tshutdownUnderway.await();\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n\tprivate void doShutdown(GracefulShutdownCallback callback, CountDownLatch shutdownUnderway) {\n\t\ttry {\n\t\t\tList<Connector> connectors = getConnectors();\n\t\t\tconnectors.forEach(this::close);\n\t\t\tshutdownUnderway.countDown();\n\t\t\tawaitInactiveOrAborted();\n\t\t\tif (this.aborted) {\n\t\t\t\tlogger.info(\"Graceful shutdown aborted with one or more requests still active\");\n\t\t\t\tcallback.shutdownComplete(GracefulShutdownResult.REQUESTS_ACTIVE);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Graceful shutdown complete\");\n\t\t\t\tcallback.shutdownComplete(GracefulShutdownResult.IDLE);\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tshutdownUnderway.countDown();\n\t\t}\n\t}\n\n\tprivate List<Connector> getConnectors() {\n\t\tList<Connector> connectors = new ArrayList<>();\n\t\tfor (Service service : this.tomcat.getServer().findServices()) {\n\t\t\tCollections.addAll(connectors, service.findConnectors());\n\t\t}\n\t\treturn connectors;\n\t}\n\n\tprivate void close(Connector connector) {\n\t\tconnector.pause();\n\t\tconnector.getProtocolHandler().closeServerSocketGraceful();\n\t}\n\n\tprivate void awaitInactiveOrAborted() {\n\t\ttry {\n\t\t\tfor (Container host : this.tomcat.getEngine().findChildren()) {\n\t\t\t\tfor (Container context : host.findChildren()) {\n\t\t\t\t\twhile (!this.aborted && isActive(context)) {\n\t\t\t\t\t\tThread.sleep(50);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n\tprivate boolean isActive(Container context) {\n\t\ttry {\n\t\t\tif (((StandardContext) context).getInProgressAsyncCount() > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor (Container wrapper : context.findChildren()) {\n\t\t\t\tif (((StandardWrapper) wrapper).getCountAllocated() > 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tvoid abort() {\n\t\tthis.aborted = true;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/LazySessionIdGenerator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.LifecycleException;\nimport org.apache.catalina.LifecycleState;\nimport org.apache.catalina.util.StandardSessionIdGenerator;\n\n/**\n * A specialization of {@link StandardSessionIdGenerator} that initializes\n * {@code SecureRandom} lazily.\n *\n * @author Andy Wilkinson\n */\nclass LazySessionIdGenerator extends StandardSessionIdGenerator {\n\n\t@Override\n\tprotected void startInternal() throws LifecycleException {\n\t\tsetState(LifecycleState.STARTING);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/SslConnectorCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.catalina.connector.Connector;\nimport org.apache.commons.logging.Log;\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.apache.tomcat.util.net.SSLHostConfig;\nimport org.apache.tomcat.util.net.SSLHostConfigCertificate;\nimport org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;\nimport org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.web.server.Ssl.ClientAuth;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Utility that configures SSL support on the given connector.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Cyril Dangerville\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class SslConnectorCustomizer {\n\n\tprivate final Log logger;\n\n\tprivate final @Nullable ClientAuth clientAuth;\n\n\tprivate final Connector connector;\n\n\tpublic SslConnectorCustomizer(Log logger, Connector connector, @Nullable ClientAuth clientAuth) {\n\t\tthis.logger = logger;\n\t\tthis.clientAuth = clientAuth;\n\t\tthis.connector = connector;\n\t}\n\n\tpublic void update(@Nullable String serverName, SslBundle updatedSslBundle) {\n\t\tAbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) this.connector.getProtocolHandler();\n\t\tString host = (serverName != null) ? serverName : protocol.getDefaultSSLHostConfigName();\n\t\tthis.logger.debug(\"SSL Bundle for host \" + host + \" has been updated, reloading SSL configuration\");\n\t\taddSslHostConfig(protocol, host, updatedSslBundle);\n\t}\n\n\tpublic void customize(SslBundle sslBundle, Map<String, SslBundle> serverNameSslBundles) {\n\t\tProtocolHandler handler = this.connector.getProtocolHandler();\n\t\tAssert.state(handler instanceof AbstractHttp11Protocol,\n\t\t\t\t\"To use SSL, the connector's protocol handler must be an AbstractHttp11Protocol subclass\");\n\t\tconfigureSsl((AbstractHttp11Protocol<?>) handler, sslBundle, serverNameSslBundles);\n\t\tthis.connector.setScheme(\"https\");\n\t\tthis.connector.setSecure(true);\n\t}\n\n\t/**\n\t * Configure Tomcat's {@link AbstractHttp11Protocol} for SSL.\n\t * @param protocol the protocol\n\t * @param sslBundle the SSL bundle\n\t * @param serverNameSslBundles the SSL bundles for specific SNI host names\n\t */\n\tprivate void configureSsl(AbstractHttp11Protocol<?> protocol, @Nullable SslBundle sslBundle,\n\t\t\tMap<String, SslBundle> serverNameSslBundles) {\n\t\tprotocol.setSSLEnabled(true);\n\t\tif (sslBundle != null) {\n\t\t\taddSslHostConfig(protocol, protocol.getDefaultSSLHostConfigName(), sslBundle);\n\t\t}\n\t\tserverNameSslBundles.forEach((serverName, bundle) -> addSslHostConfig(protocol, serverName, bundle));\n\t}\n\n\tprivate void addSslHostConfig(AbstractHttp11Protocol<?> protocol, String serverName, SslBundle sslBundle) {\n\t\tSSLHostConfig sslHostConfig = new SSLHostConfig();\n\t\tsslHostConfig.setHostName(serverName);\n\t\tconfigureSslClientAuth(sslHostConfig);\n\t\tapplySslBundle(protocol, sslHostConfig, sslBundle);\n\t\tprotocol.addSslHostConfig(sslHostConfig, true);\n\t}\n\n\tprivate void applySslBundle(AbstractHttp11Protocol<?> protocol, SSLHostConfig sslHostConfig, SslBundle sslBundle) {\n\t\tSslBundleKey key = sslBundle.getKey();\n\t\tSslStoreBundle stores = sslBundle.getStores();\n\t\tSslOptions options = sslBundle.getOptions();\n\t\tsslHostConfig.setSslProtocol(sslBundle.getProtocol());\n\t\tSSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);\n\t\tString keystorePassword = (stores.getKeyStorePassword() != null) ? stores.getKeyStorePassword() : \"\";\n\t\tcertificate.setCertificateKeystorePassword(keystorePassword);\n\t\tif (key.getPassword() != null) {\n\t\t\tcertificate.setCertificateKeyPassword(key.getPassword());\n\t\t}\n\t\tif (key.getAlias() != null) {\n\t\t\tcertificate.setCertificateKeyAlias(key.getAlias());\n\t\t}\n\t\tsslHostConfig.addCertificate(certificate);\n\t\tconfigureCiphers(options, sslHostConfig);\n\t\tconfigureSslStores(sslHostConfig, certificate, stores);\n\t\tconfigureEnabledProtocols(sslHostConfig, options);\n\t}\n\n\tprivate void configureCiphers(SslOptions options, SSLHostConfig sslHostConfig) {\n\t\tCipherConfiguration cipherConfiguration = CipherConfiguration.from(options);\n\t\tif (cipherConfiguration != null) {\n\t\t\tsslHostConfig.setCiphers(cipherConfiguration.tls12Ciphers);\n\t\t\ttry {\n\t\t\t\tsslHostConfig.setCipherSuites(cipherConfiguration.tls13Ciphers);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Tomcat version without setCipherSuites method. Continue.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void configureEnabledProtocols(SSLHostConfig sslHostConfig, SslOptions options) {\n\t\tif (options.getEnabledProtocols() != null) {\n\t\t\tString enabledProtocols = StringUtils.arrayToDelimitedString(options.getEnabledProtocols(), \"+\");\n\t\t\tsslHostConfig.setProtocols(enabledProtocols);\n\t\t}\n\t}\n\n\tprivate void configureSslClientAuth(SSLHostConfig config) {\n\t\tconfig.setCertificateVerification(ClientAuth.map(this.clientAuth, \"none\", \"optional\", \"required\"));\n\t}\n\n\tprivate void configureSslStores(SSLHostConfig sslHostConfig, SSLHostConfigCertificate certificate,\n\t\t\tSslStoreBundle stores) {\n\t\ttry {\n\t\t\tif (stores.getKeyStore() != null) {\n\t\t\t\tcertificate.setCertificateKeystore(stores.getKeyStore());\n\t\t\t}\n\t\t\tif (stores.getTrustStore() != null) {\n\t\t\t\tsslHostConfig.setTrustStore(stores.getTrustStore());\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Could not load store: \" + ex.getMessage(), ex);\n\t\t}\n\t}\n\n\tprivate static class CipherConfiguration {\n\n\t\tprivate final String tls12Ciphers;\n\n\t\tprivate final String tls13Ciphers;\n\n\t\tCipherConfiguration(String tls12Ciphers, String tls13Ciphers) {\n\t\t\tthis.tls12Ciphers = tls12Ciphers;\n\t\t\tthis.tls13Ciphers = tls13Ciphers;\n\t\t}\n\n\t\tstatic @Nullable CipherConfiguration from(SslOptions options) {\n\t\t\tList<String> tls12Ciphers = new ArrayList<>();\n\t\t\tList<String> tls13Ciphers = new ArrayList<>();\n\t\t\tString[] ciphers = options.getCiphers();\n\t\t\tif (ciphers == null || ciphers.length == 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tfor (String cipher : ciphers) {\n\t\t\t\tif (isTls13(cipher)) {\n\t\t\t\t\ttls13Ciphers.add(cipher);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttls12Ciphers.add(cipher);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn new CipherConfiguration(StringUtils.collectionToCommaDelimitedString(tls12Ciphers),\n\t\t\t\t\tStringUtils.collectionToCommaDelimitedString(tls13Ciphers));\n\t\t}\n\n\t\tprivate static boolean isTls13(String cipher) {\n\t\t\ttry {\n\t\t\t\treturn OpenSSLCipherConfigurationParser.isTls13Cipher(cipher);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Tomcat version without isTls13Cipher method. Continue, treating all\n\t\t\t\t// ciphers as TLSv1.2\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatConnectorCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.connector.Connector;\n\n/**\n * Callback interface that can be used to customize a Tomcat {@link Connector}.\n *\n * @author Dave Syer\n * @since 4.0.0\n * @see ConfigurableTomcatWebServerFactory\n */\n@FunctionalInterface\npublic interface TomcatConnectorCustomizer {\n\n\t/**\n\t * Customize the connector.\n\t * @param connector the connector to customize\n\t */\n\tvoid customize(Connector connector);\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.Context;\n\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\n\n/**\n * Callback interface that can be used to customize a Tomcat {@link Context}.\n *\n * @author Dave Syer\n * @since 4.0.0\n * @see TomcatServletWebServerFactory\n */\n@FunctionalInterface\npublic interface TomcatContextCustomizer {\n\n\t/**\n\t * Customize the context.\n\t * @param context the context to customize\n\t */\n\tvoid customize(Context context);\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatEmbeddedContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.ServletException;\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Manager;\nimport org.apache.catalina.Wrapper;\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.core.StandardWrapper;\nimport org.apache.catalina.session.ManagerBase;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Tomcat {@link StandardContext} used by {@link TomcatWebServer} to support deferred\n * initialization.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class TomcatEmbeddedContext extends StandardContext {\n\n\tprivate DeferredStartupExceptions deferredStartupExceptions = DeferredStartupExceptions.NONE;\n\n\tprivate @Nullable MimeMappings mimeMappings;\n\n\t@Override\n\tpublic boolean loadOnStartup(Container[] children) {\n\t\t// deferred until later (see deferredLoadOnStartup)\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void setManager(Manager manager) {\n\t\tif (manager instanceof ManagerBase) {\n\t\t\tmanager.setSessionIdGenerator(new LazySessionIdGenerator());\n\t\t}\n\t\tsuper.setManager(manager);\n\t}\n\n\tvoid deferredLoadOnStartup() {\n\t\tdoWithThreadContextClassLoader(getLoader().getClassLoader(),\n\t\t\t\t() -> getLoadOnStartupWrappers(findChildren()).forEach(this::load));\n\t}\n\n\tprivate Stream<Wrapper> getLoadOnStartupWrappers(Container[] children) {\n\t\tMap<Integer, List<Wrapper>> grouped = new TreeMap<>();\n\t\tfor (Container child : children) {\n\t\t\tWrapper wrapper = (Wrapper) child;\n\t\t\tint order = wrapper.getLoadOnStartup();\n\t\t\tif (order >= 0) {\n\t\t\t\tgrouped.computeIfAbsent(order, (o) -> new ArrayList<>()).add(wrapper);\n\t\t\t}\n\t\t}\n\t\treturn grouped.values().stream().flatMap(List::stream);\n\t}\n\n\tprivate void load(Wrapper wrapper) {\n\t\ttry {\n\t\t\twrapper.load();\n\t\t}\n\t\tcatch (ServletException ex) {\n\t\t\tString message = sm.getString(\"standardContext.loadOnStartup.loadException\", getName(), wrapper.getName());\n\t\t\tif (getComputedFailCtxIfServletStartFails()) {\n\t\t\t\tthrow new WebServerException(message, ex);\n\t\t\t}\n\t\t\tgetLogger().error(message, StandardWrapper.getRootCause(ex));\n\t\t}\n\t}\n\n\t/**\n\t * Some older Servlet frameworks (e.g. Struts, BIRT) use the Thread context class\n\t * loader to create servlet instances in this phase. If they do that and then try to\n\t * initialize them later the class loader may have changed, so wrap the call to\n\t * loadOnStartup in what we think is going to be the main webapp classloader at\n\t * runtime.\n\t * @param classLoader the class loader to use\n\t * @param code the code to run\n\t */\n\tprivate void doWithThreadContextClassLoader(@Nullable ClassLoader classLoader, Runnable code) {\n\t\tClassLoader existingLoader = (classLoader != null) ? ClassUtils.overrideThreadContextClassLoader(classLoader)\n\t\t\t\t: null;\n\t\ttry {\n\t\t\tcode.run();\n\t\t}\n\t\tfinally {\n\t\t\tif (existingLoader != null) {\n\t\t\t\tClassUtils.overrideThreadContextClassLoader(existingLoader);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Set a strategy used to capture and rethrow deferred startup exceptions.\n\t * @param deferredStartupExceptions the strategy to use\n\t */\n\tpublic void setDeferredStartupExceptions(DeferredStartupExceptions deferredStartupExceptions) {\n\t\tAssert.notNull(deferredStartupExceptions, \"'deferredStartupExceptions' must not be null\");\n\t\tthis.deferredStartupExceptions = deferredStartupExceptions;\n\t}\n\n\tDeferredStartupExceptions getDeferredStartupExceptions() {\n\t\treturn this.deferredStartupExceptions;\n\t}\n\n\tpublic void setMimeMappings(MimeMappings mimeMappings) {\n\t\tthis.mimeMappings = mimeMappings;\n\t}\n\n\t@Override\n\tpublic String[] findMimeMappings() {\n\t\tList<String> mappings = new ArrayList<>(Arrays.asList(super.findMimeMappings()));\n\t\tif (this.mimeMappings != null) {\n\t\t\tthis.mimeMappings.forEach((mapping) -> mappings.add(mapping.getExtension()));\n\t\t}\n\t\treturn mappings.toArray(String[]::new);\n\t}\n\n\t@Override\n\tpublic @Nullable String findMimeMapping(String extension) {\n\t\tString mimeMapping = super.findMimeMapping(extension);\n\t\tif (mimeMapping != null) {\n\t\t\treturn mimeMapping;\n\t\t}\n\t\treturn (this.mimeMappings != null) ? this.mimeMappings.get(extension) : null;\n\t}\n\n\t/**\n\t * Strategy interface that can be used to rethrow deferred startup exceptions.\n\t */\n\t@FunctionalInterface\n\tpublic interface DeferredStartupExceptions {\n\n\t\t/**\n\t\t * {@link DeferredStartupExceptions} that does nothing.\n\t\t */\n\t\tDeferredStartupExceptions NONE = () -> {\n\t\t};\n\n\t\t/**\n\t\t * Rethrow deferred startup exceptions if there are any.\n\t\t * @throws Exception the deferred startup exception\n\t\t */\n\t\tvoid rethrow() throws Exception;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatEmbeddedWebappClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.Collections;\nimport java.util.Enumeration;\n\nimport org.apache.catalina.loader.ParallelWebappClassLoader;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.tomcat.util.compat.JreCompat;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Extension of Tomcat's {@link ParallelWebappClassLoader} that does not consider the\n * {@link ClassLoader#getSystemClassLoader() system classloader}. This is required to\n * ensure that any custom context class loader is always used (as is the case with some\n * executable archives).\n *\n * @author Phillip Webb\n * @author Andy Clement\n * @since 4.0.0\n */\npublic class TomcatEmbeddedWebappClassLoader extends ParallelWebappClassLoader {\n\n\tprivate static final Log logger = LogFactory.getLog(TomcatEmbeddedWebappClassLoader.class);\n\n\tstatic {\n\t\tif (!JreCompat.isGraalAvailable()) {\n\t\t\tClassLoader.registerAsParallelCapable();\n\t\t}\n\t}\n\n\tpublic TomcatEmbeddedWebappClassLoader() {\n\t}\n\n\tpublic TomcatEmbeddedWebappClassLoader(@Nullable ClassLoader parent) {\n\t\tsuper(parent);\n\t}\n\n\t@Override\n\tpublic @Nullable URL findResource(String name) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic Enumeration<URL> findResources(String name) throws IOException {\n\t\treturn Collections.emptyEnumeration();\n\t}\n\n\t@Override\n\tpublic Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {\n\t\tsynchronized (JreCompat.isGraalAvailable() ? this : getClassLoadingLock(name)) {\n\t\t\tClass<?> result = findExistingLoadedClass(name);\n\t\t\tresult = (result != null) ? result : doLoadClass(name);\n\t\t\tif (result == null) {\n\t\t\t\tthrow new ClassNotFoundException(name);\n\t\t\t}\n\t\t\treturn resolveIfNecessary(result, resolve);\n\t\t}\n\t}\n\n\tprivate @Nullable Class<?> findExistingLoadedClass(String name) {\n\t\tClass<?> resultClass = findLoadedClass0(name);\n\t\tresultClass = (resultClass != null || JreCompat.isGraalAvailable()) ? resultClass : findLoadedClass(name);\n\t\treturn resultClass;\n\t}\n\n\tprivate @Nullable Class<?> doLoadClass(String name) {\n\t\tif ((this.delegate || filter(name, true))) {\n\t\t\tClass<?> result = loadFromParent(name);\n\t\t\treturn (result != null) ? result : findClassIgnoringNotFound(name);\n\t\t}\n\t\tClass<?> result = findClassIgnoringNotFound(name);\n\t\treturn (result != null) ? result : loadFromParent(name);\n\t}\n\n\tprivate Class<?> resolveIfNecessary(Class<?> resultClass, boolean resolve) {\n\t\tif (resolve) {\n\t\t\tresolveClass(resultClass);\n\t\t}\n\t\treturn (resultClass);\n\t}\n\n\t@Override\n\tprotected void addURL(URL url) {\n\t\t// Ignore URLs added by the Tomcat 8 implementation (see gh-919)\n\t\tif (logger.isTraceEnabled()) {\n\t\t\tlogger.trace(\"Ignoring request to add \" + url + \" to the tomcat classloader\");\n\t\t}\n\t}\n\n\tprivate @Nullable Class<?> loadFromParent(String name) {\n\t\tif (this.parent == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\treturn Class.forName(name, false, this.parent);\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate @Nullable Class<?> findClassIgnoringNotFound(String name) {\n\t\ttry {\n\t\t\treturn findClass(name);\n\t\t}\n\t\tcatch (ClassNotFoundException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatProtocolHandlerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.connector.Connector;\nimport org.apache.coyote.ProtocolHandler;\n\n/**\n * Callback interface that can be used to customize the {@link ProtocolHandler} on the\n * {@link Connector}.\n *\n * @param <T> specified type for customization based on {@link ProtocolHandler}\n * @author Pascal Zwick\n * @since 4.0.0\n * @see ConfigurableTomcatWebServerFactory\n */\n@FunctionalInterface\npublic interface TomcatProtocolHandlerCustomizer<T extends ProtocolHandler> {\n\n\t/**\n\t * Customize the protocol handler.\n\t * @param protocolHandler the protocol handler to customize\n\t */\n\tvoid customize(T protocolHandler);\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.BiConsumer;\nimport java.util.stream.Collectors;\n\nimport javax.naming.NamingException;\n\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Engine;\nimport org.apache.catalina.Lifecycle;\nimport org.apache.catalina.LifecycleException;\nimport org.apache.catalina.LifecycleState;\nimport org.apache.catalina.Service;\nimport org.apache.catalina.Wrapper;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.naming.ContextBindings;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link WebServer} that can be used to control a Tomcat web server. Usually this class\n * should be created using the {@link TomcatReactiveWebServerFactory} or\n * {@link TomcatServletWebServerFactory}, but not directly.\n *\n * @author Brian Clozel\n * @author Kristine Jetzke\n * @since 4.0.0\n */\npublic class TomcatWebServer implements WebServer {\n\n\tprivate static final Log logger = LogFactory.getLog(TomcatWebServer.class);\n\n\tprivate static final AtomicInteger containerCounter = new AtomicInteger(-1);\n\n\tprivate final Object monitor = new Object();\n\n\tprivate final Map<Service, Connector[]> serviceConnectors = new HashMap<>();\n\n\tprivate final Tomcat tomcat;\n\n\tprivate final boolean autoStart;\n\n\tprivate final @Nullable GracefulShutdown gracefulShutdown;\n\n\tprivate volatile boolean started;\n\n\t/**\n\t * Create a new {@link TomcatWebServer} instance.\n\t * @param tomcat the underlying Tomcat server\n\t */\n\tpublic TomcatWebServer(Tomcat tomcat) {\n\t\tthis(tomcat, true);\n\t}\n\n\t/**\n\t * Create a new {@link TomcatWebServer} instance.\n\t * @param tomcat the underlying Tomcat server\n\t * @param autoStart if the server should be started\n\t */\n\tpublic TomcatWebServer(Tomcat tomcat, boolean autoStart) {\n\t\tthis(tomcat, autoStart, Shutdown.IMMEDIATE);\n\t}\n\n\t/**\n\t * Create a new {@link TomcatWebServer} instance.\n\t * @param tomcat the underlying Tomcat server\n\t * @param autoStart if the server should be started\n\t * @param shutdown type of shutdown supported by the server\n\t * @since 4.0.0\n\t */\n\tpublic TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {\n\t\tAssert.notNull(tomcat, \"'tomcat' must not be null\");\n\t\tthis.tomcat = tomcat;\n\t\tthis.autoStart = autoStart;\n\t\tthis.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;\n\t\tinitialize();\n\t}\n\n\tprivate void initialize() throws WebServerException {\n\t\tlogger.info(\"Tomcat initialized with \" + getPortsDescription(false));\n\t\tsynchronized (this.monitor) {\n\t\t\ttry {\n\t\t\t\taddInstanceIdToEngineName();\n\n\t\t\t\tContext context = findContext();\n\t\t\t\tcontext.addLifecycleListener((event) -> {\n\t\t\t\t\tif (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {\n\t\t\t\t\t\t// Remove service connectors so that protocol binding doesn't\n\t\t\t\t\t\t// happen when the service is started.\n\t\t\t\t\t\tremoveServiceConnectors();\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tdisableBindOnInit();\n\n\t\t\t\t// Start the server to trigger initialization listeners\n\t\t\t\tthis.tomcat.start();\n\n\t\t\t\t// We can re-throw failure exception directly in the main thread\n\t\t\t\trethrowDeferredStartupExceptions();\n\n\t\t\t\ttry {\n\t\t\t\t\tContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());\n\t\t\t\t}\n\t\t\t\tcatch (NamingException ex) {\n\t\t\t\t\t// Naming is not enabled. Continue\n\t\t\t\t}\n\n\t\t\t\t// Unlike Jetty, all Tomcat threads are daemon threads. We create a\n\t\t\t\t// blocking non-daemon to stop immediate shutdown\n\t\t\t\tstartNonDaemonAwaitThread();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tstopSilently();\n\t\t\t\tdestroySilently();\n\t\t\t\tthrow new WebServerException(\"Unable to start embedded Tomcat\", ex);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate Context findContext() {\n\t\tfor (Container child : this.tomcat.getHost().findChildren()) {\n\t\t\tif (child instanceof Context context) {\n\t\t\t\treturn context;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"The host does not contain a Context\");\n\t}\n\n\tprivate void addInstanceIdToEngineName() {\n\t\tint instanceId = containerCounter.incrementAndGet();\n\t\tif (instanceId > 0) {\n\t\t\tEngine engine = this.tomcat.getEngine();\n\t\t\tengine.setName(engine.getName() + \"-\" + instanceId);\n\t\t}\n\t}\n\n\tprivate void removeServiceConnectors() {\n\t\tdoWithConnectors((service, connectors) -> {\n\t\t\tthis.serviceConnectors.put(service, connectors);\n\t\t\tfor (Connector connector : connectors) {\n\t\t\t\tservice.removeConnector(connector);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void disableBindOnInit() {\n\t\tdoWithConnectors((service, connectors) -> {\n\t\t\tfor (Connector connector : connectors) {\n\t\t\t\tObject bindOnInit = connector.getProperty(\"bindOnInit\");\n\t\t\t\tif (bindOnInit == null) {\n\t\t\t\t\tconnector.setProperty(\"bindOnInit\", \"false\");\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void doWithConnectors(BiConsumer<Service, Connector[]> consumer) {\n\t\tfor (Service service : this.tomcat.getServer().findServices()) {\n\t\t\tConnector[] connectors = service.findConnectors().clone();\n\t\t\tconsumer.accept(service, connectors);\n\t\t}\n\t}\n\n\tprivate void rethrowDeferredStartupExceptions() throws Exception {\n\t\tContainer[] children = this.tomcat.getHost().findChildren();\n\t\tfor (Container container : children) {\n\t\t\tif (container instanceof TomcatEmbeddedContext embeddedContext) {\n\t\t\t\tembeddedContext.getDeferredStartupExceptions().rethrow();\n\t\t\t}\n\t\t\tif (!LifecycleState.STARTED.equals(container.getState())) {\n\t\t\t\tthrow new IllegalStateException(container + \" failed to start\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void startNonDaemonAwaitThread() {\n\t\tThread awaitThread = new Thread(\"container-\" + (containerCounter.get())) {\n\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\tTomcatWebServer.this.tomcat.getServer().await();\n\t\t\t}\n\n\t\t};\n\t\tawaitThread.setContextClassLoader(getClass().getClassLoader());\n\t\tawaitThread.setDaemon(false);\n\t\tawaitThread.start();\n\t}\n\n\t@Override\n\tpublic void start() throws WebServerException {\n\t\tsynchronized (this.monitor) {\n\t\t\tif (this.started) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\taddPreviouslyRemovedConnectors();\n\t\t\t\tConnector connector = this.tomcat.getConnector();\n\t\t\t\tif (connector != null && this.autoStart) {\n\t\t\t\t\tperformDeferredLoadOnStartup();\n\t\t\t\t}\n\t\t\t\tcheckThatConnectorsHaveStarted();\n\t\t\t\tthis.started = true;\n\t\t\t\tlogger.info(getStartedLogMessage());\n\t\t\t}\n\t\t\tcatch (ConnectorStartFailedException ex) {\n\t\t\t\tstopSilently();\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tPortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());\n\t\t\t\tthrow new WebServerException(\"Unable to start embedded Tomcat server\", ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tContext context = findContext();\n\t\t\t\tContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());\n\t\t\t}\n\t\t}\n\t}\n\n\tString getStartedLogMessage() {\n\t\tString contextPath = getContextPath();\n\t\treturn \"Tomcat started on \" + getPortsDescription(true)\n\t\t\t\t+ ((contextPath != null) ? \" with context path '\" + contextPath + \"'\" : \"\");\n\t}\n\n\tprivate void checkThatConnectorsHaveStarted() {\n\t\tcheckConnectorHasStarted(this.tomcat.getConnector());\n\t\tfor (Connector connector : this.tomcat.getService().findConnectors()) {\n\t\t\tcheckConnectorHasStarted(connector);\n\t\t}\n\t}\n\n\tprivate void checkConnectorHasStarted(Connector connector) {\n\t\tif (LifecycleState.FAILED.equals(connector.getState())) {\n\t\t\tthrow new ConnectorStartFailedException(connector.getPort());\n\t\t}\n\t}\n\n\tprivate void stopSilently() {\n\t\ttry {\n\t\t\tstopTomcat();\n\t\t}\n\t\tcatch (LifecycleException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate void destroySilently() {\n\t\ttry {\n\t\t\tthis.tomcat.destroy();\n\t\t}\n\t\tcatch (LifecycleException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\tprivate void stopTomcat() throws LifecycleException {\n\t\tif (Thread.currentThread().getContextClassLoader() instanceof TomcatEmbeddedWebappClassLoader) {\n\t\t\tThread.currentThread().setContextClassLoader(getClass().getClassLoader());\n\t\t}\n\t\tthis.tomcat.stop();\n\t}\n\n\tprivate void addPreviouslyRemovedConnectors() {\n\t\tService[] services = this.tomcat.getServer().findServices();\n\t\tfor (Service service : services) {\n\t\t\tConnector[] connectors = this.serviceConnectors.get(service);\n\t\t\tif (connectors != null) {\n\t\t\t\tfor (Connector connector : connectors) {\n\t\t\t\t\tservice.addConnector(connector);\n\t\t\t\t\tif (!this.autoStart) {\n\t\t\t\t\t\tstopProtocolHandler(connector);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.serviceConnectors.remove(service);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void stopProtocolHandler(Connector connector) {\n\t\ttry {\n\t\t\tconnector.getProtocolHandler().stop();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.error(\"Cannot pause connector: \", ex);\n\t\t}\n\t}\n\n\tprivate void performDeferredLoadOnStartup() {\n\t\ttry {\n\t\t\tfor (Container child : this.tomcat.getHost().findChildren()) {\n\t\t\t\tif (child instanceof TomcatEmbeddedContext embeddedContext) {\n\t\t\t\t\tembeddedContext.deferredLoadOnStartup();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tif (ex instanceof WebServerException webServerException) {\n\t\t\t\tthrow webServerException;\n\t\t\t}\n\t\t\tthrow new WebServerException(\"Unable to start embedded Tomcat connectors\", ex);\n\t\t}\n\t}\n\n\tMap<Service, Connector[]> getServiceConnectors() {\n\t\treturn this.serviceConnectors;\n\t}\n\n\t@Override\n\tpublic void stop() throws WebServerException {\n\t\tsynchronized (this.monitor) {\n\t\t\tboolean wasStarted = this.started;\n\t\t\ttry {\n\t\t\t\tthis.started = false;\n\t\t\t\tif (this.gracefulShutdown != null) {\n\t\t\t\t\tthis.gracefulShutdown.abort();\n\t\t\t\t}\n\t\t\t\tremoveServiceConnectors();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new WebServerException(\"Unable to stop embedded Tomcat\", ex);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tif (wasStarted) {\n\t\t\t\t\tcontainerCounter.decrementAndGet();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() throws WebServerException {\n\t\ttry {\n\t\t\tstopTomcat();\n\t\t\tthis.tomcat.destroy();\n\t\t}\n\t\tcatch (LifecycleException ex) {\n\t\t\t// Swallow and continue\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new WebServerException(\"Unable to destroy embedded Tomcat\", ex);\n\t\t}\n\t}\n\n\tprivate String getPortsDescription(boolean localPort) {\n\t\tStringBuilder description = new StringBuilder();\n\t\tConnector[] connectors = this.tomcat.getService().findConnectors();\n\t\tdescription.append(\"port\");\n\t\tif (connectors.length != 1) {\n\t\t\tdescription.append(\"s\");\n\t\t}\n\t\tdescription.append(\" \");\n\t\tfor (int i = 0; i < connectors.length; i++) {\n\t\t\tif (i != 0) {\n\t\t\t\tdescription.append(\", \");\n\t\t\t}\n\t\t\tConnector connector = connectors[i];\n\t\t\tint port = localPort ? connector.getLocalPort() : connector.getPort();\n\t\t\tdescription.append(port).append(\" (\").append(connector.getScheme()).append(')');\n\t\t}\n\t\treturn description.toString();\n\t}\n\n\t@Override\n\tpublic int getPort() {\n\t\tConnector connector = this.tomcat.getConnector();\n\t\tif (connector != null) {\n\t\t\treturn connector.getLocalPort();\n\t\t}\n\t\treturn -1;\n\t}\n\n\tprivate @Nullable String getContextPath() {\n\t\tString contextPath = Arrays.stream(this.tomcat.getHost().findChildren())\n\t\t\t.filter(TomcatEmbeddedContext.class::isInstance)\n\t\t\t.map(TomcatEmbeddedContext.class::cast)\n\t\t\t.filter(this::imperative)\n\t\t\t.map(TomcatEmbeddedContext::getPath)\n\t\t\t.map((path) -> path.isEmpty() ? \"/\" : path)\n\t\t\t.collect(Collectors.joining(\" \"));\n\t\treturn StringUtils.hasText(contextPath) ? contextPath : null;\n\t}\n\n\tprivate boolean imperative(TomcatEmbeddedContext context) {\n\t\tfor (Container container : context.findChildren()) {\n\t\t\tif (container instanceof Wrapper wrapper) {\n\t\t\t\tif (wrapper.getServletClass()\n\t\t\t\t\t.equals(\"org.springframework.http.server.reactive.TomcatHttpHandlerAdapter\")) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns access to the underlying Tomcat server.\n\t * @return the Tomcat server\n\t */\n\tpublic Tomcat getTomcat() {\n\t\treturn this.tomcat;\n\t}\n\n\t/**\n\t * Initiates a graceful shutdown of the Tomcat web server. Handling of new requests is\n\t * prevented and the given {@code callback} is invoked at the end of the attempt. The\n\t * attempt can be explicitly ended by invoking {@link #stop}.\n\t * <p>\n\t * Once shutdown has been initiated Tomcat will reject any new connections. Requests\n\t * on existing idle connections will also be rejected.\n\t */\n\t@Override\n\tpublic void shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tif (this.gracefulShutdown == null) {\n\t\t\tcallback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);\n\t\t\treturn;\n\t\t}\n\t\tthis.gracefulShutdown.shutDownGracefully(callback);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/TomcatWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.io.File;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Engine;\nimport org.apache.catalina.Executor;\nimport org.apache.catalina.Lifecycle;\nimport org.apache.catalina.LifecycleEvent;\nimport org.apache.catalina.LifecycleListener;\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.core.AprLifecycleListener;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.coyote.AbstractProtocol;\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.coyote.http2.Http2Protocol;\nimport org.apache.tomcat.util.modeler.Registry;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.core.NativeDetector;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Base class for factories that produce a {@link TomcatWebServer}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class TomcatWebServerFactory extends AbstractConfigurableWebServerFactory\n\t\timplements ConfigurableTomcatWebServerFactory {\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\t/**\n\t * The class name of default protocol used.\n\t */\n\tpublic static final String DEFAULT_PROTOCOL = \"org.apache.coyote.http11.Http11NioProtocol\";\n\n\tprivate final Log logger = LogFactory.getLog(getClass());\n\n\tprivate @Nullable File baseDirectory;\n\n\tprivate int backgroundProcessorDelay;\n\n\tprivate List<Valve> engineValves = new ArrayList<>();\n\n\tprivate List<Valve> contextValves = new ArrayList<>();\n\n\tprivate List<LifecycleListener> contextLifecycleListeners = new ArrayList<>();\n\n\tprivate Set<TomcatContextCustomizer> contextCustomizers = new LinkedHashSet<>();\n\n\tprivate Set<TomcatConnectorCustomizer> connectorCustomizers = new LinkedHashSet<>();\n\n\tprivate Set<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers = new LinkedHashSet<>();\n\n\tprivate List<Connector> additionalConnectors = new ArrayList<>();\n\n\tprivate Charset uriEncoding = DEFAULT_CHARSET;\n\n\tprivate String protocol = DEFAULT_PROTOCOL;\n\n\tprivate boolean disableMBeanRegistry = true;\n\n\tprivate boolean useApr;\n\n\tprotected TomcatWebServerFactory() {\n\t}\n\n\tprotected TomcatWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\tprivate List<LifecycleListener> getDefaultServerLifecycleListeners() {\n\t\tArrayList<LifecycleListener> lifecycleListeners = new ArrayList<>();\n\t\tif (this.useApr && !NativeDetector.inNativeImage()) {\n\t\t\tlifecycleListeners.add(new AprLifecycleListener());\n\t\t}\n\t\treturn lifecycleListeners;\n\t}\n\n\t@Override\n\tpublic void setBaseDirectory(@Nullable File baseDirectory) {\n\t\tthis.baseDirectory = baseDirectory;\n\t}\n\n\tpublic @Nullable File getBaseDirectory() {\n\t\treturn this.baseDirectory;\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link Valve}s that will be applied to the\n\t * Tomcat {@link Engine}.\n\t * @return the engine valves that will be applied\n\t */\n\tpublic Collection<Valve> getEngineValves() {\n\t\treturn this.engineValves;\n\t}\n\n\t/**\n\t * Set {@link Valve}s that should be applied to the Tomcat {@link Engine}. Calling\n\t * this method will replace any existing valves.\n\t * @param engineValves the valves to set\n\t */\n\tpublic void setEngineValves(Collection<? extends Valve> engineValves) {\n\t\tAssert.notNull(engineValves, \"'engineValves' must not be null\");\n\t\tthis.engineValves = new ArrayList<>(engineValves);\n\t}\n\n\t@Override\n\tpublic void addEngineValves(Valve... engineValves) {\n\t\tAssert.notNull(engineValves, \"'engineValves' must not be null\");\n\t\tthis.engineValves.addAll(Arrays.asList(engineValves));\n\t}\n\n\tpublic Charset getUriEncoding() {\n\t\treturn this.uriEncoding;\n\t}\n\n\t@Override\n\tpublic void setUriEncoding(Charset uriEncoding) {\n\t\tthis.uriEncoding = uriEncoding;\n\t}\n\n\tpublic int getBackgroundProcessorDelay() {\n\t\treturn this.backgroundProcessorDelay;\n\t}\n\n\t@Override\n\tpublic void setBackgroundProcessorDelay(int delay) {\n\t\tthis.backgroundProcessorDelay = delay;\n\t}\n\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\t/**\n\t * The Tomcat protocol to use when create the {@link Connector}.\n\t * @param protocol the protocol\n\t * @see Connector#Connector(String)\n\t */\n\tpublic void setProtocol(String protocol) {\n\t\tAssert.hasLength(protocol, \"'protocol' must not be empty\");\n\t\tthis.protocol = protocol;\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link Valve}s that will be applied to the\n\t * Tomcat {@link Context}.\n\t * @return the context valves that will be applied\n\t * @see #getEngineValves()\n\t */\n\tpublic Collection<Valve> getContextValves() {\n\t\treturn this.contextValves;\n\t}\n\n\t/**\n\t * Set {@link Valve}s that should be applied to the Tomcat {@link Context}. Calling\n\t * this method will replace any existing valves.\n\t * @param contextValves the valves to set\n\t */\n\tpublic void setContextValves(Collection<? extends Valve> contextValves) {\n\t\tAssert.notNull(contextValves, \"'contextValves' must not be null\");\n\t\tthis.contextValves = new ArrayList<>(contextValves);\n\t}\n\n\t/**\n\t * Add {@link Valve}s that should be applied to the Tomcat {@link Context}.\n\t * @param contextValves the valves to add\n\t */\n\tpublic void addContextValves(Valve... contextValves) {\n\t\tAssert.notNull(contextValves, \"'contextValves' must not be null\");\n\t\tthis.contextValves.addAll(Arrays.asList(contextValves));\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link LifecycleListener}s that will be applied\n\t * to the Tomcat {@link Context}.\n\t * @return the context lifecycle listeners that will be applied\n\t */\n\tpublic Collection<LifecycleListener> getContextLifecycleListeners() {\n\t\treturn this.contextLifecycleListeners;\n\t}\n\n\t/**\n\t * Set {@link LifecycleListener}s that should be applied to the Tomcat\n\t * {@link Context}. Calling this method will replace any existing listeners.\n\t * @param contextLifecycleListeners the listeners to set\n\t */\n\tpublic void setContextLifecycleListeners(Collection<? extends LifecycleListener> contextLifecycleListeners) {\n\t\tAssert.notNull(contextLifecycleListeners, \"'contextLifecycleListeners' must not be null\");\n\t\tthis.contextLifecycleListeners = new ArrayList<>(contextLifecycleListeners);\n\t}\n\n\t/**\n\t * Add {@link LifecycleListener}s that should be added to the Tomcat {@link Context}.\n\t * @param contextLifecycleListeners the listeners to add\n\t */\n\tpublic void addContextLifecycleListeners(LifecycleListener... contextLifecycleListeners) {\n\t\tAssert.notNull(contextLifecycleListeners, \"'contextLifecycleListeners' must not be null\");\n\t\tthis.contextLifecycleListeners.addAll(Arrays.asList(contextLifecycleListeners));\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link TomcatContextCustomizer}s that will be\n\t * applied to the Tomcat {@link Context}.\n\t * @return the listeners that will be applied\n\t */\n\tpublic Collection<TomcatContextCustomizer> getContextCustomizers() {\n\t\treturn this.contextCustomizers;\n\t}\n\n\t/**\n\t * Set {@link TomcatContextCustomizer}s that should be applied to the Tomcat\n\t * {@link Context}. Calling this method will replace any existing customizers.\n\t * @param contextCustomizers the customizers to set\n\t */\n\tpublic void setContextCustomizers(Collection<? extends TomcatContextCustomizer> contextCustomizers) {\n\t\tAssert.notNull(contextCustomizers, \"'contextCustomizers' must not be null\");\n\t\tthis.contextCustomizers = new LinkedHashSet<>(contextCustomizers);\n\t}\n\n\t@Override\n\tpublic void addContextCustomizers(TomcatContextCustomizer... contextCustomizers) {\n\t\tAssert.notNull(contextCustomizers, \"'contextCustomizers' must not be null\");\n\t\tthis.contextCustomizers.addAll(Arrays.asList(contextCustomizers));\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link TomcatConnectorCustomizer}s that will be\n\t * applied to the Tomcat {@link Connector}.\n\t * @return the customizers that will be applied\n\t */\n\tpublic Set<TomcatConnectorCustomizer> getConnectorCustomizers() {\n\t\treturn this.connectorCustomizers;\n\t}\n\n\t/**\n\t * Set {@link TomcatConnectorCustomizer}s that should be applied to the Tomcat\n\t * {@link Connector}. Calling this method will replace any existing customizers.\n\t * @param connectorCustomizers the customizers to set\n\t */\n\tpublic void setConnectorCustomizers(Collection<? extends TomcatConnectorCustomizer> connectorCustomizers) {\n\t\tAssert.notNull(connectorCustomizers, \"'connectorCustomizers' must not be null\");\n\t\tthis.connectorCustomizers = new LinkedHashSet<>(connectorCustomizers);\n\t}\n\n\t@Override\n\tpublic void addConnectorCustomizers(TomcatConnectorCustomizer... connectorCustomizers) {\n\t\tAssert.notNull(connectorCustomizers, \"'connectorCustomizers' must not be null\");\n\t\tthis.connectorCustomizers.addAll(Arrays.asList(connectorCustomizers));\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link TomcatProtocolHandlerCustomizer}s that\n\t * will be applied to the Tomcat {@link Connector}.\n\t * @return the customizers that will be applied\n\t */\n\tpublic Set<TomcatProtocolHandlerCustomizer<?>> getProtocolHandlerCustomizers() {\n\t\treturn this.protocolHandlerCustomizers;\n\t}\n\n\t/**\n\t * Set {@link TomcatProtocolHandlerCustomizer}s that should be applied to the Tomcat\n\t * {@link Connector}. Calling this method will replace any existing customizers.\n\t * @param protocolHandlerCustomizers the customizers to set\n\t */\n\tpublic void setProtocolHandlerCustomizers(\n\t\t\tCollection<? extends TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {\n\t\tAssert.notNull(protocolHandlerCustomizers, \"'protocolHandlerCustomizers' must not be null\");\n\t\tthis.protocolHandlerCustomizers = new LinkedHashSet<>(protocolHandlerCustomizers);\n\t}\n\n\t@Override\n\tpublic void addProtocolHandlerCustomizers(TomcatProtocolHandlerCustomizer<?>... protocolHandlerCustomizers) {\n\t\tAssert.notNull(protocolHandlerCustomizers, \"'protocolHandlerCustomizers' must not be null\");\n\t\tthis.protocolHandlerCustomizers.addAll(Arrays.asList(protocolHandlerCustomizers));\n\t}\n\n\t/**\n\t * Returns a mutable collection of the {@link Connector}s that will be added to the\n\t * Tomcat server.\n\t * @return the additional connectors\n\t */\n\tpublic List<Connector> getAdditionalConnectors() {\n\t\treturn this.additionalConnectors;\n\t}\n\n\t/**\n\t * Set additional {@link Connector}s that should be added to the Tomcat server .\n\t * Calling this method will replace any existing additional connectors.\n\t * @param additionalConnectors the additionalConnectors to set\n\t */\n\tpublic void setAdditionalConnectors(Collection<? extends Connector> additionalConnectors) {\n\t\tAssert.notNull(additionalConnectors, \"'additionalConnectors' must not be null\");\n\t\tthis.additionalConnectors = new ArrayList<>(additionalConnectors);\n\t}\n\n\t/**\n\t * Add {@link Connector}s in addition to the default connector, e.g. for SSL or AJP.\n\t * <p>\n\t * {@link #getConnectorCustomizers Connector customizers} are not applied to\n\t * connectors added this way.\n\t * @param connectors the connectors to add\n\t */\n\tpublic void addAdditionalConnectors(Connector... connectors) {\n\t\tAssert.notNull(connectors, \"'connectors' must not be null\");\n\t\tthis.additionalConnectors.addAll(Arrays.asList(connectors));\n\t}\n\n\t/**\n\t * Returns whether the factory should disable Tomcat's MBean registry prior to\n\t * creating the server.\n\t * @return whether to disable Tomcat's MBean registry\n\t */\n\tpublic boolean isDisableMBeanRegistry() {\n\t\treturn this.disableMBeanRegistry;\n\t}\n\n\t/**\n\t * Set whether the factory should disable Tomcat's MBean registry prior to creating\n\t * the server.\n\t * @param disableMBeanRegistry whether to disable the MBean registry\n\t */\n\t@Override\n\tpublic void setDisableMBeanRegistry(boolean disableMBeanRegistry) {\n\t\tthis.disableMBeanRegistry = disableMBeanRegistry;\n\t}\n\n\t/**\n\t * Whether to use APR.\n\t * @param useApr whether to use APR\n\t */\n\t@Override\n\tpublic void setUseApr(boolean useApr) {\n\t\tthis.useApr = useApr;\n\t}\n\n\t/**\n\t * Creates the {@link Tomcat} web server.\n\t * @return the web server.\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #createTomcat(TempDirs)}\n\t */\n\t@Deprecated(forRemoval = true, since = \"4.1.0\")\n\tprotected Tomcat createTomcat() {\n\t\treturn createTomcat(new TempDirs(getPort()));\n\t}\n\n\t/**\n\t * Creates the {@link Tomcat} web server.\n\t * @param tempDirs to manage temporary directories\n\t * @return the web server\n\t * @since 4.1.0\n\t */\n\tprotected Tomcat createTomcat(TempDirs tempDirs) {\n\t\tif (this.isDisableMBeanRegistry()) {\n\t\t\tRegistry.disableRegistry();\n\t\t}\n\t\tTomcat tomcat = new Tomcat();\n\t\tFile baseDir = (getBaseDirectory() != null) ? getBaseDirectory() : tempDirs.createTempDir(\"tomcat\").toFile();\n\t\ttomcat.setBaseDir(baseDir.getAbsolutePath());\n\t\tfor (LifecycleListener listener : getDefaultServerLifecycleListeners()) {\n\t\t\ttomcat.getServer().addLifecycleListener(listener);\n\t\t}\n\t\ttomcat.getServer().addLifecycleListener(new CleanTempDirsListener(tempDirs));\n\t\tConnector connector = new Connector(getProtocol());\n\t\tconnector.setThrowOnFailure(true);\n\t\ttomcat.getService().addConnector(connector);\n\t\tcustomizeConnector(connector);\n\t\ttomcat.setConnector(connector);\n\t\tregisterConnectorExecutor(tomcat, connector);\n\t\ttomcat.getHost().setAutoDeploy(false);\n\t\tconfigureEngine(tomcat.getEngine());\n\t\tfor (Connector additionalConnector : this.getAdditionalConnectors()) {\n\t\t\ttomcat.getService().addConnector(additionalConnector);\n\t\t\tregisterConnectorExecutor(tomcat, additionalConnector);\n\t\t}\n\t\treturn tomcat;\n\t}\n\n\tprotected void customizeConnector(Connector connector) {\n\t\tint port = Math.max(getPort(), 0);\n\t\tconnector.setPort(port);\n\t\tif (StringUtils.hasText(getServerHeader())) {\n\t\t\tconnector.setProperty(\"server\", getServerHeader());\n\t\t}\n\t\tif (connector.getProtocolHandler() instanceof AbstractProtocol<?> abstractProtocol) {\n\t\t\tcustomizeProtocol(abstractProtocol);\n\t\t}\n\t\tinvokeProtocolHandlerCustomizers(connector.getProtocolHandler());\n\t\tif (getUriEncoding() != null) {\n\t\t\tconnector.setURIEncoding(getUriEncoding().name());\n\t\t}\n\t\tif (getHttp2() != null && getHttp2().isEnabled()) {\n\t\t\tconnector.addUpgradeProtocol(new Http2Protocol());\n\t\t}\n\t\tSsl ssl = getSsl();\n\t\tif (Ssl.isEnabled(ssl)) {\n\t\t\tcustomizeSsl(connector, ssl);\n\t\t}\n\t\tTomcatConnectorCustomizer compression = new CompressionConnectorCustomizer(getCompression());\n\t\tcompression.customize(connector);\n\t\tfor (TomcatConnectorCustomizer customizer : this.getConnectorCustomizers()) {\n\t\t\tcustomizer.customize(connector);\n\t\t}\n\t}\n\n\tprivate void customizeProtocol(AbstractProtocol<?> protocol) {\n\t\tif (getAddress() != null) {\n\t\t\tprotocol.setAddress(getAddress());\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void invokeProtocolHandlerCustomizers(ProtocolHandler protocolHandler) {\n\t\tLambdaSafe\n\t\t\t.callbacks(TomcatProtocolHandlerCustomizer.class, this.getProtocolHandlerCustomizers(), protocolHandler)\n\t\t\t.invoke((customizer) -> customizer.customize(protocolHandler));\n\t}\n\n\tprivate void customizeSsl(Connector connector, Ssl ssl) {\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());\n\t\tcustomizer.customize(getSslBundle(), getServerNameSslBundles());\n\t\taddBundleUpdateHandler(null, ssl.getBundle(), customizer);\n\t\tssl.getServerNameBundles()\n\t\t\t.forEach((serverNameSslBundle) -> addBundleUpdateHandler(serverNameSslBundle.serverName(),\n\t\t\t\t\tserverNameSslBundle.bundle(), customizer));\n\t}\n\n\tprivate void addBundleUpdateHandler(@Nullable String serverName, @Nullable String sslBundleName,\n\t\t\tSslConnectorCustomizer customizer) {\n\t\tif (StringUtils.hasText(sslBundleName)) {\n\t\t\tSslBundles sslBundles = getSslBundles();\n\t\t\tAssert.state(sslBundles != null, \"'sslBundles' must not be null\");\n\t\t\tsslBundles.addBundleUpdateHandler(sslBundleName, (sslBundle) -> customizer.update(serverName, sslBundle));\n\t\t}\n\t}\n\n\tprivate void registerConnectorExecutor(Tomcat tomcat, Connector connector) {\n\t\tif (connector.getProtocolHandler().getExecutor() instanceof Executor executor) {\n\t\t\ttomcat.getService().addExecutor(executor);\n\t\t}\n\t}\n\n\tprivate void configureEngine(Engine engine) {\n\t\tengine.setBackgroundProcessorDelay(getBackgroundProcessorDelay());\n\t\tfor (Valve valve : getEngineValves()) {\n\t\t\tengine.getPipeline().addValve(valve);\n\t\t}\n\t}\n\n\tprivate static class CleanTempDirsListener implements LifecycleListener {\n\n\t\tprivate final TempDirs tempDirs;\n\n\t\tCleanTempDirsListener(TempDirs tempDirs) {\n\t\t\tthis.tempDirs = tempDirs;\n\t\t}\n\n\t\t@Override\n\t\tpublic void lifecycleEvent(LifecycleEvent event) {\n\t\t\tif (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {\n\t\t\t\tthis.tempDirs.cleanup();\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/TomcatBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport org.apache.catalina.authenticator.NonLoginAuthenticator;\nimport org.apache.tomcat.util.http.Rfc6265CookieProcessor;\n\nimport org.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer;\n\n/**\n * {@link BackgroundPreinitializer} for Tomcat.\n *\n * @author Phillip Webb\n */\nfinal class TomcatBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tnew Rfc6265CookieProcessor();\n\t\tnew NonLoginAuthenticator();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/TomcatServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.io.File;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Tomcat server properties.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Ivan Sopov\n * @author Marcos Barbero\n * @author Eddú Meléndez\n * @author Quinten De Swaef\n * @author Venil Noronha\n * @author Aurélien Leboulanger\n * @author Brian Clozel\n * @author Olivier Lamy\n * @author Chentao Qu\n * @author Artsiom Yudovin\n * @author Andrew McGhie\n * @author Rafiullah Hamedy\n * @author Dirk Deyne\n * @author HaiTao Zhang\n * @author Victor Mandujano\n * @author Chris Bono\n * @author Parviz Rozikov\n * @author Florian Storz\n * @author Michael Weidmann\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@ConfigurationProperties(\"server.tomcat\")\npublic class TomcatServerProperties {\n\n\t/**\n\t * Tomcat base directory. If not specified, a temporary directory is used.\n\t */\n\tprivate @Nullable File basedir;\n\n\t/**\n\t * Delay between the invocation of backgroundProcess methods. If a duration suffix is\n\t * not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate Duration backgroundProcessorDelay = Duration.ofSeconds(10);\n\n\t/**\n\t * Maximum size of the form content in any HTTP post request.\n\t */\n\tprivate DataSize maxHttpFormPostSize = DataSize.ofMegabytes(2);\n\n\t/**\n\t * Maximum per-part header size permitted in a multipart/form-data request. Requests\n\t * that exceed this limit will be rejected. A value of less than 0 means no limit.\n\t */\n\tprivate DataSize maxPartHeaderSize = DataSize.ofBytes(512);\n\n\t/**\n\t * Maximum total number of parts permitted in a multipart/form-data request. Requests\n\t * that exceed this limit will be rejected. A value of less than 0 means no limit.\n\t */\n\tprivate int maxPartCount = 50;\n\n\t/**\n\t * Maximum amount of request body to swallow.\n\t */\n\tprivate DataSize maxSwallowSize = DataSize.ofMegabytes(2);\n\n\t/**\n\t * Whether requests to the context root should be redirected by appending a / to the\n\t * path. When using SSL terminated at a proxy, this property should be set to false.\n\t */\n\tprivate Boolean redirectContextRoot = true;\n\n\t/**\n\t * Whether HTTP 1.1 and later location headers generated by a call to sendRedirect\n\t * will use relative or absolute redirects.\n\t */\n\tprivate boolean useRelativeRedirects;\n\n\t/**\n\t * Character encoding to use to decode the URI.\n\t */\n\tprivate Charset uriEncoding = StandardCharsets.UTF_8;\n\n\t/**\n\t * Maximum number of connections that the server accepts and processes at any given\n\t * time. Once the limit has been reached, the operating system may still accept\n\t * connections based on the \"acceptCount\" property.\n\t */\n\tprivate int maxConnections = 8192;\n\n\t/**\n\t * Maximum queue length for incoming connection requests when all possible request\n\t * processing threads are in use.\n\t */\n\tprivate int acceptCount = 100;\n\n\t/**\n\t * Maximum number of idle processors that will be retained in the cache and reused\n\t * with a subsequent request. When set to -1 the cache will be unlimited with a\n\t * theoretical maximum size equal to the maximum number of connections.\n\t */\n\tprivate int processorCache = 200;\n\n\t/**\n\t * Time to wait for another HTTP request before the connection is closed. When not set\n\t * the connectionTimeout is used. When set to -1 there will be no timeout.\n\t */\n\tprivate @Nullable Duration keepAliveTimeout;\n\n\t/**\n\t * Maximum number of HTTP requests that can be pipelined before the connection is\n\t * closed. When set to 0 or 1, keep-alive and pipelining are disabled. When set to -1,\n\t * an unlimited number of pipelined or keep-alive requests are allowed.\n\t */\n\tprivate int maxKeepAliveRequests = 100;\n\n\t/**\n\t * List of additional patterns that match jars to ignore for TLD scanning. The special\n\t * '?' and '*' characters can be used in the pattern to match one and only one\n\t * character and zero or more characters respectively.\n\t */\n\tprivate List<String> additionalTldSkipPatterns = new ArrayList<>();\n\n\t/**\n\t * List of additional unencoded characters that should be allowed in URI paths. Only\n\t * \"< > [ \\ ] ^ ` { | }\" are allowed.\n\t */\n\tprivate List<Character> relaxedPathChars = new ArrayList<>();\n\n\t/**\n\t * List of additional unencoded characters that should be allowed in URI query\n\t * strings. Only \"< > [ \\ ] ^ ` { | }\" are allowed.\n\t */\n\tprivate List<Character> relaxedQueryChars = new ArrayList<>();\n\n\t/**\n\t * Amount of time the connector will wait, after accepting a connection, for the\n\t * request URI line to be presented.\n\t */\n\tprivate @Nullable Duration connectionTimeout;\n\n\t/**\n\t * Maximum size of the HTTP response header.\n\t */\n\tprivate DataSize maxHttpResponseHeaderSize = DataSize.ofKilobytes(8);\n\n\t/**\n\t * Maximum number of parameters (GET plus POST) that will be automatically parsed by\n\t * the container. A value of less than 0 means no limit.\n\t */\n\tprivate int maxParameterCount = 1000;\n\n\t/**\n\t * Whether to use APR.\n\t */\n\tprivate UseApr useApr = UseApr.NEVER;\n\n\t/**\n\t * Access log configuration.\n\t */\n\tprivate final Accesslog accesslog = new Accesslog();\n\n\t/**\n\t * Thread related configuration.\n\t */\n\tprivate final Threads threads = new Threads();\n\n\t/**\n\t * Static resource configuration.\n\t */\n\tprivate final Resource resource = new Resource();\n\n\t/**\n\t * Modeler MBean Registry configuration.\n\t */\n\tprivate final Mbeanregistry mbeanregistry = new Mbeanregistry();\n\n\t/**\n\t * Remote Ip Valve configuration.\n\t */\n\tprivate final Remoteip remoteip = new Remoteip();\n\n\tpublic Duration getBackgroundProcessorDelay() {\n\t\treturn this.backgroundProcessorDelay;\n\t}\n\n\tpublic void setBackgroundProcessorDelay(Duration backgroundProcessorDelay) {\n\t\tthis.backgroundProcessorDelay = backgroundProcessorDelay;\n\t}\n\n\tpublic @Nullable File getBasedir() {\n\t\treturn this.basedir;\n\t}\n\n\tpublic void setBasedir(@Nullable File basedir) {\n\t\tthis.basedir = basedir;\n\t}\n\n\tpublic Boolean getRedirectContextRoot() {\n\t\treturn this.redirectContextRoot;\n\t}\n\n\tpublic void setRedirectContextRoot(Boolean redirectContextRoot) {\n\t\tthis.redirectContextRoot = redirectContextRoot;\n\t}\n\n\tpublic boolean isUseRelativeRedirects() {\n\t\treturn this.useRelativeRedirects;\n\t}\n\n\tpublic void setUseRelativeRedirects(boolean useRelativeRedirects) {\n\t\tthis.useRelativeRedirects = useRelativeRedirects;\n\t}\n\n\tpublic Charset getUriEncoding() {\n\t\treturn this.uriEncoding;\n\t}\n\n\tpublic void setUriEncoding(Charset uriEncoding) {\n\t\tthis.uriEncoding = uriEncoding;\n\t}\n\n\tpublic int getMaxConnections() {\n\t\treturn this.maxConnections;\n\t}\n\n\tpublic void setMaxConnections(int maxConnections) {\n\t\tthis.maxConnections = maxConnections;\n\t}\n\n\tpublic DataSize getMaxSwallowSize() {\n\t\treturn this.maxSwallowSize;\n\t}\n\n\tpublic void setMaxSwallowSize(DataSize maxSwallowSize) {\n\t\tthis.maxSwallowSize = maxSwallowSize;\n\t}\n\n\tpublic int getAcceptCount() {\n\t\treturn this.acceptCount;\n\t}\n\n\tpublic void setAcceptCount(int acceptCount) {\n\t\tthis.acceptCount = acceptCount;\n\t}\n\n\tpublic int getProcessorCache() {\n\t\treturn this.processorCache;\n\t}\n\n\tpublic void setProcessorCache(int processorCache) {\n\t\tthis.processorCache = processorCache;\n\t}\n\n\tpublic @Nullable Duration getKeepAliveTimeout() {\n\t\treturn this.keepAliveTimeout;\n\t}\n\n\tpublic void setKeepAliveTimeout(@Nullable Duration keepAliveTimeout) {\n\t\tthis.keepAliveTimeout = keepAliveTimeout;\n\t}\n\n\tpublic int getMaxKeepAliveRequests() {\n\t\treturn this.maxKeepAliveRequests;\n\t}\n\n\tpublic void setMaxKeepAliveRequests(int maxKeepAliveRequests) {\n\t\tthis.maxKeepAliveRequests = maxKeepAliveRequests;\n\t}\n\n\tpublic List<String> getAdditionalTldSkipPatterns() {\n\t\treturn this.additionalTldSkipPatterns;\n\t}\n\n\tpublic void setAdditionalTldSkipPatterns(List<String> additionalTldSkipPatterns) {\n\t\tthis.additionalTldSkipPatterns = additionalTldSkipPatterns;\n\t}\n\n\tpublic List<Character> getRelaxedPathChars() {\n\t\treturn this.relaxedPathChars;\n\t}\n\n\tpublic void setRelaxedPathChars(List<Character> relaxedPathChars) {\n\t\tthis.relaxedPathChars = relaxedPathChars;\n\t}\n\n\tpublic List<Character> getRelaxedQueryChars() {\n\t\treturn this.relaxedQueryChars;\n\t}\n\n\tpublic void setRelaxedQueryChars(List<Character> relaxedQueryChars) {\n\t\tthis.relaxedQueryChars = relaxedQueryChars;\n\t}\n\n\tpublic @Nullable Duration getConnectionTimeout() {\n\t\treturn this.connectionTimeout;\n\t}\n\n\tpublic void setConnectionTimeout(@Nullable Duration connectionTimeout) {\n\t\tthis.connectionTimeout = connectionTimeout;\n\t}\n\n\tpublic DataSize getMaxHttpResponseHeaderSize() {\n\t\treturn this.maxHttpResponseHeaderSize;\n\t}\n\n\tpublic void setMaxHttpResponseHeaderSize(DataSize maxHttpResponseHeaderSize) {\n\t\tthis.maxHttpResponseHeaderSize = maxHttpResponseHeaderSize;\n\t}\n\n\tpublic DataSize getMaxHttpFormPostSize() {\n\t\treturn this.maxHttpFormPostSize;\n\t}\n\n\tpublic void setMaxHttpFormPostSize(DataSize maxHttpFormPostSize) {\n\t\tthis.maxHttpFormPostSize = maxHttpFormPostSize;\n\t}\n\n\tpublic DataSize getMaxPartHeaderSize() {\n\t\treturn this.maxPartHeaderSize;\n\t}\n\n\tpublic void setMaxPartHeaderSize(DataSize maxPartHeaderSize) {\n\t\tthis.maxPartHeaderSize = maxPartHeaderSize;\n\t}\n\n\tpublic int getMaxPartCount() {\n\t\treturn this.maxPartCount;\n\t}\n\n\tpublic void setMaxPartCount(int maxPartCount) {\n\t\tthis.maxPartCount = maxPartCount;\n\t}\n\n\tpublic int getMaxParameterCount() {\n\t\treturn this.maxParameterCount;\n\t}\n\n\tpublic void setMaxParameterCount(int maxParameterCount) {\n\t\tthis.maxParameterCount = maxParameterCount;\n\t}\n\n\tpublic UseApr getUseApr() {\n\t\treturn this.useApr;\n\t}\n\n\tpublic void setUseApr(UseApr useApr) {\n\t\tthis.useApr = useApr;\n\t}\n\n\tpublic Accesslog getAccesslog() {\n\t\treturn this.accesslog;\n\t}\n\n\tpublic Threads getThreads() {\n\t\treturn this.threads;\n\t}\n\n\tpublic Resource getResource() {\n\t\treturn this.resource;\n\t}\n\n\tpublic Mbeanregistry getMbeanregistry() {\n\t\treturn this.mbeanregistry;\n\t}\n\n\tpublic Remoteip getRemoteip() {\n\t\treturn this.remoteip;\n\t}\n\n\t/**\n\t * Tomcat access log properties.\n\t */\n\tpublic static class Accesslog {\n\n\t\t/**\n\t\t * Enable access log.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\t/**\n\t\t * Whether logging of the request will only be enabled if\n\t\t * \"ServletRequest.getAttribute(conditionIf)\" does not yield null.\n\t\t */\n\t\tprivate @Nullable String conditionIf;\n\n\t\t/**\n\t\t * Whether logging of the request will only be enabled if\n\t\t * \"ServletRequest.getAttribute(conditionUnless)\" yield null.\n\t\t */\n\t\tprivate @Nullable String conditionUnless;\n\n\t\t/**\n\t\t * Format pattern for access logs.\n\t\t */\n\t\tprivate String pattern = \"common\";\n\n\t\t/**\n\t\t * Directory in which log files are created. Can be absolute or relative to the\n\t\t * Tomcat base dir.\n\t\t */\n\t\tprivate String directory = \"logs\";\n\n\t\t/**\n\t\t * Log file name prefix.\n\t\t */\n\t\tprotected String prefix = \"access_log\";\n\n\t\t/**\n\t\t * Log file name suffix.\n\t\t */\n\t\tprivate String suffix = \".log\";\n\n\t\t/**\n\t\t * Character set used by the log file. Default to the system default character\n\t\t * set.\n\t\t */\n\t\tprivate @Nullable String encoding;\n\n\t\t/**\n\t\t * Locale used to format timestamps in log entries and in log file name suffix.\n\t\t * Default to the default locale of the Java process.\n\t\t */\n\t\tprivate @Nullable String locale;\n\n\t\t/**\n\t\t * Whether to check for log file existence so it can be recreated if an external\n\t\t * process has renamed it.\n\t\t */\n\t\tprivate boolean checkExists;\n\n\t\t/**\n\t\t * Whether to enable access log rotation.\n\t\t */\n\t\tprivate boolean rotate = true;\n\n\t\t/**\n\t\t * Whether to defer inclusion of the date stamp in the file name until rotate\n\t\t * time.\n\t\t */\n\t\tprivate boolean renameOnRotate;\n\n\t\t/**\n\t\t * Number of days to retain the access log files before they are removed.\n\t\t */\n\t\tprivate int maxDays = -1;\n\n\t\t/**\n\t\t * Date format to place in the log file name.\n\t\t */\n\t\tprivate String fileDateFormat = \".yyyy-MM-dd\";\n\n\t\t/**\n\t\t * Whether to use IPv6 canonical representation format as defined by RFC 5952.\n\t\t */\n\t\tprivate boolean ipv6Canonical;\n\n\t\t/**\n\t\t * Set request attributes for the IP address, Hostname, protocol, and port used\n\t\t * for the request.\n\t\t */\n\t\tprivate boolean requestAttributesEnabled;\n\n\t\t/**\n\t\t * Whether to buffer output such that it is flushed only periodically.\n\t\t */\n\t\tprivate boolean buffered = true;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t\tpublic @Nullable String getConditionIf() {\n\t\t\treturn this.conditionIf;\n\t\t}\n\n\t\tpublic void setConditionIf(@Nullable String conditionIf) {\n\t\t\tthis.conditionIf = conditionIf;\n\t\t}\n\n\t\tpublic @Nullable String getConditionUnless() {\n\t\t\treturn this.conditionUnless;\n\t\t}\n\n\t\tpublic void setConditionUnless(@Nullable String conditionUnless) {\n\t\t\tthis.conditionUnless = conditionUnless;\n\t\t}\n\n\t\tpublic String getPattern() {\n\t\t\treturn this.pattern;\n\t\t}\n\n\t\tpublic void setPattern(String pattern) {\n\t\t\tthis.pattern = pattern;\n\t\t}\n\n\t\tpublic String getDirectory() {\n\t\t\treturn this.directory;\n\t\t}\n\n\t\tpublic void setDirectory(String directory) {\n\t\t\tthis.directory = directory;\n\t\t}\n\n\t\tpublic String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic void setPrefix(String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t\tpublic String getSuffix() {\n\t\t\treturn this.suffix;\n\t\t}\n\n\t\tpublic void setSuffix(String suffix) {\n\t\t\tthis.suffix = suffix;\n\t\t}\n\n\t\tpublic @Nullable String getEncoding() {\n\t\t\treturn this.encoding;\n\t\t}\n\n\t\tpublic void setEncoding(@Nullable String encoding) {\n\t\t\tthis.encoding = encoding;\n\t\t}\n\n\t\tpublic @Nullable String getLocale() {\n\t\t\treturn this.locale;\n\t\t}\n\n\t\tpublic void setLocale(@Nullable String locale) {\n\t\t\tthis.locale = locale;\n\t\t}\n\n\t\tpublic boolean isCheckExists() {\n\t\t\treturn this.checkExists;\n\t\t}\n\n\t\tpublic void setCheckExists(boolean checkExists) {\n\t\t\tthis.checkExists = checkExists;\n\t\t}\n\n\t\tpublic boolean isRotate() {\n\t\t\treturn this.rotate;\n\t\t}\n\n\t\tpublic void setRotate(boolean rotate) {\n\t\t\tthis.rotate = rotate;\n\t\t}\n\n\t\tpublic boolean isRenameOnRotate() {\n\t\t\treturn this.renameOnRotate;\n\t\t}\n\n\t\tpublic void setRenameOnRotate(boolean renameOnRotate) {\n\t\t\tthis.renameOnRotate = renameOnRotate;\n\t\t}\n\n\t\tpublic int getMaxDays() {\n\t\t\treturn this.maxDays;\n\t\t}\n\n\t\tpublic void setMaxDays(int maxDays) {\n\t\t\tthis.maxDays = maxDays;\n\t\t}\n\n\t\tpublic String getFileDateFormat() {\n\t\t\treturn this.fileDateFormat;\n\t\t}\n\n\t\tpublic void setFileDateFormat(String fileDateFormat) {\n\t\t\tthis.fileDateFormat = fileDateFormat;\n\t\t}\n\n\t\tpublic boolean isIpv6Canonical() {\n\t\t\treturn this.ipv6Canonical;\n\t\t}\n\n\t\tpublic void setIpv6Canonical(boolean ipv6Canonical) {\n\t\t\tthis.ipv6Canonical = ipv6Canonical;\n\t\t}\n\n\t\tpublic boolean isRequestAttributesEnabled() {\n\t\t\treturn this.requestAttributesEnabled;\n\t\t}\n\n\t\tpublic void setRequestAttributesEnabled(boolean requestAttributesEnabled) {\n\t\t\tthis.requestAttributesEnabled = requestAttributesEnabled;\n\t\t}\n\n\t\tpublic boolean isBuffered() {\n\t\t\treturn this.buffered;\n\t\t}\n\n\t\tpublic void setBuffered(boolean buffered) {\n\t\t\tthis.buffered = buffered;\n\t\t}\n\n\t}\n\n\t/**\n\t * Tomcat thread properties.\n\t */\n\tpublic static class Threads {\n\n\t\t/**\n\t\t * Maximum amount of worker threads. Doesn't have an effect if virtual threads are\n\t\t * enabled.\n\t\t */\n\t\tprivate int max = 200;\n\n\t\t/**\n\t\t * Minimum amount of worker threads. Doesn't have an effect if virtual threads are\n\t\t * enabled.\n\t\t */\n\t\tprivate int minSpare = 10;\n\n\t\t/**\n\t\t * Maximum capacity of the thread pool's backing queue. This setting only has an\n\t\t * effect if the value is greater than 0.\n\t\t */\n\t\tprivate int maxQueueCapacity = 2147483647;\n\n\t\tpublic int getMax() {\n\t\t\treturn this.max;\n\t\t}\n\n\t\tpublic void setMax(int max) {\n\t\t\tthis.max = max;\n\t\t}\n\n\t\tpublic int getMinSpare() {\n\t\t\treturn this.minSpare;\n\t\t}\n\n\t\tpublic void setMinSpare(int minSpare) {\n\t\t\tthis.minSpare = minSpare;\n\t\t}\n\n\t\tpublic int getMaxQueueCapacity() {\n\t\t\treturn this.maxQueueCapacity;\n\t\t}\n\n\t\tpublic void setMaxQueueCapacity(int maxQueueCapacity) {\n\t\t\tthis.maxQueueCapacity = maxQueueCapacity;\n\t\t}\n\n\t}\n\n\t/**\n\t * Tomcat static resource properties.\n\t */\n\tpublic static class Resource {\n\n\t\t/**\n\t\t * Whether static resource caching is permitted for this web application.\n\t\t */\n\t\tprivate boolean allowCaching = true;\n\n\t\t/**\n\t\t * Maximum size of the static resource cache.\n\t\t */\n\t\tprivate DataSize cacheMaxSize = DataSize.ofMegabytes(10);\n\n\t\t/**\n\t\t * Time-to-live of the static resource cache.\n\t\t */\n\t\tprivate Duration cacheTtl = Duration.ofSeconds(5);\n\n\t\tpublic boolean isAllowCaching() {\n\t\t\treturn this.allowCaching;\n\t\t}\n\n\t\tpublic void setAllowCaching(boolean allowCaching) {\n\t\t\tthis.allowCaching = allowCaching;\n\t\t}\n\n\t\tpublic DataSize getCacheMaxSize() {\n\t\t\treturn this.cacheMaxSize;\n\t\t}\n\n\t\tpublic void setCacheMaxSize(DataSize cacheMaxSize) {\n\t\t\tthis.cacheMaxSize = cacheMaxSize;\n\t\t}\n\n\t\tpublic Duration getCacheTtl() {\n\t\t\treturn this.cacheTtl;\n\t\t}\n\n\t\tpublic void setCacheTtl(Duration cacheTtl) {\n\t\t\tthis.cacheTtl = cacheTtl;\n\t\t}\n\n\t}\n\n\tpublic static class Mbeanregistry {\n\n\t\t/**\n\t\t * Whether Tomcat's MBean Registry should be enabled.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\tpublic static class Remoteip {\n\n\t\t/**\n\t\t * Internal proxies that are to be trusted. Can be set as a comma separate list of\n\t\t * CIDR or as a regular expression.\n\t\t */\n\t\tprivate String internalProxies = \"192.168.0.0/16, 172.16.0.0/12, 169.254.0.0/16, fc00::/7, \"\n\t\t\t\t+ \"10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, fe80::/10, ::1/128\";\n\n\t\t/**\n\t\t * Header that holds the incoming protocol, usually named \"X-Forwarded-Proto\".\n\t\t */\n\t\tprivate @Nullable String protocolHeader;\n\n\t\t/**\n\t\t * Value of the protocol header indicating whether the incoming request uses SSL.\n\t\t */\n\t\tprivate String protocolHeaderHttpsValue = \"https\";\n\n\t\t/**\n\t\t * Name of the HTTP header from which the remote host is extracted.\n\t\t */\n\t\tprivate String hostHeader = \"X-Forwarded-Host\";\n\n\t\t/**\n\t\t * Name of the HTTP header used to override the original port value.\n\t\t */\n\t\tprivate String portHeader = \"X-Forwarded-Port\";\n\n\t\t/**\n\t\t * Name of the HTTP header from which the remote IP is extracted. For instance,\n\t\t * 'X-FORWARDED-FOR'.\n\t\t */\n\t\tprivate @Nullable String remoteIpHeader;\n\n\t\t/**\n\t\t * Regular expression defining proxies that are trusted when they appear in the\n\t\t * \"remote-ip-header\" header.\n\t\t */\n\t\tprivate @Nullable String trustedProxies;\n\n\t\tpublic String getInternalProxies() {\n\t\t\treturn this.internalProxies;\n\t\t}\n\n\t\tpublic void setInternalProxies(String internalProxies) {\n\t\t\tthis.internalProxies = internalProxies;\n\t\t}\n\n\t\tpublic @Nullable String getProtocolHeader() {\n\t\t\treturn this.protocolHeader;\n\t\t}\n\n\t\tpublic void setProtocolHeader(@Nullable String protocolHeader) {\n\t\t\tthis.protocolHeader = protocolHeader;\n\t\t}\n\n\t\tpublic String getProtocolHeaderHttpsValue() {\n\t\t\treturn this.protocolHeaderHttpsValue;\n\t\t}\n\n\t\tpublic String getHostHeader() {\n\t\t\treturn this.hostHeader;\n\t\t}\n\n\t\tpublic void setHostHeader(String hostHeader) {\n\t\t\tthis.hostHeader = hostHeader;\n\t\t}\n\n\t\tpublic void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) {\n\t\t\tthis.protocolHeaderHttpsValue = protocolHeaderHttpsValue;\n\t\t}\n\n\t\tpublic String getPortHeader() {\n\t\t\treturn this.portHeader;\n\t\t}\n\n\t\tpublic void setPortHeader(String portHeader) {\n\t\t\tthis.portHeader = portHeader;\n\t\t}\n\n\t\tpublic @Nullable String getRemoteIpHeader() {\n\t\t\treturn this.remoteIpHeader;\n\t\t}\n\n\t\tpublic void setRemoteIpHeader(@Nullable String remoteIpHeader) {\n\t\t\tthis.remoteIpHeader = remoteIpHeader;\n\t\t}\n\n\t\tpublic @Nullable String getTrustedProxies() {\n\t\t\treturn this.trustedProxies;\n\t\t}\n\n\t\tpublic void setTrustedProxies(@Nullable String trustedProxies) {\n\t\t\tthis.trustedProxies = trustedProxies;\n\t\t}\n\n\t}\n\n\t/**\n\t * When to use APR.\n\t */\n\tpublic enum UseApr {\n\n\t\t/**\n\t\t * Always use APR and fail if it's not available.\n\t\t */\n\t\tALWAYS,\n\n\t\t/**\n\t\t * Use APR if it is available.\n\t\t */\n\t\tWHEN_AVAILABLE,\n\n\t\t/**\n\t\t * Never use APR.\n\t\t */\n\t\tNEVER\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/TomcatVirtualThreadsWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.tomcat.util.threads.VirtualThreadExecutor;\n\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.core.Ordered;\n\n/**\n * Activates {@link VirtualThreadExecutor} on {@link ProtocolHandler Tomcat's protocol\n * handler}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class TomcatVirtualThreadsWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {\n\n\t@Override\n\tpublic void customize(ConfigurableTomcatWebServerFactory factory) {\n\t\tfactory.addProtocolHandlerCustomizers(\n\t\t\t\t(protocolHandler) -> protocolHandler.setExecutor(new VirtualThreadExecutor(\"tomcat-handler-\")));\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn TomcatWebServerFactoryCustomizer.ORDER + 1;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/TomcatWebServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport org.apache.tomcat.websocket.server.WsSci;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnThreading;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.boot.tomcat.autoconfigure.reactive.TomcatReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\n\n/**\n * {@link Configuration Configuration} for a Tomcat-based reactive or servlet web server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see TomcatReactiveWebServerAutoConfiguration\n * @see TomcatServletWebServerAutoConfiguration\n */\n@ConditionalOnNotWarDeployment\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(WebProperties.class)\npublic class TomcatWebServerConfiguration {\n\n\t@Bean\n\tTomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,\n\t\t\tServerProperties serverProperties, TomcatServerProperties tomcatProperties, WebProperties webProperties) {\n\t\treturn new TomcatWebServerFactoryCustomizer(environment, serverProperties, tomcatProperties, webProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnThreading(Threading.VIRTUAL)\n\tTomcatVirtualThreadsWebServerFactoryCustomizer tomcatVirtualThreadsProtocolHandlerCustomizer() {\n\t\treturn new TomcatVirtualThreadsWebServerFactoryCustomizer();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(WsSci.class)\n\tstatic class TomcatWebSocketConfiguration {\n\n\t\t@Bean\n\t\tWebSocketTomcatWebServerFactoryCustomizer webSocketWebServerCustomizer() {\n\t\t\treturn new WebSocketTomcatWebServerFactoryCustomizer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/TomcatWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.function.ObjIntConsumer;\nimport java.util.stream.Collectors;\n\nimport org.apache.catalina.Lifecycle;\nimport org.apache.catalina.core.AprLifecycleListener;\nimport org.apache.catalina.valves.AccessLogValve;\nimport org.apache.catalina.valves.ErrorReportValve;\nimport org.apache.catalina.valves.RemoteIpValve;\nimport org.apache.coyote.AbstractProtocol;\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.coyote.UpgradeProtocol;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.apache.coyote.http2.Http2Protocol;\n\nimport org.springframework.boot.autoconfigure.web.ErrorProperties;\nimport org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeAttribute;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.cloud.CloudPlatform;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties.Accesslog;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties.Remoteip;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties.UseApr;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Customization for Tomcat-specific features common to both Servlet and Reactive servers.\n *\n * @author Brian Clozel\n * @author Yulin Qin\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Chentao Qu\n * @author Andrew McGhie\n * @author Dirk Deyne\n * @author Rafiullah Hamedy\n * @author Victor Mandujano\n * @author Parviz Rozikov\n * @author Florian Storz\n * @author Michael Weidmann\n * @since 4.0.0\n */\npublic class TomcatWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {\n\n\tstatic final int ORDER = 0;\n\n\tprivate final Environment environment;\n\n\tprivate final ServerProperties serverProperties;\n\n\tprivate final TomcatServerProperties tomcatProperties;\n\n\tprivate final WebProperties webProperties;\n\n\tpublic TomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties,\n\t\t\tTomcatServerProperties tomcatProperties, WebProperties webProperties) {\n\t\tthis.environment = environment;\n\t\tthis.serverProperties = serverProperties;\n\t\tthis.tomcatProperties = tomcatProperties;\n\t\tthis.webProperties = webProperties;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"removal\")\n\tpublic void customize(ConfigurableTomcatWebServerFactory factory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.tomcatProperties::getBasedir).to(factory::setBaseDirectory);\n\t\tmap.from(this.tomcatProperties::getBackgroundProcessorDelay)\n\t\t\t.as(Duration::getSeconds)\n\t\t\t.as(Long::intValue)\n\t\t\t.to(factory::setBackgroundProcessorDelay);\n\t\tcustomizeRemoteIpValve(factory);\n\t\tTomcatServerProperties.Threads threadProperties = this.tomcatProperties.getThreads();\n\t\tmap.from(threadProperties::getMax)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((maxThreads) -> customizeMaxThreads(factory, maxThreads));\n\t\tmap.from(threadProperties::getMinSpare)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));\n\t\tmap.from(threadProperties::getMaxQueueCapacity)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((maxQueueCapacity) -> customizeMaxQueueCapacity(factory, maxQueueCapacity));\n\t\tmap.from(this.serverProperties.getMaxHttpRequestHeaderSize())\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((maxHttpRequestHeaderSize) -> customizeMaxHttpRequestHeaderSize(factory, maxHttpRequestHeaderSize));\n\t\tmap.from(this.tomcatProperties::getMaxHttpResponseHeaderSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((maxHttpResponseHeaderSize) -> customizeMaxHttpResponseHeaderSize(factory, maxHttpResponseHeaderSize));\n\t\tmap.from(this.tomcatProperties::getMaxSwallowSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));\n\t\tmap.from(this.tomcatProperties::getMaxHttpFormPostSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.when((maxHttpFormPostSize) -> maxHttpFormPostSize != 0)\n\t\t\t.to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize));\n\t\tmap.from(this.tomcatProperties::getMaxParameterCount)\n\t\t\t.to((maxParameterCount) -> customizeMaxParameterCount(factory, maxParameterCount));\n\t\tmap.from(this.tomcatProperties::getMaxPartHeaderSize)\n\t\t\t.asInt(DataSize::toBytes)\n\t\t\t.to((maxPartHeaderSize) -> customizeMaxPartHeaderSize(factory, maxPartHeaderSize));\n\t\tmap.from(this.tomcatProperties::getMaxPartCount)\n\t\t\t.to((maxPartCount) -> customizeMaxPartCount(factory, maxPartCount));\n\t\tmap.from(this.tomcatProperties::getAccesslog)\n\t\t\t.when(TomcatServerProperties.Accesslog::isEnabled)\n\t\t\t.to((enabled) -> customizeAccessLog(factory));\n\t\tmap.from(this.tomcatProperties::getUriEncoding).to(factory::setUriEncoding);\n\t\tmap.from(this.tomcatProperties::getConnectionTimeout)\n\t\t\t.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));\n\t\tmap.from(this.tomcatProperties::getMaxConnections)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));\n\t\tmap.from(this.tomcatProperties::getAcceptCount)\n\t\t\t.when(this::isPositive)\n\t\t\t.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));\n\t\tmap.from(this.tomcatProperties::getProcessorCache)\n\t\t\t.to((processorCache) -> customizeProcessorCache(factory, processorCache));\n\t\tmap.from(this.tomcatProperties::getKeepAliveTimeout)\n\t\t\t.to((keepAliveTimeout) -> customizeKeepAliveTimeout(factory, keepAliveTimeout));\n\t\tmap.from(this.tomcatProperties::getMaxKeepAliveRequests)\n\t\t\t.to((maxKeepAliveRequests) -> customizeMaxKeepAliveRequests(factory, maxKeepAliveRequests));\n\t\tmap.from(this.tomcatProperties::getRelaxedPathChars)\n\t\t\t.as(this::joinCharacters)\n\t\t\t.whenHasText()\n\t\t\t.to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars));\n\t\tmap.from(this.tomcatProperties::getRelaxedQueryChars)\n\t\t\t.as(this::joinCharacters)\n\t\t\t.whenHasText()\n\t\t\t.to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars));\n\t\tmap.from(this.tomcatProperties.getMbeanregistry()::isEnabled)\n\t\t\t.as((enable) -> !enable)\n\t\t\t.to(factory::setDisableMBeanRegistry);\n\t\tcustomizeStaticResources(factory);\n\t\tcustomizeErrorReportValve(this.webProperties.getError(), factory);\n\t\tfactory.setUseApr(getUseApr(this.tomcatProperties.getUseApr()));\n\t}\n\n\tprivate boolean getUseApr(UseApr useApr) {\n\t\treturn switch (useApr) {\n\t\t\tcase ALWAYS -> {\n\t\t\t\tAssert.state(isAprAvailable(), \"APR has been configured to 'ALWAYS', but it's not available\");\n\t\t\t\tyield true;\n\t\t\t}\n\t\t\tcase WHEN_AVAILABLE -> isAprAvailable();\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\tprivate boolean isAprAvailable() {\n\t\t// At least one instance of AprLifecycleListener has to be created for\n\t\t// isAprAvailable() to work\n\t\tnew AprLifecycleListener();\n\t\treturn AprLifecycleListener.isAprAvailable();\n\t}\n\n\tprivate boolean isPositive(int value) {\n\t\treturn value > 0;\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxThreads(ConfigurableTomcatWebServerFactory factory, int maxThreads) {\n\t\tcustomizeHandler(factory, maxThreads, AbstractProtocol.class, AbstractProtocol::setMaxThreads);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMinThreads(ConfigurableTomcatWebServerFactory factory, int minSpareThreads) {\n\t\tcustomizeHandler(factory, minSpareThreads, AbstractProtocol.class, AbstractProtocol::setMinSpareThreads);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxQueueCapacity(ConfigurableTomcatWebServerFactory factory, int maxQueueCapacity) {\n\t\tcustomizeHandler(factory, maxQueueCapacity, AbstractProtocol.class, AbstractProtocol::setMaxQueueSize);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeAcceptCount(ConfigurableTomcatWebServerFactory factory, int acceptCount) {\n\t\tcustomizeHandler(factory, acceptCount, AbstractProtocol.class, AbstractProtocol::setAcceptCount);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeProcessorCache(ConfigurableTomcatWebServerFactory factory, int processorCache) {\n\t\tcustomizeHandler(factory, processorCache, AbstractProtocol.class, AbstractProtocol::setProcessorCache);\n\t}\n\n\tprivate void customizeKeepAliveTimeout(ConfigurableTomcatWebServerFactory factory, Duration keepAliveTimeout) {\n\t\tfactory.addConnectorCustomizers((connector) -> {\n\t\t\tProtocolHandler handler = connector.getProtocolHandler();\n\t\t\tfor (UpgradeProtocol upgradeProtocol : handler.findUpgradeProtocols()) {\n\t\t\t\tif (upgradeProtocol instanceof Http2Protocol protocol) {\n\t\t\t\t\tprotocol.setKeepAliveTimeout(keepAliveTimeout.toMillis());\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (handler instanceof AbstractProtocol<?> protocol) {\n\t\t\t\tprotocol.setKeepAliveTimeout((int) keepAliveTimeout.toMillis());\n\t\t\t}\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxKeepAliveRequests(ConfigurableTomcatWebServerFactory factory, int maxKeepAliveRequests) {\n\t\tcustomizeHandler(factory, maxKeepAliveRequests, AbstractHttp11Protocol.class,\n\t\t\t\tAbstractHttp11Protocol::setMaxKeepAliveRequests);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) {\n\t\tcustomizeHandler(factory, maxConnections, AbstractProtocol.class, AbstractProtocol::setMaxConnections);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeConnectionTimeout(ConfigurableTomcatWebServerFactory factory, Duration connectionTimeout) {\n\t\tcustomizeHandler(factory, (int) connectionTimeout.toMillis(), AbstractProtocol.class,\n\t\t\t\tAbstractProtocol::setConnectionTimeout);\n\t}\n\n\tprivate void customizeRelaxedPathChars(ConfigurableTomcatWebServerFactory factory, String relaxedChars) {\n\t\tfactory.addConnectorCustomizers((connector) -> connector.setProperty(\"relaxedPathChars\", relaxedChars));\n\t}\n\n\tprivate void customizeRelaxedQueryChars(ConfigurableTomcatWebServerFactory factory, String relaxedChars) {\n\t\tfactory.addConnectorCustomizers((connector) -> connector.setProperty(\"relaxedQueryChars\", relaxedChars));\n\t}\n\n\tprivate String joinCharacters(List<Character> content) {\n\t\treturn content.stream().map(String::valueOf).collect(Collectors.joining());\n\t}\n\n\tprivate void customizeRemoteIpValve(ConfigurableTomcatWebServerFactory factory) {\n\t\tRemoteip remoteIpProperties = this.tomcatProperties.getRemoteip();\n\t\tString protocolHeader = remoteIpProperties.getProtocolHeader();\n\t\tString remoteIpHeader = remoteIpProperties.getRemoteIpHeader();\n\t\t// For back compatibility the valve is also enabled if protocol-header is set\n\t\tif (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader)\n\t\t\t\t|| getOrDeduceUseForwardHeaders()) {\n\t\t\tRemoteIpValve valve = new RemoteIpValve();\n\t\t\tvalve.setProtocolHeader(StringUtils.hasLength(protocolHeader) ? protocolHeader : \"X-Forwarded-Proto\");\n\t\t\tif (StringUtils.hasLength(remoteIpHeader)) {\n\t\t\t\tvalve.setRemoteIpHeader(remoteIpHeader);\n\t\t\t}\n\t\t\tvalve.setTrustedProxies(remoteIpProperties.getTrustedProxies());\n\t\t\t// The internal proxies default to a list of \"safe\" internal IP addresses\n\t\t\tvalve.setInternalProxies(remoteIpProperties.getInternalProxies());\n\t\t\ttry {\n\t\t\t\tvalve.setHostHeader(remoteIpProperties.getHostHeader());\n\t\t\t}\n\t\t\tcatch (NoSuchMethodError ex) {\n\t\t\t\t// Avoid failure with war deployments to Tomcat 8.5 before 8.5.44 and\n\t\t\t\t// Tomcat 9 before 9.0.23\n\t\t\t}\n\t\t\tvalve.setPortHeader(remoteIpProperties.getPortHeader());\n\t\t\tvalve.setProtocolHeaderHttpsValue(remoteIpProperties.getProtocolHeaderHttpsValue());\n\t\t\t// ... so it's safe to add this valve by default.\n\t\t\tfactory.addEngineValves(valve);\n\t\t}\n\t}\n\n\tprivate boolean getOrDeduceUseForwardHeaders() {\n\t\tif (this.serverProperties.getForwardHeadersStrategy() == null) {\n\t\t\tCloudPlatform platform = CloudPlatform.getActive(this.environment);\n\t\t\treturn platform != null && platform.isUsingForwardHeaders();\n\t\t}\n\t\treturn this.serverProperties.getForwardHeadersStrategy() == ServerProperties.ForwardHeadersStrategy.NATIVE;\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxHttpRequestHeaderSize(ConfigurableTomcatWebServerFactory factory,\n\t\t\tint maxHttpRequestHeaderSize) {\n\t\tcustomizeHandler(factory, maxHttpRequestHeaderSize, AbstractHttp11Protocol.class,\n\t\t\t\tAbstractHttp11Protocol::setMaxHttpRequestHeaderSize);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxHttpResponseHeaderSize(ConfigurableTomcatWebServerFactory factory,\n\t\t\tint maxHttpResponseHeaderSize) {\n\t\tcustomizeHandler(factory, maxHttpResponseHeaderSize, AbstractHttp11Protocol.class,\n\t\t\t\tAbstractHttp11Protocol::setMaxHttpResponseHeaderSize);\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate void customizeMaxSwallowSize(ConfigurableTomcatWebServerFactory factory, int maxSwallowSize) {\n\t\tcustomizeHandler(factory, maxSwallowSize, AbstractHttp11Protocol.class,\n\t\t\t\tAbstractHttp11Protocol::setMaxSwallowSize);\n\t}\n\n\tprivate <T extends ProtocolHandler> void customizeHandler(ConfigurableTomcatWebServerFactory factory, int value,\n\t\t\tClass<T> type, ObjIntConsumer<T> consumer) {\n\t\tfactory.addConnectorCustomizers((connector) -> {\n\t\t\tProtocolHandler handler = connector.getProtocolHandler();\n\t\t\tif (type.isAssignableFrom(handler.getClass())) {\n\t\t\t\tconsumer.accept(type.cast(handler), value);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void customizeMaxHttpFormPostSize(ConfigurableTomcatWebServerFactory factory, int maxHttpFormPostSize) {\n\t\tfactory.addConnectorCustomizers((connector) -> connector.setMaxPostSize(maxHttpFormPostSize));\n\t}\n\n\tprivate void customizeMaxParameterCount(ConfigurableTomcatWebServerFactory factory, int maxParameterCount) {\n\t\tfactory.addConnectorCustomizers((connector) -> connector.setMaxParameterCount(maxParameterCount));\n\t}\n\n\tprivate void customizeMaxPartCount(ConfigurableTomcatWebServerFactory factory, int maxPartCount) {\n\t\tfactory.addConnectorCustomizers((connector) -> {\n\t\t\ttry {\n\t\t\t\tconnector.setMaxPartCount(maxPartCount);\n\t\t\t}\n\t\t\tcatch (NoSuchMethodError ex) {\n\t\t\t\t// Tomcat < 10.1.42\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void customizeMaxPartHeaderSize(ConfigurableTomcatWebServerFactory factory, int maxPartHeaderSize) {\n\t\tfactory.addConnectorCustomizers((connector) -> {\n\t\t\ttry {\n\t\t\t\tconnector.setMaxPartHeaderSize(maxPartHeaderSize);\n\t\t\t}\n\t\t\tcatch (NoSuchMethodError ex) {\n\t\t\t\t// Tomcat < 10.1.42\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void customizeAccessLog(ConfigurableTomcatWebServerFactory factory) {\n\t\tAccessLogValve valve = new AccessLogValve();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tAccesslog accessLogConfig = this.tomcatProperties.getAccesslog();\n\t\tmap.from(accessLogConfig.getConditionIf()).to(valve::setConditionIf);\n\t\tmap.from(accessLogConfig.getConditionUnless()).to(valve::setConditionUnless);\n\t\tmap.from(accessLogConfig.getPattern()).to(valve::setPattern);\n\t\tmap.from(accessLogConfig.getDirectory()).to(valve::setDirectory);\n\t\tmap.from(accessLogConfig.getPrefix()).to(valve::setPrefix);\n\t\tmap.from(accessLogConfig.getSuffix()).to(valve::setSuffix);\n\t\tmap.from(accessLogConfig.getEncoding()).whenHasText().to(valve::setEncoding);\n\t\tmap.from(accessLogConfig.getLocale()).whenHasText().to(valve::setLocale);\n\t\tmap.from(accessLogConfig.isCheckExists()).to(valve::setCheckExists);\n\t\tmap.from(accessLogConfig.isRotate()).to(valve::setRotatable);\n\t\tmap.from(accessLogConfig.isRenameOnRotate()).to(valve::setRenameOnRotate);\n\t\tmap.from(accessLogConfig.getMaxDays()).to(valve::setMaxDays);\n\t\tmap.from(accessLogConfig.getFileDateFormat()).to(valve::setFileDateFormat);\n\t\tmap.from(accessLogConfig.isIpv6Canonical()).to(valve::setIpv6Canonical);\n\t\tmap.from(accessLogConfig.isRequestAttributesEnabled()).to(valve::setRequestAttributesEnabled);\n\t\tmap.from(accessLogConfig.isBuffered()).to(valve::setBuffered);\n\t\tfactory.addEngineValves(valve);\n\t}\n\n\tprivate void customizeStaticResources(ConfigurableTomcatWebServerFactory factory) {\n\t\tTomcatServerProperties.Resource resource = this.tomcatProperties.getResource();\n\t\tfactory.addContextCustomizers((context) -> context.addLifecycleListener((event) -> {\n\t\t\tif (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {\n\t\t\t\tcontext.getResources().setCachingAllowed(resource.isAllowCaching());\n\t\t\t\tcontext.getResources().setCacheMaxSize(resource.getCacheMaxSize().toKilobytes());\n\t\t\t\tcontext.getResources().setCacheTtl(resource.getCacheTtl().toMillis());\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate void customizeErrorReportValve(ErrorProperties error, ConfigurableTomcatWebServerFactory factory) {\n\t\tif (error.getIncludeStacktrace() == IncludeAttribute.NEVER) {\n\t\t\tfactory.addContextCustomizers((context) -> {\n\t\t\t\tErrorReportValve valve = new ErrorReportValve();\n\t\t\t\tvalve.setShowServerInfo(false);\n\t\t\t\tvalve.setShowReport(false);\n\t\t\t\tcontext.getParent().getPipeline().addValve(valve);\n\t\t\t});\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/WebSocketTomcatWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport org.apache.tomcat.websocket.server.WsSci;\n\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\n\n/**\n * {@link WebServerFactoryCustomizer} that configures Tomcat's WebSocket support.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class WebSocketTomcatWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory> {\n\n\t@Override\n\tpublic void customize(ConfigurableTomcatWebServerFactory factory) {\n\t\tfactory.addContextCustomizers((context) -> context.addServletContainerInitializer(new WsSci(), null));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatAccessLogCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport java.util.Collection;\nimport java.util.function.Function;\n\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.valves.AccessLogValve;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.web.server.AccessLogCustomizer;\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\n\n/**\n * {@link AccessLogCustomizer} for Tomcat.\n *\n * @param <T> the type of factory that can be customized\n * @author Andy Wilkinson\n */\nclass TomcatAccessLogCustomizer<T extends ConfigurableTomcatWebServerFactory> extends AccessLogCustomizer<T> {\n\n\tprivate final Function<T, Collection<Valve>> engineValvesExtractor;\n\n\tTomcatAccessLogCustomizer(TomcatManagementServerProperties properties,\n\t\t\tFunction<T, Collection<Valve>> engineValvesExtractor) {\n\t\tsuper(properties.getAccesslog().getPrefix());\n\t\tthis.engineValvesExtractor = engineValvesExtractor;\n\t}\n\n\t@Override\n\tpublic void customize(T factory) {\n\t\tAccessLogValve accessLogValve = findAccessLogValve(factory);\n\t\tif (accessLogValve == null) {\n\t\t\treturn;\n\t\t}\n\t\taccessLogValve.setPrefix(customizePrefix(accessLogValve.getPrefix()));\n\t}\n\n\tprivate @Nullable AccessLogValve findAccessLogValve(T factory) {\n\t\tfor (Valve engineValve : this.engineValvesExtractor.apply(factory)) {\n\t\t\tif (engineValve instanceof AccessLogValve accessLogValve) {\n\t\t\t\treturn accessLogValve;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatManagementServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties for a Tomcat-based management server.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.server.tomcat\")\npublic class TomcatManagementServerProperties {\n\n\tprivate final Accesslog accesslog = new Accesslog();\n\n\tpublic Accesslog getAccesslog() {\n\t\treturn this.accesslog;\n\t}\n\n\tpublic static class Accesslog {\n\n\t\t/**\n\t\t * Management log file name prefix.\n\t\t */\n\t\tprivate String prefix = \"management_\";\n\n\t\tpublic String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic void setPrefix(String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatReactiveManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.apache.catalina.startup.Tomcat;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Tomcat-based\n * reactive web endpoint infrastructure when a separate management context running on a\n * different port is required.\n *\n * @author Andy Wilkinson\n */\n@ConditionalOnClass(Tomcat.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(TomcatManagementServerProperties.class)\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\nclass TomcatReactiveManagementChildContextConfiguration {\n\n\t@Bean\n\tTomcatAccessLogCustomizer<TomcatReactiveWebServerFactory> tomcatManagementAccessLogCustomizer(\n\t\t\tTomcatManagementServerProperties properties) {\n\t\treturn new TomcatAccessLogCustomizer<>(properties, TomcatReactiveWebServerFactory::getEngineValves);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatReactiveManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.apache.catalina.startup.Tomcat;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatWebServerConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.reactive.TomcatReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for a Tomcat-based reactive management context.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ Tomcat.class, ManagementContextFactory.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\npublic final class TomcatReactiveManagementContextAutoConfiguration {\n\n\t@Bean\n\tstatic ManagementContextFactory reactiveWebChildContextFactory() {\n\t\treturn new ManagementContextFactory(WebApplicationType.REACTIVE, ReactiveWebServerFactory.class,\n\t\t\t\tTomcatReactiveWebServerAutoConfiguration.class, TomcatWebServerConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatServletManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.apache.catalina.startup.Tomcat;\n\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Tomcat-based\n * servlet web endpoint infrastructure when a separate management context running on a\n * different port is required.\n *\n * @author Andy Wilkinson\n */\n@ConditionalOnClass(Tomcat.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(TomcatManagementServerProperties.class)\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\nclass TomcatServletManagementChildContextConfiguration {\n\n\t@Bean\n\tTomcatAccessLogCustomizer<TomcatServletWebServerFactory> tomcatManagementAccessLogCustomizer(\n\t\t\tTomcatManagementServerProperties properties) {\n\t\treturn new TomcatAccessLogCustomizer<>(properties, TomcatServletWebServerFactory::getEngineValves);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatServletManagementContextAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatWebServerConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Auto-configuration for a Tomcat-based servlet management context.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(ManagementContextFactory.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\npublic final class TomcatServletManagementContextAutoConfiguration {\n\n\t@Bean\n\tstatic ManagementContextFactory servletWebChildContextFactory() {\n\t\treturn new ManagementContextFactory(WebApplicationType.SERVLET, ServletWebServerFactory.class,\n\t\t\t\tTomcatWebServerConfiguration.class, TomcatServletWebServerAutoConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Tomcat actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/metrics/TomcatMetricsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;\nimport org.apache.catalina.Manager;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.tomcat.metrics.TomcatMetricsBinder;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link TomcatMetrics}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafterName = \"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\")\n@ConditionalOnWebApplication\n@ConditionalOnClass({ TomcatMetrics.class, Manager.class, MeterRegistry.class })\npublic final class TomcatMetricsAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnBean(MeterRegistry.class)\n\t@ConditionalOnMissingBean({ TomcatMetrics.class, TomcatMetricsBinder.class })\n\tTomcatMetricsBinder tomcatMetricsBinder(MeterRegistry meterRegistry) {\n\t\treturn new TomcatMetricsBinder(meterRegistry);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Tomcat metrics.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.autoconfigure.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a servlet or reactive web server using\n * Tomcat.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/reactive/TomcatReactiveWebServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.reactive;\n\nimport org.apache.catalina.startup.Tomcat;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatProtocolHandlerCustomizer;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatWebServerConfiguration;\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.web.server.autoconfigure.reactive.ReactiveWebServerConfiguration;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.ReactiveHttpInputMessage;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Tomcat-based reactive web\n * server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ReactiveHttpInputMessage.class, Tomcat.class, TomcatReactiveWebServerFactory.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(TomcatServerProperties.class)\n@Import({ TomcatWebServerConfiguration.class, ReactiveWebServerConfiguration.class })\npublic final class TomcatReactiveWebServerAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ReactiveWebServerFactory.class)\n\tTomcatReactiveWebServerFactory tomcatReactiveWebServerFactory(\n\t\t\tObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,\n\t\t\tObjectProvider<TomcatContextCustomizer> contextCustomizers,\n\t\t\tObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {\n\t\tTomcatReactiveWebServerFactory factory = new TomcatReactiveWebServerFactory();\n\t\tfactory.getConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList());\n\t\tfactory.getContextCustomizers().addAll(contextCustomizers.orderedStream().toList());\n\t\tfactory.getProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList());\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a reactive web server using Tomcat.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/servlet/TomcatServletWebServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.servlet;\n\nimport jakarta.servlet.ServletRequest;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.coyote.UpgradeProtocol;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatProtocolHandlerCustomizer;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatWebServerConfiguration;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.autoconfigure.servlet.ForwardedHeaderFilterCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.servlet.ServletWebServerConfiguration;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for a Tomcat-based servlet web\n * server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ ServletRequest.class, Tomcat.class, UpgradeProtocol.class, TomcatServletWebServerFactory.class })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(TomcatServerProperties.class)\n@Import({ ServletWebServerConfiguration.class, TomcatWebServerConfiguration.class })\npublic final class TomcatServletWebServerAutoConfiguration {\n\n\tprivate final TomcatServerProperties tomcatProperties;\n\n\tTomcatServletWebServerAutoConfiguration(TomcatServerProperties tomcatProperties) {\n\t\tthis.tomcatProperties = tomcatProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)\n\tTomcatServletWebServerFactory tomcatServletWebServerFactory(\n\t\t\tObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,\n\t\t\tObjectProvider<TomcatContextCustomizer> contextCustomizers,\n\t\t\tObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();\n\t\tfactory.getConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList());\n\t\tfactory.getContextCustomizers().addAll(contextCustomizers.orderedStream().toList());\n\t\tfactory.getProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList());\n\t\treturn factory;\n\t}\n\n\t@Bean\n\tTomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(\n\t\t\tTomcatServerProperties tomcatProperties) {\n\t\treturn new TomcatServletWebServerFactoryCustomizer(tomcatProperties);\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"server.forward-headers-strategy\", havingValue = \"framework\")\n\tForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {\n\t\treturn (filter) -> filter.setRelativeRedirects(this.tomcatProperties.isUseRelativeRedirects());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/servlet/TomcatServletWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.servlet;\n\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link WebServerFactoryCustomizer} to apply {@link TomcatServerProperties} to Tomcat\n * web servers.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass TomcatServletWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {\n\n\tprivate final TomcatServerProperties tomcatProperties;\n\n\tTomcatServletWebServerFactoryCustomizer(TomcatServerProperties tomcatProperties) {\n\t\tthis.tomcatProperties = tomcatProperties;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void customize(TomcatServletWebServerFactory factory) {\n\t\tif (!ObjectUtils.isEmpty(this.tomcatProperties.getAdditionalTldSkipPatterns())) {\n\t\t\tfactory.getTldSkipPatterns().addAll(this.tomcatProperties.getAdditionalTldSkipPatterns());\n\t\t}\n\t\tif (this.tomcatProperties.getRedirectContextRoot() != null) {\n\t\t\tcustomizeRedirectContextRoot(factory, this.tomcatProperties.getRedirectContextRoot());\n\t\t}\n\t\tcustomizeUseRelativeRedirects(factory, this.tomcatProperties.isUseRelativeRedirects());\n\t}\n\n\tprivate void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory, boolean redirectContextRoot) {\n\t\tfactory.addContextCustomizers((context) -> context.setMapperContextRootRedirectEnabled(redirectContextRoot));\n\t}\n\n\tprivate void customizeUseRelativeRedirects(ConfigurableTomcatWebServerFactory factory,\n\t\t\tboolean useRelativeRedirects) {\n\t\tfactory.addContextCustomizers((context) -> context.setUseRelativeRedirects(useRelativeRedirects));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a servlet web server using Tomcat.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/metrics/TomcatMetricsBinder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.metrics;\n\nimport java.util.Collections;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.Tag;\nimport io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Manager;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\n\n/**\n * Binds {@link TomcatMetrics} in response to the {@link ApplicationStartedEvent}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class TomcatMetricsBinder implements ApplicationListener<ApplicationStartedEvent>, DisposableBean {\n\n\tprivate final MeterRegistry meterRegistry;\n\n\tprivate final Iterable<Tag> tags;\n\n\tprivate volatile @Nullable TomcatMetrics tomcatMetrics;\n\n\tpublic TomcatMetricsBinder(MeterRegistry meterRegistry) {\n\t\tthis(meterRegistry, Collections.emptyList());\n\t}\n\n\tpublic TomcatMetricsBinder(MeterRegistry meterRegistry, Iterable<Tag> tags) {\n\t\tthis.meterRegistry = meterRegistry;\n\t\tthis.tags = tags;\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationStartedEvent event) {\n\t\tApplicationContext applicationContext = event.getApplicationContext();\n\t\tManager manager = findManager(applicationContext);\n\t\tTomcatMetrics tomcatMetrics = new TomcatMetrics(manager, this.tags);\n\t\ttomcatMetrics.bindTo(this.meterRegistry);\n\t\tthis.tomcatMetrics = tomcatMetrics;\n\t}\n\n\tprivate @Nullable Manager findManager(ApplicationContext applicationContext) {\n\t\tif (applicationContext instanceof WebServerApplicationContext webServerApplicationContext) {\n\t\t\tWebServer webServer = webServerApplicationContext.getWebServer();\n\t\t\tif (webServer instanceof TomcatWebServer tomcatWebServer) {\n\t\t\t\tContext context = findContext(tomcatWebServer);\n\t\t\t\tif (context != null) {\n\t\t\t\t\treturn context.getManager();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable Context findContext(TomcatWebServer tomcatWebServer) {\n\t\tfor (Container container : tomcatWebServer.getTomcat().getHost().findChildren()) {\n\t\t\tif (container instanceof Context context) {\n\t\t\t\treturn context;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t\tTomcatMetrics tomcatMetrics = this.tomcatMetrics;\n\t\tif (tomcatMetrics != null) {\n\t\t\ttomcatMetrics.close();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/metrics/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Tomcat metrics.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.metrics;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive and servlet web server implementations backed by Tomcat.\n *\n * @see org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory\n * @see org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory\n */\n@NullMarked\npackage org.springframework.boot.tomcat;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/reactive/TomcatReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.reactive;\n\nimport java.nio.file.Path;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Host;\nimport org.apache.catalina.WebResourceRoot;\nimport org.apache.catalina.loader.WebappLoader;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.catalina.webresources.StandardRoot;\nimport org.apache.tomcat.util.scan.StandardJarScanFilter;\n\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\nimport org.springframework.boot.tomcat.DisableReferenceClearingContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatEmbeddedContext;\nimport org.springframework.boot.tomcat.TomcatEmbeddedWebappClassLoader;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.TomcatWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.TomcatHttpHandlerAdapter;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ReactiveWebServerFactory} that can be used to create a {@link TomcatWebServer}.\n *\n * @author Brian Clozel\n * @author HaiTao Zhang\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class TomcatReactiveWebServerFactory extends TomcatWebServerFactory\n\t\timplements ConfigurableTomcatWebServerFactory, ConfigurableReactiveWebServerFactory {\n\n\t/**\n\t * Create a new {@link TomcatReactiveWebServerFactory} instance.\n\t */\n\tpublic TomcatReactiveWebServerFactory() {\n\t}\n\n\t/**\n\t * Create a new {@link TomcatReactiveWebServerFactory} that listens for requests using\n\t * the specified port.\n\t * @param port the port to listen on\n\t */\n\tpublic TomcatReactiveWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\t@Override\n\tpublic WebServer getWebServer(HttpHandler httpHandler) {\n\t\tTempDirs tempDirs = new TempDirs(getPort());\n\t\tTomcat tomcat = createTomcat(tempDirs);\n\t\tTomcatHttpHandlerAdapter servlet = new TomcatHttpHandlerAdapter(httpHandler);\n\t\tprepareContext(tomcat.getHost(), servlet, tempDirs);\n\t\treturn getTomcatWebServer(tomcat);\n\t}\n\n\t/**\n\t * Prepares the context.\n\t * @param host the host\n\t * @param servlet the servlet adapter\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #prepareContext(Host, TomcatHttpHandlerAdapter, TempDirs)}\n\t */\n\t@Deprecated(forRemoval = true, since = \"4.1.0\")\n\tprotected void prepareContext(Host host, TomcatHttpHandlerAdapter servlet) {\n\t\tprepareContext(host, servlet, new TempDirs(getPort()));\n\t}\n\n\t/**\n\t * Prepares the context.\n\t * @param host the host\n\t * @param servlet the servlet adapter\n\t * @param tempDirs to manage temporary directories\n\t * @since 4.1.0\n\t */\n\tprotected void prepareContext(Host host, TomcatHttpHandlerAdapter servlet, TempDirs tempDirs) {\n\t\tPath docBase = tempDirs.createTempDir(\"tomcat-docbase\");\n\t\tTomcatEmbeddedContext context = new TomcatEmbeddedContext();\n\t\tWebResourceRoot resourceRoot = new StandardRoot(context);\n\t\tignoringNoSuchMethodError(() -> resourceRoot.setReadOnly(true));\n\t\tcontext.setResources(resourceRoot);\n\t\tcontext.setPath(\"\");\n\t\tcontext.setDocBase(docBase.toAbsolutePath().toString());\n\t\tcontext.addLifecycleListener(new Tomcat.FixContextListener());\n\t\tClassLoader parentClassLoader = ClassUtils.getDefaultClassLoader();\n\t\tcontext.setParentClassLoader(parentClassLoader);\n\t\tskipAllTldScanning(context);\n\t\tWebappLoader loader = new WebappLoader();\n\t\tloader.setLoaderInstance(new TomcatEmbeddedWebappClassLoader(parentClassLoader));\n\t\tloader.setDelegate(true);\n\t\tcontext.setLoader(loader);\n\t\tTomcat.addServlet(context, \"httpHandlerServlet\", servlet).setAsyncSupported(true);\n\t\tcontext.addServletMappingDecoded(\"/\", \"httpHandlerServlet\");\n\t\thost.addChild(context);\n\t\tconfigureContext(context);\n\t}\n\n\tprivate void ignoringNoSuchMethodError(Runnable method) {\n\t\ttry {\n\t\t\tmethod.run();\n\t\t}\n\t\tcatch (NoSuchMethodError ex) {\n\t\t}\n\t}\n\n\tprivate void skipAllTldScanning(TomcatEmbeddedContext context) {\n\t\tStandardJarScanFilter filter = new StandardJarScanFilter();\n\t\tfilter.setTldSkip(\"*.jar\");\n\t\tcontext.getJarScanner().setJarScanFilter(filter);\n\t}\n\n\t/**\n\t * Configure the Tomcat {@link Context}.\n\t * @param context the Tomcat context\n\t */\n\tprotected void configureContext(Context context) {\n\t\tthis.getContextLifecycleListeners().forEach(context::addLifecycleListener);\n\t\tnew DisableReferenceClearingContextCustomizer().customize(context);\n\t\tthis.getContextCustomizers().forEach((customizer) -> customizer.customize(context));\n\t}\n\n\t/**\n\t * Factory method called to create the {@link TomcatWebServer}. Subclasses can\n\t * override this method to return a different {@link TomcatWebServer} or apply\n\t * additional processing to the Tomcat server.\n\t * @param tomcat the Tomcat server.\n\t * @return a new {@link TomcatWebServer} instance\n\t */\n\tprotected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {\n\t\treturn new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive web server implementation backed by Tomcat.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/DeferredServletContainerInitializers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport java.util.Set;\n\nimport jakarta.servlet.ServletContainerInitializer;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.tomcat.TomcatEmbeddedContext;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\n\n/**\n * {@link ServletContainerInitializer} used to trigger {@link ServletContextInitializer\n * ServletContextInitializers} and track startup errors.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass DeferredServletContainerInitializers\n\t\timplements ServletContainerInitializer, TomcatEmbeddedContext.DeferredStartupExceptions {\n\n\tprivate static final Log logger = LogFactory.getLog(DeferredServletContainerInitializers.class);\n\n\tprivate final Iterable<ServletContextInitializer> initializers;\n\n\tprivate volatile @Nullable Exception startUpException;\n\n\tDeferredServletContainerInitializers(Iterable<ServletContextInitializer> initializers) {\n\t\tthis.initializers = initializers;\n\t}\n\n\t@Override\n\tpublic void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException {\n\t\ttry {\n\t\t\tfor (ServletContextInitializer initializer : this.initializers) {\n\t\t\t\tinitializer.onStartup(servletContext);\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthis.startUpException = ex;\n\t\t\t// Prevent Tomcat from logging and re-throwing when we know we can\n\t\t\t// deal with it in the main thread, but log for information here.\n\t\t\tif (logger.isErrorEnabled()) {\n\t\t\t\tlogger.error(\"Error starting Tomcat context. Exception: \" + ex.getClass().getName() + \". Message: \"\n\t\t\t\t\t\t+ ex.getMessage());\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tpublic void rethrow() throws Exception {\n\t\tif (this.startUpException != null) {\n\t\t\tthrow this.startUpException;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/NestedJarResourceSet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport java.io.IOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.jar.Attributes;\nimport java.util.jar.Attributes.Name;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\n\nimport org.apache.catalina.LifecycleException;\nimport org.apache.catalina.WebResource;\nimport org.apache.catalina.WebResourceRoot;\nimport org.apache.catalina.WebResourceSet;\nimport org.apache.catalina.webresources.AbstractSingleArchiveResourceSet;\nimport org.apache.catalina.webresources.JarResource;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ResourceUtils;\n\n/**\n * A {@link WebResourceSet} for a resource in a nested JAR.\n *\n * @author Phillip Webb\n */\nclass NestedJarResourceSet extends AbstractSingleArchiveResourceSet {\n\n\tprivate static final Name MULTI_RELEASE = new Name(\"Multi-Release\");\n\n\tprivate final URL url;\n\n\tprivate @Nullable JarFile archive;\n\n\tprivate long archiveUseCount;\n\n\tprivate boolean useCaches;\n\n\tprivate volatile @Nullable Boolean multiRelease;\n\n\tNestedJarResourceSet(URL url, WebResourceRoot root, String webAppMount, String internalPath)\n\t\t\tthrows IllegalArgumentException {\n\t\tthis.url = url;\n\t\tsetRoot(root);\n\t\tsetWebAppMount(webAppMount);\n\t\tsetInternalPath(internalPath);\n\t\tsetStaticOnly(true);\n\t\tif (getRoot().getState().isAvailable()) {\n\t\t\ttry {\n\t\t\t\tstart();\n\t\t\t}\n\t\t\tcatch (LifecycleException ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tprotected WebResource createArchiveResource(JarEntry jarEntry, String webAppPath, Manifest manifest) {\n\t\treturn new JarResource(this, webAppPath, getBaseUrlString(), jarEntry);\n\t}\n\n\t@Override\n\tprotected void initInternal() throws LifecycleException {\n\t\ttry {\n\t\t\tJarURLConnection connection = connect();\n\t\t\ttry {\n\t\t\t\tsetManifest(connection.getManifest());\n\t\t\t\tsetBaseUrl(connection.getJarFileURL());\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tif (!connection.getUseCaches()) {\n\t\t\t\t\tconnection.getJarFile().close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected JarFile openJarFile() throws IOException {\n\t\tsynchronized (this.archiveLock) {\n\t\t\tif (this.archive == null) {\n\t\t\t\tJarURLConnection connection = connect();\n\t\t\t\tthis.useCaches = connection.getUseCaches();\n\t\t\t\tthis.archive = connection.getJarFile();\n\t\t\t}\n\t\t\tthis.archiveUseCount++;\n\t\t\treturn this.archive;\n\t\t}\n\t}\n\n\t@Override\n\tprotected void closeJarFile() {\n\t\tsynchronized (this.archiveLock) {\n\t\t\tthis.archiveUseCount--;\n\t\t}\n\t}\n\n\t@Override\n\tprotected boolean isMultiRelease() {\n\t\tBoolean multiRelease = this.multiRelease;\n\t\tif (multiRelease == null) {\n\t\t\tsynchronized (this.archiveLock) {\n\t\t\t\tmultiRelease = this.multiRelease;\n\t\t\t\tif (multiRelease == null) {\n\t\t\t\t\t// JarFile.isMultiRelease() is final so we must go to the manifest\n\t\t\t\t\tManifest manifest = getManifest();\n\t\t\t\t\tAttributes attributes = (manifest != null) ? manifest.getMainAttributes() : null;\n\t\t\t\t\tmultiRelease = (attributes != null) && attributes.containsKey(MULTI_RELEASE);\n\t\t\t\t\tthis.multiRelease = multiRelease;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn multiRelease;\n\t}\n\n\t@Override\n\tpublic void gc() {\n\t\tsynchronized (this.archiveLock) {\n\t\t\tif (this.archive != null && this.archiveUseCount == 0) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!this.useCaches) {\n\t\t\t\t\t\tthis.archive.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t\tthis.archive = null;\n\t\t\t\tthis.archiveEntries = null;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate JarURLConnection connect() throws IOException {\n\t\tURLConnection connection = this.url.openConnection();\n\t\tResourceUtils.useCachesIfNecessary(connection);\n\t\tAssert.state(connection instanceof JarURLConnection,\n\t\t\t\t() -> \"URL '%s' did not return a JAR connection\".formatted(this.url));\n\t\tconnection.connect();\n\t\treturn (JarURLConnection) connection;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/TldPatterns.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\n/**\n * TLD skip and scan patterns used by Spring Boot.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nfinal class TldPatterns {\n\n\tstatic final Set<String> TOMCAT_SKIP;\n\n\tstatic {\n\t\t// Same as Tomcat\n\t\tSet<String> skipPatterns = new LinkedHashSet<>();\n\t\tskipPatterns.add(\"annotations-api.jar\");\n\t\tskipPatterns.add(\"ant-junit*.jar\");\n\t\tskipPatterns.add(\"ant-launcher*.jar\");\n\t\tskipPatterns.add(\"ant*.jar\");\n\t\tskipPatterns.add(\"asm-*.jar\");\n\t\tskipPatterns.add(\"aspectj*.jar\");\n\t\tskipPatterns.add(\"bcel*.jar\");\n\t\tskipPatterns.add(\"biz.aQute.bnd*.jar\");\n\t\tskipPatterns.add(\"bootstrap.jar\");\n\t\tskipPatterns.add(\"catalina-ant.jar\");\n\t\tskipPatterns.add(\"catalina-ha.jar\");\n\t\tskipPatterns.add(\"catalina-ssi.jar\");\n\t\tskipPatterns.add(\"catalina-storeconfig.jar\");\n\t\tskipPatterns.add(\"catalina-tribes.jar\");\n\t\tskipPatterns.add(\"catalina.jar\");\n\t\tskipPatterns.add(\"cglib-*.jar\");\n\t\tskipPatterns.add(\"cobertura-*.jar\");\n\t\tskipPatterns.add(\"commons-beanutils*.jar\");\n\t\tskipPatterns.add(\"commons-codec*.jar\");\n\t\tskipPatterns.add(\"commons-collections*.jar\");\n\t\tskipPatterns.add(\"commons-compress*.jar\");\n\t\tskipPatterns.add(\"commons-daemon.jar\");\n\t\tskipPatterns.add(\"commons-dbcp*.jar\");\n\t\tskipPatterns.add(\"commons-digester*.jar\");\n\t\tskipPatterns.add(\"commons-fileupload*.jar\");\n\t\tskipPatterns.add(\"commons-httpclient*.jar\");\n\t\tskipPatterns.add(\"commons-io*.jar\");\n\t\tskipPatterns.add(\"commons-lang*.jar\");\n\t\tskipPatterns.add(\"commons-logging*.jar\");\n\t\tskipPatterns.add(\"commons-math*.jar\");\n\t\tskipPatterns.add(\"commons-pool*.jar\");\n\t\tskipPatterns.add(\"derby-*.jar\");\n\t\tskipPatterns.add(\"dom4j-*.jar\");\n\t\tskipPatterns.add(\"easymock-*.jar\");\n\t\tskipPatterns.add(\"ecj-*.jar\");\n\t\tskipPatterns.add(\"el-api.jar\");\n\t\tskipPatterns.add(\"geronimo-spec-jaxrpc*.jar\");\n\t\tskipPatterns.add(\"h2*.jar\");\n\t\tskipPatterns.add(\"ha-api-*.jar\");\n\t\tskipPatterns.add(\"hamcrest-*.jar\");\n\t\tskipPatterns.add(\"hibernate*.jar\");\n\t\tskipPatterns.add(\"httpclient*.jar\");\n\t\tskipPatterns.add(\"icu4j-*.jar\");\n\t\tskipPatterns.add(\"jakartaee-migration-*.jar\");\n\t\tskipPatterns.add(\"jasper-el.jar\");\n\t\tskipPatterns.add(\"jasper.jar\");\n\t\tskipPatterns.add(\"jaspic-api.jar\");\n\t\tskipPatterns.add(\"jaxb-*.jar\");\n\t\tskipPatterns.add(\"jaxen-*.jar\");\n\t\tskipPatterns.add(\"jaxws-rt-*.jar\");\n\t\tskipPatterns.add(\"jdom-*.jar\");\n\t\tskipPatterns.add(\"jetty-*.jar\");\n\t\tskipPatterns.add(\"jmx-tools.jar\");\n\t\tskipPatterns.add(\"jmx.jar\");\n\t\tskipPatterns.add(\"jsp-api.jar\");\n\t\tskipPatterns.add(\"jstl.jar\");\n\t\tskipPatterns.add(\"jta*.jar\");\n\t\tskipPatterns.add(\"junit-*.jar\");\n\t\tskipPatterns.add(\"junit.jar\");\n\t\tskipPatterns.add(\"log4j*.jar\");\n\t\tskipPatterns.add(\"mail*.jar\");\n\t\tskipPatterns.add(\"objenesis-*.jar\");\n\t\tskipPatterns.add(\"oraclepki.jar\");\n\t\tskipPatterns.add(\"org.hamcrest.core_*.jar\");\n\t\tskipPatterns.add(\"org.junit_*.jar\");\n\t\tskipPatterns.add(\"oro-*.jar\");\n\t\tskipPatterns.add(\"servlet-api-*.jar\");\n\t\tskipPatterns.add(\"servlet-api.jar\");\n\t\tskipPatterns.add(\"slf4j*.jar\");\n\t\tskipPatterns.add(\"taglibs-standard-spec-*.jar\");\n\t\tskipPatterns.add(\"tagsoup-*.jar\");\n\t\tskipPatterns.add(\"tomcat-api.jar\");\n\t\tskipPatterns.add(\"tomcat-coyote.jar\");\n\t\tskipPatterns.add(\"tomcat-coyote-ffm.jar\");\n\t\tskipPatterns.add(\"tomcat-dbcp.jar\");\n\t\tskipPatterns.add(\"tomcat-i18n-*.jar\");\n\t\tskipPatterns.add(\"tomcat-jdbc.jar\");\n\t\tskipPatterns.add(\"tomcat-jni.jar\");\n\t\tskipPatterns.add(\"tomcat-juli-adapters.jar\");\n\t\tskipPatterns.add(\"tomcat-juli.jar\");\n\t\tskipPatterns.add(\"tomcat-util-scan.jar\");\n\t\tskipPatterns.add(\"tomcat-util.jar\");\n\t\tskipPatterns.add(\"tomcat-websocket.jar\");\n\t\tskipPatterns.add(\"tools.jar\");\n\t\tskipPatterns.add(\"unboundid-ldapsdk-*.jar\");\n\t\tskipPatterns.add(\"websocket-api.jar\");\n\t\tskipPatterns.add(\"websocket-client-api.jar\");\n\t\tskipPatterns.add(\"wsdl4j*.jar\");\n\t\tskipPatterns.add(\"xercesImpl.jar\");\n\t\tskipPatterns.add(\"xml-apis.jar\");\n\t\tskipPatterns.add(\"xmlParserAPIs-*.jar\");\n\t\tskipPatterns.add(\"xmlParserAPIs.jar\");\n\t\tskipPatterns.add(\"xom-*.jar\");\n\t\tTOMCAT_SKIP = Collections.unmodifiableSet(skipPatterns);\n\t}\n\n\tprivate static final Set<String> ADDITIONAL_SKIP;\n\n\tstatic {\n\t\t// Additional typical for Spring Boot applications\n\t\tSet<String> skipPatterns = new LinkedHashSet<>();\n\t\tskipPatterns.add(\"antlr-*.jar\");\n\t\tskipPatterns.add(\"aopalliance-*.jar\");\n\t\tskipPatterns.add(\"aspectjweaver-*.jar\");\n\t\tskipPatterns.add(\"classmate-*.jar\");\n\t\tskipPatterns.add(\"ehcache-core-*.jar\");\n\t\tskipPatterns.add(\"hsqldb-*.jar\");\n\t\tskipPatterns.add(\"jackson-annotations-*.jar\");\n\t\tskipPatterns.add(\"jackson-core-*.jar\");\n\t\tskipPatterns.add(\"jackson-databind-*.jar\");\n\t\tskipPatterns.add(\"jandex-*.jar\");\n\t\tskipPatterns.add(\"javassist-*.jar\");\n\t\tskipPatterns.add(\"jboss-logging-*.jar\");\n\t\tskipPatterns.add(\"jboss-transaction-api_*.jar\");\n\t\tskipPatterns.add(\"jcl-over-slf4j-*.jar\");\n\t\tskipPatterns.add(\"jdom-*.jar\");\n\t\tskipPatterns.add(\"jul-to-slf4j-*.jar\");\n\t\tskipPatterns.add(\"logback-classic-*.jar\");\n\t\tskipPatterns.add(\"logback-core-*.jar\");\n\t\tskipPatterns.add(\"rome-*.jar\");\n\t\tskipPatterns.add(\"spring-aop-*.jar\");\n\t\tskipPatterns.add(\"spring-aspects-*.jar\");\n\t\tskipPatterns.add(\"spring-beans-*.jar\");\n\t\tskipPatterns.add(\"spring-boot-*.jar\");\n\t\tskipPatterns.add(\"spring-core-*.jar\");\n\t\tskipPatterns.add(\"spring-context-*.jar\");\n\t\tskipPatterns.add(\"spring-data-*.jar\");\n\t\tskipPatterns.add(\"spring-expression-*.jar\");\n\t\tskipPatterns.add(\"spring-jdbc-*.jar,\");\n\t\tskipPatterns.add(\"spring-orm-*.jar\");\n\t\tskipPatterns.add(\"spring-oxm-*.jar\");\n\t\tskipPatterns.add(\"spring-tx-*.jar\");\n\t\tskipPatterns.add(\"snakeyaml-*.jar\");\n\t\tskipPatterns.add(\"tomcat-embed-core-*.jar\");\n\t\tskipPatterns.add(\"tomcat-embed-logging-*.jar\");\n\t\tskipPatterns.add(\"tomcat-embed-el-*.jar\");\n\t\tskipPatterns.add(\"validation-api-*.jar\");\n\t\tADDITIONAL_SKIP = Collections.unmodifiableSet(skipPatterns);\n\t}\n\n\tstatic final Set<String> DEFAULT_SKIP;\n\n\tstatic {\n\t\tSet<String> skipPatterns = new LinkedHashSet<>();\n\t\tskipPatterns.addAll(TOMCAT_SKIP);\n\t\tskipPatterns.addAll(ADDITIONAL_SKIP);\n\t\tDEFAULT_SKIP = Collections.unmodifiableSet(skipPatterns);\n\t}\n\n\tstatic final Set<String> TOMCAT_SCAN;\n\n\tstatic {\n\t\tSet<String> scanPatterns = new LinkedHashSet<>();\n\t\tscanPatterns.add(\"log4j-taglib*.jar\");\n\t\tscanPatterns.add(\"log4j-jakarta-web*.jar\");\n\t\tscanPatterns.add(\"log4javascript*.jar\");\n\t\tscanPatterns.add(\"slf4j-taglib*.jar\");\n\t\tTOMCAT_SCAN = Collections.unmodifiableSet(scanPatterns);\n\t}\n\n\tstatic final Set<String> DEFAULT_SCAN;\n\n\tstatic {\n\t\tSet<String> scanPatterns = new LinkedHashSet<>(TOMCAT_SCAN);\n\t\tDEFAULT_SCAN = Collections.unmodifiableSet(scanPatterns);\n\t}\n\n\tprivate TldPatterns() {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/TomcatServletWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.lang.reflect.Method;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport jakarta.servlet.ServletContainerInitializer;\nimport jakarta.servlet.http.Cookie;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Host;\nimport org.apache.catalina.Lifecycle;\nimport org.apache.catalina.LifecycleEvent;\nimport org.apache.catalina.LifecycleException;\nimport org.apache.catalina.LifecycleListener;\nimport org.apache.catalina.Manager;\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.WebResource;\nimport org.apache.catalina.WebResourceRoot;\nimport org.apache.catalina.WebResourceRoot.ResourceSetType;\nimport org.apache.catalina.WebResourceSet;\nimport org.apache.catalina.Wrapper;\nimport org.apache.catalina.loader.WebappLoader;\nimport org.apache.catalina.session.StandardManager;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.catalina.startup.Tomcat.FixContextListener;\nimport org.apache.catalina.util.LifecycleBase;\nimport org.apache.catalina.util.SessionConfig;\nimport org.apache.catalina.webresources.AbstractResourceSet;\nimport org.apache.catalina.webresources.EmptyResource;\nimport org.apache.catalina.webresources.StandardRoot;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.tomcat.util.http.Rfc6265CookieProcessor;\nimport org.apache.tomcat.util.scan.StandardJarScanFilter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.tomcat.ConfigurableTomcatWebServerFactory;\nimport org.springframework.boot.tomcat.DisableReferenceClearingContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatEmbeddedContext;\nimport org.springframework.boot.tomcat.TomcatEmbeddedWebappClassLoader;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.TomcatWebServerFactory;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.server.Cookie.SameSite;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ContextPath;\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;\nimport org.springframework.boot.web.server.servlet.DocumentRoot;\nimport org.springframework.boot.web.server.servlet.ServletContextInitializers;\nimport org.springframework.boot.web.server.servlet.ServletWebServerSettings;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ConfigurableServletWebServerFactory} that can be used to create\n * {@link TomcatWebServer}s. Can be initialized using Spring's\n * {@link ServletContextInitializer}s or Tomcat {@link LifecycleListener}s.\n * <p>\n * Unless explicitly configured otherwise this factory will create containers that listen\n * for HTTP requests on port 8080.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Brock Mills\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Eddú Meléndez\n * @author Christoffer Sawicki\n * @author Dawid Antecki\n * @author Moritz Halbritter\n * @author Scott Frederick\n * @since 4.0.0\n * @see #setPort(int)\n * @see #setContextLifecycleListeners(Collection)\n * @see TomcatWebServer\n */\npublic class TomcatServletWebServerFactory extends TomcatWebServerFactory\n\t\timplements ConfigurableTomcatWebServerFactory, ConfigurableServletWebServerFactory, ResourceLoaderAware {\n\n\tprivate static final Log logger = LogFactory.getLog(TomcatServletWebServerFactory.class);\n\n\tprivate static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;\n\n\tprivate static final Set<Class<?>> NO_CLASSES = Collections.emptySet();\n\n\tprivate final ServletWebServerSettings settings = new ServletWebServerSettings();\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ResourceLoader resourceLoader;\n\n\tprivate Set<String> tldSkipPatterns = new LinkedHashSet<>(TldPatterns.DEFAULT_SKIP);\n\n\tprivate final Set<String> tldScanPatterns = new LinkedHashSet<>(TldPatterns.DEFAULT_SCAN);\n\n\t/**\n\t * Create a new {@link TomcatServletWebServerFactory} instance.\n\t */\n\tpublic TomcatServletWebServerFactory() {\n\t}\n\n\t/**\n\t * Create a new {@link TomcatServletWebServerFactory} that listens for requests using\n\t * the specified port.\n\t * @param port the port to listen on\n\t */\n\tpublic TomcatServletWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n\t/**\n\t * Create a new {@link TomcatServletWebServerFactory} with the specified context path\n\t * and port.\n\t * @param contextPath the root context path\n\t * @param port the port to listen on\n\t */\n\tpublic TomcatServletWebServerFactory(String contextPath, int port) {\n\t\tsuper(port);\n\t\tthis.settings.setContextPath(ContextPath.of(contextPath));\n\t}\n\n\t@Override\n\tpublic WebServer getWebServer(ServletContextInitializer... initializers) {\n\t\tTempDirs tempDirs = new TempDirs(getPort());\n\t\tTomcat tomcat = createTomcat(tempDirs);\n\t\tprepareContext(tomcat.getHost(), initializers, tempDirs);\n\t\treturn getTomcatWebServer(tomcat);\n\t}\n\n\t/**\n\t * Prepares the context.\n\t * @param host the host\n\t * @param initializers the servlet context initializers\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of\n\t * {@link #prepareContext(Host, ServletContextInitializer[], TempDirs)}\n\t */\n\t@Deprecated(forRemoval = true, since = \"4.1.0\")\n\tprotected void prepareContext(Host host, ServletContextInitializer[] initializers) {\n\t\tprepareContext(host, initializers, new TempDirs(getPort()));\n\t}\n\n\t/**\n\t * Prepares the context.\n\t * @param host the host\n\t * @param initializers the servlet context initializers\n\t * @param tempDirs to manage temporary directories\n\t * @since 4.1.0\n\t */\n\tprotected void prepareContext(Host host, ServletContextInitializer[] initializers, TempDirs tempDirs) {\n\t\tDocumentRoot documentRoot = new DocumentRoot(logger);\n\t\tdocumentRoot.setDirectory(this.settings.getDocumentRoot());\n\t\tFile documentRootFile = documentRoot.getValidDirectory();\n\t\tTomcatEmbeddedContext context = new TomcatEmbeddedContext();\n\t\tWebResourceRoot resourceRoot = (documentRootFile != null) ? new LoaderHidingResourceRoot(context)\n\t\t\t\t: new StandardRoot(context);\n\t\tignoringNoSuchMethodError(() -> resourceRoot.setReadOnly(true));\n\t\tcontext.setResources(resourceRoot);\n\t\tString contextPath = this.settings.getContextPath().toString();\n\t\tcontext.setName(contextPath);\n\t\tcontext.setDisplayName(this.settings.getDisplayName());\n\t\tcontext.setPath(contextPath);\n\t\tFile docBase = (documentRootFile != null) ? documentRootFile\n\t\t\t\t: tempDirs.createTempDir(\"tomcat-docbase\").toFile();\n\t\tcontext.setDocBase(docBase.getAbsolutePath());\n\t\tcontext.addLifecycleListener(new FixContextListener());\n\t\tClassLoader parentClassLoader = (this.resourceLoader != null) ? this.resourceLoader.getClassLoader()\n\t\t\t\t: ClassUtils.getDefaultClassLoader();\n\t\tcontext.setParentClassLoader(parentClassLoader);\n\t\tresetDefaultLocaleMapping(context);\n\t\taddLocaleMappings(context);\n\t\tcontext.setCreateUploadTargets(true);\n\t\tconfigureTldPatterns(context);\n\t\tWebappLoader loader = new WebappLoader();\n\t\tloader.setLoaderInstance(new TomcatEmbeddedWebappClassLoader(parentClassLoader));\n\t\tloader.setDelegate(true);\n\t\tcontext.setLoader(loader);\n\t\tif (this.settings.isRegisterDefaultServlet()) {\n\t\t\taddDefaultServlet(context);\n\t\t}\n\t\tif (shouldRegisterJspServlet()) {\n\t\t\taddJspServlet(context);\n\t\t\taddJasperInitializer(context);\n\t\t}\n\t\tcontext.addLifecycleListener(new StaticResourceConfigurer(context));\n\t\tServletContextInitializers initializersToUse = ServletContextInitializers.from(this.settings, initializers);\n\t\thost.addChild(context);\n\t\tconfigureContext(context, initializersToUse);\n\t\tpostProcessContext(context);\n\t}\n\n\tprivate void ignoringNoSuchMethodError(Runnable method) {\n\t\ttry {\n\t\t\tmethod.run();\n\t\t}\n\t\tcatch (NoSuchMethodError ex) {\n\t\t\t// Intentionally left blank\n\t\t}\n\t}\n\n\tprivate boolean shouldRegisterJspServlet() {\n\t\treturn this.settings.getJsp() != null && this.settings.getJsp().getRegistered()\n\t\t\t\t&& ClassUtils.isPresent(this.settings.getJsp().getClassName(), getClass().getClassLoader());\n\t}\n\n\t/**\n\t * Override Tomcat's default locale mappings to align with other servers. See\n\t * {@code org.apache.catalina.util.CharsetMapperDefault.properties}.\n\t * @param context the context to reset\n\t */\n\tprivate void resetDefaultLocaleMapping(TomcatEmbeddedContext context) {\n\t\tcontext.addLocaleEncodingMappingParameter(Locale.ENGLISH.toString(), DEFAULT_CHARSET.displayName());\n\t\tcontext.addLocaleEncodingMappingParameter(Locale.FRENCH.toString(), DEFAULT_CHARSET.displayName());\n\t\tcontext.addLocaleEncodingMappingParameter(Locale.JAPANESE.toString(), DEFAULT_CHARSET.displayName());\n\t}\n\n\tprivate void addLocaleMappings(TomcatEmbeddedContext context) {\n\t\tthis.settings.getLocaleCharsetMappings()\n\t\t\t.forEach((locale, charset) -> context.addLocaleEncodingMappingParameter(locale.toString(),\n\t\t\t\t\tcharset.toString()));\n\t}\n\n\tprivate void configureTldPatterns(TomcatEmbeddedContext context) {\n\t\tStandardJarScanFilter filter = new StandardJarScanFilter();\n\t\tfilter.setTldSkip(StringUtils.collectionToCommaDelimitedString(this.tldSkipPatterns));\n\t\tfilter.setTldScan(StringUtils.collectionToCommaDelimitedString(this.tldScanPatterns));\n\t\tcontext.getJarScanner().setJarScanFilter(filter);\n\t}\n\n\tprivate void addDefaultServlet(Context context) {\n\t\tWrapper defaultServlet = context.createWrapper();\n\t\tdefaultServlet.setName(\"default\");\n\t\tdefaultServlet.setServletClass(\"org.apache.catalina.servlets.DefaultServlet\");\n\t\tdefaultServlet.addInitParameter(\"debug\", \"0\");\n\t\tdefaultServlet.addInitParameter(\"listings\", \"false\");\n\t\tdefaultServlet.setLoadOnStartup(1);\n\t\t// Otherwise the default location of a Spring DispatcherServlet cannot be set\n\t\tdefaultServlet.setOverridable(true);\n\t\tcontext.addChild(defaultServlet);\n\t\tcontext.addServletMappingDecoded(\"/\", \"default\");\n\t}\n\n\tprivate void addJspServlet(Context context) {\n\t\tWrapper jspServlet = context.createWrapper();\n\t\tjspServlet.setName(\"jsp\");\n\t\tjspServlet.setServletClass(this.settings.getJsp().getClassName());\n\t\tjspServlet.addInitParameter(\"fork\", \"false\");\n\t\tthis.settings.getJsp().getInitParameters().forEach(jspServlet::addInitParameter);\n\t\tjspServlet.setLoadOnStartup(3);\n\t\tcontext.addChild(jspServlet);\n\t\tcontext.addServletMappingDecoded(\"*.jsp\", \"jsp\");\n\t\tcontext.addServletMappingDecoded(\"*.jspx\", \"jsp\");\n\t}\n\n\tprivate void addJasperInitializer(TomcatEmbeddedContext context) {\n\t\ttry {\n\t\t\tServletContainerInitializer initializer = (ServletContainerInitializer) ClassUtils\n\t\t\t\t.forName(\"org.apache.jasper.servlet.JasperInitializer\", null)\n\t\t\t\t.getDeclaredConstructor()\n\t\t\t\t.newInstance();\n\t\t\tcontext.addServletContainerInitializer(initializer, null);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Probably not Tomcat 8\n\t\t}\n\t}\n\n\t/**\n\t * Configure the Tomcat {@link Context}.\n\t * @param context the Tomcat context\n\t * @param initializers initializers to apply\n\t */\n\tprotected void configureContext(Context context, Iterable<ServletContextInitializer> initializers) {\n\t\tDeferredServletContainerInitializers deferredInitializers = new DeferredServletContainerInitializers(\n\t\t\t\tinitializers);\n\t\tif (context instanceof TomcatEmbeddedContext embeddedContext) {\n\t\t\tembeddedContext.setDeferredStartupExceptions(deferredInitializers);\n\t\t\tembeddedContext.setFailCtxIfServletStartFails(true);\n\t\t}\n\t\tcontext.addServletContainerInitializer(deferredInitializers, NO_CLASSES);\n\t\tfor (LifecycleListener lifecycleListener : this.getContextLifecycleListeners()) {\n\t\t\tcontext.addLifecycleListener(lifecycleListener);\n\t\t}\n\t\tfor (Valve valve : this.getContextValves()) {\n\t\t\tcontext.getPipeline().addValve(valve);\n\t\t}\n\t\tfor (ErrorPage errorPage : getErrorPages()) {\n\t\t\torg.apache.tomcat.util.descriptor.web.ErrorPage tomcatErrorPage = new org.apache.tomcat.util.descriptor.web.ErrorPage();\n\t\t\ttomcatErrorPage.setLocation(errorPage.getPath());\n\t\t\ttomcatErrorPage.setErrorCode(errorPage.getStatusCode());\n\t\t\ttomcatErrorPage.setExceptionType(errorPage.getExceptionName());\n\t\t\tcontext.addErrorPage(tomcatErrorPage);\n\t\t}\n\t\tsetMimeMappings(context);\n\t\tconfigureSession(context);\n\t\tconfigureCookieProcessor(context);\n\t\tnew DisableReferenceClearingContextCustomizer().customize(context);\n\t\tfor (String webListenerClassName : getSettings().getWebListenerClassNames()) {\n\t\t\tcontext.addApplicationListener(webListenerClassName);\n\t\t}\n\t\tfor (TomcatContextCustomizer customizer : this.getContextCustomizers()) {\n\t\t\tcustomizer.customize(context);\n\t\t}\n\t}\n\n\tprivate void configureSession(Context context) {\n\t\tlong sessionTimeout = getSessionTimeoutInMinutes();\n\t\tcontext.setSessionTimeout((int) sessionTimeout);\n\t\tBoolean httpOnly = this.settings.getSession().getCookie().getHttpOnly();\n\t\tif (httpOnly != null) {\n\t\t\tcontext.setUseHttpOnly(httpOnly);\n\t\t}\n\t\tif (this.settings.getSession().isPersistent()) {\n\t\t\tManager manager = context.getManager();\n\t\t\tif (manager == null) {\n\t\t\t\tmanager = new StandardManager();\n\t\t\t\tcontext.setManager(manager);\n\t\t\t}\n\t\t\tconfigurePersistSession(manager);\n\t\t}\n\t\telse {\n\t\t\tcontext.addLifecycleListener(new DisablePersistSessionListener());\n\t\t}\n\t}\n\n\tprivate void setMimeMappings(Context context) {\n\t\tMimeMappings mimeMappings = this.settings.getMimeMappings();\n\t\tif (context instanceof TomcatEmbeddedContext embeddedContext) {\n\t\t\tembeddedContext.setMimeMappings(mimeMappings);\n\t\t\treturn;\n\t\t}\n\t\tfor (MimeMappings.Mapping mapping : mimeMappings) {\n\t\t\tcontext.addMimeMapping(mapping.getExtension(), mapping.getMimeType());\n\t\t}\n\t}\n\n\tprivate void configureCookieProcessor(Context context) {\n\t\tSameSite sessionSameSite = this.settings.getSession().getCookie().getSameSite();\n\t\tList<CookieSameSiteSupplier> suppliers = new ArrayList<>();\n\t\tif (sessionSameSite != null) {\n\t\t\tsuppliers.add(CookieSameSiteSupplier.of(sessionSameSite)\n\t\t\t\t.whenHasName(() -> SessionConfig.getSessionCookieName(context)));\n\t\t}\n\t\tif (!CollectionUtils.isEmpty(this.settings.getCookieSameSiteSuppliers())) {\n\t\t\tsuppliers.addAll(this.settings.getCookieSameSiteSuppliers());\n\t\t}\n\t\tif (!suppliers.isEmpty()) {\n\t\t\tcontext.setCookieProcessor(new SuppliedSameSiteCookieProcessor(suppliers));\n\t\t}\n\t}\n\n\tprivate void configurePersistSession(Manager manager) {\n\t\tAssert.state(manager instanceof StandardManager,\n\t\t\t\t() -> \"Unable to persist HTTP session state using manager type \" + manager.getClass().getName());\n\t\tFile dir = this.settings.getSession().getSessionStoreDirectory().getValidDirectory(true);\n\t\tFile file = new File(dir, \"SESSIONS.ser\");\n\t\t((StandardManager) manager).setPathname(file.getAbsolutePath());\n\t}\n\n\tprivate long getSessionTimeoutInMinutes() {\n\t\tDuration sessionTimeout = this.settings.getSession().getTimeout();\n\t\tif (isZeroOrLess(sessionTimeout)) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn Math.max(sessionTimeout.toMinutes(), 1);\n\t}\n\n\t@Contract(\"null -> true\")\n\tprivate boolean isZeroOrLess(@Nullable Duration sessionTimeout) {\n\t\treturn sessionTimeout == null || sessionTimeout.isNegative() || sessionTimeout.isZero();\n\t}\n\n\t/**\n\t * Post process the Tomcat {@link Context} before it's used with the Tomcat Server.\n\t * Subclasses can override this method to apply additional processing to the\n\t * {@link Context}.\n\t * @param context the Tomcat {@link Context}\n\t */\n\tprotected void postProcessContext(Context context) {\n\t}\n\n\t/**\n\t * Factory method called to create the {@link TomcatWebServer}. Subclasses can\n\t * override this method to return a different {@link TomcatWebServer} or apply\n\t * additional processing to the Tomcat server.\n\t * @param tomcat the Tomcat server.\n\t * @return a new {@link TomcatWebServer} instance\n\t */\n\tprotected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {\n\t\treturn new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());\n\t}\n\n\t@Override\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\t/**\n\t * Returns a mutable set of the patterns that match jars to ignore for TLD scanning.\n\t * @return the set of jars to ignore for TLD scanning\n\t */\n\tpublic Set<String> getTldSkipPatterns() {\n\t\treturn this.tldSkipPatterns;\n\t}\n\n\t/**\n\t * Set the patterns that match jars to ignore for TLD scanning. See Tomcat's\n\t * catalina.properties for typical values. Defaults to a list drawn from that source.\n\t * @param patterns the jar patterns to skip when scanning for TLDs etc\n\t */\n\tpublic void setTldSkipPatterns(Collection<String> patterns) {\n\t\tAssert.notNull(patterns, \"'patterns' must not be null\");\n\t\tthis.tldSkipPatterns = new LinkedHashSet<>(patterns);\n\t}\n\n\t/**\n\t * Add patterns that match jars to ignore for TLD scanning. See Tomcat's\n\t * catalina.properties for typical values.\n\t * @param patterns the additional jar patterns to skip when scanning for TLDs etc\n\t */\n\tpublic void addTldSkipPatterns(String... patterns) {\n\t\tAssert.notNull(patterns, \"'patterns' must not be null\");\n\t\tthis.tldSkipPatterns.addAll(Arrays.asList(patterns));\n\t}\n\n\t@Override\n\tpublic ServletWebServerSettings getSettings() {\n\t\treturn this.settings;\n\t}\n\n\t/**\n\t * {@link LifecycleListener} to disable persistence in the {@link StandardManager}. A\n\t * {@link LifecycleListener} is used so not to interfere with Tomcat's default manager\n\t * creation logic.\n\t */\n\tprivate static final class DisablePersistSessionListener implements LifecycleListener {\n\n\t\t@Override\n\t\tpublic void lifecycleEvent(LifecycleEvent event) {\n\t\t\tif (event.getType().equals(Lifecycle.START_EVENT)) {\n\t\t\t\tContext context = (Context) event.getLifecycle();\n\t\t\t\tManager manager = context.getManager();\n\t\t\t\tif (manager instanceof StandardManager standardManager) {\n\t\t\t\t\tstandardManager.setPathname(null);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate final class StaticResourceConfigurer implements LifecycleListener {\n\n\t\tprivate static final String WEB_APP_MOUNT = \"/\";\n\n\t\tprivate static final String INTERNAL_PATH = \"/META-INF/resources\";\n\n\t\tprivate final Context context;\n\n\t\tprivate StaticResourceConfigurer(Context context) {\n\t\t\tthis.context = context;\n\t\t}\n\n\t\t@Override\n\t\tpublic void lifecycleEvent(LifecycleEvent event) {\n\t\t\tif (event.getType().equals(Lifecycle.BEFORE_INIT_EVENT)) {\n\t\t\t\taddResourceJars(TomcatServletWebServerFactory.this.getSettings().getStaticResourceUrls());\n\t\t\t}\n\t\t}\n\n\t\tprivate void addResourceJars(List<URL> resourceJarUrls) {\n\t\t\tfor (URL url : resourceJarUrls) {\n\t\t\t\tString path = url.getPath();\n\t\t\t\tif (path.endsWith(\".jar\") || path.endsWith(\".jar!/\")) {\n\t\t\t\t\tString jar = url.toString();\n\t\t\t\t\tif (!jar.startsWith(\"jar:\")) {\n\t\t\t\t\t\t// A jar file in the file system. Convert to Jar URL.\n\t\t\t\t\t\tjar = \"jar:\" + jar + \"!/\";\n\t\t\t\t\t}\n\t\t\t\t\taddResourceSet(jar);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\taddResourceSet(url.toString());\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (WebResourceSet resources : this.context.getResources().getJarResources()) {\n\t\t\t\tresources.setReadOnly(true);\n\t\t\t}\n\t\t}\n\n\t\tprivate void addResourceSet(String resource) {\n\t\t\ttry {\n\t\t\t\tif (isInsideClassicNestedJar(resource)) {\n\t\t\t\t\taddClassicNestedResourceSet(resource);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tWebResourceRoot root = this.context.getResources();\n\t\t\t\tURL url = new URL(resource);\n\t\t\t\tif (isInsideNestedJar(resource)) {\n\t\t\t\t\troot.addJarResources(new NestedJarResourceSet(url, root, WEB_APP_MOUNT, INTERNAL_PATH));\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\troot.createWebResourceSet(ResourceSetType.RESOURCE_JAR, WEB_APP_MOUNT, url, INTERNAL_PATH);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore (probably not a directory)\n\t\t\t}\n\t\t}\n\n\t\tprivate void addClassicNestedResourceSet(String resource) throws MalformedURLException {\n\t\t\t// It's a nested jar but we now don't want the suffix because Tomcat\n\t\t\t// is going to try and locate it as a root URL (not the resource\n\t\t\t// inside it)\n\t\t\tURL url = new URL(resource.substring(0, resource.length() - 2));\n\t\t\tthis.context.getResources()\n\t\t\t\t.createWebResourceSet(ResourceSetType.RESOURCE_JAR, WEB_APP_MOUNT, url, INTERNAL_PATH);\n\t\t}\n\n\t\tprivate boolean isInsideClassicNestedJar(String resource) {\n\t\t\treturn !isInsideNestedJar(resource) && resource.indexOf(\"!/\") < resource.lastIndexOf(\"!/\");\n\t\t}\n\n\t\tprivate boolean isInsideNestedJar(String resource) {\n\t\t\treturn resource.startsWith(\"jar:nested:\");\n\t\t}\n\n\t}\n\n\tprivate static final class LoaderHidingResourceRoot extends StandardRoot {\n\n\t\tprivate LoaderHidingResourceRoot(TomcatEmbeddedContext context) {\n\t\t\tsuper(context);\n\t\t}\n\n\t\t@Override\n\t\tprotected WebResourceSet createMainResourceSet() {\n\t\t\treturn new LoaderHidingWebResourceSet(super.createMainResourceSet());\n\t\t}\n\n\t}\n\n\tprivate static final class LoaderHidingWebResourceSet extends AbstractResourceSet {\n\n\t\tprivate final WebResourceSet delegate;\n\n\t\tprivate final Method initInternal;\n\n\t\tprivate LoaderHidingWebResourceSet(WebResourceSet delegate) {\n\t\t\tthis.delegate = delegate;\n\t\t\ttry {\n\t\t\t\tthis.initInternal = LifecycleBase.class.getDeclaredMethod(\"initInternal\");\n\t\t\t\tthis.initInternal.setAccessible(true);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new IllegalStateException(ex);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic WebResource getResource(String path) {\n\t\t\tif (path.startsWith(\"/org/springframework/boot\")) {\n\t\t\t\treturn new EmptyResource(getRoot(), path);\n\t\t\t}\n\t\t\treturn this.delegate.getResource(path);\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] list(String path) {\n\t\t\treturn this.delegate.list(path);\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> listWebAppPaths(String path) {\n\t\t\treturn this.delegate.listWebAppPaths(path)\n\t\t\t\t.stream()\n\t\t\t\t.filter((webAppPath) -> !webAppPath.startsWith(\"/org/springframework/boot\"))\n\t\t\t\t.collect(Collectors.toSet());\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean mkdir(String path) {\n\t\t\treturn this.delegate.mkdir(path);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean write(String path, InputStream is, boolean overwrite) {\n\t\t\treturn this.delegate.write(path, is, overwrite);\n\t\t}\n\n\t\t@Override\n\t\tpublic URL getBaseUrl() {\n\t\t\treturn this.delegate.getBaseUrl();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setReadOnly(boolean readOnly) {\n\t\t\tthis.delegate.setReadOnly(readOnly);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isReadOnly() {\n\t\t\treturn this.delegate.isReadOnly();\n\t\t}\n\n\t\t@Override\n\t\tpublic void gc() {\n\t\t\tthis.delegate.gc();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setAllowLinking(boolean allowLinking) {\n\t\t\tthis.delegate.setAllowLinking(allowLinking);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean getAllowLinking() {\n\t\t\treturn this.delegate.getAllowLinking();\n\t\t}\n\n\t\t@Override\n\t\tprotected void initInternal() throws LifecycleException {\n\t\t\tif (this.delegate instanceof LifecycleBase) {\n\t\t\t\ttry {\n\t\t\t\t\tReflectionUtils.invokeMethod(this.initInternal, this.delegate);\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\tthrow new LifecycleException(ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link Rfc6265CookieProcessor} that supports {@link CookieSameSiteSupplier\n\t * supplied} {@link SameSite} values.\n\t */\n\tprivate static class SuppliedSameSiteCookieProcessor extends Rfc6265CookieProcessor {\n\n\t\tprivate final List<CookieSameSiteSupplier> suppliers;\n\n\t\tSuppliedSameSiteCookieProcessor(List<CookieSameSiteSupplier> suppliers) {\n\t\t\tthis.suppliers = suppliers;\n\t\t}\n\n\t\t@Override\n\t\tpublic String generateHeader(Cookie cookie, HttpServletRequest request) {\n\t\t\tSameSite sameSite = getSameSite(cookie);\n\t\t\tString sameSiteValue = (sameSite != null) ? sameSite.attributeValue() : null;\n\t\t\tif (sameSiteValue == null) {\n\t\t\t\treturn super.generateHeader(cookie, request);\n\t\t\t}\n\t\t\tRfc6265CookieProcessor delegate = new Rfc6265CookieProcessor();\n\t\t\tdelegate.setSameSiteCookies(sameSiteValue);\n\t\t\treturn delegate.generateHeader(cookie, request);\n\t\t}\n\n\t\tprivate @Nullable SameSite getSameSite(Cookie cookie) {\n\t\t\tfor (CookieSameSiteSupplier supplier : this.suppliers) {\n\t\t\t\tSameSite sameSite = supplier.getSameSite(cookie);\n\t\t\t\tif (sameSite != null) {\n\t\t\t\t\treturn sameSite;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/java/org/springframework/boot/tomcat/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Servlet web server implementation backed by Tomcat.\n */\n@NullMarked\npackage org.springframework.boot.tomcat.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"server.tomcat.max-http-post-size\",\n      \"type\": \"org.springframework.util.unit.DataSize\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.tomcat.max-http-form-post-size\",\n        \"since\": \"2.3.0\"\n      }\n    },\n    {\n      \"name\": \"server.tomcat.reject-illegal-header\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.7.12\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"server.tomcat.accesslog.encoding\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.nio.charset.Charset\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"server.tomcat.accesslog.locale\",\n      \"providers\": [\n        {\n          \"name\": \"handle-as\",\n          \"parameters\": {\n            \"target\": \"java.util.Locale\"\n          }\n        }\n      ]\n    },\n    {\n      \"name\": \"server.tomcat.relaxed-path-chars\",\n      \"values\": [\n        {\n          \"value\": \"<\"\n        },\n        {\n          \"value\": \">\"\n        },\n        {\n          \"value\": \"[\"\n        },\n        {\n          \"value\": \"\\\\\"\n        },\n        {\n          \"value\": \"]\"\n        },\n        {\n          \"value\": \"^\"\n        },\n        {\n          \"value\": \"`\"\n        },\n        {\n          \"value\": \"{\"\n        },\n        {\n          \"value\": \"|\"\n        },\n        {\n          \"value\": \"}\"\n        }\n      ]\n    },\n    {\n      \"name\": \"server.tomcat.relaxed-query-chars\",\n      \"values\": [\n        {\n          \"value\": \"<\"\n        },\n        {\n          \"value\": \">\"\n        },\n        {\n          \"value\": \"[\"\n        },\n        {\n          \"value\": \"\\\\\"\n        },\n        {\n          \"value\": \"]\"\n        },\n        {\n          \"value\": \"^\"\n        },\n        {\n          \"value\": \"`\"\n        },\n        {\n          \"value\": \"{\"\n        },\n        {\n          \"value\": \"|\"\n        },\n        {\n          \"value\": \"}\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatReactiveManagementChildContextConfiguration\norg.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementChildContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatReactiveManagementContextAutoConfiguration\norg.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementContextAutoConfiguration\norg.springframework.boot.tomcat.autoconfigure.metrics.TomcatMetricsAutoConfiguration\norg.springframework.boot.tomcat.autoconfigure.reactive.TomcatReactiveWebServerAutoConfiguration\norg.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/resources/META-INF/spring/org.springframework.boot.web.server.test.AutoConfigureWebServer.imports",
    "content": "org.springframework.boot.tomcat.autoconfigure.reactive.TomcatReactiveWebServerAutoConfiguration\norg.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/main/resources/META-INF/spring.factories",
    "content": "# Background Preinitializers\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer=\\\norg.springframework.boot.tomcat.autoconfigure.TomcatBackgroundPreinitializer\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.tomcat.ConnectorStartFailureAnalyzer\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/CompressionConnectorCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport org.apache.catalina.connector.Connector;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.apache.coyote.http2.Http2Protocol;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompressionConnectorCustomizer}\n *\n * @author Rudy Adams\n */\nclass CompressionConnectorCustomizerTests {\n\n\tprivate static final int MIN_SIZE = 100;\n\n\tprivate final String[] mimeTypes = { \"text/html\", \"text/xml\", \"text/xhtml\" };\n\n\tprivate final String[] excludedUserAgents = { \"SomeUserAgent\", \"AnotherUserAgent\" };\n\n\tprivate Compression compression;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.compression = new Compression();\n\t\tthis.compression.setEnabled(true);\n\t\tthis.compression.setMinResponseSize(DataSize.ofBytes(MIN_SIZE));\n\t\tthis.compression.setMimeTypes(this.mimeTypes);\n\t\tthis.compression.setExcludedUserAgents(this.excludedUserAgents);\n\t}\n\n\t@Test\n\tvoid shouldCustomizeCompression() {\n\t\tCompressionConnectorCustomizer compressionConnectorCustomizer = new CompressionConnectorCustomizer(\n\t\t\t\tthis.compression);\n\t\tConnector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n\t\tHttp2Protocol upgradeProtocol = new Http2Protocol();\n\t\tupgradeProtocol.setHttp11Protocol((AbstractHttp11Protocol<?>) connector.getProtocolHandler());\n\t\tconnector.addUpgradeProtocol(upgradeProtocol);\n\t\tcompressionConnectorCustomizer.customize(connector);\n\t\tAbstractHttp11Protocol<?> abstractHttp11Protocol = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();\n\t\tcompressionOn(abstractHttp11Protocol.getCompression());\n\t\tminSize(abstractHttp11Protocol.getCompressionMinSize());\n\t\tmimeType(abstractHttp11Protocol.getCompressibleMimeTypes());\n\t\texcludedUserAgents(abstractHttp11Protocol.getNoCompressionUserAgents());\n\t}\n\n\tprivate void compressionOn(String compression) {\n\t\tassertThat(compression).isEqualTo(\"on\");\n\t}\n\n\tprivate void minSize(int minSize) {\n\t\tassertThat(minSize).isEqualTo(MIN_SIZE);\n\t}\n\n\tprivate void mimeType(String[] mimeTypes) {\n\t\tassertThat(mimeTypes).isEqualTo(this.mimeTypes);\n\t}\n\n\tprivate void excludedUserAgents(String combinedUserAgents) {\n\t\tassertThat(combinedUserAgents).isEqualTo(\"SomeUserAgent,AnotherUserAgent\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/SslConnectorCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.util.Collections;\n\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.apache.tomcat.util.net.SSLHostConfig;\nimport org.apache.tomcat.util.net.openssl.ciphers.Cipher;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11Security;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11SecurityProvider;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServerSslBundle;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link SslConnectorCustomizer}\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n * @author Scott Frederick\n * @author Cyril Dangerville\n */\n@ExtendWith(OutputCaptureExtension.class)\n@DirtiesUrlFactories\n@MockPkcs11Security\nclass SslConnectorCustomizerTests {\n\n\tprivate final Log logger = LogFactory.getLog(SslConnectorCustomizerTests.class);\n\n\tprivate Tomcat tomcat;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.tomcat = new Tomcat();\n\t\tConnector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n\t\tconnector.setPort(0);\n\t\tthis.tomcat.setConnector(connector);\n\t}\n\n\t@AfterEach\n\tvoid stop() throws Exception {\n\t\tSystem.clearProperty(\"javax.net.ssl.trustStorePassword\");\n\t\tthis.tomcat.stop();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid tls12CiphersConfiguration() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setCiphers(new String[] { \"ALPHA\", \"BRAVO\", \"CHARLIE\" });\n\t\tConnector connector = this.tomcat.getConnector();\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());\n\t\tcustomizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());\n\t\tthis.tomcat.start();\n\t\tSSLHostConfig[] sslHostConfigs = connector.getProtocolHandler().findSslHostConfigs();\n\t\tassertThat(sslHostConfigs[0].getCiphers()).isEqualTo(\"ALPHA:BRAVO:CHARLIE\");\n\t\tassertThat(sslHostConfigs[0].getCipherSuites()).isEmpty();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid tls13CiphersConfiguration() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setCiphers(new String[] { Cipher.TLS_AES_128_CCM_SHA256.getOpenSSLAlias(),\n\t\t\t\tCipher.TLS_AES_256_GCM_SHA384.getOpenSSLAlias() });\n\t\tConnector connector = this.tomcat.getConnector();\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());\n\t\tcustomizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());\n\t\tthis.tomcat.start();\n\t\tSSLHostConfig[] sslHostConfigs = connector.getProtocolHandler().findSslHostConfigs();\n\t\tassertThat(sslHostConfigs[0].getCiphers()).isEmpty();\n\t\tassertThat(sslHostConfigs[0].getCipherSuites()).isEqualTo(\"TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid mixedTls12AndTls13CiphersConfiguration() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setCiphers(new String[] { Cipher.TLS_AES_128_CCM_SHA256.getOpenSSLAlias(),\n\t\t\t\tCipher.TLS_DH_DSS_WITH_AES_128_CBC_SHA256.getOpenSSLAlias(),\n\t\t\t\tCipher.TLS_AES_256_GCM_SHA384.getOpenSSLAlias() });\n\t\tConnector connector = this.tomcat.getConnector();\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());\n\t\tcustomizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());\n\t\tthis.tomcat.start();\n\t\tSSLHostConfig[] sslHostConfigs = connector.getProtocolHandler().findSslHostConfigs();\n\t\tassertThat(sslHostConfigs[0].getCiphers()).isEqualTo(\"DH-DSS-AES128-SHA256\");\n\t\tassertThat(sslHostConfigs[0].getCipherSuites()).isEqualTo(\"TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslEnabledMultipleProtocolsConfiguration() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setEnabledProtocols(new String[] { \"TLSv1.1\", \"TLSv1.2\" });\n\t\tssl.setCiphers(new String[] { \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", \"BRAVO\" });\n\t\tConnector connector = this.tomcat.getConnector();\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());\n\t\tcustomizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());\n\t\tthis.tomcat.start();\n\t\tSSLHostConfig sslHostConfig = connector.getProtocolHandler().findSslHostConfigs()[0];\n\t\tassertThat(sslHostConfig.getSslProtocol()).isEqualTo(\"TLS\");\n\t\tassertThat(sslHostConfig.getEnabledProtocols()).containsExactlyInAnyOrder(\"TLSv1.1\", \"TLSv1.2\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslEnabledProtocolsConfiguration() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setEnabledProtocols(new String[] { \"TLSv1.2\" });\n\t\tssl.setCiphers(new String[] { \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", \"BRAVO\" });\n\t\tConnector connector = this.tomcat.getConnector();\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());\n\t\tcustomizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());\n\t\tthis.tomcat.start();\n\t\tSSLHostConfig sslHostConfig = connector.getProtocolHandler().findSslHostConfigs()[0];\n\t\tassertThat(sslHostConfig.getSslProtocol()).isEqualTo(\"TLS\");\n\t\tassertThat(sslHostConfig.getEnabledProtocols()).containsExactly(\"TLSv1.2\");\n\t}\n\n\t@Test\n\tvoid customizeWhenSslIsEnabledWithNoKeyStoreAndNotPkcs11ThrowsException() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, this.tomcat.getConnector(),\n\t\t\t\t\tSsl.ClientAuth.NONE);\n\t\t\tcustomizer.customize(WebServerSslBundle.get(new Ssl()), Collections.emptyMap());\n\t\t}).withMessageContaining(\"SSL is enabled but no trust material is configured\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid customizeWhenSslIsEnabledWithPkcs11AndKeyStoreThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStoreType(\"PKCS11\");\n\t\tssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, this.tomcat.getConnector(),\n\t\t\t\t\tssl.getClientAuth());\n\t\t\tcustomizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());\n\t\t}).withMessageContaining(\"must be empty or null for PKCS11 hardware key stores\");\n\t}\n\n\t@Test\n\tvoid customizeWhenSslIsEnabledWithPkcs11AndKeyStoreProvider() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStoreType(\"PKCS11\");\n\t\tssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setKeyStorePassword(\"1234\");\n\t\tSslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, this.tomcat.getConnector(),\n\t\t\t\tssl.getClientAuth());\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> customizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/TomcatAccess.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.util.Map;\n\nimport org.apache.catalina.Service;\nimport org.apache.catalina.connector.Connector;\n\n/**\n * Helper class to provide public access to package-private methods for testing purposes.\n *\n * @author Andy Wilkinson\n */\npublic final class TomcatAccess {\n\n\tprivate TomcatAccess() {\n\n\t}\n\n\tpublic static Map<Service, Connector[]> getServiceConnectors(TomcatWebServer tomcatWebServer) {\n\t\treturn tomcatWebServer.getServiceConnectors();\n\t}\n\n\tpublic static String getStartedLogMessage(TomcatWebServer tomcatWebServer) {\n\t\treturn tomcatWebServer.getStartedLogMessage();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/TomcatEmbeddedWebappClassLoaderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.jar.JarOutputStream;\nimport java.util.zip.ZipEntry;\n\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.loader.ParallelWebappClassLoader;\nimport org.apache.catalina.webresources.StandardRoot;\nimport org.apache.catalina.webresources.WarResourceSet;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.util.CollectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TomcatEmbeddedWebappClassLoader}.\n *\n * @author Andy Wilkinson\n */\nclass TomcatEmbeddedWebappClassLoaderTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid getResourceFindsResourceFromParentClassLoader() throws Exception {\n\t\tFile war = createWar();\n\t\twithWebappClassLoader(war, (classLoader) -> assertThat(classLoader.getResource(\"test.txt\"))\n\t\t\t.isEqualTo(new URL(webInfClassesUrlString(war) + \"test.txt\")));\n\t}\n\n\t@Test\n\tvoid getResourcesOnlyFindsResourcesFromParentClassLoader() throws Exception {\n\t\tFile warFile = createWar();\n\t\twithWebappClassLoader(warFile, (classLoader) -> {\n\t\t\tList<URL> urls = new ArrayList<>();\n\t\t\tCollectionUtils.toIterator(classLoader.getResources(\"test.txt\")).forEachRemaining(urls::add);\n\t\t\tassertThat(urls).containsExactly(new URL(webInfClassesUrlString(warFile) + \"test.txt\"));\n\t\t});\n\t}\n\n\tprivate void withWebappClassLoader(File war, ClassLoaderConsumer consumer) throws Exception {\n\t\tURLClassLoader parent = new URLClassLoader(new URL[] { new URL(webInfClassesUrlString(war)) }, null);\n\t\ttry (ParallelWebappClassLoader classLoader = new TomcatEmbeddedWebappClassLoader(parent)) {\n\t\t\tStandardContext context = new StandardContext();\n\t\t\tcontext.setName(\"test\");\n\t\t\tStandardRoot resources = new StandardRoot();\n\t\t\tresources.setContext(context);\n\t\t\tresources.addJarResources(new WarResourceSet(resources, \"/\", war.getAbsolutePath()));\n\t\t\tresources.start();\n\t\t\tclassLoader.setResources(resources);\n\t\t\tclassLoader.start();\n\t\t\ttry {\n\t\t\t\tconsumer.accept(classLoader);\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tclassLoader.stop();\n\t\t\t\tclassLoader.close();\n\t\t\t\tresources.stop();\n\t\t\t}\n\t\t}\n\t\tparent.close();\n\t}\n\n\tprivate String webInfClassesUrlString(File war) {\n\t\treturn \"jar:file:\" + war.getAbsolutePath() + \"!/WEB-INF/classes/\";\n\t}\n\n\tprivate File createWar() throws IOException {\n\t\tFile warFile = new File(this.tempDir, \"test.war\");\n\t\ttry (JarOutputStream warOut = new JarOutputStream(new FileOutputStream(warFile))) {\n\t\t\tcreateEntries(warOut, \"WEB-INF/\", \"WEB-INF/classes/\", \"WEB-INF/classes/test.txt\");\n\t\t}\n\t\treturn warFile;\n\t}\n\n\tprivate void createEntries(JarOutputStream out, String... names) throws IOException {\n\t\tfor (String name : names) {\n\t\t\tout.putNextEntry(new ZipEntry(name));\n\t\t\tout.closeEntry();\n\t\t}\n\t}\n\n\tinterface ClassLoaderConsumer {\n\n\t\tvoid accept(ClassLoader classLoader) throws Exception;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/AutoConfigureWebServerTomcatReactiveTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.autoconfigure.AutoConfigureWebServerTomcatReactiveTests.ReactiveConfiguration;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureWebServer @AutoConfigureWebServer} with Tomcat.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(classes = ReactiveConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.main.web-application-type=reactive\")\n@AutoConfigureWebServer\nclass AutoConfigureWebServerTomcatReactiveTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid startsTestServer() {\n\t\tRestTestClient restClient = RestTestClient.bindToServer().baseUrl(\"http://localhost:\" + this.port).build();\n\t\tassertThat(RestTestClientResponse.from(restClient.get().exchange())).bodyText().isEqualTo(\"hello\");\n\t}\n\n\t@Configuration\n\tstatic class ReactiveConfiguration {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn (request, response) -> {\n\t\t\t\tresponse.setStatusCode(HttpStatus.OK);\n\t\t\t\tDataBuffer dataBuffer = new DefaultDataBufferFactory().wrap(\"hello\".getBytes(StandardCharsets.UTF_8));\n\t\t\t\treturn response.writeWith(Mono.just(dataBuffer));\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/AutoConfigureWebServerTomcatServletTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.autoconfigure.AutoConfigureWebServerTomcatServletTests.ServletConfiguration;\nimport org.springframework.boot.web.server.test.AutoConfigureWebServer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AutoConfigureWebServer @AutoConfigureWebServer} with Tomcat.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(classes = ServletConfiguration.class, webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebServer\nclass AutoConfigureWebServerTomcatServletTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid startsTestServer() {\n\t\tRestTestClient restClient = RestTestClient.bindToServer().baseUrl(\"http://localhost:\" + this.port).build();\n\t\tassertThat(RestTestClientResponse.from(restClient.get().exchange())).bodyText().isEqualTo(\"hello\");\n\t}\n\n\t@Configuration\n\tstatic class ServletConfiguration {\n\n\t\t@Bean\n\t\tServlet servlet() {\n\t\t\treturn new GenericServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void service(ServletRequest request, ServletResponse response)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t\tresponse.getWriter().append(\"hello\").flush();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/TomcatServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.core.StandardEngine;\nimport org.apache.catalina.valves.AccessLogValve;\nimport org.apache.catalina.valves.RemoteIpValve;\nimport org.apache.coyote.AbstractProtocol;\nimport org.apache.tomcat.util.net.AbstractEndpoint;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.tomcat.TomcatWebServerFactory;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties.Accesslog;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties.UseApr;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TomcatServerProperties}.\n *\n * @author Andy Wilkinson\n */\nclass TomcatServerPropertiesTests {\n\n\tprivate final TomcatServerProperties properties = new TomcatServerProperties();\n\n\t@Test\n\tvoid testTomcatBinding() {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"server.tomcat.accesslog.conditionIf\", \"foo\");\n\t\tmap.put(\"server.tomcat.accesslog.conditionUnless\", \"bar\");\n\t\tmap.put(\"server.tomcat.accesslog.pattern\", \"%h %t '%r' %s %b\");\n\t\tmap.put(\"server.tomcat.accesslog.prefix\", \"foo\");\n\t\tmap.put(\"server.tomcat.accesslog.suffix\", \"-bar.log\");\n\t\tmap.put(\"server.tomcat.accesslog.encoding\", \"UTF-8\");\n\t\tmap.put(\"server.tomcat.accesslog.locale\", \"en-AU\");\n\t\tmap.put(\"server.tomcat.accesslog.checkExists\", \"true\");\n\t\tmap.put(\"server.tomcat.accesslog.rotate\", \"false\");\n\t\tmap.put(\"server.tomcat.accesslog.rename-on-rotate\", \"true\");\n\t\tmap.put(\"server.tomcat.accesslog.ipv6Canonical\", \"true\");\n\t\tmap.put(\"server.tomcat.accesslog.request-attributes-enabled\", \"true\");\n\t\tmap.put(\"server.tomcat.remoteip.protocol-header\", \"X-Forwarded-Protocol\");\n\t\tmap.put(\"server.tomcat.remoteip.remote-ip-header\", \"Remote-Ip\");\n\t\tmap.put(\"server.tomcat.remoteip.internal-proxies\", \"10\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\");\n\t\tmap.put(\"server.tomcat.remoteip.trusted-proxies\", \"proxy1|proxy2|proxy3\");\n\t\tmap.put(\"server.tomcat.reject-illegal-header\", \"false\");\n\t\tmap.put(\"server.tomcat.background-processor-delay\", \"10\");\n\t\tmap.put(\"server.tomcat.relaxed-path-chars\", \"|,<\");\n\t\tmap.put(\"server.tomcat.relaxed-query-chars\", \"^  ,  | \");\n\t\tmap.put(\"server.tomcat.use-relative-redirects\", \"true\");\n\t\tbind(map);\n\t\tAccesslog accesslog = this.properties.getAccesslog();\n\t\tassertThat(accesslog.getConditionIf()).isEqualTo(\"foo\");\n\t\tassertThat(accesslog.getConditionUnless()).isEqualTo(\"bar\");\n\t\tassertThat(accesslog.getPattern()).isEqualTo(\"%h %t '%r' %s %b\");\n\t\tassertThat(accesslog.getPrefix()).isEqualTo(\"foo\");\n\t\tassertThat(accesslog.getSuffix()).isEqualTo(\"-bar.log\");\n\t\tassertThat(accesslog.getEncoding()).isEqualTo(\"UTF-8\");\n\t\tassertThat(accesslog.getLocale()).isEqualTo(\"en-AU\");\n\t\tassertThat(accesslog.isCheckExists()).isTrue();\n\t\tassertThat(accesslog.isRotate()).isFalse();\n\t\tassertThat(accesslog.isRenameOnRotate()).isTrue();\n\t\tassertThat(accesslog.isIpv6Canonical()).isTrue();\n\t\tassertThat(accesslog.isRequestAttributesEnabled()).isTrue();\n\t\tassertThat(this.properties.getRemoteip().getRemoteIpHeader()).isEqualTo(\"Remote-Ip\");\n\t\tassertThat(this.properties.getRemoteip().getProtocolHeader()).isEqualTo(\"X-Forwarded-Protocol\");\n\t\tassertThat(this.properties.getRemoteip().getInternalProxies()).isEqualTo(\"10\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\");\n\t\tassertThat(this.properties.getRemoteip().getTrustedProxies()).isEqualTo(\"proxy1|proxy2|proxy3\");\n\t\tassertThat(this.properties.getBackgroundProcessorDelay()).hasSeconds(10);\n\t\tassertThat(this.properties.getRelaxedPathChars()).containsExactly('|', '<');\n\t\tassertThat(this.properties.getRelaxedQueryChars()).containsExactly('^', '|');\n\t\tassertThat(this.properties.isUseRelativeRedirects()).isTrue();\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatUriEncoding() {\n\t\tbind(\"server.tomcat.uri-encoding\", \"US-ASCII\");\n\t\tassertThat(this.properties.getUriEncoding()).isEqualTo(StandardCharsets.US_ASCII);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatMaxThreads() {\n\t\tbind(\"server.tomcat.threads.max\", \"10\");\n\t\tassertThat(this.properties.getThreads().getMax()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatKeepAliveTimeout() {\n\t\tbind(\"server.tomcat.keep-alive-timeout\", \"30s\");\n\t\tassertThat(this.properties.getKeepAliveTimeout()).hasSeconds(30);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatKeepAliveTimeoutWithInfinite() {\n\t\tbind(\"server.tomcat.keep-alive-timeout\", \"-1\");\n\t\tassertThat(this.properties.getKeepAliveTimeout()).hasMillis(-1);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatMaxKeepAliveRequests() {\n\t\tbind(\"server.tomcat.max-keep-alive-requests\", \"200\");\n\t\tassertThat(this.properties.getMaxKeepAliveRequests()).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatMaxKeepAliveRequestsWithInfinite() {\n\t\tbind(\"server.tomcat.max-keep-alive-requests\", \"-1\");\n\t\tassertThat(this.properties.getMaxKeepAliveRequests()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatMaxParameterCount() {\n\t\tbind(\"server.tomcat.max-parameter-count\", \"100\");\n\t\tassertThat(this.properties.getMaxParameterCount()).isEqualTo(100);\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatMinSpareThreads() {\n\t\tbind(\"server.tomcat.threads.min-spare\", \"10\");\n\t\tassertThat(this.properties.getThreads().getMinSpare()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid tomcatAcceptCountMatchesProtocolDefault() throws Exception {\n\t\tassertThat(this.properties.getAcceptCount()).isEqualTo(getDefaultProtocol().getAcceptCount());\n\t}\n\n\t@Test\n\tvoid tomcatProcessorCacheMatchesProtocolDefault() throws Exception {\n\t\tassertThat(this.properties.getProcessorCache()).isEqualTo(getDefaultProtocol().getProcessorCache());\n\t}\n\n\t@Test\n\tvoid tomcatMaxConnectionsMatchesProtocolDefault() throws Exception {\n\t\tassertThat(this.properties.getMaxConnections()).isEqualTo(getDefaultProtocol().getMaxConnections());\n\t}\n\n\t@Test\n\tvoid tomcatMaxThreadsMatchesProtocolDefault() throws Exception {\n\t\tassertThat(this.properties.getThreads().getMax()).isEqualTo(getDefaultProtocol().getMaxThreads());\n\t}\n\n\t@Test\n\tvoid tomcatMinSpareThreadsMatchesProtocolDefault() throws Exception {\n\t\tassertThat(this.properties.getThreads().getMinSpare()).isEqualTo(getDefaultProtocol().getMinSpareThreads());\n\t}\n\n\t@Test\n\tvoid tomcatMaxHttpPostSizeMatchesConnectorDefault() {\n\t\tassertThat(this.properties.getMaxHttpFormPostSize().toBytes())\n\t\t\t.isEqualTo(getDefaultConnector().getMaxPostSize());\n\t}\n\n\t@Test\n\tvoid tomcatMaxParameterCountMatchesConnectorDefault() {\n\t\tassertThat(this.properties.getMaxParameterCount()).isEqualTo(getDefaultConnector().getMaxParameterCount());\n\t}\n\n\t@Test\n\tvoid tomcatBackgroundProcessorDelayMatchesEngineDefault() {\n\t\tassertThat(this.properties.getBackgroundProcessorDelay())\n\t\t\t.hasSeconds((new StandardEngine().getBackgroundProcessorDelay()));\n\t}\n\n\t@Test\n\tvoid tomcatMaxHttpFormPostSizeMatchesConnectorDefault() {\n\t\tassertThat(this.properties.getMaxHttpFormPostSize().toBytes())\n\t\t\t.isEqualTo(getDefaultConnector().getMaxPostSize());\n\t}\n\n\t@Test\n\tvoid tomcatMaxPartCountMatchesConnectorDefault() {\n\t\tassertThat(this.properties.getMaxPartCount()).isEqualTo(getDefaultConnector().getMaxPartCount());\n\t}\n\n\t@Test\n\tvoid tomcatMaxPartHeaderSizeMatchesConnectorDefault() {\n\t\tassertThat(this.properties.getMaxPartHeaderSize().toBytes())\n\t\t\t.isEqualTo(getDefaultConnector().getMaxPartHeaderSize());\n\t}\n\n\t@Test\n\tvoid tomcatUriEncodingMatchesConnectorDefault() {\n\t\tassertThat(this.properties.getUriEncoding().name()).isEqualTo(getDefaultConnector().getURIEncoding());\n\t}\n\n\t@Test\n\tvoid tomcatRedirectContextRootMatchesDefault() {\n\t\tassertThat(this.properties.getRedirectContextRoot())\n\t\t\t.isEqualTo(new StandardContext().getMapperContextRootRedirectEnabled());\n\t}\n\n\t@Test\n\tvoid tomcatAccessLogRenameOnRotateMatchesDefault() {\n\t\tassertThat(this.properties.getAccesslog().isRenameOnRotate())\n\t\t\t.isEqualTo(new AccessLogValve().isRenameOnRotate());\n\t}\n\n\t@Test\n\tvoid tomcatAccessLogRequestAttributesEnabledMatchesDefault() {\n\t\tassertThat(this.properties.getAccesslog().isRequestAttributesEnabled())\n\t\t\t.isEqualTo(new AccessLogValve().getRequestAttributesEnabled());\n\t}\n\n\t@Test\n\tvoid tomcatInternalProxiesMatchesDefault() {\n\t\tassertThat(this.properties.getRemoteip().getInternalProxies())\n\t\t\t.isEqualTo(new RemoteIpValve().getInternalProxies());\n\t}\n\n\t@Test\n\tvoid tomcatUseRelativeRedirectsDefaultsToFalse() {\n\t\tassertThat(this.properties.isUseRelativeRedirects()).isFalse();\n\t}\n\n\t@Test\n\tvoid tomcatMaxKeepAliveRequestsDefault() throws Exception {\n\t\tAbstractEndpoint<?, ?> endpoint = (AbstractEndpoint<?, ?>) ReflectionTestUtils.getField(getDefaultProtocol(),\n\t\t\t\t\"endpoint\");\n\t\tassertThat(endpoint).isNotNull();\n\t\tObject value = ReflectionTestUtils.getField(endpoint, \"maxKeepAliveRequests\");\n\t\tassertThat(value).isNotNull();\n\t\tint defaultMaxKeepAliveRequests = (int) value;\n\t\tassertThat(this.properties.getMaxKeepAliveRequests()).isEqualTo(defaultMaxKeepAliveRequests);\n\t}\n\n\t@Test\n\tvoid shouldDefaultAprToNever() {\n\t\tassertThat(this.properties.getUseApr()).isEqualTo(UseApr.NEVER);\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"server.tomcat\", Bindable.ofInstance(this.properties));\n\t}\n\n\tprivate Connector getDefaultConnector() {\n\t\treturn new Connector(TomcatWebServerFactory.DEFAULT_PROTOCOL);\n\t}\n\n\tprivate AbstractProtocol<?> getDefaultProtocol() throws Exception {\n\t\treturn (AbstractProtocol<?>) Class.forName(TomcatWebServerFactory.DEFAULT_PROTOCOL)\n\t\t\t.getDeclaredConstructor()\n\t\t\t.newInstance();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/TomcatVirtualThreadsWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport org.apache.tomcat.util.threads.VirtualThreadExecutor;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TomcatVirtualThreadsWebServerFactoryCustomizer}.\n *\n * @author Moritz Halbritter\n */\nclass TomcatVirtualThreadsWebServerFactoryCustomizerTests {\n\n\tprivate final TomcatVirtualThreadsWebServerFactoryCustomizer customizer = new TomcatVirtualThreadsWebServerFactoryCustomizer();\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid shouldSetVirtualThreadExecutor() {\n\t\twithWebServer((webServer) -> assertThat(webServer.getTomcat().getConnector().getProtocolHandler().getExecutor())\n\t\t\t.isInstanceOf(VirtualThreadExecutor.class));\n\t}\n\n\tprivate TomcatWebServer getWebServer() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tthis.customizer.customize(factory);\n\t\treturn (TomcatWebServer) factory.getWebServer();\n\t}\n\n\tprivate void withWebServer(Consumer<TomcatWebServer> callback) {\n\t\tTomcatWebServer webServer = getWebServer();\n\t\twebServer.start();\n\t\ttry {\n\t\t\tcallback.accept(webServer);\n\t\t}\n\t\tfinally {\n\t\t\twebServer.stop();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/TomcatWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Locale;\nimport java.util.function.Consumer;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.catalina.valves.AccessLogValve;\nimport org.apache.catalina.valves.ErrorReportValve;\nimport org.apache.catalina.valves.RemoteIpValve;\nimport org.apache.coyote.AbstractProtocol;\nimport org.apache.coyote.ajp.AbstractAjpProtocol;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.apache.coyote.http2.Http2Protocol;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties.ForwardHeadersStrategy;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link TomcatWebServerFactoryCustomizer}\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @author Rob Tompkins\n * @author Artsiom Yudovin\n * @author Stephane Nicoll\n * @author Andrew McGhie\n * @author Rafiullah Hamedy\n * @author Victor Mandujano\n * @author Parviz Rozikov\n * @author Moritz Halbritter\n */\n@DirtiesUrlFactories\nclass TomcatWebServerFactoryCustomizerTests {\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\tprivate final ServerProperties serverProperties = new ServerProperties();\n\n\tprivate final TomcatServerProperties tomcatProperties = new TomcatServerProperties();\n\n\tprivate final WebProperties webProperties = new WebProperties();\n\n\tprivate TomcatWebServerFactoryCustomizer customizer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tthis.customizer = new TomcatWebServerFactoryCustomizer(this.environment, this.serverProperties,\n\t\t\t\tthis.tomcatProperties, this.webProperties);\n\t}\n\n\t@Test\n\tvoid defaultsAreConsistent() {\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxSwallowSize())\n\t\t\t.isEqualTo(this.tomcatProperties.getMaxSwallowSize().toBytes()));\n\t}\n\n\t@Test\n\tvoid customAcceptCount() {\n\t\tbind(\"server.tomcat.accept-count=10\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getAcceptCount())\n\t\t\t.isEqualTo(10));\n\t}\n\n\t@Test\n\tvoid customProcessorCache() {\n\t\tbind(\"server.tomcat.processor-cache=100\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getProcessorCache())\n\t\t\t.isEqualTo(100));\n\t}\n\n\t@Test\n\tvoid customKeepAliveTimeout() {\n\t\tbind(\"server.tomcat.keep-alive-timeout=30ms\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getKeepAliveTimeout())\n\t\t\t.isEqualTo(30));\n\t}\n\n\t@Test\n\tvoid defaultKeepAliveTimeoutWithHttp2() {\n\t\tbind(\"server.http2.enabled=true\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((Http2Protocol) server.getTomcat().getConnector().findUpgradeProtocols()[0]).getKeepAliveTimeout())\n\t\t\t.isEqualTo(20000L));\n\t}\n\n\t@Test\n\tvoid customKeepAliveTimeoutWithHttp2() {\n\t\tbind(\"server.tomcat.keep-alive-timeout=30s\", \"server.http2.enabled=true\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((Http2Protocol) server.getTomcat().getConnector().findUpgradeProtocols()[0]).getKeepAliveTimeout())\n\t\t\t.isEqualTo(30000L));\n\t}\n\n\t@Test\n\tvoid customMaxKeepAliveRequests() {\n\t\tbind(\"server.tomcat.max-keep-alive-requests=-1\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxKeepAliveRequests())\n\t\t\t.isEqualTo(-1));\n\t}\n\n\t@Test\n\tvoid defaultMaxKeepAliveRequests() {\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxKeepAliveRequests())\n\t\t\t.isEqualTo(100));\n\t}\n\n\t@Test\n\tvoid unlimitedProcessorCache() {\n\t\tbind(\"server.tomcat.processor-cache=-1\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getProcessorCache())\n\t\t\t.isEqualTo(-1));\n\t}\n\n\t@Test\n\tvoid customBackgroundProcessorDelay() {\n\t\tbind(\"server.tomcat.background-processor-delay=5\");\n\t\tTomcatWebServer server = customizeAndGetServer();\n\t\tassertThat(server.getTomcat().getEngine().getBackgroundProcessorDelay()).isEqualTo(5);\n\t}\n\n\t@Test\n\tvoid customDisableMaxHttpFormPostSize() {\n\t\tbind(\"server.tomcat.max-http-form-post-size=-1\");\n\t\tcustomizeAndRunServer((server) -> assertThat(server.getTomcat().getConnector().getMaxPostSize()).isEqualTo(-1));\n\t}\n\n\t@Test\n\tvoid customMaxConnections() {\n\t\tbind(\"server.tomcat.max-connections=5\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getMaxConnections())\n\t\t\t.isEqualTo(5));\n\t}\n\n\t@Test\n\tvoid customMaxHttpFormPostSize() {\n\t\tbind(\"server.tomcat.max-http-form-post-size=10000\");\n\t\tcustomizeAndRunServer(\n\t\t\t\t(server) -> assertThat(server.getTomcat().getConnector().getMaxPostSize()).isEqualTo(10000));\n\t}\n\n\t@Test\n\tvoid defaultMaxPartCount() {\n\t\tcustomizeAndRunServer(\n\t\t\t\t(server) -> assertThat(server.getTomcat().getConnector().getMaxPartCount()).isEqualTo(50));\n\t}\n\n\t@Test\n\tvoid customMaxPartCount() {\n\t\tbind(\"server.tomcat.max-part-count=5\");\n\t\tcustomizeAndRunServer((server) -> assertThat(server.getTomcat().getConnector().getMaxPartCount()).isEqualTo(5));\n\t}\n\n\t@Test\n\tvoid defaultMaxPartHeaderSize() {\n\t\tcustomizeAndRunServer(\n\t\t\t\t(server) -> assertThat(server.getTomcat().getConnector().getMaxPartHeaderSize()).isEqualTo(512));\n\t}\n\n\t@Test\n\tvoid customMaxPartHeaderSize() {\n\t\tbind(\"server.tomcat.max-part-header-size=4KB\");\n\t\tcustomizeAndRunServer(\n\t\t\t\t(server) -> assertThat(server.getTomcat().getConnector().getMaxPartHeaderSize()).isEqualTo(4096));\n\t}\n\n\t@Test\n\t@ClassPathOverrides(\"org.apache.tomcat.embed:tomcat-embed-core:11.0.7\")\n\tvoid customizerIsCompatibleWithTomcatVersionsWithoutMaxPartCountAndMaxPartHeaderSize() {\n\t\tassertThatNoException().isThrownBy(this::customizeAndRunServer);\n\t}\n\n\t@Test\n\tvoid defaultMaxHttpRequestHeaderSize() {\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpRequestHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofKilobytes(8).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxHttpRequestHeaderSize() {\n\t\tbind(\"server.max-http-request-header-size=10MB\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpRequestHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofMegabytes(10).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxParameterCount() {\n\t\tbind(\"server.tomcat.max-parameter-count=100\");\n\t\tcustomizeAndRunServer(\n\t\t\t\t(server) -> assertThat(server.getTomcat().getConnector().getMaxParameterCount()).isEqualTo(100));\n\t}\n\n\t@Test\n\tvoid customMaxRequestHttpHeaderSizeIgnoredIfNegative() {\n\t\tbind(\"server.max-http-request-header-size=-1\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpRequestHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofKilobytes(8).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxRequestHttpHeaderSizeIgnoredIfZero() {\n\t\tbind(\"server.max-http-request-header-size=0\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpRequestHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofKilobytes(8).toBytes()));\n\t}\n\n\t@Test\n\tvoid defaultMaxHttpResponseHeaderSize() {\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpResponseHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofKilobytes(8).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxHttpResponseHeaderSize() {\n\t\tbind(\"server.tomcat.max-http-response-header-size=10MB\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpResponseHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofMegabytes(10).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxResponseHttpHeaderSizeIgnoredIfNegative() {\n\t\tbind(\"server.tomcat.max-http-response-header-size=-1\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpResponseHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofKilobytes(8).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxResponseHttpHeaderSizeIgnoredIfZero() {\n\t\tbind(\"server.tomcat.max-http-response-header-size=0\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxHttpResponseHeaderSize())\n\t\t\t.isEqualTo(DataSize.ofKilobytes(8).toBytes()));\n\t}\n\n\t@Test\n\tvoid customMaxSwallowSize() {\n\t\tbind(\"server.tomcat.max-swallow-size=10MB\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getMaxSwallowSize())\n\t\t\t.isEqualTo(DataSize.ofMegabytes(10).toBytes()));\n\t}\n\n\t@Test\n\tvoid customRemoteIpValve() {\n\t\tbind(\"server.tomcat.remoteip.remote-ip-header=x-my-remote-ip-header\",\n\t\t\t\t\"server.tomcat.remoteip.protocol-header=x-my-protocol-header\",\n\t\t\t\t\"server.tomcat.remoteip.internal-proxies=192.168.0.1\",\n\t\t\t\t\"server.tomcat.remoteip.host-header=x-my-forward-host\",\n\t\t\t\t\"server.tomcat.remoteip.port-header=x-my-forward-port\",\n\t\t\t\t\"server.tomcat.remoteip.protocol-header-https-value=On\",\n\t\t\t\t\"server.tomcat.remoteip.trusted-proxies=proxy1|proxy2\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).hasSize(1);\n\t\tValve valve = factory.getEngineValves().iterator().next();\n\t\tassertThat(valve).isInstanceOf(RemoteIpValve.class);\n\t\tRemoteIpValve remoteIpValve = (RemoteIpValve) valve;\n\t\tassertThat(remoteIpValve.getProtocolHeader()).isEqualTo(\"x-my-protocol-header\");\n\t\tassertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo(\"On\");\n\t\tassertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo(\"x-my-remote-ip-header\");\n\t\tassertThat(remoteIpValve.getHostHeader()).isEqualTo(\"x-my-forward-host\");\n\t\tassertThat(remoteIpValve.getPortHeader()).isEqualTo(\"x-my-forward-port\");\n\t\tassertThat(remoteIpValve.getInternalProxies()).isEqualTo(\"192.168.0.1\");\n\t\tassertThat(remoteIpValve.getTrustedProxies()).isEqualTo(\"proxy1|proxy2\");\n\t}\n\n\t@Test\n\tvoid resourceCacheMatchesDefault() {\n\t\tTomcatServerProperties properties = new TomcatServerProperties();\n\t\tcustomizeAndRunServer((server) -> {\n\t\t\tTomcat tomcat = server.getTomcat();\n\t\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\t\tassertThat(properties.getResource().isAllowCaching()).isEqualTo(context.getResources().isCachingAllowed());\n\t\t\tassertThat(properties.getResource().getCacheMaxSize())\n\t\t\t\t.isEqualTo(DataSize.ofKilobytes(context.getResources().getCacheMaxSize()));\n\t\t\tassertThat(properties.getResource().getCacheTtl())\n\t\t\t\t.isEqualTo(Duration.ofMillis(context.getResources().getCacheTtl()));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customStaticResourceAllowCaching() {\n\t\tbind(\"server.tomcat.resource.allow-caching=false\");\n\t\tcustomizeAndRunServer((server) -> {\n\t\t\tTomcat tomcat = server.getTomcat();\n\t\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\t\tassertThat(context.getResources().isCachingAllowed()).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customStaticResourceCacheMaxSize() {\n\t\tbind(\"server.tomcat.resource.cache-max-size=4MB\");\n\t\tcustomizeAndRunServer((server) -> {\n\t\t\tTomcat tomcat = server.getTomcat();\n\t\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\t\tassertThat(context.getResources().getCacheMaxSize()).isEqualTo(4096L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customStaticResourceCacheTtl() {\n\t\tbind(\"server.tomcat.resource.cache-ttl=10s\");\n\t\tcustomizeAndRunServer((server) -> {\n\t\t\tTomcat tomcat = server.getTomcat();\n\t\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\t\tassertThat(context.getResources().getCacheTtl()).isEqualTo(10000L);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customRelaxedPathChars() {\n\t\tbind(\"server.tomcat.relaxed-path-chars=|,^\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getRelaxedPathChars())\n\t\t\t.isEqualTo(\"|^\"));\n\t}\n\n\t@Test\n\tvoid customRelaxedQueryChars() {\n\t\tbind(\"server.tomcat.relaxed-query-chars=^  ,  | \");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractHttp11Protocol<?>) server.getTomcat().getConnector().getProtocolHandler())\n\t\t\t\t\t.getRelaxedQueryChars())\n\t\t\t.isEqualTo(\"^|\"));\n\t}\n\n\t@Test\n\tvoid deduceUseForwardHeaders() {\n\t\tthis.environment.setProperty(\"DYNO\", \"-\");\n\t\ttestRemoteIpValveConfigured();\n\t}\n\n\t@Test\n\tvoid defaultUseForwardHeaders() {\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).isEmpty();\n\t}\n\n\t@Test\n\tvoid forwardHeadersWhenStrategyIsNativeShouldConfigureValve() {\n\t\tthis.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NATIVE);\n\t\ttestRemoteIpValveConfigured();\n\t}\n\n\t@Test\n\tvoid forwardHeadersWhenStrategyIsNoneShouldNotConfigureValve() {\n\t\tthis.environment.setProperty(\"DYNO\", \"-\");\n\t\tthis.serverProperties.setForwardHeadersStrategy(ServerProperties.ForwardHeadersStrategy.NONE);\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).isEmpty();\n\t}\n\n\t@Test\n\tvoid defaultRemoteIpValve() {\n\t\t// Since 1.1.7 you need to specify at least the protocol\n\t\tbind(\"server.tomcat.remoteip.protocol-header=X-Forwarded-Proto\",\n\t\t\t\t\"server.tomcat.remoteip.remote-ip-header=X-Forwarded-For\");\n\t\ttestRemoteIpValveConfigured();\n\t}\n\n\t@Test\n\tvoid setUseNativeForwardHeadersStrategy() {\n\t\tthis.serverProperties.setForwardHeadersStrategy(ForwardHeadersStrategy.NATIVE);\n\t\ttestRemoteIpValveConfigured();\n\t}\n\n\tprivate void testRemoteIpValveConfigured() {\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).hasSize(1);\n\t\tValve valve = factory.getEngineValves().iterator().next();\n\t\tassertThat(valve).isInstanceOf(RemoteIpValve.class);\n\t\tRemoteIpValve remoteIpValve = (RemoteIpValve) valve;\n\t\tassertThat(remoteIpValve.getProtocolHeader()).isEqualTo(\"X-Forwarded-Proto\");\n\t\tassertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo(\"https\");\n\t\tassertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo(\"X-Forwarded-For\");\n\t\tassertThat(remoteIpValve.getHostHeader()).isEqualTo(\"X-Forwarded-Host\");\n\t\tassertThat(remoteIpValve.getPortHeader()).isEqualTo(\"X-Forwarded-Port\");\n\t\tString expectedInternalProxies = \"192.168.0.0/16, 172.16.0.0/12, 169.254.0.0/16, fc00::/7, 10.0.0.0/8, \"\n\t\t\t\t+ \"100.64.0.0/10, 127.0.0.0/8, fe80::/10, ::1/128\";\n\t\tassertThat(remoteIpValve.getInternalProxies()).isEqualTo(expectedInternalProxies);\n\t}\n\n\t@Test\n\tvoid defaultBackgroundProcessorDelay() {\n\t\tTomcatWebServer server = customizeAndGetServer();\n\t\tassertThat(server.getTomcat().getEngine().getBackgroundProcessorDelay()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid disableRemoteIpValve() {\n\t\tbind(\"server.tomcat.remoteip.remote-ip-header=\", \"server.tomcat.remoteip.protocol-header=\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).isEmpty();\n\t}\n\n\t@Test\n\tvoid errorReportValveIsConfiguredToNotReportStackTraces() {\n\t\tTomcatWebServer server = customizeAndGetServer();\n\t\tValve[] valves = server.getTomcat().getHost().getPipeline().getValves();\n\t\tassertThat(valves).hasAtLeastOneElementOfType(ErrorReportValve.class);\n\t\tfor (Valve valve : valves) {\n\t\t\tif (valve instanceof ErrorReportValve errorReportValve) {\n\t\t\t\tassertThat(errorReportValve.isShowReport()).isFalse();\n\t\t\t\tassertThat(errorReportValve.isShowServerInfo()).isFalse();\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid testCustomizeMinSpareThreads() {\n\t\tbind(\"server.tomcat.threads.min-spare=10\");\n\t\tassertThat(this.tomcatProperties.getThreads().getMinSpare()).isEqualTo(10);\n\t}\n\n\t@Test\n\tvoid customConnectionTimeout() {\n\t\tbind(\"server.tomcat.connection-timeout=30s\");\n\t\tcustomizeAndRunServer((server) -> assertThat(\n\t\t\t\t((AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler()).getConnectionTimeout())\n\t\t\t.isEqualTo(30000));\n\t}\n\n\t@Test\n\tvoid accessLogBufferingCanBeDisabled() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.buffered=false\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).isBuffered()).isFalse();\n\t}\n\n\t@Test\n\tvoid accessLogCanBeEnabled() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).hasSize(1);\n\t\tassertThat(factory.getEngineValves()).first().isInstanceOf(AccessLogValve.class);\n\t}\n\n\t@Test\n\tvoid accessLogFileDateFormatByDefault() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getFileDateFormat())\n\t\t\t.isEqualTo(\".yyyy-MM-dd\");\n\t}\n\n\t@Test\n\tvoid accessLogFileDateFormatCanBeRedefined() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.file-date-format=yyyy-MM-dd.HH\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getFileDateFormat())\n\t\t\t.isEqualTo(\"yyyy-MM-dd.HH\");\n\t}\n\n\t@Test\n\tvoid accessLogIsBufferedByDefault() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).isBuffered()).isTrue();\n\t}\n\n\t@Test\n\tvoid accessLogIsDisabledByDefault() {\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getEngineValves()).isEmpty();\n\t}\n\n\t@Test\n\tvoid accessLogMaxDaysDefault() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getMaxDays())\n\t\t\t.isEqualTo(this.tomcatProperties.getAccesslog().getMaxDays());\n\t}\n\n\t@Test\n\tvoid accessLogConditionCanBeSpecified() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.conditionIf=foo\",\n\t\t\t\t\"server.tomcat.accesslog.conditionUnless=bar\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getConditionIf()).isEqualTo(\"foo\");\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getConditionUnless())\n\t\t\t.isEqualTo(\"bar\");\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getCondition())\n\t\t\t.describedAs(\"value of condition should equal conditionUnless - provided for backwards compatibility\")\n\t\t\t.isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid accessLogEncodingIsNullWhenNotSpecified() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getEncoding()).isNull();\n\t}\n\n\t@Test\n\tvoid accessLogEncodingCanBeSpecified() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.encoding=UTF-8\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getEncoding()).isEqualTo(\"UTF-8\");\n\t}\n\n\t@Test\n\tvoid accessLogWithDefaultLocale() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getLocale())\n\t\t\t.isEqualTo(Locale.getDefault().toString());\n\t}\n\n\t@Test\n\tvoid accessLogLocaleCanBeSpecified() {\n\t\tString locale = \"en_AU\".equals(Locale.getDefault().toString()) ? \"en_US\" : \"en_AU\";\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.locale=\" + locale);\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getLocale()).isEqualTo(locale);\n\t}\n\n\t@Test\n\tvoid accessLogCheckExistsDefault() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).isCheckExists()).isFalse();\n\t}\n\n\t@Test\n\tvoid accessLogCheckExistsSpecified() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.check-exists=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).isCheckExists()).isTrue();\n\t}\n\n\t@Test\n\tvoid accessLogMaxDaysCanBeRedefined() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.max-days=20\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getMaxDays()).isEqualTo(20);\n\t}\n\n\t@Test\n\tvoid accessLogDoesNotUseIpv6CanonicalFormatByDefault() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getIpv6Canonical()).isFalse();\n\t}\n\n\t@Test\n\tvoid accessLogWithIpv6CanonicalSet() {\n\t\tbind(\"server.tomcat.accesslog.enabled=true\", \"server.tomcat.accesslog.ipv6-canonical=true\");\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(((AccessLogValve) factory.getEngineValves().iterator().next()).getIpv6Canonical()).isTrue();\n\t}\n\n\t@Test\n\tvoid ajpConnectorCanBeCustomized() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tfactory.setProtocol(\"AJP/1.3\");\n\t\tfactory.addConnectorCustomizers(\n\t\t\t\t(connector) -> ((AbstractAjpProtocol<?>) connector.getProtocolHandler()).setSecretRequired(false));\n\t\tthis.customizer.customize(factory);\n\t\tWebServer server = factory.getWebServer();\n\t\tserver.start();\n\t\tserver.stop();\n\t}\n\n\t@Test\n\tvoid configureExecutor() {\n\t\tbind(\"server.tomcat.threads.max=10\", \"server.tomcat.threads.min-spare=2\",\n\t\t\t\t\"server.tomcat.threads.max-queue-capacity=20\");\n\t\tcustomizeAndRunServer((server) -> {\n\t\t\tAbstractProtocol<?> protocol = (AbstractProtocol<?>) server.getTomcat().getConnector().getProtocolHandler();\n\t\t\tassertThat(protocol.getMaxThreads()).isEqualTo(10);\n\t\t\tassertThat(protocol.getMinSpareThreads()).isEqualTo(2);\n\t\t\tassertThat(protocol.getMaxQueueSize()).isEqualTo(20);\n\t\t});\n\t}\n\n\t@Test\n\tvoid enableMBeanRegistry() {\n\t\tbind(\"server.tomcat.mbeanregistry.enabled=true\");\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tassertThat(factory.isDisableMBeanRegistry()).isTrue();\n\t\tthis.customizer.customize(factory);\n\t\tassertThat(factory.isDisableMBeanRegistry()).isFalse();\n\t}\n\n\tprivate void bind(String... inlinedProperties) {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties);\n\t\tBinder binder = new Binder(ConfigurationPropertySources.get(this.environment));\n\t\tbinder.bind(\"server\", Bindable.ofInstance(this.serverProperties));\n\t\tbinder.bind(\"server.tomcat\", Bindable.ofInstance(this.tomcatProperties));\n\t}\n\n\tprivate void customizeAndRunServer() {\n\t\tcustomizeAndRunServer(null);\n\t}\n\n\tprivate void customizeAndRunServer(@Nullable Consumer<TomcatWebServer> consumer) {\n\t\tTomcatWebServer server = customizeAndGetServer();\n\t\tserver.start();\n\t\ttry {\n\t\t\tif (consumer != null) {\n\t\t\t\tconsumer.accept(server);\n\t\t\t}\n\t\t}\n\t\tfinally {\n\t\t\tserver.stop();\n\t\t}\n\t}\n\n\tprivate TomcatWebServer customizeAndGetServer() {\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\treturn (TomcatWebServer) factory.getWebServer();\n\t}\n\n\tprivate TomcatServletWebServerFactory customizeAndGetFactory() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tfactory.setHttp2(this.serverProperties.getHttp2());\n\t\tthis.customizer.customize(factory);\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/actuate/web/server/TomcatManagementServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.actuate.web.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TomcatManagementServerProperties}.\n *\n * @author Andy Wilkinson\n */\nclass TomcatManagementServerPropertiesTests {\n\n\t@Test\n\tvoid accessLogsArePrefixedByDefault() {\n\t\tTomcatManagementServerProperties properties = new TomcatManagementServerProperties();\n\t\tassertThat(properties.getAccesslog().getPrefix()).isEqualTo(\"management_\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/metrics/TomcatMetricsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.metrics;\n\nimport java.util.Collections;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.binder.tomcat.TomcatMetrics;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.apache.tomcat.util.modeler.Registry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.context.event.ApplicationStartedEvent;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.autoconfigure.reactive.TomcatReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.metrics.TomcatMetricsBinder;\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatMetricsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass TomcatMetricsAutoConfigurationTests {\n\n\t@Test\n\tvoid autoConfiguresTomcatMetricsWithEmbeddedServletTomcat() {\n\t\tresetTomcatState();\n\t\tnew WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(TomcatMetricsAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ServletWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.tomcat.mbeanregistry.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tassertThat(context).hasSingleBean(TomcatMetricsBinder.class);\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"tomcat.sessions.active.max\").meter()).isNotNull();\n\t\t\t\tassertThat(registry.find(\"tomcat.threads.current\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresTomcatMetricsWithEmbeddedReactiveTomcat() {\n\t\tresetTomcatState();\n\t\tnew ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(TomcatMetricsAutoConfiguration.class,\n\t\t\t\t\tTomcatReactiveWebServerAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ReactiveWebServerConfiguration.class, MeterRegistryConfiguration.class)\n\t\t\t.withPropertyValues(\"server.tomcat.mbeanregistry.enabled=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tcontext.publishEvent(createApplicationStartedEvent(context.getSourceApplicationContext()));\n\t\t\t\tSimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);\n\t\t\t\tassertThat(registry.find(\"tomcat.sessions.active.max\").meter()).isNotNull();\n\t\t\t\tassertThat(registry.find(\"tomcat.threads.current\").meter()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguresTomcatMetricsWithStandaloneTomcat() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(TomcatMetricsAutoConfiguration.class))\n\t\t\t.withUserConfiguration(MeterRegistryConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(TomcatMetricsBinder.class));\n\t}\n\n\t@Test\n\tvoid allowsCustomTomcatMetricsBinderToBeUsed() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(TomcatMetricsAutoConfiguration.class))\n\t\t\t.withUserConfiguration(MeterRegistryConfiguration.class, CustomTomcatMetricsBinder.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(TomcatMetricsBinder.class)\n\t\t\t\t.hasBean(\"customTomcatMetricsBinder\"));\n\t}\n\n\t@Test\n\tvoid allowsCustomTomcatMetricsToBeUsed() {\n\t\tnew WebApplicationContextRunner().withConfiguration(AutoConfigurations.of(TomcatMetricsAutoConfiguration.class))\n\t\t\t.withUserConfiguration(MeterRegistryConfiguration.class, CustomTomcatMetrics.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TomcatMetricsBinder.class)\n\t\t\t\t.hasBean(\"customTomcatMetrics\"));\n\t}\n\n\tprivate ApplicationStartedEvent createApplicationStartedEvent(ConfigurableApplicationContext context) {\n\t\treturn new ApplicationStartedEvent(new SpringApplication(), new String[0], context, null);\n\t}\n\n\tprivate void resetTomcatState() {\n\t\tReflectionTestUtils.setField(Registry.class, \"registry\", null);\n\t\tAtomicInteger containerCounter = (AtomicInteger) ReflectionTestUtils.getField(TomcatWebServer.class,\n\t\t\t\t\"containerCounter\");\n\t\tassertThat(containerCounter).isNotNull();\n\t\tcontainerCounter.set(-1);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MeterRegistryConfiguration {\n\n\t\t@Bean\n\t\tSimpleMeterRegistry meterRegistry() {\n\t\t\treturn new SimpleMeterRegistry();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletWebServerConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcatFactory() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveWebServerConfiguration {\n\n\t\t@Bean\n\t\tTomcatReactiveWebServerFactory tomcatFactory() {\n\t\t\treturn new TomcatReactiveWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn mock(HttpHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTomcatMetrics {\n\n\t\t@Bean\n\t\tTomcatMetrics customTomcatMetrics() {\n\t\t\treturn new TomcatMetrics(null, Collections.emptyList());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTomcatMetricsBinder {\n\n\t\t@Bean\n\t\tTomcatMetricsBinder customTomcatMetricsBinder(MeterRegistry meterRegistry) {\n\t\t\treturn new TomcatMetricsBinder(meterRegistry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/reactive/TomcatReactiveWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.reactive;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.websocket.server.ServerContainer;\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.startup.Tomcat;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatProtocolHandlerCustomizer;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.reactive.TomcatReactiveWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.reactive.AbstractReactiveWebServerAutoConfigurationTests;\nimport org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatReactiveWebServerAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Raheela Aslam\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass TomcatReactiveWebServerAutoConfigurationTests extends AbstractReactiveWebServerAutoConfigurationTests {\n\n\tTomcatReactiveWebServerAutoConfigurationTests() {\n\t\tsuper(TomcatReactiveWebServerAutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid tomcatConnectorCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(TomcatConnectorCustomizerConfiguration.class).run((context) -> {\n\t\t\tTomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);\n\t\t\tTomcatConnectorCustomizer customizer = context.getBean(\"connectorCustomizer\",\n\t\t\t\t\tTomcatConnectorCustomizer.class);\n\t\t\tassertThat(factory.getConnectorCustomizers()).contains(customizer);\n\t\t\tthen(customizer).should().customize(any(Connector.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatConnectorCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationTomcatConnectorCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);\n\t\t\t\tTomcatConnectorCustomizer customizer = context.getBean(\"connectorCustomizer\",\n\t\t\t\t\t\tTomcatConnectorCustomizer.class);\n\t\t\t\tassertThat(factory.getConnectorCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any(Connector.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatContextCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(TomcatContextCustomizerConfiguration.class).run((context) -> {\n\t\t\tTomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);\n\t\t\tTomcatContextCustomizer customizer = context.getBean(\"contextCustomizer\", TomcatContextCustomizer.class);\n\t\t\tassertThat(factory.getContextCustomizers()).contains(customizer);\n\t\t\tthen(customizer).should().customize(any(Context.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatContextCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationTomcatContextCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);\n\t\t\t\tTomcatContextCustomizer customizer = context.getBean(\"contextCustomizer\",\n\t\t\t\t\t\tTomcatContextCustomizer.class);\n\t\t\t\tassertThat(factory.getContextCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any(Context.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatProtocolHandlerCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(TomcatProtocolHandlerCustomizerConfiguration.class).run((context) -> {\n\t\t\tTomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);\n\t\t\tTomcatProtocolHandlerCustomizer<?> customizer = context.getBean(\"protocolHandlerCustomizer\",\n\t\t\t\t\tTomcatProtocolHandlerCustomizer.class);\n\t\t\tassertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);\n\t\t\tthen(customizer).should().customize(any());\n\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatProtocolHandlerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTomcatReactiveWebServerFactory factory = context.getBean(TomcatReactiveWebServerFactory.class);\n\t\t\t\tTomcatProtocolHandlerCustomizer<?> customizer = context.getBean(\"protocolHandlerCustomizer\",\n\t\t\t\t\t\tTomcatProtocolHandlerCustomizer.class);\n\t\t\t\tassertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid webSocketServerContainerIsAvailableFromServletContext() {\n\t\tthis.serverRunner.run((context) -> {\n\t\t\tWebServer webServer = ((ReactiveWebServerApplicationContext) context.getSourceApplicationContext())\n\t\t\t\t.getWebServer();\n\t\t\tassertThat(webServer).isNotNull();\n\t\t\tServletContext servletContext = findContext(((TomcatWebServer) webServer).getTomcat()).getServletContext();\n\t\t\tObject serverContainer = servletContext.getAttribute(\"jakarta.websocket.server.ServerContainer\");\n\t\t\tassertThat(serverContainer).isInstanceOf(ServerContainer.class);\n\t\t});\n\t}\n\n\tprivate static Context findContext(Tomcat tomcat) {\n\t\tfor (Container child : tomcat.getHost().findChildren()) {\n\t\t\tif (child instanceof Context context) {\n\t\t\t\treturn context;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"The Host does not contain a Context\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatConnectorCustomizerConfiguration {\n\n\t\t@Bean\n\t\tTomcatConnectorCustomizer connectorCustomizer() {\n\t\t\treturn mock(TomcatConnectorCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationTomcatConnectorCustomizerConfiguration {\n\n\t\tprivate final TomcatConnectorCustomizer customizer = mock(TomcatConnectorCustomizer.class);\n\n\t\t@Bean\n\t\tTomcatConnectorCustomizer connectorCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {\n\t\t\treturn (tomcat) -> tomcat.addConnectorCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatContextCustomizerConfiguration {\n\n\t\t@Bean\n\t\tTomcatContextCustomizer contextCustomizer() {\n\t\t\treturn mock(TomcatContextCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationTomcatContextCustomizerConfiguration {\n\n\t\tprivate final TomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);\n\n\t\t@Bean\n\t\tTomcatContextCustomizer contextCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {\n\t\t\treturn (tomcat) -> tomcat.addContextCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatProtocolHandlerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tTomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {\n\t\t\treturn mock(TomcatProtocolHandlerCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration {\n\n\t\tprivate final TomcatProtocolHandlerCustomizer<?> customizer = mock(TomcatProtocolHandlerCustomizer.class);\n\n\t\t@Bean\n\t\tTomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<TomcatReactiveWebServerFactory> tomcatCustomizer() {\n\t\t\treturn (tomcat) -> tomcat.addProtocolHandlerCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/servlet/TomcatServletWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.servlet;\n\nimport jakarta.servlet.Filter;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.connector.Connector;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatProtocolHandlerCustomizer;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.servlet.AbstractServletWebServerAutoConfigurationTests;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.filter.ForwardedHeaderFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatServletWebServerAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Raheela Aslam\n * @author Madhura Bhave\n */\nclass TomcatServletWebServerAutoConfigurationTests extends AbstractServletWebServerAutoConfigurationTests {\n\n\tTomcatServletWebServerAutoConfigurationTests() {\n\t\tsuper(TomcatServletWebServerAutoConfiguration.class);\n\t}\n\n\t@Test\n\tvoid tomcatConnectorCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(TomcatConnectorCustomizerConfiguration.class).run((context) -> {\n\t\t\tTomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);\n\t\t\tTomcatConnectorCustomizer customizer = context.getBean(\"connectorCustomizer\",\n\t\t\t\t\tTomcatConnectorCustomizer.class);\n\t\t\tassertThat(factory.getConnectorCustomizers()).contains(customizer);\n\t\t\tthen(customizer).should().customize(any(Connector.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatConnectorCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationTomcatConnectorCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);\n\t\t\t\tTomcatConnectorCustomizer customizer = context.getBean(\"connectorCustomizer\",\n\t\t\t\t\t\tTomcatConnectorCustomizer.class);\n\t\t\t\tassertThat(factory.getConnectorCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any(Connector.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatContextCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(TomcatContextCustomizerConfiguration.class).run((context) -> {\n\t\t\tTomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);\n\t\t\tTomcatContextCustomizer customizer = context.getBean(\"contextCustomizer\", TomcatContextCustomizer.class);\n\t\t\tassertThat(factory.getContextCustomizers()).contains(customizer);\n\t\t\tthen(customizer).should().customize(any(Context.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatContextCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationTomcatContextCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);\n\t\t\t\tTomcatContextCustomizer customizer = context.getBean(\"contextCustomizer\",\n\t\t\t\t\t\tTomcatContextCustomizer.class);\n\t\t\t\tassertThat(factory.getContextCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any(Context.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatProtocolHandlerCustomizerBeanIsAddedToFactory() {\n\t\tthis.serverRunner.withUserConfiguration(TomcatProtocolHandlerCustomizerConfiguration.class).run((context) -> {\n\t\t\tTomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);\n\t\t\tTomcatProtocolHandlerCustomizer<?> customizer = context.getBean(\"protocolHandlerCustomizer\",\n\t\t\t\t\tTomcatProtocolHandlerCustomizer.class);\n\t\t\tassertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);\n\t\t\tthen(customizer).should().customize(any());\n\t\t});\n\t}\n\n\t@Test\n\tvoid tomcatProtocolHandlerCustomizerRegisteredAsBeanAndViaFactoryIsOnlyCalledOnce() {\n\t\tthis.serverRunner.withUserConfiguration(DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTomcatServletWebServerFactory factory = context.getBean(TomcatServletWebServerFactory.class);\n\t\t\t\tTomcatProtocolHandlerCustomizer<?> customizer = context.getBean(\"protocolHandlerCustomizer\",\n\t\t\t\t\t\tTomcatProtocolHandlerCustomizer.class);\n\t\t\t\tassertThat(factory.getProtocolHandlerCustomizers()).contains(customizer);\n\t\t\t\tthen(customizer).should().customize(any());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenUsingFrameworkForwardHeadersStrategyAndRelativeRedirectsAreEnabledThenFilterIsConfiguredToUseRelativeRedirects() {\n\t\tthis.serverRunner\n\t\t\t.withPropertyValues(\"server.forward-headers-strategy=framework\",\n\t\t\t\t\t\"server.tomcat.use-relative-redirects=true\", \"server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tFilter filter = context.getBean(FilterRegistrationBean.class).getFilter();\n\t\t\t\tassertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);\n\t\t\t\tassertThat(filter).extracting(\"relativeRedirects\").isEqualTo(true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenUsingFrameworkForwardHeadersStrategyAndNotUsingRelativeRedirectsThenFilterIsNotConfiguredToUseRelativeRedirects() {\n\t\tthis.serverRunner\n\t\t\t.withPropertyValues(\"server.forward-headers-strategy=framework\",\n\t\t\t\t\t\"server.tomcat.use-relative-redirects=false\", \"server.port=0\")\n\t\t\t.run((context) -> {\n\t\t\t\tFilter filter = context.getBean(FilterRegistrationBean.class).getFilter();\n\t\t\t\tassertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);\n\t\t\t\tassertThat(filter).extracting(\"relativeRedirects\").isEqualTo(false);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatConnectorCustomizerConfiguration {\n\n\t\t@Bean\n\t\tTomcatConnectorCustomizer connectorCustomizer() {\n\t\t\treturn mock(TomcatConnectorCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationTomcatConnectorCustomizerConfiguration {\n\n\t\tprivate final TomcatConnectorCustomizer customizer = mock(TomcatConnectorCustomizer.class);\n\n\t\t@Bean\n\t\tTomcatConnectorCustomizer connectorCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {\n\t\t\treturn (tomcat) -> tomcat.addConnectorCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatContextCustomizerConfiguration {\n\n\t\t@Bean\n\t\tTomcatContextCustomizer contextCustomizer() {\n\t\t\treturn mock(TomcatContextCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationTomcatContextCustomizerConfiguration {\n\n\t\tprivate final TomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);\n\n\t\t@Bean\n\t\tTomcatContextCustomizer contextCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {\n\t\t\treturn (tomcat) -> tomcat.addContextCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatProtocolHandlerCustomizerConfiguration {\n\n\t\t@Bean\n\t\tTomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {\n\t\t\treturn mock(TomcatProtocolHandlerCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleRegistrationTomcatProtocolHandlerCustomizerConfiguration {\n\n\t\tprivate final TomcatProtocolHandlerCustomizer<?> customizer = mock(TomcatProtocolHandlerCustomizer.class);\n\n\t\t@Bean\n\t\tTomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {\n\t\t\treturn this.customizer;\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {\n\t\t\treturn (tomcat) -> tomcat.addProtocolHandlerCustomizers(this.customizer);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/autoconfigure/servlet/TomcatServletWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.autoconfigure.servlet;\n\nimport org.apache.catalina.Context;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.autoconfigure.TomcatServerProperties;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TomcatServletWebServerFactoryCustomizer}.\n *\n * @author Phillip Webb\n */\nclass TomcatServletWebServerFactoryCustomizerTests {\n\n\tprivate final TomcatServerProperties tomcatProperties = new TomcatServerProperties();\n\n\tprivate TomcatServletWebServerFactoryCustomizer customizer;\n\n\tprivate MockEnvironment environment;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new MockEnvironment();\n\t\tConfigurationPropertySources.attach(this.environment);\n\t\tthis.customizer = new TomcatServletWebServerFactoryCustomizer(this.tomcatProperties);\n\t}\n\n\t@Test\n\tvoid customTldSkip() {\n\t\tbind(\"server.tomcat.additional-tld-skip-patterns=foo.jar,bar.jar\");\n\t\ttestCustomTldSkip(\"foo.jar\", \"bar.jar\");\n\t}\n\n\t@Test\n\tvoid customTldSkipAsList() {\n\t\tbind(\"server.tomcat.additional-tld-skip-patterns[0]=biz.jar\",\n\t\t\t\t\"server.tomcat.additional-tld-skip-patterns[1]=bah.jar\");\n\t\ttestCustomTldSkip(\"biz.jar\", \"bah.jar\");\n\t}\n\n\tprivate void testCustomTldSkip(String... expectedJars) {\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\tassertThat(factory.getTldSkipPatterns()).contains(expectedJars);\n\t\tassertThat(factory.getTldSkipPatterns()).contains(\"junit-*.jar\", \"spring-boot-*.jar\");\n\t}\n\n\t@Test\n\tvoid redirectContextRootCanBeConfigured() {\n\t\tbind(\"server.tomcat.redirect-context-root=false\");\n\t\tassertThat(this.tomcatProperties.getRedirectContextRoot()).isFalse();\n\t\tTomcatWebServer server = customizeAndGetServer();\n\t\tContext context = (Context) server.getTomcat().getHost().findChildren()[0];\n\t\tassertThat(context.getMapperContextRootRedirectEnabled()).isFalse();\n\t}\n\n\t@Test\n\tvoid useRelativeRedirectsCanBeConfigured() {\n\t\tbind(\"server.tomcat.use-relative-redirects=true\");\n\t\tassertThat(this.tomcatProperties.isUseRelativeRedirects()).isTrue();\n\t\tTomcatWebServer server = customizeAndGetServer();\n\t\tContext context = (Context) server.getTomcat().getHost().findChildren()[0];\n\t\tassertThat(context.getUseRelativeRedirects()).isTrue();\n\t}\n\n\tprivate void bind(String... inlinedProperties) {\n\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment, inlinedProperties);\n\t\tnew Binder(ConfigurationPropertySources.get(this.environment)).bind(\"server.tomcat\",\n\t\t\t\tBindable.ofInstance(this.tomcatProperties));\n\t}\n\n\tprivate TomcatWebServer customizeAndGetServer() {\n\t\tTomcatServletWebServerFactory factory = customizeAndGetFactory();\n\t\treturn (TomcatWebServer) factory.getWebServer();\n\t}\n\n\tprivate TomcatServletWebServerFactory customizeAndGetFactory() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tthis.customizer.customize(factory);\n\t\treturn factory;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/metrics/TomcatMetricsBinderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.metrics;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatMetricsBinder}.\n *\n * @author Andy Wilkinson\n */\nclass TomcatMetricsBinderTests {\n\n\tprivate final MeterRegistry meterRegistry = mock(MeterRegistry.class);\n\n\t@Test\n\tvoid destroySucceedsWhenCalledBeforeApplicationHasStarted() {\n\t\tnew TomcatMetricsBinder(this.meterRegistry).destroy();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/reactive/TomcatReactiveWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.reactive;\n\nimport java.net.ConnectException;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.catalina.Context;\nimport org.apache.catalina.LifecycleEvent;\nimport org.apache.catalina.LifecycleListener;\nimport org.apache.catalina.Service;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.core.AprLifecycleListener;\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.catalina.valves.RemoteIpValve;\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.assertj.core.api.ThrowableAssert.ThrowingCallable;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.testsupport.junit.EnabledOnLocale;\nimport org.springframework.boot.tomcat.TomcatAccess;\nimport org.springframework.boot.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatProtocolHandlerCustomizer;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactoryTests;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatReactiveWebServerFactory}.\n *\n * @author Brian Clozel\n * @author Madhura Bhave\n * @author HaiTao Zhang\n */\nclass TomcatReactiveWebServerFactoryTests extends AbstractReactiveWebServerFactoryTests {\n\n\t@Override\n\tprotected TomcatReactiveWebServerFactory getFactory() {\n\t\treturn new TomcatReactiveWebServerFactory(0);\n\t}\n\n\t@Test\n\tvoid tomcatCustomizers() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tTomcatContextCustomizer[] customizers = new TomcatContextCustomizer[4];\n\t\tArrays.setAll(customizers, (i) -> mock(TomcatContextCustomizer.class));\n\t\tfactory.setContextCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tfactory.addContextCustomizers(customizers[2], customizers[3]);\n\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (TomcatContextCustomizer customizer : customizers) {\n\t\t\tthen(customizer).should(ordered).customize(any(Context.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid contextIsAddedToHostBeforeCustomizersAreCalled() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tTomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);\n\t\tfactory.addContextCustomizers(customizer);\n\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\tthen(customizer).should().customize(assertArg((context) -> assertThat(context.getParent()).isNotNull()));\n\t}\n\n\t@Test\n\tvoid defaultTomcatListeners() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tassertThat(factory.getContextLifecycleListeners()).isEmpty();\n\t\tTomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer(mock(HttpHandler.class));\n\t\tthis.webServer = tomcatWebServer;\n\t\tassertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners())\n\t\t\t.extracting((l) -> l.getClass().getSimpleName())\n\t\t\t.containsExactly(\"CleanTempDirsListener\");\n\t}\n\n\t@Test\n\tvoid aprShouldBeOptIn() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setUseApr(true);\n\t\tTomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer(mock(HttpHandler.class));\n\t\tthis.webServer = tomcatWebServer;\n\t\tassertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners())\n\t\t\t.anyMatch(AprLifecycleListener.class::isInstance);\n\t}\n\n\t@Test\n\tvoid tomcatListeners() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tLifecycleListener[] listeners = new LifecycleListener[4];\n\t\tArrays.setAll(listeners, (i) -> mock(LifecycleListener.class));\n\t\tfactory.setContextLifecycleListeners(Arrays.asList(listeners[0], listeners[1]));\n\t\tfactory.addContextLifecycleListeners(listeners[2], listeners[3]);\n\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\tInOrder ordered = inOrder((Object[]) listeners);\n\t\tfor (LifecycleListener listener : listeners) {\n\t\t\tthen(listener).should(ordered).lifecycleEvent(any(LifecycleEvent.class));\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setNullConnectorCustomizersShouldThrowException() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.setConnectorCustomizers(null))\n\t\t\t.withMessageContaining(\"'connectorCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullAddConnectorCustomizersShouldThrowException() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.addConnectorCustomizers((TomcatConnectorCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'connectorCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setNullProtocolHandlerCustomizersShouldThrowException() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.setProtocolHandlerCustomizers(null))\n\t\t\t.withMessageContaining(\"'protocolHandlerCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullProtocolHandlerCustomizersShouldThrowException() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.addProtocolHandlerCustomizers((TomcatProtocolHandlerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'protocolHandlerCustomizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid tomcatConnectorCustomizersShouldBeInvoked() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tHttpHandler handler = mock(HttpHandler.class);\n\t\tTomcatConnectorCustomizer[] customizers = new TomcatConnectorCustomizer[4];\n\t\tArrays.setAll(customizers, (i) -> mock(TomcatConnectorCustomizer.class));\n\t\tfactory.setConnectorCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tfactory.addConnectorCustomizers(customizers[2], customizers[3]);\n\t\tthis.webServer = factory.getWebServer(handler);\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (TomcatConnectorCustomizer customizer : customizers) {\n\t\t\tthen(customizer).should(ordered).customize(any(Connector.class));\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid tomcatProtocolHandlerCustomizersShouldBeInvoked() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tHttpHandler handler = mock(HttpHandler.class);\n\t\tTomcatProtocolHandlerCustomizer<AbstractHttp11Protocol<?>>[] customizers = new TomcatProtocolHandlerCustomizer[4];\n\t\tArrays.setAll(customizers, (i) -> mock(TomcatProtocolHandlerCustomizer.class));\n\t\tfactory.setProtocolHandlerCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tfactory.addProtocolHandlerCustomizers(customizers[2], customizers[3]);\n\t\tthis.webServer = factory.getWebServer(handler);\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (TomcatProtocolHandlerCustomizer customizer : customizers) {\n\t\t\tthen(customizer).should(ordered).customize(any(ProtocolHandler.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid tomcatAdditionalConnectors() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tConnector[] connectors = new Connector[4];\n\t\tArrays.setAll(connectors, (i) -> new Connector());\n\t\tfactory.addAdditionalConnectors(connectors);\n\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\tMap<Service, Connector[]> connectorsByService = TomcatAccess\n\t\t\t.getServiceConnectors((TomcatWebServer) this.webServer);\n\t\tassertThat(connectorsByService.values().iterator().next()).hasSize(connectors.length + 1);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullAdditionalConnectorsThrows() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.addAdditionalConnectors((Connector[]) null))\n\t\t\t.withMessageContaining(\"'connectors' must not be null\");\n\t}\n\n\t@Test\n\tvoid useForwardedHeaders() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tRemoteIpValve valve = new RemoteIpValve();\n\t\tvalve.setProtocolHeader(\"X-Forwarded-Proto\");\n\t\tfactory.addEngineValves(valve);\n\t\tassertForwardHeaderIsUsed(factory);\n\t}\n\n\t@Test\n\tvoid referenceClearingIsDisabled() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\tthis.webServer.start();\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tStandardContext context = (StandardContext) tomcat.getHost().findChildren()[0];\n\t\tassertThat(context.getClearReferencesRmiTargets()).isFalse();\n\t\tassertThat(context.getClearReferencesThreadLocals()).isFalse();\n\t}\n\n\t@Test\n\t@EnabledOnLocale(language = \"en\")\n\tvoid portClashOfPrimaryConnectorResultsInPortInUseException() throws Exception {\n\t\tdoWithBlockedPort((port) -> assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {\n\t\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\t\tfactory.setPort(port);\n\t\t\tthis.webServer = factory.getWebServer(mock(HttpHandler.class));\n\t\t\tthis.webServer.start();\n\t\t}).satisfies((ex) -> handleExceptionCausedByBlockedPortOnPrimaryConnector(ex, port)));\n\t}\n\n\t@Override\n\tprotected void assertThatSslWithInvalidAliasCallFails(ThrowingCallable call) {\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(call);\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() {\n\t\tTomcatReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tWebClient webClient = getWebClient(this.webServer.getPort()).build();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> {\n\t\t\tblockingHandler.stopBlocking();\n\t\t\ttry {\n\t\t\t\twebClient.get().retrieve().toBodilessEntity().block();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcatch (RuntimeException ex) {\n\t\t\t\treturn ex.getCause() instanceof ConnectException;\n\t\t\t}\n\t\t});\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\tvoid whenGetTomcatWebServerIsOverriddenThenWebServerCreationCanBeCustomized() {\n\t\tAtomicReference<TomcatWebServer> webServerReference = new AtomicReference<>();\n\t\tTomcatWebServer webServer = (TomcatWebServer) new TomcatReactiveWebServerFactory() {\n\n\t\t\t@Override\n\t\t\tprotected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {\n\t\t\t\tTomcatWebServer server = new TomcatWebServer(tomcat);\n\t\t\t\twebServerReference.set(server);\n\t\t\t\treturn server;\n\t\t\t}\n\n\t\t}.getWebServer(new EchoHandler());\n\t\tassertThat(webServerReference).hasValue(webServer);\n\t}\n\n\tprivate void handleExceptionCausedByBlockedPortOnPrimaryConnector(RuntimeException ex, int blockedPort) {\n\t\tassertThat(ex).isInstanceOf(PortInUseException.class);\n\t\tassertThat(((PortInUseException) ex).getPort()).isEqualTo(blockedPort);\n\t}\n\n\t@Override\n\tprotected String startedLogMessage() {\n\t\treturn TomcatAccess.getStartedLogMessage((TomcatWebServer) this.webServer);\n\t}\n\n\t@Override\n\tprotected void addConnector(int port, ConfigurableReactiveWebServerFactory factory) {\n\t\tConnector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n\t\tconnector.setPort(port);\n\t\t((TomcatReactiveWebServerFactory) factory).addAdditionalConnectors(connector);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/servlet/TldPatternsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TldPatterns}.\n *\n * @author Phillip Webb\n */\nclass TldPatternsTests {\n\n\t@Test\n\tvoid tomcatSkipAlignsWithTomcatDefaults() throws IOException {\n\t\tassertThat(TldPatterns.TOMCAT_SKIP).containsExactlyInAnyOrderElementsOf(getTomcatDefaultJarsToSkip());\n\t}\n\n\t@Test\n\tvoid tomcatScanAlignsWithTomcatDefaults() throws IOException {\n\t\tassertThat(TldPatterns.TOMCAT_SCAN).containsExactlyInAnyOrderElementsOf(getTomcatDefaultJarsToScan());\n\t}\n\n\tprivate Set<String> getTomcatDefaultJarsToSkip() throws IOException {\n\t\treturn getTomcatDefault(\"tomcat.util.scan.StandardJarScanFilter.jarsToSkip\");\n\t}\n\n\tprivate Set<String> getTomcatDefaultJarsToScan() throws IOException {\n\t\treturn getTomcatDefault(\"tomcat.util.scan.StandardJarScanFilter.jarsToScan\");\n\t}\n\n\tprivate Set<String> getTomcatDefault(String key) throws IOException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\ttry (InputStream inputStream = classLoader.getResource(\"catalina.properties\").openStream()) {\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.load(inputStream);\n\t\t\tString jarsToSkip = properties.getProperty(key);\n\t\t\treturn StringUtils.commaDelimitedListToSet(jarsToSkip);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/servlet/TomcatServletWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.SocketException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\nimport javax.net.ssl.HostnameVerifier;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLPeerUnverifiedException;\nimport javax.net.ssl.SSLSession;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration.Dynamic;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.LifecycleEvent;\nimport org.apache.catalina.LifecycleListener;\nimport org.apache.catalina.LifecycleState;\nimport org.apache.catalina.Service;\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.connector.Connector;\nimport org.apache.catalina.core.AprLifecycleListener;\nimport org.apache.catalina.core.StandardContext;\nimport org.apache.catalina.core.StandardWrapper;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.catalina.util.CharsetMapper;\nimport org.apache.catalina.valves.RemoteIpValve;\nimport org.apache.coyote.ProtocolHandler;\nimport org.apache.coyote.http11.AbstractHttp11Protocol;\nimport org.apache.coyote.http11.Http11Nio2Protocol;\nimport org.apache.hc.client5.http.HttpHostConnectException;\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;\nimport org.apache.hc.client5.http.ssl.HostnameVerificationPolicy;\nimport org.apache.hc.core5.http.HttpResponse;\nimport org.apache.hc.core5.http.NoHttpResponseException;\nimport org.apache.hc.core5.ssl.SSLContextBuilder;\nimport org.apache.jasper.servlet.JspServlet;\nimport org.apache.tomcat.JarScanFilter;\nimport org.apache.tomcat.JarScanType;\nimport org.apache.tomcat.util.scan.StandardJarScanFilter;\nimport org.assertj.core.api.ThrowableAssert.ThrowingCallable;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.junit.EnabledOnLocale;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.tomcat.ConnectorStartFailedException;\nimport org.springframework.boot.tomcat.TomcatAccess;\nimport org.springframework.boot.tomcat.TomcatConnectorCustomizer;\nimport org.springframework.boot.tomcat.TomcatContextCustomizer;\nimport org.springframework.boot.tomcat.TomcatEmbeddedContext;\nimport org.springframework.boot.tomcat.TomcatProtocolHandlerCustomizer;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.boot.web.server.servlet.AbstractServletWebServerFactoryTests;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TomcatServletWebServerFactory}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Moritz Halbritter\n */\nclass TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactoryTests {\n\n\t@Override\n\tprotected TomcatServletWebServerFactory getFactory() {\n\t\treturn new TomcatServletWebServerFactory(0);\n\t}\n\n\t@AfterEach\n\tvoid restoreTccl() {\n\t\tThread.currentThread().setContextClassLoader(getClass().getClassLoader());\n\t}\n\n\t// JMX MBean names clash if you get more than one Engine with the same name...\n\t@Test\n\tvoid tomcatEngineNames() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tfactory.setPort(0);\n\t\tTomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer();\n\t\t// Make sure that the names are different\n\t\tString firstName = ((TomcatWebServer) this.webServer).getTomcat().getEngine().getName();\n\t\tString secondName = tomcatWebServer.getTomcat().getEngine().getName();\n\t\tassertThat(firstName).as(\"Tomcat engines must have different names\").isNotEqualTo(secondName);\n\t\ttomcatWebServer.stop();\n\t}\n\n\t@Test\n\tvoid defaultTomcatListeners() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThat(factory.getContextLifecycleListeners()).isEmpty();\n\t\tTomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer();\n\t\tthis.webServer = tomcatWebServer;\n\t\tassertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners())\n\t\t\t.extracting((listener) -> listener.getClass().getSimpleName())\n\t\t\t.containsExactly(\"CleanTempDirsListener\");\n\t}\n\n\t@Test\n\tvoid aprShouldBeOptIn() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.setUseApr(true);\n\t\tTomcatWebServer tomcatWebServer = (TomcatWebServer) factory.getWebServer();\n\t\tthis.webServer = tomcatWebServer;\n\t\tassertThat(tomcatWebServer.getTomcat().getServer().findLifecycleListeners())\n\t\t\t.anyMatch(AprLifecycleListener.class::isInstance);\n\t}\n\n\t@Test\n\tvoid tomcatListeners() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tLifecycleListener[] listeners = new LifecycleListener[4];\n\t\tArrays.setAll(listeners, (i) -> mock(LifecycleListener.class));\n\t\tfactory.setContextLifecycleListeners(Arrays.asList(listeners[0], listeners[1]));\n\t\tfactory.addContextLifecycleListeners(listeners[2], listeners[3]);\n\t\tthis.webServer = factory.getWebServer();\n\t\tInOrder ordered = inOrder((Object[]) listeners);\n\t\tfor (LifecycleListener listener : listeners) {\n\t\t\tthen(listener).should(ordered).lifecycleEvent(any(LifecycleEvent.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid tomcatCustomizers() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tTomcatContextCustomizer[] customizers = new TomcatContextCustomizer[4];\n\t\tArrays.setAll(customizers, (i) -> mock(TomcatContextCustomizer.class));\n\t\tfactory.setContextCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tfactory.addContextCustomizers(customizers[2], customizers[3]);\n\t\tthis.webServer = factory.getWebServer();\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (TomcatContextCustomizer customizer : customizers) {\n\t\t\tthen(customizer).should(ordered).customize(any(Context.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid contextIsAddedToHostBeforeCustomizersAreCalled() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tTomcatContextCustomizer customizer = mock(TomcatContextCustomizer.class);\n\t\tfactory.addContextCustomizers(customizer);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthen(customizer).should().customize(assertArg((context) -> assertThat(context.getParent()).isNotNull()));\n\t}\n\n\t@Test\n\tvoid tomcatConnectorCustomizers() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tTomcatConnectorCustomizer[] customizers = new TomcatConnectorCustomizer[4];\n\t\tArrays.setAll(customizers, (i) -> mock(TomcatConnectorCustomizer.class));\n\t\tfactory.setConnectorCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tfactory.addConnectorCustomizers(customizers[2], customizers[3]);\n\t\tthis.webServer = factory.getWebServer();\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (TomcatConnectorCustomizer customizer : customizers) {\n\t\t\tthen(customizer).should(ordered).customize(any(Connector.class));\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tvoid tomcatProtocolHandlerCustomizersShouldBeInvoked() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tTomcatProtocolHandlerCustomizer<AbstractHttp11Protocol<?>>[] customizers = new TomcatProtocolHandlerCustomizer[4];\n\t\tArrays.setAll(customizers, (i) -> mock(TomcatProtocolHandlerCustomizer.class));\n\t\tfactory.setProtocolHandlerCustomizers(Arrays.asList(customizers[0], customizers[1]));\n\t\tfactory.addProtocolHandlerCustomizers(customizers[2], customizers[3]);\n\t\tthis.webServer = factory.getWebServer();\n\t\tInOrder ordered = inOrder((Object[]) customizers);\n\t\tfor (TomcatProtocolHandlerCustomizer customizer : customizers) {\n\t\t\tthen(customizer).should(ordered).customize(any(ProtocolHandler.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid tomcatProtocolHandlerCanBeCustomized() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tTomcatProtocolHandlerCustomizer<AbstractHttp11Protocol<?>> customizer = (protocolHandler) -> protocolHandler\n\t\t\t.setProcessorCache(250);\n\t\tfactory.addProtocolHandlerCustomizers(customizer);\n\t\tTomcat tomcat = getTomcat(factory);\n\t\tConnector[] connectors = TomcatAccess.getServiceConnectors((TomcatWebServer) this.webServer)\n\t\t\t.get(tomcat.getService());\n\t\tassertThat(connectors).isNotNull();\n\t\tConnector connector = connectors[0];\n\t\tAbstractHttp11Protocol<?> protocolHandler = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();\n\t\tassertThat(protocolHandler.getProcessorCache()).isEqualTo(250);\n\t}\n\n\t@Test\n\tvoid tomcatAdditionalConnectors() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tConnector[] connectors = new Connector[4];\n\t\tArrays.setAll(connectors, (i) -> {\n\t\t\tConnector connector = new Connector();\n\t\t\tconnector.setPort(0);\n\t\t\treturn connector;\n\t\t});\n\t\tfactory.addAdditionalConnectors(connectors);\n\t\tthis.webServer = factory.getWebServer();\n\t\tMap<Service, Connector[]> connectorsByService = new HashMap<>(\n\t\t\t\tTomcatAccess.getServiceConnectors((TomcatWebServer) this.webServer));\n\t\tassertThat(connectorsByService.values().iterator().next()).hasSize(connectors.length + 1);\n\t\tthis.webServer.start();\n\t\tthis.webServer.stop();\n\t\tconnectorsByService.forEach((service, serviceConnectors) -> {\n\t\t\tfor (Connector connector : serviceConnectors) {\n\t\t\t\tassertThat(connector.getProtocolHandler()).extracting(\"endpoint.serverSock\").isNull();\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullAdditionalConnectorThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.addAdditionalConnectors((Connector[]) null))\n\t\t\t.withMessageContaining(\"'connectors' must not be null\");\n\t}\n\n\t@Test\n\tvoid sessionTimeout() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setTimeout(Duration.ofSeconds(10));\n\t\tassertTimeout(factory, 1);\n\t}\n\n\t@Test\n\tvoid sessionTimeoutInMinutes() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setTimeout(Duration.ofMinutes(1));\n\t\tassertTimeout(factory, 1);\n\t}\n\n\t@Test\n\tvoid noSessionTimeout() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setTimeout(null);\n\t\tassertTimeout(factory, -1);\n\t}\n\n\t@Test\n\tvoid valve() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tValve valve = mock(Valve.class);\n\t\tfactory.addContextValves(valve);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthen(valve).should().setNext(any(Valve.class));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setNullTomcatContextCustomizersThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.setContextCustomizers(null))\n\t\t\t.withMessageContaining(\"'contextCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullContextCustomizersThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.addContextCustomizers((TomcatContextCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'contextCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setNullTomcatConnectorCustomizersThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.setConnectorCustomizers(null))\n\t\t\t.withMessageContaining(\"'connectorCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullConnectorCustomizersThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.addConnectorCustomizers((TomcatConnectorCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'connectorCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid setNullTomcatProtocolHandlerCustomizersThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> factory.setProtocolHandlerCustomizers(null))\n\t\t\t.withMessageContaining(\"'protocolHandlerCustomizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid addNullTomcatProtocolHandlerCustomizersThrows() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> factory.addProtocolHandlerCustomizers((TomcatProtocolHandlerCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'protocolHandlerCustomizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid uriEncoding() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.setUriEncoding(StandardCharsets.US_ASCII);\n\t\tTomcat tomcat = getTomcat(factory);\n\t\tConnector[] connectors = TomcatAccess.getServiceConnectors((TomcatWebServer) this.webServer)\n\t\t\t.get(tomcat.getService());\n\t\tassertThat(connectors).isNotNull();\n\t\tConnector connector = connectors[0];\n\t\tassertThat(connector.getURIEncoding()).isEqualTo(\"US-ASCII\");\n\t}\n\n\t@Test\n\tvoid defaultUriEncoding() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tTomcat tomcat = getTomcat(factory);\n\t\tConnector[] connectors = TomcatAccess.getServiceConnectors((TomcatWebServer) this.webServer)\n\t\t\t.get(tomcat.getService());\n\t\tassertThat(connectors).isNotNull();\n\t\tConnector connector = connectors[0];\n\t\tassertThat(connector.getURIEncoding()).isEqualTo(\"UTF-8\");\n\t}\n\n\t@Test\n\t@EnabledOnLocale(language = \"en\")\n\tvoid startupFailureDoesNotResultInUnstoppedThreadsBeingReported(CapturedOutput output) throws Exception {\n\t\tsuper.portClashOfPrimaryConnectorResultsInPortInUseException();\n\t\tassertThat(output).doesNotContain(\"appears to have started a thread named [main]\");\n\t}\n\n\t@Test\n\tvoid destroyCalledWithoutStart() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.destroy();\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tassertThat(tomcat.getServer().getState()).isSameAs(LifecycleState.DESTROYED);\n\t}\n\n\t@Override\n\tprotected void addConnector(int port, ConfigurableServletWebServerFactory factory) {\n\t\tConnector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n\t\tconnector.setPort(port);\n\t\t((TomcatServletWebServerFactory) factory).addAdditionalConnectors(connector);\n\t}\n\n\t@Test\n\tvoid useForwardHeaders() throws Exception {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.addContextValves(new RemoteIpValve());\n\t\tassertForwardHeaderIsUsed(factory);\n\t}\n\n\t@Test\n\tvoid disableDoesNotSaveSessionFiles() throws Exception {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\t// If baseDir is not set SESSIONS.ser is written to a different temp directory\n\t\t// each time. By setting it we can really ensure that data isn't saved\n\t\tfactory.setBaseDirectory(this.tempDir);\n\t\tthis.webServer = factory.getWebServer(sessionServletRegistration());\n\t\tthis.webServer.start();\n\t\tString s1 = getResponse(getLocalUrl(\"/session\"));\n\t\tString s2 = getResponse(getLocalUrl(\"/session\"));\n\t\tthis.webServer.stop();\n\t\tthis.webServer = factory.getWebServer(sessionServletRegistration());\n\t\tthis.webServer.start();\n\t\tString s3 = getResponse(getLocalUrl(\"/session\"));\n\t\tString message = \"Session error s1=\" + s1 + \" s2=\" + s2 + \" s3=\" + s3;\n\t\tassertThat(s2.split(\":\")[0]).as(message).isEqualTo(s1.split(\":\")[1]);\n\t\tassertThat(s3.split(\":\")[0]).as(message).isNotEqualTo(s2.split(\":\")[1]);\n\t}\n\n\t@Test\n\tvoid jndiLookupsCanBePerformedDuringApplicationContextRefresh() throws NamingException {\n\t\tThread.currentThread().setContextClassLoader(getClass().getClassLoader());\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0) {\n\n\t\t\t@Override\n\t\t\tprotected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {\n\t\t\t\ttomcat.enableNaming();\n\t\t\t\treturn super.getTomcatWebServer(tomcat);\n\t\t\t}\n\n\t\t};\n\t\t// Server is created in onRefresh\n\t\tthis.webServer = factory.getWebServer();\n\t\t// Lookups should now be possible\n\t\tnew InitialContext().lookup(\"java:comp/env\");\n\t\t// Called in finishRefresh, giving us an opportunity to remove the context binding\n\t\t// and avoid a leak\n\t\tthis.webServer.start();\n\t\t// Lookups should no longer be possible\n\t\tassertThatExceptionOfType(NamingException.class).isThrownBy(() -> new InitialContext().lookup(\"java:comp/env\"));\n\t}\n\n\t@Test\n\tvoid defaultLocaleCharsetMappingsAreOverridden() throws IOException {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\t// override defaults, see org.apache.catalina.util.CharsetMapperDefault.properties\n\t\tProperties charsetMapperDefault = PropertiesLoaderUtils\n\t\t\t.loadProperties(new ClassPathResource(\"CharsetMapperDefault.properties\", CharsetMapper.class));\n\t\tfor (String language : charsetMapperDefault.stringPropertyNames()) {\n\t\t\tassertThat(getCharset(new Locale(language))).isEqualTo(StandardCharsets.UTF_8);\n\t\t}\n\t}\n\n\t@Test\n\tvoid tldSkipPatternsShouldBeAppliedToContextJarScanner() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.addTldSkipPatterns(\"foo.jar\", \"bar.jar\");\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\tJarScanFilter jarScanFilter = context.getJarScanner().getJarScanFilter();\n\t\tassertThat(jarScanFilter.check(JarScanType.TLD, \"foo.jar\")).isFalse();\n\t\tassertThat(jarScanFilter.check(JarScanType.TLD, \"bar.jar\")).isFalse();\n\t\tassertThat(jarScanFilter.check(JarScanType.TLD, \"test.jar\")).isTrue();\n\t}\n\n\t@Test\n\tvoid tldScanPatternsShouldBeAppliedToContextJarScanner() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\tJarScanFilter jarScanFilter = context.getJarScanner().getJarScanFilter();\n\t\tString tldScan = ((StandardJarScanFilter) jarScanFilter).getTldScan();\n\t\tassertThat(tldScan).isEqualTo(\"log4j-taglib*.jar,log4j-jakarta-web*.jar,log4javascript*.jar,slf4j-taglib*.jar\");\n\t}\n\n\t@Test\n\tvoid customTomcatHttpOnlyCookie() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().getCookie().setHttpOnly(false);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\tassertThat(context.getUseHttpOnly()).isFalse();\n\t}\n\n\t@Test\n\tvoid exceptionThrownOnLoadFailureWhenFailCtxIfServletStartFailsIsTrue() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.addContextCustomizers((context) -> {\n\t\t\tif (context instanceof StandardContext standardContext) {\n\t\t\t\tstandardContext.setFailCtxIfServletStartFails(true);\n\t\t\t}\n\t\t});\n\t\tthis.webServer = factory\n\t\t\t.getWebServer((context) -> context.addServlet(\"failing\", FailingServlet.class).setLoadOnStartup(0));\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(this.webServer::start);\n\t}\n\n\t@Test\n\tvoid exceptionThrownOnLoadFailureWhenFailCtxIfServletStartFailsIsFalse() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.addContextCustomizers((context) -> {\n\t\t\tif (context instanceof StandardContext standardContext) {\n\t\t\t\tstandardContext.setFailCtxIfServletStartFails(false);\n\t\t\t}\n\t\t});\n\t\tthis.webServer = factory\n\t\t\t.getWebServer((context) -> context.addServlet(\"failing\", FailingServlet.class).setLoadOnStartup(0));\n\t\tthis.webServer.start();\n\t}\n\n\t@Test\n\tvoid referenceClearingIsDisabled() {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tStandardContext context = (StandardContext) tomcat.getHost().findChildren()[0];\n\t\tassertThat(context.getClearReferencesRmiTargets()).isFalse();\n\t\tassertThat(context.getClearReferencesThreadLocals()).isFalse();\n\t}\n\n\t@Test\n\tvoid nonExistentUploadDirectoryIsCreatedUponMultipartUpload() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tAtomicReference<ServletContext> servletContextReference = new AtomicReference<>();\n\t\tfactory.addInitializers((servletContext) -> {\n\t\t\tservletContextReference.set(servletContext);\n\t\t\tDynamic servlet = servletContext.addServlet(\"upload\", new HttpServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t\treq.getParts();\n\t\t\t\t}\n\n\t\t\t});\n\t\t\tservlet.addMapping(\"/upload\");\n\t\t\tservlet.setMultipartConfig(new MultipartConfigElement((String) null));\n\t\t});\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tServletContext servletContext = servletContextReference.get();\n\t\tassertThat(servletContext).isNotNull();\n\t\tFile temp = (File) servletContext.getAttribute(ServletContext.TEMPDIR);\n\t\tFileSystemUtils.deleteRecursively(temp);\n\t\tRestTemplate restTemplate = new RestTemplate();\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\tMultiValueMap<String, Object> body = new LinkedMultiValueMap<>();\n\t\tbody.add(\"file\", new ByteArrayResource(new byte[1024 * 1024]));\n\t\theaders.setContentType(MediaType.MULTIPART_FORM_DATA);\n\t\tHttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);\n\t\tResponseEntity<String> response = restTemplate.postForEntity(getLocalUrl(\"/upload\"), requestEntity,\n\t\t\t\tString.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid exceptionThrownOnContextListenerDestroysServer() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0) {\n\n\t\t\t@Override\n\t\t\tprotected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {\n\t\t\t\ttry {\n\t\t\t\t\treturn super.getTomcatWebServer(tomcat);\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tassertThat(tomcat.getServer().getState()).isEqualTo(LifecycleState.DESTROYED);\n\t\t\t\t}\n\t\t\t}\n\n\t\t};\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(\n\t\t\t\t() -> factory.getWebServer((context) -> context.addListener(new FailingServletContextListener())));\n\t}\n\n\t@Test\n\tvoid registerJspServletWithDefaultLoadOnStartup() {\n\t\tTomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(0);\n\t\tfactory.addInitializers((context) -> context.addServlet(\"manually-registered-jsp-servlet\", JspServlet.class));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t}\n\n\t@Override\n\tprotected void assertThatSslWithInvalidAliasCallFails(ThrowingCallable call) {\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(call);\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownGracefullyThenNewConnectionsCannotBeMade() throws Exception {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingServlet);\n\t\t\tregistration.addMapping(\"/blocking\");\n\t\t\tregistration.setAsyncSupported(true);\n\t\t});\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tFuture<Object> request = initiateGetRequest(port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\tObject unconnectableRequest = Awaitility.await()\n\t\t\t.until(() -> initiateGetRequest(HttpClients.createDefault(), port, \"/\").get(),\n\t\t\t\t\t(result) -> result instanceof Exception);\n\t\tassertThat(unconnectableRequest).isInstanceOf(HttpHostConnectException.class);\n\t\tblockingServlet.admitOne();\n\t\tassertThat(request.get()).isInstanceOf(HttpResponse.class);\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\tvoid whenServerIsShuttingDownARequestOnAnIdleConnectionResultsInConnectionReset() throws Exception {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingServlet);\n\t\t\tregistration.addMapping(\"/blocking\");\n\t\t\tregistration.setAsyncSupported(true);\n\t\t});\n\t\tHttpClient httpClient = HttpClients.createMinimal();\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tFuture<Object> keepAliveRequest = initiateGetRequest(httpClient, port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tblockingServlet.admitOne();\n\t\tassertThat(keepAliveRequest.get()).isInstanceOf(HttpResponse.class);\n\t\tFuture<Object> request = initiateGetRequest(port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tthis.webServer.shutDownGracefully((result) -> {\n\t\t});\n\t\tObject idleConnectionRequestResult = Awaitility.await().until(() -> {\n\t\t\tFuture<Object> idleConnectionRequest = initiateGetRequest(httpClient, port, \"/\");\n\t\t\tObject result = idleConnectionRequest.get();\n\t\t\treturn result;\n\t\t}, (result) -> result instanceof Exception);\n\t\tassertThat(idleConnectionRequestResult).isInstanceOfAny(SocketException.class, NoHttpResponseException.class);\n\t\tif (idleConnectionRequestResult instanceof SocketException socketException) {\n\t\t\tassertThat(socketException).hasMessage(\"Connection reset\");\n\t\t}\n\t\tblockingServlet.admitOne();\n\t\tObject response = request.get();\n\t\tassertThat(response).isInstanceOf(HttpResponse.class);\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"1.crt\", \"1.key\", \"2.crt\", \"2.key\" })\n\tvoid shouldUpdateSslWhenReloadingSslBundles() throws Exception {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tDefaultSslBundleRegistry bundles = new DefaultSslBundleRegistry(\"test\",\n\t\t\t\tcreatePemSslBundle(\"classpath:1.crt\", \"classpath:1.key\"));\n\t\tfactory.setSslBundles(bundles);\n\t\tfactory.setSsl(Ssl.forBundle(\"test\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tRememberingHostnameVerifier verifier = new RememberingHostnameVerifier();\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();\n\t\tDefaultClientTlsStrategy tlsSocketStrategy = new DefaultClientTlsStrategy(sslContext,\n\t\t\t\tHostnameVerificationPolicy.CLIENT, verifier);\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(tlsSocketStrategy);\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t\tassertThat(verifier.getLastPrincipal()).isEqualTo(\"CN=1\");\n\t\trequestFactory = createHttpComponentsRequestFactory(tlsSocketStrategy);\n\t\tbundles.updateBundle(\"test\", createPemSslBundle(\"classpath:2.crt\", \"classpath:2.key\"));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t\tassertThat(verifier.getLastPrincipal()).isEqualTo(\"CN=2\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWithHttp11Nio2Protocol() throws Exception {\n\t\tTomcatServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setProtocol(Http11Nio2Protocol.class.getName());\n\t\tfactory.setSsl(getSsl(null, \"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tcreateTrustSelfSignedTlsSocketStrategy());\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Override\n\tprotected @Nullable JspServlet getJspServlet() throws ServletException {\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServer).getTomcat();\n\t\tContainer container = tomcat.getHost().findChildren()[0];\n\t\tStandardWrapper standardWrapper = (StandardWrapper) container.findChild(\"jsp\");\n\t\tif (standardWrapper == null) {\n\t\t\treturn null;\n\t\t}\n\t\tstandardWrapper.load();\n\t\treturn (JspServlet) standardWrapper.getServlet();\n\t}\n\n\t@Override\n\tprotected Map<String, String> getActualMimeMappings() {\n\t\tContext context = (Context) ((TomcatWebServer) this.webServer).getTomcat().getHost().findChildren()[0];\n\t\tMap<String, String> mimeMappings = new HashMap<>();\n\t\tfor (String extension : context.findMimeMappings()) {\n\t\t\tmimeMappings.put(extension, context.findMimeMapping(extension));\n\t\t}\n\t\treturn mimeMappings;\n\t}\n\n\t@Override\n\tprotected @Nullable Charset getCharset(Locale locale) {\n\t\tContext context = (Context) ((TomcatWebServer) this.webServer).getTomcat().getHost().findChildren()[0];\n\t\tCharsetMapper mapper = ((TomcatEmbeddedContext) context).getCharsetMapper();\n\t\tString charsetName = mapper.getCharset(locale);\n\t\treturn (charsetName != null) ? Charset.forName(charsetName) : null;\n\t}\n\n\tprivate void assertTimeout(TomcatServletWebServerFactory factory, int expected) {\n\t\tTomcat tomcat = getTomcat(factory);\n\t\tContext context = (Context) tomcat.getHost().findChildren()[0];\n\t\tassertThat(context.getSessionTimeout()).isEqualTo(expected);\n\t}\n\n\tprivate Tomcat getTomcat(TomcatServletWebServerFactory factory) {\n\t\tthis.webServer = factory.getWebServer();\n\t\treturn ((TomcatWebServer) this.webServer).getTomcat();\n\t}\n\n\t@Override\n\tprotected void handleExceptionCausedByBlockedPortOnPrimaryConnector(RuntimeException ex, int blockedPort) {\n\t\tassertThat(ex).isInstanceOf(PortInUseException.class);\n\t\tassertThat(((PortInUseException) ex).getPort()).isEqualTo(blockedPort);\n\t}\n\n\t@Override\n\tprotected void handleExceptionCausedByBlockedPortOnSecondaryConnector(RuntimeException ex, int blockedPort) {\n\t\tassertThat(ex).isInstanceOf(ConnectorStartFailedException.class);\n\t\tassertThat(((ConnectorStartFailedException) ex).getPort()).isEqualTo(blockedPort);\n\t}\n\n\t@Override\n\tprotected String startedLogMessage() {\n\t\treturn TomcatAccess.getStartedLogMessage((TomcatWebServer) this.webServer);\n\t}\n\n\tprivate static final class RememberingHostnameVerifier implements HostnameVerifier {\n\n\t\tprivate volatile @Nullable String lastPrincipal;\n\n\t\t@Override\n\t\tpublic boolean verify(String hostname, SSLSession session) {\n\t\t\ttry {\n\t\t\t\tthis.lastPrincipal = session.getPeerPrincipal().getName();\n\t\t\t}\n\t\t\tcatch (SSLPeerUnverifiedException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\t@Nullable String getLastPrincipal() {\n\t\t\treturn this.lastPrincipal;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/servlet/TomcatServletWebServerMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.context.AbstractServletWebServerMvcIntegrationTests;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Integration tests for {@link ServletWebServerApplicationContext} and\n * {@link TomcatWebServer} running Spring MVC.\n */\nclass TomcatServletWebServerMvcIntegrationTests extends AbstractServletWebServerMvcIntegrationTests {\n\n\tprotected TomcatServletWebServerMvcIntegrationTests() {\n\t\tsuper(TomcatConfig.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatConfig {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/java/org/springframework/boot/tomcat/servlet/TomcatServletWebServerServletContextListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.tomcat.servlet;\n\nimport jakarta.servlet.ServletContextListener;\n\nimport org.springframework.boot.web.server.servlet.AbstractServletWebServerServletContextListenerTests;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Tests for Tomcat driving {@link ServletContextListener}s correctly.\n *\n * @author Andy Wilkinson\n */\nclass TomcatServletWebServerServletContextListenerTests extends AbstractServletWebServerServletContextListenerTests {\n\n\tTomcatServletWebServerServletContextListenerTests() {\n\t\tsuper(TomcatConfiguration.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TomcatConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/resources/org/springframework/boot/tomcat/servlet/1.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBLjCB4aADAgECAhQ25wrNnapZEkFc8kgf5NDHXKxnTzAFBgMrZXAwDDEKMAgG\nA1UEAwwBMTAgFw0yMzEwMTAwODU1MTJaGA8yMTIzMDkxNjA4NTUxMlowDDEKMAgG\nA1UEAwwBMTAqMAUGAytlcAMhAOyxNxHzcNj7xTkcjVLI09sYUGUGIvdV5s0YWXT8\nXAiwo1MwUTAdBgNVHQ4EFgQUmm23oLIu5MgdBb/snZSuE+MrRZ0wHwYDVR0jBBgw\nFoAUmm23oLIu5MgdBb/snZSuE+MrRZ0wDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXAD\nQQA2KMpIyySC8u4onW2MVW1iK2dJJZbMRaNMLlQuE+ZIHQLwflYW4sH/Pp76pboc\nQhqKXcO7xH7f2tD5hE2izcUB\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/resources/org/springframework/boot/tomcat/servlet/1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIJb1A+i5bmilBD9mUbhk1oFVI6FAZQGnhduv7xV6WWEc\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/resources/org/springframework/boot/tomcat/servlet/2.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBLjCB4aADAgECAhR4TMDk3qg5sKREp16lEHR3bV3M9zAFBgMrZXAwDDEKMAgG\nA1UEAwwBMjAgFw0yMzEwMTAwODU1MjBaGA8yMTIzMDkxNjA4NTUyMFowDDEKMAgG\nA1UEAwwBMjAqMAUGAytlcAMhADPft6hzyCjHCe5wSprChuuO/CuPIJ2t+l4roS1D\n43/wo1MwUTAdBgNVHQ4EFgQUfrRibAWml4Ous4kpnBIggM2xnLcwHwYDVR0jBBgw\nFoAUfrRibAWml4Ous4kpnBIggM2xnLcwDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXAD\nQQC/MOclal2Cp0B3kmaLbK0M8mapclIOJa78hzBkqPA3URClAF2GmF187wHqi7qV\n+xZ+KWv26pLJR46vk8Kc6ZIO\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-tomcat/src/test/resources/org/springframework/boot/tomcat/servlet/2.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICxhres2Z2lICm7/isnm+2iNR12GmgG7KK86BNDZDeIF\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-transaction/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Transaction\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-persistence\"))\n\tapi(\"org.springframework:spring-tx\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"jakarta.transaction:jakarta.transaction-api\")\n\toptional(\"org.springframework:spring-aspects\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.github.h-thurow:simple-jndi\")\n\ttestImplementation(\"com.zaxxer:HikariCP\")\n\ttestImplementation(\"org.hsqldb:hsqldb\")\n\ttestImplementation(\"org.springframework:spring-jdbc\")\n\n\ttestRuntimeOnly(project(\":module:spring-boot-reactor\"))\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(project(\":module:spring-boot-reactor\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/ExecutionListenersTransactionManagerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.transaction.ConfigurableTransactionManager;\nimport org.springframework.transaction.TransactionExecutionListener;\n\n/**\n * {@link TransactionManagerCustomizer} that adds {@link TransactionExecutionListener\n * execution listeners} to any transaction manager that is\n * {@link ConfigurableTransactionManager configurable}.\n *\n * @author Andy Wilkinson\n */\nclass ExecutionListenersTransactionManagerCustomizer\n\t\timplements TransactionManagerCustomizer<ConfigurableTransactionManager> {\n\n\tprivate final List<TransactionExecutionListener> listeners;\n\n\tExecutionListenersTransactionManagerCustomizer(List<TransactionExecutionListener> listeners) {\n\t\tthis.listeners = listeners;\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableTransactionManager transactionManager) {\n\t\tthis.listeners.forEach(transactionManager::addListener);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/TransactionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.ReactiveTransactionManager;\nimport org.springframework.transaction.TransactionManager;\nimport org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.aspectj.AbstractTransactionAspect;\nimport org.springframework.transaction.reactive.TransactionalOperator;\nimport org.springframework.transaction.support.TransactionOperations;\nimport org.springframework.transaction.support.TransactionTemplate;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration\n * Auto-configuration} for Spring transaction.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(PlatformTransactionManager.class)\npublic final class TransactionAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnSingleCandidate(ReactiveTransactionManager.class)\n\tTransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) {\n\t\treturn TransactionalOperator.create(transactionManager);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnSingleCandidate(PlatformTransactionManager.class)\n\tstatic class TransactionTemplateConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(TransactionOperations.class)\n\t\tTransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {\n\t\t\treturn new TransactionTemplate(transactionManager);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(TransactionManager.class)\n\t@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)\n\tstatic class EnableTransactionManagementConfiguration {\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableTransactionManagement(proxyTargetClass = false)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.aop.proxy-target-class\", havingValue = false)\n\t\tstatic class JdkDynamicAutoProxyConfiguration {\n\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\t@EnableTransactionManagement(proxyTargetClass = true)\n\t\t@ConditionalOnBooleanProperty(name = \"spring.aop.proxy-target-class\", matchIfMissing = true)\n\t\tstatic class CglibAutoProxyConfiguration {\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(AbstractTransactionAspect.class)\n\tstatic class AspectJTransactionManagementConfiguration {\n\n\t\t@Bean\n\t\tstatic LazyInitializationExcludeFilter eagerTransactionAspect() {\n\t\t\treturn LazyInitializationExcludeFilter.forBeanTypes(AbstractTransactionAspect.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/TransactionManagerCustomizationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionExecutionListener;\nimport org.springframework.transaction.TransactionManager;\n\n/**\n * Auto-configuration for the customization of a {@link TransactionManager}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ConditionalOnClass(PlatformTransactionManager.class)\n@AutoConfiguration(before = TransactionAutoConfiguration.class)\n@EnableConfigurationProperties(TransactionProperties.class)\npublic final class TransactionManagerCustomizationAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tTransactionManagerCustomizers platformTransactionManagerCustomizers(\n\t\t\tObjectProvider<TransactionManagerCustomizer<?>> customizers) {\n\t\treturn TransactionManagerCustomizers.of(customizers.orderedStream().toList());\n\t}\n\n\t@Bean\n\tExecutionListenersTransactionManagerCustomizer transactionExecutionListeners(\n\t\t\tObjectProvider<TransactionExecutionListener> listeners) {\n\t\treturn new ExecutionListenersTransactionManagerCustomizer(listeners.orderedStream().toList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/TransactionManagerCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport org.springframework.transaction.TransactionManager;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize a\n * {@link TransactionManager} to fine-tune its auto-configuration.\n *\n * @param <T> the transaction manager type\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface TransactionManagerCustomizer<T extends TransactionManager> {\n\n\t/**\n\t * Customize the given transaction manager.\n\t * @param transactionManager the transaction manager to customize\n\t */\n\tvoid customize(T transactionManager);\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/TransactionManagerCustomizers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.transaction.TransactionManager;\n\n/**\n * A collection of {@link TransactionManagerCustomizer TransactionManagerCustomizers}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic final class TransactionManagerCustomizers {\n\n\tprivate final List<? extends TransactionManagerCustomizer<?>> customizers;\n\n\tprivate TransactionManagerCustomizers(List<? extends TransactionManagerCustomizer<?>> customizers) {\n\t\tthis.customizers = customizers;\n\t}\n\n\t/**\n\t * Customize the given {@code transactionManager}.\n\t * @param transactionManager the transaction manager to customize\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic void customize(TransactionManager transactionManager) {\n\t\tLambdaSafe.callbacks(TransactionManagerCustomizer.class, this.customizers, transactionManager)\n\t\t\t.withLogger(TransactionManagerCustomizers.class)\n\t\t\t.invoke((customizer) -> customizer.customize(transactionManager));\n\t}\n\n\t/**\n\t * Returns a new {@code TransactionManagerCustomizers} instance containing the given\n\t * {@code customizers}.\n\t * @param customizers the customizers\n\t * @return the new instance\n\t */\n\tpublic static TransactionManagerCustomizers of(\n\t\t\t@Nullable Collection<? extends TransactionManagerCustomizer<?>> customizers) {\n\t\treturn new TransactionManagerCustomizers(\n\t\t\t\t(customizers != null) ? new ArrayList<>(customizers) : Collections.emptyList());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/TransactionProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.transaction.support.AbstractPlatformTransactionManager;\n\n/**\n * Configuration properties that can be applied to an\n * {@link AbstractPlatformTransactionManager}.\n *\n * @author Kazuki Shimizu\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.transaction\")\npublic class TransactionProperties implements TransactionManagerCustomizer<AbstractPlatformTransactionManager> {\n\n\t/**\n\t * Default transaction timeout. If a duration suffix is not specified, seconds will be\n\t * used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate @Nullable Duration defaultTimeout;\n\n\t/**\n\t * Whether to roll back on commit failures.\n\t */\n\tprivate @Nullable Boolean rollbackOnCommitFailure;\n\n\tpublic @Nullable Duration getDefaultTimeout() {\n\t\treturn this.defaultTimeout;\n\t}\n\n\tpublic void setDefaultTimeout(@Nullable Duration defaultTimeout) {\n\t\tthis.defaultTimeout = defaultTimeout;\n\t}\n\n\tpublic @Nullable Boolean getRollbackOnCommitFailure() {\n\t\treturn this.rollbackOnCommitFailure;\n\t}\n\n\tpublic void setRollbackOnCommitFailure(@Nullable Boolean rollbackOnCommitFailure) {\n\t\tthis.rollbackOnCommitFailure = rollbackOnCommitFailure;\n\t}\n\n\t@Override\n\tpublic void customize(AbstractPlatformTransactionManager transactionManager) {\n\t\tif (this.defaultTimeout != null) {\n\t\t\ttransactionManager.setDefaultTimeout((int) this.defaultTimeout.getSeconds());\n\t\t}\n\t\tif (this.rollbackOnCommitFailure != null) {\n\t\t\ttransactionManager.setRollbackOnCommitFailure(this.rollbackOnCommitFailure);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for transaction support.\n */\n@NullMarked\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/jta/autoconfigure/JndiJtaConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.jta.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnJndi;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizers;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\n/**\n * JTA Configuration for a JNDI-managed {@link JtaTransactionManager}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Kazuki Shimizu\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(JtaTransactionManager.class)\n@ConditionalOnJndi({ JtaTransactionManager.DEFAULT_USER_TRANSACTION_NAME, \"java:comp/TransactionManager\",\n\t\t\"java:appserver/TransactionManager\", \"java:pm/TransactionManager\", \"java:/TransactionManager\" })\n@ConditionalOnMissingBean(org.springframework.transaction.TransactionManager.class)\nclass JndiJtaConfiguration {\n\n\t@Bean\n\tJtaTransactionManager transactionManager(\n\t\t\tObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {\n\t\tJtaTransactionManager jtaTransactionManager = new JtaTransactionManager();\n\t\ttransactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(jtaTransactionManager));\n\t\treturn jtaTransactionManager;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/jta/autoconfigure/JtaAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.jta.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for JTA.\n *\n * @author Josh Long\n * @author Phillip Webb\n * @author Nishant Raut\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbefore = { TransactionAutoConfiguration.class, TransactionManagerCustomizationAutoConfiguration.class })\n@ConditionalOnClass(jakarta.transaction.Transaction.class)\n@ConditionalOnBooleanProperty(name = \"spring.jta.enabled\", matchIfMissing = true)\n@Import(JndiJtaConfiguration.class)\npublic final class JtaAutoConfiguration {\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/java/org/springframework/boot/transaction/jta/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for JTA.\n */\n@NullMarked\npackage org.springframework.boot.transaction.jta.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.jta.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable JTA support.\",\n      \"defaultValue\": true\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration\norg.springframework.boot.transaction.autoconfigure.TransactionManagerCustomizationAutoConfiguration\norg.springframework.boot.transaction.jta.autoconfigure.JtaAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-transaction/src/test/java/org/springframework/boot/transaction/autoconfigure/ExecutionListenersTransactionManagerCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.transaction.ConfigurableTransactionManager;\nimport org.springframework.transaction.TransactionExecutionListener;\n\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ExecutionListenersTransactionManagerCustomizer}.\n *\n * @author Andy Wilkinson\n */\nclass ExecutionListenersTransactionManagerCustomizerTests {\n\n\t@Test\n\tvoid whenTransactionManagerIsCustomizedThenExecutionListenersAreAddedToIt() {\n\t\tTransactionExecutionListener listener1 = mock(TransactionExecutionListener.class);\n\t\tTransactionExecutionListener listener2 = mock(TransactionExecutionListener.class);\n\t\tConfigurableTransactionManager transactionManager = mock(ConfigurableTransactionManager.class);\n\t\tnew ExecutionListenersTransactionManagerCustomizer(List.of(listener1, listener2)).customize(transactionManager);\n\t\tthen(transactionManager).should().addListener(listener1);\n\t\tthen(transactionManager).should().addListener(listener2);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/test/java/org/springframework/boot/transaction/autoconfigure/TransactionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.AdviceMode;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.ReactiveTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.transaction.aspectj.AbstractTransactionAspect;\nimport org.springframework.transaction.reactive.TransactionalOperator;\nimport org.springframework.transaction.support.TransactionSynchronizationManager;\nimport org.springframework.transaction.support.TransactionTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TransactionAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass TransactionAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(TransactionAutoConfiguration.class));\n\n\t@Test\n\tvoid whenThereIsNoPlatformTransactionManagerNoTransactionTemplateIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(TransactionTemplate.class));\n\t}\n\n\t@Test\n\tvoid whenThereIsASinglePlatformTransactionManagerATransactionTemplateIsAutoConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(SinglePlatformTransactionManagerConfiguration.class).run((context) -> {\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tTransactionTemplate transactionTemplate = context.getBean(TransactionTemplate.class);\n\t\t\tassertThat(transactionTemplate.getTransactionManager()).isSameAs(transactionManager);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenThereIsASingleReactiveTransactionManagerATransactionalOperatorIsAutoConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(SingleReactiveTransactionManagerConfiguration.class).run((context) -> {\n\t\t\tReactiveTransactionManager transactionManager = context.getBean(ReactiveTransactionManager.class);\n\t\t\tTransactionalOperator transactionalOperator = context.getBean(TransactionalOperator.class);\n\t\t\tassertThat(transactionalOperator).extracting(\"transactionManager\").isSameAs(transactionManager);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenThereAreBothReactiveAndPlatformTransactionManagersATemplateAndAnOperatorAreAutoConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(SinglePlatformTransactionManagerConfiguration.class,\n\t\t\t\t\tSingleReactiveTransactionManagerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.datasource.url:jdbc:h2:mem:\" + UUID.randomUUID())\n\t\t\t.run((context) -> {\n\t\t\t\tPlatformTransactionManager platformTransactionManager = context\n\t\t\t\t\t.getBean(PlatformTransactionManager.class);\n\t\t\t\tTransactionTemplate transactionTemplate = context.getBean(TransactionTemplate.class);\n\t\t\t\tassertThat(transactionTemplate.getTransactionManager()).isSameAs(platformTransactionManager);\n\t\t\t\tReactiveTransactionManager reactiveTransactionManager = context\n\t\t\t\t\t.getBean(ReactiveTransactionManager.class);\n\t\t\t\tTransactionalOperator transactionalOperator = context.getBean(TransactionalOperator.class);\n\t\t\t\tassertThat(transactionalOperator).extracting(\"transactionManager\").isSameAs(reactiveTransactionManager);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenThereAreSeveralPlatformTransactionManagersNoTransactionTemplateIsAutoConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(SeveralPlatformTransactionManagersConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TransactionTemplate.class));\n\t}\n\n\t@Test\n\tvoid whenThereAreSeveralReactiveTransactionManagersNoTransactionOperatorIsAutoConfigured() {\n\t\tthis.contextRunner.withUserConfiguration(SeveralReactiveTransactionManagersConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(TransactionalOperator.class));\n\t}\n\n\t@Test\n\tvoid whenAUserProvidesATransactionTemplateTheAutoConfiguredTemplateBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomPlatformTransactionManagerConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(TransactionTemplate.class);\n\t\t\tassertThat(context.getBean(\"transactionTemplateFoo\")).isInstanceOf(TransactionTemplate.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenAUserProvidesATransactionalOperatorTheAutoConfiguredOperatorBacksOff() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(SingleReactiveTransactionManagerConfiguration.class,\n\t\t\t\t\tCustomTransactionalOperatorConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(TransactionalOperator.class);\n\t\t\t\tassertThat(context.getBean(\"customTransactionalOperator\")).isInstanceOf(TransactionalOperator.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid transactionNotManagedWithNoTransactionManager() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(TransactionalService.class).isTransactionActive()).isFalse());\n\t}\n\n\t@Test\n\tvoid transactionManagerUsesCglibByDefault() {\n\t\tthis.contextRunner.withUserConfiguration(PlatformTransactionManagersConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBean(AnotherServiceImpl.class).isTransactionActive()).isTrue();\n\t\t\tassertThat(context.getBeansOfType(TransactionalServiceImpl.class)).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid transactionManagerCanBeConfiguredToJdkProxy() {\n\t\tthis.contextRunner.withUserConfiguration(PlatformTransactionManagersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.aop.proxy-target-class=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(AnotherService.class).isTransactionActive()).isTrue();\n\t\t\t\tassertThat(context).doesNotHaveBean(AnotherServiceImpl.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(TransactionalServiceImpl.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customEnableTransactionManagementTakesPrecedence() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomTransactionManagementConfiguration.class,\n\t\t\t\t\tPlatformTransactionManagersConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.aop.proxy-target-class=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(AnotherService.class).isTransactionActive()).isTrue();\n\t\t\t\tassertThat(context).doesNotHaveBean(AnotherServiceImpl.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(TransactionalServiceImpl.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid excludesAbstractTransactionAspectFromLazyInit() {\n\t\tthis.contextRunner.withUserConfiguration(AspectJTransactionManagementConfiguration.class).run((context) -> {\n\t\t\tLazyInitializationExcludeFilter filter = context.getBean(LazyInitializationExcludeFilter.class);\n\t\t\tassertThat(filter.isExcluded(\"bean\", mock(BeanDefinition.class), AbstractTransactionAspect.class)).isTrue();\n\t\t});\n\t}\n\n\t@Configuration\n\tstatic class SinglePlatformTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn mock(PlatformTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class SingleReactiveTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tReactiveTransactionManager reactiveTransactionManager() {\n\t\t\treturn mock(ReactiveTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SeveralPlatformTransactionManagersConfiguration {\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManagerOne() {\n\t\t\treturn mock(PlatformTransactionManager.class);\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManagerTwo() {\n\t\t\treturn mock(PlatformTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SeveralReactiveTransactionManagersConfiguration {\n\n\t\t@Bean\n\t\tReactiveTransactionManager reactiveTransactionManager1() {\n\t\t\treturn mock(ReactiveTransactionManager.class);\n\t\t}\n\n\t\t@Bean\n\t\tReactiveTransactionManager reactiveTransactionManager2() {\n\t\t\treturn mock(ReactiveTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomPlatformTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tTransactionTemplate transactionTemplateFoo(PlatformTransactionManager transactionManager) {\n\t\t\treturn new TransactionTemplate(transactionManager);\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManagerFoo() {\n\t\t\treturn mock(PlatformTransactionManager.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTransactionalOperatorConfiguration {\n\n\t\t@Bean\n\t\tTransactionalOperator customTransactionalOperator() {\n\t\t\treturn mock(TransactionalOperator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tTransactionalService transactionalService() {\n\t\t\treturn new TransactionalServiceImpl();\n\t\t}\n\n\t\t@Bean\n\t\tAnotherServiceImpl anotherService() {\n\t\t\treturn new AnotherServiceImpl();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class PlatformTransactionManagersConfiguration {\n\n\t\t@Bean\n\t\tDataSourceTransactionManager transactionManager(DataSource dataSource) {\n\t\t\treturn new DataSourceTransactionManager(dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\tHikariDataSource dataSource = new HikariDataSource();\n\t\t\tdataSource.setDriverClassName(\"org.hsqldb.jdbc.JDBCDriver\");\n\t\t\tdataSource.setJdbcUrl(\"jdbc:hsqldb:mem:tx\");\n\t\t\tdataSource.setUsername(\"sa\");\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableTransactionManagement(proxyTargetClass = false)\n\tstatic class CustomTransactionManagementConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)\n\tstatic class AspectJTransactionManagementConfiguration {\n\n\t}\n\n\tinterface TransactionalService {\n\n\t\t@Transactional\n\t\tboolean isTransactionActive();\n\n\t}\n\n\tstatic class TransactionalServiceImpl implements TransactionalService {\n\n\t\t@Override\n\t\tpublic boolean isTransactionActive() {\n\t\t\treturn TransactionSynchronizationManager.isActualTransactionActive();\n\t\t}\n\n\t}\n\n\tinterface AnotherService {\n\n\t\tboolean isTransactionActive();\n\n\t}\n\n\tstatic class AnotherServiceImpl implements AnotherService {\n\n\t\t@Override\n\t\t@Transactional\n\t\tpublic boolean isTransactionActive() {\n\t\t\treturn TransactionSynchronizationManager.isActualTransactionActive();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/test/java/org/springframework/boot/transaction/autoconfigure/TransactionManagerCustomizationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link TransactionManagerCustomizationAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass TransactionManagerCustomizationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(TransactionManagerCustomizationAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguresTransactionManagerCustomizers() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.transaction.default-timeout=30s\").run((context) -> {\n\t\t\tTransactionManagerCustomizers customizers = context.getBean(TransactionManagerCustomizers.class);\n\t\t\tassertThat(customizers).extracting(\"customizers\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.hasSize(2)\n\t\t\t\t.hasAtLeastOneElementOfType(TransactionProperties.class)\n\t\t\t\t.hasAtLeastOneElementOfType(ExecutionListenersTransactionManagerCustomizer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid autoConfiguredTransactionManagerCustomizersBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(CustomTransactionManagerCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTransactionManagerCustomizers customizers = context.getBean(TransactionManagerCustomizers.class);\n\t\t\t\tassertThat(customizers).extracting(\"customizers\")\n\t\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t\t.isEmpty();\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTransactionManagerCustomizersConfiguration {\n\n\t\t@Bean\n\t\tTransactionManagerCustomizers customTransactionManagerCustomizers() {\n\t\t\treturn TransactionManagerCustomizers.of(Collections.<TransactionManagerCustomizer<?>>emptyList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/test/java/org/springframework/boot/transaction/autoconfigure/TransactionManagerCustomizersTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.TransactionManager;\nimport org.springframework.transaction.jta.JtaTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link TransactionManagerCustomizers}.\n *\n * @author Phillip Webb\n */\nclass TransactionManagerCustomizersTests {\n\n\t@Test\n\tvoid customizeWithNullCustomizersShouldDoNothing() {\n\t\tTransactionManagerCustomizers.of(null).customize(mock(TransactionManager.class));\n\t}\n\n\t@Test\n\tvoid customizeShouldCheckGeneric() {\n\t\tList<TestCustomizer<?>> list = new ArrayList<>();\n\t\tlist.add(new TestCustomizer<>());\n\t\tlist.add(new TestJtaCustomizer());\n\t\tTransactionManagerCustomizers customizers = TransactionManagerCustomizers.of(list);\n\t\tcustomizers.customize(mock(PlatformTransactionManager.class));\n\t\tcustomizers.customize(mock(JtaTransactionManager.class));\n\t\tassertThat(list.get(0).getCount()).isEqualTo(2);\n\t\tassertThat(list.get(1).getCount()).isOne();\n\t}\n\n\tstatic class TestCustomizer<T extends PlatformTransactionManager> implements TransactionManagerCustomizer<T> {\n\n\t\tprivate int count;\n\n\t\t@Override\n\t\tpublic void customize(T transactionManager) {\n\t\t\tthis.count++;\n\t\t}\n\n\t\tint getCount() {\n\t\t\treturn this.count;\n\t\t}\n\n\t}\n\n\tstatic class TestJtaCustomizer extends TestCustomizer<JtaTransactionManager> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/test/java/org/springframework/boot/transaction/jta/autoconfigure/JtaAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.transaction.jta.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Properties;\n\nimport javax.naming.Context;\nimport javax.naming.InitialContext;\nimport javax.naming.NamingException;\n\nimport jakarta.transaction.TransactionManager;\nimport jakarta.transaction.UserTransaction;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ExtensionContext.Namespace;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolutionException;\nimport org.junit.jupiter.api.extension.ParameterResolver;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\nimport org.osjava.sj.loader.JndiLoader;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.jta.JtaTransactionManager;\nimport org.springframework.transaction.jta.UserTransactionAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link JtaAutoConfiguration}.\n *\n * @author Josh Long\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Kazuki Shimizu\n * @author Nishant Raut\n */\n@ClassPathExclusions(\"jetty-jndi-*.jar\")\nclass JtaAutoConfigurationTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\n\t}\n\n\t@ParameterizedTest\n\t@ExtendWith(JndiExtension.class)\n\t@MethodSource(\"transactionManagerJndiEntries\")\n\tvoid transactionManagerFromJndi(JndiEntry jndiEntry, InitialContext initialContext) throws NamingException {\n\t\tjndiEntry.register(initialContext);\n\t\tthis.context = new AnnotationConfigApplicationContext(JtaAutoConfiguration.class);\n\t\tJtaTransactionManager transactionManager = this.context.getBean(JtaTransactionManager.class);\n\t\tif (jndiEntry.value instanceof UserTransaction) {\n\t\t\tassertThat(transactionManager.getUserTransaction()).isEqualTo(jndiEntry.value);\n\t\t\tassertThat(transactionManager.getTransactionManager()).isNull();\n\t\t}\n\t\telse {\n\t\t\tassertThat(transactionManager.getUserTransaction()).isInstanceOf(UserTransactionAdapter.class);\n\t\t\tassertThat(transactionManager.getTransactionManager()).isEqualTo(jndiEntry.value);\n\t\t}\n\t}\n\n\tstatic List<Arguments> transactionManagerJndiEntries() {\n\t\treturn Arrays.asList(Arguments.of(new JndiEntry(\"java:comp/UserTransaction\", UserTransaction.class)),\n\t\t\t\tArguments.of(new JndiEntry(\"java:appserver/TransactionManager\", TransactionManager.class)),\n\t\t\t\tArguments.of(new JndiEntry(\"java:pm/TransactionManager\", TransactionManager.class)),\n\t\t\t\tArguments.of(new JndiEntry(\"java:/TransactionManager\", TransactionManager.class)));\n\t}\n\n\t@Test\n\tvoid customTransactionManager() {\n\t\tthis.context = new AnnotationConfigApplicationContext(CustomTransactionManagerConfig.class,\n\t\t\t\tJtaAutoConfiguration.class);\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {\n\t\t\tassertThat(this.context).isNotNull();\n\t\t\tthis.context.getBean(JtaTransactionManager.class);\n\t\t});\n\t}\n\n\t@Test\n\t@ExtendWith(JndiExtension.class)\n\tvoid disableJtaSupport(InitialContext initialContext) throws NamingException {\n\t\tnew JndiEntry(\"java:comp/UserTransaction\", UserTransaction.class).register(initialContext);\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues.of(\"spring.jta.enabled:false\").applyTo(this.context);\n\t\tthis.context.register(JtaAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBeansOfType(JtaTransactionManager.class)).isEmpty();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomTransactionManagerConfig {\n\n\t\t@Bean\n\t\torg.springframework.transaction.TransactionManager testTransactionManager() {\n\t\t\treturn mock(org.springframework.transaction.TransactionManager.class);\n\t\t}\n\n\t}\n\n\tprivate static final class JndiEntry {\n\n\t\tprivate final String name;\n\n\t\tprivate final Class<?> type;\n\n\t\tprivate final Object value;\n\n\t\tprivate JndiEntry(String name, Class<?> type) {\n\t\t\tthis.name = name;\n\t\t\tthis.type = type;\n\t\t\tthis.value = mock(type);\n\t\t}\n\n\t\tprivate void register(InitialContext initialContext) throws NamingException {\n\t\t\tString[] components = this.name.split(\"/\");\n\t\t\tString subcontextName = components[0];\n\t\t\tString entryName = components[1];\n\t\t\tContext javaComp = initialContext.createSubcontext(subcontextName);\n\t\t\tJndiLoader loader = new JndiLoader(initialContext.getEnvironment());\n\t\t\tProperties properties = new Properties();\n\t\t\tproperties.setProperty(entryName + \"/type\", this.type.getName());\n\t\t\tproperties.put(entryName + \"/valueToConvert\", this.value);\n\t\t\tloader.load(properties, javaComp);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tprivate static final class JndiExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {\n\n\t\t@Override\n\t\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\t\tNamespace namespace = Namespace.create(getClass(), context.getUniqueId());\n\t\t\tcontext.getStore(namespace)\n\t\t\t\t.computeIfAbsent(InitialContext.class, (k) -> createInitialContext(), InitialContext.class);\n\t\t}\n\n\t\tprivate InitialContext createInitialContext() {\n\t\t\ttry {\n\t\t\t\treturn new InitialContext();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tthrow new RuntimeException();\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\t\tNamespace namespace = Namespace.create(getClass(), context.getUniqueId());\n\t\t\tInitialContext initialContext = context.getStore(namespace)\n\t\t\t\t.remove(InitialContext.class, InitialContext.class);\n\t\t\tassertThat(initialContext).isNotNull();\n\t\t\tinitialContext.removeFromEnvironment(\"org.osjava.sj.jndi.ignoreClose\");\n\t\t\tinitialContext.close();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\t\tthrows ParameterResolutionException {\n\t\t\treturn InitialContext.class.isAssignableFrom(parameterContext.getParameter().getType());\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\t\tthrows ParameterResolutionException {\n\t\t\tNamespace namespace = Namespace.create(getClass(), extensionContext.getUniqueId());\n\t\t\treturn extensionContext.getStore(namespace).get(InitialContext.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-transaction/src/test/resources/jndi.properties",
    "content": "java.naming.factory.initial = org.osjava.sj.SimpleJndiContextFactory\norg.osjava.sj.delimiter = /\norg.osjava.sj.jndi.shared = true\norg.osjava.sj.root = src/test/resources/simple-jndi\norg.osjava.sj.jndi.ignoreClose = true"
  },
  {
    "path": "module/spring-boot-transaction/src/test/resources/simple-jndi",
    "content": ""
  },
  {
    "path": "module/spring-boot-validation/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Validation\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.apache.tomcat.embed:tomcat-embed-el\")\n\tapi(\"org.hibernate.validator:hibernate-validator\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/java/org/springframework/boot/validation/autoconfigure/JakartaValidationBackgroundPreinitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport jakarta.validation.Configuration;\nimport jakarta.validation.Validation;\n\nimport org.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer;\n\n/**\n * {@link BackgroundPreinitializer} for jakarta.validation.\n *\n * @author Phillip Webb\n */\nfinal class JakartaValidationBackgroundPreinitializer implements BackgroundPreinitializer {\n\n\t@Override\n\tpublic void preinitialize() throws Exception {\n\t\tConfiguration<?> configuration = Validation.byDefaultProvider().configure();\n\t\tconfiguration.buildValidatorFactory().getValidator();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/java/org/springframework/boot/validation/autoconfigure/PrimaryDefaultValidatorPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\n\n/**\n * Enable the {@code Primary} flag on the auto-configured validator if necessary.\n * <p>\n * As {@link LocalValidatorFactoryBean} exposes 3 validator related contracts and we're\n * only checking for the absence {@link jakarta.validation.Validator}, we should flag the\n * auto-configured validator as primary only if no Spring's {@link Validator} is flagged\n * as primary.\n *\n * @author Stephane Nicoll\n * @author Matej Nedic\n * @author Andy Wilkinson\n */\nclass PrimaryDefaultValidatorPostProcessor implements ImportBeanDefinitionRegistrar, BeanFactoryAware {\n\n\t/**\n\t * The bean name of the auto-configured Validator.\n\t */\n\tprivate static final String VALIDATOR_BEAN_NAME = \"defaultValidator\";\n\n\tprivate @Nullable ConfigurableListableBeanFactory beanFactory;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\tif (beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {\n\t\t\tthis.beanFactory = listableBeanFactory;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tBeanDefinition definition = getAutoConfiguredValidator(registry);\n\t\tif (definition != null) {\n\t\t\tdefinition.setPrimary(!hasPrimarySpringValidator());\n\t\t}\n\t}\n\n\tprivate @Nullable BeanDefinition getAutoConfiguredValidator(BeanDefinitionRegistry registry) {\n\t\tif (registry.containsBeanDefinition(VALIDATOR_BEAN_NAME)) {\n\t\t\tBeanDefinition definition = registry.getBeanDefinition(VALIDATOR_BEAN_NAME);\n\t\t\tif (definition.getRole() == BeanDefinition.ROLE_INFRASTRUCTURE\n\t\t\t\t\t&& isTypeMatch(VALIDATOR_BEAN_NAME, LocalValidatorFactoryBean.class)) {\n\t\t\t\treturn definition;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isTypeMatch(String name, Class<?> type) {\n\t\treturn this.beanFactory != null && this.beanFactory.isTypeMatch(name, type);\n\t}\n\n\tprivate boolean hasPrimarySpringValidator() {\n\t\tAssert.state(this.beanFactory != null, \"'beanFactory' must not be null\");\n\t\tString[] validatorBeans = this.beanFactory.getBeanNamesForType(Validator.class, false, false);\n\t\tfor (String validatorBean : validatorBeans) {\n\t\t\tBeanDefinition definition = this.beanFactory.getBeanDefinition(validatorBean);\n\t\t\tif (definition.isPrimary()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/java/org/springframework/boot/validation/autoconfigure/ValidationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport jakarta.validation.Validator;\nimport jakarta.validation.executable.ExecutableValidator;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnResource;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.validation.MessageInterpolatorFactory;\nimport org.springframework.boot.validation.beanvalidation.FilteredMethodValidationPostProcessor;\nimport org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.core.env.Environment;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to configure the validation\n * infrastructure.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @author Yanming Zhou\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(ExecutableValidator.class)\n@ConditionalOnResource(resources = \"classpath:META-INF/services/jakarta.validation.spi.ValidationProvider\")\n@Import(PrimaryDefaultValidatorPostProcessor.class)\npublic final class ValidationAutoConfiguration {\n\n\t@Bean\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t@ConditionalOnMissingBean(Validator.class)\n\tstatic LocalValidatorFactoryBean defaultValidator(ApplicationContext applicationContext,\n\t\t\tObjectProvider<ValidationConfigurationCustomizer> customizers) {\n\t\tLocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();\n\t\tfactoryBean.setConfigurationInitializer((configuration) -> customizers.orderedStream()\n\t\t\t.forEach((customizer) -> customizer.customize(configuration)));\n\t\tMessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory(applicationContext);\n\t\tfactoryBean.setMessageInterpolator(interpolatorFactory.getObject());\n\t\treturn factoryBean;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)\n\tstatic MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,\n\t\t\tObjectProvider<Validator> validator, ObjectProvider<MethodValidationExcludeFilter> excludeFilters) {\n\t\tFilteredMethodValidationPostProcessor processor = new FilteredMethodValidationPostProcessor(\n\t\t\t\texcludeFilters.orderedStream());\n\t\tboolean proxyTargetClass = environment.getProperty(\"spring.aop.proxy-target-class\", Boolean.class, true);\n\t\tprocessor.setProxyTargetClass(proxyTargetClass);\n\t\tboolean adaptConstraintViolations = environment\n\t\t\t.getProperty(\"spring.validation.method.adapt-constraint-violations\", Boolean.class, false);\n\t\tprocessor.setAdaptConstraintViolations(adaptConstraintViolations);\n\t\tprocessor.setValidatorProvider(validator);\n\t\treturn processor;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/java/org/springframework/boot/validation/autoconfigure/ValidationConfigurationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport jakarta.validation.Configuration;\n\n/**\n * Callback interface that can be used to customize {@link Configuration}.\n *\n * @author Dang Zhicairang\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ValidationConfigurationCustomizer {\n\n\t/**\n\t * Customize the given {@code configuration}.\n\t * @param configuration the configuration to customize\n\t */\n\tvoid customize(Configuration<?> configuration);\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/java/org/springframework/boot/validation/autoconfigure/ValidatorAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport jakarta.validation.ValidationException;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.validation.MessageInterpolatorFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.MessageSource;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.SmartValidator;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;\nimport org.springframework.validation.beanvalidation.SpringValidatorAdapter;\n\n/**\n * {@link Validator} implementation that delegates calls to another {@link Validator}.\n * This {@link Validator} implements Spring's {@link SmartValidator} interface but does\n * not implement the JSR-303 {@code jakarta.validator.Validator} interface.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Zisis Pavloudis\n * @since 4.0.0\n */\npublic class ValidatorAdapter implements SmartValidator, ApplicationContextAware, InitializingBean, DisposableBean {\n\n\tprivate final SmartValidator target;\n\n\tprivate final boolean existingBean;\n\n\tValidatorAdapter(SmartValidator target, boolean existingBean) {\n\t\tthis.target = target;\n\t\tthis.existingBean = existingBean;\n\t}\n\n\tpublic final Validator getTarget() {\n\t\treturn this.target;\n\t}\n\n\t@Override\n\tpublic boolean supports(Class<?> type) {\n\t\treturn this.target.supports(type);\n\t}\n\n\t@Override\n\tpublic void validate(Object target, Errors errors) {\n\t\tthis.target.validate(target, errors);\n\t}\n\n\t@Override\n\tpublic void validate(Object target, Errors errors, Object... validationHints) {\n\t\tthis.target.validate(target, errors, validationHints);\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tif (!this.existingBean && this.target instanceof ApplicationContextAware contextAwareTarget) {\n\t\t\tcontextAwareTarget.setApplicationContext(applicationContext);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (!this.existingBean && this.target instanceof InitializingBean initializingBean) {\n\t\t\tinitializingBean.afterPropertiesSet();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() throws Exception {\n\t\tif (!this.existingBean && this.target instanceof DisposableBean disposableBean) {\n\t\t\tdisposableBean.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * Return a {@link Validator} that only implements the {@link Validator} interface,\n\t * wrapping it if necessary.\n\t * <p>\n\t * If the specified {@link Validator} is not {@code null}, it is wrapped. If not, a\n\t * {@link jakarta.validation.Validator} is retrieved from the context and wrapped.\n\t * Otherwise, a new default validator is created.\n\t * @param applicationContext the application context\n\t * @param validator an existing validator to use or {@code null}\n\t * @return the validator to use\n\t */\n\tpublic static Validator get(ApplicationContext applicationContext, @Nullable Validator validator) {\n\t\tif (validator != null) {\n\t\t\treturn wrap(validator, false);\n\t\t}\n\t\treturn getExistingOrCreate(applicationContext);\n\t}\n\n\tprivate static Validator getExistingOrCreate(ApplicationContext applicationContext) {\n\t\tValidator existing = getExisting(applicationContext);\n\t\tif (existing != null) {\n\t\t\treturn wrap(existing, true);\n\t\t}\n\t\treturn create(applicationContext);\n\t}\n\n\tprivate static @Nullable Validator getExisting(ApplicationContext applicationContext) {\n\t\ttry {\n\t\t\tjakarta.validation.Validator validatorBean = applicationContext.getBean(jakarta.validation.Validator.class);\n\t\t\tif (validatorBean instanceof Validator validator) {\n\t\t\t\treturn validator;\n\t\t\t}\n\t\t\treturn new SpringValidatorAdapter(validatorBean);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate static Validator create(MessageSource messageSource) {\n\t\tOptionalValidatorFactoryBean validator = new OptionalValidatorFactoryBean();\n\t\ttry {\n\t\t\tMessageInterpolatorFactory factory = new MessageInterpolatorFactory(messageSource);\n\t\t\tvalidator.setMessageInterpolator(factory.getObject());\n\t\t}\n\t\tcatch (ValidationException ex) {\n\t\t\t// Ignore\n\t\t}\n\t\treturn wrap(validator, false);\n\t}\n\n\tprivate static Validator wrap(Validator validator, boolean existingBean) {\n\t\tif (validator instanceof jakarta.validation.Validator jakartaValidator) {\n\t\t\tif (jakartaValidator instanceof SpringValidatorAdapter adapter) {\n\t\t\t\treturn new ValidatorAdapter(adapter, existingBean);\n\t\t\t}\n\t\t\treturn new ValidatorAdapter(new SpringValidatorAdapter(jakartaValidator), existingBean);\n\t\t}\n\t\treturn validator;\n\t}\n\n\t@Override\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> @Nullable T unwrap(@Nullable Class<T> type) {\n\t\tAssert.state(type != null, \"'type' must not be null\");\n\t\tif (type.isInstance(this.target)) {\n\t\t\treturn (T) this.target;\n\t\t}\n\t\treturn this.target.unwrap(type);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/java/org/springframework/boot/validation/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for (JSR-303) Validation.\n */\n@NullMarked\npackage org.springframework.boot.validation.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.validation.method.adapt-constraint-violations\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to adapt ConstraintViolations to MethodValidationResult.\",\n      \"defaultValue\": false\n    }\n  ],\n  \"hints\": []\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-validation/src/main/resources/META-INF/spring.factories",
    "content": "# Background Preinitializers\norg.springframework.boot.autoconfigure.preinitialize.BackgroundPreinitializer=\\\norg.springframework.boot.validation.autoconfigure.JakartaValidationBackgroundPreinitializer\n"
  },
  {
    "path": "module/spring-boot-validation/src/test/java/org/springframework/boot/validation/autoconfigure/ValidationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport jakarta.validation.ConstraintViolationException;\nimport jakarta.validation.Validator;\nimport jakarta.validation.constraints.Min;\nimport jakarta.validation.constraints.Size;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\nimport org.mockito.Mockito;\n\nimport org.springframework.beans.factory.BeanFactoryUtils;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.validation.autoconfigure.ValidationAutoConfigurationTests.CustomValidatorConfiguration.TestBeanPostProcessor;\nimport org.springframework.boot.validation.beanvalidation.MethodValidationExcludeFilter;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.validation.beanvalidation.CustomValidatorBean;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\nimport org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;\nimport org.springframework.validation.method.MethodValidationException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ValidationAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nclass ValidationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));\n\n\t@Test\n\tvoid validationAutoConfigurationShouldConfigureDefaultValidator() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"defaultValidator\");\n\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t.containsExactly(\"defaultValidator\");\n\t\t\tassertThat(context.getBean(Validator.class)).isInstanceOf(LocalValidatorFactoryBean.class)\n\t\t\t\t.isEqualTo(context.getBean(org.springframework.validation.Validator.class));\n\t\t\tassertThat(isPrimaryBean(context, \"defaultValidator\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationAutoConfigurationWhenUserProvidesValidatorShouldBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(UserDefinedValidatorConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"customValidator\");\n\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t.containsExactly(\"customValidator\");\n\t\t\tassertThat(context.getBean(Validator.class)).isInstanceOf(OptionalValidatorFactoryBean.class)\n\t\t\t\t.isEqualTo(context.getBean(org.springframework.validation.Validator.class));\n\t\t\tassertThat(isPrimaryBean(context, \"customValidator\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationAutoConfigurationWhenUserProvidesDefaultValidatorShouldNotEnablePrimary() {\n\t\tthis.contextRunner.withUserConfiguration(UserDefinedDefaultValidatorConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"defaultValidator\");\n\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t.containsExactly(\"defaultValidator\");\n\t\t\tassertThat(isPrimaryBean(context, \"defaultValidator\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationAutoConfigurationWhenUserProvidesJsrValidatorShouldBackOff() {\n\t\tthis.contextRunner.withUserConfiguration(UserDefinedJsrValidatorConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"customValidator\");\n\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class)).isEmpty();\n\t\t\tassertThat(isPrimaryBean(context, \"customValidator\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationAutoConfigurationWhenUserProvidesSpringValidatorShouldCreateJsrValidator() {\n\t\tthis.contextRunner.withUserConfiguration(UserDefinedSpringValidatorConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"defaultValidator\");\n\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t.containsExactly(\"customValidator\", \"anotherCustomValidator\", \"defaultValidator\");\n\t\t\tassertThat(context.getBean(Validator.class)).isInstanceOf(LocalValidatorFactoryBean.class)\n\t\t\t\t.isEqualTo(context.getBean(org.springframework.validation.Validator.class));\n\t\t\tassertThat(isPrimaryBean(context, \"defaultValidator\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationAutoConfigurationWhenUserProvidesPrimarySpringValidatorShouldRemovePrimaryFlag() {\n\t\tthis.contextRunner.withUserConfiguration(UserDefinedPrimarySpringValidatorConfig.class).run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"defaultValidator\");\n\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t.containsExactly(\"customValidator\", \"anotherCustomValidator\", \"defaultValidator\");\n\t\t\tassertThat(context.getBean(Validator.class)).isInstanceOf(LocalValidatorFactoryBean.class);\n\t\t\tassertThat(context.getBean(org.springframework.validation.Validator.class))\n\t\t\t\t.isEqualTo(context.getBean(\"anotherCustomValidator\"));\n\t\t\tassertThat(isPrimaryBean(context, \"defaultValidator\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUserProvidesSpringValidatorInParentContextThenAutoConfiguredValidatorIsPrimary() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(UserDefinedSpringValidatorConfig.class).run((parent) -> {\n\t\t\tthis.contextRunner.withParent(parent).run((context) -> {\n\t\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"defaultValidator\");\n\t\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t\t.containsExactly(\"defaultValidator\");\n\t\t\t\tassertThat(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context.getBeanFactory(),\n\t\t\t\t\t\torg.springframework.validation.Validator.class))\n\t\t\t\t\t.containsExactly(\"defaultValidator\", \"customValidator\", \"anotherCustomValidator\");\n\t\t\t\tassertThat(isPrimaryBean(context, \"defaultValidator\")).isTrue();\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUserProvidesPrimarySpringValidatorInParentContextThenAutoConfiguredValidatorIsPrimary() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(UserDefinedPrimarySpringValidatorConfig.class)\n\t\t\t.run((parent) -> {\n\t\t\t\tthis.contextRunner.withParent(parent).run((context) -> {\n\t\t\t\t\tassertThat(context.getBeanNamesForType(Validator.class)).containsExactly(\"defaultValidator\");\n\t\t\t\t\tassertThat(context.getBeanNamesForType(org.springframework.validation.Validator.class))\n\t\t\t\t\t\t.containsExactly(\"defaultValidator\");\n\t\t\t\t\tassertThat(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context.getBeanFactory(),\n\t\t\t\t\t\t\torg.springframework.validation.Validator.class))\n\t\t\t\t\t\t.containsExactly(\"defaultValidator\", \"customValidator\", \"anotherCustomValidator\");\n\t\t\t\t\tassertThat(isPrimaryBean(context, \"defaultValidator\")).isTrue();\n\t\t\t\t});\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validationIsEnabled() {\n\t\tthis.contextRunner.withUserConfiguration(SampleService.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\tSampleService service = context.getBean(SampleService.class);\n\t\t\tservice.doSomething(\"Valid\");\n\t\t\tassertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(\"KO\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid classCanBeExcludedFromValidation() {\n\t\tthis.contextRunner.withUserConfiguration(ExcludedServiceConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\tExcludedService service = context.getBean(ExcludedService.class);\n\t\t\tservice.doSomething(\"Valid\");\n\t\t\tassertThatNoException().isThrownBy(() -> service.doSomething(\"KO\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationUsesCglibProxy() {\n\t\tthis.contextRunner.withUserConfiguration(DefaultAnotherSampleService.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\tDefaultAnotherSampleService service = context.getBean(DefaultAnotherSampleService.class);\n\t\t\tservice.doSomething(42);\n\t\t\tassertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(2));\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationCanBeConfiguredToUseJdkProxy() {\n\t\tthis.contextRunner.withUserConfiguration(AnotherSampleServiceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.aop.proxy-target-class=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\t\tassertThat(context.getBeansOfType(DefaultAnotherSampleService.class)).isEmpty();\n\t\t\t\tAnotherSampleService service = context.getBean(AnotherSampleService.class);\n\t\t\t\tservice.doSomething(42);\n\t\t\t\tassertThatExceptionOfType(ConstraintViolationException.class).isThrownBy(() -> service.doSomething(2));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validationCanBeConfiguredToAdaptConstraintViolations() {\n\t\tthis.contextRunner.withUserConfiguration(AnotherSampleServiceConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.validation.method.adapt-constraint-violations=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\t\tAnotherSampleService service = context.getBean(AnotherSampleService.class);\n\t\t\t\tservice.doSomething(42);\n\t\t\t\tassertThatExceptionOfType(MethodValidationException.class).isThrownBy(() -> service.doSomething(2));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validationUseDefaultAdaptToConstraintViolationsValue() {\n\t\tthis.contextRunner.withUserConfiguration(AnotherSampleServiceConfiguration.class).run((context) -> {\n\t\t\tMethodValidationPostProcessor postProcessor = context.getBean(MethodValidationPostProcessor.class);\n\t\t\tassertThat(postProcessor).hasFieldOrPropertyWithValue(\"adaptConstraintViolations\", false);\n\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid userDefinedMethodValidationPostProcessorTakesPrecedence() {\n\t\tthis.contextRunner.withUserConfiguration(SampleConfiguration.class).run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\tObject userMethodValidationPostProcessor = context.getBean(\"testMethodValidationPostProcessor\");\n\t\t\tassertThat(context.getBean(MethodValidationPostProcessor.class))\n\t\t\t\t.isSameAs(userMethodValidationPostProcessor);\n\t\t\tassertThat(context.getBeansOfType(MethodValidationPostProcessor.class)).hasSize(1);\n\t\t\tObject validator = ReflectionTestUtils.getField(userMethodValidationPostProcessor, \"validator\");\n\t\t\tassertThat(validator).isInstanceOf(Supplier.class);\n\t\t\tassertThat(context.getBean(Validator.class)).isNotSameAs(((Supplier<Validator>) validator).get());\n\t\t});\n\t}\n\n\t@Test\n\tvoid methodValidationPostProcessorValidatorDependencyDoesNotTriggerEarlyInitialization() {\n\t\tthis.contextRunner.withUserConfiguration(CustomValidatorConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(TestBeanPostProcessor.class).postProcessed)\n\t\t\t\t.contains(\"someService\"));\n\t}\n\n\t@Test\n\tvoid validationIsEnabledInChildContext() {\n\t\tthis.contextRunner.run((parent) -> new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(SampleService.class)\n\t\t\t.withParent(parent)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(Validator.class)).isEmpty();\n\t\t\t\tassertThat(parent.getBeansOfType(Validator.class)).hasSize(1);\n\t\t\t\tSampleService service = context.getBean(SampleService.class);\n\t\t\t\tservice.doSomething(\"Valid\");\n\t\t\t\tassertThatExceptionOfType(ConstraintViolationException.class)\n\t\t\t\t\t.isThrownBy(() -> service.doSomething(\"KO\"));\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid configurationCustomizerBeansAreCalledInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(ConfigurationCustomizersConfiguration.class).run((context) -> {\n\t\t\tValidationConfigurationCustomizer customizerOne = context.getBean(\"customizerOne\",\n\t\t\t\t\tValidationConfigurationCustomizer.class);\n\t\t\tValidationConfigurationCustomizer customizerTwo = context.getBean(\"customizerTwo\",\n\t\t\t\t\tValidationConfigurationCustomizer.class);\n\t\t\tInOrder inOrder = Mockito.inOrder(customizerOne, customizerTwo);\n\t\t\tthen(customizerTwo).should(inOrder).customize(any(jakarta.validation.Configuration.class));\n\t\t\tthen(customizerOne).should(inOrder).customize(any(jakarta.validation.Configuration.class));\n\t\t});\n\t}\n\n\tprivate boolean isPrimaryBean(AssertableApplicationContext context, String beanName) {\n\t\treturn ((BeanDefinitionRegistry) context.getSourceApplicationContext()).getBeanDefinition(beanName).isPrimary();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDefinedValidatorConfig {\n\n\t\t@Bean\n\t\tOptionalValidatorFactoryBean customValidator() {\n\t\t\treturn new OptionalValidatorFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDefinedDefaultValidatorConfig {\n\n\t\t@Bean\n\t\tOptionalValidatorFactoryBean defaultValidator() {\n\t\t\treturn new OptionalValidatorFactoryBean();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDefinedJsrValidatorConfig {\n\n\t\t@Bean\n\t\tValidator customValidator() {\n\t\t\treturn mock(Validator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDefinedSpringValidatorConfig {\n\n\t\t@Bean\n\t\torg.springframework.validation.Validator customValidator() {\n\t\t\treturn mock(org.springframework.validation.Validator.class);\n\t\t}\n\n\t\t@Bean\n\t\torg.springframework.validation.Validator anotherCustomValidator() {\n\t\t\treturn mock(org.springframework.validation.Validator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UserDefinedPrimarySpringValidatorConfig {\n\n\t\t@Bean\n\t\torg.springframework.validation.Validator customValidator() {\n\t\t\treturn mock(org.springframework.validation.Validator.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\torg.springframework.validation.Validator anotherCustomValidator() {\n\t\t\treturn mock(org.springframework.validation.Validator.class);\n\t\t}\n\n\t}\n\n\t@Validated\n\tstatic class SampleService {\n\n\t\tvoid doSomething(@Size(min = 3, max = 10) String name) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic final class ExcludedServiceConfiguration {\n\n\t\t@Bean\n\t\tExcludedService excludedService() {\n\t\t\treturn new ExcludedService();\n\t\t}\n\n\t\t@Bean\n\t\tMethodValidationExcludeFilter exclusionFilter() {\n\t\t\treturn (type) -> type.equals(ExcludedService.class);\n\t\t}\n\n\t}\n\n\t@Validated\n\tstatic final class ExcludedService {\n\n\t\tvoid doSomething(@Size(min = 3, max = 10) String name) {\n\t\t}\n\n\t}\n\n\tinterface AnotherSampleService {\n\n\t\tvoid doSomething(@Min(42) Integer counter);\n\n\t}\n\n\t@Validated\n\tstatic class DefaultAnotherSampleService implements AnotherSampleService {\n\n\t\t@Override\n\t\tpublic void doSomething(Integer counter) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnotherSampleServiceConfiguration {\n\n\t\t@Bean\n\t\tAnotherSampleService anotherSampleService() {\n\t\t\treturn new DefaultAnotherSampleService();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SampleConfiguration {\n\n\t\t@Bean\n\t\tstatic MethodValidationPostProcessor testMethodValidationPostProcessor() {\n\t\t\treturn new MethodValidationPostProcessor();\n\t\t}\n\n\t}\n\n\t@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)\n\tstatic class CustomValidatorConfiguration {\n\n\t\tCustomValidatorConfiguration(SomeService someService) {\n\n\t\t}\n\n\t\t@Bean\n\t\tValidator customValidator() {\n\t\t\treturn new CustomValidatorBean();\n\t\t}\n\n\t\t@Bean\n\t\tstatic TestBeanPostProcessor testBeanPostProcessor() {\n\t\t\treturn new TestBeanPostProcessor();\n\t\t}\n\n\t\t@Configuration(proxyBeanMethods = false)\n\t\tstatic class SomeServiceConfiguration {\n\n\t\t\t@Bean\n\t\t\tSomeService someService() {\n\t\t\t\treturn new SomeService();\n\t\t\t}\n\n\t\t}\n\n\t\tstatic class SomeService {\n\n\t\t}\n\n\t\tstatic class TestBeanPostProcessor implements BeanPostProcessor {\n\n\t\t\tprivate final Set<String> postProcessed = new HashSet<>();\n\n\t\t\t@Override\n\t\t\tpublic Object postProcessAfterInitialization(Object bean, String name) {\n\t\t\t\tthis.postProcessed.add(name);\n\t\t\t\treturn bean;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Object postProcessBeforeInitialization(Object bean, String name) {\n\t\t\t\treturn bean;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ConfigurationCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(1)\n\t\tValidationConfigurationCustomizer customizerOne() {\n\t\t\treturn mock(ValidationConfigurationCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tValidationConfigurationCustomizer customizerTwo() {\n\t\t\treturn mock(ValidationConfigurationCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/test/java/org/springframework/boot/validation/autoconfigure/ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport jakarta.validation.Validator;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link ValidationAutoConfiguration} when Hibernate validator is present but no\n * EL implementation is available.\n *\n * @author Stephane Nicoll\n */\n@ClassPathExclusions({ \"tomcat-embed-el-*.jar\", \"el-api-*.jar\" })\nclass ValidationAutoConfigurationWithHibernateValidatorMissingElImplTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));\n\n\t@Test\n\tvoid missingElDependencyIsTolerated() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Validator.class);\n\t\t\tassertThat(context).hasSingleBean(MethodValidationPostProcessor.class);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/test/java/org/springframework/boot/validation/autoconfigure/ValidationAutoConfigurationWithoutValidatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport jakarta.validation.Validator;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.validation.beanvalidation.MethodValidationPostProcessor;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Test for {@link ValidationAutoConfiguration} when no JSR-303 provider is available.\n *\n * @author Stephane Nicoll\n */\n@ClassPathExclusions(\"hibernate-validator-*.jar\")\nclass ValidationAutoConfigurationWithoutValidatorTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));\n\n\t@Test\n\tvoid validationIsDisabled() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(Validator.class);\n\t\t\tassertThat(context).doesNotHaveBean(MethodValidationPostProcessor.class);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-validation/src/test/java/org/springframework/boot/validation/autoconfigure/ValidatorAdapterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.validation.autoconfigure;\n\nimport java.util.HashMap;\n\nimport jakarta.validation.Validator;\nimport jakarta.validation.constraints.Min;\nimport org.hibernate.validator.HibernateValidator;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.MapBindingResult;\nimport org.springframework.validation.SmartValidator;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatRuntimeException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ValidatorAdapter}.\n *\n * @author Stephane Nicoll\n * @author Madhura Bhave\n */\nclass ValidatorAdapterTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner();\n\n\t@Test\n\tvoid wrapLocalValidatorFactoryBean() {\n\t\tthis.contextRunner.withUserConfiguration(LocalValidatorFactoryBeanConfig.class).run((context) -> {\n\t\t\tValidatorAdapter wrapper = context.getBean(ValidatorAdapter.class);\n\t\t\tassertThat(wrapper.supports(SampleData.class)).isTrue();\n\t\t\tMapBindingResult errors = new MapBindingResult(new HashMap<>(), \"test\");\n\t\t\twrapper.validate(new SampleData(40), errors);\n\t\t\tassertThat(errors.getErrorCount()).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid wrapperInvokesCallbackOnNonManagedBean() {\n\t\tthis.contextRunner.withUserConfiguration(NonManagedBeanConfig.class).run((context) -> {\n\t\t\tLocalValidatorFactoryBean validator = context.getBean(NonManagedBeanConfig.class).validator;\n\t\t\tthen(validator).should().setApplicationContext(any(ApplicationContext.class));\n\t\t\tthen(validator).should().afterPropertiesSet();\n\t\t\tthen(validator).should(never()).destroy();\n\t\t\tcontext.close();\n\t\t\tthen(validator).should().destroy();\n\t\t});\n\t}\n\n\t@Test\n\tvoid wrapperDoesNotInvokeCallbackOnManagedBean() {\n\t\tthis.contextRunner.withUserConfiguration(ManagedBeanConfig.class).run((context) -> {\n\t\t\tLocalValidatorFactoryBean validator = context.getBean(ManagedBeanConfig.class).validator;\n\t\t\tthen(validator).should(never()).setApplicationContext(any(ApplicationContext.class));\n\t\t\tthen(validator).should(never()).afterPropertiesSet();\n\t\t\tthen(validator).should(never()).destroy();\n\t\t\tcontext.close();\n\t\t\tthen(validator).should(never()).destroy();\n\t\t});\n\t}\n\n\t@Test\n\tvoid wrapperWhenValidationProviderNotPresentShouldNotThrowException() {\n\t\tClassPathResource hibernateValidator = new ClassPathResource(\n\t\t\t\t\"META-INF/services/jakarta.validation.spi.ValidationProvider\");\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(FilteredClassLoader.ClassPathResourceFilter.of(hibernateValidator),\n\t\t\t\t\tFilteredClassLoader.PackageFilter.of(\"org.hibernate.validator\")))\n\t\t\t.run((context) -> ValidatorAdapter.get(context, null));\n\t}\n\n\t@Test\n\tvoid unwrapToJakartaValidatorShouldReturnJakartaValidator() {\n\t\tthis.contextRunner.withUserConfiguration(LocalValidatorFactoryBeanConfig.class).run((context) -> {\n\t\t\tValidatorAdapter wrapper = context.getBean(ValidatorAdapter.class);\n\t\t\tassertThat(wrapper.unwrap(Validator.class)).isInstanceOf(Validator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenJakartaValidatorIsWrappedMultipleTimesUnwrapToJakartaValidatorShouldReturnJakartaValidator() {\n\t\tthis.contextRunner.withUserConfiguration(DoubleWrappedConfig.class).run((context) -> {\n\t\t\tValidatorAdapter wrapper = context.getBean(ValidatorAdapter.class);\n\t\t\tassertThat(wrapper.unwrap(Validator.class)).isInstanceOf(Validator.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid unwrapToUnsupportedTypeShouldThrow() {\n\t\tthis.contextRunner.withUserConfiguration(LocalValidatorFactoryBeanConfig.class).run((context) -> {\n\t\t\tValidatorAdapter wrapper = context.getBean(ValidatorAdapter.class);\n\t\t\tassertThatRuntimeException().isThrownBy(() -> wrapper.unwrap(HibernateValidator.class));\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class LocalValidatorFactoryBeanConfig {\n\n\t\t@Bean\n\t\tLocalValidatorFactoryBean validator() {\n\t\t\treturn new LocalValidatorFactoryBean();\n\t\t}\n\n\t\t@Bean\n\t\tValidatorAdapter wrapper(LocalValidatorFactoryBean validator) {\n\t\t\treturn new ValidatorAdapter(validator, true);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DoubleWrappedConfig {\n\n\t\t@Bean\n\t\tLocalValidatorFactoryBean validator() {\n\t\t\treturn new LocalValidatorFactoryBean();\n\t\t}\n\n\t\t@Bean\n\t\tValidatorAdapter wrapper(LocalValidatorFactoryBean validator) {\n\t\t\treturn new ValidatorAdapter(new Wrapper(validator), true);\n\t\t}\n\n\t\tstatic class Wrapper implements SmartValidator {\n\n\t\t\tprivate final SmartValidator delegate;\n\n\t\t\tWrapper(SmartValidator delegate) {\n\t\t\t\tthis.delegate = delegate;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean supports(Class<?> type) {\n\t\t\t\treturn this.delegate.supports(type);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void validate(Object target, Errors errors) {\n\t\t\t\tthis.delegate.validate(target, errors);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void validate(Object target, Errors errors, Object... validationHints) {\n\t\t\t\tthis.delegate.validate(target, errors, validationHints);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tpublic <T> @Nullable T unwrap(@Nullable Class<T> type) {\n\t\t\t\tif (type != null && type.isInstance(this.delegate)) {\n\t\t\t\t\treturn (T) this.delegate;\n\t\t\t\t}\n\t\t\t\treturn this.delegate.unwrap(type);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonManagedBeanConfig {\n\n\t\tprivate final LocalValidatorFactoryBean validator = mock(LocalValidatorFactoryBean.class);\n\n\t\t@Bean\n\t\tValidatorAdapter wrapper() {\n\t\t\treturn new ValidatorAdapter(this.validator, false);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ManagedBeanConfig {\n\n\t\tprivate final LocalValidatorFactoryBean validator = mock(LocalValidatorFactoryBean.class);\n\n\t\t@Bean\n\t\tValidatorAdapter wrapper() {\n\t\t\treturn new ValidatorAdapter(this.validator, true);\n\t\t}\n\n\t}\n\n\tstatic class SampleData {\n\n\t\t@Min(42)\n\t\tprivate final int counter;\n\n\t\tSampleData(int counter) {\n\t\t\tthis.counter = counter;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Web Server\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-web\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test\"))\n\toptional(\"io.projectreactor:reactor-core\")\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\toptional(\"org.springframework:spring-test\")\n\n\ttestFixturesCompileOnly(project(\":core:spring-boot-test\"))\n\ttestFixturesCompileOnly(project(\":test-support:spring-boot-test-support\"))\n\ttestFixturesCompileOnly(\"io.projectreactor:reactor-test\")\n\ttestFixturesCompileOnly(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestFixturesCompileOnly(\"org.apache.httpcomponents.client5:httpclient5\")\n\ttestFixturesCompileOnly(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\ttestFixturesCompileOnly(\"org.eclipse.jetty.http2:jetty-http2-client\")\n\ttestFixturesCompileOnly(\"org.eclipse.jetty.http2:jetty-http2-client-transport\")\n\ttestFixturesCompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestFixturesCompileOnly(\"jakarta.websocket:jakarta.websocket-api\")\n\ttestFixturesCompileOnly(\"jakarta.websocket:jakarta.websocket-client-api\")\n\ttestFixturesCompileOnly(\"org.mockito:mockito-core\")\n\ttestFixturesCompileOnly(\"org.springframework:spring-tx\")\n\ttestFixturesCompileOnly(\"org.springframework:spring-webflux\")\n\ttestFixturesCompileOnly(\"org.springframework:spring-webmvc\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot\")))\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-core\")\n\ttestImplementation(\"org.springframework:spring-webmvc\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.server.Ssl.ServerNameSslBundle;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileSystemUtils;\n\n/**\n * Abstract base class for {@link ConfigurableWebServerFactory} implementations.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Ivan Sopov\n * @author Eddú Meléndez\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 2.0.0\n */\npublic abstract class AbstractConfigurableWebServerFactory implements ConfigurableWebServerFactory {\n\n\tprivate int port = 8080;\n\n\tprivate @Nullable InetAddress address;\n\n\tprivate Set<ErrorPage> errorPages = new LinkedHashSet<>();\n\n\tprivate @Nullable Ssl ssl;\n\n\tprivate @Nullable SslBundles sslBundles;\n\n\tprivate @Nullable Http2 http2;\n\n\tprivate @Nullable Compression compression;\n\n\tprivate @Nullable String serverHeader;\n\n\tprivate Shutdown shutdown = Shutdown.IMMEDIATE;\n\n\t/**\n\t * Create a new {@link AbstractConfigurableWebServerFactory} instance.\n\t */\n\tpublic AbstractConfigurableWebServerFactory() {\n\t}\n\n\t/**\n\t * Create a new {@link AbstractConfigurableWebServerFactory} instance with the\n\t * specified port.\n\t * @param port the port number for the web server\n\t */\n\tpublic AbstractConfigurableWebServerFactory(int port) {\n\t\tthis.port = port;\n\t}\n\n\t/**\n\t * The port that the web server listens on.\n\t * @return the port\n\t */\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\t@Override\n\tpublic void setPort(int port) {\n\t\tthis.port = port;\n\t}\n\n\t/**\n\t * Return the address that the web server binds to.\n\t * @return the address\n\t */\n\tpublic @Nullable InetAddress getAddress() {\n\t\treturn this.address;\n\t}\n\n\t@Override\n\tpublic void setAddress(@Nullable InetAddress address) {\n\t\tthis.address = address;\n\t}\n\n\t/**\n\t * Returns a mutable set of {@link ErrorPage ErrorPages} that will be used when\n\t * handling exceptions.\n\t * @return the error pages\n\t */\n\tpublic Set<ErrorPage> getErrorPages() {\n\t\treturn this.errorPages;\n\t}\n\n\t@Override\n\tpublic void setErrorPages(Set<? extends ErrorPage> errorPages) {\n\t\tAssert.notNull(errorPages, \"'errorPages' must not be null\");\n\t\tthis.errorPages = new LinkedHashSet<>(errorPages);\n\t}\n\n\t@Override\n\tpublic void addErrorPages(ErrorPage... errorPages) {\n\t\tAssert.notNull(errorPages, \"'errorPages' must not be null\");\n\t\tthis.errorPages.addAll(Arrays.asList(errorPages));\n\t}\n\n\tpublic @Nullable Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\t@Override\n\tpublic void setSsl(@Nullable Ssl ssl) {\n\t\tthis.ssl = ssl;\n\t}\n\n\t/**\n\t * Return the configured {@link SslBundles}.\n\t * @return the {@link SslBundles} or {@code null}\n\t * @since 3.2.0\n\t */\n\tpublic @Nullable SslBundles getSslBundles() {\n\t\treturn this.sslBundles;\n\t}\n\n\t@Override\n\tpublic void setSslBundles(@Nullable SslBundles sslBundles) {\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\tpublic @Nullable Http2 getHttp2() {\n\t\treturn this.http2;\n\t}\n\n\t@Override\n\tpublic void setHttp2(@Nullable Http2 http2) {\n\t\tthis.http2 = http2;\n\t}\n\n\tpublic @Nullable Compression getCompression() {\n\t\treturn this.compression;\n\t}\n\n\t@Override\n\tpublic void setCompression(@Nullable Compression compression) {\n\t\tthis.compression = compression;\n\t}\n\n\tpublic @Nullable String getServerHeader() {\n\t\treturn this.serverHeader;\n\t}\n\n\t@Override\n\tpublic void setServerHeader(@Nullable String serverHeader) {\n\t\tthis.serverHeader = serverHeader;\n\t}\n\n\t@Override\n\tpublic void setShutdown(Shutdown shutdown) {\n\t\tthis.shutdown = shutdown;\n\t}\n\n\t/**\n\t * Returns the shutdown configuration that will be applied to the server.\n\t * @return the shutdown configuration\n\t * @since 2.3.0\n\t */\n\tpublic Shutdown getShutdown() {\n\t\treturn this.shutdown;\n\t}\n\n\t/**\n\t * Return the {@link SslBundle} that should be used with this server.\n\t * @return the SSL bundle\n\t */\n\tprotected final SslBundle getSslBundle() {\n\t\treturn WebServerSslBundle.get(this.ssl, this.sslBundles);\n\t}\n\n\tprotected final Map<String, SslBundle> getServerNameSslBundles() {\n\t\tAssert.state(this.ssl != null, \"'ssl' must not be null\");\n\t\treturn this.ssl.getServerNameBundles()\n\t\t\t.stream()\n\t\t\t.collect(Collectors.toMap(ServerNameSslBundle::serverName, (serverNameSslBundle) -> {\n\t\t\t\tAssert.state(this.sslBundles != null, \"'sslBundles' must not be null\");\n\t\t\t\treturn this.sslBundles.getBundle(serverNameSslBundle.bundle());\n\t\t\t}));\n\t}\n\n\t/**\n\t * Return the absolute temp dir for given web server.\n\t * @param prefix server name\n\t * @return the temp dir for given server.\n\t * @deprecated since 4.1.0 for removal in 4.3.0 in favor of {@link TempDirs}.\n\t */\n\t@Deprecated(since = \"4.1.0\", forRemoval = true)\n\tprotected final File createTempDir(String prefix) {\n\t\ttry {\n\t\t\tFile tempDir = Files.createTempDirectory(prefix + \".\" + getPort() + \".\").toFile();\n\t\t\ttempDir.deleteOnExit();\n\t\t\treturn tempDir;\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new WebServerException(\n\t\t\t\t\t\"Unable to create tempDir. java.io.tmpdir is set to \" + System.getProperty(\"java.io.tmpdir\"), ex);\n\t\t}\n\t}\n\n\t/**\n\t * Manages temporary directories.\n\t *\n\t * @since 4.1.0\n\t */\n\tpublic static class TempDirs {\n\n\t\tprivate final Set<Path> dirs = new HashSet<>();\n\n\t\tprivate final int port;\n\n\t\tpublic TempDirs(int port) {\n\t\t\tthis.port = port;\n\t\t}\n\n\t\t/**\n\t\t * Creates a temporary directory and registers it for {@link #cleanup cleanup}.\n\t\t * @param prefix the directory prefix\n\t\t * @return the path to the temporary directory\n\t\t */\n\t\tpublic Path createTempDir(String prefix) {\n\t\t\ttry {\n\t\t\t\tPath directory = Files.createTempDirectory(prefix + \".\" + this.port + \".\").toAbsolutePath();\n\t\t\t\tthis.dirs.add(directory);\n\t\t\t\treturn directory;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new WebServerException(\n\t\t\t\t\t\t\"Unable to create tempDir. java.io.tmpdir is set to \" + System.getProperty(\"java.io.tmpdir\"),\n\t\t\t\t\t\tex);\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Deletes all created temporary directories.\n\t\t */\n\t\tpublic void cleanup() {\n\t\t\tfor (Path dir : this.dirs) {\n\t\t\t\ttry {\n\t\t\t\t\tFileSystemUtils.deleteRecursively(dir);\n\t\t\t\t}\n\t\t\t\tcatch (IOException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.dirs.clear();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Compression.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * Simple server-independent abstraction for compression configuration.\n *\n * @author Ivan Sopov\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class Compression {\n\n\t/**\n\t * Whether response compression is enabled.\n\t */\n\tprivate boolean enabled;\n\n\t/**\n\t * Comma-separated list of MIME types that should be compressed.\n\t */\n\tprivate String[] mimeTypes = new String[] { \"text/html\", \"text/xml\", \"text/plain\", \"text/css\", \"text/javascript\",\n\t\t\t\"application/javascript\", \"application/json\", \"application/xml\" };\n\n\t/**\n\t * Comma-separated list of additional MIME types that should be compressed.\n\t */\n\tprivate String[] additionalMimeTypes = new String[0];\n\n\t/**\n\t * Comma-separated list of user agents for which responses should not be compressed.\n\t */\n\tprivate String @Nullable [] excludedUserAgents;\n\n\t/**\n\t * Minimum \"Content-Length\" value that is required for compression to be performed.\n\t */\n\tprivate DataSize minResponseSize = DataSize.ofKilobytes(2);\n\n\t/**\n\t * Return whether response compression is enabled.\n\t * @return {@code true} if response compression is enabled\n\t */\n\tpublic boolean getEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * Return the MIME types that should be compressed.\n\t * @return the MIME types that should be compressed\n\t */\n\tpublic String[] getMimeTypes() {\n\t\treturn this.mimeTypes;\n\t}\n\n\tpublic void setMimeTypes(String[] mimeTypes) {\n\t\tthis.mimeTypes = mimeTypes;\n\t}\n\n\t/**\n\t * Return the MIME types that should be compressed, including any additional types.\n\t * @return the MIME types that should be compressed\n\t */\n\tpublic String[] getAllMimeTypes() {\n\t\tString[] combined = StringUtils.concatenateStringArrays(this.mimeTypes, this.additionalMimeTypes);\n\t\treturn (combined != null) ? combined : this.mimeTypes;\n\t}\n\n\tpublic String[] getAdditionalMimeTypes() {\n\t\treturn this.additionalMimeTypes;\n\t}\n\n\tpublic void setAdditionalMimeTypes(String[] additionalMimeTypes) {\n\t\tthis.additionalMimeTypes = additionalMimeTypes;\n\t}\n\n\tpublic String @Nullable [] getExcludedUserAgents() {\n\t\treturn this.excludedUserAgents;\n\t}\n\n\tpublic void setExcludedUserAgents(String @Nullable [] excludedUserAgents) {\n\t\tthis.excludedUserAgents = excludedUserAgents;\n\t}\n\n\t/**\n\t * Return the minimum \"Content-Length\" value that is required for compression to be\n\t * performed.\n\t * @return the minimum content size in bytes that is required for compression\n\t */\n\tpublic DataSize getMinResponseSize() {\n\t\treturn this.minResponseSize;\n\t}\n\n\tpublic void setMinResponseSize(DataSize minSize) {\n\t\tthis.minResponseSize = minSize;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/ConfigurableWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.net.InetAddress;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.error.ErrorPageRegistry;\n\n/**\n * A configurable {@link WebServerFactory}.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 2.0.0\n * @see ErrorPageRegistry\n */\npublic interface ConfigurableWebServerFactory extends WebServerFactory, ErrorPageRegistry {\n\n\t/**\n\t * Sets the port that the web server should listen on. If not specified port '8080'\n\t * will be used. Use port -1 to disable auto-start (i.e. start the web application\n\t * context but not have it listen to any port).\n\t * @param port the port to set\n\t */\n\tvoid setPort(int port);\n\n\t/**\n\t * Sets the specific network address that the server should bind to.\n\t * @param address the address to set (defaults to {@code null})\n\t */\n\tvoid setAddress(@Nullable InetAddress address);\n\n\t/**\n\t * Sets the error pages that will be used when handling exceptions.\n\t * @param errorPages the error pages\n\t */\n\tvoid setErrorPages(Set<? extends ErrorPage> errorPages);\n\n\t/**\n\t * Sets the SSL configuration that will be applied to the server's default connector.\n\t * @param ssl the SSL configuration\n\t */\n\tvoid setSsl(@Nullable Ssl ssl);\n\n\t/**\n\t * Sets the SSL bundles that can be used to configure SSL connections.\n\t * @param sslBundles the SSL bundles\n\t * @since 3.1.0\n\t */\n\tvoid setSslBundles(@Nullable SslBundles sslBundles);\n\n\t/**\n\t * Sets the HTTP/2 configuration that will be applied to the server.\n\t * @param http2 the HTTP/2 configuration\n\t */\n\tvoid setHttp2(@Nullable Http2 http2);\n\n\t/**\n\t * Sets the compression configuration that will be applied to the server's default\n\t * connector.\n\t * @param compression the compression configuration\n\t */\n\tvoid setCompression(@Nullable Compression compression);\n\n\t/**\n\t * Sets the server header value.\n\t * @param serverHeader the server header value\n\t */\n\tvoid setServerHeader(@Nullable String serverHeader);\n\n\t/**\n\t * Sets the shutdown configuration that will be applied to the server.\n\t * @param shutdown the shutdown configuration\n\t * @since 2.3.0\n\t */\n\tdefault void setShutdown(Shutdown shutdown) {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Cookie.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.convert.DurationUnit;\n\n/**\n * Cookie properties.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Brian Clozel\n * @author Weix Sun\n * @since 2.6.0\n */\npublic class Cookie {\n\n\t/**\n\t * Name for the cookie.\n\t */\n\tprivate @Nullable String name;\n\n\t/**\n\t * Domain for the cookie.\n\t */\n\tprivate @Nullable String domain;\n\n\t/**\n\t * Path of the cookie.\n\t */\n\tprivate @Nullable String path;\n\n\t/**\n\t * Whether to use \"HttpOnly\" cookies for the cookie.\n\t */\n\tprivate @Nullable Boolean httpOnly;\n\n\t/**\n\t * Whether to always mark the cookie as secure.\n\t */\n\tprivate @Nullable Boolean secure;\n\n\t/**\n\t * Whether the generated cookie carries the Partitioned attribute.\n\t */\n\tprivate @Nullable Boolean partitioned;\n\n\t/**\n\t * Maximum age of the cookie. If a duration suffix is not specified, seconds will be\n\t * used. A positive value indicates when the cookie expires relative to the current\n\t * time. A value of 0 means the cookie should expire immediately. A negative value\n\t * means no \"Max-Age\".\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate @Nullable Duration maxAge;\n\n\t/**\n\t * SameSite setting for the cookie.\n\t */\n\tprivate @Nullable SameSite sameSite;\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic @Nullable String getDomain() {\n\t\treturn this.domain;\n\t}\n\n\tpublic void setDomain(@Nullable String domain) {\n\t\tthis.domain = domain;\n\t}\n\n\tpublic @Nullable String getPath() {\n\t\treturn this.path;\n\t}\n\n\tpublic void setPath(@Nullable String path) {\n\t\tthis.path = path;\n\t}\n\n\tpublic @Nullable Boolean getHttpOnly() {\n\t\treturn this.httpOnly;\n\t}\n\n\tpublic void setHttpOnly(@Nullable Boolean httpOnly) {\n\t\tthis.httpOnly = httpOnly;\n\t}\n\n\tpublic @Nullable Boolean getSecure() {\n\t\treturn this.secure;\n\t}\n\n\tpublic void setSecure(@Nullable Boolean secure) {\n\t\tthis.secure = secure;\n\t}\n\n\tpublic @Nullable Duration getMaxAge() {\n\t\treturn this.maxAge;\n\t}\n\n\tpublic void setMaxAge(@Nullable Duration maxAge) {\n\t\tthis.maxAge = maxAge;\n\t}\n\n\tpublic @Nullable SameSite getSameSite() {\n\t\treturn this.sameSite;\n\t}\n\n\tpublic void setSameSite(@Nullable SameSite sameSite) {\n\t\tthis.sameSite = sameSite;\n\t}\n\n\tpublic @Nullable Boolean getPartitioned() {\n\t\treturn this.partitioned;\n\t}\n\n\tpublic void setPartitioned(@Nullable Boolean partitioned) {\n\t\tthis.partitioned = partitioned;\n\t}\n\n\t/**\n\t * SameSite values.\n\t */\n\tpublic enum SameSite {\n\n\t\t/**\n\t\t * SameSite attribute will be omitted when creating the cookie.\n\t\t */\n\t\tOMITTED(null),\n\n\t\t/**\n\t\t * SameSite attribute will be set to None. Cookies are sent in both first-party\n\t\t * and cross-origin requests.\n\t\t */\n\t\tNONE(\"None\"),\n\n\t\t/**\n\t\t * SameSite attribute will be set to Lax. Cookies are sent in a first-party\n\t\t * context, also when following a link to the origin site.\n\t\t */\n\t\tLAX(\"Lax\"),\n\n\t\t/**\n\t\t * SameSite attribute will be set to Strict. Cookies are only sent in a\n\t\t * first-party context (i.e. not when following a link to the origin site).\n\t\t */\n\t\tSTRICT(\"Strict\");\n\n\t\tprivate @Nullable final String attributeValue;\n\n\t\tSameSite(@Nullable String attributeValue) {\n\t\t\tthis.attributeValue = attributeValue;\n\t\t}\n\n\t\tpublic @Nullable String attributeValue() {\n\t\t\treturn this.attributeValue;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/GracefulShutdownCallback.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\n/**\n * A callback for the result of a graceful shutdown request.\n *\n * @author Andy Wilkinson\n * @since 2.3.0\n * @see WebServer#shutDownGracefully(GracefulShutdownCallback)\n */\n@FunctionalInterface\npublic interface GracefulShutdownCallback {\n\n\t/**\n\t * Graceful shutdown has completed with the given {@code result}.\n\t * @param result the result of the shutdown\n\t */\n\tvoid shutdownComplete(GracefulShutdownResult result);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/GracefulShutdownResult.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\n/**\n * The result of a graceful shutdown request.\n *\n * @author Andy Wilkinson\n * @since 2.3.0\n * @see GracefulShutdownCallback\n * @see WebServer#shutDownGracefully(GracefulShutdownCallback)\n */\npublic enum GracefulShutdownResult {\n\n\t/**\n\t * Requests remained active at the end of the grace period.\n\t */\n\tREQUESTS_ACTIVE,\n\n\t/**\n\t * The server was idle with no active requests at the end of the grace period.\n\t */\n\tIDLE,\n\n\t/**\n\t * The server was shutdown immediately, ignoring any active requests.\n\t */\n\tIMMEDIATE\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Http2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\n/**\n * Simple server-independent abstraction for HTTP/2 configuration.\n *\n * @author Brian Clozel\n * @since 2.0.0\n */\npublic class Http2 {\n\n\t/**\n\t * Whether to enable HTTP/2 support, if the current environment supports it.\n\t */\n\tprivate boolean enabled;\n\n\t/**\n\t * Return whether to enable HTTP/2 support, if the current environment supports it.\n\t * @return {@code true} to enable HTTP/2 support\n\t */\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/MimeMappings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.util.Assert;\n\n/**\n * Simple server-independent abstraction for mime mappings. Roughly equivalent to the\n * {@literal &lt;mime-mapping&gt;} element traditionally found in web.xml.\n *\n * @author Phillip Webb\n * @author Guirong Hu\n * @since 2.0.0\n */\npublic sealed class MimeMappings implements Iterable<MimeMappings.Mapping> {\n\n\t/**\n\t * Default mime mapping commonly used.\n\t */\n\tpublic static final MimeMappings DEFAULT = new DefaultMimeMappings();\n\n\tprivate final Map<String, Mapping> map;\n\n\t/**\n\t * Create a new empty {@link MimeMappings} instance.\n\t */\n\tpublic MimeMappings() {\n\t\tthis.map = new LinkedHashMap<>();\n\t}\n\n\t/**\n\t * Create a new {@link MimeMappings} instance from the specified mappings.\n\t * @param mappings the source mappings\n\t */\n\tpublic MimeMappings(MimeMappings mappings) {\n\t\tthis(mappings, true);\n\t}\n\n\t/**\n\t * Create a new {@link MimeMappings} from the specified mappings.\n\t * @param mappings the source mappings with extension as the key and mime-type as the\n\t * value\n\t */\n\tpublic MimeMappings(Map<String, String> mappings) {\n\t\tAssert.notNull(mappings, \"'mappings' must not be null\");\n\t\tthis.map = new LinkedHashMap<>();\n\t\tmappings.forEach(this::add);\n\t}\n\n\t/**\n\t * Internal constructor.\n\t * @param mappings source mappings\n\t * @param mutable if the new object should be mutable.\n\t */\n\tMimeMappings(MimeMappings mappings, boolean mutable) {\n\t\tAssert.notNull(mappings, \"'mappings' must not be null\");\n\t\tthis.map = (mutable ? new LinkedHashMap<>(mappings.map) : Collections.unmodifiableMap(mappings.map));\n\t}\n\n\t/**\n\t * Add a new mime mapping.\n\t * @param extension the file extension (excluding '.')\n\t * @param mimeType the mime type to map\n\t * @return any previous mapping or {@code null}\n\t */\n\tpublic @Nullable String add(String extension, String mimeType) {\n\t\tAssert.notNull(extension, \"'extension' must not be null\");\n\t\tAssert.notNull(mimeType, \"'mimeType' must not be null\");\n\t\tMapping previous = this.map.put(extension.toLowerCase(Locale.ENGLISH), new Mapping(extension, mimeType));\n\t\treturn (previous != null) ? previous.getMimeType() : null;\n\t}\n\n\t/**\n\t * Remove an existing mapping.\n\t * @param extension the file extension (excluding '.')\n\t * @return the removed mime mapping or {@code null} if no item was removed\n\t */\n\tpublic @Nullable String remove(String extension) {\n\t\tAssert.notNull(extension, \"'extension' must not be null\");\n\t\tMapping previous = this.map.remove(extension.toLowerCase(Locale.ENGLISH));\n\t\treturn (previous != null) ? previous.getMimeType() : null;\n\t}\n\n\t/**\n\t * Get a mime mapping for the given extension.\n\t * @param extension the file extension (excluding '.')\n\t * @return a mime mapping or {@code null}\n\t */\n\tpublic @Nullable String get(String extension) {\n\t\tAssert.notNull(extension, \"'extension' must not be null\");\n\t\tMapping mapping = this.map.get(extension.toLowerCase(Locale.ENGLISH));\n\t\treturn (mapping != null) ? mapping.getMimeType() : null;\n\t}\n\n\t/**\n\t * Returns all defined mappings.\n\t * @return the mappings.\n\t */\n\tpublic Collection<Mapping> getAll() {\n\t\treturn this.map.values();\n\t}\n\n\t@Override\n\tpublic final Iterator<Mapping> iterator() {\n\t\treturn getAll().iterator();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == null) {\n\t\t\treturn false;\n\t\t}\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof MimeMappings other) {\n\t\t\treturn getMap().equals(other.map);\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn getMap().hashCode();\n\t}\n\n\tMap<String, Mapping> getMap() {\n\t\treturn this.map;\n\t}\n\n\t/**\n\t * Create a new unmodifiable view of the specified mapping. Methods that attempt to\n\t * modify the returned map will throw {@link UnsupportedOperationException}s.\n\t * @param mappings the mappings\n\t * @return an unmodifiable view of the specified mappings.\n\t */\n\tpublic static MimeMappings unmodifiableMappings(MimeMappings mappings) {\n\t\tAssert.notNull(mappings, \"'mappings' must not be null\");\n\t\treturn new MimeMappings(mappings, false);\n\t}\n\n\t/**\n\t * Create a new lazy copy of the given mappings that will only copy entries if the\n\t * mappings are mutated.\n\t * @param mappings the source mappings\n\t * @return a new mappings instance\n\t * @since 3.0.0\n\t */\n\tpublic static MimeMappings lazyCopy(MimeMappings mappings) {\n\t\tAssert.notNull(mappings, \"'mappings' must not be null\");\n\t\treturn new LazyMimeMappingsCopy(mappings);\n\t}\n\n\t/**\n\t * A single mime mapping.\n\t */\n\tpublic static final class Mapping {\n\n\t\tprivate final String extension;\n\n\t\tprivate final String mimeType;\n\n\t\tpublic Mapping(String extension, String mimeType) {\n\t\t\tAssert.notNull(extension, \"'extension' must not be null\");\n\t\t\tAssert.notNull(mimeType, \"'mimeType' must not be null\");\n\t\t\tthis.extension = extension;\n\t\t\tthis.mimeType = mimeType;\n\t\t}\n\n\t\tpublic String getExtension() {\n\t\t\treturn this.extension;\n\t\t}\n\n\t\tpublic String getMimeType() {\n\t\t\treturn this.mimeType;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean equals(Object obj) {\n\t\t\tif (obj == null) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (obj == this) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (obj instanceof Mapping other) {\n\t\t\t\treturn this.extension.equals(other.extension) && this.mimeType.equals(other.mimeType);\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic int hashCode() {\n\t\t\treturn this.extension.hashCode();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Mapping [extension=\" + this.extension + \", mimeType=\" + this.mimeType + \"]\";\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link MimeMappings} implementation used for {@link MimeMappings#DEFAULT}. Provides\n\t * in-memory access for common mappings and lazily loads the complete set when\n\t * necessary.\n\t */\n\tstatic final class DefaultMimeMappings extends MimeMappings {\n\n\t\tstatic final String MIME_MAPPINGS_PROPERTIES = \"mime-mappings.properties\";\n\n\t\tprivate static final MimeMappings COMMON;\n\n\t\tstatic {\n\t\t\tMimeMappings mappings = new MimeMappings();\n\t\t\tmappings.add(\"avi\", \"video/x-msvideo\");\n\t\t\tmappings.add(\"bin\", \"application/octet-stream\");\n\t\t\tmappings.add(\"body\", \"text/html\");\n\t\t\tmappings.add(\"class\", \"application/java\");\n\t\t\tmappings.add(\"css\", \"text/css\");\n\t\t\tmappings.add(\"dtd\", \"application/xml-dtd\");\n\t\t\tmappings.add(\"gif\", \"image/gif\");\n\t\t\tmappings.add(\"gtar\", \"application/x-gtar\");\n\t\t\tmappings.add(\"gz\", \"application/x-gzip\");\n\t\t\tmappings.add(\"htm\", \"text/html\");\n\t\t\tmappings.add(\"html\", \"text/html\");\n\t\t\tmappings.add(\"jar\", \"application/java-archive\");\n\t\t\tmappings.add(\"java\", \"text/x-java-source\");\n\t\t\tmappings.add(\"jnlp\", \"application/x-java-jnlp-file\");\n\t\t\tmappings.add(\"jpe\", \"image/jpeg\");\n\t\t\tmappings.add(\"jpeg\", \"image/jpeg\");\n\t\t\tmappings.add(\"jpg\", \"image/jpeg\");\n\t\t\tmappings.add(\"js\", \"text/javascript\");\n\t\t\tmappings.add(\"json\", \"application/json\");\n\t\t\tmappings.add(\"otf\", \"font/otf\");\n\t\t\tmappings.add(\"pdf\", \"application/pdf\");\n\t\t\tmappings.add(\"png\", \"image/png\");\n\t\t\tmappings.add(\"ps\", \"application/postscript\");\n\t\t\tmappings.add(\"tar\", \"application/x-tar\");\n\t\t\tmappings.add(\"tif\", \"image/tiff\");\n\t\t\tmappings.add(\"tiff\", \"image/tiff\");\n\t\t\tmappings.add(\"ttf\", \"font/ttf\");\n\t\t\tmappings.add(\"txt\", \"text/plain\");\n\t\t\tmappings.add(\"xht\", \"application/xhtml+xml\");\n\t\t\tmappings.add(\"xhtml\", \"application/xhtml+xml\");\n\t\t\tmappings.add(\"xls\", \"application/vnd.ms-excel\");\n\t\t\tmappings.add(\"xml\", \"application/xml\");\n\t\t\tmappings.add(\"xsl\", \"application/xml\");\n\t\t\tmappings.add(\"xslt\", \"application/xslt+xml\");\n\t\t\tmappings.add(\"wasm\", \"application/wasm\");\n\t\t\tmappings.add(\"zip\", \"application/zip\");\n\t\t\tCOMMON = unmodifiableMappings(mappings);\n\t\t}\n\n\t\tprivate volatile @Nullable Map<String, Mapping> loaded;\n\n\t\tDefaultMimeMappings() {\n\t\t\tsuper(new MimeMappings(), false);\n\t\t}\n\n\t\t@Override\n\t\tpublic Collection<Mapping> getAll() {\n\t\t\treturn load().values();\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(String extension) {\n\t\t\tAssert.notNull(extension, \"'extension' must not be null\");\n\t\t\textension = extension.toLowerCase(Locale.ENGLISH);\n\t\t\tMap<String, Mapping> loaded = this.loaded;\n\t\t\tif (loaded != null) {\n\t\t\t\treturn get(loaded, extension);\n\t\t\t}\n\t\t\tString commonMimeType = COMMON.get(extension);\n\t\t\tif (commonMimeType != null) {\n\t\t\t\treturn commonMimeType;\n\t\t\t}\n\t\t\tloaded = load();\n\t\t\treturn get(loaded, extension);\n\t\t}\n\n\t\tprivate @Nullable String get(Map<String, Mapping> mappings, String extension) {\n\t\t\tMapping mapping = mappings.get(extension);\n\t\t\treturn (mapping != null) ? mapping.getMimeType() : null;\n\t\t}\n\n\t\t@Override\n\t\tMap<String, Mapping> getMap() {\n\t\t\treturn load();\n\t\t}\n\n\t\tprivate Map<String, Mapping> load() {\n\t\t\tMap<String, Mapping> loaded = this.loaded;\n\t\t\tif (loaded != null) {\n\t\t\t\treturn loaded;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tloaded = new LinkedHashMap<>();\n\t\t\t\tfor (Entry<?, ?> entry : PropertiesLoaderUtils\n\t\t\t\t\t.loadProperties(new ClassPathResource(MIME_MAPPINGS_PROPERTIES, getClass()))\n\t\t\t\t\t.entrySet()) {\n\t\t\t\t\tloaded.put((String) entry.getKey(),\n\t\t\t\t\t\t\tnew Mapping((String) entry.getKey(), (String) entry.getValue()));\n\t\t\t\t}\n\t\t\t\tloaded = Collections.unmodifiableMap(loaded);\n\t\t\t\tthis.loaded = loaded;\n\t\t\t\treturn loaded;\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Unable to load the default MIME types\", ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link MimeMappings} implementation used to create a lazy copy only when the\n\t * mappings are mutated.\n\t */\n\tstatic final class LazyMimeMappingsCopy extends MimeMappings {\n\n\t\tprivate final MimeMappings source;\n\n\t\tprivate final AtomicBoolean copied = new AtomicBoolean();\n\n\t\tLazyMimeMappingsCopy(MimeMappings source) {\n\t\t\tthis.source = source;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String add(String extension, String mimeType) {\n\t\t\tcopyIfNecessary();\n\t\t\treturn super.add(extension, mimeType);\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String remove(String extension) {\n\t\t\tcopyIfNecessary();\n\t\t\treturn super.remove(extension);\n\t\t}\n\n\t\tprivate void copyIfNecessary() {\n\t\t\tif (this.copied.compareAndSet(false, true)) {\n\t\t\t\tthis.source.forEach((mapping) -> add(mapping.getExtension(), mapping.getMimeType()));\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String get(String extension) {\n\t\t\treturn !this.copied.get() ? this.source.get(extension) : super.get(extension);\n\t\t}\n\n\t\t@Override\n\t\tpublic Collection<Mapping> getAll() {\n\t\t\treturn !this.copied.get() ? this.source.getAll() : super.getAll();\n\t\t}\n\n\t\t@Override\n\t\tMap<String, Mapping> getMap() {\n\t\t\treturn !this.copied.get() ? this.source.getMap() : super.getMap();\n\t\t}\n\n\t}\n\n\tstatic class MimeMappingsRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.resources()\n\t\t\t\t.registerPattern(\"org/springframework/boot/web/server/\" + DefaultMimeMappings.MIME_MAPPINGS_PROPERTIES);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/PortInUseException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.net.BindException;\nimport java.util.Locale;\nimport java.util.function.Consumer;\nimport java.util.function.IntSupplier;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A {@code PortInUseException} is thrown when a web server fails to start due to a port\n * already being in use.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 2.0.0\n */\npublic class PortInUseException extends WebServerException {\n\n\tprivate final int port;\n\n\t/**\n\t * Creates a new port in use exception for the given {@code port}.\n\t * @param port the port that was in use\n\t */\n\tpublic PortInUseException(int port) {\n\t\tthis(port, null);\n\t}\n\n\t/**\n\t * Creates a new port in use exception for the given {@code port}.\n\t * @param port the port that was in use\n\t * @param cause the cause of the exception\n\t */\n\tpublic PortInUseException(int port, @Nullable Throwable cause) {\n\t\tsuper(\"Port \" + port + \" is already in use\", cause);\n\t\tthis.port = port;\n\t}\n\n\t/**\n\t * Returns the port that was in use.\n\t * @return the port\n\t */\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\t/**\n\t * Throw a {@link PortInUseException} if the given exception was caused by a \"port in\n\t * use\" {@link BindException}.\n\t * @param ex the source exception\n\t * @param port a supplier used to provide the port\n\t * @since 2.2.7\n\t */\n\tpublic static void throwIfPortBindingException(Exception ex, IntSupplier port) {\n\t\tifPortBindingException(ex, (bindException) -> {\n\t\t\tthrow new PortInUseException(port.getAsInt(), ex);\n\t\t});\n\t}\n\n\t/**\n\t * Perform an action if the given exception was caused by a \"port in use\"\n\t * {@link BindException}.\n\t * @param ex the source exception\n\t * @param action the action to perform\n\t * @since 2.2.7\n\t */\n\tpublic static void ifPortBindingException(Exception ex, Consumer<BindException> action) {\n\t\tifCausedBy(ex, BindException.class, (bindException) -> {\n\t\t\t// bind exception can be also thrown because an address can't be assigned\n\t\t\tString message = bindException.getMessage();\n\t\t\tif (message != null && message.toLowerCase(Locale.ROOT).contains(\"in use\")) {\n\t\t\t\taction.accept(bindException);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Perform an action if the given exception was caused by a specific exception type.\n\t * @param <E> the cause exception type\n\t * @param ex the source exception\n\t * @param causedBy the required cause type\n\t * @param action the action to perform\n\t * @since 2.2.7\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <E extends Exception> void ifCausedBy(Exception ex, Class<E> causedBy, Consumer<E> action) {\n\t\tThrowable candidate = ex;\n\t\twhile (candidate != null) {\n\t\t\tif (causedBy.isInstance(candidate)) {\n\t\t\t\taction.accept((E) candidate);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcandidate = candidate.getCause();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/PortInUseFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\n\n/**\n * A {@code FailureAnalyzer} that performs analysis of failures caused by a\n * {@code PortInUseException}.\n *\n * @author Andy Wilkinson\n */\nclass PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {\n\t\treturn new FailureAnalysis(\"Web server failed to start. Port \" + cause.getPort() + \" was already in use.\",\n\t\t\t\t\"Identify and stop the process that's listening on port \" + cause.getPort() + \" or configure this \"\n\t\t\t\t\t\t+ \"application to listen on another port.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Shutdown.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\n/**\n * Configuration for shutting down a {@link WebServer}.\n *\n * @author Andy Wilkinson\n * @since 2.3.0\n */\npublic enum Shutdown {\n\n\t/**\n\t * The {@link WebServer} should support graceful shutdown, allowing active requests\n\t * time to complete.\n\t */\n\tGRACEFUL,\n\n\t/**\n\t * The {@link WebServer} should shut down immediately.\n\t */\n\tIMMEDIATE\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/Ssl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationPropertiesSource;\nimport org.springframework.lang.Contract;\n\n/**\n * Simple server-independent abstraction for SSL configuration.\n *\n * @author Andy Wilkinson\n * @author Vladimir Tsanev\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 2.0.0\n */\n@ConfigurationPropertiesSource\npublic class Ssl {\n\n\t/**\n\t * Whether to enable SSL support.\n\t */\n\tprivate boolean enabled = true;\n\n\t/**\n\t * Name of a configured SSL bundle.\n\t */\n\tprivate @Nullable String bundle;\n\n\t/**\n\t * Client authentication mode. Requires a trust store.\n\t */\n\tprivate @Nullable ClientAuth clientAuth;\n\n\t/**\n\t * Supported SSL ciphers.\n\t */\n\tprivate String @Nullable [] ciphers;\n\n\t/**\n\t * Enabled SSL protocols.\n\t */\n\tprivate String @Nullable [] enabledProtocols;\n\n\t/**\n\t * Alias that identifies the key in the key store.\n\t */\n\tprivate @Nullable String keyAlias;\n\n\t/**\n\t * Password used to access the key in the key store.\n\t */\n\tprivate @Nullable String keyPassword;\n\n\t/**\n\t * Path to the key store that holds the SSL certificate (typically a jks file).\n\t */\n\tprivate @Nullable String keyStore;\n\n\t/**\n\t * Password used to access the key store.\n\t */\n\tprivate @Nullable String keyStorePassword;\n\n\t/**\n\t * Type of the key store.\n\t */\n\tprivate @Nullable String keyStoreType;\n\n\t/**\n\t * Provider for the key store.\n\t */\n\tprivate @Nullable String keyStoreProvider;\n\n\t/**\n\t * Trust store that holds SSL certificates.\n\t */\n\tprivate @Nullable String trustStore;\n\n\t/**\n\t * Password used to access the trust store.\n\t */\n\tprivate @Nullable String trustStorePassword;\n\n\t/**\n\t * Type of the trust store.\n\t */\n\tprivate @Nullable String trustStoreType;\n\n\t/**\n\t * Provider for the trust store.\n\t */\n\tprivate @Nullable String trustStoreProvider;\n\n\t/**\n\t * Path to a PEM-encoded SSL certificate file.\n\t */\n\tprivate @Nullable String certificate;\n\n\t/**\n\t * Path to a PEM-encoded private key file for the SSL certificate.\n\t */\n\tprivate @Nullable String certificatePrivateKey;\n\n\t/**\n\t * Path to a PEM-encoded SSL certificate authority file.\n\t */\n\tprivate @Nullable String trustCertificate;\n\n\t/**\n\t * Path to a PEM-encoded private key file for the SSL certificate authority.\n\t */\n\tprivate @Nullable String trustCertificatePrivateKey;\n\n\t/**\n\t * SSL protocol to use.\n\t */\n\tprivate String protocol = \"TLS\";\n\n\t/**\n\t * Mapping of host names to SSL bundles for SNI configuration.\n\t */\n\tprivate List<ServerNameSslBundle> serverNameBundles = new ArrayList<>();\n\n\t/**\n\t * Return whether to enable SSL support.\n\t * @return whether to enable SSL support\n\t */\n\tpublic boolean isEnabled() {\n\t\treturn this.enabled;\n\t}\n\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * Return the name of the SSL bundle to use.\n\t * @return the SSL bundle name\n\t * @since 3.1.0\n\t */\n\tpublic @Nullable String getBundle() {\n\t\treturn this.bundle;\n\t}\n\n\t/**\n\t * Set the name of the SSL bundle to use.\n\t * @param bundle the SSL bundle name\n\t * @since 3.1.0\n\t */\n\tpublic void setBundle(@Nullable String bundle) {\n\t\tthis.bundle = bundle;\n\t}\n\n\t/**\n\t * Return Whether client authentication is not wanted (\"none\"), wanted (\"want\") or\n\t * needed (\"need\"). Requires a trust store.\n\t * @return the {@link ClientAuth} to use\n\t */\n\tpublic @Nullable ClientAuth getClientAuth() {\n\t\treturn this.clientAuth;\n\t}\n\n\tpublic void setClientAuth(@Nullable ClientAuth clientAuth) {\n\t\tthis.clientAuth = clientAuth;\n\t}\n\n\t/**\n\t * Return the supported SSL ciphers.\n\t * @return the supported SSL ciphers\n\t */\n\tpublic String @Nullable [] getCiphers() {\n\t\treturn this.ciphers;\n\t}\n\n\tpublic void setCiphers(String @Nullable [] ciphers) {\n\t\tthis.ciphers = ciphers;\n\t}\n\n\t/**\n\t * Return the enabled SSL protocols.\n\t * @return the enabled SSL protocols.\n\t */\n\tpublic String @Nullable [] getEnabledProtocols() {\n\t\treturn this.enabledProtocols;\n\t}\n\n\tpublic void setEnabledProtocols(String @Nullable [] enabledProtocols) {\n\t\tthis.enabledProtocols = enabledProtocols;\n\t}\n\n\t/**\n\t * Return the alias that identifies the key in the key store.\n\t * @return the key alias\n\t */\n\tpublic @Nullable String getKeyAlias() {\n\t\treturn this.keyAlias;\n\t}\n\n\tpublic void setKeyAlias(@Nullable String keyAlias) {\n\t\tthis.keyAlias = keyAlias;\n\t}\n\n\t/**\n\t * Return the password used to access the key in the key store.\n\t * @return the key password\n\t */\n\tpublic @Nullable String getKeyPassword() {\n\t\treturn this.keyPassword;\n\t}\n\n\tpublic void setKeyPassword(@Nullable String keyPassword) {\n\t\tthis.keyPassword = keyPassword;\n\t}\n\n\t/**\n\t * Return the path to the key store that holds the SSL certificate (typically a jks\n\t * file).\n\t * @return the path to the key store\n\t */\n\tpublic @Nullable String getKeyStore() {\n\t\treturn this.keyStore;\n\t}\n\n\tpublic void setKeyStore(@Nullable String keyStore) {\n\t\tthis.keyStore = keyStore;\n\t}\n\n\t/**\n\t * Return the password used to access the key store.\n\t * @return the key store password\n\t */\n\tpublic @Nullable String getKeyStorePassword() {\n\t\treturn this.keyStorePassword;\n\t}\n\n\tpublic void setKeyStorePassword(@Nullable String keyStorePassword) {\n\t\tthis.keyStorePassword = keyStorePassword;\n\t}\n\n\t/**\n\t * Return the type of the key store.\n\t * @return the key store type\n\t */\n\tpublic @Nullable String getKeyStoreType() {\n\t\treturn this.keyStoreType;\n\t}\n\n\tpublic void setKeyStoreType(@Nullable String keyStoreType) {\n\t\tthis.keyStoreType = keyStoreType;\n\t}\n\n\t/**\n\t * Return the provider for the key store.\n\t * @return the key store provider\n\t */\n\tpublic @Nullable String getKeyStoreProvider() {\n\t\treturn this.keyStoreProvider;\n\t}\n\n\tpublic void setKeyStoreProvider(@Nullable String keyStoreProvider) {\n\t\tthis.keyStoreProvider = keyStoreProvider;\n\t}\n\n\t/**\n\t * Return the trust store that holds SSL certificates.\n\t * @return the trust store\n\t */\n\tpublic @Nullable String getTrustStore() {\n\t\treturn this.trustStore;\n\t}\n\n\tpublic void setTrustStore(@Nullable String trustStore) {\n\t\tthis.trustStore = trustStore;\n\t}\n\n\t/**\n\t * Return the password used to access the trust store.\n\t * @return the trust store password\n\t */\n\tpublic @Nullable String getTrustStorePassword() {\n\t\treturn this.trustStorePassword;\n\t}\n\n\tpublic void setTrustStorePassword(@Nullable String trustStorePassword) {\n\t\tthis.trustStorePassword = trustStorePassword;\n\t}\n\n\t/**\n\t * Return the type of the trust store.\n\t * @return the trust store type\n\t */\n\tpublic @Nullable String getTrustStoreType() {\n\t\treturn this.trustStoreType;\n\t}\n\n\tpublic void setTrustStoreType(@Nullable String trustStoreType) {\n\t\tthis.trustStoreType = trustStoreType;\n\t}\n\n\t/**\n\t * Return the provider for the trust store.\n\t * @return the trust store provider\n\t */\n\tpublic @Nullable String getTrustStoreProvider() {\n\t\treturn this.trustStoreProvider;\n\t}\n\n\tpublic void setTrustStoreProvider(@Nullable String trustStoreProvider) {\n\t\tthis.trustStoreProvider = trustStoreProvider;\n\t}\n\n\t/**\n\t * Return the location of the certificate in PEM format.\n\t * @return the certificate location\n\t */\n\tpublic @Nullable String getCertificate() {\n\t\treturn this.certificate;\n\t}\n\n\tpublic void setCertificate(@Nullable String certificate) {\n\t\tthis.certificate = certificate;\n\t}\n\n\t/**\n\t * Return the location of the private key for the certificate in PEM format.\n\t * @return the location of the certificate private key\n\t */\n\tpublic @Nullable String getCertificatePrivateKey() {\n\t\treturn this.certificatePrivateKey;\n\t}\n\n\tpublic void setCertificatePrivateKey(@Nullable String certificatePrivateKey) {\n\t\tthis.certificatePrivateKey = certificatePrivateKey;\n\t}\n\n\t/**\n\t * Return the location of the trust certificate authority chain in PEM format.\n\t * @return the location of the trust certificate\n\t */\n\tpublic @Nullable String getTrustCertificate() {\n\t\treturn this.trustCertificate;\n\t}\n\n\tpublic void setTrustCertificate(@Nullable String trustCertificate) {\n\t\tthis.trustCertificate = trustCertificate;\n\t}\n\n\t/**\n\t * Return the location of the private key for the trust certificate in PEM format.\n\t * @return the location of the trust certificate private key\n\t */\n\tpublic @Nullable String getTrustCertificatePrivateKey() {\n\t\treturn this.trustCertificatePrivateKey;\n\t}\n\n\tpublic void setTrustCertificatePrivateKey(@Nullable String trustCertificatePrivateKey) {\n\t\tthis.trustCertificatePrivateKey = trustCertificatePrivateKey;\n\t}\n\n\t/**\n\t * Return the SSL protocol to use.\n\t * @return the SSL protocol\n\t */\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\tpublic void setProtocol(String protocol) {\n\t\tthis.protocol = protocol;\n\t}\n\n\t/**\n\t * Returns if SSL is enabled for the given instance.\n\t * @param ssl the {@link Ssl SSL} instance or {@code null}\n\t * @return {@code true} if SSL is enabled\n\t * @since 3.1.0\n\t */\n\t@Contract(\"null -> false\")\n\tpublic static boolean isEnabled(@Nullable Ssl ssl) {\n\t\treturn (ssl != null) && ssl.isEnabled();\n\t}\n\n\t/**\n\t * Return the mapping of host names to SSL bundles for SNI configuration.\n\t * @return the host name to SSL bundle mapping\n\t */\n\tpublic List<ServerNameSslBundle> getServerNameBundles() {\n\t\treturn this.serverNameBundles;\n\t}\n\n\tpublic void setServerNameBundles(List<ServerNameSslBundle> serverNameBundles) {\n\t\tthis.serverNameBundles = serverNameBundles;\n\t}\n\n\t/**\n\t * Factory method to create an {@link Ssl} instance for a specific bundle name.\n\t * @param bundle the name of the bundle\n\t * @return a new {@link Ssl} instance with the bundle set\n\t * @since 3.1.0\n\t */\n\tpublic static Ssl forBundle(String bundle) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setBundle(bundle);\n\t\treturn ssl;\n\t}\n\n\tpublic record ServerNameSslBundle(String serverName, String bundle) {\n\t}\n\n\t/**\n\t * Client authentication types.\n\t */\n\tpublic enum ClientAuth {\n\n\t\t/**\n\t\t * Client authentication is not wanted.\n\t\t */\n\t\tNONE,\n\n\t\t/**\n\t\t * Client authentication is wanted but not mandatory.\n\t\t */\n\t\tWANT,\n\n\t\t/**\n\t\t * Client authentication is needed and mandatory.\n\t\t */\n\t\tNEED;\n\n\t\t/**\n\t\t * Map an optional {@link ClientAuth} value to a different type.\n\t\t * @param <R> the result type\n\t\t * @param clientAuth the client auth to map (may be {@code null})\n\t\t * @param none the value for {@link ClientAuth#NONE} or {@code null}\n\t\t * @param want the value for {@link ClientAuth#WANT}\n\t\t * @param need the value for {@link ClientAuth#NEED}\n\t\t * @return the mapped value\n\t\t * @since 3.1.0\n\t\t */\n\t\t@Contract(\"_, !null, _, _ -> !null\")\n\t\tpublic static <R> @Nullable R map(@Nullable ClientAuth clientAuth, @Nullable R none, R want, R need) {\n\t\t\tif (clientAuth == null) {\n\t\t\t\treturn none;\n\t\t\t}\n\t\t\treturn switch (clientAuth) {\n\t\t\t\tcase NONE -> none;\n\t\t\t\tcase WANT -> want;\n\t\t\t\tcase NEED -> need;\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\n/**\n * Simple interface that represents a fully configured web server (for example Tomcat,\n * Jetty, Netty). Allows the server to be {@link #start() started} and {@link #stop()\n * stopped}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @since 2.0.0\n */\npublic interface WebServer {\n\n\t/**\n\t * Starts the web server. Calling this method on an already started server has no\n\t * effect.\n\t * @throws WebServerException if the server cannot be started\n\t */\n\tvoid start() throws WebServerException;\n\n\t/**\n\t * Stops the web server. Calling this method on an already stopped server has no\n\t * effect.\n\t * @throws WebServerException if the server cannot be stopped\n\t */\n\tvoid stop() throws WebServerException;\n\n\t/**\n\t * Return the port this server is listening on.\n\t * @return the port (or -1 if none)\n\t */\n\tint getPort();\n\n\t/**\n\t * Initiates a graceful shutdown of the web server. Handling of new requests is\n\t * prevented and the given {@code callback} is invoked at the end of the attempt. The\n\t * attempt can be explicitly ended by invoking {@link #stop}. The default\n\t * implementation invokes the callback immediately with\n\t * {@link GracefulShutdownResult#IMMEDIATE}, i.e. no attempt is made at a graceful\n\t * shutdown.\n\t * @param callback the callback to invoke when the graceful shutdown completes\n\t * @since 2.3.0\n\t */\n\tdefault void shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tcallback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);\n\t}\n\n\t/**\n\t * Destroys the web server such that it cannot be started again.\n\t * @since 3.2.0\n\t */\n\tdefault void destroy() {\n\t\tstop();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Exceptions thrown by a web server.\n *\n * @author Phillip Webb\n * @since 2.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class WebServerException extends RuntimeException {\n\n\tpublic WebServerException(String message, @Nullable Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\n/**\n * Tagging interface for factories that create a {@link WebServer}.\n *\n * @author Phillip Webb\n * @since 2.0.0\n * @see WebServer\n * @see org.springframework.boot.web.server.servlet.ServletWebServerFactory\n * @see org.springframework.boot.web.server.reactive.ReactiveWebServerFactory\n */\npublic interface WebServerFactory {\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\n\n/**\n * Strategy interface for customizing {@link WebServerFactory web server factories}. Any\n * beans of this type will get a callback with the server factory before the server itself\n * is started, so you can set the port, address, error pages etc.\n * <p>\n * Beware: calls to this interface are usually made from a\n * {@link WebServerFactoryCustomizerBeanPostProcessor} which is a\n * {@link BeanPostProcessor} (so called very early in the ApplicationContext lifecycle).\n * It might be safer to lookup dependencies lazily in the enclosing BeanFactory rather\n * than injecting them with {@code @Autowired}.\n *\n * @param <T> the configurable web server factory\n * @author Phillip Webb\n * @author Dave Syer\n * @author Brian Clozel\n * @since 2.0.0\n * @see WebServerFactoryCustomizerBeanPostProcessor\n */\n@FunctionalInterface\npublic interface WebServerFactoryCustomizer<T extends WebServerFactory> {\n\n\t/**\n\t * Customize the specified {@link WebServerFactory}.\n\t * @param factory the web server factory to customize\n\t */\n\tvoid customize(T factory);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.util.LambdaSafe;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.util.Assert;\n\n/**\n * {@link BeanPostProcessor} that applies all {@link WebServerFactoryCustomizer} beans\n * from the bean factory to {@link WebServerFactory} beans.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 2.0.0\n */\npublic class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ListableBeanFactory beanFactory;\n\n\tprivate @Nullable List<WebServerFactoryCustomizer<?>> customizers;\n\n\t@Override\n\tpublic void setBeanFactory(BeanFactory beanFactory) {\n\t\tAssert.isInstanceOf(ListableBeanFactory.class, beanFactory, \"'beanFactory' must be a ListableBeanFactory\");\n\t\tthis.beanFactory = (ListableBeanFactory) beanFactory;\n\t}\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof WebServerFactory webServerFactory) {\n\t\t\tpostProcessBeforeInitialization(webServerFactory);\n\t\t}\n\t\treturn bean;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\treturn bean;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void postProcessBeforeInitialization(WebServerFactory webServerFactory) {\n\t\tLambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)\n\t\t\t.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)\n\t\t\t.invoke((customizer) -> customizer.customize(webServerFactory));\n\t}\n\n\tprivate Collection<WebServerFactoryCustomizer<?>> getCustomizers() {\n\t\tif (this.customizers == null) {\n\t\t\t// Look up does not include the parent context\n\t\t\tthis.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());\n\t\t\tthis.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);\n\t\t\tthis.customizers = Collections.unmodifiableList(this.customizers);\n\t\t}\n\t\treturn this.customizers;\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {\n\t\treturn (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/WebServerSslBundle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.security.KeyStore;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.ssl.SslManagerBundle;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.core.style.ToStringCreator;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link SslBundle} backed by {@link Ssl}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @since 3.1.0\n */\npublic final class WebServerSslBundle implements SslBundle {\n\n\tprivate final SslStoreBundle stores;\n\n\tprivate final SslBundleKey key;\n\n\tprivate final SslOptions options;\n\n\tprivate final String protocol;\n\n\tprivate final SslManagerBundle managers;\n\n\tprivate WebServerSslBundle(SslStoreBundle stores, @Nullable String keyPassword, Ssl ssl) {\n\t\tthis.stores = stores;\n\t\tthis.key = SslBundleKey.of(keyPassword, ssl.getKeyAlias());\n\t\tthis.protocol = ssl.getProtocol();\n\t\tthis.options = SslOptions.of(ssl.getCiphers(), ssl.getEnabledProtocols());\n\t\tthis.managers = SslManagerBundle.from(this.stores, this.key);\n\t}\n\n\tprivate static SslStoreBundle createPemKeyStoreBundle(Ssl ssl) {\n\t\tPemSslStoreDetails keyStoreDetails = new PemSslStoreDetails(ssl.getKeyStoreType(), ssl.getCertificate(),\n\t\t\t\tssl.getCertificatePrivateKey())\n\t\t\t.withAlias(ssl.getKeyAlias());\n\t\treturn new PemSslStoreBundle(keyStoreDetails, null);\n\t}\n\n\tprivate static SslStoreBundle createPemTrustStoreBundle(Ssl ssl) {\n\t\tPemSslStoreDetails trustStoreDetails = new PemSslStoreDetails(ssl.getTrustStoreType(),\n\t\t\t\tssl.getTrustCertificate(), ssl.getTrustCertificatePrivateKey())\n\t\t\t.withAlias(ssl.getKeyAlias());\n\t\treturn new PemSslStoreBundle(null, trustStoreDetails);\n\t}\n\n\tprivate static SslStoreBundle createJksKeyStoreBundle(Ssl ssl) {\n\t\tJksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(ssl.getKeyStoreType(), ssl.getKeyStoreProvider(),\n\t\t\t\tssl.getKeyStore(), ssl.getKeyStorePassword());\n\t\treturn new JksSslStoreBundle(keyStoreDetails, null);\n\t}\n\n\tprivate static SslStoreBundle createJksTrustStoreBundle(Ssl ssl) {\n\t\tJksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(ssl.getTrustStoreType(),\n\t\t\t\tssl.getTrustStoreProvider(), ssl.getTrustStore(), ssl.getTrustStorePassword());\n\t\treturn new JksSslStoreBundle(null, trustStoreDetails);\n\t}\n\n\t@Override\n\tpublic SslStoreBundle getStores() {\n\t\treturn this.stores;\n\t}\n\n\t@Override\n\tpublic SslBundleKey getKey() {\n\t\treturn this.key;\n\t}\n\n\t@Override\n\tpublic SslOptions getOptions() {\n\t\treturn this.options;\n\t}\n\n\t@Override\n\tpublic String getProtocol() {\n\t\treturn this.protocol;\n\t}\n\n\t@Override\n\tpublic SslManagerBundle getManagers() {\n\t\treturn this.managers;\n\t}\n\n\t/**\n\t * Get the {@link SslBundle} that should be used for the given {@link Ssl} instance.\n\t * @param ssl the source ssl instance\n\t * @return a {@link SslBundle} instance\n\t * @throws NoSuchSslBundleException if a bundle lookup fails\n\t */\n\tpublic static SslBundle get(Ssl ssl) throws NoSuchSslBundleException {\n\t\treturn get(ssl, null);\n\t}\n\n\t/**\n\t * Get the {@link SslBundle} that should be used for the given {@link Ssl} instance.\n\t * @param ssl the source ssl instance\n\t * @param sslBundles the bundles that should be used when {@link Ssl#getBundle()} is\n\t * set\n\t * @return a {@link SslBundle} instance\n\t * @throws NoSuchSslBundleException if a bundle lookup fails\n\t */\n\tpublic static SslBundle get(@Nullable Ssl ssl, @Nullable SslBundles sslBundles) throws NoSuchSslBundleException {\n\t\tAssert.state(Ssl.isEnabled(ssl), \"SSL is not enabled\");\n\t\tString keyPassword = ssl.getKeyPassword();\n\t\tString bundleName = ssl.getBundle();\n\t\tif (StringUtils.hasText(bundleName)) {\n\t\t\tAssert.state(sslBundles != null,\n\t\t\t\t\t() -> \"SSL bundle '%s' was requested but no SslBundles instance was provided\"\n\t\t\t\t\t\t.formatted(bundleName));\n\t\t\treturn sslBundles.getBundle(bundleName);\n\t\t}\n\t\tSslStoreBundle stores = createStoreBundle(ssl);\n\t\treturn new WebServerSslBundle(stores, keyPassword, ssl);\n\t}\n\n\tprivate static SslStoreBundle createStoreBundle(Ssl ssl) {\n\t\tKeyStore keyStore = createKeyStore(ssl);\n\t\tKeyStore trustStore = createTrustStore(ssl);\n\t\treturn new WebServerSslStoreBundle(keyStore, trustStore, ssl.getKeyStorePassword());\n\t}\n\n\tprivate static @Nullable KeyStore createKeyStore(Ssl ssl) {\n\t\tif (hasPemKeyStoreProperties(ssl)) {\n\t\t\treturn createPemKeyStoreBundle(ssl).getKeyStore();\n\t\t}\n\t\telse if (hasJksKeyStoreProperties(ssl)) {\n\t\t\treturn createJksKeyStoreBundle(ssl).getKeyStore();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static @Nullable KeyStore createTrustStore(Ssl ssl) {\n\t\tif (hasPemTrustStoreProperties(ssl)) {\n\t\t\treturn createPemTrustStoreBundle(ssl).getTrustStore();\n\t\t}\n\t\telse if (hasJksTrustStoreProperties(ssl)) {\n\t\t\treturn createJksTrustStoreBundle(ssl).getTrustStore();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static boolean hasPemKeyStoreProperties(Ssl ssl) {\n\t\treturn Ssl.isEnabled(ssl) && ssl.getCertificate() != null && ssl.getCertificatePrivateKey() != null;\n\t}\n\n\tprivate static boolean hasPemTrustStoreProperties(Ssl ssl) {\n\t\treturn Ssl.isEnabled(ssl) && ssl.getTrustCertificate() != null;\n\t}\n\n\tprivate static boolean hasJksKeyStoreProperties(Ssl ssl) {\n\t\treturn Ssl.isEnabled(ssl) && (ssl.getKeyStore() != null\n\t\t\t\t|| (ssl.getKeyStoreType() != null && ssl.getKeyStoreType().equals(\"PKCS11\")));\n\t}\n\n\tprivate static boolean hasJksTrustStoreProperties(Ssl ssl) {\n\t\treturn Ssl.isEnabled(ssl) && (ssl.getTrustStore() != null\n\t\t\t\t|| (ssl.getTrustStoreType() != null && ssl.getTrustStoreType().equals(\"PKCS11\")));\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\tToStringCreator creator = new ToStringCreator(this);\n\t\tcreator.append(\"key\", this.key);\n\t\tcreator.append(\"protocol\", this.protocol);\n\t\tcreator.append(\"stores\", this.stores);\n\t\tcreator.append(\"options\", this.options);\n\t\treturn creator.toString();\n\t}\n\n\tprivate static final class WebServerSslStoreBundle implements SslStoreBundle {\n\n\t\tprivate final @Nullable KeyStore keyStore;\n\n\t\tprivate final @Nullable KeyStore trustStore;\n\n\t\tprivate final @Nullable String keyStorePassword;\n\n\t\tprivate WebServerSslStoreBundle(@Nullable KeyStore keyStore, @Nullable KeyStore trustStore,\n\t\t\t\t@Nullable String keyStorePassword) {\n\t\t\tAssert.state(keyStore != null || trustStore != null,\n\t\t\t\t\t\"SSL is enabled but no trust material is configured for the default host\");\n\t\t\tthis.keyStore = keyStore;\n\t\t\tthis.trustStore = trustStore;\n\t\t\tthis.keyStorePassword = keyStorePassword;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable KeyStore getKeyStore() {\n\t\t\treturn this.keyStore;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable KeyStore getTrustStore() {\n\t\t\treturn this.trustStore;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable String getKeyStorePassword() {\n\t\t\treturn this.keyStorePassword;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\tToStringCreator creator = new ToStringCreator(this);\n\t\t\tcreator.append(\"keyStore.type\", (this.keyStore != null) ? this.keyStore.getType() : \"none\");\n\t\t\tcreator.append(\"keyStorePassword\", (this.keyStorePassword != null) ? \"******\" : null);\n\t\t\tcreator.append(\"trustStore.type\", (this.trustStore != null) ? this.trustStore.getType() : \"none\");\n\t\t\treturn creator.toString();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/ServerProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure;\n\nimport java.net.InetAddress;\nimport java.nio.charset.Charset;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.boot.web.server.Cookie;\nimport org.springframework.boot.web.server.Http2;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.servlet.Jsp;\nimport org.springframework.boot.web.server.servlet.Session;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for a web server (e.g. port\n * and path settings).\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Ivan Sopov\n * @author Marcos Barbero\n * @author Eddú Meléndez\n * @author Quinten De Swaef\n * @author Venil Noronha\n * @author Aurélien Leboulanger\n * @author Brian Clozel\n * @author Olivier Lamy\n * @author Chentao Qu\n * @author Artsiom Yudovin\n * @author Andrew McGhie\n * @author Rafiullah Hamedy\n * @author Dirk Deyne\n * @author HaiTao Zhang\n * @author Victor Mandujano\n * @author Chris Bono\n * @author Parviz Rozikov\n * @author Florian Storz\n * @author Michael Weidmann\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@ConfigurationProperties(\"server\")\npublic class ServerProperties {\n\n\t/**\n\t * Server HTTP port.\n\t */\n\tprivate @Nullable Integer port;\n\n\t/**\n\t * Network address to which the server should bind.\n\t */\n\tprivate @Nullable InetAddress address;\n\n\t/**\n\t * Strategy for handling X-Forwarded-* headers.\n\t */\n\tprivate @Nullable ForwardHeadersStrategy forwardHeadersStrategy;\n\n\t/**\n\t * Value to use for the Server response header (if empty, no header is sent).\n\t */\n\tprivate @Nullable String serverHeader;\n\n\t/**\n\t * Maximum size of the HTTP request header. Refer to the documentation for your chosen\n\t * embedded server for details of exactly how this limit is applied. For example,\n\t * Netty applies the limit separately to each individual header in the request whereas\n\t * Tomcat applies the limit to the combined size of the request line and all of the\n\t * header names and values in the request.\n\t */\n\tprivate DataSize maxHttpRequestHeaderSize = DataSize.ofKilobytes(8);\n\n\t/**\n\t * Type of shutdown that the server will support.\n\t */\n\tprivate Shutdown shutdown = Shutdown.GRACEFUL;\n\n\t@NestedConfigurationProperty\n\tprivate @Nullable Ssl ssl;\n\n\t@NestedConfigurationProperty\n\tprivate final Compression compression = new Compression();\n\n\t/**\n\t * Custom MIME mappings in addition to the default MIME mappings.\n\t */\n\tprivate final MimeMappings mimeMappings = new MimeMappings();\n\n\t@NestedConfigurationProperty\n\tprivate final Http2 http2 = new Http2();\n\n\tprivate final Servlet servlet = new Servlet();\n\n\tprivate final Reactive reactive = new Reactive();\n\n\tpublic @Nullable Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(@Nullable Integer port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic @Nullable InetAddress getAddress() {\n\t\treturn this.address;\n\t}\n\n\tpublic void setAddress(@Nullable InetAddress address) {\n\t\tthis.address = address;\n\t}\n\n\tpublic @Nullable String getServerHeader() {\n\t\treturn this.serverHeader;\n\t}\n\n\tpublic void setServerHeader(@Nullable String serverHeader) {\n\t\tthis.serverHeader = serverHeader;\n\t}\n\n\tpublic DataSize getMaxHttpRequestHeaderSize() {\n\t\treturn this.maxHttpRequestHeaderSize;\n\t}\n\n\tpublic void setMaxHttpRequestHeaderSize(DataSize maxHttpRequestHeaderSize) {\n\t\tthis.maxHttpRequestHeaderSize = maxHttpRequestHeaderSize;\n\t}\n\n\tpublic Shutdown getShutdown() {\n\t\treturn this.shutdown;\n\t}\n\n\tpublic void setShutdown(Shutdown shutdown) {\n\t\tthis.shutdown = shutdown;\n\t}\n\n\tpublic @Nullable Ssl getSsl() {\n\t\treturn this.ssl;\n\t}\n\n\tpublic void setSsl(@Nullable Ssl ssl) {\n\t\tthis.ssl = ssl;\n\t}\n\n\tpublic Compression getCompression() {\n\t\treturn this.compression;\n\t}\n\n\tpublic MimeMappings getMimeMappings() {\n\t\treturn this.mimeMappings;\n\t}\n\n\tpublic void setMimeMappings(Map<String, String> customMappings) {\n\t\tcustomMappings.forEach(this.mimeMappings::add);\n\t}\n\n\tpublic Http2 getHttp2() {\n\t\treturn this.http2;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic Reactive getReactive() {\n\t\treturn this.reactive;\n\t}\n\n\tpublic @Nullable ForwardHeadersStrategy getForwardHeadersStrategy() {\n\t\treturn this.forwardHeadersStrategy;\n\t}\n\n\tpublic void setForwardHeadersStrategy(@Nullable ForwardHeadersStrategy forwardHeadersStrategy) {\n\t\tthis.forwardHeadersStrategy = forwardHeadersStrategy;\n\t}\n\n\t/**\n\t * Servlet server properties.\n\t */\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Servlet context init parameters.\n\t\t */\n\t\tprivate final Map<String, String> contextParameters = new HashMap<>();\n\n\t\t/**\n\t\t * Context path of the application.\n\t\t */\n\t\tprivate @Nullable String contextPath;\n\n\t\t/**\n\t\t * Display name of the application.\n\t\t */\n\t\tprivate String applicationDisplayName = \"application\";\n\n\t\t/**\n\t\t * Whether to register the default Servlet with the container.\n\t\t */\n\t\tprivate boolean registerDefaultServlet;\n\n\t\tprivate final Encoding encoding = new Encoding();\n\n\t\t@NestedConfigurationProperty\n\t\tprivate final Jsp jsp = new Jsp();\n\n\t\t@NestedConfigurationProperty\n\t\tprivate final Session session = new Session();\n\n\t\tpublic @Nullable String getContextPath() {\n\t\t\treturn this.contextPath;\n\t\t}\n\n\t\tpublic void setContextPath(@Nullable String contextPath) {\n\t\t\tthis.contextPath = cleanContextPath(contextPath);\n\t\t}\n\n\t\tprivate @Nullable String cleanContextPath(@Nullable String contextPath) {\n\t\t\tString candidate = null;\n\t\t\tif (StringUtils.hasLength(contextPath)) {\n\t\t\t\tcandidate = contextPath.strip();\n\t\t\t}\n\t\t\tif (StringUtils.hasText(candidate) && candidate.endsWith(\"/\")) {\n\t\t\t\treturn candidate.substring(0, candidate.length() - 1);\n\t\t\t}\n\t\t\treturn candidate;\n\t\t}\n\n\t\tpublic String getApplicationDisplayName() {\n\t\t\treturn this.applicationDisplayName;\n\t\t}\n\n\t\tpublic void setApplicationDisplayName(String displayName) {\n\t\t\tthis.applicationDisplayName = displayName;\n\t\t}\n\n\t\tpublic boolean isRegisterDefaultServlet() {\n\t\t\treturn this.registerDefaultServlet;\n\t\t}\n\n\t\tpublic void setRegisterDefaultServlet(boolean registerDefaultServlet) {\n\t\t\tthis.registerDefaultServlet = registerDefaultServlet;\n\t\t}\n\n\t\tpublic Map<String, String> getContextParameters() {\n\t\t\treturn this.contextParameters;\n\t\t}\n\n\t\tpublic Encoding getEncoding() {\n\t\t\treturn this.encoding;\n\t\t}\n\n\t\tpublic Jsp getJsp() {\n\t\t\treturn this.jsp;\n\t\t}\n\n\t\tpublic Session getSession() {\n\t\t\treturn this.session;\n\t\t}\n\n\t}\n\n\t/**\n\t * Reactive server properties.\n\t */\n\tpublic static class Reactive {\n\n\t\tprivate final Session session = new Session();\n\n\t\tpublic Session getSession() {\n\t\t\treturn this.session;\n\t\t}\n\n\t\tpublic static class Session {\n\n\t\t\t/**\n\t\t\t * Session timeout. If a duration suffix is not specified, seconds will be\n\t\t\t * used.\n\t\t\t */\n\t\t\t@DurationUnit(ChronoUnit.SECONDS)\n\t\t\tprivate Duration timeout = Duration.ofMinutes(30);\n\n\t\t\t/**\n\t\t\t * Maximum number of sessions that can be stored.\n\t\t\t */\n\t\t\tprivate int maxSessions = 10000;\n\n\t\t\t@NestedConfigurationProperty\n\t\t\tprivate final Cookie cookie = new Cookie();\n\n\t\t\tpublic Duration getTimeout() {\n\t\t\t\treturn this.timeout;\n\t\t\t}\n\n\t\t\tpublic void setTimeout(Duration timeout) {\n\t\t\t\tthis.timeout = timeout;\n\t\t\t}\n\n\t\t\tpublic int getMaxSessions() {\n\t\t\t\treturn this.maxSessions;\n\t\t\t}\n\n\t\t\tpublic void setMaxSessions(int maxSessions) {\n\t\t\t\tthis.maxSessions = maxSessions;\n\t\t\t}\n\n\t\t\tpublic Cookie getCookie() {\n\t\t\t\treturn this.cookie;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Strategies for supporting forward headers.\n\t */\n\tpublic enum ForwardHeadersStrategy {\n\n\t\t/**\n\t\t * Use the underlying container's native support for forwarded headers.\n\t\t */\n\t\tNATIVE,\n\n\t\t/**\n\t\t * Use Spring's support for handling forwarded headers.\n\t\t */\n\t\tFRAMEWORK,\n\n\t\t/**\n\t\t * Ignore X-Forwarded-* headers.\n\t\t */\n\t\tNONE\n\n\t}\n\n\tpublic static class Encoding {\n\n\t\t/**\n\t\t * Mapping of locale to charset for response encoding.\n\t\t */\n\t\tprivate @Nullable Map<Locale, Charset> mapping;\n\n\t\tpublic @Nullable Map<Locale, Charset> getMapping() {\n\t\t\treturn this.mapping;\n\t\t}\n\n\t\tpublic void setMapping(@Nullable Map<Locale, Charset> mapping) {\n\t\t\tthis.mapping = mapping;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a web server.\n */\n@NullMarked\npackage org.springframework.boot.web.server.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.reactive;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.server.adapter.ForwardedHeaderTransformer;\n\n/**\n * {@link Configuration Configuration} for a reactive web server.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 4.0.0\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(ServerProperties.class)\n@Import(ReactiveWebServerConfiguration.BeanPostProcessorsRegistrar.class)\npublic class ReactiveWebServerConfiguration {\n\n\t@Bean\n\tReactiveWebServerFactoryCustomizer reactiveWebServerFactoryCustomizer(ServerProperties serverProperties,\n\t\t\tObjectProvider<SslBundles> sslBundles) {\n\t\treturn new ReactiveWebServerFactoryCustomizer(serverProperties, sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(name = \"server.forward-headers-strategy\", havingValue = \"framework\")\n\tForwardedHeaderTransformer forwardedHeaderTransformer() {\n\t\treturn new ForwardedHeaderTransformer();\n\t}\n\n\t/**\n\t * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via\n\t * {@link ImportBeanDefinitionRegistrar} for early registration.\n\t */\n\tstatic class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {\n\n\t\tprivate @Nullable ConfigurableListableBeanFactory beanFactory;\n\n\t\t@Override\n\t\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\t\tif (beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {\n\t\t\t\tthis.beanFactory = listableBeanFactory;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,\n\t\t\t\tBeanDefinitionRegistry registry) {\n\t\t\tif (this.beanFactory == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tregisterSyntheticBeanIfMissing(this.beanFactory, registry, \"webServerFactoryCustomizerBeanPostProcessor\",\n\t\t\t\t\tWebServerFactoryCustomizerBeanPostProcessor.class);\n\t\t}\n\n\t\tprivate <T> void registerSyntheticBeanIfMissing(ConfigurableListableBeanFactory beanFactory,\n\t\t\t\tBeanDefinitionRegistry registry, String name, Class<T> beanClass) {\n\t\t\tif (ObjectUtils.isEmpty(beanFactory.getBeanNamesForType(beanClass, true, false))) {\n\t\t\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);\n\t\t\t\tbeanDefinition.setSynthetic(true);\n\t\t\t\tregistry.registerBeanDefinition(name, beanDefinition);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.reactive;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} to reactive\n * servers.\n *\n * @author Brian Clozel\n * @author Yunkun Huang\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic class ReactiveWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory>, Ordered {\n\n\tprivate final ServerProperties serverProperties;\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\t/**\n\t * Create a new {@link ReactiveWebServerFactoryCustomizer} instance.\n\t * @param serverProperties the server properties\n\t */\n\tpublic ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties) {\n\t\tthis(serverProperties, null);\n\t}\n\n\t/**\n\t * Create a new {@link ReactiveWebServerFactoryCustomizer} instance.\n\t * @param serverProperties the server properties\n\t * @param sslBundles the SSL bundles\n\t * @since 4.0.0\n\t */\n\tpublic ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties, @Nullable SslBundles sslBundles) {\n\t\tthis.serverProperties = serverProperties;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableReactiveWebServerFactory factory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.serverProperties::getPort).to(factory::setPort);\n\t\tmap.from(this.serverProperties::getAddress).to(factory::setAddress);\n\t\tmap.from(this.serverProperties::getSsl).to(factory::setSsl);\n\t\tmap.from(this.serverProperties::getCompression).to(factory::setCompression);\n\t\tmap.from(this.serverProperties::getHttp2).to(factory::setHttp2);\n\t\tmap.from(this.serverProperties.getShutdown()).to(factory::setShutdown);\n\t\tmap.from(() -> this.sslBundles).to(factory::setSslBundles);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a reactive web server.\n */\n@NullMarked\npackage org.springframework.boot.web.server.autoconfigure.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ForwardedHeaderFilterCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.servlet;\n\nimport org.springframework.web.filter.ForwardedHeaderFilter;\n\n/**\n * Customizer for the auto-configured {@link ForwardedHeaderFilter}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface ForwardedHeaderFilterCustomizer {\n\n\t/**\n\t * Customizes the given {@code filter}.\n\t * @param filter the filter to customize\n\t */\n\tvoid customize(ForwardedHeaderFilter filter);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.servlet;\n\nimport jakarta.servlet.DispatcherType;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.BeanFactoryAware;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.error.ErrorPageRegistrarBeanPostProcessor;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistrar;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.filter.ForwardedHeaderFilter;\n\n/**\n * {@link Configuration Configuration} for a servlet web server.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Ivan Sopov\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @since 4.0.0\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(ServerProperties.class)\n@Import(ServletWebServerConfiguration.BeanPostProcessorsRegistrar.class)\npublic class ServletWebServerConfiguration {\n\n\t@Bean\n\tServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,\n\t\t\tObjectProvider<WebListenerRegistrar> webListenerRegistrars,\n\t\t\tObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers, ObjectProvider<SslBundles> sslBundles) {\n\t\treturn new ServletWebServerFactoryCustomizer(serverProperties, webListenerRegistrars.orderedStream().toList(),\n\t\t\t\tcookieSameSiteSuppliers.orderedStream().toList(), sslBundles.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnProperty(name = \"server.forward-headers-strategy\", havingValue = \"framework\")\n\t@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)\n\tFilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(\n\t\t\tObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {\n\t\tForwardedHeaderFilter filter = new ForwardedHeaderFilter();\n\t\tcustomizerProvider.ifAvailable((customizer) -> customizer.customize(filter));\n\t\tFilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);\n\t\tregistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);\n\t\tregistration.setOrder(Ordered.HIGHEST_PRECEDENCE);\n\t\treturn registration;\n\t}\n\n\t/**\n\t * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via\n\t * {@link ImportBeanDefinitionRegistrar} for early registration.\n\t */\n\tstatic class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {\n\n\t\tprivate @Nullable ConfigurableListableBeanFactory beanFactory;\n\n\t\t@Override\n\t\tpublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {\n\t\t\tif (beanFactory instanceof ConfigurableListableBeanFactory listableBeanFactory) {\n\t\t\t\tthis.beanFactory = listableBeanFactory;\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,\n\t\t\t\tBeanDefinitionRegistry registry) {\n\t\t\tif (this.beanFactory == null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tregisterSyntheticBeanIfMissing(this.beanFactory, registry, \"webServerFactoryCustomizerBeanPostProcessor\",\n\t\t\t\t\tWebServerFactoryCustomizerBeanPostProcessor.class);\n\t\t\tregisterSyntheticBeanIfMissing(this.beanFactory, registry, \"errorPageRegistrarBeanPostProcessor\",\n\t\t\t\t\tErrorPageRegistrarBeanPostProcessor.class);\n\t\t}\n\n\t\tprivate <T> void registerSyntheticBeanIfMissing(ConfigurableListableBeanFactory beanFactory,\n\t\t\t\tBeanDefinitionRegistry registry, String name, Class<T> beanClass) {\n\t\t\tif (ObjectUtils.isEmpty(beanFactory.getBeanNamesForType(beanClass, true, false))) {\n\t\t\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);\n\t\t\t\tbeanDefinition.setSynthetic(true);\n\t\t\t\tregistry.registerBeanDefinition(name, beanDefinition);\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerFactoryCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.servlet;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistrar;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * {@link WebServerFactoryCustomizer} to apply {@link ServerProperties} and\n * {@link WebListenerRegistrar WebListenerRegistrars} to servlet web servers.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Olivier Lamy\n * @author Yunkun Huang\n * @author Scott Frederick\n * @author Lasse Wulff\n * @since 4.0.0\n */\npublic class ServletWebServerFactoryCustomizer\n\t\timplements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {\n\n\tprivate final ServerProperties serverProperties;\n\n\tprivate final List<WebListenerRegistrar> webListenerRegistrars;\n\n\tprivate final List<CookieSameSiteSupplier> cookieSameSiteSuppliers;\n\n\tprivate final @Nullable SslBundles sslBundles;\n\n\tpublic ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {\n\t\tthis(serverProperties, Collections.emptyList(), Collections.emptyList(), null);\n\t}\n\n\tpublic ServletWebServerFactoryCustomizer(ServerProperties serverProperties,\n\t\t\tList<WebListenerRegistrar> webListenerRegistrars, List<CookieSameSiteSupplier> cookieSameSiteSuppliers,\n\t\t\t@Nullable SslBundles sslBundles) {\n\t\tthis.serverProperties = serverProperties;\n\t\tthis.webListenerRegistrars = webListenerRegistrars;\n\t\tthis.cookieSameSiteSuppliers = cookieSameSiteSuppliers;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableServletWebServerFactory factory) {\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(this.serverProperties::getPort).to(factory::setPort);\n\t\tmap.from(this.serverProperties::getAddress).to(factory::setAddress);\n\t\tmap.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);\n\t\tmap.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);\n\t\tmap.from(this.serverProperties.getServlet()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);\n\t\tmap.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);\n\t\tmap.from(this.serverProperties::getSsl).to(factory::setSsl);\n\t\tmap.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);\n\t\tmap.from(this.serverProperties::getCompression).to(factory::setCompression);\n\t\tmap.from(this.serverProperties::getHttp2).to(factory::setHttp2);\n\t\tmap.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);\n\t\tmap.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);\n\t\tmap.from(this.serverProperties.getShutdown()).to(factory::setShutdown);\n\t\tmap.from(() -> this.sslBundles).to(factory::setSslBundles);\n\t\tmap.from(() -> this.cookieSameSiteSuppliers)\n\t\t\t.whenNot(CollectionUtils::isEmpty)\n\t\t\t.to(factory::setCookieSameSiteSuppliers);\n\t\tmap.from(this.serverProperties::getMimeMappings).to(factory::addMimeMappings);\n\t\tmap.from(this.serverProperties.getServlet().getEncoding()::getMapping).to(factory::setLocaleCharsetMappings);\n\t\tthis.webListenerRegistrars.forEach((registrar) -> registrar.register(factory));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes related to the auto-configuration of a servlet web server.\n */\n@NullMarked\npackage org.springframework.boot.web.server.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/ConfigurableWebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * SPI interface to be implemented by most if not all {@link WebServerApplicationContext\n * web server application contexts}. Provides facilities to configure the context, in\n * addition to the methods in the {WebServerApplicationContext} interface.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface ConfigurableWebServerApplicationContext\n\t\textends ConfigurableApplicationContext, WebServerApplicationContext {\n\n\t/**\n\t * Set the server namespace of the context.\n\t * @param serverNamespace the server namespace\n\t * @see #getServerNamespace()\n\t */\n\tvoid setServerNamespace(@Nullable String serverNamespace);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.web.server.WebServerFactory;\n\n/**\n * Exception thrown when there is no {@link WebServerFactory} bean of the required type\n * defined in a {@link WebServerApplicationContext}.\n *\n * @author Guirong Hu\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class MissingWebServerFactoryBeanException extends NoSuchBeanDefinitionException {\n\n\tprivate final WebApplicationType webApplicationType;\n\n\t/**\n\t * Create a new {@code MissingWebServerFactoryBeanException}.\n\t * @param webServerApplicationContextClass the class of the\n\t * WebServerApplicationContext that required the WebServerFactory\n\t * @param webServerFactoryClass the class of the WebServerFactory that was missing\n\t * @param webApplicationType the type of the web application\n\t */\n\tpublic MissingWebServerFactoryBeanException(\n\t\t\tClass<? extends WebServerApplicationContext> webServerApplicationContextClass,\n\t\t\tClass<? extends WebServerFactory> webServerFactoryClass, WebApplicationType webApplicationType) {\n\t\tsuper(webServerFactoryClass, String.format(\"Unable to start %s due to missing %s bean\",\n\t\t\t\twebServerApplicationContextClass.getSimpleName(), webServerFactoryClass.getSimpleName()));\n\t\tthis.webApplicationType = webApplicationType;\n\t}\n\n\t/**\n\t * Returns the type of web application for which a {@link WebServerFactory} bean was\n\t * missing.\n\t * @return the type of web application\n\t */\n\tpublic WebApplicationType getWebApplicationType() {\n\t\treturn this.webApplicationType;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.util.Locale;\n\nimport org.springframework.boot.diagnostics.AbstractFailureAnalyzer;\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.diagnostics.FailureAnalyzer;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.Assert;\n\n/**\n * A {@link FailureAnalyzer} that performs analysis of failures caused by a\n * {@link MissingWebServerFactoryBeanException}.\n *\n * @author Guirong Hu\n * @author Andy Wilkinson\n */\n@Order(0)\nclass MissingWebServerFactoryBeanFailureAnalyzer extends AbstractFailureAnalyzer<MissingWebServerFactoryBeanException> {\n\n\t@Override\n\tprotected FailureAnalysis analyze(Throwable rootFailure, MissingWebServerFactoryBeanException cause) {\n\t\tClass<?> beanType = cause.getBeanType();\n\t\tAssert.state(beanType != null, \"'beanType' must not be null\");\n\t\treturn new FailureAnalysis(\n\t\t\t\t\"Web application could not be started as there was no \" + beanType.getName()\n\t\t\t\t\t\t+ \" bean defined in the context.\",\n\t\t\t\t\"Check your application's dependencies for a supported \"\n\t\t\t\t\t\t+ cause.getWebApplicationType().name().toLowerCase(Locale.ENGLISH) + \" web server.\\n\"\n\t\t\t\t\t\t+ \"Check the configured web application type.\",\n\t\t\t\tcause);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/ServerPortInfoApplicationContextInitializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationContextInitializer} that sets {@link Environment} properties for the\n * ports that {@link WebServer} servers are actually listening on. The property\n * {@literal \"local.server.port\"} can be injected directly into tests using\n * {@link Value @Value} or obtained through the {@link Environment}.\n * <p>\n * If the {@link WebServerInitializedEvent} has a\n * {@link WebServerApplicationContext#getServerNamespace() server namespace}, it will be\n * used to construct the property name. For example, the \"management\" actuator context\n * will have the property name {@literal \"local.management.port\"}.\n * <p>\n * Properties are automatically propagated up to any parent context.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class ServerPortInfoApplicationContextInitializer implements\n\t\tApplicationContextInitializer<ConfigurableApplicationContext>, ApplicationListener<WebServerInitializedEvent> {\n\n\tprivate static final String PROPERTY_SOURCE_NAME = \"server.ports\";\n\n\t@Override\n\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\tapplicationContext.addApplicationListener(this);\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(WebServerInitializedEvent event) {\n\t\tString propertyName = \"local.\" + getName(event.getApplicationContext()) + \".port\";\n\t\tsetPortProperty(event.getApplicationContext(), propertyName, event.getWebServer().getPort());\n\t}\n\n\tprivate String getName(WebServerApplicationContext context) {\n\t\tString name = context.getServerNamespace();\n\t\treturn StringUtils.hasText(name) ? name : \"server\";\n\t}\n\n\tprivate void setPortProperty(ApplicationContext context, String propertyName, int port) {\n\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\tsetPortProperty(configurableContext.getEnvironment(), propertyName, port);\n\t\t}\n\t\tif (context.getParent() != null) {\n\t\t\tsetPortProperty(context.getParent(), propertyName, port);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void setPortProperty(ConfigurableEnvironment environment, String propertyName, int port) {\n\t\tMutablePropertySources sources = environment.getPropertySources();\n\t\tPropertySource<?> source = sources.get(PROPERTY_SOURCE_NAME);\n\t\tif (source == null) {\n\t\t\tsource = new MapPropertySource(PROPERTY_SOURCE_NAME, new HashMap<>());\n\t\t\tsources.addFirst(source);\n\t\t}\n\t\t((Map<String, Object>) source.getSource()).put(propertyName, port);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/SpringBootTestRandomPortContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.event.SmartApplicationListener;\nimport org.springframework.core.convert.ConversionFailedException;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.PropertyResolver;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.core.env.PropertySources;\nimport org.springframework.lang.Contract;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link SmartApplicationListener} for tests that starts the management context on a\n * random port if the main server's port is 0 and the management context is expected on a\n * different port.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass SpringBootTestRandomPortContextCustomizer implements ContextCustomizer {\n\n\tprivate static final String TEST_SOURCE_NAME = TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME;\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\tpostProcessEnvironment(context.getEnvironment());\n\t}\n\n\tvoid postProcessEnvironment(ConfigurableEnvironment environment) {\n\t\tMapPropertySource testSource = (MapPropertySource) environment.getPropertySources().get(TEST_SOURCE_NAME);\n\t\tif (testSource != null) {\n\t\t\tMutablePropertySources nonTestSources = new MutablePropertySources(environment.getPropertySources());\n\t\t\tnonTestSources.remove(TEST_SOURCE_NAME);\n\t\t\tPorts ports = new Ports(environment, environment.getConversionService());\n\t\t\tString value = getManagementServerPortPropertyValue(testSource, nonTestSources, ports);\n\t\t\tif (value != null) {\n\t\t\t\ttestSource.getSource().put(Port.MANAGEMENT.property(), value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate @Nullable String getManagementServerPortPropertyValue(MapPropertySource testSource,\n\t\t\tMutablePropertySources nonTestSources, Ports ports) {\n\t\tif (ports.isFixed(testSource, Port.SERVER) || ports.isConfigured(testSource, Port.MANAGEMENT)) {\n\t\t\treturn null;\n\t\t}\n\t\tInteger managementPort = ports.get(nonTestSources, Port.MANAGEMENT, null);\n\t\tif (managementPort == null || managementPort.equals(-1) || managementPort.equals(0)) {\n\t\t\treturn null;\n\t\t}\n\t\tInteger serverPort = ports.get(nonTestSources, Port.SERVER, 8080);\n\t\treturn (!managementPort.equals(serverPort)) ? \"0\" : \"\";\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\treturn (obj != null) && (obj.getClass() == getClass());\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn getClass().hashCode();\n\t}\n\n\tprivate enum Port {\n\n\t\tSERVER(\"server.port\"), MANAGEMENT(\"management.server.port\");\n\n\t\tprivate final String property;\n\n\t\tPort(String property) {\n\t\t\tthis.property = property;\n\t\t}\n\n\t\tString property() {\n\t\t\treturn this.property;\n\t\t}\n\n\t}\n\n\tprivate record Ports(PropertyResolver resolver, ConversionService conversionService) {\n\n\t\tprivate static final Integer ZERO = Integer.valueOf(0);\n\n\t\tboolean isFixed(MapPropertySource source, Port port) {\n\t\t\treturn !ZERO.equals(get(source, port));\n\t\t}\n\n\t\tboolean isConfigured(PropertySource<?> source, Port port) {\n\t\t\treturn source.getProperty(port.property()) != null;\n\t\t}\n\n\t\t@Contract(\"_, _, !null -> !null\")\n\t\t@Nullable Integer get(PropertySources sources, Port port, @Nullable Integer defaultValue) {\n\t\t\treturn sources.stream()\n\t\t\t\t.map((source) -> get(source, port))\n\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t.findFirst()\n\t\t\t\t.orElse(defaultValue);\n\t\t}\n\n\t\t@Nullable Integer get(PropertySource<?> source, Port port) {\n\t\t\tObject value = source.getProperty(port.property());\n\t\t\tif (value == null || ClassUtils.isAssignableValue(Integer.class, value)) {\n\t\t\t\treturn (Integer) value;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn asInteger(value);\n\t\t\t}\n\t\t\tcatch (ConversionFailedException ex) {\n\t\t\t\tif (value instanceof String string) {\n\t\t\t\t\treturn asInteger(resolver().resolveRequiredPlaceholders(string));\n\t\t\t\t}\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t\tprivate @Nullable Integer asInteger(@Nullable Object value) {\n\t\t\treturn conversionService().convert(value, Integer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/SpringBootTestRandomPortContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\n\n/**\n * {@link ContextCustomizerFactory} implementation to apply\n * {@link SpringBootTestRandomPortContextCustomizer} to tests.\n *\n * @author Phillip Webb\n */\nclass SpringBootTestRandomPortContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic @Nullable ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\treturn new SpringBootTestRandomPortContextCustomizer();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Interface to be implemented by {@link ApplicationContext application contexts} that\n * create and manage the lifecycle of an embedded {@link WebServer}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface WebServerApplicationContext extends ApplicationContext {\n\n\t/**\n\t * {@link SmartLifecycle#getPhase() SmartLifecycle phase} in which graceful shutdown\n\t * of the web server is performed.\n\t * @since 4.0.0\n\t */\n\tint GRACEFUL_SHUTDOWN_PHASE = SmartLifecycle.DEFAULT_PHASE - 1024;\n\n\t/**\n\t * {@link SmartLifecycle#getPhase() SmartLifecycle phase} in which starting and\n\t * stopping of the web server is performed.\n\t */\n\tint START_STOP_LIFECYCLE_PHASE = GRACEFUL_SHUTDOWN_PHASE - 1024;\n\n\t/**\n\t * Returns the {@link WebServer} that was created by the context or {@code null} if\n\t * the server has not yet been created.\n\t * @return the web server\n\t */\n\t@Nullable WebServer getWebServer();\n\n\t/**\n\t * Returns the namespace of the web server application context or {@code null} if no\n\t * namespace has been set. Used for disambiguation when multiple web servers are\n\t * running in the same application (for example a management context running on a\n\t * different port).\n\t * @return the server namespace\n\t */\n\t@Nullable String getServerNamespace();\n\n\t/**\n\t * Returns {@code true} if the specified context is a\n\t * {@link WebServerApplicationContext} with a matching server namespace.\n\t * @param context the context to check\n\t * @param serverNamespace the server namespace to match against\n\t * @return {@code true} if the server namespace of the context matches\n\t */\n\tstatic boolean hasServerNamespace(@Nullable ApplicationContext context, String serverNamespace) {\n\t\treturn (context instanceof WebServerApplicationContext webServerApplicationContext)\n\t\t\t\t&& ObjectUtils.nullSafeEquals(webServerApplicationContext.getServerNamespace(), serverNamespace);\n\t}\n\n\t/**\n\t * Returns the server namespace if the specified context is a\n\t * {@link WebServerApplicationContext}.\n\t * @param context the context\n\t * @return the server namespace or {@code null} if the context is not a\n\t * {@link WebServerApplicationContext}\n\t */\n\tstatic @Nullable String getServerNamespace(@Nullable ApplicationContext context) {\n\t\treturn (context instanceof WebServerApplicationContext configurableContext)\n\t\t\t\t? configurableContext.getServerNamespace() : null;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerGracefulShutdownLifecycle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.context.SmartLifecycle;\n\n/**\n * {@link SmartLifecycle} to trigger {@link WebServer} graceful shutdown.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic final class WebServerGracefulShutdownLifecycle implements SmartLifecycle {\n\n\t/**\n\t * {@link SmartLifecycle#getPhase() SmartLifecycle phase} in which graceful shutdown\n\t * of the web server is performed.\n\t * @deprecated as of 4.0.0 in favor of\n\t * {@link WebServerApplicationContext#GRACEFUL_SHUTDOWN_PHASE}\n\t */\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\tpublic static final int SMART_LIFECYCLE_PHASE = SmartLifecycle.DEFAULT_PHASE - 1024;\n\n\tprivate final WebServer webServer;\n\n\tprivate volatile boolean running;\n\n\t/**\n\t * Creates a new {@code WebServerGracefulShutdownLifecycle} that will gracefully shut\n\t * down the given {@code webServer}.\n\t * @param webServer web server to shut down gracefully\n\t */\n\tpublic WebServerGracefulShutdownLifecycle(WebServer webServer) {\n\t\tthis.webServer = webServer;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tthis.running = true;\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthrow new UnsupportedOperationException(\"Stop must not be invoked directly\");\n\t}\n\n\t@Override\n\tpublic void stop(Runnable callback) {\n\t\tthis.running = false;\n\t\tthis.webServer.shutDownGracefully((result) -> callback.run());\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn this.running;\n\t}\n\n\t@Override\n\tpublic int getPhase() {\n\t\treturn WebServerApplicationContext.GRACEFUL_SHUTDOWN_PHASE;\n\t}\n\n\t@Override\n\tpublic boolean isPauseable() {\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerInitializedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * Event to be published when the {@link WebServer} is ready. Useful for obtaining the\n * local port of a running server.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@SuppressWarnings(\"serial\")\npublic abstract class WebServerInitializedEvent extends ApplicationEvent {\n\n\tprotected WebServerInitializedEvent(WebServer webServer) {\n\t\tsuper(webServer);\n\t}\n\n\t/**\n\t * Access the {@link WebServer}.\n\t * @return the embedded web server\n\t */\n\tpublic WebServer getWebServer() {\n\t\treturn getSource();\n\t}\n\n\t/**\n\t * Access the application context that the server was created in. Sometimes it is\n\t * prudent to check that this matches expectations (like being equal to the current\n\t * context) before acting on the server itself.\n\t * @return the applicationContext that the server was created from\n\t */\n\tpublic abstract WebServerApplicationContext getApplicationContext();\n\n\t/**\n\t * Access the source of the event (an {@link WebServer}).\n\t * @return the embedded web server\n\t */\n\t@Override\n\tpublic WebServer getSource() {\n\t\treturn (WebServer) super.getSource();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/WebServerPortFileWriter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.io.File;\nimport java.util.Locale;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.system.SystemProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link ApplicationListener} that saves embedded server port and management port into\n * file. This application listener will be triggered whenever the server starts, and the\n * file name can be overridden at runtime with a System property or environment variable\n * named \"PORTFILE\" or \"portfile\".\n *\n * @author David Liu\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class WebServerPortFileWriter implements ApplicationListener<WebServerInitializedEvent> {\n\n\tprivate static final String DEFAULT_FILE_NAME = \"application.port\";\n\n\tprivate static final String[] PROPERTY_VARIABLES = { \"PORTFILE\", \"portfile\" };\n\n\tprivate static final Log logger = LogFactory.getLog(WebServerPortFileWriter.class);\n\n\tprivate final File file;\n\n\t/**\n\t * Create a new {@link WebServerPortFileWriter} instance using the filename\n\t * 'application.port'.\n\t */\n\tpublic WebServerPortFileWriter() {\n\t\tthis(new File(DEFAULT_FILE_NAME));\n\t}\n\n\t/**\n\t * Create a new {@link WebServerPortFileWriter} instance with a specified filename.\n\t * @param filename the name of file containing port\n\t */\n\tpublic WebServerPortFileWriter(String filename) {\n\t\tthis(new File(filename));\n\t}\n\n\t/**\n\t * Create a new {@link WebServerPortFileWriter} instance with a specified file.\n\t * @param file the file containing port\n\t */\n\tpublic WebServerPortFileWriter(File file) {\n\t\tAssert.notNull(file, \"'file' must not be null\");\n\t\tString override = SystemProperties.get(PROPERTY_VARIABLES);\n\t\tif (override != null) {\n\t\t\tthis.file = new File(override);\n\t\t}\n\t\telse {\n\t\t\tthis.file = file;\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(WebServerInitializedEvent event) {\n\t\tFile portFile = getPortFile(event.getApplicationContext());\n\t\ttry {\n\t\t\tString port = String.valueOf(event.getWebServer().getPort());\n\t\t\tcreateParentDirectory(portFile);\n\t\t\tFileCopyUtils.copy(port.getBytes(), portFile);\n\t\t\tportFile.deleteOnExit();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.warn(LogMessage.format(\"Cannot create port file %s\", this.file));\n\t\t}\n\t}\n\n\t/**\n\t * Return the actual port file that should be written for the given application\n\t * context. The default implementation builds a file from the source file and the\n\t * application context namespace if available.\n\t * @param applicationContext the source application context\n\t * @return the file that should be written\n\t */\n\tprotected File getPortFile(ApplicationContext applicationContext) {\n\t\tString namespace = getServerNamespace(applicationContext);\n\t\tif (!StringUtils.hasLength(namespace)) {\n\t\t\treturn this.file;\n\t\t}\n\t\tString filename = this.file.getName();\n\t\tString extension = StringUtils.getFilenameExtension(filename);\n\t\tString filenameWithoutExtension = (extension != null)\n\t\t\t\t? filename.substring(0, filename.length() - extension.length() - 1) : filename;\n\t\tString suffix = (!isUpperCase(filename)) ? namespace.toLowerCase(Locale.ENGLISH)\n\t\t\t\t: namespace.toUpperCase(Locale.ENGLISH);\n\t\treturn new File(this.file.getParentFile(),\n\t\t\t\tfilenameWithoutExtension + \"-\" + suffix + ((!StringUtils.hasLength(extension)) ? \"\" : \".\" + extension));\n\t}\n\n\tprivate @Nullable String getServerNamespace(ApplicationContext applicationContext) {\n\t\tif (applicationContext instanceof WebServerApplicationContext webServerApplicationContext) {\n\t\t\treturn webServerApplicationContext.getServerNamespace();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate boolean isUpperCase(String name) {\n\t\tfor (int i = 0; i < name.length(); i++) {\n\t\t\tif (Character.isLetter(name.charAt(i)) && !Character.isUpperCase(name.charAt(i))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate void createParentDirectory(File file) {\n\t\tFile parent = file.getParentFile();\n\t\tif (parent != null) {\n\t\t\tparent.mkdirs();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Web integrations with Spring's {@link org.springframework.context.ApplicationContext\n * ApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.web.server.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for embedded web servers.\n */\n@NullMarked\npackage org.springframework.boot.web.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/AbstractReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive;\n\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\n\n/**\n * Abstract base class for {@link ReactiveWebServerFactory} implementations.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic abstract class AbstractReactiveWebServerFactory extends AbstractConfigurableWebServerFactory\n\t\timplements ConfigurableReactiveWebServerFactory {\n\n\tpublic AbstractReactiveWebServerFactory() {\n\t}\n\n\tpublic AbstractReactiveWebServerFactory(int port) {\n\t\tsuper(port);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/ConfigurableReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive;\n\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\n\n/**\n * Configurable {@link ReactiveWebServerFactory}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic interface ConfigurableReactiveWebServerFactory extends ConfigurableWebServerFactory, ReactiveWebServerFactory {\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/ReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\n\n/**\n * Factory interface that can be used to create a reactive {@link WebServer}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see WebServer\n */\n@FunctionalInterface\npublic interface ReactiveWebServerFactory extends WebServerFactory {\n\n\t/**\n\t * Gets a new fully configured but paused {@link WebServer} instance. Clients should\n\t * not be able to connect to the returned server until {@link WebServer#start()} is\n\t * called (which happens when the {@code ApplicationContext} has been fully\n\t * refreshed).\n\t * @param httpHandler the HTTP handler in charge of processing requests\n\t * @return a fully configured and started {@link WebServer}\n\t * @see WebServer#stop()\n\t */\n\tWebServer getWebServer(HttpHandler httpHandler);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/AnnotationConfigReactiveWebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.AnnotationScopeMetadataResolver;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.ScopeMetadataResolver;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * {@link ReactiveWebServerApplicationContext} that accepts annotated classes as input -\n * in particular\n * {@link org.springframework.context.annotation.Configuration @Configuration}-annotated\n * classes, but also plain {@link Component @Component} classes and JSR-330 compliant\n * classes using {@code javax.inject} annotations. Allows for registering classes one by\n * one (specifying class names as config location) as well as for classpath scanning\n * (specifying base packages as config location).\n * <p>\n * Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}\n * definitions will override ones defined in earlier loaded files. This can be leveraged\n * to deliberately override certain bean definitions through an extra Configuration class.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see #register(Class...)\n * @see #scan(String...)\n * @see ReactiveWebServerApplicationContext\n * @see AnnotationConfigApplicationContext\n */\npublic class AnnotationConfigReactiveWebServerApplicationContext extends ReactiveWebServerApplicationContext\n\t\timplements AnnotationConfigRegistry {\n\n\tprivate final AnnotatedBeanDefinitionReader reader;\n\n\tprivate final ClassPathBeanDefinitionScanner scanner;\n\n\tprivate final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();\n\n\tprivate String @Nullable [] basePackages;\n\n\t/**\n\t * Create a new {@link AnnotationConfigReactiveWebServerApplicationContext} that needs\n\t * to be populated through {@link #register} calls and then manually\n\t * {@linkplain #refresh refreshed}.\n\t */\n\tpublic AnnotationConfigReactiveWebServerApplicationContext() {\n\t\tthis.reader = new AnnotatedBeanDefinitionReader(this);\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(this);\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigReactiveWebServerApplicationContext} with the\n\t * given {@code DefaultListableBeanFactory}. The context needs to be populated through\n\t * {@link #register} calls and then manually {@linkplain #refresh refreshed}.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t */\n\tpublic AnnotationConfigReactiveWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t\tthis.reader = new AnnotatedBeanDefinitionReader(this);\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(this);\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigReactiveWebServerApplicationContext}, deriving\n\t * bean definitions from the given annotated classes and automatically refreshing the\n\t * context.\n\t * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}\n\t * classes\n\t */\n\tpublic AnnotationConfigReactiveWebServerApplicationContext(Class<?>... annotatedClasses) {\n\t\tthis();\n\t\tregister(annotatedClasses);\n\t\trefresh();\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigReactiveWebServerApplicationContext}, scanning\n\t * for bean definitions in the given packages and automatically refreshing the\n\t * context.\n\t * @param basePackages the packages to check for annotated classes\n\t */\n\tpublic AnnotationConfigReactiveWebServerApplicationContext(String... basePackages) {\n\t\tthis();\n\t\tscan(basePackages);\n\t\trefresh();\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <p>\n\t * Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader} and\n\t * {@link ClassPathBeanDefinitionScanner} members.\n\t */\n\t@Override\n\tpublic void setEnvironment(ConfigurableEnvironment environment) {\n\t\tsuper.setEnvironment(environment);\n\t\tthis.reader.setEnvironment(environment);\n\t\tthis.scanner.setEnvironment(environment);\n\t}\n\n\t/**\n\t * Provide a custom {@link BeanNameGenerator} for use with\n\t * {@link AnnotatedBeanDefinitionReader} and/or\n\t * {@link ClassPathBeanDefinitionScanner}, if any.\n\t * <p>\n\t * Default is\n\t * {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.\n\t * <p>\n\t * Any call to this method must occur prior to calls to {@link #register(Class...)}\n\t * and/or {@link #scan(String...)}.\n\t * @param beanNameGenerator the bean name generator\n\t * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator\n\t * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator\n\t */\n\tpublic void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {\n\t\tthis.reader.setBeanNameGenerator(beanNameGenerator);\n\t\tthis.scanner.setBeanNameGenerator(beanNameGenerator);\n\t\tgetBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);\n\t}\n\n\t/**\n\t * Set the {@link ScopeMetadataResolver} to use for detected bean classes.\n\t * <p>\n\t * The default is an {@link AnnotationScopeMetadataResolver}.\n\t * <p>\n\t * Any call to this method must occur prior to calls to {@link #register(Class...)}\n\t * and/or {@link #scan(String...)}.\n\t * @param scopeMetadataResolver the scope metadata resolver\n\t */\n\tpublic void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {\n\t\tthis.reader.setScopeMetadataResolver(scopeMetadataResolver);\n\t\tthis.scanner.setScopeMetadataResolver(scopeMetadataResolver);\n\t}\n\n\t/**\n\t * Register one or more annotated classes to be processed. Note that\n\t * {@link #refresh()} must be called in order for the context to fully process the new\n\t * class.\n\t * <p>\n\t * Calls to {@code #register} are idempotent; adding the same annotated class more\n\t * than once has no additional effect.\n\t * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}\n\t * classes\n\t * @see #scan(String...)\n\t * @see #refresh()\n\t */\n\t@Override\n\tpublic final void register(Class<?>... annotatedClasses) {\n\t\tAssert.notEmpty(annotatedClasses, \"'annotatedClasses' must not be empty\");\n\t\tthis.annotatedClasses.addAll(Arrays.asList(annotatedClasses));\n\t}\n\n\t/**\n\t * Perform a scan within the specified base packages. Note that {@link #refresh()}\n\t * must be called in order for the context to fully process the new class.\n\t * @param basePackages the packages to check for annotated classes\n\t * @see #register(Class...)\n\t * @see #refresh()\n\t */\n\t@Override\n\tpublic final void scan(String... basePackages) {\n\t\tAssert.notEmpty(basePackages, \"'basePackages' must not be empty\");\n\t\tthis.basePackages = basePackages;\n\t}\n\n\t@Override\n\tprotected void prepareRefresh() {\n\t\tthis.scanner.clearCache();\n\t\tsuper.prepareRefresh();\n\t}\n\n\t@Override\n\tprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\tsuper.postProcessBeanFactory(beanFactory);\n\t\tif (!ObjectUtils.isEmpty(this.basePackages)) {\n\t\t\tthis.scanner.scan(this.basePackages);\n\t\t}\n\t\tif (!this.annotatedClasses.isEmpty()) {\n\t\t\tthis.reader.register(ClassUtils.toClassArray(this.annotatedClasses));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ApplicationReactiveWebEnvironment.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySources;\nimport org.springframework.boot.web.context.reactive.StandardReactiveWebEnvironment;\nimport org.springframework.core.env.ConfigurablePropertyResolver;\nimport org.springframework.core.env.MutablePropertySources;\n\n/**\n * {@link StandardReactiveWebEnvironment} for typical use in a typical\n * {@link SpringApplication}.\n *\n * @author Phillip Webb\n */\nclass ApplicationReactiveWebEnvironment extends StandardReactiveWebEnvironment {\n\n\t@Override\n\tprotected @Nullable String doGetActiveProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected @Nullable String doGetDefaultProfilesProperty() {\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {\n\t\treturn ConfigurationPropertySources.createPropertyResolver(propertySources);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.web.context.reactive.GenericReactiveWebApplicationContext;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.ConfigurableWebServerApplicationContext;\nimport org.springframework.boot.web.server.context.MissingWebServerFactoryBeanException;\nimport org.springframework.boot.web.server.context.WebServerGracefulShutdownLifecycle;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link GenericReactiveWebApplicationContext} that can be used to bootstrap itself\n * from a contained {@link ReactiveWebServerFactory} bean.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext\n\t\timplements ConfigurableWebServerApplicationContext {\n\n\tprivate volatile @Nullable WebServerManager serverManager;\n\n\tprivate @Nullable String serverNamespace;\n\n\t/**\n\t * Create a new {@link ReactiveWebServerApplicationContext}.\n\t */\n\tpublic ReactiveWebServerApplicationContext() {\n\t}\n\n\t/**\n\t * Create a new {@link ReactiveWebServerApplicationContext} with the given\n\t * {@code DefaultListableBeanFactory}.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t */\n\tpublic ReactiveWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t}\n\n\t@Override\n\tpublic final void refresh() throws BeansException, IllegalStateException {\n\t\ttry {\n\t\t\tsuper.refresh();\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tWebServer webServer = getWebServer();\n\t\t\tif (webServer != null) {\n\t\t\t\ttry {\n\t\t\t\t\twebServer.stop();\n\t\t\t\t\twebServer.destroy();\n\t\t\t\t}\n\t\t\t\tcatch (RuntimeException stopOrDestroyEx) {\n\t\t\t\t\tex.addSuppressed(stopOrDestroyEx);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onRefresh() {\n\t\tsuper.onRefresh();\n\t\ttry {\n\t\t\tcreateWebServer();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow new ApplicationContextException(\"Unable to start reactive web server\", ex);\n\t\t}\n\t}\n\n\tprivate void createWebServer() {\n\t\tWebServerManager serverManager = this.serverManager;\n\t\tif (serverManager == null) {\n\t\t\tStartupStep createWebServer = getApplicationStartup().start(\"spring.boot.webserver.create\");\n\t\t\tString webServerFactoryBeanName = getWebServerFactoryBeanName();\n\t\t\tReactiveWebServerFactory webServerFactory = getWebServerFactory(webServerFactoryBeanName);\n\t\t\tcreateWebServer.tag(\"factory\", webServerFactory.getClass().toString());\n\t\t\tboolean lazyInit = getBeanFactory().getBeanDefinition(webServerFactoryBeanName).isLazyInit();\n\t\t\tserverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit);\n\t\t\tthis.serverManager = serverManager;\n\t\t\tgetBeanFactory().registerSingleton(\"webServerGracefulShutdown\",\n\t\t\t\t\tnew WebServerGracefulShutdownLifecycle(serverManager.getWebServer()));\n\t\t\tgetBeanFactory().registerSingleton(\"webServerStartStop\", new WebServerStartStopLifecycle(serverManager));\n\t\t\tcreateWebServer.end();\n\t\t}\n\t\tinitPropertySources();\n\t}\n\n\tprotected String getWebServerFactoryBeanName() {\n\t\t// Use bean names so that we don't consider the hierarchy\n\t\tString[] beanNames = getBeanFactory().getBeanNamesForType(ReactiveWebServerFactory.class);\n\t\tif (beanNames.length == 0) {\n\t\t\tthrow new MissingWebServerFactoryBeanException(getClass(), ReactiveWebServerFactory.class,\n\t\t\t\t\tWebApplicationType.REACTIVE);\n\t\t}\n\t\tif (beanNames.length > 1) {\n\t\t\tthrow new ApplicationContextException(\"Unable to start ReactiveWebApplicationContext due to multiple \"\n\t\t\t\t\t+ \"ReactiveWebServerFactory beans : \" + StringUtils.arrayToCommaDelimitedString(beanNames));\n\t\t}\n\t\treturn beanNames[0];\n\t}\n\n\tprotected ReactiveWebServerFactory getWebServerFactory(String factoryBeanName) {\n\t\treturn getBeanFactory().getBean(factoryBeanName, ReactiveWebServerFactory.class);\n\t}\n\n\t/**\n\t * Return the {@link HttpHandler} that should be used to process the reactive web\n\t * server. By default this method searches for a suitable bean in the context itself.\n\t * @return a {@link HttpHandler} (never {@code null}\n\t */\n\tprotected HttpHandler getHttpHandler() {\n\t\t// Use bean names so that we don't consider the hierarchy\n\t\tString[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);\n\t\tif (beanNames.length == 0) {\n\t\t\tthrow new ApplicationContextException(\n\t\t\t\t\t\"Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean.\");\n\t\t}\n\t\tif (beanNames.length > 1) {\n\t\t\tthrow new ApplicationContextException(\n\t\t\t\t\t\"Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans : \"\n\t\t\t\t\t\t\t+ StringUtils.arrayToCommaDelimitedString(beanNames));\n\t\t}\n\t\treturn getBeanFactory().getBean(beanNames[0], HttpHandler.class);\n\t}\n\n\t@Override\n\tprotected void doClose() {\n\t\tif (isActive()) {\n\t\t\tAvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);\n\t\t}\n\t\tsuper.doClose();\n\t\tWebServer webServer = getWebServer();\n\t\tif (webServer != null) {\n\t\t\twebServer.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the {@link WebServer} that was created by the context or {@code null} if\n\t * the server has not yet been created.\n\t * @return the web server\n\t */\n\t@Override\n\tpublic @Nullable WebServer getWebServer() {\n\t\tWebServerManager serverManager = this.serverManager;\n\t\treturn (serverManager != null) ? serverManager.getWebServer() : null;\n\t}\n\n\t@Override\n\tpublic @Nullable String getServerNamespace() {\n\t\treturn this.serverNamespace;\n\t}\n\n\t@Override\n\tpublic void setServerNamespace(@Nullable String serverNamespace) {\n\t\tthis.serverNamespace = serverNamespace;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * {@link ApplicationContextFactory} registered in {@code spring.factories} to support\n * {@link AnnotationConfigReactiveWebServerApplicationContext} and\n * {@link ReactiveWebServerApplicationContext}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ReactiveWebServerApplicationContextFactory implements ApplicationContextFactory {\n\n\t@Override\n\tpublic @Nullable Class<? extends ConfigurableEnvironment> getEnvironmentType(\n\t\t\t@Nullable WebApplicationType webApplicationType) {\n\t\treturn (webApplicationType != WebApplicationType.REACTIVE) ? null : ApplicationReactiveWebEnvironment.class;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {\n\t\treturn (webApplicationType != WebApplicationType.REACTIVE) ? null : new ApplicationReactiveWebEnvironment();\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) {\n\t\treturn (webApplicationType != WebApplicationType.REACTIVE) ? null : createContext();\n\t}\n\n\tprivate ConfigurableApplicationContext createContext() {\n\t\tif (!AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn new AnnotationConfigReactiveWebServerApplicationContext();\n\t\t}\n\t\treturn new ReactiveWebServerApplicationContext();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextLocalTestWebServerProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.BaseUriDetails;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * {@link LocalTestWebServer} provider for a {@link ReactiveWebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass ReactiveWebServerApplicationContextLocalTestWebServerProvider implements LocalTestWebServer.Provider {\n\n\tprivate final @Nullable ReactiveWebServerApplicationContext context;\n\n\tReactiveWebServerApplicationContextLocalTestWebServerProvider(ApplicationContext context) {\n\t\tthis.context = getWebServerApplicationContextIfPossible(context);\n\t}\n\n\tstatic @Nullable ReactiveWebServerApplicationContext getWebServerApplicationContextIfPossible(\n\t\t\tApplicationContext context) {\n\t\ttry {\n\t\t\treturn (ReactiveWebServerApplicationContext) context;\n\t\t}\n\t\tcatch (NoClassDefFoundError | ClassCastException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\tif (this.context == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn LocalTestWebServer.of((isSslEnabled(this.context)) ? Scheme.HTTPS : Scheme.HTTP, () -> {\n\t\t\tint port = this.context.getEnvironment().getProperty(\"local.server.port\", Integer.class, 8080);\n\t\t\tString path = this.context.getEnvironment().getProperty(\"spring.webflux.base-path\", \"\");\n\t\t\treturn new BaseUriDetails(port, path);\n\t\t});\n\t}\n\n\tprivate boolean isSslEnabled(ReactiveWebServerApplicationContext context) {\n\t\ttry {\n\t\t\tAbstractConfigurableWebServerFactory webServerFactory = context\n\t\t\t\t.getBean(AbstractConfigurableWebServerFactory.class);\n\t\t\treturn webServerFactory.getSsl() != null && webServerFactory.getSsl().isEnabled();\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerInitializedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerInitializedEvent;\n\n/**\n * Event to be published after the {@link WebServer} is ready. Useful for obtaining the\n * local port of a running server.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class ReactiveWebServerInitializedEvent extends WebServerInitializedEvent {\n\n\tprivate final ReactiveWebServerApplicationContext applicationContext;\n\n\tpublic ReactiveWebServerInitializedEvent(WebServer webServer,\n\t\t\tReactiveWebServerApplicationContext applicationContext) {\n\t\tsuper(webServer);\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Override\n\tpublic ReactiveWebServerApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/WebServerManager.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport java.util.function.Supplier;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.web.server.GracefulShutdownCallback;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.util.Assert;\n\n/**\n * Internal class used to manage the server and the {@link HttpHandler}, taking care not\n * to initialize the handler too early.\n *\n * @author Andy Wilkinson\n */\nclass WebServerManager {\n\n\tprivate final ReactiveWebServerApplicationContext applicationContext;\n\n\tprivate final DelayedInitializationHttpHandler handler;\n\n\tprivate final WebServer webServer;\n\n\tWebServerManager(ReactiveWebServerApplicationContext applicationContext, ReactiveWebServerFactory factory,\n\t\t\tSupplier<HttpHandler> handlerSupplier, boolean lazyInit) {\n\t\tthis.applicationContext = applicationContext;\n\t\tAssert.notNull(factory, \"'factory' must not be null\");\n\t\tthis.handler = new DelayedInitializationHttpHandler(handlerSupplier, lazyInit);\n\t\tthis.webServer = factory.getWebServer(this.handler);\n\t}\n\n\tvoid start() {\n\t\tthis.handler.initializeHandler();\n\t\tthis.webServer.start();\n\t\tthis.applicationContext\n\t\t\t.publishEvent(new ReactiveWebServerInitializedEvent(this.webServer, this.applicationContext));\n\t}\n\n\tvoid shutDownGracefully(GracefulShutdownCallback callback) {\n\t\tthis.webServer.shutDownGracefully(callback);\n\t}\n\n\tvoid stop() {\n\t\tthis.webServer.stop();\n\t}\n\n\tWebServer getWebServer() {\n\t\treturn this.webServer;\n\t}\n\n\tHttpHandler getHandler() {\n\t\treturn this.handler;\n\t}\n\n\t/**\n\t * A delayed {@link HttpHandler} that doesn't initialize things too early.\n\t */\n\tstatic final class DelayedInitializationHttpHandler implements HttpHandler {\n\n\t\tprivate final Supplier<HttpHandler> handlerSupplier;\n\n\t\tprivate final boolean lazyInit;\n\n\t\tprivate volatile HttpHandler delegate = this::handleUninitialized;\n\n\t\tprivate DelayedInitializationHttpHandler(Supplier<HttpHandler> handlerSupplier, boolean lazyInit) {\n\t\t\tthis.handlerSupplier = handlerSupplier;\n\t\t\tthis.lazyInit = lazyInit;\n\t\t}\n\n\t\tprivate Mono<Void> handleUninitialized(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\tthrow new IllegalStateException(\"The HttpHandler has not yet been initialized\");\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\treturn this.delegate.handle(request, response);\n\t\t}\n\n\t\tvoid initializeHandler() {\n\t\t\tthis.delegate = this.lazyInit ? new LazyHttpHandler(this.handlerSupplier) : this.handlerSupplier.get();\n\t\t}\n\n\t\tHttpHandler getHandler() {\n\t\t\treturn this.delegate;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link HttpHandler} that initializes its delegate on first request.\n\t */\n\tprivate static final class LazyHttpHandler implements HttpHandler {\n\n\t\tprivate final Mono<HttpHandler> delegate;\n\n\t\tprivate LazyHttpHandler(Supplier<HttpHandler> handlerSupplier) {\n\t\t\tthis.delegate = Mono.fromSupplier(handlerSupplier);\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\treturn this.delegate.flatMap((handler) -> handler.handle(request, response));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/WebServerStartStopLifecycle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.SmartLifecycle;\n\n/**\n * {@link SmartLifecycle} to start and stop the {@link WebServer} in a\n * {@link ReactiveWebServerApplicationContext}.\n *\n * @author Andy Wilkinson\n */\nclass WebServerStartStopLifecycle implements SmartLifecycle {\n\n\tprivate final WebServerManager weServerManager;\n\n\tprivate volatile boolean running;\n\n\tWebServerStartStopLifecycle(WebServerManager weServerManager) {\n\t\tthis.weServerManager = weServerManager;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tthis.weServerManager.start();\n\t\tthis.running = true;\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.running = false;\n\t\tthis.weServerManager.stop();\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn this.running;\n\t}\n\n\t@Override\n\tpublic int getPhase() {\n\t\treturn WebServerApplicationContext.START_STOP_LIFECYCLE_PHASE;\n\t}\n\n\t@Override\n\tpublic boolean isPauseable() {\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive web server based integrations with Spring's\n * {@link org.springframework.context.ApplicationContext ApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Reactive web server abstractions.\n */\n@NullMarked\npackage org.springframework.boot.web.server.reactive;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ConfigurableServletWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.nio.charset.Charset;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Cookie.SameSite;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\n\n/**\n * A configurable {@link ServletWebServerFactory}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Brian Clozel\n * @since 4.0.0\n * @see ServletWebServerFactory\n * @see WebServerFactoryCustomizer\n */\npublic interface ConfigurableServletWebServerFactory\n\t\textends ConfigurableWebServerFactory, ServletWebServerFactory, WebListenerRegistry {\n\n\tServletWebServerSettings getSettings();\n\n\t/**\n\t * Sets the context path for the web server. The context should start with a \"/\"\n\t * character but not end with a \"/\" character. The default context path can be\n\t * specified using an empty string.\n\t * @param contextPath the context path to set\n\t */\n\tdefault void setContextPath(String contextPath) {\n\t\tgetSettings().setContextPath(ContextPath.of(contextPath));\n\t}\n\n\t/**\n\t * Returns the context path for the servlet web server.\n\t * @return the context path\n\t */\n\tdefault String getContextPath() {\n\t\treturn getSettings().getContextPath().toString();\n\t}\n\n\t/**\n\t * Sets the display name of the application deployed in the web server.\n\t * @param displayName the displayName to set\n\t */\n\tdefault void setDisplayName(String displayName) {\n\t\tgetSettings().setDisplayName(displayName);\n\t}\n\n\t/**\n\t * Sets the configuration that will be applied to the container's HTTP session\n\t * support.\n\t * @param session the session configuration\n\t */\n\tdefault void setSession(Session session) {\n\t\tgetSettings().setSession(session);\n\t}\n\n\t/**\n\t * Set if the DefaultServlet should be registered. Defaults to {@code false} since\n\t * 2.4.\n\t * @param registerDefaultServlet if the default servlet should be registered\n\t */\n\tdefault void setRegisterDefaultServlet(boolean registerDefaultServlet) {\n\t\tgetSettings().setRegisterDefaultServlet(registerDefaultServlet);\n\t}\n\n\t/**\n\t * Sets the mime-type mappings.\n\t * @param mimeMappings the mime type mappings (defaults to\n\t * {@link MimeMappings#DEFAULT})\n\t */\n\tdefault void setMimeMappings(MimeMappings mimeMappings) {\n\t\tgetSettings().setMimeMappings(mimeMappings);\n\t}\n\n\t/**\n\t * Adds mime-type mappings.\n\t * @param mimeMappings the mime type mappings to add\n\t */\n\tdefault void addMimeMappings(MimeMappings mimeMappings) {\n\t\tgetSettings().addMimeMappings(mimeMappings);\n\t}\n\n\t/**\n\t * Sets the document root directory which will be used by the web context to serve\n\t * static files.\n\t * @param documentRoot the document root or {@code null} if not required\n\t */\n\tdefault void setDocumentRoot(@Nullable File documentRoot) {\n\t\tgetSettings().setDocumentRoot(documentRoot);\n\t}\n\n\t/**\n\t * Sets {@link ServletContextInitializer} that should be applied in addition to\n\t * {@link ServletWebServerFactory#getWebServer(ServletContextInitializer...)}\n\t * parameters. This method will replace any previously set or added initializers.\n\t * @param initializers the initializers to set\n\t * @see #addInitializers\n\t */\n\tdefault void setInitializers(List<? extends ServletContextInitializer> initializers) {\n\t\tgetSettings().setInitializers(initializers);\n\t}\n\n\t/**\n\t * Add {@link ServletContextInitializer}s to those that should be applied in addition\n\t * to {@link ServletWebServerFactory#getWebServer(ServletContextInitializer...)}\n\t * parameters.\n\t * @param initializers the initializers to add\n\t * @see #setInitializers\n\t */\n\tdefault void addInitializers(ServletContextInitializer... initializers) {\n\t\tgetSettings().addInitializers(initializers);\n\t}\n\n\t/**\n\t * Sets the configuration that will be applied to the server's JSP servlet.\n\t * @param jsp the JSP servlet configuration\n\t */\n\tdefault void setJsp(Jsp jsp) {\n\t\tgetSettings().setJsp(jsp);\n\t}\n\n\t/**\n\t * Sets the Locale to Charset mappings.\n\t * @param localeCharsetMappings the Locale to Charset mappings\n\t */\n\tdefault void setLocaleCharsetMappings(Map<Locale, Charset> localeCharsetMappings) {\n\t\tgetSettings().setLocaleCharsetMappings(localeCharsetMappings);\n\t}\n\n\t/**\n\t * Sets the init parameters that are applied to the container's\n\t * {@link ServletContext}.\n\t * @param initParameters the init parameters\n\t */\n\tdefault void setInitParameters(Map<String, String> initParameters) {\n\t\tgetSettings().setInitParameters(initParameters);\n\t}\n\n\t/**\n\t * Sets {@link CookieSameSiteSupplier CookieSameSiteSuppliers} that should be used to\n\t * obtain the {@link SameSite} attribute of any added cookie. This method will replace\n\t * any previously set or added suppliers.\n\t * @param cookieSameSiteSuppliers the suppliers to add\n\t * @see #addCookieSameSiteSuppliers\n\t */\n\tdefault void setCookieSameSiteSuppliers(List<? extends CookieSameSiteSupplier> cookieSameSiteSuppliers) {\n\t\tgetSettings().setCookieSameSiteSuppliers(cookieSameSiteSuppliers);\n\t}\n\n\t/**\n\t * Add {@link CookieSameSiteSupplier CookieSameSiteSuppliers} to those that should be\n\t * used to obtain the {@link SameSite} attribute of any added cookie.\n\t * @param cookieSameSiteSuppliers the suppliers to add\n\t * @see #setCookieSameSiteSuppliers\n\t */\n\tdefault void addCookieSameSiteSuppliers(CookieSameSiteSupplier... cookieSameSiteSuppliers) {\n\t\tgetSettings().addCookieSameSiteSuppliers(cookieSameSiteSuppliers);\n\t}\n\n\t@Override\n\tdefault void addWebListeners(String... webListenerClassNames) {\n\t\tgetSettings().addWebListenerClassNames(webListenerClassNames);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ContextPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport org.springframework.util.Assert;\n\n/**\n * The context path of a servlet web server.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic final class ContextPath {\n\n\t/**\n\t * The default context path.\n\t */\n\tpublic static final ContextPath DEFAULT = ContextPath.of(\"\");\n\n\tprivate final String path;\n\n\tprivate ContextPath(String path) {\n\t\tthis.path = path;\n\t}\n\n\tpublic static ContextPath of(String contextPath) {\n\t\tAssert.notNull(contextPath, \"'contextPath' must not be null\");\n\t\tif (!contextPath.isEmpty()) {\n\t\t\tif (\"/\".equals(contextPath)) {\n\t\t\t\tthrow new IllegalArgumentException(\"Root context path must be specified using an empty string\");\n\t\t\t}\n\t\t\tif (!contextPath.startsWith(\"/\") || contextPath.endsWith(\"/\")) {\n\t\t\t\tthrow new IllegalArgumentException(\"Context path must start with '/' and not end with '/'\");\n\t\t\t}\n\t\t}\n\t\treturn new ContextPath(contextPath);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.path;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.util.function.Predicate;\nimport java.util.function.Supplier;\nimport java.util.regex.Pattern;\n\nimport jakarta.servlet.http.Cookie;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.Cookie.SameSite;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ObjectUtils;\n\n/**\n * Strategy interface that can be used with {@link ConfigurableServletWebServerFactory}\n * implementations in order to supply custom {@link SameSite} values for specific\n * {@link Cookie cookies}.\n * <p>\n * Basic CookieSameSiteSupplier implementations can be constructed using the {@code of...}\n * factory methods, typically combined with name matching. For example: <pre class=\"code\">\n * CookieSameSiteSupplier.ofLax().whenHasName(\"mycookie\");\n * </pre>\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see ConfigurableServletWebServerFactory#addCookieSameSiteSuppliers(CookieSameSiteSupplier...)\n */\n@FunctionalInterface\npublic interface CookieSameSiteSupplier {\n\n\t/**\n\t * Get the {@link SameSite} values that should be used for the given {@link Cookie}.\n\t * @param cookie the cookie to check\n\t * @return the {@link SameSite} value to use or {@code null} if the next supplier\n\t * should be checked\n\t */\n\t@Nullable SameSite getSameSite(Cookie cookie);\n\n\t/**\n\t * Limit this supplier so that it's only called if the Cookie has the given name.\n\t * @param name the name to check\n\t * @return a new {@link CookieSameSiteSupplier} that only calls this supplier when the\n\t * name matches\n\t */\n\tdefault CookieSameSiteSupplier whenHasName(String name) {\n\t\tAssert.hasText(name, \"'name' must not be empty\");\n\t\treturn when((cookie) -> ObjectUtils.nullSafeEquals(cookie.getName(), name));\n\t}\n\n\t/**\n\t * Limit this supplier so that it's only called if the Cookie has the given name.\n\t * @param nameSupplier a supplier providing the name to check\n\t * @return a new {@link CookieSameSiteSupplier} that only calls this supplier when the\n\t * name matches\n\t */\n\tdefault CookieSameSiteSupplier whenHasName(Supplier<String> nameSupplier) {\n\t\tAssert.notNull(nameSupplier, \"'nameSupplier' must not be null\");\n\t\treturn when((cookie) -> ObjectUtils.nullSafeEquals(cookie.getName(), nameSupplier.get()));\n\t}\n\n\t/**\n\t * Limit this supplier so that it's only called if the Cookie name matches the given\n\t * regex.\n\t * @param regex the regex pattern that must match\n\t * @return a new {@link CookieSameSiteSupplier} that only calls this supplier when the\n\t * name matches the regex\n\t */\n\tdefault CookieSameSiteSupplier whenHasNameMatching(String regex) {\n\t\tAssert.hasText(regex, \"'regex' must not be empty\");\n\t\treturn whenHasNameMatching(Pattern.compile(regex));\n\t}\n\n\t/**\n\t * Limit this supplier so that it's only called if the Cookie name matches the given\n\t * {@link Pattern}.\n\t * @param pattern the regex pattern that must match\n\t * @return a new {@link CookieSameSiteSupplier} that only calls this supplier when the\n\t * name matches the pattern\n\t */\n\tdefault CookieSameSiteSupplier whenHasNameMatching(Pattern pattern) {\n\t\tAssert.notNull(pattern, \"'pattern' must not be null\");\n\t\treturn when((cookie) -> pattern.matcher(cookie.getName()).matches());\n\t}\n\n\t/**\n\t * Limit this supplier so that it's only called if the predicate accepts the Cookie.\n\t * @param predicate the predicate used to match the cookie\n\t * @return a new {@link CookieSameSiteSupplier} that only calls this supplier when the\n\t * cookie matches the predicate\n\t */\n\tdefault CookieSameSiteSupplier when(Predicate<Cookie> predicate) {\n\t\tAssert.notNull(predicate, \"'predicate' must not be null\");\n\t\treturn (cookie) -> predicate.test(cookie) ? getSameSite(cookie) : null;\n\t}\n\n\t/**\n\t * Return a new {@link CookieSameSiteSupplier} that always returns\n\t * {@link SameSite#NONE}.\n\t * @return the supplier instance\n\t */\n\tstatic CookieSameSiteSupplier ofNone() {\n\t\treturn of(SameSite.NONE);\n\t}\n\n\t/**\n\t * Return a new {@link CookieSameSiteSupplier} that always returns\n\t * {@link SameSite#LAX}.\n\t * @return the supplier instance\n\t */\n\tstatic CookieSameSiteSupplier ofLax() {\n\t\treturn of(SameSite.LAX);\n\t}\n\n\t/**\n\t * Return a new {@link CookieSameSiteSupplier} that always returns\n\t * {@link SameSite#STRICT}.\n\t * @return the supplier instance\n\t */\n\tstatic CookieSameSiteSupplier ofStrict() {\n\t\treturn of(SameSite.STRICT);\n\t}\n\n\t/**\n\t * Return a new {@link CookieSameSiteSupplier} that always returns the given\n\t * {@link SameSite} value.\n\t * @param sameSite the value to return\n\t * @return the supplier instance\n\t */\n\tstatic CookieSameSiteSupplier of(SameSite sameSite) {\n\t\tAssert.notNull(sameSite, \"'sameSite' must not be null\");\n\t\treturn (cookie) -> sameSite;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/DocumentRoot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.security.CodeSource;\nimport java.util.Arrays;\nimport java.util.Locale;\nimport java.util.function.Function;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Manages a {@link ServletWebServerFactory} document root.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DocumentRoot {\n\n\tprivate static final String WAR_SOURCE_DIRECTORY_ENVIRONMENT_VARIABLE = \"WAR_SOURCE_DIRECTORY\";\n\n\tprivate final Log logger;\n\n\tprivate final File rootDirectory;\n\n\tprivate final String[] commonDocRoots;\n\n\tprivate @Nullable File directory;\n\n\tpublic DocumentRoot(Log logger) {\n\t\tthis(logger, new File(\".\"), System::getenv);\n\t}\n\n\tDocumentRoot(Log logger, File rootDirectory, Function<String, @Nullable String> systemEnvironment) {\n\t\tthis.logger = logger;\n\t\tthis.rootDirectory = rootDirectory;\n\t\tthis.commonDocRoots = new String[] { getWarSourceDirectory(systemEnvironment), \"public\", \"static\" };\n\t}\n\n\tprivate static String getWarSourceDirectory(Function<String, @Nullable String> systemEnvironment) {\n\t\tString name = systemEnvironment.apply(WAR_SOURCE_DIRECTORY_ENVIRONMENT_VARIABLE);\n\t\treturn (name != null) ? name : \"src/main/webapp\";\n\t}\n\n\t@Nullable File getDirectory() {\n\t\treturn this.directory;\n\t}\n\n\tpublic void setDirectory(@Nullable File directory) {\n\t\tthis.directory = directory;\n\t}\n\n\t/**\n\t * Returns the absolute document root when it points to a valid directory, logging a\n\t * warning and returning {@code null} otherwise.\n\t * @return the valid document root\n\t */\n\tpublic final @Nullable File getValidDirectory() {\n\t\tFile file = this.directory;\n\t\tfile = (file != null) ? file : getWarFileDocumentRoot();\n\t\tfile = (file != null) ? file : getExplodedWarFileDocumentRoot();\n\t\tfile = (file != null) ? file : getCommonDocumentRoot();\n\t\tif (file == null && this.logger.isDebugEnabled()) {\n\t\t\tlogNoDocumentRoots();\n\t\t}\n\t\telse if (this.logger.isDebugEnabled()) {\n\t\t\tthis.logger.debug(\"Document root: \" + file);\n\t\t}\n\t\treturn file;\n\t}\n\n\tprivate @Nullable File getWarFileDocumentRoot() {\n\t\treturn getArchiveFileDocumentRoot(\".war\");\n\t}\n\n\tprivate @Nullable File getArchiveFileDocumentRoot(String extension) {\n\t\tFile file = getCodeSourceArchive();\n\t\tif (this.logger.isDebugEnabled()) {\n\t\t\tthis.logger.debug(\"Code archive: \" + file);\n\t\t}\n\t\tif (file != null && file.exists() && !file.isDirectory()\n\t\t\t\t&& file.getName().toLowerCase(Locale.ENGLISH).endsWith(extension)) {\n\t\t\treturn file.getAbsoluteFile();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable File getExplodedWarFileDocumentRoot() {\n\t\treturn getExplodedWarFileDocumentRoot(getCodeSourceArchive());\n\t}\n\n\tprivate @Nullable File getCodeSourceArchive() {\n\t\treturn getCodeSourceArchive(getClass().getProtectionDomain().getCodeSource());\n\t}\n\n\t@Nullable File getCodeSourceArchive(@Nullable CodeSource codeSource) {\n\t\ttry {\n\t\t\tURL location = (codeSource != null) ? codeSource.getLocation() : null;\n\t\t\tif (location == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tString path;\n\t\t\tURLConnection connection = location.openConnection();\n\t\t\tif (connection instanceof JarURLConnection jarURLConnection) {\n\t\t\t\tpath = jarURLConnection.getJarFile().getName();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpath = location.toURI().getPath();\n\t\t\t}\n\t\t\tint index = path.indexOf(\"!/\");\n\t\t\tif (index != -1) {\n\t\t\t\tpath = path.substring(0, index);\n\t\t\t}\n\t\t\treturn new File(path);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tfinal @Nullable File getExplodedWarFileDocumentRoot(@Nullable File codeSourceFile) {\n\t\tif (this.logger.isDebugEnabled()) {\n\t\t\tthis.logger.debug(\"Code archive: \" + codeSourceFile);\n\t\t}\n\t\tif (codeSourceFile != null && codeSourceFile.exists()) {\n\t\t\tString path = codeSourceFile.getAbsolutePath();\n\t\t\tint webInfPathIndex = path.indexOf(File.separatorChar + \"WEB-INF\" + File.separatorChar);\n\t\t\tif (webInfPathIndex >= 0) {\n\t\t\t\tpath = path.substring(0, webInfPathIndex);\n\t\t\t\treturn new File(path);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable File getCommonDocumentRoot() {\n\t\tfor (String commonDocRoot : this.commonDocRoots) {\n\t\t\tFile root = new File(this.rootDirectory, commonDocRoot);\n\t\t\tif (root.exists() && root.isDirectory()) {\n\t\t\t\treturn root.getAbsoluteFile();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void logNoDocumentRoots() {\n\t\tthis.logger.debug(\"None of the document roots \" + Arrays.asList(this.commonDocRoots)\n\t\t\t\t+ \" point to a directory and will be ignored.\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/Jsp.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Configuration for the server's JSP servlet.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @since 4.0.0\n */\npublic class Jsp {\n\n\t/**\n\t * Class name of the servlet to use for JSPs. If registered is true and this class is\n\t * on the classpath then it will be registered.\n\t */\n\tprivate String className = \"org.apache.jasper.servlet.JspServlet\";\n\n\tprivate Map<String, String> initParameters = new HashMap<>();\n\n\t/**\n\t * Whether the JSP servlet is registered.\n\t */\n\tprivate boolean registered = true;\n\n\tpublic Jsp() {\n\t\tthis.initParameters.put(\"development\", \"false\");\n\t}\n\n\t/**\n\t * Return the class name of the servlet to use for JSPs. If {@link #getRegistered()\n\t * registered} is {@code true} and this class is on the classpath then it will be\n\t * registered.\n\t * @return the class name of the servlet to use for JSPs\n\t */\n\tpublic String getClassName() {\n\t\treturn this.className;\n\t}\n\n\tpublic void setClassName(String className) {\n\t\tthis.className = className;\n\t}\n\n\t/**\n\t * Return the init parameters used to configure the JSP servlet.\n\t * @return the init parameters\n\t */\n\tpublic Map<String, String> getInitParameters() {\n\t\treturn this.initParameters;\n\t}\n\n\tpublic void setInitParameters(Map<String, String> initParameters) {\n\t\tthis.initParameters = initParameters;\n\t}\n\n\t/**\n\t * Return whether the JSP servlet is registered.\n\t * @return {@code true} to register the JSP servlet\n\t */\n\tpublic boolean getRegistered() {\n\t\treturn this.registered;\n\t}\n\n\tpublic void setRegistered(boolean registered) {\n\t\tthis.registered = registered;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletContextInitializers.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.SessionCookieConfig;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.web.server.Cookie;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.lang.Contract;\n\n/**\n * The {@link ServletContextInitializer ServletContextInitializers} to apply to a servlet\n * {@link WebServer}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic final class ServletContextInitializers implements Iterable<ServletContextInitializer> {\n\n\tprivate final List<ServletContextInitializer> initializers;\n\n\tprivate ServletContextInitializers(List<ServletContextInitializer> initializers) {\n\t\tthis.initializers = initializers;\n\t}\n\n\t@Override\n\tpublic Iterator<ServletContextInitializer> iterator() {\n\t\treturn this.initializers.iterator();\n\t}\n\n\t/**\n\t * Creates a new instance from the given {@code settings} and {@code initializers}.\n\t * @param settings the settings\n\t * @param initializers the initializers\n\t * @return the new instance\n\t */\n\tpublic static ServletContextInitializers from(ServletWebServerSettings settings,\n\t\t\tServletContextInitializer... initializers) {\n\t\tList<ServletContextInitializer> mergedInitializers = new ArrayList<>();\n\t\tmergedInitializers\n\t\t\t.add((servletContext) -> settings.getInitParameters().forEach(servletContext::setInitParameter));\n\t\tmergedInitializers.add(new SessionConfiguringInitializer(settings.getSession()));\n\t\tmergedInitializers.addAll(Arrays.asList(initializers));\n\t\tmergedInitializers.addAll(settings.getInitializers());\n\t\treturn new ServletContextInitializers(mergedInitializers);\n\t}\n\n\tprivate static final class SessionConfiguringInitializer implements ServletContextInitializer {\n\n\t\tprivate final Session session;\n\n\t\tprivate SessionConfiguringInitializer(Session session) {\n\t\t\tthis.session = session;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onStartup(ServletContext servletContext) throws ServletException {\n\t\t\tif (this.session.getTrackingModes() != null) {\n\t\t\t\tservletContext.setSessionTrackingModes(unwrap(this.session.getTrackingModes()));\n\t\t\t}\n\t\t\tconfigureSessionCookie(servletContext.getSessionCookieConfig());\n\t\t}\n\n\t\tprivate void configureSessionCookie(SessionCookieConfig config) {\n\t\t\tCookie cookie = this.session.getCookie();\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(cookie::getName).to(config::setName);\n\t\t\tmap.from(cookie::getDomain).to(config::setDomain);\n\t\t\tmap.from(cookie::getPath).to(config::setPath);\n\t\t\tmap.from(cookie::getHttpOnly).to(config::setHttpOnly);\n\t\t\tmap.from(cookie::getSecure).to(config::setSecure);\n\t\t\tmap.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(config::setMaxAge);\n\t\t\tmap.from(cookie::getPartitioned)\n\t\t\t\t.as(Object::toString)\n\t\t\t\t.to((partitioned) -> config.setAttribute(\"Partitioned\", partitioned));\n\t\t}\n\n\t\t@Contract(\"!null -> !null\")\n\t\tprivate @Nullable Set<jakarta.servlet.SessionTrackingMode> unwrap(\n\t\t\t\t@Nullable Set<Session.SessionTrackingMode> modes) {\n\t\t\tif (modes == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tSet<jakarta.servlet.SessionTrackingMode> result = new LinkedHashSet<>();\n\t\t\tfor (Session.SessionTrackingMode mode : modes) {\n\t\t\t\tresult.add(jakarta.servlet.SessionTrackingMode.valueOf(mode.name()));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerFactory;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\n\n/**\n * Factory interface that can be used to create a {@link WebServer}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see WebServer\n */\n@FunctionalInterface\npublic interface ServletWebServerFactory extends WebServerFactory {\n\n\t/**\n\t * Gets a new fully configured but paused {@link WebServer} instance. Clients should\n\t * not be able to connect to the returned server until {@link WebServer#start()} is\n\t * called (which happens when the {@code ApplicationContext} has been fully\n\t * refreshed).\n\t * @param initializers {@link ServletContextInitializer}s that should be applied as\n\t * the server starts\n\t * @return a fully configured and started {@link WebServer}\n\t * @see WebServer#stop()\n\t */\n\tWebServer getWebServer(ServletContextInitializer... initializers);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/ServletWebServerSettings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.util.Assert;\n\n/**\n * Settings for a servlet {@link WebServer} to be created by a\n * {@link ConfigurableServletWebServerFactory}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class ServletWebServerSettings {\n\n\tprivate ContextPath contextPath = ContextPath.DEFAULT;\n\n\tprivate @Nullable String displayName;\n\n\tprivate Session session = new Session();\n\n\tprivate boolean registerDefaultServlet;\n\n\tprivate MimeMappings mimeMappings = MimeMappings.lazyCopy(MimeMappings.DEFAULT);\n\n\tprivate @Nullable File documentRoot;\n\n\tprivate List<ServletContextInitializer> initializers = new ArrayList<>();\n\n\tprivate Jsp jsp = new Jsp();\n\n\tprivate Map<Locale, Charset> localeCharsetMappings = new HashMap<>();\n\n\tprivate Map<String, String> initParameters = new HashMap<>();\n\n\tprivate List<CookieSameSiteSupplier> cookieSameSiteSuppliers = new ArrayList<>();\n\n\tprivate final Set<String> webListenerClassNames = new HashSet<>();\n\n\tprivate final StaticResourceJars staticResourceJars = new StaticResourceJars();\n\n\tpublic ContextPath getContextPath() {\n\t\treturn this.contextPath;\n\t}\n\n\tpublic void setContextPath(ContextPath contextPath) {\n\t\tthis.contextPath = contextPath;\n\t}\n\n\tpublic @Nullable String getDisplayName() {\n\t\treturn this.displayName;\n\t}\n\n\tpublic void setDisplayName(@Nullable String displayName) {\n\t\tthis.displayName = displayName;\n\t}\n\n\tpublic Session getSession() {\n\t\treturn this.session;\n\t}\n\n\tpublic void setSession(Session session) {\n\t\tthis.session = session;\n\t}\n\n\tpublic boolean isRegisterDefaultServlet() {\n\t\treturn this.registerDefaultServlet;\n\t}\n\n\tpublic void setRegisterDefaultServlet(boolean registerDefaultServlet) {\n\t\tthis.registerDefaultServlet = registerDefaultServlet;\n\t}\n\n\tpublic MimeMappings getMimeMappings() {\n\t\treturn this.mimeMappings;\n\t}\n\n\tpublic @Nullable File getDocumentRoot() {\n\t\treturn this.documentRoot;\n\t}\n\n\tpublic void setDocumentRoot(@Nullable File documentRoot) {\n\t\tthis.documentRoot = documentRoot;\n\t}\n\n\tpublic List<? extends ServletContextInitializer> getInitializers() {\n\t\treturn this.initializers;\n\t}\n\n\tpublic void setJsp(Jsp jsp) {\n\t\tthis.jsp = jsp;\n\t}\n\n\tpublic Jsp getJsp() {\n\t\treturn this.jsp;\n\t}\n\n\tpublic Map<Locale, Charset> getLocaleCharsetMappings() {\n\t\treturn this.localeCharsetMappings;\n\t}\n\n\tpublic Map<String, String> getInitParameters() {\n\t\treturn this.initParameters;\n\t}\n\n\tpublic List<? extends CookieSameSiteSupplier> getCookieSameSiteSuppliers() {\n\t\treturn this.cookieSameSiteSuppliers;\n\t}\n\n\tpublic void setMimeMappings(MimeMappings mimeMappings) {\n\t\tAssert.notNull(mimeMappings, \"'mimeMappings' must not be null\");\n\t\tthis.mimeMappings = new MimeMappings(mimeMappings);\n\t}\n\n\tpublic void addMimeMappings(MimeMappings mimeMappings) {\n\t\tmimeMappings.forEach((mapping) -> this.mimeMappings.add(mapping.getExtension(), mapping.getMimeType()));\n\t}\n\n\tpublic void setInitializers(List<? extends ServletContextInitializer> initializers) {\n\t\tAssert.notNull(initializers, \"'initializers' must not be null\");\n\t\tthis.initializers = new ArrayList<>(initializers);\n\t}\n\n\tpublic void addInitializers(ServletContextInitializer... initializers) {\n\t\tAssert.notNull(initializers, \"'initializers' must not be null\");\n\t\tthis.initializers.addAll(Arrays.asList(initializers));\n\t}\n\n\tpublic void setLocaleCharsetMappings(Map<Locale, Charset> localeCharsetMappings) {\n\t\tAssert.notNull(localeCharsetMappings, \"'localeCharsetMappings' must not be null\");\n\t\tthis.localeCharsetMappings = localeCharsetMappings;\n\t}\n\n\tpublic void setInitParameters(Map<String, String> initParameters) {\n\t\tthis.initParameters = initParameters;\n\t}\n\n\tpublic void setCookieSameSiteSuppliers(List<? extends CookieSameSiteSupplier> cookieSameSiteSuppliers) {\n\t\tAssert.notNull(cookieSameSiteSuppliers, \"'cookieSameSiteSuppliers' must not be null\");\n\t\tthis.cookieSameSiteSuppliers = new ArrayList<>(cookieSameSiteSuppliers);\n\t}\n\n\tpublic void addCookieSameSiteSuppliers(CookieSameSiteSupplier... cookieSameSiteSuppliers) {\n\t\tAssert.notNull(cookieSameSiteSuppliers, \"'cookieSameSiteSuppliers' must not be null\");\n\t\tthis.cookieSameSiteSuppliers.addAll(Arrays.asList(cookieSameSiteSuppliers));\n\t}\n\n\tpublic void addWebListenerClassNames(String... webListenerClassNames) {\n\t\tthis.webListenerClassNames.addAll(Arrays.asList(webListenerClassNames));\n\t}\n\n\tpublic Set<String> getWebListenerClassNames() {\n\t\treturn this.webListenerClassNames;\n\t}\n\n\tpublic List<URL> getStaticResourceUrls() {\n\t\treturn this.staticResourceJars.getUrls();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/Session.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\nimport org.springframework.boot.convert.DurationUnit;\nimport org.springframework.boot.web.server.Cookie;\n\n/**\n * Session properties.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class Session {\n\n\t/**\n\t * Session timeout. If a duration suffix is not specified, seconds will be used.\n\t */\n\t@DurationUnit(ChronoUnit.SECONDS)\n\tprivate @Nullable Duration timeout = Duration.ofMinutes(30);\n\n\t/**\n\t * Session tracking modes.\n\t */\n\tprivate @Nullable Set<Session.SessionTrackingMode> trackingModes;\n\n\t/**\n\t * Whether to persist session data between restarts.\n\t */\n\tprivate boolean persistent;\n\n\t/**\n\t * Directory used to store session data.\n\t */\n\tprivate @Nullable File storeDir;\n\n\t@NestedConfigurationProperty\n\tprivate final Cookie cookie = new Cookie();\n\n\tprivate final SessionStoreDirectory sessionStoreDirectory = new SessionStoreDirectory();\n\n\tpublic @Nullable Duration getTimeout() {\n\t\treturn this.timeout;\n\t}\n\n\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\t/**\n\t * Return the {@link SessionTrackingMode session tracking modes}.\n\t * @return the session tracking modes\n\t */\n\tpublic @Nullable Set<Session.SessionTrackingMode> getTrackingModes() {\n\t\treturn this.trackingModes;\n\t}\n\n\tpublic void setTrackingModes(@Nullable Set<Session.SessionTrackingMode> trackingModes) {\n\t\tthis.trackingModes = trackingModes;\n\t}\n\n\t/**\n\t * Return whether to persist session data between restarts.\n\t * @return {@code true} to persist session data between restarts.\n\t */\n\tpublic boolean isPersistent() {\n\t\treturn this.persistent;\n\t}\n\n\tpublic void setPersistent(boolean persistent) {\n\t\tthis.persistent = persistent;\n\t}\n\n\t/**\n\t * Return the directory used to store session data.\n\t * @return the session data store directory\n\t */\n\tpublic @Nullable File getStoreDir() {\n\t\treturn this.storeDir;\n\t}\n\n\tpublic void setStoreDir(@Nullable File storeDir) {\n\t\tthis.sessionStoreDirectory.setDirectory(storeDir);\n\t\tthis.storeDir = storeDir;\n\t}\n\n\tpublic Cookie getCookie() {\n\t\treturn this.cookie;\n\t}\n\n\tpublic SessionStoreDirectory getSessionStoreDirectory() {\n\t\treturn this.sessionStoreDirectory;\n\t}\n\n\t/**\n\t * Available session tracking modes (mirrors\n\t * {@link jakarta.servlet.SessionTrackingMode}).\n\t */\n\tpublic enum SessionTrackingMode {\n\n\t\t/**\n\t\t * Send a cookie in response to the client's first request.\n\t\t */\n\t\tCOOKIE,\n\n\t\t/**\n\t\t * Rewrite the URL to append a session ID.\n\t\t */\n\t\tURL,\n\n\t\t/**\n\t\t * Use SSL build-in mechanism to track the session.\n\t\t */\n\t\tSSL\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/SessionStoreDirectory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.system.ApplicationHome;\nimport org.springframework.boot.system.ApplicationTemp;\nimport org.springframework.util.Assert;\n\n/**\n * Manages a session store directory.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class SessionStoreDirectory {\n\n\tprivate @Nullable File directory;\n\n\t@Nullable File getDirectory() {\n\t\treturn this.directory;\n\t}\n\n\tvoid setDirectory(@Nullable File directory) {\n\t\tthis.directory = directory;\n\t}\n\n\tpublic File getValidDirectory(boolean mkdirs) {\n\t\tFile dir = getDirectory();\n\t\tif (dir == null) {\n\t\t\treturn new ApplicationTemp().getDir(\"servlet-sessions\");\n\t\t}\n\t\tif (!dir.isAbsolute()) {\n\t\t\tdir = new File(new ApplicationHome().getDir(), dir.getPath());\n\t\t}\n\t\tif (!dir.exists() && mkdirs) {\n\t\t\tdir.mkdirs();\n\t\t}\n\t\tassertDirectory(mkdirs, dir);\n\t\treturn dir;\n\t}\n\n\tprivate void assertDirectory(boolean mkdirs, File dir) {\n\t\tAssert.state(!mkdirs || dir.exists(), () -> \"Session dir \" + dir + \" does not exist\");\n\t\tAssert.state(!dir.isFile(), () -> \"Session dir \" + dir + \" points to a file\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/StaticResourceJars.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.management.ManagementFactory;\nimport java.net.JarURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.net.URLConnection;\nimport java.nio.file.InvalidPathException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.jar.JarFile;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Logic to extract URLs of static resource jars (those containing\n * {@code \"META-INF/resources\"} directories).\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass StaticResourceJars {\n\n\tList<URL> getUrls() {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tif (classLoader instanceof URLClassLoader urlClassLoader) {\n\t\t\treturn getUrlsFrom(urlClassLoader.getURLs());\n\t\t}\n\t\telse {\n\t\t\treturn getUrlsFrom(Stream.of(ManagementFactory.getRuntimeMXBean().getClassPath().split(File.pathSeparator))\n\t\t\t\t.map(this::toUrl)\n\t\t\t\t.toArray(URL[]::new));\n\t\t}\n\t}\n\n\tList<URL> getUrlsFrom(URL... urls) {\n\t\tList<URL> resourceJarUrls = new ArrayList<>();\n\t\tfor (URL url : urls) {\n\t\t\taddUrl(resourceJarUrls, url);\n\t\t}\n\t\treturn resourceJarUrls;\n\t}\n\n\tprivate URL toUrl(String classPathEntry) {\n\t\ttry {\n\t\t\treturn new File(classPathEntry).toURI().toURL();\n\t\t}\n\t\tcatch (MalformedURLException ex) {\n\t\t\tthrow new IllegalArgumentException(\"URL could not be created from '\" + classPathEntry + \"'\", ex);\n\t\t}\n\t}\n\n\tprivate @Nullable File toFile(URL url) {\n\t\ttry {\n\t\t\treturn new File(url.toURI());\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to create File from URL '\" + url + \"'\");\n\t\t}\n\t\tcatch (IllegalArgumentException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate void addUrl(List<URL> urls, URL url) {\n\t\ttry {\n\t\t\tif (!\"file\".equals(url.getProtocol())) {\n\t\t\t\taddUrlConnection(urls, url, url.openConnection());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tFile file = toFile(url);\n\t\t\t\tif (file != null) {\n\t\t\t\t\taddUrlFile(urls, url, file);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\taddUrlConnection(urls, url, url.openConnection());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate void addUrlFile(List<URL> urls, URL url, File file) {\n\t\tif ((file.isDirectory() && new File(file, \"META-INF/resources\").isDirectory()) || isResourcesJar(file)) {\n\t\t\turls.add(url);\n\t\t}\n\t}\n\n\tprivate void addUrlConnection(List<URL> urls, URL url, URLConnection connection) {\n\t\tif (connection instanceof JarURLConnection jarURLConnection && isResourcesJar(jarURLConnection)) {\n\t\t\turls.add(url);\n\t\t}\n\t}\n\n\tprivate boolean isResourcesJar(JarURLConnection connection) {\n\t\ttry {\n\t\t\treturn isResourcesJar(connection.getJarFile(), !connection.getUseCaches());\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean isResourcesJar(File file) {\n\t\ttry {\n\t\t\treturn isResourcesJar(new JarFile(file), true);\n\t\t}\n\t\tcatch (IOException | InvalidPathException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean isResourcesJar(JarFile jarFile, boolean closeJarFile) throws IOException {\n\t\ttry {\n\t\t\treturn jarFile.getName().endsWith(\".jar\") && (jarFile.getJarEntry(\"META-INF/resources\") != null);\n\t\t}\n\t\tfinally {\n\t\t\tif (closeJarFile) {\n\t\t\t\tjarFile.close();\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/WebListenerRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport jakarta.servlet.annotation.WebListener;\n\n/**\n * Interface to be implemented by types that register {@link WebListener @WebListeners}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface WebListenerRegistrar {\n\n\t/**\n\t * Register web listeners with the given registry.\n\t * @param registry the web listener registry\n\t */\n\tvoid register(WebListenerRegistry registry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/WebListenerRegistry.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport jakarta.servlet.annotation.WebListener;\n\n/**\n * A registry that holds {@link WebListener @WebListeners}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic interface WebListenerRegistry {\n\n\t/**\n\t * Adds web listeners that will be registered with the servlet web server.\n\t * @param webListenerClassNames the class names of the web listeners\n\t */\n\tvoid addWebListeners(String... webListenerClassNames);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/AnnotationConfigServletWebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanNameGenerator;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.context.annotation.AnnotatedBeanDefinitionReader;\nimport org.springframework.context.annotation.AnnotationConfigRegistry;\nimport org.springframework.context.annotation.AnnotationConfigUtils;\nimport org.springframework.context.annotation.AnnotationScopeMetadataResolver;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.ScopeMetadataResolver;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ServletWebServerApplicationContext} that accepts annotated classes as input - in\n * particular {@link org.springframework.context.annotation.Configuration @Configuration}\n * -annotated classes, but also plain {@link Component @Component} classes and JSR-330\n * compliant classes using {@code javax.inject} annotations. Allows for registering\n * classes one by one (specifying class names as config location) as well as for classpath\n * scanning (specifying base packages as config location).\n * <p>\n * Note: In case of multiple {@code @Configuration} classes, later {@code @Bean}\n * definitions will override ones defined in earlier loaded files. This can be leveraged\n * to deliberately override certain bean definitions through an extra Configuration class.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see #register(Class...)\n * @see #scan(String...)\n * @see ServletWebServerApplicationContext\n */\npublic class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext\n\t\timplements AnnotationConfigRegistry {\n\n\tprivate final AnnotatedBeanDefinitionReader reader;\n\n\tprivate final ClassPathBeanDefinitionScanner scanner;\n\n\tprivate final Set<Class<?>> annotatedClasses = new LinkedHashSet<>();\n\n\tprivate String @Nullable [] basePackages;\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebServerApplicationContext} that needs\n\t * to be populated through {@link #register} calls and then manually\n\t * {@linkplain #refresh refreshed}.\n\t */\n\tpublic AnnotationConfigServletWebServerApplicationContext() {\n\t\tthis.reader = new AnnotatedBeanDefinitionReader(this);\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(this);\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebServerApplicationContext} with the\n\t * given {@code DefaultListableBeanFactory}. The context needs to be populated through\n\t * {@link #register} calls and then manually {@linkplain #refresh refreshed}.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t */\n\tpublic AnnotationConfigServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t\tthis.reader = new AnnotatedBeanDefinitionReader(this);\n\t\tthis.scanner = new ClassPathBeanDefinitionScanner(this);\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebServerApplicationContext}, deriving\n\t * bean definitions from the given annotated classes and automatically refreshing the\n\t * context.\n\t * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}\n\t * classes\n\t */\n\tpublic AnnotationConfigServletWebServerApplicationContext(Class<?>... annotatedClasses) {\n\t\tthis();\n\t\tregister(annotatedClasses);\n\t\trefresh();\n\t}\n\n\t/**\n\t * Create a new {@link AnnotationConfigServletWebServerApplicationContext}, scanning\n\t * for bean definitions in the given packages and automatically refreshing the\n\t * context.\n\t * @param basePackages the packages to check for annotated classes\n\t */\n\tpublic AnnotationConfigServletWebServerApplicationContext(String... basePackages) {\n\t\tthis();\n\t\tscan(basePackages);\n\t\trefresh();\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <p>\n\t * Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader} and\n\t * {@link ClassPathBeanDefinitionScanner} members.\n\t */\n\t@Override\n\tpublic void setEnvironment(ConfigurableEnvironment environment) {\n\t\tsuper.setEnvironment(environment);\n\t\tthis.reader.setEnvironment(environment);\n\t\tthis.scanner.setEnvironment(environment);\n\t}\n\n\t/**\n\t * Provide a custom {@link BeanNameGenerator} for use with\n\t * {@link AnnotatedBeanDefinitionReader} and/or\n\t * {@link ClassPathBeanDefinitionScanner}, if any.\n\t * <p>\n\t * Default is\n\t * {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.\n\t * <p>\n\t * Any call to this method must occur prior to calls to {@link #register(Class...)}\n\t * and/or {@link #scan(String...)}.\n\t * @param beanNameGenerator the bean name generator\n\t * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator\n\t * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator\n\t */\n\tpublic void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {\n\t\tthis.reader.setBeanNameGenerator(beanNameGenerator);\n\t\tthis.scanner.setBeanNameGenerator(beanNameGenerator);\n\t\tgetBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);\n\t}\n\n\t/**\n\t * Set the {@link ScopeMetadataResolver} to use for detected bean classes.\n\t * <p>\n\t * The default is an {@link AnnotationScopeMetadataResolver}.\n\t * <p>\n\t * Any call to this method must occur prior to calls to {@link #register(Class...)}\n\t * and/or {@link #scan(String...)}.\n\t * @param scopeMetadataResolver the scope metadata resolver\n\t */\n\tpublic void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {\n\t\tthis.reader.setScopeMetadataResolver(scopeMetadataResolver);\n\t\tthis.scanner.setScopeMetadataResolver(scopeMetadataResolver);\n\t}\n\n\t/**\n\t * Register one or more annotated classes to be processed. Note that\n\t * {@link #refresh()} must be called in order for the context to fully process the new\n\t * class.\n\t * <p>\n\t * Calls to {@code #register} are idempotent; adding the same annotated class more\n\t * than once has no additional effect.\n\t * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}\n\t * classes\n\t * @see #scan(String...)\n\t * @see #refresh()\n\t */\n\t@Override\n\tpublic final void register(Class<?>... annotatedClasses) {\n\t\tAssert.notEmpty(annotatedClasses, \"'annotatedClasses' must not be empty\");\n\t\tthis.annotatedClasses.addAll(Arrays.asList(annotatedClasses));\n\t}\n\n\t/**\n\t * Perform a scan within the specified base packages. Note that {@link #refresh()}\n\t * must be called in order for the context to fully process the new class.\n\t * @param basePackages the packages to check for annotated classes\n\t * @see #register(Class...)\n\t * @see #refresh()\n\t */\n\t@Override\n\tpublic final void scan(String... basePackages) {\n\t\tAssert.notEmpty(basePackages, \"'basePackages' must not be empty\");\n\t\tthis.basePackages = basePackages;\n\t}\n\n\t@Override\n\tprotected void prepareRefresh() {\n\t\tthis.scanner.clearCache();\n\t\tsuper.prepareRefresh();\n\t}\n\n\t@Override\n\tprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\tsuper.postProcessBeanFactory(beanFactory);\n\t\tif (this.basePackages != null && this.basePackages.length > 0) {\n\t\t\tthis.scanner.scan(this.basePackages);\n\t\t}\n\t\tif (!this.annotatedClasses.isEmpty()) {\n\t\t\tthis.reader.register(ClassUtils.toClassArray(this.annotatedClasses));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.lang.annotation.Annotation;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\nimport org.springframework.core.type.filter.TypeFilter;\nimport org.springframework.util.Assert;\n\n/**\n * Abstract base class for handlers of Servlet components discovered through classpath\n * scanning.\n *\n * @author Andy Wilkinson\n */\nabstract class ServletComponentHandler {\n\n\tprivate final Class<? extends Annotation> annotationType;\n\n\tprivate final TypeFilter typeFilter;\n\n\tprotected ServletComponentHandler(Class<? extends Annotation> annotationType) {\n\t\tthis.typeFilter = new AnnotationTypeFilter(annotationType);\n\t\tthis.annotationType = annotationType;\n\t}\n\n\tTypeFilter getTypeFilter() {\n\t\treturn this.typeFilter;\n\t}\n\n\tprotected String[] extractUrlPatterns(Map<String, @Nullable Object> attributes) {\n\t\tString[] value = (String[]) attributes.get(\"value\");\n\t\tString[] urlPatterns = (String[]) attributes.get(\"urlPatterns\");\n\t\tAssert.state(urlPatterns != null, \"'urlPatterns' must not be null\");\n\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\tif (urlPatterns.length > 0) {\n\t\t\tAssert.state(value.length == 0, \"The urlPatterns and value attributes are mutually exclusive\");\n\t\t\treturn urlPatterns;\n\t\t}\n\t\treturn value;\n\t}\n\n\tprotected final Map<String, String> extractInitParameters(Map<String, @Nullable Object> attributes) {\n\t\tMap<String, String> initParameters = new HashMap<>();\n\t\tAnnotationAttributes[] initParams = (AnnotationAttributes[]) attributes.get(\"initParams\");\n\t\tAssert.state(initParams != null, \"'initParams' must not be null\");\n\t\tfor (AnnotationAttributes initParam : initParams) {\n\t\t\tString name = (String) initParam.get(\"name\");\n\t\t\tString value = (String) initParam.get(\"value\");\n\t\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\t\tAssert.state(value != null, \"'value' must not be null\");\n\t\t\tinitParameters.put(name, value);\n\t\t}\n\t\treturn initParameters;\n\t}\n\n\tvoid handle(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {\n\t\tMap<String, @Nullable Object> attributes = beanDefinition.getMetadata()\n\t\t\t.getAnnotationAttributes(this.annotationType.getName());\n\t\tif (attributes != null) {\n\t\t\tdoHandle(attributes, beanDefinition, registry);\n\t\t}\n\t}\n\n\tprotected abstract void doHandle(Map<String, @Nullable Object> attributes, AnnotatedBeanDefinition beanDefinition,\n\t\t\tBeanDefinitionRegistry registry);\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentRegisteringPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;\nimport org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * {@link BeanFactoryPostProcessor} that registers beans for Servlet components found via\n * package scanning.\n *\n * @author Andy Wilkinson\n * @see ServletComponentScan\n * @see ServletComponentScanRegistrar\n */\nclass ServletComponentRegisteringPostProcessor\n\t\timplements BeanFactoryPostProcessor, ApplicationContextAware, BeanFactoryInitializationAotProcessor {\n\n\tprivate static final boolean MOCK_SERVLET_CONTEXT_AVAILABLE = ClassUtils\n\t\t.isPresent(\"org.springframework.mock.web.MockServletContext\", null);\n\n\tprivate static final List<ServletComponentHandler> HANDLERS;\n\n\tstatic {\n\t\tList<ServletComponentHandler> servletComponentHandlers = new ArrayList<>();\n\t\tservletComponentHandlers.add(new WebServletHandler());\n\t\tservletComponentHandlers.add(new WebFilterHandler());\n\t\tservletComponentHandlers.add(new WebListenerHandler());\n\t\tHANDLERS = Collections.unmodifiableList(servletComponentHandlers);\n\t}\n\n\tprivate final Set<String> packagesToScan;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ApplicationContext applicationContext;\n\n\tServletComponentRegisteringPostProcessor(Set<String> packagesToScan) {\n\t\tthis.packagesToScan = packagesToScan;\n\t}\n\n\t@Override\n\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\tif (eligibleForServletComponentScanning()) {\n\t\t\tClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();\n\t\t\tfor (String packageToScan : this.packagesToScan) {\n\t\t\t\tscanPackage(componentProvider, packageToScan);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider, String packageToScan) {\n\t\tfor (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {\n\t\t\tif (candidate instanceof AnnotatedBeanDefinition annotatedBeanDefinition) {\n\t\t\t\tfor (ServletComponentHandler handler : HANDLERS) {\n\t\t\t\t\thandler.handle(annotatedBeanDefinition, (BeanDefinitionRegistry) this.applicationContext);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate boolean eligibleForServletComponentScanning() {\n\t\treturn this.applicationContext instanceof WebApplicationContext webApplicationContext\n\t\t\t\t&& (webApplicationContext.getServletContext() == null || (MOCK_SERVLET_CONTEXT_AVAILABLE\n\t\t\t\t\t\t&& webApplicationContext.getServletContext() instanceof MockServletContext));\n\t}\n\n\tprivate ClassPathScanningCandidateComponentProvider createComponentProvider() {\n\t\tClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(\n\t\t\t\tfalse);\n\t\tcomponentProvider.setEnvironment(this.applicationContext.getEnvironment());\n\t\tcomponentProvider.setResourceLoader(this.applicationContext);\n\t\tfor (ServletComponentHandler handler : HANDLERS) {\n\t\t\tcomponentProvider.addIncludeFilter(handler.getTypeFilter());\n\t\t}\n\t\treturn componentProvider;\n\t}\n\n\tSet<String> getPackagesToScan() {\n\t\treturn Collections.unmodifiableSet(this.packagesToScan);\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Override\n\tpublic BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {\n\t\treturn (generationContext, beanFactoryInitializationCode) -> {\n\t\t\tfor (String beanName : beanFactory.getBeanDefinitionNames()) {\n\t\t\t\tBeanDefinition definition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\tif (Objects.equals(definition.getBeanClassName(),\n\t\t\t\t\t\tWebListenerHandler.ServletComponentWebListenerRegistrar.class.getName())) {\n\t\t\t\t\tValueHolder firstArgument = definition.getConstructorArgumentValues()\n\t\t\t\t\t\t.getArgumentValue(0, String.class);\n\t\t\t\t\tAssert.notNull(firstArgument, \"'firstArgument' must not be null\");\n\t\t\t\t\tString listenerClassName = (String) firstArgument.getValue();\n\t\t\t\t\tAssert.state(listenerClassName != null, \"'listenerClassName' must not be null\");\n\t\t\t\t\tgenerationContext.getRuntimeHints()\n\t\t\t\t\t\t.reflection()\n\t\t\t\t\t\t.registerType(TypeReference.of(listenerClassName), MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentScan.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.servlet.annotation.WebFilter;\nimport jakarta.servlet.annotation.WebListener;\nimport jakarta.servlet.annotation.WebServlet;\n\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Enables scanning for Servlet components ({@link WebFilter filters}, {@link WebServlet\n * servlets}, and {@link WebListener listeners}). Scanning is only performed when using an\n * embedded web server.\n * <p>\n * Typically, one of {@code value}, {@code basePackages}, or {@code basePackageClasses}\n * should be specified to control the packages to be scanned for components. In their\n * absence, scanning will be performed from the package of the class with the annotation.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see WebServlet\n * @see WebFilter\n * @see WebListener\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Import(ServletComponentScanRegistrar.class)\npublic @interface ServletComponentScan {\n\n\t/**\n\t * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation\n\t * declarations e.g.: {@code @ServletComponentScan(\"org.my.pkg\")} instead of\n\t * {@code @ServletComponentScan(basePackages=\"org.my.pkg\")}.\n\t * @return the base packages to scan\n\t */\n\t@AliasFor(\"basePackages\")\n\tString[] value() default {};\n\n\t/**\n\t * Base packages to scan for annotated servlet components. {@link #value()} is an\n\t * alias for (and mutually exclusive with) this attribute.\n\t * <p>\n\t * Use {@link #basePackageClasses()} for a type-safe alternative to String-based\n\t * package names.\n\t * @return the base packages to scan\n\t */\n\t@AliasFor(\"value\")\n\tString[] basePackages() default {};\n\n\t/**\n\t * Type-safe alternative to {@link #basePackages()} for specifying the packages to\n\t * scan for annotated servlet components. The package of each class specified will be\n\t * scanned.\n\t * @return classes from the base packages to scan\n\t */\n\tClass<?>[] basePackageClasses() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanRegistrar.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\nimport java.util.function.Supplier;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link ImportBeanDefinitionRegistrar} used by\n * {@link ServletComponentScan @ServletComponentScan}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\nclass ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {\n\n\tprivate static final String BEAN_NAME = \"servletComponentRegisteringPostProcessor\";\n\n\t@Override\n\tpublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {\n\t\tSet<String> packagesToScan = getPackagesToScan(importingClassMetadata);\n\t\tif (registry.containsBeanDefinition(BEAN_NAME)) {\n\t\t\tupdatePostProcessor(registry, packagesToScan);\n\t\t}\n\t\telse {\n\t\t\taddPostProcessor(registry, packagesToScan);\n\t\t}\n\t}\n\n\tprivate void updatePostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {\n\t\tServletComponentRegisteringPostProcessorBeanDefinition definition = (ServletComponentRegisteringPostProcessorBeanDefinition) registry\n\t\t\t.getBeanDefinition(BEAN_NAME);\n\t\tdefinition.addPackageNames(packagesToScan);\n\t}\n\n\tprivate void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {\n\t\tServletComponentRegisteringPostProcessorBeanDefinition definition = new ServletComponentRegisteringPostProcessorBeanDefinition(\n\t\t\t\tpackagesToScan);\n\t\tregistry.registerBeanDefinition(BEAN_NAME, definition);\n\t}\n\n\tprivate Set<String> getPackagesToScan(AnnotationMetadata metadata) {\n\t\tAnnotationAttributes attributes = AnnotationAttributes\n\t\t\t.fromMap(metadata.getAnnotationAttributes(ServletComponentScan.class.getName()));\n\t\tAssert.state(attributes != null, \"'attributes' must not be null\");\n\t\tString[] basePackages = attributes.getStringArray(\"basePackages\");\n\t\tClass<?>[] basePackageClasses = attributes.getClassArray(\"basePackageClasses\");\n\t\tSet<String> packagesToScan = new LinkedHashSet<>(Arrays.asList(basePackages));\n\t\tfor (Class<?> basePackageClass : basePackageClasses) {\n\t\t\tpackagesToScan.add(ClassUtils.getPackageName(basePackageClass));\n\t\t}\n\t\tif (packagesToScan.isEmpty()) {\n\t\t\tpackagesToScan.add(ClassUtils.getPackageName(metadata.getClassName()));\n\t\t}\n\t\treturn packagesToScan;\n\t}\n\n\tstatic final class ServletComponentRegisteringPostProcessorBeanDefinition extends RootBeanDefinition {\n\n\t\tprivate final Set<String> packageNames = new LinkedHashSet<>();\n\n\t\tServletComponentRegisteringPostProcessorBeanDefinition(Collection<String> packageNames) {\n\t\t\tsetBeanClass(ServletComponentRegisteringPostProcessor.class);\n\t\t\tsetRole(BeanDefinition.ROLE_INFRASTRUCTURE);\n\t\t\taddPackageNames(packageNames);\n\t\t}\n\n\t\t@Override\n\t\tpublic Supplier<?> getInstanceSupplier() {\n\t\t\treturn () -> new ServletComponentRegisteringPostProcessor(this.packageNames);\n\t\t}\n\n\t\tprivate void addPackageNames(Collection<String> additionalPackageNames) {\n\t\t\tthis.packageNames.addAll(additionalPackageNames);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletConfig;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.Scope;\nimport org.springframework.beans.factory.support.DefaultListableBeanFactory;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.web.context.servlet.WebApplicationContextInitializer;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.ConfigurableWebServerApplicationContext;\nimport org.springframework.boot.web.server.context.MissingWebServerFactoryBeanException;\nimport org.springframework.boot.web.server.context.WebServerGracefulShutdownLifecycle;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.metrics.StartupStep;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.ServletContextAware;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.GenericWebApplicationContext;\nimport org.springframework.web.context.support.ServletContextAwareProcessor;\nimport org.springframework.web.context.support.ServletContextResource;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\n\n/**\n * A {@link WebApplicationContext} that can be used to bootstrap itself from a contained\n * {@link ServletWebServerFactory} bean.\n * <p>\n * This context will create, initialize and run an {@link WebServer} by searching for a\n * single {@link ServletWebServerFactory} bean within the {@link ApplicationContext}\n * itself. The {@link ServletWebServerFactory} is free to use standard Spring concepts\n * (such as dependency injection, lifecycle callbacks and property placeholder variables).\n * <p>\n * In addition, any {@link Servlet} or {@link Filter} beans defined in the context will be\n * automatically registered with the web server. In the case of a single Servlet bean, the\n * '/' mapping will be used. If multiple Servlet beans are found then the lowercase bean\n * name will be used as a mapping prefix. Any Servlet named 'dispatcherServlet' will\n * always be mapped to '/'. Filter beans will be mapped to all URLs ('/*').\n * <p>\n * For more advanced configuration, the context can instead define beans that implement\n * the {@link ServletContextInitializer} interface (most often\n * {@link ServletRegistrationBean}s and/or {@link FilterRegistrationBean}s). To prevent\n * double registration, the use of {@link ServletContextInitializer} beans will disable\n * automatic Servlet and Filter bean registration.\n * <p>\n * Although this context can be used directly, most developers should consider using the\n * {@link AnnotationConfigServletWebServerApplicationContext} or\n * {@link XmlServletWebServerApplicationContext} variants.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Scott Frederick\n * @since 4.0.0\n * @see AnnotationConfigServletWebServerApplicationContext\n * @see XmlServletWebServerApplicationContext\n * @see ServletWebServerFactory\n */\npublic class ServletWebServerApplicationContext extends GenericWebApplicationContext\n\t\timplements ConfigurableWebServerApplicationContext {\n\n\tprivate static final Log logger = LogFactory.getLog(ServletWebServerApplicationContext.class);\n\n\t/**\n\t * Constant value for the DispatcherServlet bean name. A Servlet bean with this name\n\t * is deemed to be the \"main\" servlet and is automatically given a mapping of \"/\" by\n\t * default. To change the default behavior you can use a\n\t * {@link ServletRegistrationBean} or a different bean name.\n\t */\n\tpublic static final String DISPATCHER_SERVLET_NAME = \"dispatcherServlet\";\n\n\tprivate volatile @Nullable WebServer webServer;\n\n\tprivate @Nullable ServletConfig servletConfig;\n\n\tprivate @Nullable String serverNamespace;\n\n\t/**\n\t * Create a new {@link ServletWebServerApplicationContext}.\n\t */\n\tpublic ServletWebServerApplicationContext() {\n\t}\n\n\t/**\n\t * Create a new {@link ServletWebServerApplicationContext} with the given\n\t * {@code DefaultListableBeanFactory}.\n\t * @param beanFactory the DefaultListableBeanFactory instance to use for this context\n\t */\n\tpublic ServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {\n\t\tsuper(beanFactory);\n\t}\n\n\t/**\n\t * Register ServletContextAwareProcessor.\n\t * @see ServletContextAwareProcessor\n\t */\n\t@Override\n\tprotected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\tbeanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));\n\t\tbeanFactory.ignoreDependencyInterface(ServletContextAware.class);\n\t\tregisterWebApplicationScopes();\n\t}\n\n\t@Override\n\tpublic final void refresh() throws BeansException, IllegalStateException {\n\t\ttry {\n\t\t\tsuper.refresh();\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\tWebServer webServer = this.webServer;\n\t\t\tif (webServer != null) {\n\t\t\t\ttry {\n\t\t\t\t\twebServer.stop();\n\t\t\t\t\twebServer.destroy();\n\t\t\t\t}\n\t\t\t\tcatch (RuntimeException stopOrDestroyEx) {\n\t\t\t\t\tex.addSuppressed(stopOrDestroyEx);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onRefresh() {\n\t\tsuper.onRefresh();\n\t\ttry {\n\t\t\tcreateWebServer();\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\tthrow new ApplicationContextException(\"Unable to start web server\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void doClose() {\n\t\tif (isActive()) {\n\t\t\tAvailabilityChangeEvent.publish(this, ReadinessState.REFUSING_TRAFFIC);\n\t\t}\n\t\tsuper.doClose();\n\t\tWebServer webServer = this.webServer;\n\t\tif (webServer != null) {\n\t\t\twebServer.destroy();\n\t\t}\n\t}\n\n\tprivate void createWebServer() {\n\t\tWebServer webServer = this.webServer;\n\t\tServletContext servletContext = getServletContext();\n\t\tif (webServer == null && servletContext == null) {\n\t\t\tStartupStep createWebServer = getApplicationStartup().start(\"spring.boot.webserver.create\");\n\t\t\tServletWebServerFactory factory = getWebServerFactory();\n\t\t\tcreateWebServer.tag(\"factory\", factory.getClass().toString());\n\t\t\twebServer = factory.getWebServer(getSelfInitializer());\n\t\t\tthis.webServer = webServer;\n\t\t\tcreateWebServer.end();\n\t\t\tgetBeanFactory().registerSingleton(\"webServerGracefulShutdown\",\n\t\t\t\t\tnew WebServerGracefulShutdownLifecycle(webServer));\n\t\t\tgetBeanFactory().registerSingleton(\"webServerStartStop\", new WebServerStartStopLifecycle(this, webServer));\n\t\t}\n\t\telse if (servletContext != null) {\n\t\t\ttry {\n\t\t\t\tgetSelfInitializer().onStartup(servletContext);\n\t\t\t}\n\t\t\tcatch (ServletException ex) {\n\t\t\t\tthrow new ApplicationContextException(\"Cannot initialize servlet context\", ex);\n\t\t\t}\n\t\t}\n\t\tinitPropertySources();\n\t}\n\n\t/**\n\t * Returns the {@link ServletWebServerFactory} that should be used to create the\n\t * embedded {@link WebServer}. By default this method searches for a suitable bean in\n\t * the context itself.\n\t * @return a {@link ServletWebServerFactory} (never {@code null})\n\t */\n\tprotected ServletWebServerFactory getWebServerFactory() {\n\t\t// Use bean names so that we don't consider the hierarchy\n\t\tString[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);\n\t\tif (beanNames.length == 0) {\n\t\t\tthrow new MissingWebServerFactoryBeanException(getClass(), ServletWebServerFactory.class,\n\t\t\t\t\tWebApplicationType.SERVLET);\n\t\t}\n\t\tif (beanNames.length > 1) {\n\t\t\tthrow new ApplicationContextException(\"Unable to start ServletWebServerApplicationContext due to multiple \"\n\t\t\t\t\t+ \"ServletWebServerFactory beans : \" + StringUtils.arrayToCommaDelimitedString(beanNames));\n\t\t}\n\t\treturn getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);\n\t}\n\n\t/**\n\t * Returns the {@link ServletContextInitializer} that will be used to complete the\n\t * setup of this {@link WebApplicationContext}.\n\t * @return the self initializer\n\t * @see #prepareWebApplicationContext(ServletContext)\n\t */\n\tprivate org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {\n\t\treturn new WebApplicationContextInitializer(this)::initialize;\n\t}\n\n\tprivate void registerWebApplicationScopes() {\n\t\tExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(getBeanFactory());\n\t\tWebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());\n\t\texistingScopes.restore();\n\t}\n\n\t@Override\n\tprotected Resource getResourceByPath(String path) {\n\t\tif (getServletContext() == null) {\n\t\t\treturn new ClassPathContextResource(path, getClassLoader());\n\t\t}\n\t\treturn new ServletContextResource(getServletContext(), path);\n\t}\n\n\t@Override\n\tpublic @Nullable String getServerNamespace() {\n\t\treturn this.serverNamespace;\n\t}\n\n\t@Override\n\tpublic void setServerNamespace(@Nullable String serverNamespace) {\n\t\tthis.serverNamespace = serverNamespace;\n\t}\n\n\t@Override\n\tpublic void setServletConfig(@Nullable ServletConfig servletConfig) {\n\t\tthis.servletConfig = servletConfig;\n\t}\n\n\t@Override\n\tpublic @Nullable ServletConfig getServletConfig() {\n\t\treturn this.servletConfig;\n\t}\n\n\t/**\n\t * Returns the {@link WebServer} that was created by the context or {@code null} if\n\t * the server has not yet been created.\n\t * @return the embedded web server\n\t */\n\t@Override\n\tpublic @Nullable WebServer getWebServer() {\n\t\treturn this.webServer;\n\t}\n\n\t/**\n\t * Utility class to store and restore any user defined scopes. This allows scopes to\n\t * be registered in an ApplicationContextInitializer in the same way as they would in\n\t * a classic non-embedded web application context.\n\t */\n\tpublic static class ExistingWebApplicationScopes {\n\n\t\tprivate static final Set<String> SCOPES;\n\n\t\tstatic {\n\t\t\tSet<String> scopes = new LinkedHashSet<>();\n\t\t\tscopes.add(WebApplicationContext.SCOPE_REQUEST);\n\t\t\tscopes.add(WebApplicationContext.SCOPE_SESSION);\n\t\t\tSCOPES = Collections.unmodifiableSet(scopes);\n\t\t}\n\n\t\tprivate final ConfigurableListableBeanFactory beanFactory;\n\n\t\tprivate final Map<String, Scope> scopes = new HashMap<>();\n\n\t\tpublic ExistingWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tthis.beanFactory = beanFactory;\n\t\t\tfor (String scopeName : SCOPES) {\n\t\t\t\tScope scope = beanFactory.getRegisteredScope(scopeName);\n\t\t\t\tif (scope != null) {\n\t\t\t\t\tthis.scopes.put(scopeName, scope);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpublic void restore() {\n\t\t\tthis.scopes.forEach((key, value) -> {\n\t\t\t\tif (logger.isInfoEnabled()) {\n\t\t\t\t\tlogger.info(\"Restoring user defined scope \" + key);\n\t\t\t\t}\n\t\t\t\tthis.beanFactory.registerScope(key, value);\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.AotDetector;\nimport org.springframework.boot.ApplicationContextFactory;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.web.context.servlet.ApplicationServletEnvironment;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * {@link ApplicationContextFactory} registered in {@code spring.factories} to support\n * {@link AnnotationConfigServletWebServerApplicationContext} and\n * {@link ServletWebServerApplicationContext}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ServletWebServerApplicationContextFactory implements ApplicationContextFactory {\n\n\t@Override\n\tpublic @Nullable Class<? extends ConfigurableEnvironment> getEnvironmentType(\n\t\t\t@Nullable WebApplicationType webApplicationType) {\n\t\treturn (webApplicationType != WebApplicationType.SERVLET) ? null : ApplicationServletEnvironment.class;\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurableEnvironment createEnvironment(@Nullable WebApplicationType webApplicationType) {\n\t\treturn (webApplicationType != WebApplicationType.SERVLET) ? null : new ApplicationServletEnvironment();\n\t}\n\n\t@Override\n\tpublic @Nullable ConfigurableApplicationContext create(@Nullable WebApplicationType webApplicationType) {\n\t\treturn (webApplicationType != WebApplicationType.SERVLET) ? null : createContext();\n\t}\n\n\tprivate ConfigurableApplicationContext createContext() {\n\t\tif (!AotDetector.useGeneratedArtifacts()) {\n\t\t\treturn new AnnotationConfigServletWebServerApplicationContext();\n\t\t}\n\t\treturn new ServletWebServerApplicationContext();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextLocalTestWebServerProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.BaseUriDetails;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * {@link LocalTestWebServer} provider for a {@link ServletWebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass ServletWebServerApplicationContextLocalTestWebServerProvider implements LocalTestWebServer.Provider {\n\n\tprivate final @Nullable ServletWebServerApplicationContext context;\n\n\tServletWebServerApplicationContextLocalTestWebServerProvider(ApplicationContext context) {\n\t\tthis.context = getWebServerApplicationContextIfPossible(context);\n\t}\n\n\tstatic @Nullable ServletWebServerApplicationContext getWebServerApplicationContextIfPossible(\n\t\t\tApplicationContext context) {\n\t\ttry {\n\t\t\treturn (ServletWebServerApplicationContext) context;\n\t\t}\n\t\tcatch (NoClassDefFoundError | ClassCastException ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\tif (this.context == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn LocalTestWebServer.of((isSslEnabled(this.context)) ? Scheme.HTTPS : Scheme.HTTP, () -> {\n\t\t\tint port = this.context.getEnvironment().getProperty(\"local.server.port\", Integer.class, 8080);\n\t\t\tString path = this.context.getEnvironment().getProperty(\"server.servlet.context-path\", \"\");\n\t\t\treturn new BaseUriDetails(port, path);\n\t\t});\n\t}\n\n\tprivate boolean isSslEnabled(ServletWebServerApplicationContext context) {\n\t\ttry {\n\t\t\tAbstractConfigurableWebServerFactory webServerFactory = context\n\t\t\t\t.getBean(AbstractConfigurableWebServerFactory.class);\n\t\t\treturn webServerFactory.getSsl() != null && webServerFactory.getSsl().isEnabled();\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerInitializedEvent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerInitializedEvent;\n\n/**\n * Event to be published after the {@link WebServer} is ready. Useful for obtaining the\n * local port of a running server.\n *\n * <p>\n * Normally it will have been started, but listeners are free to inspect the server and\n * stop and start it if they want to.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\n@SuppressWarnings(\"serial\")\npublic class ServletWebServerInitializedEvent extends WebServerInitializedEvent {\n\n\tprivate final ServletWebServerApplicationContext applicationContext;\n\n\tpublic ServletWebServerInitializedEvent(WebServer webServer,\n\t\t\tServletWebServerApplicationContext applicationContext) {\n\t\tsuper(webServer);\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t/**\n\t * Access the application context that the server was created in. Sometimes it is\n\t * prudent to check that this matches expectations (like being equal to the current\n\t * context) before acting on the server itself.\n\t * @return the applicationContext that the server was created from\n\t */\n\t@Override\n\tpublic ServletWebServerApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebApplicationContextServletContextAwareProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport jakarta.servlet.ServletConfig;\nimport jakarta.servlet.ServletContext;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.support.ServletContextAwareProcessor;\n\n/**\n * Variant of {@link ServletContextAwareProcessor} for use with a\n * {@link ConfigurableWebApplicationContext}. Can be used when registering the processor\n * can occur before the {@link ServletContext} or {@link ServletConfig} have been\n * initialized.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class WebApplicationContextServletContextAwareProcessor extends ServletContextAwareProcessor {\n\n\tprivate final ConfigurableWebApplicationContext webApplicationContext;\n\n\tpublic WebApplicationContextServletContextAwareProcessor(ConfigurableWebApplicationContext webApplicationContext) {\n\t\tAssert.notNull(webApplicationContext, \"'webApplicationContext' must not be null\");\n\t\tthis.webApplicationContext = webApplicationContext;\n\t}\n\n\t@Override\n\tprotected @Nullable ServletContext getServletContext() {\n\t\tServletContext servletContext = this.webApplicationContext.getServletContext();\n\t\treturn (servletContext != null) ? servletContext : super.getServletContext();\n\t}\n\n\t@Override\n\tprotected @Nullable ServletConfig getServletConfig() {\n\t\tServletConfig servletConfig = this.webApplicationContext.getServletConfig();\n\t\treturn (servletConfig != null) ? servletConfig : super.getServletConfig();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebFilterHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.Arrays;\nimport java.util.EnumSet;\nimport java.util.Map;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.annotation.WebFilter;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Handler for {@link WebFilter @WebFilter}-annotated classes.\n *\n * @author Andy Wilkinson\n */\nclass WebFilterHandler extends ServletComponentHandler {\n\n\tWebFilterHandler() {\n\t\tsuper(WebFilter.class);\n\t}\n\n\t@Override\n\tpublic void doHandle(Map<String, @Nullable Object> attributes, AnnotatedBeanDefinition beanDefinition,\n\t\t\tBeanDefinitionRegistry registry) {\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class);\n\t\tbuilder.addPropertyValue(\"asyncSupported\", attributes.get(\"asyncSupported\"));\n\t\tbuilder.addPropertyValue(\"dispatcherTypes\", extractDispatcherTypes(attributes));\n\t\tbuilder.addPropertyValue(\"filter\", beanDefinition);\n\t\tbuilder.addPropertyValue(\"initParameters\", extractInitParameters(attributes));\n\t\tString name = determineName(attributes, beanDefinition);\n\t\tbuilder.addPropertyValue(\"name\", name);\n\t\tbuilder.addPropertyValue(\"servletNames\", attributes.get(\"servletNames\"));\n\t\tbuilder.addPropertyValue(\"urlPatterns\", extractUrlPatterns(attributes));\n\t\tregistry.registerBeanDefinition(name, builder.getBeanDefinition());\n\t}\n\n\tprivate EnumSet<DispatcherType> extractDispatcherTypes(Map<String, @Nullable Object> attributes) {\n\t\tDispatcherType[] dispatcherTypes = (DispatcherType[]) attributes.get(\"dispatcherTypes\");\n\t\tAssert.state(dispatcherTypes != null, \"'dispatcherTypes' must not be null\");\n\t\tif (dispatcherTypes.length == 0) {\n\t\t\treturn EnumSet.noneOf(DispatcherType.class);\n\t\t}\n\t\tif (dispatcherTypes.length == 1) {\n\t\t\treturn EnumSet.of(dispatcherTypes[0]);\n\t\t}\n\t\treturn EnumSet.of(dispatcherTypes[0], Arrays.copyOfRange(dispatcherTypes, 1, dispatcherTypes.length));\n\t}\n\n\tprivate String determineName(Map<String, @Nullable Object> attributes, BeanDefinition beanDefinition) {\n\t\tString filterName = (String) attributes.get(\"filterName\");\n\t\treturn (StringUtils.hasText(filterName) ? filterName : getBeanClassName(beanDefinition));\n\t}\n\n\tprivate String getBeanClassName(BeanDefinition beanDefinition) {\n\t\tString name = beanDefinition.getBeanClassName();\n\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\treturn name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebListenerHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.Map;\n\nimport jakarta.servlet.annotation.WebListener;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistrar;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistry;\n\n/**\n * Handler for {@link WebListener @WebListener}-annotated classes.\n *\n * @author Andy Wilkinson\n */\nclass WebListenerHandler extends ServletComponentHandler {\n\n\tWebListenerHandler() {\n\t\tsuper(WebListener.class);\n\t}\n\n\t@Override\n\tprotected void doHandle(Map<String, @Nullable Object> attributes, AnnotatedBeanDefinition beanDefinition,\n\t\t\tBeanDefinitionRegistry registry) {\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder\n\t\t\t.rootBeanDefinition(ServletComponentWebListenerRegistrar.class);\n\t\tbuilder.addConstructorArgValue(beanDefinition.getBeanClassName());\n\t\tregistry.registerBeanDefinition(beanDefinition.getBeanClassName() + \"Registrar\", builder.getBeanDefinition());\n\t}\n\n\tstatic class ServletComponentWebListenerRegistrar implements WebListenerRegistrar {\n\n\t\tprivate final String listenerClassName;\n\n\t\tServletComponentWebListenerRegistrar(String listenerClassName) {\n\t\t\tthis.listenerClassName = listenerClassName;\n\t\t}\n\n\t\t@Override\n\t\tpublic void register(WebListenerRegistry registry) {\n\t\t\tregistry.addWebListeners(this.listenerClassName);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebServerStartStopLifecycle.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.context.SmartLifecycle;\n\n/**\n * {@link SmartLifecycle} to start and stop the {@link WebServer} in a\n * {@link ServletWebServerApplicationContext}.\n *\n * @author Andy Wilkinson\n */\nclass WebServerStartStopLifecycle implements SmartLifecycle {\n\n\tprivate final ServletWebServerApplicationContext applicationContext;\n\n\tprivate final WebServer webServer;\n\n\tprivate volatile boolean running;\n\n\tWebServerStartStopLifecycle(ServletWebServerApplicationContext applicationContext, WebServer webServer) {\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.webServer = webServer;\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tthis.webServer.start();\n\t\tthis.running = true;\n\t\tthis.applicationContext\n\t\t\t.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.running = false;\n\t\tthis.webServer.stop();\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn this.running;\n\t}\n\n\t@Override\n\tpublic int getPhase() {\n\t\treturn WebServerApplicationContext.START_STOP_LIFECYCLE_PHASE;\n\t}\n\n\t@Override\n\tpublic boolean isPauseable() {\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/WebServletHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.Map;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.annotation.MultipartConfig;\nimport jakarta.servlet.annotation.WebServlet;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Handler for {@link WebServlet @WebServlet}-annotated classes.\n *\n * @author Andy Wilkinson\n */\nclass WebServletHandler extends ServletComponentHandler {\n\n\tWebServletHandler() {\n\t\tsuper(WebServlet.class);\n\t}\n\n\t@Override\n\tpublic void doHandle(Map<String, @Nullable Object> attributes, AnnotatedBeanDefinition beanDefinition,\n\t\t\tBeanDefinitionRegistry registry) {\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServletRegistrationBean.class);\n\t\tbuilder.addPropertyValue(\"asyncSupported\", attributes.get(\"asyncSupported\"));\n\t\tbuilder.addPropertyValue(\"initParameters\", extractInitParameters(attributes));\n\t\tbuilder.addPropertyValue(\"loadOnStartup\", attributes.get(\"loadOnStartup\"));\n\t\tString name = determineName(attributes, beanDefinition);\n\t\tbuilder.addPropertyValue(\"name\", name);\n\t\tbuilder.addPropertyValue(\"servlet\", beanDefinition);\n\t\tbuilder.addPropertyValue(\"urlMappings\", extractUrlPatterns(attributes));\n\t\tbuilder.addPropertyValue(\"multipartConfig\", determineMultipartConfig(beanDefinition));\n\t\tregistry.registerBeanDefinition(name, builder.getBeanDefinition());\n\t}\n\n\tprivate String determineName(Map<String, @Nullable Object> attributes, BeanDefinition beanDefinition) {\n\t\tString name = (String) attributes.get(\"name\");\n\t\treturn StringUtils.hasText(name) ? name : getBeanClassName(beanDefinition);\n\t}\n\n\tprivate String getBeanClassName(BeanDefinition beanDefinition) {\n\t\tString name = beanDefinition.getBeanClassName();\n\t\tAssert.state(name != null, \"'name' must not be null\");\n\t\treturn name;\n\t}\n\n\tprivate @Nullable BeanDefinition determineMultipartConfig(AnnotatedBeanDefinition beanDefinition) {\n\t\tMap<String, @Nullable Object> attributes = beanDefinition.getMetadata()\n\t\t\t.getAnnotationAttributes(MultipartConfig.class.getName());\n\t\tif (attributes == null) {\n\t\t\treturn null;\n\t\t}\n\t\tBeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(MultipartConfigElement.class);\n\t\tbuilder.addConstructorArgValue(attributes.get(\"location\"));\n\t\tbuilder.addConstructorArgValue(attributes.get(\"maxFileSize\"));\n\t\tbuilder.addConstructorArgValue(attributes.get(\"maxRequestSize\"));\n\t\tbuilder.addConstructorArgValue(attributes.get(\"fileSizeThreshold\"));\n\t\treturn builder.getBeanDefinition();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/XmlServletWebServerApplicationContext.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.springframework.beans.factory.xml.XmlBeanDefinitionReader;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.web.context.support.XmlWebApplicationContext;\n\n/**\n * {@link ServletWebServerApplicationContext} which takes its configuration from XML\n * documents, understood by an\n * {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.\n * <p>\n * Note: In case of multiple config locations, later bean definitions will override ones\n * defined in earlier loaded files. This can be leveraged to deliberately override certain\n * bean definitions through an extra XML file.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see #setNamespace\n * @see #setConfigLocations\n * @see ServletWebServerApplicationContext\n * @see XmlWebApplicationContext\n */\npublic class XmlServletWebServerApplicationContext extends ServletWebServerApplicationContext {\n\n\tprivate final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);\n\n\t/**\n\t * Create a new {@link XmlServletWebServerApplicationContext} that needs to be\n\t * {@linkplain #load loaded} and then manually {@link #refresh refreshed}.\n\t */\n\tpublic XmlServletWebServerApplicationContext() {\n\t\tthis.reader.setEnvironment(getEnvironment());\n\t}\n\n\t/**\n\t * Create a new {@link XmlServletWebServerApplicationContext}, loading bean\n\t * definitions from the given resources and automatically refreshing the context.\n\t * @param resources the resources to load from\n\t */\n\tpublic XmlServletWebServerApplicationContext(Resource... resources) {\n\t\tload(resources);\n\t\trefresh();\n\t}\n\n\t/**\n\t * Create a new {@link XmlServletWebServerApplicationContext}, loading bean\n\t * definitions from the given resource locations and automatically refreshing the\n\t * context.\n\t * @param resourceLocations the resources to load from\n\t */\n\tpublic XmlServletWebServerApplicationContext(String... resourceLocations) {\n\t\tload(resourceLocations);\n\t\trefresh();\n\t}\n\n\t/**\n\t * Create a new {@link XmlServletWebServerApplicationContext}, loading bean\n\t * definitions from the given resource locations and automatically refreshing the\n\t * context.\n\t * @param relativeClass class whose package will be used as a prefix when loading each\n\t * specified resource name\n\t * @param resourceNames relatively-qualified names of resources to load\n\t */\n\tpublic XmlServletWebServerApplicationContext(Class<?> relativeClass, String... resourceNames) {\n\t\tload(relativeClass, resourceNames);\n\t\trefresh();\n\t}\n\n\t/**\n\t * Set whether to use XML validation. Default is {@code true}.\n\t * @param validating if validating the XML\n\t */\n\tpublic void setValidating(boolean validating) {\n\t\tthis.reader.setValidating(validating);\n\t}\n\n\t/**\n\t * {@inheritDoc}\n\t * <p>\n\t * Delegates the given environment to underlying {@link XmlBeanDefinitionReader}.\n\t * Should be called before any call to {@link #load}.\n\t */\n\t@Override\n\tpublic void setEnvironment(ConfigurableEnvironment environment) {\n\t\tsuper.setEnvironment(environment);\n\t\tthis.reader.setEnvironment(getEnvironment());\n\t}\n\n\t/**\n\t * Load bean definitions from the given XML resources.\n\t * @param resources one or more resources to load from\n\t */\n\tpublic final void load(Resource... resources) {\n\t\tthis.reader.loadBeanDefinitions(resources);\n\t}\n\n\t/**\n\t * Load bean definitions from the given XML resources.\n\t * @param resourceLocations one or more resource locations to load from\n\t */\n\tpublic final void load(String... resourceLocations) {\n\t\tthis.reader.loadBeanDefinitions(resourceLocations);\n\t}\n\n\t/**\n\t * Load bean definitions from the given XML resources.\n\t * @param relativeClass class whose package will be used as a prefix when loading each\n\t * specified resource name\n\t * @param resourceNames relatively-qualified names of resources to load\n\t */\n\tpublic final void load(Class<?> relativeClass, String... resourceNames) {\n\t\tResource[] resources = new Resource[resourceNames.length];\n\t\tfor (int i = 0; i < resourceNames.length; i++) {\n\t\t\tresources[i] = new ClassPathResource(resourceNames[i], relativeClass);\n\t\t}\n\t\tthis.reader.loadBeanDefinitions(resources);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Servlet web server based web integrations with Spring's\n * {@link org.springframework.web.context.WebApplicationContext WebApplicationContext}.\n */\n@NullMarked\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Servlet web server abstractions.\n */\n@NullMarked\npackage org.springframework.boot.web.server.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"server.connection-timeout\",\n      \"type\": \"java.time.Duration\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Each server behaves differently. Use server specific properties instead.\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.include-binding-errors\",\n      \"description\": \"When to include \\\"errors\\\" attribute.\",\n      \"defaultValue\": \"never\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.include-binding-errors\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.include-exception\",\n      \"description\": \"Include the \\\"exception\\\" attribute.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.include-exception\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.include-message\",\n      \"description\": \"When to include the \\\"message\\\" attribute.\",\n      \"defaultValue\": \"never\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.include-message\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.include-path\",\n      \"description\": \"When to include the \\\"path\\\" attribute.\",\n      \"defaultValue\": \"always\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.include-path\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.include-stacktrace\",\n      \"description\": \"When to include the \\\"trace\\\" attribute.\",\n      \"defaultValue\": \"never\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.include-stacktrace\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.path\",\n      \"description\": \"Path of the error controller\",\n      \"defaultValue\": \"/error\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.path\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.error.whitelabel.enabled\",\n      \"description\": \"Whether to enable the default error page displayed in browsers in case of a server error.\",\n      \"defaultValue\": true ,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.error.whitelabel.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.max-http-header-size\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"server.max-http-request-header-size\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.max-http-post-size\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Maximum size in bytes of the HTTP post content.\",\n      \"defaultValue\": 0,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Use dedicated property for each container.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.port\",\n      \"defaultValue\": 8080\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.domain\",\n      \"description\": \"Domain for the cookie.\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.http-only\",\n      \"description\": \"Whether to use \\\"HttpOnly\\\" cookies for the cookie.\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.max-age\",\n      \"description\": \"Maximum age of the cookie. If a duration suffix is not specified, seconds will be used. A positive value indicates when the cookie expires relative to the current time. A value of 0 means the cookie should expire immediately. A negative value means no \\\"Max-Age\\\".\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.name\",\n      \"description\": \"Name for the cookie.\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.partitioned\",\n      \"description\": \"Whether the generated cookie carries the Partitioned attribute.\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.path\",\n      \"description\": \"Path of the cookie.\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.same-site\",\n      \"description\": \"SameSite setting for the cookie.\"\n    },\n    {\n      \"name\": \"server.reactive.session.cookie.secure\",\n      \"description\": \"Whether to always mark the cookie as secure.\"\n    },\n    {\n      \"name\": \"server.servlet.encoding.charset\",\n      \"type\": \"java.nio.charset.Charset\",\n      \"description\": \"Charset of HTTP requests and responses. Added to the Content-Type header if not set explicitly.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.servlet.encoding.charset\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.servlet.encoding.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable http encoding support.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.servlet.encoding.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.servlet.encoding.force\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to force the encoding to the configured charset on HTTP requests and responses.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.servlet.encoding.force\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.servlet.encoding.force-request\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to force the encoding to the configured charset on HTTP requests. Defaults to true when force has not been specified.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.servlet.encoding.force-request\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.servlet.encoding.force-response\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to force the encoding to the configured charset on HTTP responses.\",\n      \"defaultValue\": false,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.servlet.encoding.force-response\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"server.servlet.jsp.class-name\",\n      \"description\": \"Class name of the servlet to use for JSPs. If registered is true and this class\\n\\t * is on the classpath then it will be registered.\",\n      \"defaultValue\": \"org.apache.jasper.servlet.JspServlet\"\n    },\n    {\n      \"name\": \"server.servlet.jsp.init-parameters\",\n      \"description\": \"Init parameters used to configure the JSP servlet.\"\n    },\n    {\n      \"name\": \"server.servlet.path\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Path of the main dispatcher servlet.\",\n      \"defaultValue\": \"/\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mvc.servlet.path\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"server.servlet.session.cookie.comment\",\n      \"description\": \"Comment for the cookie.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"server.ssl.protocol\",\n      \"description\": \"SSL protocol to use.\",\n      \"defaultValue\": \"TLS\"\n    },\n    {\n      \"name\": \"server.ssl.server-name-bundles\",\n      \"description\": \"Mapping of host names to SSL bundles for SNI configuration.\"\n    },\n    {\n      \"name\": \"server.ssl.trust-certificate\",\n      \"description\": \"Path to a PEM-encoded SSL certificate authority file.\"\n    },\n    {\n      \"name\": \"server.ssl.trust-certificate-private-key\",\n      \"description\": \"Path to a PEM-encoded private key file for the SSL certificate authority.\"\n    },\n    {\n      \"name\": \"server.ssl.trust-store\",\n      \"description\": \"Trust store that holds SSL certificates.\"\n    },\n    {\n      \"name\": \"server.ssl.trust-store-password\",\n      \"description\": \"Password used to access the trust store.\"\n    },\n    {\n      \"name\": \"server.ssl.trust-store-provider\",\n      \"description\": \"Provider for the trust store.\"\n    },\n    {\n      \"name\": \"server.ssl.trust-store-type\",\n      \"description\": \"Type of the trust store.\"\n    },\n    {\n      \"name\": \"server.use-forward-headers\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Replaced to support additional strategies.\",\n        \"replacement\": \"server.forward-headers-strategy\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}"
  },
  {
    "path": "module/spring-boot-web-server/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.web.server.MimeMappings$MimeMappingsRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.server.servlet.jsp.init-parameters.development=true\ndefaults.server.servlet.session.persistent=true\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/resources/META-INF/spring.factories",
    "content": "# Application Context Factories\norg.springframework.boot.ApplicationContextFactory=\\\norg.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContextFactory,\\\norg.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContextFactory\n\n# Application Context Initializers\norg.springframework.context.ApplicationContextInitializer=\\\norg.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer\n\n# Failure Analyzers\norg.springframework.boot.diagnostics.FailureAnalyzer=\\\norg.springframework.boot.web.server.PortInUseFailureAnalyzer,\\\norg.springframework.boot.web.server.context.MissingWebServerFactoryBeanFailureAnalyzer\n\n# HTTP Server LocalTestWebServer Providers\norg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\norg.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContextLocalTestWebServerProvider,\\\norg.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContextLocalTestWebServerProvider\n\n# Spring Test Context Customizer Factories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.web.server.context.SpringBootTestRandomPortContextCustomizerFactory\n\n"
  },
  {
    "path": "module/spring-boot-web-server/src/main/resources/org/springframework/boot/web/server/mime-mappings.properties",
    "content": "# Copyright 2012-2024 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n123=application/vnd.lotus-1-2-3\n3dml=text/vnd.in3d.3dml\n3ds=image/x-3ds\n3g2=video/3gpp2\n3gp=video/3gpp\n7z=application/x-7z-compressed\naab=application/x-authorware-bin\naac=audio/x-aac\naam=application/x-authorware-map\naas=application/x-authorware-seg\nabs=audio/x-mpeg\nabw=application/x-abiword\nac=application/pkix-attr-cert\nacc=application/vnd.americandynamics.acc\nace=application/x-ace-compressed\nacu=application/vnd.acucobol\nacutc=application/vnd.acucorp\nadp=audio/adpcm\naep=application/vnd.audiograph\nafm=application/x-font-type1\nafp=application/vnd.ibm.modcap\nahead=application/vnd.ahead.space\nai=application/postscript\naif=audio/x-aiff\naifc=audio/x-aiff\naiff=audio/x-aiff\naim=application/x-aim\nair=application/vnd.adobe.air-application-installer-package+zip\nait=application/vnd.dvb.ait\nami=application/vnd.amiga.ami\nanx=application/annodex\napk=application/vnd.android.package-archive\nappcache=text/cache-manifest\napplication=application/x-ms-application\napr=application/vnd.lotus-approach\narc=application/x-freearc\nart=image/x-jg\nasc=application/pgp-signature\nasf=video/x-ms-asf\nasm=text/x-asm\naso=application/vnd.accpac.simply.aso\nasx=video/x-ms-asf\natc=application/vnd.acucorp\natom=application/atom+xml\natomcat=application/atomcat+xml\natomsvc=application/atomsvc+xml\natx=application/vnd.antix.game-component\nau=audio/basic\navi=video/x-msvideo\navif=image/avif\navx=video/x-rad-screenplay\naw=application/applixware\naxa=audio/annodex\naxv=video/annodex\nazf=application/vnd.airzip.filesecure.azf\nazs=application/vnd.airzip.filesecure.azs\nazw=application/vnd.amazon.ebook\nbat=application/x-msdownload\nbcpio=application/x-bcpio\nbdf=application/x-font-bdf\nbdm=application/vnd.syncml.dm+wbxml\nbed=application/vnd.realvnc.bed\nbh2=application/vnd.fujitsu.oasysprs\nbin=application/octet-stream\nblb=application/x-blorb\nblorb=application/x-blorb\nbmi=application/vnd.bmi\nbmp=image/bmp\nbody=text/html\nbook=application/vnd.framemaker\nbox=application/vnd.previewsystems.box\nboz=application/x-bzip2\nbpk=application/octet-stream\nbtif=image/prs.btif\nbz=application/x-bzip\nbz2=application/x-bzip2\nc=text/x-c\nc11amc=application/vnd.cluetrust.cartomobile-config\nc11amz=application/vnd.cluetrust.cartomobile-config-pkg\nc4d=application/vnd.clonk.c4group\nc4f=application/vnd.clonk.c4group\nc4g=application/vnd.clonk.c4group\nc4p=application/vnd.clonk.c4group\nc4u=application/vnd.clonk.c4group\ncab=application/vnd.ms-cab-compressed\ncaf=audio/x-caf\ncap=application/vnd.tcpdump.pcap\ncar=application/vnd.curl.car\ncat=application/vnd.ms-pki.seccat\ncb7=application/x-cbr\ncba=application/x-cbr\ncbr=application/x-cbr\ncbt=application/x-cbr\ncbz=application/x-cbr\ncc=text/x-c\ncct=application/x-director\nccxml=application/ccxml+xml\ncdbcmsg=application/vnd.contact.cmsg\ncdf=application/x-cdf\ncdkey=application/vnd.mediastation.cdkey\ncdmia=application/cdmi-capability\ncdmic=application/cdmi-container\ncdmid=application/cdmi-domain\ncdmio=application/cdmi-object\ncdmiq=application/cdmi-queue\ncdx=chemical/x-cdx\ncdxml=application/vnd.chemdraw+xml\ncdy=application/vnd.cinderella\ncer=application/pkix-cert\ncfs=application/x-cfs-compressed\ncgm=image/cgm\nchat=application/x-chat\nchm=application/vnd.ms-htmlhelp\nchrt=application/vnd.kde.kchart\ncif=chemical/x-cif\ncii=application/vnd.anser-web-certificate-issue-initiation\ncil=application/vnd.ms-artgalry\ncla=application/vnd.claymore\nclass=application/java\nclkk=application/vnd.crick.clicker.keyboard\nclkp=application/vnd.crick.clicker.palette\nclkt=application/vnd.crick.clicker.template\nclkw=application/vnd.crick.clicker.wordbank\nclkx=application/vnd.crick.clicker\nclp=application/x-msclip\ncmc=application/vnd.cosmocaller\ncmdf=chemical/x-cmdf\ncml=chemical/x-cml\ncmp=application/vnd.yellowriver-custom-menu\ncmx=image/x-cmx\ncod=application/vnd.rim.cod\ncom=application/x-msdownload\nconf=text/plain\ncpio=application/x-cpio\ncpp=text/x-c\ncpt=application/mac-compactpro\ncrd=application/x-mscardfile\ncrl=application/pkix-crl\ncrt=application/x-x509-ca-cert\ncryptonote=application/vnd.rig.cryptonote\ncsh=application/x-csh\ncsml=chemical/x-csml\ncsp=application/vnd.commonspace\ncss=text/css\ncst=application/x-director\ncsv=text/csv\ncu=application/cu-seeme\ncurl=text/vnd.curl\ncww=application/prs.cww\ncxt=application/x-director\ncxx=text/x-c\ndae=model/vnd.collada+xml\ndaf=application/vnd.mobius.daf\ndart=application/vnd.dart\ndataless=application/vnd.fdsn.seed\ndavmount=application/davmount+xml\ndbk=application/docbook+xml\ndcr=application/x-director\ndcurl=text/vnd.curl.dcurl\ndd2=application/vnd.oma.dd2+xml\nddd=application/vnd.fujixerox.ddd\ndeb=application/x-debian-package\ndef=text/plain\ndeploy=application/octet-stream\nder=application/x-x509-ca-cert\ndfac=application/vnd.dreamfactory\ndgc=application/x-dgc-compressed\ndib=image/bmp\ndic=text/x-c\ndir=application/x-director\ndis=application/vnd.mobius.dis\ndist=application/octet-stream\ndistz=application/octet-stream\ndjv=image/vnd.djvu\ndjvu=image/vnd.djvu\ndll=application/x-msdownload\ndmg=application/x-apple-diskimage\ndmp=application/vnd.tcpdump.pcap\ndms=application/octet-stream\ndna=application/vnd.dna\ndoc=application/msword\ndocm=application/vnd.ms-word.document.macroenabled.12\ndocx=application/vnd.openxmlformats-officedocument.wordprocessingml.document\ndot=application/msword\ndotm=application/vnd.ms-word.template.macroenabled.12\ndotx=application/vnd.openxmlformats-officedocument.wordprocessingml.template\ndp=application/vnd.osgi.dp\ndpg=application/vnd.dpgraph\ndra=audio/vnd.dra\ndsc=text/prs.lines.tag\ndssc=application/dssc+der\ndtb=application/x-dtbook+xml\ndtd=application/xml-dtd\ndts=audio/vnd.dts\ndtshd=audio/vnd.dts.hd\ndump=application/octet-stream\ndv=video/x-dv\ndvb=video/vnd.dvb.file\ndvi=application/x-dvi\ndwf=model/vnd.dwf\ndwg=image/vnd.dwg\ndxf=image/vnd.dxf\ndxp=application/vnd.spotfire.dxp\ndxr=application/x-director\necelp4800=audio/vnd.nuera.ecelp4800\necelp7470=audio/vnd.nuera.ecelp7470\necelp9600=audio/vnd.nuera.ecelp9600\necma=application/ecmascript\nedm=application/vnd.novadigm.edm\nedx=application/vnd.novadigm.edx\nefif=application/vnd.picsel\nei6=application/vnd.pg.osasli\nelc=application/octet-stream\nemf=application/x-msmetafile\neml=message/rfc822\nemma=application/emma+xml\nemz=application/x-msmetafile\neol=audio/vnd.digital-winds\neot=application/vnd.ms-fontobject\neps=application/postscript\nepub=application/epub+zip\nes3=application/vnd.eszigno3+xml\nesa=application/vnd.osgi.subsystem\nesf=application/vnd.epson.esf\net3=application/vnd.eszigno3+xml\netx=text/x-setext\neva=application/x-eva\nevy=application/x-envoy\nexe=application/octet-stream\nexi=application/exi\next=application/vnd.novadigm.ext\nez=application/andrew-inset\nez2=application/vnd.ezpix-album\nez3=application/vnd.ezpix-package\nf=text/x-fortran\nf4v=video/x-f4v\nf77=text/x-fortran\nf90=text/x-fortran\nfbs=image/vnd.fastbidsheet\nfcdt=application/vnd.adobe.formscentral.fcdt\nfcs=application/vnd.isac.fcs\nfdf=application/vnd.fdf\nfe_launch=application/vnd.denovo.fcselayout-link\nfg5=application/vnd.fujitsu.oasysgp\nfgd=application/x-director\nfh=image/x-freehand\nfh4=image/x-freehand\nfh5=image/x-freehand\nfh7=image/x-freehand\nfhc=image/x-freehand\nfig=application/x-xfig\nflac=audio/flac\nfli=video/x-fli\nflo=application/vnd.micrografx.flo\nflv=video/x-flv\nflw=application/vnd.kde.kivio\nflx=text/vnd.fmi.flexstor\nfly=text/vnd.fly\nfm=application/vnd.framemaker\nfnc=application/vnd.frogans.fnc\nfor=text/x-fortran\nfpx=image/vnd.fpx\nframe=application/vnd.framemaker\nfsc=application/vnd.fsc.weblaunch\nfst=image/vnd.fst\nftc=application/vnd.fluxtime.clip\nfti=application/vnd.anser-web-funds-transfer-initiation\nfvt=video/vnd.fvt\nfxp=application/vnd.adobe.fxp\nfxpl=application/vnd.adobe.fxp\nfzs=application/vnd.fuzzysheet\ng2w=application/vnd.geoplan\ng3=image/g3fax\ng3w=application/vnd.geospace\ngac=application/vnd.groove-account\ngam=application/x-tads\ngbr=application/rpki-ghostbusters\ngca=application/x-gca-compressed\ngdl=model/vnd.gdl\ngeo=application/vnd.dynageo\ngex=application/vnd.geometry-explorer\nggb=application/vnd.geogebra.file\nggs=application/vnd.geogebra.slides\nggt=application/vnd.geogebra.tool\nghf=application/vnd.groove-help\ngif=image/gif\ngim=application/vnd.groove-identity-message\ngml=application/gml+xml\ngmx=application/vnd.gmx\ngnumeric=application/x-gnumeric\ngph=application/vnd.flographit\ngpx=application/gpx+xml\ngqf=application/vnd.grafeq\ngqs=application/vnd.grafeq\ngram=application/srgs\ngramps=application/x-gramps-xml\ngre=application/vnd.geometry-explorer\ngrv=application/vnd.groove-injector\ngrxml=application/srgs+xml\ngsf=application/x-font-ghostscript\ngtar=application/x-gtar\ngtm=application/vnd.groove-tool-message\ngtw=model/vnd.gtw\ngv=text/vnd.graphviz\ngxf=application/gxf\ngxt=application/vnd.geonext\ngz=application/x-gzip\nh=text/x-c\nh261=video/h261\nh263=video/h263\nh264=video/h264\nhal=application/vnd.hal+xml\nhbci=application/vnd.hbci\nhdf=application/x-hdf\nhh=text/x-c\nhlp=application/winhlp\nhpgl=application/vnd.hp-hpgl\nhpid=application/vnd.hp-hpid\nhps=application/vnd.hp-hps\nhqx=application/mac-binhex40\nhtc=text/x-component\nhtke=application/vnd.kenameaapp\nhtm=text/html\nhtml=text/html\nhvd=application/vnd.yamaha.hv-dic\nhvp=application/vnd.yamaha.hv-voice\nhvs=application/vnd.yamaha.hv-script\ni2g=application/vnd.intergeo\nicc=application/vnd.iccprofile\nice=x-conference/x-cooltalk\nicm=application/vnd.iccprofile\nico=image/x-icon\nics=text/calendar\nief=image/ief\nifb=text/calendar\nifm=application/vnd.shana.informed.formdata\niges=model/iges\nigl=application/vnd.igloader\nigm=application/vnd.insors.igm\nigs=model/iges\nigx=application/vnd.micrografx.igx\niif=application/vnd.shana.informed.interchange\nimp=application/vnd.accpac.simply.imp\nims=application/vnd.ms-ims\nin=text/plain\nink=application/inkml+xml\ninkml=application/inkml+xml\ninstall=application/x-install-instructions\niota=application/vnd.astraea-software.iota\nipfix=application/ipfix\nipk=application/vnd.shana.informed.package\nirm=application/vnd.ibm.rights-management\nirp=application/vnd.irepository.package+xml\niso=application/x-iso9660-image\nitp=application/vnd.shana.informed.formtemplate\nivp=application/vnd.immervision-ivp\nivu=application/vnd.immervision-ivu\njad=text/vnd.sun.j2me.app-descriptor\njam=application/vnd.jam\njar=application/java-archive\njava=text/x-java-source\njisp=application/vnd.jisp\njlt=application/vnd.hp-jlyt\njnlp=application/x-java-jnlp-file\njoda=application/vnd.joost.joda-archive\njpe=image/jpeg\njpeg=image/jpeg\njpg=image/jpeg\njpgm=video/jpm\njpgv=video/jpeg\njpm=video/jpm\njs=text/javascript\njsf=text/plain\njson=application/json\njsonml=application/jsonml+json\njspf=text/plain\njxl=image/jxl\nkar=audio/midi\nkarbon=application/vnd.kde.karbon\nkfo=application/vnd.kde.kformula\nkia=application/vnd.kidspiration\nkml=application/vnd.google-earth.kml+xml\nkmz=application/vnd.google-earth.kmz\nkne=application/vnd.kinar\nknp=application/vnd.kinar\nkon=application/vnd.kde.kontour\nkpr=application/vnd.kde.kpresenter\nkpt=application/vnd.kde.kpresenter\nkpxx=application/vnd.ds-keypoint\nksp=application/vnd.kde.kspread\nktr=application/vnd.kahootz\nktx=image/ktx\nktz=application/vnd.kahootz\nkwd=application/vnd.kde.kword\nkwt=application/vnd.kde.kword\nlasxml=application/vnd.las.las+xml\nlatex=application/x-latex\nlbd=application/vnd.llamagraphics.life-balance.desktop\nlbe=application/vnd.llamagraphics.life-balance.exchange+xml\nles=application/vnd.hhe.lesson-player\nlha=application/x-lzh-compressed\nlink66=application/vnd.route66.link66+xml\nlist=text/plain\nlist3820=application/vnd.ibm.modcap\nlistafp=application/vnd.ibm.modcap\nlnk=application/x-ms-shortcut\nlog=text/plain\nlostxml=application/lost+xml\nlrf=application/octet-stream\nlrm=application/vnd.ms-lrm\nltf=application/vnd.frogans.ltf\nlvp=audio/vnd.lucent.voice\nlwp=application/vnd.lotus-wordpro\nlzh=application/x-lzh-compressed\nm13=application/x-msmediaview\nm14=application/x-msmediaview\nm1v=video/mpeg\nm21=application/mp21\nm2a=audio/mpeg\nm2t=video/mp2t\nm2ts=video/mp2t\nm2v=video/mpeg\nm3a=audio/mpeg\nm3u=audio/x-mpegurl\nm3u8=application/vnd.apple.mpegurl\nm4a=audio/mp4\nm4b=audio/mp4\nm4r=audio/mp4\nm4u=video/vnd.mpegurl\nm4v=video/mp4\nma=application/mathematica\nmac=image/x-macpaint\nmads=application/mads+xml\nmag=application/vnd.ecowin.chart\nmaker=application/vnd.framemaker\nman=text/troff\nmar=application/octet-stream\nmathml=application/mathml+xml\nmb=application/mathematica\nmbk=application/vnd.mobius.mbk\nmbox=application/mbox\nmc1=application/vnd.medcalcdata\nmcd=application/vnd.mcd\nmcurl=text/vnd.curl.mcurl\nmdb=application/x-msaccess\nmdi=image/vnd.ms-modi\nme=text/troff\nmesh=model/mesh\nmeta4=application/metalink4+xml\nmetalink=application/metalink+xml\nmets=application/mets+xml\nmfm=application/vnd.mfmp\nmft=application/rpki-manifest\nmgp=application/vnd.osgeo.mapguide.package\nmgz=application/vnd.proteus.magazine\nmid=audio/midi\nmidi=audio/midi\nmie=application/x-mie\nmif=application/x-mif\nmime=message/rfc822\nmj2=video/mj2\nmjp2=video/mj2\nmjs=text/javascript\nmk3d=video/x-matroska\nmka=audio/x-matroska\nmks=video/x-matroska\nmkv=video/x-matroska\nmlp=application/vnd.dolby.mlp\nmmd=application/vnd.chipnuts.karaoke-mmd\nmmf=application/vnd.smaf\nmmr=image/vnd.fujixerox.edmics-mmr\nmng=video/x-mng\nmny=application/x-msmoney\nmobi=application/x-mobipocket-ebook\nmods=application/mods+xml\nmov=video/quicktime\nmovie=video/x-sgi-movie\nmp1=audio/mpeg\nmp2=audio/mpeg\nmp21=application/mp21\nmp2a=audio/mpeg\nmp3=audio/mpeg\nmp4=video/mp4\nmp4a=audio/mp4\nmp4s=application/mp4\nmp4v=video/mp4\nmpa=audio/mpeg\nmpc=application/vnd.mophun.certificate\nmpe=video/mpeg\nmpeg=video/mpeg\nmpega=audio/x-mpeg\nmpg=video/mpeg\nmpg4=video/mp4\nmpga=audio/mpeg\nmpkg=application/vnd.apple.installer+xml\nmpm=application/vnd.blueice.multipass\nmpn=application/vnd.mophun.application\nmpp=application/vnd.ms-project\nmpt=application/vnd.ms-project\nmpv2=video/mpeg2\nmpy=application/vnd.ibm.minipay\nmqy=application/vnd.mobius.mqy\nmrc=application/marc\nmrcx=application/marcxml+xml\nms=text/troff\nmscml=application/mediaservercontrol+xml\nmseed=application/vnd.fdsn.mseed\nmseq=application/vnd.mseq\nmsf=application/vnd.epson.msf\nmsh=model/mesh\nmsi=application/x-msdownload\nmsl=application/vnd.mobius.msl\nmsty=application/vnd.muvee.style\nmts=video/mp2t\nmus=application/vnd.musician\nmusicxml=application/vnd.recordare.musicxml+xml\nmvb=application/x-msmediaview\nmwf=application/vnd.mfer\nmxf=application/mxf\nmxl=application/vnd.recordare.musicxml\nmxml=application/xv+xml\nmxs=application/vnd.triscape.mxs\nmxu=video/vnd.mpegurl\nn-gage=application/vnd.nokia.n-gage.symbian.install\nn3=text/n3\nnb=application/mathematica\nnbp=application/vnd.wolfram.player\nnc=application/x-netcdf\nncx=application/x-dtbncx+xml\nnfo=text/x-nfo\nngdat=application/vnd.nokia.n-gage.data\nnitf=application/vnd.nitf\nnlu=application/vnd.neurolanguage.nlu\nnml=application/vnd.enliven\nnnd=application/vnd.noblenet-directory\nnns=application/vnd.noblenet-sealer\nnnw=application/vnd.noblenet-web\nnpx=image/vnd.net-fpx\nnsc=application/x-conference\nnsf=application/vnd.lotus-notes\nntf=application/vnd.nitf\nnzb=application/x-nzb\noa2=application/vnd.fujitsu.oasys2\noa3=application/vnd.fujitsu.oasys3\noas=application/vnd.fujitsu.oasys\nobd=application/x-msbinder\nobj=application/x-tgif\noda=application/oda\nodb=application/vnd.oasis.opendocument.database\nodc=application/vnd.oasis.opendocument.chart\nodf=application/vnd.oasis.opendocument.formula\nodft=application/vnd.oasis.opendocument.formula-template\nodg=application/vnd.oasis.opendocument.graphics\nodi=application/vnd.oasis.opendocument.image\nodm=application/vnd.oasis.opendocument.text-master\nodp=application/vnd.oasis.opendocument.presentation\nods=application/vnd.oasis.opendocument.spreadsheet\nodt=application/vnd.oasis.opendocument.text\noga=audio/ogg\nogg=audio/ogg\nogv=video/ogg\nogx=application/ogg\nomdoc=application/omdoc+xml\nonepkg=application/onenote\nonetmp=application/onenote\nonetoc=application/onenote\nonetoc2=application/onenote\nopf=application/oebps-package+xml\nopml=text/x-opml\noprc=application/vnd.palm\nopus=audio/ogg\norg=application/vnd.lotus-organizer\nosf=application/vnd.yamaha.openscoreformat\nosfpvg=application/vnd.yamaha.openscoreformat.osfpvg+xml\notc=application/vnd.oasis.opendocument.chart-template\notf=font/otf\notg=application/vnd.oasis.opendocument.graphics-template\noth=application/vnd.oasis.opendocument.text-web\noti=application/vnd.oasis.opendocument.image-template\notp=application/vnd.oasis.opendocument.presentation-template\nots=application/vnd.oasis.opendocument.spreadsheet-template\nott=application/vnd.oasis.opendocument.text-template\noxps=application/oxps\noxt=application/vnd.openofficeorg.extension\np=text/x-pascal\np10=application/pkcs10\np12=application/x-pkcs12\np7b=application/x-pkcs7-certificates\np7c=application/pkcs7-mime\np7m=application/pkcs7-mime\np7r=application/x-pkcs7-certreqresp\np7s=application/pkcs7-signature\np8=application/pkcs8\npas=text/x-pascal\npaw=application/vnd.pawaafile\npbd=application/vnd.powerbuilder6\npbm=image/x-portable-bitmap\npcap=application/vnd.tcpdump.pcap\npcf=application/x-font-pcf\npcl=application/vnd.hp-pcl\npclxl=application/vnd.hp-pclxl\npct=image/pict\npcurl=application/vnd.curl.pcurl\npcx=image/x-pcx\npdb=application/vnd.palm\npdf=application/pdf\npfa=application/x-font-type1\npfb=application/x-font-type1\npfm=application/x-font-type1\npfr=application/font-tdpfr\npfx=application/x-pkcs12\npgm=image/x-portable-graymap\npgn=application/x-chess-pgn\npgp=application/pgp-encrypted\npic=image/pict\npict=image/pict\npkg=application/octet-stream\npki=application/pkixcmp\npkipath=application/pkix-pkipath\nplb=application/vnd.3gpp.pic-bw-large\nplc=application/vnd.mobius.plc\nplf=application/vnd.pocketlearn\npls=audio/x-scpls\npml=application/vnd.ctc-posml\npng=image/png\npnm=image/x-portable-anymap\npnt=image/x-macpaint\nportpkg=application/vnd.macports.portpkg\npot=application/vnd.ms-powerpoint\npotm=application/vnd.ms-powerpoint.template.macroenabled.12\npotx=application/vnd.openxmlformats-officedocument.presentationml.template\nppam=application/vnd.ms-powerpoint.addin.macroenabled.12\nppd=application/vnd.cups-ppd\nppm=image/x-portable-pixmap\npps=application/vnd.ms-powerpoint\nppsm=application/vnd.ms-powerpoint.slideshow.macroenabled.12\nppsx=application/vnd.openxmlformats-officedocument.presentationml.slideshow\nppt=application/vnd.ms-powerpoint\npptm=application/vnd.ms-powerpoint.presentation.macroenabled.12\npptx=application/vnd.openxmlformats-officedocument.presentationml.presentation\npqa=application/vnd.palm\nprc=application/x-mobipocket-ebook\npre=application/vnd.lotus-freelance\nprf=application/pics-rules\nps=application/postscript\npsb=application/vnd.3gpp.pic-bw-small\npsd=image/vnd.adobe.photoshop\npsf=application/x-font-linux-psf\npskcxml=application/pskc+xml\nptid=application/vnd.pvi.ptid1\npub=application/x-mspublisher\npvb=application/vnd.3gpp.pic-bw-var\npwn=application/vnd.3m.post-it-notes\npya=audio/vnd.ms-playready.media.pya\npyv=video/vnd.ms-playready.media.pyv\nqam=application/vnd.epson.quickanime\nqbo=application/vnd.intu.qbo\nqfx=application/vnd.intu.qfx\nqps=application/vnd.publishare-delta-tree\nqt=video/quicktime\nqti=image/x-quicktime\nqtif=image/x-quicktime\nqwd=application/vnd.quark.quarkxpress\nqwt=application/vnd.quark.quarkxpress\nqxb=application/vnd.quark.quarkxpress\nqxd=application/vnd.quark.quarkxpress\nqxl=application/vnd.quark.quarkxpress\nqxt=application/vnd.quark.quarkxpress\nra=audio/x-pn-realaudio\nram=audio/x-pn-realaudio\nrar=application/x-rar-compressed\nras=image/x-cmu-raster\nrcprofile=application/vnd.ipunplugged.rcprofile\nrdf=application/rdf+xml\nrdz=application/vnd.data-vision.rdz\nrep=application/vnd.businessobjects\nres=application/x-dtbresource+xml\nrgb=image/x-rgb\nrif=application/reginfo+xml\nrip=audio/vnd.rip\nris=application/x-research-info-systems\nrl=application/resource-lists+xml\nrlc=image/vnd.fujixerox.edmics-rlc\nrld=application/resource-lists-diff+xml\nrm=application/vnd.rn-realmedia\nrmi=audio/midi\nrmp=audio/x-pn-realaudio-plugin\nrms=application/vnd.jcp.javame.midlet-rms\nrmvb=application/vnd.rn-realmedia-vbr\nrnc=application/relax-ng-compact-syntax\nroa=application/rpki-roa\nroff=text/troff\nrp9=application/vnd.cloanto.rp9\nrpss=application/vnd.nokia.radio-presets\nrpst=application/vnd.nokia.radio-preset\nrq=application/sparql-query\nrs=application/rls-services+xml\nrsd=application/rsd+xml\nrss=application/rss+xml\nrtf=application/rtf\nrtx=text/richtext\ns=text/x-asm\ns3m=audio/s3m\nsaf=application/vnd.yamaha.smaf-audio\nsbml=application/sbml+xml\nsc=application/vnd.ibm.secure-container\nscd=application/x-msschedule\nscm=application/vnd.lotus-screencam\nscq=application/scvp-cv-request\nscs=application/scvp-cv-response\nscurl=text/vnd.curl.scurl\nsda=application/vnd.stardivision.draw\nsdc=application/vnd.stardivision.calc\nsdd=application/vnd.stardivision.impress\nsdkd=application/vnd.solent.sdkm+xml\nsdkm=application/vnd.solent.sdkm+xml\nsdp=application/sdp\nsdw=application/vnd.stardivision.writer\nsee=application/vnd.seemail\nseed=application/vnd.fdsn.seed\nsema=application/vnd.sema\nsemd=application/vnd.semd\nsemf=application/vnd.semf\nser=application/java-serialized-object\nsetpay=application/set-payment-initiation\nsetreg=application/set-registration-initiation\nsfd-hdstx=application/vnd.hydrostatix.sof-data\nsfs=application/vnd.spotfire.sfs\nsfv=text/x-sfv\nsgi=image/sgi\nsgl=application/vnd.stardivision.writer-global\nsgm=text/sgml\nsgml=text/sgml\nsh=application/x-sh\nshar=application/x-shar\nshf=application/shf+xml\nsid=image/x-mrsid-image\nsig=application/pgp-signature\nsil=audio/silk\nsilo=model/mesh\nsis=application/vnd.symbian.install\nsisx=application/vnd.symbian.install\nsit=application/x-stuffit\nsitx=application/x-stuffitx\nskd=application/vnd.koan\nskm=application/vnd.koan\nskp=application/vnd.koan\nskt=application/vnd.koan\nsldm=application/vnd.ms-powerpoint.slide.macroenabled.12\nsldx=application/vnd.openxmlformats-officedocument.presentationml.slide\nslt=application/vnd.epson.salt\nsm=application/vnd.stepmania.stepchart\nsmf=application/vnd.stardivision.math\nsmi=application/smil+xml\nsmil=application/smil+xml\nsmv=video/x-smv\nsmzip=application/vnd.stepmania.package\nsnd=audio/basic\nsnf=application/x-font-snf\nso=application/octet-stream\nspc=application/x-pkcs7-certificates\nspf=application/vnd.yamaha.smaf-phrase\nspl=application/x-futuresplash\nspot=text/vnd.in3d.spot\nspp=application/scvp-vp-response\nspq=application/scvp-vp-request\nspx=audio/ogg\nsql=application/x-sql\nsqlite=application/vnd.sqlite3\nsqlite3=application/vnd.sqlite3\nsrc=application/x-wais-source\nsrt=application/x-subrip\nsru=application/sru+xml\nsrx=application/sparql-results+xml\nssdl=application/ssdl+xml\nsse=application/vnd.kodak-descriptor\nssf=application/vnd.epson.ssf\nssml=application/ssml+xml\nst=application/vnd.sailingtracker.track\nstc=application/vnd.sun.xml.calc.template\nstd=application/vnd.sun.xml.draw.template\nstf=application/vnd.wt.stf\nsti=application/vnd.sun.xml.impress.template\nstk=application/hyperstudio\nstl=application/vnd.ms-pki.stl\nstr=application/vnd.pg.format\nstw=application/vnd.sun.xml.writer.template\nsub=text/vnd.dvb.subtitle\nsus=application/vnd.sus-calendar\nsusp=application/vnd.sus-calendar\nsv4cpio=application/x-sv4cpio\nsv4crc=application/x-sv4crc\nsvc=application/vnd.dvb.service\nsvd=application/vnd.svd\nsvg=image/svg+xml\nsvgz=image/svg+xml\nswa=application/x-director\nswf=application/x-shockwave-flash\nswi=application/vnd.aristanetworks.swi\nsxc=application/vnd.sun.xml.calc\nsxd=application/vnd.sun.xml.draw\nsxg=application/vnd.sun.xml.writer.global\nsxi=application/vnd.sun.xml.impress\nsxm=application/vnd.sun.xml.math\nsxw=application/vnd.sun.xml.writer\nt=text/troff\nt3=application/x-t3vm-image\ntaglet=application/vnd.mynfc\ntao=application/vnd.tao.intent-module-archive\ntar=application/x-tar\ntcap=application/vnd.3gpp2.tcap\ntcl=application/x-tcl\nteacher=application/vnd.smart.teacher\ntei=application/tei+xml\nteicorpus=application/tei+xml\ntex=application/x-tex\ntexi=application/x-texinfo\ntexinfo=application/x-texinfo\ntext=text/plain\ntfi=application/thraud+xml\ntfm=application/x-tex-tfm\ntga=image/x-tga\nthmx=application/vnd.ms-officetheme\ntif=image/tiff\ntiff=image/tiff\ntmo=application/vnd.tmobile-livetv\ntorrent=application/x-bittorrent\ntpl=application/vnd.groove-tool-template\ntpt=application/vnd.trid.tpt\ntr=text/troff\ntra=application/vnd.trueapp\ntrm=application/x-msterminal\nts=video/mp2t\ntsd=application/timestamped-data\ntsv=text/tab-separated-values\nttc=font/collection\nttf=font/ttf\nttl=text/turtle\ntwd=application/vnd.simtech-mindmapper\ntwds=application/vnd.simtech-mindmapper\ntxd=application/vnd.genomatix.tuxedo\ntxf=application/vnd.mobius.txf\ntxt=text/plain\nu32=application/x-authorware-bin\nudeb=application/x-debian-package\nufd=application/vnd.ufdl\nufdl=application/vnd.ufdl\nulw=audio/basic\nulx=application/x-glulx\numj=application/vnd.umajin\nunityweb=application/vnd.unity\nuoml=application/vnd.uoml+xml\nuri=text/uri-list\nuris=text/uri-list\nurls=text/uri-list\nustar=application/x-ustar\nutz=application/vnd.uiq.theme\nuu=text/x-uuencode\nuva=audio/vnd.dece.audio\nuvd=application/vnd.dece.data\nuvf=application/vnd.dece.data\nuvg=image/vnd.dece.graphic\nuvh=video/vnd.dece.hd\nuvi=image/vnd.dece.graphic\nuvm=video/vnd.dece.mobile\nuvp=video/vnd.dece.pd\nuvs=video/vnd.dece.sd\nuvt=application/vnd.dece.ttml+xml\nuvu=video/vnd.uvvu.mp4\nuvv=video/vnd.dece.video\nuvva=audio/vnd.dece.audio\nuvvd=application/vnd.dece.data\nuvvf=application/vnd.dece.data\nuvvg=image/vnd.dece.graphic\nuvvh=video/vnd.dece.hd\nuvvi=image/vnd.dece.graphic\nuvvm=video/vnd.dece.mobile\nuvvp=video/vnd.dece.pd\nuvvs=video/vnd.dece.sd\nuvvt=application/vnd.dece.ttml+xml\nuvvu=video/vnd.uvvu.mp4\nuvvv=video/vnd.dece.video\nuvvx=application/vnd.dece.unspecified\nuvvz=application/vnd.dece.zip\nuvx=application/vnd.dece.unspecified\nuvz=application/vnd.dece.zip\nvcard=text/vcard\nvcd=application/x-cdlink\nvcf=text/x-vcard\nvcg=application/vnd.groove-vcard\nvcs=text/x-vcalendar\nvcx=application/vnd.vcx\nvis=application/vnd.visionary\nviv=video/vnd.vivo\nvob=video/x-ms-vob\nvor=application/vnd.stardivision.writer\nvox=application/x-authorware-bin\nvrml=model/vrml\nvsd=application/vnd.visio\nvsf=application/vnd.vsf\nvss=application/vnd.visio\nvst=application/vnd.visio\nvsw=application/vnd.visio\nvtu=model/vnd.vtu\nvxml=application/voicexml+xml\nw3d=application/x-director\nwad=application/x-doom\nwasm=application/wasm\nwav=audio/x-wav\nwax=audio/x-ms-wax\nwbmp=image/vnd.wap.wbmp\nwbs=application/vnd.criticaltools.wbs+xml\nwbxml=application/vnd.wap.wbxml\nwcm=application/vnd.ms-works\nwdb=application/vnd.ms-works\nwdp=image/vnd.ms-photo\nweba=audio/webm\nwebm=video/webm\nwebp=image/webp\nwg=application/vnd.pmi.widget\nwgt=application/widget\nwks=application/vnd.ms-works\nwm=video/x-ms-wm\nwma=audio/x-ms-wma\nwmd=application/x-ms-wmd\nwmf=application/x-msmetafile\nwml=text/vnd.wap.wml\nwmlc=application/vnd.wap.wmlc\nwmls=text/vnd.wap.wmlscript\nwmlsc=application/vnd.wap.wmlscriptc\nwmv=video/x-ms-wmv\nwmx=video/x-ms-wmx\nwmz=application/x-msmetafile\nwoff=font/woff\nwoff2=font/woff2\nwpd=application/vnd.wordperfect\nwpl=application/vnd.ms-wpl\nwps=application/vnd.ms-works\nwqd=application/vnd.wqd\nwri=application/x-mswrite\nwrl=model/vrml\nwsdl=application/wsdl+xml\nwspolicy=application/wspolicy+xml\nwtb=application/vnd.webturbo\nwvx=video/x-ms-wvx\nx32=application/x-authorware-bin\nx3d=model/x3d+xml\nx3db=model/x3d+binary\nx3dbz=model/x3d+binary\nx3dv=model/x3d+vrml\nx3dvz=model/x3d+vrml\nx3dz=model/x3d+xml\nxaml=application/xaml+xml\nxap=application/x-silverlight-app\nxar=application/vnd.xara\nxbap=application/x-ms-xbap\nxbd=application/vnd.fujixerox.docuworks.binder\nxbm=image/x-xbitmap\nxdf=application/xcap-diff+xml\nxdm=application/vnd.syncml.dm+xml\nxdp=application/vnd.adobe.xdp+xml\nxdssc=application/dssc+xml\nxdw=application/vnd.fujixerox.docuworks\nxenc=application/xenc+xml\nxer=application/patch-ops-error+xml\nxfdf=application/vnd.adobe.xfdf\nxfdl=application/vnd.xfdl\nxht=application/xhtml+xml\nxhtml=application/xhtml+xml\nxhvml=application/xv+xml\nxif=image/vnd.xiff\nxla=application/vnd.ms-excel\nxlam=application/vnd.ms-excel.addin.macroenabled.12\nxlc=application/vnd.ms-excel\nxlf=application/x-xliff+xml\nxlm=application/vnd.ms-excel\nxls=application/vnd.ms-excel\nxlsb=application/vnd.ms-excel.sheet.binary.macroenabled.12\nxlsm=application/vnd.ms-excel.sheet.macroenabled.12\nxlsx=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\nxlt=application/vnd.ms-excel\nxltm=application/vnd.ms-excel.template.macroenabled.12\nxltx=application/vnd.openxmlformats-officedocument.spreadsheetml.template\nxlw=application/vnd.ms-excel\nxm=audio/xm\nxml=application/xml\nxo=application/vnd.olpc-sugar\nxop=application/xop+xml\nxpi=application/x-xpinstall\nxpl=application/xproc+xml\nxpm=image/x-xpixmap\nxpr=application/vnd.is-xpr\nxps=application/vnd.ms-xpsdocument\nxpw=application/vnd.intercon.formnet\nxpx=application/vnd.intercon.formnet\nxsl=application/xml\nxslt=application/xslt+xml\nxsm=application/vnd.syncml+xml\nxspf=application/xspf+xml\nxul=application/vnd.mozilla.xul+xml\nxvm=application/xv+xml\nxvml=application/xv+xml\nxwd=image/x-xwindowdump\nxyz=chemical/x-xyz\nxz=application/x-xz\nyang=application/yang\nyin=application/yin+xml\nz=application/x-compress\nz1=application/x-zmachine\nz2=application/x-zmachine\nz3=application/x-zmachine\nz4=application/x-zmachine\nz5=application/x-zmachine\nz6=application/x-zmachine\nz7=application/x-zmachine\nz8=application/x-zmachine\nzaz=application/vnd.zzazz.deck+xml\nzip=application/zip\nzir=application/vnd.zul\nzirz=application/vnd.zul\nzmm=application/vnd.handheld-entertainment+xml\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory.TempDirs;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractConfigurableWebServerFactory}.\n *\n * @author Moritz Halbritter\n */\nclass AbstractConfigurableWebServerFactoryTests {\n\n\t@Test\n\tvoid shouldCleanUpTempDirs() throws IOException {\n\t\tTempDirs tempDirs = new TempDirs(1234);\n\t\tPath tempDir1 = tempDirs.createTempDir(getClass().getSimpleName());\n\t\tPath tempDir2 = tempDirs.createTempDir(getClass().getSimpleName());\n\t\tassertThat(tempDir1).isNotEqualTo(tempDir2);\n\t\tassertThat(tempDir1).exists();\n\t\tassertThat(tempDir2).exists();\n\t\tFiles.writeString(tempDir1.resolve(\"test.txt\"), \"test\");\n\t\ttempDirs.cleanup();\n\t\tassertThat(tempDir1).doesNotExist();\n\t\tassertThat(tempDir2).doesNotExist();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/CompressionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport org.apache.coyote.http11.Http11NioProtocol;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link Compression}.\n *\n * @author Andy Wilkinson\n */\nclass CompressionTests {\n\n\t@Test\n\tvoid defaultCompressibleMimeTypesMatchesTomcatsDefault() {\n\t\tassertThat(new Compression().getMimeTypes()).containsExactlyInAnyOrder(getTomcatDefaultCompressibleMimeTypes());\n\t}\n\n\tprivate String[] getTomcatDefaultCompressibleMimeTypes() {\n\t\tHttp11NioProtocol protocol = new Http11NioProtocol();\n\t\treturn protocol.getCompressibleMimeTypes();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/MimeMappingsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.regex.Pattern;\n\nimport org.apache.catalina.startup.Tomcat;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.web.server.MimeMappings.DefaultMimeMappings;\nimport org.springframework.boot.web.server.MimeMappings.Mapping;\nimport org.springframework.boot.web.server.MimeMappings.MimeMappingsRuntimeHints;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.support.PropertiesLoaderUtils;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link MimeMappings}.\n *\n * @author Phillip Webb\n * @author Guirong Hu\n */\nclass MimeMappingsTests {\n\n\t@Test\n\tvoid defaultsCannotBeModified() {\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> MimeMappings.DEFAULT.add(\"foo\", \"foo/bar\"));\n\t}\n\n\t@Test\n\tvoid createFromExisting() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tMimeMappings clone = new MimeMappings(mappings);\n\t\tmappings.add(\"baz\", \"bar\");\n\t\tassertThat(clone.get(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(clone.get(\"baz\")).isNull();\n\t}\n\n\t@Test\n\tvoid createFromMap() {\n\t\tMap<String, String> mappings = new HashMap<>();\n\t\tmappings.put(\"foo\", \"bar\");\n\t\tMimeMappings clone = new MimeMappings(mappings);\n\t\tmappings.put(\"baz\", \"bar\");\n\t\tassertThat(clone.get(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(clone.get(\"baz\")).isNull();\n\t}\n\n\t@Test\n\tvoid iterate() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tmappings.add(\"baz\", \"boo\");\n\t\tList<MimeMappings.Mapping> mappingList = new ArrayList<>();\n\t\tfor (MimeMappings.Mapping mapping : mappings) {\n\t\t\tmappingList.add(mapping);\n\t\t}\n\t\tassertThat(mappingList.get(0).getExtension()).isEqualTo(\"foo\");\n\t\tassertThat(mappingList.get(0).getMimeType()).isEqualTo(\"bar\");\n\t\tassertThat(mappingList.get(1).getExtension()).isEqualTo(\"baz\");\n\t\tassertThat(mappingList.get(1).getMimeType()).isEqualTo(\"boo\");\n\t}\n\n\t@Test\n\tvoid getAll() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tmappings.add(\"baz\", \"boo\");\n\t\tList<MimeMappings.Mapping> mappingList = new ArrayList<>(mappings.getAll());\n\t\tassertThat(mappingList.get(0).getExtension()).isEqualTo(\"foo\");\n\t\tassertThat(mappingList.get(0).getMimeType()).isEqualTo(\"bar\");\n\t\tassertThat(mappingList.get(1).getExtension()).isEqualTo(\"baz\");\n\t\tassertThat(mappingList.get(1).getMimeType()).isEqualTo(\"boo\");\n\t}\n\n\t@Test\n\tvoid addNew() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tassertThat(mappings.add(\"foo\", \"bar\")).isNull();\n\t}\n\n\t@Test\n\tvoid addReplacesExisting() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tassertThat(mappings.add(\"foo\", \"baz\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid remove() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tassertThat(mappings.remove(\"foo\")).isEqualTo(\"bar\");\n\t\tassertThat(mappings.remove(\"foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid get() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tassertThat(mappings.get(\"foo\")).isEqualTo(\"bar\");\n\t}\n\n\t@Test\n\tvoid getMissing() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tassertThat(mappings.get(\"foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid makeUnmodifiable() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"foo\", \"bar\");\n\t\tMimeMappings unmodifiable = MimeMappings.unmodifiableMappings(mappings);\n\t\ttry {\n\t\t\tunmodifiable.remove(\"foo\");\n\t\t}\n\t\tcatch (UnsupportedOperationException ex) {\n\t\t\t// Expected\n\t\t}\n\t\tmappings.remove(\"foo\");\n\t\tassertThat(unmodifiable.get(\"foo\")).isNull();\n\t}\n\n\t@Test\n\tvoid mimeTypesInDefaultMappingsAreCorrectlyStructured() {\n\t\tString regName = \"[A-Za-z0-9!#$&.+\\\\-^_]{1,127}\";\n\t\tPattern pattern = Pattern.compile(\"^\" + regName + \"/\" + regName + \"$\");\n\t\tassertThat(MimeMappings.DEFAULT).allSatisfy((mapping) -> assertThat(mapping.getMimeType()).matches(pattern));\n\t}\n\n\t@Test\n\tvoid getCommonTypeOnDefaultMimeMappingsDoesNotLoadMappings() {\n\t\tDefaultMimeMappings mappings = new DefaultMimeMappings();\n\t\tassertThat(mappings.get(\"json\")).isEqualTo(\"application/json\");\n\t\tassertThat((Object) mappings).extracting(\"loaded\").isNull();\n\t}\n\n\t@Test\n\tvoid getExoticTypeOnDefaultMimeMappingsLoadsMappings() {\n\t\tDefaultMimeMappings mappings = new DefaultMimeMappings();\n\t\tassertThat(mappings.get(\"123\")).isEqualTo(\"application/vnd.lotus-1-2-3\");\n\t\tassertThat((Object) mappings).extracting(\"loaded\").isNotNull();\n\t}\n\n\t@Test\n\tvoid iterateOnDefaultMimeMappingsLoadsMappings() {\n\t\tDefaultMimeMappings mappings = new DefaultMimeMappings();\n\t\tassertThat(mappings).isNotEmpty();\n\t\tassertThat((Object) mappings).extracting(\"loaded\").isNotNull();\n\t}\n\n\t@Test\n\tvoid commonMappingsAreSubsetOfAllMappings() {\n\t\tMimeMappings defaultMappings = new DefaultMimeMappings();\n\t\tMimeMappings commonMappings = (MimeMappings) ReflectionTestUtils.getField(DefaultMimeMappings.class, \"COMMON\");\n\t\tassertThat(commonMappings).isNotNull();\n\t\tfor (Mapping commonMapping : commonMappings) {\n\t\t\tassertThat(defaultMappings.get(commonMapping.getExtension())).isEqualTo(commonMapping.getMimeType());\n\t\t}\n\t}\n\n\t@Test\n\tvoid lazyCopyWhenNotMutatedDelegates() {\n\t\tDefaultMimeMappings mappings = new DefaultMimeMappings();\n\t\tMimeMappings lazyCopy = MimeMappings.lazyCopy(mappings);\n\t\tassertThat(lazyCopy.get(\"json\")).isEqualTo(\"application/json\");\n\t\tassertThat((Object) mappings).extracting(\"loaded\").isNull();\n\t}\n\n\t@Test\n\tvoid lazyCopyWhenMutatedCreatesCopy() {\n\t\tDefaultMimeMappings mappings = new DefaultMimeMappings();\n\t\tMimeMappings lazyCopy = MimeMappings.lazyCopy(mappings);\n\t\tlazyCopy.add(\"json\", \"other/json\");\n\t\tassertThat(lazyCopy.get(\"json\")).isEqualTo(\"other/json\");\n\t\tassertThat((Object) mappings).extracting(\"loaded\").isNotNull();\n\t}\n\n\t@Test\n\tvoid lazyCopyWhenMutatedCreatesCopyOnlyOnce() {\n\t\tMimeMappings mappings = new MimeMappings();\n\t\tmappings.add(\"json\", \"one/json\");\n\t\tMimeMappings lazyCopy = MimeMappings.lazyCopy(mappings);\n\t\tlazyCopy.add(\"first\", \"copy/yes\");\n\t\tassertThat(lazyCopy.get(\"json\")).isEqualTo(\"one/json\");\n\t\tmappings.add(\"json\", \"two/json\");\n\t\tlazyCopy.add(\"second\", \"copy/no\");\n\t\tassertThat(lazyCopy.get(\"json\")).isEqualTo(\"one/json\");\n\t}\n\n\t@Test\n\tvoid mimeMappingsMatchesTomcatDefaults() throws IOException {\n\t\tProperties ourDefaultMimeMappings = PropertiesLoaderUtils\n\t\t\t.loadProperties(new ClassPathResource(\"mime-mappings.properties\", getClass()));\n\t\tProperties tomcatDefaultMimeMappings = PropertiesLoaderUtils\n\t\t\t.loadProperties(new ClassPathResource(\"MimeTypeMappings.properties\", Tomcat.class));\n\t\tassertThat(ourDefaultMimeMappings).containsExactlyInAnyOrderEntriesOf(tomcatDefaultMimeMappings);\n\t}\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew MimeMappingsRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.resource()\n\t\t\t.forResource(\"org/springframework/boot/web/server/mime-mappings.properties\")).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/SpringApplicationWebServerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.util.Iterator;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.boot.web.context.reactive.StandardReactiveWebEnvironment;\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.StandardServletEnvironment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringApplication} with a {@link WebServer}.\n *\n * @author Andy wilkinson\n */\nclass SpringApplicationWebServerTests {\n\n\tprivate @Nullable String headlessProperty;\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@BeforeEach\n\tvoid storeAndClearHeadlessProperty() {\n\t\tthis.headlessProperty = System.getProperty(\"java.awt.headless\");\n\t\tSystem.clearProperty(\"java.awt.headless\");\n\t}\n\n\t@AfterEach\n\tvoid reinstateHeadlessProperty() {\n\t\tif (this.headlessProperty == null) {\n\t\t\tSystem.clearProperty(\"java.awt.headless\");\n\t\t}\n\t\telse {\n\t\t\tSystem.setProperty(\"java.awt.headless\", this.headlessProperty);\n\t\t}\n\t}\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tSystem.clearProperty(\"spring.main.banner-mode\");\n\t}\n\n\t@Test\n\tvoid defaultApplicationContextForWeb() {\n\t\tSpringApplication application = new SpringApplication(ExampleWebConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.SERVLET);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isInstanceOf(AnnotationConfigServletWebServerApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid defaultApplicationContextForReactiveWeb() {\n\t\tSpringApplication application = new SpringApplication(ExampleReactiveWebConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.REACTIVE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context).isInstanceOf(AnnotationConfigReactiveWebServerApplicationContext.class);\n\t}\n\n\t@Test\n\tvoid environmentForWeb() {\n\t\tSpringApplication application = new SpringApplication(ExampleWebConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.SERVLET);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment()).isInstanceOf(StandardServletEnvironment.class);\n\t\tassertThat(this.context.getEnvironment().getClass().getName()).endsWith(\"ApplicationServletEnvironment\");\n\t}\n\n\t@Test\n\tvoid environmentForReactiveWeb() {\n\t\tSpringApplication application = new SpringApplication(ExampleReactiveWebConfig.class);\n\t\tapplication.setWebApplicationType(WebApplicationType.REACTIVE);\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment()).isInstanceOf(StandardReactiveWebEnvironment.class);\n\t\tassertThat(this.context.getEnvironment().getClass().getName()).endsWith(\"ApplicationReactiveWebEnvironment\");\n\t}\n\n\t@Test\n\tvoid webApplicationConfiguredViaAPropertyHasTheCorrectTypeOfContextAndEnvironment() {\n\t\tConfigurableApplicationContext context = new SpringApplication(ExampleWebConfig.class)\n\t\t\t.run(\"--spring.main.web-application-type=servlet\");\n\t\tassertThat(context).isInstanceOf(WebApplicationContext.class);\n\t\tassertThat(context.getEnvironment()).isInstanceOf(StandardServletEnvironment.class);\n\t\tassertThat(context.getEnvironment().getClass().getName()).endsWith(\"ApplicationServletEnvironment\");\n\t}\n\n\t@Test\n\tvoid reactiveApplicationConfiguredViaAPropertyHasTheCorrectTypeOfContextAndEnvironment() {\n\t\tConfigurableApplicationContext context = new SpringApplication(ExampleReactiveWebConfig.class)\n\t\t\t.run(\"--spring.main.web-application-type=reactive\");\n\t\tassertThat(context).isInstanceOf(ReactiveWebApplicationContext.class);\n\t\tassertThat(context.getEnvironment()).isInstanceOf(StandardReactiveWebEnvironment.class);\n\t\tassertThat(context.getEnvironment().getClass().getName()).endsWith(\"ApplicationReactiveWebEnvironment\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"application-withwebapplicationtype.properties\",\n\t\t\tcontent = \"spring.main.web-application-type=reactive\")\n\tvoid environmentIsConvertedIfTypeDoesNotMatch() {\n\t\tConfigurableApplicationContext context = new SpringApplication(ExampleReactiveWebConfig.class)\n\t\t\t.run(\"--spring.profiles.active=withwebapplicationtype\");\n\t\tassertThat(context).isInstanceOf(ReactiveWebApplicationContext.class);\n\t\tassertThat(context.getEnvironment()).isInstanceOf(StandardReactiveWebEnvironment.class);\n\t\tassertThat(context.getEnvironment().getClass().getName()).endsWith(\"ApplicationReactiveWebEnvironment\");\n\t}\n\n\t@Test\n\tvoid webApplicationSwitchedOffInListener() {\n\t\tSpringApplication application = new SpringApplication(ExampleWebConfig.class);\n\t\tapplication.addListeners((ApplicationListener<ApplicationEnvironmentPreparedEvent>) (event) -> {\n\t\t\tassertThat(event.getEnvironment().getClass().getName()).endsWith(\"ApplicationServletEnvironment\");\n\t\t\tTestPropertySourceUtils.addInlinedPropertiesToEnvironment(event.getEnvironment(), \"foo=bar\");\n\t\t\tevent.getSpringApplication().setWebApplicationType(WebApplicationType.NONE);\n\t\t});\n\t\tthis.context = application.run();\n\t\tassertThat(this.context.getEnvironment()).isNotInstanceOf(StandardServletEnvironment.class);\n\t\tassertThat(this.context.getEnvironment().getProperty(\"foo\")).isEqualTo(\"bar\");\n\t\tIterator<PropertySource<?>> iterator = this.context.getEnvironment().getPropertySources().iterator();\n\t\tassertThat(iterator.next().getName()).isEqualTo(\"configurationProperties\");\n\t\tassertThat(iterator.next().getName())\n\t\t\t.isEqualTo(TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleWebConfig {\n\n\t\t@Bean\n\t\tMockServletWebServerFactory webServer() {\n\t\t\treturn new MockServletWebServerFactory();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExampleReactiveWebConfig {\n\n\t\t@Bean\n\t\tMockReactiveWebServerFactory webServerFactory() {\n\t\t\treturn new MockReactiveWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn (serverHttpRequest, serverHttpResponse) -> Mono.empty();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/WebServerFactoryCustomizerBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ListableBeanFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebServerFactoryCustomizerBeanPostProcessor}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass WebServerFactoryCustomizerBeanPostProcessorTests {\n\n\tprivate final WebServerFactoryCustomizerBeanPostProcessor processor = new WebServerFactoryCustomizerBeanPostProcessor();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ListableBeanFactory beanFactory;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.processor.setBeanFactory(this.beanFactory);\n\t}\n\n\t@Test\n\tvoid setBeanFactoryWhenNotListableShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.processor.setBeanFactory(mock(BeanFactory.class)))\n\t\t\t.withMessageContaining(\"'beanFactory' must be a ListableBeanFactory\");\n\t}\n\n\t@Test\n\tvoid postProcessBeforeShouldReturnBean() {\n\t\tObject bean = new Object();\n\t\tObject result = this.processor.postProcessBeforeInitialization(bean, \"foo\");\n\t\tassertThat(result).isSameAs(bean);\n\t}\n\n\t@Test\n\tvoid postProcessAfterShouldReturnBean() {\n\t\tObject bean = new Object();\n\t\tObject result = this.processor.postProcessAfterInitialization(bean, \"foo\");\n\t\tassertThat(result).isSameAs(bean);\n\t}\n\n\t@Test\n\tvoid postProcessAfterShouldCallInterfaceCustomizers() {\n\t\tMap<String, Object> beans = addInterfaceBeans();\n\t\taddMockBeans(beans);\n\t\tpostProcessBeforeInitialization(WebServerFactory.class);\n\t\tassertThat(wasCalled(beans, \"one\")).isFalse();\n\t\tassertThat(wasCalled(beans, \"two\")).isFalse();\n\t\tassertThat(wasCalled(beans, \"all\")).isTrue();\n\t}\n\n\t@Test\n\tvoid postProcessAfterWhenWebServerFactoryOneShouldCallInterfaceCustomizers() {\n\t\tMap<String, Object> beans = addInterfaceBeans();\n\t\taddMockBeans(beans);\n\t\tpostProcessBeforeInitialization(WebServerFactoryOne.class);\n\t\tassertThat(wasCalled(beans, \"one\")).isTrue();\n\t\tassertThat(wasCalled(beans, \"two\")).isFalse();\n\t\tassertThat(wasCalled(beans, \"all\")).isTrue();\n\t}\n\n\t@Test\n\tvoid postProcessAfterWhenWebServerFactoryTwoShouldCallInterfaceCustomizers() {\n\t\tMap<String, Object> beans = addInterfaceBeans();\n\t\taddMockBeans(beans);\n\t\tpostProcessBeforeInitialization(WebServerFactoryTwo.class);\n\t\tassertThat(wasCalled(beans, \"one\")).isFalse();\n\t\tassertThat(wasCalled(beans, \"two\")).isTrue();\n\t\tassertThat(wasCalled(beans, \"all\")).isTrue();\n\t}\n\n\tprivate Map<String, Object> addInterfaceBeans() {\n\t\tWebServerFactoryOneCustomizer oneCustomizer = new WebServerFactoryOneCustomizer();\n\t\tWebServerFactoryTwoCustomizer twoCustomizer = new WebServerFactoryTwoCustomizer();\n\t\tWebServerFactoryAllCustomizer allCustomizer = new WebServerFactoryAllCustomizer();\n\t\tMap<String, Object> beans = new LinkedHashMap<>();\n\t\tbeans.put(\"one\", oneCustomizer);\n\t\tbeans.put(\"two\", twoCustomizer);\n\t\tbeans.put(\"all\", allCustomizer);\n\t\treturn beans;\n\t}\n\n\t@Test\n\tvoid postProcessAfterShouldCallLambdaCustomizers() {\n\t\tList<String> called = new ArrayList<>();\n\t\taddLambdaBeans(called);\n\t\tpostProcessBeforeInitialization(WebServerFactory.class);\n\t\tassertThat(called).containsExactly(\"all\");\n\t}\n\n\t@Test\n\tvoid postProcessAfterWhenWebServerFactoryOneShouldCallLambdaCustomizers() {\n\t\tList<String> called = new ArrayList<>();\n\t\taddLambdaBeans(called);\n\t\tpostProcessBeforeInitialization(WebServerFactoryOne.class);\n\t\tassertThat(called).containsExactly(\"one\", \"all\");\n\t}\n\n\t@Test\n\tvoid postProcessAfterWhenWebServerFactoryTwoShouldCallLambdaCustomizers() {\n\t\tList<String> called = new ArrayList<>();\n\t\taddLambdaBeans(called);\n\t\tpostProcessBeforeInitialization(WebServerFactoryTwo.class);\n\t\tassertThat(called).containsExactly(\"two\", \"all\");\n\t}\n\n\tprivate void addLambdaBeans(List<String> called) {\n\t\tWebServerFactoryCustomizer<WebServerFactoryOne> one = (f) -> called.add(\"one\");\n\t\tWebServerFactoryCustomizer<WebServerFactoryTwo> two = (f) -> called.add(\"two\");\n\t\tWebServerFactoryCustomizer<WebServerFactory> all = (f) -> called.add(\"all\");\n\t\tMap<String, Object> beans = new LinkedHashMap<>();\n\t\tbeans.put(\"one\", one);\n\t\tbeans.put(\"two\", two);\n\t\tbeans.put(\"all\", all);\n\t\taddMockBeans(beans);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate void addMockBeans(Map<String, ?> beans) {\n\t\tgiven(this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false))\n\t\t\t.willReturn((Map<String, WebServerFactoryCustomizer>) beans);\n\t}\n\n\tprivate void postProcessBeforeInitialization(Class<?> type) {\n\t\tthis.processor.postProcessBeforeInitialization(mock(type), \"foo\");\n\t}\n\n\tprivate boolean wasCalled(Map<String, ?> beans, String name) {\n\t\tObject bean = beans.get(name);\n\t\tassertThat(bean).isNotNull();\n\t\treturn ((MockWebServerFactoryCustomizer<?>) bean).wasCalled();\n\t}\n\n\tinterface WebServerFactoryOne extends WebServerFactory {\n\n\t}\n\n\tinterface WebServerFactoryTwo extends WebServerFactory {\n\n\t}\n\n\tstatic class MockWebServerFactoryCustomizer<T extends WebServerFactory> implements WebServerFactoryCustomizer<T> {\n\n\t\tprivate boolean called;\n\n\t\t@Override\n\t\tpublic void customize(T factory) {\n\t\t\tthis.called = true;\n\t\t}\n\n\t\tboolean wasCalled() {\n\t\t\treturn this.called;\n\t\t}\n\n\t}\n\n\tstatic class WebServerFactoryOneCustomizer extends MockWebServerFactoryCustomizer<WebServerFactoryOne> {\n\n\t}\n\n\tstatic class WebServerFactoryTwoCustomizer extends MockWebServerFactoryCustomizer<WebServerFactoryTwo> {\n\n\t}\n\n\tstatic class WebServerFactoryAllCustomizer extends MockWebServerFactoryCustomizer<WebServerFactory> {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/WebServerSslBundleTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundleKey;\nimport org.springframework.boot.ssl.SslOptions;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11Security;\nimport org.springframework.boot.testsupport.ssl.MockPkcs11SecurityProvider;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link WebServerSslBundle}.\n *\n * @author Scott Frederick\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@MockPkcs11Security\nclass WebServerSslBundleTests {\n\n\t@Test\n\tvoid whenSslDisabledThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setEnabled(false);\n\t\tassertThatIllegalStateException().isThrownBy(() -> WebServerSslBundle.get(ssl))\n\t\t\t.withMessage(\"SSL is not enabled\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.p12\")\n\tvoid whenFromJksProperties() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.p12\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyStoreType(\"PKCS12\");\n\t\tssl.setTrustStore(\"classpath:test.p12\");\n\t\tssl.setTrustStorePassword(\"secret\");\n\t\tssl.setTrustStoreType(\"PKCS12\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setKeyAlias(\"alias\");\n\t\tssl.setClientAuth(Ssl.ClientAuth.NONE);\n\t\tssl.setCiphers(new String[] { \"ONE\", \"TWO\", \"THREE\" });\n\t\tssl.setEnabledProtocols(new String[] { \"TLSv1.1\", \"TLSv1.2\" });\n\t\tssl.setProtocol(\"TestProtocol\");\n\t\tSslBundle bundle = WebServerSslBundle.get(ssl);\n\t\tassertThat(bundle).isNotNull();\n\t\tassertThat(bundle.getProtocol()).isEqualTo(\"TestProtocol\");\n\t\tSslBundleKey key = bundle.getKey();\n\t\tassertThat(key.getPassword()).isEqualTo(\"password\");\n\t\tassertThat(key.getAlias()).isEqualTo(\"alias\");\n\t\tSslStoreBundle stores = bundle.getStores();\n\t\tassertThat(stores.getKeyStorePassword()).isEqualTo(\"secret\");\n\t\tassertThat(stores.getKeyStore()).isNotNull();\n\t\tassertThat(stores.getTrustStore()).isNotNull();\n\t\tSslOptions options = bundle.getOptions();\n\t\tassertThat(options.getCiphers()).containsExactly(\"ONE\", \"TWO\", \"THREE\");\n\t\tassertThat(options.getEnabledProtocols()).containsExactly(\"TLSv1.1\", \"TLSv1.2\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid whenFromJksPropertiesWithPkcs11StoreType(@ResourcePath(\"test.jks\") String keyStorePath) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStoreType(\"PKCS11\");\n\t\tssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setKeyStore(keyStorePath);\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setClientAuth(Ssl.ClientAuth.NONE);\n\t\tassertThatIllegalStateException().isThrownBy(() -> WebServerSslBundle.get(ssl))\n\t\t\t.withMessageContaining(\"must be empty or null for PKCS11 hardware key stores\");\n\t}\n\n\t@Test\n\tvoid whenFromPkcs11Properties() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStoreType(\"PKCS11\");\n\t\tssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setTrustStoreType(\"PKCS11\");\n\t\tssl.setTrustStoreProvider(MockPkcs11SecurityProvider.NAME);\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setClientAuth(Ssl.ClientAuth.NONE);\n\t\tSslBundle bundle = WebServerSslBundle.get(ssl);\n\t\tassertThat(bundle).isNotNull();\n\t\tassertThat(bundle.getProtocol()).isEqualTo(\"TLS\");\n\t\tSslBundleKey key = bundle.getKey();\n\t\tassertThat(key.getPassword()).isEqualTo(\"password\");\n\t\tSslStoreBundle stores = bundle.getStores();\n\t\tassertThat(stores.getKeyStore()).isNotNull();\n\t\tassertThat(stores.getTrustStore()).isNotNull();\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\", \"test-cert-chain.pem\" })\n\tvoid whenFromPemProperties() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setCertificate(\"classpath:test-cert.pem\");\n\t\tssl.setCertificatePrivateKey(\"classpath:test-key.pem\");\n\t\tssl.setTrustCertificate(\"classpath:test-cert-chain.pem\");\n\t\tssl.setKeyStoreType(\"PKCS12\");\n\t\tssl.setTrustStoreType(\"PKCS12\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setClientAuth(Ssl.ClientAuth.NONE);\n\t\tssl.setCiphers(new String[] { \"ONE\", \"TWO\", \"THREE\" });\n\t\tssl.setEnabledProtocols(new String[] { \"TLSv1.1\", \"TLSv1.2\" });\n\t\tssl.setProtocol(\"TLSv1.1\");\n\t\tSslBundle bundle = WebServerSslBundle.get(ssl);\n\t\tassertThat(bundle).isNotNull();\n\t\tSslBundleKey key = bundle.getKey();\n\t\tassertThat(key.getAlias()).isNull();\n\t\tassertThat(key.getPassword()).isEqualTo(\"password\");\n\t\tSslStoreBundle stores = bundle.getStores();\n\t\tassertThat(stores.getKeyStorePassword()).isNull();\n\t\tassertThat(stores.getKeyStore()).isNotNull();\n\t\tassertThat(stores.getTrustStore()).isNotNull();\n\t\tSslOptions options = bundle.getOptions();\n\t\tassertThat(options.getCiphers()).containsExactly(\"ONE\", \"TWO\", \"THREE\");\n\t\tassertThat(options.getEnabledProtocols()).containsExactly(\"TLSv1.1\", \"TLSv1.2\");\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\", \"test.p12\" })\n\tvoid whenPemKeyStoreAndJksTrustStoreProperties() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setCertificate(\"classpath:test-cert.pem\");\n\t\tssl.setCertificatePrivateKey(\"classpath:test-key.pem\");\n\t\tssl.setKeyStoreType(\"PKCS12\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setTrustStore(\"classpath:test.p12\");\n\t\tssl.setTrustStorePassword(\"secret\");\n\t\tssl.setTrustStoreType(\"PKCS12\");\n\t\tssl.setClientAuth(Ssl.ClientAuth.NONE);\n\t\tssl.setCiphers(new String[] { \"ONE\", \"TWO\", \"THREE\" });\n\t\tssl.setEnabledProtocols(new String[] { \"TLSv1.1\", \"TLSv1.2\" });\n\t\tssl.setProtocol(\"TLSv1.1\");\n\t\tSslBundle bundle = WebServerSslBundle.get(ssl);\n\t\tassertThat(bundle).isNotNull();\n\t\tSslBundleKey key = bundle.getKey();\n\t\tassertThat(key.getAlias()).isNull();\n\t\tassertThat(key.getPassword()).isEqualTo(\"password\");\n\t\tSslStoreBundle stores = bundle.getStores();\n\t\tassertThat(stores.getKeyStorePassword()).isNull();\n\t\tassertThat(stores.getKeyStore()).isNotNull();\n\t\tassertThat(stores.getTrustStore()).isNotNull();\n\t\tSslOptions options = bundle.getOptions();\n\t\tassertThat(options.getCiphers()).containsExactly(\"ONE\", \"TWO\", \"THREE\");\n\t\tassertThat(options.getEnabledProtocols()).containsExactly(\"TLSv1.1\", \"TLSv1.2\");\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test.p12\", \"test-cert-chain.pem\" })\n\tvoid whenJksKeyStoreAndPemTrustStoreProperties() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(\"classpath:test.p12\");\n\t\tssl.setKeyStoreType(\"PKCS12\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setTrustCertificate(\"classpath:test-cert-chain.pem\");\n\t\tssl.setTrustStorePassword(\"secret\");\n\t\tssl.setTrustStoreType(\"PKCS12\");\n\t\tssl.setClientAuth(Ssl.ClientAuth.NONE);\n\t\tssl.setCiphers(new String[] { \"ONE\", \"TWO\", \"THREE\" });\n\t\tssl.setEnabledProtocols(new String[] { \"TLSv1.1\", \"TLSv1.2\" });\n\t\tssl.setProtocol(\"TLSv1.1\");\n\t\tSslBundle bundle = WebServerSslBundle.get(ssl);\n\t\tassertThat(bundle).isNotNull();\n\t\tSslBundleKey key = bundle.getKey();\n\t\tassertThat(key.getAlias()).isNull();\n\t\tassertThat(key.getPassword()).isEqualTo(\"password\");\n\t\tSslStoreBundle stores = bundle.getStores();\n\t\tassertThat(stores.getKeyStorePassword()).isNull();\n\t\tassertThat(stores.getKeyStore()).isNotNull();\n\t\tassertThat(stores.getTrustStore()).isNotNull();\n\t\tSslOptions options = bundle.getOptions();\n\t\tassertThat(options.getCiphers()).containsExactly(\"ONE\", \"TWO\", \"THREE\");\n\t\tassertThat(options.getEnabledProtocols()).containsExactly(\"TLSv1.1\", \"TLSv1.2\");\n\t}\n\n\t@Test\n\tvoid whenMissingPropertiesThrowsException() {\n\t\tSsl ssl = new Ssl();\n\t\tassertThatIllegalStateException().isThrownBy(() -> WebServerSslBundle.get(ssl))\n\t\t\t.withMessageContaining(\"SSL is enabled but no trust material is configured\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/autoconfigure/ServerPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure;\n\nimport java.net.InetAddress;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.apache.coyote.http11.Http11Nio2Protocol;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.MimeMappings.Mapping;\nimport org.springframework.util.unit.DataSize;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ServerProperties}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Quinten De Swaef\n * @author Venil Noronha\n * @author Andrew McGhie\n * @author HaiTao Zhang\n * @author Rafiullah Hamedy\n * @author Chris Bono\n * @author Parviz Rozikov\n * @author Lasse Wulff\n * @author Moritz Halbritter\n */\nclass ServerPropertiesTests {\n\n\tprivate final ServerProperties properties = new ServerProperties();\n\n\t@Test\n\tvoid testAddressBinding() throws Exception {\n\t\tbind(\"server.address\", \"127.0.0.1\");\n\t\tassertThat(this.properties.getAddress()).isEqualTo(InetAddress.getByName(\"127.0.0.1\"));\n\t}\n\n\t@Test\n\tvoid testPortBinding() {\n\t\tbind(\"server.port\", \"9000\");\n\t\tInteger port = this.properties.getPort();\n\t\tassertThat(port).isNotNull();\n\t\tassertThat(port.intValue()).isEqualTo(9000);\n\t}\n\n\t@Test\n\tvoid testServerHeaderDefault() {\n\t\tassertThat(this.properties.getServerHeader()).isNull();\n\t}\n\n\t@Test\n\tvoid testServerHeader() {\n\t\tbind(\"server.server-header\", \"Custom Server\");\n\t\tassertThat(this.properties.getServerHeader()).isEqualTo(\"Custom Server\");\n\t}\n\n\t@Test\n\tvoid testTrailingSlashOfContextPathIsRemoved() {\n\t\tbind(\"server.servlet.context-path\", \"/foo/\");\n\t\tassertThat(this.properties.getServlet().getContextPath()).isEqualTo(\"/foo\");\n\t}\n\n\t@Test\n\tvoid testSlashOfContextPathIsDefaultValue() {\n\t\tbind(\"server.servlet.context-path\", \"/\");\n\t\tassertThat(this.properties.getServlet().getContextPath()).isEmpty();\n\t}\n\n\t@Test\n\tvoid testContextPathWithLeadingWhitespace() {\n\t\tbind(\"server.servlet.context-path\", \" /assets\");\n\t\tassertThat(this.properties.getServlet().getContextPath()).isEqualTo(\"/assets\");\n\t}\n\n\t@Test\n\tvoid testContextPathWithTrailingWhitespace() {\n\t\tbind(\"server.servlet.context-path\", \"/assets/copy/ \");\n\t\tassertThat(this.properties.getServlet().getContextPath()).isEqualTo(\"/assets/copy\");\n\t}\n\n\t@Test\n\tvoid testContextPathWithLeadingAndTrailingWhitespace() {\n\t\tbind(\"server.servlet.context-path\", \" /assets \");\n\t\tassertThat(this.properties.getServlet().getContextPath()).isEqualTo(\"/assets\");\n\t}\n\n\t@Test\n\tvoid testContextPathWithLeadingAndTrailingWhitespaceAndContextWithSpace() {\n\t\tbind(\"server.servlet.context-path\", \"  /assets /copy/    \");\n\t\tassertThat(this.properties.getServlet().getContextPath()).isEqualTo(\"/assets /copy\");\n\t}\n\n\t@Test\n\tvoid testDefaultMimeMapping() {\n\t\tassertThat(this.properties.getMimeMappings()).isEmpty();\n\t}\n\n\t@Test\n\tvoid testCustomizedMimeMapping() {\n\t\tMimeMappings expectedMappings = new MimeMappings();\n\t\texpectedMappings.add(\"mjs\", \"text/javascript\");\n\t\tbind(\"server.mime-mappings.mjs\", \"text/javascript\");\n\t\tassertThat(this.properties.getMimeMappings())\n\t\t\t.containsExactly(expectedMappings.getAll().toArray(new Mapping[0]));\n\t}\n\n\t@Test\n\tvoid testCustomizeMaxHttpRequestHeaderSize() {\n\t\tbind(\"server.max-http-request-header-size\", \"1MB\");\n\t\tassertThat(this.properties.getMaxHttpRequestHeaderSize()).isEqualTo(DataSize.ofMegabytes(1));\n\t}\n\n\t@Test\n\tvoid testCustomizeMaxHttpRequestHeaderSizeUseBytesByDefault() {\n\t\tbind(\"server.max-http-request-header-size\", \"1024\");\n\t\tassertThat(this.properties.getMaxHttpRequestHeaderSize()).isEqualTo(DataSize.ofKilobytes(1));\n\t}\n\n\t@Test\n\tvoid defaultMaxHttpRequestHeaderSizeMatchesTomcatsDefault() {\n\t\tassertThat(this.properties.getMaxHttpRequestHeaderSize().toBytes())\n\t\t\t.isEqualTo(new Http11Nio2Protocol().getMaxHttpRequestHeaderSize());\n\t}\n\n\t@Test\n\tvoid additionalCompressionMimeTypesAreAddedToDefaults() {\n\t\tbind(\"server.compression.additional-mime-types\", \"application/zip\");\n\t\tassertThat(this.properties.getCompression().getAllMimeTypes()).contains(new Compression().getMimeTypes());\n\t\tassertThat(this.properties.getCompression().getAllMimeTypes()).contains(\"application/zip\");\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"server\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/autoconfigure/reactive/ReactiveWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.reactive;\n\nimport java.net.InetAddress;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveWebServerFactoryCustomizer}.\n *\n * @author Brian Clozel\n * @author Yunkun Huang\n * @author Scott Frederick\n */\nclass ReactiveWebServerFactoryCustomizerTests {\n\n\tprivate final ServerProperties properties = new ServerProperties();\n\n\tprivate final SslBundles sslBundles = new DefaultSslBundleRegistry();\n\n\tprivate ReactiveWebServerFactoryCustomizer customizer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.customizer = new ReactiveWebServerFactoryCustomizer(this.properties, this.sslBundles);\n\t}\n\n\t@Test\n\tvoid testCustomizeServerPort() {\n\t\tConfigurableReactiveWebServerFactory factory = mock(ConfigurableReactiveWebServerFactory.class);\n\t\tthis.properties.setPort(9000);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setPort(9000);\n\t}\n\n\t@Test\n\tvoid testCustomizeServerAddress() {\n\t\tConfigurableReactiveWebServerFactory factory = mock(ConfigurableReactiveWebServerFactory.class);\n\t\tInetAddress address = InetAddress.getLoopbackAddress();\n\t\tthis.properties.setAddress(address);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setAddress(address);\n\t}\n\n\t@Test\n\tvoid testCustomizeServerSsl() {\n\t\tConfigurableReactiveWebServerFactory factory = mock(ConfigurableReactiveWebServerFactory.class);\n\t\tSsl ssl = mock(Ssl.class);\n\t\tthis.properties.setSsl(ssl);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setSsl(ssl);\n\t\tthen(factory).should().setSslBundles(this.sslBundles);\n\t}\n\n\t@Test\n\tvoid whenShutdownPropertyIsSetThenShutdownIsCustomized() {\n\t\tthis.properties.setShutdown(Shutdown.GRACEFUL);\n\t\tConfigurableReactiveWebServerFactory factory = mock(ConfigurableReactiveWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setShutdown(assertArg((shutdown) -> assertThat(shutdown).isEqualTo(Shutdown.GRACEFUL)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/autoconfigure/servlet/ServletWebServerFactoryCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.servlet;\n\nimport java.io.File;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\nimport org.springframework.boot.web.server.Cookie;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.Jsp;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyMap;\nimport static org.mockito.ArgumentMatchers.assertArg;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Tests for {@link ServletWebServerFactoryCustomizer}.\n *\n * @author Brian Clozel\n * @author Yunkun Huang\n * @author Lasse Wulff\n */\nclass ServletWebServerFactoryCustomizerTests {\n\n\tprivate final ServerProperties properties = new ServerProperties();\n\n\tprivate ServletWebServerFactoryCustomizer customizer;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.customizer = new ServletWebServerFactoryCustomizer(this.properties);\n\t}\n\n\t@Test\n\tvoid testDefaultDisplayName() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setDisplayName(\"application\");\n\t}\n\n\t@Test\n\tvoid testCustomizeDisplayName() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.properties.getServlet().setApplicationDisplayName(\"TestName\");\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setDisplayName(\"TestName\");\n\t}\n\n\t@Test\n\tvoid withNoCustomMimeMappingsThenEmptyMimeMappingsIsAdded() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tArgumentCaptor<MimeMappings> mimeMappingsCaptor = ArgumentCaptor.forClass(MimeMappings.class);\n\t\tthen(factory).should().addMimeMappings(mimeMappingsCaptor.capture());\n\t\tMimeMappings mimeMappings = mimeMappingsCaptor.getValue();\n\t\tassertThat(mimeMappings.getAll()).isEmpty();\n\t}\n\n\t@Test\n\tvoid withCustomMimeMappingsThenPopulatedMimeMappingsIsAdded() {\n\t\tthis.properties.getMimeMappings().add(\"a\", \"alpha\");\n\t\tthis.properties.getMimeMappings().add(\"b\", \"bravo\");\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tArgumentCaptor<MimeMappings> mimeMappingsCaptor = ArgumentCaptor.forClass(MimeMappings.class);\n\t\tthen(factory).should().addMimeMappings(mimeMappingsCaptor.capture());\n\t\tMimeMappings mimeMappings = mimeMappingsCaptor.getValue();\n\t\tassertThat(mimeMappings.getAll()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid testCustomizeDefaultServlet() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.properties.getServlet().setRegisterDefaultServlet(false);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setRegisterDefaultServlet(false);\n\t}\n\n\t@Test\n\tvoid testCustomizeSsl() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tSsl ssl = mock(Ssl.class);\n\t\tthis.properties.setSsl(ssl);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setSsl(ssl);\n\t}\n\n\t@Test\n\tvoid testCustomizeJsp() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setJsp(any(Jsp.class));\n\t}\n\n\t@Test\n\tvoid customizeSessionProperties() {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"server.servlet.session.timeout\", \"123\");\n\t\tmap.put(\"server.servlet.session.tracking-modes\", \"cookie,url\");\n\t\tmap.put(\"server.servlet.session.cookie.name\", \"testname\");\n\t\tmap.put(\"server.servlet.session.cookie.domain\", \"testdomain\");\n\t\tmap.put(\"server.servlet.session.cookie.path\", \"/testpath\");\n\t\tmap.put(\"server.servlet.session.cookie.http-only\", \"true\");\n\t\tmap.put(\"server.servlet.session.cookie.secure\", \"true\");\n\t\tmap.put(\"server.servlet.session.cookie.max-age\", \"60\");\n\t\tbindProperties(map);\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setSession(assertArg((session) -> {\n\t\t\tassertThat(session.getTimeout()).hasSeconds(123);\n\t\t\tCookie cookie = session.getCookie();\n\t\t\tassertThat(cookie.getName()).isEqualTo(\"testname\");\n\t\t\tassertThat(cookie.getDomain()).isEqualTo(\"testdomain\");\n\t\t\tassertThat(cookie.getPath()).isEqualTo(\"/testpath\");\n\t\t\tassertThat(cookie.getHttpOnly()).isTrue();\n\t\t\tassertThat(cookie.getMaxAge()).hasSeconds(60);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid testCustomizeTomcatPort() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.properties.setPort(8080);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setPort(8080);\n\t}\n\n\t@Test\n\tvoid customizeServletDisplayName() {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"server.servlet.application-display-name\", \"MyBootApp\");\n\t\tbindProperties(map);\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setDisplayName(\"MyBootApp\");\n\t}\n\n\t@Test\n\tvoid sessionStoreDir() {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"server.servlet.session.store-dir\", \"mydirectory\");\n\t\tbindProperties(map);\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should()\n\t\t\t.setSession(assertArg((session) -> assertThat(session.getStoreDir()).isEqualTo(new File(\"mydirectory\"))));\n\t}\n\n\t@Test\n\tvoid whenShutdownPropertyIsSetThenShutdownIsCustomized() {\n\t\tMap<String, String> map = new HashMap<>();\n\t\tmap.put(\"server.shutdown\", \"immediate\");\n\t\tbindProperties(map);\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should().setShutdown(assertArg((shutdown) -> assertThat(shutdown).isEqualTo(Shutdown.IMMEDIATE)));\n\t}\n\n\t@Test\n\tvoid noLocaleCharsetMapping() {\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should(never()).setLocaleCharsetMappings(anyMap());\n\t}\n\n\t@Test\n\tvoid customLocaleCharsetMappings() {\n\t\tMap<String, String> map = Map.of(\"server.servlet.encoding.mapping.en\", \"UTF-8\",\n\t\t\t\t\"server.servlet.encoding.mapping.fr_FR\", \"UTF-8\");\n\t\tbindProperties(map);\n\t\tConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class);\n\t\tthis.customizer.customize(factory);\n\t\tthen(factory).should()\n\t\t\t.setLocaleCharsetMappings((assertArg((mappings) -> assertThat(mappings).hasSize(2)\n\t\t\t\t.containsEntry(Locale.ENGLISH, StandardCharsets.UTF_8)\n\t\t\t\t.containsEntry(Locale.FRANCE, StandardCharsets.UTF_8))));\n\t}\n\n\tprivate void bindProperties(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"server\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/context/MissingWebServerFactoryBeanFailureAnalyzerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.diagnostics.FailureAnalysis;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MissingWebServerFactoryBeanFailureAnalyzer}.\n *\n * @author Guirong Hu\n * @author Andy Wilkinson\n */\nclass MissingWebServerFactoryBeanFailureAnalyzerTests {\n\n\t@Test\n\tvoid missingServletWebServerFactoryBeanFailure() {\n\t\tApplicationContextException failure = createFailure(new ServletWebServerApplicationContext());\n\t\tassertThat(failure).isNotNull();\n\t\tFailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).isEqualTo(\"Web application could not be started as there was no \"\n\t\t\t\t+ ServletWebServerFactory.class.getName() + \" bean defined in the context.\");\n\t\tassertThat(analysis.getAction()).isEqualTo(\n\t\t\t\t\"Check your application's dependencies for a supported servlet web server.\\nCheck the configured web \"\n\t\t\t\t\t\t+ \"application type.\");\n\t}\n\n\t@Test\n\tvoid missingReactiveWebServerFactoryBeanFailure() {\n\t\tApplicationContextException failure = createFailure(new ReactiveWebServerApplicationContext());\n\t\tFailureAnalysis analysis = new MissingWebServerFactoryBeanFailureAnalyzer().analyze(failure);\n\t\tassertThat(analysis).isNotNull();\n\t\tassertThat(analysis.getDescription()).isEqualTo(\"Web application could not be started as there was no \"\n\t\t\t\t+ ReactiveWebServerFactory.class.getName() + \" bean defined in the context.\");\n\t\tassertThat(analysis.getAction()).isEqualTo(\n\t\t\t\t\"Check your application's dependencies for a supported reactive web server.\\nCheck the configured web \"\n\t\t\t\t\t\t+ \"application type.\");\n\t}\n\n\tprivate ApplicationContextException createFailure(ConfigurableApplicationContext context) {\n\t\ttry {\n\t\t\tcontext.refresh();\n\t\t\tcontext.close();\n\t\t\tthrow new AssertionError(\"Should not be reached\");\n\t\t}\n\t\tcatch (ApplicationContextException ex) {\n\t\t\treturn ex;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/context/SpringBootTestRandomPortContextCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.test.context.support.TestPropertySourceUtils;\nimport org.springframework.util.PlaceholderResolutionException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link SpringBootTestRandomPortContextCustomizer}.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\nclass SpringBootTestRandomPortContextCustomizerTests {\n\n\tprivate final SpringBootTestRandomPortContextCustomizer customizer = new SpringBootTestRandomPortContextCustomizer();\n\n\tprivate MockEnvironment environment;\n\n\tprivate MutablePropertySources propertySources;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.environment = new MockEnvironment();\n\t\tthis.propertySources = this.environment.getPropertySources();\n\t}\n\n\t@Test\n\tvoid postProcessWhenServerAndManagementPortIsZeroInTestPropertySource() {\n\t\taddTestPropertySource(\"0\", \"0\");\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"0\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenServerPortAndManagementPortIsZeroInDifferentPropertySources() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"management.server.port\", \"0\");\n\t\tthis.propertySources.addLast(new MapPropertySource(\"other\", source));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"0\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerAndTestManagementPortAreNonZero() {\n\t\taddTestPropertySource(\"8080\", \"8081\");\n\t\tthis.environment.setProperty(\"server.port\", \"8080\");\n\t\tthis.environment.setProperty(\"management.server.port\", \"8081\");\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"8080\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"8081\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndTestManagementPortIsNotNull() {\n\t\taddTestPropertySource(\"0\", \"8080\");\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"8080\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndManagementPortIsNull() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isNull();\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndSameInProduction() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tMap<String, Object> other = new HashMap<>();\n\t\tother.put(\"server.port\", \"8081\");\n\t\tother.put(\"management.server.port\", \"8081\");\n\t\tMapPropertySource otherSource = new MapPropertySource(\"other\", other);\n\t\tthis.propertySources.addLast(otherSource);\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDefaultSameInProduction() {\n\t\t// mgmt port is 8080 which means it's on the same port as main server since that\n\t\t// is null in app properties\n\t\taddTestPropertySource(\"0\", null);\n\t\tthis.propertySources\n\t\t\t.addLast(new MapPropertySource(\"other\", Collections.singletonMap(\"management.server.port\", \"8080\")));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEmpty();\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndManagementPortIsNotNullAndDifferentInProduction() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tthis.propertySources\n\t\t\t.addLast(new MapPropertySource(\"other\", Collections.singletonMap(\"management.server.port\", \"8081\")));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"0\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndManagementPortMinusOne() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tthis.propertySources\n\t\t\t.addLast(new MapPropertySource(\"other\", Collections.singletonMap(\"management.server.port\", \"-1\")));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"-1\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenTestServerPortIsZeroAndManagementPortIsAnInteger() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tthis.propertySources\n\t\t\t.addLast(new MapPropertySource(\"other\", Collections.singletonMap(\"management.server.port\", 8081)));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"0\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenManagementServerPortPlaceholderPresentShouldResolvePlaceholder() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tMapPropertySource testPropertySource = (MapPropertySource) this.propertySources\n\t\t\t.get(TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);\n\t\tassertThat(testPropertySource).isNotNull();\n\t\ttestPropertySource.getSource().put(\"port\", \"9090\");\n\t\tthis.propertySources\n\t\t\t.addLast(new MapPropertySource(\"other\", Collections.singletonMap(\"management.server.port\", \"${port}\")));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"0\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenManagementServerPortPlaceholderAbsentShouldFail() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tthis.propertySources\n\t\t\t.addLast(new MapPropertySource(\"other\", Collections.singletonMap(\"management.server.port\", \"${port}\")));\n\t\tassertThatExceptionOfType(PlaceholderResolutionException.class)\n\t\t\t.isThrownBy(() -> this.customizer.postProcessEnvironment(this.environment))\n\t\t\t.withMessage(\"Could not resolve placeholder 'port' in value \\\"${port}\\\"\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenServerPortPlaceholderPresentShouldResolvePlaceholder() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tMapPropertySource testPropertySource = (MapPropertySource) this.propertySources\n\t\t\t.get(TestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME);\n\t\tassertThat(testPropertySource).isNotNull();\n\t\ttestPropertySource.getSource().put(\"port\", \"8080\");\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"server.port\", \"${port}\");\n\t\tsource.put(\"management.server.port\", \"9090\");\n\t\tthis.propertySources.addLast(new MapPropertySource(\"other\", source));\n\t\tthis.customizer.postProcessEnvironment(this.environment);\n\t\tassertThat(this.environment.getProperty(\"server.port\")).isEqualTo(\"0\");\n\t\tassertThat(this.environment.getProperty(\"management.server.port\")).isEqualTo(\"0\");\n\t}\n\n\t@Test\n\tvoid postProcessWhenServerPortPlaceholderAbsentShouldFail() {\n\t\taddTestPropertySource(\"0\", null);\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"server.port\", \"${port}\");\n\t\tsource.put(\"management.server.port\", \"9090\");\n\t\tthis.propertySources.addLast(new MapPropertySource(\"other\", source));\n\t\tassertThatExceptionOfType(PlaceholderResolutionException.class)\n\t\t\t.isThrownBy(() -> this.customizer.postProcessEnvironment(this.environment))\n\t\t\t.withMessage(\"Could not resolve placeholder 'port' in value \\\"${port}\\\"\");\n\t}\n\n\tprivate void addTestPropertySource(String serverPort, @Nullable String managementPort) {\n\t\tMap<String, Object> source = new HashMap<>();\n\t\tsource.put(\"server.port\", serverPort);\n\t\tsource.put(\"management.server.port\", managementPort);\n\t\tMapPropertySource inlineTestSource = new MapPropertySource(\n\t\t\t\tTestPropertySourceUtils.INLINED_PROPERTIES_PROPERTY_SOURCE_NAME, source);\n\t\tthis.propertySources.addFirst(inlineTestSource);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/context/WebServerApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass WebServerApplicationContextTests {\n\n\t@Test\n\tvoid hasServerNamespaceWhenContextIsNotWebServerApplicationContextReturnsFalse() {\n\t\tApplicationContext context = mock(ApplicationContext.class);\n\t\tassertThat(WebServerApplicationContext.hasServerNamespace(context, \"test\")).isFalse();\n\t}\n\n\t@Test\n\tvoid hasServerNamespaceWhenContextIsWebServerApplicationContextAndNamespaceDoesNotMatchReturnsFalse() {\n\t\tApplicationContext context = mock(WebServerApplicationContext.class);\n\t\tassertThat(WebServerApplicationContext.hasServerNamespace(context, \"test\")).isFalse();\n\t}\n\n\t@Test\n\tvoid hasServerNamespaceWhenContextIsWebServerApplicationContextAndNamespaceMatchesReturnsTrue() {\n\t\tWebServerApplicationContext context = mock(WebServerApplicationContext.class);\n\t\tgiven(context.getServerNamespace()).willReturn(\"test\");\n\t\tassertThat(WebServerApplicationContext.hasServerNamespace(context, \"test\")).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/context/WebServerPortFileWriterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.context;\n\nimport java.io.File;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.contentOf;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests {@link WebServerPortFileWriter}.\n *\n * @author David Liu\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass WebServerPortFileWriterTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid reset() {\n\t\tSystem.clearProperty(\"PORTFILE\");\n\t}\n\n\t@Test\n\tvoid createPortFile() {\n\t\tFile file = new File(this.tempDir, \"port.file\");\n\t\tWebServerPortFileWriter listener = new WebServerPortFileWriter(file);\n\t\tlistener.onApplicationEvent(mockEvent(\"\", 8080));\n\t\tassertThat(contentOf(file)).isEqualTo(\"8080\");\n\t}\n\n\t@Test\n\tvoid overridePortFileWithDefault() {\n\t\tSystem.setProperty(\"PORTFILE\", new File(this.tempDir, \"port.file\").getAbsolutePath());\n\t\tWebServerPortFileWriter listener = new WebServerPortFileWriter();\n\t\tlistener.onApplicationEvent(mockEvent(\"\", 8080));\n\t\tString content = contentOf(new File(System.getProperty(\"PORTFILE\")));\n\t\tassertThat(content).isEqualTo(\"8080\");\n\t}\n\n\t@Test\n\tvoid overridePortFileWithExplicitFile() {\n\t\tFile file = new File(this.tempDir, \"port.file\");\n\t\tSystem.setProperty(\"PORTFILE\", new File(this.tempDir, \"override.file\").getAbsolutePath());\n\t\tWebServerPortFileWriter listener = new WebServerPortFileWriter(file);\n\t\tlistener.onApplicationEvent(mockEvent(\"\", 8080));\n\t\tString content = contentOf(new File(System.getProperty(\"PORTFILE\")));\n\t\tassertThat(content).isEqualTo(\"8080\");\n\t}\n\n\t@Test\n\tvoid createManagementPortFile() {\n\t\tFile file = new File(this.tempDir, \"port.file\");\n\t\tWebServerPortFileWriter listener = new WebServerPortFileWriter(file);\n\t\tlistener.onApplicationEvent(mockEvent(\"\", 8080));\n\t\tlistener.onApplicationEvent(mockEvent(\"management\", 9090));\n\t\tassertThat(contentOf(file)).isEqualTo(\"8080\");\n\t\tString managementFile = file.getName();\n\t\tString extension = StringUtils.getFilenameExtension(managementFile);\n\t\tassertThat(extension).isNotNull();\n\t\tmanagementFile = managementFile.substring(0, managementFile.length() - extension.length() - 1);\n\t\tmanagementFile = managementFile + \"-management.\" + StringUtils.getFilenameExtension(file.getName());\n\t\tString content = contentOf(new File(file.getParentFile(), managementFile));\n\t\tassertThat(content).isEqualTo(\"9090\");\n\t\tassertThat(collectFileNames(file.getParentFile())).contains(managementFile);\n\t}\n\n\t@Test\n\tvoid createUpperCaseManagementPortFile() {\n\t\tFile file = new File(this.tempDir, \"port.file\");\n\t\tfile = new File(file.getParentFile(), file.getName().toUpperCase(Locale.ENGLISH));\n\t\tWebServerPortFileWriter listener = new WebServerPortFileWriter(file);\n\t\tlistener.onApplicationEvent(mockEvent(\"management\", 9090));\n\t\tString managementFile = file.getName();\n\t\tString extension = StringUtils.getFilenameExtension(managementFile);\n\t\tassertThat(extension).isNotNull();\n\t\tmanagementFile = managementFile.substring(0, managementFile.length() - extension.length() - 1);\n\t\tmanagementFile = managementFile + \"-MANAGEMENT.\" + StringUtils.getFilenameExtension(file.getName());\n\t\tString content = contentOf(new File(file.getParentFile(), managementFile));\n\t\tassertThat(content).isEqualTo(\"9090\");\n\t\tassertThat(collectFileNames(file.getParentFile())).contains(managementFile);\n\t}\n\n\t@Test\n\tvoid getPortFileWhenPortFileNameDoesNotHaveExtension() {\n\t\tFile file = new File(this.tempDir, \"portfile\");\n\t\tWebServerPortFileWriter listener = new WebServerPortFileWriter(file);\n\t\tWebServerApplicationContext applicationContext = mock(WebServerApplicationContext.class);\n\t\tgiven(applicationContext.getServerNamespace()).willReturn(\"management\");\n\t\tassertThat(listener.getPortFile(applicationContext).getName()).isEqualTo(\"portfile-management\");\n\t}\n\n\tprivate WebServerInitializedEvent mockEvent(String namespace, int port) {\n\t\tWebServer webServer = mock(WebServer.class);\n\t\tgiven(webServer.getPort()).willReturn(port);\n\t\tWebServerApplicationContext applicationContext = mock(WebServerApplicationContext.class);\n\t\tgiven(applicationContext.getServerNamespace()).willReturn(namespace);\n\t\tgiven(applicationContext.getWebServer()).willReturn(webServer);\n\t\tWebServerInitializedEvent event = mock(WebServerInitializedEvent.class);\n\t\tgiven(event.getApplicationContext()).willReturn(applicationContext);\n\t\tgiven(event.getWebServer()).willReturn(webServer);\n\t\treturn event;\n\t}\n\n\tprivate Set<String> collectFileNames(File directory) {\n\t\tSet<String> names = new HashSet<>();\n\t\tif (directory.isDirectory()) {\n\t\t\tfor (File file : directory.listFiles()) {\n\t\t\t\tnames.add(file.getName());\n\t\t\t}\n\t\t}\n\t\treturn names;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/reactive/context/AnnotationConfigReactiveWebServerApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.context.WebServerManager.DelayedInitializationHttpHandler;\nimport org.springframework.boot.web.server.reactive.context.config.ExampleReactiveWebServerApplicationConfiguration;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.ApplicationEventMulticaster;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.event.SimpleApplicationEventMulticaster;\nimport org.springframework.http.server.reactive.HttpHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link AnnotationConfigReactiveWebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass AnnotationConfigReactiveWebServerApplicationContextTests {\n\n\tprivate @Nullable AnnotationConfigReactiveWebServerApplicationContext context;\n\n\t@Test\n\tvoid createFromScan() {\n\t\tthis.context = new AnnotationConfigReactiveWebServerApplicationContext(\n\t\t\t\tExampleReactiveWebServerApplicationConfiguration.class.getPackage().getName());\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid createFromConfigClass() {\n\t\tthis.context = new AnnotationConfigReactiveWebServerApplicationContext(\n\t\t\t\tExampleReactiveWebServerApplicationConfiguration.class);\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid registerAndRefresh() {\n\t\tthis.context = new AnnotationConfigReactiveWebServerApplicationContext();\n\t\tthis.context.register(ExampleReactiveWebServerApplicationConfiguration.class);\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid multipleRegistersAndRefresh() {\n\t\tthis.context = new AnnotationConfigReactiveWebServerApplicationContext();\n\t\tthis.context.register(WebServerConfiguration.class);\n\t\tthis.context.register(HttpHandlerConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBeansOfType(WebServerConfiguration.class)).hasSize(1);\n\t\tassertThat(this.context.getBeansOfType(HttpHandlerConfiguration.class)).hasSize(1);\n\t}\n\n\t@Test\n\tvoid scanAndRefresh() {\n\t\tthis.context = new AnnotationConfigReactiveWebServerApplicationContext();\n\t\tthis.context.scan(ExampleReactiveWebServerApplicationConfiguration.class.getPackage().getName());\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid httpHandlerInitialization() {\n\t\t// gh-14666\n\t\tthis.context = new AnnotationConfigReactiveWebServerApplicationContext(InitializationTestConfig.class);\n\t\tverifyContext();\n\t}\n\n\tprivate void verifyContext() {\n\t\tassertThat(this.context).isNotNull();\n\t\tMockReactiveWebServerFactory factory = this.context.getBean(MockReactiveWebServerFactory.class);\n\t\tHttpHandler expectedHandler = this.context.getBean(HttpHandler.class);\n\t\tHttpHandler actualHandler = factory.getWebServer().getHttpHandler();\n\t\tif (actualHandler instanceof DelayedInitializationHttpHandler delayedHandler) {\n\t\t\tactualHandler = delayedHandler.getHandler();\n\t\t}\n\t\tassertThat(actualHandler).isEqualTo(expectedHandler);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerConfiguration {\n\n\t\t@Bean\n\t\tReactiveWebServerFactory webServerFactory() {\n\t\t\treturn new MockReactiveWebServerFactory();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpHandlerConfiguration {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn mock(HttpHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class InitializationTestConfig {\n\n\t\tprivate static boolean addedListener;\n\n\t\t@Bean\n\t\tReactiveWebServerFactory webServerFactory() {\n\t\t\treturn new MockReactiveWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\tif (!addedListener) {\n\t\t\t\tthrow new RuntimeException(\n\t\t\t\t\t\t\"Handlers should be added after listeners, we're being initialized too early!\");\n\t\t\t}\n\t\t\treturn mock(HttpHandler.class);\n\t\t}\n\n\t\t@Bean\n\t\tListener listener() {\n\t\t\treturn new Listener();\n\t\t}\n\n\t\t@Bean\n\t\tApplicationEventMulticaster applicationEventMulticaster() {\n\t\t\treturn new SimpleApplicationEventMulticaster() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addApplicationListenerBean(String listenerBeanName) {\n\t\t\t\t\tsuper.addApplicationListenerBean(listenerBeanName);\n\t\t\t\t\tif (\"listener\".equals(listenerBeanName)) {\n\t\t\t\t\t\taddedListener = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\tstatic class Listener implements ApplicationListener<ContextRefreshedEvent> {\n\n\t\t\t@Override\n\t\t\tpublic void onApplicationEvent(ContextRefreshedEvent event) {\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/reactive/context/ApplicationReactiveWebEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport org.springframework.boot.AbstractApplicationEnvironmentTests;\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * Tests for {@link ApplicationReactiveWebEnvironment}.\n *\n * @author Phillip Webb\n */\nclass ApplicationReactiveWebEnvironmentTests extends AbstractApplicationEnvironmentTests {\n\n\t@Override\n\tprotected StandardEnvironment createEnvironment() {\n\t\treturn new ApplicationReactiveWebEnvironment();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.List;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.availability.ReadinessState;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.http.server.reactive.HttpHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link ReactiveWebServerApplicationContext}.\n *\n * @author Andy Wilkinson\n */\nclass ReactiveWebServerApplicationContextTests {\n\n\tprivate final ReactiveWebServerApplicationContext context = new ReactiveWebServerApplicationContext();\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid whenThereIsNoWebServerFactoryBeanThenContextRefreshWillFail() {\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Unable to start ReactiveWebServerApplicationContext due to missing ReactiveWebServerFactory bean\");\n\t}\n\n\t@Test\n\tvoid whenThereIsNoHttpHandlerBeanThenContextRefreshWillFail() {\n\t\taddWebServerFactoryBean();\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\"Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean\");\n\t}\n\n\t@Test\n\tvoid whenThereAreMultipleWebServerFactoryBeansThenContextRefreshWillFail() {\n\t\taddWebServerFactoryBean();\n\t\taddWebServerFactoryBean(\"anotherWebServerFactory\");\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\n\t\t\t\t\t\"Unable to start ReactiveWebApplicationContext due to multiple ReactiveWebServerFactory beans\");\n\t}\n\n\t@Test\n\tvoid whenThereAreMultipleHttpHandlerBeansThenContextRefreshWillFail() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean(\"httpHandler1\");\n\t\taddHttpHandlerBean(\"httpHandler2\");\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\"Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans\");\n\t}\n\n\t@Test\n\tvoid whenContextIsRefreshedThenReactiveWebServerInitializedEventIsPublished() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tTestApplicationListener listener = new TestApplicationListener();\n\t\tthis.context.addApplicationListener(listener);\n\t\tthis.context.refresh();\n\t\tList<ApplicationEvent> events = listener.receivedEvents();\n\t\tassertThat(events).hasSize(2)\n\t\t\t.extracting(\"class\")\n\t\t\t.containsExactly(ReactiveWebServerInitializedEvent.class, ContextRefreshedEvent.class);\n\t\tReactiveWebServerInitializedEvent initializedEvent = (ReactiveWebServerInitializedEvent) events.get(0);\n\t\tassertThat(initializedEvent.getSource().getPort()).isGreaterThanOrEqualTo(0);\n\t\tassertThat(initializedEvent.getApplicationContext()).isEqualTo(this.context);\n\t}\n\n\t@Test\n\tvoid whenContextIsRefreshedThenLocalServerPortIsAvailableFromTheEnvironment() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tnew ServerPortInfoApplicationContextInitializer().initialize(this.context);\n\t\tthis.context.refresh();\n\t\tConfigurableEnvironment environment = this.context.getEnvironment();\n\t\tassertThat(environment.containsProperty(\"local.server.port\")).isTrue();\n\t\tassertThat(environment.getProperty(\"local.server.port\")).isEqualTo(\"8080\");\n\t}\n\n\t@Test\n\tvoid whenContextRefreshFailedThenWebServerIsStoppedAndDestroyed() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh);\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tthen(webServer).should(times(2)).stop();\n\t\tthen(webServer).should().destroy();\n\t}\n\n\t@Test\n\tvoid whenContextRefreshFailedThenWebServerStopFailedCatchStopException() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class, () -> {\n\t\t\twillThrow(new RuntimeException(\"WebServer has failed to stop\")).willCallRealMethod()\n\t\t\t\t.given(this.context.getWebServer())\n\t\t\t\t.stop();\n\t\t\treturn new RefreshFailure();\n\t\t}));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh)\n\t\t\t.withStackTraceContaining(\"WebServer has failed to stop\");\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tthen(webServer).should().stop();\n\t\tthen(webServer).should(never()).destroy();\n\t}\n\n\t@Test\n\tvoid whenContextRefreshFailedThenWebServerIsStoppedAndDestroyFailedCatchDestroyException() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class, () -> {\n\t\t\twillThrow(new RuntimeException(\"WebServer has failed to destroy\")).willCallRealMethod()\n\t\t\t\t.given(this.context.getWebServer())\n\t\t\t\t.destroy();\n\t\t\treturn new RefreshFailure();\n\t\t}));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh)\n\t\t\t.withStackTraceContaining(\"WebServer has failed to destroy\");\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tthen(webServer).should().stop();\n\t\tthen(webServer).should().destroy();\n\t}\n\n\t@Test\n\tvoid whenContextIsClosedThenWebServerIsStoppedAndDestroyed() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tthis.context.refresh();\n\t\tMockReactiveWebServerFactory factory = this.context.getBean(MockReactiveWebServerFactory.class);\n\t\tthis.context.close();\n\t\tthen(factory.getWebServer()).should(times(2)).stop();\n\t\tthen(factory.getWebServer()).should().destroy();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid whenContextIsClosedThenApplicationAvailabilityChangesToRefusingTraffic() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tTestApplicationListener listener = new TestApplicationListener();\n\t\tthis.context.refresh();\n\t\tthis.context.addApplicationListener(listener);\n\t\tthis.context.close();\n\t\tList<ApplicationEvent> events = listener.receivedEvents();\n\t\tassertThat(events).hasSize(2)\n\t\t\t.extracting(\"class\")\n\t\t\t.contains(AvailabilityChangeEvent.class, ContextClosedEvent.class);\n\t\tassertThat(((AvailabilityChangeEvent<ReadinessState>) events.get(0)).getState())\n\t\t\t.isEqualTo(ReadinessState.REFUSING_TRAFFIC);\n\t}\n\n\t@Test\n\tvoid whenContextIsNotActiveThenCloseDoesNotChangeTheApplicationAvailability() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tTestApplicationListener listener = new TestApplicationListener();\n\t\tthis.context.addApplicationListener(listener);\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh);\n\t\tthis.context.close();\n\t\tassertThat(listener.receivedEvents()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenTheContextIsRefreshedThenASubsequentRefreshAttemptWillFail() {\n\t\taddWebServerFactoryBean();\n\t\taddHttpHandlerBean();\n\t\tthis.context.refresh();\n\t\tassertThatIllegalStateException().isThrownBy(this.context::refresh)\n\t\t\t.withMessageContaining(\"multiple refresh attempts\");\n\t}\n\n\tprivate void addHttpHandlerBean() {\n\t\taddHttpHandlerBean(\"httpHandler\");\n\t}\n\n\tprivate void addHttpHandlerBean(String beanName) {\n\t\tthis.context.registerBeanDefinition(beanName,\n\t\t\t\tnew RootBeanDefinition(HttpHandler.class, () -> (request, response) -> Mono.empty()));\n\t}\n\n\tprivate void addWebServerFactoryBean() {\n\t\taddWebServerFactoryBean(\"webServerFactory\");\n\t}\n\n\tprivate void addWebServerFactoryBean(String beanName) {\n\t\tthis.context.registerBeanDefinition(beanName, new RootBeanDefinition(MockReactiveWebServerFactory.class));\n\t}\n\n\tstatic class TestApplicationListener implements ApplicationListener<ApplicationEvent> {\n\n\t\tprivate final Deque<ApplicationEvent> events = new ArrayDeque<>();\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tthis.events.add(event);\n\t\t}\n\n\t\tList<ApplicationEvent> receivedEvents() {\n\t\t\tList<ApplicationEvent> receivedEvents = new ArrayList<>();\n\t\t\twhile (!this.events.isEmpty()) {\n\t\t\t\treceivedEvents.add(this.events.pollFirst());\n\t\t\t}\n\t\t\treturn receivedEvents;\n\t\t}\n\n\t}\n\n\tstatic class RefreshFailure {\n\n\t\tRefreshFailure() {\n\t\t\tthrow new RuntimeException(\"Fail refresh\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/reactive/context/config/ExampleReactiveWebServerApplicationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive.context.config;\n\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.reactive.HttpHandler;\n\nimport static org.mockito.Mockito.mock;\n\n/**\n * Example {@code @Configuration} for use with\n * {@code AnnotationConfigReactiveWebServerApplicationContextTests}.\n *\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\npublic class ExampleReactiveWebServerApplicationConfiguration {\n\n\t@Bean\n\tpublic MockReactiveWebServerFactory webServerFactory() {\n\t\treturn new MockReactiveWebServerFactory();\n\t}\n\n\t@Bean\n\tpublic HttpHandler httpHandler() {\n\t\treturn mock(HttpHandler.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/reactive/context/config/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.web.server.reactive.context.config;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/CookieSameSiteSupplierTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.util.function.Supplier;\nimport java.util.regex.Pattern;\n\nimport jakarta.servlet.http.Cookie;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.server.Cookie.SameSite;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link CookieSameSiteSupplier}.\n *\n * @author Phillip Webb\n */\nclass CookieSameSiteSupplierTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid whenHasNameWhenNameIsNullThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.whenHasName((String) null))\n\t\t\t.withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\tvoid whenHasNameWhenNameIsEmptyThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.whenHasName(\"\"))\n\t\t\t.withMessage(\"'name' must not be empty\");\n\t}\n\n\t@Test\n\tvoid whenHasNameWhenNameMatchesCallsGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThat(supplier.whenHasName(\"test\").getSameSite(new Cookie(\"test\", \"x\"))).isEqualTo(SameSite.LAX);\n\t}\n\n\t@Test\n\tvoid whenHasNameWhenNameDoesNotMatchDoesNotCallGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> fail(\"Supplier Called\");\n\t\tassertThat(supplier.whenHasName(\"test\").getSameSite(new Cookie(\"tset\", \"x\"))).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid whenHasSuppliedNameWhenNameIsNullThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.whenHasName((Supplier<String>) null))\n\t\t\t.withMessage(\"'nameSupplier' must not be null\");\n\t}\n\n\t@Test\n\tvoid whenHasSuppliedNameWhenNameMatchesCallsGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThat(supplier.whenHasName(() -> \"test\").getSameSite(new Cookie(\"test\", \"x\"))).isEqualTo(SameSite.LAX);\n\t}\n\n\t@Test\n\tvoid whenHasSuppliedNameWhenNameDoesNotMatchDoesNotCallGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> fail(\"Supplier Called\");\n\t\tassertThat(supplier.whenHasName(() -> \"test\").getSameSite(new Cookie(\"tset\", \"x\"))).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid whenHasNameMatchingRegexWhenRegexIsNullThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.whenHasNameMatching((String) null))\n\t\t\t.withMessage(\"'regex' must not be empty\");\n\t}\n\n\t@Test\n\tvoid whenHasNameMatchingRegexWhenRegexIsEmptyThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.whenHasNameMatching(\"\"))\n\t\t\t.withMessage(\"'regex' must not be empty\");\n\t}\n\n\t@Test\n\tvoid whenHasNameMatchingRegexWhenNameMatchesCallsGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThat(supplier.whenHasNameMatching(\"te.*\").getSameSite(new Cookie(\"test\", \"x\"))).isEqualTo(SameSite.LAX);\n\t}\n\n\t@Test\n\tvoid whenHasNameMatchingRegexWhenNameDoesNotMatchDoesNotCallGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> fail(\"Supplier Called\");\n\t\tassertThat(supplier.whenHasNameMatching(\"te.*\").getSameSite(new Cookie(\"tset\", \"x\"))).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid whenHasNameMatchingPatternWhenPatternIsNullThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.whenHasNameMatching((Pattern) null))\n\t\t\t.withMessage(\"'pattern' must not be null\");\n\t}\n\n\t@Test\n\tvoid whenHasNameMatchingPatternWhenNameMatchesCallsGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThat(supplier.whenHasNameMatching(Pattern.compile(\"te.*\")).getSameSite(new Cookie(\"test\", \"x\")))\n\t\t\t.isEqualTo(SameSite.LAX);\n\t}\n\n\t@Test\n\tvoid whenHasNameMatchingPatternWhenNameDoesNotMatchDoesNotCallGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> fail(\"Supplier Called\");\n\t\tassertThat(supplier.whenHasNameMatching(Pattern.compile(\"te.*\")).getSameSite(new Cookie(\"tset\", \"x\"))).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid whenWhenPredicateIsNullThrowsException() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> supplier.when(null))\n\t\t\t.withMessage(\"'predicate' must not be null\");\n\t}\n\n\t@Test\n\tvoid whenWhenPredicateMatchesCallsGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> SameSite.LAX;\n\t\tassertThat(supplier.when((cookie) -> cookie.getName().equals(\"test\")).getSameSite(new Cookie(\"test\", \"x\")))\n\t\t\t.isEqualTo(SameSite.LAX);\n\t}\n\n\t@Test\n\tvoid whenWhenPredicateDoesNotMatchDoesNotCallGetSameSite() {\n\t\tCookieSameSiteSupplier supplier = (cookie) -> fail(\"Supplier Called\");\n\t\tassertThat(supplier.when((cookie) -> cookie.getName().equals(\"test\")).getSameSite(new Cookie(\"tset\", \"x\")))\n\t\t\t.isNull();\n\t}\n\n\t@Test\n\tvoid ofNoneSuppliesNone() {\n\t\tassertThat(CookieSameSiteSupplier.ofNone().getSameSite(new Cookie(\"test\", \"x\"))).isEqualTo(SameSite.NONE);\n\t}\n\n\t@Test\n\tvoid ofLaxSuppliesLax() {\n\t\tassertThat(CookieSameSiteSupplier.ofLax().getSameSite(new Cookie(\"test\", \"x\"))).isEqualTo(SameSite.LAX);\n\t}\n\n\t@Test\n\tvoid ofStrictSuppliesStrict() {\n\t\tassertThat(CookieSameSiteSupplier.ofStrict().getSameSite(new Cookie(\"test\", \"x\"))).isEqualTo(SameSite.STRICT);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid ofWhenNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> CookieSameSiteSupplier.of(null))\n\t\t\t.withMessage(\"'sameSite' must not be null\");\n\t}\n\n\t@Test\n\tvoid ofSuppliesValue() {\n\t\tassertThat(CookieSameSiteSupplier.of(SameSite.STRICT).getSameSite(new Cookie(\"test\", \"x\")))\n\t\t\t.isEqualTo(SameSite.STRICT);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/DocumentRootTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.cert.Certificate;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DocumentRoot}.\n *\n * @author Phillip Webb\n */\nclass DocumentRootTests {\n\n\tprivate static final Log logger = LogFactory.getLog(DocumentRootTests.class);\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\tprivate final DocumentRoot documentRoot = new DocumentRoot(logger);\n\n\t@Test\n\tvoid explodedWarFileDocumentRootWhenRunningFromExplodedWar() throws Exception {\n\t\tFile codeSourceFile = new File(this.tempDir, \"test.war/WEB-INF/lib/spring-boot.jar\");\n\t\tcodeSourceFile.getParentFile().mkdirs();\n\t\tcodeSourceFile.createNewFile();\n\t\tFile directory = this.documentRoot.getExplodedWarFileDocumentRoot(codeSourceFile);\n\t\tassertThat(directory).isEqualTo(codeSourceFile.getParentFile().getParentFile().getParentFile());\n\t}\n\n\t@Test\n\tvoid explodedWarFileDocumentRootWhenRunningFromPackagedWar() {\n\t\tFile codeSourceFile = new File(this.tempDir, \"test.war\");\n\t\tFile directory = this.documentRoot.getExplodedWarFileDocumentRoot(codeSourceFile);\n\t\tassertThat(directory).isNull();\n\t}\n\n\t@Test\n\tvoid codeSourceArchivePath() throws Exception {\n\t\tCodeSource codeSource = new CodeSource(new URL(\"file\", \"\", \"/some/test/path/\"), (Certificate[]) null);\n\t\tFile codeSourceArchive = this.documentRoot.getCodeSourceArchive(codeSource);\n\t\tassertThat(codeSourceArchive).isEqualTo(new File(\"/some/test/path/\"));\n\t}\n\n\t@Test\n\tvoid codeSourceArchivePathContainingSpaces() throws Exception {\n\t\tCodeSource codeSource = new CodeSource(new URL(\"file\", \"\", \"/test/path/with%20space/\"), (Certificate[]) null);\n\t\tFile codeSourceArchive = this.documentRoot.getCodeSourceArchive(codeSource);\n\t\tassertThat(codeSourceArchive).isEqualTo(new File(\"/test/path/with space/\"));\n\t}\n\n\t@Test\n\tvoid getValidDirectoryWhenHasSrcMainWebApp() {\n\t\tMap<String, String> systemEnvironment = new HashMap<>();\n\t\tFile directory = new File(this.tempDir, \"src/main/webapp\");\n\t\tdirectory.mkdirs();\n\t\tDocumentRoot documentRoot = new DocumentRoot(logger, this.tempDir, systemEnvironment::get);\n\t\tassertThat(documentRoot.getValidDirectory()).isEqualTo(directory);\n\t}\n\n\t@Test\n\tvoid getValidDirectoryWhenHasCustomSrcMainWebApp() {\n\t\tMap<String, String> systemEnvironment = new HashMap<>();\n\t\tsystemEnvironment.put(\"WAR_SOURCE_DIRECTORY\", \"src/main/unusual\");\n\t\tFile directory = new File(this.tempDir, \"src/main/unusual\");\n\t\tdirectory.mkdirs();\n\t\tDocumentRoot documentRoot = new DocumentRoot(logger, this.tempDir, systemEnvironment::get);\n\t\tassertThat(documentRoot.getValidDirectory()).isEqualTo(directory);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/StaticResourceJarsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.JarURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLStreamHandler;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarOutputStream;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link StaticResourceJars}.\n *\n * @author Rupert Madden-Abbott\n * @author Andy Wilkinson\n */\nclass StaticResourceJarsTests {\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile tempDir;\n\n\t@Test\n\tvoid includeJarWithStaticResources() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test-resources.jar\");\n\t\tList<URL> staticResourceJarUrls = new StaticResourceJars().getUrlsFrom(jarFile.toURI().toURL());\n\t\tassertThat(staticResourceJarUrls).hasSize(1);\n\t}\n\n\t@Test\n\tvoid includeJarWithStaticResourcesWithUrlEncodedSpaces() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test resources.jar\");\n\t\tList<URL> staticResourceJarUrls = new StaticResourceJars().getUrlsFrom(jarFile.toURI().toURL());\n\t\tassertThat(staticResourceJarUrls).hasSize(1);\n\t}\n\n\t@Test\n\tvoid includeJarWithStaticResourcesWithPlusInItsPath() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test + resources.jar\");\n\t\tList<URL> staticResourceJarUrls = new StaticResourceJars().getUrlsFrom(jarFile.toURI().toURL());\n\t\tassertThat(staticResourceJarUrls).hasSize(1);\n\t}\n\n\t@Test\n\tvoid excludeJarWithoutStaticResources() throws Exception {\n\t\tFile jarFile = createJar(\"dependency.jar\");\n\t\tList<URL> staticResourceJarUrls = new StaticResourceJars().getUrlsFrom(jarFile.toURI().toURL());\n\t\tassertThat(staticResourceJarUrls).isEmpty();\n\t}\n\n\t@Test\n\t@DisabledForJreRange(min = JRE.JAVA_25) // Requires -Djdk.net.file.ftpfallback=true\n\tvoid uncPathsAreTolerated() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test-resources.jar\");\n\t\tList<URL> staticResourceJarUrls = new StaticResourceJars().getUrlsFrom(jarFile.toURI().toURL(),\n\t\t\t\tnew URL(\"file://unc.example.com/test.jar\"));\n\t\tassertThat(staticResourceJarUrls).hasSize(1);\n\t}\n\n\t@Test\n\tvoid ignoreWildcardUrls() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test-resources.jar\");\n\t\tURL folderUrl = jarFile.getParentFile().toURI().toURL();\n\t\tURL wildcardUrl = new URL(folderUrl + \"*.jar\");\n\t\tList<URL> staticResourceJarUrls = new StaticResourceJars().getUrlsFrom(wildcardUrl);\n\t\tassertThat(staticResourceJarUrls).isEmpty();\n\t}\n\n\t@Test\n\tvoid doesNotCloseJarFromCachedConnection() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test-resources.jar\");\n\t\tTrackedURLStreamHandler handler = new TrackedURLStreamHandler(true);\n\t\tURL url = new URL(\"jar\", null, 0, jarFile.toURI().toURL() + \"!/\", handler);\n\t\ttry {\n\t\t\tnew StaticResourceJars().getUrlsFrom(url);\n\t\t\tassertThatNoException().isThrownBy(() -> {\n\t\t\t\tJarURLConnection connection = (JarURLConnection) handler.getConnection();\n\t\t\t\tassertThat(connection).isNotNull();\n\t\t\t\tconnection.getJarFile().getComment();\n\t\t\t});\n\t\t}\n\t\tfinally {\n\t\t\tJarURLConnection connection = (JarURLConnection) handler.getConnection();\n\t\t\tassertThat(connection).isNotNull();\n\t\t\tconnection.getJarFile().close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid closesJarFromNonCachedConnection() throws Exception {\n\t\tFile jarFile = createResourcesJar(\"test-resources.jar\");\n\t\tTrackedURLStreamHandler handler = new TrackedURLStreamHandler(false);\n\t\tURL url = new URL(\"jar\", null, 0, jarFile.toURI().toURL() + \"!/\", handler);\n\t\tnew StaticResourceJars().getUrlsFrom(url);\n\t\tassertThatIllegalStateException().isThrownBy(() -> {\n\t\t\tJarURLConnection connection = (JarURLConnection) handler.getConnection();\n\t\t\tassertThat(connection).isNotNull();\n\t\t\tconnection.getJarFile().getComment();\n\t\t}).withMessageContaining(\"closed\");\n\t}\n\n\tprivate File createResourcesJar(String name) throws IOException {\n\t\treturn createJar(name, (output) -> {\n\t\t\tJarEntry jarEntry = new JarEntry(\"META-INF/resources\");\n\t\t\ttry {\n\t\t\t\toutput.putNextEntry(jarEntry);\n\t\t\t\toutput.closeEntry();\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new RuntimeException(ex);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate File createJar(String name) throws IOException {\n\t\treturn createJar(name, null);\n\t}\n\n\tprivate File createJar(String name, @Nullable Consumer<JarOutputStream> customizer) throws IOException {\n\t\tFile jarFile = new File(this.tempDir, name);\n\t\tJarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile));\n\t\tif (customizer != null) {\n\t\t\tcustomizer.accept(jarOutputStream);\n\t\t}\n\t\tjarOutputStream.close();\n\t\treturn jarFile;\n\t}\n\n\tprivate static class TrackedURLStreamHandler extends URLStreamHandler {\n\n\t\tprivate final boolean useCaches;\n\n\t\tprivate @Nullable URLConnection connection;\n\n\t\tTrackedURLStreamHandler(boolean useCaches) {\n\t\t\tthis.useCaches = useCaches;\n\t\t}\n\n\t\t@Override\n\t\tprotected URLConnection openConnection(URL u) throws IOException {\n\t\t\tthis.connection = new URL(u.toExternalForm()).openConnection();\n\t\t\tthis.connection.setUseCaches(this.useCaches);\n\t\t\treturn this.connection;\n\t\t}\n\n\t\t@Nullable URLConnection getConnection() {\n\t\t\treturn this.connection;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/AnnotationConfigServletWebServerApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.config.ExampleServletWebServerApplicationConfiguration;\nimport org.springframework.boot.web.servlet.mock.MockServlet;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.context.annotation.ScopedProxyMode;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.context.ServletContextAware;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link AnnotationConfigServletWebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass AnnotationConfigServletWebServerApplicationContextTests {\n\n\tprivate @Nullable AnnotationConfigServletWebServerApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid createFromScan() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tExampleServletWebServerApplicationConfiguration.class.getPackage().getName());\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid sessionScopeAvailable() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tExampleServletWebServerApplicationConfiguration.class, SessionScopedComponent.class);\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid sessionScopeAvailableToServlet() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tExampleServletWebServerApplicationConfiguration.class, ExampleServletWithAutowired.class,\n\t\t\t\tSessionScopedComponent.class);\n\t\tServlet servlet = this.context.getBean(ExampleServletWithAutowired.class);\n\t\tassertThat(servlet).isNotNull();\n\t}\n\n\t@Test\n\tvoid createFromConfigClass() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tExampleServletWebServerApplicationConfiguration.class);\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid registerAndRefresh() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.register(ExampleServletWebServerApplicationConfiguration.class);\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid multipleRegistersAndRefresh() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.register(WebServerConfiguration.class);\n\t\tthis.context.register(ServletContextAwareConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBeansOfType(Servlet.class)).hasSize(1);\n\t\tassertThat(this.context.getBeansOfType(ServletWebServerFactory.class)).hasSize(1);\n\t}\n\n\t@Test\n\tvoid scanAndRefresh() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.scan(ExampleServletWebServerApplicationConfiguration.class.getPackage().getName());\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid createAndInitializeCyclic() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tServletContextAwareEmbeddedConfiguration.class);\n\t\tverifyContext();\n\t\t// You can't initialize the application context and inject the servlet context\n\t\t// because of a cycle - we'd like this to be not null, but it never will be\n\t\tassertThat(this.context.getBean(ServletContextAwareEmbeddedConfiguration.class).getServletContext()).isNull();\n\t}\n\n\t@Test\n\tvoid createAndInitializeWithParent() {\n\t\tAnnotationConfigServletWebServerApplicationContext parent = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tWebServerConfiguration.class);\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.register(WebServerConfiguration.class, ServletContextAwareConfiguration.class);\n\t\tthis.context.setParent(parent);\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t\tassertThat(this.context.getBean(ServletContextAwareConfiguration.class).getServletContext()).isNotNull();\n\t}\n\n\tprivate void verifyContext() {\n\t\tassertThat(this.context).isNotNull();\n\t\tMockServletWebServerFactory factory = this.context.getBean(MockServletWebServerFactory.class);\n\t\tServlet servlet = this.context.getBean(Servlet.class);\n\t\tthen(factory.getServletContext()).should().addServlet(\"servlet\", servlet);\n\t}\n\n\t@Component\n\tstatic class ExampleServletWithAutowired extends GenericServlet {\n\n\t\t@Autowired\n\t\tprivate SessionScopedComponent component;\n\n\t\t@Override\n\t\tpublic void service(ServletRequest req, ServletResponse res) {\n\t\t\tassertThat(this.component).isNotNull();\n\t\t}\n\n\t}\n\n\t@Component\n\t@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)\n\tstatic class SessionScopedComponent {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class ServletContextAwareEmbeddedConfiguration implements ServletContextAware {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ServletContext servletContext;\n\n\t\t@Bean\n\t\tServletWebServerFactory webServerFactory() {\n\t\t\treturn new MockServletWebServerFactory();\n\t\t}\n\n\t\t@Bean\n\t\tServlet servlet() {\n\t\t\treturn new MockServlet();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setServletContext(ServletContext servletContext) {\n\t\t\tthis.servletContext = servletContext;\n\t\t}\n\n\t\tServletContext getServletContext() {\n\t\t\treturn this.servletContext;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServerConfiguration {\n\n\t\t@Bean\n\t\tServletWebServerFactory webServerFactory() {\n\t\t\treturn new MockServletWebServerFactory();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class ServletContextAwareConfiguration implements ServletContextAware {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ServletContext servletContext;\n\n\t\t@Bean\n\t\tServlet servlet() {\n\t\t\treturn new MockServlet();\n\t\t}\n\n\t\t@Override\n\t\tpublic void setServletContext(ServletContext servletContext) {\n\t\t\tthis.servletContext = servletContext;\n\t\t}\n\n\t\tServletContext getServletContext() {\n\t\t\treturn this.servletContext;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/ApplicationServletEnvironmentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport org.springframework.boot.AbstractApplicationEnvironmentTests;\nimport org.springframework.boot.web.context.servlet.ApplicationServletEnvironment;\nimport org.springframework.core.env.StandardEnvironment;\n\n/**\n * Tests for {@link ApplicationServletEnvironment}.\n *\n * @author Phillip Webb\n */\nclass ApplicationServletEnvironmentTests extends AbstractApplicationEnvironmentTests {\n\n\t@Override\n\tprotected StandardEnvironment createEnvironment() {\n\t\treturn new ApplicationServletEnvironment();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/MockWebEnvironmentServletComponentScanIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.annotation.WebFilter;\nimport jakarta.servlet.annotation.WebListener;\nimport jakarta.servlet.annotation.WebServlet;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistrar;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistry;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.filter.TestFilter;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.listener.TestListener;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.servlet.TestMultipartServlet;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.servlet.TestServlet;\nimport org.springframework.boot.web.servlet.RegistrationBean;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.mock.web.MockServletContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Integration tests for {@link ServletComponentScan @ServletComponentScan} with a mock\n * web environment.\n *\n * @author Andy Wilkinson\n */\nclass MockWebEnvironmentServletComponentScanIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\tvoid componentsAreRegistered() {\n\t\tprepareContext();\n\t\tassertThat(this.context).isNotNull();\n\t\tthis.context.refresh();\n\t\tMap<String, RegistrationBean> registrationBeans = this.context.getBeansOfType(RegistrationBean.class);\n\t\tassertThat(registrationBeans).hasSize(3);\n\t\tassertThat(registrationBeans.keySet()).containsExactlyInAnyOrder(TestServlet.class.getName(),\n\t\t\t\tTestFilter.class.getName(), TestMultipartServlet.class.getName());\n\t\tWebListenerRegistry registry = mock(WebListenerRegistry.class);\n\t\tthis.context.getBean(WebListenerRegistrar.class).register(registry);\n\t\tthen(registry).should().addWebListeners(TestListener.class.getName());\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\tvoid indexedComponentsAreRegistered() throws IOException {\n\t\twriteIndex(this.temp);\n\t\tprepareContext();\n\t\tassertThat(this.context).isNotNull();\n\t\ttry (URLClassLoader classLoader = new URLClassLoader(new URL[] { this.temp.toURI().toURL() },\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\tthis.context.setClassLoader(classLoader);\n\t\t\tthis.context.refresh();\n\t\t\tMap<String, RegistrationBean> registrationBeans = this.context.getBeansOfType(RegistrationBean.class);\n\t\t\tassertThat(registrationBeans).hasSize(2);\n\t\t\tassertThat(registrationBeans.keySet()).containsExactlyInAnyOrder(TestServlet.class.getName(),\n\t\t\t\t\tTestFilter.class.getName());\n\t\t\tWebListenerRegistry registry = mock(WebListenerRegistry.class);\n\t\t\tthis.context.getBean(WebListenerRegistrar.class).register(registry);\n\t\t\tthen(registry).should().addWebListeners(TestListener.class.getName());\n\t\t}\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\tvoid multipartConfigIsHonoured() {\n\t\tprepareContext();\n\t\tassertThat(this.context).isNotNull();\n\t\tthis.context.refresh();\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tMap<String, ServletRegistrationBean> beans = this.context.getBeansOfType(ServletRegistrationBean.class);\n\t\tServletRegistrationBean<?> servletRegistrationBean = beans.get(TestMultipartServlet.class.getName());\n\t\tassertThat(servletRegistrationBean).isNotNull();\n\t\tMultipartConfigElement multipartConfig = servletRegistrationBean.getMultipartConfig();\n\t\tassertThat(multipartConfig).isNotNull();\n\t\tassertThat(multipartConfig.getLocation()).isEqualTo(\"test\");\n\t\tassertThat(multipartConfig.getMaxRequestSize()).isEqualTo(2048);\n\t\tassertThat(multipartConfig.getMaxFileSize()).isEqualTo(1024);\n\t\tassertThat(multipartConfig.getFileSizeThreshold()).isEqualTo(512);\n\t}\n\n\tprivate void writeIndex(File temp) throws IOException {\n\t\tFile metaInf = new File(temp, \"META-INF\");\n\t\tmetaInf.mkdirs();\n\t\tProperties index = new Properties();\n\t\tindex.setProperty(TestFilter.class.getName(), WebFilter.class.getName());\n\t\tindex.setProperty(TestListener.class.getName(), WebListener.class.getName());\n\t\tindex.setProperty(TestServlet.class.getName(), WebServlet.class.getName());\n\t\ttry (FileWriter writer = new FileWriter(new File(metaInf, \"spring.components\"))) {\n\t\t\tindex.store(writer, null);\n\t\t}\n\t}\n\n\tprivate void prepareContext() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(ScanningConfiguration.class);\n\t\tthis.context.setServletContext(new MockServletContext());\n\t}\n\n\t@ServletComponentScan(basePackages = \"org.springframework.boot.web.server.servlet.context.testcomponents\")\n\tstatic class ScanningConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.annotation.WebFilter;\nimport jakarta.servlet.annotation.WebListener;\nimport jakarta.servlet.annotation.WebServlet;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.WebListenerRegistrar;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.filter.TestFilter;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.listener.TestListener;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.servlet.TestMultipartServlet;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.servlet.TestServlet;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ServletComponentScan @ServletComponentScan}\n *\n * @author Andy Wilkinson\n */\nclass ServletComponentScanIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebServerApplicationContext context;\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tFile temp;\n\n\t@AfterEach\n\tvoid cleanUp() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid componentsAreRegistered() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.register(TestConfiguration.class);\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = this.context.getServletContext();\n\t\tassertThat(servletContext).isNotNull();\n\t\tassertThat(servletContext.getFilterRegistrations()).hasSize(1).containsKey(TestFilter.class.getName());\n\t\tassertThat(servletContext.getServletRegistrations()).hasSize(2)\n\t\t\t.containsKeys(TestServlet.class.getName(), TestMultipartServlet.class.getName());\n\t\tassertThat(this.context.getBean(MockServletWebServerFactory.class).getSettings().getWebListenerClassNames())\n\t\t\t.containsExactly(TestListener.class.getName());\n\t}\n\n\t@Test\n\tvoid indexedComponentsAreRegistered() throws IOException {\n\t\twriteIndex(this.temp);\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\ttry (URLClassLoader classLoader = new URLClassLoader(new URL[] { this.temp.toURI().toURL() },\n\t\t\t\tgetClass().getClassLoader())) {\n\t\t\tthis.context.setClassLoader(classLoader);\n\t\t\tthis.context.register(TestConfiguration.class);\n\t\t\tthis.context.refresh();\n\t\t\tServletContext servletContext = this.context.getServletContext();\n\t\t\tassertThat(servletContext).isNotNull();\n\t\t\tassertThat(servletContext.getFilterRegistrations()).hasSize(1).containsKey(TestFilter.class.getName());\n\t\t\tassertThat(servletContext.getServletRegistrations()).hasSize(1).containsKeys(TestServlet.class.getName());\n\t\t\tassertThat(this.context.getBean(MockServletWebServerFactory.class).getSettings().getWebListenerClassNames())\n\t\t\t\t.containsExactly(TestListener.class.getName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid multipartConfigIsHonoured() {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tthis.context.register(TestConfiguration.class);\n\t\tthis.context.refresh();\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tMap<String, ServletRegistrationBean> beans = this.context.getBeansOfType(ServletRegistrationBean.class);\n\t\tServletRegistrationBean<?> servletRegistrationBean = beans.get(TestMultipartServlet.class.getName());\n\t\tassertThat(servletRegistrationBean).isNotNull();\n\t\tMultipartConfigElement multipartConfig = servletRegistrationBean.getMultipartConfig();\n\t\tassertThat(multipartConfig).isNotNull();\n\t\tassertThat(multipartConfig.getLocation()).isEqualTo(\"test\");\n\t\tassertThat(multipartConfig.getMaxRequestSize()).isEqualTo(2048);\n\t\tassertThat(multipartConfig.getMaxFileSize()).isEqualTo(1024);\n\t\tassertThat(multipartConfig.getFileSizeThreshold()).isEqualTo(512);\n\t}\n\n\tprivate void writeIndex(File temp) throws IOException {\n\t\tFile metaInf = new File(temp, \"META-INF\");\n\t\tmetaInf.mkdirs();\n\t\tProperties index = new Properties();\n\t\tindex.setProperty(TestFilter.class.getName(), WebFilter.class.getName());\n\t\tindex.setProperty(TestListener.class.getName(), WebListener.class.getName());\n\t\tindex.setProperty(TestServlet.class.getName(), WebServlet.class.getName());\n\t\ttry (FileWriter writer = new FileWriter(new File(metaInf, \"spring.components\"))) {\n\t\t\tindex.store(writer, null);\n\t\t}\n\t}\n\n\t@ServletComponentScan(basePackages = \"org.springframework.boot.web.server.servlet.context.testcomponents\")\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tprotected ServletWebServerFactory webServerFactory(ObjectProvider<WebListenerRegistrar> webListenerRegistrars) {\n\t\t\tConfigurableServletWebServerFactory factory = new MockServletWebServerFactory();\n\t\t\twebListenerRegistrars.orderedStream().forEach((registrar) -> registrar.register(factory));\n\t\t\treturn factory;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/ServletComponentScanRegistrarTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.aot.test.generate.TestGenerationContext;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.web.server.servlet.context.testcomponents.listener.TestListener;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.aot.ApplicationContextAotGenerator;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.core.annotation.AnnotationConfigurationException;\nimport org.springframework.core.test.tools.CompileWithForkedClassLoader;\nimport org.springframework.core.test.tools.TestCompiler;\nimport org.springframework.javapoet.ClassName;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatNoException;\n\n/**\n * Tests for {@link ServletComponentScanRegistrar}\n *\n * @author Andy Wilkinson\n */\nclass ServletComponentScanRegistrarTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tvoid after() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid packagesConfiguredWithValue() {\n\t\tthis.context = new AnnotationConfigApplicationContext(ValuePackages.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).contains(\"com.example.foo\", \"com.example.bar\");\n\t}\n\n\t@Test\n\tvoid packagesConfiguredWithValueAsm() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.registerBeanDefinition(\"valuePackages\", new RootBeanDefinition(ValuePackages.class.getName()));\n\t\tthis.context.refresh();\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).contains(\"com.example.foo\", \"com.example.bar\");\n\t}\n\n\t@Test\n\tvoid packagesConfiguredWithBackPackages() {\n\t\tthis.context = new AnnotationConfigApplicationContext(BasePackages.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).contains(\"com.example.foo\", \"com.example.bar\");\n\t}\n\n\t@Test\n\tvoid packagesConfiguredWithBasePackageClasses() {\n\t\tthis.context = new AnnotationConfigApplicationContext(BasePackageClasses.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).contains(getClass().getPackage().getName());\n\t}\n\n\t@Test\n\tvoid packagesConfiguredWithBothValueAndBasePackages() {\n\t\tassertThatExceptionOfType(AnnotationConfigurationException.class)\n\t\t\t.isThrownBy(() -> this.context = new AnnotationConfigApplicationContext(ValueAndBasePackages.class))\n\t\t\t.withMessageContaining(\"'value'\")\n\t\t\t.withMessageContaining(\"'basePackages'\")\n\t\t\t.withMessageContaining(\"com.example.foo\")\n\t\t\t.withMessageContaining(\"com.example.bar\");\n\t}\n\n\t@Test\n\tvoid packagesFromMultipleAnnotationsAreMerged() {\n\t\tthis.context = new AnnotationConfigApplicationContext(BasePackages.class, AdditionalPackages.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).contains(\"com.example.foo\", \"com.example.bar\", \"com.example.baz\");\n\t}\n\n\t@Test\n\tvoid withNoBasePackagesScanningUsesBasePackageOfAnnotatedClass() {\n\t\tthis.context = new AnnotationConfigApplicationContext(NoBasePackages.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan())\n\t\t\t.containsExactly(\"org.springframework.boot.web.server.servlet.context\");\n\t}\n\n\t@Test\n\tvoid noBasePackageAndBasePackageAreCombinedCorrectly() {\n\t\tthis.context = new AnnotationConfigApplicationContext(NoBasePackages.class, BasePackages.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).containsExactlyInAnyOrder(\n\t\t\t\t\"org.springframework.boot.web.server.servlet.context\", \"com.example.foo\", \"com.example.bar\");\n\t}\n\n\t@Test\n\tvoid basePackageAndNoBasePackageAreCombinedCorrectly() {\n\t\tthis.context = new AnnotationConfigApplicationContext(BasePackages.class, NoBasePackages.class);\n\t\tServletComponentRegisteringPostProcessor postProcessor = this.context\n\t\t\t.getBean(ServletComponentRegisteringPostProcessor.class);\n\t\tassertThat(postProcessor.getPackagesToScan()).containsExactlyInAnyOrder(\n\t\t\t\t\"org.springframework.boot.web.server.servlet.context\", \"com.example.foo\", \"com.example.bar\");\n\t}\n\n\t@Test\n\t@CompileWithForkedClassLoader\n\tvoid processAheadOfTimeDoesNotRegisterServletComponentRegisteringPostProcessor() {\n\t\tGenericApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.registerBean(BasePackages.class);\n\t\tcompile(context, (freshContext) -> {\n\t\t\tfreshContext.refresh();\n\t\t\tassertThat(freshContext.getBeansOfType(ServletComponentRegisteringPostProcessor.class)).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeRegistersReflectionHintsForWebListeners() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tcontext.registerBean(ScanListenerPackage.class);\n\t\tTestGenerationContext generationContext = new TestGenerationContext(\n\t\t\t\tClassName.get(getClass().getPackageName(), \"TestTarget\"));\n\t\tnew ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TestListener.class)\n\t\t\t.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))\n\t\t\t.accepts(generationContext.getRuntimeHints());\n\t}\n\n\t@Test\n\tvoid processAheadOfTimeSucceedsForWebServletWithMultipartConfig() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\t\tcontext.registerBean(ScanServletPackage.class);\n\t\tTestGenerationContext generationContext = new TestGenerationContext(\n\t\t\t\tClassName.get(getClass().getPackageName(), \"TestTarget\"));\n\t\tassertThatNoException()\n\t\t\t.isThrownBy(() -> new ApplicationContextAotGenerator().processAheadOfTime(context, generationContext));\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void compile(GenericApplicationContext context, Consumer<GenericApplicationContext> freshContext) {\n\t\tTestGenerationContext generationContext = new TestGenerationContext(\n\t\t\t\tClassName.get(getClass().getPackageName(), \"TestTarget\"));\n\t\tClassName className = new ApplicationContextAotGenerator().processAheadOfTime(context, generationContext);\n\t\tgenerationContext.writeGeneratedContent();\n\t\tTestCompiler.forSystem()\n\t\t\t.withCompilerOptions(\"-Xlint:deprecation,removal\", \"-Werror\")\n\t\t\t.with(generationContext)\n\t\t\t.compile((compiled) -> {\n\t\t\t\tGenericApplicationContext freshApplicationContext = new GenericApplicationContext();\n\t\t\t\tApplicationContextInitializer<GenericApplicationContext> initializer = compiled\n\t\t\t\t\t.getInstance(ApplicationContextInitializer.class, className.toString());\n\t\t\t\tinitializer.initialize(freshApplicationContext);\n\t\t\t\tfreshContext.accept(freshApplicationContext);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan({ \"com.example.foo\", \"com.example.bar\" })\n\tstatic class ValuePackages {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan(basePackages = { \"com.example.foo\", \"com.example.bar\" })\n\tstatic class BasePackages {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan(basePackages = \"com.example.baz\")\n\tstatic class AdditionalPackages {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan(basePackageClasses = ServletComponentScanRegistrarTests.class)\n\tstatic class BasePackageClasses {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan(value = \"com.example.foo\", basePackages = \"com.example.bar\")\n\tstatic class ValueAndBasePackages {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan\n\tstatic class NoBasePackages {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan(\"org.springframework.boot.web.server.servlet.context.testcomponents.listener\")\n\tstatic class ScanListenerPackage {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ServletComponentScan(\"org.springframework.boot.web.server.servlet.context.testcomponents.servlet\")\n\tstatic class ScanServletPackage {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Properties;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Captor;\nimport org.mockito.InOrder;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.ConstructorArgumentValues;\nimport org.springframework.beans.factory.config.Scope;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.RootBeanDefinition;\nimport org.springframework.boot.availability.AvailabilityChangeEvent;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.event.ContextClosedEvent;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.context.support.PropertySourcesPlaceholderConfigurer;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.mock.web.MockFilterChain;\nimport org.springframework.mock.web.MockFilterConfig;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.web.context.ServletContextAware;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.request.SessionScope;\nimport org.springframework.web.filter.GenericFilterBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.atMost;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.withSettings;\n\n/**\n * Tests for {@link ServletWebServerApplicationContext}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@ExtendWith({ OutputCaptureExtension.class, MockitoExtension.class })\nclass ServletWebServerApplicationContextTests {\n\n\tprivate final ServletWebServerApplicationContext context = new ServletWebServerApplicationContext();\n\n\t@Captor\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ArgumentCaptor<Filter> filterCaptor;\n\n\t@AfterEach\n\tvoid cleanup() {\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid startRegistrations() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\t// Ensure that the context has been set up\n\t\tassertThat(this.context.getServletContext()).isEqualTo(factory.getServletContext());\n\t\tthen(factory.getServletContext()).should()\n\t\t\t.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);\n\t\t// Ensure WebApplicationContextUtils.registerWebApplicationScopes was called\n\t\tassertThat(this.context.getBeanFactory().getRegisteredScope(WebApplicationContext.SCOPE_SESSION))\n\t\t\t.isInstanceOf(SessionScope.class);\n\t\t// Ensure WebApplicationContextUtils.registerEnvironmentBeans was called\n\t\tassertThat(this.context.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)).isTrue();\n\t}\n\n\t@Test\n\tvoid doesNotRegistersShutdownHook() {\n\t\t// See gh-314 for background. We no longer register the shutdown hook\n\t\t// since it is really the caller's responsibility. The shutdown hook could\n\t\t// also be problematic in a classic WAR deployment.\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tassertThat(this.context).hasFieldOrPropertyWithValue(\"shutdownHook\", null);\n\t}\n\n\t@Test\n\tvoid ServletWebServerInitializedEventPublished() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.registerBeanDefinition(\"listener\", new RootBeanDefinition(TestApplicationListener.class));\n\t\tthis.context.refresh();\n\t\tList<ApplicationEvent> events = this.context.getBean(TestApplicationListener.class).receivedEvents();\n\t\tassertThat(events).hasSize(2)\n\t\t\t.extracting(\"class\")\n\t\t\t.containsExactly(ServletWebServerInitializedEvent.class, ContextRefreshedEvent.class);\n\t\tServletWebServerInitializedEvent initializedEvent = (ServletWebServerInitializedEvent) events.get(0);\n\t\tassertThat(initializedEvent.getSource().getPort()).isGreaterThanOrEqualTo(0);\n\t\tassertThat(initializedEvent.getApplicationContext()).isEqualTo(this.context);\n\t}\n\n\t@Test\n\tvoid localPortIsAvailable() {\n\t\taddWebServerFactoryBean();\n\t\tnew ServerPortInfoApplicationContextInitializer().initialize(this.context);\n\t\tthis.context.refresh();\n\t\tConfigurableEnvironment environment = this.context.getEnvironment();\n\t\tassertThat(environment.containsProperty(\"local.server.port\")).isTrue();\n\t\tassertThat(environment.getProperty(\"local.server.port\")).isEqualTo(\"8080\");\n\t}\n\n\t@Test\n\tvoid stopOnStop() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tthen(factory.getWebServer()).should().start();\n\t\tthis.context.stop();\n\t\tthen(factory.getWebServer()).should().stop();\n\t}\n\n\t@Test\n\tvoid startOnStartAfterStop() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tthen(factory.getWebServer()).should().start();\n\t\tthis.context.stop();\n\t\tthen(factory.getWebServer()).should().stop();\n\t\tthis.context.start();\n\t\tthen(factory.getWebServer()).should(times(2)).start();\n\t}\n\n\t@Test\n\tvoid stopAndDestroyOnClose() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tthis.context.close();\n\t\tthen(factory.getWebServer()).should(times(2)).stop();\n\t\tthen(factory.getWebServer()).should().destroy();\n\t}\n\n\t@Test\n\tvoid applicationIsUnreadyDuringShutdown() {\n\t\tTestApplicationListener listener = new TestApplicationListener();\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tthis.context.addApplicationListener(listener);\n\t\tthis.context.close();\n\t\tassertThat(listener.receivedEvents()).hasSize(2)\n\t\t\t.extracting(\"class\")\n\t\t\t.contains(AvailabilityChangeEvent.class, ContextClosedEvent.class);\n\t}\n\n\t@Test\n\tvoid whenContextIsNotActiveThenCloseDoesNotChangeTheApplicationAvailability() {\n\t\taddWebServerFactoryBean();\n\t\tTestApplicationListener listener = new TestApplicationListener();\n\t\tthis.context.addApplicationListener(listener);\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh);\n\t\tthis.context.close();\n\t\tassertThat(listener.receivedEvents()).isEmpty();\n\t}\n\n\t@Test\n\tvoid whenContextRefreshFailedThenWebServerIsStoppedAndDestroyed() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh);\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tthen(webServer).should(times(2)).stop();\n\t\tthen(webServer).should().destroy();\n\t}\n\n\t@Test\n\tvoid whenContextRefreshFailedThenWebServerStopFailedCatchStopException() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class, () -> {\n\t\t\twillThrow(new RuntimeException(\"WebServer has failed to stop\")).willCallRealMethod()\n\t\t\t\t.given(this.context.getWebServer())\n\t\t\t\t.stop();\n\t\t\treturn new RefreshFailure();\n\t\t}));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh)\n\t\t\t.withStackTraceContaining(\"WebServer has failed to stop\");\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tthen(webServer).should().stop();\n\t\tthen(webServer).should(never()).destroy();\n\t}\n\n\t@Test\n\tvoid whenContextRefreshFailedThenWebServerIsStoppedAndDestroyFailedCatchDestroyException() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.registerBeanDefinition(\"refreshFailure\", new RootBeanDefinition(RefreshFailure.class, () -> {\n\t\t\twillThrow(new RuntimeException(\"WebServer has failed to destroy\")).willCallRealMethod()\n\t\t\t\t.given(this.context.getWebServer())\n\t\t\t\t.destroy();\n\t\t\treturn new RefreshFailure();\n\t\t}));\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh)\n\t\t\t.withStackTraceContaining(\"WebServer has failed to destroy\");\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tthen(webServer).should().stop();\n\t\tthen(webServer).should().destroy();\n\t}\n\n\t@Test\n\tvoid cannotSecondRefresh() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tassertThatIllegalStateException().isThrownBy(this.context::refresh);\n\t}\n\n\t@Test\n\tvoid servletContextAwareBeansAreInjected() {\n\t\taddWebServerFactoryBean();\n\t\tServletContextAware bean = mock(ServletContextAware.class);\n\t\tthis.context.registerBeanDefinition(\"bean\", beanDefinition(bean));\n\t\tthis.context.refresh();\n\t\tthen(bean).should().setServletContext(getWebServerFactory().getServletContext());\n\t}\n\n\t@Test\n\tvoid missingServletWebServerFactory() {\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\"Unable to start ServletWebServerApplicationContext due to missing \"\n\t\t\t\t\t+ \"ServletWebServerFactory bean\");\n\t}\n\n\t@Test\n\tvoid tooManyWebServerFactories() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.registerBeanDefinition(\"webServerFactory2\",\n\t\t\t\tnew RootBeanDefinition(MockServletWebServerFactory.class));\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.withMessageContaining(\"Unable to start ServletWebServerApplicationContext due to \"\n\t\t\t\t\t+ \"multiple ServletWebServerFactory beans\");\n\n\t}\n\n\t@Test\n\tvoid singleServletBean() {\n\t\taddWebServerFactoryBean();\n\t\tServlet servlet = mock(Servlet.class);\n\t\tthis.context.registerBeanDefinition(\"servletBean\", beanDefinition(servlet));\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tthen(factory.getServletContext()).should().addServlet(\"servletBean\", servlet);\n\t\tthen(factory.getRegisteredServlet(0).getRegistration()).should().addMapping(\"/\");\n\t}\n\n\t@Test\n\tvoid orderedBeanInsertedCorrectly() {\n\t\taddWebServerFactoryBean();\n\t\tOrderedFilter filter = new OrderedFilter();\n\t\tthis.context.registerBeanDefinition(\"filterBean\", beanDefinition(filter));\n\t\tFilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();\n\t\tregistration.setName(\"filterBeanRegistration\");\n\t\tregistration.setFilter(mock(Filter.class));\n\t\tregistration.setOrder(100);\n\t\tthis.context.registerBeanDefinition(\"filterRegistrationBean\", beanDefinition(registration));\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tthen(factory.getServletContext()).should().addFilter(\"filterBean\", filter);\n\t\tthen(factory.getServletContext()).should().addFilter(\"filterBeanRegistration\", registration.getFilter());\n\t\tassertThat(factory.getRegisteredFilter(0).getFilter()).isEqualTo(filter);\n\t}\n\n\t@Test\n\tvoid multipleServletBeans() {\n\t\taddWebServerFactoryBean();\n\t\tServlet servlet1 = mock(Servlet.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) servlet1).getOrder()).willReturn(1);\n\t\tServlet servlet2 = mock(Servlet.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) servlet2).getOrder()).willReturn(2);\n\t\tthis.context.registerBeanDefinition(\"servletBean2\", beanDefinition(servlet2));\n\t\tthis.context.registerBeanDefinition(\"servletBean1\", beanDefinition(servlet1));\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tServletContext servletContext = factory.getServletContext();\n\t\tInOrder ordered = inOrder(servletContext);\n\t\tthen(servletContext).should(ordered).addServlet(\"servletBean1\", servlet1);\n\t\tthen(servletContext).should(ordered).addServlet(\"servletBean2\", servlet2);\n\t\tthen(factory.getRegisteredServlet(0).getRegistration()).should().addMapping(\"/servletBean1/\");\n\t\tthen(factory.getRegisteredServlet(1).getRegistration()).should().addMapping(\"/servletBean2/\");\n\t}\n\n\t@Test\n\tvoid multipleServletBeansWithMainDispatcher() {\n\t\taddWebServerFactoryBean();\n\t\tServlet servlet1 = mock(Servlet.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) servlet1).getOrder()).willReturn(1);\n\t\tServlet servlet2 = mock(Servlet.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) servlet2).getOrder()).willReturn(2);\n\t\tthis.context.registerBeanDefinition(\"servletBean2\", beanDefinition(servlet2));\n\t\tthis.context.registerBeanDefinition(\"dispatcherServlet\", beanDefinition(servlet1));\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tServletContext servletContext = factory.getServletContext();\n\t\tInOrder ordered = inOrder(servletContext);\n\t\tthen(servletContext).should(ordered).addServlet(\"dispatcherServlet\", servlet1);\n\t\tthen(servletContext).should(ordered).addServlet(\"servletBean2\", servlet2);\n\t\tthen(factory.getRegisteredServlet(0).getRegistration()).should().addMapping(\"/\");\n\t\tthen(factory.getRegisteredServlet(1).getRegistration()).should().addMapping(\"/servletBean2/\");\n\t}\n\n\t@Test\n\tvoid servletAndFilterBeans() {\n\t\taddWebServerFactoryBean();\n\t\tServlet servlet = mock(Servlet.class);\n\t\tFilter filter1 = mock(Filter.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) filter1).getOrder()).willReturn(1);\n\t\tFilter filter2 = mock(Filter.class, withSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) filter2).getOrder()).willReturn(2);\n\t\tthis.context.registerBeanDefinition(\"servletBean\", beanDefinition(servlet));\n\t\tthis.context.registerBeanDefinition(\"filterBean2\", beanDefinition(filter2));\n\t\tthis.context.registerBeanDefinition(\"filterBean1\", beanDefinition(filter1));\n\t\tthis.context.refresh();\n\t\tMockServletWebServerFactory factory = getWebServerFactory();\n\t\tServletContext servletContext = factory.getServletContext();\n\t\tInOrder ordered = inOrder(servletContext);\n\t\tthen(factory.getServletContext()).should().addServlet(\"servletBean\", servlet);\n\t\tthen(factory.getRegisteredServlet(0).getRegistration()).should().addMapping(\"/\");\n\t\tthen(factory.getServletContext()).should(ordered).addFilter(\"filterBean1\", filter1);\n\t\tthen(factory.getServletContext()).should(ordered).addFilter(\"filterBean2\", filter2);\n\t\tthen(factory.getRegisteredFilter(0).getRegistration()).should()\n\t\t\t.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, \"/*\");\n\t\tthen(factory.getRegisteredFilter(1).getRegistration()).should()\n\t\t\t.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, \"/*\");\n\t}\n\n\t@Test\n\tvoid servletContextInitializerBeans() throws Exception {\n\t\taddWebServerFactoryBean();\n\t\tServletContextInitializer initializer1 = mock(ServletContextInitializer.class,\n\t\t\t\twithSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) initializer1).getOrder()).willReturn(1);\n\t\tServletContextInitializer initializer2 = mock(ServletContextInitializer.class,\n\t\t\t\twithSettings().extraInterfaces(Ordered.class));\n\t\tgiven(((Ordered) initializer2).getOrder()).willReturn(2);\n\t\tthis.context.registerBeanDefinition(\"initializerBean2\", beanDefinition(initializer2));\n\t\tthis.context.registerBeanDefinition(\"initializerBean1\", beanDefinition(initializer1));\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tInOrder ordered = inOrder(initializer1, initializer2);\n\t\tthen(initializer1).should(ordered).onStartup(servletContext);\n\t\tthen(initializer2).should(ordered).onStartup(servletContext);\n\t}\n\n\t@Test\n\tvoid servletContextListenerBeans() {\n\t\taddWebServerFactoryBean();\n\t\tServletContextListener initializer = mock(ServletContextListener.class);\n\t\tthis.context.registerBeanDefinition(\"initializerBean\", beanDefinition(initializer));\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tthen(servletContext).should().addListener(initializer);\n\t}\n\n\t@Test\n\tvoid unorderedServletContextInitializerBeans() throws Exception {\n\t\taddWebServerFactoryBean();\n\t\tServletContextInitializer initializer1 = mock(ServletContextInitializer.class);\n\t\tServletContextInitializer initializer2 = mock(ServletContextInitializer.class);\n\t\tthis.context.registerBeanDefinition(\"initializerBean2\", beanDefinition(initializer2));\n\t\tthis.context.registerBeanDefinition(\"initializerBean1\", beanDefinition(initializer1));\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tthen(initializer1).should().onStartup(servletContext);\n\t\tthen(initializer2).should().onStartup(servletContext);\n\t}\n\n\t@Test\n\tvoid servletContextInitializerBeansDoesNotSkipServletsAndFilters() throws Exception {\n\t\taddWebServerFactoryBean();\n\t\tServletContextInitializer initializer = mock(ServletContextInitializer.class);\n\t\tServlet servlet = mock(Servlet.class);\n\t\tFilter filter = mock(Filter.class);\n\t\tthis.context.registerBeanDefinition(\"initializerBean\", beanDefinition(initializer));\n\t\tthis.context.registerBeanDefinition(\"servletBean\", beanDefinition(servlet));\n\t\tthis.context.registerBeanDefinition(\"filterBean\", beanDefinition(filter));\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tthen(initializer).should().onStartup(servletContext);\n\t\tthen(servletContext).should().addServlet(anyString(), any(Servlet.class));\n\t\tthen(servletContext).should().addFilter(anyString(), any(Filter.class));\n\t}\n\n\t@Test\n\tvoid servletContextInitializerBeansSkipsRegisteredServletsAndFilters() {\n\t\taddWebServerFactoryBean();\n\t\tServlet servlet = mock(Servlet.class);\n\t\tFilter filter = mock(Filter.class);\n\t\tServletRegistrationBean<Servlet> initializer = new ServletRegistrationBean<>(servlet, \"/foo\");\n\t\tthis.context.registerBeanDefinition(\"initializerBean\", beanDefinition(initializer));\n\t\tthis.context.registerBeanDefinition(\"servletBean\", beanDefinition(servlet));\n\t\tthis.context.registerBeanDefinition(\"filterBean\", beanDefinition(filter));\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tthen(servletContext).should(atMost(1)).addServlet(anyString(), any(Servlet.class));\n\t\tthen(servletContext).should(atMost(1)).addFilter(anyString(), any(Filter.class));\n\t}\n\n\t@Test\n\tvoid filterRegistrationBeansSkipsRegisteredFilters() {\n\t\taddWebServerFactoryBean();\n\t\tFilter filter = mock(Filter.class);\n\t\tFilterRegistrationBean<Filter> initializer = new FilterRegistrationBean<>(filter);\n\t\tthis.context.registerBeanDefinition(\"initializerBean\", beanDefinition(initializer));\n\t\tthis.context.registerBeanDefinition(\"filterBean\", beanDefinition(filter));\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tthen(servletContext).should(atMost(1)).addFilter(anyString(), any(Filter.class));\n\t}\n\n\t@Test\n\tvoid delegatingFilterProxyRegistrationBeansSkipsTargetBeanNames() {\n\t\taddWebServerFactoryBean();\n\t\tDelegatingFilterProxyRegistrationBean initializer = new DelegatingFilterProxyRegistrationBean(\"filterBean\");\n\t\tthis.context.registerBeanDefinition(\"initializerBean\", beanDefinition(initializer));\n\t\tBeanDefinition filterBeanDefinition = beanDefinition(new IllegalStateException(\"Create FilterBean Failure\"));\n\t\tfilterBeanDefinition.setLazyInit(true);\n\t\tthis.context.registerBeanDefinition(\"filterBean\", filterBeanDefinition);\n\t\tthis.context.refresh();\n\t\tServletContext servletContext = getWebServerFactory().getServletContext();\n\t\tthen(servletContext).should(atMost(1)).addFilter(anyString(), this.filterCaptor.capture());\n\t\t// Up to this point the filterBean should not have been created, calling\n\t\t// the delegate proxy will trigger creation and an exception\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> {\n\t\t\tthis.filterCaptor.getValue().init(new MockFilterConfig());\n\t\t\tthis.filterCaptor.getValue()\n\t\t\t\t.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse(), new MockFilterChain());\n\t\t}).withMessageContaining(\"Create FilterBean Failure\");\n\t}\n\n\t@Test\n\tvoid postProcessWebServerFactory() {\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(MockServletWebServerFactory.class);\n\t\tMutablePropertyValues pv = new MutablePropertyValues();\n\t\tpv.add(\"port\", \"${port}\");\n\t\tbeanDefinition.setPropertyValues(pv);\n\t\tthis.context.registerBeanDefinition(\"webServerFactory\", beanDefinition);\n\t\tPropertySourcesPlaceholderConfigurer propertySupport = new PropertySourcesPlaceholderConfigurer();\n\t\tProperties properties = new Properties();\n\t\tproperties.put(\"port\", 8080);\n\t\tpropertySupport.setProperties(properties);\n\t\tthis.context.registerBeanDefinition(\"propertySupport\", beanDefinition(propertySupport));\n\t\tthis.context.refresh();\n\t\tassertThat(getWebServerFactory().getWebServer().getPort()).isEqualTo(8080);\n\t}\n\n\t@Test\n\tvoid doesNotReplaceExistingScopes() {\n\t\t// gh-2082\n\t\tScope scope = mock(Scope.class);\n\t\tConfigurableListableBeanFactory factory = this.context.getBeanFactory();\n\t\tfactory.registerScope(WebApplicationContext.SCOPE_REQUEST, scope);\n\t\tfactory.registerScope(WebApplicationContext.SCOPE_SESSION, scope);\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tassertThat(factory.getRegisteredScope(WebApplicationContext.SCOPE_REQUEST)).isSameAs(scope);\n\t\tassertThat(factory.getRegisteredScope(WebApplicationContext.SCOPE_SESSION)).isSameAs(scope);\n\t}\n\n\t@Test\n\tvoid servletRequestCanBeInjectedEarly(CapturedOutput output) {\n\t\t// gh-14990\n\t\tint initialOutputLength = output.length();\n\t\taddWebServerFactoryBean();\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition(WithAutowiredServletRequest.class);\n\t\tbeanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);\n\t\tthis.context.registerBeanDefinition(\"withAutowiredServletRequest\", beanDefinition);\n\t\tthis.context.addBeanFactoryPostProcessor((beanFactory) -> {\n\t\t\tWithAutowiredServletRequest bean = beanFactory.getBean(WithAutowiredServletRequest.class);\n\t\t\tassertThat(bean.getRequest()).isNotNull();\n\t\t});\n\t\tthis.context.refresh();\n\t\tassertThat(output.toString().substring(initialOutputLength)).doesNotContain(\"Replacing scope\");\n\t}\n\n\t@Test\n\tvoid webApplicationScopeIsRegistered() {\n\t\taddWebServerFactoryBean();\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBeanFactory().getRegisteredScope(WebApplicationContext.SCOPE_APPLICATION))\n\t\t\t.isNotNull();\n\t}\n\n\tprivate void addWebServerFactoryBean() {\n\t\tthis.context.registerBeanDefinition(\"webServerFactory\",\n\t\t\t\tnew RootBeanDefinition(MockServletWebServerFactory.class));\n\t}\n\n\tMockServletWebServerFactory getWebServerFactory() {\n\t\treturn this.context.getBean(MockServletWebServerFactory.class);\n\t}\n\n\tprivate BeanDefinition beanDefinition(Object bean) {\n\t\tRootBeanDefinition beanDefinition = new RootBeanDefinition();\n\t\tbeanDefinition.setBeanClass(getClass());\n\t\tbeanDefinition.setFactoryMethodName(\"getBean\");\n\t\tConstructorArgumentValues constructorArguments = new ConstructorArgumentValues();\n\t\tconstructorArguments.addGenericArgumentValue(bean);\n\t\tbeanDefinition.setConstructorArgumentValues(constructorArguments);\n\t\treturn beanDefinition;\n\t}\n\n\tstatic <T> T getBean(T object) {\n\t\tif (object instanceof RuntimeException runtimeException) {\n\t\t\tthrow runtimeException;\n\t\t}\n\t\treturn object;\n\t}\n\n\tstatic class TestApplicationListener implements ApplicationListener<ApplicationEvent> {\n\n\t\tprivate final Deque<ApplicationEvent> events = new ArrayDeque<>();\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(ApplicationEvent event) {\n\t\t\tthis.events.add(event);\n\t\t}\n\n\t\tList<ApplicationEvent> receivedEvents() {\n\t\t\tList<ApplicationEvent> receivedEvents = new ArrayList<>();\n\t\t\twhile (!this.events.isEmpty()) {\n\t\t\t\treceivedEvents.add(this.events.pollFirst());\n\t\t\t}\n\t\t\treturn receivedEvents;\n\t\t}\n\n\t}\n\n\t@Order(10)\n\tstatic class OrderedFilter extends GenericFilterBean {\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\t\t}\n\n\t}\n\n\tstatic class WithAutowiredServletRequest {\n\n\t\tprivate final ServletRequest request;\n\n\t\tWithAutowiredServletRequest(ServletRequest request) {\n\t\t\tthis.request = request;\n\t\t}\n\n\t\tServletRequest getRequest() {\n\t\t\treturn this.request;\n\t\t}\n\n\t}\n\n\tstatic class RefreshFailure {\n\n\t\tRefreshFailure() {\n\t\t\tthrow new RuntimeException(\"Fail refresh\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/WebFilterHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.io.IOException;\nimport java.util.EnumSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.annotation.WebFilter;\nimport jakarta.servlet.annotation.WebInitParam;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebFilterHandler}\n *\n * @author Andy Wilkinson\n */\nclass WebFilterHandlerTests {\n\n\tprivate final WebFilterHandler handler = new WebFilterHandler();\n\n\tprivate final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid defaultFilterConfiguration() throws IOException {\n\t\tAnnotatedBeanDefinition definition = createBeanDefinition(DefaultConfigurationFilter.class);\n\t\tthis.handler.handle(definition, this.registry);\n\t\tBeanDefinition filterRegistrationBean = this.registry\n\t\t\t.getBeanDefinition(DefaultConfigurationFilter.class.getName());\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat(propertyValues.get(\"asyncSupported\")).isEqualTo(false);\n\t\tassertThat((EnumSet<DispatcherType>) propertyValues.get(\"dispatcherTypes\"))\n\t\t\t.containsExactly(DispatcherType.REQUEST);\n\t\tassertThat(((Map<String, String>) propertyValues.get(\"initParameters\"))).isEmpty();\n\t\tassertThat((String[]) propertyValues.get(\"servletNames\")).isEmpty();\n\t\tassertThat((String[]) propertyValues.get(\"urlPatterns\")).isEmpty();\n\t\tassertThat(propertyValues.get(\"name\")).isEqualTo(DefaultConfigurationFilter.class.getName());\n\t\tassertThat(propertyValues.get(\"filter\")).isEqualTo(definition);\n\t}\n\n\t@Test\n\tvoid filterWithCustomName() throws IOException {\n\t\tAnnotatedBeanDefinition definition = createBeanDefinition(CustomNameFilter.class);\n\t\tthis.handler.handle(definition, this.registry);\n\t\tBeanDefinition filterRegistrationBean = this.registry.getBeanDefinition(\"custom\");\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat(propertyValues.get(\"name\")).isEqualTo(\"custom\");\n\t}\n\n\t@Test\n\tvoid asyncSupported() throws IOException {\n\t\tBeanDefinition filterRegistrationBean = handleBeanDefinitionForClass(AsyncSupportedFilter.class);\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat(propertyValues.get(\"asyncSupported\")).isEqualTo(true);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid dispatcherTypes() throws IOException {\n\t\tBeanDefinition filterRegistrationBean = handleBeanDefinitionForClass(DispatcherTypesFilter.class);\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat((Set<DispatcherType>) propertyValues.get(\"dispatcherTypes\")).containsExactly(DispatcherType.FORWARD,\n\t\t\t\tDispatcherType.INCLUDE, DispatcherType.REQUEST);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid initParameters() throws IOException {\n\t\tBeanDefinition filterRegistrationBean = handleBeanDefinitionForClass(InitParametersFilter.class);\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat((Map<String, String>) propertyValues.get(\"initParameters\")).containsEntry(\"a\", \"alpha\")\n\t\t\t.containsEntry(\"b\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid servletNames() throws IOException {\n\t\tBeanDefinition filterRegistrationBean = handleBeanDefinitionForClass(ServletNamesFilter.class);\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat((String[]) propertyValues.get(\"servletNames\")).contains(\"alpha\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid urlPatterns() throws IOException {\n\t\tBeanDefinition filterRegistrationBean = handleBeanDefinitionForClass(UrlPatternsFilter.class);\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat((String[]) propertyValues.get(\"urlPatterns\")).contains(\"alpha\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid urlPatternsFromValue() throws IOException {\n\t\tBeanDefinition filterRegistrationBean = handleBeanDefinitionForClass(UrlPatternsFromValueFilter.class);\n\t\tMutablePropertyValues propertyValues = filterRegistrationBean.getPropertyValues();\n\t\tassertThat((String[]) propertyValues.get(\"urlPatterns\")).contains(\"alpha\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid urlPatternsDeclaredTwice() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> handleBeanDefinitionForClass(UrlPatternsDeclaredTwiceFilter.class))\n\t\t\t.withMessageContaining(\"The urlPatterns and value attributes are mutually exclusive\");\n\t}\n\n\tprivate AnnotatedBeanDefinition createBeanDefinition(Class<?> filterClass) throws IOException {\n\t\tAnnotatedBeanDefinition definition = mock(AnnotatedBeanDefinition.class);\n\t\tgiven(definition.getBeanClassName()).willReturn(filterClass.getName());\n\t\tgiven(definition.getMetadata()).willReturn(\n\t\t\t\tnew SimpleMetadataReaderFactory().getMetadataReader(filterClass.getName()).getAnnotationMetadata());\n\t\treturn definition;\n\t}\n\n\tprivate BeanDefinition handleBeanDefinitionForClass(Class<?> filterClass) throws IOException {\n\t\tthis.handler.handle(createBeanDefinition(filterClass), this.registry);\n\t\treturn this.registry.getBeanDefinition(filterClass.getName());\n\t}\n\n\t@WebFilter\n\tclass DefaultConfigurationFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(asyncSupported = true)\n\tclass AsyncSupportedFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE })\n\tclass DispatcherTypesFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(initParams = { @WebInitParam(name = \"a\", value = \"alpha\"), @WebInitParam(name = \"b\", value = \"bravo\") })\n\tclass InitParametersFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(servletNames = { \"alpha\", \"bravo\" })\n\tclass ServletNamesFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(urlPatterns = { \"alpha\", \"bravo\" })\n\tclass UrlPatternsFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter({ \"alpha\", \"bravo\" })\n\tclass UrlPatternsFromValueFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(value = { \"alpha\", \"bravo\" }, urlPatterns = { \"alpha\", \"bravo\" })\n\tclass UrlPatternsDeclaredTwiceFilter extends BaseFilter {\n\n\t}\n\n\t@WebFilter(filterName = \"custom\")\n\tclass CustomNameFilter extends BaseFilter {\n\n\t}\n\n\tclass BaseFilter implements Filter {\n\n\t\t@Override\n\t\tpublic void init(FilterConfig filterConfig) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroy() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/WebListenerHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.ServletContextAttributeEvent;\nimport jakarta.servlet.ServletContextAttributeListener;\nimport jakarta.servlet.annotation.WebListener;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\n\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebListenerHandler}.\n *\n * @author Andy Wilkinson\n */\nclass WebListenerHandlerTests {\n\n\tprivate final WebListenerHandler handler = new WebListenerHandler();\n\n\tprivate final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();\n\n\t@Test\n\tvoid listener() throws IOException {\n\t\tAnnotatedBeanDefinition definition = mock(AnnotatedBeanDefinition.class);\n\t\tgiven(definition.getBeanClassName()).willReturn(TestListener.class.getName());\n\t\tgiven(definition.getMetadata())\n\t\t\t.willReturn(new SimpleMetadataReaderFactory().getMetadataReader(TestListener.class.getName())\n\t\t\t\t.getAnnotationMetadata());\n\t\tthis.handler.handle(definition, this.registry);\n\t\tthis.registry.getBeanDefinition(TestListener.class.getName() + \"Registrar\");\n\t}\n\n\t@WebListener\n\tstatic class TestListener implements ServletContextAttributeListener {\n\n\t\t@Override\n\t\tpublic void attributeAdded(ServletContextAttributeEvent event) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void attributeRemoved(ServletContextAttributeEvent event) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void attributeReplaced(ServletContextAttributeEvent event) {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/WebServletHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport java.io.IOException;\nimport java.util.Map;\n\nimport jakarta.servlet.annotation.WebInitParam;\nimport jakarta.servlet.annotation.WebServlet;\nimport jakarta.servlet.http.HttpServlet;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.MutablePropertyValues;\nimport org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebServletHandler}.\n *\n * @author Andy Wilkinson\n */\nclass WebServletHandlerTests {\n\n\tprivate final WebServletHandler handler = new WebServletHandler();\n\n\tprivate final SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid defaultServletConfiguration() throws IOException {\n\t\tAnnotatedBeanDefinition servletDefinition = createBeanDefinition(DefaultConfigurationServlet.class);\n\t\tthis.handler.handle(servletDefinition, this.registry);\n\t\tBeanDefinition servletRegistrationBean = this.registry\n\t\t\t.getBeanDefinition(DefaultConfigurationServlet.class.getName());\n\t\tMutablePropertyValues propertyValues = servletRegistrationBean.getPropertyValues();\n\t\tassertThat(propertyValues.get(\"asyncSupported\")).isEqualTo(false);\n\t\tassertThat(((Map<String, String>) propertyValues.get(\"initParameters\"))).isEmpty();\n\t\tassertThat((Integer) propertyValues.get(\"loadOnStartup\")).isEqualTo(-1);\n\t\tassertThat(propertyValues.get(\"name\")).isEqualTo(DefaultConfigurationServlet.class.getName());\n\t\tassertThat((String[]) propertyValues.get(\"urlMappings\")).isEmpty();\n\t\tassertThat(propertyValues.get(\"servlet\")).isEqualTo(servletDefinition);\n\t}\n\n\t@Test\n\tvoid servletWithCustomName() throws IOException {\n\t\tAnnotatedBeanDefinition definition = createBeanDefinition(CustomNameServlet.class);\n\t\tthis.handler.handle(definition, this.registry);\n\t\tBeanDefinition servletRegistrationBean = this.registry.getBeanDefinition(\"custom\");\n\t\tMutablePropertyValues propertyValues = servletRegistrationBean.getPropertyValues();\n\t\tassertThat(propertyValues.get(\"name\")).isEqualTo(\"custom\");\n\t}\n\n\t@Test\n\tvoid asyncSupported() throws IOException {\n\t\tBeanDefinition servletRegistrationBean = handleBeanDefinitionForClass(AsyncSupportedServlet.class);\n\t\tMutablePropertyValues propertyValues = servletRegistrationBean.getPropertyValues();\n\t\tassertThat(propertyValues.get(\"asyncSupported\")).isEqualTo(true);\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid initParameters() throws IOException {\n\t\tBeanDefinition servletRegistrationBean = handleBeanDefinitionForClass(InitParametersServlet.class);\n\t\tMutablePropertyValues propertyValues = servletRegistrationBean.getPropertyValues();\n\t\tassertThat((Map<String, String>) propertyValues.get(\"initParameters\")).containsEntry(\"a\", \"alpha\")\n\t\t\t.containsEntry(\"b\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid urlMappings() throws IOException {\n\t\tBeanDefinition servletRegistrationBean = handleBeanDefinitionForClass(UrlPatternsServlet.class);\n\t\tMutablePropertyValues propertyValues = servletRegistrationBean.getPropertyValues();\n\t\tassertThat((String[]) propertyValues.get(\"urlMappings\")).contains(\"alpha\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid urlMappingsFromValue() throws IOException {\n\t\tBeanDefinition servletRegistrationBean = handleBeanDefinitionForClass(UrlPatternsFromValueServlet.class);\n\t\tMutablePropertyValues propertyValues = servletRegistrationBean.getPropertyValues();\n\t\tassertThat((String[]) propertyValues.get(\"urlMappings\")).contains(\"alpha\", \"bravo\");\n\t}\n\n\t@Test\n\tvoid urlPatternsDeclaredTwice() {\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> handleBeanDefinitionForClass(UrlPatternsDeclaredTwiceServlet.class))\n\t\t\t.withMessageContaining(\"The urlPatterns and value attributes are mutually exclusive\");\n\t}\n\n\tprivate AnnotatedBeanDefinition createBeanDefinition(Class<?> servletClass) throws IOException {\n\t\tAnnotatedBeanDefinition definition = mock(AnnotatedBeanDefinition.class);\n\t\tgiven(definition.getBeanClassName()).willReturn(servletClass.getName());\n\t\tgiven(definition.getMetadata()).willReturn(\n\t\t\t\tnew SimpleMetadataReaderFactory().getMetadataReader(servletClass.getName()).getAnnotationMetadata());\n\t\treturn definition;\n\t}\n\n\tprivate BeanDefinition handleBeanDefinitionForClass(Class<?> filterClass) throws IOException {\n\t\tthis.handler.handle(createBeanDefinition(filterClass), this.registry);\n\t\treturn this.registry.getBeanDefinition(filterClass.getName());\n\t}\n\n\t@WebServlet\n\tclass DefaultConfigurationServlet extends HttpServlet {\n\n\t}\n\n\t@WebServlet(asyncSupported = true)\n\tclass AsyncSupportedServlet extends HttpServlet {\n\n\t}\n\n\t@WebServlet(initParams = { @WebInitParam(name = \"a\", value = \"alpha\"), @WebInitParam(name = \"b\", value = \"bravo\") })\n\tclass InitParametersServlet extends HttpServlet {\n\n\t}\n\n\t@WebServlet(urlPatterns = { \"alpha\", \"bravo\" })\n\tclass UrlPatternsServlet extends HttpServlet {\n\n\t}\n\n\t@WebServlet({ \"alpha\", \"bravo\" })\n\tclass UrlPatternsFromValueServlet extends HttpServlet {\n\n\t}\n\n\t@WebServlet(value = { \"alpha\", \"bravo\" }, urlPatterns = { \"alpha\", \"bravo\" })\n\tclass UrlPatternsDeclaredTwiceServlet extends HttpServlet {\n\n\t}\n\n\t@WebServlet(name = \"custom\")\n\tclass CustomNameServlet extends HttpServlet {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/XmlServletWebServerApplicationContextTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context;\n\nimport jakarta.servlet.Servlet;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link XmlServletWebServerApplicationContext}.\n *\n * @author Phillip Webb\n */\nclass XmlServletWebServerApplicationContextTests {\n\n\tprivate static final String PATH = XmlServletWebServerApplicationContextTests.class.getPackage()\n\t\t.getName()\n\t\t.replace('.', '/') + \"/\";\n\n\tprivate static final String FILE = \"exampleEmbeddedWebApplicationConfiguration.xml\";\n\n\tprivate @Nullable XmlServletWebServerApplicationContext context;\n\n\t@Test\n\tvoid createFromResource() {\n\t\tthis.context = new XmlServletWebServerApplicationContext(new ClassPathResource(FILE, getClass()));\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid createFromResourceLocation() {\n\t\tthis.context = new XmlServletWebServerApplicationContext(PATH + FILE);\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid createFromRelativeResourceLocation() {\n\t\tthis.context = new XmlServletWebServerApplicationContext(getClass(), FILE);\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid loadAndRefreshFromResource() {\n\t\tthis.context = new XmlServletWebServerApplicationContext();\n\t\tthis.context.load(new ClassPathResource(FILE, getClass()));\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid loadAndRefreshFromResourceLocation() {\n\t\tthis.context = new XmlServletWebServerApplicationContext();\n\t\tthis.context.load(PATH + FILE);\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\t@Test\n\tvoid loadAndRefreshFromRelativeResourceLocation() {\n\t\tthis.context = new XmlServletWebServerApplicationContext();\n\t\tthis.context.load(getClass(), FILE);\n\t\tthis.context.refresh();\n\t\tverifyContext();\n\t}\n\n\tprivate void verifyContext() {\n\t\tassertThat(this.context).isNotNull();\n\t\tMockServletWebServerFactory factory = this.context.getBean(MockServletWebServerFactory.class);\n\t\tServlet servlet = this.context.getBean(Servlet.class);\n\t\tthen(factory.getServletContext()).should().addServlet(\"servlet\", servlet);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/config/ExampleServletWebServerApplicationConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context.config;\n\nimport jakarta.servlet.Servlet;\n\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.servlet.mock.MockServlet;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Example {@code @Configuration} for use with\n * {@code AnnotationConfigServletWebServerApplicationContextTests}.\n *\n * @author Phillip Webb\n */\n@Configuration(proxyBeanMethods = false)\npublic class ExampleServletWebServerApplicationConfiguration {\n\n\t@Bean\n\tpublic MockServletWebServerFactory webServerFactory() {\n\t\treturn new MockServletWebServerFactory();\n\t}\n\n\t@Bean\n\tpublic Servlet servlet() {\n\t\treturn new MockServlet();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/config/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.web.server.servlet.context.config;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/filter/TestFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context.testcomponents.filter;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.annotation.WebFilter;\n\n@WebFilter(\"/*\")\npublic class TestFilter implements Filter {\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\trequest.setAttribute(\"filterAttribute\", \"bravo\");\n\t\tchain.doFilter(request, response);\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/filter/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.web.server.servlet.context.testcomponents.filter;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/listener/TestListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context.testcomponents.listener;\n\nimport java.io.IOException;\nimport java.util.EnumSet;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.annotation.WebListener;\n\n@WebListener\npublic class TestListener implements ServletContextListener {\n\n\t@Override\n\tpublic void contextInitialized(ServletContextEvent sce) {\n\t\tsce.getServletContext()\n\t\t\t.addFilter(\"listenerAddedFilter\", new ListenerAddedFilter())\n\t\t\t.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, \"/*\");\n\t\tsce.getServletContext().setAttribute(\"listenerAttribute\", \"alpha\");\n\t}\n\n\t@Override\n\tpublic void contextDestroyed(ServletContextEvent sce) {\n\n\t}\n\n\tstatic class ListenerAddedFilter implements Filter {\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\tthrows IOException, ServletException {\n\t\t\trequest.setAttribute(\"listenerAddedFilterAttribute\", \"charlie\");\n\t\t\tchain.doFilter(request, response);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/listener/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.web.server.servlet.context.testcomponents.listener;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/servlet/TestMultipartServlet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context.testcomponents.servlet;\n\nimport jakarta.servlet.annotation.MultipartConfig;\nimport jakarta.servlet.annotation.WebServlet;\nimport jakarta.servlet.http.HttpServlet;\n\n@WebServlet(\"/test-multipart\")\n@MultipartConfig(location = \"test\", maxFileSize = 1024, maxRequestSize = 2048, fileSizeThreshold = 512)\npublic class TestMultipartServlet extends HttpServlet {\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/servlet/TestServlet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet.context.testcomponents.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.annotation.WebServlet;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\n@WebServlet(\"/test\")\npublic class TestServlet extends HttpServlet {\n\n\t@Override\n\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\tresp.getWriter()\n\t\t\t.print(((String) req.getServletContext().getAttribute(\"listenerAttribute\")) + \" \"\n\t\t\t\t\t+ req.getAttribute(\"filterAttribute\") + \" \" + req.getAttribute(\"listenerAddedFilterAttribute\"));\n\t\tresp.getWriter().flush();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/java/org/springframework/boot/web/server/servlet/context/testcomponents/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.web.server.servlet.context.testcomponents.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs1/dsa.key",
    "content": "-----BEGIN DSA PRIVATE KEY-----\nMIIBuwIBAAKBgQCDX+Ux7y7dkfCnQgRIXzAlFrG8uPxwFdC8J4FJNrAurnjL//PV\n8LEHBDVbyPjHaoNbH8Pfc2pJnOzndWZVf0nqBd4Q/Tz9w/pJ9g6E8HOh+rzU3eK5\nmF0rezcMbJsot2Vdx6XrTztDKi2GY0etKNV399DYtepIYA6v5ovuYAOjLwIVAPyb\n9zR+UjyCkBwESDm9dpzKsGp1AoGAS2vtTiO7/MT8cJwo4mxYtiJnV5R2mk1JJOTe\n4AFPgmnce/YbBzU2JwL9J9HGewDkmxudW0zoxZVeNw4dRua6oB5STV8XciW8vSo6\nmdDBJFoBW9/DUscRP4j2aRfkXGlYuiEF6ZT8g6pPHZG7pLviihMAWNRVLmBt38wa\n8FA9aZECgYADbfwh7OhSE1J0WRaEk/4Usos5Oi6fhUyqr2u34Ereug9Gt4tkhePa\nb3y31i2PQfsatpR+4VpBC6zpPgHQYpuqlqDRWJCd+Cxo9751nOiA3xYVxNoiwIn/\nWxoUkC8Jv8kYFAJRceXkF/auVh77MUoruAmoT2lGE6zP6ngP2q6jFwIVAJMF5kZ+\nAUZbUBUpZaPuZ15RL8GF\n-----END DSA PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs1/rsa-aes-256-cbc.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,2036BA8802B364C6BE415A48E1AC9966\n\n0euP/daGIbl798XGc2Tc6u6NmnCl8C6hE0a2grO+wbvFEa13IT4hNVNTzqahfLb8\nSTF9LXdvPbz9HybyWnG8KNm5sqsSY1omsHQI38khhwuhpHuWfjb62TqWobwrAmAU\nqh2+kjc7upzW48axJLRQ69vfE4zKczZ4Sqv8qImPz9SiXPeaXinHf/wKfgXZZOvr\n6A8nCykLglVrFbrZWydqKrTM9w/LTXsn0gNpDmrfZERDgWnabKnjYidHkXdgAoFy\nulsBjKvj2hJFtnJHTkCPXj6XAj18cwUWsN7inFJR5wqjIWXuLqfv/fNbK9lPzjAk\nvMTEVWwynekvXFsSvnHAyEJfmRCNF6DOE+5VwjEROCFq8xceK4fz4T3BHC7XSgis\n2ofBZwjCAJ0pP6SdRpbbZ0wlXH09wqDDTZ2vWD6bEG7hO9VuP/aO76MIWydLa78z\nbDb2R6MnYKmYEInPzwfU4H66Z3/cz8orfYLlnF55DRd4rO+fJm6Y/XY14ac3x0S+\nP67s5e0WbdImagUsOxGNBjgOr84lwmtk/LoVd5nKho8JyQw3V7tiyrsKsM1lAXdS\nTaJXKRnN6LbgC8d+Tgfjc/qMUdVqLlN8zATIa6E4sc861DDiJsneXuFm43pHc/ja\n0sxSifBKgLGenj8xY5ANEfrYnXKrzaQemUnMzd+zan6OS02I+e8WTQevESt1j0D8\n7mgLJ9W2SfNNfiEd5OKar21lLNOc3POaFn7M73zL/gyhTROipPR3fpV+08k27UKl\nnzGhFtRwQieXl34QjM0JrHokKKfv8FsAJsbrGnz2/wcm6jJGmrj5VVsogMKc90v4\nZTM44NAKymM0UTuIp/rKb/UUVYDpl9VWDegWh2+XKX8io31ENrDMcvQTJ/mzNCuZ\nSINrAeMbVD6W5L0i7THEt32YsDmbFsBaEJBlNXlUNBa/NCK0pjwAn5AYOFUvEqBC\noZUEleUMU6Q3TKI287o37euw3No6jo5VdPULlrwHsZAjmq9EUvRCgMoIEPdxv5XG\na4PljE7DQLlk6G9d+gjRzClLFfkadSTbtH9o2011RtWUKP4dcRuSOcBm64xVIO6J\nrhe38sE3yzHvLUM/mvLsEM8B0AHl85nrEstlbBzftXMo2CAJ2Gs9c61PYfft+xiT\npRdHx4HB1P+kfHa96ayvAytOexHih2iVKVG5CchOr5tbWmkhXVE5cZAKzvczDYFd\nYvniHNiqt6LO8EbJOzz+Yxessmd0zBXj/rjxTMdGwaRjiFI0BIguYpvmGoMS8+bp\nspRj2DMtqjNZz68BEEfgKQwDHPCTblYSR+3Uw4sja608sflqQ8rTmOwbfta3SNS8\nKq/zzWfYzarQ8hAk5n/H1Jm6AQdvcptyMjuF8FAiMnvt8xDCBRMD3xY2BHb/tcs9\ndBWBxhb76CKIrV3pzm9gGhhZ32Ndq9KmmE+bWCYyvrLxvPJxODfM7X5XamPmG5SH\nwEKSbp0wPF0b6vyxt5M72OYnU8UnxYWu6PlbVvczfWEu9fIw/oIN/kDT/QUojTyt\nwBgzVSTSNFaDtVXJw10IWQgsgWdNY5XueHKH060P5g+14woxU8i3TboNd+tC3hRl\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs1/rsa.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIJKAIBAAKCAgEA1zZsVLbl+bOl2QlFZ5R5hbJrR5u+G3Ddd/f25JWwno9tfRik\n+39KrIHJKwxq/TH1d0WjfOuvFBz5Ucnh86NOSnffz7kxLgP8QcjQkwuVTjDj4lTp\nsJpi/U1npAZ6Eu1/KeC3R2u8qqvYG3U3G6cQYw5Y+0wHf5EYlIvKfx5oVEEf67pz\n7q2TffqoOV7PQHyHt+/BKFJI1ehj8W/2uQJJ9UTmGvixAYLZ6gHLmtEUj1cBZUb1\n5X/lVbbsiL8B2prbuPoJWYcppH8L2cqSq4JP43Y2VR3CtrQH9MBbLxBfPVnzuD1j\nX1J++xMMN7NCRpBNI/xoJNxvxO+3RgNbkhz4f8WhJbuCwaoNJStytq2fcqOfT3t7\nlW10Gj67joMJZtIsW7JPquFGW6RNq7YqMCJ9ML8Vv9B9UJcUEeE+a+IX6epJBQK6\n1KC6TIe4SB+xl1Vu1xosuAyvni2H7QDjbiZvE8WX2apKk7fv81Epi+9J5Dn4zMpk\nZ5GG1/itA+rZSCWCs8c3lbGq0olZMsXNNhbNZOqiih3yeaMw/B/3v/XMn98rliMl\nC8VOX92eKKBJTX/CjMuSU48mxNE8lQJaDcfld9JE6ndmiZWe7BpXEF8wYtL/NObI\nxZXfcLDsEHopPpU9gaRDZmtL2aUweliF3WIIUmoo/C3kR7ZOSJ5fC66a+yECAwEA\nAQKCAgAhLFxqen7cjJqF5+3w12wb9bKfqRwWssEQmwJNnd1Js6YW4FOeCLMEAEV4\nA0QCn07NAcj/mny0RvsPZmUT3xpUVEIFjPBNvYOGyGOOJvzuvo6B9sDG3iVgEixl\nljH+9OjjFaZqteqxDCgVo23JL2lRO4bvxXpqaX02eI3QJmnCgv9eoLD6G3teseJ4\nZWrg79EjwystAfIENvwg3TdUsUuhKOunQKpYJ0lbzscJqCzZI3otmFCS/bHmEnpH\nYdnxTmmMC86hJDqBBqxW9+i/0yhpUXFykVHQQ9PuIDBuAsILfPAaeCv3J4o3PWpm\ns5UFt3yMjX2oIOqBmsnPWvkkfp63Gr2rGfAMftXSA0l9VcyMPZx78jihZx43f8bK\nMVu4Rd/V1Yxc0n7fr/TTOl5m3Fb4rdOuPOoLEDUQeO4SplStxbjIAEwa1oFFSD8x\nxtsBhSP63+dwflkeuV7OgRP8Fsuu2MDnn5AHeHaM81J4smLjpZ9j6BdhWMVmimvH\nL0Y/MiScC9ngTXpop5ph1VzOXVM1R05jnt53P3UNNTubkndOnuBoa71Zbcjz1HkZ\nAPWbETt/1CgJ7aCN9CV7FYNA8/z9t4R/VObquwHE3qfzIOAzSb+rehoBr3nrtzAZ\nA4uUOcvgnHzbm9FG0ysdqhri830KxnYfzeQ+bXeZDGU8PZcuIQKCAQEA/BS0oeP0\n5HAPSFVtNrSMNHTUvprHyfxp959Q8gAHD8MmQctoEUcABARUeDNNZbP/pNF2lCWB\nrJfDLod8VZsViBj3coF0w4VinuC1hphEiu+He7UhOdS/PlpEr6Ci0gTsIIhqboVa\nvKdvaEYaEHVp1//P8yC+M9CtF/fSCNlRElqgWzwkcFxMB4ErTWnIU0+ni+GtcKMs\n4DrpAuSf4LXUBxoP6MBuTbRMcurEFE7Vwbslup/AZphXCF++2E5viOvXn3/uBPkh\nL/wVTAgjb9Vdd/zTQKYp8Ol769OosrQcfb6Aa6OBuGhpkUVVSdNiSqZrclVfSWOR\n5WoHHjiDiZ9a/QKCAQEA2o763dX7lKVTSXTAB7jTBMONrOX7g1gY8Dt2RvCzZY6R\nzLQ/mQOcU8r1PdJc3WEdHP6YYzWy+7buMp/vsMsu17UnVW3ac22vISOLwStbZ0XJ\nDvm7rPQvaBG7/EDJvSGv654MCPGyM/JEgispK1I4yTAKltBFQ2NebUtg8NBPqK0q\nKrRUiMB1H2QhoRIW47yFTTm3snosu1nnQ/qGDgWWUW2iGZtftN40HzXQPy2bMv2x\n/ATRjsWVJcdqytqlg0wYM+4Ekkz633cnR59qZ76o3DoNEJUoM5fBwTKNfxExKRSc\nWkqkXWoWGqkvXaW7jPec+8HQ/o15aLzCvhP3OIKz9QKCAQEA+n4I0SaY37eLODHL\niST4fdfq4E0mY0z0cCBca14jpkIh7heWnjSTi2pSFe/E5V9slfefga+ToFJengn8\nP4UQbGGC4sJJqVEOoxpgyBLfacCEPSXMko8aS3ef8XYK1fAWRG3KdXEGrZkkV9Xx\naJGEUCPgHJVY7Fxc5QhaKnjo2vg7iO3Gt/C/jGWLBi4r5r2snI/xrZA4s8lWao2N\nYdrNixEW5g7yjTyxCzDHD/cW6qBx6XV913ViZuvd1Ux8AO97IQAbIc3+cJRrBVbB\nAAxiCS2vLvrvino5ripx5MKd3UZEjrG34eu/m5/uFKJ9dfjRpJe5TFApVnN6B0nZ\nTBSScQKCAQAieroC8zYcTjSkewGsdjD8KGmaZDHYl7Zfd9ICAQkcNXC07Z624gXw\nhi1IUn6KAj8YiuW5iQgyg7pyTB8BMhyytQZ+iLUUzrH5NWVf1Ro3YaAFd8puz5sG\n/P0+H250IvNg5W8anh6x6T97lZmKFw+UVbrl7fdvWSbVcTXa59IZVzA2ynonlM0l\nZaOUiIkJ5nzVIQzk4DdcWyOL6uLpJWKAeB5Bkex4WTG51sCCpww78B/7FTuGHY+Z\nBSvI0tOXshKDZsJb3j8Zr++HchPUSBTVoWbcPdu4v/E2LGZ8LFcoFvNPn0Ts48aW\n8CfjyziaVZnzcbEp52HG7zh9yiKPTLddAoIBAEpS/V+z3Vu1iMdQ9uoBIdcQbcLX\nGYBoyyLEgmBBAYfNHJ9YTt4HwvDr57vgAqnadXmQh9+IRdpF7rSizr3OBqnBJE0J\nnbGLKvJArMw4IcF29JOkpuR3GiuigfYgQ0JgYw7fZwc24eesKwopDWutUexo0Tlc\nef2CmgR/+rymyEknpX8xT5ExYaNz8odguNjRqSohM63p2UXkdi5CLYpu0q28iY59\n0s+3LAwsLPeZirR8TZ0NgirMMAIrILsCYmP78OGV6stOEUj1oUPIu6Txa/Z20saA\nb6z079eXrl1voiiRyJ0h7tHL9VEQA62dICHY9BY1I7H9ZL+Fi1Af5jfXGSs=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP256r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGIAgEAMBQGByqGSM49AgEGCSskAwMCCAEBBwRtMGsCAQEEIBfCkWEWyc2tHIvS\nAo6hhcj09dnh8NOmtZeqGmcXHnIqoUQDQgAElux3elmSzb/WqEZXb1vdXx/tcIpC\nYq2vewG8H1SikMoACeFVRcjuy31gJ4Q8M7UQmrR4+WXSptV/UQ6Gkt3XuQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP256t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGIAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCARtMGsCAQEEIILhgc3joEZDWMDm\n9TYgrENN7gbqtMpMw1e2MTLwlJhCoUQDQgAEiDN20JP8O9zSK46tP6MkXJPNAfyN\nIQ0hOgcQ//Fw5V0yiSU+BPGeDoIDsW8LnElS1hIZWq0JVQNZge5ei2bshQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP320r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGiAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCQSBhjCBgwIBAQQoNifTnb4a5dOR\nyr8QFVM7Zkw/f/AMm5T5PQ6iVTCzrnw/kZ8glwl+JKFUA1IABHSnWUC/tKXpNHGE\nP89QVKEgvetwCQWFoOENAgXORniLiaLdAdsR80ouTsZiFgHG9su0l5ESEnFWQr5x\nUMj/vPwwhSYm+YP5ucx5NezuBM4d\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP320t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGiAgEAMBQGByqGSM49AgEGCSskAwMCCAEBCgSBhjCBgwIBAQQotGnirBX69ezE\n7a9yIBQcqeCMm7hc5YAG8D4396ytBa/2/O/lonDlOqFUA1IABDQHDepa3l/S8Gt9\nWrNCNpCPZNBXvmkGPnVXZchZI5BtUySwYxHX1tpatGs3jY7drVYm+NyxZE81pecY\nTvXR8bu7e3BIp2SwZmXEDxdYp1fw\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP384r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG6AgEAMBQGByqGSM49AgEGCSskAwMCCAEBCwSBnjCBmwIBAQQwK6y6NydLMTNm\nLhDNPyTDKEemTWTUuMGfBQxEz+lQKAqz/So4uA+fQzor/t8to+uioWQDYgAEaK8X\n3KCyRDMpbACw2xG4UUe9OxyuGWFaGKPxhKJDyW5Z56gT5P1Q2y4CblL/X9VcDIMX\ndcQqRNBkPQfy1+fJXwKO0ClfD6MIE3bv6PTZ55J6H2H1dpg38a2soRchz0FN\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP384t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG6AgEAMBQGByqGSM49AgEGCSskAwMCCAEBDASBnjCBmwIBAQQwBGUaEvTtnxm8\nfOWj2c2cX4991rvGmfGviuWWQRblSii/v9FG4nQ4Q2IrgBy+hgK9oWQDYgAEQL0d\nQoOTArIx70V/XxipoxxBeKT7zmIe7id5pQiw4O4nA2S2BFxQF9eW9ipnm6DaN6ja\nX/+2k+cC4qIfqzeLcLUFXxz0qdec8lNNtr9QmwoQlv11beeHmQu9C1GwHmvG\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP512r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHsAgEAMBQGByqGSM49AgEGCSskAwMCCAEBDQSB0DCBzQIBAQRAmEQNFMGIDLoj\nKtdg8V71WdSs7FiBkE6Bft25+yY8ohugk/u8aKeIKNVtSirMgQhGFJy/BIBkvM6V\n1JfnrglkjqGBhQOBggAEYbjTnA0x42NdM7jVv7jAoZq0iOYopbwejlOEsx8/MqRa\nYt4Ef83holIsgOHWSeW+kw1oMDmieoCrhnkM/3KgGzV+BxCeieAWGxABsj9YhAmb\nATorRJ4q/pMxRq8gIUv05/dGuUttl1gdbKKnGQjxDBM4v5H+/4z00nzzj4Gbfx8=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/brainpoolP512t1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHsAgEAMBQGByqGSM49AgEGCSskAwMCCAEBDgSB0DCBzQIBAQRATamyZ088BsIP\nScslwa0I1xfC0/6udycncr+i/QIFOXNr4OQiVb4KC/CS/2FPotVMFSHZfCS2bgi6\nYvg3Mta5SKGBhQOBggAEm/uIqsytMZypsqCuL0jwZh8xCRVEkUd02YPXcOBhMzS9\nbhAao4CLAuXhWzplr5qk/7ttvczl7qFDOvBzNAIieZHwbFrouZ6Pew8pQXRcMDB+\nFnXwNgpljTNmz/f1ePjVKU1ZgbQ+xVf8Qt8OI9S0Pla8siTgbVweGMLtq0A8Wuo=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/dsa-aes-128-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIDzTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIJ2oQD0S0aMcCAggA\nMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBCNXluHkzV+EEdxlhmcIAWBBIID\ncAWJ20CCQlOCxxCddujc5gPPotUyKTbXA7xI3J9DdjrqBaHrNY/Yii4Zxk9lpzPL\n3x3M3O4C8nJjk4OEA0fiyBYOV1d+KZfa7UZojIe/e+7BuTH9WAvgVzORYYEFX6x7\nDTTmYH6VSej/RBdNTV1KeWA4+20Zn+vqCwcBG6R78cQDP3xGOmT6jOAQR/0kkqEv\nGN22UGpuMlHb7SDiYeDRqQPdRMkpu1RZS37MWEZ//yuwqEyaowK0JgTVGKyibf3E\nqXYV7TqEumdfrpZxPXkmJwswUSoFwE1wM0XU5WMg+lnNiroaVQjzqLEEqENpJ03c\nY27l0m83GRVvISvwLGOKY0Sbcb2d6NnqBjbVjbJopjBrww3iiTUqGiQZTFjiJ3CD\nVNKdG3HPWEdjZG5xoF9BLF3ZVz/jrfLkK2RcZBs0U6SyENd3H1gOk3yv4Uw2VjXi\nh/PA27oFJ2I5DN9bcHhbKVMFykc9JZbisDO0TNx6gbVxZUdNEER0nsP4/sZCwXp+\nK7rGvrUk17vBesp0K/tTfdBM2xVkV6oCMKPeQpsdekwCSAdNamSpxZn5LqUaX+Gw\nbMf1FxTlIL0ujLiN6/U3VWxLuJuoJauFyM5wYlpqgBOQIszVREQqMOs/Zp1WT5uS\nVUA7tdcIpSE7aA3q2rg1BkaiLMSEBMY/XWAI6SCj7iQyRD6GDse/ayJrQ4rUPvD4\niRLQN9B1BYwAplGX3Cmi++Yos7tOq8D2HfTDsI0bHAi+oSDTRUAsiezx5QRLgrp1\npO2dyBlJ5HOlK4SA8h5CMlk2fVgCLGCZ61VcqF1DHu5NKuCnCR73QrwuZAPlo19L\nJt1YAgcXBfFoSbjAvE+AXcxu2uw+t2kj6cjGRSRpBNSHCn3bJ2zu0qrPL3lOMhtt\nDYp0QNWJkW/6/fpmXXAYQQv6bFY0Bia8Ima9LATcCwpYcRox1pL2rvU1EWLDVy6N\nPdFdlzLM7UcrY9Vy40gEj1qz9epAXqzfPkmbyP3i41BjKlZfmmzpJEI6hIJMtT6T\nxWU1Kgg+mAED6STAJ6nem2bIEzMfsNM00VrHXoLU4IWPCe8NMYOaVox1xBWs1mer\nlu9dgGBAy4/gn6v55XzjQ4R16wyiiJn3ZQGrUD0AE6N2E/tfWiphVG1tYDjjWCLv\nbXG/U6P6DjClkBocb4DgKBc=\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/dsa.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIDXQIBADCCAzYGByqGSM44BAEwggMpAoIBgQC1d6MOqEDLxjfjz1v7Vg44bBBX\nVOoNdWhvJPl9NL2Js57UmYGrTqFit2VCLxbS5FVLyOZ25S0myQRsEtKyi4V9+ELI\n0q3oQplm+l3tZqKjtO69ZlbzYSl9IG1254/FCwBnBTuN7Vl6A2vryIhY7cL4E053\nYy0xqfP7swPgMYNBqjc9c53hNHKiseQJ8Q2wFKZqm13xgqnBqmWbm7yNmzKJbjMW\nZt3/WpJdjqfRnjSljFOkYPPBkGRUIKHcZ9fw4odVov2vblGzXwR+sFeE3lcF50WN\nuppjszMXlqR4y937CUSFbCabatRHEcPTq/FxioERCrCdx3AKOfwAquahtvWb9V7A\n47FlibDDeybh5jCH0j9HSjhjSiDZdadSgGKFynPNlVAlOETZKGqkeqAZZ+dsPkVO\nn8tx+VXZJF00YSe1HLKJUWXaT1tEGF6vw/dXhhQVir4j63fN2tZdhTOW1ao/J/iT\nVYEQQjYeMKKuZQveBKRBlpAjhmjOztbE8VL4O/cCHQCxPXlCpORbfOMEEGU0hbEE\nHsxFHMXHCnURCJxVAoIBgQCBqsk+z57UndC1Ut6u19wILXs7UBgLo0ivId2QHtm5\nkY77P9/lNOyCIQkBnULbJ36lHm6yxLZ8imyC5Lc7wlFJpJ6PpiTJ3nPi3fzhbftB\n2KCJVSwB3XfkjvyyS8bfwwqyrmce9el+AIFJuWPrFSkjNthq7U5vU5a+uNT9XZrs\nEaDbjkjVJXRX1oDS3IfWXWpb9i/LOE9HU+NfDKfydasWASvwNX1F5BKXD0AH9adj\n9Q7b0p4DVTh+UPWLBk9/e6gsA5HaRI1urAMNxs5Xnmd8UYF1I+AmjQ9Mi63Pa0YW\nQjpdH2hoOQGLemQ/72woFVzLaHWBcTuSwjREilaAA5M8CWq4rpuA79MrcHgzSp2C\nW1gtZa2/3SymcJ7Py2PHbncod8gR9dxHWVO07ccOXUG0iL9m4MzQ27uVvTh8Nrma\nM+JET778E2FaAkAIT34eNMC6Yk2IDrxU9L66FFx3+3n0cOeWaJxIWrIQ6uWk+uIH\nVzPsZAQU/V0/QBABlHuSj1cEHgIcYTbB5VrbIgust0jVvQCnlF4b1V0qz2iDJt6o\nsA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/ed25519-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAi1t9NlcmE8TwICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJacGnDl5HIWWbv604Vp0CUEQDEx\njZKBJnhmLTPMJbE1TgVe+9N8ZG1CVpSFz0xo9xCk15G4E9jgxXw/a8Sqy7NiDqRb\nFLJrSStMU+ygP7wXIFo=\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/ed25519.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIJ55hBE+FwS4M3k/c45ZJKPHtsklKrb6qJlER0cMJ2rn\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/ed448.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMEcCAQAwBQYDK2VxBDsEOSSF8O0uKk5pRrjUNV+QgonwO+WeDRb/i1U7vM+TLzh7\njAV58E6oglA53konKxGv+GC38dCb72gSeQ==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/prime256v1-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjZ2eXtLFXLdgICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEIlOTfeoLwq9Bs9TFtw7VSMEgZAU\nRO9W+K3vvzRG4sACrcFaB7PMhv3+HUOcPFf09QHa7aSJMWsb8EXGFBK4xlFhkK0/\nN0C8sRtH2N1JdYj9hiwS7I8WyybaR2W0ZALNR57iLz3WsOGQ7nVECFprElboqnSW\nBtjkKTD9pz3xX/6cMkDV/2WqbS6Y/dzWJTH8yTTqjzTjbs4vguEK1Io6dlIRVqA=\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/prime256v1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQguc9upTMQn8b+loAx\n6c8q20dHYBf3V9374I3kJIDmC1ShRANCAARnLuOxL7n7Gq12zd9vq2neAv6PYc1h\nW6M2gJKSbfFYGhte382jOJ2TgwaTQL/J5IPSfuJKkmAPBIl8CdJKWlwA\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/rsa-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIX1pl8K5MBZoCAggA\nMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDAZbI9gwQvuQp1MWqsGkJeBIIJ\nUIsFUQY5CFVcTqF2wNDdyA/5X4YvQ1wKPwYdSIHhGAe4UjljSqUBG5StfZmdA4aT\nDdrzdApbZxP8BUlIjrjfR1tsbgnvevEkWUTftA2jzOmKBmYQ44WmQV2JGz6rWcH1\nZUc0ArKq1Jz2OU+JnE3Olrbf4QupcYCQ+qgB5Afkp78hMUWiGPXaW12Ankjk0qVU\n6zKiLP7cpignOlDTth+pYe/ltFQr1cLSgTsas/9X565usS333s8P7RQQsPRa5+De\nhsgZIGeJTX6RGG0ipxZjd97jle54T6UPnYQWmHHZuX0LNqThTeUHZxPaMLJ7jnFY\nNtqNvlXydkWRqdVmP2L2uk4mECrQrKqcqLIdlEL+sB00t+hjNtyCh6dIaQ5rbYDS\n1k7fNDx1m2k1u3ydtUUeN6/7OJ7X1Is8k3WDTxHguFDz1mmeCw0lgH9tWZ4peG0/\nhIP2p02icaoSx24K7b6yHShJ/+B6lp17tYe/FgVBzO75tB7ljH5bZjYcZ9iIGy9h\nT9Jq53M/lAnsAADLt1fiYRTWq9G5w/wzl0vqNTVpnpE7nXTs7d6Di812k8uyf2G+\nRU8Bsv50SJEZzW4liXhGxJXaI2TKKa8o27vPm/hK6cL2uoS6d22+/dUL1yP0ZXl7\nLOgqnNS3e6wT5xfdbXXclGUER8jP1QRPTm3evI13BRWHswLTeHWmdivZFrCHHw6o\n7f3LARYLkefwO/FsC9IJzpdgN3B4V/K0BIcVYwXYgrqUIei91b+3EHgqvB3cXLdG\nr91IBTvV15V9Hz8FUmTo+0uRdP7nrQ9+4451p6RP8FUuaAV03/a47YWemkZtqmzd\nzuWB/Eo1fzmxrbHyXZoN9D04ubOB9S/6jUy9N2IwQykeKy+go/FHltQr8l0JhkKs\nipbaRc719n2Fj/hBkaIzLl/nxK2KWR2kCAiVXo8WHJOzzRlgEMUCbgoNbvf7X+ek\n7O2VXOR2ZrqDSXs0WsZsq2LeAXlN2rIS3TKVru1T+0YKe/z/qZFvdygkTGB0qX7n\nG+v03iRVSGingsl3UiW/S0wLDxdxnBgERggD+YSwQ/pFQTPn4AOe7xStW/2/d95W\nS6rA23ijN+U3O1yN1jCJjMZUFK4DDwKbIUyqcF+m8jvYLrvYxNuVh3pwwDbGARGF\nq3rzm4K0UUeCZa3sBlV9EkVhIxdibO9fPFP/9o+pGHacZ9/B0QtCXLfb3RnRX3AW\nuM5L3gMd14TeIaeTMyHz4H9epUNwph022TKV98au8diLNGtB8eNZuu4wAYTfwYfi\nkUcS+Yp/EqwO8/evdCvWSe5xJ1QuLcl+Fr6XGEs+QmcGNDSq9VaqNu5QndZSBR26\nZv5vGpukqwxGXdHmETvLavam4io4Q/2XUQgZLdCTKxs4Sf3BiAyrW0DWEFQ0vLXt\nFFNQ6AXuVe7jvaGDox86RZ3bHDwWJePBAkQtOza/lFkvLd2h9bcjppeHxznr36Ha\nAnVfIJ57sjBlQA0bpUmTGDkcC1FmRnM5ADQdCENu6ZCkgkVwpFeYfJX/Vk3wMH41\nDQwSF7gP75DDLBnwyb8WooMWEkULBzBEa6N6koZejmgEaULv0aWN0BhE8G1XxVq+\n+hOwgNMVm0d9UrceOUsyj4G7UpJbMO0jtLSt3PWE9xfCqDm7vVPf9sA3/Qa6YtXX\nEkNCfItqqbYBWsNKzNpZXDpiS26DFhpww9JrwEL2KBRp247ANxZxG7dhk5H12+Zv\n2c49np0/zAHAhREzuebnPZiWbEMPOM0y9WxIhbCN+u1E16nxZWDeNagDsOCkiNrR\nc02C3U+MZd6S5oYT2h9kc5qq9NyCkJQTFO4012sBYn9LZ0aFUXIPPCilrr2dRMJG\nCUMGrtMfbauEQ7iZYSCdg1PDNmtrv3sirJWZueMNQhEppdtYiV5gfCPVl0sa3fvP\n4yLiPiMMrTjspyXq66jTR116Sm0ZdffDZHGDFUSFowEJZ5JbigUsQDvRwcGjoZ//\nIKT3PPQ55tukuD2WmI2FT4j9SYr3YSBWcraY0povPanxwAIewZZW9BxrOgEDthkY\n7VPeShzcJ4z8O60ioJTtR7gZYhcy9NoTHM8sbXhHS8QloWa22cwXACtPtuh7ErQZ\njPHIhb+KLFa7P7O6ceTYwZlqUnA+HFI9VHarrutxqRaUWa37JAEhd1bplmxBXDZo\n/8S4pNVlxT9xQmuYpN5JvWCeUadV5SwHCGVHcIDVsDVAWF6zLYwb6zWF1i3uRYTP\nFNwZx4DiskQhQu34QAnvvajZ1wZf3xJ6LS+exOoAZ8Z/qyxWmDwffSvf6Nx/Tw1r\nwLFmKTcMGxBUzGMJ4txp0tiJIHYE8IQMYWNOBeB/GjRWxTEBl5doFpXpDdFz+mfP\nk/wRUTkbuRg1KxXV2GPGB94m9elePD+Rf+m0Hl9rWPGsPR2JE6lr6k/kUYAWXuSh\no/3w85skoGcAe51EVvtrtqbPTTcd/ndigKI7U4shQnZCm8nUISYlIukor2vNlIuw\n1MC94zP2sfWBreka5VAC3IsP67lkdJx6DLvv80GJ50O7u1oKjQCroEKGC22puTb9\nNZn0h8BepBrgY6eWA9eZyrJ+v0HfMKN0O4lBBhtcedHTGZmBhKffjS0KTqvztFyo\nvnx86mIoiskANpfTn1QWSHxVJm5fNlRNK3DdCDzsQ8OcweIGc/omcg1MYp3Qav17\nE6HoYWVrYUhVbzrOPiW3SorE5c0Xk1tTZQXH212mt3RhMTPmrqc6+PVIwFfU/lzi\nSABjj1Jws9QLbb74J8O5eP4+ZxAvkZtKaLTBibJhYOGtGIrsWzfmcsEzCH+YUPYz\n3vMT6E6wB/KazfI3TWc2g0eHklu7mx1HDlR1V6BOfJ3tOMOqqOOpvAp8A3J+TULB\nZlQIOlMYH+fnQfRg2FcVHGCik32h7HdjeoZha/Qsogrg5j4LL0NkJf3k5E8I/c4L\no7yY0rPMKt6qmmZe4msO9wFGomWCms5LBV9K3H4bEtNdPs5rdP8wO8C9NaGRuUgZ\n3pPm1AYRdxJNW3TGR+D7nTuDrRIKrxMkWyKOkwQteWAqI4OAiMezhpv8X0+pq5K8\n8rPROuQkq/znG8wktQ0V6P+JjL1oBayhrpadgYY/tc1+S8U/zeeCPnFtUXLLdk/K\nstzs8gsvZCWWn6M5mlSrsyLaB1sgbxbuOlaH4FlUAYZC\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/rsa-des-ede3-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJnDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQInDrn6GvZlw8CAggA\nMAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECNwtOc3eKItmBIIJSNZzJs9X5vLX\n1PNFSOjg2bDJFXWJ4X8vtnA8g0JsK0+kGmRxg+FlWXTqAGJbm0imoE4YSQ0NXkfj\n6eFtgebm2zdRRfbABJX/drZMSIDYl5Le7B/zqIeI9cO16GDEbyDam+MXD+mRt3Bk\nJ4JyJPCin22nAtKb+D0zHs2F/9Iwi+3IYL1awvHspfOQVwARoj9Jc0K98qtGSa9M\nKikC+0LGr4zw0fOSMzrhijg5mqi8wTsYn/9u5+TkQ8cwg6cBKCGCjNOi7ml6uyC5\nLE4dYAcSkFbbRRNOuM/RYiKxFpGAFrfxUVfHI3dLjDe6DUAN18ZmLitij2WI5TcU\nazfFRYMnkmI12Tu6JeKrFrhQOt4gUq1W2h5KwvKvZAikRvc1pE+X8h08S/kAwsUb\nPuxgAN54myeHIGoaxG/C1ImaRoSPquKVoayJoIwDQ2kKJJ5EdXFJ56SyA1kYk4y4\nOhv+kvk47ZAwFZnNz+Lt+22uFOnrMZobv/jKsTRfJsz0QhwmTIaB9C5QehkAeZJD\n6M/JVjRWoLALcNu/S7imzbzNBS4r1ctYLv2dkakzBhR4o5Yfn4sg48p1x5EBTTre\n6X3/qWH9z1vtpJsjC7vA4ACkLaz0Vb9Tb9No+Sjjp2xi6arJphMwjuZ0LPf0EuVd\nwzbkRHXzpYMACuaypNaTQrNCgpR19eV98SThrf8QkyyKD0qwtzwoTmGX45FnGFWy\nH8HL+lZzfpA9zzRCjqLGeTkgQJLIMP0orD9kkVYCHtUorUQPr8MIu/o45PKCZtNd\n++kaTm8x+wjXYNK+cyOnyda5rj3XsMYqPnMtdg42cHu4oODEV1JH2fl8sXpuGB4A\n7qsSBORrZJiPEdayT9Gsve0A6Vi7gGK+9a5WRxqS2Hlbgr6lgqUr8zX1YYi6Ace3\nd2GhEqNvyAX+6Cp9FYH7JauKtrMf40LxCNTpTmhhrhwS61nd+ka/5e8v6G05eSTA\nESbBKo+QiE2Ek1xfrfKlsc8IcBXxmPF5QQ7Gb9eGI69myPRNTv/XN4mnvA8bZF8k\nKqLp3lO6Y5jGKHToooViTDX0WRApJF94oaefuUbDJpW9foaOfZpBz4yhLnY7syTd\nn8LNRYbMHbFbbe5eoGhb6goHD1R24/SeKumDpzyj1HewcoYGP00toDFxijY/AA96\n+4HlKJX7JJEDvORgVEZ+tOGo1xplagrndpKnX+WsFzvuPJ3RNFifbkp7iRP1W6HJ\nGq+oZ0ewj3z4MKi0s58BgTwQENRmLEdp0G1nyYY1nuRmaq+t1IlvR0bMYhTARqcY\nGAdHdwJN6MXQWFyqTQ8L9N0OuCpENposKBvdUcrSFAIALafX+vJrB0aS0ZVM5w37\nyiskAa1KMqo20XTiH9z3awnKAVZqjY0oE2BTehdK/NWgaLH82AsxFIMFmN7GCyY9\nQOIlzceqRlltJ7PsTmvDN+pRaO6KdcbtO/7hsvUgZWOs6x21JRQHUShDNB765dlE\nusuEl3T72TBlTdxQ1tj4fA0RUCAF1T6B/9aW/rBsPTQIBLyJEr/78m7lBKmgQ+2i\nREjuQC8NYkzLLa+fOiIO9LTjPqdSpzMCqMIbjiR1eYMJHFoP+8E2gAqKZBDOaNoI\nV5tfZk+/Uz5AIYQocd1aUEQCgyf2WJLp2B5boO2lS1qXBb4YML/D2L7Udz4JU3Qk\nfkSlDC4zx01XdmmbGedBCGG3npf/pCerrHcaPJUWOjMk+M1tR3Mpmmm+/yJm4Xyu\nbPcvV4pEqlfBsIjLCt6xyF18vuF458yB7djtZJ3wkx9lLbpLAh/z7ywoCF7B35nQ\n+kUjFBsboV+1J+9sK4bULrtYOhjxAU1P7Mpq4BbWbRWBWK9/Kz8maeCrLEW/tpnk\nEureG7aZtwQz6vHyeDDQTpFVdeSFO4qFy7Pouf/VVzX/eph/6y3ZDsjYfxFiUD6z\nTV9aPs8WDDcWhd+voSQlBlBB4ttspQgZhefCScu6hhW5PNVFyNm/TSHleOEBXiEf\n0Ab4FeFkQ+c1GwhtvsmGLBP/2VzkkDSunO2QDbpNYGzR2Lsn56JQjeKwiTHblzRy\nAwSJ4DU/V7S2K4wu9QmP2SefrBJTlbLd8VFbwAGAHDeM5Xi/TnleaQvUPGz56F5l\nmoaYsXbDQGlyA+PYs+CCa9rSfvppX4EwDIftDqxAzEAIbQJir4VEiPpE/CrJtUc0\nJMI6ug1Cpp1p2U38y+POyv42Awk8M3KOPUvXxQkfU7leSClLh2zCAkC1CeUGLrZU\nG/Fuob5ZjjJ6I6/+3jF91Y6bDvh9e71jys6eTnYNfXs23f7uwqv7G0VqhY3AjXKs\n9YS81sdBNbZIObMeXA9w2kG+RLWB5C4hpkqgoRJHDyE06Vzy7zzWLBS6AY6/f2lX\nlNVUETpf7j3PU2bGry865V5eGS43lTUnsMUDVQL1OuiWLg30JUH2AP8cqQqgN+O/\nmK44RfZIrGz7o3currsobXBMNaqFqVlCRtdqEVsiRprWiGlHtLEnAh/UNVp3h4ca\ns9nGo0wA9bpHqAYzyJoDKRgjj4V7vk6rDNdJeRow9v4byVOpEXBY2WX+oRWYruyR\n+ArU/zAeK/6oUb4yegc25SGTZxEHlZvZs9U8Ft3SmzGDtuiS8tgMgfLe23fN8mUv\npRwRqkRmPYRZpH23MTWVBGSAos9nlP5MxA7IgclRywpINOJpNsbPbihhcjd5oBhK\nZK6eqdpYUdSWHpUdSUi3DhirYXWQA3bGjhJ/IuvGpqdXm2P9rpUArEjwuG7De7QS\nt65n15oECLzVg/3vZviKSC0RkW5p+pQEbVifxu3Azs8SrUlXsilcHMTnTVGK2wG2\nFi4ReqftHwy1JIAsMEeAQAvuR86TFaHKasw2p+/IenHo/cTAyqEJjgGeTJWjUtCK\ndUavMKA5ZYIP1E5/F0/QBNVToghoDgMVV870p7QWjgLVtPVCDPx3I7JKh9GBmNR5\n0dd3JMpO9Gkk8cBGwurrr/Ak8ynRLv0MRdB/8HDp66XiHR6tBl8ZoZ4ZsnME56Bc\nF2+OmOuxVThpOxPlECU8XtI37ZlSxbG0X/s5eBy2mmrVDzGQDYXC3VuEp3lrk8QV\nk1KU6zxzFLXnKEhZraP78TIKhvV7tiggyTBmx1emLigMqmd7AnVseY1LRlFQgUB1\nwloOOrNW1gpIoUUMVuRjFA==\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/rsa-pss.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEApfv1BYcLTl09aBmW\nOnwUEKxByqBZeCXLp6Ck6/plp3GgC9gtFMfSk7mImkIt8BAFWK27A0/vOFDf7SDX\ntFYtlL6ZukxSgaltyEjMVMX/oqB3vMsqzDX96So4UauDlQexWORT0LcUp3IcjA8L\nJrrZS6j278y3ah/Xkex56IRpfFbdqPj/p4rJMw0WFtqvINV6C2xGxeoC1/LcHM/H\nWQLpeRD5PgnIwUw/dqMYtV7nfUDU5wCJLe6I0ogdgmCGrAeogldFilakPs47yU03\n/b6qWFHaj7OwGZRV51R/GChS1HdVN42nsXHiIz26KPIf8BS6O/iAZlUaS8xhw5XB\nje0uIQIDAQABAoIBAAh8WZn3Pfo7JRUJ3dbOmh4CGHj5+qj8Ua2XtmbEDediFTsV\nybQ6xQa9YQD16jBQOV2/wARa1VGNPO18FNsI3tqwZd6S4VL0rQKkyiF5X+jaCFUU\nE/ONvRXrDScLvDXlx0jSn4BXo8wttszoRfssaUiHclxvHF9mEljI/LCI+HWdTAys\n+3l/Yn1ewwA2iFFU+ZcwgvZHXjLjRLfImTfr7oQLeolpP9sxfwb2RdQ24ifgIh9N\nYv9KzFfFJNl+2o3q6XBKqvjXYWmTam/hwXhGnFNb3LgrOwkSUIVpUJl52F/fu+BD\nAdJu0ELPUNIu2Ll0fBp3Efj80vcSZqtDSJ3Bl/sCgYEA6DZQm1L1Y2tPMcX+JLtV\nBKC19YRTJLI+CQsU5YnD4DN6O3a8PITfRf+SHWI9slGGs4QU0rv6NLMj4c0Vxsbk\n74LQArprdw768+hLH8z3r/fAZ0QrTJZSKMuGvs4To4dHvNSdc2lYDtadDysPxkKZ\n23aL3ApmCqZpHvIUndOGKV8CgYEAtvzWJd6faGWUEbQI2qI4/H2w/t4oxIgVDOeu\nqCjIfw3jj9QUQrzC/ckHEJrb9ILYuzxfe92qPf9qmqHyE3aKMCN4MFIz+PdfwM7F\nP3/QSriS+PdCnS0ysmHrUdJRXOsl6SYDVnCfyhU6HtL4GFO5expMesogpw2xXkYk\ngYOaWH8CgYAP0SNMcSoly3lpeoMFHX19AzVhs9G1/i4bj5WszOV6sAbzZfMMbECJ\nFA9v0PFC5Cq4r5Z7hDJWxJz9FGsXTxTo+5APn4MSaQLO+lOjpuJ4KfgBELOiU9rk\nzHgxJvhPezd3tUPESLimyheIoPZCGuc/+6MrKcopj4w5f2PIHFBXIQKBgQCN7qTn\n8LpyTj/AT4WCl8tdxNxRg93ZOrghL18gnamOKyaz+8rPTPxtvsyVC5jKGeejqxtg\nxzlyJzf3wt8yS4K5/fkOeeRIGxARTBBgxXG5U1rkc10e7tzg0eSlrV1glh/srIhw\nNqEqLLbNC9RVgjNfEbH6l+clzBAkUIGmV36TXwKBgQCI9r8ZYR7xGYYDTpMSbGdL\nXpWuNWwgZQsvBAH+pXaE3A/36tXdggA5nZH3SA+yIoJHGiXHeM8K9LOMAbAzHhsJ\nia/yFcH7lat92/28mrxoAkHHk5oUdIcP6pcPny3cE874sh/UPG7BNKrS+h2ll21e\nOFsE0r+qLh68/S0HZM1/eA==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/rsa-scrypt.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIIJpTBPBgkqhkiG9w0BBQ0wQjAhBgkrBgEEAdpHBAswFAQIXPgQcyUbFcgCAkAA\nAgEIAgEBMB0GCWCGSAFlAwQBKgQQAEM4E1Gom8Gno5BsBlIbbgSCCVBXC6unomo8\nRViDXg/JbarYH5GAj7PJfOHMtYVGWSuysLnoANxqBLsmxvfnzkoI6hBVkU+FJwyG\n4CZodJn/q7OxuK2VYtE2LV/2QgfBfhDpBSvcfoyfFy6QfBZaIP1rfp4cDucuHxn0\n5sab/On/lw2qALw5gS63uEJQ6GoTvTgkMiRVKLi/ozqg44mn7N/Rvbx58IUexcrm\nZsFCzJBNPp8Z4fKCTi1CE+Z7BemhAzL6JvE2IHBjaGsZyr6rKOYv7u1QC2KTUyEm\nFLNthxOAqCTaWGYP9cstE38fL0zE24crfOJaRd+7oZu0LwwF2R8kewSKNze7+WbZ\nhbDWu4qWTdHszDeLnEJTCX/xQr5uj/c6Xp89FR8ovsTY/nnt9cEhX+x2tzjxIuR1\npTGrJvgwL/3PS+4d/O5w7SBpSUSjU8/gPLSU+pZq87+1JRZQpiBUouwpwE96/PjO\nD4iQM7BcDLYaY+f4pP/K9N3fIBr5hDH+QeArfZ5/Fy96yXijlJIm18Z6xs+aoLbe\niL3coTVUc3sF7beKDE7Y5qlVBw/pTazmcwnUxP509j/W/+WLXFf6WjucH94ZchrG\n5cgi8LGtP+jnrfyoIK7lLBsT66tK3cUxjhpiiHebEQ2RpHpvutoiC933oCZ3FLQf\n3TzuuhWiY3ufIZ67xXZ+i13Gwt/f1OEk0hIecGbLheHKFykA2t36c+/3WZb3niPW\nwdwAzhPaX+nvrk5vsHVgdFJNrXyYwEg/ygO/F/0yXbjYUX7tKyWbb4ikhJdxjgZv\nieDC+9RIAMpcC7Ac7G4c2vNgiJlLs81apP0LGQ3n+eibCz2VJWzsWohbMXBTcDfc\na8yJMRaiOSIQlEwes5k3vs993qL9nKSGHHGe2e7PMHuVinzEgkaDHlDfIuFn1KnA\n/aQGbgU8jwK8VpOkjNZllaE2bPZibgQAcgctq/yGRbxfJcmX2HBKUoca1Z0ntLDb\nL4Y/hZb7b577NlWsepxfZRlVqj0KXIzTc2XrMz2U+4D5fj4+KUkk1z75gE3o8wGa\ndkfRSA+LFRCyExtoMSSSxIvlaHRVsL84kkcClh0IjRViGo2708HObkPrBxk8lMaU\nx7lLB0IU1ENjcqrF4rfLwh2K/b9AcOv2zcZ/zgDYEeRXEHhw48+/PzdQ8GRsSanF\nGNjZC9tJ6uCP/uVOcoUoHycD21WjSjZ9naGI0nXWbIUYb6uaQtwPKmNqQElwaXaJ\ny/ncQkxYDrOEoUI8fZFnX1PXHEtP9LmB/MH11RguZn6ha0onFvSMqb9ZWPWZH9FL\nL7tf2jMSHOXjwCKKGugjcj+RYg21P68PUpkCeKnDTpWe62Nx0CHGuylM9UvOS9AG\nO9N7XW/nzPtgoAoWnZafiE4bFea1w65OszHDFuK+k5zrF79dxb8ajJ8XCbhh+Ywc\nDAhNM2jMsK0Tx2rQylFzdl+KcTMiczeTSBxV/g78uoJ2H6/pks4AHkTZ5ZSe1mkM\nqt8DIVhTyV0jUwSj12Fss0yAps51k9UjrQ0iQaeJ6VCCaePRHQ1YyBJT/UyDLlBD\nOPgsUnC5CeN4sFfORAAhUq3jNZ8TmQ8d4RJIaqTrI3ItMz9kiBluq6uDQMJ8a0gl\nJDv2aocsar1dri7TefouEkPUwbkfw+ahlerKiQcQHmaG4V/KWyu30N0axJKXLMHY\nticksi9RzJGthbkHTCru/Rs+va5b7Tdxla8r9krRamkjxG7RtDet2czWNLJTCC0q\nVZAy4iMT9NeJTgvWkOhYzWPczkNiCDGSPJkyHezK6lYRbnkBR5KITiRsIjXHsH99\nLH/77bewFdyl2mNwy/0+6p+rLGnvPX1ZhxYYoKKKTmNsddVZh2xLSczvKi7Pd/9Q\nkALBSxMPdt7klPXh5BGte9WA/4DEsiyvmUwNsySCtgcMj9xiSJM3COhcs1uhmGch\nuv0Znl7VSE/1Y0yKQhW91QlA6JIGAh319t1VJYcbSiOt3FoCelu4ya/JmGLNtfKF\nAlMJrj1dqxO0pGwpfKHfLeC7G430TPd6ukjFwy+jrPn+LGw0Wzw5BS2fc6E2JaAd\ntfLM+AUlS7I/+O371e6V1g9+55KaGWsN1K99j7W9Md64BsqvGXeJwQtG+JLkPIiv\n+ETwbPe4yrcJgslZ0CDocwfLIMfv7sU8PxFXdzYz96NDSYU5HN9l6XACfBkYc5DQ\ntYqdcqDXIRAOpMhviZXkNW6HnaYugHIOIfIVDo1ZoZSNnQKAHt7jvjjQ/Kb+JvMB\nKfCtyJvDl19S3XhslRViEc0LrvE3xZIP91QM1SyhnqagVY142QWyB6vd/yiMjndO\nTk0bH7wWdk6DiQTBKO3QV2SWPkTy5+O4uHKPO2S2ebIEzi5btsgTkwsBtzS+bo4f\n54t1RvBqg9uHUHKg/PGBX+l/TNQnk8RBVXF3U/Tct2d2W14+YT/UbvxopFNizXHn\nG+kZvv3iOAACfYlGgqarZ5i/O5eiMtOBxE2iCwFq6h7LBH3R28L1pZ0U/pMBWG/n\nvadGNZQ5DGd82n15ieRqXeRNlFt9+jPW3T/eHDUEIqsCEkorGLzlyNWJrtn/0WyH\nyLeiKBSfyBrS/IbDCQ80kVYaFF3+m77kjpFxSN4ugyruPEXL+ofZQyzt/k9cprlr\nnPun523IiG+4bMWHQn8boYEWua28R9Cyn5q9C2HZskFAvEiglyEQTfrU6/lrhhei\nyZU88IL7vwc+8ajToqnNngPedRDkXlOVP/YLuoSry7oEV9Vb5PETypLEvdIwaOcZ\niTp1EKt+ZD+ryJn+D4vrhNDAGYhEDEPiQY9nHC6/w1/O/oAmbhwiqChSxTXecw2m\nKWZflrm53t0S1NsEvmzWKo5QgJlLbeMO/o9HE4xy1gLINXQQYDUBV4IVjYxsIRYd\n3TERnB5bmL3Efsa+rKXmYy2zNg+RVl5iK56K3mSlCo4dD0yAYT/tD7lX8brCCahz\nO35C+rkwdCIRr6CgCTRStqxJjndC+uyn7/SxfNMc57Mdb87UjO2DHiLAr4OUoq0+\nuOmNwygqpe7kzCD1q2AdueMCII5aaqVpVtJ//r+0iswlRaciWj/VMfTqTQDweSvw\nw2gQo//1NRalhDYYWzr0PfggIIcEhQfXfPCk2kG/6mCBfXKRvBm9+WrQkKS6zdJ4\noDEneepILtLCVoJewFPvdkpnL1xcdjveuw==\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/rsa.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQCb/Jbg0D7zw7IF\nDBzn/KZ0kjPf+vkOaZOxNG/PosID2/+OKHK9oXgnZcVbEtvJgR4KKjc4nrSMFtFa\nBbwsvJWxUEqGjLQ5WahSe04R2yZ4LViGbFuBOHAWq9qtxRyDdkghrQvNy8cOr53K\nO8/UAOJCgkYr7x562QLEQ+FUvpGqID2xWI5TUxVezmHdU/sZF8bRyH7TtEZ5zMqZ\nLt2hjD8CrzFt9aMv2eBldX8c2YTi1/3YPKi8mos21jsyRFa8gPeyi/TnKfA5mows\nDWxCN2dvOw3ynKapFQV1QZief7KRxw3FGnUOdUfw/FqfpddZK7TJ3/AoaM6oNHy5\naAqcVMqPqb4ZC0eO1R6+xIA4SoZBD+ZTJC2khoVQRRwfRyKQJpp9eWJ9+SOGCkCY\nr+yZbcvGAuz7Y8SPp3kUWZwflofRCeE3p77U+icKkppkkmEJIb1iMm6qYoTjc5M/\nwTpI5qeQmGaftzz4dlWafTAbHT2jbwvSMgYFQQvW4RyV8Iu95PYl6aUg12mXwv6a\npYf0QuOPGCMP4UzfLfFTYDniS+34aaWkl77Lzmw98BRHa2Xjmn+iGQcHYjKvh7FM\nbRBiFxcSEWjkh+mgDypV+8mqS6FOPC7WeCNvt1XGIRoKnlF4OarZjdI5KP9wKtV5\nhhx6GQpeuZSWyTBLKbVIsuUiGG2VxwIDAQABAoICAD24HM7JNw9mkCqVF17nRcl8\nC9CE0kTUm16TO+ZxJMk4JA7QjE3h9NPJ3ePiO1qonwUwnPbnPNLtOFqhSEp/N8+X\n0FUamTjT89jm9wXzq24DqzJM74vak+c0imsVQen2RCYm/TOpfJKgBBP/xITC8MOW\nHkPF8k5zTTfxD9hjKumgpihkvLPVfPAtQuW7E/BiywU4io4jl3sb/9HKjGEeR9Q9\nE5bJiY8mazZZ3jjBDGZhRgxoO++cSpcg/v0tsxAVC2z3GajZnDZ+oxXPHdW5bFDD\nkgo712mxap5xnPyh1DsAAr/JbyWQXC3K++SNTv72Xys9Ux36EkLVub/2nbQrjJXb\nVc6eoJRpoeXwvfeqnJOaRUWqluSxqhxI7ngLtVxTAAM79H0GBdAEaB5DvU20zdu8\n7k3ggJ9Xoyu19KiCsC6L+Odix+vTyv+QmIQBGHB4Ts/4YrKMLF49HWpo2qjV9Zef\nbCKjjzz8VrFk5FyFWJQk8o0P9NLn6+epD7n/ndjeUWy04pLc9i3ya7wmojZZbWKE\nUpwcruX/el7A8t7cQjMKHO8/tzFVPsI7o2osqvfY/sZRBWuDe3iHgY40ROwvUvjr\n6k6qwIHPmJqgywmMbv0KD+nnjGqIYThxuvh1n9gp/JlI/QWOs26Mvwk+QFMbA+6g\nXfihMLpzLXWY+Z/7uT0ZAoIBAQDIFiDO/Z2VRS+vNlYOAAEYP0amVTH6Isza3bZe\nO3nvC47Gj4/vcxJQdrMHEtI2/geLXDv9jexox8YvcxQ6KeJVPSNRFVHGIEWLUK29\npEzPZDUl3xYFl/WTHLn6gxV7uqxO+Xz5TTCaMRCssbz69QZPryfdIZZ1+WXtKX6s\npaRhwwizln9c7vHoN4lPO51Dk1iP6JqcJZdRzPXHSjYSBnuapWBy62+rkHQBbOFn\nyv7WzhnbOEYM8GlvteDNH4xG0gcT4G81dOtGw4frtfpphU8k0Vy3LypjlVQr1Smd\ndZdbC9TT8kC2hyB3saCp9vQUc1U48CHHW7BGBYTSyaRosndrAoIBAQDHk6IQuF1A\nOM/FNwD2nao8I2bOJEYyPgaPFv/lUytC5fmCUuU/FKBdyW+0wtIQDxp/zG2Mq9L0\nle0E/L4WI1Zz4jt0tef7qDLm4tadK9foU4vFuFpfwnvgP8uAgzxgK45CTQU09X3N\nPRfw4Jp6BK1giEqLhuxXrQvhTocswnIgB2s4LUv6g2LEGpyfXCLBoiyBNTYpxHYq\n3E4VtOycxniwUWnR+PQOt9GwIDpjKHzZMHfEOOrOyac85N1s1JDxC1s5XftPII79\njNxTDeN7O/BP1eEQN1U5Qbw36cjrNzgxNzK3L8NqZP0YlSHpm1s816Am0+TM0oF6\nmKV0VCYYcd4VAoIBAEWPa9iKUz6RzwIa4c/8MGU9mlI5TCap8o4khkI8ayev3PMq\n9d9JIhTXL2ZGJM75gaXxaum7bXT//uaAG4gdB5KarqyBvOwkTAkjA0Pq2sk/DTsd\nU4qeScHbOszcxZs+SqkqE0iYjU0Nwb5IDGsyw/7v5ev6wVRCYC0TP/bFn2BdbakB\nqUWlzHPu2s2w6/uSPjfJpfajGvhVSRz/r8yUdGRPGjjZoPkEP1A/ih2LdQ04mcSc\ny72z1vP/RygIz7vPSKagYAk1nJX9ZEOOAICu19T09Ea7HwF/6MNUWCNlvjjo5BTL\nI7RRRfhWyIROVozFi9s/oH6uYZn2UTb24zGC2gECggEBALiIfECDh82a+hm7Cwv8\nqmwiu6r9hV5tVXk25fNv3D9mDzd+WHPkKYeuergjr0GkBXeHWP/J3CvE+Lw0yboE\ngKpz00/N5qsdUbuEoLYA1Qj/PuzZ0c5bMFkgA5VXQxsVCtupBZh7KQ/9XkaeFped\n/YWVX3/1iFBlM+fmyTwMqqOM2Im/8FG47Diw9oKvGX/66LWrsuIZwr1MqHKPsHwh\nU3SMQpEgZOG6+4qjsfj/dbkIhKUNj6cWc6jtYQOA5GfMfVPk3zrBuxUcCphM7jqD\nKGdZNlndH9LqQhNc+ibrDu0Kwbz5z/FvYUo6knnC6TCvm2hrYlI0jf4CaHHQYM0X\ndCUCggEACvTEoQ7gZMeaqr+j8fhsisLoRRCtslqoU27jqWTriISlnlvjNHqYOWb/\nJXinuvpiYZG5jih6KXxa26H+Q5Pb4amVNPq/d6qBu5yv9qpD3mCJaHNHPByLScZ9\nG+pBW+y5JXHCdFJjo6G4ipLLpPglAPte/TmEnoShGsxtgOmupYSliNteAz0ykvSv\nAt+UfdzdSY2uHC7JLnJjB7SeOz8YeXyE8KCBOAokxCjs0CdBeZDK46sti9umMuIr\ncDVIk/azvt5ex5sXP944Ds7tUs/qS1bdm5DsG4XYBkSKRhNqlkdxLumMPnGcwsZC\nJSRSgO3qryi1B/PjFld2fmtKpkffCw==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/secp224r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMHgCAQAwEAYHKoZIzj0CAQYFK4EEACEEYTBfAgEBBByDAgBh6UOQqYJSPoiNWrK0\nrA0rTMLw8JdCEveBoTwDOgAEABwjlgBV9PPpMfo8fo6yWRdT+sb1cUdEhobd+V/D\n/i58cWpDqd4CApevJWtkGbwhU4J9mN0aYrk=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/secp256k1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgAjoYh3zy6gJciB7F/pHi\nfU+IfPBeEhgQBFT3zNvox5ihRANCAATTIv3AIcnOXMvnURBseRspHsowmPAxPgsx\nLH5+aU2mW06f2PsIe9F8gG/Nf2UOOuO+aqwEStIkfSBR+Fwpl2UR\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/secp256r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgSFp08cP6os9Fxmky\no5VFi6woYEqvbhVNYTp9NvwzBCChRANCAAQo6UQaiHkZr7lxrKDZyL9Qinr4Vy0Q\nW3K2EPFYbVIupvzW0RH8vBy+0/yoaNyUsw/IsmBO+A60mhBB4rTjmq6R\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/secp384r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCqdZTmuPvhbOVI/Vkk\nyjowWmBb1+81m+ay2QF15TZns1iX4HQlaOZ1GzaqhJRS0R2hZANiAASYw9dep7R9\nIoC8Dzt6T0NYOOJE/TPdOXOH+M6uJvKAtmXGalFeLQX6HKlUDNPnBDTKp9p6Nu/o\n2k/p2C9m0DaX70sNuyfOmh738Bw2Hlz3If+903Jj+hKSR4kWDkKYb/s=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/secp521r1.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAdO/4HyMRu7/QcjYn\nf8vynFJRVOKHVVmRFrAzZwkdusoqf9gkicCxcxhOpOGLezzTH4XBynbcmmMn4PNS\nZriTYO6hgYkDgYYABAAp8YOO/QeQoVEdzsOwZt1ta0/b5r0ESM/QNkBVgrRdCsJ+\ny3p/xis4wFlhv7lsrtuDoeuMimnvl+fAfptCzMKHugGBvSE0SjLgydEmUjh/y/a4\nO3cGqwUXnnxiLKJ98NFaooGYY+AwH4h77oCbQR1lf8jhe1qsJkR9mXpYuGnkaJ7l\nqg==\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/x25519.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VuBCIEINAdGSXck38nDXMgbRKqKiBPVuxDirhOs9VDE+NaokZz\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/x448-aes-256-cbc.key",
    "content": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nMIGrMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjrmjUn6y1PFwICCAAw\nDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEJuU2Lvx741TqKFa9X8bRGkEUPYI\nSNtLGe+fIcgz7rF8YaTnA0oeMsRp4RxBw/fsaEGrHUTM1ddjuyRzdKKNnghZIs0w\nzy/O8QNXDzrss5bnxZyHZA2XEvftHTH1Mw9jCtwA\n-----END ENCRYPTED PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/pkcs8/x448.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMEYCAQAwBQYDK2VvBDoEOFRfvQhj134qZjH0wDbmPc90BADiqrpGZSae/sd8GG84\nau0ISBY6I7BJJZdiLLED+0abd0hLYAyl\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP256r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHgCAQEEIBfCkWEWyc2tHIvSAo6hhcj09dnh8NOmtZeqGmcXHnIqoAsGCSskAwMC\nCAEBB6FEA0IABJbsd3pZks2/1qhGV29b3V8f7XCKQmKtr3sBvB9UopDKAAnhVUXI\n7st9YCeEPDO1EJq0ePll0qbVf1EOhpLd17k=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP256t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHgCAQEEIILhgc3joEZDWMDm9TYgrENN7gbqtMpMw1e2MTLwlJhCoAsGCSskAwMC\nCAEBCKFEA0IABIgzdtCT/Dvc0iuOrT+jJFyTzQH8jSENIToHEP/xcOVdMoklPgTx\nng6CA7FvC5xJUtYSGVqtCVUDWYHuXotm7IU=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP320r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGQAgEBBCg2J9Odvhrl05HKvxAVUztmTD9/8AyblPk9DqJVMLOufD+RnyCXCX4k\noAsGCSskAwMCCAEBCaFUA1IABHSnWUC/tKXpNHGEP89QVKEgvetwCQWFoOENAgXO\nRniLiaLdAdsR80ouTsZiFgHG9su0l5ESEnFWQr5xUMj/vPwwhSYm+YP5ucx5Nezu\nBM4d\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP320t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGQAgEBBCi0aeKsFfr17MTtr3IgFByp4IybuFzlgAbwPjf3rK0Fr/b87+WicOU6\noAsGCSskAwMCCAEBCqFUA1IABDQHDepa3l/S8Gt9WrNCNpCPZNBXvmkGPnVXZchZ\nI5BtUySwYxHX1tpatGs3jY7drVYm+NyxZE81pecYTvXR8bu7e3BIp2SwZmXEDxdY\np1fw\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP384r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGoAgEBBDArrLo3J0sxM2YuEM0/JMMoR6ZNZNS4wZ8FDETP6VAoCrP9Kji4D59D\nOiv+3y2j66KgCwYJKyQDAwIIAQELoWQDYgAEaK8X3KCyRDMpbACw2xG4UUe9Oxyu\nGWFaGKPxhKJDyW5Z56gT5P1Q2y4CblL/X9VcDIMXdcQqRNBkPQfy1+fJXwKO0Clf\nD6MIE3bv6PTZ55J6H2H1dpg38a2soRchz0FN\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP384t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGoAgEBBDAEZRoS9O2fGbx85aPZzZxfj33Wu8aZ8a+K5ZZBFuVKKL+/0UbidDhD\nYiuAHL6GAr2gCwYJKyQDAwIIAQEMoWQDYgAEQL0dQoOTArIx70V/XxipoxxBeKT7\nzmIe7id5pQiw4O4nA2S2BFxQF9eW9ipnm6DaN6jaX/+2k+cC4qIfqzeLcLUFXxz0\nqdec8lNNtr9QmwoQlv11beeHmQu9C1GwHmvG\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP512r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIHaAgEBBECYRA0UwYgMuiMq12DxXvVZ1KzsWIGQToF+3bn7JjyiG6CT+7xop4go\n1W1KKsyBCEYUnL8EgGS8zpXUl+euCWSOoAsGCSskAwMCCAEBDaGBhQOBggAEYbjT\nnA0x42NdM7jVv7jAoZq0iOYopbwejlOEsx8/MqRaYt4Ef83holIsgOHWSeW+kw1o\nMDmieoCrhnkM/3KgGzV+BxCeieAWGxABsj9YhAmbATorRJ4q/pMxRq8gIUv05/dG\nuUttl1gdbKKnGQjxDBM4v5H+/4z00nzzj4Gbfx8=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/brainpoolP512t1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIHaAgEBBEBNqbJnTzwGwg9JyyXBrQjXF8LT/q53Jydyv6L9AgU5c2vg5CJVvgoL\n8JL/YU+i1UwVIdl8JLZuCLpi+Dcy1rlIoAsGCSskAwMCCAEBDqGBhQOBggAEm/uI\nqsytMZypsqCuL0jwZh8xCRVEkUd02YPXcOBhMzS9bhAao4CLAuXhWzplr5qk/7tt\nvczl7qFDOvBzNAIieZHwbFrouZ6Pew8pQXRcMDB+FnXwNgpljTNmz/f1ePjVKU1Z\ngbQ+xVf8Qt8OI9S0Pla8siTgbVweGMLtq0A8Wuo=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/prime256v1-aes-128-cbc.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-128-CBC,3F26BBC4C7A6F3B5B3A5C03C7CC59B33\n\nrp4qC+n+qIG+WKJp4BHQHk5z0oraaaLZvoVK5glESGx5IcR3mCsN7tdg2aZ7yEk+\nHnT4nQuM3R5pv248cmK0xDUje8N7FLe8lixVnEyQx3JdZfGdauowt9yaxL3AJypX\nidWxNrxz1xff5RSMI6+PFv2SQpG0l794EpOjZxOUABM=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/prime256v1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEILnPbqUzEJ/G/paAMenPKttHR2AX91fd++CN5CSA5gtUoAoGCCqGSM49\nAwEHoUQDQgAEZy7jsS+5+xqtds3fb6tp3gL+j2HNYVujNoCSkm3xWBobXt/Nozid\nk4MGk0C/yeSD0n7iSpJgDwSJfAnSSlpcAA==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/secp224r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMGgCAQEEHIMCAGHpQ5CpglI+iI1asrSsDStMwvDwl0IS94GgBwYFK4EEACGhPAM6\nAAQAHCOWAFX08+kx+jx+jrJZF1P6xvVxR0SGht35X8P+LnxxakOp3gICl68la2QZ\nvCFTgn2Y3RpiuQ==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/secp256k1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIDA00HY8HWvgF6YYE3GNc9cCxlHqL6gmeNXQjyrg7HCGoAcGBSuBBAAK\noUQDQgAEwTINsajIo/W+G+UG2iAlGPjwl4HcCLix2q7rRmCcNO0Px/dddeFdgKqH\nHLWuyAKpRzn+BxuX8W3TqZnJONcYHw==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/secp256r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEILoEofWgFpdy7y8VmPl31ZVoI0hRFwOStu2PpKlzpgdMoAoGCCqGSM49\nAwEHoUQDQgAEgr3Herakdcrvfr71ncnniKEH2Te6kcfhkHT62MzoL+kveMsY6NDu\nrd7NNt9Px1scfCzkpZZI3fe4m1lHMatQMw==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/secp384r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDBtqXb+BJ63n8LaSU1UU25vFg8yW998I+yJwXLCgqMuPDaxfY1py4KF\nmBX2kRNlBVygBwYFK4EEACKhZANiAASYI+WvOkNIX6vPYCBx57uUpFeEsK+9jbRG\nFGaqN0ip/aPMWLp3n6JlmO8Ug3xgk3qvy+gJdFBJsIWs/LiCJc/sEilUlg7JAd3J\nvFB22r5EORPqSGgHhdlBUM+9z8L8v2k=\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/sec1/secp521r1.key",
    "content": "-----BEGIN EC PRIVATE KEY-----\nMIHcAgEBBEIBbhPg/ddqjdlQ/u0GlA1O6bzbOaKVRn/fxzWVEOySNPMLwiOTddzy\nvfuKFliNFLTx0KV4523h5UQjFB6Kwh4pDuegBwYFK4EEACOhgYkDgYYABAAHrlzH\nUouimWUmKMrMBYlhLNQUzn0FahYNtOt8XxLhTUoo7ySLL4YvwZKYBp3ZMjqHyG+S\nHcy9pkkQsF3vUP9rJAGzxg/TJUEQNd6k4AQS3qtLxA2p7Ygd2zU1Ed+OM/aaj9SD\nYxRQKIAqe6jZ2M71zy2oa/WZl+MNvgfb+Oq8YaPZqg==\n-----END EC PRIVATE KEY-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/servlet/context/exampleEmbeddedWebApplicationConfiguration.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\">\n\n\t<bean name=\"servletContainerFactory\"\n\t\tclass=\"org.springframework.boot.web.server.servlet.MockServletWebServerFactory\" />\n\n\t<bean name=\"servlet\" class=\"org.springframework.boot.web.servlet.mock.MockServlet\"/>\n\n</beans>\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/test-cert-chain.pem",
    "content": "-----BEGIN TRUSTED CERTIFICATE-----\nMIIClzCCAgACCQCPbjkRoMVEQDANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMC\nVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x\nDTALBgNVBAoMBFRlc3QxDTALBgNVBAsMBFRlc3QxFDASBgNVBAMMC2V4YW1wbGUu\nY29tMR8wHQYJKoZIhvcNAQkBFhB0ZXN0QGV4YW1wbGUuY29tMB4XDTIwMDMyNzIx\nNTgwNFoXDTIxMDMyNzIxNTgwNFowgY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD\nYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARUZXN0\nMQ0wCwYDVQQLDARUZXN0MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3\nDQEJARYQdGVzdEBleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC\ngYEA1YzixWEoyzrd20C2R1gjyPCoPfFLlG6UYTyT0tueNy6yjv6qbJ8lcZg7616O\n3I9LuOHhZh9U+fCDCgPfiDdyJfDEW/P+dsOMFyMUXPrJPze2yPpOnvV8iJ5DM93u\nfEVhCCyzLdYu0P2P3hU2W+T3/Im9DA7FOPA2vF1SrIJ2qtUCAwEAATANBgkqhkiG\n9w0BAQUFAAOBgQBdShkwUv78vkn1jAdtfbB+7mpV9tufVdo29j7pmotTCz3ny5fc\nzLEfeu6JPugAR71JYbc2CqGrMneSk1zT91EH6ohIz8OR5VNvzB7N7q65Ci7OFMPl\nly6k3rHpMCBtHoyNFhNVfPLxGJ9VlWFKLgIAbCmL4OIQm1l6Fr1MSM38Zw==\n-----END TRUSTED CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAfgCAQEwDQYJKoZIhvcNAQEFBQAwgY8xCzAJBgNVBAYTAlVTMRMwEQYD\nVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQK\nDARUZXN0MQ0wCwYDVQQLDARUZXN0MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEfMB0G\nCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0yMDAzMjcyMjAxNDZaFw0y\nMTAzMjcyMjAxNDZaMIGPMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5p\nYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwEVGVzdDENMAsGA1UE\nCwwEVGVzdDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRl\nc3RAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM7kd2cj\nF49wm1+OQ7Q5GE96cXueWNPr/Nwei71tf6G4BmE0B+suXHEvnLpHTj9pdX/ZzBIK\n8jIZ/x8RnSduK/Ky+zm1QMYUWZtWCAgCW8WzgB69Cn/hQG8KSX3S9bqODuQAvP54\nGQJD7+4kVuNBGjFb4DaD4nvMmPtALSZf8ZCZAgMBAAEwDQYJKoZIhvcNAQEFBQAD\ngYEAOn6X8+0VVlDjF+TvTgI0KIasA6nDm+KXe7LVtfvqWqQZH4qyd2uiwcDM3Aux\na/OsPdOw0j+NqFDBd3mSMhSVgfvXdK6j9WaxY1VGXyaidLARgvn63wfzgr857sQW\nc8eSxbwEQxwlMvVxW6Os4VhCfUQr8VrBrvPa2zs+6IlK+Ug=\n-----END CERTIFICATE-----"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/test-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/test/resources/org/springframework/boot/web/server/test-key.pem",
    "content": "Bag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nKey Attributes: <No Attributes>\n-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD8B1saBN8Y0ZjX\nQ/pvnv2hZa+cBBkFHVkgw+tdzgdcO5Kjv2rnRKd3Oh8Qwdxj3BC9GpicF4GOgkDG\nLrMrYbmV/xGUnNh3YpUwbv+U/pm3VnuSZCk4aYgNEWHrnEHyrge87+MqYqGuMIke\nA5z7GV44PeThfKQs2BLLL/ME+Pb/jN6IVlIHxdBT5TBQkqNGFU7swdZoQ5Viqv44\nUNdVqU5pP3UF/perbOm2CHCbeLiLRvmuvGuBbrbko2XUwBNH+UjmEQaRh/epoy8B\nD31vGY87ym/YOEdpIrqD8bwg7NWP/Fdsryqi8p+U8fcfw4xZjotA0Sv04BC7zXHg\nm1AyZoVzAgMBAAECggEAfEqiZqANaF+BqXQIb4Dw42ZTJzWsIyYYnPySOGZRoe5t\nQJ03uwtULYv34xtANe1DQgd6SMyc46ugBzzjtprQ3ET5Jhn99U6kdcjf+dpf85dO\nhOEppP0CkDNI39nleinSfh6uIOqYgt/D143/nqQhn8oCdSOzkbwT9KnWh1bC9T7I\nvFjGfElvt1/xl88qYgrWgYLgXaencNGgiv/4/M0FNhiHEGsVC7SCu6kapC/WIQpE\n5IdV+HR+tiLoGZhXlhqorY7QC4xKC4wwafVSiFxqDOQAuK+SMD4TCEv0Aop+c+SE\nYBigVTmgVeJkjK7IkTEhKkAEFmRF5/5w+bZD9FhTNQKBgQD+4fNG1ChSU8RdizZT\n5dPlDyAxpETSCEXFFVGtPPh2j93HDWn7XugNyjn5FylTH507QlabC+5wZqltdIjK\nGRB5MIinQ9/nR2fuwGc9s+0BiSEwNOUB1MWm7wWL/JUIiKq6sTi6sJIfsYg79zco\nqxl5WE94aoINx9Utq1cdWhwJTQKBgQD9IjPksd4Jprz8zMrGLzR8k1gqHyhv24qY\nEJ7jiHKKAP6xllTUYwh1IBSL6w2j5lfZPpIkb4Jlk2KUoX6fN81pWkBC/fTBUSIB\nEHM9bL51+yKEYUbGIy/gANuRbHXsWg3sjUsFTNPN4hGTFk3w2xChCyl/f5us8Lo8\nZ633SNdpvwKBgQCGyDU9XzNzVZihXtx7wS0sE7OSjKtX5cf/UCbA1V0OVUWR3SYO\nJ0HPCQFfF0BjFHSwwYPKuaR9C8zMdLNhK5/qdh/NU7czNi9fsZ7moh7SkRFbzJzN\nOxbKD9t/CzJEMQEXeF/nWTfsSpUgILqqZtAxuuFLbAcaAnJYlCKdAumQgQKBgQCK\nmqjJh68pn7gJwGUjoYNe1xtGbSsqHI9F9ovZ0MPO1v6e5M7sQJHH+Fnnxzv/y8e8\nd6tz8e73iX1IHymDKv35uuZHCGF1XOR+qrA/KQUc+vcKf21OXsP/JtkTRs1HLoRD\nS5aRf2DWcfvniyYARSNU2xTM8GWgi2ueWbMDHUp+ZwKBgA/swC+K+Jg5DEWm6Sau\ne6y+eC6S+SoXEKkI3wf7m9aKoZo0y+jh8Gas6gratlc181pSM8O3vZG0n19b493I\napCFomMLE56zEzvyzfpsNhFhk5MBMCn0LPyzX6MiynRlGyWIj0c99fbHI3pOMufP\nWgmVLTZ8uDcSW1MbdUCwFSk5\n-----END PRIVATE KEY-----\nBag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nsubject=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\nissuer=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\n-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/autoconfigure/reactive/AbstractReactiveWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.reactive;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.reactive.ConfigurableReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.ReactiveWebServerFactory;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.web.server.adapter.ForwardedHeaderTransformer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Base class for testing sub-classes of {@link ReactiveWebServerConfiguration}.\n *\n * @author Brian Clozel\n * @author Raheela Aslam\n * @author Madhura Bhave\n * @author Scott Frederick\n */\n// @DirtiesUrlFactories\npublic abstract class AbstractReactiveWebServerAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner mockServerRunner;\n\n\tprotected final ReactiveWebApplicationContextRunner serverRunner;\n\n\tprotected AbstractReactiveWebServerAutoConfigurationTests(Class<?> serverAutoConfiguration) {\n\t\tReactiveWebApplicationContextRunner common = new ReactiveWebApplicationContextRunner(\n\t\t\t\tAnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(serverAutoConfiguration));\n\t\tthis.serverRunner = common.withPropertyValues(\"server.port=0\")\n\t\t\t.withUserConfiguration(HttpHandlerConfiguration.class);\n\t\tthis.mockServerRunner = common.withUserConfiguration(MockWebServerConfiguration.class);\n\t}\n\n\t@Test\n\tvoid createFromConfigClass() {\n\t\tthis.mockServerRunner.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBeansOfType(ReactiveWebServerFactory.class)).hasSize(1);\n\t\t\t\tassertThat(context.getBeansOfType(WebServerFactoryCustomizer.class)).hasSizeGreaterThanOrEqualTo(1);\n\t\t\t\tassertThat(context.getBeansOfType(ReactiveWebServerFactoryCustomizer.class)).hasSize(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid missingHttpHandler() {\n\t\tthis.mockServerRunner.withUserConfiguration(MockWebServerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getStartupFailure()).isInstanceOf(ApplicationContextException.class)\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"missing HttpHandler bean\"));\n\t}\n\n\t@Test\n\tvoid multipleHttpHandler() {\n\t\tthis.mockServerRunner\n\t\t\t.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class,\n\t\t\t\t\tTooManyHttpHandlers.class)\n\t\t\t.run((context) -> assertThat(context.getStartupFailure()).isInstanceOf(ApplicationContextException.class)\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"multiple HttpHandler beans : httpHandler,additionalHttpHandler\"));\n\t}\n\n\t@Test\n\tvoid customizeReactiveWebServer() {\n\t\tthis.mockServerRunner\n\t\t\t.withUserConfiguration(MockWebServerConfiguration.class, HttpHandlerConfiguration.class,\n\t\t\t\t\tReactiveWebServerCustomization.class)\n\t\t\t.run((context) -> assertThat(context.getBean(MockReactiveWebServerFactory.class).getPort())\n\t\t\t\t.isEqualTo(9000));\n\t}\n\n\t@Test\n\tvoid webServerFailsWithInvalidSslBundle() {\n\t\tthis.serverRunner.withUserConfiguration(HttpHandlerConfiguration.class)\n\t\t\t.withBean(WebServerFactoryCustomizer.class,\n\t\t\t\t\t() -> (WebServerFactoryCustomizer<ConfigurableWebServerFactory>) (factory) -> factory\n\t\t\t\t\t\t.setSslBundles(new DefaultSslBundleRegistry()))\n\t\t\t.withPropertyValues(\"server.ssl.bundle=test-bundle\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context.getStartupFailure().getCause()).isInstanceOf(NoSuchSslBundleException.class)\n\t\t\t\t\t.withFailMessage(\"test\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid forwardedHeaderTransformerShouldBeConfigured() {\n\t\tthis.mockServerRunner.withUserConfiguration(HttpHandlerConfiguration.class)\n\t\t\t.withPropertyValues(\"server.forward-headers-strategy=framework\", \"server.port=0\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ForwardedHeaderTransformer.class));\n\t}\n\n\t@Test\n\tvoid forwardedHeaderTransformerWhenStrategyNotFilterShouldNotBeConfigured() {\n\t\tthis.mockServerRunner.withUserConfiguration(HttpHandlerConfiguration.class)\n\t\t\t.withPropertyValues(\"server.forward-headers-strategy=native\", \"server.port=0\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ForwardedHeaderTransformer.class));\n\t}\n\n\t@Test\n\tvoid forwardedHeaderTransformerWhenAlreadyRegisteredShouldBackOff() {\n\t\tthis.mockServerRunner\n\t\t\t.withUserConfiguration(ForwardedHeaderTransformerConfiguration.class, HttpHandlerConfiguration.class)\n\t\t\t.withPropertyValues(\"server.forward-headers-strategy=framework\", \"server.port=0\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ForwardedHeaderTransformer.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpHandlerConfiguration {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn mock(HttpHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TooManyHttpHandlers {\n\n\t\t@Bean\n\t\tHttpHandler additionalHttpHandler() {\n\t\t\treturn mock(HttpHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ReactiveWebServerCustomization {\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory> reactiveWebServerCustomizer() {\n\t\t\treturn (factory) -> factory.setPort(9000);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MockWebServerConfiguration {\n\n\t\t@Bean\n\t\tMockReactiveWebServerFactory mockReactiveWebServerFactory() {\n\t\t\treturn new MockReactiveWebServerFactory();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ForwardedHeaderTransformerConfiguration {\n\n\t\t@Bean\n\t\tForwardedHeaderTransformer testForwardedHeaderTransformer() {\n\t\t\treturn new ForwardedHeaderTransformer();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/autoconfigure/servlet/AbstractServletWebServerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.autoconfigure.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.websocket.server.ServerContainer;\nimport jakarta.websocket.server.ServerEndpoint;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.CookieSameSiteSupplier;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.client.HttpClientErrorException;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.filter.ForwardedHeaderFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Base class for testing sub-classes of {@link ServletWebServerConfiguration}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Raheela Aslam\n * @author Madhura Bhave\n */\npublic abstract class AbstractServletWebServerAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner mockServerRunner;\n\n\tprotected final WebApplicationContextRunner serverRunner;\n\n\tprotected AbstractServletWebServerAutoConfigurationTests(Class<?> serverAutoConfiguration) {\n\t\tWebApplicationContextRunner common = new WebApplicationContextRunner(\n\t\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(serverAutoConfiguration));\n\t\tthis.serverRunner = common.withPropertyValues(\"server.port=0\");\n\t\tthis.mockServerRunner = common.withUserConfiguration(MockWebServerConfiguration.class);\n\t}\n\n\t@Test\n\tvoid createFromConfigClass() {\n\t\tthis.mockServerRunner\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ServletWebServerFactoryCustomizer.class));\n\t}\n\n\t@Test\n\tvoid webServerHasNoServletContext() {\n\t\tthis.mockServerRunner.withUserConfiguration(EnsureWebServerHasNoServletContext.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid webServerFactoryCustomizerBeansAreCalledToCustomizeWebServerFactory() {\n\t\tthis.mockServerRunner\n\t\t\t.withBean(WebServerFactoryCustomizer.class,\n\t\t\t\t\t() -> (WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>) (factory) -> factory\n\t\t\t\t\t\t.setPort(9000))\n\t\t\t.run((context) -> assertThat(context.getBean(MockServletWebServerFactory.class).getPort()).isEqualTo(9000));\n\t}\n\n\t@Test\n\tvoid initParametersAreConfiguredOnTheServletContext() {\n\t\tthis.mockServerRunner\n\t\t\t.withPropertyValues(\"server.servlet.context-parameters.a:alpha\",\n\t\t\t\t\t\"server.servlet.context-parameters.b:bravo\")\n\t\t\t.run((context) -> {\n\t\t\t\tServletContext servletContext = context.getServletContext();\n\t\t\t\tassertThat(servletContext.getInitParameter(\"a\")).isEqualTo(\"alpha\");\n\t\t\t\tassertThat(servletContext.getInitParameter(\"b\")).isEqualTo(\"bravo\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid forwardedHeaderFilterShouldBeConfigured() {\n\t\tthis.mockServerRunner.withPropertyValues(\"server.forward-headers-strategy=framework\").run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\t\tFilter filter = context.getBean(FilterRegistrationBean.class).getFilter();\n\t\t\tassertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);\n\t\t\tassertThat(filter).extracting(\"relativeRedirects\").isEqualTo(false);\n\t\t});\n\t}\n\n\t@Test\n\tvoid forwardedHeaderFilterWhenStrategyNotFilterShouldNotBeConfigured() {\n\t\tthis.mockServerRunner.withPropertyValues(\"server.forward-headers-strategy=native\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid forwardedHeaderFilterWhenFilterAlreadyRegisteredShouldBackOff() {\n\t\tthis.mockServerRunner.withUserConfiguration(ForwardedHeaderFilterConfiguration.class)\n\t\t\t.withPropertyValues(\"server.forward-headers-strategy=framework\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(FilterRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid cookieSameSiteSuppliersAreApplied() {\n\t\tthis.mockServerRunner.withUserConfiguration(CookieSameSiteSupplierConfiguration.class).run((context) -> {\n\t\t\tConfigurableServletWebServerFactory webServerFactory = context\n\t\t\t\t.getBean(ConfigurableServletWebServerFactory.class);\n\t\t\tassertThat(webServerFactory.getSettings().getCookieSameSiteSuppliers()).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid webSocketServerContainerIsAvailableFromServletContext() {\n\t\tthis.serverRunner.run((context) -> {\n\t\t\tObject serverContainer = context.getServletContext()\n\t\t\t\t.getAttribute(\"jakarta.websocket.server.ServerContainer\");\n\t\t\tassertThat(serverContainer).isInstanceOf(ServerContainer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid webSocketUpgradeDoesNotPreventAFilterFromRejectingTheRequest() {\n\t\tthis.serverRunner\n\t\t\t.withBean(\"testEndpointRegistrar\", ServletContextInitializer.class, () -> TestEndpoint::register)\n\t\t\t.withUserConfiguration(UnauthorizedFilterConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestEndpoint.register(context.getServletContext());\n\t\t\t\tWebServer webServer = ((WebServerApplicationContext) context.getSourceApplicationContext())\n\t\t\t\t\t.getWebServer();\n\t\t\t\tint port = webServer.getPort();\n\t\t\t\tRestTemplate rest = new RestTemplate();\n\t\t\t\tRequestEntity<Void> request = RequestEntity.get(\"http://localhost:\" + port)\n\t\t\t\t\t.header(\"Upgrade\", \"websocket\")\n\t\t\t\t\t.header(\"Connection\", \"upgrade\")\n\t\t\t\t\t.header(\"Sec-WebSocket-Version\", \"13\")\n\t\t\t\t\t.header(\"Sec-WebSocket-Key\", \"key\")\n\t\t\t\t\t.build();\n\t\t\t\tassertThatExceptionOfType(HttpClientErrorException.Unauthorized.class)\n\t\t\t\t\t.isThrownBy(() -> rest.exchange(request, Void.class));\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnExpression(\"true\")\n\tstatic class MockWebServerConfiguration {\n\n\t\t@Bean\n\t\tServletWebServerFactory webServerFactory() {\n\t\t\treturn new MockServletWebServerFactory();\n\t\t}\n\n\t}\n\n\t@Component\n\tstatic class EnsureWebServerHasNoServletContext implements BeanPostProcessor {\n\n\t\t@Override\n\t\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) {\n\t\t\tif (bean instanceof ConfigurableServletWebServerFactory) {\n\t\t\t\tMockServletWebServerFactory webServerFactory = (MockServletWebServerFactory) bean;\n\t\t\t\tassertThat(webServerFactory.getServletContext()).isNull();\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) {\n\t\t\treturn bean;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ForwardedHeaderFilterConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<ForwardedHeaderFilter> testForwardedHeaderFilter() {\n\t\t\tForwardedHeaderFilter filter = new ForwardedHeaderFilter();\n\t\t\treturn new FilterRegistrationBean<>(filter);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CookieSameSiteSupplierConfiguration {\n\n\t\t@Bean\n\t\tCookieSameSiteSupplier cookieSameSiteSupplier1() {\n\t\t\treturn CookieSameSiteSupplier.ofLax().whenHasName(\"test1\");\n\t\t}\n\n\t\t@Bean\n\t\tCookieSameSiteSupplier cookieSameSiteSupplier2() {\n\t\t\treturn CookieSameSiteSupplier.ofNone().whenHasName(\"test2\");\n\t\t}\n\n\t}\n\n\t@ServerEndpoint(\"/\")\n\tpublic static class TestEndpoint {\n\n\t\tstatic void register(ServletContext context) {\n\t\t\ttry {\n\t\t\t\tServerContainer serverContainer = (ServerContainer) context\n\t\t\t\t\t.getAttribute(\"jakarta.websocket.server.ServerContainer\");\n\t\t\t\tif (serverContainer != null) {\n\t\t\t\t\tserverContainer.addEndpoint(TestEndpoint.class);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Continue\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class UnauthorizedFilterConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<Filter> unauthorizedFilter() {\n\t\t\tFilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>(new Filter() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\t\t\tthrows IOException, ServletException {\n\t\t\t\t\t((HttpServletResponse) response).sendError(HttpStatus.UNAUTHORIZED.value());\n\t\t\t\t}\n\n\t\t\t});\n\t\t\tregistration.setOrder(Ordered.HIGHEST_PRECEDENCE);\n\t\t\tregistration.addUrlPatterns(\"/*\");\n\t\t\tregistration.setDispatcherTypes(DispatcherType.REQUEST);\n\t\t\treturn registration;\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<HttpServlet> basicServlet() {\n\t\t\tServletRegistrationBean<HttpServlet> registration = new ServletRegistrationBean<>(new HttpServlet() {\n\t\t\t});\n\t\t\tregistration.addUrlMappings(\"/\");\n\t\t\treturn registration;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/AbstractReactiveWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive;\n\nimport java.io.InputStream;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.nio.charset.StandardCharsets;\nimport java.security.KeyStore;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport javax.net.ssl.KeyManagerFactory;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpResponse;\nimport io.netty.handler.ssl.SslProvider;\nimport io.netty.handler.ssl.util.InsecureTrustManagerFactory;\nimport org.assertj.core.api.ThrowableAssert.ThrowingCallable;\nimport org.awaitility.Awaitility;\nimport org.eclipse.jetty.client.ContentResponse;\nimport org.eclipse.jetty.client.StringRequestContent;\nimport org.eclipse.jetty.http2.client.HTTP2Client;\nimport org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.core.publisher.Sinks;\nimport reactor.netty.NettyPipeline;\nimport reactor.netty.http.Http11SslContextSpec;\nimport reactor.netty.http.client.HttpClient;\nimport reactor.netty.tcp.SslProvider.GenericSslContextSpec;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.boot.web.server.Http2;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.core.io.buffer.DataBufferFactory;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.client.reactive.ReactorClientHttpConnector;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.WebClientRequestException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Base for testing classes that extends {@link AbstractReactiveWebServerFactory}.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n */\npublic abstract class AbstractReactiveWebServerFactoryTests {\n\n\tprotected WebServer webServer;\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.webServer != null) {\n\t\t\ttry {\n\t\t\t\tthis.webServer.stop();\n\t\t\t\ttry {\n\t\t\t\t\tthis.webServer.destroy();\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected abstract ConfigurableReactiveWebServerFactory getFactory();\n\n\t@Test\n\tvoid specificPort() throws Exception {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tint specificPort = doWithRetry(() -> {\n\t\t\tfactory.setPort(0);\n\t\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\t\tthis.webServer.start();\n\t\t\treturn this.webServer.getPort();\n\t\t});\n\t\tMono<String> result = getWebClient(this.webServer.getPort()).build()\n\t\t\t.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t\tassertThat(result.block(Duration.ofSeconds(30))).isEqualTo(\"Hello World\");\n\t\tassertThat(this.webServer.getPort()).isEqualTo(specificPort);\n\t}\n\n\t@Test\n\tprotected void restartAfterStop() throws Exception {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tassertThat(getResponse(port, \"/test\")).isEqualTo(\"Hello World\");\n\t\tthis.webServer.stop();\n\t\tassertThatException().isThrownBy(() -> getResponse(port, \"/test\"));\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(this.webServer.getPort(), \"/test\")).isEqualTo(\"Hello World\");\n\t}\n\n\tprivate String getResponse(int port, String uri) {\n\t\tWebClient webClient = getWebClient(port).build();\n\t\tMono<String> result = webClient.post()\n\t\t\t.uri(uri)\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t\treturn result.block(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\tvoid portIsMinusOneWhenConnectionIsClosed() {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tassertThat(this.webServer.getPort()).isGreaterThan(0);\n\t\tthis.webServer.destroy();\n\t\tassertThat(this.webServer.getPort()).isEqualTo(-1);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid basicSslFromClassPath() {\n\t\ttestBasicSslWithKeyStore(\"classpath:test.jks\", \"password\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid basicSslFromFileSystem(@ResourcePath(\"test.jks\") String keyStore) {\n\t\ttestBasicSslWithKeyStore(keyStore, \"password\");\n\n\t}\n\n\tprotected final void testBasicSslWithKeyStore(String keyStore, String keyPassword) {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyPassword(keyPassword);\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tfactory.setSsl(ssl);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tReactorClientHttpConnector connector = buildTrustAllSslConnector();\n\t\tWebClient client = WebClient.builder()\n\t\t\t.baseUrl(\"https://localhost:\" + this.webServer.getPort())\n\t\t\t.clientConnector(connector)\n\t\t\t.build();\n\t\tMono<String> result = client.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t\tassertThat(result.block(Duration.ofSeconds(30))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWithValidAlias() {\n\t\tString keyStore = \"classpath:test.jks\";\n\t\tString keyPassword = \"password\";\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyPassword(keyPassword);\n\t\tssl.setKeyAlias(\"test-alias\");\n\t\tfactory.setSsl(ssl);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tReactorClientHttpConnector connector = buildTrustAllSslConnector();\n\t\tWebClient client = WebClient.builder()\n\t\t\t.baseUrl(\"https://localhost:\" + this.webServer.getPort())\n\t\t\t.clientConnector(connector)\n\t\t\t.build();\n\n\t\tMono<String> result = client.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\n\t\tStepVerifier.create(result).expectNext(\"Hello World\").expectComplete().verify(Duration.ofSeconds(30));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWithInvalidAliasFailsDuringStartup() {\n\t\tString keyStore = \"classpath:test.jks\";\n\t\tString keyPassword = \"password\";\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tSsl ssl = new Ssl();\n\t\tssl.setKeyStore(keyStore);\n\t\tssl.setKeyPassword(keyPassword);\n\t\tssl.setKeyAlias(\"test-alias-404\");\n\t\tfactory.setSsl(ssl);\n\t\tassertThatSslWithInvalidAliasCallFails(() -> factory.getWebServer(new EchoHandler()).start());\n\t}\n\n\tprotected void assertThatSslWithInvalidAliasCallFails(ThrowingCallable call) {\n\t\tassertThatException().isThrownBy(call)\n\t\t\t.withStackTraceContaining(\"Keystore does not contain alias 'test-alias-404'\");\n\t}\n\n\tprotected ReactorClientHttpConnector buildTrustAllSslConnector() {\n\t\tGenericSslContextSpec<?> sslContextSpec = Http11SslContextSpec.forClient()\n\t\t\t.configure((builder) -> builder.sslProvider(SslProvider.JDK)\n\t\t\t\t.trustManager(InsecureTrustManagerFactory.INSTANCE));\n\t\tHttpClient client = HttpClient.create().wiretap(true).secure((spec) -> spec.sslContext(sslContextSpec));\n\t\treturn new ReactorClientHttpConnector(client);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWantsClientAuthenticationSucceedsWithClientCertificate() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(Ssl.ClientAuth.WANT);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setTrustStore(\"classpath:test.jks\");\n\t\ttestClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector(\"test.jks\", \"password\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWantsClientAuthenticationSucceedsWithoutClientCertificate() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(Ssl.ClientAuth.WANT);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setTrustStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\ttestClientAuthSuccess(ssl, buildTrustAllSslConnector());\n\t}\n\n\tprotected ReactorClientHttpConnector buildTrustAllSslWithClientKeyConnector(String keyStore,\n\t\t\tString keyStorePassword) throws Exception {\n\t\tKeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\ttry (InputStream stream = new ClassPathResource(keyStore).getInputStream()) {\n\t\t\tclientKeyStore.load(stream, \"secret\".toCharArray());\n\t\t}\n\t\tKeyManagerFactory clientKeyManagerFactory = KeyManagerFactory\n\t\t\t.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n\t\tclientKeyManagerFactory.init(clientKeyStore, keyStorePassword.toCharArray());\n\n\t\tGenericSslContextSpec<?> sslContextSpec = Http11SslContextSpec.forClient()\n\t\t\t.configure((builder) -> builder.sslProvider(SslProvider.JDK)\n\t\t\t\t.trustManager(InsecureTrustManagerFactory.INSTANCE)\n\t\t\t\t.keyManager(clientKeyManagerFactory));\n\t\tHttpClient client = HttpClient.create().wiretap(true).secure((spec) -> spec.sslContext(sslContextSpec));\n\t\treturn new ReactorClientHttpConnector(client);\n\t}\n\n\tprotected void testClientAuthSuccess(Ssl sslConfiguration, ReactorClientHttpConnector clientConnector) {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(sslConfiguration);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tWebClient client = WebClient.builder()\n\t\t\t.baseUrl(\"https://localhost:\" + this.webServer.getPort())\n\t\t\t.clientConnector(clientConnector)\n\t\t\t.build();\n\t\tMono<String> result = client.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t\tassertThat(result.block(Duration.ofSeconds(30))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslNeedsClientAuthenticationSucceedsWithClientCertificate() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(Ssl.ClientAuth.NEED);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setTrustStore(\"classpath:test.jks\");\n\t\ttestClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector(\"test.jks\", \"password\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslNeedsClientAuthenticationFailsWithoutClientCertificate() {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(Ssl.ClientAuth.NEED);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyStorePassword(\"secret\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tssl.setTrustStore(\"classpath:test.jks\");\n\t\ttestClientAuthFailure(ssl, buildTrustAllSslConnector());\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test-cert.pem\", \"test-key.pem\", \"test.p12\" })\n\tvoid sslWithPemCertificates() throws Exception {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(Ssl.ClientAuth.NEED);\n\t\tssl.setCertificate(\"classpath:test-cert.pem\");\n\t\tssl.setCertificatePrivateKey(\"classpath:test-key.pem\");\n\t\tssl.setTrustCertificate(\"classpath:test-cert.pem\");\n\t\ttestClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector(\"test.p12\", \"secret\"));\n\t}\n\n\tprotected void testClientAuthFailure(Ssl sslConfiguration, ReactorClientHttpConnector clientConnector) {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(sslConfiguration);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tWebClient client = WebClient.builder()\n\t\t\t.baseUrl(\"https://localhost:\" + this.webServer.getPort())\n\t\t\t.clientConnector(clientConnector)\n\t\t\t.build();\n\t\tMono<String> result = client.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t\tStepVerifier.create(result).expectError(WebClientRequestException.class).verify(Duration.ofSeconds(10));\n\t}\n\n\tprotected WebClient.Builder getWebClient(int port) {\n\t\treturn getWebClient(HttpClient.create().wiretap(true), port);\n\t}\n\n\tprotected WebClient.Builder getWebClient(HttpClient client, int port) {\n\t\tInetSocketAddress address = new InetSocketAddress(port);\n\t\tString baseUrl = \"http://\" + address.getHostString() + \":\" + address.getPort();\n\t\treturn WebClient.builder().clientConnector(new ReactorClientHttpConnector(client)).baseUrl(baseUrl);\n\t}\n\n\t@Test\n\tprotected void compressionOfResponseToGetRequest() {\n\t\tWebClient client = prepareCompressionTest();\n\t\tResponseEntity<Void> response = client.get().retrieve().toBodilessEntity().block(Duration.ofSeconds(30));\n\t\tassertResponseIsCompressed(response);\n\t}\n\n\t@Test\n\tprotected void compressionOfResponseToPostRequest() {\n\t\tWebClient client = prepareCompressionTest();\n\t\tResponseEntity<Void> response = client.post().retrieve().toBodilessEntity().block(Duration.ofSeconds(30));\n\t\tassertResponseIsCompressed(response);\n\t}\n\n\t@Test\n\tvoid noCompressionForSmallResponse() {\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tcompression.setMinResponseSize(DataSize.ofBytes(3001));\n\t\tWebClient client = prepareCompressionTest(compression);\n\t\tResponseEntity<Void> response = client.get().retrieve().toBodilessEntity().block(Duration.ofSeconds(30));\n\t\tassertResponseIsNotCompressed(response);\n\t}\n\n\t@Test\n\tvoid noCompressionForMimeType() {\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tcompression.setMimeTypes(new String[] { \"application/json\" });\n\t\tWebClient client = prepareCompressionTest(compression);\n\t\tResponseEntity<Void> response = client.get().retrieve().toBodilessEntity().block(Duration.ofSeconds(30));\n\t\tassertResponseIsNotCompressed(response);\n\t}\n\n\t@Test\n\tprotected void noCompressionForUserAgent() {\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tcompression.setExcludedUserAgents(new String[] { \"testUserAgent\" });\n\t\tWebClient client = prepareCompressionTest(compression);\n\t\tResponseEntity<Void> response = client.get()\n\t\t\t.header(\"User-Agent\", \"testUserAgent\")\n\t\t\t.retrieve()\n\t\t\t.toBodilessEntity()\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertResponseIsNotCompressed(response);\n\t}\n\n\t@Test\n\tvoid noCompressionForResponseWithInvalidContentType() {\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tcompression.setMimeTypes(new String[] { \"application/json\" });\n\t\tWebClient client = prepareCompressionTest(compression, \"test~plain\");\n\t\tResponseEntity<Void> response = client.get().retrieve().toBodilessEntity().block(Duration.ofSeconds(30));\n\t\tassertResponseIsNotCompressed(response);\n\t}\n\n\t@Test\n\tvoid whenSslIsEnabledAndNoKeyStoreIsConfiguredThenServerFailsToStart() {\n\t\tassertThatIllegalStateException().isThrownBy(() -> testBasicSslWithKeyStore(null, null))\n\t\t\t.withMessageContaining(\"SSL is enabled but no trust material is configured\");\n\t}\n\n\t@Test\n\tvoid whenThereAreNoInFlightRequestsShutDownGracefullyReturnsTrueBeforePeriodElapses() throws Exception {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> GracefulShutdownResult.IDLE == result.get());\n\t}\n\n\t@Test\n\tvoid whenARequestRemainsInFlightThenShutDownGracefullyDoesNotInvokeCallbackUntilTheRequestCompletes()\n\t\t\tthrows Exception {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tMono<ResponseEntity<Void>> request = getWebClient(this.webServer.getPort()).build()\n\t\t\t.get()\n\t\t\t.retrieve()\n\t\t\t.toBodilessEntity();\n\t\tAtomicReference<ResponseEntity<Void>> responseReference = new AtomicReference<>();\n\t\tCountDownLatch responseLatch = new CountDownLatch(1);\n\t\trequest.subscribe((response) -> {\n\t\t\tresponseReference.set(response);\n\t\t\tresponseLatch.countDown();\n\t\t});\n\t\tblockingHandler.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tassertThat(responseReference.get()).isNull();\n\t\tblockingHandler.completeOne();\n\t\tassertThat(responseLatch.await(5, TimeUnit.SECONDS)).isTrue();\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> GracefulShutdownResult.IDLE == result.get());\n\t}\n\n\t@Test\n\tvoid givenAnInflightRequestWhenTheServerIsStoppedThenGracefulShutdownCallbackIsCalledWithRequestsActive()\n\t\t\tthrows Exception {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tMono<ResponseEntity<Void>> request = getWebClient(this.webServer.getPort()).build()\n\t\t\t.get()\n\t\t\t.retrieve()\n\t\t\t.toBodilessEntity();\n\t\tAtomicReference<ResponseEntity<Void>> responseReference = new AtomicReference<>();\n\t\tCountDownLatch responseLatch = new CountDownLatch(1);\n\t\trequest.subscribe((response) -> {\n\t\t\tresponseReference.set(response);\n\t\t\tresponseLatch.countDown();\n\t\t});\n\t\tblockingHandler.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tassertThat(responseReference.get()).isNull();\n\t\ttry {\n\t\t\tthis.webServer.stop();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Continue\n\t\t}\n\t\tSystem.out.println(\"Stopped\");\n\t\tAwaitility.await()\n\t\t\t.atMost(Duration.ofSeconds(5))\n\t\t\t.until(() -> GracefulShutdownResult.REQUESTS_ACTIVE == result.get());\n\t\tblockingHandler.completeOne();\n\t}\n\n\t@Test\n\tvoid whenARequestIsActiveAfterGracefulShutdownEndsThenStopWillComplete() throws InterruptedException {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tMono<ResponseEntity<Void>> request = getWebClient(this.webServer.getPort()).build()\n\t\t\t.get()\n\t\t\t.retrieve()\n\t\t\t.toBodilessEntity();\n\t\tAtomicReference<ResponseEntity<Void>> responseReference = new AtomicReference<>();\n\t\tCountDownLatch responseLatch = new CountDownLatch(1);\n\t\trequest.subscribe((response) -> {\n\t\t\tresponseReference.set(response);\n\t\t\tresponseLatch.countDown();\n\t\t});\n\t\tblockingHandler.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tthis.webServer.stop();\n\t\tAwaitility.await()\n\t\t\t.atMost(Duration.ofSeconds(30))\n\t\t\t.until(() -> GracefulShutdownResult.REQUESTS_ACTIVE == result.get());\n\t\tblockingHandler.completeOne();\n\t}\n\n\t@Test\n\tvoid whenARequestIsActiveThenStopWillComplete() throws InterruptedException {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tBlockingHandler blockingHandler = new BlockingHandler();\n\t\tthis.webServer = factory.getWebServer(blockingHandler);\n\t\tthis.webServer.start();\n\t\tMono<ResponseEntity<Void>> request = getWebClient(this.webServer.getPort()).build()\n\t\t\t.get()\n\t\t\t.retrieve()\n\t\t\t.toBodilessEntity();\n\t\tAtomicReference<ResponseEntity<Void>> responseReference = new AtomicReference<>();\n\t\tCountDownLatch responseLatch = new CountDownLatch(1);\n\t\trequest.subscribe((response) -> {\n\t\t\tresponseReference.set(response);\n\t\t\tresponseLatch.countDown();\n\t\t});\n\t\tblockingHandler.awaitQueue();\n\t\ttry {\n\t\t\tthis.webServer.stop();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Continue\n\t\t}\n\t\tblockingHandler.completeOne();\n\t}\n\n\t@Test\n\tprotected void whenHttp2IsEnabledAndSslIsDisabledThenH2cCanBeUsed() throws Exception {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tHttp2 http2 = new Http2();\n\t\thttp2.setEnabled(true);\n\t\tfactory.setHttp2(http2);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\n\t\ttry (org.eclipse.jetty.client.HttpClient client = new org.eclipse.jetty.client.HttpClient(\n\t\t\t\tnew HttpClientTransportOverHTTP2(new HTTP2Client()))) {\n\t\t\tclient.start();\n\t\t\tContentResponse response = client.POST(\"http://localhost:\" + this.webServer.getPort())\n\t\t\t\t.body(new StringRequestContent(\"text/plain\", \"Hello World\"))\n\t\t\t\t.send();\n\t\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());\n\t\t\tassertThat(response.getContentAsString()).isEqualTo(\"Hello World\");\n\t\t}\n\t}\n\n\t@Test\n\tprotected void whenHttp2IsEnabledAndSslIsDisabledThenHttp11CanStillBeUsed() {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tHttp2 http2 = new Http2();\n\t\thttp2.setEnabled(true);\n\t\tfactory.setHttp2(http2);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tMono<String> result = getWebClient(this.webServer.getPort()).build()\n\t\t\t.post()\n\t\t\t.uri(\"/test\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.body(BodyInserters.fromValue(\"Hello World\"))\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class);\n\t\tassertThat(result.block(Duration.ofSeconds(30))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid startedLogMessageWithSinglePort() {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tassertThat(startedLogMessage())\n\t\t\t.matches(\"(Jetty|Netty|Tomcat) started on port \" + this.webServer.getPort() + \" \\\\(http(/1.1)?\\\\)\");\n\t}\n\n\t@Test\n\tprotected void startedLogMessageWithMultiplePorts() {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\taddConnector(0, factory);\n\t\tthis.webServer = factory.getWebServer(new EchoHandler());\n\t\tthis.webServer.start();\n\t\tassertThat(startedLogMessage()).matches(\"(Jetty|Tomcat) started on ports \" + this.webServer.getPort()\n\t\t\t\t+ \" \\\\(http(/1.1)?\\\\), [0-9]+ \\\\(http(/1.1)?\\\\)\");\n\t}\n\n\tprotected WebClient prepareCompressionTest() {\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\treturn prepareCompressionTest(compression);\n\t}\n\n\tprotected WebClient prepareCompressionTest(Compression compression) {\n\t\treturn prepareCompressionTest(compression, MediaType.TEXT_PLAIN_VALUE);\n\t}\n\n\tprotected WebClient prepareCompressionTest(Compression compression, String responseContentType) {\n\t\tConfigurableReactiveWebServerFactory factory = getFactory();\n\t\tfactory.setCompression(compression);\n\t\tthis.webServer = factory.getWebServer(new CharsHandler(3000, responseContentType));\n\t\tthis.webServer.start();\n\n\t\tHttpClient client = HttpClient.create()\n\t\t\t.wiretap(true)\n\t\t\t.compress(true)\n\t\t\t.doOnConnected((connection) -> connection.channel()\n\t\t\t\t.pipeline()\n\t\t\t\t.addBefore(NettyPipeline.HttpDecompressor, \"CompressionTest\", new CompressionDetectionHandler()));\n\t\treturn getWebClient(client, this.webServer.getPort()).build();\n\t}\n\n\tprotected void assertResponseIsCompressed(ResponseEntity<Void> response) {\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(response.getHeaders().getFirst(\"X-Test-Compressed\")).isEqualTo(\"true\");\n\t}\n\n\tprotected void assertResponseIsNotCompressed(ResponseEntity<Void> response) {\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(response.getHeaders().headerNames()).doesNotContain(\"X-Test-Compressed\");\n\t}\n\n\tprotected void assertForwardHeaderIsUsed(ConfigurableReactiveWebServerFactory factory) {\n\t\tthis.webServer = factory.getWebServer(new XForwardedHandler());\n\t\tthis.webServer.start();\n\t\tString body = getWebClient(this.webServer.getPort()).build()\n\t\t\t.get()\n\t\t\t.header(\"X-Forwarded-Proto\", \"https\")\n\t\t\t.retrieve()\n\t\t\t.bodyToMono(String.class)\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(body).isEqualTo(\"https\");\n\t}\n\n\tprivate <T> T doWithRetry(Callable<T> action) throws Exception {\n\t\tException lastFailure = null;\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\ttry {\n\t\t\t\treturn action.call();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlastFailure = ex;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Action was not successful in 10 attempts\", lastFailure);\n\t}\n\n\tprotected final void doWithBlockedPort(BlockedPortAction action) throws Exception {\n\t\tServerSocket serverSocket = new ServerSocket();\n\t\ttry (serverSocket) {\n\t\t\tint blockedPort = doWithRetry(() -> {\n\t\t\t\tserverSocket.bind(null);\n\t\t\t\treturn serverSocket.getLocalPort();\n\t\t\t});\n\t\t\taction.run(blockedPort);\n\t\t}\n\t}\n\n\tprotected abstract String startedLogMessage();\n\n\tprotected abstract void addConnector(int port, ConfigurableReactiveWebServerFactory factory);\n\n\tpublic interface BlockedPortAction {\n\n\t\tvoid run(int port);\n\n\t}\n\n\tprotected static class EchoHandler implements HttpHandler {\n\n\t\tpublic EchoHandler() {\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\tresponse.setStatusCode(HttpStatus.OK);\n\t\t\treturn response.writeWith(request.getBody());\n\t\t}\n\n\t}\n\n\tprotected static class BlockingHandler implements HttpHandler {\n\n\t\tprivate final BlockingQueue<Sinks.Empty<Void>> processors = new ArrayBlockingQueue<>(10);\n\n\t\tprivate volatile boolean blocking = true;\n\n\t\tpublic BlockingHandler() {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\tif (this.blocking) {\n\t\t\t\tSinks.Empty<Void> completion = Sinks.empty();\n\t\t\t\tthis.processors.add(completion);\n\t\t\t\treturn completion.asMono().then(Mono.empty());\n\t\t\t}\n\t\t\treturn Mono.empty();\n\t\t}\n\n\t\tpublic void completeOne() {\n\t\t\ttry {\n\t\t\t\tSinks.Empty<Void> processor = this.processors.take();\n\t\t\t\tprocessor.tryEmitEmpty();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t}\n\t\t}\n\n\t\tpublic void awaitQueue() throws InterruptedException {\n\t\t\twhile (this.processors.isEmpty()) {\n\t\t\t\tThread.sleep(100);\n\t\t\t}\n\t\t}\n\n\t\tpublic void stopBlocking() {\n\t\t\tthis.blocking = false;\n\t\t\tthis.processors.forEach(Sinks.Empty::tryEmitEmpty);\n\t\t}\n\n\t}\n\n\tstatic class CompressionDetectionHandler extends ChannelInboundHandlerAdapter {\n\n\t\t@Override\n\t\tpublic void channelRead(ChannelHandlerContext ctx, Object msg) {\n\t\t\tif (msg instanceof HttpResponse response) {\n\t\t\t\tboolean compressed = response.headers().contains(HttpHeaderNames.CONTENT_ENCODING, \"gzip\", true);\n\t\t\t\tif (compressed) {\n\t\t\t\t\tresponse.headers().set(\"X-Test-Compressed\", \"true\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tctx.fireChannelRead(msg);\n\t\t}\n\n\t}\n\n\tstatic class CharsHandler implements HttpHandler {\n\n\t\tprivate static final DefaultDataBufferFactory factory = new DefaultDataBufferFactory();\n\n\t\tprivate final DataBuffer bytes;\n\n\t\tprivate final String mediaType;\n\n\t\tCharsHandler(int contentSize, String mediaType) {\n\t\t\tchar[] chars = new char[contentSize];\n\t\t\tArrays.fill(chars, 'F');\n\t\t\tthis.bytes = factory.wrap(new String(chars).getBytes(StandardCharsets.UTF_8));\n\t\t\tthis.mediaType = mediaType;\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\tresponse.setStatusCode(HttpStatus.OK);\n\t\t\tresponse.getHeaders().set(HttpHeaders.CONTENT_TYPE, this.mediaType);\n\t\t\tresponse.getHeaders().setContentLength(this.bytes.readableByteCount());\n\t\t\treturn response.writeWith(Mono.just(this.bytes));\n\t\t}\n\n\t}\n\n\tstatic class XForwardedHandler implements HttpHandler {\n\n\t\t@Override\n\t\tpublic Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {\n\t\t\tString scheme = request.getURI().getScheme();\n\t\t\tDataBufferFactory bufferFactory = new DefaultDataBufferFactory();\n\t\t\tDataBuffer buffer = bufferFactory.wrap(scheme.getBytes(StandardCharsets.UTF_8));\n\t\t\treturn response.writeWith(Mono.just(buffer));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/MockReactiveWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive;\n\nimport java.util.Map;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.http.server.reactive.HttpHandler;\n\n/**\n * A mock reactive {@link WebServer}.\n *\n * @author Brian Clozel\n */\npublic class MockReactiveWebServer implements WebServer {\n\n\tprivate final int port;\n\n\tprivate HttpHandler httpHandler;\n\n\tprivate Map<String, HttpHandler> httpHandlerMap;\n\n\tMockReactiveWebServer(HttpHandler httpHandler, int port) {\n\t\tthis.httpHandler = httpHandler;\n\t\tthis.port = port;\n\t}\n\n\tMockReactiveWebServer(Map<String, HttpHandler> httpHandlerMap, int port) {\n\t\tthis.httpHandlerMap = httpHandlerMap;\n\t\tthis.port = port;\n\t}\n\n\tpublic HttpHandler getHttpHandler() {\n\t\treturn this.httpHandler;\n\t}\n\n\tpublic Map<String, HttpHandler> getHttpHandlerMap() {\n\t\treturn this.httpHandlerMap;\n\t}\n\n\t@Override\n\tpublic void start() {\n\n\t}\n\n\t@Override\n\tpublic void stop() {\n\n\t}\n\n\t@Override\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/reactive/MockReactiveWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.reactive;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.http.server.reactive.HttpHandler;\n\nimport static org.mockito.Mockito.spy;\n\n/**\n * Mock {@link ReactiveWebServerFactory}.\n *\n * @author Brian Clozel\n */\npublic class MockReactiveWebServerFactory extends AbstractReactiveWebServerFactory {\n\n\tprivate MockReactiveWebServer webServer;\n\n\t@Override\n\tpublic WebServer getWebServer(HttpHandler httpHandler) {\n\t\tthis.webServer = spy(new MockReactiveWebServer(httpHandler, getPort()));\n\t\treturn this.webServer;\n\t}\n\n\tpublic MockReactiveWebServer getWebServer() {\n\t\treturn this.webServer;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/AbstractServletWebServerFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PrintWriter;\nimport java.net.InetAddress;\nimport java.net.MalformedURLException;\nimport java.net.ServerSocket;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.RunnableFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.Supplier;\nimport java.util.zip.GZIPInputStream;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLException;\n\nimport jakarta.servlet.AsyncContext;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.ServletConfig;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration.Dynamic;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.SessionCookieConfig;\nimport jakarta.servlet.http.Cookie;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpSession;\nimport org.apache.hc.client5.http.classic.HttpClient;\nimport org.apache.hc.client5.http.classic.methods.HttpGet;\nimport org.apache.hc.client5.http.entity.InputStreamFactory;\nimport org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;\nimport org.apache.hc.client5.http.impl.classic.HttpClientBuilder;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;\nimport org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;\nimport org.apache.hc.client5.http.protocol.HttpClientContext;\nimport org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;\nimport org.apache.hc.client5.http.ssl.TlsSocketStrategy;\nimport org.apache.hc.core5.http.HttpResponse;\nimport org.apache.hc.core5.http.io.HttpClientResponseHandler;\nimport org.apache.hc.core5.http.protocol.HttpContext;\nimport org.apache.hc.core5.ssl.SSLContextBuilder;\nimport org.apache.hc.core5.ssl.TrustStrategy;\nimport org.apache.hc.core5.util.TimeValue;\nimport org.apache.jasper.EmbeddedServletOptions;\nimport org.apache.jasper.servlet.JspServlet;\nimport org.assertj.core.api.ThrowableAssert.ThrowingCallable;\nimport org.awaitility.Awaitility;\nimport org.eclipse.jetty.client.ContentResponse;\nimport org.eclipse.jetty.http2.client.HTTP2Client;\nimport org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Assumptions;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\nimport org.mockito.InOrder;\n\nimport org.springframework.boot.ssl.DefaultSslBundleRegistry;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreBundle;\nimport org.springframework.boot.ssl.jks.JksSslStoreDetails;\nimport org.springframework.boot.ssl.pem.PemSslStoreBundle;\nimport org.springframework.boot.ssl.pem.PemSslStoreDetails;\nimport org.springframework.boot.system.ApplicationHome;\nimport org.springframework.boot.system.ApplicationTemp;\nimport org.springframework.boot.testsupport.classpath.resources.ResourcePath;\nimport org.springframework.boot.testsupport.classpath.resources.WithPackageResources;\nimport org.springframework.boot.testsupport.junit.EnabledOnLocale;\nimport org.springframework.boot.testsupport.system.CapturedOutput;\nimport org.springframework.boot.testsupport.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.web.servlet.ExampleFilter;\nimport org.springframework.boot.testsupport.web.servlet.ExampleServlet;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.server.Compression;\nimport org.springframework.boot.web.server.Cookie.SameSite;\nimport org.springframework.boot.web.server.GracefulShutdownResult;\nimport org.springframework.boot.web.server.Http2;\nimport org.springframework.boot.web.server.MimeMappings;\nimport org.springframework.boot.web.server.PortInUseException;\nimport org.springframework.boot.web.server.Shutdown;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.Ssl.ClientAuth;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.boot.web.server.servlet.Session.SessionTrackingMode;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\nimport static org.assertj.core.api.Assertions.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\n\n/**\n * Base for testing classes that implements {@link ConfigurableServletWebServerFactory}.\n *\n * @author Phillip Webb\n * @author Greg Turnquist\n * @author Andy Wilkinson\n * @author Raja Kolli\n * @author Scott Frederick\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\n// @DirtiesUrlFactories\npublic abstract class AbstractServletWebServerFactoryTests {\n\n\t@TempDir\n\tprotected File tempDir;\n\n\tprotected WebServer webServer;\n\n\tprivate final HttpClientContext httpClientContext = HttpClientContext.create();\n\n\tprivate final Supplier<HttpClientBuilder> httpClientBuilder = () -> HttpClients.custom()\n\t\t.setRetryStrategy(new DefaultHttpRequestRetryStrategy(10, TimeValue.of(200, TimeUnit.MILLISECONDS)));\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.webServer != null) {\n\t\t\ttry {\n\t\t\t\tthis.webServer.stop();\n\t\t\t\ttry {\n\t\t\t\t\tthis.webServer.destroy();\n\t\t\t\t}\n\t\t\t\tcatch (Exception ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t}\n\n\t@Test\n\tvoid startServlet() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid startCalledTwice(CapturedOutput output) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tthis.webServer.start();\n\t\tassertThat(this.webServer.getPort()).isEqualTo(port);\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"Hello World\");\n\t\tassertThat(output).containsOnlyOnce(\"started on port\");\n\t}\n\n\t@Test\n\tvoid stopCalledTwice() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tthis.webServer.stop();\n\t\tthis.webServer.stop();\n\t}\n\n\t@Test\n\tprotected void restartAfterStop() throws IOException, URISyntaxException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"Hello World\");\n\t\tint port = this.webServer.getPort();\n\t\tthis.webServer.stop();\n\t\tassertThatIOException().isThrownBy(() -> getResponse(getLocalUrl(port, \"/hello\")));\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid emptyServerWhenPortIsMinusOne() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setPort(-1);\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(this.webServer.getPort()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid stopServlet() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tthis.webServer.stop();\n\t\tassertThatIOException().isThrownBy(() -> getResponse(getLocalUrl(port, \"/hello\")));\n\t}\n\n\t@Test\n\tvoid startServletAndFilter() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration(),\n\t\t\t\tnew FilterRegistrationBean<>(new ExampleFilter()));\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"[Hello World]\");\n\t}\n\n\t@Test\n\tvoid startBlocksUntilReadyToServe() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfinal Date[] date = new Date[1];\n\t\tthis.webServer = factory.getWebServer((servletContext) -> {\n\t\t\ttry {\n\t\t\t\tThread.sleep(500);\n\t\t\t\tdate[0] = new Date();\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tthrow new ServletException(ex);\n\t\t\t}\n\t\t});\n\t\tthis.webServer.start();\n\t\tassertThat(date[0]).isNotNull();\n\t}\n\n\t@Test\n\tvoid loadOnStartAfterContextIsInitialized() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfinal InitCountingServlet servlet = new InitCountingServlet();\n\t\tthis.webServer = factory\n\t\t\t.getWebServer((servletContext) -> servletContext.addServlet(\"test\", servlet).setLoadOnStartup(1));\n\t\tassertThat(servlet.getInitCount()).isZero();\n\t\tthis.webServer.start();\n\t\tassertThat(servlet.getInitCount()).isOne();\n\t}\n\n\t@Test\n\tvoid portIsMinusOneWhenConnectionIsClosed() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tassertThat(this.webServer.getPort()).isGreaterThan(0);\n\t\tthis.webServer.destroy();\n\t\tassertThat(this.webServer.getPort()).isEqualTo(-1);\n\t}\n\n\t@Test\n\tvoid specificPort() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tint specificPort = doWithRetry(() -> {\n\t\t\tfactory.setPort(0);\n\t\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\t\tthis.webServer.start();\n\t\t\treturn this.webServer.getPort();\n\t\t});\n\t\tassertThat(getResponse(\"http://localhost:\" + specificPort + \"/hello\")).isEqualTo(\"Hello World\");\n\t\tassertThat(this.webServer.getPort()).isEqualTo(specificPort);\n\t}\n\n\t@Test\n\tvoid specificContextRoot() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setContextPath(\"/say\");\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/say/hello\"))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid contextPathIsLoggedOnStartup(CapturedOutput output) {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setContextPath(\"/custom\");\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(output).containsOnlyOnce(\"with context path '/custom'\");\n\t}\n\n\t@Test\n\tvoid contextPathMustStartWithSlash() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> getFactory().setContextPath(\"missingslash\"))\n\t\t\t.withMessageContaining(\"Context path must start with '/' and not end with '/'\");\n\t}\n\n\t@Test\n\tvoid contextPathMustNotEndWithSlash() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> getFactory().setContextPath(\"extraslash/\"))\n\t\t\t.withMessageContaining(\"Context path must start with '/' and not end with '/'\");\n\t}\n\n\t@Test\n\tvoid contextRootPathMustNotBeSlash() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> getFactory().setContextPath(\"/\"))\n\t\t\t.withMessageContaining(\"Root context path must be specified using an empty string\");\n\t}\n\n\t@Test\n\tvoid multipleConfigurations() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tServletContextInitializer[] initializers = new ServletContextInitializer[6];\n\t\tArrays.setAll(initializers, (i) -> mock(ServletContextInitializer.class));\n\t\tfactory.setInitializers(Arrays.asList(initializers[2], initializers[3]));\n\t\tfactory.addInitializers(initializers[4], initializers[5]);\n\t\tthis.webServer = factory.getWebServer(initializers[0], initializers[1]);\n\t\tthis.webServer.start();\n\t\tInOrder ordered = inOrder((Object[]) initializers);\n\t\tfor (ServletContextInitializer initializer : initializers) {\n\t\t\tthen(initializer).should(ordered).onStartup(any(ServletContext.class));\n\t\t}\n\t}\n\n\t@Test\n\tvoid documentRoot() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/test.txt\"))).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid mimeType() throws Exception {\n\t\tFileCopyUtils.copy(\"test\", new FileWriter(new File(this.tempDir, \"test.xxcss\")));\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setRegisterDefaultServlet(true);\n\t\tfactory.setDocumentRoot(this.tempDir);\n\t\tMimeMappings mimeMappings = new MimeMappings();\n\t\tmimeMappings.add(\"xxcss\", \"text/css\");\n\t\tfactory.setMimeMappings(mimeMappings);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tClientHttpResponse response = getClientResponse(getLocalUrl(\"/test.xxcss\"));\n\t\tassertThat(response.getHeaders().getContentType()).hasToString(\"text/css\");\n\t\tresponse.close();\n\t}\n\n\t@Test\n\tvoid errorPage() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, \"/hello\"));\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration(), errorServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"))).isEqualTo(\"Hello World\");\n\t\tassertThat(getResponse(getLocalUrl(\"/bang\"))).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid errorPageFromPutRequest() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, \"/hello\"));\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration(), errorServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"), HttpMethod.PUT)).isEqualTo(\"Hello World\");\n\t\tassertThat(getResponse(getLocalUrl(\"/bang\"), HttpMethod.PUT)).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid basicSslFromClassPath() throws Exception {\n\t\ttestBasicSslWithKeyStore(\"classpath:test.jks\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid basicSslFromFileSystem(@ResourcePath(\"test.jks\") String keyStore) throws Exception {\n\t\ttestBasicSslWithKeyStore(keyStore);\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslDisabled() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tSsl ssl = getSsl(null, \"password\", \"classpath:test.jks\");\n\t\tssl.setEnabled(false);\n\t\tfactory.setSsl(ssl);\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), \"/hello\"));\n\t\tthis.webServer.start();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tcreateTrustSelfSignedTlsSocketStrategy());\n\t\tassertThatExceptionOfType(SSLException.class)\n\t\t\t.isThrownBy(() -> getResponse(getLocalUrl(\"https\", \"/hello\"), requestFactory));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslGetScheme() throws Exception { // gh-2232\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(getSsl(null, \"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), \"/hello\"));\n\t\tthis.webServer.start();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tcreateTrustSelfSignedTlsSocketStrategy());\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/hello\"), requestFactory)).contains(\"scheme=https\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslKeyAlias() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tSsl ssl = getSsl(null, \"password\", \"test-alias\", \"classpath:test.jks\");\n\t\tfactory.setSsl(ssl);\n\t\tServletRegistrationBean<ExampleServlet> registration = new ServletRegistrationBean<>(\n\t\t\t\tnew ExampleServlet(true, false), \"/hello\");\n\t\tthis.webServer = factory.getWebServer(registration);\n\t\tthis.webServer.start();\n\t\tTrustStrategy trustStrategy = new SerialNumberValidatingTrustSelfSignedStrategy(\"14ca9ba6abe2a70d\");\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build();\n\t\tPoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()\n\t\t\t.setTlsSocketStrategy(new DefaultClientTlsStrategy(sslContext))\n\t\t\t.build();\n\t\tHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();\n\t\tString response = getResponse(getLocalUrl(\"https\", \"/hello\"),\n\t\t\t\tnew HttpComponentsClientHttpRequestFactory(httpClient));\n\t\tassertThat(response).contains(\"scheme=https\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWithInvalidAliasFailsDuringStartup() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tSsl ssl = getSsl(null, \"password\", \"test-alias-404\", \"classpath:test.jks\");\n\t\tfactory.setSsl(ssl);\n\t\tServletRegistrationBean<ExampleServlet> registration = new ServletRegistrationBean<>(\n\t\t\t\tnew ExampleServlet(true, false), \"/hello\");\n\t\tThrowingCallable call = () -> factory.getWebServer(registration).start();\n\t\tassertThatSslWithInvalidAliasCallFails(call);\n\t}\n\n\tprotected void assertThatSslWithInvalidAliasCallFails(ThrowingCallable call) {\n\t\tassertThatException().isThrownBy(call)\n\t\t\t.withStackTraceContaining(\"Keystore does not contain alias 'test-alias-404'\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid serverHeaderIsDisabledByDefaultWhenUsingSsl() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setSsl(getSsl(null, \"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), \"/hello\"));\n\t\tthis.webServer.start();\n\t\tPoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()\n\t\t\t.setTlsSocketStrategy(createTrustSelfSignedTlsSocketStrategy())\n\t\t\t.build();\n\t\tHttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build();\n\t\tClientHttpResponse response = getClientResponse(getLocalUrl(\"https\", \"/hello\"), HttpMethod.GET,\n\t\t\t\tnew HttpComponentsClientHttpRequestFactory(httpClient));\n\t\tassertThat(response.getHeaders().get(\"Server\")).isNullOrEmpty();\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid serverHeaderCanBeCustomizedWhenUsingSsl() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setServerHeader(\"MyServer\");\n\t\tfactory.setSsl(getSsl(null, \"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), \"/hello\"));\n\t\tthis.webServer.start();\n\t\tPoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()\n\t\t\t.setTlsSocketStrategy(createTrustSelfSignedTlsSocketStrategy())\n\t\t\t.build();\n\t\tHttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build();\n\t\tClientHttpResponse response = getClientResponse(getLocalUrl(\"https\", \"/hello\"), HttpMethod.GET,\n\t\t\t\tnew HttpComponentsClientHttpRequestFactory(httpClient));\n\t\tassertThat(response.getHeaders().get(\"Server\")).containsExactly(\"MyServer\");\n\t}\n\n\tprotected final void testBasicSslWithKeyStore(String keyStore) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(getSsl(null, \"password\", keyStore));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tcreateTrustSelfSignedTlsSocketStrategy());\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.p12\")\n\tvoid pkcs12KeyStoreAndTrustStore(@ResourcePath(\"test.p12\") File keyStoreFile) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(getSsl(ClientAuth.NEED, null, \"classpath:test.p12\", \"classpath:test.p12\", null, null));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tKeyStore keyStore = KeyStore.getInstance(\"pkcs12\");\n\t\tloadStore(keyStore, new FileSystemResource(keyStoreFile));\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())\n\t\t\t.loadKeyMaterial(keyStore, \"secret\".toCharArray())\n\t\t\t.build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tnew DefaultClientTlsStrategy(sslContext));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test.p12\", \"test-cert.pem\", \"test-key.pem\" })\n\tvoid pemKeyStoreAndTrustStore(@ResourcePath(\"test.p12\") File keyStoreFile) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(getSsl(\"classpath:test-cert.pem\", \"classpath:test-key.pem\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tKeyStore keyStore = KeyStore.getInstance(\"pkcs12\");\n\t\tloadStore(keyStore, new FileSystemResource(keyStoreFile));\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())\n\t\t\t.loadKeyMaterial(keyStore, \"secret\".toCharArray())\n\t\t\t.build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tnew DefaultClientTlsStrategy(sslContext));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.p12\")\n\tvoid pkcs12KeyStoreAndTrustStoreFromBundle(@ResourcePath(\"test.p12\") File keyStoreFile) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(Ssl.forBundle(\"test\"));\n\t\tfactory.setSslBundles(\n\t\t\t\tnew DefaultSslBundleRegistry(\"test\", createJksSslBundle(\"classpath:test.p12\", \"classpath:test.p12\")));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tKeyStore keyStore = KeyStore.getInstance(\"pkcs12\");\n\t\tloadStore(keyStore, new FileSystemResource(keyStoreFile));\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())\n\t\t\t.loadKeyMaterial(keyStore, \"secret\".toCharArray())\n\t\t\t.build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tnew DefaultClientTlsStrategy(sslContext));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources({ \"test.p12\", \"test-cert.pem\", \"test-key.pem\" })\n\tvoid pemKeyStoreAndTrustStoreFromBundle(@ResourcePath(\"test.p12\") File keyStoreFile) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(Ssl.forBundle(\"test\"));\n\t\tfactory.setSslBundles(new DefaultSslBundleRegistry(\"test\",\n\t\t\t\tcreatePemSslBundle(\"classpath:test-cert.pem\", \"classpath:test-key.pem\")));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tKeyStore keyStore = KeyStore.getInstance(\"pkcs12\");\n\t\tloadStore(keyStore, new FileSystemResource(keyStoreFile));\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())\n\t\t\t.loadKeyMaterial(keyStore, \"secret\".toCharArray())\n\t\t\t.build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tnew DefaultClientTlsStrategy(sslContext));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslNeedsClientAuthenticationSucceedsWithClientCertificate(@ResourcePath(\"test.jks\") File keyStoreFile)\n\t\t\tthrows Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setRegisterDefaultServlet(true);\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(getSsl(ClientAuth.NEED, \"password\", \"classpath:test.jks\", \"classpath:test.jks\", null, null));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tKeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\tloadStore(keyStore, new FileSystemResource(keyStoreFile));\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())\n\t\t\t.loadKeyMaterial(keyStore, \"password\".toCharArray())\n\t\t\t.build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tnew DefaultClientTlsStrategy(sslContext));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslNeedsClientAuthenticationFailsWithoutClientCertificate() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(getSsl(ClientAuth.NEED, \"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tcreateTrustSelfSignedTlsSocketStrategy());\n\t\tString localUrl = getLocalUrl(\"https\", \"/test.txt\");\n\t\tassertThatIOException().isThrownBy(() -> getResponse(localUrl, requestFactory));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWantsClientAuthenticationSucceedsWithClientCertificate(@ResourcePath(\"test.jks\") File keyStoreFile)\n\t\t\tthrows Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory\n\t\t\t.setSsl(getSsl(ClientAuth.WANT, \"password\", \"classpath:test.jks\", null, new String[] { \"TLSv1.2\" }, null));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tKeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\n\t\tloadStore(keyStore, new FileSystemResource(keyStoreFile));\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())\n\t\t\t.loadKeyMaterial(keyStore, \"password\".toCharArray())\n\t\t\t.build();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tnew DefaultClientTlsStrategy(sslContext));\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tvoid sslWantsClientAuthenticationSucceedsWithoutClientCertificate() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddTestTxtFile(factory);\n\t\tfactory.setSsl(getSsl(ClientAuth.WANT, \"password\", \"classpath:test.jks\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tHttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(\n\t\t\t\tcreateTrustSelfSignedTlsSocketStrategy());\n\t\tassertThat(getResponse(getLocalUrl(\"https\", \"/test.txt\"), requestFactory)).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid disableJspServletRegistration() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getJsp().setRegistered(false);\n\t\tthis.webServer = factory.getWebServer();\n\t\tassertThat(getJspServlet()).isNull();\n\t}\n\n\t@Test\n\tvoid cannotReadClassPathFiles() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tClientHttpResponse response = getClientResponse(\n\t\t\t\tgetLocalUrl(\"/org/springframework/boot/SpringApplication.class\"));\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\tprotected Ssl getSsl(@Nullable ClientAuth clientAuth, @Nullable String keyPassword, @Nullable String keyStore) {\n\t\treturn getSsl(clientAuth, keyPassword, keyStore, null, null, null);\n\t}\n\n\tprotected Ssl getSsl(@Nullable ClientAuth clientAuth, @Nullable String keyPassword, @Nullable String keyAlias,\n\t\t\t@Nullable String keyStore) {\n\t\treturn getSsl(clientAuth, keyPassword, keyAlias, keyStore, null, null, null);\n\t}\n\n\tprotected Ssl getSsl(@Nullable ClientAuth clientAuth, @Nullable String keyPassword, @Nullable String keyStore,\n\t\t\t@Nullable String trustStore, String @Nullable [] supportedProtocols, String @Nullable [] ciphers) {\n\t\treturn getSsl(clientAuth, keyPassword, null, keyStore, trustStore, supportedProtocols, ciphers);\n\t}\n\n\tprivate Ssl getSsl(@Nullable ClientAuth clientAuth, @Nullable String keyPassword, @Nullable String keyAlias,\n\t\t\t@Nullable String keyStore, @Nullable String trustStore, String @Nullable [] supportedProtocols,\n\t\t\tString @Nullable [] ciphers) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(clientAuth);\n\t\tif (keyPassword != null) {\n\t\t\tssl.setKeyPassword(keyPassword);\n\t\t}\n\t\tif (keyAlias != null) {\n\t\t\tssl.setKeyAlias(keyAlias);\n\t\t}\n\t\tif (keyStore != null) {\n\t\t\tssl.setKeyStore(keyStore);\n\t\t\tssl.setKeyStorePassword(\"secret\");\n\t\t\tssl.setKeyStoreType(getStoreType(keyStore));\n\t\t}\n\t\tif (trustStore != null) {\n\t\t\tssl.setTrustStore(trustStore);\n\t\t\tssl.setTrustStorePassword(\"secret\");\n\t\t\tssl.setTrustStoreType(getStoreType(trustStore));\n\t\t}\n\t\tif (ciphers != null) {\n\t\t\tssl.setCiphers(ciphers);\n\t\t}\n\t\tif (supportedProtocols != null) {\n\t\t\tssl.setEnabledProtocols(supportedProtocols);\n\t\t}\n\t\treturn ssl;\n\t}\n\n\tprivate Ssl getSsl(String cert, String privateKey) {\n\t\tSsl ssl = new Ssl();\n\t\tssl.setClientAuth(ClientAuth.NEED);\n\t\tssl.setCertificate(cert);\n\t\tssl.setCertificatePrivateKey(privateKey);\n\t\tssl.setTrustCertificate(cert);\n\t\treturn ssl;\n\t}\n\n\tprivate SslBundle createJksSslBundle(String keyStore, String trustStore) {\n\t\tJksSslStoreDetails keyStoreDetails = getJksStoreDetails(keyStore);\n\t\tJksSslStoreDetails trustStoreDetails = getJksStoreDetails(trustStore);\n\t\tSslStoreBundle stores = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\treturn SslBundle.of(stores);\n\t}\n\n\tprivate JksSslStoreDetails getJksStoreDetails(String location) {\n\t\treturn new JksSslStoreDetails(getStoreType(location), null, location, \"secret\");\n\t}\n\n\tprotected SslBundle createPemSslBundle(String cert, String privateKey) {\n\t\tPemSslStoreDetails keyStoreDetails = PemSslStoreDetails.forCertificate(cert).withPrivateKey(privateKey);\n\t\tPemSslStoreDetails trustStoreDetails = PemSslStoreDetails.forCertificate(cert);\n\t\tSslStoreBundle stores = new PemSslStoreBundle(keyStoreDetails, trustStoreDetails);\n\t\treturn SslBundle.of(stores);\n\t}\n\n\tprotected HttpComponentsClientHttpRequestFactory createHttpComponentsRequestFactory(\n\t\t\tTlsSocketStrategy tlsSocketStrategy) {\n\t\tPoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()\n\t\t\t.setTlsSocketStrategy(tlsSocketStrategy)\n\t\t\t.build();\n\t\tHttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build();\n\t\treturn new HttpComponentsClientHttpRequestFactory(httpClient);\n\t}\n\n\tprivate String getStoreType(String keyStore) {\n\t\treturn keyStore.endsWith(\".p12\") ? \"pkcs12\" : null;\n\t}\n\n\t@Test\n\tvoid defaultSessionTimeout() {\n\t\tassertThat(getFactory().getSettings().getSession().getTimeout()).hasMinutes(30);\n\t}\n\n\t@Test\n\tvoid persistSession() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setPersistent(true);\n\t\tthis.webServer = factory.getWebServer(sessionServletRegistration());\n\t\tthis.webServer.start();\n\t\tString s1 = getResponse(getLocalUrl(\"/session\"));\n\t\tString s2 = getResponse(getLocalUrl(\"/session\"));\n\t\tthis.webServer.destroy();\n\t\tthis.webServer = factory.getWebServer(sessionServletRegistration());\n\t\tthis.webServer.start();\n\t\tString s3 = getResponse(getLocalUrl(\"/session\"));\n\t\tString message = \"Session error s1=\" + s1 + \" s2=\" + s2 + \" s3=\" + s3;\n\t\tassertThat(s2.split(\":\")[0]).as(message).isEqualTo(s1.split(\":\")[1]);\n\t\tassertThat(s3.split(\":\")[0]).as(message).isEqualTo(s2.split(\":\")[1]);\n\t}\n\n\t@Test\n\tvoid persistSessionInSpecificSessionStoreDir() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tFile sessionStoreDir = new File(this.tempDir, \"sessions\");\n\t\tsessionStoreDir.mkdir();\n\t\tfactory.getSettings().getSession().setPersistent(true);\n\t\tfactory.getSettings().getSession().setStoreDir(sessionStoreDir);\n\t\tthis.webServer = factory.getWebServer(sessionServletRegistration());\n\t\tthis.webServer.start();\n\t\tgetResponse(getLocalUrl(\"/session\"));\n\t\tthis.webServer.destroy();\n\t\tFile[] dirContents = sessionStoreDir.listFiles((dir, name) -> !(\".\".equals(name) || \"..\".equals(name)));\n\t\tassertThat(dirContents).isNotEmpty();\n\t}\n\n\t@Test\n\tvoid getValidSessionStoreWhenSessionStoreNotSet() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tFile dir = factory.getSettings().getSession().getSessionStoreDirectory().getValidDirectory(false);\n\t\tassertThat(dir).hasName(\"servlet-sessions\");\n\t\tassertThat(dir).hasParent(new ApplicationTemp().getDir());\n\t}\n\n\t@Test\n\tvoid getValidSessionStoreWhenSessionStoreIsRelative() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().setStoreDir(new File(\"sessions\"));\n\t\tFile dir = factory.getSettings().getSession().getSessionStoreDirectory().getValidDirectory(false);\n\t\tassertThat(dir).hasName(\"sessions\");\n\t\tassertThat(dir).hasParent(new ApplicationHome().getDir());\n\t}\n\n\t@Test\n\tvoid getValidSessionStoreWhenSessionStoreReferencesFile() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\tfile.createNewFile();\n\t\tfactory.getSettings().getSession().setStoreDir(file);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> factory.getSettings().getSession().getSessionStoreDirectory().getValidDirectory(false))\n\t\t\t.withMessageContaining(\"points to a file\");\n\t}\n\n\t@Test\n\tvoid sessionCookieConfiguration() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\torg.springframework.boot.web.server.Cookie cookie = factory.getSettings().getSession().getCookie();\n\t\tcookie.setName(\"testname\");\n\t\tcookie.setDomain(\"testdomain\");\n\t\tcookie.setPath(\"/testpath\");\n\t\tcookie.setHttpOnly(true);\n\t\tcookie.setSecure(true);\n\t\tcookie.setPartitioned(true);\n\t\tcookie.setMaxAge(Duration.ofSeconds(60));\n\t\tfinal AtomicReference<SessionCookieConfig> configReference = new AtomicReference<>();\n\t\tthis.webServer = factory.getWebServer((context) -> configReference.set(context.getSessionCookieConfig()));\n\t\tSessionCookieConfig sessionCookieConfig = configReference.get();\n\t\tassertThat(sessionCookieConfig.getName()).isEqualTo(\"testname\");\n\t\tassertThat(sessionCookieConfig.getDomain()).isEqualTo(\"testdomain\");\n\t\tassertThat(sessionCookieConfig.getPath()).isEqualTo(\"/testpath\");\n\t\tassertThat(sessionCookieConfig.isHttpOnly()).isTrue();\n\t\tassertThat(sessionCookieConfig.isSecure()).isTrue();\n\t\tassertThat(sessionCookieConfig.getAttribute(\"Partitioned\")).isEqualTo(\"true\");\n\t\tassertThat(sessionCookieConfig.getMaxAge()).isEqualTo(60);\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(mode = EnumSource.Mode.EXCLUDE, names = \"OMITTED\")\n\tvoid sessionCookieSameSiteAttributeCanBeConfiguredAndOnlyAffectsSessionCookies(SameSite sameSite) throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().getCookie().setSameSite(sameSite);\n\t\tfactory.addInitializers(new ServletRegistrationBean<>(new CookieServlet(false), \"/\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tClientHttpResponse clientResponse = getClientResponse(getLocalUrl(\"/\"));\n\t\tList<String> setCookieHeaders = clientResponse.getHeaders().get(\"Set-Cookie\");\n\t\tassertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(\n\t\t\t\t(header) -> assertThat(header).contains(\"JSESSIONID\").contains(\"SameSite=\" + sameSite.attributeValue()),\n\t\t\t\t(header) -> assertThat(header).contains(\"test=test\").doesNotContain(\"SameSite\"));\n\t}\n\n\t@ParameterizedTest\n\t@EnumSource(mode = EnumSource.Mode.EXCLUDE, names = \"OMITTED\")\n\tvoid sessionCookieSameSiteAttributeCanBeConfiguredAndOnlyAffectsSessionCookiesWhenUsingCustomName(SameSite sameSite)\n\t\t\tthrows Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().getCookie().setName(\"THESESSION\");\n\t\tfactory.getSettings().getSession().getCookie().setSameSite(sameSite);\n\t\tfactory.addInitializers(new ServletRegistrationBean<>(new CookieServlet(false), \"/\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tClientHttpResponse clientResponse = getClientResponse(getLocalUrl(\"/\"));\n\t\tList<String> setCookieHeaders = clientResponse.getHeaders().get(\"Set-Cookie\");\n\t\tassertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(\n\t\t\t\t(header) -> assertThat(header).contains(\"THESESSION\").contains(\"SameSite=\" + sameSite.attributeValue()),\n\t\t\t\t(header) -> assertThat(header).contains(\"test=test\").doesNotContain(\"SameSite\"));\n\t}\n\n\t@Test\n\tvoid cookieSameSiteSuppliers() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofLax().whenHasName(\"relaxed\"));\n\t\tfactory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofNone().whenHasName(\"empty\"));\n\t\tfactory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofStrict().whenHasName(\"controlled\"));\n\t\tfactory.addInitializers(new ServletRegistrationBean<>(new CookieServlet(true), \"/\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tClientHttpResponse clientResponse = getClientResponse(getLocalUrl(\"/\"));\n\t\tassertThat(clientResponse.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tList<String> setCookieHeaders = clientResponse.getHeaders().get(\"Set-Cookie\");\n\t\tassertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(\n\t\t\t\t(header) -> assertThat(header).contains(\"JSESSIONID\").doesNotContain(\"SameSite\"),\n\t\t\t\t(header) -> assertThat(header).contains(\"test=test\").doesNotContain(\"SameSite\"),\n\t\t\t\t(header) -> assertThat(header).contains(\"relaxed=test\").contains(\"SameSite=Lax\"),\n\t\t\t\t(header) -> assertThat(header).contains(\"empty=test\").contains(\"SameSite=None\"),\n\t\t\t\t(header) -> assertThat(header).contains(\"controlled=test\").contains(\"SameSite=Strict\"));\n\t}\n\n\t@Test\n\tvoid cookieSameSiteSuppliersShouldNotAffectSessionCookie() throws IOException, URISyntaxException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().getCookie().setSameSite(SameSite.LAX);\n\t\tfactory.getSettings().getSession().getCookie().setName(\"SESSIONCOOKIE\");\n\t\tfactory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofStrict());\n\t\tfactory.addInitializers(new ServletRegistrationBean<>(new CookieServlet(false), \"/\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tClientHttpResponse clientResponse = getClientResponse(getLocalUrl(\"/\"));\n\t\tassertThat(clientResponse.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tList<String> setCookieHeaders = clientResponse.getHeaders().get(\"Set-Cookie\");\n\t\tassertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(\n\t\t\t\t(header) -> assertThat(header).contains(\"SESSIONCOOKIE\").contains(\"SameSite=Lax\"),\n\t\t\t\t(header) -> assertThat(header).contains(\"test=test\").contains(\"SameSite=Strict\"));\n\t}\n\n\t@Test\n\tvoid cookieSameSiteSuppliersShouldNotAffectOmittedSameSite() throws IOException, URISyntaxException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getSession().getCookie().setSameSite(SameSite.OMITTED);\n\t\tfactory.getSettings().getSession().getCookie().setName(\"SESSIONCOOKIE\");\n\t\tfactory.addCookieSameSiteSuppliers(CookieSameSiteSupplier.ofStrict());\n\t\tfactory.addInitializers(new ServletRegistrationBean<>(new CookieServlet(false), \"/\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tClientHttpResponse clientResponse = getClientResponse(getLocalUrl(\"/\"));\n\t\tassertThat(clientResponse.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tList<String> setCookieHeaders = clientResponse.getHeaders().get(\"Set-Cookie\");\n\t\tassertThat(setCookieHeaders).satisfiesExactlyInAnyOrder(\n\t\t\t\t(header) -> assertThat(header).contains(\"SESSIONCOOKIE\").doesNotContain(\"SameSite\"),\n\t\t\t\t(header) -> assertThat(header).contains(\"test=test\").contains(\"SameSite=Strict\"));\n\t}\n\n\t@Test\n\t@WithPackageResources(\"test.jks\")\n\tprotected void sslSessionTracking() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tSsl ssl = new Ssl();\n\t\tssl.setEnabled(true);\n\t\tssl.setKeyStore(\"classpath:test.jks\");\n\t\tssl.setKeyPassword(\"password\");\n\t\tfactory.setSsl(ssl);\n\t\tfactory.getSettings().getSession().setTrackingModes(EnumSet.of(SessionTrackingMode.SSL));\n\t\tAtomicReference<ServletContext> contextReference = new AtomicReference<>();\n\t\tthis.webServer = factory.getWebServer(contextReference::set);\n\t\tassertThat(contextReference.get().getEffectiveSessionTrackingModes())\n\t\t\t.isEqualTo(EnumSet.of(jakarta.servlet.SessionTrackingMode.SSL));\n\t}\n\n\t@Test\n\tvoid compressionOfResponseToGetRequest() throws Exception {\n\t\tassertThat(doTestCompression(10000, null, null)).isTrue();\n\t}\n\n\t@Test\n\tvoid compressionOfResponseToPostRequest() throws Exception {\n\t\tassertThat(doTestCompression(10000, null, null, HttpMethod.POST)).isTrue();\n\t}\n\n\t@Test\n\tvoid noCompressionForSmallResponse() throws Exception {\n\t\tassertThat(doTestCompression(100, null, null)).isFalse();\n\t}\n\n\t@Test\n\tvoid noCompressionForMimeType() throws Exception {\n\t\tString[] mimeTypes = new String[] { \"text/html\", \"text/xml\", \"text/css\" };\n\t\tassertThat(doTestCompression(10000, mimeTypes, null)).isFalse();\n\t}\n\n\t@Test\n\tprotected void noCompressionForUserAgent() throws Exception {\n\t\tassertThat(doTestCompression(10000, null, new String[] { \"testUserAgent\" })).isFalse();\n\t}\n\n\t@Test\n\tvoid compressionWithoutContentSizeHeader() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tfactory.setCompression(compression);\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(false, true), \"/hello\"));\n\t\tthis.webServer.start();\n\t\tTestGzipInputStreamFactory inputStreamFactory = new TestGzipInputStreamFactory();\n\t\tLinkedHashMap<String, InputStreamFactory> contentDecoderMap = new LinkedHashMap<>();\n\t\tcontentDecoderMap.put(\"gzip\", inputStreamFactory);\n\t\tgetResponse(getLocalUrl(\"/hello\"), new HttpComponentsClientHttpRequestFactory(\n\t\t\t\tthis.httpClientBuilder.get().setContentDecoderRegistry(contentDecoderMap).build()));\n\t\tassertThat(inputStreamFactory.wasCompressionUsed()).isTrue();\n\t}\n\n\t@Test\n\tvoid mimeMappingsAreCorrectlyConfigured() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tCollection<MimeMappings.Mapping> configuredMimeMappings = getActualMimeMappings().entrySet()\n\t\t\t.stream()\n\t\t\t.map((entry) -> new MimeMappings.Mapping(entry.getKey(), entry.getValue()))\n\t\t\t.toList();\n\t\tCollection<MimeMappings.Mapping> expectedMimeMappings = MimeMappings.DEFAULT.getAll();\n\t\tassertThat(configuredMimeMappings).containsExactlyInAnyOrderElementsOf(expectedMimeMappings);\n\t}\n\n\t@Test\n\tvoid additionalMimeMappingsCanBeConfigured() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tMimeMappings additionalMimeMappings = new MimeMappings();\n\t\tadditionalMimeMappings.add(\"a\", \"alpha\");\n\t\tadditionalMimeMappings.add(\"b\", \"bravo\");\n\t\tfactory.addMimeMappings(additionalMimeMappings);\n\t\tthis.webServer = factory.getWebServer();\n\t\tCollection<MimeMappings.Mapping> configuredMimeMappings = getActualMimeMappings().entrySet()\n\t\t\t.stream()\n\t\t\t.map((entry) -> new MimeMappings.Mapping(entry.getKey(), entry.getValue()))\n\t\t\t.toList();\n\t\tList<MimeMappings.Mapping> expectedMimeMappings = new ArrayList<>(MimeMappings.DEFAULT.getAll());\n\t\texpectedMimeMappings.addAll(additionalMimeMappings.getAll());\n\t\tassertThat(configuredMimeMappings).containsExactlyInAnyOrderElementsOf(expectedMimeMappings);\n\t}\n\n\t@Test\n\tvoid rootServletContextResource() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfinal AtomicReference<URL> rootResource = new AtomicReference<>();\n\t\tthis.webServer = factory.getWebServer((servletContext) -> {\n\t\t\ttry {\n\t\t\t\trootResource.set(servletContext.getResource(\"/\"));\n\t\t\t}\n\t\t\tcatch (MalformedURLException ex) {\n\t\t\t\tthrow new ServletException(ex);\n\t\t\t}\n\t\t});\n\t\tthis.webServer.start();\n\t\tassertThat(rootResource.get()).isNotNull();\n\t}\n\n\t@Test\n\tvoid customServerHeader() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setServerHeader(\"MyServer\");\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tClientHttpResponse response = getClientResponse(getLocalUrl(\"/hello\"));\n\t\tassertThat(response.getHeaders().getFirst(\"server\")).isEqualTo(\"MyServer\");\n\t}\n\n\t@Test\n\tvoid serverHeaderIsDisabledByDefault() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tClientHttpResponse response = getClientResponse(getLocalUrl(\"/hello\"));\n\t\tassertThat(response.getHeaders().getFirst(\"server\")).isNull();\n\t}\n\n\t@Test\n\t@EnabledOnLocale(language = \"en\")\n\tprotected void portClashOfPrimaryConnectorResultsInPortInUseException() throws Exception {\n\t\tdoWithBlockedPort((port) -> {\n\t\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {\n\t\t\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\t\t\tfactory.setPort(port);\n\t\t\t\tAbstractServletWebServerFactoryTests.this.webServer = factory.getWebServer();\n\t\t\t\tAbstractServletWebServerFactoryTests.this.webServer.start();\n\t\t\t}).satisfies((ex) -> handleExceptionCausedByBlockedPortOnPrimaryConnector(ex, port));\n\t\t});\n\t}\n\n\t@Test\n\t@EnabledOnLocale(language = \"en\")\n\tprotected void portClashOfSecondaryConnectorResultsInPortInUseException() throws Exception {\n\t\tdoWithBlockedPort((port) -> {\n\t\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {\n\t\t\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\t\t\taddConnector(port, factory);\n\t\t\t\tAbstractServletWebServerFactoryTests.this.webServer = factory.getWebServer();\n\t\t\t\tAbstractServletWebServerFactoryTests.this.webServer.start();\n\t\t\t}).satisfies((ex) -> handleExceptionCausedByBlockedPortOnSecondaryConnector(ex, port));\n\t\t});\n\t}\n\n\t@Test\n\tvoid malformedAddress() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setAddress(InetAddress.getByName(\"129.129.129.129\"));\n\t\tassertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> {\n\t\t\tthis.webServer = factory.getWebServer();\n\t\t\tthis.webServer.start();\n\t\t}).isNotInstanceOf(PortInUseException.class);\n\t}\n\n\t@Test\n\tvoid localeCharsetMappingsAreConfigured() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tMap<Locale, Charset> mappings = new HashMap<>();\n\t\tmappings.put(Locale.GERMAN, StandardCharsets.UTF_8);\n\t\tfactory.setLocaleCharsetMappings(mappings);\n\t\tthis.webServer = factory.getWebServer();\n\t\tassertThat(getCharset(Locale.GERMAN)).isEqualTo(StandardCharsets.UTF_8);\n\t\tassertThat(getCharset(Locale.ITALIAN)).isNull();\n\t}\n\n\t@Test\n\tvoid jspServletInitParameters() throws Exception {\n\t\tMap<String, String> initParameters = new HashMap<>();\n\t\tinitParameters.put(\"a\", \"alpha\");\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.getSettings().getJsp().setInitParameters(initParameters);\n\t\tthis.webServer = factory.getWebServer();\n\t\tAssumptions.assumeFalse(getJspServlet() == null);\n\t\tJspServlet jspServlet = getJspServlet();\n\t\tassertThat(jspServlet.getInitParameter(\"a\")).isEqualTo(\"alpha\");\n\t}\n\n\t@Test\n\tvoid jspServletIsNotInDevelopmentModeByDefault() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tAssumptions.assumeFalse(getJspServlet() == null);\n\t\tJspServlet jspServlet = getJspServlet();\n\t\tEmbeddedServletOptions options = (EmbeddedServletOptions) ReflectionTestUtils.getField(jspServlet, \"options\");\n\t\tassertThat(options.getDevelopment()).isFalse();\n\t}\n\n\t@Test\n\tvoid faultyFilterCausesStartFailure() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.addInitializers((servletContext) -> servletContext.addFilter(\"faulty\", new Filter() {\n\n\t\t\t@Override\n\t\t\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t\t\t\tthrow new ServletException(\"Faulty filter\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\t\tthrows IOException, ServletException {\n\t\t\t\tchain.doFilter(request, response);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void destroy() {\n\t\t\t}\n\n\t\t}));\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(() -> factory.getWebServer().start());\n\t}\n\n\t@Test\n\tvoid sessionConfiguration() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tSession session = factory.getSettings().getSession();\n\t\tsession.setTimeout(Duration.ofSeconds(123));\n\t\tsession.setTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE, SessionTrackingMode.URL));\n\t\torg.springframework.boot.web.server.Cookie cookie = session.getCookie();\n\t\tcookie.setName(\"testname\");\n\t\tcookie.setDomain(\"testdomain\");\n\t\tcookie.setPath(\"/testpath\");\n\t\tcookie.setHttpOnly(true);\n\t\tcookie.setSecure(true);\n\t\tcookie.setPartitioned(false);\n\t\tcookie.setMaxAge(Duration.ofMinutes(1));\n\t\tAtomicReference<ServletContext> contextReference = new AtomicReference<>();\n\t\tfactory.getWebServer(contextReference::set).start();\n\t\tServletContext servletContext = contextReference.get();\n\t\tassertThat(servletContext.getEffectiveSessionTrackingModes())\n\t\t\t.isEqualTo(EnumSet.of(jakarta.servlet.SessionTrackingMode.COOKIE, jakarta.servlet.SessionTrackingMode.URL));\n\t\tSessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();\n\t\tassertThat(sessionCookieConfig.getName()).isEqualTo(\"testname\");\n\t\tassertThat(sessionCookieConfig.getDomain()).isEqualTo(\"testdomain\");\n\t\tassertThat(sessionCookieConfig.getPath()).isEqualTo(\"/testpath\");\n\t\tassertThat(sessionCookieConfig.isHttpOnly()).isTrue();\n\t\tassertThat(sessionCookieConfig.isSecure()).isTrue();\n\t\tassertThat(sessionCookieConfig.getMaxAge()).isEqualTo(60);\n\t\tassertThat(sessionCookieConfig.getAttribute(\"Partitioned\")).isEqualTo(\"false\");\n\t}\n\n\t@Test\n\tprotected void servletContextListenerContextDestroyedIsNotCalledWhenContainerIsStopped() throws Exception {\n\t\tServletContextListener listener = mock(ServletContextListener.class);\n\t\tthis.webServer = getFactory().getWebServer((servletContext) -> servletContext.addListener(listener));\n\t\tthis.webServer.start();\n\t\tthis.webServer.stop();\n\t\tthen(listener).should(never()).contextDestroyed(any(ServletContextEvent.class));\n\t}\n\n\t@Test\n\tvoid servletContextListenerContextDestroyedIsCalledWhenContainerIsDestroyed() throws Exception {\n\t\tServletContextListener listener = mock(ServletContextListener.class);\n\t\tthis.webServer = getFactory().getWebServer((servletContext) -> servletContext.addListener(listener));\n\t\tthis.webServer.start();\n\t\tthis.webServer.destroy();\n\t\tthen(listener).should().contextDestroyed(any(ServletContextEvent.class));\n\t}\n\n\t@Test\n\tvoid exceptionThrownOnLoadFailureIsRethrown() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory\n\t\t\t.getWebServer((context) -> context.addServlet(\"failing\", FailingServlet.class).setLoadOnStartup(0));\n\t\tassertThatExceptionOfType(WebServerException.class).isThrownBy(this.webServer::start)\n\t\t\t.satisfies(this::wrapsFailingServletException);\n\t}\n\n\t@Test\n\tvoid whenThereAreNoInFlightRequestsShutDownGracefullyInvokesCallbackWithIdle() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> GracefulShutdownResult.IDLE == result.get());\n\t}\n\n\t@Test\n\tvoid whenARequestRemainsInFlightThenShutDownGracefullyDoesNotInvokeCallbackUntilTheRequestCompletes()\n\t\t\tthrows Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingServlet);\n\t\t\tregistration.addMapping(\"/blocking\");\n\t\t});\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tFuture<Object> request = initiateGetRequest(port, \"/blocking\");\n\t\tblockingServlet.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tblockingServlet.admitOne();\n\t\tassertThat(request.get()).isInstanceOf(HttpResponse.class);\n\t\tAwaitility.await().atMost(Duration.ofSeconds(30)).until(() -> GracefulShutdownResult.IDLE == result.get());\n\t}\n\n\t@Test\n\tvoid whenAnAsyncRequestRemainsInFlightThenShutDownGracefullyDoesNotInvokeCallbackUntilRequestCompletes()\n\t\t\tthrows Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingAsyncServlet blockingAsyncServlet = new BlockingAsyncServlet();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tDynamic registration = context.addServlet(\"blockingServlet\", blockingAsyncServlet);\n\t\t\tregistration.addMapping(\"/blockingAsync\");\n\t\t\tregistration.setAsyncSupported(true);\n\t\t});\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tFuture<Object> request = initiateGetRequest(port, \"/blockingAsync\");\n\t\tblockingAsyncServlet.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tThread.sleep(5000);\n\t\tassertThat(result.get()).isNull();\n\t\tassertThat(request.isDone()).isFalse();\n\t\tblockingAsyncServlet.admitOne();\n\t\tassertThat(request.get()).isInstanceOf(HttpResponse.class);\n\t\tAwaitility.await().atMost(Duration.ofSeconds(5)).until(() -> GracefulShutdownResult.IDLE == result.get());\n\t}\n\n\t@Test\n\tvoid whenARequestIsActiveThenStopWillComplete() throws InterruptedException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory\n\t\t\t.getWebServer((context) -> context.addServlet(\"blockingServlet\", blockingServlet).addMapping(\"/\"));\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tinitiateGetRequest(port, \"/\");\n\t\tblockingServlet.awaitQueue();\n\t\tthis.webServer.stop();\n\t\ttry {\n\t\t\tblockingServlet.admitOne();\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t@Test\n\tprotected void whenHttp2IsEnabledAndSslIsDisabledThenH2cCanBeUsed() throws Exception {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tHttp2 http2 = new Http2();\n\t\thttp2.setEnabled(true);\n\t\tfactory.setHttp2(http2);\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\ttry (org.eclipse.jetty.client.HttpClient client = new org.eclipse.jetty.client.HttpClient(\n\t\t\t\tnew HttpClientTransportOverHTTP2(new HTTP2Client()))) {\n\t\t\tclient.start();\n\t\t\tContentResponse response = client.GET(\"http://localhost:\" + this.webServer.getPort() + \"/hello\");\n\t\t\tassertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());\n\t\t\tassertThat(response.getContentAsString()).isEqualTo(\"Hello World\");\n\t\t}\n\t}\n\n\t@Test\n\tprotected void whenHttp2IsEnabledAndSslIsDisabledThenHttp11CanStillBeUsed() throws IOException, URISyntaxException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tHttp2 http2 = new Http2();\n\t\thttp2.setEnabled(true);\n\t\tfactory.setHttp2(http2);\n\t\tthis.webServer = factory.getWebServer(exampleServletRegistration());\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(\"http://localhost:\" + this.webServer.getPort() + \"/hello\")).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid whenARequestIsActiveAfterGracefulShutdownEndsThenStopWillComplete() throws InterruptedException {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setShutdown(Shutdown.GRACEFUL);\n\t\tBlockingServlet blockingServlet = new BlockingServlet();\n\t\tthis.webServer = factory\n\t\t\t.getWebServer((context) -> context.addServlet(\"blockingServlet\", blockingServlet).addMapping(\"/\"));\n\t\tthis.webServer.start();\n\t\tint port = this.webServer.getPort();\n\t\tinitiateGetRequest(port, \"/\");\n\t\tblockingServlet.awaitQueue();\n\t\tAtomicReference<GracefulShutdownResult> result = new AtomicReference<>();\n\t\tthis.webServer.shutDownGracefully(result::set);\n\t\tthis.webServer.stop();\n\t\tassertThat(Awaitility.await().atMost(Duration.ofSeconds(30)).until(result::get, Objects::nonNull))\n\t\t\t.isEqualTo(GracefulShutdownResult.REQUESTS_ACTIVE);\n\t\ttry {\n\t\t\tblockingServlet.admitOne();\n\t\t}\n\t\tcatch (RuntimeException ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t@Test\n\tvoid startedLogMessageWithSinglePort() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tassertThat(startedLogMessage()).matches(\"(Jetty|Tomcat) started on port \" + this.webServer.getPort()\n\t\t\t\t+ \" \\\\(http(/1.1)?\\\\) with context path '/'\");\n\t}\n\n\t@Test\n\tvoid startedLogMessageWithSinglePortAndContextPath() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tfactory.setContextPath(\"/test\");\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tassertThat(startedLogMessage()).matches(\"(Jetty|Tomcat) started on port \" + this.webServer.getPort()\n\t\t\t\t+ \" \\\\(http(/1.1)?\\\\) with context path '/test'\");\n\t}\n\n\t@Test\n\tvoid startedLogMessageWithMultiplePorts() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\taddConnector(0, factory);\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\tassertThat(startedLogMessage()).matches(\"(Jetty|Tomcat) started on ports \" + this.webServer.getPort()\n\t\t\t\t+ \" \\\\(http(/1.1)?\\\\), [0-9]+ \\\\(http(/1.1)?\\\\) with context path '/'\");\n\t}\n\n\t@Test\n\tvoid servletComponentsAreInitializedWithTheSameThreadContextClassLoader() {\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tThreadContextClassLoaderCapturingServlet servlet = new ThreadContextClassLoaderCapturingServlet();\n\t\tThreadContextClassLoaderCapturingFilter filter = new ThreadContextClassLoaderCapturingFilter();\n\t\tThreadContextClassLoaderCapturingListener listener = new ThreadContextClassLoaderCapturingListener();\n\t\tthis.webServer = factory.getWebServer((context) -> {\n\t\t\tcontext.addServlet(\"tcclCapturingServlet\", servlet).setLoadOnStartup(0);\n\t\t\tcontext.addFilter(\"tcclCapturingFilter\", filter);\n\t\t\tcontext.addListener(listener);\n\t\t});\n\t\tthis.webServer.start();\n\t\tassertThat(servlet.contextClassLoader).isNotNull();\n\t\tassertThat(filter.contextClassLoader).isNotNull();\n\t\tassertThat(listener.contextClassLoader).isNotNull();\n\t\tassertThat(new HashSet<>(\n\t\t\t\tArrays.asList(servlet.contextClassLoader, filter.contextClassLoader, listener.contextClassLoader)))\n\t\t\t.hasSize(1);\n\t}\n\n\tprotected Future<Object> initiateGetRequest(int port, String path) {\n\t\treturn initiateGetRequest(HttpClients.createMinimal(), port, path);\n\t}\n\n\tprotected Future<Object> initiateGetRequest(HttpClient httpClient, int port, String path) {\n\t\tRunnableFuture<Object> getRequest = new FutureTask<>(() -> {\n\t\t\ttry {\n\t\t\t\treturn httpClient.execute(new HttpGet(\"http://localhost:\" + port + path),\n\t\t\t\t\t\t(HttpClientResponseHandler<HttpResponse>) (response) -> {\n\t\t\t\t\t\t\tresponse.getEntity().getContent().close();\n\t\t\t\t\t\t\treturn response;\n\t\t\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn ex;\n\t\t\t}\n\t\t});\n\t\tnew Thread(getRequest, \"GET \" + path).start();\n\t\treturn getRequest;\n\t}\n\n\tprivate void wrapsFailingServletException(WebServerException ex) {\n\t\tThrowable cause = ex.getCause();\n\t\twhile (cause != null) {\n\t\t\tif (cause instanceof FailingServletException) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcause = cause.getCause();\n\t\t}\n\t\tfail(\"Exception did not wrap FailingServletException\");\n\t}\n\n\tprotected abstract void addConnector(int port, ConfigurableServletWebServerFactory factory);\n\n\tprotected abstract void handleExceptionCausedByBlockedPortOnPrimaryConnector(RuntimeException ex, int blockedPort);\n\n\tprotected abstract void handleExceptionCausedByBlockedPortOnSecondaryConnector(RuntimeException ex,\n\t\t\tint blockedPort);\n\n\tprivate boolean doTestCompression(int contentSize, String[] mimeTypes, String[] excludedUserAgents)\n\t\t\tthrows Exception {\n\t\treturn doTestCompression(contentSize, mimeTypes, excludedUserAgents, HttpMethod.GET);\n\t}\n\n\tprivate boolean doTestCompression(int contentSize, String[] mimeTypes, String[] excludedUserAgents,\n\t\t\tHttpMethod method) throws Exception {\n\t\tString testContent = setUpFactoryForCompression(contentSize, mimeTypes, excludedUserAgents);\n\t\tTestGzipInputStreamFactory inputStreamFactory = new TestGzipInputStreamFactory();\n\t\tLinkedHashMap<String, InputStreamFactory> contentDecoderMap = new LinkedHashMap<>();\n\t\tcontentDecoderMap.put(\"gzip\", inputStreamFactory);\n\t\tString response = getResponse(getLocalUrl(\"/test.txt\"), method,\n\t\t\t\tnew HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create()\n\t\t\t\t\t.setUserAgent(\"testUserAgent\")\n\t\t\t\t\t.setContentDecoderRegistry(contentDecoderMap)\n\t\t\t\t\t.build()));\n\t\tassertThat(response).isEqualTo(testContent);\n\t\treturn inputStreamFactory.wasCompressionUsed();\n\t}\n\n\tprivate String setUpFactoryForCompression(int contentSize, String[] mimeTypes, String[] excludedUserAgents) {\n\t\tchar[] chars = new char[contentSize];\n\t\tArrays.fill(chars, 'F');\n\t\tString testContent = new String(chars);\n\t\tConfigurableServletWebServerFactory factory = getFactory();\n\t\tCompression compression = new Compression();\n\t\tcompression.setEnabled(true);\n\t\tif (mimeTypes != null) {\n\t\t\tcompression.setMimeTypes(mimeTypes);\n\t\t}\n\t\tif (excludedUserAgents != null) {\n\t\t\tcompression.setExcludedUserAgents(excludedUserAgents);\n\t\t}\n\t\tfactory.setCompression(compression);\n\t\tfactory.addInitializers(new ServletRegistrationBean<>(new HttpServlet() {\n\n\t\t\t@Override\n\t\t\tprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {\n\t\t\t\tresp.setContentType(\"text/plain\");\n\t\t\t\tresp.setContentLength(testContent.length());\n\t\t\t\tresp.getWriter().write(testContent);\n\t\t\t\tresp.getWriter().flush();\n\t\t\t}\n\n\t\t}, \"/test.txt\"));\n\t\tthis.webServer = factory.getWebServer();\n\t\tthis.webServer.start();\n\t\treturn testContent;\n\t}\n\n\tprotected abstract Map<String, String> getActualMimeMappings();\n\n\tprotected abstract @Nullable Charset getCharset(Locale locale);\n\n\tprotected void addTestTxtFile(ConfigurableServletWebServerFactory factory) throws IOException {\n\t\tFileCopyUtils.copy(\"test\", new FileWriter(new File(this.tempDir, \"test.txt\")));\n\t\tfactory.setDocumentRoot(this.tempDir);\n\t\tfactory.setRegisterDefaultServlet(true);\n\t}\n\n\tprotected String getLocalUrl(String resourcePath) {\n\t\treturn getLocalUrl(\"http\", resourcePath);\n\t}\n\n\tprotected String getLocalUrl(String scheme, String resourcePath) {\n\t\treturn scheme + \"://localhost:\" + this.webServer.getPort() + resourcePath;\n\t}\n\n\tprotected String getLocalUrl(int port, String resourcePath) {\n\t\treturn \"http://localhost:\" + port + resourcePath;\n\t}\n\n\tprotected String getResponse(String url, String... headers) throws IOException, URISyntaxException {\n\t\treturn getResponse(url, HttpMethod.GET, headers);\n\t}\n\n\tprotected String getResponse(String url, HttpMethod method, String... headers)\n\t\t\tthrows IOException, URISyntaxException {\n\t\ttry (ClientHttpResponse response = getClientResponse(url, method, headers)) {\n\t\t\treturn StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);\n\t\t}\n\t}\n\n\tprotected String getResponse(String url, HttpComponentsClientHttpRequestFactory requestFactory, String... headers)\n\t\t\tthrows IOException, URISyntaxException {\n\t\treturn getResponse(url, HttpMethod.GET, requestFactory, headers);\n\t}\n\n\tprotected String getResponse(String url, HttpMethod method, HttpComponentsClientHttpRequestFactory requestFactory,\n\t\t\tString... headers) throws IOException, URISyntaxException {\n\t\ttry (ClientHttpResponse response = getClientResponse(url, method, requestFactory, headers)) {\n\t\t\treturn StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);\n\t\t}\n\t}\n\n\tprotected ClientHttpResponse getClientResponse(String url, String... headers)\n\t\t\tthrows IOException, URISyntaxException {\n\t\treturn getClientResponse(url, HttpMethod.GET, headers);\n\t}\n\n\tprotected ClientHttpResponse getClientResponse(String url, HttpMethod method, String... headers)\n\t\t\tthrows IOException, URISyntaxException {\n\t\treturn getClientResponse(url, method,\n\t\t\t\tnew HttpComponentsClientHttpRequestFactory(this.httpClientBuilder.get().build()) {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tprotected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {\n\t\t\t\t\t\treturn AbstractServletWebServerFactoryTests.this.httpClientContext;\n\t\t\t\t\t}\n\n\t\t\t\t}, headers);\n\t}\n\n\tprotected ClientHttpResponse getClientResponse(String url, HttpMethod method,\n\t\t\tHttpComponentsClientHttpRequestFactory requestFactory, String... headers)\n\t\t\tthrows IOException, URISyntaxException {\n\t\tClientHttpRequest request = requestFactory.createRequest(new URI(url), method);\n\t\tfor (String header : headers) {\n\t\t\tString[] parts = header.split(\":\");\n\t\t\trequest.getHeaders().add(parts[0], parts[1]);\n\t\t}\n\t\treturn request.execute();\n\t}\n\n\tprotected void assertForwardHeaderIsUsed(ServletWebServerFactory factory) throws IOException, URISyntaxException {\n\t\tthis.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), \"/hello\"));\n\t\tthis.webServer.start();\n\t\tassertThat(getResponse(getLocalUrl(\"/hello\"), \"X-Forwarded-For:140.211.11.130\"))\n\t\t\t.contains(\"remoteaddr=140.211.11.130\");\n\t}\n\n\tprotected abstract ConfigurableServletWebServerFactory getFactory();\n\n\tprotected abstract org.apache.jasper.servlet.@Nullable JspServlet getJspServlet() throws Exception;\n\n\tprotected ServletContextInitializer exampleServletRegistration() {\n\t\treturn new ServletRegistrationBean<>(new ExampleServlet(), \"/hello\");\n\t}\n\n\t@SuppressWarnings(\"serial\")\n\tprivate ServletContextInitializer errorServletRegistration() {\n\t\tServletRegistrationBean<ExampleServlet> bean = new ServletRegistrationBean<>(new ExampleServlet() {\n\n\t\t\t@Override\n\t\t\tpublic void service(ServletRequest request, ServletResponse response) {\n\t\t\t\tthrow new RuntimeException(\"Planned\");\n\t\t\t}\n\n\t\t}, \"/bang\");\n\t\tbean.setName(\"error\");\n\t\treturn bean;\n\t}\n\n\tprotected final ServletContextInitializer sessionServletRegistration() {\n\t\tServletRegistrationBean<ExampleServlet> bean = new ServletRegistrationBean<>(new ExampleServlet() {\n\n\t\t\t@Override\n\t\t\tpublic void service(ServletRequest request, ServletResponse response) throws IOException {\n\t\t\t\tHttpSession session = ((HttpServletRequest) request).getSession(true);\n\t\t\t\tlong value = System.currentTimeMillis();\n\t\t\t\tObject existing = session.getAttribute(\"boot\");\n\t\t\t\tsession.setAttribute(\"boot\", value);\n\t\t\t\tPrintWriter writer = response.getWriter();\n\t\t\t\twriter.append(String.valueOf(existing)).append(\":\").append(String.valueOf(value));\n\t\t\t}\n\n\t\t}, \"/session\");\n\t\tbean.setName(\"session\");\n\t\treturn bean;\n\t}\n\n\tprivate <T> T doWithRetry(Callable<T> action) throws Exception {\n\t\tException lastFailure = null;\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\ttry {\n\t\t\t\treturn action.call();\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlastFailure = ex;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Action was not successful in 10 attempts\", lastFailure);\n\t}\n\n\tprotected final void doWithBlockedPort(BlockedPortAction action) throws Exception {\n\t\tServerSocket serverSocket = new ServerSocket();\n\t\ttry (serverSocket) {\n\t\t\tint blockedPort = doWithRetry(() -> {\n\t\t\t\tserverSocket.bind(null);\n\t\t\t\treturn serverSocket.getLocalPort();\n\t\t\t});\n\t\t\taction.run(blockedPort);\n\t\t}\n\t}\n\n\tprivate void loadStore(KeyStore keyStore, Resource resource)\n\t\t\tthrows IOException, NoSuchAlgorithmException, CertificateException {\n\t\ttry (InputStream stream = resource.getInputStream()) {\n\t\t\tkeyStore.load(stream, \"secret\".toCharArray());\n\t\t}\n\t}\n\n\tprotected abstract String startedLogMessage();\n\n\tprotected TlsSocketStrategy createTrustSelfSignedTlsSocketStrategy()\n\t\t\tthrows NoSuchAlgorithmException, KeyStoreException, KeyManagementException {\n\t\tSSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();\n\t\treturn new DefaultClientTlsStrategy(sslContext);\n\t}\n\n\tprivate final class TestGzipInputStreamFactory implements InputStreamFactory {\n\n\t\tprivate final AtomicBoolean requested = new AtomicBoolean();\n\n\t\t@Override\n\t\tpublic InputStream create(InputStream in) throws IOException {\n\t\t\tif (this.requested.get()) {\n\t\t\t\tthrow new IllegalStateException(\"On deflated InputStream already requested\");\n\t\t\t}\n\t\t\tthis.requested.set(true);\n\t\t\treturn new GZIPInputStream(in);\n\t\t}\n\n\t\tboolean wasCompressionUsed() {\n\t\t\treturn this.requested.get();\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"serial\")\n\tstatic class InitCountingServlet extends GenericServlet {\n\n\t\tprivate int initCount;\n\n\t\t@Override\n\t\tpublic void init() {\n\t\t\tthis.initCount++;\n\t\t}\n\n\t\t@Override\n\t\tpublic void service(ServletRequest req, ServletResponse res) {\n\t\t}\n\n\t\tint getInitCount() {\n\t\t\treturn this.initCount;\n\t\t}\n\n\t}\n\n\tinterface BlockedPortAction {\n\n\t\tvoid run(int port);\n\n\t}\n\n\t/**\n\t * {@link TrustSelfSignedStrategy} that also validates certificate serial number.\n\t */\n\tprivate static final class SerialNumberValidatingTrustSelfSignedStrategy extends TrustSelfSignedStrategy {\n\n\t\tprivate final String serialNumber;\n\n\t\tprivate SerialNumberValidatingTrustSelfSignedStrategy(String serialNumber) {\n\t\t\tthis.serialNumber = serialNumber;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isTrusted(X509Certificate[] chain, String authType) {\n\t\t\tString hexSerialNumber = chain[0].getSerialNumber().toString(16);\n\t\t\tboolean isMatch = hexSerialNumber.equalsIgnoreCase(this.serialNumber);\n\t\t\treturn super.isTrusted(chain, authType) && isMatch;\n\t\t}\n\n\t}\n\n\tpublic static class FailingServlet extends HttpServlet {\n\n\t\t@Override\n\t\tpublic void init() throws ServletException {\n\t\t\tthrow new FailingServletException();\n\t\t}\n\n\t}\n\n\tpublic static class FailingServletContextListener implements ServletContextListener {\n\n\t\t@Override\n\t\tpublic void contextInitialized(ServletContextEvent sce) {\n\t\t\tthrow new FailingServletException();\n\t\t}\n\n\t}\n\n\tstatic class FailingServletException extends RuntimeException {\n\n\t\tFailingServletException() {\n\t\t\tsuper(\"Init Failure\");\n\t\t}\n\n\t}\n\n\tprotected static class BlockingServlet extends HttpServlet {\n\n\t\tprivate final BlockingQueue<Blocker> blockers = new ArrayBlockingQueue<>(10);\n\n\t\tpublic BlockingServlet() {\n\n\t\t}\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t\tBlocker blocker = new Blocker();\n\t\t\tthis.blockers.add(blocker);\n\t\t\tblocker.await();\n\t\t}\n\n\t\tpublic void admitOne() throws InterruptedException {\n\t\t\tthis.blockers.take().clear();\n\t\t}\n\n\t\tpublic void awaitQueue() throws InterruptedException {\n\t\t\twhile (this.blockers.isEmpty()) {\n\t\t\t\tThread.sleep(100);\n\t\t\t}\n\t\t}\n\n\t\tpublic void awaitQueue(int size) throws InterruptedException {\n\t\t\twhile (this.blockers.size() < size) {\n\t\t\t\tThread.sleep(100);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic class BlockingAsyncServlet extends HttpServlet {\n\n\t\tprivate final BlockingQueue<Blocker> blockers = new ArrayBlockingQueue<>(10);\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t\tBlocker blocker = new Blocker();\n\t\t\tthis.blockers.add(blocker);\n\t\t\tAsyncContext async = req.startAsync();\n\t\t\tnew Thread(() -> {\n\t\t\t\tblocker.await();\n\t\t\t\tasync.complete();\n\t\t\t}).start();\n\t\t}\n\n\t\tprivate void admitOne() throws InterruptedException {\n\t\t\tthis.blockers.take().clear();\n\t\t}\n\n\t\tprivate void awaitQueue() throws InterruptedException {\n\t\t\twhile (this.blockers.isEmpty()) {\n\t\t\t\tThread.sleep(100);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate static final class Blocker {\n\n\t\tprivate boolean block = true;\n\n\t\tprivate final Object monitor = new Object();\n\n\t\tprivate void await() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\twhile (this.block) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.monitor.wait();\n\t\t\t\t\t}\n\t\t\t\t\tcatch (InterruptedException ex) {\n\t\t\t\t\t\tSystem.out.println(\"Interrupted!\");\n\t\t\t\t\t\t// Keep waiting\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void clear() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.block = false;\n\t\t\t\tthis.monitor.notifyAll();\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic final class CookieServlet extends HttpServlet {\n\n\t\tprivate final boolean addSupplierTestCookies;\n\n\t\tCookieServlet(boolean addSupplierTestCookies) {\n\t\t\tthis.addSupplierTestCookies = addSupplierTestCookies;\n\t\t}\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n\t\t\treq.getSession(true);\n\t\t\tresp.addCookie(new Cookie(\"test\", \"test\"));\n\t\t\tif (this.addSupplierTestCookies) {\n\t\t\t\tresp.addCookie(new Cookie(\"relaxed\", \"test\"));\n\t\t\t\tresp.addCookie(new Cookie(\"empty\", \"test\"));\n\t\t\t\tresp.addCookie(new Cookie(\"controlled\", \"test\"));\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprotected static class TrustSelfSignedStrategy implements TrustStrategy {\n\n\t\tpublic TrustSelfSignedStrategy() {\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isTrusted(X509Certificate[] chain, String authType) {\n\t\t\treturn chain.length == 1;\n\t\t}\n\n\t}\n\n\tstatic class ThreadContextClassLoaderCapturingServlet extends HttpServlet {\n\n\t\tprivate ClassLoader contextClassLoader;\n\n\t\t@Override\n\t\tpublic void init(ServletConfig config) throws ServletException {\n\t\t\tthis.contextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\t}\n\n\t}\n\n\tstatic class ThreadContextClassLoaderCapturingListener implements ServletContextListener {\n\n\t\tprivate ClassLoader contextClassLoader;\n\n\t\t@Override\n\t\tpublic void contextInitialized(ServletContextEvent sce) {\n\t\t\tthis.contextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\t}\n\n\t}\n\n\tstatic class ThreadContextClassLoaderCapturingFilter implements Filter {\n\n\t\tprivate ClassLoader contextClassLoader;\n\n\t\t@Override\n\t\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t\t\tthis.contextClassLoader = Thread.currentThread().getContextClassLoader();\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\t\tthrows IOException, ServletException {\n\t\t\tchain.doFilter(request, response);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/AbstractServletWebServerServletContextListenerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.ForkedClassPath;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.ServletListenerRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Base class for tests for {@link WebServer}s driving {@link ServletContextListener}s\n * correctly.\n *\n * @author Andy Wilkinson\n */\n@DirtiesUrlFactories\npublic abstract class AbstractServletWebServerServletContextListenerTests {\n\n\tprivate final Class<?> webServerConfiguration;\n\n\tprotected AbstractServletWebServerServletContextListenerTests(Class<?> webServerConfiguration) {\n\t\tthis.webServerConfiguration = webServerConfiguration;\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\tvoid registeredServletContextListenerBeanIsCalled() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tServletListenerRegistrationBeanConfiguration.class, this.webServerConfiguration);\n\t\tServletContextListener servletContextListener = (ServletContextListener) context\n\t\t\t.getBean(\"registration\", ServletListenerRegistrationBean.class)\n\t\t\t.getListener();\n\t\tthen(servletContextListener).should().contextInitialized(any(ServletContextEvent.class));\n\t\tcontext.close();\n\t}\n\n\t@Test\n\t@ForkedClassPath\n\tvoid servletContextListenerBeanIsCalled() {\n\t\tAnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(\n\t\t\t\tServletContextListenerBeanConfiguration.class, this.webServerConfiguration);\n\t\tServletContextListener servletContextListener = context.getBean(\"servletContextListener\",\n\t\t\t\tServletContextListener.class);\n\t\tthen(servletContextListener).should().contextInitialized(any(ServletContextEvent.class));\n\t\tcontext.close();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletContextListenerBeanConfiguration {\n\n\t\t@Bean\n\t\tServletContextListener servletContextListener() {\n\t\t\treturn mock(ServletContextListener.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletListenerRegistrationBeanConfiguration {\n\n\t\t@Bean\n\t\tServletListenerRegistrationBean<ServletContextListener> registration() {\n\t\t\treturn new ServletListenerRegistrationBean<>(mock(ServletContextListener.class));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/MockServletWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.StreamSupport;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterRegistration;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration;\nimport jakarta.servlet.SessionCookieConfig;\n\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerException;\nimport org.springframework.mock.web.MockSessionCookieConfig;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.lenient;\nimport static org.mockito.Mockito.mock;\n\n/**\n * A mock servlet {@link WebServer}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic class MockServletWebServer implements WebServer {\n\n\tprivate ServletContext servletContext;\n\n\tprivate final Initializer[] initializers;\n\n\tprivate final List<RegisteredServlet> registeredServlets = new ArrayList<>();\n\n\tprivate final List<RegisteredFilter> registeredFilters = new ArrayList<>();\n\n\tprivate final Map<String, FilterRegistration> filterRegistrations = new HashMap<>();\n\n\tprivate final Map<String, ServletRegistration> servletRegistrations = new HashMap<>();\n\n\tprivate final int port;\n\n\tMockServletWebServer(ServletContextInitializers initializers, int port) {\n\t\tthis(StreamSupport.stream(initializers.spliterator(), false)\n\t\t\t.map((initializer) -> (Initializer) initializer::onStartup)\n\t\t\t.toArray(Initializer[]::new), port);\n\t}\n\n\tMockServletWebServer(Initializer[] initializers, int port) {\n\t\tthis.initializers = initializers;\n\t\tthis.port = port;\n\t\tinitialize();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate void initialize() {\n\t\ttry {\n\t\t\tthis.servletContext = mock(ServletContext.class);\n\t\t\tlenient().doAnswer((invocation) -> {\n\t\t\t\tRegisteredServlet registeredServlet = new RegisteredServlet(invocation.getArgument(1));\n\t\t\t\tMockServletWebServer.this.registeredServlets.add(registeredServlet);\n\t\t\t\tthis.servletRegistrations.put(invocation.getArgument(0), registeredServlet.getRegistration());\n\t\t\t\treturn registeredServlet.getRegistration();\n\t\t\t}).when(this.servletContext).addServlet(anyString(), any(Servlet.class));\n\t\t\tlenient().doAnswer((invocation) -> {\n\t\t\t\tRegisteredFilter registeredFilter = new RegisteredFilter(invocation.getArgument(1));\n\t\t\t\tMockServletWebServer.this.registeredFilters.add(registeredFilter);\n\t\t\t\tthis.filterRegistrations.put(invocation.getArgument(0), registeredFilter.getRegistration());\n\t\t\t\treturn registeredFilter.getRegistration();\n\t\t\t}).when(this.servletContext).addFilter(anyString(), any(Filter.class));\n\t\t\tfinal SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig();\n\t\t\tgiven(this.servletContext.getSessionCookieConfig()).willReturn(sessionCookieConfig);\n\t\t\tfinal Map<String, String> initParameters = new HashMap<>();\n\t\t\tlenient().doAnswer((invocation) -> {\n\t\t\t\tinitParameters.put(invocation.getArgument(0), invocation.getArgument(1));\n\t\t\t\treturn null;\n\t\t\t}).when(this.servletContext).setInitParameter(anyString(), anyString());\n\t\t\tgiven(this.servletContext.getInitParameterNames())\n\t\t\t\t.willReturn(Collections.enumeration(initParameters.keySet()));\n\t\t\tlenient().doAnswer((invocation) -> initParameters.get(invocation.getArgument(0)))\n\t\t\t\t.when(this.servletContext)\n\t\t\t\t.getInitParameter(anyString());\n\t\t\tgiven(this.servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\t\tlenient().when((Map<String, FilterRegistration>) this.servletContext.getFilterRegistrations())\n\t\t\t\t.thenReturn(this.filterRegistrations);\n\t\t\tlenient().when((Map<String, ServletRegistration>) this.servletContext.getServletRegistrations())\n\t\t\t\t.thenReturn(this.servletRegistrations);\n\t\t\tfor (Initializer initializer : this.initializers) {\n\t\t\t\tinitializer.onStartup(this.servletContext);\n\t\t\t}\n\t\t}\n\t\tcatch (ServletException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void start() throws WebServerException {\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.servletContext = null;\n\t\tthis.registeredServlets.clear();\n\t\tthis.filterRegistrations.clear();\n\t\tthis.registeredFilters.clear();\n\t}\n\n\tpublic ServletContext getServletContext() {\n\t\treturn this.servletContext;\n\t}\n\n\tpublic Servlet[] getServlets() {\n\t\tServlet[] servlets = new Servlet[this.registeredServlets.size()];\n\t\tArrays.setAll(servlets, (i) -> this.registeredServlets.get(i).getServlet());\n\t\treturn servlets;\n\t}\n\n\tpublic RegisteredServlet getRegisteredServlet(int index) {\n\t\treturn getRegisteredServlets().get(index);\n\t}\n\n\tpublic List<RegisteredServlet> getRegisteredServlets() {\n\t\treturn this.registeredServlets;\n\t}\n\n\tpublic RegisteredFilter getRegisteredFilters(int index) {\n\t\treturn getRegisteredFilters().get(index);\n\t}\n\n\tpublic List<RegisteredFilter> getRegisteredFilters() {\n\t\treturn this.registeredFilters;\n\t}\n\n\t@Override\n\tpublic int getPort() {\n\t\treturn this.port;\n\t}\n\n\t/**\n\t * A registered servlet.\n\t */\n\tpublic static class RegisteredServlet {\n\n\t\tprivate final Servlet servlet;\n\n\t\tprivate final ServletRegistration.Dynamic registration;\n\n\t\tpublic RegisteredServlet(Servlet servlet) {\n\t\t\tthis.servlet = servlet;\n\t\t\tthis.registration = mock(ServletRegistration.Dynamic.class);\n\t\t}\n\n\t\tpublic ServletRegistration.Dynamic getRegistration() {\n\t\t\treturn this.registration;\n\t\t}\n\n\t\tpublic Servlet getServlet() {\n\t\t\treturn this.servlet;\n\t\t}\n\n\t}\n\n\t/**\n\t * A registered filter.\n\t */\n\tpublic static class RegisteredFilter {\n\n\t\tprivate final Filter filter;\n\n\t\tprivate final FilterRegistration.Dynamic registration;\n\n\t\tpublic RegisteredFilter(Filter filter) {\n\t\t\tthis.filter = filter;\n\t\t\tthis.registration = mock(FilterRegistration.Dynamic.class);\n\t\t}\n\n\t\tpublic FilterRegistration.Dynamic getRegistration() {\n\t\t\treturn this.registration;\n\t\t}\n\n\t\tpublic Filter getFilter() {\n\t\t\treturn this.filter;\n\t\t}\n\n\t}\n\n\t/**\n\t * Initializer (usually implement by adapting {@code ServletContextInitializer}).\n\t */\n\t@FunctionalInterface\n\tprotected interface Initializer {\n\n\t\tvoid onStartup(ServletContext context) throws ServletException;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/server/servlet/MockServletWebServerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.servlet;\n\nimport jakarta.servlet.ServletContext;\n\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.MockServletWebServer.RegisteredFilter;\nimport org.springframework.boot.web.server.servlet.MockServletWebServer.RegisteredServlet;\nimport org.springframework.boot.web.servlet.ServletContextInitializer;\n\nimport static org.mockito.Mockito.spy;\n\n/**\n * Mock {@link ServletWebServerFactory}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic class MockServletWebServerFactory extends AbstractConfigurableWebServerFactory\n\t\timplements ConfigurableServletWebServerFactory {\n\n\tprivate final ServletWebServerSettings settings = new ServletWebServerSettings();\n\n\tprivate MockServletWebServer webServer;\n\n\t@Override\n\tpublic WebServer getWebServer(ServletContextInitializer... initializers) {\n\t\tthis.webServer = spy(\n\t\t\t\tnew MockServletWebServer(ServletContextInitializers.from(this.settings, initializers), getPort()));\n\t\treturn this.webServer;\n\t}\n\n\tpublic MockServletWebServer getWebServer() {\n\t\treturn this.webServer;\n\t}\n\n\tpublic ServletContext getServletContext() {\n\t\treturn (getWebServer() != null) ? getWebServer().getServletContext() : null;\n\t}\n\n\tpublic RegisteredServlet getRegisteredServlet(int index) {\n\t\treturn (getWebServer() != null) ? getWebServer().getRegisteredServlet(index) : null;\n\t}\n\n\tpublic RegisteredFilter getRegisteredFilter(int index) {\n\t\treturn (getWebServer() != null) ? getWebServer().getRegisteredFilters(index) : null;\n\t}\n\n\t@Override\n\tpublic ServletWebServerSettings getSettings() {\n\t\treturn this.settings;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/java/org/springframework/boot/web/servlet/context/AbstractServletWebServerMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.servlet.context;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.PropertySource;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.client.ClientHttpRequest;\nimport org.springframework.http.client.ClientHttpResponse;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for integration testing of {@link ServletWebServerApplicationContext} and\n * {@link WebServer}s running Spring MVC.\n *\n * @author Phillip Webb\n * @author Ivan Sopov\n */\npublic abstract class AbstractServletWebServerMvcIntegrationTests {\n\n\tprivate AnnotationConfigServletWebServerApplicationContext context;\n\n\tprivate Class<?> webServerConfiguration;\n\n\tprotected AbstractServletWebServerMvcIntegrationTests(Class<?> webServerConfiguration) {\n\t\tthis.webServerConfiguration = webServerConfiguration;\n\t}\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\ttry {\n\t\t\tthis.context.close();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Ignore\n\t\t}\n\t}\n\n\t@Test\n\tvoid basicConfig() throws Exception {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(this.webServerConfiguration,\n\t\t\t\tConfig.class);\n\t\tdoTest(this.context, \"/hello\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"conf.properties\", content = \"context=/example\")\n\tvoid advancedConfig() throws Exception {\n\t\tthis.context = new AnnotationConfigServletWebServerApplicationContext(this.webServerConfiguration,\n\t\t\t\tAdvancedConfig.class);\n\t\tdoTest(this.context, \"/example/spring/hello\");\n\t}\n\n\tprivate void doTest(AnnotationConfigServletWebServerApplicationContext context, String resourcePath)\n\t\t\tthrows Exception {\n\t\tSimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();\n\t\tClientHttpRequest request = clientHttpRequestFactory.createRequest(\n\t\t\t\tnew URI(\"http://localhost:\" + context.getWebServer().getPort() + resourcePath), HttpMethod.GET);\n\t\ttry (ClientHttpResponse response = request.execute()) {\n\t\t\tassertThat(response.getBody()).hasContent(\"Hello World\");\n\t\t}\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class Config {\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t\t@Bean\n\t\tHelloWorldController helloWorldController() {\n\t\t\treturn new HelloWorldController();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\t@PropertySource(\"classpath:conf.properties\")\n\tstatic class AdvancedConfig {\n\n\t\tprivate final Environment env;\n\n\t\tAdvancedConfig(Environment env) {\n\t\t\tthis.env = env;\n\t\t}\n\n\t\t@Bean\n\t\tstatic WebServerFactoryCustomizerBeanPostProcessor webServerFactoryCustomizerBeanPostProcessor() {\n\t\t\treturn new WebServerFactoryCustomizerBeanPostProcessor();\n\t\t}\n\n\t\t@Bean\n\t\tWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> contextPathCustomizer() {\n\t\t\treturn (factory) -> {\n\t\t\t\tString contextPath = this.env.getProperty(\"context\");\n\t\t\t\tfactory.setContextPath(contextPath);\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<DispatcherServlet> dispatcherRegistration(DispatcherServlet dispatcherServlet) {\n\t\t\tServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet);\n\t\t\tregistration.addUrlMappings(\"/spring/*\");\n\t\t\treturn registration;\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\t// Can configure dispatcher servlet here as would usually do through\n\t\t\t// init-params\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t\t@Bean\n\t\tHelloWorldController helloWorldController() {\n\t\t\treturn new HelloWorldController();\n\t\t}\n\n\t}\n\n\t@Controller\n\tstatic class HelloWorldController {\n\n\t\t@RequestMapping(\"/hello\")\n\t\t@ResponseBody\n\t\tString sayHello() {\n\t\t\treturn \"Hello World\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/resources/org/springframework/boot/web/server/reactive/test-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/resources/org/springframework/boot/web/server/reactive/test-key.pem",
    "content": "Bag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nKey Attributes: <No Attributes>\n-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD8B1saBN8Y0ZjX\nQ/pvnv2hZa+cBBkFHVkgw+tdzgdcO5Kjv2rnRKd3Oh8Qwdxj3BC9GpicF4GOgkDG\nLrMrYbmV/xGUnNh3YpUwbv+U/pm3VnuSZCk4aYgNEWHrnEHyrge87+MqYqGuMIke\nA5z7GV44PeThfKQs2BLLL/ME+Pb/jN6IVlIHxdBT5TBQkqNGFU7swdZoQ5Viqv44\nUNdVqU5pP3UF/perbOm2CHCbeLiLRvmuvGuBbrbko2XUwBNH+UjmEQaRh/epoy8B\nD31vGY87ym/YOEdpIrqD8bwg7NWP/Fdsryqi8p+U8fcfw4xZjotA0Sv04BC7zXHg\nm1AyZoVzAgMBAAECggEAfEqiZqANaF+BqXQIb4Dw42ZTJzWsIyYYnPySOGZRoe5t\nQJ03uwtULYv34xtANe1DQgd6SMyc46ugBzzjtprQ3ET5Jhn99U6kdcjf+dpf85dO\nhOEppP0CkDNI39nleinSfh6uIOqYgt/D143/nqQhn8oCdSOzkbwT9KnWh1bC9T7I\nvFjGfElvt1/xl88qYgrWgYLgXaencNGgiv/4/M0FNhiHEGsVC7SCu6kapC/WIQpE\n5IdV+HR+tiLoGZhXlhqorY7QC4xKC4wwafVSiFxqDOQAuK+SMD4TCEv0Aop+c+SE\nYBigVTmgVeJkjK7IkTEhKkAEFmRF5/5w+bZD9FhTNQKBgQD+4fNG1ChSU8RdizZT\n5dPlDyAxpETSCEXFFVGtPPh2j93HDWn7XugNyjn5FylTH507QlabC+5wZqltdIjK\nGRB5MIinQ9/nR2fuwGc9s+0BiSEwNOUB1MWm7wWL/JUIiKq6sTi6sJIfsYg79zco\nqxl5WE94aoINx9Utq1cdWhwJTQKBgQD9IjPksd4Jprz8zMrGLzR8k1gqHyhv24qY\nEJ7jiHKKAP6xllTUYwh1IBSL6w2j5lfZPpIkb4Jlk2KUoX6fN81pWkBC/fTBUSIB\nEHM9bL51+yKEYUbGIy/gANuRbHXsWg3sjUsFTNPN4hGTFk3w2xChCyl/f5us8Lo8\nZ633SNdpvwKBgQCGyDU9XzNzVZihXtx7wS0sE7OSjKtX5cf/UCbA1V0OVUWR3SYO\nJ0HPCQFfF0BjFHSwwYPKuaR9C8zMdLNhK5/qdh/NU7czNi9fsZ7moh7SkRFbzJzN\nOxbKD9t/CzJEMQEXeF/nWTfsSpUgILqqZtAxuuFLbAcaAnJYlCKdAumQgQKBgQCK\nmqjJh68pn7gJwGUjoYNe1xtGbSsqHI9F9ovZ0MPO1v6e5M7sQJHH+Fnnxzv/y8e8\nd6tz8e73iX1IHymDKv35uuZHCGF1XOR+qrA/KQUc+vcKf21OXsP/JtkTRs1HLoRD\nS5aRf2DWcfvniyYARSNU2xTM8GWgi2ueWbMDHUp+ZwKBgA/swC+K+Jg5DEWm6Sau\ne6y+eC6S+SoXEKkI3wf7m9aKoZo0y+jh8Gas6gratlc181pSM8O3vZG0n19b493I\napCFomMLE56zEzvyzfpsNhFhk5MBMCn0LPyzX6MiynRlGyWIj0c99fbHI3pOMufP\nWgmVLTZ8uDcSW1MbdUCwFSk5\n-----END PRIVATE KEY-----\nBag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nsubject=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\nissuer=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\n-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/resources/org/springframework/boot/web/server/servlet/test-cert.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-web-server/src/testFixtures/resources/org/springframework/boot/web/server/servlet/test-key.pem",
    "content": "Bag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nKey Attributes: <No Attributes>\n-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD8B1saBN8Y0ZjX\nQ/pvnv2hZa+cBBkFHVkgw+tdzgdcO5Kjv2rnRKd3Oh8Qwdxj3BC9GpicF4GOgkDG\nLrMrYbmV/xGUnNh3YpUwbv+U/pm3VnuSZCk4aYgNEWHrnEHyrge87+MqYqGuMIke\nA5z7GV44PeThfKQs2BLLL/ME+Pb/jN6IVlIHxdBT5TBQkqNGFU7swdZoQ5Viqv44\nUNdVqU5pP3UF/perbOm2CHCbeLiLRvmuvGuBbrbko2XUwBNH+UjmEQaRh/epoy8B\nD31vGY87ym/YOEdpIrqD8bwg7NWP/Fdsryqi8p+U8fcfw4xZjotA0Sv04BC7zXHg\nm1AyZoVzAgMBAAECggEAfEqiZqANaF+BqXQIb4Dw42ZTJzWsIyYYnPySOGZRoe5t\nQJ03uwtULYv34xtANe1DQgd6SMyc46ugBzzjtprQ3ET5Jhn99U6kdcjf+dpf85dO\nhOEppP0CkDNI39nleinSfh6uIOqYgt/D143/nqQhn8oCdSOzkbwT9KnWh1bC9T7I\nvFjGfElvt1/xl88qYgrWgYLgXaencNGgiv/4/M0FNhiHEGsVC7SCu6kapC/WIQpE\n5IdV+HR+tiLoGZhXlhqorY7QC4xKC4wwafVSiFxqDOQAuK+SMD4TCEv0Aop+c+SE\nYBigVTmgVeJkjK7IkTEhKkAEFmRF5/5w+bZD9FhTNQKBgQD+4fNG1ChSU8RdizZT\n5dPlDyAxpETSCEXFFVGtPPh2j93HDWn7XugNyjn5FylTH507QlabC+5wZqltdIjK\nGRB5MIinQ9/nR2fuwGc9s+0BiSEwNOUB1MWm7wWL/JUIiKq6sTi6sJIfsYg79zco\nqxl5WE94aoINx9Utq1cdWhwJTQKBgQD9IjPksd4Jprz8zMrGLzR8k1gqHyhv24qY\nEJ7jiHKKAP6xllTUYwh1IBSL6w2j5lfZPpIkb4Jlk2KUoX6fN81pWkBC/fTBUSIB\nEHM9bL51+yKEYUbGIy/gANuRbHXsWg3sjUsFTNPN4hGTFk3w2xChCyl/f5us8Lo8\nZ633SNdpvwKBgQCGyDU9XzNzVZihXtx7wS0sE7OSjKtX5cf/UCbA1V0OVUWR3SYO\nJ0HPCQFfF0BjFHSwwYPKuaR9C8zMdLNhK5/qdh/NU7czNi9fsZ7moh7SkRFbzJzN\nOxbKD9t/CzJEMQEXeF/nWTfsSpUgILqqZtAxuuFLbAcaAnJYlCKdAumQgQKBgQCK\nmqjJh68pn7gJwGUjoYNe1xtGbSsqHI9F9ovZ0MPO1v6e5M7sQJHH+Fnnxzv/y8e8\nd6tz8e73iX1IHymDKv35uuZHCGF1XOR+qrA/KQUc+vcKf21OXsP/JtkTRs1HLoRD\nS5aRf2DWcfvniyYARSNU2xTM8GWgi2ueWbMDHUp+ZwKBgA/swC+K+Jg5DEWm6Sau\ne6y+eC6S+SoXEKkI3wf7m9aKoZo0y+jh8Gas6gratlc181pSM8O3vZG0n19b493I\napCFomMLE56zEzvyzfpsNhFhk5MBMCn0LPyzX6MiynRlGyWIj0c99fbHI3pOMufP\nWgmVLTZ8uDcSW1MbdUCwFSk5\n-----END PRIVATE KEY-----\nBag Attributes\n    friendlyName: test-alias\n    localKeyID: 54 69 6D 65 20 31 36 38 33 32 38 36 31 31 34 30 37 31 \nsubject=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\nissuer=C = US, ST = California, L = Palo Alto, O = VMware, OU = Spring, CN = localhost\n-----BEGIN CERTIFICATE-----\nMIIDqzCCApOgAwIBAgIIFMqbpqvipw0wDQYJKoZIhvcNAQELBQAwbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDAgFw0yMzA1MDUxMTI2NThaGA8yMTIzMDQxMTExMjY1OFowbDELMAkGA1UE\nBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEP\nMA0GA1UEChMGVk13YXJlMQ8wDQYDVQQLEwZTcHJpbmcxEjAQBgNVBAMTCWxvY2Fs\naG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwHWxoE3xjRmNdD\n+m+e/aFlr5wEGQUdWSDD613OB1w7kqO/audEp3c6HxDB3GPcEL0amJwXgY6CQMYu\nsythuZX/EZSc2HdilTBu/5T+mbdWe5JkKThpiA0RYeucQfKuB7zv4ypioa4wiR4D\nnPsZXjg95OF8pCzYEssv8wT49v+M3ohWUgfF0FPlMFCSo0YVTuzB1mhDlWKq/jhQ\n11WpTmk/dQX+l6ts6bYIcJt4uItG+a68a4FutuSjZdTAE0f5SOYRBpGH96mjLwEP\nfW8ZjzvKb9g4R2kiuoPxvCDs1Y/8V2yvKqLyn5Tx9x/DjFmOi0DRK/TgELvNceCb\nUDJmhXMCAwEAAaNPME0wHQYDVR0OBBYEFMBIGU1nwix5RS3O5hGLLoMdR1+NMCwG\nA1UdEQQlMCOCCWxvY2FsaG9zdIcQAAAAAAAAAAAAAAAAAAAAAYcEfwAAATANBgkq\nhkiG9w0BAQsFAAOCAQEAhepfJgTFvqSccsT97XdAZfvB0noQx5NSynRV8NWmeOld\nhHP6Fzj6xCxHSYvlUfmX8fVP9EOAuChgcbbuTIVJBu60rnDT21oOOnp8FvNonCV6\ngJ89sCL7wZ77dw2RKIeUFjXXEV3QJhx2wCOVmLxnJspDoKFIEVjfLyiPXKxqe/6b\ndG8zzWDZ6z+M2JNCtVoOGpljpHqMPCmbDktncv6H3dDTZ83bmLj1nbpOU587gAJ8\nfl1PiUDyPRIl2cnOJd+wCHKsyym/FL7yzk0OSEZ81I92LpGd/0b2Ld3m/bpe+C4Z\nILzLXTnC6AhrLcDc9QN/EO+BiCL52n7EplNLtSn1LQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "module/spring-boot-web-server-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Web Server Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-web-server\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/AutoConfigureWebServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.web.server.test;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for starting and embedded\n * web server for tests. Commonly used with {@link SpringBootTest @SpringBootTest} when\n * {@code classes} are specified and the {@code webEnvironment} attribute is\n * {@code RANDOM_PORT} or {@code DEFINED_PORT}.\n *\n * @author Phillip Webb\n * @since 4.1.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJson\n@ImportAutoConfiguration\npublic @interface AutoConfigureWebServer {\n\n}\n"
  },
  {
    "path": "module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for embedded web servers tests.\n */\n@NullMarked\npackage org.springframework.boot.web.server.test;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot WebClient\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-http-client\"))\n\tapi(\"org.springframework:spring-webflux\")\n\n\timplementation(project(\":module:spring-boot-http-codec\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-reactor-netty\"))\n\toptional(\"org.apache.httpcomponents.client5:httpclient5\")\n\toptional(\"org.apache.httpcomponents.core5:httpcore5-reactive\")\n\toptional(\"org.eclipse.jetty:jetty-reactive-httpclient\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/WebClientCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient;\n\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * Callback interface that can be used to customize a\n * {@link org.springframework.web.reactive.function.client.WebClient.Builder\n * WebClient.Builder}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface WebClientCustomizer {\n\n\t/**\n\t * Callback to customize a\n\t * {@link org.springframework.web.reactive.function.client.WebClient.Builder\n\t * WebClient.Builder} instance.\n\t * @param webClientBuilder the client builder to customize\n\t */\n\tvoid customize(WebClient.Builder webClientBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/AutoConfiguredWebClientSsl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * An auto-configured {@link WebClientSsl} implementation.\n *\n * @author Phillip Webb\n */\nclass AutoConfiguredWebClientSsl implements WebClientSsl {\n\n\tprivate final ClientHttpConnectorBuilder<?> connectorBuilder;\n\n\tprivate final HttpClientSettings settings;\n\n\tprivate final SslBundles sslBundles;\n\n\tAutoConfiguredWebClientSsl(ClientHttpConnectorBuilder<?> connectorBuilder, HttpClientSettings settings,\n\t\t\tSslBundles sslBundles) {\n\t\tthis.connectorBuilder = connectorBuilder;\n\t\tthis.settings = settings;\n\t\tthis.sslBundles = sslBundles;\n\t}\n\n\t@Override\n\tpublic Consumer<WebClient.Builder> fromBundle(String bundleName) {\n\t\treturn fromBundle(this.sslBundles.getBundle(bundleName));\n\t}\n\n\t@Override\n\tpublic Consumer<WebClient.Builder> fromBundle(SslBundle bundle) {\n\t\treturn (builder) -> {\n\t\t\tHttpClientSettings settings = this.settings.withSslBundle(bundle);\n\t\t\tClientHttpConnector connector = this.connectorBuilder.build(settings);\n\t\t\tbuilder.clientConnector(connector);\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/WebClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Lazy;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link WebClient}.\n * <p>\n * This will produce a\n * {@link org.springframework.web.reactive.function.client.WebClient.Builder\n * WebClient.Builder} bean with the {@code prototype} scope, meaning each injection point\n * will receive a newly cloned instance of the builder.\n *\n * @author Brian Clozel\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = { ReactiveHttpClientAutoConfiguration.class, CodecsAutoConfiguration.class })\n@ConditionalOnClass(WebClient.class)\npublic final class WebClientAutoConfiguration {\n\n\t@Bean\n\t@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)\n\t@ConditionalOnMissingBean\n\tWebClient.Builder webClientBuilder(ObjectProvider<WebClientCustomizer> customizerProvider) {\n\t\tWebClient.Builder builder = WebClient.builder();\n\t\tcustomizerProvider.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder;\n\t}\n\n\t@Bean\n\t@Lazy\n\t@Order(0)\n\t@ConditionalOnBean(ClientHttpConnector.class)\n\tWebClientCustomizer webClientHttpConnectorCustomizer(ClientHttpConnector clientHttpConnector) {\n\t\treturn (builder) -> builder.clientConnector(clientHttpConnector);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(WebClientSsl.class)\n\t@ConditionalOnBean(SslBundles.class)\n\tAutoConfiguredWebClientSsl webClientSsl(ResourceLoader resourceLoader,\n\t\t\tObjectProvider<ClientHttpConnectorBuilder<?>> clientHttpConnectorBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings, SslBundles sslBundles) {\n\t\treturn new AutoConfiguredWebClientSsl(\n\t\t\t\tclientHttpConnectorBuilder\n\t\t\t\t\t.getIfAvailable(() -> ClientHttpConnectorBuilder.detect(resourceLoader.getClassLoader())),\n\t\t\t\thttpClientSettings.getIfAvailable(HttpClientSettings::defaults), sslBundles);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBean(CodecCustomizer.class)\n\tprotected static class WebClientCodecsConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\t@Order(0)\n\t\tWebClientCodecCustomizer exchangeStrategiesCustomizer(ObjectProvider<CodecCustomizer> codecCustomizers) {\n\t\t\treturn new WebClientCodecCustomizer(codecCustomizers.orderedStream().toList());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/WebClientCodecCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * {@link WebClientCustomizer} that configures codecs for the HTTP client.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class WebClientCodecCustomizer implements WebClientCustomizer {\n\n\tprivate final List<CodecCustomizer> codecCustomizers;\n\n\tpublic WebClientCodecCustomizer(List<CodecCustomizer> codecCustomizers) {\n\t\tthis.codecCustomizers = codecCustomizers;\n\t}\n\n\t@Override\n\tpublic void customize(WebClient.Builder webClientBuilder) {\n\t\twebClientBuilder\n\t\t\t.codecs((codecs) -> this.codecCustomizers.forEach((customizer) -> customizer.customize(codecs)));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/WebClientObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.boot.webclient.observation.ObservationWebClientCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.reactive.function.client.ClientRequestObservationConvention;\nimport org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * Configure the instrumentation of {@link WebClient}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tbeforeName = \"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\")\n@ConditionalOnClass({ WebClient.class, ObservationWebClientCustomizer.class, ObservationRegistry.class,\n\t\tObservationProperties.class })\n@EnableConfigurationProperties(ObservationProperties.class)\npublic final class WebClientObservationAutoConfiguration {\n\n\t@Bean\n\tObservationWebClientCustomizer observationWebClientCustomizer(ObservationRegistry observationRegistry,\n\t\t\tObjectProvider<ClientRequestObservationConvention> customConvention,\n\t\t\tObservationProperties observationProperties) {\n\t\tString name = observationProperties.getHttp().getClient().getRequests().getName();\n\t\tClientRequestObservationConvention observationConvention = customConvention\n\t\t\t.getIfAvailable(() -> new DefaultClientRequestObservationConvention(name));\n\t\treturn new ObservationWebClientCustomizer(observationRegistry, observationConvention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/WebClientSsl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * Interface that can be used to {@link WebClient.Builder#apply apply} SSL configuration\n * to a {@link org.springframework.web.reactive.function.client.WebClient.Builder\n * WebClient.Builder}.\n * <p>\n * Typically used as follows: <pre class=\"code\">\n * &#064;Bean\n * public MyBean myBean(WebClient.Builder webClientBuilder, WebClientSsl ssl) {\n *     WebClient webClient = webClientBuilder.apply(ssl.fromBundle(\"mybundle\")).build();\n *     return new MyBean(webClient);\n * }\n * </pre> NOTE: Apply SSL configuration will replace any previously\n * {@link WebClient.Builder#clientConnector configured} {@link ClientHttpConnector}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface WebClientSsl {\n\n\t/**\n\t * Return a {@link Consumer} that will apply SSL configuration for the named\n\t * {@link SslBundle} to a\n\t * {@link org.springframework.web.reactive.function.client.WebClient.Builder\n\t * WebClient.Builder}.\n\t * @param bundleName the name of the SSL bundle to apply\n\t * @return a {@link Consumer} to apply the configuration\n\t * @throws NoSuchSslBundleException if a bundle with the provided name does not exist\n\t */\n\tConsumer<WebClient.Builder> fromBundle(String bundleName) throws NoSuchSslBundleException;\n\n\t/**\n\t * Return a {@link Consumer} that will apply SSL configuration for the\n\t * {@link SslBundle} to a\n\t * {@link org.springframework.web.reactive.function.client.WebClient.Builder\n\t * WebClient.Builder}.\n\t * @param bundle the SSL bundle to apply\n\t * @return a {@link Consumer} to apply the configuration\n\t */\n\tConsumer<WebClient.Builder> fromBundle(SslBundle bundle);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Framework's functional web client.\n */\n@NullMarked\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/service/PropertiesWebClientHttpServiceGroupConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure.service;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.ApiversionProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientProperties;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientSettingsPropertyMapper;\nimport org.springframework.boot.http.client.autoconfigure.PropertiesApiVersionInserter;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer;\nimport org.springframework.web.service.registry.HttpServiceGroup;\n\n/**\n * A {@link WebClientHttpServiceGroupConfigurer} that configures the group and its\n * underlying {@link WebClient} using {@link HttpServiceClientProperties}.\n *\n * @author Olga Maciaszek-Sharma\n * @author Phillip Webb\n */\nclass PropertiesWebClientHttpServiceGroupConfigurer implements WebClientHttpServiceGroupConfigurer {\n\n\tprivate final HttpServiceClientProperties properties;\n\n\tprivate final HttpClientSettingsPropertyMapper clientSettingsPropertyMapper;\n\n\tprivate final ClientHttpConnectorBuilder<?> clientConnectorBuilder;\n\n\tPropertiesWebClientHttpServiceGroupConfigurer(@Nullable ClassLoader classLoader,\n\t\t\tHttpServiceClientProperties properties, @Nullable SslBundles sslBundles,\n\t\t\tObjectProvider<ClientHttpConnectorBuilder<?>> clientConnectorBuilder,\n\t\t\t@Nullable HttpClientSettings httpClientSettings) {\n\t\tthis.properties = properties;\n\t\tthis.clientSettingsPropertyMapper = new HttpClientSettingsPropertyMapper(sslBundles, httpClientSettings);\n\t\tthis.clientConnectorBuilder = clientConnectorBuilder\n\t\t\t.getIfAvailable(() -> ClientHttpConnectorBuilder.detect(classLoader));\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tpublic void configureGroups(Groups<WebClient.Builder> groups) {\n\t\tgroups.forEachClient(this::configureClient);\n\t}\n\n\tprivate void configureClient(HttpServiceGroup group, WebClient.Builder builder) {\n\t\tHttpClientProperties clientProperties = this.properties.get(group.name());\n\t\tHttpClientSettings clientSettings = this.clientSettingsPropertyMapper.map(clientProperties);\n\t\tbuilder.clientConnector(this.clientConnectorBuilder.build(clientSettings));\n\t\tif (clientProperties != null) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(clientProperties::getBaseUrl).whenHasText().to(builder::baseUrl);\n\t\t\tmap.from(clientProperties::getDefaultHeader).as(this::putAllHeaders).to(builder::defaultHeaders);\n\t\t\tmap.from(clientProperties::getApiversion)\n\t\t\t\t.as(ApiversionProperties::getDefaultVersion)\n\t\t\t\t.to(builder::defaultApiVersion);\n\t\t\tmap.from(clientProperties::getApiversion)\n\t\t\t\t.as(ApiversionProperties::getInsert)\n\t\t\t\t.as(PropertiesApiVersionInserter::get)\n\t\t\t\t.to(builder::apiVersionInserter);\n\t\t}\n\t}\n\n\tprivate Consumer<HttpHeaders> putAllHeaders(Map<String, List<String>> defaultHeaders) {\n\t\treturn (httpHeaders) -> httpHeaders.putAll(defaultHeaders);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/service/ReactiveHttpServiceClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure.service;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientProperties;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientPropertiesAutoConfiguration;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.support.WebClientAdapter;\nimport org.springframework.web.service.registry.HttpServiceProxyRegistry;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring reactive HTTP Service\n * Clients backed by {@link WebClient}.\n *\n * @author Olga Maciaszek-Sharma\n * @author Rossen Stoyanchev\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = { HttpServiceClientPropertiesAutoConfiguration.class,\n\t\tReactiveHttpClientAutoConfiguration.class, WebClientAutoConfiguration.class })\n@ConditionalOnClass(WebClientAdapter.class)\n@ConditionalOnBean(HttpServiceProxyRegistry.class)\npublic final class ReactiveHttpServiceClientAutoConfiguration {\n\n\t@Bean\n\tPropertiesWebClientHttpServiceGroupConfigurer webClientPropertiesHttpServiceGroupConfigurer(\n\t\t\tResourceLoader resourceLoader, HttpServiceClientProperties properties,\n\t\t\tObjectProvider<SslBundles> sslBundles, ObjectProvider<ClientHttpConnectorBuilder<?>> clientConnectorBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings) {\n\t\treturn new PropertiesWebClientHttpServiceGroupConfigurer(resourceLoader.getClassLoader(), properties,\n\t\t\t\tsslBundles.getIfAvailable(), clientConnectorBuilder, httpClientSettings.getIfAvailable());\n\t}\n\n\t@Bean\n\tWebClientCustomizerHttpServiceGroupConfigurer webClientCustomizerHttpServiceGroupConfigurer(\n\t\t\tObjectProvider<WebClientCustomizer> customizers) {\n\t\treturn new WebClientCustomizerHttpServiceGroupConfigurer(customizers);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/service/WebClientCustomizerHttpServiceGroupConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure.service;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer;\nimport org.springframework.web.service.registry.HttpServiceGroup;\n\n/**\n * A {@link WebClientHttpServiceGroupConfigurer} to apply auto-configured\n * {@link WebClientCustomizer} beans to the group's {@link WebClient}.\n *\n * @author Olga Maciaszek-Sharma\n * @author Phillip Webb\n */\nclass WebClientCustomizerHttpServiceGroupConfigurer implements WebClientHttpServiceGroupConfigurer {\n\n\t/**\n\t * Allow user defined configurers to apply before / after ours.\n\t */\n\tprivate static final int ORDER = 0;\n\n\tprivate final ObjectProvider<WebClientCustomizer> customizers;\n\n\tWebClientCustomizerHttpServiceGroupConfigurer(ObjectProvider<WebClientCustomizer> customizers) {\n\t\tthis.customizers = customizers;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn ORDER;\n\t}\n\n\t@Override\n\tpublic void configureGroups(Groups<WebClient.Builder> groups) {\n\t\tgroups.forEachClient(this::configureClient);\n\t}\n\n\tprivate void configureClient(HttpServiceGroup group, WebClient.Builder builder) {\n\t\tthis.customizers.orderedStream().forEach((customizer) -> customizer.customize(builder));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/autoconfigure/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-Configuration for Spring's Reactive HTTP Service Interface Clients.\n */\n@NullMarked\npackage org.springframework.boot.webclient.autoconfigure.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/observation/ObservationWebClientCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.web.reactive.function.client.ClientRequestObservationConvention;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * {@link WebClientCustomizer} that configures the {@link WebClient} to record request\n * observations.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\npublic class ObservationWebClientCustomizer implements WebClientCustomizer {\n\n\tprivate final ObservationRegistry observationRegistry;\n\n\tprivate final ClientRequestObservationConvention observationConvention;\n\n\t/**\n\t * Create a new {@code ObservationWebClientCustomizer} that will configure the\n\t * {@code Observation} setup on the client.\n\t * @param observationRegistry the registry to publish observations to\n\t * @param observationConvention the convention to use to populate observations\n\t */\n\tpublic ObservationWebClientCustomizer(ObservationRegistry observationRegistry,\n\t\t\tClientRequestObservationConvention observationConvention) {\n\t\tthis.observationRegistry = observationRegistry;\n\t\tthis.observationConvention = observationConvention;\n\t}\n\n\t@Override\n\tpublic void customize(WebClient.Builder webClientBuilder) {\n\t\twebClientBuilder.observationRegistry(this.observationRegistry)\n\t\t\t.observationConvention(this.observationConvention);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/observation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Observation integration for WebClient.\n */\n@NullMarked\npackage org.springframework.boot.webclient.observation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/java/org/springframework/boot/webclient/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring WebFlux WebClient support abstractions.\n */\n@NullMarked\npackage org.springframework.boot.webclient;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webclient/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration\norg.springframework.boot.webclient.autoconfigure.WebClientObservationAutoConfiguration\norg.springframework.boot.webclient.autoconfigure.service.ReactiveHttpServiceClientAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/WebClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.codec.CodecConfigurer;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebClientAutoConfiguration}\n *\n * @author Brian Clozel\n * @author Phillip Webb\n */\nclass WebClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveHttpClientAutoConfiguration.class,\n\t\t\t\tHttpClientAutoConfiguration.class, WebClientAutoConfiguration.class, SslAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldCreateBuilder() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebClient.Builder builder = context.getBean(WebClient.Builder.class);\n\t\t\tWebClient webClient = builder.build();\n\t\t\tassertThat(webClient).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeClientCodecs() {\n\t\tthis.contextRunner.withUserConfiguration(CodecConfiguration.class).run((context) -> {\n\t\t\tWebClient.Builder builder = context.getBean(WebClient.Builder.class);\n\t\t\tCodecCustomizer codecCustomizer = context.getBean(CodecCustomizer.class);\n\t\t\tWebClientCodecCustomizer clientCustomizer = context.getBean(WebClientCodecCustomizer.class);\n\t\t\tbuilder.build();\n\t\t\tassertThat(clientCustomizer).isNotNull();\n\t\t\tthen(codecCustomizer).should().customize(any(CodecConfigurer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid webClientShouldApplyCustomizers() {\n\t\tthis.contextRunner.withUserConfiguration(WebClientCustomizerConfig.class).run((context) -> {\n\t\t\tWebClient.Builder builder = context.getBean(WebClient.Builder.class);\n\t\t\tWebClientCustomizer customizer = context.getBean(\"webClientCustomizer\", WebClientCustomizer.class);\n\t\t\tbuilder.build();\n\t\t\tthen(customizer).should().customize(any(WebClient.Builder.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldGetPrototypeScopedBean() {\n\t\tthis.contextRunner.withUserConfiguration(WebClientCustomizerConfig.class).run((context) -> {\n\t\t\tWebClient.Builder firstBuilder = context.getBean(WebClient.Builder.class);\n\t\t\tWebClient.Builder secondBuilder = context.getBean(WebClient.Builder.class);\n\t\t\tassertThat(firstBuilder).isNotEqualTo(secondBuilder);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotCreateClientBuilderIfAlreadyPresent() {\n\t\tthis.contextRunner.withUserConfiguration(WebClientCustomizerConfig.class, CustomWebClientBuilderConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tWebClient.Builder builder = context.getBean(WebClient.Builder.class);\n\t\t\t\tassertThat(builder).isInstanceOf(MyWebClientBuilder.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateWebClientSsl() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebClientSsl webClientSsl = context.getBean(WebClientSsl.class);\n\t\t\tassertThat(webClientSsl).isInstanceOf(AutoConfiguredWebClientSsl.class);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CodecConfiguration {\n\n\t\t@Bean\n\t\tCodecCustomizer myCodecCustomizer() {\n\t\t\treturn mock(CodecCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebClientCustomizerConfig {\n\n\t\t@Bean\n\t\tWebClientCustomizer webClientCustomizer() {\n\t\t\treturn mock(WebClientCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebClientBuilderConfig {\n\n\t\t@Bean\n\t\tMyWebClientBuilder myWebClientBuilder() {\n\t\t\treturn mock(MyWebClientBuilder.class);\n\t\t}\n\n\t}\n\n\tinterface MyWebClientBuilder extends WebClient.Builder {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/WebClientObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure;\n\nimport java.time.Duration;\n\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webclient.observation.ObservationWebClientCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.mock.http.client.reactive.MockClientHttpResponse;\nimport org.springframework.web.reactive.function.client.ClientRequestObservationContext;\nimport org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebClientObservationAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass WebClientObservationAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withBean(ObservationRegistry.class, TestObservationRegistry::create)\n\t\t.withConfiguration(AutoConfigurations.of(ObservationAutoConfiguration.class, WebClientAutoConfiguration.class))\n\t\t.withUserConfiguration(WebClientObservationAutoConfiguration.class);\n\n\t@Test\n\tvoid contributesCustomizerBean() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ObservationWebClientCustomizer.class));\n\t}\n\n\t@Test\n\tvoid webClientCreatedWithBuilderIsInstrumented() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tWebClient.Builder builder = context.getBean(WebClient.Builder.class);\n\t\t\tvalidateWebClient(builder, registry);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConventionIfAvailable() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConvention.class).run((context) -> {\n\t\t\tTestObservationRegistry registry = context.getBean(TestObservationRegistry.class);\n\t\t\tWebClient.Builder builder = context.getBean(WebClient.Builder.class);\n\t\t\tWebClient webClient = mockWebClient(builder);\n\t\t\tassertThat(registry).doesNotHaveAnyObservation();\n\t\t\twebClient.get()\n\t\t\t\t.uri(\"https://example.org/projects/{project}\", \"spring-boot\")\n\t\t\t\t.retrieve()\n\t\t\t\t.toBodilessEntity()\n\t\t\t\t.block(Duration.ofSeconds(30));\n\t\t\tassertThat(registry).hasObservationWithNameEqualTo(\"http.client.requests\")\n\t\t\t\t.that()\n\t\t\t\t.hasLowCardinalityKeyValue(\"project\", \"spring-boot\");\n\t\t});\n\t}\n\n\tprivate void validateWebClient(WebClient.Builder builder, TestObservationRegistry registry) {\n\t\tWebClient webClient = mockWebClient(builder);\n\t\tassertThat(registry).doesNotHaveAnyObservation();\n\t\twebClient.get()\n\t\t\t.uri(\"https://example.org/projects/{project}\", \"spring-boot\")\n\t\t\t.retrieve()\n\t\t\t.toBodilessEntity()\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(registry).hasObservationWithNameEqualTo(\"http.client.requests\")\n\t\t\t.that()\n\t\t\t.hasLowCardinalityKeyValue(\"uri\", \"/projects/{project}\");\n\t}\n\n\tprivate WebClient mockWebClient(WebClient.Builder builder) {\n\t\tClientHttpConnector connector = mock(ClientHttpConnector.class);\n\t\tgiven(connector.connect(any(), any(), any())).willReturn(Mono.just(new MockClientHttpResponse(HttpStatus.OK)));\n\t\treturn builder.clientConnector(connector).build();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConventionConfig {\n\n\t\t@Bean\n\t\tCustomConvention customConvention() {\n\t\t\treturn new CustomConvention();\n\t\t}\n\n\t}\n\n\tstatic class CustomConvention extends DefaultClientRequestObservationConvention {\n\n\t\t@Override\n\t\tpublic KeyValues getLowCardinalityKeyValues(ClientRequestObservationContext context) {\n\t\t\treturn super.getLowCardinalityKeyValues(context).and(\"project\", \"spring-boot\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsConfiguration {\n\n\t\t@Bean\n\t\tMeterObservationHandler<Context> meterObservationHandler(MeterRegistry registry) {\n\t\t\treturn new DefaultMeterObservationHandler(registry);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/autoconfigure/service/ReactiveHttpServiceClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.autoconfigure.service;\n\nimport java.lang.reflect.InvocationHandler;\nimport java.lang.reflect.Proxy;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpClient.Redirect;\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.extractor.Extractors;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.ArgumentCaptor;\n\nimport org.springframework.aop.Advisor;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.http.client.autoconfigure.HttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.reactive.ReactiveHttpClientAutoConfiguration;\nimport org.springframework.boot.http.client.autoconfigure.service.HttpServiceClientPropertiesAutoConfiguration;\nimport org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.client.reactive.ClientHttpConnector;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer;\nimport org.springframework.web.service.annotation.GetExchange;\nimport org.springframework.web.service.registry.HttpServiceGroup;\nimport org.springframework.web.service.registry.HttpServiceGroup.ClientType;\nimport org.springframework.web.service.registry.HttpServiceGroupConfigurer.ClientCallback;\nimport org.springframework.web.service.registry.HttpServiceGroupConfigurer.Groups;\nimport org.springframework.web.service.registry.HttpServiceProxyRegistry;\nimport org.springframework.web.service.registry.ImportHttpServices;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ReactiveHttpServiceClientAutoConfiguration},\n * {@link PropertiesWebClientHttpServiceGroupConfigurer} and\n * {@link WebClientCustomizerHttpServiceGroupConfigurer}.\n *\n * @author Phillip Webb\n */\nclass ReactiveHttpServiceClientAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpServiceClientPropertiesAutoConfiguration.class,\n\t\t\t\tReactiveHttpServiceClientAutoConfiguration.class, ReactiveHttpClientAutoConfiguration.class,\n\t\t\t\tWebClientAutoConfiguration.class));\n\n\t@Test\n\tvoid configuresClientFromProperties() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com/one\",\n\t\t\t\t\t\"spring.http.serviceclient.one.default-header.test=true\",\n\t\t\t\t\t\"spring.http.serviceclient.two.base-url=https://example.com/two\",\n\t\t\t\t\t\"spring.http.serviceclient.two.default-header.test=true\",\n\t\t\t\t\t\"spring.http.serviceclient.two.default-header.two=iam2\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tHttpServiceProxyRegistry serviceProxyRegistry = context.getBean(HttpServiceProxyRegistry.class);\n\t\t\t\tassertThat(serviceProxyRegistry.getGroupNames()).containsOnly(\"one\", \"two\");\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tWebClient webClientOne = getWebClient(clientOne);\n\t\t\t\tassertThat(getUriComponentsBuilder(webClientOne).toUriString()).isEqualTo(\"https://example.com/one\");\n\t\t\t\tassertThat(getHttpHeaders(webClientOne).headerSet())\n\t\t\t\t\t.containsExactlyInAnyOrder(Map.entry(\"test\", List.of(\"true\")));\n\t\t\t\tTestClientTwo clientTwo = context.getBean(TestClientTwo.class);\n\t\t\t\tWebClient webClientTwo = getWebClient(clientTwo);\n\t\t\t\tassertThat(getUriComponentsBuilder(webClientTwo).toUriString()).isEqualTo(\"https://example.com/two\");\n\t\t\t\tassertThat(getHttpHeaders(webClientTwo).headerSet())\n\t\t\t\t\t.containsExactlyInAnyOrder(Map.entry(\"test\", List.of(\"true\")), Map.entry(\"two\", List.of(\"iam2\")));\n\t\t\t});\n\t}\n\n\t@Test // gh-46915\n\tvoid configuresClientFromPropertiesWhenHasHttpConnectorAutoConfiguration() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(HttpClientAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.http.serviceclient.one.connect-timeout=5s\",\n\t\t\t\t\t\"spring.http.serviceclient.two.connect-timeout=10s\", \"spring.http.clients.reactive.connector=jdk\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tPropertiesWebClientHttpServiceGroupConfigurer configurer = context\n\t\t\t\t\t.getBean(PropertiesWebClientHttpServiceGroupConfigurer.class);\n\t\t\t\tGroups<WebClient.Builder> groups = mock();\n\t\t\t\tconfigurer.configureGroups(groups);\n\t\t\t\tArgumentCaptor<ClientCallback<WebClient.Builder>> callbackCaptor = ArgumentCaptor.captor();\n\t\t\t\tthen(groups).should().forEachClient(callbackCaptor.capture());\n\t\t\t\tClientCallback<WebClient.Builder> callback = callbackCaptor.getValue();\n\t\t\t\tassertConnectTimeout(callback, \"one\", Duration.ofSeconds(5));\n\t\t\t\tassertConnectTimeout(callback, \"two\", Duration.ofSeconds(10));\n\t\t\t});\n\t}\n\n\tprivate void assertConnectTimeout(ClientCallback<WebClient.Builder> callback, String name,\n\t\t\tDuration expectedReadTimeout) {\n\t\tHttpServiceGroup group = mock();\n\t\tgiven(group.name()).willReturn(name);\n\t\tWebClient.Builder builder = mock();\n\t\tcallback.withClient(group, builder);\n\t\tArgumentCaptor<ClientHttpConnector> connectorCaptor = ArgumentCaptor.captor();\n\t\tthen(builder).should().clientConnector(connectorCaptor.capture());\n\t\tClientHttpConnector client = connectorCaptor.getValue();\n\t\tHttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(client, \"httpClient\");\n\t\tassertThat(httpClient).isNotNull();\n\t\tassertThat(httpClient.connectTimeout()).contains(expectedReadTimeout);\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedHttpConnectorBuilder() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.reactiveclient.service.base-url=https://example.com\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, HttpConnectorBuilderConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(getJdkHttpClient(clientOne).followRedirects()).isEqualTo(Redirect.NEVER);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedRequestFactorySettings() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\",\n\t\t\t\t\t\"spring.http.clients.reactive.connector=jdk\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, HttpConnectorSettingsConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tassertThat(getJdkHttpClient(clientOne).followRedirects()).isEqualTo(Redirect.NEVER);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedWebClientCustomizer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, WebClientCustomizerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tWebClient webClientOne = getWebClient(clientOne);\n\t\t\t\tassertThat(getHttpHeaders(webClientOne).headerSet())\n\t\t\t\t\t.containsExactlyInAnyOrder(Map.entry(\"customized\", List.of(\"true\")));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasUserDefinedHttpServiceGroupConfigurer() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\")\n\t\t\t.withUserConfiguration(HttpClientConfiguration.class, HttpServiceGroupConfigurerConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tTestClientOne clientOne = context.getBean(TestClientOne.class);\n\t\t\t\tWebClient webClientOne = getWebClient(clientOne);\n\t\t\t\tassertThat(getHttpHeaders(webClientOne).headerSet())\n\t\t\t\t\t.containsExactlyInAnyOrder(Map.entry(\"customizedgroup\", List.of(\"true\")));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenHasNoHttpServiceProxyRegistryBean() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.http.serviceclient.one.base-url=https://example.com\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpServiceProxyRegistry.class));\n\t}\n\n\tprivate HttpClient getJdkHttpClient(Object proxy) {\n\t\treturn (HttpClient) Extractors.byName(\"builder.connector.httpClient\").apply(getWebClient(proxy));\n\t}\n\n\tprivate HttpHeaders getHttpHeaders(WebClient webClient) {\n\t\treturn (HttpHeaders) Extractors.byName(\"defaultHeaders\").apply(webClient);\n\t}\n\n\tprivate UriComponentsBuilder getUriComponentsBuilder(WebClient webClient) {\n\t\treturn (UriComponentsBuilder) Extractors.byName(\"uriBuilderFactory.baseUri\").apply(webClient);\n\t}\n\n\tprivate WebClient getWebClient(Object proxy) {\n\t\tInvocationHandler handler = Proxy.getInvocationHandler(proxy);\n\t\tAdvisor[] advisors = (Advisor[]) Extractors.byName(\"advised.advisors\").apply(handler);\n\t\tMap<?, ?> serviceMethods = (Map<?, ?>) Extractors.byName(\"advice.httpServiceMethods\").apply(advisors[0]);\n\t\tObject serviceMethod = serviceMethods.values().iterator().next();\n\t\treturn (WebClient) Extractors.byName(\"responseFunction.responseFunction.arg$1.webClient\").apply(serviceMethod);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportHttpServices(group = \"one\", types = TestClientOne.class, clientType = ClientType.WEB_CLIENT)\n\t@ImportHttpServices(group = \"two\", types = TestClientTwo.class, clientType = ClientType.WEB_CLIENT)\n\tstatic class HttpClientConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpConnectorBuilderConfiguration {\n\n\t\t@Bean\n\t\tClientHttpConnectorBuilder<?> httpConnectorBuilder() {\n\t\t\treturn ClientHttpConnectorBuilder.jdk()\n\t\t\t\t.withHttpClientCustomizer((httpClient) -> httpClient.followRedirects(Redirect.NEVER));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpConnectorSettingsConfiguration {\n\n\t\t@Bean\n\t\tHttpClientSettings httpClientSettings() {\n\t\t\treturn HttpClientSettings.defaults().withRedirects(HttpRedirects.DONT_FOLLOW);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebClientCustomizerConfiguration {\n\n\t\t@Bean\n\t\tWebClientCustomizer webClientCustomizer() {\n\t\t\treturn (builder) -> builder.defaultHeader(\"customized\", \"true\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpServiceGroupConfigurerConfiguration {\n\n\t\t@Bean\n\t\tWebClientHttpServiceGroupConfigurer restClientHttpServiceGroupConfigurer() {\n\t\t\treturn (groups) -> groups.filterByName(\"one\")\n\t\t\t\t.forEachClient((group, builder) -> builder.defaultHeader(\"customizedgroup\", \"true\"));\n\t\t}\n\n\t}\n\n\tinterface TestClientOne {\n\n\t\t@GetExchange(\"/hello\")\n\t\tString hello();\n\n\t}\n\n\tinterface TestClientTwo {\n\n\t\t@GetExchange(\"/there\")\n\t\tString there();\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient/src/test/java/org/springframework/boot/webclient/observation/ObservationWebClientCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.observation;\n\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.web.reactive.function.client.ClientRequestObservationConvention;\nimport org.springframework.web.reactive.function.client.DefaultClientRequestObservationConvention;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ObservationWebClientCustomizer}\n *\n * @author Brian Clozel\n */\nclass ObservationWebClientCustomizerTests {\n\n\tprivate static final String TEST_METRIC_NAME = \"http.test.metric.name\";\n\n\tprivate final TestObservationRegistry observationRegistry = TestObservationRegistry.create();\n\n\tprivate final ClientRequestObservationConvention observationConvention = new DefaultClientRequestObservationConvention(\n\t\t\tTEST_METRIC_NAME);\n\n\tprivate final ObservationWebClientCustomizer customizer = new ObservationWebClientCustomizer(\n\t\t\tthis.observationRegistry, this.observationConvention);\n\n\tprivate final WebClient.Builder clientBuilder = WebClient.builder();\n\n\t@Test\n\tvoid shouldCustomizeObservationConfiguration() {\n\t\tthis.customizer.customize(this.clientBuilder);\n\t\tassertThat(this.clientBuilder).hasFieldOrPropertyWithValue(\"observationRegistry\", this.observationRegistry);\n\t\tassertThat(this.clientBuilder).extracting(\"observationConvention\")\n\t\t\t.isInstanceOf(DefaultClientRequestObservationConvention.class)\n\t\t\t.hasFieldOrPropertyWithValue(\"name\", TEST_METRIC_NAME);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot WebClient Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-webclient\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(\"org.apache.httpcomponents.client5:httpclient5\")\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\toptional(\"org.springframework:spring-test\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-micrometer-metrics\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/main/java/org/springframework/boot/webclient/test/autoconfigure/AutoConfigureWebClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration of a\n * {@link Builder WebClient.Builder}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJson\n@ImportAutoConfiguration\npublic @interface AutoConfigureWebClient {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/main/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.web.client.RestClient.Builder;\n\n/**\n * Annotation for a Spring WebClient test that focuses <strong>only</strong> on beans that\n * use {@link Builder WebClient.Builder}.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to rest client\n * tests. Similarly, component scanning is limited to beans annotated with:\n * <ul>\n * <li>{@code @JacksonComponent}</li>\n * </ul>\n * <p>\n * as well as beans that implement:\n * <ul>\n * <li>{@code JacksonModule}, if Jackson is available</li>\n * </ul>\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(WebClientTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(WebClientTypeExcludeFilter.class)\n@AutoConfigureWebClient\n@ImportAutoConfiguration\npublic @interface WebClientTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the components to test. This is an alias of {@link #components()} which\n\t * can be used for brevity if no other attributes are defined. See\n\t * {@link #components()} for details.\n\t * @see #components()\n\t * @return the components to test\n\t */\n\t@AliasFor(\"components\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the components to test. May be left blank if components will be manually\n\t * imported or created directly.\n\t * @see #value()\n\t * @return the components to test\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] components() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default, only\n\t * {@code @JacksonComponent} and {@code JacksonModule} beans are included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/main/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link WebClientTest @WebClientTest} support.\n *\n * @author Andy Wilkinson\n */\nclass WebClientTestContextBootstrapper extends TestSliceTestContextBootstrapper<WebClientTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/main/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TypeExcludeFilter} for {@link WebClientTest @WebClientTest}.\n *\n * @author Andy Wilkinson\n */\nclass WebClientTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<WebClientTest> {\n\n\tprivate static final Class<?>[] NO_COMPONENTS = {};\n\n\tprivate static final String DATABIND_MODULE_CLASS_NAME = \"tools.jackson.databind.JacksonModule\";\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>();\n\t\tif (ClassUtils.isPresent(DATABIND_MODULE_CLASS_NAME, WebClientTypeExcludeFilter.class.getClassLoader())) {\n\t\t\ttry {\n\t\t\t\tincludes.add(Class.forName(DATABIND_MODULE_CLASS_NAME, true,\n\t\t\t\t\t\tWebClientTypeExcludeFilter.class.getClassLoader()));\n\t\t\t}\n\t\t\tcatch (ClassNotFoundException ex) {\n\t\t\t\tthrow new IllegalStateException(\"Failed to load \" + DATABIND_MODULE_CLASS_NAME, ex);\n\t\t\t}\n\t\t\tincludes.add(JacksonComponent.class);\n\t\t}\n\t\tKNOWN_INCLUDES = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate final Class<?>[] components;\n\n\tWebClientTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.components = getAnnotation().getValue(\"components\", Class[].class).orElse(NO_COMPONENTS);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.components));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/main/java/org/springframework/boot/webclient/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for web clients.\n */\n@NullMarked\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/main/resources/META-INF/spring/org.springframework.boot.webclient.test.autoconfigure.AutoConfigureWebClient.imports",
    "content": "org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration\norg.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/AnotherExampleWebClientService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * A second example web client used with {@link WebClientTest @WebClientTest} tests.\n *\n * @author Scott Frederick\n */\n@Service\npublic class AnotherExampleWebClientService {\n\n\tprivate final WebClient.Builder builder;\n\n\tprivate final WebClient webClient;\n\n\tpublic AnotherExampleWebClientService(WebClient.Builder builder) {\n\t\tthis.builder = builder;\n\t\tthis.webClient = builder.baseUrl(\"https://example.com\").build();\n\t}\n\n\tprotected WebClient.Builder geWebClientBuilder() {\n\t\treturn this.builder;\n\t}\n\n\tpublic @Nullable String test() {\n\t\tResponseEntity<String> response = this.webClient.get().uri(\"/test\").retrieve().toEntity(String.class).block();\n\t\tassertThat(response).isNotNull();\n\t\treturn response.getBody();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/ExampleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.ConstructorBinding;\nimport org.springframework.boot.context.properties.bind.DefaultValue;\n\n/**\n * Example {@link ConstructorBinding constructor-bound}\n * {@link ConfigurationProperties @ConfigurationProperties} used to test the use of\n * configuration properties scan with sliced test.\n *\n * @author Stephane Nicoll\n */\n@ConfigurationProperties(\"example\")\npublic class ExampleProperties {\n\n\tprivate final String name;\n\n\tpublic ExampleProperties(@DefaultValue(\"test\") String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/ExampleWebClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link WebClientTest @WebClientTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\n@ConfigurationPropertiesScan\npublic class ExampleWebClientApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/ExampleWebClientService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Example web client using {@code WebClient} with {@link WebClientTest @WebClientTest}\n * tests.\n *\n * @author Scott Frederick\n */\n@Service\npublic class ExampleWebClientService {\n\n\tprivate final WebClient.Builder builder;\n\n\tprivate final WebClient webClient;\n\n\tpublic ExampleWebClientService(WebClient.Builder builder) {\n\t\tthis.builder = builder;\n\t\tthis.webClient = builder.build();\n\t}\n\n\tprotected WebClient.Builder getWebClientBuilder() {\n\t\treturn this.builder;\n\t}\n\n\tpublic @Nullable String test() {\n\t\tResponseEntity<String> response = this.webClient.get().uri(\"/test\").retrieve().toEntity(String.class).block();\n\t\tassertThat(response).isNotNull();\n\t\treturn response.getBody();\n\t}\n\n\tpublic void testPostWithBody(String body) {\n\t\tthis.webClient.post().uri(\"/test\").bodyValue(body).retrieve().toBodilessEntity().block();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/MockWebServerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\n\nimport okhttp3.mockwebserver.MockWebServer;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.boot.webclient.WebClientCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.reactive.function.client.WebClient;\n\n/**\n * Configuration for a {@link MockWebServer}.\n *\n * @author Andy Wilkinson\n */\n@Configuration(proxyBeanMethods = false)\npublic class MockWebServerConfiguration implements DisposableBean, WebClientCustomizer {\n\n\tprivate final MockWebServer mockWebServer = new MockWebServer();\n\n\tMockWebServerConfiguration() {\n\t\ttry {\n\t\t\tthis.mockWebServer.start();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t\ttry {\n\t\t\tthis.mockWebServer.shutdown();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void customize(WebClient.Builder webClientBuilder) {\n\t\twebClientBuilder.baseUrl(this.mockWebServer.url(\"/\").toString());\n\t}\n\n\t@Bean\n\tMockWebServer mockWebServer() {\n\t\treturn this.mockWebServer;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebClientTest @WebClientTest}.\n *\n * @author Scott Frederick\n */\n@WebClientTest(ExampleWebClientService.class)\n@Import(MockWebServerConfiguration.class)\nclass WebClientTestIntegrationTests {\n\n\t@Autowired\n\tprivate MockWebServer server;\n\n\t@Autowired\n\tprivate ExampleWebClientService client;\n\n\t@Test\n\tvoid mockServerCall1() throws InterruptedException {\n\t\tthis.server.enqueue(new MockResponse().setBody(\"1\"));\n\t\tassertThat(this.client.test()).isEqualTo(\"1\");\n\t\tthis.server.takeRequest();\n\t}\n\n\t@Test\n\tvoid mockServerCall2() throws InterruptedException {\n\t\tthis.server.enqueue(new MockResponse().setBody(\"2\"));\n\t\tassertThat(this.client.test()).isEqualTo(\"2\");\n\t\tthis.server.takeRequest();\n\t}\n\n\t@Test\n\tvoid mockServerCallWithContent() throws InterruptedException {\n\t\tthis.server.enqueue(new MockResponse().setBody(\"1\"));\n\t\tthis.client.testPostWithBody(\"test\");\n\t\tassertThat(this.server.takeRequest().getBody().readString(StandardCharsets.UTF_8)).isEqualTo(\"test\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTestNoComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link WebClientTest @WebClientTest} with no specific client.\n *\n * @author Phillip Webb\n */\n@WebClientTest\n@Import(MockWebServerConfiguration.class)\nclass WebClientTestNoComponentIntegrationTests {\n\n\t@Autowired\n\tprivate MockWebServer server;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate WebClient.Builder webClientBuilder;\n\n\t@Test\n\tvoid exampleWebClientServiceIsNotInjected() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleWebClientService.class));\n\t}\n\n\t@Test\n\tvoid examplePropertiesIsNotInjected() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleProperties.class));\n\t}\n\n\t@Test\n\tvoid manuallyCreateBean() throws InterruptedException {\n\t\tExampleWebClientService client = new ExampleWebClientService(this.webClientBuilder);\n\t\tthis.server.enqueue(new MockResponse().setBody(\"hello\"));\n\t\tassertThat(client.test()).isEqualTo(\"hello\");\n\t\tthis.server.takeRequest();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link WebClientTest#properties properties} attribute of\n * {@link WebClientTest @WebClientTest}.\n *\n * @author Artsiom Yudovin\n */\n@WebClientTest(properties = \"spring.profiles.active=test\")\nclass WebClientTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(WebClientTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTestWithConfigurationPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebClientTest @WebClientTest} with a\n * {@link ConfigurationProperties @ConfigurationProperties} annotated type.\n *\n * @author Stephane Nicoll\n */\n@WebClientTest(components = ExampleProperties.class, properties = \"example.name=Hello\")\nclass WebClientTestWithConfigurationPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid configurationPropertiesCanBeAddedAsComponent() {\n\t\tassertThat(this.applicationContext.getBeansOfType(ExampleProperties.class).keySet())\n\t\t\t.containsOnly(\"example-\" + ExampleProperties.class.getName());\n\t\tassertThat(this.applicationContext.getBean(ExampleProperties.class).getName()).isEqualTo(\"Hello\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webclient-test/src/test/java/org/springframework/boot/webclient/test/autoconfigure/WebClientTestWithoutJacksonIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webclient.test.autoconfigure;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebClientTest @WebClientTest} without Jackson.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"jackson-*.jar\")\n@WebClientTest(ExampleWebClientService.class)\n@Import(MockWebServerConfiguration.class)\nclass WebClientTestWithoutJacksonIntegrationTests {\n\n\t@Autowired\n\tprivate MockWebServer server;\n\n\t@Autowired\n\tprivate ExampleWebClientService client;\n\n\t@Test\n\tvoid webClientTestCanBeUsedWhenJacksonIsNotOnTheClassPath() throws InterruptedException {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tassertThat(ClassUtils.isPresent(\"com.fasterxml.jackson.databind.Module\", classLoader)).isFalse();\n\t\tassertThat(ClassUtils.isPresent(\"tools.jackson.databind.JacksonModule\", classLoader)).isFalse();\n\t\tthis.server.enqueue(new MockResponse().setBody(\"hello\"));\n\t\tassertThat(this.client.test()).isEqualTo(\"hello\");\n\t\tthis.server.takeRequest();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot WebFlux\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-http-codec\"))\n\tapi(\"org.springframework:spring-webflux\")\n\n\timplementation(project(\":module:spring-boot-web-server\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-validation\"))\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"org.springframework.security:spring-security-core\")\n\n\ttestFixturesApi(testFixtures(project(\":module:spring-boot-actuator\")))\n\ttestFixturesImplementation(project(\":module:spring-boot-jackson\"))\n\ttestFixturesImplementation(project(\":module:spring-boot-reactor-netty\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-reactor-netty\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-actuator-autoconfigure\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n\ttestImplementation(\"org.aspectj:aspectjweaver\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"test\") {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/WebFluxWebApplicationTypeDeducer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link WebApplicationType} deducer to ensure Spring WebFlux applications use\n * {@link WebApplicationType#REACTIVE}.\n *\n * @author Phillip Webb\n */\n@Order(20) // Ordered after MVC\nclass WebFluxWebApplicationTypeDeducer implements WebApplicationType.Deducer {\n\n\tprivate static final String[] INDICATOR_CLASSES = { \"reactor.core.publisher.Mono\",\n\t\t\t\"org.springframework.web.reactive.DispatcherHandler\" };\n\n\t@Override\n\tpublic @Nullable WebApplicationType deduceWebApplicationType() {\n\t\t// Guard in case the classic module is being used and dependencies are excluded\n\t\tfor (String indicatorClass : INDICATOR_CLASSES) {\n\t\t\tif (!ClassUtils.isPresent(indicatorClass, null)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn WebApplicationType.REACTIVE;\n\t}\n\n\tstatic class WebFluxWebApplicationTypeDeducerRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tfor (String servletIndicatorClass : INDICATOR_CLASSES) {\n\t\t\t\tregisterTypeIfPresent(servletIndicatorClass, classLoader, hints);\n\t\t\t}\n\t\t}\n\n\t\tprivate void registerTypeIfPresent(String typeName, @Nullable ClassLoader classLoader, RuntimeHints hints) {\n\t\t\tif (ClassUtils.isPresent(typeName, classLoader)) {\n\t\t\t\thints.reflection().registerType(TypeReference.of(typeName));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/endpoint/web/AbstractWebFluxEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\nimport java.security.Principal;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport org.jspecify.annotations.Nullable;\nimport org.reactivestreams.Publisher;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.OperationType;\nimport org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.ResponseEntity.BodyBuilder;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.security.authorization.AuthorityAuthorizationManager;\nimport org.springframework.security.authorization.AuthorizationResult;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.ReactiveSecurityContextHolder;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.result.method.RequestMappingInfo;\nimport org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;\nimport org.springframework.web.server.ResponseStatusException;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.util.pattern.PathPattern;\n\n/**\n * A custom {@link HandlerMapping} that makes web endpoints available over HTTP using\n * Spring WebFlux.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 4.0.0\n */\n@ImportRuntimeHints(AbstractWebFluxEndpointHandlerMappingRuntimeHints.class)\npublic abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappingInfoHandlerMapping {\n\n\tprivate final EndpointMapping endpointMapping;\n\n\tprivate final Collection<ExposableWebEndpoint> endpoints;\n\n\tprivate final EndpointMediaTypes endpointMediaTypes;\n\n\tprivate final @Nullable CorsConfiguration corsConfiguration;\n\n\tprivate final Method handleWriteMethod = getHandleWriteMethod();\n\n\tprivate final Method handleReadMethod = getHandleReadMethod();\n\n\tprivate final Method handleCatchAllMethod = getCatchAllMethod();\n\n\tprivate final boolean shouldRegisterLinksMapping;\n\n\t/**\n\t * Creates a new {@code AbstractWebFluxEndpointHandlerMapping} that provides mappings\n\t * for the operations of the given {@code webEndpoints}.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param endpointMediaTypes media types consumed and produced by the endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints\n\t * @param shouldRegisterLinksMapping whether the links endpoint should be registered\n\t */\n\tpublic AbstractWebFluxEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,\n\t\t\t@Nullable CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {\n\t\tthis.endpointMapping = endpointMapping;\n\t\tthis.endpoints = endpoints;\n\t\tthis.endpointMediaTypes = endpointMediaTypes;\n\t\tthis.corsConfiguration = corsConfiguration;\n\t\tthis.shouldRegisterLinksMapping = shouldRegisterLinksMapping;\n\t\tsetOrder(-100);\n\t}\n\n\tprivate static Method getHandleWriteMethod() {\n\t\tMethod method = ReflectionUtils.findMethod(WriteOperationHandler.class, \"handle\", ServerWebExchange.class,\n\t\t\t\tMap.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\treturn method;\n\t}\n\n\tprivate static Method getHandleReadMethod() {\n\t\tMethod method = ReflectionUtils.findMethod(ReadOperationHandler.class, \"handle\", ServerWebExchange.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\treturn method;\n\t}\n\n\tprivate static Method getCatchAllMethod() {\n\t\tMethod method = ReflectionUtils.findMethod(CatchAllHandler.class, \"handle\", ServerWebExchange.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\treturn method;\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tfor (ExposableWebEndpoint endpoint : this.endpoints) {\n\t\t\tfor (WebOperation operation : endpoint.getOperations()) {\n\t\t\t\tregisterMappingForOperation(endpoint, operation);\n\t\t\t}\n\t\t}\n\t\tif (this.shouldRegisterLinksMapping) {\n\t\t\tregisterLinksMapping();\n\t\t}\n\t}\n\n\t@Override\n\tprotected HandlerMethod createHandlerMethod(Object handler, Method method) {\n\t\tHandlerMethod handlerMethod = super.createHandlerMethod(handler, method);\n\t\treturn new WebFluxEndpointHandlerMethod(handlerMethod.getBean(), handlerMethod.getMethod());\n\t}\n\n\tprivate void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {\n\t\tRequestMappingInfo requestMappingInfo = createRequestMappingInfo(operation);\n\t\tif (operation.getType() == OperationType.WRITE) {\n\t\t\tReactiveWebOperation reactiveWebOperation = wrapReactiveWebOperation(endpoint, operation,\n\t\t\t\t\tnew ReactiveWebOperationAdapter(operation));\n\t\t\tregisterMapping(requestMappingInfo, new WriteOperationHandler((reactiveWebOperation)),\n\t\t\t\t\tthis.handleWriteMethod);\n\t\t}\n\t\telse {\n\t\t\tregisterReadMapping(requestMappingInfo, endpoint, operation);\n\t\t}\n\t}\n\n\tprotected void registerReadMapping(RequestMappingInfo requestMappingInfo, ExposableWebEndpoint endpoint,\n\t\t\tWebOperation operation) {\n\t\tReactiveWebOperation reactiveWebOperation = wrapReactiveWebOperation(endpoint, operation,\n\t\t\t\tnew ReactiveWebOperationAdapter(operation));\n\t\tregisterMapping(requestMappingInfo, new ReadOperationHandler((reactiveWebOperation)), this.handleReadMethod);\n\t}\n\n\t/**\n\t * Hook point that allows subclasses to wrap the {@link ReactiveWebOperation} before\n\t * it's called. Allows additional features, such as security, to be added.\n\t * @param endpoint the source endpoint\n\t * @param operation the source operation\n\t * @param reactiveWebOperation the reactive web operation to wrap\n\t * @return a wrapped reactive web operation\n\t */\n\tprotected ReactiveWebOperation wrapReactiveWebOperation(ExposableWebEndpoint endpoint, WebOperation operation,\n\t\t\tReactiveWebOperation reactiveWebOperation) {\n\t\treturn reactiveWebOperation;\n\t}\n\n\t/**\n\t * Register a \"catch all\" handler for the rest of actuator namespace, ensuring that\n\t * all requests are handled by this handler mapping.\n\t * @param responseStatus the response status to use for handled requests\n\t */\n\tprotected void registerCatchAllMapping(HttpStatus responseStatus) {\n\t\tString subPath = this.endpointMapping.createSubPath(\"/**\");\n\t\tregisterMapping(RequestMappingInfo.paths(subPath).build(), new CatchAllHandler(responseStatus),\n\t\t\t\tthis.handleCatchAllMethod);\n\t}\n\n\tprivate RequestMappingInfo createRequestMappingInfo(WebOperation operation) {\n\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\tString path = this.endpointMapping.createSubPath(predicate.getPath());\n\t\tList<String> paths = new ArrayList<>();\n\t\tpaths.add(path);\n\t\tif (!StringUtils.hasText(path)) {\n\t\t\tpaths.add(\"/\");\n\t\t}\n\t\tRequestMethod method = RequestMethod.valueOf(predicate.getHttpMethod().name());\n\t\tString[] consumes = StringUtils.toStringArray(predicate.getConsumes());\n\t\tString[] produces = StringUtils.toStringArray(predicate.getProduces());\n\t\treturn RequestMappingInfo.paths(paths.toArray(new String[0]))\n\t\t\t.methods(method)\n\t\t\t.consumes(consumes)\n\t\t\t.produces(produces)\n\t\t\t.build();\n\t}\n\n\tprivate void registerLinksMapping() {\n\t\tString path = this.endpointMapping.getPath();\n\t\tString linksPath = StringUtils.hasLength(path) ? path : \"/\";\n\t\tString[] produces = StringUtils.toStringArray(this.endpointMediaTypes.getProduced());\n\t\tRequestMappingInfo mapping = RequestMappingInfo.paths(linksPath)\n\t\t\t.methods(RequestMethod.GET)\n\t\t\t.produces(produces)\n\t\t\t.build();\n\t\tLinksHandler linksHandler = getLinksHandler();\n\t\tMethod linksMethod = ReflectionUtils.findMethod(linksHandler.getClass(), \"links\", ServerWebExchange.class);\n\t\tAssert.state(linksMethod != null, \"'linksMethod' must not be null\");\n\t\tregisterMapping(mapping, linksHandler, linksMethod);\n\t}\n\n\t@Override\n\tprotected boolean hasCorsConfigurationSource(Object handler) {\n\t\treturn this.corsConfiguration != null;\n\t}\n\n\t@Override\n\tprotected @Nullable CorsConfiguration initCorsConfiguration(Object handler, Method method,\n\t\t\tRequestMappingInfo mapping) {\n\t\treturn this.corsConfiguration;\n\t}\n\n\t@Override\n\tprotected @Nullable CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) {\n\t\tCorsConfiguration corsConfiguration = super.getCorsConfiguration(handler, exchange);\n\t\treturn (corsConfiguration != null) ? corsConfiguration : this.corsConfiguration;\n\t}\n\n\t@Override\n\tprotected boolean isHandler(Class<?> beanType) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tprotected @Nullable RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the Handler providing actuator links at the root endpoint.\n\t * @return the links handler\n\t */\n\tprotected abstract LinksHandler getLinksHandler();\n\n\t/**\n\t * Return the web endpoints being mapped.\n\t * @return the endpoints\n\t */\n\tpublic Collection<ExposableWebEndpoint> getEndpoints() {\n\t\treturn this.endpoints;\n\t}\n\n\t/**\n\t * An {@link OperationInvoker} that performs the invocation of a blocking operation on\n\t * a separate thread using Reactor's {@link Schedulers#boundedElastic() bounded\n\t * elastic scheduler}.\n\t */\n\tprotected static final class ElasticSchedulerInvoker implements OperationInvoker {\n\n\t\tprivate final OperationInvoker invoker;\n\n\t\tpublic ElasticSchedulerInvoker(OperationInvoker invoker) {\n\t\t\tthis.invoker = invoker;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object invoke(InvocationContext context) {\n\t\t\treturn Mono.fromCallable(() -> this.invoker.invoke(context)).subscribeOn(Schedulers.boundedElastic());\n\t\t}\n\n\t}\n\n\tprotected static final class ExceptionCapturingInvoker implements OperationInvoker {\n\n\t\tprivate final OperationInvoker invoker;\n\n\t\tpublic ExceptionCapturingInvoker(OperationInvoker invoker) {\n\t\t\tthis.invoker = invoker;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object invoke(InvocationContext context) {\n\t\t\ttry {\n\t\t\t\treturn this.invoker.invoke(context);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\treturn Mono.error(ex);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * Reactive handler providing actuator links at the root endpoint.\n\t */\n\t@FunctionalInterface\n\tprotected interface LinksHandler {\n\n\t\tObject links(ServerWebExchange exchange);\n\n\t}\n\n\t/**\n\t * A reactive web operation that can be handled by WebFlux.\n\t */\n\t@FunctionalInterface\n\tprotected interface ReactiveWebOperation {\n\n\t\tMono<ResponseEntity<Object>> handle(ServerWebExchange exchange, @Nullable Map<String, String> body);\n\n\t}\n\n\t/**\n\t * Adapter class to convert an {@link OperationInvoker} into a\n\t * {@link ReactiveWebOperation}.\n\t */\n\tprivate static final class ReactiveWebOperationAdapter implements ReactiveWebOperation {\n\n\t\tprivate static final String PATH_SEPARATOR = AntPathMatcher.DEFAULT_PATH_SEPARATOR;\n\n\t\tprivate final WebOperation operation;\n\n\t\tprivate final OperationInvoker invoker;\n\n\t\tprivate final Supplier<Mono<? extends SecurityContext>> securityContextSupplier;\n\n\t\tprivate ReactiveWebOperationAdapter(WebOperation operation) {\n\t\t\tthis.operation = operation;\n\t\t\tthis.invoker = getInvoker(operation);\n\t\t\tthis.securityContextSupplier = getSecurityContextSupplier();\n\t\t}\n\n\t\tprivate OperationInvoker getInvoker(WebOperation operation) {\n\t\t\tOperationInvoker invoker = operation::invoke;\n\t\t\tif (operation.isBlocking()) {\n\t\t\t\treturn new ElasticSchedulerInvoker(invoker);\n\t\t\t}\n\t\t\treturn new ExceptionCapturingInvoker(invoker);\n\t\t}\n\n\t\tprivate Supplier<Mono<? extends SecurityContext>> getSecurityContextSupplier() {\n\t\t\tif (ClassUtils.isPresent(\"org.springframework.security.core.context.ReactiveSecurityContextHolder\",\n\t\t\t\t\tgetClass().getClassLoader())) {\n\t\t\t\treturn this::springSecurityContext;\n\t\t\t}\n\t\t\treturn this::emptySecurityContext;\n\t\t}\n\n\t\tMono<? extends SecurityContext> springSecurityContext() {\n\t\t\treturn ReactiveSecurityContextHolder.getContext()\n\t\t\t\t.map((securityContext) -> new ReactiveSecurityContext(securityContext.getAuthentication()))\n\t\t\t\t.switchIfEmpty(Mono.just(new ReactiveSecurityContext(null)));\n\t\t}\n\n\t\tMono<SecurityContext> emptySecurityContext() {\n\t\t\treturn Mono.just(SecurityContext.NONE);\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<ResponseEntity<Object>> handle(ServerWebExchange exchange, @Nullable Map<String, String> body) {\n\t\t\treturn this.securityContextSupplier.get()\n\t\t\t\t.map((securityContext) -> getInvocationContext(securityContext, exchange, body))\n\t\t\t\t.flatMap((invocationContext) -> handleResult(invoke(invocationContext),\n\t\t\t\t\t\texchange.getRequest().getMethod()));\n\t\t}\n\n\t\tprivate InvocationContext getInvocationContext(SecurityContext securityContext, ServerWebExchange exchange,\n\t\t\t\t@Nullable Map<String, String> body) {\n\t\t\tMap<String, Object> arguments = getArguments(exchange, body);\n\t\t\tOperationArgumentResolver serverNamespaceResolver = OperationArgumentResolver.of(WebServerNamespace.class,\n\t\t\t\t\t() -> getServerNamespace(exchange));\n\t\t\tOperationArgumentResolver producibleOperationResolver = new ProducibleOperationArgumentResolver(\n\t\t\t\t\t() -> exchange.getRequest().getHeaders().get(\"Accept\"));\n\t\t\treturn new InvocationContext(securityContext, arguments, serverNamespaceResolver,\n\t\t\t\t\tproducibleOperationResolver);\n\t\t}\n\n\t\tprivate WebServerNamespace getServerNamespace(ServerWebExchange exchange) {\n\t\t\tApplicationContext context = exchange.getApplicationContext();\n\t\t\treturn WebServerNamespace.from(WebServerApplicationContext.getServerNamespace(context));\n\t\t}\n\n\t\tprivate @Nullable Publisher<?> invoke(InvocationContext invocationContext) {\n\t\t\treturn (@Nullable Publisher<?>) this.invoker.invoke(invocationContext);\n\t\t}\n\n\t\tprivate Map<String, Object> getArguments(ServerWebExchange exchange, @Nullable Map<String, String> body) {\n\t\t\tMap<String, Object> arguments = new LinkedHashMap<>(getTemplateVariables(exchange));\n\t\t\tString matchAllRemainingPathSegmentsVariable = this.operation.getRequestPredicate()\n\t\t\t\t.getMatchAllRemainingPathSegmentsVariable();\n\t\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\t\targuments.put(matchAllRemainingPathSegmentsVariable, getRemainingPathSegments(exchange));\n\t\t\t}\n\t\t\tif (body != null) {\n\t\t\t\targuments.putAll(body);\n\t\t\t}\n\t\t\texchange.getRequest()\n\t\t\t\t.getQueryParams()\n\t\t\t\t.forEach((name, values) -> arguments.put(name, (values.size() != 1) ? values : values.get(0)));\n\t\t\treturn arguments;\n\t\t}\n\n\t\tprivate Object getRemainingPathSegments(ServerWebExchange exchange) {\n\t\t\tPathPattern pathPattern = exchange.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);\n\t\t\tAssert.state(pathPattern != null, \"'pathPattern' must not be null\");\n\t\t\tif (pathPattern.hasPatternSyntax()) {\n\t\t\t\tString remainingSegments = pathPattern\n\t\t\t\t\t.extractPathWithinPattern(exchange.getRequest().getPath().pathWithinApplication())\n\t\t\t\t\t.value();\n\t\t\t\treturn tokenizePathSegments(remainingSegments);\n\t\t\t}\n\t\t\treturn tokenizePathSegments(pathPattern.toString());\n\t\t}\n\n\t\tprivate String[] tokenizePathSegments(String value) {\n\t\t\tString[] segments = StringUtils.tokenizeToStringArray(value, PATH_SEPARATOR, false, true);\n\t\t\tfor (int i = 0; i < segments.length; i++) {\n\t\t\t\tif (segments[i].contains(\"%\")) {\n\t\t\t\t\tsegments[i] = StringUtils.uriDecode(segments[i], StandardCharsets.UTF_8);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn segments;\n\t\t}\n\n\t\tprivate Map<String, String> getTemplateVariables(ServerWebExchange exchange) {\n\t\t\tMap<String, String> result = exchange.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n\t\t\tAssert.state(result != null, \"'result' must not be null\");\n\t\t\treturn result;\n\t\t}\n\n\t\tprivate Mono<ResponseEntity<Object>> handleResult(@Nullable Publisher<?> result, HttpMethod httpMethod) {\n\t\t\tif (result instanceof Flux) {\n\t\t\t\tresult = ((Flux<?>) result).collectList();\n\t\t\t}\n\t\t\tMono<?> mono = (result != null) ? Mono.from(result) : Mono.empty();\n\t\t\treturn mono.map(this::toResponseEntity)\n\t\t\t\t.onErrorMap(InvalidEndpointRequestException.class,\n\t\t\t\t\t\t(ex) -> new ResponseStatusException(HttpStatus.BAD_REQUEST, ex.getReason()))\n\t\t\t\t.defaultIfEmpty(new ResponseEntity<>(\n\t\t\t\t\t\t(httpMethod != HttpMethod.GET) ? HttpStatus.NO_CONTENT : HttpStatus.NOT_FOUND));\n\t\t}\n\n\t\tprivate ResponseEntity<Object> toResponseEntity(Object response) {\n\t\t\tif (!(response instanceof WebEndpointResponse<?> webEndpointResponse)) {\n\t\t\t\treturn new ResponseEntity<>(response, HttpStatus.OK);\n\t\t\t}\n\t\t\tMediaType contentType = (webEndpointResponse.getContentType() != null)\n\t\t\t\t\t? new MediaType(webEndpointResponse.getContentType()) : null;\n\t\t\tBodyBuilder builder = ResponseEntity.status(webEndpointResponse.getStatus());\n\t\t\tif (contentType != null) {\n\t\t\t\tbuilder = builder.contentType(contentType);\n\t\t\t}\n\t\t\treturn builder.body(webEndpointResponse.getBody());\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator web endpoint '\" + this.operation.getId() + \"'\";\n\t\t}\n\n\t}\n\n\t/**\n\t * Handler for a {@link ReactiveWebOperation}.\n\t */\n\tprivate static final class WriteOperationHandler {\n\n\t\tprivate final ReactiveWebOperation operation;\n\n\t\tWriteOperationHandler(ReactiveWebOperation operation) {\n\t\t\tthis.operation = operation;\n\t\t}\n\n\t\t@ResponseBody\n\t\t@Reflective\n\t\tPublisher<ResponseEntity<Object>> handle(ServerWebExchange exchange,\n\t\t\t\t@RequestBody(required = false) Map<String, String> body) {\n\t\t\treturn this.operation.handle(exchange, body);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.operation.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * Handler for a {@link ReactiveWebOperation}.\n\t */\n\tprivate static final class ReadOperationHandler {\n\n\t\tprivate final ReactiveWebOperation operation;\n\n\t\tReadOperationHandler(ReactiveWebOperation operation) {\n\t\t\tthis.operation = operation;\n\t\t}\n\n\t\t@ResponseBody\n\t\t@Reflective\n\t\tPublisher<ResponseEntity<Object>> handle(ServerWebExchange exchange) {\n\t\t\treturn this.operation.handle(exchange, null);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.operation.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * Catch-all handler that always replies with a fixed HTTP status.\n\t */\n\tprivate static final class CatchAllHandler {\n\n\t\tprivate final HttpStatus responseStatus;\n\n\t\tCatchAllHandler(HttpStatus responseStatus) {\n\t\t\tthis.responseStatus = responseStatus;\n\t\t}\n\n\t\t@Reflective\n\t\tMono<Void> handle(ServerWebExchange exchange) {\n\t\t\tServerHttpResponse response = exchange.getResponse();\n\t\t\tresponse.setStatusCode(this.responseStatus);\n\t\t\treturn response.setComplete();\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator catch-all endpoint\";\n\t\t}\n\n\t}\n\n\tprivate static class WebFluxEndpointHandlerMethod extends HandlerMethod {\n\n\t\tWebFluxEndpointHandlerMethod(Object bean, Method method) {\n\t\t\tsuper(bean, method);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn getBean().toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic HandlerMethod createWithResolvedBean() {\n\t\t\tHandlerMethod handlerMethod = super.createWithResolvedBean();\n\t\t\treturn new WebFluxEndpointHandlerMethod(handlerMethod.getBean(), handlerMethod.getMethod());\n\t\t}\n\n\t}\n\n\tprivate static final class ReactiveSecurityContext implements SecurityContext {\n\n\t\tprivate static final String ROLE_PREFIX = \"ROLE_\";\n\n\t\tprivate final @Nullable Authentication authentication;\n\n\t\tReactiveSecurityContext(@Nullable Authentication authentication) {\n\t\t\tthis.authentication = authentication;\n\t\t}\n\n\t\tprivate @Nullable Authentication getAuthentication() {\n\t\t\treturn this.authentication;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Principal getPrincipal() {\n\t\t\treturn this.authentication;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isUserInRole(String role) {\n\t\t\tString authority = (!role.startsWith(ROLE_PREFIX)) ? ROLE_PREFIX + role : role;\n\t\t\tAuthorizationResult result = AuthorityAuthorizationManager.hasAuthority(authority)\n\t\t\t\t.authorize(this::getAuthentication, new Object());\n\t\t\treturn result != null && result.isGranted();\n\t\t}\n\n\t}\n\n\tstatic class AbstractWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.reflectiveRegistrar.registerRuntimeHints(hints, WriteOperationHandler.class,\n\t\t\t\t\tReadOperationHandler.class, CatchAllHandler.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/endpoint/web/AdditionalHealthEndpointPathsWebFluxHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.result.method.RequestMappingInfo;\n\n/**\n * A custom {@link HandlerMapping} that allows health groups to be mapped to an additional\n * path.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class AdditionalHealthEndpointPathsWebFluxHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {\n\n\tprivate final EndpointMapping endpointMapping;\n\n\tprivate final @Nullable ExposableWebEndpoint healthEndpoint;\n\n\tprivate final Set<HealthEndpointGroup> groups;\n\n\tpublic AdditionalHealthEndpointPathsWebFluxHandlerMapping(EndpointMapping endpointMapping,\n\t\t\t@Nullable ExposableWebEndpoint healthEndpoint, Set<HealthEndpointGroup> groups) {\n\t\tsuper(endpointMapping, asList(healthEndpoint), new EndpointMediaTypes(), null, false);\n\t\tthis.endpointMapping = endpointMapping;\n\t\tthis.groups = groups;\n\t\tthis.healthEndpoint = healthEndpoint;\n\t}\n\n\tprivate static Collection<ExposableWebEndpoint> asList(@Nullable ExposableWebEndpoint healthEndpoint) {\n\t\treturn (healthEndpoint != null) ? Collections.singletonList(healthEndpoint) : Collections.emptyList();\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tif (this.healthEndpoint == null) {\n\t\t\treturn;\n\t\t}\n\t\tfor (WebOperation operation : this.healthEndpoint.getOperations()) {\n\t\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\t\tString matchAllRemainingPathSegmentsVariable = predicate.getMatchAllRemainingPathSegmentsVariable();\n\t\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\t\tfor (HealthEndpointGroup group : this.groups) {\n\t\t\t\t\tAdditionalHealthEndpointPath additionalPath = group.getAdditionalPath();\n\t\t\t\t\tif (additionalPath != null) {\n\t\t\t\t\t\tRequestMappingInfo requestMappingInfo = getRequestMappingInfo(operation,\n\t\t\t\t\t\t\t\tadditionalPath.getValue());\n\t\t\t\t\t\tregisterReadMapping(requestMappingInfo, this.healthEndpoint, operation);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate RequestMappingInfo getRequestMappingInfo(WebOperation operation, String additionalPath) {\n\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\tString path = this.endpointMapping.createSubPath(additionalPath);\n\t\tRequestMethod method = RequestMethod.valueOf(predicate.getHttpMethod().name());\n\t\tString[] consumes = StringUtils.toStringArray(predicate.getConsumes());\n\t\tString[] produces = StringUtils.toStringArray(predicate.getProduces());\n\t\treturn RequestMappingInfo.paths(path).methods(method).consumes(consumes).produces(produces).build();\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn (exchange) -> Mono.empty();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/endpoint/web/ControllerEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.result.method.RequestMappingInfo;\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.util.pattern.PathPattern;\n\n/**\n * {@link HandlerMapping} that exposes\n * {@link org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint @ControllerEndpoint}\n * and\n * {@link org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint @RestControllerEndpoint}\n * annotated endpoints over Spring WebFlux.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.5\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ControllerEndpointHandlerMapping extends RequestMappingHandlerMapping {\n\n\tprivate static final Set<RequestMethod> READ_ONLY_ACCESS_REQUEST_METHODS = EnumSet.of(RequestMethod.GET,\n\t\t\tRequestMethod.HEAD);\n\n\tprivate final EndpointMapping endpointMapping;\n\n\tprivate final @Nullable CorsConfiguration corsConfiguration;\n\n\tprivate final Map<Object, ExposableControllerEndpoint> handlers;\n\n\tprivate final EndpointAccessResolver accessResolver;\n\n\t/**\n\t * Create a new {@link ControllerEndpointHandlerMapping} instance providing mappings\n\t * for the specified endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t */\n\tpublic ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableControllerEndpoint> endpoints, @Nullable CorsConfiguration corsConfiguration) {\n\t\tthis(endpointMapping, endpoints, corsConfiguration, (endpointId, defaultAccess) -> Access.NONE);\n\t}\n\n\t/**\n\t * Create a new {@link ControllerEndpointHandlerMapping} instance providing mappings\n\t * for the specified endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t * @param endpointAccessResolver resolver for endpoint access\n\t */\n\tpublic ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableControllerEndpoint> endpoints, @Nullable CorsConfiguration corsConfiguration,\n\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\tAssert.notNull(endpointMapping, \"'endpointMapping' must not be null\");\n\t\tAssert.notNull(endpoints, \"'endpoints' must not be null\");\n\t\tthis.endpointMapping = endpointMapping;\n\t\tthis.handlers = getHandlers(endpoints);\n\t\tthis.corsConfiguration = corsConfiguration;\n\t\tthis.accessResolver = endpointAccessResolver;\n\t\tsetOrder(-100);\n\t}\n\n\tprivate Map<Object, ExposableControllerEndpoint> getHandlers(Collection<ExposableControllerEndpoint> endpoints) {\n\t\tMap<Object, ExposableControllerEndpoint> handlers = new LinkedHashMap<>();\n\t\tendpoints.forEach((endpoint) -> handlers.put(endpoint.getController(), endpoint));\n\t\treturn Collections.unmodifiableMap(handlers);\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tthis.handlers.keySet().forEach(this::detectHandlerMethods);\n\t}\n\n\t@Override\n\tprotected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {\n\t\tExposableControllerEndpoint endpoint = this.handlers.get(handler);\n\t\tAssert.state(endpoint != null, \"'endpoint' must not be null\");\n\t\tAccess access = this.accessResolver.accessFor(endpoint.getEndpointId(), endpoint.getDefaultAccess());\n\t\tif (access == Access.NONE) {\n\t\t\treturn;\n\t\t}\n\t\tif (access == Access.READ_ONLY) {\n\t\t\tmapping = withReadOnlyAccess(access, mapping);\n\t\t\tif (CollectionUtils.isEmpty(mapping.getMethodsCondition().getMethods())) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tmapping = withEndpointMappedPatterns(endpoint, mapping);\n\t\tsuper.registerHandlerMethod(handler, method, mapping);\n\t}\n\n\tprivate RequestMappingInfo withReadOnlyAccess(Access access, RequestMappingInfo mapping) {\n\t\tSet<RequestMethod> methods = new HashSet<>(mapping.getMethodsCondition().getMethods());\n\t\tif (methods.isEmpty()) {\n\t\t\tmethods.addAll(READ_ONLY_ACCESS_REQUEST_METHODS);\n\t\t}\n\t\telse {\n\t\t\tmethods.retainAll(READ_ONLY_ACCESS_REQUEST_METHODS);\n\t\t}\n\t\treturn mapping.mutate().methods(methods.toArray(new RequestMethod[0])).build();\n\t}\n\n\tprivate RequestMappingInfo withEndpointMappedPatterns(ExposableControllerEndpoint endpoint,\n\t\t\tRequestMappingInfo mapping) {\n\t\tSet<PathPattern> patterns = mapping.getPatternsCondition().getPatterns();\n\t\tif (patterns.isEmpty()) {\n\t\t\tpatterns = Collections.singleton(getPathPatternParser().parse(\"\"));\n\t\t}\n\t\tString[] endpointMappedPatterns = patterns.stream()\n\t\t\t.map((pattern) -> getEndpointMappedPattern(endpoint, pattern))\n\t\t\t.toArray(String[]::new);\n\t\treturn mapping.mutate().paths(endpointMappedPatterns).build();\n\t}\n\n\tprivate String getEndpointMappedPattern(ExposableControllerEndpoint endpoint, PathPattern pattern) {\n\t\treturn this.endpointMapping.createSubPath(endpoint.getRootPath() + pattern);\n\t}\n\n\t@Override\n\tprotected boolean hasCorsConfigurationSource(Object handler) {\n\t\treturn this.corsConfiguration != null;\n\t}\n\n\t@Override\n\tprotected @Nullable CorsConfiguration initCorsConfiguration(Object handler, Method method,\n\t\t\tRequestMappingInfo mapping) {\n\t\treturn this.corsConfiguration;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/endpoint/web/WebFluxEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.util.UriComponentsBuilder;\n\n/**\n * A custom {@link HandlerMapping} that makes web endpoints available over HTTP using\n * Spring WebFlux.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Brian Clozel\n * @since 4.0.0\n */\n@ImportRuntimeHints(WebFluxEndpointHandlerMappingRuntimeHints.class)\npublic class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping implements InitializingBean {\n\n\tprivate final EndpointLinksResolver linksResolver;\n\n\t/**\n\t * Creates a new {@code WebFluxEndpointHandlerMapping} instance that provides mappings\n\t * for the given endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param endpointMediaTypes media types consumed and produced by the endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t * @param linksResolver resolver for determining links to available endpoints\n\t * @param shouldRegisterLinksMapping whether the links endpoint should be registered\n\t */\n\tpublic WebFluxEndpointHandlerMapping(EndpointMapping endpointMapping, Collection<ExposableWebEndpoint> endpoints,\n\t\t\tEndpointMediaTypes endpointMediaTypes, @Nullable CorsConfiguration corsConfiguration,\n\t\t\tEndpointLinksResolver linksResolver, boolean shouldRegisterLinksMapping) {\n\t\tsuper(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping);\n\t\tthis.linksResolver = linksResolver;\n\t\tsetOrder(-100);\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn new WebFluxLinksHandler();\n\t}\n\n\t/**\n\t * Handler for root endpoint providing links.\n\t */\n\tclass WebFluxLinksHandler implements LinksHandler {\n\n\t\t@Override\n\t\t@ResponseBody\n\t\t@Reflective\n\t\tpublic Map<String, Map<String, Link>> links(ServerWebExchange exchange) {\n\t\t\tString requestUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI())\n\t\t\t\t.replaceQuery(null)\n\t\t\t\t.toUriString();\n\t\t\tMap<String, Link> links = WebFluxEndpointHandlerMapping.this.linksResolver.resolveLinks(requestUri);\n\t\t\treturn OperationResponseBody.of(Collections.singletonMap(\"_links\", links));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator root web endpoint\";\n\t\t}\n\n\t}\n\n\tstatic class WebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.reflectiveRegistrar.registerRuntimeHints(hints, WebFluxLinksHandler.class);\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring WebFlux support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/exchanges/HttpExchangesWebFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport java.security.Principal;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.core.Ordered;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebFilter;\nimport org.springframework.web.server.WebFilterChain;\nimport org.springframework.web.server.WebSession;\n\n/**\n * A {@link WebFilter} for recording {@link HttpExchange HTTP exchanges}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class HttpExchangesWebFilter implements WebFilter, Ordered {\n\n\tprivate static final Object NONE = new Object();\n\n\t// Not LOWEST_PRECEDENCE, but near the end, so it has a good chance of catching all\n\t// enriched headers, but users can add stuff after this if they want to\n\tprivate int order = Ordered.LOWEST_PRECEDENCE - 10;\n\n\tprivate final HttpExchangeRepository repository;\n\n\tprivate final Set<Include> includes;\n\n\t/**\n\t * Create a new {@link HttpExchangesWebFilter} instance.\n\t * @param repository the repository used to record events\n\t * @param includes the include options\n\t */\n\tpublic HttpExchangesWebFilter(HttpExchangeRepository repository, Set<Include> includes) {\n\t\tthis.repository = repository;\n\t\tthis.includes = includes;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\tMono<?> principal = exchange.getPrincipal().cast(Object.class).defaultIfEmpty(NONE);\n\t\tMono<Object> session = exchange.getSession().cast(Object.class).defaultIfEmpty(NONE);\n\t\treturn Mono.zip(PrincipalAndSession::new, principal, session)\n\t\t\t.flatMap((principalAndSession) -> filter(exchange, chain, principalAndSession));\n\t}\n\n\tprivate Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain,\n\t\t\tPrincipalAndSession principalAndSession) {\n\t\treturn Mono.fromRunnable(() -> addExchangeOnCommit(exchange, principalAndSession)).and(chain.filter(exchange));\n\t}\n\n\tprivate void addExchangeOnCommit(ServerWebExchange exchange, PrincipalAndSession principalAndSession) {\n\t\tRecordableServerHttpRequest sourceRequest = new RecordableServerHttpRequest(exchange.getRequest());\n\t\tHttpExchange.Started startedHttpExchange = HttpExchange.start(sourceRequest);\n\t\texchange.getResponse().beforeCommit(() -> {\n\t\t\tRecordableServerHttpResponse sourceResponse = new RecordableServerHttpResponse(exchange.getResponse());\n\t\t\tHttpExchange finishedExchange = startedHttpExchange.finish(sourceResponse,\n\t\t\t\t\tprincipalAndSession::getPrincipal, principalAndSession::getSessionId, this.includes);\n\t\t\tthis.repository.add(finishedExchange);\n\t\t\treturn Mono.empty();\n\t\t});\n\t}\n\n\t/**\n\t * A {@link Principal} and {@link WebSession}.\n\t */\n\tprivate static class PrincipalAndSession {\n\n\t\tprivate final @Nullable Principal principal;\n\n\t\tprivate final @Nullable WebSession session;\n\n\t\tPrincipalAndSession(Object[] zipped) {\n\t\t\tthis.principal = (zipped[0] != NONE) ? (Principal) zipped[0] : null;\n\t\t\tthis.session = (zipped[1] != NONE) ? (WebSession) zipped[1] : null;\n\t\t}\n\n\t\t@Nullable Principal getPrincipal() {\n\t\t\treturn this.principal;\n\t\t}\n\n\t\t@Nullable String getSessionId() {\n\t\t\treturn (this.session != null && this.session.isStarted()) ? this.session.getId() : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/exchanges/RecordableServerHttpRequest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.URI;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.web.exchanges.RecordableHttpRequest;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\n\n/**\n * A {@link RecordableHttpRequest} backed by a {@link ServerHttpRequest}.\n *\n * @author Andy Wilkinson\n */\nclass RecordableServerHttpRequest implements RecordableHttpRequest {\n\n\tprivate final String method;\n\n\tprivate final HttpHeaders headers;\n\n\tprivate final URI uri;\n\n\tprivate final @Nullable String remoteAddress;\n\n\tRecordableServerHttpRequest(ServerHttpRequest request) {\n\t\tthis.method = request.getMethod().name();\n\t\tthis.headers = request.getHeaders();\n\t\tthis.uri = request.getURI();\n\t\tthis.remoteAddress = getRemoteAddress(request);\n\t}\n\n\tprivate static @Nullable String getRemoteAddress(ServerHttpRequest request) {\n\t\tInetSocketAddress remoteAddress = request.getRemoteAddress();\n\t\tInetAddress address = (remoteAddress != null) ? remoteAddress.getAddress() : null;\n\t\treturn (address != null) ? address.toString() : null;\n\t}\n\n\t@Override\n\tpublic String getMethod() {\n\t\treturn this.method;\n\t}\n\n\t@Override\n\tpublic URI getUri() {\n\t\treturn this.uri;\n\t}\n\n\t@Override\n\tpublic Map<String, List<String>> getHeaders() {\n\t\tMap<String, List<String>> headers = new LinkedHashMap<>();\n\t\tthis.headers.forEach(headers::put);\n\t\treturn Collections.unmodifiableMap(headers);\n\t}\n\n\t@Override\n\tpublic @Nullable String getRemoteAddress() {\n\t\treturn this.remoteAddress;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/exchanges/RecordableServerHttpResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.boot.actuate.web.exchanges.RecordableHttpResponse;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\n\n/**\n * An adapter that exposes a {@link ServerHttpResponse} as a\n * {@link RecordableHttpResponse}.\n *\n * @author Andy Wilkinson\n */\nclass RecordableServerHttpResponse implements RecordableHttpResponse {\n\n\tprivate final int status;\n\n\tprivate final Map<String, List<String>> headers;\n\n\tRecordableServerHttpResponse(ServerHttpResponse response) {\n\t\tthis.status = (response.getStatusCode() != null) ? response.getStatusCode().value() : HttpStatus.OK.value();\n\t\tMap<String, List<String>> headers = new LinkedHashMap<>();\n\t\tresponse.getHeaders().forEach(headers::put);\n\t\tthis.headers = Collections.unmodifiableMap(headers);\n\t}\n\n\t@Override\n\tpublic int getStatus() {\n\t\treturn this.status;\n\t}\n\n\t@Override\n\tpublic Map<String, List<String>> getHeaders() {\n\t\treturn this.headers;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/exchanges/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator HTTP exchanges support for reactive servers.\n *\n * @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository\n */\n@NullMarked\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/mappings/DispatcherHandlerMappingDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.reactive.DispatcherHandler;\n\n/**\n * A description of a mapping known to a {@link DispatcherHandler}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class DispatcherHandlerMappingDescription {\n\n\tprivate final String predicate;\n\n\tprivate final String handler;\n\n\tprivate final @Nullable DispatcherHandlerMappingDetails details;\n\n\tDispatcherHandlerMappingDescription(String predicate, String handler,\n\t\t\t@Nullable DispatcherHandlerMappingDetails details) {\n\t\tthis.predicate = predicate;\n\t\tthis.handler = handler;\n\t\tthis.details = details;\n\t}\n\n\tpublic String getHandler() {\n\t\treturn this.handler;\n\t}\n\n\tpublic String getPredicate() {\n\t\treturn this.predicate;\n\t}\n\n\tpublic @Nullable DispatcherHandlerMappingDetails getDetails() {\n\t\treturn this.details;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/mappings/DispatcherHandlerMappingDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;\nimport org.springframework.web.reactive.DispatcherHandler;\n\n/**\n * Details of a {@link DispatcherHandler} mapping.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class DispatcherHandlerMappingDetails {\n\n\tprivate @Nullable HandlerMethodDescription handlerMethod;\n\n\tprivate @Nullable HandlerFunctionDescription handlerFunction;\n\n\tprivate @Nullable RequestMappingConditionsDescription requestMappingConditions;\n\n\tpublic @Nullable HandlerMethodDescription getHandlerMethod() {\n\t\treturn this.handlerMethod;\n\t}\n\n\tvoid setHandlerMethod(@Nullable HandlerMethodDescription handlerMethod) {\n\t\tthis.handlerMethod = handlerMethod;\n\t}\n\n\tpublic @Nullable HandlerFunctionDescription getHandlerFunction() {\n\t\treturn this.handlerFunction;\n\t}\n\n\tvoid setHandlerFunction(@Nullable HandlerFunctionDescription handlerFunction) {\n\t\tthis.handlerFunction = handlerFunction;\n\t}\n\n\tpublic @Nullable RequestMappingConditionsDescription getRequestMappingConditions() {\n\t\treturn this.requestMappingConditions;\n\t}\n\n\tvoid setRequestMappingConditions(@Nullable RequestMappingConditionsDescription requestMappingConditions) {\n\t\tthis.requestMappingConditions = requestMappingConditions;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/mappings/DispatcherHandlersMappingDescriptionProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlersMappingDescriptionProvider.DispatcherHandlersMappingDescriptionProviderRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.io.Resource;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.reactive.DispatcherHandler;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.function.server.HandlerFunction;\nimport org.springframework.web.reactive.function.server.RequestPredicate;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions.Visitor;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.support.RouterFunctionMapping;\nimport org.springframework.web.reactive.handler.AbstractUrlHandlerMapping;\nimport org.springframework.web.reactive.result.method.RequestMappingInfo;\nimport org.springframework.web.reactive.result.method.RequestMappingInfoHandlerMapping;\nimport org.springframework.web.util.pattern.PathPattern;\n\n/**\n * A {@link MappingDescriptionProvider} that introspects the {@link HandlerMapping\n * HandlerMappings} that are known to a {@link DispatcherHandler}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@ImportRuntimeHints(DispatcherHandlersMappingDescriptionProviderRuntimeHints.class)\npublic class DispatcherHandlersMappingDescriptionProvider implements MappingDescriptionProvider {\n\n\tprivate static final List<HandlerMappingDescriptionProvider<? extends HandlerMapping>> descriptionProviders = Arrays\n\t\t.asList(new RequestMappingInfoHandlerMappingDescriptionProvider(), new UrlHandlerMappingDescriptionProvider(),\n\t\t\t\tnew RouterFunctionMappingDescriptionProvider());\n\n\t@Override\n\tpublic String getMappingName() {\n\t\treturn \"dispatcherHandlers\";\n\t}\n\n\t@Override\n\tpublic Map<String, List<DispatcherHandlerMappingDescription>> describeMappings(ApplicationContext context) {\n\t\tMap<String, List<DispatcherHandlerMappingDescription>> mappings = new HashMap<>();\n\t\tcontext.getBeansOfType(DispatcherHandler.class)\n\t\t\t.forEach((name, handler) -> mappings.put(name, describeMappings(handler)));\n\t\treturn mappings;\n\t}\n\n\tprivate List<DispatcherHandlerMappingDescription> describeMappings(DispatcherHandler dispatcherHandler) {\n\t\tList<HandlerMapping> handlerMappings = dispatcherHandler.getHandlerMappings();\n\t\tif (handlerMappings == null) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t\treturn handlerMappings.stream().flatMap(this::describe).toList();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T extends HandlerMapping> Stream<DispatcherHandlerMappingDescription> describe(T handlerMapping) {\n\t\tfor (HandlerMappingDescriptionProvider<?> descriptionProvider : descriptionProviders) {\n\t\t\tif (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {\n\t\t\t\treturn ((HandlerMappingDescriptionProvider<T>) descriptionProvider).describe(handlerMapping).stream();\n\t\t\t}\n\t\t}\n\t\treturn Stream.empty();\n\t}\n\n\tprivate interface HandlerMappingDescriptionProvider<T extends HandlerMapping> {\n\n\t\tClass<T> getMappingClass();\n\n\t\tList<DispatcherHandlerMappingDescription> describe(T handlerMapping);\n\n\t}\n\n\tprivate static final class RequestMappingInfoHandlerMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<RequestMappingInfoHandlerMapping> {\n\n\t\t@Override\n\t\tpublic Class<RequestMappingInfoHandlerMapping> getMappingClass() {\n\t\t\treturn RequestMappingInfoHandlerMapping.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherHandlerMappingDescription> describe(RequestMappingInfoHandlerMapping handlerMapping) {\n\t\t\tMap<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();\n\t\t\treturn handlerMethods.entrySet().stream().map(this::describe).toList();\n\t\t}\n\n\t\tprivate DispatcherHandlerMappingDescription describe(Entry<RequestMappingInfo, HandlerMethod> mapping) {\n\t\t\tDispatcherHandlerMappingDetails handlerMapping = new DispatcherHandlerMappingDetails();\n\t\t\thandlerMapping.setHandlerMethod(new HandlerMethodDescription(mapping.getValue()));\n\t\t\thandlerMapping.setRequestMappingConditions(new RequestMappingConditionsDescription(mapping.getKey()));\n\t\t\treturn new DispatcherHandlerMappingDescription(mapping.getKey().toString(), mapping.getValue().toString(),\n\t\t\t\t\thandlerMapping);\n\t\t}\n\n\t}\n\n\tprivate static final class UrlHandlerMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<AbstractUrlHandlerMapping> {\n\n\t\t@Override\n\t\tpublic Class<AbstractUrlHandlerMapping> getMappingClass() {\n\t\t\treturn AbstractUrlHandlerMapping.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherHandlerMappingDescription> describe(AbstractUrlHandlerMapping handlerMapping) {\n\t\t\treturn handlerMapping.getHandlerMap().entrySet().stream().map(this::describe).toList();\n\t\t}\n\n\t\tprivate DispatcherHandlerMappingDescription describe(Entry<PathPattern, Object> mapping) {\n\t\t\treturn new DispatcherHandlerMappingDescription(mapping.getKey().getPatternString(),\n\t\t\t\t\tmapping.getValue().toString(), null);\n\t\t}\n\n\t}\n\n\tprivate static final class RouterFunctionMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<RouterFunctionMapping> {\n\n\t\t@Override\n\t\tpublic Class<RouterFunctionMapping> getMappingClass() {\n\t\t\treturn RouterFunctionMapping.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherHandlerMappingDescription> describe(RouterFunctionMapping handlerMapping) {\n\t\t\tMappingDescriptionVisitor visitor = new MappingDescriptionVisitor();\n\t\t\tRouterFunction<?> routerFunction = handlerMapping.getRouterFunction();\n\t\t\tif (routerFunction != null) {\n\t\t\t\trouterFunction.accept(visitor);\n\t\t\t}\n\t\t\treturn visitor.descriptions;\n\t\t}\n\n\t}\n\n\tprivate static final class MappingDescriptionVisitor implements Visitor {\n\n\t\tprivate final List<DispatcherHandlerMappingDescription> descriptions = new ArrayList<>();\n\n\t\tprivate Deque<RequestPredicate> predicates = new ArrayDeque<>();\n\n\t\t@Override\n\t\tpublic void startNested(RequestPredicate predicate) {\n\t\t\tthis.predicates.addLast(predicate);\n\t\t}\n\n\t\t@Override\n\t\tpublic void endNested(RequestPredicate predicate) {\n\t\t\tthis.predicates.removeLast();\n\t\t}\n\n\t\t@Override\n\t\tpublic void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction) {\n\t\t\tDispatcherHandlerMappingDetails details = new DispatcherHandlerMappingDetails();\n\t\t\tdetails.setHandlerFunction(new HandlerFunctionDescription(handlerFunction));\n\t\t\tRequestPredicate reduced = this.predicates.stream()\n\t\t\t\t.reduce(RequestPredicate::and)\n\t\t\t\t.map((all) -> all.and(predicate))\n\t\t\t\t.orElse(predicate);\n\t\t\tthis.descriptions\n\t\t\t\t.add(new DispatcherHandlerMappingDescription(reduced.toString(), handlerFunction.toString(), details));\n\t\t}\n\n\t\t@Override\n\t\tpublic void resources(Function<ServerRequest, Mono<Resource>> lookupFunction) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void attributes(Map<String, Object> attributes) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void unknown(RouterFunction<?> routerFunction) {\n\t\t}\n\n\t}\n\n\tstatic class DispatcherHandlersMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(),\n\t\t\t\t\tDispatcherHandlerMappingDescription.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/mappings/HandlerFunctionDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport org.springframework.web.reactive.function.server.HandlerFunction;\n\n/**\n * Description of a {@link HandlerFunction}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class HandlerFunctionDescription {\n\n\tprivate final String className;\n\n\tHandlerFunctionDescription(HandlerFunction<?> handlerFunction) {\n\t\tthis.className = getHandlerFunctionClassName(handlerFunction);\n\t}\n\n\tprivate static String getHandlerFunctionClassName(HandlerFunction<?> handlerFunction) {\n\t\tClass<?> functionClass = handlerFunction.getClass();\n\t\tString canonicalName = functionClass.getCanonicalName();\n\t\treturn (canonicalName != null) ? canonicalName : functionClass.getName();\n\t}\n\n\tpublic String getClassName() {\n\t\treturn this.className;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/mappings/RequestMappingConditionsDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.reactive.result.condition.MediaTypeExpression;\nimport org.springframework.web.reactive.result.condition.NameValueExpression;\nimport org.springframework.web.reactive.result.method.RequestMappingInfo;\nimport org.springframework.web.util.pattern.PathPattern;\n\n/**\n * Description of the conditions of a {@link RequestMappingInfo}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class RequestMappingConditionsDescription {\n\n\tprivate final List<MediaTypeExpressionDescription> consumes;\n\n\tprivate final List<NameValueExpressionDescription> headers;\n\n\tprivate final Set<RequestMethod> methods;\n\n\tprivate final List<NameValueExpressionDescription> params;\n\n\tprivate final Set<String> patterns;\n\n\tprivate final List<MediaTypeExpressionDescription> produces;\n\n\tRequestMappingConditionsDescription(RequestMappingInfo requestMapping) {\n\t\tthis.consumes = requestMapping.getConsumesCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(MediaTypeExpressionDescription::new)\n\t\t\t.toList();\n\t\tthis.headers = requestMapping.getHeadersCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(NameValueExpressionDescription::new)\n\t\t\t.toList();\n\t\tthis.methods = requestMapping.getMethodsCondition().getMethods();\n\t\tthis.params = requestMapping.getParamsCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(NameValueExpressionDescription::new)\n\t\t\t.toList();\n\t\tthis.patterns = requestMapping.getPatternsCondition()\n\t\t\t.getPatterns()\n\t\t\t.stream()\n\t\t\t.map(PathPattern::getPatternString)\n\t\t\t.collect(Collectors.collectingAndThen(Collectors.toSet(), Collections::unmodifiableSet));\n\t\tthis.produces = requestMapping.getProducesCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(MediaTypeExpressionDescription::new)\n\t\t\t.toList();\n\t}\n\n\tpublic List<MediaTypeExpressionDescription> getConsumes() {\n\t\treturn this.consumes;\n\t}\n\n\tpublic List<NameValueExpressionDescription> getHeaders() {\n\t\treturn this.headers;\n\t}\n\n\tpublic Set<RequestMethod> getMethods() {\n\t\treturn this.methods;\n\t}\n\n\tpublic List<NameValueExpressionDescription> getParams() {\n\t\treturn this.params;\n\t}\n\n\tpublic Set<String> getPatterns() {\n\t\treturn this.patterns;\n\t}\n\n\tpublic List<MediaTypeExpressionDescription> getProduces() {\n\t\treturn this.produces;\n\t}\n\n\t/**\n\t * A description of a {@link MediaTypeExpression} in a request mapping condition.\n\t */\n\tpublic static class MediaTypeExpressionDescription {\n\n\t\tprivate final String mediaType;\n\n\t\tprivate final boolean negated;\n\n\t\tMediaTypeExpressionDescription(MediaTypeExpression expression) {\n\t\t\tthis.mediaType = expression.getMediaType().toString();\n\t\t\tthis.negated = expression.isNegated();\n\t\t}\n\n\t\tpublic String getMediaType() {\n\t\t\treturn this.mediaType;\n\t\t}\n\n\t\tpublic boolean isNegated() {\n\t\t\treturn this.negated;\n\t\t}\n\n\t}\n\n\t/**\n\t * A description of a {@link NameValueExpression} in a request mapping condition.\n\t */\n\tpublic static class NameValueExpressionDescription {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable Object value;\n\n\t\tprivate final boolean negated;\n\n\t\tNameValueExpressionDescription(NameValueExpression<?> expression) {\n\t\t\tthis.name = expression.getName();\n\t\t\tthis.value = expression.getValue();\n\t\t\tthis.negated = expression.isNegated();\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic @Nullable Object getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tpublic boolean isNegated() {\n\t\t\treturn this.negated;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator reactive request mappings support.\n */\n@NullMarked\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/HttpHandlerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.server.reactive.ContextPathCompositeHandler;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.reactive.DispatcherHandler;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HttpHandler}.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@AutoConfiguration(after = { WebFluxAutoConfiguration.class })\n@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnMissingBean(HttpHandler.class)\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)\npublic final class HttpHandlerAutoConfiguration {\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AnnotationConfig {\n\n\t\tprivate final ApplicationContext applicationContext;\n\n\t\tAnnotationConfig(ApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider,\n\t\t\t\tObjectProvider<WebHttpHandlerBuilderCustomizer> handlerBuilderCustomizers) {\n\t\t\tWebFluxProperties properties = propsProvider.getIfAvailable();\n\t\t\tWebHttpHandlerBuilder handlerBuilder = WebHttpHandlerBuilder.applicationContext(this.applicationContext);\n\t\t\tif (properties != null) {\n\t\t\t\thandlerBuilder.defaultHtmlEscape(properties.getDefaultHtmlEscape());\n\t\t\t}\n\t\t\thandlerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(handlerBuilder));\n\t\t\tHttpHandler httpHandler = handlerBuilder.build();\n\t\t\tif (properties != null && StringUtils.hasText(properties.getBasePath())) {\n\t\t\t\tMap<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);\n\t\t\t\treturn new ContextPathCompositeHandler(handlersMap);\n\t\t\t}\n\t\t\treturn httpHandler;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/ProblemDetailsExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.reactive.result.method.annotation.ResponseEntityExceptionHandler;\n\n/**\n * {@code @ControllerAdvice} annotated {@link ResponseEntityExceptionHandler} that is\n * auto-configured for problem details support.\n *\n * @author Brian Clozel\n */\n@ControllerAdvice\nclass ProblemDetailsExceptionHandler extends ResponseEntityExceptionHandler {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/ReactiveMultipartAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.io.IOException;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;\nimport org.springframework.http.codec.multipart.PartEventHttpMessageReader;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for multipart support in Spring\n * WebFlux.\n *\n * @author Chris Bono\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ DefaultPartHttpMessageReader.class, WebFluxConfigurer.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties(ReactiveMultipartProperties.class)\npublic final class ReactiveMultipartAutoConfiguration {\n\n\t@Bean\n\t@Order(0)\n\tCodecCustomizer defaultPartHttpMessageReaderCustomizer(ReactiveMultipartProperties multipartProperties) {\n\t\treturn (configurer) -> configurer.defaultCodecs().configureDefaultCodec((codec) -> {\n\t\t\tif (codec instanceof DefaultPartHttpMessageReader defaultPartHttpMessageReader) {\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(multipartProperties::getMaxInMemorySize)\n\t\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t\t.to(defaultPartHttpMessageReader::setMaxInMemorySize);\n\t\t\t\tmap.from(multipartProperties::getMaxHeadersSize)\n\t\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t\t.to(defaultPartHttpMessageReader::setMaxHeadersSize);\n\t\t\t\tmap.from(multipartProperties::getMaxDiskUsagePerPart)\n\t\t\t\t\t.as(DataSize::toBytes)\n\t\t\t\t\t.to(defaultPartHttpMessageReader::setMaxDiskUsagePerPart);\n\t\t\t\tmap.from(multipartProperties::getMaxParts).to(defaultPartHttpMessageReader::setMaxParts);\n\t\t\t\tmap.from(multipartProperties::getFileStorageDirectory)\n\t\t\t\t\t.as(Paths::get)\n\t\t\t\t\t.to((dir) -> configureFileStorageDirectory(defaultPartHttpMessageReader, dir));\n\t\t\t\tmap.from(multipartProperties::getHeadersCharset).to(defaultPartHttpMessageReader::setHeadersCharset);\n\t\t\t}\n\t\t\telse if (codec instanceof PartEventHttpMessageReader partEventHttpMessageReader) {\n\t\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\t\tmap.from(multipartProperties::getMaxInMemorySize)\n\t\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t\t.to(partEventHttpMessageReader::setMaxInMemorySize);\n\t\t\t\tmap.from(multipartProperties::getMaxHeadersSize)\n\t\t\t\t\t.asInt(DataSize::toBytes)\n\t\t\t\t\t.to(partEventHttpMessageReader::setMaxHeadersSize);\n\t\t\t\tmap.from(multipartProperties::getMaxDiskUsagePerPart)\n\t\t\t\t\t.as(DataSize::toBytes)\n\t\t\t\t\t.to(partEventHttpMessageReader::setMaxPartSize);\n\t\t\t\tmap.from(multipartProperties::getMaxParts).to(partEventHttpMessageReader::setMaxParts);\n\t\t\t\tmap.from(multipartProperties::getHeadersCharset).to(partEventHttpMessageReader::setHeadersCharset);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate void configureFileStorageDirectory(DefaultPartHttpMessageReader defaultPartHttpMessageReader,\n\t\t\tPath fileStorageDirectory) {\n\t\ttry {\n\t\t\tdefaultPartHttpMessageReader.setFileStorageDirectory(fileStorageDirectory);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to configure multipart file storage directory\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/ReactiveMultipartProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;\nimport org.springframework.http.codec.multipart.PartEventHttpMessageReader;\nimport org.springframework.util.unit.DataSize;\n\n/**\n * {@link ConfigurationProperties Configuration properties} for configuring multipart\n * support in Spring Webflux. Used to configure the {@link DefaultPartHttpMessageReader}\n * and the {@link PartEventHttpMessageReader}.\n *\n * @author Chris Bono\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.webflux.multipart\")\npublic class ReactiveMultipartProperties {\n\n\t/**\n\t * Maximum amount of memory allowed per part before it's written to disk. Set to -1 to\n\t * store all contents in memory.\n\t */\n\tprivate DataSize maxInMemorySize = DataSize.ofKilobytes(256);\n\n\t/**\n\t * Maximum amount of memory allowed per headers section of each part. Set to -1 to\n\t * enforce no limits.\n\t */\n\tprivate DataSize maxHeadersSize = DataSize.ofKilobytes(10);\n\n\t/**\n\t * Maximum amount of disk space allowed per part. Default is -1 which enforces no\n\t * limits.\n\t */\n\tprivate DataSize maxDiskUsagePerPart = DataSize.ofBytes(-1);\n\n\t/**\n\t * Maximum number of parts allowed in a given multipart request. Default is -1 which\n\t * enforces no limits.\n\t */\n\tprivate Integer maxParts = -1;\n\n\t/**\n\t * Directory used to store file parts larger than 'maxInMemorySize'. Default is a\n\t * directory named 'spring-multipart' created under the system temporary directory.\n\t * Ignored when using the PartEvent streaming support.\n\t */\n\tprivate @Nullable String fileStorageDirectory;\n\n\t/**\n\t * Character set used to decode headers.\n\t */\n\tprivate Charset headersCharset = StandardCharsets.UTF_8;\n\n\tpublic DataSize getMaxInMemorySize() {\n\t\treturn this.maxInMemorySize;\n\t}\n\n\tpublic void setMaxInMemorySize(DataSize maxInMemorySize) {\n\t\tthis.maxInMemorySize = maxInMemorySize;\n\t}\n\n\tpublic DataSize getMaxHeadersSize() {\n\t\treturn this.maxHeadersSize;\n\t}\n\n\tpublic void setMaxHeadersSize(DataSize maxHeadersSize) {\n\t\tthis.maxHeadersSize = maxHeadersSize;\n\t}\n\n\tpublic DataSize getMaxDiskUsagePerPart() {\n\t\treturn this.maxDiskUsagePerPart;\n\t}\n\n\tpublic void setMaxDiskUsagePerPart(DataSize maxDiskUsagePerPart) {\n\t\tthis.maxDiskUsagePerPart = maxDiskUsagePerPart;\n\t}\n\n\tpublic Integer getMaxParts() {\n\t\treturn this.maxParts;\n\t}\n\n\tpublic void setMaxParts(Integer maxParts) {\n\t\tthis.maxParts = maxParts;\n\t}\n\n\tpublic @Nullable String getFileStorageDirectory() {\n\t\treturn this.fileStorageDirectory;\n\t}\n\n\tpublic void setFileStorageDirectory(@Nullable String fileStorageDirectory) {\n\t\tthis.fileStorageDirectory = fileStorageDirectory;\n\t}\n\n\tpublic Charset getHeadersCharset() {\n\t\treturn this.headersCharset;\n\t}\n\n\tpublic void setHeadersCharset(Charset headersCharset) {\n\t\tthis.headersCharset = headersCharset;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/ResourceChainResourceHandlerRegistrationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.util.Assert;\nimport org.springframework.web.reactive.config.ResourceChainRegistration;\nimport org.springframework.web.reactive.config.ResourceHandlerRegistration;\nimport org.springframework.web.reactive.resource.EncodedResourceResolver;\nimport org.springframework.web.reactive.resource.ResourceResolver;\nimport org.springframework.web.reactive.resource.VersionResourceResolver;\n\n/**\n * {@link ResourceHandlerRegistrationCustomizer} used by auto-configuration to customize\n * the resource chain.\n *\n * @author Brian Clozel\n */\nclass ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer {\n\n\tprivate final Resources resourceProperties;\n\n\tResourceChainResourceHandlerRegistrationCustomizer(Resources resources) {\n\t\tthis.resourceProperties = resources;\n\t}\n\n\t@Override\n\tpublic void customize(ResourceHandlerRegistration registration) {\n\t\tResources.Chain properties = this.resourceProperties.getChain();\n\t\tconfigureResourceChain(properties, registration.resourceChain(properties.isCache()));\n\t}\n\n\tprivate void configureResourceChain(Resources.Chain properties, ResourceChainRegistration chain) {\n\t\tResources.Chain.Strategy strategy = properties.getStrategy();\n\t\tif (properties.isCompressed()) {\n\t\t\tchain.addResolver(new EncodedResourceResolver());\n\t\t}\n\t\tif (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {\n\t\t\tchain.addResolver(getVersionResourceResolver(strategy));\n\t\t}\n\t}\n\n\tprivate ResourceResolver getVersionResourceResolver(Resources.Chain.Strategy properties) {\n\t\tVersionResourceResolver resolver = new VersionResourceResolver();\n\t\tif (properties.getFixed().isEnabled()) {\n\t\t\tString version = properties.getFixed().getVersion();\n\t\t\tString[] paths = properties.getFixed().getPaths();\n\t\t\tAssert.state(version != null, \"'version' must not be null\");\n\t\t\tresolver.addFixedVersionStrategy(version, paths);\n\t\t}\n\t\tif (properties.getContent().isEnabled()) {\n\t\t\tString[] paths = properties.getContent().getPaths();\n\t\t\tresolver.addContentVersionStrategy(paths);\n\t\t}\n\t\treturn resolver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/ResourceHandlerRegistrationCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.springframework.web.reactive.config.ResourceHandlerRegistration;\n\n/**\n * Callback interface that can be used to customize {@link ResourceHandlerRegistration}.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ResourceHandlerRegistrationCustomizer {\n\n\t/**\n\t * Customize the given {@link ResourceHandlerRegistration}.\n\t * @param registration the registration to customize\n\t */\n\tvoid customize(ResourceHandlerRegistration registration);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Locale;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.autoconfigure.web.WebResourcesRuntimeHints;\nimport org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;\nimport org.springframework.boot.autoconfigure.web.format.WebConversionService;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.thread.Threading;\nimport org.springframework.boot.validation.autoconfigure.ValidatorAdapter;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxProperties.Apiversion;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxProperties.Apiversion.Use;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxProperties.Format;\nimport org.springframework.boot.webflux.filter.OrderedHiddenHttpMethodFilter;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.format.FormatterRegistry;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.http.CacheControl;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.validation.Validator;\nimport org.springframework.web.accept.ApiVersionParser;\nimport org.springframework.web.filter.reactive.HiddenHttpMethodFilter;\nimport org.springframework.web.reactive.accept.ApiVersionDeprecationHandler;\nimport org.springframework.web.reactive.accept.ApiVersionResolver;\nimport org.springframework.web.reactive.accept.ApiVersionStrategy;\nimport org.springframework.web.reactive.config.ApiVersionConfigurer;\nimport org.springframework.web.reactive.config.BlockingExecutionConfigurer;\nimport org.springframework.web.reactive.config.DelegatingWebFluxConfiguration;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.reactive.config.ResourceHandlerRegistration;\nimport org.springframework.web.reactive.config.ResourceHandlerRegistry;\nimport org.springframework.web.reactive.config.ViewResolverRegistry;\nimport org.springframework.web.reactive.config.WebFluxConfigurationSupport;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.reactive.function.server.support.RouterFunctionMapping;\nimport org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;\nimport org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.reactive.result.method.annotation.ResponseEntityExceptionHandler;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.WebSession;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\nimport org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;\nimport org.springframework.web.server.i18n.FixedLocaleContextResolver;\nimport org.springframework.web.server.i18n.LocaleContextResolver;\nimport org.springframework.web.server.session.DefaultWebSessionManager;\nimport org.springframework.web.server.session.InMemoryWebSessionStore;\nimport org.springframework.web.server.session.WebSessionIdResolver;\nimport org.springframework.web.server.session.WebSessionManager;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebFlux WebFlux}.\n *\n * @author Brian Clozel\n * @author Rob Winch\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Eddú Meléndez\n * @author Artsiom Yudovin\n * @author Chris Bono\n * @author Weix Sun\n * @since 4.0.0\n */\n@AutoConfiguration(\n\t\tafter = { ReactiveMultipartAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class,\n\t\t\t\tCodecsAutoConfiguration.class },\n\t\tafterName = \"org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\")\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass(WebFluxConfigurer.class)\n@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)\n@ImportRuntimeHints(WebResourcesRuntimeHints.class)\npublic final class WebFluxAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)\n\t@ConditionalOnBooleanProperty(\"spring.webflux.hiddenmethod.filter.enabled\")\n\tOrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {\n\t\treturn new OrderedHiddenHttpMethodFilter();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WelcomePageConfiguration {\n\n\t\t@Bean\n\t\t@Nullable RouterFunctionMapping welcomePageRouterFunctionMapping(ApplicationContext applicationContext,\n\t\t\t\tWebFluxProperties webFluxProperties, WebProperties webProperties) {\n\t\t\tString[] staticLocations = webProperties.getResources().getStaticLocations();\n\t\t\tWelcomePageRouterFunctionFactory factory = new WelcomePageRouterFunctionFactory(\n\t\t\t\t\tnew TemplateAvailabilityProviders(applicationContext), applicationContext, staticLocations,\n\t\t\t\t\twebFluxProperties.getStaticPathPattern());\n\t\t\tRouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();\n\t\t\tif (routerFunction != null) {\n\t\t\t\tRouterFunctionMapping routerFunctionMapping = new RouterFunctionMapping(routerFunction);\n\t\t\t\trouterFunctionMapping.setOrder(1);\n\t\t\t\treturn routerFunctionMapping;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties({ WebProperties.class, WebFluxProperties.class })\n\t@Import({ EnableWebFluxConfiguration.class })\n\t@Order(0)\n\tstatic class WebFluxConfig implements WebFluxConfigurer {\n\n\t\tprivate static final Log logger = LogFactory.getLog(WebFluxConfig.class);\n\n\t\tprivate final Environment environment;\n\n\t\tprivate final Resources resourceProperties;\n\n\t\tprivate final WebFluxProperties webFluxProperties;\n\n\t\tprivate final ListableBeanFactory beanFactory;\n\n\t\tprivate final ObjectProvider<HandlerMethodArgumentResolver> argumentResolvers;\n\n\t\tprivate final ObjectProvider<CodecCustomizer> codecCustomizers;\n\n\t\tprivate final ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizers;\n\n\t\tprivate final ObjectProvider<ViewResolver> viewResolvers;\n\n\t\tprivate final ObjectProvider<ApiVersionResolver> apiVersionResolvers;\n\n\t\tprivate final ObjectProvider<ApiVersionParser<?>> apiVersionParser;\n\n\t\tprivate final ObjectProvider<ApiVersionDeprecationHandler> apiVersionDeprecationHandler;\n\n\t\tWebFluxConfig(Environment environment, WebProperties webProperties, WebFluxProperties webFluxProperties,\n\t\t\t\tListableBeanFactory beanFactory, ObjectProvider<HandlerMethodArgumentResolver> resolvers,\n\t\t\t\tObjectProvider<CodecCustomizer> codecCustomizers,\n\t\t\t\tObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizers,\n\t\t\t\tObjectProvider<ViewResolver> viewResolvers, ObjectProvider<ApiVersionResolver> apiVersionResolvers,\n\t\t\t\tObjectProvider<ApiVersionParser<?>> apiVersionParser,\n\t\t\t\tObjectProvider<ApiVersionDeprecationHandler> apiVersionDeprecationHandler) {\n\t\t\tthis.environment = environment;\n\t\t\tthis.resourceProperties = webProperties.getResources();\n\t\t\tthis.webFluxProperties = webFluxProperties;\n\t\t\tthis.beanFactory = beanFactory;\n\t\t\tthis.argumentResolvers = resolvers;\n\t\t\tthis.codecCustomizers = codecCustomizers;\n\t\t\tthis.resourceHandlerRegistrationCustomizers = resourceHandlerRegistrationCustomizers;\n\t\t\tthis.viewResolvers = viewResolvers;\n\t\t\tthis.apiVersionResolvers = apiVersionResolvers;\n\t\t\tthis.apiVersionParser = apiVersionParser;\n\t\t\tthis.apiVersionDeprecationHandler = apiVersionDeprecationHandler;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {\n\t\t\tthis.argumentResolvers.orderedStream().forEach(configurer::addCustomResolver);\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {\n\t\t\tthis.codecCustomizers.orderedStream().forEach((customizer) -> customizer.customize(configurer));\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureBlockingExecution(BlockingExecutionConfigurer configurer) {\n\t\t\tif (Threading.VIRTUAL.isActive(this.environment) && this.beanFactory\n\t\t\t\t.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {\n\t\t\t\tObject taskExecutor = this.beanFactory\n\t\t\t\t\t.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);\n\t\t\t\tif (taskExecutor instanceof AsyncTaskExecutor asyncTaskExecutor) {\n\t\t\t\t\tconfigurer.setExecutor(asyncTaskExecutor);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n\t\t\tif (!this.resourceProperties.isAddMappings()) {\n\t\t\t\tlogger.debug(\"Default resource handling disabled\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tList<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizers = this.resourceHandlerRegistrationCustomizers\n\t\t\t\t.orderedStream()\n\t\t\t\t.toList();\n\t\t\tString webjarsPathPattern = this.webFluxProperties.getWebjarsPathPattern();\n\t\t\tif (!registry.hasMappingForPattern(webjarsPathPattern)) {\n\t\t\t\tResourceHandlerRegistration registration = registry.addResourceHandler(webjarsPathPattern)\n\t\t\t\t\t.addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n\t\t\t\tconfigureResourceCaching(registration);\n\t\t\t\tresourceHandlerRegistrationCustomizers.forEach((customizer) -> customizer.customize(registration));\n\t\t\t}\n\t\t\tString staticPathPattern = this.webFluxProperties.getStaticPathPattern();\n\t\t\tif (!registry.hasMappingForPattern(staticPathPattern)) {\n\t\t\t\tResourceHandlerRegistration registration = registry.addResourceHandler(staticPathPattern)\n\t\t\t\t\t.addResourceLocations(this.resourceProperties.getStaticLocations());\n\t\t\t\tconfigureResourceCaching(registration);\n\t\t\t\tresourceHandlerRegistrationCustomizers.forEach((customizer) -> customizer.customize(registration));\n\t\t\t}\n\t\t}\n\n\t\tprivate void configureResourceCaching(ResourceHandlerRegistration registration) {\n\t\t\tDuration cachePeriod = this.resourceProperties.getCache().getPeriod();\n\t\t\tWebProperties.Resources.Cache.Cachecontrol cacheControl = this.resourceProperties.getCache()\n\t\t\t\t.getCachecontrol();\n\t\t\tif (cachePeriod != null && cacheControl.getMaxAge() == null) {\n\t\t\t\tcacheControl.setMaxAge(cachePeriod);\n\t\t\t}\n\t\t\tCacheControl httpCacheControl = cacheControl.toHttpCacheControl();\n\t\t\tif (httpCacheControl != null) {\n\t\t\t\tregistration.setCacheControl(httpCacheControl);\n\t\t\t}\n\t\t\tregistration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureViewResolvers(ViewResolverRegistry registry) {\n\t\t\tthis.viewResolvers.orderedStream().forEach(registry::viewResolver);\n\t\t}\n\n\t\t@Override\n\t\tpublic void addFormatters(FormatterRegistry registry) {\n\t\t\tApplicationConversionService.addBeans(registry, this.beanFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureApiVersioning(ApiVersionConfigurer configurer) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tApiversion properties = this.webFluxProperties.getApiversion();\n\t\t\tmap.from(properties::getRequired).to(configurer::setVersionRequired);\n\t\t\tmap.from(properties::getDefaultVersion).to(configurer::setDefaultVersion);\n\t\t\tmap.from(properties::getSupported).to((supported) -> supported.forEach(configurer::addSupportedVersions));\n\t\t\tmap.from(properties::getDetectSupported).to(configurer::detectSupportedVersions);\n\t\t\tconfigureApiVersioningUse(configurer, properties.getUse());\n\t\t\tthis.apiVersionResolvers.orderedStream().forEach(configurer::useVersionResolver);\n\t\t\tthis.apiVersionParser.ifAvailable(configurer::setVersionParser);\n\t\t\tthis.apiVersionDeprecationHandler.ifAvailable(configurer::setDeprecationHandler);\n\t\t}\n\n\t\tprivate void configureApiVersioningUse(ApiVersionConfigurer configurer, Use use) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(use::getHeader).whenHasText().to(configurer::useRequestHeader);\n\t\t\tmap.from(use::getQueryParameter).whenHasText().to(configurer::useQueryParam);\n\t\t\tmap.from(use::getPathSegment).to(configurer::usePathSegment);\n\t\t\tuse.getMediaTypeParameter()\n\t\t\t\t.forEach((mediaType, parameterName) -> configurer.useMediaTypeParameter(mediaType, parameterName));\n\t\t}\n\n\t}\n\n\t/**\n\t * Configuration equivalent to {@code @EnableWebFlux}.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties({ WebProperties.class, ServerProperties.class })\n\t@ImportRuntimeHints(WebFluxValidatorRuntimeHints.class)\n\tstatic class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {\n\n\t\tprivate final WebFluxProperties webFluxProperties;\n\n\t\tprivate final WebProperties webProperties;\n\n\t\tprivate final ServerProperties serverProperties;\n\n\t\tprivate final @Nullable WebFluxRegistrations webFluxRegistrations;\n\n\t\tEnableWebFluxConfiguration(WebFluxProperties webFluxProperties, WebProperties webProperties,\n\t\t\t\tServerProperties serverProperties, ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {\n\t\t\tthis.webFluxProperties = webFluxProperties;\n\t\t\tthis.webProperties = webProperties;\n\t\t\tthis.serverProperties = serverProperties;\n\t\t\tthis.webFluxRegistrations = webFluxRegistrations.getIfUnique();\n\t\t}\n\n\t\t@Bean\n\t\t@Override\n\t\tpublic FormattingConversionService webFluxConversionService() {\n\t\t\tFormat format = this.webFluxProperties.getFormat();\n\t\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\t\tnew DateTimeFormatters().dateFormat(format.getDate())\n\t\t\t\t\t\t.timeFormat(format.getTime())\n\t\t\t\t\t\t.dateTimeFormat(format.getDateTime()));\n\t\t\taddFormatters(conversionService);\n\t\t\treturn conversionService;\n\t\t}\n\n\t\t@Bean\n\t\t@Override\n\t\tpublic Validator webFluxValidator() {\n\t\t\tif (!ClassUtils.isPresent(\"jakarta.validation.Validator\", getClass().getClassLoader())\n\t\t\t\t\t|| !ClassUtils.isPresent(\"org.springframework.boot.validation.autoconfigure.ValidatorAdapter\",\n\t\t\t\t\t\t\tgetClass().getClassLoader())) {\n\t\t\t\treturn super.webFluxValidator();\n\t\t\t}\n\t\t\tApplicationContext applicationContext = getApplicationContext();\n\t\t\tAssert.state(applicationContext != null, \"'applicationContext' must not be null\");\n\t\t\treturn ValidatorAdapter.get(applicationContext, getValidator());\n\t\t}\n\n\t\t@Override\n\t\tprotected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {\n\t\t\tif (this.webFluxRegistrations != null) {\n\t\t\t\tRequestMappingHandlerAdapter adapter = this.webFluxRegistrations.getRequestMappingHandlerAdapter();\n\t\t\t\tif (adapter != null) {\n\t\t\t\t\treturn adapter;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.createRequestMappingHandlerAdapter();\n\t\t}\n\n\t\t@Override\n\t\tprotected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {\n\t\t\tif (this.webFluxRegistrations != null) {\n\t\t\t\tRequestMappingHandlerMapping mapping = this.webFluxRegistrations.getRequestMappingHandlerMapping();\n\t\t\t\tif (mapping != null) {\n\t\t\t\t\treturn mapping;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.createRequestMappingHandlerMapping();\n\t\t}\n\n\t\t@Bean\n\t\t@Override\n\t\t@ConditionalOnMissingBean(name = WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME)\n\t\tpublic LocaleContextResolver localeContextResolver() {\n\t\t\tLocale locale = this.webProperties.getLocale();\n\t\t\tif (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {\n\t\t\t\tAssert.state(locale != null, \"'locale' must not be null\");\n\t\t\t\treturn new FixedLocaleContextResolver(locale);\n\t\t\t}\n\t\t\tAcceptHeaderLocaleContextResolver localeContextResolver = new AcceptHeaderLocaleContextResolver();\n\t\t\tlocaleContextResolver.setDefaultLocale(locale);\n\t\t\treturn localeContextResolver;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = WebHttpHandlerBuilder.WEB_SESSION_MANAGER_BEAN_NAME)\n\t\tWebSessionManager webSessionManager(ObjectProvider<WebSessionIdResolver> webSessionIdResolver) {\n\t\t\tDefaultWebSessionManager webSessionManager = new DefaultWebSessionManager();\n\t\t\tDuration timeout = this.serverProperties.getReactive().getSession().getTimeout();\n\t\t\tint maxSessions = this.serverProperties.getReactive().getSession().getMaxSessions();\n\t\t\tMaxIdleTimeInMemoryWebSessionStore sessionStore = new MaxIdleTimeInMemoryWebSessionStore(timeout);\n\t\t\tsessionStore.setMaxSessions(maxSessions);\n\t\t\twebSessionManager.setSessionStore(sessionStore);\n\t\t\twebSessionIdResolver.ifAvailable(webSessionManager::setSessionIdResolver);\n\t\t\treturn webSessionManager;\n\t\t}\n\n\t\t@Override\n\t\t@ConditionalOnMissingBean(name = \"webFluxApiVersionStrategy\")\n\t\tpublic @Nullable ApiVersionStrategy webFluxApiVersionStrategy() {\n\t\t\treturn super.webFluxApiVersionStrategy();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnEnabledResourceChain\n\tstatic class ResourceChainCustomizerConfiguration {\n\n\t\t@Bean\n\t\tResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(\n\t\t\t\tWebProperties webProperties) {\n\t\t\treturn new ResourceChainResourceHandlerRegistrationCustomizer(webProperties.getResources());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(\"spring.webflux.problemdetails.enabled\")\n\tstatic class ProblemDetailsErrorHandlingConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ResponseEntityExceptionHandler.class)\n\t\t@Order(0)\n\t\tProblemDetailsExceptionHandler problemDetailsExceptionHandler() {\n\t\t\treturn new ProblemDetailsExceptionHandler();\n\t\t}\n\n\t}\n\n\tstatic final class MaxIdleTimeInMemoryWebSessionStore extends InMemoryWebSessionStore {\n\n\t\tprivate final Duration timeout;\n\n\t\tprivate MaxIdleTimeInMemoryWebSessionStore(Duration timeout) {\n\t\t\tthis.timeout = timeout;\n\t\t}\n\n\t\t@Override\n\t\tpublic Mono<WebSession> createWebSession() {\n\t\t\treturn super.createWebSession().doOnSuccess(this::setMaxIdleTime);\n\t\t}\n\n\t\tprivate void setMaxIdleTime(WebSession session) {\n\t\t\tsession.setMaxIdleTime(this.timeout);\n\t\t}\n\n\t}\n\n\tstatic class WebFluxValidatorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerType(TypeReference.of(\"org.springframework.boot.validation.autoconfigure.ValidatorAdapter\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention;\nimport org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring\n * WebFlux applications.\n *\n * @author Brian Clozel\n * @author Jon Schneider\n * @author Dmytro Nosan\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = {\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration\",\n\t\t\"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\" })\n@ConditionalOnClass({ Observation.class, MeterRegistry.class })\n@ConditionalOnBean({ ObservationRegistry.class, MeterRegistry.class })\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@EnableConfigurationProperties({ MetricsProperties.class, ObservationProperties.class })\npublic final class WebFluxObservationAutoConfiguration {\n\n\tprivate final ObservationProperties observationProperties;\n\n\tWebFluxObservationAutoConfiguration(ObservationProperties observationProperties) {\n\t\tthis.observationProperties = observationProperties;\n\t}\n\n\t@Bean\n\t@Order(0)\n\tMaximumAllowableTagsMeterFilter metricsHttpServerUriTagFilter(MetricsProperties metricsProperties) {\n\t\tString meterNamePrefix = this.observationProperties.getHttp().getServer().getRequests().getName();\n\t\tint maxUriTags = metricsProperties.getWeb().getServer().getMaxUriTags();\n\t\treturn new MaximumAllowableTagsMeterFilter(meterNamePrefix, \"uri\", maxUriTags);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(ServerRequestObservationConvention.class)\n\tDefaultServerRequestObservationConvention defaultServerRequestObservationConvention() {\n\t\treturn new DefaultServerRequestObservationConvention(\n\t\t\t\tthis.observationProperties.getHttp().getServer().getRequests().getName());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ConfigurationProperties Properties} for Spring WebFlux.\n *\n * @author Brian Clozel\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.webflux\")\npublic class WebFluxProperties {\n\n\t/**\n\t * Base path for all web handlers.\n\t */\n\tprivate @Nullable String basePath;\n\n\tprivate final Format format = new Format();\n\n\tprivate final Problemdetails problemdetails = new Problemdetails();\n\n\tprivate final Apiversion apiversion = new Apiversion();\n\n\t/**\n\t * Path pattern used for static resources.\n\t */\n\tprivate String staticPathPattern = \"/**\";\n\n\t/**\n\t * Path pattern used for WebJar assets.\n\t */\n\tprivate String webjarsPathPattern = \"/webjars/**\";\n\n\t/**\n\t * Whether default HTML escaping is enabled for the web application.\n\t */\n\tprivate @Nullable Boolean defaultHtmlEscape;\n\n\tpublic @Nullable String getBasePath() {\n\t\treturn this.basePath;\n\t}\n\n\tpublic void setBasePath(@Nullable String basePath) {\n\t\tthis.basePath = cleanBasePath(basePath);\n\t}\n\n\tprivate @Nullable String cleanBasePath(@Nullable String basePath) {\n\t\tString candidate = null;\n\t\tif (StringUtils.hasLength(basePath)) {\n\t\t\tcandidate = basePath.strip();\n\t\t}\n\t\tif (StringUtils.hasText(candidate)) {\n\t\t\tif (!candidate.startsWith(\"/\")) {\n\t\t\t\tcandidate = \"/\" + candidate;\n\t\t\t}\n\t\t\tif (candidate.endsWith(\"/\")) {\n\t\t\t\tcandidate = candidate.substring(0, candidate.length() - 1);\n\t\t\t}\n\t\t}\n\t\treturn candidate;\n\t}\n\n\tpublic Format getFormat() {\n\t\treturn this.format;\n\t}\n\n\tpublic Problemdetails getProblemdetails() {\n\t\treturn this.problemdetails;\n\t}\n\n\tpublic Apiversion getApiversion() {\n\t\treturn this.apiversion;\n\t}\n\n\tpublic String getStaticPathPattern() {\n\t\treturn this.staticPathPattern;\n\t}\n\n\tpublic void setStaticPathPattern(String staticPathPattern) {\n\t\tthis.staticPathPattern = staticPathPattern;\n\t}\n\n\tpublic String getWebjarsPathPattern() {\n\t\treturn this.webjarsPathPattern;\n\t}\n\n\tpublic void setWebjarsPathPattern(String webjarsPathPattern) {\n\t\tthis.webjarsPathPattern = webjarsPathPattern;\n\t}\n\n\tpublic @Nullable Boolean getDefaultHtmlEscape() {\n\t\treturn this.defaultHtmlEscape;\n\t}\n\n\tpublic void setDefaultHtmlEscape(@Nullable Boolean defaultHtmlEscape) {\n\t\tthis.defaultHtmlEscape = defaultHtmlEscape;\n\t}\n\n\tpublic static class Format {\n\n\t\t/**\n\t\t * Date format to use, for example 'dd/MM/yyyy'. Used for formatting of\n\t\t * java.util.Date and java.time.LocalDate.\n\t\t */\n\t\tprivate @Nullable String date;\n\n\t\t/**\n\t\t * Time format to use, for example 'HH:mm:ss'. Used for formatting of java.time's\n\t\t * LocalTime and OffsetTime.\n\t\t */\n\t\tprivate @Nullable String time;\n\n\t\t/**\n\t\t * Date-time format to use, for example 'yyyy-MM-dd HH:mm:ss'. Used for formatting\n\t\t * of java.time's LocalDateTime, OffsetDateTime, and ZonedDateTime.\n\t\t */\n\t\tprivate @Nullable String dateTime;\n\n\t\tpublic @Nullable String getDate() {\n\t\t\treturn this.date;\n\t\t}\n\n\t\tpublic void setDate(@Nullable String date) {\n\t\t\tthis.date = date;\n\t\t}\n\n\t\tpublic @Nullable String getTime() {\n\t\t\treturn this.time;\n\t\t}\n\n\t\tpublic void setTime(@Nullable String time) {\n\t\t\tthis.time = time;\n\t\t}\n\n\t\tpublic @Nullable String getDateTime() {\n\t\t\treturn this.dateTime;\n\t\t}\n\n\t\tpublic void setDateTime(@Nullable String dateTime) {\n\t\t\tthis.dateTime = dateTime;\n\t\t}\n\n\t}\n\n\tpublic static class Problemdetails {\n\n\t\t/**\n\t\t * Whether RFC 9457 Problem Details support should be enabled.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\tpublic static class Apiversion {\n\n\t\t/**\n\t\t * Whether the API version is required with each request.\n\t\t */\n\t\tprivate @Nullable Boolean required;\n\n\t\t/**\n\t\t * Default version that should be used for each request.\n\t\t */\n\t\t@Name(\"default\")\n\t\tprivate @Nullable String defaultVersion;\n\n\t\t/**\n\t\t * Supported versions.\n\t\t */\n\t\tprivate @Nullable List<String> supported;\n\n\t\t/**\n\t\t * Whether supported versions should be detected from controllers.\n\t\t */\n\t\tprivate @Nullable Boolean detectSupported;\n\n\t\t/**\n\t\t * How version details should be inserted into requests.\n\t\t */\n\t\tprivate final Use use = new Use();\n\n\t\tpublic @Nullable Boolean getRequired() {\n\t\t\treturn this.required;\n\t\t}\n\n\t\tpublic void setRequired(@Nullable Boolean required) {\n\t\t\tthis.required = required;\n\t\t}\n\n\t\tpublic @Nullable String getDefaultVersion() {\n\t\t\treturn this.defaultVersion;\n\t\t}\n\n\t\tpublic void setDefaultVersion(@Nullable String defaultVersion) {\n\t\t\tthis.defaultVersion = defaultVersion;\n\t\t}\n\n\t\tpublic @Nullable List<String> getSupported() {\n\t\t\treturn this.supported;\n\t\t}\n\n\t\tpublic void setSupported(@Nullable List<String> supported) {\n\t\t\tthis.supported = supported;\n\t\t}\n\n\t\tpublic @Nullable Boolean getDetectSupported() {\n\t\t\treturn this.detectSupported;\n\t\t}\n\n\t\tpublic void setDetectSupported(@Nullable Boolean detectSupported) {\n\t\t\tthis.detectSupported = detectSupported;\n\t\t}\n\n\t\tpublic Use getUse() {\n\t\t\treturn this.use;\n\t\t}\n\n\t\tpublic static class Use {\n\n\t\t\t/**\n\t\t\t * Use the HTTP header with the given name to obtain the version.\n\t\t\t */\n\t\t\tprivate @Nullable String header;\n\n\t\t\t/**\n\t\t\t * Use the query parameter with the given name to obtain the version.\n\t\t\t */\n\t\t\tprivate @Nullable String queryParameter;\n\n\t\t\t/**\n\t\t\t * Use the path segment at the given index to obtain the version.\n\t\t\t */\n\t\t\tprivate @Nullable Integer pathSegment;\n\n\t\t\t/**\n\t\t\t * Use the media type parameter with the given name to obtain the version.\n\t\t\t */\n\t\t\tprivate Map<MediaType, String> mediaTypeParameter = new LinkedHashMap<>();\n\n\t\t\tpublic @Nullable String getHeader() {\n\t\t\t\treturn this.header;\n\t\t\t}\n\n\t\t\tpublic void setHeader(@Nullable String header) {\n\t\t\t\tthis.header = header;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getQueryParameter() {\n\t\t\t\treturn this.queryParameter;\n\t\t\t}\n\n\t\t\tpublic void setQueryParameter(@Nullable String queryParameter) {\n\t\t\t\tthis.queryParameter = queryParameter;\n\t\t\t}\n\n\t\t\tpublic @Nullable Integer getPathSegment() {\n\t\t\t\treturn this.pathSegment;\n\t\t\t}\n\n\t\t\tpublic void setPathSegment(@Nullable Integer pathSegment) {\n\t\t\t\tthis.pathSegment = pathSegment;\n\t\t\t}\n\n\t\t\tpublic Map<MediaType, String> getMediaTypeParameter() {\n\t\t\t\treturn this.mediaTypeParameter;\n\t\t\t}\n\n\t\t\tpublic void setMediaTypeParameter(Map<MediaType, String> mediaTypeParameter) {\n\t\t\t\tthis.mediaTypeParameter = mediaTypeParameter;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebFluxRegistrations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;\n\n/**\n * Interface to register key components of the {@link WebFluxAutoConfiguration} in place\n * of the default ones provided by Spring WebFlux.\n * <p>\n * All custom instances are later processed by Boot and Spring WebFlux configurations. A\n * single instance of this component should be registered, otherwise making it impossible\n * to choose from redundant WebFlux components.\n *\n * @author Artsiom Yudovin\n * @since 4.0.0\n * @see org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration.EnableWebFluxConfiguration\n */\npublic interface WebFluxRegistrations {\n\n\t/**\n\t * Return the custom {@link RequestMappingHandlerMapping} that should be used and\n\t * processed by the WebFlux configuration.\n\t * @return the custom {@link RequestMappingHandlerMapping} instance\n\t */\n\tdefault @Nullable RequestMappingHandlerMapping getRequestMappingHandlerMapping() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the custom {@link RequestMappingHandlerAdapter} that should be used and\n\t * processed by the WebFlux configuration.\n\t * @return the custom {@link RequestMappingHandlerAdapter} instance\n\t */\n\tdefault @Nullable RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebHttpHandlerBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\n/**\n * Callback interface used to customize a {@link WebHttpHandlerBuilder}.\n *\n * @author Lasse Wulff\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface WebHttpHandlerBuilderCustomizer {\n\n\t/**\n\t * Callback to customize a {@link WebHttpHandlerBuilder} instance.\n\t * @param webHttpHandlerBuilder the {@link WebHttpHandlerBuilder} to customize\n\t */\n\tvoid customize(WebHttpHandlerBuilder webHttpHandlerBuilder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WebSessionIdResolverAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.web.server.Cookie;\nimport org.springframework.boot.web.server.Cookie.SameSite;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.ResponseCookie.ResponseCookieBuilder;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.server.session.CookieWebSessionIdResolver;\nimport org.springframework.web.server.session.WebSessionIdResolver;\nimport org.springframework.web.server.session.WebSessionManager;\n\n/**\n * Auto-configuration for {@link WebSessionIdResolver}.\n *\n * @author Phillip Webb\n * @author Brian Clozel\n * @author Weix Sun\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass({ WebSessionManager.class, Mono.class })\n@EnableConfigurationProperties({ WebFluxProperties.class, ServerProperties.class })\npublic final class WebSessionIdResolverAutoConfiguration {\n\n\tprivate final ServerProperties serverProperties;\n\n\tWebSessionIdResolverAutoConfiguration(ServerProperties serverProperties, WebFluxProperties webFluxProperties) {\n\t\tthis.serverProperties = serverProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tWebSessionIdResolver webSessionIdResolver() {\n\t\tCookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver();\n\t\tString cookieName = this.serverProperties.getReactive().getSession().getCookie().getName();\n\t\tif (StringUtils.hasText(cookieName)) {\n\t\t\tresolver.setCookieName(cookieName);\n\t\t}\n\t\tresolver.addCookieInitializer(this::initializeCookie);\n\t\treturn resolver;\n\t}\n\n\tprivate void initializeCookie(ResponseCookieBuilder builder) {\n\t\tCookie cookie = this.serverProperties.getReactive().getSession().getCookie();\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tmap.from(cookie::getDomain).to(builder::domain);\n\t\tmap.from(cookie::getPath).to(builder::path);\n\t\tmap.from(cookie::getHttpOnly).to(builder::httpOnly);\n\t\tmap.from(cookie::getSecure).to(builder::secure);\n\t\tmap.from(cookie::getMaxAge).to(builder::maxAge);\n\t\tmap.from(cookie::getPartitioned).to(builder::partitioned);\n\t\tmap.from(cookie::getSameSite).as(SameSite::attributeValue).always().to(builder::sameSite);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/WelcomePageRouterFunctionFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.util.Arrays;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.springframework.web.reactive.function.server.RequestPredicates.GET;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.accept;\n\n/**\n * A {@link RouterFunction} factory for an application's welcome page. Supports both\n * static and templated files. If both a static and templated index page are available,\n * the static page is preferred.\n *\n * @author Brian Clozel\n */\nfinal class WelcomePageRouterFunctionFactory {\n\n\tprivate final String staticPathPattern;\n\n\tprivate final @Nullable Resource welcomePage;\n\n\tprivate final boolean welcomePageTemplateExists;\n\n\tWelcomePageRouterFunctionFactory(TemplateAvailabilityProviders templateAvailabilityProviders,\n\t\t\tApplicationContext applicationContext, String[] staticLocations, String staticPathPattern) {\n\t\tthis.staticPathPattern = staticPathPattern;\n\t\tthis.welcomePage = getWelcomePage(applicationContext, staticLocations);\n\t\tthis.welcomePageTemplateExists = welcomeTemplateExists(templateAvailabilityProviders, applicationContext);\n\t}\n\n\tprivate @Nullable Resource getWelcomePage(ResourceLoader resourceLoader, String[] staticLocations) {\n\t\treturn Arrays.stream(staticLocations)\n\t\t\t.map((location) -> getIndexHtml(resourceLoader, location))\n\t\t\t.filter(this::isReadable)\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n\tprivate Resource getIndexHtml(ResourceLoader resourceLoader, String location) {\n\t\treturn resourceLoader.getResource(location + \"index.html\");\n\t}\n\n\tprivate boolean isReadable(Resource resource) {\n\t\ttry {\n\t\t\treturn resource.exists() && (resource.getURL() != null);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate boolean welcomeTemplateExists(TemplateAvailabilityProviders templateAvailabilityProviders,\n\t\t\tApplicationContext applicationContext) {\n\t\treturn templateAvailabilityProviders.getProvider(\"index\", applicationContext) != null;\n\t}\n\n\t@Nullable RouterFunction<ServerResponse> createRouterFunction() {\n\t\tif (this.welcomePage != null && \"/**\".equals(this.staticPathPattern)) {\n\t\t\treturn RouterFunctions.route(GET(\"/\").and(accept(MediaType.TEXT_HTML)),\n\t\t\t\t\t(req) -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(this.welcomePage));\n\t\t}\n\t\telse if (this.welcomePageTemplateExists) {\n\t\t\treturn RouterFunctions.route(GET(\"/\").and(accept(MediaType.TEXT_HTML)),\n\t\t\t\t\t(req) -> ServerResponse.ok().render(\"index\"));\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/endpoint/web/WebFluxHealthEndpointExtensionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.endpoint.web;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.webflux.actuate.endpoint.web.AdditionalHealthEndpointPathsWebFluxHandlerMapping;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HealthEndpoint} web\n * extension with Spring WebFlux.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass({ HealthEndpoint.class, Health.class })\n@ConditionalOnBean({ WebEndpointsSupplier.class, HealthEndpointGroups.class })\n@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\npublic final class WebFluxHealthEndpointExtensionAutoConfiguration {\n\n\t@Bean\n\tAdditionalHealthEndpointPathsWebFluxHandlerMapping healthEndpointWebFluxHandlerMapping(\n\t\t\tWebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {\n\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\tExposableWebEndpoint health = webEndpoints.stream()\n\t\t\t.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t\treturn new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(\"\"), health,\n\t\t\t\tgroups.getAllWithAdditionalPath(WebServerNamespace.SERVER));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring WebFlux actuator web endpoint support.\n */\n@NullMarked\npackage org.springframework.boot.webflux.autoconfigure.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxEndpointManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Supplier;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.webflux.actuate.endpoint.web.AdditionalHealthEndpointPathsWebFluxHandlerMapping;\nimport org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.core.codec.Encoder;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.EncoderHttpMessageWriter;\nimport org.springframework.http.codec.HttpMessageWriter;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.http.codec.json.JacksonJsonEncoder;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.util.StringUtils;\nimport org.springframework.util.function.SingletonSupplier;\nimport org.springframework.web.reactive.DispatcherHandler;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Reactive\n * {@link Endpoint @Endpoint} concerns.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ManagementContextConfiguration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })\n@ConditionalOnBean(WebEndpointsSupplier.class)\n@EnableConfigurationProperties(CorsEndpointProperties.class)\npublic class WebFluxEndpointManagementContextConfiguration {\n\n\tprivate static final List<MediaType> MEDIA_TYPES = Collections\n\t\t.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType(\"application\", \"*+json\")));\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@SuppressWarnings(\"removal\")\n\tpublic WebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,\n\t\t\tEndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,\n\t\t\tWebEndpointProperties webEndpointProperties, Environment environment) {\n\t\tString basePath = webEndpointProperties.getBasePath();\n\t\tEndpointMapping endpointMapping = new EndpointMapping(basePath);\n\t\tCollection<ExposableWebEndpoint> endpoints = webEndpointsSupplier.getEndpoints();\n\t\tList<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();\n\t\tallEndpoints.addAll(endpoints);\n\t\tallEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());\n\t\treturn new WebFluxEndpointHandlerMapping(endpointMapping, endpoints, endpointMediaTypes,\n\t\t\t\tcorsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),\n\t\t\t\tshouldRegisterLinksMapping(webEndpointProperties, environment, basePath));\n\t}\n\n\tprivate boolean shouldRegisterLinksMapping(WebEndpointProperties properties, Environment environment,\n\t\t\tString basePath) {\n\t\treturn properties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)\n\t\t\t\t|| ManagementPortType.get(environment) == ManagementPortType.DIFFERENT);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"3.3.5\", forRemoval = true)\n\tpublic org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,\n\t\t\tCorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties,\n\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\tEndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());\n\t\treturn new org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping(\n\t\t\t\tendpointMapping, controllerEndpointsSupplier.getEndpoints(), corsProperties.toCorsConfiguration(),\n\t\t\t\tendpointAccessResolver);\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(EndpointJsonMapper.class)\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\tstatic ServerCodecConfigurerEndpointJsonMapperBeanPostProcessor serverCodecConfigurerEndpointJsonMapperBeanPostProcessor(\n\t\t\tObjectProvider<EndpointJsonMapper> endpointJsonMapper) {\n\t\treturn new ServerCodecConfigurerEndpointJsonMapperBeanPostProcessor(\n\t\t\t\tSingletonSupplier.of(endpointJsonMapper::getObject));\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\t@ConditionalOnBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\tstatic ServerCodecConfigurerEndpointJackson2JsonMapperBeanPostProcessor serverCodecConfigurerEndpointJackson2JsonMapperBeanPostProcessor(\n\t\t\tObjectProvider<org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper> endpointJsonMapper) {\n\t\treturn new ServerCodecConfigurerEndpointJackson2JsonMapperBeanPostProcessor(\n\t\t\t\tSingletonSupplier.of(endpointJsonMapper::getObject));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HealthEndpoint.class)\n\tstatic class HealthConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\n\t\t@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\n\t\t@ConditionalOnBean(HealthEndpoint.class)\n\t\tAdditionalHealthEndpointPathsWebFluxHandlerMapping managementHealthEndpointWebFluxHandlerMapping(\n\t\t\t\tWebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {\n\t\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\t\tExposableWebEndpoint healthEndpoint = webEndpoints.stream()\n\t\t\t\t.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))\n\t\t\t\t.findFirst()\n\t\t\t\t.orElse(null);\n\t\t\treturn new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(\"\"), healthEndpoint,\n\t\t\t\t\tgroups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link BeanPostProcessor} to apply {@link EndpointJsonMapper} for\n\t * {@link OperationResponseBody} to {@link JacksonJsonEncoder} instances.\n\t */\n\tstatic class ServerCodecConfigurerEndpointJsonMapperBeanPostProcessor implements BeanPostProcessor {\n\n\t\tprivate final Supplier<EndpointJsonMapper> mapper;\n\n\t\tServerCodecConfigurerEndpointJsonMapperBeanPostProcessor(Supplier<EndpointJsonMapper> mapper) {\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tif (bean instanceof ServerCodecConfigurer serverCodecConfigurer) {\n\t\t\t\tprocess(serverCodecConfigurer);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate void process(ServerCodecConfigurer configurer) {\n\t\t\tfor (HttpMessageWriter<?> writer : configurer.getWriters()) {\n\t\t\t\tif (writer instanceof EncoderHttpMessageWriter<?> encoderHttpMessageWriter) {\n\t\t\t\t\tprocess((encoderHttpMessageWriter).getEncoder());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void process(Encoder<?> encoder) {\n\t\t\tif (encoder instanceof JacksonJsonEncoder jacksonEncoder) {\n\t\t\t\tjacksonEncoder.registerMappersForType(OperationResponseBody.class, (associations) -> {\n\t\t\t\t\tJsonMapper mapper = this.mapper.get().get();\n\t\t\t\t\tMEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, mapper));\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link BeanPostProcessor} to apply\n\t * {@link org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper}\n\t * for {@link OperationResponseBody} to\n\t * {@link org.springframework.http.codec.json.Jackson2JsonEncoder} instances.\n\t *\n\t * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n\t */\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tstatic class ServerCodecConfigurerEndpointJackson2JsonMapperBeanPostProcessor implements BeanPostProcessor {\n\n\t\tprivate final Supplier<org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper> mapper;\n\n\t\tServerCodecConfigurerEndpointJackson2JsonMapperBeanPostProcessor(\n\t\t\t\tSupplier<org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper> mapper) {\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\t\tif (bean instanceof ServerCodecConfigurer serverCodecConfigurer) {\n\t\t\t\tprocess(serverCodecConfigurer);\n\t\t\t}\n\t\t\treturn bean;\n\t\t}\n\n\t\tprivate void process(ServerCodecConfigurer configurer) {\n\t\t\tfor (HttpMessageWriter<?> writer : configurer.getWriters()) {\n\t\t\t\tif (writer instanceof EncoderHttpMessageWriter<?> encoderHttpMessageWriter) {\n\t\t\t\t\tprocess((encoderHttpMessageWriter).getEncoder());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprivate void process(Encoder<?> encoder) {\n\t\t\tif (encoder instanceof org.springframework.http.codec.json.Jackson2JsonEncoder jacksonEncoder) {\n\t\t\t\tjacksonEncoder.registerObjectMappersForType(OperationResponseBody.class, (associations) -> {\n\t\t\t\t\tcom.fasterxml.jackson.databind.ObjectMapper mapper = this.mapper.get().get();\n\t\t\t\t\tMEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, mapper));\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxManagementChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementWebServerFactoryCustomizer;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.web.server.ConfigurableWebServerFactory;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.server.reactive.ContextPathCompositeHandler;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.reactive.DispatcherHandler;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for reactive web\n * infrastructure when a separate management context with a web server running on a\n * different port is required.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass(DispatcherHandler.class)\n@EnableWebFlux\nclass WebFluxManagementChildContextConfiguration {\n\n\t@Bean\n\tManagementWebServerFactoryCustomizer<ConfigurableWebServerFactory> reactiveManagementWebServerFactoryCustomizer(\n\t\t\tListableBeanFactory beanFactory) {\n\t\treturn new ManagementWebServerFactoryCustomizer<>(beanFactory);\n\t}\n\n\t@Bean\n\tHttpHandler httpHandler(ApplicationContext applicationContext, ManagementServerProperties properties) {\n\t\tHttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t\tif (StringUtils.hasText(properties.getBasePath())) {\n\t\t\tMap<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);\n\t\t\treturn new ContextPathCompositeHandler(handlersMap);\n\t\t}\n\t\treturn httpHandler;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/exchanges/WebFluxHttpExchangesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web.exchanges;\n\nimport org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesProperties;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange;\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.webflux.actuate.web.exchanges.HttpExchangesWebFilter;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to record {@link HttpExchange HTTP\n * exchanges}.\n *\n * @author Dave Syer\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnBooleanProperty(name = \"management.httpexchanges.recording.enabled\", matchIfMissing = true)\n@ConditionalOnBean(HttpExchangeRepository.class)\n@EnableConfigurationProperties(HttpExchangesProperties.class)\npublic final class WebFluxHttpExchangesAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tHttpExchangesWebFilter httpExchangesWebFilter(HttpExchangeRepository repository,\n\t\t\tHttpExchangesProperties properties) {\n\t\treturn new HttpExchangesWebFilter(repository, properties.getRecording().getInclude());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/exchanges/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator HTTP exchanges auto-configuration for reactive servers.\n *\n * @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository\n */\n@NullMarked\npackage org.springframework.boot.webflux.autoconfigure.actuate.web.exchanges;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/mappings/WebFluxMappingsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web.mappings;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlersMappingDescriptionProvider;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.reactive.DispatcherHandler;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to {@link MappingDescriptionProvider\n * describe} WebFlux mappings.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(after = WebFluxAutoConfiguration.class)\n@ConditionalOnClass({ ConditionalOnAvailableEndpoint.class, DispatcherHandler.class, MappingsEndpoint.class })\n@ConditionalOnAvailableEndpoint(MappingsEndpoint.class)\n@ConditionalOnBean(DispatcherHandler.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\npublic final class WebFluxMappingsAutoConfiguration {\n\n\t@Bean\n\tDispatcherHandlersMappingDescriptionProvider dispatcherHandlersMappingDescriptionProvider() {\n\t\treturn new DispatcherHandlersMappingDescriptionProvider();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator reactive request mappings auto-configuration.\n */\n@NullMarked\npackage org.springframework.boot.webflux.autoconfigure.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/actuate/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for WebFlux-based actuator web concerns.\n */\n@NullMarked\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/error/AbstractErrorWebExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.webflux.error.ErrorAttributes;\nimport org.springframework.boot.webflux.error.ErrorWebExceptionHandler;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.http.HttpLogging;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.codec.HttpMessageReader;\nimport org.springframework.http.codec.HttpMessageWriter;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.util.DisconnectedClientHelper;\nimport org.springframework.web.util.HtmlUtils;\n\n/**\n * Abstract base class for {@link ErrorWebExceptionHandler} implementations.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 4.0.0\n * @see ErrorAttributes\n */\npublic abstract class AbstractErrorWebExceptionHandler implements ErrorWebExceptionHandler, InitializingBean {\n\n\tprivate static final Log logger = HttpLogging.forLogName(AbstractErrorWebExceptionHandler.class);\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final ErrorAttributes errorAttributes;\n\n\tprivate final Resources resources;\n\n\tprivate final TemplateAvailabilityProviders templateAvailabilityProviders;\n\n\tprivate List<HttpMessageReader<?>> messageReaders = Collections.emptyList();\n\n\tprivate List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();\n\n\tprivate List<ViewResolver> viewResolvers = Collections.emptyList();\n\n\t/**\n\t * Create a new {@code AbstractErrorWebExceptionHandler}.\n\t * @param errorAttributes the error attributes\n\t * @param resources the resources configuration properties\n\t * @param applicationContext the application context\n\t */\n\tpublic AbstractErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,\n\t\t\tApplicationContext applicationContext) {\n\t\tAssert.notNull(errorAttributes, \"'errorAttributes' must not be null\");\n\t\tAssert.notNull(resources, \"'resources' must not be null\");\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tthis.errorAttributes = errorAttributes;\n\t\tthis.resources = resources;\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.templateAvailabilityProviders = new TemplateAvailabilityProviders(applicationContext);\n\t}\n\n\t/**\n\t * Configure HTTP message writers to serialize the response body with.\n\t * @param messageWriters the {@link HttpMessageWriter}s to use\n\t */\n\tpublic void setMessageWriters(List<HttpMessageWriter<?>> messageWriters) {\n\t\tAssert.notNull(messageWriters, \"'messageWriters' must not be null\");\n\t\tthis.messageWriters = messageWriters;\n\t}\n\n\t/**\n\t * Configure HTTP message readers to deserialize the request body with.\n\t * @param messageReaders the {@link HttpMessageReader}s to use\n\t */\n\tpublic void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {\n\t\tAssert.notNull(messageReaders, \"'messageReaders' must not be null\");\n\t\tthis.messageReaders = messageReaders;\n\t}\n\n\t/**\n\t * Configure the {@link ViewResolver} to use for rendering views.\n\t * @param viewResolvers the list of {@link ViewResolver}s to use\n\t */\n\tpublic void setViewResolvers(List<ViewResolver> viewResolvers) {\n\t\tthis.viewResolvers = viewResolvers;\n\t}\n\n\t/**\n\t * Extract the error attributes from the current request, to be used to populate error\n\t * views or JSON payloads.\n\t * @param request the source request\n\t * @param options options to control error attributes\n\t * @return the error attributes as a Map\n\t */\n\tprotected Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {\n\t\treturn this.errorAttributes.getErrorAttributes(request, options);\n\t}\n\n\t/**\n\t * Extract the original error from the current request.\n\t * @param request the source request\n\t * @return the error\n\t */\n\tprotected @Nullable Throwable getError(ServerRequest request) {\n\t\treturn this.errorAttributes.getError(request);\n\t}\n\n\t/**\n\t * Check whether the trace attribute has been set on the given request.\n\t * @param request the source request\n\t * @return {@code true} if the error trace has been requested, {@code false} otherwise\n\t */\n\tprotected boolean isTraceEnabled(ServerRequest request) {\n\t\treturn getBooleanParameter(request, \"trace\");\n\t}\n\n\t/**\n\t * Check whether the message attribute has been set on the given request.\n\t * @param request the source request\n\t * @return {@code true} if the message attribute has been requested, {@code false}\n\t * otherwise\n\t */\n\tprotected boolean isMessageEnabled(ServerRequest request) {\n\t\treturn getBooleanParameter(request, \"message\");\n\t}\n\n\t/**\n\t * Check whether the errors attribute has been set on the given request.\n\t * @param request the source request\n\t * @return {@code true} if the errors attribute has been requested, {@code false}\n\t * otherwise\n\t */\n\tprotected boolean isBindingErrorsEnabled(ServerRequest request) {\n\t\treturn getBooleanParameter(request, \"errors\");\n\t}\n\n\t/**\n\t * Check whether the path attribute has been set on the given request.\n\t * @param request the source request\n\t * @return {@code true} if the path attribute has been requested, {@code false}\n\t * otherwise\n\t */\n\tprotected boolean isPathEnabled(ServerRequest request) {\n\t\treturn getBooleanParameter(request, \"path\");\n\t}\n\n\tprivate boolean getBooleanParameter(ServerRequest request, String parameterName) {\n\t\tString parameter = request.queryParam(parameterName).orElse(\"false\");\n\t\treturn !\"false\".equalsIgnoreCase(parameter);\n\t}\n\n\t/**\n\t * Render the given error data as a view, using a template view if available or a\n\t * static HTML file if available otherwise. This will return an empty\n\t * {@code Publisher} if none of the above are available.\n\t * @param viewName the view name\n\t * @param responseBody the error response being built\n\t * @param error the error data as a map\n\t * @return a Publisher of the {@link ServerResponse}\n\t */\n\tprotected Mono<ServerResponse> renderErrorView(String viewName, ServerResponse.BodyBuilder responseBody,\n\t\t\tMap<String, @Nullable Object> error) {\n\t\tif (isTemplateAvailable(viewName)) {\n\t\t\treturn responseBody.render(viewName, error);\n\t\t}\n\t\tResource resource = resolveResource(viewName);\n\t\tif (resource != null) {\n\t\t\treturn responseBody.body(BodyInserters.fromResource(resource));\n\t\t}\n\t\treturn Mono.empty();\n\t}\n\n\tprivate boolean isTemplateAvailable(String viewName) {\n\t\treturn this.templateAvailabilityProviders.getProvider(viewName, this.applicationContext) != null;\n\t}\n\n\tprivate @Nullable Resource resolveResource(String viewName) {\n\t\tfor (String location : this.resources.getStaticLocations()) {\n\t\t\ttry {\n\t\t\t\tResource resource = this.applicationContext.getResource(location);\n\t\t\t\tresource = resource.createRelative(viewName + \".html\");\n\t\t\t\tif (resource.exists()) {\n\t\t\t\t\treturn resource;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Render a default HTML \"Whitelabel Error Page\".\n\t * <p>\n\t * Useful when no other error view is available in the application.\n\t * @param responseBody the error response being built\n\t * @param error the error data as a map\n\t * @return a Publisher of the {@link ServerResponse}\n\t */\n\tprotected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody,\n\t\t\tMap<String, @Nullable Object> error) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tDate timestamp = (Date) error.get(\"timestamp\");\n\t\tObject message = error.get(\"message\");\n\t\tObject trace = error.get(\"trace\");\n\t\tObject requestId = error.get(\"requestId\");\n\t\tbuilder.append(\"<html><body><h1>Whitelabel Error Page</h1>\")\n\t\t\t.append(\"<p>This application has no configured error view, so you are seeing this as a fallback.</p>\")\n\t\t\t.append(\"<div id='created'>\")\n\t\t\t.append(timestamp)\n\t\t\t.append(\"</div>\")\n\t\t\t.append(\"<div>[\")\n\t\t\t.append(requestId)\n\t\t\t.append(\"] There was an unexpected error (type=\")\n\t\t\t.append(htmlEscape(error.get(\"error\")))\n\t\t\t.append(\", status=\")\n\t\t\t.append(htmlEscape(error.get(\"status\")))\n\t\t\t.append(\").</div>\");\n\t\tif (message != null) {\n\t\t\tbuilder.append(\"<div>\").append(htmlEscape(message)).append(\"</div>\");\n\t\t}\n\t\tif (trace != null) {\n\t\t\tbuilder.append(\"<div style='white-space:pre-wrap;'>\").append(htmlEscape(trace)).append(\"</div>\");\n\t\t}\n\t\tbuilder.append(\"</body></html>\");\n\t\treturn responseBody.bodyValue(builder.toString());\n\t}\n\n\tprivate @Nullable String htmlEscape(@Nullable Object input) {\n\t\treturn (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (CollectionUtils.isEmpty(this.messageWriters)) {\n\t\t\tthrow new IllegalArgumentException(\"Property 'messageWriters' is required\");\n\t\t}\n\t}\n\n\t/**\n\t * Create a {@link RouterFunction} that can route and handle errors as JSON responses\n\t * or HTML views.\n\t * <p>\n\t * If the returned {@link RouterFunction} doesn't route to a {@code HandlerFunction},\n\t * the original exception is propagated in the pipeline and can be processed by other\n\t * {@link org.springframework.web.server.WebExceptionHandler}s.\n\t * @param errorAttributes the {@code ErrorAttributes} instance to use to extract error\n\t * information\n\t * @return a {@link RouterFunction} that routes and handles errors\n\t */\n\tprotected abstract RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes);\n\n\t@Override\n\tpublic Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {\n\t\tif (exchange.getResponse().isCommitted() || isDisconnectedClientError(throwable)) {\n\t\t\treturn Mono.error(throwable);\n\t\t}\n\t\tthis.errorAttributes.storeErrorInformation(throwable, exchange);\n\t\tServerRequest request = ServerRequest.create(exchange, this.messageReaders);\n\t\treturn getRoutingFunction(this.errorAttributes).route(request)\n\t\t\t.switchIfEmpty(Mono.error(throwable))\n\t\t\t.flatMap((handler) -> handler.handle(request))\n\t\t\t.doOnNext((response) -> logError(request, response, throwable))\n\t\t\t.flatMap((response) -> write(exchange, response));\n\t}\n\n\tprivate boolean isDisconnectedClientError(Throwable ex) {\n\t\treturn DisconnectedClientHelper.isClientDisconnectedException(ex);\n\t}\n\n\t/**\n\t * Logs the {@code throwable} error for the given {@code request} and {@code response}\n\t * exchange. The default implementation logs all errors at debug level. Additionally,\n\t * any internal server error (500) is logged at error level.\n\t * @param request the request that was being handled\n\t * @param response the response that was being sent\n\t * @param throwable the error to be logged\n\t */\n\tprotected void logError(ServerRequest request, ServerResponse response, Throwable throwable) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(request.exchange().getLogPrefix() + formatError(throwable, request));\n\t\t}\n\t\tif (HttpStatus.resolve(response.statusCode().value()) != null\n\t\t\t\t&& response.statusCode().equals(HttpStatus.INTERNAL_SERVER_ERROR)) {\n\t\t\tlogger.error(LogMessage.of(() -> String.format(\"%s 500 Server Error for %s\",\n\t\t\t\t\trequest.exchange().getLogPrefix(), formatRequest(request))), throwable);\n\t\t}\n\t}\n\n\tprivate String formatError(Throwable ex, ServerRequest request) {\n\t\tString reason = ex.getClass().getSimpleName() + \": \" + ex.getMessage();\n\t\treturn \"Resolved [\" + reason + \"] for HTTP \" + request.method() + \" \" + request.path();\n\t}\n\n\tprivate String formatRequest(ServerRequest request) {\n\t\tString rawQuery = request.uri().getRawQuery();\n\t\tString query = StringUtils.hasText(rawQuery) ? \"?\" + rawQuery : \"\";\n\t\treturn \"HTTP \" + request.method() + \" \\\"\" + request.path() + query + \"\\\"\";\n\t}\n\n\tprivate Mono<? extends Void> write(ServerWebExchange exchange, ServerResponse response) {\n\t\t// force content-type since writeTo won't overwrite response header values\n\t\texchange.getResponse().getHeaders().setContentType(response.headers().getContentType());\n\t\treturn response.writeTo(exchange, new ResponseContext());\n\t}\n\n\tprivate final class ResponseContext implements ServerResponse.Context {\n\n\t\t@Override\n\t\tpublic List<HttpMessageWriter<?>> messageWriters() {\n\t\t\treturn AbstractErrorWebExceptionHandler.this.messageWriters;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<ViewResolver> viewResolvers() {\n\t\t\treturn AbstractErrorWebExceptionHandler.this.viewResolvers;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/error/DefaultErrorWebExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.web.ErrorProperties;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.boot.webflux.error.DefaultErrorAttributes;\nimport org.springframework.boot.webflux.error.ErrorAttributes;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.InvalidMediaTypeException;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.MimeTypeUtils;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.server.RequestPredicate;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.springframework.web.reactive.function.server.RequestPredicates.all;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n/**\n * Basic global {@link org.springframework.web.server.WebExceptionHandler}, rendering\n * {@link ErrorAttributes}.\n * <p>\n * More specific errors can be handled either using Spring WebFlux abstractions (e.g.\n * {@code @ExceptionHandler} with the annotation model) or by adding\n * {@link RouterFunction} to the chain.\n * <p>\n * This implementation will render error as HTML views if the client explicitly supports\n * that media type. It attempts to resolve error views using well known conventions. Will\n * search for templates and static assets under {@code '/error'} using the\n * {@link HttpStatus status code} and the {@link HttpStatus#series() status series}.\n * <p>\n * For example, an {@code HTTP 404} will search (in the specific order):\n * <ul>\n * <li>{@code '/<templates>/error/404.<ext>'}</li>\n * <li>{@code '/<static>/error/404.html'}</li>\n * <li>{@code '/<templates>/error/4xx.<ext>'}</li>\n * <li>{@code '/<static>/error/4xx.html'}</li>\n * <li>{@code '/<templates>/error/error'}</li>\n * <li>{@code '/<static>/error/error.html'}</li>\n * </ul>\n * <p>\n * If none found, a default \"Whitelabel Error\" HTML view will be rendered.\n * <p>\n * If the client doesn't support HTML, the error information will be rendered as a JSON\n * payload.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {\n\n\tprivate static final MediaType TEXT_HTML_UTF8 = new MediaType(\"text\", \"html\", StandardCharsets.UTF_8);\n\n\tprivate static final Map<HttpStatus.Series, String> SERIES_VIEWS;\n\n\tstatic {\n\t\tMap<HttpStatus.Series, String> views = new EnumMap<>(HttpStatus.Series.class);\n\t\tviews.put(HttpStatus.Series.CLIENT_ERROR, \"4xx\");\n\t\tviews.put(HttpStatus.Series.SERVER_ERROR, \"5xx\");\n\t\tSERIES_VIEWS = Collections.unmodifiableMap(views);\n\t}\n\n\tprivate static final ErrorAttributeOptions ONLY_STATUS = ErrorAttributeOptions.of(Include.STATUS);\n\n\tprivate static final DefaultErrorAttributes defaultErrorAttributes = new DefaultErrorAttributes();\n\n\tprivate final ErrorProperties errorProperties;\n\n\t/**\n\t * Create a new {@code DefaultErrorWebExceptionHandler} instance.\n\t * @param errorAttributes the error attributes\n\t * @param resources the resources configuration properties\n\t * @param errorProperties the error configuration properties\n\t * @param applicationContext the current application context\n\t */\n\tpublic DefaultErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,\n\t\t\tErrorProperties errorProperties, ApplicationContext applicationContext) {\n\t\tsuper(errorAttributes, resources, applicationContext);\n\t\tthis.errorProperties = errorProperties;\n\t}\n\n\t@Override\n\tprotected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {\n\t\treturn route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);\n\t}\n\n\t/**\n\t * Render the error information as an HTML view.\n\t * @param request the current request\n\t * @return a {@code Publisher} of the HTTP response\n\t */\n\tprotected Mono<ServerResponse> renderErrorView(ServerRequest request) {\n\t\tMap<String, @Nullable Object> errorAttributes = getErrorAttributes(request, MediaType.TEXT_HTML);\n\t\tint status = getHttpStatus(request, errorAttributes);\n\t\tServerResponse.BodyBuilder responseBody = ServerResponse.status(status).contentType(TEXT_HTML_UTF8);\n\t\treturn Flux.just(getData(status).toArray(new String[] {}))\n\t\t\t.flatMap((viewName) -> renderErrorView(viewName, responseBody, errorAttributes))\n\t\t\t.switchIfEmpty(this.errorProperties.getWhitelabel().isEnabled()\n\t\t\t\t\t? renderDefaultErrorView(responseBody, errorAttributes) : getErrorMono(request))\n\t\t\t.next();\n\t}\n\n\tprivate Mono<ServerResponse> getErrorMono(ServerRequest request) {\n\t\tThrowable error = getError(request);\n\t\treturn (error != null) ? Mono.error(error) : Mono.empty();\n\t}\n\n\tprivate List<String> getData(int errorStatus) {\n\t\tList<String> data = new ArrayList<>();\n\t\tdata.add(\"error/\" + errorStatus);\n\t\tHttpStatus.Series series = HttpStatus.Series.resolve(errorStatus);\n\t\tif (series != null) {\n\t\t\tdata.add(\"error/\" + SERIES_VIEWS.get(series));\n\t\t}\n\t\tdata.add(\"error/error\");\n\t\treturn data;\n\t}\n\n\t/**\n\t * Render the error information as a JSON payload.\n\t * @param request the current request\n\t * @return a {@code Publisher} of the HTTP response\n\t */\n\tprotected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {\n\t\tMap<String, @Nullable Object> errorAttributes = getErrorAttributes(request, MediaType.ALL);\n\t\tint status = getHttpStatus(request, errorAttributes);\n\t\treturn ServerResponse.status(status)\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.body(BodyInserters.fromValue(errorAttributes));\n\t}\n\n\tprivate Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, MediaType mediaType) {\n\t\treturn getErrorAttributes(request, getErrorAttributeOptions(request, mediaType));\n\t}\n\n\tprotected ErrorAttributeOptions getErrorAttributeOptions(ServerRequest request, MediaType mediaType) {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.defaults();\n\t\tif (this.errorProperties.isIncludeException()) {\n\t\t\toptions = options.including(Include.EXCEPTION);\n\t\t}\n\t\tif (isIncludeStackTrace(request, mediaType)) {\n\t\t\toptions = options.including(Include.STACK_TRACE);\n\t\t}\n\t\tif (isIncludeMessage(request, mediaType)) {\n\t\t\toptions = options.including(Include.MESSAGE);\n\t\t}\n\t\tif (isIncludeBindingErrors(request, mediaType)) {\n\t\t\toptions = options.including(Include.BINDING_ERRORS);\n\t\t}\n\t\toptions = isIncludePath(request, mediaType) ? options.including(Include.PATH) : options.excluding(Include.PATH);\n\t\treturn options;\n\t}\n\n\t/**\n\t * Determine if the stacktrace attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the stacktrace attribute should be included\n\t */\n\tprotected boolean isIncludeStackTrace(ServerRequest request, MediaType produces) {\n\t\treturn switch (this.errorProperties.getIncludeStacktrace()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> isTraceEnabled(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Determine if the message attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the message attribute should be included\n\t */\n\tprotected boolean isIncludeMessage(ServerRequest request, MediaType produces) {\n\t\treturn switch (this.errorProperties.getIncludeMessage()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> isMessageEnabled(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Determine if the errors attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the errors attribute should be included\n\t */\n\tprotected boolean isIncludeBindingErrors(ServerRequest request, MediaType produces) {\n\t\treturn switch (this.errorProperties.getIncludeBindingErrors()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> isBindingErrorsEnabled(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Determine if the path attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the path attribute should be included\n\t */\n\tprotected boolean isIncludePath(ServerRequest request, MediaType produces) {\n\t\treturn switch (this.errorProperties.getIncludePath()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> isPathEnabled(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\tprivate int getHttpStatus(ServerRequest request, Map<String, @Nullable Object> errorAttributes) {\n\t\treturn getHttpStatus(errorAttributes.containsKey(\"status\") ? errorAttributes\n\t\t\t\t: defaultErrorAttributes.getErrorAttributes(request, ONLY_STATUS));\n\t}\n\n\t/**\n\t * Get the HTTP error status information from the error map.\n\t * @param errorAttributes the current error information\n\t * @return the error HTTP status\n\t */\n\tprotected int getHttpStatus(Map<String, @Nullable Object> errorAttributes) {\n\t\tObject status = errorAttributes.get(\"status\");\n\t\tAssert.state(status instanceof Integer, \"ErrorAttributes must contain a status integer\");\n\t\treturn (int) status;\n\t}\n\n\t/**\n\t * Predicate that checks whether the current request explicitly support\n\t * {@code \"text/html\"} media type.\n\t * <p>\n\t * The \"match-all\" media type is not considered here.\n\t * @return the request predicate\n\t */\n\tprotected RequestPredicate acceptsTextHtml() {\n\t\treturn (serverRequest) -> {\n\t\t\ttry {\n\t\t\t\tList<MediaType> acceptedMediaTypes = serverRequest.headers().accept();\n\t\t\t\tacceptedMediaTypes.removeIf(MediaType.ALL::equalsTypeAndSubtype);\n\t\t\t\tMimeTypeUtils.sortBySpecificity(acceptedMediaTypes);\n\t\t\t\treturn acceptedMediaTypes.stream().anyMatch(MediaType.TEXT_HTML::isCompatibleWith);\n\t\t\t}\n\t\t\tcatch (InvalidMediaTypeException ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/error/ErrorWebFluxAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.boot.webflux.error.DefaultErrorAttributes;\nimport org.springframework.boot.webflux.error.ErrorAttributes;\nimport org.springframework.boot.webflux.error.ErrorWebExceptionHandler;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.reactive.result.view.ViewResolver;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to render errors through a WebFlux\n * {@link org.springframework.web.server.WebExceptionHandler}.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(before = WebFluxAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.REACTIVE)\n@ConditionalOnClass(WebFluxConfigurer.class)\n@EnableConfigurationProperties(WebProperties.class)\npublic final class ErrorWebFluxAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)\n\t@Order(-1)\n\tErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties,\n\t\t\tObjectProvider<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer,\n\t\t\tApplicationContext applicationContext) {\n\t\tDefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,\n\t\t\t\twebProperties.getResources(), webProperties.getError(), applicationContext);\n\t\texceptionHandler.setViewResolvers(viewResolvers.orderedStream().toList());\n\t\texceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());\n\t\texceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());\n\t\treturn exceptionHandler;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)\n\tDefaultErrorAttributes errorAttributes() {\n\t\treturn new DefaultErrorAttributes();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/error/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring WebFlux error handling.\n */\n@NullMarked\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for reactive web servers and Spring WebFlux.\n */\n@NullMarked\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/error/DefaultErrorAttributes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.error;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.error.Error;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.util.StringUtils;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.method.MethodValidationResult;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.server.ResponseStatusException;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Default implementation of {@link ErrorAttributes}. Provides the following attributes\n * when possible:\n * <ul>\n * <li>timestamp - The time that the errors were extracted</li>\n * <li>status - The status code</li>\n * <li>error - The error reason</li>\n * <li>exception - The class name of the root exception (if configured)</li>\n * <li>message - The exception message (if configured)</li>\n * <li>errors - Any validation errors derived from a {@link BindingResult} or\n * {@link MethodValidationResult} exception (if configured). To ensure safe serialization\n * to JSON, errors are {@link Error#wrapIfNecessary(java.util.List) wrapped if\n * necessary}</li>\n * <li>trace - The exception stack trace (if configured)</li>\n * <li>path - The URL path when the exception was raised</li>\n * <li>requestId - Unique ID associated with the current request</li>\n * </ul>\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Michele Mancioppi\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Yanming Zhou\n * @author Yongjun Hong\n * @since 4.0.0\n * @see ErrorAttributes\n */\npublic class DefaultErrorAttributes implements ErrorAttributes {\n\n\tprivate static final String ERROR_INTERNAL_ATTRIBUTE = DefaultErrorAttributes.class.getName() + \".ERROR\";\n\n\t@Override\n\tpublic Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {\n\t\tMap<String, @Nullable Object> errorAttributes = getErrorAttributes(request,\n\t\t\t\toptions.isIncluded(Include.STACK_TRACE));\n\t\toptions.retainIncluded(errorAttributes);\n\t\treturn errorAttributes;\n\t}\n\n\tprivate Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {\n\t\tMap<String, @Nullable Object> errorAttributes = new LinkedHashMap<>();\n\t\terrorAttributes.put(\"timestamp\", new Date());\n\t\terrorAttributes.put(\"path\", request.requestPath().value());\n\t\tThrowable error = getError(request);\n\t\tMergedAnnotation<ResponseStatus> responseStatusAnnotation = MergedAnnotations\n\t\t\t.from(error.getClass(), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(ResponseStatus.class);\n\t\tHttpStatus errorStatus = determineHttpStatus(error, responseStatusAnnotation);\n\t\terrorAttributes.put(\"status\", errorStatus.value());\n\t\terrorAttributes.put(\"error\", errorStatus.getReasonPhrase());\n\t\terrorAttributes.put(\"requestId\", request.exchange().getRequest().getId());\n\t\thandleException(errorAttributes, error, responseStatusAnnotation, includeStackTrace);\n\t\treturn errorAttributes;\n\t}\n\n\tprivate HttpStatus determineHttpStatus(Throwable error, MergedAnnotation<ResponseStatus> responseStatusAnnotation) {\n\t\tif (error instanceof ResponseStatusException responseStatusException) {\n\t\t\tHttpStatus httpStatus = HttpStatus.resolve(responseStatusException.getStatusCode().value());\n\t\t\tif (httpStatus != null) {\n\t\t\t\treturn httpStatus;\n\t\t\t}\n\t\t}\n\t\treturn responseStatusAnnotation.getValue(\"code\", HttpStatus.class).orElse(HttpStatus.INTERNAL_SERVER_ERROR);\n\t}\n\n\tprivate void addStackTrace(Map<String, @Nullable Object> errorAttributes, Throwable error) {\n\t\tStringWriter stackTrace = new StringWriter();\n\t\terror.printStackTrace(new PrintWriter(stackTrace));\n\t\tstackTrace.flush();\n\t\terrorAttributes.put(\"trace\", stackTrace.toString());\n\t}\n\n\tprivate void handleException(Map<String, @Nullable Object> errorAttributes, Throwable error,\n\t\t\tMergedAnnotation<ResponseStatus> responseStatusAnnotation, boolean includeStackTrace) {\n\t\tThrowable exception;\n\t\tif (error instanceof BindingResult bindingResult) {\n\t\t\texception = error;\n\t\t\terrorAttributes.put(\"message\", error.getMessage());\n\t\t\terrorAttributes.put(\"errors\", Error.wrapIfNecessary(bindingResult.getAllErrors()));\n\t\t}\n\t\telse if (error instanceof MethodValidationResult methodValidationResult) {\n\t\t\texception = error;\n\t\t\terrorAttributes.put(\"message\", getErrorMessage(methodValidationResult));\n\t\t\terrorAttributes.put(\"errors\", Error.wrapIfNecessary(methodValidationResult.getAllErrors()));\n\t\t}\n\t\telse if (error instanceof ResponseStatusException responseStatusException) {\n\t\t\texception = (responseStatusException.getCause() != null) ? responseStatusException.getCause() : error;\n\t\t\terrorAttributes.put(\"message\", responseStatusException.getReason());\n\t\t\tif (exception instanceof BindingResult bindingResult) {\n\t\t\t\terrorAttributes.put(\"errors\", Error.wrapIfNecessary(bindingResult.getAllErrors()));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\texception = error;\n\t\t\tString reason = responseStatusAnnotation.getValue(\"reason\", String.class).orElse(\"\");\n\t\t\tString message = StringUtils.hasText(reason) ? reason : error.getMessage();\n\t\t\terrorAttributes.put(\"message\", (message != null) ? message : \"\");\n\t\t}\n\t\terrorAttributes.put(\"exception\", exception.getClass().getName());\n\t\tif (includeStackTrace) {\n\t\t\taddStackTrace(errorAttributes, exception);\n\t\t}\n\t}\n\n\tprivate String getErrorMessage(MethodValidationResult methodValidationResult) {\n\t\treturn \"Validation failed for method='%s'. Error count: %s\".formatted(methodValidationResult.getMethod(),\n\t\t\t\tmethodValidationResult.getAllErrors().size());\n\t}\n\n\t@Override\n\tpublic Throwable getError(ServerRequest request) {\n\t\tOptional<Object> error = request.attribute(ERROR_INTERNAL_ATTRIBUTE);\n\t\treturn (Throwable) error\n\t\t\t.orElseThrow(() -> new IllegalStateException(\"Missing exception attribute in ServerWebExchange\"));\n\t}\n\n\t@Override\n\tpublic void storeErrorInformation(Throwable error, ServerWebExchange exchange) {\n\t\texchange.getAttributes().putIfAbsent(ERROR_INTERNAL_ATTRIBUTE, error);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/error/ErrorAttributes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.error;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.server.ServerWebExchange;\n\n/**\n * Provides access to error attributes which can be logged or presented to the user.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 4.0.0\n * @see DefaultErrorAttributes\n */\npublic interface ErrorAttributes {\n\n\t/**\n\t * Return a {@link Map} of the error attributes. The map can be used as the model of\n\t * an error page, or returned as a {@link ServerResponse} body.\n\t * @param request the source request\n\t * @param options options for error attribute contents\n\t * @return a map of error attributes\n\t */\n\tdefault Map<String, @Nullable Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {\n\t\treturn Collections.emptyMap();\n\t}\n\n\t/**\n\t * Return the underlying cause of the error or {@code null} if the error cannot be\n\t * extracted.\n\t * @param request the source ServerRequest\n\t * @return the {@link Exception} that caused the error or {@code null}\n\t */\n\t@Nullable Throwable getError(ServerRequest request);\n\n\t/**\n\t * Store the given error information in the current {@link ServerWebExchange}.\n\t * @param error the {@link Exception} that caused the error\n\t * @param exchange the source exchange\n\t */\n\tvoid storeErrorInformation(Throwable error, ServerWebExchange exchange);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/error/ErrorWebExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.error;\n\nimport org.springframework.web.server.WebExceptionHandler;\n\n/**\n * Marker interface that indicates that a {@link WebExceptionHandler} is used to render\n * errors.\n *\n * @author Brian Clozel\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ErrorWebExceptionHandler extends WebExceptionHandler {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/error/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring WebFlux error handling infrastructure.\n */\n@NullMarked\npackage org.springframework.boot.webflux.error;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/filter/OrderedHiddenHttpMethodFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.filter;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.web.filter.reactive.HiddenHttpMethodFilter;\n\n/**\n * {@link HiddenHttpMethodFilter} that also implements {@link Ordered}.\n *\n * @author Artsiom Yudovin\n * @since 4.0.0\n */\npublic class OrderedHiddenHttpMethodFilter extends HiddenHttpMethodFilter implements OrderedWebFilter {\n\n\t/**\n\t * The default order is high to ensure the filter is applied before Spring Security.\n\t */\n\tpublic static final int DEFAULT_ORDER = REQUEST_WRAPPER_FILTER_MAX_ORDER - 10000;\n\n\tprivate int order = DEFAULT_ORDER;\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\t/**\n\t * Set the order for this filter.\n\t * @param order the order to set\n\t */\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/filter/OrderedWebFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.filter;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.web.server.WebFilter;\n\n/**\n * An {@link Ordered} {@link org.springframework.web.server.WebFilter}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic interface OrderedWebFilter extends WebFilter, Ordered {\n\n\t/**\n\t * Filters that wrap the request should be ordered less than or equal to this.\n\t */\n\tint REQUEST_WRAPPER_FILTER_MAX_ORDER = 0;\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/filter/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring Boot specific {@link org.springframework.web.server.WebFilter} implementations.\n */\n@NullMarked\npackage org.springframework.boot.webflux.filter;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/java/org/springframework/boot/webflux/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core integration between Spring Boot and Spring WebFlux.\n */\n@NullMarked\npackage org.springframework.boot.webflux;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.webflux.hiddenmethod.filter.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Spring's HiddenHttpMethodFilter.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.webflux.multipart.streaming\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Replaced by the PartEventHttpMessageReader and the PartEvent API.\",\n        \"since\": \"3.0.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.webflux.format.date\",\n      \"values\": [\n        {\n          \"value\": \"dd/MM/yyyy\",\n          \"description\": \"Example date format. Any format supported by DateTimeFormatter.parse can be used.\"\n        },\n        {\n          \"value\": \"iso\",\n          \"description\": \"ISO-8601 extended local date format.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.webflux.format.date-time\",\n      \"values\": [\n        {\n          \"value\": \"yyyy-MM-dd HH:mm:ss\",\n          \"description\": \"Example date-time format. Any format supported by DateTimeFormatter.parse can be used.\"\n        },\n        {\n          \"value\": \"iso\",\n          \"description\": \"ISO-8601 extended local date-time format.\"\n        },\n        {\n          \"value\": \"iso-offset\",\n          \"description\": \"ISO offset date-time format.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.webflux.format.time\",\n      \"values\": [\n        {\n          \"value\": \"HH:mm:ss\",\n          \"description\": \"Example time format. Any format supported by DateTimeFormatter.parse can be used.\"\n        },\n        {\n          \"value\": \"iso\",\n          \"description\": \"ISO-8601 extended local time format.\"\n        },\n        {\n          \"value\": \"iso-offset\",\n          \"description\": \"ISO offset time format.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.webflux.WebFluxWebApplicationTypeDeducer$WebFluxWebApplicationTypeDeducerRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.webflux.autoconfigure.actuate.web.WebFluxEndpointManagementContextConfiguration\norg.springframework.boot.webflux.autoconfigure.actuate.web.WebFluxManagementChildContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.ReactiveMultipartAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.WebFluxObservationAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.WebSessionIdResolverAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.actuate.endpoint.web.WebFluxHealthEndpointExtensionAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.actuate.web.exchanges.WebFluxHttpExchangesAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.actuate.web.mappings.WebFluxMappingsAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webflux/src/main/resources/META-INF/spring.factories",
    "content": "# WebApplicationType Deducers\norg.springframework.boot.WebApplicationType$Deducer=\\\norg.springframework.boot.webflux.WebFluxWebApplicationTypeDeducer\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/endpoint/web/AbstractWebFluxEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractWebFluxEndpointHandlerMapping}.\n *\n * @author Moritz Halbritter\n */\nclass AbstractWebFluxEndpointHandlerMappingTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew AbstractWebFluxEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference\n\t\t\t\t.of(\"org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.WriteOperationHandler\")))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference\n\t\t\t\t.of(\"org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.ReadOperationHandler\")))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference\n\t\t\t\t.of(\"org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.CatchAllHandler\")))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/endpoint/web/ControllerEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport java.lang.reflect.Method;\nimport java.time.Duration;\nimport java.util.Arrays;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.server.MethodNotAllowedException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ControllerEndpointHandlerMapping}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.5\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass ControllerEndpointHandlerMappingTests {\n\n\tprivate final StaticApplicationContext context = new StaticApplicationContext();\n\n\t@Test\n\tvoid mappingWithNoPrefix() {\n\t\tExposableControllerEndpoint first = firstEndpoint();\n\t\tExposableControllerEndpoint second = secondEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"\", first, second);\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/first\")).isEqualTo(handlerOf(first.getController(), \"get\"));\n\t\tassertThat(getHandler(mapping, HttpMethod.POST, \"/second\"))\n\t\t\t.isEqualTo(handlerOf(second.getController(), \"save\"));\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/third\")).isNull();\n\t}\n\n\t@Test\n\tvoid mappingWithPrefix() {\n\t\tExposableControllerEndpoint first = firstEndpoint();\n\t\tExposableControllerEndpoint second = secondEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"actuator\", first, second);\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/actuator/first\"))\n\t\t\t.isEqualTo(handlerOf(first.getController(), \"get\"));\n\t\tassertThat(getHandler(mapping, HttpMethod.POST, \"/actuator/second\"))\n\t\t\t.isEqualTo(handlerOf(second.getController(), \"save\"));\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/first\")).isNull();\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/second\")).isNull();\n\t}\n\n\t@Test\n\tvoid mappingWithNoPath() {\n\t\tExposableControllerEndpoint pathless = pathlessEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"actuator\", pathless);\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/actuator/pathless\"))\n\t\t\t.isEqualTo(handlerOf(pathless.getController(), \"get\"));\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/pathless\")).isNull();\n\t\tassertThat(getHandler(mapping, HttpMethod.GET, \"/\")).isNull();\n\t}\n\n\t@Test\n\tvoid mappingNarrowedToMethod() {\n\t\tExposableControllerEndpoint first = firstEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"actuator\", first);\n\t\tassertThatExceptionOfType(MethodNotAllowedException.class)\n\t\t\t.isThrownBy(() -> getHandler(mapping, HttpMethod.POST, \"/actuator/first\"));\n\t}\n\n\tprivate @Nullable Object getHandler(ControllerEndpointHandlerMapping mapping, HttpMethod method,\n\t\t\tString requestURI) {\n\t\treturn mapping.getHandler(exchange(method, requestURI)).block(Duration.ofSeconds(30));\n\t}\n\n\tprivate ControllerEndpointHandlerMapping createMapping(String prefix, ExposableControllerEndpoint... endpoints) {\n\t\tControllerEndpointHandlerMapping mapping = new ControllerEndpointHandlerMapping(new EndpointMapping(prefix),\n\t\t\t\tArrays.asList(endpoints), null, (endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\t\tmapping.setApplicationContext(this.context);\n\t\tmapping.afterPropertiesSet();\n\t\treturn mapping;\n\t}\n\n\tprivate HandlerMethod handlerOf(Object source, String methodName) {\n\t\tMethod method = ReflectionUtils.findMethod(source.getClass(), methodName);\n\t\tassertThat(method).isNotNull();\n\t\treturn new HandlerMethod(source, method);\n\t}\n\n\tprivate MockServerWebExchange exchange(HttpMethod method, String requestURI) {\n\t\treturn MockServerWebExchange.from(MockServerHttpRequest.method(method, requestURI).build());\n\t}\n\n\tprivate ExposableControllerEndpoint firstEndpoint() {\n\t\treturn mockEndpoint(EndpointId.of(\"first\"), new FirstTestMvcEndpoint());\n\t}\n\n\tprivate ExposableControllerEndpoint secondEndpoint() {\n\t\treturn mockEndpoint(EndpointId.of(\"second\"), new SecondTestMvcEndpoint());\n\t}\n\n\tprivate ExposableControllerEndpoint pathlessEndpoint() {\n\t\treturn mockEndpoint(EndpointId.of(\"pathless\"), new PathlessControllerEndpoint());\n\t}\n\n\tprivate ExposableControllerEndpoint mockEndpoint(EndpointId id, Object controller) {\n\t\tExposableControllerEndpoint endpoint = mock(ExposableControllerEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\tgiven(endpoint.getController()).willReturn(controller);\n\t\tgiven(endpoint.getRootPath()).willReturn(id.toString());\n\t\treturn endpoint;\n\t}\n\n\t@ControllerEndpoint(id = \"first\")\n\tstatic class FirstTestMvcEndpoint {\n\n\t\t@GetMapping(\"/\")\n\t\tString get() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\t@ControllerEndpoint(id = \"second\")\n\tstatic class SecondTestMvcEndpoint {\n\n\t\t@PostMapping(\"/\")\n\t\tvoid save() {\n\n\t\t}\n\n\t}\n\n\t@ControllerEndpoint(id = \"pathless\")\n\tstatic class PathlessControllerEndpoint {\n\n\t\t@GetMapping\n\t\tString get() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/endpoint/web/WebFluxEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;\nimport org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping.WebFluxLinksHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxEndpointHandlerMapping}.\n *\n * @author Moritz Halbritter\n */\nclass WebFluxEndpointHandlerMappingTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew WebFluxEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(WebFluxLinksHandler.class, \"links\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/web/exchanges/HttpExchangesWebFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport java.util.EnumSet;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.reactive.function.server.HandlerFunction;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.GET;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n/**\n * Integration tests for {@link HttpExchangesWebFilter}.\n *\n * @author Andy Wilkinson\n */\nclass HttpExchangesWebFilterIntegrationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withUserConfiguration(Config.class);\n\n\t@Test\n\tvoid exchangeForNotFoundResponseHas404Status() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient.bindToApplicationContext(context)\n\t\t\t\t.build()\n\t\t\t\t.get()\n\t\t\t\t.uri(\"/\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound();\n\t\t\tHttpExchangeRepository repository = context.getBean(HttpExchangeRepository.class);\n\t\t\tassertThat(repository.findAll()).hasSize(1);\n\t\t\tassertThat(repository.findAll().get(0).getResponse().getStatus()).isEqualTo(404);\n\t\t});\n\t}\n\n\t@Test\n\tvoid exchangeForMonoErrorWithRuntimeExceptionHas500Status() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient.bindToApplicationContext(context)\n\t\t\t\t.build()\n\t\t\t\t.get()\n\t\t\t\t.uri(\"/mono-error\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\t\tHttpExchangeRepository repository = context.getBean(HttpExchangeRepository.class);\n\t\t\tassertThat(repository.findAll()).hasSize(1);\n\t\t\tassertThat(repository.findAll().get(0).getResponse().getStatus()).isEqualTo(500);\n\t\t});\n\t}\n\n\t@Test\n\tvoid exchangeForThrownRuntimeExceptionHas500Status() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient.bindToApplicationContext(context)\n\t\t\t\t.build()\n\t\t\t\t.get()\n\t\t\t\t.uri(\"/thrown\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\t\tHttpExchangeRepository repository = context.getBean(HttpExchangeRepository.class);\n\t\t\tassertThat(repository.findAll()).hasSize(1);\n\t\t\tassertThat(repository.findAll().get(0).getResponse().getStatus()).isEqualTo(500);\n\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\tstatic class Config {\n\n\t\t@Bean\n\t\tHttpExchangesWebFilter httpExchangesWebFilter(HttpExchangeRepository repository) {\n\t\t\treturn new HttpExchangesWebFilter(repository, EnumSet.allOf(Include.class));\n\t\t}\n\n\t\t@Bean\n\t\tHttpExchangeRepository httpExchangeRepository() {\n\t\t\treturn new InMemoryHttpExchangeRepository();\n\t\t}\n\n\t\t@Bean\n\t\tHttpHandler httpHandler(ApplicationContext applicationContext) {\n\t\t\treturn WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> router() {\n\t\t\treturn route(GET(\"/mono-error\"), (request) -> Mono.error(new RuntimeException())).andRoute(GET(\"/thrown\"),\n\t\t\t\t\t(HandlerFunction<ServerResponse>) (request) -> {\n\t\t\t\t\t\tthrow new RuntimeException();\n\t\t\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/web/exchanges/HttpExchangesWebFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport java.security.Principal;\nimport java.time.Duration;\nimport java.util.EnumSet;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchange.Session;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.ServerWebExchangeDecorator;\nimport org.springframework.web.server.WebFilterChain;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link HttpExchangesWebFilter}.\n *\n * @author Andy Wilkinson\n */\nclass HttpExchangesWebFilterTests {\n\n\tprivate final InMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();\n\n\tprivate final HttpExchangesWebFilter filter = new HttpExchangesWebFilter(this.repository,\n\t\t\tEnumSet.allOf(Include.class));\n\n\t@Test\n\tvoid filterRecordsExchange() {\n\t\texecuteFilter(MockServerWebExchange.from(MockServerHttpRequest.get(\"https://api.example.com\")),\n\t\t\t\t(exchange) -> Mono.empty());\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t}\n\n\t@Test\n\tvoid filterRecordsSessionIdWhenSessionIsUsed() {\n\t\texecuteFilter(MockServerWebExchange.from(MockServerHttpRequest.get(\"https://api.example.com\")),\n\t\t\t\t(exchange) -> exchange.getSession()\n\t\t\t\t\t.doOnNext((session) -> session.getAttributes().put(\"a\", \"alpha\"))\n\t\t\t\t\t.then());\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t\tSession session = this.repository.findAll().get(0).getSession();\n\t\tassertThat(session).isNotNull();\n\t\tassertThat(session.getId()).isNotNull();\n\t}\n\n\t@Test\n\tvoid filterDoesNotRecordIdOfUnusedSession() {\n\t\texecuteFilter(MockServerWebExchange.from(MockServerHttpRequest.get(\"https://api.example.com\")),\n\t\t\t\t(exchange) -> exchange.getSession().then());\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t\tSession session = this.repository.findAll().get(0).getSession();\n\t\tassertThat(session).isNull();\n\t}\n\n\t@Test\n\tvoid filterRecordsPrincipal() {\n\t\tPrincipal principal = mock(Principal.class);\n\t\tgiven(principal.getName()).willReturn(\"alice\");\n\t\texecuteFilter(new ServerWebExchangeDecorator(\n\t\t\t\tMockServerWebExchange.from(MockServerHttpRequest.get(\"https://api.example.com\"))) {\n\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\t@Override\n\t\t\tpublic <T extends Principal> Mono<T> getPrincipal() {\n\t\t\t\treturn Mono.just((T) principal);\n\t\t\t}\n\n\t\t}, (exchange) -> exchange.getSession().doOnNext((session) -> session.getAttributes().put(\"a\", \"alpha\")).then());\n\t\tassertThat(this.repository.findAll()).hasSize(1);\n\t\torg.springframework.boot.actuate.web.exchanges.HttpExchange.Principal recordedPrincipal = this.repository\n\t\t\t.findAll()\n\t\t\t.get(0)\n\t\t\t.getPrincipal();\n\t\tassertThat(recordedPrincipal).isNotNull();\n\t\tassertThat(recordedPrincipal.getName()).isEqualTo(\"alice\");\n\t}\n\n\tprivate void executeFilter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\tStepVerifier\n\t\t\t.create(this.filter.filter(exchange, chain).then(Mono.defer(() -> exchange.getResponse().setComplete())))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/web/exchanges/RecordableServerHttpRequestTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.exchanges;\n\nimport java.net.InetSocketAddress;\nimport java.net.URI;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.web.server.ServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link RecordableServerHttpRequest}.\n *\n * @author Dmytro Nosan\n */\nclass RecordableServerHttpRequestTests {\n\n\tprivate ServerWebExchange exchange;\n\n\tprivate ServerHttpRequest request;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.exchange = mock(ServerWebExchange.class);\n\t\tthis.request = mock(ServerHttpRequest.class);\n\t\tgiven(this.exchange.getRequest()).willReturn(this.request);\n\t\tgiven(this.request.getMethod()).willReturn(HttpMethod.GET);\n\t}\n\n\t@Test\n\tvoid getMethod() {\n\t\tRecordableServerHttpRequest sourceRequest = new RecordableServerHttpRequest(this.request);\n\t\tassertThat(sourceRequest.getMethod()).isEqualTo(\"GET\");\n\t}\n\n\t@Test\n\tvoid getUri() {\n\t\tURI uri = URI.create(\"http://localhost:8080/\");\n\t\tgiven(this.request.getURI()).willReturn(uri);\n\t\tRecordableServerHttpRequest sourceRequest = new RecordableServerHttpRequest(this.request);\n\t\tassertThat(sourceRequest.getUri()).isSameAs(uri);\n\t}\n\n\t@Test\n\tvoid getHeaders() {\n\t\tHttpHeaders httpHeaders = new HttpHeaders();\n\t\thttpHeaders.add(\"name\", \"value\");\n\t\tgiven(this.request.getHeaders()).willReturn(httpHeaders);\n\t\tRecordableServerHttpRequest sourceRequest = new RecordableServerHttpRequest(this.request);\n\t\tassertThat(sourceRequest.getHeaders()).containsOnly(entry(\"name\", Collections.singletonList(\"value\")));\n\t}\n\n\t@Test\n\tvoid getUnresolvedRemoteAddress() {\n\t\tInetSocketAddress socketAddress = InetSocketAddress.createUnresolved(\"unresolved.example.com\", 8080);\n\t\tgiven(this.request.getRemoteAddress()).willReturn(socketAddress);\n\t\tRecordableServerHttpRequest sourceRequest = new RecordableServerHttpRequest(this.request);\n\t\tassertThat(sourceRequest.getRemoteAddress()).isNull();\n\t}\n\n\t@Test\n\tvoid getRemoteAddress() {\n\t\tInetSocketAddress socketAddress = new InetSocketAddress(0);\n\t\tgiven(this.request.getRemoteAddress()).willReturn(socketAddress);\n\t\tRecordableServerHttpRequest sourceRequest = new RecordableServerHttpRequest(this.request);\n\t\tassertThat(sourceRequest.getRemoteAddress()).isEqualTo(socketAddress.getAddress().toString());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/actuate/web/mappings/DispatcherHandlersMappingDescriptionProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.web.mappings;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlersMappingDescriptionProvider.DispatcherHandlersMappingDescriptionProviderRuntimeHints;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.reactive.config.EnableWebFlux;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.accept;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.contentType;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.path;\n\n/**\n * Tests for {@link DispatcherHandlersMappingDescriptionProvider}.\n *\n * @author Moritz Halbritter\n * @author Brian Clozel\n */\nclass DispatcherHandlersMappingDescriptionProviderTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew DispatcherHandlersMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(DispatcherHandlerMappingDescription.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid shouldDescribeAnnotatedControllers() {\n\t\tnew ReactiveWebApplicationContextRunner().withUserConfiguration(ControllerWebConfiguration.class)\n\t\t\t.run((context) -> {\n\n\t\t\t\tMap<String, List<DispatcherHandlerMappingDescription>> describedMappings = new DispatcherHandlersMappingDescriptionProvider()\n\t\t\t\t\t.describeMappings(context);\n\t\t\t\tassertThat(describedMappings).hasSize(1).containsOnlyKeys(\"webHandler\");\n\t\t\t\tList<DispatcherHandlerMappingDescription> descriptions = describedMappings.get(\"webHandler\");\n\t\t\t\tassertThat(descriptions).hasSize(2)\n\t\t\t\t\t.extracting(\"predicate\")\n\t\t\t\t\t.containsExactlyInAnyOrder(\"{POST /api/projects, consumes [application/json]}\",\n\t\t\t\t\t\t\t\"{GET /api/projects/{id}, produces [application/json]}\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldDescribeRouterFunctions() {\n\t\tnew ReactiveWebApplicationContextRunner().withUserConfiguration(RouterConfiguration.class).run((context) -> {\n\n\t\t\tMap<String, List<DispatcherHandlerMappingDescription>> describedMappings = new DispatcherHandlersMappingDescriptionProvider()\n\t\t\t\t.describeMappings(context);\n\t\t\tassertThat(describedMappings).hasSize(1).containsOnlyKeys(\"webHandler\");\n\t\t\tList<DispatcherHandlerMappingDescription> descriptions = describedMappings.get(\"webHandler\");\n\t\t\tassertThat(descriptions).hasSize(2)\n\t\t\t\t.extracting(\"predicate\")\n\t\t\t\t.containsExactlyInAnyOrder(\"(/api && (POST && (/projects/ && Content-Type: application/json)))\",\n\t\t\t\t\t\t\"(/api && (GET && (/projects//{id} && Accept: application/json)))\");\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\tstatic class ControllerWebConfiguration {\n\n\t\t@Controller\n\t\t@RequestMapping(\"/api\")\n\t\tstatic class SampleController {\n\n\t\t\t@PostMapping(path = \"/projects\", consumes = MediaType.APPLICATION_JSON_VALUE)\n\t\t\tvoid createProject() {\n\t\t\t}\n\n\t\t\t@GetMapping(path = \"/projects/{id}\", produces = MediaType.APPLICATION_JSON_VALUE)\n\t\t\tvoid findProject() {\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebFlux\n\tstatic class RouterConfiguration {\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> routerFunctions() {\n\t\t\treturn RouterFunctions.route()\n\t\t\t\t.nest(path(\"/api\"),\n\t\t\t\t\t\t(builder) -> builder\n\t\t\t\t\t\t\t.POST(path(\"/projects/\").and(contentType(MediaType.APPLICATION_JSON)),\n\t\t\t\t\t\t\t\t\t(request) -> ServerResponse.ok().build())\n\t\t\t\t\t\t\t.GET(path(\"/projects//{id}\").and(accept(MediaType.APPLICATION_JSON)),\n\t\t\t\t\t\t\t\t\t(request) -> ServerResponse.ok().build()))\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/HttpHandlerAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.server.reactive.ContextPathCompositeHandler;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.http.server.reactive.ServerHttpRequest;\nimport org.springframework.http.server.reactive.ServerHttpResponse;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.http.server.reactive.MockServerHttpResponse;\nimport org.springframework.web.reactive.DispatcherHandler;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.server.WebHandler;\nimport org.springframework.web.server.adapter.HttpWebHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.web.reactive.function.server.RequestPredicates.GET;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n/**\n * Tests for {@link HttpHandlerAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Lasse Wulff\n */\nclass HttpHandlerAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HttpHandlerAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotProcessIfExistingHttpHandler() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpHandler.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(HttpHandler.class);\n\t\t\tassertThat(context).getBean(HttpHandler.class).isSameAs(context.getBean(\"customHttpHandler\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureHttpHandlerAnnotation() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HttpHandler.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureHttpHandlerWithoutWebFluxAutoConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomWebHandler.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HttpHandler.class));\n\t}\n\n\t@Test\n\tvoid customizersAreCalled() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))\n\t\t\t.withUserConfiguration(WebHttpHandlerBuilderCustomizers.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpHandler.class);\n\t\t\t\tHttpHandler httpHandler = context.getBean(HttpHandler.class);\n\t\t\t\tServerHttpRequest request = MockServerHttpRequest.get(\"\").build();\n\t\t\t\tServerHttpResponse response = new MockServerHttpResponse();\n\t\t\t\thttpHandler.handle(request, response).block();\n\t\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.EXPECTATION_FAILED);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureBasePathCompositeHandler() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.webflux.base-path=/something\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpHandler.class);\n\t\t\t\tHttpHandler httpHandler = context.getBean(HttpHandler.class);\n\t\t\t\tassertThat(httpHandler).isInstanceOf(ContextPathCompositeHandler.class)\n\t\t\t\t\t.extracting(\"handlerMap\", InstanceOfAssertFactories.map(String.class, HttpHandler.class))\n\t\t\t\t\t.containsKey(\"/something\");\n\t\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(booleans = { true, false })\n\tvoid shouldConfigureDefaultHtmlEscape(boolean enabled) {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.webflux.default-html-escape=\" + enabled)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpHandler.class);\n\t\t\t\tassertThat(context.getBean(HttpHandler.class)).isInstanceOfSatisfying(HttpWebHandlerAdapter.class,\n\t\t\t\t\t\t(adapter) -> assertThat(adapter.getDefaultHtmlEscape()).isEqualTo(enabled));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotConfigureDefaultHtmlEscaperWithoutWebFluxAutoConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(CustomWebHandler.class)\n\t\t\t.withPropertyValues(\"spring.webflux.default-html-escape=true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpHandler.class);\n\t\t\t\tassertThat(context.getBean(HttpHandler.class)).isInstanceOfSatisfying(HttpWebHandlerAdapter.class,\n\t\t\t\t\t\t(adapter) -> assertThat(adapter.getDefaultHtmlEscape()).isNull());\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHttpHandler {\n\n\t\t@Bean\n\t\tHttpHandler customHttpHandler() {\n\t\t\treturn (serverHttpRequest, serverHttpResponse) -> Mono.empty();\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> routerFunction() {\n\t\t\treturn route(GET(\"/test\"), (serverRequest) -> Mono.empty());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebHandler {\n\n\t\t@Bean\n\t\tWebHandler webHandler() {\n\t\t\treturn new DispatcherHandler();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebHttpHandlerBuilderCustomizers {\n\n\t\t@Bean\n\t\tWebHttpHandlerBuilderCustomizer customizerDecorator() {\n\t\t\treturn (webHttpHandlerBuilder) -> webHttpHandlerBuilder\n\t\t\t\t.httpHandlerDecorator(((httpHandler) -> (request, response) -> {\n\t\t\t\t\tresponse.setStatusCode(HttpStatus.EXPECTATION_FAILED);\n\t\t\t\t\treturn response.setComplete();\n\t\t\t\t}));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/ReactiveMultipartAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;\nimport org.springframework.http.codec.multipart.PartEventHttpMessageReader;\nimport org.springframework.http.codec.support.DefaultServerCodecConfigurer;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveMultipartAutoConfiguration}.\n *\n * @author Chris Bono\n * @author Brian Clozel\n */\nclass ReactiveMultipartAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ReactiveMultipartAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldNotProvideCustomizerForNonReactiveApp() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(ReactiveMultipartAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CodecCustomizer.class));\n\t}\n\n\t@Test\n\tvoid shouldNotProvideCustomizerWhenWebFluxNotAvailable() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(WebFluxConfigurer.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(CodecCustomizer.class));\n\t}\n\n\t@Test\n\tvoid shouldConfigureMultipartPropertiesForDefaultReader() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.webflux.multipart.max-in-memory-size=1GB\",\n\t\t\t\t\t\"spring.webflux.multipart.max-headers-size=16KB\",\n\t\t\t\t\t\"spring.webflux.multipart.max-disk-usage-per-part=3GB\", \"spring.webflux.multipart.max-parts=7\",\n\t\t\t\t\t\"spring.webflux.multipart.headers-charset:UTF_16\")\n\t\t\t.run((context) -> {\n\t\t\t\tCodecCustomizer customizer = context.getBean(CodecCustomizer.class);\n\t\t\t\tDefaultServerCodecConfigurer configurer = new DefaultServerCodecConfigurer();\n\t\t\t\tcustomizer.customize(configurer);\n\t\t\t\tDefaultPartHttpMessageReader partReader = getDefaultPartReader(configurer);\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxParts\", 7);\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxHeadersSize\",\n\t\t\t\t\t\tMath.toIntExact(DataSize.ofKilobytes(16).toBytes()));\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"headersCharset\", StandardCharsets.UTF_16);\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxInMemorySize\",\n\t\t\t\t\t\tMath.toIntExact(DataSize.ofGigabytes(1).toBytes()));\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxDiskUsagePerPart\",\n\t\t\t\t\t\tDataSize.ofGigabytes(3).toBytes());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldConfigureMultipartPropertiesForPartEventReader() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.webflux.multipart.max-in-memory-size=1GB\",\n\t\t\t\t\t\"spring.webflux.multipart.max-headers-size=16KB\",\n\t\t\t\t\t\"spring.webflux.multipart.max-disk-usage-per-part=3GB\", \"spring.webflux.multipart.max-parts=7\",\n\t\t\t\t\t\"spring.webflux.multipart.headers-charset:UTF_16\")\n\t\t\t.run((context) -> {\n\t\t\t\tCodecCustomizer customizer = context.getBean(CodecCustomizer.class);\n\t\t\t\tDefaultServerCodecConfigurer configurer = new DefaultServerCodecConfigurer();\n\t\t\t\tcustomizer.customize(configurer);\n\t\t\t\tPartEventHttpMessageReader partReader = getPartEventReader(configurer);\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxParts\", 7);\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxHeadersSize\",\n\t\t\t\t\t\tMath.toIntExact(DataSize.ofKilobytes(16).toBytes()));\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"headersCharset\", StandardCharsets.UTF_16);\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxInMemorySize\",\n\t\t\t\t\t\tMath.toIntExact(DataSize.ofGigabytes(1).toBytes()));\n\t\t\t\tassertThat(partReader).hasFieldOrPropertyWithValue(\"maxPartSize\", DataSize.ofGigabytes(3).toBytes());\n\t\t\t});\n\t}\n\n\tprivate DefaultPartHttpMessageReader getDefaultPartReader(DefaultServerCodecConfigurer codecConfigurer) {\n\t\treturn codecConfigurer.getReaders()\n\t\t\t.stream()\n\t\t\t.filter(DefaultPartHttpMessageReader.class::isInstance)\n\t\t\t.map(DefaultPartHttpMessageReader.class::cast)\n\t\t\t.findFirst()\n\t\t\t.orElseThrow(() -> new IllegalStateException(\"Could not find DefaultPartHttpMessageReader\"));\n\t}\n\n\tprivate PartEventHttpMessageReader getPartEventReader(DefaultServerCodecConfigurer codecConfigurer) {\n\t\treturn codecConfigurer.getReaders()\n\t\t\t.stream()\n\t\t\t.filter(PartEventHttpMessageReader.class::isInstance)\n\t\t\t.map(PartEventHttpMessageReader.class::cast)\n\t\t\t.findFirst()\n\t\t\t.orElseThrow(() -> new IllegalStateException(\"Could not find PartEventHttpMessageReader\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/ReactiveMultipartPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.http.codec.multipart.DefaultPartHttpMessageReader;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ReactiveMultipartProperties}\n *\n * @author Chris Bono\n */\nclass ReactiveMultipartPropertiesTests {\n\n\t@Test\n\tvoid defaultValuesAreConsistent() {\n\t\tReactiveMultipartProperties multipartProperties = new ReactiveMultipartProperties();\n\t\tDefaultPartHttpMessageReader defaultPartHttpMessageReader = new DefaultPartHttpMessageReader();\n\t\tassertThat(defaultPartHttpMessageReader).hasFieldOrPropertyWithValue(\"maxInMemorySize\",\n\t\t\t\t(int) multipartProperties.getMaxInMemorySize().toBytes());\n\t\tassertThat(defaultPartHttpMessageReader).hasFieldOrPropertyWithValue(\"maxHeadersSize\",\n\t\t\t\t(int) multipartProperties.getMaxHeadersSize().toBytes());\n\t\tassertThat(defaultPartHttpMessageReader).hasFieldOrPropertyWithValue(\"maxDiskUsagePerPart\",\n\t\t\t\tmultipartProperties.getMaxDiskUsagePerPart().toBytes());\n\t\tassertThat(defaultPartHttpMessageReader).hasFieldOrPropertyWithValue(\"maxParts\",\n\t\t\t\tmultipartProperties.getMaxParts());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.time.format.FormatStyle;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport jakarta.validation.ValidatorFactory;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.annotation.AfterReturning;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration;\nimport org.springframework.boot.validation.autoconfigure.ValidatorAdapter;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.boot.web.server.reactive.MockReactiveWebServerFactory;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration.WebFluxConfig;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration.WebFluxValidatorRuntimeHints;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice;\nimport org.springframework.boot.webflux.filter.OrderedHiddenHttpMethodFilter;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.i18n.LocaleContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.format.Parser;\nimport org.springframework.format.Printer;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.http.CacheControl;\nimport org.springframework.http.ResponseCookie;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\nimport org.springframework.web.accept.ApiVersionParser;\nimport org.springframework.web.accept.InvalidApiVersionException;\nimport org.springframework.web.accept.MissingApiVersionException;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.filter.reactive.HiddenHttpMethodFilter;\nimport org.springframework.web.method.ControllerAdviceBean;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.accept.ApiVersionDeprecationHandler;\nimport org.springframework.web.reactive.accept.ApiVersionResolver;\nimport org.springframework.web.reactive.accept.DefaultApiVersionStrategy;\nimport org.springframework.web.reactive.accept.RequestedContentTypeResolver;\nimport org.springframework.web.reactive.accept.StandardApiVersionDeprecationHandler;\nimport org.springframework.web.reactive.config.BlockingExecutionConfigurer;\nimport org.springframework.web.reactive.config.DelegatingWebFluxConfiguration;\nimport org.springframework.web.reactive.config.ResourceHandlerRegistration;\nimport org.springframework.web.reactive.config.WebFluxConfigurationSupport;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.reactive.function.server.support.RouterFunctionMapping;\nimport org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;\nimport org.springframework.web.reactive.resource.CachingResourceResolver;\nimport org.springframework.web.reactive.resource.CachingResourceTransformer;\nimport org.springframework.web.reactive.resource.PathResourceResolver;\nimport org.springframework.web.reactive.resource.ResourceWebHandler;\nimport org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;\nimport org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;\nimport org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.reactive.result.method.annotation.ResponseEntityExceptionHandler;\nimport org.springframework.web.reactive.result.view.ViewResolutionResultHandler;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebSession;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\nimport org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;\nimport org.springframework.web.server.i18n.FixedLocaleContextResolver;\nimport org.springframework.web.server.i18n.LocaleContextResolver;\nimport org.springframework.web.server.session.CookieWebSessionIdResolver;\nimport org.springframework.web.server.session.DefaultWebSessionManager;\nimport org.springframework.web.server.session.InMemoryWebSessionStore;\nimport org.springframework.web.server.session.WebSessionIdResolver;\nimport org.springframework.web.server.session.WebSessionManager;\nimport org.springframework.web.server.session.WebSessionStore;\nimport org.springframework.web.util.pattern.PathPattern;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.setExtractBareNamePropertyMethods;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\n\n/**\n * Tests for {@link WebFluxAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Andy Wilkinson\n * @author Artsiom Yudovin\n * @author Vedran Pavic\n */\nclass WebFluxAutoConfigurationTests {\n\n\tprivate static final MockReactiveWebServerFactory mockReactiveWebServerFactory = new MockReactiveWebServerFactory();\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(WebFluxAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class))\n\t\t.withUserConfiguration(Config.class);\n\n\t@Test\n\tvoid shouldNotProcessIfExistingWebReactiveConfiguration() {\n\t\tthis.contextRunner.withUserConfiguration(WebFluxConfigurationSupport.class).run((context) -> {\n\t\t\tassertThat(context).getBeans(RequestMappingHandlerMapping.class).hasSize(1);\n\t\t\tassertThat(context).getBeans(RequestMappingHandlerAdapter.class).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCreateDefaultBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).getBeans(RequestMappingHandlerMapping.class).hasSize(1);\n\t\t\tassertThat(context).getBeans(RequestMappingHandlerAdapter.class).hasSize(1);\n\t\t\tassertThat(context).getBeans(RequestedContentTypeResolver.class).hasSize(1);\n\t\t\tassertThat(context).getBeans(RouterFunctionMapping.class).hasSize(1);\n\t\t\tassertThat(context.getBean(WebHttpHandlerBuilder.WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class))\n\t\t\t\t.isNotNull();\n\t\t\tassertThat(context.getBean(\"resourceHandlerMapping\", HandlerMapping.class)).isNotNull();\n\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@Test\n\tvoid shouldRegisterCustomHandlerMethodArgumentResolver() {\n\t\tthis.contextRunner.withUserConfiguration(CustomArgumentResolvers.class).run((context) -> {\n\t\t\tRequestMappingHandlerAdapter adapter = context.getBean(RequestMappingHandlerAdapter.class);\n\t\t\tArgumentResolverConfigurer configurer = adapter.getArgumentResolverConfigurer();\n\t\t\tassertThat(configurer).isNotNull();\n\t\t\tList<HandlerMethodArgumentResolver> customResolvers = (List<HandlerMethodArgumentResolver>) ReflectionTestUtils\n\t\t\t\t.getField(configurer, \"customResolvers\");\n\t\t\tassertThat(customResolvers).contains(context.getBean(\"firstResolver\", HandlerMethodArgumentResolver.class),\n\t\t\t\t\tcontext.getBean(\"secondResolver\", HandlerMethodArgumentResolver.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeCodecs() {\n\t\tthis.contextRunner.withUserConfiguration(CustomCodecCustomizers.class).run((context) -> {\n\t\t\tCodecCustomizer codecCustomizer = context.getBean(\"firstCodecCustomizer\", CodecCustomizer.class);\n\t\t\tassertThat(codecCustomizer).isNotNull();\n\t\t\tthen(codecCustomizer).should().customize(any(ServerCodecConfigurer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeResources() {\n\t\tthis.contextRunner.withUserConfiguration(ResourceHandlerRegistrationCustomizers.class).run((context) -> {\n\t\t\tResourceHandlerRegistrationCustomizer customizer1 = context\n\t\t\t\t.getBean(\"firstResourceHandlerRegistrationCustomizer\", ResourceHandlerRegistrationCustomizer.class);\n\t\t\tResourceHandlerRegistrationCustomizer customizer2 = context\n\t\t\t\t.getBean(\"secondResourceHandlerRegistrationCustomizer\", ResourceHandlerRegistrationCustomizer.class);\n\t\t\tthen(customizer1).should(times(2)).customize(any(ResourceHandlerRegistration.class));\n\t\t\tthen(customizer2).should(times(2)).customize(any(ResourceHandlerRegistration.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterResourceHandlerMapping() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tSimpleUrlHandlerMapping hm = context.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class);\n\t\t\tassertThat(hm.getUrlMap().get(\"/**\")).isInstanceOf(ResourceWebHandler.class);\n\t\t\tResourceWebHandler staticHandler = (ResourceWebHandler) hm.getUrlMap().get(\"/**\");\n\t\t\tassertThat(staticHandler.getLocations()).hasSize(4);\n\t\t\tassertThat(hm.getUrlMap().get(\"/webjars/**\")).isInstanceOf(ResourceWebHandler.class);\n\t\t\tResourceWebHandler webjarsHandler = (ResourceWebHandler) hm.getUrlMap().get(\"/webjars/**\");\n\t\t\tassertThat(webjarsHandler.getLocations()).hasSize(1);\n\t\t\tassertThat(webjarsHandler.getLocations().get(0))\n\t\t\t\t.isEqualTo(new ClassPathResource(\"/META-INF/resources/webjars/\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldMapResourcesToCustomPath() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.static-path-pattern:/static/**\").run((context) -> {\n\t\t\tSimpleUrlHandlerMapping hm = context.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class);\n\t\t\tassertThat(hm.getUrlMap().get(\"/static/**\")).isInstanceOf(ResourceWebHandler.class);\n\t\t\tResourceWebHandler staticHandler = (ResourceWebHandler) hm.getUrlMap().get(\"/static/**\");\n\t\t\tassertThat(staticHandler).extracting(\"locationValues\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.hasSize(4);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldMapWebjarsToCustomPath() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.webjars-path-pattern:/assets/**\").run((context) -> {\n\t\t\tSimpleUrlHandlerMapping hm = context.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class);\n\t\t\tassertThat(hm.getUrlMap().get(\"/assets/**\")).isInstanceOf(ResourceWebHandler.class);\n\t\t\tResourceWebHandler webjarsHandler = (ResourceWebHandler) hm.getUrlMap().get(\"/assets/**\");\n\t\t\tassertThat(webjarsHandler.getLocations()).hasSize(1);\n\t\t\tassertThat(webjarsHandler.getLocations().get(0))\n\t\t\t\t.isEqualTo(new ClassPathResource(\"/META-INF/resources/webjars/\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotMapResourcesWhenDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.add-mappings:false\")\n\t\t\t.run((context) -> assertThat(context.getBean(\"resourceHandlerMapping\"))\n\t\t\t\t.isNotInstanceOf(SimpleUrlHandlerMapping.class));\n\t}\n\n\t@Test\n\tvoid resourceHandlerChainEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.chain.enabled:true\").run((context) -> {\n\t\t\tSimpleUrlHandlerMapping hm = context.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class);\n\t\t\tassertThat(hm.getUrlMap().get(\"/**\")).isInstanceOf(ResourceWebHandler.class);\n\t\t\tResourceWebHandler staticHandler = (ResourceWebHandler) hm.getUrlMap().get(\"/**\");\n\t\t\tassertThat(staticHandler.getResourceResolvers()).extractingResultOf(\"getClass\")\n\t\t\t\t.containsOnly(CachingResourceResolver.class, PathResourceResolver.class);\n\t\t\tassertThat(staticHandler.getResourceTransformers()).extractingResultOf(\"getClass\")\n\t\t\t\t.containsOnly(CachingResourceTransformer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldRegisterViewResolvers() {\n\t\tthis.contextRunner.withUserConfiguration(ViewResolvers.class).run((context) -> {\n\t\t\tViewResolutionResultHandler resultHandler = context.getBean(ViewResolutionResultHandler.class);\n\t\t\tassertThat(resultHandler.getViewResolvers()).containsExactly(\n\t\t\t\t\tcontext.getBean(\"aViewResolver\", ViewResolver.class),\n\t\t\t\t\tcontext.getBean(\"anotherViewResolver\", ViewResolver.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDateFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tDate date = Date.from(ZonedDateTime.of(1988, 6, 25, 20, 30, 0, 0, ZoneId.systemDefault()).toInstant());\n\t\t\t// formatting conversion service should use simple toString()\n\t\t\tassertThat(conversionService.convert(date, String.class)).isEqualTo(date.toString());\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.format.date:dd*MM*yyyy\").run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tDate date = Date.from(ZonedDateTime.of(1988, 6, 25, 20, 30, 0, 0, ZoneId.systemDefault()).toInstant());\n\t\t\tassertThat(conversionService.convert(date, String.class)).isEqualTo(\"25*06*1988\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultTimeFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalTime time = LocalTime.of(11, 43, 10);\n\t\t\tassertThat(conversionService.convert(time, String.class))\n\t\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(time));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.format.time=HH:mm:ss\").run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalTime time = LocalTime.of(11, 43, 10);\n\t\t\tassertThat(conversionService.convert(time, String.class)).isEqualTo(\"11:43:10\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDateTimeFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 28, 11, 43, 10);\n\t\t\tassertThat(conversionService.convert(dateTime, String.class))\n\t\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).format(dateTime));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateTimeTimeFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.format.date-time=yyyy-MM-dd HH:mm:ss\").run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 28, 11, 43, 10);\n\t\t\tassertThat(conversionService.convert(dateTime, String.class)).isEqualTo(\"2020-04-28 11:43:10\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWhenNoValidatorShouldUseDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(jakarta.validation.Validator.class);\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsExactly(\"webFluxValidator\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWhenNoCustomizationShouldUseAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class)\n\t\t\t\t\t.containsExactly(\"defaultValidator\");\n\t\t\t\tassertThat(context).getBeanNames(Validator.class)\n\t\t\t\t\t.containsExactlyInAnyOrder(\"defaultValidator\", \"webFluxValidator\");\n\t\t\t\tValidator validator = context.getBean(\"webFluxValidator\", Validator.class);\n\t\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\t\tObject defaultValidator = context.getBean(\"defaultValidator\");\n\t\t\t\tassertThat(((ValidatorAdapter) validator).getTarget()).isSameAs(defaultValidator);\n\t\t\t\t// Primary Spring validator is the one used by WebFlux behind the\n\t\t\t\t// scenes\n\t\t\t\tassertThat(context.getBean(Validator.class)).isEqualTo(defaultValidator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithConfigurerShouldUseSpringValidator() {\n\t\tthis.contextRunner.withUserConfiguration(ValidatorWebFluxConfigurer.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(jakarta.validation.Validator.class);\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"webFluxValidator\");\n\t\t\tassertThat(context.getBean(\"webFluxValidator\"))\n\t\t\t\t.isSameAs(context.getBean(ValidatorWebFluxConfigurer.class).validator);\n\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithConfigurerDoesNotExposeJsr303() {\n\t\tthis.contextRunner.withUserConfiguration(ValidatorJsr303WebFluxConfigurer.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(jakarta.validation.Validator.class);\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"webFluxValidator\");\n\t\t\tValidator validator = context.getBean(\"webFluxValidator\", Validator.class);\n\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\tassertThat(((ValidatorAdapter) validator).getTarget())\n\t\t\t\t.isSameAs(context.getBean(ValidatorJsr303WebFluxConfigurer.class).validator);\n\t\t});\n\t}\n\n\t@Test\n\tvoid validationCustomConfigurerTakesPrecedence() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(ValidatorWebFluxConfigurer.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(ValidatorFactory.class).hasSize(1);\n\t\t\t\tassertThat(context).getBeans(jakarta.validation.Validator.class).hasSize(1);\n\t\t\t\tassertThat(context).getBeanNames(Validator.class)\n\t\t\t\t\t.containsExactlyInAnyOrder(\"defaultValidator\", \"webFluxValidator\");\n\t\t\t\tassertThat(context.getBean(\"webFluxValidator\"))\n\t\t\t\t\t.isSameAs(context.getBean(ValidatorWebFluxConfigurer.class).validator);\n\t\t\t\t// Primary Spring validator is the auto-configured one as the WebFlux\n\t\t\t\t// one has been customized through a WebFluxConfigurer\n\t\t\t\tassertThat(context.getBean(Validator.class)).isEqualTo(context.getBean(\"defaultValidator\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithCustomSpringValidatorIgnored() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomSpringValidator.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class)\n\t\t\t\t\t.containsExactly(\"defaultValidator\");\n\t\t\t\tassertThat(context).getBeanNames(Validator.class)\n\t\t\t\t\t.containsExactlyInAnyOrder(\"customValidator\", \"defaultValidator\", \"webFluxValidator\");\n\t\t\t\tValidator validator = context.getBean(\"webFluxValidator\", Validator.class);\n\t\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\t\tObject defaultValidator = context.getBean(\"defaultValidator\");\n\t\t\t\tassertThat(((ValidatorAdapter) validator).getTarget()).isSameAs(defaultValidator);\n\t\t\t\t// Primary Spring validator is the one used by WebFlux behind the\n\t\t\t\t// scenes\n\t\t\t\tassertThat(context.getBean(Validator.class)).isEqualTo(defaultValidator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithCustomJsr303ValidatorExposedAsSpringValidator() {\n\t\tthis.contextRunner.withUserConfiguration(CustomJsr303Validator.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class).containsExactly(\"customValidator\");\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsExactly(\"webFluxValidator\");\n\t\t\tValidator validator = context.getBean(Validator.class);\n\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\tValidator target = ((ValidatorAdapter) validator).getTarget();\n\t\t\tassertThat(target).hasFieldOrPropertyWithValue(\"targetValidator\", context.getBean(\"customValidator\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid hiddenHttpMethodFilterIsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HiddenHttpMethodFilter.class));\n\t}\n\n\t@Test\n\tvoid hiddenHttpMethodFilterCanBeOverridden() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.hiddenmethod.filter.enabled=true\")\n\t\t\t.withUserConfiguration(CustomHiddenHttpMethodFilter.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(OrderedHiddenHttpMethodFilter.class);\n\t\t\t\tassertThat(context).hasSingleBean(HiddenHttpMethodFilter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid hiddenHttpMethodFilterCanBeEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.hiddenmethod.filter.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OrderedHiddenHttpMethodFilter.class));\n\t}\n\n\t@Test\n\tvoid customRequestMappingHandlerMapping() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRequestMappingHandlerMapping.class).run((context) -> {\n\t\t\tassertThat(context).getBean(RequestMappingHandlerMapping.class)\n\t\t\t\t.isInstanceOf(MyRequestMappingHandlerMapping.class);\n\t\t\tassertThat(context.getBean(CustomRequestMappingHandlerMapping.class).handlerMappings).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customRequestMappingHandlerAdapter() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRequestMappingHandlerAdapter.class).run((context) -> {\n\t\t\tassertThat(context).getBean(RequestMappingHandlerAdapter.class)\n\t\t\t\t.isInstanceOf(MyRequestMappingHandlerAdapter.class);\n\t\t\tassertThat(context.getBean(CustomRequestMappingHandlerAdapter.class).handlerAdapters).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid multipleWebFluxRegistrations() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleWebFluxRegistrations.class).run((context) -> {\n\t\t\tassertThat(context.getBean(RequestMappingHandlerMapping.class))\n\t\t\t\t.isNotInstanceOf(MyRequestMappingHandlerMapping.class);\n\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t\t.isNotInstanceOf(MyRequestMappingHandlerAdapter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid cachePeriod() {\n\t\tsetExtractBareNamePropertyMethods(false);\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.cache.period:5\").run((context) -> {\n\t\t\tMap<PathPattern, Object> handlerMap = getHandlerMap(context);\n\t\t\tassertThat(handlerMap).hasSize(2);\n\t\t\tfor (Object handler : handlerMap.values()) {\n\t\t\t\tif (handler instanceof ResourceWebHandler resourceWebHandler) {\n\t\t\t\t\tassertThat(resourceWebHandler.getCacheControl()).usingRecursiveComparison()\n\t\t\t\t\t\t.isEqualTo(CacheControl.maxAge(5, TimeUnit.SECONDS));\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tsetExtractBareNamePropertyMethods(true);\n\t}\n\n\t@Test\n\tvoid cacheControl() {\n\t\tsetExtractBareNamePropertyMethods(false);\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.resources.cache.cachecontrol.max-age:5\",\n\t\t\t\t\t\"spring.web.resources.cache.cachecontrol.proxy-revalidate:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tMap<PathPattern, Object> handlerMap = getHandlerMap(context);\n\t\t\t\tassertThat(handlerMap).hasSize(2);\n\t\t\t\tfor (Object handler : handlerMap.values()) {\n\t\t\t\t\tif (handler instanceof ResourceWebHandler resourceWebHandler) {\n\t\t\t\t\t\tassertThat(resourceWebHandler.getCacheControl()).usingRecursiveComparison()\n\t\t\t\t\t\t\t.isEqualTo(CacheControl.maxAge(5, TimeUnit.SECONDS).proxyRevalidate());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\tsetExtractBareNamePropertyMethods(true);\n\t}\n\n\t@Test\n\tvoid useLastModified() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.cache.use-last-modified=false\").run((context) -> {\n\t\t\tMap<PathPattern, Object> handlerMap = getHandlerMap(context);\n\t\t\tassertThat(handlerMap).hasSize(2);\n\t\t\tfor (Object handler : handlerMap.values()) {\n\t\t\t\tif (handler instanceof ResourceWebHandler resourceWebHandler) {\n\t\t\t\t\tassertThat(resourceWebHandler.isUseLastModified()).isFalse();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPrinterAndParserShouldBeRegisteredAsConverters() {\n\t\tthis.contextRunner.withUserConfiguration(ParserConfiguration.class, PrinterConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConversionService service = context.getBean(ConversionService.class);\n\t\t\t\tassertThat(service.convert(new Example(\"spring\", new Date()), String.class)).isEqualTo(\"spring\");\n\t\t\t\tassertThat(service.convert(\"boot\", Example.class)).extracting(Example::getName).isEqualTo(\"boot\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"welcome-page/index.html\", content = \"welcome-page-static\")\n\tvoid welcomePageHandlerMapping() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.static-locations=classpath:/welcome-page/\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeans(RouterFunctionMapping.class).hasSize(2);\n\t\t\t\tassertThat(context.getBean(\"welcomePageRouterFunctionMapping\", HandlerMapping.class)).isNotNull()\n\t\t\t\t\t.extracting(\"order\")\n\t\t\t\t\t.isEqualTo(1);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultLocaleContextResolver() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(LocaleContextResolver.class);\n\t\t\tLocaleContextResolver resolver = context.getBean(LocaleContextResolver.class);\n\t\t\tassertThat(((AcceptHeaderLocaleContextResolver) resolver).getDefaultLocale()).isNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenFixedLocalContextResolverIsUsedThenAcceptLanguagesHeaderIsIgnored() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.locale:en_UK\", \"spring.web.locale-resolver=fixed\")\n\t\t\t.run((context) -> {\n\t\t\t\tLocale locale = StringUtils.parseLocaleString(\"nl_NL\");\n\t\t\t\tassertThat(locale).isNotNull();\n\t\t\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/\").acceptLanguageAsLocales(locale).build();\n\t\t\t\tMockServerWebExchange exchange = MockServerWebExchange.from(request);\n\t\t\t\tLocaleContextResolver localeContextResolver = context.getBean(LocaleContextResolver.class);\n\t\t\t\tassertThat(localeContextResolver).isInstanceOf(FixedLocaleContextResolver.class);\n\t\t\t\tLocaleContext localeContext = localeContextResolver.resolveLocaleContext(exchange);\n\t\t\t\tassertThat(localeContext.getLocale()).isEqualTo(StringUtils.parseLocaleString(\"en_UK\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid whenAcceptHeaderLocaleContextResolverIsUsedThenAcceptLanguagesHeaderIsHonoured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.locale:en_UK\").run((context) -> {\n\t\t\tLocale locale = StringUtils.parseLocaleString(\"nl_NL\");\n\t\t\tassertThat(locale).isNotNull();\n\t\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/\").acceptLanguageAsLocales(locale).build();\n\t\t\tMockServerWebExchange exchange = MockServerWebExchange.from(request);\n\t\t\tLocaleContextResolver localeContextResolver = context.getBean(LocaleContextResolver.class);\n\t\t\tassertThat(localeContextResolver).isInstanceOf(AcceptHeaderLocaleContextResolver.class);\n\t\t\tLocaleContext localeContext = localeContextResolver.resolveLocaleContext(exchange);\n\t\t\tassertThat(localeContext.getLocale()).isEqualTo(locale);\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenAcceptHeaderLocaleContextResolverIsUsedAndHeaderIsAbsentThenConfiguredLocaleIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.locale:en_UK\").run((context) -> {\n\t\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/\").build();\n\t\t\tMockServerWebExchange exchange = MockServerWebExchange.from(request);\n\t\t\tLocaleContextResolver localeContextResolver = context.getBean(LocaleContextResolver.class);\n\t\t\tassertThat(localeContextResolver).isInstanceOf(AcceptHeaderLocaleContextResolver.class);\n\t\t\tLocaleContext localeContext = localeContextResolver.resolveLocaleContext(exchange);\n\t\t\tassertThat(localeContext.getLocale()).isEqualTo(StringUtils.parseLocaleString(\"en_UK\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customLocaleContextResolverWithMatchingNameReplacedAutoConfiguredLocaleContextResolver() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"localeContextResolver\", CustomLocaleContextResolver.class, CustomLocaleContextResolver::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LocaleContextResolver.class);\n\t\t\t\tassertThat(context.getBean(\"localeContextResolver\")).isInstanceOf(CustomLocaleContextResolver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customLocaleContextResolverWithDifferentNameDoesNotReplaceAutoConfiguredLocaleContextResolver() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customLocaleContextResolver\", CustomLocaleContextResolver.class,\n\t\t\t\t\tCustomLocaleContextResolver::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(\"customLocaleContextResolver\"))\n\t\t\t\t\t.isInstanceOf(CustomLocaleContextResolver.class);\n\t\t\t\tassertThat(context.getBean(\"localeContextResolver\"))\n\t\t\t\t\t.isInstanceOf(AcceptHeaderLocaleContextResolver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid userConfigurersCanBeOrderedBeforeOrAfterTheAutoConfiguredConfigurer() {\n\t\tthis.contextRunner.withBean(HighPrecedenceConfigurer.class, HighPrecedenceConfigurer::new)\n\t\t\t.withBean(LowPrecedenceConfigurer.class, LowPrecedenceConfigurer::new)\n\t\t\t.run((context) -> assertThat(context.getBean(DelegatingWebFluxConfiguration.class))\n\t\t\t\t.extracting(\"configurers.delegates\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.extracting((configurer) -> (Class) configurer.getClass())\n\t\t\t\t.containsExactly(HighPrecedenceConfigurer.class, WebFluxConfig.class, LowPrecedenceConfigurer.class));\n\t}\n\n\t@Test\n\tvoid customWebSessionIdResolverShouldBeApplied() {\n\t\tthis.contextRunner.withUserConfiguration(CustomWebSessionIdResolver.class)\n\t\t\t.run(assertExchangeWithSession(\n\t\t\t\t\t(exchange) -> assertThat(exchange.getResponse().getCookies().get(\"TEST\")).isNotEmpty()));\n\t}\n\n\t@Test\n\tvoid customSessionTimeoutConfigurationShouldBeApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"server.reactive.session.timeout:123\")\n\t\t\t.run((assertSessionTimeoutWithWebSession((webSession) -> {\n\t\t\t\twebSession.start();\n\t\t\t\tassertThat(webSession.getMaxIdleTime()).hasSeconds(123);\n\t\t\t})));\n\t}\n\n\t@Test\n\tvoid customSessionMaxSessionsConfigurationShouldBeApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"server.reactive.session.max-sessions:123\")\n\t\t\t.run(assertMaxSessionsWithWebSession(123));\n\t}\n\n\t@Test\n\tvoid defaultSessionMaxSessionsConfigurationShouldBeInSync() {\n\t\tint defaultMaxSessions = new InMemoryWebSessionStore().getMaxSessions();\n\t\tthis.contextRunner.run(assertMaxSessionsWithWebSession(defaultMaxSessions));\n\t}\n\n\t@Test\n\tvoid customSessionCookieConfigurationShouldBeApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"server.reactive.session.cookie.name:JSESSIONID\",\n\t\t\t\t\"server.reactive.session.cookie.domain:.example.com\", \"server.reactive.session.cookie.path:/example\",\n\t\t\t\t\"server.reactive.session.cookie.max-age:60\", \"server.reactive.session.cookie.http-only:false\",\n\t\t\t\t\"server.reactive.session.cookie.secure:false\", \"server.reactive.session.cookie.same-site:strict\",\n\t\t\t\t\"server.reactive.session.cookie.partitioned:true\")\n\t\t\t.run(assertExchangeWithSession((exchange) -> {\n\t\t\t\tList<ResponseCookie> cookies = exchange.getResponse().getCookies().get(\"JSESSIONID\");\n\t\t\t\tassertThat(cookies).isNotEmpty();\n\t\t\t\tassertThat(cookies)\n\t\t\t\t\t.allMatch((cookie) -> cookie.getDomain() != null && cookie.getDomain().equals(\".example.com\"));\n\t\t\t\tassertThat(cookies)\n\t\t\t\t\t.allMatch((cookie) -> cookie.getPath() != null && cookie.getPath().equals(\"/example\"));\n\t\t\t\tassertThat(cookies).allMatch((cookie) -> cookie.getMaxAge().equals(Duration.ofSeconds(60)));\n\t\t\t\tassertThat(cookies).allMatch((cookie) -> !cookie.isHttpOnly());\n\t\t\t\tassertThat(cookies).allMatch((cookie) -> !cookie.isSecure());\n\t\t\t\tassertThat(cookies)\n\t\t\t\t\t.allMatch((cookie) -> cookie.getSameSite() != null && cookie.getSameSite().equals(\"Strict\"));\n\t\t\t\tassertThat(cookies).allMatch(ResponseCookie::isPartitioned);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid sessionCookieOmittedConfigurationShouldBeApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"server.reactive.session.cookie.same-site:omitted\")\n\t\t\t.run(assertExchangeWithSession((exchange) -> {\n\t\t\t\tList<ResponseCookie> cookies = exchange.getResponse().getCookies().get(\"SESSION\");\n\t\t\t\tassertThat(cookies).extracting(ResponseCookie::getSameSite).containsOnlyNulls();\n\t\t\t}));\n\t}\n\n\t@ParameterizedTest\n\t@ValueSource(classes = { ServerProperties.class, WebFluxProperties.class })\n\tvoid propertiesAreNotEnabledInNonWebApplication(Class<?> propertiesClass) {\n\t\tnew ApplicationContextRunner()\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(WebFluxAutoConfiguration.class, WebSessionIdResolverAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(propertiesClass));\n\t}\n\n\t@Test\n\tvoid problemDetailsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ProblemDetailsExceptionHandler.class));\n\t}\n\n\t@Test\n\tvoid problemDetailsEnabledAddsExceptionHandler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.problemdetails.enabled:true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ProblemDetailsExceptionHandler.class));\n\t}\n\n\t@Test\n\tvoid problemDetailsExceptionHandlerDoesNotPreventProxying() {\n\t\tthis.contextRunner.withUserConfiguration(AopConfiguration.class)\n\t\t\t.withBean(ExceptionHandlerInterceptor.class)\n\t\t\t.withPropertyValues(\"spring.webflux.problemdetails.enabled:true\")\n\t\t\t.run((context) -> assertThat(context).getBean(ProblemDetailsExceptionHandler.class)\n\t\t\t\t.matches(AopUtils::isCglibProxy));\n\t}\n\n\t@Test\n\tvoid problemDetailsBacksOffWhenExceptionHandler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.problemdetails.enabled:true\")\n\t\t\t.withUserConfiguration(CustomExceptionHandlerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ProblemDetailsExceptionHandler.class)\n\t\t\t\t.hasSingleBean(CustomExceptionHandler.class));\n\t}\n\n\t@Test\n\tvoid problemDetailsExceptionHandlerIsOrderedAt0() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.problemdetails.enabled:true\")\n\t\t\t.withUserConfiguration(OrderedControllerAdviceBeansConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tControllerAdviceBean.findAnnotatedBeans(context).stream().map(ControllerAdviceBean::getBeanType))\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(Class.class))\n\t\t\t\t.containsExactly(HighestOrderedControllerAdvice.class, ProblemDetailsExceptionHandler.class,\n\t\t\t\t\t\tLowestOrderedControllerAdvice.class));\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorWithPlatformThreadsAndApplicationTaskExecutor() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"scheduler.executor\")\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid asyncTaskExecutorWithVirtualThreadsAndApplicationTaskExecutor() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"scheduler.executor\")\n\t\t\t\t\t.isSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid asyncTaskExecutorWithVirtualThreadsAndNonMatchApplicationTaskExecutorBean() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withUserConfiguration(CustomApplicationTaskExecutorConfig.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"scheduler.executor\")\n\t\t\t\t\t.isNotSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid asyncTaskExecutorWithVirtualThreadsAndWebFluxConfigurerCanOverrideExecutor() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withUserConfiguration(CustomAsyncTaskExecutorConfigurer.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t\t.extracting(\"scheduler.executor\")\n\t\t\t\t.isSameAs(context.getBean(CustomAsyncTaskExecutorConfigurer.class).taskExecutor));\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid asyncTaskExecutorWithVirtualThreadsAndCustomNonApplicationTaskExecutor() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.threads.virtual.enabled=true\")\n\t\t\t.withUserConfiguration(CustomAsyncTaskExecutorConfig.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"scheduler.executor\")\n\t\t\t\t\t.isNull();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionPropertiesAreApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.webflux.apiversion.use.header=version\",\n\t\t\t\t\t\"spring.webflux.apiversion.required=true\", \"spring.webflux.apiversion.supported=123,456\",\n\t\t\t\t\t\"spring.webflux.apiversion.detect-supported=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t\t\t.from(MockServerHttpRequest.get(\"https://example.com\"));\n\t\t\t\tassertThatExceptionOfType(MissingApiVersionException.class)\n\t\t\t\t\t.isThrownBy(() -> versionStrategy.validateVersion(null, request));\n\t\t\t\tassertThatExceptionOfType(InvalidApiVersionException.class)\n\t\t\t\t\t.isThrownBy(() -> versionStrategy.validateVersion(versionStrategy.parseVersion(\"789\"),\n\t\t\t\t\t\t\tMockServerWebExchange.from(MockServerHttpRequest.get(\"https://example.com\"))));\n\t\t\t\tassertThat(versionStrategy.detectSupportedVersions()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionDefaultVersionPropertyIsApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.webflux.apiversion.use.header=version\",\n\t\t\t\t\t\"spring.webflux.apiversion.default=1.0.0\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t\t\t.from(MockServerHttpRequest.get(\"https://example.com\"));\n\t\t\t\tversionStrategy.addSupportedVersion(\"1.0.0\");\n\t\t\t\tComparable<?> version = versionStrategy.parseVersion(\"1.0.0\");\n\t\t\t\tassertThat(versionStrategy.getDefaultVersion()).isEqualTo(version);\n\t\t\t\tversionStrategy.validateVersion(version, request);\n\t\t\t\tversionStrategy.validateVersion(null, request);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUseHeaderPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.apiversion.use.header=hv\").run((context) -> {\n\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t\t.from(MockServerHttpRequest.get(\"https://example.com\").header(\"hv\", \"123\"));\n\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUseQueryParameterPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.apiversion.use.query-parameter=rpv\").run((context) -> {\n\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t\t.from(MockServerHttpRequest.get(\"https://example.com?rpv=123\"));\n\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUsePathSegmentPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webflux.apiversion.use.path-segment=1\").run((context) -> {\n\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t\t.from(MockServerHttpRequest.get(\"https://example.com/test/123\"));\n\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUseMediaTypeParameterPropertyIsApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.webflux.apiversion.use.media-type-parameter[application/json]=mtpv\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\t\tMockServerWebExchange request = MockServerWebExchange\n\t\t\t\t\t.from(MockServerHttpRequest.get(\"https://example.com\")\n\t\t\t\t\t\t.header(\"content-type\", \"application/json;mtpv=123\"));\n\t\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionBeansAreInjected() {\n\t\tthis.contextRunner.withUserConfiguration(ApiVersionConfiguration.class).run((context) -> {\n\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"webFluxApiVersionStrategy\",\n\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\tassertThat(versionStrategy).extracting(\"versionResolvers\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.containsExactly(context.getBean(ApiVersionResolver.class));\n\t\t\tassertThat(versionStrategy).extracting(\"deprecationHandler\")\n\t\t\t\t.isEqualTo(context.getBean(ApiVersionDeprecationHandler.class));\n\t\t\tassertThat(versionStrategy).extracting(\"versionParser\").isEqualTo(context.getBean(ApiVersionParser.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid registersRuntimeHintsForValidatorCreation() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew WebFluxValidatorRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ValidatorAdapter.class)).accepts(hints);\n\t}\n\n\tprivate ContextConsumer<ReactiveWebApplicationContext> assertExchangeWithSession(\n\t\t\tConsumer<MockServerWebExchange> exchange) {\n\t\treturn (context) -> {\n\t\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/\").build();\n\t\t\tMockServerWebExchange webExchange = MockServerWebExchange.from(request);\n\t\t\tWebSessionManager webSessionManager = context.getBean(WebSessionManager.class);\n\t\t\tWebSession webSession = webSessionManager.getSession(webExchange).block();\n\t\t\tassertThat(webSession).isNotNull();\n\t\t\twebSession.start();\n\t\t\twebExchange.getResponse().setComplete().block();\n\t\t\texchange.accept(webExchange);\n\t\t};\n\t}\n\n\tprivate ContextConsumer<ReactiveWebApplicationContext> assertSessionTimeoutWithWebSession(\n\t\t\tConsumer<WebSession> session) {\n\t\treturn (context) -> {\n\t\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/\").build();\n\t\t\tMockServerWebExchange webExchange = MockServerWebExchange.from(request);\n\t\t\tWebSessionManager webSessionManager = context.getBean(WebSessionManager.class);\n\t\t\tWebSession webSession = webSessionManager.getSession(webExchange).block();\n\t\t\tsession.accept(webSession);\n\t\t};\n\t}\n\n\tprivate ContextConsumer<ReactiveWebApplicationContext> assertMaxSessionsWithWebSession(int maxSessions) {\n\t\treturn (context) -> {\n\t\t\tWebSessionManager sessionManager = context.getBean(WebSessionManager.class);\n\t\t\tassertThat(sessionManager).isInstanceOf(DefaultWebSessionManager.class);\n\t\t\tWebSessionStore sessionStore = ((DefaultWebSessionManager) sessionManager).getSessionStore();\n\t\t\tassertThat(sessionStore).isInstanceOf(InMemoryWebSessionStore.class);\n\t\t\tassertThat(((InMemoryWebSessionStore) sessionStore).getMaxSessions()).isEqualTo(maxSessions);\n\t\t};\n\t}\n\n\tprivate Map<PathPattern, Object> getHandlerMap(ApplicationContext context) {\n\t\tHandlerMapping mapping = context.getBean(\"resourceHandlerMapping\", HandlerMapping.class);\n\t\tif (mapping instanceof SimpleUrlHandlerMapping simpleMapping) {\n\t\t\treturn simpleMapping.getHandlerMap();\n\t\t}\n\t\treturn Collections.emptyMap();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebSessionIdResolver {\n\n\t\t@Bean\n\t\tWebSessionIdResolver webSessionIdResolver() {\n\t\t\tCookieWebSessionIdResolver resolver = new CookieWebSessionIdResolver();\n\t\t\tresolver.setCookieName(\"TEST\");\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomArgumentResolvers {\n\n\t\t@Bean\n\t\tHandlerMethodArgumentResolver firstResolver() {\n\t\t\treturn mock(HandlerMethodArgumentResolver.class);\n\t\t}\n\n\t\t@Bean\n\t\tHandlerMethodArgumentResolver secondResolver() {\n\t\t\treturn mock(HandlerMethodArgumentResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomCodecCustomizers {\n\n\t\t@Bean\n\t\tCodecCustomizer firstCodecCustomizer() {\n\t\t\treturn mock(CodecCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceHandlerRegistrationCustomizers {\n\n\t\t@Bean\n\t\tResourceHandlerRegistrationCustomizer firstResourceHandlerRegistrationCustomizer() {\n\t\t\treturn mock(ResourceHandlerRegistrationCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\tResourceHandlerRegistrationCustomizer secondResourceHandlerRegistrationCustomizer() {\n\t\t\treturn mock(ResourceHandlerRegistrationCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ViewResolvers {\n\n\t\t@Bean\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tViewResolver aViewResolver() {\n\t\t\treturn mock(ViewResolver.class);\n\t\t}\n\n\t\t@Bean\n\t\tViewResolver anotherViewResolver() {\n\t\t\treturn mock(ViewResolver.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tMockReactiveWebServerFactory mockReactiveWebServerFactory() {\n\t\t\treturn mockReactiveWebServerFactory;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHttpHandler {\n\n\t\t@Bean\n\t\tHttpHandler httpHandler() {\n\t\t\treturn (serverHttpRequest, serverHttpResponse) -> Mono.empty();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ValidatorWebFluxConfigurer implements WebFluxConfigurer {\n\n\t\tprivate final Validator validator = mock(Validator.class);\n\n\t\t@Override\n\t\tpublic Validator getValidator() {\n\t\t\treturn this.validator;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ValidatorJsr303WebFluxConfigurer implements WebFluxConfigurer {\n\n\t\tprivate final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();\n\n\t\t@Override\n\t\tpublic Validator getValidator() {\n\t\t\treturn this.validator;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJsr303Validator {\n\n\t\t@Bean\n\t\tjakarta.validation.Validator customValidator() {\n\t\t\treturn mock(jakarta.validation.Validator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSpringValidator {\n\n\t\t@Bean\n\t\tValidator customValidator() {\n\t\t\treturn mock(Validator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHiddenHttpMethodFilter {\n\n\t\t@Bean\n\t\tHiddenHttpMethodFilter customHiddenHttpMethodFilter() {\n\t\t\treturn mock(HiddenHttpMethodFilter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRequestMappingHandlerAdapter {\n\n\t\tprivate int handlerAdapters;\n\n\t\t@Bean\n\t\tWebFluxRegistrations webFluxRegistrationsHandlerAdapter() {\n\t\t\treturn new WebFluxRegistrations() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {\n\t\t\t\t\tCustomRequestMappingHandlerAdapter.this.handlerAdapters++;\n\t\t\t\t\treturn new WebFluxAutoConfigurationTests.MyRequestMappingHandlerAdapter();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class MyRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ WebFluxAutoConfigurationTests.CustomRequestMappingHandlerMapping.class,\n\t\t\tWebFluxAutoConfigurationTests.CustomRequestMappingHandlerAdapter.class })\n\tstatic class MultipleWebFluxRegistrations {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRequestMappingHandlerMapping {\n\n\t\tprivate int handlerMappings;\n\n\t\t@Bean\n\t\tWebFluxRegistrations webFluxRegistrationsHandlerMapping() {\n\t\t\treturn new WebFluxRegistrations() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic RequestMappingHandlerMapping getRequestMappingHandlerMapping() {\n\t\t\t\t\tCustomRequestMappingHandlerMapping.this.handlerMappings++;\n\t\t\t\t\treturn new MyRequestMappingHandlerMapping();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class MyRequestMappingHandlerMapping extends RequestMappingHandlerMapping {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrinterConfiguration {\n\n\t\t@Bean\n\t\tPrinter<Example> examplePrinter() {\n\t\t\treturn new ExamplePrinter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParserConfiguration {\n\n\t\t@Bean\n\t\tParser<Example> exampleParser() {\n\t\t\treturn new ExampleParser();\n\t\t}\n\n\t}\n\n\tstatic final class Example {\n\n\t\tprivate final String name;\n\n\t\tprivate Example(String name, Date date) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic class ExamplePrinter implements Printer<Example> {\n\n\t\t@Override\n\t\tpublic String print(Example example, Locale locale) {\n\t\t\treturn example.getName();\n\t\t}\n\n\t}\n\n\tstatic class ExampleParser implements Parser<Example> {\n\n\t\t@Override\n\t\tpublic Example parse(String source, Locale locale) {\n\t\t\treturn new Example(source, new Date());\n\t\t}\n\n\t}\n\n\tstatic class CustomLocaleContextResolver implements LocaleContextResolver {\n\n\t\t@Override\n\t\tpublic LocaleContext resolveLocaleContext(ServerWebExchange exchange) {\n\t\t\treturn () -> Locale.ENGLISH;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLocaleContext(ServerWebExchange exchange, @Nullable LocaleContext localeContext) {\n\t\t}\n\n\t}\n\n\t@Order(-100)\n\tstatic class HighPrecedenceConfigurer implements WebFluxConfigurer {\n\n\t}\n\n\t@Order(100)\n\tstatic class LowPrecedenceConfigurer implements WebFluxConfigurer {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomExceptionHandlerConfiguration {\n\n\t\t@Bean\n\t\tCustomExceptionHandler customExceptionHandler() {\n\t\t\treturn new CustomExceptionHandler();\n\t\t}\n\n\t}\n\n\t@ControllerAdvice\n\tstatic class CustomExceptionHandler extends ResponseEntityExceptionHandler {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ LowestOrderedControllerAdvice.class, HighestOrderedControllerAdvice.class })\n\tstatic class OrderedControllerAdviceBeansConfiguration {\n\n\t\t@ControllerAdvice\n\t\t@Order\n\t\tstatic class LowestOrderedControllerAdvice {\n\n\t\t}\n\n\t\t@ControllerAdvice\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tstatic class HighestOrderedControllerAdvice {\n\n\t\t}\n\n\t}\n\n\t@Aspect\n\tstatic class ExceptionHandlerInterceptor {\n\n\t\t@AfterReturning(pointcut = \"@annotation(org.springframework.web.bind.annotation.ExceptionHandler)\",\n\t\t\t\treturning = \"returnValue\")\n\t\tvoid exceptionHandlerIntercept(JoinPoint joinPoint, Object returnValue) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAspectJAutoProxy(proxyTargetClass = true)\n\tstatic class AopConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomApplicationTaskExecutorConfig {\n\n\t\t@Bean\n\t\tExecutor applicationTaskExecutor() {\n\t\t\treturn mock(Executor.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAsyncTaskExecutorConfig {\n\n\t\t@Bean\n\t\tAsyncTaskExecutor customTaskExecutor() {\n\t\t\treturn mock(AsyncTaskExecutor.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAsyncTaskExecutorConfigurer implements WebFluxConfigurer {\n\n\t\tprivate final AsyncTaskExecutor taskExecutor = mock(AsyncTaskExecutor.class);\n\n\t\t@Override\n\t\tpublic void configureBlockingExecution(BlockingExecutionConfigurer configurer) {\n\t\t\tconfigurer.setExecutor(this.taskExecutor);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ApiVersionConfiguration {\n\n\t\t@Bean\n\t\tApiVersionResolver apiVersionResolver() {\n\t\t\treturn (request) -> \"latest\";\n\t\t}\n\n\t\t@Bean\n\t\tApiVersionDeprecationHandler apiVersionDeprecationHandler(ApiVersionParser<?> apiVersionParser) {\n\t\t\treturn new StandardApiVersionDeprecationHandler(apiVersionParser);\n\t\t}\n\n\t\t@Bean\n\t\tApiVersionParser<String> apiVersionParser() {\n\t\t\treturn (version) -> String.valueOf(version);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.time.Duration;\nimport java.time.temporal.ChronoUnit;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention;\nimport org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebFluxObservationAutoConfiguration}\n *\n * @author Brian Clozel\n * @author Dmytro Nosan\n * @author Madhura Bhave\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass WebFluxObservationAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withBean(SimpleMeterRegistry.class)\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(ObservationAutoConfiguration.class, WebFluxObservationAutoConfiguration.class));\n\n\t@Test\n\tvoid afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestController.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\tWebFluxAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.web.server.max-uri-tags=2\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context);\n\t\t\t\tassertThat(registry.get(\"http.server.requests\").meters()).hasSizeLessThanOrEqualTo(2);\n\t\t\t\tassertThat(output).contains(\"Reached the maximum number of 'uri' tags for 'http.server.requests'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestController.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\tWebFluxAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.web.server.max-uri-tags=2\",\n\t\t\t\t\t\"management.observations.http.server.requests.name=my.http.server.requests\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context, \"my.http.server.requests\");\n\t\t\t\tassertThat(registry.get(\"my.http.server.requests\").meters()).hasSizeLessThanOrEqualTo(2);\n\t\t\t\tassertThat(output).contains(\"Reached the maximum number of 'uri' tags for 'my.http.server.requests'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestController.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\tWebFluxAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.web.server.max-uri-tags=5\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context);\n\t\t\t\tassertThat(registry.get(\"http.server.requests\").meters()).hasSize(3);\n\t\t\t\tassertThat(output)\n\t\t\t\t\t.doesNotContain(\"Reached the maximum number of 'uri' tags for 'http.server.requests'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldSupplyDefaultServerRequestObservationConvention() {\n\t\tthis.contextRunner.withPropertyValues(\"management.observations.http.server.requests.name=some-other-name\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(DefaultServerRequestObservationConvention.class);\n\t\t\t\tDefaultServerRequestObservationConvention bean = context\n\t\t\t\t\t.getBean(DefaultServerRequestObservationConvention.class);\n\t\t\t\tassertThat(bean.getName()).isEqualTo(\"some-other-name\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomServerRequestObservationConvention() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customServerRequestObservationConvention\", ServerRequestObservationConvention.class,\n\t\t\t\t\t() -> mock(ServerRequestObservationConvention.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasBean(\"customServerRequestObservationConvention\");\n\t\t\t\tassertThat(context).hasSingleBean(ServerRequestObservationConvention.class);\n\t\t\t});\n\t}\n\n\tprivate MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context) {\n\t\treturn getInitializedMeterRegistry(context, \"http.server.requests\");\n\t}\n\n\tprivate MeterRegistry getInitializedMeterRegistry(AssertableReactiveWebApplicationContext context,\n\t\t\tString metricName) {\n\t\tMeterRegistry meterRegistry = context.getBean(MeterRegistry.class);\n\t\tmeterRegistry.timer(metricName, \"uri\", \"/test0\").record(Duration.of(500, ChronoUnit.SECONDS));\n\t\tmeterRegistry.timer(metricName, \"uri\", \"/test1\").record(Duration.of(500, ChronoUnit.SECONDS));\n\t\tmeterRegistry.timer(metricName, \"uri\", \"/test2\").record(Duration.of(500, ChronoUnit.SECONDS));\n\t\treturn meterRegistry;\n\t}\n\n\t@RestController\n\tstatic class TestController {\n\n\t\t@GetMapping(\"test0\")\n\t\tString test0() {\n\t\t\treturn \"test0\";\n\t\t}\n\n\t\t@GetMapping(\"test1\")\n\t\tString test1() {\n\t\t\treturn \"test1\";\n\t\t}\n\n\t\t@GetMapping(\"test2\")\n\t\tString test2() {\n\t\t\treturn \"test2\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WebFluxPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxProperties}\n *\n * @author Brian Clozel\n */\nclass WebFluxPropertiesTests {\n\n\tprivate final WebFluxProperties properties = new WebFluxProperties();\n\n\t@Test\n\tvoid shouldPrefixBasePathWithMissingSlash() {\n\t\tbind(\"spring.webflux.base-path\", \"something\");\n\t\tassertThat(this.properties.getBasePath()).isEqualTo(\"/something\");\n\t}\n\n\t@Test\n\tvoid shouldRemoveTrailingSlashFromBasePath() {\n\t\tbind(\"spring.webflux.base-path\", \"/something/\");\n\t\tassertThat(this.properties.getBasePath()).isEqualTo(\"/something\");\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"spring.webflux\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/WelcomePageRouterFunctionFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.core.io.buffer.DataBuffer;\nimport org.springframework.core.io.buffer.DataBufferFactory;\nimport org.springframework.core.io.buffer.DefaultDataBufferFactory;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.function.server.HandlerStrategies;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport org.springframework.web.reactive.result.view.View;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.ServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WelcomePageRouterFunctionFactory}\n *\n * @author Brian Clozel\n */\n@WithResource(name = \"welcome-page/index.html\", content = \"welcome-page-static\")\nclass WelcomePageRouterFunctionFactoryTests {\n\n\tprivate StaticApplicationContext applicationContext;\n\n\tprivate final String[] noIndexLocations = { \"classpath:/\" };\n\n\tprivate final String[] indexLocations = { \"classpath:/public/\", \"classpath:/welcome-page/\" };\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.applicationContext = new StaticApplicationContext();\n\t\tthis.applicationContext.refresh();\n\t}\n\n\t@Test\n\tvoid handlesRequestForStaticPageThatAcceptsTextHtml() {\n\t\tWebTestClient client = withStaticIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-static\");\n\t}\n\n\t@Test\n\tvoid handlesRequestForStaticPageThatAcceptsAll() {\n\t\tWebTestClient client = withStaticIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.ALL)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-static\");\n\t}\n\n\t@Test\n\tvoid doesNotHandleRequestThatDoesNotAcceptTextHtml() {\n\t\tWebTestClient client = withStaticIndex();\n\t\tclient.get().uri(\"/\").accept(MediaType.APPLICATION_JSON).exchange().expectStatus().isNotFound();\n\t}\n\n\t@Test\n\tvoid handlesRequestWithNoAcceptHeader() {\n\t\tWebTestClient client = withStaticIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-static\");\n\t}\n\n\t@Test\n\tvoid handlesRequestWithEmptyAcceptHeader() {\n\t\tWebTestClient client = withStaticIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.header(HttpHeaders.ACCEPT, \"\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-static\");\n\t}\n\n\t@Test\n\tvoid producesNotFoundResponseWhenThereIsNoWelcomePage() {\n\t\tWelcomePageRouterFunctionFactory factory = factoryWithoutTemplateSupport(this.noIndexLocations, \"/**\");\n\t\tassertThat(factory.createRouterFunction()).isNull();\n\t}\n\n\t@Test\n\tvoid handlesRequestForTemplateThatAcceptsTextHtml() {\n\t\tWebTestClient client = withTemplateIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-template\");\n\t}\n\n\t@Test\n\tvoid handlesRequestForTemplateThatAcceptsAll() {\n\t\tWebTestClient client = withTemplateIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.ALL)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-template\");\n\t}\n\n\t@Test\n\tvoid prefersAStaticResourceToATemplate() {\n\t\tWebTestClient client = withStaticAndTemplateIndex();\n\t\tclient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.ALL)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"welcome-page-static\");\n\t}\n\n\tprivate WebTestClient withStaticIndex() {\n\t\tWelcomePageRouterFunctionFactory factory = factoryWithoutTemplateSupport(this.indexLocations, \"/**\");\n\t\tRouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();\n\t\tassertThat(routerFunction).isNotNull();\n\t\treturn WebTestClient.bindToRouterFunction(routerFunction).build();\n\t}\n\n\tprivate WebTestClient withTemplateIndex() {\n\t\tWelcomePageRouterFunctionFactory factory = factoryWithTemplateSupport(this.noIndexLocations);\n\t\tTestViewResolver testViewResolver = new TestViewResolver();\n\t\tRouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();\n\t\tassertThat(routerFunction).isNotNull();\n\t\treturn WebTestClient.bindToRouterFunction(routerFunction)\n\t\t\t.handlerStrategies(HandlerStrategies.builder().viewResolver(testViewResolver).build())\n\t\t\t.build();\n\t}\n\n\tprivate WebTestClient withStaticAndTemplateIndex() {\n\t\tWelcomePageRouterFunctionFactory factory = factoryWithTemplateSupport(this.indexLocations);\n\t\tTestViewResolver testViewResolver = new TestViewResolver();\n\t\tRouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();\n\t\tassertThat(routerFunction).isNotNull();\n\t\treturn WebTestClient.bindToRouterFunction(routerFunction)\n\t\t\t.handlerStrategies(HandlerStrategies.builder().viewResolver(testViewResolver).build())\n\t\t\t.build();\n\t}\n\n\tprivate WelcomePageRouterFunctionFactory factoryWithoutTemplateSupport(String[] locations,\n\t\t\tString staticPathPattern) {\n\t\treturn new WelcomePageRouterFunctionFactory(new TestTemplateAvailabilityProviders(), this.applicationContext,\n\t\t\t\tlocations, staticPathPattern);\n\t}\n\n\tprivate WelcomePageRouterFunctionFactory factoryWithTemplateSupport(String[] locations) {\n\t\treturn new WelcomePageRouterFunctionFactory(new TestTemplateAvailabilityProviders(\"index\"),\n\t\t\t\tthis.applicationContext, locations, \"/**\");\n\t}\n\n\tstatic class TestTemplateAvailabilityProviders extends TemplateAvailabilityProviders {\n\n\t\tTestTemplateAvailabilityProviders() {\n\t\t\tsuper(Collections.emptyList());\n\t\t}\n\n\t\tTestTemplateAvailabilityProviders(String viewName) {\n\t\t\tthis((view, environment, classLoader, resourceLoader) -> view.equals(viewName));\n\t\t}\n\n\t\tTestTemplateAvailabilityProviders(TemplateAvailabilityProvider provider) {\n\t\t\tsuper(Collections.singletonList(provider));\n\t\t}\n\n\t}\n\n\tstatic class TestViewResolver implements ViewResolver {\n\n\t\t@Override\n\t\tpublic Mono<View> resolveViewName(String viewName, Locale locale) {\n\t\t\treturn Mono.just(new TestView());\n\t\t}\n\n\t}\n\n\tstatic class TestView implements View {\n\n\t\tprivate final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();\n\n\t\t@Override\n\t\tpublic Mono<Void> render(@Nullable Map<String, ?> model, @Nullable MediaType contentType,\n\t\t\t\tServerWebExchange exchange) {\n\t\t\tDataBuffer buffer = this.bufferFactory.wrap(\"welcome-page-template\".getBytes(StandardCharsets.UTF_8));\n\t\t\treturn exchange.getResponse().writeWith(Mono.just(buffer));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/endpoint/web/WebFluxHealthEndpointAdditionalPathIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.endpoint.web;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.integrationtest.AbstractHealthEndpointAdditionalPathIntegrationTests;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.application.DiskSpaceHealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.reactor.netty.autoconfigure.actuate.web.server.NettyReactiveManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\n\n/**\n * Integration tests for Webflux health groups on an additional path.\n *\n * @author Madhura Bhave\n */\nclass WebFluxHealthEndpointAdditionalPathIntegrationTests extends\n\t\tAbstractHealthEndpointAdditionalPathIntegrationTests<ReactiveWebApplicationContextRunner, ConfigurableReactiveWebApplicationContext, AssertableReactiveWebApplicationContext> {\n\n\tWebFluxHealthEndpointAdditionalPathIntegrationTests() {\n\t\tsuper(new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, CodecsAutoConfiguration.class,\n\t\t\t\t\tWebFluxAutoConfiguration.class, HealthContributorAutoConfiguration.class,\n\t\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HttpHandlerAutoConfiguration.class,\n\t\t\t\t\tEndpointAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\t\tWebFluxHealthEndpointExtensionAutoConfiguration.class,\n\t\t\t\t\tDiskSpaceHealthContributorAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\tManagementContextAutoConfiguration.class, NettyReactiveWebServerAutoConfiguration.class,\n\t\t\t\t\tNettyReactiveManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class))\n\t\t\t.withInitializer(new ServerPortInfoApplicationContextInitializer())\n\t\t\t.withPropertyValues(\"server.port=0\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/endpoint/web/WebFluxHealthEndpointExtensionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.ReactiveHealthEndpointWebExtension;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.health.contributor.ReactiveHealthIndicator;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.actuate.endpoint.web.AdditionalHealthEndpointPathsWebFluxHandlerMapping;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxHealthEndpointExtensionAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass WebFluxHealthEndpointExtensionAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withUserConfiguration(HealthIndicatorsConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tWebFluxHealthEndpointExtensionAutoConfiguration.class));\n\n\t@Test\n\t@WithTestEndpointOutcomeExposureContributor\n\tvoid additionalReactiveHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.exclude=*\",\n\t\t\t\t\t\"management.endpoints.test.exposure.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).hasSingleBean(HealthEndpoint.class);\n\t\t\t\tassertThat(context).hasSingleBean(ReactiveHealthEndpointWebExtension.class);\n\t\t\t\tassertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();\n\t\t\t\tassertThat(context).hasSingleBean(AdditionalHealthEndpointPathsWebFluxHandlerMapping.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithTestEndpointOutcomeExposureContributor\n\tvoid backsOffWithoutWebEndpointInfrastructure() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.exclude=*\",\n\t\t\t\t\t\"management.endpoints.test.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(AdditionalHealthEndpointPathsWebFluxHandlerMapping.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthIndicatorsConfiguration {\n\n\t\t@Bean\n\t\tReactiveHealthIndicator simpleHealthIndicator() {\n\t\t\treturn () -> Mono.just(Health.up().build());\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator additionalHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/ControllerEndpointWebFluxIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.reactive.AnnotationConfigReactiveWebApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.GetMapping;\n\n/**\n * Integration tests for the Actuator's WebFlux {@link ControllerEndpoint controller\n * endpoints}.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"removal\")\nclass ControllerEndpointWebFluxIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigReactiveWebApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid endpointsCanBeAccessed() {\n\t\tthis.context = new AnnotationConfigReactiveWebApplicationContext();\n\t\tthis.context.register(DefaultConfiguration.class, ExampleController.class);\n\t\tTestPropertyValues.of(\"management.endpoints.web.exposure.include=*\").applyTo(this.context);\n\t\tthis.context.refresh();\n\t\tWebTestClient webClient = WebTestClient.bindToApplicationContext(this.context).build();\n\t\twebClient.get().uri(\"/actuator/example\").exchange().expectStatus().isOk();\n\t}\n\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\tWebEndpointAutoConfiguration.class, AuditAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class, WebFluxAutoConfiguration.class,\n\t\t\tManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class })\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@RestControllerEndpoint(id = \"example\")\n\tstatic class ExampleController {\n\n\t\t@GetMapping(\"/\")\n\t\tString example() {\n\t\t\treturn \"Example\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxEndpointAccessIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.reactive.server.EntityExchangeResult;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.reactive.function.client.ExchangeStrategies;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for controlling access to endpoints exposed by Spring WebFlux.\n *\n * @author Andy Wilkinson\n */\nclass WebFluxEndpointAccessIntegrationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(\n\t\t\tAnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(NettyReactiveWebServerAutoConfiguration.class,\n\t\t\t\tHttpHandlerAutoConfiguration.class, JacksonAutoConfiguration.class, CodecsAutoConfiguration.class,\n\t\t\t\tWebFluxAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tManagementContextAutoConfiguration.class))\n\t\t.withConfiguration(AutoConfigurations.of(BeansEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(CustomWebFluxEndpoint.class)\n\t\t.withPropertyValues(\"server.port:0\");\n\n\t@Test\n\tvoid accessIsUnrestrictedByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\").run((context) -> {\n\t\t\tWebTestClient client = createClient(context);\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customwebflux\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customwebflux\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeReadOnlyByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customwebflux\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customwebflux\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeNoneByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customwebflux\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customwebflux\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessForOneEndpointCanOverrideTheDefaultAccess() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\", \"management.endpoint.customwebflux.access=UNRESTRICTED\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customwebflux\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customwebflux\")).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtReadOnly() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\",\n\t\t\t\t\t\"management.endpoints.access.max-permitted=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customwebflux\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customwebflux\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtNone() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\", \"management.endpoints.access.max-permitted=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customwebflux\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customwebflux\")).isFalse();\n\t\t\t});\n\t}\n\n\tprivate WebTestClient createClient(AssertableReactiveWebApplicationContext context) {\n\t\tWebServer webServer = context.getSourceApplicationContext(ReactiveWebServerApplicationContext.class)\n\t\t\t.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tint port = webServer.getPort();\n\t\tExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()\n\t\t\t.codecs((configurer) -> configurer.defaultCodecs().maxInMemorySize(-1))\n\t\t\t.build();\n\t\treturn WebTestClient.bindToServer()\n\t\t\t.baseUrl(\"http://localhost:\" + port)\n\t\t\t.exchangeStrategies(exchangeStrategies)\n\t\t\t.responseTimeout(Duration.ofMinutes(5))\n\t\t\t.build();\n\t}\n\n\tprivate boolean isAccessible(WebTestClient client, HttpMethod method, String path) {\n\t\tpath = \"/actuator/\" + path;\n\t\tEntityExchangeResult<byte[]> result = client.method(method).uri(path).exchange().expectBody().returnResult();\n\t\tif (result.getStatus() == HttpStatus.OK) {\n\t\t\treturn true;\n\t\t}\n\t\tif (result.getStatus() == HttpStatus.NOT_FOUND || result.getStatus() == HttpStatus.METHOD_NOT_ALLOWED) {\n\t\t\treturn false;\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\tString.format(\"Unexpected %s HTTP status for endpoint %s\", result.getStatus(), path));\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"customwebflux\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class CustomWebFluxEndpoint {\n\n\t\t@GetMapping(\"/\")\n\t\tString get() {\n\t\t\treturn \"get\";\n\t\t}\n\n\t\t@PostMapping(\"/\")\n\t\tString post() {\n\t\t\treturn \"post\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxEndpointCorsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for the WebFlux actuator endpoints' CORS support\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @see WebFluxEndpointManagementContextConfiguration\n */\nclass WebFluxEndpointCorsIntegrationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, CodecsAutoConfiguration.class,\n\t\t\t\tWebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\tBeansEndpointAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.endpoints.web.exposure.include:*\");\n\n\t@Test\n\tvoid corsIsDisabledByDefault() {\n\t\tthis.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient.options()\n\t\t\t.uri(\"/actuator/beans\")\n\t\t\t.header(\"Origin\", \"spring.example.org\")\n\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t.exchange()\n\t\t\t.expectHeader()\n\t\t\t.doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)));\n\t}\n\n\t@Test\n\tvoid settingAllowedOriginsEnablesCors() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\")\n\t\t\t.run(withWebTestClient((webTestClient) -> {\n\t\t\t\twebTestClient.options()\n\t\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t\t.header(\"Origin\", \"test.example.org\")\n\t\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isForbidden();\n\t\t\t\tperformAcceptedCorsRequest(webTestClient, \"/actuator/beans\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid settingAllowedOriginPatternsEnablesCors() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origin-patterns:*.example.org\",\n\t\t\t\t\t\"management.endpoints.web.cors.allow-credentials:true\")\n\t\t\t.run(withWebTestClient((webTestClient) -> {\n\t\t\t\twebTestClient.options()\n\t\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t\t.header(\"Origin\", \"spring.example.com\")\n\t\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isForbidden();\n\t\t\t\tperformAcceptedCorsRequest(webTestClient, \"/actuator/beans\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid maxAgeDefaultsTo30Minutes() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\")\n\t\t\t.run(withWebTestClient(\n\t\t\t\t\t(webTestClient) -> performAcceptedCorsRequest(webTestClient, \"/actuator/beans\").expectHeader()\n\t\t\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_MAX_AGE, \"1800\")));\n\t}\n\n\t@Test\n\tvoid maxAgeCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\",\n\t\t\t\t\t\"management.endpoints.web.cors.max-age: 2400\")\n\t\t\t.run(withWebTestClient(\n\t\t\t\t\t(webTestClient) -> performAcceptedCorsRequest(webTestClient, \"/actuator/beans\").expectHeader()\n\t\t\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_MAX_AGE, \"2400\")));\n\t}\n\n\t@Test\n\tvoid requestsWithDisallowedHeadersAreRejected() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(\"Origin\", \"spring.example.org\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, \"Alpha\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isForbidden()));\n\t}\n\n\t@Test\n\tvoid allowedHeadersCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\",\n\t\t\t\t\t\"management.endpoints.web.cors.allowed-headers:Alpha,Bravo\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(\"Origin\", \"spring.example.org\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, \"Alpha\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, \"Alpha\")));\n\t}\n\n\t@Test\n\tvoid requestsWithDisallowedMethodsAreRejected() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(\"Origin\", \"spring.example.org\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"PATCH\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isForbidden()));\n\t}\n\n\t@Test\n\tvoid allowedMethodsCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\",\n\t\t\t\t\t\"management.endpoints.web.cors.allowed-methods:GET,HEAD\")\n\t\t\t.run(withWebTestClient((webTestClient) -> webTestClient.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(\"Origin\", \"spring.example.org\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"HEAD\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectHeader()\n\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, \"GET,HEAD\")));\n\t}\n\n\t@Test\n\tvoid credentialsCanBeAllowed() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\",\n\t\t\t\t\t\"management.endpoints.web.cors.allow-credentials:true\")\n\t\t\t.run(withWebTestClient(\n\t\t\t\t\t(webTestClient) -> performAcceptedCorsRequest(webTestClient, \"/actuator/beans\").expectHeader()\n\t\t\t\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, \"true\")));\n\t}\n\n\t@Test\n\tvoid credentialsCanBeDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:spring.example.org\",\n\t\t\t\t\t\"management.endpoints.web.cors.allow-credentials:false\")\n\t\t\t.run(withWebTestClient(\n\t\t\t\t\t(webTestClient) -> performAcceptedCorsRequest(webTestClient, \"/actuator/beans\").expectHeader()\n\t\t\t\t\t\t.doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)));\n\t}\n\n\tprivate ContextConsumer<ReactiveWebApplicationContext> withWebTestClient(Consumer<WebTestClient> webTestClient) {\n\t\treturn (context) -> webTestClient.accept(WebTestClient.bindToApplicationContext(context)\n\t\t\t.configureClient()\n\t\t\t.baseUrl(\"https://spring.example.org\")\n\t\t\t.build());\n\t}\n\n\tprivate WebTestClient.ResponseSpec performAcceptedCorsRequest(WebTestClient webTestClient, String url) {\n\t\treturn webTestClient.options()\n\t\t\t.uri(url)\n\t\t\t.header(HttpHeaders.ORIGIN, \"spring.example.org\")\n\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t.exchange()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, \"spring.example.org\")\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.jsontype.TypeSerializer;\nimport tools.jackson.databind.module.SimpleModule;\nimport tools.jackson.databind.ser.std.StdScalarSerializer;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the WebFlux actuator endpoints.\n *\n * @author Andy Wilkinson\n */\nclass WebFluxEndpointIntegrationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, CodecsAutoConfiguration.class,\n\t\t\t\tWebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\tBeansEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(EndpointsConfiguration.class);\n\n\t@Test\n\tvoid linksAreProvidedToAllEndpointTypes() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include:*\").run((context) -> {\n\t\t\tWebTestClient client = createWebTestClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/actuator\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isOk()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"_links.beans\")\n\t\t\t\t.isNotEmpty()\n\t\t\t\t.jsonPath(\"_links.restcontroller\")\n\t\t\t\t.isNotEmpty()\n\t\t\t\t.jsonPath(\"_links.controller\")\n\t\t\t\t.isNotEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid linksPageIsNotAvailableWhenDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.discovery.enabled=false\").run((context) -> {\n\t\t\tWebTestClient client = createWebTestClient(context);\n\t\t\tclient.get().uri(\"/actuator\").exchange().expectStatus().isNotFound();\n\t\t});\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperCanBeApplied() {\n\t\tthis.contextRunner.withUserConfiguration(EndpointJsonMapperConfiguration.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include:*\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = createWebTestClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isOk()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.consumeWith((result) -> {\n\t\t\t\t\t\tString json = new String(result.getResponseBody(), StandardCharsets.UTF_8);\n\t\t\t\t\t\tassertThat(json).contains(\"\\\"scope\\\":\\\"notelgnis\\\"\");\n\t\t\t\t\t});\n\t\t\t});\n\t}\n\n\tprivate WebTestClient createWebTestClient(ApplicationContext context) {\n\t\treturn WebTestClient.bindToApplicationContext(context)\n\t\t\t.configureClient()\n\t\t\t.baseUrl(\"https://spring.example.org\")\n\t\t\t.build();\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint(id = \"controller\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestControllerEndpoint {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"restcontroller\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestRestControllerEndpoint {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointsConfiguration {\n\n\t\t@Bean\n\t\tTestControllerEndpoint testControllerEndpoint() {\n\t\t\treturn new TestControllerEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestRestControllerEndpoint testRestControllerEndpoint() {\n\t\t\treturn new TestRestControllerEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class EndpointJsonMapperConfiguration {\n\n\t\t@Bean\n\t\tEndpointJsonMapper endpointJsonMapper() {\n\t\t\tSimpleModule module = new SimpleModule();\n\t\t\tmodule.addSerializer(String.class, new ReverseStringSerializer());\n\t\t\tJsonMapper jsonMapper = JsonMapper.builder().addModule(module).build();\n\t\t\treturn () -> jsonMapper;\n\t\t}\n\n\t\tstatic class ReverseStringSerializer extends StdScalarSerializer<Object> {\n\n\t\t\tReverseStringSerializer() {\n\t\t\t\tsuper(String.class, false);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isEmpty(SerializationContext context, Object value) {\n\t\t\t\treturn ((String) value).isEmpty();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void serialize(Object value, JsonGenerator gen, SerializationContext context) {\n\t\t\t\tserialize(value, gen);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic final void serializeWithType(Object value, JsonGenerator gen, SerializationContext context,\n\t\t\t\t\tTypeSerializer typeSer) {\n\t\t\t\tserialize(value, gen);\n\t\t\t}\n\n\t\t\tprivate void serialize(Object value, JsonGenerator gen) {\n\t\t\t\tStringBuilder builder = new StringBuilder((String) value);\n\t\t\t\tgen.writeString(builder.reverse().toString());\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxManagementChildContextConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.apache.catalina.Valve;\nimport org.apache.catalina.startup.Tomcat;\nimport org.apache.catalina.valves.AccessLogValve;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.env.ConfigTreePropertySource;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatReactiveManagementContextAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.reactive.TomcatReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.context.WebServerInitializedEvent;\nimport org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link WebFluxManagementChildContextConfiguration}.\n *\n * @author Andy Wilkinson\n */\n@DirtiesUrlFactories\nclass WebFluxManagementChildContextConfigurationIntegrationTests {\n\n\tprivate final List<WebServer> webServers = new ArrayList<>();\n\n\tprivate final ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(\n\t\t\tAnnotationConfigReactiveWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,\n\t\t\t\tTomcatReactiveWebServerAutoConfiguration.class, TomcatReactiveManagementContextAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, EndpointAutoConfiguration.class, HttpHandlerAutoConfiguration.class,\n\t\t\t\tWebFluxAutoConfiguration.class))\n\t\t.withUserConfiguration(SucceedingEndpoint.class)\n\t\t.withInitializer(new ServerPortInfoApplicationContextInitializer())\n\t\t.withInitializer((context) -> context.addApplicationListener(\n\t\t\t\t(ApplicationListener<WebServerInitializedEvent>) (event) -> this.webServers.add(event.getWebServer())))\n\t\t.withPropertyValues(\"server.port=0\", \"management.server.port=0\", \"management.endpoints.web.exposure.include=*\");\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath temp;\n\n\t@Test\n\tvoid endpointsAreBeneathActuatorByDefault() {\n\t\tthis.runner.withPropertyValues(\"management.server.port:0\").run(withWebTestClient((client) -> {\n\t\t\tString body = client.get()\n\t\t\t\t.uri(\"actuator/success\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchangeToMono((response) -> response.bodyToMono(String.class))\n\t\t\t\t.block();\n\t\t\tassertThat(body).isEqualTo(\"Success\");\n\t\t}));\n\t}\n\n\t@Test\n\tvoid whenManagementServerBasePathIsConfiguredThenEndpointsAreBeneathThatPath() {\n\t\tthis.runner.withPropertyValues(\"management.server.port:0\", \"management.server.base-path:/manage\")\n\t\t\t.run(withWebTestClient((client) -> {\n\t\t\t\tString body = client.get()\n\t\t\t\t\t.uri(\"manage/actuator/success\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchangeToMono((response) -> response.bodyToMono(String.class))\n\t\t\t\t\t.block();\n\t\t\t\tassertThat(body).isEqualTo(\"Success\");\n\t\t\t}));\n\t}\n\n\t@Test // gh-32941\n\tvoid whenManagementServerPortLoadedFromConfigTree() {\n\t\tthis.runner.withInitializer(this::addConfigTreePropertySource)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid accessLogHasManagementServerSpecificPrefix() {\n\t\tthis.runner.withPropertyValues(\"server.tomcat.accesslog.enabled=true\").run((context) -> {\n\t\t\tAccessLogValve accessLogValve = findAccessLogValve();\n\t\t\tassertThat(accessLogValve).isNotNull();\n\t\t\tassertThat(accessLogValve.getPrefix()).isEqualTo(\"management_access_log\");\n\t\t});\n\t}\n\n\t@Test\n\t@ClassPathExclusions(packages = \"org.springframework.boot.health.actuate.endpoint\")\n\tvoid refreshSucceedsWithoutHealth() {\n\t\tthis.runner.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\tprivate @Nullable AccessLogValve findAccessLogValve() {\n\t\tassertThat(this.webServers).hasSize(2);\n\t\tTomcat tomcat = ((TomcatWebServer) this.webServers.get(1)).getTomcat();\n\t\tfor (Valve valve : tomcat.getEngine().getPipeline().getValves()) {\n\t\t\tif (valve instanceof AccessLogValve accessLogValve) {\n\t\t\t\treturn accessLogValve;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void addConfigTreePropertySource(ConfigurableApplicationContext applicationContext) {\n\t\ttry {\n\t\t\tapplicationContext.getEnvironment()\n\t\t\t\t.setConversionService((ConfigurableConversionService) ApplicationConversionService.getSharedInstance());\n\t\t\tPath configtree = this.temp.resolve(\"configtree\");\n\t\t\tPath file = configtree.resolve(\"management/server/port\");\n\t\t\tfile.toFile().getParentFile().mkdirs();\n\t\t\tFileCopyUtils.copy(\"0\".getBytes(StandardCharsets.UTF_8), file.toFile());\n\t\t\tConfigTreePropertySource source = new ConfigTreePropertySource(\"configtree\", configtree);\n\t\t\tapplicationContext.getEnvironment().getPropertySources().addFirst(source);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate ContextConsumer<AssertableReactiveWebApplicationContext> withWebTestClient(Consumer<WebClient> webClient) {\n\t\treturn (context) -> {\n\t\t\tString port = context.getEnvironment().getProperty(\"local.management.port\");\n\t\t\tWebClient client = WebClient.create(\"http://localhost:\" + port);\n\t\t\twebClient.accept(client);\n\t\t};\n\t}\n\n\t@Endpoint(id = \"success\")\n\tstatic class SucceedingEndpoint {\n\n\t\t@ReadOperation\n\t\tString fail() {\n\t\t\treturn \"Success\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/WebFluxManagementChildContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxManagementChildContextConfiguration}.\n *\n * @author Moritz Halbritter\n */\nclass WebFluxManagementChildContextConfigurationTests {\n\n\t@Test\n\t// gh-45857\n\tvoid failsWithoutManagementServerPropertiesBeanFromParent() {\n\t\tnew ReactiveWebApplicationContextRunner()\n\t\t\t.run((parent) -> new ReactiveWebApplicationContextRunner().withParent(parent)\n\t\t\t\t.withUserConfiguration(WebFluxManagementChildContextConfiguration.class)\n\t\t\t\t.run((context) -> assertThat(context).hasFailed()));\n\t}\n\n\t@Test\n\t// gh-45857\n\tvoid succeedsWithManagementServerPropertiesBeanFromParent() {\n\t\tnew ReactiveWebApplicationContextRunner().withBean(ManagementServerProperties.class)\n\t\t\t.run((parent) -> new ReactiveWebApplicationContextRunner().withParent(parent)\n\t\t\t\t.withUserConfiguration(WebFluxManagementChildContextConfiguration.class)\n\t\t\t\t.run((context) -> assertThat(context).hasNotFailed()));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/exchanges/WebFluxHttpExchangesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web.exchanges;\n\nimport java.util.EnumSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.actuate.web.exchanges.Include;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.actuate.web.exchanges.HttpExchangesWebFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxHttpExchangesAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\nclass WebFluxHttpExchangesAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebFluxHttpExchangesAutoConfiguration.class));\n\n\t@Test\n\tvoid whenRecordingIsDisabledThenFilterIsNotCreated() {\n\t\tthis.contextRunner.withBean(InMemoryHttpExchangeRepository.class)\n\t\t\t.withPropertyValues(\"management.httpexchanges.recording.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesWebFilter.class));\n\t}\n\n\t@Test\n\tvoid whenNoRepositoryIsDefinedThenFilterIsNotCreated() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesWebFilter.class));\n\t}\n\n\t@Test\n\tvoid filterIsCreated() {\n\t\tthis.contextRunner.withBean(InMemoryHttpExchangeRepository.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HttpExchangesWebFilter.class));\n\t}\n\n\t@Test\n\tvoid usesUserProvidedWebFilter() {\n\t\tInMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();\n\t\tthis.contextRunner.withBean(InMemoryHttpExchangeRepository.class, () -> repository)\n\t\t\t.withBean(CustomHttpExchangesWebFilter.class,\n\t\t\t\t\t() -> new CustomHttpExchangesWebFilter(repository, EnumSet.allOf(Include.class)))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(HttpExchangesWebFilter.class);\n\t\t\t\tassertThat(context.getBean(HttpExchangesWebFilter.class))\n\t\t\t\t\t.isInstanceOf(CustomHttpExchangesWebFilter.class);\n\t\t\t});\n\t}\n\n\tprivate static final class CustomHttpExchangesWebFilter extends HttpExchangesWebFilter {\n\n\t\tprivate CustomHttpExchangesWebFilter(HttpExchangeRepository repository, Set<Include> includes) {\n\t\t\tsuper(repository, includes);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/actuate/web/mappings/WebFluxMappingsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.actuate.web.mappings;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.webflux.actuate.web.mappings.DispatcherHandlersMappingDescriptionProvider;\nimport org.springframework.web.reactive.DispatcherHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxMappingsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass WebFluxMappingsAutoConfigurationTests {\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebFluxMappingsAutoConfiguration.class));\n\n\t@Test\n\tvoid whenEndpointIsUnavailableThenDescriptionProviderIsNotCreated() {\n\t\tthis.contextRunner.withBean(DispatcherHandler.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DispatcherHandlersMappingDescriptionProvider.class));\n\t}\n\n\t@Test\n\tvoid whenEndpointIsAvailableButThereIsNoDispatcherHandlerThenDescriptionProviderIsNotCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=mappings\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DispatcherHandlersMappingDescriptionProvider.class));\n\t}\n\n\t@Test\n\tvoid whenEndpointIsAvailableThenDescriptionProviderIsCreated() {\n\t\tthis.contextRunner.withBean(DispatcherHandler.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=mappings\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DispatcherHandlersMappingDescriptionProvider.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/error/DefaultErrorWebExceptionHandlerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport jakarta.validation.Valid;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport reactor.core.publisher.Mono;\nimport reactor.core.scheduler.Schedulers;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.reactor.netty.autoconfigure.NettyReactiveWebServerAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.boot.webflux.error.DefaultErrorAttributes;\nimport org.springframework.boot.webflux.error.ErrorAttributes;\nimport org.springframework.boot.webflux.error.ErrorWebExceptionHandler;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.test.web.reactive.server.HttpHandlerConnector.FailureAfterResponseCompletedException;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.ResponseStatusException;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebFilter;\nimport org.springframework.web.server.WebFilterChain;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Integration tests for {@link DefaultErrorWebExceptionHandler}\n *\n * @author Brian Clozel\n * @author Scott Frederick\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass DefaultErrorWebExceptionHandlerIntegrationTests {\n\n\tprivate static final MediaType TEXT_HTML_UTF8 = new MediaType(\"text\", \"html\", StandardCharsets.UTF_8);\n\n\tprivate final LogIdFilter logIdFilter = new LogIdFilter();\n\n\tprivate final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(NettyReactiveWebServerAutoConfiguration.class,\n\t\t\t\tHttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class, ErrorWebFluxAutoConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class))\n\t\t.withPropertyValues(\"spring.main.web-application-type=reactive\", \"server.port=0\")\n\t\t.withUserConfiguration(Application.class);\n\n\t@BeforeEach\n\t@AfterEach\n\tvoid clearReactorSchedulers() {\n\t\tSchedulers.shutdownNow();\n\t}\n\n\t@Test\n\tvoid jsonError(CapturedOutput output) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t.jsonPath(\"path\")\n\t\t\t\t.isEqualTo((\"/\"))\n\t\t\t\t.jsonPath(\"message\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"trace\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\tassertThat(output).contains(\"500 Server Error for HTTP GET \\\"/\\\"\")\n\t\t\t\t.contains(\"java.lang.IllegalStateException: Expected!\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid notFound() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/notFound\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"404\")\n\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t.isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase())\n\t\t\t\t.jsonPath(\"path\")\n\t\t\t\t.isEqualTo((\"/notFound\"))\n\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t});\n\t}\n\n\t@Test\n\tvoid bindingResultError() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.post()\n\t\t\t\t.uri(\"/bind\")\n\t\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t\t.bodyValue(\"{}\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"400\")\n\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())\n\t\t\t\t.jsonPath(\"path\")\n\t\t\t\t.isEqualTo((\"/bind\"))\n\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"errors\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"message\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t});\n\t}\n\n\t@Test\n\tvoid bindingResultErrorIncludeMessageAndErrors() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-message=on-param\",\n\t\t\t\t\t\"spring.web.error.include-binding-errors=on-param\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.post()\n\t\t\t\t\t.uri(\"/bind?message=true&errors=true\")\n\t\t\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.bodyValue(\"{}\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isBadRequest()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"400\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"path\")\n\t\t\t\t\t.isEqualTo((\"/bind\"))\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.doesNotExist()\n\t\t\t\t\t.jsonPath(\"errors\")\n\t\t\t\t\t.isArray()\n\t\t\t\t\t.jsonPath(\"message\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid includeStackTraceOnParam() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-exception=true\",\n\t\t\t\t\t\"spring.web.error.include-stacktrace=on-param\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/?trace=true\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.isEqualTo(IllegalStateException.class.getName())\n\t\t\t\t\t.jsonPath(\"trace\")\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid alwaysIncludeStackTrace() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-exception=true\", \"spring.web.error.include-stacktrace=always\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/?trace=false\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.isEqualTo(IllegalStateException.class.getName())\n\t\t\t\t\t.jsonPath(\"trace\")\n\t\t\t\t\t.exists()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid neverIncludeStackTrace() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-exception=true\", \"spring.web.error.include-stacktrace=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/?trace=true\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.isEqualTo(IllegalStateException.class.getName())\n\t\t\t\t\t.jsonPath(\"trace\")\n\t\t\t\t\t.doesNotExist()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid includeMessageOnParam() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-exception=true\", \"spring.web.error.include-message=on-param\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/?message=true\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.isEqualTo(IllegalStateException.class.getName())\n\t\t\t\t\t.jsonPath(\"message\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid alwaysIncludeMessage() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-exception=true\", \"spring.web.error.include-message=always\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/?trace=false\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.isEqualTo(IllegalStateException.class.getName())\n\t\t\t\t\t.jsonPath(\"message\")\n\t\t\t\t\t.isNotEmpty()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid neverIncludeMessage() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.include-exception=true\", \"spring.web.error.include-message=never\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/?trace=true\")\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t\t.isEqualTo(\"500\")\n\t\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase())\n\t\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t\t.isEqualTo(IllegalStateException.class.getName())\n\t\t\t\t\t.jsonPath(\"message\")\n\t\t\t\t\t.doesNotExist()\n\t\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid statusException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.error.include-exception=true\").run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/badRequest\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"400\")\n\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())\n\t\t\t\t.jsonPath(\"exception\")\n\t\t\t\t.isEqualTo(ResponseStatusException.class.getName())\n\t\t\t\t.jsonPath(\"requestId\")\n\t\t\t\t.isEqualTo(this.logIdFilter.getLogId());\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultErrorView() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mustache.prefix=classpath:/unknown/\",\n\t\t\t\t\t\"spring.web.error.include-stacktrace=always\", \"spring.web.error.include-message=always\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tString body = client.get()\n\t\t\t\t\t.uri(\"/\")\n\t\t\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.contentType(TEXT_HTML_UTF8)\n\t\t\t\t\t.expectBody(String.class)\n\t\t\t\t\t.returnResult()\n\t\t\t\t\t.getResponseBody();\n\t\t\t\tassertThat(body).contains(\"Whitelabel Error Page\")\n\t\t\t\t\t.contains(this.logIdFilter.getLogId())\n\t\t\t\t\t.contains(\"<div>Expected!</div>\")\n\t\t\t\t\t.contains(\"<div style='white-space:pre-wrap;'>java.lang.IllegalStateException\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid escapeHtmlInDefaultErrorView() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mustache.prefix=classpath:/unknown/\", \"spring.web.error.include-message=always\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tString body = client.get()\n\t\t\t\t\t.uri(\"/html\")\n\t\t\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t\t\t.expectHeader()\n\t\t\t\t\t.contentType(TEXT_HTML_UTF8)\n\t\t\t\t\t.expectBody(String.class)\n\t\t\t\t\t.returnResult()\n\t\t\t\t\t.getResponseBody();\n\t\t\t\tassertThat(body).contains(\"Whitelabel Error Page\")\n\t\t\t\t\t.contains(this.logIdFilter.getLogId())\n\t\t\t\t\t.doesNotContain(\"<script>\")\n\t\t\t\t\t.contains(\"&lt;script&gt;\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid testExceptionWithNullMessage() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mustache.prefix=classpath:/unknown/\").run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tString body = client.get()\n\t\t\t\t.uri(\"/notfound\")\n\t\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isNotFound()\n\t\t\t\t.expectHeader()\n\t\t\t\t.contentType(TEXT_HTML_UTF8)\n\t\t\t\t.expectBody(String.class)\n\t\t\t\t.returnResult()\n\t\t\t\t.getResponseBody();\n\t\t\tassertThat(body).contains(\"Whitelabel Error Page\")\n\t\t\t\t.contains(this.logIdFilter.getLogId())\n\t\t\t\t.contains(\"type=Not Found, status=404\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid responseCommitted() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tassertThatExceptionOfType(RuntimeException.class)\n\t\t\t\t.isThrownBy(() -> client.get().uri(\"/commit\").exchange().expectStatus())\n\t\t\t\t.withCauseInstanceOf(FailureAfterResponseCompletedException.class)\n\t\t\t\t.withMessageContaining(\"Error occurred after response was completed\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whitelabelDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.error.whitelabel.enabled=false\",\n\t\t\t\t\t\"spring.mustache.prefix=classpath:/unknown/\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient client = getWebClient(context);\n\t\t\t\tclient.get()\n\t\t\t\t\t.uri(\"/notfound\")\n\t\t\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t\t\t.exchange()\n\t\t\t\t\t.expectStatus()\n\t\t\t\t\t.isNotFound()\n\t\t\t\t\t.expectBody()\n\t\t\t\t\t.isEmpty();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid invalidAcceptMediaType() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/notfound\")\n\t\t\t\t.header(\"Accept\", \"v=3.0\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isEqualTo(HttpStatus.NOT_FOUND);\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultErrorAttributesSubclassUsingDelegation() {\n\t\tthis.contextRunner.withUserConfiguration(CustomErrorAttributesWithDelegation.class).run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/badRequest\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"400\")\n\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t.isEqualTo(\"custom error\")\n\t\t\t\t.jsonPath(\"newAttribute\")\n\t\t\t\t.isEqualTo(\"value\")\n\t\t\t\t.jsonPath(\"path\")\n\t\t\t\t.doesNotExist();\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultErrorAttributesSubclassWithoutDelegation() {\n\t\tthis.contextRunner.withUserConfiguration(CustomErrorAttributesWithoutDelegation.class).run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/badRequest\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.isEqualTo(\"400\")\n\t\t\t\t.jsonPath(\"timestamp\")\n\t\t\t\t.doesNotExist()\n\t\t\t\t.jsonPath(\"error\")\n\t\t\t\t.isEqualTo(\"custom error\")\n\t\t\t\t.jsonPath(\"path\")\n\t\t\t\t.doesNotExist();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customErrorWebExceptionHandlerWithoutStatus() {\n\t\tthis.contextRunner.withUserConfiguration(CustomErrorWebExceptionHandlerWithoutStatus.class).run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/badRequest\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.doesNotExist();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customErrorAttributesWithoutStatus() {\n\t\tthis.contextRunner.withUserConfiguration(CustomErrorAttributesWithoutStatus.class).run((context) -> {\n\t\t\tWebTestClient client = getWebClient(context);\n\t\t\tclient.get()\n\t\t\t\t.uri(\"/badRequest\")\n\t\t\t\t.exchange()\n\t\t\t\t.expectStatus()\n\t\t\t\t.isBadRequest()\n\t\t\t\t.expectBody()\n\t\t\t\t.jsonPath(\"status\")\n\t\t\t\t.doesNotExist();\n\t\t});\n\t}\n\n\tprivate WebTestClient getWebClient(AssertableReactiveWebApplicationContext context) {\n\t\treturn WebTestClient.bindToApplicationContext(context).webFilter(this.logIdFilter).build();\n\t}\n\n\tprivate static final class LogIdFilter implements WebFilter {\n\n\t\tprivate @Nullable String logId;\n\n\t\t@Override\n\t\tpublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {\n\t\t\tthis.logId = exchange.getRequest().getId();\n\t\t\treturn chain.filter(exchange);\n\t\t}\n\n\t\t@Nullable String getLogId() {\n\t\t\treturn this.logId;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Application {\n\n\t\t@RestController\n\t\tstatic class ErrorController {\n\n\t\t\t@GetMapping(\"/\")\n\t\t\tString home() {\n\t\t\t\tthrow new IllegalStateException(\"Expected!\");\n\t\t\t}\n\n\t\t\t@GetMapping(\"/badRequest\")\n\t\t\tMono<String> badRequest() {\n\t\t\t\treturn Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST));\n\t\t\t}\n\n\t\t\t@GetMapping(\"/commit\")\n\t\t\tMono<Void> commit(ServerWebExchange exchange) {\n\t\t\t\treturn exchange.getResponse()\n\t\t\t\t\t.setComplete()\n\t\t\t\t\t.then(Mono.error(new IllegalStateException(\"already committed!\")));\n\t\t\t}\n\n\t\t\t@GetMapping(\"/html\")\n\t\t\tString htmlEscape() {\n\t\t\t\tthrow new IllegalStateException(\"<script>\");\n\t\t\t}\n\n\t\t\t@PostMapping(path = \"/bind\", produces = \"application/json\")\n\t\t\t@ResponseBody\n\t\t\tString bodyValidation(@Valid @RequestBody DummyBody body) {\n\t\t\t\treturn body.getContent();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomErrorAttributesWithDelegation {\n\n\t\t@Bean\n\t\tErrorAttributes errorAttributes() {\n\t\t\treturn new DefaultErrorAttributes() {\n\t\t\t\t@Override\n\t\t\t\tpublic Map<String, @Nullable Object> getErrorAttributes(ServerRequest request,\n\t\t\t\t\t\tErrorAttributeOptions options) {\n\t\t\t\t\tMap<String, @Nullable Object> errorAttributes = super.getErrorAttributes(request, options);\n\t\t\t\t\terrorAttributes.put(\"error\", \"custom error\");\n\t\t\t\t\terrorAttributes.put(\"newAttribute\", \"value\");\n\t\t\t\t\terrorAttributes.remove(\"path\");\n\t\t\t\t\treturn errorAttributes;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomErrorAttributesWithoutDelegation {\n\n\t\t@Bean\n\t\tErrorAttributes errorAttributes() {\n\t\t\treturn new DefaultErrorAttributes() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Map<String, @Nullable Object> getErrorAttributes(ServerRequest request,\n\t\t\t\t\t\tErrorAttributeOptions options) {\n\t\t\t\t\tMap<String, @Nullable Object> errorAttributes = new HashMap<>();\n\t\t\t\t\terrorAttributes.put(\"status\", 400);\n\t\t\t\t\terrorAttributes.put(\"error\", \"custom error\");\n\t\t\t\t\treturn errorAttributes;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class CustomErrorWebExceptionHandlerWithoutStatus {\n\n\t\t@Bean\n\t\t@Order(-1)\n\t\tErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties,\n\t\t\t\tObjectProvider<ViewResolver> viewResolvers, ServerCodecConfigurer serverCodecConfigurer,\n\t\t\t\tApplicationContext applicationContext) {\n\t\t\tDefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,\n\t\t\t\t\twebProperties.getResources(), webProperties.getError(), applicationContext) {\n\n\t\t\t\t@Override\n\t\t\t\tprotected ErrorAttributeOptions getErrorAttributeOptions(ServerRequest request, MediaType mediaType) {\n\t\t\t\t\treturn super.getErrorAttributeOptions(request, mediaType).excluding(Include.STATUS, Include.ERROR);\n\t\t\t\t}\n\n\t\t\t};\n\t\t\texceptionHandler.setViewResolvers(viewResolvers.orderedStream().toList());\n\t\t\texceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());\n\t\t\texceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());\n\t\t\treturn exceptionHandler;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomErrorAttributesWithoutStatus {\n\n\t\t@Bean\n\t\tErrorAttributes errorAttributes() {\n\t\t\treturn new DefaultErrorAttributes() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic Map<String, @Nullable Object> getErrorAttributes(ServerRequest request,\n\t\t\t\t\t\tErrorAttributeOptions options) {\n\t\t\t\t\tMap<String, @Nullable Object> attributes = new LinkedHashMap<>(\n\t\t\t\t\t\t\tsuper.getErrorAttributes(request, options));\n\t\t\t\t\tattributes.remove(\"status\");\n\t\t\t\t\treturn attributes;\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/error/DefaultErrorWebExceptionHandlerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.autoconfigure.web.ErrorProperties;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.context.reactive.AnnotationConfigReactiveWebApplicationContext;\nimport org.springframework.boot.webflux.error.ErrorAttributes;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.HttpMessageReader;\nimport org.springframework.http.codec.ResourceHttpMessageWriter;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.result.view.View;\nimport org.springframework.web.reactive.result.view.ViewResolver;\nimport org.springframework.web.server.ServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultErrorWebExceptionHandler}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass DefaultErrorWebExceptionHandlerTests {\n\n\t@Test\n\t@WithResource(name = \"static/error/498.html\", content = \"\"\"\n\t\t\t<html>\n\t\t\t<body>\n\t\t\t<ul>\n\t\t\t<li>status: 498</li>\n\t\t\t<li>message: non standard error</li>\n\t\t\t</ul>\n\t\t\t</body>\n\t\t\t</html>\n\t\t\t\"\"\")\n\tvoid nonStandardErrorStatusCodeShouldNotFail() {\n\t\tErrorAttributes errorAttributes = mock(ErrorAttributes.class);\n\t\tgiven(errorAttributes.getErrorAttributes(any(), any())).willReturn(Collections.singletonMap(\"status\", 498));\n\t\tResources resourceProperties = new Resources();\n\t\tErrorProperties errorProperties = new ErrorProperties();\n\t\tApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();\n\t\tDefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,\n\t\t\t\tresourceProperties, errorProperties, context);\n\t\texceptionHandler.setMessageWriters(List.of(new ResourceHttpMessageWriter()));\n\t\tsetupViewResolver(exceptionHandler);\n\t\tServerWebExchange exchange = MockServerWebExchange\n\t\t\t.from(MockServerHttpRequest.get(\"/some-other-path\").accept(MediaType.TEXT_HTML));\n\t\texceptionHandler.handle(exchange, new RuntimeException()).block();\n\t}\n\n\tprivate void setupViewResolver(DefaultErrorWebExceptionHandler exceptionHandler) {\n\t\tView view = mock(View.class);\n\t\tgiven(view.render(any(), any(), any())).willReturn(Mono.empty());\n\t\tViewResolver viewResolver = mock(ViewResolver.class);\n\t\tgiven(viewResolver.resolveViewName(any(), any())).willReturn(Mono.just(view));\n\t\texceptionHandler.setViewResolvers(Collections.singletonList(viewResolver));\n\t}\n\n\t@Test\n\tvoid acceptsTextHtmlShouldNotConsiderMediaAllEvenWithQuality() {\n\t\tErrorAttributes errorAttributes = mock(ErrorAttributes.class);\n\t\tResources resourceProperties = new Resources();\n\t\tErrorProperties errorProperties = new ErrorProperties();\n\t\tApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();\n\t\tDefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,\n\t\t\t\tresourceProperties, errorProperties, context);\n\t\tMediaType allWithQuality = new MediaType(MediaType.ALL.getType(), MediaType.ALL.getSubtype(), 0.9);\n\t\tMockServerWebExchange exchange = MockServerWebExchange\n\t\t\t.from(MockServerHttpRequest.get(\"/test\").accept(allWithQuality));\n\t\tList<HttpMessageReader<?>> readers = ServerCodecConfigurer.create().getReaders();\n\t\tServerRequest request = ServerRequest.create(exchange, readers);\n\t\tassertThat(exceptionHandler.acceptsTextHtml().test(request)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/autoconfigure/error/DummyBody.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.autoconfigure.error;\n\nimport jakarta.validation.constraints.NotNull;\n\npublic class DummyBody {\n\n\t@NotNull\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String content;\n\n\tpublic String getContent() {\n\t\treturn this.content;\n\t}\n\n\tpublic void setContent(String content) {\n\t\tthis.content = content;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/test/java/org/springframework/boot/webflux/error/DefaultErrorAttributesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.error;\n\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.codec.HttpMessageReader;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.mock.http.server.reactive.MockServerHttpRequest;\nimport org.springframework.mock.web.server.MockServerWebExchange;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.MapBindingResult;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.validation.method.MethodValidationResult;\nimport org.springframework.validation.method.ParameterValidationResult;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.support.WebExchangeBindException;\nimport org.springframework.web.method.annotation.HandlerMethodValidationException;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.server.ResponseStatusException;\nimport org.springframework.web.server.ServerWebExchange;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link DefaultErrorAttributes}.\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Yanming Zhou\n * @author Yongjun Hong\n */\nclass DefaultErrorAttributesTests {\n\n\tprivate static final ResponseStatusException NOT_FOUND = new ResponseStatusException(HttpStatus.NOT_FOUND);\n\n\tprivate DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes();\n\n\tprivate final List<HttpMessageReader<?>> readers = ServerCodecConfigurer.create().getReaders();\n\n\t@Test\n\tvoid missingExceptionAttribute() {\n\t\tMockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(\"/test\").build());\n\t\tServerRequest request = ServerRequest.create(exchange, this.readers);\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.errorAttributes.getErrorAttributes(request, ErrorAttributeOptions.defaults()))\n\t\t\t.withMessageContaining(\"Missing exception attribute in ServerWebExchange\");\n\t}\n\n\t@Test\n\tvoid includeTimeStamp() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, NOT_FOUND), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes.get(\"timestamp\")).isInstanceOf(Date.class);\n\t}\n\n\t@Test\n\tvoid defaultStatusCode() {\n\t\tError error = new OutOfMemoryError(\"Test error\");\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, error), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"error\", HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());\n\t\tassertThat(attributes).containsEntry(\"status\", 500);\n\t}\n\n\t@Test\n\tvoid annotatedResponseStatusCode() {\n\t\tException error = new CustomException();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, error), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"error\", HttpStatus.EXPECTATION_FAILED.getReasonPhrase());\n\t\tassertThat(attributes).doesNotContainKey(\"message\");\n\t\tassertThat(attributes).containsEntry(\"status\", HttpStatus.EXPECTATION_FAILED.value());\n\t}\n\n\t@Test\n\tvoid annotatedResponseStatusCodeWithExceptionMessage() {\n\t\tException error = new CustomException(\"Test Message\");\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(\n\t\t\t\tbuildServerRequest(request, error),\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE, Include.STATUS, Include.ERROR));\n\t\tassertThat(attributes).containsEntry(\"error\", HttpStatus.EXPECTATION_FAILED.getReasonPhrase());\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test Message\");\n\t\tassertThat(attributes).containsEntry(\"status\", HttpStatus.EXPECTATION_FAILED.value());\n\t}\n\n\t@Test\n\tvoid annotatedResponseStatusCodeWithCustomReasonPhrase() {\n\t\tException error = new Custom2Exception();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(\n\t\t\t\tbuildServerRequest(request, error),\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE, Include.STATUS, Include.ERROR));\n\t\tassertThat(attributes).containsEntry(\"error\", HttpStatus.EXPECTATION_FAILED.getReasonPhrase());\n\t\tassertThat(attributes).containsEntry(\"status\", HttpStatus.EXPECTATION_FAILED.value());\n\t\tassertThat(attributes).containsEntry(\"message\", \"Nope!\");\n\t}\n\n\t@Test\n\tvoid includeStatusCode() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, NOT_FOUND), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"error\", HttpStatus.NOT_FOUND.getReasonPhrase());\n\t\tassertThat(attributes).containsEntry(\"status\", 404);\n\t}\n\n\t@Test\n\tvoid getError() {\n\t\tError error = new OutOfMemoryError(\"Test error\");\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test error\");\n\t}\n\n\t@Test\n\tvoid excludeMessage() {\n\t\tError error = new OutOfMemoryError(\"Test error\");\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);\n\t\tassertThat(attributes).doesNotContainKey(\"message\");\n\t}\n\n\t@Test\n\tvoid includeException() {\n\t\tRuntimeException error = new RuntimeException(\"Test\");\n\t\tthis.errorAttributes = new DefaultErrorAttributes();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.EXCEPTION, Include.MESSAGE));\n\t\tassertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);\n\t\tassertThat(attributes).containsEntry(\"exception\", RuntimeException.class.getName());\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid processResponseStatusException() {\n\t\tRuntimeException nested = new RuntimeException(\"Test\");\n\t\tResponseStatusException error = new ResponseStatusException(HttpStatus.BAD_REQUEST, \"invalid request\", nested);\n\t\tthis.errorAttributes = new DefaultErrorAttributes();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.EXCEPTION, Include.MESSAGE, Include.STATUS));\n\t\tassertThat(attributes).containsEntry(\"status\", 400);\n\t\tassertThat(attributes).containsEntry(\"message\", \"invalid request\");\n\t\tassertThat(attributes).containsEntry(\"exception\", RuntimeException.class.getName());\n\t\tassertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);\n\t}\n\n\t@Test\n\tvoid processResponseStatusExceptionWithNoNestedCause() {\n\t\tResponseStatusException error = new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE,\n\t\t\t\t\"could not process request\");\n\t\tthis.errorAttributes = new DefaultErrorAttributes();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.EXCEPTION, Include.MESSAGE, Include.STATUS));\n\t\tassertThat(attributes).containsEntry(\"status\", 406);\n\t\tassertThat(attributes).containsEntry(\"message\", \"could not process request\");\n\t\tassertThat(attributes).containsEntry(\"exception\", ResponseStatusException.class.getName());\n\t\tassertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);\n\t}\n\n\t@Test\n\tvoid notIncludeTrace() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, ex), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\tvoid includeTrace() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, ex), ErrorAttributeOptions.of(Include.STACK_TRACE));\n\t\tObject trace = attributes.get(\"trace\");\n\t\tassertThat(trace).isNotNull();\n\t\tassertThat(trace.toString()).startsWith(\"java.lang\");\n\t}\n\n\t@Test\n\tvoid includePathByDefault() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, NOT_FOUND), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"path\", \"/test\");\n\t}\n\n\t@Test\n\tvoid includePath() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, NOT_FOUND), ErrorAttributeOptions.of(Include.PATH));\n\t\tassertThat(attributes).containsEntry(\"path\", \"/test\");\n\t}\n\n\t@Test\n\tvoid pathShouldIncludeContext() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/context/test\").contextPath(\"/context\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, NOT_FOUND), ErrorAttributeOptions.of(Include.PATH));\n\t\tassertThat(attributes).containsEntry(\"path\", \"/context/test\");\n\t}\n\n\t@Test\n\tvoid excludePath() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, NOT_FOUND), ErrorAttributeOptions.of());\n\t\tassertThat(attributes).doesNotContainEntry(\"path\", \"/test\");\n\t}\n\n\t@Test\n\tvoid includeLogPrefix() {\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, NOT_FOUND);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"requestId\", serverRequest.exchange().getRequest().getId());\n\t}\n\n\t@Test\n\tvoid extractBindingResultErrors() throws Exception {\n\t\tMethod method = getClass().getDeclaredMethod(\"method\", String.class);\n\t\tMethodParameter stringParam = new MethodParameter(method, 0);\n\t\tBindingResult bindingResult = new MapBindingResult(Collections.singletonMap(\"a\", \"b\"), \"objectName\");\n\t\tbindingResult.addError(new ObjectError(\"c\", \"d\"));\n\t\tException ex = new WebExchangeBindException(stringParam, bindingResult);\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(\n\t\t\t\tbuildServerRequest(request, ex), ErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t\tassertThat(attributes.get(\"message\")).asString()\n\t\t\t.startsWith(\"Validation failed for argument at index 0 in method: \" + \"int \" + getClass().getName()\n\t\t\t\t\t+ \".method(java.lang.String), with 1 error(s)\");\n\t\tassertThat(attributes).containsEntry(\"errors\",\n\t\t\t\torg.springframework.boot.web.error.Error.wrapIfNecessary(bindingResult.getAllErrors()));\n\t}\n\n\t@Test\n\tvoid extractBindingResultErrorsThatCausedAResponseStatusException() throws Exception {\n\t\tMethod method = getClass().getDeclaredMethod(\"method\", String.class);\n\t\tMethodParameter stringParam = new MethodParameter(method, 0);\n\t\tBindingResult bindingResult = new MapBindingResult(Collections.singletonMap(\"a\", \"b\"), \"objectName\");\n\t\tbindingResult.addError(new ObjectError(\"c\", \"d\"));\n\t\tException ex = new WebExchangeBindException(stringParam, bindingResult);\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(\n\t\t\t\tbuildServerRequest(request, new ResponseStatusException(HttpStatus.BAD_REQUEST, \"Invalid\", ex)),\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t\tassertThat(attributes.get(\"message\")).isEqualTo(\"Invalid\");\n\t\tassertThat(attributes).containsEntry(\"errors\",\n\t\t\t\torg.springframework.boot.web.error.Error.wrapIfNecessary(bindingResult.getAllErrors()));\n\t}\n\n\t@Test\n\tvoid extractMethodValidationResultErrors() throws Exception {\n\t\tObject target = \"test\";\n\t\tMethod method = String.class.getMethod(\"substring\", int.class);\n\t\tMethodParameter parameter = new MethodParameter(method, 0);\n\t\tMethodValidationResult methodValidationResult = MethodValidationResult.create(target, method,\n\t\t\t\tList.of(new ParameterValidationResult(parameter, -1,\n\t\t\t\t\t\tList.of(new ObjectError(\"beginIndex\", \"beginIndex is negative\")), null, null, null,\n\t\t\t\t\t\t(error, sourceType) -> {\n\t\t\t\t\t\t\tthrow new IllegalArgumentException(\"No source object of the given type\");\n\t\t\t\t\t\t})));\n\t\tHandlerMethodValidationException ex = new HandlerMethodValidationException(methodValidationResult);\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(\n\t\t\t\tbuildServerRequest(request, ex), ErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t\tassertThat(attributes.get(\"message\")).asString()\n\t\t\t.isEqualTo(\n\t\t\t\t\t\"Validation failed for method='public java.lang.String java.lang.String.substring(int)'. Error count: 1\");\n\t\tassertThat(attributes).containsEntry(\"errors\",\n\t\t\t\torg.springframework.boot.web.error.Error.wrapIfNecessary(methodValidationResult.getAllErrors()));\n\t}\n\n\t@Test\n\tvoid extractBindingResultErrorsExcludeMessageAndErrors() throws Exception {\n\t\tMethod method = getClass().getDeclaredMethod(\"method\", String.class);\n\t\tMethodParameter stringParam = new MethodParameter(method, 0);\n\t\tBindingResult bindingResult = new MapBindingResult(Collections.singletonMap(\"a\", \"b\"), \"objectName\");\n\t\tbindingResult.addError(new ObjectError(\"c\", \"d\"));\n\t\tException ex = new WebExchangeBindException(stringParam, bindingResult);\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes\n\t\t\t.getErrorAttributes(buildServerRequest(request, ex), ErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).doesNotContainKey(\"message\");\n\t\tassertThat(attributes).doesNotContainKey(\"errors\");\n\t}\n\n\t@Test\n\tvoid extractParameterValidationResultErrors() throws Exception {\n\t\tObject target = \"test\";\n\t\tMethod method = String.class.getMethod(\"substring\", int.class);\n\t\tMethodParameter parameter = new MethodParameter(method, 0);\n\t\tParameterValidationResult parameterValidationResult = new ParameterValidationResult(parameter, -1,\n\t\t\t\tList.of(new ObjectError(\"beginIndex\", \"beginIndex is negative\")), null, null, null,\n\t\t\t\t(error, sourceType) -> {\n\t\t\t\t\tthrow new IllegalArgumentException(\"No source object of the given type\");\n\t\t\t\t});\n\t\tMethodValidationResult methodValidationResult = MethodValidationResult.create(target, method,\n\t\t\t\tList.of(parameterValidationResult));\n\t\tHandlerMethodValidationException ex = new HandlerMethodValidationException(methodValidationResult);\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(\n\t\t\t\tbuildServerRequest(request, ex), ErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t\tassertThat(attributes.get(\"message\")).asString()\n\t\t\t.isEqualTo(\n\t\t\t\t\t\"Validation failed for method='public java.lang.String java.lang.String.substring(int)'. Error count: 1\");\n\t\tassertThat(attributes).containsEntry(\"errors\",\n\t\t\t\torg.springframework.boot.web.error.Error.wrapIfNecessary(methodValidationResult.getAllErrors()));\n\t}\n\n\t@Test\n\tvoid excludeStatus() {\n\t\tResponseStatusException error = new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE,\n\t\t\t\t\"could not process request\");\n\t\tthis.errorAttributes = new DefaultErrorAttributes();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.defaults().excluding(Include.STATUS));\n\t\tassertThat(attributes).doesNotContainKey(\"status\");\n\t}\n\n\t@Test\n\tvoid excludeError() {\n\t\tResponseStatusException error = new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE,\n\t\t\t\t\"could not process request\");\n\t\tthis.errorAttributes = new DefaultErrorAttributes();\n\t\tMockServerHttpRequest request = MockServerHttpRequest.get(\"/test\").build();\n\t\tServerRequest serverRequest = buildServerRequest(request, error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest,\n\t\t\t\tErrorAttributeOptions.defaults().excluding(Include.ERROR));\n\t\tassertThat(attributes).doesNotContainKey(\"error\");\n\t}\n\n\tprivate ServerRequest buildServerRequest(MockServerHttpRequest request, Throwable error) {\n\t\tServerWebExchange exchange = MockServerWebExchange.from(request);\n\t\tthis.errorAttributes.storeErrorInformation(error, exchange);\n\t\treturn ServerRequest.create(exchange, this.readers);\n\t}\n\n\tint method(String firstParam) {\n\t\treturn 42;\n\t}\n\n\t@ResponseStatus(HttpStatus.EXPECTATION_FAILED)\n\tstatic class CustomException extends RuntimeException {\n\n\t\tCustomException() {\n\t\t}\n\n\t\tCustomException(String message) {\n\t\t\tsuper(message);\n\t\t}\n\n\t}\n\n\t@ResponseStatus(value = HttpStatus.EXPECTATION_FAILED, reason = \"Nope!\")\n\tstatic class Custom2Exception extends RuntimeException {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/testFixtures/java/org/springframework/boot/webflux/actuate/endpoint/web/test/WebFluxEndpointConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web.test;\n\nimport java.util.Collections;\n\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;\nimport org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;\nimport org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.server.reactive.HttpHandler;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\n/**\n * Endpoint configuration for WebFlux.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ImportAutoConfiguration({ JacksonAutoConfiguration.class, WebFluxAutoConfiguration.class })\nclass WebFluxEndpointConfiguration {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tWebFluxEndpointConfiguration(ApplicationContext applicationContext) {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Bean\n\tNettyReactiveWebServerFactory netty() {\n\t\treturn new NettyReactiveWebServerFactory(0);\n\t}\n\n\t@Bean\n\tHttpHandler httpHandler(ApplicationContext applicationContext) {\n\t\treturn WebHttpHandlerBuilder.applicationContext(applicationContext).build();\n\t}\n\n\t@Bean\n\tWebFluxEndpointHandlerMapping webEndpointReactiveHandlerMapping() {\n\t\tEndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;\n\t\tWebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,\n\t\t\t\tnew ConversionServiceParameterValueMapper(), endpointMediaTypes, Collections.emptyList(),\n\t\t\t\tCollections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());\n\t\treturn new WebFluxEndpointHandlerMapping(new EndpointMapping(\"/actuator\"), discoverer.getEndpoints(),\n\t\t\t\tendpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),\n\t\t\t\ttrue);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/testFixtures/java/org/springframework/boot/webflux/actuate/endpoint/web/test/WebFluxWebEndpointInfrastructureProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.actuate.endpoint.web.test;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\n\n/**\n * {@link WebEndpointInfrastructureProvider} for WebFlux.\n *\n * @author Stephane Nicoll\n */\nclass WebFluxWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {\n\n\t@Override\n\tpublic boolean supports(Infrastructure infrastructure) {\n\t\treturn infrastructure == Infrastructure.WEBFLUX;\n\t}\n\n\t@Override\n\tpublic List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {\n\t\treturn List.of(WebFluxEndpointConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux/src/testFixtures/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\\\norg.springframework.boot.webflux.actuate.endpoint.web.test.WebFluxWebEndpointInfrastructureProvider\n"
  },
  {
    "path": "module/spring-boot-webflux-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-metadata\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot WebFlux Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-webflux\"))\n\tapi(project(\":module:spring-boot-webtestclient\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-http-codec\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-validation\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/AutoConfigureWebFlux.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Spring WebFlux\n * tests. Most tests should consider using {@link WebFluxTest @WebFluxTest} rather than\n * using this annotation directly.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n * @see WebFluxTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureWebFlux {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Annotation that can be used for a Spring WebFlux test that focuses\n * <strong>only</strong> on Spring WebFlux components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to WebFlux\n * tests. Similarly, component scanning is limited to beans annotated with:\n * <ul>\n * <li>{@code @Controller}</li>\n * <li>{@code @ControllerAdvice}</li>\n * <li>{@code @JacksonComponent}</li>\n * <li>{@code @JsonComponent} (Jackson 2, deprecated)</li>\n * </ul>\n * <p>\n * as well as beans that implement:\n * <ul>\n * <li>{@code Converter}</li>\n * <li>{@code GenericConverter}</li>\n * <li>{@code IDialect}, if Thymeleaf is available</li>\n * <li>{@code JacksonModule}, if Jackson is available</li>\n * <li>{@code Module}, if Jackson 2 is available (deprecated)</li>\n * <li>{@code WebExceptionHandler}</li>\n * <li>{@code WebFluxConfigurer}</li>\n * <li>{@code WebFilter}</li>\n * </ul>\n * <p>\n * By default, tests annotated with {@code @WebFluxTest} will also auto-configure a\n * {@link WebTestClient}. For more fine-grained control of WebTestClient the\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient} annotation can be used.\n * <p>\n * Typically {@code @WebFluxTest} is used in combination with\n * {@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}\n * or {@link Import @Import} to create any collaborators required by your\n * {@code @Controller} beans.\n * <p>\n * If you are looking to load your full application configuration and use WebTestClient,\n * you should consider {@link SpringBootTest @SpringBootTest} combined with\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient} rather than this\n * annotation.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @since 4.0.0\n * @see AutoConfigureWebFlux\n * @see AutoConfigureWebTestClient\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(WebFluxTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(WebFluxTypeExcludeFilter.class)\n@AutoConfigureJson\n@AutoConfigureWebFlux\n@AutoConfigureWebTestClient\n@ImportAutoConfiguration\npublic @interface WebFluxTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the controllers to test. This is an alias of {@link #controllers()} which\n\t * can be used for brevity if no other attributes are defined. See\n\t * {@link #controllers()} for details.\n\t * @see #controllers()\n\t * @return the controllers to test\n\t */\n\t@AliasFor(\"controllers\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the controllers to test. May be left blank if all {@code @Controller}\n\t * beans should be added to the application context.\n\t * @see #value()\n\t * @return the controllers to test\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] controllers() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default only\n\t * {@code @Controller} (when no explicit {@link #controllers() controllers} are\n\t * defined), {@code @ControllerAdvice} and {@code WebFluxConfigurer} beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.boot.test.context.ReactiveWebMergedContextConfiguration;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link WebFluxTest @WebFluxTest} support.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n */\nclass WebFluxTestContextBootstrapper extends TestSliceTestContextBootstrapper<WebFluxTest> {\n\n\t@Override\n\tprotected MergedContextConfiguration processMergedContextConfiguration(MergedContextConfiguration mergedConfig) {\n\t\treturn new ReactiveWebMergedContextConfiguration(super.processMergedContextConfiguration(mergedConfig));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.server.WebExceptionHandler;\nimport org.springframework.web.server.WebFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link WebFluxTest @WebFluxTest}.\n *\n * @author Stephane Nicoll\n */\nclass WebFluxTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<WebFluxTest> {\n\n\tprivate static final Class<?>[] NO_CONTROLLERS = {};\n\n\tprivate static final String[] OPTIONAL_INCLUDES = { \"tools.jackson.databind.JacksonModule\",\n\t\t\t\"org.springframework.boot.jackson.JacksonComponent\", \"com.fasterxml.jackson.databind.Module\",\n\t\t\t\"org.springframework.boot.jackson2.JsonComponent\" };\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>();\n\t\tincludes.add(ControllerAdvice.class);\n\t\tincludes.add(WebFluxConfigurer.class);\n\t\tincludes.add(Converter.class);\n\t\tincludes.add(GenericConverter.class);\n\t\tincludes.add(WebExceptionHandler.class);\n\t\tincludes.add(WebFilter.class);\n\t\tfor (String optionalInclude : OPTIONAL_INCLUDES) {\n\t\t\ttry {\n\t\t\t\tincludes.add(ClassUtils.forName(optionalInclude, null));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tKNOWN_INCLUDES = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES_AND_CONTROLLER;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>(KNOWN_INCLUDES);\n\t\tincludes.add(Controller.class);\n\t\tKNOWN_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate final Class<?>[] controllers;\n\n\tWebFluxTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.controllers = getAnnotation().getValue(\"controllers\", Class[].class).orElse(NO_CONTROLLERS);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\tif (ObjectUtils.isEmpty(this.controllers)) {\n\t\t\treturn KNOWN_INCLUDES_AND_CONTROLLER;\n\t\t}\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.controllers));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring WebFlux tests.\n */\n@NullMarked\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/resources/META-INF/spring/org.springframework.boot.webflux.test.autoconfigure.AutoConfigureWebFlux.imports",
    "content": "org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration\norg.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration\noptional:org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration\noptional:org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.webtestclient.timeout\",\n      \"type\": \"java.time.Duration\",\n      \"description\": \"Maximum amount of time to wait for responses.\",\n      \"defaultValue\": \"5s\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleController1.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebFluxTest @WebFluxTest}\n * tests.\n *\n * @author Stephane Nicoll\n */\n@RestController\npublic class ExampleController1 {\n\n\t@GetMapping(\"/one\")\n\tpublic Mono<String> one() {\n\t\treturn Mono.just(\"one\");\n\t}\n\n\t@GetMapping(\"/one/error\")\n\tpublic Mono<String> error() {\n\t\tthrow new RuntimeException(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleController2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebFluxTest @WebFluxTest}\n * tests.\n *\n * @author Stephane Nicoll\n */\n@RestController\npublic class ExampleController2 {\n\n\t@GetMapping(\"/two\")\n\tpublic Mono<String> two() {\n\t\treturn Mono.just(\"two\");\n\t}\n\n\t@GetMapping(\"/two/{id}\")\n\tpublic Mono<String> two(@PathVariable ExampleId id) {\n\t\treturn Mono.just(id.getId() + \"two\");\n\t}\n\n\t@PostMapping(\"/two/{id}\")\n\t@ResponseBody\n\tpublic Mono<ExampleResult> twoUpdate(@PathVariable String id) {\n\t\treturn Mono.just(new ExampleResult(id));\n\t}\n\n\t@PostMapping(\"/two2/{id}\")\n\t@ResponseBody\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tpublic Mono<ExampleResult2> two2Update(@PathVariable String id) {\n\t\treturn Mono.just(new ExampleResult2(id));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleId.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.util.UUID;\n\nimport org.springframework.core.convert.converter.Converter;\n\n/**\n * An example attribute that requires a {@link Converter}.\n *\n * @author Stephane Nicoll\n */\npublic class ExampleId {\n\n\tprivate final UUID id;\n\n\tExampleId(UUID id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic UUID getId() {\n\t\treturn this.id;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleIdConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.UUID;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.core.convert.TypeDescriptor;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.stereotype.Component;\n\n/**\n * Example {@link GenericConverter} used with {@link WebFluxTest @WebFluxTest} tests.\n *\n * @author Stephane Nicoll\n */\n@Component\npublic class ExampleIdConverter implements GenericConverter {\n\n\t@Override\n\tpublic Set<ConvertiblePair> getConvertibleTypes() {\n\t\treturn Collections.singleton(new ConvertiblePair(String.class, ExampleId.class));\n\t}\n\n\t@Override\n\tpublic @Nullable Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ExampleId(UUID.fromString((String) source));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExamplePojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\n/**\n * Example POJO used with {@link WebFluxTest @WebFluxTest} tests.\n *\n * @author Andy Wilkinson\n */\npublic class ExamplePojo {\n\n\tprivate final String alpha;\n\n\tprivate final String bravo;\n\n\tpublic ExamplePojo(String alpha, String bravo) {\n\t\tthis.alpha = alpha;\n\t\tthis.bravo = bravo;\n\t}\n\n\tpublic String getAlpha() {\n\t\treturn this.alpha;\n\t}\n\n\tpublic String getBravo() {\n\t\treturn this.bravo;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleRealService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * Example {@link Service @Service} used with {@link WebFluxTest @WebFluxTest} tests.\n *\n * @author Stephane Nicoll\n */\n@Service\npublic class ExampleRealService {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleResult.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.springframework.boot.jackson.JacksonComponent;\n\n/**\n * Example result that requires a {@link JacksonComponent}.\n *\n * @param id sample data\n * @author Stephane Nicoll\n */\npublic record ExampleResult(String id) {\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleResult2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\n/**\n * Example result that requires a {@link org.springframework.boot.jackson2.JsonComponent}.\n *\n * @param id sample data\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic record ExampleResult2(String id) {\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleResult2Serializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson2.JsonComponent;\nimport org.springframework.boot.jackson2.JsonObjectSerializer;\n\n/**\n * {@link JsonObjectSerializer} for {@link ExampleResult}.\n *\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@JsonComponent\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ExampleResult2Serializer extends JsonObjectSerializer<ExampleResult2> {\n\n\t@Override\n\tprotected void serializeObject(ExampleResult2 item, JsonGenerator jgen, SerializerProvider provider)\n\t\t\tthrows IOException {\n\t\tjgen.writeStringField(\"identifier2\", item.id());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleResultSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.SerializationContext;\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.jackson.ObjectValueSerializer;\n\n/**\n * {@link ObjectValueSerializer} for {@link ExampleResult}.\n *\n * @author Stephane Nicoll\n */\n@JacksonComponent\npublic class ExampleResultSerializer extends ObjectValueSerializer<ExampleResult> {\n\n\t@Override\n\tprotected void serializeObject(ExampleResult item, JsonGenerator jsonWriter, SerializationContext context) {\n\t\tjsonWriter.writeStringProperty(\"identifier\", item.id());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleWebExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.boot.webflux.error.ErrorWebExceptionHandler;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebExceptionHandler;\n\n/**\n * Example {@link WebExceptionHandler} used with {@link WebFluxTest @WebFluxTest} tests.\n *\n * @author Madhura Bhave\n */\n@Component\n@Order(-2)\npublic class ExampleWebExceptionHandler implements WebExceptionHandler {\n\n\tprivate final ErrorWebExceptionHandler fallback;\n\n\tpublic ExampleWebExceptionHandler(ErrorWebExceptionHandler fallback) {\n\t\tthis.fallback = fallback;\n\t}\n\n\t@Override\n\tpublic Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {\n\t\tif (ex instanceof RuntimeException && \"foo\".equals(ex.getMessage())) {\n\t\t\texchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);\n\t\t\treturn exchange.getResponse().setComplete();\n\t\t}\n\t\treturn this.fallback.handle(exchange, ex);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/ExampleWebFluxApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link WebFluxTest @WebFluxTest} tests.\n *\n * @author Stephane Nicoll\n */\n@SpringBootApplication\npublic class ExampleWebFluxApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/JsonController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebFluxTest @WebFluxTest}\n * tests.\n *\n * @author Andy Wilkinson\n */\n@RestController\npublic class JsonController {\n\n\t@GetMapping(value = \"/json\", produces = MediaType.APPLICATION_JSON_VALUE)\n\tpublic Mono<ExamplePojo> json() {\n\t\treturn Mono.just(new ExamplePojo(\"a\", \"b\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestAllControllersIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Tests for {@link WebFluxTest @WebFluxTest} when no explicit controller is defined.\n *\n * @author Stephane Nicoll\n */\n@WebFluxTest\nclass WebFluxTestAllControllersIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid shouldFindController1() {\n\t\tthis.webClient.get().uri(\"/one\").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(\"one\");\n\t}\n\n\t@Test\n\tvoid shouldFindController2() {\n\t\tthis.webClient.get().uri(\"/two\").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(\"two\");\n\t}\n\n\t@Test\n\tvoid webExceptionHandling() {\n\t\tthis.webClient.get().uri(\"/one/error\").exchange().expectStatus().isBadRequest();\n\t}\n\n\t@Test\n\tvoid shouldFindJsonController() {\n\t\tthis.webClient.get().uri(\"/json\").exchange().expectStatus().isOk();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration;\nimport org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration;\nimport org.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Tests for the auto-configuration imported by {@link WebFluxTest @WebFluxTest}.\n *\n * @author Stephane Nicoll\n * @author Artsiom Yudovin\n * @author Ali Dehghani\n * @author Madhura Bhave\n */\n@WebFluxTest\nclass WebFluxTestAutoConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid messageSourceAutoConfigurationIsImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(MessageSourceAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid validationAutoConfigurationIsImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ValidationAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid errorWebFluxAutoConfigurationIsImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(ErrorWebFluxAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestConverterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Tests for {@link WebFluxTest @WebFluxTest} to validate converters are discovered.\n *\n * @author Stephane Nicoll\n */\n@WebFluxTest(controllers = ExampleController2.class)\nclass WebFluxTestConverterIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid shouldFindConverter() {\n\t\tUUID id = UUID.randomUUID();\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/two/\" + id)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(id + \"two\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestJacksonComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.test.json.JsonCompareMode;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Tests for {@link WebFluxTest @WebFluxTest} to validate {@link JacksonComponent} beans\n * are discovered.\n *\n * @author Stephane Nicoll\n */\n@WebFluxTest(controllers = ExampleController2.class)\nclass WebFluxTestJacksonComponentIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid shouldFindJacksonComponent() {\n\t\tthis.webClient.post()\n\t\t\t.uri(\"/two/\" + \"1234abcd\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.json(\"{ \\\"identifier\\\": \\\"1234abcd\\\" }\", JsonCompareMode.LENIENT);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestJsonComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.json.JsonCompareMode;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Tests for {@link WebFluxTest @WebFluxTest} to validate\n * {@link org.springframework.boot.jackson2.JsonComponent} beans are discovered.\n *\n * @author Stephane Nicoll\n */\n@WebFluxTest(controllers = ExampleController2.class, properties = \"spring.http.codecs.preferred-json-mapper=jackson2\")\nclass WebFluxTestJsonComponentIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid shouldFindJsonComponent() {\n\t\tthis.webClient.post()\n\t\t\t.uri(\"/two2/1234abcd\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.json(\"{ \\\"identifier2\\\": \\\"1234abcd\\\" }\", JsonCompareMode.LENIENT);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestMessageSourceIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.MessageSource;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link WebFluxTest @WebFluxTest} and {@link MessageSource}\n * auto-configuration.\n *\n * @author Stephane Nicoll\n */\n@WebFluxTest\n@TestPropertySource(properties = \"spring.messages.basename=web-test-messages\")\nclass WebFluxTestMessageSourceIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid messageSourceHasBeenAutoConfigured() {\n\t\tassertThat(this.context.getMessage(\"a\", null, Locale.ENGLISH)).isEqualTo(\"alpha\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestOneControllerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Tests for {@link WebFluxTest @WebFluxTest} when a specific controller is defined.\n *\n * @author Stephane Nicoll\n */\n@WebFluxTest(controllers = ExampleController1.class)\nclass WebFluxTestOneControllerIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid shouldFindController() {\n\t\tthis.webClient.get().uri(\"/one\").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(\"one\");\n\t}\n\n\t@Test\n\tvoid shouldNotScanOtherController() {\n\t\tthis.webClient.get().uri(\"/two\").exchange().expectStatus().isNotFound();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link WebFluxTest#properties properties} attribute of\n * {@link WebFluxTest @WebFluxTest}.\n *\n * @author Artsiom Yudovin\n */\n@WebFluxTest(properties = \"spring.profiles.active=test\")\nclass WebFluxTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(WebFluxTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTestWebTestClientCodecCustomizationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Tests for {@link WebFluxTest @WebFluxTest} to validate the {@link WebTestClient\n * WebTestClient's} codecs are customized.\n *\n * @author Andy Wilkinson\n */\n@WebFluxTest(controllers = JsonController.class)\nclass WebFluxTestWebTestClientCodecCustomizationIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid shouldBeAbleToCreatePojoViaParametersModule() {\n\t\tthis.webClient.get().uri(\"/json\").exchange().expectStatus().isOk().expectBody(ExamplePojo.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebFluxTypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webflux.test.autoconfigure;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport tools.jackson.databind.module.SimpleModule;\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.reactive.config.WebFluxConfigurer;\nimport org.springframework.web.server.ServerWebExchange;\nimport org.springframework.web.server.WebFilter;\nimport org.springframework.web.server.WebFilterChain;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebFluxTypeExcludeFilter}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\nclass WebFluxTypeExcludeFilterTests {\n\n\tprivate final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\t@Test\n\tvoid matchWhenHasNoControllers() throws Exception {\n\t\tWebFluxTypeExcludeFilter filter = new WebFluxTypeExcludeFilter(WithNoControllers.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebFilter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenHasController() throws Exception {\n\t\tWebFluxTypeExcludeFilter filter = new WebFluxTypeExcludeFilter(WithController.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebFilter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchNotUsingDefaultFilters() throws Exception {\n\t\tWebFluxTypeExcludeFilter filter = new WebFluxTypeExcludeFilter(NotUsingDefaultFilters.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isTrue();\n\t\tassertThat(excludes(filter, Controller2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebFilter.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWithIncludeFilter() throws Exception {\n\t\tWebFluxTypeExcludeFilter filter = new WebFluxTypeExcludeFilter(WithIncludeFilter.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWebFilter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWithExcludeFilter() throws Exception {\n\t\tWebFluxTypeExcludeFilter filter = new WebFluxTypeExcludeFilter(WithExcludeFilter.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isTrue();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebFilter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\tprivate boolean excludes(WebFluxTypeExcludeFilter filter, Class<?> type) throws IOException {\n\t\tMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());\n\t\treturn filter.match(metadataReader, this.metadataReaderFactory);\n\t}\n\n\t@WebFluxTest\n\tstatic class WithNoControllers {\n\n\t}\n\n\t@WebFluxTest(Controller1.class)\n\tstatic class WithController {\n\n\t}\n\n\t@WebFluxTest(useDefaultFilters = false)\n\tstatic class NotUsingDefaultFilters {\n\n\t}\n\n\t@WebFluxTest(includeFilters = @Filter(Repository.class))\n\tstatic class WithIncludeFilter {\n\n\t}\n\n\t@WebFluxTest(excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Controller1.class))\n\tstatic class WithExcludeFilter {\n\n\t}\n\n\t@Controller\n\tstatic class Controller1 {\n\n\t}\n\n\t@Controller\n\tstatic class Controller2 {\n\n\t}\n\n\t@ControllerAdvice\n\tstatic class ExampleControllerAdvice {\n\n\t}\n\n\tstatic class ExampleWeb implements WebFluxConfigurer {\n\n\t}\n\n\t@Service\n\tstatic class ExampleService {\n\n\t}\n\n\t@Repository\n\tstatic class ExampleRepository {\n\n\t}\n\n\tstatic class ExampleWebFilter implements WebFilter {\n\n\t\t@Override\n\t\tpublic Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {\n\t\t\treturn Mono.empty();\n\t\t}\n\n\t}\n\n\tstatic class ExampleModule extends SimpleModule {\n\n\t}\n\n\t@JacksonComponent\n\tstatic class ExampleJacksonComponent {\n\n\t}\n\n\tstatic class ExampleModule2 extends com.fasterxml.jackson.databind.module.SimpleModule {\n\n\t}\n\n\t@org.springframework.boot.jackson2.JsonComponent\n\t@SuppressWarnings(\"removal\")\n\tstatic class ExampleJsonComponent {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webflux-test/src/test/resources/web-test-messages.properties",
    "content": "a=alpha\n"
  },
  {
    "path": "module/spring-boot-webmvc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"java-test-fixtures\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Web MVC\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-servlet\"))\n\tapi(\"org.springframework:spring-web\")\n\tapi(\"org.springframework:spring-webmvc\")\n\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\n\timplementation(project(\":module:spring-boot-http-converter\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-actuator-autoconfigure\"))\n\toptional(project(\":module:spring-boot-health\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-micrometer-metrics\"))\n\toptional(project(\":module:spring-boot-micrometer-observation\"))\n\toptional(project(\":module:spring-boot-tomcat\"))\n\toptional(project(\":module:spring-boot-validation\"))\n\toptional(project(\":module:spring-boot-web-server\"))\n\toptional(\"com.fasterxml.jackson.core:jackson-databind\")\n\toptional(\"io.projectreactor:reactor-core\")\n\n\ttestFixturesApi(testFixtures(project(\":module:spring-boot-actuator\")))\n\ttestFixturesImplementation(project(\":module:spring-boot-http-converter\"))\n\ttestFixturesImplementation(project(\":module:spring-boot-jackson\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-jackson\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-actuator-autoconfigure\")))\n\ttestImplementation(testFixtures(project(\":module:spring-boot-web-server\")))\n\ttestImplementation(\"io.micrometer:micrometer-observation-test\")\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.aspectj:aspectjweaver\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"com.fasterxml.jackson.core:jackson-databind\")\n\ttestRuntimeOnly(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/WebMvcWebApplicationTypeDeducer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link WebApplicationType} deducer to ensure Spring MVC applications use\n * {@link WebApplicationType#SERVLET}.\n *\n * @author Phillip Webb\n */\n@Order(10) // Ordered before WebFlux\nclass WebMvcWebApplicationTypeDeducer implements WebApplicationType.Deducer {\n\n\tprivate static final String[] INDICATOR_CLASSES = { \"jakarta.servlet.Servlet\",\n\t\t\t\"org.springframework.web.servlet.DispatcherServlet\",\n\t\t\t\"org.springframework.web.context.ConfigurableWebApplicationContext\" };\n\n\t@Override\n\tpublic @Nullable WebApplicationType deduceWebApplicationType() {\n\t\t// Guard in case the classic module is being used and dependencies are excluded\n\t\tfor (String indicatorClass : INDICATOR_CLASSES) {\n\t\t\tif (!ClassUtils.isPresent(indicatorClass, null)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn WebApplicationType.SERVLET;\n\t}\n\n\tstatic class WebMvcWebApplicationTypeDeducerRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tfor (String servletIndicatorClass : INDICATOR_CLASSES) {\n\t\t\t\tregisterTypeIfPresent(servletIndicatorClass, classLoader, hints);\n\t\t\t}\n\t\t}\n\n\t\tprivate void registerTypeIfPresent(String typeName, @Nullable ClassLoader classLoader, RuntimeHints hints) {\n\t\t\tif (ClassUtils.isPresent(typeName, classLoader)) {\n\t\t\t\thints.reflection().registerType(TypeReference.of(typeName));\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/endpoint/web/AbstractWebMvcEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\nimport java.security.Principal;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.boot.actuate.endpoint.InvalidEndpointRequestException;\nimport org.springframework.boot.actuate.endpoint.InvocationContext;\nimport org.springframework.boot.actuate.endpoint.OperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.ProducibleOperationArgumentResolver;\nimport org.springframework.boot.actuate.endpoint.SecurityContext;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvoker;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.ResponseEntity.BodyBuilder;\nimport org.springframework.http.server.ServletServerHttpRequest;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.WebApplicationContextUtils;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.server.ResponseStatusException;\nimport org.springframework.web.servlet.HandlerMapping;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;\n\n/**\n * A custom {@link HandlerMapping} that makes {@link ExposableWebEndpoint web endpoints}\n * available over HTTP using Spring MVC.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Brian Clozel\n * @since 4.0.0\n */\n@ImportRuntimeHints(AbstractWebMvcEndpointHandlerMappingRuntimeHints.class)\npublic abstract class AbstractWebMvcEndpointHandlerMapping extends RequestMappingInfoHandlerMapping\n\t\timplements InitializingBean {\n\n\tprivate final EndpointMapping endpointMapping;\n\n\tprivate final Collection<ExposableWebEndpoint> endpoints;\n\n\tprivate final EndpointMediaTypes endpointMediaTypes;\n\n\tprivate final @Nullable CorsConfiguration corsConfiguration;\n\n\tprivate final boolean shouldRegisterLinksMapping;\n\n\tprivate final Method handleMethod = getHandleMethod();\n\n\tprivate final Method catchAllMethod = getCatchAllMethod();\n\n\tprivate RequestMappingInfo.BuilderConfiguration builderConfig = new RequestMappingInfo.BuilderConfiguration();\n\n\t/**\n\t * Creates a new {@code WebEndpointHandlerMapping} that provides mappings for the\n\t * operations of the given {@code webEndpoints}.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param endpointMediaTypes media types consumed and produced by the endpoints\n\t * @param shouldRegisterLinksMapping whether the links endpoint should be registered\n\t */\n\tpublic AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,\n\t\t\tboolean shouldRegisterLinksMapping) {\n\t\tthis(endpointMapping, endpoints, endpointMediaTypes, null, shouldRegisterLinksMapping);\n\t}\n\n\t/**\n\t * Creates a new {@code AbstractWebMvcEndpointHandlerMapping} that provides mappings\n\t * for the operations of the given endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param endpointMediaTypes media types consumed and produced by the endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t * @param shouldRegisterLinksMapping whether the links endpoint should be registered\n\t */\n\tpublic AbstractWebMvcEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,\n\t\t\t@Nullable CorsConfiguration corsConfiguration, boolean shouldRegisterLinksMapping) {\n\t\tthis.endpointMapping = endpointMapping;\n\t\tthis.endpoints = endpoints;\n\t\tthis.endpointMediaTypes = endpointMediaTypes;\n\t\tthis.corsConfiguration = corsConfiguration;\n\t\tthis.shouldRegisterLinksMapping = shouldRegisterLinksMapping;\n\t\tsetOrder(-100);\n\t}\n\n\tprivate static Method getHandleMethod() {\n\t\tMethod method = ReflectionUtils.findMethod(OperationHandler.class, \"handle\", HttpServletRequest.class,\n\t\t\t\tMap.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\treturn method;\n\t}\n\n\tprivate static Method getCatchAllMethod() {\n\t\tMethod method = ReflectionUtils.findMethod(CatchAllHandler.class, \"handle\", HttpServletResponse.class);\n\t\tAssert.state(method != null, \"'method' must not be null\");\n\t\treturn method;\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tthis.builderConfig = new RequestMappingInfo.BuilderConfiguration();\n\t\tthis.builderConfig.setPatternParser(getPatternParser());\n\t\tsuper.afterPropertiesSet();\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tfor (ExposableWebEndpoint endpoint : this.endpoints) {\n\t\t\tfor (WebOperation operation : endpoint.getOperations()) {\n\t\t\t\tregisterMappingForOperation(endpoint, operation);\n\t\t\t}\n\t\t}\n\t\tif (this.shouldRegisterLinksMapping) {\n\t\t\tregisterLinksMapping();\n\t\t}\n\t}\n\n\t@Override\n\tprotected HandlerMethod createHandlerMethod(Object handler, Method method) {\n\t\tHandlerMethod handlerMethod = super.createHandlerMethod(handler, method);\n\t\treturn new WebMvcEndpointHandlerMethod(handlerMethod.getBean(), handlerMethod.getMethod());\n\t}\n\n\tprivate void registerMappingForOperation(ExposableWebEndpoint endpoint, WebOperation operation) {\n\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\tString path = predicate.getPath();\n\t\tString matchAllRemainingPathSegmentsVariable = predicate.getMatchAllRemainingPathSegmentsVariable();\n\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\tpath = path.replace(\"{*\" + matchAllRemainingPathSegmentsVariable + \"}\", \"**\");\n\t\t}\n\t\tregisterMapping(endpoint, predicate, operation, path);\n\t}\n\n\tprotected void registerMapping(ExposableWebEndpoint endpoint, WebOperationRequestPredicate predicate,\n\t\t\tWebOperation operation, String path) {\n\t\tServletWebOperation servletWebOperation = wrapServletWebOperation(endpoint, operation,\n\t\t\t\tnew ServletWebOperationAdapter(operation));\n\t\tregisterMapping(createRequestMappingInfo(predicate, path), new OperationHandler(servletWebOperation),\n\t\t\t\tthis.handleMethod);\n\t}\n\n\t/**\n\t * Hook point that allows subclasses to wrap the {@link ServletWebOperation} before\n\t * it's called. Allows additional features, such as security, to be added.\n\t * @param endpoint the source endpoint\n\t * @param operation the source operation\n\t * @param servletWebOperation the servlet web operation to wrap\n\t * @return a wrapped servlet web operation\n\t */\n\tprotected ServletWebOperation wrapServletWebOperation(ExposableWebEndpoint endpoint, WebOperation operation,\n\t\t\tServletWebOperation servletWebOperation) {\n\t\treturn servletWebOperation;\n\t}\n\n\t/**\n\t * Register a \"catch all\" handler for the rest of actuator namespace, ensuring that\n\t * all requests are handled by this handler mapping.\n\t * @param responseStatus the response status to use for handled requests\n\t */\n\tprotected void registerCatchAllMapping(HttpStatus responseStatus) {\n\t\tString subPath = this.endpointMapping.createSubPath(\"/**\");\n\t\tregisterMapping(RequestMappingInfo.paths(subPath).options(this.builderConfig).build(),\n\t\t\t\tnew CatchAllHandler(responseStatus), this.catchAllMethod);\n\t}\n\n\tprivate RequestMappingInfo createRequestMappingInfo(WebOperationRequestPredicate predicate, String path) {\n\t\tString subPath = this.endpointMapping.createSubPath(path);\n\t\tList<String> paths = new ArrayList<>();\n\t\tpaths.add(subPath);\n\t\tif (!StringUtils.hasLength(subPath)) {\n\t\t\tpaths.add(\"/\");\n\t\t}\n\t\treturn RequestMappingInfo.paths(paths.toArray(new String[0]))\n\t\t\t.options(this.builderConfig)\n\t\t\t.methods(RequestMethod.valueOf(predicate.getHttpMethod().name()))\n\t\t\t.consumes(predicate.getConsumes().toArray(new String[0]))\n\t\t\t.produces(predicate.getProduces().toArray(new String[0]))\n\t\t\t.build();\n\t}\n\n\tprivate void registerLinksMapping() {\n\t\tString path = this.endpointMapping.getPath();\n\t\tString linksPath = (StringUtils.hasLength(path)) ? this.endpointMapping.createSubPath(\"/\") : \"/\";\n\t\tRequestMappingInfo mapping = RequestMappingInfo.paths(linksPath)\n\t\t\t.methods(RequestMethod.GET)\n\t\t\t.produces(this.endpointMediaTypes.getProduced().toArray(new String[0]))\n\t\t\t.options(this.builderConfig)\n\t\t\t.build();\n\t\tLinksHandler linksHandler = getLinksHandler();\n\t\tMethod links = ReflectionUtils.findMethod(linksHandler.getClass(), \"links\", HttpServletRequest.class,\n\t\t\t\tHttpServletResponse.class);\n\t\tAssert.state(links != null, \"'links' must not be null\");\n\t\tregisterMapping(mapping, linksHandler, links);\n\t}\n\n\t@Override\n\tprotected boolean hasCorsConfigurationSource(Object handler) {\n\t\treturn this.corsConfiguration != null;\n\t}\n\n\t@Override\n\tprotected @Nullable CorsConfiguration initCorsConfiguration(Object handler, Method method,\n\t\t\tRequestMappingInfo mapping) {\n\t\treturn this.corsConfiguration;\n\t}\n\n\t@Override\n\tprotected @Nullable CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {\n\t\tCorsConfiguration corsConfiguration = super.getCorsConfiguration(handler, request);\n\t\treturn (corsConfiguration != null) ? corsConfiguration : this.corsConfiguration;\n\t}\n\n\t@Override\n\tprotected boolean isHandler(Class<?> beanType) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tprotected @Nullable RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the Handler providing actuator links at the root endpoint.\n\t * @return the links handler\n\t */\n\tprotected abstract LinksHandler getLinksHandler();\n\n\t/**\n\t * Return the web endpoints being mapped.\n\t * @return the endpoints\n\t */\n\tpublic Collection<ExposableWebEndpoint> getEndpoints() {\n\t\treturn this.endpoints;\n\t}\n\n\t/**\n\t * Handler providing actuator links at the root endpoint.\n\t */\n\t@FunctionalInterface\n\tprotected interface LinksHandler {\n\n\t\t@Nullable Object links(HttpServletRequest request, HttpServletResponse response);\n\n\t}\n\n\t/**\n\t * A servlet web operation that can be handled by Spring MVC.\n\t */\n\t@FunctionalInterface\n\tprotected interface ServletWebOperation {\n\n\t\t@Nullable Object handle(HttpServletRequest request, @Nullable Map<String, String> body);\n\n\t}\n\n\t/**\n\t * Adapter class to convert an {@link OperationInvoker} into a\n\t * {@link ServletWebOperation}.\n\t */\n\tprivate static class ServletWebOperationAdapter implements ServletWebOperation {\n\n\t\tprivate static final String PATH_SEPARATOR = AntPathMatcher.DEFAULT_PATH_SEPARATOR;\n\n\t\tprivate static final List<Function<Object, Object>> BODY_CONVERTERS;\n\n\t\tstatic {\n\t\t\tList<Function<Object, Object>> converters = new ArrayList<>();\n\t\t\tif (ClassUtils.isPresent(\"reactor.core.publisher.Flux\",\n\t\t\t\t\tServletWebOperationAdapter.class.getClassLoader())) {\n\t\t\t\tconverters.add(new FluxBodyConverter());\n\t\t\t}\n\t\t\tBODY_CONVERTERS = Collections.unmodifiableList(converters);\n\t\t}\n\n\t\tprivate final WebOperation operation;\n\n\t\tServletWebOperationAdapter(WebOperation operation) {\n\t\t\tthis.operation = operation;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable Object handle(HttpServletRequest request,\n\t\t\t\t@RequestBody(required = false) @Nullable Map<String, String> body) {\n\t\t\tHttpHeaders headers = new ServletServerHttpRequest(request).getHeaders();\n\t\t\ttry {\n\t\t\t\tServletSecurityContext securityContext = new ServletSecurityContext(request);\n\t\t\t\tInvocationContext invocationContext = getInvocationContext(request, body, headers, securityContext);\n\t\t\t\treturn handleResult(this.operation.invoke(invocationContext), HttpMethod.valueOf(request.getMethod()));\n\t\t\t}\n\t\t\tcatch (InvalidEndpointRequestException ex) {\n\t\t\t\tthrow new InvalidEndpointBadRequestException(ex);\n\t\t\t}\n\t\t}\n\n\t\tprivate InvocationContext getInvocationContext(HttpServletRequest request, @Nullable Map<String, String> body,\n\t\t\t\tHttpHeaders headers, ServletSecurityContext securityContext) {\n\t\t\tMap<String, Object> arguments = getArguments(request, body);\n\t\t\tOperationArgumentResolver serverNamespaceResolver = OperationArgumentResolver.of(WebServerNamespace.class,\n\t\t\t\t\t() -> getServerNamespace(request));\n\t\t\tProducibleOperationArgumentResolver producibleOperationResolver = new ProducibleOperationArgumentResolver(\n\t\t\t\t\t() -> headers.get(\"Accept\"));\n\t\t\treturn new InvocationContext(securityContext, arguments, serverNamespaceResolver,\n\t\t\t\t\tproducibleOperationResolver);\n\t\t}\n\n\t\tprivate @Nullable WebServerNamespace getServerNamespace(HttpServletRequest request) {\n\t\t\tWebApplicationContext context = WebApplicationContextUtils\n\t\t\t\t.getRequiredWebApplicationContext(request.getServletContext());\n\t\t\treturn WebServerNamespace.from(context);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator web endpoint '\" + this.operation.getId() + \"'\";\n\t\t}\n\n\t\tprivate Map<String, Object> getArguments(HttpServletRequest request, @Nullable Map<String, String> body) {\n\t\t\tMap<String, Object> arguments = new LinkedHashMap<>(getTemplateVariables(request));\n\t\t\tString matchAllRemainingPathSegmentsVariable = this.operation.getRequestPredicate()\n\t\t\t\t.getMatchAllRemainingPathSegmentsVariable();\n\t\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\t\targuments.put(matchAllRemainingPathSegmentsVariable, getRemainingPathSegments(request));\n\t\t\t}\n\t\t\tif (body != null && HttpMethod.POST.name().equals(request.getMethod())) {\n\t\t\t\targuments.putAll(body);\n\t\t\t}\n\t\t\trequest.getParameterMap()\n\t\t\t\t.forEach((name, values) -> arguments.put(name,\n\t\t\t\t\t\t(values.length != 1) ? Arrays.asList(values) : values[0]));\n\t\t\treturn arguments;\n\t\t}\n\n\t\tprivate Object getRemainingPathSegments(HttpServletRequest request) {\n\t\t\tString[] pathTokens = tokenize(request, HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, true);\n\t\t\tString[] patternTokens = tokenize(request, HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, false);\n\t\t\tint numberOfRemainingPathSegments = pathTokens.length - patternTokens.length + 1;\n\t\t\tAssert.state(numberOfRemainingPathSegments >= 0, \"Unable to extract remaining path segments\");\n\t\t\tString[] remainingPathSegments = new String[numberOfRemainingPathSegments];\n\t\t\tSystem.arraycopy(pathTokens, patternTokens.length - 1, remainingPathSegments, 0,\n\t\t\t\t\tnumberOfRemainingPathSegments);\n\t\t\treturn remainingPathSegments;\n\t\t}\n\n\t\tprivate String[] tokenize(HttpServletRequest request, String attributeName, boolean decode) {\n\t\t\tString value = (String) request.getAttribute(attributeName);\n\t\t\tString[] segments = StringUtils.tokenizeToStringArray(value, PATH_SEPARATOR, false, true);\n\t\t\tif (decode) {\n\t\t\t\tfor (int i = 0; i < segments.length; i++) {\n\t\t\t\t\tif (segments[i].contains(\"%\")) {\n\t\t\t\t\t\tsegments[i] = StringUtils.uriDecode(segments[i], StandardCharsets.UTF_8);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn segments;\n\t\t}\n\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tprivate Map<String, String> getTemplateVariables(HttpServletRequest request) {\n\t\t\treturn (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);\n\t\t}\n\n\t\tprivate @Nullable Object handleResult(@Nullable Object result, HttpMethod httpMethod) {\n\t\t\tif (result == null) {\n\t\t\t\treturn new ResponseEntity<>(\n\t\t\t\t\t\t(httpMethod != HttpMethod.GET) ? HttpStatus.NO_CONTENT : HttpStatus.NOT_FOUND);\n\t\t\t}\n\t\t\tif (!(result instanceof WebEndpointResponse<?> response)) {\n\t\t\t\treturn convertIfNecessary(result);\n\t\t\t}\n\t\t\tMediaType contentType = (response.getContentType() != null) ? new MediaType(response.getContentType())\n\t\t\t\t\t: null;\n\t\t\tBodyBuilder builder = ResponseEntity.status(response.getStatus());\n\t\t\tif (contentType != null) {\n\t\t\t\tbuilder = builder.contentType(contentType);\n\t\t\t}\n\t\t\treturn builder.body(convertIfNecessary(response.getBody()));\n\t\t}\n\n\t\tprivate @Nullable Object convertIfNecessary(@Nullable Object body) {\n\t\t\tif (body == null) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tfor (Function<Object, Object> converter : BODY_CONVERTERS) {\n\t\t\t\tbody = converter.apply(body);\n\t\t\t}\n\t\t\treturn body;\n\t\t}\n\n\t\tprivate static final class FluxBodyConverter implements Function<Object, Object> {\n\n\t\t\t@Override\n\t\t\tpublic Object apply(Object body) {\n\t\t\t\tif (!(body instanceof Flux)) {\n\t\t\t\t\treturn body;\n\t\t\t\t}\n\t\t\t\treturn ((Flux<?>) body).collectList();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Handler for a {@link ServletWebOperation}.\n\t */\n\tprivate static final class OperationHandler {\n\n\t\tprivate final ServletWebOperation operation;\n\n\t\tOperationHandler(ServletWebOperation operation) {\n\t\t\tthis.operation = operation;\n\t\t}\n\n\t\t@ResponseBody\n\t\t@Reflective\n\t\t@Nullable Object handle(HttpServletRequest request, @RequestBody(required = false) Map<String, String> body) {\n\t\t\treturn this.operation.handle(request, body);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.operation.toString();\n\t\t}\n\n\t}\n\n\t/**\n\t * Catch-all handler that always replies with a fixed HTTP status.\n\t */\n\tprivate static final class CatchAllHandler {\n\n\t\tprivate final HttpStatus responseStatus;\n\n\t\tCatchAllHandler(HttpStatus responseStatus) {\n\t\t\tthis.responseStatus = responseStatus;\n\t\t}\n\n\t\t@Reflective\n\t\tvoid handle(HttpServletResponse response) {\n\t\t\tresponse.setStatus(this.responseStatus.value());\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link HandlerMethod} subclass for endpoint information logging.\n\t */\n\tprivate static class WebMvcEndpointHandlerMethod extends HandlerMethod {\n\n\t\tWebMvcEndpointHandlerMethod(Object bean, Method method) {\n\t\t\tsuper(bean, method);\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn getBean().toString();\n\t\t}\n\n\t\t@Override\n\t\tpublic HandlerMethod createWithResolvedBean() {\n\t\t\treturn this;\n\t\t}\n\n\t}\n\n\t/**\n\t * Nested exception used to wrap an {@link InvalidEndpointRequestException} and\n\t * provide a {@link HttpStatus#BAD_REQUEST} status.\n\t */\n\tprivate static class InvalidEndpointBadRequestException extends ResponseStatusException {\n\n\t\tInvalidEndpointBadRequestException(InvalidEndpointRequestException cause) {\n\t\t\tsuper(HttpStatus.BAD_REQUEST, cause.getReason(), cause);\n\t\t}\n\n\t}\n\n\tprivate static final class ServletSecurityContext implements SecurityContext {\n\n\t\tprivate final HttpServletRequest request;\n\n\t\tprivate ServletSecurityContext(HttpServletRequest request) {\n\t\t\tthis.request = request;\n\t\t}\n\n\t\t@Override\n\t\tpublic Principal getPrincipal() {\n\t\t\treturn this.request.getUserPrincipal();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isUserInRole(String role) {\n\t\t\treturn this.request.isUserInRole(role);\n\t\t}\n\n\t}\n\n\tstatic class AbstractWebMvcEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.reflectiveRegistrar.registerRuntimeHints(hints, OperationHandler.class, CatchAllHandler.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/endpoint/web/AdditionalHealthEndpointPathsWebMvcHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebOperation;\nimport org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;\nimport org.springframework.boot.health.actuate.endpoint.AdditionalHealthEndpointPath;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroup;\nimport org.springframework.web.servlet.HandlerMapping;\n\n/**\n * A custom {@link HandlerMapping} that allows health groups to be mapped to an additional\n * path.\n *\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class AdditionalHealthEndpointPathsWebMvcHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {\n\n\tprivate final @Nullable ExposableWebEndpoint healthEndpoint;\n\n\tprivate final Set<HealthEndpointGroup> groups;\n\n\tpublic AdditionalHealthEndpointPathsWebMvcHandlerMapping(@Nullable ExposableWebEndpoint healthEndpoint,\n\t\t\tSet<HealthEndpointGroup> groups) {\n\t\tsuper(new EndpointMapping(\"\"), asList(healthEndpoint), new EndpointMediaTypes(), false);\n\t\tthis.healthEndpoint = healthEndpoint;\n\t\tthis.groups = groups;\n\t}\n\n\tprivate static Collection<ExposableWebEndpoint> asList(@Nullable ExposableWebEndpoint healthEndpoint) {\n\t\treturn (healthEndpoint != null) ? Collections.singletonList(healthEndpoint) : Collections.emptyList();\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tif (this.healthEndpoint == null) {\n\t\t\treturn;\n\t\t}\n\t\tfor (WebOperation operation : this.healthEndpoint.getOperations()) {\n\t\t\tWebOperationRequestPredicate predicate = operation.getRequestPredicate();\n\t\t\tString matchAllRemainingPathSegmentsVariable = predicate.getMatchAllRemainingPathSegmentsVariable();\n\t\t\tif (matchAllRemainingPathSegmentsVariable != null) {\n\t\t\t\tfor (HealthEndpointGroup group : this.groups) {\n\t\t\t\t\tAdditionalHealthEndpointPath additionalPath = group.getAdditionalPath();\n\t\t\t\t\tif (additionalPath != null) {\n\t\t\t\t\t\tregisterMapping(this.healthEndpoint, predicate, operation, additionalPath.getValue());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn (request, response) -> null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/endpoint/web/ControllerEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.servlet.HandlerMapping;\nimport org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.util.pattern.PathPattern;\nimport org.springframework.web.util.pattern.PathPatternParser;\n\n/**\n * {@link HandlerMapping} that exposes\n * {@link org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint @ControllerEndpoint}\n * and\n * {@link org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint @RestControllerEndpoint}\n * annotated endpoints over Spring MVC.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.5\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ControllerEndpointHandlerMapping extends RequestMappingHandlerMapping {\n\n\tprivate static final Set<RequestMethod> READ_ONLY_ACCESS_REQUEST_METHODS = EnumSet.of(RequestMethod.GET,\n\t\t\tRequestMethod.HEAD);\n\n\tprivate final EndpointMapping endpointMapping;\n\n\tprivate final @Nullable CorsConfiguration corsConfiguration;\n\n\tprivate final Map<Object, ExposableControllerEndpoint> handlers;\n\n\tprivate final EndpointAccessResolver accessResolver;\n\n\t/**\n\t * Create a new {@link ControllerEndpointHandlerMapping} instance providing mappings\n\t * for the specified endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t */\n\tpublic ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableControllerEndpoint> endpoints, @Nullable CorsConfiguration corsConfiguration) {\n\t\tthis(endpointMapping, endpoints, corsConfiguration, (endpointId, defaultAccess) -> Access.NONE);\n\t}\n\n\t/**\n\t * Create a new {@link ControllerEndpointHandlerMapping} instance providing mappings\n\t * for the specified endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t * @param endpointAccessResolver resolver for endpoint access\n\t */\n\tpublic ControllerEndpointHandlerMapping(EndpointMapping endpointMapping,\n\t\t\tCollection<ExposableControllerEndpoint> endpoints, @Nullable CorsConfiguration corsConfiguration,\n\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\tAssert.notNull(endpointMapping, \"'endpointMapping' must not be null\");\n\t\tAssert.notNull(endpoints, \"'endpoints' must not be null\");\n\t\tthis.endpointMapping = endpointMapping;\n\t\tthis.handlers = getHandlers(endpoints);\n\t\tthis.corsConfiguration = corsConfiguration;\n\t\tthis.accessResolver = endpointAccessResolver;\n\t\tsetOrder(-100);\n\t}\n\n\tprivate Map<Object, ExposableControllerEndpoint> getHandlers(Collection<ExposableControllerEndpoint> endpoints) {\n\t\tMap<Object, ExposableControllerEndpoint> handlers = new LinkedHashMap<>();\n\t\tendpoints.forEach((endpoint) -> handlers.put(endpoint.getController(), endpoint));\n\t\treturn Collections.unmodifiableMap(handlers);\n\t}\n\n\t@Override\n\tprotected void initHandlerMethods() {\n\t\tthis.handlers.keySet().forEach(this::detectHandlerMethods);\n\t}\n\n\t@Override\n\tprotected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {\n\t\tExposableControllerEndpoint endpoint = this.handlers.get(handler);\n\t\tAssert.state(endpoint != null, \"'endpoint' must not be null\");\n\t\tAccess access = this.accessResolver.accessFor(endpoint.getEndpointId(), endpoint.getDefaultAccess());\n\t\tif (access == Access.NONE) {\n\t\t\treturn;\n\t\t}\n\t\tif (access == Access.READ_ONLY) {\n\t\t\tmapping = withReadOnlyAccess(access, mapping);\n\t\t\tif (CollectionUtils.isEmpty(mapping.getMethodsCondition().getMethods())) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tmapping = withEndpointMappedPatterns(endpoint, mapping);\n\t\tsuper.registerHandlerMethod(handler, method, mapping);\n\t}\n\n\tprivate RequestMappingInfo withReadOnlyAccess(Access access, RequestMappingInfo mapping) {\n\t\tSet<RequestMethod> methods = mapping.getMethodsCondition().getMethods();\n\t\tSet<RequestMethod> modifiedMethods = new HashSet<>(methods);\n\t\tif (modifiedMethods.isEmpty()) {\n\t\t\tmodifiedMethods.addAll(READ_ONLY_ACCESS_REQUEST_METHODS);\n\t\t}\n\t\telse {\n\t\t\tmodifiedMethods.retainAll(READ_ONLY_ACCESS_REQUEST_METHODS);\n\t\t}\n\t\treturn mapping.mutate().methods(modifiedMethods.toArray(new RequestMethod[0])).build();\n\t}\n\n\tprivate RequestMappingInfo withEndpointMappedPatterns(ExposableControllerEndpoint endpoint,\n\t\t\tRequestMappingInfo mapping) {\n\t\tPathPatternsRequestCondition condition = mapping.getPathPatternsCondition();\n\t\tAssert.state(condition != null, \"'condition' must not be null\");\n\t\tSet<PathPattern> patterns = condition.getPatterns();\n\t\tif (patterns.isEmpty()) {\n\t\t\tPathPatternParser parser = getPatternParser();\n\t\t\tAssert.state(parser != null, \"'parser' must not be null\");\n\t\t\tpatterns = Collections.singleton(parser.parse(\"\"));\n\t\t}\n\t\tString[] endpointMappedPatterns = patterns.stream()\n\t\t\t.map((pattern) -> getEndpointMappedPattern(endpoint, pattern))\n\t\t\t.toArray(String[]::new);\n\t\treturn mapping.mutate().paths(endpointMappedPatterns).build();\n\t}\n\n\tprivate String getEndpointMappedPattern(ExposableControllerEndpoint endpoint, PathPattern pattern) {\n\t\treturn this.endpointMapping.createSubPath(endpoint.getRootPath() + pattern);\n\t}\n\n\t@Override\n\tprotected boolean hasCorsConfigurationSource(Object handler) {\n\t\treturn this.corsConfiguration != null;\n\t}\n\n\t@Override\n\tprotected @Nullable CorsConfiguration initCorsConfiguration(Object handler, Method method,\n\t\t\tRequestMappingInfo mapping) {\n\t\treturn this.corsConfiguration;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/endpoint/web/WebMvcEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.servlet.HandlerMapping;\n\n/**\n * A custom {@link HandlerMapping} that makes web endpoints available over HTTP using\n * Spring MVC.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@ImportRuntimeHints(WebMvcEndpointHandlerMappingRuntimeHints.class)\npublic class WebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {\n\n\tprivate final EndpointLinksResolver linksResolver;\n\n\t/**\n\t * Creates a new {@code WebMvcEndpointHandlerMapping} instance that provides mappings\n\t * for the given endpoints.\n\t * @param endpointMapping the base mapping for all endpoints\n\t * @param endpoints the web endpoints\n\t * @param endpointMediaTypes media types consumed and produced by the endpoints\n\t * @param corsConfiguration the CORS configuration for the endpoints or {@code null}\n\t * @param linksResolver resolver for determining links to available endpoints\n\t * @param shouldRegisterLinksMapping whether the links endpoint should be registered\n\t */\n\tpublic WebMvcEndpointHandlerMapping(EndpointMapping endpointMapping, Collection<ExposableWebEndpoint> endpoints,\n\t\t\tEndpointMediaTypes endpointMediaTypes, @Nullable CorsConfiguration corsConfiguration,\n\t\t\tEndpointLinksResolver linksResolver, boolean shouldRegisterLinksMapping) {\n\t\tsuper(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, shouldRegisterLinksMapping);\n\t\tthis.linksResolver = linksResolver;\n\t\tsetOrder(-100);\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn new WebMvcLinksHandler();\n\t}\n\n\t/**\n\t * Handler for root endpoint providing links.\n\t */\n\tclass WebMvcLinksHandler implements LinksHandler {\n\n\t\t@Override\n\t\t@ResponseBody\n\t\t@Reflective\n\t\tpublic Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {\n\t\t\tMap<String, Link> links = WebMvcEndpointHandlerMapping.this.linksResolver\n\t\t\t\t.resolveLinks(request.getRequestURL().toString());\n\t\t\treturn OperationResponseBody.of(Collections.singletonMap(\"_links\", links));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator root web endpoint\";\n\t\t}\n\n\t}\n\n\tstatic class WebMvcEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.reflectiveRegistrar.registerRuntimeHints(hints, WebMvcLinksHandler.class);\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring MVC support for actuator endpoints.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/DispatcherServletHandlerMappings.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.ServletException;\nimport org.apache.catalina.Container;\nimport org.apache.catalina.Context;\nimport org.apache.catalina.core.StandardWrapper;\n\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.HandlerMapping;\n\n/**\n * {@code DispatcherServletHandlerMappings} provides access to a {@link DispatcherServlet\n * DispatcherServlet's} handler mappings, triggering initialization of the dispatcher\n * servlet if necessary.\n *\n * @author Andy Wilkinson\n */\nfinal class DispatcherServletHandlerMappings {\n\n\tprivate static final boolean TOMCAT_WEB_SERVER_PRESENT = ClassUtils.isPresent(\n\t\t\t\"org.springframework.boot.tomcat.TomcatWebServer\", DispatcherServletHandlerMappings.class.getClassLoader());\n\n\tprivate final String name;\n\n\tprivate final DispatcherServlet dispatcherServlet;\n\n\tprivate final WebApplicationContext applicationContext;\n\n\tDispatcherServletHandlerMappings(String name, DispatcherServlet dispatcherServlet,\n\t\t\tWebApplicationContext applicationContext) {\n\t\tthis.name = name;\n\t\tthis.dispatcherServlet = dispatcherServlet;\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\tList<HandlerMapping> getHandlerMappings() {\n\t\tList<HandlerMapping> handlerMappings = this.dispatcherServlet.getHandlerMappings();\n\t\tif (handlerMappings == null) {\n\t\t\tinitializeDispatcherServletIfPossible();\n\t\t\thandlerMappings = this.dispatcherServlet.getHandlerMappings();\n\t\t}\n\t\treturn (handlerMappings != null) ? handlerMappings : Collections.emptyList();\n\t}\n\n\tprivate void initializeDispatcherServletIfPossible() {\n\t\tif (!(this.applicationContext instanceof ServletWebServerApplicationContext webServerApplicationContext)) {\n\t\t\treturn;\n\t\t}\n\t\tWebServer webServer = webServerApplicationContext.getWebServer();\n\t\tif (TOMCAT_WEB_SERVER_PRESENT && webServer instanceof TomcatWebServer tomcatWebServer) {\n\t\t\tnew TomcatServletInitializer(tomcatWebServer).initializeServlet(this.name);\n\t\t}\n\t}\n\n\tString getName() {\n\t\treturn this.name;\n\t}\n\n\tprivate static final class TomcatServletInitializer {\n\n\t\tprivate final TomcatWebServer webServer;\n\n\t\tprivate TomcatServletInitializer(TomcatWebServer webServer) {\n\t\t\tthis.webServer = webServer;\n\t\t}\n\n\t\tvoid initializeServlet(String name) {\n\t\t\tfindContext().ifPresent((context) -> initializeServlet(context, name));\n\t\t}\n\n\t\tprivate Optional<Context> findContext() {\n\t\t\treturn Stream.of(this.webServer.getTomcat().getHost().findChildren())\n\t\t\t\t.filter(Context.class::isInstance)\n\t\t\t\t.map(Context.class::cast)\n\t\t\t\t.findFirst();\n\t\t}\n\n\t\tprivate void initializeServlet(Context context, String name) {\n\t\t\tContainer child = context.findChild(name);\n\t\t\tif (child instanceof StandardWrapper wrapper) {\n\t\t\t\ttry {\n\t\t\t\t\twrapper.deallocate(wrapper.allocate());\n\t\t\t\t}\n\t\t\t\tcatch (ServletException ex) {\n\t\t\t\t\t// Continue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/DispatcherServletMappingDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * A description of a mapping known to a {@link DispatcherServlet}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class DispatcherServletMappingDescription {\n\n\tprivate final String handler;\n\n\tprivate final String predicate;\n\n\tprivate final @Nullable DispatcherServletMappingDetails details;\n\n\tDispatcherServletMappingDescription(String predicate, String handler,\n\t\t\t@Nullable DispatcherServletMappingDetails details) {\n\t\tthis.handler = handler;\n\t\tthis.predicate = predicate;\n\t\tthis.details = details;\n\t}\n\n\tpublic String getHandler() {\n\t\treturn this.handler;\n\t}\n\n\tpublic String getPredicate() {\n\t\treturn this.predicate;\n\t}\n\n\tpublic @Nullable DispatcherServletMappingDetails getDetails() {\n\t\treturn this.details;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/DispatcherServletMappingDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * Details of a {@link DispatcherServlet} mapping.\n *\n * @author Andy Wilkinson\n * @author Xiong Tang\n * @since 4.0.0\n */\npublic class DispatcherServletMappingDetails {\n\n\tprivate @Nullable HandlerMethodDescription handlerMethod;\n\n\tprivate @Nullable HandlerFunctionDescription handlerFunction;\n\n\tprivate @Nullable RequestMappingConditionsDescription requestMappingConditions;\n\n\tpublic @Nullable HandlerMethodDescription getHandlerMethod() {\n\t\treturn this.handlerMethod;\n\t}\n\n\tvoid setHandlerMethod(@Nullable HandlerMethodDescription handlerMethod) {\n\t\tthis.handlerMethod = handlerMethod;\n\t}\n\n\tpublic @Nullable HandlerFunctionDescription getHandlerFunction() {\n\t\treturn this.handlerFunction;\n\t}\n\n\tvoid setHandlerFunction(@Nullable HandlerFunctionDescription handlerFunction) {\n\t\tthis.handlerFunction = handlerFunction;\n\t}\n\n\tpublic @Nullable RequestMappingConditionsDescription getRequestMappingConditions() {\n\t\treturn this.requestMappingConditions;\n\t}\n\n\tvoid setRequestMappingConditions(@Nullable RequestMappingConditionsDescription requestMappingConditions) {\n\t\tthis.requestMappingConditions = requestMappingConditions;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/DispatcherServletsMappingDescriptionProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.function.Function;\nimport java.util.stream.Stream;\n\nimport jakarta.servlet.Servlet;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.BindingReflectionHintsRegistrar;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.boot.actuate.web.mappings.HandlerMethodDescription;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletsMappingDescriptionProvider.DispatcherServletsMappingDescriptionProviderRuntimeHints;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.io.Resource;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.HandlerMapping;\nimport org.springframework.web.servlet.function.HandlerFunction;\nimport org.springframework.web.servlet.function.RequestPredicate;\nimport org.springframework.web.servlet.function.RouterFunction;\nimport org.springframework.web.servlet.function.RouterFunctions.Visitor;\nimport org.springframework.web.servlet.function.ServerRequest;\nimport org.springframework.web.servlet.function.support.RouterFunctionMapping;\nimport org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;\n\n/**\n * A {@link MappingDescriptionProvider} that introspects the {@link HandlerMapping\n * HandlerMappings} that are known to one or more {@link DispatcherServlet\n * DispatcherServlets}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Xiong Tang\n * @since 4.0.0\n */\n@ImportRuntimeHints(DispatcherServletsMappingDescriptionProviderRuntimeHints.class)\npublic class DispatcherServletsMappingDescriptionProvider implements MappingDescriptionProvider {\n\n\tprivate static final List<HandlerMappingDescriptionProvider<?>> descriptionProviders;\n\n\tstatic {\n\t\tList<HandlerMappingDescriptionProvider<?>> providers = new ArrayList<>();\n\t\tproviders.add(new RequestMappingInfoHandlerMappingDescriptionProvider());\n\t\tproviders.add(new UrlHandlerMappingDescriptionProvider());\n\t\tproviders.add(new IterableDelegatesHandlerMappingDescriptionProvider(new ArrayList<>(providers)));\n\t\tproviders.add(new RouterFunctionMappingDescriptionProvider());\n\t\tdescriptionProviders = Collections.unmodifiableList(providers);\n\t}\n\n\t@Override\n\tpublic String getMappingName() {\n\t\treturn \"dispatcherServlets\";\n\t}\n\n\t@Override\n\tpublic Map<String, List<DispatcherServletMappingDescription>> describeMappings(ApplicationContext context) {\n\t\tif (context instanceof WebApplicationContext webApplicationContext) {\n\t\t\treturn describeMappings(webApplicationContext);\n\t\t}\n\t\treturn Collections.emptyMap();\n\t}\n\n\tprivate Map<String, List<DispatcherServletMappingDescription>> describeMappings(WebApplicationContext context) {\n\t\tMap<String, List<DispatcherServletMappingDescription>> mappings = new HashMap<>();\n\t\tdetermineDispatcherServlets(context).forEach((name, dispatcherServlet) -> mappings.put(name,\n\t\t\t\tdescribeMappings(new DispatcherServletHandlerMappings(name, dispatcherServlet, context))));\n\t\treturn mappings;\n\t}\n\n\tprivate Map<String, DispatcherServlet> determineDispatcherServlets(WebApplicationContext context) {\n\t\tMap<String, DispatcherServlet> dispatcherServlets = new LinkedHashMap<>();\n\t\tcontext.getBeansOfType(ServletRegistrationBean.class).values().forEach((registration) -> {\n\t\t\tServlet servlet = registration.getServlet();\n\t\t\tif (servlet instanceof DispatcherServlet && !dispatcherServlets.containsValue(servlet)) {\n\t\t\t\tdispatcherServlets.put(registration.getServletName(), (DispatcherServlet) servlet);\n\t\t\t}\n\t\t});\n\t\tcontext.getBeansOfType(DispatcherServlet.class).forEach((name, dispatcherServlet) -> {\n\t\t\tif (!dispatcherServlets.containsValue(dispatcherServlet)) {\n\t\t\t\tdispatcherServlets.put(name, dispatcherServlet);\n\t\t\t}\n\t\t});\n\t\treturn dispatcherServlets;\n\t}\n\n\tprivate List<DispatcherServletMappingDescription> describeMappings(DispatcherServletHandlerMappings mappings) {\n\t\treturn mappings.getHandlerMappings().stream().flatMap(this::describe).toList();\n\t}\n\n\tprivate <T> Stream<DispatcherServletMappingDescription> describe(T handlerMapping) {\n\t\treturn describe(handlerMapping, descriptionProviders).stream();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static <T> List<DispatcherServletMappingDescription> describe(T handlerMapping,\n\t\t\tList<HandlerMappingDescriptionProvider<?>> descriptionProviders) {\n\t\tfor (HandlerMappingDescriptionProvider<?> descriptionProvider : descriptionProviders) {\n\t\t\tif (descriptionProvider.getMappingClass().isInstance(handlerMapping)) {\n\t\t\t\treturn ((HandlerMappingDescriptionProvider<T>) descriptionProvider).describe(handlerMapping);\n\t\t\t}\n\t\t}\n\t\treturn Collections.emptyList();\n\t}\n\n\tprivate interface HandlerMappingDescriptionProvider<T> {\n\n\t\tClass<T> getMappingClass();\n\n\t\tList<DispatcherServletMappingDescription> describe(T handlerMapping);\n\n\t}\n\n\tprivate static final class RequestMappingInfoHandlerMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<RequestMappingInfoHandlerMapping> {\n\n\t\t@Override\n\t\tpublic Class<RequestMappingInfoHandlerMapping> getMappingClass() {\n\t\t\treturn RequestMappingInfoHandlerMapping.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherServletMappingDescription> describe(RequestMappingInfoHandlerMapping handlerMapping) {\n\t\t\tMap<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();\n\t\t\treturn handlerMethods.entrySet().stream().map(this::describe).toList();\n\t\t}\n\n\t\tprivate DispatcherServletMappingDescription describe(Entry<RequestMappingInfo, HandlerMethod> mapping) {\n\t\t\tDispatcherServletMappingDetails mappingDetails = new DispatcherServletMappingDetails();\n\t\t\tmappingDetails.setHandlerMethod(new HandlerMethodDescription(mapping.getValue()));\n\t\t\tmappingDetails.setRequestMappingConditions(new RequestMappingConditionsDescription(mapping.getKey()));\n\t\t\treturn new DispatcherServletMappingDescription(mapping.getKey().toString(), mapping.getValue().toString(),\n\t\t\t\t\tmappingDetails);\n\t\t}\n\n\t}\n\n\tprivate static final class UrlHandlerMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<AbstractUrlHandlerMapping> {\n\n\t\t@Override\n\t\tpublic Class<AbstractUrlHandlerMapping> getMappingClass() {\n\t\t\treturn AbstractUrlHandlerMapping.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherServletMappingDescription> describe(AbstractUrlHandlerMapping handlerMapping) {\n\t\t\treturn handlerMapping.getHandlerMap().entrySet().stream().map(this::describe).toList();\n\t\t}\n\n\t\tprivate DispatcherServletMappingDescription describe(Entry<String, Object> mapping) {\n\t\t\treturn new DispatcherServletMappingDescription(mapping.getKey(), mapping.getValue().toString(), null);\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate static final class IterableDelegatesHandlerMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<Iterable> {\n\n\t\tprivate final List<HandlerMappingDescriptionProvider<?>> descriptionProviders;\n\n\t\tprivate IterableDelegatesHandlerMappingDescriptionProvider(\n\t\t\t\tList<HandlerMappingDescriptionProvider<?>> descriptionProviders) {\n\t\t\tthis.descriptionProviders = descriptionProviders;\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<Iterable> getMappingClass() {\n\t\t\treturn Iterable.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherServletMappingDescription> describe(Iterable handlerMapping) {\n\t\t\tList<DispatcherServletMappingDescription> descriptions = new ArrayList<>();\n\t\t\tfor (Object delegate : handlerMapping) {\n\t\t\t\tdescriptions\n\t\t\t\t\t.addAll(DispatcherServletsMappingDescriptionProvider.describe(delegate, this.descriptionProviders));\n\t\t\t}\n\t\t\treturn descriptions;\n\t\t}\n\n\t}\n\n\tprivate static final class RouterFunctionMappingDescriptionProvider\n\t\t\timplements HandlerMappingDescriptionProvider<RouterFunctionMapping> {\n\n\t\t@Override\n\t\tpublic Class<RouterFunctionMapping> getMappingClass() {\n\t\t\treturn RouterFunctionMapping.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic List<DispatcherServletMappingDescription> describe(RouterFunctionMapping handlerMapping) {\n\t\t\tMappingDescriptionVisitor visitor = new MappingDescriptionVisitor();\n\t\t\tRouterFunction<?> routerFunction = handlerMapping.getRouterFunction();\n\t\t\tif (routerFunction != null) {\n\t\t\t\trouterFunction.accept(visitor);\n\t\t\t}\n\t\t\treturn visitor.descriptions;\n\t\t}\n\n\t}\n\n\tprivate static final class MappingDescriptionVisitor implements Visitor {\n\n\t\tprivate final List<DispatcherServletMappingDescription> descriptions = new ArrayList<>();\n\n\t\tprivate Deque<RequestPredicate> predicates = new ArrayDeque<>();\n\n\t\t@Override\n\t\tpublic void startNested(RequestPredicate predicate) {\n\t\t\tthis.predicates.addLast(predicate);\n\t\t}\n\n\t\t@Override\n\t\tpublic void endNested(RequestPredicate predicate) {\n\t\t\tthis.predicates.removeLast();\n\t\t}\n\n\t\t@Override\n\t\tpublic void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction) {\n\t\t\tDispatcherServletMappingDetails details = new DispatcherServletMappingDetails();\n\t\t\tdetails.setHandlerFunction(new HandlerFunctionDescription(handlerFunction));\n\t\t\tRequestPredicate reduced = this.predicates.stream()\n\t\t\t\t.reduce(RequestPredicate::and)\n\t\t\t\t.map((all) -> all.and(predicate))\n\t\t\t\t.orElse(predicate);\n\t\t\tthis.descriptions\n\t\t\t\t.add(new DispatcherServletMappingDescription(reduced.toString(), handlerFunction.toString(), details));\n\t\t}\n\n\t\t@Override\n\t\tpublic void resources(Function<ServerRequest, Optional<Resource>> lookupFunction) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void attributes(Map<String, Object> attributes) {\n\t\t}\n\n\t\t@Override\n\t\tpublic void unknown(RouterFunction<?> routerFunction) {\n\n\t\t}\n\n\t}\n\n\tstatic class DispatcherServletsMappingDescriptionProviderRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\tprivate final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\tthis.bindingRegistrar.registerReflectionHints(hints.reflection(),\n\t\t\t\t\tDispatcherServletMappingDescription.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/HandlerFunctionDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport org.springframework.web.servlet.function.HandlerFunction;\n\n/**\n * Description of a {@link HandlerFunction}.\n *\n * @author Xiong Tang\n * @since 4.0.0\n */\npublic class HandlerFunctionDescription {\n\n\tprivate final String className;\n\n\tHandlerFunctionDescription(HandlerFunction<?> handlerFunction) {\n\t\tthis.className = getHandlerFunctionClassName(handlerFunction);\n\t}\n\n\tprivate static String getHandlerFunctionClassName(HandlerFunction<?> handlerFunction) {\n\t\tClass<?> functionClass = handlerFunction.getClass();\n\t\tString canonicalName = functionClass.getCanonicalName();\n\t\treturn (canonicalName != null) ? canonicalName : functionClass.getName();\n\t}\n\n\tpublic String getClassName() {\n\t\treturn this.className;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/RequestMappingConditionsDescription.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.servlet.mvc.condition.MediaTypeExpression;\nimport org.springframework.web.servlet.mvc.condition.NameValueExpression;\nimport org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;\nimport org.springframework.web.servlet.mvc.method.RequestMappingInfo;\n\n/**\n * Description of the conditions of a {@link RequestMappingInfo}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class RequestMappingConditionsDescription {\n\n\tprivate final List<MediaTypeExpressionDescription> consumes;\n\n\tprivate final List<NameValueExpressionDescription> headers;\n\n\tprivate final Set<RequestMethod> methods;\n\n\tprivate final List<NameValueExpressionDescription> params;\n\n\tprivate final Set<String> patterns;\n\n\tprivate final List<MediaTypeExpressionDescription> produces;\n\n\tRequestMappingConditionsDescription(RequestMappingInfo requestMapping) {\n\t\tthis.consumes = requestMapping.getConsumesCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(MediaTypeExpressionDescription::new)\n\t\t\t.toList();\n\t\tthis.headers = requestMapping.getHeadersCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(NameValueExpressionDescription::new)\n\t\t\t.toList();\n\t\tthis.methods = requestMapping.getMethodsCondition().getMethods();\n\t\tthis.params = requestMapping.getParamsCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(NameValueExpressionDescription::new)\n\t\t\t.toList();\n\t\tthis.patterns = extractPathPatterns(requestMapping);\n\t\tthis.produces = requestMapping.getProducesCondition()\n\t\t\t.getExpressions()\n\t\t\t.stream()\n\t\t\t.map(MediaTypeExpressionDescription::new)\n\t\t\t.toList();\n\t}\n\n\t@SuppressWarnings({ \"removal\", \"deprecation\" })\n\tprivate Set<String> extractPathPatterns(RequestMappingInfo requestMapping) {\n\t\torg.springframework.web.servlet.mvc.condition.PatternsRequestCondition patternsCondition = requestMapping\n\t\t\t.getPatternsCondition();\n\t\tif (patternsCondition != null) {\n\t\t\treturn patternsCondition.getPatterns();\n\t\t}\n\t\tPathPatternsRequestCondition condition = requestMapping.getPathPatternsCondition();\n\t\tAssert.state(condition != null, \"'condition' must not be null\");\n\t\treturn condition.getPatternValues();\n\t}\n\n\tpublic List<MediaTypeExpressionDescription> getConsumes() {\n\t\treturn this.consumes;\n\t}\n\n\tpublic List<NameValueExpressionDescription> getHeaders() {\n\t\treturn this.headers;\n\t}\n\n\tpublic Set<RequestMethod> getMethods() {\n\t\treturn this.methods;\n\t}\n\n\tpublic List<NameValueExpressionDescription> getParams() {\n\t\treturn this.params;\n\t}\n\n\tpublic Set<String> getPatterns() {\n\t\treturn this.patterns;\n\t}\n\n\tpublic List<MediaTypeExpressionDescription> getProduces() {\n\t\treturn this.produces;\n\t}\n\n\t/**\n\t * A description of a {@link MediaTypeExpression} in a request mapping condition.\n\t */\n\tpublic static class MediaTypeExpressionDescription {\n\n\t\tprivate final String mediaType;\n\n\t\tprivate final boolean negated;\n\n\t\tMediaTypeExpressionDescription(MediaTypeExpression expression) {\n\t\t\tthis.mediaType = expression.getMediaType().toString();\n\t\t\tthis.negated = expression.isNegated();\n\t\t}\n\n\t\tpublic String getMediaType() {\n\t\t\treturn this.mediaType;\n\t\t}\n\n\t\tpublic boolean isNegated() {\n\t\t\treturn this.negated;\n\t\t}\n\n\t}\n\n\t/**\n\t * A description of a {@link NameValueExpression} in a request mapping condition.\n\t */\n\tpublic static class NameValueExpressionDescription {\n\n\t\tprivate final String name;\n\n\t\tprivate final @Nullable Object value;\n\n\t\tprivate final boolean negated;\n\n\t\tNameValueExpressionDescription(NameValueExpression<?> expression) {\n\t\t\tthis.name = expression.getName();\n\t\t\tthis.value = expression.getValue();\n\t\t\tthis.negated = expression.isNegated();\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t\tpublic @Nullable Object getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tpublic boolean isNegated() {\n\t\t\treturn this.negated;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator request mappings support for Spring MVC.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/DispatcherServletAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.ServletRegistration;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Style;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.util.Assert;\nimport org.springframework.web.multipart.MultipartResolver;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for the Spring\n * {@link DispatcherServlet}. Should work for a standalone application where an embedded\n * web server is already present and also for a deployable application using\n * {@link SpringBootServletInitializer}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @since 4.0.0\n */\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(DispatcherServlet.class)\npublic final class DispatcherServletAutoConfiguration {\n\n\t/**\n\t * The bean name for a DispatcherServlet that will be mapped to the root URL \"/\".\n\t */\n\tpublic static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = \"dispatcherServlet\";\n\n\t/**\n\t * The bean name for a ServletRegistrationBean for the DispatcherServlet \"/\".\n\t */\n\tpublic static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = \"dispatcherServletRegistration\";\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(DefaultDispatcherServletCondition.class)\n\t@ConditionalOnClass(ServletRegistration.class)\n\t@EnableConfigurationProperties(WebMvcProperties.class)\n\tprotected static class DispatcherServletConfiguration {\n\n\t\t@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)\n\t\tDispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {\n\t\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet();\n\t\t\tdispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());\n\t\t\tdispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());\n\t\t\tdispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());\n\t\t\tdispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());\n\t\t\treturn dispatcherServlet;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBean(MultipartResolver.class)\n\t\t@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)\n\t\tMultipartResolver multipartResolver(MultipartResolver resolver) {\n\t\t\t// Detect if the user has created a MultipartResolver but named it incorrectly\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(DispatcherServletRegistrationCondition.class)\n\t@ConditionalOnClass(ServletRegistration.class)\n\t@EnableConfigurationProperties(WebMvcProperties.class)\n\t@Import(DispatcherServletConfiguration.class)\n\tprotected static class DispatcherServletRegistrationConfiguration {\n\n\t\t@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)\n\t\t@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)\n\t\tDispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,\n\t\t\t\tWebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {\n\t\t\tDispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,\n\t\t\t\t\twebMvcProperties.getServlet().getPath());\n\t\t\tregistration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);\n\t\t\tregistration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());\n\t\t\tmultipartConfig.ifAvailable(registration::setMultipartConfig);\n\t\t\treturn registration;\n\t\t}\n\n\t}\n\n\t@Order(Ordered.LOWEST_PRECEDENCE - 10)\n\tprivate static final class DefaultDispatcherServletCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"Default DispatcherServlet\");\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\t\tList<String> dispatchServletBeans = Arrays\n\t\t\t\t.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));\n\t\t\tif (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {\n\t\t\t\treturn ConditionOutcome\n\t\t\t\t\t.noMatch(message.found(\"dispatcher servlet bean\").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));\n\t\t\t}\n\t\t\tif (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {\n\t\t\t\treturn ConditionOutcome\n\t\t\t\t\t.noMatch(message.found(\"non dispatcher servlet bean\").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));\n\t\t\t}\n\t\t\tif (dispatchServletBeans.isEmpty()) {\n\t\t\t\treturn ConditionOutcome.match(message.didNotFind(\"dispatcher servlet beans\").atAll());\n\t\t\t}\n\t\t\treturn ConditionOutcome.match(message.found(\"dispatcher servlet bean\", \"dispatcher servlet beans\")\n\t\t\t\t.items(Style.QUOTE, dispatchServletBeans)\n\t\t\t\t.append(\"and none is named \" + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));\n\t\t}\n\n\t}\n\n\t@Order(Ordered.LOWEST_PRECEDENCE - 10)\n\tprivate static final class DispatcherServletRegistrationCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tAssert.state(beanFactory != null, \"'beanFactory' must not be null\");\n\t\t\tConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);\n\t\t\tif (!outcome.isMatch()) {\n\t\t\t\treturn outcome;\n\t\t\t}\n\t\t\treturn checkServletRegistration(beanFactory);\n\t\t}\n\n\t\tprivate ConditionOutcome checkDefaultDispatcherName(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tboolean containsDispatcherBean = beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);\n\t\t\tif (!containsDispatcherBean) {\n\t\t\t\treturn ConditionOutcome.match();\n\t\t\t}\n\t\t\tList<String> servlets = Arrays\n\t\t\t\t.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));\n\t\t\tif (!servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {\n\t\t\t\treturn ConditionOutcome.noMatch(\n\t\t\t\t\t\tstartMessage().found(\"non dispatcher servlet\").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));\n\t\t\t}\n\t\t\treturn ConditionOutcome.match();\n\t\t}\n\n\t\tprivate ConditionOutcome checkServletRegistration(ConfigurableListableBeanFactory beanFactory) {\n\t\t\tConditionMessage.Builder message = startMessage();\n\t\t\tList<String> registrations = Arrays\n\t\t\t\t.asList(beanFactory.getBeanNamesForType(ServletRegistrationBean.class, false, false));\n\t\t\tboolean containsDispatcherRegistrationBean = beanFactory\n\t\t\t\t.containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);\n\t\t\tif (registrations.isEmpty()) {\n\t\t\t\tif (containsDispatcherRegistrationBean) {\n\t\t\t\t\treturn ConditionOutcome.noMatch(message.found(\"non servlet registration bean\")\n\t\t\t\t\t\t.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));\n\t\t\t\t}\n\t\t\t\treturn ConditionOutcome.match(message.didNotFind(\"servlet registration bean\").atAll());\n\t\t\t}\n\t\t\tif (registrations.contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.found(\"servlet registration bean\")\n\t\t\t\t\t.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));\n\t\t\t}\n\t\t\tif (containsDispatcherRegistrationBean) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.found(\"non servlet registration bean\")\n\t\t\t\t\t.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));\n\t\t\t}\n\t\t\treturn ConditionOutcome.match(message.found(\"servlet registration beans\")\n\t\t\t\t.items(Style.QUOTE, registrations)\n\t\t\t\t.append(\"and none is named \" + DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));\n\t\t}\n\n\t\tprivate ConditionMessage.Builder startMessage() {\n\t\t\treturn ConditionMessage.forCondition(\"DispatcherServlet Registration\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/DispatcherServletPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * Interface that can be used by auto-configurations that need path details for the\n * {@link DispatcherServletAutoConfiguration#DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME\n * default} {@link DispatcherServlet}.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface DispatcherServletPath {\n\n\t/**\n\t * Returns the configured path of the dispatcher servlet.\n\t * @return the configured path\n\t */\n\tString getPath();\n\n\t/**\n\t * Return a form of the given path that's relative to the dispatcher servlet path.\n\t * @param path the path to make relative\n\t * @return the relative path\n\t */\n\tdefault String getRelativePath(String path) {\n\t\tString prefix = getPrefix();\n\t\tif (!path.startsWith(\"/\")) {\n\t\t\tpath = \"/\" + path;\n\t\t}\n\t\treturn prefix + path;\n\t}\n\n\t/**\n\t * Return a cleaned up version of the path that can be used as a prefix for URLs. The\n\t * resulting path will have path will not have a trailing slash.\n\t * @return the prefix\n\t * @see #getRelativePath(String)\n\t */\n\tdefault String getPrefix() {\n\t\tString result = getPath();\n\t\tint index = result.indexOf('*');\n\t\tif (index != -1) {\n\t\t\tresult = result.substring(0, index);\n\t\t}\n\t\tif (result.endsWith(\"/\")) {\n\t\t\tresult = result.substring(0, result.length() - 1);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Return a URL mapping pattern that can be used with a\n\t * {@link ServletRegistrationBean} to map the dispatcher servlet.\n\t * @return the path as a servlet URL mapping\n\t */\n\tdefault String getServletUrlMapping() {\n\t\tif (getPath().isEmpty() || getPath().equals(\"/\")) {\n\t\t\treturn \"/\";\n\t\t}\n\t\tif (getPath().contains(\"*\")) {\n\t\t\treturn getPath();\n\t\t}\n\t\tif (getPath().endsWith(\"/\")) {\n\t\t\treturn getPath() + \"*\";\n\t\t}\n\t\treturn getPath() + \"/*\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/DispatcherServletRegistrationBean.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.util.Assert;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * {@link ServletRegistrationBean} for the auto-configured {@link DispatcherServlet}. Both\n * registers the servlet and exposes {@link DispatcherServletPath} information.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic class DispatcherServletRegistrationBean extends ServletRegistrationBean<DispatcherServlet>\n\t\timplements DispatcherServletPath {\n\n\tprivate final String path;\n\n\t/**\n\t * Create a new {@link DispatcherServletRegistrationBean} instance for the given\n\t * servlet and path.\n\t * @param servlet the dispatcher servlet\n\t * @param path the dispatcher servlet path\n\t */\n\tpublic DispatcherServletRegistrationBean(DispatcherServlet servlet, String path) {\n\t\tsuper(servlet);\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tthis.path = path;\n\t\tsuper.addUrlMappings(getServletUrlMapping());\n\t}\n\n\t@Override\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\t@Override\n\tpublic void setUrlMappings(Collection<String> urlMappings) {\n\t\tthrow new UnsupportedOperationException(\"URL Mapping cannot be changed on a DispatcherServlet registration\");\n\t}\n\n\t@Override\n\tpublic void addUrlMappings(String... urlMappings) {\n\t\tthrow new UnsupportedOperationException(\"URL Mapping cannot be changed on a DispatcherServlet registration\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/JspTemplateAvailabilityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.io.File;\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.util.ClassUtils;\n\n/**\n * {@link TemplateAvailabilityProvider} that provides availability information for JSP\n * view templates.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Madhura Bhave\n * @since 4.0.0\n */\npublic class JspTemplateAvailabilityProvider implements TemplateAvailabilityProvider {\n\n\tprivate static final String WAR_SOURCE_DIRECTORY_ENVIRONMENT_VARIABLE = \"WAR_SOURCE_DIRECTORY\";\n\n\tprivate final File warSourceDirectory;\n\n\tpublic JspTemplateAvailabilityProvider() {\n\t\tthis(new File(\".\"), System::getenv);\n\t}\n\n\tJspTemplateAvailabilityProvider(File rootDirectory, Function<String, @Nullable String> systemEnvironment) {\n\t\tthis.warSourceDirectory = new File(rootDirectory, getWarSourceDirectory(systemEnvironment));\n\t}\n\n\tprivate static String getWarSourceDirectory(Function<String, @Nullable String> systemEnvironment) {\n\t\tString name = systemEnvironment.apply(WAR_SOURCE_DIRECTORY_ENVIRONMENT_VARIABLE);\n\t\treturn (name != null) ? name : \"src/main/webapp\";\n\t}\n\n\t@Override\n\tpublic boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader,\n\t\t\tResourceLoader resourceLoader) {\n\t\tif (ClassUtils.isPresent(\"org.apache.jasper.compiler.JspConfig\", classLoader)) {\n\t\t\tString resourceName = getResourceName(view, environment);\n\t\t\tif (resourceLoader.getResource(resourceName).exists()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn new File(this.warSourceDirectory, resourceName).exists();\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate String getResourceName(String view, Environment environment) {\n\t\tString prefix = environment.getProperty(\"spring.mvc.view.prefix\", WebMvcAutoConfiguration.DEFAULT_PREFIX);\n\t\tString suffix = environment.getProperty(\"spring.mvc.view.suffix\", WebMvcAutoConfiguration.DEFAULT_SUFFIX);\n\t\treturn prefix + view + suffix;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/ProblemDetailsExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;\n\n/**\n * {@code @ControllerAdvice} annotated {@link ResponseEntityExceptionHandler} that is\n * auto-configured for problem details support.\n *\n * @author Brian Clozel\n */\n@ControllerAdvice\nclass ProblemDetailsExceptionHandler extends ResponseEntityExceptionHandler {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletContext;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureOrder;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources.Chain.Strategy;\nimport org.springframework.boot.autoconfigure.web.WebResourcesRuntimeHints;\nimport org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;\nimport org.springframework.boot.autoconfigure.web.format.WebConversionService;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer;\nimport org.springframework.boot.servlet.filter.OrderedFormContentFilter;\nimport org.springframework.boot.servlet.filter.OrderedHiddenHttpMethodFilter;\nimport org.springframework.boot.servlet.filter.OrderedRequestContextFilter;\nimport org.springframework.boot.validation.autoconfigure.ValidatorAdapter;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcProperties.Apiversion;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcProperties.Apiversion.Use;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcProperties.Format;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ResourceLoaderAware;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.format.FormatterRegistry;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.http.CacheControl;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.validation.DefaultMessageCodesResolver;\nimport org.springframework.validation.MessageCodesResolver;\nimport org.springframework.validation.Validator;\nimport org.springframework.web.accept.ApiVersionDeprecationHandler;\nimport org.springframework.web.accept.ApiVersionParser;\nimport org.springframework.web.accept.ApiVersionResolver;\nimport org.springframework.web.accept.ApiVersionStrategy;\nimport org.springframework.web.accept.ContentNegotiationManager;\nimport org.springframework.web.bind.support.ConfigurableWebBindingInitializer;\nimport org.springframework.web.context.ServletContextAware;\nimport org.springframework.web.context.request.RequestContextListener;\nimport org.springframework.web.context.support.ServletContextResource;\nimport org.springframework.web.filter.FormContentFilter;\nimport org.springframework.web.filter.HiddenHttpMethodFilter;\nimport org.springframework.web.filter.RequestContextFilter;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.FlashMapManager;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.LocaleResolver;\nimport org.springframework.web.servlet.RequestToViewNameTranslator;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.ViewResolver;\nimport org.springframework.web.servlet.config.annotation.ApiVersionConfigurer;\nimport org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;\nimport org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;\nimport org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.config.annotation.PathMatchConfigurer;\nimport org.springframework.web.servlet.config.annotation.ResourceChainRegistration;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;\nimport org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;\nimport org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;\nimport org.springframework.web.servlet.i18n.FixedLocaleResolver;\nimport org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;\nimport org.springframework.web.servlet.resource.EncodedResourceResolver;\nimport org.springframework.web.servlet.resource.ResourceResolver;\nimport org.springframework.web.servlet.resource.ResourceUrlProvider;\nimport org.springframework.web.servlet.resource.VersionResourceResolver;\nimport org.springframework.web.servlet.view.BeanNameViewResolver;\nimport org.springframework.web.servlet.view.ContentNegotiatingViewResolver;\nimport org.springframework.web.servlet.view.InternalResourceViewResolver;\nimport org.springframework.web.util.UrlPathHelper;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link EnableWebMvc Web MVC}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Sébastien Deleuze\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n * @author Kristine Jetzke\n * @author Bruce Brouwer\n * @author Artsiom Yudovin\n * @author Scott Frederick\n * @since 4.0.0\n */\n@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class },\n\t\tafterName = \"org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\")\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })\n@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)\n@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)\n@ImportRuntimeHints(WebResourcesRuntimeHints.class)\npublic final class WebMvcAutoConfiguration {\n\n\t/**\n\t * The default Spring MVC view prefix.\n\t */\n\tpublic static final String DEFAULT_PREFIX = \"\";\n\n\t/**\n\t * The default Spring MVC view suffix.\n\t */\n\tpublic static final String DEFAULT_SUFFIX = \"\";\n\n\tprivate static final String SERVLET_LOCATION = \"/\";\n\n\t@Bean\n\t@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)\n\t@ConditionalOnBooleanProperty(\"spring.mvc.hiddenmethod.filter.enabled\")\n\tOrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {\n\t\treturn new OrderedHiddenHttpMethodFilter();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(FormContentFilter.class)\n\t@ConditionalOnBooleanProperty(name = \"spring.mvc.formcontent.filter.enabled\", matchIfMissing = true)\n\tOrderedFormContentFilter formContentFilter() {\n\t\treturn new OrderedFormContentFilter();\n\t}\n\n\t// Defined as a nested config to ensure WebMvcConfigurer is not read when not\n\t// on the classpath\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(EnableWebMvcConfiguration.class)\n\t@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })\n\t@Order(0)\n\tstatic class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {\n\n\t\tprivate static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);\n\n\t\tprivate final Resources resourceProperties;\n\n\t\tprivate final WebMvcProperties mvcProperties;\n\n\t\tprivate final ListableBeanFactory beanFactory;\n\n\t\tprivate final ObjectProvider<DispatcherServletPath> dispatcherServletPath;\n\n\t\tprivate final ObjectProvider<ServletRegistrationBean<?>> servletRegistrations;\n\n\t\tprivate final ObjectProvider<ServerHttpMessageConvertersCustomizer> httpMessageConvertersCustomizerProvider;\n\n\t\tprivate final @Nullable ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;\n\n\t\tprivate @Nullable ServletContext servletContext;\n\n\t\tprivate final ObjectProvider<ApiVersionResolver> apiVersionResolvers;\n\n\t\tprivate final ObjectProvider<ApiVersionParser<?>> apiVersionParser;\n\n\t\tprivate final ObjectProvider<ApiVersionDeprecationHandler> apiVersionDeprecationHandler;\n\n\t\tWebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,\n\t\t\t\tListableBeanFactory beanFactory,\n\t\t\t\tObjectProvider<ServerHttpMessageConvertersCustomizer> httpMessageConvertersCustomizerProvider,\n\t\t\t\tObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,\n\t\t\t\tObjectProvider<DispatcherServletPath> dispatcherServletPath,\n\t\t\t\tObjectProvider<ServletRegistrationBean<?>> servletRegistrations,\n\t\t\t\tObjectProvider<ApiVersionResolver> apiVersionResolvers,\n\t\t\t\tObjectProvider<ApiVersionParser<?>> apiVersionParser,\n\t\t\t\tObjectProvider<ApiVersionDeprecationHandler> apiVersionDeprecationHandler) {\n\t\t\tthis.resourceProperties = webProperties.getResources();\n\t\t\tthis.mvcProperties = mvcProperties;\n\t\t\tthis.beanFactory = beanFactory;\n\t\t\tthis.httpMessageConvertersCustomizerProvider = httpMessageConvertersCustomizerProvider;\n\t\t\tthis.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();\n\t\t\tthis.dispatcherServletPath = dispatcherServletPath;\n\t\t\tthis.servletRegistrations = servletRegistrations;\n\t\t\tthis.apiVersionResolvers = apiVersionResolvers;\n\t\t\tthis.apiVersionParser = apiVersionParser;\n\t\t\tthis.apiVersionDeprecationHandler = apiVersionDeprecationHandler;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setServletContext(ServletContext servletContext) {\n\t\t\tthis.servletContext = servletContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureMessageConverters(ServerBuilder builder) {\n\t\t\tthis.httpMessageConvertersCustomizerProvider.orderedStream()\n\t\t\t\t.forEach((customizer) -> customizer.customize(builder));\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureAsyncSupport(AsyncSupportConfigurer configurer) {\n\t\t\tif (this.beanFactory.containsBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)) {\n\t\t\t\tObject taskExecutor = this.beanFactory\n\t\t\t\t\t.getBean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);\n\t\t\t\tif (taskExecutor instanceof AsyncTaskExecutor asyncTaskExecutor) {\n\t\t\t\t\tconfigurer.setTaskExecutor(asyncTaskExecutor);\n\t\t\t\t}\n\t\t\t}\n\t\t\tDuration timeout = this.mvcProperties.getAsync().getRequestTimeout();\n\t\t\tif (timeout != null) {\n\t\t\t\tconfigurer.setDefaultTimeout(timeout.toMillis());\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\t@SuppressWarnings(\"removal\")\n\t\tpublic void configurePathMatch(PathMatchConfigurer configurer) {\n\t\t\tif (this.mvcProperties.getPathmatch()\n\t\t\t\t.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.ANT_PATH_MATCHER) {\n\t\t\t\tconfigurer.setPathMatcher(new AntPathMatcher());\n\t\t\t\tthis.dispatcherServletPath.ifAvailable((dispatcherPath) -> {\n\t\t\t\t\tString servletUrlMapping = dispatcherPath.getServletUrlMapping();\n\t\t\t\t\tif (servletUrlMapping.equals(\"/\") && singleDispatcherServlet()) {\n\t\t\t\t\t\tUrlPathHelper urlPathHelper = new UrlPathHelper();\n\t\t\t\t\t\turlPathHelper.setAlwaysUseFullPath(true);\n\t\t\t\t\t\tconfigurer.setUrlPathHelper(urlPathHelper);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tprivate boolean singleDispatcherServlet() {\n\t\t\treturn this.servletRegistrations.stream()\n\t\t\t\t.map(ServletRegistrationBean::getServlet)\n\t\t\t\t.filter(DispatcherServlet.class::isInstance)\n\t\t\t\t.count() == 1;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {\n\t\t\tWebMvcProperties.Contentnegotiation contentnegotiation = this.mvcProperties.getContentnegotiation();\n\t\t\tconfigurer.favorParameter(contentnegotiation.isFavorParameter());\n\t\t\tif (contentnegotiation.getParameterName() != null) {\n\t\t\t\tconfigurer.parameterName(contentnegotiation.getParameterName());\n\t\t\t}\n\t\t\tMap<String, MediaType> mediaTypes = contentnegotiation.getMediaTypes();\n\t\t\tmediaTypes.forEach(configurer::mediaType);\n\t\t\tList<MediaType> defaultContentTypes = contentnegotiation.getDefaultContentTypes();\n\t\t\tif (!CollectionUtils.isEmpty(defaultContentTypes)) {\n\t\t\t\tconfigurer.defaultContentType(defaultContentTypes.toArray(new MediaType[0]));\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tInternalResourceViewResolver defaultViewResolver() {\n\t\t\tInternalResourceViewResolver resolver = new InternalResourceViewResolver();\n\t\t\tresolver.setPrefix(this.mvcProperties.getView().getPrefix());\n\t\t\tresolver.setSuffix(this.mvcProperties.getView().getSuffix());\n\t\t\treturn resolver;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBean(View.class)\n\t\t@ConditionalOnMissingBean\n\t\tBeanNameViewResolver beanNameViewResolver() {\n\t\t\tBeanNameViewResolver resolver = new BeanNameViewResolver();\n\t\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);\n\t\t\treturn resolver;\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBean(ViewResolver.class)\n\t\t@ConditionalOnMissingBean(name = \"viewResolver\", value = ContentNegotiatingViewResolver.class)\n\t\tContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {\n\t\t\tContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();\n\t\t\tresolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));\n\t\t\t// ContentNegotiatingViewResolver uses all the other view resolvers to locate\n\t\t\t// a view so it should have a high precedence\n\t\t\tresolver.setOrder(Ordered.HIGHEST_PRECEDENCE);\n\t\t\treturn resolver;\n\t\t}\n\n\t\t@Override\n\t\tpublic @Nullable MessageCodesResolver getMessageCodesResolver() {\n\t\t\tif (this.mvcProperties.getMessageCodesResolverFormat() != null) {\n\t\t\t\tDefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();\n\t\t\t\tresolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());\n\t\t\t\treturn resolver;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tpublic void addFormatters(FormatterRegistry registry) {\n\t\t\tApplicationConversionService.addBeans(registry, this.beanFactory);\n\t\t}\n\n\t\t@Override\n\t\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n\t\t\tif (!this.resourceProperties.isAddMappings()) {\n\t\t\t\tlogger.debug(\"Default resource handling disabled\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\taddResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(),\n\t\t\t\t\t\"classpath:/META-INF/resources/webjars/\");\n\t\t\taddResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {\n\t\t\t\tregistration.addResourceLocations(this.resourceProperties.getStaticLocations());\n\t\t\t\tif (this.servletContext != null) {\n\t\t\t\t\tServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);\n\t\t\t\t\tregistration.addResourceLocations(resource);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tprivate void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {\n\t\t\taddResourceHandler(registry, pattern, (registration) -> registration.addResourceLocations(locations));\n\t\t}\n\n\t\tprivate void addResourceHandler(ResourceHandlerRegistry registry, String pattern,\n\t\t\t\tConsumer<ResourceHandlerRegistration> customizer) {\n\t\t\tif (registry.hasMappingForPattern(pattern)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tResourceHandlerRegistration registration = registry.addResourceHandler(pattern);\n\t\t\tcustomizer.accept(registration);\n\t\t\tInteger cachePeriod = getSeconds(this.resourceProperties.getCache().getPeriod());\n\t\t\tif (cachePeriod != null) {\n\t\t\t\tregistration.setCachePeriod(cachePeriod);\n\t\t\t}\n\t\t\tCacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();\n\t\t\tif (cacheControl != null) {\n\t\t\t\tregistration.setCacheControl(cacheControl);\n\t\t\t}\n\t\t\tregistration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());\n\t\t\tcustomizeResourceHandlerRegistration(registration);\n\t\t}\n\n\t\t@Contract(\"!null -> !null\")\n\t\tprivate @Nullable Integer getSeconds(@Nullable Duration cachePeriod) {\n\t\t\treturn (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;\n\t\t}\n\n\t\tprivate void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {\n\t\t\tif (this.resourceHandlerRegistrationCustomizer != null) {\n\t\t\t\tthis.resourceHandlerRegistrationCustomizer.customize(registration);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureApiVersioning(ApiVersionConfigurer configurer) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tApiversion properties = this.mvcProperties.getApiversion();\n\t\t\tmap.from(properties::getRequired).to(configurer::setVersionRequired);\n\t\t\tmap.from(properties::getDefaultVersion).to(configurer::setDefaultVersion);\n\t\t\tmap.from(properties::getSupported).to((supported) -> supported.forEach(configurer::addSupportedVersions));\n\t\t\tmap.from(properties::getDetectSupported).to(configurer::detectSupportedVersions);\n\t\t\tconfigureApiVersioningUse(configurer, properties.getUse());\n\t\t\tthis.apiVersionResolvers.orderedStream().forEach(configurer::useVersionResolver);\n\t\t\tthis.apiVersionParser.ifAvailable(configurer::setVersionParser);\n\t\t\tthis.apiVersionDeprecationHandler.ifAvailable(configurer::setDeprecationHandler);\n\t\t}\n\n\t\tprivate void configureApiVersioningUse(ApiVersionConfigurer configurer, Use use) {\n\t\t\tPropertyMapper map = PropertyMapper.get();\n\t\t\tmap.from(use::getHeader).whenHasText().to(configurer::useRequestHeader);\n\t\t\tmap.from(use::getQueryParameter).whenHasText().to(configurer::useQueryParam);\n\t\t\tmap.from(use::getPathSegment).to(configurer::usePathSegment);\n\t\t\tuse.getMediaTypeParameter().forEach(configurer::useMediaTypeParameter);\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class })\n\t\t@ConditionalOnMissingFilterBean\n\t\tstatic RequestContextFilter requestContextFilter() {\n\t\t\treturn new OrderedRequestContextFilter();\n\t\t}\n\n\t}\n\n\t/**\n\t * Configuration equivalent to {@code @EnableWebMvc}.\n\t */\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(WebProperties.class)\n\t@ImportRuntimeHints(MvcValidatorRuntimeHints.class)\n\tstatic class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {\n\n\t\tprivate final Resources resourceProperties;\n\n\t\tprivate final WebMvcProperties mvcProperties;\n\n\t\tprivate final WebProperties webProperties;\n\n\t\tprivate final ListableBeanFactory beanFactory;\n\n\t\tprivate final @Nullable WebMvcRegistrations mvcRegistrations;\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ResourceLoader resourceLoader;\n\n\t\tEnableWebMvcConfiguration(WebMvcProperties mvcProperties, WebProperties webProperties,\n\t\t\t\tObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,\n\t\t\t\tObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,\n\t\t\t\tListableBeanFactory beanFactory) {\n\t\t\tthis.resourceProperties = webProperties.getResources();\n\t\t\tthis.mvcProperties = mvcProperties;\n\t\t\tthis.webProperties = webProperties;\n\t\t\tthis.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();\n\t\t\tthis.beanFactory = beanFactory;\n\t\t}\n\n\t\t@Override\n\t\tprotected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {\n\t\t\tif (this.mvcRegistrations != null) {\n\t\t\t\tRequestMappingHandlerAdapter adapter = this.mvcRegistrations.getRequestMappingHandlerAdapter();\n\t\t\t\tif (adapter != null) {\n\t\t\t\t\treturn adapter;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.createRequestMappingHandlerAdapter();\n\t\t}\n\n\t\t@Bean\n\t\tWelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,\n\t\t\t\tFormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {\n\t\t\treturn createWelcomePageHandlerMapping(applicationContext, mvcConversionService, mvcResourceUrlProvider,\n\t\t\t\t\tWelcomePageHandlerMapping::new);\n\t\t}\n\n\t\t@Bean\n\t\tWelcomePageNotAcceptableHandlerMapping welcomePageNotAcceptableHandlerMapping(\n\t\t\t\tApplicationContext applicationContext, FormattingConversionService mvcConversionService,\n\t\t\t\tResourceUrlProvider mvcResourceUrlProvider) {\n\t\t\treturn createWelcomePageHandlerMapping(applicationContext, mvcConversionService, mvcResourceUrlProvider,\n\t\t\t\t\tWelcomePageNotAcceptableHandlerMapping::new);\n\t\t}\n\n\t\tprivate <T extends AbstractUrlHandlerMapping> T createWelcomePageHandlerMapping(\n\t\t\t\tApplicationContext applicationContext, FormattingConversionService mvcConversionService,\n\t\t\t\tResourceUrlProvider mvcResourceUrlProvider, WelcomePageHandlerMappingFactory<T> factory) {\n\t\t\tTemplateAvailabilityProviders templateAvailabilityProviders = new TemplateAvailabilityProviders(\n\t\t\t\t\tapplicationContext);\n\t\t\tString staticPathPattern = this.mvcProperties.getStaticPathPattern();\n\t\t\tT handlerMapping = factory.create(templateAvailabilityProviders, applicationContext, getIndexHtmlResource(),\n\t\t\t\t\tstaticPathPattern);\n\t\t\thandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));\n\t\t\thandlerMapping.setCorsConfigurations(getCorsConfigurations());\n\t\t\treturn handlerMapping;\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)\n\t\tpublic LocaleResolver localeResolver() {\n\t\t\tLocale locale = this.webProperties.getLocale();\n\t\t\tif (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) {\n\t\t\t\tAssert.state(locale != null, \"'locale' must not be null\");\n\t\t\t\treturn new FixedLocaleResolver(locale);\n\t\t\t}\n\t\t\tAcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();\n\t\t\tlocaleResolver.setDefaultLocale(locale);\n\t\t\treturn localeResolver;\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)\n\t\tpublic FlashMapManager flashMapManager() {\n\t\t\treturn super.flashMapManager();\n\t\t}\n\n\t\t@Override\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(name = DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME)\n\t\tpublic RequestToViewNameTranslator viewNameTranslator() {\n\t\t\treturn super.viewNameTranslator();\n\t\t}\n\n\t\tprivate @Nullable Resource getIndexHtmlResource() {\n\t\t\tfor (String location : this.resourceProperties.getStaticLocations()) {\n\t\t\t\tResource indexHtml = getIndexHtmlResource(location);\n\t\t\t\tif (indexHtml != null) {\n\t\t\t\t\treturn indexHtml;\n\t\t\t\t}\n\t\t\t}\n\t\t\tServletContext servletContext = getServletContext();\n\t\t\tif (servletContext != null) {\n\t\t\t\treturn getIndexHtmlResource(new ServletContextResource(servletContext, SERVLET_LOCATION));\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tprivate @Nullable Resource getIndexHtmlResource(String location) {\n\t\t\treturn getIndexHtmlResource(this.resourceLoader.getResource(location));\n\t\t}\n\n\t\tprivate @Nullable Resource getIndexHtmlResource(Resource location) {\n\t\t\ttry {\n\t\t\t\tResource resource = location.createRelative(\"index.html\");\n\t\t\t\tif (resource.exists() && (resource.getURL() != null)) {\n\t\t\t\t\treturn resource;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t@Bean\n\t\t@Override\n\t\tpublic FormattingConversionService mvcConversionService() {\n\t\t\tFormat format = this.mvcProperties.getFormat();\n\t\t\tWebConversionService conversionService = new WebConversionService(\n\t\t\t\t\tnew DateTimeFormatters().dateFormat(format.getDate())\n\t\t\t\t\t\t.timeFormat(format.getTime())\n\t\t\t\t\t\t.dateTimeFormat(format.getDateTime()));\n\t\t\taddFormatters(conversionService);\n\t\t\treturn conversionService;\n\t\t}\n\n\t\t@Bean\n\t\t@Override\n\t\tpublic Validator mvcValidator() {\n\t\t\tif (!ClassUtils.isPresent(\"jakarta.validation.Validator\", getClass().getClassLoader())\n\t\t\t\t\t|| !ClassUtils.isPresent(\"org.springframework.boot.validation.autoconfigure.ValidatorAdapter\",\n\t\t\t\t\t\t\tgetClass().getClassLoader())) {\n\t\t\t\treturn super.mvcValidator();\n\t\t\t}\n\t\t\tApplicationContext applicationContext = getApplicationContext();\n\t\t\tAssert.state(applicationContext != null, \"'applicationContext' must not be null\");\n\t\t\treturn ValidatorAdapter.get(applicationContext, getValidator());\n\t\t}\n\n\t\t@Override\n\t\tprotected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {\n\t\t\tif (this.mvcRegistrations != null) {\n\t\t\t\tRequestMappingHandlerMapping mapping = this.mvcRegistrations.getRequestMappingHandlerMapping();\n\t\t\t\tif (mapping != null) {\n\t\t\t\t\treturn mapping;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.createRequestMappingHandlerMapping();\n\t\t}\n\n\t\t@Override\n\t\tprotected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer(\n\t\t\t\tFormattingConversionService mvcConversionService, Validator mvcValidator) {\n\t\t\ttry {\n\t\t\t\treturn this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn super.getConfigurableWebBindingInitializer(mvcConversionService, mvcValidator);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tprotected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {\n\t\t\tif (this.mvcRegistrations != null) {\n\t\t\t\tExceptionHandlerExceptionResolver resolver = this.mvcRegistrations\n\t\t\t\t\t.getExceptionHandlerExceptionResolver();\n\t\t\t\tif (resolver != null) {\n\t\t\t\t\treturn resolver;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn super.createExceptionHandlerExceptionResolver();\n\t\t}\n\n\t\t@Override\n\t\tprotected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n\t\t\tsuper.extendHandlerExceptionResolvers(exceptionResolvers);\n\t\t\tif (this.mvcProperties.isLogResolvedException()) {\n\t\t\t\tfor (HandlerExceptionResolver resolver : exceptionResolvers) {\n\t\t\t\t\tif (resolver instanceof AbstractHandlerExceptionResolver abstractResolver) {\n\t\t\t\t\t\tabstractResolver.setWarnLogCategory(resolver.getClass().getName());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\t\tthis.resourceLoader = resourceLoader;\n\t\t}\n\n\t\t@Override\n\t\t@ConditionalOnMissingBean(name = \"mvcApiVersionStrategy\")\n\t\tpublic @Nullable ApiVersionStrategy mvcApiVersionStrategy() {\n\t\t\treturn super.mvcApiVersionStrategy();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnEnabledResourceChain\n\tstatic class ResourceChainCustomizerConfiguration {\n\n\t\t@Bean\n\t\tResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(\n\t\t\t\tWebProperties webProperties) {\n\t\t\treturn new ResourceChainResourceHandlerRegistrationCustomizer(webProperties.getResources());\n\t\t}\n\n\t}\n\n\t@FunctionalInterface\n\tinterface WelcomePageHandlerMappingFactory<T extends AbstractUrlHandlerMapping> {\n\n\t\tT create(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext,\n\t\t\t\t@Nullable Resource indexHtmlResource, String staticPathPattern);\n\n\t}\n\n\t@FunctionalInterface\n\tinterface ResourceHandlerRegistrationCustomizer {\n\n\t\tvoid customize(ResourceHandlerRegistration registration);\n\n\t}\n\n\tstatic class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer {\n\n\t\tprivate final Resources resourceProperties;\n\n\t\tResourceChainResourceHandlerRegistrationCustomizer(Resources resourceProperties) {\n\t\t\tthis.resourceProperties = resourceProperties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ResourceHandlerRegistration registration) {\n\t\t\tResources.Chain properties = this.resourceProperties.getChain();\n\t\t\tconfigureResourceChain(properties, registration.resourceChain(properties.isCache()));\n\t\t}\n\n\t\tprivate void configureResourceChain(Resources.Chain properties, ResourceChainRegistration chain) {\n\t\t\tStrategy strategy = properties.getStrategy();\n\t\t\tif (properties.isCompressed()) {\n\t\t\t\tchain.addResolver(new EncodedResourceResolver());\n\t\t\t}\n\t\t\tif (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {\n\t\t\t\tchain.addResolver(getVersionResourceResolver(strategy));\n\t\t\t}\n\t\t}\n\n\t\tprivate ResourceResolver getVersionResourceResolver(Strategy properties) {\n\t\t\tVersionResourceResolver resolver = new VersionResourceResolver();\n\t\t\tif (properties.getFixed().isEnabled()) {\n\t\t\t\tString version = properties.getFixed().getVersion();\n\t\t\t\tString[] paths = properties.getFixed().getPaths();\n\t\t\t\tAssert.state(version != null, \"'version' must not be null\");\n\t\t\t\tresolver.addFixedVersionStrategy(version, paths);\n\t\t\t}\n\t\t\tif (properties.getContent().isEnabled()) {\n\t\t\t\tString[] paths = properties.getContent().getPaths();\n\t\t\t\tresolver.addContentVersionStrategy(paths);\n\t\t\t}\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(\"spring.mvc.problemdetails.enabled\")\n\tstatic class ProblemDetailsErrorHandlingConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(ResponseEntityExceptionHandler.class)\n\t\t@Order(0)\n\t\tProblemDetailsExceptionHandler problemDetailsExceptionHandler() {\n\t\t\treturn new ProblemDetailsExceptionHandler();\n\t\t}\n\n\t}\n\n\tstatic class MvcValidatorRuntimeHints implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {\n\t\t\thints.reflection()\n\t\t\t\t.registerType(TypeReference.of(\"org.springframework.boot.validation.autoconfigure.ValidatorAdapter\"));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\nimport jakarta.servlet.DispatcherType;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingFilterBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.server.observation.DefaultServerRequestObservationConvention;\nimport org.springframework.http.server.observation.ServerRequestObservationConvention;\nimport org.springframework.web.filter.ServerHttpObservationFilter;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for instrumentation of Spring Web\n * MVC servlet-based request mappings.\n *\n * @author Brian Clozel\n * @author Jon Schneider\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = {\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration\",\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration\",\n\t\t\"org.springframework.boot.micrometer.metrics.autoconfigure.export.simple.SimpleMetricsExportAutoConfiguration\",\n\t\t\"org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration\" })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ DispatcherServlet.class, Observation.class, ObservationProperties.class })\n@ConditionalOnBean(ObservationRegistry.class)\n@EnableConfigurationProperties(ObservationProperties.class)\npublic final class WebMvcObservationAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingFilterBean\n\tFilterRegistrationBean<ServerHttpObservationFilter> webMvcObservationFilter(ObservationRegistry registry,\n\t\t\tObjectProvider<ServerRequestObservationConvention> customConvention,\n\t\t\tObservationProperties observationProperties) {\n\t\tString name = observationProperties.getHttp().getServer().getRequests().getName();\n\t\tServerRequestObservationConvention convention = customConvention\n\t\t\t.getIfAvailable(() -> new DefaultServerRequestObservationConvention(name));\n\t\tServerHttpObservationFilter filter = new ServerHttpObservationFilter(registry, convention);\n\t\tFilterRegistrationBean<ServerHttpObservationFilter> registration = new FilterRegistrationBean<>(filter);\n\t\tregistration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);\n\t\tregistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);\n\t\treturn registration;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass({ MeterRegistry.class, MetricsProperties.class })\n\t@ConditionalOnBean(MeterRegistry.class)\n\t@EnableConfigurationProperties(MetricsProperties.class)\n\tstatic class MeterFilterConfiguration {\n\n\t\t@Bean\n\t\t@Order(0)\n\t\tMaximumAllowableTagsMeterFilter metricsHttpServerUriTagFilter(ObservationProperties observationProperties,\n\t\t\t\tMetricsProperties metricsProperties) {\n\t\t\tString meterNamePrefix = observationProperties.getHttp().getServer().getRequests().getName();\n\t\t\tint maxUriTags = metricsProperties.getWeb().getServer().getMaxUriTags();\n\t\t\treturn new MaximumAllowableTagsMeterFilter(meterNamePrefix, \"uri\", maxUriTags);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Name;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.DefaultMessageCodesResolver;\n\n/**\n * {@link ConfigurationProperties Properties} for Spring MVC.\n *\n * @author Phillip Webb\n * @author Sébastien Deleuze\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Brian Clozel\n * @author Vedran Pavic\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.mvc\")\npublic class WebMvcProperties {\n\n\t/**\n\t * Formatting strategy for message codes. For instance, 'PREFIX_ERROR_CODE'.\n\t */\n\tprivate DefaultMessageCodesResolver.@Nullable Format messageCodesResolverFormat;\n\n\tprivate final Format format = new Format();\n\n\t/**\n\t * Whether to dispatch TRACE requests to the FrameworkServlet doService method.\n\t */\n\tprivate boolean dispatchTraceRequest;\n\n\t/**\n\t * Whether to dispatch OPTIONS requests to the FrameworkServlet doService method.\n\t */\n\tprivate boolean dispatchOptionsRequest = true;\n\n\t/**\n\t * Whether to publish a ServletRequestHandledEvent at the end of each request.\n\t */\n\tprivate boolean publishRequestHandledEvents = true;\n\n\t/**\n\t * Whether logging of (potentially sensitive) request details at DEBUG and TRACE level\n\t * is allowed.\n\t */\n\tprivate boolean logRequestDetails;\n\n\t/**\n\t * Whether to enable warn logging of exceptions resolved by a\n\t * \"HandlerExceptionResolver\", except for \"DefaultHandlerExceptionResolver\".\n\t */\n\tprivate boolean logResolvedException;\n\n\t/**\n\t * Path pattern used for static resources.\n\t */\n\tprivate String staticPathPattern = \"/**\";\n\n\t/**\n\t * Path pattern used for WebJar assets.\n\t */\n\tprivate String webjarsPathPattern = \"/webjars/**\";\n\n\tprivate final Async async = new Async();\n\n\tprivate final Servlet servlet = new Servlet();\n\n\tprivate final View view = new View();\n\n\tprivate final Contentnegotiation contentnegotiation = new Contentnegotiation();\n\n\tprivate final Pathmatch pathmatch = new Pathmatch();\n\n\tprivate final Problemdetails problemdetails = new Problemdetails();\n\n\tprivate final Apiversion apiversion = new Apiversion();\n\n\tpublic DefaultMessageCodesResolver.@Nullable Format getMessageCodesResolverFormat() {\n\t\treturn this.messageCodesResolverFormat;\n\t}\n\n\tpublic void setMessageCodesResolverFormat(DefaultMessageCodesResolver.@Nullable Format messageCodesResolverFormat) {\n\t\tthis.messageCodesResolverFormat = messageCodesResolverFormat;\n\t}\n\n\tpublic Format getFormat() {\n\t\treturn this.format;\n\t}\n\n\tpublic boolean isPublishRequestHandledEvents() {\n\t\treturn this.publishRequestHandledEvents;\n\t}\n\n\tpublic void setPublishRequestHandledEvents(boolean publishRequestHandledEvents) {\n\t\tthis.publishRequestHandledEvents = publishRequestHandledEvents;\n\t}\n\n\tpublic boolean isLogRequestDetails() {\n\t\treturn this.logRequestDetails;\n\t}\n\n\tpublic void setLogRequestDetails(boolean logRequestDetails) {\n\t\tthis.logRequestDetails = logRequestDetails;\n\t}\n\n\tpublic boolean isLogResolvedException() {\n\t\treturn this.logResolvedException;\n\t}\n\n\tpublic void setLogResolvedException(boolean logResolvedException) {\n\t\tthis.logResolvedException = logResolvedException;\n\t}\n\n\tpublic boolean isDispatchOptionsRequest() {\n\t\treturn this.dispatchOptionsRequest;\n\t}\n\n\tpublic void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {\n\t\tthis.dispatchOptionsRequest = dispatchOptionsRequest;\n\t}\n\n\tpublic boolean isDispatchTraceRequest() {\n\t\treturn this.dispatchTraceRequest;\n\t}\n\n\tpublic void setDispatchTraceRequest(boolean dispatchTraceRequest) {\n\t\tthis.dispatchTraceRequest = dispatchTraceRequest;\n\t}\n\n\tpublic String getStaticPathPattern() {\n\t\treturn this.staticPathPattern;\n\t}\n\n\tpublic void setStaticPathPattern(String staticPathPattern) {\n\t\tthis.staticPathPattern = staticPathPattern;\n\t}\n\n\tpublic String getWebjarsPathPattern() {\n\t\treturn this.webjarsPathPattern;\n\t}\n\n\tpublic void setWebjarsPathPattern(String webjarsPathPattern) {\n\t\tthis.webjarsPathPattern = webjarsPathPattern;\n\t}\n\n\tpublic Async getAsync() {\n\t\treturn this.async;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic View getView() {\n\t\treturn this.view;\n\t}\n\n\tpublic Contentnegotiation getContentnegotiation() {\n\t\treturn this.contentnegotiation;\n\t}\n\n\tpublic Pathmatch getPathmatch() {\n\t\treturn this.pathmatch;\n\t}\n\n\tpublic Problemdetails getProblemdetails() {\n\t\treturn this.problemdetails;\n\t}\n\n\tpublic Apiversion getApiversion() {\n\t\treturn this.apiversion;\n\t}\n\n\tpublic static class Async {\n\n\t\t/**\n\t\t * Amount of time before asynchronous request handling times out. If this value is\n\t\t * not set, the default timeout of the underlying implementation is used.\n\t\t */\n\t\tprivate @Nullable Duration requestTimeout;\n\n\t\tpublic @Nullable Duration getRequestTimeout() {\n\t\t\treturn this.requestTimeout;\n\t\t}\n\n\t\tpublic void setRequestTimeout(@Nullable Duration requestTimeout) {\n\t\t\tthis.requestTimeout = requestTimeout;\n\t\t}\n\n\t}\n\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Path of the dispatcher servlet. Setting a custom value for this property is not\n\t\t * compatible with the PathPatternParser matching strategy.\n\t\t */\n\t\tprivate String path = \"/\";\n\n\t\t/**\n\t\t * Load on startup priority of the dispatcher servlet.\n\t\t */\n\t\tprivate int loadOnStartup = -1;\n\n\t\tpublic String getPath() {\n\t\t\treturn this.path;\n\t\t}\n\n\t\tpublic void setPath(String path) {\n\t\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\t\tAssert.isTrue(!path.contains(\"*\"), \"'path' must not contain wildcards\");\n\t\t\tthis.path = path;\n\t\t}\n\n\t\tpublic int getLoadOnStartup() {\n\t\t\treturn this.loadOnStartup;\n\t\t}\n\n\t\tpublic void setLoadOnStartup(int loadOnStartup) {\n\t\t\tthis.loadOnStartup = loadOnStartup;\n\t\t}\n\n\t\tpublic String getServletMapping() {\n\t\t\tif (this.path.isEmpty() || this.path.equals(\"/\")) {\n\t\t\t\treturn \"/\";\n\t\t\t}\n\t\t\tif (this.path.endsWith(\"/\")) {\n\t\t\t\treturn this.path + \"*\";\n\t\t\t}\n\t\t\treturn this.path + \"/*\";\n\t\t}\n\n\t\tpublic String getPath(String path) {\n\t\t\tString prefix = getServletPrefix();\n\t\t\tif (!path.startsWith(\"/\")) {\n\t\t\t\tpath = \"/\" + path;\n\t\t\t}\n\t\t\treturn prefix + path;\n\t\t}\n\n\t\tpublic String getServletPrefix() {\n\t\t\tString result = this.path;\n\t\t\tint index = result.indexOf('*');\n\t\t\tif (index != -1) {\n\t\t\t\tresult = result.substring(0, index);\n\t\t\t}\n\t\t\tif (result.endsWith(\"/\")) {\n\t\t\t\tresult = result.substring(0, result.length() - 1);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t}\n\n\tpublic static class View {\n\n\t\t/**\n\t\t * Spring MVC view prefix.\n\t\t */\n\t\tprivate @Nullable String prefix;\n\n\t\t/**\n\t\t * Spring MVC view suffix.\n\t\t */\n\t\tprivate @Nullable String suffix;\n\n\t\tpublic @Nullable String getPrefix() {\n\t\t\treturn this.prefix;\n\t\t}\n\n\t\tpublic void setPrefix(@Nullable String prefix) {\n\t\t\tthis.prefix = prefix;\n\t\t}\n\n\t\tpublic @Nullable String getSuffix() {\n\t\t\treturn this.suffix;\n\t\t}\n\n\t\tpublic void setSuffix(@Nullable String suffix) {\n\t\t\tthis.suffix = suffix;\n\t\t}\n\n\t}\n\n\tpublic static class Contentnegotiation {\n\n\t\t/**\n\t\t * Whether a request parameter (\"format\" by default) should be used to determine\n\t\t * the requested media type.\n\t\t */\n\t\tprivate boolean favorParameter;\n\n\t\t/**\n\t\t * Query parameter name to use when \"favor-parameter\" is enabled.\n\t\t */\n\t\tprivate @Nullable String parameterName;\n\n\t\t/**\n\t\t * Map file extensions to media types for content negotiation. For instance, yml\n\t\t * to text/yaml.\n\t\t */\n\t\tprivate Map<String, MediaType> mediaTypes = new LinkedHashMap<>();\n\n\t\t/**\n\t\t * List of default content types to be used when no specific content type is\n\t\t * requested.\n\t\t */\n\t\tprivate List<MediaType> defaultContentTypes = new ArrayList<>();\n\n\t\tpublic boolean isFavorParameter() {\n\t\t\treturn this.favorParameter;\n\t\t}\n\n\t\tpublic void setFavorParameter(boolean favorParameter) {\n\t\t\tthis.favorParameter = favorParameter;\n\t\t}\n\n\t\tpublic @Nullable String getParameterName() {\n\t\t\treturn this.parameterName;\n\t\t}\n\n\t\tpublic void setParameterName(@Nullable String parameterName) {\n\t\t\tthis.parameterName = parameterName;\n\t\t}\n\n\t\tpublic Map<String, MediaType> getMediaTypes() {\n\t\t\treturn this.mediaTypes;\n\t\t}\n\n\t\tpublic void setMediaTypes(Map<String, MediaType> mediaTypes) {\n\t\t\tthis.mediaTypes = mediaTypes;\n\t\t}\n\n\t\tpublic List<MediaType> getDefaultContentTypes() {\n\t\t\treturn this.defaultContentTypes;\n\t\t}\n\n\t\tpublic void setDefaultContentTypes(List<MediaType> defaultContentTypes) {\n\t\t\tthis.defaultContentTypes = defaultContentTypes;\n\t\t}\n\n\t}\n\n\tpublic static class Pathmatch {\n\n\t\t/**\n\t\t * Choice of strategy for matching request paths against registered mappings.\n\t\t */\n\t\tprivate MatchingStrategy matchingStrategy = MatchingStrategy.PATH_PATTERN_PARSER;\n\n\t\tpublic MatchingStrategy getMatchingStrategy() {\n\t\t\treturn this.matchingStrategy;\n\t\t}\n\n\t\tpublic void setMatchingStrategy(MatchingStrategy matchingStrategy) {\n\t\t\tthis.matchingStrategy = matchingStrategy;\n\t\t}\n\n\t}\n\n\tpublic static class Format {\n\n\t\t/**\n\t\t * Date format to use, for example 'dd/MM/yyyy'. Used for formatting of\n\t\t * java.util.Date and java.time.LocalDate.\n\t\t */\n\t\tprivate @Nullable String date;\n\n\t\t/**\n\t\t * Time format to use, for example 'HH:mm:ss'. Used for formatting of java.time's\n\t\t * LocalTime and OffsetTime.\n\t\t */\n\t\tprivate @Nullable String time;\n\n\t\t/**\n\t\t * Date-time format to use, for example 'yyyy-MM-dd HH:mm:ss'. Used for formatting\n\t\t * of java.time's LocalDateTime, OffsetDateTime, and ZonedDateTime.\n\t\t */\n\t\tprivate @Nullable String dateTime;\n\n\t\tpublic @Nullable String getDate() {\n\t\t\treturn this.date;\n\t\t}\n\n\t\tpublic void setDate(@Nullable String date) {\n\t\t\tthis.date = date;\n\t\t}\n\n\t\tpublic @Nullable String getTime() {\n\t\t\treturn this.time;\n\t\t}\n\n\t\tpublic void setTime(@Nullable String time) {\n\t\t\tthis.time = time;\n\t\t}\n\n\t\tpublic @Nullable String getDateTime() {\n\t\t\treturn this.dateTime;\n\t\t}\n\n\t\tpublic void setDateTime(@Nullable String dateTime) {\n\t\t\tthis.dateTime = dateTime;\n\t\t}\n\n\t}\n\n\t/**\n\t * Matching strategy options.\n\t */\n\tpublic enum MatchingStrategy {\n\n\t\t/**\n\t\t * Use the {@code AntPathMatcher} implementation.\n\t\t * @deprecated since 4.0.0 for removal in 4.2.0 in favor of\n\t\t * {@link #PATH_PATTERN_PARSER}\n\t\t */\n\t\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t\tANT_PATH_MATCHER,\n\n\t\t/**\n\t\t * Use the {@code PathPatternParser} implementation.\n\t\t */\n\t\tPATH_PATTERN_PARSER\n\n\t}\n\n\t/**\n\t * Problem Details.\n\t */\n\tpublic static class Problemdetails {\n\n\t\t/**\n\t\t * Whether RFC 9457 Problem Details support should be enabled.\n\t\t */\n\t\tprivate boolean enabled;\n\n\t\tpublic boolean isEnabled() {\n\t\t\treturn this.enabled;\n\t\t}\n\n\t\tpublic void setEnabled(boolean enabled) {\n\t\t\tthis.enabled = enabled;\n\t\t}\n\n\t}\n\n\t/**\n\t * API Version.\n\t */\n\tpublic static class Apiversion {\n\n\t\t/**\n\t\t * Whether the API version is required with each request.\n\t\t */\n\t\tprivate @Nullable Boolean required;\n\n\t\t/**\n\t\t * Default version that should be used for each request.\n\t\t */\n\t\t@Name(\"default\")\n\t\tprivate @Nullable String defaultVersion;\n\n\t\t/**\n\t\t * Supported versions.\n\t\t */\n\t\tprivate @Nullable List<String> supported;\n\n\t\t/**\n\t\t * Whether supported versions should be detected from controllers.\n\t\t */\n\t\tprivate @Nullable Boolean detectSupported;\n\n\t\t/**\n\t\t * How version details should be inserted into requests.\n\t\t */\n\t\tprivate final Use use = new Use();\n\n\t\tpublic @Nullable Boolean getRequired() {\n\t\t\treturn this.required;\n\t\t}\n\n\t\tpublic void setRequired(@Nullable Boolean required) {\n\t\t\tthis.required = required;\n\t\t}\n\n\t\tpublic @Nullable String getDefaultVersion() {\n\t\t\treturn this.defaultVersion;\n\t\t}\n\n\t\tpublic void setDefaultVersion(@Nullable String defaultVersion) {\n\t\t\tthis.defaultVersion = defaultVersion;\n\t\t}\n\n\t\tpublic @Nullable List<String> getSupported() {\n\t\t\treturn this.supported;\n\t\t}\n\n\t\tpublic void setSupported(@Nullable List<String> supported) {\n\t\t\tthis.supported = supported;\n\t\t}\n\n\t\tpublic @Nullable Boolean getDetectSupported() {\n\t\t\treturn this.detectSupported;\n\t\t}\n\n\t\tpublic void setDetectSupported(@Nullable Boolean detectSupported) {\n\t\t\tthis.detectSupported = detectSupported;\n\t\t}\n\n\t\tpublic Use getUse() {\n\t\t\treturn this.use;\n\t\t}\n\n\t\tpublic static class Use {\n\n\t\t\t/**\n\t\t\t * Use the HTTP header with the given name to obtain the version.\n\t\t\t */\n\t\t\tprivate @Nullable String header;\n\n\t\t\t/**\n\t\t\t * Use the query parameter with the given name to obtain the version.\n\t\t\t */\n\t\t\tprivate @Nullable String queryParameter;\n\n\t\t\t/**\n\t\t\t * Use the path segment at the given index to obtain the version.\n\t\t\t */\n\t\t\tprivate @Nullable Integer pathSegment;\n\n\t\t\t/**\n\t\t\t * Use the media type parameter with the given name to obtain the version.\n\t\t\t */\n\t\t\tprivate Map<MediaType, String> mediaTypeParameter = new LinkedHashMap<>();\n\n\t\t\tpublic @Nullable String getHeader() {\n\t\t\t\treturn this.header;\n\t\t\t}\n\n\t\t\tpublic void setHeader(@Nullable String header) {\n\t\t\t\tthis.header = header;\n\t\t\t}\n\n\t\t\tpublic @Nullable String getQueryParameter() {\n\t\t\t\treturn this.queryParameter;\n\t\t\t}\n\n\t\t\tpublic void setQueryParameter(@Nullable String queryParameter) {\n\t\t\t\tthis.queryParameter = queryParameter;\n\t\t\t}\n\n\t\t\tpublic @Nullable Integer getPathSegment() {\n\t\t\t\treturn this.pathSegment;\n\t\t\t}\n\n\t\t\tpublic void setPathSegment(@Nullable Integer pathSegment) {\n\t\t\t\tthis.pathSegment = pathSegment;\n\t\t\t}\n\n\t\t\tpublic Map<MediaType, String> getMediaTypeParameter() {\n\t\t\t\treturn this.mediaTypeParameter;\n\t\t\t}\n\n\t\t\tpublic void setMediaTypeParameter(Map<MediaType, String> mediaTypeParameter) {\n\t\t\t\tthis.mediaTypeParameter = mediaTypeParameter;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WebMvcRegistrations.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\n\n/**\n * Interface to register key components of the {@link WebMvcConfigurationSupport} in place\n * of the default ones provided by Spring MVC.\n * <p>\n * All custom instances are later processed by Boot and Spring MVC configurations. To\n * participate in, and if desired, override that subsequent processing,\n * {@link WebMvcConfigurer} should be used.\n * <p>\n * A single instance of this component should be registered, otherwise making it\n * impossible to choose from redundant MVC components.\n *\n * @author Brian Clozel\n * @since 4.0.0\n * @see org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration.EnableWebMvcConfiguration\n */\npublic interface WebMvcRegistrations {\n\n\t/**\n\t * Return the custom {@link RequestMappingHandlerMapping} that should be used and\n\t * processed by the MVC configuration.\n\t * @return the custom {@link RequestMappingHandlerMapping} instance\n\t */\n\tdefault @Nullable RequestMappingHandlerMapping getRequestMappingHandlerMapping() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the custom {@link RequestMappingHandlerAdapter} that should be used and\n\t * processed by the MVC configuration.\n\t * @return the custom {@link RequestMappingHandlerAdapter} instance\n\t */\n\tdefault @Nullable RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Return the custom {@link ExceptionHandlerExceptionResolver} that should be used and\n\t * processed by the MVC configuration.\n\t * @return the custom {@link ExceptionHandlerExceptionResolver} instance\n\t */\n\tdefault @Nullable ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WelcomePage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\n\n/**\n * Details for a welcome page resolved from a resource or a template.\n *\n * @author Phillip Webb\n */\nfinal class WelcomePage {\n\n\t/**\n\t * Value used for an unresolved welcome page.\n\t */\n\tstatic final WelcomePage UNRESOLVED = new WelcomePage(null, false);\n\n\tprivate final @Nullable String viewName;\n\n\tprivate final boolean templated;\n\n\tprivate WelcomePage(@Nullable String viewName, boolean templated) {\n\t\tthis.viewName = viewName;\n\t\tthis.templated = templated;\n\t}\n\n\t/**\n\t * Return the view name of the welcome page.\n\t * @return the view name\n\t */\n\t@Nullable String getViewName() {\n\t\treturn this.viewName;\n\t}\n\n\t/**\n\t * Return if the welcome page is from a template.\n\t * @return if the welcome page is templated\n\t */\n\tboolean isTemplated() {\n\t\treturn this.templated;\n\t}\n\n\t/**\n\t * Resolve the {@link WelcomePage} to use.\n\t * @param templateAvailabilityProviders the template availability providers\n\t * @param applicationContext the application context\n\t * @param indexHtmlResource the index HTML resource to use or {@code null}\n\t * @param staticPathPattern the static path pattern being used\n\t * @return a resolved {@link WelcomePage} instance or {@link #UNRESOLVED}\n\t */\n\tstatic WelcomePage resolve(TemplateAvailabilityProviders templateAvailabilityProviders,\n\t\t\tApplicationContext applicationContext, @Nullable Resource indexHtmlResource, String staticPathPattern) {\n\t\tif (indexHtmlResource != null && \"/**\".equals(staticPathPattern)) {\n\t\t\treturn new WelcomePage(\"forward:index.html\", false);\n\t\t}\n\t\tif (templateAvailabilityProviders.getProvider(\"index\", applicationContext) != null) {\n\t\t\treturn new WelcomePage(\"index\", true);\n\t\t}\n\t\treturn UNRESOLVED;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WelcomePageHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.log.LogMessage;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.InvalidMediaTypeException;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;\nimport org.springframework.web.servlet.mvc.ParameterizableViewController;\n\n/**\n * An {@link AbstractUrlHandlerMapping} for an application's HTML welcome page. Supports\n * both static and templated files. If both a static and templated index page are\n * available, the static page is preferred.\n *\n * @author Andy Wilkinson\n * @author Bruce Brouwer\n * @author Moritz Halbritter\n * @see WelcomePageNotAcceptableHandlerMapping\n */\nfinal class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {\n\n\tprivate static final Log logger = LogFactory.getLog(WelcomePageHandlerMapping.class);\n\n\tprivate static final List<MediaType> MEDIA_TYPES_ALL = Collections.singletonList(MediaType.ALL);\n\n\tWelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,\n\t\t\tApplicationContext applicationContext, @Nullable Resource indexHtmlResource, String staticPathPattern) {\n\t\tsetOrder(2);\n\t\tWelcomePage welcomePage = WelcomePage.resolve(templateAvailabilityProviders, applicationContext,\n\t\t\t\tindexHtmlResource, staticPathPattern);\n\t\tif (welcomePage != WelcomePage.UNRESOLVED) {\n\t\t\tlogger.info(LogMessage.of(() -> (!welcomePage.isTemplated()) ? \"Adding welcome page: \" + indexHtmlResource\n\t\t\t\t\t: \"Adding welcome page template: index\"));\n\t\t\tParameterizableViewController controller = new ParameterizableViewController();\n\t\t\tcontroller.setViewName(welcomePage.getViewName());\n\t\t\tsetRootHandler(controller);\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable Object getHandlerInternal(HttpServletRequest request) throws Exception {\n\t\treturn (!isHtmlTextAccepted(request)) ? null : super.getHandlerInternal(request);\n\t}\n\n\tprivate boolean isHtmlTextAccepted(HttpServletRequest request) {\n\t\tfor (MediaType mediaType : getAcceptedMediaTypes(request)) {\n\t\t\tif (mediaType.includes(MediaType.TEXT_HTML)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate List<MediaType> getAcceptedMediaTypes(HttpServletRequest request) {\n\t\tString acceptHeader = request.getHeader(HttpHeaders.ACCEPT);\n\t\tif (StringUtils.hasText(acceptHeader)) {\n\t\t\ttry {\n\t\t\t\treturn MediaType.parseMediaTypes(acceptHeader);\n\t\t\t}\n\t\t\tcatch (InvalidMediaTypeException ex) {\n\t\t\t\tlogger.warn(\"Received invalid Accept header. Assuming all media types are accepted\",\n\t\t\t\t\t\tlogger.isDebugEnabled() ? ex : null);\n\t\t\t}\n\t\t}\n\t\treturn MEDIA_TYPES_ALL;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/WelcomePageNotAcceptableHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;\nimport org.springframework.web.servlet.mvc.Controller;\n\n/**\n * An {@link AbstractUrlHandlerMapping} for an application's welcome page that was\n * ultimately not accepted.\n *\n * @author Phillip Webb\n */\nclass WelcomePageNotAcceptableHandlerMapping extends AbstractUrlHandlerMapping {\n\n\tWelcomePageNotAcceptableHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,\n\t\t\tApplicationContext applicationContext, @Nullable Resource indexHtmlResource, String staticPathPattern) {\n\t\tsetOrder(LOWEST_PRECEDENCE - 10); // Before ResourceHandlerRegistry\n\t\tWelcomePage welcomePage = WelcomePage.resolve(templateAvailabilityProviders, applicationContext,\n\t\t\t\tindexHtmlResource, staticPathPattern);\n\t\tif (welcomePage != WelcomePage.UNRESOLVED) {\n\t\t\tsetRootHandler((Controller) this::handleRequest);\n\t\t}\n\t}\n\n\tprivate @Nullable ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {\n\t\tresponse.setStatus(HttpStatus.NOT_ACCEPTABLE.value());\n\t\treturn null;\n\t}\n\n\t@Override\n\tprotected @Nullable Object getHandlerInternal(HttpServletRequest request) throws Exception {\n\t\treturn super.getHandlerInternal(request);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/endpoint/web/WebMvcHealthEndpointExtensionAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web;\n\nimport java.util.Collection;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link HealthEndpoint} web\n * extension with Spring MVC.\n *\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(HealthEndpoint.class)\n@ConditionalOnBean({ HealthEndpoint.class, WebEndpointsSupplier.class, HealthEndpointGroups.class })\n@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\npublic final class WebMvcHealthEndpointExtensionAutoConfiguration {\n\n\t@Bean\n\tAdditionalHealthEndpointPathsWebMvcHandlerMapping healthEndpointWebMvcHandlerMapping(\n\t\t\tWebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {\n\t\tExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);\n\t\treturn new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health,\n\t\t\t\tgroups.getAllWithAdditionalPath(WebServerNamespace.SERVER));\n\t}\n\n\tprivate static @Nullable ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {\n\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\treturn webEndpoints.stream()\n\t\t\t.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))\n\t\t\t.findFirst()\n\t\t\t.orElse(null);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/endpoint/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring MVC actuator web endpoint support.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/CompositeHandlerAdapter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.web.servlet.HandlerAdapter;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * Composite {@link HandlerAdapter}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass CompositeHandlerAdapter implements HandlerAdapter {\n\n\tprivate final ListableBeanFactory beanFactory;\n\n\tprivate @Nullable List<HandlerAdapter> adapters;\n\n\tCompositeHandlerAdapter(ListableBeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic boolean supports(Object handler) {\n\t\treturn getAdapter(handler).isPresent();\n\t}\n\n\t@Override\n\tpublic @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)\n\t\t\tthrows Exception {\n\t\tOptional<HandlerAdapter> adapter = getAdapter(handler);\n\t\tif (adapter.isPresent()) {\n\t\t\treturn adapter.get().handle(request, response, handler);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate Optional<HandlerAdapter> getAdapter(Object handler) {\n\t\tif (this.adapters == null) {\n\t\t\tthis.adapters = extractAdapters();\n\t\t}\n\t\treturn this.adapters.stream().filter((a) -> a.supports(handler)).findFirst();\n\t}\n\n\tprivate List<HandlerAdapter> extractAdapters() {\n\t\tList<HandlerAdapter> list = new ArrayList<>(this.beanFactory.getBeansOfType(HandlerAdapter.class).values());\n\t\tlist.remove(this);\n\t\tAnnotationAwareOrderComparator.sort(list);\n\t\treturn list;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/CompositeHandlerExceptionResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.HierarchicalBeanFactory;\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.error.DefaultErrorAttributes;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;\n\n/**\n * Composite {@link HandlerExceptionResolver}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Guirong Hu\n */\nclass CompositeHandlerExceptionResolver implements HandlerExceptionResolver {\n\n\t@Autowired\n\tprivate ListableBeanFactory beanFactory;\n\n\tprivate volatile @Nullable List<HandlerExceptionResolver> resolvers;\n\n\t@Override\n\tpublic @Nullable ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,\n\t\t\t@Nullable Object handler, Exception ex) {\n\t\tfor (HandlerExceptionResolver resolver : getResolvers()) {\n\t\t\tModelAndView resolved = resolver.resolveException(request, response, handler, ex);\n\t\t\tif (resolved != null) {\n\t\t\t\treturn resolved;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate List<HandlerExceptionResolver> getResolvers() {\n\t\tList<HandlerExceptionResolver> resolvers = this.resolvers;\n\t\tif (resolvers == null) {\n\t\t\tresolvers = new ArrayList<>();\n\t\t\tcollectResolverBeans(resolvers, this.beanFactory);\n\t\t\tresolvers.remove(this);\n\t\t\tAnnotationAwareOrderComparator.sort(resolvers);\n\t\t\tif (resolvers.isEmpty()) {\n\t\t\t\tresolvers.add(new DefaultErrorAttributes());\n\t\t\t\tresolvers.add(new DefaultHandlerExceptionResolver());\n\t\t\t}\n\t\t\tthis.resolvers = resolvers;\n\t\t}\n\t\treturn resolvers;\n\t}\n\n\tprivate void collectResolverBeans(List<HandlerExceptionResolver> resolvers, @Nullable BeanFactory beanFactory) {\n\t\tif (beanFactory instanceof ListableBeanFactory listableBeanFactory) {\n\t\t\tresolvers.addAll(listableBeanFactory.getBeansOfType(HandlerExceptionResolver.class).values());\n\t\t}\n\t\tif (beanFactory instanceof HierarchicalBeanFactory hierarchicalBeanFactory) {\n\t\t\tcollectResolverBeans(resolvers, hierarchicalBeanFactory.getParentBeanFactory());\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/CompositeHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.web.servlet.HandlerExecutionChain;\nimport org.springframework.web.servlet.HandlerMapping;\n\n/**\n * Composite {@link HandlerMapping}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass CompositeHandlerMapping implements HandlerMapping {\n\n\t@Autowired\n\tprivate ListableBeanFactory beanFactory;\n\n\tprivate @Nullable List<HandlerMapping> mappings;\n\n\t@Override\n\tpublic @Nullable HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {\n\t\tfor (HandlerMapping mapping : getMappings()) {\n\t\t\tHandlerExecutionChain handler = mapping.getHandler(request);\n\t\t\tif (handler != null) {\n\t\t\t\treturn handler;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic boolean usesPathPatterns() {\n\t\tfor (HandlerMapping mapping : getMappings()) {\n\t\t\tif (mapping.usesPathPatterns()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate List<HandlerMapping> getMappings() {\n\t\tif (this.mappings == null) {\n\t\t\tthis.mappings = extractMappings();\n\t\t}\n\t\treturn this.mappings;\n\t}\n\n\tprivate List<HandlerMapping> extractMappings() {\n\t\tList<HandlerMapping> list = new ArrayList<>(this.beanFactory.getBeansOfType(HandlerMapping.class).values());\n\t\tlist.remove(this);\n\t\tAnnotationAwareOrderComparator.sort(list);\n\t\treturn list;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ManagementErrorEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.web.ErrorProperties;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.boot.webmvc.error.ErrorController;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.Assert;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.context.request.ServletWebRequest;\n\n/**\n * {@link Controller @Controller} for handling \"/error\" path when the management servlet\n * is in a child context. The regular {@link ErrorController} should be available there\n * but because of the way the handler mappings are set up it will not be detected.\n *\n * @author Dave Syer\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@Controller\npublic class ManagementErrorEndpoint {\n\n\tprivate final ErrorAttributes errorAttributes;\n\n\tprivate final ErrorProperties errorProperties;\n\n\tpublic ManagementErrorEndpoint(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {\n\t\tAssert.notNull(errorAttributes, \"'errorAttributes' must not be null\");\n\t\tAssert.notNull(errorProperties, \"'errorProperties' must not be null\");\n\t\tthis.errorAttributes = errorAttributes;\n\t\tthis.errorProperties = errorProperties;\n\t}\n\n\t@RequestMapping(\"${spring.web.error.path:${error.path:/error}}\")\n\t@ResponseBody\n\tpublic Map<String, @Nullable Object> invoke(ServletWebRequest request) {\n\t\treturn this.errorAttributes.getErrorAttributes(request, getErrorAttributeOptions(request));\n\t}\n\n\tprivate ErrorAttributeOptions getErrorAttributeOptions(ServletWebRequest request) {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.defaults();\n\t\tif (this.errorProperties.isIncludeException()) {\n\t\t\toptions = options.including(Include.EXCEPTION);\n\t\t}\n\t\tif (includeStackTrace(request)) {\n\t\t\toptions = options.including(Include.STACK_TRACE);\n\t\t}\n\t\tif (includeMessage(request)) {\n\t\t\toptions = options.including(Include.MESSAGE);\n\t\t}\n\t\tif (includeBindingErrors(request)) {\n\t\t\toptions = options.including(Include.BINDING_ERRORS);\n\t\t}\n\t\toptions = includePath(request) ? options.including(Include.PATH) : options.excluding(Include.PATH);\n\t\treturn options;\n\t}\n\n\tprivate boolean includeStackTrace(ServletWebRequest request) {\n\t\treturn switch (this.errorProperties.getIncludeStacktrace()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getBooleanParameter(request, \"trace\");\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\tprivate boolean includeMessage(ServletWebRequest request) {\n\t\treturn switch (this.errorProperties.getIncludeMessage()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getBooleanParameter(request, \"message\");\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\tprivate boolean includeBindingErrors(ServletWebRequest request) {\n\t\treturn switch (this.errorProperties.getIncludeBindingErrors()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getBooleanParameter(request, \"errors\");\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\tprivate boolean includePath(ServletWebRequest request) {\n\t\treturn switch (this.errorProperties.getIncludePath()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getBooleanParameter(request, \"path\");\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\tprotected boolean getBooleanParameter(ServletWebRequest request, String parameterName) {\n\t\tString parameter = request.getParameter(parameterName);\n\t\tif (parameter == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn !\"false\".equalsIgnoreCase(parameter);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointChildContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.servlet.filter.OrderedRequestContextFilter;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizer;\nimport org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletRegistrationBean;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\nimport org.springframework.web.context.request.RequestContextListener;\nimport org.springframework.web.filter.RequestContextFilter;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Spring MVC\n * infrastructure when a separate management context with a web server running on a\n * different port is required.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(DispatcherServlet.class)\n@EnableWebMvc\nclass WebMvcEndpointChildContextConfiguration {\n\n\t/*\n\t * The error controller is present but not mapped as an endpoint in this context\n\t * because of the DispatcherServlet having had its HandlerMapping explicitly disabled.\n\t * So we expose the same feature but only for machine endpoints.\n\t */\n\t@Bean\n\t@ConditionalOnBean(ErrorAttributes.class)\n\tManagementErrorEndpoint errorEndpoint(ErrorAttributes errorAttributes, WebProperties webProperties) {\n\t\treturn new ManagementErrorEndpoint(errorAttributes, webProperties.getError());\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(ErrorAttributes.class)\n\tManagementErrorPageCustomizer managementErrorPageCustomizer(WebProperties webProperties) {\n\t\treturn new ManagementErrorPageCustomizer(webProperties);\n\t}\n\n\t@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)\n\tDispatcherServlet dispatcherServlet() {\n\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet();\n\t\t// Ensure the parent configuration does not leak down to us\n\t\tdispatcherServlet.setDetectAllHandlerAdapters(false);\n\t\tdispatcherServlet.setDetectAllHandlerExceptionResolvers(false);\n\t\tdispatcherServlet.setDetectAllHandlerMappings(false);\n\t\tdispatcherServlet.setDetectAllViewResolvers(false);\n\t\treturn dispatcherServlet;\n\t}\n\n\t@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)\n\tDispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {\n\t\treturn new DispatcherServletRegistrationBean(dispatcherServlet, \"/\");\n\t}\n\n\t@Bean(name = DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)\n\tCompositeHandlerMapping compositeHandlerMapping() {\n\t\treturn new CompositeHandlerMapping();\n\t}\n\n\t@Bean(name = DispatcherServlet.HANDLER_ADAPTER_BEAN_NAME)\n\tCompositeHandlerAdapter compositeHandlerAdapter(ListableBeanFactory beanFactory) {\n\t\treturn new CompositeHandlerAdapter(beanFactory);\n\t}\n\n\t@Bean(name = DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)\n\tCompositeHandlerExceptionResolver compositeHandlerExceptionResolver() {\n\t\treturn new CompositeHandlerExceptionResolver();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class })\n\tRequestContextFilter requestContextFilter() {\n\t\treturn new OrderedRequestContextFilter();\n\t}\n\n\t/**\n\t * {@link WebServerFactoryCustomizer} to add an {@link ErrorPage} so that the\n\t * {@link ManagementErrorEndpoint} can be used.\n\t */\n\tstatic class ManagementErrorPageCustomizer\n\t\t\timplements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {\n\n\t\tprivate final WebProperties properties;\n\n\t\tManagementErrorPageCustomizer(WebProperties properties) {\n\t\t\tthis.properties = properties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(ConfigurableServletWebServerFactory factory) {\n\t\t\tfactory.addErrorPages(new ErrorPage(this.properties.getError().getPath()));\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 10; // Run after ManagementWebServerFactoryCustomizer\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointManagementContextConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.ExposableEndpoint;\nimport org.springframework.boot.actuate.endpoint.OperationResponseBody;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.WebServerNamespace;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointGroups;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * {@link ManagementContextConfiguration @ManagementContextConfiguration} for Spring MVC\n * {@link Endpoint @Endpoint} concerns.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ManagementContextConfiguration(proxyBeanMethods = false)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnBean({ DispatcherServlet.class, WebEndpointsSupplier.class })\n@EnableConfigurationProperties(CorsEndpointProperties.class)\npublic class WebMvcEndpointManagementContextConfiguration {\n\n\tprivate static final List<MediaType> MEDIA_TYPES = Collections\n\t\t.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType(\"application\", \"*+json\")));\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@SuppressWarnings(\"removal\")\n\tWebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,\n\t\t\tEndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,\n\t\t\tWebEndpointProperties webEndpointProperties, Environment environment) {\n\t\tList<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();\n\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\tallEndpoints.addAll(webEndpoints);\n\t\tallEndpoints.addAll(servletEndpointsSupplier.getEndpoints());\n\t\tallEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());\n\t\tString basePath = webEndpointProperties.getBasePath();\n\t\tEndpointMapping endpointMapping = new EndpointMapping(basePath);\n\t\tboolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);\n\t\treturn new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,\n\t\t\t\tcorsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),\n\t\t\t\tshouldRegisterLinksMapping);\n\t}\n\n\tprivate boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,\n\t\t\tString basePath) {\n\t\treturn webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)\n\t\t\t\t|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@SuppressWarnings(\"removal\")\n\t@Deprecated(since = \"3.3.5\", forRemoval = true)\n\torg.springframework.boot.webmvc.actuate.endpoint.web.ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,\n\t\t\tCorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties,\n\t\t\tEndpointAccessResolver endpointAccessResolver) {\n\t\tEndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());\n\t\treturn new org.springframework.boot.webmvc.actuate.endpoint.web.ControllerEndpointHandlerMapping(\n\t\t\t\tendpointMapping, controllerEndpointsSupplier.getEndpoints(), corsProperties.toCorsConfiguration(),\n\t\t\t\tendpointAccessResolver);\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\torg.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar servletEndpointRegistrar(\n\t\t\tWebEndpointProperties properties,\n\t\t\torg.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,\n\t\t\tDispatcherServletPath dispatcherServletPath, EndpointAccessResolver endpointAccessResolver) {\n\t\treturn new org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar(\n\t\t\t\tdispatcherServletPath.getRelativePath(properties.getBasePath()),\n\t\t\t\tservletEndpointsSupplier.getEndpoints(), endpointAccessResolver);\n\t}\n\n\t@Bean\n\t@ConditionalOnBean(EndpointJsonMapper.class)\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\tstatic EndpointJsonMapperWebMvcConfigurer endpointJsonMapperWebMvcConfigurer(\n\t\t\tEndpointJsonMapper endpointJsonMapper) {\n\t\treturn new EndpointJsonMapperWebMvcConfigurer(endpointJsonMapper);\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"removal\")\n\t@ConditionalOnBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\tstatic EndpointJackson2ObjectMapperWebMvcConfigurer endpointJackson2ObjectMapperWebMvcConfigurer(\n\t\t\torg.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper endpointJsonMapper) {\n\t\treturn new EndpointJackson2ObjectMapperWebMvcConfigurer(endpointJsonMapper);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HealthEndpoint.class)\n\tstatic class HealthConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)\n\t\t@ConditionalOnBean(HealthEndpoint.class)\n\t\t@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)\n\t\tAdditionalHealthEndpointPathsWebMvcHandlerMapping managementHealthEndpointWebMvcHandlerMapping(\n\t\t\t\tWebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {\n\t\t\tCollection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();\n\t\t\tExposableWebEndpoint healthEndpoint = webEndpoints.stream()\n\t\t\t\t.filter(this::isHealthEndpoint)\n\t\t\t\t.findFirst()\n\t\t\t\t.orElse(null);\n\t\t\treturn new AdditionalHealthEndpointPathsWebMvcHandlerMapping(healthEndpoint,\n\t\t\t\t\tgroups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));\n\t\t}\n\n\t\tprivate boolean isHealthEndpoint(ExposableWebEndpoint endpoint) {\n\t\t\treturn endpoint.getEndpointId().equals(HealthEndpoint.ID);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link WebMvcConfigurer} to apply {@link EndpointJsonMapper} for\n\t * {@link OperationResponseBody} to {@link JacksonJsonHttpMessageConverter} instances.\n\t */\n\tstatic class EndpointJsonMapperWebMvcConfigurer implements WebMvcConfigurer {\n\n\t\tprivate final EndpointJsonMapper mapper;\n\n\t\tEndpointJsonMapperWebMvcConfigurer(EndpointJsonMapper mapper) {\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureMessageConverters(ServerBuilder builder) {\n\t\t\tbuilder.configureMessageConverters((converter) -> {\n\t\t\t\tif (converter instanceof JacksonJsonHttpMessageConverter jacksonConverter) {\n\t\t\t\t\tconfigure(jacksonConverter);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tprivate void configure(JacksonJsonHttpMessageConverter converter) {\n\t\t\tconverter.registerMappersForType(OperationResponseBody.class, (associations) -> {\n\t\t\t\tJsonMapper jsonMapper = this.mapper.get();\n\t\t\t\tMEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, jsonMapper));\n\t\t\t});\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link WebMvcConfigurer} to apply\n\t * {@link org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper}\n\t * for {@link OperationResponseBody} to\n\t * {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter}\n\t * instances.\n\t *\n\t * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3.\n\t */\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tstatic class EndpointJackson2ObjectMapperWebMvcConfigurer implements WebMvcConfigurer {\n\n\t\tprivate final org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper mapper;\n\n\t\tEndpointJackson2ObjectMapperWebMvcConfigurer(\n\t\t\t\torg.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper mapper) {\n\t\t\tthis.mapper = mapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureMessageConverters(ServerBuilder builder) {\n\t\t\tbuilder.configureMessageConverters((converter) -> {\n\t\t\t\tif (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter jacksonConverter) {\n\t\t\t\t\tconfigure(jacksonConverter);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tprivate void configure(org.springframework.http.converter.json.MappingJackson2HttpMessageConverter converter) {\n\t\t\tconverter.registerObjectMappersForType(OperationResponseBody.class, (associations) -> {\n\t\t\t\tcom.fasterxml.jackson.databind.ObjectMapper jsonMapper = this.mapper.get();\n\t\t\t\tMEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, jsonMapper));\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/mappings/WebMvcMappingsAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web.mappings;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;\nimport org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletsMappingDescriptionProvider;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to describe Web MVC\n * {@link MappingDescriptionProvider mappings}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@AutoConfiguration(after = DispatcherServletAutoConfiguration.class)\n@ConditionalOnClass({ ConditionalOnAvailableEndpoint.class, DispatcherServlet.class, MappingsEndpoint.class })\n@ConditionalOnAvailableEndpoint(MappingsEndpoint.class)\n@ConditionalOnBean(DispatcherServlet.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\npublic final class WebMvcMappingsAutoConfiguration {\n\n\t@Bean\n\tDispatcherServletsMappingDescriptionProvider dispatcherServletMappingDescriptionProvider() {\n\t\treturn new DispatcherServletsMappingDescriptionProvider();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/mappings/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Actuator request mappings auto-configuration for Spring MVC.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web.mappings;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring MVC-based actuator infrastructure.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/AbstractErrorController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.RequestDispatcher;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.boot.webmvc.error.ErrorController;\nimport org.springframework.core.annotation.AnnotationAwareOrderComparator;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.Assert;\nimport org.springframework.web.context.request.ServletWebRequest;\nimport org.springframework.web.context.request.WebRequest;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * Abstract base class for error {@link Controller @Controller} implementations.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 4.0.0\n * @see ErrorAttributes\n */\npublic abstract class AbstractErrorController implements ErrorController {\n\n\tprivate final ErrorAttributes errorAttributes;\n\n\tprivate final List<ErrorViewResolver> errorViewResolvers;\n\n\tpublic AbstractErrorController(ErrorAttributes errorAttributes) {\n\t\tthis(errorAttributes, null);\n\t}\n\n\tpublic AbstractErrorController(ErrorAttributes errorAttributes,\n\t\t\t@Nullable List<ErrorViewResolver> errorViewResolvers) {\n\t\tAssert.notNull(errorAttributes, \"'errorAttributes' must not be null\");\n\t\tthis.errorAttributes = errorAttributes;\n\t\tthis.errorViewResolvers = sortErrorViewResolvers(errorViewResolvers);\n\t}\n\n\tprivate List<ErrorViewResolver> sortErrorViewResolvers(@Nullable List<ErrorViewResolver> resolvers) {\n\t\tList<ErrorViewResolver> sorted = new ArrayList<>();\n\t\tif (resolvers != null) {\n\t\t\tsorted.addAll(resolvers);\n\t\t\tAnnotationAwareOrderComparator.sortIfNecessary(sorted);\n\t\t}\n\t\treturn sorted;\n\t}\n\n\tprotected Map<String, @Nullable Object> getErrorAttributes(HttpServletRequest request,\n\t\t\tErrorAttributeOptions options) {\n\t\tWebRequest webRequest = new ServletWebRequest(request);\n\t\treturn this.errorAttributes.getErrorAttributes(webRequest, options);\n\t}\n\n\t/**\n\t * Returns whether the trace parameter is set.\n\t * @param request the request\n\t * @return whether the trace parameter is set\n\t */\n\tprotected boolean getTraceParameter(HttpServletRequest request) {\n\t\treturn getBooleanParameter(request, \"trace\");\n\t}\n\n\t/**\n\t * Returns whether the message parameter is set.\n\t * @param request the request\n\t * @return whether the message parameter is set\n\t */\n\tprotected boolean getMessageParameter(HttpServletRequest request) {\n\t\treturn getBooleanParameter(request, \"message\");\n\t}\n\n\t/**\n\t * Returns whether the errors parameter is set.\n\t * @param request the request\n\t * @return whether the errors parameter is set\n\t */\n\tprotected boolean getErrorsParameter(HttpServletRequest request) {\n\t\treturn getBooleanParameter(request, \"errors\");\n\t}\n\n\t/**\n\t * Returns whether the path parameter is set.\n\t * @param request the request\n\t * @return whether the path parameter is set\n\t */\n\tprotected boolean getPathParameter(HttpServletRequest request) {\n\t\treturn getBooleanParameter(request, \"path\");\n\t}\n\n\tprotected boolean getBooleanParameter(HttpServletRequest request, String parameterName) {\n\t\tString parameter = request.getParameter(parameterName);\n\t\tif (parameter == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn !\"false\".equalsIgnoreCase(parameter);\n\t}\n\n\tprotected HttpStatus getStatus(HttpServletRequest request) {\n\t\tInteger statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);\n\t\tif (statusCode == null) {\n\t\t\treturn HttpStatus.INTERNAL_SERVER_ERROR;\n\t\t}\n\t\ttry {\n\t\t\treturn HttpStatus.valueOf(statusCode);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\treturn HttpStatus.INTERNAL_SERVER_ERROR;\n\t\t}\n\t}\n\n\t/**\n\t * Resolve any specific error views. By default this method delegates to\n\t * {@link ErrorViewResolver ErrorViewResolvers}.\n\t * @param request the request\n\t * @param response the response\n\t * @param status the HTTP status\n\t * @param model the suggested model\n\t * @return a specific {@link ModelAndView} or {@code null} if the default should be\n\t * used\n\t */\n\tprotected @Nullable ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response,\n\t\t\tHttpStatus status, Map<String, Object> model) {\n\t\tfor (ErrorViewResolver resolver : this.errorViewResolvers) {\n\t\t\tModelAndView modelAndView = resolver.resolveErrorView(request, status, model);\n\t\t\tif (modelAndView != null) {\n\t\t\t\treturn modelAndView;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.web.ErrorProperties;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.boot.web.error.ErrorPageRegistrar;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.Assert;\nimport org.springframework.web.HttpMediaTypeNotAcceptableException;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * Basic global error {@link Controller @Controller}, rendering {@link ErrorAttributes}.\n * More specific errors can be handled either using Spring MVC abstractions (e.g.\n * {@code @ExceptionHandler}) or by\n * {@link ErrorPageRegistrar#registerErrorPages(org.springframework.boot.web.error.ErrorPageRegistry)\n * registering error pages}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Michael Stummvoll\n * @author Stephane Nicoll\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @since 4.0.0\n * @see ErrorAttributes\n * @see ErrorProperties\n */\n@Controller\n@RequestMapping(\"${spring.web.error.path:${error.path:/error}}\")\npublic class BasicErrorController extends AbstractErrorController {\n\n\tprivate final ErrorProperties errorProperties;\n\n\t/**\n\t * Create a new {@link BasicErrorController} instance.\n\t * @param errorAttributes the error attributes\n\t * @param errorProperties configuration properties\n\t */\n\tpublic BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {\n\t\tthis(errorAttributes, errorProperties, Collections.emptyList());\n\t}\n\n\t/**\n\t * Create a new {@link BasicErrorController} instance.\n\t * @param errorAttributes the error attributes\n\t * @param errorProperties configuration properties\n\t * @param errorViewResolvers error view resolvers\n\t */\n\tpublic BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties,\n\t\t\tList<ErrorViewResolver> errorViewResolvers) {\n\t\tsuper(errorAttributes, errorViewResolvers);\n\t\tAssert.notNull(errorProperties, \"'errorProperties' must not be null\");\n\t\tthis.errorProperties = errorProperties;\n\t}\n\n\t@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)\n\tpublic ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {\n\t\tHttpStatus status = getStatus(request);\n\t\tMap<String, Object> model = Collections\n\t\t\t.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));\n\t\tresponse.setStatus(status.value());\n\t\tModelAndView modelAndView = resolveErrorView(request, response, status, model);\n\t\treturn (modelAndView != null) ? modelAndView : new ModelAndView(\"error\", model);\n\t}\n\n\t@RequestMapping\n\tpublic ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {\n\t\tHttpStatus status = getStatus(request);\n\t\tif (status == HttpStatus.NO_CONTENT) {\n\t\t\treturn new ResponseEntity<>(status);\n\t\t}\n\t\tMap<String, @Nullable Object> body = getErrorAttributes(request,\n\t\t\t\tgetErrorAttributeOptions(request, MediaType.ALL));\n\t\treturn new ResponseEntity<>(body, status);\n\t}\n\n\t@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)\n\tpublic ResponseEntity<String> mediaTypeNotAcceptable(HttpServletRequest request) {\n\t\tHttpStatus status = getStatus(request);\n\t\treturn ResponseEntity.status(status).build();\n\t}\n\n\tprotected ErrorAttributeOptions getErrorAttributeOptions(HttpServletRequest request, MediaType mediaType) {\n\t\tErrorAttributeOptions options = ErrorAttributeOptions.defaults();\n\t\tif (this.errorProperties.isIncludeException()) {\n\t\t\toptions = options.including(Include.EXCEPTION);\n\t\t}\n\t\tif (isIncludeStackTrace(request, mediaType)) {\n\t\t\toptions = options.including(Include.STACK_TRACE);\n\t\t}\n\t\tif (isIncludeMessage(request, mediaType)) {\n\t\t\toptions = options.including(Include.MESSAGE);\n\t\t}\n\t\tif (isIncludeBindingErrors(request, mediaType)) {\n\t\t\toptions = options.including(Include.BINDING_ERRORS);\n\t\t}\n\t\toptions = isIncludePath(request, mediaType) ? options.including(Include.PATH) : options.excluding(Include.PATH);\n\t\treturn options;\n\t}\n\n\t/**\n\t * Determine if the stacktrace attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the stacktrace attribute should be included\n\t */\n\tprotected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {\n\t\treturn switch (getErrorProperties().getIncludeStacktrace()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getTraceParameter(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Determine if the message attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the message attribute should be included\n\t */\n\tprotected boolean isIncludeMessage(HttpServletRequest request, MediaType produces) {\n\t\treturn switch (getErrorProperties().getIncludeMessage()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getMessageParameter(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Determine if the errors attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the errors attribute should be included\n\t */\n\tprotected boolean isIncludeBindingErrors(HttpServletRequest request, MediaType produces) {\n\t\treturn switch (getErrorProperties().getIncludeBindingErrors()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getErrorsParameter(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Determine if the path attribute should be included.\n\t * @param request the source request\n\t * @param produces the media type produced (or {@code MediaType.ALL})\n\t * @return if the path attribute should be included\n\t */\n\tprotected boolean isIncludePath(HttpServletRequest request, MediaType produces) {\n\t\treturn switch (getErrorProperties().getIncludePath()) {\n\t\t\tcase ALWAYS -> true;\n\t\t\tcase ON_PARAM -> getPathParameter(request);\n\t\t\tcase NEVER -> false;\n\t\t};\n\t}\n\n\t/**\n\t * Provide access to the error properties.\n\t * @return the error properties\n\t */\n\tprotected ErrorProperties getErrorProperties() {\n\t\treturn this.errorProperties;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/DefaultErrorViewResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.util.Collections;\nimport java.util.EnumMap;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.HttpStatus.Series;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.View;\n\n/**\n * Default {@link ErrorViewResolver} implementation that attempts to resolve error views\n * using well known conventions. Will search for templates and static assets under\n * {@code '/error'} using the {@link HttpStatus status code} and the\n * {@link HttpStatus#series() status series}.\n * <p>\n * For example, an {@code HTTP 404} will search (in the specific order):\n * <ul>\n * <li>{@code '/<templates>/error/404.<ext>'}</li>\n * <li>{@code '/<static>/error/404.html'}</li>\n * <li>{@code '/<templates>/error/4xx.<ext>'}</li>\n * <li>{@code '/<static>/error/4xx.html'}</li>\n * </ul>\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {\n\n\tprivate static final Map<Series, String> SERIES_VIEWS;\n\n\tstatic {\n\t\tMap<Series, String> views = new EnumMap<>(Series.class);\n\t\tviews.put(Series.CLIENT_ERROR, \"4xx\");\n\t\tviews.put(Series.SERVER_ERROR, \"5xx\");\n\t\tSERIES_VIEWS = Collections.unmodifiableMap(views);\n\t}\n\n\tprivate final ApplicationContext applicationContext;\n\n\tprivate final Resources resources;\n\n\tprivate final TemplateAvailabilityProviders templateAvailabilityProviders;\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Create a new {@link DefaultErrorViewResolver} instance.\n\t * @param applicationContext the source application context\n\t * @param resources resource properties\n\t */\n\tpublic DefaultErrorViewResolver(ApplicationContext applicationContext, Resources resources) {\n\t\tAssert.notNull(applicationContext, \"'applicationContext' must not be null\");\n\t\tAssert.notNull(resources, \"'resources' must not be null\");\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.resources = resources;\n\t\tthis.templateAvailabilityProviders = new TemplateAvailabilityProviders(applicationContext);\n\t}\n\n\tDefaultErrorViewResolver(ApplicationContext applicationContext, Resources resourceProperties,\n\t\t\tTemplateAvailabilityProviders templateAvailabilityProviders) {\n\t\tAssert.notNull(applicationContext, \"ApplicationContext must not be null\");\n\t\tAssert.notNull(resourceProperties, \"Resources must not be null\");\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.resources = resourceProperties;\n\t\tthis.templateAvailabilityProviders = templateAvailabilityProviders;\n\t}\n\n\t@Override\n\tpublic @Nullable ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,\n\t\t\tMap<String, Object> model) {\n\t\tModelAndView modelAndView = resolve(String.valueOf(status.value()), model);\n\t\tif (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {\n\t\t\tmodelAndView = resolve(SERIES_VIEWS.get(status.series()), model);\n\t\t}\n\t\treturn modelAndView;\n\t}\n\n\tprivate @Nullable ModelAndView resolve(String viewName, Map<String, Object> model) {\n\t\tString errorViewName = \"error/\" + viewName;\n\t\tTemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,\n\t\t\t\tthis.applicationContext);\n\t\tif (provider != null) {\n\t\t\treturn new ModelAndView(errorViewName, model);\n\t\t}\n\t\treturn resolveResource(errorViewName, model);\n\t}\n\n\tprivate @Nullable ModelAndView resolveResource(String viewName, Map<String, Object> model) {\n\t\tfor (String location : this.resources.getStaticLocations()) {\n\t\t\ttry {\n\t\t\t\tResource resource = this.applicationContext.getResource(location);\n\t\t\t\tresource = resource.createRelative(viewName + \".html\");\n\t\t\t\tif (resource.exists()) {\n\t\t\t\t\treturn new ModelAndView(new HtmlResourceView(resource), model);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t/**\n\t * {@link View} backed by an HTML resource.\n\t */\n\tprivate static class HtmlResourceView implements View {\n\n\t\tprivate final Resource resource;\n\n\t\tHtmlResourceView(Resource resource) {\n\t\t\tthis.resource = resource;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getContentType() {\n\t\t\treturn MediaType.TEXT_HTML_VALUE;\n\t\t}\n\n\t\t@Override\n\t\tpublic void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)\n\t\t\t\tthrows Exception {\n\t\t\tresponse.setContentType(getContentType());\n\t\t\tFileCopyUtils.copy(this.resource.getInputStream(), response.getOutputStream());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/ErrorMvcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\n\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.aop.framework.autoproxy.AutoProxyUtils;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.config.BeanFactoryPostProcessor;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.condition.SearchStrategy;\nimport org.springframework.boot.autoconfigure.condition.SpringBootCondition;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.error.ErrorPageRegistrar;\nimport org.springframework.boot.web.error.ErrorPageRegistry;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;\nimport org.springframework.boot.webmvc.error.DefaultErrorAttributes;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.boot.webmvc.error.ErrorController;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ConditionContext;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.type.AnnotatedTypeMetadata;\nimport org.springframework.http.MediaType;\nimport org.springframework.lang.Contract;\nimport org.springframework.util.Assert;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.view.BeanNameViewResolver;\nimport org.springframework.web.util.HtmlUtils;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} to render errors through an MVC\n * error controller.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @author Scott Frederick\n * @since 4.0.0\n */\n// Load before the main WebMvcAutoConfiguration so that the error View is available\n@AutoConfiguration(before = WebMvcAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })\n@EnableConfigurationProperties({ WebProperties.class, WebMvcProperties.class })\npublic final class ErrorMvcAutoConfiguration {\n\n\tprivate final WebProperties webProperties;\n\n\tErrorMvcAutoConfiguration(WebProperties webProperties) {\n\t\tthis.webProperties = webProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)\n\tDefaultErrorAttributes errorAttributes() {\n\t\treturn new DefaultErrorAttributes();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)\n\tBasicErrorController basicErrorController(ErrorAttributes errorAttributes,\n\t\t\tObjectProvider<ErrorViewResolver> errorViewResolvers) {\n\t\treturn new BasicErrorController(errorAttributes, this.webProperties.getError(),\n\t\t\t\terrorViewResolvers.orderedStream().toList());\n\t}\n\n\t@Bean\n\tErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {\n\t\treturn new ErrorPageCustomizer(this.webProperties, dispatcherServletPath);\n\t}\n\n\t@Bean\n\tstatic PreserveErrorControllerTargetClassPostProcessor preserveErrorControllerTargetClassPostProcessor() {\n\t\treturn new PreserveErrorControllerTargetClassPostProcessor();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DefaultErrorViewResolverConfiguration {\n\n\t\tprivate final ApplicationContext applicationContext;\n\n\t\tprivate final Resources resources;\n\n\t\tDefaultErrorViewResolverConfiguration(ApplicationContext applicationContext, WebProperties webProperties) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t\tthis.resources = webProperties.getResources();\n\t\t}\n\n\t\t@Bean\n\t\t@ConditionalOnBean(DispatcherServlet.class)\n\t\t@ConditionalOnMissingBean(ErrorViewResolver.class)\n\t\tDefaultErrorViewResolver conventionErrorViewResolver() {\n\t\t\treturn new DefaultErrorViewResolver(this.applicationContext, this.resources);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnBooleanProperty(name = \"spring.web.error.whitelabel.enabled\", matchIfMissing = true)\n\t@Conditional(ErrorTemplateMissingCondition.class)\n\tprotected static class WhitelabelErrorViewConfiguration {\n\n\t\tprivate final StaticView defaultErrorView = new StaticView();\n\n\t\t@Bean(name = \"error\")\n\t\t@ConditionalOnMissingBean(name = \"error\")\n\t\tView defaultErrorView() {\n\t\t\treturn this.defaultErrorView;\n\t\t}\n\n\t\t// If the user adds @EnableWebMvc then the bean name view resolver from\n\t\t// WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.\n\t\t@Bean\n\t\t@ConditionalOnMissingBean\n\t\tBeanNameViewResolver beanNameViewResolver() {\n\t\t\tBeanNameViewResolver resolver = new BeanNameViewResolver();\n\t\t\tresolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);\n\t\t\treturn resolver;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link SpringBootCondition} that matches when no error template view is detected.\n\t */\n\tprivate static final class ErrorTemplateMissingCondition extends SpringBootCondition {\n\n\t\t@Override\n\t\tpublic ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {\n\t\t\tConditionMessage.Builder message = ConditionMessage.forCondition(\"ErrorTemplate Missing\");\n\t\t\tClassLoader classLoader = context.getClassLoader();\n\t\t\tAssert.state(classLoader != null, \"'classLoader' must not be null\");\n\t\t\tTemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(classLoader);\n\t\t\tTemplateAvailabilityProvider provider = providers.getProvider(\"error\", context.getEnvironment(),\n\t\t\t\t\tclassLoader, context.getResourceLoader());\n\t\t\tif (provider != null) {\n\t\t\t\treturn ConditionOutcome.noMatch(message.foundExactly(\"template from \" + provider));\n\t\t\t}\n\t\t\treturn ConditionOutcome.match(message.didNotFind(\"error template view\").atAll());\n\t\t}\n\n\t}\n\n\t/**\n\t * Simple {@link View} implementation that writes a default HTML error page.\n\t */\n\tprivate static final class StaticView implements View {\n\n\t\tprivate static final MediaType TEXT_HTML_UTF8 = new MediaType(\"text\", \"html\", StandardCharsets.UTF_8);\n\n\t\tprivate static final Log logger = LogFactory.getLog(StaticView.class);\n\n\t\t@Override\n\t\tpublic void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)\n\t\t\t\tthrows Exception {\n\t\t\tAssert.state(model != null, \"'model' must not be null\");\n\t\t\tif (response.isCommitted()) {\n\t\t\t\tString message = getMessage(model);\n\t\t\t\tlogger.error(message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresponse.setContentType(TEXT_HTML_UTF8.toString());\n\t\t\tStringBuilder builder = new StringBuilder();\n\t\t\tObject timestamp = model.get(\"timestamp\");\n\t\t\tObject message = model.get(\"message\");\n\t\t\tObject trace = model.get(\"trace\");\n\t\t\tif (response.getContentType() == null) {\n\t\t\t\tresponse.setContentType(getContentType());\n\t\t\t}\n\t\t\tbuilder.append(\"<html><body><h1>Whitelabel Error Page</h1>\")\n\t\t\t\t.append(\"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>\")\n\t\t\t\t.append(\"<div id='created'>\")\n\t\t\t\t.append(timestamp)\n\t\t\t\t.append(\"</div>\")\n\t\t\t\t.append(\"<div>There was an unexpected error (type=\")\n\t\t\t\t.append(htmlEscape(model.get(\"error\")))\n\t\t\t\t.append(\", status=\")\n\t\t\t\t.append(htmlEscape(model.get(\"status\")))\n\t\t\t\t.append(\").</div>\");\n\t\t\tif (message != null) {\n\t\t\t\tbuilder.append(\"<div>\").append(htmlEscape(message)).append(\"</div>\");\n\t\t\t}\n\t\t\tif (trace != null) {\n\t\t\t\tbuilder.append(\"<div style='white-space:pre-wrap;'>\").append(htmlEscape(trace)).append(\"</div>\");\n\t\t\t}\n\t\t\tbuilder.append(\"</body></html>\");\n\t\t\tresponse.getWriter().append(builder.toString());\n\t\t}\n\n\t\t@Contract(\"!null -> !null\")\n\t\tprivate @Nullable String htmlEscape(@Nullable Object input) {\n\t\t\treturn (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;\n\t\t}\n\n\t\tprivate String getMessage(Map<String, ?> model) {\n\t\t\tObject path = model.get(\"path\");\n\t\t\tString message = \"Cannot render error page for request [\" + path + \"]\";\n\t\t\tif (model.get(\"message\") != null) {\n\t\t\t\tmessage += \" and exception [\" + model.get(\"message\") + \"]\";\n\t\t\t}\n\t\t\tmessage += \" as the response has already been committed.\";\n\t\t\tmessage += \" As a result, the response may have the wrong status code.\";\n\t\t\treturn message;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getContentType() {\n\t\t\treturn \"text/html\";\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link ErrorPageRegistrar} that configures the server's error pages.\n\t */\n\tstatic class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {\n\n\t\tprivate final WebProperties properties;\n\n\t\tprivate final DispatcherServletPath dispatcherServletPath;\n\n\t\tprotected ErrorPageCustomizer(WebProperties properties, DispatcherServletPath dispatcherServletPath) {\n\t\t\tthis.properties = properties;\n\t\t\tthis.dispatcherServletPath = dispatcherServletPath;\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerErrorPages(ErrorPageRegistry errorPageRegistry) {\n\t\t\tErrorPage errorPage = new ErrorPage(\n\t\t\t\t\tthis.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));\n\t\t\terrorPageRegistry.addErrorPages(errorPage);\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link BeanFactoryPostProcessor} to ensure that the target class of ErrorController\n\t * MVC beans are preserved when using AOP.\n\t */\n\tstatic class PreserveErrorControllerTargetClassPostProcessor implements BeanFactoryPostProcessor {\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t\tString[] errorControllerBeans = beanFactory.getBeanNamesForType(ErrorController.class, false, false);\n\t\t\tfor (String errorControllerBean : errorControllerBeans) {\n\t\t\t\ttry {\n\t\t\t\t\tbeanFactory.getBeanDefinition(errorControllerBean)\n\t\t\t\t\t\t.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);\n\t\t\t\t}\n\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/ErrorViewResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * Interface that can be implemented by beans that resolve error views.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ErrorViewResolver {\n\n\t/**\n\t * Resolve an error view for the specified details.\n\t * @param request the source request\n\t * @param status the http status of the error\n\t * @param model the suggested model to be used with the view\n\t * @return a resolved {@link ModelAndView} or {@code null}\n\t */\n\t@Nullable ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/error/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring MVC error handling.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring MVC.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/DefaultErrorAttributes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.error;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport jakarta.servlet.RequestDispatcher;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.error.Error;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.method.MethodValidationResult;\nimport org.springframework.web.context.request.RequestAttributes;\nimport org.springframework.web.context.request.WebRequest;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * Default implementation of {@link ErrorAttributes}. Provides the following attributes\n * when possible:\n * <ul>\n * <li>timestamp - The time that the errors were extracted</li>\n * <li>status - The status code</li>\n * <li>error - The error reason</li>\n * <li>exception - The class name of the root exception (if configured)</li>\n * <li>message - The exception message (if configured)</li>\n * <li>errors - Any validation errors derived from a {@link BindingResult} or\n * {@link MethodValidationResult} exception (if configured). To ensure safe serialization\n * to JSON, errors are {@link Error#wrapIfNecessary(java.util.List) wrapped if\n * necessary}</li>\n * <li>trace - The exception stack trace (if configured)</li>\n * <li>path - The URL path when the exception was raised</li>\n * </ul>\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Vedran Pavic\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Yanming Zhou\n * @author Yongjun Hong\n * @since 4.0.0\n * @see ErrorAttributes\n */\n@Order(Ordered.HIGHEST_PRECEDENCE)\npublic class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {\n\n\tprivate static final String ERROR_INTERNAL_ATTRIBUTE = DefaultErrorAttributes.class.getName() + \".ERROR\";\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n\t@Override\n\tpublic @Nullable ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,\n\t\t\t@Nullable Object handler, Exception ex) {\n\t\tstoreErrorAttributes(request, ex);\n\t\treturn null;\n\t}\n\n\tprivate void storeErrorAttributes(HttpServletRequest request, Exception ex) {\n\t\trequest.setAttribute(ERROR_INTERNAL_ATTRIBUTE, ex);\n\t}\n\n\t@Override\n\tpublic Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {\n\t\tMap<String, @Nullable Object> errorAttributes = getErrorAttributes(webRequest,\n\t\t\t\toptions.isIncluded(Include.STACK_TRACE));\n\t\toptions.retainIncluded(errorAttributes);\n\t\treturn errorAttributes;\n\t}\n\n\tprivate Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {\n\t\tMap<String, @Nullable Object> errorAttributes = new LinkedHashMap<>();\n\t\terrorAttributes.put(\"timestamp\", new Date());\n\t\taddStatus(errorAttributes, webRequest);\n\t\taddErrorDetails(errorAttributes, webRequest, includeStackTrace);\n\t\taddPath(errorAttributes, webRequest);\n\t\treturn errorAttributes;\n\t}\n\n\tprivate void addStatus(Map<String, @Nullable Object> errorAttributes, RequestAttributes requestAttributes) {\n\t\tInteger status = getAttribute(requestAttributes, RequestDispatcher.ERROR_STATUS_CODE);\n\t\tif (status == null) {\n\t\t\terrorAttributes.put(\"status\", 999);\n\t\t\terrorAttributes.put(\"error\", \"None\");\n\t\t\treturn;\n\t\t}\n\t\terrorAttributes.put(\"status\", status);\n\t\ttry {\n\t\t\terrorAttributes.put(\"error\", HttpStatus.valueOf(status).getReasonPhrase());\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\t// Unable to obtain a reason\n\t\t\terrorAttributes.put(\"error\", \"Http Status \" + status);\n\t\t}\n\t}\n\n\tprivate void addErrorDetails(Map<String, @Nullable Object> errorAttributes, WebRequest webRequest,\n\t\t\tboolean includeStackTrace) {\n\t\tThrowable error = getError(webRequest);\n\t\tif (error != null) {\n\t\t\twhile (error instanceof ServletException && error.getCause() != null) {\n\t\t\t\terror = error.getCause();\n\t\t\t}\n\t\t\terrorAttributes.put(\"exception\", error.getClass().getName());\n\t\t\tif (includeStackTrace) {\n\t\t\t\taddStackTrace(errorAttributes, error);\n\t\t\t}\n\t\t}\n\t\taddErrorMessage(errorAttributes, webRequest, error);\n\t}\n\n\tprivate void addErrorMessage(Map<String, @Nullable Object> errorAttributes, WebRequest webRequest,\n\t\t\t@Nullable Throwable error) {\n\t\tBindingResult bindingResult = extractBindingResult(error);\n\t\tif (bindingResult != null) {\n\t\t\taddMessageAndErrorsFromBindingResult(errorAttributes, bindingResult);\n\t\t\treturn;\n\t\t}\n\t\tMethodValidationResult methodValidationResult = extractMethodValidationResult(error);\n\t\tif (methodValidationResult != null) {\n\t\t\taddMessageAndErrorsFromMethodValidationResult(errorAttributes, methodValidationResult);\n\t\t\treturn;\n\t\t}\n\t\taddExceptionErrorMessage(errorAttributes, webRequest, error);\n\t}\n\n\tprivate void addMessageAndErrorsFromBindingResult(Map<String, @Nullable Object> errorAttributes,\n\t\t\tBindingResult result) {\n\t\terrorAttributes.put(\"message\", \"Validation failed for object='%s'. Error count: %s\"\n\t\t\t.formatted(result.getObjectName(), result.getAllErrors().size()));\n\t\terrorAttributes.put(\"errors\", Error.wrapIfNecessary(result.getAllErrors()));\n\t}\n\n\tprivate void addMessageAndErrorsFromMethodValidationResult(Map<String, @Nullable Object> errorAttributes,\n\t\t\tMethodValidationResult result) {\n\t\terrorAttributes.put(\"message\", \"Validation failed for method='%s'. Error count: %s\"\n\t\t\t.formatted(result.getMethod(), result.getAllErrors().size()));\n\t\terrorAttributes.put(\"errors\", Error.wrapIfNecessary(result.getAllErrors()));\n\t}\n\n\tprivate void addExceptionErrorMessage(Map<String, @Nullable Object> errorAttributes, WebRequest webRequest,\n\t\t\t@Nullable Throwable error) {\n\t\terrorAttributes.put(\"message\", getMessage(webRequest, error));\n\t}\n\n\t/**\n\t * Returns the message to be included as the value of the {@code message} error\n\t * attribute. By default the returned message is the first of the following that is\n\t * not empty:\n\t * <ol>\n\t * <li>Value of the {@link RequestDispatcher#ERROR_MESSAGE} request attribute.\n\t * <li>Message of the given {@code error}.\n\t * <li>{@code No message available}.\n\t * </ol>\n\t * @param webRequest current request\n\t * @param error current error, if any\n\t * @return message to include in the error attributes\n\t */\n\tprotected String getMessage(WebRequest webRequest, @Nullable Throwable error) {\n\t\tObject message = getAttribute(webRequest, RequestDispatcher.ERROR_MESSAGE);\n\t\tif (!ObjectUtils.isEmpty(message)) {\n\t\t\treturn message.toString();\n\t\t}\n\t\tif (error != null && StringUtils.hasLength(error.getMessage())) {\n\t\t\treturn error.getMessage();\n\t\t}\n\t\treturn \"No message available\";\n\t}\n\n\tprivate @Nullable BindingResult extractBindingResult(@Nullable Throwable error) {\n\t\tif (error instanceof BindingResult bindingResult) {\n\t\t\treturn bindingResult;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate @Nullable MethodValidationResult extractMethodValidationResult(@Nullable Throwable error) {\n\t\tif (error instanceof MethodValidationResult methodValidationResult) {\n\t\t\treturn methodValidationResult;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate void addStackTrace(Map<String, @Nullable Object> errorAttributes, Throwable error) {\n\t\tStringWriter stackTrace = new StringWriter();\n\t\terror.printStackTrace(new PrintWriter(stackTrace));\n\t\tstackTrace.flush();\n\t\terrorAttributes.put(\"trace\", stackTrace.toString());\n\t}\n\n\tprivate void addPath(Map<String, @Nullable Object> errorAttributes, RequestAttributes requestAttributes) {\n\t\tString path = getAttribute(requestAttributes, RequestDispatcher.ERROR_REQUEST_URI);\n\t\tif (path != null) {\n\t\t\terrorAttributes.put(\"path\", path);\n\t\t}\n\t}\n\n\t@Override\n\tpublic @Nullable Throwable getError(WebRequest webRequest) {\n\t\tThrowable exception = getAttribute(webRequest, ERROR_INTERNAL_ATTRIBUTE);\n\t\tif (exception == null) {\n\t\t\texception = getAttribute(webRequest, RequestDispatcher.ERROR_EXCEPTION);\n\t\t}\n\t\treturn exception;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate <T> @Nullable T getAttribute(RequestAttributes requestAttributes, String name) {\n\t\treturn (T) requestAttributes.getAttribute(name, RequestAttributes.SCOPE_REQUEST);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/ErrorAttributes.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.error;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.context.request.WebRequest;\nimport org.springframework.web.servlet.ModelAndView;\n\n/**\n * Provides access to error attributes which can be logged or presented to the user.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n * @see DefaultErrorAttributes\n */\npublic interface ErrorAttributes {\n\n\t/**\n\t * Returns a {@link Map} of the error attributes. The map can be used as the model of\n\t * an error page {@link ModelAndView}, or returned as a\n\t * {@link ResponseBody @ResponseBody}.\n\t * @param webRequest the source request\n\t * @param options options for error attribute contents\n\t * @return a map of error attributes\n\t */\n\tdefault Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {\n\t\treturn Collections.emptyMap();\n\t}\n\n\t/**\n\t * Return the underlying cause of the error or {@code null} if the error cannot be\n\t * extracted.\n\t * @param webRequest the source request\n\t * @return the {@link Exception} that caused the error or {@code null}\n\t */\n\t@Nullable Throwable getError(WebRequest webRequest);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/ErrorController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.error;\n\nimport org.springframework.stereotype.Controller;\n\n/**\n * Marker interface used to identify a {@link Controller @Controller} that should be used\n * to render errors.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n * @since 4.0.0\n */\npublic interface ErrorController {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/error/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Spring MVC error handling infrastructure.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.error;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/java/org/springframework/boot/webmvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core integration between Spring Boot and Spring Web MVC.\n */\n@NullMarked\npackage org.springframework.boot.webmvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"spring.mvc.date-format\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Date format to use, for example 'dd/MM/yyyy'.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mvc.favicon.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable resolution of favicon.ico.\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"since\": \"2.2.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mvc.formcontent.filter.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Spring's FormContentFilter.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.mvc.formcontent.putfilter.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Spring's HttpPutFormContentFilter.\",\n      \"defaultValue\": true,\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.mvc.formcontent.filter.enabled\",\n        \"since\": \"2.1.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mvc.hiddenmethod.filter.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether to enable Spring's HiddenHttpMethodFilter.\",\n      \"defaultValue\": false\n    },\n    {\n      \"name\": \"spring.mvc.ignore-default-model-on-redirect\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"Deprecated for removal in Spring MVC.\",\n        \"since\": \"3.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mvc.locale\",\n      \"type\": \"java.util.Locale\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.locale\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mvc.locale-resolver\",\n      \"type\": \"org.springframework.boot.autoconfigure.web.WebProperties$LocaleResolver\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.web.locale-resolver\",\n        \"since\": \"2.4.0\"\n      }\n    },\n    {\n      \"name\": \"spring.mvc.throw-exception-if-no-handler-found\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"reason\": \"DispatcherServlet property is deprecated for removal and should no longer need to be configured.\",\n        \"since\": \"3.2.0\"\n      }\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.mvc.converters.preferred-json-mapper\",\n      \"values\": [\n        {\n          \"value\": \"gson\"\n        },\n        {\n          \"value\": \"jackson\"\n        },\n        {\n          \"value\": \"jsonb\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.mvc.format.date\",\n      \"values\": [\n        {\n          \"value\": \"dd/MM/yyyy\",\n          \"description\": \"Example date format. Any format supported by DateTimeFormatter.parse can be used.\"\n        },\n        {\n          \"value\": \"iso\",\n          \"description\": \"ISO-8601 extended local date format.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.mvc.format.date-time\",\n      \"values\": [\n        {\n          \"value\": \"yyyy-MM-dd HH:mm:ss\",\n          \"description\": \"Example date-time format. Any format supported by DateTimeFormatter.parse can be used.\"\n        },\n        {\n          \"value\": \"iso\",\n          \"description\": \"ISO-8601 extended local date-time format.\"\n        },\n        {\n          \"value\": \"iso-offset\",\n          \"description\": \"ISO offset date-time format.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    },\n    {\n      \"name\": \"spring.mvc.format.time\",\n      \"values\": [\n        {\n          \"value\": \"HH:mm:ss\",\n          \"description\": \"Example time format. Any format supported by DateTimeFormatter.parse can be used.\"\n        },\n        {\n          \"value\": \"iso\",\n          \"description\": \"ISO-8601 extended local time format.\"\n        },\n        {\n          \"value\": \"iso-offset\",\n          \"description\": \"ISO offset time format.\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.boot.webmvc.WebMvcWebApplicationTypeDeducer$WebMvcWebApplicationTypeDeducerRuntimeHints\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports",
    "content": "org.springframework.boot.webmvc.autoconfigure.actuate.web.WebMvcEndpointManagementContextConfiguration\norg.springframework.boot.webmvc.autoconfigure.actuate.web.WebMvcEndpointChildContextConfiguration\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.WebMvcObservationAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web.WebMvcHealthEndpointExtensionAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.actuate.web.mappings.WebMvcMappingsAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.web.server.test.AutoConfigureWebServer.imports",
    "content": "org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/spring-devtools.properties",
    "content": "defaults.spring.mvc.log-resolved-exception=true\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/main/resources/META-INF/spring.factories",
    "content": "# Template Availability Providers\norg.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\\\norg.springframework.boot.webmvc.autoconfigure.JspTemplateAvailabilityProvider\n\n# WebApplicationType Deducers\norg.springframework.boot.WebApplicationType$Deducer=\\\norg.springframework.boot.webmvc.WebMvcWebApplicationTypeDeducer\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/actuate/endpoint/web/AbstractWebMvcEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link AbstractWebMvcEndpointHandlerMapping}.\n *\n * @author Moritz Halbritter\n */\nclass AbstractWebMvcEndpointHandlerMappingTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew AbstractWebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference\n\t\t\t\t.of(\"org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.OperationHandler\")))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(TypeReference\n\t\t\t\t.of(\"org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.CatchAllHandler\")))\n\t\t\t.accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/actuate/endpoint/web/ControllerEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport java.lang.reflect.Method;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ExposableControllerEndpoint;\nimport org.springframework.context.support.StaticApplicationContext;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.web.HttpRequestMethodNotSupportedException;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.method.HandlerMethod;\nimport org.springframework.web.servlet.HandlerExecutionChain;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ControllerEndpointHandlerMapping}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support\n */\n@Deprecated(since = \"3.3.5\", forRemoval = true)\n@SuppressWarnings(\"removal\")\nclass ControllerEndpointHandlerMappingTests {\n\n\tprivate final StaticApplicationContext context = new StaticApplicationContext();\n\n\t@Test\n\tvoid mappingWithNoPrefix() throws Exception {\n\t\tExposableControllerEndpoint firstEndpoint = firstEndpoint();\n\t\tExposableControllerEndpoint secondEndpoint = secondEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"\", firstEndpoint, secondEndpoint);\n\t\tHandlerExecutionChain firstHandler = mapping.getHandler(request(\"GET\", \"/first\"));\n\t\tassertThat(firstHandler).isNotNull();\n\t\tassertThat(firstHandler.getHandler()).isEqualTo(handlerOf(firstEndpoint.getController(), \"get\"));\n\t\tHandlerExecutionChain secondHandler = mapping.getHandler(request(\"POST\", \"/second\"));\n\t\tassertThat(secondHandler).isNotNull();\n\t\tassertThat(secondHandler.getHandler()).isEqualTo(handlerOf(secondEndpoint.getController(), \"save\"));\n\t\tHandlerExecutionChain thirdHandler = mapping.getHandler(request(\"GET\", \"/third\"));\n\t\tassertThat(thirdHandler).isNull();\n\t}\n\n\t@Test\n\tvoid mappingWithPrefix() throws Exception {\n\t\tExposableControllerEndpoint firstEndpoint = firstEndpoint();\n\t\tExposableControllerEndpoint secondEndpoint = secondEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"actuator\", firstEndpoint, secondEndpoint);\n\t\tHandlerExecutionChain firstHandler = mapping.getHandler(request(\"GET\", \"/actuator/first\"));\n\t\tassertThat(firstHandler).isNotNull();\n\t\tassertThat(firstHandler.getHandler()).isEqualTo(handlerOf(firstEndpoint.getController(), \"get\"));\n\t\tHandlerExecutionChain secondHandler = mapping.getHandler(request(\"POST\", \"/actuator/second\"));\n\t\tassertThat(secondHandler).isNotNull();\n\t\tassertThat(secondHandler.getHandler()).isEqualTo(handlerOf(secondEndpoint.getController(), \"save\"));\n\t\tassertThat(mapping.getHandler(request(\"GET\", \"/first\"))).isNull();\n\t\tassertThat(mapping.getHandler(request(\"GET\", \"/second\"))).isNull();\n\t}\n\n\t@Test\n\tvoid mappingNarrowedToMethod() {\n\t\tExposableControllerEndpoint first = firstEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"actuator\", first);\n\t\tassertThatExceptionOfType(HttpRequestMethodNotSupportedException.class)\n\t\t\t.isThrownBy(() -> mapping.getHandler(request(\"POST\", \"/actuator/first\")));\n\t}\n\n\t@Test\n\tvoid mappingWithNoPath() throws Exception {\n\t\tExposableControllerEndpoint pathless = pathlessEndpoint();\n\t\tControllerEndpointHandlerMapping mapping = createMapping(\"actuator\", pathless);\n\t\tHandlerExecutionChain handler = mapping.getHandler(request(\"GET\", \"/actuator/pathless\"));\n\t\tassertThat(handler).isNotNull();\n\t\tassertThat(handler.getHandler()).isEqualTo(handlerOf(pathless.getController(), \"get\"));\n\t\tassertThat(mapping.getHandler(request(\"GET\", \"/pathless\"))).isNull();\n\t\tassertThat(mapping.getHandler(request(\"GET\", \"/\"))).isNull();\n\t}\n\n\tprivate ControllerEndpointHandlerMapping createMapping(String prefix, ExposableControllerEndpoint... endpoints) {\n\t\tControllerEndpointHandlerMapping mapping = new ControllerEndpointHandlerMapping(new EndpointMapping(prefix),\n\t\t\t\tArrays.asList(endpoints), null, (endpointId, defaultAccess) -> Access.UNRESTRICTED);\n\t\tmapping.setApplicationContext(this.context);\n\t\tmapping.afterPropertiesSet();\n\t\treturn mapping;\n\t}\n\n\tprivate HandlerMethod handlerOf(Object source, String methodName) {\n\t\tMethod method = ReflectionUtils.findMethod(source.getClass(), methodName);\n\t\tassertThat(method).isNotNull();\n\t\treturn new HandlerMethod(source, method);\n\t}\n\n\tprivate MockHttpServletRequest request(String method, String requestURI) {\n\t\treturn new MockHttpServletRequest(method, requestURI);\n\t}\n\n\tprivate ExposableControllerEndpoint firstEndpoint() {\n\t\treturn mockEndpoint(EndpointId.of(\"first\"), new FirstTestMvcEndpoint());\n\t}\n\n\tprivate ExposableControllerEndpoint secondEndpoint() {\n\t\treturn mockEndpoint(EndpointId.of(\"second\"), new SecondTestMvcEndpoint());\n\t}\n\n\tprivate ExposableControllerEndpoint pathlessEndpoint() {\n\t\treturn mockEndpoint(EndpointId.of(\"pathless\"), new PathlessControllerEndpoint());\n\t}\n\n\tprivate ExposableControllerEndpoint mockEndpoint(EndpointId id, Object controller) {\n\t\tExposableControllerEndpoint endpoint = mock(ExposableControllerEndpoint.class);\n\t\tgiven(endpoint.getEndpointId()).willReturn(id);\n\t\tgiven(endpoint.getController()).willReturn(controller);\n\t\tgiven(endpoint.getRootPath()).willReturn(id.toString());\n\t\treturn endpoint;\n\t}\n\n\t@ControllerEndpoint(id = \"first\")\n\tstatic class FirstTestMvcEndpoint {\n\n\t\t@GetMapping(\"/\")\n\t\tString get() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\t@ControllerEndpoint(id = \"second\")\n\tstatic class SecondTestMvcEndpoint {\n\n\t\t@PostMapping(\"/\")\n\t\tvoid save() {\n\n\t\t}\n\n\t}\n\n\t@ControllerEndpoint(id = \"pathless\")\n\tstatic class PathlessControllerEndpoint {\n\n\t\t@GetMapping\n\t\tString get() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/actuate/endpoint/web/WebMvcEndpointHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcLinksHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcEndpointHandlerMapping}.\n *\n * @author Moritz Halbritter\n */\nclass WebMvcEndpointHandlerMappingTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew WebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(WebMvcLinksHandler.class, \"links\"))\n\t\t\t.accepts(runtimeHints);\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(Link.class)).accepts(runtimeHints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/actuate/web/mappings/DispatcherServletsMappingDescriptionProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.web.mappings;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.FilterRegistration;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRegistration;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletsMappingDescriptionProvider.DispatcherServletsMappingDescriptionProviderRuntimeHints;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.web.MockServletConfig;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.function.RouterFunction;\nimport org.springframework.web.servlet.function.RouterFunctions;\nimport org.springframework.web.servlet.function.ServerResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.Mockito.mock;\nimport static org.springframework.web.servlet.function.RequestPredicates.accept;\nimport static org.springframework.web.servlet.function.RequestPredicates.contentType;\nimport static org.springframework.web.servlet.function.RequestPredicates.path;\n\n/**\n * Tests for {@link DispatcherServletsMappingDescriptionProvider}.\n *\n * @author Moritz Halbritter\n * @author Brian Clozel\n */\nclass DispatcherServletsMappingDescriptionProviderTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints runtimeHints = new RuntimeHints();\n\t\tnew DispatcherServletsMappingDescriptionProviderRuntimeHints().registerHints(runtimeHints,\n\t\t\t\tgetClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection()\n\t\t\t.onType(DispatcherServletMappingDescription.class)\n\t\t\t.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(runtimeHints);\n\t}\n\n\t@Test\n\tvoid shouldDescribeAnnotatedControllers() {\n\t\tSupplier<ConfigurableWebApplicationContext> contextSupplier = prepareContextSupplier();\n\t\tnew WebApplicationContextRunner(contextSupplier).withUserConfiguration(ControllerWebConfiguration.class)\n\t\t\t.run((context) -> {\n\n\t\t\t\tMap<String, List<DispatcherServletMappingDescription>> describedMappings = new DispatcherServletsMappingDescriptionProvider()\n\t\t\t\t\t.describeMappings(context);\n\t\t\t\tassertThat(describedMappings).hasSize(1).containsOnlyKeys(\"dispatcherServlet\");\n\t\t\t\tList<DispatcherServletMappingDescription> descriptions = describedMappings.get(\"dispatcherServlet\");\n\t\t\t\tassertThat(descriptions).hasSize(2)\n\t\t\t\t\t.extracting(\"predicate\")\n\t\t\t\t\t.containsExactlyInAnyOrder(\"{POST [/api/projects], consumes [application/json]}\",\n\t\t\t\t\t\t\t\"{GET [/api/projects/{id}], produces [application/json]}\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldDescribeRouterFunctions() {\n\t\tSupplier<ConfigurableWebApplicationContext> contextSupplier = prepareContextSupplier();\n\t\tnew WebApplicationContextRunner(contextSupplier).withUserConfiguration(RouterConfiguration.class)\n\t\t\t.run((context) -> {\n\n\t\t\t\tMap<String, List<DispatcherServletMappingDescription>> describedMappings = new DispatcherServletsMappingDescriptionProvider()\n\t\t\t\t\t.describeMappings(context);\n\t\t\t\tassertThat(describedMappings).hasSize(1).containsOnlyKeys(\"dispatcherServlet\");\n\t\t\t\tList<DispatcherServletMappingDescription> descriptions = describedMappings.get(\"dispatcherServlet\");\n\t\t\t\tassertThat(descriptions).hasSize(2)\n\t\t\t\t\t.extracting(\"predicate\")\n\t\t\t\t\t.containsExactlyInAnyOrder(\"(/api && (POST && (/projects/ && Content-Type: application/json)))\",\n\t\t\t\t\t\t\t\"(/api && (GET && (/projects//{id} && Accept: application/json)))\");\n\t\t\t});\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Supplier<ConfigurableWebApplicationContext> prepareContextSupplier() {\n\t\tServletContext servletContext = mock(ServletContext.class);\n\t\tgiven(servletContext.getInitParameterNames()).willReturn(Collections.emptyEnumeration());\n\t\tgiven(servletContext.getAttributeNames()).willReturn(Collections.emptyEnumeration());\n\t\tFilterRegistration filterRegistration = mock(FilterRegistration.class);\n\t\tgiven((Map<String, FilterRegistration>) servletContext.getFilterRegistrations())\n\t\t\t.willReturn(Collections.singletonMap(\"testFilter\", filterRegistration));\n\t\tServletRegistration servletRegistration = mock(ServletRegistration.class);\n\t\tgiven((Map<String, ServletRegistration>) servletContext.getServletRegistrations())\n\t\t\t.willReturn(Collections.singletonMap(\"testServlet\", servletRegistration));\n\t\treturn () -> {\n\t\t\tAnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\t\t\tcontext.setServletContext(servletContext);\n\t\t\treturn context;\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class ControllerWebConfiguration {\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet(WebApplicationContext context) throws ServletException {\n\t\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet(context);\n\t\t\tdispatcherServlet.init(new MockServletConfig());\n\t\t\treturn dispatcherServlet;\n\t\t}\n\n\t\t@Controller\n\t\t@RequestMapping(\"/api\")\n\t\tstatic class SampleController {\n\n\t\t\t@PostMapping(path = \"/projects\", consumes = MediaType.APPLICATION_JSON_VALUE)\n\t\t\tvoid createProject() {\n\t\t\t}\n\n\t\t\t@GetMapping(path = \"/projects/{id}\", produces = MediaType.APPLICATION_JSON_VALUE)\n\t\t\tvoid findProject() {\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class RouterConfiguration {\n\n\t\t@Bean\n\t\tDispatcherServlet dispatcherServlet(WebApplicationContext context) throws ServletException {\n\t\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet(context);\n\t\t\tdispatcherServlet.init(new MockServletConfig());\n\t\t\treturn dispatcherServlet;\n\t\t}\n\n\t\t@Bean\n\t\tRouterFunction<ServerResponse> routerFunctions() {\n\t\t\treturn RouterFunctions.route()\n\t\t\t\t.nest(path(\"/api\"),\n\t\t\t\t\t\t(builder) -> builder\n\t\t\t\t\t\t\t.POST(path(\"/projects/\").and(contentType(MediaType.APPLICATION_JSON)),\n\t\t\t\t\t\t\t\t\t(request) -> ServerResponse.ok().build())\n\t\t\t\t\t\t\t.GET(path(\"/projects//{id}\").and(accept(MediaType.APPLICATION_JSON)),\n\t\t\t\t\t\t\t\t\t(request) -> ServerResponse.ok().build()))\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/DispatcherServletAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport jakarta.servlet.MultipartConfigElement;\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.event.ContextRefreshedEvent;\nimport org.springframework.util.unit.DataSize;\nimport org.springframework.web.multipart.MultipartHttpServletRequest;\nimport org.springframework.web.multipart.MultipartResolver;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DispatcherServletAutoConfiguration}.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Brian Clozel\n */\nclass DispatcherServletAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class));\n\n\t@Test\n\tvoid registrationProperties() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context.getBean(DispatcherServlet.class)).isNotNull();\n\t\t\tServletRegistrationBean<?> registration = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registration.getUrlMappings()).containsExactly(\"/\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid registrationNonServletBean() {\n\t\tthis.contextRunner.withUserConfiguration(NonServletConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ServletRegistrationBean.class);\n\t\t\tassertThat(context).doesNotHaveBean(DispatcherServlet.class);\n\t\t\tassertThat(context).doesNotHaveBean(DispatcherServletPath.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid registrationOverrideWithDefaultDispatcherServletNameResultsInSingleDispatcherServlet() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDispatcherServletSameName.class).run((context) -> {\n\t\t\tServletRegistrationBean<?> registration = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registration.getUrlMappings()).containsExactly(\"/\");\n\t\t\tassertThat(registration.getServletName()).isEqualTo(\"dispatcherServlet\");\n\t\t\tassertThat(context).getBeanNames(DispatcherServlet.class).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid registrationOverrideWithNonDefaultDispatcherServletNameResultsInTwoDispatcherServlets() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomDispatcherServletDifferentName.class, CustomDispatcherServletPath.class)\n\t\t\t.run((context) -> {\n\t\t\t\tServletRegistrationBean<?> registration = context.getBean(ServletRegistrationBean.class);\n\t\t\t\tassertThat(registration.getUrlMappings()).containsExactly(\"/\");\n\t\t\t\tassertThat(registration.getServletName()).isEqualTo(\"dispatcherServlet\");\n\t\t\t\tassertThat(context).getBeanNames(DispatcherServlet.class).hasSize(2);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registrationOverrideWithAutowiredServlet() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAutowiredRegistration.class).run((context) -> {\n\t\t\tServletRegistrationBean<?> registration = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registration.getUrlMappings()).containsExactly(\"/foo\");\n\t\t\tassertThat(registration.getServletName()).isEqualTo(\"customDispatcher\");\n\t\t\tassertThat(context).hasSingleBean(DispatcherServlet.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid servletPath() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.servlet.path:/spring\").run((context) -> {\n\t\t\tassertThat(context.getBean(DispatcherServlet.class)).isNotNull();\n\t\t\tServletRegistrationBean<?> registration = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registration.getUrlMappings()).containsExactly(\"/spring/*\");\n\t\t\tassertThat(registration.getMultipartConfig()).isNull();\n\t\t\tassertThat(context.getBean(DispatcherServletPath.class).getPath()).isEqualTo(\"/spring\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid dispatcherServletPathWhenCustomDispatcherServletSameNameShouldReturnConfiguredServletPath() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDispatcherServletSameName.class)\n\t\t\t.withPropertyValues(\"spring.mvc.servlet.path:/spring\")\n\t\t\t.run((context) -> assertThat(context.getBean(DispatcherServletPath.class).getPath()).isEqualTo(\"/spring\"));\n\t}\n\n\t@Test\n\tvoid dispatcherServletPathNotCreatedWhenDefaultDispatcherServletNotAvailable() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(CustomDispatcherServletDifferentName.class, NonServletConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DispatcherServletPath.class));\n\t}\n\n\t@Test\n\tvoid dispatcherServletPathNotCreatedWhenCustomRegistrationBeanPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomDispatcherServletRegistration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DispatcherServletPath.class));\n\t}\n\n\t@Test\n\tvoid multipartConfig() {\n\t\tthis.contextRunner.withUserConfiguration(MultipartConfiguration.class).run((context) -> {\n\t\t\tServletRegistrationBean<?> registration = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registration.getMultipartConfig()).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tvoid renamesMultipartResolver() {\n\t\tthis.contextRunner.withUserConfiguration(MultipartResolverConfiguration.class).run((context) -> {\n\t\t\tDispatcherServlet dispatcherServlet = context.getBean(DispatcherServlet.class);\n\t\t\tdispatcherServlet.onApplicationEvent(new ContextRefreshedEvent(context));\n\t\t\tassertThat(dispatcherServlet.getMultipartResolver()).isInstanceOf(MockMultipartResolver.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid dispatcherServletDefaultConfig() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tDispatcherServlet dispatcherServlet = context.getBean(DispatcherServlet.class);\n\t\t\tassertThat(dispatcherServlet).extracting(\"dispatchOptionsRequest\").isEqualTo(true);\n\t\t\tassertThat(dispatcherServlet).extracting(\"dispatchTraceRequest\").isEqualTo(false);\n\t\t\tassertThat(dispatcherServlet).extracting(\"enableLoggingRequestDetails\").isEqualTo(false);\n\t\t\tassertThat(dispatcherServlet).extracting(\"publishEvents\").isEqualTo(true);\n\t\t\tassertThat(context.getBean(\"dispatcherServletRegistration\")).hasFieldOrPropertyWithValue(\"loadOnStartup\",\n\t\t\t\t\t-1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid dispatcherServletCustomConfig() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mvc.dispatch-options-request:false\", \"spring.mvc.dispatch-trace-request:true\",\n\t\t\t\t\t\"spring.mvc.publish-request-handled-events:false\", \"spring.mvc.servlet.load-on-startup=5\")\n\t\t\t.run((context) -> {\n\t\t\t\tDispatcherServlet dispatcherServlet = context.getBean(DispatcherServlet.class);\n\t\t\t\tassertThat(dispatcherServlet).extracting(\"dispatchOptionsRequest\").isEqualTo(false);\n\t\t\t\tassertThat(dispatcherServlet).extracting(\"dispatchTraceRequest\").isEqualTo(true);\n\t\t\t\tassertThat(dispatcherServlet).extracting(\"publishEvents\").isEqualTo(false);\n\t\t\t\tassertThat(context.getBean(\"dispatcherServletRegistration\"))\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"loadOnStartup\", 5);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipartConfiguration {\n\n\t\t@Bean\n\t\tMultipartConfigElement multipartConfig() {\n\t\t\treturn new MultipartConfigElement(null, DataSize.ofKilobytes(128).toBytes(),\n\t\t\t\t\tDataSize.ofKilobytes(128).toBytes(), 0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDispatcherServletDifferentName {\n\n\t\t@Bean\n\t\tDispatcherServlet customDispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDispatcherServletPath {\n\n\t\t@Bean\n\t\tDispatcherServletPath dispatcherServletPath() {\n\t\t\treturn mock(DispatcherServletPath.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAutowiredRegistration {\n\n\t\t@Bean\n\t\tServletRegistrationBean<?> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {\n\t\t\tServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet,\n\t\t\t\t\t\"/foo\");\n\t\t\tregistration.setName(\"customDispatcher\");\n\t\t\treturn registration;\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServletPath dispatcherServletPath() {\n\t\t\treturn mock(DispatcherServletPath.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class NonServletConfiguration {\n\n\t\t@Bean\n\t\tString dispatcherServlet() {\n\t\t\treturn \"spring\";\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MultipartResolverConfiguration {\n\n\t\t@Bean\n\t\tMultipartResolver getMultipartResolver() {\n\t\t\treturn new MockMultipartResolver();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDispatcherServletSameName {\n\n\t\t@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)\n\t\tDispatcherServlet dispatcherServlet() {\n\t\t\treturn new DispatcherServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomDispatcherServletRegistration {\n\n\t\t@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)\n\t\tServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {\n\t\t\tServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(dispatcherServlet,\n\t\t\t\t\t\"/foo\");\n\t\t\tregistration.setName(\"customDispatcher\");\n\t\t\treturn registration;\n\t\t}\n\n\t}\n\n\tstatic class MockMultipartResolver implements MultipartResolver {\n\n\t\t@Override\n\t\tpublic boolean isMultipart(HttpServletRequest request) {\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) {\n\t\t\treturn mock(MultipartHttpServletRequest.class);\n\t\t}\n\n\t\t@Override\n\t\tpublic void cleanupMultipart(MultipartHttpServletRequest request) {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/DispatcherServletPathTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link DispatcherServletPath}.\n *\n * @author Phillip Webb\n */\nclass DispatcherServletPathTests {\n\n\t@Test\n\tvoid getRelativePathReturnsRelativePath() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring\").getRelativePath(\"boot\")).isEqualTo(\"spring/boot\");\n\t\tassertThat(((DispatcherServletPath) () -> \"spring/\").getRelativePath(\"boot\")).isEqualTo(\"spring/boot\");\n\t\tassertThat(((DispatcherServletPath) () -> \"spring\").getRelativePath(\"/boot\")).isEqualTo(\"spring/boot\");\n\t}\n\n\t@Test\n\tvoid getPrefixWhenHasSimplePathReturnPath() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring\").getPrefix()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getPrefixWhenHasPatternRemovesPattern() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring/*.do\").getPrefix()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getPathWhenPathEndsWithSlashRemovesSlash() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring/\").getPrefix()).isEqualTo(\"spring\");\n\t}\n\n\t@Test\n\tvoid getServletUrlMappingWhenPathIsEmptyReturnsSlash() {\n\t\tassertThat(((DispatcherServletPath) () -> \"\").getServletUrlMapping()).isEqualTo(\"/\");\n\t}\n\n\t@Test\n\tvoid getServletUrlMappingWhenPathIsSlashReturnsSlash() {\n\t\tassertThat(((DispatcherServletPath) () -> \"/\").getServletUrlMapping()).isEqualTo(\"/\");\n\t}\n\n\t@Test\n\tvoid getServletUrlMappingWhenPathContainsStarReturnsPath() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring/*.do\").getServletUrlMapping()).isEqualTo(\"spring/*.do\");\n\t}\n\n\t@Test\n\tvoid getServletUrlMappingWhenHasPathNotEndingSlashReturnsSlashStarPattern() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring/boot\").getServletUrlMapping()).isEqualTo(\"spring/boot/*\");\n\t}\n\n\t@Test\n\tvoid getServletUrlMappingWhenHasPathEndingWithSlashReturnsSlashStarPattern() {\n\t\tassertThat(((DispatcherServletPath) () -> \"spring/boot/\").getServletUrlMapping()).isEqualTo(\"spring/boot/*\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/DispatcherServletRegistrationBeanTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link DispatcherServletRegistrationBean}.\n *\n * @author Phillip Webb\n */\nclass DispatcherServletRegistrationBeanTests {\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenPathIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DispatcherServletRegistrationBean(new DispatcherServlet(), null))\n\t\t\t.withMessageContaining(\"'path' must not be null\");\n\t}\n\n\t@Test\n\tvoid getPathReturnsPath() {\n\t\tDispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(new DispatcherServlet(),\n\t\t\t\t\"/test\");\n\t\tassertThat(bean.getPath()).isEqualTo(\"/test\");\n\t}\n\n\t@Test\n\tvoid getUrlMappingsReturnsSinglePathMappedPattern() {\n\t\tDispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(new DispatcherServlet(),\n\t\t\t\t\"/test\");\n\t\tassertThat(bean.getUrlMappings()).containsOnly(\"/test/*\");\n\t}\n\n\t@Test\n\tvoid setUrlMappingsCannotBeCalled() {\n\t\tDispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(new DispatcherServlet(),\n\t\t\t\t\"/test\");\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class)\n\t\t\t.isThrownBy(() -> bean.setUrlMappings(Collections.emptyList()));\n\t}\n\n\t@Test\n\tvoid addUrlMappingsCannotBeCalled() {\n\t\tDispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(new DispatcherServlet(),\n\t\t\t\t\"/test\");\n\t\tassertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> bean.addUrlMappings(\"/test\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/JspTemplateAvailabilityProviderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.mock.env.MockEnvironment;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link JspTemplateAvailabilityProvider}.\n *\n * @author Yunkun Huang\n */\nclass JspTemplateAvailabilityProviderTests {\n\n\tprivate final JspTemplateAvailabilityProvider provider = new JspTemplateAvailabilityProvider();\n\n\tprivate final ResourceLoader resourceLoader = new DefaultResourceLoader();\n\n\tprivate final MockEnvironment environment = new MockEnvironment();\n\n\t@Test\n\tvoid availabilityOfTemplateThatDoesNotExist() {\n\t\tassertThat(isTemplateAvailable(\"whatever\")).isFalse();\n\t}\n\n\t@Test\n\t@WithResource(name = \"custom-templates/custom.jsp\")\n\tvoid availabilityOfTemplateWithCustomPrefix() {\n\t\tthis.environment.setProperty(\"spring.mvc.view.prefix\", \"classpath:/custom-templates/\");\n\t\tassertThat(isTemplateAvailable(\"custom.jsp\")).isTrue();\n\t}\n\n\t@Test\n\t@WithResource(name = \"suffixed.java-server-pages\")\n\tvoid availabilityOfTemplateWithCustomSuffix() {\n\t\tthis.environment.setProperty(\"spring.mvc.view.suffix\", \".java-server-pages\");\n\t\tassertThat(isTemplateAvailable(\"suffixed\")).isTrue();\n\t}\n\n\t@Test\n\tvoid availabilityOfTemplateInSrcMainWebapp(@TempDir File rootDirectory) throws Exception {\n\t\tFile jsp = new File(rootDirectory, \"src/main/webapp/test.jsp\");\n\t\tjsp.getParentFile().mkdirs();\n\t\tFileCopyUtils.copy(new byte[0], jsp);\n\t\tMap<String, String> systemEnvironment = new HashMap<>();\n\t\tJspTemplateAvailabilityProvider provider = new JspTemplateAvailabilityProvider(rootDirectory,\n\t\t\t\tsystemEnvironment::get);\n\t\tassertThat(isTemplateAvailable(provider, \"test.jsp\")).isTrue();\n\t\tassertThat(isTemplateAvailable(provider, \"missing.jsp\")).isFalse();\n\t}\n\n\t@Test\n\tvoid availabilityOfTemplateInCustomSrcMainWebapp(@TempDir File rootDirectory) throws Exception {\n\t\tFile jsp = new File(rootDirectory, \"src/main/unusual/test.jsp\");\n\t\tjsp.getParentFile().mkdirs();\n\t\tFileCopyUtils.copy(new byte[0], jsp);\n\t\tMap<String, String> systemEnvironment = new HashMap<>();\n\t\tsystemEnvironment.put(\"WAR_SOURCE_DIRECTORY\", \"src/main/unusual\");\n\t\tJspTemplateAvailabilityProvider provider = new JspTemplateAvailabilityProvider(rootDirectory,\n\t\t\t\tsystemEnvironment::get);\n\t\tassertThat(isTemplateAvailable(provider, \"test.jsp\")).isTrue();\n\t\tassertThat(isTemplateAvailable(provider, \"missing.jsp\")).isFalse();\n\t}\n\n\tprivate boolean isTemplateAvailable(String view) {\n\t\treturn isTemplateAvailable(this.provider, view);\n\t}\n\n\tprivate boolean isTemplateAvailable(JspTemplateAvailabilityProvider provider, String view) {\n\t\treturn provider.isTemplateAvailable(view, this.environment, getClass().getClassLoader(), this.resourceLoader);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.time.LocalDateTime;\nimport java.time.LocalTime;\nimport java.time.ZoneId;\nimport java.time.ZonedDateTime;\nimport java.time.format.DateTimeFormatter;\nimport java.time.format.FormatStyle;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.validation.ValidatorFactory;\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.annotation.AfterReturning;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.InOrder;\n\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer;\nimport org.springframework.boot.servlet.filter.OrderedFormContentFilter;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration;\nimport org.springframework.boot.validation.autoconfigure.ValidatorAdapter;\nimport org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;\nimport org.springframework.boot.web.server.servlet.MockServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration.MvcValidatorRuntimeHints;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.HighestOrderedControllerAdvice;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfigurationTests.OrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.format.Parser;\nimport org.springframework.format.Printer;\nimport org.springframework.format.support.FormattingConversionService;\nimport org.springframework.http.CacheControl;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.http.server.RequestPath;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.validation.Validator;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\nimport org.springframework.web.accept.ApiVersionDeprecationHandler;\nimport org.springframework.web.accept.ApiVersionParser;\nimport org.springframework.web.accept.ApiVersionResolver;\nimport org.springframework.web.accept.ApiVersionStrategy;\nimport org.springframework.web.accept.ContentNegotiationManager;\nimport org.springframework.web.accept.DefaultApiVersionStrategy;\nimport org.springframework.web.accept.FixedContentNegotiationStrategy;\nimport org.springframework.web.accept.InvalidApiVersionException;\nimport org.springframework.web.accept.MissingApiVersionException;\nimport org.springframework.web.accept.ParameterContentNegotiationStrategy;\nimport org.springframework.web.accept.StandardApiVersionDeprecationHandler;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.support.ConfigurableWebBindingInitializer;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.context.support.AnnotationConfigWebApplicationContext;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.FormContentFilter;\nimport org.springframework.web.filter.HiddenHttpMethodFilter;\nimport org.springframework.web.filter.RequestContextFilter;\nimport org.springframework.web.method.ControllerAdviceBean;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.FlashMap;\nimport org.springframework.web.servlet.FlashMapManager;\nimport org.springframework.web.servlet.HandlerAdapter;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.HandlerMapping;\nimport org.springframework.web.servlet.LocaleResolver;\nimport org.springframework.web.servlet.RequestToViewNameTranslator;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.ViewResolver;\nimport org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;\nimport org.springframework.web.servlet.config.annotation.CorsRegistry;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;\nimport org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;\nimport org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;\nimport org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;\nimport org.springframework.web.servlet.i18n.FixedLocaleResolver;\nimport org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;\nimport org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;\nimport org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;\nimport org.springframework.web.servlet.resource.CachingResourceResolver;\nimport org.springframework.web.servlet.resource.CachingResourceTransformer;\nimport org.springframework.web.servlet.resource.ContentVersionStrategy;\nimport org.springframework.web.servlet.resource.CssLinkResourceTransformer;\nimport org.springframework.web.servlet.resource.EncodedResourceResolver;\nimport org.springframework.web.servlet.resource.FixedVersionStrategy;\nimport org.springframework.web.servlet.resource.PathResourceResolver;\nimport org.springframework.web.servlet.resource.ResourceHttpRequestHandler;\nimport org.springframework.web.servlet.resource.ResourceResolver;\nimport org.springframework.web.servlet.resource.ResourceTransformer;\nimport org.springframework.web.servlet.resource.VersionResourceResolver;\nimport org.springframework.web.servlet.resource.VersionStrategy;\nimport org.springframework.web.servlet.support.AbstractFlashMapManager;\nimport org.springframework.web.servlet.support.SessionFlashMapManager;\nimport org.springframework.web.servlet.view.AbstractView;\nimport org.springframework.web.servlet.view.ContentNegotiatingViewResolver;\nimport org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator;\nimport org.springframework.web.util.ServletRequestPathUtils;\nimport org.springframework.web.util.UrlPathHelper;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.inOrder;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebMvcAutoConfiguration}.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @author Eddú Meléndez\n * @author Kristine Jetzke\n * @author Artsiom Yudovin\n * @author Scott Frederick\n * @author Vedran Pavic\n */\nclass WebMvcAutoConfigurationTests {\n\n\tprivate static final MockServletWebServerFactory webServerFactory = new MockServletWebServerFactory();\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\t\t\tHttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class))\n\t\t.withUserConfiguration(Config.class);\n\n\t@Test\n\tvoid handlerAdaptersCreated() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).getBeans(HandlerAdapter.class).hasSize(4);\n\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class).getMessageConverters()).isNotEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid handlerMappingsCreated() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).getBeans(HandlerMapping.class).hasSize(6));\n\t}\n\n\t@Test\n\tvoid resourceHandlerMapping() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMap<String, List<Resource>> locations = getResourceMappingLocations(context);\n\t\t\tassertThat(locations.get(\"/**\")).hasSize(5);\n\t\t\tassertThat(locations.get(\"/webjars/**\")).hasSize(1);\n\t\t\tassertThat(locations.get(\"/webjars/**\").get(0))\n\t\t\t\t.isEqualTo(new ClassPathResource(\"/META-INF/resources/webjars/\"));\n\t\t\tassertThat(getResourceResolvers(context, \"/webjars/**\")).hasSize(1);\n\t\t\tassertThat(getResourceTransformers(context, \"/webjars/**\")).isEmpty();\n\t\t\tassertThat(getResourceResolvers(context, \"/**\")).hasSize(1);\n\t\t\tassertThat(getResourceTransformers(context, \"/**\")).isEmpty();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customResourceHandlerMapping() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.static-path-pattern:/static/**\").run((context) -> {\n\t\t\tMap<String, List<Resource>> locations = getResourceMappingLocations(context);\n\t\t\tassertThat(locations.get(\"/static/**\")).hasSize(5);\n\t\t\tassertThat(getResourceResolvers(context, \"/static/**\")).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customWebjarsHandlerMapping() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.webjars-path-pattern:/assets/**\").run((context) -> {\n\t\t\tMap<String, List<Resource>> locations = getResourceMappingLocations(context);\n\t\t\tassertThat(locations.get(\"/assets/**\")).hasSize(1);\n\t\t\tassertThat(locations.get(\"/assets/**\").get(0))\n\t\t\t\t.isEqualTo(new ClassPathResource(\"/META-INF/resources/webjars/\"));\n\t\t\tassertThat(getResourceResolvers(context, \"/assets/**\")).hasSize(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid resourceHandlerMappingOverrideWebjars() {\n\t\tthis.contextRunner.withUserConfiguration(WebJars.class).run((context) -> {\n\t\t\tMap<String, List<Resource>> locations = getResourceMappingLocations(context);\n\t\t\tassertThat(locations.get(\"/webjars/**\")).hasSize(1);\n\t\t\tassertThat(locations.get(\"/webjars/**\").get(0)).isEqualTo(new ClassPathResource(\"/foo/\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid resourceHandlerMappingOverrideAll() {\n\t\tthis.contextRunner.withUserConfiguration(AllResources.class).run((context) -> {\n\t\t\tMap<String, List<Resource>> locations = getResourceMappingLocations(context);\n\t\t\tassertThat(locations.get(\"/**\")).hasSize(1);\n\t\t\tassertThat(locations.get(\"/**\").get(0)).isEqualTo(new ClassPathResource(\"/foo/\"));\n\t\t});\n\t}\n\n\t@Test\n\tvoid resourceHandlerMappingDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.add-mappings:false\")\n\t\t\t.run((context) -> assertThat(getResourceMappingLocations(context)).isEmpty());\n\t}\n\n\t@Test\n\tvoid resourceHandlerChainEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.chain.enabled:true\").run((context) -> {\n\t\t\tassertThat(getResourceResolvers(context, \"/webjars/**\")).hasSize(2);\n\t\t\tassertThat(getResourceTransformers(context, \"/webjars/**\")).hasSize(1);\n\t\t\tassertThat(getResourceResolvers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t.containsOnly(CachingResourceResolver.class, PathResourceResolver.class);\n\t\t\tassertThat(getResourceTransformers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t.containsOnly(CachingResourceTransformer.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid resourceHandlerFixedStrategyEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.resources.chain.strategy.fixed.enabled:true\",\n\t\t\t\t\t\"spring.web.resources.chain.strategy.fixed.version:test\",\n\t\t\t\t\t\"spring.web.resources.chain.strategy.fixed.paths:/**/*.js\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getResourceResolvers(context, \"/webjars/**\")).hasSize(3);\n\t\t\t\tassertThat(getResourceTransformers(context, \"/webjars/**\")).hasSize(2);\n\t\t\t\tassertThat(getResourceResolvers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t\t.containsOnly(CachingResourceResolver.class, VersionResourceResolver.class,\n\t\t\t\t\t\t\tPathResourceResolver.class);\n\t\t\t\tassertThat(getResourceTransformers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t\t.containsOnly(CachingResourceTransformer.class, CssLinkResourceTransformer.class);\n\t\t\t\tVersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(context, \"/**\")\n\t\t\t\t\t.get(1);\n\t\t\t\tassertThat(resolver.getStrategyMap().get(\"/**/*.js\")).isInstanceOf(FixedVersionStrategy.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid resourceHandlerContentStrategyEnabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.resources.chain.strategy.content.enabled:true\",\n\t\t\t\t\t\"spring.web.resources.chain.strategy.content.paths:/**,/*.png\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getResourceResolvers(context, \"/webjars/**\")).hasSize(3);\n\t\t\t\tassertThat(getResourceTransformers(context, \"/webjars/**\")).hasSize(2);\n\t\t\t\tassertThat(getResourceResolvers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t\t.containsOnly(CachingResourceResolver.class, VersionResourceResolver.class,\n\t\t\t\t\t\t\tPathResourceResolver.class);\n\t\t\t\tassertThat(getResourceTransformers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t\t.containsOnly(CachingResourceTransformer.class, CssLinkResourceTransformer.class);\n\t\t\t\tVersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(context, \"/**\")\n\t\t\t\t\t.get(1);\n\t\t\t\tassertThat(resolver.getStrategyMap().get(\"/*.png\")).isInstanceOf(ContentVersionStrategy.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid resourceHandlerChainCustomized() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.chain.enabled:true\",\n\t\t\t\t\"spring.web.resources.chain.cache:false\", \"spring.web.resources.chain.strategy.content.enabled:true\",\n\t\t\t\t\"spring.web.resources.chain.strategy.content.paths:/**,/*.png\",\n\t\t\t\t\"spring.web.resources.chain.strategy.fixed.enabled:true\",\n\t\t\t\t\"spring.web.resources.chain.strategy.fixed.version:test\",\n\t\t\t\t\"spring.web.resources.chain.strategy.fixed.paths:/**/*.js\",\n\t\t\t\t\"spring.web.resources.chain.html-application-cache:true\", \"spring.web.resources.chain.compressed:true\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(getResourceResolvers(context, \"/webjars/**\")).hasSize(3);\n\t\t\t\tassertThat(getResourceTransformers(context, \"/webjars/**\")).hasSize(1);\n\t\t\t\tassertThat(getResourceResolvers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t\t.containsOnly(EncodedResourceResolver.class, VersionResourceResolver.class,\n\t\t\t\t\t\t\tPathResourceResolver.class);\n\t\t\t\tassertThat(getResourceTransformers(context, \"/**\")).extractingResultOf(\"getClass\")\n\t\t\t\t\t.containsOnly(CssLinkResourceTransformer.class);\n\t\t\t\tVersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(context, \"/**\")\n\t\t\t\t\t.get(1);\n\t\t\t\tMap<String, VersionStrategy> strategyMap = resolver.getStrategyMap();\n\t\t\t\tassertThat(strategyMap.get(\"/*.png\")).isInstanceOf(ContentVersionStrategy.class);\n\t\t\t\tassertThat(strategyMap.get(\"/**/*.js\")).isInstanceOf(FixedVersionStrategy.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultLocaleResolver() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(LocaleResolver.class);\n\t\t\tLocaleResolver localeResolver = context.getBean(LocaleResolver.class);\n\t\t\tassertThat(localeResolver).hasFieldOrPropertyWithValue(\"defaultLocale\", null);\n\t\t});\n\t}\n\n\t@Test\n\tvoid overrideLocale() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.locale:en_UK\", \"spring.web.locale-resolver=fixed\")\n\t\t\t.run((loader) -> {\n\t\t\t\t// mock request and set user preferred locale\n\t\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\t\tLocale locale = StringUtils.parseLocaleString(\"nl_NL\");\n\t\t\t\tassertThat(locale).isNotNull();\n\t\t\t\trequest.addPreferredLocale(locale);\n\t\t\t\trequest.addHeader(HttpHeaders.ACCEPT_LANGUAGE, \"nl_NL\");\n\t\t\t\tLocaleResolver localeResolver = loader.getBean(LocaleResolver.class);\n\t\t\t\tassertThat(localeResolver).isInstanceOf(FixedLocaleResolver.class);\n\t\t\t\tLocale resolvedLocale = localeResolver.resolveLocale(request);\n\t\t\t\t// test locale resolver uses fixed locale and not user preferred\n\t\t\t\t// locale\n\t\t\t\tassertThat(resolvedLocale).hasToString(\"en_UK\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid useAcceptHeaderLocale() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.locale:en_UK\").run((loader) -> {\n\t\t\t// mock request and set user preferred locale\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\tLocale locale = StringUtils.parseLocaleString(\"nl_NL\");\n\t\t\tassertThat(locale).isNotNull();\n\t\t\trequest.addPreferredLocale(locale);\n\t\t\trequest.addHeader(HttpHeaders.ACCEPT_LANGUAGE, \"nl_NL\");\n\t\t\tLocaleResolver localeResolver = loader.getBean(LocaleResolver.class);\n\t\t\tassertThat(localeResolver).isInstanceOf(AcceptHeaderLocaleResolver.class);\n\t\t\tLocale resolvedLocale = localeResolver.resolveLocale(request);\n\t\t\t// test locale resolver uses user preferred locale\n\t\t\tassertThat(resolvedLocale).hasToString(\"nl_NL\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid useDefaultLocaleIfAcceptHeaderNoSet() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.locale:en_UK\").run((context) -> {\n\t\t\t// mock request and set user preferred locale\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\tLocaleResolver localeResolver = context.getBean(LocaleResolver.class);\n\t\t\tassertThat(localeResolver).isInstanceOf(AcceptHeaderLocaleResolver.class);\n\t\t\tLocale locale = localeResolver.resolveLocale(request);\n\t\t\t// test locale resolver uses default locale if no header is set\n\t\t\tassertThat(locale).hasToString(\"en_UK\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid customLocaleResolverWithMatchingNameReplacesAutoConfiguredLocaleResolver() {\n\t\tthis.contextRunner.withBean(\"localeResolver\", CustomLocaleResolver.class, CustomLocaleResolver::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(LocaleResolver.class);\n\t\t\t\tassertThat(context.getBean(\"localeResolver\")).isInstanceOf(CustomLocaleResolver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customLocaleResolverWithDifferentNameDoesNotReplaceAutoConfiguredLocaleResolver() {\n\t\tthis.contextRunner.withBean(\"customLocaleResolver\", CustomLocaleResolver.class, CustomLocaleResolver::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(\"customLocaleResolver\")).isInstanceOf(CustomLocaleResolver.class);\n\t\t\t\tassertThat(context.getBean(\"localeResolver\")).isInstanceOf(AcceptHeaderLocaleResolver.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customFlashMapManagerWithMatchingNameReplacesDefaultFlashMapManager() {\n\t\tthis.contextRunner.withBean(\"flashMapManager\", CustomFlashMapManager.class, CustomFlashMapManager::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(FlashMapManager.class);\n\t\t\t\tassertThat(context.getBean(\"flashMapManager\")).isInstanceOf(CustomFlashMapManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customFlashMapManagerWithDifferentNameDoesNotReplaceDefaultFlashMapManager() {\n\t\tthis.contextRunner.withBean(\"customFlashMapManager\", CustomFlashMapManager.class, CustomFlashMapManager::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(\"customFlashMapManager\")).isInstanceOf(CustomFlashMapManager.class);\n\t\t\t\tassertThat(context.getBean(\"flashMapManager\")).isInstanceOf(SessionFlashMapManager.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customViewNameTranslatorWithMatchingNameReplacesDefaultViewNameTranslator() {\n\t\tthis.contextRunner.withBean(\"viewNameTranslator\", CustomViewNameTranslator.class, CustomViewNameTranslator::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RequestToViewNameTranslator.class);\n\t\t\t\tassertThat(context.getBean(\"viewNameTranslator\")).isInstanceOf(CustomViewNameTranslator.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customViewNameTranslatorWithDifferentNameDoesNotReplaceDefaultViewNameTranslator() {\n\t\tthis.contextRunner\n\t\t\t.withBean(\"customViewNameTranslator\", CustomViewNameTranslator.class, CustomViewNameTranslator::new)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context.getBean(\"customViewNameTranslator\")).isInstanceOf(CustomViewNameTranslator.class);\n\t\t\t\tassertThat(context.getBean(\"viewNameTranslator\"))\n\t\t\t\t\t.isInstanceOf(DefaultRequestToViewNameTranslator.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDateFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tDate date = Date.from(ZonedDateTime.of(1988, 6, 25, 20, 30, 0, 0, ZoneId.systemDefault()).toInstant());\n\t\t\t// formatting conversion service should use simple toString()\n\t\t\tassertThat(conversionService.convert(date, String.class)).isEqualTo(date.toString());\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.format.date:dd*MM*yyyy\").run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tDate date = Date.from(ZonedDateTime.of(1988, 6, 25, 20, 30, 0, 0, ZoneId.systemDefault()).toInstant());\n\t\t\tassertThat(conversionService.convert(date, String.class)).isEqualTo(\"25*06*1988\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultTimeFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalTime time = LocalTime.of(11, 43, 10);\n\t\t\tassertThat(conversionService.convert(time, String.class))\n\t\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(time));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customTimeFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.format.time=HH:mm:ss\").run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalTime time = LocalTime.of(11, 43, 10);\n\t\t\tassertThat(conversionService.convert(time, String.class)).isEqualTo(\"11:43:10\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultDateTimeFormat() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 28, 11, 43, 10);\n\t\t\tassertThat(conversionService.convert(dateTime, String.class))\n\t\t\t\t.isEqualTo(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).format(dateTime));\n\t\t});\n\t}\n\n\t@Test\n\tvoid customDateTimeTimeFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.format.date-time=yyyy-MM-dd HH:mm:ss\").run((context) -> {\n\t\t\tFormattingConversionService conversionService = context.getBean(FormattingConversionService.class);\n\t\t\tLocalDateTime dateTime = LocalDateTime.of(2020, 4, 28, 11, 43, 10);\n\t\t\tassertThat(conversionService.convert(dateTime, String.class)).isEqualTo(\"2020-04-28 11:43:10\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid noMessageCodesResolver() {\n\t\tthis.contextRunner.run(\n\t\t\t\t(context) -> assertThat(context.getBean(WebMvcAutoConfigurationAdapter.class).getMessageCodesResolver())\n\t\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid overrideMessageCodesFormat() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.messageCodesResolverFormat:POSTFIX_ERROR_CODE\")\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(WebMvcAutoConfigurationAdapter.class).getMessageCodesResolver())\n\t\t\t\t.isNotNull());\n\t}\n\n\t@Test\n\tvoid customViewResolver() {\n\t\tthis.contextRunner.withUserConfiguration(CustomViewResolver.class)\n\t\t\t.run((context) -> assertThat(context.getBean(\"viewResolver\")).isInstanceOf(MyViewResolver.class));\n\t}\n\n\t@Test\n\tvoid customContentNegotiatingViewResolver() {\n\t\tthis.contextRunner.withUserConfiguration(CustomContentNegotiatingViewResolver.class)\n\t\t\t.run((context) -> assertThat(context).getBeanNames(ContentNegotiatingViewResolver.class)\n\t\t\t\t.containsOnly(\"myViewResolver\"));\n\t}\n\n\t@Test\n\tvoid defaultAsyncRequestTimeout() {\n\t\tthis.contextRunner.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t.extracting(\"asyncRequestTimeout\")\n\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid customAsyncRequestTimeout() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.async.request-timeout:12345\")\n\t\t\t.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t\t.extracting(\"asyncRequestTimeout\")\n\t\t\t\t.isEqualTo(12345L));\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorWithApplicationTaskExecutor() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"taskExecutor\")\n\t\t\t\t\t.isSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorWithNonMatchApplicationTaskExecutorBean() {\n\t\tthis.contextRunner.withUserConfiguration(CustomApplicationTaskExecutorConfig.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"taskExecutor\")\n\t\t\t\t\t.isNotSameAs(context.getBean(\"applicationTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorWithMvcConfigurerCanOverrideExecutor() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfigurer.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"taskExecutor\")\n\t\t\t\t.isSameAs(context.getBean(CustomAsyncTaskExecutorConfigurer.class).taskExecutor));\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorWithCustomNonApplicationTaskExecutor() {\n\t\tthis.contextRunner.withUserConfiguration(CustomAsyncTaskExecutorConfig.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(TaskExecutionAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(AsyncTaskExecutor.class);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class)).extracting(\"taskExecutor\")\n\t\t\t\t\t.isNotSameAs(context.getBean(\"customTaskExecutor\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid customMediaTypes() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.contentnegotiation.media-types.yaml:text/yaml\")\n\t\t\t.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t\t.extracting(\"contentNegotiationManager\",\n\t\t\t\t\t\tInstanceOfAssertFactories.type(ContentNegotiationManager.class))\n\t\t\t\t.satisfies((contentNegotiationManager) -> assertThat(contentNegotiationManager.getAllFileExtensions())\n\t\t\t\t\t.contains(\"yaml\")));\n\t}\n\n\t@Test\n\tvoid customDefaultContentTypes() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mvc.contentnegotiation.default-content-types:application/json,application/xml\")\n\t\t\t.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t\t.extracting(\"contentNegotiationManager\",\n\t\t\t\t\t\tInstanceOfAssertFactories.type(ContentNegotiationManager.class))\n\t\t\t\t.satisfies((contentNegotiationManager) -> {\n\t\t\t\t\tFixedContentNegotiationStrategy strategy = contentNegotiationManager\n\t\t\t\t\t\t.getStrategy(FixedContentNegotiationStrategy.class);\n\t\t\t\t\tassertThat(strategy).isNotNull();\n\t\t\t\t\tassertThat(strategy.getContentTypes()).containsExactly(MediaType.APPLICATION_JSON,\n\t\t\t\t\t\t\tMediaType.APPLICATION_XML);\n\t\t\t\t}));\n\t}\n\n\t@Test\n\tvoid formContentFilterIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(OrderedFormContentFilter.class));\n\t}\n\n\t@Test\n\tvoid formContentFilterCanBeOverridden() {\n\t\tthis.contextRunner.withUserConfiguration(CustomFormContentFilter.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(OrderedFormContentFilter.class);\n\t\t\tassertThat(context).hasSingleBean(FormContentFilter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid formContentFilterCanBeDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.formcontent.filter.enabled=false\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(FormContentFilter.class));\n\t}\n\n\t@Test\n\tvoid hiddenHttpMethodFilterCanBeEnabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.hiddenmethod.filter.enabled=true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(HiddenHttpMethodFilter.class));\n\t}\n\n\t@Test\n\tvoid hiddenHttpMethodFilterDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HiddenHttpMethodFilter.class));\n\t}\n\n\t@Test\n\tvoid customConfigurableWebBindingInitializer() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConfigurableWebBindingInitializer.class)\n\t\t\t.run((context) -> assertThat(context.getBean(RequestMappingHandlerAdapter.class).getWebBindingInitializer())\n\t\t\t\t.isInstanceOf(CustomWebBindingInitializer.class));\n\t}\n\n\t@Test\n\tvoid customRequestMappingHandlerMapping() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRequestMappingHandlerMapping.class).run((context) -> {\n\t\t\tassertThat(context).getBean(RequestMappingHandlerMapping.class)\n\t\t\t\t.isInstanceOf(MyRequestMappingHandlerMapping.class);\n\t\t\tassertThat(context.getBean(CustomRequestMappingHandlerMapping.class).handlerMappings).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customRequestMappingHandlerAdapter() {\n\t\tthis.contextRunner.withUserConfiguration(CustomRequestMappingHandlerAdapter.class).run((context) -> {\n\t\t\tassertThat(context).getBean(RequestMappingHandlerAdapter.class)\n\t\t\t\t.isInstanceOf(MyRequestMappingHandlerAdapter.class);\n\t\t\tassertThat(context.getBean(CustomRequestMappingHandlerAdapter.class).handlerAdapters).isOne();\n\t\t});\n\t}\n\n\t@Test\n\tvoid customExceptionHandlerExceptionResolver() {\n\t\tthis.contextRunner.withUserConfiguration(CustomExceptionHandlerExceptionResolver.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tcontext.getBean(CustomExceptionHandlerExceptionResolver.class).exceptionResolvers)\n\t\t\t\t.isOne());\n\t}\n\n\t@Test\n\tvoid multipleWebMvcRegistrations() {\n\t\tthis.contextRunner.withUserConfiguration(MultipleWebMvcRegistrations.class).run((context) -> {\n\t\t\tassertThat(context.getBean(RequestMappingHandlerMapping.class))\n\t\t\t\t.isNotInstanceOf(MyRequestMappingHandlerMapping.class);\n\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class))\n\t\t\t\t.isNotInstanceOf(MyRequestMappingHandlerAdapter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid defaultLogResolvedException() {\n\t\tthis.contextRunner.run(assertExceptionResolverWarnLoggers((logger) -> assertThat(logger).isNull()));\n\t}\n\n\t@Test\n\tvoid customLogResolvedException() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.log-resolved-exception:true\")\n\t\t\t.run(assertExceptionResolverWarnLoggers((logger) -> assertThat(logger).isNotNull()));\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> assertExceptionResolverWarnLoggers(\n\t\t\tConsumer<Object> consumer) {\n\t\treturn (context) -> {\n\t\t\tHandlerExceptionResolver resolver = context.getBean(HandlerExceptionResolver.class);\n\t\t\tassertThat(resolver).isInstanceOf(HandlerExceptionResolverComposite.class);\n\t\t\tList<HandlerExceptionResolver> delegates = ((HandlerExceptionResolverComposite) resolver)\n\t\t\t\t.getExceptionResolvers();\n\t\t\tfor (HandlerExceptionResolver delegate : delegates) {\n\t\t\t\tif (delegate instanceof AbstractHandlerExceptionResolver\n\t\t\t\t\t\t&& !(delegate instanceof DefaultHandlerExceptionResolver)) {\n\t\t\t\t\tconsumer.accept(ReflectionTestUtils.getField(delegate, \"warnLogger\"));\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t@Test\n\t@WithResource(name = \"welcome-page/index.html\", content = \"welcome-page-static\")\n\tvoid welcomePageHandlerMappingIsAutoConfigured() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.static-locations:classpath:/welcome-page/\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(WelcomePageHandlerMapping.class);\n\t\t\t\tassertThat(context.getBean(WelcomePageHandlerMapping.class).getRootHandler()).isNotNull();\n\t\t\t\tassertThat(context.getBean(WelcomePageNotAcceptableHandlerMapping.class).getRootHandler()).isNotNull();\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"welcome-page/index.html\", content = \"welcome-page-static\")\n\tvoid welcomePageHandlerIncludesCorsConfiguration() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.static-locations:classpath:/welcome-page/\")\n\t\t\t.withUserConfiguration(CorsConfigurer.class)\n\t\t\t.run((context) -> {\n\t\t\t\tWelcomePageHandlerMapping bean = context.getBean(WelcomePageHandlerMapping.class);\n\t\t\t\tUrlBasedCorsConfigurationSource source = (UrlBasedCorsConfigurationSource) bean\n\t\t\t\t\t.getCorsConfigurationSource();\n\t\t\t\tassertThat(source).isNotNull();\n\t\t\t\tassertThat(source.getCorsConfigurations()).containsKey(\"/**\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWhenNoValidatorShouldUseDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(jakarta.validation.Validator.class);\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"mvcValidator\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWhenNoCustomizationShouldUseAutoConfigured() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class).containsOnly(\"defaultValidator\");\n\t\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"defaultValidator\", \"mvcValidator\");\n\t\t\t\tValidator validator = context.getBean(\"mvcValidator\", Validator.class);\n\t\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\t\tObject defaultValidator = context.getBean(\"defaultValidator\");\n\t\t\t\tassertThat(((ValidatorAdapter) validator).getTarget()).isSameAs(defaultValidator);\n\t\t\t\t// Primary Spring validator is the one used by MVC behind the scenes\n\t\t\t\tassertThat(context.getBean(Validator.class)).isEqualTo(defaultValidator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithConfigurerAloneShouldUseSpringValidator() {\n\t\tthis.contextRunner.withUserConfiguration(MvcValidator.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(jakarta.validation.Validator.class);\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"mvcValidator\");\n\t\t\tValidator expectedValidator = context.getBean(MvcValidator.class).validator;\n\t\t\tassertThat(context.getBean(\"mvcValidator\")).isSameAs(expectedValidator);\n\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class).getWebBindingInitializer())\n\t\t\t\t.hasFieldOrPropertyWithValue(\"validator\", expectedValidator);\n\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithConfigurerShouldUseSpringValidator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(MvcValidator.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class).containsOnly(\"defaultValidator\");\n\t\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"defaultValidator\", \"mvcValidator\");\n\t\t\t\tValidator expectedValidator = context.getBean(MvcValidator.class).validator;\n\t\t\t\tassertThat(context.getBean(\"mvcValidator\")).isSameAs(expectedValidator);\n\t\t\t\tassertThat(context.getBean(RequestMappingHandlerAdapter.class).getWebBindingInitializer())\n\t\t\t\t\t.hasFieldOrPropertyWithValue(\"validator\", expectedValidator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithConfigurerDoesNotExposeJsr303() {\n\t\tthis.contextRunner.withUserConfiguration(MvcJsr303Validator.class).run((context) -> {\n\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\tassertThat(context).doesNotHaveBean(jakarta.validation.Validator.class);\n\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"mvcValidator\");\n\t\t\tValidator validator = context.getBean(\"mvcValidator\", Validator.class);\n\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\tassertThat(((ValidatorAdapter) validator).getTarget())\n\t\t\t\t.isSameAs(context.getBean(MvcJsr303Validator.class).validator);\n\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithConfigurerTakesPrecedence() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(MvcValidator.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(ValidatorFactory.class);\n\t\t\t\tassertThat(context).hasSingleBean(jakarta.validation.Validator.class);\n\t\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"defaultValidator\", \"mvcValidator\");\n\t\t\t\tassertThat(context.getBean(\"mvcValidator\")).isSameAs(context.getBean(MvcValidator.class).validator);\n\t\t\t\t// Primary Spring validator is the auto-configured one as the MVC one\n\t\t\t\t// has been customized through a WebMvcConfigurer\n\t\t\t\tassertThat(context.getBean(Validator.class)).isEqualTo(context.getBean(\"defaultValidator\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithCustomSpringValidatorIgnored() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomSpringValidator.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class).containsOnly(\"defaultValidator\");\n\t\t\t\tassertThat(context).getBeanNames(Validator.class)\n\t\t\t\t\t.containsOnly(\"customSpringValidator\", \"defaultValidator\", \"mvcValidator\");\n\t\t\t\tValidator validator = context.getBean(\"mvcValidator\", Validator.class);\n\t\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\t\tObject defaultValidator = context.getBean(\"defaultValidator\");\n\t\t\t\tassertThat(((ValidatorAdapter) validator).getTarget()).isSameAs(defaultValidator);\n\t\t\t\t// Primary Spring validator is the one used by MVC behind the scenes\n\t\t\t\tassertThat(context.getBean(Validator.class)).isEqualTo(defaultValidator);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid validatorWithCustomJsr303ValidatorExposedAsSpringValidator() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class))\n\t\t\t.withUserConfiguration(CustomJsr303Validator.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).doesNotHaveBean(ValidatorFactory.class);\n\t\t\t\tassertThat(context).getBeanNames(jakarta.validation.Validator.class)\n\t\t\t\t\t.containsOnly(\"customJsr303Validator\");\n\t\t\t\tassertThat(context).getBeanNames(Validator.class).containsOnly(\"mvcValidator\");\n\t\t\t\tValidator validator = context.getBean(Validator.class);\n\t\t\t\tassertThat(validator).isInstanceOf(ValidatorAdapter.class);\n\t\t\t\tValidator target = ((ValidatorAdapter) validator).getTarget();\n\t\t\t\tassertThat(target).extracting(\"targetValidator\").isSameAs(context.getBean(\"customJsr303Validator\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid httpMessageConverterThatUsesConversionServiceDoesNotCreateACycle() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpMessageConverter.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid cachePeriod() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.cache.period:5\").run((context) -> {\n\t\t\tassertResourceHttpRequestHandler((context), (handler) -> {\n\t\t\t\tassertThat(handler.getCacheSeconds()).isEqualTo(5);\n\t\t\t\tassertThat(handler.getCacheControl()).isNull();\n\t\t\t});\n\t\t});\n\t}\n\n\t@Test\n\tvoid cacheControl() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.web.resources.cache.cachecontrol.max-age:5\",\n\t\t\t\t\t\"spring.web.resources.cache.cachecontrol.proxy-revalidate:true\")\n\t\t\t.run((context) -> assertResourceHttpRequestHandler(context, (handler) -> {\n\t\t\t\tassertThat(handler.getCacheSeconds()).isEqualTo(-1);\n\t\t\t\tassertThat(handler.getCacheControl()).usingRecursiveComparison()\n\t\t\t\t\t.isEqualTo(CacheControl.maxAge(5, TimeUnit.SECONDS).proxyRevalidate());\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid usePathPatternParser() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.pathmatch.matching-strategy:path_pattern_parser\")\n\t\t\t.run((context) -> {\n\t\t\t\tRequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);\n\t\t\t\tassertThat(handlerMapping.usesPathPatterns()).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid queryParameterContentNegotiation() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.contentnegotiation.favor-parameter:true\").run((context) -> {\n\t\t\tRequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);\n\t\t\tContentNegotiationManager contentNegotiationManager = handlerMapping.getContentNegotiationManager();\n\t\t\tassertThat(contentNegotiationManager.getStrategies())\n\t\t\t\t.hasAtLeastOneElementOfType(ParameterContentNegotiationStrategy.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid requestContextFilterIsAutoConfigured() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(RequestContextFilter.class));\n\t}\n\n\t@Test\n\tvoid whenUserDefinesARequestContextFilterTheAutoConfiguredRegistrationBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(RequestContextFilterConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(RequestContextFilter.class);\n\t\t\tassertThat(context).hasBean(\"customRequestContextFilter\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid whenUserDefinesARequestContextFilterRegistrationTheAutoConfiguredFilterBacksOff() {\n\t\tthis.contextRunner.withUserConfiguration(RequestContextFilterRegistrationConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\t\tassertThat(context).hasBean(\"customRequestContextFilterRegistration\");\n\t\t\tassertThat(context).doesNotHaveBean(RequestContextFilter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customPrinterAndParserShouldBeRegisteredAsConverters() {\n\t\tthis.contextRunner.withUserConfiguration(ParserConfiguration.class, PrinterConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tConversionService service = context.getBean(ConversionService.class);\n\t\t\t\tassertThat(service.convert(new Example(\"spring\", new Date()), String.class)).isEqualTo(\"spring\");\n\t\t\t\tassertThat(service.convert(\"boot\", Example.class)).extracting(Example::getName).isEqualTo(\"boot\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid urlPathHelperUsesFullPathByDefaultWhenAntPathMatchingIsUsed() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.pathmatch.matching-strategy:ant-path-matcher\")\n\t\t\t.run((context) -> {\n\t\t\t\tUrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);\n\t\t\t\tassertThat(urlPathHelper).extracting(\"alwaysUseFullPath\").isEqualTo(true);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid urlPathHelperDoesNotUseFullPathWithServletMapping() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.pathmatch.matching-strategy:ant-path-matcher\")\n\t\t\t.withPropertyValues(\"spring.mvc.servlet.path=/test/\")\n\t\t\t.run((context) -> {\n\t\t\t\tUrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);\n\t\t\t\tassertThat(urlPathHelper).extracting(\"alwaysUseFullPath\").isEqualTo(false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid urlPathHelperDoesNotUseFullPathWithAdditionalDispatcherServlet() {\n\t\tthis.contextRunner.withUserConfiguration(AdditionalDispatcherServletConfiguration.class).run((context) -> {\n\t\t\tUrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);\n\t\t\tassertThat(urlPathHelper).extracting(\"alwaysUseFullPath\").isEqualTo(false);\n\t\t});\n\t}\n\n\t@Test\n\tvoid urlPathHelperDoesNotUseFullPathWithAdditionalUntypedDispatcherServlet() {\n\t\tthis.contextRunner.withUserConfiguration(AdditionalUntypedDispatcherServletConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tUrlPathHelper urlPathHelper = context.getBean(UrlPathHelper.class);\n\t\t\t\tassertThat(urlPathHelper).extracting(\"alwaysUseFullPath\").isEqualTo(false);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid lastModifiedNotUsedIfDisabled() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.web.resources.cache.use-last-modified=false\")\n\t\t\t.run((context) -> assertResourceHttpRequestHandler(context,\n\t\t\t\t\t(handler) -> assertThat(handler.isUseLastModified()).isFalse()));\n\t}\n\n\t@Test // gh-25743\n\tvoid addResourceHandlersAppliesToChildAndParentContext() {\n\t\ttry (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext()) {\n\t\t\tcontext.register(WebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\t\tHttpMessageConvertersAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tResourceHandlersWithChildAndParentContextConfiguration.class);\n\t\t\tcontext.refresh();\n\t\t\tSimpleUrlHandlerMapping resourceHandlerMapping = context.getBean(\"resourceHandlerMapping\",\n\t\t\t\t\tSimpleUrlHandlerMapping.class);\n\t\t\tDispatcherServlet extraDispatcherServlet = context.getBean(\"extraDispatcherServlet\",\n\t\t\t\t\tDispatcherServlet.class);\n\t\t\tWebApplicationContext webApplicationContext = extraDispatcherServlet.getWebApplicationContext();\n\t\t\tassertThat(webApplicationContext).isNotNull();\n\t\t\tSimpleUrlHandlerMapping extraResourceHandlerMapping = webApplicationContext\n\t\t\t\t.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class);\n\t\t\tassertThat(resourceHandlerMapping).isNotSameAs(extraResourceHandlerMapping);\n\t\t\tassertThat(resourceHandlerMapping.getUrlMap()).containsKey(\"/**\");\n\t\t\tassertThat(extraResourceHandlerMapping.getUrlMap()).containsKey(\"/**\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid problemDetailsDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ProblemDetailsExceptionHandler.class));\n\t}\n\n\t@Test\n\tvoid problemDetailsEnabledAddsExceptionHandler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.problemdetails.enabled:true\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ProblemDetailsExceptionHandler.class));\n\t}\n\n\t@Test\n\tvoid problemDetailsExceptionHandlerDoesNotPreventProxying() {\n\t\tthis.contextRunner.withUserConfiguration(AopConfiguration.class)\n\t\t\t.withBean(ExceptionHandlerInterceptor.class)\n\t\t\t.withPropertyValues(\"spring.mvc.problemdetails.enabled:true\")\n\t\t\t.run((context) -> assertThat(context).getBean(ProblemDetailsExceptionHandler.class)\n\t\t\t\t.matches(AopUtils::isCglibProxy));\n\t}\n\n\t@Test\n\tvoid problemDetailsBacksOffWhenExceptionHandler() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.problemdetails.enabled:true\")\n\t\t\t.withUserConfiguration(CustomExceptionHandlerConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ProblemDetailsExceptionHandler.class)\n\t\t\t\t.hasSingleBean(CustomExceptionHandler.class));\n\t}\n\n\t@Test\n\tvoid problemDetailsExceptionHandlerIsOrderedAt0() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.problemdetails.enabled:true\")\n\t\t\t.withUserConfiguration(OrderedControllerAdviceBeansConfiguration.class)\n\t\t\t.run((context) -> assertThat(\n\t\t\t\t\tControllerAdviceBean.findAnnotatedBeans(context).stream().map(ControllerAdviceBean::getBeanType))\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.list(Class.class))\n\t\t\t\t.containsExactly(HighestOrderedControllerAdvice.class, ProblemDetailsExceptionHandler.class,\n\t\t\t\t\t\tOrderedControllerAdviceBeansConfiguration.LowestOrderedControllerAdvice.class));\n\t}\n\n\t@Test\n\tvoid apiVersionPropertiesAreApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mvc.apiversion.use.header=version\", \"spring.mvc.apiversion.required=true\",\n\t\t\t\t\t\"spring.mvc.apiversion.supported=123,456\", \"spring.mvc.apiversion.detect-supported=false\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\",\n\t\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\t\tassertThatExceptionOfType(MissingApiVersionException.class)\n\t\t\t\t\t.isThrownBy(() -> versionStrategy.validateVersion(null, new MockHttpServletRequest()));\n\t\t\t\tassertThatExceptionOfType(InvalidApiVersionException.class).isThrownBy(() -> versionStrategy\n\t\t\t\t\t.validateVersion(versionStrategy.parseVersion(\"789\"), new MockHttpServletRequest()));\n\t\t\t\tassertThat(versionStrategy.detectSupportedVersions()).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionDefaultVersionPropertyIsApplied() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.mvc.apiversion.use.header=version\", \"spring.mvc.apiversion.default=1.0.0\")\n\t\t\t.run((context) -> {\n\t\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\",\n\t\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\t\tversionStrategy.addSupportedVersion(\"1.0.0\");\n\t\t\t\tComparable<?> version = versionStrategy.parseVersion(\"1.0.0\");\n\t\t\t\tassertThat(versionStrategy.getDefaultVersion()).isEqualTo(version);\n\t\t\t\tversionStrategy.validateVersion(version, new MockHttpServletRequest());\n\t\t\t\tversionStrategy.validateVersion(null, new MockHttpServletRequest());\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUseHeaderPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.apiversion.use.header=hv\").run((context) -> {\n\t\t\tApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\", ApiVersionStrategy.class);\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\trequest.addHeader(\"hv\", \"123\");\n\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUseQueryParameterPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.apiversion.use.query-parameter=rpv\").run((context) -> {\n\t\t\tApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\", ApiVersionStrategy.class);\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\trequest.setQueryString(\"rpv=123\");\n\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUsePathSegmentPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.apiversion.use.path-segment=1\").run((context) -> {\n\t\t\tApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\", ApiVersionStrategy.class);\n\t\t\tMockHttpServletRequest request = new MockHttpServletRequest(\"GET\", \"https://example.com/test/123\");\n\t\t\tServletRequestPathUtils.setParsedRequestPath(RequestPath.parse(\"/test/123\", \"/\"), request);\n\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionUseMediaTypeParameterPropertyIsApplied() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.mvc.apiversion.use.media-type-parameter[application/json]=mtpv\")\n\t\t\t.run((context) -> {\n\t\t\t\tApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\", ApiVersionStrategy.class);\n\t\t\t\tMockHttpServletRequest request = new MockHttpServletRequest();\n\t\t\t\trequest.addHeader(HttpHeaders.CONTENT_TYPE, \"application/json;mtpv=123\");\n\t\t\t\tassertThat(versionStrategy.resolveVersion(request)).isEqualTo(\"123\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid apiVersionBeansAreInjected() {\n\t\tthis.contextRunner.withUserConfiguration(ApiVersionConfiguration.class).run((context) -> {\n\t\t\tDefaultApiVersionStrategy versionStrategy = context.getBean(\"mvcApiVersionStrategy\",\n\t\t\t\t\tDefaultApiVersionStrategy.class);\n\t\t\tassertThat(versionStrategy).extracting(\"versionResolvers\")\n\t\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t\t.containsExactly(context.getBean(ApiVersionResolver.class));\n\t\t\tassertThat(versionStrategy).extracting(\"deprecationHandler\")\n\t\t\t\t.isEqualTo(context.getBean(ApiVersionDeprecationHandler.class));\n\t\t\tassertThat(versionStrategy).extracting(\"versionParser\").isEqualTo(context.getBean(ApiVersionParser.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid serverHttpMessageConverterCustomizersAreAppliedInOrder() {\n\t\tthis.contextRunner.withUserConfiguration(ServerHttpMessageConverterCustomizersConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tServerHttpMessageConvertersCustomizer customizer1 = context.getBean(\"customizer1\",\n\t\t\t\t\t\tServerHttpMessageConvertersCustomizer.class);\n\t\t\t\tServerHttpMessageConvertersCustomizer customizer2 = context.getBean(\"customizer2\",\n\t\t\t\t\t\tServerHttpMessageConvertersCustomizer.class);\n\t\t\t\tServerHttpMessageConvertersCustomizer customizer3 = context.getBean(\"customizer3\",\n\t\t\t\t\t\tServerHttpMessageConvertersCustomizer.class);\n\t\t\t\tInOrder inOrder = inOrder(customizer1, customizer2, customizer3);\n\t\t\t\tinOrder.verify(customizer3).customize(any(ServerBuilder.class));\n\t\t\t\tinOrder.verify(customizer1).customize(any(ServerBuilder.class));\n\t\t\t\tinOrder.verify(customizer2).customize(any(ServerBuilder.class));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid registersRuntimeHintsForValidatorCreation() {\n\t\tRuntimeHints hints = new RuntimeHints();\n\t\tnew MvcValidatorRuntimeHints().registerHints(hints, getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ValidatorAdapter.class)).accepts(hints);\n\t}\n\n\tprivate void assertResourceHttpRequestHandler(AssertableWebApplicationContext context,\n\t\t\tConsumer<ResourceHttpRequestHandler> handlerConsumer) {\n\t\tMap<String, Object> handlerMap = getHandlerMap(context.getBean(\"resourceHandlerMapping\", HandlerMapping.class));\n\t\tassertThat(handlerMap).hasSize(2);\n\t\tfor (Object handler : handlerMap.values()) {\n\t\t\tif (handler instanceof ResourceHttpRequestHandler resourceHandler) {\n\t\t\t\thandlerConsumer.accept(resourceHandler);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected Map<String, List<Resource>> getResourceMappingLocations(ApplicationContext context) {\n\t\tObject bean = context.getBean(\"resourceHandlerMapping\");\n\t\tif (bean instanceof HandlerMapping handlerMapping) {\n\t\t\treturn getMappingLocations(context, handlerMapping);\n\t\t}\n\t\tassertThat(bean).hasToString(\"null\");\n\t\treturn Collections.emptyMap();\n\t}\n\n\tprotected List<ResourceResolver> getResourceResolvers(ApplicationContext context, String mapping) {\n\t\tResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) context\n\t\t\t.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class)\n\t\t\t.getHandlerMap()\n\t\t\t.get(mapping);\n\t\tassertThat(resourceHandler).isNotNull();\n\t\treturn resourceHandler.getResourceResolvers();\n\t}\n\n\tprotected List<ResourceTransformer> getResourceTransformers(ApplicationContext context, String mapping) {\n\t\tSimpleUrlHandlerMapping handler = context.getBean(\"resourceHandlerMapping\", SimpleUrlHandlerMapping.class);\n\t\tResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler.getHandlerMap().get(mapping);\n\t\tassertThat(resourceHandler).isNotNull();\n\t\treturn resourceHandler.getResourceTransformers();\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprivate Map<String, List<Resource>> getMappingLocations(ApplicationContext context, HandlerMapping mapping) {\n\t\tMap<String, List<Resource>> mappingLocations = new LinkedHashMap<>();\n\t\tgetHandlerMap(mapping).forEach((key, value) -> {\n\t\t\tList<String> locationValues = (List<String>) ReflectionTestUtils.getField(value, \"locationValues\");\n\t\t\tassertThat(locationValues).isNotNull();\n\t\t\tList<Resource> locationResources = (List<Resource>) ReflectionTestUtils.getField(value,\n\t\t\t\t\t\"locationResources\");\n\t\t\tassertThat(locationResources).isNotNull();\n\t\t\tList<Resource> resources = new ArrayList<>();\n\t\t\tfor (String locationValue : locationValues) {\n\t\t\t\tresources.add(context.getResource(locationValue));\n\t\t\t}\n\t\t\tresources.addAll(locationResources);\n\t\t\tmappingLocations.put(key, resources);\n\t\t});\n\t\treturn mappingLocations;\n\t}\n\n\tprotected Map<String, Object> getHandlerMap(HandlerMapping mapping) {\n\t\tif (mapping instanceof SimpleUrlHandlerMapping handlerMapping) {\n\t\t\treturn handlerMapping.getHandlerMap();\n\t\t}\n\t\treturn Collections.emptyMap();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ViewConfig {\n\n\t\t@Bean\n\t\tView jsonView() {\n\t\t\treturn new AbstractView() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,\n\t\t\t\t\t\tHttpServletResponse response) throws Exception {\n\t\t\t\t\tresponse.getOutputStream().write(\"Hello World\".getBytes());\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebJars implements WebMvcConfigurer {\n\n\t\t@Override\n\t\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n\t\t\tregistry.addResourceHandler(\"/webjars/**\").addResourceLocations(\"classpath:/foo/\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AllResources implements WebMvcConfigurer {\n\n\t\t@Override\n\t\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n\t\t\tregistry.addResourceHandler(\"/**\").addResourceLocations(\"classpath:/foo/\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\tServletWebServerFactory webServerFactory() {\n\t\t\treturn webServerFactory;\n\t\t}\n\n\t\t@Bean\n\t\tstatic WebServerFactoryCustomizerBeanPostProcessor servletWebServerCustomizerBeanPostProcessor() {\n\t\t\treturn new WebServerFactoryCustomizerBeanPostProcessor();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomViewResolver {\n\n\t\t@Bean\n\t\tViewResolver viewResolver() {\n\t\t\treturn new MyViewResolver();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomContentNegotiatingViewResolver {\n\n\t\t@Bean\n\t\tContentNegotiatingViewResolver myViewResolver() {\n\t\t\treturn new ContentNegotiatingViewResolver();\n\t\t}\n\n\t}\n\n\tstatic class MyViewResolver implements ViewResolver {\n\n\t\t@Override\n\t\tpublic @Nullable View resolveViewName(String viewName, Locale locale) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConfigurableWebBindingInitializer {\n\n\t\t@Bean\n\t\tConfigurableWebBindingInitializer customConfigurableWebBindingInitializer() {\n\t\t\treturn new CustomWebBindingInitializer();\n\t\t}\n\n\t}\n\n\tstatic class CustomWebBindingInitializer extends ConfigurableWebBindingInitializer {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomFormContentFilter {\n\n\t\t@Bean\n\t\tFormContentFilter customFormContentFilter() {\n\t\t\treturn new FormContentFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRequestMappingHandlerMapping {\n\n\t\tprivate int handlerMappings;\n\n\t\t@Bean\n\t\tWebMvcRegistrations webMvcRegistrationsHandlerMapping() {\n\t\t\treturn new WebMvcRegistrations() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic RequestMappingHandlerMapping getRequestMappingHandlerMapping() {\n\t\t\t\t\tCustomRequestMappingHandlerMapping.this.handlerMappings++;\n\t\t\t\t\treturn new MyRequestMappingHandlerMapping();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class MyRequestMappingHandlerMapping extends RequestMappingHandlerMapping {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomRequestMappingHandlerAdapter {\n\n\t\tprivate int handlerAdapters;\n\n\t\t@Bean\n\t\tWebMvcRegistrations webMvcRegistrationsHandlerAdapter() {\n\t\t\treturn new WebMvcRegistrations() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {\n\t\t\t\t\tCustomRequestMappingHandlerAdapter.this.handlerAdapters++;\n\t\t\t\t\treturn new MyRequestMappingHandlerAdapter();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class MyRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomExceptionHandlerExceptionResolver {\n\n\t\tprivate int exceptionResolvers;\n\n\t\t@Bean\n\t\tWebMvcRegistrations webMvcRegistrationsExceptionResolver() {\n\t\t\treturn new WebMvcRegistrations() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() {\n\t\t\t\t\tCustomExceptionHandlerExceptionResolver.this.exceptionResolvers++;\n\t\t\t\t\treturn new MyExceptionHandlerExceptionResolver();\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class MyExceptionHandlerExceptionResolver extends ExceptionHandlerExceptionResolver {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ CustomRequestMappingHandlerMapping.class, CustomRequestMappingHandlerAdapter.class })\n\tstatic class MultipleWebMvcRegistrations {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MvcValidator implements WebMvcConfigurer {\n\n\t\tprivate final Validator validator = mock(Validator.class);\n\n\t\t@Override\n\t\tpublic Validator getValidator() {\n\t\t\treturn this.validator;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MvcJsr303Validator implements WebMvcConfigurer {\n\n\t\tprivate final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();\n\n\t\t@Override\n\t\tpublic Validator getValidator() {\n\t\t\treturn this.validator;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomJsr303Validator {\n\n\t\t@Bean\n\t\tjakarta.validation.Validator customJsr303Validator() {\n\t\t\treturn mock(jakarta.validation.Validator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSpringValidator {\n\n\t\t@Bean\n\t\tValidator customSpringValidator() {\n\t\t\treturn mock(Validator.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHttpMessageConverter {\n\n\t\t@Bean\n\t\tHttpMessageConverter<?> customHttpMessageConverter(ConversionService conversionService) {\n\t\t\treturn mock(HttpMessageConverter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomApplicationTaskExecutorConfig {\n\n\t\t@Bean\n\t\tExecutor applicationTaskExecutor() {\n\t\t\treturn mock(Executor.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAsyncTaskExecutorConfig {\n\n\t\t@Bean\n\t\tAsyncTaskExecutor customTaskExecutor() {\n\t\t\treturn mock(AsyncTaskExecutor.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomAsyncTaskExecutorConfigurer implements WebMvcConfigurer {\n\n\t\tprivate final AsyncTaskExecutor taskExecutor = mock(AsyncTaskExecutor.class);\n\n\t\t@Override\n\t\tpublic void configureAsyncSupport(AsyncSupportConfigurer configurer) {\n\t\t\tconfigurer.setTaskExecutor(this.taskExecutor);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestContextFilterConfiguration {\n\n\t\t@Bean\n\t\tRequestContextFilter customRequestContextFilter() {\n\t\t\treturn new RequestContextFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestContextFilterRegistrationConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<RequestContextFilter> customRequestContextFilterRegistration() {\n\t\t\treturn new FilterRegistrationBean<>(new RequestContextFilter());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class PrinterConfiguration {\n\n\t\t@Bean\n\t\tPrinter<Example> examplePrinter() {\n\t\t\treturn new ExamplePrinter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ParserConfiguration {\n\n\t\t@Bean\n\t\tParser<Example> exampleParser() {\n\t\t\treturn new ExampleParser();\n\t\t}\n\n\t}\n\n\tstatic final class Example {\n\n\t\tprivate final String name;\n\n\t\tprivate Example(String name, Date date) {\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tString getName() {\n\t\t\treturn this.name;\n\t\t}\n\n\t}\n\n\tstatic class ExamplePrinter implements Printer<Example> {\n\n\t\t@Override\n\t\tpublic String print(Example example, Locale locale) {\n\t\t\treturn example.getName();\n\t\t}\n\n\t}\n\n\tstatic class ExampleParser implements Parser<Example> {\n\n\t\t@Override\n\t\tpublic Example parse(String source, Locale locale) {\n\t\t\treturn new Example(source, new Date());\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class CorsConfigurer implements WebMvcConfigurer {\n\n\t\t@Override\n\t\tpublic void addCorsMappings(CorsRegistry registry) {\n\t\t\tregistry.addMapping(\"/**\").allowedMethods(\"GET\");\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AdditionalDispatcherServletConfiguration {\n\n\t\t@Bean\n\t\tServletRegistrationBean<DispatcherServlet> additionalDispatcherServlet() {\n\t\t\treturn new ServletRegistrationBean<>(new DispatcherServlet());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AdditionalUntypedDispatcherServletConfiguration {\n\n\t\t@Bean\n\t\tServletRegistrationBean<?> additionalDispatcherServlet() {\n\t\t\treturn new ServletRegistrationBean<>(new DispatcherServlet());\n\t\t}\n\n\t}\n\n\tstatic class CustomLocaleResolver implements LocaleResolver {\n\n\t\t@Override\n\t\tpublic Locale resolveLocale(HttpServletRequest request) {\n\t\t\treturn Locale.ENGLISH;\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response,\n\t\t\t\t@Nullable Locale locale) {\n\t\t}\n\n\t}\n\n\tstatic class CustomFlashMapManager extends AbstractFlashMapManager {\n\n\t\t@Override\n\t\tprotected @Nullable List<FlashMap> retrieveFlashMaps(HttpServletRequest request) {\n\t\t\treturn null;\n\t\t}\n\n\t\t@Override\n\t\tprotected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request,\n\t\t\t\tHttpServletResponse response) {\n\n\t\t}\n\n\t}\n\n\tstatic class CustomViewNameTranslator implements RequestToViewNameTranslator {\n\n\t\t@Override\n\t\tpublic @Nullable String getViewName(HttpServletRequest requestAttributes) {\n\t\t\treturn null;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ResourceHandlersWithChildAndParentContextConfiguration {\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tServletRegistrationBean<?> additionalDispatcherServlet(DispatcherServlet extraDispatcherServlet) {\n\t\t\tServletRegistrationBean<?> registration = new ServletRegistrationBean<>(extraDispatcherServlet, \"/extra/*\");\n\t\t\tregistration.setName(\"additionalDispatcherServlet\");\n\t\t\tregistration.setLoadOnStartup(1);\n\t\t\treturn registration;\n\t\t}\n\n\t\t@Bean\n\t\tprivate DispatcherServlet extraDispatcherServlet() {\n\t\t\tDispatcherServlet dispatcherServlet = new DispatcherServlet();\n\t\t\tAnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();\n\t\t\tapplicationContext.register(ResourceHandlersWithChildAndParentContextChildConfiguration.class);\n\t\t\tdispatcherServlet.setApplicationContext(applicationContext);\n\t\t\treturn dispatcherServlet;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebMvc\n\tstatic class ResourceHandlersWithChildAndParentContextChildConfiguration {\n\n\t\t@Bean\n\t\tWebMvcConfigurer myConfigurer() {\n\t\t\treturn new WebMvcConfigurer() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addResourceHandlers(ResourceHandlerRegistry registry) {\n\t\t\t\t\tregistry.addResourceHandler(\"/testtesttest\");\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomExceptionHandlerConfiguration {\n\n\t\t@Bean\n\t\tCustomExceptionHandler customExceptionHandler() {\n\t\t\treturn new CustomExceptionHandler();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ LowestOrderedControllerAdvice.class, HighestOrderedControllerAdvice.class })\n\tstatic class OrderedControllerAdviceBeansConfiguration {\n\n\t\t@ControllerAdvice\n\t\t@Order\n\t\tstatic class LowestOrderedControllerAdvice {\n\n\t\t}\n\n\t\t@ControllerAdvice\n\t\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t\tstatic class HighestOrderedControllerAdvice {\n\n\t\t}\n\n\t}\n\n\t@ControllerAdvice\n\tstatic class CustomExceptionHandler extends ResponseEntityExceptionHandler {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAspectJAutoProxy(proxyTargetClass = true)\n\tstatic class AopConfiguration {\n\n\t}\n\n\t@Aspect\n\tstatic class ExceptionHandlerInterceptor {\n\n\t\t@AfterReturning(pointcut = \"@annotation(org.springframework.web.bind.annotation.ExceptionHandler)\",\n\t\t\t\treturning = \"returnValue\")\n\t\tvoid exceptionHandlerIntercept(JoinPoint joinPoint, Object returnValue) {\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ApiVersionConfiguration {\n\n\t\t@Bean\n\t\tApiVersionResolver apiVersionResolver() {\n\t\t\treturn (request) -> \"latest\";\n\t\t}\n\n\t\t@Bean\n\t\tApiVersionDeprecationHandler apiVersionDeprecationHandler(ApiVersionParser<?> apiVersionParser) {\n\t\t\treturn new StandardApiVersionDeprecationHandler(apiVersionParser);\n\t\t}\n\n\t\t@Bean\n\t\tApiVersionParser<String> apiVersionParser() {\n\t\t\treturn (version) -> String.valueOf(version);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServerHttpMessageConverterCustomizersConfiguration {\n\n\t\t@Bean\n\t\t@Order(-5)\n\t\tServerHttpMessageConvertersCustomizer customizer1() {\n\t\t\treturn mock(ServerHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(5)\n\t\tServerHttpMessageConvertersCustomizer customizer2() {\n\t\t\treturn mock(ServerHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t\t@Bean\n\t\t@Order(-10)\n\t\tServerHttpMessageConvertersCustomizer customizer3() {\n\t\t\treturn mock(ServerHttpMessageConvertersCustomizer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcObservationAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.util.EnumSet;\n\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler.IgnoredMeters;\nimport io.micrometer.core.instrument.observation.MeterObservationHandler;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.micrometer.observation.Observation.Context;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.micrometer.metrics.MaximumAllowableTagsMeterFilter;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsProperties;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationProperties;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.http.server.observation.DefaultServerRequestObservationConvention;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.filter.ServerHttpObservationFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebMvcObservationAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Dmytro Nosan\n * @author Tadaya Tsuyukubo\n * @author Madhura Bhave\n * @author Chanhyeong LEE\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass WebMvcObservationAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(\n\t\t\t\tAutoConfigurations.of(ObservationAutoConfiguration.class, WebMvcObservationAutoConfiguration.class))\n\t\t.withBean(SimpleMeterRegistry.class);\n\n\t@Test\n\tvoid backsOffWhenObservationRegistryIsMissing() {\n\t\tnew WebApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(WebMvcObservationAutoConfiguration.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid backsOffWhenObservationPropertiesIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(ObservationProperties.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid definesFilterWhenRegistryIsPresent() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\t\tassertThat(context.getBean(FilterRegistrationBean.class).getFilter())\n\t\t\t\t.isInstanceOf(ServerHttpObservationFilter.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customConventionWhenPresent() {\n\t\tthis.contextRunner.withUserConfiguration(CustomConventionConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(FilterRegistrationBean.class).getFilter())\n\t\t\t\t.extracting(\"observationConvention\")\n\t\t\t\t.isInstanceOf(CustomConvention.class));\n\t}\n\n\t@Test\n\tvoid filterRegistrationHasExpectedDispatcherTypesAndOrder() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tFilterRegistrationBean<?> registration = context.getBean(FilterRegistrationBean.class);\n\t\t\tassertThat(registration).hasFieldOrPropertyWithValue(\"dispatcherTypes\",\n\t\t\t\t\tEnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC));\n\t\t\tassertThat(registration.getOrder()).isEqualTo(Ordered.HIGHEST_PRECEDENCE + 1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid filterRegistrationBacksOffWithAnotherServerHttpObservationFilterRegistration() {\n\t\tthis.contextRunner.withUserConfiguration(TestServerHttpObservationFilterRegistrationConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\t\t\tassertThat(context.getBean(FilterRegistrationBean.class))\n\t\t\t\t\t.isSameAs(context.getBean(\"testServerHttpObservationFilter\"));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid filterRegistrationBacksOffWithAnotherServerHttpObservationFilter() {\n\t\tthis.contextRunner.withUserConfiguration(TestServerHttpObservationFilterConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(FilterRegistrationBean.class)\n\t\t\t\t.hasSingleBean(ServerHttpObservationFilter.class));\n\t}\n\n\t@Test\n\tvoid filterRegistrationDoesNotBackOffWithOtherFilterRegistration() {\n\t\tthis.contextRunner.withUserConfiguration(TestFilterRegistrationConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"testFilter\").hasBean(\"webMvcObservationFilter\"));\n\t}\n\n\t@Test\n\tvoid filterRegistrationDoesNotBackOffWithOtherFilter() {\n\t\tthis.contextRunner.withUserConfiguration(TestFilterConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasBean(\"testFilter\").hasBean(\"webMvcObservationFilter\"));\n\t}\n\n\t@Test\n\tvoid afterMaxUrisReachedFurtherUrisAreDenied(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestController.class, MetricsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\tWebMvcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.web.server.max-uri-tags=2\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context);\n\t\t\t\tassertThat(registry.get(\"http.server.requests\").meters()).hasSizeLessThanOrEqualTo(2);\n\t\t\t\tassertThat(output).contains(\"Reached the maximum number of 'uri' tags for 'http.server.requests'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid afterMaxUrisReachedFurtherUrisAreDeniedWhenUsingCustomObservationName(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestController.class, MetricsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\tWebMvcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.web.server.max-uri-tags=2\",\n\t\t\t\t\t\"management.observations.http.server.requests.name=my.http.server.requests\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context);\n\t\t\t\tassertThat(registry.get(\"my.http.server.requests\").meters()).hasSizeLessThanOrEqualTo(2);\n\t\t\t\tassertThat(output).contains(\"Reached the maximum number of 'uri' tags for 'my.http.server.requests'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotDenyNorLogIfMaxUrisIsNotReached(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TestController.class, MetricsConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(MetricsAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\t\t\tWebMvcAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"management.metrics.web.server.max-uri-tags=5\")\n\t\t\t.run((context) -> {\n\t\t\t\tMeterRegistry registry = getInitializedMeterRegistry(context);\n\t\t\t\tassertThat(registry.get(\"http.server.requests\").meters()).hasSize(3);\n\t\t\t\tassertThat(output)\n\t\t\t\t\t.doesNotContain(\"Reached the maximum number of 'uri' tags for 'http.server.requests'\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffIfMetricsPropertiesIsNotPresent() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(MetricsProperties.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MaximumAllowableTagsMeterFilter.class));\n\t}\n\n\tprivate MeterRegistry getInitializedMeterRegistry(AssertableWebApplicationContext context) {\n\t\treturn getInitializedMeterRegistry(context, \"/test0\", \"/test1\", \"/test2\");\n\t}\n\n\tprivate MeterRegistry getInitializedMeterRegistry(AssertableWebApplicationContext context, String... urls) {\n\t\tassertThat(context).hasSingleBean(FilterRegistrationBean.class);\n\t\tFilter filter = context.getBean(FilterRegistrationBean.class).getFilter();\n\t\tassertThat(filter).isInstanceOf(ServerHttpObservationFilter.class);\n\t\tMockMvcTester mvc = MockMvcTester.from(context, (builder) -> builder.addFilters(filter).build());\n\t\tfor (String url : urls) {\n\t\t\tassertThat(mvc.get().uri(url)).hasStatusOk();\n\t\t}\n\t\treturn context.getBean(MeterRegistry.class);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestServerHttpObservationFilterRegistrationConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tFilterRegistrationBean<ServerHttpObservationFilter> testServerHttpObservationFilter() {\n\t\t\treturn mock(FilterRegistrationBean.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestServerHttpObservationFilterConfiguration {\n\n\t\t@Bean\n\t\tServerHttpObservationFilter testServerHttpObservationFilter() {\n\t\t\treturn new ServerHttpObservationFilter(TestObservationRegistry.create());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestFilterRegistrationConfiguration {\n\n\t\t@Bean\n\t\t@SuppressWarnings(\"unchecked\")\n\t\tFilterRegistrationBean<Filter> testFilter() {\n\t\t\treturn mock(FilterRegistrationBean.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestFilterConfiguration {\n\n\t\t@Bean\n\t\tFilter testFilter() {\n\t\t\treturn mock(Filter.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomConventionConfiguration {\n\n\t\t@Bean\n\t\tCustomConvention customConvention() {\n\t\t\treturn new CustomConvention();\n\t\t}\n\n\t}\n\n\tstatic class CustomConvention extends DefaultServerRequestObservationConvention {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class MetricsConfiguration {\n\n\t\t@Bean\n\t\tMeterObservationHandler<Context> meterObservationHandler(MeterRegistry registry) {\n\t\t\treturn new DefaultMeterObservationHandler(registry, IgnoredMeters.LONG_TASK_TIMER);\n\t\t}\n\n\t}\n\n\t@RestController\n\tstatic class TestController {\n\n\t\t@GetMapping(\"test0\")\n\t\tString test0() {\n\t\t\treturn \"test0\";\n\t\t}\n\n\t\t@GetMapping(\"test1\")\n\t\tString test1() {\n\t\t\treturn \"test1\";\n\t\t}\n\n\t\t@GetMapping(\"test2\")\n\t\tString test2() {\n\t\t\treturn \"test2\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WebMvcPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.assertj.core.util.Throwables;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.bind.BindException;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.context.properties.source.ConfigurationPropertySource;\nimport org.springframework.boot.context.properties.source.MapConfigurationPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link WebMvcProperties}.\n *\n * @author Stephane Nicoll\n */\nclass WebMvcPropertiesTests {\n\n\tprivate final WebMvcProperties properties = new WebMvcProperties();\n\n\t@Test\n\tvoid servletPathWhenEndsWithSlashHasValidMappingAndPrefix() {\n\t\tbind(\"spring.mvc.servlet.path\", \"/foo/\");\n\t\tassertThat(this.properties.getServlet().getServletMapping()).isEqualTo(\"/foo/*\");\n\t\tassertThat(this.properties.getServlet().getServletPrefix()).isEqualTo(\"/foo\");\n\t}\n\n\t@Test\n\tvoid servletPathWhenDoesNotEndWithSlashHasValidMappingAndPrefix() {\n\t\tbind(\"spring.mvc.servlet.path\", \"/foo\");\n\t\tassertThat(this.properties.getServlet().getServletMapping()).isEqualTo(\"/foo/*\");\n\t\tassertThat(this.properties.getServlet().getServletPrefix()).isEqualTo(\"/foo\");\n\t}\n\n\t@Test\n\tvoid servletPathWhenHasWildcardThrowsException() {\n\t\tassertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(\"spring.mvc.servlet.path\", \"/*\"))\n\t\t\t.withRootCauseInstanceOf(IllegalArgumentException.class)\n\t\t\t.satisfies((ex) -> assertThat(Throwables.getRootCause(ex)).hasMessage(\"'path' must not contain wildcards\"));\n\t}\n\n\tprivate void bind(String name, String value) {\n\t\tbind(Collections.singletonMap(name, value));\n\t}\n\n\tprivate void bind(Map<String, String> map) {\n\t\tConfigurationPropertySource source = new MapConfigurationPropertySource(map);\n\t\tnew Binder(source).bind(\"spring.mvc\", Bindable.ofInstance(this.properties));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WelcomePageHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ByteArrayResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.servlet.ViewResolver;\nimport org.springframework.web.servlet.view.AbstractView;\nimport org.springframework.web.servlet.view.InternalResourceView;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WelcomePageHandlerMapping}.\n *\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass WelcomePageHandlerMappingTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(HandlerMappingConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid isOrderedAtLowPriority() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class).run((context) -> {\n\t\t\tWelcomePageHandlerMapping handler = context.getBean(WelcomePageHandlerMapping.class);\n\t\t\tassertThat(handler.getOrder()).isEqualTo(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid handlesRequestForStaticPageThatAcceptsTextHtml() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.TEXT_HTML)).hasStatusOk()\n\t\t\t\t.hasForwardedUrl(\"index.html\")));\n\t}\n\n\t@Test\n\tvoid handlesRequestForStaticPageThatAcceptsAll() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.ALL)).hasStatusOk()\n\t\t\t\t.hasForwardedUrl(\"index.html\")));\n\t}\n\n\t@Test\n\tvoid doesNotHandleRequestThatDoesNotAcceptTextHtml() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.APPLICATION_JSON))\n\t\t\t\t.hasStatus(HttpStatus.NOT_FOUND)));\n\t}\n\n\t@Test\n\tvoid handlesRequestWithNoAcceptHeader() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\")).hasStatusOk().hasForwardedUrl(\"index.html\")));\n\t}\n\n\t@Test\n\tvoid handlesRequestWithEmptyAcceptHeader() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").header(HttpHeaders.ACCEPT, \"\")).hasStatusOk()\n\t\t\t\t.hasForwardedUrl(\"index.html\")));\n\t}\n\n\t@Test\n\tvoid rootHandlerIsNotRegisteredWhenStaticPathPatternIsNotSlashStarStar() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.withPropertyValues(\"static-path-pattern=/foo/**\")\n\t\t\t.run((context) -> assertThat(context.getBean(WelcomePageHandlerMapping.class).getRootHandler()).isNull());\n\t}\n\n\t@Test\n\tvoid producesNotFoundResponseWhenThereIsNoWelcomePage() {\n\t\tthis.contextRunner.run(testWith(\n\t\t\t\t(mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.TEXT_HTML)).hasStatus(HttpStatus.NOT_FOUND)));\n\t}\n\n\t@Test\n\tvoid handlesRequestForTemplateThatAcceptsTextHtml() {\n\t\tthis.contextRunner.withUserConfiguration(TemplateConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.TEXT_HTML)).hasStatusOk()\n\t\t\t\t.hasBodyTextEqualTo(\"index template\")));\n\t}\n\n\t@Test\n\tvoid handlesRequestForTemplateThatAcceptsAll() {\n\t\tthis.contextRunner.withUserConfiguration(TemplateConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.ALL)).hasStatusOk()\n\t\t\t\t.hasBodyTextEqualTo(\"index template\")));\n\t}\n\n\t@Test\n\tvoid prefersAStaticResourceToATemplate() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class, TemplateConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.ALL)).hasStatusOk()\n\t\t\t\t.hasForwardedUrl(\"index.html\")));\n\t}\n\n\t@Test\n\tvoid logsInvalidAcceptHeader(CapturedOutput output) {\n\t\tthis.contextRunner.withUserConfiguration(TemplateConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(\"*/*q=0.8\")).hasStatusOk()\n\t\t\t\t.hasBodyTextEqualTo(\"index template\")));\n\t\tassertThat(output).contains(\"Received invalid Accept header. Assuming all media types are accepted\");\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> testWith(ThrowingConsumer<MockMvcTester> mvc) {\n\t\treturn (context) -> mvc.accept(MockMvcTester.from(context));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HandlerMappingConfiguration {\n\n\t\t@Bean\n\t\tWelcomePageHandlerMapping handlerMapping(ApplicationContext applicationContext,\n\t\t\t\tObjectProvider<TemplateAvailabilityProviders> templateAvailabilityProviders,\n\t\t\t\tObjectProvider<Resource> staticIndexPage,\n\t\t\t\t@Value(\"${static-path-pattern:/**}\") String staticPathPattern) {\n\t\t\treturn new WelcomePageHandlerMapping(\n\t\t\t\t\ttemplateAvailabilityProviders\n\t\t\t\t\t\t.getIfAvailable(() -> new TemplateAvailabilityProviders(applicationContext)),\n\t\t\t\t\tapplicationContext, staticIndexPage.getIfAvailable(), staticPathPattern);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StaticResourceConfiguration {\n\n\t\t@Bean\n\t\tResource staticIndexPage() {\n\t\t\treturn new ByteArrayResource(\"welcome-page-static\".getBytes(StandardCharsets.UTF_8));\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TemplateConfiguration {\n\n\t\t@Bean\n\t\tTemplateAvailabilityProviders templateAvailabilityProviders() {\n\t\t\treturn new TestTemplateAvailabilityProviders(\n\t\t\t\t\t(view, environment, classLoader, resourceLoader) -> view.equals(\"index\"));\n\t\t}\n\n\t\t@Bean\n\t\tViewResolver viewResolver() {\n\t\t\treturn (name, locale) -> {\n\t\t\t\tif (name.startsWith(\"forward:\")) {\n\t\t\t\t\treturn new InternalResourceView(name.substring(\"forward:\".length()));\n\t\t\t\t}\n\t\t\t\treturn new AbstractView() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,\n\t\t\t\t\t\t\tHttpServletResponse response) throws Exception {\n\t\t\t\t\t\tresponse.getWriter().print(name + \" template\");\n\t\t\t\t\t}\n\n\t\t\t\t};\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class TestTemplateAvailabilityProviders extends TemplateAvailabilityProviders {\n\n\t\tTestTemplateAvailabilityProviders(TemplateAvailabilityProvider provider) {\n\t\t\tsuper(Collections.singletonList(provider));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WelcomePageIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.context.WebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the welcome page.\n *\n * @author Madhura Bhave\n * @author Andy Wilkinson\n */\n@WithResource(name = \"static/index.html\", content = \"custom welcome page\")\nclass WelcomePageIntegrationTests {\n\n\tprivate WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withPropertyValues(\"spring.web.resources.chain.strategy.content.enabled=true\", \"server.port=0\")\n\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\tWebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\t\tTomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class));\n\n\tprivate final TestRestTemplate template = new TestRestTemplate();\n\n\t@Test\n\tvoid contentStrategyWithWelcomePage() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebServer webServer = ((WebServerApplicationContext) context.getSourceApplicationContext()).getWebServer();\n\t\t\tassertThat(webServer).isNotNull();\n\t\t\tint port = webServer.getPort();\n\t\t\tRequestEntity<?> entity = RequestEntity.get(new URI(\"http://localhost:\" + port + \"/\"))\n\t\t\t\t.header(\"Accept\", MediaType.ALL.toString())\n\t\t\t\t.build();\n\t\t\tResponseEntity<String> content = this.template.exchange(entity, String.class);\n\t\t\tassertThat(content.getBody()).contains(\"custom welcome page\");\n\t\t\tassertThat(content.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t});\n\t}\n\n\t@Test\n\tvoid notAcceptableWelcomePage() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tWebServer webServer = ((WebServerApplicationContext) context.getSourceApplicationContext()).getWebServer();\n\t\t\tassertThat(webServer).isNotNull();\n\t\t\tint port = webServer.getPort();\n\t\t\tRequestEntity<?> entity = RequestEntity.get(new URI(\"http://localhost:\" + port + \"/\"))\n\t\t\t\t.header(\"Accept\", \"spring/boot\")\n\t\t\t\t.build();\n\t\t\tResponseEntity<String> content = this.template.exchange(entity, String.class);\n\t\t\tassertThat(content.getStatusCode()).isEqualTo(HttpStatus.NOT_ACCEPTABLE);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/WelcomePageNotAcceptableHandlerMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure;\n\nimport jakarta.servlet.ServletContext;\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WelcomePageNotAcceptableHandlerMapping}.\n *\n * @author Phillip Webb\n */\nclass WelcomePageNotAcceptableHandlerMappingTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(HandlerMappingConfiguration.class)\n\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class));\n\n\t@Test\n\tvoid isOrderedAtLowPriorityButAboveResourceHandlerRegistry() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class).run((context) -> {\n\t\t\tWelcomePageNotAcceptableHandlerMapping handler = context\n\t\t\t\t.getBean(WelcomePageNotAcceptableHandlerMapping.class);\n\t\t\tResourceHandlerRegistry registry = new ResourceHandlerRegistry(context, mock(ServletContext.class));\n\t\t\tInteger resourceOrder = (Integer) ReflectionTestUtils.getField(registry, \"order\");\n\t\t\tassertThat(handler.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE - 10);\n\t\t\tassertThat(handler.getOrder()).isLessThan(resourceOrder);\n\t\t});\n\t}\n\n\t@Test\n\tvoid handlesRequestForStaticPageThatAcceptsTextHtml() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.TEXT_HTML))\n\t\t\t\t.hasStatus(HttpStatus.NOT_ACCEPTABLE)));\n\t}\n\n\t@Test\n\tvoid handlesRequestForStaticPageThatDoesNotAcceptTextHtml() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.APPLICATION_JSON))\n\t\t\t\t.hasStatus(HttpStatus.NOT_ACCEPTABLE)));\n\t}\n\n\t@Test\n\tvoid handlesRequestWithNoAcceptHeader() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\")).hasStatus(HttpStatus.NOT_ACCEPTABLE)));\n\t}\n\n\t@Test\n\tvoid handlesRequestWithEmptyAcceptHeader() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.run(testWith((mvc) -> assertThat(mvc.get().uri(\"/\").header(HttpHeaders.ACCEPT, \"\"))\n\t\t\t\t.hasStatus(HttpStatus.NOT_ACCEPTABLE)));\n\t}\n\n\t@Test\n\tvoid rootHandlerIsNotRegisteredWhenStaticPathPatternIsNotSlashStarStar() {\n\t\tthis.contextRunner.withUserConfiguration(StaticResourceConfiguration.class)\n\t\t\t.withPropertyValues(\"static-path-pattern=/foo/**\")\n\t\t\t.run((context) -> assertThat(context.getBean(WelcomePageNotAcceptableHandlerMapping.class).getRootHandler())\n\t\t\t\t.isNull());\n\t}\n\n\t@Test\n\tvoid producesNotFoundResponseWhenThereIsNoWelcomePage() {\n\t\tthis.contextRunner.run(testWith(\n\t\t\t\t(mvc) -> assertThat(mvc.get().uri(\"/\").accept(MediaType.TEXT_HTML)).hasStatus(HttpStatus.NOT_FOUND)));\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> testWith(ThrowingConsumer<MockMvcTester> mvc) {\n\t\treturn (context) -> mvc.accept(MockMvcTester.from(context));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HandlerMappingConfiguration {\n\n\t\t@Bean\n\t\tWelcomePageNotAcceptableHandlerMapping handlerMapping(ApplicationContext applicationContext,\n\t\t\t\tObjectProvider<TemplateAvailabilityProviders> templateAvailabilityProviders,\n\t\t\t\tObjectProvider<Resource> staticIndexPage,\n\t\t\t\t@Value(\"${static-path-pattern:/**}\") String staticPathPattern) {\n\t\t\treturn new WelcomePageNotAcceptableHandlerMapping(\n\t\t\t\t\ttemplateAvailabilityProviders\n\t\t\t\t\t\t.getIfAvailable(() -> new TemplateAvailabilityProviders(applicationContext)),\n\t\t\t\t\tapplicationContext, staticIndexPage.getIfAvailable(), staticPathPattern);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class StaticResourceConfiguration {\n\n\t\t@Bean\n\t\tResource staticIndexPage() {\n\t\t\treturn new FileSystemResource(\"src/test/resources/welcome-page/index.html\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/endpoint/web/WebMvcHealthEndpointAdditionalPathIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.integrationtest.AbstractHealthEndpointAdditionalPathIntegrationTests;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.application.DiskSpaceHealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementContextAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\n\n/**\n * Integration tests for MVC health groups on an additional path.\n *\n * @author Madhura Bhave\n */\nclass WebMvcHealthEndpointAdditionalPathIntegrationTests extends\n\t\tAbstractHealthEndpointAdditionalPathIntegrationTests<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {\n\n\tWebMvcHealthEndpointAdditionalPathIntegrationTests() {\n\t\tsuper(new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)\n\t\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,\n\t\t\t\t\tHealthContributorAutoConfiguration.class, HealthContributorRegistryAutoConfiguration.class,\n\t\t\t\t\tHttpMessageConvertersAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\t\tTomcatServletWebServerAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,\n\t\t\t\t\tTomcatServletManagementContextAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\t\t\tServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\t\tEndpointAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\t\tHealthEndpointAutoConfiguration.class, WebMvcHealthEndpointExtensionAutoConfiguration.class,\n\t\t\t\t\tDiskSpaceHealthContributorAutoConfiguration.class))\n\t\t\t.withInitializer(new ServerPortInfoApplicationContextInitializer())\n\t\t\t.withPropertyValues(\"server.port=0\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/endpoint/web/WebMvcHealthEndpointExtensionAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.endpoint.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpointWebExtension;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcHealthEndpointExtensionAutoConfiguration}.\n *\n * @author Stephane Nicoll\n */\nclass WebMvcHealthEndpointExtensionAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,\n\t\t\t\tHealthContributorRegistryAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tWebMvcHealthEndpointExtensionAutoConfiguration.class));\n\n\t@Test\n\t@WithTestEndpointOutcomeExposureContributor\n\tvoid additionalHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {\n\t\tthis.contextRunner\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))\n\t\t\t.withBean(DispatcherServlet.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.exclude=*\",\n\t\t\t\t\t\"management.endpoints.test.exposure.include=*\")\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasNotFailed();\n\t\t\t\tassertThat(context).hasSingleBean(HealthEndpoint.class);\n\t\t\t\tassertThat(context).hasSingleBean(HealthEndpointWebExtension.class);\n\t\t\t\tassertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();\n\t\t\t\tassertThat(context).hasSingleBean(AdditionalHealthEndpointPathsWebMvcHandlerMapping.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithTestEndpointOutcomeExposureContributor\n\tvoid backsOffWithoutWebEndpointInfrastructure() {\n\t\tthis.contextRunner.withConfiguration(AutoConfigurations.of(EndpointAutoConfiguration.class))\n\t\t\t.withBean(DispatcherServlet.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.exclude=*\",\n\t\t\t\t\t\"management.endpoints.test.exposure.include=*\")\n\t\t\t.run((context) -> assertThat(context)\n\t\t\t\t.doesNotHaveBean(AdditionalHealthEndpointPathsWebMvcHandlerMapping.class));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HealthIndicatorsConfiguration {\n\n\t\t@Bean\n\t\tHealthIndicator simpleHealthIndicator() {\n\t\t\treturn () -> Health.up().withDetail(\"counter\", 42).build();\n\t\t}\n\n\t\t@Bean\n\t\tHealthIndicator additionalHealthIndicator() {\n\t\t\treturn () -> Health.up().build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/CompositeHandlerExceptionResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.web.HttpRequestMethodNotSupportedException;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CompositeHandlerExceptionResolver}.\n *\n * @author Madhura Bhave\n * @author Scott Frederick\n */\nclass CompositeHandlerExceptionResolverTests {\n\n\tprivate @Nullable AnnotationConfigApplicationContext context;\n\n\tprivate final MockHttpServletRequest request = new MockHttpServletRequest();\n\n\tprivate final MockHttpServletResponse response = new MockHttpServletResponse();\n\n\t@Test\n\tvoid resolverShouldDelegateToOtherResolversInContext() {\n\t\tload(TestConfiguration.class);\n\t\tassertThat(this.context).isNotNull();\n\t\tCompositeHandlerExceptionResolver resolver = (CompositeHandlerExceptionResolver) this.context\n\t\t\t.getBean(DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME);\n\t\tModelAndView resolved = resolver.resolveException(this.request, this.response, null,\n\t\t\t\tnew HttpRequestMethodNotSupportedException(\"POST\"));\n\t\tassertThat(resolved).isNotNull();\n\t\tassertThat(resolved.getViewName()).isEqualTo(\"test-view\");\n\t}\n\n\t@Test\n\tvoid resolverShouldAddDefaultResolverIfNonePresent() {\n\t\tload(BaseConfiguration.class);\n\t\tassertThat(this.context).isNotNull();\n\t\tCompositeHandlerExceptionResolver resolver = (CompositeHandlerExceptionResolver) this.context\n\t\t\t.getBean(DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME);\n\t\tHttpRequestMethodNotSupportedException exception = new HttpRequestMethodNotSupportedException(\"POST\");\n\t\tModelAndView resolved = resolver.resolveException(this.request, this.response, null, exception);\n\t\tassertThat(resolved).isNotNull();\n\t\tassertThat(resolved.isEmpty()).isTrue();\n\t}\n\n\tprivate void load(Class<?>... configs) {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(configs);\n\t\tcontext.refresh();\n\t\tthis.context = context;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean(name = DispatcherServlet.HANDLER_EXCEPTION_RESOLVER_BEAN_NAME)\n\t\tCompositeHandlerExceptionResolver compositeHandlerExceptionResolver() {\n\t\t\treturn new CompositeHandlerExceptionResolver();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\t@Bean\n\t\tHandlerExceptionResolver testResolver() {\n\t\t\treturn new TestHandlerExceptionResolver();\n\t\t}\n\n\t}\n\n\tstatic class TestHandlerExceptionResolver implements HandlerExceptionResolver {\n\n\t\t@Override\n\t\tpublic ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\t@Nullable Object handler, Exception ex) {\n\t\t\treturn new ModelAndView(\"test-view\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ControllerEndpointWebMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.bind.annotation.GetMapping;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Actuator's MVC\n * {@link org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint\n * controller endpoints}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass ControllerEndpointWebMvcIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@AfterEach\n\tvoid close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid endpointsCanBeAccessed() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(DefaultConfiguration.class, ExampleController.class);\n\t\tTestPropertyValues\n\t\t\t.of(\"management.endpoints.web.base-path:/management\", \"management.endpoints.web.exposure.include=*\")\n\t\t\t.applyTo(this.context);\n\t\tMockMvcTester mvc = createMockMvcTester();\n\t\tassertThat(mvc.get().uri(\"/management/example\")).hasStatusOk();\n\t}\n\n\tprivate MockMvcTester createMockMvcTester() {\n\t\tassertThat(this.context).isNotNull();\n\t\tthis.context.setServletContext(new MockServletContext());\n\t\tthis.context.refresh();\n\t\treturn MockMvcTester.from(this.context);\n\t}\n\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\tServletManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tManagementContextAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\tBeansEndpointAutoConfiguration.class })\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"example\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class ExampleController {\n\n\t\t@GetMapping(\"/\")\n\t\tString example() {\n\t\t\treturn \"Example\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/ManagementErrorEndpointTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.web.ErrorProperties;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.webmvc.error.DefaultErrorAttributes;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.web.context.request.ServletWebRequest;\nimport org.springframework.web.context.request.WebRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Tests for {@link ManagementErrorEndpoint}.\n *\n * @author Scott Frederick\n */\nclass ManagementErrorEndpointTests {\n\n\tprivate final ErrorAttributes errorAttributes = new DefaultErrorAttributes();\n\n\tprivate final ErrorProperties errorProperties = new ErrorProperties();\n\n\tprivate final MockHttpServletRequest request = new MockHttpServletRequest();\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", new RuntimeException(\"test exception\"));\n\t}\n\n\t@Test\n\tvoid errorResponseNeverDetails() {\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));\n\t\tassertThat(response).doesNotContainKey(\"message\");\n\t\tassertThat(response).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\tvoid errorResponseAlwaysDetails() {\n\t\tthis.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ALWAYS);\n\t\tthis.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ALWAYS);\n\t\tthis.request.addParameter(\"trace\", \"false\");\n\t\tthis.request.addParameter(\"message\", \"false\");\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(this.request));\n\t\tassertThat(response).containsEntry(\"message\", \"test exception\");\n\t\tassertThat(response).hasEntrySatisfying(\"trace\",\n\t\t\t\t(value) -> assertThat(value).asString().startsWith(\"java.lang.RuntimeException: test exception\"));\n\t}\n\n\t@Test\n\tvoid errorResponseParamsAbsent() {\n\t\tthis.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ON_PARAM);\n\t\tthis.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(this.request));\n\t\tassertThat(response).doesNotContainKey(\"message\");\n\t\tassertThat(response).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\tvoid errorResponseParamsTrue() {\n\t\tthis.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ON_PARAM);\n\t\tthis.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);\n\t\tthis.request.addParameter(\"trace\", \"true\");\n\t\tthis.request.addParameter(\"message\", \"true\");\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(this.request));\n\t\tassertThat(response).containsEntry(\"message\", \"test exception\");\n\t\tassertThat(response).hasEntrySatisfying(\"trace\",\n\t\t\t\t(value) -> assertThat(value).asString().startsWith(\"java.lang.RuntimeException: test exception\"));\n\t}\n\n\t@Test\n\tvoid errorResponseParamsFalse() {\n\t\tthis.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeAttribute.ON_PARAM);\n\t\tthis.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);\n\t\tthis.request.addParameter(\"trace\", \"false\");\n\t\tthis.request.addParameter(\"message\", \"false\");\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(this.request));\n\t\tassertThat(response).doesNotContainKey(\"message\");\n\t\tassertThat(response).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\tvoid errorResponseWithCustomErrorAttributesUsingDeprecatedApi() {\n\t\tErrorAttributes attributes = new ErrorAttributes() {\n\n\t\t\t@Override\n\t\t\tpublic Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest,\n\t\t\t\t\tErrorAttributeOptions options) {\n\t\t\t\treturn Collections.singletonMap(\"message\", \"An error occurred\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic @Nullable Throwable getError(WebRequest webRequest) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t};\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(attributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));\n\t\tassertThat(response).containsExactly(entry(\"message\", \"An error occurred\"));\n\t}\n\n\t@Test\n\tvoid errorResponseWithDefaultErrorAttributesSubclassUsingDelegation() {\n\t\tErrorAttributes attributes = new DefaultErrorAttributes() {\n\n\t\t\t@Override\n\t\t\tpublic Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest,\n\t\t\t\t\tErrorAttributeOptions options) {\n\t\t\t\tMap<String, @Nullable Object> response = super.getErrorAttributes(webRequest, options);\n\t\t\t\tresponse.put(\"error\", \"custom error\");\n\t\t\t\tresponse.put(\"custom\", \"value\");\n\t\t\t\tresponse.remove(\"path\");\n\t\t\t\treturn response;\n\t\t\t}\n\n\t\t};\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(attributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));\n\t\tassertThat(response).containsEntry(\"error\", \"custom error\");\n\t\tassertThat(response).containsEntry(\"custom\", \"value\");\n\t\tassertThat(response).doesNotContainKey(\"path\");\n\t\tassertThat(response).containsKey(\"timestamp\");\n\t}\n\n\t@Test\n\tvoid errorResponseWithDefaultErrorAttributesSubclassWithoutDelegation() {\n\t\tErrorAttributes attributes = new DefaultErrorAttributes() {\n\n\t\t\t@Override\n\t\t\tpublic Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest,\n\t\t\t\t\tErrorAttributeOptions options) {\n\t\t\t\treturn Collections.singletonMap(\"error\", \"custom error\");\n\t\t\t}\n\n\t\t};\n\t\tManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(attributes, this.errorProperties);\n\t\tMap<String, @Nullable Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));\n\t\tassertThat(response).containsExactly(entry(\"error\", \"custom error\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointAccessIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.io.IOException;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for controlling access to endpoints exposed by Spring MVC.\n *\n * @author Andy Wilkinson\n */\nclass WebMvcEndpointAccessIntegrationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(TomcatServletWebServerAutoConfiguration.class,\n\t\t\t\tTomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\tJacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\t\tWebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tManagementContextAutoConfiguration.class, ServletManagementContextAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class, BeansEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(CustomMvcEndpoint.class, CustomServletEndpoint.class)\n\t\t.withPropertyValues(\"server.port:0\");\n\n\t@Test\n\tvoid accessIsUnrestrictedByDefault() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\").run((context) -> {\n\t\t\tRestClient client = createClient(context);\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"custommvc\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"custommvc\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isTrue();\n\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeReadOnlyByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"custommvc\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeNoneByDefault() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessForOneEndpointCanOverrideTheDefaultAccess() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=READ_ONLY\",\n\t\t\t\t\t\"management.endpoint.customservlet.access=UNRESTRICTED\")\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"custommvc\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isTrue();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtReadOnly() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\",\n\t\t\t\t\t\"management.endpoints.access.max-permitted=READ_ONLY\")\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"custommvc\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isTrue();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid accessCanBeCappedAtNone() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\"management.endpoints.access.default=UNRESTRICTED\", \"management.endpoints.access.max-permitted=NONE\")\n\t\t\t.run((context) -> {\n\t\t\t\tRestClient client = createClient(context);\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"custommvc\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.GET, \"customservlet\")).isFalse();\n\t\t\t\tassertThat(isAccessible(client, HttpMethod.POST, \"customservlet\")).isFalse();\n\t\t\t});\n\t}\n\n\tprivate RestClient createClient(AssertableWebApplicationContext context) {\n\t\tWebServer webServer = context.getSourceApplicationContext(ServletWebServerApplicationContext.class)\n\t\t\t.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tint port = webServer.getPort();\n\t\treturn RestClient.builder().defaultStatusHandler((status) -> true, (request, response) -> {\n\t\t}).baseUrl(\"http://localhost:\" + port).build();\n\t}\n\n\tprivate boolean isAccessible(RestClient client, HttpMethod method, String path) {\n\t\tpath = \"/actuator/\" + path;\n\t\tResponseEntity<byte[]> result = client.method(method).uri(path).retrieve().toEntity(byte[].class);\n\t\tif (result.getStatusCode() == HttpStatus.OK) {\n\t\t\treturn true;\n\t\t}\n\t\tif (result.getStatusCode() == HttpStatus.NOT_FOUND || result.getStatusCode() == HttpStatus.METHOD_NOT_ALLOWED) {\n\t\t\treturn false;\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\tString.format(\"Unexpected %s HTTP status for endpoint %s\", result.getStatusCode(), path));\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"custommvc\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class CustomMvcEndpoint {\n\n\t\t@GetMapping(\"/\")\n\t\tString get() {\n\t\t\treturn \"get\";\n\t\t}\n\n\t\t@PostMapping(\"/\")\n\t\tString post() {\n\t\t\treturn \"post\";\n\t\t}\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"customservlet\")\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic class CustomServletEndpoint\n\t\t\timplements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {\n\n\t\t@Override\n\t\tpublic org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {\n\t\t\treturn new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doPost(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointChildContextConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport jakarta.validation.Valid;\nimport jakarta.validation.constraints.NotEmpty;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.convert.ApplicationConversionService;\nimport org.springframework.boot.env.ConfigTreePropertySource;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.actuate.web.server.TomcatServletManagementContextAutoConfiguration;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.http.MediaType;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.client.RestClient;\nimport org.springframework.web.client.RestClient.RequestHeadersSpec.ExchangeFunction;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link WebMvcEndpointChildContextConfiguration}.\n *\n * @author Phillip Webb\n * @author Scott Frederick\n */\nclass WebMvcEndpointChildContextConfigurationIntegrationTests {\n\n\tprivate final WebApplicationContextRunner runner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(ManagementContextAutoConfiguration.class,\n\t\t\t\tTomcatServletWebServerAutoConfiguration.class, TomcatServletManagementContextAutoConfiguration.class,\n\t\t\t\tServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tEndpointAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\tErrorMvcAutoConfiguration.class))\n\t\t.withUserConfiguration(SucceedingEndpoint.class, FailingEndpoint.class, FailingControllerEndpoint.class)\n\t\t.withInitializer(new ServerPortInfoApplicationContextInitializer())\n\t\t.withPropertyValues(\"server.port=0\", \"management.server.port=0\", \"management.endpoints.web.exposure.include=*\",\n\t\t\t\t\"spring.web.error.include-exception=true\", \"spring.web.error.include-message=always\",\n\t\t\t\t\"spring.web.error.include-binding-errors=always\");\n\n\t@TempDir\n\t@SuppressWarnings(\"NullAway.Init\")\n\tPath temp;\n\n\t@Test // gh-17938\n\tvoid errorEndpointIsUsedWithEndpoint() {\n\t\tthis.runner.run(withRestClient((client) -> {\n\t\t\tMap<String, ?> body = client.get()\n\t\t\t\t.uri(\"actuator/fail\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange(toResponseBody());\n\t\t\tassertThat(body).hasEntrySatisfying(\"exception\",\n\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"IllegalStateException\"));\n\t\t\tassertThat(body).hasEntrySatisfying(\"message\",\n\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"Epic Fail\"));\n\t\t}));\n\t}\n\n\t@Test\n\tvoid errorPageAndErrorControllerIncludeDetails() {\n\t\tthis.runner\n\t\t\t.withPropertyValues(\"spring.web.error.include-stacktrace=always\", \"spring.web.error.include-message=always\")\n\t\t\t.run(withRestClient((client) -> {\n\t\t\t\tMap<String, ?> body = client.get()\n\t\t\t\t\t.uri(\"actuator/fail\")\n\t\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t\t.exchange(toResponseBody());\n\t\t\t\tassertThat(body).hasEntrySatisfying(\"message\",\n\t\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"Epic Fail\"));\n\t\t\t\tassertThat(body).hasEntrySatisfying(\"trace\",\n\t\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"java.lang.IllegalStateException: Epic Fail\"));\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid errorEndpointIsUsedWithRestControllerEndpoint() {\n\t\tthis.runner.run(withRestClient((client) -> {\n\t\t\tMap<String, ?> body = client.get()\n\t\t\t\t.uri(\"actuator/failController\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange(toResponseBody());\n\t\t\tassertThat(body).hasEntrySatisfying(\"exception\",\n\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"IllegalStateException\"));\n\t\t\tassertThat(body).hasEntrySatisfying(\"message\",\n\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"Epic Fail\"));\n\t\t}));\n\t}\n\n\t@Test\n\tvoid errorEndpointIsUsedWithRestControllerEndpointOnBindingError() {\n\t\tthis.runner.run(withRestClient((client) -> {\n\t\t\tMap<String, ?> body = client.post()\n\t\t\t\t.uri(\"actuator/failController\")\n\t\t\t\t.body(Collections.singletonMap(\"content\", \"\"))\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.exchange(toResponseBody());\n\t\t\tassertThat(body).hasEntrySatisfying(\"exception\",\n\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"MethodArgumentNotValidException\"));\n\t\t\tassertThat(body).hasEntrySatisfying(\"message\",\n\t\t\t\t\t(value) -> assertThat(value).asString().contains(\"Validation failed\"));\n\t\t\tassertThat(body).hasEntrySatisfying(\"errors\",\n\t\t\t\t\t(value) -> assertThat(value).asInstanceOf(InstanceOfAssertFactories.LIST).isNotEmpty());\n\t\t}));\n\t}\n\n\t@Test\n\tvoid whenManagementServerBasePathIsConfiguredThenEndpointsAreBeneathThatPath() {\n\t\tthis.runner.withPropertyValues(\"management.server.base-path:/manage\").run(withRestClient((client) -> {\n\t\t\tString body = client.get()\n\t\t\t\t.uri(\"manage/actuator/success\")\n\t\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t\t.retrieve()\n\t\t\t\t.body(String.class);\n\t\t\tassertThat(body).isEqualTo(\"Success\");\n\t\t}));\n\t}\n\n\t@Test // gh-32941\n\tvoid whenManagementServerPortLoadedFromConfigTree() {\n\t\tthis.runner.withInitializer(this::addConfigTreePropertySource)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\tprivate void addConfigTreePropertySource(ConfigurableApplicationContext applicationContext) {\n\t\ttry {\n\t\t\tapplicationContext.getEnvironment()\n\t\t\t\t.setConversionService((ConfigurableConversionService) ApplicationConversionService.getSharedInstance());\n\t\t\tPath configtree = this.temp.resolve(\"configtree\");\n\t\t\tPath file = configtree.resolve(\"management/server/port\");\n\t\t\tfile.toFile().getParentFile().mkdirs();\n\t\t\tFileCopyUtils.copy(\"0\".getBytes(StandardCharsets.UTF_8), file.toFile());\n\t\t\tConfigTreePropertySource source = new ConfigTreePropertySource(\"configtree\", configtree);\n\t\t\tapplicationContext.getEnvironment().getPropertySources().addFirst(source);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate ContextConsumer<AssertableWebApplicationContext> withRestClient(Consumer<RestClient> restClient) {\n\t\treturn (context) -> {\n\t\t\tString port = context.getEnvironment().getProperty(\"local.management.port\");\n\t\t\tRestClient client = RestClient.create(\"http://localhost:\" + port);\n\t\t\trestClient.accept(client);\n\t\t};\n\t}\n\n\tprivate ExchangeFunction<Map<String, ?>> toResponseBody() {\n\t\treturn (request, response) -> {\n\t\t\tMap<String, ?> body = response.bodyTo(new ParameterizedTypeReference<>() {\n\t\t\t});\n\t\t\tassertThat(body).isNotNull();\n\t\t\treturn body;\n\t\t};\n\t}\n\n\t@Endpoint(id = \"fail\")\n\tstatic class FailingEndpoint {\n\n\t\t@ReadOperation\n\t\tString fail() {\n\t\t\tthrow new IllegalStateException(\"Epic Fail\");\n\t\t}\n\n\t}\n\n\t@Endpoint(id = \"success\")\n\tstatic class SucceedingEndpoint {\n\n\t\t@ReadOperation\n\t\tString fail() {\n\t\t\treturn \"Success\";\n\t\t}\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"failController\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class FailingControllerEndpoint {\n\n\t\t@GetMapping\n\t\tString fail() {\n\t\t\tthrow new IllegalStateException(\"Epic Fail\");\n\t\t}\n\n\t\t@PostMapping(produces = \"application/json\")\n\t\t@ResponseBody\n\t\tString bodyValidation(@Valid @RequestBody TestBody body) {\n\t\t\treturn body.getContent();\n\t\t}\n\n\t}\n\n\tpublic static class TestBody {\n\n\t\t@NotEmpty\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String content;\n\n\t\tpublic String getContent() {\n\t\t\treturn this.content;\n\t\t}\n\n\t\tpublic void setContent(String content) {\n\t\t\tthis.content = content;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointChildContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.servlet.filter.OrderedRequestContextFilter;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.context.request.RequestContextListener;\nimport org.springframework.web.filter.RequestContextFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcEndpointChildContextConfiguration}.\n *\n * @author Madhura Bhave\n */\nclass WebMvcEndpointChildContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withAllowBeanDefinitionOverriding(true);\n\n\t@Test\n\tvoid contextShouldConfigureRequestContextFilter() {\n\t\tthis.contextRunner.withUserConfiguration(WebMvcEndpointChildContextConfiguration.class)\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(OrderedRequestContextFilter.class));\n\t}\n\n\t@Test\n\tvoid contextShouldNotConfigureRequestContextFilterWhenPresent() {\n\t\tthis.contextRunner.withUserConfiguration(ExistingConfig.class, WebMvcEndpointChildContextConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RequestContextFilter.class);\n\t\t\t\tassertThat(context).hasBean(\"testRequestContextFilter\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextShouldNotConfigureRequestContextFilterWhenRequestContextListenerPresent() {\n\t\tthis.contextRunner\n\t\t\t.withUserConfiguration(RequestContextListenerConfig.class, WebMvcEndpointChildContextConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(RequestContextListener.class);\n\t\t\t\tassertThat(context).doesNotHaveBean(OrderedRequestContextFilter.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid contextShouldConfigureDispatcherServletPathWithRootPath() {\n\t\tthis.contextRunner.withUserConfiguration(WebMvcEndpointChildContextConfiguration.class)\n\t\t\t.run((context) -> assertThat(context.getBean(DispatcherServletPath.class).getPath()).isEqualTo(\"/\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ExistingConfig {\n\n\t\t@Bean\n\t\tRequestContextFilter testRequestContextFilter() {\n\t\t\treturn new RequestContextFilter();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class RequestContextListenerConfig {\n\n\t\t@Bean\n\t\tRequestContextListener testRequestContextListener() {\n\t\t\treturn new RequestContextListener();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointCorsIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport org.assertj.core.api.ThrowingConsumer;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.test.web.servlet.assertj.MvcTestResult;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the MVC actuator endpoints' CORS support\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @see WebMvcEndpointManagementContextConfiguration\n */\nclass WebMvcEndpointCorsIntegrationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,\n\t\t\t\tHttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\t\tDispatcherServletAutoConfiguration.class, EndpointAutoConfiguration.class,\n\t\t\t\tWebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\tServletManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class))\n\t\t.withPropertyValues(\"management.endpoints.web.exposure.include:*\");\n\n\t@Test\n\tvoid corsIsDisabledByDefault() {\n\t\tthis.contextRunner.run(withMockMvc((mvc) -> assertThat(mvc.options()\n\t\t\t.uri(\"/actuator/beans\")\n\t\t\t.header(\"Origin\", \"foo.example.com\")\n\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\"))\n\t\t\t.doesNotContainHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)));\n\t}\n\n\t@Test\n\tvoid settingAllowedOriginsEnablesCors() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\")\n\t\t\t.run(withMockMvc((mvc) -> {\n\t\t\t\tassertThat(mvc.options()\n\t\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t\t.header(\"Origin\", \"bar.example.com\")\n\t\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")).hasStatus(HttpStatus.FORBIDDEN);\n\t\t\t\tperformAcceptedCorsRequest(mvc);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid settingAllowedOriginPatternsEnablesCors() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origin-patterns:*.example.com\",\n\t\t\t\t\t\"management.endpoints.web.cors.allow-credentials:true\")\n\t\t\t.run(withMockMvc((mvc) -> {\n\t\t\t\tassertThat(mvc.options()\n\t\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t\t.header(\"Origin\", \"bar.example.org\")\n\t\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")).hasStatus(HttpStatus.FORBIDDEN);\n\t\t\t\tperformAcceptedCorsRequest(mvc);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid maxAgeDefaultsTo30Minutes() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\")\n\t\t\t.run(withMockMvc((mvc) -> {\n\t\t\t\tMvcTestResult result = performAcceptedCorsRequest(mvc);\n\t\t\t\tassertThat(result).hasHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, \"1800\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid maxAgeCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\",\n\t\t\t\t\t\"management.endpoints.web.cors.max-age: 2400\")\n\t\t\t.run(withMockMvc((mvc) -> {\n\t\t\t\tMvcTestResult result = performAcceptedCorsRequest(mvc);\n\t\t\t\tassertThat(result).hasHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, \"2400\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid requestsWithDisallowedHeadersAreRejected() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\")\n\t\t\t.run(withMockMvc((mvc) -> assertThat(mvc.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(\"Origin\", \"foo.example.com\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, \"Alpha\")).hasStatus(HttpStatus.FORBIDDEN)));\n\t}\n\n\t@Test\n\tvoid allowedHeadersCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\",\n\t\t\t\t\t\"management.endpoints.web.cors.allowed-headers:Alpha,Bravo\")\n\t\t\t.run(withMockMvc((mvc) -> assertThat(mvc.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(\"Origin\", \"foo.example.com\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, \"Alpha\")).hasStatusOk()\n\t\t\t\t.headers()\n\t\t\t\t.hasValue(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, \"Alpha\")));\n\t}\n\n\t@Test\n\tvoid requestsWithDisallowedMethodsAreRejected() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\")\n\t\t\t.run(withMockMvc((mvc) -> assertThat(mvc.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(HttpHeaders.ORIGIN, \"foo.example.com\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"PATCH\")).hasStatus(HttpStatus.FORBIDDEN)));\n\t}\n\n\t@Test\n\tvoid allowedMethodsCanBeConfigured() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\",\n\t\t\t\t\t\"management.endpoints.web.cors.allowed-methods:GET,HEAD\")\n\t\t\t.run(withMockMvc((mvc) -> assertThat(mvc.options()\n\t\t\t\t.uri(\"/actuator/beans\")\n\t\t\t\t.header(HttpHeaders.ORIGIN, \"foo.example.com\")\n\t\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"HEAD\")).hasStatusOk()\n\t\t\t\t.headers()\n\t\t\t\t.hasValue(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, \"GET,HEAD\")));\n\t}\n\n\t@Test\n\tvoid credentialsCanBeAllowed() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\",\n\t\t\t\t\t\"management.endpoints.web.cors.allow-credentials:true\")\n\t\t\t.run(withMockMvc((mvc) -> {\n\t\t\t\tMvcTestResult result = performAcceptedCorsRequest(mvc);\n\t\t\t\tassertThat(result).hasHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, \"true\");\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid credentialsCanBeDisabled() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.cors.allowed-origins:foo.example.com\",\n\t\t\t\t\t\"management.endpoints.web.cors.allow-credentials:false\")\n\t\t\t.run(withMockMvc((mvc) -> {\n\t\t\t\tMvcTestResult result = performAcceptedCorsRequest(mvc);\n\t\t\t\tassertThat(result).doesNotContainHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS);\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<WebApplicationContext> withMockMvc(ThrowingConsumer<MockMvcTester> mvc) {\n\t\treturn (context) -> mvc.accept(MockMvcTester.from(context));\n\t}\n\n\tprivate MvcTestResult performAcceptedCorsRequest(MockMvcTester mvc) {\n\t\treturn performAcceptedCorsRequest(mvc, \"/actuator/beans\");\n\t}\n\n\tprivate MvcTestResult performAcceptedCorsRequest(MockMvcTester mvc, String url) {\n\t\tMvcTestResult result = mvc.options()\n\t\t\t.uri(url)\n\t\t\t.header(HttpHeaders.ORIGIN, \"foo.example.com\")\n\t\t\t.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, \"GET\")\n\t\t\t.exchange();\n\t\tassertThat(result).hasStatusOk().hasHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, \"foo.example.com\");\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointExposureIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.io.IOException;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndpointAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;\nimport org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.exchanges.ServletHttpExchangesAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Endpoints over Spring MVC.\n *\n * @author Stephane Nicoll\n * @author Phillip Webb\n */\nclass WebMvcEndpointExposureIntegrationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(\n\t\t\tAnnotationConfigServletWebServerApplicationContext::new)\n\t\t.withConfiguration(AutoConfigurations.of(TomcatServletWebServerAutoConfiguration.class,\n\t\t\t\tTomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\t\tJacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\t\tWebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\t\tManagementContextAutoConfiguration.class, ManagementContextAutoConfiguration.class,\n\t\t\t\tServletManagementContextAutoConfiguration.class, ServletHttpExchangesAutoConfiguration.class,\n\t\t\t\tHealthContributorAutoConfiguration.class, HealthContributorRegistryAutoConfiguration.class,\n\t\t\t\tBeansEndpointAutoConfiguration.class, HealthEndpointAutoConfiguration.class,\n\t\t\t\tShutdownEndpointAutoConfiguration.class))\n\t\t.withUserConfiguration(CustomMvcEndpoint.class, CustomServletEndpoint.class,\n\t\t\t\tHttpExchangeRepositoryConfiguration.class, AuditEventRepositoryConfiguration.class)\n\t\t.withPropertyValues(\"server.port:0\");\n\n\t@Test\n\tvoid webEndpointsExceptHealthAreDisabledByDefault() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tRestClient client = createClient(context);\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"health\")).isTrue();\n\t\t\tassertThat(isExposed(client, HttpMethod.POST, \"shutdown\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid webEndpointsCanBeExposed() {\n\t\tWebApplicationContextRunner contextRunner = this.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=*\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tRestClient client = createClient(context);\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"health\")).isTrue();\n\t\t\tassertThat(isExposed(client, HttpMethod.POST, \"shutdown\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid singleWebEndpointCanBeExposed() {\n\t\tWebApplicationContextRunner contextRunner = this.contextRunner\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=beans\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tRestClient client = createClient(context);\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"beans\")).isTrue();\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"health\")).isFalse();\n\t\t\tassertThat(isExposed(client, HttpMethod.POST, \"shutdown\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tvoid singleWebEndpointCanBeExcluded() {\n\t\tWebApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(\n\t\t\t\t\"management.endpoints.web.exposure.include=*\", \"management.endpoints.web.exposure.exclude=beans\");\n\t\tcontextRunner.run((context) -> {\n\t\t\tRestClient client = createClient(context);\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"beans\")).isFalse();\n\t\t\tassertThat(isExposed(client, HttpMethod.GET, \"health\")).isTrue();\n\t\t\tassertThat(isExposed(client, HttpMethod.POST, \"shutdown\")).isFalse();\n\t\t});\n\t}\n\n\tprivate RestClient createClient(AssertableWebApplicationContext context) {\n\t\tWebServer webServer = context.getSourceApplicationContext(ServletWebServerApplicationContext.class)\n\t\t\t.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tint port = webServer.getPort();\n\t\treturn RestClient.builder().defaultStatusHandler((status) -> true, (request, response) -> {\n\t\t}).baseUrl(\"http://localhost:\" + port).build();\n\t}\n\n\tprivate boolean isExposed(RestClient client, HttpMethod method, String path) {\n\t\tpath = \"/actuator/\" + path;\n\t\tResponseEntity<byte[]> result = client.method(method).uri(path).retrieve().toEntity(byte[].class);\n\t\tif (result.getStatusCode() == HttpStatus.OK) {\n\t\t\treturn true;\n\t\t}\n\t\tif (result.getStatusCode() == HttpStatus.NOT_FOUND) {\n\t\t\treturn false;\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\tString.format(\"Unexpected %s HTTP status for endpoint %s\", result.getStatusCode(), path));\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"custommvc\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class CustomMvcEndpoint {\n\n\t\t@GetMapping(\"/\")\n\t\tString main() {\n\t\t\treturn \"test\";\n\t\t}\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"customservlet\")\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic class CustomServletEndpoint\n\t\t\timplements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {\n\n\t\t@Override\n\t\tpublic org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {\n\t\t\treturn new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp)\n\t\t\t\t\t\tthrows ServletException, IOException {\n\t\t\t\t}\n\n\t\t\t});\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class HttpExchangeRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryHttpExchangeRepository httpExchangeRepository() {\n\t\t\treturn new InMemoryHttpExchangeRepository();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class AuditEventRepositoryConfiguration {\n\n\t\t@Bean\n\t\tInMemoryAuditEventRepository auditEventRepository() {\n\t\t\treturn new InMemoryAuditEventRepository();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.http.HttpServlet;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.json.JsonMapper;\nimport tools.jackson.databind.jsontype.TypeSerializer;\nimport tools.jackson.databind.module.SimpleModule;\nimport tools.jackson.databind.ser.std.StdScalarSerializer;\n\nimport org.springframework.boot.actuate.autoconfigure.audit.AuditAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.actuate.web.ServletManagementContextAutoConfiguration;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.util.pattern.PathPatternParser;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the Actuator's MVC endpoints.\n *\n * @author Andy Wilkinson\n */\nclass WebMvcEndpointIntegrationTests {\n\n\tprivate @Nullable AnnotationConfigServletWebApplicationContext context;\n\n\t@Test\n\tvoid webMvcEndpointHandlerMappingIsConfiguredWithPathPatternParser() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(DefaultConfiguration.class);\n\t\tthis.context.setServletContext(new MockServletContext());\n\t\tthis.context.refresh();\n\t\tWebMvcEndpointHandlerMapping handlerMapping = this.context.getBean(WebMvcEndpointHandlerMapping.class);\n\t\tassertThat(handlerMapping.getPatternParser()).isInstanceOf(PathPatternParser.class);\n\t}\n\n\t@Test\n\tvoid linksAreProvidedToAllEndpointTypes() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(DefaultConfiguration.class, EndpointsConfiguration.class);\n\t\tTestPropertyValues.of(\"management.endpoints.web.exposure.include=*\").applyTo(this.context);\n\t\tMockMvcTester mvc = doCreateMockMvcTester();\n\t\tassertThat(mvc.get().uri(\"/actuator\").accept(\"*/*\")).hasStatusOk()\n\t\t\t.bodyJson()\n\t\t\t.extractingPath(\"_links\")\n\t\t\t.asMap()\n\t\t\t.containsKeys(\"beans\", \"servlet\", \"restcontroller\", \"controller\");\n\t}\n\n\t@Test\n\tvoid linksPageIsNotAvailableWhenDisabled() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(DefaultConfiguration.class, EndpointsConfiguration.class);\n\t\tTestPropertyValues.of(\"management.endpoints.web.discovery.enabled=false\").applyTo(this.context);\n\t\tMockMvcTester mvc = doCreateMockMvcTester();\n\t\tassertThat(mvc.get().uri(\"/actuator\").accept(\"*/*\")).hasStatus(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid endpointJsonMapperCanBeApplied() {\n\t\tthis.context = new AnnotationConfigServletWebApplicationContext();\n\t\tthis.context.register(EndpointJsonMapperConfiguration.class, DefaultConfiguration.class);\n\t\tTestPropertyValues.of(\"management.endpoints.web.exposure.include=*\").applyTo(this.context);\n\t\tMockMvcTester mvc = doCreateMockMvcTester();\n\t\tassertThat(mvc.get().uri(\"/actuator/beans\")).hasStatusOk().bodyText().contains(\"\\\"scope\\\":\\\"notelgnis\\\"\");\n\t}\n\n\tprivate MockMvcTester doCreateMockMvcTester() {\n\t\tassertThat(this.context).isNotNull();\n\t\tthis.context.setServletContext(new MockServletContext());\n\t\tthis.context.refresh();\n\t\treturn MockMvcTester.from(this.context);\n\t}\n\n\t@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,\n\t\t\tServletManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tManagementContextAutoConfiguration.class, AuditAutoConfiguration.class,\n\t\t\tDispatcherServletAutoConfiguration.class, BeansEndpointAutoConfiguration.class })\n\tstatic class DefaultConfiguration {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint(id = \"servlet\")\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\tstatic class TestServletEndpoint\n\t\t\timplements Supplier<org.springframework.boot.actuate.endpoint.web.EndpointServlet> {\n\n\t\t@Override\n\t\tpublic org.springframework.boot.actuate.endpoint.web.EndpointServlet get() {\n\t\t\treturn new org.springframework.boot.actuate.endpoint.web.EndpointServlet(new HttpServlet() {\n\t\t\t});\n\t\t}\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint(id = \"controller\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestControllerEndpoint {\n\n\t}\n\n\t@org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint(id = \"restcontroller\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestRestControllerEndpoint {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class EndpointsConfiguration {\n\n\t\t@Bean\n\t\tTestServletEndpoint testServletEndpoint() {\n\t\t\treturn new TestServletEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestControllerEndpoint testControllerEndpoint() {\n\t\t\treturn new TestControllerEndpoint();\n\t\t}\n\n\t\t@Bean\n\t\tTestRestControllerEndpoint testRestControllerEndpoint() {\n\t\t\treturn new TestRestControllerEndpoint();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tstatic class EndpointJsonMapperConfiguration {\n\n\t\t@Bean\n\t\tEndpointJsonMapper endpointJsonMapper() {\n\t\t\tSimpleModule module = new SimpleModule();\n\t\t\tmodule.addSerializer(String.class, new ReverseStringSerializer());\n\t\t\tJsonMapper jsonMapper = JsonMapper.builder().addModule(module).build();\n\t\t\treturn () -> jsonMapper;\n\t\t}\n\n\t\tstatic class ReverseStringSerializer extends StdScalarSerializer<Object> {\n\n\t\t\tReverseStringSerializer() {\n\t\t\t\tsuper(String.class, false);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic boolean isEmpty(SerializationContext context, Object value) {\n\t\t\t\treturn ((String) value).isEmpty();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void serialize(Object value, JsonGenerator gen, SerializationContext context) {\n\t\t\t\tserialize(value, gen);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic final void serializeWithType(Object value, JsonGenerator gen, SerializationContext context,\n\t\t\t\t\tTypeSerializer typeSer) {\n\t\t\t\tserialize(value, gen);\n\t\t\t}\n\n\t\t\tprivate void serialize(Object value, JsonGenerator gen) {\n\t\t\t\tStringBuilder builder = new StringBuilder((String) value);\n\t\t\t\tgen.writeString(builder.reverse().toString());\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/WebMvcEndpointManagementContextConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;\nimport org.springframework.boot.actuate.endpoint.Access;\nimport org.springframework.boot.actuate.endpoint.EndpointAccessResolver;\nimport org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcEndpointManagementContextConfiguration}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n */\n@SuppressWarnings(\"removal\")\nclass WebMvcEndpointManagementContextConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfig.class)\n\t\t.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,\n\t\t\t\tEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class));\n\n\t@Test\n\tvoid contextShouldContainServletEndpointRegistrar() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(ServletEndpointRegistrar.class);\n\t\t\tServletEndpointRegistrar bean = context.getBean(ServletEndpointRegistrar.class);\n\t\t\tassertThat(bean).hasFieldOrPropertyWithValue(\"basePath\", \"/test/actuator\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid contextWhenNotServletBasedShouldNotContainServletEndpointRegistrar() {\n\t\tnew ApplicationContextRunner().withUserConfiguration(TestConfig.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ServletEndpointRegistrar.class));\n\t}\n\n\t@Test\n\t@ClassPathExclusions(packages = \"org.springframework.boot.health.actuate.endpoint\")\n\tvoid refreshSucceedsWithoutHealth() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(WebMvcEndpointManagementContextConfiguration.class)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tServletEndpointsSupplier servletEndpointsSupplier() {\n\t\t\treturn Collections::emptyList;\n\t\t}\n\n\t\t@Bean\n\t\tDispatcherServletPath dispatcherServletPath() {\n\t\t\treturn () -> \"/test\";\n\t\t}\n\n\t\t@Bean\n\t\tEndpointAccessResolver endpointAccessResolver() {\n\t\t\treturn (endpointId, defaultAccess) -> Access.UNRESTRICTED;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/actuate/web/mappings/WebMvcMappingsAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.actuate.web.mappings;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.webmvc.actuate.web.mappings.DispatcherServletsMappingDescriptionProvider;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcMappingsAutoConfiguration}.\n *\n * @author Andy Wilkinson\n */\nclass WebMvcMappingsAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebMvcMappingsAutoConfiguration.class));\n\n\t@Test\n\tvoid whenEndpointIsUnavailableThenDescriptionProviderIsNotCreated() {\n\t\tthis.contextRunner.withBean(DispatcherServlet.class)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DispatcherServletsMappingDescriptionProvider.class));\n\t}\n\n\t@Test\n\tvoid whenEndpointIsAvailableButThereIsNoDispatcherServletThenDescriptionProviderIsNotCreated() {\n\t\tthis.contextRunner.withPropertyValues(\"management.endpoints.web.exposure.include=mappings\")\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(DispatcherServletsMappingDescriptionProvider.class));\n\t}\n\n\t@Test\n\tvoid whenEndpointIsAvailableThenDescriptionProviderIsCreated() {\n\t\tthis.contextRunner.withBean(DispatcherServlet.class)\n\t\t\t.withPropertyValues(\"management.endpoints.web.exposure.include=mappings\")\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(DispatcherServletsMappingDescriptionProvider.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorControllerDirectMockMvcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport jakarta.servlet.ServletException;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.test.util.ApplicationContextTestUtils;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.EnableAspectJAutoProxy;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.context.ConfigurableWebApplicationContext;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BasicErrorController} using {@link MockMvcTester} but not\n * {@link org.springframework.test.context.junit.jupiter.SpringExtension}.\n *\n * @author Dave Syer\n * @author Sebastien Deleuze\n */\nclass BasicErrorControllerDirectMockMvcTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ConfigurableWebApplicationContext wac;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate MockMvcTester mvc;\n\n\t@AfterEach\n\tvoid close() {\n\t\tApplicationContextTestUtils.closeAll(this.wac);\n\t}\n\n\tvoid setup(ConfigurableWebApplicationContext context) {\n\t\tthis.wac = context;\n\t\tthis.mvc = MockMvcTester.from(this.wac);\n\t}\n\n\t@Test\n\tvoid errorPageAvailableWithParentContext() {\n\t\tsetup((ConfigurableWebApplicationContext) new SpringApplicationBuilder(ParentConfiguration.class)\n\t\t\t.child(ChildConfiguration.class)\n\t\t\t.run(\"--server.port=0\"));\n\t\tassertThat(this.mvc.get().uri(\"/error\").accept(MediaType.TEXT_HTML)).hasStatus5xxServerError()\n\t\t\t.bodyText()\n\t\t\t.contains(\"status=999\");\n\t}\n\n\t@Test\n\tvoid errorPageAvailableWithMvcIncluded() {\n\t\tsetup((ConfigurableWebApplicationContext) new SpringApplication(WebMvcIncludedConfiguration.class)\n\t\t\t.run(\"--server.port=0\"));\n\t\tassertThat(this.mvc.get().uri(\"/error\").accept(MediaType.TEXT_HTML)).hasStatus5xxServerError()\n\t\t\t.bodyText()\n\t\t\t.contains(\"status=999\");\n\t}\n\n\t@Test\n\tvoid errorPageNotAvailableWithWhitelabelDisabled() {\n\t\tsetup((ConfigurableWebApplicationContext) new SpringApplication(WebMvcIncludedConfiguration.class)\n\t\t\t.run(\"--server.port=0\", \"--spring.web.error.whitelabel.enabled=false\"));\n\t\tassertThat(this.mvc.get().uri(\"/error\").accept(MediaType.TEXT_HTML)).hasFailed()\n\t\t\t.failure()\n\t\t\t.isInstanceOf(ServletException.class);\n\t}\n\n\t@Test\n\tvoid errorControllerWithAop() {\n\t\tsetup((ConfigurableWebApplicationContext) new SpringApplication(WithAopConfiguration.class)\n\t\t\t.run(\"--server.port=0\"));\n\t\tassertThat(this.mvc.get().uri(\"/error\").accept(MediaType.TEXT_HTML)).hasStatus5xxServerError()\n\t\t\t.bodyText()\n\t\t\t.contains(\"status=999\");\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\tWebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\tstatic class ParentConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\t@EnableWebMvc\n\tstatic class WebMvcIncludedConfiguration {\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(WebMvcIncludedConfiguration.class, args);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\tstatic class VanillaConfiguration {\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(VanillaConfiguration.class, args);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\tstatic class ChildConfiguration {\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tnew SpringApplicationBuilder(ParentConfiguration.class).child(ChildConfiguration.class).run(args);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAspectJAutoProxy(proxyTargetClass = false)\n\t@MinimalWebConfiguration\n\t@Aspect\n\tstatic class WithAopConfiguration {\n\n\t\t@Pointcut(\"within(@org.springframework.stereotype.Controller *)\")\n\t\tprivate void controllerPointCut() {\n\t\t}\n\n\t\t@Around(\"controllerPointCut()\")\n\t\tObject mvcAdvice(ProceedingJoinPoint pjp) throws Throwable {\n\t\t\treturn pjp.proceed();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorControllerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.net.URI;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.validation.Valid;\nimport jakarta.validation.constraints.NotNull;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.autoconfigure.web.WebProperties;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.validation.BindException;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestAttribute;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.view.AbstractView;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BasicErrorController} using a real HTTP server.\n *\n * @author Phillip Webb\n * @author Dave Syer\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\nclass BasicErrorControllerIntegrationTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid testErrorForMachineClientDefault() {\n\t\tload();\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"?trace=true\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"500\", \"Internal Server Error\", null, null, \"/\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"exception\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\tvoid testErrorForMachineClientWithParamsTrue() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-stacktrace=on-param\",\n\t\t\t\t\"--spring.web.error.include-message=on-param\");\n\t\texceptionWithStackTraceAndMessage(\"?trace=true&message=true\");\n\t}\n\n\t@Test\n\tvoid testErrorForMachineClientWithParamsFalse() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-stacktrace=on-param\",\n\t\t\t\t\"--spring.web.error.include-message=on-param\");\n\t\texceptionWithoutStackTraceAndMessage(\"?trace=false&message=false\");\n\t}\n\n\t@Test\n\tvoid testErrorForMachineClientWithParamsAbsent() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-stacktrace=on-param\",\n\t\t\t\t\"--spring.web.error.include-message=on-param\");\n\t\texceptionWithoutStackTraceAndMessage(\"\");\n\t}\n\n\t@Test\n\tvoid testErrorForMachineClientNeverParams() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-stacktrace=never\",\n\t\t\t\t\"--spring.web.error.include-message=never\");\n\t\texceptionWithoutStackTraceAndMessage(\"?trace=true&message=true\");\n\t}\n\n\t@Test\n\tvoid testErrorForMachineClientAlwaysParams() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-stacktrace=always\",\n\t\t\t\t\"--spring.web.error.include-message=always\");\n\t\texceptionWithStackTraceAndMessage(\"?trace=false&message=false\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid testErrorForMachineClientAlwaysParamsWithoutMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=always\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/noMessage\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"500\", \"Internal Server Error\", IllegalStateException.class,\n\t\t\t\t\"No message available\", \"/noMessage\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void exceptionWithStackTraceAndMessage(String path) {\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(path), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"500\", \"Internal Server Error\", IllegalStateException.class,\n\t\t\t\t\"Expected!\", \"/\");\n\t\tassertThat(entity.getBody()).containsKey(\"trace\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void exceptionWithoutStackTraceAndMessage(String path) {\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(path), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"500\", \"Internal Server Error\", IllegalStateException.class, null, \"/\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid testErrorForAnnotatedExceptionWithoutMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/annotated\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", TestConfiguration.Errors.ExpectedException.class,\n\t\t\t\tnull, \"/annotated\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid testErrorForAnnotatedExceptionWithMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=always\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/annotated\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", TestConfiguration.Errors.ExpectedException.class,\n\t\t\t\t\"Expected!\", \"/annotated\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid testErrorForAnnotatedNoReasonExceptionWithoutMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/annotatedNoReason\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"406\", \"Not Acceptable\",\n\t\t\t\tTestConfiguration.Errors.NoReasonExpectedException.class, null, \"/annotatedNoReason\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid testErrorForAnnotatedNoReasonExceptionWithMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=always\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/annotatedNoReason\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"406\", \"Not Acceptable\",\n\t\t\t\tTestConfiguration.Errors.NoReasonExpectedException.class, \"Expected message\", \"/annotatedNoReason\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid testErrorForAnnotatedNoMessageExceptionWithMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=always\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/annotatedNoMessage\"), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"406\", \"Not Acceptable\",\n\t\t\t\tTestConfiguration.Errors.NoReasonExpectedException.class, \"No message available\",\n\t\t\t\t\"/annotatedNoMessage\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientWithErrorsParamTrue() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-binding-errors=on-param\");\n\t\tbindingExceptionWithErrors(\"?errors=true\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientWithErrorsParamFalse() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-binding-errors=on-param\");\n\t\tbindingExceptionWithoutErrors(\"?errors=false\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientWithErrorsParamAbsent() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-binding-errors=on-param\");\n\t\tbindingExceptionWithoutErrors(\"\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientAlwaysErrors() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-binding-errors=always\");\n\t\tbindingExceptionWithErrors(\"?errors=false\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientNeverErrors() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-binding-errors=never\");\n\t\tbindingExceptionWithoutErrors(\"?errors=true\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientWithMessageParamTrue() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=on-param\");\n\t\tbindingExceptionWithMessage(\"?message=true\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientWithMessageParamFalse() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=on-param\");\n\t\tbindingExceptionWithoutMessage(\"?message=false\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientWithMessageParamAbsent() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=on-param\");\n\t\tbindingExceptionWithoutMessage(\"\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientAlwaysMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=always\");\n\t\tbindingExceptionWithMessage(\"?message=false\");\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClientNeverMessage() {\n\t\tload(\"--spring.web.error.include-exception=true\", \"--spring.web.error.include-message=never\");\n\t\tbindingExceptionWithoutMessage(\"?message=true\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void bindingExceptionWithErrors(String param) {\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/bind\" + param), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", MethodArgumentNotValidException.class, null,\n\t\t\t\t\"/bind\");\n\t\tassertThat(entity.getBody()).containsKey(\"errors\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void bindingExceptionWithoutErrors(String param) {\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/bind\" + param), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", MethodArgumentNotValidException.class, null,\n\t\t\t\t\"/bind\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"errors\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void bindingExceptionWithMessage(String param) {\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/bind\" + param), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", MethodArgumentNotValidException.class,\n\t\t\t\t\"Validation failed for object='test'. Error count: 1\", \"/bind\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"errors\");\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate void bindingExceptionWithoutMessage(String param) {\n\t\tResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(\"/bind\" + param), Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", MethodArgumentNotValidException.class, null,\n\t\t\t\t\"/bind\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"errors\");\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid testRequestBodyValidationForMachineClient() {\n\t\tload(\"--spring.web.error.include-exception=true\");\n\t\tRequestEntity request = RequestEntity.post(URI.create(createUrl(\"/bodyValidation\")))\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.body(\"{}\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().exchange(request, Map.class);\n\t\tassertErrorAttributes(entity.getBody(), \"400\", \"Bad Request\", MethodArgumentNotValidException.class, null,\n\t\t\t\t\"/bodyValidation\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"errors\");\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid testBindingExceptionForMachineClientDefault() {\n\t\tload();\n\t\tRequestEntity request = RequestEntity.get(URI.create(createUrl(\"/bind?trace=true,message=true\")))\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.build();\n\t\tResponseEntity<Map> entity = new TestRestTemplate().exchange(request, Map.class);\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"exception\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"trace\");\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"errors\");\n\t}\n\n\t@Test\n\tvoid testIncompatibleMediaType() {\n\t\tload();\n\t\tRequestEntity<?> request = RequestEntity.get(URI.create(createUrl(\"/incompatibleType\")))\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.build();\n\t\tResponseEntity<String> entity = new TestRestTemplate().exchange(request, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);\n\t\tassertThat(entity.getHeaders().getContentType()).isNull();\n\t\tassertThat(entity.getBody()).isNull();\n\t}\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid customErrorControllerWithoutStatusConfiguration() {\n\t\tload(CustomErrorControllerWithoutStatusConfiguration.class);\n\t\tRequestEntity request = RequestEntity.post(URI.create(createUrl(\"/bodyValidation\")))\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.contentType(MediaType.APPLICATION_JSON)\n\t\t\t.body(\"{}\");\n\t\tResponseEntity<Map> entity = new TestRestTemplate().exchange(request, Map.class);\n\t\tassertThat(entity.getBody()).doesNotContainKey(\"status\");\n\t}\n\n\tprivate void assertErrorAttributes(@Nullable Map<?, ?> content, String status, String error,\n\t\t\t@Nullable Class<?> exception, @Nullable String message, String path) {\n\t\tassertThat(content).isNotNull();\n\t\tassertThat(content.get(\"status\")).as(\"Wrong status\").hasToString(status);\n\t\tassertThat(content.get(\"error\")).as(\"Wrong error\").isEqualTo(error);\n\t\tif (exception != null) {\n\t\t\tassertThat(content.get(\"exception\")).as(\"Wrong exception\").isEqualTo(exception.getName());\n\t\t}\n\t\telse {\n\t\t\tassertThat(content.containsKey(\"exception\")).as(\"Exception attribute should not be set\").isFalse();\n\t\t}\n\t\tassertThat(content.get(\"message\")).as(\"Wrong message\").isEqualTo(message);\n\t\tassertThat(content.get(\"path\")).as(\"Wrong path\").isEqualTo(path);\n\t}\n\n\tprivate String createUrl(String path) {\n\t\tassertThat(this.context).isNotNull();\n\t\tInteger port = this.context.getEnvironment().getProperty(\"local.server.port\", Integer.class);\n\t\tassertThat(port).isNotNull();\n\t\treturn \"http://localhost:\" + port + path;\n\t}\n\n\tprivate void load(String... arguments) {\n\t\tload(TestConfiguration.class, arguments);\n\t}\n\n\tprivate void load(Class<?> configuration, String... arguments) {\n\t\tList<String> args = new ArrayList<>();\n\t\targs.add(\"--server.port=0\");\n\t\tif (arguments != null) {\n\t\t\targs.addAll(Arrays.asList(arguments));\n\t\t}\n\t\tthis.context = SpringApplication.run(configuration, StringUtils.toStringArray(args));\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\tWebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tprivate @interface MinimalWebConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\t// @ImportAutoConfiguration(FreeMarkerAutoConfiguration.class)\n\tpublic static class TestConfiguration {\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(TestConfiguration.class, args);\n\t\t}\n\n\t\t@Bean\n\t\tView error() {\n\t\t\treturn new AbstractView() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,\n\t\t\t\t\t\tHttpServletResponse response) throws Exception {\n\t\t\t\t\tresponse.getWriter().write(\"ERROR_BEAN\");\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t\t@RestController\n\t\tpublic static class Errors {\n\n\t\t\tpublic String getFoo() {\n\t\t\t\treturn \"foo\";\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/\")\n\t\t\tString home() {\n\t\t\t\tthrow new IllegalStateException(\"Expected!\");\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/noMessage\")\n\t\t\tString noMessage() {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/annotated\")\n\t\t\tString annotated() {\n\t\t\t\tthrow new ExpectedException();\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/annotatedNoReason\")\n\t\t\tString annotatedNoReason() {\n\t\t\t\tthrow new NoReasonExpectedException(\"Expected message\");\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/annotatedNoMessage\")\n\t\t\tString annotatedNoMessage() {\n\t\t\t\tthrow new NoReasonExpectedException(\"\");\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/bind\")\n\t\t\tString bind(@RequestAttribute(required = false) String foo) throws Exception {\n\t\t\t\tBindException error = new BindException(this, \"test\");\n\t\t\t\terror.rejectValue(\"foo\", \"bar.error\");\n\t\t\t\tMethod method = ReflectionUtils.findMethod(Errors.class, \"bind\", String.class);\n\t\t\t\tassertThat(method).isNotNull();\n\t\t\t\tParameter fooParameter = method.getParameters()[0];\n\t\t\t\tthrow new MethodArgumentNotValidException(MethodParameter.forParameter(fooParameter), error);\n\t\t\t}\n\n\t\t\t@PostMapping(path = \"/bodyValidation\", produces = \"application/json\")\n\t\t\tString bodyValidation(@Valid @RequestBody DummyBody body) {\n\t\t\t\treturn body.content;\n\t\t\t}\n\n\t\t\t@RequestMapping(path = \"/incompatibleType\", produces = \"text/plain\")\n\t\t\tString incompatibleType() {\n\t\t\t\tthrow new ExpectedException();\n\t\t\t}\n\n\t\t\t@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = \"Expected!\")\n\t\t\t@SuppressWarnings(\"serial\")\n\t\t\tstatic class ExpectedException extends RuntimeException {\n\n\t\t\t}\n\n\t\t\t@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)\n\t\t\t@SuppressWarnings(\"serial\")\n\t\t\tstatic class NoReasonExpectedException extends RuntimeException {\n\n\t\t\t\tNoReasonExpectedException(String message) {\n\t\t\t\t\tsuper(message);\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstatic class DummyBody {\n\n\t\t\t\t@NotNull\n\t\t\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\t\t\tprivate String content;\n\n\t\t\t\tString getContent() {\n\t\t\t\t\treturn this.content;\n\t\t\t\t}\n\n\t\t\t\tvoid setContent(String content) {\n\t\t\t\t\tthis.content = content;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic class CustomErrorControllerWithoutStatusConfiguration extends TestConfiguration {\n\n\t\t@Bean\n\t\tBasicErrorController basicErrorController(WebProperties webProperties, ErrorAttributes errorAttributes,\n\t\t\t\tObjectProvider<ErrorViewResolver> errorViewResolvers) {\n\t\t\treturn new BasicErrorController(errorAttributes, webProperties.getError(),\n\t\t\t\t\terrorViewResolvers.orderedStream().toList()) {\n\n\t\t\t\t@Override\n\t\t\t\tprotected ErrorAttributeOptions getErrorAttributeOptions(HttpServletRequest request,\n\t\t\t\t\t\tMediaType mediaType) {\n\t\t\t\t\treturn super.getErrorAttributeOptions(request, mediaType).excluding(Include.STATUS);\n\t\t\t\t}\n\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/BasicErrorControllerMockMvcTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.Map;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.ServletContext;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.web.servlet.MvcResult;\nimport org.springframework.test.web.servlet.RequestBuilder;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.test.web.servlet.assertj.MvcTestResult;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.validation.BindException;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.bind.annotation.RequestAttribute;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.view.AbstractView;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link BasicErrorController} using {@link MockMvcTester} and\n * {@link SpringBootTest @SpringBootTest}.\n *\n * @author Dave Syer\n * @author Scott Frederick\n */\n@SpringBootTest(properties = { \"spring.web.error.include-message=always\", \"debug=true\" })\n@DirtiesContext\nclass BasicErrorControllerMockMvcTests {\n\n\t@Autowired\n\tprivate WebApplicationContext wac;\n\n\tprivate MockMvcTester mvc;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.mvc = MockMvcTester.from(this.wac);\n\t}\n\n\t@Test\n\tvoid testDirectAccessForMachineClient() {\n\t\tassertThat(this.mvc.get().uri(\"/error\")).hasStatus5xxServerError().bodyText().contains(\"999\");\n\t}\n\n\t@Test\n\tvoid testErrorWithNotFoundResponseStatus() {\n\t\tassertThat(this.mvc.get().uri(\"/bang\")).hasStatus(HttpStatus.NOT_FOUND)\n\t\t\t.satisfies((result) -> assertThat(this.mvc.perform(new ErrorDispatcher(result, \"/error\"))).bodyText()\n\t\t\t\t.contains(\"Expected!\"));\n\t}\n\n\t@Test\n\tvoid testErrorWithNoContentResponseStatus() {\n\t\tassertThat(this.mvc.get().uri(\"/noContent\").accept(\"some/thing\")).hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t.satisfies((result) -> assertThat(this.mvc.perform(new ErrorDispatcher(result, \"/error\")))\n\t\t\t\t.hasStatus(HttpStatus.NO_CONTENT)\n\t\t\t\t.body()\n\t\t\t\t.isEmpty());\n\t}\n\n\t@Test\n\tvoid testBindingExceptionForMachineClient() {\n\t\t// In a real server the response is carried over into the error dispatcher, but\n\t\t// in the mock a new one is created, so we have to assert the status at this\n\t\t// intermediate point, and the rendered status code is always wrong (but would\n\t\t// be 400 in a real system)\n\t\tassertThat(this.mvc.get().uri(\"/bind\")).hasStatus4xxClientError()\n\t\t\t.satisfies((result) -> assertThat(this.mvc.perform(new ErrorDispatcher(result, \"/error\"))).bodyText()\n\t\t\t\t.contains(\"Validation failed\"));\n\t}\n\n\t@Test\n\tvoid testDirectAccessForBrowserClient() {\n\t\tassertThat(this.mvc.get().uri(\"/error\").accept(MediaType.TEXT_HTML)).hasStatus5xxServerError()\n\t\t\t.bodyText()\n\t\t\t.contains(\"ERROR_BEAN\");\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@ImportAutoConfiguration({ DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tHttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprivate @interface MinimalWebConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\tstatic class TestConfiguration {\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(TestConfiguration.class, args);\n\t\t}\n\n\t\t@Bean\n\t\tView error() {\n\t\t\treturn new AbstractView() {\n\t\t\t\t@Override\n\t\t\t\tprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,\n\t\t\t\t\t\tHttpServletResponse response) throws Exception {\n\t\t\t\t\tresponse.getWriter().write(\"ERROR_BEAN\");\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@RestController\n\t\tpublic static class Errors {\n\n\t\t\t@RequestMapping(\"/\")\n\t\t\tString home() {\n\t\t\t\tthrow new IllegalStateException(\"Expected!\");\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/bang\")\n\t\t\tString bang() {\n\t\t\t\tthrow new NotFoundException(\"Expected!\");\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/bind\")\n\t\t\tString bind(@RequestAttribute(required = false) String foo) throws Exception {\n\t\t\t\tBindException error = new BindException(this, \"test\");\n\t\t\t\terror.rejectValue(\"foo\", \"bar.error\");\n\t\t\t\tMethod method = ReflectionUtils.findMethod(Errors.class, \"bind\", String.class);\n\t\t\t\tassertThat(method).isNotNull();\n\t\t\t\tParameter fooParameter = method.getParameters()[0];\n\t\t\t\tthrow new MethodArgumentNotValidException(MethodParameter.forParameter(fooParameter), error);\n\t\t\t}\n\n\t\t\t@RequestMapping(\"/noContent\")\n\t\t\tvoid noContent() {\n\t\t\t\tthrow new NoContentException(\"Expected!\");\n\t\t\t}\n\n\t\t\tpublic String getFoo() {\n\t\t\t\treturn \"foo\";\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@ResponseStatus(HttpStatus.NOT_FOUND)\n\tstatic class NotFoundException extends RuntimeException {\n\n\t\tNotFoundException(String string) {\n\t\t\tsuper(string);\n\t\t}\n\n\t}\n\n\t@ResponseStatus(HttpStatus.NO_CONTENT)\n\tprivate static class NoContentException extends RuntimeException {\n\n\t\tNoContentException(String string) {\n\t\t\tsuper(string);\n\t\t}\n\n\t}\n\n\tprivate class ErrorDispatcher implements RequestBuilder {\n\n\t\tprivate final MvcResult result;\n\n\t\tprivate final String path;\n\n\t\tErrorDispatcher(MvcTestResult mvcTestResult, String path) {\n\t\t\tthis.result = mvcTestResult.getMvcResult();\n\t\t\tthis.path = path;\n\t\t}\n\n\t\t@Override\n\t\tpublic MockHttpServletRequest buildRequest(ServletContext servletContext) {\n\t\t\tMockHttpServletRequest request = this.result.getRequest();\n\t\t\trequest.setDispatcherType(DispatcherType.ERROR);\n\t\t\trequest.setRequestURI(this.path);\n\t\t\trequest.setAttribute(\"jakarta.servlet.error.status_code\", this.result.getResponse().getStatus());\n\t\t\treturn request;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/DefaultErrorViewIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the default error view.\n *\n * @author Dave Syer\n * @author Scott Frederick\n */\n@SpringBootTest(properties = { \"spring.web.error.include-message=always\" })\n@DirtiesContext\nclass DefaultErrorViewIntegrationTests {\n\n\t@Autowired\n\tprivate WebApplicationContext wac;\n\n\tprivate MockMvcTester mvc;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.mvc = MockMvcTester.from(this.wac);\n\t}\n\n\t@Test\n\tvoid testErrorForBrowserClient() {\n\t\tassertThat(this.mvc.get().uri(\"/error\").accept(MediaType.TEXT_HTML)).hasStatus5xxServerError()\n\t\t\t.bodyText()\n\t\t\t.contains(\"<html>\", \"999\");\n\t}\n\n\t@Test\n\tvoid testErrorWithHtmlEscape() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/error\")\n\t\t\t.requestAttr(\"jakarta.servlet.error.exception\",\n\t\t\t\t\tnew RuntimeException(\"<script>alert('Hello World')</script>\"))\n\t\t\t.accept(MediaType.TEXT_HTML)).hasStatus5xxServerError()\n\t\t\t.bodyText()\n\t\t\t.contains(\"&lt;script&gt;\", \"Hello World\", \"999\");\n\t}\n\n\t@Test\n\tvoid testErrorWithSpelEscape() {\n\t\tString spel = \"${T(\" + getClass().getName() + \").injectCall()}\";\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/error\")\n\t\t\t.requestAttr(\"jakarta.servlet.error.exception\", new RuntimeException(spel))\n\t\t\t.accept(MediaType.TEXT_HTML)).hasStatus5xxServerError().bodyText().doesNotContain(\"injection\");\n\t}\n\n\tstatic String injectCall() {\n\t\treturn \"injection\";\n\t}\n\n\t@Target(ElementType.TYPE)\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Import({ DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tHttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\tprotected @interface MinimalWebConfiguration {\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@MinimalWebConfiguration\n\tstatic class TestConfiguration {\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tSpringApplication.run(TestConfiguration.class, args);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/DefaultErrorViewResolverTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;\nimport org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;\nimport org.springframework.boot.autoconfigure.web.WebProperties.Resources;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.env.Environment;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.View;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.BDDMockito.given;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultErrorViewResolver}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(MockitoExtension.class)\nclass DefaultErrorViewResolverTests {\n\n\tprivate DefaultErrorViewResolver resolver;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate TemplateAvailabilityProvider templateAvailabilityProvider;\n\n\tprivate Resources resourcesProperties;\n\n\tprivate final Map<String, Object> model = new HashMap<>();\n\n\tprivate final HttpServletRequest request = new MockHttpServletRequest();\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tAnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();\n\t\tapplicationContext.refresh();\n\t\tthis.resourcesProperties = new Resources();\n\t\tTemplateAvailabilityProviders templateAvailabilityProviders = new TestTemplateAvailabilityProviders(\n\t\t\t\tthis.templateAvailabilityProvider);\n\t\tthis.resolver = new DefaultErrorViewResolver(applicationContext, this.resourcesProperties,\n\t\t\t\ttemplateAvailabilityProviders);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenApplicationContextIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new DefaultErrorViewResolver(null, new Resources()))\n\t\t\t.withMessageContaining(\"'applicationContext' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenResourcePropertiesIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> new DefaultErrorViewResolver(mock(ApplicationContext.class), (Resources) null))\n\t\t\t.withMessageContaining(\"'resources' must not be null\");\n\t}\n\n\t@Test\n\tvoid resolveWhenNoMatchShouldReturnNull() {\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNull();\n\t}\n\n\t@Test\n\tvoid resolveWhenExactTemplateMatchShouldReturnTemplate() {\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/404\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(true);\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tassertThat(resolved.getViewName()).isEqualTo(\"error/404\");\n\t\tthen(this.templateAvailabilityProvider).should()\n\t\t\t.isTemplateAvailable(eq(\"error/404\"), any(Environment.class), any(ClassLoader.class),\n\t\t\t\t\tany(ResourceLoader.class));\n\t\tthen(this.templateAvailabilityProvider).shouldHaveNoMoreInteractions();\n\t}\n\n\t@Test\n\tvoid resolveWhenSeries5xxTemplateMatchShouldReturnTemplate() {\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/503\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(false);\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/5xx\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(true);\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.SERVICE_UNAVAILABLE,\n\t\t\t\tthis.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tassertThat(resolved.getViewName()).isEqualTo(\"error/5xx\");\n\t}\n\n\t@Test\n\tvoid resolveWhenSeries4xxTemplateMatchShouldReturnTemplate() {\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/404\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(false);\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/4xx\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(true);\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tassertThat(resolved.getViewName()).isEqualTo(\"error/4xx\");\n\t}\n\n\t@Test\n\tvoid resolveWhenExactResourceMatchShouldReturnResource() throws Exception {\n\t\tsetResourceLocation(\"/exact\");\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tMockHttpServletResponse response = render(resolved);\n\t\tassertThat(response.getContentAsString().trim()).isEqualTo(\"exact/404\");\n\t\tassertThat(response.getContentType()).isEqualTo(MediaType.TEXT_HTML_VALUE);\n\t}\n\n\t@Test\n\tvoid resolveWhenSeries4xxResourceMatchShouldReturnResource() throws Exception {\n\t\tsetResourceLocation(\"/4xx\");\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tMockHttpServletResponse response = render(resolved);\n\t\tassertThat(response.getContentAsString().trim()).isEqualTo(\"4xx/4xx\");\n\t\tassertThat(response.getContentType()).isEqualTo(MediaType.TEXT_HTML_VALUE);\n\t}\n\n\t@Test\n\tvoid resolveWhenSeries5xxResourceMatchShouldReturnResource() throws Exception {\n\t\tsetResourceLocation(\"/5xx\");\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.INTERNAL_SERVER_ERROR,\n\t\t\t\tthis.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tMockHttpServletResponse response = render(resolved);\n\t\tassertThat(response.getContentAsString().trim()).isEqualTo(\"5xx/5xx\");\n\t\tassertThat(response.getContentType()).isEqualTo(MediaType.TEXT_HTML_VALUE);\n\t}\n\n\t@Test\n\tvoid resolveWhenTemplateAndResourceMatchShouldFavorTemplate() {\n\t\tsetResourceLocation(\"/exact\");\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/404\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(true);\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tassertThat(resolved.getViewName()).isEqualTo(\"error/404\");\n\t}\n\n\t@Test\n\tvoid resolveWhenExactResourceMatchAndSeriesTemplateMatchShouldFavorResource() throws Exception {\n\t\tsetResourceLocation(\"/exact\");\n\t\tgiven(this.templateAvailabilityProvider.isTemplateAvailable(eq(\"error/404\"), any(Environment.class),\n\t\t\t\tany(ClassLoader.class), any(ResourceLoader.class)))\n\t\t\t.willReturn(false);\n\t\tModelAndView resolved = this.resolver.resolveErrorView(this.request, HttpStatus.NOT_FOUND, this.model);\n\t\tassertThat(resolved).isNotNull();\n\t\tthen(this.templateAvailabilityProvider).shouldHaveNoMoreInteractions();\n\t\tMockHttpServletResponse response = render(resolved);\n\t\tassertThat(response.getContentAsString().trim()).isEqualTo(\"exact/404\");\n\t\tassertThat(response.getContentType()).isEqualTo(MediaType.TEXT_HTML_VALUE);\n\t}\n\n\t@Test\n\tvoid orderShouldBeLowest() {\n\t\tassertThat(this.resolver.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);\n\t}\n\n\t@Test\n\tvoid setOrderShouldChangeOrder() {\n\t\tthis.resolver.setOrder(123);\n\t\tassertThat(this.resolver.getOrder()).isEqualTo(123);\n\t}\n\n\tprivate void setResourceLocation(String path) {\n\t\tString packageName = getClass().getPackage().getName();\n\t\tthis.resourcesProperties\n\t\t\t.setStaticLocations(new String[] { \"classpath:\" + packageName.replace('.', '/') + path + \"/\" });\n\t}\n\n\tprivate MockHttpServletResponse render(ModelAndView modelAndView) throws Exception {\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tView view = modelAndView.getView();\n\t\tassertThat(view).isNotNull();\n\t\tview.render(this.model, this.request, response);\n\t\treturn response;\n\t}\n\n\tstatic class TestTemplateAvailabilityProviders extends TemplateAvailabilityProviders {\n\n\t\tTestTemplateAvailabilityProviders(TemplateAvailabilityProvider provider) {\n\t\t\tsuper(Collections.singletonList(provider));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/ErrorMvcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport java.time.Clock;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.web.context.request.RequestAttributes;\nimport org.springframework.web.servlet.View;\nimport org.springframework.web.servlet.handler.DispatcherServletWebRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ErrorMvcAutoConfiguration}.\n *\n * @author Brian Clozel\n * @author Scott Frederick\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass ErrorMvcAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner().withConfiguration(\n\t\t\tAutoConfigurations.of(DispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class));\n\n\t@Test\n\tvoid renderContainsViewWithExceptionDetails() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tView errorView = context.getBean(\"error\", View.class);\n\t\t\tErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);\n\t\t\tDispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException(\"Exception message\"),\n\t\t\t\t\tfalse);\n\t\t\tHttpServletResponse response = webRequest.getResponse();\n\t\t\tassertThat(response).isNotNull();\n\t\t\terrorView.render(errorAttributes.getErrorAttributes(webRequest, withAllOptions()), webRequest.getRequest(),\n\t\t\t\t\tresponse);\n\t\t\tassertThat(response.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\t\t\tString responseString = ((MockHttpServletResponse) response).getContentAsString();\n\t\t\tassertThat(responseString).contains(\n\t\t\t\t\t\"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>\")\n\t\t\t\t.contains(\"<div>Exception message</div>\")\n\t\t\t\t.contains(\"<div style='white-space:pre-wrap;'>java.lang.IllegalStateException\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid renderCanUseJavaTimeTypeAsTimestamp() { // gh-23256\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tView errorView = context.getBean(\"error\", View.class);\n\t\t\tErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);\n\t\t\tDispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException(\"Exception message\"),\n\t\t\t\t\tfalse);\n\t\t\tMap<String, @Nullable Object> attributes = errorAttributes.getErrorAttributes(webRequest, withAllOptions());\n\t\t\tattributes.put(\"timestamp\", Clock.systemUTC().instant());\n\t\t\tHttpServletResponse response = webRequest.getResponse();\n\t\t\tassertThat(response).isNotNull();\n\t\t\terrorView.render(attributes, webRequest.getRequest(), response);\n\t\t\tassertThat(response.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\t\t\tString responseString = ((MockHttpServletResponse) response).getContentAsString();\n\t\t\tassertThat(responseString).contains(\"This application has no explicit mapping for /error\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid renderWhenAlreadyCommittedLogsMessage(CapturedOutput output) {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tView errorView = context.getBean(\"error\", View.class);\n\t\t\tErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);\n\t\t\tDispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException(\"Exception message\"),\n\t\t\t\t\ttrue);\n\t\t\tHttpServletResponse response = webRequest.getResponse();\n\t\t\tassertThat(response).isNotNull();\n\t\t\terrorView.render(errorAttributes.getErrorAttributes(webRequest, withAllOptions()), webRequest.getRequest(),\n\t\t\t\t\tresponse);\n\t\t\tassertThat(output).contains(\"Cannot render error page for request [/path] \"\n\t\t\t\t\t+ \"and exception [Exception message] as the response has \"\n\t\t\t\t\t+ \"already been committed. As a result, the response may have the wrong status code.\");\n\t\t});\n\t}\n\n\tprivate DispatcherServletWebRequest createWebRequest(Exception ex, boolean committed) {\n\t\tMockHttpServletRequest request = new MockHttpServletRequest(\"GET\", \"/path\");\n\t\tMockHttpServletResponse response = new MockHttpServletResponse();\n\t\tDispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);\n\t\twebRequest.setAttribute(\"jakarta.servlet.error.exception\", ex, RequestAttributes.SCOPE_REQUEST);\n\t\twebRequest.setAttribute(\"jakarta.servlet.error.request_uri\", \"/path\", RequestAttributes.SCOPE_REQUEST);\n\t\tresponse.setCommitted(committed);\n\t\tresponse.setOutputStreamAccessAllowed(!committed);\n\t\tresponse.setWriterAccessAllowed(!committed);\n\t\treturn webRequest;\n\t}\n\n\tprivate ErrorAttributeOptions withAllOptions() {\n\t\treturn ErrorAttributeOptions.of(Include.values());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/autoconfigure/error/RemappedErrorViewIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.autoconfigure.error;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.web.error.ErrorPage;\nimport org.springframework.boot.web.error.ErrorPageRegistrar;\nimport org.springframework.boot.web.error.ErrorPageRegistry;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for remapped error pages.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.mvc.servlet.path:/spring/\")\n@DirtiesContext\nclass RemappedErrorViewIntegrationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\tprivate final TestRestTemplate template = new TestRestTemplate();\n\n\t@Test\n\tvoid directAccessToErrorPage() {\n\t\tString content = this.template.getForObject(\"http://localhost:\" + this.port + \"/spring/error\", String.class);\n\t\tassertThat(content).contains(\"error\");\n\t\tassertThat(content).contains(\"999\");\n\t}\n\n\t@Test\n\tvoid forwardToErrorPage() {\n\t\tString content = this.template.getForObject(\"http://localhost:\" + this.port + \"/spring/\", String.class);\n\t\tassertThat(content).contains(\"error\");\n\t\tassertThat(content).contains(\"500\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class,\n\t\t\tHttpMessageConvertersAutoConfiguration.class, TomcatServletWebServerAutoConfiguration.class,\n\t\t\tDispatcherServletAutoConfiguration.class, ErrorMvcAutoConfiguration.class })\n\t@Controller\n\tstatic class TestConfiguration implements ErrorPageRegistrar {\n\n\t\t@RequestMapping(\"/\")\n\t\tString home() {\n\t\t\tthrow new RuntimeException(\"Planned!\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void registerErrorPages(ErrorPageRegistry errorPageRegistry) {\n\t\t\terrorPageRegistry.addErrorPages(new ErrorPage(\"/spring/error\"));\n\t\t}\n\n\t\t// For manual testing\n\t\tstatic void main(String[] args) {\n\t\t\tnew SpringApplicationBuilder(TestConfiguration.class).properties(\"spring.mvc.servlet.path:spring/*\")\n\t\t\t\t.run(args);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/java/org/springframework/boot/webmvc/error/DefaultErrorAttributesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.error;\n\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.web.error.ErrorAttributeOptions.Include;\nimport org.springframework.context.MessageSourceResolvable;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.util.ReflectionUtils;\nimport org.springframework.validation.BindException;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.MapBindingResult;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.validation.method.MethodValidationResult;\nimport org.springframework.validation.method.ParameterValidationResult;\nimport org.springframework.web.bind.MethodArgumentNotValidException;\nimport org.springframework.web.context.request.ServletWebRequest;\nimport org.springframework.web.context.request.WebRequest;\nimport org.springframework.web.method.annotation.HandlerMethodValidationException;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link DefaultErrorAttributes}.\n *\n * @author Phillip Webb\n * @author Vedran Pavic\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Yanming Zhou\n */\nclass DefaultErrorAttributesTests {\n\n\tprivate final DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes();\n\n\tprivate final MockHttpServletRequest request = new MockHttpServletRequest();\n\n\tprivate final WebRequest webRequest = new ServletWebRequest(this.request);\n\n\t@Test\n\tvoid includeTimeStamp() {\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes.get(\"timestamp\")).isInstanceOf(Date.class);\n\t}\n\n\t@Test\n\tvoid specificStatusCode() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.status_code\", 404);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"error\", HttpStatus.NOT_FOUND.getReasonPhrase());\n\t\tassertThat(attributes).containsEntry(\"status\", 404);\n\t}\n\n\t@Test\n\tvoid missingStatusCode() {\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"error\", \"None\");\n\t\tassertThat(attributes).containsEntry(\"status\", 999);\n\t}\n\n\t@Test\n\tvoid mvcError() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tModelAndView modelAndView = this.errorAttributes.resolveException(this.request, mock(HttpServletResponse.class),\n\t\t\t\tnull, ex);\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", new RuntimeException(\"Ignored\"));\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(ex);\n\t\tassertThat(modelAndView).isNull();\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid servletErrorWithMessage() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", ex);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(ex);\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid servletErrorWithoutMessage() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", ex);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(ex);\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).doesNotContainKey(\"message\");\n\t}\n\n\t@Test\n\tvoid servletMessageWithMessage() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.message\", \"Test\");\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid servletMessageWithoutMessage() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.message\", \"Test\");\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).doesNotContainKey(\"message\");\n\t}\n\n\t@Test\n\tvoid nullExceptionMessage() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", new RuntimeException());\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.message\", \"Test\");\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid nullExceptionMessageAndServletMessage() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", new RuntimeException());\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"No message available\");\n\t}\n\n\t@Test\n\tvoid unwrapServletException() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tServletException wrapped = new ServletException(new ServletException(ex));\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", wrapped);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(wrapped);\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid getError() {\n\t\tError error = new OutOfMemoryError(\"Test error\");\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", error);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(error);\n\t\tassertThat(attributes).doesNotContainKey(\"exception\");\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test error\");\n\t}\n\n\t@Test\n\tvoid withBindingErrors() {\n\t\tBindingResult bindingResult = new MapBindingResult(Collections.singletonMap(\"a\", \"b\"), \"objectName\");\n\t\tbindingResult.addError(new ObjectError(\"c\", \"d\"));\n\t\tException ex = new BindException(bindingResult);\n\t\ttestBindingResult(bindingResult, ex, ErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t}\n\n\t@Test\n\tvoid withoutBindingErrors() {\n\t\tBindingResult bindingResult = new MapBindingResult(Collections.singletonMap(\"a\", \"b\"), \"objectName\");\n\t\tbindingResult.addError(new ObjectError(\"c\", \"d\"));\n\t\tException ex = new BindException(bindingResult);\n\t\ttestBindingResult(bindingResult, ex, ErrorAttributeOptions.defaults());\n\t}\n\n\t@Test\n\tvoid withMethodArgumentNotValidExceptionBindingErrors() {\n\t\tMethod method = ReflectionUtils.findMethod(String.class, \"substring\", int.class);\n\t\tassertThat(method).isNotNull();\n\t\tMethodParameter parameter = new MethodParameter(method, 0);\n\t\tBindingResult bindingResult = new MapBindingResult(Collections.singletonMap(\"a\", \"b\"), \"objectName\");\n\t\tbindingResult.addError(new ObjectError(\"c\", \"d\"));\n\t\tException ex = new MethodArgumentNotValidException(parameter, bindingResult);\n\t\ttestBindingResult(bindingResult, ex, ErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t}\n\n\t@Test\n\tvoid withHandlerMethodValidationExceptionBindingErrors() {\n\t\tObject target = \"test\";\n\t\tMethod method = ReflectionUtils.findMethod(String.class, \"substring\", int.class);\n\t\tassertThat(method).isNotNull();\n\t\tMethodParameter parameter = new MethodParameter(method, 0);\n\t\tMethodValidationResult methodValidationResult = MethodValidationResult.create(target, method,\n\t\t\t\tList.of(new ParameterValidationResult(parameter, -1,\n\t\t\t\t\t\tList.of(new ObjectError(\"beginIndex\", \"beginIndex is negative\")), null, null, null,\n\t\t\t\t\t\t(error, sourceType) -> {\n\t\t\t\t\t\t\tthrow new IllegalArgumentException(\"No source object of the given type\");\n\t\t\t\t\t\t})));\n\t\tHandlerMethodValidationException ex = new HandlerMethodValidationException(methodValidationResult);\n\t\ttestErrors(methodValidationResult.getAllErrors(),\n\t\t\t\t\"Validation failed for method='public java.lang.String java.lang.String.substring(int)'. Error count: 1\",\n\t\t\t\tex, ErrorAttributeOptions.of(Include.MESSAGE, Include.BINDING_ERRORS));\n\t}\n\n\tprivate void testBindingResult(BindingResult bindingResult, Exception ex, ErrorAttributeOptions options) {\n\t\ttestErrors(bindingResult.getAllErrors(), \"Validation failed for object='objectName'. Error count: 1\", ex,\n\t\t\t\toptions);\n\t}\n\n\tprivate void testErrors(List<? extends MessageSourceResolvable> errors, String expectedMessage, Exception ex,\n\t\t\tErrorAttributeOptions options) {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", ex);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, options);\n\t\tif (options.isIncluded(Include.MESSAGE)) {\n\t\t\tassertThat(attributes).containsEntry(\"message\", expectedMessage);\n\t\t}\n\t\telse {\n\t\t\tassertThat(attributes).doesNotContainKey(\"message\");\n\t\t}\n\t\tif (options.isIncluded(Include.BINDING_ERRORS)) {\n\t\t\tassertThat(attributes).containsEntry(\"errors\",\n\t\t\t\t\torg.springframework.boot.web.error.Error.wrapIfNecessary(errors));\n\t\t}\n\t\telse {\n\t\t\tassertThat(attributes).doesNotContainKey(\"errors\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid withExceptionAttribute() {\n\t\tDefaultErrorAttributes errorAttributes = new DefaultErrorAttributes();\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", ex);\n\t\tMap<String, @Nullable Object> attributes = errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.EXCEPTION, Include.MESSAGE));\n\t\tassertThat(attributes).containsEntry(\"exception\", RuntimeException.class.getName());\n\t\tassertThat(attributes).containsEntry(\"message\", \"Test\");\n\t}\n\n\t@Test\n\tvoid withStackTraceAttribute() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", ex);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.STACK_TRACE));\n\t\tObject trace = attributes.get(\"trace\");\n\t\tassertThat(trace).isNotNull();\n\t\tassertThat(trace.toString()).startsWith(\"java.lang\");\n\t}\n\n\t@Test\n\tvoid withoutStackTraceAttribute() {\n\t\tRuntimeException ex = new RuntimeException(\"Test\");\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.exception\", ex);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).doesNotContainKey(\"trace\");\n\t}\n\n\t@Test\n\tvoid shouldIncludePathByDefault() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.request_uri\", \"path\");\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults());\n\t\tassertThat(attributes).containsEntry(\"path\", \"path\");\n\t}\n\n\t@Test\n\tvoid shouldIncludePath() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.request_uri\", \"path\");\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of(Include.PATH));\n\t\tassertThat(attributes).containsEntry(\"path\", \"path\");\n\t}\n\n\t@Test\n\tvoid shouldExcludePath() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.request_uri\", \"path\");\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.of());\n\t\tassertThat(attributes).doesNotContainEntry(\"path\", \"path\");\n\t}\n\n\t@Test\n\tvoid whenGetMessageIsOverriddenThenMessageAttributeContainsValueReturnedFromIt() {\n\t\tMap<String, @Nullable Object> attributes = new DefaultErrorAttributes() {\n\n\t\t\t@Override\n\t\t\tprotected String getMessage(WebRequest webRequest, @Nullable Throwable error) {\n\t\t\t\treturn \"custom message\";\n\t\t\t}\n\n\t\t}.getErrorAttributes(this.webRequest, ErrorAttributeOptions.of(Include.MESSAGE));\n\t\tassertThat(attributes).containsEntry(\"message\", \"custom message\");\n\t}\n\n\t@Test\n\tvoid excludeStatus() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.status_code\", 404);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults().excluding(Include.STATUS));\n\t\tassertThat(attributes).doesNotContainKey(\"status\");\n\t}\n\n\t@Test\n\tvoid excludeError() {\n\t\tthis.request.setAttribute(\"jakarta.servlet.error.status_code\", 404);\n\t\tMap<String, @Nullable Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest,\n\t\t\t\tErrorAttributeOptions.defaults().excluding(Include.ERROR));\n\t\tassertThat(attributes).doesNotContainKey(\"error\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/error/4xx/error/402.html",
    "content": "4xx/402\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/error/4xx/error/4xx.html",
    "content": "4xx/4xx\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/error/5xx/error/4xx.html",
    "content": "5xx/4xx\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/error/5xx/error/5xx.html",
    "content": "5xx/5xx\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/error/exact/error/404.html",
    "content": "exact/404\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/error/exact/error/4xx.html",
    "content": "exact/4xx\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/index.html",
    "content": "<!doctype html>\n<html xmlns:th=\"https://www.thymeleaf.org\">\n<head>\n    <title>Test Thymeleaf</title>\n    <link th:href=\"@{/custom.css}\" rel=\"stylesheet\" />\n</head>\n<body>\n\n</body>\n</html>\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/test/resources/org/springframework/boot/webmvc/autoconfigure/static/custom.css",
    "content": ""
  },
  {
    "path": "module/spring-boot-webmvc/src/testFixtures/java/org/springframework/boot/webmvc/actuate/endpoint/web/test/WebMvcEndpointConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web.test;\n\nimport java.util.Collections;\n\nimport org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\n\n/**\n * Endpoint configuration for WebMvc.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ImportAutoConfiguration({ JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\tWebMvcAutoConfiguration.class, DispatcherServletAutoConfiguration.class })\nclass WebMvcEndpointConfiguration {\n\n\tprivate final ApplicationContext applicationContext;\n\n\tWebMvcEndpointConfiguration(ApplicationContext applicationContext) {\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\t@Bean\n\tTomcatServletWebServerFactory tomcat() {\n\t\treturn new TomcatServletWebServerFactory(0);\n\t}\n\n\t@Bean\n\tWebMvcEndpointHandlerMapping webEndpointServletHandlerMapping() {\n\t\tEndpointMediaTypes endpointMediaTypes = EndpointMediaTypes.DEFAULT;\n\t\tWebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,\n\t\t\t\tnew ConversionServiceParameterValueMapper(), endpointMediaTypes, Collections.emptyList(),\n\t\t\t\tCollections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());\n\t\treturn new WebMvcEndpointHandlerMapping(new EndpointMapping(\"/actuator\"), discoverer.getEndpoints(),\n\t\t\t\tendpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),\n\t\t\t\ttrue);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/testFixtures/java/org/springframework/boot/webmvc/actuate/endpoint/web/test/WebMvcWebEndpointInfrastructureProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.actuate.endpoint.web.test;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider;\nimport org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest.Infrastructure;\n\n/**\n * {@link WebEndpointInfrastructureProvider} for MVC.\n *\n * @author Stephane Nicoll\n */\nclass WebMvcWebEndpointInfrastructureProvider implements WebEndpointInfrastructureProvider {\n\n\t@Override\n\tpublic boolean supports(Infrastructure infrastructure) {\n\t\treturn infrastructure == Infrastructure.MVC;\n\t}\n\n\t@Override\n\tpublic List<Class<?>> getInfrastructureConfiguration(Infrastructure infrastructure) {\n\t\treturn List.of(WebMvcEndpointConfiguration.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc/src/testFixtures/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.actuate.endpoint.web.test.WebEndpointInfrastructureProvider=\\\norg.springframework.boot.webmvc.actuate.endpoint.web.test.WebMvcWebEndpointInfrastructureProvider\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Web MVC Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-webmvc\"))\n\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\n\timplementation(project(\":module:spring-boot-http-converter\"))\n\timplementation(project(\":module:spring-boot-web-server\"))\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-test-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\toptional(project(\":module:spring-boot-validation\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\toptional(\"org.seleniumhq.selenium:htmlunit3-driver\") {\n\t\texclude(group: \"com.sun.activation\", module: \"jakarta.activation\")\n\t}\n\toptional(\"org.seleniumhq.selenium:selenium-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.junit.platform:junit-platform-engine\")\n\ttestImplementation(\"org.junit.platform:junit-platform-launcher\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"test\") {\n\texclude(\"**/WebMvcTestPrintDefaultIntegrationTests\\$*\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/AutoConfigureMockMvc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.htmlunit.WebClient;\nimport org.openqa.selenium.WebDriver;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.boot.test.context.PropertyMapping.Skip;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.MvcResult;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of {@link MockMvc}. If AssertJ is available a {@link MockMvcTester}\n * is auto-configured as well.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see MockMvcAutoConfiguration\n * @see SpringBootMockMvcBuilderCustomizer\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.mockmvc\")\npublic @interface AutoConfigureMockMvc {\n\n\t/**\n\t * If filters from the application context should be registered with MockMVC. Defaults\n\t * to {@code true}.\n\t * @return if filters should be added\n\t */\n\tboolean addFilters() default true;\n\n\t/**\n\t * How {@link MvcResult} information should be printed after each MockMVC invocation.\n\t * @return how information is printed\n\t */\n\t@PropertyMapping(skip = Skip.ON_DEFAULT_VALUE)\n\tMockMvcPrint print() default MockMvcPrint.DEFAULT;\n\n\t/**\n\t * If {@link MvcResult} information should be printed only if the test fails.\n\t * @return {@code true} if printing only occurs on failure\n\t */\n\tboolean printOnlyOnFailure() default true;\n\n\t/**\n\t * Settings for the integration between MockMVC and HtmlUnit.\n\t * @return the HtmlUnit settings\n\t */\n\t@PropertyMapping(\"htmlunit\")\n\tHtmlUnit htmlUnit() default @HtmlUnit;\n\n\t/**\n\t * HtmlUnit settings.\n\t */\n\t@Target({ ElementType.TYPE, ElementType.METHOD })\n\t@Retention(RetentionPolicy.RUNTIME)\n\t@Documented\n\t@Inherited\n\t@interface HtmlUnit {\n\n\t\t/**\n\t\t * The URL that should be used when expanding relative paths.\n\t\t * @return the URL used to expand relative paths\n\t\t */\n\t\tString url() default \"http://localhost\";\n\n\t\t/**\n\t\t * If a {@link WebClient} should be auto-configured when HtmlUnit is on the\n\t\t * classpath. Defaults to {@code true}.\n\t\t * @return if a {@link WebClient} is auto-configured\n\t\t */\n\t\t@PropertyMapping(\"webclient.enabled\")\n\t\tboolean webClient() default true;\n\n\t\t/**\n\t\t * If a {@link WebDriver} should be auto-configured when Selenium is on the\n\t\t * classpath. Defaults to {@code true}.\n\t\t * @return if a {@link WebDriver} is auto-configured\n\t\t */\n\t\t@PropertyMapping(\"webdriver.enabled\")\n\t\tboolean webDriver() default true;\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/AutoConfigureWebMvc.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.autoconfigure.json.AutoConfigureJson;\n\n/**\n * {@link ImportAutoConfiguration Auto-configuration imports} for typical Spring MVC\n * tests. Most tests should consider using {@link WebMvcTest @WebMvcTest} rather than\n * using this annotation directly.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see WebMvcTest\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@AutoConfigureJson\n@ImportAutoConfiguration\npublic @interface AutoConfigureWebMvc {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * Auto-configuration for {@link MockMvc}.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n * @author Brian Clozel\n * @since 4.0.0\n * @see AutoConfigureWebMvc\n */\n@AutoConfiguration(after = WebMvcAutoConfiguration.class)\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@EnableConfigurationProperties(WebMvcProperties.class)\n@Import({ MockMvcConfiguration.class, MockMvcTesterConfiguration.class })\npublic final class MockMvcAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDispatcherServletPath dispatcherServletPath(WebMvcProperties webMvcProperties) {\n\t\treturn () -> webMvcProperties.getServlet().getPath();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tDispatcherServlet dispatcherServlet(MockMvc mockMvc) {\n\t\treturn mockMvc.getDispatcherServlet();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.springframework.test.web.servlet.MockMvcBuilder;\nimport org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;\n\n/**\n * A customizer for a {@link ConfigurableMockMvcBuilder}. Any\n * {@code MockMvcBuilderCustomizer} beans found in the application context will be\n * {@link #customize called} to customize the auto-configured {@link MockMvcBuilder}.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n * @see MockMvcAutoConfiguration\n */\n@FunctionalInterface\npublic interface MockMvcBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the builder\n\t */\n\tvoid customize(ConfigurableMockMvcBuilder<?> builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.web.servlet.DispatcherServletCustomizer;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.MockMvcBuilder;\nimport org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.servlet.DispatcherServlet;\n\n/**\n * Configuration for core {@link MockMvc}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\nclass MockMvcConfiguration {\n\n\tprivate final WebApplicationContext context;\n\n\tprivate final WebMvcProperties webMvcProperties;\n\n\tMockMvcConfiguration(WebApplicationContext context, WebMvcProperties webMvcProperties) {\n\t\tthis.context = context;\n\t\tthis.webMvcProperties = webMvcProperties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(MockMvcBuilder.class)\n\tDefaultMockMvcBuilder mockMvcBuilder(List<MockMvcBuilderCustomizer> customizers) {\n\t\tDefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.context);\n\t\tbuilder.addDispatcherServletCustomizer(new MockMvcDispatcherServletCustomizer(this.webMvcProperties));\n\t\tfor (MockMvcBuilderCustomizer customizer : customizers) {\n\t\t\tcustomizer.customize(builder);\n\t\t}\n\t\treturn builder;\n\t}\n\n\t@Bean\n\t@ConfigurationProperties(\"spring.test.mockmvc\")\n\tSpringBootMockMvcBuilderCustomizer springBootMockMvcBuilderCustomizer() {\n\t\treturn new SpringBootMockMvcBuilderCustomizer(this.context);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMockMvc mockMvc(MockMvcBuilder builder) {\n\t\treturn builder.build();\n\t}\n\n\tprivate static class MockMvcDispatcherServletCustomizer implements DispatcherServletCustomizer {\n\n\t\tprivate final WebMvcProperties webMvcProperties;\n\n\t\tMockMvcDispatcherServletCustomizer(WebMvcProperties webMvcProperties) {\n\t\t\tthis.webMvcProperties = webMvcProperties;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(DispatcherServlet dispatcherServlet) {\n\t\t\tdispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest());\n\t\t\tdispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcHtmlUnitDriverCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.openqa.selenium.htmlunit.HtmlUnitDriver;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the MockMvc\n * {@link HtmlUnitDriver} to fine-tune its auto-configuration.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface MockMvcHtmlUnitDriverCustomizer {\n\n\t/**\n\t * Customize the MockMvc HtmlUnitDriver.\n\t * @param htmlUnitDriver the driver to customize\n\t */\n\tvoid customize(HtmlUnitDriver htmlUnitDriver);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcPrint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\n/**\n * MVC print options specified from {@link AutoConfigureMockMvc @AutoConfigureMockMvc}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\npublic enum MockMvcPrint {\n\n\t/**\n\t * Use the default print setting ({@code MockMvcPrint.SYSTEM_OUT} unless explicitly\n\t * overridden).\n\t */\n\tDEFAULT,\n\n\t/**\n\t * Log MVC interactions at the {@code DEBUG} level.\n\t */\n\tLOG_DEBUG,\n\n\t/**\n\t * Print MVC interactions to {@code System.out}.\n\t */\n\tSYSTEM_OUT,\n\n\t/**\n\t * Print MVC interactions to {@code System.err}.\n\t */\n\tSYSTEM_ERR,\n\n\t/**\n\t * Do not print MVC interactions.\n\t */\n\tNONE\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcPrintOnlyOnFailureTestExecutionListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.SpringBootMockMvcBuilderCustomizer.DeferredLinesWriter;\nimport org.springframework.core.Ordered;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestExecutionListener;\nimport org.springframework.test.context.support.AbstractTestExecutionListener;\n\n/**\n * {@link TestExecutionListener} used to print MVC lines only on failure.\n *\n * @author Phillip Webb\n */\nclass MockMvcPrintOnlyOnFailureTestExecutionListener extends AbstractTestExecutionListener {\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE - 100;\n\t}\n\n\t@Override\n\tpublic void afterTestMethod(TestContext testContext) throws Exception {\n\t\tDeferredLinesWriter writer = DeferredLinesWriter.get(testContext.getApplicationContext());\n\t\tif (writer != null) {\n\t\t\tif (testContext.getTestException() != null) {\n\t\t\t\twriter.writeDeferredResult();\n\t\t\t}\n\t\t\twriter.clear();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcTesterConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.http.converter.autoconfigure.ServerHttpMessageConvertersCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.converter.HttpMessageConverters;\nimport org.springframework.http.converter.HttpMessageConverters.ServerBuilder;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\n/**\n * Configuration for {@link MockMvcTester}.\n *\n * @author Stephane Nicoll\n */\n@Configuration(proxyBeanMethods = false)\n@ConditionalOnClass(name = \"org.assertj.core.api.Assert\")\nclass MockMvcTesterConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tMockMvcTester mockMvcTester(MockMvc mockMvc,\n\t\t\tObjectProvider<ServerHttpMessageConvertersCustomizer> customizersProvider) {\n\t\tMockMvcTester mockMvcTester = MockMvcTester.create(mockMvc);\n\t\tList<ServerHttpMessageConvertersCustomizer> customizers = customizersProvider.orderedStream().toList();\n\t\tif (!customizers.isEmpty()) {\n\t\t\tServerBuilder serverBuilder = HttpMessageConverters.forServer();\n\t\t\tcustomizersProvider.orderedStream().forEach((customizer) -> customizer.customize(serverBuilder));\n\t\t\tmockMvcTester = mockMvcTester.withHttpMessageConverters(serverBuilder.build());\n\t\t}\n\t\treturn mockMvcTester;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcWebClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.htmlunit.WebClient;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.web.htmlunit.UriBuilderFactoryWebClient;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.htmlunit.MockMvcWebClientBuilder;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\n/**\n * Auto-configuration for HtmlUnit {@link WebClient} MockMVC integration.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = MockMvcAutoConfiguration.class)\n@ConditionalOnClass(WebClient.class)\n@ConditionalOnBooleanProperty(name = \"spring.test.mockmvc.htmlunit.webclient.enabled\", matchIfMissing = true)\npublic final class MockMvcWebClientAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean({ WebClient.class, MockMvcWebClientBuilder.class })\n\t@ConditionalOnBean(MockMvc.class)\n\tMockMvcWebClientBuilder mockMvcWebClientBuilder(Environment environment, MockMvc mockMvc) {\n\t\tString url = environment.getProperty(\"spring.test.mockmvc.htmlunit.url\", \"http://localhost\");\n\t\treturn MockMvcWebClientBuilder.mockMvcSetup(mockMvc)\n\t\t\t.withDelegate(new UriBuilderFactoryWebClient(new DefaultUriBuilderFactory(url)));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnBean(MockMvcWebClientBuilder.class)\n\tWebClient htmlUnitWebClient(MockMvcWebClientBuilder builder) {\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcWebDriverAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.htmlunit.BrowserVersion;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.htmlunit.HtmlUnitDriver;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.test.web.htmlunit.UriBuilderFactoryWebConnectionHtmlUnitDriver;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;\nimport org.springframework.web.util.DefaultUriBuilderFactory;\n\n/**\n * Auto-configuration for Selenium {@link WebDriver} MockMVC integration.\n *\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = MockMvcAutoConfiguration.class)\n@ConditionalOnClass(HtmlUnitDriver.class)\n@ConditionalOnBooleanProperty(name = \"spring.test.mockmvc.htmlunit.webdriver.enabled\", matchIfMissing = true)\npublic final class MockMvcWebDriverAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean({ WebDriver.class, MockMvcHtmlUnitDriverBuilder.class })\n\t@ConditionalOnBean(MockMvc.class)\n\tMockMvcHtmlUnitDriverBuilder mockMvcHtmlUnitDriverBuilder(Environment environment, MockMvc mockMvc) {\n\t\tString url = environment.getProperty(\"spring.test.mockmvc.htmlunit.url\", \"http://localhost\");\n\t\treturn MockMvcHtmlUnitDriverBuilder.mockMvcSetup(mockMvc)\n\t\t\t.withDelegate(new UriBuilderFactoryWebConnectionHtmlUnitDriver(new DefaultUriBuilderFactory(url),\n\t\t\t\t\tBrowserVersion.CHROME));\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(WebDriver.class)\n\t@ConditionalOnBean(MockMvcHtmlUnitDriverBuilder.class)\n\tHtmlUnitDriver htmlUnitDriver(MockMvcHtmlUnitDriverBuilder builder,\n\t\t\tObjectProvider<MockMvcHtmlUnitDriverCustomizer> customizers) {\n\t\tHtmlUnitDriver driver = builder.build();\n\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(driver));\n\t\treturn driver;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/SpringBootMockMvcBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.io.PrintStream;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.EnumSet;\nimport java.util.List;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.annotation.WebInitParam;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.factory.ListableBeanFactory;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.web.servlet.AbstractFilterRegistrationBean;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.boot.web.servlet.FilterRegistration;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.RegistrationBean;\nimport org.springframework.boot.web.servlet.ServletContextInitializerBeans;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.web.servlet.MvcResult;\nimport org.springframework.test.web.servlet.ResultHandler;\nimport org.springframework.test.web.servlet.result.PrintingResultHandler;\nimport org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.context.WebApplicationContext;\n\n/**\n * {@link MockMvcBuilderCustomizer} for a typical Spring Boot application. Usually applied\n * automatically through {@link AutoConfigureMockMvc @AutoConfigureMockMvc}, but may also\n * be used directly.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic class SpringBootMockMvcBuilderCustomizer implements MockMvcBuilderCustomizer {\n\n\tprivate final WebApplicationContext context;\n\n\t/**\n\t * Whether to add servlet filters.\n\t */\n\tprivate boolean addFilters = true;\n\n\t/**\n\t * MVC Print option.\n\t */\n\tprivate MockMvcPrint print = MockMvcPrint.DEFAULT;\n\n\t/**\n\t * Whether to only print failed exchanges.\n\t */\n\tprivate boolean printOnlyOnFailure = true;\n\n\t/**\n\t * Create a new {@link SpringBootMockMvcBuilderCustomizer} instance.\n\t * @param context the source application context\n\t */\n\tpublic SpringBootMockMvcBuilderCustomizer(WebApplicationContext context) {\n\t\tAssert.notNull(context, \"'context' must not be null\");\n\t\tthis.context = context;\n\t}\n\n\t@Override\n\tpublic void customize(ConfigurableMockMvcBuilder<?> builder) {\n\t\tif (this.addFilters) {\n\t\t\taddFilters(builder);\n\t\t}\n\t\tResultHandler printHandler = getPrintHandler();\n\t\tif (printHandler != null) {\n\t\t\tbuilder.alwaysDo(printHandler);\n\t\t}\n\t}\n\n\tprivate @Nullable ResultHandler getPrintHandler() {\n\t\tLinesWriter writer = getLinesWriter();\n\t\tif (writer == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this.printOnlyOnFailure) {\n\t\t\twriter = new DeferredLinesWriter(this.context, writer);\n\t\t}\n\t\treturn new LinesWritingResultHandler(writer);\n\t}\n\n\tprivate @Nullable LinesWriter getLinesWriter() {\n\t\tif (this.print == MockMvcPrint.NONE) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this.print == MockMvcPrint.LOG_DEBUG) {\n\t\t\treturn (LoggingLinesWriter.isDebugEnabled()) ? new LoggingLinesWriter() : null;\n\t\t}\n\t\treturn new SystemLinesWriter(this.print);\n\t}\n\n\tprivate void addFilters(ConfigurableMockMvcBuilder<?> builder) {\n\t\tFilterRegistrationBeans registrations = new FilterRegistrationBeans(this.context);\n\t\tregistrations.stream()\n\t\t\t.map(AbstractFilterRegistrationBean.class::cast)\n\t\t\t.filter(AbstractFilterRegistrationBean<?>::isEnabled)\n\t\t\t.forEach((registration) -> addFilter(builder, registration));\n\t}\n\n\tprivate void addFilter(ConfigurableMockMvcBuilder<?> builder, AbstractFilterRegistrationBean<?> registration) {\n\t\tCollection<String> urls = registration.getUrlPatterns();\n\t\tFilter filter = registration.getFilter();\n\t\tAssert.state(filter != null, \"'filter' must not be null\");\n\t\tbuilder.addFilter(filter, registration.getFilterName(), registration.getInitParameters(),\n\t\t\t\tregistration.determineDispatcherTypes(), StringUtils.toStringArray(urls));\n\t}\n\n\tpublic void setAddFilters(boolean addFilters) {\n\t\tthis.addFilters = addFilters;\n\t}\n\n\tpublic boolean isAddFilters() {\n\t\treturn this.addFilters;\n\t}\n\n\tpublic void setPrint(MockMvcPrint print) {\n\t\tthis.print = print;\n\t}\n\n\tpublic MockMvcPrint getPrint() {\n\t\treturn this.print;\n\t}\n\n\tpublic void setPrintOnlyOnFailure(boolean printOnlyOnFailure) {\n\t\tthis.printOnlyOnFailure = printOnlyOnFailure;\n\t}\n\n\tpublic boolean isPrintOnlyOnFailure() {\n\t\treturn this.printOnlyOnFailure;\n\t}\n\n\t/**\n\t * {@link ResultHandler} that prints {@link MvcResult} details to a given\n\t * {@link LinesWriter}.\n\t */\n\tprivate static class LinesWritingResultHandler implements ResultHandler {\n\n\t\tprivate final LinesWriter writer;\n\n\t\tLinesWritingResultHandler(LinesWriter writer) {\n\t\t\tthis.writer = writer;\n\t\t}\n\n\t\t@Override\n\t\tpublic void handle(MvcResult result) throws Exception {\n\t\t\tLinesPrintingResultHandler delegate = new LinesPrintingResultHandler();\n\t\t\tdelegate.handle(result);\n\t\t\tdelegate.write(this.writer);\n\t\t}\n\n\t\tprivate static class LinesPrintingResultHandler extends PrintingResultHandler {\n\n\t\t\tprotected LinesPrintingResultHandler() {\n\t\t\t\tsuper(new Printer());\n\t\t\t}\n\n\t\t\tvoid write(LinesWriter writer) {\n\t\t\t\twriter.write(((Printer) getPrinter()).getLines());\n\t\t\t}\n\n\t\t\tprivate static final class Printer implements ResultValuePrinter {\n\n\t\t\t\tprivate final List<String> lines = new ArrayList<>();\n\n\t\t\t\t@Override\n\t\t\t\tpublic void printHeading(String heading) {\n\t\t\t\t\tthis.lines.add(\"\");\n\t\t\t\t\tthis.lines.add(String.format(\"%s:\", heading));\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void printValue(String label, @Nullable Object value) {\n\t\t\t\t\tif (value != null && value.getClass().isArray()) {\n\t\t\t\t\t\tvalue = CollectionUtils.arrayToList(value);\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.lines.add(\"%17s = %s\".formatted(label, value));\n\t\t\t\t\t}\n\t\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\t\tthis.lines.add(\"%17s = << Exception '%s' occurred while formatting >>\".formatted(label, ex));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tList<String> getLines() {\n\t\t\t\t\treturn this.lines;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Strategy interface to write MVC result lines.\n\t */\n\tinterface LinesWriter {\n\n\t\tvoid write(List<String> lines);\n\n\t}\n\n\t/**\n\t * {@link LinesWriter} used to defer writing until errors are detected.\n\t *\n\t * @see MockMvcPrintOnlyOnFailureTestExecutionListener\n\t */\n\tstatic class DeferredLinesWriter implements LinesWriter {\n\n\t\tprivate static final String BEAN_NAME = DeferredLinesWriter.class.getName();\n\n\t\tprivate final LinesWriter delegate;\n\n\t\tprivate final ThreadLocal<List<String>> lines = ThreadLocal.withInitial(ArrayList::new);\n\n\t\tDeferredLinesWriter(WebApplicationContext context, LinesWriter delegate) {\n\t\t\tAssert.state(context instanceof ConfigurableApplicationContext,\n\t\t\t\t\t\"A ConfigurableApplicationContext is required for printOnlyOnFailure\");\n\t\t\t((ConfigurableApplicationContext) context).getBeanFactory().registerSingleton(BEAN_NAME, this);\n\t\t\tthis.delegate = delegate;\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(List<String> lines) {\n\t\t\tthis.lines.get().addAll(lines);\n\t\t}\n\n\t\tvoid writeDeferredResult() {\n\t\t\tthis.delegate.write(this.lines.get());\n\t\t}\n\n\t\tstatic @Nullable DeferredLinesWriter get(ApplicationContext applicationContext) {\n\t\t\ttry {\n\t\t\t\treturn applicationContext.getBean(BEAN_NAME, DeferredLinesWriter.class);\n\t\t\t}\n\t\t\tcatch (NoSuchBeanDefinitionException ex) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tvoid clear() {\n\t\t\tthis.lines.remove();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link LinesWriter} to output results to the log.\n\t */\n\tprivate static final class LoggingLinesWriter implements LinesWriter {\n\n\t\tprivate static final Log logger = LogFactory.getLog(\"org.springframework.test.web.servlet.result\");\n\n\t\t@Override\n\t\tpublic void write(List<String> lines) {\n\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\tStringWriter stringWriter = new StringWriter();\n\t\t\t\tPrintWriter printWriter = new PrintWriter(stringWriter);\n\t\t\t\tfor (String line : lines) {\n\t\t\t\t\tprintWriter.println(line);\n\t\t\t\t}\n\t\t\t\tlogger.debug(\"MvcResult details:\\n\" + stringWriter);\n\t\t\t}\n\t\t}\n\n\t\tstatic boolean isDebugEnabled() {\n\t\t\treturn logger.isDebugEnabled();\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link LinesWriter} to output results to {@code System.out} or {@code System.err}.\n\t */\n\tprivate static class SystemLinesWriter implements LinesWriter {\n\n\t\tprivate final MockMvcPrint print;\n\n\t\tSystemLinesWriter(MockMvcPrint print) {\n\t\t\tthis.print = print;\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(List<String> lines) {\n\t\t\tPrintStream printStream = getPrintStream();\n\t\t\tfor (String line : lines) {\n\t\t\t\tprintStream.println(line);\n\t\t\t}\n\t\t}\n\n\t\tprivate PrintStream getPrintStream() {\n\t\t\tif (this.print == MockMvcPrint.SYSTEM_ERR) {\n\t\t\t\treturn System.err;\n\t\t\t}\n\t\t\treturn System.out;\n\t\t}\n\n\t}\n\n\tprivate static class FilterRegistrationBeans extends ServletContextInitializerBeans {\n\n\t\tFilterRegistrationBeans(ListableBeanFactory beanFactory) {\n\t\t\tsuper(beanFactory, FilterRegistrationBean.class, DelegatingFilterProxyRegistrationBean.class);\n\t\t}\n\n\t\t@Override\n\t\tprotected void addAdaptableBeans(ListableBeanFactory beanFactory) {\n\t\t\taddAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter(beanFactory));\n\t\t}\n\n\t\tprivate static final class FilterRegistrationBeanAdapter implements RegistrationBeanAdapter<Filter> {\n\n\t\t\tprivate final ListableBeanFactory beanFactory;\n\n\t\t\tprivate FilterRegistrationBeanAdapter(ListableBeanFactory beanFactory) {\n\t\t\t\tthis.beanFactory = beanFactory;\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic RegistrationBean createRegistrationBean(String beanName, Filter source,\n\t\t\t\t\tint totalNumberOfSourceBeans) {\n\t\t\t\tFilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>(source);\n\t\t\t\tbean.setName(beanName);\n\t\t\t\tFilterRegistration registrationAnnotation = this.beanFactory.findAnnotationOnBean(beanName,\n\t\t\t\t\t\tFilterRegistration.class);\n\t\t\t\tif (registrationAnnotation != null) {\n\t\t\t\t\t// Supports @Order annotation on @Bean methods\n\t\t\t\t\tOrder orderAnnotation = this.beanFactory.findAnnotationOnBean(beanName, Order.class);\n\t\t\t\t\tAssert.state(orderAnnotation != null, \"'orderAnnotation' must not be null\");\n\t\t\t\t\tconfigureFromAnnotation(bean, registrationAnnotation, orderAnnotation);\n\t\t\t\t}\n\t\t\t\treturn bean;\n\t\t\t}\n\n\t\t\tprivate void configureFromAnnotation(FilterRegistrationBean<Filter> bean,\n\t\t\t\t\tFilterRegistration registrationAnnotation, Order orderAnnotation) {\n\t\t\t\tbean.setEnabled(registrationAnnotation.enabled());\n\t\t\t\tbean.setOrder(orderAnnotation.value());\n\t\t\t\tif (StringUtils.hasText(registrationAnnotation.name())) {\n\t\t\t\t\tbean.setName(registrationAnnotation.name());\n\t\t\t\t}\n\t\t\t\tif (registrationAnnotation.dispatcherTypes().length > 0) {\n\t\t\t\t\tbean.setDispatcherTypes(EnumSet.copyOf(Arrays.asList(registrationAnnotation.dispatcherTypes())));\n\t\t\t\t}\n\t\t\t\tfor (WebInitParam param : registrationAnnotation.initParameters()) {\n\t\t\t\t\tbean.addInitParameter(param.name(), param.value());\n\t\t\t\t}\n\t\t\t\tbean.setUrlPatterns(Arrays.asList(registrationAnnotation.urlPatterns()));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebDriverContextCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.MergedContextConfiguration;\n\n/**\n * {@link ContextCustomizer} that registers a {@link WebDriverScope} and configures\n * appropriate bean definitions to use it.\n *\n * @author Phillip Webb\n * @see WebDriverScope\n */\nclass WebDriverContextCustomizer implements ContextCustomizer {\n\n\t@Override\n\tpublic void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {\n\t\tWebDriverScope.registerWith(context);\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\treturn obj != null && obj.getClass() == getClass();\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn getClass().hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebDriverContextCustomizerFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.test.context.ContextConfigurationAttributes;\nimport org.springframework.test.context.ContextCustomizer;\nimport org.springframework.test.context.ContextCustomizerFactory;\n\n/**\n * {@link ContextCustomizerFactory} to register a {@link WebDriverScope} and configure\n * appropriate bean definitions to use it. Expects the scope to be reset with a\n * {@link WebDriverTestExecutionListener}.\n *\n * @author Phillip Webb\n * @see WebDriverTestExecutionListener\n * @see WebDriverScope\n */\nclass WebDriverContextCustomizerFactory implements ContextCustomizerFactory {\n\n\t@Override\n\tpublic ContextCustomizer createContextCustomizer(Class<?> testClass,\n\t\t\tList<ContextConfigurationAttributes> configAttributes) {\n\t\treturn new WebDriverContextCustomizer();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebDriverScope.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.openqa.selenium.WebDriver;\n\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.config.Scope;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * A special scope used for {@link WebDriver} beans. Usually registered by a\n * {@link WebDriverContextCustomizerFactory} and reset by a\n * {@link WebDriverTestExecutionListener}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see WebDriverContextCustomizerFactory\n * @see WebDriverTestExecutionListener\n */\npublic class WebDriverScope implements Scope {\n\n\t/**\n\t * WebDriver bean scope name.\n\t */\n\tpublic static final String NAME = \"webDriver\";\n\n\tprivate static final String WEB_DRIVER_CLASS = \"org.openqa.selenium.WebDriver\";\n\n\tprivate static final String[] BEAN_CLASSES = { WEB_DRIVER_CLASS,\n\t\t\t\"org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder\" };\n\n\tprivate final Map<String, Object> instances = new HashMap<>();\n\n\t@Override\n\tpublic Object get(String name, ObjectFactory<?> objectFactory) {\n\t\tsynchronized (this.instances) {\n\t\t\tObject instance = this.instances.get(name);\n\t\t\tif (instance == null) {\n\t\t\t\tinstance = objectFactory.getObject();\n\t\t\t\tthis.instances.put(name, instance);\n\t\t\t}\n\t\t\treturn instance;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Object remove(String name) {\n\t\tsynchronized (this.instances) {\n\t\t\treturn this.instances.remove(name);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void registerDestructionCallback(String name, Runnable callback) {\n\t}\n\n\t@Override\n\tpublic @Nullable Object resolveContextualObject(String key) {\n\t\treturn null;\n\t}\n\n\t@Override\n\tpublic @Nullable String getConversationId() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Reset all instances in the scope.\n\t * @return {@code true} if items were reset\n\t */\n\tboolean reset() {\n\t\tboolean reset = false;\n\t\tsynchronized (this.instances) {\n\t\t\tfor (Object instance : this.instances.values()) {\n\t\t\t\treset = true;\n\t\t\t\tif (instance instanceof WebDriver webDriver) {\n\t\t\t\t\twebDriver.quit();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.instances.clear();\n\t\t}\n\t\treturn reset;\n\t}\n\n\t/**\n\t * Register this scope with the specified context and reassign appropriate bean\n\t * definitions to use it.\n\t * @param context the application context\n\t */\n\tstatic void registerWith(ConfigurableApplicationContext context) {\n\t\tif (!ClassUtils.isPresent(WEB_DRIVER_CLASS, null)) {\n\t\t\treturn;\n\t\t}\n\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\tif (beanFactory.getRegisteredScope(NAME) == null) {\n\t\t\tbeanFactory.registerScope(NAME, new WebDriverScope());\n\t\t}\n\t\tcontext.addBeanFactoryPostProcessor(WebDriverScope::postProcessBeanFactory);\n\t}\n\n\tprivate static void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {\n\t\tfor (String beanClass : BEAN_CLASSES) {\n\t\t\tfor (String beanName : beanFactory.getBeanNamesForType(ClassUtils.resolveClassName(beanClass, null))) {\n\t\t\t\tBeanDefinition definition = beanFactory.getBeanDefinition(beanName);\n\t\t\t\tif (!StringUtils.hasLength(definition.getScope())) {\n\t\t\t\t\tdefinition.setScope(NAME);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Return the {@link WebDriverScope} being used by the specified context (if any).\n\t * @param context the application context\n\t * @return the web driver scope or {@code null}\n\t */\n\tstatic @Nullable WebDriverScope getFrom(ApplicationContext context) {\n\t\tif (context instanceof ConfigurableApplicationContext configurableContext) {\n\t\t\tScope scope = configurableContext.getBeanFactory().getRegisteredScope(NAME);\n\t\t\treturn (scope instanceof WebDriverScope webDriverScope) ? webDriverScope : null;\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebDriverTestExecutionListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.springframework.core.Ordered;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestExecutionListener;\nimport org.springframework.test.context.support.AbstractTestExecutionListener;\nimport org.springframework.test.context.support.DependencyInjectionTestExecutionListener;\n\n/**\n * {@link TestExecutionListener} to reset the {@link WebDriverScope}.\n *\n * @author Phillip Webb\n * @since 4.0.0\n * @see WebDriverContextCustomizerFactory\n * @see WebDriverScope\n */\npublic class WebDriverTestExecutionListener extends AbstractTestExecutionListener {\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE - 100;\n\t}\n\n\t@Override\n\tpublic void afterTestMethod(TestContext testContext) throws Exception {\n\t\tWebDriverScope scope = WebDriverScope.getFrom(testContext.getApplicationContext());\n\t\tif (scope != null && scope.reset()) {\n\t\t\ttestContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE,\n\t\t\t\t\tBoolean.TRUE);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebMvcTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.web.servlet.MockMvc;\n\n/**\n * Annotation that can be used for a Spring MVC test that focuses <strong>only</strong> on\n * Spring MVC components.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to MVC tests.\n * Similarly, component scanning is limited to beans annotated with:\n * <ul>\n * <li>{@code @Controller}</li>\n * <li>{@code @ControllerAdvice}</li>\n * <li>{@code @JacksonComponent}</li>\n * <li>{@code @JsonComponent} (Jackson 2, deprecated)</li>\n * </ul>\n * <p>\n * as well as beans that implement:\n * <ul>\n * <li>{@code Converter}</li>\n * <li>{@code DelegatingFilterProxyRegistrationBean}</li>\n * <li>{@code ErrorAttributes}</li>\n * <li>{@code Filter}</li>\n * <li>{@code FilterRegistrationBean}</li>\n * <li>{@code GenericConverter}</li>\n * <li>{@code HandlerInterceptor}</li>\n * <li>{@code HandlerMethodArgumentResolver}</li>\n * <li>{@code HttpMessageConverter}</li>\n * <li>{@code IDialect}, if Thymeleaf is available</li>\n * <li>{@code JacksonModule}, if Jackson is available</li>\n * <li>{@code Module} (deprecated), if Jackson 2 is available</li>\n * <li>{@code SecurityFilterChain}</li>\n * <li>{@code WebMvcConfigurer}</li>\n * <li>{@code WebMvcRegistrations}</li>\n * <li>{@code WebSecurityConfigurer}</li>\n * </ul>\n * <p>\n * By default, tests annotated with {@code @WebMvcTest} will also auto-configure Spring\n * Security and {@link MockMvc} (include support for HtmlUnit WebClient and Selenium\n * WebDriver). For more fine-grained control of MockMVC the\n * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} annotation can be used.\n * <p>\n * Typically {@code @WebMvcTest} is used in combination with\n * {@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}\n * or {@link Import @Import} to create any collaborators required by your\n * {@code @Controller} beans.\n * <p>\n * If you are looking to load your full application configuration and use MockMVC, you\n * should consider {@link SpringBootTest @SpringBootTest} combined with\n * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} rather than this annotation.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @see AutoConfigureWebMvc\n * @see AutoConfigureMockMvc\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(WebMvcTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(WebMvcTypeExcludeFilter.class)\n@AutoConfigureWebMvc\n@AutoConfigureMockMvc\n@ImportAutoConfiguration\npublic @interface WebMvcTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the controllers to test. This is an alias of {@link #controllers()} which\n\t * can be used for brevity if no other attributes are defined. See\n\t * {@link #controllers()} for details.\n\t * @see #controllers()\n\t * @return the controllers to test\n\t */\n\t@AliasFor(\"controllers\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the controllers to test. May be left blank if all {@code @Controller}\n\t * beans should be added to the application context.\n\t * @see #value()\n\t * @return the controllers to test\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] controllers() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default only\n\t * {@code @Controller} (when no explicit {@link #controllers() controllers} are\n\t * defined), {@code @ControllerAdvice} and {@code WebMvcConfigurer} beans are\n\t * included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tFilter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tFilter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebMvcTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextBootstrapper;\nimport org.springframework.test.context.web.WebMergedContextConfiguration;\n\n/**\n * {@link TestContextBootstrapper} for {@link WebMvcTest @WebMvcTest} support.\n *\n * @author Phillip Webb\n * @author Artsiom Yudovin\n * @author Lorenzo Dee\n */\nclass WebMvcTestContextBootstrapper extends TestSliceTestContextBootstrapper<WebMvcTest> {\n\n\t@Override\n\tprotected MergedContextConfiguration processMergedContextConfiguration(MergedContextConfiguration mergedConfig) {\n\t\tMergedContextConfiguration processedMergedConfiguration = super.processMergedContextConfiguration(mergedConfig);\n\t\treturn new WebMergedContextConfiguration(processedMergedConfiguration, determineResourceBasePath(mergedConfig));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/WebMvcTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.core.convert.converter.GenericConverter;\nimport org.springframework.http.converter.HttpMessageConverter;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.method.support.HandlerMethodArgumentResolver;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * {@link TypeExcludeFilter} for {@link WebMvcTest @WebMvcTest}.\n *\n * @author Phillip Webb\n * @author Madhura Bhave\n * @author Yanming Zhou\n */\nclass WebMvcTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<WebMvcTest> {\n\n\tprivate static final Class<?>[] NO_CONTROLLERS = {};\n\n\tprivate static final String[] OPTIONAL_INCLUDES = { \"tools.jackson.databind.JacksonModule\",\n\t\t\t\"org.springframework.boot.jackson.JacksonComponent\", \"org.thymeleaf.dialect.IDialect\",\n\t\t\t\"com.fasterxml.jackson.databind.Module\", \"org.springframework.boot.jackson2.JsonComponent\" };\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>();\n\t\tincludes.add(ControllerAdvice.class);\n\t\tincludes.add(WebMvcConfigurer.class);\n\t\tincludes.add(WebMvcRegistrations.class);\n\t\tincludes.add(jakarta.servlet.Filter.class);\n\t\tincludes.add(FilterRegistrationBean.class);\n\t\tincludes.add(DelegatingFilterProxyRegistrationBean.class);\n\t\tincludes.add(HandlerMethodArgumentResolver.class);\n\t\tincludes.add(HttpMessageConverter.class);\n\t\tincludes.add(ErrorAttributes.class);\n\t\tincludes.add(Converter.class);\n\t\tincludes.add(GenericConverter.class);\n\t\tincludes.add(HandlerInterceptor.class);\n\t\tfor (String optionalInclude : OPTIONAL_INCLUDES) {\n\t\t\ttry {\n\t\t\t\tincludes.add(ClassUtils.forName(optionalInclude, null));\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\tKNOWN_INCLUDES = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES_AND_CONTROLLER;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>(KNOWN_INCLUDES);\n\t\tincludes.add(Controller.class);\n\t\tKNOWN_INCLUDES_AND_CONTROLLER = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate final Class<?>[] controllers;\n\n\tWebMvcTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.controllers = getAnnotation().getValue(\"controllers\", Class[].class).orElse(NO_CONTROLLERS);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\tif (ObjectUtils.isEmpty(this.controllers)) {\n\t\t\treturn KNOWN_INCLUDES_AND_CONTROLLER;\n\t\t}\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.controllers));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring MVC tests.\n */\n@NullMarked\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.mockmvc.htmlunit.url\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"URL to use when HtmlUnit expands relative paths.\",\n      \"defaultValue\": \"http://localhost\"\n    },\n    {\n      \"name\": \"spring.test.mockmvc.htmlunit.webclient.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether HTMLUnit's WebClient should be auto-configured when it's on the classpath.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.test.mockmvc.htmlunit.webdriver.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether Selenium's WebDriver should be auto-configured when it's on the classpath.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.test.mockmvc.webclient.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.test.mockmvc.htmlunit.webclient.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    },\n    {\n      \"name\": \"spring.test.mockmvc.webdriver.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"spring.test.mockmvc.htmlunit.webdriver.enabled\",\n        \"since\": \"4.0.0\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc.imports",
    "content": "org.springframework.boot.webmvc.test.autoconfigure.MockMvcAutoConfiguration\norg.springframework.boot.webmvc.test.autoconfigure.MockMvcWebClientAutoConfiguration\norg.springframework.boot.webmvc.test.autoconfigure.MockMvcWebDriverAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/resources/META-INF/spring/org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureWebMvc.imports",
    "content": "org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration\norg.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration\norg.springframework.boot.servlet.autoconfigure.HttpEncodingAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration\norg.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration\noptional:org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration\noptional:org.springframework.boot.validation.autoconfigure.ValidationAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Context Customizer Factories\norg.springframework.test.context.ContextCustomizerFactory=\\\norg.springframework.boot.webmvc.test.autoconfigure.WebDriverContextCustomizerFactory\n\n# Spring Test Execution Listeners\norg.springframework.test.context.TestExecutionListener=\\\norg.springframework.boot.webmvc.test.autoconfigure.MockMvcPrintOnlyOnFailureTestExecutionListener,\\\norg.springframework.boot.webmvc.test.autoconfigure.WebDriverTestExecutionListener\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/main/webapp/inwebapp",
    "content": ""
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/ExampleWebMvcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\npublic class ExampleWebMvcApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.RequestBuilder;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link MockMvcAutoConfiguration}.\n *\n * @author Madhura Bhave\n * @author Brian Clozel\n * @author Stephane Nicoll\n */\nclass MockMvcAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MockMvcAutoConfiguration.class));\n\n\t@Test\n\tvoid registersDispatcherServletFromMockMvc() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tMockMvc mockMvc = context.getBean(MockMvc.class);\n\t\t\tassertThat(context).hasSingleBean(DispatcherServlet.class);\n\t\t\tassertThat(context.getBean(DispatcherServlet.class)).isEqualTo(mockMvc.getDispatcherServlet());\n\t\t});\n\t}\n\n\t@Test\n\tvoid registersMockMvcTester() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MockMvcTester.class));\n\t}\n\n\t@Test\n\tvoid shouldNotRegisterMockMvcTesterIfAssertJMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(org.assertj.core.api.Assert.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MockMvcTester.class));\n\t}\n\n\t@Test\n\tvoid registeredMockMvcTesterDelegatesToConfiguredMockMvc() {\n\t\tMockMvc mockMvc = mock(MockMvc.class);\n\t\tthis.contextRunner.withBean(\"customMockMvc\", MockMvc.class, () -> mockMvc).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(MockMvc.class).hasSingleBean(MockMvcTester.class);\n\t\t\tMockMvcTester mvc = context.getBean(MockMvcTester.class);\n\t\t\tmvc.get().uri(\"/dummy\").exchange();\n\t\t\tthen(mockMvc).should().perform(any(RequestBuilder.class));\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/SpringBootMockMvcBuilderCustomizerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServlet;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.webmvc.test.autoconfigure.SpringBootMockMvcBuilderCustomizer.DeferredLinesWriter;\nimport org.springframework.boot.webmvc.test.autoconfigure.SpringBootMockMvcBuilderCustomizer.LinesWriter;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.mock.web.MockServletContext;\nimport org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\n\nimport static org.assertj.core.api.Assertions.as;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.tuple;\n\n/**\n * Tests for {@link SpringBootMockMvcBuilderCustomizer}.\n *\n * @author Madhura Bhave\n */\nclass SpringBootMockMvcBuilderCustomizerTests {\n\n\t@Test\n\tvoid customizeShouldAddFilters() {\n\t\tAnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tcontext.setServletContext(servletContext);\n\t\tcontext.register(ServletConfiguration.class, FilterConfiguration.class);\n\t\tcontext.refresh();\n\t\tDefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(context);\n\t\tSpringBootMockMvcBuilderCustomizer customizer = new SpringBootMockMvcBuilderCustomizer(context);\n\t\tcustomizer.customize(builder);\n\t\tFilterRegistrationBean<?> registrationBean = (FilterRegistrationBean<?>) context.getBean(\"otherTestFilter\");\n\t\tTestFilter testFilter = context.getBean(\"testFilter\", TestFilter.class);\n\t\tOtherTestFilter otherTestFilter = (OtherTestFilter) registrationBean.getFilter();\n\t\tassertThat(otherTestFilter).isNotNull();\n\t\tassertThat(builder).extracting(\"filters\", as(InstanceOfAssertFactories.LIST))\n\t\t\t.extracting(\"delegate\", \"dispatcherTypes\")\n\t\t\t.containsExactlyInAnyOrder(tuple(testFilter, EnumSet.of(DispatcherType.REQUEST)),\n\t\t\t\t\ttuple(otherTestFilter, EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)));\n\t\tbuilder.build();\n\t\tassertThat(testFilter.filterName).isEqualTo(\"testFilter\");\n\t\tassertThat(testFilter.initParams).isEmpty();\n\t\tassertThat(otherTestFilter.filterName).isEqualTo(\"otherTestFilter\");\n\t\tassertThat(otherTestFilter.initParams).isEqualTo(Map.of(\"a\", \"alpha\", \"b\", \"bravo\"));\n\t}\n\n\t@Test\n\tvoid whenCalledInParallelDeferredLinesWriterSeparatesOutputByThread() throws Exception {\n\t\tAnnotationConfigServletWebApplicationContext context = new AnnotationConfigServletWebApplicationContext();\n\t\tMockServletContext servletContext = new MockServletContext();\n\t\tcontext.setServletContext(servletContext);\n\t\tcontext.register(ServletConfiguration.class, FilterConfiguration.class);\n\t\tcontext.refresh();\n\n\t\tCapturingLinesWriter delegate = new CapturingLinesWriter();\n\t\tnew DeferredLinesWriter(context, delegate);\n\t\tCountDownLatch latch = new CountDownLatch(10);\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tThread thread = new Thread(() -> {\n\t\t\t\tfor (int j = 0; j < 1000; j++) {\n\t\t\t\t\tDeferredLinesWriter writer = DeferredLinesWriter.get(context);\n\t\t\t\t\tassertThat(writer).isNotNull();\n\t\t\t\t\twriter.write(Arrays.asList(\"1\", \"2\", \"3\", \"4\", \"5\"));\n\t\t\t\t\twriter.writeDeferredResult();\n\t\t\t\t\twriter.clear();\n\t\t\t\t}\n\t\t\t\tlatch.countDown();\n\t\t\t});\n\t\t\tthread.start();\n\t\t}\n\t\tassertThat(latch.await(60, TimeUnit.SECONDS)).isTrue();\n\n\t\tassertThat(delegate.allWritten).hasSize(10000);\n\t\tassertThat(delegate.allWritten)\n\t\t\t.allSatisfy((written) -> assertThat(written).containsExactly(\"1\", \"2\", \"3\", \"4\", \"5\"));\n\t}\n\n\tprivate static final class CapturingLinesWriter implements LinesWriter {\n\n\t\tList<List<String>> allWritten = new ArrayList<>();\n\n\t\tprivate final Object monitor = new Object();\n\n\t\t@Override\n\t\tpublic void write(List<String> lines) {\n\t\t\tList<String> written = new ArrayList<>(lines);\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.allWritten.add(written);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ServletConfiguration {\n\n\t\t@Bean\n\t\tTestServlet testServlet() {\n\t\t\treturn new TestServlet();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class FilterConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<OtherTestFilter> otherTestFilter() {\n\t\t\tFilterRegistrationBean<OtherTestFilter> filterRegistrationBean = new FilterRegistrationBean<>(\n\t\t\t\t\tnew OtherTestFilter());\n\t\t\tfilterRegistrationBean.setInitParameters(Map.of(\"a\", \"alpha\", \"b\", \"bravo\"));\n\t\t\tfilterRegistrationBean.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR));\n\t\t\treturn filterRegistrationBean;\n\t\t}\n\n\t\t@Bean\n\t\tTestFilter testFilter() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t}\n\n\tstatic class TestServlet extends HttpServlet {\n\n\t}\n\n\tstatic class TestFilter implements Filter {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String filterName;\n\n\t\tprivate final Map<String, String> initParams = new HashMap<>();\n\n\t\t@Override\n\t\tpublic void init(FilterConfig filterConfig) {\n\t\t\tthis.filterName = filterConfig.getFilterName();\n\t\t\tCollections.list(filterConfig.getInitParameterNames())\n\t\t\t\t.forEach((name) -> this.initParams.put(name, filterConfig.getInitParameter(name)));\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroy() {\n\n\t\t}\n\n\t}\n\n\tstatic class OtherTestFilter implements Filter {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String filterName;\n\n\t\tprivate final Map<String, String> initParams = new HashMap<>();\n\n\t\t@Override\n\t\tpublic void init(FilterConfig filterConfig) {\n\t\t\tthis.filterName = filterConfig.getFilterName();\n\t\t\tCollections.list(filterConfig.getInitParameterNames())\n\t\t\t\t.forEach((name) -> this.initParams.put(name, filterConfig.getInitParameter(name)));\n\t\t}\n\n\t\t@Override\n\t\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {\n\n\t\t}\n\n\t\t@Override\n\t\tpublic void destroy() {\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/WebMvcTestAutoConfigurationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.boot.servlet.autoconfigure.HttpEncodingAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Tests for the auto-configuration imported by {@link WebMvcTest @WebMvcTest}.\n *\n * @author Andy Wilkinson\n * @author Levi Puot Paul\n * @author Madhura Bhave\n */\n@WebMvcTest\nclass WebMvcTestAutoConfigurationIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid taskExecutionAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(TaskExecutionAutoConfiguration.class));\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorWithApplicationTaskExecutor() {\n\t\tassertThat(this.applicationContext.getBeansOfType(AsyncTaskExecutor.class)).hasSize(1);\n\t\tassertThat(this.applicationContext.getBean(RequestMappingHandlerAdapter.class)).extracting(\"taskExecutor\")\n\t\t\t.isSameAs(this.applicationContext.getBean(\"applicationTaskExecutor\"));\n\t}\n\n\t@Test\n\tvoid httpEncodingAutoConfigurationWasImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(HttpEncodingAutoConfiguration.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/WebMvcTestPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link WebMvcTest#properties properties} attribute of\n * {@link WebMvcTest @WebMvcTest}.\n *\n * @author Artsiom Yudovin\n */\n@WebMvcTest(properties = \"spring.profiles.active=test\")\nclass WebMvcTestPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(WebMvcTestPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/WebMvcTypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.module.SimpleModule;\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations;\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.servlet.HandlerInterceptor;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTypeExcludeFilter}.\n *\n * @author Phillip Webb\n * @author Yanming Zhou\n */\nclass WebMvcTypeExcludeFilterTests {\n\n\tprivate final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\t@Test\n\tvoid matchWhenHasNoControllers() throws Exception {\n\t\tWebMvcTypeExcludeFilter filter = new WebMvcTypeExcludeFilter(WithNoControllers.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWebMvcRegistrations.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWhenHasController() throws Exception {\n\t\tWebMvcTypeExcludeFilter filter = new WebMvcTypeExcludeFilter(WithController.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWebMvcRegistrations.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchNotUsingDefaultFilters() throws Exception {\n\t\tWebMvcTypeExcludeFilter filter = new WebMvcTypeExcludeFilter(NotUsingDefaultFilters.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isTrue();\n\t\tassertThat(excludes(filter, Controller2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleWebMvcRegistrations.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleMessageConverter.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleHandlerInterceptor.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWithIncludeFilter() throws Exception {\n\t\tWebMvcTypeExcludeFilter filter = new WebMvcTypeExcludeFilter(WithIncludeFilter.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isFalse();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWebMvcRegistrations.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWithExcludeFilter() throws Exception {\n\t\tWebMvcTypeExcludeFilter filter = new WebMvcTypeExcludeFilter(WithExcludeFilter.class);\n\t\tassertThat(excludes(filter, Controller1.class)).isTrue();\n\t\tassertThat(excludes(filter, Controller2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleControllerAdvice.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWeb.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleWebMvcRegistrations.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleMessageConverter.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleService.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleRepository.class)).isTrue();\n\t\tassertThat(excludes(filter, ExampleHandlerInterceptor.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJacksonComponent.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleModule2.class)).isFalse();\n\t\tassertThat(excludes(filter, ExampleJsonComponent.class)).isFalse();\n\t}\n\n\tprivate boolean excludes(WebMvcTypeExcludeFilter filter, Class<?> type) throws IOException {\n\t\tMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());\n\t\treturn filter.match(metadataReader, this.metadataReaderFactory);\n\t}\n\n\t@WebMvcTest\n\tstatic class WithNoControllers {\n\n\t}\n\n\t@WebMvcTest(Controller1.class)\n\tstatic class WithController {\n\n\t}\n\n\t@WebMvcTest(useDefaultFilters = false)\n\tstatic class NotUsingDefaultFilters {\n\n\t}\n\n\t@WebMvcTest(includeFilters = @Filter(Repository.class))\n\tstatic class WithIncludeFilter {\n\n\t}\n\n\t@WebMvcTest(excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Controller1.class))\n\tstatic class WithExcludeFilter {\n\n\t}\n\n\t@Controller\n\tstatic class Controller1 {\n\n\t}\n\n\t@Controller\n\tstatic class Controller2 {\n\n\t}\n\n\t@ControllerAdvice\n\tstatic class ExampleControllerAdvice {\n\n\t}\n\n\tstatic class ExampleWeb implements WebMvcConfigurer {\n\n\t}\n\n\tstatic class ExampleWebMvcRegistrations implements WebMvcRegistrations {\n\n\t}\n\n\t@SuppressWarnings(\"removal\")\n\tstatic class ExampleMessageConverter extends JacksonJsonHttpMessageConverter {\n\n\t}\n\n\t@Service\n\tstatic class ExampleService {\n\n\t}\n\n\t@Repository\n\tstatic class ExampleRepository {\n\n\t}\n\n\tstatic class ExampleHandlerInterceptor implements HandlerInterceptor {\n\n\t}\n\n\tstatic class ExampleModule extends SimpleModule {\n\n\t}\n\n\t@JacksonComponent\n\tstatic class ExampleJacksonComponent {\n\n\t}\n\n\tstatic class ExampleModule2 extends com.fasterxml.jackson.databind.module.SimpleModule {\n\n\t}\n\n\t@org.springframework.boot.jackson2.JsonComponent\n\t@SuppressWarnings(\"removal\")\n\tstatic class ExampleJsonComponent {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleArgument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\n/**\n * @author Phillip Webb\n */\npublic class ExampleArgument {\n\n\tprivate final String value;\n\n\tpublic ExampleArgument(String value) {\n\t\tthis.value = value;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.value;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleController1.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.context.request.RequestAttributes;\nimport org.springframework.web.context.request.WebRequest;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@RestController\npublic class ExampleController1 {\n\n\t@GetMapping(\"/one\")\n\tpublic String one() {\n\t\treturn \"one\";\n\t}\n\n\t@GetMapping(\"/error\")\n\tpublic String error() {\n\t\tthrow new ExampleException();\n\t}\n\n\t@GetMapping(path = \"/html\", produces = \"text/html\")\n\tpublic String html() {\n\t\treturn \"<html><body>Hello</body></html>\";\n\t}\n\n\t@GetMapping(\"/formatting\")\n\tpublic String formatting(WebRequest request) {\n\t\tObject formattingFails = new Object() {\n\t\t\t@Override\n\t\t\tpublic String toString() {\n\t\t\t\tthrow new IllegalStateException(\"Formatting failed\");\n\t\t\t}\n\t\t};\n\t\trequest.setAttribute(\"attribute-1\", formattingFails, RequestAttributes.SCOPE_SESSION);\n\t\treturn \"formatting\";\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleController2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\n@Controller\npublic class ExampleController2 {\n\n\t@GetMapping(\"/two\")\n\t@ResponseBody\n\tpublic String two(ExampleArgument argument) {\n\t\treturn argument + \"two\";\n\t}\n\n\t@GetMapping(\"/two/{id}\")\n\t@ResponseBody\n\tpublic String two(@PathVariable ExampleId id) {\n\t\treturn id.getId() + \"two\";\n\t}\n\n\t@PostMapping(\"/two/{id}\")\n\t@ResponseBody\n\tpublic ExampleResult twoUpdate(@PathVariable String id) {\n\t\treturn new ExampleResult(id);\n\t}\n\n\t@PostMapping(\"/two2/{id}\")\n\t@ResponseBody\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tpublic ExampleResult2 two2Update(@PathVariable String id) {\n\t\treturn new ExampleResult2(id);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleController3.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport jakarta.validation.constraints.Size;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Stephane Nicoll\n */\n@RestController\n@Validated\npublic class ExampleController3 {\n\n\t@GetMapping(\"/three/{id}\")\n\tpublic String three(@PathVariable @Size(max = 4) String id) {\n\t\treturn \"Hello \" + id;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleControllerAdvice.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.servlet.NoHandlerFoundException;\n\n/**\n * Example {@link ControllerAdvice @ControllerAdvice} used with\n * {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@ControllerAdvice\npublic class ExampleControllerAdvice {\n\n\t@ExceptionHandler\n\tpublic ResponseEntity<String> onExampleError(ExampleException exception) {\n\t\treturn ResponseEntity.ok(\"recovered\");\n\t}\n\n\t@ExceptionHandler(NoHandlerFoundException.class)\n\t@ResponseStatus(HttpStatus.BAD_REQUEST)\n\tpublic ResponseEntity<String> noHandlerFoundHandler(NoHandlerFoundException exception) {\n\t\treturn ResponseEntity.badRequest().body(\"Invalid request: \" + exception.getRequestURL());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\n\n/**\n * Example exception used in {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\npublic class ExampleException extends RuntimeException {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.core.Ordered;\nimport org.springframework.stereotype.Component;\n\n/**\n * Example filter used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\n@Component\npublic class ExampleFilter implements Filter, Ordered {\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tchain.doFilter(request, response);\n\t\t((HttpServletResponse) response).addHeader(\"x-test\", \"abc\");\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleId.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.util.UUID;\n\nimport org.springframework.core.convert.converter.GenericConverter;\n\n/**\n * An example attribute that requires a {@link GenericConverter}.\n *\n * @author Stephane Nicoll\n */\npublic class ExampleId {\n\n\tprivate final UUID id;\n\n\tExampleId(UUID id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic UUID getId() {\n\t\treturn this.id;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleIdConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.util.UUID;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.stereotype.Component;\n\n/**\n * Example {@link Converter} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Stephane Nicoll\n */\n@Component\npublic class ExampleIdConverter implements Converter<String, ExampleId> {\n\n\t@Override\n\tpublic ExampleId convert(String source) {\n\t\treturn new ExampleId(UUID.fromString(source));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleMockableService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example mockable {@link Service @Service} used with {@link WebMvcTest @WebMvcTest}\n * tests.\n *\n * @author Phillip Webb\n */\n@Service\npublic class ExampleMockableService {\n\n\tpublic ExampleMockableService() {\n\t\tthrow new IllegalStateException(\"Should not be called\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleRealService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.stereotype.Service;\n\n/**\n * Example {@link Service @Service} used with {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\n@Service\npublic class ExampleRealService {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleResult.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.springframework.boot.jackson.JacksonComponent;\n\n/**\n * Example result that requires a {@link JacksonComponent}.\n *\n * @param id sample data\n * @author Stephane Nicoll\n */\npublic record ExampleResult(String id) {\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleResult2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\n/**\n * Example result that requires a {@link org.springframework.boot.jackson2.JsonComponent}.\n *\n * @param id sample data\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@Deprecated(since = \"4.0.0\", forRemoval = true)\npublic record ExampleResult2(String id) {\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleResult2Serializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson2.JsonComponent;\nimport org.springframework.boot.jackson2.JsonObjectSerializer;\n\n/**\n * {@link JsonObjectSerializer} for {@link ExampleResult}.\n *\n * @author Stephane Nicoll\n * @deprecated since 4.0.0 for removal in 4.3.0 in favor of Jackson 3\n */\n@JsonComponent\n@Deprecated(since = \"4.0.0\", forRemoval = true)\n@SuppressWarnings(\"removal\")\npublic class ExampleResult2Serializer extends JsonObjectSerializer<ExampleResult2> {\n\n\t@Override\n\tprotected void serializeObject(ExampleResult2 item, JsonGenerator jgen, SerializerProvider provider)\n\t\t\tthrows IOException {\n\t\tjgen.writeStringField(\"identifier2\", item.id());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleResultSerializer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.SerializationContext;\n\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.jackson.ObjectValueSerializer;\n\n/**\n * {@link ObjectValueSerializer} for {@link ExampleResult}.\n *\n * @author Stephane Nicoll\n */\n@JacksonComponent\npublic class ExampleResultSerializer extends ObjectValueSerializer<ExampleResult> {\n\n\t@Override\n\tprotected void serializeObject(ExampleResult item, JsonGenerator jsonWriter, SerializationContext context) {\n\t\tjsonWriter.writeStringProperty(\"identifier\", item.id());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/ExampleWebMvcConfigurer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.core.MethodParameter;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.support.WebDataBinderFactory;\nimport org.springframework.web.context.request.NativeWebRequest;\nimport org.springframework.web.method.support.HandlerMethodArgumentResolver;\nimport org.springframework.web.method.support.ModelAndViewContainer;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n/**\n * Example {@link WebMvcConfigurer} used in {@link WebMvcTest @WebMvcTest} tests.\n *\n * @author Phillip Webb\n */\n@Component\npublic class ExampleWebMvcConfigurer implements WebMvcConfigurer {\n\n\t@Override\n\tpublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {\n\t\targumentResolvers.add(new HandlerMethodArgumentResolver() {\n\n\t\t\t@Override\n\t\t\tpublic boolean supportsParameter(MethodParameter parameter) {\n\t\t\t\treturn parameter.getParameterType().equals(ExampleArgument.class);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,\n\t\t\t\t\tNativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {\n\t\t\t\treturn new ExampleArgument(\"hello\");\n\t\t\t}\n\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/MockMvcSpringBootTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.MockMvcPrint;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} (i.e. full integration test).\n * <p>\n * This uses the regular {@link MockMvc} (Hamcrest integration).\n *\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\n@SpringBootTest\n@AutoConfigureMockMvc(print = MockMvcPrint.SYSTEM_ERR, printOnlyOnFailure = false)\n@AutoConfigureRestTestClient\n@ExtendWith(OutputCaptureExtension.class)\nclass MockMvcSpringBootTestIntegrationTests {\n\n\t@MockitoBean\n\tprivate ExampleMockableService service;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate MockMvc mvc;\n\n\t@Test\n\tvoid shouldFindController1(CapturedOutput output) throws Exception {\n\t\tthis.mvc.perform(get(\"/one\")).andExpect(content().string(\"one\")).andExpect(status().isOk());\n\t\tassertThat(output).contains(\"Request URI = /one\");\n\t}\n\n\t@Test\n\tvoid shouldFindController2() throws Exception {\n\t\tthis.mvc.perform(get(\"/two\")).andExpect(content().string(\"hellotwo\")).andExpect(status().isOk());\n\t}\n\n\t@Test\n\tvoid shouldFindControllerAdvice() throws Exception {\n\t\tthis.mvc.perform(get(\"/error\")).andExpect(content().string(\"recovered\")).andExpect(status().isOk());\n\t}\n\n\t@Test\n\tvoid shouldHaveRealService() {\n\t\tassertThat(this.applicationContext.getBean(ExampleRealService.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid shouldTestWithRestTestClient(@Autowired RestTestClient restTestClient) {\n\t\tResponseSpec spec = restTestClient.get().uri(\"/one\").exchange();\n\t\tassertThat(RestTestClientResponse.from(spec)).hasStatusOk().bodyText().isEqualTo(\"one\");\n\t}\n\n\t@Test\n\tvoid shouldNotFailIfFormattingValueThrowsException(CapturedOutput output) throws Exception {\n\t\tthis.mvc.perform(get(\"/formatting\")).andExpect(content().string(\"formatting\")).andExpect(status().isOk());\n\t\tassertThat(output).contains(\n\t\t\t\t\"Session Attrs = << Exception 'java.lang.IllegalStateException: Formatting failed' occurred while formatting >>\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/MockMvcTesterSpringBootTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.MockMvcPrint;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.test.web.servlet.client.RestTestClient;\nimport org.springframework.test.web.servlet.client.RestTestClient.ResponseSpec;\nimport org.springframework.test.web.servlet.client.assertj.RestTestClientResponse;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureMockMvc @AutoConfigureMockMvc} (i.e. full integration test).\n * <p>\n * This uses {@link MockMvcTester} (AssertJ integration).\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@AutoConfigureMockMvc(print = MockMvcPrint.SYSTEM_ERR, printOnlyOnFailure = false)\n@AutoConfigureRestTestClient\n@ExtendWith(OutputCaptureExtension.class)\nclass MockMvcTesterSpringBootTestIntegrationTests {\n\n\t@MockitoBean\n\tprivate ExampleMockableService service;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldFindController1(CapturedOutput output) {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"one\");\n\t\tassertThat(output).contains(\"Request URI = /one\");\n\t}\n\n\t@Test\n\tvoid shouldFindController2() {\n\t\tassertThat(this.mvc.get().uri(\"/two\")).hasStatusOk().hasBodyTextEqualTo(\"hellotwo\");\n\t}\n\n\t@Test\n\tvoid shouldFindControllerAdvice() {\n\t\tassertThat(this.mvc.get().uri(\"/error\")).hasStatusOk().hasBodyTextEqualTo(\"recovered\");\n\t}\n\n\t@Test\n\tvoid shouldHaveRealService() {\n\t\tassertThat(this.applicationContext.getBean(ExampleRealService.class)).isNotNull();\n\t}\n\n\t@Test\n\tvoid shouldTestWithRestTestClient(@Autowired RestTestClient restTestClient) {\n\t\tResponseSpec spec = restTestClient.get().uri(\"/one\").exchange();\n\t\tassertThat(RestTestClientResponse.from(spec)).hasStatusOk().bodyText().isEqualTo(\"one\");\n\t}\n\n\t@Test\n\tvoid shouldNotFailIfFormattingValueThrowsException(CapturedOutput output) {\n\t\tassertThat(this.mvc.get().uri(\"/formatting\")).hasStatusOk().hasBodyTextEqualTo(\"formatting\");\n\t\tassertThat(output).contains(\n\t\t\t\t\"Session Attrs = << Exception 'java.lang.IllegalStateException: Formatting failed' occurred while formatting >>\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestAllControllersIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.util.function.Consumer;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.validation.ConstraintViolationException;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.error.ErrorAttributes;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.test.web.servlet.assertj.MvcTestResult;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} when no explicit controller is defined.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@WebMvcTest\nclass WebMvcTestAllControllersIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Autowired(required = false)\n\tprivate ErrorAttributes errorAttributes;\n\n\t@Test\n\tvoid shouldFindController1() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).satisfies(hasBody(\"one\"));\n\t}\n\n\t@Test\n\tvoid shouldFindController2() {\n\t\tassertThat(this.mvc.get().uri(\"/two\")).satisfies(hasBody(\"hellotwo\"));\n\t}\n\n\t@Test\n\tvoid shouldFindControllerAdvice() {\n\t\tassertThat(this.mvc.get().uri(\"/error\")).satisfies(hasBody(\"recovered\"));\n\t}\n\n\t@Test\n\tvoid shouldRunValidationSuccess() {\n\t\tassertThat(this.mvc.get().uri(\"/three/OK\")).satisfies(hasBody(\"Hello OK\"));\n\t}\n\n\t@Test\n\tvoid shouldRunValidationFailure() {\n\t\tassertThat(this.mvc.get().uri(\"/three/invalid\")).failure()\n\t\t\t.isInstanceOf(ServletException.class)\n\t\t\t.hasCauseInstanceOf(ConstraintViolationException.class);\n\t}\n\n\t@Test\n\tvoid shouldNotFilterErrorAttributes() {\n\t\tassertThat(this.errorAttributes).isNotNull();\n\n\t}\n\n\tprivate Consumer<MvcTestResult> hasBody(String expected) {\n\t\treturn (result) -> assertThat(result).hasStatusOk().hasBodyTextEqualTo(expected);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestConverterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} to validate converters are discovered.\n *\n * @author Stephane Nicoll\n */\n@WebMvcTest(controllers = ExampleController2.class)\nclass WebMvcTestConverterIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldFindConverter() {\n\t\tString id = UUID.randomUUID().toString();\n\t\tassertThat(this.mvc.get().uri(\"/two/\" + id)).hasStatusOk().hasBodyTextEqualTo(id + \"two\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestCustomDispatcherServletIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.servlet.DispatcherServlet;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for Test {@link DispatcherServlet} customizations.\n *\n * @author Stephane Nicoll\n */\n@WebMvcTest\n@TestPropertySource(properties = { \"spring.mvc.throw-exception-if-no-handler-found=true\",\n\t\t\"spring.mvc.static-path-pattern=/static/**\" })\nclass WebMvcTestCustomDispatcherServletIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid dispatcherServletIsCustomized() {\n\t\tassertThat(this.mvc.get().uri(\"/does-not-exist\")).hasStatus(HttpStatus.BAD_REQUEST)\n\t\t\t.hasBodyTextEqualTo(\"Invalid request: /does-not-exist\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestHtmlUnitWebClientIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.htmlunit.WebClient;\nimport org.htmlunit.html.HtmlPage;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc.HtmlUnit;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with {@link WebClient}.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\n@AutoConfigureMockMvc(htmlUnit = @HtmlUnit(url = \"http://localhost:8181\"))\nclass WebMvcTestHtmlUnitWebClientIntegrationTests {\n\n\t@Autowired\n\tprivate WebClient webClient;\n\n\t@Test\n\tvoid shouldAutoConfigureWebClient() throws Exception {\n\t\tHtmlPage page = this.webClient.getPage(\"/html\");\n\t\tassertThat(page.getBody().getTextContent()).isEqualTo(\"Hello\");\n\t\tassertThat(page.getBaseURI()).isEqualTo(\"http://localhost:8181/html\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestHtmlUnitWebDriverCustomScopeIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.htmlunit.HtmlUnitDriver;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.ConfigurableBeanFactory;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with {@link WebDriver} in a custom scope.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\n@TestMethodOrder(MethodOrderer.MethodName.class)\nclass WebMvcTestHtmlUnitWebDriverCustomScopeIntegrationTests {\n\n\t// gh-7454\n\tprivate static @Nullable WebDriver previousWebDriver;\n\n\t@Autowired\n\tprivate WebDriver webDriver;\n\n\t@Test\n\tvoid shouldAutoConfigureWebClient() {\n\t\tWebMvcTestHtmlUnitWebDriverCustomScopeIntegrationTests.previousWebDriver = this.webDriver;\n\t}\n\n\t@Test\n\tvoid shouldBeTheSameWebClient() {\n\t\tassertThat(previousWebDriver).isNotNull().isSameAs(this.webDriver);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class Config {\n\n\t\t@Bean\n\t\t@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)\n\t\tWebDriverFactory webDriver(MockMvc mockMvc) {\n\t\t\treturn new WebDriverFactory(mockMvc);\n\t\t}\n\n\t}\n\n\tstatic class WebDriverFactory implements FactoryBean<WebDriver> {\n\n\t\tprivate final HtmlUnitDriver driver;\n\n\t\tWebDriverFactory(MockMvc mockMvc) {\n\t\t\tthis.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(mockMvc).build();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean isSingleton() {\n\t\t\treturn true;\n\t\t}\n\n\t\t@Override\n\t\tpublic Class<?> getObjectType() {\n\t\t\treturn WebDriver.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic WebDriver getObject() {\n\t\t\treturn this.driver;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestHtmlUnitWebDriverIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\nimport org.openqa.selenium.By;\nimport org.openqa.selenium.NoSuchSessionException;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.WebElement;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc.HtmlUnit;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with {@link WebDriver}.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\n@TestMethodOrder(MethodOrderer.MethodName.class)\n@AutoConfigureMockMvc(htmlUnit = @HtmlUnit(url = \"http://localhost:8181\"))\nclass WebMvcTestHtmlUnitWebDriverIntegrationTests {\n\n\tprivate static @Nullable WebDriver previousWebDriver;\n\n\t@Autowired\n\tprivate WebDriver webDriver;\n\n\t@Test\n\tvoid shouldAutoConfigureWebClient() {\n\t\tthis.webDriver.get(\"/html\");\n\t\tWebElement element = this.webDriver.findElement(By.tagName(\"body\"));\n\t\tassertThat(element.getText()).isEqualTo(\"Hello\");\n\t\tWebMvcTestHtmlUnitWebDriverIntegrationTests.previousWebDriver = this.webDriver;\n\t}\n\n\t@Test\n\tvoid shouldBeADifferentWebClient() {\n\t\tthis.webDriver.get(\"/html\");\n\t\tWebElement element = this.webDriver.findElement(By.tagName(\"body\"));\n\t\tassertThat(element.getText()).isEqualTo(\"Hello\");\n\t\tassertThat(previousWebDriver).isNotNull().isNotSameAs(this.webDriver);\n\t\tassertThatExceptionOfType(NoSuchSessionException.class).isThrownBy(previousWebDriver::getWindowHandle);\n\t\tassertThat(this.webDriver.getCurrentUrl()).isEqualTo(\"http://localhost:8181/html\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestJacksonComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jackson.JacksonComponent;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} to validate {@link JacksonComponent} beans are\n * discovered.\n *\n * @author Stephane Nicoll\n */\n@WebMvcTest(controllers = ExampleController2.class)\nclass WebMvcTestJacksonComponentIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldFindJacksonComponent() {\n\t\tassertThat(this.mvc.post().uri(\"/two/1234abcd\")).hasStatusOk().bodyJson().isLenientlyEqualTo(\"\"\"\n\t\t\t\t{ \"identifier\": \"1234abcd\" }\n\t\t\t\t\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestJsonComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} to validate\n * {@link org.springframework.boot.jackson2.JsonComponent} beans are discovered.\n *\n * @author Stephane Nicoll\n */\n@WebMvcTest(controllers = ExampleController2.class,\n\t\tproperties = \"spring.http.converters.preferred-json-mapper=jackson2\")\nclass WebMvcTestJsonComponentIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldFindJsonComponent() {\n\t\tassertThat(this.mvc.post().uri(\"/two2/1234abcd\")).hasStatusOk().bodyJson().isLenientlyEqualTo(\"\"\"\n\t\t\t\t{ \"identifier2\": \"1234abcd\" }\n\t\t\t\t\"\"\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestMessageSourceIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.MessageSource;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link WebMvcTest @WebMvcTest} and {@link MessageSource}\n * auto-configuration.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\n@TestPropertySource(properties = \"spring.messages.basename=web-test-messages\")\nclass WebMvcTestMessageSourceIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid messageSourceHasBeenAutoConfigured() {\n\t\tassertThat(this.context.getMessage(\"a\", null, Locale.ENGLISH)).isEqualTo(\"alpha\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestNestedIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} using {@link Nested}.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest(controllers = ExampleController2.class)\nclass WebMvcTestNestedIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldNotFindController1() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatus(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid shouldFindController2() {\n\t\tassertThat(this.mvc.get().uri(\"/two\")).hasStatusOk().hasBodyTextEqualTo(\"hellotwo\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Test\n\t\tvoid shouldNotFindController1() {\n\t\t\tassertThat(WebMvcTestNestedIntegrationTests.this.mvc.get().uri(\"/one\")).hasStatus(HttpStatus.NOT_FOUND);\n\t\t}\n\n\t\t@Test\n\t\tvoid shouldFindController2() {\n\t\t\tassertThat(WebMvcTestNestedIntegrationTests.this.mvc.get().uri(\"/two\")).hasStatusOk()\n\t\t\t\t.hasBodyTextEqualTo(\"hellotwo\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestOneControllerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} when a specific controller is defined.\n *\n * @author Phillip Webb\n */\n@WebMvcTest(controllers = ExampleController2.class)\nclass WebMvcTestOneControllerIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldNotFindController1() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatus(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid shouldFindController2() {\n\t\tassertThat(this.mvc.get().uri(\"/two\")).hasStatusOk().hasBodyTextEqualTo(\"hellotwo\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestPrintAlwaysIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} default print output.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\n@AutoConfigureMockMvc(printOnlyOnFailure = false)\n@ExtendWith(OutputCaptureExtension.class)\nclass WebMvcTestPrintAlwaysIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldPrint(CapturedOutput output) {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"one\");\n\t\tassertThat(output).contains(\"Request URI = /one\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.MethodOrderer;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.TestMethodOrder;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.platform.engine.discovery.DiscoverySelectors;\nimport org.junit.platform.launcher.Launcher;\nimport org.junit.platform.launcher.LauncherDiscoveryRequest;\nimport org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;\nimport org.junit.platform.launcher.core.LauncherFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} default print output.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\n@TestMethodOrder(MethodOrderer.MethodName.class)\nclass WebMvcTestPrintDefaultIntegrationTests {\n\n\t@Test\n\tvoid shouldNotPrint(CapturedOutput output) {\n\t\texecuteTests(ShouldNotPrint.class);\n\t\tassertThat(output).doesNotContain(\"HTTP Method\");\n\t}\n\n\t@Test\n\tvoid shouldPrint(CapturedOutput output) {\n\t\texecuteTests(ShouldPrint.class);\n\t\tassertThat(output).containsOnlyOnce(\"HTTP Method\");\n\t}\n\n\tprivate void executeTests(Class<?> testClass) {\n\t\tLauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()\n\t\t\t.selectors(DiscoverySelectors.selectClass(testClass))\n\t\t\t.build();\n\t\tLauncher launcher = LauncherFactory.create();\n\t\tlauncher.execute(request);\n\t}\n\n\t@WebMvcTest\n\t@AutoConfigureMockMvc\n\tstatic class ShouldNotPrint {\n\n\t\t@Autowired\n\t\tprivate MockMvcTester mvc;\n\n\t\t@Test\n\t\tvoid test() {\n\t\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"one\");\n\t\t}\n\n\t}\n\n\t@WebMvcTest\n\t@AutoConfigureMockMvc\n\tstatic class ShouldPrint {\n\n\t\t@Autowired\n\t\tprivate MockMvcTester mvc;\n\n\t\t@Test\n\t\tvoid test() {\n\t\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"none\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestPrintDefaultOverrideIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} when a specific controller is defined.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\n@TestPropertySource(properties = \"spring.test.mockmvc.print=NONE\")\n@ExtendWith(OutputCaptureExtension.class)\nclass WebMvcTestPrintDefaultOverrideIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldFindController1(CapturedOutput output) {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"one\");\n\t\tassertThat(output).doesNotContain(\"Request URI = /one\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestPrintOverrideIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.MockMvcPrint;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} when a specific print option is defined.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\n@AutoConfigureMockMvc(print = MockMvcPrint.NONE)\n@ExtendWith(OutputCaptureExtension.class)\nclass WebMvcTestPrintOverrideIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldNotPrint(CapturedOutput output) {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasStatusOk().hasBodyTextEqualTo(\"one\");\n\t\tassertThat(output).doesNotContain(\"Request URI = /one\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestServletContextResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} when loading resources via\n * {@link ServletContext}.\n *\n * @author Lorenzo Dee\n */\n@WebMvcTest\nclass WebMvcTestServletContextResourceTests {\n\n\t@Autowired\n\tprivate ServletContext servletContext;\n\n\t@Test\n\tvoid getResourceLocation() throws Exception {\n\t\ttestResource(\"/inwebapp\", \"src/main/webapp\");\n\t\ttestResource(\"/inmetainfresources\", \"/META-INF/resources\");\n\t\ttestResource(\"/inresources\", \"/resources\");\n\t\ttestResource(\"/instatic\", \"/static\");\n\t\ttestResource(\"/inpublic\", \"/public\");\n\t}\n\n\tprivate void testResource(String path, String expectedLocation) throws MalformedURLException {\n\t\tURL resource = this.servletContext.getResource(path);\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.getPath()).contains(expectedLocation);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestServletFilterIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} servlet filter registration.\n *\n * @author Phillip Webb\n */\n@WebMvcTest\nclass WebMvcTestServletFilterIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldApplyFilter() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).hasHeader(\"x-test\", \"abc\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestServletFilterRegistrationDisabledIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with a disabled filter registration.\n *\n * @author Andy Wilkinson\n */\n@WebMvcTest\nclass WebMvcTestServletFilterRegistrationDisabledIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldNotApplyFilter() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).doesNotContainHeader(\"x-test\");\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class DisabledRegistrationConfiguration {\n\n\t\t@Bean\n\t\tFilterRegistrationBean<ExampleFilter> exampleFilterRegistration(ExampleFilter filter) {\n\t\t\tFilterRegistrationBean<ExampleFilter> registration = new FilterRegistrationBean<>(filter);\n\t\t\tregistration.setEnabled(false);\n\t\t\treturn registration;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestServletFilterRegistrationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.annotation.WebInitParam;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.web.servlet.FilterRegistration;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\nimport org.springframework.web.filter.OncePerRequestFilter;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FilterRegistration} and {@link FilterRegistrationBean} with\n * {@link WebMvcTest @WebMvcTest}.\n *\n * @author Dmytro Nosan\n */\n@WebMvcTest\nclass WebMvcTestServletFilterRegistrationIntegrationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid annotation() {\n\t\tassertThat(this.mvc.get().uri(\"/annotation\")).headers()\n\t\t\t.hasValue(\"name\", \"annotation\")\n\t\t\t.hasValue(\"param1\", \"value1\")\n\t\t\t.hasValue(\"param2\", \"value2\")\n\t\t\t.doesNotContainHeader(\"param3\")\n\t\t\t.doesNotContainHeader(\"param4\");\n\t}\n\n\t@Test\n\tvoid registration() {\n\t\tassertThat(this.mvc.get().uri(\"/registration\")).headers()\n\t\t\t.hasValue(\"name\", \"registration\")\n\t\t\t.hasValue(\"param3\", \"value3\")\n\t\t\t.hasValue(\"param4\", \"value4\")\n\t\t\t.doesNotContainHeader(\"param1\")\n\t\t\t.doesNotContainHeader(\"param2\");\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class FilterRegistrationConfiguration {\n\n\t\t@Bean\n\t\t@FilterRegistration(name = \"annotation\", urlPatterns = \"/annotation\",\n\t\t\t\tinitParameters = { @WebInitParam(name = \"param1\", value = \"value1\"),\n\t\t\t\t\t\t@WebInitParam(name = \"param2\", value = \"value2\") })\n\t\t@Order(0)\n\t\tTestFilter testFilterAnnotationBean() {\n\t\t\treturn new TestFilter();\n\t\t}\n\n\t\t@Bean\n\t\tFilterRegistrationBean<TestFilter> testFilterRegistrationBean() {\n\t\t\tFilterRegistrationBean<TestFilter> registration = new FilterRegistrationBean<>(new TestFilter());\n\t\t\tregistration.setName(\"registration\");\n\t\t\tregistration.addUrlPatterns(\"/registration\");\n\t\t\tregistration.setInitParameters(Map.of(\"param3\", \"value3\", \"param4\", \"value4\"));\n\t\t\tregistration.setOrder(0);\n\t\t\treturn registration;\n\t\t}\n\n\t}\n\n\tprivate static final class TestFilter extends OncePerRequestFilter {\n\n\t\t@Override\n\t\tprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n\t\t\t\tFilterChain filterChain) throws ServletException, IOException {\n\t\t\tresponse.addHeader(\"name\", getFilterName());\n\t\t\tFilterConfig config = getFilterConfig();\n\t\t\tif (config != null) {\n\t\t\t\tCollections.list(config.getInitParameterNames())\n\t\t\t\t\t.forEach((name) -> response.addHeader(name, config.getInitParameter(name)));\n\t\t\t}\n\t\t\tfilterChain.doFilter(request, response);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestWithAutoConfigureMockMvcIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.htmlunit.WebClient;\nimport org.junit.jupiter.api.Test;\nimport org.openqa.selenium.WebDriver;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc.HtmlUnit;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} with\n * {@link AutoConfigureMockMvc @AutoConfigureMockMvc}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n */\n@WebMvcTest\n@AutoConfigureMockMvc(addFilters = false, htmlUnit = @HtmlUnit(webClient = false, webDriver = false))\nclass WebMvcTestWithAutoConfigureMockMvcIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid shouldNotAddFilters() {\n\t\tassertThat(this.mvc.get().uri(\"/one\")).doesNotContainHeader(\"x-test\");\n\t}\n\n\t@Test\n\tvoid shouldNotHaveWebDriver() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.context.getBean(WebDriver.class));\n\t}\n\n\t@Test\n\tvoid shouldNotHaveWebClient() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.context.getBean(WebClient.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/WebMvcTestWithWebAppConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport jakarta.servlet.ServletContext;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.context.web.WebAppConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebMvcTest @WebMvcTest} when loading resources through the\n * {@link ServletContext} with {@link WebAppConfiguration @WebAppConfiguration}.\n *\n * @author Lorenzo Dee\n */\n@WebMvcTest\n@WebAppConfiguration(\"src/test/webapp\")\nclass WebMvcTestWithWebAppConfigurationTests {\n\n\t@Autowired\n\tprivate ServletContext servletContext;\n\n\t@Test\n\tvoid whenBasePathIsCustomizedResourcesCanBeLoadedFromThatLocation() throws Exception {\n\t\ttestResource(\"/inwebapp\", \"src/test/webapp\");\n\t\ttestResource(\"/inmetainfresources\", \"/META-INF/resources\");\n\t\ttestResource(\"/inresources\", \"/resources\");\n\t\ttestResource(\"/instatic\", \"/static\");\n\t\ttestResource(\"/inpublic\", \"/public\");\n\t}\n\n\tprivate void testResource(String path, String expectedLocation) throws MalformedURLException {\n\t\tURL resource = this.servletContext.getResource(path);\n\t\tassertThat(resource).isNotNull();\n\t\tassertThat(resource.getPath()).contains(expectedLocation);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/mockmvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.webmvc.test.autoconfigure.mockmvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/resources/META-INF/resources/inmetainfresources",
    "content": ""
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/resources/public/inpublic",
    "content": ""
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/resources/resources/inresources",
    "content": ""
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/resources/static/instatic",
    "content": ""
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/resources/web-test-messages.properties",
    "content": "a=alpha\n"
  },
  {
    "path": "module/spring-boot-webmvc-test/src/test/webapp/inwebapp",
    "content": ""
  },
  {
    "path": "module/spring-boot-webservices/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Web Services\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(project(\":module:spring-boot-http-client\"))\n\tapi(\"org.springframework:spring-oxm\")\n\tapi(\"org.springframework.ws:spring-ws-core\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(\"org.eclipse.jetty:jetty-client\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"io.projectreactor.netty:reactor-netty-http\")\n\ttestRuntimeOnly(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/autoconfigure/OnWsdlLocationsCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage;\nimport org.springframework.boot.autoconfigure.condition.OnPropertyListCondition;\n\n/**\n * Condition to determine if {@code spring.webservices.wsdl-locations} is specified.\n *\n * @author Eneias Silva\n * @author Stephane Nicoll\n */\nclass OnWsdlLocationsCondition extends OnPropertyListCondition {\n\n\tOnWsdlLocationsCondition() {\n\t\tsuper(\"spring.webservices.wsdl-locations\", () -> ConditionMessage.forCondition(\"WSDL locations\"));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/autoconfigure/WebServicesAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.context.properties.bind.Bindable;\nimport org.springframework.boot.context.properties.bind.Binder;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Role;\nimport org.springframework.core.io.Resource;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\nimport org.springframework.ws.config.annotation.EnableWs;\nimport org.springframework.ws.config.annotation.WsConfigurationSupport;\nimport org.springframework.ws.transport.http.MessageDispatcherServlet;\nimport org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition;\nimport org.springframework.xml.xsd.SimpleXsdSchema;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Spring Web Services.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass(MessageDispatcherServlet.class)\n@ConditionalOnMissingBean(WsConfigurationSupport.class)\n@EnableConfigurationProperties(WebServicesProperties.class)\npublic final class WebServicesAutoConfiguration {\n\n\t@Bean\n\tServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext,\n\t\t\tWebServicesProperties properties) {\n\t\tMessageDispatcherServlet servlet = new MessageDispatcherServlet();\n\t\tservlet.setApplicationContext(applicationContext);\n\t\tString path = properties.getPath();\n\t\tString urlMapping = path + (path.endsWith(\"/\") ? \"*\" : \"/*\");\n\t\tServletRegistrationBean<MessageDispatcherServlet> registration = new ServletRegistrationBean<>(servlet,\n\t\t\t\turlMapping);\n\t\tWebServicesProperties.Servlet servletProperties = properties.getServlet();\n\t\tregistration.setLoadOnStartup(servletProperties.getLoadOnStartup());\n\t\tservletProperties.getInit().forEach(registration::addInitParameter);\n\t\treturn registration;\n\t}\n\n\t@Bean\n\t@Role(BeanDefinition.ROLE_INFRASTRUCTURE)\n\t@Conditional(OnWsdlLocationsCondition.class)\n\tstatic WsdlDefinitionBeanFactoryPostProcessor wsdlDefinitionBeanFactoryPostProcessor() {\n\t\treturn new WsdlDefinitionBeanFactoryPostProcessor();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWs\n\tprotected static class WsConfiguration {\n\n\t}\n\n\tstatic class WsdlDefinitionBeanFactoryPostProcessor\n\t\t\timplements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {\n\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate ApplicationContext applicationContext;\n\n\t\t@Override\n\t\tpublic void setApplicationContext(ApplicationContext applicationContext) {\n\t\t\tthis.applicationContext = applicationContext;\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {\n\t\t\tBinder binder = Binder.get(this.applicationContext.getEnvironment());\n\t\t\tList<String> wsdlLocations = binder.bind(\"spring.webservices.wsdl-locations\", Bindable.listOf(String.class))\n\t\t\t\t.orElse(Collections.emptyList());\n\t\t\tfor (String wsdlLocation : wsdlLocations) {\n\t\t\t\tregisterBeans(wsdlLocation, \"*.wsdl\", SimpleWsdl11Definition.class, SimpleWsdl11Definition::new,\n\t\t\t\t\t\tregistry);\n\t\t\t\tregisterBeans(wsdlLocation, \"*.xsd\", SimpleXsdSchema.class, SimpleXsdSchema::new, registry);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {\n\t\t}\n\n\t\tprivate <T> void registerBeans(String location, String pattern, Class<T> type,\n\t\t\t\tFunction<Resource, T> beanSupplier, BeanDefinitionRegistry registry) {\n\t\t\tfor (Resource resource : getResources(location, pattern)) {\n\t\t\t\tBeanDefinition beanDefinition = BeanDefinitionBuilder\n\t\t\t\t\t.rootBeanDefinition(type, () -> beanSupplier.apply(resource))\n\t\t\t\t\t.getBeanDefinition();\n\t\t\t\tString filename = resource.getFilename();\n\t\t\t\tAssert.state(filename != null, \"'filename' must not be null\");\n\t\t\t\tregistry.registerBeanDefinition(StringUtils.stripFilenameExtension(filename), beanDefinition);\n\t\t\t}\n\t\t}\n\n\t\tprivate Resource[] getResources(String location, String pattern) {\n\t\t\ttry {\n\t\t\t\treturn this.applicationContext.getResources(ensureTrailingSlash(location) + pattern);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\treturn new Resource[0];\n\t\t\t}\n\t\t}\n\n\t\tprivate String ensureTrailingSlash(String path) {\n\t\t\treturn path.endsWith(\"/\") ? path : path + \"/\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/autoconfigure/WebServicesProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigurationProperties @ConfigurationProperties} for Spring Web Services.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @since 4.0.0\n */\n@ConfigurationProperties(\"spring.webservices\")\npublic class WebServicesProperties {\n\n\t/**\n\t * Path that serves as the base URI for the services.\n\t */\n\tprivate String path = \"/services\";\n\n\tprivate final Servlet servlet = new Servlet();\n\n\tpublic String getPath() {\n\t\treturn this.path;\n\t}\n\n\tpublic void setPath(String path) {\n\t\tAssert.notNull(path, \"'path' must not be null\");\n\t\tAssert.isTrue(path.length() > 1, \"'path' must have length greater than 1\");\n\t\tAssert.isTrue(path.startsWith(\"/\"), \"'path' must start with '/'\");\n\t\tthis.path = path;\n\t}\n\n\tpublic Servlet getServlet() {\n\t\treturn this.servlet;\n\t}\n\n\tpublic static class Servlet {\n\n\t\t/**\n\t\t * Servlet init parameters to pass to Spring Web Services.\n\t\t */\n\t\tprivate Map<String, String> init = new HashMap<>();\n\n\t\t/**\n\t\t * Load on startup priority of the Spring Web Services servlet.\n\t\t */\n\t\tprivate int loadOnStartup = -1;\n\n\t\tpublic Map<String, String> getInit() {\n\t\t\treturn this.init;\n\t\t}\n\n\t\tpublic void setInit(Map<String, String> init) {\n\t\t\tthis.init = init;\n\t\t}\n\n\t\tpublic int getLoadOnStartup() {\n\t\t\treturn this.loadOnStartup;\n\t\t}\n\n\t\tpublic void setLoadOnStartup(int loadOnStartup) {\n\t\t\tthis.loadOnStartup = loadOnStartup;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/autoconfigure/client/WebServiceTemplateAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure.client;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.webservices.client.WebServiceMessageSenderFactory;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.boot.webservices.client.WebServiceTemplateCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.oxm.Marshaller;\nimport org.springframework.oxm.Unmarshaller;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for {@link WebServiceTemplate}.\n *\n * @author Dmytro Nosan\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass({ WebServiceTemplate.class, Unmarshaller.class, Marshaller.class })\npublic final class WebServiceTemplateAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tWebServiceMessageSenderFactory webServiceHttpMessageSenderFactory(\n\t\t\tObjectProvider<ClientHttpRequestFactoryBuilder<?>> clientHttpRequestFactoryBuilder,\n\t\t\tObjectProvider<HttpClientSettings> httpClientSettings) {\n\t\treturn WebServiceMessageSenderFactory.http(\n\t\t\t\tclientHttpRequestFactoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect),\n\t\t\t\thttpClientSettings.getIfAvailable());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tWebServiceTemplateBuilder webServiceTemplateBuilder(\n\t\t\tObjectProvider<WebServiceMessageSenderFactory> httpWebServiceMessageSenderBuilder,\n\t\t\tObjectProvider<WebServiceTemplateCustomizer> webServiceTemplateCustomizers) {\n\t\tWebServiceTemplateBuilder templateBuilder = new WebServiceTemplateBuilder();\n\t\tWebServiceMessageSenderFactory httpMessageSenderFactory = httpWebServiceMessageSenderBuilder.getIfAvailable();\n\t\tif (httpMessageSenderFactory != null) {\n\t\t\ttemplateBuilder = templateBuilder.httpMessageSenderFactory(httpMessageSenderFactory);\n\t\t}\n\t\tList<WebServiceTemplateCustomizer> customizers = webServiceTemplateCustomizers.orderedStream().toList();\n\t\tif (!customizers.isEmpty()) {\n\t\t\ttemplateBuilder = templateBuilder.customizers(customizers);\n\t\t}\n\t\treturn templateBuilder;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/autoconfigure/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Web Services Clients.\n */\n@NullMarked\npackage org.springframework.boot.webservices.autoconfigure.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Spring Web Services.\n */\n@NullMarked\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/client/WebServiceMessageSenderFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.client;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.util.Assert;\nimport org.springframework.ws.transport.WebServiceMessageSender;\nimport org.springframework.ws.transport.http.ClientHttpRequestMessageSender;\n\n/**\n * Factory that can be used to create a {@link WebServiceMessageSender}.\n *\n * @author Phillip Webb\n * @since 3.4.0\n */\n@FunctionalInterface\npublic interface WebServiceMessageSenderFactory {\n\n\t/**\n\t * Return a new {@link WebServiceMessageSender} instance.\n\t * @return the web service message sender\n\t */\n\tWebServiceMessageSender getWebServiceMessageSender();\n\n\t/**\n\t * Returns a factory that will create a {@link ClientHttpRequestMessageSender} backed\n\t * by a detected {@link ClientHttpRequestFactory}.\n\t * @return a new {@link WebServiceMessageSenderFactory}\n\t */\n\tstatic WebServiceMessageSenderFactory http() {\n\t\treturn http(ClientHttpRequestFactoryBuilder.detect(), null);\n\t}\n\n\t/**\n\t * Returns a factory that will create a {@link ClientHttpRequestMessageSender} backed\n\t * by a detected {@link ClientHttpRequestFactory}.\n\t * @param clientSettings the setting to apply\n\t * @return a new {@link WebServiceMessageSenderFactory}\n\t */\n\tstatic WebServiceMessageSenderFactory http(HttpClientSettings clientSettings) {\n\t\treturn http(ClientHttpRequestFactoryBuilder.detect(), clientSettings);\n\t}\n\n\t/**\n\t * Returns a factory that will create a {@link ClientHttpRequestMessageSender} backed\n\t * by a {@link ClientHttpRequestFactory} created from the given\n\t * {@link ClientHttpRequestFactoryBuilder}.\n\t * @param requestFactoryBuilder the request factory builder to use\n\t * @param clientSettings the settings to apply\n\t * @return a new {@link WebServiceMessageSenderFactory}\n\t */\n\tstatic WebServiceMessageSenderFactory http(ClientHttpRequestFactoryBuilder<?> requestFactoryBuilder,\n\t\t\t@Nullable HttpClientSettings clientSettings) {\n\t\tAssert.notNull(requestFactoryBuilder, \"'requestFactoryBuilder' must not be null\");\n\t\treturn () -> new ClientHttpRequestMessageSender(requestFactoryBuilder.build(clientSettings));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilder.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.client;\n\nimport java.net.URI;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport javax.xml.transform.TransformerFactory;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.boot.context.properties.PropertyMapper;\nimport org.springframework.oxm.Marshaller;\nimport org.springframework.oxm.Unmarshaller;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.ws.WebServiceMessageFactory;\nimport org.springframework.ws.client.core.FaultMessageResolver;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.client.support.destination.DestinationProvider;\nimport org.springframework.ws.client.support.interceptor.ClientInterceptor;\nimport org.springframework.ws.transport.WebServiceMessageSender;\n\n/**\n * Builder that can be used to configure and create a {@link WebServiceTemplate}. Provides\n * convenience methods to register {@link #messageSenders(WebServiceMessageSender...)\n * message senders}, {@link #interceptors(ClientInterceptor...) client interceptors} and\n * {@link #customizers(WebServiceTemplateCustomizer...) customizers}.\n * <p>\n * By default the built {@link WebServiceTemplate} uses the most suitable HTTP-based\n * {@link WebServiceMessageSender}, call {@link #detectHttpMessageSender(boolean)\n * detectHttpMessageSender(false)} if you prefer to keep the default. In a typical\n * auto-configured Spring Boot application this builder is available as a bean and can be\n * injected whenever a {@link WebServiceTemplate} is needed.\n *\n * @author Dmytro Nosan\n * @author Stephane Nicoll\n * @since 2.1.0\n */\npublic class WebServiceTemplateBuilder {\n\n\tprivate final @Nullable WebServiceMessageSenderFactory httpMessageSenderFactory;\n\n\tprivate final boolean detectHttpMessageSender;\n\n\tprivate final @Nullable Set<ClientInterceptor> interceptors;\n\n\tprivate final @Nullable Set<WebServiceTemplateCustomizer> internalCustomizers;\n\n\tprivate final Set<WebServiceTemplateCustomizer> customizers;\n\n\tprivate final WebServiceMessageSenders messageSenders;\n\n\tprivate final @Nullable Marshaller marshaller;\n\n\tprivate final @Nullable Unmarshaller unmarshaller;\n\n\tprivate final @Nullable DestinationProvider destinationProvider;\n\n\tprivate final @Nullable Class<? extends TransformerFactory> transformerFactoryClass;\n\n\tprivate final @Nullable WebServiceMessageFactory messageFactory;\n\n\tpublic WebServiceTemplateBuilder(WebServiceTemplateCustomizer... customizers) {\n\t\tthis.httpMessageSenderFactory = null;\n\t\tthis.detectHttpMessageSender = true;\n\t\tthis.interceptors = null;\n\t\tthis.internalCustomizers = null;\n\t\tthis.customizers = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(customizers)));\n\t\tthis.messageSenders = new WebServiceMessageSenders();\n\t\tthis.marshaller = null;\n\t\tthis.unmarshaller = null;\n\t\tthis.destinationProvider = null;\n\t\tthis.transformerFactoryClass = null;\n\t\tthis.messageFactory = null;\n\t}\n\n\tprivate WebServiceTemplateBuilder(@Nullable WebServiceMessageSenderFactory messageSenderFactory,\n\t\t\tboolean detectHttpMessageSender, @Nullable Set<ClientInterceptor> interceptors,\n\t\t\t@Nullable Set<WebServiceTemplateCustomizer> internalCustomizers,\n\t\t\tSet<WebServiceTemplateCustomizer> customizers, WebServiceMessageSenders messageSenders,\n\t\t\t@Nullable Marshaller marshaller, @Nullable Unmarshaller unmarshaller,\n\t\t\t@Nullable DestinationProvider destinationProvider,\n\t\t\t@Nullable Class<? extends TransformerFactory> transformerFactoryClass,\n\t\t\t@Nullable WebServiceMessageFactory messageFactory) {\n\t\tthis.httpMessageSenderFactory = messageSenderFactory;\n\t\tthis.detectHttpMessageSender = detectHttpMessageSender;\n\t\tthis.interceptors = interceptors;\n\t\tthis.internalCustomizers = internalCustomizers;\n\t\tthis.customizers = customizers;\n\t\tthis.messageSenders = messageSenders;\n\t\tthis.marshaller = marshaller;\n\t\tthis.unmarshaller = unmarshaller;\n\t\tthis.destinationProvider = destinationProvider;\n\t\tthis.transformerFactoryClass = transformerFactoryClass;\n\t\tthis.messageFactory = messageFactory;\n\t}\n\n\t/**\n\t * Set the {@link WebServiceMessageSenderFactory} that should be used to send HTTP\n\t * messages.\n\t * @param messageSenderFactory the {@link WebServiceMessageSenderFactory} to use\n\t * @return a new builder instance\n\t * @since 3.4.0\n\t */\n\tpublic WebServiceTemplateBuilder httpMessageSenderFactory(WebServiceMessageSenderFactory messageSenderFactory) {\n\t\tAssert.notNull(messageSenderFactory, \"'messageSenderFactory' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(messageSenderFactory, this.detectHttpMessageSender, this.interceptors,\n\t\t\t\tthis.internalCustomizers, this.customizers, this.messageSenders, this.marshaller, this.unmarshaller,\n\t\t\t\tthis.destinationProvider, this.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Set if a suitable HTTP-based {@link WebServiceMessageSender} should be detected\n\t * based on the classpath when one has not been specified. Default is {@code true}.\n\t * @param detectHttpMessageSender if an HTTP-based {@link WebServiceMessageSender}\n\t * should be detected\n\t * @return a new builder instance\n\t */\n\tpublic WebServiceTemplateBuilder detectHttpMessageSender(boolean detectHttpMessageSender) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, detectHttpMessageSender, this.interceptors,\n\t\t\t\tthis.internalCustomizers, this.customizers, this.messageSenders, this.marshaller, this.unmarshaller,\n\t\t\t\tthis.destinationProvider, this.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be\n\t * used with the {@link WebServiceTemplate}. Setting this value will replace any\n\t * previously defined message senders, including the HTTP-based message sender, if\n\t * any. Consider using {@link #additionalMessageSenders(WebServiceMessageSender...)}\n\t * to keep it with user-defined message senders.\n\t * @param messageSenders the message senders to set\n\t * @return a new builder instance.\n\t * @see #additionalMessageSenders(WebServiceMessageSender...)\n\t * @see #detectHttpMessageSender(boolean)\n\t */\n\tpublic WebServiceTemplateBuilder messageSenders(WebServiceMessageSender... messageSenders) {\n\t\tAssert.notNull(messageSenders, \"'messageSenders' must not be null\");\n\t\treturn messageSenders(Arrays.asList(messageSenders));\n\t}\n\n\t/**\n\t * Sets the {@link WebServiceMessageSender WebServiceMessageSenders} that should be\n\t * used with the {@link WebServiceTemplate}. Setting this value will replace any\n\t * previously defined message senders, including the HTTP-based message sender, if\n\t * any. Consider using {@link #additionalMessageSenders(Collection)} to keep it with\n\t * user-defined message senders.\n\t * @param messageSenders the message senders to set\n\t * @return a new builder instance.\n\t * @see #additionalMessageSenders(Collection)\n\t * @see #detectHttpMessageSender(boolean)\n\t */\n\tpublic WebServiceTemplateBuilder messageSenders(Collection<? extends WebServiceMessageSender> messageSenders) {\n\t\tAssert.notNull(messageSenders, \"'messageSenders' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders.set(messageSenders),\n\t\t\t\tthis.marshaller, this.unmarshaller, this.destinationProvider, this.transformerFactoryClass,\n\t\t\t\tthis.messageFactory);\n\t}\n\n\t/**\n\t * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should\n\t * be used with the {@link WebServiceTemplate}.\n\t * @param messageSenders the message senders to add\n\t * @return a new builder instance.\n\t * @see #messageSenders(WebServiceMessageSender...)\n\t */\n\tpublic WebServiceTemplateBuilder additionalMessageSenders(WebServiceMessageSender... messageSenders) {\n\t\tAssert.notNull(messageSenders, \"'messageSenders' must not be null\");\n\t\treturn additionalMessageSenders(Arrays.asList(messageSenders));\n\t}\n\n\t/**\n\t * Add additional {@link WebServiceMessageSender WebServiceMessageSenders} that should\n\t * be used with the {@link WebServiceTemplate}.\n\t * @param messageSenders the message senders to add\n\t * @return a new builder instance.\n\t * @see #messageSenders(Collection)\n\t */\n\tpublic WebServiceTemplateBuilder additionalMessageSenders(\n\t\t\tCollection<? extends WebServiceMessageSender> messageSenders) {\n\t\tAssert.notNull(messageSenders, \"'messageSenders' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders.add(messageSenders),\n\t\t\t\tthis.marshaller, this.unmarshaller, this.destinationProvider, this.transformerFactoryClass,\n\t\t\t\tthis.messageFactory);\n\t}\n\n\t/**\n\t * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the\n\t * {@link WebServiceTemplate}. Setting this value will replace any previously defined\n\t * interceptors.\n\t * @param interceptors the interceptors to set\n\t * @return a new builder instance\n\t * @see #additionalInterceptors(ClientInterceptor...)\n\t */\n\tpublic WebServiceTemplateBuilder interceptors(ClientInterceptor... interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn interceptors(Arrays.asList(interceptors));\n\t}\n\n\t/**\n\t * Set the {@link ClientInterceptor ClientInterceptors} that should be used with the\n\t * {@link WebServiceTemplate}. Setting this value will replace any previously defined\n\t * interceptors.\n\t * @param interceptors the interceptors to set\n\t * @return a new builder instance\n\t * @see #additionalInterceptors(Collection)\n\t */\n\tpublic WebServiceTemplateBuilder interceptors(Collection<? extends ClientInterceptor> interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tappend(Collections.<ClientInterceptor>emptySet(), interceptors), this.internalCustomizers,\n\t\t\t\tthis.customizers, this.messageSenders, this.marshaller, this.unmarshaller, this.destinationProvider,\n\t\t\t\tthis.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Add additional {@link ClientInterceptor ClientInterceptors} that should be used\n\t * with the {@link WebServiceTemplate}.\n\t * @param interceptors the interceptors to add\n\t * @return a new builder instance\n\t * @see #interceptors(ClientInterceptor...)\n\t */\n\tpublic WebServiceTemplateBuilder additionalInterceptors(ClientInterceptor... interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn additionalInterceptors(Arrays.asList(interceptors));\n\t}\n\n\t/**\n\t * Add additional {@link ClientInterceptor ClientInterceptors} that should be used\n\t * with the {@link WebServiceTemplate}.\n\t * @param interceptors the interceptors to add\n\t * @return a new builder instance\n\t * @see #interceptors(Collection)\n\t */\n\tpublic WebServiceTemplateBuilder additionalInterceptors(Collection<? extends ClientInterceptor> interceptors) {\n\t\tAssert.notNull(interceptors, \"'interceptors' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tappend(this.interceptors, interceptors), this.internalCustomizers, this.customizers,\n\t\t\t\tthis.messageSenders, this.marshaller, this.unmarshaller, this.destinationProvider,\n\t\t\t\tthis.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should\n\t * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order\n\t * that they were added after builder configuration has been applied. Setting this\n\t * value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(WebServiceTemplateCustomizer...)\n\t */\n\tpublic WebServiceTemplateBuilder customizers(WebServiceTemplateCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn customizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Set {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers} that should\n\t * be applied to the {@link WebServiceTemplate}. Customizers are applied in the order\n\t * that they were added after builder configuration has been applied. Setting this\n\t * value will replace any previously configured customizers.\n\t * @param customizers the customizers to set\n\t * @return a new builder instance\n\t * @see #additionalCustomizers(Collection)\n\t */\n\tpublic WebServiceTemplateBuilder customizers(Collection<? extends WebServiceTemplateCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers,\n\t\t\t\tappend(Collections.<WebServiceTemplateCustomizer>emptySet(), customizers), this.messageSenders,\n\t\t\t\tthis.marshaller, this.unmarshaller, this.destinationProvider, this.transformerFactoryClass,\n\t\t\t\tthis.messageFactory);\n\t}\n\n\t/**\n\t * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers}\n\t * that should be applied to the {@link WebServiceTemplate}. Customizers are applied\n\t * in the order that they were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(WebServiceTemplateCustomizer...)\n\t */\n\tpublic WebServiceTemplateBuilder additionalCustomizers(WebServiceTemplateCustomizer... customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn additionalCustomizers(Arrays.asList(customizers));\n\t}\n\n\t/**\n\t * Add additional {@link WebServiceTemplateCustomizer WebServiceTemplateCustomizers}\n\t * that should be applied to the {@link WebServiceTemplate}. Customizers are applied\n\t * in the order that they were added after builder configuration has been applied.\n\t * @param customizers the customizers to add\n\t * @return a new builder instance\n\t * @see #customizers(Collection)\n\t */\n\tpublic WebServiceTemplateBuilder additionalCustomizers(\n\t\t\tCollection<? extends WebServiceTemplateCustomizer> customizers) {\n\t\tAssert.notNull(customizers, \"'customizers' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, append(this.customizers, customizers), this.messageSenders,\n\t\t\t\tthis.marshaller, this.unmarshaller, this.destinationProvider, this.transformerFactoryClass,\n\t\t\t\tthis.messageFactory);\n\t}\n\n\t/**\n\t * Indicates whether the connection should be checked for fault indicators\n\t * ({@code true}), or whether we should rely on the message only ({@code false}).\n\t * @param checkConnectionForFault whether to check for fault indicators\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setCheckConnectionForFault(boolean)\n\t */\n\tpublic WebServiceTemplateBuilder setCheckConnectionForFault(boolean checkConnectionForFault) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors,\n\t\t\t\tappend(this.internalCustomizers, new CheckConnectionFaultCustomizer(checkConnectionForFault)),\n\t\t\t\tthis.customizers, this.messageSenders, this.marshaller, this.unmarshaller, this.destinationProvider,\n\t\t\t\tthis.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Indicates whether the connection should be checked for error indicators\n\t * ({@code true}), or whether these should be ignored ({@code false}).\n\t * @param checkConnectionForError whether to check for error indicators\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setCheckConnectionForError(boolean)\n\t */\n\tpublic WebServiceTemplateBuilder setCheckConnectionForError(boolean checkConnectionForError) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors,\n\t\t\t\tappend(this.internalCustomizers, new CheckConnectionForErrorCustomizer(checkConnectionForError)),\n\t\t\t\tthis.customizers, this.messageSenders, this.marshaller, this.unmarshaller, this.destinationProvider,\n\t\t\t\tthis.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Sets the {@link WebServiceMessageFactory} to use for creating messages.\n\t * @param messageFactory the message factory to use for creating messages\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setMessageFactory(WebServiceMessageFactory)\n\t */\n\tpublic WebServiceTemplateBuilder setWebServiceMessageFactory(WebServiceMessageFactory messageFactory) {\n\t\tAssert.notNull(messageFactory, \"'messageFactory' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, this.marshaller,\n\t\t\t\tthis.unmarshaller, this.destinationProvider, this.transformerFactoryClass, messageFactory);\n\t}\n\n\t/**\n\t * Set the {@link Unmarshaller} to use to deserialize messages.\n\t * @param unmarshaller the message unmarshaller\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setUnmarshaller(Unmarshaller)\n\t */\n\tpublic WebServiceTemplateBuilder setUnmarshaller(Unmarshaller unmarshaller) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, this.marshaller,\n\t\t\t\tunmarshaller, this.destinationProvider, this.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Set the {@link Marshaller} to use to serialize messages.\n\t * @param marshaller the message marshaller\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setMarshaller(Marshaller)\n\t */\n\tpublic WebServiceTemplateBuilder setMarshaller(Marshaller marshaller) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, marshaller,\n\t\t\t\tthis.unmarshaller, this.destinationProvider, this.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Set the {@link FaultMessageResolver} to use.\n\t * @param faultMessageResolver the fault message resolver to use\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver)\n\t */\n\tpublic WebServiceTemplateBuilder setFaultMessageResolver(FaultMessageResolver faultMessageResolver) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors,\n\t\t\t\tappend(this.internalCustomizers, new FaultMessageResolverCustomizer(faultMessageResolver)),\n\t\t\t\tthis.customizers, this.messageSenders, this.marshaller, this.unmarshaller, this.destinationProvider,\n\t\t\t\tthis.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Set the {@link TransformerFactory} implementation to use.\n\t * @param transformerFactoryClass the transformer factory implementation to use\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setTransformerFactoryClass(Class)\n\t */\n\tpublic WebServiceTemplateBuilder setTransformerFactoryClass(\n\t\t\tClass<? extends TransformerFactory> transformerFactoryClass) {\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, this.marshaller,\n\t\t\t\tthis.unmarshaller, this.destinationProvider, transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Set the default URI to be used on operations that do not have a URI parameter.\n\t * Typically, either this property is set, or\n\t * {@link #setDestinationProvider(DestinationProvider)}, but not both.\n\t * @param defaultUri the destination provider URI to be used on operations that do not\n\t * have a URI parameter.\n\t * @return a new builder instance.\n\t * @see #setDestinationProvider(DestinationProvider)\n\t */\n\tpublic WebServiceTemplateBuilder setDefaultUri(String defaultUri) {\n\t\tAssert.hasText(defaultUri, \"'defaultUri' must not be empty\");\n\t\treturn setDestinationProvider(() -> URI.create(defaultUri));\n\t}\n\n\t/**\n\t * Set the {@link DestinationProvider} to use. Typically, either this property is set,\n\t * or {@link #setDefaultUri(String)}, but not both.\n\t * @param destinationProvider the destination provider to be used on operations that\n\t * do not have a URI parameter.\n\t * @return a new builder instance.\n\t * @see WebServiceTemplate#setDestinationProvider(DestinationProvider)\n\t */\n\tpublic WebServiceTemplateBuilder setDestinationProvider(DestinationProvider destinationProvider) {\n\t\tAssert.notNull(destinationProvider, \"'destinationProvider' must not be null\");\n\t\treturn new WebServiceTemplateBuilder(this.httpMessageSenderFactory, this.detectHttpMessageSender,\n\t\t\t\tthis.interceptors, this.internalCustomizers, this.customizers, this.messageSenders, this.marshaller,\n\t\t\t\tthis.unmarshaller, destinationProvider, this.transformerFactoryClass, this.messageFactory);\n\t}\n\n\t/**\n\t * Build a new {@link WebServiceTemplate} instance and configure it using this\n\t * builder.\n\t * @return a configured {@link WebServiceTemplate} instance.\n\t * @see #build(Class)\n\t * @see #configure(WebServiceTemplate)\n\t */\n\tpublic WebServiceTemplate build() {\n\t\treturn configure(\n\t\t\t\t(this.messageFactory != null) ? new WebServiceTemplate(this.messageFactory) : new WebServiceTemplate());\n\t}\n\n\t/**\n\t * Build a new {@link WebServiceTemplate} instance of the specified type and configure\n\t * it using this builder.\n\t * @param <T> the type of web service template\n\t * @param webServiceTemplateClass the template type to create\n\t * @return a configured {@link WebServiceTemplate} instance.\n\t * @see WebServiceTemplateBuilder#build()\n\t * @see #configure(WebServiceTemplate)\n\t */\n\tpublic <T extends WebServiceTemplate> T build(Class<T> webServiceTemplateClass) {\n\t\tAssert.notNull(webServiceTemplateClass, \"'webServiceTemplateClass' must not be null\");\n\t\treturn configure(BeanUtils.instantiateClass(webServiceTemplateClass));\n\t}\n\n\t/**\n\t * Configure the provided {@link WebServiceTemplate} instance using this builder.\n\t * @param <T> the type of web service template\n\t * @param webServiceTemplate the {@link WebServiceTemplate} to configure\n\t * @return the web service template instance\n\t * @see #build()\n\t * @see #build(Class)\n\t */\n\tpublic <T extends WebServiceTemplate> T configure(T webServiceTemplate) {\n\t\tAssert.notNull(webServiceTemplate, \"'webServiceTemplate' must not be null\");\n\t\tconfigureMessageSenders(webServiceTemplate);\n\t\tPropertyMapper map = PropertyMapper.get();\n\t\tapplyCustomizers(webServiceTemplate, this.internalCustomizers);\n\t\tmap.from(this.marshaller).to(webServiceTemplate::setMarshaller);\n\t\tmap.from(this.unmarshaller).to(webServiceTemplate::setUnmarshaller);\n\t\tmap.from(this.destinationProvider).to(webServiceTemplate::setDestinationProvider);\n\t\tmap.from(this.transformerFactoryClass).to(webServiceTemplate::setTransformerFactoryClass);\n\t\tmap.from(this.messageFactory).to(webServiceTemplate::setMessageFactory);\n\t\tif (!CollectionUtils.isEmpty(this.interceptors)) {\n\t\t\tSet<ClientInterceptor> merged = new LinkedHashSet<>(this.interceptors);\n\t\t\tif (webServiceTemplate.getInterceptors() != null) {\n\t\t\t\tmerged.addAll(Arrays.asList(webServiceTemplate.getInterceptors()));\n\t\t\t}\n\t\t\twebServiceTemplate.setInterceptors(merged.toArray(new ClientInterceptor[0]));\n\t\t}\n\t\tapplyCustomizers(webServiceTemplate, this.customizers);\n\t\treturn webServiceTemplate;\n\t}\n\n\tprivate void applyCustomizers(WebServiceTemplate webServiceTemplate,\n\t\t\t@Nullable Set<WebServiceTemplateCustomizer> customizers) {\n\t\tif (!CollectionUtils.isEmpty(customizers)) {\n\t\t\tfor (WebServiceTemplateCustomizer customizer : customizers) {\n\t\t\t\tcustomizer.customize(webServiceTemplate);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate <T extends WebServiceTemplate> void configureMessageSenders(T webServiceTemplate) {\n\t\tif (this.messageSenders.isOnlyAdditional()\n\t\t\t\t&& (this.httpMessageSenderFactory != null || this.detectHttpMessageSender)) {\n\t\t\tWebServiceMessageSenderFactory httpMessageSenderFactory = (this.httpMessageSenderFactory != null)\n\t\t\t\t\t? this.httpMessageSenderFactory : WebServiceMessageSenderFactory.http();\n\t\t\tSet<WebServiceMessageSender> merged = append(this.messageSenders.getMessageSenders(),\n\t\t\t\t\thttpMessageSenderFactory.getWebServiceMessageSender());\n\t\t\twebServiceTemplate.setMessageSenders(merged.toArray(new WebServiceMessageSender[0]));\n\t\t}\n\t\telse if (!CollectionUtils.isEmpty(this.messageSenders.getMessageSenders())) {\n\t\t\twebServiceTemplate\n\t\t\t\t.setMessageSenders(this.messageSenders.getMessageSenders().toArray(new WebServiceMessageSender[0]));\n\t\t}\n\t}\n\n\tprivate <T> Set<T> append(@Nullable Set<T> set, T addition) {\n\t\treturn append(set, Collections.singleton(addition));\n\t}\n\n\tprivate static <T> Set<T> append(@Nullable Set<T> set, @Nullable Collection<? extends T> additions) {\n\t\tSet<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet());\n\t\tresult.addAll((additions != null) ? additions : Collections.emptyList());\n\t\treturn Collections.unmodifiableSet(result);\n\t}\n\n\t/**\n\t * Collect user-defined {@link WebServiceMessageSender} and whether only additional\n\t * message senders were added or not.\n\t */\n\tprivate static final class WebServiceMessageSenders {\n\n\t\tprivate final boolean onlyAdditional;\n\n\t\tprivate final Set<WebServiceMessageSender> messageSenders;\n\n\t\tprivate WebServiceMessageSenders() {\n\t\t\tthis(true, Collections.emptySet());\n\t\t}\n\n\t\tprivate WebServiceMessageSenders(boolean onlyAdditional, Set<WebServiceMessageSender> messageSenders) {\n\t\t\tthis.onlyAdditional = onlyAdditional;\n\t\t\tthis.messageSenders = messageSenders;\n\t\t}\n\n\t\tboolean isOnlyAdditional() {\n\t\t\treturn this.onlyAdditional;\n\t\t}\n\n\t\tSet<WebServiceMessageSender> getMessageSenders() {\n\t\t\treturn this.messageSenders;\n\t\t}\n\n\t\tWebServiceMessageSenders set(Collection<? extends WebServiceMessageSender> messageSenders) {\n\t\t\treturn new WebServiceMessageSenders(false, new LinkedHashSet<>(messageSenders));\n\t\t}\n\n\t\tWebServiceMessageSenders add(Collection<? extends WebServiceMessageSender> messageSenders) {\n\t\t\treturn new WebServiceMessageSenders(this.onlyAdditional, append(this.messageSenders, messageSenders));\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link WebServiceTemplateCustomizer} to set\n\t * {@link WebServiceTemplate#setCheckConnectionForFault(boolean)\n\t * checkConnectionForFault}.\n\t */\n\tprivate static final class CheckConnectionFaultCustomizer implements WebServiceTemplateCustomizer {\n\n\t\tprivate final boolean checkConnectionFault;\n\n\t\tprivate CheckConnectionFaultCustomizer(boolean checkConnectionFault) {\n\t\t\tthis.checkConnectionFault = checkConnectionFault;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(WebServiceTemplate webServiceTemplate) {\n\t\t\twebServiceTemplate.setCheckConnectionForFault(this.checkConnectionFault);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link WebServiceTemplateCustomizer} to set\n\t * {@link WebServiceTemplate#setCheckConnectionForError(boolean)\n\t * checkConnectionForError}.\n\t */\n\tprivate static final class CheckConnectionForErrorCustomizer implements WebServiceTemplateCustomizer {\n\n\t\tprivate final boolean checkConnectionForError;\n\n\t\tprivate CheckConnectionForErrorCustomizer(boolean checkConnectionForError) {\n\t\t\tthis.checkConnectionForError = checkConnectionForError;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(WebServiceTemplate webServiceTemplate) {\n\t\t\twebServiceTemplate.setCheckConnectionForError(this.checkConnectionForError);\n\t\t}\n\n\t}\n\n\t/**\n\t * {@link WebServiceTemplateCustomizer} to set\n\t * {@link WebServiceTemplate#setFaultMessageResolver(FaultMessageResolver)\n\t * faultMessageResolver}.\n\t */\n\tprivate static final class FaultMessageResolverCustomizer implements WebServiceTemplateCustomizer {\n\n\t\tprivate final FaultMessageResolver faultMessageResolver;\n\n\t\tprivate FaultMessageResolverCustomizer(FaultMessageResolver faultMessageResolver) {\n\t\t\tthis.faultMessageResolver = faultMessageResolver;\n\t\t}\n\n\t\t@Override\n\t\tpublic void customize(WebServiceTemplate webServiceTemplate) {\n\t\t\twebServiceTemplate.setFaultMessageResolver(this.faultMessageResolver);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/client/WebServiceTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.client;\n\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n/**\n * Callback interface that can be used to customize a {@link WebServiceTemplate}.\n *\n * @author Dmytro Nosan\n * @since 2.1.0\n */\n@FunctionalInterface\npublic interface WebServiceTemplateCustomizer {\n\n\t/**\n\t * Callback to customize a {@link WebServiceTemplate} instance.\n\t * @param webServiceTemplate the template to customize\n\t */\n\tvoid customize(WebServiceTemplate webServiceTemplate);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/java/org/springframework/boot/webservices/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Web Services client utilities.\n */\n@NullMarked\npackage org.springframework.boot.webservices.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.webservices.wsdl-locations\",\n      \"type\": \"java.util.List<java.lang.String>\",\n      \"description\": \"Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans.\"\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.webservices.autoconfigure.WebServicesAutoConfiguration\norg.springframework.boot.webservices.autoconfigure.client.WebServiceTemplateAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webservices/src/test/java/org/springframework/boot/webservices/autoconfigure/OnWsdlLocationsConditionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link OnWsdlLocationsCondition}.\n *\n * @author Eneias Silva\n * @author Stephane Nicoll\n */\nclass OnWsdlLocationsConditionTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withUserConfiguration(TestConfig.class);\n\n\t@Test\n\tvoid wsdlLocationsNotDefined() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid wsdlLocationsDefinedAsCommaSeparated() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webservices.wsdl-locations=value1\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Test\n\tvoid wsdlLocationsDefinedAsList() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webservices.wsdl-locations[0]=value1\")\n\t\t\t.run((context) -> assertThat(context).hasBean(\"foo\"));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Conditional(OnWsdlLocationsCondition.class)\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tString foo() {\n\t\t\treturn \"foo\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/test/java/org/springframework/boot/webservices/autoconfigure/WebServicesAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport java.util.Collection;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition;\nimport org.springframework.xml.xsd.SimpleXsdSchema;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebServicesAutoConfiguration}.\n *\n * @author Vedran Pavic\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Eneias Silva\n */\nclass WebServicesAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebServicesAutoConfiguration.class));\n\n\t@Test\n\tvoid defaultConfiguration() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(ServletRegistrationBean.class));\n\t}\n\n\t@Test\n\tvoid customPathMustBeginWithASlash() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webservices.path=invalid\")\n\t\t\t.run((context) -> assertThat(context).getFailure()\n\t\t\t\t.isInstanceOf(BeanCreationException.class)\n\t\t\t\t.rootCause()\n\t\t\t\t.hasMessageContaining(\"'path' must start with '/'\"));\n\t}\n\n\t@Test\n\tvoid customPath() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webservices.path=/valid\")\n\t\t\t.run((context) -> assertThat(getUrlMappings(context)).contains(\"/valid/*\"));\n\t}\n\n\t@Test\n\tvoid customPathWithTrailingSlash() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webservices.path=/valid/\")\n\t\t\t.run((context) -> assertThat(getUrlMappings(context)).contains(\"/valid/*\"));\n\t}\n\n\t@Test\n\tvoid customLoadOnStartup() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.webservices.servlet.load-on-startup=1\").run((context) -> {\n\t\t\tServletRegistrationBean<?> registrationBean = context.getBean(ServletRegistrationBean.class);\n\t\t\tassertThat(registrationBean).extracting(\"loadOnStartup\").isEqualTo(1);\n\t\t});\n\t}\n\n\t@Test\n\tvoid customInitParameters() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.webservices.servlet.init.key1=value1\",\n\t\t\t\t\t\"spring.webservices.servlet.init.key2=value2\")\n\t\t\t.run((context) -> assertThat(getServletRegistrationBean(context).getInitParameters())\n\t\t\t\t.containsEntry(\"key1\", \"value1\")\n\t\t\t\t.containsEntry(\"key2\", \"value2\"));\n\t}\n\n\t@ParameterizedTest\n\t@WithResource(name = \"wsdl/service.wsdl\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<wsdl:definitions\n\t\t\t\txmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\"\n\t\t\t\txmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\"\n\t\t\t\txmlns:tns=\"https://www.springframework.org/spring-ws/wsdl\"\n\t\t\t\ttargetNamespace=\"https://www.springframework.org/spring-ws/wsdl\">\n\t\t\t\t<wsdl:types>\n\t\t\t\t\t<xsd:schema xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n\t\t\t\t\t\telementFormDefault=\"qualified\"\n\t\t\t\t\t\ttargetNamespace=\"https://www.springframework.org/spring-ws/wsdl\">\n\t\t\t\t\t\t<xsd:element name=\"request\" type=\"xsd:string\" />\n\t\t\t\t\t\t<xsd:element name=\"response\" type=\"xsd:string\" />\n\t\t\t\t\t</xsd:schema>\n\t\t\t\t</wsdl:types>\n\t\t\t\t<wsdl:message name=\"responseMessage\">\n\t\t\t\t\t<wsdl:part name=\"body\" element=\"tns:response\" />\n\t\t\t\t</wsdl:message>\n\t\t\t\t<wsdl:message name=\"requestMessage\">\n\t\t\t\t\t<wsdl:part name=\"body\" element=\"tns:request\" />\n\t\t\t\t</wsdl:message>\n\t\t\t\t<wsdl:portType name=\"portType\">\n\t\t\t\t\t<wsdl:operation name=\"operation\">\n\t\t\t\t\t\t<wsdl:input message=\"tns:requestMessage\" name=\"request\" />\n\t\t\t\t\t\t<wsdl:output message=\"tns:responseMessage\"\n\t\t\t\t\t\t\tname=\"response\" />\n\t\t\t\t\t</wsdl:operation>\n\t\t\t\t</wsdl:portType>\n\t\t\t\t<wsdl:binding name=\"binding\" type=\"tns:portType\">\n\t\t\t\t\t<soap:binding style=\"document\"\n\t\t\t\t\t\ttransport=\"http://schemas.xmlsoap.org/soap/http\" />\n\t\t\t\t\t<wsdl:operation name=\"operation\">\n\t\t\t\t\t\t<soap:operation soapAction=\"\" />\n\t\t\t\t\t\t<wsdl:input name=\"request\">\n\t\t\t\t\t\t\t<soap:body use=\"literal\" />\n\t\t\t\t\t\t</wsdl:input>\n\t\t\t\t\t\t<wsdl:output name=\"response\">\n\t\t\t\t\t\t\t<soap:body use=\"literal\" />\n\t\t\t\t\t\t</wsdl:output>\n\t\t\t\t\t</wsdl:operation>\n\t\t\t\t</wsdl:binding>\n\t\t\t\t<wsdl:service name=\"service\">\n\t\t\t\t\t<wsdl:port binding=\"tns:binding\" name=\"port\">\n\t\t\t\t\t\t<soap:address location=\"/services\" />\n\t\t\t\t\t</wsdl:port>\n\t\t\t\t</wsdl:service>\n\t\t\t</wsdl:definitions>\n\t\t\t\"\"\")\n\t@WithResource(name = \"wsdl/types.xsd\", content = \"\"\"\n\t\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t\t<schema xmlns=\"http://www.w3.org/2001/XMLSchema\"\n\t\t\t\telementFormDefault=\"qualified\"\n\t\t\t\ttargetNamespace=\"https://www.springframework.org/spring-ws/wsdl/schemas\">\n\t\t\t\t<element name=\"request\" type=\"string\" />\n\t\t\t\t<element name=\"response\" type=\"string\" />\n\t\t\t</schema>\n\t\t\t\"\"\")\n\t@ValueSource(strings = { \"spring.webservices.wsdl-locations\", \"spring.webservices.wsdl-locations[0]\" })\n\tvoid withWsdlBeans(String propertyName) {\n\t\tthis.contextRunner.withPropertyValues(propertyName + \"=classpath:/wsdl\").run((context) -> {\n\t\t\tassertThat(context.getBeansOfType(SimpleWsdl11Definition.class)).containsOnlyKeys(\"service\");\n\t\t\tassertThat(context.getBeansOfType(SimpleXsdSchema.class)).containsOnlyKeys(\"types\");\n\t\t});\n\t}\n\n\tprivate Collection<String> getUrlMappings(ApplicationContext context) {\n\t\treturn getServletRegistrationBean(context).getUrlMappings();\n\t}\n\n\tprivate ServletRegistrationBean<?> getServletRegistrationBean(ApplicationContext loaded) {\n\t\treturn loaded.getBean(ServletRegistrationBean.class);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/test/java/org/springframework/boot/webservices/autoconfigure/WebServicesPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link WebServicesProperties}.\n *\n * @author Madhura Bhave\n */\nclass WebServicesPropertiesTests {\n\n\tprivate WebServicesProperties properties;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.properties = new WebServicesProperties();\n\t}\n\n\t@Test\n\tvoid pathMustNotBeEmpty() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.properties.setPath(\"\"))\n\t\t\t.withMessageContaining(\"'path' must have length greater than 1\");\n\t}\n\n\t@Test\n\tvoid pathMustHaveLengthGreaterThanOne() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.properties.setPath(\"/\"))\n\t\t\t.withMessageContaining(\"'path' must have length greater than 1\");\n\t}\n\n\t@Test\n\tvoid customPathMustBeginWithASlash() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.properties.setPath(\"custom\"))\n\t\t\t.withMessageContaining(\"'path' must start with '/'\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/test/java/org/springframework/boot/webservices/autoconfigure/client/WebServiceTemplateAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.autoconfigure.client;\n\nimport java.util.function.Consumer;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.context.runner.ContextConsumer;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.boot.webservices.client.WebServiceTemplateCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.client.SimpleClientHttpRequestFactory;\nimport org.springframework.oxm.Marshaller;\nimport org.springframework.oxm.Unmarshaller;\nimport org.springframework.oxm.jaxb.Jaxb2Marshaller;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.transport.WebServiceMessageSender;\nimport org.springframework.ws.transport.http.ClientHttpRequestMessageSender;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebServiceTemplateAutoConfiguration}.\n *\n * @author Stephane Nicoll\n * @author Dmytro Nosan\n */\nclass WebServiceTemplateAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebServiceTemplateAutoConfiguration.class));\n\n\t@Test\n\tvoid autoConfiguredBuilderShouldNotHaveMarshallerAndUnmarshaller() {\n\t\tthis.contextRunner.run(assertWebServiceTemplateBuilder((builder) -> {\n\t\t\tWebServiceTemplate webServiceTemplate = builder.build();\n\t\t\tassertThat(webServiceTemplate.getUnmarshaller()).isNull();\n\t\t\tassertThat(webServiceTemplate.getMarshaller()).isNull();\n\t\t}));\n\t}\n\n\t@Test\n\tvoid autoConfiguredBuilderShouldHaveHttpMessageSenderByDefault() {\n\t\tthis.contextRunner.run(assertWebServiceTemplateBuilder((builder) -> {\n\t\t\tWebServiceTemplate webServiceTemplate = builder.build();\n\t\t\tassertThat(webServiceTemplate.getMessageSenders()).hasSize(1);\n\t\t\tWebServiceMessageSender messageSender = webServiceTemplate.getMessageSenders()[0];\n\t\t\tassertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class);\n\t\t}));\n\t}\n\n\t@Test\n\tvoid webServiceTemplateWhenHasCustomBuilderShouldUseCustomBuilder() {\n\t\tthis.contextRunner.withUserConfiguration(CustomWebServiceTemplateBuilderConfig.class)\n\t\t\t.run(assertWebServiceTemplateBuilder((builder) -> {\n\t\t\t\tWebServiceTemplate webServiceTemplate = builder.build();\n\t\t\t\tassertThat(webServiceTemplate.getMarshaller())\n\t\t\t\t\t.isSameAs(CustomWebServiceTemplateBuilderConfig.marshaller);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid webServiceTemplateShouldApplyCustomizer() {\n\t\tthis.contextRunner.withUserConfiguration(WebServiceTemplateCustomizerConfig.class)\n\t\t\t.run(assertWebServiceTemplateBuilder((builder) -> {\n\t\t\t\tWebServiceTemplate webServiceTemplate = builder.build();\n\t\t\t\tassertThat(webServiceTemplate.getUnmarshaller())\n\t\t\t\t\t.isSameAs(WebServiceTemplateCustomizerConfig.unmarshaller);\n\t\t\t}));\n\t}\n\n\t@Test\n\tvoid builderShouldBeFreshForEachUse() {\n\t\tthis.contextRunner.withUserConfiguration(DirtyWebServiceTemplateConfig.class)\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\t@Test\n\tvoid whenHasFactory() {\n\t\tthis.contextRunner.withBean(ClientHttpRequestFactoryBuilder.class, ClientHttpRequestFactoryBuilder::simple)\n\t\t\t.run(assertWebServiceTemplateBuilder((builder) -> {\n\t\t\t\tWebServiceTemplate webServiceTemplate = builder.build();\n\t\t\t\tassertThat(webServiceTemplate.getMessageSenders()).hasSize(1);\n\t\t\t\tClientHttpRequestMessageSender messageSender = (ClientHttpRequestMessageSender) webServiceTemplate\n\t\t\t\t\t.getMessageSenders()[0];\n\t\t\t\tassertThat(messageSender.getRequestFactory()).isInstanceOf(SimpleClientHttpRequestFactory.class);\n\t\t\t}));\n\t}\n\n\tprivate ContextConsumer<AssertableApplicationContext> assertWebServiceTemplateBuilder(\n\t\t\tConsumer<WebServiceTemplateBuilder> builder) {\n\t\treturn (context) -> {\n\t\t\tassertThat(context).hasSingleBean(WebServiceTemplateBuilder.class);\n\t\t\tbuilder.accept(context.getBean(WebServiceTemplateBuilder.class));\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class DirtyWebServiceTemplateConfig {\n\n\t\t@Bean\n\t\tWebServiceTemplate webServiceTemplateOne(WebServiceTemplateBuilder builder) {\n\t\t\ttry {\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tbreakBuilderOnNextCall(builder);\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tWebServiceTemplate webServiceTemplateTwo(WebServiceTemplateBuilder builder) {\n\t\t\ttry {\n\t\t\t\treturn builder.build();\n\t\t\t}\n\t\t\tfinally {\n\t\t\t\tbreakBuilderOnNextCall(builder);\n\t\t\t}\n\t\t}\n\n\t\tprivate void breakBuilderOnNextCall(WebServiceTemplateBuilder builder) {\n\t\t\tbuilder.additionalCustomizers((webServiceTemplate) -> {\n\t\t\t\tthrow new IllegalStateException();\n\t\t\t});\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomWebServiceTemplateBuilderConfig {\n\n\t\tprivate static final Marshaller marshaller = new Jaxb2Marshaller();\n\n\t\t@Bean\n\t\tWebServiceTemplateBuilder webServiceTemplateBuilder() {\n\t\t\treturn new WebServiceTemplateBuilder().setMarshaller(marshaller);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebServiceTemplateCustomizerConfig {\n\n\t\tprivate static final Unmarshaller unmarshaller = new Jaxb2Marshaller();\n\n\t\t@Bean\n\t\tWebServiceTemplateCustomizer webServiceTemplateCustomizer() {\n\t\t\treturn (ws) -> ws.setUnmarshaller(unmarshaller);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/test/java/org/springframework/boot/webservices/client/WebServiceMessageSenderFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.client;\n\nimport java.time.Duration;\n\nimport org.eclipse.jetty.client.HttpClient;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.http.client.JettyClientHttpRequestFactory;\nimport org.springframework.http.client.ReactorClientHttpRequestFactory;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.ws.transport.WebServiceMessageSender;\nimport org.springframework.ws.transport.http.ClientHttpRequestMessageSender;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link WebServiceMessageSenderFactory}.\n *\n * @author Phillip Webb\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n */\nclass WebServiceMessageSenderFactoryTests {\n\n\t@Test\n\tvoid httpWhenDetectedHttpComponents() {\n\t\tWebServiceMessageSender sender = WebServiceMessageSenderFactory.http().getWebServiceMessageSender();\n\t\tassertRequestFactoryInstanceOf(sender, HttpComponentsClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"httpclient5-*.jar\")\n\tvoid httpWhenDetectedJetty() {\n\t\tWebServiceMessageSender sender = WebServiceMessageSenderFactory.http().getWebServiceMessageSender();\n\t\tassertRequestFactoryInstanceOf(sender, JettyClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"httpclient5-*.jar\", \"jetty-client-*.jar\" })\n\tvoid httpWhenDetectedReactor() {\n\t\tWebServiceMessageSender sender = WebServiceMessageSenderFactory.http().getWebServiceMessageSender();\n\t\tassertRequestFactoryInstanceOf(sender, ReactorClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"httpclient5-*.jar\", \"jetty-client-*.jar\", \"reactor-netty-http-*.jar\" })\n\tvoid httpWhenDetectedJdk() {\n\t\tWebServiceMessageSender sender = WebServiceMessageSenderFactory.http().getWebServiceMessageSender();\n\t\tassertRequestFactoryInstanceOf(sender, JdkClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"httpclient5-*.jar\")\n\tvoid httpWithSettingsUsesSettings() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults()\n\t\t\t.withConnectTimeout(Duration.ofSeconds(5))\n\t\t\t.withReadTimeout(Duration.ofSeconds(2));\n\t\tWebServiceMessageSender sender = WebServiceMessageSenderFactory.http(settings).getWebServiceMessageSender();\n\t\tassertTimeoutsOnJetty(sender);\n\t}\n\n\t@Test\n\tvoid httpWithFactoryAndSettingsUsesFactoryAndSettings() {\n\t\tHttpClientSettings settings = HttpClientSettings.defaults()\n\t\t\t.withConnectTimeout(Duration.ofSeconds(5))\n\t\t\t.withReadTimeout(Duration.ofSeconds(2));\n\t\tWebServiceMessageSender sender = WebServiceMessageSenderFactory\n\t\t\t.http(ClientHttpRequestFactoryBuilder.jetty(), settings)\n\t\t\t.getWebServiceMessageSender();\n\t\tassertTimeoutsOnJetty(sender);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid httpWithFactoryAndSettingsWhenFactoryIsNullThrowsException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> WebServiceMessageSenderFactory.http(null, null))\n\t\t\t.withMessage(\"'requestFactoryBuilder' must not be null\");\n\t}\n\n\tprivate void assertTimeoutsOnJetty(WebServiceMessageSender sender) {\n\t\tClientHttpRequestFactory requestFactory = getRequestFactory(sender);\n\t\tHttpClient client = (HttpClient) ReflectionTestUtils.getField(requestFactory, \"httpClient\");\n\t\tassertThat(client).isNotNull();\n\t\tassertThat(client.getConnectTimeout()).isEqualTo(5000);\n\t\tassertThat(requestFactory).hasFieldOrPropertyWithValue(\"readTimeout\", 2000L);\n\t}\n\n\tprivate void assertRequestFactoryInstanceOf(WebServiceMessageSender sender, Class<?> expectedRequestFactoryType) {\n\t\tassertThat(getRequestFactory(sender)).isInstanceOf(expectedRequestFactoryType);\n\t}\n\n\tprivate ClientHttpRequestFactory getRequestFactory(WebServiceMessageSender sender) {\n\t\tassertThat(sender).isInstanceOf(ClientHttpRequestMessageSender.class);\n\t\treturn ((ClientHttpRequestMessageSender) sender).getRequestFactory();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices/src/test/java/org/springframework/boot/webservices/client/WebServiceTemplateBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.client;\n\nimport java.net.URI;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport javax.xml.transform.sax.SAXTransformerFactory;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport org.springframework.http.client.ClientHttpRequestFactory;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.http.client.JdkClientHttpRequestFactory;\nimport org.springframework.oxm.Marshaller;\nimport org.springframework.oxm.Unmarshaller;\nimport org.springframework.ws.WebServiceMessageFactory;\nimport org.springframework.ws.client.core.FaultMessageResolver;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.client.support.destination.DestinationProvider;\nimport org.springframework.ws.client.support.interceptor.ClientInterceptor;\nimport org.springframework.ws.soap.saaj.SaajSoapMessageFactory;\nimport org.springframework.ws.transport.WebServiceMessageSender;\nimport org.springframework.ws.transport.http.ClientHttpRequestMessageSender;\nimport org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\n\n/**\n * Tests for {@link WebServiceTemplateBuilder}.\n *\n * @author Stephane Nicoll\n * @author Dmytro Nosan\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass WebServiceTemplateBuilderTests {\n\n\tprivate final WebServiceTemplateBuilder builder = new WebServiceTemplateBuilder();\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate WebServiceMessageSender messageSender;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate ClientInterceptor interceptor;\n\n\t@Test\n\tvoid createWithCustomizersShouldApplyCustomizers() {\n\t\tWebServiceTemplateCustomizer customizer = mock(WebServiceTemplateCustomizer.class);\n\t\tWebServiceTemplate template = new WebServiceTemplateBuilder(customizer).build();\n\t\tthen(customizer).should().customize(template);\n\t}\n\n\t@Test\n\tvoid buildShouldDetectHttpMessageSender() {\n\t\tWebServiceTemplate webServiceTemplate = this.builder.build();\n\t\tassertThat(webServiceTemplate.getMessageSenders()).hasSize(1);\n\t\tWebServiceMessageSender messageSender = webServiceTemplate.getMessageSenders()[0];\n\t\tassertRequestFactoryInstanceOf(messageSender, HttpComponentsClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\tvoid detectHttpMessageSenderWhenFalseShouldDisableDetection() {\n\t\tWebServiceTemplate webServiceTemplate = this.builder.detectHttpMessageSender(false).build();\n\t\tassertThat(webServiceTemplate.getMessageSenders()).hasSize(1);\n\t\tassertThat(webServiceTemplate.getMessageSenders()[0]).isInstanceOf(HttpUrlConnectionMessageSender.class);\n\t}\n\n\t@Test\n\tvoid httpMessageSenderFactoryUsesFactory() {\n\t\tWebServiceTemplate webServiceTemplate = this.builder\n\t\t\t.httpMessageSenderFactory(() -> new ClientHttpRequestMessageSender(new JdkClientHttpRequestFactory()))\n\t\t\t.build();\n\t\tassertThat(webServiceTemplate.getMessageSenders()).hasSize(1);\n\t\tWebServiceMessageSender messageSender = webServiceTemplate.getMessageSenders()[0];\n\t\tassertRequestFactoryInstanceOf(messageSender, JdkClientHttpRequestFactory.class);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid messageSendersWhenSendersAreAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.messageSenders((WebServiceMessageSender[]) null))\n\t\t\t.withMessageContaining(\"'messageSenders' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid messageSendersCollectionWhenSendersAreAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.messageSenders((Collection<? extends WebServiceMessageSender>) null))\n\t\t\t.withMessageContaining(\"'messageSenders' must not be null\");\n\t}\n\n\t@Test\n\tvoid messageSendersShouldApply() {\n\t\tWebServiceTemplate template = this.builder.messageSenders(this.messageSender).build();\n\t\tassertThat(template.getMessageSenders()).containsOnly(this.messageSender);\n\t}\n\n\t@Test\n\tvoid messageSendersShouldReplaceExisting() {\n\t\tWebServiceTemplate template = this.builder.messageSenders(new ClientHttpRequestMessageSender())\n\t\t\t.messageSenders(this.messageSender)\n\t\t\t.build();\n\t\tassertThat(template.getMessageSenders()).containsOnly(this.messageSender);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalMessageSendersWhenSendersAreAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalMessageSenders((WebServiceMessageSender[]) null))\n\t\t\t.withMessageContaining(\"'messageSenders' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalMessageSendersCollectionWhenSendersAreAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.builder.additionalMessageSenders((Collection<? extends WebServiceMessageSender>) null))\n\t\t\t.withMessageContaining(\"'messageSenders' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalMessageSendersShouldAddToExisting() {\n\t\tClientHttpRequestMessageSender httpMessageSender = new ClientHttpRequestMessageSender();\n\t\tWebServiceTemplate template = this.builder.messageSenders(httpMessageSender)\n\t\t\t.additionalMessageSenders(this.messageSender)\n\t\t\t.build();\n\t\tassertThat(template.getMessageSenders()).containsOnly(httpMessageSender, this.messageSender);\n\t}\n\n\t@Test\n\tvoid additionalMessageSendersShouldKeepDetectedHttpMessageSender() {\n\t\tWebServiceTemplate template = this.builder.additionalMessageSenders(this.messageSender).build();\n\t\tassertThat(template.getMessageSenders()).contains(this.messageSender);\n\t\tassertThat(template.getMessageSenders()).hasSize(2);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid interceptorsWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.builder.interceptors((ClientInterceptor[]) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid interceptorsCollectionWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.interceptors((Collection<? extends ClientInterceptor>) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\tvoid interceptorsShouldApply() {\n\t\tWebServiceTemplate template = this.builder.interceptors(this.interceptor).build();\n\t\tassertThat(template.getInterceptors()).containsOnly(this.interceptor);\n\t}\n\n\t@Test\n\tvoid interceptorsShouldReplaceExisting() {\n\t\tWebServiceTemplate template = this.builder.interceptors(mock(ClientInterceptor.class))\n\t\t\t.interceptors(Collections.singleton(this.interceptor))\n\t\t\t.build();\n\t\tassertThat(template.getInterceptors()).containsOnly(this.interceptor);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalInterceptorsWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalInterceptors((ClientInterceptor[]) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalInterceptorsCollectionWhenInterceptorsAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalInterceptors((Set<ClientInterceptor>) null))\n\t\t\t.withMessageContaining(\"'interceptors' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalInterceptorsShouldAddToExisting() {\n\t\tClientInterceptor interceptor = mock(ClientInterceptor.class);\n\t\tWebServiceTemplate template = this.builder.interceptors(interceptor)\n\t\t\t.additionalInterceptors(this.interceptor)\n\t\t\t.build();\n\t\tassertThat(template.getInterceptors()).containsOnly(interceptor, this.interceptor);\n\t}\n\n\t@Test\n\tvoid additionalInterceptorsShouldAddToExistingWebServiceTemplate() {\n\t\tClientInterceptor f1 = mock(ClientInterceptor.class);\n\t\tClientInterceptor f2 = mock(ClientInterceptor.class);\n\t\tWebServiceTemplate webServiceTemplate = new WebServiceTemplate();\n\t\twebServiceTemplate.setInterceptors(new ClientInterceptor[] { f1 });\n\t\tthis.builder.additionalInterceptors(f2).configure(webServiceTemplate);\n\t\tassertThat(webServiceTemplate.getInterceptors()).containsExactlyInAnyOrder(f2, f1);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((WebServiceTemplateCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid customizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.customizers((Collection<? extends WebServiceTemplateCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid customizersShouldApply() {\n\t\tWebServiceTemplateCustomizer customizer = mock(WebServiceTemplateCustomizer.class);\n\t\tWebServiceTemplate template = this.builder.customizers(customizer).build();\n\t\tthen(customizer).should().customize(template);\n\t}\n\n\t@Test\n\tvoid customizersShouldBeAppliedLast() {\n\t\tWebServiceTemplate template = spy(new WebServiceTemplate());\n\t\tthis.builder.additionalCustomizers(\n\t\t\t\t((webServiceTemplate) -> then(webServiceTemplate).should().setMessageSenders(any())));\n\t\tthis.builder.configure(template);\n\t}\n\n\t@Test\n\tvoid customizersShouldReplaceExisting() {\n\t\tWebServiceTemplateCustomizer customizer1 = mock(WebServiceTemplateCustomizer.class);\n\t\tWebServiceTemplateCustomizer customizer2 = mock(WebServiceTemplateCustomizer.class);\n\t\tWebServiceTemplate template = this.builder.customizers(customizer1)\n\t\t\t.customizers(Collections.singleton(customizer2))\n\t\t\t.build();\n\t\tthen(customizer1).shouldHaveNoInteractions();\n\t\tthen(customizer2).should().customize(template);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(() -> this.builder.additionalCustomizers((WebServiceTemplateCustomizer[]) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException()\n\t\t\t.isThrownBy(\n\t\t\t\t\t() -> this.builder.additionalCustomizers((Collection<? extends WebServiceTemplateCustomizer>) null))\n\t\t\t.withMessageContaining(\"'customizers' must not be null\");\n\t}\n\n\t@Test\n\tvoid additionalCustomizersShouldAddToExisting() {\n\t\tWebServiceTemplateCustomizer customizer1 = mock(WebServiceTemplateCustomizer.class);\n\t\tWebServiceTemplateCustomizer customizer2 = mock(WebServiceTemplateCustomizer.class);\n\t\tWebServiceTemplate template = this.builder.customizers(customizer1).additionalCustomizers(customizer2).build();\n\t\tthen(customizer1).should().customize(template);\n\t\tthen(customizer2).should().customize(template);\n\t}\n\n\t@Test\n\tvoid setCheckConnectionForFault() {\n\t\tWebServiceTemplate template = mock(WebServiceTemplate.class);\n\t\tthis.builder.setCheckConnectionForFault(false).configure(template);\n\t\tthen(template).should().setCheckConnectionForFault(false);\n\t}\n\n\t@Test\n\tvoid setCheckConnectionForError() {\n\t\tWebServiceTemplate template = mock(WebServiceTemplate.class);\n\t\tthis.builder.setCheckConnectionForError(false).configure(template);\n\t\tthen(template).should().setCheckConnectionForError(false);\n\n\t}\n\n\t@Test\n\tvoid setTransformerFactoryClass() {\n\t\tWebServiceTemplate template = mock(WebServiceTemplate.class);\n\t\tthis.builder.setTransformerFactoryClass(SAXTransformerFactory.class).configure(template);\n\t\tthen(template).should().setTransformerFactoryClass(SAXTransformerFactory.class);\n\t}\n\n\t@Test\n\tvoid buildShouldDetectWebServiceMessageFactory() {\n\t\tWebServiceTemplate webServiceTemplate = this.builder.build();\n\t\tassertThat(webServiceTemplate.getMessageFactory()).isInstanceOf(SaajSoapMessageFactory.class);\n\t}\n\n\t@Test\n\tvoid setWebServiceMessageFactory() {\n\t\tWebServiceMessageFactory messageFactory = mock(WebServiceMessageFactory.class);\n\t\tWebServiceTemplate template = this.builder.setWebServiceMessageFactory(messageFactory).build();\n\t\tassertThat(template.getMessageFactory()).isEqualTo(messageFactory);\n\t}\n\n\t@Test\n\tvoid setMarshaller() {\n\t\tMarshaller marshaller = mock(Marshaller.class);\n\t\tWebServiceTemplate template = this.builder.setMarshaller(marshaller).build();\n\t\tassertThat(template.getMarshaller()).isEqualTo(marshaller);\n\t}\n\n\t@Test\n\tvoid setUnmarshaller() {\n\t\tUnmarshaller unmarshaller = mock(Unmarshaller.class);\n\t\tWebServiceTemplate webServiceTemplate = this.builder.setUnmarshaller(unmarshaller).build();\n\t\tassertThat(webServiceTemplate.getUnmarshaller()).isEqualTo(unmarshaller);\n\t}\n\n\t@Test\n\tvoid setFaultMessageResolver() {\n\t\tFaultMessageResolver faultMessageResolver = mock(FaultMessageResolver.class);\n\t\tWebServiceTemplate webServiceTemplate = this.builder.setFaultMessageResolver(faultMessageResolver).build();\n\t\tassertThat(webServiceTemplate.getFaultMessageResolver()).isEqualTo(faultMessageResolver);\n\t}\n\n\t@Test\n\tvoid setDefaultUri() {\n\t\tURI uri = URI.create(\"http://localhost:8080\");\n\t\tWebServiceTemplate webServiceTemplate = this.builder.setDefaultUri(uri.toString()).build();\n\t\tDestinationProvider destinationProvider = webServiceTemplate.getDestinationProvider();\n\t\tassertThat(destinationProvider).isNotNull();\n\t\tassertThat(destinationProvider.getDestination()).isEqualTo(uri);\n\t}\n\n\t@Test\n\tvoid setDestinationProvider() {\n\t\tDestinationProvider destinationProvider = () -> URI.create(\"http://localhost:8080\");\n\t\tWebServiceTemplate webServiceTemplate = this.builder.setDestinationProvider(destinationProvider).build();\n\t\tassertThat(webServiceTemplate.getDestinationProvider()).isEqualTo(destinationProvider);\n\t}\n\n\tprivate void assertRequestFactoryInstanceOf(WebServiceMessageSender messageSender, Class<?> type) {\n\t\tassertThat(messageSender).isInstanceOf(ClientHttpRequestMessageSender.class);\n\t\tClientHttpRequestMessageSender sender = (ClientHttpRequestMessageSender) messageSender;\n\t\tClientHttpRequestFactory requestFactory = sender.getRequestFactory();\n\t\tassertThat(requestFactory).isInstanceOf(type);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-slice\"\n}\n\ndescription = \"Spring Boot Web Services Test\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\tapi(project(\":module:spring-boot-webservices\"))\n\tapi(\"org.springframework.ws:spring-ws-test\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(\"org.junit.jupiter:junit-jupiter-api\")\n\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/AutoConfigureMockWebServiceServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of a single {@link MockWebServiceServer}.\n *\n * @author Dmytro Nosan\n * @since 2.3.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.webservice.client.mockserver\")\npublic @interface AutoConfigureMockWebServiceServer {\n\n\t/**\n\t * If {@link MockWebServiceServer} bean should be registered. Defaults to\n\t * {@code true}.\n\t * @return if mock support is enabled\n\t */\n\tboolean enabled() default true;\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/AutoConfigureWebServiceClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of web service clients.\n *\n * @author Dmytro Nosan\n * @since 2.3.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.webservice.client\")\npublic @interface AutoConfigureWebServiceClient {\n\n\t/**\n\t * If a {@link WebServiceTemplate} bean should be registered. Defaults to\n\t * {@code false} with the assumption that the {@link WebServiceTemplateBuilder} will\n\t * be used.\n\t * @return if a {@link WebServiceTemplate} bean should be added.\n\t */\n\tboolean registerWebServiceTemplate() default false;\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/MockWebServiceServerAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.test.client.MockWebServiceMessageSender;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\n/**\n * Auto-configuration for {@link MockWebServiceServer} support.\n *\n * @author Dmytro Nosan\n * @since 2.3.0\n * @see AutoConfigureMockWebServiceServer\n */\n@AutoConfiguration\n@ConditionalOnBooleanProperty(\"spring.test.webservice.client.mockserver.enabled\")\n@ConditionalOnClass({ MockWebServiceServer.class, WebServiceTemplate.class })\npublic final class MockWebServiceServerAutoConfiguration {\n\n\t@Bean\n\tTestMockWebServiceServer mockWebServiceServer() {\n\t\treturn new TestMockWebServiceServer(new MockWebServiceMessageSender());\n\t}\n\n\t@Bean\n\tMockWebServiceServerWebServiceTemplateCustomizer mockWebServiceServerWebServiceTemplateCustomizer(\n\t\t\tTestMockWebServiceServer mockWebServiceServer) {\n\t\treturn new MockWebServiceServerWebServiceTemplateCustomizer(mockWebServiceServer);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/MockWebServiceServerTestExecutionListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.TestExecutionListener;\nimport org.springframework.test.context.support.AbstractTestExecutionListener;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\n/**\n * {@link TestExecutionListener} to {@code verify} and {@code reset}\n * {@link MockWebServiceServer}.\n *\n * @author Dmytro Nosan\n * @since 2.3.0\n */\npublic class MockWebServiceServerTestExecutionListener extends AbstractTestExecutionListener {\n\n\tprivate static final boolean MOCK_SERVER_PRESENT = ClassUtils.isPresent(\n\t\t\t\"org.springframework.ws.test.client.MockWebServiceServer\",\n\t\t\tMockWebServiceServerTestExecutionListener.class.getClassLoader());\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.LOWEST_PRECEDENCE - 100;\n\t}\n\n\t@Override\n\tpublic void afterTestMethod(TestContext testContext) {\n\t\tif (MOCK_SERVER_PRESENT) {\n\t\t\tApplicationContext applicationContext = testContext.getApplicationContext();\n\t\t\tString[] names = applicationContext.getBeanNamesForType(MockWebServiceServer.class, false, false);\n\t\t\tfor (String name : names) {\n\t\t\t\tMockWebServiceServer mockServer = applicationContext.getBean(name, MockWebServiceServer.class);\n\t\t\t\tmockServer.verify();\n\t\t\t\tmockServer.reset();\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/MockWebServiceServerWebServiceTemplateCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.boot.webservices.client.WebServiceTemplateCustomizer;\nimport org.springframework.util.Assert;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\n/**\n * {@link WebServiceTemplateCustomizer} that can be applied to a\n * {@link WebServiceTemplateBuilder} instances to add {@link MockWebServiceServer}\n * support.\n *\n * @author Dmytro Nosan\n */\nclass MockWebServiceServerWebServiceTemplateCustomizer implements WebServiceTemplateCustomizer {\n\n\tprivate final AtomicBoolean applied = new AtomicBoolean();\n\n\tprivate final TestMockWebServiceServer mockServer;\n\n\tMockWebServiceServerWebServiceTemplateCustomizer(TestMockWebServiceServer mockServer) {\n\t\tthis.mockServer = mockServer;\n\t}\n\n\t@Override\n\tpublic void customize(WebServiceTemplate webServiceTemplate) {\n\t\tAssert.state(!this.applied.getAndSet(true), \"@WebServiceClientTest supports only a single WebServiceTemplate\");\n\t\twebServiceTemplate.setMessageSender(this.mockServer.getMockMessageSender());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/TestMockWebServiceServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.ws.test.client.MockWebServiceMessageSender;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\n/**\n * Test {@link MockWebServiceServer} which provides access to the underlying\n * {@link MockWebServiceMessageSender}.\n *\n * @author Dmytro Nosan\n */\nfinal class TestMockWebServiceServer extends MockWebServiceServer {\n\n\tprivate final MockWebServiceMessageSender mockMessageSender;\n\n\tTestMockWebServiceServer(MockWebServiceMessageSender mockMessageSender) {\n\t\tsuper(mockMessageSender);\n\t\tthis.mockMessageSender = mockMessageSender;\n\t}\n\n\tMockWebServiceMessageSender getMockMessageSender() {\n\t\treturn this.mockMessageSender;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\n\n/**\n * {@link TypeExcludeFilter} for {@link WebServiceClientTest @WebServiceClientTest}.\n *\n * @author Dmytro Nosan\n */\nclass WebServiceClientExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<WebServiceClientTest> {\n\n\tprivate final Class<?>[] components;\n\n\tWebServiceClientExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.components = getAnnotation().getValue(\"components\", Class[].class).orElseGet(() -> new Class<?>[0]);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.components));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientTemplateAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.webservices.autoconfigure.client.WebServiceTemplateAutoConfiguration;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n/**\n * Auto-configuration for a web-client {@link WebServiceTemplate}. Used when\n * {@link AutoConfigureWebServiceClient#registerWebServiceTemplate()} is {@code true}.\n *\n * @author Dmytro Nosan\n * @since 2.3.0\n * @see AutoConfigureWebServiceClient\n */\n@AutoConfiguration(after = WebServiceTemplateAutoConfiguration.class)\n@ConditionalOnBooleanProperty(\"spring.test.webservice.client.register-web-service-template\")\n@ConditionalOnClass(WebServiceTemplate.class)\n@ConditionalOnBean(WebServiceTemplateBuilder.class)\npublic final class WebServiceClientTemplateAutoConfiguration {\n\n\t@Bean\n\tWebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder builder) {\n\t\treturn builder.build();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\n/**\n * Annotation that can be used for a typical Spring web service client test. Can be used\n * when a test focuses <strong>only</strong> on beans that use\n * {@link WebServiceTemplateBuilder}. By default, tests annotated with\n * {@code WebServiceClientTest} will also auto-configure a {@link MockWebServiceServer}.\n * <p>\n * If you are testing a bean that doesn't use {@link WebServiceTemplateBuilder} but\n * instead injects a {@link WebServiceTemplate} directly, you can add\n * {@code @AutoConfigureWebServiceClient(registerWebServiceTemplate=true)}.\n * <p>\n * When using JUnit 4, this annotation should be used in combination with\n * {@code @RunWith(SpringRunner.class)}.\n *\n * @author Dmytro Nosan\n * @since 2.3.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(WebServiceClientTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(WebServiceClientExcludeFilter.class)\n@AutoConfigureMockWebServiceServer\n@AutoConfigureWebServiceClient\n@ImportAutoConfiguration\npublic @interface WebServiceClientTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the components to test. This is an alias of {@link #components()} which\n\t * can be used for brevity if no other attributes are defined. See\n\t * {@link #components()} for details.\n\t * @see #components()\n\t * @return the components to test\n\t */\n\t@AliasFor(\"components\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the components to test. May be left blank if components will be manually\n\t * imported or created directly.\n\t * @see #value()\n\t * @return the components to test\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] components() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default, only\n\t * {@code @JacksonComponent} and {@code JacksonModule} beans are included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.TestContextBootstrapper;\n\n/**\n * {@link TestContextBootstrapper} for {@link WebServiceClientTest @WebServiceClientTest}\n * support.\n *\n * @author Dmytro Nosan\n */\nclass WebServiceClientTestContextBootstrapper extends TestSliceTestContextBootstrapper<WebServiceClientTest> {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for web service clients.\n */\n@NullMarked\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/AutoConfigureMockWebServiceClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.ws.test.server.MockWebServiceClient;\n\n/**\n * Annotation that can be applied to a test class to enable auto-configuration of\n * {@link MockWebServiceClient}.\n *\n * @author Daniil Razorenov\n * @since 4.0.0\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureMockWebServiceClient {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/AutoConfigureWebServiceServer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Annotation that can be applied to a test class to enable and configure\n * auto-configuration of web service servers endpoints.\n *\n * @author Daniil Razorenov\n * @since 4.0.0\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\npublic @interface AutoConfigureWebServiceServer {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/MockWebServiceClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.ws.test.server.MockWebServiceClient;\n\n/**\n * Auto-configuration for {@link MockWebServiceClient} support.\n *\n * @author Daniil Razorenov\n * @since 4.0.0\n * @see AutoConfigureMockWebServiceClient\n */\n@AutoConfiguration\n@ConditionalOnClass(MockWebServiceClient.class)\npublic final class MockWebServiceClientAutoConfiguration {\n\n\t@Bean\n\tMockWebServiceClient mockWebServiceClient(ApplicationContext applicationContext) {\n\t\treturn MockWebServiceClient.createClient(applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/WebServiceServerTest.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;\nimport org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.core.annotation.AliasFor;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.BootstrapWith;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\n/**\n * Annotation that can be used for a typical Spring web service server test. Can be used\n * when a test focuses <strong>only</strong> on Spring WS endpoints.\n * <p>\n * Using this annotation only enables auto-configuration that is relevant to Web Service\n * Server tests. Similarly, component scanning is limited to beans annotated with:\n * <ul>\n * <li>{@code @Endpoint}</li>\n * </ul>\n * <p>\n * as well as beans that implement:\n * <ul>\n * <li>{@code EndpointInterceptor}</li>\n * </ul>\n * <p>\n * Typically {@code WebServiceServerTest} is used in combination with\n * {@link org.springframework.test.context.bean.override.mockito.MockitoBean @MockitoBean}\n * or {@link org.springframework.context.annotation.Import @Import} to create any\n * collaborators required by your {@code Endpoint} beans.\n * <p>\n * If you are looking to load your full application configuration and use\n * MockWebServiceClient, you should consider\n * {@link org.springframework.boot.test.context.SpringBootTest @SpringBootTest} combined\n * with {@link AutoConfigureMockWebServiceClient @AutoConfigureMockWebServiceClient}\n * rather than this annotation.\n *\n * @author Daniil Razorenov\n * @since 4.0.0\n * @see AutoConfigureMockWebServiceClient\n * @see AutoConfigureWebServiceServer\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@BootstrapWith(WebServiceServerTestContextBootstrapper.class)\n@ExtendWith(SpringExtension.class)\n@OverrideAutoConfiguration(enabled = false)\n@TypeExcludeFilters(WebServiceServerTypeExcludeFilter.class)\n@AutoConfigureWebServiceServer\n@AutoConfigureMockWebServiceClient\n@ImportAutoConfiguration\npublic @interface WebServiceServerTest {\n\n\t/**\n\t * Properties in form {@literal key=value} that should be added to the Spring\n\t * {@link Environment} before the test runs.\n\t * @return the properties to add\n\t */\n\tString[] properties() default {};\n\n\t/**\n\t * Specifies the endpoints to test. This is an alias of {@link #endpoints()} which can\n\t * be used for brevity if no other attributes are defined. See {@link #endpoints()}\n\t * for details.\n\t * @return the endpoints to test\n\t * @see #endpoints()\n\t */\n\t@AliasFor(\"endpoints\")\n\tClass<?>[] value() default {};\n\n\t/**\n\t * Specifies the endpoints to test. May be left blank if all {@code @Endpoint} beans\n\t * should be added to the application context.\n\t * @return the endpoints to test\n\t * @see #value()\n\t */\n\t@AliasFor(\"value\")\n\tClass<?>[] endpoints() default {};\n\n\t/**\n\t * Determines if default filtering should be used with\n\t * {@link SpringBootApplication @SpringBootApplication}. By default only\n\t * {@code @Endpoint} (when no explicit {@link #endpoints() controllers} are defined)\n\t * are included.\n\t * @see #includeFilters()\n\t * @see #excludeFilters()\n\t * @return if default filters should be used\n\t */\n\tboolean useDefaultFilters() default true;\n\n\t/**\n\t * A set of include filters which can be used to add otherwise filtered beans to the\n\t * application context.\n\t * @return include filters to apply\n\t */\n\tComponentScan.Filter[] includeFilters() default {};\n\n\t/**\n\t * A set of exclude filters which can be used to filter beans that would otherwise be\n\t * added to the application context.\n\t * @return exclude filters to apply\n\t */\n\tComponentScan.Filter[] excludeFilters() default {};\n\n\t/**\n\t * Auto-configuration exclusions that should be applied for this test.\n\t * @return auto-configuration exclusions to apply\n\t */\n\t@AliasFor(annotation = ImportAutoConfiguration.class, attribute = \"exclude\")\n\tClass<?>[] excludeAutoConfiguration() default {};\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/WebServiceServerTestContextBootstrapper.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.springframework.boot.test.autoconfigure.TestSliceTestContextBootstrapper;\nimport org.springframework.test.context.MergedContextConfiguration;\nimport org.springframework.test.context.TestContextBootstrapper;\nimport org.springframework.test.context.web.WebMergedContextConfiguration;\n\n/**\n * {@link TestContextBootstrapper} for {@link WebServiceServerTest @WebServiceServerTest}\n * support.\n *\n * @author Daniil Razorenov\n */\nclass WebServiceServerTestContextBootstrapper extends TestSliceTestContextBootstrapper<WebServiceServerTest> {\n\n\t@Override\n\tprotected MergedContextConfiguration processMergedContextConfiguration(MergedContextConfiguration mergedConfig) {\n\t\tMergedContextConfiguration processedMergedConfiguration = super.processMergedContextConfiguration(mergedConfig);\n\t\treturn new WebMergedContextConfiguration(processedMergedConfiguration, determineResourceBasePath(mergedConfig));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/WebServiceServerTypeExcludeFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\nimport org.springframework.boot.context.TypeExcludeFilter;\nimport org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.ws.server.EndpointInterceptor;\nimport org.springframework.ws.server.endpoint.annotation.Endpoint;\n\n/**\n * {@link TypeExcludeFilter} for {@link WebServiceServerTest @WebServiceServerTest}.\n *\n * @author Daniil Razorenov\n */\nclass WebServiceServerTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<WebServiceServerTest> {\n\n\tprivate static final Class<?>[] NO_ENDPOINTS = {};\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES;\n\n\tprivate static final Set<Class<?>> KNOWN_INCLUDES_AND_ENDPOINT;\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>();\n\t\tincludes.add(EndpointInterceptor.class);\n\t\tKNOWN_INCLUDES = Collections.unmodifiableSet(includes);\n\t}\n\n\tstatic {\n\t\tSet<Class<?>> includes = new LinkedHashSet<>(KNOWN_INCLUDES);\n\t\tincludes.add(Endpoint.class);\n\t\tKNOWN_INCLUDES_AND_ENDPOINT = Collections.unmodifiableSet(includes);\n\t}\n\n\tprivate final Class<?>[] endpoints;\n\n\tWebServiceServerTypeExcludeFilter(Class<?> testClass) {\n\t\tsuper(testClass);\n\t\tthis.endpoints = getAnnotation().getValue(\"endpoints\", Class[].class).orElse(NO_ENDPOINTS);\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getKnownIncludes() {\n\t\tif (ObjectUtils.isEmpty(this.endpoints)) {\n\t\t\treturn KNOWN_INCLUDES_AND_ENDPOINT;\n\t\t}\n\t\treturn KNOWN_INCLUDES;\n\t}\n\n\t@Override\n\tprotected Set<Class<?>> getComponentIncludes() {\n\t\treturn new LinkedHashSet<>(Arrays.asList(this.endpoints));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/java/org/springframework/boot/webservices/test/autoconfigure/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for web service server tests.\n */\n@NullMarked\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.test.webservice.client.mockserver.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether a MockWebServiceServer should be auto-configured.\",\n      \"defaultValue\": true\n    },\n    {\n      \"name\": \"spring.test.webservice.client.register-web-service-template\",\n      \"type\": \"java.lang.Boolean\",\n      \"description\": \"Whether a WebServiceTemplate bean should be registered.\",\n      \"defaultValue\": false\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/resources/META-INF/spring/org.springframework.boot.webservices.test.autoconfigure.client.AutoConfigureMockWebServiceServer.imports",
    "content": "org.springframework.boot.webservices.test.autoconfigure.client.MockWebServiceServerAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/resources/META-INF/spring/org.springframework.boot.webservices.test.autoconfigure.client.AutoConfigureWebServiceClient.imports",
    "content": "org.springframework.boot.webservices.autoconfigure.client.WebServiceTemplateAutoConfiguration\norg.springframework.boot.webservices.test.autoconfigure.client.WebServiceClientTemplateAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/resources/META-INF/spring/org.springframework.boot.webservices.test.autoconfigure.server.AutoConfigureMockWebServiceClient.imports",
    "content": "org.springframework.boot.webservices.test.autoconfigure.server.MockWebServiceClientAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/resources/META-INF/spring/org.springframework.boot.webservices.test.autoconfigure.server.AutoConfigureWebServiceServer.imports",
    "content": "org.springframework.boot.webservices.autoconfigure.WebServicesAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/main/resources/META-INF/spring.factories",
    "content": "# Spring Test Execution Listeners\norg.springframework.test.context.TestExecutionListener=\\\norg.springframework.boot.webservices.test.autoconfigure.client.MockWebServiceServerTestExecutionListener\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/AutoConfigureMockWebServiceServerEnabledIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.ws.test.client.MockWebServiceServer;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link AutoConfigureMockWebServiceServer @AutoConfigureMockWebServiceServer}\n * with {@code enabled=false}.\n *\n * @author Dmytro Nosan\n */\n@WebServiceClientTest\n@AutoConfigureMockWebServiceServer(enabled = false)\nclass AutoConfigureMockWebServiceServerEnabledIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid mockWebServiceServerShouldNotBeRegistered() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(MockWebServiceServer.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/AutoConfigureWebServiceClientWebServiceTemplateIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.ws.client.core.WebServiceTemplate;\nimport org.springframework.ws.test.client.MockWebServiceServer;\nimport org.springframework.xml.transform.StringSource;\n\nimport static org.springframework.ws.test.client.RequestMatchers.payload;\nimport static org.springframework.ws.test.client.ResponseCreators.withPayload;\n\n/**\n * Tests for {@link AutoConfigureWebServiceClient @AutoConfigureWebServiceClient} with\n * {@code registerWebServiceTemplate=true}.\n *\n * @author Dmytro Nosan\n */\n@SpringBootTest\n@AutoConfigureWebServiceClient(registerWebServiceTemplate = true)\n@AutoConfigureMockWebServiceServer\nclass AutoConfigureWebServiceClientWebServiceTemplateIntegrationTests {\n\n\t@Autowired\n\tprivate WebServiceTemplate webServiceTemplate;\n\n\t@Autowired\n\tprivate MockWebServiceServer server;\n\n\t@Test\n\tvoid webServiceTemplateTest() {\n\t\tthis.server.expect(payload(new StringSource(\"<request/>\")))\n\t\t\t.andRespond(withPayload(new StringSource(\"<response/>\")));\n\t\tthis.webServiceTemplate.marshalSendAndReceive(\"https://example.com\", new Request());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(WebServiceMarshallerConfiguration.class)\n\tstatic class Config {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/ExampleWebServiceClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.stereotype.Service;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\n/**\n * Example web client used with {@link WebServiceClientTest @WebServiceClientTest} tests.\n *\n * @author Dmytro Nosan\n */\n@Service\npublic class ExampleWebServiceClient {\n\n\tprivate final WebServiceTemplate webServiceTemplate;\n\n\tpublic ExampleWebServiceClient(WebServiceTemplateBuilder builder) {\n\t\tthis.webServiceTemplate = builder.build();\n\t}\n\n\tpublic @Nullable Response test() {\n\t\treturn (Response) this.webServiceTemplate.marshalSendAndReceive(\"https://example.com\", new Request());\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/ExampleWebServiceClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link WebServiceClientTest @WebServiceClientTest} tests.\n *\n * @author Dmytro Nosan\n */\n@SpringBootApplication\n@Import(WebServiceMarshallerConfiguration.class)\npublic class ExampleWebServiceClientApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/Request.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport jakarta.xml.bind.annotation.XmlRootElement;\n\n/**\n * Test request.\n *\n * @author Dmytro Nosan\n */\n@XmlRootElement(name = \"request\")\nclass Request {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/Response.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport jakarta.xml.bind.annotation.XmlAccessType;\nimport jakarta.xml.bind.annotation.XmlAccessorType;\nimport jakarta.xml.bind.annotation.XmlRootElement;\n\n/**\n * Test response.\n *\n * @author Dmytro Nosan\n */\n@XmlRootElement(name = \"response\")\n@XmlAccessorType(XmlAccessType.FIELD)\nclass Response {\n\n\tprivate int status;\n\n\tint getStatus() {\n\t\treturn this.status;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.ws.client.WebServiceTransportException;\nimport org.springframework.ws.test.client.MockWebServiceServer;\nimport org.springframework.ws.test.support.SourceAssertionError;\nimport org.springframework.xml.transform.StringSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.ws.test.client.RequestMatchers.connectionTo;\nimport static org.springframework.ws.test.client.RequestMatchers.payload;\nimport static org.springframework.ws.test.client.ResponseCreators.withError;\nimport static org.springframework.ws.test.client.ResponseCreators.withPayload;\n\n/**\n * Tests for {@link WebServiceClientTest @WebServiceClientTest}.\n *\n * @author Dmytro Nosan\n */\n@WebServiceClientTest(ExampleWebServiceClient.class)\nclass WebServiceClientIntegrationTests {\n\n\t@Autowired\n\tprivate MockWebServiceServer server;\n\n\t@Autowired\n\tprivate ExampleWebServiceClient client;\n\n\t@Test\n\tvoid mockServerCall() {\n\t\tthis.server.expect(payload(new StringSource(\"<request/>\")))\n\t\t\t.andRespond(withPayload(new StringSource(\"<response><status>200</status></response>\")));\n\t\tassertThat(this.client.test()).extracting(Response::getStatus).isEqualTo(200);\n\t}\n\n\t@Test\n\tvoid mockServerCall1() {\n\t\tthis.server.expect(connectionTo(\"https://example1\")).andRespond(withPayload(new StringSource(\"<response/>\")));\n\t\tassertThatExceptionOfType(SourceAssertionError.class).isThrownBy(this.client::test)\n\t\t\t.withMessageContaining(\"Unexpected connection expected\");\n\t}\n\n\t@Test\n\tvoid mockServerCall2() {\n\t\tthis.server.expect(payload(new StringSource(\"<request/>\"))).andRespond(withError(\"Invalid Request\"));\n\t\tassertThatExceptionOfType(WebServiceTransportException.class).isThrownBy(this.client::test)\n\t\t\t.withMessageContaining(\"Invalid Request\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientNoComponentIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webservices.client.WebServiceTemplateBuilder;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.ws.test.client.MockWebServiceServer;\nimport org.springframework.xml.transform.StringSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.ws.test.client.RequestMatchers.payload;\nimport static org.springframework.ws.test.client.ResponseCreators.withPayload;\n\n/**\n * Tests for {@link WebServiceClientTest @WebServiceClientTest} with no specific client.\n *\n * @author Dmytro Nosan\n */\n@WebServiceClientTest\nclass WebServiceClientNoComponentIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate WebServiceTemplateBuilder webServiceTemplateBuilder;\n\n\t@Autowired\n\tprivate MockWebServiceServer server;\n\n\t@Test\n\tvoid exampleClientIsNotInjected() {\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(ExampleWebServiceClient.class));\n\t}\n\n\t@Test\n\tvoid manuallyCreateBean() {\n\t\tExampleWebServiceClient client = new ExampleWebServiceClient(this.webServiceTemplateBuilder);\n\t\tthis.server.expect(payload(new StringSource(\"<request/>\")))\n\t\t\t.andRespond(withPayload(new StringSource(\"<response><status>200</status></response>\")));\n\t\tassertThat(client.test()).extracting(Response::getStatus).isEqualTo(200);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceClientPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link WebServiceClientTest#properties properties} attribute of\n * {@link WebServiceClientTest @WebServiceClientTest}.\n *\n * @author Dmytro Nosan\n */\n@WebServiceClientTest(properties = \"spring.profiles.active=test\")\nclass WebServiceClientPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(WebServiceClientPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/client/WebServiceMarshallerConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.client;\n\nimport org.springframework.boot.webservices.client.WebServiceTemplateCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.oxm.Marshaller;\nimport org.springframework.oxm.Unmarshaller;\nimport org.springframework.oxm.jaxb.Jaxb2Marshaller;\n\n/**\n * Test configuration to configure {@code Marshaller} and {@code Unmarshaller}.\n *\n * @author Dmytro Nosan\n */\n@Configuration(proxyBeanMethods = false)\nclass WebServiceMarshallerConfiguration {\n\n\t@Bean\n\tWebServiceTemplateCustomizer marshallerCustomizer(Marshaller marshaller) {\n\t\treturn (webServiceTemplate) -> webServiceTemplate.setMarshaller(marshaller);\n\t}\n\n\t@Bean\n\tWebServiceTemplateCustomizer unmarshallerCustomizer(Unmarshaller unmarshaller) {\n\t\treturn (webServiceTemplate) -> webServiceTemplate.setUnmarshaller(unmarshaller);\n\t}\n\n\t@Bean\n\tJaxb2Marshaller createJaxbMarshaller() {\n\t\tJaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();\n\t\tjaxb2Marshaller.setClassesToBeBound(Request.class, Response.class);\n\t\treturn jaxb2Marshaller;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/ExampleWebServiceEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.springframework.ws.server.endpoint.annotation.Endpoint;\nimport org.springframework.ws.server.endpoint.annotation.PayloadRoot;\nimport org.springframework.ws.server.endpoint.annotation.RequestPayload;\nimport org.springframework.ws.server.endpoint.annotation.ResponsePayload;\n\n/**\n * Example web service {@code @Endpoint} used with\n * {@link WebServiceServerTest @WebServiceServerTest} tests.\n *\n * @author Daniil Razorenov\n */\n@Endpoint\npublic class ExampleWebServiceEndpoint {\n\n\t@PayloadRoot(localPart = \"request\")\n\t@ResponsePayload\n\tResponse payloadMethod(@RequestPayload Request request) {\n\t\treturn new Response(42);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/ExampleWebServiceServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link WebServiceServerTest @WebServiceServerTest} tests.\n *\n * @author Daniil Razorenov\n */\n@SpringBootApplication\npublic class ExampleWebServiceServerApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/MockWebServiceClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.WebApplicationContextRunner;\nimport org.springframework.ws.test.server.MockWebServiceClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link MockWebServiceClientAutoConfiguration}.\n *\n * @author Daniil Razorenov\n */\nclass MockWebServiceClientAutoConfigurationTests {\n\n\tprivate final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(MockWebServiceClientAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldRegisterMockWebServiceClient() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(MockWebServiceClient.class));\n\t}\n\n\t@Test\n\tvoid shouldNotRegisterMockWebServiceClientWhenItIsNotOnTheClasspath() {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(MockWebServiceClient.class);\n\n\t\tthis.contextRunner.withClassLoader(classLoader)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(MockWebServiceClient.class));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/Request.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport jakarta.xml.bind.annotation.XmlElement;\nimport jakarta.xml.bind.annotation.XmlRootElement;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Test request.\n *\n * @author Daniil Razorenov\n */\n@XmlRootElement(name = \"request\")\nclass Request {\n\n\t@XmlElement(required = true)\n\tprivate @Nullable String message;\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/Response.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport jakarta.xml.bind.annotation.XmlElement;\nimport jakarta.xml.bind.annotation.XmlRootElement;\n\n/**\n * Test response.\n *\n * @author Daniil Razorenov\n */\n@XmlRootElement(name = \"response\")\nclass Response {\n\n\t@XmlElement(required = true)\n\tprivate int code;\n\n\tResponse(int code) {\n\t\tthis.code = code;\n\t}\n\n\tResponse() {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/WebServiceServerIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.ws.test.server.MockWebServiceClient;\nimport org.springframework.ws.test.server.RequestCreators;\nimport org.springframework.ws.test.server.ResponseMatchers;\nimport org.springframework.xml.transform.StringSource;\n\n/**\n * Tests for {@link WebServiceServerTest @WebServiceServerTest}.\n *\n * @author Daniil Razorenov\n */\n@WebServiceServerTest(endpoints = ExampleWebServiceEndpoint.class)\nclass WebServiceServerIntegrationTests {\n\n\t@Autowired\n\tprivate MockWebServiceClient mock;\n\n\t@Test\n\tvoid payloadRootMethod() {\n\t\tthis.mock\n\t\t\t.sendRequest(RequestCreators.withPayload(new StringSource(\"<request><message>Hello</message></request>\")))\n\t\t\t.andExpect(ResponseMatchers.payload(new StringSource(\"<response><code>42</code></response>\")));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/WebServiceServerPropertiesIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.env.Environment;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the {@link WebServiceServerTest#properties properties} attribute of\n * {@link WebServiceServerTest @WebServiceServerTest}.\n *\n * @author Daniil Razorenov\n */\n@WebServiceServerTest(properties = \"spring.profiles.active=test\")\nclass WebServiceServerPropertiesIntegrationTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid environmentWithNewProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"test\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Autowired\n\t\tprivate Environment innerEnvironment;\n\n\t\t@Test\n\t\tvoid propertiesFromEnclosingClassAffectNestedTests() {\n\t\t\tassertThat(WebServiceServerPropertiesIntegrationTests.this.environment.getActiveProfiles())\n\t\t\t\t.containsExactly(\"test\");\n\t\t\tassertThat(this.innerEnvironment.getActiveProfiles()).containsExactly(\"test\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webservices-test/src/test/java/org/springframework/boot/webservices/test/autoconfigure/server/WebServiceServerTypeExcludeFilterTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webservices.test.autoconfigure.server;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.annotation.ComponentScan.Filter;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.core.type.classreading.SimpleMetadataReaderFactory;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.stereotype.Service;\nimport org.springframework.ws.server.endpoint.annotation.Endpoint;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WebServiceServerTypeExcludeFilter}.\n *\n * @author Daniil Razorenov\n */\nclass WebServiceServerTypeExcludeFilterTests {\n\n\tprivate final MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();\n\n\t@Test\n\tvoid matchWhenHasNoEndpoints() throws IOException {\n\t\tWebServiceServerTypeExcludeFilter filter = new WebServiceServerTypeExcludeFilter(WithNoEndpoints.class);\n\t\tassertThat(exclude(filter, WebService1.class)).isFalse();\n\t\tassertThat(exclude(filter, WebService2.class)).isFalse();\n\t\tassertThat(exclude(filter, ExampleService.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleRepository.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWhenHasEndpoint() throws IOException {\n\t\tWebServiceServerTypeExcludeFilter filter = new WebServiceServerTypeExcludeFilter(WithEndpoint.class);\n\t\tassertThat(exclude(filter, WebService1.class)).isFalse();\n\t\tassertThat(exclude(filter, WebService2.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleService.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleRepository.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchNotUsingDefaultFilters() throws IOException {\n\t\tWebServiceServerTypeExcludeFilter filter = new WebServiceServerTypeExcludeFilter(NotUsingDefaultFilters.class);\n\t\tassertThat(exclude(filter, WebService1.class)).isTrue();\n\t\tassertThat(exclude(filter, WebService2.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleService.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleRepository.class)).isTrue();\n\t}\n\n\t@Test\n\tvoid matchWithIncludeFilter() throws IOException {\n\t\tWebServiceServerTypeExcludeFilter filter = new WebServiceServerTypeExcludeFilter(WithIncludeFilter.class);\n\t\tassertThat(exclude(filter, WebService1.class)).isFalse();\n\t\tassertThat(exclude(filter, WebService2.class)).isFalse();\n\t\tassertThat(exclude(filter, ExampleService.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleRepository.class)).isFalse();\n\t}\n\n\t@Test\n\tvoid matchWithExcludeFilter() throws IOException {\n\t\tWebServiceServerTypeExcludeFilter filter = new WebServiceServerTypeExcludeFilter(WithExcludeFilter.class);\n\t\tassertThat(exclude(filter, WebService1.class)).isTrue();\n\t\tassertThat(exclude(filter, WebService2.class)).isFalse();\n\t\tassertThat(exclude(filter, ExampleService.class)).isTrue();\n\t\tassertThat(exclude(filter, ExampleRepository.class)).isTrue();\n\t}\n\n\tprivate boolean exclude(WebServiceServerTypeExcludeFilter filter, Class<?> type) throws IOException {\n\t\tMetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());\n\t\treturn filter.match(metadataReader, this.metadataReaderFactory);\n\t}\n\n\t@WebServiceServerTest\n\tstatic class WithNoEndpoints {\n\n\t}\n\n\t@WebServiceServerTest(WebService1.class)\n\tstatic class WithEndpoint {\n\n\t}\n\n\t@WebServiceServerTest(useDefaultFilters = false)\n\tstatic class NotUsingDefaultFilters {\n\n\t}\n\n\t@WebServiceServerTest(includeFilters = @Filter(Repository.class))\n\tstatic class WithIncludeFilter {\n\n\t}\n\n\t@WebServiceServerTest(excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = WebService1.class))\n\tstatic class WithExcludeFilter {\n\n\t}\n\n\t@Endpoint\n\tstatic class WebService1 {\n\n\t}\n\n\t@Endpoint\n\tstatic class WebService2 {\n\n\t}\n\n\t@Service\n\tstatic class ExampleService {\n\n\t}\n\n\t@Repository\n\tstatic class ExampleRepository {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-websocket/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot WebSocket\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"org.springframework:spring-messaging\")\n\tapi(\"org.springframework:spring-websocket\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":module:spring-boot-jackson\"))\n\toptional(project(\":module:spring-boot-jackson2\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":module:spring-boot-tomcat\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(project(\":module:spring-boot-webmvc\"))\n\ttestImplementation(\"org.apache.tomcat.embed:tomcat-embed-websocket\")\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"test\") {\n\tjvmArgs += \"--add-opens=java.base/java.net=ALL-UNNAMED\"\n}\n"
  },
  {
    "path": "module/spring-boot-websocket/src/main/java/org/springframework/boot/websocket/autoconfigure/servlet/WebSocketMessagingAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.websocket.autoconfigure.servlet;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.jspecify.annotations.Nullable;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.LazyInitializationExcludeFilter;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.AnyNestedCondition;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;\nimport org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.messaging.converter.ByteArrayMessageConverter;\nimport org.springframework.messaging.converter.DefaultContentTypeResolver;\nimport org.springframework.messaging.converter.JacksonJsonMessageConverter;\nimport org.springframework.messaging.converter.MessageConverter;\nimport org.springframework.messaging.converter.StringMessageConverter;\nimport org.springframework.messaging.simp.config.ChannelRegistration;\nimport org.springframework.util.MimeTypeUtils;\nimport org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration;\nimport org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for WebSocket-based messaging.\n *\n * @author Andy Wilkinson\n * @author Lasse Wulff\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@AutoConfiguration(afterName = { \"org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration\",\n\t\t\"org.springframework.boot.jackson2.autoconfigure.Jackson2AutoConfiguration\" })\n@ConditionalOnWebApplication(type = Type.SERVLET)\n@ConditionalOnClass({ WebSocketMessageBrokerConfigurer.class, DelegatingWebSocketMessageBrokerConfiguration.class })\n@ConditionalOnBean(DelegatingWebSocketMessageBrokerConfiguration.class)\npublic final class WebSocketMessagingAutoConfiguration {\n\n\t@Bean\n\tstatic LazyInitializationExcludeFilter eagerStompWebSocketHandlerMapping() {\n\t\treturn (name, definition, type) -> name.equals(\"stompWebSocketHandlerMapping\");\n\t}\n\n\t@Bean\n\tSpringBootWebSocketMessageBrokerConfigurer springBootWebSocketMessageBrokerConfigurer(\n\t\t\tMap<String, AsyncTaskExecutor> taskExecutors) {\n\t\treturn new SpringBootWebSocketMessageBrokerConfigurer(taskExecutors);\n\t}\n\n\t@Order(1)\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnProperty(name = \"spring.websocket.messaging.preferred-json-mapper\", havingValue = \"jackson\",\n\t\t\tmatchIfMissing = true)\n\t@ConditionalOnBean(JsonMapper.class)\n\t@ConditionalOnClass(JsonMapper.class)\n\tstatic class JacksonWebSocketMessageConverterConfiguration implements WebSocketMessageBrokerConfigurer {\n\n\t\tprivate final JsonMapper jsonMapper;\n\n\t\tJacksonWebSocketMessageConverterConfiguration(JsonMapper jsonMapper) {\n\t\t\tthis.jsonMapper = jsonMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean configureMessageConverters(List<MessageConverter> messageConverters) {\n\t\t\tJacksonJsonMessageConverter converter = new JacksonJsonMessageConverter(this.jsonMapper);\n\t\t\tDefaultContentTypeResolver resolver = new DefaultContentTypeResolver();\n\t\t\tresolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);\n\t\t\tconverter.setContentTypeResolver(resolver);\n\t\t\tmessageConverters.add(converter);\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\t@Order(1)\n\t@Configuration(proxyBeanMethods = false)\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\t@Conditional(NoJacksonOrJackson2Preferred.class)\n\t@ConditionalOnBean(ObjectMapper.class)\n\t@ConditionalOnClass(ObjectMapper.class)\n\tstatic class Jackson2WebSocketMessageConverterConfiguration implements WebSocketMessageBrokerConfigurer {\n\n\t\tprivate final ObjectMapper objectMapper;\n\n\t\tJackson2WebSocketMessageConverterConfiguration(ObjectMapper objectMapper) {\n\t\t\tthis.objectMapper = objectMapper;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean configureMessageConverters(List<MessageConverter> messageConverters) {\n\t\t\torg.springframework.messaging.converter.MappingJackson2MessageConverter converter = new org.springframework.messaging.converter.MappingJackson2MessageConverter(\n\t\t\t\t\tthis.objectMapper);\n\t\t\tDefaultContentTypeResolver resolver = new DefaultContentTypeResolver();\n\t\t\tresolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);\n\t\t\tconverter.setContentTypeResolver(resolver);\n\t\t\tmessageConverters.add(converter);\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n\tstatic class NoJacksonOrJackson2Preferred extends AnyNestedCondition {\n\n\t\tNoJacksonOrJackson2Preferred() {\n\t\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t\t}\n\n\t\t@ConditionalOnMissingClass(\"tools.jackson.databind.json.JsonMapper\")\n\t\tstatic class NoJackson {\n\n\t\t}\n\n\t\t@ConditionalOnProperty(name = \"spring.websocket.messaging.preferred-json-mapper\", havingValue = \"jackson2\")\n\t\tstatic class Jackson2Preferred {\n\n\t\t}\n\n\t}\n\n\tstatic class SpringBootWebSocketMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer, Ordered {\n\n\t\tprivate final @Nullable AsyncTaskExecutor executor;\n\n\t\tSpringBootWebSocketMessageBrokerConfigurer(Map<String, AsyncTaskExecutor> taskExecutors) {\n\t\t\tthis.executor = determineAsyncTaskExecutor(taskExecutors);\n\t\t}\n\n\t\tprivate static @Nullable AsyncTaskExecutor determineAsyncTaskExecutor(\n\t\t\t\tMap<String, AsyncTaskExecutor> taskExecutors) {\n\t\t\tif (taskExecutors.size() == 1) {\n\t\t\t\treturn taskExecutors.values().iterator().next();\n\t\t\t}\n\t\t\treturn taskExecutors.get(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME);\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean configureMessageConverters(List<MessageConverter> messageConverters) {\n\t\t\tmessageConverters.add(new StringMessageConverter());\n\t\t\tmessageConverters.add(new ByteArrayMessageConverter());\n\t\t\treturn false;\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureClientInboundChannel(ChannelRegistration registration) {\n\t\t\tif (this.executor != null) {\n\t\t\t\tregistration.executor(this.executor);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureClientOutboundChannel(ChannelRegistration registration) {\n\t\t\tif (this.executor != null) {\n\t\t\t\tregistration.executor(this.executor);\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic int getOrder() {\n\t\t\treturn 0;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-websocket/src/main/java/org/springframework/boot/websocket/autoconfigure/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for WebSocket support in servlet web servers.\n */\n@NullMarked\npackage org.springframework.boot.websocket.autoconfigure.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-websocket/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"properties\": [\n    {\n      \"name\": \"spring.websocket.messaging.preferred-json-mapper\",\n      \"type\": \"java.lang.String\",\n      \"defaultValue\": \"jackson\",\n      \"description\": \"Preferred JSON mapper to use for WebSocket messaging. By default, auto-detected according to the environment. Supported values are 'jackson' and 'jackson2' (deprecated).\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"spring.websocket.messaging.preferred-json-mapper\",\n      \"values\": [\n        {\n          \"value\": \"jackson\"\n        },\n        {\n          \"value\": \"jackson2\"\n        }\n      ],\n      \"providers\": [\n        {\n          \"name\": \"any\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "module/spring-boot-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.websocket.autoconfigure.servlet.WebSocketMessagingAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-websocket/src/test/java/org/springframework/boot/websocket/autoconfigure/servlet/WebSocketMessagingAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.websocket.autoconfigure.servlet;\n\nimport java.lang.reflect.Type;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.apache.tomcat.websocket.WsWebSocketContainer;\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.skyscreamer.jsonassert.JSONAssert;\n\nimport org.springframework.boot.LazyInitializationBeanFactoryPostProcessor;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;\nimport org.springframework.boot.tomcat.autoconfigure.WebSocketTomcatWebServerFactoryCustomizer;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.WebServer;\nimport org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.websocket.autoconfigure.servlet.WebSocketMessagingAutoConfiguration.JacksonWebSocketMessageConverterConfiguration;\nimport org.springframework.boot.websocket.autoconfigure.servlet.WebSocketMessagingAutoConfiguration.SpringBootWebSocketMessageBrokerConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.task.AsyncTaskExecutor;\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.messaging.converter.CompositeMessageConverter;\nimport org.springframework.messaging.converter.MessageConverter;\nimport org.springframework.messaging.converter.SimpleMessageConverter;\nimport org.springframework.messaging.simp.annotation.SubscribeMapping;\nimport org.springframework.messaging.simp.config.MessageBrokerRegistry;\nimport org.springframework.messaging.simp.stomp.StompCommand;\nimport org.springframework.messaging.simp.stomp.StompFrameHandler;\nimport org.springframework.messaging.simp.stomp.StompHeaders;\nimport org.springframework.messaging.simp.stomp.StompSession;\nimport org.springframework.messaging.simp.stomp.StompSessionHandler;\nimport org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;\nimport org.springframework.stereotype.Component;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.client.RestTemplate;\nimport org.springframework.web.socket.client.standard.StandardWebSocketClient;\nimport org.springframework.web.socket.config.annotation.DelegatingWebSocketMessageBrokerConfiguration;\nimport org.springframework.web.socket.config.annotation.EnableWebSocket;\nimport org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;\nimport org.springframework.web.socket.config.annotation.StompEndpointRegistry;\nimport org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;\nimport org.springframework.web.socket.messaging.WebSocketStompClient;\nimport org.springframework.web.socket.sockjs.client.RestTemplateXhrTransport;\nimport org.springframework.web.socket.sockjs.client.SockJsClient;\nimport org.springframework.web.socket.sockjs.client.Transport;\nimport org.springframework.web.socket.sockjs.client.WebSocketTransport;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link WebSocketMessagingAutoConfiguration}.\n *\n * @author Andy Wilkinson\n * @author Lasse Wulff\n */\n@DirtiesUrlFactories\nclass WebSocketMessagingAutoConfigurationTests {\n\n\tprivate final AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext();\n\n\tprivate SockJsClient sockJsClient;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tList<Transport> transports = Arrays.asList(\n\t\t\t\tnew WebSocketTransport(new StandardWebSocketClient(new WsWebSocketContainer())),\n\t\t\t\tnew RestTemplateXhrTransport(new RestTemplate()));\n\t\tthis.sockJsClient = new SockJsClient(transports);\n\t}\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.context.isActive()) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tthis.sockJsClient.stop();\n\t}\n\n\t@Test\n\tvoid basicMessagingWithJsonResponse() throws Throwable {\n\t\tthis.context.register(JacksonAutoConfiguration.class);\n\t\tObject result = performStompSubscription(\"/app/json\");\n\t\tJSONAssert.assertEquals(\"{\\\"foo\\\" : 5,\\\"bar\\\" : \\\"baz\\\"}\", new String((byte[]) result), true);\n\t}\n\n\t@Test\n\tvoid basicMessagingWithStringResponse() throws Throwable {\n\t\tObject result = performStompSubscription(\"/app/string\");\n\t\tassertThat(new String((byte[]) result)).isEqualTo(\"string data\");\n\t}\n\n\t@Test\n\tvoid whenLazyInitializationIsEnabledThenBasicMessagingWorks() throws Throwable {\n\t\tthis.context.register(LazyInitializationBeanFactoryPostProcessor.class);\n\t\tObject result = performStompSubscription(\"/app/string\");\n\t\tassertThat(new String((byte[]) result)).isEqualTo(\"string data\");\n\t}\n\n\t@Test\n\tvoid customizedConverterTypesMatchDefaultConverterTypes() {\n\t\tthis.context.register(WebSocketMessagingConfiguration.class, JacksonAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tList<MessageConverter> customizedConverters = getConverters(\n\t\t\t\tthis.context.getBean(DelegatingWebSocketMessageBrokerConfiguration.class));\n\t\tList<MessageConverter> defaultConverters = getDefaultConverters();\n\t\tassertThat(customizedConverters).hasSameSizeAs(defaultConverters);\n\t\tIterator<MessageConverter> customizedIterator = customizedConverters.iterator();\n\t\tIterator<MessageConverter> defaultIterator = defaultConverters.iterator();\n\t\twhile (customizedIterator.hasNext()) {\n\t\t\tassertThat(customizedIterator.next()).isInstanceOf(defaultIterator.next().getClass());\n\t\t}\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorBeanIsSelectedForInboundChannel() {\n\t\tAsyncTaskExecutor expectedExecutor = new SimpleAsyncTaskExecutor();\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.registerBean(AsyncTaskExecutor.class, () -> expectedExecutor);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(\"clientInboundChannelExecutor\", Executor.class)).isSameAs(expectedExecutor);\n\t}\n\n\t@Test\n\tvoid asyncTaskExecutorBeanIsSelectedForOutboundChannel() {\n\t\tAsyncTaskExecutor expectedExecutor = new SimpleAsyncTaskExecutor();\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.registerBean(AsyncTaskExecutor.class, () -> expectedExecutor);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(\"clientOutboundChannelExecutor\", Executor.class)).isSameAs(expectedExecutor);\n\t}\n\n\t@Test\n\tvoid withMultipleAsyncTaskExecutorBeansApplicationTaskExecutorIsSelectedForInboundChannel() {\n\t\tAsyncTaskExecutor applicationTaskExecutor = new SimpleAsyncTaskExecutor();\n\t\tAsyncTaskExecutor additionalTaskExecutor = new SimpleAsyncTaskExecutor();\n\t\tthis.context.registerBean(\"applicationTaskExecutor\", AsyncTaskExecutor.class, () -> applicationTaskExecutor);\n\t\tthis.context.registerBean(AsyncTaskExecutor.class, () -> additionalTaskExecutor);\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(\"clientInboundChannelExecutor\", Executor.class))\n\t\t\t.isSameAs(applicationTaskExecutor);\n\t}\n\n\t@Test\n\tvoid withMultipleAsyncTaskExecutorBeansApplicationTaskExecutorIsSelectedForOutboundChannel() {\n\t\tAsyncTaskExecutor applicationTaskExecutor = new SimpleAsyncTaskExecutor();\n\t\tAsyncTaskExecutor additionalTaskExecutor = new SimpleAsyncTaskExecutor();\n\t\tthis.context.registerBean(\"applicationTaskExecutor\", AsyncTaskExecutor.class, () -> applicationTaskExecutor);\n\t\tthis.context.registerBean(AsyncTaskExecutor.class, () -> additionalTaskExecutor);\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBean(\"clientOutboundChannelExecutor\", Executor.class))\n\t\t\t.isSameAs(applicationTaskExecutor);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid webSocketMessageBrokerConfigurerOrdering() throws Throwable {\n\t\tTestPropertyValues.of(\"server.port:0\").applyTo(this.context);\n\t\tthis.context.register(WebSocketMessagingConfiguration.class, CustomLowWebSocketMessageBrokerConfigurer.class,\n\t\t\t\tCustomHighWebSocketMessageBrokerConfigurer.class, JacksonAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tDelegatingWebSocketMessageBrokerConfiguration delegatingConfiguration = this.context\n\t\t\t.getBean(DelegatingWebSocketMessageBrokerConfiguration.class);\n\t\tassertThat(delegatingConfiguration).extracting(\"configurers\")\n\t\t\t.asInstanceOf(InstanceOfAssertFactories.LIST)\n\t\t\t.satisfies((configurers) -> {\n\t\t\t\tassertThat(configurers).hasSize(5);\n\t\t\t\tassertThat(configurers).first().isInstanceOf(CustomHighWebSocketMessageBrokerConfigurer.class);\n\t\t\t\tassertThat(configurers.get(1)).isInstanceOf(SpringBootWebSocketMessageBrokerConfigurer.class);\n\t\t\t\tassertThat(configurers.get(2)).isInstanceOf(JacksonWebSocketMessageConverterConfiguration.class);\n\t\t\t\tassertThat((List<Object>) configurers.subList(3, 5)).contains(\n\t\t\t\t\t\tthis.context.getBean(WebSocketMessagingConfiguration.class),\n\t\t\t\t\t\tthis.context.getBean(CustomLowWebSocketMessageBrokerConfigurer.class));\n\t\t\t});\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\tvoid shouldUseJackson2WhenPreferred() {\n\t\tTestPropertyValues.of(\"server.port:0\", \"spring.websocket.messaging.preferred-json-mapper=jackson2\")\n\t\t\t.applyTo(this.context);\n\t\tthis.context.register(WebSocketMessagingConfiguration.class, CustomLowWebSocketMessageBrokerConfigurer.class,\n\t\t\t\tCustomHighWebSocketMessageBrokerConfigurer.class);\n\t\tthis.context.registerBean(ObjectMapper.class);\n\t\tthis.context.refresh();\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context)).hasSingleBean(\n\t\t\t\torg.springframework.boot.websocket.autoconfigure.servlet.WebSocketMessagingAutoConfiguration.Jackson2WebSocketMessageConverterConfiguration.class)\n\t\t\t.doesNotHaveBean(JacksonWebSocketMessageConverterConfiguration.class);\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.0\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\t@ClassPathExclusions(\"jackson-*-3*\")\n\tvoid shouldUseJackson2WhenJacksonIsMissing() {\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.registerBean(ObjectMapper.class);\n\t\tthis.context.refresh();\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context))\n\t\t\t.hasSingleBean(WebSocketMessagingAutoConfiguration.Jackson2WebSocketMessageConverterConfiguration.class)\n\t\t\t.doesNotHaveBean(JacksonWebSocketMessageConverterConfiguration.class);\n\t}\n\n\t@Test\n\t@Deprecated(since = \"4.0.4\", forRemoval = true)\n\t@SuppressWarnings(\"removal\")\n\t@ClassPathExclusions(\"jackson-*-3*\")\n\tvoid jackson2ConfigurationShouldBackOffWhenThereIsNoObjectMapperBean() {\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context))\n\t\t\t.doesNotHaveBean(WebSocketMessagingAutoConfiguration.Jackson2WebSocketMessageConverterConfiguration.class)\n\t\t\t.doesNotHaveBean(JacksonWebSocketMessageConverterConfiguration.class);\n\t}\n\n\t@Test\n\tvoid jacksonConfigurationShouldBackOffWhenThereIsNoJsonMapperBean() {\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(AssertableApplicationContext.get(() -> this.context))\n\t\t\t.doesNotHaveBean(JacksonWebSocketMessageConverterConfiguration.class);\n\t}\n\n\tprivate List<MessageConverter> getDefaultConverters() {\n\t\treturn getConverters(new DelegatingWebSocketMessageBrokerConfiguration());\n\t}\n\n\tprivate List<MessageConverter> getConverters(DelegatingWebSocketMessageBrokerConfiguration configuration) {\n\t\tCompositeMessageConverter compositeDefaultConverter = configuration.brokerMessageConverter();\n\t\treturn compositeDefaultConverter.getConverters();\n\t}\n\n\tprivate @Nullable Object performStompSubscription(String topic) throws Throwable {\n\t\tTestPropertyValues.of(\"server.port:0\").applyTo(this.context);\n\t\tthis.context.register(WebSocketMessagingConfiguration.class);\n\t\tthis.context.refresh();\n\t\tWebSocketStompClient stompClient = new WebSocketStompClient(this.sockJsClient);\n\t\tfinal AtomicReference<Throwable> failure = new AtomicReference<>();\n\t\tfinal AtomicReference<Object> result = new AtomicReference<>();\n\t\tfinal CountDownLatch latch = new CountDownLatch(1);\n\t\tStompSessionHandler handler = new StompSessionHandlerAdapter() {\n\n\t\t\t@Override\n\t\t\tpublic void afterConnected(StompSession session, StompHeaders connectedHeaders) {\n\t\t\t\tsession.subscribe(topic, new StompFrameHandler() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void handleFrame(StompHeaders headers, @Nullable Object payload) {\n\t\t\t\t\t\tassertThat(payload).isNotNull();\n\t\t\t\t\t\tresult.set(payload);\n\t\t\t\t\t\tlatch.countDown();\n\t\t\t\t\t}\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Type getPayloadType(StompHeaders headers) {\n\t\t\t\t\t\treturn Object.class;\n\t\t\t\t\t}\n\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void handleFrame(StompHeaders headers, @Nullable Object payload) {\n\t\t\t\tlatch.countDown();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void handleException(StompSession session, @Nullable StompCommand command, StompHeaders headers,\n\t\t\t\t\tbyte[] payload, Throwable exception) {\n\t\t\t\tfailure.set(exception);\n\t\t\t\tlatch.countDown();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void handleTransportError(StompSession session, Throwable exception) {\n\t\t\t\tfailure.set(exception);\n\t\t\t\tlatch.countDown();\n\t\t\t}\n\n\t\t};\n\n\t\tstompClient.setMessageConverter(new SimpleMessageConverter());\n\t\tWebServer webServer = this.context.getWebServer();\n\t\tassertThat(webServer).isNotNull();\n\t\tstompClient.connectAsync(\"ws://localhost:{port}/messaging\", handler, webServer.getPort());\n\n\t\tif (!latch.await(30, TimeUnit.SECONDS)) {\n\t\t\tif (failure.get() != null) {\n\t\t\t\tthrow failure.get();\n\t\t\t}\n\t\t\tfail(\"Response was not received within 30 seconds\");\n\t\t}\n\t\treturn result.get();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableWebSocket\n\t@EnableConfigurationProperties\n\t@EnableWebSocketMessageBroker\n\t@ImportAutoConfiguration({ TomcatServletWebServerAutoConfiguration.class, WebSocketMessagingAutoConfiguration.class,\n\t\t\tDispatcherServletAutoConfiguration.class })\n\tstatic class WebSocketMessagingConfiguration implements WebSocketMessageBrokerConfigurer {\n\n\t\t@Override\n\t\tpublic void registerStompEndpoints(StompEndpointRegistry registry) {\n\n\t\t\tregistry.addEndpoint(\"/messaging\").withSockJS();\n\t\t}\n\n\t\t@Override\n\t\tpublic void configureMessageBroker(MessageBrokerRegistry registry) {\n\t\t\tregistry.setApplicationDestinationPrefixes(\"/app\");\n\t\t}\n\n\t\t@Bean\n\t\tMessagingController messagingController() {\n\t\t\treturn new MessagingController();\n\t\t}\n\n\t\t@Bean\n\t\tTomcatServletWebServerFactory tomcat() {\n\t\t\treturn new TomcatServletWebServerFactory(0);\n\t\t}\n\n\t\t@Bean\n\t\tWebSocketTomcatWebServerFactoryCustomizer tomcatCustomizer() {\n\t\t\treturn new WebSocketTomcatWebServerFactoryCustomizer();\n\t\t}\n\n\t}\n\n\t@Component\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\tstatic class CustomHighWebSocketMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer {\n\n\t}\n\n\t@Component\n\t@Order(Ordered.LOWEST_PRECEDENCE)\n\tstatic class CustomLowWebSocketMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer {\n\n\t}\n\n\t@Controller\n\tstatic class MessagingController {\n\n\t\t@SubscribeMapping(\"/json\")\n\t\tData json() {\n\t\t\treturn new Data(5, \"baz\");\n\t\t}\n\n\t\t@SubscribeMapping(\"/string\")\n\t\tString string() {\n\t\t\treturn \"string data\";\n\t\t}\n\n\t}\n\n\tpublic static class Data {\n\n\t\tprivate final int foo;\n\n\t\tprivate final String bar;\n\n\t\tData(int foo, String bar) {\n\t\t\tthis.foo = foo;\n\t\t\tthis.bar = bar;\n\t\t}\n\n\t\tpublic int getFoo() {\n\t\t\treturn this.foo;\n\t\t}\n\n\t\tpublic String getBar() {\n\t\t\treturn this.bar;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n\tid \"org.springframework.boot.test-auto-configuration\"\n}\n\ndescription = \"Spring Boot WebTestClient\"\n\ndependencies {\n\tapi(project(\":core:spring-boot-test\"))\n\tapi(project(\":module:spring-boot-http-codec\"))\n\tapi(\"org.springframework:spring-webflux\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-autoconfigure\")))\n\n\ttestRuntimeOnly(\"ch.qos.logback:logback-classic\")\n\ttestRuntimeOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestRuntimeOnly(\"org.springframework:spring-webmvc\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/autoconfigure/AutoConfigureWebTestClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.time.Duration;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.PropertyMapping;\nimport org.springframework.boot.test.context.PropertyMapping.Skip;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Annotation that can be applied to a test class to enable a {@link WebTestClient}.\n *\n * @author Stephane Nicoll\n * @author Jay Choi\n * @since 4.0.0\n * @see WebTestClientAutoConfiguration\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@ImportAutoConfiguration\n@PropertyMapping(\"spring.test.webtestclient\")\npublic @interface AutoConfigureWebTestClient {\n\n\t/**\n\t * The timeout duration for the client (in any format handled by\n\t * {@link Duration#parse(CharSequence)}).\n\t * @return the web client timeout\n\t */\n\t@PropertyMapping(skip = Skip.ON_DEFAULT_VALUE)\n\tString timeout() default \"\";\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/autoconfigure/SpringBootWebTestClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport java.time.Duration;\nimport java.util.Collection;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.http.codec.ClientCodecConfigurer;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient.Builder;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.web.reactive.function.client.ExchangeStrategies;\n\n/**\n * {@link WebTestClientBuilderCustomizer} for a typical Spring Boot application. Usually\n * applied automatically via\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient}, but may also be used\n * directly.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\npublic class SpringBootWebTestClientBuilderCustomizer implements WebTestClientBuilderCustomizer {\n\n\tprivate final Collection<CodecCustomizer> codecCustomizers;\n\n\tprivate @Nullable Duration timeout;\n\n\t/**\n\t * Create a new {@code SpringBootWebTestClientBuilderCustomizer} that will configure\n\t * the builder's codecs using the given {@code codecCustomizers}.\n\t * @param codecCustomizers the codec customizers\n\t */\n\tpublic SpringBootWebTestClientBuilderCustomizer(Collection<CodecCustomizer> codecCustomizers) {\n\t\tthis.codecCustomizers = codecCustomizers;\n\t}\n\n\tpublic void setTimeout(@Nullable Duration timeout) {\n\t\tthis.timeout = timeout;\n\t}\n\n\t@Override\n\tpublic void customize(Builder builder) {\n\t\tif (this.timeout != null) {\n\t\t\tbuilder.responseTimeout(this.timeout);\n\t\t}\n\t\tcustomizeWebTestClientCodecs(builder);\n\t}\n\n\tprivate void customizeWebTestClientCodecs(WebTestClient.Builder builder) {\n\t\tif (!CollectionUtils.isEmpty(this.codecCustomizers)) {\n\t\t\tbuilder.exchangeStrategies(\n\t\t\t\t\tExchangeStrategies.builder().codecs(applyCustomizers(this.codecCustomizers)).build());\n\t\t}\n\t}\n\n\tprivate Consumer<ClientCodecConfigurer> applyCustomizers(Collection<CodecCustomizer> customizers) {\n\t\treturn (codecs) -> customizers.forEach((customizer) -> customizer.customize(codecs));\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/autoconfigure/WebTestClientAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.web.reactive.server.MockServerConfigurer;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient.MockServerSpec;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.client.MockMvcWebTestClient;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.reactive.function.client.WebClient;\nimport org.springframework.web.server.adapter.WebHttpHandlerBuilder;\n\n/**\n * Auto-configuration for {@link WebTestClient}.\n *\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @since 4.0.0\n */\n@AutoConfiguration(after = CodecsAutoConfiguration.class)\n@ConditionalOnClass({ CodecCustomizer.class, WebClient.class, WebTestClient.class })\n@EnableConfigurationProperties\npublic final class WebTestClientAutoConfiguration {\n\n\tprivate static final String WEB_APPLICATION_CONTEXT_CLASS = \"org.springframework.web.context.WebApplicationContext\";\n\n\t@Bean\n\t@ConfigurationProperties(\"spring.test.webtestclient\")\n\tSpringBootWebTestClientBuilderCustomizer springBootWebTestClientBuilderCustomizer(\n\t\t\tObjectProvider<CodecCustomizer> codecCustomizers) {\n\t\treturn new SpringBootWebTestClientBuilderCustomizer(codecCustomizers.orderedStream().toList());\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tWebTestClient webTestClient(ApplicationContext applicationContext, List<WebTestClientBuilderCustomizer> customizers,\n\t\t\tList<MockServerConfigurer> configurers) {\n\t\tWebTestClient.Builder builder = getBuilder(applicationContext, configurers);\n\t\tcustomizers.forEach((customizer) -> customizer.customize(builder));\n\t\treturn builder.build();\n\t}\n\n\tprivate WebTestClient.Builder getBuilder(ApplicationContext applicationContext,\n\t\t\tList<MockServerConfigurer> configurers) {\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.get(applicationContext);\n\t\tif (localTestWebServer != null) {\n\t\t\treturn WebTestClient.bindToServer().uriBuilderFactory(localTestWebServer.uriBuilderFactory());\n\t\t}\n\t\tif (applicationContext.containsBean(WebHttpHandlerBuilder.WEB_HANDLER_BEAN_NAME)) {\n\t\t\tMockServerSpec<?> spec = WebTestClient.bindToApplicationContext(applicationContext);\n\t\t\tconfigurers.forEach(spec::apply);\n\t\t\treturn spec.configureClient();\n\t\t}\n\t\tif (ClassUtils.isPresent(WEB_APPLICATION_CONTEXT_CLASS, applicationContext.getClassLoader())) {\n\t\t\tMockMvc mockMvc = applicationContext.getBeanProvider(MockMvc.class).getIfUnique();\n\t\t\tif (mockMvc != null) {\n\t\t\t\treturn MockMvcWebTestClient.bindTo(mockMvc);\n\t\t\t}\n\t\t\tif (applicationContext instanceof WebApplicationContext webApplicationContext) {\n\t\t\t\treturn MockMvcWebTestClient.bindToApplicationContext(webApplicationContext).configureClient();\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Mock WebTestClient support requires a WebHandler (named 'webHandler') bean or a WebApplicationContext and neither was present\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/autoconfigure/WebTestClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient.Builder;\n\n/**\n * A customizer that can be implemented by beans wishing to customize the {@link Builder\n * WebTestClient.Builder} to fine-tune its auto-configuration before a\n * {@link WebTestClient} is created.\n *\n * @author Andy Wilkinson\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface WebTestClientBuilderCustomizer {\n\n\t/**\n\t * Customize the given {@code builder}.\n\t * @param builder the builder\n\t */\n\tvoid customize(WebTestClient.Builder builder);\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for WebTestClient.\n */\n@NullMarked\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/main/resources/META-INF/spring/org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient.imports",
    "content": "org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration\norg.springframework.boot.webtestclient.autoconfigure.WebTestClientAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/AutoConfigureWebTestClientIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.boot.autoconfigure.AutoConfigurationImportedCondition.importedAutoConfiguration;\n\n/**\n * Integration tests for {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureWebTestClient\nclass AutoConfigureWebTestClientIntegrationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid codecsAutoConfigurationIsImported() {\n\t\tassertThat(this.applicationContext).has(importedAutoConfiguration(CodecsAutoConfiguration.class));\n\t}\n\n\t@SpringBootConfiguration\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/ExampleController1.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with tests.\n *\n * @author Stephane Nicoll\n */\n@RestController\npublic class ExampleController1 {\n\n\t@GetMapping(\"/one\")\n\tpublic Mono<String> one() {\n\t\treturn Mono.just(\"one\");\n\t}\n\n\t@GetMapping(\"/one/error\")\n\tpublic Mono<String> error() {\n\t\tthrow new RuntimeException(\"foo\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/ExampleController2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Example {@link Controller @Controller} used with tests.\n *\n * @author Stephane Nicoll\n */\n@RestController\npublic class ExampleController2 {\n\n\t@GetMapping(\"/two\")\n\tpublic Mono<String> two() {\n\t\treturn Mono.just(\"two\");\n\t}\n\n\t@GetMapping(\"/two/{id}\")\n\tpublic Mono<String> two(@PathVariable ExampleId id) {\n\t\treturn Mono.just(id.getId() + \"two\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/ExampleId.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport java.util.UUID;\n\nimport org.springframework.core.convert.converter.Converter;\n\n/**\n * An example attribute that requires a {@link Converter}.\n *\n * @author Stephane Nicoll\n */\npublic class ExampleId {\n\n\tprivate final UUID id;\n\n\tExampleId(UUID id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic UUID getId() {\n\t\treturn this.id;\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/ExampleRealService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport org.springframework.stereotype.Service;\n\n/**\n * Example {@link Service @Service} used with\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient} tests.\n *\n * @author Stephane Nicoll\n */\n@Service\npublic class ExampleRealService {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/ExampleWebTestClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Example {@link SpringBootApplication @SpringBootApplication} used with\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient} tests.\n *\n * @author Stephane Nicoll\n */\n@SpringBootApplication\npublic class ExampleWebTestClientApplication {\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/WebTestClientAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.http.codec.CodecCustomizer;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;\nimport org.springframework.boot.testsupport.classpath.resources.WithResource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.client.reactive.JdkClientHttpConnector;\nimport org.springframework.http.codec.CodecConfigurer;\nimport org.springframework.test.web.reactive.server.HttpHandlerConnector;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.client.MockMvcHttpConnector;\nimport org.springframework.web.context.WebApplicationContext;\nimport org.springframework.web.server.WebHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.BDDMockito.then;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link WebTestClientAutoConfiguration}\n *\n * @author Brian Clozel\n * @author Stephane Nicoll\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass WebTestClientAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldDefineWebTestClientBoundToHttpHandler() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(WebTestClient.class);\n\t\t\tassertThat(context).hasBean(\"webTestClient\");\n\t\t\tassertThat(context.getBean(WebTestClient.class)).extracting(\"wiretapConnector\")\n\t\t\t\t.extracting(\"delegate\")\n\t\t\t\t.isInstanceOf(HttpHandlerConnector.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailWhenDefaultWebHandlerIsNotAvailable() {\n\t\tthis.contextRunner.withBean(\"myWebHandler\", WebHandler.class, () -> mock(WebHandler.class)).run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(RuntimeException.class)\n\t\t\t\t.hasMessageStartingWith(\"Mock WebTestClient support requires\")\n\t\t\t\t.hasMessageContaining(\"WebHandler\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldFailWithNeitherDefaultWebHandlerNorWebApplicationContext() {\n\t\tClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(parentClassLoader, WebApplicationContext.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasFailed();\n\t\t\t\tassertThat(context).getFailure()\n\t\t\t\t\t.rootCause()\n\t\t\t\t\t.isInstanceOf(RuntimeException.class)\n\t\t\t\t\t.hasMessageStartingWith(\"Mock WebTestClient support requires\")\n\t\t\t\t\t.hasMessageContaining(\"WebApplicationContext\");\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\t\t\torg.springframework.boot.webtestclient.autoconfigure.WebTestClientAutoConfigurationTests$TestLocalTestWebServerProvider\n\t\t\t\t\t\"\"\")\n\tvoid shouldDefineWebTestClientBoundToWebServer() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(WebTestClient.class);\n\t\t\tassertThat(context).hasBean(\"webTestClient\");\n\t\t\tassertThat(context.getBean(WebTestClient.class)).extracting(\"wiretapConnector\")\n\t\t\t\t.extracting(\"delegate\")\n\t\t\t\t.isInstanceOf(JdkClientHttpConnector.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid failsWithMockBaseUrlAndNoWebHandlerOrMockMvcBean() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasFailed();\n\t\t\tassertThat(context).getFailure()\n\t\t\t\t.rootCause()\n\t\t\t\t.isInstanceOf(RuntimeException.class)\n\t\t\t\t.hasMessageStartingWith(\"Mock WebTestClient support requires\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeClientCodecs() {\n\t\tthis.contextRunner.withUserConfiguration(CodecConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(WebTestClient.class);\n\t\t\tassertThat(context).hasSingleBean(CodecCustomizer.class);\n\t\t\tthen(context.getBean(CodecCustomizer.class)).should().customize(any(CodecConfigurer.class));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldHaveConsistentDefaultTimeout() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class).run((context) -> {\n\t\t\tWebTestClient webTestClient = context.getBean(WebTestClient.class);\n\t\t\tassertThat(webTestClient).hasFieldOrPropertyWithValue(\"responseTimeout\", Duration.ofSeconds(5));\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldCustomizeTimeout() {\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.test.webtestclient.timeout=15m\")\n\t\t\t.run((context) -> {\n\t\t\t\tWebTestClient webTestClient = context.getBean(WebTestClient.class);\n\t\t\t\tassertThat(webTestClient).hasFieldOrPropertyWithValue(\"responseTimeout\", Duration.ofMinutes(15));\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffWithoutCodecCustomizer() {\n\t\tFilteredClassLoader classLoader = new FilteredClassLoader(CodecCustomizer.class);\n\t\tthis.contextRunner.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withClassLoader(classLoader)\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(WebTestClient.class));\n\t}\n\n\t@Test\n\tvoid shouldCreateMockMvcBasedWebTestClientWhenMockMvcBeanIsPresent() {\n\t\tthis.contextRunner.withBean(MockMvc.class, () -> mock(MockMvc.class))\n\t\t\t.withUserConfiguration(WebTestClientCustomConfig.class)\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(WebTestClient.class);\n\t\t\t\tassertThat(context).hasBean(\"webTestClient\");\n\t\t\t\tassertThat(context).hasBean(\"myWebTestClientCustomizer\");\n\t\t\t\tthen(context.getBean(\"myWebTestClientCustomizer\", WebTestClientBuilderCustomizer.class)).should()\n\t\t\t\t\t.customize(any(WebTestClient.Builder.class));\n\t\t\t\tWebTestClient webTestClient = context.getBean(WebTestClient.class);\n\t\t\t\tassertThat(webTestClient).extracting(\"builder\")\n\t\t\t\t\t.extracting(\"connector\")\n\t\t\t\t\t.isInstanceOf(MockMvcHttpConnector.class);\n\t\t\t});\n\t}\n\n\t@Test\n\t@WithResource(name = \"META-INF/spring.factories\",\n\t\t\tcontent = \"\"\"\n\t\t\t\t\torg.springframework.boot.test.http.server.LocalTestWebServer$Provider=\\\n\t\t\t\t\torg.springframework.boot.webtestclient.autoconfigure.WebTestClientAutoConfigurationTests$TestLocalTestWebServerProvider\n\t\t\t\t\t\"\"\")\n\tvoid shouldWorkWithoutServletStack() {\n\t\tClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(parentClassLoader, WebApplicationContext.class))\n\t\t\t.run((context) -> {\n\t\t\t\tassertThat(context).hasSingleBean(WebTestClient.class);\n\t\t\t\tassertThat(context).hasBean(\"webTestClient\");\n\t\t\t\tassertThat(context.getBean(WebTestClient.class)).extracting(\"wiretapConnector\")\n\t\t\t\t\t.extracting(\"delegate\")\n\t\t\t\t\t.isInstanceOf(JdkClientHttpConnector.class);\n\t\t\t});\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class WebTestClientCustomConfig {\n\n\t\t@Bean\n\t\tWebTestClientBuilderCustomizer myWebTestClientCustomizer() {\n\t\t\treturn mock(WebTestClientBuilderCustomizer.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BaseConfiguration {\n\n\t\t@Bean\n\t\tWebHandler webHandler() {\n\t\t\treturn mock(WebHandler.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(BaseConfiguration.class)\n\tstatic class CodecConfiguration {\n\n\t\t@Bean\n\t\tCodecCustomizer myCodecCustomizer() {\n\t\t\treturn mock(CodecCustomizer.class);\n\t\t}\n\n\t}\n\n\t@SuppressWarnings(\"unused\")\n\tstatic class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {\n\n\t\t@Override\n\t\tpublic @Nullable LocalTestWebServer getLocalTestWebServer() {\n\t\t\treturn LocalTestWebServer.of(Scheme.HTTPS, 8080);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/WebTestClientSpringBootTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.config.EnableWebFlux;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient} (i.e. full integration\n * test).\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(properties = { \"spring.main.web-application-type=reactive\", \"debug=true\" },\n\t\tclasses = ExampleWebTestClientApplication.class)\n@AutoConfigureWebTestClient\n@EnableWebFlux\n@Import({ ExampleController1.class, ExampleController2.class })\nclass WebTestClientSpringBootTestIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid shouldFindController1() {\n\t\tthis.webClient.get().uri(\"/one\").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(\"one\");\n\t}\n\n\t@Test\n\tvoid shouldFindController2() {\n\t\tthis.webClient.get().uri(\"/two\").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo(\"two\");\n\t}\n\n\t@Test\n\tvoid shouldHaveRealService() {\n\t\tassertThat(this.applicationContext.getBeansOfType(ExampleRealService.class)).hasSize(1);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webtestclient/autoconfigure/WebTestClientTimeoutSpringBootTestIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.webtestclient.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.config.EnableWebFlux;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SpringBootTest @SpringBootTest} with\n * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient} timeout property\n * binding.\n *\n * @author Jay Choi\n * @author Andy Wilkinson\n */\n@SpringBootTest(properties = { \"spring.main.web-application-type=reactive\" },\n\t\tclasses = ExampleWebTestClientApplication.class)\nclass WebTestClientTimeoutSpringBootTestIntegrationTests {\n\n\t@Nested\n\t@EnableWebFlux\n\t@AutoConfigureWebTestClient\n\t@TestPropertySource(properties = \"spring.test.webtestclient.timeout=30s\")\n\tclass TimeoutFromProperty {\n\n\t\t@Autowired\n\t\tprivate WebTestClient webClient;\n\n\t\t@Test\n\t\tvoid timeoutIsApplied() {\n\t\t\tassertThat(this.webClient).hasFieldOrPropertyWithValue(\"responseTimeout\", Duration.ofSeconds(30));\n\t\t}\n\n\t}\n\n\t@Nested\n\t@EnableWebFlux\n\t@AutoConfigureWebTestClient(timeout = \"25s\")\n\tclass TimeoutFromAnnotation {\n\n\t\t@Autowired\n\t\tprivate WebTestClient webClient;\n\n\t\t@Test\n\t\tvoid timeoutIsApplied() {\n\t\t\tassertThat(this.webClient).hasFieldOrPropertyWithValue(\"responseTimeout\", Duration.ofSeconds(25));\n\t\t}\n\n\t}\n\n\t@Nested\n\t@EnableWebFlux\n\t@AutoConfigureWebTestClient\n\tclass DefaultTimeout {\n\n\t\t@Autowired\n\t\tprivate WebTestClient webClient;\n\n\t\t@Test\n\t\tvoid timeoutIsApplied() {\n\t\t\tassertThat(this.webClient).hasFieldOrPropertyWithValue(\"responseTimeout\", Duration.ofSeconds(5));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.auto-configuration\"\n\tid \"org.springframework.boot.docker-test\"\n\tid \"org.springframework.boot.configuration-properties\"\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Zipkin\"\n\ndependencies {\n\tapi(project(\":core:spring-boot\"))\n\tapi(\"io.zipkin.reporter2:zipkin-reporter-brave\")\n\n\toptional(project(\":core:spring-boot-autoconfigure\"))\n\toptional(project(\":core:spring-boot-docker-compose\"))\n\toptional(project(\":core:spring-boot-testcontainers\"))\n\toptional(\"io.zipkin.reporter2:zipkin-reporter-brave\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(testFixtures(project(\":core:spring-boot-docker-compose\")))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n\ttestImplementation(testFixtures(project(\":core:spring-boot-testcontainers\")))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/dockerTest/java/org/springframework/boot/zipkin/docker/compose/ZipkinDockerComposeConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.docker.compose;\n\nimport org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinConnectionDetails;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link ZipkinDockerComposeConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ZipkinDockerComposeConnectionDetailsFactoryIntegrationTests {\n\n\t@DockerComposeTest(composeFile = \"zipkin-compose.yaml\", image = TestImage.ZIPKIN)\n\tvoid runCreatesConnectionDetails(ZipkinConnectionDetails connectionDetails) {\n\t\tassertThat(connectionDetails.getSpanEndpoint()).startsWith(\"http://\").endsWith(\"/api/v2/spans\");\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/dockerTest/java/org/springframework/boot/zipkin/testcontainers/ZipkinContainerConnectionDetailsFactoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.testcontainers;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.boot.testsupport.container.ZipkinContainer;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinConnectionDetails;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipkinContainerConnectionDetailsFactory}.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\n@SpringJUnitConfig\n@Testcontainers(disabledWithoutDocker = true)\nclass ZipkinContainerConnectionDetailsFactoryIntegrationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final GenericContainer<?> zipkin = TestImage.container(ZipkinContainer.class);\n\n\t@Autowired(required = false)\n\tprivate ZipkinConnectionDetails connectionDetails;\n\n\t@Test\n\tvoid connectionCanBeMadeToZipkinContainer() {\n\t\tassertThat(this.connectionDetails).isNotNull();\n\t\tassertThat(this.connectionDetails.getSpanEndpoint())\n\t\t\t.startsWith(\"http://\" + zipkin.getHost() + \":\" + zipkin.getMappedPort(9411));\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportAutoConfiguration(ZipkinAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/dockerTest/resources/org/springframework/boot/zipkin/docker/compose/zipkin-compose.yaml",
    "content": "services:\n  zipkin:\n    image: '{imageName}'\n    ports:\n      - '9411'\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/HttpSender.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.zip.GZIPOutputStream;\n\nimport zipkin2.reporter.BaseHttpSender;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.HttpEndpointSupplier.Factory;\n\nimport org.springframework.util.unit.DataSize;\n\n/**\n * A Zipkin {@link BytesMessageSender} that uses an HTTP client to send JSON spans.\n * Supports automatic compression with gzip.\n *\n * @author Moritz Halbritter\n * @author Stefan Bratanov\n */\nabstract class HttpSender extends BaseHttpSender<URI, byte[]> {\n\n\t/**\n\t * Only use gzip compression on data which is bigger than this in bytes.\n\t */\n\tprivate static final DataSize COMPRESSION_THRESHOLD = DataSize.ofKilobytes(1);\n\n\tHttpSender(Encoding encoding, Factory endpointSupplierFactory, String endpoint) {\n\t\tsuper(encoding, endpointSupplierFactory, endpoint);\n\t}\n\n\t@Override\n\tprotected URI newEndpoint(String endpoint) {\n\t\treturn URI.create(endpoint);\n\t}\n\n\t@Override\n\tprotected byte[] newBody(List<byte[]> list) {\n\t\treturn this.encoding.encode(list);\n\t}\n\n\t@Override\n\tprotected void postSpans(URI endpoint, byte[] body) throws IOException {\n\t\tMap<String, String> headers = getDefaultHeaders();\n\t\tif (needsCompression(body)) {\n\t\t\tbody = compress(body);\n\t\t\theaders.put(\"Content-Encoding\", \"gzip\");\n\t\t}\n\t\tpostSpans(endpoint, headers, body);\n\t}\n\n\tabstract void postSpans(URI endpoint, Map<String, String> headers, byte[] body) throws IOException;\n\n\tMap<String, String> getDefaultHeaders() {\n\t\tMap<String, String> headers = new LinkedHashMap<>();\n\t\theaders.put(\"b3\", \"0\");\n\t\theaders.put(\"Content-Type\", this.encoding.mediaType());\n\t\treturn headers;\n\t}\n\n\tprivate boolean needsCompression(byte[] body) {\n\t\treturn body.length > COMPRESSION_THRESHOLD.toBytes();\n\t}\n\n\tprivate byte[] compress(byte[] input) throws IOException {\n\t\tByteArrayOutputStream result = new ByteArrayOutputStream();\n\t\ttry (GZIPOutputStream gzip = new GZIPOutputStream(result)) {\n\t\t\tgzip.write(input);\n\t\t}\n\t\treturn result.toByteArray();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/PropertiesZipkinConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\n/**\n * Adapts {@link ZipkinProperties} to {@link ZipkinConnectionDetails}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass PropertiesZipkinConnectionDetails implements ZipkinConnectionDetails {\n\n\tprivate final ZipkinProperties properties;\n\n\tPropertiesZipkinConnectionDetails(ZipkinProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Override\n\tpublic String getSpanEndpoint() {\n\t\treturn this.properties.getEndpoint();\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.net.http.HttpClient;\nimport java.net.http.HttpClient.Builder;\n\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.HttpEndpointSupplier;\nimport zipkin2.reporter.HttpEndpointSuppliers;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * {@link EnableAutoConfiguration Auto-configuration} for Zipkin.\n *\n * @author Moritz Halbritter\n * @author Moritz Halbritter\n * @author Stefan Bratanov\n * @author Wick Dynex\n * @since 4.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(Encoding.class)\n@EnableConfigurationProperties(ZipkinProperties.class)\npublic final class ZipkinAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean(ZipkinConnectionDetails.class)\n\tPropertiesZipkinConnectionDetails zipkinConnectionDetails(ZipkinProperties properties) {\n\t\treturn new PropertiesZipkinConnectionDetails(properties);\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tEncoding encoding(ZipkinProperties properties) {\n\t\treturn switch (properties.getEncoding()) {\n\t\t\tcase JSON -> Encoding.JSON;\n\t\t\tcase PROTO3 -> Encoding.PROTO3;\n\t\t};\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ConditionalOnClass(HttpClient.class)\n\tstatic class ZipkinHttpClientConfiguration {\n\n\t\t@Bean\n\t\t@ConditionalOnMissingBean(BytesMessageSender.class)\n\t\tZipkinHttpClientSender httpClientSender(ZipkinProperties properties, Encoding encoding,\n\t\t\t\tObjectProvider<ZipkinHttpClientBuilderCustomizer> customizers,\n\t\t\t\tObjectProvider<ZipkinConnectionDetails> connectionDetailsProvider,\n\t\t\t\tObjectProvider<HttpEndpointSupplier.Factory> endpointSupplierFactoryProvider) {\n\t\t\tZipkinConnectionDetails connectionDetails = connectionDetailsProvider\n\t\t\t\t.getIfAvailable(() -> new PropertiesZipkinConnectionDetails(properties));\n\t\t\tHttpEndpointSupplier.Factory endpointSupplierFactory = endpointSupplierFactoryProvider\n\t\t\t\t.getIfAvailable(HttpEndpointSuppliers::constantFactory);\n\t\t\tBuilder httpClientBuilder = HttpClient.newBuilder().connectTimeout(properties.getConnectTimeout());\n\t\t\tcustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));\n\t\t\treturn new ZipkinHttpClientSender(encoding, endpointSupplierFactory, connectionDetails.getSpanEndpoint(),\n\t\t\t\t\thttpClientBuilder.build(), properties.getReadTimeout());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinConnectionDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport zipkin2.reporter.HttpEndpointSupplier.Factory;\n\nimport org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;\n\n/**\n * Details required to establish a connection to a Zipkin server.\n * <p>\n * Note: {@linkplain #getSpanEndpoint()} is only read once and passed to a bean of type\n * {@link Factory HttpEndpointSupplier.Factory} which defaults to no-op (constant).\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\npublic interface ZipkinConnectionDetails extends ConnectionDetails {\n\n\t/**\n\t * The endpoint for the span reporting.\n\t * @return the endpoint\n\t */\n\tString getSpanEndpoint();\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinHttpClientBuilderCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.net.http.HttpClient.Builder;\n\n/**\n * Callback interface that can be implemented by beans wishing to customize the\n * {@link Builder HttpClient.Builder} used to send spans to Zipkin.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@FunctionalInterface\npublic interface ZipkinHttpClientBuilderCustomizer {\n\n\t/**\n\t * Customize the http client builder.\n\t * @param httpClient the http client builder to customize\n\t */\n\tvoid customize(Builder httpClient);\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinHttpClientSender.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpRequest.BodyPublishers;\nimport java.net.http.HttpRequest.Builder;\nimport java.net.http.HttpResponse;\nimport java.net.http.HttpResponse.BodyHandlers;\nimport java.time.Duration;\nimport java.util.Map;\n\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.HttpEndpointSupplier.Factory;\n\n/**\n * A {@link HttpSender} which uses the JDK {@link HttpClient} for HTTP communication.\n *\n * @author Moritz Halbritter\n */\nclass ZipkinHttpClientSender extends HttpSender {\n\n\tprivate final HttpClient httpClient;\n\n\tprivate final Duration readTimeout;\n\n\tZipkinHttpClientSender(Encoding encoding, Factory endpointSupplierFactory, String endpoint, HttpClient httpClient,\n\t\t\tDuration readTimeout) {\n\t\tsuper(encoding, endpointSupplierFactory, endpoint);\n\t\tthis.httpClient = httpClient;\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\t@Override\n\tvoid postSpans(URI endpoint, Map<String, String> headers, byte[] body) throws IOException {\n\t\tBuilder request = HttpRequest.newBuilder()\n\t\t\t.POST(BodyPublishers.ofByteArray(body))\n\t\t\t.uri(endpoint)\n\t\t\t.timeout(this.readTimeout);\n\t\theaders.forEach((name, value) -> request.header(name, value));\n\t\ttry {\n\t\t\tHttpResponse<Void> response = this.httpClient.send(request.build(), BodyHandlers.discarding());\n\t\t\tif (response.statusCode() / 100 != 2) {\n\t\t\t\tthrow new IOException(\"Expected HTTP status 2xx, got %d\".formatted(response.statusCode()));\n\t\t\t}\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t\tthrow new IOException(\"Got interrupted while sending spans\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/ZipkinProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.time.Duration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Configuration properties for {@link ZipkinAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @since 4.0.0\n */\n@ConfigurationProperties(\"management.tracing.export.zipkin\")\npublic class ZipkinProperties {\n\n\t/**\n\t * URL to the Zipkin API.\n\t */\n\tprivate String endpoint = \"http://localhost:9411/api/v2/spans\";\n\n\t/**\n\t * How to encode the POST body to the Zipkin API.\n\t */\n\tprivate Encoding encoding = Encoding.JSON;\n\n\t/**\n\t * Connection timeout for requests to Zipkin.\n\t */\n\tprivate Duration connectTimeout = Duration.ofSeconds(1);\n\n\t/**\n\t * Read timeout for requests to Zipkin.\n\t */\n\tprivate Duration readTimeout = Duration.ofSeconds(10);\n\n\tpublic String getEndpoint() {\n\t\treturn this.endpoint;\n\t}\n\n\tpublic void setEndpoint(String endpoint) {\n\t\tthis.endpoint = endpoint;\n\t}\n\n\tpublic Encoding getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\tpublic void setEncoding(Encoding encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\tpublic Duration getConnectTimeout() {\n\t\treturn this.connectTimeout;\n\t}\n\n\tpublic void setConnectTimeout(Duration connectTimeout) {\n\t\tthis.connectTimeout = connectTimeout;\n\t}\n\n\tpublic Duration getReadTimeout() {\n\t\treturn this.readTimeout;\n\t}\n\n\tpublic void setReadTimeout(Duration readTimeout) {\n\t\tthis.readTimeout = readTimeout;\n\t}\n\n\t/**\n\t * Zipkin message encoding.\n\t */\n\tpublic enum Encoding {\n\n\t\t/**\n\t\t * JSON.\n\t\t */\n\t\tJSON,\n\n\t\t/**\n\t\t * Protocol Buffers v3.\n\t\t */\n\t\tPROTO3\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration for Zipkin.\n */\n@NullMarked\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/docker/compose/ZipkinDockerComposeConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.docker.compose;\n\nimport org.springframework.boot.docker.compose.core.RunningService;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;\nimport org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinConnectionDetails;\n\n/**\n * {@link DockerComposeConnectionDetailsFactory} to create {@link ZipkinConnectionDetails}\n * for a {@code zipkin} service.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\nclass ZipkinDockerComposeConnectionDetailsFactory\n\t\textends DockerComposeConnectionDetailsFactory<ZipkinConnectionDetails> {\n\n\tprivate static final int ZIPKIN_PORT = 9411;\n\n\tZipkinDockerComposeConnectionDetailsFactory() {\n\t\tsuper(\"openzipkin/zipkin\", \"org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected ZipkinConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {\n\t\treturn new ZipkinDockerComposeConnectionDetails(source.getRunningService());\n\t}\n\n\t/**\n\t * {@link ZipkinConnectionDetails} backed by a {@code zipkin} {@link RunningService}.\n\t */\n\tstatic class ZipkinDockerComposeConnectionDetails extends DockerComposeConnectionDetails\n\t\t\timplements ZipkinConnectionDetails {\n\n\t\tprivate final String host;\n\n\t\tprivate final int port;\n\n\t\tZipkinDockerComposeConnectionDetails(RunningService source) {\n\t\t\tsuper(source);\n\t\t\tthis.host = source.host();\n\t\t\tthis.port = source.ports().get(ZIPKIN_PORT);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getSpanEndpoint() {\n\t\t\treturn \"http://\" + this.host + \":\" + this.port + \"/api/v2/spans\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/docker/compose/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for Docker Compose Zipkin service connections.\n */\n@NullMarked\npackage org.springframework.boot.zipkin.docker.compose;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/testcontainers/ZipkinContainerConnectionDetailsFactory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.testcontainers;\n\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\n\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinConnectionDetails;\n\n/**\n * {@link ContainerConnectionDetailsFactory} to create {@link ZipkinConnectionDetails}\n * from a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer}\n * using the {@code \"openzipkin/zipkin\"} image.\n *\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass ZipkinContainerConnectionDetailsFactory\n\t\textends ContainerConnectionDetailsFactory<Container<?>, ZipkinConnectionDetails> {\n\n\tprivate static final int ZIPKIN_PORT = 9411;\n\n\tZipkinContainerConnectionDetailsFactory() {\n\t\tsuper(\"openzipkin/zipkin\", \"org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration\");\n\t}\n\n\t@Override\n\tprotected ZipkinConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\treturn new ZipkinContainerConnectionDetails(source);\n\t}\n\n\t/**\n\t * {@link ZipkinConnectionDetails} backed by a {@link ContainerConnectionSource}.\n\t */\n\tprivate static class ZipkinContainerConnectionDetails extends ContainerConnectionDetails<Container<?>>\n\t\t\timplements ZipkinConnectionDetails {\n\n\t\tZipkinContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {\n\t\t\tsuper(source);\n\t\t}\n\n\t\t@Override\n\t\tpublic String getSpanEndpoint() {\n\t\t\treturn \"http://\" + getContainer().getHost() + \":\" + getContainer().getMappedPort(ZIPKIN_PORT)\n\t\t\t\t\t+ \"/api/v2/spans\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/java/org/springframework/boot/zipkin/testcontainers/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testcontainers Zipkin service connections.\n */\n@NullMarked\npackage org.springframework.boot.zipkin.testcontainers;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n  \"groups\": [],\n  \"properties\": [\n    {\n      \"name\": \"management.zipkin.tracing.connect-timeout\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.tracing.export.zipkin.connect-timeout\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"management.zipkin.tracing.encoding\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.tracing.export.zipkin.encoding\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"management.zipkin.tracing.endpoint\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.tracing.export.zipkin.endpoint\",\n        \"since\": \"3.2.0\"\n      }\n    },\n    {\n      \"name\": \"management.zipkin.tracing.read-timeout\",\n      \"deprecation\": {\n        \"level\": \"error\",\n        \"replacement\": \"management.tracing.export.zipkin.read-timeout\",\n        \"since\": \"3.2.0\"\n      }\n    }\n  ],\n  \"hints\": []\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/main/resources/META-INF/spring.factories",
    "content": "# Connection Details Factories\norg.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\\\norg.springframework.boot.zipkin.docker.compose.ZipkinDockerComposeConnectionDetailsFactory,\\\norg.springframework.boot.zipkin.testcontainers.ZipkinContainerConnectionDetailsFactory\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/test/java/org/springframework/boot/zipkin/autoconfigure/TestHttpEndpointSupplier.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport zipkin2.reporter.HttpEndpointSupplier;\n\n/**\n * Test {@link HttpEndpointSupplier}.\n *\n * @author Moritz Halbritter\n */\nclass TestHttpEndpointSupplier implements HttpEndpointSupplier {\n\n\tprivate final String url;\n\n\tprivate final AtomicInteger suffix = new AtomicInteger();\n\n\tTestHttpEndpointSupplier(String url) {\n\t\tthis.url = url;\n\t}\n\n\t@Override\n\tpublic String get() {\n\t\treturn this.url + \"/\" + this.suffix.incrementAndGet();\n\t}\n\n\t@Override\n\tpublic void close() {\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/test/java/org/springframework/boot/zipkin/autoconfigure/ZipkinAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.net.http.HttpClient;\n\nimport org.junit.jupiter.api.Test;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.HttpEndpointSupplier;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.FilteredClassLoader;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Tests for {@link ZipkinAutoConfiguration}.\n *\n * @author Moritz Halbritter\n * @author Wick Dynex\n */\nclass ZipkinAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(ZipkinAutoConfiguration.class));\n\n\t@Test\n\tvoid shouldSupplyBeans() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tassertThat(context).hasSingleBean(Encoding.class);\n\t\t\tassertThat(context).hasSingleBean(PropertiesZipkinConnectionDetails.class);\n\t\t\tassertThat(context).hasSingleBean(BytesMessageSender.class);\n\t\t\tassertThat(context).hasSingleBean(ZipkinHttpClientSender.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldNotSupplyBeansIfZipkinReporterIsMissing() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(\"zipkin2.reporter\"))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(Encoding.class));\n\t}\n\n\t@Test\n\tvoid shouldNotProvideHttpClientSenderIfHttpClientIsNotAvailable() {\n\t\tthis.contextRunner.withClassLoader(new FilteredClassLoader(HttpClient.class))\n\t\t\t.run((context) -> assertThat(context).doesNotHaveBean(ZipkinHttpClientSender.class));\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomEncodingBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomEncodingConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customEncoding\");\n\t\t\tassertThat(context).hasSingleBean(Encoding.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldBackOffOnCustomSenderBeans() {\n\t\tthis.contextRunner.withUserConfiguration(CustomSenderConfiguration.class).run((context) -> {\n\t\t\tassertThat(context).hasBean(\"customSender\");\n\t\t\tassertThat(context).hasSingleBean(BytesMessageSender.class);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldUseCustomHttpEndpointSupplierFactory() {\n\t\tthis.contextRunner.withUserConfiguration(CustomHttpEndpointSupplierFactoryConfiguration.class)\n\t\t\t.run((context) -> {\n\t\t\t\tZipkinHttpClientSender httpClientSender = context.getBean(ZipkinHttpClientSender.class);\n\t\t\t\tassertThat(httpClientSender).extracting(\"endpointSupplier\")\n\t\t\t\t\t.isInstanceOf(CustomHttpEndpointSupplier.class);\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid definesPropertiesBasedConnectionDetailsByDefault() {\n\t\tthis.contextRunner.run((context) -> assertThat(context).hasSingleBean(PropertiesZipkinConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldUseCustomConnectionDetailsWhenDefined() {\n\t\tthis.contextRunner\n\t\t\t.withBean(ZipkinConnectionDetails.class, () -> new FixedZipkinConnectionDetails(\"http://localhost\"))\n\t\t\t.run((context) -> assertThat(context).hasSingleBean(ZipkinConnectionDetails.class)\n\t\t\t\t.doesNotHaveBean(PropertiesZipkinConnectionDetails.class));\n\t}\n\n\t@Test\n\tvoid shouldWorkWithoutSenders() {\n\t\tthis.contextRunner\n\t\t\t.withClassLoader(new FilteredClassLoader(\"org.springframework.web.client\",\n\t\t\t\t\t\"org.springframework.web.reactive.function.client\"))\n\t\t\t.run((context) -> assertThat(context).hasNotFailed());\n\t}\n\n\tprivate static final class FixedZipkinConnectionDetails implements ZipkinConnectionDetails {\n\n\t\tprivate final String spanEndpoint;\n\n\t\tprivate FixedZipkinConnectionDetails(String spanEndpoint) {\n\t\t\tthis.spanEndpoint = spanEndpoint;\n\t\t}\n\n\t\t@Override\n\t\tpublic String getSpanEndpoint() {\n\t\t\treturn this.spanEndpoint;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprivate static final class CustomEncodingConfiguration {\n\n\t\t@Bean\n\t\tEncoding customEncoding() {\n\t\t\treturn Encoding.PROTO3;\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomSenderConfiguration {\n\n\t\t@Bean\n\t\tBytesMessageSender customSender() {\n\t\t\treturn mock(BytesMessageSender.class);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class CustomHttpEndpointSupplierFactoryConfiguration {\n\n\t\t@Bean\n\t\tHttpEndpointSupplier.Factory httpEndpointSupplier() {\n\t\t\treturn new CustomHttpEndpointSupplierFactory();\n\t\t}\n\n\t}\n\n\tstatic class CustomHttpEndpointSupplierFactory implements HttpEndpointSupplier.Factory {\n\n\t\t@Override\n\t\tpublic HttpEndpointSupplier create(String endpoint) {\n\t\t\treturn new CustomHttpEndpointSupplier(endpoint);\n\t\t}\n\n\t}\n\n\tstatic class CustomHttpEndpointSupplier implements HttpEndpointSupplier {\n\n\t\tprivate final String endpoint;\n\n\t\tCustomHttpEndpointSupplier(String endpoint) {\n\t\t\tthis.endpoint = endpoint;\n\t\t}\n\n\t\t@Override\n\t\tpublic String get() {\n\t\t\treturn this.endpoint;\n\t\t}\n\n\t\t@Override\n\t\tpublic void close() {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/test/java/org/springframework/boot/zipkin/autoconfigure/ZipkinHttpClientSenderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.io.IOException;\nimport java.net.http.HttpClient;\nimport java.time.Duration;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport okhttp3.mockwebserver.RecordedRequest;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.Encoding;\nimport zipkin2.reporter.HttpEndpointSupplier;\nimport zipkin2.reporter.HttpEndpointSuppliers;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatException;\nimport static org.assertj.core.api.Assertions.assertThatIOException;\n\n/**\n * Tests for {@link ZipkinHttpClientSender}.\n *\n * @author Moritz Halbritter\n */\n@ClassPathExclusions(\"spring-web-*.jar\")\nclass ZipkinHttpClientSenderTests extends ZipkinHttpSenderTests {\n\n\tprivate MockWebServer mockBackEnd;\n\n\tprivate String zipkinUrl;\n\n\t@Override\n\t@BeforeEach\n\tvoid beforeEach() {\n\t\tthis.mockBackEnd = new MockWebServer();\n\t\ttry {\n\t\t\tthis.mockBackEnd.start();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\tthis.zipkinUrl = this.mockBackEnd.url(\"/api/v2/spans\").toString();\n\t\tsuper.beforeEach();\n\t}\n\n\t@Override\n\tvoid afterEach() throws IOException {\n\t\tsuper.afterEach();\n\t\tthis.mockBackEnd.shutdown();\n\t}\n\n\t@Override\n\tBytesMessageSender createSender() {\n\t\treturn createSender(Encoding.JSON, Duration.ofSeconds(10));\n\t}\n\n\tZipkinHttpClientSender createSender(Encoding encoding, Duration timeout) {\n\t\treturn createSender(HttpEndpointSuppliers.constantFactory(), encoding, timeout);\n\t}\n\n\tZipkinHttpClientSender createSender(HttpEndpointSupplier.Factory endpointSupplierFactory, Encoding encoding,\n\t\t\tDuration timeout) {\n\t\tHttpClient httpClient = HttpClient.newBuilder().connectTimeout(timeout).build();\n\t\treturn new ZipkinHttpClientSender(encoding, endpointSupplierFactory, this.zipkinUrl, httpClient, timeout);\n\t}\n\n\t@Test\n\tvoid sendShouldSendSpansToZipkin() throws IOException, InterruptedException {\n\t\tthis.mockBackEnd.enqueue(new MockResponse());\n\t\tList<byte[]> encodedSpans = List.of(toByteArray(\"span1\"), toByteArray(\"span2\"));\n\t\tthis.sender.send(encodedSpans);\n\t\trequestAssertions((request) -> {\n\t\t\tassertThat(request.getMethod()).isEqualTo(\"POST\");\n\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/json\");\n\t\t\tassertThat(request.getBody().readUtf8()).isEqualTo(\"[span1,span2]\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid sendShouldSendSpansToZipkinInProto3() throws IOException, InterruptedException {\n\t\tthis.mockBackEnd.enqueue(new MockResponse());\n\t\tList<byte[]> encodedSpans = List.of(toByteArray(\"span1\"), toByteArray(\"span2\"));\n\t\ttry (BytesMessageSender sender = createSender(Encoding.PROTO3, Duration.ofSeconds(10))) {\n\t\t\tsender.send(encodedSpans);\n\t\t}\n\t\trequestAssertions((request) -> {\n\t\t\tassertThat(request.getMethod()).isEqualTo(\"POST\");\n\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/x-protobuf\");\n\t\t\tassertThat(request.getBody().readUtf8()).isEqualTo(\"span1span2\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid sendUsesDynamicEndpoint() throws Exception {\n\t\tthis.mockBackEnd.enqueue(new MockResponse());\n\t\tthis.mockBackEnd.enqueue(new MockResponse());\n\t\ttry (TestHttpEndpointSupplier httpEndpointSupplier = new TestHttpEndpointSupplier(this.zipkinUrl)) {\n\t\t\ttry (BytesMessageSender sender = createSender((endpoint) -> httpEndpointSupplier, Encoding.JSON,\n\t\t\t\t\tDuration.ofSeconds(10))) {\n\t\t\t\tsender.send(Collections.emptyList());\n\t\t\t\tsender.send(Collections.emptyList());\n\t\t\t}\n\t\t\tassertThat(this.mockBackEnd.takeRequest().getPath()).endsWith(\"/1\");\n\t\t\tassertThat(this.mockBackEnd.takeRequest().getPath()).endsWith(\"/2\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid sendShouldHandleHttpFailures() throws InterruptedException {\n\t\tthis.mockBackEnd.enqueue(new MockResponse().setResponseCode(500));\n\t\tassertThatException().isThrownBy(() -> this.sender.send(Collections.emptyList()))\n\t\t\t.withMessageContaining(\"Expected HTTP status 2xx, got 500\");\n\t\trequestAssertions((request) -> assertThat(request.getMethod()).isEqualTo(\"POST\"));\n\t}\n\n\t@Test\n\tvoid sendShouldCompressData() throws IOException, InterruptedException {\n\t\tString uncompressed = \"a\".repeat(10000);\n\t\t// This is gzip compressed 10000 times 'a'\n\t\tbyte[] compressed = Base64.getDecoder()\n\t\t\t.decode(\"H4sIAAAAAAAA/+3BMQ0AAAwDIKFLj/k3UR8NcA8AAAAAAAAAAAADUsAZfeASJwAA\");\n\t\tthis.mockBackEnd.enqueue(new MockResponse());\n\t\tthis.sender.send(List.of(toByteArray(uncompressed)));\n\t\trequestAssertions((request) -> {\n\t\t\tassertThat(request.getMethod()).isEqualTo(\"POST\");\n\t\t\tassertThat(request.getHeader(\"Content-Type\")).isEqualTo(\"application/json\");\n\t\t\tassertThat(request.getHeader(\"Content-Encoding\")).isEqualTo(\"gzip\");\n\t\t\tassertThat(request.getBody().readByteArray()).isEqualTo(compressed);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldTimeout() throws IOException {\n\t\ttry (BytesMessageSender sender = createSender(Encoding.JSON, Duration.ofMillis(1))) {\n\t\t\tMockResponse response = new MockResponse().setResponseCode(200).setHeadersDelay(100, TimeUnit.MILLISECONDS);\n\t\t\tthis.mockBackEnd.enqueue(response);\n\t\t\tassertThatIOException().isThrownBy(() -> sender.send(Collections.emptyList()))\n\t\t\t\t.withMessageContaining(\"timed out\");\n\t\t}\n\t}\n\n\tprivate void requestAssertions(Consumer<RecordedRequest> assertions) throws InterruptedException {\n\t\tRecordedRequest request = this.mockBackEnd.takeRequest();\n\t\tassertThat(request).satisfies(assertions);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/test/java/org/springframework/boot/zipkin/autoconfigure/ZipkinHttpSenderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.autoconfigure;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport zipkin2.reporter.BytesMessageSender;\nimport zipkin2.reporter.ClosedSenderException;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Abstract base test class which is used for testing the different implementations of the\n * {@link HttpSender}.\n *\n * @author Stefan Bratanov\n */\nabstract class ZipkinHttpSenderTests {\n\n\tprotected BytesMessageSender sender;\n\n\tabstract BytesMessageSender createSender();\n\n\t@BeforeEach\n\tvoid beforeEach() {\n\t\tthis.sender = createSender();\n\t}\n\n\t@AfterEach\n\tvoid afterEach() throws IOException {\n\t\tthis.sender.close();\n\t}\n\n\t@Test\n\tvoid sendShouldThrowIfCloseWasCalled() throws IOException {\n\t\tthis.sender.close();\n\t\tassertThatExceptionOfType(ClosedSenderException.class)\n\t\t\t.isThrownBy(() -> this.sender.send(Collections.emptyList()));\n\t}\n\n\tprotected byte[] toByteArray(String input) {\n\t\treturn input.getBytes(StandardCharsets.UTF_8);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/test/java/org/springframework/boot/zipkin/testcontainers/ZipkinContainerConnectionDetailsFactoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.testcontainers;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.predicate.RuntimeHintsPredicates;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipkinContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\nclass ZipkinContainerConnectionDetailsFactoryTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(RuntimeHintsPredicates.reflection().onType(ZipkinAutoConfiguration.class)).accepts(hints);\n\t}\n\n}\n"
  },
  {
    "path": "module/spring-boot-zipkin/src/test/java/org/springframework/boot/zipkin/testcontainers/ZipkinContainerConnectionDetailsFactoryWithoutActuatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.zipkin.testcontainers;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactoryHints;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ZipkinContainerConnectionDetailsFactory}.\n *\n * @author Moritz Halbritter\n */\n@ClassPathExclusions(\"spring-boot-actuator-*\")\nclass ZipkinContainerConnectionDetailsFactoryWithoutActuatorTests {\n\n\t@Test\n\tvoid shouldRegisterHints() {\n\t\tRuntimeHints hints = ContainerConnectionDetailsFactoryHints.getRegisteredHints(getClass().getClassLoader());\n\t\tassertThat(hints).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "platform/spring-boot-dependencies/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.bom\"\n\tid \"org.springframework.boot.deployed\"\n}\n\ndescription = \"Spring Boot Dependencies\"\n\nbom {\n\tupgrade {\n\t\tpolicy = \"same-major-version\"\n\t\tgitHub {\n\t\t\tissueLabels = [\n\t\t\t\t\"type: dependency-upgrade\",\n\t\t\t\t\"status: team-only\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"ActiveMQ\", \"6.2.1\") {\n\t\tprohibit {\n\t\t\tversionRange \"[6.2.2]\"\n\t\t\tbecause \"it contains a regression on Windows (https://github.com/apache/activemq/issues/1830)\"\n\t\t}\n\t\tgroup(\"org.apache.activemq\") {\n\t\t\tmodules = [\n\t\t\t\t\"activemq-console\",\n\t\t\t\t\"activemq-spring\"\n\t\t\t]\n\t\t\tbom(\"activemq-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://activemq.apache.org\")\n\t\t\tdocs(\"https://activemq.apache.org/components/classic/documentation\")\n\t\t\treleaseNotes(version -> \"https://activemq.apache.org/components/classic/download/classic-%02d-%02d-%02d\"\n\t\t\t\t.formatted(version.componentInts()))\n\t\t}\n\t}\n\tlibrary(\"Angus Mail\", \"2.0.5\") {\n\t\tgroup(\"org.eclipse.angus\") {\n\t\t\tmodules = [\n\t\t\t\t\"angus-core\",\n\t\t\t\t\"angus-mail\",\n\t\t\t\t\"dsn\",\n\t\t\t\t\"gimap\",\n\t\t\t\t\"imap\",\n\t\t\t\t\"jakarta.mail\",\n\t\t\t\t\"logging-mailhandler\",\n\t\t\t\t\"pop3\",\n\t\t\t\t\"smtp\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/eclipse-ee4j/angus-mail\")\n\t\t\treleaseNotes(\"https://github.com/eclipse-ee4j/angus-mail/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Artemis\", \"2.53.0\") {\n\t\tgroup(\"org.apache.artemis\") {\n\t\t\tbom(\"artemis-bom\") {\n\t\t\t\tpermit(\"org.apache.activemq:artemis-amqp-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-boot\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-cdi-client\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-cli\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-commons\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-console\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-core-client-all\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-core-client-osgi\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-core-client\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-dto\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-features:2.50.0:f\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-hornetq-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-hqclient-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-cdi-client\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-client-all\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-client-osgi\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-client\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-openwire-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-ra\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-server\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jakarta-service-extensions\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jdbc-store\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jms-client-all\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jms-client-osgi\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jms-client\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-jms-server\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-journal\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-lockmanager-api\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-lockmanager-ri\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-mqtt-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-openwire-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-ra\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-selector\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-server-osgi\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-server\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-service-extensions\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-stomp-protocol\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-web\")\n\t\t\t\tpermit(\"org.apache.activemq:artemis-website\")\n\t\t\t}\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://activemq.apache.org/components/artemis\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.apache.activemq/artemis-jms-server/{version}\", \"org.apache.activemq.artemis.jms.server\")\n\t\t\treleaseNotes(\"https://activemq.apache.org/components/artemis/download/release-notes-{version}\")\n\t\t}\n\t}\n\tlibrary(\"AspectJ\", \"1.9.25.1\") {\n\t\tgroup(\"org.aspectj\") {\n\t\t\tmodules = [\n\t\t\t\t\"aspectjrt\",\n\t\t\t\t\"aspectjtools\",\n\t\t\t\t\"aspectjweaver\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://eclipse.dev/aspectj\")\n\t\t\treleaseNotes(version -> \"https://github.com/eclipse-aspectj/aspectj/blob/master/docs/release/README-%s.%s.%s.adoc\"\n\t\t\t\t.formatted(version.major(), version.minor(), version.patch()))\n\t\t}\n\t}\n\tlibrary(\"AssertJ\", \"${assertjVersion}\") {\n\t\tprohibit {\n\t\t\tcontains \"-M\"\n\t\t\tcontains \"-RC\"\n\t\t\tbecause \"we don't want milestones or release candidates\"\n\t\t}\n\t\tgroup(\"org.assertj\") {\n\t\t\tbom(\"assertj-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://assertj.github.io/doc\")\n\t\t\treleaseNotes(\"https://github.com/assertj/assertj/releases/tag/assertj-build-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Awaitility\", \"4.3.0\") {\n\t\tgroup(\"org.awaitility\") {\n\t\t\tmodules = [\n\t\t\t\t\"awaitility\",\n\t\t\t\t\"awaitility-groovy\",\n\t\t\t\t\"awaitility-kotlin\",\n\t\t\t\t\"awaitility-scala\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(version -> \"https://github.com/awaitility/awaitility/wiki/ReleaseNotes%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t}\n\t}\n\tlibrary(\"Zipkin Reporter\", \"3.5.3\") {\n\t\tgroup(\"io.zipkin.reporter2\") {\n\t\t\tbom(\"zipkin-reporter-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/openzipkin/zipkin-reporter-java\")\n\t\t\treleaseNotes(\"https://github.com/openzipkin/zipkin-reporter-java/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Brave\", \"6.3.1\") {\n\t\tgroup(\"io.zipkin.brave\") {\n\t\t\tbom(\"brave-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/openzipkin/brave\")\n\t\t\treleaseNotes(\"https://github.com/openzipkin/brave/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Build Helper Maven Plugin\", \"3.6.1\") {\n\t\tgroup(\"org.codehaus.mojo\") {\n\t\t\tplugins = [\n\t\t\t\t\"build-helper-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.mojohaus.org/build-helper-maven-plugin\")\n\t\t\treleaseNotes(\"https://github.com/mojohaus/build-helper-maven-plugin/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Byte Buddy\", \"1.18.7\") {\n\t\tgroup(\"net.bytebuddy\") {\n\t\t\tmodules = [\n\t\t\t\t\"byte-buddy\",\n\t\t\t\t\"byte-buddy-agent\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://bytebuddy.net\")\n\t\t\tdocs(\"https://bytebuddy.net/#/tutorial\")\n\t\t\treleaseNotes(\"https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-{version}\")\n\t\t}\n\t}\n\tlibrary(\"cache2k\", \"2.6.1.Final\") {\n\t\tgroup(\"org.cache2k\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"cache2k-api\",\n\t\t\t\t\t\"cache2k-config\",\n\t\t\t\t\t\"cache2k-core\",\n\t\t\t\t\t\"cache2k-jcache\",\n\t\t\t\t\t\"cache2k-micrometer\",\n\t\t\t\t\t\"cache2k-spring\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://cache2k.org\")\n\t\t\treleaseNotes(\"https://github.com/cache2k/cache2k/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Caffeine\", \"3.2.3\") {\n\t\tgroup(\"com.github.ben-manes.caffeine\") {\n\t\t\tmodules = [\n\t\t\t\t\"caffeine\",\n\t\t\t\t\"guava\",\n\t\t\t\t\"jcache\",\n\t\t\t\t\"simulator\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/ben-manes/caffeine\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/{version}\", \"com.github.benmanes.caffeine\")\n\t\t\tdocs(\"https://github.com/ben-manes/caffeine/wiki\")\n\t\t\treleaseNotes(\"https://github.com/ben-manes/caffeine/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Cassandra Driver\", \"4.19.2\") {\n\t\tgroup(\"org.apache.cassandra\") {\n\t\t\tbom(\"java-driver-bom\") {\n\t\t\t\tpermit(\"com.datastax.oss:native-protocol\")\n\t\t\t}\n\t\t\tmodules = [\n\t\t\t\t\"java-driver-core\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Classmate\", \"1.7.3\") {\n\t\tgroup(\"com.fasterxml\") {\n\t\t\tmodules = [\n\t\t\t\t\"classmate\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/FasterXML/java-classmate\")\n\t\t}\n\t}\n\tlibrary(\"Commons Codec\", \"${commonsCodecVersion}\") {\n\t\tgroup(\"commons-codec\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-codec\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://commons.apache.org/proper/commons-codec\")\n\t\t\treleaseNotes(\"https://commons.apache.org/proper/commons-codec/changes.html#a{version}\")\n\t\t}\n\t}\n\tlibrary(\"Commons DBCP2\", \"2.14.0\") {\n\t\tgroup(\"org.apache.commons\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-dbcp2\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://commons.apache.org/proper/commons-dbcp\")\n\t\t\treleaseNotes(\"https://commons.apache.org/proper/commons-dbcp/changes-report.html#a{version}\")\n\t\t}\n\t}\n\tlibrary(\"Commons Lang3\", \"3.20.0\") {\n\t\tgroup(\"org.apache.commons\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-lang3\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://commons.apache.org/proper/commons-lang\")\n\t\t\treleaseNotes(\"https://commons.apache.org/proper/commons-lang/changes.html#a{version}\")\n\t\t}\n\t}\n\tlibrary(\"Commons Logging\", \"1.3.6\") {\n\t\tgroup(\"commons-logging\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"commons-logging\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://commons.apache.org/proper/commons-logging\")\n\t\t\treleaseNotes(\"https://commons.apache.org/proper/commons-logging/changes-report.html#a{version}\")\n\t\t}\n\t}\n\tlibrary(\"Commons Pool\", \"1.6\") {\n\t\tgroup(\"commons-pool\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-pool\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Commons Pool2\", \"2.13.1\") {\n\t\tgroup(\"org.apache.commons\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-pool2\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://commons.apache.org/proper/commons-pool\")\n\t\t}\n\t}\n\tlibrary(\"Couchbase Client\", \"3.11.1\") {\n\t\tgroup(\"com.couchbase.client\") {\n\t\t\tmodules = [\n\t\t\t\t\"java-client\"\n\t\t\t]\n\t\t}\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tfrom \"org.springframework.data:spring-data-couchbase\"\n\t\t\t\tmanagedBy \"Spring Data Bom\"\n\t\t\t}\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://docs.couchbase.com/java-sdk/current/hello-world/overview.html\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/com.couchbase.client/java-client/{version}\", \"com.couchbase.client\")\n\t\t\treleaseNotes(\"https://docs.couchbase.com/java-sdk/current/project-docs/sdk-release-notes.html\")\n\t\t}\n\t}\n\tlibrary(\"Crac\", \"1.5.0\") {\n\t\tgroup(\"org.crac\") {\n\t\t\tmodules = [\n\t\t\t\t\"crac\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"CycloneDX Maven Plugin\", \"2.9.1\") {\n\t\tgroup(\"org.cyclonedx\") {\n\t\t\tplugins = [\n\t\t\t\t\"cyclonedx-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/CycloneDX/cyclonedx-maven-plugin/releases/tag/cyclonedx-maven-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"DB2 JDBC\", \"12.1.4.0\") {\n\t\tgroup(\"com.ibm.db2\") {\n\t\t\tmodules = [\n\t\t\t\t\"jcc\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Dependency Management Plugin\", \"1.1.7\") {\n\t\tgroup(\"io.spring.gradle\") {\n\t\t\tmodules = [\n\t\t\t\t\"dependency-management-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/spring-gradle-plugins/dependency-management-plugin\")\n\t\t\tdocs(\"https://docs.spring.io/dependency-management-plugin/docs/{version}/reference/html\")\n\t\t\treleaseNotes(\"https://github.com/spring-gradle-plugins/dependency-management-plugin/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Derby\", \"10.16.1.1\") {\n\t\tprohibit {\n\t\t\tversionRange \"[10.17.1.0,)\"\n\t\t\tbecause \"it requires Java 21\"\n\t\t}\n\t\tgroup(\"org.apache.derby\") {\n\t\t\tmodules = [\n\t\t\t\t\"derby\",\n\t\t\t\t\"derbyclient\",\n\t\t\t\t\"derbynet\",\n\t\t\t\t\"derbyoptionaltools\",\n\t\t\t\t\"derbyshared\",\n\t\t\t\t\"derbytools\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Ehcache3\", \"3.11.1\") {\n\t\tgroup(\"org.ehcache\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"ehcache\",\n\t\t\t\t\t\"ehcache\" {\n\t\t\t\t\t\tclassifier = 'jakarta'\n\t\t\t\t\t},\n\t\t\t\t\t\"ehcache-clustered\",\n\t\t\t\t\t\"ehcache-transactions\",\n\t\t\t\t\t\"ehcache-transactions\" {\n\t\t\t\t\t\tclassifier = 'jakarta'\n\t\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.ehcache.org\")\n\t\t\treleaseNotes(\"https://github.com/ehcache/ehcache3/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Elasticsearch Client\", \"9.3.1\") {\n\t\tprohibit {\n\t\t\tcontains \"-alpha\"\n\t\t\tcontains \"-beta\"\n\t\t\tcontains \"-rc\"\n\t\t\tbecause \"we don't want preview releases\"\n\t\t}\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tfrom \"org.springframework.data:spring-data-elasticsearch\"\n\t\t\t\tmanagedBy \"Spring Data Bom\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"co.elastic.clients\") {\n\t\t\tmodules = [\n\t\t\t\t\"elasticsearch-java\",\n\t\t\t\t\"elasticsearch-rest5-client\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(version -> \"https://www.elastic.co/docs/release-notes/elasticsearch/clients/java/%s\".formatted(version.toString(\"-\")))\n\t\t\tjavadoc(\"elasticsearch-java\", version -> \"https://javadoc.io/doc/co.elastic.clients/elasticsearch-java/%s/index.html\".formatted(version), \"co.elastic.clients.elasticsearch\", \"co.elastic.clients.transport\")\n\t\t}\n\t}\n\tlibrary(\"Flyway\", \"12.1.1\") {\n\t\tgroup(\"org.flywaydb\") {\n\t\t\tmodules = [\n\t\t\t\t\"flyway-command-test-connection\",\n\t\t\t\t\"flyway-commandline\",\n\t\t\t\t\"flyway-core\",\n\t\t\t\t\"flyway-database-cassandra\",\n\t\t\t\t\"flyway-database-db2\",\n\t\t\t\t\"flyway-database-derby\",\n\t\t\t\t\"flyway-database-hsqldb\",\n\t\t\t\t\"flyway-database-informix\",\n\t\t\t\t\"flyway-database-nc-couchbase\",\n\t\t\t\t\"flyway-database-nc-mongodb\",\n\t\t\t\t\"flyway-database-oracle\",\n\t\t\t\t\"flyway-database-postgresql\",\n\t\t\t\t\"flyway-database-redshift\",\n\t\t\t\t\"flyway-database-saphana\",\n\t\t\t\t\"flyway-database-snowflake\",\n\t\t\t\t\"flyway-database-sybasease\",\n\t\t\t\t\"flyway-firebird\",\n\t\t\t\t\"flyway-gcp-bigquery\",\n\t\t\t\t\"flyway-gcp-spanner\",\n\t\t\t\t\"flyway-mysql\",\n\t\t\t\t\"flyway-singlestore\",\n\t\t\t\t\"flyway-sqlserver\"\n\t\t\t]\n\t\t\tplugins = [\n\t\t\t\t\"flyway-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://documentation.red-gate.com/flyway\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.flywaydb/flyway-core/{version}\", \"org.flywaydb\")\n\t\t\treleaseNotes(\"https://documentation.red-gate.com/flyway/release-notes-and-older-versions/release-notes-for-flyway-engine\")\n\t\t}\n\t}\n\tlibrary(\"FreeMarker\", \"2.3.34\") {\n\t\tgroup(\"org.freemarker\") {\n\t\t\tmodules = [\n\t\t\t\t\"freemarker\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://freemarker.apache.org\")\n\t\t\treleaseNotes(version -> \"https://freemarker.apache.org/docs/versions_%s.html\"\n\t\t\t\t.formatted(version.toString(\"_\")))\n\t\t}\n\t}\n\tlibrary(\"Git Commit ID Maven Plugin\", \"9.0.2\") {\n\t\tgroup(\"io.github.git-commit-id\") {\n\t\t\tplugins = [\n\t\t\t\t\"git-commit-id-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/git-commit-id/git-commit-id-maven-plugin\")\n\t\t\treleaseNotes(\"https://github.com/git-commit-id/git-commit-id-maven-plugin/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Glassfish JAXB\", \"4.0.6\") {\n\t\tprohibit {\n\t\t\tversionRange \"[4.0.7]\"\n\t\t\tbecause \"it contains a regression (https://github.com/spring-projects/spring-boot/issues/49607#issuecomment-4072451614)\"\n\t\t}\n\t\talignWith {\n\t\t\tdependencyManagementDeclaredIn(\"org.glassfish.jaxb:jaxb-bom\") {\n\t\t\t\texcluding { candidate -> candidate.classifier().equals(\"sources\") }\n\t\t\t\texcluding { candidate ->\n\t\t\t\t\tdef permittedGroups = Set.of(\"org.glassfish.jaxb\", \"com.sun.xml.bind\")\n\t\t\t\t\treturn !permittedGroups.contains(candidate.groupId())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgroup(\"org.glassfish.jaxb\") {\n\t\t\tmodules = [\n\t\t\t\t\"codemodel\",\n\t\t\t\t\"jaxb-core\",\n\t\t\t\t\"jaxb-jxc\",\n\t\t\t\t\"jaxb-runtime\",\n\t\t\t\t\"jaxb-xjc\",\n\t\t\t\t\"txw2\",\n\t\t\t\t\"xsom\"\n\t\t\t]\n\t\t}\n\t\tgroup(\"com.sun.xml.bind\") {\n\t\t\tmodules = [\n\t\t\t\t\"jaxb-core\",\n\t\t\t\t\"jaxb-impl\",\n\t\t\t\t\"jaxb-jxc\",\n\t\t\t\t\"jaxb-osgi\",\n\t\t\t\t\"jaxb-xjc\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/eclipse-ee4j/jaxb-ri/releases/tag/{version}-RI\")\n\t\t}\n\t}\n\tlibrary(\"Glassfish JSTL\", \"3.0.1\") {\n\t\tgroup(\"org.glassfish.web\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.servlet.jsp.jstl\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"GraphQL Java\", \"25.0\") {\n\t\tprohibit {\n\t\t\tstartsWith([\"2018-\", \"2019-\", \"2020-\", \"2021-\", \"230521-\"])\n\t\t\tbecause \"we don't want thses snapshots\"\n\t\t}\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tfrom \"org.springframework.graphql:spring-graphql\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"com.graphql-java\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"graphql-java\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.graphql-java.com\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/com.graphql-java/graphql-java/{version}\", \"graphql\")\n\t\t\treleaseNotes(\"https://github.com/graphql-java/graphql-java/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Groovy\", \"5.0.4\") {\n\t\tprohibit {\n\t\t\tcontains \"-alpha-\"\n\t\t\tbecause \"we don't want alpha dependencies\"\n\t\t}\n\t\tgroup(\"org.apache.groovy\") {\n\t\t\tbom(\"groovy-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://groovy-lang.org\")\n\t\t}\n\t}\n\tlibrary(\"Grpc Java\", \"1.80.0\") {\n\t\tgroup(\"io.grpc\") {\n\t\t\tbom(\"grpc-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tgithub(\"https://github.com/grpc/grpc-java\")\n\t\t\tdocs(\"https://grpc.io/docs/languages/java/\")\n\t\t\treleaseNotes(\"https://github.com/grpc/grpc-java/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Grpc Kotlin\", \"1.5.0\") {\n\t\tgroup(\"io.grpc\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"grpc-kotlin-stub\" {\n\t\t\t\t\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tgithub(\"https://github.com/grpc/grpc-kotlin\")\n\t\t\tdocs(\"https://grpc.io/docs/languages/kotlin/\")\n\t\t\treleaseNotes(\"https://github.com/grpc/grpc-kotlin/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Gson\", \"2.13.2\") {\n\t\tgroup(\"com.google.code.gson\") {\n\t\t\tmodules = [\n\t\t\t\t\"gson\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/google/gson\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/com.google.code.gson/gson/{version}\", \"com.google.gson\")\n\t\t\treleaseNotes(\"https://github.com/google/gson/releases/tag/gson-parent-{version}\")\n\t\t}\n\t}\n\tlibrary(\"H2\", \"2.4.240\") {\n\t\tgroup(\"com.h2database\") {\n\t\t\tmodules = [\n\t\t\t\t\"h2\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.h2database.com\")\n\t\t\tjavadoc(\"https://www.h2database.com/javadoc\", \"org.h2\")\n\t\t\treleaseNotes(\"https://github.com/h2database/h2database/releases/tag/version-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Hamcrest\", \"${hamcrestVersion}\") {\n\t\tgroup(\"org.hamcrest\") {\n\t\t\tmodules = [\n\t\t\t\t\"hamcrest\",\n\t\t\t\t\"hamcrest-core\",\n\t\t\t\t\"hamcrest-library\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/hamcrest/JavaHamcrest/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Hazelcast\", \"5.5.0\") {\n\t\tprohibit {\n\t\t\tversionRange \"[5.6.0,)\"\n\t\t\tbecause \"https://github.com/hazelcast/hazelcast/issues/26546\"\n\t\t}\n\t\tgroup(\"com.hazelcast\") {\n\t\t\tmodules = [\n\t\t\t\t\"hazelcast\",\n\t\t\t\t\"hazelcast-spring\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://hazelcast.com\")\n\t\t\tjavadoc(\"https://docs.hazelcast.org/docs/{version}/javadoc\", \"com.hazelcast\")\n\t\t\treleaseNotes(\"https://github.com/hazelcast/hazelcast/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Hibernate\", \"7.2.7.Final\") {\n\t\tgroup(\"org.hibernate.orm\") {\n\t\t\tmodules = [\n\t\t\t\t\"hibernate-agroal\",\n\t\t\t\t\"hibernate-ant\",\n\t\t\t\t\"hibernate-c3p0\",\n\t\t\t\t\"hibernate-community-dialects\",\n\t\t\t\t\"hibernate-core\",\n\t\t\t\t\"hibernate-envers\",\n\t\t\t\t\"hibernate-graalvm\",\n\t\t\t\t\"hibernate-hikaricp\",\n\t\t\t\t\"hibernate-jcache\",\n\t\t\t\t\"hibernate-micrometer\",\n\t\t\t\t\"hibernate-processor\",\n\t\t\t\t\"hibernate-scan-jandex\",\n\t\t\t\t\"hibernate-spatial\",\n\t\t\t\t\"hibernate-testing\",\n\t\t\t\t\"hibernate-vector\",\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://hibernate.org/orm\")\n\t\t\tjavadoc(version -> \"https://docs.jboss.org/hibernate/orm/%s.%s/javadocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"org.hibernate.boot\", \"org.hibernate.resource\")\n\t\t\tdocs(version -> \"https://hibernate.org/orm/documentation/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\treleaseNotes(version -> \"https://github.com/hibernate/hibernate-orm/releases/tag/%s\"\n\t\t\t\t.formatted(version.toString().replace(\".Final\", \"\")))\n\t\t\tadd(\"userguide\", version -> \"https://docs.jboss.org/hibernate/orm/%s.%s/userguide/html_single/Hibernate_User_Guide.html\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t}\n\t}\n\tlibrary(\"Hibernate Validator\", \"9.1.0.Final\") {\n\t\tgroup(\"org.hibernate.validator\") {\n\t\t\tmodules = [\n\t\t\t\t\"hibernate-validator\",\n\t\t\t\t\"hibernate-validator-annotation-processor\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"HikariCP\", \"7.0.2\") {\n\t\tgroup(\"com.zaxxer\") {\n\t\t\tmodules = [\n\t\t\t\t\"HikariCP\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/brettwooldridge/HikariCP\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/com.zaxxer/HikariCP/{version}/com.zaxxer.hikari\", \"com.zaxxer.hikari\")\n\t\t}\n\t}\n\tlibrary(\"HSQLDB\", \"2.7.3\") {\n\t\tprohibit {\n\t\t\tversionRange \"[2.7.4]\"\n\t\t\tbecause \"it contains a bug that breaks Spring Data (https://sourceforge.net/p/hsqldb/bugs/1725/)\"\n\t\t}\n\t\tgroup(\"org.hsqldb\") {\n\t\t\tmodules = [\n\t\t\t\t\"hsqldb\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"HtmlUnit\", \"4.21.0\") {\n\t\tgroup(\"org.htmlunit\") {\n\t\t\tmodules = [\n\t\t\t\t\"htmlunit\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.htmlunit.org\")\n\t\t\treleaseNotes(\"https://github.com/HtmlUnit/htmlunit/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"HttpAsyncClient\", \"4.1.5\") {\n\t\tprohibit {\n\t\t\tcontains \"-alpha\"\n\t\t\tcontains \"-beta\"\n\t\t\tcontains \"-rc\"\n\t\t\tbecause \"we don't want preview releases\"\n\t\t}\n\t\tgroup(\"org.apache.httpcomponents\") {\n\t\t\tmodules = [\n\t\t\t\t\"httpasyncclient\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"HttpClient5\", \"5.6\") {\n\t\tprohibit {\n\t\t\tcontains \"-alpha\"\n\t\t\tcontains \"-beta\"\n\t\t\tcontains \"-rc\"\n\t\t\tbecause \"we don't want preview releases\"\n\t\t}\n\t\tgroup(\"org.apache.httpcomponents.client5\") {\n\t\t\tmodules = [\n\t\t\t\t\"httpclient5\",\n\t\t\t\t\"httpclient5-cache\",\n\t\t\t\t\"httpclient5-fluent\",\n\t\t\t\t\"httpclient5-observation\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"HttpCore\", \"4.4.16\") {\n\t\tgroup(\"org.apache.httpcomponents\") {\n\t\t\tmodules = [\n\t\t\t\t\"httpcore\",\n\t\t\t\t\"httpcore-nio\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"HttpCore5\", \"5.4.2\") {\n\t\tgroup(\"org.apache.httpcomponents.core5\") {\n\t\t\tmodules = [\n\t\t\t\t\"httpcore5\",\n\t\t\t\t\"httpcore5-h2\",\n\t\t\t\t\"httpcore5-reactive\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Infinispan\", \"16.1.2\") {\n\t\tgroup(\"org.infinispan\") {\n\t\t\tbom(\"infinispan-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://infinispan.org\")\n\t\t\tjavadoc(version -> \"https://docs.jboss.org/infinispan/%s.%s/apidocs\".formatted(version.major(), version.minor()), \"org.infinispan\")\n\t\t\treleaseNotes(\"https://github.com/infinispan/infinispan/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"InfluxDB Java\", \"2.25\") {\n\t\tgroup(\"org.influxdb\") {\n\t\t\tmodules = [\n\t\t\t\t\"influxdb-java\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/influxdata/influxdb-java\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.influxdb/influxdb-java/{version}\", \"org.influxdb\")\n\t\t\treleaseNotes(\"https://github.com/influxdata/influxdb-java/releases/tag/influxdb-java-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jackson 2 Bom\", \"${jackson2Version}\") {\n\t\tgroup(\"com.fasterxml.jackson\") {\n\t\t\tbom(\"jackson-bom\")\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/FasterXML/jackson/wiki/Jackson-Release-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jackson Bom\", \"${jacksonVersion}\") {\n\t\tgroup(\"tools.jackson\") {\n\t\t\tbom(\"jackson-bom\") {\n\t\t\t\tpermit(\"com.fasterxml.jackson.core:jackson-annotations\")\n\t\t\t}\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/FasterXML/jackson/wiki/Jackson-Release-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Activation\", \"2.1.4\") {\n\t\tgroup(\"jakarta.activation\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.activation-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/jakartaee/jaf-api\")\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/activation/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.activation\")\n\t\t\treleaseNotes(\"https://github.com/jakartaee/jaf-api/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Annotation\", \"3.0.0\") {\n\t\tgroup(\"jakarta.annotation\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.annotation-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/annotations/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.annotation\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Inject\", \"2.0.1\") {\n\t\tgroup(\"jakarta.inject\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.inject-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/dependency-injection/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.inject\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta JMS\", \"3.1.0\") {\n\t\tgroup(\"jakarta.jms\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.jms-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(version -> \"https://jakarta.ee/specifications/messaging/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/messaging/%s.%s/apidocs/jakarta.messaging\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.jms\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Json\", \"2.1.3\") {\n\t\tgroup(\"jakarta.json\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.json-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/jsonp/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.json\")\n\t\t\treleaseNotes(\"https://github.com/jakartaee/jsonp-api/releases/tag/{version}-RELEASE\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Json Bind\", \"3.0.1\") {\n\t\tgroup(\"jakarta.json.bind\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.json.bind-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/jsonb/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.json.bind\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Mail\", \"2.1.5\") {\n\t\tgroup(\"jakarta.mail\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.mail-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(version -> \"https://jakarta.ee/specifications/mail/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/mail/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.mail\")\n\t\t\treleaseNotes(\"https://github.com/jakartaee/mail-api/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Management\", \"1.1.4\") {\n\t\tgroup(\"jakarta.management.j2ee\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.management.j2ee-api\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Jakarta Persistence\", \"3.2.0\") {\n\t\tgroup(\"jakarta.persistence\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.persistence-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(version -> \"https://jakarta.ee/specifications/persistence/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/persistence/%s.%s/apidocs/jakarta.persistence\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.persistence\")\n\t\t\treleaseNotes(version -> \"https://github.com/jakartaee/persistence/releases/tag/%s.%s-%s-RELEASE\"\n\t\t\t\t.formatted(version.major(), version.minor(), version))\n\t\t}\n\t}\n\tlibrary(\"Jakarta Servlet\", \"6.1.0\") {\n\t\tgroup(\"jakarta.servlet\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.servlet-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(version -> \"https://jakarta.ee/specifications/servlet/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/servlet/%s.%s/apidocs/jakarta.servlet\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.servlet\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Servlet JSP JSTL\", \"3.0.2\") {\n\t\tgroup(\"jakarta.servlet.jsp.jstl\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.servlet.jsp.jstl-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/jakartaee/tags/releases/tag/{version}-RELEASE\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Transaction\", \"2.0.1\") {\n\t\tgroup(\"jakarta.transaction\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.transaction-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/transactions/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.transaction\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta Validation\", \"3.1.1\") {\n\t\tgroup(\"jakarta.validation\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.validation-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/bean-validation/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.validation\")\n\t\t\treleaseNotes(\"https://github.com/jakartaee/validation/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta WebSocket\", \"2.2.0\") {\n\t\tgroup(\"jakarta.websocket\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.websocket-api\",\n\t\t\t\t\"jakarta.websocket-client-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(\"jakarta-websocket-server\", version -> \"https://jakarta.ee/specifications/websocket/%s.%s/apidocs/server\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.websocket.server\")\n\t\t\tjavadoc(\"jakarta-websocket-client\", version -> \"https://jakarta.ee/specifications/websocket/%s.%s/apidocs/client\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.websocket\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta WS RS\", \"4.0.0\") {\n\t\tgroup(\"jakarta.ws.rs\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.ws.rs-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/restful-ws/%s.%s/apidocs\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.ws.rs\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta XML Bind\", \"4.0.4\") {\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tfrom \"org.glassfish.jaxb:jaxb-core\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"jakarta.xml.bind\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.xml.bind-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/jakartaee/jaxb-api/releases/tag/{version}\")\n\t\t\tjavadoc(version -> \"https://jakarta.ee/specifications/xml-binding/%s.%s/apidocs/jakarta.xml.bind\"\n\t\t\t\t.formatted(version.major(), version.minor()), \"jakarta.xml.bind\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta XML SOAP\", \"3.0.2\") {\n\t\tgroup(\"jakarta.xml.soap\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"jakarta.xml.soap-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/jakartaee/saaj-api/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jakarta XML WS\", \"4.0.3\") {\n\t\tgroup(\"jakarta.xml.ws\") {\n\t\t\tmodules = [\n\t\t\t\t\"jakarta.xml.ws-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/jakartaee/jax-ws-api/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Janino\", \"3.1.12\") {\n\t\tgroup(\"org.codehaus.janino\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-compiler\",\n\t\t\t\t\"commons-compiler-jdk\",\n\t\t\t\t\"janino\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Javax Cache\", \"1.1.1\") {\n\t\tgroup(\"javax.cache\") {\n\t\t\tmodules = [\n\t\t\t\t\"cache-api\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(\"https://javadoc.io/doc/javax.cache/cache-api/{version}\", \"javax.cache\")\n\t\t}\n\t}\n\tlibrary(\"Javax Money\", \"1.1\") {\n\t\tgroup(\"javax.money\") {\n\t\t\tmodules = [\n\t\t\t\t\"money-api\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Jaxen\", \"2.0.0\") {\n\t\tgroup(\"jaxen\") {\n\t\t\tmodules = [\n\t\t\t\t\"jaxen\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/jaxen-xpath/jaxen/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jaybird\", \"6.0.4\") {\n\t\tprohibit {\n\t\t\tendsWith \".java8\"\n\t\t\tbecause \"we use the .java11 version\"\n\t\t}\n\t\tgroup(\"org.firebirdsql.jdbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"jaybird\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(version -> \"https://github.com/FirebirdSQL/jaybird/releases/tag/v%s\"\n\t\t\t\t.formatted(version.toString().replace(\".java11\", \"\")))\n\t\t}\n\t}\n\tlibrary(\"JBoss Logging\", \"3.6.3.Final\") {\n\t\tgroup(\"org.jboss.logging\") {\n\t\t\tmodules = [\n\t\t\t\t\"jboss-logging\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/jboss-logging/jboss-logging/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"JDOM2\", \"2.0.6.1\") {\n\t\tgroup(\"org.jdom\") {\n\t\t\tmodules = [\n\t\t\t\t\"jdom2\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/hunterhacker/jdom/releases/tag/JDOM-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jedis\", \"7.4.0\") {\n\t\talignWith {\n\t\t\tproperty {\n\t\t\t\tname \"jedis\"\n\t\t\t\tof \"org.springframework.data:spring-data-redis\"\n\t\t\t\tmanagedBy \"Spring Data Bom\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"redis.clients\") {\n\t\t\tmodules = [\n\t\t\t\t\"jedis\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/redis/jedis\")\n\t\t\treleaseNotes(\"https://github.com/redis/jedis/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jersey\", \"4.0.2\") {\n\t\tgroup(\"org.glassfish.jersey\") {\n\t\t\tbom(\"jersey-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/eclipse-ee4j/jersey\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.glassfish.jersey.core/jersey-server/{version}\", \"org.glassfish.jersey.server\")\n\t\t\treleaseNotes(\"https://github.com/eclipse-ee4j/jersey/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Jetty Reactive HTTPClient\", \"4.1.4\") {\n\t\tgroup(\"org.eclipse.jetty\") {\n\t\t\tmodules = [\n\t\t\t\t\"jetty-reactive-httpclient\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Jetty\", \"12.1.7\") {\n\t\tprohibit {\n\t\t\tcontains \".alpha\"\n\t\t\tbecause \"we don't want alpha dependencies\"\n\t\t}\n\t\tgroup(\"org.eclipse.jetty.ee11\") {\n\t\t\tbom(\"jetty-ee11-bom\")\n\t\t}\n\t\tgroup(\"org.eclipse.jetty\") {\n\t\t\tbom(\"jetty-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://eclipse.dev/jetty\")\n\t\t\tjavadoc(version -> \"https://javadoc.jetty.org/jetty-%s\".formatted(version.major()), \"org.eclipse.jetty\")\n\t\t\treleaseNotes(\"https://github.com/jetty/jetty.project/releases/tag/jetty-{version}\")\n\t\t}\n\t}\n\tlibrary(\"JMustache\", \"1.16\") {\n\t\tgroup(\"com.samskivert\") {\n\t\t\tmodules = [\n\t\t\t\t\"jmustache\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"jOOQ\", \"3.21.0\") {\n\t\tgroup(\"org.jooq\") {\n\t\t\tbom(\"jooq-bom\")\n\t\t\tplugins = [\n\t\t\t\t\"jooq-codegen-maven\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.jooq.org\")\n\t\t\tjavadoc(\"https://www.jooq.org/javadoc/{version}\", \"org.jooq\")\n\t\t\tdocs(\"https://www.jooq.org/doc/{version}/manual-single-page\")\n\t\t\treleaseNotes(\"https://github.com/jOOQ/jOOQ/releases/tag/version-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Json Path\", \"2.10.0\") {\n\t\tgroup(\"com.jayway.jsonpath\") {\n\t\t\tmodules = [\n\t\t\t\t\"json-path\",\n\t\t\t\t\"json-path-assert\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/json-path/JsonPath\")\n\t\t\treleaseNotes(\"https://github.com/json-path/JsonPath/releases/tag/json-path-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Json-smart\", \"2.6.0\") {\n\t\tgroup(\"net.minidev\") {\n\t\t\tmodules = [\n\t\t\t\t\"json-smart\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/netplex/json-smart-v2\")\n\t\t\treleaseNotes(\"https://github.com/netplex/json-smart-v2/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"JsonAssert\", \"1.5.3\") {\n\t\tprohibit {\n\t\t\tcontains \"-rc\"\n\t\t\tbecause \"we don't want release candidates\"\n\t\t}\n\t\tgroup(\"org.skyscreamer\") {\n\t\t\tmodules = [\n\t\t\t\t\"jsonassert\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/skyscreamer/JSONassert\")\n\t\t\treleaseNotes(\"https://github.com/skyscreamer/JSONassert/releases/tag/jsonassert-{version}\")\n\t\t}\n\t}\n\tlibrary(\"JSpecify\", \"1.0.0\") {\n\t\tgroup(\"org.jspecify\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"jspecify\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://jspecify.dev\")\n\t\t\tdocs(\"https://jspecify.dev/docs/user-guide\")\n\t\t\tjavadoc(\"https://jspecify.dev/docs/api\", \"org.jspecify\")\n\t\t\treleaseNotes(\"https://github.com/jspecify/jspecify/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"JTDS\", \"1.3.1\") {\n\t\tgroup(\"net.sourceforge.jtds\") {\n\t\t\tmodules = [\n\t\t\t\t\"jtds\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"JUnit\", \"4.13.2\") {\n\t\tgroup(\"junit\") {\n\t\t\tmodules = [\n\t\t\t\t\"junit\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/junit-team/junit4/blob/HEAD/doc/ReleaseNotes{version}.md\")\n\t\t}\n\t}\n\tlibrary(\"JUnit Jupiter\", \"${junitJupiterVersion}\") {\n\t\tprohibit {\n\t\t\tcontains \"-M\"\n\t\t\tbecause \"we don't want milestones\"\n\t\t}\n\t\tgroup(\"org.junit\") {\n\t\t\tbom(\"junit-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://junit.org/junit5\")\n\t\t\tjavadoc(\"junit-platform-engine\", version -> \"https://junit.org/junit5/docs/%s/api/org.junit.platform.engine\".formatted(version), \"org.junit.platform\")\n\t\t\tjavadoc(\"junit-jupiter-api\", version -> \"https://junit.org/junit5/docs/%s/api/org.junit.jupiter.api\".formatted(version), \"org.junit.jupiter.api\")\n\t\t\tdocs(\"https://junit.org/junit5/docs/{version}/user-guide\")\n\t\t\treleaseNotes(\"https://junit.org/junit5/docs/{version}/release-notes\")\n\t\t}\n\t}\n\tlibrary(\"Kafka\", \"4.2.0\") {\n\t\tgroup(\"org.apache.kafka\") {\n\t\t\tmodules = [\n\t\t\t\t\"connect\",\n\t\t\t\t\"connect-api\",\n\t\t\t\t\"connect-basic-auth-extension\",\n\t\t\t\t\"connect-file\",\n\t\t\t\t\"connect-json\",\n\t\t\t\t\"connect-mirror\",\n\t\t\t\t\"connect-mirror-client\",\n\t\t\t\t\"connect-runtime\",\n\t\t\t\t\"connect-transforms\",\n\t\t\t\t\"generator\",\n\t\t\t\t\"kafka-clients\",\n\t\t\t\t\"kafka-clients\" {\n\t\t\t\t\tclassifier = \"test\"\n\t\t\t\t},\n\t\t\t\t\"kafka-metadata\",\n\t\t\t\t\"kafka-raft\",\n\t\t\t\t\"kafka-server\",\n\t\t\t\t\"kafka-server-common\",\n\t\t\t\t\"kafka-server-common\" {\n\t\t\t\t\tclassifier = \"test\"\n\t\t\t\t},\n\t\t\t\t\"kafka-shell\",\n\t\t\t\t\"kafka-storage\",\n\t\t\t\t\"kafka-storage-api\",\n\t\t\t\t\"kafka-streams\",\n\t\t\t\t\"kafka-streams-scala_2.13\",\n\t\t\t\t\"kafka-streams-test-utils\",\n\t\t\t\t\"kafka-tools\",\n\t\t\t\t\"kafka_2.13\",\n\t\t\t\t\"kafka_2.13\" {\n\t\t\t\t\tclassifier = \"test\"\n\t\t\t\t},\n\t\t\t\t\"trogdor\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://kafka.apache.org\")\n\t\t\tjavadoc(version -> \"https://kafka.apache.org/%s%s/javadoc\".formatted(version.major(), version.minor()), \"org.apache.kafka\")\n\t\t\treleaseNotes(\"https://downloads.apache.org/kafka/{version}/RELEASE_NOTES.html\")\n\t\t}\n\t}\n\tlibrary(\"Kotlin\", \"${kotlinVersion}\") {\n\t\tgroup(\"org.jetbrains.kotlin\") {\n\t\t\tbom(\"kotlin-bom\")\n\t\t\tplugins = [\n\t\t\t\t\"kotlin-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://kotlinlang.org\")\n\t\t\tdocs(\"https://kotlinlang.org/docs/reference\")\n\t\t\treleaseNotes(\"https://github.com/JetBrains/kotlin/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Kotlin Coroutines\", \"1.10.2\") {\n\t\tgroup(\"org.jetbrains.kotlinx\") {\n\t\t\tbom(\"kotlinx-coroutines-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/Kotlin/kotlinx.coroutines\")\n\t\t\treleaseNotes(\"https://github.com/Kotlin/kotlinx.coroutines/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Kotlin Serialization\", \"1.10.0\") {\n\t\tgroup(\"org.jetbrains.kotlinx\") {\n\t\t\tbom(\"kotlinx-serialization-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/Kotlin/kotlinx.serialization\")\n\t\t\treleaseNotes(\"https://github.com/Kotlin/kotlinx.serialization/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Lettuce\", \"7.5.0.RELEASE\") {\n\t\tprohibit {\n\t\t\tcontains \".BETA\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\talignWith {\n\t\t\tproperty {\n\t\t\t\tname \"lettuce\"\n\t\t\t\tof \"org.springframework.data:spring-data-redis\"\n\t\t\t\tmanagedBy \"Spring Data Bom\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"io.lettuce\") {\n\t\t\tmodules = [\n\t\t\t\t\"lettuce-core\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/redis/lettuce\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/io.lettuce/lettuce-core/{version}\", \"io.lettuce.core\")\n\t\t\tdocs(\"https://redis.github.io/lettuce\")\n\t\t\treleaseNotes(\"https://github.com/redis/lettuce/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Liquibase\", \"5.0.2\") {\n\t\tgroup(\"org.liquibase\") {\n\t\t\tmodules = [\n\t\t\t\t\"liquibase-cdi\",\n\t\t\t\t\"liquibase-core\"\n\t\t\t]\n\t\t\tplugins = [\n\t\t\t\t\"liquibase-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.liquibase.com\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.liquibase/liquibase-core/{version}\", \"liquibase\")\n\t\t\treleaseNotes(\"https://github.com/liquibase/liquibase/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Log4j2\", \"2.25.3\") {\n\t\tprohibit {\n\t\t\tcontains \"-alpha\"\n\t\t\tcontains \"-beta\"\n\t\t\tbecause \"we don't want alphas or betas\"\n\t\t}\n\t\tgroup(\"org.apache.logging.log4j\") {\n\t\t\tbom(\"log4j-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://logging.apache.org/log4j\")\n\t\t\tjavadoc(\"log4j-api\", version -> \"https://logging.apache.org/log4j/%s.x/javadoc/log4j-api\".formatted(version.major()))\n\t\t\tjavadoc(\"log4j-core\", version -> \"https://logging.apache.org/log4j/%s.x/javadoc/log4j-core\".formatted(version.major()), \"org.apache.logging.log4j.core\")\n\t\t\tdocs(version -> \"https://logging.apache.org/log4j/%s.x/manual\".formatted(version.major()))\n\t\t\treleaseNotes(\"https://github.com/apache/logging-log4j2/releases/tag/rel%2F{version}\")\n\t\t}\n\t}\n\tlibrary(\"Logback\", \"1.5.32\") {\n\t\tgroup(\"ch.qos.logback\") {\n\t\t\tmodules = [\n\t\t\t\t\"logback-classic\",\n\t\t\t\t\"logback-core\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://logback.qos.ch\")\n\t\t\tjavadoc(\"https://logback.qos.ch/apidocs/ch.qos.logback.core\", \"ch.qos.logback\")\n\t\t}\n\t}\n\tlibrary(\"Lombok\", \"1.18.44\") {\n\t\tgroup(\"org.projectlombok\") {\n\t\t\tmodules = [\n\t\t\t\t\"lombok\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://projectlombok.org\")\n\t\t\tjavadoc(\"https://projectlombok.org/api\")\n\t\t}\n\t}\n\tlibrary(\"MariaDB\", \"3.5.7\") {\n\t\tgroup(\"org.mariadb.jdbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"mariadb-java-client\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://mariadb.com/kb/en/mariadb-connector-j\")\n\t\t\treleaseNotes(version -> \"https://mariadb.com/kb/en/mariadb-connector-j-%s-release-notes\"\n\t\t\t\t.formatted(version.toString(\"-\")))\n\t\t}\n\t}\n\tlibrary(\"Maven AntRun Plugin\", \"3.2.0\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-antrun-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-antrun-plugin/releases/tag/maven-antrun-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Assembly Plugin\", \"3.8.0\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-assembly-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-assembly-plugin/releases/tag/maven-assembly-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Clean Plugin\", \"3.5.0\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-clean-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-clean-plugin/releases/tag/maven-clean-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Compiler Plugin\", \"3.15.0\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-compiler-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-compiler-plugin/releases/tag/maven-compiler-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Dependency Plugin\", \"3.10.0\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-dependency-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-dependency-plugin/releases/tag/maven-dependency-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Deploy Plugin\", \"3.1.4\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-deploy-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-deploy-plugin/releases/tag/maven-deploy-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Enforcer Plugin\", \"3.6.2\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-enforcer-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-enforcer/releases/tag/enforcer-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Failsafe Plugin\", \"3.5.5\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-failsafe-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-surefire/releases/tag/surefire-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Help Plugin\", \"3.5.1\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-help-plugin\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven Install Plugin\", \"3.1.4\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-install-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-install-plugin/releases/tag/maven-install-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Invoker Plugin\", \"3.9.1\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-invoker-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-invoker-plugin/releases/tag/maven-invoker-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Jar Plugin\", \"3.5.0\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-jar-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-jar-plugin/releases/tag/maven-jar-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Javadoc Plugin\", \"3.12.0\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-javadoc-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-javadoc-plugin/releases/tag/maven-javadoc-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Resources Plugin\", \"3.5.0\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-resources-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-resources-plugin/releases/tag/maven-resources-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Shade Plugin\", \"3.6.2\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-shade-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-shade-plugin/releases/tag/maven-shade-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Source Plugin\", \"3.4.0\") {\n\t\tprohibit {\n\t\t\tcontains \"-beta-\"\n\t\t\tbecause \"we don't want betas\"\n\t\t}\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-source-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-source-plugin/releases/tag/maven-source-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven Surefire Plugin\", \"3.5.5\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-surefire-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-surefire/releases/tag/surefire-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Maven War Plugin\", \"3.5.1\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tplugins = [\n\t\t\t\t\"maven-war-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/apache/maven-war-plugin/releases/tag/maven-war-plugin-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Micrometer\", \"1.17.0-M3\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"io.micrometer\") {\n\t\t\tmodules = [\n\t\t\t\t\"micrometer-registry-stackdriver\" {\n\t\t\t\t\texclude group: \"javax.annotation\", module: \"javax.annotation-api\"\n\t\t\t\t}\n\t\t\t]\n\t\t\tbom(\"micrometer-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://micrometer.io\")\n\t\t\tjavadoc(\"micrometer-core\", version -> \"https://javadoc.io/doc/io.micrometer/micrometer-core/%s\".formatted(version), \"io.micrometer.core\")\n\t\t\tjavadoc(\"micrometer-observation\", version -> \"https://javadoc.io/doc/io.micrometer/micrometer-observation/%s\".formatted(version), \"io.micrometer.observation\")\n\t\t\tjavadoc(\"micrometer-registry-graphite\", version -> \"https://javadoc.io/doc/io.micrometer/micrometer-registry-graphite/%s\".formatted(version), \"io.micrometer.graphite\")\n\t\t\tjavadoc(\"micrometer-registry-otlp\", version -> \"https://javadoc.io/doc/io.micrometer/micrometer-registry-otlp/%s\".formatted(version), \"io.micrometer.registry.otlp\")\n\t\t\tjavadoc(\"micrometer-registry-jmx\", version -> \"https://javadoc.io/doc/io.micrometer/micrometer-registry-jmx/%s\".formatted(version), \"io.micrometer.jmx\")\n\t\t\tjavadoc(\"micrometer-new-relic\", version -> \"https://javadoc.io/doc/io.micrometer/micrometer-registry-new-relic/%s\".formatted(version), \"io.micrometer.newrelic\")\n\t\t\tdocs(version -> \"https://docs.micrometer.io/micrometer/reference/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\treleaseNotes(\"https://github.com/micrometer-metrics/micrometer/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Micrometer Tracing\", \"1.7.0-M4\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"io.micrometer\") {\n\t\t\tbom(\"micrometer-tracing-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://micrometer.io\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/io.micrometer/micrometer-tracing/{version}\", \"io.micrometer.tracing\")\n\t\t\tdocs(version -> \"https://docs.micrometer.io/tracing/reference/%s.%s\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\treleaseNotes(\"https://github.com/micrometer-metrics/tracing/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Mockito\", \"${mockitoVersion}\") {\n\t\tgroup(\"org.mockito\") {\n\t\t\tbom(\"mockito-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://site.mockito.org\")\n\t\t\treleaseNotes(\"https://github.com/mockito/mockito/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"MongoDB\", \"5.7.0-beta1\") {\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tof \"org.mongodb:mongodb-driver-core\"\n\t\t\t\tfrom \"org.springframework.data:spring-data-mongodb\"\n\t\t\t\tmanagedBy \"Spring Data Bom\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"org.mongodb\") {\n\t\t\tbom(\"mongodb-driver-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/mongodb/mongo-java-driver\")\n\t\t\t// Mongo has split packages so we can't use them\n\t\t\tjavadoc(\"mongodb-driver-core\", version -> \"https://mongodb.github.io/mongo-java-driver/%s.%s/apidocs/mongodb-driver-core\".formatted(version.major(), version.minor()))\n\t\t\tjavadoc(\"mongodb-driver-sync\", version -> \"https://mongodb.github.io/mongo-java-driver/%s.%s/apidocs/mongodb-driver-sync\".formatted(version.major(), version.minor()))\n\t\t\treleaseNotes(\"https://github.com/mongodb/mongo-java-driver/releases/tag/r{version}\")\n\t\t}\n\t}\n\tlibrary(\"MSSQL JDBC\", \"13.4.0.jre11\") {\n\t\tprohibit {\n\t\t\tendsWith(\".jre8\")\n\t\t\tbecause \"we want to use the jre11 version\"\n\t\t}\n\t\tprohibit {\n\t\t\tendsWith(\"-preview\")\n\t\t\tbecause \"we only want to use non-preview releases\"\n\t\t}\n\t\tgroup(\"com.microsoft.sqlserver\") {\n\t\t\tmodules = [\n\t\t\t\t\"mssql-jdbc\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/microsoft/mssql-jdbc\")\n\t\t\treleaseNotes(version -> \"https://github.com/microsoft/mssql-jdbc/releases/tag/v%s\"\n\t\t\t\t.formatted(version.toString().replace(\".jre11\", \"\")))\n\t\t}\n\t}\n\tlibrary(\"MySQL\", \"9.6.0\") {\n\t\tupgradePolicy = \"same-major-version\"\n\t\tgroup(\"com.mysql\") {\n\t\t\tmodules = [\n\t\t\t\t\"mysql-connector-j\" {\n\t\t\t\t\texclude group: \"com.google.protobuf\", module: \"protobuf-java\"\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(version -> \"https://dev.mysql.com/doc/relnotes/connector-j/en/news-%s.html\"\n\t\t\t\t.formatted(version.toString().replace(\".\", \"-\")))\n\t\t}\n\t}\n\tlibrary(\"Native Build Tools Plugin\", \"${nativeBuildToolsVersion}\") {\n\t\tgroup(\"org.graalvm.buildtools\") {\n\t\t\tplugins = [\n\t\t\t\t\t\"native-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/graalvm/native-build-tools\")\n\t\t\treleaseNotes(\"https://github.com/graalvm/native-build-tools/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"NekoHTML\", \"1.9.22\") {\n\t\tgroup(\"net.sourceforge.nekohtml\") {\n\t\t\tmodules = [\n\t\t\t\t\"nekohtml\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Neo4j Java Driver\", \"6.0.3\") {\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tof \"org.neo4j.driver:neo4j-java-driver\"\n\t\t\t\tfrom \"org.springframework.data:spring-data-neo4j\"\n\t\t\t\tmanagedBy \"Spring Data Bom\"\n\t\t\t}\n\t\t}\n\t\tgroup(\"org.neo4j.driver\") {\n\t\t\tbom(\"neo4j-java-driver-bom\") {\n\t\t\t\tpermit(\"org.neo4j.bolt:neo4j-bolt-connection-netty\")\n\t\t\t\tpermit(\"org.neo4j.bolt:neo4j-bolt-connection-pooled\")\n\t\t\t\tpermit(\"org.neo4j.bolt:neo4j-bolt-connection-query-api\")\n\t\t\t\tpermit(\"org.neo4j.bolt:neo4j-bolt-connection-routed\")\n\t\t\t\tpermit(\"org.neo4j.bolt:neo4j-bolt-connection\")\n\t\t\t}\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/neo4j/neo4j-java-driver\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.neo4j.driver/neo4j-java-driver/{version}\", \"org.neo4j.driver\")\n\t\t\treleaseNotes(\"https://github.com/neo4j/neo4j-java-driver/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Netty\", \"4.2.12.Final\") {\n\t\tprohibit {\n\t\t\tcontains \".Alpha\"\n\t\t\tcontains \".Beta\"\n\t\t\tcontains \".RC\"\n\t\t\tbecause \"we don't want alphas, betas, or release candidates\"\n\t\t}\n\t\tgroup(\"io.netty\") {\n\t\t\tbom(\"netty-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://netty.io\")\n\t\t\tjavadoc(version -> \"https://netty.io/%s.%s/api\".formatted(version.major(), version.minor()), \"io.netty\")\n\t\t}\n\t}\n\tlibrary(\"OpenTelemetry\", \"1.59.0\") {\n\t\tgroup(\"io.opentelemetry\") {\n\t\t\tbom(\"opentelemetry-bom\")\n\t\t}\n\t\talignWith {\n\t\t\tversion {\n\t\t\t\tof \"io.opentelemetry:opentelemetry-api\"\n\t\t\t\tfrom \"io.micrometer:micrometer-tracing-bridge-otel\"\n\t\t\t\tmanagedBy \"Micrometer Tracing\"\n\t\t\t}\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/open-telemetry/opentelemetry-java\")\n\t\t\tjavadoc(\"opentelemetry-api\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-api/%s\".formatted(version), \"io.opentelemetry.api\")\n\t\t\tjavadoc(\"opentelemetry-context\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-context/%s\".formatted(version), \"io.opentelemetry.context\")\n\t\t\tjavadoc(\"opentelemetry-sdk-common\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-common/%s\".formatted(version), \"io.opentelemetry.sdk.common\", \"io.opentelemetry.sdk.resources\")\n\t\t\tjavadoc(\"opentelemetry-sdk-logs\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-logs/%s\".formatted(version), \"io.opentelemetry.sdk.logs\")\n\t\t\tjavadoc(\"opentelemetry-sdk-metrics\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-metrics/%s\".formatted(version), \"io.opentelemetry.sdk.metrics\")\n\t\t\tjavadoc(\"opentelemetry-sdk-trace\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-trace/%s\".formatted(version), \"io.opentelemetry.sdk.trace\")\n\t\t\tjavadoc(\"opentelemetry-exporter-otlp\", version -> \"https://javadoc.io/doc/io.opentelemetry/opentelemetry-exporter-otlp/%s\".formatted(version), \"io.opentelemetry.exporter.otlp\")\n\t\t\treleaseNotes(\"https://github.com/open-telemetry/opentelemetry-java/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Oracle Database\", \"23.26.1.0.0\") {\n\t\talignWith {\n\t\t\tdependencyManagementDeclaredIn(\"com.oracle.database.jdbc:ojdbc-bom\")\n\t\t}\n\t\tgroup(\"com.oracle.database.ha\") {\n\t\t\tmodules = [\n\t\t\t\t\"ons\",\n\t\t\t\t\"simplefan\"\n\t\t\t]\n\t\t}\n\t\tgroup(\"com.oracle.database.jdbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"ojdbc11\",\n\t\t\t\t\"ojdbc11-production\",\n\t\t\t\t\"ojdbc17\",\n\t\t\t\t\"ojdbc17-production\",\n\t\t\t\t\"ojdbc8\",\n\t\t\t\t\"ojdbc8-production\",\n\t\t\t\t\"rsi\",\n\t\t\t\t\"ucp\",\n\t\t\t\t\"ucp11\",\n\t\t\t\t\"ucp17\"\n\t\t\t]\n\t\t}\n\t\tgroup(\"com.oracle.database.nls\") {\n\t\t\tmodules = [\n\t\t\t\t\"orai18n\"\n\t\t\t]\n\t\t}\n\t\tgroup(\"com.oracle.database.security\") {\n\t\t\tmodules = [\n\t\t\t\t\"oraclepki\"\n\t\t\t]\n\t\t}\n\t\tgroup(\"com.oracle.database.xml\") {\n\t\t\tmodules = [\n\t\t\t\t\"xdb\",\n\t\t\t\t\"xmlparserv2\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Oracle R2DBC\", \"1.3.0\") {\n\t\tgroup(\"com.oracle.database.r2dbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"oracle-r2dbc\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/oracle/oracle-r2dbc/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Protobuf Maven Plugin\", \"5.1.0\") {\n\t\tgroup(\"io.github.ascopes\") {\n\t\t\tplugins = [\n\t\t\t\t\"protobuf-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/ascopes/protobuf-maven-plugin\")\n\t\t\treleaseNotes(\"https://github.com/ascopes/protobuf-maven-plugin/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Pooled JMS\", \"3.2.2\") {\n\t\tgroup(\"org.messaginghub\") {\n\t\t\tmodules = [\n\t\t\t\t\"pooled-jms\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.messaginghub/pooled-jms/{version}\", \"org.messaginghub.pooled.jms\")\n\t\t}\n\t}\n\tlibrary(\"Postgresql\", \"42.7.10\") {\n\t\tgroup(\"org.postgresql\") {\n\t\t\tmodules = [\n\t\t\t\t\"postgresql\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/pgjdbc/pgjdbc\")\n\t\t\tjavadoc(\"https://jdbc.postgresql.org/documentation/publicapi\", \"org.postgresql\")\n\t\t\treleaseNotes(\"https://github.com/pgjdbc/pgjdbc/releases/tag/REL{version}\")\n\t\t}\n\t}\n\tlibrary(\"Prometheus Client\", \"1.5.1\") {\n\t\tgroup(\"io.prometheus\") {\n\t\t\tbom(\"prometheus-metrics-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/prometheus/client_java\")\n\t\t\tjavadoc(\"prometheus-metrics-tracer-common\", (version) -> \"https://javadoc.io/doc/io.prometheus/prometheus-metrics-tracer-common/%s\".formatted(version), \"io.prometheus.metrics.tracer.common\")\n\t\t\treleaseNotes(\"https://github.com/prometheus/client_java/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Prometheus Simpleclient\", \"0.16.0\") {\n\t\tgroup(\"io.prometheus\") {\n\t\t\tbom(\"simpleclient_bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/prometheus/client_java\")\n\t\t\tjavadoc(\"prometheus-simpleclient-tracer-common\", (version) -> \"https://javadoc.io/doc/io.prometheus/simpleclient_tracer_common/%s\".formatted(version), \"io.prometheus.client.exemplars.tracer.common\")\n\t\t\treleaseNotes(\"https://github.com/prometheus/client_java/releases/tag/parent-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Pulsar\", \"4.1.3\") {\n\t\tgroup(\"org.apache.pulsar\") {\n\t\t\tbom(\"pulsar-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://pulsar.apache.org\")\n\t\t\tdocs(version -> \"https://pulsar.apache.org/docs/%s.%s.x\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t\treleaseNotes(\"https://pulsar.apache.org/release-notes/versioned/pulsar-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Qpid ProtonJ2\", \"1.1.0\") {\n\t\tgroup(\"org.apache.qpid\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"protonj2\",\n\t\t\t\t\t\"protonj2-client\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://qpid.apache.org/proton\")\n\t\t\tjavadoc(\"https://qpid.apache.org/releases/qpid-protonj2-{version}/api\", \"org.apache.qpid.protonj2\")\n\t\t\treleaseNotes(\"https://qpid.apache.org/releases/qpid-protonj2-{version}/release-notes.html\")\n\t\t}\n\t}\n\tlibrary(\"Protobuf Common Protos\", \"2.67.0\") {\n\t\tgroup(\"com.google.api.grpc\") {\n\t\t\tmodules = [\n\t\t\t\t\"proto-google-common-protos\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tgithub(\"https://github.com/googleapis/sdk-platform-java\")\n\t\t\treleaseNotes(\"https://github.com/googleapis/sdk-platform-java/releases/tag/v-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Protobuf Java\", \"4.34.1\") {\n\t\tgroup(\"com.google.protobuf\") {\n\t\t\tbom(\"protobuf-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://protobuf.dev\")\n\t\t\tgithub(\"https://github.com/protocolbuffers/protobuf\")\n\t\t\treleaseNotes(\"https://github.com/protocolbuffers/protobuf/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Quartz\", \"2.5.2\") {\n\t\tgroup(\"org.quartz-scheduler\") {\n\t\t\tmodules = [\n\t\t\t\t\"quartz\",\n\t\t\t\t\"quartz-jobs\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/quartz-scheduler/quartz\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/org.quartz-scheduler/quartz/{version}\", \"org.quartz\")\n\t\t\treleaseNotes(\"https://github.com/quartz-scheduler/quartz/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"QueryDSL\", \"5.1.0\") {\n\t\tgroup(\"com.querydsl\") {\n\t\t\tbom(\"querydsl-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/querydsl/querydsl\")\n\t\t\treleaseNotes(version -> \"https://github.com/querydsl/querydsl/releases/tag/QUERYDSL_%s\"\n\t\t\t\t.formatted(version.toString(\"_\")))\n\t\t}\n\t}\n\tlibrary(\"R2DBC H2\", \"1.1.0.RELEASE\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"io.r2dbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-h2\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/r2dbc/r2dbc-h2/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC MariaDB\", \"1.4.0\") {\n\t\tgroup(\"org.mariadb\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-mariadb\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/mariadb-corporation/mariadb-connector-r2dbc/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC MSSQL\", \"1.0.4.RELEASE\") {\n\t\tgroup (\"io.r2dbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-mssql\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/r2dbc/r2dbc-mssql/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC MySQL\", \"1.4.1\") {\n\t\tgroup(\"io.asyncer\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-mysql\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/asyncer-io/r2dbc-mysql/releases/tag/r2dbc-mysql-{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC Pool\", \"1.0.2.RELEASE\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"io.r2dbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-pool\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/r2dbc/r2dbc-pool\")\n\t\t\treleaseNotes(\"https://github.com/r2dbc/r2dbc-pool/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC Postgresql\", \"1.1.1.RELEASE\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.postgresql\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-postgresql\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/pgjdbc/r2dbc-postgresql/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC Proxy\", \"1.1.6.RELEASE\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"io.r2dbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-proxy\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/r2dbc/r2dbc-proxy/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"R2DBC SPI\", \"1.0.0.RELEASE\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"io.r2dbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"r2dbc-spi\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://r2dbc.io\")\n\t\t\tjavadoc(\"https://r2dbc.io/spec/{version}/api\", \"io.r2dbc\")\n\t\t\treleaseNotes(\"https://github.com/r2dbc/r2dbc-spi/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Rabbit AMQP Client\", \"5.29.0\") {\n\t\tgroup(\"com.rabbitmq\") {\n\t\t\tmodules = [\n\t\t\t\t\"amqp-client\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/rabbitmq/rabbitmq-java-client\")\n\t\t\tjavadoc(\"https://rabbitmq.github.io/rabbitmq-java-client/api/current\", \"com.rabbitmq\")\n\t\t\treleaseNotes(\"https://github.com/rabbitmq/rabbitmq-java-client/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Rabbit Stream Client\", \"1.5.0\") {\n\t\tgroup(\"com.rabbitmq\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"stream-client\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/rabbitmq/rabbitmq-stream-java-client\")\n\t\t\treleaseNotes(\"https://github.com/rabbitmq/rabbitmq-stream-java-client/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Reactive Streams\", \"1.0.4\") {\n\t\tgroup(\"org.reactivestreams\") {\n\t\t\tmodules = [\n\t\t\t\t\"reactive-streams\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Reactor Bom\", \"2025.0.4\") {\n\t\tconsiderSnapshots()\n\t\tcalendarName = \"Reactor\"\n\t\tgroup(\"io.projectreactor\") {\n\t\t\tbom(\"reactor-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://projectreactor.io\")\n\t\t\treleaseNotes(\"https://github.com/reactor/reactor/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"RSocket\", \"1.1.5\") {\n\t\tgroup(\"io.rsocket\") {\n\t\t\tbom(\"rsocket-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/rsocket/rsocket-java\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/io.rsocket/rsocket-core/{version}\", \"io.rsocket\")\n\t\t\treleaseNotes(\"https://github.com/rsocket/rsocket-java/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"RxJava3\", \"3.1.12\") {\n\t\tgroup(\"io.reactivex.rxjava3\") {\n\t\t\tmodules = [\n\t\t\t\t\"rxjava\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/ReactiveX/RxJava/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Boot\", \"${version}\") {\n\t\tgroup(\"org.springframework.boot\") {\n\t\t\tmodules = [\n\t\t\t\t\"spring-boot\",\n\t\t\t\t\"spring-boot-activemq\",\n\t\t\t\t\"spring-boot-actuator\",\n\t\t\t\t\"spring-boot-actuator-autoconfigure\",\n\t\t\t\t\"spring-boot-amqp\",\n\t\t\t\t\"spring-boot-artemis\",\n\t\t\t\t\"spring-boot-autoconfigure\",\n\t\t\t\t\"spring-boot-autoconfigure-classic\",\n\t\t\t\t\"spring-boot-autoconfigure-classic-modules\",\n\t\t\t\t\"spring-boot-autoconfigure-processor\",\n\t\t\t\t\"spring-boot-batch\",\n\t\t\t\t\"spring-boot-batch-jdbc\",\n\t\t\t\t\"spring-boot-buildpack-platform\",\n\t\t\t\t\"spring-boot-cache\",\n\t\t\t\t\"spring-boot-cache-test\",\n\t\t\t\t\"spring-boot-cassandra\",\n\t\t\t\t\"spring-boot-cloudfoundry\",\n\t\t\t\t\"spring-boot-configuration-metadata\",\n\t\t\t\t\"spring-boot-configuration-processor\",\n\t\t\t\t\"spring-boot-couchbase\",\n\t\t\t\t\"spring-boot-data-cassandra\",\n\t\t\t\t\"spring-boot-data-cassandra-test\",\n\t\t\t\t\"spring-boot-data-commons\",\n\t\t\t\t\"spring-boot-data-couchbase\",\n\t\t\t\t\"spring-boot-data-couchbase-test\",\n\t\t\t\t\"spring-boot-data-elasticsearch\",\n\t\t\t\t\"spring-boot-data-elasticsearch-test\",\n\t\t\t\t\"spring-boot-data-jdbc\",\n\t\t\t\t\"spring-boot-data-jdbc-test\",\n\t\t\t\t\"spring-boot-data-jpa\",\n\t\t\t\t\"spring-boot-data-jpa-test\",\n\t\t\t\t\"spring-boot-data-ldap\",\n\t\t\t\t\"spring-boot-data-ldap-test\",\n\t\t\t\t\"spring-boot-data-mongodb\",\n\t\t\t\t\"spring-boot-data-mongodb-test\",\n\t\t\t\t\"spring-boot-data-neo4j\",\n\t\t\t\t\"spring-boot-data-neo4j-test\",\n\t\t\t\t\"spring-boot-data-r2dbc\",\n\t\t\t\t\"spring-boot-data-r2dbc-test\",\n\t\t\t\t\"spring-boot-data-redis\",\n\t\t\t\t\"spring-boot-data-redis-test\",\n\t\t\t\t\"spring-boot-data-rest\",\n\t\t\t\t\"spring-boot-devtools\",\n\t\t\t\t\"spring-boot-docker-compose\",\n\t\t\t\t\"spring-boot-elasticsearch\",\n\t\t\t\t\"spring-boot-flyway\",\n\t\t\t\t\"spring-boot-freemarker\",\n\t\t\t\t\"spring-boot-graphql\",\n\t\t\t\t\"spring-boot-graphql-test\",\n\t\t\t\t\"spring-boot-grpc-client\",\n\t\t\t\t\"spring-boot-grpc-server\",\n\t\t\t\t\"spring-boot-grpc-test\",\n\t\t\t\t\"spring-boot-groovy-templates\",\n\t\t\t\t\"spring-boot-gson\",\n\t\t\t\t\"spring-boot-h2console\",\n\t\t\t\t\"spring-boot-hateoas\",\n\t\t\t\t\"spring-boot-hazelcast\",\n\t\t\t\t\"spring-boot-health\",\n\t\t\t\t\"spring-boot-hibernate\",\n\t\t\t\t\"spring-boot-http-client\",\n\t\t\t\t\"spring-boot-http-codec\",\n\t\t\t\t\"spring-boot-http-converter\",\n\t\t\t\t\"spring-boot-integration\",\n\t\t\t\t\"spring-boot-jackson\",\n\t\t\t\t\"spring-boot-jackson2\",\n\t\t\t\t\"spring-boot-jarmode-tools\",\n\t\t\t\t\"spring-boot-jdbc\",\n\t\t\t\t\"spring-boot-jdbc-test\",\n\t\t\t\t\"spring-boot-jersey\",\n\t\t\t\t\"spring-boot-jetty\",\n\t\t\t\t\"spring-boot-jms\",\n\t\t\t\t\"spring-boot-jooq\",\n\t\t\t\t\"spring-boot-jooq-test\",\n\t\t\t\t\"spring-boot-jpa\",\n\t\t\t\t\"spring-boot-jpa-test\",\n\t\t\t\t\"spring-boot-jsonb\",\n\t\t\t\t\"spring-boot-kafka\",\n\t\t\t\t\"spring-boot-kotlinx-serialization-json\",\n\t\t\t\t\"spring-boot-ldap\",\n\t\t\t\t\"spring-boot-liquibase\",\n\t\t\t\t\"spring-boot-loader\",\n\t\t\t\t\"spring-boot-mail\",\n\t\t\t\t\"spring-boot-micrometer-metrics\",\n\t\t\t\t\"spring-boot-micrometer-metrics-test\",\n\t\t\t\t\"spring-boot-micrometer-observation\",\n\t\t\t\t\"spring-boot-micrometer-tracing\",\n\t\t\t\t\"spring-boot-micrometer-tracing-brave\",\n\t\t\t\t\"spring-boot-micrometer-tracing-opentelemetry\",\n\t\t\t\t\"spring-boot-micrometer-tracing-test\",\n\t\t\t\t\"spring-boot-mongodb\",\n\t\t\t\t\"spring-boot-mustache\",\n\t\t\t\t\"spring-boot-neo4j\",\n\t\t\t\t\"spring-boot-netty\",\n\t\t\t\t\"spring-boot-opentelemetry\",\n\t\t\t\t\"spring-boot-persistence\",\n\t\t\t\t\"spring-boot-properties-migrator\",\n\t\t\t\t\"spring-boot-pulsar\",\n\t\t\t\t\"spring-boot-quartz\",\n\t\t\t\t\"spring-boot-r2dbc\",\n\t\t\t\t\"spring-boot-reactor\",\n\t\t\t\t\"spring-boot-reactor-netty\",\n\t\t\t\t\"spring-boot-restclient\",\n\t\t\t\t\"spring-boot-restclient-test\",\n\t\t\t\t\"spring-boot-restdocs\",\n\t\t\t\t\"spring-boot-resttestclient\",\n\t\t\t\t\"spring-boot-rsocket\",\n\t\t\t\t\"spring-boot-rsocket-test\",\n\t\t\t\t\"spring-boot-security\",\n\t\t\t\t\"spring-boot-security-oauth2-authorization-server\",\n\t\t\t\t\"spring-boot-security-oauth2-client\",\n\t\t\t\t\"spring-boot-security-oauth2-resource-server\",\n\t\t\t\t\"spring-boot-security-saml2\",\n\t\t\t\t\"spring-boot-security-test\",\n\t\t\t\t\"spring-boot-sendgrid\",\n\t\t\t\t\"spring-boot-servlet\",\n\t\t\t\t\"spring-boot-session\",\n\t\t\t\t\"spring-boot-session-data-redis\",\n\t\t\t\t\"spring-boot-session-jdbc\",\n\t\t\t\t\"spring-boot-sql\",\n\t\t\t\t\"spring-boot-starter\",\n\t\t\t\t\"spring-boot-starter-activemq\",\n\t\t\t\t\"spring-boot-starter-activemq-test\",\n\t\t\t\t\"spring-boot-starter-actuator\",\n\t\t\t\t\"spring-boot-starter-actuator-test\",\n\t\t\t\t\"spring-boot-starter-amqp\",\n\t\t\t\t\"spring-boot-starter-amqp-test\",\n\t\t\t\t\"spring-boot-starter-artemis\",\n\t\t\t\t\"spring-boot-starter-artemis-test\",\n\t\t\t\t\"spring-boot-starter-aspectj\",\n\t\t\t\t\"spring-boot-starter-aspectj-test\",\n\t\t\t\t\"spring-boot-starter-batch\",\n\t\t\t\t\"spring-boot-starter-batch-jdbc\",\n\t\t\t\t\"spring-boot-starter-batch-jdbc-test\",\n\t\t\t\t\"spring-boot-starter-batch-test\",\n\t\t\t\t\"spring-boot-starter-cache\",\n\t\t\t\t\"spring-boot-starter-cache-test\",\n\t\t\t\t\"spring-boot-starter-cassandra\",\n\t\t\t\t\"spring-boot-starter-cassandra-test\",\n\t\t\t\t\"spring-boot-starter-classic\",\n\t\t\t\t\"spring-boot-starter-cloudfoundry\",\n\t\t\t\t\"spring-boot-starter-cloudfoundry-test\",\n\t\t\t\t\"spring-boot-starter-couchbase\",\n\t\t\t\t\"spring-boot-starter-couchbase-test\",\n\t\t\t\t\"spring-boot-starter-data-cassandra\",\n\t\t\t\t\"spring-boot-starter-data-cassandra-test\",\n\t\t\t\t\"spring-boot-starter-data-cassandra-reactive\",\n\t\t\t\t\"spring-boot-starter-data-cassandra-reactive-test\",\n\t\t\t\t\"spring-boot-starter-data-couchbase\",\n\t\t\t\t\"spring-boot-starter-data-couchbase-test\",\n\t\t\t\t\"spring-boot-starter-data-couchbase-reactive\",\n\t\t\t\t\"spring-boot-starter-data-couchbase-reactive-test\",\n\t\t\t\t\"spring-boot-starter-data-elasticsearch\",\n\t\t\t\t\"spring-boot-starter-data-elasticsearch-test\",\n\t\t\t\t\"spring-boot-starter-data-jdbc\",\n\t\t\t\t\"spring-boot-starter-data-jdbc-test\",\n\t\t\t\t\"spring-boot-starter-data-jpa\",\n\t\t\t\t\"spring-boot-starter-data-jpa-test\",\n\t\t\t\t\"spring-boot-starter-data-ldap\",\n\t\t\t\t\"spring-boot-starter-data-ldap-test\",\n\t\t\t\t\"spring-boot-starter-data-mongodb\",\n\t\t\t\t\"spring-boot-starter-data-mongodb-test\",\n\t\t\t\t\"spring-boot-starter-data-mongodb-reactive\",\n\t\t\t\t\"spring-boot-starter-data-mongodb-reactive-test\",\n\t\t\t\t\"spring-boot-starter-data-neo4j\",\n\t\t\t\t\"spring-boot-starter-data-neo4j-test\",\n\t\t\t\t\"spring-boot-starter-data-r2dbc\",\n\t\t\t\t\"spring-boot-starter-data-r2dbc-test\",\n\t\t\t\t\"spring-boot-starter-data-redis\",\n\t\t\t\t\"spring-boot-starter-data-redis-test\",\n\t\t\t\t\"spring-boot-starter-data-redis-reactive\",\n\t\t\t\t\"spring-boot-starter-data-redis-reactive-test\",\n\t\t\t\t\"spring-boot-starter-data-rest\",\n\t\t\t\t\"spring-boot-starter-data-rest-test\",\n\t\t\t\t\"spring-boot-starter-elasticsearch\",\n\t\t\t\t\"spring-boot-starter-elasticsearch-test\",\n\t\t\t\t\"spring-boot-starter-flyway\",\n\t\t\t\t\"spring-boot-starter-flyway-test\",\n\t\t\t\t\"spring-boot-starter-freemarker\",\n\t\t\t\t\"spring-boot-starter-freemarker-test\",\n\t\t\t\t\"spring-boot-starter-graphql\",\n\t\t\t\t\"spring-boot-starter-graphql-test\",\n\t\t\t\t\"spring-boot-starter-grpc-client\",\n\t\t\t\t\"spring-boot-starter-grpc-server\",\n\t\t\t\t\"spring-boot-starter-grpc-test\",\n\t\t\t\t\"spring-boot-starter-groovy-templates\",\n\t\t\t\t\"spring-boot-starter-groovy-templates-test\",\n\t\t\t\t\"spring-boot-starter-gson\",\n\t\t\t\t\"spring-boot-starter-gson-test\",\n\t\t\t\t\"spring-boot-starter-hateoas\",\n\t\t\t\t\"spring-boot-starter-hateoas-test\",\n\t\t\t\t\"spring-boot-starter-hazelcast\",\n\t\t\t\t\"spring-boot-starter-hazelcast-test\",\n\t\t\t\t\"spring-boot-starter-integration\",\n\t\t\t\t\"spring-boot-starter-integration-test\",\n\t\t\t\t\"spring-boot-starter-jackson\",\n\t\t\t\t\"spring-boot-starter-jackson-test\",\n\t\t\t\t\"spring-boot-starter-jdbc\",\n\t\t\t\t\"spring-boot-starter-jdbc-test\",\n\t\t\t\t\"spring-boot-starter-jersey\",\n\t\t\t\t\"spring-boot-starter-jersey-test\",\n\t\t\t\t\"spring-boot-starter-jetty\",\n\t\t\t\t\"spring-boot-starter-jetty-runtime\",\n\t\t\t\t\"spring-boot-starter-jms\",\n\t\t\t\t\"spring-boot-starter-jms-test\",\n\t\t\t\t\"spring-boot-starter-jooq\",\n\t\t\t\t\"spring-boot-starter-jooq-test\",\n\t\t\t\t\"spring-boot-starter-json\",\n\t\t\t\t\"spring-boot-starter-jsonb\",\n\t\t\t\t\"spring-boot-starter-jsonb-test\",\n\t\t\t\t\"spring-boot-starter-kafka\",\n\t\t\t\t\"spring-boot-starter-kafka-test\",\n\t\t\t\t\"spring-boot-starter-kotlinx-serialization-json\",\n\t\t\t\t\"spring-boot-starter-kotlinx-serialization-json-test\",\n\t\t\t\t\"spring-boot-starter-ldap\",\n\t\t\t\t\"spring-boot-starter-ldap-test\",\n\t\t\t\t\"spring-boot-starter-liquibase\",\n\t\t\t\t\"spring-boot-starter-liquibase-test\",\n\t\t\t\t\"spring-boot-starter-log4j2\",\n\t\t\t\t\"spring-boot-starter-logback\",\n\t\t\t\t\"spring-boot-starter-logging\",\n\t\t\t\t\"spring-boot-starter-mail\",\n\t\t\t\t\"spring-boot-starter-mail-test\",\n\t\t\t\t\"spring-boot-starter-micrometer-metrics\",\n\t\t\t\t\"spring-boot-starter-micrometer-metrics-test\",\n\t\t\t\t\"spring-boot-starter-mongodb\",\n\t\t\t\t\"spring-boot-starter-mongodb-test\",\n\t\t\t\t\"spring-boot-starter-mustache\",\n\t\t\t\t\"spring-boot-starter-mustache-test\",\n\t\t\t\t\"spring-boot-starter-neo4j\",\n\t\t\t\t\"spring-boot-starter-neo4j-test\",\n\t\t\t\t\"spring-boot-starter-oauth2-authorization-server\",\n\t\t\t\t\"spring-boot-starter-oauth2-client\",\n\t\t\t\t\"spring-boot-starter-oauth2-resource-server\",\n\t\t\t\t\"spring-boot-starter-opentelemetry\",\n\t\t\t\t\"spring-boot-starter-opentelemetry-test\",\n\t\t\t\t\"spring-boot-starter-pulsar\",\n\t\t\t\t\"spring-boot-starter-pulsar-test\",\n\t\t\t\t\"spring-boot-starter-quartz\",\n\t\t\t\t\"spring-boot-starter-quartz-test\",\n\t\t\t\t\"spring-boot-starter-r2dbc\",\n\t\t\t\t\"spring-boot-starter-r2dbc-test\",\n\t\t\t\t\"spring-boot-starter-reactor-netty\",\n\t\t\t\t\"spring-boot-starter-restclient\",\n\t\t\t\t\"spring-boot-starter-restclient-test\",\n\t\t\t\t\"spring-boot-starter-restdocs\",\n\t\t\t\t\"spring-boot-starter-rsocket\",\n\t\t\t\t\"spring-boot-starter-rsocket-test\",\n\t\t\t\t\"spring-boot-starter-security\",\n\t\t\t\t\"spring-boot-starter-security-test\",\n\t\t\t\t\"spring-boot-starter-security-oauth2-authorization-server\",\n\t\t\t\t\"spring-boot-starter-security-oauth2-authorization-server-test\",\n\t\t\t\t\"spring-boot-starter-security-oauth2-client\",\n\t\t\t\t\"spring-boot-starter-security-oauth2-client-test\",\n\t\t\t\t\"spring-boot-starter-security-oauth2-resource-server\",\n\t\t\t\t\"spring-boot-starter-security-oauth2-resource-server-test\",\n\t\t\t\t\"spring-boot-starter-security-saml2\",\n\t\t\t\t\"spring-boot-starter-security-saml2-test\",\n\t\t\t\t\"spring-boot-starter-sendgrid\",\n\t\t\t\t\"spring-boot-starter-sendgrid-test\",\n\t\t\t\t\"spring-boot-starter-session-data-redis\",\n\t\t\t\t\"spring-boot-starter-session-data-redis-test\",\n\t\t\t\t\"spring-boot-starter-session-jdbc\",\n\t\t\t\t\"spring-boot-starter-session-jdbc-test\",\n\t\t\t\t\"spring-boot-starter-test\",\n\t\t\t\t\"spring-boot-starter-test-classic\",\n\t\t\t\t\"spring-boot-starter-thymeleaf\",\n\t\t\t\t\"spring-boot-starter-thymeleaf-test\",\n\t\t\t\t\"spring-boot-starter-tomcat\",\n\t\t\t\t\"spring-boot-starter-tomcat-runtime\",\n\t\t\t\t\"spring-boot-starter-validation\",\n\t\t\t\t\"spring-boot-starter-validation-test\",\n\t\t\t\t\"spring-boot-starter-web\",\n\t\t\t\t\"spring-boot-starter-web-services\",\n\t\t\t\t\"spring-boot-starter-webclient\",\n\t\t\t\t\"spring-boot-starter-webclient-test\",\n\t\t\t\t\"spring-boot-starter-webflux\",\n\t\t\t\t\"spring-boot-starter-webflux-test\",\n\t\t\t\t\"spring-boot-starter-webmvc\",\n\t\t\t\t\"spring-boot-starter-webmvc-test\",\n\t\t\t\t\"spring-boot-starter-webservices\",\n\t\t\t\t\"spring-boot-starter-webservices-test\",\n\t\t\t\t\"spring-boot-starter-websocket\",\n\t\t\t\t\"spring-boot-starter-websocket-test\",\n\t\t\t\t\"spring-boot-starter-zipkin\",\n\t\t\t\t\"spring-boot-test\",\n\t\t\t\t\"spring-boot-test-autoconfigure\",\n\t\t\t\t\"spring-boot-test-classic-modules\",\n\t\t\t\t\"spring-boot-testcontainers\",\n\t\t\t\t\"spring-boot-thymeleaf\",\n\t\t\t\t\"spring-boot-tomcat\",\n\t\t\t\t\"spring-boot-transaction\",\n\t\t\t\t\"spring-boot-validation\",\n\t\t\t\t\"spring-boot-web-server\",\n\t\t\t\t\"spring-boot-web-server-test\",\n\t\t\t\t\"spring-boot-webclient\",\n\t\t\t\t\"spring-boot-webclient-test\",\n\t\t\t\t\"spring-boot-webflux\",\n\t\t\t\t\"spring-boot-webflux-test\",\n\t\t\t\t\"spring-boot-webmvc\",\n\t\t\t\t\"spring-boot-webmvc-test\",\n\t\t\t\t\"spring-boot-webservices\",\n\t\t\t\t\"spring-boot-webservices-test\",\n\t\t\t\t\"spring-boot-websocket\",\n\t\t\t\t\"spring-boot-webtestclient\",\n\t\t\t\t\"spring-boot-zipkin\",\n\t\t\t\t\"spring-boot-starter-zipkin-test\"\n\t\t\t]\n\t\t\tplugins = [\n\t\t\t\t\"spring-boot-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-boot\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-boot\")\n\t\t\tjavadoc(\"https://docs.spring.io/spring-boot/{version}/api/java\", \"org.springframework.boot\")\n\t\t\tdocs(\"https://docs.spring.io/spring-boot/{version}\")\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-boot/releases/tag/v{version}\")\n\t\t\tadd(\"layers-xsd\", version -> \"https://www.springframework.org/schema/boot/layers/layers-%s.%s.xsd\"\n\t\t\t\t.formatted(version.major(), version.minor()))\n\t\t}\n\t}\n\tlibrary(\"SAAJ Impl\", \"3.0.4\") {\n\t\tgroup(\"com.sun.xml.messaging.saaj\") {\n\t\t\tmodules = [\n\t\t\t\t\"saaj-impl\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Selenium\", \"4.41.0\") {\n\t\tgroup(\"org.seleniumhq.selenium\") {\n\t\t\tbom(\"selenium-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.selenium.dev\")\n\t\t\tjavadoc(\"https://www.selenium.dev/selenium/docs/api/java\", \"org.openqa.selenium\")\n\t\t\treleaseNotes(\"https://github.com/SeleniumHQ/selenium/releases/tag/selenium-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Selenium HtmlUnit\", \"4.41.0\") {\n\t\tgroup(\"org.seleniumhq.selenium\") {\n\t\t\tmodules = [\n\t\t\t\t\"htmlunit3-driver\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/SeleniumHQ/htmlunit-driver\")\n\t\t\treleaseNotes(\"https://github.com/SeleniumHQ/htmlunit-driver/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"SendGrid\", \"4.10.3\") {\n\t\tprohibit {\n\t\t\tcontains \"-rc.\"\n\t\t\tbecause \"we don't want release candidates\"\n\t\t}\n\t\tgroup(\"com.sendgrid\") {\n\t\t\tmodules = [\n\t\t\t\t\"sendgrid-java\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/sendgrid/sendgrid-java\")\n\t\t\treleaseNotes(\"https://github.com/sendgrid/sendgrid-java/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"SLF4J\", \"2.0.17\") {\n\t\tprohibit {\n\t\t\tcontains \"-alpha\"\n\t\t\tbecause \"we don't want alphas\"\n\t\t}\n\t\tgroup(\"org.slf4j\") {\n\t\t\tmodules = [\n\t\t\t\t\"jcl-over-slf4j\",\n\t\t\t\t\"jul-to-slf4j\",\n\t\t\t\t\"log4j-over-slf4j\",\n\t\t\t\t\"slf4j-api\",\n\t\t\t\t\"slf4j-ext\",\n\t\t\t\t\"slf4j-jdk-platform-logging\",\n\t\t\t\t\"slf4j-jdk14\",\n\t\t\t\t\"slf4j-log4j12\",\n\t\t\t\t\"slf4j-nop\",\n\t\t\t\t\"slf4j-reload4j\",\n\t\t\t\t\"slf4j-simple\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"SnakeYAML\", \"${snakeYamlVersion}\") {\n\t\tgroup(\"org.yaml\") {\n\t\t\tmodules = [\n\t\t\t\t\"snakeyaml\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Spring AMQP\", \"4.1.0-M3\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.amqp\") {\n\t\t\tbom(\"spring-amqp-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-amqp\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-amqp\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-amqp/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.amqp\", \"org.springframework.rabbit\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-amqp/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-amqp/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Batch\", \"6.0.3\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.batch\") {\n\t\t\tbom(\"spring-batch-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-batch\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-batch\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-batch/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.batch\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-batch/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-batch/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Data Bom\", \"2026.0.0-M2\") {\n\t\tconsiderSnapshots()\n\t\tcalendarName = \"Spring Data Release\"\n\t\tgroup(\"org.springframework.data\") {\n\t\t\tbom(\"spring-data-bom\")\n\t\t}\n\t\tlinks(\"spring-data\") {\n\t\t\tsite(\"https://spring.io/projects/spring-data\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-data-bom\")\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-data-bom/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Framework\", \"${springFrameworkVersion}\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework\") {\n\t\t\tbom(\"spring-framework-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-framework\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-framework\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-framework/docs/%s/javadoc-api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.[aop|aot|asm|beans|cache|cglib|\" +\n\t\t\t\t\t\t\"context|core|dao|ejb|expression|format|http|instrument|jca|jdbc|jms|jmx|jndi|lang|mail|\" +\n\t\t\t\t\t\t\"messaging|mock|objenesis|orm|oxm|r2dbc|scheduling|scripting|stereotype|test|transaction|\" +\n\t\t\t\t\t\t\"ui|util|validation|web]\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-framework/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-framework/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring GraphQL\", \"2.0.2\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.graphql\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"spring-graphql\",\n\t\t\t\t\t\"spring-graphql-test\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-graphql\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-graphql\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-graphql/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.graphql\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-graphql/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-graphql/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring gRPC\", \"1.1.0-M1\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.grpc\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"spring-grpc-core\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-grpc\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-grpc\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-grpc/docs/%s/api\"\n\t\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.grpc\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-grpc/docs/%s/reference\"\n\t\t\t\t\t.formatted(version.forMajorMinorGeneration()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-grpc/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring HATEOAS\", \"3.1.0-M1\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.hateoas\") {\n\t\t\tmodules = [\n\t\t\t\t\"spring-hateoas\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-hateoas\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-hateoas\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-hateoas/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.hateoas\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-hateoas/docs/%s/reference/html\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-hateoas/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Integration\", \"7.1.0-M3\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.integration\") {\n\t\t\tbom(\"spring-integration-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-integration\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-integration\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-integration/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.integration\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-integration/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-integration/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Kafka\", \"4.1.0-M2\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.kafka\") {\n\t\t\tmodules = [\n\t\t\t\t\"spring-kafka\",\n\t\t\t\t\"spring-kafka-test\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-kafka\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-kafka\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-kafka/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.kafka\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-kafka/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-kafka/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring LDAP\", \"4.1.0-M2\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.ldap\") {\n\t\t\tmodules = [\n\t\t\t\t\"spring-ldap-core\",\n\t\t\t\t\"spring-ldap-ldif-core\",\n\t\t\t\t\"spring-ldap-odm\",\n\t\t\t\t\"spring-ldap-test\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-ldap\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-ldap\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-ldap/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.ldap\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-ldap/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-ldap/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Pulsar\", \"2.0.4\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.pulsar\") {\n\t\t\tbom(\"spring-pulsar-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-pulsar\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-pulsar\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-pulsar/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.pulsar\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-pulsar/docs/%s/reference\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-pulsar/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring RESTDocs\", \"4.0.0\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.restdocs\") {\n\t\t\tbom(\"spring-restdocs-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-restdocs\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-restdocs\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-restdocs/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.restdocs\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-restdocs/docs/%s/reference/htmlsingle\"\n\t\t\t\t\t.formatted(version.forMajorMinorGeneration()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-restdocs/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Security\", \"7.1.0-M3\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.security\") {\n\t\t\tbom(\"spring-security-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-security\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-security\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-security/reference/%s/api/java\"\n\t\t\t\t.formatted(version.forAntora()), \"org.springframework.security\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-security/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-security/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring Session\", \"4.1.0-M1\") {\n\t\tconsiderSnapshots()\n\t\tprohibit {\n\t\t\tstartsWith([\"Apple-\", \"Bean-\", \"Corn-\", \"Dragonfruit-\"])\n\t\t\tbecause \"Spring Session switched to numeric version numbers\"\n\t\t}\n\t\tprohibit {\n\t\t\tversionRange \"[2020.0.0-M1,)\"\n\t\t\tbecause \"Spring Session stopped using calver\"\n\t\t}\n\t\tgroup(\"org.springframework.session\") {\n\t\t\tbom(\"spring-session-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://spring.io/projects/spring-session\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-session\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-session/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.session\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-session/reference/%s\"\n\t\t\t\t.formatted(version.forAntora()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-session/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Spring WS\", \"5.0.1\") {\n\t\tconsiderSnapshots()\n\t\tgroup(\"org.springframework.ws\") {\n\t\t\tbom(\"spring-ws-bom\")\n\t\t}\n\t\tlinks(\"spring-webservices\") {\n\t\t\tsite(\"https://spring.io/projects/spring-ws\")\n\t\t\tgithub(\"https://github.com/spring-projects/spring-ws\")\n\t\t\tjavadoc(version -> \"https://docs.spring.io/spring-ws/docs/%s/api\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()), \"org.springframework.ws\", \"org.springframework.xml\")\n\t\t\tdocs(version -> \"https://docs.spring.io/spring-ws/docs/%s/reference/html\"\n\t\t\t\t.formatted(version.forMajorMinorGeneration()))\n\t\t\treleaseNotes(\"https://github.com/spring-projects/spring-ws/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"SQLite JDBC\", \"3.51.3.0\") {\n\t\tgroup(\"org.xerial\") {\n\t\t\tmodules = [\n\t\t\t\t\"sqlite-jdbc\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/xerial/sqlite-jdbc\")\n\t\t\treleaseNotes(\"https://github.com/xerial/sqlite-jdbc/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Testcontainers\", \"2.0.4\") {\n\t\tgroup(\"org.testcontainers\") {\n\t\t\tbom(\"testcontainers-bom\")\n\t\t}\n\t\tlinks {\n\t\t\tdocs(\"https://java.testcontainers.org\")\n\t\t\tjavadoc(\"testcontainers\", version -> \"https://javadoc.io/doc/org.testcontainers/testcontainers/%s\".formatted(version), \"org.testcontainers\")\n\t\t\tjavadoc(\"testcontainers-activemq\", version -> \"https://javadoc.io/doc/org.testcontainers/activemq/%s\".formatted(version), \"org.testcontainers.activemq\")\n\t\t\tjavadoc(\"testcontainers-cassandra\", version -> \"https://javadoc.io/doc/org.testcontainers/cassandra/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-clickhouse\", version -> \"https://javadoc.io/doc/org.testcontainers/clickhouse/%s\".formatted(version), \"org.testcontainers.clickhouse\")\n\t\t\tjavadoc(\"testcontainers-couchbase\", version -> \"https://javadoc.io/doc/org.testcontainers/couchbase/%s\".formatted(version), \"org.testcontainers.couchbase\")\n\t\t\tjavadoc(\"testcontainers-elasticsearch\", version -> \"https://javadoc.io/doc/org.testcontainers/elasticsearch/%s\".formatted(version), \"org.testcontainers.elasticsearch\")\n\t\t\tjavadoc(\"testcontainers-grafana\", version -> \"https://javadoc.io/doc/org.testcontainers/grafana/%s\".formatted(version), \"org.testcontainers.grafana\")\n\t\t\tjavadoc(\"testcontainers-jdbc\", version -> \"https://javadoc.io/doc/org.testcontainers/jdbc/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-junit-jupiter\", version -> \"https://javadoc.io/doc/org.testcontainers/junit-jupiter/%s\".formatted(version), \"org.testcontainers.junit.jupiter\")\n\t\t\tjavadoc(\"testcontainers-kafka\", version -> \"https://javadoc.io/doc/org.testcontainers/kafka/%s\".formatted(version), \"org.testcontainers.kafka\")\n\t\t\tjavadoc(\"testcontainers-mariadb\", version -> \"https://javadoc.io/doc/org.testcontainers/mariadb/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-mongodb\", version -> \"https://javadoc.io/doc/org.testcontainers/mongodb/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-mssqlserver\", version -> \"https://javadoc.io/doc/org.testcontainers/mssqlserver/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-mysql\", version -> \"https://javadoc.io/doc/org.testcontainers/mysql/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-neo4j\", version -> \"https://javadoc.io/doc/org.testcontainers/neo4j/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-oracle-xe\", version -> \"https://javadoc.io/doc/org.testcontainers/oracle-xe/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-oracle-free\", version -> \"https://javadoc.io/doc/org.testcontainers/oracle-free/%s\".formatted(version), \"org.testcontainers.oracle\")\n\t\t\tjavadoc(\"testcontainers-postgresql\", version -> \"https://javadoc.io/doc/org.testcontainers/postgresql/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-pulsar\", version -> \"https://javadoc.io/doc/org.testcontainers/pulsar/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-rabbitmq\", version -> \"https://javadoc.io/doc/org.testcontainers/rabbitmq/%s\".formatted(version))\n\t\t\tjavadoc(\"testcontainers-redpanda\", version -> \"https://javadoc.io/doc/org.testcontainers/redpanda/%s\".formatted(version), \"org.testcontainers.redpanda\")\n\t\t\tjavadoc(\"testcontainers-r2dbc\", version -> \"https://javadoc.io/doc/org.testcontainers/r2dbc/%s\".formatted(version), \"org.testcontainers.r2dbc\")\n\t\t\treleaseNotes(\"https://github.com/testcontainers/testcontainers-java/releases/tag/{version}\")\n\t\t\tsite(\"https://java.testcontainers.org\")\n\t\t}\n\t}\n\tlibrary(\"Testcontainers Redis Module\", \"2.2.4\") {\n\t\tgroup(\"com.redis\") {\n\t\t\tmodules = [\n\t\t\t\t\"testcontainers-redis\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://testcontainers.com/modules/redis/\")\n\t\t\tjavadoc(\"https://javadoc.io/doc/com.redis/testcontainers-redis/{version}\", \"com.redis.testcontainers\")\n\t\t}\n\t}\n\tlibrary(\"Thymeleaf\", \"3.1.3.RELEASE\") {\n\t\tgroup(\"org.thymeleaf\") {\n\t\t\tmodules = [\n\t\t\t\t\"thymeleaf\",\n\t\t\t\t\"thymeleaf-spring6\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://www.thymeleaf.org\")\n\t\t\tjavadoc(\"thymeleaf\", version -> \"https://www.thymeleaf.org/apidocs/thymeleaf/%s\".formatted(version), \"org.thymeleaf\")\n\t\t\tjavadoc(\"thymeleaf-spring6\", version -> \"https://www.thymeleaf.org/apidocs/thymeleaf-spring6/%s\".formatted(version), \"org.thymeleaf.spring6\")\n\t\t\treleaseNotes(\"https://github.com/thymeleaf/thymeleaf/releases/tag/thymeleaf-{version}\")\n\t\t}\n\t}\n\tlibrary(\"Thymeleaf Extras Data Attribute\", \"2.0.1\") {\n\t\tgroup(\"com.github.mxab.thymeleaf.extras\") {\n\t\t\tmodules = [\n\t\t\t\t\"thymeleaf-extras-data-attribute\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Thymeleaf Extras SpringSecurity\", \"3.1.3.RELEASE\") {\n\t\tgroup(\"org.thymeleaf.extras\") {\n\t\t\tmodules = [\n\t\t\t\t\"thymeleaf-extras-springsecurity6\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Thymeleaf Layout Dialect\", \"4.0.1\") {\n\t\tgroup(\"nz.net.ultraq.thymeleaf\") {\n\t\t\tmodules = [\n\t\t\t\t\"thymeleaf-layout-dialect\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/ultraq/thymeleaf-layout-dialect/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Tomcat\", \"${tomcatVersion}\") {\n\t\tgroup(\"org.apache.tomcat\") {\n\t\t\tmodules = [\n\t\t\t\t\"tomcat-annotations-api\",\n\t\t\t\t\"tomcat-jdbc\",\n\t\t\t\t\"tomcat-jsp-api\"\n\t\t\t]\n\t\t}\n\t\tgroup(\"org.apache.tomcat.embed\") {\n\t\t\tmodules = [\n\t\t\t\t\"tomcat-embed-core\",\n\t\t\t\t\"tomcat-embed-el\",\n\t\t\t\t\"tomcat-embed-jasper\",\n\t\t\t\t\"tomcat-embed-websocket\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://tomcat.apache.org\")\n\t\t\tjavadoc(version -> \"https://tomcat.apache.org/tomcat-%s.%s-doc/api\".formatted(version.major(), version.minor()), \"org.apache.catalina\", \"org.apache.tomcat\")\n\t\t\tdocs(version -> \"https://tomcat.apache.org/tomcat-%s.%s-doc\".formatted(version.major(), version.minor()))\n\t\t\treleaseNotes(version -> \"https://tomcat.apache.org/tomcat-%s.%s-doc/changelog.html\".formatted(version.major(), version.minor()))\n\t\t}\n\t}\n\tlibrary(\"UnboundID LDAPSDK\", \"7.0.4\") {\n\t\tgroup(\"com.unboundid\") {\n\t\t\tmodules = [\n\t\t\t\t\"unboundid-ldapsdk\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/pingidentity/ldapsdk/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Versions Maven Plugin\", \"2.21.0\") {\n\t\tgroup(\"org.codehaus.mojo\") {\n\t\t\tplugins = [\n\t\t\t\t\"versions-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/mojohaus/versions/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"Vibur\", \"26.0\") {\n\t\tgroup(\"org.vibur\") {\n\t\t\tmodules = [\n\t\t\t\t\t\"vibur-dbcp\",\n\t\t\t\t\t\"vibur-object-pool\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"WebJars Locator Core\", \"0.59\") {\n\t\tgroup(\"org.webjars\") {\n\t\t\tmodules = [\n\t\t\t\t\"webjars-locator-core\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"WebJars Locator Lite\", \"1.1.3\") {\n\t\tgroup(\"org.webjars\") {\n\t\t\tmodules = [\n\t\t\t\t\"webjars-locator-lite\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"WSDL4j\", \"1.6.3\") {\n\t\tgroup(\"wsdl4j\") {\n\t\t\tmodules = [\n\t\t\t\t\"wsdl4j\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"XML Maven Plugin\", \"1.2.1\") {\n\t\tgroup(\"org.codehaus.mojo\") {\n\t\t\tplugins = [\n\t\t\t\t\"xml-maven-plugin\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\treleaseNotes(\"https://github.com/mojohaus/xml-maven-plugin/releases/tag/{version}\")\n\t\t}\n\t}\n\tlibrary(\"XmlUnit2\", \"2.11.0\") {\n\t\tgroup(\"org.xmlunit\") {\n\t\t\tmodules = [\n\t\t\t\t\"xmlunit-assertj\",\n\t\t\t\t\"xmlunit-assertj3\",\n\t\t\t\t\"xmlunit-core\",\n\t\t\t\t\"xmlunit-jakarta-jaxb-impl\",\n\t\t\t\t\"xmlunit-legacy\",\n\t\t\t\t\"xmlunit-matchers\",\n\t\t\t\t\"xmlunit-placeholders\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/xmlunit/xmlunit\")\n\t\t\treleaseNotes(\"https://github.com/xmlunit/xmlunit/releases/tag/v{version}\")\n\t\t}\n\t}\n\tlibrary(\"Yasson\", \"3.0.4\") {\n\t\tgroup(\"org.eclipse\") {\n\t\t\tmodules = [\n\t\t\t\t\"yasson\"\n\t\t\t]\n\t\t}\n\t\tlinks {\n\t\t\tsite(\"https://github.com/eclipse-ee4j/yasson\")\n\t\t\treleaseNotes(\"https://github.com/eclipse-ee4j/yasson/releases/tag/{version}\")\n\t\t}\n\t}\n}\n\ngenerateMetadataFileForMavenPublication {\n\tenabled = false\n}\n"
  },
  {
    "path": "platform/spring-boot-internal-dependencies/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.bom\"\n}\n\ndescription = \"Spring Boot Internal Dependencies\"\n\nbom {\n\tupgrade {\n\t\tpolicy = \"same-major-version\"\n\t\tgitHub {\n\t\t\tissueLabels = [\n\t\t\t\t\"type: task\",\n\t\t\t\t\"status: team-only\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"API Guardian\", \"1.1.2\") {\n\t\tgroup(\"org.apiguardian\") {\n\t\t\tmodules = [\n\t\t\t\t\"apiguardian-api\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"AWS Advanced JDBC Wrapper\", \"2.6.0\") {\n\t\tgroup(\"software.amazon.jdbc\") {\n\t\t\tmodules = [\n\t\t\t\t\"aws-advanced-jdbc-wrapper\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"C3P0\", \"0.11.1\") {\n\t\tgroup(\"com.mchange\") {\n\t\t\tmodules = [\n\t\t\t\t\"c3p0\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Checker Annotations\", \"3.51.0\") {\n\t\tgroup(\"org.checkerframework\") {\n\t\t\tmodules = [\n\t\t\t\t\"checker-qual\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"ClickHouse\", \"0.9.0\") {\n\t\tgroup(\"com.clickhouse\") {\n\t\t\tmodules = [\n\t\t\t\t\"clickhouse-jdbc\",\n\t\t\t\t\"clickhouse-r2dbc\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Commons Compress\", \"1.27.1\") {\n\t\tgroup(\"org.apache.commons\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-compress\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Commons FileUpload\", \"1.6.0\") {\n\t\tgroup(\"commons-fileupload\") {\n\t\t\tmodules = [\n\t\t\t\t\"commons-fileupload\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"CycloneDX Gradle Plugin\", \"3.0.1\") {\n\t\tgroup(\"org.cyclonedx\") {\n\t\t\tmodules = [\n\t\t\t\t\"cyclonedx-gradle-plugin\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Findbugs JSR 305\", \"3.0.2\") {\n\t\tgroup(\"com.google.code.findbugs\") {\n\t\t\tmodules = [\n\t\t\t\t\"jsr305\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Janino\", \"3.1.12\") {\n\t\tgroup(\"org.codehaus.janino\") {\n\t\t\tbom(\"janino\") {\n\t\t\t\tpermit(\"junit:junit\")\n\t\t\t}\n\t\t}\n\t}\n\tlibrary(\"JLine\", \"2.11\") {\n\t\tprohibit {\n\t\t\tversionRange \"[2.12,)\"\n\t\t\tbecause \"it contains breaking changes\"\n\t\t}\n\t\tgroup(\"jline\") {\n\t\t\tmodules = [\n\t\t\t\t\"jline\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"JNA\", \"5.17.0\") {\n\t\tgroup(\"net.java.dev.jna\") {\n\t\t\tmodules = [\n\t\t\t\t\"jna-platform\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"JOpt Simple\", \"5.0.4\") {\n\t\tgroup(\"net.sf.jopt-simple\") {\n\t\t\tmodules = [\n\t\t\t\t\"jopt-simple\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven\", \"${mavenVersion}\") {\n\t\tgroup(\"org.apache.maven\") {\n\t\t\tmodules = [\n\t\t\t\t\"maven-core\",\n\t\t\t\t\"maven-model-builder\",\n\t\t\t\t\"maven-plugin-api\",\n\t\t\t\t\"maven-resolver-provider\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven Common Artifact Filters\", \"3.4.0\") {\n\t\tgroup(\"org.apache.maven.shared\") {\n\t\t\tmodules = [\n\t\t\t\t\"maven-common-artifact-filters\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven Invoker\", \"3.3.0\") {\n\t\tgroup(\"org.apache.maven.shared\") {\n\t\t\tmodules = [\n\t\t\t\t\"maven-invoker\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven Plugin Tools\", \"3.15.1\") {\n\t\tgroup(\"org.apache.maven.plugin-tools\") {\n\t\t\tmodules = [\n\t\t\t\t\"maven-plugin-annotations\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven Resolver\", \"1.9.23\") {\n\t\tgroup(\"org.apache.maven.resolver\") {\n\t\t\tmodules = [\n\t\t\t\t\"maven-resolver-api\",\n\t\t\t\t\"maven-resolver-connector-basic\",\n\t\t\t\t\"maven-resolver-impl\",\n\t\t\t\t\"maven-resolver-spi\",\n\t\t\t\t\"maven-resolver-transport-file\",\n\t\t\t\t\"maven-resolver-transport-http\",\n\t\t\t\t\"maven-resolver-util\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Maven Shade Plugin\", \"3.6.0\") {\n\t\tgroup(\"org.apache.maven.plugins\") {\n\t\t\tmodules = [\n\t\t\t\t\"maven-shade-plugin\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"MockK\", \"1.14.2\") {\n\t\tgroup(\"io.mockk\") {\n\t\t\tmodules = [\n\t\t\t\t\"mockk\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Native Gradle Plugin\", \"${nativeBuildToolsVersion}\") {\n\t\tgroup(\"org.graalvm.buildtools\") {\n\t\t\tmodules = [\n\t\t\t\t\"native-gradle-plugin\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"OkHttp\", \"5.1.0\") {\n\t\tgroup(\"com.squareup.okhttp3\") {\n\t\t\tmodules = [\n\t\t\t\t\"mockwebserver\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"OpenTelemetry Logback Appender\", \"2.16.0-alpha\") {\n\t\tgroup(\"io.opentelemetry.instrumentation\") {\n\t\t\tmodules = [\n\t\t\t\t\"opentelemetry-logback-appender-1.0\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Plexus Build API\", \"0.0.7\") {\n\t\tgroup(\"org.sonatype.plexus\") {\n\t\t\tmodules = [\n\t\t\t\t\"plexus-build-api\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Plexus Sec Dispatcher\", \"1.4\") {\n\t\tgroup(\"org.sonatype.plexus\") {\n\t\t\tmodules = [\n\t\t\t\t\"plexus-sec-dispatcher\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Protobuf Gradle Plugin\", \"${protobufGradlePluginVersion}\") {\n\t\tgroup(\"com.google.protobuf\") {\n\t\t\tmodules = [\n\t\t\t\t\"protobuf-gradle-plugin\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Simple JNDI\", \"0.25.0\") {\n\t\tgroup(\"com.github.h-thurow\") {\n\t\t\tmodules = [\n\t\t\t\t\"simple-jndi\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Sisu\", \"2.6.0\") {\n\t\tgroup(\"org.sonatype.sisu\") {\n\t\t\tmodules = [\n\t\t\t\t\"sisu-inject-plexus\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"Spock Framework\", \"2.4-groovy-5.0\") {\n\t\tgroup(\"org.spockframework\") {\n\t\t\tmodules = [\n\t\t\t\t\"spock-core\"\n\t\t\t]\n\t\t}\n\t}\n\tlibrary(\"TestNG\", \"6.14.3\") {\n\t\tgroup(\"org.testng\") {\n\t\t\tmodules = [\n\t\t\t\t\"testng\"\n\t\t\t]\n\t\t}\n\t}\n}\n\ndependencies {\n\tapi(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n}\n\ntasks.withType(GenerateModuleMetadata).configureEach {\n\t// Internal module so enforced platform dependencies are OK\n\tsuppressedValidationErrors.add('enforced-platform')\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"${rootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\tmavenCentral()\n\t\tgradlePluginPortal()\n\t\tspring.mavenRepositories()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id == \"org.jetbrains.kotlin.jvm\") {\n\t\t\t\tuseVersion \"${kotlinVersion}\"\n\t\t\t}\n\t\t\tif (requested.id.id == \"org.jetbrains.kotlin.plugin.spring\") {\n\t\t\t\tuseVersion \"${kotlinVersion}\"\n\t\t\t}\n\t\t\tif (requested.id.id == \"org.jetbrains.kotlin.plugin.serialization\") {\n\t\t\t\tuseVersion \"${kotlinVersion}\"\n\t\t\t}\n\t\t}\n\t}\n\tincludeBuild(\"gradle/plugins\")\n}\n\nplugins {\n\tid \"io.spring.develocity.conventions\" version \"0.0.25\"\n\tid \"org.springframework.boot.cycle-detection\"\n}\n\nrootProject.name=\"spring-boot-build\"\n\nenableFeaturePreview(\"STABLE_CONFIGURATION_CACHE\")\n\nsettings.gradle.projectsLoaded {\n\tdevelocity {\n\t\tbuildScan {\n\t\t\tdef toolchainVersion = settings.gradle.rootProject.findProperty('toolchainVersion')\n\t\t\tif (toolchainVersion != null) {\n\t\t\t\tvalue('Toolchain version', toolchainVersion)\n\t\t\t}\n\t\t}\n\t}\n}\n\ninclude \"platform:spring-boot-dependencies\"\ninclude \"platform:spring-boot-internal-dependencies\"\n\ninclude \"test-support:spring-boot-test-support\"\ninclude \"test-support:spring-boot-docker-test-support\"\ninclude \"test-support:spring-boot-gradle-test-support\"\n\ninclude \"configuration-metadata:spring-boot-configuration-metadata\"\ninclude \"configuration-metadata:spring-boot-configuration-metadata-changelog-generator\"\ninclude \"configuration-metadata:spring-boot-configuration-processor\"\n\ninclude \"core:spring-boot\"\ninclude \"core:spring-boot-autoconfigure\"\ninclude \"core:spring-boot-autoconfigure-processor\"\ninclude \"core:spring-boot-docker-compose\"\ninclude \"core:spring-boot-properties-migrator\"\ninclude \"core:spring-boot-test\"\ninclude \"core:spring-boot-test-autoconfigure\"\ninclude \"core:spring-boot-testcontainers\"\n\ninclude \"module:spring-boot-activemq\"\ninclude \"module:spring-boot-actuator\"\ninclude \"module:spring-boot-actuator-autoconfigure\"\ninclude \"module:spring-boot-amqp\"\ninclude \"module:spring-boot-artemis\"\ninclude \"module:spring-boot-autoconfigure-classic\"\ninclude \"module:spring-boot-autoconfigure-classic-modules\"\ninclude \"module:spring-boot-batch\"\ninclude \"module:spring-boot-batch-data-mongodb\"\ninclude \"module:spring-boot-batch-jdbc\"\ninclude \"module:spring-boot-cache\"\ninclude \"module:spring-boot-cache-test\"\ninclude \"module:spring-boot-cassandra\"\ninclude \"module:spring-boot-cloudfoundry\"\ninclude \"module:spring-boot-couchbase\"\ninclude \"module:spring-boot-data-cassandra\"\ninclude \"module:spring-boot-data-cassandra-test\"\ninclude \"module:spring-boot-data-commons\"\ninclude \"module:spring-boot-data-couchbase\"\ninclude \"module:spring-boot-data-couchbase-test\"\ninclude \"module:spring-boot-data-elasticsearch\"\ninclude \"module:spring-boot-data-elasticsearch-test\"\ninclude \"module:spring-boot-data-jdbc\"\ninclude \"module:spring-boot-data-jdbc-test\"\ninclude \"module:spring-boot-data-jpa\"\ninclude \"module:spring-boot-data-jpa-test\"\ninclude \"module:spring-boot-data-ldap\"\ninclude \"module:spring-boot-data-ldap-test\"\ninclude \"module:spring-boot-data-mongodb\"\ninclude \"module:spring-boot-data-mongodb-test\"\ninclude \"module:spring-boot-data-neo4j\"\ninclude \"module:spring-boot-data-neo4j-test\"\ninclude \"module:spring-boot-data-r2dbc\"\ninclude \"module:spring-boot-data-r2dbc-test\"\ninclude \"module:spring-boot-data-redis\"\ninclude \"module:spring-boot-data-redis-test\"\ninclude \"module:spring-boot-data-rest\"\ninclude \"module:spring-boot-devtools\"\ninclude \"module:spring-boot-elasticsearch\"\ninclude \"module:spring-boot-flyway\"\ninclude \"module:spring-boot-freemarker\"\ninclude \"module:spring-boot-graphql\"\ninclude \"module:spring-boot-graphql-test\"\ninclude \"module:spring-boot-grpc-client\"\ninclude \"module:spring-boot-grpc-server\"\ninclude \"module:spring-boot-grpc-test\"\ninclude \"module:spring-boot-groovy-templates\"\ninclude \"module:spring-boot-gson\"\ninclude \"module:spring-boot-h2console\"\ninclude \"module:spring-boot-hateoas\"\ninclude \"module:spring-boot-hazelcast\"\ninclude \"module:spring-boot-health\"\ninclude \"module:spring-boot-hibernate\"\ninclude \"module:spring-boot-http-client\"\ninclude \"module:spring-boot-http-codec\"\ninclude \"module:spring-boot-http-converter\"\ninclude \"module:spring-boot-integration\"\ninclude \"module:spring-boot-jackson\"\ninclude \"module:spring-boot-jackson2\"\ninclude \"module:spring-boot-jdbc\"\ninclude \"module:spring-boot-jdbc-test\"\ninclude \"module:spring-boot-jersey\"\ninclude \"module:spring-boot-jetty\"\ninclude \"module:spring-boot-jms\"\ninclude \"module:spring-boot-jooq\"\ninclude \"module:spring-boot-jooq-test\"\ninclude \"module:spring-boot-jpa\"\ninclude \"module:spring-boot-jpa-test\"\ninclude \"module:spring-boot-jsonb\"\ninclude \"module:spring-boot-kafka\"\ninclude \"module:spring-boot-kotlinx-serialization-json\"\ninclude \"module:spring-boot-ldap\"\ninclude \"module:spring-boot-liquibase\"\ninclude \"module:spring-boot-mail\"\ninclude \"module:spring-boot-micrometer-metrics\"\ninclude \"module:spring-boot-micrometer-metrics-test\"\ninclude \"module:spring-boot-micrometer-observation\"\ninclude \"module:spring-boot-micrometer-tracing\"\ninclude \"module:spring-boot-micrometer-tracing-brave\"\ninclude \"module:spring-boot-micrometer-tracing-opentelemetry\"\ninclude \"module:spring-boot-micrometer-tracing-test\"\ninclude \"module:spring-boot-mongodb\"\ninclude \"module:spring-boot-mustache\"\ninclude \"module:spring-boot-neo4j\"\ninclude \"module:spring-boot-netty\"\ninclude \"module:spring-boot-opentelemetry\"\ninclude \"module:spring-boot-persistence\"\ninclude \"module:spring-boot-pulsar\"\ninclude \"module:spring-boot-quartz\"\ninclude \"module:spring-boot-r2dbc\"\ninclude \"module:spring-boot-reactor\"\ninclude \"module:spring-boot-reactor-netty\"\ninclude \"module:spring-boot-restclient\"\ninclude \"module:spring-boot-restclient-test\"\ninclude \"module:spring-boot-restdocs\"\ninclude \"module:spring-boot-resttestclient\"\ninclude \"module:spring-boot-rsocket\"\ninclude \"module:spring-boot-rsocket-test\"\ninclude \"module:spring-boot-security\"\ninclude \"module:spring-boot-security-test\"\ninclude \"module:spring-boot-security-oauth2-authorization-server\"\ninclude \"module:spring-boot-security-oauth2-client\"\ninclude \"module:spring-boot-security-oauth2-resource-server\"\ninclude \"module:spring-boot-security-saml2\"\ninclude \"module:spring-boot-sendgrid\"\ninclude \"module:spring-boot-servlet\"\ninclude \"module:spring-boot-session\"\ninclude \"module:spring-boot-session-data-redis\"\ninclude \"module:spring-boot-session-jdbc\"\ninclude \"module:spring-boot-sql\"\ninclude \"module:spring-boot-test-classic-modules\"\ninclude \"module:spring-boot-thymeleaf\"\ninclude \"module:spring-boot-tomcat\"\ninclude \"module:spring-boot-transaction\"\ninclude \"module:spring-boot-validation\"\ninclude \"module:spring-boot-web-server\"\ninclude \"module:spring-boot-web-server-test\"\ninclude \"module:spring-boot-webclient\"\ninclude \"module:spring-boot-webclient-test\"\ninclude \"module:spring-boot-webflux\"\ninclude \"module:spring-boot-webflux-test\"\ninclude \"module:spring-boot-webmvc\"\ninclude \"module:spring-boot-webmvc-test\"\ninclude \"module:spring-boot-webtestclient\"\ninclude \"module:spring-boot-webservices\"\ninclude \"module:spring-boot-webservices-test\"\ninclude \"module:spring-boot-websocket\"\ninclude \"module:spring-boot-zipkin\"\n\ninclude \"starter:spring-boot-starter\"\ninclude \"starter:spring-boot-starter-activemq\"\ninclude \"starter:spring-boot-starter-activemq-test\"\ninclude \"starter:spring-boot-starter-actuator\"\ninclude \"starter:spring-boot-starter-actuator-test\"\ninclude \"starter:spring-boot-starter-amqp\"\ninclude \"starter:spring-boot-starter-amqp-test\"\ninclude \"starter:spring-boot-starter-artemis\"\ninclude \"starter:spring-boot-starter-artemis-test\"\ninclude \"starter:spring-boot-starter-aspectj\"\ninclude \"starter:spring-boot-starter-aspectj-test\"\ninclude \"starter:spring-boot-starter-batch\"\ninclude \"starter:spring-boot-starter-batch-data-mongodb\"\ninclude \"starter:spring-boot-starter-batch-data-mongodb-test\"\ninclude \"starter:spring-boot-starter-batch-jdbc\"\ninclude \"starter:spring-boot-starter-batch-jdbc-test\"\ninclude \"starter:spring-boot-starter-batch-test\"\ninclude \"starter:spring-boot-starter-cache\"\ninclude \"starter:spring-boot-starter-cache-test\"\ninclude \"starter:spring-boot-starter-cassandra\"\ninclude \"starter:spring-boot-starter-cassandra-test\"\ninclude \"starter:spring-boot-starter-classic\"\ninclude \"starter:spring-boot-starter-cloudfoundry\"\ninclude \"starter:spring-boot-starter-cloudfoundry-test\"\ninclude \"starter:spring-boot-starter-couchbase\"\ninclude \"starter:spring-boot-starter-couchbase-test\"\ninclude \"starter:spring-boot-starter-data-cassandra\"\ninclude \"starter:spring-boot-starter-data-cassandra-test\"\ninclude \"starter:spring-boot-starter-data-cassandra-reactive\"\ninclude \"starter:spring-boot-starter-data-cassandra-reactive-test\"\ninclude \"starter:spring-boot-starter-data-couchbase\"\ninclude \"starter:spring-boot-starter-data-couchbase-test\"\ninclude \"starter:spring-boot-starter-data-couchbase-reactive\"\ninclude \"starter:spring-boot-starter-data-couchbase-reactive-test\"\ninclude \"starter:spring-boot-starter-data-elasticsearch\"\ninclude \"starter:spring-boot-starter-data-elasticsearch-test\"\ninclude \"starter:spring-boot-starter-data-jdbc\"\ninclude \"starter:spring-boot-starter-data-jdbc-test\"\ninclude \"starter:spring-boot-starter-data-jpa\"\ninclude \"starter:spring-boot-starter-data-jpa-test\"\ninclude \"starter:spring-boot-starter-data-ldap\"\ninclude \"starter:spring-boot-starter-data-ldap-test\"\ninclude \"starter:spring-boot-starter-data-mongodb\"\ninclude \"starter:spring-boot-starter-data-mongodb-test\"\ninclude \"starter:spring-boot-starter-data-mongodb-reactive\"\ninclude \"starter:spring-boot-starter-data-mongodb-reactive-test\"\ninclude \"starter:spring-boot-starter-data-neo4j\"\ninclude \"starter:spring-boot-starter-data-neo4j-test\"\ninclude \"starter:spring-boot-starter-data-r2dbc\"\ninclude \"starter:spring-boot-starter-data-r2dbc-test\"\ninclude \"starter:spring-boot-starter-data-redis\"\ninclude \"starter:spring-boot-starter-data-redis-test\"\ninclude \"starter:spring-boot-starter-data-redis-reactive\"\ninclude \"starter:spring-boot-starter-data-redis-reactive-test\"\ninclude \"starter:spring-boot-starter-data-rest\"\ninclude \"starter:spring-boot-starter-data-rest-test\"\ninclude \"starter:spring-boot-starter-elasticsearch\"\ninclude \"starter:spring-boot-starter-elasticsearch-test\"\ninclude \"starter:spring-boot-starter-flyway\"\ninclude \"starter:spring-boot-starter-flyway-test\"\ninclude \"starter:spring-boot-starter-freemarker\"\ninclude \"starter:spring-boot-starter-freemarker-test\"\ninclude \"starter:spring-boot-starter-graphql\"\ninclude \"starter:spring-boot-starter-graphql-test\"\ninclude \"starter:spring-boot-starter-grpc-client\"\ninclude \"starter:spring-boot-starter-grpc-server\"\ninclude \"starter:spring-boot-starter-grpc-test\"\ninclude \"starter:spring-boot-starter-groovy-templates\"\ninclude \"starter:spring-boot-starter-groovy-templates-test\"\ninclude \"starter:spring-boot-starter-gson\"\ninclude \"starter:spring-boot-starter-gson-test\"\ninclude \"starter:spring-boot-starter-hateoas\"\ninclude \"starter:spring-boot-starter-hateoas-test\"\ninclude \"starter:spring-boot-starter-hazelcast\"\ninclude \"starter:spring-boot-starter-hazelcast-test\"\ninclude \"starter:spring-boot-starter-integration\"\ninclude \"starter:spring-boot-starter-integration-test\"\ninclude \"starter:spring-boot-starter-jackson\"\ninclude \"starter:spring-boot-starter-jackson-test\"\ninclude \"starter:spring-boot-starter-jdbc\"\ninclude \"starter:spring-boot-starter-jdbc-test\"\ninclude \"starter:spring-boot-starter-jersey\"\ninclude \"starter:spring-boot-starter-jersey-test\"\ninclude \"starter:spring-boot-starter-jetty\"\ninclude \"starter:spring-boot-starter-jetty-runtime\"\ninclude \"starter:spring-boot-starter-jms\"\ninclude \"starter:spring-boot-starter-jms-test\"\ninclude \"starter:spring-boot-starter-jooq\"\ninclude \"starter:spring-boot-starter-jooq-test\"\ninclude \"starter:spring-boot-starter-json\"\ninclude \"starter:spring-boot-starter-jsonb\"\ninclude \"starter:spring-boot-starter-jsonb-test\"\ninclude \"starter:spring-boot-starter-kafka\"\ninclude \"starter:spring-boot-starter-kafka-test\"\ninclude \"starter:spring-boot-starter-kotlinx-serialization-json\"\ninclude \"starter:spring-boot-starter-kotlinx-serialization-json-test\"\ninclude \"starter:spring-boot-starter-ldap\"\ninclude \"starter:spring-boot-starter-ldap-test\"\ninclude \"starter:spring-boot-starter-liquibase\"\ninclude \"starter:spring-boot-starter-liquibase-test\"\ninclude \"starter:spring-boot-starter-log4j2\"\ninclude \"starter:spring-boot-starter-logback\"\ninclude \"starter:spring-boot-starter-logging\"\ninclude \"starter:spring-boot-starter-mail\"\ninclude \"starter:spring-boot-starter-mail-test\"\ninclude \"starter:spring-boot-starter-micrometer-metrics\"\ninclude \"starter:spring-boot-starter-micrometer-metrics-test\"\ninclude \"starter:spring-boot-starter-mongodb\"\ninclude \"starter:spring-boot-starter-mongodb-test\"\ninclude \"starter:spring-boot-starter-mustache\"\ninclude \"starter:spring-boot-starter-mustache-test\"\ninclude \"starter:spring-boot-starter-neo4j\"\ninclude \"starter:spring-boot-starter-neo4j-test\"\ninclude \"starter:spring-boot-starter-oauth2-authorization-server\"\ninclude \"starter:spring-boot-starter-oauth2-client\"\ninclude \"starter:spring-boot-starter-oauth2-resource-server\"\ninclude \"starter:spring-boot-starter-opentelemetry\"\ninclude \"starter:spring-boot-starter-opentelemetry-test\"\ninclude \"starter:spring-boot-starter-parent\"\ninclude \"starter:spring-boot-starter-pulsar\"\ninclude \"starter:spring-boot-starter-pulsar-test\"\ninclude \"starter:spring-boot-starter-quartz\"\ninclude \"starter:spring-boot-starter-quartz-test\"\ninclude \"starter:spring-boot-starter-r2dbc\"\ninclude \"starter:spring-boot-starter-r2dbc-test\"\ninclude \"starter:spring-boot-starter-reactor-netty\"\ninclude \"starter:spring-boot-starter-restclient\"\ninclude \"starter:spring-boot-starter-restclient-test\"\ninclude \"starter:spring-boot-starter-restdocs\"\ninclude \"starter:spring-boot-starter-rsocket\"\ninclude \"starter:spring-boot-starter-rsocket-test\"\ninclude \"starter:spring-boot-starter-security\"\ninclude \"starter:spring-boot-starter-security-test\"\ninclude \"starter:spring-boot-starter-security-oauth2-authorization-server\"\ninclude \"starter:spring-boot-starter-security-oauth2-authorization-server-test\"\ninclude \"starter:spring-boot-starter-security-oauth2-client\"\ninclude \"starter:spring-boot-starter-security-oauth2-client-test\"\ninclude \"starter:spring-boot-starter-security-oauth2-resource-server\"\ninclude \"starter:spring-boot-starter-security-oauth2-resource-server-test\"\ninclude \"starter:spring-boot-starter-security-saml2\"\ninclude \"starter:spring-boot-starter-security-saml2-test\"\ninclude \"starter:spring-boot-starter-sendgrid\"\ninclude \"starter:spring-boot-starter-sendgrid-test\"\ninclude \"starter:spring-boot-starter-session-data-redis\"\ninclude \"starter:spring-boot-starter-session-data-redis-test\"\ninclude \"starter:spring-boot-starter-session-jdbc\"\ninclude \"starter:spring-boot-starter-session-jdbc-test\"\ninclude \"starter:spring-boot-starter-test\"\ninclude \"starter:spring-boot-starter-test-classic\"\ninclude \"starter:spring-boot-starter-thymeleaf\"\ninclude \"starter:spring-boot-starter-thymeleaf-test\"\ninclude \"starter:spring-boot-starter-tomcat\"\ninclude \"starter:spring-boot-starter-tomcat-runtime\"\ninclude \"starter:spring-boot-starter-validation\"\ninclude \"starter:spring-boot-starter-validation-test\"\ninclude \"starter:spring-boot-starter-web\"\ninclude \"starter:spring-boot-starter-web-services\"\ninclude \"starter:spring-boot-starter-webclient\"\ninclude \"starter:spring-boot-starter-webclient-test\"\ninclude \"starter:spring-boot-starter-webflux\"\ninclude \"starter:spring-boot-starter-webflux-test\"\ninclude \"starter:spring-boot-starter-webmvc\"\ninclude \"starter:spring-boot-starter-webmvc-test\"\ninclude \"starter:spring-boot-starter-webservices\"\ninclude \"starter:spring-boot-starter-webservices-test\"\ninclude \"starter:spring-boot-starter-websocket\"\ninclude \"starter:spring-boot-starter-websocket-test\"\ninclude \"starter:spring-boot-starter-zipkin\"\ninclude \"starter:spring-boot-starter-zipkin-test\"\n\ninclude \"loader:spring-boot-jarmode-tools\"\ninclude \"loader:spring-boot-loader\"\ninclude \"loader:spring-boot-loader-tools\"\n\ninclude \"buildpack:spring-boot-buildpack-platform\"\n\ninclude \"build-plugin:spring-boot-antlib\"\ninclude \"build-plugin:spring-boot-gradle-plugin\"\ninclude \"build-plugin:spring-boot-maven-plugin\"\n\ninclude \"cli:spring-boot-cli\"\n\ninclude \"documentation:spring-boot-actuator-docs\"\ninclude \"documentation:spring-boot-docs\"\n\ninclude \":smoke-test:spring-boot-smoke-test-activemq\"\ninclude \":smoke-test:spring-boot-smoke-test-activemq-embedded\"\ninclude \":smoke-test:spring-boot-smoke-test-actuator\"\ninclude \":smoke-test:spring-boot-smoke-test-actuator-custom-security\"\ninclude \":smoke-test:spring-boot-smoke-test-actuator-extension\"\ninclude \":smoke-test:spring-boot-smoke-test-actuator-log4j2\"\ninclude \":smoke-test:spring-boot-smoke-test-actuator-noweb\"\ninclude \":smoke-test:spring-boot-smoke-test-actuator-ui\"\ninclude \":smoke-test:spring-boot-smoke-test-amqp\"\ninclude \":smoke-test:spring-boot-smoke-test-ant\"\ninclude \":smoke-test:spring-boot-smoke-test-artemis\"\ninclude \":smoke-test:spring-boot-smoke-test-aspectj\"\ninclude \":smoke-test:spring-boot-smoke-test-autoconfigure-classic\"\ninclude \":smoke-test:spring-boot-smoke-test-batch\"\ninclude \":smoke-test:spring-boot-smoke-test-batch-data-mongodb\"\ninclude \":smoke-test:spring-boot-smoke-test-batch-jdbc\"\ninclude \":smoke-test:spring-boot-smoke-test-bootstrap-registry\"\ninclude \":smoke-test:spring-boot-smoke-test-cache\"\ninclude \":smoke-test:spring-boot-smoke-test-config\"\ninclude \":smoke-test:spring-boot-smoke-test-data-cassandra\"\ninclude \":smoke-test:spring-boot-smoke-test-data-couchbase\"\ninclude \":smoke-test:spring-boot-smoke-test-data-elasticsearch\"\ninclude \":smoke-test:spring-boot-smoke-test-data-jdbc\"\ninclude \":smoke-test:spring-boot-smoke-test-data-jpa\"\ninclude \":smoke-test:spring-boot-smoke-test-data-ldap\"\ninclude \":smoke-test:spring-boot-smoke-test-data-mongodb\"\ninclude \":smoke-test:spring-boot-smoke-test-data-r2dbc\"\ninclude \":smoke-test:spring-boot-smoke-test-data-r2dbc-flyway\"\ninclude \":smoke-test:spring-boot-smoke-test-data-r2dbc-liquibase\"\ninclude \":smoke-test:spring-boot-smoke-test-data-redis\"\ninclude \":smoke-test:spring-boot-smoke-test-data-rest\"\ninclude \":smoke-test:spring-boot-smoke-test-devtools\"\ninclude \":smoke-test:spring-boot-smoke-test-flyway\"\ninclude \":smoke-test:spring-boot-smoke-test-graphql\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-client\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-client-test\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-server\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-server-netty-shaded\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-server-oauth\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-server-servlet\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-server-secure\"\ninclude \":smoke-test:spring-boot-smoke-test-grpc-server-test\"\ninclude \":smoke-test:spring-boot-smoke-test-hateoas\"\ninclude \":smoke-test:spring-boot-smoke-test-hibernate\"\ninclude \":smoke-test:spring-boot-smoke-test-integration\"\ninclude \":smoke-test:spring-boot-smoke-test-jackson2-mixed\"\ninclude \":smoke-test:spring-boot-smoke-test-jackson2-only\"\ninclude \":smoke-test:spring-boot-smoke-test-jersey\"\ninclude \":smoke-test:spring-boot-smoke-test-jetty\"\ninclude \":smoke-test:spring-boot-smoke-test-jetty-jsp\"\ninclude \":smoke-test:spring-boot-smoke-test-jetty-ssl\"\ninclude \":smoke-test:spring-boot-smoke-test-kafka\"\ninclude \":smoke-test:spring-boot-smoke-test-liquibase\"\ninclude \":smoke-test:spring-boot-smoke-test-log4j2\"\ninclude \":smoke-test:spring-boot-smoke-test-logback\"\ninclude \":smoke-test:spring-boot-smoke-test-oauth2-authorization-server\"\ninclude \":smoke-test:spring-boot-smoke-test-oauth2-client\"\ninclude \":smoke-test:spring-boot-smoke-test-oauth2-resource-server\"\ninclude \":smoke-test:spring-boot-smoke-test-opentelemetry\"\ninclude \":smoke-test:spring-boot-smoke-test-parent-context\"\ninclude \":smoke-test:spring-boot-smoke-test-profile\"\ninclude \":smoke-test:spring-boot-smoke-test-prometheus\"\ninclude \":smoke-test:spring-boot-smoke-test-property-validation\"\ninclude \":smoke-test:spring-boot-smoke-test-pulsar\"\ninclude \":smoke-test:spring-boot-smoke-test-quartz\"\ninclude \":smoke-test:spring-boot-smoke-test-reactive-oauth2-client\"\ninclude \":smoke-test:spring-boot-smoke-test-reactive-oauth2-resource-server\"\ninclude \":smoke-test:spring-boot-smoke-test-restclient\"\ninclude \":smoke-test:spring-boot-smoke-test-rsocket\"\ninclude \":smoke-test:spring-boot-smoke-test-saml2-service-provider\"\ninclude \":smoke-test:spring-boot-smoke-test-secure\"\ninclude \":smoke-test:spring-boot-smoke-test-secure-jersey\"\ninclude \":smoke-test:spring-boot-smoke-test-secure-webflux\"\ninclude \":smoke-test:spring-boot-smoke-test-servlet\"\ninclude \":smoke-test:spring-boot-smoke-test-session-jdbc\"\ninclude \":smoke-test:spring-boot-smoke-test-session-data-redis\"\ninclude \":smoke-test:spring-boot-smoke-test-session-data-redis-webflux\"\ninclude \":smoke-test:spring-boot-smoke-test-simple\"\ninclude \":smoke-test:spring-boot-smoke-test-structured-logging\"\ninclude \":smoke-test:spring-boot-smoke-test-structured-logging-log4j2\"\ninclude \":smoke-test:spring-boot-smoke-test-test\"\ninclude \":smoke-test:spring-boot-smoke-test-test-nomockito\"\ninclude \":smoke-test:spring-boot-smoke-test-testng\"\ninclude \":smoke-test:spring-boot-smoke-test-tomcat\"\ninclude \":smoke-test:spring-boot-smoke-test-tomcat-jsp\"\ninclude \":smoke-test:spring-boot-smoke-test-tomcat-multi-connectors\"\ninclude \":smoke-test:spring-boot-smoke-test-tomcat-ssl\"\ninclude \":smoke-test:spring-boot-smoke-test-traditional\"\ninclude \":smoke-test:spring-boot-smoke-test-war\"\ninclude \":smoke-test:spring-boot-smoke-test-web-application-type\"\ninclude \":smoke-test:spring-boot-smoke-test-web-freemarker\"\ninclude \":smoke-test:spring-boot-smoke-test-web-groovy-templates\"\ninclude \":smoke-test:spring-boot-smoke-test-web-jsp\"\ninclude \":smoke-test:spring-boot-smoke-test-web-method-security\"\ninclude \":smoke-test:spring-boot-smoke-test-web-mustache\"\ninclude \":smoke-test:spring-boot-smoke-test-web-secure\"\ninclude \":smoke-test:spring-boot-smoke-test-web-secure-custom\"\ninclude \":smoke-test:spring-boot-smoke-test-web-secure-jdbc\"\ninclude \":smoke-test:spring-boot-smoke-test-web-static\"\ninclude \":smoke-test:spring-boot-smoke-test-web-thymeleaf\"\ninclude \":smoke-test:spring-boot-smoke-test-webflux\"\ninclude \":smoke-test:spring-boot-smoke-test-webflux-coroutines\"\ninclude \":smoke-test:spring-boot-smoke-test-webservices\"\ninclude \":smoke-test:spring-boot-smoke-test-websocket-jetty\"\ninclude \":smoke-test:spring-boot-smoke-test-websocket-tomcat\"\ninclude \":smoke-test:spring-boot-smoke-test-xml\"\n\ninclude \":integration-test:spring-boot-actuator-integration-tests\"\ninclude \":integration-test:spring-boot-configuration-processor-integration-tests\"\ninclude \":integration-test:spring-boot-integration-tests\"\ninclude \":integration-test:spring-boot-loader-integration-tests\"\ninclude \":integration-test:spring-boot-server-integration-tests\"\ninclude \":integration-test:spring-boot-sni-integration-tests\"\ninclude \":integration-test:spring-boot-test-integration-tests\"\n\ninclude \":system-test:spring-boot-deployment-system-tests\"\ninclude \":system-test:spring-boot-image-system-tests\"\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot ActiveMQ smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-activemq\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-activemq-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-activemq\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/src/dockerTest/java/smoketest/activemq/SampleActiveMqTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.activemq.ActiveMQContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for demo application.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleActiveMqTests {\n\n\t@Container\n\t@ServiceConnection\n\tprivate static final ActiveMQContainer container = TestImage.container(ActiveMQContainer.class);\n\n\t@Autowired\n\tprivate Producer producer;\n\n\t@Test\n\tvoid sendSimpleMessage(CapturedOutput output) {\n\t\tthis.producer.send(\"Test message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1)).untilAsserted(() -> assertThat(output).contains(\"Test message\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/src/main/java/smoketest/activemq/Consumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq;\n\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Consumer {\n\n\t@JmsListener(destination = \"sample.queue\")\n\tpublic void receiveQueue(String text) {\n\t\tSystem.out.println(text);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/src/main/java/smoketest/activemq/Producer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq;\n\nimport jakarta.jms.Queue;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Producer implements CommandLineRunner {\n\n\t@Autowired\n\tprivate JmsClient jmsClient;\n\n\t@Autowired\n\tprivate Queue queue;\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tsend(\"Sample message\");\n\t\tSystem.out.println(\"Message was sent to the Queue\");\n\t}\n\n\tpublic void send(String msg) {\n\t\tthis.jmsClient.destination(this.queue).send(msg);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/src/main/java/smoketest/activemq/SampleActiveMQApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq;\n\nimport jakarta.jms.Queue;\nimport org.apache.activemq.command.ActiveMQQueue;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jms.annotation.EnableJms;\n\n@SpringBootApplication\n@EnableJms\npublic class SampleActiveMQApplication {\n\n\t@Bean\n\tpublic Queue queue() {\n\t\treturn new ActiveMQQueue(\"sample.queue\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActiveMQApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/src/main/java/smoketest/activemq/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.activemq;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq/src/main/resources/application.properties",
    "content": "spring.activemq.pool.enabled=false\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator ActiveMQ Embedded smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-activemq\"))\n\n\truntimeOnly(\"org.apache.activemq:activemq-broker\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-activemq-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/src/main/java/smoketest/activemq/embedded/Consumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq.embedded;\n\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Consumer {\n\n\t@JmsListener(destination = \"sample.queue\")\n\tpublic void receiveQueue(String text) {\n\t\tSystem.out.println(text);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/src/main/java/smoketest/activemq/embedded/Producer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq.embedded;\n\nimport jakarta.jms.Queue;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Producer implements CommandLineRunner {\n\n\t@Autowired\n\tprivate JmsClient jmsClient;\n\n\t@Autowired\n\tprivate Queue queue;\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tsend(\"Sample message\");\n\t\tSystem.out.println(\"Message was sent to the Queue\");\n\t}\n\n\tpublic void send(String msg) {\n\t\tthis.jmsClient.destination(this.queue).send(msg);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/src/main/java/smoketest/activemq/embedded/SampleActiveMQApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq.embedded;\n\nimport jakarta.jms.Queue;\nimport org.apache.activemq.command.ActiveMQQueue;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jms.annotation.EnableJms;\n\n@SpringBootApplication\n@EnableJms\npublic class SampleActiveMQApplication {\n\n\t@Bean\n\tpublic Queue queue() {\n\t\treturn new ActiveMQQueue(\"sample.queue\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActiveMQApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/src/main/java/smoketest/activemq/embedded/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.activemq.embedded;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-activemq-embedded/src/test/java/smoketest/activemq/embedded/SampleActiveMQApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.activemq.embedded;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for ActiveMQ smoke test with embedded broker.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleActiveMQApplicationTests {\n\n\t@Autowired\n\tprivate Producer producer;\n\n\t@Test\n\tvoid sendSimpleMessage(CapturedOutput output) throws InterruptedException {\n\t\tthis.producer.send(\"Test message\");\n\t\tThread.sleep(1000L);\n\t\tassertThat(output).contains(\"Test message\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-jdbc\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\timplementation(project(\":starter:spring-boot-starter-validation\"))\n\timplementation(\"io.micrometer:micrometer-tracing-bridge-brave\")\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-actuator-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\n\ttestRuntimeOnly(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/ExampleHealthIndicator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ExampleHealthIndicator implements HealthIndicator {\n\n\t@Override\n\tpublic Health health() {\n\t\treturn Health.up().withDetail(\"counter\", 42).build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/ExampleInfoContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Collections;\n\nimport org.springframework.boot.actuate.info.Info;\nimport org.springframework.boot.actuate.info.InfoContributor;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class ExampleInfoContributor implements InfoContributor {\n\n\t@Override\n\tpublic void contribute(Info.Builder builder) {\n\t\tbuilder.withDetail(\"example\", Collections.singletonMap(\"someKey\", \"someValue\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\tprivate final ServiceProperties configuration;\n\n\tpublic HelloWorldService(ServiceProperties configuration) {\n\t\tthis.configuration = configuration;\n\t}\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.configuration.getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/SampleActuatorApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\nimport org.springframework.boot.health.contributor.CompositeHealthContributor;\nimport org.springframework.boot.health.contributor.Health;\nimport org.springframework.boot.health.contributor.HealthContributor;\nimport org.springframework.boot.health.contributor.HealthIndicator;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\n@ConfigurationPropertiesScan\npublic class SampleActuatorApplication {\n\n\t@Bean\n\tpublic HealthIndicator helloHealthIndicator() {\n\t\treturn createHealthIndicator(\"world\");\n\t}\n\n\t@Bean\n\tpublic HealthContributor compositeHelloHealthContributor() {\n\t\tMap<String, HealthContributor> map = new LinkedHashMap<>();\n\t\tmap.put(\"spring\", createNestedHealthContributor(\"spring\"));\n\t\tmap.put(\"boot\", createNestedHealthContributor(\"boot\"));\n\t\treturn CompositeHealthContributor.fromMap(map);\n\t}\n\n\tprivate HealthContributor createNestedHealthContributor(String name) {\n\t\tMap<String, HealthContributor> map = new LinkedHashMap<>();\n\t\tmap.put(\"a\", createHealthIndicator(name + \"-a\"));\n\t\tmap.put(\"b\", createHealthIndicator(name + \"-b\"));\n\t\tmap.put(\"c\", createHealthIndicator(name + \"-c\"));\n\t\treturn CompositeHealthContributor.fromMap(map);\n\t}\n\n\tprivate HealthIndicator createHealthIndicator(String value) {\n\t\treturn () -> Health.up().withDetail(\"hello\", value).build();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication(SampleActuatorApplication.class);\n\t\tapplication.setApplicationStartup(new BufferingApplicationStartup(1024));\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport jakarta.validation.constraints.NotBlank;\n\nimport org.springframework.context.annotation.Description;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.validation.annotation.Validated;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\n@Description(\"A controller for handling requests for hello messages\")\npublic class SampleController {\n\n\tprivate final HelloWorldService helloWorldService;\n\n\tpublic SampleController(HelloWorldService helloWorldService) {\n\t\tthis.helloWorldService = helloWorldService;\n\t}\n\n\t@GetMapping(value = \"/\", produces = MediaType.APPLICATION_JSON_VALUE)\n\t@ResponseBody\n\tpublic Map<String, String> hello() {\n\t\treturn Collections.singletonMap(\"message\", this.helloWorldService.getHelloMessage());\n\t}\n\n\t@PostMapping(value = \"/\", produces = MediaType.APPLICATION_JSON_VALUE)\n\t@ResponseBody\n\tpublic Map<String, Object> olleh(@Validated Message message) {\n\t\tMap<String, Object> model = new LinkedHashMap<>();\n\t\tmodel.put(\"message\", message.getValue());\n\t\tmodel.put(\"title\", \"Hello Home\");\n\t\tmodel.put(\"date\", new Date());\n\t\treturn model;\n\t}\n\n\t@RequestMapping(\"/foo\")\n\t@ResponseBody\n\tpublic String foo() {\n\t\tthrow new IllegalArgumentException(\"Server error\");\n\t}\n\n\tprotected static class Message {\n\n\t\t@NotBlank(message = \"Message value cannot be empty\")\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String value;\n\n\t\tpublic String getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\tpublic void setValue(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/SampleLegacyEndpointWithDot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Endpoint(id = \"lega.cy\")\npublic class SampleLegacyEndpointWithDot {\n\n\t@ReadOperation\n\tpublic Map<String, String> example() {\n\t\treturn Collections.singletonMap(\"legacy\", \"legacy\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/SampleLegacyEndpointWithHyphen.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Endpoint(id = \"another-legacy\")\npublic class SampleLegacyEndpointWithHyphen {\n\n\t@ReadOperation\n\tpublic Map<String, String> example() {\n\t\treturn Collections.singletonMap(\"legacy\", \"legacy\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/SampleRestControllerEndpointWithException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\n/**\n * The Sample rest controller endpoint with exception.\n *\n * @author Guirong Hu\n */\n@Component\n@RestControllerEndpoint(id = \"exception\")\n@SuppressWarnings(\"removal\")\npublic class SampleRestControllerEndpointWithException {\n\n\t@GetMapping(\"/\")\n\tpublic String exception() {\n\t\tthrow new CustomException();\n\t}\n\n\t@RestControllerAdvice\n\tstatic class CustomExceptionHandler {\n\n\t\t@ExceptionHandler(CustomException.class)\n\t\tResponseEntity<String> handleCustomException(CustomException e) {\n\t\t\treturn new ResponseEntity<>(\"this is a custom exception body\", HttpStatus.EXPECTATION_FAILED);\n\t\t}\n\n\t}\n\n\tstatic class CustomException extends RuntimeException {\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/ServiceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = \"service\", ignoreUnknownFields = false)\npublic class ServiceProperties {\n\n\t/**\n\t * Name of the service.\n\t */\n\tprivate String name = \"World\";\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/java/smoketest/actuator/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.actuator;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/resources/META-INF/build-info.properties",
    "content": "build.artifact=spring-boot-smoke-test-actuator\nbuild.encoding.source=UTF-8\nbuild.encoding.reporting=UTF-8\nbuild.java.source=1.8\nbuild.java.target=1.8"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/resources/application.properties",
    "content": "spring.application.name=sample (test)\nspring.application.group=sample-group\n#logging.include-application-name=false\n#logging.include-application-group=false\nservice.name=Phil\n\nspring.security.user.name=user\nspring.security.user.password=password\n\n# logging.file.name=/tmp/logs/app.log\n# logging.level.org.springframework.security=DEBUG\n\nmanagement.endpoints.web.exposure.include=*\nmanagement.endpoint.shutdown.enabled=true\n\nserver.tomcat.basedir=target/tomcat\nserver.tomcat.accesslog.enabled=true\nserver.tomcat.accesslog.pattern=%h %t \"%r\" %s %b\n#spring.jackson.serialization.INDENT_OUTPUT=true\nspring.jmx.enabled=true\n\nmanagement.httpexchanges.recording.include=request-headers,response-headers,principal,remote-address,session-id\n\nmanagement.endpoint.health.show-details=always\nmanagement.endpoint.health.group.ready.include=db,diskSpace\nmanagement.endpoint.health.group.live.include=example,hello,db\nmanagement.endpoint.health.group.live.show-details=never\nmanagement.endpoint.health.group.comp.include=compositeHello/spring/a,compositeHello/spring/c\nmanagement.endpoint.health.group.comp.show-details=always\n\nmanagement.endpoints.migrate-legacy-ids=true\n\nmanagement.endpoints.jackson.isolated-json-mapper=true\nspring.jackson.mapper.require-setters-for-getters=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"CONSOLE\"/>\n\t</root>\n</configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/AbstractManagementPortAndPathSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.core.env.Environment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for integration tests with separate management and main service ports.\n *\n * @author Dave Syer\n */\nabstract class AbstractManagementPortAndPathSampleActuatorApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tnew TestRestTemplate(\"user\", \"password\").getForEntity(\"http://localhost:\" + this.port, Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsEntry(\"message\", \"Hello Phil\");\n\t}\n\n\t@Test\n\tvoid testMetrics() {\n\t\ttestHome(); // makes sure some requests have been made\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(new TestRestTemplate()\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/admin/metrics\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/admin/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody())\n\t\t\t.isEqualTo(\"{\\\"groups\\\":[\\\"comp\\\",\\\"live\\\",\\\"liveness\\\",\\\"readiness\\\",\\\"ready\\\"],\\\"status\\\":\\\"UP\\\"}\");\n\t}\n\n\t@Test\n\tvoid testGroupWithComposite() {\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/admin/health/comp\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\n\t\t\t\t\"components\\\":{\\\"a\\\":{\\\"details\\\":{\\\"hello\\\":\\\"spring-a\\\"},\\\"status\\\":\\\"UP\\\"},\\\"c\\\":{\\\"details\\\":{\\\"hello\\\":\\\"spring-c\\\"},\\\"status\\\":\\\"UP\\\"}}\");\n\t}\n\n\t@Test\n\tvoid testEnvNotFound() {\n\t\tString unknownProperty = \"test-does-not-exist\";\n\t\tassertThat(this.environment.containsProperty(unknownProperty)).isFalse();\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/admin/env/\" + unknownProperty, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid testMissing() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/admin/missing\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":404\");\n\t}\n\n\t@Test\n\tvoid testErrorPage() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.port + \"/error\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(entity.getBody()).containsEntry(\"status\", 999);\n\t}\n\n\t@Test\n\tvoid testManagementErrorPage() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/error\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsEntry(\"status\", 999);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ApplicationStartupSpringBootContextLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.test.context.SpringBootContextLoader;\n\nclass ApplicationStartupSpringBootContextLoader extends SpringBootContextLoader {\n\n\t@Override\n\tprotected SpringApplication getSpringApplication() {\n\t\tSpringApplication application = new SpringApplication();\n\t\tapplication.setApplicationStartup(new BufferingApplicationStartup(1024));\n\t\treturn application;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/CorsSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.net.URI;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ActiveProfiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for cors preflight requests to management endpoints.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@ActiveProfiles(\"cors\")\n@AutoConfigureTestRestTemplate\nclass CorsSampleActuatorApplicationTests {\n\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder();\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.obtain(this.applicationContext);\n\t\tbuilder = builder.uriTemplateHandler(localTestWebServer.uriBuilderFactory());\n\t\tthis.testRestTemplate = new TestRestTemplate(builder);\n\t}\n\n\t@Test\n\tvoid endpointShouldReturnUnauthorized() {\n\t\tResponseEntity<?> entity = this.testRestTemplate.getForEntity(\"/actuator/env\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid preflightRequestToEndpointShouldReturnOk() throws Exception {\n\t\tRequestEntity<?> healthRequest = RequestEntity.options(new URI(\"/actuator/env\"))\n\t\t\t.header(\"Origin\", \"http://localhost:8080\")\n\t\t\t.header(\"Access-Control-Request-Method\", \"GET\")\n\t\t\t.build();\n\t\tResponseEntity<?> exchange = this.testRestTemplate.exchange(healthRequest, Map.class);\n\t\tassertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid preflightRequestWhenCorsConfigInvalidShouldReturnForbidden() throws Exception {\n\t\tRequestEntity<?> entity = RequestEntity.options(new URI(\"/actuator/env\"))\n\t\t\t.header(\"Origin\", \"http://localhost:9095\")\n\t\t\t.header(\"Access-Control-Request-Method\", \"GET\")\n\t\t\t.build();\n\t\tResponseEntity<byte[]> exchange = this.testRestTemplate.exchange(entity, byte[].class);\n\t\tassertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ActiveProfiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for endpoints configuration.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@ActiveProfiles(\"endpoints\")\n@AutoConfigureTestRestTemplate\nclass EndpointsPropertiesSampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testCustomErrorPath() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/oops\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).containsEntry(\"error\", \"None\");\n\t\tassertThat(body).containsEntry(\"status\", 999);\n\t}\n\n\t@Test\n\tvoid testCustomContextPath() {\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"/admin/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t\tassertThat(entity.getBody()).contains(\"\\\"hello\\\":\\\"world\\\"\");\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementAddressActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"management.server.port=0\",\n\t\t\"management.server.address=127.0.0.1\", \"management.server.base-path:/admin\" })\nclass ManagementAddressActuatorApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tnew TestRestTemplate().getForEntity(\"http://localhost:\" + this.port, Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/admin/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementDifferentPortAndEndpointWithExceptionHandlerSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with Actuator's MVC\n * {@link org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint\n * rest controller endpoints} and {@link ExceptionHandler exception handler}.\n *\n * @author Guirong Hu\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.web.exposure.include=*\", \"management.server.port=0\" })\nclass ManagementDifferentPortAndEndpointWithExceptionHandlerSampleActuatorApplicationTests {\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid testExceptionHandlerRestControllerEndpoint() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/exception\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.EXPECTATION_FAILED);\n\t\tassertThat(entity.getBody()).isEqualTo(\"this is a custom exception body\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementDifferentPortSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with empty endpoint\n * base path.\n *\n * @author HaiTao Zhang\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.web.base-path=/\", \"management.server.port=0\" })\nclass ManagementDifferentPortSampleActuatorApplicationTests {\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid linksEndpointShouldBeAvailable() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"_links\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementEndpointConflictSmokeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.SpringApplication;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Verifies that an exception is thrown when management and server endpoint paths\n * conflict.\n *\n * @author Yongjun Hong\n */\nclass ManagementEndpointConflictSmokeTests {\n\n\t@Test\n\tvoid shouldThrowExceptionWhenManagementAndServerPathsConflict() {\n\t\tassertThatExceptionOfType(BeanCreationException.class)\n\t\t\t.isThrownBy(() -> SpringApplication.run(SampleActuatorApplication.class,\n\t\t\t\t\t\"--management.endpoints.web.base-path=/\", \"--management.endpoints.web.path-mapping.health=/\"))\n\t\t\t.withMessageContaining(\"Management base path and the 'health' actuator endpoint are both mapped to '/'\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementPathSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for endpoints configuration.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.web.base-path=/admin\" })\n@AutoConfigureTestRestTemplate\nclass ManagementPathSampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"/admin/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\t@Test\n\tvoid testHomeIsSecure() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(this.restTemplate.getForEntity(\"/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tassertThat(entity.getHeaders().headerNames()).doesNotContain(\"Set-Cookie\");\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementPortAndPathWithAntPatcherSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"management.server.port=0\",\n\t\t\"management.endpoints.web.base-path=/admin\", \"management.endpoint.health.show-details=never\" })\nclass ManagementPortAndPathWithAntPatcherSampleActuatorApplicationTests\n\t\textends AbstractManagementPortAndPathSampleActuatorApplicationTests {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementPortAndPathWithPathMatcherSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.mvc.pathmatch.matching-strategy=path-pattern-parser\", \"management.server.port=0\",\n\t\t\t\t\"management.endpoints.web.base-path=/admin\", \"management.endpoint.health.show-details=never\" })\nclass ManagementPortAndPathWithPathMatcherSampleActuatorApplicationTests\n\t\textends AbstractManagementPortAndPathSampleActuatorApplicationTests {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementPortSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport smoketest.actuator.ManagementPortSampleActuatorApplicationTests.CustomErrorAttributes;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.web.error.ErrorAttributeOptions;\nimport org.springframework.boot.webmvc.error.DefaultErrorAttributes;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.security.core.context.SecurityContext;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.web.context.request.WebRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"management.endpoint.health.show-details=always\" })\n@Import(CustomErrorAttributes.class)\nclass ManagementPortSampleActuatorApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate CustomErrorAttributes errorAttributes;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tnew TestRestTemplate(\"user\", \"password\").getForEntity(\"http://localhost:\" + this.port, Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsEntry(\"message\", \"Hello Phil\");\n\t}\n\n\t@Test\n\tvoid testMetrics() {\n\t\ttestHome(); // makes sure some requests have been made\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(new TestRestTemplate()\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/metrics\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t\tassertThat(entity.getBody()).contains(\"\\\"example\\\"\");\n\t\tassertThat(entity.getBody()).contains(\"\\\"counter\\\":42\");\n\t}\n\n\t@Test\n\tvoid testErrorPage() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/error\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsEntry(\"status\", 999);\n\t}\n\n\t@Test\n\tvoid securityContextIsAvailableToErrorHandling() {\n\t\tthis.errorAttributes.securityContext = null;\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(new TestRestTemplate(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/404\", Map.class));\n\t\tassertThat(this.errorAttributes.securityContext).isNotNull();\n\t\tassertThat(this.errorAttributes.securityContext.getAuthentication()).isNotNull();\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tassertThat(entity.getBody()).containsEntry(\"status\", 404);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n\tstatic class CustomErrorAttributes extends DefaultErrorAttributes {\n\n\t\tprivate volatile @Nullable SecurityContext securityContext;\n\n\t\t@Override\n\t\tpublic Map<String, @Nullable Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {\n\t\t\tthis.securityContext = SecurityContextHolder.getContext();\n\t\t\treturn super.getErrorAttributes(webRequest, options);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementPortWithLazyInitializationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports when\n * lazy-initialization is enabled.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"spring.main.lazy-initialization=true\" })\nclass ManagementPortWithLazyInitializationTests {\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ManagementRandomPortWithConfiguredPortSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports when a management port\n * is set.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, args = \"--management.server.port=1234\")\nclass ManagementRandomPortWithConfiguredPortSampleActuatorApplicationTests {\n\n\t@LocalServerPort\n\tprivate int serverPort;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid randomPortsShouldBeDifferent() {\n\t\tassertThat(this.serverPort).isPositive();\n\t\tassertThat(this.managementPort).isPositive();\n\t\tassertThat(this.serverPort).isNotEqualTo(this.managementPort);\n\t}\n\n\t@Test\n\tvoid randomManagementPortShouldBeApplied() {\n\t\tassertThat(this.managementPort).isNotEqualTo(1234);\n\t}\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = new TestRestTemplate().withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/NoManagementSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for switching off management endpoints.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"management.server.port=-1\" })\n@AutoConfigureTestRestTemplate\nclass NoManagementSampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsEntry(\"message\", \"Hello Phil\");\n\t}\n\n\t@Test\n\tvoid testMetricsNotAvailable() {\n\t\ttestHome(); // makes sure some requests have been made\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/metrics\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/SampleActuatorApplicationIsolatedJsonMapperFalseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for WebMVC actuator when not using an isolated {@link JsonMapper}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.jackson.isolated-json-mapper=false\",\n\t\t\t\t\"spring.jackson.mapper.require-setters-for-getters=true\" })\n@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)\n@AutoConfigureTestRestTemplate\nclass SampleActuatorApplicationIsolatedJsonMapperFalseTests {\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid bodyIsEmptyDueToMainJsonMapperRequiringSettersForGetters() {\n\t\tResponseEntity<String> entity = this.testRestTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"/actuator/startup\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"{}\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/SampleActuatorApplicationIsolatedJsonMapperTrueTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for WebMVC actuator when using an isolated {@link JsonMapper}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.jackson.isolated-json-mapper=true\",\n\t\t\t\t\"spring.jackson.mapper.require-setters-for-getters=true\" })\n@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)\n@AutoConfigureTestRestTemplate\nclass SampleActuatorApplicationIsolatedJsonMapperTrueTests {\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid bodyIsPresentAsOnlyMainObjectMapperRequiresSettersForGetters() {\n\t\tResponseEntity<String> entity = this.testRestTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"/actuator/startup\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"timeline\\\":\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/SampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Basic integration tests for service demo application.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testHomeIsSecure() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(this.restTemplate.getForEntity(\"/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tassertThat(entity.getHeaders().headerNames()).doesNotContain(\"Set-Cookie\");\n\t}\n\n\t@Test\n\tvoid testMetricsIsSecure() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.getForEntity(\"/actuator/metrics\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = asMapEntity(this.restTemplate.getForEntity(\"/actuator/metrics/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = asMapEntity(this.restTemplate.getForEntity(\"/actuator/metrics/foo\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = asMapEntity(this.restTemplate.getForEntity(\"/actuator/metrics.json\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsEntry(\"message\", \"Hello Phil\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testMetrics() {\n\t\ttestHome(); // makes sure some requests have been made\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/metrics\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tassertThat(body).containsKey(\"names\");\n\t\tList<String> names = (List<String>) body.get(\"names\");\n\t\tassertThat(names).contains(\"jvm.buffer.count\");\n\t}\n\n\t@Test\n\tvoid testEnv() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/env\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsKey(\"propertySources\");\n\t}\n\n\t@Test\n\tvoid healthInsecureByDefault() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t\tassertThat(entity.getBody()).doesNotContain(\"\\\"hello\\\":\\\"1\\\"\");\n\t}\n\n\t@Test\n\tvoid testErrorPage() {\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"/foo\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tString body = entity.getBody();\n\t\tassertThat(body).contains(\"\\\"error\\\":\");\n\t}\n\n\t@Test\n\tvoid testHtmlErrorPage() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<?> request = new HttpEntity<Void>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.exchange(\"/foo\", HttpMethod.GET, request, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tString body = entity.getBody();\n\t\tassertThat(body).as(\"Body was null\").isNotNull();\n\t\tassertThat(body).contains(\"This application has no explicit mapping for /error\");\n\t}\n\n\t@Test\n\tvoid testErrorPageDirectAccess() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/error\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(entity.getBody()).containsEntry(\"error\", \"None\");\n\t\tassertThat(entity.getBody()).containsEntry(\"status\", 999);\n\t}\n\n\t@Test\n\tvoid testBeans() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/beans\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsOnlyKeys(\"contexts\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testConfigProps() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/configprops\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tMap<String, Object> contexts = (Map<String, Object>) body.get(\"contexts\");\n\t\tassertThat(contexts).isNotNull();\n\t\tMap<String, Object> context = (Map<String, Object>) contexts.get(this.applicationContext.getId());\n\t\tassertThat(context).isNotNull();\n\t\tMap<String, Object> beans = (Map<String, Object>) context.get(\"beans\");\n\t\tassertThat(beans).containsKey(\"spring.datasource-\" + DataSourceProperties.class.getName());\n\t}\n\n\t@Test\n\tvoid testLegacyDot() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/legacy\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(entry(\"legacy\", \"legacy\"));\n\t}\n\n\t@Test\n\tvoid testLegacyHyphen() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/anotherlegacy\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(entry(\"legacy\", \"legacy\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid testInfo() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/actuator/info\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).containsKey(\"build\");\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tMap<String, Object> example = (Map<String, Object>) body.get(\"example\");\n\t\tassertThat(example).containsEntry(\"someKey\", \"someValue\");\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ServletPathSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for endpoints configuration.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"spring.mvc.servlet.path=/spring\" })\n@AutoConfigureTestRestTemplate\nclass ServletPathSampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testErrorPath() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/spring/error\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(entity.getBody()).containsEntry(\"error\", \"None\");\n\t\tassertThat(entity.getBody()).containsEntry(\"status\", 999);\n\t}\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.getForEntity(\"/spring/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\t@Test\n\tvoid testHomeIsSecure() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(this.restTemplate.getForEntity(\"/spring/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tassertThat(entity.getHeaders().headerNames()).doesNotContain(\"Set-Cookie\");\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/ShutdownSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Dave Syer\n */\n@SpringBootTest(classes = { ShutdownSampleActuatorApplicationTests.SecurityConfiguration.class,\n\t\tSampleActuatorApplication.class }, webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass ShutdownSampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(\n\t\t\t\tthis.restTemplate.withBasicAuth(\"user\", \"password\").getForEntity(\"/\", Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).containsEntry(\"message\", \"Hello Phil\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tvoid testShutdown() {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(this.restTemplate.withBasicAuth(\"user\", \"password\")\n\t\t\t.postForEntity(\"/actuator/shutdown\", null, Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tassertThat(((String) body.get(\"message\"))).contains(\"Shutting down\");\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tstatic <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/resources/application-cors.properties",
    "content": "management.endpoints.web.cors.allowed-origins=http://localhost:8080\nmanagement.endpoints.web.cors.allowed-methods=GET\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator/src/test/resources/application-endpoints.properties",
    "content": "spring.web.error.path:/oops\nmanagement.endpoint.health.show-details:always\nmanagement.endpoints.web.base-path:/admin\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator custom security smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-freemarker\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-actuator-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\n\ttestRuntimeOnly(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\npublic class ExampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String home(Map<String, Object> model) {\n\t\tmodel.put(\"message\", \"Hello World\");\n\t\tmodel.put(\"title\", \"Hello Home\");\n\t\tmodel.put(\"date\", new Date());\n\t\treturn \"home\";\n\t}\n\n\t@RequestMapping(\"/foo\")\n\tpublic String foo() {\n\t\tthrow new RuntimeException(\"Expected exception in controller\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/ExampleRestControllerEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport org.springframework.boot.actuate.endpoint.web.annotation.RestControllerEndpoint;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\n\n@Component\n@RestControllerEndpoint(id = \"example\")\n@SuppressWarnings(\"removal\")\npublic class ExampleRestControllerEndpoint {\n\n\t@GetMapping(\"/echo\")\n\tpublic ResponseEntity<String> echo(@RequestParam(\"text\") String text) {\n\t\treturn ResponseEntity.ok().header(\"echo\", text).body(text);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/SampleActuatorCustomSecurityApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport java.io.IOException;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.actuate.endpoint.web.EndpointServlet;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\n@SuppressWarnings(\"removal\")\npublic class SampleActuatorCustomSecurityApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActuatorCustomSecurityApplication.class, args);\n\t}\n\n\t@Bean\n\tTestServletEndpoint servletEndpoint() {\n\t\treturn new TestServletEndpoint();\n\t}\n\n\t@ServletEndpoint(id = \"se1\")\n\tstatic class TestServletEndpoint implements Supplier<EndpointServlet> {\n\n\t\t@Override\n\t\tpublic EndpointServlet get() {\n\t\t\treturn new EndpointServlet(ExampleServlet.class);\n\t\t}\n\n\t}\n\n\tstatic class ExampleServlet extends HttpServlet {\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/SecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.boot.security.autoconfigure.web.servlet.PathRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.User.UserBuilder;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\npublic class SecurityConfiguration {\n\n\t@Bean\n\tpublic InMemoryUserDetailsManager inMemoryUserDetailsManager() {\n\t\tList<UserDetails> userDetails = new ArrayList<>();\n\t\tuserDetails.add(createUserDetails(\"user\", \"password\", \"ROLE_USER\"));\n\t\tuserDetails.add(createUserDetails(\"beans\", \"beans\", \"ROLE_BEANS\"));\n\t\tuserDetails.add(createUserDetails(\"admin\", \"admin\", \"ROLE_ACTUATOR\", \"ROLE_USER\"));\n\t\treturn new InMemoryUserDetailsManager(userDetails);\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate UserDetails createUserDetails(String username, String password, String... authorities) {\n\t\tUserBuilder builder = User.withDefaultPasswordEncoder();\n\t\tbuilder.username(username);\n\t\tbuilder.password(password);\n\t\tbuilder.authorities(authorities);\n\t\treturn builder.build();\n\t}\n\n\t@Bean\n\tSecurityFilterChain configure(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\trequests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(\"/actuator/beans\"))\n\t\t\t\t.hasRole(\"BEANS\");\n\t\t\trequests.requestMatchers(EndpointRequest.to(\"health\")).permitAll();\n\t\t\trequests.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))\n\t\t\t\t.hasRole(\"ACTUATOR\");\n\t\t\trequests.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();\n\t\t\trequests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(\"/foo\")).permitAll();\n\t\t\trequests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(\"/error\")).permitAll();\n\t\t\trequests.requestMatchers(PathPatternRequestMatcher.withDefaults().matcher(\"/**\")).hasRole(\"USER\");\n\t\t});\n\t\thttp.cors(withDefaults());\n\t\thttp.httpBasic(withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/java/smoketest/actuator/customsecurity/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.actuator.customsecurity;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nmanagement.endpoint.health.show-details=always\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/resources/templates/error.ftlh",
    "content": "<#import \"/spring.ftl\" as spring />\n<!DOCTYPE html>\n<html>\n<head>\n<title>Error</title>\n<#assign home><@spring.url relativeUrl=\"/\"/></#assign>\n<#assign bootstrap><@spring.url relativeUrl=\"/css/bootstrap.min.css\"/></#assign>\n<link rel=\"stylesheet\" href=\"${bootstrap}\" />\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"navbar\">\n\t\t\t<div class=\"navbar-inner\">\n\t\t\t\t<a class=\"brand\" href=\"https://freemarker.apache.org/\"> FreeMarker -\n\t\t\t\t\tPlain </a>\n\t\t\t\t<ul class=\"nav\">\n\t\t\t\t\t<li><a href=\"${home}\"> Home </a></li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t\t<h1>Error Page</h1>\n\t\t<div id=\"created\">${timestamp?datetime}</div>\n\t\t<div>\n\t\t\tThere was an unexpected error (type=${error}, status=${status}).\n\t\t</div>\n\t\t<div>${message}</div>\n\t\t<div>\n\t\t\tPlease contact the operator with the above information.\n\t\t</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/main/resources/templates/home.ftlh",
    "content": "<#import \"/spring.ftl\" as spring />\n<!DOCTYPE html>\n<html>\n<head>\n<title>${title}</title>\n<#assign home><@spring.url relativeUrl=\"/\"/></#assign>\n<#assign bootstrap><@spring.url relativeUrl=\"/css/bootstrap.min.css\"/></#assign>\n<link rel=\"stylesheet\" href=\"${bootstrap}\" />\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"navbar\">\n\t\t\t<div class=\"navbar-inner\">\n\t\t\t\t<a class=\"brand\" href=\"https://freemarker.apache.org/\"> FreeMarker -\n\t\t\t\t\tPlain </a>\n\t\t\t\t<ul class=\"nav\">\n\t\t\t\t\t<li><a href=\"${home}\"> Home </a></li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t\t<h1>${title}</h1>\n\t\t<div>${message}</div>\n\t\t<div id=\"created\">${date?datetime}</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/AbstractSampleActuatorCustomSecurityTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for actuator tests with custom security.\n *\n * @author Madhura Bhave\n */\nabstract class AbstractSampleActuatorCustomSecurityTests {\n\n\tabstract String getPath();\n\n\tabstract String getActuatorPath();\n\n\tabstract ApplicationContext getApplicationContext();\n\n\t@Test\n\tvoid homeIsSecure() {\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tResponseEntity<Map> entity = restTemplate().getForEntity(getPath() + \"/\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tassertThat(entity.getHeaders().headerNames()).doesNotContain(\"Set-Cookie\");\n\t}\n\n\t@Test\n\tvoid testInsecureStaticResources() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getPath() + \"/css/bootstrap.min.css\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"body\");\n\t}\n\n\t@Test\n\tvoid actuatorInsecureEndpoint() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getActuatorPath() + \"/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t\tentity = restTemplate().getForEntity(getActuatorPath() + \"/health/diskSpace\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\t@Test\n\tvoid actuatorLinksWithAnonymous() {\n\t\tResponseEntity<Object> entity = restTemplate().getForEntity(getActuatorPath(), Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = restTemplate().getForEntity(getActuatorPath() + \"/\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid actuatorLinksWithUnauthorizedUser() {\n\t\tResponseEntity<Object> entity = userRestTemplate().getForEntity(getActuatorPath(), Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tentity = userRestTemplate().getForEntity(getActuatorPath() + \"/\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid actuatorLinksWithAuthorizedUser() {\n\t\tResponseEntity<Object> entity = adminRestTemplate().getForEntity(getActuatorPath(), Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tadminRestTemplate().getForEntity(getActuatorPath() + \"/\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid actuatorSecureEndpointWithAnonymous() {\n\t\tResponseEntity<Object> entity = restTemplate().getForEntity(getActuatorPath() + \"/env\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = restTemplate().getForEntity(getActuatorPath() + \"/env/management.endpoints.web.exposure.include\",\n\t\t\t\tObject.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid actuatorSecureEndpointWithUnauthorizedUser() {\n\t\tResponseEntity<Object> entity = userRestTemplate().getForEntity(getActuatorPath() + \"/env\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tentity = userRestTemplate().getForEntity(getActuatorPath() + \"/env/management.endpoints.web.exposure.include\",\n\t\t\t\tObject.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid actuatorSecureEndpointWithAuthorizedUser() {\n\t\tResponseEntity<Object> entity = adminRestTemplate().getForEntity(getActuatorPath() + \"/env\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tentity = adminRestTemplate().getForEntity(getActuatorPath() + \"/env/\", Object.class);\n\t\t// EndpointRequest matches the trailing slash but MVC doesn't\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tentity = adminRestTemplate().getForEntity(getActuatorPath() + \"/env/management.endpoints.web.exposure.include\",\n\t\t\t\tObject.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid secureServletEndpointWithAnonymous() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getActuatorPath() + \"/se1\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = restTemplate().getForEntity(getActuatorPath() + \"/se1/list\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid secureServletEndpointWithUnauthorizedUser() {\n\t\tResponseEntity<String> entity = userRestTemplate().getForEntity(getActuatorPath() + \"/se1\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tentity = userRestTemplate().getForEntity(getActuatorPath() + \"/se1/list\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid secureServletEndpointWithAuthorizedUser() {\n\t\tResponseEntity<String> entity = adminRestTemplate().getForEntity(getActuatorPath() + \"/se1\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tentity = adminRestTemplate().getForEntity(getActuatorPath() + \"/se1/list\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid actuatorCustomMvcSecureEndpointWithAnonymous() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getActuatorPath() + \"/example/echo?text={t}\",\n\t\t\t\tString.class, \"test\");\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid actuatorCustomMvcSecureEndpointWithUnauthorizedUser() {\n\t\tResponseEntity<String> entity = userRestTemplate().getForEntity(getActuatorPath() + \"/example/echo?text={t}\",\n\t\t\t\tString.class, \"test\");\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid actuatorCustomMvcSecureEndpointWithAuthorizedUser() {\n\t\tResponseEntity<String> entity = adminRestTemplate().getForEntity(getActuatorPath() + \"/example/echo?text={t}\",\n\t\t\t\tString.class, \"test\");\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"test\");\n\t\tassertThat(entity.getHeaders().getFirst(\"echo\")).isEqualTo(\"test\");\n\t}\n\n\t@Test\n\tvoid actuatorExcludedFromEndpointRequestMatcher() {\n\t\tResponseEntity<Object> entity = userRestTemplate().getForEntity(getActuatorPath() + \"/mappings\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\tTestRestTemplate restTemplate() {\n\t\treturn configure(new TestRestTemplate());\n\t}\n\n\tTestRestTemplate adminRestTemplate() {\n\t\treturn configure(new TestRestTemplate(\"admin\", \"admin\"));\n\t}\n\n\tTestRestTemplate userRestTemplate() {\n\t\treturn configure(new TestRestTemplate(\"user\", \"password\"));\n\t}\n\n\tTestRestTemplate beansRestTemplate() {\n\t\treturn configure(new TestRestTemplate(\"beans\", \"beans\"));\n\t}\n\n\tprivate TestRestTemplate configure(TestRestTemplate restTemplate) {\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.obtain(getApplicationContext());\n\t\trestTemplate.setUriTemplateHandler(localTestWebServer.uriBuilderFactory());\n\t\treturn restTemplate;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/CorsSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport java.net.URI;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ActiveProfiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for cors preflight requests to management endpoints.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@ActiveProfiles(\"cors\")\n@AutoConfigureTestRestTemplate\nclass CorsSampleActuatorApplicationTests {\n\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tRestTemplateBuilder builder = new RestTemplateBuilder();\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.obtain(this.applicationContext);\n\t\tbuilder = builder.uriTemplateHandler(localTestWebServer.uriBuilderFactory());\n\t\tthis.testRestTemplate = new TestRestTemplate(builder);\n\t}\n\n\t@Test\n\tvoid endpointShouldReturnUnauthorized() {\n\t\tResponseEntity<?> entity = this.testRestTemplate.getForEntity(\"/actuator/env\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid preflightRequestToEndpointShouldReturnOk() throws Exception {\n\t\tRequestEntity<?> envRequest = RequestEntity.options(new URI(\"/actuator/env\"))\n\t\t\t.header(\"Origin\", \"http://localhost:8080\")\n\t\t\t.header(\"Access-Control-Request-Method\", \"GET\")\n\t\t\t.build();\n\t\tResponseEntity<?> exchange = this.testRestTemplate.exchange(envRequest, Map.class);\n\t\tassertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid preflightRequestWhenCorsConfigInvalidShouldReturnForbidden() throws Exception {\n\t\tRequestEntity<?> entity = RequestEntity.options(new URI(\"/actuator/env\"))\n\t\t\t.header(\"Origin\", \"http://localhost:9095\")\n\t\t\t.header(\"Access-Control-Request-Method\", \"GET\")\n\t\t\t.build();\n\t\tResponseEntity<byte[]> exchange = this.testRestTemplate.exchange(entity, byte[].class);\n\t\tassertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/CustomServletPathSampleActuatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ApplicationContext;\n\n/**\n * Integration tests for actuator endpoints with custom dispatcher servlet path.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.mvc.servlet.path=/example\")\nclass CustomServletPathSampleActuatorTests extends AbstractSampleActuatorCustomSecurityTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/example\";\n\t}\n\n\t@Override\n\tString getActuatorPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/example/actuator\";\n\t}\n\n\t@Override\n\tApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/ManagementServerWithCustomBasePathAndWebEndpointsBasePathSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for a separate management server with custom base path and web\n * endpoints base path.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"management.server.port=0\",\n\t\t\"management.server.base-path=/management\", \"management.endpoints.web.base-path=/\" })\nclass ManagementServerWithCustomBasePathAndWebEndpointsBasePathSampleActuatorApplicationTests\n\t\textends AbstractSampleActuatorCustomSecurityTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testMissing() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"admin\", \"admin\")\n\t\t\t.getForEntity(getActuatorPath() + \"/missing\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":404\");\n\t}\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port;\n\t}\n\n\t@Override\n\tString getActuatorPath() {\n\t\treturn \"http://localhost:\" + this.managementPort + \"/management\";\n\t}\n\n\t@Override\n\tApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/ManagementServerWithCustomBasePathSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for a separate management server with a custom base path.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"management.server.base-path=/management\" })\nclass ManagementServerWithCustomBasePathSampleActuatorApplicationTests\n\t\textends AbstractSampleActuatorCustomSecurityTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid testMissing() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"admin\", \"admin\")\n\t\t\t.getForEntity(getActuatorPath() + \"/missing\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":404\");\n\t}\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port;\n\t}\n\n\t@Override\n\tString getActuatorPath() {\n\t\treturn \"http://localhost:\" + this.managementPort + \"/management/actuator\";\n\t}\n\n\t@Override\n\tApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/ManagementServerWithCustomServletPathSampleActuatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for a separate management server with a custom dispatcher servlet\n * path.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"spring.mvc.servlet.path=/example\" })\nclass ManagementServerWithCustomServletPathSampleActuatorTests extends AbstractSampleActuatorCustomSecurityTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid actuatorPathOnMainPortShouldNotMatch() {\n\t\tResponseEntity<String> entity = new TestRestTemplate()\n\t\t\t.getForEntity(\"http://localhost:\" + this.port + \"/example/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/example\";\n\t}\n\n\t@Override\n\tString getActuatorPath() {\n\t\treturn \"http://localhost:\" + this.managementPort + \"/actuator\";\n\t}\n\n\t@Override\n\tApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/SampleActuatorCustomSecurityApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.customsecurity;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for actuator endpoints with custom security configuration.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n * @author Scott Frederick\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.web.error.include-message=always\" })\nclass SampleActuatorCustomSecurityApplicationTests extends AbstractSampleActuatorCustomSecurityTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tvoid testInsecureApplicationPath() {\n\t\tResponseEntity<Map> entity = restTemplate().getForEntity(getPath() + \"/foo\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tMap<String, Object> body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tassertThat((String) body.get(\"message\")).contains(\"Expected exception in controller\");\n\t}\n\n\t@Test\n\tvoid mvcMatchersCanBeUsedToSecureActuators() {\n\t\tResponseEntity<Object> entity = beansRestTemplate().getForEntity(getActuatorPath() + \"/beans\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tentity = beansRestTemplate().getForEntity(getActuatorPath() + \"/beans/\", Object.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port;\n\t}\n\n\t@Override\n\tString getActuatorPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/actuator\";\n\t}\n\n\t@Override\n\tApplicationContext getApplicationContext() {\n\t\treturn this.applicationContext;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/resources/application-cors.properties",
    "content": "management.endpoints.web.cors.allowed-origins=http://localhost:8080\nmanagement.endpoints.web.cors.allowed-methods=GET\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator Extension smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-actuator-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;\nimport org.springframework.boot.actuate.endpoint.EndpointFilter;\nimport org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;\nimport org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;\nimport org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.Environment;\nimport org.springframework.web.cors.CorsConfiguration;\n\n@Configuration(proxyBeanMethods = false)\npublic class MyExtensionConfiguration {\n\n\t@Bean\n\tpublic MyExtensionWebMvcEndpointHandlerMapping myWebMvcEndpointHandlerMapping(\n\t\t\tWebEndpointsSupplier webEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,\n\t\t\tObjectProvider<CorsEndpointProperties> corsPropertiesProvider, WebEndpointProperties webEndpointProperties,\n\t\t\tEnvironment environment, ApplicationContext applicationContext, ParameterValueMapper parameterMapper) {\n\t\tCorsEndpointProperties corsProperties = corsPropertiesProvider.getIfAvailable();\n\t\tCorsConfiguration corsConfiguration = (corsProperties != null) ? corsProperties.toCorsConfiguration() : null;\n\t\tList<OperationInvokerAdvisor> invokerAdvisors = Collections.emptyList();\n\t\tList<EndpointFilter<ExposableWebEndpoint>> filters = Collections\n\t\t\t.singletonList(new MyExtensionEndpointFilter(environment));\n\t\tWebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(applicationContext, parameterMapper,\n\t\t\t\tendpointMediaTypes, null, null, invokerAdvisors, filters, Collections.emptyList());\n\t\tCollection<ExposableWebEndpoint> endpoints = discoverer.getEndpoints();\n\t\treturn new MyExtensionWebMvcEndpointHandlerMapping(endpoints, endpointMediaTypes, corsConfiguration);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionEndpointExposureOutcomeContributor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport java.util.Set;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor;\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;\nimport org.springframework.boot.actuate.endpoint.EndpointId;\nimport org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;\nimport org.springframework.boot.autoconfigure.condition.ConditionOutcome;\nimport org.springframework.core.env.Environment;\n\nclass MyExtensionEndpointExposureOutcomeContributor implements EndpointExposureOutcomeContributor {\n\n\tprivate final MyExtensionEndpointFilter filter;\n\n\tMyExtensionEndpointExposureOutcomeContributor(Environment environment) {\n\t\tthis.filter = new MyExtensionEndpointFilter(environment);\n\t}\n\n\t@Override\n\tpublic @Nullable ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,\n\t\t\tBuilder message) {\n\t\tif (exposures.contains(EndpointExposure.WEB) && this.filter.match(endpointId)) {\n\t\t\treturn ConditionOutcome.match(message.because(\"marked as exposed by a my extension '\"\n\t\t\t\t\t+ MyExtensionEndpointFilter.PROPERTY_PREFIX + \"' property\"));\n\t\t}\n\t\treturn null;\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionEndpointFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.core.env.Environment;\n\nclass MyExtensionEndpointFilter extends IncludeExcludeEndpointFilter<ExposableWebEndpoint> {\n\n\tstatic final String PROPERTY_PREFIX = \"management.endpoints.myextension.exposure\";\n\n\tMyExtensionEndpointFilter(Environment environment) {\n\t\tsuper(ExposableWebEndpoint.class, environment, PROPERTY_PREFIX, \"*\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionSecurityInterceptor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.servlet.HandlerInterceptor;\n\nclass MyExtensionSecurityInterceptor implements HandlerInterceptor {\n\n\t@Override\n\tpublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)\n\t\t\tthrows Exception {\n\t\tString auth = request.getHeader(\"Authorization\");\n\t\tif (!\"Bearer secret\".equals(auth)) {\n\t\t\tresponse.sendError(HttpStatus.UNAUTHORIZED.value());\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionWebMvcEndpointHandlerMapping.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMapping;\nimport org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;\nimport org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;\nimport org.springframework.boot.actuate.endpoint.web.Link;\nimport org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.cors.CorsConfiguration;\n\nclass MyExtensionWebMvcEndpointHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {\n\n\tprivate static final String PATH = \"/myextension\";\n\n\tprivate final EndpointLinksResolver linksResolver;\n\n\tMyExtensionWebMvcEndpointHandlerMapping(Collection<ExposableWebEndpoint> endpoints,\n\t\t\tEndpointMediaTypes endpointMediaTypes, @Nullable CorsConfiguration corsConfiguration) {\n\t\tsuper(new EndpointMapping(PATH), endpoints, endpointMediaTypes, corsConfiguration, true);\n\t\tthis.linksResolver = new EndpointLinksResolver(endpoints, PATH);\n\t\tsetOrder(-100);\n\t}\n\n\t@Override\n\tprotected LinksHandler getLinksHandler() {\n\t\treturn new WebMvcLinksHandler();\n\t}\n\n\t@Override\n\tprotected void extendInterceptors(List<Object> interceptors) {\n\t\tsuper.extendInterceptors(interceptors);\n\t\tinterceptors.add(0, new MyExtensionSecurityInterceptor());\n\t}\n\n\tclass WebMvcLinksHandler implements LinksHandler {\n\n\t\t@Override\n\t\t@ResponseBody\n\t\tpublic Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {\n\t\t\treturn Collections.singletonMap(\"_links\", MyExtensionWebMvcEndpointHandlerMapping.this.linksResolver\n\t\t\t\t.resolveLinks(request.getRequestURL().toString()));\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn \"Actuator extension root web endpoint\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/SampleActuatorExtensionApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication(proxyBeanMethods = false)\npublic class SampleActuatorExtensionApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActuatorExtensionApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.actuator.extension;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor=\\\nsmoketest.actuator.extension.MyExtensionEndpointExposureOutcomeContributor\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/main/resources/application.properties",
    "content": "spring.jmx.enabled=false\nmanagement.endpoints.web.exposure.exclude=*\nmanagement.endpoints.myextension.exposure.include=health,beans,configprops\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-extension/src/test/java/smoketest/actuator/extension/SampleActuatorExtensionApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.extension;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.http.server.LocalTestWebServer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"spring.web.error.include-message=always\" })\n@AutoConfigureTestRestTemplate\nclass SampleActuatorExtensionApplicationTests {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate RestTemplateBuilder restTemplateBuilder;\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid healthActuatorIsNotExposed() {\n\t\tResponseEntity<Map> entity = this.restTemplate.getForEntity(\"/actuator/health\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid healthExtensionWithAuthHeaderIsDenied() {\n\t\tResponseEntity<Map> entity = this.restTemplate.getForEntity(\"/myextension/health\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"rawtypes\")\n\tvoid healthExtensionWithAuthHeader() {\n\t\tTestRestTemplate restTemplate = new TestRestTemplate(\n\t\t\t\tthis.restTemplateBuilder.defaultHeader(\"Authorization\", \"Bearer secret\"));\n\t\tLocalTestWebServer localTestWebServer = LocalTestWebServer.obtain(this.applicationContext);\n\t\trestTemplate.setUriTemplateHandler(localTestWebServer.uriBuilderFactory());\n\t\tResponseEntity<Map> entity = restTemplate.getForEntity(\"/myextension/health\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-log4j2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator Log4j 2 smoke test\"\n\nconfigurations.all {\n\texclude module: \"spring-boot-starter-logging\"\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-log4j2\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-actuator-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-log4j2/src/main/java/smoketest/actuator/log4j2/SampleActuatorLog4J2Application.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.log4j2;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleActuatorLog4J2Application {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActuatorLog4J2Application.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-log4j2/src/main/java/smoketest/actuator/log4j2/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.actuator.log4j2;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-log4j2/src/main/resources/application.properties",
    "content": "spring.application.name=sample (test)\nspring.application.group=sample-group\n#logging.include-application-name=false\n#logging.include-application-group=false\nspring.security.user.name=user\nspring.security.user.password=password\nmanagement.endpoint.shutdown.enabled=true\nmanagement.endpoints.web.exposure.include=*\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-log4j2/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"WARN\" monitorInterval=\"30\">\n    <Properties>\n        <Property name=\"PID\">????</Property>\n        <Property name=\"LOG_PATTERN\">%clr{%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{${sys:APPLICATION_NAME:-}${sys:APPLICATION_GROUP:-}[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx</Property>\n    </Properties>\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n            <PatternLayout pattern=\"${LOG_PATTERN}\"/>\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Logger name=\"org.hibernate.validator.internal.util.Version\" level=\"warn\"/>\n        <Logger name=\"org.apache.coyote.http11.Http11NioProtocol\" level=\"warn\"/>\n        <Logger name=\"org.apache.tomcat.util.net.NioSelectorPool\" level=\"warn\"/>\n\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-log4j2/src/test/java/smoketest/actuator/log4j2/SampleActuatorLog4J2ApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.log4j2;\n\nimport java.util.Base64;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleActuatorLog4J2Application}.\n *\n * @author Dave Syer\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@AutoConfigureMockMvc\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleActuatorLog4J2ApplicationTests {\n\n\tprivate static final Logger logger = LogManager.getLogger(SampleActuatorLog4J2ApplicationTests.class);\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testLogger(CapturedOutput output) {\n\t\tlogger.info(\"Hello World\");\n\t\tassertThat(output).contains(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid validateLoggersEndpoint() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/actuator/loggers/org.apache.coyote.http11.Http11NioProtocol\")\n\t\t\t.header(\"Authorization\", getBasicAuth())).hasStatusOk()\n\t\t\t.hasBodyTextEqualTo(\"{\\\"configuredLevel\\\":\\\"WARN\\\",\\\"effectiveLevel\\\":\\\"WARN\\\"}\");\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator non-web smoke test\"\n\ndependencies {\n\tannotationProcessor(project(\":configuration-metadata:spring-boot-configuration-processor\"))\n\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-actuator-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/main/java/smoketest/actuator/noweb/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.noweb;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\tprivate final ServiceProperties configuration;\n\n\tpublic HelloWorldService(ServiceProperties configuration) {\n\t\tthis.configuration = configuration;\n\t}\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.configuration.getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/main/java/smoketest/actuator/noweb/SampleActuatorNoWebApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.noweb;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\n\n@SpringBootApplication\n@ConfigurationPropertiesScan\npublic class SampleActuatorNoWebApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActuatorNoWebApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/main/java/smoketest/actuator/noweb/ServiceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.noweb;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(prefix = \"service\", ignoreUnknownFields = false)\npublic class ServiceProperties {\n\n\t/**\n\t * Name of the service.\n\t */\n\tprivate String name = \"World\";\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/main/java/smoketest/actuator/noweb/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.actuator.noweb;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/main/resources/application.properties",
    "content": "service.name=Phil\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/main/resources/banner.txt",
    "content": "   ,--.   ,--.\n   \\  /-~-\\  /\n    )' a a `(\n   (  ,---.  )\n    `(_o_o_)'\n      )`-'(\n\nSpring Boot${spring-boot.formatted-version}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-noweb/src/test/java/smoketest/actuator/noweb/SampleActuatorNoWebApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.noweb;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\n\n/**\n * Basic integration tests for service demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest\nclass SampleActuatorNoWebApplicationTests {\n\n\t@Test\n\tvoid contextLoads() {\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Actuator UI smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-freemarker\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-actuator-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/main/java/smoketest/actuator/ui/SampleActuatorUiApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.ui;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@SpringBootApplication\n@Controller\npublic class SampleActuatorUiApplication {\n\n\t@GetMapping(\"/\")\n\tpublic String home(Map<String, Object> model) {\n\t\tmodel.put(\"message\", \"Hello World\");\n\t\tmodel.put(\"title\", \"Hello Home\");\n\t\tmodel.put(\"date\", new Date());\n\t\treturn \"home\";\n\t}\n\n\t@RequestMapping(\"/foo\")\n\tpublic String foo() {\n\t\tthrow new RuntimeException(\"Expected exception in controller\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleActuatorUiApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/main/java/smoketest/actuator/ui/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.actuator.ui;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/main/resources/application.properties",
    "content": "spring.security.user.name=user\nspring.security.user.password=password\nmanagement.health.diskspace.enabled=false\nmanagement.endpoints.web.exposure.include=*\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/main/resources/templates/error.ftlh",
    "content": "<#import \"/spring.ftl\" as spring />\n<!DOCTYPE html>\n<html>\n<head>\n<title>Error</title>\n<#assign home><@spring.url relativeUrl=\"/\"/></#assign>\n<#assign bootstrap><@spring.url relativeUrl=\"/css/bootstrap.min.css\"/></#assign>\n<link rel=\"stylesheet\" href=\"${bootstrap}\" />\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"navbar\">\n\t\t\t<div class=\"navbar-inner\">\n\t\t\t\t<a class=\"brand\" href=\"https://freemarker.apache.org/\"> FreeMarker -\n\t\t\t\t\tPlain </a>\n\t\t\t\t<ul class=\"nav\">\n\t\t\t\t\t<li><a href=\"${home}\"> Home </a></li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t\t<h1>Error Page</h1>\n\t\t<div id=\"created\">${timestamp?datetime}</div>\n\t\t<div>\n\t\t\tThere was an unexpected error (type=${error}, status=${status}).\n\t\t</div>\n\t\t<div>${message}</div>\n\t\t<div>\n\t\t\tPlease contact the operator with the above information.\n\t\t</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/main/resources/templates/home.ftlh",
    "content": "<#import \"/spring.ftl\" as spring />\n<!DOCTYPE html>\n<html>\n<head>\n<title>${title}</title>\n<#assign home><@spring.url relativeUrl=\"/\"/></#assign>\n<#assign bootstrap><@spring.url relativeUrl=\"/css/bootstrap.min.css\"/></#assign>\n<link rel=\"stylesheet\" href=\"${bootstrap}\" />\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"navbar\">\n\t\t\t<div class=\"navbar-inner\">\n\t\t\t\t<a class=\"brand\" href=\"https://freemarker.apache.org/\"> FreeMarker -\n\t\t\t\t\tPlain </a>\n\t\t\t\t<ul class=\"nav\">\n\t\t\t\t\t<li><a href=\"${home}\"> Home </a></li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</div>\n\t\t<h1>${title}</h1>\n\t\t<div>${message}</div>\n\t\t<div id=\"created\">${date?datetime}</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.ui;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"management.server.port:0\" })\n@AutoConfigureTestRestTemplate\nclass SampleActuatorUiApplicationPortTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.testRestTemplate.getForEntity(\"http://localhost:\" + this.port,\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid testMetrics() {\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tResponseEntity<Map> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/metrics\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testHealth() {\n\t\tResponseEntity<String> entity = this.testRestTemplate.withBasicAuth(\"user\", getPassword())\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\tprivate String getPassword() {\n\t\treturn \"password\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-actuator-ui/src/test/java/smoketest/actuator/ui/SampleActuatorUiApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.actuator.ui;\n\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"spring.web.error.include-message=always\" })\n@AutoConfigureTestRestTemplate\nclass SampleActuatorUiApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", getPassword())\n\t\t\t.exchange(\"/\", HttpMethod.GET, new HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Hello\");\n\t}\n\n\t@Test\n\tvoid testCss() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/css/bootstrap.min.css\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"body\");\n\t}\n\n\t@Test\n\tvoid testMetrics() {\n\t\t@SuppressWarnings(\"rawtypes\")\n\t\tResponseEntity<Map> entity = this.restTemplate.getForEntity(\"/actuator/metrics\", Map.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testError() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", getPassword())\n\t\t\t.exchange(\"/error\", HttpMethod.GET, new HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(entity.getBody()).contains(\"<html>\")\n\t\t\t.contains(\"<body>\")\n\t\t\t.contains(\"Please contact the operator with the above information\");\n\t}\n\n\tprivate String getPassword() {\n\t\treturn \"password\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot AMQP smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-amqp\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-amqp-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-rabbitmq\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/dockerTest/java/smoketest/amqp/SampleAmqpSimpleApplicationSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.amqp;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for RabbitMQ with SSL using an SSL bundle for SSL configuration.\n *\n * @author Scott Frederick\n */\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleAmqpSimpleApplicationSslTests {\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(\"classpath:ssl/test-ca.crt\")\n\tstatic final SecureRabbitMqContainer rabbit = TestImage.container(SecureRabbitMqContainer.class);\n\n\t@Autowired\n\tprivate Sender sender;\n\n\t@Test\n\tvoid sendSimpleMessage(CapturedOutput output) {\n\t\tthis.sender.send(\"Test message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1)).untilAsserted(() -> assertThat(output).contains(\"Test message\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/dockerTest/java/smoketest/amqp/SampleAmqpSimpleApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.amqp;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleAmqpSimpleApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final RabbitMQContainer rabbit = TestImage.container(RabbitMQContainer.class);\n\n\t@Autowired\n\tprivate Sender sender;\n\n\t@Test\n\tvoid sendSimpleMessage(CapturedOutput output) {\n\t\tthis.sender.send(\"Test message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1)).untilAsserted(() -> assertThat(output).contains(\"Test message\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/dockerTest/java/smoketest/amqp/SecureRabbitMqContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.amqp;\n\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link RabbitMQContainer} for RabbitMQ with SSL configuration.\n *\n * @author Scott Frederick\n */\nclass SecureRabbitMqContainer extends RabbitMQContainer {\n\n\tSecureRabbitMqContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t}\n\n\t@Override\n\tpublic void configure() {\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/rabbitmq.conf\"),\n\t\t\t\t\"/etc/rabbitmq/rabbitmq.conf\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.crt\"),\n\t\t\t\t\"/etc/rabbitmq/server_cert.pem\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.key\"),\n\t\t\t\t\"/etc/rabbitmq/server_key.pem\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-ca.crt\"), \"/etc/rabbitmq/ca_cert.pem\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/main/java/smoketest/amqp/SampleAmqpSimpleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.amqp;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.amqp.core.Queue;\nimport org.springframework.amqp.rabbit.annotation.RabbitHandler;\nimport org.springframework.amqp.rabbit.annotation.RabbitListener;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.messaging.handler.annotation.Payload;\n\n@SpringBootApplication\n@RabbitListener(queues = \"foo\")\npublic class SampleAmqpSimpleApplication {\n\n\tprivate static final Log logger = LogFactory.getLog(SampleAmqpSimpleApplication.class);\n\n\t@Bean\n\tpublic Sender mySender() {\n\t\treturn new Sender();\n\t}\n\n\t@Bean\n\tpublic Queue fooQueue() {\n\t\treturn new Queue(\"foo\");\n\t}\n\n\t@RabbitHandler\n\tpublic void process(@Payload String foo) {\n\t\tlogger.info(foo);\n\t}\n\n\t@Bean\n\tpublic ApplicationRunner runner(Sender sender) {\n\t\treturn (args) -> sender.send(\"Hello\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleAmqpSimpleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/main/java/smoketest/amqp/Sender.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.amqp;\n\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.beans.factory.annotation.Autowired;\n\npublic class Sender {\n\n\t@Autowired\n\tprivate RabbitTemplate rabbitTemplate;\n\n\tpublic void send(String message) {\n\t\tthis.rabbitTemplate.convertAndSend(\"foo\", message);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/main/java/smoketest/amqp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.amqp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/rabbitmq.conf",
    "content": "listeners.tcp                    = none\nlisteners.ssl.default            = 5671\nssl_options.certfile             = /etc/rabbitmq/server_cert.pem\nssl_options.keyfile              = /etc/rabbitmq/server_key.pem\nssl_options.cacertfile           = /etc/rabbitmq/ca_cert.pem\nssl_options.verify               = verify_peer\nssl_options.fail_if_no_peer_cert = true"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/test-ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6w3YrNBBRTFlK\nIjdlm5miEXCrYpdJQ090nquAPf9go1MNJlcpk87neRg8/QNd/SybcIdzJZJZVpvK\nKZli49Z6drUwSVIvhmkn1bCRmg5Dds8UrW63PqQw7CuABRyTLwf+sgqPYkQGGRId\nQgavns2NQTAbXKBpJ6szxHNbDU+0yr4Lws67e/3irMTc0ODVBGnK9X06awuyMhJ3\nRmYAk2L2+aIQf3bcqc/KKqdCZYqliJx2BCZfUZfKVLbaNmoDBo6RgaNfxR17K+ui\nGRmQzSGf25pK59AYRbjIoAKfc+SMm3OLx2sEjKMiL1hwDMHFkH2hUqpdkyWW2A7Z\n8MyYgmLQ2C3QKLt8KgQypKhwrIMowvpguv1Ra3Hht+yuT6tU71D8P+/xEqCy2/t0\nJ/YpZFfdkkQLQgEdLmAs2rSqqpVwbHctxLKF2Iok61LACc2QcyH6NJDEtKUGNxKp\nM+IZNEr9F12X7GdT+YGCTtkEY2tQVoPkxwwWN11LsiHzZoeelDWB6RadQa/5Ob8b\nryHYG9nlTar5F944KBFb2L8BhbaOBPsgWd+PJReAFC95q4wByGiaoURUt73lmBWI\nXq+YffgQqjfD0vlNCLCT+vndiUztNI5PIOrHrq3jMZgOxUyJykqbOLjZGnwSkSsB\nFHJERQgpK9az07365Pf7tqs0uAd7kQIDAQABAoICAAthB10ggfICHdqXdRqavWST\nfXLjweXz1O59EGPy4xFnQhMmB99/ovaVeTWWENN0LniWBZqtalpJHZrWqALPcOzr\nOKTlgr1kihmkOmrUoRPZNErFOl6t0WEtsoTNSu1oyyrofB46VXytoF3p/PBMU6fM\nlfrEzP07LoIr8P9WM0oHpEahKulfZ5uc/S2bCGfSKgP0qxmZFhBYXqmnv2U/laMI\nmKg6q+pL6l4d9SzldOobBbVnEVNzbDUmrjFjaVgf2SXiaSrXnrE3ftbUgqtA5FCS\nF7eCojooXVbT8PT4Ia+zdPnKP6n6S6I0kkXZcSDxacYffEPRSFQFe/opYr3UC+Mk\n1/UmOnoI8X8+N9SPcVD9cbVQUzBuuXfTy+LMx9mg3QxFebRSRre22xSOSlM7MF9B\n6MPeNgwCk3Z0NTr+IedGfyA+d6+iHTMGnv0hF4b4UkcXbC3HdeR3K4hf+msGD2oG\n7JF423T/d7t+g883y4CZm7p096apR8cCLIe2HKSwcYbKhft7LkAdm8kpnqkr5ER1\nanI7RDmucrx3HgrXeuCz9Uai6EMU6jNU1MAEBVeu4jz1rlO4e9zS2Ak68AwIz0zI\ntl5el3paHjlRYY6YTslM5qjGerJt19IyHvZxXXIzF7JdF7w1nSK9bjvninALJl49\nYZAPRIbyQ8P6DLqiDNBFAoIBAQDvQoow86vNg6zHdb8eBC10l2Y6M5DAKTWPE8RJ\nn0td1TLwEHzKvkR25v6yGKABbBO1+7ABACCqA8rkcB7M5jugak/kR9vuDrFPAsqf\nlgckf1Up7ekDheTH8X1VSDiRZPv07UElO0M3aFeMVR/xi9Wae8C3WZo9dT2wKnM0\nd0Acr4Kt4SYm1Dw7kuh+Y1L/vvWuryPm1btxhfKO6JN5v2W8DTrqVkxuxYEM1VnR\n69LfauLVico2q8EGXmQTth/Iok5wj1qI6kmrlgQR+eSY1qgNk1qzwjJVsbSmAOL8\n6Y9Ksct53bEN6DIdYRE/SrEVCz/FY1Pry2DNTjdiwImaSOZ3AoIBAQDH1KRkqsET\nYUnPJxp9pHWlynicEVE/Y7FFhhtpUKzhY1nZ+NsNy91FrZiyx5Os7pSxhLNID8g5\nxKCOfYd7qdvZCg/5bMXhtagQ3gwa/wyuyamc29dKkCpHDz/GkoEkgVe6eYu1GNdR\niNpY5ye5T9fBE1s3odbDcnRVeHAP7vqz5z17JKrlqZVhbLYlR4qGHmAogq7vWlyd\nIR5qLoXMgyqq5OHl1GaaiqfViBpJeoEWYze0cARUWOcrJRblJYS03WHMuLDG5RZd\n5nmf2xwEcMgW5AX7+GB8CdXRVZy6OZcGn7TU9+xnBJA2LbzxJlHBXjWEd8Uma2Al\n+ohlDbGrd8g3AoIBAHsWzGlqstREDbt/xBb5Jzl4OktvA+UYTkmRbcZCgU+Aw3fl\nw426XRaeuCF/sbGJnIpfNakOG7/bu6HSXMYlHD/m8bsLjQXn4Sg4021OjdYk+/da\nQiph09VZU5VwVknWnhjfhkhVOLtknsW/dXOa8QVM7VRmcId1rYrYC/TN9NnNIXm6\n/xmyzloHtjxvdN/Fqjd4OwwioRBCTQtgc56K7RfV5p1wUFocmcu0Z0UsAYyXPKOH\nA9Ukf2V7YhkR9UAO4DPgTD9r6QKxZt6opQZMSKDTUjJwkdysU7ejdSOQNPvEhF3p\nw5DYCBA9Q9Y/4uJkqyYtd5szQlXdC3lufFw3bPkCggEBAKPA3GpmB0xjWEG6UJoP\nUB1pWwbBpivk/Rr097eI1fLpIHNf29plalE0HcK7i4eWByGllekCjdjRCaVattCe\n9DraZRbHjS0WWMBhxdfFk9YUCbsx6C4BD7QlieSmn8+TcpmsCtF/psr4870Qx9uy\n0yI0Q3bGV6DYRP7ZcDOOacFNSHOGK8mB+5jXpjfMdXbMo43u8X3RNb3JqwvmTdy2\nzBs47ukQ8nfIEhsIqkn2apw2+CoT9WhNZjpT7XwgD6zLEd7apnqGtpqCSL63pjD5\nXu5rM4A1HJPo11/w4Ts2AE38SAqRlBcjhS3wszmGZk6obgC8yUFfkm3s7SKqYyMZ\nSGcCggEBAO0IDB/h1meZ2y+6bSsCVaDSxdRl0JF0CDUYVTANQsJ+q7u7CpF9xOo8\nYNrSy8eM0K6RMY/3WbTm+4z9tOldxEV2dn+29oVeMKkgpJYo0k2Au3wTMI2xMyyl\nHZ+ZttsqSZsj2CPx83LMaPwKdzVjwA7alVx4P+AkQKn7jGJgidj5xyw0G3gnzdfT\nnGzuitQFlcrcPyrVHAAmRhIw+B5CsvMFlM8PAvojN7burGswjWGeZjkgqoLvKlgq\njRMGzLTzF9Pay7P/D/pWQwPVGiseJq+QVIA+iILpy9Zb9T6DnBFaPFGOKAduzVU9\nlTLiho2DATppaxNUQKh/5k70hzbipDg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/test-client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/test-client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/test-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-amqp/src/test/resources/ssl/test-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-base\"\n}\n\ndescription = \"Spring Boot Ant smoke test\"\n\nconfigurations {\n\tantDependencies {\n\t\textendsFrom dependencyManagement\n\t}\n\ttestRepository\n}\n\nsourceSets {\n\ttest\n}\n\nplugins.withType(EclipsePlugin) {\n\teclipse {\n\t\tclasspath {\n\t\t\tplusConfigurations = [configurations.testRuntimeClasspath]\n\t\t}\n\t}\n}\n\ndependencies {\n\tantDependencies \"org.apache.ivy:ivy:2.5.0\"\n\tantDependencies project(path: \":build-plugin:spring-boot-antlib\")\n\tantDependencies \"org.apache.ant:ant-launcher:1.10.7\"\n\tantDependencies \"org.apache.ant:ant:1.10.7\"\n\n\ttestRepository(project(path: \":loader:spring-boot-loader\", configuration: \"mavenRepository\"))\n\ttestRepository(project(path: \":starter:spring-boot-starter\", configuration: \"mavenRepository\"))\n\n\ttestImplementation(project(path: \":loader:spring-boot-loader-tools\"))\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.springframework:spring-core\")\n\n\ttestRuntimeOnly(\"org.junit.platform:junit-platform-launcher\")\n}\n\ntasks.register(\"syncTestRepository\", Sync) {\n\tdestinationDir = file(layout.buildDirectory.dir(\"test-repository\"))\n\tfrom configurations.testRepository\n\trename {\n\t\tit.replaceAll(\"-[0-9]+\\\\.[0-9]+-[0-9]+\\\\.\", \"-SNAPSHOT.\")\n\t}\n}\n\ntasks.register(\"syncAntSources\", Sync) {\n\tdestinationDir = file(layout.buildDirectory.dir(\"ant\"))\n\tfrom project.layout.projectDirectory\n\tinclude \"*.xml\"\n\tfilter(springRepositoryTransformers.ant())\n}\n\ntasks.register(\"antRun\", JavaExec) {\n\tworkingDir = layout.buildDirectory.dir(\"ant\")\n\tdependsOn syncTestRepository, syncAntSources, configurations.antDependencies\n\tclasspath = configurations.antDependencies\n\tmainClass = \"org.apache.tools.ant.launch.Launcher\"\n\targs = [ \"clean\", \"build\" ]\n\tsystemProperties = [\n\t\t\"ant-spring-boot.version\" : version,\n\t\t\"projectDir\": project.layout.projectDirectory\n\t]\n}\n\ntasks.register(\"test\", Test) {\n\tdependsOn antRun\n\ttestClassesDirs = sourceSets.test.output.classesDirs\n\tclasspath = sourceSets.test.runtimeClasspath\n}\n\ncheck {\n\tdependsOn test\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/build.xml",
    "content": "<project\n\txmlns:ivy=\"antlib:org.apache.ivy.ant\"\n\txmlns:spring-boot=\"antlib:org.springframework.boot.ant\"\n\tname=\"spring-boot-smoke-test-ant\"\n\tdefault=\"build\">\n\n\t<description>\n\t\tSample ANT build script for a Spring Boot executable JAR project. Uses ivy for\n\t\tdependency management and spring-boot-antlib for additional tasks. Run with\n\t\t'$ ant -lib ivy-2.2.jar spring-boot-antlib.jar' (substitute the location of your\n\t\tactual jars). Run with '$ java -jar target/*.jar'.\n\t</description>\n\n\t<property name=\"lib.dir\" location=\"${basedir}/lib\" />\n\t<property name=\"start-class\" value=\"smoketest.ant.SampleAntApplication\" />\n\n\t<target name=\"clean-ivy-cache\">\n\t\t<ivy:cleancache />\n\t</target>\n\n\t<target name=\"resolve\" depends=\"clean-ivy-cache\" description=\"--> retrieve dependencies with ivy\">\n\t\t<ivy:retrieve pattern=\"${lib.dir}/[conf]/[artifact]-[type]-[revision].[ext]\" />\n\t</target>\n\n\t<target name=\"classpaths\" depends=\"resolve\">\n\t\t<path id=\"compile.classpath\">\n\t\t\t<fileset dir=\"${lib.dir}/compile\" includes=\"*.jar\" />\n\t\t</path>\n\t</target>\n\n\t<target name=\"init\" depends=\"classpaths\">\n\t\t<mkdir dir=\"${basedir}/classes\" />\n\t</target>\n\n\t<target name=\"compile\" depends=\"init\" description=\"compile\">\n\t\t<javac srcdir=\"${projectDir}/src/main/java\" destdir=\"${basedir}/classes\" classpathref=\"compile.classpath\" fork=\"true\" includeantruntime=\"false\" source=\"8\" target=\"8\" compiler=\"javac1.8\"/>\n\t</target>\n\n\t<target name=\"clean\" description=\"cleans all created files/dirs\">\n\t\t<delete dir=\"target\" />\n\t\t<delete dir=\"${lib.dir}\" />\n\t</target>\n\n\t<target name=\"build\" depends=\"compile\">\n\t\t<delete file=\"${basedir}/libs/${ant.project.name}.jar\"/>\n\t\t<spring-boot:exejar destfile=\"${basedir}/libs/${ant.project.name}.jar\" classes=\"${basedir}/classes\">\n\t\t\t<spring-boot:lib>\n\t\t\t\t<fileset dir=\"${lib.dir}/runtime\" />\n\t\t\t</spring-boot:lib>\n\t\t</spring-boot:exejar>\n\t</target>\n\n\t<!-- Manual equivalent of the build target -->\n\t<target name=\"manual\" depends=\"compile\">\n\t\t<jar destfile=\"target/${ant.project.name}-${ant-spring-boot.version}.jar\" compress=\"false\">\n\t\t\t<mappedresources>\n\t\t\t\t<fileset dir=\"${basedir}/classes\" />\n\t\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/classes/*\"/>\n\t\t\t</mappedresources>\n\t\t\t<mappedresources>\n\t\t\t\t<fileset dir=\"src/main/resources\" erroronmissingdir=\"false\"/>\n\t\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/classes/*\"/>\n\t\t\t</mappedresources>\n\t\t\t<mappedresources>\n\t\t\t\t<fileset dir=\"${lib.dir}/runtime\" />\n\t\t\t\t<globmapper from=\"*\" to=\"BOOT-INF/lib/*\"/>\n\t\t\t</mappedresources>\n\t\t\t<zipfileset src=\"${lib.dir}/loader/spring-boot-loader-jar-${ant-spring-boot.version}.jar\" />\n\t\t\t<manifest>\n\t\t\t\t<attribute name=\"Main-Class\" value=\"org.springframework.boot.loader.launch.JarLauncher\" />\n\t\t\t\t<attribute name=\"Start-Class\" value=\"${start-class}\" />\n\t\t\t</manifest>\n\t\t</jar>\n\t</target>\n</project>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/ivy.xml",
    "content": "<ivy-module version=\"2.0\">\n\t<info organisation=\"org.springframework.boot\" module=\"spring-boot-smoke-test-ant\" />\n\t<configurations>\n\t\t<conf name=\"compile\" description=\"everything needed to compile this module\" />\n\t\t<conf name=\"runtime\" extends=\"compile\" description=\"everything needed to run this module\" />\n\t\t<conf name=\"loader\" description=\"Spring Boot loader used when manually building an executable archive\" />\n\t</configurations>\n\t<dependencies>\n\t\t<dependency org=\"org.springframework.boot\" name=\"spring-boot-starter\" rev=\"${ant-spring-boot.version}\" conf=\"compile\" />\n\t\t<dependency org=\"org.springframework.boot\" name=\"spring-boot-loader\" rev=\"${ant-spring-boot.version}\" conf=\"loader->default\" />\n\t</dependencies>\n</ivy-module>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/ivysettings.xml",
    "content": "<ivysettings>\n\t<settings defaultResolver=\"chain\" />\n\t<caches defaultCacheDir=\"${projectDir}/build/ivy-cache\"/>\n\t<resolvers>\n\t\t<chain name=\"chain\" returnFirst=\"true\">\n\t\t\t<filesystem name=\"local\" local=\"true\" m2compatible=\"true\">\n\t\t\t\t<artifact pattern=\"${projectDir}/build/test-repository/[organisation]/[module]/[revision]/[module]-[revision].[ext]\" />\n\t\t\t\t<ivy pattern=\"${projectDir}/build/test-repository/[organisation]/[module]/[revision]/[module]-[revision].pom\" />\n\t\t\t</filesystem>\n\t\t\t<ibiblio name=\"ibiblio\" m2compatible=\"true\" />\n\t\t\t<!-- {spring.mavenRepositories} -->\n\t\t</chain>\n\t</resolvers>\n\t<!-- {spring.mavenCredentials} -->\n</ivysettings>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/src/main/java/smoketest/ant/SampleAntApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.ant;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleAntApplication implements CommandLineRunner {\n\n\t@Override\n\tpublic void run(String... args) {\n\t\tSystem.out.println(\"Spring Boot Ant Example\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleAntApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/src/test/java/smoketest/ant/SampleAntApplicationIT.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.ant;\n\nimport java.io.File;\nimport java.io.InputStreamReader;\nimport java.util.concurrent.TimeUnit;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.loader.tools.JavaExecutable;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration Tests for {@code SampleAntApplication}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\nclass SampleAntApplicationIT {\n\n\t@Test\n\tvoid runJar() throws Exception {\n\t\tFile libs = new File(\"build/ant/libs\");\n\t\tProcess process = new JavaExecutable().processBuilder(\"-jar\", \"spring-boot-smoke-test-ant.jar\")\n\t\t\t.directory(libs)\n\t\t\t.start();\n\t\tprocess.waitFor(5, TimeUnit.MINUTES);\n\t\tassertThat(process.exitValue()).isZero();\n\t\tString output = FileCopyUtils.copyToString(new InputStreamReader(process.getInputStream()));\n\t\tassertThat(output).contains(\"Spring Boot Ant Example\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-ant/src/test/resources/application.properties",
    "content": "name: Phil\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Artemis smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-artemis\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-artemis-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-activemq\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/src/dockerTest/java/smoketest/artemis/SampleArtemisTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.artemis;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.activemq.ArtemisContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for demo application.\n *\n * @author Eddú Meléndez\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleArtemisTests {\n\n\t@Container\n\t@ServiceConnection\n\tprivate static final ArtemisContainer container = TestImage.container(ArtemisContainer.class);\n\n\t@Autowired\n\tprivate Producer producer;\n\n\t@Test\n\tvoid sendSimpleMessage(CapturedOutput output) {\n\t\tthis.producer.send(\"Test message\");\n\t\tAwaitility.waitAtMost(Duration.ofMinutes(1)).untilAsserted(() -> assertThat(output).contains(\"Test message\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/src/main/java/smoketest/artemis/Consumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.artemis;\n\nimport org.springframework.jms.annotation.JmsListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Consumer {\n\n\t@JmsListener(destination = \"sample.queue\")\n\tpublic void receiveQueue(String text) {\n\t\tSystem.out.println(text);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/src/main/java/smoketest/artemis/Producer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.artemis;\n\nimport jakarta.jms.Queue;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.jms.core.JmsClient;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Producer implements CommandLineRunner {\n\n\t@Autowired\n\tprivate JmsClient jmsClient;\n\n\t@Autowired\n\tprivate Queue queue;\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tsend(\"Sample message\");\n\t\tSystem.out.println(\"Message was sent to the Queue\");\n\t}\n\n\tpublic void send(String msg) {\n\t\tthis.jmsClient.destination(this.queue).send(msg);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/src/main/java/smoketest/artemis/SampleArtemisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.artemis;\n\nimport jakarta.jms.Queue;\nimport org.apache.activemq.artemis.jms.client.ActiveMQQueue;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jms.annotation.EnableJms;\n\n@SpringBootApplication\n@EnableJms\npublic class SampleArtemisApplication {\n\n\t@Bean\n\tpublic Queue queue() {\n\t\treturn new ActiveMQQueue(\"sample.queue\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleArtemisApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/src/main/java/smoketest/artemis/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.artemis;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-artemis/src/main/resources/application.properties",
    "content": "spring.artemis.pool.enabled=false\nspring.jms.cache.enabled=false\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot AspectJ smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-aspectj\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-aspectj-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/java/smoketest/aspectj/SampleAspectJApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.aspectj;\n\nimport smoketest.aspectj.service.HelloWorldService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleAspectJApplication implements CommandLineRunner {\n\n\t// Simple example shows how an application can spy on itself with AOP\n\n\t@Autowired\n\tprivate HelloWorldService helloWorldService;\n\n\t@Override\n\tpublic void run(String... args) {\n\t\tSystem.out.println(this.helloWorldService.getHelloMessage());\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleAspectJApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/java/smoketest/aspectj/monitor/ServiceMonitor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.aspectj.monitor;\n\nimport org.aspectj.lang.JoinPoint;\nimport org.aspectj.lang.annotation.AfterReturning;\nimport org.aspectj.lang.annotation.Aspect;\n\nimport org.springframework.stereotype.Component;\n\n@Aspect\n@Component\npublic class ServiceMonitor {\n\n\t@AfterReturning(\"execution(* smoketest..*Service.*(..))\")\n\tpublic void logServiceAccess(JoinPoint joinPoint) {\n\t\tSystem.out.println(\"Completed: \" + joinPoint);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/java/smoketest/aspectj/monitor/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.aspectj.monitor;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/java/smoketest/aspectj/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.aspectj;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/java/smoketest/aspectj/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.aspectj.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/java/smoketest/aspectj/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.aspectj.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/main/resources/application.properties",
    "content": "test.name: Phil\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-aspectj/src/test/java/smoketest/aspectj/SampleAspectJApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.aspectj;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleAspectJApplication}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleAspectJApplicationTests {\n\n\tprivate String profiles;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.profiles = System.getProperty(\"spring.profiles.active\");\n\t}\n\n\t@AfterEach\n\tvoid after() {\n\t\tif (this.profiles != null) {\n\t\t\tSystem.setProperty(\"spring.profiles.active\", this.profiles);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(\"spring.profiles.active\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tSampleAspectJApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"Hello Phil\");\n\t}\n\n\t@Test\n\tvoid testCommandLineOverrides(CapturedOutput output) {\n\t\tSampleAspectJApplication.main(new String[] { \"--test.name=Gordon\" });\n\t\tassertThat(output).contains(\"Hello Gordon\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-autoconfigure-classic/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Auto-Configure Classic smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-classic\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-autoconfigure-classic/src/main/java/smoketest/autoconfigureclassic/SampleAutoConfigureClassicApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.autoconfigureclassic;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleAutoConfigureClassicApplication implements CommandLineRunner {\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tSystem.out.println(\"Auto-Configure Classic!\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleAutoConfigureClassicApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-autoconfigure-classic/src/main/java/smoketest/autoconfigureclassic/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.autoconfigureclassic;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-autoconfigure-classic/src/main/resources/application.properties",
    "content": "test.name=Phil\nsample.name=Andy\n\nspring.profiles.validate=false\nspring.profiles.active=a+very(silly)!name\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-autoconfigure-classic/src/main/resources/banner.txt",
    "content": "${Ansi.GREEN} :: Sample application build with Spring Boot${spring-boot.formatted-version} ::${Ansi.DEFAULT}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-autoconfigure-classic/src/test/java/smoketest/autoconfigureclassic/SampleAutoConfigureClassicApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.autoconfigureclassic;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleAutoConfigureClassicApplication}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleAutoConfigureClassicApplicationTests {\n\n\t@Test\n\tvoid testApplicationRuns(CapturedOutput output) {\n\t\tSampleAutoConfigureClassicApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"Auto-Configure Classic!\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Batch smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-batch\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-batch-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch/src/main/java/smoketest/batch/SampleBatchApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.batch;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleBatchApplication {\n\n\t@Bean\n\tTasklet tasklet() {\n\t\treturn (contribution, context) -> RepeatStatus.FINISHED;\n\t}\n\n\t@Bean\n\tJob job(JobRepository jobRepository, Step step) {\n\t\treturn new JobBuilder(\"job\", jobRepository).start(step).build();\n\t}\n\n\t@Bean\n\tStep step1(JobRepository jobRepository, Tasklet tasklet) {\n\t\treturn new StepBuilder(\"step1\", jobRepository).tasklet(tasklet).build();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\t// System.exit is common for Batch applications since the exit code can be used to\n\t\t// drive a workflow\n\t\tSystem.exit(SpringApplication.exit(SpringApplication.run(SampleBatchApplication.class, args)));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch/src/main/java/smoketest/batch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.batch;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch/src/test/java/smoketest/batch/SampleBatchApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.batch;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleBatchApplicationTests {\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tassertThat(SpringApplication.exit(SpringApplication.run(SampleBatchApplication.class))).isZero();\n\t\tassertThat(output).contains(\"completed with the following parameters\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-data-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Batch with Data MongoDB smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-batch-data-mongodb\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-batch-data-mongodb-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\ttestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\ttestImplementation(\"org.testcontainers:testcontainers-mongodb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-data-mongodb/src/main/java/smoketest/batch/SampleBatchApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.batch;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleBatchApplication {\n\n\t@Bean\n\tJob job(JobRepository jobRepository) {\n\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t.start(new StepBuilder(\"step1\", jobRepository)\n\t\t\t\t.tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED)\n\t\t\t\t.build())\n\t\t\t.build();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\t// System.exit is common for Batch applications since the exit code can be used to\n\t\t// drive a workflow\n\t\tSystem.exit(SpringApplication.exit(SpringApplication.run(SampleBatchApplication.class, args)));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-data-mongodb/src/main/java/smoketest/batch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.batch;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-data-mongodb/src/test/java/smoketest/batch/SampleBatchApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.batch;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Spring Batch with MongoDB.\n *\n * @author Stephane Nicoll\n */\n@ExtendWith(OutputCaptureExtension.class)\n@Testcontainers(disabledWithoutDocker = true)\nclass SampleBatchApplicationTests {\n\n\t@Container\n\tstatic final MongoDBContainer mongoDb = TestImage.container(MongoDBContainer.class).withReplicaSet();\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tint exitCode = SpringApplication.exit(SpringApplication.run(SampleBatchApplication.class,\n\t\t\t\t\"--spring.mongodb.uri=\" + mongoDb.getReplicaSetUrl(),\n\t\t\t\t\"--spring.batch.data.mongodb.schema.initialize=true\"));\n\t\tassertThat(exitCode).isZero();\n\t\tassertThat(output).contains(\"completed with the following parameters\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Batch with JDBC smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-batch-jdbc\"))\n\n\truntimeOnly(\"org.hsqldb:hsqldb\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-batch-jdbc-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-jdbc/src/main/java/smoketest/batch/SampleBatchApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.batch;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n@SpringBootApplication\npublic class SampleBatchApplication {\n\n\t@Bean\n\tTasklet tasklet() {\n\t\treturn (contribution, context) -> RepeatStatus.FINISHED;\n\t}\n\n\t@Bean\n\tJob job(JobRepository jobRepository, Step step) {\n\t\treturn new JobBuilder(\"job\", jobRepository).start(step).build();\n\t}\n\n\t@Bean\n\tStep step1(JobRepository jobRepository, Tasklet tasklet, PlatformTransactionManager transactionManager) {\n\t\treturn new StepBuilder(\"step1\", jobRepository).tasklet(tasklet, transactionManager).build();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\t// System.exit is common for Batch applications since the exit code can be used to\n\t\t// drive a workflow\n\t\tSystem.exit(SpringApplication.exit(SpringApplication.run(SampleBatchApplication.class, args)));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-jdbc/src/main/java/smoketest/batch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.batch;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-batch-jdbc/src/test/java/smoketest/batch/SampleBatchApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.batch;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleBatchApplicationTests {\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tassertThat(SpringApplication.exit(SpringApplication.run(SampleBatchApplication.class))).isZero();\n\t\tassertThat(output).contains(\"completed with the following parameters\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Bootstrap Registry smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/app/MySubversionClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.app;\n\nimport org.jspecify.annotations.Nullable;\nimport smoketest.bootstrapregistry.external.svn.SubversionClient;\nimport smoketest.bootstrapregistry.external.svn.SubversionServerCertificate;\n\npublic class MySubversionClient extends SubversionClient {\n\n\tpublic MySubversionClient(@Nullable SubversionServerCertificate serverCertificate) {\n\t\tsuper(serverCertificate);\n\t}\n\n\t@Override\n\tpublic String load(String location) {\n\t\treturn \"my-\" + super.load(location);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/app/Printer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.app;\n\nimport smoketest.bootstrapregistry.external.svn.SubversionClient;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Printer {\n\n\tPrinter(@Value(\"${svn}\") String svn, SubversionClient subversionClient) {\n\t\tSystem.out.println(\"--- svn \" + svn);\n\t\tSystem.out.println(\"--- client \" + subversionClient.getClass().getName());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/app/SampleBootstrapRegistryApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.app;\n\nimport smoketest.bootstrapregistry.external.svn.SubversionBootstrap;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleBootstrapRegistryApplication {\n\n\tpublic static void main(String[] args) {\n\t\t// This example shows how a Bootstrapper can be used to register a custom\n\t\t// SubversionClient that still has access to data provided in the\n\t\t// application.properties file\n\t\tSpringApplication application = new SpringApplication(SampleBootstrapRegistryApplication.class);\n\t\tapplication.addBootstrapRegistryInitializer(SubversionBootstrap.withCustomClient(MySubversionClient::new));\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/app/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.bootstrapregistry.app;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/SubversionBootstrap.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.external.svn;\n\nimport java.util.function.Function;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapRegistryInitializer;\n\n/**\n * Allows the user to register a {@link BootstrapRegistryInitializer} with a custom\n * {@link SubversionClient}.\n *\n * @author Phillip Webb\n */\npublic final class SubversionBootstrap {\n\n\tprivate SubversionBootstrap() {\n\t}\n\n\t/**\n\t * Return a {@link BootstrapRegistryInitializer} for the given client factory.\n\t * @param clientFactory the client factory\n\t * @return a {@link BootstrapRegistryInitializer} instance\n\t */\n\tpublic static BootstrapRegistryInitializer withCustomClient(\n\t\t\tFunction<@Nullable SubversionServerCertificate, SubversionClient> clientFactory) {\n\t\treturn (registry) -> registry.register(SubversionClient.class,\n\t\t\t\t(bootstrapContext) -> createSubversionClient(bootstrapContext, clientFactory));\n\t}\n\n\tprivate static SubversionClient createSubversionClient(BootstrapContext bootstrapContext,\n\t\t\tFunction<@Nullable SubversionServerCertificate, SubversionClient> clientFactory) {\n\t\treturn clientFactory.apply(bootstrapContext.get(SubversionServerCertificate.class));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/SubversionClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.external.svn;\n\nimport org.jspecify.annotations.Nullable;\n\n/**\n * A client that can connect to a subversion server.\n *\n * @author Phillip Webb\n */\npublic class SubversionClient {\n\n\tprivate final @Nullable SubversionServerCertificate serverCertificate;\n\n\tpublic SubversionClient(@Nullable SubversionServerCertificate serverCertificate) {\n\t\tthis.serverCertificate = serverCertificate;\n\t}\n\n\tpublic String load(String location) {\n\t\treturn \"data from svn / \" + location + \"[\" + this.serverCertificate + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/SubversionConfigDataLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.external.svn;\n\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport org.springframework.boot.bootstrap.BootstrapContext;\nimport org.springframework.boot.bootstrap.BootstrapContextClosedEvent;\nimport org.springframework.boot.bootstrap.BootstrapRegistry;\nimport org.springframework.boot.bootstrap.BootstrapRegistry.InstanceSupplier;\nimport org.springframework.boot.context.config.ConfigData;\nimport org.springframework.boot.context.config.ConfigDataLoader;\nimport org.springframework.boot.context.config.ConfigDataLoaderContext;\nimport org.springframework.boot.context.config.ConfigDataLocationNotFoundException;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.PropertySource;\nimport org.springframework.util.Assert;\n\n/**\n * {@link ConfigDataLoader} for subversion.\n *\n * @author Phillip Webb\n */\nclass SubversionConfigDataLoader implements ConfigDataLoader<SubversionConfigDataResource> {\n\n\tprivate static final ApplicationListener<BootstrapContextClosedEvent> closeListener = SubversionConfigDataLoader::onBootstrapContextClosed;\n\n\tSubversionConfigDataLoader(BootstrapRegistry bootstrapRegistry) {\n\t\tbootstrapRegistry.registerIfAbsent(SubversionClient.class, this::createSubversionClient);\n\t\tbootstrapRegistry.addCloseListener(closeListener);\n\t}\n\n\tprivate SubversionClient createSubversionClient(BootstrapContext bootstrapContext) {\n\t\treturn new SubversionClient(bootstrapContext.get(SubversionServerCertificate.class));\n\t}\n\n\t@Override\n\tpublic ConfigData load(ConfigDataLoaderContext context, SubversionConfigDataResource resource)\n\t\t\tthrows IOException, ConfigDataLocationNotFoundException {\n\t\tcontext.getBootstrapContext()\n\t\t\t.registerIfAbsent(SubversionServerCertificate.class, InstanceSupplier.of(resource.getServerCertificate()));\n\t\tSubversionClient client = context.getBootstrapContext().get(SubversionClient.class);\n\t\tAssert.state(client != null, \"'client' must not be null\");\n\t\tString loaded = client.load(resource.getLocation());\n\t\tPropertySource<?> propertySource = new MapPropertySource(\"svn\", Collections.singletonMap(\"svn\", loaded));\n\t\treturn new ConfigData(Collections.singleton(propertySource));\n\t}\n\n\tprivate static void onBootstrapContextClosed(BootstrapContextClosedEvent event) {\n\t\tSubversionClient subversionClient = event.getBootstrapContext().get(SubversionClient.class);\n\t\tAssert.state(subversionClient != null, \"'subversionClient' must not be null\");\n\t\tevent.getApplicationContext().getBeanFactory().registerSingleton(\"subversionClient\", subversionClient);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/SubversionConfigDataLocationResolver.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.external.svn;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.springframework.boot.context.config.ConfigDataLocation;\nimport org.springframework.boot.context.config.ConfigDataLocationNotFoundException;\nimport org.springframework.boot.context.config.ConfigDataLocationResolver;\nimport org.springframework.boot.context.config.ConfigDataLocationResolverContext;\nimport org.springframework.boot.context.config.ConfigDataResourceNotFoundException;\n\n/**\n * {@link ConfigDataLocationResolver} for subversion.\n *\n * @author Phillip Webb\n */\nclass SubversionConfigDataLocationResolver implements ConfigDataLocationResolver<SubversionConfigDataResource> {\n\n\tprivate static final String PREFIX = \"svn:\";\n\n\t@Override\n\tpublic boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {\n\t\treturn location.hasPrefix(PREFIX);\n\t}\n\n\t@Override\n\tpublic List<SubversionConfigDataResource> resolve(ConfigDataLocationResolverContext context,\n\t\t\tConfigDataLocation location)\n\t\t\tthrows ConfigDataLocationNotFoundException, ConfigDataResourceNotFoundException {\n\t\tString serverCertificate = context.getBinder().bind(\"spring.svn.server.certificate\", String.class).orElse(null);\n\t\treturn Collections\n\t\t\t.singletonList(new SubversionConfigDataResource(location.getNonPrefixedValue(PREFIX), serverCertificate));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/SubversionConfigDataResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.external.svn;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.config.ConfigDataResource;\n\n/**\n * A subversion {@link ConfigDataResource}.\n *\n * @author Phillip Webb\n */\nclass SubversionConfigDataResource extends ConfigDataResource {\n\n\tprivate final String location;\n\n\tprivate final @Nullable SubversionServerCertificate serverCertificate;\n\n\tSubversionConfigDataResource(String location, @Nullable String serverCertificate) {\n\t\tthis.location = location;\n\t\tthis.serverCertificate = SubversionServerCertificate.of(serverCertificate);\n\t}\n\n\tString getLocation() {\n\t\treturn this.location;\n\t}\n\n\t@Nullable SubversionServerCertificate getServerCertificate() {\n\t\treturn this.serverCertificate;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || getClass() != obj.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tSubversionConfigDataResource other = (SubversionConfigDataResource) obj;\n\t\treturn this.location.equals(other.location);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.location.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.location;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/SubversionServerCertificate.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.external.svn;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.StringUtils;\n\n/**\n * A certificate that can be used to provide a secure connection to the subversion server.\n *\n * @author Phillip Webb\n */\npublic class SubversionServerCertificate {\n\n\tprivate final String data;\n\n\tSubversionServerCertificate(String data) {\n\t\tthis.data = data;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.data;\n\t}\n\n\tpublic static @Nullable SubversionServerCertificate of(@Nullable String data) {\n\t\treturn StringUtils.hasText(data) ? new SubversionServerCertificate(data) : null;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/java/smoketest/bootstrapregistry/external/svn/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * An example of a hypothetical library that supports subversion.\n */\n@NullMarked\npackage smoketest.bootstrapregistry.external.svn;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/resources/META-INF/spring.factories",
    "content": "# ConfigData Location Resolvers\norg.springframework.boot.context.config.ConfigDataLocationResolver=\\\nsmoketest.bootstrapregistry.external.svn.SubversionConfigDataLocationResolver\n\n# ConfigData Loaders\norg.springframework.boot.context.config.ConfigDataLoader=\\\nsmoketest.bootstrapregistry.external.svn.SubversionConfigDataLoader\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/main/resources/application.properties",
    "content": "spring.svn.server.certificate=secret\nspring.config.import=svn:example.com\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-bootstrap-registry/src/test/java/smoketest/bootstrapregistry/app/SampleBootstrapRegistryApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.bootstrapregistry.app;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleBootstrapRegistryApplication}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleBootstrapRegistryApplicationTests {\n\n\t@Test\n\tvoid testBootstrapper(CapturedOutput output) {\n\t\tSampleBootstrapRegistryApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"svn my-data from svn / example.com[secret]\")\n\t\t\t.contains(\"client smoketest.bootstrapregistry.app.MySubversionClient\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot cache smoke test\"\n\nsourceSets {\n\tredisTest {\n\t\tcompileClasspath += sourceSets.main.output\n\t\truntimeClasspath += sourceSets.main.output\n\t}\n}\n\nconfigurations {\n\tcaffeine\n\tcouchbase\n\tehcache\n\thazelcast\n\tinfinispan\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-cache\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tcaffeine(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\tcaffeine(\"com.github.ben-manes.caffeine:caffeine\")\n\n\tcouchbase(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\tcouchbase(project(\":starter:spring-boot-starter-data-couchbase\"))\n\n\tehcache(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\tehcache(\"javax.cache:cache-api\")\n\tehcache(\"org.ehcache:ehcache::jakarta\")\n\n\thazelcast(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\thazelcast(project(\":module:spring-boot-hazelcast\"))\n\thazelcast(\"com.hazelcast:hazelcast-spring\")\n\n\tinfinispan(enforcedPlatform(project(\":platform:spring-boot-dependencies\")))\n\tinfinispan(\"javax.cache:cache-api\")\n\tinfinispan(\"org.infinispan:infinispan-commons\")\n\tinfinispan(\"org.infinispan:infinispan-component-annotations\")\n\tinfinispan(\"org.infinispan:infinispan-core\")\n\tinfinispan(\"org.infinispan:infinispan-jcache\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-redis-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ndef testCaffeine = tasks.register(\"testCaffeine\", Test) {\n\tdescription = \"Runs the tests against Caffeine\"\n\tclasspath = sourceSets.test.runtimeClasspath + configurations.caffeine\n\ttestClassesDirs = testing.suites.test.sources.output.classesDirs\n}\n\ndef testCouchbase = tasks.register(\"testCouchbase\", Test) {\n\tdescription = \"Runs the tests against Couchbase\"\n\tclasspath = sourceSets.test.runtimeClasspath + configurations.couchbase\n\ttestClassesDirs = testing.suites.test.sources.output.classesDirs\n}\n\ndef testEhcache = tasks.register(\"testEhcache\", Test) {\n\tdescription = \"Runs the tests against Ehcache\"\n\tclasspath = sourceSets.test.runtimeClasspath + configurations.ehcache\n\ttestClassesDirs = testing.suites.test.sources.output.classesDirs\n\tsystemProperties = [\"spring.cache.jcache.config\" : \"classpath:ehcache3.xml\"]\n}\n\ndef testHazelcast = tasks.register(\"testHazelcast\", Test) {\n\tdescription = \"Runs the tests against Hazelcast\"\n\tclasspath = sourceSets.test.runtimeClasspath + configurations.hazelcast\n\ttestClassesDirs = testing.suites.test.sources.output.classesDirs\n}\n\ndef testInfinispan = tasks.register(\"testInfinispan\", Test) {\n\tdescription = \"Runs the tests against Infinispan\"\n\tclasspath = sourceSets.test.runtimeClasspath + configurations.infinispan\n\ttestClassesDirs = testing.suites.test.sources.output.classesDirs\n\tsystemProperties = [\"spring.cache.jcache.config\" : \"classpath:infinispan.xml\"]\n}\n\ntasks.named(\"check\").configure {\n\tdependsOn testCaffeine, testCouchbase, testEhcache, testHazelcast, testInfinispan\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/dockerTest/java/smoketest/cache/SampleCacheApplicationRedisTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.Cache.ValueWrapper;\nimport org.springframework.cache.CacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@Testcontainers(disabledWithoutDocker = true)\nclass SampleCacheApplicationRedisTests {\n\n\t@Container\n\t@ServiceConnection\n\tprivate static final RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired\n\tprivate CacheManager cacheManager;\n\n\t@Autowired\n\tprivate CountryRepository countryRepository;\n\n\t@Test\n\tvoid validateCache() {\n\t\tCache countries = this.cacheManager.getCache(\"countries\");\n\t\tassertThat(countries).isNotNull();\n\t\tcountries.clear(); // Simple test assuming the cache is empty\n\t\tassertThat(countries.get(\"BE\")).isNull();\n\t\tCountry be = this.countryRepository.findByCode(\"BE\");\n\t\tValueWrapper belgium = countries.get(\"BE\");\n\t\tassertThat(belgium).isNotNull();\n\t\tassertThat((Country) belgium.get()).isEqualTo(be);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/dockerTest/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n</configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/java/smoketest/cache/CacheManagerCheck.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class CacheManagerCheck implements CommandLineRunner {\n\n\tprivate static final Log logger = LogFactory.getLog(CacheManagerCheck.class);\n\n\tprivate final CacheManager cacheManager;\n\n\tpublic CacheManagerCheck(CacheManager cacheManager) {\n\t\tthis.cacheManager = cacheManager;\n\t}\n\n\t@Override\n\tpublic void run(String... strings) throws Exception {\n\t\tlogger.info(\"\\n\\n=========================================================\\nUsing cache manager: \"\n\t\t\t\t+ this.cacheManager.getClass().getName() + \"\\n\"\n\t\t\t\t+ \"=========================================================\\n\\n\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/java/smoketest/cache/Country.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport java.io.Serializable;\n\nimport org.jspecify.annotations.Nullable;\n\n@SuppressWarnings(\"serial\")\npublic class Country implements Serializable {\n\n\tprivate final String code;\n\n\tpublic Country(String code) {\n\t\tthis.code = code;\n\t}\n\n\tpublic String getCode() {\n\t\treturn this.code;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object o) {\n\t\tif (this == o) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tCountry country = (Country) o;\n\n\t\treturn this.code.equals(country.code);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.code.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/java/smoketest/cache/CountryRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport org.springframework.cache.annotation.CacheConfig;\nimport org.springframework.cache.annotation.Cacheable;\nimport org.springframework.stereotype.Component;\n\n@Component\n@CacheConfig(cacheNames = \"countries\")\npublic class CountryRepository {\n\n\t@Cacheable\n\tpublic Country findByCode(String code) {\n\t\tSystem.out.println(\"---> Loading country with code '\" + code + \"'\");\n\t\treturn new Country(code);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/java/smoketest/cache/SampleCacheApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.scheduling.annotation.EnableScheduling;\n\n@EnableCaching\n@EnableScheduling\n@SpringBootApplication\npublic class SampleCacheApplication {\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder().sources(SampleCacheApplication.class).profiles(\"app\").run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/java/smoketest/cache/SampleClient.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Random;\n\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.scheduling.annotation.Scheduled;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Profile(\"app\")\nclass SampleClient {\n\n\tprivate static final List<String> SAMPLE_COUNTRY_CODES = Arrays.asList(\"AF\", \"AX\", \"AL\", \"DZ\", \"AS\", \"AD\", \"AO\",\n\t\t\t\"AI\", \"AQ\", \"AG\", \"AR\", \"AM\", \"AW\", \"AU\", \"AT\", \"AZ\", \"BS\", \"BH\", \"BD\", \"BB\", \"BY\", \"BE\", \"BZ\", \"BJ\", \"BM\",\n\t\t\t\"BT\", \"BO\", \"BQ\", \"BA\", \"BW\", \"BV\", \"BR\", \"IO\", \"BN\", \"BG\", \"BF\", \"BI\", \"KH\", \"CM\", \"CA\", \"CV\", \"KY\", \"CF\",\n\t\t\t\"TD\", \"CL\", \"CN\", \"CX\", \"CC\", \"CO\", \"KM\", \"CG\", \"CD\", \"CK\", \"CR\", \"CI\", \"HR\", \"CU\", \"CW\", \"CY\", \"CZ\", \"DK\",\n\t\t\t\"DJ\", \"DM\", \"DO\", \"EC\", \"EG\", \"SV\", \"GQ\", \"ER\", \"EE\", \"ET\", \"FK\", \"FO\", \"FJ\", \"FI\", \"FR\", \"GF\", \"PF\", \"TF\",\n\t\t\t\"GA\", \"GM\", \"GE\", \"DE\", \"GH\", \"GI\", \"GR\", \"GL\", \"GD\", \"GP\", \"GU\", \"GT\", \"GG\", \"GN\", \"GW\", \"GY\", \"HT\", \"HM\",\n\t\t\t\"VA\", \"HN\", \"HK\", \"HU\", \"IS\", \"IN\", \"ID\", \"IR\", \"IQ\", \"IE\", \"IM\", \"IL\", \"IT\", \"JM\", \"JP\", \"JE\", \"JO\", \"KZ\",\n\t\t\t\"KE\", \"KI\", \"KP\", \"KR\", \"KW\", \"KG\", \"LA\", \"LV\", \"LB\", \"LS\", \"LR\", \"LY\", \"LI\", \"LT\", \"LU\", \"MO\", \"MK\", \"MG\",\n\t\t\t\"MW\", \"MY\", \"MV\", \"ML\", \"MT\", \"MH\", \"MQ\", \"MR\", \"MU\", \"YT\", \"MX\", \"FM\", \"MD\", \"MC\", \"MN\", \"ME\", \"MS\", \"MA\",\n\t\t\t\"MZ\", \"MM\", \"NA\", \"NR\", \"NP\", \"NL\", \"NC\", \"NZ\", \"NI\", \"NE\", \"NG\", \"NU\", \"NF\", \"MP\", \"NO\", \"OM\", \"PK\", \"PW\",\n\t\t\t\"PS\", \"PA\", \"PG\", \"PY\", \"PE\", \"PH\", \"PN\", \"PL\", \"PT\", \"PR\", \"QA\", \"RE\", \"RO\", \"RU\", \"RW\", \"BL\", \"SH\", \"KN\",\n\t\t\t\"LC\", \"MF\", \"PM\", \"VC\", \"WS\", \"SM\", \"ST\", \"SA\", \"SN\", \"RS\", \"SC\", \"SL\", \"SG\", \"SX\", \"SK\", \"SI\", \"SB\", \"SO\",\n\t\t\t\"ZA\", \"GS\", \"SS\", \"ES\", \"LK\", \"SD\", \"SR\", \"SJ\", \"SZ\", \"SE\", \"CH\", \"SY\", \"TW\", \"TJ\", \"TZ\", \"TH\", \"TL\", \"TG\",\n\t\t\t\"TK\", \"TO\", \"TT\", \"TN\", \"TR\", \"TM\", \"TC\", \"TV\", \"UG\", \"UA\", \"AE\", \"GB\", \"US\", \"UM\", \"UY\", \"UZ\", \"VU\", \"VE\",\n\t\t\t\"VN\", \"VG\", \"VI\", \"WF\", \"EH\", \"YE\", \"ZM\", \"ZW\");\n\n\tprivate final CountryRepository countryService;\n\n\tprivate final Random random;\n\n\tSampleClient(CountryRepository countryService) {\n\t\tthis.countryService = countryService;\n\t\tthis.random = new Random();\n\t}\n\n\t@Scheduled(fixedDelay = 500)\n\tvoid retrieveCountry() {\n\t\tString randomCode = SAMPLE_COUNTRY_CODES.get(this.random.nextInt(SAMPLE_COUNTRY_CODES.size()));\n\t\tSystem.out.println(\"Looking for country with code '\" + randomCode + \"'\");\n\t\tthis.countryService.findByCode(randomCode);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/java/smoketest/cache/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.cache;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/resources/ehcache3.xml",
    "content": "<config xmlns='http://www.ehcache.org/v3'\n\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\txmlns:jsr107=\"http://www.ehcache.org/v3/jsr107\"\n\t\txsi:schemaLocation=\"http://www.ehcache.org/v3 https://www.ehcache.org/schema/ehcache-core-3.0.xsd\n\t\t\t\t\t\t\thttp://www.ehcache.org/v3/jsr107 https://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd\">\n\t<cache alias=\"countries\">\n\t\t<expiry>\n\t\t\t<ttl unit=\"seconds\">600</ttl>\n\t\t</expiry>\n\t\t<heap unit=\"entries\">200</heap>\n\t\t<jsr107:mbeans enable-statistics=\"true\"/>\n\t</cache>\n\n</config>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/main/resources/infinispan.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<infinispan>\n\n\t<!-- ************************************** -->\n\t<!-- Corresponds to @Cacheable(\"cache-name\") -->\n\t<!-- ************************************** -->\n\t<cache-container default-cache=\"countries\">\n\t\t<local-cache name=\"countries\"/>\n\t</cache-container>\n\n</infinispan>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-cache/src/test/java/smoketest/cache/SampleCacheApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.cache;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.Cache.ValueWrapper;\nimport org.springframework.cache.CacheManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\nclass SampleCacheApplicationTests {\n\n\t@Autowired\n\tprivate CacheManager cacheManager;\n\n\t@Autowired\n\tprivate CountryRepository countryRepository;\n\n\t@Test\n\tvoid validateCache() {\n\t\tCache countries = this.cacheManager.getCache(\"countries\");\n\t\tassertThat(countries).isNotNull();\n\t\tcountries.clear(); // Simple test assuming the cache is empty\n\t\tassertThat(countries.get(\"BE\")).isNull();\n\t\tCountry be = this.countryRepository.findByCode(\"BE\");\n\t\tValueWrapper belgium = countries.get(\"BE\");\n\t\tassertThat(belgium).isNotNull();\n\t\tassertThat((Country) belgium.get()).isEqualTo(be);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-config/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Config smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"test\", Test) {\n\tenvironment \"SMOKE_TEST_CONFIG_ENV\", \"from-env.key1=value1\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-config/src/main/java/smoketest/config/FromEnvConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.config;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@ConfigurationProperties(\"from-env\")\nclass FromEnvConfigurationProperties {\n\n\tprivate @Nullable String key1;\n\n\t@Nullable String getKey1() {\n\t\treturn this.key1;\n\t}\n\n\tvoid setKey1(@Nullable String key1) {\n\t\tthis.key1 = key1;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-config/src/main/java/smoketest/config/SampleConfigApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.config;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n@SpringBootApplication\n@EnableConfigurationProperties(FromEnvConfigurationProperties.class)\npublic class SampleConfigApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleConfigApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-config/src/main/java/smoketest/config/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.config;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-config/src/main/resources/application.properties",
    "content": "spring.config.import=optional:env:SMOKE_TEST_CONFIG_ENV\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-config/src/test/java/smoketest/config/FromEnvConfigurationPropertiesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FromEnvConfigurationProperties}.\n *\n * @author Moritz Halbritter\n */\n@SpringBootTest\nclass FromEnvConfigurationPropertiesTests {\n\n\t@Autowired\n\tprivate FromEnvConfigurationProperties properties;\n\n\t@Test\n\tvoid shouldHaveImportedValues() {\n\t\tassertThat(this.properties.getKey1()).isEqualTo(\"value1\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data Cassandra smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-cassandra\"))\n\timplementation(project(\":starter:spring-boot-starter-data-cassandra-reactive\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-cassandra-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-cassandra-reactive-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-cassandra\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/dockerTest/java/smoketest/data/cassandra/SampleDataCassandraApplicationReactiveSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport java.time.Duration;\nimport java.util.UUID;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.JksKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.JksTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.cassandra.core.ReactiveCassandraTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Cassandra using reactive repositories with SSL.\n *\n * @author Eddú Meléndez\n */\n@Testcontainers(disabledWithoutDocker = true)\n@SpringBootTest(properties = { \"spring.cassandra.schema-action=create-if-not-exists\",\n\t\t\"spring.cassandra.connection.connect-timeout=60s\", \"spring.cassandra.connection.init-query-timeout=60s\",\n\t\t\"spring.cassandra.request.timeout=60s\" })\nclass SampleDataCassandraApplicationReactiveSslTests {\n\n\t@Container\n\t@ServiceConnection\n\t@JksTrustStore(location = \"classpath:ssl/test-ca.p12\", password = \"password\")\n\t@JksKeyStore(location = \"classpath:ssl/test-client.p12\", password = \"password\")\n\tstatic final SecureCassandraContainer cassandra = TestImage.container(SecureCassandraContainer.class);\n\n\t@Autowired\n\tprivate ReactiveCassandraTemplate cassandraTemplate;\n\n\t@Autowired\n\tprivate SampleRepository repository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleEntity entity = new SampleEntity();\n\t\tentity.setDescription(\"Look, new @DataCassandraTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tentity.setId(id);\n\t\tSampleEntity savedEntity = this.repository.save(entity);\n\t\tSampleEntity getEntity = this.cassandraTemplate.selectOneById(id, SampleEntity.class)\n\t\t\t.block(Duration.ofSeconds(30));\n\t\tassertThat(getEntity).isNotNull();\n\t\tassertThat(getEntity.getId()).isNotNull();\n\t\tassertThat(getEntity.getId()).isEqualTo(savedEntity.getId());\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class KeyspaceTestConfiguration {\n\n\t\t@Bean\n\t\tCqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {\n\t\t\ttry (CqlSession session = cqlSessionBuilder.build()) {\n\t\t\t\tsession.execute(\"CREATE KEYSPACE IF NOT EXISTS boot_test\"\n\t\t\t\t\t\t+ \" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };\");\n\t\t\t}\n\t\t\treturn cqlSessionBuilder.withKeyspace(\"boot_test\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/dockerTest/java/smoketest/data/cassandra/SampleDataCassandraApplicationSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport java.util.UUID;\n\nimport com.datastax.oss.driver.api.core.CqlSession;\nimport com.datastax.oss.driver.api.core.CqlSessionBuilder;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.cassandra.test.autoconfigure.DataCassandraTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.JksKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.JksTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.data.cassandra.core.CassandraTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Cassandra with SSL.\n *\n * @author Scott Frederick\n * @author Eddú Meléndez\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataCassandraTest(properties = { \"spring.cassandra.schema-action=create-if-not-exists\",\n\t\t\"spring.cassandra.connection.connect-timeout=60s\", \"spring.cassandra.connection.init-query-timeout=60s\",\n\t\t\"spring.cassandra.request.timeout=60s\" })\nclass SampleDataCassandraApplicationSslTests {\n\n\t@Container\n\t@ServiceConnection\n\t@JksTrustStore(location = \"classpath:ssl/test-ca.p12\", password = \"password\")\n\t@JksKeyStore(location = \"classpath:ssl/test-client.p12\", password = \"password\")\n\tstatic final SecureCassandraContainer cassandra = TestImage.container(SecureCassandraContainer.class);\n\n\t@Autowired\n\tprivate CassandraTemplate cassandraTemplate;\n\n\t@Autowired\n\tprivate SampleRepository repository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleEntity entity = new SampleEntity();\n\t\tentity.setDescription(\"Look, new @DataCassandraTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tentity.setId(id);\n\t\tSampleEntity savedEntity = this.repository.save(entity);\n\t\tSampleEntity getEntity = this.cassandraTemplate.selectOneById(id, SampleEntity.class);\n\t\tassertThat(getEntity).isNotNull();\n\t\tassertThat(getEntity.getId()).isNotNull();\n\t\tassertThat(getEntity.getId()).isEqualTo(savedEntity.getId());\n\t\tthis.repository.deleteAll();\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class KeyspaceTestConfiguration {\n\n\t\t@Bean\n\t\tCqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {\n\t\t\ttry (CqlSession session = cqlSessionBuilder.build()) {\n\t\t\t\tsession.execute(\"CREATE KEYSPACE IF NOT EXISTS boot_test\"\n\t\t\t\t\t\t+ \" WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };\");\n\t\t\t}\n\t\t\treturn cqlSessionBuilder.withKeyspace(\"boot_test\").build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/dockerTest/java/smoketest/data/cassandra/SecureCassandraContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.containers.wait.strategy.Wait;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link CassandraContainer} for Cassandra with SSL configuration.\n *\n * @author Scott Frederick\n */\nclass SecureCassandraContainer extends CassandraContainer {\n\n\tSecureCassandraContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\tsetWaitStrategy(Wait.defaultWaitStrategy()); // default strategy uses plain text\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/cassandra.yaml\"),\n\t\t\t\t\"/etc/cassandra/cassandra.yaml\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.p12\"),\n\t\t\t\t\"/etc/cassandra/server.p12\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-ca.p12\"),\n\t\t\t\t\"/etc/cassandra/truststore.p12\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/dockerTest/resources/ssl/cassandra.yaml",
    "content": "# Cassandra storage config YAML\n\n# NOTE:\n#   See https://wiki.apache.org/cassandra/StorageConfiguration for\n#   full explanations of configuration directives\n# /NOTE\n\n# The name of the cluster. This is mainly used to prevent machines in\n# one logical cluster from joining another.\ncluster_name: 'Test Cluster'\n\n# This defines the number of tokens randomly assigned to this node on the ring\n# The more tokens, relative to other nodes, the larger the proportion of data\n# that this node will store. You probably want all nodes to have the same number\n# of tokens assuming they have equal hardware capability.\n#\n# If you leave this unspecified, Cassandra will use the default of 1 token for legacy compatibility,\n# and will use the initial_token as described below.\n#\n# Specifying initial_token will override this setting on the node's initial start,\n# on subsequent starts, this setting will apply even if initial token is set.\n#\n# If you already have a cluster with 1 token per node, and wish to migrate to \n# multiple tokens per node, see https://wiki.apache.org/cassandra/Operations\nnum_tokens: 256\n\n# Triggers automatic allocation of num_tokens tokens for this node. The allocation\n# algorithm attempts to choose tokens in a way that optimizes replicated load over\n# the nodes in the datacenter for the replication strategy used by the specified\n# keyspace.\n#\n# The load assigned to each node will be close to proportional to its number of\n# vnodes.\n#\n# Only supported with the Murmur3Partitioner.\n# allocate_tokens_for_keyspace: KEYSPACE\n\n# initial_token allows you to specify tokens manually.  While you can use it with\n# vnodes (num_tokens > 1, above) -- in which case you should provide a \n# comma-separated list -- it's primarily used when adding nodes to legacy clusters \n# that do not have vnodes enabled.\n# initial_token:\n\n# See https://wiki.apache.org/cassandra/HintedHandoff\n# May either be \"true\" or \"false\" to enable globally\nhinted_handoff_enabled: true\n\n# When hinted_handoff_enabled is true, a black list of data centers that will not\n# perform hinted handoff\n# hinted_handoff_disabled_datacenters:\n#    - DC1\n#    - DC2\n\n# this defines the maximum amount of time a dead host will have hints\n# generated.  After it has been dead this long, new hints for it will not be\n# created until it has been seen alive and gone down again.\nmax_hint_window_in_ms: 10800000 # 3 hours\n\n# Maximum throttle in KBs per second, per delivery thread.  This will be\n# reduced proportionally to the number of nodes in the cluster.  (If there\n# are two nodes in the cluster, each delivery thread will use the maximum\n# rate; if there are three, each will throttle to half of the maximum,\n# since we expect two nodes to be delivering hints simultaneously.)\nhinted_handoff_throttle_in_kb: 1024\n\n# Number of threads with which to deliver hints;\n# Consider increasing this number when you have multi-dc deployments, since\n# cross-dc handoff tends to be slower\nmax_hints_delivery_threads: 2\n\n# Directory where Cassandra should store hints.\n# If not set, the default directory is $CASSANDRA_HOME/data/hints.\n# hints_directory: /var/lib/cassandra/hints\n\n# How often hints should be flushed from the internal buffers to disk.\n# Will *not* trigger fsync.\nhints_flush_period_in_ms: 10000\n\n# Maximum size for a single hints file, in megabytes.\nmax_hints_file_size_in_mb: 128\n\n# Compression to apply to the hint files. If omitted, hints files\n# will be written uncompressed. LZ4, Snappy, and Deflate compressors\n# are supported.\n#hints_compression:\n#   - class_name: LZ4Compressor\n#     parameters:\n#         -\n\n# Maximum throttle in KBs per second, total. This will be\n# reduced proportionally to the number of nodes in the cluster.\nbatchlog_replay_throttle_in_kb: 1024\n\n# Authentication backend, implementing IAuthenticator; used to identify users\n# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthenticator,\n# PasswordAuthenticator}.\n#\n# - AllowAllAuthenticator performs no checks - set it to disable authentication.\n# - PasswordAuthenticator relies on username/password pairs to authenticate\n#   users. It keeps usernames and hashed passwords in system_auth.roles table.\n#   Please increase system_auth keyspace replication factor if you use this authenticator.\n#   If using PasswordAuthenticator, CassandraRoleManager must also be used (see below)\nauthenticator: AllowAllAuthenticator\n\n# Authorization backend, implementing IAuthorizer; used to limit access/provide permissions\n# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthorizer,\n# CassandraAuthorizer}.\n#\n# - AllowAllAuthorizer allows any action to any user - set it to disable authorization.\n# - CassandraAuthorizer stores permissions in system_auth.role_permissions table. Please\n#   increase system_auth keyspace replication factor if you use this authorizer.\nauthorizer: AllowAllAuthorizer\n\n# Part of the Authentication & Authorization backend, implementing IRoleManager; used\n# to maintain grants and memberships between roles.\n# Out of the box, Cassandra provides org.apache.cassandra.auth.CassandraRoleManager,\n# which stores role information in the system_auth keyspace. Most functions of the\n# IRoleManager require an authenticated login, so unless the configured IAuthenticator\n# actually implements authentication, most of this functionality will be unavailable.\n#\n# - CassandraRoleManager stores role data in the system_auth keyspace. Please\n#   increase system_auth keyspace replication factor if you use this role manager.\nrole_manager: CassandraRoleManager\n\n# Validity period for roles cache (fetching granted roles can be an expensive\n# operation depending on the role manager, CassandraRoleManager is one example)\n# Granted roles are cached for authenticated sessions in AuthenticatedUser and\n# after the period specified here, become eligible for (async) reload.\n# Defaults to 2000, set to 0 to disable caching entirely.\n# Will be disabled automatically for AllowAllAuthenticator.\nroles_validity_in_ms: 2000\n\n# Refresh interval for roles cache (if enabled).\n# After this interval, cache entries become eligible for refresh. Upon next\n# access, an async reload is scheduled and the old value returned until it\n# completes. If roles_validity_in_ms is non-zero, then this must be\n# also.\n# Defaults to the same value as roles_validity_in_ms.\n# roles_update_interval_in_ms: 2000\n\n# Validity period for permissions cache (fetching permissions can be an\n# expensive operation depending on the authorizer, CassandraAuthorizer is\n# one example). Defaults to 2000, set to 0 to disable.\n# Will be disabled automatically for AllowAllAuthorizer.\npermissions_validity_in_ms: 2000\n\n# Refresh interval for permissions cache (if enabled).\n# After this interval, cache entries become eligible for refresh. Upon next\n# access, an async reload is scheduled and the old value returned until it\n# completes. If permissions_validity_in_ms is non-zero, then this must be\n# also.\n# Defaults to the same value as permissions_validity_in_ms.\n# permissions_update_interval_in_ms: 2000\n\n# Validity period for credentials cache. This cache is tightly coupled to\n# the provided PasswordAuthenticator implementation of IAuthenticator. If\n# another IAuthenticator implementation is configured, this cache will not\n# be automatically used and so the following settings will have no effect.\n# Please note, credentials are cached in their encrypted form, so while\n# activating this cache may reduce the number of queries made to the\n# underlying table, it may not  bring a significant reduction in the\n# latency of individual authentication attempts.\n# Defaults to 2000, set to 0 to disable credentials caching.\ncredentials_validity_in_ms: 2000\n\n# Refresh interval for credentials cache (if enabled).\n# After this interval, cache entries become eligible for refresh. Upon next\n# access, an async reload is scheduled and the old value returned until it\n# completes. If credentials_validity_in_ms is non-zero, then this must be\n# also.\n# Defaults to the same value as credentials_validity_in_ms.\n# credentials_update_interval_in_ms: 2000\n\n# The partitioner is responsible for distributing groups of rows (by\n# partition key) across nodes in the cluster.  You should leave this\n# alone for new clusters.  The partitioner can NOT be changed without\n# reloading all data, so when upgrading you should set this to the\n# same partitioner you were already using.\n#\n# Besides Murmur3Partitioner, partitioners included for backwards\n# compatibility include RandomPartitioner, ByteOrderedPartitioner, and\n# OrderPreservingPartitioner.\n#\npartitioner: org.apache.cassandra.dht.Murmur3Partitioner\n\n# Directories where Cassandra should store data on disk.  Cassandra\n# will spread data evenly across them, subject to the granularity of\n# the configured compaction strategy.\n# If not set, the default directory is $CASSANDRA_HOME/data/data.\n# data_file_directories:\n#     - /var/lib/cassandra/data\n\n# commit log.  when running on magnetic HDD, this should be a\n# separate spindle than the data directories.\n# If not set, the default directory is $CASSANDRA_HOME/data/commitlog.\n# commitlog_directory: /var/lib/cassandra/commitlog\n\n# Enable / disable CDC functionality on a per-node basis. This modifies the logic used\n# for write path allocation rejection (standard: never reject. cdc: reject Mutation\n# containing a CDC-enabled table if at space limit in cdc_raw_directory).\ncdc_enabled: false\n\n# CommitLogSegments are moved to this directory on flush if cdc_enabled: true and the\n# segment contains mutations for a CDC-enabled table. This should be placed on a\n# separate spindle than the data directories. If not set, the default directory is\n# $CASSANDRA_HOME/data/cdc_raw.\n# cdc_raw_directory: /var/lib/cassandra/cdc_raw\n\n# Policy for data disk failures:\n#\n# die\n#   shut down gossip and client transports and kill the JVM for any fs errors or\n#   single-sstable errors, so the node can be replaced.\n#\n# stop_paranoid\n#   shut down gossip and client transports even for single-sstable errors,\n#   kill the JVM for errors during startup.\n#\n# stop\n#   shut down gossip and client transports, leaving the node effectively dead, but\n#   can still be inspected via JMX, kill the JVM for errors during startup.\n#\n# best_effort\n#    stop using the failed disk and respond to requests based on\n#    remaining available sstables.  This means you WILL see obsolete\n#    data at CL.ONE!\n#\n# ignore\n#    ignore fatal errors and let requests fail, as in pre-1.2 Cassandra\ndisk_failure_policy: stop\n\n# Policy for commit disk failures:\n#\n# die\n#   shut down gossip and Thrift and kill the JVM, so the node can be replaced.\n#\n# stop\n#   shut down gossip and Thrift, leaving the node effectively dead, but\n#   can still be inspected via JMX.\n#\n# stop_commit\n#   shutdown the commit log, letting writes collect but\n#   continuing to service reads, as in pre-2.0.5 Cassandra\n#\n# ignore\n#   ignore fatal errors and let the batches fail\ncommit_failure_policy: stop\n\n# Maximum size of the native protocol prepared statement cache\n#\n# Valid values are either \"auto\" (omitting the value) or a value greater 0.\n#\n# Note that specifying a too large value will result in long running GCs and possbily\n# out-of-memory errors. Keep the value at a small fraction of the heap.\n#\n# If you constantly see \"prepared statements discarded in the last minute because\n# cache limit reached\" messages, the first step is to investigate the root cause\n# of these messages and check whether prepared statements are used correctly -\n# i.e. use bind markers for variable parts.\n#\n# Do only change the default value, if you really have more prepared statements than\n# fit in the cache. In most cases it is not neccessary to change this value.\n# Constantly re-preparing statements is a performance penalty.\n#\n# Default value (\"auto\") is 1/256th of the heap or 10MB, whichever is greater\nprepared_statements_cache_size_mb:\n\n# Maximum size of the Thrift prepared statement cache\n#\n# If you do not use Thrift at all, it is safe to leave this value at \"auto\".\n#\n# See description of 'prepared_statements_cache_size_mb' above for more information.\n#\n# Default value (\"auto\") is 1/256th of the heap or 10MB, whichever is greater\nthrift_prepared_statements_cache_size_mb:\n\n# Maximum size of the key cache in memory.\n#\n# Each key cache hit saves 1 seek and each row cache hit saves 2 seeks at the\n# minimum, sometimes more. The key cache is fairly tiny for the amount of\n# time it saves, so it's worthwhile to use it at large numbers.\n# The row cache saves even more time, but must contain the entire row,\n# so it is extremely space-intensive. It's best to only use the\n# row cache if you have hot rows or static rows.\n#\n# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup.\n#\n# Default value is empty to make it \"auto\" (min(5% of Heap (in MB), 100MB)). Set to 0 to disable key cache.\nkey_cache_size_in_mb:\n\n# Duration in seconds after which Cassandra should\n# save the key cache. Caches are saved to saved_caches_directory as\n# specified in this configuration file.\n#\n# Saved caches greatly improve cold-start speeds, and is relatively cheap in\n# terms of I/O for the key cache. Row cache saving is much more expensive and\n# has limited use.\n#\n# Default is 14400 or 4 hours.\nkey_cache_save_period: 14400\n\n# Number of keys from the key cache to save\n# Disabled by default, meaning all keys are going to be saved\n# key_cache_keys_to_save: 100\n\n# Row cache implementation class name. Available implementations:\n#\n# org.apache.cassandra.cache.OHCProvider\n#   Fully off-heap row cache implementation (default).\n#\n# org.apache.cassandra.cache.SerializingCacheProvider\n#   This is the row cache implementation availabile\n#   in previous releases of Cassandra.\n# row_cache_class_name: org.apache.cassandra.cache.OHCProvider\n\n# Maximum size of the row cache in memory.\n# Please note that OHC cache implementation requires some additional off-heap memory to manage\n# the map structures and some in-flight memory during operations before/after cache entries can be\n# accounted against the cache capacity. This overhead is usually small compared to the whole capacity.\n# Do not specify more memory that the system can afford in the worst usual situation and leave some\n# headroom for OS block level cache. Do never allow your system to swap.\n#\n# Default value is 0, to disable row caching.\nrow_cache_size_in_mb: 0\n\n# Duration in seconds after which Cassandra should save the row cache.\n# Caches are saved to saved_caches_directory as specified in this configuration file.\n#\n# Saved caches greatly improve cold-start speeds, and is relatively cheap in\n# terms of I/O for the key cache. Row cache saving is much more expensive and\n# has limited use.\n#\n# Default is 0 to disable saving the row cache.\nrow_cache_save_period: 0\n\n# Number of keys from the row cache to save.\n# Specify 0 (which is the default), meaning all keys are going to be saved\n# row_cache_keys_to_save: 100\n\n# Maximum size of the counter cache in memory.\n#\n# Counter cache helps to reduce counter locks' contention for hot counter cells.\n# In case of RF = 1 a counter cache hit will cause Cassandra to skip the read before\n# write entirely. With RF > 1 a counter cache hit will still help to reduce the duration\n# of the lock hold, helping with hot counter cell updates, but will not allow skipping\n# the read entirely. Only the local (clock, count) tuple of a counter cell is kept\n# in memory, not the whole counter, so it's relatively cheap.\n#\n# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup.\n#\n# Default value is empty to make it \"auto\" (min(2.5% of Heap (in MB), 50MB)). Set to 0 to disable counter cache.\n# NOTE: if you perform counter deletes and rely on low gcgs, you should disable the counter cache.\ncounter_cache_size_in_mb:\n\n# Duration in seconds after which Cassandra should\n# save the counter cache (keys only). Caches are saved to saved_caches_directory as\n# specified in this configuration file.\n#\n# Default is 7200 or 2 hours.\ncounter_cache_save_period: 7200\n\n# Number of keys from the counter cache to save\n# Disabled by default, meaning all keys are going to be saved\n# counter_cache_keys_to_save: 100\n\n# saved caches\n# If not set, the default directory is $CASSANDRA_HOME/data/saved_caches.\n# saved_caches_directory: /var/lib/cassandra/saved_caches\n\n# commitlog_sync may be either \"periodic\" or \"batch.\" \n# \n# When in batch mode, Cassandra won't ack writes until the commit log\n# has been fsynced to disk.  It will wait\n# commitlog_sync_batch_window_in_ms milliseconds between fsyncs.\n# This window should be kept short because the writer threads will\n# be unable to do extra work while waiting.  (You may need to increase\n# concurrent_writes for the same reason.)\n#\n# commitlog_sync: batch\n# commitlog_sync_batch_window_in_ms: 2\n#\n# the other option is \"periodic\" where writes may be acked immediately\n# and the CommitLog is simply synced every commitlog_sync_period_in_ms\n# milliseconds.\ncommitlog_sync: periodic\ncommitlog_sync_period_in_ms: 10000\n\n# The size of the individual commitlog file segments.  A commitlog\n# segment may be archived, deleted, or recycled once all the data\n# in it (potentially from each columnfamily in the system) has been\n# flushed to sstables.\n#\n# The default size is 32, which is almost always fine, but if you are\n# archiving commitlog segments (see commitlog_archiving.properties),\n# then you probably want a finer granularity of archiving; 8 or 16 MB\n# is reasonable.\n# Max mutation size is also configurable via max_mutation_size_in_kb setting in\n# cassandra.yaml. The default is half the size commitlog_segment_size_in_mb * 1024.\n# This should be positive and less than 2048.\n#\n# NOTE: If max_mutation_size_in_kb is set explicitly then commitlog_segment_size_in_mb must\n# be set to at least twice the size of max_mutation_size_in_kb / 1024\n#\ncommitlog_segment_size_in_mb: 32\n\n# Compression to apply to the commit log. If omitted, the commit log\n# will be written uncompressed.  LZ4, Snappy, and Deflate compressors\n# are supported.\n# commitlog_compression:\n#   - class_name: LZ4Compressor\n#     parameters:\n#         -\n\n# any class that implements the SeedProvider interface and has a\n# constructor that takes a Map<String, String> of parameters will do.\nseed_provider:\n    # Addresses of hosts that are deemed contact points. \n    # Cassandra nodes use this list of hosts to find each other and learn\n    # the topology of the ring.  You must change this if you are running\n    # multiple nodes!\n    - class_name: org.apache.cassandra.locator.SimpleSeedProvider\n      parameters:\n          # seeds is actually a comma-delimited list of addresses.\n          # Ex: \"<ip1>,<ip2>,<ip3>\"\n          - seeds: \"127.0.0.1\"\n\n# For workloads with more data than can fit in memory, Cassandra's\n# bottleneck will be reads that need to fetch data from\n# disk. \"concurrent_reads\" should be set to (16 * number_of_drives) in\n# order to allow the operations to enqueue low enough in the stack\n# that the OS and drives can reorder them. Same applies to\n# \"concurrent_counter_writes\", since counter writes read the current\n# values before incrementing and writing them back.\n#\n# On the other hand, since writes are almost never IO bound, the ideal\n# number of \"concurrent_writes\" is dependent on the number of cores in\n# your system; (8 * number_of_cores) is a good rule of thumb.\nconcurrent_reads: 32\nconcurrent_writes: 32\nconcurrent_counter_writes: 32\n\n# For materialized view writes, as there is a read involved, so this should\n# be limited by the less of concurrent reads or concurrent writes.\nconcurrent_materialized_view_writes: 32\n\n# Maximum memory to use for sstable chunk cache and buffer pooling.\n# 32MB of this are reserved for pooling buffers, the rest is used as an\n# cache that holds uncompressed sstable chunks.\n# Defaults to the smaller of 1/4 of heap or 512MB. This pool is allocated off-heap,\n# so is in addition to the memory allocated for heap. The cache also has on-heap\n# overhead which is roughly 128 bytes per chunk (i.e. 0.2% of the reserved size\n# if the default 64k chunk size is used).\n# Memory is only allocated when needed.\n# file_cache_size_in_mb: 512\n\n# Flag indicating whether to allocate on or off heap when the sstable buffer\n# pool is exhausted, that is when it has exceeded the maximum memory\n# file_cache_size_in_mb, beyond which it will not cache buffers but allocate on request.\n\n# buffer_pool_use_heap_if_exhausted: true\n\n# The strategy for optimizing disk read\n# Possible values are:\n# ssd (for solid state disks, the default)\n# spinning (for spinning disks)\n# disk_optimization_strategy: ssd\n\n# Total permitted memory to use for memtables. Cassandra will stop\n# accepting writes when the limit is exceeded until a flush completes,\n# and will trigger a flush based on memtable_cleanup_threshold\n# If omitted, Cassandra will set both to 1/4 the size of the heap.\n# memtable_heap_space_in_mb: 2048\n# memtable_offheap_space_in_mb: 2048\n\n# memtable_cleanup_threshold is deprecated. The default calculation\n# is the only reasonable choice. See the comments on  memtable_flush_writers\n# for more information.\n#\n# Ratio of occupied non-flushing memtable size to total permitted size\n# that will trigger a flush of the largest memtable. Larger mct will\n# mean larger flushes and hence less compaction, but also less concurrent\n# flush activity which can make it difficult to keep your disks fed\n# under heavy write load.\n#\n# memtable_cleanup_threshold defaults to 1 / (memtable_flush_writers + 1)\n# memtable_cleanup_threshold: 0.11\n\n# Specify the way Cassandra allocates and manages memtable memory.\n# Options are:\n#\n# heap_buffers\n#   on heap nio buffers\n#\n# offheap_buffers\n#   off heap (direct) nio buffers\n#\n# offheap_objects\n#    off heap objects\nmemtable_allocation_type: heap_buffers\n\n# Limits the maximum Merkle tree depth to avoid consuming too much\n# memory during repairs.\n#\n# The default setting of 18 generates trees of maximum size around\n# 50 MiB / tree. If you are running out of memory during repairs consider\n# lowering this to 15 (~6 MiB / tree) or lower, but try not to lower it\n# too much past that or you will lose too much resolution and stream\n# too much redundant data during repair. Cannot be set lower than 10.\n#\n# For more details see https://issues.apache.org/jira/browse/CASSANDRA-14096.\n#\n# repair_session_max_tree_depth: 18\n\n# Total space to use for commit logs on disk.\n#\n# If space gets above this value, Cassandra will flush every dirty CF\n# in the oldest segment and remove it.  So a small total commitlog space\n# will tend to cause more flush activity on less-active columnfamilies.\n#\n# The default value is the smaller of 8192, and 1/4 of the total space\n# of the commitlog volume.\n#\n# commitlog_total_space_in_mb: 8192\n\n# This sets the number of memtable flush writer threads per disk\n# as well as the total number of memtables that can be flushed concurrently.\n# These are generally a combination of compute and IO bound.\n#\n# Memtable flushing is more CPU efficient than memtable ingest and a single thread\n# can keep up with the ingest rate of a whole server on a single fast disk\n# until it temporarily becomes IO bound under contention typically with compaction.\n# At that point you need multiple flush threads. At some point in the future\n# it may become CPU bound all the time.\n#\n# You can tell if flushing is falling behind using the MemtablePool.BlockedOnAllocation\n# metric which should be 0, but will be non-zero if threads are blocked waiting on flushing\n# to free memory.\n#\n# memtable_flush_writers defaults to two for a single data directory.\n# This means that two  memtables can be flushed concurrently to the single data directory.\n# If you have multiple data directories the default is one memtable flushing at a time\n# but the flush will use a thread per data directory so you will get two or more writers.\n#\n# Two is generally enough to flush on a fast disk [array] mounted as a single data directory.\n# Adding more flush writers will result in smaller more frequent flushes that introduce more\n# compaction overhead.\n#\n# There is a direct tradeoff between number of memtables that can be flushed concurrently\n# and flush size and frequency. More is not better you just need enough flush writers\n# to never stall waiting for flushing to free memory.\n#\n#memtable_flush_writers: 2\n\n# Total space to use for change-data-capture logs on disk.\n#\n# If space gets above this value, Cassandra will throw WriteTimeoutException\n# on Mutations including tables with CDC enabled. A CDCCompactor is responsible\n# for parsing the raw CDC logs and deleting them when parsing is completed.\n#\n# The default value is the min of 4096 mb and 1/8th of the total space\n# of the drive where cdc_raw_directory resides.\n# cdc_total_space_in_mb: 4096\n\n# When we hit our cdc_raw limit and the CDCCompactor is either running behind\n# or experiencing backpressure, we check at the following interval to see if any\n# new space for cdc-tracked tables has been made available. Default to 250ms\n# cdc_free_space_check_interval_ms: 250\n\n# A fixed memory pool size in MB for for SSTable index summaries. If left\n# empty, this will default to 5% of the heap size. If the memory usage of\n# all index summaries exceeds this limit, SSTables with low read rates will\n# shrink their index summaries in order to meet this limit.  However, this\n# is a best-effort process. In extreme conditions Cassandra may need to use\n# more than this amount of memory.\nindex_summary_capacity_in_mb:\n\n# How frequently index summaries should be resampled.  This is done\n# periodically to redistribute memory from the fixed-size pool to sstables\n# proportional their recent read rates.  Setting to -1 will disable this\n# process, leaving existing index summaries at their current sampling level.\nindex_summary_resize_interval_in_minutes: 60\n\n# Whether to, when doing sequential writing, fsync() at intervals in\n# order to force the operating system to flush the dirty\n# buffers. Enable this to avoid sudden dirty buffer flushing from\n# impacting read latencies. Almost always a good idea on SSDs; not\n# necessarily on platters.\ntrickle_fsync: false\ntrickle_fsync_interval_in_kb: 10240\n\n# TCP port, for commands and data\n# For security reasons, you should not expose this port to the internet.  Firewall it if needed.\nstorage_port: 7000\n\n# SSL port, for encrypted communication.  Unused unless enabled in\n# encryption_options\n# For security reasons, you should not expose this port to the internet.  Firewall it if needed.\nssl_storage_port: 7001\n\n# Address or interface to bind to and tell other Cassandra nodes to connect to.\n# You _must_ change this if you want multiple nodes to be able to communicate!\n#\n# Set listen_address OR listen_interface, not both.\n#\n# Leaving it blank leaves it up to InetAddress.getLocalHost(). This\n# will always do the Right Thing _if_ the node is properly configured\n# (hostname, name resolution, etc.), and the Right Thing is to use the\n# address associated with the hostname (it might not be).\n#\n# Setting listen_address to 0.0.0.0 is always wrong.\n#\nlisten_address: localhost\n\n# Set listen_address OR listen_interface, not both. Interfaces must correspond\n# to a single address, IP aliasing is not supported.\n# listen_interface: eth0\n\n# If you choose to specify the interface by name and the interface has an ipv4 and an ipv6 address\n# you can specify which should be chosen using listen_interface_prefer_ipv6. If false the first ipv4\n# address will be used. If true the first ipv6 address will be used. Defaults to false preferring\n# ipv4. If there is only one address it will be selected regardless of ipv4/ipv6.\n# listen_interface_prefer_ipv6: false\n\n# Address to broadcast to other Cassandra nodes\n# Leaving this blank will set it to the same value as listen_address\n# broadcast_address: 1.2.3.4\n\n# When using multiple physical network interfaces, set this\n# to true to listen on broadcast_address in addition to\n# the listen_address, allowing nodes to communicate in both\n# interfaces.\n# Ignore this property if the network configuration automatically\n# routes  between the public and private networks such as EC2.\n# listen_on_broadcast_address: false\n\n# Internode authentication backend, implementing IInternodeAuthenticator;\n# used to allow/disallow connections from peer nodes.\n# internode_authenticator: org.apache.cassandra.auth.AllowAllInternodeAuthenticator\n\n# Whether to start the native transport server.\n# Please note that the address on which the native transport is bound is the\n# same as the rpc_address. The port however is different and specified below.\nstart_native_transport: true\n# port for the CQL native transport to listen for clients on\n# For security reasons, you should not expose this port to the internet.  Firewall it if needed.\nnative_transport_port: 9042\n# Enabling native transport encryption in client_encryption_options allows you to either use\n# encryption for the standard port or to use a dedicated, additional port along with the unencrypted\n# standard native_transport_port.\n# Enabling client encryption and keeping native_transport_port_ssl disabled will use encryption\n# for native_transport_port. Setting native_transport_port_ssl to a different value\n# from native_transport_port will use encryption for native_transport_port_ssl while\n# keeping native_transport_port unencrypted.\n# native_transport_port_ssl: 9142\n# The maximum threads for handling requests when the native transport is used.\n# This is similar to rpc_max_threads though the default differs slightly (and\n# there is no native_transport_min_threads, idle threads will always be stopped\n# after 30 seconds).\n# native_transport_max_threads: 128\n#\n# The maximum size of allowed frame. Frame (requests) larger than this will\n# be rejected as invalid. The default is 256MB. If you're changing this parameter,\n# you may want to adjust max_value_size_in_mb accordingly. This should be positive and less than 2048.\n# native_transport_max_frame_size_in_mb: 256\n\n# The maximum number of concurrent client connections.\n# The default is -1, which means unlimited.\n# native_transport_max_concurrent_connections: -1\n\n# The maximum number of concurrent client connections per source ip.\n# The default is -1, which means unlimited.\n# native_transport_max_concurrent_connections_per_ip: -1\n\n# Whether to start the thrift rpc server.\nstart_rpc: false\n\n# The address or interface to bind the Thrift RPC service and native transport\n# server to.\n#\n# Set rpc_address OR rpc_interface, not both.\n#\n# Leaving rpc_address blank has the same effect as on listen_address\n# (i.e. it will be based on the configured hostname of the node).\n#\n# Note that unlike listen_address, you can specify 0.0.0.0, but you must also\n# set broadcast_rpc_address to a value other than 0.0.0.0.\n#\n# For security reasons, you should not expose this port to the internet.  Firewall it if needed.\nrpc_address: localhost\n\n# Set rpc_address OR rpc_interface, not both. Interfaces must correspond\n# to a single address, IP aliasing is not supported.\n# rpc_interface: eth1\n\n# If you choose to specify the interface by name and the interface has an ipv4 and an ipv6 address\n# you can specify which should be chosen using rpc_interface_prefer_ipv6. If false the first ipv4\n# address will be used. If true the first ipv6 address will be used. Defaults to false preferring\n# ipv4. If there is only one address it will be selected regardless of ipv4/ipv6.\n# rpc_interface_prefer_ipv6: false\n\n# port for Thrift to listen for clients on\nrpc_port: 9160\n\n# RPC address to broadcast to drivers and other Cassandra nodes. This cannot\n# be set to 0.0.0.0. If left blank, this will be set to the value of\n# rpc_address. If rpc_address is set to 0.0.0.0, broadcast_rpc_address must\n# be set.\n# broadcast_rpc_address: 1.2.3.4\n\n# enable or disable keepalive on rpc/native connections\nrpc_keepalive: true\n\n# Cassandra provides two out-of-the-box options for the RPC Server:\n#\n# sync\n#   One thread per thrift connection. For a very large number of clients, memory\n#   will be your limiting factor. On a 64 bit JVM, 180KB is the minimum stack size\n#   per thread, and that will correspond to your use of virtual memory (but physical memory\n#   may be limited depending on use of stack space).\n#\n# hsha\n#   Stands for \"half synchronous, half asynchronous.\" All thrift clients are handled\n#   asynchronously using a small number of threads that does not vary with the amount\n#   of thrift clients (and thus scales well to many clients). The rpc requests are still\n#   synchronous (one thread per active request). If hsha is selected then it is essential\n#   that rpc_max_threads is changed from the default value of unlimited.\n#\n# The default is sync because on Windows hsha is about 30% slower.  On Linux,\n# sync/hsha performance is about the same, with hsha of course using less memory.\n#\n# Alternatively,  can provide your own RPC server by providing the fully-qualified class name\n# of an o.a.c.t.TServerFactory that can create an instance of it.\nrpc_server_type: sync\n\n# Uncomment rpc_min|max_thread to set request pool size limits.\n#\n# Regardless of your choice of RPC server (see above), the number of maximum requests in the\n# RPC thread pool dictates how many concurrent requests are possible (but if you are using the sync\n# RPC server, it also dictates the number of clients that can be connected at all).\n#\n# The default is unlimited and thus provides no protection against clients overwhelming the server. You are\n# encouraged to set a maximum that makes sense for you in production, but do keep in mind that\n# rpc_max_threads represents the maximum number of client requests this server may execute concurrently.\n#\n# rpc_min_threads: 16\n# rpc_max_threads: 2048\n\n# uncomment to set socket buffer sizes on rpc connections\n# rpc_send_buff_size_in_bytes:\n# rpc_recv_buff_size_in_bytes:\n\n# Uncomment to set socket buffer size for internode communication\n# Note that when setting this, the buffer size is limited by net.core.wmem_max\n# and when not setting it it is defined by net.ipv4.tcp_wmem\n# See also:\n# /proc/sys/net/core/wmem_max\n# /proc/sys/net/core/rmem_max\n# /proc/sys/net/ipv4/tcp_wmem\n# /proc/sys/net/ipv4/tcp_wmem\n# and 'man tcp'\n# internode_send_buff_size_in_bytes:\n\n# Uncomment to set socket buffer size for internode communication\n# Note that when setting this, the buffer size is limited by net.core.wmem_max\n# and when not setting it it is defined by net.ipv4.tcp_wmem\n# internode_recv_buff_size_in_bytes:\n\n# Frame size for thrift (maximum message length).\nthrift_framed_transport_size_in_mb: 15\n\n# Set to true to have Cassandra create a hard link to each sstable\n# flushed or streamed locally in a backups/ subdirectory of the\n# keyspace data.  Removing these links is the operator's\n# responsibility.\nincremental_backups: false\n\n# Whether or not to take a snapshot before each compaction.  Be\n# careful using this option, since Cassandra won't clean up the\n# snapshots for you.  Mostly useful if you're paranoid when there\n# is a data format change.\nsnapshot_before_compaction: false\n\n# Whether or not a snapshot is taken of the data before keyspace truncation\n# or dropping of column families. The STRONGLY advised default of true \n# should be used to provide data safety. If you set this flag to false, you will\n# lose data on truncation or drop.\nauto_snapshot: true\n\n# Granularity of the collation index of rows within a partition.\n# Increase if your rows are large, or if you have a very large\n# number of rows per partition.  The competing goals are these:\n#\n# - a smaller granularity means more index entries are generated\n#   and looking up rows withing the partition by collation column\n#   is faster\n# - but, Cassandra will keep the collation index in memory for hot\n#   rows (as part of the key cache), so a larger granularity means\n#   you can cache more hot rows\ncolumn_index_size_in_kb: 64\n\n# Per sstable indexed key cache entries (the collation index in memory\n# mentioned above) exceeding this size will not be held on heap.\n# This means that only partition information is held on heap and the\n# index entries are read from disk.\n#\n# Note that this size refers to the size of the\n# serialized index information and not the size of the partition.\ncolumn_index_cache_size_in_kb: 2\n\n# Number of simultaneous compactions to allow, NOT including\n# validation \"compactions\" for anti-entropy repair.  Simultaneous\n# compactions can help preserve read performance in a mixed read/write\n# workload, by mitigating the tendency of small sstables to accumulate\n# during a single long running compactions. The default is usually\n# fine and if you experience problems with compaction running too\n# slowly or too fast, you should look at\n# compaction_throughput_mb_per_sec first.\n#\n# concurrent_compactors defaults to the smaller of (number of disks,\n# number of cores), with a minimum of 2 and a maximum of 8.\n# \n# If your data directories are backed by SSD, you should increase this\n# to the number of cores.\n#concurrent_compactors: 1\n\n# Throttles compaction to the given total throughput across the entire\n# system. The faster you insert data, the faster you need to compact in\n# order to keep the sstable count down, but in general, setting this to\n# 16 to 32 times the rate you are inserting data is more than sufficient.\n# Setting this to 0 disables throttling. Note that this account for all types\n# of compaction, including validation compaction.\ncompaction_throughput_mb_per_sec: 16\n\n# When compacting, the replacement sstable(s) can be opened before they\n# are completely written, and used in place of the prior sstables for\n# any range that has been written. This helps to smoothly transfer reads \n# between the sstables, reducing page cache churn and keeping hot rows hot\nsstable_preemptive_open_interval_in_mb: 50\n\n# Throttles all outbound streaming file transfers on this node to the\n# given total throughput in Mbps. This is necessary because Cassandra does\n# mostly sequential IO when streaming data during bootstrap or repair, which\n# can lead to saturating the network connection and degrading rpc performance.\n# When unset, the default is 200 Mbps or 25 MB/s.\n# stream_throughput_outbound_megabits_per_sec: 200\n\n# Throttles all streaming file transfer between the datacenters,\n# this setting allows users to throttle inter dc stream throughput in addition\n# to throttling all network stream traffic as configured with\n# stream_throughput_outbound_megabits_per_sec\n# When unset, the default is 200 Mbps or 25 MB/s\n# inter_dc_stream_throughput_outbound_megabits_per_sec: 200\n\n# How long the coordinator should wait for read operations to complete\nread_request_timeout_in_ms: 5000\n# How long the coordinator should wait for seq or index scans to complete\nrange_request_timeout_in_ms: 10000\n# How long the coordinator should wait for writes to complete\nwrite_request_timeout_in_ms: 2000\n# How long the coordinator should wait for counter writes to complete\ncounter_write_request_timeout_in_ms: 5000\n# How long a coordinator should continue to retry a CAS operation\n# that contends with other proposals for the same row\ncas_contention_timeout_in_ms: 1000\n# How long the coordinator should wait for truncates to complete\n# (This can be much longer, because unless auto_snapshot is disabled\n# we need to flush first so we can snapshot before removing the data.)\ntruncate_request_timeout_in_ms: 60000\n# The default timeout for other, miscellaneous operations\nrequest_timeout_in_ms: 10000\n\n# How long before a node logs slow queries. Select queries that take longer than\n# this timeout to execute, will generate an aggregated log message, so that slow queries\n# can be identified. Set this value to zero to disable slow query logging.\nslow_query_log_timeout_in_ms: 500\n\n# Enable operation timeout information exchange between nodes to accurately\n# measure request timeouts.  If disabled, replicas will assume that requests\n# were forwarded to them instantly by the coordinator, which means that\n# under overload conditions we will waste that much extra time processing \n# already-timed-out requests.\n#\n# Warning: before enabling this property make sure to ntp is installed\n# and the times are synchronized between the nodes.\ncross_node_timeout: false\n\n# Set keep-alive period for streaming\n# This node will send a keep-alive message periodically with this period.\n# If the node does not receive a keep-alive message from the peer for\n# 2 keep-alive cycles the stream session times out and fail\n# Default value is 300s (5 minutes), which means stalled stream\n# times out in 10 minutes by default\n# streaming_keep_alive_period_in_secs: 300\n\n# phi value that must be reached for a host to be marked down.\n# most users should never need to adjust this.\n# phi_convict_threshold: 8\n\n# endpoint_snitch -- Set this to a class that implements\n# IEndpointSnitch.  The snitch has two functions:\n#\n# - it teaches Cassandra enough about your network topology to route\n#   requests efficiently\n# - it allows Cassandra to spread replicas around your cluster to avoid\n#   correlated failures. It does this by grouping machines into\n#   \"datacenters\" and \"racks.\"  Cassandra will do its best not to have\n#   more than one replica on the same \"rack\" (which may not actually\n#   be a physical location)\n#\n# CASSANDRA WILL NOT ALLOW YOU TO SWITCH TO AN INCOMPATIBLE SNITCH\n# ONCE DATA IS INSERTED INTO THE CLUSTER.  This would cause data loss.\n# This means that if you start with the default SimpleSnitch, which\n# locates every node on \"rack1\" in \"datacenter1\", your only options\n# if you need to add another datacenter are GossipingPropertyFileSnitch\n# (and the older PFS).  From there, if you want to migrate to an\n# incompatible snitch like Ec2Snitch you can do it by adding new nodes\n# under Ec2Snitch (which will locate them in a new \"datacenter\") and\n# decommissioning the old ones.\n#\n# Out of the box, Cassandra provides:\n#\n# SimpleSnitch:\n#    Treats Strategy order as proximity. This can improve cache\n#    locality when disabling read repair.  Only appropriate for\n#    single-datacenter deployments.\n#\n# GossipingPropertyFileSnitch\n#    This should be your go-to snitch for production use.  The rack\n#    and datacenter for the local node are defined in\n#    cassandra-rackdc.properties and propagated to other nodes via\n#    gossip.  If cassandra-topology.properties exists, it is used as a\n#    fallback, allowing migration from the PropertyFileSnitch.\n#\n# PropertyFileSnitch:\n#    Proximity is determined by rack and data center, which are\n#    explicitly configured in cassandra-topology.properties.\n#\n# Ec2Snitch:\n#    Appropriate for EC2 deployments in a single Region. Loads Region\n#    and Availability Zone information from the EC2 API. The Region is\n#    treated as the datacenter, and the Availability Zone as the rack.\n#    Only private IPs are used, so this will not work across multiple\n#    Regions.\n#\n# Ec2MultiRegionSnitch:\n#    Uses public IPs as broadcast_address to allow cross-region\n#    connectivity.  (Thus, you should set seed addresses to the public\n#    IP as well.) You will need to open the storage_port or\n#    ssl_storage_port on the public IP firewall.  (For intra-Region\n#    traffic, Cassandra will switch to the private IP after\n#    establishing a connection.)\n#\n# RackInferringSnitch:\n#    Proximity is determined by rack and data center, which are\n#    assumed to correspond to the 3rd and 2nd octet of each node's IP\n#    address, respectively.  Unless this happens to match your\n#    deployment conventions, this is best used as an example of\n#    writing a custom Snitch class and is provided in that spirit.\n#\n# You can use a custom Snitch by setting this to the full class name\n# of the snitch, which will be assumed to be on your classpath.\nendpoint_snitch: SimpleSnitch\n\n# controls how often to perform the more expensive part of host score\n# calculation\ndynamic_snitch_update_interval_in_ms: 100 \n# controls how often to reset all host scores, allowing a bad host to\n# possibly recover\ndynamic_snitch_reset_interval_in_ms: 600000\n# if set greater than zero and read_repair_chance is < 1.0, this will allow\n# 'pinning' of replicas to hosts in order to increase cache capacity.\n# The badness threshold will control how much worse the pinned host has to be\n# before the dynamic snitch will prefer other replicas over it.  This is\n# expressed as a double which represents a percentage.  Thus, a value of\n# 0.2 means Cassandra would continue to prefer the static snitch values\n# until the pinned host was 20% worse than the fastest.\ndynamic_snitch_badness_threshold: 0.1\n\n# request_scheduler -- Set this to a class that implements\n# RequestScheduler, which will schedule incoming client requests\n# according to the specific policy. This is useful for multi-tenancy\n# with a single Cassandra cluster.\n# NOTE: This is specifically for requests from the client and does\n# not affect inter node communication.\n# org.apache.cassandra.scheduler.NoScheduler - No scheduling takes place\n# org.apache.cassandra.scheduler.RoundRobinScheduler - Round robin of\n# client requests to a node with a separate queue for each\n# request_scheduler_id. The scheduler is further customized by\n# request_scheduler_options as described below.\nrequest_scheduler: org.apache.cassandra.scheduler.NoScheduler\n\n# Scheduler Options vary based on the type of scheduler\n#\n# NoScheduler\n#   Has no options\n#\n# RoundRobin\n#   throttle_limit\n#     The throttle_limit is the number of in-flight\n#     requests per client.  Requests beyond \n#     that limit are queued up until\n#     running requests can complete.\n#     The value of 80 here is twice the number of\n#     concurrent_reads + concurrent_writes.\n#   default_weight\n#     default_weight is optional and allows for\n#     overriding the default which is 1.\n#   weights\n#     Weights are optional and will default to 1 or the\n#     overridden default_weight. The weight translates into how\n#     many requests are handled during each turn of the\n#     RoundRobin, based on the scheduler id.\n#\n# request_scheduler_options:\n#    throttle_limit: 80\n#    default_weight: 5\n#    weights:\n#      Keyspace1: 1\n#      Keyspace2: 5\n\n# request_scheduler_id -- An identifier based on which to perform\n# the request scheduling. Currently the only valid option is keyspace.\n# request_scheduler_id: keyspace\n\n# Enable or disable inter-node encryption\n# JVM defaults for supported SSL socket protocols and cipher suites can\n# be replaced using custom encryption options. This is not recommended\n# unless you have policies in place that dictate certain settings, or\n# need to disable vulnerable ciphers or protocols in case the JVM cannot\n# be updated.\n# FIPS compliant settings can be configured at JVM level and should not\n# involve changing encryption settings here:\n# https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/FIPS.html\n# *NOTE* No custom encryption options are enabled at the moment\n# The available internode options are : all, none, dc, rack\n#\n# If set to dc cassandra will encrypt the traffic between the DCs\n# If set to rack cassandra will encrypt the traffic between the racks\n#\n# The passwords used in these options must match the passwords used when generating\n# the keystore and truststore.  For instructions on generating these files, see:\n# https://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CreateKeystore\n#\nserver_encryption_options:\n    internode_encryption: none\n    keystore: conf/.keystore\n    keystore_password: cassandra\n    truststore: conf/.truststore\n    truststore_password: cassandra\n    # More advanced defaults below:\n    # protocol: TLS\n    # algorithm: SunX509\n    # store_type: JKS\n    # cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]\n    # require_client_auth: false\n    # require_endpoint_verification: false\n\n# enable or disable client/server encryption.\nclient_encryption_options:\n    enabled: true\n    optional: false\n    keystore: /etc/cassandra/server.p12\n    keystore_password: \"password\"\n    require_client_auth: true\n    truststore: /etc/cassandra/truststore.p12\n    truststore_password: \"password\"\n    store_type: PKCS12\n    # More advanced defaults below:\n    # protocol: TLS\n    # algorithm: SunX509\n    # cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]\n\n# internode_compression controls whether traffic between nodes is\n# compressed.\n# Can be:\n#\n# all\n#   all traffic is compressed\n#\n# dc\n#   traffic between different datacenters is compressed\n#\n# none\n#   nothing is compressed.\ninternode_compression: dc\n\n# Enable or disable tcp_nodelay for inter-dc communication.\n# Disabling it will result in larger (but fewer) network packets being sent,\n# reducing overhead from the TCP protocol itself, at the cost of increasing\n# latency if you block for cross-datacenter responses.\ninter_dc_tcp_nodelay: false\n\n# TTL for different trace types used during logging of the repair process.\ntracetype_query_ttl: 86400\ntracetype_repair_ttl: 604800\n\n# By default, Cassandra logs GC Pauses greater than 200 ms at INFO level\n# This threshold can be adjusted to minimize logging if necessary\n# gc_log_threshold_in_ms: 200\n\n# If unset, all GC Pauses greater than gc_log_threshold_in_ms will log at\n# INFO level\n# UDFs (user defined functions) are disabled by default.\n# As of Cassandra 3.0 there is a sandbox in place that should prevent execution of evil code.\nenable_user_defined_functions: false\n\n# Enables scripted UDFs (JavaScript UDFs).\n# Java UDFs are always enabled, if enable_user_defined_functions is true.\n# Enable this option to be able to use UDFs with \"language javascript\" or any custom JSR-223 provider.\n# This option has no effect, if enable_user_defined_functions is false.\nenable_scripted_user_defined_functions: false\n\n# The default Windows kernel timer and scheduling resolution is 15.6ms for power conservation.\n# Lowering this value on Windows can provide much tighter latency and better throughput, however\n# some virtualized environments may see a negative performance impact from changing this setting\n# below their system default. The sysinternals 'clockres' tool can confirm your system's default\n# setting.\nwindows_timer_interval: 1\n\n\n# Enables encrypting data at-rest (on disk). Different key providers can be plugged in, but the default reads from\n# a JCE-style keystore. A single keystore can hold multiple keys, but the one referenced by\n# the \"key_alias\" is the only key that will be used for encrypt opertaions; previously used keys\n# can still (and should!) be in the keystore and will be used on decrypt operations\n# (to handle the case of key rotation).\n#\n# It is strongly recommended to download and install Java Cryptography Extension (JCE)\n# Unlimited Strength Jurisdiction Policy Files for your version of the JDK.\n# (current link: https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html)\n#\n# Currently, only the following file types are supported for transparent data encryption, although\n# more are coming in future cassandra releases: commitlog, hints\ntransparent_data_encryption_options:\n    enabled: false\n    chunk_length_kb: 64\n    cipher: AES/CBC/PKCS5Padding\n    key_alias: testing:1\n    # CBC IV length for AES needs to be 16 bytes (which is also the default size)\n    # iv_length: 16\n    key_provider: \n      - class_name: org.apache.cassandra.security.JKSKeyProvider\n        parameters: \n          - keystore: conf/.keystore\n            keystore_password: cassandra\n            store_type: JCEKS\n            key_password: cassandra\n\n\n#####################\n# SAFETY THRESHOLDS #\n#####################\n\n# When executing a scan, within or across a partition, we need to keep the\n# tombstones seen in memory so we can return them to the coordinator, which\n# will use them to make sure other replicas also know about the deleted rows.\n# With workloads that generate a lot of tombstones, this can cause performance\n# problems and even exaust the server heap.\n# (https://www.datastax.com/dev/blog/cassandra-anti-patterns-queues-and-queue-like-datasets)\n# Adjust the thresholds here if you understand the dangers and want to\n# scan more tombstones anyway.  These thresholds may also be adjusted at runtime\n# using the StorageService mbean.\ntombstone_warn_threshold: 1000\ntombstone_failure_threshold: 100000\n\n# Filtering and secondary index queries at read consistency levels above ONE/LOCAL_ONE use a\n# mechanism called replica filtering protection to ensure that results from stale replicas do\n# not violate consistency. (See CASSANDRA-8272 and CASSANDRA-15907 for more details.) This\n# mechanism materializes replica results by partition on-heap at the coordinator. The more possibly\n# stale results returned by the replicas, the more rows materialized during the query.\n# replica_filtering_protection:\n    # These thresholds exist to limit the damage severely out-of-date replicas can cause during these\n    # queries. They limit the number of rows from all replicas individual index and filtering queries\n    # can materialize on-heap to return correct results at the desired read consistency level.\n    #\n    # \"cached_replica_rows_warn_threshold\" is the per-query threshold at which a warning will be logged.\n    # \"cached_replica_rows_fail_threshold\" is the per-query threshold at which the query will fail.\n    #\n    # These thresholds may also be adjusted at runtime using the StorageService mbean.\n    #\n    # If the failure threshold is breached, it is likely that either the current page/fetch size\n    # is too large or one or more replicas is severely out-of-sync and in need of repair.\n    # cached_rows_warn_threshold: 2000\n    # cached_rows_fail_threshold: 32000\n\n# Log WARN on any multiple-partition batch size exceeding this value. 5kb per batch by default.\n# Caution should be taken on increasing the size of this threshold as it can lead to node instability.\nbatch_size_warn_threshold_in_kb: 5\n\n# Fail any multiple-partition batch exceeding this value. 50kb (10x warn threshold) by default.\nbatch_size_fail_threshold_in_kb: 50\n\n# Log WARN on any batches not of type LOGGED than span across more partitions than this limit\nunlogged_batch_across_partitions_warn_threshold: 10\n\n# Log a warning when compacting partitions larger than this value\ncompaction_large_partition_warning_threshold_mb: 100\n\n# GC Pauses greater than gc_warn_threshold_in_ms will be logged at WARN level\n# Adjust the threshold based on your application throughput requirement\n# By default, Cassandra logs GC Pauses greater than 200 ms at INFO level\ngc_warn_threshold_in_ms: 1000\n\n# Maximum size of any value in SSTables. Safety measure to detect SSTable corruption\n# early. Any value size larger than this threshold will result into marking an SSTable\n# as corrupted. This should be positive and less than 2048.\n# max_value_size_in_mb: 256\n\n# Back-pressure settings #\n# If enabled, the coordinator will apply the back-pressure strategy specified below to each mutation\n# sent to replicas, with the aim of reducing pressure on overloaded replicas.\nback_pressure_enabled: false\n# The back-pressure strategy applied.\n# The default implementation, RateBasedBackPressure, takes three arguments:\n# high ratio, factor, and flow type, and uses the ratio between incoming mutation responses and outgoing mutation requests.\n# If below high ratio, outgoing mutations are rate limited according to the incoming rate decreased by the given factor;\n# if above high ratio, the rate limiting is increased by the given factor;\n# such factor is usually best configured between 1 and 10, use larger values for a faster recovery\n# at the expense of potentially more dropped mutations;\n# the rate limiting is applied according to the flow type: if FAST, it's rate limited at the speed of the fastest replica,\n# if SLOW at the speed of the slowest one.\n# New strategies can be added. Implementors need to implement org.apache.cassandra.net.BackpressureStrategy and\n# provide a public constructor accepting a Map<String, Object>.\nback_pressure_strategy:\n    - class_name: org.apache.cassandra.net.RateBasedBackPressure\n      parameters:\n        - high_ratio: 0.90\n          factor: 5\n          flow: FAST\n\n# Coalescing Strategies #\n# Coalescing multiples messages turns out to significantly boost message processing throughput (think doubling or more).\n# On bare metal, the floor for packet processing throughput is high enough that many applications won't notice, but in\n# virtualized environments, the point at which an application can be bound by network packet processing can be\n# surprisingly low compared to the throughput of task processing that is possible inside a VM. It's not that bare metal\n# doesn't benefit from coalescing messages, it's that the number of packets a bare metal network interface can process\n# is sufficient for many applications such that no load starvation is experienced even without coalescing.\n# There are other benefits to coalescing network messages that are harder to isolate with a simple metric like messages\n# per second. By coalescing multiple tasks together, a network thread can process multiple messages for the cost of one\n# trip to read from a socket, and all the task submission work can be done at the same time reducing context switching\n# and increasing cache friendliness of network message processing.\n# See CASSANDRA-8692 for details.\n\n# Strategy to use for coalescing messages in OutboundTcpConnection.\n# Can be fixed, movingaverage, timehorizon, disabled (default).\n# You can also specify a subclass of CoalescingStrategies.CoalescingStrategy by name.\n# otc_coalescing_strategy: DISABLED\n\n# How many microseconds to wait for coalescing. For fixed strategy this is the amount of time after the first\n# message is received before it will be sent with any accompanying messages. For moving average this is the\n# maximum amount of time that will be waited as well as the interval at which messages must arrive on average\n# for coalescing to be enabled.\n# otc_coalescing_window_us: 200\n\n# Do not try to coalesce messages if we already got that many messages. This should be more than 2 and less than 128.\n# otc_coalescing_enough_coalesced_messages: 8\n\n# How many milliseconds to wait between two expiration runs on the backlog (queue) of the OutboundTcpConnection.\n# Expiration is done if messages are piling up in the backlog. Droppable messages are expired to free the memory\n# taken by expired messages. The interval should be between 0 and 1000, and in most installations the default value\n# will be appropriate. A smaller value could potentially expire messages slightly sooner at the expense of more CPU\n# time and queue contention while iterating the backlog of messages.\n# An interval of 0 disables any wait time, which is the behavior of former Cassandra versions.\n#\n# otc_backlog_expiration_interval_ms: 200\n\n\n#########################\n# EXPERIMENTAL FEATURES #\n#########################\n\n# Enables materialized view creation on this node.\n# Materialized views are considered experimental and are not recommended for production use.\n# enable_materialized_views: true\n\n# Enables SASI index creation on this node.\n# SASI indexes are considered experimental and are not recommended for production use.\n# enable_sasi_indexes: true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/main/java/smoketest/data/cassandra/SampleDataCassandraApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataCassandraApplication {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/main/java/smoketest/data/cassandra/SampleEntity.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.cassandra.core.mapping.PrimaryKey;\nimport org.springframework.data.cassandra.core.mapping.Table;\n\n@Table\npublic class SampleEntity {\n\n\t@PrimaryKey\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String description;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(@Nullable String description) {\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/main/java/smoketest/data/cassandra/SampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport org.springframework.data.cassandra.repository.CassandraRepository;\n\ninterface SampleRepository extends CassandraRepository<SampleEntity, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/main/java/smoketest/data/cassandra/SampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.cassandra;\n\nimport org.springframework.data.cassandra.core.CassandraTemplate;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class SampleService {\n\n\tprivate final CassandraTemplate cassandraTemplate;\n\n\tpublic SampleService(CassandraTemplate cassandraTemplate) {\n\t\tthis.cassandraTemplate = cassandraTemplate;\n\t}\n\n\tpublic boolean hasRecord(SampleEntity entity) {\n\t\tString id = entity.getId();\n\t\tif (id == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.cassandraTemplate.exists(id, SampleEntity.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-cassandra/src/main/java/smoketest/data/cassandra/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.cassandra;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data Couchbase smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-couchbase\"))\n\timplementation(project(\":starter:spring-boot-starter-data-couchbase-reactive\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-couchbase-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-couchbase-reactive-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-couchbase\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/dockerTest/java/smoketest/data/couchbase/SampleDataCouchbaseApplicationReactiveSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Couchbase using reactive repositories with SSL.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\n@SpringBootTest(properties = { \"spring.data.couchbase.bucket-name=cbbucket\" })\nclass SampleDataCouchbaseApplicationReactiveSslTests {\n\n\tprivate static final String BUCKET_NAME = \"cbbucket\";\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(certificate = \"classpath:ssl/test-ca.crt\")\n\tstatic final CouchbaseContainer couchbase = TestImage.container(SecureCouchbaseContainer.class)\n\t\t.withBucket(new BucketDefinition(BUCKET_NAME));\n\n\t@Autowired\n\tprivate ReactiveCouchbaseTemplate couchbaseTemplate;\n\n\t@Autowired\n\tprivate SampleReactiveRepository repository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataCouchbaseTest!\");\n\t\tdocument = this.repository.save(document).block(Duration.ofSeconds(30));\n\t\tassertThat(document).isNotNull();\n\t\tassertThat(document.getId()).isNotNull();\n\t\tassertThat(this.couchbaseTemplate.getBucketName()).isEqualTo(BUCKET_NAME);\n\t\tthis.repository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/dockerTest/java/smoketest/data/couchbase/SampleDataCouchbaseApplicationSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.couchbase.BucketDefinition;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.couchbase.test.autoconfigure.DataCouchbaseTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Couchbase with SSL.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataCouchbaseTest(\n\t\tproperties = { \"spring.couchbase.env.timeouts.connect=2m\", \"spring.data.couchbase.bucket-name=cbbucket\" })\nclass SampleDataCouchbaseApplicationSslTests {\n\n\tprivate static final String BUCKET_NAME = \"cbbucket\";\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(certificate = \"classpath:ssl/test-ca.crt\")\n\tstatic final CouchbaseContainer couchbase = TestImage.container(SecureCouchbaseContainer.class)\n\t\t.withBucket(new BucketDefinition(BUCKET_NAME));\n\n\t@Autowired\n\tprivate CouchbaseTemplate couchbaseTemplate;\n\n\t@Autowired\n\tprivate SampleRepository repository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataCouchbaseTest!\");\n\t\tdocument = this.repository.save(document);\n\t\tassertThat(document.getId()).isNotNull();\n\t\tassertThat(this.couchbaseTemplate.getBucketName()).isEqualTo(BUCKET_NAME);\n\t\tthis.repository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/dockerTest/java/smoketest/data/couchbase/SecureCouchbaseContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport java.util.Base64;\n\nimport com.github.dockerjava.api.command.InspectContainerResponse;\nimport org.apache.hc.client5.http.impl.classic.CloseableHttpClient;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.core5.http.ClassicHttpRequest;\nimport org.apache.hc.core5.http.HttpResponse;\nimport org.apache.hc.core5.http.io.support.ClassicRequestBuilder;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link CouchbaseContainer} for Couchbase with SSL configuration.\n *\n * @author Scott Frederick\n * @author Stephane Nicoll\n */\npublic class SecureCouchbaseContainer extends CouchbaseContainer {\n\n\tprivate static final int MANAGEMENT_PORT = 8091;\n\n\tprivate static final int KV_SSL_PORT = 11207;\n\n\tprivate static final String ADMIN_USER = \"Administrator\";\n\n\tprivate static final String ADMIN_PASSWORD = \"password\";\n\n\tpublic SecureCouchbaseContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.crt\"),\n\t\t\t\t\"/opt/couchbase/var/lib/couchbase/inbox/chain.pem\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.key\"),\n\t\t\t\t\"/opt/couchbase/var/lib/couchbase/inbox/pkey.key\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-ca.crt\"),\n\t\t\t\t\"/opt/couchbase/var/lib/couchbase/inbox/CA/ca.pem\");\n\t}\n\n\t@Override\n\tpublic String getConnectionString() {\n\t\treturn \"couchbase://%s:%d\".formatted(getHost(), getMappedPort(KV_SSL_PORT));\n\t}\n\n\t@Override\n\tprotected void containerIsStarting(InspectContainerResponse containerInfo) {\n\t\tsuper.containerIsStarting(containerInfo);\n\t\tdoHttpRequest(\"node/controller/loadTrustedCAs\");\n\t\tdoHttpRequest(\"node/controller/reloadCertificate\");\n\t}\n\n\tprivate void doHttpRequest(String path) {\n\t\tHttpResponse response = post(path);\n\t\tif (response.getCode() != 200) {\n\t\t\tthrow new IllegalStateException(\"Error calling Couchbase HTTP endpoint: \" + response);\n\t\t}\n\t}\n\n\tprivate HttpResponse post(String path) {\n\t\ttry (CloseableHttpClient httpclient = HttpClients.createDefault()) {\n\t\t\tString basicAuth = \"Basic \"\n\t\t\t\t\t+ Base64.getEncoder().encodeToString(\"%s:%s\".formatted(ADMIN_USER, ADMIN_PASSWORD).getBytes());\n\t\t\tString url = \"http://%s:%d/%s\".formatted(getHost(), getMappedPort(MANAGEMENT_PORT), path);\n\t\t\tClassicHttpRequest httpPost = ClassicRequestBuilder.post(url)\n\t\t\t\t.addHeader(\"Authorization\", basicAuth)\n\t\t\t\t.setEntity(\"\")\n\t\t\t\t.build();\n\t\t\treturn httpclient.execute(httpPost, (response) -> response);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Error calling Couchbase HTTP endpoint\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleDataCouchbaseApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataCouchbaseApplication {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleDocument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.couchbase.core.mapping.Document;\nimport org.springframework.data.couchbase.core.mapping.id.GeneratedValue;\nimport org.springframework.data.couchbase.core.mapping.id.GenerationStrategy;\n\n@Document\npublic class SampleDocument {\n\n\t@Id\n\t@GeneratedValue(strategy = GenerationStrategy.UNIQUE)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String id;\n\n\tprivate @Nullable String text;\n\n\tpublic String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleReactiveRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository;\n\ninterface SampleReactiveRepository extends ReactiveCouchbaseRepository<SampleDocument, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport org.springframework.data.couchbase.repository.CouchbaseRepository;\n\ninterface SampleRepository extends CouchbaseRepository<SampleDocument, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.couchbase;\n\nimport org.springframework.data.couchbase.core.CouchbaseTemplate;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class SampleService {\n\n\tprivate final CouchbaseTemplate couchbaseTemplate;\n\n\tpublic SampleService(CouchbaseTemplate couchbaseTemplate) {\n\t\tthis.couchbaseTemplate = couchbaseTemplate;\n\t}\n\n\tpublic SampleDocument findById(String id) {\n\t\treturn this.couchbaseTemplate.findById(SampleDocument.class).one(id);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.couchbase;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/test/resources/ssl/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/test/resources/ssl/test-ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6w3YrNBBRTFlK\nIjdlm5miEXCrYpdJQ090nquAPf9go1MNJlcpk87neRg8/QNd/SybcIdzJZJZVpvK\nKZli49Z6drUwSVIvhmkn1bCRmg5Dds8UrW63PqQw7CuABRyTLwf+sgqPYkQGGRId\nQgavns2NQTAbXKBpJ6szxHNbDU+0yr4Lws67e/3irMTc0ODVBGnK9X06awuyMhJ3\nRmYAk2L2+aIQf3bcqc/KKqdCZYqliJx2BCZfUZfKVLbaNmoDBo6RgaNfxR17K+ui\nGRmQzSGf25pK59AYRbjIoAKfc+SMm3OLx2sEjKMiL1hwDMHFkH2hUqpdkyWW2A7Z\n8MyYgmLQ2C3QKLt8KgQypKhwrIMowvpguv1Ra3Hht+yuT6tU71D8P+/xEqCy2/t0\nJ/YpZFfdkkQLQgEdLmAs2rSqqpVwbHctxLKF2Iok61LACc2QcyH6NJDEtKUGNxKp\nM+IZNEr9F12X7GdT+YGCTtkEY2tQVoPkxwwWN11LsiHzZoeelDWB6RadQa/5Ob8b\nryHYG9nlTar5F944KBFb2L8BhbaOBPsgWd+PJReAFC95q4wByGiaoURUt73lmBWI\nXq+YffgQqjfD0vlNCLCT+vndiUztNI5PIOrHrq3jMZgOxUyJykqbOLjZGnwSkSsB\nFHJERQgpK9az07365Pf7tqs0uAd7kQIDAQABAoICAAthB10ggfICHdqXdRqavWST\nfXLjweXz1O59EGPy4xFnQhMmB99/ovaVeTWWENN0LniWBZqtalpJHZrWqALPcOzr\nOKTlgr1kihmkOmrUoRPZNErFOl6t0WEtsoTNSu1oyyrofB46VXytoF3p/PBMU6fM\nlfrEzP07LoIr8P9WM0oHpEahKulfZ5uc/S2bCGfSKgP0qxmZFhBYXqmnv2U/laMI\nmKg6q+pL6l4d9SzldOobBbVnEVNzbDUmrjFjaVgf2SXiaSrXnrE3ftbUgqtA5FCS\nF7eCojooXVbT8PT4Ia+zdPnKP6n6S6I0kkXZcSDxacYffEPRSFQFe/opYr3UC+Mk\n1/UmOnoI8X8+N9SPcVD9cbVQUzBuuXfTy+LMx9mg3QxFebRSRre22xSOSlM7MF9B\n6MPeNgwCk3Z0NTr+IedGfyA+d6+iHTMGnv0hF4b4UkcXbC3HdeR3K4hf+msGD2oG\n7JF423T/d7t+g883y4CZm7p096apR8cCLIe2HKSwcYbKhft7LkAdm8kpnqkr5ER1\nanI7RDmucrx3HgrXeuCz9Uai6EMU6jNU1MAEBVeu4jz1rlO4e9zS2Ak68AwIz0zI\ntl5el3paHjlRYY6YTslM5qjGerJt19IyHvZxXXIzF7JdF7w1nSK9bjvninALJl49\nYZAPRIbyQ8P6DLqiDNBFAoIBAQDvQoow86vNg6zHdb8eBC10l2Y6M5DAKTWPE8RJ\nn0td1TLwEHzKvkR25v6yGKABbBO1+7ABACCqA8rkcB7M5jugak/kR9vuDrFPAsqf\nlgckf1Up7ekDheTH8X1VSDiRZPv07UElO0M3aFeMVR/xi9Wae8C3WZo9dT2wKnM0\nd0Acr4Kt4SYm1Dw7kuh+Y1L/vvWuryPm1btxhfKO6JN5v2W8DTrqVkxuxYEM1VnR\n69LfauLVico2q8EGXmQTth/Iok5wj1qI6kmrlgQR+eSY1qgNk1qzwjJVsbSmAOL8\n6Y9Ksct53bEN6DIdYRE/SrEVCz/FY1Pry2DNTjdiwImaSOZ3AoIBAQDH1KRkqsET\nYUnPJxp9pHWlynicEVE/Y7FFhhtpUKzhY1nZ+NsNy91FrZiyx5Os7pSxhLNID8g5\nxKCOfYd7qdvZCg/5bMXhtagQ3gwa/wyuyamc29dKkCpHDz/GkoEkgVe6eYu1GNdR\niNpY5ye5T9fBE1s3odbDcnRVeHAP7vqz5z17JKrlqZVhbLYlR4qGHmAogq7vWlyd\nIR5qLoXMgyqq5OHl1GaaiqfViBpJeoEWYze0cARUWOcrJRblJYS03WHMuLDG5RZd\n5nmf2xwEcMgW5AX7+GB8CdXRVZy6OZcGn7TU9+xnBJA2LbzxJlHBXjWEd8Uma2Al\n+ohlDbGrd8g3AoIBAHsWzGlqstREDbt/xBb5Jzl4OktvA+UYTkmRbcZCgU+Aw3fl\nw426XRaeuCF/sbGJnIpfNakOG7/bu6HSXMYlHD/m8bsLjQXn4Sg4021OjdYk+/da\nQiph09VZU5VwVknWnhjfhkhVOLtknsW/dXOa8QVM7VRmcId1rYrYC/TN9NnNIXm6\n/xmyzloHtjxvdN/Fqjd4OwwioRBCTQtgc56K7RfV5p1wUFocmcu0Z0UsAYyXPKOH\nA9Ukf2V7YhkR9UAO4DPgTD9r6QKxZt6opQZMSKDTUjJwkdysU7ejdSOQNPvEhF3p\nw5DYCBA9Q9Y/4uJkqyYtd5szQlXdC3lufFw3bPkCggEBAKPA3GpmB0xjWEG6UJoP\nUB1pWwbBpivk/Rr097eI1fLpIHNf29plalE0HcK7i4eWByGllekCjdjRCaVattCe\n9DraZRbHjS0WWMBhxdfFk9YUCbsx6C4BD7QlieSmn8+TcpmsCtF/psr4870Qx9uy\n0yI0Q3bGV6DYRP7ZcDOOacFNSHOGK8mB+5jXpjfMdXbMo43u8X3RNb3JqwvmTdy2\nzBs47ukQ8nfIEhsIqkn2apw2+CoT9WhNZjpT7XwgD6zLEd7apnqGtpqCSL63pjD5\nXu5rM4A1HJPo11/w4Ts2AE38SAqRlBcjhS3wszmGZk6obgC8yUFfkm3s7SKqYyMZ\nSGcCggEBAO0IDB/h1meZ2y+6bSsCVaDSxdRl0JF0CDUYVTANQsJ+q7u7CpF9xOo8\nYNrSy8eM0K6RMY/3WbTm+4z9tOldxEV2dn+29oVeMKkgpJYo0k2Au3wTMI2xMyyl\nHZ+ZttsqSZsj2CPx83LMaPwKdzVjwA7alVx4P+AkQKn7jGJgidj5xyw0G3gnzdfT\nnGzuitQFlcrcPyrVHAAmRhIw+B5CsvMFlM8PAvojN7burGswjWGeZjkgqoLvKlgq\njRMGzLTzF9Pay7P/D/pWQwPVGiseJq+QVIA+iILpy9Zb9T6DnBFaPFGOKAduzVU9\nlTLiho2DATppaxNUQKh/5k70hzbipDg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/test/resources/ssl/test-client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/test/resources/ssl/test-client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/test/resources/ssl/test-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-couchbase/src/test/resources/ssl/test-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.conventions\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data Elasticsearch smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-elasticsearch\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-elasticsearch-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-elasticsearch\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/java/smoketest/data/elasticsearch/SampleDataElasticsearchApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Elasticsearch.\n *\n * @author Moritz Halbritter\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataElasticsearchTest\nclass SampleDataElasticsearchApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final ElasticsearchContainer elasticSearch = TestImage.container(ElasticsearchContainer.class);\n\n\t@Autowired\n\tprivate ElasticsearchTemplate elasticsearchTemplate;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tSampleDocument savedDocument = this.exampleRepository.save(document);\n\t\tSampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);\n\t\tassertThat(getDocument).isNotNull();\n\t\tassertThat(getDocument.getId()).isNotNull();\n\t\tassertThat(getDocument.getId()).isEqualTo(savedDocument.getId());\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/java/smoketest/data/elasticsearch/SampleDataElasticsearchSslApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Elasticsearch with SSL.\n *\n * @author Moritz Halbritter\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataElasticsearchTest(\n\t\tproperties = { \"spring.elasticsearch.connection-timeout=120s\", \"spring.elasticsearch.socket-timeout=120s\" })\nclass SampleDataElasticsearchSslApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@PemTrustStore(certificate = \"classpath:ssl.crt\")\n\tstatic final ElasticsearchContainer elasticSearch = TestImage.container(SecureElasticsearchContainer.class);\n\n\t@Autowired\n\tprivate ElasticsearchTemplate elasticsearchTemplate;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tSampleDocument savedDocument = this.exampleRepository.save(document);\n\t\tSampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);\n\t\tassertThat(getDocument).isNotNull();\n\t\tassertThat(getDocument.getId()).isNotNull();\n\t\tassertThat(getDocument.getId()).isEqualTo(savedDocument.getId());\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/java/smoketest/data/elasticsearch/SampleDataElasticsearchWithElasticsearch8ApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.Ssl;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Elasticsearch with Elasticsearch 8.\n *\n * @author Moritz Halbritter\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataElasticsearchTest\n@Disabled(\"Elasticsearch client v9 needs extra config with v8\")\nclass SampleDataElasticsearchWithElasticsearch8ApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@Ssl\n\tstatic final ElasticsearchContainer elasticSearch = new ElasticsearchContainer(TestImage.ELASTICSEARCH_8.toString())\n\t\t.withPassword(\"my-custom-password\");\n\n\t@Autowired\n\tprivate ElasticsearchTemplate elasticsearchTemplate;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tSampleDocument savedDocument = this.exampleRepository.save(document);\n\t\tSampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);\n\t\tassertThat(getDocument).isNotNull();\n\t\tassertThat(getDocument.getId()).isNotNull();\n\t\tassertThat(getDocument.getId()).isEqualTo(savedDocument.getId());\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/java/smoketest/data/elasticsearch/SampleDataElasticsearchWithElasticsearch9ApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.elasticsearch.test.autoconfigure.DataElasticsearchTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testcontainers.service.connection.Ssl;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data Elasticsearch with Elasticsearch 9.\n *\n * @author Moritz Halbritter\n * @author Stephane Nicoll\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataElasticsearchTest\nclass SampleDataElasticsearchWithElasticsearch9ApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@Ssl\n\tstatic final ElasticsearchContainer elasticSearch = new ElasticsearchContainer(TestImage.ELASTICSEARCH_9.toString())\n\t\t.withPassword(\"my-custom-password\");\n\n\t@Autowired\n\tprivate ElasticsearchTemplate elasticsearchTemplate;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tSampleDocument savedDocument = this.exampleRepository.save(document);\n\t\tSampleDocument getDocument = this.elasticsearchTemplate.get(id, SampleDocument.class);\n\t\tassertThat(getDocument).isNotNull();\n\t\tassertThat(getDocument.getId()).isNotNull();\n\t\tassertThat(getDocument.getId()).isEqualTo(savedDocument.getId());\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/java/smoketest/data/elasticsearch/SecureElasticsearchContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport java.util.Map;\n\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link ElasticsearchContainer} for Elasticsearch with SSL configuration.\n *\n * @author Moritz Halbritter\n */\nclass SecureElasticsearchContainer extends ElasticsearchContainer {\n\n\tSecureElasticsearchContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t}\n\n\t@Override\n\tpublic void configure() {\n\t\t// See\n\t\t// https://www.elastic.co/guide/en/elastic-stack-get-started/7.5/get-started-docker.html#get-started-docker-tls\n\t\twithEnv(Map.of(\"xpack.security.http.ssl.enabled\", \"true\", \"xpack.security.http.ssl.key\",\n\t\t\t\t\"/usr/share/elasticsearch/config/ssl.key\", \"xpack.security.http.ssl.certificate\",\n\t\t\t\t\"/usr/share/elasticsearch/config/ssl.crt\", \"xpack.security.transport.ssl.enabled\", \"true\",\n\t\t\t\t\"xpack.security.transport.ssl.verification_mode\", \"certificate\", \"xpack.security.transport.ssl.key\",\n\t\t\t\t\"/usr/share/elasticsearch/config/ssl.key\", \"xpack.security.transport.ssl.certificate\",\n\t\t\t\t\"/usr/share/elasticsearch/config/ssl.crt\"));\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl.crt\"),\n\t\t\t\t\"/usr/share/elasticsearch/config/ssl.crt\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl.key\"),\n\t\t\t\t\"/usr/share/elasticsearch/config/ssl.key\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/resources/ssl.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIICpjCCAY6gAwIBAgIUd1pIGeth3t+uXRwJqQgBkX6RqVwwDQYJKoZIhvcNAQEL\nBQAwDDEKMAgGA1UEAwwBKjAgFw0yNDA4MjMwOTI5MjBaGA8yMTI0MDgyMzA5Mjky\nMFowDDEKMAgGA1UEAwwBKjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAMvuy3afu6umnCgEBElfgboa2M1O7RWwuvA0OIWdEzxYYQmc9QUihd2l68pIu9jT\nhR+2CENL4iY2HNtELJ8kFSGgUGPGrsjLj/qqULG1/r2f18tPavMD7Hxo0AGA+yyX\nnECCfHGPJ7P88fWwoMfdp8Y4s/BW7QcC7vB9kQGjUOb4V/WUWI7c27Yxj6/nCPRr\nGkb5YkEvsw6TPeBfZbx7kjWaYtd8eKjVHf40lu0AhXGK+lFuaLrY9VYBYoiMRtIZ\n3/EKf2gKQiIIR7tN3DUa5zi6vYvQNaUaK14yomfyynUzGPbIcMq8V+c6j3gI7jqf\nITqaaBn5NIM0W7ox6hhr+UUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEApgal5rth\n5y94hnwgNt0/+PuVj5vwxUIi0WgV6b1GE+3033h+l57hKcIRem4l3xEQnAs3NyLK\nBnbBgnnUfSOgPZhiP8s3VHSvGeJda7z2IQhCBe+cUnx6UHs8wgN4Nh1rkbEUzBvZ\nxm98B/bcbTsiSnIRTHBvIYhySDuCmyYOZwH8HC6rct6U3PODmJ6OjtWC43kjO0jT\n4/T/1PBJnVnN0r1Xu/P+GNDgDnzifIYr5ofY0zGsOC1GhRWyqbiIfe5hgZ//q81U\n1tFbSlLNvoi3C4jf2Fj9lYo8Ylkxk7QE5dFbRmBDffCo2sD8g6wyZN3PhaIyckG5\nE0uZHTBFFpFKjQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/dockerTest/resources/ssl.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL7st2n7urppwo\nBARJX4G6GtjNTu0VsLrwNDiFnRM8WGEJnPUFIoXdpevKSLvY04UftghDS+ImNhzb\nRCyfJBUhoFBjxq7Iy4/6qlCxtf69n9fLT2rzA+x8aNABgPssl5xAgnxxjyez/PH1\nsKDH3afGOLPwVu0HAu7wfZEBo1Dm+Ff1lFiO3Nu2MY+v5wj0axpG+WJBL7MOkz3g\nX2W8e5I1mmLXfHio1R3+NJbtAIVxivpRbmi62PVWAWKIjEbSGd/xCn9oCkIiCEe7\nTdw1Guc4ur2L0DWlGiteMqJn8sp1Mxj2yHDKvFfnOo94CO46nyE6mmgZ+TSDNFu6\nMeoYa/lFAgMBAAECggEAHdNp/Ip2Fy/B7PRRcC3AumhMxxJBCIgVfyYUEi6b7pp6\nbr5+82ZOL9Ghf69NkfO1p6Km6LjDdZU6eTMqV4gecxGQUFdxnrpu71lTffpBLJih\nJgISgUJUpwlpSp8DnUz7NFAhRTaLtv5KoQVZLoITlKEcaA0+k2Txb0jeGWA6Z90t\nocHJb9MTeWU7SSaVttNshoJPj272CXExuOCSi+NziSiuCnZbKSZDQKDEe9+jMVhL\nOqvXYyp+FWoL60DuLb2BgKet5UcsVaYZNfETRY7vn5LThFpRJnOpZ6Um8JydP60+\n3gtuKpsZ8kVKcif4cawAfzpGobra9BBFOc6IqbZMrQKBgQDmVkd1LHdLGOOAd5C+\npwHqxftsh1qyJQ2PAQn6VwAPGkl6c9P/hC3eS6gWMXAf++QlqNUrQR8SvPXlOcXH\nLirqVLd/+gLAD4aRhGTKPjBK07NryGvMQO2pRCPd1n5xnd4Xpp9gt10JJlwZUaIY\ndItvGcV+5TXUMqnEl+GaNKs35wKBgQDip2iUZCwpG1mGn4Pbvs+hLTZQD3+oXPMh\nNYpe9vaStv5YxkFBXM9M+XWH2MDKSMTBZxuTV8GY4pipQwBB32UOtlVVWhOJh1go\nQh7NQOt8yPWb+ynu/i30THfgYMARrqRXXB4o/l9R0J7gW3yjyQDBSuBz5xUIQlpt\nadhg+fmv8wKBgQDjZv75YcMMsy+4H1MZxswPuxK0XRVfl1FBg+cT7lyyjGNKr5v3\nQcn/E3aJIpnuGcNuoraCE7LXzxJ9EoJ+WMgpvSXFBVE9yJY0iB7xxF/tIACdQqua\nZee9GvbGBwOirBceBnSHCcCiTerTXFLKDhWyxCDFXQm9y57r5n7mvWTktQKBgQCW\nsJ7DKeaCXgCjlKJiEvaQPjMB/4vsMAAlcCdTA/bjjG6GLylrf30DvEb7zow+8Sp/\nO0IGMC4yq1S8FCOzqAbURT1uxbh/k1B1U6CO7j6idCl3TwGON8ftyHla4HhSST5S\nJpiWwKg3CPDYUXsImba6zEF2TYiaOSNN4zVNJGVxKQKBgB2aOa93jTHxx4BWCqz1\nq8EWxbSItNHoTLfe4PgRhu3Ow2I2zi+XAfpW5XIrkNfQ09iDeZLsovaZ35fRcwMB\nLWwDlujb5OkJZ4eLgYQqHEwJaYsoR5O6OfpW4IW79t1pzYbGkR0hqY5bcGcI/Tm5\nZZg8ZonNdwagmoihBFAZ+wpB\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/main/java/smoketest/data/elasticsearch/SampleDataElasticsearchApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport java.util.UUID;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Sample application.\n *\n * @author Moritz Halbritter\n */\n@SpringBootApplication\npublic class SampleDataElasticsearchApplication {\n\n\tpublic static void main(String[] args) {\n\t\tConfigurableApplicationContext context = SpringApplication.run(SampleDataElasticsearchApplication.class, args);\n\t\tSampleRepository repository = context.getBean(SampleRepository.class);\n\t\tcreateDocument(repository);\n\t\tlistDocuments(repository);\n\t\trepository.deleteAll();\n\t\tcontext.close();\n\t}\n\n\tprivate static void listDocuments(SampleRepository repository) {\n\t\tSystem.out.println(\"Documents:\");\n\t\tfor (SampleDocument foundDocument : repository.findAll()) {\n\t\t\tSystem.out.println(\"  \" + foundDocument);\n\t\t}\n\t}\n\n\tprivate static void createDocument(SampleRepository repository) {\n\t\tSampleDocument document = new SampleDocument();\n\t\tdocument.setText(\"Look, new @DataElasticsearchTest!\");\n\t\tString id = UUID.randomUUID().toString();\n\t\tdocument.setId(id);\n\t\tSampleDocument savedDocument = repository.save(document);\n\t\tSystem.out.println(\"Saved document \" + savedDocument);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/main/java/smoketest/data/elasticsearch/SampleDocument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.elasticsearch.annotations.Document;\n\n/**\n * Sample document.\n *\n * @author Moritz Halbritter\n */\n@Document(indexName = \"examples\")\npublic class SampleDocument {\n\n\t@Id\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String text;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"SampleDocument{\" + \"id='\" + this.id + '\\'' + \", text='\" + this.text + '\\'' + '}';\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/main/java/smoketest/data/elasticsearch/SampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.elasticsearch;\n\nimport org.springframework.data.elasticsearch.repository.ElasticsearchRepository;\n\n/**\n * Sample repository.\n *\n * @author Moritz Halbritter\n */\ninterface SampleRepository extends ElasticsearchRepository<SampleDocument, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-elasticsearch/src/main/java/smoketest/data/elasticsearch/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.elasticsearch;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Data JDBC smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-jdbc\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-data-jdbc-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/java/smoketest/data/jdbc/Customer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jdbc;\n\nimport java.time.LocalDate;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\n\npublic class Customer {\n\n\t@Id\n\tprivate @Nullable Long id;\n\n\tprivate @Nullable String firstName;\n\n\tprivate @Nullable LocalDate dateOfBirth;\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getFirstName() {\n\t\treturn this.firstName;\n\t}\n\n\tpublic void setFirstName(@Nullable String firstName) {\n\t\tthis.firstName = firstName;\n\t}\n\n\tpublic @Nullable LocalDate getDateOfBirth() {\n\t\treturn this.dateOfBirth;\n\t}\n\n\tpublic void setDateOfBirth(@Nullable LocalDate dateOfBirth) {\n\t\tthis.dateOfBirth = dateOfBirth;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/java/smoketest/data/jdbc/CustomerRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jdbc;\n\nimport java.util.List;\n\nimport org.springframework.data.jdbc.repository.query.Query;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\n\npublic interface CustomerRepository extends CrudRepository<Customer, Long> {\n\n\t@Query(\"select id, first_name, date_of_birth from customer where upper(first_name) like '%' || upper(:name) || '%' \")\n\tList<Customer> findByName(@Param(\"name\") String name);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/java/smoketest/data/jdbc/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jdbc;\n\nimport java.util.List;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\npublic class SampleController {\n\n\tprivate final CustomerRepository customerRepository;\n\n\tpublic SampleController(CustomerRepository customerRepository) {\n\t\tthis.customerRepository = customerRepository;\n\t}\n\n\t@GetMapping(\"/\")\n\t@ResponseBody\n\t@Transactional(readOnly = true)\n\tpublic List<Customer> customers(@RequestParam String name) {\n\t\treturn this.customerRepository.findByName(name);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/java/smoketest/data/jdbc/SampleDataJdbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jdbc;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataJdbcApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleDataJdbcApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/java/smoketest/data/jdbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.jdbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/resources/data.sql",
    "content": "INSERT INTO CUSTOMER (ID, FIRST_NAME, DATE_OF_BIRTH) values (1, 'Meredith', '1998-07-13');\nINSERT INTO CUSTOMER (ID, FIRST_NAME, DATE_OF_BIRTH) values (2, 'Joan', '1982-10-29');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/main/resources/schema.sql",
    "content": "CREATE TABLE CUSTOMER (\n  ID             INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n  FIRST_NAME     VARCHAR(30),\n  DATE_OF_BIRTH  DATE\n);\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/test/java/smoketest/data/jdbc/CustomerRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jdbc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CustomerRepository}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureTestDatabase\nclass CustomerRepositoryIntegrationTests {\n\n\t@Autowired\n\tprivate CustomerRepository repository;\n\n\t@Test\n\tvoid findAllCustomers() {\n\t\tassertThat(this.repository.findAll()).hasSize(2);\n\t}\n\n\t@Test\n\tvoid findByNameWithMatch() {\n\t\tassertThat(this.repository.findByName(\"joan\")).hasSize(1);\n\t}\n\n\t@Test\n\tvoid findByNameWithNoMatch() {\n\t\tassertThat(this.repository.findByName(\"hugh\")).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jdbc/src/test/java/smoketest/data/jdbc/SampleDataJdbcApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jdbc;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SampleDataJdbcApplication}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureMockMvc\nclass SampleDataJdbcApplicationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testCustomers() {\n\t\tassertThat(this.mvc.get().uri(\"/\").param(\"name\", \"merEDith\")).hasStatusOk().bodyText().contains(\"Meredith\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Data JPA smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-data-jpa\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-data-jpa-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/SampleDataJpaApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataJpaApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleDataJpaApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.SequenceGenerator;\n\n@Entity\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SequenceGenerator(name = \"city_generator\", sequenceName = \"city_sequence\", initialValue = 23)\n\t@GeneratedValue(generator = \"city_generator\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country, String state, String map) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t\tthis.state = state;\n\t\tthis.map = map;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/Hotel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\nimport java.io.Serializable;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.FetchType;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.ManyToOne;\nimport jakarta.persistence.OneToMany;\nimport jakarta.persistence.SequenceGenerator;\nimport org.hibernate.annotations.NaturalId;\n\n@Entity\npublic class Hotel implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SequenceGenerator(name = \"hotel_generator\", sequenceName = \"hotel_sequence\", initialValue = 28)\n\t@GeneratedValue(generator = \"hotel_generator\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@ManyToOne(optional = false)\n\t@NaturalId\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate City city;\n\n\t@Column(nullable = false)\n\t@NaturalId\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String address;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String zip;\n\n\t@OneToMany(fetch = FetchType.LAZY, mappedBy = \"hotel\")\n\tprivate Set<Review> reviews = new HashSet<>();\n\n\tprotected Hotel() {\n\t}\n\n\tpublic Hotel(City city, String name, String address, String zip) {\n\t\tthis.city = city;\n\t\tthis.name = name;\n\t\tthis.address = address;\n\t\tthis.zip = zip;\n\t}\n\n\tpublic City getCity() {\n\t\treturn this.city;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getAddress() {\n\t\treturn this.address;\n\t}\n\n\tpublic String getZip() {\n\t\treturn this.zip;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/HotelSummary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\npublic interface HotelSummary {\n\n\tCity getCity();\n\n\tString getName();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/Rating.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\npublic enum Rating {\n\n\tTERRIBLE, POOR, AVERAGE, GOOD, EXCELLENT\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/RatingCount.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\npublic interface RatingCount {\n\n\tRating getRating();\n\n\tlong getCount();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/Review.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\nimport java.io.Serializable;\nimport java.time.LocalDate;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.EnumType;\nimport jakarta.persistence.Enumerated;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.ManyToOne;\nimport jakarta.persistence.SequenceGenerator;\n\nimport org.springframework.util.Assert;\n\n@Entity\npublic class Review implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SequenceGenerator(name = \"review_generator\", sequenceName = \"review_sequence\", initialValue = 64)\n\t@GeneratedValue(generator = \"review_generator\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Long id;\n\n\t@ManyToOne(optional = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Hotel hotel;\n\n\t@Column(nullable = false, name = \"idx\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate int index;\n\n\t@Column(nullable = false)\n\t@Enumerated(EnumType.ORDINAL)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Rating rating;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate LocalDate checkInDate;\n\n\t@Column(nullable = false)\n\t@Enumerated(EnumType.ORDINAL)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate TripType tripType;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String title;\n\n\t@Column(nullable = false, length = 5000)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String details;\n\n\tprotected Review() {\n\t}\n\n\tpublic Review(Hotel hotel, int index, ReviewDetails details) {\n\t\tAssert.notNull(hotel, \"'hotel' must not be null\");\n\t\tAssert.notNull(details, \"'details' must not be null\");\n\t\tthis.hotel = hotel;\n\t\tthis.index = index;\n\t\tthis.rating = details.getRating();\n\t\tthis.checkInDate = details.getCheckInDate();\n\t\tthis.tripType = details.getTripType();\n\t\tthis.title = details.getTitle();\n\t\tthis.details = details.getDetails();\n\t}\n\n\tpublic Hotel getHotel() {\n\t\treturn this.hotel;\n\t}\n\n\tpublic int getIndex() {\n\t\treturn this.index;\n\t}\n\n\tpublic Rating getRating() {\n\t\treturn this.rating;\n\t}\n\n\tpublic void setRating(Rating rating) {\n\t\tthis.rating = rating;\n\t}\n\n\tpublic LocalDate getCheckInDate() {\n\t\treturn this.checkInDate;\n\t}\n\n\tpublic void setCheckInDate(LocalDate checkInDate) {\n\t\tthis.checkInDate = checkInDate;\n\t}\n\n\tpublic TripType getTripType() {\n\t\treturn this.tripType;\n\t}\n\n\tpublic void setTripType(TripType tripType) {\n\t\tthis.tripType = tripType;\n\t}\n\n\tpublic String getTitle() {\n\t\treturn this.title;\n\t}\n\n\tpublic void setTitle(String title) {\n\t\tthis.title = title;\n\t}\n\n\tpublic String getDetails() {\n\t\treturn this.details;\n\t}\n\n\tpublic void setDetails(String details) {\n\t\tthis.details = details;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/ReviewDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\nimport java.io.Serializable;\nimport java.time.LocalDate;\n\npublic class ReviewDetails implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate final Rating rating;\n\n\tprivate final LocalDate checkInDate;\n\n\tprivate final TripType tripType;\n\n\tprivate final String title;\n\n\tprivate final String details;\n\n\tpublic ReviewDetails(Rating rating, LocalDate checkInDate, TripType tripType, String title, String details) {\n\t\tthis.rating = rating;\n\t\tthis.checkInDate = checkInDate;\n\t\tthis.tripType = tripType;\n\t\tthis.title = title;\n\t\tthis.details = details;\n\t}\n\n\tpublic Rating getRating() {\n\t\treturn this.rating;\n\t}\n\n\tpublic LocalDate getCheckInDate() {\n\t\treturn this.checkInDate;\n\t}\n\n\tpublic TripType getTripType() {\n\t\treturn this.tripType;\n\t}\n\n\tpublic String getTitle() {\n\t\treturn this.title;\n\t}\n\n\tpublic String getDetails() {\n\t\treturn this.details;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/TripType.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.domain;\n\npublic enum TripType {\n\n\tBUSINESS, COUPLES, FAMILY, FRIENDS, SOLO\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/domain/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.jpa.domain;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.jpa;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport org.jspecify.annotations.Nullable;\nimport smoketest.data.jpa.domain.City;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\npublic interface CityRepository extends Repository<City, Long> {\n\n\tPage<City> findAll(@Nullable Pageable pageable);\n\n\tPage<City> findByNameContainingAndCountryContainingAllIgnoringCase(String name, String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(String name, String country);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/CitySearchCriteria.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport java.io.Serializable;\n\nimport org.springframework.util.Assert;\n\npublic class CitySearchCriteria implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate final String name;\n\n\tpublic CitySearchCriteria(String name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/CityService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport smoketest.data.jpa.domain.City;\nimport smoketest.data.jpa.domain.HotelSummary;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\n\npublic interface CityService {\n\n\tPage<City> findCities(CitySearchCriteria criteria, Pageable pageable);\n\n\tCity getCity(String name, String country);\n\n\tPage<HotelSummary> getHotels(City city, Pageable pageable);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/CityServiceImpl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport smoketest.data.jpa.domain.City;\nimport smoketest.data.jpa.domain.HotelSummary;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n@Component(\"cityService\")\n@Transactional\nclass CityServiceImpl implements CityService {\n\n\tprivate final CityRepository cityRepository;\n\n\tprivate final HotelRepository hotelRepository;\n\n\tCityServiceImpl(CityRepository cityRepository, HotelRepository hotelRepository) {\n\t\tthis.cityRepository = cityRepository;\n\t\tthis.hotelRepository = hotelRepository;\n\t}\n\n\t@Override\n\tpublic Page<City> findCities(CitySearchCriteria criteria, Pageable pageable) {\n\t\tAssert.notNull(criteria, \"'criteria' must not be null\");\n\t\tString name = criteria.getName();\n\t\tif (!StringUtils.hasLength(name)) {\n\t\t\treturn this.cityRepository.findAll(null);\n\t\t}\n\t\tString country = \"\";\n\t\tint splitPos = name.lastIndexOf(',');\n\t\tif (splitPos >= 0) {\n\t\t\tcountry = name.substring(splitPos + 1);\n\t\t\tname = name.substring(0, splitPos);\n\t\t}\n\t\treturn this.cityRepository.findByNameContainingAndCountryContainingAllIgnoringCase(name.trim(), country.trim(),\n\t\t\t\tpageable);\n\t}\n\n\t@Override\n\tpublic City getCity(String name, String country) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tAssert.notNull(country, \"'country' must not be null\");\n\t\treturn this.cityRepository.findByNameAndCountryAllIgnoringCase(name, country);\n\t}\n\n\t@Override\n\tpublic Page<HotelSummary> getHotels(City city, Pageable pageable) {\n\t\tAssert.notNull(city, \"'city' must not be null\");\n\t\treturn this.hotelRepository.findByCity(city, pageable);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/HotelRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport java.util.List;\n\nimport smoketest.data.jpa.domain.City;\nimport smoketest.data.jpa.domain.Hotel;\nimport smoketest.data.jpa.domain.HotelSummary;\nimport smoketest.data.jpa.domain.RatingCount;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.Repository;\n\ninterface HotelRepository extends Repository<Hotel, Long> {\n\n\tHotel findByCityAndName(City city, String name);\n\n\t@Query(\"select h.city as city, h.name as name, avg(cast(r.rating as Integer)) as averageRating \"\n\t\t\t+ \"from Hotel h left outer join h.reviews r where h.city = ?1 group by h\")\n\tPage<HotelSummary> findByCity(City city, Pageable pageable);\n\n\t@Query(\"select r.rating as rating, count(r) as count \"\n\t\t\t+ \"from Review r where r.hotel = ?1 group by r.rating order by r.rating DESC\")\n\tList<RatingCount> findRatingCounts(Hotel hotel);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/HotelService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport smoketest.data.jpa.domain.City;\nimport smoketest.data.jpa.domain.Hotel;\nimport smoketest.data.jpa.domain.Review;\nimport smoketest.data.jpa.domain.ReviewDetails;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\n\npublic interface HotelService {\n\n\tHotel getHotel(City city, String name);\n\n\tPage<Review> getReviews(Hotel hotel, Pageable pageable);\n\n\tReview getReview(Hotel hotel, int index);\n\n\tReview addReview(Hotel hotel, ReviewDetails details);\n\n\tReviewsSummary getReviewSummary(Hotel hotel);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/HotelServiceImpl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport smoketest.data.jpa.domain.City;\nimport smoketest.data.jpa.domain.Hotel;\nimport smoketest.data.jpa.domain.Rating;\nimport smoketest.data.jpa.domain.RatingCount;\nimport smoketest.data.jpa.domain.Review;\nimport smoketest.data.jpa.domain.ReviewDetails;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.Assert;\n\n@Component(\"hotelService\")\n@Transactional\nclass HotelServiceImpl implements HotelService {\n\n\tprivate final HotelRepository hotelRepository;\n\n\tprivate final ReviewRepository reviewRepository;\n\n\tHotelServiceImpl(HotelRepository hotelRepository, ReviewRepository reviewRepository) {\n\t\tthis.hotelRepository = hotelRepository;\n\t\tthis.reviewRepository = reviewRepository;\n\t}\n\n\t@Override\n\tpublic Hotel getHotel(City city, String name) {\n\t\tAssert.notNull(city, \"'city' must not be null\");\n\t\tAssert.hasLength(name, \"'name' must not be empty\");\n\t\treturn this.hotelRepository.findByCityAndName(city, name);\n\t}\n\n\t@Override\n\tpublic Page<Review> getReviews(Hotel hotel, Pageable pageable) {\n\t\tAssert.notNull(hotel, \"'hotel' must not be null\");\n\t\treturn this.reviewRepository.findByHotel(hotel, pageable);\n\t}\n\n\t@Override\n\tpublic Review getReview(Hotel hotel, int reviewNumber) {\n\t\tAssert.notNull(hotel, \"'hotel' must not be null\");\n\t\treturn this.reviewRepository.findByHotelAndIndex(hotel, reviewNumber);\n\t}\n\n\t@Override\n\tpublic Review addReview(Hotel hotel, ReviewDetails details) {\n\t\tReview review = new Review(hotel, 1, details);\n\t\treturn this.reviewRepository.save(review);\n\t}\n\n\t@Override\n\tpublic ReviewsSummary getReviewSummary(Hotel hotel) {\n\t\tList<RatingCount> ratingCounts = this.hotelRepository.findRatingCounts(hotel);\n\t\treturn new ReviewsSummaryImpl(ratingCounts);\n\t}\n\n\tprivate static class ReviewsSummaryImpl implements ReviewsSummary {\n\n\t\tprivate final Map<Rating, Long> ratingCount;\n\n\t\tReviewsSummaryImpl(List<RatingCount> ratingCounts) {\n\t\t\tthis.ratingCount = new HashMap<>();\n\t\t\tfor (RatingCount ratingCount : ratingCounts) {\n\t\t\t\tthis.ratingCount.put(ratingCount.getRating(), ratingCount.getCount());\n\t\t\t}\n\t\t}\n\n\t\t@Override\n\t\tpublic long getNumberOfReviewsWithRating(Rating rating) {\n\t\t\tLong count = this.ratingCount.get(rating);\n\t\t\treturn (count != null) ? count : 0;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/ReviewRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport smoketest.data.jpa.domain.Hotel;\nimport smoketest.data.jpa.domain.Review;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.Repository;\n\ninterface ReviewRepository extends Repository<Review, Long> {\n\n\tPage<Review> findByHotel(Hotel hotel, Pageable pageable);\n\n\tReview findByHotelAndIndex(Hotel hotel, int index);\n\n\tReview save(Review review);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/ReviewsSummary.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport smoketest.data.jpa.domain.Rating;\n\npublic interface ReviewsSummary {\n\n\tlong getNumberOfReviewsWithRating(Rating rating);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.jpa.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.web;\n\nimport smoketest.data.jpa.service.CityService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\npublic class SampleController {\n\n\t@Autowired\n\tprivate CityService cityService;\n\n\t@GetMapping(\"/\")\n\t@ResponseBody\n\t@Transactional(readOnly = true)\n\tpublic String helloWorld() {\n\t\treturn this.cityService.getCity(\"Bath\", \"UK\").getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/java/smoketest/data/jpa/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.jpa.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/resources/application.properties",
    "content": "spring.h2.console.enabled=true\nspring.jpa.open-in-view=true\nspring.data.jpa.repositories.bootstrap-mode=deferred\nlogging.level.org.hibernate.SQL=debug\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/main/resources/import.sql",
    "content": "--\n-- Sample dataset containing a number of Hotels in various Cities across the world.  The reviews are entirely fictional :)\n--\n\n-- =================================================================================================\n-- AUSTRALIA\n\n-- Brisbane\ninsert into city(id, country, name, state, map) values (1, 'Australia', 'Brisbane', 'Queensland', '-27.470933, 153.023502')\ninsert into hotel(id, city_id, name, address, zip) values (1, 1, 'Conrad Treasury Place', 'William & George Streets', '4001')\n\n-- Melbourne\ninsert into city(id, country, name, state, map) values (2, 'Australia', 'Melbourne', 'Victoria', '-37.813187, 144.96298')\ninsert into hotel(id, city_id, name, address, zip) values (2, 2, 'The Langham', '1 Southgate Ave, Southbank', '3006')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (1, 2, 0, '2005-05-10', 2, 4, 'Pretty average', 'I stayed in 2005, the hotel was nice enough but nothing special.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (2, 2, 1, '2006-01-12', 4, 2, 'Bright hotel with big rooms', 'This hotel has a fantastic lovely big windows.  The room we stayed in had lots of space.  Recommended.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (3, 2, 2, '2006-05-25', 3, 1, 'Pretty good', 'I liked this hotel and would stay again.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (4, 2, 3, '2009-01-20', 3, 2, 'Nice clean rooms', 'The rooms are maintained to a high standard and very clean, the bathroom was spotless!!')\n\n-- Sydney\ninsert into city(id, country, name, state, map) values (3, 'Australia', 'Sydney', 'New South Wales', '-33.868901, 151.207091')\ninsert into hotel(id, city_id, name, address, zip) values (3, 3, 'Swissotel', '68 Market Street', '2000')\n\n\n-- =================================================================================================\n-- CANADA\n\n-- Montreal\ninsert into city(id, country, name, state, map) values (4, 'Canada', 'Montreal', 'Quebec', '45.508889, -73.554167')\ninsert into hotel(id, city_id, name, address, zip) values (4, 4, 'Ritz Carlton', '1228 Sherbrooke St', 'H3G1H6')\n\n\n-- =================================================================================================\n-- ISRAEL\n\n-- Tel Aviv\ninsert into city(id, country, name, state, map) values (5, 'Israel', 'Tel Aviv', '', '32.066157, 34.777821')\ninsert into hotel(id, city_id, name, address, zip) values (5, 5, 'Hilton Tel Aviv', 'Independence Park', '63405')\n\n\n-- =================================================================================================\n-- JAPAN\n\n-- Tokyo\ninsert into city(id, country, name, state, map) values (6, 'Japan', 'Tokyo', '', '35.689488, 139.691706')\ninsert into hotel(id, city_id, name, address, zip) values (6, 6, 'InterContinental Tokyo Bay', 'Takeshiba Pier', '105')\n\n\n-- =================================================================================================\n-- SPAIN\n\n-- Barcelona\ninsert into city(id, country, name, state, map) values (7, 'Spain', 'Barcelona', 'Catalunya', '41.387917, 2.169919')\ninsert into hotel(id, city_id, name, address, zip) values (7, 7, 'Hilton Diagonal Mar', 'Passeig del Taulat 262-264', '08019')\n\n-- =================================================================================================\n-- SWITZERLAND\n\n-- Neuchatel\ninsert into city(id, country, name, state, map) values (8, 'Switzerland', 'Neuchatel', '', '46.992979, 6.931933')\ninsert into hotel(id, city_id, name, address, zip) values (8, 8, 'Hotel Beaulac', ' Esplanade Leopold-Robert 2', '2000')\n\n\n-- =================================================================================================\n-- UNITED KINGDOM\n\n-- Bath\ninsert into city(id, country, name, state, map) values (9, 'UK', 'Bath', 'Somerset', '51.381428, -2.357454')\ninsert into hotel(id, city_id, name, address, zip) values (9, 9, 'The Bath Priory Hotel', 'Weston Road', 'BA1 2XT')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (5, 9, 0, '2000-01-23', 4, 1, 'A lovely hotel', 'We stayed here after a wedding and it was fantastic.  Recommend to all.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (6, 9, 1, '2000-08-04', 3, 1, 'Very special', 'A very special hotel with lovely staff.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (7, 9, 2, '2001-01-01', 2, 4, 'Nice but too hot', 'Stayed during the summer heat wave (exceptional for England!) and the room was very hot.  Still recommended.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (8, 9, 3, '2002-01-20', 3, 1, 'Big rooms and a great view', 'Considering how central this hotel is the rooms are a very good size.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (9, 9, 4, '2002-11-03', 2, 1, 'Good but pricey', 'A nice hotel but be prepared to pay over the odds for your stay.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (10, 9, 5, '2003-09-18', 4, 1, 'Fantastic place', 'Just lovely.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (11, 9, 6, '2004-03-21', 4, 3, 'A very special place', 'I stayed here in 2004 and found it to be very relaxing, a nice pool and good gym is cherry on the cake.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (12, 9, 7, '2004-04-10', 0, 0, 'Terrible', 'I complained after I was told I could not check out after 11pm.  Ridiculous!!!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (13, 9, 8, '2004-12-20', 4, 4, 'A perfect location', 'Central location makes this a perfect hotel.  Be warned though, it''s not cheap.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (14, 9, 9, '2005-04-19', 3, 2, 'Expensive but worth it', 'Dig deep into your pockets and enjoy this lovely City and fantastic hotel.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (15, 9, 10, '2005-05-21', 4, 1, 'The best hotel in the area', 'Top hotel in the area, would not stay anywhere else.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (16, 9, 11, '2005-11-17', 4, 2, 'Lovely hotel, fantastic grounds', 'The garden upkeep run into thousands (perhaps explaining why the rooms are so much) but so lovely and relaxing.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (17, 9, 12, '2006-01-04', 3, 4, 'Gorgeous Top Quality Hotel', 'Top draw stuff.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (18, 9, 13, '2006-01-21', 4, 1, 'Fabulous Hotel and Restaurant', 'The food at this hotel is second to none, try the peppered steak!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (19, 9, 14, '2006-01-29', 4, 4, 'Feels like home', 'A lovely home away from home.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (20, 9, 15, '2006-03-21', 1, 1, 'Far too expensive', 'Overpriced, Overpriced, Overpriced!!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (21, 9, 16, '2006-05-10', 4, 1, 'Excellent Hotel, Wonderful Staff', 'The staff went out of their way to help us after we missed our last train home, organising a Taxi back to Newport even after we had checked out.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (22, 9, 17, '2007-09-11', 3, 2, 'The perfect retreat', 'If you want a relaxing stay, this is the place.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (23, 9, 18, '2008-06-01', 3, 3, 'Lovely stay, fantastic staff', 'As other reviews have noted, the staff in this hotel really are the best in Bath.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (24, 9, 19, '2009-05-14', 4, 2, 'Can''t Wait to go back', 'We will stay again for sure.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (25, 9, 20, '2010-04-26', 4, 1, 'Amazing Hotel', 'We won a trip here after entering a competition.  Not sure we would pay the full price but such a wonderful place.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (26, 9, 21, '2010-10-26', 2, 2, 'Dissapointed', 'The pool was closed, the chief was ill, the staff were rude my wallet is bruised!')\ninsert into hotel(id, city_id, name, address, zip) values (10, 9, 'Bath Travelodge', 'Rossiter Road, Widcombe Basin', 'BA2 4JP')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (27, 10, 0, '2002-08-21', 0, 2, 'Terrible hotel', 'One of the worst hotels that I have ever stayed in.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (28, 10, 1, '2003-01-28', 0, 0, 'Rude and unpleasant staff', 'The staff refused to help me with any aspect of my stay, I will not stay here again.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (29, 10, 2, '2004-06-17', 1, 0, 'Below par', 'Don''t stay here!!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (30, 10, 3, '2005-07-12', 0, 1, 'Small and Unpleasant', 'The room was far too small and felt unclean.  Not recommended.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (31, 10, 4, '2006-01-07', 1, 4, 'Cheap if you are not fussy', 'This hotel has some rough edges but I challenge you to find somewhere cheaper.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (32, 10, 5, '2006-01-13', 0, 2, 'Terrible', 'Just terrible!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (33, 10, 6, '2006-03-25', 0, 0, 'Smelly and dirty room', 'My room smelt of damp and I found the socks of the previous occupant under my bed.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (34, 10, 7, '2006-04-09', 0, 4, 'Grim', 'Grim.  I would try elsewhere before staying here.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (35, 10, 8, '2006-08-01', 1, 3, 'Very Noisy', 'Building work during the day and a disco at night.  Good grief!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (36, 10, 9, '2009-01-03', 1, 4, 'Tired and falling down', 'This hotel is in serious need of refurbishment, the windows are rotting, the paintwork is tired and the carpets are from the 1970s.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (37, 10, 10, '2009-07-20', 0, 0, 'Not suitable for human habitation', 'I would not put my dog up in this hotel.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (38, 10, 11, '2010-05-20', 1, 0, 'Conveient for the railway', 'Average place but useful if you need to commute')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (39, 10, 12, '2010-01-22', 2, 2, 'Not as bad as the reviews', 'Some of the reviews seem a bit harsh, it''s not too bad for the price.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (40, 10, 13, '2011-01-10', 3, 1, 'Reburished and nice', 'Looks like this hotel has had a major facelift.  If you have stayed before 2011 perhaps it''s time to give this hotel another try.  Very good value for money and pretty nice.')\n\n-- London\ninsert into city(id, country, name, state, map) values (10, 'UK', 'London', '', '51.500152, -0.126236')\ninsert into hotel(id, city_id, name, address, zip) values (11, 10, 'Melia White House', 'Albany Street', 'NW1 3UP')\n\n-- Southampton\ninsert into city(id, country, name, state, map) values (11, 'UK', 'Southampton', 'Hampshire', '50.902571, -1.397238')\ninsert into hotel(id, city_id, name, address, zip) values (12, 11, 'Chilworth Manor', 'The Cottage, Southampton Business Park', 'SO16 7JF')\n\n\n-- =================================================================================================\n-- USA\n\n-- Atlanta\ninsert into city(id, country, name, state, map) values (12, 'USA', 'Atlanta', 'GA', '33.748995, -84.387982')\ninsert into hotel(id, city_id, name, address, zip) values (13, 12, 'Marriott Courtyard', 'Tower Place, Buckhead', '30305')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (41, 13, 0, '2009-01-20', 3, 0, 'Better than most', 'Most other hotels is this area are a bit ropey, this one is actually pretty good.')\ninsert into hotel(id, city_id, name, address, zip) values (14, 12, 'Ritz Carlton', 'Peachtree Rd, Buckhead', '30326')\ninsert into hotel(id, city_id, name, address, zip) values (15, 12, 'Doubletree', 'Tower Place, Buckhead', '30305')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (42, 15, 0, '2006-01-12', 2, 3, 'No fuss hotel', 'Cheap, no fuss hotel.  Good if you are travelling on business and just need a place to stay.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (43, 15, 1, '2009-01-20', 2, 2, 'Nice area but small rooms', 'The area felt nice and safe but the rooms are a little on the small side')\n\n-- Chicago\ninsert into city(id, country, name, state, map) values (13, 'USA', 'Chicago', 'IL', '41.878114, -87.629798')\ninsert into hotel(id, city_id, name, address, zip) values (16, 13, 'Hotel Allegro', '171 West Randolph Street', '60601')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (44, 16, 0, '2009-12-15', 3, 2, 'Cheap and Recommended', 'Good value for money, can''t really fault it.')\n\n-- Eau Claire\ninsert into city(id, country, name, state, map) values (14, 'USA', 'Eau Claire', 'WI', '44.811349, -91.498494')\ninsert into hotel(id, city_id, name, address, zip) values (17, 14, 'Sea Horse Inn', '2106 N Clairemont Ave', '54703')\ninsert into hotel(id, city_id, name, address, zip) values (18, 14, 'Super 8 Eau Claire Campus Area', '1151 W Macarthur Ave', '54701')\n\n-- Hollywood\ninsert into city(id, country, name, state, map) values (15, 'USA', 'Hollywood', 'FL', '26.011201, -80.14949')\ninsert into hotel(id, city_id, name, address, zip) values (19, 15, 'Westin Diplomat', '3555 S. Ocean Drive', '33019')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (45, 19, 0, '2006-01-11', 0, 0, 'Avoid', 'The hotel has a very bad reputation.  I would avoid it if I were you.')\n\n-- Miami\ninsert into city(id, country, name, state, map) values (16, 'USA', 'Miami', 'FL', '25.788969, -80.226439')\ninsert into hotel(id, city_id, name, address, zip) values (20, 16, 'Conrad Miami', '1395 Brickell Ave', '33131')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (46, 20, 0, '2010-01-09', 3, 2, 'Close to the local attractions', 'Fantastic access to all the local attractions mean you won''t mind the small rooms.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (47, 20, 1, '2010-09-10', 2, 2, 'Good value and friendly', 'Not expensive and very welcoming staff. I would stay again.')\n\n-- Melbourne\ninsert into city(id, country, name, state, map) values (17, 'USA', 'Melbourne', 'FL', '28.083627, -80.608109')\ninsert into hotel(id, city_id, name, address, zip) values (21, 17, 'Radisson Suite Hotel Oceanfront', '3101 North Hwy', '32903')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (48, 21, 0, '2005-06-15', 3, 3, 'A very nice hotel', 'I can''t fault this hotel and I have stayed here many times.  Always friendly staff and lovely atmosphere.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (49, 21, 1, '2006-01-20', 2, 4, 'Comfortable and good value', 'To complaints at all.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (50, 21, 2, '2007-08-21', 3, 1, 'Above average', 'Better than a lot of hotels in the area and not too pricey.')\n\n-- New York\ninsert into city(id, country, name, state, map) values (18, 'USA', 'New York', 'NY', '40.714353, -74.005973')\ninsert into hotel(id, city_id, name, address, zip) values (22, 18, 'W Union Hotel', 'Union Square, Manhattan', '10011')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (51, 22, 0, '2002-01-19', 0, 1, 'Too noisy, too small', 'The city never sleeps and neither will you if you say here.  The rooms are small and the sound insulation is poor!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (52, 22, 1, '2004-03-10', 1, 4, 'Overpriced', 'Far too much money for such a tiny room!')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (53, 22, 2, '2007-04-11', 2, 0, 'So so, nothing special', 'Not brilliant but not too bad either.')\ninsert into hotel(id, city_id, name, address, zip) values (23, 18, 'W Lexington Hotel', 'Lexington Ave, Manhattan', '10011')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (54, 23, 0, '2004-07-21', 3, 2, 'Excellent location', 'So close to the heart of the city.  Recommended.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (55, 23, 1, '2006-05-20', 3, 1, 'Very nice', 'I can''t fault this hotel, clean, good location and nice staff.')\ninsert into hotel(id, city_id, name, address, zip) values (24, 18, '70 Park Avenue Hotel', '70 Park Avenue', '10011')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (56, 24, 0, '2003-11-10', 4, 1, 'Great!!', 'I own this hotel and I think it is pretty darn good.')\n\n-- Palm Bay\ninsert into city(id, country, name, state, map) values (19, 'USA', 'Palm Bay', 'FL', '28.034462, -80.588665')\ninsert into hotel(id, city_id, name, address, zip) values (25, 19, 'Jameson Inn', '890 Palm Bay Rd NE', '32905')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (57, 25, 0, '2005-10-20', 3, 2, 'Fantastical', 'This is the BEST hotel in Palm Bay, not complaints at all.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (58, 25, 1, '2006-01-12', 4, 1, 'Top marks', 'I rate this hotel 5 stars, the best in the area by miles.')\n\n-- San Francisco\ninsert into city(id, country, name, state, map) values (20, 'USA', 'San Francisco', 'CA', '37.77493, -122.419415')\ninsert into hotel(id, city_id, name, address, zip) values (26, 20, 'Marriot Downtown', '55 Fourth Street', '94103')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (59, 26, 0, '2006-07-02', 2, 3, 'Could be better', 'I stayed in late 2006 with work, the room was very small and the restaurant does not stay open very late.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (60, 26, 1, '2008-07-01', 1, 4, 'Brrrr cold!', 'My room was freezing cold, I would not recommend this place.')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (61, 26, 2, '2009-01-05', 3, 2, 'Nice for money', 'You can''t really go wrong here for the money.  There may be better places to stay but not for this price.')\n\n-- Washington\ninsert into city(id, country, name, state, map) values (21, 'USA', 'Washington', 'DC', '38.895112, -77.036366')\ninsert into hotel(id, city_id, name, address, zip) values (27, 21, 'Hotel Rouge', '1315 16th Street NW', '20036')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (62, 27, 0, '2000-01-29', 0, 2, 'Never again', 'I will never ever stay here again!!  They wanted extra cash to get fresh batteries for the TV remote')\ninsert into review(id, hotel_id, idx, check_in_date, rating, trip_type, title, details) values (63, 27, 1, '2006-02-20', 0, 0, 'Avoid', 'This place is the pits, they charged us twice for a single night stay.  I only got refunded after contacting my credit card company.')\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/test/java/smoketest/data/jpa/SampleDataJpaApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa;\n\nimport java.lang.management.ManagementFactory;\n\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to run the application.\n *\n * @author Oliver Gierke\n * @author Dave Syer\n */\n// Enable JMX so we can test the MBeans (you can't do this in a properties file)\n@SpringBootTest(properties = \"spring.jmx.enabled:true\")\n@AutoConfigureMockMvc\n@ActiveProfiles(\"scratch\")\n// Separate profile for web tests to avoid clashing databases\nclass SampleDataJpaApplicationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testHome() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).hasStatusOk().hasBodyTextEqualTo(\"Bath\");\n\t}\n\n\t@Test\n\tvoid testJmx() throws Exception {\n\t\tassertThat(ManagementFactory.getPlatformMBeanServer()\n\t\t\t.queryMBeans(new ObjectName(\"jpa.sample:type=HikariDataSource,*\"), null)).hasSize(1);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/test/java/smoketest/data/jpa/service/CityRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.data.jpa.domain.City;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CityRepository}.\n *\n * @author Oliver Gierke\n */\n@SpringBootTest\nclass CityRepositoryIntegrationTests {\n\n\t@Autowired\n\tCityRepository repository;\n\n\t@Test\n\tvoid findsFirstPageOfCities() {\n\t\tPage<City> cities = this.repository.findAll(PageRequest.of(0, 10));\n\t\tassertThat(cities.getTotalElements()).isGreaterThan(20L);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/test/java/smoketest/data/jpa/service/HotelRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.jpa.service;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.data.jpa.domain.City;\nimport smoketest.data.jpa.domain.Hotel;\nimport smoketest.data.jpa.domain.HotelSummary;\nimport smoketest.data.jpa.domain.Rating;\nimport smoketest.data.jpa.domain.RatingCount;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Sort.Direction;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link HotelRepository}.\n *\n * @author Oliver Gierke\n */\n@SpringBootTest\nclass HotelRepositoryIntegrationTests {\n\n\t@Autowired\n\tCityRepository cityRepository;\n\n\t@Autowired\n\tHotelRepository repository;\n\n\t@Test\n\tvoid executesQueryMethodsCorrectly() {\n\t\tCity city = this.cityRepository.findAll(PageRequest.of(0, 1, Direction.ASC, \"name\")).getContent().get(0);\n\t\tassertThat(city.getName()).isEqualTo(\"Atlanta\");\n\t\tPage<HotelSummary> hotels = this.repository.findByCity(city, PageRequest.of(0, 10, Direction.ASC, \"name\"));\n\t\tHotel hotel = this.repository.findByCityAndName(city, hotels.getContent().get(0).getName());\n\t\tassertThat(hotel.getName()).isEqualTo(\"Doubletree\");\n\t\tList<RatingCount> counts = this.repository.findRatingCounts(hotel);\n\t\tassertThat(counts).hasSize(1);\n\t\tassertThat(counts.get(0).getRating()).isEqualTo(Rating.AVERAGE);\n\t\tassertThat(counts.get(0).getCount()).isGreaterThan(1L);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-jpa/src/test/resources/application-scratch.properties",
    "content": "spring.datasource.name=scratchdb\nspring.jmx.default-domain=jpa.sample\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Data LDAP smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-ldap\"))\n\n\truntimeOnly(\"com.unboundid:unboundid-ldapsdk\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-data-ldap-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/main/java/smoketest/data/ldap/Person.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.ldap;\n\nimport javax.naming.Name;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.ldap.odm.annotations.Attribute;\nimport org.springframework.ldap.odm.annotations.Entry;\nimport org.springframework.ldap.odm.annotations.Id;\n\n@Entry(objectClasses = { \"person\", \"top\" })\npublic class Person {\n\n\t@Id\n\tprivate @Nullable Name dn;\n\n\t@Attribute(name = \"telephoneNumber\")\n\tprivate @Nullable String phone;\n\n\t@Override\n\tpublic String toString() {\n\t\treturn String.format(\"Customer[dn=%s, phone='%s']\", this.dn, this.phone);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/main/java/smoketest/data/ldap/PersonRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.ldap;\n\nimport org.springframework.data.ldap.repository.LdapRepository;\n\npublic interface PersonRepository extends LdapRepository<Person> {\n\n\tPerson findByPhone(String phone);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/main/java/smoketest/data/ldap/SampleDataLdapApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.ldap;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataLdapApplication implements CommandLineRunner {\n\n\tprivate final PersonRepository repository;\n\n\tpublic SampleDataLdapApplication(PersonRepository repository) {\n\t\tthis.repository = repository;\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\n\t\t// fetch all people\n\t\tSystem.out.println(\"People found with findAll():\");\n\t\tSystem.out.println(\"-------------------------------\");\n\t\tfor (Person person : this.repository.findAll()) {\n\t\t\tSystem.out.println(person);\n\t\t}\n\t\tSystem.out.println();\n\n\t\t// fetch an individual person\n\t\tSystem.out.println(\"Person found with findByPhone('+46 555-123456'):\");\n\t\tSystem.out.println(\"--------------------------------\");\n\t\tSystem.out.println(this.repository.findByPhone(\"+46 555-123456\"));\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleDataLdapApplication.class, args).close();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/main/java/smoketest/data/ldap/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.ldap;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/main/resources/application.properties",
    "content": "spring.ldap.embedded.base-dn=dc=spring,dc=org\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/main/resources/schema.ldif",
    "content": "dn: dc=spring,dc=org\nobjectclass: top\nobjectclass: domain\nobjectclass: extensibleObject\ndc: spring\n\ndn: ou=groups,dc=spring,dc=org\nobjectclass: top\nobjectclass: organizationalUnit\nou: groups\n\ndn: cn=ROLE_USER,ou=groups,dc=spring,dc=org\nobjectclass: top\nobjectclass: groupOfUniqueNames\ncn: ROLE_USER\nuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\nuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\nuniqueMember: cn=Some Person,ou=company1,c=Sweden,dc=spring,dc=org\nuniqueMember: cn=Some Person3,ou=company1,c=Sweden,dc=spring,dc=org\n\ndn: cn=ROLE_ADMIN,ou=groups,dc=spring,dc=org\nobjectclass: top\nobjectclass: groupOfUniqueNames\ncn: ROLE_ADMIN\nuniqueMember: cn=Some Person2,ou=company1,c=Sweden,dc=spring,dc=org\n\ndn: c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: country\nc: Sweden\ndescription: The country of Sweden\n\ndn: ou=company1,c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: organizationalUnit\nou: company1\ndescription: First company in Sweden\n\ndn: cn=Alice Smith,ou=company1,c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: alice.smith\nuserPassword: password\ncn: Alice Smith\nsn: Alice Smith\ndescription: Sweden, Company1, Alice Smith\ntelephoneNumber: +46 555-123456\n\ndn: cn=Bob Smith,ou=company1,c=Sweden,dc=spring,dc=org\nobjectclass: top\nobjectclass: person\nobjectclass: organizationalPerson\nobjectclass: inetOrgPerson\nuid: bob.smith\nuserPassword: password\ncn: Bob Smith\nsn: Bob Smith\ndescription: Sweden, Company1, Some Person2\ntelephoneNumber: +46 555-654321\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-ldap/src/test/java/smoketest/data/ldap/SampleDataLdapApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.ldap;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleDataLdapApplication}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\n@SpringBootTest\nclass SampleDataLdapApplicationTests {\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tassertThat(output).contains(\"cn=Alice Smith\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data MongoDB smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-mongodb\"))\n\timplementation(project(\":starter:spring-boot-starter-data-mongodb-reactive\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-mongodb-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-mongodb-reactive-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-mongodb\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/dockerTest/java/smoketest/data/mongodb/SampleDataMongoApplicationReactiveSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.mongodb.core.ReactiveMongoTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data MongoDB using reactive repositories with SSL.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\n@SpringBootTest\nclass SampleDataMongoApplicationReactiveSslTests {\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(\"classpath:ssl/test-ca.crt\")\n\tstatic final MongoDBContainer mongoDb = TestImage.container(SecureMongoContainer.class);\n\n\t@Autowired\n\tprivate ReactiveMongoTemplate mongoTemplate;\n\n\t@Autowired\n\tprivate SampleReactiveRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument exampleDocument = new SampleDocument();\n\t\texampleDocument.setText(\"Look, new @DataMongoTest!\");\n\t\texampleDocument = this.exampleRepository.save(exampleDocument).block(Duration.ofSeconds(30));\n\t\tassertThat(exampleDocument).isNotNull();\n\t\tassertThat(exampleDocument.getId()).isNotNull();\n\t\tassertThat(this.mongoTemplate.collectionExists(\"exampleDocuments\").block(Duration.ofSeconds(30))).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/dockerTest/java/smoketest/data/mongodb/SampleMongoApplicationSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mongodb.MongoDBContainer;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.mongodb.test.autoconfigure.DataMongoTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.mongodb.core.MongoTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Data MongoDB with SSL.\n *\n * @author Scott Frederick\n * @author Eddú Meléndez\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataMongoTest\nclass SampleMongoApplicationSslTests {\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(\"classpath:ssl/test-ca.crt\")\n\tstatic final MongoDBContainer mongoDb = TestImage.container(SecureMongoContainer.class);\n\n\t@Autowired\n\tprivate MongoTemplate mongoTemplate;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tSampleDocument exampleDocument = new SampleDocument();\n\t\texampleDocument.setText(\"Look, new @DataMongoTest!\");\n\t\texampleDocument = this.exampleRepository.save(exampleDocument);\n\t\tassertThat(exampleDocument.getId()).isNotNull();\n\t\tassertThat(this.mongoTemplate.collectionExists(\"exampleDocuments\")).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/dockerTest/java/smoketest/data/mongodb/SecureMongoContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport com.github.dockerjava.api.command.InspectContainerResponse;\nimport org.testcontainers.mongodb.MongoDBContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link MongoDBContainer} for MongoDB with SSL configuration.\n *\n * @author Scott Frederick\n */\nclass SecureMongoContainer extends MongoDBContainer {\n\n\tSecureMongoContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t}\n\n\t@Override\n\tpublic void configure() {\n\t\t// test-server.pem is a single PEM file containing server certificate and key\n\t\t// content combined\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.pem\"), \"/ssl/server.pem\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-ca.crt\"), \"/ssl/ca.crt\");\n\t\twithCommand(\"mongod --tlsMode requireTLS --tlsCertificateKeyFile /ssl/server.pem --tlsCAFile /ssl/ca.crt\");\n\t}\n\n\t@Override\n\tprotected void containerIsStarted(InspectContainerResponse containerInfo, boolean reused) {\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/main/java/smoketest/data/mongodb/SampleDataMongoApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataMongoApplication {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/main/java/smoketest/data/mongodb/SampleDocument.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.mongodb.core.mapping.Document;\n\n@Document(collection = \"exampleDocuments\")\npublic class SampleDocument {\n\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String text;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/main/java/smoketest/data/mongodb/SampleReactiveRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\n\ninterface SampleReactiveRepository extends ReactiveMongoRepository<SampleDocument, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/main/java/smoketest/data/mongodb/SampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport org.springframework.data.mongodb.repository.MongoRepository;\n\ninterface SampleRepository extends MongoRepository<SampleDocument, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/main/java/smoketest/data/mongodb/SampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.mongodb;\n\nimport org.springframework.data.mongodb.core.MongoTemplate;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class SampleService {\n\n\tprivate final MongoTemplate mongoTemplate;\n\n\tpublic SampleService(MongoTemplate mongoTemplate) {\n\t\tthis.mongoTemplate = mongoTemplate;\n\t}\n\n\tpublic boolean hasCollection(String collectionName) {\n\t\treturn this.mongoTemplate.collectionExists(collectionName);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/main/java/smoketest/data/mongodb/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.mongodb;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/test/resources/ssl/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/test/resources/ssl/test-ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6w3YrNBBRTFlK\nIjdlm5miEXCrYpdJQ090nquAPf9go1MNJlcpk87neRg8/QNd/SybcIdzJZJZVpvK\nKZli49Z6drUwSVIvhmkn1bCRmg5Dds8UrW63PqQw7CuABRyTLwf+sgqPYkQGGRId\nQgavns2NQTAbXKBpJ6szxHNbDU+0yr4Lws67e/3irMTc0ODVBGnK9X06awuyMhJ3\nRmYAk2L2+aIQf3bcqc/KKqdCZYqliJx2BCZfUZfKVLbaNmoDBo6RgaNfxR17K+ui\nGRmQzSGf25pK59AYRbjIoAKfc+SMm3OLx2sEjKMiL1hwDMHFkH2hUqpdkyWW2A7Z\n8MyYgmLQ2C3QKLt8KgQypKhwrIMowvpguv1Ra3Hht+yuT6tU71D8P+/xEqCy2/t0\nJ/YpZFfdkkQLQgEdLmAs2rSqqpVwbHctxLKF2Iok61LACc2QcyH6NJDEtKUGNxKp\nM+IZNEr9F12X7GdT+YGCTtkEY2tQVoPkxwwWN11LsiHzZoeelDWB6RadQa/5Ob8b\nryHYG9nlTar5F944KBFb2L8BhbaOBPsgWd+PJReAFC95q4wByGiaoURUt73lmBWI\nXq+YffgQqjfD0vlNCLCT+vndiUztNI5PIOrHrq3jMZgOxUyJykqbOLjZGnwSkSsB\nFHJERQgpK9az07365Pf7tqs0uAd7kQIDAQABAoICAAthB10ggfICHdqXdRqavWST\nfXLjweXz1O59EGPy4xFnQhMmB99/ovaVeTWWENN0LniWBZqtalpJHZrWqALPcOzr\nOKTlgr1kihmkOmrUoRPZNErFOl6t0WEtsoTNSu1oyyrofB46VXytoF3p/PBMU6fM\nlfrEzP07LoIr8P9WM0oHpEahKulfZ5uc/S2bCGfSKgP0qxmZFhBYXqmnv2U/laMI\nmKg6q+pL6l4d9SzldOobBbVnEVNzbDUmrjFjaVgf2SXiaSrXnrE3ftbUgqtA5FCS\nF7eCojooXVbT8PT4Ia+zdPnKP6n6S6I0kkXZcSDxacYffEPRSFQFe/opYr3UC+Mk\n1/UmOnoI8X8+N9SPcVD9cbVQUzBuuXfTy+LMx9mg3QxFebRSRre22xSOSlM7MF9B\n6MPeNgwCk3Z0NTr+IedGfyA+d6+iHTMGnv0hF4b4UkcXbC3HdeR3K4hf+msGD2oG\n7JF423T/d7t+g883y4CZm7p096apR8cCLIe2HKSwcYbKhft7LkAdm8kpnqkr5ER1\nanI7RDmucrx3HgrXeuCz9Uai6EMU6jNU1MAEBVeu4jz1rlO4e9zS2Ak68AwIz0zI\ntl5el3paHjlRYY6YTslM5qjGerJt19IyHvZxXXIzF7JdF7w1nSK9bjvninALJl49\nYZAPRIbyQ8P6DLqiDNBFAoIBAQDvQoow86vNg6zHdb8eBC10l2Y6M5DAKTWPE8RJ\nn0td1TLwEHzKvkR25v6yGKABbBO1+7ABACCqA8rkcB7M5jugak/kR9vuDrFPAsqf\nlgckf1Up7ekDheTH8X1VSDiRZPv07UElO0M3aFeMVR/xi9Wae8C3WZo9dT2wKnM0\nd0Acr4Kt4SYm1Dw7kuh+Y1L/vvWuryPm1btxhfKO6JN5v2W8DTrqVkxuxYEM1VnR\n69LfauLVico2q8EGXmQTth/Iok5wj1qI6kmrlgQR+eSY1qgNk1qzwjJVsbSmAOL8\n6Y9Ksct53bEN6DIdYRE/SrEVCz/FY1Pry2DNTjdiwImaSOZ3AoIBAQDH1KRkqsET\nYUnPJxp9pHWlynicEVE/Y7FFhhtpUKzhY1nZ+NsNy91FrZiyx5Os7pSxhLNID8g5\nxKCOfYd7qdvZCg/5bMXhtagQ3gwa/wyuyamc29dKkCpHDz/GkoEkgVe6eYu1GNdR\niNpY5ye5T9fBE1s3odbDcnRVeHAP7vqz5z17JKrlqZVhbLYlR4qGHmAogq7vWlyd\nIR5qLoXMgyqq5OHl1GaaiqfViBpJeoEWYze0cARUWOcrJRblJYS03WHMuLDG5RZd\n5nmf2xwEcMgW5AX7+GB8CdXRVZy6OZcGn7TU9+xnBJA2LbzxJlHBXjWEd8Uma2Al\n+ohlDbGrd8g3AoIBAHsWzGlqstREDbt/xBb5Jzl4OktvA+UYTkmRbcZCgU+Aw3fl\nw426XRaeuCF/sbGJnIpfNakOG7/bu6HSXMYlHD/m8bsLjQXn4Sg4021OjdYk+/da\nQiph09VZU5VwVknWnhjfhkhVOLtknsW/dXOa8QVM7VRmcId1rYrYC/TN9NnNIXm6\n/xmyzloHtjxvdN/Fqjd4OwwioRBCTQtgc56K7RfV5p1wUFocmcu0Z0UsAYyXPKOH\nA9Ukf2V7YhkR9UAO4DPgTD9r6QKxZt6opQZMSKDTUjJwkdysU7ejdSOQNPvEhF3p\nw5DYCBA9Q9Y/4uJkqyYtd5szQlXdC3lufFw3bPkCggEBAKPA3GpmB0xjWEG6UJoP\nUB1pWwbBpivk/Rr097eI1fLpIHNf29plalE0HcK7i4eWByGllekCjdjRCaVattCe\n9DraZRbHjS0WWMBhxdfFk9YUCbsx6C4BD7QlieSmn8+TcpmsCtF/psr4870Qx9uy\n0yI0Q3bGV6DYRP7ZcDOOacFNSHOGK8mB+5jXpjfMdXbMo43u8X3RNb3JqwvmTdy2\nzBs47ukQ8nfIEhsIqkn2apw2+CoT9WhNZjpT7XwgD6zLEd7apnqGtpqCSL63pjD5\nXu5rM4A1HJPo11/w4Ts2AE38SAqRlBcjhS3wszmGZk6obgC8yUFfkm3s7SKqYyMZ\nSGcCggEBAO0IDB/h1meZ2y+6bSsCVaDSxdRl0JF0CDUYVTANQsJ+q7u7CpF9xOo8\nYNrSy8eM0K6RMY/3WbTm+4z9tOldxEV2dn+29oVeMKkgpJYo0k2Au3wTMI2xMyyl\nHZ+ZttsqSZsj2CPx83LMaPwKdzVjwA7alVx4P+AkQKn7jGJgidj5xyw0G3gnzdfT\nnGzuitQFlcrcPyrVHAAmRhIw+B5CsvMFlM8PAvojN7burGswjWGeZjkgqoLvKlgq\njRMGzLTzF9Pay7P/D/pWQwPVGiseJq+QVIA+iILpy9Zb9T6DnBFaPFGOKAduzVU9\nlTLiho2DATppaxNUQKh/5k70hzbipDg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/test/resources/ssl/test-client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/test/resources/ssl/test-client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-mongodb/src/test/resources/ssl/test-server.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Data R2DBC smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-data-r2dbc\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\truntimeOnly(\"io.r2dbc:r2dbc-h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-data-r2dbc-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webflux-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\n\npublic class City {\n\n\t@Id\n\tprivate @Nullable Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String state, String country) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t\tthis.country = country;\n\t}\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/CityController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class CityController {\n\n\tprivate final CityRepository repository;\n\n\tpublic CityController(CityRepository repository) {\n\t\tthis.repository = repository;\n\t}\n\n\t@GetMapping(\"/cities\")\n\tpublic Flux<City> findCities() {\n\t\treturn this.repository.findAll();\n\t}\n\n\t@GetMapping(\"/cities/{id}\")\n\tpublic Mono<City> findCityById(@PathVariable long id) {\n\t\treturn this.repository.findById(id);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface CityRepository extends ReactiveCrudRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/SampleR2dbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleR2dbcApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleR2dbcApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/java/smoketest/data/r2dbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.r2dbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/resources/application.properties",
    "content": "management.endpoint.health.show-details=always\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/resources/data.sql",
    "content": "INSERT INTO CITY (ID, NAME, STATE, COUNTRY) values (2000, 'Washington', 'DC', 'US');\nINSERT INTO CITY (ID, NAME, STATE, COUNTRY) values (2001, 'San Francisco', 'CA', 'US');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/main/resources/schema.sql",
    "content": "CREATE TABLE CITY (\n  id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n  name VARCHAR(30),\n  state  VARCHAR(30),\n  country  VARCHAR(30)\n);\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc/src/test/java/smoketest/data/r2dbc/SampleR2dbcApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport javax.sql.DataSource;\n\nimport net.minidev.json.JSONArray;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.r2dbc.generate-unique-name=true\")\n@AutoConfigureWebTestClient\nclass SampleR2dbcApplicationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Test\n\tvoid citiesEndpointReturnInitialState() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/cities\")\n\t\t\t.exchange()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"$[*].id\")\n\t\t\t.isEqualTo(new JSONArray().appendElement(2000).appendElement(2001));\n\t}\n\n\t@Test\n\tvoid citiesEndpointByIdWithExistingIdReturnCity() {\n\t\tthis.webClient.get().uri(\"/cities/2001\").exchange().expectBody().jsonPath(\"$.name\").isEqualTo(\"San Francisco\");\n\t}\n\n\t@Test\n\tvoid healthEndpointHasR2dbcEntry() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.jsonPath(\"components.r2dbc.status\")\n\t\t\t.isEqualTo(\"UP\")\n\t\t\t.jsonPath(\"components.r2dbc.details.database\")\n\t\t\t.isEqualTo(\"H2\");\n\t}\n\n\t@Test\n\tvoid dataSourceIsNotAutoConfigured() {\n\t\tassertThat(this.applicationContext.getBeansOfType(DataSource.class)).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data R2DBC with Flyway smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-r2dbc\"))\n\timplementation(project(\":starter:spring-boot-starter-flyway\"))\n\n\truntimeOnly(\"org.flywaydb:flyway-database-postgresql\")\n\truntimeOnly(\"org.postgresql:postgresql\")\n\truntimeOnly(\"org.postgresql:r2dbc-postgresql\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-r2dbc-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-flyway-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-r2dbc\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/dockerTest/java/smoketest/data/r2dbc/CityRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.r2dbc.test.autoconfigure.DataR2dbcTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CityRepository}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataR2dbcTest\nclass CityRepositoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic PostgreSQLContainer postgresql = TestImage.container(PostgreSQLContainer.class)\n\t\t.withDatabaseName(\"test_flyway\");\n\n\t@Autowired\n\tprivate CityRepository repository;\n\n\t@Test\n\tvoid databaseHasBeenInitialized() {\n\t\tStepVerifier.create(this.repository.findByState(\"DC\").filter((city) -> city.getName().equals(\"Washington\")))\n\t\t\t.consumeNextWith((city) -> assertThat(city.getId()).isNotNull())\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/main/java/smoketest/data/r2dbc/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\n\npublic class City {\n\n\t@Id\n\tprivate @Nullable Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String state, String country) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t\tthis.country = country;\n\t}\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/main/java/smoketest/data/r2dbc/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface CityRepository extends ReactiveCrudRepository<City, Long> {\n\n\tFlux<City> findByState(String state);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/main/java/smoketest/data/r2dbc/SampleR2dbcFlywayApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleR2dbcFlywayApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleR2dbcFlywayApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/main/java/smoketest/data/r2dbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.r2dbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/main/resources/application.properties",
    "content": "spring.r2dbc.url=r2dbc:postgresql://user:secret@localhost/test_flyway\n\nspring.flyway.url=jdbc:postgresql://localhost/test_flyway\nspring.flyway.user=user\nspring.flyway.password=secret"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-flyway/src/main/resources/db/migration/V1__init.sql",
    "content": "CREATE TABLE CITY (\n  id      INTEGER PRIMARY KEY,\n  name    VARCHAR(30),\n  state   VARCHAR(30),\n  country VARCHAR(30)\n);\n\nINSERT INTO CITY (ID, NAME, STATE, COUNTRY) values (2000, 'Washington', 'DC', 'US');\nINSERT INTO CITY (ID, NAME, STATE, COUNTRY) values (2001, 'San Francisco', 'CA', 'US');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data R2DBC with Liquibase smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-r2dbc\"))\n\timplementation(project(\":starter:spring-boot-starter-liquibase\"))\n\n\truntimeOnly(\"org.postgresql:postgresql\")\n\truntimeOnly(\"org.postgresql:r2dbc-postgresql\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-data-r2dbc-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-liquibase-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-postgresql\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-r2dbc\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/dockerTest/java/smoketest/data/r2dbc/CityRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.r2dbc.test.autoconfigure.DataR2dbcTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link CityRepository}.\n *\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Testcontainers(disabledWithoutDocker = true)\n@DataR2dbcTest\nclass CityRepositoryTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic PostgreSQLContainer postgresql = TestImage.container(PostgreSQLContainer.class)\n\t\t.withDatabaseName(\"test_liquibase\");\n\n\t@Autowired\n\tprivate CityRepository repository;\n\n\t@Test\n\tvoid databaseHasBeenInitialized() {\n\t\tStepVerifier.create(this.repository.findByState(\"DC\").filter((city) -> city.getName().equals(\"Washington\")))\n\t\t\t.consumeNextWith((city) -> assertThat(city.getId()).isNotNull())\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/main/java/smoketest/data/r2dbc/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\n\npublic class City {\n\n\t@Id\n\tprivate @Nullable Long id;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String state, String country) {\n\t\tthis.name = name;\n\t\tthis.state = state;\n\t\tthis.country = country;\n\t}\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/main/java/smoketest/data/r2dbc/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport reactor.core.publisher.Flux;\n\nimport org.springframework.data.repository.reactive.ReactiveCrudRepository;\n\npublic interface CityRepository extends ReactiveCrudRepository<City, Long> {\n\n\tFlux<City> findByState(String state);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/main/java/smoketest/data/r2dbc/SampleR2dbcLiquibaseApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.r2dbc;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleR2dbcLiquibaseApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleR2dbcLiquibaseApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/main/java/smoketest/data/r2dbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.r2dbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/main/resources/application.properties",
    "content": "spring.r2dbc.url=r2dbc:postgresql://user:secret@localhost/test_liquibase\n\nspring.liquibase.url=jdbc:postgresql://localhost/test_liquibase\nspring.liquibase.user=user\nspring.liquibase.password=secret"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-r2dbc-liquibase/src/main/resources/db/changelog/db.changelog-master.yaml",
    "content": "databaseChangeLog:\n  - changeSet:\n      id: 1\n      author: snicoll\n      changes:\n        - createTable:\n            tableName: city\n            columns:\n              - column:\n                  name: id\n                  type: int\n                  autoIncrement: true\n                  constraints:\n                    primaryKey: true\n                    nullable: false\n              - column:\n                  name: name\n                  type: varchar(30)\n              - column:\n                  name: state\n                  type: varchar(30)\n              - column:\n                  name: country\n                  type: varchar(30)\n  - changeSet:\n      id: 2\n      author: snicoll\n      changes:\n        - insert:\n            tableName: city\n            columns:\n              - column:\n                  name: name\n                  value: Washington\n              - column:\n                  name: state\n                  value: DC\n              - column:\n                  name: country\n                  value: US\n        - insert:\n            tableName: city\n            columns:\n              - column:\n                  name: name\n                  value: San Francisco\n              - column:\n                  name: state\n                  value: CA\n              - column:\n                  name: country\n                  value: US"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Data Redis smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-redis\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-test\"))\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":module:spring-boot-data-redis-test\"))\n\tdockerTestImplementation(project(\":module:spring-boot-reactor\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"io.projectreactor:reactor-test\")\n\tdockerTestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\tdockerTestImplementation(\"org.junit.platform:junit-platform-engine\")\n\tdockerTestImplementation(\"org.junit.platform:junit-platform-launcher\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"redis.clients:jedis\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/dockerTest/java/smoketest/data/redis/SampleRedisApplicationJedisSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.redis.test.autoconfigure.DataRedisTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.redis.core.RedisOperations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Redis using Jedis with SSL.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\n@ClassPathExclusions(\"lettuce-core-*.jar\")\n@DataRedisTest\nclass SampleRedisApplicationJedisSslTests {\n\n\tprivate static final Charset CHARSET = StandardCharsets.UTF_8;\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(\"classpath:ssl/test-ca.crt\")\n\tstatic RedisContainer redis = TestImage.container(SecureRedisContainer.class);\n\n\t@Autowired\n\tprivate RedisOperations<Object, Object> operations;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tPersonHash personHash = new PersonHash();\n\t\tpersonHash.setDescription(\"Look, new @DataRedisTest!\");\n\t\tassertThat(personHash.getId()).isNull();\n\t\tPersonHash savedEntity = this.exampleRepository.save(personHash);\n\t\tassertThat(savedEntity.getId()).isNotNull();\n\t\tassertThat(this.operations\n\t\t\t.execute((org.springframework.data.redis.connection.RedisConnection connection) -> connection.keyCommands()\n\t\t\t\t.exists((\"persons:\" + savedEntity.getId()).getBytes(CHARSET))))\n\t\t\t.isTrue();\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/dockerTest/java/smoketest/data/redis/SampleRedisApplicationReactiveSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport java.time.Duration;\nimport java.util.UUID;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.redis.core.ReactiveRedisOperations;\n\n/**\n * Smoke tests for Redis using reactive operations and SSL.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\n@SpringBootTest\nclass SampleRedisApplicationReactiveSslTests {\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(\"classpath:ssl/test-ca.crt\")\n\tstatic RedisContainer redis = TestImage.container(SecureRedisContainer.class);\n\n\t@Autowired\n\tprivate ReactiveRedisOperations<Object, Object> operations;\n\n\t@Test\n\tvoid testRepository() {\n\t\tString id = UUID.randomUUID().toString();\n\t\tStepVerifier.create(this.operations.opsForValue().set(id, \"Hello World\"))\n\t\t\t.expectNext(Boolean.TRUE)\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tStepVerifier.create(this.operations.opsForValue().get(id))\n\t\t\t.expectNext(\"Hello World\")\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t\tStepVerifier.create(this.operations.execute((action) -> action.serverCommands().flushDb()))\n\t\t\t.expectNext(\"OK\")\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/dockerTest/java/smoketest/data/redis/SampleRedisApplicationSslTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.PemKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.PemTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.data.redis.core.RedisOperations;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Smoke tests for Redis with SSL.\n *\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\n@SpringBootTest\nclass SampleRedisApplicationSslTests {\n\n\tprivate static final Charset CHARSET = StandardCharsets.UTF_8;\n\n\t@Container\n\t@ServiceConnection\n\t@PemKeyStore(certificate = \"classpath:ssl/test-client.crt\", privateKey = \"classpath:ssl/test-client.key\")\n\t@PemTrustStore(\"classpath:ssl/test-ca.crt\")\n\tstatic RedisContainer redis = TestImage.container(SecureRedisContainer.class);\n\n\t@Autowired\n\tprivate RedisOperations<Object, Object> operations;\n\n\t@Autowired\n\tprivate SampleRepository exampleRepository;\n\n\t@Test\n\tvoid testRepository() {\n\t\tPersonHash personHash = new PersonHash();\n\t\tpersonHash.setDescription(\"Look, new @DataRedisTest!\");\n\t\tassertThat(personHash.getId()).isNull();\n\t\tPersonHash savedEntity = this.exampleRepository.save(personHash);\n\t\tassertThat(savedEntity.getId()).isNotNull();\n\t\tassertThat(this.operations\n\t\t\t.execute((org.springframework.data.redis.connection.RedisConnection connection) -> connection.keyCommands()\n\t\t\t\t.exists((\"persons:\" + savedEntity.getId()).getBytes(CHARSET))))\n\t\t\t.isTrue();\n\t\tthis.exampleRepository.deleteAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/dockerTest/java/smoketest/data/redis/SecureRedisContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link RedisContainer} for Redis with SSL configuration.\n *\n * @author Scott Frederick\n */\nclass SecureRedisContainer extends RedisContainer {\n\n\tSecureRedisContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.crt\"), \"/ssl/server.crt\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-server.key\"), \"/ssl/server.key\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"/ssl/test-ca.crt\"), \"/ssl/ca.crt\");\n\t\twithCommand(\"redis-server --tls-port 6379 --port 0 \"\n\t\t\t\t+ \"--tls-cert-file /ssl/server.crt --tls-key-file /ssl/server.key --tls-ca-cert-file /ssl/ca.crt\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/main/java/smoketest/data/redis/PersonHash.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.annotation.Id;\nimport org.springframework.data.redis.core.RedisHash;\n\n@RedisHash(\"persons\")\npublic class PersonHash {\n\n\t@Id\n\tprivate @Nullable String id;\n\n\tprivate @Nullable String description;\n\n\tpublic @Nullable String getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable String id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getDescription() {\n\t\treturn this.description;\n\t}\n\n\tpublic void setDescription(@Nullable String description) {\n\t\tthis.description = description;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/main/java/smoketest/data/redis/SampleRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleRedisApplication {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/main/java/smoketest/data/redis/SampleRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport org.springframework.data.repository.CrudRepository;\n\ninterface SampleRepository extends CrudRepository<PersonHash, String> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/main/java/smoketest/data/redis/SampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.redis;\n\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\n\nimport org.springframework.data.redis.connection.RedisConnection;\nimport org.springframework.data.redis.core.RedisOperations;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class SampleService {\n\n\tprivate static final Charset CHARSET = StandardCharsets.UTF_8;\n\n\tprivate final RedisOperations<Object, Object> operations;\n\n\tpublic SampleService(RedisOperations<Object, Object> operations) {\n\t\tthis.operations = operations;\n\t}\n\n\tpublic boolean hasRecord(PersonHash personHash) {\n\t\treturn this.operations.execute((RedisConnection connection) -> connection.keyCommands()\n\t\t\t.exists((\"persons:\" + personHash.getId()).getBytes(CHARSET)));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/main/java/smoketest/data/redis/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.redis;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/test/resources/ssl/test-ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFhjCCA26gAwIBAgIUfIkk29IT9OpbgfjL8oRIPSLjUcAwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlmaWNh\ndGUgQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAusN2\nKzQQUUxZSiI3ZZuZohFwq2KXSUNPdJ6rgD3/YKNTDSZXKZPO53kYPP0DXf0sm3CH\ncyWSWVabyimZYuPWena1MElSL4ZpJ9WwkZoOQ3bPFK1utz6kMOwrgAUcky8H/rIK\nj2JEBhkSHUIGr57NjUEwG1ygaSerM8RzWw1PtMq+C8LOu3v94qzE3NDg1QRpyvV9\nOmsLsjISd0ZmAJNi9vmiEH923KnPyiqnQmWKpYicdgQmX1GXylS22jZqAwaOkYGj\nX8UdeyvrohkZkM0hn9uaSufQGEW4yKACn3PkjJtzi8drBIyjIi9YcAzBxZB9oVKq\nXZMlltgO2fDMmIJi0Ngt0Ci7fCoEMqSocKyDKML6YLr9UWtx4bfsrk+rVO9Q/D/v\n8RKgstv7dCf2KWRX3ZJEC0IBHS5gLNq0qqqVcGx3LcSyhdiKJOtSwAnNkHMh+jSQ\nxLSlBjcSqTPiGTRK/Rddl+xnU/mBgk7ZBGNrUFaD5McMFjddS7Ih82aHnpQ1gekW\nnUGv+Tm/G68h2BvZ5U2q+RfeOCgRW9i/AYW2jgT7IFnfjyUXgBQveauMAchomqFE\nVLe95ZgViF6vmH34EKo3w9L5TQiwk/r53YlM7TSOTyDqx66t4zGYDsVMicpKmzi4\n2Rp8EpErARRyREUIKSvWs9O9+uT3+7arNLgHe5ECAwEAAaOBgTB/MB0GA1UdDgQW\nBBRVMLDVqPECWaH6GruL9E52VcTrPjAfBgNVHSMEGDAWgBRVMLDVqPECWaH6GruL\n9E52VcTrPjAPBgNVHRMBAf8EBTADAQH/MCwGA1UdEQQlMCOCC2V4YW1wbGUuY29t\ngglsb2NhbGhvc3SCCTEyNy4wLjAuMTANBgkqhkiG9w0BAQsFAAOCAgEAeSpjCL3j\n2GIFBNKr/5amLOYa0kZ6r1dJs+K6xvMsUvsBJ/QQsV5nYDMIoV/NYUd8SyYV4lEj\n7LHX5ZbmJrvPk30LGEBG/5Vy2MIATrQrQ14S4nXtEdSnBvTQwPOOaHc+2dTp3YpM\nf4ffELKWyispTifx1eqdiUJhURKeQBh+3W7zpyaiN4vJaqEDKGgFQtHA/OyZL2hZ\nBpxHB0zpb2iDHV8MeyfOT7HQWUk6p13vdYm6EnyJT8fzWvE+TqYNbqFmB+CLRSXy\nR3p1yaeTd4LnVknJ0UBKqEyul3ziHZDhKhBpwdglYOQz4eWjSFhikX9XZ8NaI38Q\nQqLZVn0DsH2ztkjrQrUVgK2xn4aUuqoLDk4Hu6h5baUn+f2GLuzx+EXc/i3ikYvw\nY3JyufOgw6nGGFG+/QXEj85XtLPhN7Wm42z2e/BGzi0MLl65sfpEDXvFTA72Yzws\nOYaeg/HxeYwUHQgs2fKl/LgV4chntSCvTqfNl6OnQafD/ISJNpx3xWR3HwF+ypFG\nUaLE+e1soqEJbzL31U/6pypHLsj8Y8r9hJbZXo2ibnhjFV6fypUAP0rbIzaoWcrJ\nT0Sbliz+KQTMzCcubiAi4bI/kZ5FJ4kkaHqUpIWzlx1h2WVJ65ASFDjBWb8eVmB6\nDyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/test/resources/ssl/test-ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6w3YrNBBRTFlK\nIjdlm5miEXCrYpdJQ090nquAPf9go1MNJlcpk87neRg8/QNd/SybcIdzJZJZVpvK\nKZli49Z6drUwSVIvhmkn1bCRmg5Dds8UrW63PqQw7CuABRyTLwf+sgqPYkQGGRId\nQgavns2NQTAbXKBpJ6szxHNbDU+0yr4Lws67e/3irMTc0ODVBGnK9X06awuyMhJ3\nRmYAk2L2+aIQf3bcqc/KKqdCZYqliJx2BCZfUZfKVLbaNmoDBo6RgaNfxR17K+ui\nGRmQzSGf25pK59AYRbjIoAKfc+SMm3OLx2sEjKMiL1hwDMHFkH2hUqpdkyWW2A7Z\n8MyYgmLQ2C3QKLt8KgQypKhwrIMowvpguv1Ra3Hht+yuT6tU71D8P+/xEqCy2/t0\nJ/YpZFfdkkQLQgEdLmAs2rSqqpVwbHctxLKF2Iok61LACc2QcyH6NJDEtKUGNxKp\nM+IZNEr9F12X7GdT+YGCTtkEY2tQVoPkxwwWN11LsiHzZoeelDWB6RadQa/5Ob8b\nryHYG9nlTar5F944KBFb2L8BhbaOBPsgWd+PJReAFC95q4wByGiaoURUt73lmBWI\nXq+YffgQqjfD0vlNCLCT+vndiUztNI5PIOrHrq3jMZgOxUyJykqbOLjZGnwSkSsB\nFHJERQgpK9az07365Pf7tqs0uAd7kQIDAQABAoICAAthB10ggfICHdqXdRqavWST\nfXLjweXz1O59EGPy4xFnQhMmB99/ovaVeTWWENN0LniWBZqtalpJHZrWqALPcOzr\nOKTlgr1kihmkOmrUoRPZNErFOl6t0WEtsoTNSu1oyyrofB46VXytoF3p/PBMU6fM\nlfrEzP07LoIr8P9WM0oHpEahKulfZ5uc/S2bCGfSKgP0qxmZFhBYXqmnv2U/laMI\nmKg6q+pL6l4d9SzldOobBbVnEVNzbDUmrjFjaVgf2SXiaSrXnrE3ftbUgqtA5FCS\nF7eCojooXVbT8PT4Ia+zdPnKP6n6S6I0kkXZcSDxacYffEPRSFQFe/opYr3UC+Mk\n1/UmOnoI8X8+N9SPcVD9cbVQUzBuuXfTy+LMx9mg3QxFebRSRre22xSOSlM7MF9B\n6MPeNgwCk3Z0NTr+IedGfyA+d6+iHTMGnv0hF4b4UkcXbC3HdeR3K4hf+msGD2oG\n7JF423T/d7t+g883y4CZm7p096apR8cCLIe2HKSwcYbKhft7LkAdm8kpnqkr5ER1\nanI7RDmucrx3HgrXeuCz9Uai6EMU6jNU1MAEBVeu4jz1rlO4e9zS2Ak68AwIz0zI\ntl5el3paHjlRYY6YTslM5qjGerJt19IyHvZxXXIzF7JdF7w1nSK9bjvninALJl49\nYZAPRIbyQ8P6DLqiDNBFAoIBAQDvQoow86vNg6zHdb8eBC10l2Y6M5DAKTWPE8RJ\nn0td1TLwEHzKvkR25v6yGKABbBO1+7ABACCqA8rkcB7M5jugak/kR9vuDrFPAsqf\nlgckf1Up7ekDheTH8X1VSDiRZPv07UElO0M3aFeMVR/xi9Wae8C3WZo9dT2wKnM0\nd0Acr4Kt4SYm1Dw7kuh+Y1L/vvWuryPm1btxhfKO6JN5v2W8DTrqVkxuxYEM1VnR\n69LfauLVico2q8EGXmQTth/Iok5wj1qI6kmrlgQR+eSY1qgNk1qzwjJVsbSmAOL8\n6Y9Ksct53bEN6DIdYRE/SrEVCz/FY1Pry2DNTjdiwImaSOZ3AoIBAQDH1KRkqsET\nYUnPJxp9pHWlynicEVE/Y7FFhhtpUKzhY1nZ+NsNy91FrZiyx5Os7pSxhLNID8g5\nxKCOfYd7qdvZCg/5bMXhtagQ3gwa/wyuyamc29dKkCpHDz/GkoEkgVe6eYu1GNdR\niNpY5ye5T9fBE1s3odbDcnRVeHAP7vqz5z17JKrlqZVhbLYlR4qGHmAogq7vWlyd\nIR5qLoXMgyqq5OHl1GaaiqfViBpJeoEWYze0cARUWOcrJRblJYS03WHMuLDG5RZd\n5nmf2xwEcMgW5AX7+GB8CdXRVZy6OZcGn7TU9+xnBJA2LbzxJlHBXjWEd8Uma2Al\n+ohlDbGrd8g3AoIBAHsWzGlqstREDbt/xBb5Jzl4OktvA+UYTkmRbcZCgU+Aw3fl\nw426XRaeuCF/sbGJnIpfNakOG7/bu6HSXMYlHD/m8bsLjQXn4Sg4021OjdYk+/da\nQiph09VZU5VwVknWnhjfhkhVOLtknsW/dXOa8QVM7VRmcId1rYrYC/TN9NnNIXm6\n/xmyzloHtjxvdN/Fqjd4OwwioRBCTQtgc56K7RfV5p1wUFocmcu0Z0UsAYyXPKOH\nA9Ukf2V7YhkR9UAO4DPgTD9r6QKxZt6opQZMSKDTUjJwkdysU7ejdSOQNPvEhF3p\nw5DYCBA9Q9Y/4uJkqyYtd5szQlXdC3lufFw3bPkCggEBAKPA3GpmB0xjWEG6UJoP\nUB1pWwbBpivk/Rr097eI1fLpIHNf29plalE0HcK7i4eWByGllekCjdjRCaVattCe\n9DraZRbHjS0WWMBhxdfFk9YUCbsx6C4BD7QlieSmn8+TcpmsCtF/psr4870Qx9uy\n0yI0Q3bGV6DYRP7ZcDOOacFNSHOGK8mB+5jXpjfMdXbMo43u8X3RNb3JqwvmTdy2\nzBs47ukQ8nfIEhsIqkn2apw2+CoT9WhNZjpT7XwgD6zLEd7apnqGtpqCSL63pjD5\nXu5rM4A1HJPo11/w4Ts2AE38SAqRlBcjhS3wszmGZk6obgC8yUFfkm3s7SKqYyMZ\nSGcCggEBAO0IDB/h1meZ2y+6bSsCVaDSxdRl0JF0CDUYVTANQsJ+q7u7CpF9xOo8\nYNrSy8eM0K6RMY/3WbTm+4z9tOldxEV2dn+29oVeMKkgpJYo0k2Au3wTMI2xMyyl\nHZ+ZttsqSZsj2CPx83LMaPwKdzVjwA7alVx4P+AkQKn7jGJgidj5xyw0G3gnzdfT\nnGzuitQFlcrcPyrVHAAmRhIw+B5CsvMFlM8PAvojN7burGswjWGeZjkgqoLvKlgq\njRMGzLTzF9Pay7P/D/pWQwPVGiseJq+QVIA+iILpy9Zb9T6DnBFaPFGOKAduzVU9\nlTLiho2DATppaxNUQKh/5k70hzbipDg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/test/resources/ssl/test-client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh\nsRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7\nb8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0\nmnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV\n+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf\nNNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5\ndwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud\nDgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF\nN5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e\nMN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5\n1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs\nj9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3\nWyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO\nBJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM\nIEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS\nhlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I\nLVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8\nptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW\npgywiOifs5JbcCt0ZQ0=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/test/resources/ssl/test-client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N\n5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N\ngml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv\nP5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9\n0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry\nnAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh\n0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD\nw3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk\ntb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b\nfOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ\nzBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS\nbUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5\nFgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi\ntn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX\nGAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy\nvfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs\nRpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q\nF32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3\nwomWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b\npbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ\nQMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX\nLRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp\nKpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t\np/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77\nv16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6\nOdl4vjNOncXMZCLPHQ+bKWaf\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/test/resources/ssl/test-server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL\nBQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm\naWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow\nLzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b\nCIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV\nj5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte\nN0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT\n//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a\nDnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs\nMwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud\nDgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6\nGruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6\nOOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ\nR0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx\nt2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo\njJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC\nf1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G\n9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG\nHSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK\njaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+\nx8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg\n/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE\netL+7y0mkeQhVF+Kmy4=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-redis/src/test/resources/ssl/test-server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0\ncx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS\n55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl\nE5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL\n7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ\nGD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71\npHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ\nuY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0\n2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD\n8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU\nZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c\nCrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG\naTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k\nNccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb\nIR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+\njetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ\nyVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi\nY+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y\nV4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ\n1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2\nX/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb\nYFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q\nMYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm\nCZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1\nvsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH\nr5O3ZAgigZs/ZtKW/U4=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Data REST smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-jpa\"))\n\timplementation(project(\":starter:spring-boot-starter-data-rest\")) {\n\t\texclude module: \"spring-boot-starter-tomcat\"\n\t}\n\timplementation(\"com.h2database:h2\")\n\n\truntimeOnly(project(\":starter:spring-boot-starter-jetty\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-data-rest-test\"))\n\n\ttestRuntimeOnly(\"com.jayway.jsonpath:json-path\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/SampleDataRestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDataRestApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleDataRestApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/domain/City.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest.domain;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.SequenceGenerator;\nimport org.jspecify.annotations.Nullable;\n\n@Entity\npublic class City implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SequenceGenerator(name = \"city_generator\", sequenceName = \"city_sequence\", initialValue = 23)\n\t@GeneratedValue(generator = \"city_generator\")\n\tprivate @Nullable Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String state;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String country;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String map;\n\n\tprotected City() {\n\t}\n\n\tpublic City(String name, String country, String state, String map) {\n\t\tthis.name = name;\n\t\tthis.country = country;\n\t\tthis.state = state;\n\t\tthis.map = map;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getState() {\n\t\treturn this.state;\n\t}\n\n\tpublic String getCountry() {\n\t\treturn this.country;\n\t}\n\n\tpublic String getMap() {\n\t\treturn this.map;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getName() + \",\" + getState() + \",\" + getCountry();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/domain/Hotel.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest.domain;\n\nimport java.io.Serializable;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.ManyToOne;\nimport jakarta.persistence.SequenceGenerator;\nimport org.hibernate.annotations.NaturalId;\nimport org.jspecify.annotations.Nullable;\n\n@Entity\npublic class Hotel implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\t@Id\n\t@SequenceGenerator(name = \"hotel_generator\", sequenceName = \"hotel_sequence\", initialValue = 28)\n\t@GeneratedValue(generator = \"hotel_generator\")\n\tprivate @Nullable Long id;\n\n\t@ManyToOne(optional = false)\n\t@NaturalId\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate City city;\n\n\t@Column(nullable = false)\n\t@NaturalId\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String address;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String zip;\n\n\tprotected Hotel() {\n\t}\n\n\tpublic Hotel(City city, String name, String address, String zip) {\n\t\tthis.city = city;\n\t\tthis.name = name;\n\t\tthis.address = address;\n\t\tthis.zip = zip;\n\t}\n\n\tpublic City getCity() {\n\t\treturn this.city;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic String getAddress() {\n\t\treturn this.address;\n\t}\n\n\tpublic String getZip() {\n\t\treturn this.zip;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/domain/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.rest.domain;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.rest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/service/CityRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest.service;\n\nimport smoketest.data.rest.domain.City;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.PagingAndSortingRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\n\n@RepositoryRestResource(collectionResourceRel = \"cities\", path = \"cities\")\ninterface CityRepository extends PagingAndSortingRepository<City, Long> {\n\n\tPage<City> findByNameContainingAndCountryContainingAllIgnoringCase(@Param(\"name\") String name,\n\t\t\t@Param(\"country\") String country, Pageable pageable);\n\n\tCity findByNameAndCountryAllIgnoringCase(@Param(\"name\") String name, @Param(\"country\") String country);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/service/CitySearchCriteria.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest.service;\n\nimport java.io.Serializable;\n\nimport org.springframework.util.Assert;\n\npublic class CitySearchCriteria implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate final String name;\n\n\tpublic CitySearchCriteria(String name) {\n\t\tAssert.notNull(name, \"'name' must not be null\");\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/service/HotelRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest.service;\n\nimport smoketest.data.rest.domain.City;\nimport smoketest.data.rest.domain.Hotel;\n\nimport org.springframework.data.repository.PagingAndSortingRepository;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\n\n@RepositoryRestResource(collectionResourceRel = \"hotels\", path = \"hotels\")\ninterface HotelRepository extends PagingAndSortingRepository<Hotel, Long> {\n\n\tHotel findByCityAndName(City city, String name);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/java/smoketest/data/rest/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.data.rest.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/resources/application.properties",
    "content": "spring.data.rest.base-path=/api\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/main/resources/import.sql",
    "content": "--\n-- Sample dataset containing a number of Hotels in various Cities across the world.\n--\n\n-- =================================================================================================\n-- AUSTRALIA\n\n-- Brisbane\ninsert into city(id, country, name, state, map) values (1, 'Australia', 'Brisbane', 'Queensland', '-27.470933, 153.023502')\ninsert into hotel(id, city_id, name, address, zip) values (1, 1, 'Conrad Treasury Place', 'William & George Streets', '4001')\n\n-- Melbourne\ninsert into city(id, country, name, state, map) values (2, 'Australia', 'Melbourne', 'Victoria', '-37.813187, 144.96298')\ninsert into hotel(id, city_id, name, address, zip) values (2, 2, 'The Langham', '1 Southgate Ave, Southbank', '3006')\n\n-- Sydney\ninsert into city(id, country, name, state, map) values (3, 'Australia', 'Sydney', 'New South Wales', '-33.868901, 151.207091')\ninsert into hotel(id, city_id, name, address, zip) values (3, 3, 'Swissotel', '68 Market Street', '2000')\n\n\n-- =================================================================================================\n-- CANADA\n\n-- Montreal\ninsert into city(id, country, name, state, map) values (4, 'Canada', 'Montreal', 'Quebec', '45.508889, -73.554167')\ninsert into hotel(id, city_id, name, address, zip) values (4, 4, 'Ritz Carlton', '1228 Sherbrooke St', 'H3G1H6')\n\n\n-- =================================================================================================\n-- ISRAEL\n\n-- Tel Aviv\ninsert into city(id, country, name, state, map) values (5, 'Israel', 'Tel Aviv', '', '32.066157, 34.777821')\ninsert into hotel(id, city_id, name, address, zip) values (5, 5, 'Hilton Tel Aviv', 'Independence Park', '63405')\n\n\n-- =================================================================================================\n-- JAPAN\n\n-- Tokyo\ninsert into city(id, country, name, state, map) values (6, 'Japan', 'Tokyo', '', '35.689488, 139.691706')\ninsert into hotel(id, city_id, name, address, zip) values (6, 6, 'InterContinental Tokyo Bay', 'Takeshiba Pier', '105')\n\n\n-- =================================================================================================\n-- SPAIN\n\n-- Barcelona\ninsert into city(id, country, name, state, map) values (7, 'Spain', 'Barcelona', 'Catalunya', '41.387917, 2.169919')\ninsert into hotel(id, city_id, name, address, zip) values (7, 7, 'Hilton Diagonal Mar', 'Passeig del Taulat 262-264', '08019')\n\n-- =================================================================================================\n-- SWITZERLAND\n\n-- Neuchatel\ninsert into city(id, country, name, state, map) values (8, 'Switzerland', 'Neuchatel', '', '46.992979, 6.931933')\ninsert into hotel(id, city_id, name, address, zip) values (8, 8, 'Hotel Beaulac', ' Esplanade Leopold-Robert 2', '2000')\n\n\n-- =================================================================================================\n-- UNITED KINGDOM\n\n-- Bath\ninsert into city(id, country, name, state, map) values (9, 'UK', 'Bath', 'Somerset', '51.381428, -2.357454')\ninsert into hotel(id, city_id, name, address, zip) values (9, 9, 'The Bath Priory Hotel', 'Weston Road', 'BA1 2XT')\ninsert into hotel(id, city_id, name, address, zip) values (10, 9, 'Bath Travelodge', 'Rossiter Road, Widcombe Basin', 'BA2 4JP')\n\n-- London\ninsert into city(id, country, name, state, map) values (10, 'UK', 'London', '', '51.500152, -0.126236')\ninsert into hotel(id, city_id, name, address, zip) values (11, 10, 'Melia White House', 'Albany Street', 'NW1 3UP')\n\n-- Southampton\ninsert into city(id, country, name, state, map) values (11, 'UK', 'Southampton', 'Hampshire', '50.902571, -1.397238')\ninsert into hotel(id, city_id, name, address, zip) values (12, 11, 'Chilworth Manor', 'The Cottage, Southampton Business Park', 'SO16 7JF')\n\n\n-- =================================================================================================\n-- USA\n\n-- Atlanta\ninsert into city(id, country, name, state, map) values (12, 'USA', 'Atlanta', 'GA', '33.748995, -84.387982')\ninsert into hotel(id, city_id, name, address, zip) values (13, 12, 'Marriott Courtyard', 'Tower Place, Buckhead', '30305')\n\n-- Chicago\ninsert into city(id, country, name, state, map) values (13, 'USA', 'Chicago', 'IL', '41.878114, -87.629798')\ninsert into hotel(id, city_id, name, address, zip) values (16, 13, 'Hotel Allegro', '171 West Randolph Street', '60601')\n\n-- Eau Claire\ninsert into city(id, country, name, state, map) values (14, 'USA', 'Eau Claire', 'WI', '44.811349, -91.498494')\ninsert into hotel(id, city_id, name, address, zip) values (17, 14, 'Sea Horse Inn', '2106 N Clairemont Ave', '54703')\ninsert into hotel(id, city_id, name, address, zip) values (18, 14, 'Super 8 Eau Claire Campus Area', '1151 W Macarthur Ave', '54701')\n\n-- Hollywood\ninsert into city(id, country, name, state, map) values (15, 'USA', 'Hollywood', 'FL', '26.011201, -80.14949')\ninsert into hotel(id, city_id, name, address, zip) values (19, 15, 'Westin Diplomat', '3555 S. Ocean Drive', '33019')\n\n-- Miami\ninsert into city(id, country, name, state, map) values (16, 'USA', 'Miami', 'FL', '25.788969, -80.226439')\ninsert into hotel(id, city_id, name, address, zip) values (20, 16, 'Conrad Miami', '1395 Brickell Ave', '33131')\n\n-- Melbourne\ninsert into city(id, country, name, state, map) values (17, 'USA', 'Melbourne', 'FL', '28.083627, -80.608109')\ninsert into hotel(id, city_id, name, address, zip) values (21, 17, 'Radisson Suite Hotel Oceanfront', '3101 North Hwy', '32903')\n\n-- New York\ninsert into city(id, country, name, state, map) values (18, 'USA', 'New York', 'NY', '40.714353, -74.005973')\ninsert into hotel(id, city_id, name, address, zip) values (22, 18, 'W Union Hotel', 'Union Square, Manhattan', '10011')\ninsert into hotel(id, city_id, name, address, zip) values (23, 18, 'W Lexington Hotel', 'Lexington Ave, Manhattan', '10011')\ninsert into hotel(id, city_id, name, address, zip) values (24, 18, '70 Park Avenue Hotel', '70 Park Avenue', '10011')\n\n-- Palm Bay\ninsert into city(id, country, name, state, map) values (19, 'USA', 'Palm Bay', 'FL', '28.034462, -80.588665')\ninsert into hotel(id, city_id, name, address, zip) values (25, 19, 'Jameson Inn', '890 Palm Bay Rd NE', '32905')\n\n-- San Francisco\ninsert into city(id, country, name, state, map) values (20, 'USA', 'San Francisco', 'CA', '37.77493, -122.419415')\ninsert into hotel(id, city_id, name, address, zip) values (26, 20, 'Marriot Downtown', '55 Fourth Street', '94103')\n\n-- Washington\ninsert into city(id, country, name, state, map) values (21, 'USA', 'Washington', 'DC', '38.895112, -77.036366')\ninsert into hotel(id, city_id, name, address, zip) values (27, 21, 'Hotel Rouge', '1315 16th Street NW', '20036')\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/test/java/smoketest/data/rest/SampleDataRestApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.data.rest.domain.City;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test to run the application.\n *\n * @author Oliver Gierke\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@AutoConfigureMockMvc\n// Separate profile for web tests to avoid clashing databases\nclass SampleDataRestApplicationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testHome() {\n\t\tassertThat(this.mvc.get().uri(\"/api\")).hasStatusOk().bodyText().contains(\"hotels\");\n\t}\n\n\t@Test\n\tvoid findByNameAndCountry() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/api/cities/search/findByNameAndCountryAllIgnoringCase?name=Melbourne&country=Australia\"))\n\t\t\t.hasStatusOk()\n\t\t\t.bodyJson()\n\t\t\t.extractingPath(\"$\")\n\t\t\t.convertTo(City.class)\n\t\t\t.satisfies((city) -> {\n\t\t\t\tassertThat(city.getName()).isEqualTo(\"Melbourne\");\n\t\t\t\tassertThat(city.getState()).isEqualTo(\"Victoria\");\n\t\t\t});\n\t}\n\n\t@Test\n\tvoid findByContaining() {\n\t\tassertThat(this.mvc.get()\n\t\t\t.uri(\"/api/cities/search/findByNameContainingAndCountryContainingAllIgnoringCase?name=&country=UK\"))\n\t\t\t.hasStatusOk()\n\t\t\t.bodyJson()\n\t\t\t.extractingPath(\"_embedded.cities\")\n\t\t\t.asArray()\n\t\t\t.hasSize(3);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/test/java/smoketest/data/rest/service/CityRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.data.rest.service;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.data.rest.domain.City;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link CityRepository}.\n *\n * @author Oliver Gierke\n * @author Andy Wilkinson\n */\n@SpringBootTest\nclass CityRepositoryIntegrationTests {\n\n\t@Autowired\n\tCityRepository repository;\n\n\t@Test\n\tvoid findsFirstPageOfCities() {\n\t\tPage<City> cities = this.repository.findAll(PageRequest.of(0, 10));\n\t\tassertThat(cities.getTotalElements()).isGreaterThan(20L);\n\t}\n\n\t@Test\n\tvoid findByNameAndCountry() {\n\t\tCity city = this.repository.findByNameAndCountryAllIgnoringCase(\"Melbourne\", \"Australia\");\n\t\tassertThat(city).isNotNull();\n\t\tassertThat(city.getName()).isEqualTo(\"Melbourne\");\n\t}\n\n\t@Test\n\tvoid findContaining() {\n\t\tPage<City> cities = this.repository.findByNameContainingAndCountryContainingAllIgnoringCase(\"\", \"UK\",\n\t\t\t\tPageRequest.of(0, 10));\n\t\tassertThat(cities.getTotalElements()).isEqualTo(3L);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-data-rest/src/test/resources/application-scratch.properties",
    "content": "spring.datasource.url: jdbc:h2:mem:restdb\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot DevTools smoke test\"\n\nconfigurations {\n\tdevelopmentOnly\n\truntimeClasspath.extendsFrom developmentOnly\n}\n\ndependencies {\n\tdevelopmentOnly project(\":module:spring-boot-devtools\")\n\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/java/smoketest/devtools/Message.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.devtools;\n\npublic final class Message {\n\n\t/**\n\t * Sample message.\n\t */\n\tpublic static String MESSAGE = \"Message\";\n\n\tprivate Message() {\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/java/smoketest/devtools/MyController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.devtools;\n\nimport jakarta.annotation.PostConstruct;\n\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class MyController {\n\n\t@PostConstruct\n\tpublic void slowRestart() throws InterruptedException {\n\t\tThread.sleep(5000);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/java/smoketest/devtools/SampleDevToolsApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.devtools;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleDevToolsApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleDevToolsApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/java/smoketest/devtools/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.devtools;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/resources/application.properties",
    "content": "# Enable remote support, for local development you don't need this line\nspring.devtools.remote.secret=secret\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/resources/public/public.txt",
    "content": "public file\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/main/resources/static/css/application.css",
    "content": "h1 {\n\tcolor: green;\n}\n\n.content {\n\tfont-family: sans-serif;\n\tborder-top: 3px solid red;\n\tpadding-top: 30px;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-devtools/src/test/java/smoketest/devtools/SampleDevToolsApplicationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.devtools;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SampleDevToolsApplication}.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleDevToolsApplicationIntegrationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testStaticResource() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/css/application.css\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"color: green;\");\n\t}\n\n\t@Test\n\tvoid testPublicResource() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/public.txt\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"public file\");\n\t}\n\n\t@Test\n\tvoid testClassResource() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/application.properties\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Flyway smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-data-jpa\"))\n\timplementation(project(\":starter:spring-boot-starter-flyway\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-flyway-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/java/smoketest/flyway/Person.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.flyway;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.SequenceGenerator;\nimport org.jspecify.annotations.Nullable;\n\n@Entity\npublic class Person {\n\n\t@Id\n\t@SequenceGenerator(name = \"person_generator\", sequenceName = \"person_sequence\", allocationSize = 1)\n\t@GeneratedValue(generator = \"person_generator\")\n\tprivate @Nullable Long id;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String firstName;\n\n\t@Column(nullable = false)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String lastName;\n\n\tpublic String getFirstName() {\n\t\treturn this.firstName;\n\t}\n\n\tpublic void setFirstName(String firstName) {\n\t\tthis.firstName = firstName;\n\t}\n\n\tpublic String getLastName() {\n\t\treturn this.lastName;\n\t}\n\n\tpublic void setLastName(String lastname) {\n\t\tthis.lastName = lastname;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Person [firstName=\" + this.firstName + \", lastName=\" + this.lastName + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/java/smoketest/flyway/PersonRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.flyway;\n\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface PersonRepository extends CrudRepository<Person, Long> {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/java/smoketest/flyway/SampleFlywayApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.flyway;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleFlywayApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleFlywayApplication.class, args);\n\t}\n\n\t@Bean\n\tpublic CommandLineRunner runner(PersonRepository repository) {\n\t\treturn (args) -> System.err.println(repository.findAll());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/java/smoketest/flyway/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.flyway;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nspring.jpa.hibernate.ddl-auto=validate\nspring.jpa.open-in-view=true\nspring.h2.console.enabled=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/resources/data.sql",
    "content": "insert into PERSON (first_name, last_name) values ('Phillip', 'Webb');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/main/resources/db/migration/V1__init.sql",
    "content": "CREATE TABLE PERSON (\n\tid BIGINT GENERATED BY DEFAULT AS IDENTITY,\n\tfirst_name varchar(255) not null,\n\tlast_name varchar(255) not null\n);\n\ncreate sequence person_sequence start with 1 increment by 1;\n\ninsert into PERSON (first_name, last_name) values ('Dave', 'Syer');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-flyway/src/test/java/smoketest/flyway/SampleFlywayApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.flyway;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\nclass SampleFlywayApplicationTests {\n\n\t@Autowired\n\tprivate JdbcTemplate template;\n\n\t@Test\n\tvoid testDefaultSettings() {\n\t\tassertThat(this.template.queryForObject(\"SELECT COUNT(*) from PERSON\", Integer.class)).isEqualTo(2);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot GraphQL smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-graphql\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-graphql-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/GreetingController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.springframework.graphql.data.method.annotation.Argument;\nimport org.springframework.graphql.data.method.annotation.QueryMapping;\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class GreetingController {\n\n\tprivate final GreetingService greetingService;\n\n\tpublic GreetingController(GreetingService greetingService) {\n\t\tthis.greetingService = greetingService;\n\t}\n\n\t@QueryMapping\n\tpublic String greeting(@Argument String name) {\n\t\treturn this.greetingService.greet(name);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/GreetingService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class GreetingService {\n\n\t@PreAuthorize(\"hasRole('ADMIN')\")\n\tpublic String greet(String name) {\n\t\treturn \"Hello, \" + name + \"!\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/Project.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport java.util.Objects;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class Project {\n\n\tprivate String slug;\n\n\tprivate String name;\n\n\tpublic Project(String slug, String name) {\n\t\tthis.slug = slug;\n\t\tthis.name = name;\n\t}\n\n\tpublic String getSlug() {\n\t\treturn this.slug;\n\t}\n\n\tpublic void setSlug(String slug) {\n\t\tthis.slug = slug;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object o) {\n\t\tif (this == o) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tProject project = (Project) o;\n\t\treturn this.slug.equals(project.slug);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn Objects.hash(this.slug);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/ProjectController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.springframework.graphql.data.method.annotation.Argument;\nimport org.springframework.graphql.data.method.annotation.QueryMapping;\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class ProjectController {\n\n\tprivate final List<Project> projects;\n\n\tpublic ProjectController() {\n\t\tthis.projects = Arrays.asList(new Project(\"spring-boot\", \"Spring Boot\"),\n\t\t\t\tnew Project(\"spring-graphql\", \"Spring GraphQL\"), new Project(\"spring-framework\", \"Spring Framework\"));\n\t}\n\n\t@QueryMapping\n\tpublic Optional<Project> project(@Argument String slug) {\n\t\treturn this.projects.stream().filter((project) -> project.getSlug().equals(slug)).findFirst();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/SampleGraphQlApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGraphQlApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGraphQlApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/SecurityConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.DefaultSecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\n@EnableWebSecurity\n@EnableMethodSecurity(prePostEnabled = true)\npublic class SecurityConfig {\n\n\t@Bean\n\tpublic DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) {\n\t\treturn http.csrf(CsrfConfigurer::disable)\n\t\t\t// Demonstrate that method security works\n\t\t\t// Best practice to use both for defense in depth\n\t\t\t.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll())\n\t\t\t.httpBasic(withDefaults())\n\t\t\t.build();\n\t}\n\n\t@Bean\n\t@SuppressWarnings(\"deprecation\")\n\tpublic InMemoryUserDetailsManager userDetailsService() {\n\t\tUser.UserBuilder userBuilder = User.withDefaultPasswordEncoder();\n\t\tUserDetails rob = userBuilder.username(\"rob\").password(\"rob\").roles(\"USER\").build();\n\t\tUserDetails admin = userBuilder.username(\"admin\").password(\"admin\").roles(\"USER\", \"ADMIN\").build();\n\t\treturn new InMemoryUserDetailsManager(rob, admin);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/java/smoketest/graphql/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.graphql;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/main/resources/graphql/schema.graphqls",
    "content": "type Query {\n    greeting(name: String! = \"Spring\"): String!\n    project(slug: ID!): Project\n}\n\n\"\"\" A Project in the Spring portfolio \"\"\"\ntype Project {\n    \"\"\" Unique string id used in URLs \"\"\"\n    slug: ID!\n    \"\"\" Project name \"\"\"\n    name: String!\n}"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/test/java/smoketest/graphql/GreetingControllerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.graphql.execution.ErrorType;\nimport org.springframework.graphql.test.tester.HttpGraphQlTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@AutoConfigureHttpGraphQlTester\n@AutoConfigureMockMvc\nclass GreetingControllerTests {\n\n\t@Autowired\n\tprivate HttpGraphQlTester graphQlTester;\n\n\t@Test\n\tvoid shouldUnauthorizeAnonymousUsers() {\n\t\tthis.graphQlTester.documentName(\"greeting\").variable(\"name\", \"Brian\").execute().errors().satisfy((errors) -> {\n\t\t\tassertThat(errors).hasSize(1);\n\t\t\tassertThat(errors.get(0).getErrorType()).isEqualTo(ErrorType.UNAUTHORIZED);\n\t\t});\n\t}\n\n\t@Test\n\tvoid shouldGreetWithSpecificName() {\n\t\tHttpGraphQlTester authenticated = withAdminCredentials(this.graphQlTester);\n\t\tauthenticated.documentName(\"greeting\")\n\t\t\t.variable(\"name\", \"Brian\")\n\t\t\t.execute()\n\t\t\t.path(\"greeting\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Hello, Brian!\");\n\t}\n\n\t@Test\n\tvoid shouldGreetWithDefaultName() {\n\t\tHttpGraphQlTester authenticated = withAdminCredentials(this.graphQlTester);\n\t\tauthenticated.document(\"{ greeting }\")\n\t\t\t.execute()\n\t\t\t.path(\"greeting\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Hello, Spring!\");\n\t}\n\n\tprivate HttpGraphQlTester withAdminCredentials(HttpGraphQlTester graphQlTester) {\n\t\treturn graphQlTester.mutate()\n\t\t\t.webTestClient(\n\t\t\t\t\t(httpClient) -> httpClient.defaultHeaders((headers) -> headers.setBasicAuth(\"admin\", \"admin\")))\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/test/java/smoketest/graphql/ProjectControllerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.graphql.test.autoconfigure.GraphQlTest;\nimport org.springframework.graphql.test.tester.GraphQlTester;\n\n@GraphQlTest(ProjectController.class)\nclass ProjectControllerTests {\n\n\t@Autowired\n\tprivate GraphQlTester graphQlTester;\n\n\t@Test\n\tvoid shouldFindSpringGraphQl() {\n\t\tthis.graphQlTester.document(\"{ project(slug: \\\"spring-graphql\\\") { name } }\")\n\t\t\t.execute()\n\t\t\t.path(\"project.name\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Spring GraphQL\");\n\t}\n\n\t@Test\n\tvoid shouldNotFindUnknownProject() {\n\t\tthis.graphQlTester.document(\"{ project(slug: \\\"spring-unknown\\\") { name } }\")\n\t\t\t.execute()\n\t\t\t.path(\"project.name\")\n\t\t\t.pathDoesNotExist();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/test/java/smoketest/graphql/SampleGraphQlApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.graphql;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.graphql.test.tester.HttpGraphQlTester;\n\n/**\n * Tests for {@link SampleGraphQlApplication}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureHttpGraphQlTester\nclass SampleGraphQlApplicationTests {\n\n\t@Autowired\n\tprivate HttpGraphQlTester graphQlTester;\n\n\t@Test\n\tvoid shouldFindSpringGraphQl() {\n\t\tthis.graphQlTester.document(\"{ project(slug: \\\"spring-graphql\\\") { name } }\")\n\t\t\t.execute()\n\t\t\t.path(\"project.name\")\n\t\t\t.entity(String.class)\n\t\t\t.isEqualTo(\"Spring GraphQL\");\n\t}\n\n\t@Test\n\tvoid shouldNotFindUnknownProject() {\n\t\tthis.graphQlTester.document(\"{ project(slug: \\\"spring-unknown\\\") { name } }\")\n\t\t\t.execute()\n\t\t\t.path(\"project.name\")\n\t\t\t.pathDoesNotExist();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-graphql/src/test/resources/graphql-test/greeting.graphql",
    "content": "query greeting($name: String!) {\n    greeting(name: $name)\n}"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC client smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-client\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client/src/main/java/smoketest/grpcclient/SampleGrpcClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcclient;\n\nimport smoketest.grpcclient.proto.HelloReply;\nimport smoketest.grpcclient.proto.HelloRequest;\nimport smoketest.grpcclient.proto.HelloWorldGrpc.HelloWorldBlockingStub;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.grpc.client.ImportGrpcClients;\n\n@SpringBootApplication\n@ImportGrpcClients(types = HelloWorldBlockingStub.class)\npublic class SampleGrpcClientApplication {\n\n\t@Bean\n\tApplicationRunner applicationRunner(HelloWorldBlockingStub hello) {\n\t\treturn (args) -> {\n\t\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"Spring\").build();\n\t\t\tHelloReply reply = hello.sayHello(request);\n\t\t\tSystem.out.println(\">>> \" + reply.getMessage());\n\t\t};\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcClientApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client/src/main/java/smoketest/grpcclient/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcclient;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcclient.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHello (HelloRequest) returns (HelloReply) {}\n    rpc StreamHello(HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client/src/main/resources/application.yaml",
    "content": "spring:\n  grpc:\n    client:\n      channel:\n        default:\n          target: \"static://localhost:9090\"\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client/src/test/java/smoketest/grpcclient/SampleGrpcClientApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcclient;\n\nimport java.time.Duration;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport io.grpc.stub.StreamObserver;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport smoketest.grpcclient.SampleGrpcClientApplicationTests.MockServerInitializer;\nimport smoketest.grpcclient.proto.HelloReply;\nimport smoketest.grpcclient.proto.HelloRequest;\nimport smoketest.grpcclient.proto.HelloWorldGrpc;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ApplicationContextInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.grpc.server.NettyGrpcServerFactory;\nimport org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@ContextConfiguration(initializers = MockServerInitializer.class)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleGrpcClientApplicationTests {\n\n\t@Test\n\tvoid applicationRunsAndCallsGrpcServer(CapturedOutput output) {\n\t\tassertThat(output).contains(\">>> Hello 'Spring'\");\n\t}\n\n\tstatic class MockServerInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {\n\n\t\t@Override\n\t\tpublic void initialize(ConfigurableApplicationContext applicationContext) {\n\t\t\tNettyGrpcServerFactory serverFactory = new NettyGrpcServerFactory(\"*:0\", Collections.emptyList(), null,\n\t\t\t\t\tnull, null);\n\t\t\tHelloWorldService helloWorldService = new HelloWorldService();\n\t\t\tserverFactory.addService(helloWorldService.bindService());\n\t\t\tGrpcServerLifecycle lifecycle = new GrpcServerLifecycle(serverFactory, Duration.ofSeconds(30),\n\t\t\t\t\tapplicationContext);\n\t\t\tlifecycle.start();\n\t\t\tString target = \"static://localhost:%s\".formatted(lifecycle.getPort());\n\t\t\tapplicationContext.getEnvironment()\n\t\t\t\t.getPropertySources()\n\t\t\t\t.addFirst(new MapPropertySource(\"grpc\", Map.of(\"spring.grpc.client.channel.default.target\", target)));\n\t\t\tapplicationContext.getBeanFactory().registerSingleton(\"grpcServerLifecyce\", lifecycle);\n\t\t}\n\n\t}\n\n\tstatic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\t\t@Override\n\t\tpublic void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\t\tHelloReply reply = HelloReply.newBuilder().setMessage(\"Hello '%s'\".formatted(request.getName())).build();\n\t\t\tresponseObserver.onNext(reply);\n\t\t\tresponseObserver.onCompleted();\n\t\t}\n\n\t\t@Override\n\t\tpublic void streamHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\t\tthrow new IllegalStateException();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC client and test smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-client\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-grpc-test\"))\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client-test/src/main/java/smoketest/grpcclienttest/SampleGrpcClientTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcclienttest;\n\nimport smoketest.grpcclienttest.proto.HelloReply;\nimport smoketest.grpcclienttest.proto.HelloRequest;\nimport smoketest.grpcclienttest.proto.HelloWorldGrpc.HelloWorldBlockingStub;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.grpc.client.ImportGrpcClients;\n\n@SpringBootApplication\n@ImportGrpcClients(types = HelloWorldBlockingStub.class)\npublic class SampleGrpcClientTestApplication {\n\n\t@Bean\n\tApplicationRunner applicationRunner(HelloWorldBlockingStub hello) {\n\t\treturn (args) -> {\n\t\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"Spring\").build();\n\t\t\tHelloReply reply = hello.sayHello(request);\n\t\t\tSystem.out.println(\">>> \" + reply.getMessage());\n\t\t};\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcClientTestApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client-test/src/main/java/smoketest/grpcclienttest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcclienttest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client-test/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcclienttest.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHello (HelloRequest) returns (HelloReply) {}\n    rpc StreamHello(HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-client-test/src/test/java/smoketest/grpcclienttest/SampleGrpcClientTestApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcclienttest;\n\nimport io.grpc.stub.StreamObserver;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport smoketest.grpcclienttest.SampleGrpcClientTestApplicationTests.HelloWorldService;\nimport smoketest.grpcclienttest.proto.HelloReply;\nimport smoketest.grpcclienttest.proto.HelloRequest;\nimport smoketest.grpcclienttest.proto.HelloWorldGrpc;\n\nimport org.springframework.boot.grpc.test.autoconfigure.AutoConfigureTestGrpcTransport;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Import;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@AutoConfigureTestGrpcTransport\n@Import(HelloWorldService.class)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleGrpcClientTestApplicationTests {\n\n\t@Test\n\tvoid callsService(CapturedOutput output) {\n\t\tassertThat(output).contains(\">>> Test hello 'Spring'\");\n\t}\n\n\tstatic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\t\t@Override\n\t\tpublic void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\t\tString message = \"Test hello '%s'\".formatted(request.getName());\n\t\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\t\tresponseObserver.onNext(reply);\n\t\t\tresponseObserver.onCompleted();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC server smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-server\"))\n\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server/src/dockerTest/java/smoketest/grpcserver/SampleGrpcServerApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserver;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.DockerImageName;\nimport smoketest.grpcserver.SampleGrpcServerApplicationTests.GrpcServerStartedEventListener;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for the default Spring gRPC netty server.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(properties = \"spring.grpc.server.port=0\")\n@Testcontainers(disabledWithoutDocker = true)\n@Import(GrpcServerStartedEventListener.class)\nclass SampleGrpcServerApplicationTests {\n\n\t@Autowired\n\tprivate GrpcServerStartedEventListener startedEventListener;\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid test() {\n\t\tint port = this.startedEventListener.getPort();\n\t\tString address = \"host.testcontainers.internal:\" + port;\n\t\torg.testcontainers.Testcontainers.exposeHostPorts(port);\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(\n\t\t\t\tDockerImageName.parse(\"fullstorydev/grpcurl:v1.9.3\"))\n\t\t\t.withNetworkAliases(\"\")\n\t\t\t.withCommand(\"-d\", \"{\\\"name\\\": \\\"spring\\\"}\", \"--plaintext\", address, \"HelloWorld/SayHello\")\n\t\t\t.withStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy())) {\n\t\t\tcontainer.start();\n\t\t\tassertThat(container.getLogs()).contains(\"\\\"message\\\": \\\"Hello 'spring'\\\"\");\n\t\t}\n\n\t}\n\n\tstatic class GrpcServerStartedEventListener implements ApplicationListener<GrpcServerStartedEvent> {\n\n\t\tprivate int port;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(GrpcServerStartedEvent event) {\n\t\t\tthis.port = event.getPort();\n\t\t}\n\n\t\tint getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server/src/main/java/smoketest/grpcserver/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserver;\n\nimport io.grpc.stub.StreamObserver;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.grpcserver.proto.HelloReply;\nimport smoketest.grpcserver.proto.HelloRequest;\nimport smoketest.grpcserver.proto.HelloWorldGrpc;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\n\n@Service\npublic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\tprivate static Log logger = LogFactory.getLog(HelloWorldService.class);\n\n\t@Override\n\tpublic void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"sayHello \" + name);\n\t\tAssert.isTrue(!name.startsWith(\"error\"), () -> \"Bad name: \" + name);\n\t\tAssert.state(!name.startsWith(\"internal\"), \"Internal error\");\n\t\tString message = \"Hello '%s'\".formatted(name);\n\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\tresponseObserver.onNext(reply);\n\t\tresponseObserver.onCompleted();\n\t}\n\n\t@Override\n\tpublic void streamHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"streamHello \" + name);\n\t\tint count = 0;\n\t\twhile (count < 10) {\n\t\t\tString message = \"Hello(\" + count + \") '%s'\".formatted(name);\n\t\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\t\tresponseObserver.onNext(reply);\n\t\t\tcount++;\n\t\t\ttry {\n\t\t\t\tThread.sleep(100L);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tresponseObserver.onError(ex);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tresponseObserver.onCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server/src/main/java/smoketest/grpcserver/SampleGrpcServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserver;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGrpcServerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcServerApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server/src/main/java/smoketest/grpcserver/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcserver;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcserver.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHello (HelloRequest) returns (HelloReply) {}\n    rpc StreamHello(HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-netty-shaded/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC server netty shaded smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-server\")) {\n\t\texclude(group: \"io.grpc\", module: \"grpc-netty-shaded\")\n\t}\n\timplementation(\"io.grpc:grpc-netty-shaded\")\n\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-netty-shaded/src/dockerTest/java/smoketest/grpcservernettyshaded/SampleGrpcServerNettyShadedApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservernettyshaded;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.DockerImageName;\nimport smoketest.grpcservernettyshaded.SampleGrpcServerNettyShadedApplicationTests.GrpcServerStartedEventListener;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring gRPC with a shaded netty server.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(properties = \"spring.grpc.server.port=0\")\n@Testcontainers(disabledWithoutDocker = true)\n@Import(GrpcServerStartedEventListener.class)\nclass SampleGrpcServerNettyShadedApplicationTests {\n\n\t@Autowired\n\tprivate GrpcServerStartedEventListener startedEventListener;\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid test() {\n\t\tint port = this.startedEventListener.getPort();\n\t\tString address = \"host.testcontainers.internal:\" + port;\n\t\torg.testcontainers.Testcontainers.exposeHostPorts(port);\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(\n\t\t\t\tDockerImageName.parse(\"fullstorydev/grpcurl:v1.9.3\"))\n\t\t\t.withCommand(\"-d\", \"{\\\"name\\\": \\\"spring\\\"}\", \"--plaintext\", address, \"HelloWorld/SayHello\")\n\t\t\t.withStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy())) {\n\t\t\tcontainer.start();\n\t\t\tassertThat(container.getLogs()).contains(\"\\\"message\\\": \\\"Hello 'spring'\\\"\");\n\t\t}\n\n\t}\n\n\tstatic class GrpcServerStartedEventListener implements ApplicationListener<GrpcServerStartedEvent> {\n\n\t\tprivate int port;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(GrpcServerStartedEvent event) {\n\t\t\tthis.port = event.getPort();\n\t\t}\n\n\t\tint getPort() {\n\t\t\treturn this.port;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-netty-shaded/src/main/java/smoketest/grpcservernettyshaded/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservernettyshaded;\n\nimport io.grpc.stub.StreamObserver;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.grpcservernettyshaded.proto.HelloReply;\nimport smoketest.grpcservernettyshaded.proto.HelloRequest;\nimport smoketest.grpcservernettyshaded.proto.HelloWorldGrpc;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\n\n@Service\npublic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\tprivate static Log logger = LogFactory.getLog(HelloWorldService.class);\n\n\t@Override\n\tpublic void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"sayHello \" + name);\n\t\tAssert.isTrue(!name.startsWith(\"error\"), () -> \"Bad name: \" + name);\n\t\tAssert.state(!name.startsWith(\"internal\"), \"Internal error\");\n\t\tString message = \"Hello '%s'\".formatted(name);\n\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\tresponseObserver.onNext(reply);\n\t\tresponseObserver.onCompleted();\n\t}\n\n\t@Override\n\tpublic void streamHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"streamHello \" + name);\n\t\tint count = 0;\n\t\twhile (count < 10) {\n\t\t\tString message = \"Hello(\" + count + \") '%s'\".formatted(name);\n\t\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\t\tresponseObserver.onNext(reply);\n\t\t\tcount++;\n\t\t\ttry {\n\t\t\t\tThread.sleep(100L);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tresponseObserver.onError(ex);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tresponseObserver.onCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-netty-shaded/src/main/java/smoketest/grpcservernettyshaded/SampleGrpcServerNettyShadedApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservernettyshaded;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGrpcServerNettyShadedApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcServerNettyShadedApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-netty-shaded/src/main/java/smoketest/grpcservernettyshaded/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcservernettyshaded;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-netty-shaded/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcservernettyshaded.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHello (HelloRequest) returns (HelloReply) {}\n    rpc StreamHello(HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC server oauth smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-oauth2-authorization-server\"))\n\timplementation(project(\":starter:spring-boot-starter-oauth2-resource-server\"))\n\timplementation(project(\":starter:spring-boot-starter-grpc-server\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-grpc-client\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-grpc-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-oauth2-client\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/main/java/smoketest/grpcserveroauth/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserveroauth;\n\nimport io.grpc.stub.StreamObserver;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.grpcserveroauth.proto.HelloReply;\nimport smoketest.grpcserveroauth.proto.HelloRequest;\nimport smoketest.grpcserveroauth.proto.HelloWorldGrpc;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\n\n@Service\npublic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\tprivate static Log logger = LogFactory.getLog(HelloWorldService.class);\n\n\t@Override\n\tpublic void sayHelloProfileScope(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloProfileScope\", request, responseObserver);\n\t}\n\n\t@Override\n\tpublic void sayHelloEmailScope(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloEmailScope\", request, responseObserver);\n\t}\n\n\t@Override\n\tpublic void sayHelloAuthenticated(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloAuthenticated\", request, responseObserver);\n\t}\n\n\tpublic void sayHello(String methodName, HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(methodName + \" \" + name);\n\t\tAssert.isTrue(!name.startsWith(\"error\"), () -> \"Bad name: \" + name);\n\t\tAssert.state(!name.startsWith(\"internal\"), \"Internal error\");\n\t\tString message = \"%s '%s'\".formatted(methodName, name);\n\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\tresponseObserver.onNext(reply);\n\t\tresponseObserver.onCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/main/java/smoketest/grpcserveroauth/SampleGrpcServerOAuthApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserveroauth;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGrpcServerOAuthApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcServerOAuthApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/main/java/smoketest/grpcserveroauth/SecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserveroauth;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.security.AuthenticationProcessInterceptor;\nimport org.springframework.grpc.server.security.GrpcSecurity;\nimport org.springframework.grpc.server.security.RequestMapperConfigurer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\npublic class SecurityConfiguration {\n\n\t@Bean\n\t@GlobalServerInterceptor\n\tAuthenticationProcessInterceptor securityInterceptor(GrpcSecurity grpcSecurity) throws Exception {\n\t\treturn grpcSecurity.authorizeRequests(this::authorizeGrpcRequests)\n\t\t\t.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()))\n\t\t\t.build();\n\t}\n\n\tprivate void authorizeGrpcRequests(RequestMapperConfigurer requests) {\n\t\trequests.methods(\"HelloWorld/SayHelloProfileScope\").hasAuthority(\"SCOPE_profile\");\n\t\trequests.methods(\"HelloWorld/SayHelloEmailScope\").hasAuthority(\"SCOPE_email\");\n\t\trequests.methods(\"HelloWorld/SayHelloAuthenticated\").authenticated();\n\t\trequests.methods(\"grpc.*/*\").permitAll();\n\t\trequests.allRequests().denyAll();\n\t}\n\n\t@Bean\n\tpublic SecurityFilterChain securityFilterChain(HttpSecurity http) {\n\t\thttp.oauth2AuthorizationServer((authorizationServer) -> {\n\t\t\thttp.securityMatcher(authorizationServer.getEndpointsMatcher());\n\t\t\tauthorizationServer.oidc(withDefaults());\n\t\t});\n\t\thttp.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(withDefaults()));\n\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());\n\t\thttp.csrf((csrf) -> csrf.disable());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/main/java/smoketest/grpcserveroauth/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcserveroauth;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcserveroauth.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHelloProfileScope (HelloRequest) returns (HelloReply) {}\n    rpc SayHelloEmailScope (HelloRequest) returns (HelloReply) {}\n    rpc SayHelloAuthenticated (HelloRequest) returns (HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/main/resources/application.yaml",
    "content": "logging.level.org.springframework.security: TRACE\nspring:\n  security:\n    oauth2:\n      authorizationserver:\n        client:\n          oidc-client:\n            registration:\n              client-id: \"spring\"\n              client-secret: \"{noop}secret\"\n              client-authentication-methods:\n                - \"client_secret_basic\"\n              authorization-grant-types:\n                - \"client_credentials\"\n                - \"refresh_token\"\n              scopes:\n                - \"openid\"\n                - \"profile\"\n      resourceserver:\n        jwt:\n          jwk-set-uri: http://localhost:8080/oauth2/jwks\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-oauth/src/test/java/smoketest/grpcserveroauth/SampleGrpcServerOAuthApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserveroauth;\n\nimport java.util.function.Consumer;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\nimport io.grpc.ManagedChannelBuilder;\nimport io.grpc.Status.Code;\nimport io.grpc.StatusRuntimeException;\nimport io.grpc.reflection.v1.ServerReflectionGrpc.ServerReflectionStub;\nimport io.grpc.reflection.v1.ServerReflectionRequest;\nimport io.grpc.reflection.v1.ServerReflectionResponse;\nimport io.grpc.stub.StreamObserver;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport smoketest.grpcserveroauth.proto.HelloReply;\nimport smoketest.grpcserveroauth.proto.HelloRequest;\nimport smoketest.grpcserveroauth.proto.HelloWorldGrpc.HelloWorldBlockingStub;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.env.Environment;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.ImportGrpcClients;\nimport org.springframework.grpc.client.interceptor.security.BearerTokenAuthenticationInterceptor;\nimport org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;\nimport org.springframework.security.oauth2.client.endpoint.RestClientClientCredentialsTokenResponseClient;\nimport org.springframework.security.oauth2.client.registration.ClientRegistration;\nimport org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;\nimport org.springframework.security.oauth2.client.registration.SupplierClientRegistrationRepository;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;\nimport org.springframework.security.oauth2.jwt.JwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder;\nimport org.springframework.security.oauth2.jwt.NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder;\nimport org.springframework.security.oauth2.jwt.SupplierJwtDecoder;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.util.function.SingletonSupplier;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"spring.grpc.server.port=0\",\n\t\t\t\t\"spring.grpc.client.channel.default.target=static://localhost:${local.grpc.server.port}\",\n\t\t\t\t\"spring.grpc.client.channel.oauth.target=static://localhost:${local.grpc.server.port}\" })\n@DirtiesContext\nclass SampleGrpcServerOAuthApplicationTests {\n\n\t@Autowired\n\t@Qualifier(\"unauthenticatedHelloWorldBlockingStub\")\n\tprivate HelloWorldBlockingStub unuathenticated;\n\n\t@Autowired\n\t@Qualifier(\"oauthHelloWorldBlockingStub\")\n\tprivate HelloWorldBlockingStub oauth;\n\n\t@Autowired\n\tprivate ServerReflectionStub reflection;\n\n\t@Test\n\tvoid whenUnauthenticatedStub() {\n\t\tHelloWorldBlockingStub stub = this.unuathenticated;\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloProfileScope))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloEmailScope))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloAuthenticated))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertCanInvokeReflection();\n\t}\n\n\t@Test\n\tvoid whenOAuth() {\n\t\tHelloWorldBlockingStub stub = this.oauth;\n\t\tassertThat(invoke(stub::sayHelloProfileScope)).isEqualTo(\"sayHelloProfileScope 'Spring'\");\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloEmailScope))\n\t\t\t.satisfies(statusCode(Code.PERMISSION_DENIED));\n\t\tassertThat(invoke(stub::sayHelloAuthenticated)).isEqualTo(\"sayHelloAuthenticated 'Spring'\");\n\t\tassertCanInvokeReflection();\n\t}\n\n\tprivate String invoke(Function<HelloRequest, HelloReply> method) {\n\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"Spring\").build();\n\t\treturn method.apply(request).getMessage();\n\t}\n\n\tprivate void assertCanInvokeReflection() {\n\t\tObservedResponse<ServerReflectionResponse> response = invokeReflection();\n\t\tassertThat(response.getValue()).isNotNull();\n\t\tassertThat(response.getError()).isNull();\n\t}\n\n\tprivate ObservedResponse<ServerReflectionResponse> invokeReflection() {\n\t\tObservedResponse<ServerReflectionResponse> response = new ObservedResponse<>();\n\t\tStreamObserver<ServerReflectionRequest> request = this.reflection.serverReflectionInfo(response);\n\t\trequest.onNext(ServerReflectionRequest.newBuilder().setListServices(\"\").build());\n\t\trequest.onCompleted();\n\t\tresponse.await();\n\t\treturn response;\n\t}\n\n\tprivate Consumer<StatusRuntimeException> statusCode(Code expected) {\n\t\treturn (ex) -> assertThat(ex).extracting(\"status.code\").isEqualTo(expected);\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\t@ImportGrpcClients(types = ServerReflectionStub.class)\n\t@ImportGrpcClients(prefix = \"unauthenticated\", types = HelloWorldBlockingStub.class)\n\t@ImportGrpcClients(target = \"oauth\", prefix = \"oauth\", types = HelloWorldBlockingStub.class)\n\tstatic class GrpcClientTestConfiguration {\n\n\t\t@Bean\n\t\t<B extends ManagedChannelBuilder<B>> GrpcChannelBuilderCustomizer<B> channelSecurityCustomizer(\n\t\t\t\tObjectProvider<ClientRegistrationRepository> clientRegistrationRepository) {\n\t\t\treturn GrpcChannelBuilderCustomizer.matching(\"oauth\", (builder) -> {\n\t\t\t\tSupplier<String> tokenSupplier = SingletonSupplier\n\t\t\t\t\t.of(() -> token(clientRegistrationRepository.getObject()));\n\t\t\t\tbuilder.intercept(new BearerTokenAuthenticationInterceptor(tokenSupplier));\n\t\t\t});\n\t\t}\n\n\t\tprivate String token(ClientRegistrationRepository clientRegistrationRepository) {\n\t\t\tRestClientClientCredentialsTokenResponseClient client = new RestClientClientCredentialsTokenResponseClient();\n\t\t\tClientRegistration registration = clientRegistrationRepository.findByRegistrationId(\"spring\");\n\t\t\tOAuth2ClientCredentialsGrantRequest request = new OAuth2ClientCredentialsGrantRequest(registration);\n\t\t\treturn client.getTokenResponse(request).getAccessToken().getTokenValue();\n\t\t}\n\n\t\t@Bean\n\t\tClientRegistrationRepository lazyClientRegistrationRepository(Environment environment) {\n\t\t\treturn new SupplierClientRegistrationRepository(() -> getClientRegistrationRepository(environment));\n\t\t}\n\n\t\tprivate InMemoryClientRegistrationRepository getClientRegistrationRepository(Environment environment) {\n\t\t\treturn new InMemoryClientRegistrationRepository(ClientRegistration.withRegistrationId(\"spring\")\n\t\t\t\t.clientId(\"spring\")\n\t\t\t\t.clientSecret(\"secret\")\n\t\t\t\t.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)\n\t\t\t\t.scope(\"profile\")\n\t\t\t\t.tokenUri(environment.resolvePlaceholders(\"http://localhost:${local.server.port}/oauth2/token\"))\n\t\t\t\t.build());\n\t\t}\n\n\t\t@Bean\n\t\tSupplierJwtDecoder lazyJwtDecoder(Environment environment) {\n\t\t\treturn new SupplierJwtDecoder(() -> getJwtDecoder(environment));\n\t\t}\n\n\t\tprivate JwtDecoder getJwtDecoder(Environment environment) {\n\t\t\tJwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder\n\t\t\t\t.withJwkSetUri(environment.resolvePlaceholders(\"http://localhost:${local.server.port}/oauth2/jwks\"));\n\t\t\tbuilder.jwsAlgorithms((algorithms) -> algorithms.add(SignatureAlgorithm.from(\"RS256\")));\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n\tstatic class ObservedResponse<T> implements StreamObserver<T> {\n\n\t\tprivate volatile @Nullable T value;\n\n\t\tprivate volatile @Nullable Throwable error;\n\n\t\t@Override\n\t\tpublic synchronized void onNext(T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic synchronized void onError(Throwable error) {\n\t\t\tthis.error = error;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onCompleted() {\n\t\t}\n\n\t\tvoid await() {\n\t\t\tAwaitility.await().until(this::hasResponse);\n\t\t}\n\n\t\tprivate synchronized boolean hasResponse() {\n\t\t\treturn this.value != null || this.error != null;\n\t\t}\n\n\t\t@Nullable T getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Nullable Throwable getError() {\n\t\t\treturn this.error;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC server secure smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-server\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-grpc-client\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-grpc-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/src/main/java/smoketest/grpcserversecure/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserversecure;\n\nimport io.grpc.stub.StreamObserver;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.grpcserversecure.proto.HelloReply;\nimport smoketest.grpcserversecure.proto.HelloRequest;\nimport smoketest.grpcserversecure.proto.HelloWorldGrpc;\n\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\n\n@Service\npublic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\tprivate static Log logger = LogFactory.getLog(HelloWorldService.class);\n\n\t@Override\n\tpublic void sayHelloAdmin(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloAdmin\", request, responseObserver);\n\t}\n\n\t@Override\n\t@PreAuthorize(\"hasAuthority('ROLE_ADMIN')\")\n\tpublic void sayHelloAdminAnnotated(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloAdminAnnotated\", request, responseObserver);\n\t}\n\n\t@Override\n\tpublic void sayHelloUser(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloUser\", request, responseObserver);\n\t}\n\n\t@Override\n\t@PreAuthorize(\"hasAuthority('ROLE_USER')\")\n\tpublic void sayHelloUserAnnotated(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tsayHello(\"sayHelloUserAnnotated\", request, responseObserver);\n\t}\n\n\tpublic void sayHello(String methodName, HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(methodName + \" \" + name);\n\t\tAssert.isTrue(!name.startsWith(\"error\"), () -> \"Bad name: \" + name);\n\t\tAssert.state(!name.startsWith(\"internal\"), \"Internal error\");\n\t\tString message = \"%s '%s'\".formatted(methodName, name);\n\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\tresponseObserver.onNext(reply);\n\t\tresponseObserver.onCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/src/main/java/smoketest/grpcserversecure/SampleGrpcServerSecureApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserversecure;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGrpcServerSecureApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcServerSecureApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/src/main/java/smoketest/grpcserversecure/SecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserversecure;\n\nimport io.grpc.ServerInterceptor;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.grpc.server.GlobalServerInterceptor;\nimport org.springframework.grpc.server.security.GrpcSecurity;\nimport org.springframework.grpc.server.security.RequestMapperConfigurer;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@Configuration(proxyBeanMethods = false)\npublic class SecurityConfiguration {\n\n\t@Bean\n\tInMemoryUserDetailsManager inMemoryUserDetailsManager() {\n\t\tUserDetails user = user(\"user\", \"{noop}userpassword\", \"ROLE_USER\");\n\t\tUserDetails admin = user(\"admin\", \"{noop}adminpassword\", \"ROLE_ADMIN\");\n\t\treturn new InMemoryUserDetailsManager(user, admin);\n\t}\n\n\tprivate UserDetails user(String username, String password, String authority) {\n\t\treturn User.withUsername(username).password(password).authorities(authority).build();\n\t}\n\n\t@Bean\n\t@GlobalServerInterceptor\n\tServerInterceptor securityInterceptor(GrpcSecurity security) throws Exception {\n\t\treturn security.authorizeRequests(this::authorizeRequests)\n\t\t\t.httpBasic(withDefaults())\n\t\t\t.preauth(withDefaults())\n\t\t\t.build();\n\t}\n\n\tprivate void authorizeRequests(RequestMapperConfigurer requests) {\n\t\trequests.methods(\"HelloWorld/SayHelloAdmin\").hasAuthority(\"ROLE_ADMIN\");\n\t\trequests.methods(\"HelloWorld/SayHelloAdminAnnotated\").hasAuthority(\"ROLE_ADMIN\");\n\t\trequests.methods(\"HelloWorld/SayHelloUser\").hasAuthority(\"ROLE_USER\");\n\t\trequests.methods(\"HelloWorld/SayHelloUserAnnotated\").hasAuthority(\"ROLE_USER\");\n\t\trequests.methods(\"grpc.*/*\").permitAll();\n\t\trequests.allRequests().denyAll();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/src/main/java/smoketest/grpcserversecure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcserversecure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcserversecure.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHelloAdmin (HelloRequest) returns (HelloReply) {}\n    rpc SayHelloAdminAnnotated (HelloRequest) returns (HelloReply) {}\n    rpc SayHelloUser (HelloRequest) returns (HelloReply) {}\n    rpc SayHelloUserAnnotated (HelloRequest) returns (HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-secure/src/test/java/smoketest/grpcserversecure/SampleGrpcServerSecureApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserversecure;\n\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\nimport io.grpc.ManagedChannelBuilder;\nimport io.grpc.Status.Code;\nimport io.grpc.StatusRuntimeException;\nimport io.grpc.reflection.v1.ServerReflectionGrpc.ServerReflectionStub;\nimport io.grpc.reflection.v1.ServerReflectionRequest;\nimport io.grpc.reflection.v1.ServerReflectionResponse;\nimport io.grpc.stub.StreamObserver;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport smoketest.grpcserversecure.proto.HelloReply;\nimport smoketest.grpcserversecure.proto.HelloRequest;\nimport smoketest.grpcserversecure.proto.HelloWorldGrpc.HelloWorldBlockingStub;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.grpc.client.GrpcChannelBuilderCustomizer;\nimport org.springframework.grpc.client.ImportGrpcClients;\nimport org.springframework.grpc.client.interceptor.security.BasicAuthenticationInterceptor;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n@SpringBootTest(properties = { \"spring.grpc.server.port=0\",\n\t\t\"spring.grpc.client.channel.default.target=static://localhost:${local.grpc.server.port}\",\n\t\t\"spring.grpc.client.channel.user.target=static://localhost:${local.grpc.server.port}\",\n\t\t\"spring.grpc.client.channel.admin.target=static://localhost:${local.grpc.server.port}\" })\n@DirtiesContext\nclass SampleGrpcServerSecureApplicationTests {\n\n\t@Autowired\n\t@Qualifier(\"unauthenticatedHelloWorldBlockingStub\")\n\tprivate HelloWorldBlockingStub unuathenticated;\n\n\t@Autowired\n\t@Qualifier(\"userAuthenticatedHelloWorldBlockingStub\")\n\tprivate HelloWorldBlockingStub userAuthenticated;\n\n\t@Autowired\n\t@Qualifier(\"adminAuthenticatedHelloWorldBlockingStub\")\n\tprivate HelloWorldBlockingStub adminAuthenticated;\n\n\t@Autowired\n\tprivate ServerReflectionStub reflection;\n\n\t@Test\n\tvoid whenUnauthenticatedStub() {\n\t\tHelloWorldBlockingStub stub = this.unuathenticated;\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloUser))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloUserAnnotated))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloAdmin))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloAdminAnnotated))\n\t\t\t.satisfies(statusCode(Code.UNAUTHENTICATED));\n\t\tassertCanInvokeReflection();\n\t}\n\n\t@Test\n\tvoid whenUserAuthenticatedStub() {\n\t\tHelloWorldBlockingStub stub = this.userAuthenticated;\n\t\tassertThat(invoke(stub::sayHelloUser)).isEqualTo(\"sayHelloUser 'Spring'\");\n\t\tassertThat(invoke(stub::sayHelloUserAnnotated)).isEqualTo(\"sayHelloUserAnnotated 'Spring'\");\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloAdmin))\n\t\t\t.satisfies(statusCode(Code.PERMISSION_DENIED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloAdminAnnotated))\n\t\t\t.satisfies(statusCode(Code.PERMISSION_DENIED));\n\t\tassertCanInvokeReflection();\n\t}\n\n\t@Test\n\tvoid whenAdminAuthenticatedStub() {\n\t\tHelloWorldBlockingStub stub = this.adminAuthenticated;\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloUser))\n\t\t\t.satisfies(statusCode(Code.PERMISSION_DENIED));\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> invoke(stub::sayHelloUserAnnotated))\n\t\t\t.satisfies(statusCode(Code.PERMISSION_DENIED));\n\t\tassertThat(invoke(stub::sayHelloAdmin)).isEqualTo(\"sayHelloAdmin 'Spring'\");\n\t\tassertThat(invoke(stub::sayHelloAdminAnnotated)).isEqualTo(\"sayHelloAdminAnnotated 'Spring'\");\n\t\tassertCanInvokeReflection();\n\t}\n\n\tprivate String invoke(Function<HelloRequest, HelloReply> method) {\n\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"Spring\").build();\n\t\treturn method.apply(request).getMessage();\n\t}\n\n\tprivate void assertCanInvokeReflection() {\n\t\tObservedResponse<ServerReflectionResponse> response = invokeReflection();\n\t\tassertThat(response.getValue()).isNotNull();\n\t\tassertThat(response.getError()).isNull();\n\t}\n\n\tprivate ObservedResponse<ServerReflectionResponse> invokeReflection() {\n\t\tObservedResponse<ServerReflectionResponse> response = new ObservedResponse<>();\n\t\tStreamObserver<ServerReflectionRequest> request = this.reflection.serverReflectionInfo(response);\n\t\trequest.onNext(ServerReflectionRequest.newBuilder().setListServices(\"\").build());\n\t\trequest.onCompleted();\n\t\tresponse.await();\n\t\treturn response;\n\t}\n\n\tprivate Consumer<StatusRuntimeException> statusCode(Code expected) {\n\t\treturn (ex) -> assertThat(ex).extracting(\"status.code\").isEqualTo(expected);\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\t@ImportGrpcClients(types = ServerReflectionStub.class)\n\t@ImportGrpcClients(prefix = \"unauthenticated\", types = HelloWorldBlockingStub.class)\n\t@ImportGrpcClients(target = \"user\", prefix = \"userAuthenticated\", types = HelloWorldBlockingStub.class)\n\t@ImportGrpcClients(target = \"admin\", prefix = \"adminAuthenticated\", types = HelloWorldBlockingStub.class)\n\tstatic class GrpcClientTestConfiguration {\n\n\t\t@Bean\n\t\t<B extends ManagedChannelBuilder<B>> GrpcChannelBuilderCustomizer<B> channelSecurityCustomizer() {\n\t\t\treturn (target, builder) -> {\n\t\t\t\tif (\"user\".equals(target)) {\n\t\t\t\t\tbuilder.intercept(new BasicAuthenticationInterceptor(\"user\", \"userpassword\"));\n\t\t\t\t}\n\t\t\t\tif (\"admin\".equals(target)) {\n\t\t\t\t\tbuilder.intercept(new BasicAuthenticationInterceptor(\"admin\", \"adminpassword\"));\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\tstatic class ObservedResponse<T> implements StreamObserver<T> {\n\n\t\tprivate volatile @Nullable T value;\n\n\t\tprivate volatile @Nullable Throwable error;\n\n\t\t@Override\n\t\tpublic synchronized void onNext(T value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\t@Override\n\t\tpublic synchronized void onError(Throwable error) {\n\t\t\tthis.error = error;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onCompleted() {\n\t\t}\n\n\t\tvoid await() {\n\t\t\tAwaitility.await().until(this::hasResponse);\n\t\t}\n\n\t\tprivate synchronized boolean hasResponse() {\n\t\t\treturn this.value != null || this.error != null;\n\t\t}\n\n\t\t@Nullable T getValue() {\n\t\t\treturn this.value;\n\t\t}\n\n\t\t@Nullable Throwable getError() {\n\t\t\treturn this.error;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC server servlet smoke test\"\n\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-server\")) {\n\t\texclude(group: \"io.grpc\", module: \"grpc-netty-shaded\")\n\t}\n\timplementation(project(\":starter:spring-boot-starter-tomcat\"))\n\timplementation(\"io.grpc:grpc-servlet-jakarta\")\n\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\t\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/src/dockerTest/java/smoketest/grpcserverservlet/SampleGrpcServerServletApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserverservlet;\n\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for Spring gRPC with a servlet server.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@Testcontainers(disabledWithoutDocker = true)\nclass SampleGrpcServerServletApplicationTests {\n\n\t@LocalServerPort\n\tprivate int localServerPort;\n\n\t@Test\n\t@SuppressWarnings(\"resource\")\n\tvoid test() {\n\t\tint port = this.localServerPort;\n\t\tString address = \"host.testcontainers.internal:\" + port;\n\t\torg.testcontainers.Testcontainers.exposeHostPorts(port);\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(\n\t\t\t\tDockerImageName.parse(\"fullstorydev/grpcurl:v1.9.3\"))\n\t\t\t.withCommand(\"-d\", \"{\\\"name\\\": \\\"spring\\\"}\", \"--plaintext\", address, \"HelloWorld/SayHello\")\n\t\t\t.withStartupCheckStrategy(new IndefiniteWaitOneShotStartupCheckStrategy())) {\n\t\t\tcontainer.start();\n\t\t\tassertThat(container.getLogs()).contains(\"\\\"message\\\": \\\"Hello 'spring'\\\"\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/src/main/java/smoketest/grpcserverservlet/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserverservlet;\n\nimport io.grpc.stub.StreamObserver;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.grpcserverservlet.proto.HelloReply;\nimport smoketest.grpcserverservlet.proto.HelloRequest;\nimport smoketest.grpcserverservlet.proto.HelloWorldGrpc;\n\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\n\n@Service\npublic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\tprivate static Log logger = LogFactory.getLog(HelloWorldService.class);\n\n\t@Override\n\tpublic void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"sayHello \" + name);\n\t\tAssert.isTrue(!name.startsWith(\"error\"), () -> \"Bad name: \" + name);\n\t\tAssert.state(!name.startsWith(\"internal\"), \"Internal error\");\n\t\tString message = \"Hello '%s'\".formatted(name);\n\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\tresponseObserver.onNext(reply);\n\t\tresponseObserver.onCompleted();\n\t}\n\n\t@Override\n\tpublic void streamHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"streamHello \" + name);\n\t\tint count = 0;\n\t\twhile (count < 10) {\n\t\t\tString message = \"Hello(\" + count + \") '%s'\".formatted(name);\n\t\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\t\tresponseObserver.onNext(reply);\n\t\t\tcount++;\n\t\t\ttry {\n\t\t\t\tThread.sleep(100L);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tresponseObserver.onError(ex);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tresponseObserver.onCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/src/main/java/smoketest/grpcserverservlet/SampleGrpcServerServletApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcserverservlet;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGrpcServerServletApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcServerServletApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/src/main/java/smoketest/grpcserverservlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcserverservlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcserverservlet.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHello (HelloRequest) returns (HelloReply) {}\n    rpc StreamHello(HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-servlet/src/main/resources/application.properties",
    "content": "server.http2.enabled=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"com.google.protobuf\" version \"${protobufGradlePluginVersion}\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot gRPC server and test smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-grpc-server\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-grpc-test\"))\n}\n\ndef dependenciesBom = project(\":platform:spring-boot-dependencies\").extensions.getByName(\"bom\")\ndef grpcJava = dependenciesBom.getLibrary(\"Grpc Java\")\ndef protobufJava = dependenciesBom.getLibrary(\"Protobuf Java\")\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n\nconfigurations.named { it.startsWith(\"protobufToolsLocator_\") || it.toLowerCase().endsWith(\"protopath\") }.all {\n\textendsFrom(configurations.dependencyManagement)\n}\n\nprotobuf {\n\tprotoc {\n\t\tartifact = \"com.google.protobuf:protoc:${protobufJava.version}\"\n\t}\n\tplugins {\n\t\tgrpc {\n\t\t\tartifact = \"io.grpc:protoc-gen-grpc-java:${grpcJava.version}\"\n\t\t}\n\t}\n\tgenerateProtoTasks {\n\t\tall()*.plugins {\n\t\t\tgrpc {\n\t\t\t\toption '@generated=omit'\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/main/java/smoketest/grpcservertest/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservertest;\n\nimport io.grpc.stub.StreamObserver;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.grpcservertest.proto.HelloReply;\nimport smoketest.grpcservertest.proto.HelloRequest;\nimport smoketest.grpcservertest.proto.HelloWorldGrpc;\n\nimport org.springframework.grpc.server.advice.GrpcAdvice;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\n\n@Service\n@GrpcAdvice\npublic class HelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {\n\n\tprivate static Log logger = LogFactory.getLog(HelloWorldService.class);\n\n\t@Override\n\tpublic void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"sayHello \" + name);\n\t\tAssert.isTrue(!name.startsWith(\"error\"), () -> \"Bad name: \" + name);\n\t\tAssert.state(!name.startsWith(\"internal\"), \"Internal error\");\n\t\tString message = \"Hello '%s'\".formatted(name);\n\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\tresponseObserver.onNext(reply);\n\t\tresponseObserver.onCompleted();\n\t}\n\n\t@Override\n\tpublic void streamHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {\n\t\tString name = request.getName();\n\t\tlogger.info(\"streamHello \" + name);\n\t\tint count = 0;\n\t\twhile (count < 10) {\n\t\t\tString message = \"Hello(\" + count + \") '%s'\".formatted(name);\n\t\t\tHelloReply reply = HelloReply.newBuilder().setMessage(message).build();\n\t\t\tresponseObserver.onNext(reply);\n\t\t\tcount++;\n\t\t\ttry {\n\t\t\t\tThread.sleep(100L);\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tThread.currentThread().interrupt();\n\t\t\t\tresponseObserver.onError(ex);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tresponseObserver.onCompleted();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/main/java/smoketest/grpcservertest/SampleGrpcServerTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservertest;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleGrpcServerTestApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGrpcServerTestApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/main/java/smoketest/grpcservertest/StandardExceptionHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservertest;\n\nimport io.grpc.Status;\nimport io.grpc.Status.Code;\nimport io.grpc.StatusException;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.grpc.server.exception.GrpcExceptionHandler;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class StandardExceptionHandler implements GrpcExceptionHandler {\n\n\t@Override\n\tpublic @Nullable StatusException handleException(Throwable exception) {\n\t\tif (exception instanceof IllegalArgumentException) {\n\t\t\treturn new StatusException(Status.fromCode(Code.INVALID_ARGUMENT).withDescription(exception.getMessage()));\n\t\t}\n\t\tif (exception instanceof IllegalStateException) {\n\t\t\treturn new StatusException(Status.fromCode(Code.INTERNAL).withDescription(exception.getMessage()));\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/main/java/smoketest/grpcservertest/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.grpcservertest;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/main/proto/hello.proto",
    "content": "syntax = \"proto3\";\n\noption java_package = \"smoketest.grpcservertest.proto\";\noption java_multiple_files = true;\n\nservice HelloWorld {\n    rpc SayHello (HelloRequest) returns (HelloReply) {}\n    rpc StreamHello(HelloRequest) returns (stream HelloReply) {}\n}\n\nmessage HelloRequest {\n    string name = 1;\n}\n\nmessage HelloReply {\n    string message = 1;\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/test/java/smoketest/grpcservertest/SampleGrpcServerTestApplicationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservertest;\n\nimport io.grpc.ManagedChannel;\nimport io.grpc.netty.NettyChannelBuilder;\nimport org.junit.jupiter.api.Test;\nimport smoketest.grpcservertest.proto.HelloReply;\nimport smoketest.grpcservertest.proto.HelloRequest;\nimport smoketest.grpcservertest.proto.HelloWorldGrpc;\nimport smoketest.grpcservertest.proto.HelloWorldGrpc.HelloWorldBlockingStub;\n\nimport org.springframework.boot.grpc.test.autoconfigure.LocalGrpcServerPort;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(properties = \"spring.grpc.server.port=0\")\nclass SampleGrpcServerTestApplicationIntegrationTests {\n\n\t@LocalGrpcServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid callsService() {\n\t\tManagedChannel channel = NettyChannelBuilder.forTarget(\"localhost:%s\".formatted(this.port))\n\t\t\t.usePlaintext()\n\t\t\t.build();\n\t\ttry {\n\t\t\tHelloWorldBlockingStub hello = HelloWorldGrpc.newBlockingStub(channel);\n\t\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"Spring\").build();\n\t\t\tHelloReply reply = hello.sayHello(request);\n\t\t\tassertThat(reply.getMessage()).isEqualTo(\"Hello 'Spring'\");\n\t\t}\n\t\tfinally {\n\t\t\tchannel.shutdown();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-grpc-server-test/src/test/java/smoketest/grpcservertest/SampleGrpcServerTestApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.grpcservertest;\n\nimport io.grpc.Status.Code;\nimport io.grpc.StatusRuntimeException;\nimport org.junit.jupiter.api.Test;\nimport smoketest.grpcservertest.proto.HelloReply;\nimport smoketest.grpcservertest.proto.HelloRequest;\nimport smoketest.grpcservertest.proto.HelloWorldGrpc.HelloWorldBlockingStub;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.grpc.test.autoconfigure.AutoConfigureTestGrpcTransport;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.grpc.client.ImportGrpcClients;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n@SpringBootTest\n@AutoConfigureTestGrpcTransport\n@ImportGrpcClients(types = HelloWorldBlockingStub.class)\nclass SampleGrpcServerTestApplicationTests {\n\n\t@Autowired\n\tprivate HelloWorldBlockingStub hello;\n\n\t@Test\n\tvoid sayHello() {\n\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"Spring\").build();\n\t\tHelloReply reply = this.hello.sayHello(request);\n\t\tassertThat(reply.getMessage()).isEqualTo(\"Hello 'Spring'\");\n\t}\n\n\t@Test\n\tvoid sayHelloWhenBadName() {\n\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"errorThing\").build();\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> this.hello.sayHello(request))\n\t\t\t.satisfies((ex) -> assertThat(ex.getStatus().getCode()).isEqualTo(Code.INVALID_ARGUMENT));\n\t}\n\n\t@Test\n\tvoid sayHelloWhenInternalError() {\n\t\tHelloRequest request = HelloRequest.newBuilder().setName(\"internal\").build();\n\t\tassertThatExceptionOfType(StatusRuntimeException.class).isThrownBy(() -> this.hello.sayHello(request))\n\t\t\t.satisfies((ex) -> assertThat(ex.getStatus().getCode()).isEqualTo(Code.INTERNAL));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot HATEOAS smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-hateoas\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-hateoas-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/SampleHateoasApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.hateoas;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleHateoasApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleHateoasApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/domain/Customer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.hateoas.domain;\n\npublic class Customer {\n\n\tprivate final Long id;\n\n\tprivate final String firstName;\n\n\tprivate final String lastName;\n\n\tpublic Customer(Long id, String firstName, String lastName) {\n\t\tthis.id = id;\n\t\tthis.firstName = firstName;\n\t\tthis.lastName = lastName;\n\t}\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getFirstName() {\n\t\treturn this.firstName;\n\t}\n\n\tpublic String getLastName() {\n\t\treturn this.lastName;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/domain/CustomerRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.hateoas.domain;\n\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\npublic interface CustomerRepository {\n\n\tList<Customer> findAll();\n\n\t@Nullable Customer findOne(Long id);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/domain/InMemoryCustomerRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.hateoas.domain;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.stereotype.Repository;\nimport org.springframework.util.ObjectUtils;\n\n@Repository\npublic class InMemoryCustomerRepository implements CustomerRepository {\n\n\tprivate final List<Customer> customers = new ArrayList<>();\n\n\tpublic InMemoryCustomerRepository() {\n\t\tthis.customers.add(new Customer(1L, \"Oliver\", \"Gierke\"));\n\t\tthis.customers.add(new Customer(2L, \"Andy\", \"Wilkinson\"));\n\t\tthis.customers.add(new Customer(2L, \"Dave\", \"Syer\"));\n\t}\n\n\t@Override\n\tpublic List<Customer> findAll() {\n\t\treturn this.customers;\n\t}\n\n\t@Override\n\tpublic @Nullable Customer findOne(Long id) {\n\t\tfor (Customer customer : this.customers) {\n\t\t\tif (ObjectUtils.nullSafeEquals(customer.getId(), id)) {\n\t\t\t\treturn customer;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/domain/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.hateoas.domain;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.hateoas;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/web/CustomerController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.hateoas.web;\n\nimport smoketest.hateoas.domain.Customer;\nimport smoketest.hateoas.domain.CustomerRepository;\n\nimport org.springframework.hateoas.CollectionModel;\nimport org.springframework.hateoas.EntityModel;\nimport org.springframework.hateoas.server.EntityLinks;\nimport org.springframework.hateoas.server.ExposesResourceFor;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\n@RequestMapping(\"/customers\")\n@ExposesResourceFor(Customer.class)\npublic class CustomerController {\n\n\tprivate final CustomerRepository repository;\n\n\tprivate final EntityLinks entityLinks;\n\n\tpublic CustomerController(CustomerRepository repository, EntityLinks entityLinks) {\n\t\tthis.repository = repository;\n\t\tthis.entityLinks = entityLinks;\n\t}\n\n\t@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)\n\tHttpEntity<CollectionModel<Customer>> showCustomers() {\n\t\tCollectionModel<Customer> resources = CollectionModel.of(this.repository.findAll());\n\t\tresources.add(this.entityLinks.linkToCollectionResource(Customer.class));\n\t\treturn new ResponseEntity<>(resources, HttpStatus.OK);\n\t}\n\n\t@GetMapping(path = \"/{id}\", produces = MediaType.APPLICATION_JSON_VALUE)\n\tHttpEntity<EntityModel<Customer>> showCustomer(@PathVariable Long id) {\n\t\tCustomer customer = this.repository.findOne(id);\n\t\tif (customer == null) {\n\t\t\treturn ResponseEntity.notFound().build();\n\t\t}\n\t\tEntityModel<Customer> resource = EntityModel.of(customer);\n\t\tresource.add(this.entityLinks.linkToItemResource(Customer.class, id));\n\t\treturn new ResponseEntity<>(resource, HttpStatus.OK);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/main/java/smoketest/hateoas/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.hateoas.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hateoas/src/test/java/smoketest/hateoas/SampleHateoasApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.hateoas;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleHateoasApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid hasHalLinksWhenAnythingIsAcceptable() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/customers/1\", HttpMethod.GET,\n\t\t\t\tnew HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).startsWith(\"{\\\"_links\\\":{\\\"self\\\":{\\\"href\\\"\");\n\t\tassertThat(entity.getBody()).endsWith(\",\\\"id\\\":1,\\\"firstName\\\":\\\"Oliver\\\",\\\"lastName\\\":\\\"Gierke\\\"}\");\n\t}\n\n\t@Test\n\tvoid hasHalLinksWhenJsonIsAcceptable() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/customers/1\", HttpMethod.GET,\n\t\t\t\tnew HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).startsWith(\"{\\\"_links\\\":{\\\"self\\\":{\\\"href\\\"\");\n\t\tassertThat(entity.getBody()).endsWith(\",\\\"id\\\":1,\\\"firstName\\\":\\\"Oliver\\\",\\\"lastName\\\":\\\"Gierke\\\"}\");\n\t}\n\n\t@Test\n\tvoid producesJsonWhenXmlIsPreferred() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.set(HttpHeaders.ACCEPT, \"application/xml;q=0.9,application/json;q=0.8\");\n\t\tHttpEntity<?> request = new HttpEntity<>(headers);\n\t\tResponseEntity<String> response = this.restTemplate.exchange(\"/customers/1\", HttpMethod.GET, request,\n\t\t\t\tString.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.parseMediaType(\"application/json\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Hibernate smoke test\"\n\ndependencies {\n\timplementation(project(\":module:spring-boot-hibernate\"))\n\timplementation(project(\":starter:spring-boot-starter-freemarker\"))\n\timplementation(project(\":starter:spring-boot-starter-jdbc\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\timplementation(\"jakarta.xml.bind:jakarta.xml.bind-api\")\n\n\truntimeOnly(\"com.h2database:h2\")\n\truntimeOnly(\"jakarta.transaction:jakarta.transaction-api\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/SampleJpaApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleJpaApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJpaApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/domain/Note.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.domain;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.ManyToMany;\nimport jakarta.persistence.SequenceGenerator;\nimport org.jspecify.annotations.Nullable;\n\n@Entity\npublic class Note {\n\n\t@Id\n\t@SequenceGenerator(name = \"note_generator\", sequenceName = \"note_sequence\", initialValue = 5)\n\t@GeneratedValue(generator = \"note_generator\")\n\tprivate @Nullable Long id;\n\n\tprivate @Nullable String title;\n\n\tprivate @Nullable String body;\n\n\t@ManyToMany\n\tprivate List<Tag> tags = new ArrayList<>();\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getTitle() {\n\t\treturn this.title;\n\t}\n\n\tpublic void setTitle(@Nullable String title) {\n\t\tthis.title = title;\n\t}\n\n\tpublic @Nullable String getBody() {\n\t\treturn this.body;\n\t}\n\n\tpublic void setBody(@Nullable String body) {\n\t\tthis.body = body;\n\t}\n\n\tpublic List<Tag> getTags() {\n\t\treturn this.tags;\n\t}\n\n\tpublic void setTags(List<Tag> tags) {\n\t\tthis.tags = tags;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/domain/Tag.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.domain;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.ManyToMany;\nimport jakarta.persistence.SequenceGenerator;\nimport org.jspecify.annotations.Nullable;\n\n@Entity\npublic class Tag {\n\n\t@Id\n\t@SequenceGenerator(name = \"tag_generator\", sequenceName = \"tag_sequence\", initialValue = 4)\n\t@GeneratedValue(generator = \"tag_generator\")\n\tprivate @Nullable Long id;\n\n\tprivate @Nullable String name;\n\n\t@ManyToMany(mappedBy = \"tags\")\n\tprivate List<Note> notes = new ArrayList<>();\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic @Nullable String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic List<Note> getNotes() {\n\t\treturn this.notes;\n\t}\n\n\tpublic void setNotes(List<Note> notes) {\n\t\tthis.notes = notes;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/domain/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jpa.domain;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jpa;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/repository/JpaNoteRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.repository;\n\nimport java.util.List;\n\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.PersistenceContext;\nimport smoketest.jpa.domain.Note;\n\nimport org.springframework.stereotype.Repository;\n\n@Repository\nclass JpaNoteRepository implements NoteRepository {\n\n\t@PersistenceContext\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate EntityManager entityManager;\n\n\t@Override\n\tpublic List<Note> findAll() {\n\t\treturn this.entityManager.createQuery(\"SELECT n FROM Note n\", Note.class).getResultList();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/repository/JpaTagRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.repository;\n\nimport java.util.List;\n\nimport jakarta.persistence.EntityManager;\nimport jakarta.persistence.PersistenceContext;\nimport smoketest.jpa.domain.Tag;\n\nimport org.springframework.stereotype.Repository;\n\n@Repository\nclass JpaTagRepository implements TagRepository {\n\n\t@PersistenceContext\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate EntityManager entityManager;\n\n\t@Override\n\tpublic List<Tag> findAll() {\n\t\treturn this.entityManager.createQuery(\"SELECT t FROM Tag t\", Tag.class).getResultList();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/repository/NoteRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.repository;\n\nimport java.util.List;\n\nimport smoketest.jpa.domain.Note;\n\npublic interface NoteRepository {\n\n\tList<Note> findAll();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/repository/TagRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.repository;\n\nimport java.util.List;\n\nimport smoketest.jpa.domain.Tag;\n\npublic interface TagRepository {\n\n\tList<Tag> findAll();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/repository/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jpa.repository;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/web/IndexController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.web;\n\nimport java.util.List;\n\nimport smoketest.jpa.domain.Note;\nimport smoketest.jpa.repository.NoteRepository;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.servlet.ModelAndView;\n\n@Controller\npublic class IndexController {\n\n\t@Autowired\n\tprivate NoteRepository noteRepository;\n\n\t@GetMapping(\"/\")\n\t@Transactional(readOnly = true)\n\tpublic ModelAndView index() {\n\t\tList<Note> notes = this.noteRepository.findAll();\n\t\tModelAndView modelAndView = new ModelAndView(\"index\");\n\t\tmodelAndView.addObject(\"notes\", notes);\n\t\treturn modelAndView;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/java/smoketest/jpa/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jpa.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/resources/application.properties",
    "content": "spring.jpa.open-in-view=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/resources/import.sql",
    "content": "insert into tag(id, name) values (1, 'Spring projects')\ninsert into tag(id, name) values (2, 'Apache projects')\ninsert into tag(id, name) values (3, 'Open source')\n\ninsert into note(id, title, body) values (1, 'Spring Boot', 'Takes an opinionated view of building production-ready Spring applications.')\ninsert into note(id, title, body) values (2, 'Spring Framework', 'Core support for dependency injection, transaction management, web applications, data access, messaging, testing and more.')\ninsert into note(id, title, body) values (3, 'Spring Integration', 'Extends the Spring programming model to support the well-known Enterprise Integration Patterns.')\ninsert into note(id, title, body) values (4, 'Tomcat', 'Apache Tomcat is an open source software implementation of the Java Servlet and JavaServer Pages technologies.')\n\ninsert into note_tags(notes_id, tags_id) values (1, 1)\ninsert into note_tags(notes_id, tags_id) values (2, 1)\ninsert into note_tags(notes_id, tags_id) values (3, 1)\ninsert into note_tags(notes_id, tags_id) values (1, 3)\ninsert into note_tags(notes_id, tags_id) values (2, 3)\ninsert into note_tags(notes_id, tags_id) values (3, 3)\ninsert into note_tags(notes_id, tags_id) values (4, 2)\ninsert into note_tags(notes_id, tags_id) values (4, 3)\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/main/resources/templates/index.ftlh",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\t<table>\n\t\t<thead>\n\t\t\t<tr>\n\t\t\t\t<td>Title</td>\n\t\t\t\t<td>Body</td>\n\t\t\t\t<td>Tags</td>\n\t\t\t</tr>\n\t\t</thead>\n\t\t<tbody>\n<#list notes as note>\n\t\t\t<tr>\n\t\t\t\t<td>${note.title}</td>\n\t\t\t\t<td>${note.body}</td>\n\t\t\t\t<td>\n<#list note.tags as tag>\n\t\t\t\t\t<span>${tag.name}</span>\n</#list>\n\t\t\t\t</td>\n\t\t\t</tr>\n</#list>\n\t\t</tbody>\n\t</table>\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/test/java/smoketest/jpa/SampleJpaApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;\n\n/**\n * Integration test to run the application.\n *\n * @author Oliver Gierke\n * @author Dave Syer\n */\n@SpringBootTest\n@AutoConfigureMockMvc\nclass SampleJpaApplicationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testHome() throws Exception {\n\t\tassertThat(this.mvc.get().uri(\"/\")).hasStatusOk().matches(xpath(\"//tbody/tr\").nodeCount(4));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/test/java/smoketest/jpa/repository/JpaNoteRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.repository;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.jpa.domain.Note;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JpaNoteRepository}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@Transactional\nclass JpaNoteRepositoryIntegrationTests {\n\n\t@Autowired\n\tJpaNoteRepository repository;\n\n\t@Test\n\tvoid findsAllNotes() {\n\t\tList<Note> notes = this.repository.findAll();\n\t\tassertThat(notes).hasSize(4);\n\t\tfor (Note note : notes) {\n\t\t\tassertThat(note.getTags()).isNotEmpty();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-hibernate/src/test/java/smoketest/jpa/repository/JpaTagRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jpa.repository;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.jpa.domain.Tag;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link JpaTagRepository}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\n@Transactional\nclass JpaTagRepositoryIntegrationTests {\n\n\t@Autowired\n\tJpaTagRepository repository;\n\n\t@Test\n\tvoid findsAllTags() {\n\t\tList<Tag> tags = this.repository.findAll();\n\t\tassertThat(tags).hasSize(3);\n\t\tfor (Tag tag : tags) {\n\t\t\tassertThat(tag.getNotes()).isNotEmpty();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Integration smoke test\"\n\ndependencies {\n\tannotationProcessor(project(\":configuration-metadata:spring-boot-configuration-processor\"))\n\n\timplementation(project(\":starter:spring-boot-starter-integration\"))\n\timplementation(\"org.springframework.integration:spring-integration-file\")\n\timplementation(\"org.springframework.integration:spring-integration-jmx\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-integration-test\"))\n\ttestImplementation(\"org.awaitility:awaitility\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration;\n\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class HelloWorldService {\n\n\tprivate final ServiceProperties configuration;\n\n\tpublic HelloWorldService(ServiceProperties configuration) {\n\t\tthis.configuration = configuration;\n\t}\n\n\tpublic String getHelloMessage(String name) {\n\t\treturn this.configuration.getGreeting() + \" \" + name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/SampleApplicationRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class SampleApplicationRunner implements ApplicationRunner {\n\n\tprivate final SampleMessageGateway gateway;\n\n\tpublic SampleApplicationRunner(SampleMessageGateway gateway) {\n\t\tthis.gateway = gateway;\n\t}\n\n\t@Override\n\tpublic void run(ApplicationArguments args) throws Exception {\n\t\tfor (String arg : args.getNonOptionArgs()) {\n\t\t\tthis.gateway.echo(arg);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/SampleEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration;\n\nimport java.io.File;\nimport java.io.FileInputStream;\n\nimport org.springframework.integration.annotation.MessageEndpoint;\nimport org.springframework.integration.annotation.ServiceActivator;\nimport org.springframework.util.StreamUtils;\n\n@MessageEndpoint\npublic class SampleEndpoint {\n\n\tprivate final HelloWorldService helloWorldService;\n\n\tpublic SampleEndpoint(HelloWorldService helloWorldService) {\n\t\tthis.helloWorldService = helloWorldService;\n\t}\n\n\t@ServiceActivator\n\tpublic String hello(File input) throws Exception {\n\t\tFileInputStream in = new FileInputStream(input);\n\t\tString name = new String(StreamUtils.copyToByteArray(in));\n\t\tin.close();\n\t\treturn this.helloWorldService.getHelloMessage(name);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/SampleIntegrationApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration;\n\nimport java.io.File;\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.integration.channel.DirectChannel;\nimport org.springframework.integration.dsl.IntegrationFlow;\nimport org.springframework.integration.dsl.Pollers;\nimport org.springframework.integration.dsl.SourcePollingChannelAdapterSpec;\nimport org.springframework.integration.file.inbound.FileReadingMessageSource;\nimport org.springframework.integration.file.outbound.FileWritingMessageHandler;\nimport org.springframework.util.Assert;\n\n@SpringBootApplication\npublic class SampleIntegrationApplication {\n\n\tprivate final ServiceProperties serviceProperties;\n\n\tpublic SampleIntegrationApplication(ServiceProperties serviceProperties) {\n\t\tthis.serviceProperties = serviceProperties;\n\t}\n\n\t@Bean\n\tpublic FileReadingMessageSource fileReader() {\n\t\tFileReadingMessageSource reader = new FileReadingMessageSource();\n\t\tFile inputDir = this.serviceProperties.getInputDir();\n\t\tAssert.state(inputDir != null, \"'inputDir' must not be null\");\n\t\treader.setDirectory(inputDir);\n\t\treturn reader;\n\t}\n\n\t@Bean\n\tpublic DirectChannel inputChannel() {\n\t\treturn new DirectChannel();\n\t}\n\n\t@Bean\n\tpublic DirectChannel outputChannel() {\n\t\treturn new DirectChannel();\n\t}\n\n\t@Bean\n\tpublic FileWritingMessageHandler fileWriter() {\n\t\tFile outputDir = this.serviceProperties.getOutputDir();\n\t\tAssert.state(outputDir != null, \"'outputDir' must not be null\");\n\t\tFileWritingMessageHandler writer = new FileWritingMessageHandler(outputDir);\n\t\twriter.setExpectReply(false);\n\t\treturn writer;\n\t}\n\n\t@Bean\n\tpublic IntegrationFlow integrationFlow(SampleEndpoint endpoint) {\n\t\treturn IntegrationFlow.from(fileReader(), new FixedRatePoller())\n\t\t\t.channel(inputChannel())\n\t\t\t.handle(endpoint)\n\t\t\t.channel(outputChannel())\n\t\t\t.handle(fileWriter())\n\t\t\t.get();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleIntegrationApplication.class, args);\n\t}\n\n\tprivate static final class FixedRatePoller implements Consumer<SourcePollingChannelAdapterSpec> {\n\n\t\t@Override\n\t\tpublic void accept(SourcePollingChannelAdapterSpec spec) {\n\t\t\tspec.poller(Pollers.fixedRate(500));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/SampleMessageGateway.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration;\n\nimport org.springframework.integration.annotation.MessagingGateway;\n\n@MessagingGateway(defaultRequestChannel = \"outputChannel\")\npublic interface SampleMessageGateway {\n\n\tvoid echo(String message);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/ServiceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.jmx.export.annotation.ManagedAttribute;\nimport org.springframework.jmx.export.annotation.ManagedResource;\n\n@ConfigurationProperties(prefix = \"service\", ignoreUnknownFields = false)\n@ManagedResource\npublic class ServiceProperties {\n\n\tprivate String greeting = \"Hello\";\n\n\tprivate @Nullable File inputDir;\n\n\tprivate @Nullable File outputDir;\n\n\t@ManagedAttribute\n\tpublic String getGreeting() {\n\t\treturn this.greeting;\n\t}\n\n\tpublic void setGreeting(String greeting) {\n\t\tthis.greeting = greeting;\n\t}\n\n\tpublic @Nullable File getInputDir() {\n\t\treturn this.inputDir;\n\t}\n\n\tpublic void setInputDir(@Nullable File inputDir) {\n\t\tthis.inputDir = inputDir;\n\t}\n\n\tpublic @Nullable File getOutputDir() {\n\t\treturn this.outputDir;\n\t}\n\n\tpublic void setOutputDir(@Nullable File outputDir) {\n\t\tthis.outputDir = outputDir;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/java/smoketest/integration/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.integration;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.integration.file=DEBUG\nservice.greeting=Hello\nservice.input-dir=input\nservice.output-dir=output\nspring.jmx.enabled=true"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/test/java/smoketest/integration/consumer/SampleIntegrationApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration.consumer;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.io.TempDir;\nimport smoketest.integration.SampleIntegrationApplication;\nimport smoketest.integration.ServiceProperties;\nimport smoketest.integration.producer.ProducerApplication;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.ResourcePatternUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.hamcrest.Matchers.containsString;\n\n/**\n * Basic integration tests for service demo application.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleIntegrationApplicationTests {\n\n\tprivate @Nullable ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tvoid stopAndCheck(CapturedOutput output) {\n\t\tassertThat(output).doesNotContain(\"WARN\");\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tvoid testVanillaExchange(@TempDir Path temp) {\n\t\tFile inputDir = new File(temp.toFile(), \"input\");\n\t\tFile outputDir = new File(temp.toFile(), \"output\");\n\t\tthis.context = SpringApplication.run(SampleIntegrationApplication.class, \"--service.input-dir=\" + inputDir,\n\t\t\t\t\"--service.output-dir=\" + outputDir);\n\t\tSpringApplication.run(ProducerApplication.class, \"World\", \"--service.input-dir=\" + inputDir,\n\t\t\t\t\"--service.output-dir=\" + outputDir);\n\t\tawaitOutputContaining(outputDir, \"Hello World\");\n\t}\n\n\t@Test\n\tvoid testMessageGateway(@TempDir Path temp) {\n\t\tFile inputDir = new File(temp.toFile(), \"input\");\n\t\tFile outputDir = new File(temp.toFile(), \"output\");\n\t\tthis.context = SpringApplication.run(SampleIntegrationApplication.class, \"testviamg\",\n\t\t\t\t\"--service.input-dir=\" + inputDir, \"--service.output-dir=\" + outputDir);\n\t\tawaitOutputContaining(this.context.getBean(ServiceProperties.class).getOutputDir(), \"testviamg\");\n\t}\n\n\tprivate void awaitOutputContaining(@Nullable File outputDir, String requiredContents) {\n\t\tassertThat(outputDir).isNotNull();\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30))\n\t\t\t.until(() -> outputIn(outputDir), containsString(requiredContents));\n\t}\n\n\tprivate @Nullable String outputIn(File outputDir) throws IOException {\n\t\tResource[] resources = findResources(outputDir);\n\t\tif (resources.length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\treturn readResources(resources);\n\t}\n\n\tprivate Resource[] findResources(File outputDir) throws IOException {\n\t\treturn ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader())\n\t\t\t.getResources(\"file:\" + outputDir.getAbsolutePath() + \"/*.txt\");\n\t}\n\n\tprivate String readResources(Resource[] resources) throws IOException {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tfor (Resource resource : resources) {\n\t\t\ttry (InputStream input = resource.getInputStream()) {\n\t\t\t\tbuilder.append(new String(StreamUtils.copyToByteArray(input)));\n\t\t\t}\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/test/java/smoketest/integration/consumer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.integration.consumer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/test/java/smoketest/integration/producer/ProducerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.integration.producer;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\n\nimport org.jspecify.annotations.Nullable;\nimport smoketest.integration.ServiceProperties;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.Assert;\n\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(ServiceProperties.class)\npublic class ProducerApplication implements ApplicationRunner {\n\n\tprivate final ServiceProperties serviceProperties;\n\n\tpublic ProducerApplication(ServiceProperties serviceProperties) {\n\t\tthis.serviceProperties = serviceProperties;\n\t}\n\n\t@Override\n\tpublic void run(ApplicationArguments args) throws Exception {\n\t\t@Nullable File inputDir = this.serviceProperties.getInputDir();\n\t\tAssert.notNull(inputDir, \"No inputDir configured\");\n\t\tinputDir.mkdirs();\n\t\tif (!args.getNonOptionArgs().isEmpty()) {\n\t\t\tFileOutputStream stream = new FileOutputStream(\n\t\t\t\t\tnew File(inputDir, \"data\" + System.currentTimeMillis() + \".txt\"));\n\t\t\tfor (String arg : args.getNonOptionArgs()) {\n\t\t\t\tstream.write(arg.getBytes());\n\t\t\t}\n\t\t\tstream.flush();\n\t\t\tstream.close();\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(ProducerApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-integration/src/test/java/smoketest/integration/producer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.integration.producer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Jackson 2 mixed with Jackson 3 smoke test\"\n\ndependencies {\n\timplementation(project(\":module:spring-boot-jackson2\"))\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/Name.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\npublic record Name(String first, String last) {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/NamesEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport java.util.List;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.stereotype.Component;\n\n/**\n * Names endpoint.\n *\n * @author Andy Wilkinson\n */\n@Component\n@Endpoint(id = \"names\")\npublic class NamesEndpoint {\n\n\t@ReadOperation\n\tList<Name> names() {\n\t\treturn List.of(new Name(\"Spring\", \"Boot\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport java.util.List;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SampleController {\n\n\t@GetMapping(\"/names\")\n\tList<Name> names() {\n\t\treturn List.of(new Name(\"Spring\", \"Boot\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/SampleJackson2MixedApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleJackson2MixedApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJackson2MixedApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/SampleJacksonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport tools.jackson.core.JacksonException;\nimport tools.jackson.core.JsonGenerator;\nimport tools.jackson.databind.SerializationContext;\nimport tools.jackson.databind.ValueSerializer;\n\nimport org.springframework.boot.jackson.JacksonComponent;\n\n@JacksonComponent\npublic class SampleJacksonComponent {\n\n\tpublic static class Serializer extends ValueSerializer<Name> {\n\n\t\t@Override\n\t\tpublic void serialize(Name value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException {\n\t\t\tgen.writeString(\"JACKSON:%s:%s\".formatted(value.first(), value.last()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/SampleJsonComponent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.databind.JsonSerializer;\nimport com.fasterxml.jackson.databind.SerializerProvider;\n\nimport org.springframework.boot.jackson2.JsonComponent;\n\n@JsonComponent\n@SuppressWarnings(\"removal\")\npublic class SampleJsonComponent {\n\n\tpublic static class Serializer extends JsonSerializer<Name> {\n\n\t\t@Override\n\t\tpublic void serialize(Name value, JsonGenerator gen, SerializerProvider serializers) throws IOException {\n\t\t\tgen.writeString(\"JACKSON2:%s:%s\".formatted(value.first(), value.last()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/java/smoketest/jackson2/mixed/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jackson2.mixed;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nspring.http.converters.preferred-json-mapper=jackson2\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/test/java/smoketest/jackson2/mixed/MixedJacksonPresenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the presence of mixed versions of Jackson.\n *\n * @author Andy Wilkinson\n */\nclass MixedJacksonPresenceTests {\n\n\t@Test\n\tvoid jackson2IsPresent() {\n\t\tassertThat(ClassUtils.isPresent(\"com.fasterxml.jackson.databind.ObjectMapper\", null)).isTrue();\n\t}\n\n\t@Test\n\tvoid jackson3IsPresent() {\n\t\tassertThat(ClassUtils.isPresent(\"tools.jackson.databind.ObjectMapper\", null)).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/test/java/smoketest/jackson2/mixed/SampleJackson2MixedApplicationJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JacksonTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * {@link JsonTest JSON Tests} for {@link SampleJackson2MixedApplication}.\n *\n * @author Andy Wilkinson\n */\n@JsonTest\nclass SampleJackson2MixedApplicationJsonTests {\n\n\t@Autowired\n\t@SuppressWarnings({ \"deprecation\", \"removal\" })\n\torg.springframework.boot.test.json.Jackson2Tester<Pojo> jackson2Tester;\n\n\t@Autowired\n\tJacksonTester<Pojo> jacksonTester;\n\n\t@Test\n\tvoid jackson2TesterIsInitialized() {\n\t\tassertThat(this.jackson2Tester).isNotNull();\n\t}\n\n\t@Test\n\tvoid jacksonTesterIsInitialized() {\n\t\tassertThat(this.jacksonTester).isNotNull();\n\t}\n\n\tstatic class Pojo {\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/test/java/smoketest/jackson2/mixed/SampleJackson2MixedApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleJackson2MixedApplication}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureRestTestClient\nclass SampleJackson2MixedApplicationTests {\n\n\t@Autowired\n\tRestTestClient rest;\n\n\t@Test\n\tvoid jackson2IsUsedForHttpMessageConversion() {\n\t\tthis.rest.get().uri(\"/names\").exchange().expectBody().json(\"[\\\"JACKSON2:Spring:Boot\\\"]\");\n\t}\n\n\t@Test\n\tvoid jackson2IsUsedForActuatorEndpoints() {\n\t\tthis.rest.get().uri(\"/actuator/names\").exchange().expectBody().json(\"[\\\"JACKSON2:Spring:Boot\\\"]\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid configPropsShouldReturnOk() {\n\t\tthis.rest.get()\n\t\t\t.uri(\"/actuator/configprops\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(Map.class)\n\t\t\t.value((body) -> assertThat(body).containsOnlyKeys(\"contexts\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid actuatorLinksShouldReturnOk() {\n\t\tthis.rest.get()\n\t\t\t.uri(\"/actuator\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(Map.class)\n\t\t\t.value((body) -> assertThat(body).containsOnlyKeys(\"_links\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-mixed/src/test/java/smoketest/jackson2/mixed/SampleJackson2MixedApplicationWithJackson3PreferredTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.mixed;\n\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleJackson2MixedApplication} when Jackson 3 is preferred.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.http.converters.preferred-json-mapper=jackson\")\n@AutoConfigureRestTestClient\nclass SampleJackson2MixedApplicationWithJackson3PreferredTests {\n\n\t@Autowired\n\tRestTestClient rest;\n\n\t@Test\n\tvoid jacksonIsUsedForHttpMessageConversion() {\n\t\tthis.rest.get().uri(\"/names\").exchange().expectBody().json(\"[\\\"JACKSON:Spring:Boot\\\"]\");\n\t}\n\n\t@Test\n\tvoid jacksonIsUsedForActuatorEndpoints() {\n\t\tthis.rest.get().uri(\"/actuator/names\").exchange().expectBody().json(\"[\\\"JACKSON:Spring:Boot\\\"]\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid configPropsShouldReturnOk() {\n\t\tthis.rest.get()\n\t\t\t.uri(\"/actuator/configprops\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(Map.class)\n\t\t\t.value((body) -> assertThat(body).containsOnlyKeys(\"contexts\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid actuatorLinksShouldReturnOk() {\n\t\tthis.rest.get()\n\t\t\t.uri(\"/actuator\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(Map.class)\n\t\t\t.value((body) -> assertThat(body).containsOnlyKeys(\"_links\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Jackson 2 without Jackson 3 smoke test\"\n\ndependencies {\n\timplementation(project(\":module:spring-boot-jackson2\"))\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude module: 'spring-boot-starter-jackson'\n\t}\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\")) {\n\t\texclude module: 'spring-boot-starter-jackson'\n\t}\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/main/java/smoketest/jackson2/only/SampleJackson2OnlyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.only;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleJackson2OnlyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJackson2OnlyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/main/java/smoketest/jackson2/only/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jackson2.only;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/main/resources/application.properties",
    "content": "management.endpoints.jmx.exposure.include=*\nmanagement.endpoints.web.exposure.include=*\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/test/java/smoketest/jackson2/only/JsonPojo.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.only;\n\n/**\n * POJO for serialization to JSON.\n *\n * @author Andy Wilkinson\n */\nclass JsonPojo {\n\n\tprivate String alpha;\n\n\tprivate String bravo;\n\n\tString getAlpha() {\n\t\treturn this.alpha;\n\t}\n\n\tvoid setAlpha(String alpha) {\n\t\tthis.alpha = alpha;\n\t}\n\n\tString getBravo() {\n\t\treturn this.bravo;\n\t}\n\n\tvoid setBravo(String bravo) {\n\t\tthis.bravo = bravo;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/test/java/smoketest/jackson2/only/OnlyJackson2PresenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.only;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for the presence of mixed versions of Jackson.\n *\n * @author Andy Wilkinson\n */\nclass OnlyJackson2PresenceTests {\n\n\t@Test\n\tvoid jackson2IsPresent() {\n\t\tassertThat(ClassUtils.isPresent(\"com.fasterxml.jackson.databind.ObjectMapper\", null)).isTrue();\n\t}\n\n\t@Test\n\tvoid jackson3IsNotPresent() {\n\t\tassertThat(ClassUtils.isPresent(\"tools.jackson.databind.ObjectMapper\", null)).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/test/java/smoketest/jackson2/only/SampleJackson2OnlyApplicationJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.only;\n\nimport java.io.IOException;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.ObjectContent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleJackson2OnlyApplication} using {@link JsonTest @JsonTest}.\n *\n * @author Andy Wilkinson\n */\n@JsonTest\n@SuppressWarnings({ \"deprecation\", \"removal\" })\nclass SampleJackson2OnlyApplicationJsonTests {\n\n\t@Autowired\n\tObjectMapper objectMapper;\n\n\t@Autowired\n\torg.springframework.boot.test.json.Jackson2Tester<JsonPojo> tester;\n\n\t@Test\n\tvoid objectMapperIsInjected() {\n\t\tassertThat(this.objectMapper).isNotNull();\n\t}\n\n\t@Test\n\tvoid jacksonTesterWorks() throws IOException {\n\t\tObjectContent<JsonPojo> pojo = this.tester.parse(\"{\\\"alpha\\\":\\\"a\\\",\\\"bravo\\\":\\\"b\\\"}\");\n\t\tassertThat(pojo).extracting(JsonPojo::getAlpha).isEqualTo(\"a\");\n\t\tassertThat(pojo).extracting(JsonPojo::getBravo).isEqualTo(\"b\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/test/java/smoketest/jackson2/only/SampleJackson2OnlyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.only;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Map;\n\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.test.web.servlet.client.RestTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for Actuator running in {@link SampleJackson2OnlyApplication}.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.jmx.enabled=true\")\n@AutoConfigureRestTestClient\nclass SampleJackson2OnlyApplicationTests {\n\n\t@Autowired\n\tRestTestClient rest;\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid configPropsShouldReturnOk() {\n\t\tthis.rest.get()\n\t\t\t.uri(\"/actuator/configprops\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(Map.class)\n\t\t\t.value((body) -> assertThat(body).containsOnlyKeys(\"contexts\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid actuatorLinksShouldReturnOk() {\n\t\tthis.rest.get()\n\t\t\t.uri(\"/actuator\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(Map.class)\n\t\t\t.value((body) -> assertThat(body).containsOnlyKeys(\"_links\"));\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid jmxEndpointsShouldWork() throws Exception {\n\t\tMBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();\n\t\tMap<String, Object> result = (Map<String, Object>) mbeanServer.invoke(\n\t\t\t\tObjectName.getInstance(\"org.springframework.boot:type=Endpoint,name=Configprops\"),\n\t\t\t\t\"configurationProperties\", new Object[0], null);\n\t\tassertThat(result).containsOnlyKeys(\"contexts\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jackson2-only/src/test/java/smoketest/jackson2/only/SampleJackson2OnlyWithoutSpringWebApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jackson2.only;\n\nimport java.lang.management.ManagementFactory;\nimport java.util.Map;\n\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for Actuator running in {@link SampleJackson2OnlyApplication} with\n * {@code spring-web} on the classpath.\n *\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(\"spring-web-*\")\n@SpringBootTest(properties = \"spring.jmx.enabled=true\")\nclass SampleJackson2OnlyWithoutSpringWebApplicationTests {\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid jmxEndpointsShouldWork() throws Exception {\n\t\tMBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();\n\t\tMap<String, Object> result = (Map<String, Object>) mbeanServer.invoke(\n\t\t\t\tObjectName.getInstance(\"org.springframework.boot:type=Endpoint,name=Configprops\"),\n\t\t\t\t\"configurationProperties\", new Object[0], null);\n\t\tassertThat(result).containsOnlyKeys(\"contexts\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Jersey smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-jersey\"))\n\timplementation(project(\":starter:spring-boot-starter-tomcat\"))\n\n\truntimeOnly(\"jakarta.xml.bind:jakarta.xml.bind-api\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-jersey-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/java/smoketest/jersey/Endpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\n\nimport org.springframework.stereotype.Component;\n\n@Component\n@Path(\"/hello\")\npublic class Endpoint {\n\n\tprivate final Service service;\n\n\tpublic Endpoint(Service service) {\n\t\tthis.service = service;\n\t}\n\n\t@GET\n\tpublic String message() {\n\t\treturn \"Hello \" + this.service.message();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/java/smoketest/jersey/JerseyConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class JerseyConfig extends ResourceConfig {\n\n\tpublic JerseyConfig() {\n\t\tregister(Endpoint.class);\n\t\tregister(ReverseEndpoint.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/java/smoketest/jersey/ReverseEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.QueryParam;\n\nimport org.springframework.stereotype.Component;\n\n@Component\n@Path(\"/reverse\")\npublic class ReverseEndpoint {\n\n\t@GET\n\tpublic String reverse(@QueryParam(\"input\") @NotNull String input) {\n\t\treturn new StringBuilder(input).reverse().toString();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/java/smoketest/jersey/SampleJerseyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class SampleJerseyApplication extends SpringBootServletInitializer {\n\n\tpublic static void main(String[] args) {\n\t\tnew SampleJerseyApplication()\n\t\t\t.configure(new SpringApplicationBuilder(SampleJerseyApplication.class)\n\t\t\t\t.applicationStartup(new BufferingApplicationStartup(2048)))\n\t\t\t.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/java/smoketest/jersey/Service.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Service {\n\n\t@Value(\"${message:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String msg;\n\n\tpublic String message() {\n\t\treturn this.msg;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/java/smoketest/jersey/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jersey;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nmanagement.endpoints.jackson.isolated-json-mapper=true\nspring.jackson2.visibility.field=any\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@AutoConfigureTestRestTemplate\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"logging.level.root=debug\")\nabstract class AbstractJerseyApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid reverse() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/reverse?input=olleh\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"hello\");\n\t}\n\n\t@Test\n\tvoid validation() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/reverse\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);\n\t}\n\n\t@Test\n\tvoid actuatorStatus() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"{\\\"status\\\":\\\"UP\\\",\\\"groups\\\":[\\\"liveness\\\",\\\"readiness\\\"]}\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/AbstractJerseyManagementPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport org.junit.jupiter.api.Test;\nimport smoketest.jersey.AbstractJerseyManagementPortTests.ResourceConfigConfiguration;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jersey.autoconfigure.ResourceConfigCustomizer;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Base class for integration tests for Jersey using separate management and main service\n * ports.\n *\n * @author Madhura Bhave\n */\n@AutoConfigureTestRestTemplate\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = \"management.server.port=0\")\n@Import(ResourceConfigConfiguration.class)\nclass AbstractJerseyManagementPortTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid resourceShouldBeAvailableOnMainPort() {\n\t\tResponseEntity<String> entity = this.testRestTemplate.getForEntity(\"http://localhost:\" + this.port + \"/test\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"test\");\n\t}\n\n\t@Test\n\tvoid resourceShouldNotBeAvailableOnManagementPort() {\n\t\tResponseEntity<String> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/test\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid actuatorShouldBeAvailableOnManagementPort() {\n\t\tResponseEntity<String> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid actuatorShouldNotBeAvailableOnMainPort() {\n\t\tResponseEntity<String> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.port + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@TestConfiguration\n\tstatic class ResourceConfigConfiguration {\n\n\t\t@Bean\n\t\tResourceConfigCustomizer customizer() {\n\t\t\treturn (config) -> config.register(TestEndpoint.class);\n\t\t}\n\n\t\t@Path(\"/test\")\n\t\tpublic static class TestEndpoint {\n\n\t\t\t@GET\n\t\t\tpublic String test() {\n\t\t\t\treturn \"test\";\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/ApplicationStartupSpringBootContextLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.test.context.SpringBootContextLoader;\n\nclass ApplicationStartupSpringBootContextLoader extends SpringBootContextLoader {\n\n\t@Override\n\tprotected SpringApplication getSpringApplication() {\n\t\tSpringApplication application = new SpringApplication();\n\t\tapplication.setApplicationStartup(new BufferingApplicationStartup(1024));\n\t\treturn application;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyActuatorIsolatedObjectMapperFalseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for Jersey actuator when not using an isolated {@link ObjectMapper}.\n *\n * @author Phillip Webb\n */\n@AutoConfigureTestRestTemplate\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"management.endpoints.jackson2.isolated-object-mapper=false\")\n@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)\nclass JerseyActuatorIsolatedObjectMapperFalseTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid resourceShouldBeAvailableOnMainPort() {\n\t\tResponseEntity<String> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.port + \"/actuator/startup\", String.class);\n\t\tSystem.out.println(entity.getBody());\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);\n\t\tassertThat(entity.getBody())\n\t\t\t.contains(\"Java 8 date/time type `java.time.Clock$SystemClock` not supported by default\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyActuatorIsolatedObjectMapperTrueTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.ContextConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for Jersey actuator when using an isolated {@link ObjectMapper}.\n *\n * @author Phillip Webb\n */\n@AutoConfigureTestRestTemplate\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"management.endpoints.jackson.isolated-json-mapper=true\")\n@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)\nclass JerseyActuatorIsolatedObjectMapperTrueTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid resourceShouldBeAvailableOnMainPort() {\n\t\tResponseEntity<String> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.port + \"/actuator/startup\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"timeline\\\":\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyApplicationPathAndManagementPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with custom\n * application path.\n *\n * @author Madhura Bhave\n */\n@AutoConfigureTestRestTemplate\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"spring.jersey.application-path=/app\" })\nclass JerseyApplicationPathAndManagementPortTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid applicationPathShouldNotAffectActuators() {\n\t\tResponseEntity<String> entity = this.testRestTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyDifferentPortSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with empty base path\n * for endpoints.\n *\n * @author HaiTao Zhang\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"management.endpoints.web.base-path=/\" })\nclass JerseyDifferentPortSampleActuatorApplicationTests {\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid linksEndpointShouldBeAvailable() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"user\", getPassword())\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"_links\\\"\");\n\t}\n\n\tprivate String getPassword() {\n\t\treturn \"password\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.springframework.test.context.TestPropertySource;\n\n/**\n * Smoke tests for Jersey configured as a Filter.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = { \"spring.jersey.type=filter\", \"server.servlet.register-default-servlet=true\" })\nclass JerseyFilterApplicationTests extends AbstractJerseyApplicationTests {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyFilterManagementPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\nimport org.springframework.test.context.TestPropertySource;\n\n/**\n * Integration tests for Jersey configured as a Servlet using separate management and main\n * service ports.\n *\n * @author Andy Wilkinson\n */\n@TestPropertySource(properties = { \"spring.jersey.type=filter\", \"server.servlet.register-default-servlet=true\" })\nclass JerseyFilterManagementPortTests extends AbstractJerseyManagementPortTests {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\n/**\n * Smoke tests for Jersey configured as a Servlet.\n *\n * @author Andy Wilkinson\n */\nclass JerseyServletApplicationTests extends AbstractJerseyApplicationTests {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jersey/src/test/java/smoketest/jersey/JerseyServletManagementPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jersey;\n\n/**\n * Integration tests for Jersey configured as a Servlet using separate management and main\n * service ports.\n *\n * @author Andy Wilkinson\n */\nclass JerseyServletManagementPortTests extends AbstractJerseyManagementPortTests {\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Jetty smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-jetty\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude module: \"spring-boot-starter-tomcat\"\n\t}\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/ExampleServletContextListener.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty;\n\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\n\nimport org.springframework.stereotype.Component;\n\n/**\n * Simple {@link ServletContextListener} to test gh-2058.\n */\n@Component\npublic class ExampleServletContextListener implements ServletContextListener {\n\n\t@Override\n\tpublic void contextInitialized(ServletContextEvent sce) {\n\t\tSystem.out.println(\"*** contextInitialized\");\n\t}\n\n\t@Override\n\tpublic void contextDestroyed(ServletContextEvent sce) {\n\t\tSystem.out.println(\"*** contextDestroyed\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/SampleJettyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleJettyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJettyApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/service/HttpHeaderService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.service;\n\nimport smoketest.jetty.util.StringUtil;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HttpHeaderService {\n\n\t@Value(\"${server.jetty.max-http-response-header-size}\")\n\tprivate int maxHttpResponseHeaderSize;\n\n\t/**\n\t * Generates a header value, which is longer than\n\t * 'server.jetty.max-http-response-header-size'.\n\t * @return the header value\n\t */\n\tpublic String getHeaderValue() {\n\t\treturn StringUtil.repeat('A', this.maxHttpResponseHeaderSize + 1);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/util/StringUtil.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.util;\n\nimport java.util.Arrays;\n\npublic final class StringUtil {\n\n\tprivate StringUtil() {\n\t}\n\n\tpublic static String repeat(char c, int length) {\n\t\tchar[] chars = new char[length];\n\t\tArrays.fill(chars, c);\n\t\treturn new String(chars);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty.util;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.web;\n\nimport jakarta.servlet.http.HttpServletResponse;\nimport smoketest.jetty.service.HelloWorldService;\nimport smoketest.jetty.service.HttpHeaderService;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\npublic class SampleController {\n\n\tprivate final HelloWorldService helloWorldService;\n\n\tprivate final HttpHeaderService httpHeaderService;\n\n\tpublic SampleController(HelloWorldService helloWorldService, HttpHeaderService httpHeaderService) {\n\t\tthis.helloWorldService = helloWorldService;\n\t\tthis.httpHeaderService = httpHeaderService;\n\t}\n\n\t@GetMapping(\"/\")\n\t@ResponseBody\n\tpublic String helloWorld() {\n\t\treturn this.helloWorldService.getHelloMessage();\n\t}\n\n\t@GetMapping(\"/max-http-response-header\")\n\t@ResponseBody\n\tpublic String maxHttpResponseHeader(HttpServletResponse response) {\n\t\tString headerValue = this.httpHeaderService.getHeaderValue();\n\t\tresponse.addHeader(\"x-max-header\", headerValue);\n\t\treturn this.helloWorldService.getHelloMessage();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/java/smoketest/jetty/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/main/resources/application.properties",
    "content": "server.compression.enabled: true\nserver.compression.min-response-size: 1\nserver.max-http-request-header-size=1000\nserver.jetty.threads.acceptors=2\nserver.jetty.max-http-response-header-size=4096\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty/src/test/java/smoketest/jetty/SampleJettyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.jetty.util.StringUtil;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Florian Storz\n * @author Michael Weidmann\n * @author Moritz Halbritter\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleJettyApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Value(\"${server.max-http-request-header-size}\")\n\tprivate int maxHttpRequestHeaderSize;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testCompression() {\n\t\t// Jetty HttpClient sends Accept-Encoding: gzip by default\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t\t// Jetty HttpClient decodes gzip responses automatically and removes the\n\t\t// Content-Encoding header. We have to assume that the response was gzipped.\n\t}\n\n\t@Test\n\tvoid testMaxHttpResponseHeaderSize() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/max-http-response-header\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t}\n\n\t@Test\n\tvoid testMaxHttpRequestHeaderSize() {\n\t\tString headerValue = StringUtil.repeat('A', this.maxHttpRequestHeaderSize + 1);\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.add(\"x-max-request-header\", headerValue);\n\t\tHttpEntity<?> httpEntity = new HttpEntity<>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, httpEntity, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot Jetty JSP smoke test\"\n\nconfigurations {\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\tcompileOnly(project(\":starter:spring-boot-starter-jetty\"))\n\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude module: \"spring-boot-starter-tomcat\"\n\t}\n\n\tprovidedRuntime(\"org.eclipse.jetty.ee11:jetty-ee11-apache-jsp\")\n\n\truntimeOnly(\"org.glassfish.web:jakarta.servlet.jsp.jstl\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-jetty\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/java/smoketest/jetty/jsp/MyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.jsp;\n\npublic class MyException extends RuntimeException {\n\n\tpublic MyException(String message) {\n\t\tsuper(message);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/java/smoketest/jetty/jsp/MyRestResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.jsp;\n\npublic class MyRestResponse {\n\n\tprivate final String message;\n\n\tpublic MyRestResponse(String message) {\n\t\tthis.message = message;\n\t}\n\n\tpublic String getMessage() {\n\t\treturn this.message;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/java/smoketest/jetty/jsp/SampleJettyJspApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.jsp;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class SampleJettyJspApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleJettyJspApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJettyJspApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/java/smoketest/jetty/jsp/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.jsp;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n@Controller\npublic class WelcomeController {\n\n\t@Value(\"${application.message:Hello World}\")\n\tprivate String message = \"Hello World\";\n\n\t@RequestMapping(\"/\")\n\tpublic String welcome(Map<String, Object> model) {\n\t\tmodel.put(\"time\", new Date());\n\t\tmodel.put(\"message\", this.message);\n\t\treturn \"welcome\";\n\t}\n\n\t@RequestMapping(\"/fail\")\n\tpublic String fail() {\n\t\tthrow new MyException(\"Oh dear!\");\n\t}\n\n\t@RequestMapping(\"/fail2\")\n\tpublic String fail2() {\n\t\tthrow new IllegalStateException();\n\t}\n\n\t@ExceptionHandler(MyException.class)\n\t@ResponseStatus(HttpStatus.BAD_REQUEST)\n\tpublic @ResponseBody MyRestResponse handleMyRuntimeException(MyException exception) {\n\t\treturn new MyRestResponse(\"Some data I want to send back to the client.\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/java/smoketest/jetty/jsp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty.jsp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/resources/application.properties",
    "content": "application.message: Hello Spring Boot\nserver.servlet.jsp.class-name=org.eclipse.jetty.ee11.jsp.JettyJspServlet\nspring.mvc.view.prefix: /WEB-INF/jsp/\nspring.mvc.view.suffix: .jsp\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp",
    "content": "<!DOCTYPE html>\n\n<%@ taglib prefix=\"spring\" uri=\"http://www.springframework.org/tags\"%>\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\n\n<html lang=\"en\">\n\n<body>\n\t<c:url value=\"/resources/text.txt\" var=\"url\"/>\n\t<spring:url value=\"/resources/text.txt\" htmlEscape=\"true\" var=\"springUrl\" />\n\tSpring URL: ${springUrl} at ${time}\n\t<br>\n\tJSTL URL: ${url}\n\t<br>\n\tMessage: ${message}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-jsp/src/test/java/smoketest/jetty/jsp/SampleWebJspApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.jsp;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for JSP application.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebJspApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testJspWithEl() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"/resources/text.txt\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Jetty SSL smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-jetty\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude module: \"spring-boot-starter-tomcat\"\n\t}\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\n\ttestRuntimeOnly(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/src/main/java/smoketest/jetty/ssl/SampleJettySslApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.ssl;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleJettySslApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJettySslApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/src/main/java/smoketest/jetty/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/src/main/java/smoketest/jetty/ssl/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.ssl.web;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String helloWorld() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/src/main/java/smoketest/jetty/ssl/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jetty.ssl.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/src/main/resources/application.properties",
    "content": "server.port = 8443\nserver.ssl.key-store = classpath:sample.jks\nserver.ssl.key-store-password = secret\nserver.ssl.key-password = password\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-jetty-ssl/src/test/java/smoketest/jetty/ssl/SampleJettySslApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jetty.ssl;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"debug=true\")\n@AutoConfigureTestRestTemplate\nclass SampleJettySslApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate AbstractConfigurableWebServerFactory webServerFactory;\n\n\t@Test\n\tvoid testSsl() {\n\t\tSsl ssl = this.webServerFactory.getSsl();\n\t\tassertThat(ssl).isNotNull();\n\t\tassertThat(ssl.isEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Kafka smoke test\"\n\nconfigurations.all {\n\tresolutionStrategy.eachDependency { DependencyResolveDetails details ->\n\t\tif (details.requested.module.group == \"org.apache.kafka\" && details.requested.module.name == \"kafka-server-common\") {\n\t\t\tdetails.artifactSelection {\n\t\t\t\tselectArtifact(DependencyArtifact.DEFAULT_TYPE, null, null)\n\t\t\t}\n\t\t}\n\t}\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-jackson\"))\n\timplementation(project(\":starter:spring-boot-starter-kafka\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-kafka-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-kafka\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-kafka-test\"))\n\ttestImplementation(\"org.awaitility:awaitility\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/dockerTest/java/smoketest/kafka/ssl/SampleKafkaSslApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka.ssl;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.kafka.ConfluentKafkaContainer;\nimport smoketest.kafka.Consumer;\nimport smoketest.kafka.Producer;\nimport smoketest.kafka.SampleMessage;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.JksKeyStore;\nimport org.springframework.boot.testcontainers.service.connection.JksTrustStore;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.hamcrest.Matchers.empty;\nimport static org.hamcrest.Matchers.not;\n\n/**\n * Smoke tests for Apache Kafka with SSL.\n *\n * @author Scott Frederick\n * @author Eddú Meléndez\n */\n@Testcontainers(disabledWithoutDocker = true)\n@SpringBootTest(classes = { SampleKafkaSslApplication.class, Producer.class, Consumer.class })\nclass SampleKafkaSslApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\t@JksTrustStore(location = \"classpath:ssl/test-ca.p12\", password = \"password\")\n\t@JksKeyStore(location = \"classpath:ssl/test-client.p12\", password = \"password\")\n\tpublic static ConfluentKafkaContainer kafka = TestImage.container(SecureKafkaContainer.class);\n\n\t@Autowired\n\tprivate Producer producer;\n\n\t@Autowired\n\tprivate Consumer consumer;\n\n\t@Test\n\tvoid testVanillaExchange() {\n\t\tthis.producer.send(new SampleMessage(1, \"A simple test message\"));\n\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30)).until(this.consumer::getMessages, not(empty()));\n\t\tassertThat(this.consumer.getMessages()).extracting(\"message\").containsOnly(\"A simple test message\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/dockerTest/java/smoketest/kafka/ssl/SecureKafkaContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka.ssl;\n\nimport org.testcontainers.kafka.ConfluentKafkaContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * Kafka container with SSL enabled.\n *\n * @author Scott Frederick\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n */\nclass SecureKafkaContainer extends ConfluentKafkaContainer {\n\n\tSecureKafkaContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t}\n\n\t@Override\n\tprotected void configure() {\n\t\tsuper.configure();\n\t\twithEnv(\"KAFKA_LISTENER_SECURITY_PROTOCOL_MAP\", \"PLAINTEXT:SSL,BROKER:PLAINTEXT,CONTROLLER:PLAINTEXT\")\n\t\t\t.withEnv(\"KAFKA_AUTO_CREATE_TOPICS_ENABLE\", \"true\")\n\t\t\t.withEnv(\"KAFKA_SSL_CLIENT_AUTH\", \"required\")\n\t\t\t.withEnv(\"KAFKA_SSL_KEYSTORE_LOCATION\", \"/etc/kafka/secrets/certs/test-server.p12\")\n\t\t\t.withEnv(\"KAFKA_SSL_KEYSTORE_PASSWORD\", \"password\")\n\t\t\t.withEnv(\"KAFKA_SSL_KEY_PASSWORD\", \"password\")\n\t\t\t.withEnv(\"KAFKA_SSL_TRUSTSTORE_LOCATION\", \"/etc/kafka/secrets/certs/test-ca.p12\")\n\t\t\t.withEnv(\"KAFKA_SSL_TRUSTSTORE_PASSWORD\", \"password\")\n\t\t\t.withEnv(\"KAFKA_SSL_ENDPOINT_IDENTIFICATION_ALGORITHM\", \"\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"ssl/test-server.p12\"),\n\t\t\t\t\"/etc/kafka/secrets/certs/test-server.p12\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"ssl/credentials\"),\n\t\t\t\t\"/etc/kafka/secrets/certs/credentials\");\n\t\twithCopyFileToContainer(MountableFile.forClasspathResource(\"ssl/test-ca.p12\"),\n\t\t\t\t\"/etc/kafka/secrets/certs/test-ca.p12\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/dockerTest/resources/ssl/credentials",
    "content": "password"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/Consumer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.springframework.kafka.annotation.KafkaListener;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Consumer {\n\n\tprivate final List<SampleMessage> messages = new CopyOnWriteArrayList<>();\n\n\t@KafkaListener(topics = \"testTopic\")\n\tvoid processMessage(SampleMessage message) {\n\t\tthis.messages.add(message);\n\t\tSystem.out.println(\"Received sample message [\" + message + \"]\");\n\t}\n\n\tpublic List<SampleMessage> getMessages() {\n\t\treturn this.messages;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/Producer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka;\n\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Producer {\n\n\tprivate final KafkaTemplate<Object, SampleMessage> kafkaTemplate;\n\n\tProducer(KafkaTemplate<Object, SampleMessage> kafkaTemplate) {\n\t\tthis.kafkaTemplate = kafkaTemplate;\n\t}\n\n\tpublic void send(SampleMessage message) {\n\t\tthis.kafkaTemplate.send(\"testTopic\", message);\n\t\tSystem.out.println(\"Sent sample message [\" + message + \"]\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/SampleKafkaApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka;\n\nimport org.apache.kafka.clients.admin.NewTopic;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleKafkaApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleKafkaApplication.class, args);\n\t}\n\n\t@Bean\n\tpublic NewTopic kafkaTestTopic() {\n\t\treturn new NewTopic(\"testTopic\", 10, (short) 2);\n\t}\n\n\t@Bean\n\tpublic ApplicationRunner runner(Producer producer) {\n\t\treturn (args) -> producer.send(new SampleMessage(1, \"A simple test message\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/SampleMessage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\npublic class SampleMessage {\n\n\tprivate final Integer id;\n\n\tprivate final String message;\n\n\t@JsonCreator\n\tpublic SampleMessage(@JsonProperty(\"id\") Integer id, @JsonProperty(\"message\") String message) {\n\t\tthis.id = id;\n\t\tthis.message = message;\n\t}\n\n\tpublic Integer getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getMessage() {\n\t\treturn this.message;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"SampleMessage{id=\" + this.id + \", message='\" + this.message + \"'}\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.kafka;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/ssl/SampleKafkaSslApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka.ssl;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleKafkaSslApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleKafkaSslApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/java/smoketest/kafka/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.kafka.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/main/resources/application.properties",
    "content": "spring.kafka.bootstrap-servers=localhost:9092\nspring.kafka.consumer.group-id=testGroup\nspring.kafka.consumer.auto-offset-reset=earliest\nspring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JacksonJsonDeserializer\nspring.kafka.consumer.properties.spring.json.trusted.packages=smoketest.kafka\nspring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JacksonJsonSerializer\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-kafka/src/test/java/smoketest/kafka/SampleKafkaApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.kafka;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.DisabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.kafka.test.context.EmbeddedKafka;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.hamcrest.Matchers.empty;\nimport static org.hamcrest.Matchers.not;\n\n/**\n * Integration tests for demo application.\n *\n * @author hcxin\n * @author Gary Russell\n * @author Stephane Nicoll\n */\n@DisabledOnOs(OS.WINDOWS)\n@SpringBootTest(properties = \"spring.kafka.bootstrap-servers=${spring.embedded.kafka.brokers}\")\n@EmbeddedKafka(topics = \"testTopic\")\nclass SampleKafkaApplicationTests {\n\n\t@Autowired\n\tprivate Consumer consumer;\n\n\t@Test\n\tvoid testVanillaExchange() {\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30)).until(this.consumer::getMessages, not(empty()));\n\t\tassertThat(this.consumer.getMessages()).extracting(\"message\").containsOnly(\"A simple test message\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-liquibase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Liquibase smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-liquibase\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-liquibase-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-liquibase/src/main/java/smoketest/liquibase/SampleLiquibaseApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.liquibase;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleLiquibaseApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleLiquibaseApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-liquibase/src/main/java/smoketest/liquibase/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.liquibase;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-liquibase/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\n\nspring.h2.console.enabled=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-liquibase/src/main/resources/db/changelog/db.changelog-master.yaml",
    "content": "databaseChangeLog:\n  - changeSet:\n      id: 1\n      author: marceloverdijk\n      changes:\n        - createTable:\n            tableName: person\n            columns:\n              - column:\n                  name: id\n                  type: int\n                  autoIncrement: true\n                  constraints:\n                    primaryKey: true\n                    nullable: false\n              - column:\n                  name: first_name\n                  type: varchar(255)\n                  constraints:\n                    nullable: false\n              - column:\n                  name: last_name\n                  type: varchar(255)\n                  constraints:\n                    nullable: false\n  - changeSet:\n      id: 2\n      author: marceloverdijk\n      changes:\n        - insert:\n            tableName: person\n            columns:\n              - column:\n                  name: first_name\n                  value: Marcel\n              - column:\n                  name: last_name\n                  value: Overdijk\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-liquibase/src/test/java/smoketest/liquibase/SampleLiquibaseApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.liquibase;\n\nimport java.net.ConnectException;\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.core.NestedCheckedException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assumptions.assumeThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleLiquibaseApplicationTests {\n\n\tprivate Locale defaultLocale;\n\n\t@BeforeEach\n\tvoid init() throws SecurityException {\n\t\tthis.defaultLocale = Locale.getDefault();\n\t\tLocale.setDefault(Locale.ENGLISH);\n\t}\n\n\t@AfterEach\n\tvoid restoreLocale() {\n\t\tLocale.setDefault(this.defaultLocale);\n\t}\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\ttry {\n\t\t\tSampleLiquibaseApplication.main(new String[] { \"--server.port=0\" });\n\t\t}\n\t\tcatch (IllegalStateException ex) {\n\t\t\tassumeThat(serverNotRunning(ex)).isFalse();\n\t\t}\n\t\tassertThat(output).contains(\"Successfully acquired change log lock\")\n\t\t\t.contains(\"Creating database changelog table with name: PUBLIC.DATABASECHANGELOG\")\n\t\t\t.contains(\"Table person created\")\n\t\t\t.contains(\"ChangeSet db/changelog/db.changelog-master.yaml::1::\" + \"marceloverdijk ran successfully\")\n\t\t\t.contains(\"New row inserted into person\")\n\t\t\t.contains(\"ChangeSet db/changelog/\" + \"db.changelog-master.yaml::2::marceloverdijk ran successfully\")\n\t\t\t.contains(\"Successfully released change log lock\");\n\t}\n\n\tprivate boolean serverNotRunning(IllegalStateException ex) {\n\t\tNestedCheckedException nested = new NestedCheckedException(\"failed\", ex) {\n\t\t};\n\t\tif (nested.contains(ConnectException.class)) {\n\t\t\tThrowable root = nested.getRootCause();\n\t\t\tassertThat(root).isNotNull();\n\t\t\tString message = root.getMessage();\n\t\t\tassertThat(message).isNotNull();\n\t\t\treturn message.contains(\"Connection refused\");\n\t\t}\n\t\treturn false;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-log4j2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Log4j2 smoke test\"\n\ndependencies {\n\tmodules {\n\t\tmodule(\"org.springframework.boot:spring-boot-starter-logging\") {\n\t\t\treplacedBy(\"org.springframework.boot:spring-boot-starter-log4j2\", \"Use Log4j2 instead of Logback\")\n\t\t}\n\t}\n\n\timplementation(project(\":starter:spring-boot-starter\"))\n\timplementation(project(\":starter:spring-boot-starter-log4j2\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-log4j2/src/main/java/smoketest/log4j2/SampleLog4j2Application.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.log4j2;\n\nimport jakarta.annotation.PostConstruct;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleLog4j2Application {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(SampleLog4j2Application.class);\n\n\t@PostConstruct\n\tpublic void logSomething() {\n\t\tlogger.debug(\"Sample Debug Message\");\n\t\tlogger.trace(\"Sample Trace Message\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleLog4j2Application.class, args).close();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-log4j2/src/main/java/smoketest/log4j2/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.log4j2;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-log4j2/src/main/resources/application.properties",
    "content": "logging.log4j2.config.override=classpath:org/springframework/boot/logging/log4j2/log4j2.xml"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-log4j2/src/main/resources/log4j2-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"WARN\">\n\t<SpringProfile name=\"staging\">\n\t\t<Loggers>\n\t\t\t<Logger name=\"smoketest.log4j2\" level=\"TRACE\"/>\n\t\t\t<Root level=\"INFO\">\n\t\t\t\t<AppenderRef ref=\"Console\"/>\n\t\t\t</Root>\n\t\t</Loggers>\n\t</SpringProfile>\n\t<Loggers>\n\t\t<Logger name=\"smoketest.log4j2\" level=\"DEBUG\"/>\n\t\t<Root level=\"INFO\">\n\t\t\t<AppenderRef ref=\"Console\"/>\n\t\t</Root>\n\t</Loggers>\n</Configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-log4j2/src/test/java/smoketest/log4j2/SampleLog4j2ApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.log4j2;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleLog4j2ApplicationTests {\n\n\t@Test\n\tvoid testLoadedCustomLogbackConfig(CapturedOutput output) {\n\t\tSampleLog4j2Application.main(new String[0]);\n\t\tassertThat(output).contains(\"Sample Debug Message\").doesNotContain(\"Sample Trace Message\");\n\t}\n\n\t@Test\n\tvoid testProfile(CapturedOutput output) {\n\t\tSampleLog4j2Application.main(new String[] { \"--spring.profiles.active=staging\" });\n\t\tassertThat(output).contains(\"Sample Debug Message\").contains(\"Sample Trace Message\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-logback/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Logback smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-logback/src/main/java/smoketest/logback/SampleLogbackApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.logback;\n\nimport jakarta.annotation.PostConstruct;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleLogbackApplication {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(SampleLogbackApplication.class);\n\n\t@PostConstruct\n\tpublic void logSomething() {\n\t\tlogger.debug(\"Sample Debug Message\");\n\t\tlogger.trace(\"Sample Trace Message\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleLogbackApplication.class, args).close();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-logback/src/main/java/smoketest/logback/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.logback;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-logback/src/main/resources/logback-spring.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t<logger name=\"smoketest.logback\" level=\"DEBUG\"/>\n\t<springProfile name=\"staging\">\n\t\t<logger name=\"smoketest.logback\" level=\"TRACE\"/>\n\t</springProfile>\n</configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-logback/src/test/java/smoketest/logback/SampleLogbackApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.logback;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleLogbackApplicationTests {\n\n\t@Test\n\tvoid testLoadedCustomLogbackConfig(CapturedOutput output) {\n\t\tSampleLogbackApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"Sample Debug Message\").doesNotContain(\"Sample Trace Message\");\n\t}\n\n\t@Test\n\tvoid testProfile(CapturedOutput output) {\n\t\tSampleLogbackApplication.main(new String[] { \"--spring.profiles.active=staging\" });\n\t\tassertThat(output).contains(\"Sample Debug Message\").contains(\"Sample Trace Message\");\n\t}\n\n\t@Test\n\tvoid testDisableConsoleLogging(CapturedOutput output) {\n\t\tSampleLogbackApplication.main(new String[] { \"--logging.console.enabled=false\" });\n\t\tassertThat(output).doesNotContain(\"---\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-authorization-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot OAuth2 Authorization Server smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security-oauth2-authorization-server\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-oauth2-authorization-server-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-authorization-server/src/main/java/smoketest/oauth2/server/SampleOAuth2AuthorizationServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.server;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleOAuth2AuthorizationServerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleOAuth2AuthorizationServerApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-authorization-server/src/main/java/smoketest/oauth2/server/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.oauth2.server;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-authorization-server/src/main/resources/application.yml",
    "content": "spring:\n  security:\n    oauth2:\n      authorizationserver:\n        issuer: https://provider.com\n        endpoint:\n          authorization-uri: /authorize\n          token-uri: /token\n          jwk-set-uri: /jwks\n          token-revocation-uri: /revoke\n          token-introspection-uri: /introspect\n          pushed-authorization-request-uri: /par\n          oidc:\n            logout-uri: /logout\n            client-registration-uri: /register\n            user-info-uri: /user\n        client:\n          messaging-client:\n            registration:\n              client-id: messaging-client\n              client-secret: \"{noop}secret\"\n              client-authentication-methods:\n                - client_secret_basic\n              authorization-grant-types:\n                - client_credentials\n              scopes:\n                - message.read\n                - message.write\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-authorization-server/src/test/java/smoketest/oauth2/server/SampleOAuth2AuthorizationServerApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.server;\n\nimport java.net.URI;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.security.oauth2.core.AuthorizationGrantType;\nimport org.springframework.security.oauth2.core.OAuth2AccessToken;\nimport org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;\nimport org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationServerMetadata;\nimport org.springframework.security.oauth2.server.authorization.oidc.OidcProviderConfiguration;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleOAuth2AuthorizationServerApplicationTests {\n\n\tprivate static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE_REFERENCE = new ParameterizedTypeReference<>() {\n\t};\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid openidConfigurationShouldAllowAccess() {\n\t\tResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(\"/.well-known/openid-configuration\",\n\t\t\t\tHttpMethod.GET, null, MAP_TYPE_REFERENCE);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tOidcProviderConfiguration config = OidcProviderConfiguration.withClaims(entity.getBody()).build();\n\t\tassertThat(config.getIssuer()).hasToString(\"https://provider.com\");\n\t\tassertThat(config.getAuthorizationEndpoint()).hasToString(\"https://provider.com/authorize\");\n\t\tassertThat(config.getTokenEndpoint()).hasToString(\"https://provider.com/token\");\n\t\tassertThat(config.getJwkSetUrl()).hasToString(\"https://provider.com/jwks\");\n\t\tassertThat(config.getTokenRevocationEndpoint()).hasToString(\"https://provider.com/revoke\");\n\t\tassertThat(config.getEndSessionEndpoint()).hasToString(\"https://provider.com/logout\");\n\t\tassertThat(config.getTokenIntrospectionEndpoint()).hasToString(\"https://provider.com/introspect\");\n\t\tassertThat(config.getUserInfoEndpoint()).hasToString(\"https://provider.com/user\");\n\t\t// PAR endpoint and OIDC Client Registration are disabled by default\n\t\tassertThat(config.getClientRegistrationEndpoint()).isNull();\n\t\tassertThat(config.getPushedAuthorizationRequestEndpoint()).isNull();\n\t}\n\n\t@Test\n\tvoid authServerMetadataShouldAllowAccess() {\n\t\tResponseEntity<Map<String, Object>> entity = this.restTemplate\n\t\t\t.exchange(\"/.well-known/oauth-authorization-server\", HttpMethod.GET, null, MAP_TYPE_REFERENCE);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tOAuth2AuthorizationServerMetadata config = OAuth2AuthorizationServerMetadata.withClaims(entity.getBody())\n\t\t\t.build();\n\t\tassertThat(config.getIssuer()).hasToString(\"https://provider.com\");\n\t\tassertThat(config.getAuthorizationEndpoint()).hasToString(\"https://provider.com/authorize\");\n\t\tassertThat(config.getTokenEndpoint()).hasToString(\"https://provider.com/token\");\n\t\tassertThat(config.getJwkSetUrl()).hasToString(\"https://provider.com/jwks\");\n\t\tassertThat(config.getTokenRevocationEndpoint()).hasToString(\"https://provider.com/revoke\");\n\t\tassertThat(config.getTokenIntrospectionEndpoint()).hasToString(\"https://provider.com/introspect\");\n\t\t// PAR endpoint and OIDC Client Registration are disabled by default\n\t\tassertThat(config.getClientRegistrationEndpoint()).isNull();\n\t\tassertThat(config.getPushedAuthorizationRequestEndpoint()).isNull();\n\t}\n\n\t@Test\n\tvoid anonymousShouldRedirectToLogin() {\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tassertThat(entity.getHeaders().getLocation()).isEqualTo(URI.create(\"http://localhost:\" + this.port + \"/login\"));\n\t}\n\n\t@Test\n\tvoid validTokenRequestShouldReturnTokenResponse() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setBasicAuth(\"messaging-client\", \"secret\");\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, Object> body = new LinkedMultiValueMap<>();\n\t\tbody.add(OAuth2ParameterNames.CLIENT_ID, \"messaging-client\");\n\t\tbody.add(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue());\n\t\tbody.add(OAuth2ParameterNames.SCOPE, \"message.read message.write\");\n\t\tHttpEntity<Object> request = new HttpEntity<>(body, headers);\n\t\tResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(\"/token\", HttpMethod.POST, request,\n\t\t\t\tMAP_TYPE_REFERENCE);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> tokenResponse = Objects.requireNonNull(entity.getBody());\n\t\tassertThat(tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN)).isNotNull();\n\t\tassertThat(tokenResponse.get(OAuth2ParameterNames.EXPIRES_IN)).isNotNull();\n\t\tassertThat(tokenResponse.get(OAuth2ParameterNames.SCOPE)).isEqualTo(\"message.read message.write\");\n\t\tassertThat(tokenResponse.get(OAuth2ParameterNames.TOKEN_TYPE))\n\t\t\t.isEqualTo(OAuth2AccessToken.TokenType.BEARER.getValue());\n\t}\n\n\t@Test\n\tvoid anonymousTokenRequestShouldReturnUnauthorized() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, Object> body = new LinkedMultiValueMap<>();\n\t\tbody.add(OAuth2ParameterNames.CLIENT_ID, \"messaging-client\");\n\t\tbody.add(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue());\n\t\tbody.add(OAuth2ParameterNames.SCOPE, \"message.read message.write\");\n\t\tHttpEntity<Object> request = new HttpEntity<>(body, headers);\n\t\tResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(\"/token\", HttpMethod.POST, request,\n\t\t\t\tMAP_TYPE_REFERENCE);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid anonymousTokenRequestWithAcceptHeaderAllShouldReturnUnauthorized() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\theaders.setAccept(List.of(MediaType.ALL));\n\t\tMultiValueMap<String, Object> body = new LinkedMultiValueMap<>();\n\t\tbody.add(OAuth2ParameterNames.CLIENT_ID, \"messaging-client\");\n\t\tbody.add(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue());\n\t\tbody.add(OAuth2ParameterNames.SCOPE, \"message.read message.write\");\n\t\tHttpEntity<Object> request = new HttpEntity<>(body, headers);\n\t\tResponseEntity<Map<String, Object>> entity = this.restTemplate.exchange(\"/token\", HttpMethod.POST, request,\n\t\t\t\tMAP_TYPE_REFERENCE);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid anonymousTokenRequestWithAcceptHeaderTextHtmlShouldRedirectToLogin() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\theaders.setAccept(List.of(MediaType.TEXT_HTML));\n\t\tMultiValueMap<String, Object> body = new LinkedMultiValueMap<>();\n\t\tbody.add(OAuth2ParameterNames.CLIENT_ID, \"messaging-client\");\n\t\tbody.add(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue());\n\t\tbody.add(OAuth2ParameterNames.SCOPE, \"message.read message.write\");\n\t\tHttpEntity<Object> request = new HttpEntity<>(body, headers);\n\t\tResponseEntity<Map<String, Object>> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/token\", HttpMethod.POST, request, MAP_TYPE_REFERENCE);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tassertThat(entity.getHeaders().getLocation()).isEqualTo(URI.create(\"http://localhost:\" + this.port + \"/login\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot OAuth2 Client smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security-oauth2-client\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-oauth2-client-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-client/src/main/java/smoketest/oauth2/client/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.client;\n\nimport java.security.Principal;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class ExampleController {\n\n\t@RequestMapping(\"/\")\n\tpublic String email(Principal principal) {\n\t\treturn \"Hello \" + principal.getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-client/src/main/java/smoketest/oauth2/client/SampleOAuth2ClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.client;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleOAuth2ClientApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleOAuth2ClientApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-client/src/main/java/smoketest/oauth2/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.oauth2.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-client/src/main/resources/application.yml",
    "content": "spring:\n  security:\n    oauth2:\n      client:\n        registration:\n          github-client-1:\n            client-id: ${APP-CLIENT-ID}\n            client-secret: ${APP-CLIENT-SECRET}\n            client-name: Github user\n            provider: github\n            scope: user\n            redirect-uri: http://localhost:8080/login/oauth2/code/github\n          github-client-2:\n            client-id: ${APP-CLIENT-ID}\n            client-secret: ${APP-CLIENT-SECRET}\n            client-name: Github email\n            provider: github\n            scope: user:email\n            redirect-uri: http://localhost:8080/login/oauth2/code/github\n          yahoo-oidc:\n            client-id: ${YAHOO-CLIENT-ID}\n            client-secret: ${YAHOO-CLIENT-SECRET}\n          github-repos:\n            client-id: ${APP-CLIENT-ID}\n            client-secret: ${APP-CLIENT-SECRET}\n            scope: public_repo\n            redirect-uri: \"{baseUrl}/github-repos\"\n            provider: github\n            client-name: GitHub Repositories\n        provider:\n          yahoo-oidc:\n            issuer-uri: https://api.login.yahoo.com\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-client/src/test/java/smoketest/oauth2/client/SampleOAuth2ClientApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.client;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"APP-CLIENT-ID=my-client-id\", \"APP-CLIENT-SECRET=my-client-secret\",\n\t\t\t\t\"YAHOO-CLIENT-ID=my-yahoo-client-id\", \"YAHOO-CLIENT-SECRET=my-yahoo-client-secret\" })\n@AutoConfigureTestRestTemplate\nclass SampleOAuth2ClientApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid everythingShouldRedirectToLogin() {\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tassertThat(entity.getHeaders().getLocation()).isEqualTo(URI.create(\"http://localhost:\" + this.port + \"/login\"));\n\t}\n\n\t@Test\n\tvoid loginShouldHaveAllOAuth2ClientsToChooseFrom() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/login\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"/oauth2/authorization/yahoo\");\n\t\tassertThat(entity.getBody()).contains(\"/oauth2/authorization/github-client-1\");\n\t\tassertThat(entity.getBody()).contains(\"/oauth2/authorization/github-client-2\");\n\t\tassertThat(entity.getBody()).contains(\"/oauth2/authorization/github-repos\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-resource-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot OAuth2 Resource Server smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security-oauth2-resource-server\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-oauth2-resource-server-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-resource-server/src/main/java/smoketest/oauth2/resource/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.resource;\n\nimport org.springframework.security.core.annotation.AuthenticationPrincipal;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class ExampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String index(@AuthenticationPrincipal Jwt jwt) {\n\t\treturn String.format(\"Hello, %s!\", jwt.getSubject());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-resource-server/src/main/java/smoketest/oauth2/resource/SampleOauth2ResourceServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.resource;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleOauth2ResourceServerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleOauth2ResourceServerApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-resource-server/src/main/java/smoketest/oauth2/resource/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.oauth2.resource;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-resource-server/src/main/resources/application.yml",
    "content": "spring:\n  security:\n    oauth2:\n      resourceserver:\n        jwt:\n        # To run the application, replace this with a valid JWK Set URI\n          jwk-set-uri: https://example.com/oauth2/default/v1/keys\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-oauth2-resource-server/src/test/java/smoketest/oauth2/resource/SampleOauth2ResourceServerApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.resource;\n\nimport java.io.IOException;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleOauth2ResourceServerApplicationTests {\n\n\tprivate static final MockWebServer server = new MockWebServer();\n\n\tprivate static final String VALID_TOKEN = \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQi\"\n\t\t\t+ \"LCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgU\"\n\t\t\t+ \"OBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwIN\"\n\t\t\t+ \"afU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_Ql\"\n\t\t\t+ \"R44vmRqS5ncrF-1R0EGcPX49U6A\";\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@BeforeAll\n\tstatic void setup() throws Exception {\n\t\tserver.start();\n\t\tString url = server.url(\"/.well-known/jwks.json\").toString();\n\t\tserver.enqueue(mockResponse());\n\t\tSystem.setProperty(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\", url);\n\t}\n\n\t@AfterAll\n\tstatic void shutdown() throws IOException {\n\t\tserver.shutdown();\n\t\tSystem.clearProperty(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\");\n\t}\n\n\t@Test\n\tvoid withValidBearerTokenShouldAllowAccess() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setBearerAuth(VALID_TOKEN);\n\t\tHttpEntity<?> request = new HttpEntity<Void>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, request, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid withNoBearerTokenShouldNotAllowAccess() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\tHttpEntity<?> request = new HttpEntity<Void>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, request, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\tprivate static MockResponse mockResponse() {\n\t\tString body = \"{\\\"keys\\\":[{\\\"p\\\":\\\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMw\"\n\t\t\t\t+ \"DBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\\\"\"\n\t\t\t\t+ \",\\\"kty\\\":\\\"RSA\\\",\\\"q\\\":\\\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO\"\n\t\t\t\t+ \"1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\\\",\\\"d\\\"\"\n\t\t\t\t+ \":\\\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7\"\n\t\t\t\t+ \"VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0\"\n\t\t\t\t+ \"851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo\"\n\t\t\t\t+ \"3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\\\",\\\"e\\\":\\\"AQAB\\\",\\\"use\\\":\\\"sig\\\",\\\"kid\\\":\\\"one\\\",\\\"qi\\\":\\\"qS0OK4\"\n\t\t\t\t+ \"8M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6o\"\n\t\t\t\t+ \"XZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\\\",\\\"dp\\\":\\\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQ\"\n\t\t\t\t+ \"PDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8\"\n\t\t\t\t+ \"M6NfObDFmbTc_3tJkN_raISo8z_ziIE\\\",\\\"dq\\\":\\\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkF\"\n\t\t\t\t+ \"k5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrn\"\n\t\t\t\t+ \"uYNNtG4_4Bt0\\\",\\\"n\\\":\\\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHs\"\n\t\t\t\t+ \"V9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC5\"\n\t\t\t\t+ \"8CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eq\"\n\t\t\t\t+ \"D9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\\\"}]}\";\n\t\treturn new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)\n\t\t\t.setResponseCode(200)\n\t\t\t.setBody(body);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot OpenTelemetry smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-web\"))\n\timplementation(project(\":starter:spring-boot-starter-opentelemetry\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n\ttestImplementation(\"io.micrometer:micrometer-registry-otlp\")\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"test\") {\n\tenvironment \"OTEL_EXPORTER_OTLP_ENDPOINT\", \"http://localhost:4318\"\n\tenvironment \"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT\", \"http://localhost:4319/custom/traces\"\n\tenvironment \"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT\", \"http://localhost:4320/custom/metrics\"\n\tenvironment \"OTEL_EXPORTER_OTLP_LOGS_ENDPOINT\", \"http://localhost:4321/custom/logs\"\n\tenvironment \"OTEL_RESOURCE_ATTRIBUTES\", \"service.name=my-service,service.version=1.0.0\"\n\tenvironment \"OTEL_EXPORTER_OTLP_HEADERS\", \"Authorization=Bearer token123,X-Custom-Header=value1\"\n\tenvironment \"OTEL_EXPORTER_OTLP_TRACES_HEADERS\", \"X-Trace-Header=trace-value\"\n\tenvironment \"OTEL_EXPORTER_OTLP_COMPRESSION\", \"gzip\"\n\tenvironment \"OTEL_EXPORTER_OTLP_TRACES_TIMEOUT\", \"5000\"\n\tenvironment \"OTEL_EXPORTER_OTLP_PROTOCOL\", \"http/protobuf\"\n}\n\ntasks.named(\"dockerTest\") {\n\tenvironment \"OTEL_EXPORTER_OTLP_ENDPOINT\", \"https://localhost:12345\"\n\tenvironment \"OTEL_EXPORTER_OTLP_CERTIFICATE\", \"${project.projectDir}/src/dockerTest/resources/certs/ca.crt\"\n\tenvironment \"OTEL_EXPORTER_OTLP_HEADERS\", \"Authorization=Basic dGVzdHVzZXI6dGVzdHBhc3MxMjM=\" // testuser:testpass123\n\tenvironment \"OTEL_RESOURCE_ATTRIBUTES\", \"service.name=my-service,service.version=1.0.0\"\n\tenvironment \"OTEL_TRACES_SAMPLER\", \"traceidratio\"\n\tenvironment \"OTEL_TRACES_SAMPLER_ARG\", \"1.0\"\n\tenvironment \"OTEL_METRIC_EXPORT_INTERVAL\", \"1000\"\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/java/smoketest/opentelemetry/OtlpCollectorIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.InternetProtocol;\nimport org.testcontainers.containers.output.ToStringConsumer;\nimport org.testcontainers.containers.wait.strategy.Wait;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for OpenTelemetry environment variable mapping with a real OTLP\n * collector.\n *\n * @author Moritz Halbritter\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@Testcontainers(disabledWithoutDocker = true)\nclass OtlpCollectorIntegrationTests {\n\n\tprivate static final int OTLP_HTTP_PORT = 4318;\n\n\tprivate static final int OTLP_EXPOSED_PORT = 12345;\n\n\tprivate static final ToStringConsumer collectorOutput = new ToStringConsumer();\n\n\t@Container\n\tprivate static final OtlpCollectorContainer collector = new OtlpCollectorContainer()\n\t\t.withCopyFileToContainer(MountableFile.forClasspathResource(\"otel-collector-config.yaml\"),\n\t\t\t\t\"/etc/otel-collector-config.yaml\")\n\t\t.withCopyFileToContainer(MountableFile.forClasspathResource(\"certs/server.crt\"), \"/etc/certs/server.crt\")\n\t\t.withCopyFileToContainer(MountableFile.forClasspathResource(\"certs/server.key\", 644), \"/etc/certs/server.key\")\n\t\t.withCommand(\"--config=/etc/otel-collector-config.yaml\")\n\t\t.withLogConsumer(collectorOutput)\n\t\t.waitingFor(Wait.forLogMessage(\".*Everything is ready.*\", 1).withStartupTimeout(Duration.ofSeconds(10)));\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid tracesAreSentToCollector() {\n\t\tRestClient restClient = RestClient.create();\n\t\tString response = restClient.get().uri(\"http://localhost:\" + this.port + \"/\").retrieve().body(String.class);\n\t\tassertThat(response).contains(\"Greetings from Spring Boot!\");\n\t\tAwaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {\n\t\t\tString log = getContainerLog();\n\t\t\tassertThat(log).contains(\"service.name: Str(my-service)\")\n\t\t\t\t.contains(\"service.version: Str(1.0.0)\")\n\t\t\t\t.containsAnyOf(\"Span\", \"ScopeSpans\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid metricsAreSentToCollector() {\n\t\tAwaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {\n\t\t\tString log = getContainerLog();\n\t\t\tassertThat(log).contains(\"service.name: Str(my-service)\")\n\t\t\t\t.contains(\"service.version: Str(1.0.0)\")\n\t\t\t\t.containsAnyOf(\"jvm.memory.used\", \"ResourceMetrics\", \"ScopeMetrics\");\n\t\t});\n\t}\n\n\tprivate static String getContainerLog() {\n\t\treturn collectorOutput.toUtf8String();\n\t}\n\n\tprivate static class OtlpCollectorContainer extends GenericContainer<OtlpCollectorContainer> {\n\n\t\tOtlpCollectorContainer() {\n\t\t\tsuper(DockerImageName.parse(TestImage.OTEL_COLLECTOR.toString()));\n\t\t}\n\n\t\t@Override\n\t\tprotected void configure() {\n\t\t\tsuper.configure();\n\t\t\taddFixedExposedPort(OTLP_EXPOSED_PORT, OTLP_HTTP_PORT, InternetProtocol.TCP);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/java/smoketest/opentelemetry/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * OpenTelemetry smoke test.\n */\n@NullMarked\npackage smoketest.opentelemetry;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/resources/certs/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFBzCCAu+gAwIBAgIUAO7sh3YWNEe7Ih2nYxN86PVe0SUwDQYJKoZIhvcNAQEL\nBQAwEjEQMA4GA1UEAwwHdGVzdC1jYTAgFw0yNjAzMzAxMjQ3MDVaGA8yMTI2MDMw\nNjEyNDcwNVowEjEQMA4GA1UEAwwHdGVzdC1jYTCCAiIwDQYJKoZIhvcNAQEBBQAD\nggIPADCCAgoCggIBAMvDAR2nxrwHdPeEqF1UOqbrhnhp6Oz7usPqTsM0tmVapo7M\nm61uFD/Mcz6/fY2PrZ6WcXIIHmznhm2VjFP052DUibpf7bI5MiBUXyt/livg1Pg6\nkNMs7gM60leIdRIKWb6zb6EveaX3FsTwKszChnDBW435tEZrWbaDIbnfX7zcujwt\nPmVBUbZTGnnMKf73rPJMNYjvRRJH+8lj25oRU0MDCAZvJuCVJE8kQmcq2fWwTGtG\nv2JlE92hW51jobgTrhvyLOofaidBCp/GGTUga9j1tiBU7qf4mqA3unXEKT9AnKYm\nKPrWDq64SEizXPHJL4wACnLyPp3DUxSP/H2JA5GKF/+dpCJNZd85TkoaOsXauwh1\nrZe5RmO7KHs7AWABQeuGlpxtZkcbgt9of0j+2m33eUkuwceUKFAXuiLFfbxiSwXi\n4pj/k4NpJqaGV489DdeKTVywFEmHP5lQCJoX1D7PaxQ8z1vpEkukkC3pENwYpXwY\nWUf0W4E1tYqsq2fj0KnCf0lIZKi6+KQQqh9///N1XYy/6XuM8j8Z5KrOixRAKgpx\n9bDB6M/OX6baToUwtXiiC/YtLEyR7GjczKS7r7FLJOCyZ9jb/dNTiGJdsLSKqpms\n+n4D2BydWYgq1ulz9Pm3nifjqogsc8HyeUMatuKAhNZzJn4A9aip69y86G3HAgMB\nAAGjUzBRMB0GA1UdDgQWBBSPSKkkcym4W7WBCvDI36OItoYaqjAfBgNVHSMEGDAW\ngBSPSKkkcym4W7WBCvDI36OItoYaqjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\nDQEBCwUAA4ICAQB1Jn5frNv8ZuVGAtr/Ay+S35NjNLPBJUWW2TJ/x6ua6ks0wDw+\npRZ3yjpYoFUu7Z5egQ8NECFvGSxaHy7ACa5eeE330agEhkqSP2XYb9NnEydLPXug\nrm+U4/1W+V5iUd8P0aQ+5InLpGzoO3Germs+idEz6gO0vdIHY2wZHPyNw4qoiJAd\njPuIAk/Dnan8NvtnyTg7mTLvTJtZ/mwdRVGoCVBWnvb/j6ymlH4T7NzhyqivCxvu\njh+biVCE9TGYqfUotYyp/TLWoM1iiQrM7JDAV77+mV/JvsPbuc7ddJmEttFuCf3Z\niXWk5fcNc59VXvWBWwWnKhwA9srigw44xwGv7gW1e3xaBPAGb3EtJ3uDWn37ggba\n0KuMjhT1btyQD4WgtgHQBt/5qbAr0q+EA5vnpn2hekk74KvCaHWQHPo4tg/ygKTL\njNCoV2125KaLsGO/1/35rgs4DhauA2RzmGuM+QDN65PQjTpWYFjTmC08tn1KewK6\nmbJzgZWoUj3EKHXb9m1AQLPzAYDzKXZgtdE263TjVOgWk/IE/WWEo7P+8He6/ymq\nb9pLCbDJTTJD1fuvMdaEhzBTyCU88rVDswbY++m1KVwABcqvNYQoThOtD8Sz2EcG\nzepFBLRiZoX2/jm+b3nfM5OJItHjYUlAsvU3X16xPWG+BLslyAdD/Rf8JQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/resources/certs/ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDLwwEdp8a8B3T3\nhKhdVDqm64Z4aejs+7rD6k7DNLZlWqaOzJutbhQ/zHM+v32Nj62elnFyCB5s54Zt\nlYxT9Odg1Im6X+2yOTIgVF8rf5Yr4NT4OpDTLO4DOtJXiHUSClm+s2+hL3ml9xbE\n8CrMwoZwwVuN+bRGa1m2gyG531+83Lo8LT5lQVG2Uxp5zCn+96zyTDWI70USR/vJ\nY9uaEVNDAwgGbybglSRPJEJnKtn1sExrRr9iZRPdoVudY6G4E64b8izqH2onQQqf\nxhk1IGvY9bYgVO6n+JqgN7p1xCk/QJymJij61g6uuEhIs1zxyS+MAApy8j6dw1MU\nj/x9iQORihf/naQiTWXfOU5KGjrF2rsIda2XuUZjuyh7OwFgAUHrhpacbWZHG4Lf\naH9I/tpt93lJLsHHlChQF7oixX28YksF4uKY/5ODaSamhlePPQ3Xik1csBRJhz+Z\nUAiaF9Q+z2sUPM9b6RJLpJAt6RDcGKV8GFlH9FuBNbWKrKtn49Cpwn9JSGSouvik\nEKoff//zdV2Mv+l7jPI/GeSqzosUQCoKcfWwwejPzl+m2k6FMLV4ogv2LSxMkexo\n3Myku6+xSyTgsmfY2/3TU4hiXbC0iqqZrPp+A9gcnVmIKtbpc/T5t54n46qILHPB\n8nlDGrbigITWcyZ+APWoqevcvOhtxwIDAQABAoICABRmgjqXXSjfMEFF2Vt6vuKO\nayisJeNwMptB3r/hi69rG4jpiF6dSk626ATsxCPDslTR6CrMEEvEBGv9UI7pUq8Z\nqG5uA0zYOCIPgHXI8N6UxI3Tw0M5WN0e6wdThLEZMzIKIg+Hwsywh+mQyCA3C6HH\nYiS9TuTMA6/nwh0rdZjhmo3C09/sYcN434o5PC0oW/roUWXT2t0BMv7PTiHHQUhQ\nyeFnCIPsurVnwnQ00JyuGYCWFTxDNXF3ocYIvxzAb6qhnQiVu5mRhABKI6TziYiv\n1Ru4lSphFA4ddkArMxv/mo9x+6FdhBvPHIGW36PfijCgomsuwMEn2K4S2msxKBeg\n+THxW6u0LQXR4l4uOeYmh7mxqB3gUKLlcJKxthutKmelJpKiZJE93dvqUHaY0QWm\nKbzOSa791xRzb7ITjy7iTq9QH5XQqe6YihR88iGKBctXsLwNbFV8+kFTx8aWGtD5\nBY3MFpdIi+5UaptmVQwMDWiFl/CiU456Q6Sertk8ZBm2U71qqDWkMYYd8ZMmb+ws\nQjMcagX69RZG/CBW504XgLteg7LyTzOGmdCM/Jk2IpycGoJdfugIOv4OkoXQuHbB\n6qtaqBXsVG/Z8dmGQiM04LHxtSgzXaoTN5ma6Ni1ieDFfKJJB1DtcoCAU2CgCIzb\n3noMedyQ7LFbTgU3DbeNAoIBAQDmMKgF5t7hNU6Mrfa4Yi3rteUTRlmr6CsupQsk\nTBk8dLu4XHbWSd3/ZxmXVMe6zwhFi7exBSHiB5/WUcyqJe/rGot713aBYkQUA2Is\n3jtPTfS8jGLDdaaW241PbxHHmTSDUppqgQaB0nYoOdBTmZNMfh3l8S6tkvajutLV\ne67S/l8gKMyQosCKB2YJNOzZUbIsFb6qFB6CM4nbk+mus2EpOh+iNiyYWNpdM6iA\nRUq82WeCUST+Siwufrv+56a66mp46LYtXFCe6DDrVW3wqDyW0AXg5Bnk0g9UDq7n\n8idlw6oWDCfAGfTczMeZkPXrkdiRIayRog9tbIPN56nXNOy1AoIBAQDim8DBwSmZ\nsUIA1XZWHmqetimDsN0A/+mKInqrmU6Fq9r72OPAxYmSwCdFW9zr9mOFv1YR0g5L\nnJwaduN9KgQpGON6iSM5eftKa9Cv6HbIdQ8+MYHFHvY5kwd0pbDk5yJqReWdnrXi\nGcd3MJYUo5JWdyHXA678623DqS4paan/E2eCJuX3Twin5OG9Qy0mQiiLGsRJuAIn\n/AL6m5zHwm+yp6BmP2QXYBfch3WcOE/w5EAmEKwATsiUKGRfnin7xAds/iPzz/PT\nuou0Y27GMlViXnThmb2BNhoMidiZAKtBYKTsmcsDVYH6XgBhxMejP3TcMrqmUJkm\niTEISMSKBHoLAoIBAQDMTObzxgKOszcyGLxezZSgHWJhBxFTR837qjQHVRsY0ypA\n6J/4dLr5kVHfRDm4jUN0Jhs0m6+E4utz1knlwaH8ciTWF1dwYfy2HoKl+9979V5/\nccG+ZM8kGVyD4bpQAqPe4hN272kNE/QWo6lIaYeYXl6+1J5vI36PtqKlIw746RcY\nfd2BiVGFsCdZiIWmI6IVCn+ciBrDyGZUYiUHDuHvK00kNRzDYij8i3rDzbwVfIcn\n3EkPAFnSMl08UfFi9+bjxPbbr5FGWCIC3GGlNEwCNkLhZNGuitlb62RFLGDXKx/s\nTYGCOAdhaMbGfygkmd8ygEafQsyae7NHrpLJFIn5AoIBAAjfXE65x20zGYh60yVQ\nD5CjRUDYve56FqTH8NGjMQXe0rYlqdU0ZsyOJXt7u0yp2v+znCUaemDPgvUuTn3q\nFTues9lqYSyw7/vb+NHKYkw6+RvQSGp1aeKbNSGGE0UDH7/VeMYRHsH5jGvIRTgN\np38nLvYCOOnCNgwBJcONVZCdK+JWr45dU9NvDL+iT7Q9xuSbabAROlRic6NoUF0p\n6cGu+oLGXJ7lrkl+LEavlcGyzigvYuyoKQZUBooP4UjwRfIoiTPUopFZrnqjogS0\nl89AL4ddw6O5gI+ZHhfvhMUMiaiR5Pb+dBZfc9hgIgjsRSESA2jbowN1P6w5XSii\nQD0CggEBAJz9Y4bmOHRC+Jb01sdsKPWE6OgGDnApc8ng5IqgkCjZS4/rgAb/cAAZ\ncqBdI5iSsNrv3SGAMJAeJEuxJ4tFF3+NOIZFXwkzKLM+SW1C1wDkUQwCSBJgOA1F\nrQlp8XnvBEM7HKAtRyuAMsEq+fa7Ad0AXDKt7VRDD0iSOLDBVErQiStkUEhdKbuc\nBQ7fAuY738KgKBo66CRHBD0ZEBXObAnYEbrZUH0ot1wtvKfQyQkydNjhtkOrhslY\nnBcGDyNk98+XKedYPlz44nry5Oe9w2EpywiYGxorQueOkFbFi7y+pZLQEvWvRZ8g\negUiLGwkss03YP534t8VzQ6ewsW9Wpg=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/resources/certs/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFFDCCAvygAwIBAgIUa3TPUMqR0hxgacc4KhQa2fxeZycwDQYJKoZIhvcNAQEL\nBQAwEjEQMA4GA1UEAwwHdGVzdC1jYTAgFw0yNjAzMzAxMjQ3MDVaGA8yMTI2MDMw\nNjEyNDcwNVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF\nAAOCAg8AMIICCgKCAgEAq6zgJxaQPo/WFxlGMbpQhFOg/Lw9eg/le1GtYEMUE92Q\nWx9wdmZmfBsYF0Ph0h/9JS6noqhRehYy1KaTsul5V9caddgjgPZiJ7GxBBAWZtCT\nk9fHnp+QN9+Gp8IDHzn0Ao/DK+HDzd5UNKr/NJIjeElZ9aSFZiW9c/gGlciZwr4J\nU4QvXghg/UeY4UDGHGAYBdKe6fCuViTYFVE0Z4XkA2nb4I5Hxfvkl1JdiJvI65lT\nzjm9SjCN+/zm/Q78iccmb604yA6PxiOxDDNLeV4vduHwZzVoV2yDYy1AJ1ReEuia\nomEYote7dZ/ZWfbpIZKLZiZPTqZeCU0tbNmZvfEpfryOlaN9wDZdc2btATxG4UV/\nalwVQQfIt+hHvtabQU90Bq/UPCVDJWGjbaEGFwF5fzkDakWAGIWmS0fM2jAn8PU4\n9reVZKz4cfOCeqHis+VkLqbQyF3dnXAe7mmcCHf2Bs7EvOvRNS7tHmSxGmt0howB\njrM/rJCwkfiMPurE0d7Ig9h+UUnZ3K/iVjSlWxm6bSaCiS72KO3rRWRZAOpma4+T\nbuOYRtaOw4yZZhXJqdNHePa4nq6Xl7RmBQVKbVG92olq6fLp6S4iMDZUVocXldh8\nqE9BbKefNQEO1+eG4V/IKLgM8JTHqHl6B4YxjgZgA8fU2NScsNxxH89e0Yiuk8MC\nAwEAAaNeMFwwGgYDVR0RBBMwEYcEfwAAAYIJbG9jYWxob3N0MB0GA1UdDgQWBBS4\n/fykVDFeP1dWQTPPJwE4Ptg5TzAfBgNVHSMEGDAWgBSPSKkkcym4W7WBCvDI36OI\ntoYaqjANBgkqhkiG9w0BAQsFAAOCAgEADsgCihVnbxyJbVIq0c0cdWw7wSp8ck9j\nzTbgA8TBCr+IeT31D2mWL6Y8TLtCvJ7utn3NiNgsPEqZn0gClLTB5QEGwv1t5kjG\n/+IZHYFqXgzjJwLUaTUu+bzfL5AWj5o6nmd01ThAgcoiqBUfU8FhiePA9oiXWhSe\nOSY5gQfSlPpddp/k5RUsseM1JmhZGRgl9rFbx5XpYpALx5Elk+sX4tgojBWGPM3t\nJyFxAxLplsO8JbYCKvTLodCWk5w1w1ndlIkGWyMlymhbe8F1L16/9EtHBLpMRU2t\na6Sn67sb0oQ6TDfzYHnzwXKMmvyYnNEtA5J8m35tcLLTvPo/cZDh6T16ZBLvuKVO\n2FgFnCsuUyc4TbY4/aaxO/N/ENGp5PmHJEYqqFCwh5FgqzpkaIl+5xjC6aoAoR/p\n7nii83zPToFZzfcupbiLCjsZQUb0DEoLvLVo7h4ByobJ5vdnVjseiG2kkGwz2N4W\nif0bSb/mRH7hsQCfOAuBAytetUuejogCeiJwMj2xUcK2LJGmLpzQb5U0KuZXbgLe\ny+dVo+znbpx1grpyNR3P+RkSZmxZDj2Sl6YUciTMtRtlcmPqi1xPAQ+knmwgLAi1\nqyPGsYtVT0clcGeXemOaUEBRis+1tnerVVgxkVBBcoxNWG+Klud/iudW3NzmbCf5\nsaVQ3Tw+6a8=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/resources/certs/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCrrOAnFpA+j9YX\nGUYxulCEU6D8vD16D+V7Ua1gQxQT3ZBbH3B2ZmZ8GxgXQ+HSH/0lLqeiqFF6FjLU\nppOy6XlX1xp12COA9mInsbEEEBZm0JOT18een5A334anwgMfOfQCj8Mr4cPN3lQ0\nqv80kiN4SVn1pIVmJb1z+AaVyJnCvglThC9eCGD9R5jhQMYcYBgF0p7p8K5WJNgV\nUTRnheQDadvgjkfF++SXUl2Im8jrmVPOOb1KMI37/Ob9DvyJxyZvrTjIDo/GI7EM\nM0t5Xi924fBnNWhXbINjLUAnVF4S6JqiYRii17t1n9lZ9ukhkotmJk9Opl4JTS1s\n2Zm98Sl+vI6Vo33ANl1zZu0BPEbhRX9qXBVBB8i36Ee+1ptBT3QGr9Q8JUMlYaNt\noQYXAXl/OQNqRYAYhaZLR8zaMCfw9Tj2t5VkrPhx84J6oeKz5WQuptDIXd2dcB7u\naZwId/YGzsS869E1Lu0eZLEaa3SGjAGOsz+skLCR+Iw+6sTR3siD2H5RSdncr+JW\nNKVbGbptJoKJLvYo7etFZFkA6mZrj5Nu45hG1o7DjJlmFcmp00d49rierpeXtGYF\nBUptUb3aiWrp8unpLiIwNlRWhxeV2HyoT0Fsp581AQ7X54bhX8gouAzwlMeoeXoH\nhjGOBmADx9TY1Jyw3HEfz17RiK6TwwIDAQABAoICAAjg/IjZAGXT75krO/encLGf\nV6Sqoa1V9CLwIvznCztJysUDt7/P5P4HMrRFVQEWmXOaWZ4ugWREkKVx5hKrQ5TY\n8avlnVR2qbXu2T5iDJ6NrAxJ7S+VhhJ1s5Oqk5nCWA3n3IrA9u0HUiiVLXTNGBuJ\nA6eSNjoFuqosSj7l7JnnVTkmDYMaANYopU4FGRnvmF54ubJUudeHuUtE82ZlRNku\nWOpgwXKKaBSxdFfz4qzYtb5lOxaCs100g8fTxhjkHWdKOLUUF7iCMQ51+rHQvrix\nz8qutvJKkPMIrJg8I09sC09ZoToO2UmolkeyXvVXDHGgipqBPTzS6oYGLQ7nUaOA\nLr8/dvuvTH8eZL3hRnlIaWZzxxNGFi8eX+GeFu3FRPpxCNrC0/PD3DyOogC1zXMY\nY4FUey9rF0XA/v/IHAaZhQFGP0AygUH4UOMbNDz7UQO1zlzHhwRR2BwAnsQYCJ3q\nyVCF6KcE/fn/RAISxmUOm/SmeIJOhME8gaqbQ6dOvez5oDqJWvp79AYXAsozn49r\n3oP+gQ5MxGbSxBz2z1S89mjLnuegTs/qs26vYoGhRF6yZUmmt5v4Rm8dSBlZwOZF\njo/Q5eEqeiX1kPwa3L/1Mfi3NHgdRBjigHMCu0K29aybV3REu1lD3jWWZ3DIzNfr\nMFC/0i08tEn2+HMY8/OpAoIBAQDZrTZY7hkWYsEjCvBzPiPQuF+4xy6nNo77eM3z\nkxPqnO0dTQt+7S1N9qm0AWwkZ/RywbBYo+rVegG68LvJrcs7+HhFm7kSuTfsoR8y\nX513OJu+tlpwOa1z72P6mskz9BqHZUjKCnb74Yi+Bt6o1E4Loe2HF50GG+2+fVar\n/XkyUQGEoEUUoWtgmdmYXPtjCGa5yORJZC5aazFOs7A9HlXBw3dg+KL1GuuWWnca\nQMfSneCgwAiz1iafcXv55CyVekYk2v2UcX0gbUIxKKMWXvX/P/h/u66O/tvfrJpV\n4sSWarkBwuzOjE6UpAcCh1hh9cBKYQN2ocVd7yPT6a2eEOz7AoIBAQDJ5ly+vhdD\nAqII+3W58JEhV/0kkWaKTZDFTrvea9ijIarPfntodnn/gkmU1ePdGB7lVCNwIB93\n2loSCIIDP6xisI3oxyWPVjBak042H32iZc2uNL6GOJY7N/lAr7L9G/IjtNoKDCh0\nmnIFhuYXQbX9aHwEwcaUbqt1Km2rZ7kq9SHpvGz9Z5V0Z3zL8xZiFcFvj+zyyKM9\n/PTECxIlYrR2+4bSNt10SEj80/7RwOxKmpFeBA/+XHw7GpJbGjl+9GMm+3I04Lh1\n1dOlGqgVwms1zRoQdkXqFeUmkeW3iQo6XMBpb3fO3vGTAQSo5dL8PmdJn34yvw9g\n79N64PNSbKnZAoIBAQCHDX2bnVX5WpoDuOTIS3SDKfFRvlrGqgX6JdB53/XKaUSA\nGm4YeOTT60cNBJjo2YqDrIJR7Jlli4YJSxTnoyll8toELgKciEgXSzwEz+ftsTSI\nFbF00YQ5WvyH3oMY9cmD2aZYnDeIPTzO0YpR6y7k7rllSJRG1wshVbhxixkny7SK\nabmSfDgXvjyP2Jirr+m0ONzSYBKWTM1RzBB7Sxff2Pt3MaxBMEuchFJC+pA/r25P\nrfV4RlS+NfW6bAPxVeSxNyF/eQ4uETuxLkpJNe+gRztRXMuHsr4OP5Od180qmdph\nKmQsHkce18n1mq2OUZ/VRe2VK/c9OYLcFq5+VHgDAoIBAQCfprBqCEi+rWNR9P33\nxXoNwtUiyHMsI/+5dfPrAp6xCJtYLm0Jgr4fxHfI4IWpvDwaHblUHaKklJ4qql2c\nkgoPlArzKh7SRFZCGT98XtRqyVOmUIDkA/UP6MgJVaYUrbeAcq8DyO9onQRSyIRD\nmat+MdP3sv8DOqwMHzvPkVqD1Ik3mc8ZZoJxJLAzWgq2DvwB6u50YSFskA1AxHxZ\n4b5QY78NlWLyY4KLoltao9J1f9o5XL8E5T87QVy/+3HBqSCKn8SEebqDO017viNx\n6WX7ii71G4FXhG7KXA4pXo0e718bQJCdnf+qveBgajO3UOU9+4fAOwK/JYW2IhFm\neRSpAoIBAQDAFxukiGd8Jz4P++F+P/HofnlkZ/pibY6ziQAsltHWOok4c7E+T7lg\nE307s+HDIzOLW7Ed9c5TvDG8qN3do/tQMi6B/yiKRtS73hs9Sdu04DQeVvP+DJ35\nAiMwNWBOi6xZiC6ZpUKs+8pJ+UYvQ8vFeVhgEkJyamOBDFf+S+I0KbLSifDf/O0e\nION3vbOnlf9qgV7xsouo787FSWdegON7hyT+h6tR2gQQCXEBTgM91OayOPTIdgLv\nEkVwjVJ40XNZwLdXEzkLFJxbgeqWBmzE7FV234seqvPMvM7cpso5yXoceW3YNP6J\nmfrhfPLpoXr3DxpZfiyqnDIYvP2LJ9qX\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/dockerTest/resources/otel-collector-config.yaml",
    "content": "receivers:\n  otlp:\n    protocols:\n      http:\n        endpoint: 0.0.0.0:4318\n        tls:\n          cert_file: /etc/certs/server.crt\n          key_file: /etc/certs/server.key\n        auth:\n          authenticator: basicauth/server\n\nprocessors:\n  batch:\n\nexporters:\n  logging:\n    loglevel: debug\n\nextensions:\n  basicauth/server:\n    htpasswd:\n      inline: |\n        testuser:testpass123\n\nservice:\n  extensions: [basicauth/server]\n  pipelines:\n    traces:\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [logging]\n    metrics:\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [logging]\n    logs:\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [logging]\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/main/java/smoketest/opentelemetry/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String home() {\n\t\treturn \"Greetings from Spring Boot!\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/main/java/smoketest/opentelemetry/SampleOpenTelemetryApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleOpenTelemetryApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleOpenTelemetryApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/main/java/smoketest/opentelemetry/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * OpenTelemetry smoke test.\n */\n@NullMarked\npackage smoketest.opentelemetry;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/test/java/smoketest/opentelemetry/DisabledMappingTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsProperties;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingProperties;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingProperties;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.TestPropertySource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\n@TestPropertySource(properties = \"management.opentelemetry.map-environment-variables=false\")\nclass DisabledMappingTests {\n\n\t@Autowired\n\tprivate OtlpTracingProperties tracingProperties;\n\n\t@Autowired\n\tprivate OtlpLoggingProperties loggingProperties;\n\n\t@Autowired\n\tprivate OtlpMetricsProperties metricsProperties;\n\n\t@Test\n\tvoid environmentVariablesAreNotMappedWhenDisabled() {\n\t\tassertThat(this.tracingProperties.getEndpoint()).isNull();\n\t\tassertThat(this.loggingProperties.getEndpoint()).isNull();\n\t\tassertThat(this.metricsProperties.getUrl()).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/test/java/smoketest/opentelemetry/HeadersAndCompressionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport java.time.Duration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsProperties;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingProperties;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.Transport;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingProperties;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\nclass HeadersAndCompressionTests {\n\n\t@Autowired\n\tprivate OtlpTracingProperties tracingProperties;\n\n\t@Autowired\n\tprivate OtlpLoggingProperties loggingProperties;\n\n\t@Autowired\n\tprivate OtlpMetricsProperties metricsProperties;\n\n\t@Test\n\tvoid generalHeadersAreMappedToAllSignalsWhenSignalSpecificNotSet() {\n\t\tassertThat(this.loggingProperties.getHeaders()).containsEntry(\"Authorization\", \"Bearer token123\")\n\t\t\t.containsEntry(\"X-Custom-Header\", \"value1\");\n\t\tassertThat(this.metricsProperties.getHeaders()).containsEntry(\"Authorization\", \"Bearer token123\")\n\t\t\t.containsEntry(\"X-Custom-Header\", \"value1\");\n\t}\n\n\t@Test\n\tvoid signalSpecificHeadersCompletelyOverrideGeneral() {\n\t\tassertThat(this.tracingProperties.getHeaders()).containsEntry(\"X-Trace-Header\", \"trace-value\")\n\t\t\t.as(\"Signal-specific headers completely override general headers, not merge\")\n\t\t\t.doesNotContainKey(\"Authorization\");\n\t}\n\n\t@Test\n\tvoid compressionIsMapped() {\n\t\tassertThat(this.tracingProperties.getCompression()).isEqualTo(OtlpTracingProperties.Compression.GZIP);\n\t\tassertThat(this.loggingProperties.getCompression()).isEqualTo(OtlpLoggingProperties.Compression.GZIP);\n\t\tassertThat(this.metricsProperties.getCompressionMode())\n\t\t\t.isEqualTo(io.micrometer.registry.otlp.CompressionMode.GZIP);\n\t}\n\n\t@Test\n\tvoid timeoutIsMapped() {\n\t\tassertThat(this.tracingProperties.getTimeout()).isEqualTo(Duration.ofMillis(5000));\n\t}\n\n\t@Test\n\tvoid protocolIsMapped() {\n\t\tassertThat(this.tracingProperties.getTransport()).isEqualTo(Transport.HTTP);\n\t\tassertThat(this.loggingProperties.getTransport())\n\t\t\t.isEqualTo(org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.Transport.HTTP);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/test/java/smoketest/opentelemetry/SampleOpenTelemetryApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport io.opentelemetry.api.common.AttributeKey;\nimport io.opentelemetry.sdk.resources.Resource;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\nclass SampleOpenTelemetryApplicationTests {\n\n\t@Autowired\n\tprivate Resource resource;\n\n\t@Test\n\tvoid resourceAttributesAreMapped() {\n\t\tassertThat(this.resource.getAttribute(AttributeKey.stringKey(\"service.name\"))).isEqualTo(\"my-service\");\n\t\tassertThat(this.resource.getAttribute(AttributeKey.stringKey(\"service.version\"))).isEqualTo(\"1.0.0\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/test/java/smoketest/opentelemetry/SignalSpecificPrecedenceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.opentelemetry;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.export.otlp.OtlpMetricsProperties;\nimport org.springframework.boot.micrometer.tracing.opentelemetry.autoconfigure.otlp.OtlpTracingProperties;\nimport org.springframework.boot.opentelemetry.autoconfigure.logging.otlp.OtlpLoggingProperties;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\nclass SignalSpecificPrecedenceTests {\n\n\t@Autowired\n\tprivate OtlpTracingProperties tracingProperties;\n\n\t@Autowired\n\tprivate OtlpLoggingProperties loggingProperties;\n\n\t@Autowired\n\tprivate OtlpMetricsProperties metricsProperties;\n\n\t@Test\n\tvoid signalSpecificEndpointTakesPrecedenceOverGeneral() {\n\t\tassertThat(this.tracingProperties.getEndpoint()).isEqualTo(\"http://localhost:4319/custom/traces\");\n\t\tassertThat(this.loggingProperties.getEndpoint()).isEqualTo(\"http://localhost:4321/custom/logs\");\n\t\tassertThat(this.metricsProperties.getUrl()).isEqualTo(\"http://localhost:4320/custom/metrics\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-opentelemetry/src/test/java/smoketest/opentelemetry/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * OpenTelemetry smoke test.\n */\n@NullMarked\npackage smoketest.opentelemetry;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot parent context smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-integration\"))\n\timplementation(\"org.springframework.integration:spring-integration-file\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-integration-test\"))\n\ttestImplementation(\"org.awaitility:awaitility\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/main/java/smoketest/parent/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.parent;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\tprivate final ServiceProperties configuration;\n\n\tpublic HelloWorldService(ServiceProperties configuration) {\n\t\tthis.configuration = configuration;\n\t}\n\n\tpublic String getHelloMessage(String name) {\n\t\treturn this.configuration.getGreeting() + \" \" + name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/main/java/smoketest/parent/SampleEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.parent;\n\nimport java.io.File;\nimport java.io.FileInputStream;\n\nimport org.springframework.integration.annotation.MessageEndpoint;\nimport org.springframework.integration.annotation.ServiceActivator;\nimport org.springframework.util.StreamUtils;\n\n@MessageEndpoint\npublic class SampleEndpoint {\n\n\tprivate final HelloWorldService helloWorldService;\n\n\tpublic SampleEndpoint(HelloWorldService helloWorldService) {\n\t\tthis.helloWorldService = helloWorldService;\n\t}\n\n\t@ServiceActivator\n\tpublic String hello(File input) throws Exception {\n\t\tFileInputStream in = new FileInputStream(input);\n\t\tString name = new String(StreamUtils.copyToByteArray(in));\n\t\tin.close();\n\t\treturn this.helloWorldService.getHelloMessage(name);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/main/java/smoketest/parent/SampleParentContextApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.parent;\n\nimport java.io.File;\nimport java.util.function.Consumer;\n\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.integration.channel.DirectChannel;\nimport org.springframework.integration.dsl.IntegrationFlow;\nimport org.springframework.integration.dsl.Pollers;\nimport org.springframework.integration.dsl.SourcePollingChannelAdapterSpec;\nimport org.springframework.integration.file.inbound.FileReadingMessageSource;\nimport org.springframework.integration.file.outbound.FileWritingMessageHandler;\nimport org.springframework.util.Assert;\n\n@SpringBootApplication\npublic class SampleParentContextApplication {\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(Parent.class).child(SampleParentContextApplication.class).run(args);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration\n\tprotected static class Parent {\n\n\t\tprivate final ServiceProperties serviceProperties;\n\n\t\tpublic Parent(ServiceProperties serviceProperties) {\n\t\t\tthis.serviceProperties = serviceProperties;\n\t\t}\n\n\t\t@Bean\n\t\tpublic FileReadingMessageSource fileReader() {\n\t\t\tFileReadingMessageSource reader = new FileReadingMessageSource();\n\t\t\tFile inputDir = this.serviceProperties.getInputDir();\n\t\t\tAssert.state(inputDir != null, \"'inputDir' must not be null\");\n\t\t\treader.setDirectory(inputDir);\n\t\t\treturn reader;\n\t\t}\n\n\t\t@Bean\n\t\tpublic DirectChannel inputChannel() {\n\t\t\treturn new DirectChannel();\n\t\t}\n\n\t\t@Bean\n\t\tpublic DirectChannel outputChannel() {\n\t\t\treturn new DirectChannel();\n\t\t}\n\n\t\t@Bean\n\t\tpublic FileWritingMessageHandler fileWriter() {\n\t\t\tFile outputDir = this.serviceProperties.getOutputDir();\n\t\t\tAssert.state(outputDir != null, \"'outputDir' must not be null\");\n\t\t\tFileWritingMessageHandler writer = new FileWritingMessageHandler(outputDir);\n\t\t\twriter.setExpectReply(false);\n\t\t\treturn writer;\n\t\t}\n\n\t\t@Bean\n\t\tpublic IntegrationFlow integrationFlow(SampleEndpoint endpoint) {\n\t\t\treturn IntegrationFlow.from(fileReader(), new FixedRatePoller())\n\t\t\t\t.channel(inputChannel())\n\t\t\t\t.handle(endpoint)\n\t\t\t\t.channel(outputChannel())\n\t\t\t\t.handle(fileWriter())\n\t\t\t\t.get();\n\t\t}\n\n\t\tprivate static final class FixedRatePoller implements Consumer<SourcePollingChannelAdapterSpec> {\n\n\t\t\t@Override\n\t\t\tpublic void accept(SourcePollingChannelAdapterSpec spec) {\n\t\t\t\tspec.poller(Pollers.fixedRate(500));\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/main/java/smoketest/parent/ServiceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.parent;\n\nimport java.io.File;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.jmx.export.annotation.ManagedAttribute;\nimport org.springframework.jmx.export.annotation.ManagedResource;\n\n@ConfigurationProperties(prefix = \"service\", ignoreUnknownFields = false)\n@ManagedResource\npublic class ServiceProperties {\n\n\tprivate String greeting = \"Hello\";\n\n\tprivate @Nullable File inputDir;\n\n\tprivate @Nullable File outputDir;\n\n\t@ManagedAttribute\n\tpublic String getGreeting() {\n\t\treturn this.greeting;\n\t}\n\n\tpublic void setGreeting(String greeting) {\n\t\tthis.greeting = greeting;\n\t}\n\n\tpublic @Nullable File getInputDir() {\n\t\treturn this.inputDir;\n\t}\n\n\tpublic void setInputDir(@Nullable File inputDir) {\n\t\tthis.inputDir = inputDir;\n\t}\n\n\tpublic @Nullable File getOutputDir() {\n\t\treturn this.outputDir;\n\t}\n\n\tpublic void setOutputDir(@Nullable File outputDir) {\n\t\tthis.outputDir = outputDir;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/main/java/smoketest/parent/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.parent;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/main/resources/application.properties",
    "content": "service.greeting=Hello\nservice.input-dir=input\nservice.output-dir=output\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/test/java/smoketest/parent/consumer/SampleIntegrationParentApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.parent.consumer;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.Path;\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\nimport smoketest.parent.SampleParentContextApplication;\nimport smoketest.parent.producer.ProducerApplication;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.io.DefaultResourceLoader;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.ResourcePatternUtils;\nimport org.springframework.util.StreamUtils;\n\nimport static org.hamcrest.Matchers.containsString;\n\n/**\n * Basic integration tests for service demo application.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n */\nclass SampleIntegrationParentApplicationTests {\n\n\t@Test\n\tvoid testVanillaExchange(@TempDir Path temp) {\n\t\tFile inputDir = new File(temp.toFile(), \"input\");\n\t\tFile outputDir = new File(temp.toFile(), \"output\");\n\t\ttry (ConfigurableApplicationContext app = SpringApplication.run(SampleParentContextApplication.class,\n\t\t\t\t\"--service.input-dir=\" + inputDir, \"--service.output-dir=\" + outputDir)) {\n\t\t\ttry (ConfigurableApplicationContext producer = SpringApplication.run(ProducerApplication.class,\n\t\t\t\t\t\"--service.input-dir=\" + inputDir, \"--service.output-dir=\" + outputDir, \"World\")) {\n\t\t\t\tawaitOutputContaining(outputDir, \"Hello World\");\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void awaitOutputContaining(File outputDir, String requiredContents) {\n\t\tAwaitility.waitAtMost(Duration.ofSeconds(30))\n\t\t\t.until(() -> outputIn(outputDir), containsString(requiredContents));\n\t}\n\n\tprivate @Nullable String outputIn(File outputDir) throws IOException {\n\t\tResource[] resources = findResources(outputDir);\n\t\tif (resources.length == 0) {\n\t\t\treturn null;\n\t\t}\n\t\treturn readResources(resources);\n\t}\n\n\tprivate Resource[] findResources(File outputDir) throws IOException {\n\t\treturn ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader())\n\t\t\t.getResources(\"file:\" + outputDir.getAbsolutePath() + \"/*.txt\");\n\t}\n\n\tprivate String readResources(Resource[] resources) throws IOException {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tfor (Resource resource : resources) {\n\t\t\ttry (InputStream input = resource.getInputStream()) {\n\t\t\t\tbuilder.append(new String(StreamUtils.copyToByteArray(input)));\n\t\t\t}\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/test/java/smoketest/parent/consumer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.parent.consumer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/test/java/smoketest/parent/producer/ProducerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.parent.producer;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\n\nimport org.jspecify.annotations.Nullable;\nimport smoketest.parent.ServiceProperties;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.util.Assert;\n\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(ServiceProperties.class)\npublic class ProducerApplication implements ApplicationRunner {\n\n\tprivate final ServiceProperties serviceProperties;\n\n\tpublic ProducerApplication(ServiceProperties serviceProperties) {\n\t\tthis.serviceProperties = serviceProperties;\n\t}\n\n\t@Override\n\tpublic void run(ApplicationArguments args) throws Exception {\n\t\t@Nullable File inputDir = this.serviceProperties.getInputDir();\n\t\tAssert.notNull(inputDir, \"No inputDir configured\");\n\t\tinputDir.mkdirs();\n\t\tif (!args.getNonOptionArgs().isEmpty()) {\n\t\t\tFileOutputStream stream = new FileOutputStream(\n\t\t\t\t\tnew File(inputDir, \"data\" + System.currentTimeMillis() + \".txt\"));\n\t\t\tfor (String arg : args.getNonOptionArgs()) {\n\t\t\t\tstream.write(arg.getBytes());\n\t\t\t}\n\t\t\tstream.flush();\n\t\t\tstream.close();\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(ProducerApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-parent-context/src/test/java/smoketest/parent/producer/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.parent.producer;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/application.yml",
    "content": "test.hello: Bonjour\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot profile smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/ActiveProfilesEnvironmentPostProcessor.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile;\n\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n/**\n * {@link EnvironmentPostProcessor} that adds an active profile.\n *\n * @author Madhura Bhave\n */\n@Order(Ordered.HIGHEST_PRECEDENCE)\nclass ActiveProfilesEnvironmentPostProcessor implements EnvironmentPostProcessor {\n\n\t@Override\n\tpublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {\n\t\tif (environment.getProperty(\"enableEnvironmentPostProcessor\") != null) {\n\t\t\tenvironment.addActiveProfile(\"dev\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/SampleProfileApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile;\n\nimport smoketest.profile.service.MessageService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.core.env.ConfigurableEnvironment;\n\n@SpringBootApplication\npublic class SampleProfileApplication implements CommandLineRunner {\n\n\t// Simple example shows how a command line spring application can execute an\n\t// injected bean service. Also demonstrates how you can use @Value to inject\n\t// command line args ('--test.name=whatever') or application properties\n\n\t@Autowired\n\tprivate MessageService helloWorldService;\n\n\t@Override\n\tpublic void run(String... args) {\n\t\tSystem.out.println(this.helloWorldService.getMessage());\n\t}\n\n\tpublic static void main(String... args) {\n\t\tSpringApplication application = new SpringApplication(SampleProfileApplication.class) {\n\n\t\t\t@Override\n\t\t\tprotected void bindToSpringApplication(ConfigurableEnvironment environment) {\n\t\t\t}\n\n\t\t};\n\t\tapplication.setWebApplicationType(WebApplicationType.NONE);\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.profile;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/service/GenericService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Profile({ \"generic\" })\npublic class GenericService implements MessageService {\n\n\t@Value(\"${test.hello:Hello}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String hello;\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn this.hello + \" \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/service/GoodbyeWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Profile(\"goodbye\")\npublic class GoodbyeWorldService implements MessageService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn \"Goodbye \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.stereotype.Component;\n\n@Component\n@Profile({ \"hello\", \"default\" })\npublic class HelloWorldService implements MessageService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn \"Hello \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/service/MessageService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile.service;\n\npublic interface MessageService {\n\n\tString getMessage();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/java/smoketest/profile/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.profile.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/resources/META-INF/spring.factories",
    "content": "# Environment Post Processors\norg.springframework.boot.EnvironmentPostProcessor=\\\nsmoketest.profile.ActiveProfilesEnvironmentPostProcessor"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/main/resources/application.yml",
    "content": "test.name: Phil\n\n---\n\nspring.config.activate.on-profile: goodbye | dev\ntest.name: Everyone\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/test/java/smoketest/profile/ActiveProfilesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.EnvironmentPostProcessor;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.core.env.Environment;\nimport org.springframework.test.context.ActiveProfiles;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests that profiles are activated in the correct order from an\n * {@link EnvironmentPostProcessor}.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = { \"enableEnvironmentPostProcessor=true\" }) // gh-28530\n@ActiveProfiles(\"hello\")\nclass ActiveProfilesTests {\n\n\t@Autowired\n\tprivate Environment environment;\n\n\t@Test\n\tvoid activeProfileShouldTakePrecedenceOverProgrammaticallySetProfile() {\n\t\tassertThat(this.environment.getActiveProfiles()).containsExactly(\"dev\", \"hello\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/test/java/smoketest/profile/AttributeInjectionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n// gh-29169\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\nclass AttributeInjectionTests {\n\n\t@Autowired(required = false)\n\tprivate org.springframework.boot.webmvc.error.ErrorAttributes errorAttributesServlet;\n\n\t@Autowired(required = false)\n\tprivate org.springframework.boot.webflux.error.ErrorAttributes errorAttributesReactive;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.errorAttributesServlet).isNull();\n\t\tassertThat(this.errorAttributesReactive).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/test/java/smoketest/profile/SampleProfileApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.profile;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleProfileApplicationTests {\n\n\tprivate String profiles;\n\n\t@BeforeEach\n\tvoid before() {\n\t\tthis.profiles = System.getProperty(\"spring.profiles.active\");\n\t}\n\n\t@AfterEach\n\tvoid after() {\n\t\tif (this.profiles != null) {\n\t\t\tSystem.setProperty(\"spring.profiles.active\", this.profiles);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(\"spring.profiles.active\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultProfile(CapturedOutput output) {\n\t\tSampleProfileApplication.main();\n\t\tassertThat(output).contains(\"Hello Phil\");\n\t}\n\n\t@Test\n\tvoid testGoodbyeProfile(CapturedOutput output) {\n\t\tSystem.setProperty(\"spring.profiles.active\", \"goodbye\");\n\t\tSampleProfileApplication.main();\n\t\tassertThat(output).contains(\"Goodbye Everyone\");\n\t}\n\n\t@Test\n\tvoid testGenericProfile(CapturedOutput output) {\n\t\t/*\n\t\t * This is a profile that requires a new environment property, and one which is\n\t\t * only overridden in the current working directory. That file also only contains\n\t\t * partial overrides, and the default application.yml should still supply the\n\t\t * \"test.name\" property.\n\t\t */\n\t\tSystem.setProperty(\"spring.profiles.active\", \"generic\");\n\t\tSampleProfileApplication.main();\n\t\tassertThat(output).contains(\"Bonjour Phil\");\n\t}\n\n\t@Test\n\tvoid testGoodbyeProfileFromCommandline(CapturedOutput output) {\n\t\tSampleProfileApplication.main(\"--spring.profiles.active=goodbye\");\n\t\tassertThat(output).contains(\"Goodbye Everyone\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-profile/src/test/resources/application.properties",
    "content": "spring.main.web-application-type=reactive"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-prometheus/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Prometheus smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\timplementation(project(\":module:spring-boot-micrometer-tracing-brave\"))\n\timplementation('io.micrometer:micrometer-tracing-bridge-brave')\n\n\truntimeOnly('io.micrometer:micrometer-registry-prometheus')\n\n\ttestImplementation(project(\":starter:spring-boot-starter-micrometer-metrics-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-prometheus/src/main/java/smoketest/prometheus/SamplePrometheusApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.prometheus;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SamplePrometheusApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SamplePrometheusApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-prometheus/src/main/java/smoketest/prometheus/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.prometheus;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-prometheus/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nmanagement.tracing.sampling.probability=1.0\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-prometheus/src/test/java/smoketest/prometheus/SamplePrometheusApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.prometheus;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.micrometer.metrics.test.autoconfigure.AutoConfigureMetrics;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SamplePrometheusApplication}.\n *\n * @author Moritz Halbritter\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureMetrics\n@AutoConfigureTestRestTemplate\nclass SamplePrometheusApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid shouldExportExemplars() {\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tResponseEntity<String> response = this.restTemplate.getForEntity(\"/actuator\", String.class);\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t}\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.add(HttpHeaders.ACCEPT, \"application/openmetrics-text; version=1.0.0; charset=utf-8\");\n\t\tResponseEntity<String> metrics = this.restTemplate.exchange(\"/actuator/prometheus\", HttpMethod.GET,\n\t\t\t\tnew HttpEntity<>(headers), String.class);\n\t\tassertThat(metrics.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(metrics.getBody()).containsSubsequence(\"http_client_requests_seconds_count\", \"span_id\", \"trace_id\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot property validation smoke test\"\n\ndependencies {\n\tannotationProcessor(project(\":configuration-metadata:spring-boot-configuration-processor\"))\n\n\timplementation(project(\":starter:spring-boot-starter\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n\ttestImplementation(project(\":module:spring-boot-web-server\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/src/main/java/smoketest/propertyvalidation/SampleProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.propertyvalidation;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.validation.annotation.Validated;\n\n@ConfigurationProperties(\"sample\")\n@Validated\npublic class SampleProperties {\n\n\t/**\n\t * Sample host.\n\t */\n\tprivate @Nullable String host;\n\n\t/**\n\t * Sample port.\n\t */\n\tprivate Integer port = 8080;\n\n\tpublic @Nullable String getHost() {\n\t\treturn this.host;\n\t}\n\n\tpublic void setHost(@Nullable String host) {\n\t\tthis.host = host;\n\t}\n\n\tpublic Integer getPort() {\n\t\treturn this.port;\n\t}\n\n\tpublic void setPort(Integer port) {\n\t\tthis.port = port;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/src/main/java/smoketest/propertyvalidation/SamplePropertiesValidator.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.propertyvalidation;\n\nimport java.util.regex.Pattern;\n\nimport org.springframework.validation.Errors;\nimport org.springframework.validation.ValidationUtils;\nimport org.springframework.validation.Validator;\n\npublic class SamplePropertiesValidator implements Validator {\n\n\tfinal Pattern pattern = Pattern.compile(\"^(?:[0-9]{1,3}\\\\.){3}[0-9]{1,3}$\");\n\n\t@Override\n\tpublic boolean supports(Class<?> type) {\n\t\treturn type == SampleProperties.class;\n\t}\n\n\t@Override\n\tpublic void validate(Object o, Errors errors) {\n\t\tValidationUtils.rejectIfEmpty(errors, \"host\", \"host.empty\");\n\t\tValidationUtils.rejectIfEmpty(errors, \"port\", \"port.empty\");\n\t\tSampleProperties properties = (SampleProperties) o;\n\t\tif (properties.getHost() != null && !this.pattern.matcher(properties.getHost()).matches()) {\n\t\t\terrors.rejectValue(\"host\", \"Invalid host\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/src/main/java/smoketest/propertyvalidation/SamplePropertyValidationApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.propertyvalidation;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.validation.Validator;\n\n@SpringBootApplication\n@ConfigurationPropertiesScan\npublic class SamplePropertyValidationApplication implements CommandLineRunner {\n\n\tprivate final SampleProperties properties;\n\n\tpublic SamplePropertyValidationApplication(SampleProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\tpublic static Validator configurationPropertiesValidator() {\n\t\treturn new SamplePropertiesValidator();\n\t}\n\n\t@Override\n\tpublic void run(String... args) {\n\t\tSystem.out.println(\"=========================================\");\n\t\tSystem.out.println(\"Sample host: \" + this.properties.getHost());\n\t\tSystem.out.println(\"Sample port: \" + this.properties.getPort());\n\t\tSystem.out.println(\"=========================================\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(SamplePropertyValidationApplication.class).run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/src/main/java/smoketest/propertyvalidation/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.propertyvalidation;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/src/main/resources/application.properties",
    "content": "sample.host=192.168.0.1\nsample.port=7070\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-property-validation/src/test/java/smoketest/propertyvalidation/SamplePropertyValidationApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.propertyvalidation;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.context.properties.bind.validation.BindValidationException;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.boot.web.server.autoconfigure.ServerProperties;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for {@link SamplePropertyValidationApplication}.\n *\n * @author Lucas Saldanha\n * @author Stephane Nicoll\n */\nclass SamplePropertyValidationApplicationTests {\n\n\tprivate final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\n\t@AfterEach\n\tvoid closeContext() {\n\t\tthis.context.close();\n\t}\n\n\t@Test\n\tvoid bindValidProperties() {\n\t\tthis.context.register(SamplePropertyValidationApplication.class);\n\t\tTestPropertyValues.of(\"sample.host:192.168.0.1\", \"sample.port:9090\").applyTo(this.context);\n\t\tthis.context.refresh();\n\t\tSampleProperties properties = this.context.getBean(SampleProperties.class);\n\t\tassertThat(properties.getHost()).isEqualTo(\"192.168.0.1\");\n\t\tassertThat(properties.getPort()).isEqualTo(Integer.valueOf(9090));\n\t}\n\n\t@Test\n\tvoid bindInvalidHost() {\n\t\tthis.context.register(SamplePropertyValidationApplication.class);\n\t\tTestPropertyValues.of(\"sample.host:xxxxxx\", \"sample.port:9090\").applyTo(this.context);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(BindValidationException.class);\n\t}\n\n\t@Test\n\tvoid bindNullHost() {\n\t\tthis.context.register(SamplePropertyValidationApplication.class);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(this.context::refresh)\n\t\t\t.havingRootCause()\n\t\t\t.isInstanceOf(BindValidationException.class);\n\t}\n\n\t@Test\n\tvoid validatorOnlyCalledOnSupportedClass() {\n\t\tthis.context.register(SamplePropertyValidationApplication.class);\n\t\tthis.context.register(ServerProperties.class); // our validator will not apply\n\t\tTestPropertyValues.of(\"sample.host:192.168.0.1\", \"sample.port:9090\").applyTo(this.context);\n\t\tthis.context.refresh();\n\t\tSampleProperties properties = this.context.getBean(SampleProperties.class);\n\t\tassertThat(properties.getHost()).isEqualTo(\"192.168.0.1\");\n\t\tassertThat(properties.getPort()).isEqualTo(Integer.valueOf(9090));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Pulsar smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-pulsar\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-pulsar-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"org.awaitility:awaitility\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-pulsar\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/src/dockerTest/java/smoketest/pulsar/SamplePulsarApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.pulsar;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.pulsar.PulsarContainer;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.awaitility.Awaitility.waitAtMost;\n\n@Testcontainers(disabledWithoutDocker = true)\n@ExtendWith(OutputCaptureExtension.class)\n@SpringBootTest\nclass SamplePulsarApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic final PulsarContainer pulsar = TestImage.container(PulsarContainer.class);\n\n\t@Test\n\tvoid appProducesAndConsumesMessages(CapturedOutput output) {\n\t\tList<String> expectedOutput = new ArrayList<>();\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\texpectedOutput.add(\"++++++PRODUCE:(%s)------\".formatted(i));\n\t\t\texpectedOutput.add(\"++++++CONSUME:(%s)------\".formatted(i));\n\t\t}\n\t\twaitAtMost(Duration.ofSeconds(30)).untilAsserted(() -> assertThat(output).contains(expectedOutput));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/src/main/java/smoketest/pulsar/SampleMessage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.pulsar;\n\nrecord SampleMessage(Integer id, String content) {\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/src/main/java/smoketest/pulsar/SamplePulsarApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.pulsar;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SamplePulsarApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SamplePulsarApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/src/main/java/smoketest/pulsar/SamplePulsarApplicationConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.pulsar;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.pulsar.annotation.PulsarListener;\nimport org.springframework.pulsar.core.PulsarTemplate;\nimport org.springframework.pulsar.core.PulsarTopic;\nimport org.springframework.pulsar.core.PulsarTopicBuilder;\n\n@Configuration(proxyBeanMethods = false)\nclass SamplePulsarApplicationConfig {\n\n\tprivate static final Log logger = LogFactory.getLog(SamplePulsarApplicationConfig.class);\n\n\tprivate static final String TOPIC = \"pulsar-smoke-test-topic\";\n\n\t@Bean\n\tPulsarTopic pulsarTestTopic() {\n\t\treturn new PulsarTopicBuilder().name(TOPIC).numberOfPartitions(1).build();\n\t}\n\n\t@Bean\n\tApplicationRunner sendMessagesToPulsarTopic(PulsarTemplate<SampleMessage> template) {\n\t\treturn (args) -> {\n\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\ttemplate.send(TOPIC, new SampleMessage(i, \"message:\" + i));\n\t\t\t\tlogger.info(\"++++++PRODUCE:(\" + i + \")------\");\n\t\t\t}\n\t\t};\n\t}\n\n\t@PulsarListener(topics = TOPIC)\n\tvoid consumeMessagesFromPulsarTopic(SampleMessage msg) {\n\t\tlogger.info(\"++++++CONSUME:(\" + msg.id() + \")------\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/src/main/java/smoketest/pulsar/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.pulsar;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-pulsar/src/main/resources/application.properties",
    "content": "spring.pulsar.consumer.subscription.initial-position=earliest\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Quartz smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-jdbc\"))\n\timplementation(project(\":starter:spring-boot-starter-quartz\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-quartz-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.awaitility:awaitility\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/src/main/java/smoketest/quartz/SampleJob.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.quartz;\n\nimport org.jspecify.annotations.Nullable;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\n\nimport org.springframework.scheduling.quartz.QuartzJobBean;\n\npublic class SampleJob extends QuartzJobBean {\n\n\tprivate @Nullable String name;\n\n\t// Invoked if a Job data map entry with that name\n\tpublic void setName(@Nullable String name) {\n\t\tthis.name = name;\n\t}\n\n\t@Override\n\tprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {\n\t\tSystem.out.println(String.format(\"Hello %s!\", this.name));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/src/main/java/smoketest/quartz/SampleQuartzApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.quartz;\n\nimport java.util.Calendar;\n\nimport org.quartz.CalendarIntervalScheduleBuilder;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.DailyTimeIntervalScheduleBuilder;\nimport org.quartz.DateBuilder.IntervalUnit;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.TimeOfDay;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleQuartzApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleQuartzApplication.class, args);\n\t}\n\n\t@Bean\n\tpublic JobDetail helloJobDetail() {\n\t\treturn JobBuilder.newJob(SampleJob.class)\n\t\t\t.withIdentity(\"helloJob\", \"samples\")\n\t\t\t.usingJobData(\"name\", \"World\")\n\t\t\t.storeDurably()\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic JobDetail anotherJobDetail() {\n\t\treturn JobBuilder.newJob(SampleJob.class)\n\t\t\t.withIdentity(\"anotherJob\", \"samples\")\n\t\t\t.usingJobData(\"name\", \"Everyone\")\n\t\t\t.storeDurably()\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic JobDetail onDemandJobDetail() {\n\t\treturn JobBuilder.newJob(SampleJob.class)\n\t\t\t.withIdentity(\"onDemandJob\", \"samples\")\n\t\t\t.usingJobData(\"name\", \"On Demand Job\")\n\t\t\t.storeDurably()\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic Trigger everyTwoSecTrigger() {\n\t\treturn TriggerBuilder.newTrigger()\n\t\t\t.forJob(\"helloJob\", \"samples\")\n\t\t\t.withIdentity(\"sampleTrigger\")\n\t\t\t.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever())\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic Trigger everyDayTrigger() {\n\t\treturn TriggerBuilder.newTrigger()\n\t\t\t.forJob(\"helloJob\", \"samples\")\n\t\t\t.withIdentity(\"every-day\", \"samples\")\n\t\t\t.withSchedule(SimpleScheduleBuilder.repeatHourlyForever(24))\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic Trigger threeAmWeekdaysTrigger() {\n\t\treturn TriggerBuilder.newTrigger()\n\t\t\t.forJob(\"anotherJob\", \"samples\")\n\t\t\t.withIdentity(\"3am-weekdays\", \"samples\")\n\t\t\t.withSchedule(CronScheduleBuilder.atHourAndMinuteOnGivenDaysOfWeek(3, 0, 1, 2, 3, 4, 5))\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic Trigger onceAWeekTrigger() {\n\t\treturn TriggerBuilder.newTrigger()\n\t\t\t.forJob(\"anotherJob\", \"samples\")\n\t\t\t.withIdentity(\"once-a-week\", \"samples\")\n\t\t\t.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInWeeks(1))\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic Trigger everyHourWorkingHourTuesdayAndThursdayTrigger() {\n\t\treturn TriggerBuilder.newTrigger()\n\t\t\t.forJob(\"helloJob\", \"samples\")\n\t\t\t.withIdentity(\"every-hour-tue-thu\", \"samples\")\n\t\t\t.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()\n\t\t\t\t.onDaysOfTheWeek(Calendar.TUESDAY, Calendar.THURSDAY)\n\t\t\t\t.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))\n\t\t\t\t.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(18, 0))\n\t\t\t\t.withInterval(1, IntervalUnit.HOUR))\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/src/main/java/smoketest/quartz/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.quartz;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/src/main/resources/application.properties",
    "content": "spring.quartz.job-store-type=jdbc\n\nmanagement.endpoints.web.exposure.include=health,quartz"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/src/test/java/smoketest/quartz/SampleQuartzApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.quartz;\n\nimport java.time.Duration;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.hamcrest.Matchers.containsString;\n\n/**\n * Tests for {@link SampleQuartzApplication}.\n *\n * @author Eddú Meléndez\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleQuartzApplicationTests {\n\n\t@Test\n\tvoid quartzJobIsTriggered(CapturedOutput output) {\n\t\ttry (ConfigurableApplicationContext context = SpringApplication.run(SampleQuartzApplication.class,\n\t\t\t\t\"--server.port=0\")) {\n\t\t\tAwaitility.waitAtMost(Duration.ofSeconds(5)).until(output::toString, containsString(\"Hello World!\"));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-quartz/src/test/java/smoketest/quartz/SampleQuartzApplicationWebTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.quartz;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Map;\n\nimport org.assertj.core.api.InstanceOfAssertFactories;\nimport org.assertj.core.api.InstanceOfAssertFactory;\nimport org.assertj.core.api.MapAssert;\nimport org.awaitility.Awaitility;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\nimport static org.assertj.core.api.Assertions.within;\n\n/**\n * Web tests for {@link SampleQuartzApplication}.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@ExtendWith(OutputCaptureExtension.class)\n@AutoConfigureTestRestTemplate\nclass SampleQuartzApplicationWebTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid quartzGroupNames() {\n\t\tMap<String, Object> content = getContent(\"/actuator/quartz\");\n\t\tassertThat(content).containsOnlyKeys(\"jobs\", \"triggers\");\n\t}\n\n\t@Test\n\tvoid quartzJobGroups() {\n\t\tMap<String, Object> content = getContent(\"/actuator/quartz/jobs\");\n\t\tassertThat(content).containsOnlyKeys(\"groups\");\n\t\tassertThat(content).extractingByKey(\"groups\", nestedMap()).containsOnlyKeys(\"samples\");\n\t}\n\n\t@Test\n\tvoid quartzTriggerGroups() {\n\t\tMap<String, Object> content = getContent(\"/actuator/quartz/triggers\");\n\t\tassertThat(content).containsOnlyKeys(\"groups\");\n\t\tassertThat(content).extractingByKey(\"groups\", nestedMap()).containsOnlyKeys(\"DEFAULT\", \"samples\");\n\t}\n\n\t@Test\n\tvoid quartzJobDetail() {\n\t\tMap<String, Object> content = getContent(\"/actuator/quartz/jobs/samples/helloJob\");\n\t\tassertThat(content).containsEntry(\"name\", \"helloJob\").containsEntry(\"group\", \"samples\");\n\t}\n\n\t@Test\n\tvoid quartzJobDetailWhenNameDoesNotExistReturns404() {\n\t\tResponseEntity<String> response = this.restTemplate.getForEntity(\"/actuator/quartz/jobs/samples/does-not-exist\",\n\t\t\t\tString.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid quartzTriggerDetail() {\n\t\tMap<String, Object> content = getContent(\"/actuator/quartz/triggers/samples/3am-weekdays\");\n\t\tassertThat(content).contains(entry(\"group\", \"samples\"), entry(\"name\", \"3am-weekdays\"), entry(\"state\", \"NORMAL\"),\n\t\t\t\tentry(\"type\", \"cron\"));\n\t}\n\n\t@Test\n\tvoid quartzTriggerDetailWhenNameDoesNotExistReturns404() {\n\t\tResponseEntity<String> response = this.restTemplate\n\t\t\t.getForEntity(\"/actuator/quartz/triggers/samples/does-not-exist\", String.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid quartzJobTriggeredManually(CapturedOutput output) {\n\t\tResponseEntity<Map<String, Object>> result = asMapEntity(this.restTemplate.postForEntity(\n\t\t\t\t\"/actuator/quartz/jobs/samples/onDemandJob\", new HttpEntity<>(Map.of(\"state\", \"running\")), Map.class));\n\t\tassertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> content = result.getBody();\n\t\tassertThat(content).contains(entry(\"group\", \"samples\"), entry(\"name\", \"onDemandJob\"),\n\t\t\t\tentry(\"className\", SampleJob.class.getName()));\n\t\tassertThat(content).extractingByKey(\"triggerTime\", InstanceOfAssertFactories.STRING)\n\t\t\t.satisfies((triggerTime) -> assertThat(Instant.parse(triggerTime)).isCloseTo(Instant.now(),\n\t\t\t\t\twithin(10, ChronoUnit.SECONDS)));\n\t\tAwaitility.await()\n\t\t\t.atMost(Duration.ofSeconds(30))\n\t\t\t.untilAsserted(() -> assertThat(output).contains(\"Hello On Demand Job\"));\n\t}\n\n\tprivate @Nullable Map<String, Object> getContent(String path) {\n\t\tResponseEntity<Map<String, Object>> entity = asMapEntity(this.restTemplate.getForEntity(path, Map.class));\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\treturn entity.getBody();\n\t}\n\n\t@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\n\tprivate static <K, V> ResponseEntity<Map<K, V>> asMapEntity(ResponseEntity<Map> entity) {\n\t\treturn (ResponseEntity) entity;\n\t}\n\n\t@SuppressWarnings(\"rawtypes\")\n\tprivate static InstanceOfAssertFactory<Map, MapAssert<String, Object>> nestedMap() {\n\t\treturn InstanceOfAssertFactories.map(String.class, Object.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot reactive OAuth 2 client smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-security-oauth2-client\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-oauth2-client-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webflux-test\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-client/src/main/java/smoketest/oauth2/client/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.client;\n\nimport java.security.Principal;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class ExampleController {\n\n\t@RequestMapping(\"/\")\n\tpublic String email(Principal principal) {\n\t\treturn \"Hello \" + principal.getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-client/src/main/java/smoketest/oauth2/client/SampleReactiveOAuth2ClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.client;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleReactiveOAuth2ClientApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleReactiveOAuth2ClientApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-client/src/main/java/smoketest/oauth2/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.oauth2.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-client/src/main/resources/application.yml",
    "content": "spring:\n  security:\n    oauth2:\n      client:\n        registration:\n          github-client-1:\n            client-id: ${APP-CLIENT-ID}\n            client-secret: ${APP-CLIENT-SECRET}\n            client-name: Github user\n            provider: github\n            scope: user\n            redirect-uri: http://localhost:8080/login/oauth2/code/github\n          github-client-2:\n            client-id: ${APP-CLIENT-ID}\n            client-secret: ${APP-CLIENT-SECRET}\n            client-name: Github email\n            provider: github\n            scope: user:email\n            redirect-uri: http://localhost:8080/login/oauth2/code/github\n          yahoo-oidc:\n            client-id: ${YAHOO-CLIENT-ID}\n            client-secret: ${YAHOO-CLIENT-SECRET}\n        provider:\n          yahoo-oidc:\n            issuer-uri: https://api.login.yahoo.com\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-client/src/test/java/smoketest/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.client;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"APP-CLIENT-ID=my-client-id\", \"APP-CLIENT-SECRET=my-client-secret\",\n\t\t\t\t\"YAHOO-CLIENT-ID=my-google-client-id\", \"YAHOO-CLIENT-SECRET=my-google-client-secret\" })\n@AutoConfigureWebTestClient\nclass SampleReactiveOAuth2ClientApplicationTests {\n\n\t@Autowired\n\tprivate WebTestClient webTestClient;\n\n\t@Test\n\tvoid everythingShouldRedirectToLogin() {\n\t\tthis.webTestClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isFound()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(\"Location\", \"/login\");\n\t}\n\n\t@Test\n\tvoid loginShouldHaveBothOAuthClientsToChooseFrom() {\n\t\tbyte[] body = this.webTestClient.get()\n\t\t\t.uri(\"/login\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.returnResult(String.class)\n\t\t\t.getResponseBodyContent();\n\t\tString bodyString = new String(body);\n\t\tassertThat(bodyString).contains(\"/oauth2/authorization/yahoo\");\n\t\tassertThat(bodyString).contains(\"/oauth2/authorization/github-client-1\");\n\t\tassertThat(bodyString).contains(\"/oauth2/authorization/github-client-2\");\n\t}\n\n\t@Test\n\tvoid actuatorShouldBeSecuredByOAuth() {\n\t\tthis.webTestClient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isFound()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(\"Location\", \"/login\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-resource-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot reactive OAuth 2 resource server smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security-oauth2-resource-server\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webflux-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-security-oauth2-resource-server-test\"))\n\ttestImplementation(\"com.squareup.okhttp3:mockwebserver\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-resource-server/src/main/java/smoketest/oauth2/resource/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.resource;\n\nimport org.springframework.security.core.annotation.AuthenticationPrincipal;\nimport org.springframework.security.oauth2.jwt.Jwt;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class ExampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String index(@AuthenticationPrincipal Jwt jwt) {\n\t\treturn String.format(\"Hello, %s!\", jwt.getSubject());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-resource-server/src/main/java/smoketest/oauth2/resource/SampleReactiveOAuth2ResourceServerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.resource;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleReactiveOAuth2ResourceServerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleReactiveOAuth2ResourceServerApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-resource-server/src/main/java/smoketest/oauth2/resource/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.oauth2.resource;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-resource-server/src/main/resources/application.yml",
    "content": "spring:\n  security:\n    oauth2:\n      resourceserver:\n        jwt:\n          # To run the application, replace this with a valid JWK Set URI\n          jwk-set-uri: https://example.com/oauth2/default/v1/keys\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-reactive-oauth2-resource-server/src/test/java/smoketest/oauth2/resource/SampleReactiveOAuth2ResourceServerApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.oauth2.resource;\n\nimport okhttp3.mockwebserver.MockResponse;\nimport okhttp3.mockwebserver.MockWebServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebTestClient\nclass SampleReactiveOAuth2ResourceServerApplicationTests {\n\n\t@Autowired\n\tprivate WebTestClient webTestClient;\n\n\tprivate static final MockWebServer server = new MockWebServer();\n\n\tprivate static final String VALID_TOKEN = \"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQi\"\n\t\t\t+ \"LCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgU\"\n\t\t\t+ \"OBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwIN\"\n\t\t\t+ \"afU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_Ql\"\n\t\t\t+ \"R44vmRqS5ncrF-1R0EGcPX49U6A\";\n\n\t@BeforeAll\n\tstatic void setup() throws Exception {\n\t\tserver.start();\n\t\tString url = server.url(\"/.well-known/jwks.json\").toString();\n\t\tserver.enqueue(mockResponse());\n\t\tSystem.setProperty(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\", url);\n\t}\n\n\t@AfterAll\n\tstatic void shutdown() throws Exception {\n\t\tserver.shutdown();\n\t\tSystem.clearProperty(\"spring.security.oauth2.resourceserver.jwt.jwk-set-uri\");\n\t}\n\n\t@Test\n\tvoid getWhenValidTokenShouldBeOk() {\n\t\tthis.webTestClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.headers((headers) -> headers.setBearerAuth(VALID_TOKEN))\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello, subject!\");\n\t}\n\n\t@Test\n\tvoid getWhenNoTokenShouldBeUnauthorized() {\n\t\tthis.webTestClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized()\n\t\t\t.expectHeader()\n\t\t\t.valueEquals(HttpHeaders.WWW_AUTHENTICATE, \"Bearer\");\n\t}\n\n\tprivate static MockResponse mockResponse() {\n\t\tString body = \"{\\\"keys\\\":[{\\\"p\\\":\\\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMw\"\n\t\t\t\t+ \"DBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\\\"\"\n\t\t\t\t+ \",\\\"kty\\\":\\\"RSA\\\",\\\"q\\\":\\\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO\"\n\t\t\t\t+ \"1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\\\",\\\"d\\\"\"\n\t\t\t\t+ \":\\\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7\"\n\t\t\t\t+ \"VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0\"\n\t\t\t\t+ \"851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo\"\n\t\t\t\t+ \"3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\\\",\\\"e\\\":\\\"AQAB\\\",\\\"use\\\":\\\"sig\\\",\\\"kid\\\":\\\"one\\\",\\\"qi\\\":\\\"qS0OK4\"\n\t\t\t\t+ \"8M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6o\"\n\t\t\t\t+ \"XZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\\\",\\\"dp\\\":\\\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQ\"\n\t\t\t\t+ \"PDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8\"\n\t\t\t\t+ \"M6NfObDFmbTc_3tJkN_raISo8z_ziIE\\\",\\\"dq\\\":\\\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkF\"\n\t\t\t\t+ \"k5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrn\"\n\t\t\t\t+ \"uYNNtG4_4Bt0\\\",\\\"n\\\":\\\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHs\"\n\t\t\t\t+ \"V9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC5\"\n\t\t\t\t+ \"8CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eq\"\n\t\t\t\t+ \"D9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\\\"}]}\";\n\t\treturn new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)\n\t\t\t.setResponseCode(200)\n\t\t\t.setBody(body);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Rest Client smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-restclient\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/src/main/java/aaaa/Gh49223AutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage aaaa;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\n\n@AutoConfiguration(afterName = { \"org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration\",\n\t\t\"org.springframework.boot.restclient.autoconfigure.RestTemplateAutoConfiguration\" })\npublic final class Gh49223AutoConfiguration {\n\n\t// Class must be in a package name that is ordered early\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/src/main/java/aaaa/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage aaaa;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/src/main/java/smoketest/restclient/SampleRestClientApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.restclient;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleRestClientApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleRestClientApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/src/main/java/smoketest/restclient/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.restclient;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "aaaa.Gh49223AutoConfiguration\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-restclient/src/test/java/smoketest/restclient/SampleRestClientApplicationGh49223Tests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.restclient;\n\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.DeserializationFeature;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.web.client.RestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(properties = \"spring.jackson.deserialization.fail-on-null-for-primitives=false\")\nclass SampleRestClientApplicationGh49223Tests {\n\n\t@Autowired\n\tprivate RestClient.Builder restClientBuilder;\n\n\t@Test\n\tvoid applicationStarts() {\n\t\tRestClient restClient = this.restClientBuilder.build();\n\t\tList<?> messageConverters = (List<?>) ReflectionTestUtils.getField(restClient, \"messageConverters\");\n\t\tassertThat(messageConverters).isNotNull();\n\t\tJacksonJsonHttpMessageConverter jacksonConverter = (JacksonJsonHttpMessageConverter) messageConverters.stream()\n\t\t\t.filter((converter) -> converter instanceof JacksonJsonHttpMessageConverter)\n\t\t\t.findFirst()\n\t\t\t.orElseThrow();\n\t\tassertThat(jacksonConverter.getMapper().isEnabled(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES))\n\t\t\t.isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot RSocket smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-rsocket\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(\"org.springframework.security:spring-security-rsocket\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-rsocket-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/src/main/java/smoketest/rsocket/Project.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.rsocket;\n\npublic class Project {\n\n\tprivate final String name;\n\n\tpublic Project(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/src/main/java/smoketest/rsocket/ProjectController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.rsocket;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.messaging.handler.annotation.DestinationVariable;\nimport org.springframework.messaging.handler.annotation.MessageMapping;\nimport org.springframework.stereotype.Controller;\n\n@Controller\npublic class ProjectController {\n\n\t@MessageMapping(\"find.project.{name}\")\n\tpublic Mono<Project> findProject(@DestinationVariable String name) {\n\t\treturn Mono.just(new Project(name));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/src/main/java/smoketest/rsocket/SampleRSocketApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.rsocket;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleRSocketApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleRSocketApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/src/main/java/smoketest/rsocket/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.rsocket;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/src/main/resources/application.properties",
    "content": "spring.rsocket.server.port=0\nspring.security.user.password=password\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-rsocket/src/test/java/smoketest/rsocket/SampleRSocketApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.rsocket;\n\nimport java.time.Duration;\n\nimport io.rsocket.metadata.WellKnownMimeType;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\nimport reactor.test.StepVerifier;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.rsocket.server.LocalRSocketServerPort;\nimport org.springframework.messaging.rsocket.RSocketRequester;\nimport org.springframework.security.rsocket.metadata.SimpleAuthenticationEncoder;\nimport org.springframework.security.rsocket.metadata.UsernamePasswordMetadata;\nimport org.springframework.util.MimeTypeUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(properties = \"spring.rsocket.server.port=0\")\nclass SampleRSocketApplicationTests {\n\n\t@LocalRSocketServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate RSocketRequester.Builder builder;\n\n\t@Test\n\tvoid unauthenticatedAccessToRSocketEndpoint() {\n\t\tRSocketRequester requester = this.builder.tcp(\"localhost\", this.port);\n\t\tMono<Project> result = requester.route(\"find.project.spring-boot\").retrieveMono(Project.class);\n\t\tStepVerifier.create(result).expectErrorMessage(\"Access Denied\").verify();\n\t}\n\n\t@Test\n\tvoid rSocketEndpoint() {\n\t\tRSocketRequester requester = this.builder\n\t\t\t.rsocketStrategies((builder) -> builder.encoder(new SimpleAuthenticationEncoder()))\n\t\t\t.setupMetadata(new UsernamePasswordMetadata(\"user\", \"password\"),\n\t\t\t\t\tMimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString()))\n\t\t\t.tcp(\"localhost\", this.port);\n\t\tMono<Project> result = requester.route(\"find.project.spring-boot\").retrieveMono(Project.class);\n\t\tStepVerifier.create(result)\n\t\t\t.assertNext((project) -> assertThat(project.getName()).isEqualTo(\"spring-boot\"))\n\t\t\t.expectComplete()\n\t\t\t.verify(Duration.ofSeconds(30));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot SAML 2 service provider smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security-saml2\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-saml2-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/main/java/smoketest/saml2/serviceprovider/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.saml2.serviceprovider;\n\nimport java.security.Principal;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class ExampleController {\n\n\t@RequestMapping(\"/\")\n\tpublic String email(Principal principal) {\n\t\treturn \"Hello \" + principal.getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/main/java/smoketest/saml2/serviceprovider/SampleSaml2RelyingPartyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.saml2.serviceprovider;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleSaml2RelyingPartyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSaml2RelyingPartyApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/main/java/smoketest/saml2/serviceprovider/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.saml2.serviceprovider;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/main/resources/application.yml",
    "content": "spring:\n  security:\n    saml2:\n      relyingparty:\n        registration:\n          simplesamlphp:\n            signing:\n              credentials:\n              - private-key-location: \"classpath:saml/privatekey.txt\"\n                certificate-location: \"classpath:saml/certificate.txt\"\n            assertingparty:\n              verification:\n                credentials:\n                  - certificate-location: \"classpath:saml/certificate.txt\"\n              entity-id: simplesaml\n              singlesignon:\n                url: https://simplesaml-for-spring-saml/SSOService.php\n            relying-party-entity-id: \"{baseUrl}/saml2/simple-relying-party\"\n          okta:\n            signing:\n              credentials:\n              - private-key-location: \"classpath:saml/privatekey.txt\"\n                certificate-location: \"classpath:saml/certificate.txt\"\n            assertingparty:\n              verification:\n                credentials:\n                  - certificate-location: \"classpath:saml/certificate.txt\"\n              entity-id: okta-id-1234\n              singlesignon:\n                url:\n                  https://okta-for-spring/saml2/idp/SSOService.php\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/main/resources/saml/certificate.txt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\nVQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX\nc2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw\naXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ\nBgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa\nBgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD\nDBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr\nQHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62\nE1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz\n2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW\nRDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ\nnX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5\ncljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph\niJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5\nogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD\nAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO\nnRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v\nZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\nxbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\nV9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\nlx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n-----END CERTIFICATE-----"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/main/resources/saml/privatekey.txt",
    "content": "-----BEGIN PRIVATE KEY-----\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\nVUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\ncDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6\nQ2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn\nx7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5\nwJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd\nvwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY\n8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX\noPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx\nEGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\nKkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\nYX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\nINrtuLp4YHbgk1mi\n-----END PRIVATE KEY-----"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-saml2-service-provider/src/test/java/smoketest/saml2/serviceprovider/SampleSaml2RelyingPartyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.saml2.serviceprovider;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleSaml2RelyingPartyApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid everythingShouldRedirectToLogin() {\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tassertThat(entity.getHeaders().getLocation()).isEqualTo(URI.create(\"http://localhost:\" + this.port + \"/login\"));\n\t}\n\n\t@Test\n\tvoid loginShouldHaveAllAssertingPartiesToChooseFrom() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/login\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"/saml2/authenticate?registrationId=simplesamlphp\");\n\t\tassertThat(entity.getBody()).contains(\"/saml2/authenticate?registrationId=okta\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Security smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure/src/main/java/smoketest/secure/SampleSecureApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.core.authority.AuthorityUtils;\nimport org.springframework.security.core.context.SecurityContextHolder;\n\n@EnableAutoConfiguration\n@ComponentScan\n@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true)\npublic class SampleSecureApplication implements CommandLineRunner {\n\n\t@Autowired\n\tprivate SampleService service;\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tSecurityContextHolder.getContext()\n\t\t\t.setAuthentication(new UsernamePasswordAuthenticationToken(\"user\", \"N/A\",\n\t\t\t\t\tAuthorityUtils.commaSeparatedStringToAuthorityList(\"ROLE_USER\")));\n\t\ttry {\n\t\t\tSystem.out.println(this.service.secure());\n\t\t}\n\t\tfinally {\n\t\t\tSecurityContextHolder.clearContext();\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSecureApplication.class, \"--debug\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure/src/main/java/smoketest/secure/SampleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure;\n\nimport org.springframework.security.access.annotation.Secured;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class SampleService {\n\n\t@Secured(\"ROLE_USER\")\n\tpublic String secure() {\n\t\treturn \"Hello Security\";\n\t}\n\n\t@PreAuthorize(\"true\")\n\tpublic String authorized() {\n\t\treturn \"Hello World\";\n\t}\n\n\t@PreAuthorize(\"false\")\n\tpublic String denied() {\n\t\treturn \"Goodbye World\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure/src/main/java/smoketest/secure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.secure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure/src/main/resources/application.properties",
    "content": "# debug: true\nspring.security.user.name=user\nspring.security.user.password=password\nspring.security.user.roles=USER\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure/src/test/java/smoketest/secure/SampleSecureApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.AuthenticationException;\nimport org.springframework.security.core.authority.AuthorityUtils;\nimport org.springframework.security.core.context.SecurityContextHolder;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(classes = { SampleSecureApplication.class })\nclass SampleSecureApplicationTests {\n\n\t@Autowired\n\tprivate SampleService service;\n\n\tprivate Authentication authentication;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.authentication = new UsernamePasswordAuthenticationToken(\"user\", \"password\");\n\t}\n\n\t@AfterEach\n\tvoid close() {\n\t\tSecurityContextHolder.clearContext();\n\t}\n\n\t@Test\n\tvoid secure() {\n\t\tassertThatExceptionOfType(AuthenticationException.class)\n\t\t\t.isThrownBy(() -> SampleSecureApplicationTests.this.service.secure());\n\t}\n\n\t@Test\n\tvoid authenticated() {\n\t\tSecurityContextHolder.getContext()\n\t\t\t.setAuthentication(new UsernamePasswordAuthenticationToken(\"user\", \"N/A\",\n\t\t\t\t\tAuthorityUtils.commaSeparatedStringToAuthorityList(\"ROLE_USER\")));\n\t\tassertThat(this.service.secure()).isEqualTo(\"Hello Security\");\n\t}\n\n\t@Test\n\tvoid preauth() {\n\t\tSecurityContextHolder.getContext().setAuthentication(this.authentication);\n\t\tassertThat(this.service.authorized()).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid denied() {\n\t\tSecurityContextHolder.getContext().setAuthentication(this.authentication);\n\t\tassertThatExceptionOfType(AccessDeniedException.class)\n\t\t\t.isThrownBy(() -> SampleSecureApplicationTests.this.service.denied());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot secure Jersey smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-jersey\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-jersey-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/Endpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\n\nimport org.springframework.stereotype.Component;\n\n@Component\n@Path(\"/hello\")\npublic class Endpoint {\n\n\tprivate final Service service;\n\n\tpublic Endpoint(Service service) {\n\t\tthis.service = service;\n\t}\n\n\t@GET\n\tpublic String message() {\n\t\treturn \"Hello \" + this.service.message();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/JerseyConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.glassfish.jersey.server.ResourceConfig;\n\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class JerseyConfig extends ResourceConfig {\n\n\tpublic JerseyConfig() {\n\t\tregister(Endpoint.class);\n\t\tregister(ReverseEndpoint.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/ReverseEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport jakarta.validation.constraints.NotNull;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.QueryParam;\n\nimport org.springframework.stereotype.Component;\n\n@Component\n@Path(\"/reverse\")\npublic class ReverseEndpoint {\n\n\t@GET\n\tpublic String reverse(@QueryParam(\"input\") @NotNull String input) {\n\t\treturn new StringBuilder(input).reverse().toString();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/SampleSecureJerseyApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport java.io.IOException;\nimport java.util.function.Supplier;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.actuate.endpoint.web.EndpointServlet;\nimport org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\n@SuppressWarnings(\"removal\")\npublic class SampleSecureJerseyApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSecureJerseyApplication.class, args);\n\t}\n\n\t@Bean\n\tTestServletEndpoint servletEndpoint() {\n\t\treturn new TestServletEndpoint();\n\t}\n\n\t@ServletEndpoint(id = \"se1\")\n\t@SuppressWarnings(\"removal\")\n\tstatic class TestServletEndpoint implements Supplier<EndpointServlet> {\n\n\t\t@Override\n\t\tpublic EndpointServlet get() {\n\t\t\treturn new EndpointServlet(ExampleServlet.class);\n\t\t}\n\n\t}\n\n\tstatic class ExampleServlet extends HttpServlet {\n\n\t\t@Override\n\t\tprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/SecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.Customizer;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration\npublic class SecurityConfiguration {\n\n\t@Bean\n\t@SuppressWarnings(\"deprecation\")\n\tpublic InMemoryUserDetailsManager inMemoryUserDetailsManager() {\n\t\treturn new InMemoryUserDetailsManager(\n\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t.username(\"user\")\n\t\t\t\t\t.password(\"password\")\n\t\t\t\t\t.authorities(\"ROLE_USER\")\n\t\t\t\t\t.build(),\n\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t.username(\"admin\")\n\t\t\t\t\t.password(\"admin\")\n\t\t\t\t\t.authorities(\"ROLE_ACTUATOR\", \"ROLE_USER\")\n\t\t\t\t\t.build());\n\t}\n\n\t@Bean\n\tSecurityFilterChain configure(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\trequests.requestMatchers(EndpointRequest.to(\"health\")).permitAll();\n\t\t\trequests.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))\n\t\t\t\t.hasRole(\"ACTUATOR\");\n\t\t\trequests.requestMatchers(\"/**\").hasRole(\"USER\");\n\t\t});\n\t\thttp.httpBasic(Customizer.withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/Service.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class Service {\n\n\t@Value(\"${message:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String msg;\n\n\tpublic String message() {\n\t\treturn this.msg;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/java/smoketest/secure/jersey/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.secure.jersey;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nmanagement.endpoint.health.show-details=always\n\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/test/java/smoketest/secure/jersey/AbstractJerseySecureTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for actuator tests with custom security.\n *\n * @author Madhura Bhave\n */\n@AutoConfigureTestRestTemplate\nabstract class AbstractJerseySecureTests {\n\n\tabstract String getPath();\n\n\tabstract String getManagementPath();\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid helloEndpointIsSecure() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getPath() + \"/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid actuatorInsecureEndpoint() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + \"/actuator/health\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t\tentity = restTemplate().getForEntity(getManagementPath() + \"/actuator/health/diskSpace\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\t@Test\n\tvoid actuatorLinksWithAnonymous() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + \"/actuator\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = restTemplate().getForEntity(getManagementPath() + \"/actuator/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid actuatorLinksWithUnauthorizedUser() {\n\t\tResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + \"/actuator\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tentity = userRestTemplate().getForEntity(getManagementPath() + \"/actuator/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid actuatorLinksWithAuthorizedUser() {\n\t\tResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + \"/actuator\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tadminRestTemplate().getForEntity(getManagementPath() + \"/actuator/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid actuatorSecureEndpointWithAnonymous() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + \"/actuator/env\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = restTemplate().getForEntity(\n\t\t\t\tgetManagementPath() + \"/actuator/env/management.endpoints.web.exposure.include\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid actuatorSecureEndpointWithUnauthorizedUser() {\n\t\tResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + \"/actuator/env\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tentity = userRestTemplate().getForEntity(\n\t\t\t\tgetManagementPath() + \"/actuator/env/management.endpoints.web.exposure.include\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid actuatorSecureEndpointWithAuthorizedUser() {\n\t\tResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + \"/actuator/env\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tentity = adminRestTemplate().getForEntity(\n\t\t\t\tgetManagementPath() + \"/actuator/env/management.endpoints.web.exposure.include\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid secureServletEndpointWithAnonymous() {\n\t\tResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + \"/actuator/se1\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tentity = restTemplate().getForEntity(getManagementPath() + \"/actuator/se1/list\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid secureServletEndpointWithUnauthorizedUser() {\n\t\tResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + \"/actuator/se1\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tentity = userRestTemplate().getForEntity(getManagementPath() + \"/actuator/se1/list\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t}\n\n\t@Test\n\tvoid secureServletEndpointWithAuthorizedUser() {\n\t\tResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + \"/actuator/se1\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tentity = adminRestTemplate().getForEntity(getManagementPath() + \"/actuator/se1/list\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid actuatorExcludedFromEndpointRequestMatcher() {\n\t\tResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + \"/actuator/mappings\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\tTestRestTemplate restTemplate() {\n\t\treturn this.testRestTemplate;\n\t}\n\n\tTestRestTemplate adminRestTemplate() {\n\t\treturn this.testRestTemplate.withBasicAuth(\"admin\", \"admin\");\n\t}\n\n\tTestRestTemplate userRestTemplate() {\n\t\treturn this.testRestTemplate.withBasicAuth(\"user\", \"password\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/test/java/smoketest/secure/jersey/CustomApplicationPathActuatorTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\n\n/**\n * Integration tests for actuator endpoints with custom application path.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.jersey.application-path=/example\")\nclass CustomApplicationPathActuatorTests extends AbstractJerseySecureTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/example\";\n\t}\n\n\t@Override\n\tString getManagementPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/example\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/test/java/smoketest/secure/jersey/JerseySecureApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\n\n/**\n * Integration tests for actuator endpoints with custom security configuration.\n *\n * @author Madhura Bhave\n * @author Stephane Nicoll\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\nclass JerseySecureApplicationTests extends AbstractJerseySecureTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port;\n\t}\n\n\t@Override\n\tString getManagementPath() {\n\t\treturn \"http://localhost:\" + this.port;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/test/java/smoketest/secure/jersey/ManagementPortAndPathJerseyApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with custom management\n * context path.\n *\n * @author Dave Syer\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"management.server.base-path=/management\" })\nclass ManagementPortAndPathJerseyApplicationTests extends AbstractJerseySecureTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid testMissing() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"admin\", \"admin\")\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/management/actuator/missing\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port;\n\t}\n\n\t@Override\n\tString getManagementPath() {\n\t\treturn \"http://localhost:\" + this.managementPort + \"/management\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-jersey/src/test/java/smoketest/secure/jersey/ManagementPortCustomApplicationPathJerseyTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.jersey;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with custom\n * application path.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"spring.jersey.application-path=/example\" })\nclass ManagementPortCustomApplicationPathJerseyTests extends AbstractJerseySecureTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid actuatorPathOnMainPortShouldNotMatch() {\n\t\tResponseEntity<String> entity = new TestRestTemplate()\n\t\t\t.getForEntity(\"http://localhost:\" + this.port + \"/example/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Override\n\tString getPath() {\n\t\treturn \"http://localhost:\" + this.port + \"/example\";\n\t}\n\n\t@Override\n\tString getManagementPath() {\n\t\treturn \"http://localhost:\" + this.managementPort;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot secure WebFlux smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webflux-test\"))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/main/java/smoketest/secure/webflux/EchoHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\n@Component\npublic class EchoHandler {\n\n\tpublic Mono<ServerResponse> echo(ServerRequest request) {\n\t\treturn ServerResponse.ok().body(request.bodyToMono(String.class), String.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/main/java/smoketest/secure/webflux/SampleSecureWebFluxApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.springframework.web.reactive.function.server.RequestPredicates.POST;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n@SpringBootApplication\npublic class SampleSecureWebFluxApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSecureWebFluxApplication.class);\n\t}\n\n\t@Bean\n\tpublic RouterFunction<ServerResponse> monoRouterFunction(EchoHandler echoHandler) {\n\t\treturn route(POST(\"/echo\"), echoHandler::echo);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/main/java/smoketest/secure/webflux/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport java.security.Principal;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class WelcomeController {\n\n\t@GetMapping(\"/\")\n\tpublic String welcome(Principal principal) {\n\t\treturn \"Hello \" + principal.getName();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/main/java/smoketest/secure/webflux/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.secure.webflux;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/main/resources/application.properties",
    "content": "spring.security.user.name=user\nspring.security.user.password=password\nmanagement.endpoints.web.exposure.include=*\n\ndebug=true"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/test/java/smoketest/secure/webflux/CorsSampleActuatorApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration test for cors preflight requests to management endpoints.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@ActiveProfiles(\"cors\")\n@AutoConfigureWebTestClient\nclass CorsSampleActuatorApplicationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid endpointShouldReturnUnauthorized() {\n\t\tthis.webClient.get().uri(\"/actuator/env\").exchange().expectStatus().isUnauthorized();\n\t}\n\n\t@Test\n\tvoid preflightRequestToEndpointShouldReturnOk() {\n\t\tthis.webClient.options()\n\t\t\t.uri(\"/actuator/env\")\n\t\t\t.header(\"Origin\", \"http://localhost:8080\")\n\t\t\t.header(\"Access-Control-Request-Method\", \"GET\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\t@Test\n\tvoid preflightRequestWhenCorsConfigInvalidShouldReturnForbidden() {\n\t\tthis.webClient.options()\n\t\t\t.uri(\"/actuator/env\")\n\t\t\t.header(\"Origin\", \"http://localhost:9095\")\n\t\t\t.header(\"Access-Control-Request-Method\", \"GET\")\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isForbidden();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/test/java/smoketest/secure/webflux/ManagementPortSampleSecureWebFluxTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.security.autoconfigure.actuate.web.reactive.EndpointRequest;\nimport org.springframework.boot.security.autoconfigure.web.reactive.PathRequest;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Integration tests for separate management and main service ports.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { \"management.server.port=0\" },\n\t\tclasses = { ManagementPortSampleSecureWebFluxTests.SecurityConfiguration.class,\n\t\t\t\tSampleSecureWebFluxApplication.class })\n@AutoConfigureWebTestClient\nclass ManagementPortSampleSecureWebFluxTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid testHome() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"http://localhost:\" + this.port, String.class)\n\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello user\");\n\t}\n\n\t@Test\n\tvoid actuatorPathOnMainPortShouldNotMatch() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"http://localhost:\" + this.port + \"/actuator\", String.class)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized();\n\t\tthis.webClient.get()\n\t\t\t.uri(\"http://localhost:\" + this.port + \"/actuator/health\", String.class)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized();\n\t}\n\n\t@Test\n\tvoid testSecureActuator() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"http://localhost:\" + this.managementPort + \"/actuator/env\", String.class)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized();\n\t}\n\n\t@Test\n\tvoid testInsecureActuator() {\n\t\tString responseBody = this.webClient.get()\n\t\t\t.uri(\"http://localhost:\" + this.managementPort + \"/actuator/health\", String.class)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody(String.class)\n\t\t\t.returnResult()\n\t\t\t.getResponseBody();\n\t\tassertThat(responseBody).contains(\"\\\"status\\\":\\\"UP\\\"\");\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\t\thttp.authorizeExchange((exchanges) -> {\n\t\t\t\texchanges.matchers(EndpointRequest.to(\"health\")).permitAll();\n\t\t\t\texchanges.matchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))\n\t\t\t\t\t.hasRole(\"ACTUATOR\");\n\t\t\t\texchanges.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();\n\t\t\t\texchanges.pathMatchers(\"/login\").permitAll();\n\t\t\t\texchanges.anyExchange().authenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/test/java/smoketest/secure/webflux/SampleSecureWebFluxApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration tests for a secure reactive application.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"management.endpoint.health.show-details=never\")\n@AutoConfigureWebTestClient\nclass SampleSecureWebFluxApplicationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid userDefinedMappingsSecureByDefault() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid healthInsecureByDefault() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\t@Test\n\tvoid otherActuatorsSecureByDefault() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/env\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized();\n\t}\n\n\t@Test\n\tvoid userDefinedMappingsAccessibleOnLogin() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t.exchange()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello user\");\n\t}\n\n\t@Test\n\tvoid actuatorsAccessibleOnLogin() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t.exchange()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"{\\\"groups\\\":[\\\"liveness\\\",\\\"readiness\\\"],\\\"status\\\":\\\"UP\\\"}\");\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/test/java/smoketest/secure/webflux/SampleSecureWebFluxCustomSecurityTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.secure.webflux;\n\nimport java.util.Base64;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.actuate.web.mappings.MappingsEndpoint;\nimport org.springframework.boot.security.autoconfigure.actuate.web.reactive.EndpointRequest;\nimport org.springframework.boot.security.autoconfigure.web.reactive.PathRequest;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.core.userdetails.MapReactiveUserDetailsService;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Integration tests for a secure reactive application with custom security.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tclasses = { SampleSecureWebFluxCustomSecurityTests.SecurityConfiguration.class,\n\t\t\t\tSampleSecureWebFluxApplication.class })\n@AutoConfigureWebTestClient\nclass SampleSecureWebFluxCustomSecurityTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid userDefinedMappingsSecure() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid healthDoesNotRequireAuthentication() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\t@Test\n\tvoid actuatorsSecuredByRole() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/env\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isForbidden();\n\t}\n\n\t@Test\n\tvoid actuatorsAccessibleOnCorrectLogin() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/env\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", getBasicAuthForAdmin())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\t@Test\n\tvoid actuatorExcludedFromEndpointRequestMatcher() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/mappings\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", getBasicAuth())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\t@Test\n\tvoid staticResourceShouldBeAccessible() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/css/bootstrap.min.css\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\t@Test\n\tvoid actuatorLinksIsSecure() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isUnauthorized();\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.header(\"Authorization\", getBasicAuthForAdmin())\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk();\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n\tprivate String getBasicAuthForAdmin() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"admin:admin\".getBytes());\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@SuppressWarnings(\"deprecation\")\n\t\t@Bean\n\t\tMapReactiveUserDetailsService userDetailsService() {\n\t\t\treturn new MapReactiveUserDetailsService(\n\t\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t\t.username(\"user\")\n\t\t\t\t\t\t.password(\"password\")\n\t\t\t\t\t\t.authorities(\"ROLE_USER\")\n\t\t\t\t\t\t.build(),\n\t\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t\t.username(\"admin\")\n\t\t\t\t\t\t.password(\"admin\")\n\t\t\t\t\t\t.authorities(\"ROLE_ACTUATOR\", \"ROLE_USER\")\n\t\t\t\t\t\t.build());\n\t\t}\n\n\t\t@Bean\n\t\tSecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\t\thttp.authorizeExchange((exchanges) -> {\n\t\t\t\texchanges.matchers(EndpointRequest.to(\"health\")).permitAll();\n\t\t\t\texchanges.matchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class))\n\t\t\t\t\t.hasRole(\"ACTUATOR\");\n\t\t\t\texchanges.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll();\n\t\t\t\texchanges.pathMatchers(\"/login\").permitAll();\n\t\t\t\texchanges.anyExchange().authenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-secure-webflux/src/test/resources/application-cors.properties",
    "content": "management.endpoints.web.cors.allowed-origins=http://localhost:8080\nmanagement.endpoints.web.cors.allowed-methods=GET\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-servlet/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot Servlet smoke test\"\n\ndependencies {\n\tcompileOnly(project(\":starter:spring-boot-starter-tomcat\"))\n\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n\n\ttestRuntimeOnly(project(\":starter:spring-boot-starter-tomcat\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-servlet/src/main/java/smoketest/servlet/SampleServletApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.Servlet;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.SpringBootConfiguration;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootConfiguration\n@EnableAutoConfiguration\npublic class SampleServletApplication extends SpringBootServletInitializer {\n\n\t@SuppressWarnings(\"serial\")\n\t@Bean\n\tpublic Servlet dispatcherServlet() {\n\t\treturn new GenericServlet() {\n\t\t\t@Override\n\t\t\tpublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n\t\t\t\tres.setContentType(\"text/plain\");\n\t\t\t\tres.getWriter().append(\"Hello World\");\n\t\t\t}\n\t\t};\n\t}\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleServletApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleServletApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-servlet/src/main/java/smoketest/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.servlet;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-servlet/src/main/resources/application.properties",
    "content": "spring.security.user.name=user\nspring.security.user.password=password\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-servlet/src/test/java/smoketest/servlet/SampleServletApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.servlet;\n\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleServletApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHomeIsSecure() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, new HttpEntity<>(headers),\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.withBasicAuth(\"user\", getPassword())\n\t\t\t.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t}\n\n\tprivate String getPassword() {\n\t\treturn \"password\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Session Redis smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-session-data-redis\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":module:spring-boot-restclient\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-session-data-redis-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/dockerTest/java/smoketest/session/redis/SampleSessionRedisApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport java.net.URI;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleSessionRedisApplication}.\n *\n * @author Angel L. Villalain\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@Testcontainers(disabledWithoutDocker = true)\n@AutoConfigureTestRestTemplate\nclass SampleSessionRedisApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\tstatic RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid sessionsEndpointShouldReturnUserSessions() {\n\t\tperformLogin();\n\t\tResponseEntity<Map<String, Object>> response = getSessions();\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> body = response.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tList<Map<String, Object>> sessions = (List<Map<String, Object>>) body.get(\"sessions\");\n\t\tassertThat(sessions).hasSize(1);\n\t}\n\n\tprivate void performLogin() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"user\");\n\t\tform.set(\"password\", \"password\");\n\t\tthis.restTemplate.exchange(\"/login\", HttpMethod.POST, new HttpEntity<>(form, headers), String.class);\n\t}\n\n\tprivate RequestEntity<Object> getRequestEntity(URI uri) {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setBasicAuth(\"user\", \"password\");\n\t\treturn new RequestEntity<>(headers, HttpMethod.GET, uri);\n\t}\n\n\tprivate ResponseEntity<Map<String, Object>> getSessions() {\n\t\tRequestEntity<Object> request = getRequestEntity(URI.create(\"/actuator/sessions?username=user\"));\n\t\tParameterizedTypeReference<Map<String, Object>> stringObjectMap = new ParameterizedTypeReference<>() {\n\t\t};\n\t\treturn this.restTemplate.exchange(request, stringObjectMap);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/dockerTest/java/smoketest/session/redis/TestPropertiesImportSampleSessionRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport com.redis.testcontainers.RedisContainer;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\npublic class TestPropertiesImportSampleSessionRedisApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.from(SampleSessionRedisApplication::main).with(ContainerConfiguration.class).run(args);\n\t}\n\n\t@ImportTestcontainers\n\tstatic class ContainerConfiguration {\n\n\t\tstatic RedisContainer container = TestImage.container(RedisContainer.class);\n\n\t\t@DynamicPropertySource\n\t\tstatic void containerProperties(DynamicPropertyRegistry properties) {\n\t\t\tproperties.add(\"spring.data.redis.host\", container::getHost);\n\t\t\tproperties.add(\"spring.data.redis.port\", container::getFirstMappedPort);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/dockerTest/java/smoketest/session/redis/TestPropertiesSampleSessionRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport com.redis.testcontainers.RedisContainer;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.test.context.DynamicPropertyRegistry;\n\npublic class TestPropertiesSampleSessionRedisApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.from(SampleSessionRedisApplication::main).with(ContainerConfiguration.class).run(args);\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class ContainerConfiguration {\n\n\t\t@Bean\n\t\tRedisContainer redisContainer(DynamicPropertyRegistry properties) {\n\t\t\tRedisContainer container = TestImage.container(RedisContainer.class);\n\t\t\tproperties.add(\"spring.data.redis.host\", container::getHost);\n\t\t\tproperties.add(\"spring.data.redis.port\", container::getFirstMappedPort);\n\t\t\treturn container;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/dockerTest/java/smoketest/session/redis/TestServiceConnectionImportSampleSessionRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport com.redis.testcontainers.RedisContainer;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.testcontainers.context.ImportTestcontainers;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\n\npublic class TestServiceConnectionImportSampleSessionRedisApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.from(SampleSessionRedisApplication::main).with(ContainerConfiguration.class).run(args);\n\t}\n\n\t@ImportTestcontainers\n\tstatic class ContainerConfiguration {\n\n\t\t@ServiceConnection // We don't need a name here because we have the container\n\t\tstatic RedisContainer redisContainer = TestImage.container(RedisContainer.class);\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/dockerTest/java/smoketest/session/redis/TestServiceConnectionSampleSessionRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport com.redis.testcontainers.RedisContainer;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.context.annotation.Bean;\n\npublic class TestServiceConnectionSampleSessionRedisApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.from(SampleSessionRedisApplication::main).with(ContainerConfiguration.class).run(args);\n\t}\n\n\t@TestConfiguration(proxyBeanMethods = false)\n\tstatic class ContainerConfiguration {\n\n\t\t@Bean\n\t\t@ServiceConnection\n\t\tRedisContainer redisContainer() {\n\t\t\treturn TestImage.container(RedisContainer.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/main/java/smoketest/session/redis/SampleSessionRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleSessionRedisApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSessionRedisApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/main/java/smoketest/session/redis/SecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session.redis;\n\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Security configuration.\n *\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\nclass SecurityConfiguration {\n\n\t@Bean\n\tSecurityFilterChain managementSecurityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\trequests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();\n\t\t\trequests.anyRequest().authenticated();\n\t\t});\n\t\thttp.formLogin(withDefaults());\n\t\thttp.httpBasic(withDefaults());\n\t\thttp.csrf(CsrfConfigurer::disable);\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/main/java/smoketest/session/redis/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.session.redis;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\nspring.security.user.name=user\nspring.security.user.password=password\nspring.session.data.redis.repository-type=indexed\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis-webflux/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n\tid \"org.springframework.boot.docker-test\"\n}\n\ndescription = \"Spring Boot Session WebFlux Redis smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-session-data-redis\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\truntimeOnly(project(\":starter:spring-boot-starter-data-redis-reactive\"))\n\n\tdockerTestImplementation(project(\":core:spring-boot-testcontainers\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-session-data-redis-test\"))\n\tdockerTestImplementation(project(\":starter:spring-boot-starter-webclient-test\"))\n\tdockerTestImplementation(project(\":test-support:spring-boot-docker-test-support\"))\n\tdockerTestImplementation(\"com.redis:testcontainers-redis\")\n\tdockerTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileDockerTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis-webflux/src/dockerTest/java/smoketest/session/SampleSessionWebFluxRedisApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport java.time.Duration;\nimport java.util.Base64;\n\nimport com.redis.testcontainers.RedisContainer;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport reactor.util.function.Tuples;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.boot.testsupport.container.TestImage;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseCookie;\nimport org.springframework.web.reactive.function.client.WebClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link SampleSessionWebFluxRedisApplication}.\n *\n * @author Vedran Pavic\n * @author Scott Frederick\n * @author Moritz Halbritter\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@SpringBootTest(properties = \"spring.session.timeout:10\", webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@Testcontainers(disabledWithoutDocker = true)\nclass SampleSessionWebFluxRedisApplicationTests {\n\n\t@Container\n\t@ServiceConnection\n\tprivate static final RedisContainer redis = TestImage.container(RedisContainer.class);\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate WebClient.Builder webClientBuilder;\n\n\t@Test\n\tvoid userDefinedMappingsSecureByDefault() {\n\t\tWebClient client = this.webClientBuilder.baseUrl(\"http://localhost:\" + this.port + \"/\").build();\n\t\tclient.get().header(\"Authorization\", getBasicAuth()).exchangeToMono((response) -> {\n\t\t\tassertThat(response.statusCode()).isEqualTo(HttpStatus.OK);\n\t\t\treturn response.bodyToMono(String.class).map((sessionId) -> {\n\t\t\t\tResponseCookie session = response.cookies().getFirst(\"SESSION\");\n\t\t\t\tassertThat(session).isNotNull();\n\t\t\t\treturn Tuples.of(session.getValue(), sessionId);\n\t\t\t});\n\t\t}).flatMap((tuple) -> {\n\t\t\tString sessionCookie = tuple.getT1();\n\t\t\treturn client.get().cookie(\"SESSION\", sessionCookie).exchangeToMono((response) -> {\n\t\t\t\tassertThat(response.statusCode()).isEqualTo(HttpStatus.OK);\n\t\t\t\treturn response.bodyToMono(String.class)\n\t\t\t\t\t.doOnNext((sessionId) -> assertThat(sessionId).isEqualTo(tuple.getT2()))\n\t\t\t\t\t.thenReturn(sessionCookie);\n\t\t\t});\n\t\t})\n\t\t\t.delayElement(Duration.ofSeconds(10))\n\t\t\t.flatMap((sessionCookie) -> client.get().cookie(\"SESSION\", sessionCookie).exchangeToMono((response) -> {\n\t\t\t\tassertThat(response.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\t\t\treturn response.releaseBody();\n\t\t\t}))\n\t\t\t.block(Duration.ofSeconds(30));\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis-webflux/src/main/java/smoketest/session/HelloRestController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.server.WebSession;\n\n@RestController\npublic class HelloRestController {\n\n\t@GetMapping(\"/\")\n\tString sessionId(WebSession session) {\n\t\treturn session.getId();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis-webflux/src/main/java/smoketest/session/SampleSessionWebFluxRedisApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.web.server.ServerHttpSecurity;\nimport org.springframework.security.web.server.SecurityWebFilterChain;\nimport org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@SpringBootApplication\npublic class SampleSessionWebFluxRedisApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSessionWebFluxRedisApplication.class);\n\t}\n\n\t@Bean\n\tpublic SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {\n\t\thttp.authorizeExchange((exchange) -> exchange.anyExchange().authenticated());\n\t\thttp.httpBasic((basic) -> basic.securityContextRepository(new WebSessionServerSecurityContextRepository()));\n\t\thttp.formLogin(withDefaults());\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis-webflux/src/main/java/smoketest/session/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.session;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-data-redis-webflux/src/main/resources/application.properties",
    "content": "spring.security.user.name=user\nspring.security.user.password=password\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Session JDBC smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-session-jdbc\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(project(\":starter:spring-boot-starter-jdbc\"))\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-session-jdbc-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/src/main/java/smoketest/session/HelloRestController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport jakarta.servlet.http.HttpSession;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class HelloRestController {\n\n\t@GetMapping(\"/\")\n\tString uid(HttpSession session) {\n\t\treturn session.getId();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/src/main/java/smoketest/session/SampleSessionJdbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleSessionJdbcApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSessionJdbcApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/src/main/java/smoketest/session/SecurityConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport org.springframework.boot.health.actuate.endpoint.HealthEndpoint;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Security configuration.\n *\n * @author Madhura Bhave\n */\n@Configuration(proxyBeanMethods = false)\nclass SecurityConfiguration {\n\n\t@Bean\n\tSecurityFilterChain managementSecurityFilterChain(HttpSecurity http) {\n\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\trequests.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll();\n\t\t\trequests.anyRequest().authenticated();\n\t\t});\n\t\thttp.formLogin(withDefaults());\n\t\thttp.httpBasic(withDefaults());\n\t\thttp.csrf(CsrfConfigurer::disable);\n\t\treturn http.build();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/src/main/java/smoketest/session/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.session;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/src/main/resources/application.properties",
    "content": "spring.security.user.name=user\nspring.security.user.password=password\nmanagement.endpoints.web.exposure.include=*\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-session-jdbc/src/test/java/smoketest/session/SampleSessionJdbcApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.session;\n\nimport java.net.URI;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpClientSettings;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleSessionJdbcApplication}.\n *\n * @author Andy Wilkinson\n * @author Vedran Pavic\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"server.servlet.session.timeout:2\", \"debug=true\" })\n@AutoConfigureTestRestTemplate\nclass SampleSessionJdbcApplicationTests {\n\n\tprivate static final HttpClientSettings DONT_FOLLOW_REDIRECTS = HttpClientSettings.defaults()\n\t\t.withRedirects(HttpRedirects.DONT_FOLLOW);\n\n\t@Autowired\n\tprivate RestTemplateBuilder restTemplateBuilder;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@LocalServerPort\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String port;\n\n\tprivate static final URI ROOT_URI = URI.create(\"/\");\n\n\t@Test\n\tvoid sessionExpiry() throws Exception {\n\t\tString cookie = performLogin();\n\t\tString sessionId1 = performRequest(ROOT_URI, cookie).getBody();\n\t\tString sessionId2 = performRequest(ROOT_URI, cookie).getBody();\n\t\tassertThat(sessionId1).isEqualTo(sessionId2);\n\t\tThread.sleep(2100);\n\t\tString loginPage = performRequest(ROOT_URI, cookie).getBody();\n\t\tassertThat(loginPage).containsIgnoringCase(\"login\");\n\t}\n\n\tprivate @Nullable String performLogin() {\n\t\tRestTemplate restTemplate = this.restTemplateBuilder.clientSettings(DONT_FOLLOW_REDIRECTS).build();\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"user\");\n\t\tform.set(\"password\", \"password\");\n\t\tResponseEntity<String> entity = restTemplate.exchange(\"http://localhost:\" + this.port + \"/login\",\n\t\t\t\tHttpMethod.POST, new HttpEntity<>(form, headers), String.class);\n\t\treturn entity.getHeaders().getFirst(\"Set-Cookie\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"unchecked\")\n\tvoid sessionsEndpointShouldReturnUserSession() {\n\t\tperformLogin();\n\t\tResponseEntity<Map<String, Object>> response = getSessions();\n\t\tassertThat(response).isNotNull();\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tMap<String, Object> body = response.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tList<Map<String, Object>> sessions = (List<Map<String, Object>>) body.get(\"sessions\");\n\t\tassertThat(sessions).hasSize(1);\n\t}\n\n\tprivate ResponseEntity<String> performRequest(URI uri, @Nullable String cookie) {\n\t\tHttpHeaders headers = getHeaders(cookie);\n\t\tRequestEntity<Object> request = new RequestEntity<>(headers, HttpMethod.GET, uri);\n\t\treturn this.restTemplate.exchange(request, String.class);\n\t}\n\n\tprivate HttpHeaders getHeaders(@Nullable String cookie) {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\tif (cookie != null) {\n\t\t\theaders.set(\"Cookie\", cookie);\n\t\t}\n\t\telse {\n\t\t\theaders.set(\"Authorization\", getBasicAuth());\n\t\t}\n\t\treturn headers;\n\t}\n\n\tprivate String getBasicAuth() {\n\t\treturn \"Basic \" + Base64.getEncoder().encodeToString(\"user:password\".getBytes());\n\t}\n\n\tprivate ResponseEntity<Map<String, Object>> getSessions() {\n\t\tHttpHeaders headers = getHeaders(null);\n\t\tRequestEntity<Object> request = new RequestEntity<>(headers, HttpMethod.GET,\n\t\t\t\tURI.create(\"/actuator/sessions?username=user\"));\n\t\tParameterizedTypeReference<Map<String, Object>> stringObjectMap = new ParameterizedTypeReference<>() {\n\t\t};\n\t\treturn this.restTemplate.exchange(request, stringObjectMap);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Simple smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\timplementation(project(\":starter:spring-boot-starter-validation\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/java/smoketest/simple/ExitException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.simple;\n\nimport org.springframework.boot.ExitCodeGenerator;\n\npublic class ExitException extends RuntimeException implements ExitCodeGenerator {\n\n\t@Override\n\tpublic int getExitCode() {\n\t\treturn 10;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/java/smoketest/simple/SampleConfigurationProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.simple;\n\nimport jakarta.validation.constraints.NotNull;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.validation.annotation.Validated;\n\n@Validated\n@ConfigurationProperties(\"sample\")\npublic final class SampleConfigurationProperties {\n\n\t@NotNull\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/java/smoketest/simple/SampleSimpleApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.simple;\n\nimport smoketest.simple.service.HelloWorldService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\n\n@SpringBootApplication\n@EnableConfigurationProperties(SampleConfigurationProperties.class)\npublic class SampleSimpleApplication implements CommandLineRunner {\n\n\t// Simple example shows how a command line spring application can execute an\n\t// injected bean service. Also demonstrates how you can use @Value to inject\n\t// command line args ('--test.name=whatever') or application properties\n\n\t@Autowired\n\tprivate HelloWorldService helloWorldService;\n\n\t@Override\n\tpublic void run(String... args) {\n\t\tSystem.out.println(this.helloWorldService.getHelloMessage());\n\t\tif (args.length > 0 && args[0].equals(\"exitcode\")) {\n\t\t\tthrow new ExitException();\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleSimpleApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/java/smoketest/simple/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.simple;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/java/smoketest/simple/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.simple.service;\n\nimport java.time.Duration;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\t@Value(\"${test.duration:10s}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate Duration duration;\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.name + \" for \" + this.duration.getSeconds() + \" seconds\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/java/smoketest/simple/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.simple.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/resources/application.properties",
    "content": "test.name=Phil\nsample.name=Andy\n\nspring.profiles.validate=false\nspring.profiles.active=a+very(silly)!name\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/main/resources/banner.txt",
    "content": "${Ansi.GREEN} :: Sample application build with Spring Boot${spring-boot.formatted-version} ::${Ansi.DEFAULT}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/test/java/smoketest/simple/SampleSimpleApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.simple;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleSimpleApplication}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleSimpleApplicationTests {\n\n\tprivate String profiles;\n\n\t@BeforeEach\n\tvoid init() {\n\t\tthis.profiles = System.getProperty(\"spring.profiles.active\");\n\t}\n\n\t@AfterEach\n\tvoid after() {\n\t\tif (this.profiles != null) {\n\t\t\tSystem.setProperty(\"spring.profiles.active\", this.profiles);\n\t\t}\n\t\telse {\n\t\t\tSystem.clearProperty(\"spring.profiles.active\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tSampleSimpleApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"Hello Phil\");\n\t}\n\n\t@Test\n\tvoid testCommandLineOverrides(CapturedOutput output) {\n\t\tSampleSimpleApplication.main(new String[] { \"--test.name=Gordon\", \"--test.duration=1m\" });\n\t\tassertThat(output).contains(\"Hello Gordon for 60 seconds\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-simple/src/test/java/smoketest/simple/SpringTestSampleSimpleApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.simple;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleSimpleApplication}.\n *\n * @author Dave Syer\n */\n@SpringBootTest\nclass SpringTestSampleSimpleApplicationTests {\n\n\t@Autowired\n\tApplicationContext ctx;\n\n\t@Test\n\tvoid testContextLoads() {\n\t\tassertThat(this.ctx).isNotNull();\n\t\tassertThat(this.ctx.containsBean(\"helloWorldService\")).isTrue();\n\t\tassertThat(this.ctx.containsBean(\"sampleSimpleApplication\")).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot structured logging smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/java/smoketest/structuredlogging/CustomStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging;\n\nimport ch.qos.logback.classic.pattern.ThrowableProxyConverter;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport ch.qos.logback.classic.spi.IThrowableProxy;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.core.env.Environment;\n\npublic class CustomStructuredLogFormatter implements StructuredLogFormatter<ILoggingEvent> {\n\n\tprivate final @Nullable Long pid;\n\n\tprivate final ThrowableProxyConverter throwableProxyConverter;\n\n\tpublic CustomStructuredLogFormatter(Environment environment, ThrowableProxyConverter throwableProxyConverter) {\n\t\tthis.pid = environment.getProperty(\"spring.application.pid\", Long.class);\n\t\tthis.throwableProxyConverter = throwableProxyConverter;\n\t}\n\n\t@Override\n\tpublic String format(ILoggingEvent event) {\n\t\tStringBuilder result = new StringBuilder();\n\t\tresult.append(\"epoch=\").append(event.getInstant().toEpochMilli());\n\t\tif (this.pid != null) {\n\t\t\tresult.append(\" pid=\").append(this.pid);\n\t\t}\n\t\tresult.append(\" msg=\\\"\").append(event.getFormattedMessage()).append('\"');\n\t\tIThrowableProxy throwable = event.getThrowableProxy();\n\t\tif (throwable != null) {\n\t\t\tresult.append(\" error=\\\"\").append(this.throwableProxyConverter.convert(event)).append('\"');\n\t\t}\n\t\tresult.append('\\n');\n\t\treturn result.toString();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/java/smoketest/structuredlogging/DuplicateJsonMembersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging;\n\nimport java.util.Objects;\n\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\n\npublic class DuplicateJsonMembersCustomizer implements StructuredLoggingJsonMembersCustomizer<Object> {\n\n\t@Override\n\tpublic void customize(Members<Object> members) {\n\t\tmembers.add(\"test\").as(Objects::toString);\n\t\tmembers.add(\"test\").as(Objects::toString);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/java/smoketest/structuredlogging/SampleJsonMembersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging;\n\nimport java.util.function.UnaryOperator;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.json.JsonWriter.ValueProcessor;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\n\npublic class SampleJsonMembersCustomizer implements StructuredLoggingJsonMembersCustomizer<Object> {\n\n\t@Override\n\tpublic void customize(Members<Object> members) {\n\t\tUnaryOperator<@Nullable String> formatted = \"!!%s!!\"::formatted;\n\t\tmembers.applyingValueProcessor(\n\t\t\t\tValueProcessor.of(String.class, formatted).whenHasUnescapedPath(\"process.thread.name\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/java/smoketest/structuredlogging/SampleStructuredLoggingApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleStructuredLoggingApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleStructuredLoggingApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/java/smoketest/structuredlogging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.structuredlogging;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/resources/application.properties",
    "content": "bar=hello\nlogging.structured.format.console=ecs\nlogging.structured.json.exclude=@timestamp\nlogging.structured.json.rename[process.pid]=process.procid\nlogging.structured.json.add.foo=${bar}\nlogging.structured.json.customizer=smoketest.structuredlogging.SampleJsonMembersCustomizer\n#---\nspring.config.activate.on-profile=custom\nlogging.structured.format.console=smoketest.structuredlogging.CustomStructuredLogFormatter\n#---\nspring.config.activate.on-profile=on-error\nlogging.structured.json.customizer=smoketest.structuredlogging.DuplicateJsonMembersCustomizer\n#---\nlogging.config=classpath:custom-logback.xml\nspring.config.activate.on-profile=on-error-custom-logback-file\nlogging.structured.json.customizer=smoketest.structuredlogging.DuplicateJsonMembersCustomizer\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/main/resources/custom-logback.xml",
    "content": "<configuration>\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder class=\"org.springframework.boot.logging.logback.StructuredLogEncoder\">\n\t\t\t<format>ecs</format>\n\t\t\t<charset>UTF-8</charset>\n\t\t</encoder>\n\t</appender>\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"STDOUT\"/>\n\t</root>\n</configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging/src/test/java/smoketest/structuredlogging/SampleStructuredLoggingApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleStructuredLoggingApplication}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleStructuredLoggingApplicationTests {\n\n\t@AfterEach\n\tvoid reset(CapturedOutput output) {\n\t\tLoggingSystem.get(getClass().getClassLoader()).cleanUp();\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t\tassertThat(output).doesNotContain(\"-INFO in ch.qos.logback.classic.LoggerContext\");\n\t}\n\n\t@Test\n\tvoid shouldNotLogBanner(CapturedOutput output) {\n\t\tSampleStructuredLoggingApplication.main(new String[0]);\n\t\tassertThat(output).doesNotContain(\" :: Spring Boot :: \");\n\t}\n\n\t@Test\n\tvoid json(CapturedOutput output) {\n\t\tSampleStructuredLoggingApplication.main(new String[0]);\n\t\tassertThat(output).doesNotContain(\"{\\\"@timestamp\\\"\")\n\t\t\t.contains(\"\\\"thread\\\":{\\\"name\\\":\\\"!!\")\n\t\t\t.contains(\"\\\"process.procid\\\"\")\n\t\t\t.contains(\"\\\"message\\\":\\\"Starting SampleStructuredLoggingApplication\")\n\t\t\t.contains(\"\\\"foo\\\":\\\"hello\");\n\t}\n\n\t@Test\n\tvoid custom(CapturedOutput output) {\n\t\tSampleStructuredLoggingApplication.main(new String[] { \"--spring.profiles.active=custom\" });\n\t\tassertThat(output).contains(\"epoch=\").contains(\"msg=\\\"Starting SampleStructuredLoggingApplication\");\n\t}\n\n\t@Test\n\tvoid shouldCaptureCustomizerError(CapturedOutput output) {\n\t\tSampleStructuredLoggingApplication.main(new String[] { \"--spring.profiles.active=on-error\" });\n\t\tassertThat(output).contains(\"The name 'test' has already been written\");\n\t}\n\n\t@Test\n\tvoid shouldCaptureCustomizerErrorWhenUsingCustomLogbackFile(CapturedOutput output) {\n\t\tSampleStructuredLoggingApplication\n\t\t\t.main(new String[] { \"--spring.profiles.active=on-error-custom-logback-file\" });\n\t\tassertThat(output).contains(\"The name 'test' has already been written\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot structured logging Log4j2 smoke test\"\n\nconfigurations.all {\n\texclude module: \"spring-boot-starter-logging\"\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\timplementation(project(\":starter:spring-boot-starter-log4j2\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/CustomStructuredLogFormatter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging.log4j2;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\nimport org.apache.logging.log4j.core.LogEvent;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.logging.structured.StructuredLogFormatter;\nimport org.springframework.core.env.Environment;\n\npublic class CustomStructuredLogFormatter implements StructuredLogFormatter<LogEvent> {\n\n\tprivate final @Nullable Long pid;\n\n\tpublic CustomStructuredLogFormatter(Environment environment) {\n\t\tthis.pid = environment.getProperty(\"spring.application.pid\", Long.class);\n\t}\n\n\t@Override\n\tpublic String format(LogEvent event) {\n\t\tStringBuilder result = new StringBuilder();\n\t\tresult.append(\"epoch=\").append(event.getInstant().getEpochMillisecond());\n\t\tif (this.pid != null) {\n\t\t\tresult.append(\" pid=\").append(this.pid);\n\t\t}\n\t\tresult.append(\" msg=\\\"\").append(event.getMessage().getFormattedMessage()).append('\"');\n\t\tThrowable throwable = event.getThrown();\n\t\tif (throwable != null) {\n\t\t\tStringWriter stackTrace = new StringWriter();\n\t\t\tthrowable.printStackTrace(new PrintWriter(stackTrace));\n\t\t\tresult.append(\" error=\\\"\").append(stackTrace).append('\"');\n\t\t}\n\t\tresult.append('\\n');\n\t\treturn result.toString();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/DuplicateJsonMembersCustomizer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging.log4j2;\n\nimport java.util.Objects;\n\nimport org.springframework.boot.json.JsonWriter.Members;\nimport org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;\n\npublic class DuplicateJsonMembersCustomizer implements StructuredLoggingJsonMembersCustomizer<Object> {\n\n\t@Override\n\tpublic void customize(Members<Object> members) {\n\t\tmembers.add(\"test\").as(Objects::toString);\n\t\tmembers.add(\"test\").as(Objects::toString);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/SampleLog4j2StructuredLoggingApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging.log4j2;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleLog4j2StructuredLoggingApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleLog4j2StructuredLoggingApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/java/smoketest/structuredlogging/log4j2/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.structuredlogging.log4j2;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/main/resources/application.properties",
    "content": "logging.structured.format.console=ecs\n#---\nspring.config.activate.on-profile=custom\nlogging.structured.format.console=smoketest.structuredlogging.log4j2.CustomStructuredLogFormatter\n#---\nspring.config.activate.on-profile=on-error\nlogging.structured.json.customizer=smoketest.structuredlogging.log4j2.DuplicateJsonMembersCustomizer\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-structured-logging-log4j2/src/test/java/smoketest/structuredlogging/log4j2/SampleLog4j2StructuredLoggingApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.structuredlogging.log4j2;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.logging.LoggingSystem;\nimport org.springframework.boot.logging.LoggingSystemProperty;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link SampleLog4j2StructuredLoggingApplication}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleLog4j2StructuredLoggingApplicationTests {\n\n\t@AfterEach\n\tvoid reset() {\n\t\tLoggingSystem.get(getClass().getClassLoader()).cleanUp();\n\t\tfor (LoggingSystemProperty property : LoggingSystemProperty.values()) {\n\t\t\tSystem.getProperties().remove(property.getEnvironmentVariableName());\n\t\t}\n\t}\n\n\t@Test\n\tvoid shouldNotLogBanner(CapturedOutput output) {\n\t\tSampleLog4j2StructuredLoggingApplication.main(new String[0]);\n\t\tassertThat(output).doesNotContain(\" :: Spring Boot :: \");\n\t}\n\n\t@Test\n\tvoid json(CapturedOutput output) {\n\t\tSampleLog4j2StructuredLoggingApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"{\\\"@timestamp\\\"\")\n\t\t\t.contains(\"\\\"message\\\":\\\"Starting SampleLog4j2StructuredLoggingApplication\");\n\t}\n\n\t@Test\n\tvoid custom(CapturedOutput output) {\n\t\tSampleLog4j2StructuredLoggingApplication.main(new String[] { \"--spring.profiles.active=custom\" });\n\t\tassertThat(output).contains(\"epoch=\").contains(\"msg=\\\"Starting SampleLog4j2StructuredLoggingApplication\");\n\t}\n\n\t@Test\n\tvoid shouldCaptureCustomizerError(CapturedOutput output) {\n\t\tSampleLog4j2StructuredLoggingApplication.main(new String[] { \"--spring.profiles.active=on-error\" });\n\t\tassertThat(output).contains(\"The name 'test' has already been written\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Test smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-data-jpa\"))\n\timplementation(project(\":starter:spring-boot-starter-restclient\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-data-jpa-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-restclient-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(\"org.htmlunit:htmlunit\")\n\ttestImplementation(\"org.mockito:mockito-junit-jupiter\")\n\ttestImplementation(\"org.seleniumhq.selenium:selenium-api\")\n\ttestImplementation(\"org.seleniumhq.selenium:htmlunit3-driver\") {\n\t\texclude(group: \"com.sun.activation\", module: \"jakarta.activation\")\n\t}\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/SampleTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.ConfigurationPropertiesScan;\n\n/**\n * Sample application to demonstrate testing.\n *\n * @author Phillip Webb\n */\n@SpringBootApplication\n@ConfigurationPropertiesScan\npublic class SampleTestApplication {\n\n\t// NOTE: this application will intentionally not start without MySQL, the test will\n\t// still run.\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTestApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/WelcomeCommandLineRunner.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\n/**\n * Simple component that just prints a message. Used to show how different types of\n * integration tests work.\n *\n * @author Phillip Webb\n */\n@Component\npublic class WelcomeCommandLineRunner implements CommandLineRunner {\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tSystem.out.println(\"***** WELCOME TO THE DEMO *****\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/User.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport jakarta.persistence.Column;\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.Table;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A user of the system.\n *\n * @author Phillip Webb\n */\n@Entity\n@Table(name = \"DRIVER\")\npublic class User {\n\n\t@Id\n\t@GeneratedValue\n\tprivate @Nullable Long id;\n\n\t@Column(unique = true)\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String username;\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate VehicleIdentificationNumber vin;\n\n\tprotected User() {\n\t}\n\n\tpublic User(String username, VehicleIdentificationNumber vin) {\n\t\tAssert.hasLength(username, \"'username' must not be empty\");\n\t\tAssert.notNull(vin, \"'vin' must not be null\");\n\t\tthis.username = username;\n\t\tthis.vin = vin;\n\t}\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn this.username;\n\t}\n\n\tpublic VehicleIdentificationNumber getVin() {\n\t\treturn this.vin;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/UserRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.data.repository.Repository;\n\n/**\n * Domain repository for {@link User}.\n *\n * @author Phillip Webb\n */\npublic interface UserRepository extends Repository<User, Long> {\n\n\t@Nullable User findByUsername(String username);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/VehicleIdentificationNumber.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * A Vehicle Identification Number.\n *\n * @author Phillip Webb\n */\npublic final class VehicleIdentificationNumber {\n\n\tprivate final String vin;\n\n\tpublic VehicleIdentificationNumber(String vin) {\n\t\tAssert.notNull(vin, \"'vin' must not be null\");\n\t\tAssert.isTrue(vin.length() == 17, \"'vin' must be exactly 17 characters\");\n\t\tthis.vin = vin;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.vin.equals(((VehicleIdentificationNumber) obj).vin);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.vin.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.vin;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/VehicleIdentificationNumberAttributeConverter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport jakarta.persistence.AttributeConverter;\nimport jakarta.persistence.Converter;\n\n/**\n * JPA {@link AttributeConverter} for {@link VehicleIdentificationNumber}.\n *\n * @author Phillip Webb\n */\n@Converter(autoApply = true)\npublic class VehicleIdentificationNumberAttributeConverter\n\t\timplements AttributeConverter<VehicleIdentificationNumber, String> {\n\n\t@Override\n\tpublic String convertToDatabaseColumn(VehicleIdentificationNumber attribute) {\n\t\treturn attribute.toString();\n\t}\n\n\t@Override\n\tpublic VehicleIdentificationNumber convertToEntityAttribute(String dbData) {\n\t\treturn new VehicleIdentificationNumber(dbData);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/domain/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.test.domain;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.test;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/service/RemoteVehicleDetailsService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport smoketest.test.domain.VehicleIdentificationNumber;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.Assert;\nimport org.springframework.web.client.HttpStatusCodeException;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * {@link VehicleDetailsService} backed by a remote REST service.\n *\n * @author Phillip Webb\n */\n@Service\npublic class RemoteVehicleDetailsService implements VehicleDetailsService {\n\n\tprivate static final Log logger = LogFactory.getLog(RemoteVehicleDetailsService.class);\n\n\tprivate final RestTemplate restTemplate;\n\n\tpublic RemoteVehicleDetailsService(ServiceProperties properties, RestTemplateBuilder restTemplateBuilder) {\n\t\tthis.restTemplate = restTemplateBuilder.baseUri(properties.getVehicleServiceRootUrl()).build();\n\t}\n\n\t@Override\n\tpublic VehicleDetails getVehicleDetails(VehicleIdentificationNumber vin)\n\t\t\tthrows VehicleIdentificationNumberNotFoundException {\n\t\tAssert.notNull(vin, \"'vin' must not be null\");\n\t\tlogger.debug(\"Retrieving vehicle data for: \" + vin);\n\t\ttry {\n\t\t\tVehicleDetails response = this.restTemplate.getForObject(\"/vehicle/{vin}/details\", VehicleDetails.class,\n\t\t\t\t\tvin);\n\t\t\tAssert.state(response != null, \"'response' must not be null\");\n\t\t\treturn response;\n\t\t}\n\t\tcatch (HttpStatusCodeException ex) {\n\t\t\tif (HttpStatus.NOT_FOUND.equals(ex.getStatusCode())) {\n\t\t\t\tthrow new VehicleIdentificationNumberNotFoundException(vin, ex);\n\t\t\t}\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/service/ServiceProperties.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties for the service.\n *\n * @author Phillip Webb\n */\n@ConfigurationProperties\npublic class ServiceProperties {\n\n\tprivate String vehicleServiceRootUrl = \"http://localhost:8080/vs\";\n\n\tpublic String getVehicleServiceRootUrl() {\n\t\treturn this.vehicleServiceRootUrl;\n\t}\n\n\tpublic void setVehicleServiceRootUrl(String vehicleServiceRootUrl) {\n\t\tthis.vehicleServiceRootUrl = vehicleServiceRootUrl;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/service/VehicleDetails.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\n\n/**\n * Details of a single vehicle.\n *\n * @author Phillip Webb\n */\npublic class VehicleDetails {\n\n\tprivate final String make;\n\n\tprivate final String model;\n\n\t@JsonCreator\n\tpublic VehicleDetails(@JsonProperty(\"make\") String make, @JsonProperty(\"model\") String model) {\n\t\tAssert.notNull(make, \"'make' must not be null\");\n\t\tAssert.notNull(model, \"'model' must not be null\");\n\t\tthis.make = make;\n\t\tthis.model = model;\n\t}\n\n\tpublic String getMake() {\n\t\treturn this.make;\n\t}\n\n\tpublic String getModel() {\n\t\treturn this.model;\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj == null || obj.getClass() != getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tVehicleDetails other = (VehicleDetails) obj;\n\t\treturn this.make.equals(other.make) && this.model.equals(other.model);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn this.make.hashCode() * 31 + this.model.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/service/VehicleDetailsService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport smoketest.test.domain.VehicleIdentificationNumber;\n\n/**\n * A service to obtain {@link VehicleDetails} given a {@link VehicleIdentificationNumber}.\n *\n * @author Phillip Webb\n */\npublic interface VehicleDetailsService {\n\n\t/**\n\t * Get vehicle details for a given {@link VehicleIdentificationNumber}.\n\t * @param vin the vehicle identification number\n\t * @return vehicle details\n\t * @throws VehicleIdentificationNumberNotFoundException if the VIN is not known\n\t */\n\tVehicleDetails getVehicleDetails(VehicleIdentificationNumber vin)\n\t\t\tthrows VehicleIdentificationNumberNotFoundException;\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/service/VehicleIdentificationNumberNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport org.jspecify.annotations.Nullable;\nimport smoketest.test.domain.VehicleIdentificationNumber;\n\n/**\n * Exception thrown when a {@link VehicleIdentificationNumber} is not found.\n *\n * @author Phillip Webb\n */\npublic class VehicleIdentificationNumberNotFoundException extends RuntimeException {\n\n\tprivate final VehicleIdentificationNumber vehicleIdentificationNumber;\n\n\tpublic VehicleIdentificationNumberNotFoundException(VehicleIdentificationNumber vin) {\n\t\tthis(vin, null);\n\t}\n\n\tpublic VehicleIdentificationNumberNotFoundException(VehicleIdentificationNumber vin, @Nullable Throwable cause) {\n\t\tsuper(\"Unable to find VehicleIdentificationNumber \" + vin, cause);\n\t\tthis.vehicleIdentificationNumber = vin;\n\t}\n\n\tpublic VehicleIdentificationNumber getVehicleIdentificationNumber() {\n\t\treturn this.vehicleIdentificationNumber;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.test.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/web/UserNameNotFoundException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n@ResponseStatus(HttpStatus.NOT_FOUND)\npublic class UserNameNotFoundException extends RuntimeException {\n\n\tprivate final String username;\n\n\tpublic UserNameNotFoundException(String username) {\n\t\tthis.username = username;\n\t}\n\n\tpublic String getUsername() {\n\t\treturn this.username;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/web/UserVehicleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport smoketest.test.domain.User;\nimport smoketest.test.service.VehicleDetails;\nimport smoketest.test.service.VehicleIdentificationNumberNotFoundException;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Controller to return vehicle information for a given {@link User}.\n *\n * @author Phillip Webb\n */\n@RestController\npublic class UserVehicleController {\n\n\tprivate final UserVehicleService userVehicleService;\n\n\tpublic UserVehicleController(UserVehicleService userVehicleService) {\n\t\tthis.userVehicleService = userVehicleService;\n\t}\n\n\t@GetMapping(path = \"/{username}/vehicle\", produces = MediaType.TEXT_PLAIN_VALUE)\n\tpublic String getVehicleDetailsText(@PathVariable String username) {\n\t\tVehicleDetails details = this.userVehicleService.getVehicleDetails(username);\n\t\treturn details.getMake() + \" \" + details.getModel();\n\t}\n\n\t@GetMapping(path = \"/{username}/vehicle\", produces = MediaType.APPLICATION_JSON_VALUE)\n\tpublic VehicleDetails VehicleDetailsJson(@PathVariable String username) {\n\t\treturn this.userVehicleService.getVehicleDetails(username);\n\t}\n\n\t@GetMapping(path = \"/{username}/vehicle.html\", produces = MediaType.TEXT_HTML_VALUE)\n\tpublic String VehicleDetailsHtml(@PathVariable String username) {\n\t\tVehicleDetails details = this.userVehicleService.getVehicleDetails(username);\n\t\tString makeAndModel = details.getMake() + \" \" + details.getModel();\n\t\treturn \"<html><body><h1>\" + makeAndModel + \"</h1></body></html>\";\n\t}\n\n\t@ExceptionHandler\n\t@ResponseStatus(HttpStatus.NOT_FOUND)\n\tprivate void handleVinNotFound(VehicleIdentificationNumberNotFoundException ex) {\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/web/UserVehicleService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport smoketest.test.domain.User;\nimport smoketest.test.domain.UserRepository;\nimport smoketest.test.service.VehicleDetails;\nimport smoketest.test.service.VehicleDetailsService;\nimport smoketest.test.service.VehicleIdentificationNumberNotFoundException;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.util.Assert;\n\n/**\n * Controller service used to provide vehicle information for a given user.\n *\n * @author Phillip Webb\n */\n@Component\npublic class UserVehicleService {\n\n\tprivate final UserRepository userRepository;\n\n\tprivate final VehicleDetailsService vehicleDetailsService;\n\n\tpublic UserVehicleService(UserRepository userRepository, VehicleDetailsService vehicleDetailsService) {\n\t\tthis.userRepository = userRepository;\n\t\tthis.vehicleDetailsService = vehicleDetailsService;\n\t}\n\n\tpublic VehicleDetails getVehicleDetails(String username)\n\t\t\tthrows UserNameNotFoundException, VehicleIdentificationNumberNotFoundException {\n\t\tAssert.notNull(username, \"'username' must not be null\");\n\t\tUser user = this.userRepository.findByUsername(username);\n\t\tif (user == null) {\n\t\t\tthrow new UserNameNotFoundException(username);\n\t\t}\n\t\treturn this.vehicleDetailsService.getVehicleDetails(user.getVin());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/java/smoketest/test/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.test.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/main/resources/application.properties",
    "content": "spring.datasource.url=jdbc:mysql://localhost/doesnotexist\nspring.jpa.open-in-view=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/SampleTestApplicationWebIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport smoketest.test.domain.VehicleIdentificationNumber;\nimport smoketest.test.service.VehicleDetails;\nimport smoketest.test.service.VehicleDetailsService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * {@code @SpringBootTest} with a random port for {@link SampleTestApplication}.\n *\n * @author Phillip Webb\n * @author Jorge Cordoba\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestDatabase\n@AutoConfigureTestRestTemplate\nclass SampleTestApplicationWebIntegrationTests {\n\n\tprivate static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber(\"01234567890123456\");\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@MockitoBean\n\tprivate VehicleDetailsService vehicleDetailsService;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tgiven(this.vehicleDetailsService.getVehicleDetails(VIN)).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t}\n\n\t@Test\n\tvoid test() {\n\t\tassertThat(this.restTemplate.getForEntity(\"/{username}/vehicle\", String.class, \"sframework\").getStatusCode())\n\t\t\t.isEqualTo(HttpStatus.OK);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/domain/UserEntityTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;\nimport org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Data JPA tests for {@link User}.\n *\n * @author Phillip Webb\n */\n@DataJpaTest\nclass UserEntityTests {\n\n\tprivate static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber(\"00000000000000000\");\n\n\t@Autowired\n\tprivate TestEntityManager entityManager;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenUsernameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new User(null, VIN))\n\t\t\t.withMessage(\"'username' must not be empty\");\n\t}\n\n\t@Test\n\tvoid createWhenUsernameIsEmptyShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new User(\"\", VIN))\n\t\t\t.withMessage(\"'username' must not be empty\");\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenVinIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new User(\"sboot\", null))\n\t\t\t.withMessage(\"'vin' must not be null\");\n\t}\n\n\t@Test\n\tvoid saveShouldPersistData() {\n\t\tUser user = this.entityManager.persistFlushFind(new User(\"sboot\", VIN));\n\t\tassertThat(user.getUsername()).isEqualTo(\"sboot\");\n\t\tassertThat(user.getVin()).isEqualTo(VIN);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/domain/UserRepositoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;\nimport org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link UserRepository}.\n *\n * @author Phillip Webb\n */\n@DataJpaTest\nclass UserRepositoryTests {\n\n\tprivate static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber(\"00000000000000000\");\n\n\t@Autowired\n\tprivate TestEntityManager entityManager;\n\n\t@Autowired\n\tprivate UserRepository repository;\n\n\t@Test\n\tvoid findByUsernameShouldReturnUser() {\n\t\tthis.entityManager.persist(new User(\"sboot\", VIN));\n\t\tUser user = this.repository.findByUsername(\"sboot\");\n\t\tassertThat(user).isNotNull();\n\t\tassertThat(user.getUsername()).isEqualTo(\"sboot\");\n\t\tassertThat(user.getVin()).isEqualTo(VIN);\n\t}\n\n\t@Test\n\tvoid findByUsernameWhenNoUserShouldReturnNull() {\n\t\tthis.entityManager.persist(new User(\"sboot\", VIN));\n\t\tUser user = this.repository.findByUsername(\"mmouse\");\n\t\tassertThat(user).isNull();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/domain/VehicleIdentificationNumberTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.domain;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\n\n/**\n * Tests for {@link VehicleIdentificationNumber}.\n *\n * @author Phillip Webb\n * @see <a href=\"https://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html\">\n * Naming standards for unit tests</a>\n * @see <a href=\"https://joel-costigliola.github.io/assertj/\">AssertJ</a>\n */\nclass VehicleIdentificationNumberTests {\n\n\tprivate static final String SAMPLE_VIN = \"41549485710496749\";\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid createWhenVinIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new VehicleIdentificationNumber(null))\n\t\t\t.withMessage(\"'vin' must not be null\");\n\t}\n\n\t@Test\n\tvoid createWhenVinIsMoreThan17CharsShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new VehicleIdentificationNumber(\"012345678901234567\"))\n\t\t\t.withMessage(\"'vin' must be exactly 17 characters\");\n\t}\n\n\t@Test\n\tvoid createWhenVinIsLessThan17CharsShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> new VehicleIdentificationNumber(\"0123456789012345\"))\n\t\t\t.withMessage(\"'vin' must be exactly 17 characters\");\n\t}\n\n\t@Test\n\tvoid toStringShouldReturnVin() {\n\t\tVehicleIdentificationNumber vin = new VehicleIdentificationNumber(SAMPLE_VIN);\n\t\tassertThat(vin).hasToString(SAMPLE_VIN);\n\t}\n\n\t@Test\n\tvoid equalsAndHashCodeShouldBeBasedOnVin() {\n\t\tVehicleIdentificationNumber vin1 = new VehicleIdentificationNumber(SAMPLE_VIN);\n\t\tVehicleIdentificationNumber vin2 = new VehicleIdentificationNumber(SAMPLE_VIN);\n\t\tVehicleIdentificationNumber vin3 = new VehicleIdentificationNumber(\"00000000000000000\");\n\t\tassertThat(vin1).hasSameHashCodeAs(vin2);\n\t\tassertThat(vin1).isEqualTo(vin1).isEqualTo(vin2).isNotEqualTo(vin3);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/service/RemoteVehicleDetailsServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.test.domain.VehicleIdentificationNumber;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.restclient.test.autoconfigure.RestClientTest;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.client.MockRestServiceServer;\nimport org.springframework.web.client.HttpServerErrorException;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withServerError;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;\nimport static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;\n\n/**\n * Tests for {@link RemoteVehicleDetailsService}.\n *\n * @author Phillip Webb\n */\n@RestClientTest({ RemoteVehicleDetailsService.class, ServiceProperties.class })\nclass RemoteVehicleDetailsServiceTests {\n\n\tprivate static final String VIN = \"00000000000000000\";\n\n\t@Autowired\n\tprivate RemoteVehicleDetailsService service;\n\n\t@Autowired\n\tprivate MockRestServiceServer server;\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getVehicleDetailsWhenVinIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.service.getVehicleDetails(null))\n\t\t\t.withMessage(\"'vin' must not be null\");\n\t}\n\n\t@Test\n\tvoid getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() {\n\t\tthis.server.expect(requestTo(\"/vehicle/\" + VIN + \"/details\"))\n\t\t\t.andRespond(withSuccess(getClassPathResource(\"vehicledetails.json\"), MediaType.APPLICATION_JSON));\n\t\tVehicleDetails details = this.service.getVehicleDetails(new VehicleIdentificationNumber(VIN));\n\t\tassertThat(details.getMake()).isEqualTo(\"Honda\");\n\t\tassertThat(details.getModel()).isEqualTo(\"Civic\");\n\t}\n\n\t@Test\n\tvoid getVehicleDetailsWhenResultIsNotFoundShouldThrowException() {\n\t\tthis.server.expect(requestTo(\"/vehicle/\" + VIN + \"/details\")).andRespond(withStatus(HttpStatus.NOT_FOUND));\n\t\tassertThatExceptionOfType(VehicleIdentificationNumberNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.service.getVehicleDetails(new VehicleIdentificationNumber(VIN)));\n\t}\n\n\t@Test\n\tvoid getVehicleDetailsWhenResultIServerErrorShouldThrowException() {\n\t\tthis.server.expect(requestTo(\"/vehicle/\" + VIN + \"/details\")).andRespond(withServerError());\n\t\tassertThatExceptionOfType(HttpServerErrorException.class)\n\t\t\t.isThrownBy(() -> this.service.getVehicleDetails(new VehicleIdentificationNumber(VIN)));\n\t}\n\n\tprivate ClassPathResource getClassPathResource(String path) {\n\t\treturn new ClassPathResource(path, getClass());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/service/VehicleDetailsJsonTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.service;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.json.JsonTest;\nimport org.springframework.boot.test.json.JacksonTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * JSON tests for {@link VehicleDetails}.\n *\n * @author Phillip Webb\n */\n@JsonTest\nclass VehicleDetailsJsonTests {\n\n\t@Autowired\n\tprivate JacksonTester<VehicleDetails> json;\n\n\t@Test\n\tvoid serializeJson() throws Exception {\n\t\tVehicleDetails details = new VehicleDetails(\"Honda\", \"Civic\");\n\t\tassertThat(this.json.write(details)).isEqualTo(\"vehicledetails.json\");\n\t\tassertThat(this.json.write(details)).isEqualToJson(\"vehicledetails.json\");\n\t\tassertThat(this.json.write(details)).hasJsonPathStringValue(\"@.make\");\n\t\tassertThat(this.json.write(details)).extractingJsonPathStringValue(\"@.make\").isEqualTo(\"Honda\");\n\t}\n\n\t@Test\n\tvoid deserializeJson() throws Exception {\n\t\tString content = \"{\\\"make\\\":\\\"Ford\\\",\\\"model\\\":\\\"Focus\\\"}\";\n\t\tassertThat(this.json.parse(content)).isEqualTo(new VehicleDetails(\"Ford\", \"Focus\"));\n\t\tassertThat(this.json.parseObject(content).getMake()).isEqualTo(\"Ford\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/web/UserVehicleControllerApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.test.WelcomeCommandLineRunner;\nimport smoketest.test.service.VehicleDetails;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * {@code @SpringBootTest} based tests for {@link UserVehicleController}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest\n@AutoConfigureMockMvc\n@AutoConfigureTestDatabase\nclass UserVehicleControllerApplicationTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid getVehicleWhenRequestingTextShouldReturnMakeAndModel() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle\").accept(MediaType.TEXT_PLAIN)).hasStatusOk()\n\t\t\t.hasBodyTextEqualTo(\"Honda Civic\");\n\t}\n\n\t@Test\n\tvoid welcomeCommandLineRunnerShouldBeAvailable() {\n\t\t// Since we're a @SpringBootTest all beans should be available.\n\t\tassertThat(this.applicationContext.getBean(WelcomeCommandLineRunner.class)).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/web/UserVehicleControllerHtmlUnitTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport org.htmlunit.WebClient;\nimport org.htmlunit.html.HtmlPage;\nimport org.junit.jupiter.api.Test;\nimport smoketest.test.service.VehicleDetails;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * HtmlUnit based tests for {@link UserVehicleController}.\n *\n * @author Phillip Webb\n */\n@WebMvcTest(UserVehicleController.class)\nclass UserVehicleControllerHtmlUnitTests {\n\n\t@Autowired\n\tprivate WebClient webClient;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid getVehicleWhenRequestingTextShouldReturnMakeAndModel() throws Exception {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tHtmlPage page = this.webClient.getPage(\"/sboot/vehicle.html\");\n\t\tassertThat(page.getBody().getTextContent()).isEqualTo(\"Honda Civic\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/web/UserVehicleControllerSeleniumTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport org.junit.jupiter.api.Test;\nimport org.openqa.selenium.By;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.WebElement;\nimport smoketest.test.service.VehicleDetails;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Selenium based tests for {@link UserVehicleController}.\n *\n * @author Phillip Webb\n */\n@WebMvcTest(UserVehicleController.class)\nclass UserVehicleControllerSeleniumTests {\n\n\t@Autowired\n\tprivate WebDriver webDriver;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid getVehicleWhenRequestingTextShouldReturnMakeAndModel() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tthis.webDriver.get(\"/sboot/vehicle.html\");\n\t\tWebElement element = this.webDriver.findElement(By.tagName(\"h1\"));\n\t\tassertThat(element.getText()).isEqualTo(\"Honda Civic\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/web/UserVehicleControllerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.test.WelcomeCommandLineRunner;\nimport smoketest.test.domain.VehicleIdentificationNumber;\nimport smoketest.test.service.VehicleDetails;\nimport smoketest.test.service.VehicleIdentificationNumberNotFoundException;\n\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * {@code @WebMvcTest} based tests for {@link UserVehicleController}.\n *\n * @author Phillip Webb\n */\n@WebMvcTest(UserVehicleController.class)\nclass UserVehicleControllerTests {\n\n\tprivate static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber(\"00000000000000000\");\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@MockitoBean\n\tprivate UserVehicleService userVehicleService;\n\n\t@Test\n\tvoid getVehicleWhenRequestingTextShouldReturnMakeAndModel() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle\").accept(MediaType.TEXT_PLAIN)).hasStatusOk()\n\t\t\t.hasBodyTextEqualTo(\"Honda Civic\");\n\t}\n\n\t@Test\n\tvoid getVehicleWhenRequestingJsonShouldReturnMakeAndModel() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle\").accept(MediaType.APPLICATION_JSON)).hasStatusOk()\n\t\t\t.bodyJson()\n\t\t\t.isLenientlyEqualTo(\"{'make':'Honda','model':'Civic'}\");\n\t}\n\n\t@Test\n\tvoid getVehicleWhenRequestingHtmlShouldReturnMakeAndModel() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willReturn(new VehicleDetails(\"Honda\", \"Civic\"));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle.html\").accept(MediaType.TEXT_HTML)).hasStatusOk()\n\t\t\t.bodyText()\n\t\t\t.contains(\"<h1>Honda Civic</h1>\");\n\t}\n\n\t@Test\n\tvoid getVehicleWhenUserNotFoundShouldReturnNotFound() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\")).willThrow(new UserNameNotFoundException(\"sboot\"));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle\")).hasStatus(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid getVehicleWhenVinNotFoundShouldReturnNotFound() {\n\t\tgiven(this.userVehicleService.getVehicleDetails(\"sboot\"))\n\t\t\t.willThrow(new VehicleIdentificationNumberNotFoundException(VIN));\n\t\tassertThat(this.mvc.get().uri(\"/sboot/vehicle\")).hasStatus(HttpStatus.NOT_FOUND);\n\t}\n\n\t@Test\n\tvoid welcomeCommandLineRunnerShouldNotBeAvailable() {\n\t\t// Since we're a @WebMvcTest WelcomeCommandLineRunner should not be available.\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class)\n\t\t\t.isThrownBy(() -> this.applicationContext.getBean(WelcomeCommandLineRunner.class));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/java/smoketest/test/web/UserVehicleServiceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.test.web;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport smoketest.test.domain.User;\nimport smoketest.test.domain.UserRepository;\nimport smoketest.test.domain.VehicleIdentificationNumber;\nimport smoketest.test.service.VehicleDetails;\nimport smoketest.test.service.VehicleDetailsService;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.given;\n\n/**\n * Tests for {@link UserVehicleService}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockitoExtension.class)\nclass UserVehicleServiceTests {\n\n\tprivate static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber(\"00000000000000000\");\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate VehicleDetailsService vehicleDetailsService;\n\n\t@Mock\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate UserRepository userRepository;\n\n\tprivate UserVehicleService service;\n\n\t@BeforeEach\n\tvoid setup() {\n\t\tthis.service = new UserVehicleService(this.userRepository, this.vehicleDetailsService);\n\t}\n\n\t@Test\n\t@SuppressWarnings(\"NullAway\") // Test null check\n\tvoid getVehicleDetailsWhenUsernameIsNullShouldThrowException() {\n\t\tassertThatIllegalArgumentException().isThrownBy(() -> this.service.getVehicleDetails(null))\n\t\t\t.withMessage(\"'username' must not be null\");\n\t}\n\n\t@Test\n\tvoid getVehicleDetailsWhenUsernameNotFoundShouldThrowException() {\n\t\tgiven(this.userRepository.findByUsername(anyString())).willReturn(null);\n\t\tassertThatExceptionOfType(UserNameNotFoundException.class)\n\t\t\t.isThrownBy(() -> this.service.getVehicleDetails(\"sboot\"));\n\t}\n\n\t@Test\n\tvoid getVehicleDetailsShouldReturnMakeAndModel() {\n\t\tgiven(this.userRepository.findByUsername(anyString())).willReturn(new User(\"sboot\", VIN));\n\t\tVehicleDetails details = new VehicleDetails(\"Honda\", \"Civic\");\n\t\tgiven(this.vehicleDetailsService.getVehicleDetails(VIN)).willReturn(details);\n\t\tVehicleDetails actual = this.service.getVehicleDetails(\"sboot\");\n\t\tassertThat(actual).isEqualTo(details);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/resources/application.properties",
    "content": "spring.test.mockmvc.print=none\nspring.jpa.defer-datasource-initialization=true\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/resources/data.sql",
    "content": "INSERT INTO DRIVER(id, username, vin) values (123, 'sframework', '01234567890123456');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test/src/test/resources/smoketest/test/service/vehicledetails.json",
    "content": "{\n\t\"make\" : \"Honda\",\n\t\"model\" : \"Civic\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test-nomockito/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Test no Mockito smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":core:spring-boot-test\"))\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.junit.jupiter:junit-jupiter\")\n\ttestImplementation(\"org.springframework:spring-test\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test-nomockito/src/main/java/smoketest/testnomockito/SampleTestNoMockitoApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.testnomockito;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleTestNoMockitoApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTestNoMockitoApplication.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test-nomockito/src/main/java/smoketest/testnomockito/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.testnomockito;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-test-nomockito/src/test/java/smoketest/testnomockito/SampleTestNoMockitoApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.testnomockito;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests that {@code ResetMocksTestExecutionListener} and\n * {@code MockitoTestExecutionListener} gracefully degrade when Mockito is not on the\n * classpath.\n *\n * @author Madhura Bhave\n */\n@ExtendWith(SpringExtension.class)\nclass SampleTestNoMockitoApplicationTests {\n\n\t// gh-7065\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.context).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot TestNG smoke test\"\n\ndependencies {\n\timplementation(platform(project(\":platform:spring-boot-dependencies\")))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-restclient-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(\"org.assertj:assertj-core\")\n\ttestImplementation(\"org.springframework:spring-test\")\n\ttestImplementation(\"org.testng:testng:6.8.13\")\n}\n\ntest {\n\tuseTestNG()\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/java/smoketest/testng/SampleTestNGApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.testng;\n\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleTestNGApplication {\n\n\tprivate static final Log logger = LogFactory.getLog(SampleTestNGApplication.class);\n\n\t@Bean\n\tprotected ServletContextListener listener() {\n\t\treturn new ServletContextListener() {\n\n\t\t\t@Override\n\t\t\tpublic void contextInitialized(ServletContextEvent sce) {\n\t\t\t\tlogger.info(\"ServletContext initialized\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void contextDestroyed(ServletContextEvent sce) {\n\t\t\t\tlogger.info(\"ServletContext destroyed\");\n\t\t\t}\n\n\t\t};\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTestNGApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/java/smoketest/testng/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.testng;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/java/smoketest/testng/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.testng.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/java/smoketest/testng/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.testng.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/java/smoketest/testng/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.testng.web;\n\nimport smoketest.testng.service.HelloWorldService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\npublic class SampleController {\n\n\t@Autowired\n\tprivate HelloWorldService helloWorldService;\n\n\t@GetMapping(\"/\")\n\t@ResponseBody\n\tpublic String helloWorld() {\n\t\treturn this.helloWorldService.getHelloMessage();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/java/smoketest/testng/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.testng.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/main/resources/public/test.css",
    "content": "p.{}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-testng/src/test/java/smoketest/testng/SampleTestNGApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.testng;\n\nimport org.testng.annotations.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.testng.AbstractTestNGSpringContextTests;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\npublic class SampleTestNGApplicationTests extends AbstractTestNGSpringContextTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tpublic void testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Tomcat smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/SampleTomcatApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat;\n\nimport jakarta.servlet.ServletContextEvent;\nimport jakarta.servlet.ServletContextListener;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\npublic class SampleTomcatApplication {\n\n\tprivate static final Log logger = LogFactory.getLog(SampleTomcatApplication.class);\n\n\t@Bean\n\tprotected ServletContextListener listener() {\n\t\treturn new ServletContextListener() {\n\n\t\t\t@Override\n\t\t\tpublic void contextInitialized(ServletContextEvent sce) {\n\t\t\t\tlogger.info(\"ServletContext initialized\");\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void contextDestroyed(ServletContextEvent sce) {\n\t\t\t\tlogger.info(\"ServletContext destroyed\");\n\t\t\t}\n\n\t\t};\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTomcatApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/service/HttpHeaderService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.service;\n\nimport smoketest.tomcat.util.RandomStringUtil;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HttpHeaderService {\n\n\t@Value(\"${server.tomcat.max-http-response-header-size}\")\n\tprivate int maxHttpResponseHeaderSize;\n\n\t/**\n\t * Generates random data. The data is:\n\t * <ol>\n\t * <li>is longer than configured\n\t * <code>server.tomcat.max-http-response-header-size</code></li>\n\t * <li>is url encoded by base 64 encode the random value</li>\n\t * </ol>\n\t * @return a base64 encoded string of random bytes\n\t */\n\tpublic String getHeaderValue() {\n\t\treturn RandomStringUtil.getRandomBase64EncodedString(this.maxHttpResponseHeaderSize + 1);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/util/RandomStringUtil.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.util;\n\nimport java.util.Base64;\nimport java.util.Random;\n\npublic final class RandomStringUtil {\n\n\tprivate RandomStringUtil() {\n\t}\n\n\tpublic static String getRandomBase64EncodedString(int length) {\n\t\tbyte[] responseHeader = new byte[length];\n\t\tnew Random().nextBytes(responseHeader);\n\t\treturn Base64.getEncoder().encodeToString(responseHeader);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/util/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.util;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.web;\n\nimport jakarta.servlet.http.HttpServletResponse;\nimport smoketest.tomcat.service.HelloWorldService;\nimport smoketest.tomcat.service.HttpHeaderService;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@Controller\npublic class SampleController {\n\n\tprivate final HelloWorldService helloWorldService;\n\n\tprivate final HttpHeaderService httpHeaderService;\n\n\tpublic SampleController(HelloWorldService helloWorldService, HttpHeaderService httpHeaderService) {\n\t\tthis.helloWorldService = helloWorldService;\n\t\tthis.httpHeaderService = httpHeaderService;\n\t}\n\n\t@GetMapping(\"/\")\n\t@ResponseBody\n\tpublic String helloWorld() {\n\t\treturn this.helloWorldService.getHelloMessage();\n\t}\n\n\t@GetMapping(\"/max-http-response-header\")\n\t@ResponseBody\n\tpublic String maxHttpResponseHeader(HttpServletResponse response) {\n\t\tString headerValue = this.httpHeaderService.getHeaderValue();\n\t\tresponse.addHeader(\"x-max-header\", headerValue);\n\t\treturn this.helloWorldService.getHelloMessage();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/java/smoketest/tomcat/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/main/resources/application.properties",
    "content": "server.compression.enabled: true\nserver.compression.min-response-size: 1\nserver.max-http-request-header-size=1000\nserver.tomcat.connection-timeout=5s\nserver.tomcat.max-http-response-header-size=1000\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/test/java/smoketest/tomcat/NonAutoConfigurationSampleTomcatApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.tomcat.service.HelloWorldService;\nimport smoketest.tomcat.web.SampleController;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;\nimport org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass NonAutoConfigurationSampleTomcatApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import({ TomcatServletWebServerAutoConfiguration.class, DispatcherServletAutoConfiguration.class,\n\t\t\tWebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,\n\t\t\tPropertyPlaceholderAutoConfiguration.class })\n\t@ComponentScan(basePackageClasses = { SampleController.class, HelloWorldService.class })\n\tpublic static class NonAutoConfigurationSampleTomcatApplication {\n\n\t\tpublic static void main(String[] args) {\n\t\t\tSpringApplication.run(SampleTomcatApplication.class, args);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat/src/test/java/smoketest/tomcat/SampleTomcatApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.zip.GZIPInputStream;\n\nimport org.apache.coyote.AbstractProtocol;\nimport org.apache.coyote.ProtocolHandler;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport smoketest.tomcat.util.RandomStringUtil;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n * @author Andy Wilkinson\n * @author Florian Storz\n * @author Michael Weidmann\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@ExtendWith(OutputCaptureExtension.class)\n@AutoConfigureTestRestTemplate\nclass SampleTomcatApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Value(\"${server.max-http-request-header-size}\")\n\tprivate int maxHttpRequestHeaderSize;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getHeaders().get(HttpHeaders.CONTENT_ENCODING)).isNull();\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testCompression() throws IOException {\n\t\tHttpHeaders requestHeaders = new HttpHeaders();\n\t\trequestHeaders.set(\"Accept-Encoding\", \"gzip\");\n\t\tHttpEntity<?> requestEntity = new HttpEntity<>(requestHeaders);\n\t\tResponseEntity<byte[]> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, requestEntity, byte[].class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getHeaders().get(HttpHeaders.CONTENT_ENCODING)).containsExactly(\"gzip\");\n\t\ttry (GZIPInputStream inflater = new GZIPInputStream(new ByteArrayInputStream(entity.getBody()))) {\n\t\t\tassertThat(StreamUtils.copyToString(inflater, StandardCharsets.UTF_8)).isEqualTo(\"Hello World\");\n\t\t}\n\t}\n\n\t@Test\n\tvoid testTimeout() {\n\t\tServletWebServerApplicationContext context = (ServletWebServerApplicationContext) this.applicationContext;\n\t\tTomcatWebServer embeddedServletContainer = (TomcatWebServer) context.getWebServer();\n\t\tassertThat(embeddedServletContainer).isNotNull();\n\t\tProtocolHandler protocolHandler = embeddedServletContainer.getTomcat().getConnector().getProtocolHandler();\n\t\tint timeout = ((AbstractProtocol<?>) protocolHandler).getConnectionTimeout();\n\t\tassertThat(timeout).isEqualTo(5000);\n\t}\n\n\t@Test\n\tvoid testMaxHttpResponseHeaderSize(CapturedOutput output) {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/max-http-response-header\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(output).contains(\n\t\t\t\t\"threw exception [Request processing failed: org.apache.coyote.http11.HeadersTooLargeException: An attempt was made to write more data to the response headers than there was room available in the buffer. Increase maxHttpHeaderSize on the connector or write less data into the response headers.]\");\n\t}\n\n\t@Test\n\tvoid testMaxHttpRequestHeaderSize(CapturedOutput output) {\n\t\tString headerValue = RandomStringUtil.getRandomBase64EncodedString(this.maxHttpRequestHeaderSize + 1);\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.add(\"x-max-request-header\", headerValue);\n\t\tHttpEntity<?> httpEntity = new HttpEntity<>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, httpEntity, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);\n\t\tassertThat(output).contains(\"java.lang.IllegalArgumentException: Request header is too large\");\n\t}\n\n\t@TestConfiguration\n\tstatic class DisableCompressionConfiguration {\n\n\t\t@Bean\n\t\tRestTemplateBuilder restTemplateBuilder() {\n\t\t\treturn new RestTemplateBuilder().requestFactoryBuilder(ClientHttpRequestFactoryBuilder.jdk()\n\t\t\t\t.withCustomizer((factory) -> factory.enableCompression(false)));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot Tomcat JSP smoke test\"\n\nconfigurations {\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tprovidedRuntime(project(\":starter:spring-boot-starter-tomcat-runtime\"))\n\tprovidedRuntime(\"org.glassfish.web:jakarta.servlet.jsp.jstl\")\n\tprovidedRuntime(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/java/smoketest/tomcat/jsp/MyException.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.jsp;\n\npublic class MyException extends RuntimeException {\n\n\tpublic MyException(String message) {\n\t\tsuper(message);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/java/smoketest/tomcat/jsp/MyRestResponse.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.jsp;\n\npublic class MyRestResponse {\n\n\tprivate final String message;\n\n\tpublic MyRestResponse(String message) {\n\t\tthis.message = message;\n\t}\n\n\tpublic String getMessage() {\n\t\treturn this.message;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/java/smoketest/tomcat/jsp/SampleTomcatJspApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.jsp;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class SampleTomcatJspApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleTomcatJspApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTomcatJspApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/java/smoketest/tomcat/jsp/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.jsp;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n@Controller\npublic class WelcomeController {\n\n\t@Value(\"${application.message:Hello World}\")\n\tprivate String message = \"Hello World\";\n\n\t@GetMapping(\"/\")\n\tpublic String welcome(Map<String, Object> model) {\n\t\tmodel.put(\"time\", new Date());\n\t\tmodel.put(\"message\", this.message);\n\t\treturn \"welcome\";\n\t}\n\n\t@RequestMapping(\"/fail\")\n\tpublic String fail() {\n\t\tthrow new MyException(\"Oh dear!\");\n\t}\n\n\t@RequestMapping(\"/fail2\")\n\tpublic String fail2() {\n\t\tthrow new IllegalStateException();\n\t}\n\n\t@ExceptionHandler(MyException.class)\n\t@ResponseStatus(HttpStatus.BAD_REQUEST)\n\tpublic @ResponseBody MyRestResponse handleMyRuntimeException(MyException exception) {\n\t\treturn new MyRestResponse(\"Some data I want to send back to the client.\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/java/smoketest/tomcat/jsp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.jsp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/resources/application.properties",
    "content": "spring.mvc.view.prefix: /WEB-INF/jsp/\nspring.mvc.view.suffix: .jsp\napplication.message: Hello Phil\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp",
    "content": "<!DOCTYPE html>\n\n<%@ taglib prefix=\"spring\" uri=\"http://www.springframework.org/tags\"%>\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\n\n<html lang=\"en\">\n\n<body>\n\t<c:url value=\"/resources/text.txt\" var=\"url\"/>\n\t<spring:url value=\"/resources/text.txt\" htmlEscape=\"true\" var=\"springUrl\" />\n\tSpring URL: ${springUrl} at ${time}\n\t<br>\n\tJSTL URL: ${url}\n\t<br>\n\tMessage: ${message}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-jsp/src/test/java/smoketest/tomcat/jsp/SampleWebJspApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.jsp;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for JSP application.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebJspApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testJspWithEl() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"/resources/text.txt\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Tomcat multi-connectors smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/src/main/java/smoketest/tomcat/multiconnector/SampleTomcatTwoConnectorsApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.multiconnector;\n\nimport org.apache.catalina.connector.Connector;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Sample Application to show Tomcat running two connectors.\n *\n * @author Brock Mills\n * @author Andy Wilkinson\n */\n@SpringBootApplication\npublic class SampleTomcatTwoConnectorsApplication {\n\n\t@Bean\n\tpublic ServletWebServerFactory servletContainer() {\n\t\tTomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();\n\t\ttomcat.addAdditionalConnectors(createStandardConnector());\n\t\treturn tomcat;\n\t}\n\n\tprivate Connector createStandardConnector() {\n\t\tConnector connector = new Connector(\"org.apache.coyote.http11.Http11NioProtocol\");\n\t\tconnector.setPort(0);\n\t\treturn connector;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTomcatTwoConnectorsApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/src/main/java/smoketest/tomcat/multiconnector/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.multiconnector;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/src/main/java/smoketest/tomcat/multiconnector/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.multiconnector.web;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SampleController {\n\n\t@GetMapping(\"/hello\")\n\tpublic String helloWorld() {\n\t\treturn \"hello\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/src/main/java/smoketest/tomcat/multiconnector/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.multiconnector.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/src/main/resources/application.properties",
    "content": "server.port = 8443\nserver.ssl.key-store = classpath:sample.jks\nserver.ssl.key-store-password = secret\nserver.ssl.key-password = password\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-multi-connectors/src/test/java/smoketest/tomcat/multiconnector/SampleTomcatTwoConnectorsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.multiconnector;\n\nimport org.apache.catalina.Service;\nimport org.apache.catalina.connector.Connector;\nimport org.junit.jupiter.api.Test;\nimport smoketest.tomcat.multiconnector.SampleTomcatTwoConnectorsApplicationTests.Ports;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.TomcatWebServer;\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.boot.web.server.context.WebServerInitializedEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for {@link SampleTomcatTwoConnectorsApplication}.\n *\n * @author Brock Mills\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@Import(Ports.class)\n@AutoConfigureTestRestTemplate\nclass SampleTomcatTwoConnectorsApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate Ports ports;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate AbstractConfigurableWebServerFactory webServerFactory;\n\n\t@Test\n\tvoid testSsl() {\n\t\tSsl ssl = this.webServerFactory.getSsl();\n\t\tassertThat(ssl).isNotNull();\n\t\tassertThat(ssl.isEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid testHello() {\n\t\tassertThat(this.ports.getHttpsPort()).isEqualTo(this.port);\n\t\tassertThat(this.ports.getHttpPort()).isNotEqualTo(this.port);\n\t\tResponseEntity<String> entity = this.restTemplate\n\t\t\t.getForEntity(\"http://localhost:\" + this.ports.getHttpPort() + \"/hello\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"hello\");\n\t\tResponseEntity<String> httpsEntity = this.restTemplate.getForEntity(\"https://localhost:\" + this.port + \"/hello\",\n\t\t\t\tString.class);\n\t\tassertThat(httpsEntity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(httpsEntity.getBody()).isEqualTo(\"hello\");\n\t}\n\n\t@TestConfiguration\n\tstatic class Ports implements ApplicationListener<WebServerInitializedEvent> {\n\n\t\tprivate int httpPort;\n\n\t\tprivate int httpsPort;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(WebServerInitializedEvent event) {\n\t\t\tService service = ((TomcatWebServer) event.getWebServer()).getTomcat().getService();\n\t\t\tfor (Connector connector : service.findConnectors()) {\n\t\t\t\tif (connector.getSecure()) {\n\t\t\t\t\tthis.httpsPort = connector.getLocalPort();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.httpPort = connector.getLocalPort();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tint getHttpPort() {\n\t\t\treturn this.httpPort;\n\t\t}\n\n\t\tint getHttpsPort() {\n\t\t\treturn this.httpsPort;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Tomcat SSL smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/src/main/java/smoketest/tomcat/ssl/SampleTomcatSslApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.ssl;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleTomcatSslApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTomcatSslApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/src/main/java/smoketest/tomcat/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.ssl;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/src/main/java/smoketest/tomcat/ssl/web/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.ssl.web;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String helloWorld() {\n\t\treturn \"Hello, world\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/src/main/java/smoketest/tomcat/ssl/web/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.tomcat.ssl.web;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/src/main/resources/application.properties",
    "content": "server.port=8443\n\nmanagement.endpoints.web.exposure.include=*\nmanagement.endpoint.health.show-details=always\nmanagement.health.ssl.certificate-validity-warning-threshold=7d\nmanagement.health.ssl.enabled=true\nmanagement.info.ssl.enabled=true\n\nserver.ssl.bundle=ssldemo\nspring.ssl.bundle.jks.ssldemo.keystore.location=classpath:sample.jks\nspring.ssl.bundle.jks.ssldemo.keystore.password=secret\nspring.ssl.bundle.jks.ssldemo.keystore.type=JKS\nspring.ssl.bundle.jks.ssldemo.key.password=password\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-tomcat-ssl/src/test/java/smoketest/tomcat/ssl/SampleTomcatSslApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.tomcat.ssl;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;\nimport org.springframework.boot.web.server.Ssl;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.json.JsonContent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleTomcatSslApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Autowired\n\tprivate AbstractConfigurableWebServerFactory webServerFactory;\n\n\t@Test\n\tvoid testSsl() {\n\t\tSsl ssl = this.webServerFactory.getSsl();\n\t\tassertThat(ssl).isNotNull();\n\t\tassertThat(ssl.isEnabled()).isTrue();\n\t}\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).isEqualTo(\"Hello, world\");\n\t}\n\n\t@Test\n\tvoid testSslInfo() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/actuator/info\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tString body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tJsonContent json = new JsonContent(body);\n\t\tassertThat(json).extractingPath(\"ssl.bundles[0].name\").isEqualTo(\"ssldemo\");\n\t\tassertThat(json).extractingPath(\"ssl.bundles[0].certificateChains[0].alias\")\n\t\t\t.isEqualTo(\"spring-boot-ssl-sample\");\n\t\tassertThat(json).extractingPath(\"ssl.bundles[0].certificateChains[0].certificates[0].issuer\")\n\t\t\t.isEqualTo(\"CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown\");\n\t\tassertThat(json).extractingPath(\"ssl.bundles[0].certificateChains[0].certificates[0].subject\")\n\t\t\t.isEqualTo(\"CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown\");\n\t\tassertThat(json).extractingPath(\"ssl.bundles[0].certificateChains[0].certificates[0].validity.status\")\n\t\t\t.isEqualTo(\"EXPIRED\");\n\t\tassertThat(json).extractingPath(\"ssl.bundles[0].certificateChains[0].certificates[0].validity.message\")\n\t\t\t.asString()\n\t\t\t.startsWith(\"Not valid after \");\n\t}\n\n\t@Test\n\tvoid testSslHealth() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/actuator/health\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);\n\t\tString body = entity.getBody();\n\t\tassertThat(body).isNotNull();\n\t\tJsonContent json = new JsonContent(body);\n\t\tassertThat(json).extractingPath(\"status\").isEqualTo(\"OUT_OF_SERVICE\");\n\t\tassertThat(json).extractingPath(\"components.ssl.status\").isEqualTo(\"OUT_OF_SERVICE\");\n\t\tassertThat(json).extractingPath(\"components.ssl.details.invalidChains[0].alias\")\n\t\t\t.isEqualTo(\"spring-boot-ssl-sample\");\n\t\tassertThat(json).extractingPath(\"components.ssl.details.invalidChains[0].certificates[0].issuer\")\n\t\t\t.isEqualTo(\"CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown\");\n\t\tassertThat(json).extractingPath(\"components.ssl.details.invalidChains[0].certificates[0].subject\")\n\t\t\t.isEqualTo(\"CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown\");\n\t\tassertThat(json).extractingPath(\"components.ssl.details.invalidChains[0].certificates[0].validity.status\")\n\t\t\t.isEqualTo(\"EXPIRED\");\n\t\tassertThat(json).extractingPath(\"components.ssl.details.invalidChains[0].certificates[0].validity.message\")\n\t\t\t.asString()\n\t\t\t.startsWith(\"Not valid after \");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot traditional deployment smoke test\"\n\nconfigurations {\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\timplementation(project(\":module:spring-boot-webmvc\"))\n\n\tprovidedRuntime(project(\":starter:spring-boot-starter-tomcat-runtime\"))\n\tprovidedRuntime(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/java/smoketest/traditional/SampleTraditionalApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.traditional;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleTraditionalApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTraditionalApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/java/smoketest/traditional/config/WebConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.traditional.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.servlet.DispatcherServlet;\nimport org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;\nimport org.springframework.web.servlet.config.annotation.EnableWebMvc;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\nimport org.springframework.web.servlet.view.InternalResourceViewResolver;\n\n@EnableWebMvc\n@ComponentScan\n@Configuration(proxyBeanMethods = false)\npublic class WebConfig implements WebMvcConfigurer {\n\n\t@Override\n\tpublic void addViewControllers(ViewControllerRegistry registry) {\n\t\tregistry.addViewController(\"/\").setViewName(\"home\");\n\t}\n\n\t@Bean\n\tpublic InternalResourceViewResolver viewResolver() {\n\t\tInternalResourceViewResolver viewResolver = new InternalResourceViewResolver();\n\t\tviewResolver.setPrefix(\"/WEB-INF/views/\");\n\t\tviewResolver.setSuffix(\".jsp\");\n\t\treturn viewResolver;\n\t}\n\n\t@Bean\n\t// Only used when running in embedded servlet\n\tpublic DispatcherServlet dispatcherServlet() {\n\t\treturn new DispatcherServlet();\n\t}\n\n\t@Override\n\tpublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {\n\t\tconfigurer.enable();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/java/smoketest/traditional/config/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.traditional.config;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/java/smoketest/traditional/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.traditional;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/resources/application.properties",
    "content": "server.servlet.register-default-servlet=true"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/webapp/WEB-INF/views/home.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\" pageEncoding=\"UTF-8\"%>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"https://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n<title>Home</title>\n</head>\n<body>\n  <h1>Home</h1>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/webapp/WEB-INF/web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app version=\"3.1\" xmlns=\"http://xmlns.jcp.org/xml/ns/javaee \"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\">\n\n\t<servlet>\n\t\t<servlet-name>appServlet</servlet-name>\n\t\t<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>\n\t\t<init-param>\n\t\t\t<param-name>contextClass</param-name>\n\t\t\t<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>\n\t\t</init-param>\n\t\t<init-param>\n\t\t\t<param-name>contextConfigLocation</param-name>\n\t\t\t<param-value>sample.traditional.config</param-value>\n\t\t</init-param>\n\t\t<load-on-startup>1</load-on-startup>\n\t</servlet>\n\n\t<servlet-mapping>\n\t\t<servlet-name>appServlet</servlet-name>\n\t\t<url-pattern>/</url-pattern>\n\t</servlet-mapping>\n\n</web-app>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/main/webapp/index.html",
    "content": "<html>\n<body>\n<h1>Hello</h1>\nHello World!\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/test/java/smoketest/traditional/SampleTraditionalApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.traditional;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleTraditionalApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHomeJsp() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tString body = entity.getBody();\n\t\tassertThat(body).contains(\"<html>\").contains(\"<h1>Home</h1>\");\n\t}\n\n\t@Test\n\tvoid testStaticPage() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/index.html\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tString body = entity.getBody();\n\t\tassertThat(body).contains(\"<html>\").contains(\"<h1>Hello</h1>\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-traditional/src/test/resources/log4j.properties",
    "content": "log4j.rootCategory=INFO, stdout\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.layout=org.apache.log4j.PatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n\n\nlog4j.category.org.springframework.web=DEBUG\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot war smoke test\"\n\nconfigurations {\n\tprovidedCompile {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude module: \"spring-boot-starter-tomcat\"\n\t}\n\n\tprovidedCompile(\"jakarta.servlet:jakarta.servlet-api\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/src/main/java/smoketest/war/MyController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.war;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class MyController {\n\n\t@GetMapping(\"/\")\n\tpublic String hello() {\n\t\treturn \"Hello World!\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/src/main/java/smoketest/war/SampleWarApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.war;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.annotation.PropertySource;\n\n@SpringBootApplication\n@PropertySource(\"WEB-INF/custom.properties\")\npublic class SampleWarApplication extends SpringBootServletInitializer {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWarApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/src/main/java/smoketest/war/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.war;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/src/main/webapp/WEB-INF/custom.properties",
    "content": "demo.string.value=demo\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/src/main/webapp/webapp.txt",
    "content": "Hello WebApp\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-war/src/test/java/smoketest/war/WarApplicationResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.war;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.test.context.SpringBootTest;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest\nclass WarApplicationResourceTests {\n\n\t// gh-6371\n\n\t@Value(\"${demo.string.value}\")\n\tprivate @Nullable String demoStringValue;\n\n\t@Test\n\tvoid contextLoads() {\n\t\tassertThat(this.demoStringValue).isEqualTo(\"demo\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web application type smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n\ttestImplementation(project(\":test-support:spring-boot-test-support\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/main/java/smoketest/webapplicationtype/SampleWebApplicationTypeApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webapplicationtype;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleWebApplicationTypeApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebApplicationTypeApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/main/java/smoketest/webapplicationtype/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.webapplicationtype;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/main/resources/application.properties",
    "content": "spring.main.web-application-type=reactive\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/test/java/smoketest/webapplicationtype/OverriddenWebApplicationTypeApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webapplicationtype;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for an application using an overridden web application type\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(properties = \"spring.main.web-application-type=servlet\")\nclass OverriddenWebApplicationTypeApplicationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid contextIsServlet() {\n\t\tassertThat(this.context).isInstanceOf(WebApplicationContext.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/test/java/smoketest/webapplicationtype/SampleWebApplicationTypeApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webapplicationtype;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for an application using a configured web application type\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest\nclass SampleWebApplicationTypeApplicationTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid contextIsReactive() {\n\t\tassertThat(this.context).isInstanceOf(ReactiveWebApplicationContext.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/test/java/smoketest/webapplicationtype/WebApplicationTypeIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webapplicationtype;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for {@link WebApplicationType} deducers.\n *\n * @author Phillip Webb\n */\nclass WebApplicationTypeIntegrationTests {\n\n\t@Test\n\t@ClassPathExclusions(\"spring-boot-webflux*\")\n\tvoid deduceWhenNoWebFluxModuleAndWebMvcModule() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-boot-webflux*\", \"spring-web-*\" })\n\tvoid deduceWhenNoWebFluxModuleAndNoSpringWebAndWebMvcModule() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"spring-boot-webmvc*\")\n\tvoid deduceWhenNoWebMvcModuleAndWebFluxModule() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.REACTIVE);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-boot-webmvc*\", \"spring-webflux-*\" })\n\tvoid deduceWhenNoWebMvcModuleAndNoWebFluxAndWebFluxModule() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-boot-webmvc*\", \"spring-webflux-*\", \"spring-web-*\" })\n\tvoid deduceWhenNoWebMvcModuleAndNoWebFluxAndNoWebAndWebFluxModule() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE);\n\t}\n\n\t@Test\n\tvoid deduceWhenWebMvcAndWebFlux() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(\"spring-webmvc-*\")\n\tvoid deduceWhenNoWebMvc() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.REACTIVE);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-webmvc-*\", \"spring-webflux-*\" })\n\tvoid deduceWhenNoWebMvcAndNoWebFlux() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.SERVLET);\n\t}\n\n\t@Test\n\t@ClassPathExclusions({ \"spring-web-*\" })\n\tvoid deduceWhenNoWeb() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE);\n\t}\n\n\t@Test\n\t@ClassPathExclusions(packages = \"jakarta.servlet\", files = \"spring-webflux-*\")\n\tvoid deduceWhenNoServletOrWebFlux() {\n\t\tassertThat(WebApplicationType.deduce()).isEqualTo(WebApplicationType.NONE);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-application-type/src/test/java/smoketest/webapplicationtype/WebEnvironmentNoneOverridesWebApplicationTypeTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webapplicationtype;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for a web environment of none overriding the configured web\n * application type.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.NONE)\nclass WebEnvironmentNoneOverridesWebApplicationTypeTests {\n\n\t@Autowired\n\tprivate ApplicationContext context;\n\n\t@Test\n\tvoid contextIsPlain() {\n\t\tassertThat(this.context).isNotInstanceOf(ReactiveWebApplicationContext.class);\n\t\tassertThat(this.context).isNotInstanceOf(WebApplicationContext.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web FreeMarker smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-freemarker\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-freemarker-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/java/smoketest/freemarker/SampleWebFreeMarkerApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.freemarker;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleWebFreeMarkerApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebFreeMarkerApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/java/smoketest/freemarker/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.freemarker;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.server.ResponseStatusException;\n\n@Controller\npublic class WelcomeController {\n\n\t@Value(\"${application.message:Hello World}\")\n\tprivate String message = \"Hello World\";\n\n\t@GetMapping(\"/\")\n\tpublic String welcome(Map<String, Object> model) {\n\t\tmodel.put(\"time\", new Date());\n\t\tmodel.put(\"message\", this.message);\n\t\treturn \"welcome\";\n\t}\n\n\t@GetMapping(\"insufficient-storage\")\n\tvoid outOfStorage() {\n\t\tthrow new ResponseStatusException(HttpStatus.INSUFFICIENT_STORAGE);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/java/smoketest/freemarker/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.freemarker;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/resources/application.properties",
    "content": "application.message: Hello, Andy\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/resources/templates/error/507.ftlh",
    "content": "We are out of storage"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/resources/templates/error.ftlh",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tSomething went wrong: ${status} ${error}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/main/resources/templates/welcome.ftlh",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tDate: ${time?date}\n\t<br>\n\tTime: ${time?time}\n\t<br>\n\tMessage: ${message}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-freemarker/src/test/java/smoketest/freemarker/SampleWebFreeMarkerApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.freemarker;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for FreeMarker application.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebFreeMarkerApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\t@Test\n\tvoid testFreeMarkerTemplate() {\n\t\tResponseEntity<String> entity = this.testRestTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"Hello, Andy\");\n\t}\n\n\t@Test\n\tvoid testFreeMarkerErrorTemplate() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<String> requestEntity = new HttpEntity<>(headers);\n\n\t\tResponseEntity<String> responseEntity = this.testRestTemplate.exchange(\"/does-not-exist\", HttpMethod.GET,\n\t\t\t\trequestEntity, String.class);\n\n\t\tassertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tassertThat(responseEntity.getBody()).contains(\"Something went wrong: 404 Not Found\");\n\t}\n\n\t@Test\n\tvoid templateErrorPageForSpecificStatusCode() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<String> requestEntity = new HttpEntity<>(headers);\n\n\t\tResponseEntity<String> responseEntity = this.testRestTemplate.exchange(\"/insufficient-storage\", HttpMethod.GET,\n\t\t\t\trequestEntity, String.class);\n\n\t\tassertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INSUFFICIENT_STORAGE);\n\t\tassertThat(responseEntity.getBody()).contains(\"We are out of storage\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web Groovy Templates smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-groovy-templates\"))\n\timplementation(project(\":starter:spring-boot-starter-validation\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\timplementation(\"jakarta.xml.bind:jakarta.xml.bind-api\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-groovy-templates-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/InMemoryMessageRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class InMemoryMessageRepository implements MessageRepository {\n\n\tprivate static final AtomicLong counter = new AtomicLong();\n\n\tprivate final ConcurrentMap<Long, Message> messages = new ConcurrentHashMap<>();\n\n\t@Override\n\tpublic Iterable<Message> findAll() {\n\t\treturn this.messages.values();\n\t}\n\n\t@Override\n\tpublic Message save(Message message) {\n\t\tLong id = message.getId();\n\t\tif (id == null) {\n\t\t\tid = counter.incrementAndGet();\n\t\t\tmessage.setId(id);\n\t\t}\n\t\tthis.messages.put(id, message);\n\t\treturn message;\n\t}\n\n\t@Override\n\tpublic @Nullable Message findMessage(Long id) {\n\t\treturn this.messages.get(id);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/Message.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates;\n\nimport java.util.Date;\n\nimport jakarta.validation.constraints.NotEmpty;\nimport org.jspecify.annotations.Nullable;\n\npublic class Message {\n\n\tprivate @Nullable Long id;\n\n\t@NotEmpty(message = \"Text is required.\")\n\tprivate @Nullable String text;\n\n\t@NotEmpty(message = \"Summary is required.\")\n\tprivate @Nullable String summary;\n\n\tprivate Date created = new Date();\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic Date getCreated() {\n\t\treturn this.created;\n\t}\n\n\tpublic void setCreated(Date created) {\n\t\tthis.created = created;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n\tpublic @Nullable String getSummary() {\n\t\treturn this.summary;\n\t}\n\n\tpublic void setSummary(@Nullable String summary) {\n\t\tthis.summary = summary;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/MessageRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates;\n\nimport org.jspecify.annotations.Nullable;\n\npublic interface MessageRepository {\n\n\tIterable<Message> findAll();\n\n\tMessage save(Message message);\n\n\t@Nullable Message findMessage(Long id);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/SampleGroovyTemplateApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.convert.converter.Converter;\n\n@SpringBootApplication\npublic class SampleGroovyTemplateApplication {\n\n\t@Bean\n\tpublic MessageRepository messageRepository() {\n\t\treturn new InMemoryMessageRepository();\n\t}\n\n\t@Bean\n\tpublic Converter<String, @Nullable Message> messageConverter() {\n\t\treturn (id) -> messageRepository().findMessage(Long.valueOf(id));\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleGroovyTemplateApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/mvc/MessageController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates.mvc;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport jakarta.validation.Valid;\nimport smoketest.groovytemplates.Message;\nimport smoketest.groovytemplates.MessageRepository;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.validation.FieldError;\nimport org.springframework.validation.ObjectError;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ModelAttribute;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\n@Controller\n@RequestMapping(\"/\")\npublic class MessageController {\n\n\tprivate final MessageRepository messageRepository;\n\n\tpublic MessageController(MessageRepository messageRepository) {\n\t\tthis.messageRepository = messageRepository;\n\t}\n\n\t@GetMapping\n\tpublic ModelAndView list() {\n\t\tIterable<Message> messages = this.messageRepository.findAll();\n\t\treturn new ModelAndView(\"messages/list\", \"messages\", messages);\n\t}\n\n\t@GetMapping(\"{id}\")\n\tpublic ModelAndView view(@PathVariable(\"id\") Message message) {\n\t\treturn new ModelAndView(\"messages/view\", \"message\", message);\n\t}\n\n\t@GetMapping(params = \"form\")\n\tpublic String createForm(@ModelAttribute Message message) {\n\t\treturn \"messages/form\";\n\t}\n\n\t@PostMapping\n\tpublic ModelAndView create(@Valid Message message, BindingResult result, RedirectAttributes redirect) {\n\t\tif (result.hasErrors()) {\n\t\t\tModelAndView mav = new ModelAndView(\"messages/form\");\n\t\t\tmav.addObject(\"formErrors\", result.getAllErrors());\n\t\t\tmav.addObject(\"fieldErrors\", getFieldErrors(result));\n\t\t\treturn mav;\n\t\t}\n\t\tmessage = this.messageRepository.save(message);\n\t\tredirect.addFlashAttribute(\"globalMessage\", \"Successfully created a new message\");\n\t\tLong id = message.getId();\n\t\tAssert.state(id != null, \"'id' must not be null\");\n\t\treturn new ModelAndView(\"redirect:/{message.id}\", \"message.id\", id);\n\t}\n\n\tprivate Map<String, ObjectError> getFieldErrors(BindingResult result) {\n\t\tMap<String, ObjectError> map = new HashMap<>();\n\t\tfor (FieldError error : result.getFieldErrors()) {\n\t\t\tmap.put(error.getField(), error);\n\t\t}\n\t\treturn map;\n\t}\n\n\t@RequestMapping(\"foo\")\n\tpublic String foo() {\n\t\tthrow new RuntimeException(\"Expected exception in controller\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/mvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.groovytemplates.mvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/java/smoketest/groovytemplates/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.groovytemplates;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/application.properties",
    "content": "# Allow templates to be reloaded at dev time\nspring.groovy.template.cache: false\nlogging.level.org.springframework.web: INFO\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/static/js/jquery-1.7.2.js",
    "content": "/*!\n * jQuery JavaScript Library v1.7.2\n * https://jquery.com/\n *\n * Copyright 2011, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * https://jquery.org/license\n *\n * Includes Sizzle.js\n * https://sizzlejs.com/\n * Copyright 2011, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Wed Mar 21 12:46:34 2012 -0700\n */\n(function( window, undefined ) {\n\n// Use the correct document accordingly with window argument (sandbox)\nvar document = window.document,\n  navigator = window.navigator,\n  location = window.location;\nvar jQuery = (function() {\n\n// Define a local copy of jQuery\nvar jQuery = function( selector, context ) {\n    // The jQuery object is actually just the init constructor 'enhanced'\n    return new jQuery.fn.init( selector, context, rootjQuery );\n  },\n\n  // Map over jQuery in case of overwrite\n  _jQuery = window.jQuery,\n\n  // Map over the $ in case of overwrite\n  _$ = window.$,\n\n  // A central reference to the root jQuery(document)\n  rootjQuery,\n\n  // A simple way to check for HTML strings or ID strings\n  // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n  quickExpr = /^(?:[^#<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)/,\n\n  // Check if a string has a non-whitespace character in it\n  rnotwhite = /\\S/,\n\n  // Used for trimming whitespace\n  trimLeft = /^\\s+/,\n  trimRight = /\\s+$/,\n\n  // Match a standalone tag\n  rsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\n\n  // JSON RegExp\n  rvalidchars = /^[\\],:{}\\s]*$/,\n  rvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,\n  rvalidtokens = /\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,\n  rvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\n  // Useragent RegExp\n  rwebkit = /(webkit)[ \\/]([\\w.]+)/,\n  ropera = /(opera)(?:.*version)?[ \\/]([\\w.]+)/,\n  rmsie = /(msie) ([\\w.]+)/,\n  rmozilla = /(mozilla)(?:.*? rv:([\\w.]+))?/,\n\n  // Matches dashed string for camelizing\n  rdashAlpha = /-([a-z]|[0-9])/ig,\n  rmsPrefix = /^-ms-/,\n\n  // Used by jQuery.camelCase as callback to replace()\n  fcamelCase = function( all, letter ) {\n    return ( letter + \"\" ).toUpperCase();\n  },\n\n  // Keep a UserAgent string for use with jQuery.browser\n  userAgent = navigator.userAgent,\n\n  // For matching the engine and version of the browser\n  browserMatch,\n\n  // The deferred used on DOM ready\n  readyList,\n\n  // The ready event handler\n  DOMContentLoaded,\n\n  // Save a reference to some core methods\n  toString = Object.prototype.toString,\n  hasOwn = Object.prototype.hasOwnProperty,\n  push = Array.prototype.push,\n  slice = Array.prototype.slice,\n  trim = String.prototype.trim,\n  indexOf = Array.prototype.indexOf,\n\n  // [[Class]] -> type pairs\n  class2type = {};\n\njQuery.fn = jQuery.prototype = {\n  constructor: jQuery,\n  init: function( selector, context, rootjQuery ) {\n    var match, elem, ret, doc;\n\n    // Handle $(\"\"), $(null), or $(undefined)\n    if ( !selector ) {\n      return this;\n    }\n\n    // Handle $(DOMElement)\n    if ( selector.nodeType ) {\n      this.context = this[0] = selector;\n      this.length = 1;\n      return this;\n    }\n\n    // The body element only exists once, optimize finding it\n    if ( selector === \"body\" && !context && document.body ) {\n      this.context = document;\n      this[0] = document.body;\n      this.selector = selector;\n      this.length = 1;\n      return this;\n    }\n\n    // Handle HTML strings\n    if ( typeof selector === \"string\" ) {\n      // Are we dealing with HTML string or an ID?\n      if ( selector.charAt(0) === \"<\" && selector.charAt( selector.length - 1 ) === \">\" && selector.length >= 3 ) {\n        // Assume that strings that start and end with <> are HTML and skip the regex check\n        match = [ null, selector, null ];\n\n      } else {\n        match = quickExpr.exec( selector );\n      }\n\n      // Verify a match, and that no context was specified for #id\n      if ( match && (match[1] || !context) ) {\n\n        // HANDLE: $(html) -> $(array)\n        if ( match[1] ) {\n          context = context instanceof jQuery ? context[0] : context;\n          doc = ( context ? context.ownerDocument || context : document );\n\n          // If a single string is passed in and it's a single tag\n          // just do a createElement and skip the rest\n          ret = rsingleTag.exec( selector );\n\n          if ( ret ) {\n            if ( jQuery.isPlainObject( context ) ) {\n              selector = [ document.createElement( ret[1] ) ];\n              jQuery.fn.attr.call( selector, context, true );\n\n            } else {\n              selector = [ doc.createElement( ret[1] ) ];\n            }\n\n          } else {\n            ret = jQuery.buildFragment( [ match[1] ], [ doc ] );\n            selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;\n          }\n\n          return jQuery.merge( this, selector );\n\n        // HANDLE: $(\"#id\")\n        } else {\n          elem = document.getElementById( match[2] );\n\n          // Check parentNode to catch when Blackberry 4.6 returns\n          // nodes that are no longer in the document #6963\n          if ( elem && elem.parentNode ) {\n            // Handle the case where IE and Opera return items\n            // by name instead of ID\n            if ( elem.id !== match[2] ) {\n              return rootjQuery.find( selector );\n            }\n\n            // Otherwise, we inject the element directly into the jQuery object\n            this.length = 1;\n            this[0] = elem;\n          }\n\n          this.context = document;\n          this.selector = selector;\n          return this;\n        }\n\n      // HANDLE: $(expr, $(...))\n      } else if ( !context || context.jquery ) {\n        return ( context || rootjQuery ).find( selector );\n\n      // HANDLE: $(expr, context)\n      // (which is just equivalent to: $(context).find(expr)\n      } else {\n        return this.constructor( context ).find( selector );\n      }\n\n    // HANDLE: $(function)\n    // Shortcut for document ready\n    } else if ( jQuery.isFunction( selector ) ) {\n      return rootjQuery.ready( selector );\n    }\n\n    if ( selector.selector !== undefined ) {\n      this.selector = selector.selector;\n      this.context = selector.context;\n    }\n\n    return jQuery.makeArray( selector, this );\n  },\n\n  // Start with an empty selector\n  selector: \"\",\n\n  // The current version of jQuery being used\n  jquery: \"1.7.2\",\n\n  // The default length of a jQuery object is 0\n  length: 0,\n\n  // The number of elements contained in the matched element set\n  size: function() {\n    return this.length;\n  },\n\n  toArray: function() {\n    return slice.call( this, 0 );\n  },\n\n  // Get the Nth element in the matched element set OR\n  // Get the whole matched element set as a clean array\n  get: function( num ) {\n    return num == null ?\n\n      // Return a 'clean' array\n      this.toArray() :\n\n      // Return just the object\n      ( num < 0 ? this[ this.length + num ] : this[ num ] );\n  },\n\n  // Take an array of elements and push it onto the stack\n  // (returning the new matched element set)\n  pushStack: function( elems, name, selector ) {\n    // Build a new jQuery matched element set\n    var ret = this.constructor();\n\n    if ( jQuery.isArray( elems ) ) {\n      push.apply( ret, elems );\n\n    } else {\n      jQuery.merge( ret, elems );\n    }\n\n    // Add the old object onto the stack (as a reference)\n    ret.prevObject = this;\n\n    ret.context = this.context;\n\n    if ( name === \"find\" ) {\n      ret.selector = this.selector + ( this.selector ? \" \" : \"\" ) + selector;\n    } else if ( name ) {\n      ret.selector = this.selector + \".\" + name + \"(\" + selector + \")\";\n    }\n\n    // Return the newly-formed element set\n    return ret;\n  },\n\n  // Execute a callback for every element in the matched set.\n  // (You can seed the arguments with an array of args, but this is\n  // only used internally.)\n  each: function( callback, args ) {\n    return jQuery.each( this, callback, args );\n  },\n\n  ready: function( fn ) {\n    // Attach the listeners\n    jQuery.bindReady();\n\n    // Add the callback\n    readyList.add( fn );\n\n    return this;\n  },\n\n  eq: function( i ) {\n    i = +i;\n    return i === -1 ?\n      this.slice( i ) :\n      this.slice( i, i + 1 );\n  },\n\n  first: function() {\n    return this.eq( 0 );\n  },\n\n  last: function() {\n    return this.eq( -1 );\n  },\n\n  slice: function() {\n    return this.pushStack( slice.apply( this, arguments ),\n      \"slice\", slice.call(arguments).join(\",\") );\n  },\n\n  map: function( callback ) {\n    return this.pushStack( jQuery.map(this, function( elem, i ) {\n      return callback.call( elem, i, elem );\n    }));\n  },\n\n  end: function() {\n    return this.prevObject || this.constructor(null);\n  },\n\n  // For internal use only.\n  // Behaves like an Array's method, not like a jQuery method.\n  push: push,\n  sort: [].sort,\n  splice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n  var options, name, src, copy, copyIsArray, clone,\n    target = arguments[0] || {},\n    i = 1,\n    length = arguments.length,\n    deep = false;\n\n  // Handle a deep copy situation\n  if ( typeof target === \"boolean\" ) {\n    deep = target;\n    target = arguments[1] || {};\n    // skip the boolean and the target\n    i = 2;\n  }\n\n  // Handle case when target is a string or something (possible in deep copy)\n  if ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n    target = {};\n  }\n\n  // extend jQuery itself if only one argument is passed\n  if ( length === i ) {\n    target = this;\n    --i;\n  }\n\n  for ( ; i < length; i++ ) {\n    // Only deal with non-null/undefined values\n    if ( (options = arguments[ i ]) != null ) {\n      // Extend the base object\n      for ( name in options ) {\n        src = target[ name ];\n        copy = options[ name ];\n\n        // Prevent never-ending loop\n        if ( target === copy ) {\n          continue;\n        }\n\n        // Recurse if we're merging plain objects or arrays\n        if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n          if ( copyIsArray ) {\n            copyIsArray = false;\n            clone = src && jQuery.isArray(src) ? src : [];\n\n          } else {\n            clone = src && jQuery.isPlainObject(src) ? src : {};\n          }\n\n          // Never move original objects, clone them\n          target[ name ] = jQuery.extend( deep, clone, copy );\n\n        // Don't bring in undefined values\n        } else if ( copy !== undefined ) {\n          target[ name ] = copy;\n        }\n      }\n    }\n  }\n\n  // Return the modified object\n  return target;\n};\n\njQuery.extend({\n  noConflict: function( deep ) {\n    if ( window.$ === jQuery ) {\n      window.$ = _$;\n    }\n\n    if ( deep && window.jQuery === jQuery ) {\n      window.jQuery = _jQuery;\n    }\n\n    return jQuery;\n  },\n\n  // Is the DOM ready to be used? Set to true once it occurs.\n  isReady: false,\n\n  // A counter to track how many items to wait for before\n  // the ready event fires. See #6781\n  readyWait: 1,\n\n  // Hold (or release) the ready event\n  holdReady: function( hold ) {\n    if ( hold ) {\n      jQuery.readyWait++;\n    } else {\n      jQuery.ready( true );\n    }\n  },\n\n  // Handle when the DOM is ready\n  ready: function( wait ) {\n    // Either a released hold or an DOMready/load event and not yet ready\n    if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {\n      // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n      if ( !document.body ) {\n        return setTimeout( jQuery.ready, 1 );\n      }\n\n      // Remember that the DOM is ready\n      jQuery.isReady = true;\n\n      // If a normal DOM Ready event fired, decrement, and wait if need be\n      if ( wait !== true && --jQuery.readyWait > 0 ) {\n        return;\n      }\n\n      // If there are functions bound, to execute\n      readyList.fireWith( document, [ jQuery ] );\n\n      // Trigger any bound ready events\n      if ( jQuery.fn.trigger ) {\n        jQuery( document ).trigger( \"ready\" ).off( \"ready\" );\n      }\n    }\n  },\n\n  bindReady: function() {\n    if ( readyList ) {\n      return;\n    }\n\n    readyList = jQuery.Callbacks( \"once memory\" );\n\n    // Catch cases where $(document).ready() is called after the\n    // browser event has already occurred.\n    if ( document.readyState === \"complete\" ) {\n      // Handle it asynchronously to allow scripts the opportunity to delay ready\n      return setTimeout( jQuery.ready, 1 );\n    }\n\n    // Mozilla, Opera and webkit nightlies currently support this event\n    if ( document.addEventListener ) {\n      // Use the handy event callback\n      document.addEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\n      // A fallback to window.onload, that will always work\n      window.addEventListener( \"load\", jQuery.ready, false );\n\n    // If IE event model is used\n    } else if ( document.attachEvent ) {\n      // ensure firing before onload,\n      // maybe late but safe also for iframes\n      document.attachEvent( \"onreadystatechange\", DOMContentLoaded );\n\n      // A fallback to window.onload, that will always work\n      window.attachEvent( \"onload\", jQuery.ready );\n\n      // If IE and not a frame\n      // continually check to see if the document is ready\n      var toplevel = false;\n\n      try {\n        toplevel = window.frameElement == null;\n      } catch(e) {}\n\n      if ( document.documentElement.doScroll && toplevel ) {\n        doScrollCheck();\n      }\n    }\n  },\n\n  // See test/unit/core.js for details concerning isFunction.\n  // Since version 1.3, DOM methods and functions like alert\n  // aren't supported. They return false on IE (#2968).\n  isFunction: function( obj ) {\n    return jQuery.type(obj) === \"function\";\n  },\n\n  isArray: Array.isArray || function( obj ) {\n    return jQuery.type(obj) === \"array\";\n  },\n\n  isWindow: function( obj ) {\n    return obj != null && obj == obj.window;\n  },\n\n  isNumeric: function( obj ) {\n    return !isNaN( parseFloat(obj) ) && isFinite( obj );\n  },\n\n  type: function( obj ) {\n    return obj == null ?\n      String( obj ) :\n      class2type[ toString.call(obj) ] || \"object\";\n  },\n\n  isPlainObject: function( obj ) {\n    // Must be an Object.\n    // Because of IE, we also have to check the presence of the constructor property.\n    // Make sure that DOM nodes and window objects don't pass through, as well\n    if ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n      return false;\n    }\n\n    try {\n      // Not own constructor property must be Object\n      if ( obj.constructor &&\n        !hasOwn.call(obj, \"constructor\") &&\n        !hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n        return false;\n      }\n    } catch ( e ) {\n      // IE8,9 Will throw exceptions on certain host objects #9897\n      return false;\n    }\n\n    // Own properties are enumerated firstly, so to speed up,\n    // if last one is own, then all properties are own.\n\n    var key;\n    for ( key in obj ) {}\n\n    return key === undefined || hasOwn.call( obj, key );\n  },\n\n  isEmptyObject: function( obj ) {\n    for ( var name in obj ) {\n      return false;\n    }\n    return true;\n  },\n\n  error: function( msg ) {\n    throw new Error( msg );\n  },\n\n  parseJSON: function( data ) {\n    if ( typeof data !== \"string\" || !data ) {\n      return null;\n    }\n\n    // Make sure leading/trailing whitespace is removed (IE can't handle it)\n    data = jQuery.trim( data );\n\n    // Attempt to parse using the native JSON parser first\n    if ( window.JSON && window.JSON.parse ) {\n      return window.JSON.parse( data );\n    }\n\n    // Make sure the incoming data is actual JSON\n    // Logic borrowed from https://json.org/json2.js\n    if ( rvalidchars.test( data.replace( rvalidescape, \"@\" )\n      .replace( rvalidtokens, \"]\" )\n      .replace( rvalidbraces, \"\")) ) {\n\n      return ( new Function( \"return \" + data ) )();\n\n    }\n    jQuery.error( \"Invalid JSON: \" + data );\n  },\n\n  // Cross-browser xml parsing\n  parseXML: function( data ) {\n    if ( typeof data !== \"string\" || !data ) {\n      return null;\n    }\n    var xml, tmp;\n    try {\n      if ( window.DOMParser ) { // Standard\n        tmp = new DOMParser();\n        xml = tmp.parseFromString( data , \"text/xml\" );\n      } else { // IE\n        xml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n        xml.async = \"false\";\n        xml.loadXML( data );\n      }\n    } catch( e ) {\n      xml = undefined;\n    }\n    if ( !xml || !xml.documentElement || xml.getElementsByTagName( \"parsererror\" ).length ) {\n      jQuery.error( \"Invalid XML: \" + data );\n    }\n    return xml;\n  },\n\n  noop: function() {},\n\n  // Evaluates a script in a global context\n  // Workarounds based on findings by Jim Driscoll\n  // https://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context\n  globalEval: function( data ) {\n    if ( data && rnotwhite.test( data ) ) {\n      // We use execScript on Internet Explorer\n      // We use an anonymous function so that context is window\n      // rather than jQuery in Firefox\n      ( window.execScript || function( data ) {\n        window[ \"eval\" ].call( window, data );\n      } )( data );\n    }\n  },\n\n  // Convert dashed to camelCase; used by the css and data modules\n  // Microsoft forgot to hump their vendor prefix (#9572)\n  camelCase: function( string ) {\n    return string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n  },\n\n  nodeName: function( elem, name ) {\n    return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();\n  },\n\n  // args is for internal usage only\n  each: function( object, callback, args ) {\n    var name, i = 0,\n      length = object.length,\n      isObj = length === undefined || jQuery.isFunction( object );\n\n    if ( args ) {\n      if ( isObj ) {\n        for ( name in object ) {\n          if ( callback.apply( object[ name ], args ) === false ) {\n            break;\n          }\n        }\n      } else {\n        for ( ; i < length; ) {\n          if ( callback.apply( object[ i++ ], args ) === false ) {\n            break;\n          }\n        }\n      }\n\n    // A special, fast, case for the most common use of each\n    } else {\n      if ( isObj ) {\n        for ( name in object ) {\n          if ( callback.call( object[ name ], name, object[ name ] ) === false ) {\n            break;\n          }\n        }\n      } else {\n        for ( ; i < length; ) {\n          if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {\n            break;\n          }\n        }\n      }\n    }\n\n    return object;\n  },\n\n  // Use native String.trim function wherever possible\n  trim: trim ?\n    function( text ) {\n      return text == null ?\n        \"\" :\n        trim.call( text );\n    } :\n\n    // Otherwise use our own trimming functionality\n    function( text ) {\n      return text == null ?\n        \"\" :\n        text.toString().replace( trimLeft, \"\" ).replace( trimRight, \"\" );\n    },\n\n  // results is for internal usage only\n  makeArray: function( array, results ) {\n    var ret = results || [];\n\n    if ( array != null ) {\n      // The window, strings (and functions) also have 'length'\n      // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930\n      var type = jQuery.type( array );\n\n      if ( array.length == null || type === \"string\" || type === \"function\" || type === \"regexp\" || jQuery.isWindow( array ) ) {\n        push.call( ret, array );\n      } else {\n        jQuery.merge( ret, array );\n      }\n    }\n\n    return ret;\n  },\n\n  inArray: function( elem, array, i ) {\n    var len;\n\n    if ( array ) {\n      if ( indexOf ) {\n        return indexOf.call( array, elem, i );\n      }\n\n      len = array.length;\n      i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;\n\n      for ( ; i < len; i++ ) {\n        // Skip accessing in sparse arrays\n        if ( i in array && array[ i ] === elem ) {\n          return i;\n        }\n      }\n    }\n\n    return -1;\n  },\n\n  merge: function( first, second ) {\n    var i = first.length,\n      j = 0;\n\n    if ( typeof second.length === \"number\" ) {\n      for ( var l = second.length; j < l; j++ ) {\n        first[ i++ ] = second[ j ];\n      }\n\n    } else {\n      while ( second[j] !== undefined ) {\n        first[ i++ ] = second[ j++ ];\n      }\n    }\n\n    first.length = i;\n\n    return first;\n  },\n\n  grep: function( elems, callback, inv ) {\n    var ret = [], retVal;\n    inv = !!inv;\n\n    // Go through the array, only saving the items\n    // that pass the validator function\n    for ( var i = 0, length = elems.length; i < length; i++ ) {\n      retVal = !!callback( elems[ i ], i );\n      if ( inv !== retVal ) {\n        ret.push( elems[ i ] );\n      }\n    }\n\n    return ret;\n  },\n\n  // arg is for internal usage only\n  map: function( elems, callback, arg ) {\n    var value, key, ret = [],\n      i = 0,\n      length = elems.length,\n      // jquery objects are treated as arrays\n      isArray = elems instanceof jQuery || length !== undefined && typeof length === \"number\" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;\n\n    // Go through the array, translating each of the items to their\n    if ( isArray ) {\n      for ( ; i < length; i++ ) {\n        value = callback( elems[ i ], i, arg );\n\n        if ( value != null ) {\n          ret[ ret.length ] = value;\n        }\n      }\n\n    // Go through every key on the object,\n    } else {\n      for ( key in elems ) {\n        value = callback( elems[ key ], key, arg );\n\n        if ( value != null ) {\n          ret[ ret.length ] = value;\n        }\n      }\n    }\n\n    // Flatten any nested arrays\n    return ret.concat.apply( [], ret );\n  },\n\n  // A global GUID counter for objects\n  guid: 1,\n\n  // Bind a function to a context, optionally partially applying any\n  // arguments.\n  proxy: function( fn, context ) {\n    if ( typeof context === \"string\" ) {\n      var tmp = fn[ context ];\n      context = fn;\n      fn = tmp;\n    }\n\n    // Quick check to determine if target is callable, in the spec\n    // this throws a TypeError, but we will just return undefined.\n    if ( !jQuery.isFunction( fn ) ) {\n      return undefined;\n    }\n\n    // Simulated bind\n    var args = slice.call( arguments, 2 ),\n      proxy = function() {\n        return fn.apply( context, args.concat( slice.call( arguments ) ) );\n      };\n\n    // Set the guid of unique handler to the same of original handler, so it can be removed\n    proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;\n\n    return proxy;\n  },\n\n  // Mutifunctional method to get and set values to a collection\n  // The value/s can optionally be executed if it's a function\n  access: function( elems, fn, key, value, chainable, emptyGet, pass ) {\n    var exec,\n      bulk = key == null,\n      i = 0,\n      length = elems.length;\n\n    // Sets many values\n    if ( key && typeof key === \"object\" ) {\n      for ( i in key ) {\n        jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );\n      }\n      chainable = 1;\n\n    // Sets one value\n    } else if ( value !== undefined ) {\n      // Optionally, function values get executed if exec is true\n      exec = pass === undefined && jQuery.isFunction( value );\n\n      if ( bulk ) {\n        // Bulk operations only iterate when executing function values\n        if ( exec ) {\n          exec = fn;\n          fn = function( elem, key, value ) {\n            return exec.call( jQuery( elem ), value );\n          };\n\n        // Otherwise they run against the entire set\n        } else {\n          fn.call( elems, value );\n          fn = null;\n        }\n      }\n\n      if ( fn ) {\n        for (; i < length; i++ ) {\n          fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );\n        }\n      }\n\n      chainable = 1;\n    }\n\n    return chainable ?\n      elems :\n\n      // Gets\n      bulk ?\n        fn.call( elems ) :\n        length ? fn( elems[0], key ) : emptyGet;\n  },\n\n  now: function() {\n    return ( new Date() ).getTime();\n  },\n\n  // Use of jQuery.browser is frowned upon.\n  // More details: https://docs.jquery.com/Utilities/jQuery.browser\n  uaMatch: function( ua ) {\n    ua = ua.toLowerCase();\n\n    var match = rwebkit.exec( ua ) ||\n      ropera.exec( ua ) ||\n      rmsie.exec( ua ) ||\n      ua.indexOf(\"compatible\") < 0 && rmozilla.exec( ua ) ||\n      [];\n\n    return { browser: match[1] || \"\", version: match[2] || \"0\" };\n  },\n\n  sub: function() {\n    function jQuerySub( selector, context ) {\n      return new jQuerySub.fn.init( selector, context );\n    }\n    jQuery.extend( true, jQuerySub, this );\n    jQuerySub.superclass = this;\n    jQuerySub.fn = jQuerySub.prototype = this();\n    jQuerySub.fn.constructor = jQuerySub;\n    jQuerySub.sub = this.sub;\n    jQuerySub.fn.init = function init( selector, context ) {\n      if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {\n        context = jQuerySub( context );\n      }\n\n      return jQuery.fn.init.call( this, selector, context, rootjQuerySub );\n    };\n    jQuerySub.fn.init.prototype = jQuerySub.fn;\n    var rootjQuerySub = jQuerySub(document);\n    return jQuerySub;\n  },\n\n  browser: {}\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"), function(i, name) {\n  class2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nbrowserMatch = jQuery.uaMatch( userAgent );\nif ( browserMatch.browser ) {\n  jQuery.browser[ browserMatch.browser ] = true;\n  jQuery.browser.version = browserMatch.version;\n}\n\n// Deprecated, use jQuery.browser.webkit instead\nif ( jQuery.browser.webkit ) {\n  jQuery.browser.safari = true;\n}\n\n// IE doesn't match non-breaking spaces with \\s\nif ( rnotwhite.test( \"\\xA0\" ) ) {\n  trimLeft = /^[\\s\\xA0]+/;\n  trimRight = /[\\s\\xA0]+$/;\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\n\n// Cleanup functions for the document ready method\nif ( document.addEventListener ) {\n  DOMContentLoaded = function() {\n    document.removeEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n    jQuery.ready();\n  };\n\n} else if ( document.attachEvent ) {\n  DOMContentLoaded = function() {\n    // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n    if ( document.readyState === \"complete\" ) {\n      document.detachEvent( \"onreadystatechange\", DOMContentLoaded );\n      jQuery.ready();\n    }\n  };\n}\n\n// The DOM ready check for Internet Explorer\nfunction doScrollCheck() {\n  if ( jQuery.isReady ) {\n    return;\n  }\n\n  try {\n    // If IE is used, use the trick by Diego Perini\n    // http://javascript.nwbox.com/IEContentLoaded/\n    document.documentElement.doScroll(\"left\");\n  } catch(e) {\n    setTimeout( doScrollCheck, 1 );\n    return;\n  }\n\n  // and execute any waiting functions\n  jQuery.ready();\n}\n\nreturn jQuery;\n\n})();\n\n\n// String to Object flags format cache\nvar flagsCache = {};\n\n// Convert String-formatted flags into Object-formatted ones and store in cache\nfunction createFlags( flags ) {\n  var object = flagsCache[ flags ] = {},\n    i, length;\n  flags = flags.split( /\\s+/ );\n  for ( i = 0, length = flags.length; i < length; i++ ) {\n    object[ flags[i] ] = true;\n  }\n  return object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\tflags:\tan optional list of space-separated flags that will change how\n *\t\t\tthe callback list behaves\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible flags:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( flags ) {\n\n  // Convert flags from String-formatted to Object-formatted\n  // (we check in cache first)\n  flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};\n\n  var // Actual callback list\n    list = [],\n    // Stack of fire calls for repeatable lists\n    stack = [],\n    // Last fire value (for non-forgettable lists)\n    memory,\n    // Flag to know if list was already fired\n    fired,\n    // Flag to know if list is currently firing\n    firing,\n    // First callback to fire (used internally by add and fireWith)\n    firingStart,\n    // End of the loop when firing\n    firingLength,\n    // Index of currently firing callback (modified by remove if needed)\n    firingIndex,\n    // Add one or several callbacks to the list\n    add = function( args ) {\n      var i,\n        length,\n        elem,\n        type,\n        actual;\n      for ( i = 0, length = args.length; i < length; i++ ) {\n        elem = args[ i ];\n        type = jQuery.type( elem );\n        if ( type === \"array\" ) {\n          // Inspect recursively\n          add( elem );\n        } else if ( type === \"function\" ) {\n          // Add if not in unique mode and callback is not in\n          if ( !flags.unique || !self.has( elem ) ) {\n            list.push( elem );\n          }\n        }\n      }\n    },\n    // Fire callbacks\n    fire = function( context, args ) {\n      args = args || [];\n      memory = !flags.memory || [ context, args ];\n      fired = true;\n      firing = true;\n      firingIndex = firingStart || 0;\n      firingStart = 0;\n      firingLength = list.length;\n      for ( ; list && firingIndex < firingLength; firingIndex++ ) {\n        if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {\n          memory = true; // Mark as halted\n          break;\n        }\n      }\n      firing = false;\n      if ( list ) {\n        if ( !flags.once ) {\n          if ( stack && stack.length ) {\n            memory = stack.shift();\n            self.fireWith( memory[ 0 ], memory[ 1 ] );\n          }\n        } else if ( memory === true ) {\n          self.disable();\n        } else {\n          list = [];\n        }\n      }\n    },\n    // Actual Callbacks object\n    self = {\n      // Add a callback or a collection of callbacks to the list\n      add: function() {\n        if ( list ) {\n          var length = list.length;\n          add( arguments );\n          // Do we need to add the callbacks to the\n          // current firing batch?\n          if ( firing ) {\n            firingLength = list.length;\n          // With memory, if we're not firing then\n          // we should call right away, unless previous\n          // firing was halted (stopOnFalse)\n          } else if ( memory && memory !== true ) {\n            firingStart = length;\n            fire( memory[ 0 ], memory[ 1 ] );\n          }\n        }\n        return this;\n      },\n      // Remove a callback from the list\n      remove: function() {\n        if ( list ) {\n          var args = arguments,\n            argIndex = 0,\n            argLength = args.length;\n          for ( ; argIndex < argLength ; argIndex++ ) {\n            for ( var i = 0; i < list.length; i++ ) {\n              if ( args[ argIndex ] === list[ i ] ) {\n                // Handle firingIndex and firingLength\n                if ( firing ) {\n                  if ( i <= firingLength ) {\n                    firingLength--;\n                    if ( i <= firingIndex ) {\n                      firingIndex--;\n                    }\n                  }\n                }\n                // Remove the element\n                list.splice( i--, 1 );\n                // If we have some unicity property then\n                // we only need to do this once\n                if ( flags.unique ) {\n                  break;\n                }\n              }\n            }\n          }\n        }\n        return this;\n      },\n      // Control if a given callback is in the list\n      has: function( fn ) {\n        if ( list ) {\n          var i = 0,\n            length = list.length;\n          for ( ; i < length; i++ ) {\n            if ( fn === list[ i ] ) {\n              return true;\n            }\n          }\n        }\n        return false;\n      },\n      // Remove all callbacks from the list\n      empty: function() {\n        list = [];\n        return this;\n      },\n      // Have the list do nothing anymore\n      disable: function() {\n        list = stack = memory = undefined;\n        return this;\n      },\n      // Is it disabled?\n      disabled: function() {\n        return !list;\n      },\n      // Lock the list in its current state\n      lock: function() {\n        stack = undefined;\n        if ( !memory || memory === true ) {\n          self.disable();\n        }\n        return this;\n      },\n      // Is it locked?\n      locked: function() {\n        return !stack;\n      },\n      // Call all callbacks with the given context and arguments\n      fireWith: function( context, args ) {\n        if ( stack ) {\n          if ( firing ) {\n            if ( !flags.once ) {\n              stack.push( [ context, args ] );\n            }\n          } else if ( !( flags.once && memory ) ) {\n            fire( context, args );\n          }\n        }\n        return this;\n      },\n      // Call all the callbacks with the given arguments\n      fire: function() {\n        self.fireWith( this, arguments );\n        return this;\n      },\n      // To know if the callbacks have already been called at least once\n      fired: function() {\n        return !!fired;\n      }\n    };\n\n  return self;\n};\n\n\n\n\nvar // Static reference to slice\n  sliceDeferred = [].slice;\n\njQuery.extend({\n\n  Deferred: function( func ) {\n    var doneList = jQuery.Callbacks( \"once memory\" ),\n      failList = jQuery.Callbacks( \"once memory\" ),\n      progressList = jQuery.Callbacks( \"memory\" ),\n      state = \"pending\",\n      lists = {\n        resolve: doneList,\n        reject: failList,\n        notify: progressList\n      },\n      promise = {\n        done: doneList.add,\n        fail: failList.add,\n        progress: progressList.add,\n\n        state: function() {\n          return state;\n        },\n\n        // Deprecated\n        isResolved: doneList.fired,\n        isRejected: failList.fired,\n\n        then: function( doneCallbacks, failCallbacks, progressCallbacks ) {\n          deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );\n          return this;\n        },\n        always: function() {\n          deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );\n          return this;\n        },\n        pipe: function( fnDone, fnFail, fnProgress ) {\n          return jQuery.Deferred(function( newDefer ) {\n            jQuery.each( {\n              done: [ fnDone, \"resolve\" ],\n              fail: [ fnFail, \"reject\" ],\n              progress: [ fnProgress, \"notify\" ]\n            }, function( handler, data ) {\n              var fn = data[ 0 ],\n                action = data[ 1 ],\n                returned;\n              if ( jQuery.isFunction( fn ) ) {\n                deferred[ handler ](function() {\n                  returned = fn.apply( this, arguments );\n                  if ( returned && jQuery.isFunction( returned.promise ) ) {\n                    returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );\n                  } else {\n                    newDefer[ action + \"With\" ]( this === deferred ? newDefer : this, [ returned ] );\n                  }\n                });\n              } else {\n                deferred[ handler ]( newDefer[ action ] );\n              }\n            });\n          }).promise();\n        },\n        // Get a promise for this deferred\n        // If obj is provided, the promise aspect is added to the object\n        promise: function( obj ) {\n          if ( obj == null ) {\n            obj = promise;\n          } else {\n            for ( var key in promise ) {\n              obj[ key ] = promise[ key ];\n            }\n          }\n          return obj;\n        }\n      },\n      deferred = promise.promise({}),\n      key;\n\n    for ( key in lists ) {\n      deferred[ key ] = lists[ key ].fire;\n      deferred[ key + \"With\" ] = lists[ key ].fireWith;\n    }\n\n    // Handle state\n    deferred.done( function() {\n      state = \"resolved\";\n    }, failList.disable, progressList.lock ).fail( function() {\n      state = \"rejected\";\n    }, doneList.disable, progressList.lock );\n\n    // Call given func if any\n    if ( func ) {\n      func.call( deferred, deferred );\n    }\n\n    // All done!\n    return deferred;\n  },\n\n  // Deferred helper\n  when: function( firstParam ) {\n    var args = sliceDeferred.call( arguments, 0 ),\n      i = 0,\n      length = args.length,\n      pValues = new Array( length ),\n      count = length,\n      pCount = length,\n      deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?\n        firstParam :\n        jQuery.Deferred(),\n      promise = deferred.promise();\n    function resolveFunc( i ) {\n      return function( value ) {\n        args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;\n        if ( !( --count ) ) {\n          deferred.resolveWith( deferred, args );\n        }\n      };\n    }\n    function progressFunc( i ) {\n      return function( value ) {\n        pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;\n        deferred.notifyWith( promise, pValues );\n      };\n    }\n    if ( length > 1 ) {\n      for ( ; i < length; i++ ) {\n        if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {\n          args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );\n        } else {\n          --count;\n        }\n      }\n      if ( !count ) {\n        deferred.resolveWith( deferred, args );\n      }\n    } else if ( deferred !== firstParam ) {\n      deferred.resolveWith( deferred, length ? [ firstParam ] : [] );\n    }\n    return promise;\n  }\n});\n\n\n\n\njQuery.support = (function() {\n\n  var support,\n    all,\n    a,\n    select,\n    opt,\n    input,\n    fragment,\n    tds,\n    events,\n    eventName,\n    i,\n    isSupported,\n    div = document.createElement( \"div\" ),\n    documentElement = document.documentElement;\n\n  // Preliminary tests\n  div.setAttribute(\"className\", \"t\");\n  div.innerHTML = \"   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";\n\n  all = div.getElementsByTagName( \"*\" );\n  a = div.getElementsByTagName( \"a\" )[ 0 ];\n\n  // Can't get basic test support\n  if ( !all || !all.length || !a ) {\n    return {};\n  }\n\n  // First batch of supports tests\n  select = document.createElement( \"select\" );\n  opt = select.appendChild( document.createElement(\"option\") );\n  input = div.getElementsByTagName( \"input\" )[ 0 ];\n\n  support = {\n    // IE strips leading whitespace when .innerHTML is used\n    leadingWhitespace: ( div.firstChild.nodeType === 3 ),\n\n    // Make sure that tbody elements aren't automatically inserted\n    // IE will insert them into empty tables\n    tbody: !div.getElementsByTagName(\"tbody\").length,\n\n    // Make sure that link elements get serialized correctly by innerHTML\n    // This requires a wrapper element in IE\n    htmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n    // Get the style information from getAttribute\n    // (IE uses .cssText instead)\n    style: /top/.test( a.getAttribute(\"style\") ),\n\n    // Make sure that URLs aren't manipulated\n    // (IE normalizes it by default)\n    hrefNormalized: ( a.getAttribute(\"href\") === \"/a\" ),\n\n    // Make sure that element opacity exists\n    // (IE uses filter instead)\n    // Use a regex to work around a WebKit issue. See #5145\n    opacity: /^0.55/.test( a.style.opacity ),\n\n    // Verify style float existence\n    // (IE uses styleFloat instead of cssFloat)\n    cssFloat: !!a.style.cssFloat,\n\n    // Make sure that if no value is specified for a checkbox\n    // that it defaults to \"on\".\n    // (WebKit defaults to \"\" instead)\n    checkOn: ( input.value === \"on\" ),\n\n    // Make sure that a selected-by-default option has a working selected property.\n    // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n    optSelected: opt.selected,\n\n    // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n    getSetAttribute: div.className !== \"t\",\n\n    // Tests for enctype support on a form(#6743)\n    enctype: !!document.createElement(\"form\").enctype,\n\n    // Makes sure cloning an html5 element does not cause problems\n    // Where outerHTML is undefined, this still works\n    html5Clone: document.createElement(\"nav\").cloneNode( true ).outerHTML !== \"<:nav></:nav>\",\n\n    // Will be defined later\n    submitBubbles: true,\n    changeBubbles: true,\n    focusinBubbles: false,\n    deleteExpando: true,\n    noCloneEvent: true,\n    inlineBlockNeedsLayout: false,\n    shrinkWrapBlocks: false,\n    reliableMarginRight: true,\n    pixelMargin: true\n  };\n\n  // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead\n  jQuery.boxModel = support.boxModel = (document.compatMode === \"CSS1Compat\");\n\n  // Make sure checked status is properly cloned\n  input.checked = true;\n  support.noCloneChecked = input.cloneNode( true ).checked;\n\n  // Make sure that the options inside disabled selects aren't marked as disabled\n  // (WebKit marks them as disabled)\n  select.disabled = true;\n  support.optDisabled = !opt.disabled;\n\n  // Test to see if it's possible to delete an expando from an element\n  // Fails in Internet Explorer\n  try {\n    delete div.test;\n  } catch( e ) {\n    support.deleteExpando = false;\n  }\n\n  if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {\n    div.attachEvent( \"onclick\", function() {\n      // Cloning a node shouldn't copy over any\n      // bound event handlers (IE does this)\n      support.noCloneEvent = false;\n    });\n    div.cloneNode( true ).fireEvent( \"onclick\" );\n  }\n\n  // Check if a radio maintains its value\n  // after being appended to the DOM\n  input = document.createElement(\"input\");\n  input.value = \"t\";\n  input.setAttribute(\"type\", \"radio\");\n  support.radioValue = input.value === \"t\";\n\n  input.setAttribute(\"checked\", \"checked\");\n\n  // #11217 - WebKit loses check when the name is after the checked attribute\n  input.setAttribute( \"name\", \"t\" );\n\n  div.appendChild( input );\n  fragment = document.createDocumentFragment();\n  fragment.appendChild( div.lastChild );\n\n  // WebKit doesn't clone checked state correctly in fragments\n  support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n  // Check if a disconnected checkbox will retain its checked\n  // value of true after appended to the DOM (IE6/7)\n  support.appendChecked = input.checked;\n\n  fragment.removeChild( input );\n  fragment.appendChild( div );\n\n  // Technique from Juriy Zaytsev\n  // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/\n  // We only care about the case where non-standard event systems\n  // are used, namely in IE. Short-circuiting here helps us to\n  // avoid an eval call (in setAttribute) which can cause CSP\n  // to go haywire. See: https://developer.mozilla.org/en/Security/CSP\n  if ( div.attachEvent ) {\n    for ( i in {\n      submit: 1,\n      change: 1,\n      focusin: 1\n    }) {\n      eventName = \"on\" + i;\n      isSupported = ( eventName in div );\n      if ( !isSupported ) {\n        div.setAttribute( eventName, \"return;\" );\n        isSupported = ( typeof div[ eventName ] === \"function\" );\n      }\n      support[ i + \"Bubbles\" ] = isSupported;\n    }\n  }\n\n  fragment.removeChild( div );\n\n  // Null elements to avoid leaks in IE\n  fragment = select = opt = div = input = null;\n\n  // Run tests that need a body at doc ready\n  jQuery(function() {\n    var container, outer, inner, table, td, offsetSupport,\n      marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,\n      paddingMarginBorderVisibility, paddingMarginBorder,\n      body = document.getElementsByTagName(\"body\")[0];\n\n    if ( !body ) {\n      // Return for frameset docs that don't have a body\n      return;\n    }\n\n    conMarginTop = 1;\n    paddingMarginBorder = \"padding:0;margin:0;border:\";\n    positionTopLeftWidthHeight = \"position:absolute;top:0;left:0;width:1px;height:1px;\";\n    paddingMarginBorderVisibility = paddingMarginBorder + \"0;visibility:hidden;\";\n    style = \"style='\" + positionTopLeftWidthHeight + paddingMarginBorder + \"5px solid #000;\";\n    html = \"<div \" + style + \"display:block;'><div style='\" + paddingMarginBorder + \"0;display:block;overflow:hidden;'></div></div>\" +\n      \"<table \" + style + \"' cellpadding='0' cellspacing='0'>\" +\n      \"<tr><td></td></tr></table>\";\n\n    container = document.createElement(\"div\");\n    container.style.cssText = paddingMarginBorderVisibility + \"width:0;height:0;position:static;top:0;margin-top:\" + conMarginTop + \"px\";\n    body.insertBefore( container, body.firstChild );\n\n    // Construct the test element\n    div = document.createElement(\"div\");\n    container.appendChild( div );\n\n    // Check if table cells still have offsetWidth/Height when they are set\n    // to display:none and there are still other visible table cells in a\n    // table row; if so, offsetWidth/Height are not reliable for use when\n    // determining if an element has been hidden directly using\n    // display:none (it is still safe to use offsets if a parent element is\n    // hidden; don safety goggles and see bug #4512 for more information).\n    // (only IE 8 fails this test)\n    div.innerHTML = \"<table><tr><td style='\" + paddingMarginBorder + \"0;display:none'></td><td>t</td></tr></table>\";\n    tds = div.getElementsByTagName( \"td\" );\n    isSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n    tds[ 0 ].style.display = \"\";\n    tds[ 1 ].style.display = \"none\";\n\n    // Check if empty table cells still have offsetWidth/Height\n    // (IE <= 8 fail this test)\n    support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\n    // Check if div with explicit width and no margin-right incorrectly\n    // gets computed margin-right based on width of container. For more\n    // info see bug #3333\n    // Fails in WebKit before Feb 2011 nightlies\n    // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n    if ( window.getComputedStyle ) {\n      div.innerHTML = \"\";\n      marginDiv = document.createElement( \"div\" );\n      marginDiv.style.width = \"0\";\n      marginDiv.style.marginRight = \"0\";\n      div.style.width = \"2px\";\n      div.appendChild( marginDiv );\n      support.reliableMarginRight =\n        ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;\n    }\n\n    if ( typeof div.style.zoom !== \"undefined\" ) {\n      // Check if natively block-level elements act like inline-block\n      // elements when setting their display to 'inline' and giving\n      // them layout\n      // (IE < 8 does this)\n      div.innerHTML = \"\";\n      div.style.width = div.style.padding = \"1px\";\n      div.style.border = 0;\n      div.style.overflow = \"hidden\";\n      div.style.display = \"inline\";\n      div.style.zoom = 1;\n      support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );\n\n      // Check if elements with layout shrink-wrap their children\n      // (IE 6 does this)\n      div.style.display = \"block\";\n      div.style.overflow = \"visible\";\n      div.innerHTML = \"<div style='width:5px;'></div>\";\n      support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );\n    }\n\n    div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;\n    div.innerHTML = html;\n\n    outer = div.firstChild;\n    inner = outer.firstChild;\n    td = outer.nextSibling.firstChild.firstChild;\n\n    offsetSupport = {\n      doesNotAddBorder: ( inner.offsetTop !== 5 ),\n      doesAddBorderForTableAndCells: ( td.offsetTop === 5 )\n    };\n\n    inner.style.position = \"fixed\";\n    inner.style.top = \"20px\";\n\n    // safari subtracts parent border width here which is 5px\n    offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );\n    inner.style.position = inner.style.top = \"\";\n\n    outer.style.overflow = \"hidden\";\n    outer.style.position = \"relative\";\n\n    offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );\n    offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );\n\n    if ( window.getComputedStyle ) {\n      div.style.marginTop = \"1%\";\n      support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== \"1%\";\n    }\n\n    if ( typeof container.style.zoom !== \"undefined\" ) {\n      container.style.zoom = 1;\n    }\n\n    body.removeChild( container );\n    marginDiv = div = container = null;\n\n    jQuery.extend( support, offsetSupport );\n  });\n\n  return support;\n})();\n\n\n\n\nvar rbrace = /^(?:\\{.*\\}|\\[.*\\])$/,\n  rmultiDash = /([A-Z])/g;\n\njQuery.extend({\n  cache: {},\n\n  // Please use with caution\n  uuid: 0,\n\n  // Unique for each copy of jQuery on the page\n  // Non-digits removed to match rinlinejQuery\n  expando: \"jQuery\" + ( jQuery.fn.jquery + Math.random() ).replace( /\\D/g, \"\" ),\n\n  // The following elements throw uncatchable exceptions if you\n  // attempt to add expando properties to them.\n  noData: {\n    \"embed\": true,\n    // Ban all objects except for Flash (which handle expandos)\n    \"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n    \"applet\": true\n  },\n\n  hasData: function( elem ) {\n    elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n    return !!elem && !isEmptyDataObject( elem );\n  },\n\n  data: function( elem, name, data, pvt /* Internal Use Only */ ) {\n    if ( !jQuery.acceptData( elem ) ) {\n      return;\n    }\n\n    var privateCache, thisCache, ret,\n      internalKey = jQuery.expando,\n      getByName = typeof name === \"string\",\n\n      // We have to handle DOM nodes and JS objects differently because IE6-7\n      // can't GC object references properly across the DOM-JS boundary\n      isNode = elem.nodeType,\n\n      // Only DOM nodes need the global jQuery cache; JS object data is\n      // attached directly to the object so GC can occur automatically\n      cache = isNode ? jQuery.cache : elem,\n\n      // Only defining an ID for JS objects if its cache already exists allows\n      // the code to shortcut on the same path as a DOM node with no cache\n      id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,\n      isEvents = name === \"events\";\n\n    // Avoid doing any more work than we need to when trying to get data on an\n    // object that has no data at all\n    if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {\n      return;\n    }\n\n    if ( !id ) {\n      // Only DOM nodes need a new unique ID for each element since their data\n      // ends up in the global cache\n      if ( isNode ) {\n        elem[ internalKey ] = id = ++jQuery.uuid;\n      } else {\n        id = internalKey;\n      }\n    }\n\n    if ( !cache[ id ] ) {\n      cache[ id ] = {};\n\n      // Avoids exposing jQuery metadata on plain JS objects when the object\n      // is serialized using JSON.stringify\n      if ( !isNode ) {\n        cache[ id ].toJSON = jQuery.noop;\n      }\n    }\n\n    // An object can be passed to jQuery.data instead of a key/value pair; this gets\n    // shallow copied over onto the existing cache\n    if ( typeof name === \"object\" || typeof name === \"function\" ) {\n      if ( pvt ) {\n        cache[ id ] = jQuery.extend( cache[ id ], name );\n      } else {\n        cache[ id ].data = jQuery.extend( cache[ id ].data, name );\n      }\n    }\n\n    privateCache = thisCache = cache[ id ];\n\n    // jQuery data() is stored in a separate object inside the object's internal data\n    // cache in order to avoid key collisions between internal data and user-defined\n    // data.\n    if ( !pvt ) {\n      if ( !thisCache.data ) {\n        thisCache.data = {};\n      }\n\n      thisCache = thisCache.data;\n    }\n\n    if ( data !== undefined ) {\n      thisCache[ jQuery.camelCase( name ) ] = data;\n    }\n\n    // Users should not attempt to inspect the internal events object using jQuery.data,\n    // it is undocumented and subject to change. But does anyone listen? No.\n    if ( isEvents && !thisCache[ name ] ) {\n      return privateCache.events;\n    }\n\n    // Check for both converted-to-camel and non-converted data property names\n    // If a data property was specified\n    if ( getByName ) {\n\n      // First Try to find as-is property data\n      ret = thisCache[ name ];\n\n      // Test for null|undefined property data\n      if ( ret == null ) {\n\n        // Try to find the camelCased property\n        ret = thisCache[ jQuery.camelCase( name ) ];\n      }\n    } else {\n      ret = thisCache;\n    }\n\n    return ret;\n  },\n\n  removeData: function( elem, name, pvt /* Internal Use Only */ ) {\n    if ( !jQuery.acceptData( elem ) ) {\n      return;\n    }\n\n    var thisCache, i, l,\n\n      // Reference to internal data cache key\n      internalKey = jQuery.expando,\n\n      isNode = elem.nodeType,\n\n      // See jQuery.data for more information\n      cache = isNode ? jQuery.cache : elem,\n\n      // See jQuery.data for more information\n      id = isNode ? elem[ internalKey ] : internalKey;\n\n    // If there is already no cache entry for this object, there is no\n    // purpose in continuing\n    if ( !cache[ id ] ) {\n      return;\n    }\n\n    if ( name ) {\n\n      thisCache = pvt ? cache[ id ] : cache[ id ].data;\n\n      if ( thisCache ) {\n\n        // Support array or space separated string names for data keys\n        if ( !jQuery.isArray( name ) ) {\n\n          // try the string as a key before any manipulation\n          if ( name in thisCache ) {\n            name = [ name ];\n          } else {\n\n            // split the camel cased version by spaces unless a key with the spaces exists\n            name = jQuery.camelCase( name );\n            if ( name in thisCache ) {\n              name = [ name ];\n            } else {\n              name = name.split( \" \" );\n            }\n          }\n        }\n\n        for ( i = 0, l = name.length; i < l; i++ ) {\n          delete thisCache[ name[i] ];\n        }\n\n        // If there is no data left in the cache, we want to continue\n        // and let the cache object itself get destroyed\n        if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {\n          return;\n        }\n      }\n    }\n\n    // See jQuery.data for more information\n    if ( !pvt ) {\n      delete cache[ id ].data;\n\n      // Don't destroy the parent cache unless the internal data object\n      // had been the only thing left in it\n      if ( !isEmptyDataObject(cache[ id ]) ) {\n        return;\n      }\n    }\n\n    // Browsers that fail expando deletion also refuse to delete expandos on\n    // the window, but it will allow it on all other JS objects; other browsers\n    // don't care\n    // Ensure that `cache` is not a window object #10080\n    if ( jQuery.support.deleteExpando || !cache.setInterval ) {\n      delete cache[ id ];\n    } else {\n      cache[ id ] = null;\n    }\n\n    // We destroyed the cache and need to eliminate the expando on the node to avoid\n    // false lookups in the cache for entries that no longer exist\n    if ( isNode ) {\n      // IE does not allow us to delete expando properties from nodes,\n      // nor does it have a removeAttribute function on Document nodes;\n      // we must handle all of these cases\n      if ( jQuery.support.deleteExpando ) {\n        delete elem[ internalKey ];\n      } else if ( elem.removeAttribute ) {\n        elem.removeAttribute( internalKey );\n      } else {\n        elem[ internalKey ] = null;\n      }\n    }\n  },\n\n  // For internal use only.\n  _data: function( elem, name, data ) {\n    return jQuery.data( elem, name, data, true );\n  },\n\n  // A method for determining if a DOM node can handle the data expando\n  acceptData: function( elem ) {\n    if ( elem.nodeName ) {\n      var match = jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n      if ( match ) {\n        return !(match === true || elem.getAttribute(\"classid\") !== match);\n      }\n    }\n\n    return true;\n  }\n});\n\njQuery.fn.extend({\n  data: function( key, value ) {\n    var parts, part, attr, name, l,\n      elem = this[0],\n      i = 0,\n      data = null;\n\n    // Gets all values\n    if ( key === undefined ) {\n      if ( this.length ) {\n        data = jQuery.data( elem );\n\n        if ( elem.nodeType === 1 && !jQuery._data( elem, \"parsedAttrs\" ) ) {\n          attr = elem.attributes;\n          for ( l = attr.length; i < l; i++ ) {\n            name = attr[i].name;\n\n            if ( name.indexOf( \"data-\" ) === 0 ) {\n              name = jQuery.camelCase( name.substring(5) );\n\n              dataAttr( elem, name, data[ name ] );\n            }\n          }\n          jQuery._data( elem, \"parsedAttrs\", true );\n        }\n      }\n\n      return data;\n    }\n\n    // Sets multiple values\n    if ( typeof key === \"object\" ) {\n      return this.each(function() {\n        jQuery.data( this, key );\n      });\n    }\n\n    parts = key.split( \".\", 2 );\n    parts[1] = parts[1] ? \".\" + parts[1] : \"\";\n    part = parts[1] + \"!\";\n\n    return jQuery.access( this, function( value ) {\n\n      if ( value === undefined ) {\n        data = this.triggerHandler( \"getData\" + part, [ parts[0] ] );\n\n        // Try to fetch any internally stored data first\n        if ( data === undefined && elem ) {\n          data = jQuery.data( elem, key );\n          data = dataAttr( elem, key, data );\n        }\n\n        return data === undefined && parts[1] ?\n          this.data( parts[0] ) :\n          data;\n      }\n\n      parts[1] = value;\n      this.each(function() {\n        var self = jQuery( this );\n\n        self.triggerHandler( \"setData\" + part, parts );\n        jQuery.data( this, key, value );\n        self.triggerHandler( \"changeData\" + part, parts );\n      });\n    }, null, value, arguments.length > 1, null, false );\n  },\n\n  removeData: function( key ) {\n    return this.each(function() {\n      jQuery.removeData( this, key );\n    });\n  }\n});\n\nfunction dataAttr( elem, key, data ) {\n  // If nothing was found internally, try to fetch any\n  // data from the HTML5 data-* attribute\n  if ( data === undefined && elem.nodeType === 1 ) {\n\n    var name = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\n    data = elem.getAttribute( name );\n\n    if ( typeof data === \"string\" ) {\n      try {\n        data = data === \"true\" ? true :\n        data === \"false\" ? false :\n        data === \"null\" ? null :\n        jQuery.isNumeric( data ) ? +data :\n          rbrace.test( data ) ? jQuery.parseJSON( data ) :\n          data;\n      } catch( e ) {}\n\n      // Make sure we set the data so it isn't changed later\n      jQuery.data( elem, key, data );\n\n    } else {\n      data = undefined;\n    }\n  }\n\n  return data;\n}\n\n// checks a cache object for emptiness\nfunction isEmptyDataObject( obj ) {\n  for ( var name in obj ) {\n\n    // if the public data object is empty, the private is still empty\n    if ( name === \"data\" && jQuery.isEmptyObject( obj[name] ) ) {\n      continue;\n    }\n    if ( name !== \"toJSON\" ) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\n\n\n\nfunction handleQueueMarkDefer( elem, type, src ) {\n  var deferDataKey = type + \"defer\",\n    queueDataKey = type + \"queue\",\n    markDataKey = type + \"mark\",\n    defer = jQuery._data( elem, deferDataKey );\n  if ( defer &&\n    ( src === \"queue\" || !jQuery._data(elem, queueDataKey) ) &&\n    ( src === \"mark\" || !jQuery._data(elem, markDataKey) ) ) {\n    // Give room for hard-coded callbacks to fire first\n    // and eventually mark/queue something else on the element\n    setTimeout( function() {\n      if ( !jQuery._data( elem, queueDataKey ) &&\n        !jQuery._data( elem, markDataKey ) ) {\n        jQuery.removeData( elem, deferDataKey, true );\n        defer.fire();\n      }\n    }, 0 );\n  }\n}\n\njQuery.extend({\n\n  _mark: function( elem, type ) {\n    if ( elem ) {\n      type = ( type || \"fx\" ) + \"mark\";\n      jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );\n    }\n  },\n\n  _unmark: function( force, elem, type ) {\n    if ( force !== true ) {\n      type = elem;\n      elem = force;\n      force = false;\n    }\n    if ( elem ) {\n      type = type || \"fx\";\n      var key = type + \"mark\",\n        count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );\n      if ( count ) {\n        jQuery._data( elem, key, count );\n      } else {\n        jQuery.removeData( elem, key, true );\n        handleQueueMarkDefer( elem, type, \"mark\" );\n      }\n    }\n  },\n\n  queue: function( elem, type, data ) {\n    var q;\n    if ( elem ) {\n      type = ( type || \"fx\" ) + \"queue\";\n      q = jQuery._data( elem, type );\n\n      // Speed up dequeue by getting out quickly if this is just a lookup\n      if ( data ) {\n        if ( !q || jQuery.isArray(data) ) {\n          q = jQuery._data( elem, type, jQuery.makeArray(data) );\n        } else {\n          q.push( data );\n        }\n      }\n      return q || [];\n    }\n  },\n\n  dequeue: function( elem, type ) {\n    type = type || \"fx\";\n\n    var queue = jQuery.queue( elem, type ),\n      fn = queue.shift(),\n      hooks = {};\n\n    // If the fx queue is dequeued, always remove the progress sentinel\n    if ( fn === \"inprogress\" ) {\n      fn = queue.shift();\n    }\n\n    if ( fn ) {\n      // Add a progress sentinel to prevent the fx queue from being\n      // automatically dequeued\n      if ( type === \"fx\" ) {\n        queue.unshift( \"inprogress\" );\n      }\n\n      jQuery._data( elem, type + \".run\", hooks );\n      fn.call( elem, function() {\n        jQuery.dequeue( elem, type );\n      }, hooks );\n    }\n\n    if ( !queue.length ) {\n      jQuery.removeData( elem, type + \"queue \" + type + \".run\", true );\n      handleQueueMarkDefer( elem, type, \"queue\" );\n    }\n  }\n});\n\njQuery.fn.extend({\n  queue: function( type, data ) {\n    var setter = 2;\n\n    if ( typeof type !== \"string\" ) {\n      data = type;\n      type = \"fx\";\n      setter--;\n    }\n\n    if ( arguments.length < setter ) {\n      return jQuery.queue( this[0], type );\n    }\n\n    return data === undefined ?\n      this :\n      this.each(function() {\n        var queue = jQuery.queue( this, type, data );\n\n        if ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n          jQuery.dequeue( this, type );\n        }\n      });\n  },\n  dequeue: function( type ) {\n    return this.each(function() {\n      jQuery.dequeue( this, type );\n    });\n  },\n  // Based off of the plugin by Clint Helfers, with permission.\n  // http://blindsignals.com\n  delay: function( time, type ) {\n    time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n    type = type || \"fx\";\n\n    return this.queue( type, function( next, hooks ) {\n      var timeout = setTimeout( next, time );\n      hooks.stop = function() {\n        clearTimeout( timeout );\n      };\n    });\n  },\n  clearQueue: function( type ) {\n    return this.queue( type || \"fx\", [] );\n  },\n  // Get a promise resolved when queues of a certain type\n  // are emptied (fx is the type by default)\n  promise: function( type, object ) {\n    if ( typeof type !== \"string\" ) {\n      object = type;\n      type = undefined;\n    }\n    type = type || \"fx\";\n    var defer = jQuery.Deferred(),\n      elements = this,\n      i = elements.length,\n      count = 1,\n      deferDataKey = type + \"defer\",\n      queueDataKey = type + \"queue\",\n      markDataKey = type + \"mark\",\n      tmp;\n    function resolve() {\n      if ( !( --count ) ) {\n        defer.resolveWith( elements, [ elements ] );\n      }\n    }\n    while( i-- ) {\n      if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||\n          ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||\n            jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&\n          jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( \"once memory\" ), true ) )) {\n        count++;\n        tmp.add( resolve );\n      }\n    }\n    resolve();\n    return defer.promise( object );\n  }\n});\n\n\n\n\nvar rclass = /[\\n\\t\\r]/g,\n  rspace = /\\s+/,\n  rreturn = /\\r/g,\n  rtype = /^(?:button|input)$/i,\n  rfocusable = /^(?:button|input|object|select|textarea)$/i,\n  rclickable = /^a(?:rea)?$/i,\n  rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,\n  getSetAttribute = jQuery.support.getSetAttribute,\n  nodeHook, boolHook, fixSpecified;\n\njQuery.fn.extend({\n  attr: function( name, value ) {\n    return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );\n  },\n\n  removeAttr: function( name ) {\n    return this.each(function() {\n      jQuery.removeAttr( this, name );\n    });\n  },\n\n  prop: function( name, value ) {\n    return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );\n  },\n\n  removeProp: function( name ) {\n    name = jQuery.propFix[ name ] || name;\n    return this.each(function() {\n      // try/catch handles cases where IE balks (such as removing a property on window)\n      try {\n        this[ name ] = undefined;\n        delete this[ name ];\n      } catch( e ) {}\n    });\n  },\n\n  addClass: function( value ) {\n    var classNames, i, l, elem,\n      setClass, c, cl;\n\n    if ( jQuery.isFunction( value ) ) {\n      return this.each(function( j ) {\n        jQuery( this ).addClass( value.call(this, j, this.className) );\n      });\n    }\n\n    if ( value && typeof value === \"string\" ) {\n      classNames = value.split( rspace );\n\n      for ( i = 0, l = this.length; i < l; i++ ) {\n        elem = this[ i ];\n\n        if ( elem.nodeType === 1 ) {\n          if ( !elem.className && classNames.length === 1 ) {\n            elem.className = value;\n\n          } else {\n            setClass = \" \" + elem.className + \" \";\n\n            for ( c = 0, cl = classNames.length; c < cl; c++ ) {\n              if ( !~setClass.indexOf( \" \" + classNames[ c ] + \" \" ) ) {\n                setClass += classNames[ c ] + \" \";\n              }\n            }\n            elem.className = jQuery.trim( setClass );\n          }\n        }\n      }\n    }\n\n    return this;\n  },\n\n  removeClass: function( value ) {\n    var classNames, i, l, elem, className, c, cl;\n\n    if ( jQuery.isFunction( value ) ) {\n      return this.each(function( j ) {\n        jQuery( this ).removeClass( value.call(this, j, this.className) );\n      });\n    }\n\n    if ( (value && typeof value === \"string\") || value === undefined ) {\n      classNames = ( value || \"\" ).split( rspace );\n\n      for ( i = 0, l = this.length; i < l; i++ ) {\n        elem = this[ i ];\n\n        if ( elem.nodeType === 1 && elem.className ) {\n          if ( value ) {\n            className = (\" \" + elem.className + \" \").replace( rclass, \" \" );\n            for ( c = 0, cl = classNames.length; c < cl; c++ ) {\n              className = className.replace(\" \" + classNames[ c ] + \" \", \" \");\n            }\n            elem.className = jQuery.trim( className );\n\n          } else {\n            elem.className = \"\";\n          }\n        }\n      }\n    }\n\n    return this;\n  },\n\n  toggleClass: function( value, stateVal ) {\n    var type = typeof value,\n      isBool = typeof stateVal === \"boolean\";\n\n    if ( jQuery.isFunction( value ) ) {\n      return this.each(function( i ) {\n        jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n      });\n    }\n\n    return this.each(function() {\n      if ( type === \"string\" ) {\n        // toggle individual class names\n        var className,\n          i = 0,\n          self = jQuery( this ),\n          state = stateVal,\n          classNames = value.split( rspace );\n\n        while ( (className = classNames[ i++ ]) ) {\n          // check each className given, space seperated list\n          state = isBool ? state : !self.hasClass( className );\n          self[ state ? \"addClass\" : \"removeClass\" ]( className );\n        }\n\n      } else if ( type === \"undefined\" || type === \"boolean\" ) {\n        if ( this.className ) {\n          // store className if set\n          jQuery._data( this, \"__className__\", this.className );\n        }\n\n        // toggle whole className\n        this.className = this.className || value === false ? \"\" : jQuery._data( this, \"__className__\" ) || \"\";\n      }\n    });\n  },\n\n  hasClass: function( selector ) {\n    var className = \" \" + selector + \" \",\n      i = 0,\n      l = this.length;\n    for ( ; i < l; i++ ) {\n      if ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) > -1 ) {\n        return true;\n      }\n    }\n\n    return false;\n  },\n\n  val: function( value ) {\n    var hooks, ret, isFunction,\n      elem = this[0];\n\n    if ( !arguments.length ) {\n      if ( elem ) {\n        hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n        if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n          return ret;\n        }\n\n        ret = elem.value;\n\n        return typeof ret === \"string\" ?\n          // handle most common string cases\n          ret.replace(rreturn, \"\") :\n          // handle cases where value is null/undef or number\n          ret == null ? \"\" : ret;\n      }\n\n      return;\n    }\n\n    isFunction = jQuery.isFunction( value );\n\n    return this.each(function( i ) {\n      var self = jQuery(this), val;\n\n      if ( this.nodeType !== 1 ) {\n        return;\n      }\n\n      if ( isFunction ) {\n        val = value.call( this, i, self.val() );\n      } else {\n        val = value;\n      }\n\n      // Treat null/undefined as \"\"; convert numbers to string\n      if ( val == null ) {\n        val = \"\";\n      } else if ( typeof val === \"number\" ) {\n        val += \"\";\n      } else if ( jQuery.isArray( val ) ) {\n        val = jQuery.map(val, function ( value ) {\n          return value == null ? \"\" : value + \"\";\n        });\n      }\n\n      hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n      // If set returns undefined, fall back to normal setting\n      if ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n        this.value = val;\n      }\n    });\n  }\n});\n\njQuery.extend({\n  valHooks: {\n    option: {\n      get: function( elem ) {\n        // attributes.value is undefined in Blackberry 4.7 but\n        // uses .value. See #6932\n        var val = elem.attributes.value;\n        return !val || val.specified ? elem.value : elem.text;\n      }\n    },\n    select: {\n      get: function( elem ) {\n        var value, i, max, option,\n          index = elem.selectedIndex,\n          values = [],\n          options = elem.options,\n          one = elem.type === \"select-one\";\n\n        // Nothing was selected\n        if ( index < 0 ) {\n          return null;\n        }\n\n        // Loop through all the selected options\n        i = one ? index : 0;\n        max = one ? index + 1 : options.length;\n        for ( ; i < max; i++ ) {\n          option = options[ i ];\n\n          // Don't return options that are disabled or in a disabled optgroup\n          if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute(\"disabled\") === null) &&\n              (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" )) ) {\n\n            // Get the specific value for the option\n            value = jQuery( option ).val();\n\n            // We don't need an array for one selects\n            if ( one ) {\n              return value;\n            }\n\n            // Multi-Selects return an array\n            values.push( value );\n          }\n        }\n\n        // Fixes Bug #2551 -- select.val() broken in IE after form.reset()\n        if ( one && !values.length && options.length ) {\n          return jQuery( options[ index ] ).val();\n        }\n\n        return values;\n      },\n\n      set: function( elem, value ) {\n        var values = jQuery.makeArray( value );\n\n        jQuery(elem).find(\"option\").each(function() {\n          this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n        });\n\n        if ( !values.length ) {\n          elem.selectedIndex = -1;\n        }\n        return values;\n      }\n    }\n  },\n\n  attrFn: {\n    val: true,\n    css: true,\n    html: true,\n    text: true,\n    data: true,\n    width: true,\n    height: true,\n    offset: true\n  },\n\n  attr: function( elem, name, value, pass ) {\n    var ret, hooks, notxml,\n      nType = elem.nodeType;\n\n    // don't get/set attributes on text, comment and attribute nodes\n    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n      return;\n    }\n\n    if ( pass && name in jQuery.attrFn ) {\n      return jQuery( elem )[ name ]( value );\n    }\n\n    // Fallback to prop when attributes are not supported\n    if ( typeof elem.getAttribute === \"undefined\" ) {\n      return jQuery.prop( elem, name, value );\n    }\n\n    notxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n    // All attributes are lowercase\n    // Grab necessary hook if one is defined\n    if ( notxml ) {\n      name = name.toLowerCase();\n      hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );\n    }\n\n    if ( value !== undefined ) {\n\n      if ( value === null ) {\n        jQuery.removeAttr( elem, name );\n        return;\n\n      } else if ( hooks && \"set\" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {\n        return ret;\n\n      } else {\n        elem.setAttribute( name, \"\" + value );\n        return value;\n      }\n\n    } else if ( hooks && \"get\" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {\n      return ret;\n\n    } else {\n\n      ret = elem.getAttribute( name );\n\n      // Non-existent attributes return null, we normalize to undefined\n      return ret === null ?\n        undefined :\n        ret;\n    }\n  },\n\n  removeAttr: function( elem, value ) {\n    var propName, attrNames, name, l, isBool,\n      i = 0;\n\n    if ( value && elem.nodeType === 1 ) {\n      attrNames = value.toLowerCase().split( rspace );\n      l = attrNames.length;\n\n      for ( ; i < l; i++ ) {\n        name = attrNames[ i ];\n\n        if ( name ) {\n          propName = jQuery.propFix[ name ] || name;\n          isBool = rboolean.test( name );\n\n          // See #9699 for explanation of this approach (setting first, then removal)\n          // Do not do this for boolean attributes (see #10870)\n          if ( !isBool ) {\n            jQuery.attr( elem, name, \"\" );\n          }\n          elem.removeAttribute( getSetAttribute ? name : propName );\n\n          // Set corresponding property to false for boolean attributes\n          if ( isBool && propName in elem ) {\n            elem[ propName ] = false;\n          }\n        }\n      }\n    }\n  },\n\n  attrHooks: {\n    type: {\n      set: function( elem, value ) {\n        // We can't allow the type property to be changed (since it causes problems in IE)\n        if ( rtype.test( elem.nodeName ) && elem.parentNode ) {\n          jQuery.error( \"type property can't be changed\" );\n        } else if ( !jQuery.support.radioValue && value === \"radio\" && jQuery.nodeName(elem, \"input\") ) {\n          // Setting the type on a radio button after the value resets the value in IE6-9\n          // Reset value to it's default in case type is set after value\n          // This is for element creation\n          var val = elem.value;\n          elem.setAttribute( \"type\", value );\n          if ( val ) {\n            elem.value = val;\n          }\n          return value;\n        }\n      }\n    },\n    // Use the value property for back compat\n    // Use the nodeHook for button elements in IE6/7 (#1954)\n    value: {\n      get: function( elem, name ) {\n        if ( nodeHook && jQuery.nodeName( elem, \"button\" ) ) {\n          return nodeHook.get( elem, name );\n        }\n        return name in elem ?\n          elem.value :\n          null;\n      },\n      set: function( elem, value, name ) {\n        if ( nodeHook && jQuery.nodeName( elem, \"button\" ) ) {\n          return nodeHook.set( elem, value, name );\n        }\n        // Does not return so that setAttribute is also used\n        elem.value = value;\n      }\n    }\n  },\n\n  propFix: {\n    tabindex: \"tabIndex\",\n    readonly: \"readOnly\",\n    \"for\": \"htmlFor\",\n    \"class\": \"className\",\n    maxlength: \"maxLength\",\n    cellspacing: \"cellSpacing\",\n    cellpadding: \"cellPadding\",\n    rowspan: \"rowSpan\",\n    colspan: \"colSpan\",\n    usemap: \"useMap\",\n    frameborder: \"frameBorder\",\n    contenteditable: \"contentEditable\"\n  },\n\n  prop: function( elem, name, value ) {\n    var ret, hooks, notxml,\n      nType = elem.nodeType;\n\n    // don't get/set properties on text, comment and attribute nodes\n    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n      return;\n    }\n\n    notxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n    if ( notxml ) {\n      // Fix name and attach hooks\n      name = jQuery.propFix[ name ] || name;\n      hooks = jQuery.propHooks[ name ];\n    }\n\n    if ( value !== undefined ) {\n      if ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n        return ret;\n\n      } else {\n        return ( elem[ name ] = value );\n      }\n\n    } else {\n      if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n        return ret;\n\n      } else {\n        return elem[ name ];\n      }\n    }\n  },\n\n  propHooks: {\n    tabIndex: {\n      get: function( elem ) {\n        // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n        // https://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n        var attributeNode = elem.getAttributeNode(\"tabindex\");\n\n        return attributeNode && attributeNode.specified ?\n          parseInt( attributeNode.value, 10 ) :\n          rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n            0 :\n            undefined;\n      }\n    }\n  }\n});\n\n// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)\njQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;\n\n// Hook for boolean attributes\nboolHook = {\n  get: function( elem, name ) {\n    // Align boolean attributes with corresponding properties\n    // Fall back to attribute presence where some booleans are not supported\n    var attrNode,\n      property = jQuery.prop( elem, name );\n    return property === true || typeof property !== \"boolean\" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?\n      name.toLowerCase() :\n      undefined;\n  },\n  set: function( elem, value, name ) {\n    var propName;\n    if ( value === false ) {\n      // Remove boolean attributes when set to false\n      jQuery.removeAttr( elem, name );\n    } else {\n      // value is true since we know at this point it's type boolean and not false\n      // Set boolean attributes to the same name and set the DOM property\n      propName = jQuery.propFix[ name ] || name;\n      if ( propName in elem ) {\n        // Only set the IDL specifically if it already exists on the element\n        elem[ propName ] = true;\n      }\n\n      elem.setAttribute( name, name.toLowerCase() );\n    }\n    return name;\n  }\n};\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !getSetAttribute ) {\n\n  fixSpecified = {\n    name: true,\n    id: true,\n    coords: true\n  };\n\n  // Use this for any attribute in IE6/7\n  // This fixes almost every IE6/7 issue\n  nodeHook = jQuery.valHooks.button = {\n    get: function( elem, name ) {\n      var ret;\n      ret = elem.getAttributeNode( name );\n      return ret && ( fixSpecified[ name ] ? ret.nodeValue !== \"\" : ret.specified ) ?\n        ret.nodeValue :\n        undefined;\n    },\n    set: function( elem, value, name ) {\n      // Set the existing or create a new attribute node\n      var ret = elem.getAttributeNode( name );\n      if ( !ret ) {\n        ret = document.createAttribute( name );\n        elem.setAttributeNode( ret );\n      }\n      return ( ret.nodeValue = value + \"\" );\n    }\n  };\n\n  // Apply the nodeHook to tabindex\n  jQuery.attrHooks.tabindex.set = nodeHook.set;\n\n  // Set width and height to auto instead of 0 on empty string( Bug #8150 )\n  // This is for removals\n  jQuery.each([ \"width\", \"height\" ], function( i, name ) {\n    jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n      set: function( elem, value ) {\n        if ( value === \"\" ) {\n          elem.setAttribute( name, \"auto\" );\n          return value;\n        }\n      }\n    });\n  });\n\n  // Set contenteditable to false on removals(#10429)\n  // Setting to empty string throws an error as an invalid value\n  jQuery.attrHooks.contenteditable = {\n    get: nodeHook.get,\n    set: function( elem, value, name ) {\n      if ( value === \"\" ) {\n        value = \"false\";\n      }\n      nodeHook.set( elem, value, name );\n    }\n  };\n}\n\n\n// Some attributes require a special call on IE\nif ( !jQuery.support.hrefNormalized ) {\n  jQuery.each([ \"href\", \"src\", \"width\", \"height\" ], function( i, name ) {\n    jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n      get: function( elem ) {\n        var ret = elem.getAttribute( name, 2 );\n        return ret === null ? undefined : ret;\n      }\n    });\n  });\n}\n\nif ( !jQuery.support.style ) {\n  jQuery.attrHooks.style = {\n    get: function( elem ) {\n      // Return undefined in the case of empty string\n      // Normalize to lowercase since IE uppercases css property names\n      return elem.style.cssText.toLowerCase() || undefined;\n    },\n    set: function( elem, value ) {\n      return ( elem.style.cssText = \"\" + value );\n    }\n  };\n}\n\n// Safari mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !jQuery.support.optSelected ) {\n  jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {\n    get: function( elem ) {\n      var parent = elem.parentNode;\n\n      if ( parent ) {\n        parent.selectedIndex;\n\n        // Make sure that it also works with optgroups, see #5701\n        if ( parent.parentNode ) {\n          parent.parentNode.selectedIndex;\n        }\n      }\n      return null;\n    }\n  });\n}\n\n// IE6/7 call enctype encoding\nif ( !jQuery.support.enctype ) {\n  jQuery.propFix.enctype = \"encoding\";\n}\n\n// Radios and checkboxes getter/setter\nif ( !jQuery.support.checkOn ) {\n  jQuery.each([ \"radio\", \"checkbox\" ], function() {\n    jQuery.valHooks[ this ] = {\n      get: function( elem ) {\n        // Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n        return elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n      }\n    };\n  });\n}\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n  jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {\n    set: function( elem, value ) {\n      if ( jQuery.isArray( value ) ) {\n        return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n      }\n    }\n  });\n});\n\n\n\n\nvar rformElems = /^(?:textarea|input|select)$/i,\n  rtypenamespace = /^([^\\.]*)?(?:\\.(.+))?$/,\n  rhoverHack = /(?:^|\\s)hover(\\.\\S+)?\\b/,\n  rkeyEvent = /^key/,\n  rmouseEvent = /^(?:mouse|contextmenu)|click/,\n  rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n  rquickIs = /^(\\w*)(?:#([\\w\\-]+))?(?:\\.([\\w\\-]+))?$/,\n  quickParse = function( selector ) {\n    var quick = rquickIs.exec( selector );\n    if ( quick ) {\n      //   0  1    2   3\n      // [ _, tag, id, class ]\n      quick[1] = ( quick[1] || \"\" ).toLowerCase();\n      quick[3] = quick[3] && new RegExp( \"(?:^|\\\\s)\" + quick[3] + \"(?:\\\\s|$)\" );\n    }\n    return quick;\n  },\n  quickIs = function( elem, m ) {\n    var attrs = elem.attributes || {};\n    return (\n      (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&\n      (!m[2] || (attrs.id || {}).value === m[2]) &&\n      (!m[3] || m[3].test( (attrs[ \"class\" ] || {}).value ))\n    );\n  },\n  hoverHack = function( events ) {\n    return jQuery.event.special.hover ? events : events.replace( rhoverHack, \"mouseenter$1 mouseleave$1\" );\n  };\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n  add: function( elem, types, handler, data, selector ) {\n\n    var elemData, eventHandle, events,\n      t, tns, type, namespaces, handleObj,\n      handleObjIn, quick, handlers, special;\n\n    // Don't attach events to noData or text/comment nodes (allow plain objects tho)\n    if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {\n      return;\n    }\n\n    // Caller can pass in an object of custom data in lieu of the handler\n    if ( handler.handler ) {\n      handleObjIn = handler;\n      handler = handleObjIn.handler;\n      selector = handleObjIn.selector;\n    }\n\n    // Make sure that the handler has a unique ID, used to find/remove it later\n    if ( !handler.guid ) {\n      handler.guid = jQuery.guid++;\n    }\n\n    // Init the element's event structure and main handler, if this is the first\n    events = elemData.events;\n    if ( !events ) {\n      elemData.events = events = {};\n    }\n    eventHandle = elemData.handle;\n    if ( !eventHandle ) {\n      elemData.handle = eventHandle = function( e ) {\n        // Discard the second event of a jQuery.event.trigger() and\n        // when an event is called after a page has unloaded\n        return typeof jQuery !== \"undefined\" && (!e || jQuery.event.triggered !== e.type) ?\n          jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :\n          undefined;\n      };\n      // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events\n      eventHandle.elem = elem;\n    }\n\n    // Handle multiple events separated by a space\n    // jQuery(...).bind(\"mouseover mouseout\", fn);\n    types = jQuery.trim( hoverHack(types) ).split( \" \" );\n    for ( t = 0; t < types.length; t++ ) {\n\n      tns = rtypenamespace.exec( types[t] ) || [];\n      type = tns[1];\n      namespaces = ( tns[2] || \"\" ).split( \".\" ).sort();\n\n      // If event changes its type, use the special event handlers for the changed type\n      special = jQuery.event.special[ type ] || {};\n\n      // If selector defined, determine special event api type, otherwise given type\n      type = ( selector ? special.delegateType : special.bindType ) || type;\n\n      // Update special based on newly reset type\n      special = jQuery.event.special[ type ] || {};\n\n      // handleObj is passed to all event handlers\n      handleObj = jQuery.extend({\n        type: type,\n        origType: tns[1],\n        data: data,\n        handler: handler,\n        guid: handler.guid,\n        selector: selector,\n        quick: selector && quickParse( selector ),\n        namespace: namespaces.join(\".\")\n      }, handleObjIn );\n\n      // Init the event handler queue if we're the first\n      handlers = events[ type ];\n      if ( !handlers ) {\n        handlers = events[ type ] = [];\n        handlers.delegateCount = 0;\n\n        // Only use addEventListener/attachEvent if the special events handler returns false\n        if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n          // Bind the global event handler to the element\n          if ( elem.addEventListener ) {\n            elem.addEventListener( type, eventHandle, false );\n\n          } else if ( elem.attachEvent ) {\n            elem.attachEvent( \"on\" + type, eventHandle );\n          }\n        }\n      }\n\n      if ( special.add ) {\n        special.add.call( elem, handleObj );\n\n        if ( !handleObj.handler.guid ) {\n          handleObj.handler.guid = handler.guid;\n        }\n      }\n\n      // Add to the element's handler list, delegates in front\n      if ( selector ) {\n        handlers.splice( handlers.delegateCount++, 0, handleObj );\n      } else {\n        handlers.push( handleObj );\n      }\n\n      // Keep track of which events have ever been used, for event optimization\n      jQuery.event.global[ type ] = true;\n    }\n\n    // Nullify elem to prevent memory leaks in IE\n    elem = null;\n  },\n\n  global: {},\n\n  // Detach an event or set of events from an element\n  remove: function( elem, types, handler, selector, mappedTypes ) {\n\n    var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),\n      t, tns, type, origType, namespaces, origCount,\n      j, events, special, handle, eventType, handleObj;\n\n    if ( !elemData || !(events = elemData.events) ) {\n      return;\n    }\n\n    // Once for each type.namespace in types; type may be omitted\n    types = jQuery.trim( hoverHack( types || \"\" ) ).split(\" \");\n    for ( t = 0; t < types.length; t++ ) {\n      tns = rtypenamespace.exec( types[t] ) || [];\n      type = origType = tns[1];\n      namespaces = tns[2];\n\n      // Unbind all events (on this namespace, if provided) for the element\n      if ( !type ) {\n        for ( type in events ) {\n          jQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n        }\n        continue;\n      }\n\n      special = jQuery.event.special[ type ] || {};\n      type = ( selector? special.delegateType : special.bindType ) || type;\n      eventType = events[ type ] || [];\n      origCount = eventType.length;\n      namespaces = namespaces ? new RegExp(\"(^|\\\\.)\" + namespaces.split(\".\").sort().join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\") : null;\n\n      // Remove matching events\n      for ( j = 0; j < eventType.length; j++ ) {\n        handleObj = eventType[ j ];\n\n        if ( ( mappedTypes || origType === handleObj.origType ) &&\n           ( !handler || handler.guid === handleObj.guid ) &&\n           ( !namespaces || namespaces.test( handleObj.namespace ) ) &&\n           ( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n          eventType.splice( j--, 1 );\n\n          if ( handleObj.selector ) {\n            eventType.delegateCount--;\n          }\n          if ( special.remove ) {\n            special.remove.call( elem, handleObj );\n          }\n        }\n      }\n\n      // Remove generic event handler if we removed something and no more handlers exist\n      // (avoids potential for endless recursion during removal of special event handlers)\n      if ( eventType.length === 0 && origCount !== eventType.length ) {\n        if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {\n          jQuery.removeEvent( elem, type, elemData.handle );\n        }\n\n        delete events[ type ];\n      }\n    }\n\n    // Remove the expando if it's no longer used\n    if ( jQuery.isEmptyObject( events ) ) {\n      handle = elemData.handle;\n      if ( handle ) {\n        handle.elem = null;\n      }\n\n      // removeData also checks for emptiness and clears the expando if empty\n      // so use it instead of delete\n      jQuery.removeData( elem, [ \"events\", \"handle\" ], true );\n    }\n  },\n\n  // Events that are safe to short-circuit if no handlers are attached.\n  // Native DOM events should not be added, they may have inline handlers.\n  customEvent: {\n    \"getData\": true,\n    \"setData\": true,\n    \"changeData\": true\n  },\n\n  trigger: function( event, data, elem, onlyHandlers ) {\n    // Don't do events on text and comment nodes\n    if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {\n      return;\n    }\n\n    // Event object or event type\n    var type = event.type || event,\n      namespaces = [],\n      cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;\n\n    // focus/blur morphs to focusin/out; ensure we're not firing them right now\n    if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n      return;\n    }\n\n    if ( type.indexOf( \"!\" ) >= 0 ) {\n      // Exclusive events trigger only for the exact event (no namespaces)\n      type = type.slice(0, -1);\n      exclusive = true;\n    }\n\n    if ( type.indexOf( \".\" ) >= 0 ) {\n      // Namespaced trigger; create a regexp to match event type in handle()\n      namespaces = type.split(\".\");\n      type = namespaces.shift();\n      namespaces.sort();\n    }\n\n    if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {\n      // No jQuery handlers for this event type, and it can't have inline handlers\n      return;\n    }\n\n    // Caller can pass in an Event, Object, or just an event type string\n    event = typeof event === \"object\" ?\n      // jQuery.Event object\n      event[ jQuery.expando ] ? event :\n      // Object literal\n      new jQuery.Event( type, event ) :\n      // Just the event type (string)\n      new jQuery.Event( type );\n\n    event.type = type;\n    event.isTrigger = true;\n    event.exclusive = exclusive;\n    event.namespace = namespaces.join( \".\" );\n    event.namespace_re = event.namespace? new RegExp(\"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\") : null;\n    ontype = type.indexOf( \":\" ) < 0 ? \"on\" + type : \"\";\n\n    // Handle a global trigger\n    if ( !elem ) {\n\n      // TODO: Stop taunting the data cache; remove global events and always attach to document\n      cache = jQuery.cache;\n      for ( i in cache ) {\n        if ( cache[ i ].events && cache[ i ].events[ type ] ) {\n          jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );\n        }\n      }\n      return;\n    }\n\n    // Clean up the event in case it is being reused\n    event.result = undefined;\n    if ( !event.target ) {\n      event.target = elem;\n    }\n\n    // Clone any incoming data and prepend the event, creating the handler arg list\n    data = data != null ? jQuery.makeArray( data ) : [];\n    data.unshift( event );\n\n    // Allow special events to draw outside the lines\n    special = jQuery.event.special[ type ] || {};\n    if ( special.trigger && special.trigger.apply( elem, data ) === false ) {\n      return;\n    }\n\n    // Determine event propagation path in advance, per W3C events spec (#9951)\n    // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n    eventPath = [[ elem, special.bindType || type ]];\n    if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n      bubbleType = special.delegateType || type;\n      cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;\n      old = null;\n      for ( ; cur; cur = cur.parentNode ) {\n        eventPath.push([ cur, bubbleType ]);\n        old = cur;\n      }\n\n      // Only add window if we got to document (e.g., not plain obj or detached DOM)\n      if ( old && old === elem.ownerDocument ) {\n        eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);\n      }\n    }\n\n    // Fire handlers on the event path\n    for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {\n\n      cur = eventPath[i][0];\n      event.type = eventPath[i][1];\n\n      handle = ( jQuery._data( cur, \"events\" ) || {} )[ event.type ] && jQuery._data( cur, \"handle\" );\n      if ( handle ) {\n        handle.apply( cur, data );\n      }\n      // Note that this is a bare JS function and not a jQuery handler\n      handle = ontype && cur[ ontype ];\n      if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {\n        event.preventDefault();\n      }\n    }\n    event.type = type;\n\n    // If nobody prevented the default action, do it now\n    if ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n      if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&\n        !(type === \"click\" && jQuery.nodeName( elem, \"a\" )) && jQuery.acceptData( elem ) ) {\n\n        // Call a native DOM method on the target with the same name name as the event.\n        // Can't use an .isFunction() check here because IE6/7 fails that test.\n        // Don't do default actions on window, that's where global variables be (#6170)\n        // IE<9 dies on focus/blur to hidden element (#1486)\n        if ( ontype && elem[ type ] && ((type !== \"focus\" && type !== \"blur\") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {\n\n          // Don't re-trigger an onFOO event when we call its FOO() method\n          old = elem[ ontype ];\n\n          if ( old ) {\n            elem[ ontype ] = null;\n          }\n\n          // Prevent re-triggering of the same event, since we already bubbled it above\n          jQuery.event.triggered = type;\n          elem[ type ]();\n          jQuery.event.triggered = undefined;\n\n          if ( old ) {\n            elem[ ontype ] = old;\n          }\n        }\n      }\n    }\n\n    return event.result;\n  },\n\n  dispatch: function( event ) {\n\n    // Make a writable jQuery.Event from the native event object\n    event = jQuery.event.fix( event || window.event );\n\n    var handlers = ( (jQuery._data( this, \"events\" ) || {} )[ event.type ] || []),\n      delegateCount = handlers.delegateCount,\n      args = [].slice.call( arguments, 0 ),\n      run_all = !event.exclusive && !event.namespace,\n      special = jQuery.event.special[ event.type ] || {},\n      handlerQueue = [],\n      i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;\n\n    // Use the fix-ed jQuery.Event rather than the (read-only) native event\n    args[0] = event;\n    event.delegateTarget = this;\n\n    // Call the preDispatch hook for the mapped type, and let it bail if desired\n    if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n      return;\n    }\n\n    // Determine handlers that should run if there are delegated events\n    // Avoid non-left-click bubbling in Firefox (#3861)\n    if ( delegateCount && !(event.button && event.type === \"click\") ) {\n\n      // Pregenerate a single jQuery object for reuse with .is()\n      jqcur = jQuery(this);\n      jqcur.context = this.ownerDocument || this;\n\n      for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {\n\n        // Don't process events on disabled elements (#6911, #8165)\n        if ( cur.disabled !== true ) {\n          selMatch = {};\n          matches = [];\n          jqcur[0] = cur;\n          for ( i = 0; i < delegateCount; i++ ) {\n            handleObj = handlers[ i ];\n            sel = handleObj.selector;\n\n            if ( selMatch[ sel ] === undefined ) {\n              selMatch[ sel ] = (\n                handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )\n              );\n            }\n            if ( selMatch[ sel ] ) {\n              matches.push( handleObj );\n            }\n          }\n          if ( matches.length ) {\n            handlerQueue.push({ elem: cur, matches: matches });\n          }\n        }\n      }\n    }\n\n    // Add the remaining (directly-bound) handlers\n    if ( handlers.length > delegateCount ) {\n      handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });\n    }\n\n    // Run delegates first; they may want to stop propagation beneath us\n    for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {\n      matched = handlerQueue[ i ];\n      event.currentTarget = matched.elem;\n\n      for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {\n        handleObj = matched.matches[ j ];\n\n        // Triggered event must either 1) be non-exclusive and have no namespace, or\n        // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).\n        if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {\n\n          event.data = handleObj.data;\n          event.handleObj = handleObj;\n\n          ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n              .apply( matched.elem, args );\n\n          if ( ret !== undefined ) {\n            event.result = ret;\n            if ( ret === false ) {\n              event.preventDefault();\n              event.stopPropagation();\n            }\n          }\n        }\n      }\n    }\n\n    // Call the postDispatch hook for the mapped type\n    if ( special.postDispatch ) {\n      special.postDispatch.call( this, event );\n    }\n\n    return event.result;\n  },\n\n  // Includes some event props shared by KeyEvent and MouseEvent\n  // *** attrChange attrName relatedNode srcElement  are not normalized, non-W3C, deprecated, will be removed in 1.8 ***\n  props: \"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n  fixHooks: {},\n\n  keyHooks: {\n    props: \"char charCode key keyCode\".split(\" \"),\n    filter: function( event, original ) {\n\n      // Add which for key events\n      if ( event.which == null ) {\n        event.which = original.charCode != null ? original.charCode : original.keyCode;\n      }\n\n      return event;\n    }\n  },\n\n  mouseHooks: {\n    props: \"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n    filter: function( event, original ) {\n      var eventDoc, doc, body,\n        button = original.button,\n        fromElement = original.fromElement;\n\n      // Calculate pageX/Y if missing and clientX/Y available\n      if ( event.pageX == null && original.clientX != null ) {\n        eventDoc = event.target.ownerDocument || document;\n        doc = eventDoc.documentElement;\n        body = eventDoc.body;\n\n        event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n        event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n      }\n\n      // Add relatedTarget, if necessary\n      if ( !event.relatedTarget && fromElement ) {\n        event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;\n      }\n\n      // Add which for click: 1 === left; 2 === middle; 3 === right\n      // Note: button is not normalized, so don't use it\n      if ( !event.which && button !== undefined ) {\n        event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n      }\n\n      return event;\n    }\n  },\n\n  fix: function( event ) {\n    if ( event[ jQuery.expando ] ) {\n      return event;\n    }\n\n    // Create a writable copy of the event object and normalize some properties\n    var i, prop,\n      originalEvent = event,\n      fixHook = jQuery.event.fixHooks[ event.type ] || {},\n      copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n    event = jQuery.Event( originalEvent );\n\n    for ( i = copy.length; i; ) {\n      prop = copy[ --i ];\n      event[ prop ] = originalEvent[ prop ];\n    }\n\n    // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)\n    if ( !event.target ) {\n      event.target = originalEvent.srcElement || document;\n    }\n\n    // Target should not be a text node (#504, Safari)\n    if ( event.target.nodeType === 3 ) {\n      event.target = event.target.parentNode;\n    }\n\n    // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)\n    if ( event.metaKey === undefined ) {\n      event.metaKey = event.ctrlKey;\n    }\n\n    return fixHook.filter? fixHook.filter( event, originalEvent ) : event;\n  },\n\n  special: {\n    ready: {\n      // Make sure the ready event is setup\n      setup: jQuery.bindReady\n    },\n\n    load: {\n      // Prevent triggered image.load events from bubbling to window.load\n      noBubble: true\n    },\n\n    focus: {\n      delegateType: \"focusin\"\n    },\n    blur: {\n      delegateType: \"focusout\"\n    },\n\n    beforeunload: {\n      setup: function( data, namespaces, eventHandle ) {\n        // We only want to do this special case on windows\n        if ( jQuery.isWindow( this ) ) {\n          this.onbeforeunload = eventHandle;\n        }\n      },\n\n      teardown: function( namespaces, eventHandle ) {\n        if ( this.onbeforeunload === eventHandle ) {\n          this.onbeforeunload = null;\n        }\n      }\n    }\n  },\n\n  simulate: function( type, elem, event, bubble ) {\n    // Piggyback on a donor event to simulate a different one.\n    // Fake originalEvent to avoid donor's stopPropagation, but if the\n    // simulated event prevents default then we do the same on the donor.\n    var e = jQuery.extend(\n      new jQuery.Event(),\n      event,\n      { type: type,\n        isSimulated: true,\n        originalEvent: {}\n      }\n    );\n    if ( bubble ) {\n      jQuery.event.trigger( e, null, elem );\n    } else {\n      jQuery.event.dispatch.call( elem, e );\n    }\n    if ( e.isDefaultPrevented() ) {\n      event.preventDefault();\n    }\n  }\n};\n\n// Some plugins are using, but it's undocumented/deprecated and will be removed.\n// The 1.7 special event interface should provide all the hooks needed now.\njQuery.event.handle = jQuery.event.dispatch;\n\njQuery.removeEvent = document.removeEventListener ?\n  function( elem, type, handle ) {\n    if ( elem.removeEventListener ) {\n      elem.removeEventListener( type, handle, false );\n    }\n  } :\n  function( elem, type, handle ) {\n    if ( elem.detachEvent ) {\n      elem.detachEvent( \"on\" + type, handle );\n    }\n  };\n\njQuery.Event = function( src, props ) {\n  // Allow instantiation without the 'new' keyword\n  if ( !(this instanceof jQuery.Event) ) {\n    return new jQuery.Event( src, props );\n  }\n\n  // Event object\n  if ( src && src.type ) {\n    this.originalEvent = src;\n    this.type = src.type;\n\n    // Events bubbling up the document may have been marked as prevented\n    // by a handler lower down the tree; reflect the correct value.\n    this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||\n      src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;\n\n  // Event type\n  } else {\n    this.type = src;\n  }\n\n  // Put explicitly provided properties onto the event object\n  if ( props ) {\n    jQuery.extend( this, props );\n  }\n\n  // Create a timestamp if incoming event doesn't have one\n  this.timeStamp = src && src.timeStamp || jQuery.now();\n\n  // Mark it as fixed\n  this[ jQuery.expando ] = true;\n};\n\nfunction returnFalse() {\n  return false;\n}\nfunction returnTrue() {\n  return true;\n}\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n  preventDefault: function() {\n    this.isDefaultPrevented = returnTrue;\n\n    var e = this.originalEvent;\n    if ( !e ) {\n      return;\n    }\n\n    // if preventDefault exists run it on the original event\n    if ( e.preventDefault ) {\n      e.preventDefault();\n\n    // otherwise set the returnValue property of the original event to false (IE)\n    } else {\n      e.returnValue = false;\n    }\n  },\n  stopPropagation: function() {\n    this.isPropagationStopped = returnTrue;\n\n    var e = this.originalEvent;\n    if ( !e ) {\n      return;\n    }\n    // if stopPropagation exists run it on the original event\n    if ( e.stopPropagation ) {\n      e.stopPropagation();\n    }\n    // otherwise set the cancelBubble property of the original event to true (IE)\n    e.cancelBubble = true;\n  },\n  stopImmediatePropagation: function() {\n    this.isImmediatePropagationStopped = returnTrue;\n    this.stopPropagation();\n  },\n  isDefaultPrevented: returnFalse,\n  isPropagationStopped: returnFalse,\n  isImmediatePropagationStopped: returnFalse\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\njQuery.each({\n  mouseenter: \"mouseover\",\n  mouseleave: \"mouseout\"\n}, function( orig, fix ) {\n  jQuery.event.special[ orig ] = {\n    delegateType: fix,\n    bindType: fix,\n\n    handle: function( event ) {\n      var target = this,\n        related = event.relatedTarget,\n        handleObj = event.handleObj,\n        selector = handleObj.selector,\n        ret;\n\n      // For mousenter/leave call the handler if related is outside the target.\n      // NB: No relatedTarget if the mouse left/entered the browser window\n      if ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n        event.type = handleObj.origType;\n        ret = handleObj.handler.apply( this, arguments );\n        event.type = fix;\n      }\n      return ret;\n    }\n  };\n});\n\n// IE submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\n  jQuery.event.special.submit = {\n    setup: function() {\n      // Only need this for delegated form submit events\n      if ( jQuery.nodeName( this, \"form\" ) ) {\n        return false;\n      }\n\n      // Lazy-add a submit handler when a descendant form may potentially be submitted\n      jQuery.event.add( this, \"click._submit keypress._submit\", function( e ) {\n        // Node name check avoids a VML-related crash in IE (#9807)\n        var elem = e.target,\n          form = jQuery.nodeName( elem, \"input\" ) || jQuery.nodeName( elem, \"button\" ) ? elem.form : undefined;\n        if ( form && !form._submit_attached ) {\n          jQuery.event.add( form, \"submit._submit\", function( event ) {\n            event._submit_bubble = true;\n          });\n          form._submit_attached = true;\n        }\n      });\n      // return undefined since we don't need an event listener\n    },\n\n    postDispatch: function( event ) {\n      // If form was submitted by the user, bubble the event up the tree\n      if ( event._submit_bubble ) {\n        delete event._submit_bubble;\n        if ( this.parentNode && !event.isTrigger ) {\n          jQuery.event.simulate( \"submit\", this.parentNode, event, true );\n        }\n      }\n    },\n\n    teardown: function() {\n      // Only need this for delegated form submit events\n      if ( jQuery.nodeName( this, \"form\" ) ) {\n        return false;\n      }\n\n      // Remove delegated handlers; cleanData eventually reaps submit handlers attached above\n      jQuery.event.remove( this, \"._submit\" );\n    }\n  };\n}\n\n// IE change delegation and checkbox/radio fix\nif ( !jQuery.support.changeBubbles ) {\n\n  jQuery.event.special.change = {\n\n    setup: function() {\n\n      if ( rformElems.test( this.nodeName ) ) {\n        // IE doesn't fire change on a check/radio until blur; trigger it on click\n        // after a propertychange. Eat the blur-change in special.change.handle.\n        // This still fires onchange a second time for check/radio after blur.\n        if ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n          jQuery.event.add( this, \"propertychange._change\", function( event ) {\n            if ( event.originalEvent.propertyName === \"checked\" ) {\n              this._just_changed = true;\n            }\n          });\n          jQuery.event.add( this, \"click._change\", function( event ) {\n            if ( this._just_changed && !event.isTrigger ) {\n              this._just_changed = false;\n              jQuery.event.simulate( \"change\", this, event, true );\n            }\n          });\n        }\n        return false;\n      }\n      // Delegated event; lazy-add a change handler on descendant inputs\n      jQuery.event.add( this, \"beforeactivate._change\", function( e ) {\n        var elem = e.target;\n\n        if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {\n          jQuery.event.add( elem, \"change._change\", function( event ) {\n            if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {\n              jQuery.event.simulate( \"change\", this.parentNode, event, true );\n            }\n          });\n          elem._change_attached = true;\n        }\n      });\n    },\n\n    handle: function( event ) {\n      var elem = event.target;\n\n      // Swallow native change events from checkbox/radio, we already triggered them above\n      if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== \"radio\" && elem.type !== \"checkbox\") ) {\n        return event.handleObj.handler.apply( this, arguments );\n      }\n    },\n\n    teardown: function() {\n      jQuery.event.remove( this, \"._change\" );\n\n      return rformElems.test( this.nodeName );\n    }\n  };\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !jQuery.support.focusinBubbles ) {\n  jQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n    // Attach a single capturing handler while someone wants focusin/focusout\n    var attaches = 0,\n      handler = function( event ) {\n        jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n      };\n\n    jQuery.event.special[ fix ] = {\n      setup: function() {\n        if ( attaches++ === 0 ) {\n          document.addEventListener( orig, handler, true );\n        }\n      },\n      teardown: function() {\n        if ( --attaches === 0 ) {\n          document.removeEventListener( orig, handler, true );\n        }\n      }\n    };\n  });\n}\n\njQuery.fn.extend({\n\n  on: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n    var origFn, type;\n\n    // Types can be a map of types/handlers\n    if ( typeof types === \"object\" ) {\n      // ( types-Object, selector, data )\n      if ( typeof selector !== \"string\" ) { // && selector != null\n        // ( types-Object, data )\n        data = data || selector;\n        selector = undefined;\n      }\n      for ( type in types ) {\n        this.on( type, selector, data, types[ type ], one );\n      }\n      return this;\n    }\n\n    if ( data == null && fn == null ) {\n      // ( types, fn )\n      fn = selector;\n      data = selector = undefined;\n    } else if ( fn == null ) {\n      if ( typeof selector === \"string\" ) {\n        // ( types, selector, fn )\n        fn = data;\n        data = undefined;\n      } else {\n        // ( types, data, fn )\n        fn = data;\n        data = selector;\n        selector = undefined;\n      }\n    }\n    if ( fn === false ) {\n      fn = returnFalse;\n    } else if ( !fn ) {\n      return this;\n    }\n\n    if ( one === 1 ) {\n      origFn = fn;\n      fn = function( event ) {\n        // Can use an empty set, since event contains the info\n        jQuery().off( event );\n        return origFn.apply( this, arguments );\n      };\n      // Use same guid so caller can remove using origFn\n      fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n    }\n    return this.each( function() {\n      jQuery.event.add( this, types, fn, data, selector );\n    });\n  },\n  one: function( types, selector, data, fn ) {\n    return this.on( types, selector, data, fn, 1 );\n  },\n  off: function( types, selector, fn ) {\n    if ( types && types.preventDefault && types.handleObj ) {\n      // ( event )  dispatched jQuery.Event\n      var handleObj = types.handleObj;\n      jQuery( types.delegateTarget ).off(\n        handleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n        handleObj.selector,\n        handleObj.handler\n      );\n      return this;\n    }\n    if ( typeof types === \"object\" ) {\n      // ( types-object [, selector] )\n      for ( var type in types ) {\n        this.off( type, selector, types[ type ] );\n      }\n      return this;\n    }\n    if ( selector === false || typeof selector === \"function\" ) {\n      // ( types [, fn] )\n      fn = selector;\n      selector = undefined;\n    }\n    if ( fn === false ) {\n      fn = returnFalse;\n    }\n    return this.each(function() {\n      jQuery.event.remove( this, types, fn, selector );\n    });\n  },\n\n  bind: function( types, data, fn ) {\n    return this.on( types, null, data, fn );\n  },\n  unbind: function( types, fn ) {\n    return this.off( types, null, fn );\n  },\n\n  live: function( types, data, fn ) {\n    jQuery( this.context ).on( types, this.selector, data, fn );\n    return this;\n  },\n  die: function( types, fn ) {\n    jQuery( this.context ).off( types, this.selector || \"**\", fn );\n    return this;\n  },\n\n  delegate: function( selector, types, data, fn ) {\n    return this.on( types, selector, data, fn );\n  },\n  undelegate: function( selector, types, fn ) {\n    // ( namespace ) or ( selector, types [, fn] )\n    return arguments.length == 1? this.off( selector, \"**\" ) : this.off( types, selector, fn );\n  },\n\n  trigger: function( type, data ) {\n    return this.each(function() {\n      jQuery.event.trigger( type, data, this );\n    });\n  },\n  triggerHandler: function( type, data ) {\n    if ( this[0] ) {\n      return jQuery.event.trigger( type, data, this[0], true );\n    }\n  },\n\n  toggle: function( fn ) {\n    // Save reference to arguments for access in closure\n    var args = arguments,\n      guid = fn.guid || jQuery.guid++,\n      i = 0,\n      toggler = function( event ) {\n        // Figure out which function to execute\n        var lastToggle = ( jQuery._data( this, \"lastToggle\" + fn.guid ) || 0 ) % i;\n        jQuery._data( this, \"lastToggle\" + fn.guid, lastToggle + 1 );\n\n        // Make sure that clicks stop\n        event.preventDefault();\n\n        // and execute the function\n        return args[ lastToggle ].apply( this, arguments ) || false;\n      };\n\n    // link all the functions, so any of them can unbind this click handler\n    toggler.guid = guid;\n    while ( i < args.length ) {\n      args[ i++ ].guid = guid;\n    }\n\n    return this.click( toggler );\n  },\n\n  hover: function( fnOver, fnOut ) {\n    return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n  }\n});\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n  \"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n  \"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n  // Handle event binding\n  jQuery.fn[ name ] = function( data, fn ) {\n    if ( fn == null ) {\n      fn = data;\n      data = null;\n    }\n\n    return arguments.length > 0 ?\n      this.on( name, null, data, fn ) :\n      this.trigger( name );\n  };\n\n  if ( jQuery.attrFn ) {\n    jQuery.attrFn[ name ] = true;\n  }\n\n  if ( rkeyEvent.test( name ) ) {\n    jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;\n  }\n\n  if ( rmouseEvent.test( name ) ) {\n    jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;\n  }\n});\n\n\n\n/*!\n * Sizzle CSS Selector Engine\n *  Copyright 2011, The Dojo Foundation\n *  Released under the MIT, BSD, and GPL Licenses.\n *  More information: https://sizzlejs.com/\n */\n(function(){\n\nvar chunker = /((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,\n  expando = \"sizcache\" + (Math.random() + '').replace('.', ''),\n  done = 0,\n  toString = Object.prototype.toString,\n  hasDuplicate = false,\n  baseHasDuplicate = true,\n  rBackslash = /\\\\/g,\n  rReturn = /\\r\\n/g,\n  rNonWord = /\\W/;\n\n// Here we check if the JavaScript engine is using some sort of\n// optimization where it does not always call our comparision\n// function. If that is the case, discard the hasDuplicate value.\n//   Thus far that includes Google Chrome.\n[0, 0].sort(function() {\n  baseHasDuplicate = false;\n  return 0;\n});\n\nvar Sizzle = function( selector, context, results, seed ) {\n  results = results || [];\n  context = context || document;\n\n  var origContext = context;\n\n  if ( context.nodeType !== 1 && context.nodeType !== 9 ) {\n    return [];\n  }\n\n  if ( !selector || typeof selector !== \"string\" ) {\n    return results;\n  }\n\n  var m, set, checkSet, extra, ret, cur, pop, i,\n    prune = true,\n    contextXML = Sizzle.isXML( context ),\n    parts = [],\n    soFar = selector;\n\n  // Reset the position of the chunker regexp (start from head)\n  do {\n    chunker.exec( \"\" );\n    m = chunker.exec( soFar );\n\n    if ( m ) {\n      soFar = m[3];\n\n      parts.push( m[1] );\n\n      if ( m[2] ) {\n        extra = m[3];\n        break;\n      }\n    }\n  } while ( m );\n\n  if ( parts.length > 1 && origPOS.exec( selector ) ) {\n\n    if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\n      set = posProcess( parts[0] + parts[1], context, seed );\n\n    } else {\n      set = Expr.relative[ parts[0] ] ?\n        [ context ] :\n        Sizzle( parts.shift(), context );\n\n      while ( parts.length ) {\n        selector = parts.shift();\n\n        if ( Expr.relative[ selector ] ) {\n          selector += parts.shift();\n        }\n\n        set = posProcess( selector, set, seed );\n      }\n    }\n\n  } else {\n    // Take a shortcut and set the context if the root selector is an ID\n    // (but not if it'll be faster if the inner selector is an ID)\n    if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\n        Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\n\n      ret = Sizzle.find( parts.shift(), context, contextXML );\n      context = ret.expr ?\n        Sizzle.filter( ret.expr, ret.set )[0] :\n        ret.set[0];\n    }\n\n    if ( context ) {\n      ret = seed ?\n        { expr: parts.pop(), set: makeArray(seed) } :\n        Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === \"~\" || parts[0] === \"+\") && context.parentNode ? context.parentNode : context, contextXML );\n\n      set = ret.expr ?\n        Sizzle.filter( ret.expr, ret.set ) :\n        ret.set;\n\n      if ( parts.length > 0 ) {\n        checkSet = makeArray( set );\n\n      } else {\n        prune = false;\n      }\n\n      while ( parts.length ) {\n        cur = parts.pop();\n        pop = cur;\n\n        if ( !Expr.relative[ cur ] ) {\n          cur = \"\";\n        } else {\n          pop = parts.pop();\n        }\n\n        if ( pop == null ) {\n          pop = context;\n        }\n\n        Expr.relative[ cur ]( checkSet, pop, contextXML );\n      }\n\n    } else {\n      checkSet = parts = [];\n    }\n  }\n\n  if ( !checkSet ) {\n    checkSet = set;\n  }\n\n  if ( !checkSet ) {\n    Sizzle.error( cur || selector );\n  }\n\n  if ( toString.call(checkSet) === \"[object Array]\" ) {\n    if ( !prune ) {\n      results.push.apply( results, checkSet );\n\n    } else if ( context && context.nodeType === 1 ) {\n      for ( i = 0; checkSet[i] != null; i++ ) {\n        if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {\n          results.push( set[i] );\n        }\n      }\n\n    } else {\n      for ( i = 0; checkSet[i] != null; i++ ) {\n        if ( checkSet[i] && checkSet[i].nodeType === 1 ) {\n          results.push( set[i] );\n        }\n      }\n    }\n\n  } else {\n    makeArray( checkSet, results );\n  }\n\n  if ( extra ) {\n    Sizzle( extra, origContext, results, seed );\n    Sizzle.uniqueSort( results );\n  }\n\n  return results;\n};\n\nSizzle.uniqueSort = function( results ) {\n  if ( sortOrder ) {\n    hasDuplicate = baseHasDuplicate;\n    results.sort( sortOrder );\n\n    if ( hasDuplicate ) {\n      for ( var i = 1; i < results.length; i++ ) {\n        if ( results[i] === results[ i - 1 ] ) {\n          results.splice( i--, 1 );\n        }\n      }\n    }\n  }\n\n  return results;\n};\n\nSizzle.matches = function( expr, set ) {\n  return Sizzle( expr, null, null, set );\n};\n\nSizzle.matchesSelector = function( node, expr ) {\n  return Sizzle( expr, null, null, [node] ).length > 0;\n};\n\nSizzle.find = function( expr, context, isXML ) {\n  var set, i, len, match, type, left;\n\n  if ( !expr ) {\n    return [];\n  }\n\n  for ( i = 0, len = Expr.order.length; i < len; i++ ) {\n    type = Expr.order[i];\n\n    if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\n      left = match[1];\n      match.splice( 1, 1 );\n\n      if ( left.substr( left.length - 1 ) !== \"\\\\\" ) {\n        match[1] = (match[1] || \"\").replace( rBackslash, \"\" );\n        set = Expr.find[ type ]( match, context, isXML );\n\n        if ( set != null ) {\n          expr = expr.replace( Expr.match[ type ], \"\" );\n          break;\n        }\n      }\n    }\n  }\n\n  if ( !set ) {\n    set = typeof context.getElementsByTagName !== \"undefined\" ?\n      context.getElementsByTagName( \"*\" ) :\n      [];\n  }\n\n  return { set: set, expr: expr };\n};\n\nSizzle.filter = function( expr, set, inplace, not ) {\n  var match, anyFound,\n    type, found, item, filter, left,\n    i, pass,\n    old = expr,\n    result = [],\n    curLoop = set,\n    isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );\n\n  while ( expr && set.length ) {\n    for ( type in Expr.filter ) {\n      if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\n        filter = Expr.filter[ type ];\n        left = match[1];\n\n        anyFound = false;\n\n        match.splice(1,1);\n\n        if ( left.substr( left.length - 1 ) === \"\\\\\" ) {\n          continue;\n        }\n\n        if ( curLoop === result ) {\n          result = [];\n        }\n\n        if ( Expr.preFilter[ type ] ) {\n          match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\n\n          if ( !match ) {\n            anyFound = found = true;\n\n          } else if ( match === true ) {\n            continue;\n          }\n        }\n\n        if ( match ) {\n          for ( i = 0; (item = curLoop[i]) != null; i++ ) {\n            if ( item ) {\n              found = filter( item, match, i, curLoop );\n              pass = not ^ found;\n\n              if ( inplace && found != null ) {\n                if ( pass ) {\n                  anyFound = true;\n\n                } else {\n                  curLoop[i] = false;\n                }\n\n              } else if ( pass ) {\n                result.push( item );\n                anyFound = true;\n              }\n            }\n          }\n        }\n\n        if ( found !== undefined ) {\n          if ( !inplace ) {\n            curLoop = result;\n          }\n\n          expr = expr.replace( Expr.match[ type ], \"\" );\n\n          if ( !anyFound ) {\n            return [];\n          }\n\n          break;\n        }\n      }\n    }\n\n    // Improper expression\n    if ( expr === old ) {\n      if ( anyFound == null ) {\n        Sizzle.error( expr );\n\n      } else {\n        break;\n      }\n    }\n\n    old = expr;\n  }\n\n  return curLoop;\n};\n\nSizzle.error = function( msg ) {\n  throw new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Utility function for retreiving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\nvar getText = Sizzle.getText = function( elem ) {\n    var i, node,\n    nodeType = elem.nodeType,\n    ret = \"\";\n\n  if ( nodeType ) {\n    if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n      // Use textContent || innerText for elements\n      if ( typeof elem.textContent === 'string' ) {\n        return elem.textContent;\n      } else if ( typeof elem.innerText === 'string' ) {\n        // Replace IE's carriage returns\n        return elem.innerText.replace( rReturn, '' );\n      } else {\n        // Traverse it's children\n        for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {\n          ret += getText( elem );\n        }\n      }\n    } else if ( nodeType === 3 || nodeType === 4 ) {\n      return elem.nodeValue;\n    }\n  } else {\n\n    // If no nodeType, this is expected to be an array\n    for ( i = 0; (node = elem[i]); i++ ) {\n      // Do not traverse comment nodes\n      if ( node.nodeType !== 8 ) {\n        ret += getText( node );\n      }\n    }\n  }\n  return ret;\n};\n\nvar Expr = Sizzle.selectors = {\n  order: [ \"ID\", \"NAME\", \"TAG\" ],\n\n  match: {\n    ID: /#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n    CLASS: /\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n    NAME: /\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,\n    ATTR: /\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,\n    TAG: /^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,\n    CHILD: /:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,\n    POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,\n    PSEUDO: /:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/\n  },\n\n  leftMatch: {},\n\n  attrMap: {\n    \"class\": \"className\",\n    \"for\": \"htmlFor\"\n  },\n\n  attrHandle: {\n    href: function( elem ) {\n      return elem.getAttribute( \"href\" );\n    },\n    type: function( elem ) {\n      return elem.getAttribute( \"type\" );\n    }\n  },\n\n  relative: {\n    \"+\": function(checkSet, part){\n      var isPartStr = typeof part === \"string\",\n        isTag = isPartStr && !rNonWord.test( part ),\n        isPartStrNotTag = isPartStr && !isTag;\n\n      if ( isTag ) {\n        part = part.toLowerCase();\n      }\n\n      for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\n        if ( (elem = checkSet[i]) ) {\n          while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\n\n          checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\n            elem || false :\n            elem === part;\n        }\n      }\n\n      if ( isPartStrNotTag ) {\n        Sizzle.filter( part, checkSet, true );\n      }\n    },\n\n    \">\": function( checkSet, part ) {\n      var elem,\n        isPartStr = typeof part === \"string\",\n        i = 0,\n        l = checkSet.length;\n\n      if ( isPartStr && !rNonWord.test( part ) ) {\n        part = part.toLowerCase();\n\n        for ( ; i < l; i++ ) {\n          elem = checkSet[i];\n\n          if ( elem ) {\n            var parent = elem.parentNode;\n            checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\n          }\n        }\n\n      } else {\n        for ( ; i < l; i++ ) {\n          elem = checkSet[i];\n\n          if ( elem ) {\n            checkSet[i] = isPartStr ?\n              elem.parentNode :\n              elem.parentNode === part;\n          }\n        }\n\n        if ( isPartStr ) {\n          Sizzle.filter( part, checkSet, true );\n        }\n      }\n    },\n\n    \"\": function(checkSet, part, isXML){\n      var nodeCheck,\n        doneName = done++,\n        checkFn = dirCheck;\n\n      if ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n        part = part.toLowerCase();\n        nodeCheck = part;\n        checkFn = dirNodeCheck;\n      }\n\n      checkFn( \"parentNode\", part, doneName, checkSet, nodeCheck, isXML );\n    },\n\n    \"~\": function( checkSet, part, isXML ) {\n      var nodeCheck,\n        doneName = done++,\n        checkFn = dirCheck;\n\n      if ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n        part = part.toLowerCase();\n        nodeCheck = part;\n        checkFn = dirNodeCheck;\n      }\n\n      checkFn( \"previousSibling\", part, doneName, checkSet, nodeCheck, isXML );\n    }\n  },\n\n  find: {\n    ID: function( match, context, isXML ) {\n      if ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n        var m = context.getElementById(match[1]);\n        // Check parentNode to catch when Blackberry 4.6 returns\n        // nodes that are no longer in the document #6963\n        return m && m.parentNode ? [m] : [];\n      }\n    },\n\n    NAME: function( match, context ) {\n      if ( typeof context.getElementsByName !== \"undefined\" ) {\n        var ret = [],\n          results = context.getElementsByName( match[1] );\n\n        for ( var i = 0, l = results.length; i < l; i++ ) {\n          if ( results[i].getAttribute(\"name\") === match[1] ) {\n            ret.push( results[i] );\n          }\n        }\n\n        return ret.length === 0 ? null : ret;\n      }\n    },\n\n    TAG: function( match, context ) {\n      if ( typeof context.getElementsByTagName !== \"undefined\" ) {\n        return context.getElementsByTagName( match[1] );\n      }\n    }\n  },\n  preFilter: {\n    CLASS: function( match, curLoop, inplace, result, not, isXML ) {\n      match = \" \" + match[1].replace( rBackslash, \"\" ) + \" \";\n\n      if ( isXML ) {\n        return match;\n      }\n\n      for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\n        if ( elem ) {\n          if ( not ^ (elem.className && (\" \" + elem.className + \" \").replace(/[\\t\\n\\r]/g, \" \").indexOf(match) >= 0) ) {\n            if ( !inplace ) {\n              result.push( elem );\n            }\n\n          } else if ( inplace ) {\n            curLoop[i] = false;\n          }\n        }\n      }\n\n      return false;\n    },\n\n    ID: function( match ) {\n      return match[1].replace( rBackslash, \"\" );\n    },\n\n    TAG: function( match, curLoop ) {\n      return match[1].replace( rBackslash, \"\" ).toLowerCase();\n    },\n\n    CHILD: function( match ) {\n      if ( match[1] === \"nth\" ) {\n        if ( !match[2] ) {\n          Sizzle.error( match[0] );\n        }\n\n        match[2] = match[2].replace(/^\\+|\\s*/g, '');\n\n        // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\n        var test = /(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(\n          match[2] === \"even\" && \"2n\" || match[2] === \"odd\" && \"2n+1\" ||\n          !/\\D/.test( match[2] ) && \"0n+\" + match[2] || match[2]);\n\n        // calculate the numbers (first)n+(last) including if they are negative\n        match[2] = (test[1] + (test[2] || 1)) - 0;\n        match[3] = test[3] - 0;\n      }\n      else if ( match[2] ) {\n        Sizzle.error( match[0] );\n      }\n\n      // TODO: Move to normal caching system\n      match[0] = done++;\n\n      return match;\n    },\n\n    ATTR: function( match, curLoop, inplace, result, not, isXML ) {\n      var name = match[1] = match[1].replace( rBackslash, \"\" );\n\n      if ( !isXML && Expr.attrMap[name] ) {\n        match[1] = Expr.attrMap[name];\n      }\n\n      // Handle if an un-quoted value was used\n      match[4] = ( match[4] || match[5] || \"\" ).replace( rBackslash, \"\" );\n\n      if ( match[2] === \"~=\" ) {\n        match[4] = \" \" + match[4] + \" \";\n      }\n\n      return match;\n    },\n\n    PSEUDO: function( match, curLoop, inplace, result, not ) {\n      if ( match[1] === \"not\" ) {\n        // If we're dealing with a complex expression, or a simple one\n        if ( ( chunker.exec(match[3]) || \"\" ).length > 1 || /^\\w/.test(match[3]) ) {\n          match[3] = Sizzle(match[3], null, null, curLoop);\n\n        } else {\n          var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\n\n          if ( !inplace ) {\n            result.push.apply( result, ret );\n          }\n\n          return false;\n        }\n\n      } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\n        return true;\n      }\n\n      return match;\n    },\n\n    POS: function( match ) {\n      match.unshift( true );\n\n      return match;\n    }\n  },\n\n  filters: {\n    enabled: function( elem ) {\n      return elem.disabled === false && elem.type !== \"hidden\";\n    },\n\n    disabled: function( elem ) {\n      return elem.disabled === true;\n    },\n\n    checked: function( elem ) {\n      return elem.checked === true;\n    },\n\n    selected: function( elem ) {\n      // Accessing this property makes selected-by-default\n      // options in Safari work properly\n      if ( elem.parentNode ) {\n        elem.parentNode.selectedIndex;\n      }\n\n      return elem.selected === true;\n    },\n\n    parent: function( elem ) {\n      return !!elem.firstChild;\n    },\n\n    empty: function( elem ) {\n      return !elem.firstChild;\n    },\n\n    has: function( elem, i, match ) {\n      return !!Sizzle( match[3], elem ).length;\n    },\n\n    header: function( elem ) {\n      return (/h\\d/i).test( elem.nodeName );\n    },\n\n    text: function( elem ) {\n      var attr = elem.getAttribute( \"type\" ), type = elem.type;\n      // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)\n      // use getAttribute instead to test this case\n      return elem.nodeName.toLowerCase() === \"input\" && \"text\" === type && ( attr === type || attr === null );\n    },\n\n    radio: function( elem ) {\n      return elem.nodeName.toLowerCase() === \"input\" && \"radio\" === elem.type;\n    },\n\n    checkbox: function( elem ) {\n      return elem.nodeName.toLowerCase() === \"input\" && \"checkbox\" === elem.type;\n    },\n\n    file: function( elem ) {\n      return elem.nodeName.toLowerCase() === \"input\" && \"file\" === elem.type;\n    },\n\n    password: function( elem ) {\n      return elem.nodeName.toLowerCase() === \"input\" && \"password\" === elem.type;\n    },\n\n    submit: function( elem ) {\n      var name = elem.nodeName.toLowerCase();\n      return (name === \"input\" || name === \"button\") && \"submit\" === elem.type;\n    },\n\n    image: function( elem ) {\n      return elem.nodeName.toLowerCase() === \"input\" && \"image\" === elem.type;\n    },\n\n    reset: function( elem ) {\n      var name = elem.nodeName.toLowerCase();\n      return (name === \"input\" || name === \"button\") && \"reset\" === elem.type;\n    },\n\n    button: function( elem ) {\n      var name = elem.nodeName.toLowerCase();\n      return name === \"input\" && \"button\" === elem.type || name === \"button\";\n    },\n\n    input: function( elem ) {\n      return (/input|select|textarea|button/i).test( elem.nodeName );\n    },\n\n    focus: function( elem ) {\n      return elem === elem.ownerDocument.activeElement;\n    }\n  },\n  setFilters: {\n    first: function( elem, i ) {\n      return i === 0;\n    },\n\n    last: function( elem, i, match, array ) {\n      return i === array.length - 1;\n    },\n\n    even: function( elem, i ) {\n      return i % 2 === 0;\n    },\n\n    odd: function( elem, i ) {\n      return i % 2 === 1;\n    },\n\n    lt: function( elem, i, match ) {\n      return i < match[3] - 0;\n    },\n\n    gt: function( elem, i, match ) {\n      return i > match[3] - 0;\n    },\n\n    nth: function( elem, i, match ) {\n      return match[3] - 0 === i;\n    },\n\n    eq: function( elem, i, match ) {\n      return match[3] - 0 === i;\n    }\n  },\n  filter: {\n    PSEUDO: function( elem, match, i, array ) {\n      var name = match[1],\n        filter = Expr.filters[ name ];\n\n      if ( filter ) {\n        return filter( elem, i, match, array );\n\n      } else if ( name === \"contains\" ) {\n        return (elem.textContent || elem.innerText || getText([ elem ]) || \"\").indexOf(match[3]) >= 0;\n\n      } else if ( name === \"not\" ) {\n        var not = match[3];\n\n        for ( var j = 0, l = not.length; j < l; j++ ) {\n          if ( not[j] === elem ) {\n            return false;\n          }\n        }\n\n        return true;\n\n      } else {\n        Sizzle.error( name );\n      }\n    },\n\n    CHILD: function( elem, match ) {\n      var first, last,\n        doneName, parent, cache,\n        count, diff,\n        type = match[1],\n        node = elem;\n\n      switch ( type ) {\n        case \"only\":\n        case \"first\":\n          while ( (node = node.previousSibling) ) {\n            if ( node.nodeType === 1 ) {\n              return false;\n            }\n          }\n\n          if ( type === \"first\" ) {\n            return true;\n          }\n\n          node = elem;\n\n          /* falls through */\n        case \"last\":\n          while ( (node = node.nextSibling) ) {\n            if ( node.nodeType === 1 ) {\n              return false;\n            }\n          }\n\n          return true;\n\n        case \"nth\":\n          first = match[2];\n          last = match[3];\n\n          if ( first === 1 && last === 0 ) {\n            return true;\n          }\n\n          doneName = match[0];\n          parent = elem.parentNode;\n\n          if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {\n            count = 0;\n\n            for ( node = parent.firstChild; node; node = node.nextSibling ) {\n              if ( node.nodeType === 1 ) {\n                node.nodeIndex = ++count;\n              }\n            }\n\n            parent[ expando ] = doneName;\n          }\n\n          diff = elem.nodeIndex - last;\n\n          if ( first === 0 ) {\n            return diff === 0;\n\n          } else {\n            return ( diff % first === 0 && diff / first >= 0 );\n          }\n      }\n    },\n\n    ID: function( elem, match ) {\n      return elem.nodeType === 1 && elem.getAttribute(\"id\") === match;\n    },\n\n    TAG: function( elem, match ) {\n      return (match === \"*\" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;\n    },\n\n    CLASS: function( elem, match ) {\n      return (\" \" + (elem.className || elem.getAttribute(\"class\")) + \" \")\n        .indexOf( match ) > -1;\n    },\n\n    ATTR: function( elem, match ) {\n      var name = match[1],\n        result = Sizzle.attr ?\n          Sizzle.attr( elem, name ) :\n          Expr.attrHandle[ name ] ?\n          Expr.attrHandle[ name ]( elem ) :\n          elem[ name ] != null ?\n            elem[ name ] :\n            elem.getAttribute( name ),\n        value = result + \"\",\n        type = match[2],\n        check = match[4];\n\n      return result == null ?\n        type === \"!=\" :\n        !type && Sizzle.attr ?\n        result != null :\n        type === \"=\" ?\n        value === check :\n        type === \"*=\" ?\n        value.indexOf(check) >= 0 :\n        type === \"~=\" ?\n        (\" \" + value + \" \").indexOf(check) >= 0 :\n        !check ?\n        value && result !== false :\n        type === \"!=\" ?\n        value !== check :\n        type === \"^=\" ?\n        value.indexOf(check) === 0 :\n        type === \"$=\" ?\n        value.substr(value.length - check.length) === check :\n        type === \"|=\" ?\n        value === check || value.substr(0, check.length + 1) === check + \"-\" :\n        false;\n    },\n\n    POS: function( elem, match, i, array ) {\n      var name = match[2],\n        filter = Expr.setFilters[ name ];\n\n      if ( filter ) {\n        return filter( elem, i, match, array );\n      }\n    }\n  }\n};\n\nvar origPOS = Expr.match.POS,\n  fescape = function(all, num){\n    return \"\\\\\" + (num - 0 + 1);\n  };\n\nfor ( var type in Expr.match ) {\n  Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\\[]*\\])(?![^\\(]*\\))/.source) );\n  Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\\r|\\n)*?)/.source + Expr.match[ type ].source.replace(/\\\\(\\d+)/g, fescape) );\n}\n// Expose origPOS\n// \"global\" as in regardless of relation to brackets/parens\nExpr.match.globalPOS = origPOS;\n\nvar makeArray = function( array, results ) {\n  array = Array.prototype.slice.call( array, 0 );\n\n  if ( results ) {\n    results.push.apply( results, array );\n    return results;\n  }\n\n  return array;\n};\n\n// Perform a simple check to determine if the browser is capable of\n// converting a NodeList to an array using builtin methods.\n// Also verifies that the returned array holds DOM nodes\n// (which is not the case in the Blackberry browser)\ntry {\n  Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;\n\n// Provide a fallback method if it does not work\n} catch( e ) {\n  makeArray = function( array, results ) {\n    var i = 0,\n      ret = results || [];\n\n    if ( toString.call(array) === \"[object Array]\" ) {\n      Array.prototype.push.apply( ret, array );\n\n    } else {\n      if ( typeof array.length === \"number\" ) {\n        for ( var l = array.length; i < l; i++ ) {\n          ret.push( array[i] );\n        }\n\n      } else {\n        for ( ; array[i]; i++ ) {\n          ret.push( array[i] );\n        }\n      }\n    }\n\n    return ret;\n  };\n}\n\nvar sortOrder, siblingCheck;\n\nif ( document.documentElement.compareDocumentPosition ) {\n  sortOrder = function( a, b ) {\n    if ( a === b ) {\n      hasDuplicate = true;\n      return 0;\n    }\n\n    if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {\n      return a.compareDocumentPosition ? -1 : 1;\n    }\n\n    return a.compareDocumentPosition(b) & 4 ? -1 : 1;\n  };\n\n} else {\n  sortOrder = function( a, b ) {\n    // The nodes are identical, we can exit early\n    if ( a === b ) {\n      hasDuplicate = true;\n      return 0;\n\n    // Fallback to using sourceIndex (in IE) if it's available on both nodes\n    } else if ( a.sourceIndex && b.sourceIndex ) {\n      return a.sourceIndex - b.sourceIndex;\n    }\n\n    var al, bl,\n      ap = [],\n      bp = [],\n      aup = a.parentNode,\n      bup = b.parentNode,\n      cur = aup;\n\n    // If the nodes are siblings (or identical) we can do a quick check\n    if ( aup === bup ) {\n      return siblingCheck( a, b );\n\n    // If no parents were found then the nodes are disconnected\n    } else if ( !aup ) {\n      return -1;\n\n    } else if ( !bup ) {\n      return 1;\n    }\n\n    // Otherwise they're somewhere else in the tree so we need\n    // to build up a full list of the parentNodes for comparison\n    while ( cur ) {\n      ap.unshift( cur );\n      cur = cur.parentNode;\n    }\n\n    cur = bup;\n\n    while ( cur ) {\n      bp.unshift( cur );\n      cur = cur.parentNode;\n    }\n\n    al = ap.length;\n    bl = bp.length;\n\n    // Start walking down the tree looking for a discrepancy\n    for ( var i = 0; i < al && i < bl; i++ ) {\n      if ( ap[i] !== bp[i] ) {\n        return siblingCheck( ap[i], bp[i] );\n      }\n    }\n\n    // We ended someplace up the tree so do a sibling check\n    return i === al ?\n      siblingCheck( a, bp[i], -1 ) :\n      siblingCheck( ap[i], b, 1 );\n  };\n\n  siblingCheck = function( a, b, ret ) {\n    if ( a === b ) {\n      return ret;\n    }\n\n    var cur = a.nextSibling;\n\n    while ( cur ) {\n      if ( cur === b ) {\n        return -1;\n      }\n\n      cur = cur.nextSibling;\n    }\n\n    return 1;\n  };\n}\n\n// Check to see if the browser returns elements by name when\n// querying by getElementById (and provide a workaround)\n(function(){\n  // We're going to inject a fake input element with a specified name\n  var form = document.createElement(\"div\"),\n    id = \"script\" + (new Date()).getTime(),\n    root = document.documentElement;\n\n  form.innerHTML = \"<a name='\" + id + \"'/>\";\n\n  // Inject it into the root element, check its status, and remove it quickly\n  root.insertBefore( form, root.firstChild );\n\n  // The workaround has to do additional checks after a getElementById\n  // Which slows things down for other browsers (hence the branching)\n  if ( document.getElementById( id ) ) {\n    Expr.find.ID = function( match, context, isXML ) {\n      if ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n        var m = context.getElementById(match[1]);\n\n        return m ?\n          m.id === match[1] || typeof m.getAttributeNode !== \"undefined\" && m.getAttributeNode(\"id\").nodeValue === match[1] ?\n            [m] :\n            undefined :\n          [];\n      }\n    };\n\n    Expr.filter.ID = function( elem, match ) {\n      var node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\n      return elem.nodeType === 1 && node && node.nodeValue === match;\n    };\n  }\n\n  root.removeChild( form );\n\n  // release memory in IE\n  root = form = null;\n})();\n\n(function(){\n  // Check to see if the browser returns only elements\n  // when doing getElementsByTagName(\"*\")\n\n  // Create a fake element\n  var div = document.createElement(\"div\");\n  div.appendChild( document.createComment(\"\") );\n\n  // Make sure no comments are found\n  if ( div.getElementsByTagName(\"*\").length > 0 ) {\n    Expr.find.TAG = function( match, context ) {\n      var results = context.getElementsByTagName( match[1] );\n\n      // Filter out possible comments\n      if ( match[1] === \"*\" ) {\n        var tmp = [];\n\n        for ( var i = 0; results[i]; i++ ) {\n          if ( results[i].nodeType === 1 ) {\n            tmp.push( results[i] );\n          }\n        }\n\n        results = tmp;\n      }\n\n      return results;\n    };\n  }\n\n  // Check to see if an attribute returns normalized href attributes\n  div.innerHTML = \"<a href='#'></a>\";\n\n  if ( div.firstChild && typeof div.firstChild.getAttribute !== \"undefined\" &&\n      div.firstChild.getAttribute(\"href\") !== \"#\" ) {\n\n    Expr.attrHandle.href = function( elem ) {\n      return elem.getAttribute( \"href\", 2 );\n    };\n  }\n\n  // release memory in IE\n  div = null;\n})();\n\nif ( document.querySelectorAll ) {\n  (function(){\n    var oldSizzle = Sizzle,\n      div = document.createElement(\"div\"),\n      id = \"__sizzle__\";\n\n    div.innerHTML = \"<p class='TEST'></p>\";\n\n    // Safari can't handle uppercase or unicode characters when\n    // in quirks mode.\n    if ( div.querySelectorAll && div.querySelectorAll(\".TEST\").length === 0 ) {\n      return;\n    }\n\n    Sizzle = function( query, context, extra, seed ) {\n      context = context || document;\n\n      // Only use querySelectorAll on non-XML documents\n      // (ID selectors don't work in non-HTML documents)\n      if ( !seed && !Sizzle.isXML(context) ) {\n        // See if we find a selector to speed up\n        var match = /^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec( query );\n\n        if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {\n          // Speed-up: Sizzle(\"TAG\")\n          if ( match[1] ) {\n            return makeArray( context.getElementsByTagName( query ), extra );\n\n          // Speed-up: Sizzle(\".CLASS\")\n          } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {\n            return makeArray( context.getElementsByClassName( match[2] ), extra );\n          }\n        }\n\n        if ( context.nodeType === 9 ) {\n          // Speed-up: Sizzle(\"body\")\n          // The body element only exists once, optimize finding it\n          if ( query === \"body\" && context.body ) {\n            return makeArray( [ context.body ], extra );\n\n          // Speed-up: Sizzle(\"#ID\")\n          } else if ( match && match[3] ) {\n            var elem = context.getElementById( match[3] );\n\n            // Check parentNode to catch when Blackberry 4.6 returns\n            // nodes that are no longer in the document #6963\n            if ( elem && elem.parentNode ) {\n              // Handle the case where IE and Opera return items\n              // by name instead of ID\n              if ( elem.id === match[3] ) {\n                return makeArray( [ elem ], extra );\n              }\n\n            } else {\n              return makeArray( [], extra );\n            }\n          }\n\n          try {\n            return makeArray( context.querySelectorAll(query), extra );\n          } catch(qsaError) {}\n\n        // qSA works strangely on Element-rooted queries\n        // We can work around this by specifying an extra ID on the root\n        // and working up from there (Thanks to Andrew Dupont for the technique)\n        // IE 8 doesn't work on object elements\n        } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n          var oldContext = context,\n            old = context.getAttribute( \"id\" ),\n            nid = old || id,\n            hasParent = context.parentNode,\n            relativeHierarchySelector = /^\\s*[+~]/.test( query );\n\n          if ( !old ) {\n            context.setAttribute( \"id\", nid );\n          } else {\n            nid = nid.replace( /'/g, \"\\\\$&\" );\n          }\n          if ( relativeHierarchySelector && hasParent ) {\n            context = context.parentNode;\n          }\n\n          try {\n            if ( !relativeHierarchySelector || hasParent ) {\n              return makeArray( context.querySelectorAll( \"[id='\" + nid + \"'] \" + query ), extra );\n            }\n\n          } catch(pseudoError) {\n          } finally {\n            if ( !old ) {\n              oldContext.removeAttribute( \"id\" );\n            }\n          }\n        }\n      }\n\n      return oldSizzle(query, context, extra, seed);\n    };\n\n    for ( var prop in oldSizzle ) {\n      Sizzle[ prop ] = oldSizzle[ prop ];\n    }\n\n    // release memory in IE\n    div = null;\n  })();\n}\n\n(function(){\n  var html = document.documentElement,\n    matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;\n\n  if ( matches ) {\n    // Check to see if it's possible to do matchesSelector\n    // on a disconnected node (IE 9 fails this)\n    var disconnectedMatch = !matches.call( document.createElement( \"div\" ), \"div\" ),\n      pseudoWorks = false;\n\n    try {\n      // This should fail with an exception\n      // Gecko does not error, returns false instead\n      matches.call( document.documentElement, \"[test!='']:sizzle\" );\n\n    } catch( pseudoError ) {\n      pseudoWorks = true;\n    }\n\n    Sizzle.matchesSelector = function( node, expr ) {\n      // Make sure that attribute selectors are quoted\n      expr = expr.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g, \"='$1']\");\n\n      if ( !Sizzle.isXML( node ) ) {\n        try {\n          if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {\n            var ret = matches.call( node, expr );\n\n            // IE 9's matchesSelector returns false on disconnected nodes\n            if ( ret || !disconnectedMatch ||\n                // As well, disconnected nodes are said to be in a document\n                // fragment in IE 9, so check for that\n                node.document && node.document.nodeType !== 11 ) {\n              return ret;\n            }\n          }\n        } catch(e) {}\n      }\n\n      return Sizzle(expr, null, null, [node]).length > 0;\n    };\n  }\n})();\n\n(function(){\n  var div = document.createElement(\"div\");\n\n  div.innerHTML = \"<div class='test e'></div><div class='test'></div>\";\n\n  // Opera can't find a second classname (in 9.6)\n  // Also, make sure that getElementsByClassName actually exists\n  if ( !div.getElementsByClassName || div.getElementsByClassName(\"e\").length === 0 ) {\n    return;\n  }\n\n  // Safari caches class attributes, doesn't catch changes (in 3.2)\n  div.lastChild.className = \"e\";\n\n  if ( div.getElementsByClassName(\"e\").length === 1 ) {\n    return;\n  }\n\n  Expr.order.splice(1, 0, \"CLASS\");\n  Expr.find.CLASS = function( match, context, isXML ) {\n    if ( typeof context.getElementsByClassName !== \"undefined\" && !isXML ) {\n      return context.getElementsByClassName(match[1]);\n    }\n  };\n\n  // release memory in IE\n  div = null;\n})();\n\nfunction dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n  for ( var i = 0, l = checkSet.length; i < l; i++ ) {\n    var elem = checkSet[i];\n\n    if ( elem ) {\n      var match = false;\n\n      elem = elem[dir];\n\n      while ( elem ) {\n        if ( elem[ expando ] === doneName ) {\n          match = checkSet[elem.sizset];\n          break;\n        }\n\n        if ( elem.nodeType === 1 && !isXML ){\n          elem[ expando ] = doneName;\n          elem.sizset = i;\n        }\n\n        if ( elem.nodeName.toLowerCase() === cur ) {\n          match = elem;\n          break;\n        }\n\n        elem = elem[dir];\n      }\n\n      checkSet[i] = match;\n    }\n  }\n}\n\nfunction dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n  for ( var i = 0, l = checkSet.length; i < l; i++ ) {\n    var elem = checkSet[i];\n\n    if ( elem ) {\n      var match = false;\n\n      elem = elem[dir];\n\n      while ( elem ) {\n        if ( elem[ expando ] === doneName ) {\n          match = checkSet[elem.sizset];\n          break;\n        }\n\n        if ( elem.nodeType === 1 ) {\n          if ( !isXML ) {\n            elem[ expando ] = doneName;\n            elem.sizset = i;\n          }\n\n          if ( typeof cur !== \"string\" ) {\n            if ( elem === cur ) {\n              match = true;\n              break;\n            }\n\n          } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\n            match = elem;\n            break;\n          }\n        }\n\n        elem = elem[dir];\n      }\n\n      checkSet[i] = match;\n    }\n  }\n}\n\nif ( document.documentElement.contains ) {\n  Sizzle.contains = function( a, b ) {\n    return a !== b && (a.contains ? a.contains(b) : true);\n  };\n\n} else if ( document.documentElement.compareDocumentPosition ) {\n  Sizzle.contains = function( a, b ) {\n    return !!(a.compareDocumentPosition(b) & 16);\n  };\n\n} else {\n  Sizzle.contains = function() {\n    return false;\n  };\n}\n\nSizzle.isXML = function( elem ) {\n  // documentElement is verified for cases where it doesn't yet exist\n  // (such as loading iframes in IE - #4833)\n  var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;\n\n  return documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\nvar posProcess = function( selector, context, seed ) {\n  var match,\n    tmpSet = [],\n    later = \"\",\n    root = context.nodeType ? [context] : context;\n\n  // Position selectors must be done after the filter\n  // And so must :not(positional) so we move all PSEUDOs to the end\n  while ( (match = Expr.match.PSEUDO.exec( selector )) ) {\n    later += match[0];\n    selector = selector.replace( Expr.match.PSEUDO, \"\" );\n  }\n\n  selector = Expr.relative[selector] ? selector + \"*\" : selector;\n\n  for ( var i = 0, l = root.length; i < l; i++ ) {\n    Sizzle( selector, root[i], tmpSet, seed );\n  }\n\n  return Sizzle.filter( later, tmpSet );\n};\n\n// EXPOSE\n// Override sizzle attribute retrieval\nSizzle.attr = jQuery.attr;\nSizzle.selectors.attrMap = {};\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.filters;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n})();\n\n\nvar runtil = /Until$/,\n  rparentsprev = /^(?:parents|prevUntil|prevAll)/,\n  // Note: This RegExp should be improved, or likely pulled from Sizzle\n  rmultiselector = /,/,\n  isSimple = /^.[^:#\\[\\.,]*$/,\n  slice = Array.prototype.slice,\n  POS = jQuery.expr.match.globalPOS,\n  // methods guaranteed to produce a unique set when starting from a unique set\n  guaranteedUnique = {\n    children: true,\n    contents: true,\n    next: true,\n    prev: true\n  };\n\njQuery.fn.extend({\n  find: function( selector ) {\n    var self = this,\n      i, l;\n\n    if ( typeof selector !== \"string\" ) {\n      return jQuery( selector ).filter(function() {\n        for ( i = 0, l = self.length; i < l; i++ ) {\n          if ( jQuery.contains( self[ i ], this ) ) {\n            return true;\n          }\n        }\n      });\n    }\n\n    var ret = this.pushStack( \"\", \"find\", selector ),\n      length, n, r;\n\n    for ( i = 0, l = this.length; i < l; i++ ) {\n      length = ret.length;\n      jQuery.find( selector, this[i], ret );\n\n      if ( i > 0 ) {\n        // Make sure that the results are unique\n        for ( n = length; n < ret.length; n++ ) {\n          for ( r = 0; r < length; r++ ) {\n            if ( ret[r] === ret[n] ) {\n              ret.splice(n--, 1);\n              break;\n            }\n          }\n        }\n      }\n    }\n\n    return ret;\n  },\n\n  has: function( target ) {\n    var targets = jQuery( target );\n    return this.filter(function() {\n      for ( var i = 0, l = targets.length; i < l; i++ ) {\n        if ( jQuery.contains( this, targets[i] ) ) {\n          return true;\n        }\n      }\n    });\n  },\n\n  not: function( selector ) {\n    return this.pushStack( winnow(this, selector, false), \"not\", selector);\n  },\n\n  filter: function( selector ) {\n    return this.pushStack( winnow(this, selector, true), \"filter\", selector );\n  },\n\n  is: function( selector ) {\n    return !!selector && (\n      typeof selector === \"string\" ?\n        // If this is a positional selector, check membership in the returned set\n        // so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n        POS.test( selector ) ?\n          jQuery( selector, this.context ).index( this[0] ) >= 0 :\n          jQuery.filter( selector, this ).length > 0 :\n        this.filter( selector ).length > 0 );\n  },\n\n  closest: function( selectors, context ) {\n    var ret = [], i, l, cur = this[0];\n\n    // Array (deprecated as of jQuery 1.7)\n    if ( jQuery.isArray( selectors ) ) {\n      var level = 1;\n\n      while ( cur && cur.ownerDocument && cur !== context ) {\n        for ( i = 0; i < selectors.length; i++ ) {\n\n          if ( jQuery( cur ).is( selectors[ i ] ) ) {\n            ret.push({ selector: selectors[ i ], elem: cur, level: level });\n          }\n        }\n\n        cur = cur.parentNode;\n        level++;\n      }\n\n      return ret;\n    }\n\n    // String\n    var pos = POS.test( selectors ) || typeof selectors !== \"string\" ?\n        jQuery( selectors, context || this.context ) :\n        0;\n\n    for ( i = 0, l = this.length; i < l; i++ ) {\n      cur = this[i];\n\n      while ( cur ) {\n        if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n          ret.push( cur );\n          break;\n\n        } else {\n          cur = cur.parentNode;\n          if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {\n            break;\n          }\n        }\n      }\n    }\n\n    ret = ret.length > 1 ? jQuery.unique( ret ) : ret;\n\n    return this.pushStack( ret, \"closest\", selectors );\n  },\n\n  // Determine the position of an element within\n  // the matched set of elements\n  index: function( elem ) {\n\n    // No argument, return index in parent\n    if ( !elem ) {\n      return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;\n    }\n\n    // index in selector\n    if ( typeof elem === \"string\" ) {\n      return jQuery.inArray( this[0], jQuery( elem ) );\n    }\n\n    // Locate the position of the desired element\n    return jQuery.inArray(\n      // If it receives a jQuery object, the first element is used\n      elem.jquery ? elem[0] : elem, this );\n  },\n\n  add: function( selector, context ) {\n    var set = typeof selector === \"string\" ?\n        jQuery( selector, context ) :\n        jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),\n      all = jQuery.merge( this.get(), set );\n\n    return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?\n      all :\n      jQuery.unique( all ) );\n  },\n\n  andSelf: function() {\n    return this.add( this.prevObject );\n  }\n});\n\n// A painfully simple check to see if an element is disconnected\n// from a document (should be improved, where feasible).\nfunction isDisconnected( node ) {\n  return !node || !node.parentNode || node.parentNode.nodeType === 11;\n}\n\njQuery.each({\n  parent: function( elem ) {\n    var parent = elem.parentNode;\n    return parent && parent.nodeType !== 11 ? parent : null;\n  },\n  parents: function( elem ) {\n    return jQuery.dir( elem, \"parentNode\" );\n  },\n  parentsUntil: function( elem, i, until ) {\n    return jQuery.dir( elem, \"parentNode\", until );\n  },\n  next: function( elem ) {\n    return jQuery.nth( elem, 2, \"nextSibling\" );\n  },\n  prev: function( elem ) {\n    return jQuery.nth( elem, 2, \"previousSibling\" );\n  },\n  nextAll: function( elem ) {\n    return jQuery.dir( elem, \"nextSibling\" );\n  },\n  prevAll: function( elem ) {\n    return jQuery.dir( elem, \"previousSibling\" );\n  },\n  nextUntil: function( elem, i, until ) {\n    return jQuery.dir( elem, \"nextSibling\", until );\n  },\n  prevUntil: function( elem, i, until ) {\n    return jQuery.dir( elem, \"previousSibling\", until );\n  },\n  siblings: function( elem ) {\n    return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n  },\n  children: function( elem ) {\n    return jQuery.sibling( elem.firstChild );\n  },\n  contents: function( elem ) {\n    return jQuery.nodeName( elem, \"iframe\" ) ?\n      elem.contentDocument || elem.contentWindow.document :\n      jQuery.makeArray( elem.childNodes );\n  }\n}, function( name, fn ) {\n  jQuery.fn[ name ] = function( until, selector ) {\n    var ret = jQuery.map( this, fn, until );\n\n    if ( !runtil.test( name ) ) {\n      selector = until;\n    }\n\n    if ( selector && typeof selector === \"string\" ) {\n      ret = jQuery.filter( selector, ret );\n    }\n\n    ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n    if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {\n      ret = ret.reverse();\n    }\n\n    return this.pushStack( ret, name, slice.call( arguments ).join(\",\") );\n  };\n});\n\njQuery.extend({\n  filter: function( expr, elems, not ) {\n    if ( not ) {\n      expr = \":not(\" + expr + \")\";\n    }\n\n    return elems.length === 1 ?\n      jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n      jQuery.find.matches(expr, elems);\n  },\n\n  dir: function( elem, dir, until ) {\n    var matched = [],\n      cur = elem[ dir ];\n\n    while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n      if ( cur.nodeType === 1 ) {\n        matched.push( cur );\n      }\n      cur = cur[dir];\n    }\n    return matched;\n  },\n\n  nth: function( cur, result, dir, elem ) {\n    result = result || 1;\n    var num = 0;\n\n    for ( ; cur; cur = cur[dir] ) {\n      if ( cur.nodeType === 1 && ++num === result ) {\n        break;\n      }\n    }\n\n    return cur;\n  },\n\n  sibling: function( n, elem ) {\n    var r = [];\n\n    for ( ; n; n = n.nextSibling ) {\n      if ( n.nodeType === 1 && n !== elem ) {\n        r.push( n );\n      }\n    }\n\n    return r;\n  }\n});\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, keep ) {\n\n  // Can't pass null or undefined to indexOf in Firefox 4\n  // Set to 0 to skip string check\n  qualifier = qualifier || 0;\n\n  if ( jQuery.isFunction( qualifier ) ) {\n    return jQuery.grep(elements, function( elem, i ) {\n      var retVal = !!qualifier.call( elem, i, elem );\n      return retVal === keep;\n    });\n\n  } else if ( qualifier.nodeType ) {\n    return jQuery.grep(elements, function( elem, i ) {\n      return ( elem === qualifier ) === keep;\n    });\n\n  } else if ( typeof qualifier === \"string\" ) {\n    var filtered = jQuery.grep(elements, function( elem ) {\n      return elem.nodeType === 1;\n    });\n\n    if ( isSimple.test( qualifier ) ) {\n      return jQuery.filter(qualifier, filtered, !keep);\n    } else {\n      qualifier = jQuery.filter( qualifier, filtered );\n    }\n  }\n\n  return jQuery.grep(elements, function( elem, i ) {\n    return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;\n  });\n}\n\n\n\n\nfunction createSafeFragment( document ) {\n  var list = nodeNames.split( \"|\" ),\n  safeFrag = document.createDocumentFragment();\n\n  if ( safeFrag.createElement ) {\n    while ( list.length ) {\n      safeFrag.createElement(\n        list.pop()\n      );\n    }\n  }\n  return safeFrag;\n}\n\nvar nodeNames = \"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|\" +\n    \"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",\n  rinlinejQuery = / jQuery\\d+=\"(?:\\d+|null)\"/g,\n  rleadingWhitespace = /^\\s+/,\n  rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,\n  rtagName = /<([\\w:]+)/,\n  rtbody = /<tbody/i,\n  rhtml = /<|&#?\\w+;/,\n  rnoInnerhtml = /<(?:script|style)/i,\n  rnocache = /<(?:script|object|embed|option|style)/i,\n  rnoshimcache = new RegExp(\"<(?:\" + nodeNames + \")[\\\\s/>]\", \"i\"),\n  // checked=\"checked\" or checked\n  rchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n  rscriptType = /\\/(java|ecma)script/i,\n  rcleanScript = /^\\s*<!(?:\\[CDATA\\[|\\-\\-)/,\n  wrapMap = {\n    option: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n    legend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n    thead: [ 1, \"<table>\", \"</table>\" ],\n    tr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n    td: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n    col: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n    area: [ 1, \"<map>\", \"</map>\" ],\n    _default: [ 0, \"\", \"\" ]\n  },\n  safeFragment = createSafeFragment( document );\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// IE can't serialize <link> and <script> tags normally\nif ( !jQuery.support.htmlSerialize ) {\n  wrapMap._default = [ 1, \"div<div>\", \"</div>\" ];\n}\n\njQuery.fn.extend({\n  text: function( value ) {\n    return jQuery.access( this, function( value ) {\n      return value === undefined ?\n        jQuery.text( this ) :\n        this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );\n    }, null, value, arguments.length );\n  },\n\n  wrapAll: function( html ) {\n    if ( jQuery.isFunction( html ) ) {\n      return this.each(function(i) {\n        jQuery(this).wrapAll( html.call(this, i) );\n      });\n    }\n\n    if ( this[0] ) {\n      // The elements to wrap the target around\n      var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n      if ( this[0].parentNode ) {\n        wrap.insertBefore( this[0] );\n      }\n\n      wrap.map(function() {\n        var elem = this;\n\n        while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n          elem = elem.firstChild;\n        }\n\n        return elem;\n      }).append( this );\n    }\n\n    return this;\n  },\n\n  wrapInner: function( html ) {\n    if ( jQuery.isFunction( html ) ) {\n      return this.each(function(i) {\n        jQuery(this).wrapInner( html.call(this, i) );\n      });\n    }\n\n    return this.each(function() {\n      var self = jQuery( this ),\n        contents = self.contents();\n\n      if ( contents.length ) {\n        contents.wrapAll( html );\n\n      } else {\n        self.append( html );\n      }\n    });\n  },\n\n  wrap: function( html ) {\n    var isFunction = jQuery.isFunction( html );\n\n    return this.each(function(i) {\n      jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n    });\n  },\n\n  unwrap: function() {\n    return this.parent().each(function() {\n      if ( !jQuery.nodeName( this, \"body\" ) ) {\n        jQuery( this ).replaceWith( this.childNodes );\n      }\n    }).end();\n  },\n\n  append: function() {\n    return this.domManip(arguments, true, function( elem ) {\n      if ( this.nodeType === 1 ) {\n        this.appendChild( elem );\n      }\n    });\n  },\n\n  prepend: function() {\n    return this.domManip(arguments, true, function( elem ) {\n      if ( this.nodeType === 1 ) {\n        this.insertBefore( elem, this.firstChild );\n      }\n    });\n  },\n\n  before: function() {\n    if ( this[0] && this[0].parentNode ) {\n      return this.domManip(arguments, false, function( elem ) {\n        this.parentNode.insertBefore( elem, this );\n      });\n    } else if ( arguments.length ) {\n      var set = jQuery.clean( arguments );\n      set.push.apply( set, this.toArray() );\n      return this.pushStack( set, \"before\", arguments );\n    }\n  },\n\n  after: function() {\n    if ( this[0] && this[0].parentNode ) {\n      return this.domManip(arguments, false, function( elem ) {\n        this.parentNode.insertBefore( elem, this.nextSibling );\n      });\n    } else if ( arguments.length ) {\n      var set = this.pushStack( this, \"after\", arguments );\n      set.push.apply( set, jQuery.clean(arguments) );\n      return set;\n    }\n  },\n\n  // keepData is for internal use only--do not document\n  remove: function( selector, keepData ) {\n    for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n      if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {\n        if ( !keepData && elem.nodeType === 1 ) {\n          jQuery.cleanData( elem.getElementsByTagName(\"*\") );\n          jQuery.cleanData( [ elem ] );\n        }\n\n        if ( elem.parentNode ) {\n          elem.parentNode.removeChild( elem );\n        }\n      }\n    }\n\n    return this;\n  },\n\n  empty: function() {\n    for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n      // Remove element nodes and prevent memory leaks\n      if ( elem.nodeType === 1 ) {\n        jQuery.cleanData( elem.getElementsByTagName(\"*\") );\n      }\n\n      // Remove any remaining nodes\n      while ( elem.firstChild ) {\n        elem.removeChild( elem.firstChild );\n      }\n    }\n\n    return this;\n  },\n\n  clone: function( dataAndEvents, deepDataAndEvents ) {\n    dataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n    deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n    return this.map( function () {\n      return jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n    });\n  },\n\n  html: function( value ) {\n    return jQuery.access( this, function( value ) {\n      var elem = this[0] || {},\n        i = 0,\n        l = this.length;\n\n      if ( value === undefined ) {\n        return elem.nodeType === 1 ?\n          elem.innerHTML.replace( rinlinejQuery, \"\" ) :\n          null;\n      }\n\n\n      if ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n        ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&\n        !wrapMap[ ( rtagName.exec( value ) || [\"\", \"\"] )[1].toLowerCase() ] ) {\n\n        value = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n        try {\n          for (; i < l; i++ ) {\n            // Remove element nodes and prevent memory leaks\n            elem = this[i] || {};\n            if ( elem.nodeType === 1 ) {\n              jQuery.cleanData( elem.getElementsByTagName( \"*\" ) );\n              elem.innerHTML = value;\n            }\n          }\n\n          elem = 0;\n\n        // If using innerHTML throws an exception, use the fallback method\n        } catch(e) {}\n      }\n\n      if ( elem ) {\n        this.empty().append( value );\n      }\n    }, null, value, arguments.length );\n  },\n\n  replaceWith: function( value ) {\n    if ( this[0] && this[0].parentNode ) {\n      // Make sure that the elements are removed from the DOM before they are inserted\n      // this can help fix replacing a parent with child elements\n      if ( jQuery.isFunction( value ) ) {\n        return this.each(function(i) {\n          var self = jQuery(this), old = self.html();\n          self.replaceWith( value.call( this, i, old ) );\n        });\n      }\n\n      if ( typeof value !== \"string\" ) {\n        value = jQuery( value ).detach();\n      }\n\n      return this.each(function() {\n        var next = this.nextSibling,\n          parent = this.parentNode;\n\n        jQuery( this ).remove();\n\n        if ( next ) {\n          jQuery(next).before( value );\n        } else {\n          jQuery(parent).append( value );\n        }\n      });\n    } else {\n      return this.length ?\n        this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), \"replaceWith\", value ) :\n        this;\n    }\n  },\n\n  detach: function( selector ) {\n    return this.remove( selector, true );\n  },\n\n  domManip: function( args, table, callback ) {\n    var results, first, fragment, parent,\n      value = args[0],\n      scripts = [];\n\n    // We can't cloneNode fragments that contain checked, in WebKit\n    if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === \"string\" && rchecked.test( value ) ) {\n      return this.each(function() {\n        jQuery(this).domManip( args, table, callback, true );\n      });\n    }\n\n    if ( jQuery.isFunction(value) ) {\n      return this.each(function(i) {\n        var self = jQuery(this);\n        args[0] = value.call(this, i, table ? self.html() : undefined);\n        self.domManip( args, table, callback );\n      });\n    }\n\n    if ( this[0] ) {\n      parent = value && value.parentNode;\n\n      // If we're in a fragment, just use that instead of building a new one\n      if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {\n        results = { fragment: parent };\n\n      } else {\n        results = jQuery.buildFragment( args, this, scripts );\n      }\n\n      fragment = results.fragment;\n\n      if ( fragment.childNodes.length === 1 ) {\n        first = fragment = fragment.firstChild;\n      } else {\n        first = fragment.firstChild;\n      }\n\n      if ( first ) {\n        table = table && jQuery.nodeName( first, \"tr\" );\n\n        for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {\n          callback.call(\n            table ?\n              root(this[i], first) :\n              this[i],\n            // Make sure that we do not leak memory by inadvertently discarding\n            // the original fragment (which might have attached data) instead of\n            // using it; in addition, use the original fragment object for the last\n            // item instead of first because it can end up being emptied incorrectly\n            // in certain situations (Bug #8070).\n            // Fragments from the fragment cache must always be cloned and never used\n            // in place.\n            results.cacheable || ( l > 1 && i < lastIndex ) ?\n              jQuery.clone( fragment, true, true ) :\n              fragment\n          );\n        }\n      }\n\n      if ( scripts.length ) {\n        jQuery.each( scripts, function( i, elem ) {\n          if ( elem.src ) {\n            jQuery.ajax({\n              type: \"GET\",\n              global: false,\n              url: elem.src,\n              async: false,\n              dataType: \"script\"\n            });\n          } else {\n            jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || \"\" ).replace( rcleanScript, \"/*$0*/\" ) );\n          }\n\n          if ( elem.parentNode ) {\n            elem.parentNode.removeChild( elem );\n          }\n        });\n      }\n    }\n\n    return this;\n  }\n});\n\nfunction root( elem, cur ) {\n  return jQuery.nodeName(elem, \"table\") ?\n    (elem.getElementsByTagName(\"tbody\")[0] ||\n    elem.appendChild(elem.ownerDocument.createElement(\"tbody\"))) :\n    elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n  if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n    return;\n  }\n\n  var type, i, l,\n    oldData = jQuery._data( src ),\n    curData = jQuery._data( dest, oldData ),\n    events = oldData.events;\n\n  if ( events ) {\n    delete curData.handle;\n    curData.events = {};\n\n    for ( type in events ) {\n      for ( i = 0, l = events[ type ].length; i < l; i++ ) {\n        jQuery.event.add( dest, type, events[ type ][ i ] );\n      }\n    }\n  }\n\n  // make the cloned public data object a copy from the original\n  if ( curData.data ) {\n    curData.data = jQuery.extend( {}, curData.data );\n  }\n}\n\nfunction cloneFixAttributes( src, dest ) {\n  var nodeName;\n\n  // We do not need to do anything for non-Elements\n  if ( dest.nodeType !== 1 ) {\n    return;\n  }\n\n  // clearAttributes removes the attributes, which we don't want,\n  // but also removes the attachEvent events, which we *do* want\n  if ( dest.clearAttributes ) {\n    dest.clearAttributes();\n  }\n\n  // mergeAttributes, in contrast, only merges back on the\n  // original attributes, not the events\n  if ( dest.mergeAttributes ) {\n    dest.mergeAttributes( src );\n  }\n\n  nodeName = dest.nodeName.toLowerCase();\n\n  // IE6-8 fail to clone children inside object elements that use\n  // the proprietary classid attribute value (rather than the type\n  // attribute) to identify the type of content to display\n  if ( nodeName === \"object\" ) {\n    dest.outerHTML = src.outerHTML;\n\n  } else if ( nodeName === \"input\" && (src.type === \"checkbox\" || src.type === \"radio\") ) {\n    // IE6-8 fails to persist the checked state of a cloned checkbox\n    // or radio button. Worse, IE6-7 fail to give the cloned element\n    // a checked appearance if the defaultChecked value isn't also set\n    if ( src.checked ) {\n      dest.defaultChecked = dest.checked = src.checked;\n    }\n\n    // IE6-7 get confused and end up setting the value of a cloned\n    // checkbox/radio button to an empty string instead of \"on\"\n    if ( dest.value !== src.value ) {\n      dest.value = src.value;\n    }\n\n  // IE6-8 fails to return the selected option to the default selected\n  // state when cloning options\n  } else if ( nodeName === \"option\" ) {\n    dest.selected = src.defaultSelected;\n\n  // IE6-8 fails to set the defaultValue to the correct value when\n  // cloning other types of input fields\n  } else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n    dest.defaultValue = src.defaultValue;\n\n  // IE blanks contents when cloning scripts\n  } else if ( nodeName === \"script\" && dest.text !== src.text ) {\n    dest.text = src.text;\n  }\n\n  // Event data gets referenced instead of copied if the expando\n  // gets copied too\n  dest.removeAttribute( jQuery.expando );\n\n  // Clear flags for bubbling special change/submit events, they must\n  // be reattached when the newly cloned events are first activated\n  dest.removeAttribute( \"_submit_attached\" );\n  dest.removeAttribute( \"_change_attached\" );\n}\n\njQuery.buildFragment = function( args, nodes, scripts ) {\n  var fragment, cacheable, cacheresults, doc,\n  first = args[ 0 ];\n\n  // nodes may contain either an explicit document object,\n  // a jQuery collection or context object.\n  // If nodes[0] contains a valid object to assign to doc\n  if ( nodes && nodes[0] ) {\n    doc = nodes[0].ownerDocument || nodes[0];\n  }\n\n  // Ensure that an attr object doesn't incorrectly stand in as a document object\n  // Chrome and Firefox seem to allow this to occur and will throw exception\n  // Fixes #8950\n  if ( !doc.createDocumentFragment ) {\n    doc = document;\n  }\n\n  // Only cache \"small\" (1/2 KB) HTML strings that are associated with the main document\n  // Cloning options loses the selected state, so don't cache them\n  // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment\n  // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache\n  // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501\n  if ( args.length === 1 && typeof first === \"string\" && first.length < 512 && doc === document &&\n    first.charAt(0) === \"<\" && !rnocache.test( first ) &&\n    (jQuery.support.checkClone || !rchecked.test( first )) &&\n    (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {\n\n    cacheable = true;\n\n    cacheresults = jQuery.fragments[ first ];\n    if ( cacheresults && cacheresults !== 1 ) {\n      fragment = cacheresults;\n    }\n  }\n\n  if ( !fragment ) {\n    fragment = doc.createDocumentFragment();\n    jQuery.clean( args, doc, fragment, scripts );\n  }\n\n  if ( cacheable ) {\n    jQuery.fragments[ first ] = cacheresults ? fragment : 1;\n  }\n\n  return { fragment: fragment, cacheable: cacheable };\n};\n\njQuery.fragments = {};\n\njQuery.each({\n  appendTo: \"append\",\n  prependTo: \"prepend\",\n  insertBefore: \"before\",\n  insertAfter: \"after\",\n  replaceAll: \"replaceWith\"\n}, function( name, original ) {\n  jQuery.fn[ name ] = function( selector ) {\n    var ret = [],\n      insert = jQuery( selector ),\n      parent = this.length === 1 && this[0].parentNode;\n\n    if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {\n      insert[ original ]( this[0] );\n      return this;\n\n    } else {\n      for ( var i = 0, l = insert.length; i < l; i++ ) {\n        var elems = ( i > 0 ? this.clone(true) : this ).get();\n        jQuery( insert[i] )[ original ]( elems );\n        ret = ret.concat( elems );\n      }\n\n      return this.pushStack( ret, name, insert.selector );\n    }\n  };\n});\n\nfunction getAll( elem ) {\n  if ( typeof elem.getElementsByTagName !== \"undefined\" ) {\n    return elem.getElementsByTagName( \"*\" );\n\n  } else if ( typeof elem.querySelectorAll !== \"undefined\" ) {\n    return elem.querySelectorAll( \"*\" );\n\n  } else {\n    return [];\n  }\n}\n\n// Used in clean, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n  if ( elem.type === \"checkbox\" || elem.type === \"radio\" ) {\n    elem.defaultChecked = elem.checked;\n  }\n}\n// Finds all inputs and passes them to fixDefaultChecked\nfunction findInputs( elem ) {\n  var nodeName = ( elem.nodeName || \"\" ).toLowerCase();\n  if ( nodeName === \"input\" ) {\n    fixDefaultChecked( elem );\n  // Skip scripts, get other children\n  } else if ( nodeName !== \"script\" && typeof elem.getElementsByTagName !== \"undefined\" ) {\n    jQuery.grep( elem.getElementsByTagName(\"input\"), fixDefaultChecked );\n  }\n}\n\n// Derived From: https://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js\nfunction shimCloneNode( elem ) {\n  var div = document.createElement( \"div\" );\n  safeFragment.appendChild( div );\n\n  div.innerHTML = elem.outerHTML;\n  return div.firstChild;\n}\n\njQuery.extend({\n  clone: function( elem, dataAndEvents, deepDataAndEvents ) {\n    var srcElements,\n      destElements,\n      i,\n      // IE<=8 does not properly clone detached, unknown element nodes\n      clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( \"<\" + elem.nodeName + \">\" ) ?\n        elem.cloneNode( true ) :\n        shimCloneNode( elem );\n\n    if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n        (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n      // IE copies events bound via attachEvent when using cloneNode.\n      // Calling detachEvent on the clone will also remove the events\n      // from the original. In order to get around this, we use some\n      // proprietary methods to clear the events. Thanks to MooTools\n      // guys for this hotness.\n\n      cloneFixAttributes( elem, clone );\n\n      // Using Sizzle here is crazy slow, so we use getElementsByTagName instead\n      srcElements = getAll( elem );\n      destElements = getAll( clone );\n\n      // Weird iteration because IE will replace the length property\n      // with an element if you are cloning the body and one of the\n      // elements on the page has a name or id of \"length\"\n      for ( i = 0; srcElements[i]; ++i ) {\n        // Ensure that the destination node is not null; Fixes #9587\n        if ( destElements[i] ) {\n          cloneFixAttributes( srcElements[i], destElements[i] );\n        }\n      }\n    }\n\n    // Copy the events from the original to the clone\n    if ( dataAndEvents ) {\n      cloneCopyEvent( elem, clone );\n\n      if ( deepDataAndEvents ) {\n        srcElements = getAll( elem );\n        destElements = getAll( clone );\n\n        for ( i = 0; srcElements[i]; ++i ) {\n          cloneCopyEvent( srcElements[i], destElements[i] );\n        }\n      }\n    }\n\n    srcElements = destElements = null;\n\n    // Return the cloned set\n    return clone;\n  },\n\n  clean: function( elems, context, fragment, scripts ) {\n    var checkScriptType, script, j,\n        ret = [];\n\n    context = context || document;\n\n    // !context.createElement fails in IE with an error but returns typeof 'object'\n    if ( typeof context.createElement === \"undefined\" ) {\n      context = context.ownerDocument || context[0] && context[0].ownerDocument || document;\n    }\n\n    for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n      if ( typeof elem === \"number\" ) {\n        elem += \"\";\n      }\n\n      if ( !elem ) {\n        continue;\n      }\n\n      // Convert html string into DOM nodes\n      if ( typeof elem === \"string\" ) {\n        if ( !rhtml.test( elem ) ) {\n          elem = context.createTextNode( elem );\n        } else {\n          // Fix \"XHTML\"-style tags in all browsers\n          elem = elem.replace(rxhtmlTag, \"<$1></$2>\");\n\n          // Trim whitespace, otherwise indexOf won't work as expected\n          var tag = ( rtagName.exec( elem ) || [\"\", \"\"] )[1].toLowerCase(),\n            wrap = wrapMap[ tag ] || wrapMap._default,\n            depth = wrap[0],\n            div = context.createElement(\"div\"),\n            safeChildNodes = safeFragment.childNodes,\n            remove;\n\n          // Append wrapper element to unknown element safe doc fragment\n          if ( context === document ) {\n            // Use the fragment we've already created for this document\n            safeFragment.appendChild( div );\n          } else {\n            // Use a fragment created with the owner document\n            createSafeFragment( context ).appendChild( div );\n          }\n\n          // Go to html and back, then peel off extra wrappers\n          div.innerHTML = wrap[1] + elem + wrap[2];\n\n          // Move to the right depth\n          while ( depth-- ) {\n            div = div.lastChild;\n          }\n\n          // Remove IE's autoinserted <tbody> from table fragments\n          if ( !jQuery.support.tbody ) {\n\n            // String was a <table>, *may* have spurious <tbody>\n            var hasBody = rtbody.test(elem),\n              tbody = tag === \"table\" && !hasBody ?\n                div.firstChild && div.firstChild.childNodes :\n\n                // String was a bare <thead> or <tfoot>\n                wrap[1] === \"<table>\" && !hasBody ?\n                  div.childNodes :\n                  [];\n\n            for ( j = tbody.length - 1; j >= 0 ; --j ) {\n              if ( jQuery.nodeName( tbody[ j ], \"tbody\" ) && !tbody[ j ].childNodes.length ) {\n                tbody[ j ].parentNode.removeChild( tbody[ j ] );\n              }\n            }\n          }\n\n          // IE completely kills leading whitespace when innerHTML is used\n          if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n            div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );\n          }\n\n          elem = div.childNodes;\n\n          // Clear elements from DocumentFragment (safeFragment or otherwise)\n          // to avoid hoarding elements. Fixes #11356\n          if ( div ) {\n            div.parentNode.removeChild( div );\n\n            // Guard against -1 index exceptions in FF3.6\n            if ( safeChildNodes.length > 0 ) {\n              remove = safeChildNodes[ safeChildNodes.length - 1 ];\n\n              if ( remove && remove.parentNode ) {\n                remove.parentNode.removeChild( remove );\n              }\n            }\n          }\n        }\n      }\n\n      // Resets defaultChecked for any radios and checkboxes\n      // about to be appended to the DOM in IE 6/7 (#8060)\n      var len;\n      if ( !jQuery.support.appendChecked ) {\n        if ( elem[0] && typeof (len = elem.length) === \"number\" ) {\n          for ( j = 0; j < len; j++ ) {\n            findInputs( elem[j] );\n          }\n        } else {\n          findInputs( elem );\n        }\n      }\n\n      if ( elem.nodeType ) {\n        ret.push( elem );\n      } else {\n        ret = jQuery.merge( ret, elem );\n      }\n    }\n\n    if ( fragment ) {\n      checkScriptType = function( elem ) {\n        return !elem.type || rscriptType.test( elem.type );\n      };\n      for ( i = 0; ret[i]; i++ ) {\n        script = ret[i];\n        if ( scripts && jQuery.nodeName( script, \"script\" ) && (!script.type || rscriptType.test( script.type )) ) {\n          scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );\n\n        } else {\n          if ( script.nodeType === 1 ) {\n            var jsTags = jQuery.grep( script.getElementsByTagName( \"script\" ), checkScriptType );\n\n            ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );\n          }\n          fragment.appendChild( script );\n        }\n      }\n    }\n\n    return ret;\n  },\n\n  cleanData: function( elems ) {\n    var data, id,\n      cache = jQuery.cache,\n      special = jQuery.event.special,\n      deleteExpando = jQuery.support.deleteExpando;\n\n    for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n      if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n        continue;\n      }\n\n      id = elem[ jQuery.expando ];\n\n      if ( id ) {\n        data = cache[ id ];\n\n        if ( data && data.events ) {\n          for ( var type in data.events ) {\n            if ( special[ type ] ) {\n              jQuery.event.remove( elem, type );\n\n            // This is a shortcut to avoid jQuery.event.remove's overhead\n            } else {\n              jQuery.removeEvent( elem, type, data.handle );\n            }\n          }\n\n          // Null the DOM reference to avoid IE6/7/8 leak (#7054)\n          if ( data.handle ) {\n            data.handle.elem = null;\n          }\n        }\n\n        if ( deleteExpando ) {\n          delete elem[ jQuery.expando ];\n\n        } else if ( elem.removeAttribute ) {\n          elem.removeAttribute( jQuery.expando );\n        }\n\n        delete cache[ id ];\n      }\n    }\n  }\n});\n\n\n\n\nvar ralpha = /alpha\\([^)]*\\)/i,\n  ropacity = /opacity=([^)]*)/,\n  // fixed for IE9, see #8346\n  rupper = /([A-Z]|^ms)/g,\n  rnum = /^[\\-+]?(?:\\d*\\.)?\\d+$/i,\n  rnumnonpx = /^-?(?:\\d*\\.)?\\d+(?!px)[^\\d\\s]+$/i,\n  rrelNum = /^([\\-+])=([\\-+.\\de]+)/,\n  rmargin = /^margin/,\n\n  cssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\n  // order is important!\n  cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ],\n\n  curCSS,\n\n  getComputedStyle,\n  currentStyle;\n\njQuery.fn.css = function( name, value ) {\n  return jQuery.access( this, function( elem, name, value ) {\n    return value !== undefined ?\n      jQuery.style( elem, name, value ) :\n      jQuery.css( elem, name );\n  }, name, value, arguments.length > 1 );\n};\n\njQuery.extend({\n  // Add in style property hooks for overriding the default\n  // behavior of getting and setting a style property\n  cssHooks: {\n    opacity: {\n      get: function( elem, computed ) {\n        if ( computed ) {\n          // We should always get a number back from opacity\n          var ret = curCSS( elem, \"opacity\" );\n          return ret === \"\" ? \"1\" : ret;\n\n        } else {\n          return elem.style.opacity;\n        }\n      }\n    }\n  },\n\n  // Exclude the following css properties to add px\n  cssNumber: {\n    \"fillOpacity\": true,\n    \"fontWeight\": true,\n    \"lineHeight\": true,\n    \"opacity\": true,\n    \"orphans\": true,\n    \"widows\": true,\n    \"zIndex\": true,\n    \"zoom\": true\n  },\n\n  // Add in properties whose names you wish to fix before\n  // setting or getting the value\n  cssProps: {\n    // normalize float css property\n    \"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n  },\n\n  // Get and set the style property on a DOM Node\n  style: function( elem, name, value, extra ) {\n    // Don't set styles on text and comment nodes\n    if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n      return;\n    }\n\n    // Make sure that we're working with the right name\n    var ret, type, origName = jQuery.camelCase( name ),\n      style = elem.style, hooks = jQuery.cssHooks[ origName ];\n\n    name = jQuery.cssProps[ origName ] || origName;\n\n    // Check if we're setting a value\n    if ( value !== undefined ) {\n      type = typeof value;\n\n      // convert relative number strings (+= or -=) to relative numbers. #7345\n      if ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n        value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );\n        // Fixes bug #9237\n        type = \"number\";\n      }\n\n      // Make sure that NaN and null values aren't set. See: #7116\n      if ( value == null || type === \"number\" && isNaN( value ) ) {\n        return;\n      }\n\n      // If a number was passed in, add 'px' to the (except for certain CSS properties)\n      if ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n        value += \"px\";\n      }\n\n      // If a hook was provided, use that value, otherwise just set the specified value\n      if ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {\n        // Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n        // Fixes bug #5509\n        try {\n          style[ name ] = value;\n        } catch(e) {}\n      }\n\n    } else {\n      // If a hook was provided get the non-computed value from there\n      if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n        return ret;\n      }\n\n      // Otherwise just get the value from the style object\n      return style[ name ];\n    }\n  },\n\n  css: function( elem, name, extra ) {\n    var ret, hooks;\n\n    // Make sure that we're working with the right name\n    name = jQuery.camelCase( name );\n    hooks = jQuery.cssHooks[ name ];\n    name = jQuery.cssProps[ name ] || name;\n\n    // cssFloat needs a special treatment\n    if ( name === \"cssFloat\" ) {\n      name = \"float\";\n    }\n\n    // If a hook was provided get the computed value from there\n    if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {\n      return ret;\n\n    // Otherwise, if a way to get the computed value exists, use that\n    } else if ( curCSS ) {\n      return curCSS( elem, name );\n    }\n  },\n\n  // A method for quickly swapping in/out CSS properties to get correct calculations\n  swap: function( elem, options, callback ) {\n    var old = {},\n      ret, name;\n\n    // Remember the old values, and insert the new ones\n    for ( name in options ) {\n      old[ name ] = elem.style[ name ];\n      elem.style[ name ] = options[ name ];\n    }\n\n    ret = callback.call( elem );\n\n    // Revert the old values\n    for ( name in options ) {\n      elem.style[ name ] = old[ name ];\n    }\n\n    return ret;\n  }\n});\n\n// DEPRECATED in 1.3, Use jQuery.css() instead\njQuery.curCSS = jQuery.css;\n\nif ( document.defaultView && document.defaultView.getComputedStyle ) {\n  getComputedStyle = function( elem, name ) {\n    var ret, defaultView, computedStyle, width,\n      style = elem.style;\n\n    name = name.replace( rupper, \"-$1\" ).toLowerCase();\n\n    if ( (defaultView = elem.ownerDocument.defaultView) &&\n        (computedStyle = defaultView.getComputedStyle( elem, null )) ) {\n\n      ret = computedStyle.getPropertyValue( name );\n      if ( ret === \"\" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {\n        ret = jQuery.style( elem, name );\n      }\n    }\n\n    // A tribute to the \"awesome hack by Dean Edwards\"\n    // WebKit uses \"computed value (percentage if specified)\" instead of \"used value\" for margins\n    // which is against the CSSOM draft spec: https://dev.w3.org/csswg/cssom/#resolved-values\n    if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {\n      width = style.width;\n      style.width = ret;\n      ret = computedStyle.width;\n      style.width = width;\n    }\n\n    return ret;\n  };\n}\n\nif ( document.documentElement.currentStyle ) {\n  currentStyle = function( elem, name ) {\n    var left, rsLeft, uncomputed,\n      ret = elem.currentStyle && elem.currentStyle[ name ],\n      style = elem.style;\n\n    // Avoid setting ret to empty string here\n    // so we don't default to auto\n    if ( ret == null && style && (uncomputed = style[ name ]) ) {\n      ret = uncomputed;\n    }\n\n    // From the awesome hack by Dean Edwards\n    // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n    // If we're not dealing with a regular pixel number\n    // but a number that has a weird ending, we need to convert it to pixels\n    if ( rnumnonpx.test( ret ) ) {\n\n      // Remember the original values\n      left = style.left;\n      rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;\n\n      // Put in the new values to get a computed value out\n      if ( rsLeft ) {\n        elem.runtimeStyle.left = elem.currentStyle.left;\n      }\n      style.left = name === \"fontSize\" ? \"1em\" : ret;\n      ret = style.pixelLeft + \"px\";\n\n      // Revert the changed values\n      style.left = left;\n      if ( rsLeft ) {\n        elem.runtimeStyle.left = rsLeft;\n      }\n    }\n\n    return ret === \"\" ? \"auto\" : ret;\n  };\n}\n\ncurCSS = getComputedStyle || currentStyle;\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n  // Start with offset property\n  var val = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n    i = name === \"width\" ? 1 : 0,\n    len = 4;\n\n  if ( val > 0 ) {\n    if ( extra !== \"border\" ) {\n      for ( ; i < len; i += 2 ) {\n        if ( !extra ) {\n          val -= parseFloat( jQuery.css( elem, \"padding\" + cssExpand[ i ] ) ) || 0;\n        }\n        if ( extra === \"margin\" ) {\n          val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;\n        } else {\n          val -= parseFloat( jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\" ) ) || 0;\n        }\n      }\n    }\n\n    return val + \"px\";\n  }\n\n  // Fall back to computed then uncomputed css if necessary\n  val = curCSS( elem, name );\n  if ( val < 0 || val == null ) {\n    val = elem.style[ name ];\n  }\n\n  // Computed unit is not pixels. Stop here and return.\n  if ( rnumnonpx.test(val) ) {\n    return val;\n  }\n\n  // Normalize \"\", auto, and prepare for extra\n  val = parseFloat( val ) || 0;\n\n  // Add padding, border, margin\n  if ( extra ) {\n    for ( ; i < len; i += 2 ) {\n      val += parseFloat( jQuery.css( elem, \"padding\" + cssExpand[ i ] ) ) || 0;\n      if ( extra !== \"padding\" ) {\n        val += parseFloat( jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\" ) ) || 0;\n      }\n      if ( extra === \"margin\" ) {\n        val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;\n      }\n    }\n  }\n\n  return val + \"px\";\n}\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n  jQuery.cssHooks[ name ] = {\n    get: function( elem, computed, extra ) {\n      if ( computed ) {\n        if ( elem.offsetWidth !== 0 ) {\n          return getWidthOrHeight( elem, name, extra );\n        } else {\n          return jQuery.swap( elem, cssShow, function() {\n            return getWidthOrHeight( elem, name, extra );\n          });\n        }\n      }\n    },\n\n    set: function( elem, value ) {\n      return rnum.test( value ) ?\n        value + \"px\" :\n        value;\n    }\n  };\n});\n\nif ( !jQuery.support.opacity ) {\n  jQuery.cssHooks.opacity = {\n    get: function( elem, computed ) {\n      // IE uses filters for opacity\n      return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\" ) ?\n        ( parseFloat( RegExp.$1 ) / 100 ) + \"\" :\n        computed ? \"1\" : \"\";\n    },\n\n    set: function( elem, value ) {\n      var style = elem.style,\n        currentStyle = elem.currentStyle,\n        opacity = jQuery.isNumeric( value ) ? \"alpha(opacity=\" + value * 100 + \")\" : \"\",\n        filter = currentStyle && currentStyle.filter || style.filter || \"\";\n\n      // IE has trouble with opacity if it does not have layout\n      // Force it by setting the zoom level\n      style.zoom = 1;\n\n      // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652\n      if ( value >= 1 && jQuery.trim( filter.replace( ralpha, \"\" ) ) === \"\" ) {\n\n        // Setting style.filter to null, \"\" & \" \" still leave \"filter:\" in the cssText\n        // if \"filter:\" is present at all, clearType is disabled, we want to avoid this\n        // style.removeAttribute is IE Only, but so apparently is this code path...\n        style.removeAttribute( \"filter\" );\n\n        // if there there is no filter style applied in a css rule, we are done\n        if ( currentStyle && !currentStyle.filter ) {\n          return;\n        }\n      }\n\n      // otherwise, set new filter values\n      style.filter = ralpha.test( filter ) ?\n        filter.replace( ralpha, opacity ) :\n        filter + \" \" + opacity;\n    }\n  };\n}\n\njQuery(function() {\n  // This hook cannot be added until DOM ready because the support test\n  // for it is not run until after DOM ready\n  if ( !jQuery.support.reliableMarginRight ) {\n    jQuery.cssHooks.marginRight = {\n      get: function( elem, computed ) {\n        // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n        // Work around by temporarily setting element display to inline-block\n        return jQuery.swap( elem, { \"display\": \"inline-block\" }, function() {\n          if ( computed ) {\n            return curCSS( elem, \"margin-right\" );\n          } else {\n            return elem.style.marginRight;\n          }\n        });\n      }\n    };\n  }\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n  jQuery.expr.filters.hidden = function( elem ) {\n    var width = elem.offsetWidth,\n      height = elem.offsetHeight;\n\n    return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, \"display\" )) === \"none\");\n  };\n\n  jQuery.expr.filters.visible = function( elem ) {\n    return !jQuery.expr.filters.hidden( elem );\n  };\n}\n\n// These hooks are used by animate to expand properties\njQuery.each({\n  margin: \"\",\n  padding: \"\",\n  border: \"Width\"\n}, function( prefix, suffix ) {\n\n  jQuery.cssHooks[ prefix + suffix ] = {\n    expand: function( value ) {\n      var i,\n\n        // assumes a single number if not a string\n        parts = typeof value === \"string\" ? value.split(\" \") : [ value ],\n        expanded = {};\n\n      for ( i = 0; i < 4; i++ ) {\n        expanded[ prefix + cssExpand[ i ] + suffix ] =\n          parts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n      }\n\n      return expanded;\n    }\n  };\n});\n\n\n\n\nvar r20 = /%20/g,\n  rbracket = /\\[\\]$/,\n  rCRLF = /\\r?\\n/g,\n  rhash = /#.*$/,\n  rheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n  rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,\n  // #7653, #8125, #8152: local protocol detection\n  rlocalProtocol = /^(?:about|app|app\\-storage|.+\\-extension|file|res|widget):$/,\n  rnoContent = /^(?:GET|HEAD)$/,\n  rprotocol = /^\\/\\//,\n  rquery = /\\?/,\n  rscript = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\n  rselectTextarea = /^(?:select|textarea)/i,\n  rspacesAjax = /\\s+/,\n  rts = /([?&])_=[^&]*/,\n  rurl = /^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,\n\n  // Keep a copy of the old load method\n  _load = jQuery.fn.load,\n\n  /* Prefilters\n   * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n   * 2) These are called:\n   *    - BEFORE asking for a transport\n   *    - AFTER param serialization (s.data is a string if s.processData is true)\n   * 3) key is the dataType\n   * 4) the catchall symbol \"*\" can be used\n   * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n   */\n  prefilters = {},\n\n  /* Transports bindings\n   * 1) key is the dataType\n   * 2) the catchall symbol \"*\" can be used\n   * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n   */\n  transports = {},\n\n  // Document location\n  ajaxLocation,\n\n  // Document location segments\n  ajaxLocParts,\n\n  // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n  allTypes = [\"*/\"] + [\"*\"];\n\n// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n  ajaxLocation = location.href;\n} catch( e ) {\n  // Use the href attribute of an A element\n  // since IE will modify it given document.location\n  ajaxLocation = document.createElement( \"a\" );\n  ajaxLocation.href = \"\";\n  ajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n  // dataTypeExpression is optional and defaults to \"*\"\n  return function( dataTypeExpression, func ) {\n\n    if ( typeof dataTypeExpression !== \"string\" ) {\n      func = dataTypeExpression;\n      dataTypeExpression = \"*\";\n    }\n\n    if ( jQuery.isFunction( func ) ) {\n      var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),\n        i = 0,\n        length = dataTypes.length,\n        dataType,\n        list,\n        placeBefore;\n\n      // For each dataType in the dataTypeExpression\n      for ( ; i < length; i++ ) {\n        dataType = dataTypes[ i ];\n        // We control if we're asked to add before\n        // any existing element\n        placeBefore = /^\\+/.test( dataType );\n        if ( placeBefore ) {\n          dataType = dataType.substr( 1 ) || \"*\";\n        }\n        list = structure[ dataType ] = structure[ dataType ] || [];\n        // then we add to the structure accordingly\n        list[ placeBefore ? \"unshift\" : \"push\" ]( func );\n      }\n    }\n  };\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,\n    dataType /* internal */, inspected /* internal */ ) {\n\n  dataType = dataType || options.dataTypes[ 0 ];\n  inspected = inspected || {};\n\n  inspected[ dataType ] = true;\n\n  var list = structure[ dataType ],\n    i = 0,\n    length = list ? list.length : 0,\n    executeOnly = ( structure === prefilters ),\n    selection;\n\n  for ( ; i < length && ( executeOnly || !selection ); i++ ) {\n    selection = list[ i ]( options, originalOptions, jqXHR );\n    // If we got redirected to another dataType\n    // we try there if executing only and not done already\n    if ( typeof selection === \"string\" ) {\n      if ( !executeOnly || inspected[ selection ] ) {\n        selection = undefined;\n      } else {\n        options.dataTypes.unshift( selection );\n        selection = inspectPrefiltersOrTransports(\n            structure, options, originalOptions, jqXHR, selection, inspected );\n      }\n    }\n  }\n  // If we're only executing or nothing was selected\n  // we try the catchall dataType if not done already\n  if ( ( executeOnly || !selection ) && !inspected[ \"*\" ] ) {\n    selection = inspectPrefiltersOrTransports(\n        structure, options, originalOptions, jqXHR, \"*\", inspected );\n  }\n  // unnecessary when only executing (prefilters)\n  // but it'll be ignored by the caller in that case\n  return selection;\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n  var key, deep,\n    flatOptions = jQuery.ajaxSettings.flatOptions || {};\n  for ( key in src ) {\n    if ( src[ key ] !== undefined ) {\n      ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n    }\n  }\n  if ( deep ) {\n    jQuery.extend( true, target, deep );\n  }\n}\n\njQuery.fn.extend({\n  load: function( url, params, callback ) {\n    if ( typeof url !== \"string\" && _load ) {\n      return _load.apply( this, arguments );\n\n    // Don't do a request if no elements are being requested\n    } else if ( !this.length ) {\n      return this;\n    }\n\n    var off = url.indexOf( \" \" );\n    if ( off >= 0 ) {\n      var selector = url.slice( off, url.length );\n      url = url.slice( 0, off );\n    }\n\n    // Default to a GET request\n    var type = \"GET\";\n\n    // If the second parameter was provided\n    if ( params ) {\n      // If it's a function\n      if ( jQuery.isFunction( params ) ) {\n        // We assume that it's the callback\n        callback = params;\n        params = undefined;\n\n      // Otherwise, build a param string\n      } else if ( typeof params === \"object\" ) {\n        params = jQuery.param( params, jQuery.ajaxSettings.traditional );\n        type = \"POST\";\n      }\n    }\n\n    var self = this;\n\n    // Request the remote document\n    jQuery.ajax({\n      url: url,\n      type: type,\n      dataType: \"html\",\n      data: params,\n      // Complete callback (responseText is used internally)\n      complete: function( jqXHR, status, responseText ) {\n        // Store the response as specified by the jqXHR object\n        responseText = jqXHR.responseText;\n        // If successful, inject the HTML into all the matched elements\n        if ( jqXHR.isResolved() ) {\n          // #4825: Get the actual response in case\n          // a dataFilter is present in ajaxSettings\n          jqXHR.done(function( r ) {\n            responseText = r;\n          });\n          // See if a selector was specified\n          self.html( selector ?\n            // Create a dummy div to hold the results\n            jQuery(\"<div>\")\n              // inject the contents of the document in, removing the scripts\n              // to avoid any 'Permission Denied' errors in IE\n              .append(responseText.replace(rscript, \"\"))\n\n              // Locate the specified elements\n              .find(selector) :\n\n            // If not, just inject the full result\n            responseText );\n        }\n\n        if ( callback ) {\n          self.each( callback, [ responseText, status, jqXHR ] );\n        }\n      }\n    });\n\n    return this;\n  },\n\n  serialize: function() {\n    return jQuery.param( this.serializeArray() );\n  },\n\n  serializeArray: function() {\n    return this.map(function(){\n      return this.elements ? jQuery.makeArray( this.elements ) : this;\n    })\n    .filter(function(){\n      return this.name && !this.disabled &&\n        ( this.checked || rselectTextarea.test( this.nodeName ) ||\n          rinput.test( this.type ) );\n    })\n    .map(function( i, elem ){\n      var val = jQuery( this ).val();\n\n      return val == null ?\n        null :\n        jQuery.isArray( val ) ?\n          jQuery.map( val, function( val, i ){\n            return { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n          }) :\n          { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n    }).get();\n  }\n});\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( \"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split( \" \" ), function( i, o ){\n  jQuery.fn[ o ] = function( f ){\n    return this.on( o, f );\n  };\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n  jQuery[ method ] = function( url, data, callback, type ) {\n    // shift arguments if data argument was omitted\n    if ( jQuery.isFunction( data ) ) {\n      type = type || callback;\n      callback = data;\n      data = undefined;\n    }\n\n    return jQuery.ajax({\n      type: method,\n      url: url,\n      data: data,\n      success: callback,\n      dataType: type\n    });\n  };\n});\n\njQuery.extend({\n\n  getScript: function( url, callback ) {\n    return jQuery.get( url, undefined, callback, \"script\" );\n  },\n\n  getJSON: function( url, data, callback ) {\n    return jQuery.get( url, data, callback, \"json\" );\n  },\n\n  // Creates a full fledged settings object into target\n  // with both ajaxSettings and settings fields.\n  // If target is omitted, writes into ajaxSettings.\n  ajaxSetup: function( target, settings ) {\n    if ( settings ) {\n      // Building a settings object\n      ajaxExtend( target, jQuery.ajaxSettings );\n    } else {\n      // Extending ajaxSettings\n      settings = target;\n      target = jQuery.ajaxSettings;\n    }\n    ajaxExtend( target, settings );\n    return target;\n  },\n\n  ajaxSettings: {\n    url: ajaxLocation,\n    isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n    global: true,\n    type: \"GET\",\n    contentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n    processData: true,\n    async: true,\n    /*\n    timeout: 0,\n    data: null,\n    dataType: null,\n    username: null,\n    password: null,\n    cache: null,\n    traditional: false,\n    headers: {},\n    */\n\n    accepts: {\n      xml: \"application/xml, text/xml\",\n      html: \"text/html\",\n      text: \"text/plain\",\n      json: \"application/json, text/javascript\",\n      \"*\": allTypes\n    },\n\n    contents: {\n      xml: /xml/,\n      html: /html/,\n      json: /json/\n    },\n\n    responseFields: {\n      xml: \"responseXML\",\n      text: \"responseText\"\n    },\n\n    // List of data converters\n    // 1) key format is \"source_type destination_type\" (a single space in-between)\n    // 2) the catchall symbol \"*\" can be used for source_type\n    converters: {\n\n      // Convert anything to text\n      \"* text\": window.String,\n\n      // Text to html (true = no transformation)\n      \"text html\": true,\n\n      // Evaluate text as a json expression\n      \"text json\": jQuery.parseJSON,\n\n      // Parse text as xml\n      \"text xml\": jQuery.parseXML\n    },\n\n    // For options that shouldn't be deep extended:\n    // you can add your own custom options here if\n    // and when you create one that shouldn't be\n    // deep extended (see ajaxExtend)\n    flatOptions: {\n      context: true,\n      url: true\n    }\n  },\n\n  ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n  ajaxTransport: addToPrefiltersOrTransports( transports ),\n\n  // Main method\n  ajax: function( url, options ) {\n\n    // If url is an object, simulate pre-1.5 signature\n    if ( typeof url === \"object\" ) {\n      options = url;\n      url = undefined;\n    }\n\n    // Force options to be an object\n    options = options || {};\n\n    var // Create the final options object\n      s = jQuery.ajaxSetup( {}, options ),\n      // Callbacks context\n      callbackContext = s.context || s,\n      // Context for global events\n      // It's the callbackContext if one was provided in the options\n      // and if it's a DOM node or a jQuery collection\n      globalEventContext = callbackContext !== s &&\n        ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?\n            jQuery( callbackContext ) : jQuery.event,\n      // Deferreds\n      deferred = jQuery.Deferred(),\n      completeDeferred = jQuery.Callbacks( \"once memory\" ),\n      // Status-dependent callbacks\n      statusCode = s.statusCode || {},\n      // ifModified key\n      ifModifiedKey,\n      // Headers (they are sent all at once)\n      requestHeaders = {},\n      requestHeadersNames = {},\n      // Response headers\n      responseHeadersString,\n      responseHeaders,\n      // transport\n      transport,\n      // timeout handle\n      timeoutTimer,\n      // Cross-domain detection vars\n      parts,\n      // The jqXHR state\n      state = 0,\n      // To know if global events are to be dispatched\n      fireGlobals,\n      // Loop variable\n      i,\n      // Fake xhr\n      jqXHR = {\n\n        readyState: 0,\n\n        // Caches the header\n        setRequestHeader: function( name, value ) {\n          if ( !state ) {\n            var lname = name.toLowerCase();\n            name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n            requestHeaders[ name ] = value;\n          }\n          return this;\n        },\n\n        // Raw string\n        getAllResponseHeaders: function() {\n          return state === 2 ? responseHeadersString : null;\n        },\n\n        // Builds headers hashtable if needed\n        getResponseHeader: function( key ) {\n          var match;\n          if ( state === 2 ) {\n            if ( !responseHeaders ) {\n              responseHeaders = {};\n              while( ( match = rheaders.exec( responseHeadersString ) ) ) {\n                responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n              }\n            }\n            match = responseHeaders[ key.toLowerCase() ];\n          }\n          return match === undefined ? null : match;\n        },\n\n        // Overrides response content-type header\n        overrideMimeType: function( type ) {\n          if ( !state ) {\n            s.mimeType = type;\n          }\n          return this;\n        },\n\n        // Cancel the request\n        abort: function( statusText ) {\n          statusText = statusText || \"abort\";\n          if ( transport ) {\n            transport.abort( statusText );\n          }\n          done( 0, statusText );\n          return this;\n        }\n      };\n\n    // Callback for when everything is done\n    // It is defined here because jslint complains if it is declared\n    // at the end of the function (which would be more logical and readable)\n    function done( status, nativeStatusText, responses, headers ) {\n\n      // Called once\n      if ( state === 2 ) {\n        return;\n      }\n\n      // State is \"done\" now\n      state = 2;\n\n      // Clear timeout if it exists\n      if ( timeoutTimer ) {\n        clearTimeout( timeoutTimer );\n      }\n\n      // Dereference transport for early garbage collection\n      // (no matter how long the jqXHR object will be used)\n      transport = undefined;\n\n      // Cache response headers\n      responseHeadersString = headers || \"\";\n\n      // Set readyState\n      jqXHR.readyState = status > 0 ? 4 : 0;\n\n      var isSuccess,\n        success,\n        error,\n        statusText = nativeStatusText,\n        response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,\n        lastModified,\n        etag;\n\n      // If successful, handle type chaining\n      if ( status >= 200 && status < 300 || status === 304 ) {\n\n        // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n        if ( s.ifModified ) {\n\n          if ( ( lastModified = jqXHR.getResponseHeader( \"Last-Modified\" ) ) ) {\n            jQuery.lastModified[ ifModifiedKey ] = lastModified;\n          }\n          if ( ( etag = jqXHR.getResponseHeader( \"Etag\" ) ) ) {\n            jQuery.etag[ ifModifiedKey ] = etag;\n          }\n        }\n\n        // If not modified\n        if ( status === 304 ) {\n\n          statusText = \"notmodified\";\n          isSuccess = true;\n\n        // If we have data\n        } else {\n\n          try {\n            success = ajaxConvert( s, response );\n            statusText = \"success\";\n            isSuccess = true;\n          } catch(e) {\n            // We have a parsererror\n            statusText = \"parsererror\";\n            error = e;\n          }\n        }\n      } else {\n        // We extract error from statusText\n        // then normalize statusText and status for non-aborts\n        error = statusText;\n        if ( !statusText || status ) {\n          statusText = \"error\";\n          if ( status < 0 ) {\n            status = 0;\n          }\n        }\n      }\n\n      // Set data for the fake xhr object\n      jqXHR.status = status;\n      jqXHR.statusText = \"\" + ( nativeStatusText || statusText );\n\n      // Success/Error\n      if ( isSuccess ) {\n        deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n      } else {\n        deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n      }\n\n      // Status-dependent callbacks\n      jqXHR.statusCode( statusCode );\n      statusCode = undefined;\n\n      if ( fireGlobals ) {\n        globalEventContext.trigger( \"ajax\" + ( isSuccess ? \"Success\" : \"Error\" ),\n            [ jqXHR, s, isSuccess ? success : error ] );\n      }\n\n      // Complete\n      completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n      if ( fireGlobals ) {\n        globalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n        // Handle the global AJAX counter\n        if ( !( --jQuery.active ) ) {\n          jQuery.event.trigger( \"ajaxStop\" );\n        }\n      }\n    }\n\n    // Attach deferreds\n    deferred.promise( jqXHR );\n    jqXHR.success = jqXHR.done;\n    jqXHR.error = jqXHR.fail;\n    jqXHR.complete = completeDeferred.add;\n\n    // Status-dependent callbacks\n    jqXHR.statusCode = function( map ) {\n      if ( map ) {\n        var tmp;\n        if ( state < 2 ) {\n          for ( tmp in map ) {\n            statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];\n          }\n        } else {\n          tmp = map[ jqXHR.status ];\n          jqXHR.then( tmp, tmp );\n        }\n      }\n      return this;\n    };\n\n    // Remove hash character (#7531: and string promotion)\n    // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)\n    // We also use the url parameter if available\n    s.url = ( ( url || s.url ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n    // Extract dataTypes list\n    s.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().split( rspacesAjax );\n\n    // Determine if a cross-domain request is in order\n    if ( s.crossDomain == null ) {\n      parts = rurl.exec( s.url.toLowerCase() );\n      s.crossDomain = !!( parts &&\n        ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||\n          ( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? 80 : 443 ) ) !=\n            ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? 80 : 443 ) ) )\n      );\n    }\n\n    // Convert data if not already a string\n    if ( s.data && s.processData && typeof s.data !== \"string\" ) {\n      s.data = jQuery.param( s.data, s.traditional );\n    }\n\n    // Apply prefilters\n    inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n    // If request was aborted inside a prefilter, stop there\n    if ( state === 2 ) {\n      return false;\n    }\n\n    // We can fire global events as of now if asked to\n    fireGlobals = s.global;\n\n    // Uppercase the type\n    s.type = s.type.toUpperCase();\n\n    // Determine if request has content\n    s.hasContent = !rnoContent.test( s.type );\n\n    // Watch for a new set of requests\n    if ( fireGlobals && jQuery.active++ === 0 ) {\n      jQuery.event.trigger( \"ajaxStart\" );\n    }\n\n    // More options handling for requests with no content\n    if ( !s.hasContent ) {\n\n      // If data is available, append data to url\n      if ( s.data ) {\n        s.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.data;\n        // #9682: remove data so that it's not used in an eventual retry\n        delete s.data;\n      }\n\n      // Get ifModifiedKey before adding the anti-cache parameter\n      ifModifiedKey = s.url;\n\n      // Add anti-cache in url if needed\n      if ( s.cache === false ) {\n\n        var ts = jQuery.now(),\n          // try replacing _= if it is there\n          ret = s.url.replace( rts, \"$1_=\" + ts );\n\n        // if nothing was replaced, add timestamp to the end\n        s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? \"&\" : \"?\" ) + \"_=\" + ts : \"\" );\n      }\n    }\n\n    // Set the correct header, if data is being sent\n    if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n      jqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n    }\n\n    // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n    if ( s.ifModified ) {\n      ifModifiedKey = ifModifiedKey || s.url;\n      if ( jQuery.lastModified[ ifModifiedKey ] ) {\n        jqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ ifModifiedKey ] );\n      }\n      if ( jQuery.etag[ ifModifiedKey ] ) {\n        jqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ ifModifiedKey ] );\n      }\n    }\n\n    // Set the Accepts header for the server, depending on the dataType\n    jqXHR.setRequestHeader(\n      \"Accept\",\n      s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n        s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n        s.accepts[ \"*\" ]\n    );\n\n    // Check for headers option\n    for ( i in s.headers ) {\n      jqXHR.setRequestHeader( i, s.headers[ i ] );\n    }\n\n    // Allow custom headers/mimetypes and early abort\n    if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n        // Abort if not done already\n        jqXHR.abort();\n        return false;\n\n    }\n\n    // Install callbacks on deferreds\n    for ( i in { success: 1, error: 1, complete: 1 } ) {\n      jqXHR[ i ]( s[ i ] );\n    }\n\n    // Get transport\n    transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n    // If no transport, we auto-abort\n    if ( !transport ) {\n      done( -1, \"No Transport\" );\n    } else {\n      jqXHR.readyState = 1;\n      // Send global event\n      if ( fireGlobals ) {\n        globalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n      }\n      // Timeout\n      if ( s.async && s.timeout > 0 ) {\n        timeoutTimer = setTimeout( function(){\n          jqXHR.abort( \"timeout\" );\n        }, s.timeout );\n      }\n\n      try {\n        state = 1;\n        transport.send( requestHeaders, done );\n      } catch (e) {\n        // Propagate exception as error if not done\n        if ( state < 2 ) {\n          done( -1, e );\n        // Simply rethrow otherwise\n        } else {\n          throw e;\n        }\n      }\n    }\n\n    return jqXHR;\n  },\n\n  // Serialize an array of form elements or a set of\n  // key/values into a query string\n  param: function( a, traditional ) {\n    var s = [],\n      add = function( key, value ) {\n        // If value is a function, invoke it and return its value\n        value = jQuery.isFunction( value ) ? value() : value;\n        s[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n      };\n\n    // Set traditional to true for jQuery <= 1.3.2 behavior.\n    if ( traditional === undefined ) {\n      traditional = jQuery.ajaxSettings.traditional;\n    }\n\n    // If an array was passed in, assume that it is an array of form elements.\n    if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n      // Serialize the form elements\n      jQuery.each( a, function() {\n        add( this.name, this.value );\n      });\n\n    } else {\n      // If traditional, encode the \"old\" way (the way 1.3.2 or older\n      // did it), otherwise encode params recursively.\n      for ( var prefix in a ) {\n        buildParams( prefix, a[ prefix ], traditional, add );\n      }\n    }\n\n    // Return the resulting serialization\n    return s.join( \"&\" ).replace( r20, \"+\" );\n  }\n});\n\nfunction buildParams( prefix, obj, traditional, add ) {\n  if ( jQuery.isArray( obj ) ) {\n    // Serialize array item.\n    jQuery.each( obj, function( i, v ) {\n      if ( traditional || rbracket.test( prefix ) ) {\n        // Treat each array item as a scalar.\n        add( prefix, v );\n\n      } else {\n        // If array item is non-scalar (array or object), encode its\n        // numeric index to resolve deserialization ambiguity issues.\n        // Note that rack (as of 1.0.0) can't currently deserialize\n        // nested arrays properly, and attempting to do so may cause\n        // a server error. Possible fixes are to modify rack's\n        // deserialization algorithm or to provide an option or flag\n        // to force array serialization to be shallow.\n        buildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n      }\n    });\n\n  } else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n    // Serialize object item.\n    for ( var name in obj ) {\n      buildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n    }\n\n  } else {\n    // Serialize scalar item.\n    add( prefix, obj );\n  }\n}\n\n// This is still on the jQuery object... for now\n// Want to move this to jQuery.ajax some day\njQuery.extend({\n\n  // Counter for holding the number of active queries\n  active: 0,\n\n  // Last-Modified header cache for next request\n  lastModified: {},\n  etag: {}\n\n});\n\n/* Handles responses to an ajax request:\n * - sets all responseXXX fields accordingly\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n  var contents = s.contents,\n    dataTypes = s.dataTypes,\n    responseFields = s.responseFields,\n    ct,\n    type,\n    finalDataType,\n    firstDataType;\n\n  // Fill responseXXX fields\n  for ( type in responseFields ) {\n    if ( type in responses ) {\n      jqXHR[ responseFields[type] ] = responses[ type ];\n    }\n  }\n\n  // Remove auto dataType and get content-type in the process\n  while( dataTypes[ 0 ] === \"*\" ) {\n    dataTypes.shift();\n    if ( ct === undefined ) {\n      ct = s.mimeType || jqXHR.getResponseHeader( \"content-type\" );\n    }\n  }\n\n  // Check if we're dealing with a known content-type\n  if ( ct ) {\n    for ( type in contents ) {\n      if ( contents[ type ] && contents[ type ].test( ct ) ) {\n        dataTypes.unshift( type );\n        break;\n      }\n    }\n  }\n\n  // Check to see if we have a response for the expected dataType\n  if ( dataTypes[ 0 ] in responses ) {\n    finalDataType = dataTypes[ 0 ];\n  } else {\n    // Try convertible dataTypes\n    for ( type in responses ) {\n      if ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n        finalDataType = type;\n        break;\n      }\n      if ( !firstDataType ) {\n        firstDataType = type;\n      }\n    }\n    // Or just use first one\n    finalDataType = finalDataType || firstDataType;\n  }\n\n  // If we found a dataType\n  // We add the dataType to the list if needed\n  // and return the corresponding response\n  if ( finalDataType ) {\n    if ( finalDataType !== dataTypes[ 0 ] ) {\n      dataTypes.unshift( finalDataType );\n    }\n    return responses[ finalDataType ];\n  }\n}\n\n// Chain conversions given the request and the original response\nfunction ajaxConvert( s, response ) {\n\n  // Apply the dataFilter if provided\n  if ( s.dataFilter ) {\n    response = s.dataFilter( response, s.dataType );\n  }\n\n  var dataTypes = s.dataTypes,\n    converters = {},\n    i,\n    key,\n    length = dataTypes.length,\n    tmp,\n    // Current and previous dataTypes\n    current = dataTypes[ 0 ],\n    prev,\n    // Conversion expression\n    conversion,\n    // Conversion function\n    conv,\n    // Conversion functions (transitive conversion)\n    conv1,\n    conv2;\n\n  // For each dataType in the chain\n  for ( i = 1; i < length; i++ ) {\n\n    // Create converters map\n    // with lowercased keys\n    if ( i === 1 ) {\n      for ( key in s.converters ) {\n        if ( typeof key === \"string\" ) {\n          converters[ key.toLowerCase() ] = s.converters[ key ];\n        }\n      }\n    }\n\n    // Get the dataTypes\n    prev = current;\n    current = dataTypes[ i ];\n\n    // If current is auto dataType, update it to prev\n    if ( current === \"*\" ) {\n      current = prev;\n    // If no auto and dataTypes are actually different\n    } else if ( prev !== \"*\" && prev !== current ) {\n\n      // Get the converter\n      conversion = prev + \" \" + current;\n      conv = converters[ conversion ] || converters[ \"* \" + current ];\n\n      // If there is no direct converter, search transitively\n      if ( !conv ) {\n        conv2 = undefined;\n        for ( conv1 in converters ) {\n          tmp = conv1.split( \" \" );\n          if ( tmp[ 0 ] === prev || tmp[ 0 ] === \"*\" ) {\n            conv2 = converters[ tmp[1] + \" \" + current ];\n            if ( conv2 ) {\n              conv1 = converters[ conv1 ];\n              if ( conv1 === true ) {\n                conv = conv2;\n              } else if ( conv2 === true ) {\n                conv = conv1;\n              }\n              break;\n            }\n          }\n        }\n      }\n      // If we found no converter, dispatch an error\n      if ( !( conv || conv2 ) ) {\n        jQuery.error( \"No conversion from \" + conversion.replace(\" \",\" to \") );\n      }\n      // If found converter is not an equivalence\n      if ( conv !== true ) {\n        // Convert with 1 or 2 converters accordingly\n        response = conv ? conv( response ) : conv2( conv1(response) );\n      }\n    }\n  }\n  return response;\n}\n\n\n\n\nvar jsc = jQuery.now(),\n  jsre = /(\\=)\\?(&|$)|\\?\\?/i;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n  jsonp: \"callback\",\n  jsonpCallback: function() {\n    return jQuery.expando + \"_\" + ( jsc++ );\n  }\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n  var inspectData = ( typeof s.data === \"string\" ) && /^application\\/x\\-www\\-form\\-urlencoded/.test( s.contentType );\n\n  if ( s.dataTypes[ 0 ] === \"jsonp\" ||\n    s.jsonp !== false && ( jsre.test( s.url ) ||\n        inspectData && jsre.test( s.data ) ) ) {\n\n    var responseContainer,\n      jsonpCallback = s.jsonpCallback =\n        jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,\n      previous = window[ jsonpCallback ],\n      url = s.url,\n      data = s.data,\n      replace = \"$1\" + jsonpCallback + \"$2\";\n\n    if ( s.jsonp !== false ) {\n      url = url.replace( jsre, replace );\n      if ( s.url === url ) {\n        if ( inspectData ) {\n          data = data.replace( jsre, replace );\n        }\n        if ( s.data === data ) {\n          // Add callback manually\n          url += (/\\?/.test( url ) ? \"&\" : \"?\") + s.jsonp + \"=\" + jsonpCallback;\n        }\n      }\n    }\n\n    s.url = url;\n    s.data = data;\n\n    // Install callback\n    window[ jsonpCallback ] = function( response ) {\n      responseContainer = [ response ];\n    };\n\n    // Clean-up function\n    jqXHR.always(function() {\n      // Set callback back to previous value\n      window[ jsonpCallback ] = previous;\n      // Call if it was a function and we have a response\n      if ( responseContainer && jQuery.isFunction( previous ) ) {\n        window[ jsonpCallback ]( responseContainer[ 0 ] );\n      }\n    });\n\n    // Use data converter to retrieve json after script execution\n    s.converters[\"script json\"] = function() {\n      if ( !responseContainer ) {\n        jQuery.error( jsonpCallback + \" was not called\" );\n      }\n      return responseContainer[ 0 ];\n    };\n\n    // force json dataType\n    s.dataTypes[ 0 ] = \"json\";\n\n    // Delegate to script\n    return \"script\";\n  }\n});\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup({\n  accepts: {\n    script: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n  },\n  contents: {\n    script: /javascript|ecmascript/\n  },\n  converters: {\n    \"text script\": function( text ) {\n      jQuery.globalEval( text );\n      return text;\n    }\n  }\n});\n\n// Handle cache's special case and global\njQuery.ajaxPrefilter( \"script\", function( s ) {\n  if ( s.cache === undefined ) {\n    s.cache = false;\n  }\n  if ( s.crossDomain ) {\n    s.type = \"GET\";\n    s.global = false;\n  }\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function(s) {\n\n  // This transport only deals with cross domain requests\n  if ( s.crossDomain ) {\n\n    var script,\n      head = document.head || document.getElementsByTagName( \"head\" )[0] || document.documentElement;\n\n    return {\n\n      send: function( _, callback ) {\n\n        script = document.createElement( \"script\" );\n\n        script.async = \"async\";\n\n        if ( s.scriptCharset ) {\n          script.charset = s.scriptCharset;\n        }\n\n        script.src = s.url;\n\n        // Attach handlers for all browsers\n        script.onload = script.onreadystatechange = function( _, isAbort ) {\n\n          if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n            // Handle memory leak in IE\n            script.onload = script.onreadystatechange = null;\n\n            // Remove the script\n            if ( head && script.parentNode ) {\n              head.removeChild( script );\n            }\n\n            // Dereference the script\n            script = undefined;\n\n            // Callback if not abort\n            if ( !isAbort ) {\n              callback( 200, \"success\" );\n            }\n          }\n        };\n        // Use insertBefore instead of appendChild  to circumvent an IE6 bug.\n        // This arises when a base node is used (#2709 and #4378).\n        head.insertBefore( script, head.firstChild );\n      },\n\n      abort: function() {\n        if ( script ) {\n          script.onload( 0, 1 );\n        }\n      }\n    };\n  }\n});\n\n\n\n\nvar // #5280: Internet Explorer will keep connections alive if we don't abort on unload\n  xhrOnUnloadAbort = window.ActiveXObject ? function() {\n    // Abort all pending requests\n    for ( var key in xhrCallbacks ) {\n      xhrCallbacks[ key ]( 0, 1 );\n    }\n  } : false,\n  xhrId = 0,\n  xhrCallbacks;\n\n// Functions to create xhrs\nfunction createStandardXHR() {\n  try {\n    return new window.XMLHttpRequest();\n  } catch( e ) {}\n}\n\nfunction createActiveXHR() {\n  try {\n    return new window.ActiveXObject( \"Microsoft.XMLHTTP\" );\n  } catch( e ) {}\n}\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject ?\n  /* Microsoft failed to properly\n   * implement the XMLHttpRequest in IE7 (can't request local files),\n   * so we use the ActiveXObject when it is available\n   * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n   * we need a fallback.\n   */\n  function() {\n    return !this.isLocal && createStandardXHR() || createActiveXHR();\n  } :\n  // For all other browsers, use the standard XMLHttpRequest object\n  createStandardXHR;\n\n// Determine support properties\n(function( xhr ) {\n  jQuery.extend( jQuery.support, {\n    ajax: !!xhr,\n    cors: !!xhr && ( \"withCredentials\" in xhr )\n  });\n})( jQuery.ajaxSettings.xhr() );\n\n// Create transport if the browser can provide an xhr\nif ( jQuery.support.ajax ) {\n\n  jQuery.ajaxTransport(function( s ) {\n    // Cross domain only allowed if supported through XMLHttpRequest\n    if ( !s.crossDomain || jQuery.support.cors ) {\n\n      var callback;\n\n      return {\n        send: function( headers, complete ) {\n\n          // Get a new xhr\n          var xhr = s.xhr(),\n            handle,\n            i;\n\n          // Open the socket\n          // Passing null username, generates a login popup on Opera (#2865)\n          if ( s.username ) {\n            xhr.open( s.type, s.url, s.async, s.username, s.password );\n          } else {\n            xhr.open( s.type, s.url, s.async );\n          }\n\n          // Apply custom fields if provided\n          if ( s.xhrFields ) {\n            for ( i in s.xhrFields ) {\n              xhr[ i ] = s.xhrFields[ i ];\n            }\n          }\n\n          // Override mime type if needed\n          if ( s.mimeType && xhr.overrideMimeType ) {\n            xhr.overrideMimeType( s.mimeType );\n          }\n\n          // X-Requested-With header\n          // For cross-domain requests, seeing as conditions for a preflight are\n          // akin to a jigsaw puzzle, we simply never set it to be sure.\n          // (it can always be set on a per-request basis or even using ajaxSetup)\n          // For same-domain requests, won't change header if already provided.\n          if ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n            headers[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n          }\n\n          // Need an extra try/catch for cross domain requests in Firefox 3\n          try {\n            for ( i in headers ) {\n              xhr.setRequestHeader( i, headers[ i ] );\n            }\n          } catch( _ ) {}\n\n          // Do send the request\n          // This may raise an exception which is actually\n          // handled in jQuery.ajax (so no try/catch here)\n          xhr.send( ( s.hasContent && s.data ) || null );\n\n          // Listener\n          callback = function( _, isAbort ) {\n\n            var status,\n              statusText,\n              responseHeaders,\n              responses,\n              xml;\n\n            // Firefox throws exceptions when accessing properties\n            // of an xhr when a network error occured\n            // https://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n            try {\n\n              // Was never called and is aborted or complete\n              if ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n                // Only called once\n                callback = undefined;\n\n                // Do not keep as active anymore\n                if ( handle ) {\n                  xhr.onreadystatechange = jQuery.noop;\n                  if ( xhrOnUnloadAbort ) {\n                    delete xhrCallbacks[ handle ];\n                  }\n                }\n\n                // If it's an abort\n                if ( isAbort ) {\n                  // Abort it manually if needed\n                  if ( xhr.readyState !== 4 ) {\n                    xhr.abort();\n                  }\n                } else {\n                  status = xhr.status;\n                  responseHeaders = xhr.getAllResponseHeaders();\n                  responses = {};\n                  xml = xhr.responseXML;\n\n                  // Construct response list\n                  if ( xml && xml.documentElement /* #4958 */ ) {\n                    responses.xml = xml;\n                  }\n\n                  // When requesting binary data, IE6-9 will throw an exception\n                  // on any attempt to access responseText (#11426)\n                  try {\n                    responses.text = xhr.responseText;\n                  } catch( _ ) {\n                  }\n\n                  // Firefox throws an exception when accessing\n                  // statusText for faulty cross-domain requests\n                  try {\n                    statusText = xhr.statusText;\n                  } catch( e ) {\n                    // We normalize with Webkit giving an empty statusText\n                    statusText = \"\";\n                  }\n\n                  // Filter status for non standard behaviors\n\n                  // If the request is local and we have data: assume a success\n                  // (success with no data won't get notified, that's the best we\n                  // can do given current implementations)\n                  if ( !status && s.isLocal && !s.crossDomain ) {\n                    status = responses.text ? 200 : 404;\n                  // IE - #1450: sometimes returns 1223 when it should be 204\n                  } else if ( status === 1223 ) {\n                    status = 204;\n                  }\n                }\n              }\n            } catch( firefoxAccessException ) {\n              if ( !isAbort ) {\n                complete( -1, firefoxAccessException );\n              }\n            }\n\n            // Call complete if needed\n            if ( responses ) {\n              complete( status, statusText, responses, responseHeaders );\n            }\n          };\n\n          // if we're in sync mode or it's in cache\n          // and has been retrieved directly (IE6 & IE7)\n          // we need to manually fire the callback\n          if ( !s.async || xhr.readyState === 4 ) {\n            callback();\n          } else {\n            handle = ++xhrId;\n            if ( xhrOnUnloadAbort ) {\n              // Create the active xhrs callbacks list if needed\n              // and attach the unload handler\n              if ( !xhrCallbacks ) {\n                xhrCallbacks = {};\n                jQuery( window ).unload( xhrOnUnloadAbort );\n              }\n              // Add to list of active xhrs callbacks\n              xhrCallbacks[ handle ] = callback;\n            }\n            xhr.onreadystatechange = callback;\n          }\n        },\n\n        abort: function() {\n          if ( callback ) {\n            callback(0,1);\n          }\n        }\n      };\n    }\n  });\n}\n\n\n\n\nvar elemdisplay = {},\n  iframe, iframeDoc,\n  rfxtypes = /^(?:toggle|show|hide)$/,\n  rfxnum = /^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,\n  timerId,\n  fxAttrs = [\n    // height animations\n    [ \"height\", \"marginTop\", \"marginBottom\", \"paddingTop\", \"paddingBottom\" ],\n    // width animations\n    [ \"width\", \"marginLeft\", \"marginRight\", \"paddingLeft\", \"paddingRight\" ],\n    // opacity animations\n    [ \"opacity\" ]\n  ],\n  fxNow;\n\njQuery.fn.extend({\n  show: function( speed, easing, callback ) {\n    var elem, display;\n\n    if ( speed || speed === 0 ) {\n      return this.animate( genFx(\"show\", 3), speed, easing, callback );\n\n    } else {\n      for ( var i = 0, j = this.length; i < j; i++ ) {\n        elem = this[ i ];\n\n        if ( elem.style ) {\n          display = elem.style.display;\n\n          // Reset the inline display of this element to learn if it is\n          // being hidden by cascaded rules or not\n          if ( !jQuery._data(elem, \"olddisplay\") && display === \"none\" ) {\n            display = elem.style.display = \"\";\n          }\n\n          // Set elements which have been overridden with display: none\n          // in a stylesheet to whatever the default browser style is\n          // for such an element\n          if ( (display === \"\" && jQuery.css(elem, \"display\") === \"none\") ||\n            !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {\n            jQuery._data( elem, \"olddisplay\", defaultDisplay(elem.nodeName) );\n          }\n        }\n      }\n\n      // Set the display of most of the elements in a second loop\n      // to avoid the constant reflow\n      for ( i = 0; i < j; i++ ) {\n        elem = this[ i ];\n\n        if ( elem.style ) {\n          display = elem.style.display;\n\n          if ( display === \"\" || display === \"none\" ) {\n            elem.style.display = jQuery._data( elem, \"olddisplay\" ) || \"\";\n          }\n        }\n      }\n\n      return this;\n    }\n  },\n\n  hide: function( speed, easing, callback ) {\n    if ( speed || speed === 0 ) {\n      return this.animate( genFx(\"hide\", 3), speed, easing, callback);\n\n    } else {\n      var elem, display,\n        i = 0,\n        j = this.length;\n\n      for ( ; i < j; i++ ) {\n        elem = this[i];\n        if ( elem.style ) {\n          display = jQuery.css( elem, \"display\" );\n\n          if ( display !== \"none\" && !jQuery._data( elem, \"olddisplay\" ) ) {\n            jQuery._data( elem, \"olddisplay\", display );\n          }\n        }\n      }\n\n      // Set the display of the elements in a second loop\n      // to avoid the constant reflow\n      for ( i = 0; i < j; i++ ) {\n        if ( this[i].style ) {\n          this[i].style.display = \"none\";\n        }\n      }\n\n      return this;\n    }\n  },\n\n  // Save the old toggle function\n  _toggle: jQuery.fn.toggle,\n\n  toggle: function( fn, fn2, callback ) {\n    var bool = typeof fn === \"boolean\";\n\n    if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {\n      this._toggle.apply( this, arguments );\n\n    } else if ( fn == null || bool ) {\n      this.each(function() {\n        var state = bool ? fn : jQuery(this).is(\":hidden\");\n        jQuery(this)[ state ? \"show\" : \"hide\" ]();\n      });\n\n    } else {\n      this.animate(genFx(\"toggle\", 3), fn, fn2, callback);\n    }\n\n    return this;\n  },\n\n  fadeTo: function( speed, to, easing, callback ) {\n    return this.filter(\":hidden\").css(\"opacity\", 0).show().end()\n          .animate({opacity: to}, speed, easing, callback);\n  },\n\n  animate: function( prop, speed, easing, callback ) {\n    var optall = jQuery.speed( speed, easing, callback );\n\n    if ( jQuery.isEmptyObject( prop ) ) {\n      return this.each( optall.complete, [ false ] );\n    }\n\n    // Do not change referenced properties as per-property easing will be lost\n    prop = jQuery.extend( {}, prop );\n\n    function doAnimation() {\n      // XXX 'this' does not always have a nodeName when running the\n      // test suite\n\n      if ( optall.queue === false ) {\n        jQuery._mark( this );\n      }\n\n      var opt = jQuery.extend( {}, optall ),\n        isElement = this.nodeType === 1,\n        hidden = isElement && jQuery(this).is(\":hidden\"),\n        name, val, p, e, hooks, replace,\n        parts, start, end, unit,\n        method;\n\n      // will store per property easing and be used to determine when an animation is complete\n      opt.animatedProperties = {};\n\n      // first pass over propertys to expand / normalize\n      for ( p in prop ) {\n        name = jQuery.camelCase( p );\n        if ( p !== name ) {\n          prop[ name ] = prop[ p ];\n          delete prop[ p ];\n        }\n\n        if ( ( hooks = jQuery.cssHooks[ name ] ) && \"expand\" in hooks ) {\n          replace = hooks.expand( prop[ name ] );\n          delete prop[ name ];\n\n          // not quite $.extend, this wont overwrite keys already present.\n          // also - reusing 'p' from above because we have the correct \"name\"\n          for ( p in replace ) {\n            if ( ! ( p in prop ) ) {\n              prop[ p ] = replace[ p ];\n            }\n          }\n        }\n      }\n\n      for ( name in prop ) {\n        val = prop[ name ];\n        // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)\n        if ( jQuery.isArray( val ) ) {\n          opt.animatedProperties[ name ] = val[ 1 ];\n          val = prop[ name ] = val[ 0 ];\n        } else {\n          opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';\n        }\n\n        if ( val === \"hide\" && hidden || val === \"show\" && !hidden ) {\n          return opt.complete.call( this );\n        }\n\n        if ( isElement && ( name === \"height\" || name === \"width\" ) ) {\n          // Make sure that nothing sneaks out\n          // Record all 3 overflow attributes because IE does not\n          // change the overflow attribute when overflowX and\n          // overflowY are set to the same value\n          opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];\n\n          // Set display property to inline-block for height/width\n          // animations on inline elements that are having width/height animated\n          if ( jQuery.css( this, \"display\" ) === \"inline\" &&\n              jQuery.css( this, \"float\" ) === \"none\" ) {\n\n            // inline-level elements accept inline-block;\n            // block-level elements need to be inline with layout\n            if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === \"inline\" ) {\n              this.style.display = \"inline-block\";\n\n            } else {\n              this.style.zoom = 1;\n            }\n          }\n        }\n      }\n\n      if ( opt.overflow != null ) {\n        this.style.overflow = \"hidden\";\n      }\n\n      for ( p in prop ) {\n        e = new jQuery.fx( this, opt, p );\n        val = prop[ p ];\n\n        if ( rfxtypes.test( val ) ) {\n\n          // Tracks whether to show or hide based on private\n          // data attached to the element\n          method = jQuery._data( this, \"toggle\" + p ) || ( val === \"toggle\" ? hidden ? \"show\" : \"hide\" : 0 );\n          if ( method ) {\n            jQuery._data( this, \"toggle\" + p, method === \"show\" ? \"hide\" : \"show\" );\n            e[ method ]();\n          } else {\n            e[ val ]();\n          }\n\n        } else {\n          parts = rfxnum.exec( val );\n          start = e.cur();\n\n          if ( parts ) {\n            end = parseFloat( parts[2] );\n            unit = parts[3] || ( jQuery.cssNumber[ p ] ? \"\" : \"px\" );\n\n            // We need to compute starting value\n            if ( unit !== \"px\" ) {\n              jQuery.style( this, p, (end || 1) + unit);\n              start = ( (end || 1) / e.cur() ) * start;\n              jQuery.style( this, p, start + unit);\n            }\n\n            // If a +=/-= token was provided, we're doing a relative animation\n            if ( parts[1] ) {\n              end = ( (parts[ 1 ] === \"-=\" ? -1 : 1) * end ) + start;\n            }\n\n            e.custom( start, end, unit );\n\n          } else {\n            e.custom( start, val, \"\" );\n          }\n        }\n      }\n\n      // For JS strict compliance\n      return true;\n    }\n\n    return optall.queue === false ?\n      this.each( doAnimation ) :\n      this.queue( optall.queue, doAnimation );\n  },\n\n  stop: function( type, clearQueue, gotoEnd ) {\n    if ( typeof type !== \"string\" ) {\n      gotoEnd = clearQueue;\n      clearQueue = type;\n      type = undefined;\n    }\n    if ( clearQueue && type !== false ) {\n      this.queue( type || \"fx\", [] );\n    }\n\n    return this.each(function() {\n      var index,\n        hadTimers = false,\n        timers = jQuery.timers,\n        data = jQuery._data( this );\n\n      // clear marker counters if we know they won't be\n      if ( !gotoEnd ) {\n        jQuery._unmark( true, this );\n      }\n\n      function stopQueue( elem, data, index ) {\n        var hooks = data[ index ];\n        jQuery.removeData( elem, index, true );\n        hooks.stop( gotoEnd );\n      }\n\n      if ( type == null ) {\n        for ( index in data ) {\n          if ( data[ index ] && data[ index ].stop && index.indexOf(\".run\") === index.length - 4 ) {\n            stopQueue( this, data, index );\n          }\n        }\n      } else if ( data[ index = type + \".run\" ] && data[ index ].stop ){\n        stopQueue( this, data, index );\n      }\n\n      for ( index = timers.length; index--; ) {\n        if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n          if ( gotoEnd ) {\n\n            // force the next step to be the last\n            timers[ index ]( true );\n          } else {\n            timers[ index ].saveState();\n          }\n          hadTimers = true;\n          timers.splice( index, 1 );\n        }\n      }\n\n      // start the next in the queue if the last step wasn't forced\n      // timers currently will call their complete callbacks, which will dequeue\n      // but only if they were gotoEnd\n      if ( !( gotoEnd && hadTimers ) ) {\n        jQuery.dequeue( this, type );\n      }\n    });\n  }\n\n});\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n  setTimeout( clearFxNow, 0 );\n  return ( fxNow = jQuery.now() );\n}\n\nfunction clearFxNow() {\n  fxNow = undefined;\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, num ) {\n  var obj = {};\n\n  jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {\n    obj[ this ] = type;\n  });\n\n  return obj;\n}\n\n// Generate shortcuts for custom animations\njQuery.each({\n  slideDown: genFx( \"show\", 1 ),\n  slideUp: genFx( \"hide\", 1 ),\n  slideToggle: genFx( \"toggle\", 1 ),\n  fadeIn: { opacity: \"show\" },\n  fadeOut: { opacity: \"hide\" },\n  fadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n  jQuery.fn[ name ] = function( speed, easing, callback ) {\n    return this.animate( props, speed, easing, callback );\n  };\n});\n\njQuery.extend({\n  speed: function( speed, easing, fn ) {\n    var opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n      complete: fn || !fn && easing ||\n        jQuery.isFunction( speed ) && speed,\n      duration: speed,\n      easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n    };\n\n    opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n      opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n    // normalize opt.queue - true/undefined/null -> \"fx\"\n    if ( opt.queue == null || opt.queue === true ) {\n      opt.queue = \"fx\";\n    }\n\n    // Queueing\n    opt.old = opt.complete;\n\n    opt.complete = function( noUnmark ) {\n      if ( jQuery.isFunction( opt.old ) ) {\n        opt.old.call( this );\n      }\n\n      if ( opt.queue ) {\n        jQuery.dequeue( this, opt.queue );\n      } else if ( noUnmark !== false ) {\n        jQuery._unmark( this );\n      }\n    };\n\n    return opt;\n  },\n\n  easing: {\n    linear: function( p ) {\n      return p;\n    },\n    swing: function( p ) {\n      return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;\n    }\n  },\n\n  timers: [],\n\n  fx: function( elem, options, prop ) {\n    this.options = options;\n    this.elem = elem;\n    this.prop = prop;\n\n    options.orig = options.orig || {};\n  }\n\n});\n\njQuery.fx.prototype = {\n  // Simple function for setting a style value\n  update: function() {\n    if ( this.options.step ) {\n      this.options.step.call( this.elem, this.now, this );\n    }\n\n    ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );\n  },\n\n  // Get the current size\n  cur: function() {\n    if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {\n      return this.elem[ this.prop ];\n    }\n\n    var parsed,\n      r = jQuery.css( this.elem, this.prop );\n    // Empty strings, null, undefined and \"auto\" are converted to 0,\n    // complex values such as \"rotate(1rad)\" are returned as is,\n    // simple values such as \"10px\" are parsed to Float.\n    return isNaN( parsed = parseFloat( r ) ) ? !r || r === \"auto\" ? 0 : r : parsed;\n  },\n\n  // Start an animation from one number to another\n  custom: function( from, to, unit ) {\n    var self = this,\n      fx = jQuery.fx;\n\n    this.startTime = fxNow || createFxNow();\n    this.end = to;\n    this.now = this.start = from;\n    this.pos = this.state = 0;\n    this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? \"\" : \"px\" );\n\n    function t( gotoEnd ) {\n      return self.step( gotoEnd );\n    }\n\n    t.queue = this.options.queue;\n    t.elem = this.elem;\n    t.saveState = function() {\n      if ( jQuery._data( self.elem, \"fxshow\" + self.prop ) === undefined ) {\n        if ( self.options.hide ) {\n          jQuery._data( self.elem, \"fxshow\" + self.prop, self.start );\n        } else if ( self.options.show ) {\n          jQuery._data( self.elem, \"fxshow\" + self.prop, self.end );\n        }\n      }\n    };\n\n    if ( t() && jQuery.timers.push(t) && !timerId ) {\n      timerId = setInterval( fx.tick, fx.interval );\n    }\n  },\n\n  // Simple 'show' function\n  show: function() {\n    var dataShow = jQuery._data( this.elem, \"fxshow\" + this.prop );\n\n    // Remember where we started, so that we can go back to it later\n    this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );\n    this.options.show = true;\n\n    // Begin the animation\n    // Make sure that we start at a small width/height to avoid any flash of content\n    if ( dataShow !== undefined ) {\n      // This show is picking up where a previous hide or show left off\n      this.custom( this.cur(), dataShow );\n    } else {\n      this.custom( this.prop === \"width\" || this.prop === \"height\" ? 1 : 0, this.cur() );\n    }\n\n    // Start by showing the element\n    jQuery( this.elem ).show();\n  },\n\n  // Simple 'hide' function\n  hide: function() {\n    // Remember where we started, so that we can go back to it later\n    this.options.orig[ this.prop ] = jQuery._data( this.elem, \"fxshow\" + this.prop ) || jQuery.style( this.elem, this.prop );\n    this.options.hide = true;\n\n    // Begin the animation\n    this.custom( this.cur(), 0 );\n  },\n\n  // Each step of an animation\n  step: function( gotoEnd ) {\n    var p, n, complete,\n      t = fxNow || createFxNow(),\n      done = true,\n      elem = this.elem,\n      options = this.options;\n\n    if ( gotoEnd || t >= options.duration + this.startTime ) {\n      this.now = this.end;\n      this.pos = this.state = 1;\n      this.update();\n\n      options.animatedProperties[ this.prop ] = true;\n\n      for ( p in options.animatedProperties ) {\n        if ( options.animatedProperties[ p ] !== true ) {\n          done = false;\n        }\n      }\n\n      if ( done ) {\n        // Reset the overflow\n        if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {\n\n          jQuery.each( [ \"\", \"X\", \"Y\" ], function( index, value ) {\n            elem.style[ \"overflow\" + value ] = options.overflow[ index ];\n          });\n        }\n\n        // Hide the element if the \"hide\" operation was done\n        if ( options.hide ) {\n          jQuery( elem ).hide();\n        }\n\n        // Reset the properties, if the item has been hidden or shown\n        if ( options.hide || options.show ) {\n          for ( p in options.animatedProperties ) {\n            jQuery.style( elem, p, options.orig[ p ] );\n            jQuery.removeData( elem, \"fxshow\" + p, true );\n            // Toggle data is no longer needed\n            jQuery.removeData( elem, \"toggle\" + p, true );\n          }\n        }\n\n        // Execute the complete function\n        // in the event that the complete function throws an exception\n        // we must ensure it won't be called twice. #5684\n\n        complete = options.complete;\n        if ( complete ) {\n\n          options.complete = false;\n          complete.call( elem );\n        }\n      }\n\n      return false;\n\n    } else {\n      // classical easing cannot be used with an Infinity duration\n      if ( options.duration == Infinity ) {\n        this.now = t;\n      } else {\n        n = t - this.startTime;\n        this.state = n / options.duration;\n\n        // Perform the easing function, defaults to swing\n        this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );\n        this.now = this.start + ( (this.end - this.start) * this.pos );\n      }\n      // Perform the next step of the animation\n      this.update();\n    }\n\n    return true;\n  }\n};\n\njQuery.extend( jQuery.fx, {\n  tick: function() {\n    var timer,\n      timers = jQuery.timers,\n      i = 0;\n\n    for ( ; i < timers.length; i++ ) {\n      timer = timers[ i ];\n      // Checks the timer has not already been removed\n      if ( !timer() && timers[ i ] === timer ) {\n        timers.splice( i--, 1 );\n      }\n    }\n\n    if ( !timers.length ) {\n      jQuery.fx.stop();\n    }\n  },\n\n  interval: 13,\n\n  stop: function() {\n    clearInterval( timerId );\n    timerId = null;\n  },\n\n  speeds: {\n    slow: 600,\n    fast: 200,\n    // Default speed\n    _default: 400\n  },\n\n  step: {\n    opacity: function( fx ) {\n      jQuery.style( fx.elem, \"opacity\", fx.now );\n    },\n\n    _default: function( fx ) {\n      if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {\n        fx.elem.style[ fx.prop ] = fx.now + fx.unit;\n      } else {\n        fx.elem[ fx.prop ] = fx.now;\n      }\n    }\n  }\n});\n\n// Ensure props that can't be negative don't go there on undershoot easing\njQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {\n  // exclude marginTop, marginLeft, marginBottom and marginRight from this list\n  if ( prop.indexOf( \"margin\" ) ) {\n    jQuery.fx.step[ prop ] = function( fx ) {\n      jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );\n    };\n  }\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n  jQuery.expr.filters.animated = function( elem ) {\n    return jQuery.grep(jQuery.timers, function( fn ) {\n      return elem === fn.elem;\n    }).length;\n  };\n}\n\n// Try to restore the default display value of an element\nfunction defaultDisplay( nodeName ) {\n\n  if ( !elemdisplay[ nodeName ] ) {\n\n    var body = document.body,\n      elem = jQuery( \"<\" + nodeName + \">\" ).appendTo( body ),\n      display = elem.css( \"display\" );\n    elem.remove();\n\n    // If the simple way fails,\n    // get element's real default display by attaching it to a temp iframe\n    if ( display === \"none\" || display === \"\" ) {\n      // No iframe to use yet, so create it\n      if ( !iframe ) {\n        iframe = document.createElement( \"iframe\" );\n        iframe.frameBorder = iframe.width = iframe.height = 0;\n      }\n\n      body.appendChild( iframe );\n\n      // Create a cacheable copy of the iframe document on first call.\n      // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML\n      // document to it; WebKit & Firefox won't allow reusing the iframe document.\n      if ( !iframeDoc || !iframe.createElement ) {\n        iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;\n        iframeDoc.write( ( jQuery.support.boxModel ? \"<!doctype html>\" : \"\" ) + \"<html><body>\" );\n        iframeDoc.close();\n      }\n\n      elem = iframeDoc.createElement( nodeName );\n\n      iframeDoc.body.appendChild( elem );\n\n      display = jQuery.css( elem, \"display\" );\n      body.removeChild( iframe );\n    }\n\n    // Store the correct default display\n    elemdisplay[ nodeName ] = display;\n  }\n\n  return elemdisplay[ nodeName ];\n}\n\n\n\n\nvar getOffset,\n  rtable = /^t(?:able|d|h)$/i,\n  rroot = /^(?:body|html)$/i;\n\nif ( \"getBoundingClientRect\" in document.documentElement ) {\n  getOffset = function( elem, doc, docElem, box ) {\n    try {\n      box = elem.getBoundingClientRect();\n    } catch(e) {}\n\n    // Make sure we're not dealing with a disconnected DOM node\n    if ( !box || !jQuery.contains( docElem, elem ) ) {\n      return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };\n    }\n\n    var body = doc.body,\n      win = getWindow( doc ),\n      clientTop  = docElem.clientTop  || body.clientTop  || 0,\n      clientLeft = docElem.clientLeft || body.clientLeft || 0,\n      scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,\n      scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,\n      top  = box.top  + scrollTop  - clientTop,\n      left = box.left + scrollLeft - clientLeft;\n\n    return { top: top, left: left };\n  };\n\n} else {\n  getOffset = function( elem, doc, docElem ) {\n    var computedStyle,\n      offsetParent = elem.offsetParent,\n      prevOffsetParent = elem,\n      body = doc.body,\n      defaultView = doc.defaultView,\n      prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,\n      top = elem.offsetTop,\n      left = elem.offsetLeft;\n\n    while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {\n      if ( jQuery.support.fixedPosition && prevComputedStyle.position === \"fixed\" ) {\n        break;\n      }\n\n      computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;\n      top  -= elem.scrollTop;\n      left -= elem.scrollLeft;\n\n      if ( elem === offsetParent ) {\n        top  += elem.offsetTop;\n        left += elem.offsetLeft;\n\n        if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {\n          top  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n          left += parseFloat( computedStyle.borderLeftWidth ) || 0;\n        }\n\n        prevOffsetParent = offsetParent;\n        offsetParent = elem.offsetParent;\n      }\n\n      if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== \"visible\" ) {\n        top  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n        left += parseFloat( computedStyle.borderLeftWidth ) || 0;\n      }\n\n      prevComputedStyle = computedStyle;\n    }\n\n    if ( prevComputedStyle.position === \"relative\" || prevComputedStyle.position === \"static\" ) {\n      top  += body.offsetTop;\n      left += body.offsetLeft;\n    }\n\n    if ( jQuery.support.fixedPosition && prevComputedStyle.position === \"fixed\" ) {\n      top  += Math.max( docElem.scrollTop, body.scrollTop );\n      left += Math.max( docElem.scrollLeft, body.scrollLeft );\n    }\n\n    return { top: top, left: left };\n  };\n}\n\njQuery.fn.offset = function( options ) {\n  if ( arguments.length ) {\n    return options === undefined ?\n      this :\n      this.each(function( i ) {\n        jQuery.offset.setOffset( this, options, i );\n      });\n  }\n\n  var elem = this[0],\n    doc = elem && elem.ownerDocument;\n\n  if ( !doc ) {\n    return null;\n  }\n\n  if ( elem === doc.body ) {\n    return jQuery.offset.bodyOffset( elem );\n  }\n\n  return getOffset( elem, doc, doc.documentElement );\n};\n\njQuery.offset = {\n\n  bodyOffset: function( body ) {\n    var top = body.offsetTop,\n      left = body.offsetLeft;\n\n    if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {\n      top  += parseFloat( jQuery.css(body, \"marginTop\") ) || 0;\n      left += parseFloat( jQuery.css(body, \"marginLeft\") ) || 0;\n    }\n\n    return { top: top, left: left };\n  },\n\n  setOffset: function( elem, options, i ) {\n    var position = jQuery.css( elem, \"position\" );\n\n    // set position first, in-case top/left are set even on static elem\n    if ( position === \"static\" ) {\n      elem.style.position = \"relative\";\n    }\n\n    var curElem = jQuery( elem ),\n      curOffset = curElem.offset(),\n      curCSSTop = jQuery.css( elem, \"top\" ),\n      curCSSLeft = jQuery.css( elem, \"left\" ),\n      calculatePosition = ( position === \"absolute\" || position === \"fixed\" ) && jQuery.inArray(\"auto\", [curCSSTop, curCSSLeft]) > -1,\n      props = {}, curPosition = {}, curTop, curLeft;\n\n    // need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n    if ( calculatePosition ) {\n      curPosition = curElem.position();\n      curTop = curPosition.top;\n      curLeft = curPosition.left;\n    } else {\n      curTop = parseFloat( curCSSTop ) || 0;\n      curLeft = parseFloat( curCSSLeft ) || 0;\n    }\n\n    if ( jQuery.isFunction( options ) ) {\n      options = options.call( elem, i, curOffset );\n    }\n\n    if ( options.top != null ) {\n      props.top = ( options.top - curOffset.top ) + curTop;\n    }\n    if ( options.left != null ) {\n      props.left = ( options.left - curOffset.left ) + curLeft;\n    }\n\n    if ( \"using\" in options ) {\n      options.using.call( elem, props );\n    } else {\n      curElem.css( props );\n    }\n  }\n};\n\n\njQuery.fn.extend({\n\n  position: function() {\n    if ( !this[0] ) {\n      return null;\n    }\n\n    var elem = this[0],\n\n    // Get *real* offsetParent\n    offsetParent = this.offsetParent(),\n\n    // Get correct offsets\n    offset       = this.offset(),\n    parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();\n\n    // Subtract element margins\n    // note: when an element has margin: auto the offsetLeft and marginLeft\n    // are the same in Safari causing offset.left to incorrectly be 0\n    offset.top  -= parseFloat( jQuery.css(elem, \"marginTop\") ) || 0;\n    offset.left -= parseFloat( jQuery.css(elem, \"marginLeft\") ) || 0;\n\n    // Add offsetParent borders\n    parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], \"borderTopWidth\") ) || 0;\n    parentOffset.left += parseFloat( jQuery.css(offsetParent[0], \"borderLeftWidth\") ) || 0;\n\n    // Subtract the two offsets\n    return {\n      top:  offset.top  - parentOffset.top,\n      left: offset.left - parentOffset.left\n    };\n  },\n\n  offsetParent: function() {\n    return this.map(function() {\n      var offsetParent = this.offsetParent || document.body;\n      while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, \"position\") === \"static\") ) {\n        offsetParent = offsetParent.offsetParent;\n      }\n      return offsetParent;\n    });\n  }\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( {scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\"}, function( method, prop ) {\n  var top = /Y/.test( prop );\n\n  jQuery.fn[ method ] = function( val ) {\n    return jQuery.access( this, function( elem, method, val ) {\n      var win = getWindow( elem );\n\n      if ( val === undefined ) {\n        return win ? (prop in win) ? win[ prop ] :\n          jQuery.support.boxModel && win.document.documentElement[ method ] ||\n            win.document.body[ method ] :\n          elem[ method ];\n      }\n\n      if ( win ) {\n        win.scrollTo(\n          !top ? val : jQuery( win ).scrollLeft(),\n           top ? val : jQuery( win ).scrollTop()\n        );\n\n      } else {\n        elem[ method ] = val;\n      }\n    }, method, val, arguments.length, null );\n  };\n});\n\nfunction getWindow( elem ) {\n  return jQuery.isWindow( elem ) ?\n    elem :\n    elem.nodeType === 9 ?\n      elem.defaultView || elem.parentWindow :\n      false;\n}\n\n\n\n\n// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n  var clientProp = \"client\" + name,\n    scrollProp = \"scroll\" + name,\n    offsetProp = \"offset\" + name;\n\n  // innerHeight and innerWidth\n  jQuery.fn[ \"inner\" + name ] = function() {\n    var elem = this[0];\n    return elem ?\n      elem.style ?\n      parseFloat( jQuery.css( elem, type, \"padding\" ) ) :\n      this[ type ]() :\n      null;\n  };\n\n  // outerHeight and outerWidth\n  jQuery.fn[ \"outer\" + name ] = function( margin ) {\n    var elem = this[0];\n    return elem ?\n      elem.style ?\n      parseFloat( jQuery.css( elem, type, margin ? \"margin\" : \"border\" ) ) :\n      this[ type ]() :\n      null;\n  };\n\n  jQuery.fn[ type ] = function( value ) {\n    return jQuery.access( this, function( elem, type, value ) {\n      var doc, docElemProp, orig, ret;\n\n      if ( jQuery.isWindow( elem ) ) {\n        // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat\n        doc = elem.document;\n        docElemProp = doc.documentElement[ clientProp ];\n        return jQuery.support.boxModel && docElemProp ||\n          doc.body && doc.body[ clientProp ] || docElemProp;\n      }\n\n      // Get document width or height\n      if ( elem.nodeType === 9 ) {\n        // Either scroll[Width/Height] or offset[Width/Height], whichever is greater\n        doc = elem.documentElement;\n\n        // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]\n        // so we can't use max, as it'll choose the incorrect offset[Width/Height]\n        // instead we use the correct client[Width/Height]\n        // support:IE6\n        if ( doc[ clientProp ] >= doc[ scrollProp ] ) {\n          return doc[ clientProp ];\n        }\n\n        return Math.max(\n          elem.body[ scrollProp ], doc[ scrollProp ],\n          elem.body[ offsetProp ], doc[ offsetProp ]\n        );\n      }\n\n      // Get width or height on the element\n      if ( value === undefined ) {\n        orig = jQuery.css( elem, type );\n        ret = parseFloat( orig );\n        return jQuery.isNumeric( ret ) ? ret : orig;\n      }\n\n      // Set the width or height on the element\n      jQuery( elem ).css( type, value );\n    }, type, value, arguments.length, null );\n  };\n});\n\n\n\n\n// Expose jQuery to the global object\nwindow.jQuery = window.$ = jQuery;\n\n// Expose jQuery as an AMD module, but only for AMD loaders that\n// understand the issues with loading multiple versions of jQuery\n// in a page that all might call define(). The loader will indicate\n// they have special allowances for multiple jQuery versions by\n// specifying define.amd.jQuery = true. Register as a named module,\n// since jQuery can be concatenated with other files that may use define,\n// but not use a proper concatenation script that understands anonymous\n// AMD modules. A named AMD is safest and most robust way to register.\n// Lowercase jquery is used because AMD module names are derived from\n// file names, and jQuery is normally delivered in a lowercase file name.\n// Do this after creating the global so that if an AMD module wants to call\n// noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd && define.amd.jQuery ) {\n  define( \"jquery\", [], function () { return jQuery; } );\n}\n\n\n\n})( window );"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/static/js/jquery.validate.js",
    "content": "/**\n * jQuery Validation Plugin @VERSION\n *\n * https://bassistance.de/jquery-plugins/jquery-plugin-validation/\n * https://docs.jquery.com/Plugins/Validation\n *\n * Copyright (c) 2012 JÃ¶rn Zaefferer\n *\n * Dual licensed under the MIT and GPL licenses:\n *   https://www.opensource.org/licenses/mit-license.php\n *   https://www.gnu.org/licenses/gpl.html\n */\n\n(function($) {\n\n$.extend($.fn, {\n  // https://docs.jquery.com/Plugins/Validation/validate\n  validate: function( options ) {\n\n    // if nothing is selected, return nothing; can't chain anyway\n    if (!this.length) {\n      if (options && options.debug && window.console) {\n        console.warn( \"nothing selected, can't validate, returning nothing\" );\n      }\n      return;\n    }\n\n    // check if a validator for this form was already created\n    var validator = $.data(this[0], 'validator');\n    if ( validator ) {\n      return validator;\n    }\n\n    // Add novalidate tag if HTML5.\n    this.attr('novalidate', 'novalidate');\n\n    validator = new $.validator( options, this[0] );\n    $.data(this[0], 'validator', validator);\n\n    if ( validator.settings.onsubmit ) {\n\n      this.validateDelegate( \":submit\", \"click\", function(ev) {\n        if ( validator.settings.submitHandler ) {\n          validator.submitButton = ev.target;\n        }\n        // allow suppressing validation by adding a cancel class to the submit button\n        if ( $(ev.target).hasClass('cancel') ) {\n          validator.cancelSubmit = true;\n        }\n      });\n\n      // validate the form on submit\n      this.submit( function( event ) {\n        if ( validator.settings.debug ) {\n          // prevent form submit to be able to see console output\n          event.preventDefault();\n        }\n        function handle() {\n          var hidden;\n          if ( validator.settings.submitHandler ) {\n            if (validator.submitButton) {\n              // insert a hidden input as a replacement for the missing submit button\n              hidden = $(\"<input type='hidden'/>\").attr(\"name\", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);\n            }\n            validator.settings.submitHandler.call( validator, validator.currentForm, event );\n            if (validator.submitButton) {\n              // and clean up afterwards; thanks to no-block-scope, hidden can be referenced\n              hidden.remove();\n            }\n            return false;\n          }\n          return true;\n        }\n\n        // prevent submit for invalid forms or custom submit handlers\n        if ( validator.cancelSubmit ) {\n          validator.cancelSubmit = false;\n          return handle();\n        }\n        if ( validator.form() ) {\n          if ( validator.pendingRequest ) {\n            validator.formSubmitted = true;\n            return false;\n          }\n          return handle();\n        } else {\n          validator.focusInvalid();\n          return false;\n        }\n      });\n    }\n\n    return validator;\n  },\n  // https://docs.jquery.com/Plugins/Validation/valid\n  valid: function() {\n    if ( $(this[0]).is('form')) {\n      return this.validate().form();\n    } else {\n      var valid = true;\n      var validator = $(this[0].form).validate();\n      this.each(function() {\n        valid &= validator.element(this);\n      });\n      return valid;\n    }\n  },\n  // attributes: space seperated list of attributes to retrieve and remove\n  removeAttrs: function(attributes) {\n    var result = {},\n      $element = this;\n    $.each(attributes.split(/\\s/), function(index, value) {\n      result[value] = $element.attr(value);\n      $element.removeAttr(value);\n    });\n    return result;\n  },\n  // https://docs.jquery.com/Plugins/Validation/rules\n  rules: function(command, argument) {\n    var element = this[0];\n\n    if (command) {\n      var settings = $.data(element.form, 'validator').settings;\n      var staticRules = settings.rules;\n      var existingRules = $.validator.staticRules(element);\n      switch(command) {\n      case \"add\":\n        $.extend(existingRules, $.validator.normalizeRule(argument));\n        staticRules[element.name] = existingRules;\n        if (argument.messages) {\n          settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );\n        }\n        break;\n      case \"remove\":\n        if (!argument) {\n          delete staticRules[element.name];\n          return existingRules;\n        }\n        var filtered = {};\n        $.each(argument.split(/\\s/), function(index, method) {\n          filtered[method] = existingRules[method];\n          delete existingRules[method];\n        });\n        return filtered;\n      }\n    }\n\n    var data = $.validator.normalizeRules(\n    $.extend(\n      {},\n      $.validator.metadataRules(element),\n      $.validator.classRules(element),\n      $.validator.attributeRules(element),\n      $.validator.staticRules(element)\n    ), element);\n\n    // make sure required is at front\n    if (data.required) {\n      var param = data.required;\n      delete data.required;\n      data = $.extend({required: param}, data);\n    }\n\n    return data;\n  }\n});\n\n// Custom selectors\n$.extend($.expr[\":\"], {\n  // https://docs.jquery.com/Plugins/Validation/blank\n  blank: function(a) {return !$.trim(\"\" + a.value);},\n  // https://docs.jquery.com/Plugins/Validation/filled\n  filled: function(a) {return !!$.trim(\"\" + a.value);},\n  // https://docs.jquery.com/Plugins/Validation/unchecked\n  unchecked: function(a) {return !a.checked;}\n});\n\n// constructor for validator\n$.validator = function( options, form ) {\n  this.settings = $.extend( true, {}, $.validator.defaults, options );\n  this.currentForm = form;\n  this.init();\n};\n\n$.validator.format = function(source, params) {\n  if ( arguments.length === 1 ) {\n    return function() {\n      var args = $.makeArray(arguments);\n      args.unshift(source);\n      return $.validator.format.apply( this, args );\n    };\n  }\n  if ( arguments.length > 2 && params.constructor !== Array  ) {\n    params = $.makeArray(arguments).slice(1);\n  }\n  if ( params.constructor !== Array ) {\n    params = [ params ];\n  }\n  $.each(params, function(i, n) {\n    source = source.replace(new RegExp(\"\\\\{\" + i + \"\\\\}\", \"g\"), n);\n  });\n  return source;\n};\n\n$.extend($.validator, {\n\n  defaults: {\n    messages: {},\n    groups: {},\n    rules: {},\n    errorClass: \"error\",\n    validClass: \"valid\",\n    errorElement: \"label\",\n    focusInvalid: true,\n    errorContainer: $( [] ),\n    errorLabelContainer: $( [] ),\n    onsubmit: true,\n    ignore: \":hidden\",\n    ignoreTitle: false,\n    onfocusin: function(element, event) {\n      this.lastActive = element;\n\n      // hide error label and remove error class on focus if enabled\n      if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {\n        if ( this.settings.unhighlight ) {\n          this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );\n        }\n        this.addWrapper(this.errorsFor(element)).hide();\n      }\n    },\n    onfocusout: function(element, event) {\n      if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {\n        this.element(element);\n      }\n    },\n    onkeyup: function(element, event) {\n      if ( element.name in this.submitted || element === this.lastElement ) {\n        this.element(element);\n      }\n    },\n    onclick: function(element, event) {\n      // click on selects, radiobuttons and checkboxes\n      if ( element.name in this.submitted ) {\n        this.element(element);\n      }\n      // or option elements, check parent select in that case\n      else if (element.parentNode.name in this.submitted) {\n        this.element(element.parentNode);\n      }\n    },\n    highlight: function(element, errorClass, validClass) {\n      if (element.type === 'radio') {\n        this.findByName(element.name).addClass(errorClass).removeClass(validClass);\n      } else {\n        $(element).addClass(errorClass).removeClass(validClass);\n      }\n    },\n    unhighlight: function(element, errorClass, validClass) {\n      if (element.type === 'radio') {\n        this.findByName(element.name).removeClass(errorClass).addClass(validClass);\n      } else {\n        $(element).removeClass(errorClass).addClass(validClass);\n      }\n    }\n  },\n\n  // https://docs.jquery.com/Plugins/Validation/Validator/setDefaults\n  setDefaults: function(settings) {\n    $.extend( $.validator.defaults, settings );\n  },\n\n  messages: {\n    required: \"This field is required.\",\n    remote: \"Please fix this field.\",\n    email: \"Please enter a valid email address.\",\n    url: \"Please enter a valid URL.\",\n    date: \"Please enter a valid date.\",\n    dateISO: \"Please enter a valid date (ISO).\",\n    number: \"Please enter a valid number.\",\n    digits: \"Please enter only digits.\",\n    creditcard: \"Please enter a valid credit card number.\",\n    equalTo: \"Please enter the same value again.\",\n    accept: \"Please enter a value with a valid extension.\",\n    maxlength: $.validator.format(\"Please enter no more than {0} characters.\"),\n    minlength: $.validator.format(\"Please enter at least {0} characters.\"),\n    rangelength: $.validator.format(\"Please enter a value between {0} and {1} characters long.\"),\n    range: $.validator.format(\"Please enter a value between {0} and {1}.\"),\n    max: $.validator.format(\"Please enter a value less than or equal to {0}.\"),\n    min: $.validator.format(\"Please enter a value greater than or equal to {0}.\")\n  },\n\n  autoCreateRanges: false,\n\n  prototype: {\n\n    init: function() {\n      this.labelContainer = $(this.settings.errorLabelContainer);\n      this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);\n      this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );\n      this.submitted = {};\n      this.valueCache = {};\n      this.pendingRequest = 0;\n      this.pending = {};\n      this.invalid = {};\n      this.reset();\n\n      var groups = (this.groups = {});\n      $.each(this.settings.groups, function(key, value) {\n        $.each(value.split(/\\s/), function(index, name) {\n          groups[name] = key;\n        });\n      });\n      var rules = this.settings.rules;\n      $.each(rules, function(key, value) {\n        rules[key] = $.validator.normalizeRule(value);\n      });\n\n      function delegate(event) {\n        var validator = $.data(this[0].form, \"validator\"),\n          eventType = \"on\" + event.type.replace(/^validate/, \"\");\n        if (validator.settings[eventType]) {\n          validator.settings[eventType].call(validator, this[0], event);\n        }\n      }\n      $(this.currentForm)\n        .validateDelegate(\"[type='text'], [type='password'], [type='file'], select, textarea, \" +\n          \"[type='number'], [type='search'] ,[type='tel'], [type='url'], \" +\n          \"[type='email'], [type='datetime'], [type='date'], [type='month'], \" +\n          \"[type='week'], [type='time'], [type='datetime-local'], \" +\n          \"[type='range'], [type='color'] \",\n          \"focusin focusout keyup\", delegate)\n        .validateDelegate(\"[type='radio'], [type='checkbox'], select, option\", \"click\", delegate);\n\n      if (this.settings.invalidHandler) {\n        $(this.currentForm).bind(\"invalid-form.validate\", this.settings.invalidHandler);\n      }\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Validator/form\n    form: function() {\n      this.checkForm();\n      $.extend(this.submitted, this.errorMap);\n      this.invalid = $.extend({}, this.errorMap);\n      if (!this.valid()) {\n        $(this.currentForm).triggerHandler(\"invalid-form\", [this]);\n      }\n      this.showErrors();\n      return this.valid();\n    },\n\n    checkForm: function() {\n      this.prepareForm();\n      for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {\n        this.check( elements[i] );\n      }\n      return this.valid();\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Validator/element\n    element: function( element ) {\n      element = this.validationTargetFor( this.clean( element ) );\n      this.lastElement = element;\n      this.prepareElement( element );\n      this.currentElements = $(element);\n      var result = this.check( element ) !== false;\n      if (result) {\n        delete this.invalid[element.name];\n      } else {\n        this.invalid[element.name] = true;\n      }\n      if ( !this.numberOfInvalids() ) {\n        // Hide error containers on last error\n        this.toHide = this.toHide.add( this.containers );\n      }\n      this.showErrors();\n      return result;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Validator/showErrors\n    showErrors: function(errors) {\n      if(errors) {\n        // add items to error list and map\n        $.extend( this.errorMap, errors );\n        this.errorList = [];\n        for ( var name in errors ) {\n          this.errorList.push({\n            message: errors[name],\n            element: this.findByName(name)[0]\n          });\n        }\n        // remove items from success list\n        this.successList = $.grep( this.successList, function(element) {\n          return !(element.name in errors);\n        });\n      }\n      if (this.settings.showErrors) {\n        this.settings.showErrors.call( this, this.errorMap, this.errorList );\n      } else {\n        this.defaultShowErrors();\n      }\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Validator/resetForm\n    resetForm: function() {\n      if ( $.fn.resetForm ) {\n        $( this.currentForm ).resetForm();\n      }\n      this.submitted = {};\n      this.lastElement = null;\n      this.prepareForm();\n      this.hideErrors();\n      this.elements().removeClass( this.settings.errorClass );\n    },\n\n    numberOfInvalids: function() {\n      return this.objectLength(this.invalid);\n    },\n\n    objectLength: function( obj ) {\n      var count = 0;\n      for ( var i in obj ) {\n        count++;\n      }\n      return count;\n    },\n\n    hideErrors: function() {\n      this.addWrapper( this.toHide ).hide();\n    },\n\n    valid: function() {\n      return this.size() === 0;\n    },\n\n    size: function() {\n      return this.errorList.length;\n    },\n\n    focusInvalid: function() {\n      if( this.settings.focusInvalid ) {\n        try {\n          $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])\n          .filter(\":visible\")\n          .focus()\n          // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find\n          .trigger(\"focusin\");\n        } catch(e) {\n          // ignore IE throwing errors when focusing hidden elements\n        }\n      }\n    },\n\n    findLastActive: function() {\n      var lastActive = this.lastActive;\n      return lastActive && $.grep(this.errorList, function(n) {\n        return n.element.name === lastActive.name;\n      }).length === 1 && lastActive;\n    },\n\n    elements: function() {\n      var validator = this,\n        rulesCache = {};\n\n      // select all valid inputs inside the form (no submit or reset buttons)\n      return $(this.currentForm)\n      .find(\"input, select, textarea\")\n      .not(\":submit, :reset, :image, [disabled]\")\n      .not( this.settings.ignore )\n      .filter(function() {\n        if ( !this.name && validator.settings.debug && window.console ) {\n          console.error( \"%o has no name assigned\", this);\n        }\n\n        // select only the first element for each name, and only those with rules specified\n        if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {\n          return false;\n        }\n\n        rulesCache[this.name] = true;\n        return true;\n      });\n    },\n\n    clean: function( selector ) {\n      return $( selector )[0];\n    },\n\n    errors: function() {\n      var errorClass = this.settings.errorClass.replace(' ', '.');\n      return $( this.settings.errorElement + \".\" + errorClass, this.errorContext );\n    },\n\n    reset: function() {\n      this.successList = [];\n      this.errorList = [];\n      this.errorMap = {};\n      this.toShow = $([]);\n      this.toHide = $([]);\n      this.currentElements = $([]);\n    },\n\n    prepareForm: function() {\n      this.reset();\n      this.toHide = this.errors().add( this.containers );\n    },\n\n    prepareElement: function( element ) {\n      this.reset();\n      this.toHide = this.errorsFor(element);\n    },\n\n    elementValue: function( element ) {\n      var val = $(element).val();\n      if( typeof val === 'string' ) {\n        return val.replace(/\\r/g, \"\");\n      }\n      return val;\n    },\n\n    check: function( element ) {\n      element = this.validationTargetFor( this.clean( element ) );\n\n      var rules = $(element).rules();\n      var dependencyMismatch = false;\n      var val = this.elementValue(element);\n      var result;\n\n      for (var method in rules ) {\n        var rule = { method: method, parameters: rules[method] };\n        try {\n\n          result = $.validator.methods[method].call( this, val, element, rule.parameters );\n\n          // if a method indicates that the field is optional and therefore valid,\n          // don't mark it as valid when there are no other rules\n          if ( result === \"dependency-mismatch\" ) {\n            dependencyMismatch = true;\n            continue;\n          }\n          dependencyMismatch = false;\n\n          if ( result === \"pending\" ) {\n            this.toHide = this.toHide.not( this.errorsFor(element) );\n            return;\n          }\n\n          if( !result ) {\n            this.formatAndAdd( element, rule );\n            return false;\n          }\n        } catch(e) {\n          if ( this.settings.debug && window.console ) {\n            console.log(\"exception occured when checking element \" + element.id + \", check the '\" + rule.method + \"' method\", e);\n          }\n          throw e;\n        }\n      }\n      if (dependencyMismatch) {\n        return;\n      }\n      if ( this.objectLength(rules) ) {\n        this.successList.push(element);\n      }\n      return true;\n    },\n\n    // return the custom message for the given element and validation method\n    // specified in the element's \"messages\" metadata\n    customMetaMessage: function(element, method) {\n      if (!$.metadata) {\n        return;\n      }\n      var meta = this.settings.meta ? $(element).metadata()[this.settings.meta] : $(element).metadata();\n      return meta && meta.messages && meta.messages[method];\n    },\n\n    // return the custom message for the given element name and validation method\n    customMessage: function( name, method ) {\n      var m = this.settings.messages[name];\n      return m && (m.constructor === String ? m : m[method]);\n    },\n\n    // return the first defined argument, allowing empty strings\n    findDefined: function() {\n      for(var i = 0; i < arguments.length; i++) {\n        if (arguments[i] !== undefined) {\n          return arguments[i];\n        }\n      }\n      return undefined;\n    },\n\n    defaultMessage: function( element, method) {\n      return this.findDefined(\n        this.customMessage( element.name, method ),\n        this.customMetaMessage( element, method ),\n        // title is never undefined, so handle empty string as undefined\n        !this.settings.ignoreTitle && element.title || undefined,\n        $.validator.messages[method],\n        \"<strong>Warning: No message defined for \" + element.name + \"</strong>\"\n      );\n    },\n\n    formatAndAdd: function( element, rule ) {\n      var message = this.defaultMessage( element, rule.method ),\n        theregex = /\\$?\\{(\\d+)\\}/g;\n      if ( typeof message === \"function\" ) {\n        message = message.call(this, rule.parameters, element);\n      } else if (theregex.test(message)) {\n        message = $.validator.format(message.replace(theregex, '{$1}'), rule.parameters);\n      }\n      this.errorList.push({\n        message: message,\n        element: element\n      });\n\n      this.errorMap[element.name] = message;\n      this.submitted[element.name] = message;\n    },\n\n    addWrapper: function(toToggle) {\n      if ( this.settings.wrapper ) {\n        toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );\n      }\n      return toToggle;\n    },\n\n    defaultShowErrors: function() {\n      var i, elements;\n      for ( i = 0; this.errorList[i]; i++ ) {\n        var error = this.errorList[i];\n        if ( this.settings.highlight ) {\n          this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );\n        }\n        this.showLabel( error.element, error.message );\n      }\n      if( this.errorList.length ) {\n        this.toShow = this.toShow.add( this.containers );\n      }\n      if (this.settings.success) {\n        for ( i = 0; this.successList[i]; i++ ) {\n          this.showLabel( this.successList[i] );\n        }\n      }\n      if (this.settings.unhighlight) {\n        for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {\n          this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );\n        }\n      }\n      this.toHide = this.toHide.not( this.toShow );\n      this.hideErrors();\n      this.addWrapper( this.toShow ).show();\n    },\n\n    validElements: function() {\n      return this.currentElements.not(this.invalidElements());\n    },\n\n    invalidElements: function() {\n      return $(this.errorList).map(function() {\n        return this.element;\n      });\n    },\n\n    showLabel: function(element, message) {\n      var label = this.errorsFor( element );\n      if ( label.length ) {\n        // refresh error/success class\n        label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );\n\n        // check if we have a generated label, replace the message then\n        if ( label.attr(\"generated\") ) {\n          label.html(message);\n        }\n      } else {\n        // create label\n        label = $(\"<\" + this.settings.errorElement + \"/>\")\n          .attr({\"for\":  this.idOrName(element), generated: true})\n          .addClass(this.settings.errorClass)\n          .html(message || \"\");\n        if ( this.settings.wrapper ) {\n          // make sure the element is visible, even in IE\n          // actually showing the wrapped element is handled elsewhere\n          label = label.hide().show().wrap(\"<\" + this.settings.wrapper + \"/>\").parent();\n        }\n        if ( !this.labelContainer.append(label).length ) {\n          if ( this.settings.errorPlacement ) {\n            this.settings.errorPlacement(label, $(element) );\n          } else {\n          label.insertAfter(element);\n          }\n        }\n      }\n      if ( !message && this.settings.success ) {\n        label.text(\"\");\n        if ( typeof this.settings.success === \"string\" ) {\n          label.addClass( this.settings.success );\n        } else {\n          this.settings.success( label );\n        }\n      }\n      this.toShow = this.toShow.add(label);\n    },\n\n    errorsFor: function(element) {\n      var name = this.idOrName(element);\n      return this.errors().filter(function() {\n        return $(this).attr('for') === name;\n      });\n    },\n\n    idOrName: function(element) {\n      return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);\n    },\n\n    validationTargetFor: function(element) {\n      // if radio/checkbox, validate first element in group instead\n      if (this.checkable(element)) {\n        element = this.findByName( element.name ).not(this.settings.ignore)[0];\n      }\n      return element;\n    },\n\n    checkable: function( element ) {\n      return (/radio|checkbox/i).test(element.type);\n    },\n\n    findByName: function( name ) {\n      // select by name and filter by form for performance over form.find(\"[name=...]\")\n      var form = this.currentForm;\n      return $(document.getElementsByName(name)).map(function(index, element) {\n        return element.form === form && element.name === name && element  || null;\n      });\n    },\n\n    getLength: function(value, element) {\n      switch( element.nodeName.toLowerCase() ) {\n      case 'select':\n        return $(\"option:selected\", element).length;\n      case 'input':\n        if( this.checkable( element) ) {\n          return this.findByName(element.name).filter(':checked').length;\n        }\n      }\n      return value.length;\n    },\n\n    depend: function(param, element) {\n      return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;\n    },\n\n    dependTypes: {\n      \"boolean\": function(param, element) {\n        return param;\n      },\n      \"string\": function(param, element) {\n        return !!$(param, element.form).length;\n      },\n      \"function\": function(param, element) {\n        return param(element);\n      }\n    },\n\n    optional: function(element) {\n      var val = this.elementValue(element);\n      return !$.validator.methods.required.call(this, val, element) && \"dependency-mismatch\";\n    },\n\n    startRequest: function(element) {\n      if (!this.pending[element.name]) {\n        this.pendingRequest++;\n        this.pending[element.name] = true;\n      }\n    },\n\n    stopRequest: function(element, valid) {\n      this.pendingRequest--;\n      // sometimes synchronization fails, make sure pendingRequest is never < 0\n      if (this.pendingRequest < 0) {\n        this.pendingRequest = 0;\n      }\n      delete this.pending[element.name];\n      if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {\n        $(this.currentForm).submit();\n        this.formSubmitted = false;\n      } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {\n        $(this.currentForm).triggerHandler(\"invalid-form\", [this]);\n        this.formSubmitted = false;\n      }\n    },\n\n    previousValue: function(element) {\n      return $.data(element, \"previousValue\") || $.data(element, \"previousValue\", {\n        old: null,\n        valid: true,\n        message: this.defaultMessage( element, \"remote\" )\n      });\n    }\n\n  },\n\n  classRuleSettings: {\n    required: {required: true},\n    email: {email: true},\n    url: {url: true},\n    date: {date: true},\n    dateISO: {dateISO: true},\n    number: {number: true},\n    digits: {digits: true},\n    creditcard: {creditcard: true}\n  },\n\n  addClassRules: function(className, rules) {\n    if ( className.constructor === String ) {\n      this.classRuleSettings[className] = rules;\n    } else {\n      $.extend(this.classRuleSettings, className);\n    }\n  },\n\n  classRules: function(element) {\n    var rules = {};\n    var classes = $(element).attr('class');\n    if ( classes ) {\n      $.each(classes.split(' '), function() {\n        if (this in $.validator.classRuleSettings) {\n          $.extend(rules, $.validator.classRuleSettings[this]);\n        }\n      });\n    }\n    return rules;\n  },\n\n  attributeRules: function(element) {\n    var rules = {};\n    var $element = $(element);\n\n    for (var method in $.validator.methods) {\n      var value;\n\n      // support for <input required> in both html5 and older browsers\n      if (method === 'required') {\n        value = $element.get(0).getAttribute(method);\n        // Some browsers return an empty string for the required attribute\n        // and non-HTML5 browsers might have required=\"\" markup\n        if (value === \"\") {\n          value = true;\n        } else if (value === \"false\") {\n          value = false;\n        }\n        // force non-HTML5 browsers to return bool\n        value = !!value;\n      } else {\n        value = $element.attr(method);\n      }\n\n      if (value) {\n        rules[method] = value;\n      } else if ($element[0].getAttribute(\"type\") === method) {\n        rules[method] = true;\n      }\n    }\n\n    // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs\n    if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {\n      delete rules.maxlength;\n    }\n\n    return rules;\n  },\n\n  metadataRules: function(element) {\n    if (!$.metadata) {\n      return {};\n    }\n\n    var meta = $.data(element.form, 'validator').settings.meta;\n    return meta ?\n      $(element).metadata()[meta] :\n      $(element).metadata();\n  },\n\n  staticRules: function(element) {\n    var rules = {};\n    var validator = $.data(element.form, 'validator');\n    if (validator.settings.rules) {\n      rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};\n    }\n    return rules;\n  },\n\n  normalizeRules: function(rules, element) {\n    // handle dependency check\n    $.each(rules, function(prop, val) {\n      // ignore rule when param is explicitly false, eg. required:false\n      if (val === false) {\n        delete rules[prop];\n        return;\n      }\n      if (val.param || val.depends) {\n        var keepRule = true;\n        switch (typeof val.depends) {\n          case \"string\":\n            keepRule = !!$(val.depends, element.form).length;\n            break;\n          case \"function\":\n            keepRule = val.depends.call(element, element);\n            break;\n        }\n        if (keepRule) {\n          rules[prop] = val.param !== undefined ? val.param : true;\n        } else {\n          delete rules[prop];\n        }\n      }\n    });\n\n    // evaluate parameters\n    $.each(rules, function(rule, parameter) {\n      rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;\n    });\n\n    // clean number parameters\n    $.each(['minlength', 'maxlength', 'min', 'max'], function() {\n      if (rules[this]) {\n        rules[this] = Number(rules[this]);\n      }\n    });\n    $.each(['rangelength', 'range'], function() {\n      if (rules[this]) {\n        rules[this] = [Number(rules[this][0]), Number(rules[this][1])];\n      }\n    });\n\n    if ($.validator.autoCreateRanges) {\n      // auto-create ranges\n      if (rules.min && rules.max) {\n        rules.range = [rules.min, rules.max];\n        delete rules.min;\n        delete rules.max;\n      }\n      if (rules.minlength && rules.maxlength) {\n        rules.rangelength = [rules.minlength, rules.maxlength];\n        delete rules.minlength;\n        delete rules.maxlength;\n      }\n    }\n\n    // To support custom messages in metadata ignore rule methods titled \"messages\"\n    if (rules.messages) {\n      delete rules.messages;\n    }\n\n    return rules;\n  },\n\n  // Converts a simple string to a {string: true} rule, e.g., \"required\" to {required:true}\n  normalizeRule: function(data) {\n    if( typeof data === \"string\" ) {\n      var transformed = {};\n      $.each(data.split(/\\s/), function() {\n        transformed[this] = true;\n      });\n      data = transformed;\n    }\n    return data;\n  },\n\n  // https://docs.jquery.com/Plugins/Validation/Validator/addMethod\n  addMethod: function(name, method, message) {\n    $.validator.methods[name] = method;\n    $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];\n    if (method.length < 3) {\n      $.validator.addClassRules(name, $.validator.normalizeRule(name));\n    }\n  },\n\n  methods: {\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/required\n    required: function(value, element, param) {\n      // check if dependency is met\n      if ( !this.depend(param, element) ) {\n        return \"dependency-mismatch\";\n      }\n      if ( element.nodeName.toLowerCase() === \"select\" ) {\n        // could be an array for select-multiple or a string, both are fine this way\n        var val = $(element).val();\n        return val && val.length > 0;\n      }\n      if ( this.checkable(element) ) {\n        return this.getLength(value, element) > 0;\n      }\n      return $.trim(value).length > 0;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/remote\n    remote: function(value, element, param) {\n      if ( this.optional(element) ) {\n        return \"dependency-mismatch\";\n      }\n\n      var previous = this.previousValue(element);\n      if (!this.settings.messages[element.name] ) {\n        this.settings.messages[element.name] = {};\n      }\n      previous.originalMessage = this.settings.messages[element.name].remote;\n      this.settings.messages[element.name].remote = previous.message;\n\n      param = typeof param === \"string\" && {url:param} || param;\n\n      if ( this.pending[element.name] ) {\n        return \"pending\";\n      }\n      if ( previous.old === value ) {\n        return previous.valid;\n      }\n\n      previous.old = value;\n      var validator = this;\n      this.startRequest(element);\n      var data = {};\n      data[element.name] = value;\n      $.ajax($.extend(true, {\n        url: param,\n        mode: \"abort\",\n        port: \"validate\" + element.name,\n        dataType: \"json\",\n        data: data,\n        success: function(response) {\n          validator.settings.messages[element.name].remote = previous.originalMessage;\n          var valid = response === true;\n          if ( valid ) {\n            var submitted = validator.formSubmitted;\n            validator.prepareElement(element);\n            validator.formSubmitted = submitted;\n            validator.successList.push(element);\n            validator.showErrors();\n          } else {\n            var errors = {};\n            var message = response || validator.defaultMessage( element, \"remote\" );\n            errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;\n            validator.showErrors(errors);\n          }\n          previous.valid = valid;\n          validator.stopRequest(element, valid);\n        }\n      }, param));\n      return \"pending\";\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/minlength\n    minlength: function(value, element, param) {\n      var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);\n      return this.optional(element) || length >= param;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/maxlength\n    maxlength: function(value, element, param) {\n      var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);\n      return this.optional(element) || length <= param;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/rangelength\n    rangelength: function(value, element, param) {\n      var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);\n      return this.optional(element) || ( length >= param[0] && length <= param[1] );\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/min\n    min: function( value, element, param ) {\n      return this.optional(element) || value >= param;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/max\n    max: function( value, element, param ) {\n      return this.optional(element) || value <= param;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/range\n    range: function( value, element, param ) {\n      return this.optional(element) || ( value >= param[0] && value <= param[1] );\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/email\n    email: function(value, element) {\n      // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/\n      return this.optional(element) || /^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))$/i.test(value);\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/url\n    url: function(value, element) {\n      // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/\n      return this.optional(element) || /^(https?|ftp):\\/\\/(((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:)*@)?(((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]))|((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?)(:\\d*)?)(\\/((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)+(\\/(([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)*)*)?)?(\\?((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|[\\uE000-\\uF8FF]|\\/|\\?)*)?(\\#((([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(%[\\da-f]{2})|[!\\$&'\\(\\)\\*\\+,;=]|:|@)|\\/|\\?)*)?$/i.test(value);\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/date\n    date: function(value, element) {\n      return this.optional(element) || !/Invalid|NaN/.test(new Date(value));\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/dateISO\n    dateISO: function(value, element) {\n      return this.optional(element) || /^\\d{4}[\\/\\-]\\d{1,2}[\\/\\-]\\d{1,2}$/.test(value);\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/number\n    number: function(value, element) {\n      return this.optional(element) || /^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$/.test(value);\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/digits\n    digits: function(value, element) {\n      return this.optional(element) || /^\\d+$/.test(value);\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/creditcard\n    // based on https://en.wikipedia.org/wiki/Luhn\n    creditcard: function(value, element) {\n      if ( this.optional(element) ) {\n        return \"dependency-mismatch\";\n      }\n      // accept only spaces, digits and dashes\n      if (/[^0-9 \\-]+/.test(value)) {\n        return false;\n      }\n      var nCheck = 0,\n        nDigit = 0,\n        bEven = false;\n\n      value = value.replace(/\\D/g, \"\");\n\n      for (var n = value.length - 1; n >= 0; n--) {\n        var cDigit = value.charAt(n);\n        nDigit = parseInt(cDigit, 10);\n        if (bEven) {\n          if ((nDigit *= 2) > 9) {\n            nDigit -= 9;\n          }\n        }\n        nCheck += nDigit;\n        bEven = !bEven;\n      }\n\n      return (nCheck % 10) === 0;\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/accept\n    accept: function(value, element, param) {\n      param = typeof param === \"string\" ? param.replace(/,/g, '|') : \"png|jpe?g|gif\";\n      return this.optional(element) || value.match(new RegExp(\".(\" + param + \")$\", \"i\"));\n    },\n\n    // https://docs.jquery.com/Plugins/Validation/Methods/equalTo\n    equalTo: function(value, element, param) {\n      // bind to the blur event of the target in order to revalidate whenever the target field is updated\n      // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead\n      var target = $(param).unbind(\".validate-equalTo\").bind(\"blur.validate-equalTo\", function() {\n        $(element).valid();\n      });\n      return value === target.val();\n    }\n\n  }\n\n});\n\n// deprecated, use $.validator.format instead\n$.format = $.validator.format;\n\n}(jQuery));\n\n// ajax mode: abort\n// usage: $.ajax({ mode: \"abort\"[, port: \"uniqueport\"]});\n// if mode:\"abort\" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()\n(function($) {\n  var pendingRequests = {};\n  // Use a prefilter if available (1.5+)\n  if ( $.ajaxPrefilter ) {\n    $.ajaxPrefilter(function(settings, _, xhr) {\n      var port = settings.port;\n      if (settings.mode === \"abort\") {\n        if ( pendingRequests[port] ) {\n          pendingRequests[port].abort();\n        }\n        pendingRequests[port] = xhr;\n      }\n    });\n  } else {\n    // Proxy ajax\n    var ajax = $.ajax;\n    $.ajax = function(settings) {\n      var mode = ( \"mode\" in settings ? settings : $.ajaxSettings ).mode,\n        port = ( \"port\" in settings ? settings : $.ajaxSettings ).port;\n      if (mode === \"abort\") {\n        if ( pendingRequests[port] ) {\n          pendingRequests[port].abort();\n        }\n        return (pendingRequests[port] = ajax.apply(this, arguments));\n      }\n      return ajax.apply(this, arguments);\n    };\n  }\n}(jQuery));\n\n// provides cross-browser focusin and focusout events\n// IE has native support, in other browsers, use event caputuring (neither bubbles)\n\n// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation\n// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target\n(function($) {\n  // only implement if not provided by jQuery core (since 1.4)\n  // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs\n  if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {\n    $.each({\n      focus: 'focusin',\n      blur: 'focusout'\n    }, function( original, fix ){\n      $.event.special[fix] = {\n        setup:function() {\n          this.addEventListener( original, handler, true );\n        },\n        teardown:function() {\n          this.removeEventListener( original, handler, true );\n        },\n        handler: function(e) {\n          var args = arguments;\n          args[0] = $.event.fix(e);\n          args[0].type = fix;\n          return $.event.handle.apply(this, args);\n        }\n      };\n      function handler(e) {\n        e = $.event.fix(e);\n        e.type = fix;\n        return $.event.handle.call(this, e);\n      }\n    });\n  }\n  $.extend($.fn, {\n    validateDelegate: function(delegate, type, handler) {\n      return this.bind(type, function(event) {\n        var target = $(event.target);\n        if (target.is(delegate)) {\n          return handler.apply(target, arguments);\n        }\n      });\n    }\n  });\n}(jQuery));"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/templates/layout.tpl",
    "content": "html {\n  head {\n    title(title)\n    link(rel:'stylesheet', href:'/css/bootstrap.min.css')\n  }\n  body {\n    div(class:'container') {\n      div(class:'navbar') {\n        div(class:'navbar-inner') {\n          a(class:'brand',\n              href:'https://docs.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html') {\n              yield 'Groovy - Layout'\n          }\n          ul(class:'nav') {\n            li {\n              a(href:'/') {\n                yield 'Messages'\n              }\n            }\n          }\n        }\n      }\n      h1(title)\n      div { content() }\n    }\n  }\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/templates/messages/form.tpl",
    "content": "layout 'layout.tpl', title: 'Messages : Create',\n  content: contents {\n    div (class:'container') {\n      form (id:'messageForm', action:'/', method:'post') {\n      \tif (formErrors) {\n          div(class:'alert alert-error') {\n            formErrors.each { error ->\n              p error.defaultMessage\n            }\n          }\n        }\n        div (class:'pull-right') {\n          a (href:'/', 'Messages')\n        }\n        label (for:'summary', 'Summary')\n        input (name:'summary', type:'text', value:message.summary?:'',\n            class:fieldErrors?.summary ? 'field-error' : 'none')\n        label (for:'text', 'Message')\n        textarea (name:'text', class:fieldErrors?.text ? 'field-error' : 'none', message.text?:'')\n        div (class:'form-actions') {\n          input (type:'submit', value:'Create')\n        }\n      }\n    }\n  }"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/templates/messages/list.tpl",
    "content": "layout 'layout.tpl', title: 'Messages : View all',\n  content: contents {\n    div(class:'container') {\n      div(class:'pull-right') {\n        a(href:'/?form', 'Create Message')\n      }\n      table(class:'table table-bordered table-striped') {\n        thead {\n          tr {\n            td 'ID'\n            td 'Created'\n            td 'Summary'\n          }\n        }\n        tbody {\n          if (messages.empty) { tr { td(colspan:'3', 'No Messages' ) } }\n          messages.each { message ->\n            tr { \n              td message.id\n              td \"${message.created}\"\n              td {\n                a(href:\"/${message.id}\") {\n                  yield message.summary\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/main/resources/templates/messages/view.tpl",
    "content": "layout 'layout.tpl', title:'Messages : View',\n  content: contents {\n    div(class:'container') {\n      if (globalMessage) {\n        div (class:'alert alert-success', globalMessage)\n      }\n      div(class:'pull-right') {\n        a(href:'/', 'Messages')\n      }\n      dl {\n        dt 'ID'\n        dd(id:'id', message.id)\n        dt 'Date'\n        dd(id:'created', \"${message.created}\")\n        dt 'Summary'\n        dd(id:'summary', message.summary)\n        dt 'Message'\n        dd(id:'text', message.text)\n      }\n    }\n  }"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/test/java/smoketest/groovytemplates/MessageControllerWebTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates;\n\nimport java.util.regex.Pattern;\n\nimport org.assertj.core.api.HamcrestCondition;\nimport org.hamcrest.Description;\nimport org.hamcrest.TypeSafeMatcher;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * A Basic Spring MVC Test for the Sample Controller.\n *\n * @author Biju Kunjummen\n * @author Doo-Hwan, Kwak\n */\n@SpringBootTest\n@AutoConfigureMockMvc\nclass MessageControllerWebTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testHome() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).hasStatusOk().bodyText().contains(\"<title>Messages\");\n\t}\n\n\t@Test\n\tvoid testCreate() {\n\t\tassertThat(this.mvc.post().uri(\"/\").param(\"text\", \"FOO text\").param(\"summary\", \"FOO\"))\n\t\t\t.hasStatus(HttpStatus.FOUND)\n\t\t\t.headers()\n\t\t\t.hasHeaderSatisfying(\"Location\",\n\t\t\t\t\t(values) -> assertThat(values).hasSize(1)\n\t\t\t\t\t\t.element(0)\n\t\t\t\t\t\t.satisfies(HamcrestCondition.matching(RegexMatcher.matches(\"/[0-9]+\"))));\n\t}\n\n\t@Test\n\tvoid testCreateValidation() {\n\t\tassertThat(this.mvc.post().uri(\"/\").param(\"text\", \"\").param(\"summary\", \"\")).hasStatusOk()\n\t\t\t.bodyText()\n\t\t\t.contains(\"is required\");\n\t}\n\n\tprivate static class RegexMatcher extends TypeSafeMatcher<String> {\n\n\t\tprivate final String regex;\n\n\t\tRegexMatcher(String regex) {\n\t\t\tthis.regex = regex;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matchesSafely(String item) {\n\t\t\treturn Pattern.compile(this.regex).matcher(item).find();\n\t\t}\n\n\t\t@Override\n\t\tpublic void describeMismatchSafely(String item, Description mismatchDescription) {\n\t\t\tmismatchDescription.appendText(\"was \\\"\").appendText(item).appendText(\"\\\"\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void describeTo(Description description) {\n\t\t\tdescription.appendText(\"a string that matches regex: \").appendText(this.regex);\n\t\t}\n\n\t\tstatic org.hamcrest.Matcher<java.lang.String> matches(String regex) {\n\t\t\treturn new RegexMatcher(regex);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-groovy-templates/src/test/java/smoketest/groovytemplates/SampleGroovyTemplateApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.groovytemplates;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.http.clients.redirects=dont-follow\")\n@AutoConfigureTestRestTemplate\nclass SampleGroovyTemplateApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Messages\");\n\t\tassertThat(entity.getBody()).doesNotContain(\"layout:fragment\");\n\t}\n\n\t@Test\n\tvoid testCreate() {\n\t\tMultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n\t\tmap.set(\"text\", \"FOO text\");\n\t\tmap.set(\"summary\", \"FOO\");\n\t\tURI location = this.restTemplate.postForLocation(\"/\", map);\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).contains(\"localhost:\" + this.port);\n\t}\n\n\t@Test\n\tvoid testCss() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/css/bootstrap.min.css\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"body\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot web JSP smoke test\"\n\nconfigurations {\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tprovidedRuntime(project(\":starter:spring-boot-starter-tomcat-runtime\"))\n\tprovidedRuntime(\"org.apache.tomcat.embed:tomcat-embed-jasper\")\n\tprovidedRuntime(\"org.glassfish.web:jakarta.servlet.jsp.jstl\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/main/java/smoketest/jsp/SampleWebJspApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jsp;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class SampleWebJspApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleWebJspApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebJspApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/main/java/smoketest/jsp/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jsp;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n@Controller\npublic class WelcomeController {\n\n\t@Value(\"${application.message:Hello World}\")\n\tprivate String message = \"Hello World\";\n\n\t@GetMapping(\"/\")\n\tpublic String welcome(Map<String, Object> model) {\n\t\tmodel.put(\"time\", new Date());\n\t\tmodel.put(\"message\", this.message);\n\t\treturn \"welcome\";\n\t}\n\n\t@RequestMapping(\"/foo\")\n\tpublic String foo(Map<String, Object> model) {\n\t\tthrow new RuntimeException(\"Foo\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/main/java/smoketest/jsp/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.jsp;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/main/resources/application.properties",
    "content": "spring.mvc.view.prefix: /WEB-INF/jsp/\nspring.mvc.view.suffix: .jsp\napplication.message: Hello Phil\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/main/webapp/WEB-INF/jsp/error.jsp",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<body>\nSomething went wrong: ${status} ${error}\n</body>\n</html>"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp",
    "content": "<!DOCTYPE html>\n\n<%@ taglib prefix=\"spring\" uri=\"http://www.springframework.org/tags\"%>\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>\n\n<html lang=\"en\">\n\n<body>\n\t<c:url value=\"/resources/text.txt\" var=\"url\"/>\n\t<spring:url value=\"/resources/text.txt\" htmlEscape=\"true\" var=\"springUrl\" />\n\tSpring URL: ${springUrl} at ${time}\n\t<br>\n\tJSTL URL: ${url}\n\t<br>\n\tMessage: ${message}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-jsp/src/test/java/smoketest/jsp/SampleWebJspApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.jsp;\n\nimport java.net.URI;\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.RequestEntity;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for JSP application.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebJspApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testJspWithEl() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"/resources/text.txt\");\n\t}\n\n\t@Test\n\tvoid customErrorPage() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tRequestEntity<Void> request = new RequestEntity<>(headers, HttpMethod.GET, URI.create(\"/foo\"));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(request, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(entity.getBody()).contains(\"Something went wrong: 500 Internal Server Error\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web method security smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/main/java/smoketest/security/method/SampleMethodSecurityApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.security.method;\n\nimport jakarta.servlet.DispatcherType;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.security.access.annotation.Secured;\nimport org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n@SpringBootApplication\n@EnableMethodSecurity(securedEnabled = true)\npublic class SampleMethodSecurityApplication implements WebMvcConfigurer {\n\n\t@Override\n\tpublic void addViewControllers(ViewControllerRegistry registry) {\n\t\tregistry.addViewController(\"/login\").setViewName(\"login\");\n\t\tregistry.addViewController(\"/access\").setViewName(\"access\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(SampleMethodSecurityApplication.class).run(args);\n\t}\n\n\t@Order(Ordered.HIGHEST_PRECEDENCE)\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class AuthenticationSecurity {\n\n\t\t@SuppressWarnings(\"deprecation\")\n\t\t@Bean\n\t\tpublic InMemoryUserDetailsManager inMemoryUserDetailsManager() {\n\t\t\treturn new InMemoryUserDetailsManager(\n\t\t\t\t\tUser.withDefaultPasswordEncoder()\n\t\t\t\t\t\t.username(\"admin\")\n\t\t\t\t\t\t.password(\"admin\")\n\t\t\t\t\t\t.roles(\"ADMIN\", \"USER\", \"ACTUATOR\")\n\t\t\t\t\t\t.build(),\n\t\t\t\t\tUser.withDefaultPasswordEncoder().username(\"user\").password(\"user\").roles(\"USER\").build());\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class ApplicationSecurity {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll();\n\t\t\t\trequests.anyRequest().fullyAuthenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\thttp.formLogin((form) -> form.loginPage(\"/login\").permitAll());\n\t\t\thttp.exceptionHandling((exceptions) -> exceptions.accessDeniedPage(\"/access\"));\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Order(1)\n\tprotected static class ActuatorSecurity {\n\n\t\t@Bean\n\t\tSecurityFilterChain actuatorSecurity(HttpSecurity http) {\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\thttp.securityMatcher(EndpointRequest.toAnyEndpoint());\n\t\t\thttp.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n\t@Controller\n\tprotected static class HomeController {\n\n\t\t@GetMapping(\"/\")\n\t\t@Secured(\"ROLE_ADMIN\")\n\t\tpublic String home() {\n\t\t\treturn \"home\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/main/java/smoketest/security/method/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.security.method;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.security=INFO\nmanagement.endpoints.web.exposure.include=*\nspring.mvc.view.prefix=/templates/\nspring.mvc.view.suffix=.html\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/main/webapp/templates/access.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Error</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<p>Access denied: you do not have permission for that resource</p>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/main/webapp/templates/home.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Home</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<p>Home</p>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/main/webapp/templates/login.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Login</title>\n</head>\n<body\">\n\t<div class=\"container\">\n\t\t<div class=\"content\">\n\t\t\t<h2>Login with Username and Password</h2>\n\t\t\t<form name=\"form\" action=\"/login\" method=\"POST\">\n\t\t\t\t<fieldset>\n\t\t\t\t\t<input type=\"text\" name=\"username\" value=\"\" placeholder=\"Username\" />\n\t\t\t\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\" />\n\t\t\t\t</fieldset>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n\t\t</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-method-security/src/test/java/smoketest/security/method/SampleMethodSecurityApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.security.method;\n\nimport java.net.URI;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.client.support.BasicAuthenticationInterceptor;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n * @author Scott Frederick\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tproperties = \"spring.http.clients.imperative.factory=simple\")\n@AutoConfigureTestRestTemplate\nclass SampleMethodSecurityApplicationTests {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/\", HttpMethod.GET, new HttpEntity<>(headers),\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t}\n\n\t@Test\n\tvoid testLogin() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"admin\");\n\t\tform.set(\"password\", \"admin\");\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/login\", HttpMethod.POST,\n\t\t\t\tnew HttpEntity<>(form, headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/\");\n\t}\n\n\t@Test\n\tvoid testDenied() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"user\");\n\t\tform.set(\"password\", \"user\");\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/login\", HttpMethod.POST,\n\t\t\t\tnew HttpEntity<>(form, headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tString cookie = entity.getHeaders().getFirst(\"Set-Cookie\");\n\t\theaders.set(\"Cookie\", cookie);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tResponseEntity<String> page = this.restTemplate.exchange(location, HttpMethod.GET, new HttpEntity<>(headers),\n\t\t\t\tString.class);\n\t\tassertThat(page.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);\n\t\tassertThat(page.getBody()).contains(\"Access denied\");\n\t}\n\n\t@Test\n\tvoid testManagementProtected() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/actuator/beans\", HttpMethod.GET,\n\t\t\t\tnew HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t}\n\n\t@Test\n\tvoid testManagementAuthorizedAccess() {\n\t\tBasicAuthenticationInterceptor basicAuthInterceptor = new BasicAuthenticationInterceptor(\"admin\", \"admin\");\n\t\tthis.restTemplate.getRestTemplate().getInterceptors().add(basicAuthInterceptor);\n\t\ttry {\n\t\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/actuator/beans\", String.class);\n\t\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t}\n\t\tfinally {\n\t\t\tthis.restTemplate.getRestTemplate().getInterceptors().remove(basicAuthInterceptor);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web Mustache smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-mustache\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-mustache-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/java/smoketest/mustache/SampleWebMustacheApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.mustache;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleWebMustacheApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebMustacheApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/java/smoketest/mustache/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.mustache;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n@Controller\npublic class WelcomeController {\n\n\t@Value(\"${application.message:Hello World}\")\n\tprivate String message = \"Hello World\";\n\n\t@GetMapping(\"/\")\n\tpublic String welcome(Map<String, Object> model) {\n\t\tmodel.put(\"time\", new Date());\n\t\tmodel.put(\"message\", this.message);\n\t\treturn \"welcome\";\n\t}\n\n\t@RequestMapping(\"/serviceUnavailable\")\n\tpublic String ServiceUnavailable() {\n\t\tthrow new ServiceUnavailableException();\n\t}\n\n\t@RequestMapping(\"/bang\")\n\tpublic String bang() {\n\t\tthrow new RuntimeException(\"Boom\");\n\t}\n\n\t@RequestMapping(\"/insufficientStorage\")\n\tpublic String insufficientStorage() {\n\t\tthrow new InsufficientStorageException();\n\t}\n\n\t@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)\n\tprivate static final class ServiceUnavailableException extends RuntimeException {\n\n\t}\n\n\t@ResponseStatus(HttpStatus.INSUFFICIENT_STORAGE)\n\tprivate static final class InsufficientStorageException extends RuntimeException {\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/java/smoketest/mustache/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.mustache;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/resources/application.properties",
    "content": "application.message: Hello, Andy\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/resources/public/error/503.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tI'm a 503\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/resources/public/error/5xx.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tI'm a 5xx\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/resources/templates/error/507.mustache",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tI'm a 507 invoked from {{path}}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/resources/templates/error.mustache",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tSomething went wrong: {{status}} {{error}}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/main/resources/templates/welcome.mustache",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n\tDate: {{time.date}}\n\t<br>\n\tTime: {{time.time}}\n\t<br>\n\tMessage: {{message}}\n</body>\n\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-mustache/src/test/java/smoketest/mustache/SampleWebMustacheApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.mustache;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for Mustache application.\n *\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebMustacheApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testMustacheTemplate() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"Hello, Andy\");\n\t}\n\n\t@Test\n\tvoid testMustacheErrorTemplate() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<String> requestEntity = new HttpEntity<>(headers);\n\t\tResponseEntity<String> responseEntity = this.restTemplate.exchange(\"/does-not-exist\", HttpMethod.GET,\n\t\t\t\trequestEntity, String.class);\n\t\tassertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tassertThat(responseEntity.getBody()).contains(\"Something went wrong: 404 Not Found\");\n\t}\n\n\t@Test\n\tvoid test503HtmlResource() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<String> requestEntity = new HttpEntity<>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/serviceUnavailable\", HttpMethod.GET, requestEntity,\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);\n\t\tassertThat(entity.getBody()).contains(\"I'm a 503\");\n\t}\n\n\t@Test\n\tvoid test5xxHtmlResource() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<String> requestEntity = new HttpEntity<>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/bang\", HttpMethod.GET, requestEntity,\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tassertThat(entity.getBody()).contains(\"I'm a 5xx\");\n\t}\n\n\t@Test\n\tvoid test507Template() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Arrays.asList(MediaType.TEXT_HTML));\n\t\tHttpEntity<String> requestEntity = new HttpEntity<>(headers);\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/insufficientStorage\", HttpMethod.GET,\n\t\t\t\trequestEntity, String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INSUFFICIENT_STORAGE);\n\t\tassertThat(entity.getBody()).contains(\"I'm a 507\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web secure smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/main/java/smoketest/web/secure/SampleWebSecureApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@SpringBootApplication\npublic class SampleWebSecureApplication implements WebMvcConfigurer {\n\n\t@Override\n\tpublic void addViewControllers(ViewControllerRegistry registry) {\n\t\tregistry.addViewController(\"/\").setViewName(\"home\");\n\t\tregistry.addViewController(\"/login\").setViewName(\"login\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(SampleWebSecureApplication.class).run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/main/java/smoketest/web/secure/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.web.secure;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.security=INFO\nlogging.level.org.springframework.boot.actuate.audit.listener.AuditListener=DEBUG\nspring.security.user.name=user\nspring.security.user.password=password\nspring.mvc.view.prefix=/templates/\nspring.mvc.view.suffix=.html"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/main/webapp/templates/home.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Home</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<p>Home</p>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/main/webapp/templates/login.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Login</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"content\">\n\t\t\t<h2>Login with Username and Password</h2>\n\t\t\t<form name=\"form\" action=\"/login\" method=\"POST\">\n\t\t\t\t<fieldset>\n\t\t\t\t\t<input type=\"text\" name=\"username\" value=\"\" placeholder=\"Username\" />\n\t\t\t\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\" />\n\t\t\t\t</fieldset>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n\t\t</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/AbstractErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for tests to ensure that the error page is accessible only to\n * authorized users.\n *\n * @author Madhura Bhave\n */\n@AutoConfigureTestRestTemplate\nabstract class AbstractErrorPageTests {\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\tprivate final String pathPrefix;\n\n\tprotected AbstractErrorPageTests(String pathPrefix) {\n\t\tthis.pathPrefix = pathPrefix;\n\t}\n\n\t@Test\n\tvoid testBadCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"wrongpassword\")\n\t\t\t.exchange(this.pathPrefix + \"/test\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNull();\n\t}\n\n\t@Test\n\tvoid testNoCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.exchange(this.pathPrefix + \"/test\",\n\t\t\t\tHttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNull();\n\t}\n\n\t@Test\n\tvoid testPublicNotFoundPageWithCorrectCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"password\")\n\t\t\t.exchange(this.pathPrefix + \"/public/notfound\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Not Found\");\n\t}\n\n\t@Test\n\tvoid testPublicNotFoundPageWithBadCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"wrong\")\n\t\t\t.exchange(this.pathPrefix + \"/public/notfound\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNull();\n\t}\n\n\t@Test\n\tvoid testCorrectCredentialsWithControllerException() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"password\")\n\t\t\t.exchange(this.pathPrefix + \"/fail\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Internal Server Error\");\n\t}\n\n\t@Test\n\tvoid testCorrectCredentials() {\n\t\tfinal ResponseEntity<String> response = this.testRestTemplate.withBasicAuth(\"username\", \"password\")\n\t\t\t.exchange(this.pathPrefix + \"/test\", HttpMethod.GET, null, String.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tresponse.getBody();\n\t\tassertThat(response.getBody()).isEqualTo(\"test\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class TestConfiguration {\n\n\t\t@RestController\n\t\tstatic class TestController {\n\n\t\t\t@GetMapping(\"/test\")\n\t\t\tString test() {\n\t\t\t\treturn \"test\";\n\t\t\t}\n\n\t\t\t@GetMapping(\"/fail\")\n\t\t\tString fail() {\n\t\t\t\tthrow new RuntimeException();\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/AbstractUnauthenticatedErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.JsonNode;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract base class for tests to ensure that the error page is accessible only to\n * authorized users.\n *\n * @author Madhura Bhave\n */\n@AutoConfigureTestRestTemplate\nabstract class AbstractUnauthenticatedErrorPageTests {\n\n\t@Autowired\n\tprivate TestRestTemplate testRestTemplate;\n\n\tprivate final String pathPrefix;\n\n\tprotected AbstractUnauthenticatedErrorPageTests(String pathPrefix) {\n\t\tthis.pathPrefix = pathPrefix;\n\t}\n\n\t@Test\n\tvoid testBadCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"wrongpassword\")\n\t\t\t.exchange(this.pathPrefix + \"/test\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Unauthorized\");\n\t}\n\n\t@Test\n\tvoid testNoCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.exchange(this.pathPrefix + \"/test\",\n\t\t\t\tHttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Unauthorized\");\n\t}\n\n\t@Test\n\tvoid testPublicNotFoundPage() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.exchange(this.pathPrefix + \"/public/notfound\",\n\t\t\t\tHttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Not Found\");\n\t}\n\n\t@Test\n\tvoid testPublicNotFoundPageWithCorrectCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"password\")\n\t\t\t.exchange(this.pathPrefix + \"/public/notfound\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Not Found\");\n\t}\n\n\t@Test\n\tvoid testPublicNotFoundPageWithBadCredentials() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"wrong\")\n\t\t\t.exchange(this.pathPrefix + \"/public/notfound\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Unauthorized\");\n\t}\n\n\t@Test\n\tvoid testCorrectCredentialsWithControllerException() {\n\t\tfinal ResponseEntity<JsonNode> response = this.testRestTemplate.withBasicAuth(\"username\", \"password\")\n\t\t\t.exchange(this.pathPrefix + \"/fail\", HttpMethod.GET, null, JsonNode.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);\n\t\tJsonNode jsonResponse = response.getBody();\n\t\tassertThat(jsonResponse).isNotNull();\n\t\tassertThat(jsonResponse.get(\"error\").asString()).isEqualTo(\"Internal Server Error\");\n\t}\n\n\t@Test\n\tvoid testCorrectCredentials() {\n\t\tfinal ResponseEntity<String> response = this.testRestTemplate.withBasicAuth(\"username\", \"password\")\n\t\t\t.exchange(this.pathPrefix + \"/test\", HttpMethod.GET, null, String.class);\n\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(response.getBody()).isEqualTo(\"test\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/CustomContextPathErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\n\n/**\n * Tests to ensure that the error page with a custom context path is accessible only to\n * authorized users.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class, ErrorPageTests.SecurityConfiguration.class,\n\t\t\t\tSampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\", \"server.servlet.context-path=/example\" })\nclass CustomContextPathErrorPageTests extends AbstractErrorPageTests {\n\n\tCustomContextPathErrorPageTests() {\n\t\tsuper(\"\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/CustomContextPathUnauthenticatedErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\n\n/**\n * Tests for error page that permits access to all with a custom context path.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class,\n\t\t\t\tUnauthenticatedErrorPageTests.SecurityConfiguration.class, SampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\", \"server.servlet.context-path=/example\" })\nclass CustomContextPathUnauthenticatedErrorPageTests extends AbstractUnauthenticatedErrorPageTests {\n\n\tCustomContextPathUnauthenticatedErrorPageTests() {\n\t\tsuper(\"\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/CustomServletPathErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests to ensure that the error page with a custom servlet path is accessible only to\n * authorized users.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class,\n\t\t\t\tCustomServletPathErrorPageTests.SecurityConfiguration.class, SampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\", \"spring.mvc.servlet.path=/custom/servlet/path\" })\nclass CustomServletPathErrorPageTests extends AbstractErrorPageTests {\n\n\tCustomServletPathErrorPageTests() {\n\t\tsuper(\"/custom/servlet/path\");\n\t}\n\n\t@org.springframework.boot.test.context.TestConfiguration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(\"/public/**\").permitAll();\n\t\t\t\trequests.anyRequest().fullyAuthenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\thttp.formLogin((form) -> form.loginPage(\"/custom/servlet/path/login\").permitAll());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/CustomServletPathUnauthenticatedErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for error page that permits access to all with a custom servlet path.\n *\n * @author Andy Wilkinson\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class,\n\t\t\t\tCustomServletPathUnauthenticatedErrorPageTests.SecurityConfiguration.class,\n\t\t\t\tSampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\", \"spring.mvc.servlet.path=/custom/servlet/path\" })\nclass CustomServletPathUnauthenticatedErrorPageTests extends AbstractUnauthenticatedErrorPageTests {\n\n\tCustomServletPathUnauthenticatedErrorPageTests() {\n\t\tsuper(\"/custom/servlet/path\");\n\t}\n\n\t@org.springframework.boot.test.context.TestConfiguration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(\"/error\").permitAll();\n\t\t\t\trequests.requestMatchers(\"/public/**\").permitAll();\n\t\t\t\trequests.anyRequest().authenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/ErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests to ensure that the error page is accessible only to authorized users.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class, ErrorPageTests.SecurityConfiguration.class,\n\t\t\t\tSampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\" })\nclass ErrorPageTests extends AbstractErrorPageTests {\n\n\tErrorPageTests() {\n\t\tsuper(\"\");\n\t}\n\n\t@org.springframework.boot.test.context.TestConfiguration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(\"/public/**\").permitAll();\n\t\t\t\trequests.anyRequest().fullyAuthenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\thttp.formLogin((form) -> form.loginPage(\"/login\").permitAll());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/NoSessionErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for error page when a stateless session creation policy is used.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class, NoSessionErrorPageTests.SecurityConfiguration.class,\n\t\t\t\tSampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\" })\nclass NoSessionErrorPageTests extends AbstractErrorPageTests {\n\n\tNoSessionErrorPageTests() {\n\t\tsuper(\"\");\n\t}\n\n\t@org.springframework.boot.test.context.TestConfiguration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))\n\t\t\t\t.authorizeHttpRequests((requests) -> {\n\t\t\t\t\trequests.requestMatchers(\"/public/**\").permitAll();\n\t\t\t\t\trequests.anyRequest().authenticated();\n\t\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/SampleWebSecureApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport java.net.URI;\nimport java.util.Collections;\n\nimport jakarta.servlet.DispatcherType;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n * @author Scott Frederick\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tclasses = { SampleWebSecureApplicationTests.SecurityConfiguration.class, SampleWebSecureApplication.class })\n@AutoConfigureTestRestTemplate\nclass SampleWebSecureApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid testHome() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/home\", HttpMethod.GET, new HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/login\");\n\t}\n\n\t@Test\n\tvoid testLoginPage() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/login\", HttpMethod.GET, new HttpEntity<>(headers),\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Login</title>\");\n\t}\n\n\t@Test\n\tvoid testLogin() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"user\");\n\t\tform.set(\"password\", \"password\");\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/login\", HttpMethod.POST, new HttpEntity<>(form, headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/\");\n\t}\n\n\t@org.springframework.boot.test.context.TestConfiguration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(\"/public/**\").permitAll();\n\t\t\t\trequests.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll();\n\t\t\t\trequests.anyRequest().fullyAuthenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\thttp.formLogin((form) -> form.loginPage(\"/login\").permitAll());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure/src/test/java/smoketest/web/secure/UnauthenticatedErrorPageTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\nimport static org.springframework.security.config.Customizer.withDefaults;\n\n/**\n * Tests for error page that permits access to all.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,\n\t\tclasses = { AbstractErrorPageTests.TestConfiguration.class,\n\t\t\t\tUnauthenticatedErrorPageTests.SecurityConfiguration.class, SampleWebSecureApplication.class },\n\t\tproperties = { \"spring.web.error.include-message=always\", \"spring.security.user.name=username\",\n\t\t\t\t\"spring.security.user.password=password\" })\nclass UnauthenticatedErrorPageTests extends AbstractUnauthenticatedErrorPageTests {\n\n\tUnauthenticatedErrorPageTests() {\n\t\tsuper(\"\");\n\t}\n\n\t@org.springframework.boot.test.context.TestConfiguration(proxyBeanMethods = false)\n\tstatic class SecurityConfiguration {\n\n\t\t@Bean\n\t\tSecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) {\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.requestMatchers(\"/error\").permitAll();\n\t\t\t\trequests.requestMatchers(\"/public/**\").permitAll();\n\t\t\t\trequests.anyRequest().authenticated();\n\t\t\t});\n\t\t\thttp.httpBasic(withDefaults());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web secure custom smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/src/main/java/smoketest/web/secure/custom/SampleWebSecureCustomApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure.custom;\n\nimport jakarta.servlet.DispatcherType;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@SpringBootApplication\npublic class SampleWebSecureCustomApplication implements WebMvcConfigurer {\n\n\t@Override\n\tpublic void addViewControllers(ViewControllerRegistry registry) {\n\t\tregistry.addViewController(\"/\").setViewName(\"home\");\n\t\tregistry.addViewController(\"/login\").setViewName(\"login\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(SampleWebSecureCustomApplication.class).run(args);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class ApplicationSecurity {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll();\n\t\t\t\trequests.anyRequest().fullyAuthenticated();\n\t\t\t});\n\t\t\thttp.formLogin((form) -> form.loginPage(\"/login\").permitAll());\n\t\t\treturn http.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/src/main/java/smoketest/web/secure/custom/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.web.secure.custom;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.security=INFO\nspring.security.user.name=user\nspring.security.user.password=password\nspring.mvc.view.prefix=/templates/\nspring.mvc.view.suffix=.html"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/src/main/webapp/templates/home.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Home</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<p>Home</p>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/src/main/webapp/templates/login.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Login</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<div class=\"content\">\n\t\t\t<h2>Login with Username and Password</h2>\n\t\t\t<form name=\"form\" action=\"/login\" method=\"POST\">\n\t\t\t\t<fieldset>\n\t\t\t\t\t<input type=\"text\" name=\"username\" value=\"\" placeholder=\"Username\" />\n\t\t\t\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\" />\n\t\t\t\t</fieldset>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n\t\t</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-custom/src/test/java/smoketest/web/secure/custom/SampleWebSecureCustomApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure.custom;\n\nimport java.net.URI;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n * @author Scott Frederick\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebSecureCustomApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid testHome() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/\", HttpMethod.GET, new HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/login\");\n\t}\n\n\t@Test\n\tvoid testLoginPage() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/login\", HttpMethod.GET, new HttpEntity<>(headers),\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Login</title>\");\n\t}\n\n\t@Test\n\tvoid testLogin() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"user\");\n\t\tform.set(\"password\", \"password\");\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/login\", HttpMethod.POST, new HttpEntity<>(form, headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web secure JDBC smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-jdbc\"))\n\timplementation(project(\":starter:spring-boot-starter-security\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\truntimeOnly(\"com.h2database:h2\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-security-test\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure.jdbc;\n\nimport javax.sql.DataSource;\n\nimport jakarta.servlet.DispatcherType;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;\nimport org.springframework.security.provisioning.JdbcUserDetailsManager;\nimport org.springframework.security.web.SecurityFilterChain;\nimport org.springframework.web.servlet.config.annotation.ViewControllerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurer;\n\n@SpringBootApplication\npublic class SampleWebSecureJdbcApplication implements WebMvcConfigurer {\n\n\t@Override\n\tpublic void addViewControllers(ViewControllerRegistry registry) {\n\t\tregistry.addViewController(\"/\").setViewName(\"home\");\n\t\tregistry.addViewController(\"/login\").setViewName(\"login\");\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tnew SpringApplicationBuilder(SampleWebSecureJdbcApplication.class).run(args);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class ApplicationSecurity {\n\n\t\t@Bean\n\t\tSecurityFilterChain configure(HttpSecurity http) {\n\t\t\thttp.csrf(CsrfConfigurer::disable);\n\t\t\thttp.authorizeHttpRequests((requests) -> {\n\t\t\t\trequests.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll();\n\t\t\t\trequests.anyRequest().fullyAuthenticated();\n\t\t\t});\n\t\t\thttp.formLogin((form) -> form.loginPage(\"/login\").permitAll());\n\t\t\treturn http.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic JdbcUserDetailsManager jdbcUserDetailsManager(DataSource dataSource) {\n\t\t\treturn new JdbcUserDetailsManager(dataSource);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/java/smoketest/web/secure/jdbc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.web.secure.jdbc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.security=INFO\nspring.mvc.view.prefix=/templates/\nspring.mvc.view.suffix=.html"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/resources/data.sql",
    "content": "insert into users (username, password, enabled) values ('user', '{noop}user', true);\n\ninsert into authorities (username, authority) values ('user', 'ROLE_ADMIN');\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/resources/schema.sql",
    "content": "create table users (\n  username varchar(256),\n  password varchar(256),\n  enabled boolean\n);\n\ncreate table authorities (\n  username varchar(256),\n  authority varchar(256)\n);\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/webapp/templates/home.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n\t<title>Home</title>\n</head>\n<body>\n\t<div class=\"container\">\n\t\t<p>Home</p>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/main/webapp/templates/login.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Login</title>\n</head>\n<body\">\n\t<div class=\"container\">\n\t\t<div class=\"content\">\n\t\t\t<h2>Login with Username and Password</h2>\n\t\t\t<form name=\"form\" action=\"/login\" method=\"POST\">\n\t\t\t\t<fieldset>\n\t\t\t\t\t<input type=\"text\" name=\"username\" value=\"\" placeholder=\"Username\" />\n\t\t\t\t\t<input type=\"password\" name=\"password\" placeholder=\"Password\" />\n\t\t\t\t</fieldset>\n\t\t\t\t<input type=\"submit\" id=\"login\" value=\"Login\" class=\"btn btn-primary\" />\n\t\t\t</form>\n\t\t</div>\n\t</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-secure-jdbc/src/test/java/smoketest/web/secure/jdbc/SampleWebSecureJdbcApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.secure.jdbc;\n\nimport java.net.URI;\nimport java.util.Collections;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.http.client.HttpRedirects;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n * @author Scott Frederick\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebSecureJdbcApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid testHome() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/\", HttpMethod.GET, new HttpEntity<>(headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/login\");\n\t}\n\n\t@Test\n\tvoid testLoginPage() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\tResponseEntity<String> entity = this.restTemplate.exchange(\"/login\", HttpMethod.GET, new HttpEntity<>(headers),\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Login</title>\");\n\t}\n\n\t@Test\n\tvoid testLogin() {\n\t\tHttpHeaders headers = new HttpHeaders();\n\t\theaders.setAccept(Collections.singletonList(MediaType.TEXT_HTML));\n\t\theaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);\n\t\tMultiValueMap<String, String> form = new LinkedMultiValueMap<>();\n\t\tform.set(\"username\", \"user\");\n\t\tform.set(\"password\", \"user\");\n\t\tResponseEntity<String> entity = this.restTemplate.withRedirects(HttpRedirects.DONT_FOLLOW)\n\t\t\t.exchange(\"/login\", HttpMethod.POST, new HttpEntity<>(form, headers), String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);\n\t\tURI location = entity.getHeaders().getLocation();\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).endsWith(this.port + \"/\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-static/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n}\n\ndescription = \"Spring Boot web static smoke test\"\n\nconfigurations {\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tprovidedRuntime( project(\":starter:spring-boot-starter-tomcat-runtime\"))\n\n\truntimeOnly(\"org.webjars:bootstrap:3.0.3\")\n\truntimeOnly(\"org.webjars:jquery:2.0.3-1\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-static/src/main/java/smoketest/web/staticcontent/SampleWebStaticApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.staticcontent;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class SampleWebStaticApplication extends SpringBootServletInitializer {\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleWebStaticApplication.class);\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebStaticApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-static/src/main/java/smoketest/web/staticcontent/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.web.staticcontent;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-static/src/main/resources/static/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n<title>Static</title>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<link rel=\"stylesheet\" type=\"text/css\"\n\thref=\"webjars/bootstrap/3.0.3/css/bootstrap.min.css\" />\n</head>\n<body>\n\t<script type=\"text/javascript\"\n\t\tsrc=\"webjars/jquery/2.0.3/jquery.min.js\"></script>\n\t<div id=\"navbar\" class=\"navbar navbar-default\" role=\"navigation\">\n\t\t<div class=\"navbar-header\">\n\t\t\t<button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\"\n\t\t\t\tdata-target=\".navbar-collapse\">\n\t\t\t\t<span class=\"icon-bar\"></span> <span class=\"icon-bar\"></span> <span\n\t\t\t\t\tclass=\"icon-bar\"></span>\n\t\t\t</button>\n\t\t\t<a class=\"navbar-brand\"\n\t\t\t\thref=\"https://github.com/spring-projects/spring-boot\"> Spring Boot\n\t\t\t</a>\n\t\t</div>\n\t\t<div class=\"navbar-collapse collapse\">\n\t\t\t<ul class=\"nav navbar-nav\">\n\t\t\t\t<li><a href=\"\"> Home </a></li>\n\t\t\t</ul>\n\t\t</div>\n\t</div>\n\t<div class=\"jumbotron\">\n\t\t<h1>Home</h1>\n\t\t<p>Some static content</p>\n\t\t<p>\n          <a class=\"btn btn-lg btn-primary\" href=\"#navbar\" role=\"button\">Go &raquo;</a>\n        </p>\n\t</div>\n\t<script type=\"text/javascript\"\n\t\tsrc=\"webjars/bootstrap/3.0.3/js/bootstrap.min.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-static/src/test/java/smoketest/web/staticcontent/SampleWebStaticApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.staticcontent;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureTestRestTemplate\nclass SampleWebStaticApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Static\");\n\t}\n\n\t@Test\n\tvoid testCss() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/webjars/bootstrap/3.0.3/css/bootstrap.min.css\",\n\t\t\t\tString.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"body\");\n\t\tassertThat(entity.getHeaders().getContentType()).isEqualTo(MediaType.valueOf(\"text/css\"));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot web Thymeleaf smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-thymeleaf\"))\n\timplementation(project(\":starter:spring-boot-starter-webmvc\"))\n\timplementation(project(\":starter:spring-boot-starter-validation\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webmvc-test\"))\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/InMemoryMessageRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class InMemoryMessageRepository implements MessageRepository {\n\n\tprivate static final AtomicLong counter = new AtomicLong();\n\n\tprivate final ConcurrentMap<Long, Message> messages = new ConcurrentHashMap<>();\n\n\t@Override\n\tpublic Iterable<Message> findAll() {\n\t\treturn this.messages.values();\n\t}\n\n\t@Override\n\tpublic Message save(Message message) {\n\t\tLong id = message.getId();\n\t\tif (id == null) {\n\t\t\tid = counter.incrementAndGet();\n\t\t\tmessage.setId(id);\n\t\t}\n\t\tthis.messages.put(id, message);\n\t\treturn message;\n\t}\n\n\t@Override\n\tpublic @Nullable Message findMessage(Long id) {\n\t\treturn this.messages.get(id);\n\t}\n\n\t@Override\n\tpublic void deleteMessage(Long id) {\n\t\tthis.messages.remove(id);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/Message.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf;\n\nimport java.util.Calendar;\n\nimport jakarta.validation.constraints.NotEmpty;\nimport org.jspecify.annotations.Nullable;\n\npublic class Message {\n\n\tprivate @Nullable Long id;\n\n\t@NotEmpty(message = \"Text is required.\")\n\tprivate @Nullable String text;\n\n\t@NotEmpty(message = \"Summary is required.\")\n\tprivate @Nullable String summary;\n\n\tprivate Calendar created = Calendar.getInstance();\n\n\tpublic @Nullable Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(@Nullable Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic Calendar getCreated() {\n\t\treturn this.created;\n\t}\n\n\tpublic void setCreated(Calendar created) {\n\t\tthis.created = created;\n\t}\n\n\tpublic @Nullable String getText() {\n\t\treturn this.text;\n\t}\n\n\tpublic void setText(@Nullable String text) {\n\t\tthis.text = text;\n\t}\n\n\tpublic @Nullable String getSummary() {\n\t\treturn this.summary;\n\t}\n\n\tpublic void setSummary(@Nullable String summary) {\n\t\tthis.summary = summary;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/MessageRepository.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf;\n\nimport org.jspecify.annotations.Nullable;\n\npublic interface MessageRepository {\n\n\tIterable<Message> findAll();\n\n\tMessage save(Message message);\n\n\t@Nullable Message findMessage(Long id);\n\n\tvoid deleteMessage(Long id);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/SampleWebUiApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.convert.converter.Converter;\n\n@SpringBootApplication\npublic class SampleWebUiApplication {\n\n\t@Bean\n\tpublic MessageRepository messageRepository() {\n\t\treturn new InMemoryMessageRepository();\n\t}\n\n\t@Bean\n\tpublic Converter<String, @Nullable Message> messageConverter() {\n\t\treturn (id) -> messageRepository().findMessage(Long.valueOf(id));\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebUiApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/mvc/MessageController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf.mvc;\n\nimport jakarta.validation.Valid;\nimport smoketest.web.thymeleaf.Message;\nimport smoketest.web.thymeleaf.MessageRepository;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.util.Assert;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.ModelAttribute;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.servlet.ModelAndView;\nimport org.springframework.web.servlet.mvc.support.RedirectAttributes;\n\n@Controller\n@RequestMapping(\"/\")\npublic class MessageController {\n\n\tprivate final MessageRepository messageRepository;\n\n\tpublic MessageController(MessageRepository messageRepository) {\n\t\tthis.messageRepository = messageRepository;\n\t}\n\n\t@GetMapping\n\tpublic ModelAndView list() {\n\t\tIterable<Message> messages = this.messageRepository.findAll();\n\t\treturn new ModelAndView(\"messages/list\", \"messages\", messages);\n\t}\n\n\t@GetMapping(\"{id}\")\n\tpublic ModelAndView view(@PathVariable(\"id\") Message message) {\n\t\treturn new ModelAndView(\"messages/view\", \"message\", message);\n\t}\n\n\t@GetMapping(params = \"form\")\n\tpublic String createForm(@ModelAttribute Message message) {\n\t\treturn \"messages/form\";\n\t}\n\n\t@PostMapping\n\tpublic ModelAndView create(@Valid Message message, BindingResult result, RedirectAttributes redirect) {\n\t\tif (result.hasErrors()) {\n\t\t\treturn new ModelAndView(\"messages/form\", \"formErrors\", result.getAllErrors());\n\t\t}\n\t\tmessage = this.messageRepository.save(message);\n\t\tredirect.addFlashAttribute(\"globalMessage\", \"view.success\");\n\t\tLong id = message.getId();\n\t\tAssert.state(id != null, \"'id' must not be null\");\n\t\treturn new ModelAndView(\"redirect:/{message.id}\", \"message.id\", id);\n\t}\n\n\t@RequestMapping(\"foo\")\n\tpublic String foo() {\n\t\tthrow new RuntimeException(\"Expected exception in controller\");\n\t}\n\n\t@GetMapping(\"delete/{id}\")\n\tpublic ModelAndView delete(@PathVariable(\"id\") Long id) {\n\t\tthis.messageRepository.deleteMessage(id);\n\t\tIterable<Message> messages = this.messageRepository.findAll();\n\t\treturn new ModelAndView(\"messages/list\", \"messages\", messages);\n\t}\n\n\t@GetMapping(\"modify/{id}\")\n\tpublic ModelAndView modifyForm(@PathVariable(\"id\") Message message) {\n\t\treturn new ModelAndView(\"messages/form\", \"message\", message);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/mvc/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.web.thymeleaf.mvc;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/java/smoketest/web/thymeleaf/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.web.thymeleaf;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/application.properties",
    "content": "# Allow Thymeleaf templates to be reloaded at dev time\nspring.thymeleaf.cache: false\nserver.tomcat.access_log_enabled: true\nserver.tomcat.basedir: target/tomcat\n\nlogging.level.org.thymeleaf:trace"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\n\t<!-- logger name=\"org.springframework\" level=\"DEBUG\"/-->\n\n</configuration>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/messages.properties",
    "content": "form.message=Message\nform.messages=Messages\nform.submit=Submit\nform.summary=Summary\nform.title=Messages : Create\n\nlist.create=Create Message\nlist.table.created=Created\nlist.table.empty=No messages\nlist.table.id=Id\nlist.table.summary=Summary\nlist.title=Messages : View all\n\nnavbar.messages=Messages\nnavbar.thymeleaf=Thymeleaf\n\nview.delete=delete\nview.messages=Messages\nview.modify=modify\nview.success=Successfully created a new message\nview.title=Messages : View\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/templates/fragments.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"https://www.thymeleaf.org\">\n\t<head th:fragment=\"head (title)\">\n\t\t<title th:text=\"${title}\">Fragments</title>\n\t\t<link rel=\"stylesheet\" th:href=\"@{/css/bootstrap.min.css}\"\n\t\t\thref=\"../../css/bootstrap.min.css\" />\n\t</head>\n\t<body>\n\t\t<div class=\"container\">\n\t\t\t<nav th:fragment=\"navbar\" class=\"navbar navbar-dark bg-primary\">\n\t\t\t\t<a class=\"navbar-brand\" href=\"https://www.thymeleaf.org/\" th:text=\"#{navbar.thymeleaf}\">Thymeleaf</a>\n\t\t\t\t<ul class=\"navbar-nav mr-auto mt-2 mt-lg-0\">\n\t\t\t\t\t<li class=\"nav-item\"><a class=\"nav-link\" th:href=\"@{/}\" href=\"messages.html\" th:text=\"#{navbar.messages}\">Messages</a></li>\n\t\t\t\t</ul>\n\t\t\t</nav>\n\t\t</div>\n\t</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/templates/messages/form.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"https://www.thymeleaf.org\">\n\t<head th:replace=\"fragments :: head(title=~{::title/text()})\">\n\t\t<title th:text=\"#{form.title}\">Messages : Create</title>\n\t</head>\n\t<body>\n\t\t<div class=\"container\">\n\t\t\t<div th:replace=\"fragments :: navbar\"></div>\n\t\t\t<div class=\"float-right mt-2\">\n\t\t\t\t<a class=\"btn btn-primary btn-sm\" th:href=\"@{/}\" href=\"messages.html\" th:text=\"#{form.messages}\"> Messages </a>\n\t\t\t</div>\n\t\t\t<h4 class=\"float-left mt-2\" th:text=\"#{form.title}\">Messages : Create</h4>\n\t\t\t<div class=\"clearfix\"></div>\n\t\t\t<form id=\"messageForm\" th:action=\"@{/(form)}\" th:object=\"${message}\" action=\"#\" method=\"post\">\n\t\t\t\t<div th:if=\"${#fields.hasErrors('*')}\" class=\"alert alert-danger\" role=\"alert\">\n\t\t\t\t\t<p th:each=\"error : ${#fields.errors('*')}\" class=\"m-0\" th:text=\"${error}\">Validation error</p>\n\t\t\t\t</div>\n\t\t\t\t<input type=\"hidden\" th:field=\"*{id}\" th:class=\"${'form-control' + (#fields.hasErrors('id') ? ' is-invalid' : '')}\"/>\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"summary\" th:text=\"#{form.summary}\">Summary</label>\n\t\t\t\t\t<input type=\"text\" th:field=\"*{summary}\" th:class=\"${'form-control' + (#fields.hasErrors('summary') ? ' is-invalid' : '')}\">\n\t\t\t\t</div>\n\t\t\t\t<div class=\"form-group\">\n\t\t\t\t\t<label for=\"text\" th:text=\"#{form.message}\">Message</label>\n\t\t\t\t\t<textarea th:field=\"*{text}\" th:class=\"${'form-control' + (#fields.hasErrors('text') ? ' is-invalid' : '')}\"></textarea>\n\t\t\t\t</div>\n\t\t\t\t<button type=\"submit\" class=\"btn btn-primary\" th:text=\"#{form.submit}\">Submit</button>\n\t\t\t</form>\n\t\t</div>\n\t</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/templates/messages/list.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"https://www.thymeleaf.org\">\n\t<head th:replace=\"fragments :: head(title=~{::title/text()})\">\n\t\t<title th:text=\"#{list.title}\">Messages : View all</title>\n\t</head>\n\t<body>\n\t\t<div class=\"container\">\n\t\t\t<div th:replace=\"fragments :: navbar\"></div>\n\t\t\t<div class=\"float-right mt-2\">\n\t\t\t\t<a class=\"btn btn-primary btn-sm\" href=\"form.html\" th:href=\"@{/(form)}\" th:text=\"#{list.create}\">Create Message</a>\n\t\t\t</div>\n\t\t\t<h4 class=\"float-left mt-2\" th:text=\"#{list.title}\">Messages : View all</h4>\n\t\t\t<table class=\"table table-bordered table-striped\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th th:text=\"#{list.table.id}\">ID</th>\n\t\t\t\t\t\t<th th:text=\"#{list.table.created}\">Created</th>\n\t\t\t\t\t\t<th th:text=\"#{list.table.summary}\">Summary</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr th:if=\"${messages.empty}\">\n\t\t\t\t\t\t<td colspan=\"3\" th:text=\"#{list.table.empty}\">No messages</td>\n\t\t\t\t\t</tr>\n\t\t\t\t\t<tr th:each=\"message : ${messages}\">\n\t\t\t\t\t\t<td th:text=\"${message.id}\">1</td>\n\t\t\t\t\t\t<td th:text=\"${#calendars.format(message.created)}\">July 11,\n\t\t\t\t\t\t\t2012 2:17:16 PM CDT</td>\n\t\t\t\t\t\t<td><a href=\"view.html\" th:href=\"@{'/' + ${message.id}}\"\n                               th:text=\"${message.summary}\"> The summary </a></td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/main/resources/templates/messages/view.html",
    "content": "<!DOCTYPE html>\n<html xmlns:th=\"https://www.thymeleaf.org\">\n\t<head th:replace=\"fragments :: head(title=~{::title/text()})\">\n\t\t<title th:text=\"#{view.title}\">Messages : View</title>\n\t</head>\n\t<body>\n\t\t<div class=\"container\">\n\t\t\t<div th:replace=\"fragments :: navbar\"></div>\n\t\t\t<div class=\"float-right mt-2\">\n\t\t\t\t<a class=\"btn btn-primary btn-sm\" href=\"list.html\" th:href=\"@{/}\" th:text=\"#{view.messages}\">Messages</a>\n\t\t\t</div>\n\t\t\t<h4 class=\"float-left mt-2\" th:text=\"#{view.title}\">Messages : View</h4>\n\t\t\t<div class=\"clearfix\"></div>\n\t\t\t<div class=\"alert alert-success\" th:if=\"${globalMessage}\" th:text=\"#{${globalMessage}}\">Some Success message\n\t\t\t</div>\n\t\t\t<div class=\"card\">\n\t\t\t\t<div class=\"card-body\">\n\t\t\t\t\t<h4 class=\"card-title\" th:text=\"${message.id + ': ' + message.summary}\">123 - A short summary...</h4>\n\t\t\t\t\t<h6 class=\"card-subtitle mb-2 text-muted\" th:text=\"${#calendars.format(message.created)}\">July 11, 2012 2:17:16 PM CDT</h6>\n\t\t\t\t\t<p class=\"card-text\" th:text=\"${message.text}\">A detailed message that is longer than the summary.</p>\n\t\t\t\t\t<a class=\"card-link\" href=\"messages\" th:href=\"@{'/delete/' + ${message.id}}\" th:text=\"#{view.delete}\">delete</a>\n\t\t\t\t\t<a class=\"card-link\" href=\"form.html\" th:href=\"@{'/modify/' + ${message.id}}\" th:text=\"#{view.modify}\"> modify</a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/test/java/smoketest/web/thymeleaf/MessageControllerWebTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf;\n\nimport java.util.regex.Pattern;\n\nimport org.assertj.core.api.HamcrestCondition;\nimport org.hamcrest.Description;\nimport org.hamcrest.TypeSafeMatcher;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.test.web.servlet.assertj.MockMvcTester;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * A Basic Spring MVC Test for the Sample Controller.\n *\n * @author Biju Kunjummen\n * @author Doo-Hwan, Kwak\n */\n@SpringBootTest\n@AutoConfigureMockMvc\nclass MessageControllerWebTests {\n\n\t@Autowired\n\tprivate MockMvcTester mvc;\n\n\t@Test\n\tvoid testHome() {\n\t\tassertThat(this.mvc.get().uri(\"/\")).hasStatusOk().bodyText().contains(\"<title>Messages\");\n\t}\n\n\t@Test\n\tvoid testCreate() {\n\t\tassertThat(this.mvc.post().uri(\"/\").param(\"text\", \"FOO text\").param(\"summary\", \"FOO\"))\n\t\t\t.hasStatus(HttpStatus.FOUND)\n\t\t\t.headers()\n\t\t\t.hasHeaderSatisfying(\"Location\",\n\t\t\t\t\t(values) -> assertThat(values).hasSize(1)\n\t\t\t\t\t\t.element(0)\n\t\t\t\t\t\t.satisfies(HamcrestCondition.matching(RegexMatcher.matches(\"/[0-9]+\"))));\n\t}\n\n\t@Test\n\tvoid testCreateValidation() {\n\t\tassertThat(this.mvc.post().uri(\"/\").param(\"text\", \"\").param(\"summary\", \"\")).hasStatusOk()\n\t\t\t.bodyText()\n\t\t\t.contains(\"is required\");\n\t}\n\n\tprivate static class RegexMatcher extends TypeSafeMatcher<String> {\n\n\t\tprivate final String regex;\n\n\t\tRegexMatcher(String regex) {\n\t\t\tthis.regex = regex;\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean matchesSafely(String item) {\n\t\t\treturn Pattern.compile(this.regex).matcher(item).find();\n\t\t}\n\n\t\t@Override\n\t\tpublic void describeMismatchSafely(String item, Description mismatchDescription) {\n\t\t\tmismatchDescription.appendText(\"was \\\"\").appendText(item).appendText(\"\\\"\");\n\t\t}\n\n\t\t@Override\n\t\tpublic void describeTo(Description description) {\n\t\t\tdescription.appendText(\"a string that matches regex: \").appendText(this.regex);\n\t\t}\n\n\t\tstatic org.hamcrest.Matcher<java.lang.String> matches(String regex) {\n\t\t\treturn new RegexMatcher(regex);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-web-thymeleaf/src/test/java/smoketest/web/thymeleaf/SampleWebUiApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.web.thymeleaf;\n\nimport java.net.URI;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for demo application.\n *\n * @author Dave Syer\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.http.clients.redirects=dont-follow\")\n@AutoConfigureTestRestTemplate\nclass SampleWebUiApplicationTests {\n\n\t@Autowired\n\tprivate TestRestTemplate restTemplate;\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid testHome() {\n\t\tResponseEntity<String> entity = this.restTemplate.getForEntity(\"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"<title>Messages\");\n\t\tassertThat(entity.getBody()).doesNotContain(\"layout:fragment\");\n\t}\n\n\t@Test\n\tvoid testCreate() {\n\t\tMultiValueMap<String, String> map = new LinkedMultiValueMap<>();\n\t\tmap.set(\"text\", \"FOO text\");\n\t\tmap.set(\"summary\", \"FOO\");\n\t\tURI location = this.restTemplate.postForLocation(\"/\", map);\n\t\tassertThat(location).isNotNull();\n\t\tassertThat(location.toString()).contains(\"localhost:\" + this.port);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot WebFlux smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\timplementation(project(\":starter:spring-boot-starter-mustache\"))\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\n\ttestImplementation(project(\":module:spring-boot-restclient\"))\n\ttestImplementation(project(\":module:spring-boot-resttestclient\"))\n\ttestImplementation(project(\":starter:spring-boot-starter-webflux-test\"))\n\ttestImplementation(\"io.projectreactor:reactor-test\")\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/java/smoketest/webflux/EchoHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\n@Component\npublic class EchoHandler {\n\n\tpublic Mono<ServerResponse> echo(ServerRequest request) {\n\t\treturn ServerResponse.ok().body(request.bodyToMono(String.class), String.class);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/java/smoketest/webflux/ExampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.server.ResponseStatusException;\n\n@RestController\npublic class ExampleController {\n\n\t@PostMapping(path = \"/\", consumes = { MediaType.APPLICATION_JSON_VALUE, \"!application/xml\" },\n\t\t\tproduces = MediaType.TEXT_PLAIN_VALUE, headers = \"X-Custom=Foo\", params = \"a!=alpha\")\n\tpublic String example() {\n\t\treturn \"Hello World\";\n\t}\n\n\t@GetMapping(\"/bad-request\")\n\tMono<String> badRequest() {\n\t\treturn Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST));\n\t}\n\n\t@GetMapping(\"five-hundred\")\n\tvoid fiveHundred() {\n\t\tthrow new RuntimeException(\"Expected!\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/java/smoketest/webflux/SampleWebFluxApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\nimport static org.springframework.web.reactive.function.server.RequestPredicates.POST;\nimport static org.springframework.web.reactive.function.server.RouterFunctions.route;\n\n@SpringBootApplication\npublic class SampleWebFluxApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication(SampleWebFluxApplication.class);\n\t\tapplication.setApplicationStartup(new BufferingApplicationStartup(1024));\n\t\tapplication.run(args);\n\t}\n\n\t@Bean\n\tpublic RouterFunction<ServerResponse> monoRouterFunction(EchoHandler echoHandler) {\n\t\treturn route(POST(\"/echo\"), echoHandler::echo);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/java/smoketest/webflux/WelcomeController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class WelcomeController {\n\n\t@GetMapping(\"/\")\n\tpublic String welcome() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/java/smoketest/webflux/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.webflux;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/resources/application.properties",
    "content": "management.endpoints.web.exposure.include=*\n\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/resources/templates/error/404.mustache",
    "content": "404 page\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/resources/templates/error/4xx.mustache",
    "content": "4xx page\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/main/resources/templates/error/error.mustache",
    "content": "<html>\n<body>\n<ul>\n\t<li>status: {{status}}</li>\n\t<li>message: {{message}}</li>\n</ul>\n</body>\n</html>"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/test/java/smoketest/webflux/ApplicationStartupSpringBootContextLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;\nimport org.springframework.boot.test.context.SpringBootContextLoader;\n\nclass ApplicationStartupSpringBootContextLoader extends SpringBootContextLoader {\n\n\t@Override\n\tprotected SpringApplication getSpringApplication() {\n\t\tSpringApplication application = new SpringApplication();\n\t\tapplication.setApplicationStartup(new BufferingApplicationStartup(1024));\n\t\treturn application;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/test/java/smoketest/webflux/SampleWebFluxApplicationActuatorDifferentPortTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.web.server.LocalManagementPort;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration tests for separate management and main service ports with empty endpoint\n * base path.\n *\n * @author HaiTao Zhang\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.server.port=0\", \"management.endpoints.web.base-path=/\" })\nclass SampleWebFluxApplicationActuatorDifferentPortTests {\n\n\t@LocalManagementPort\n\tprivate int managementPort;\n\n\t@Test\n\tvoid linksEndpointShouldBeAvailable() {\n\t\tResponseEntity<String> entity = new TestRestTemplate(\"user\", getPassword())\n\t\t\t.getForEntity(\"http://localhost:\" + this.managementPort + \"/\", String.class);\n\t\tassertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\tassertThat(entity.getBody()).contains(\"\\\"_links\\\"\");\n\t}\n\n\tprivate String getPassword() {\n\t\treturn \"password\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/test/java/smoketest/webflux/SampleWebFluxApplicationActuatorIsolatedJsonMapperFalseTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\n/**\n * Integration test for WebFlux actuator when using an isolated {@link JsonMapper}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.jackson.isolated-json-mapper=false\",\n\t\t\t\t\"spring.jackson.mapper.require-setters-for-getters=true\" })\n@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)\n@AutoConfigureWebTestClient\nclass SampleWebFluxApplicationActuatorIsolatedJsonMapperFalseTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid bodyIsEmptyDueToMainJsonMapperRequiringSettersForGetters() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/startup\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.json(\"{}\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/test/java/smoketest/webflux/SampleWebFluxApplicationActuatorIsolatedJsonMapperTrueTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.web.reactive.server.EntityExchangeResult;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Integration test for WebFlux actuator when not using an isolated {@link JsonMapper}.\n *\n * @author Phillip Webb\n */\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,\n\t\tproperties = { \"management.endpoints.jackson.isolated-json-mapper=true\",\n\t\t\t\t\"spring.jackson.mapper.require-setters-for-getters=true\" })\n@ContextConfiguration(loader = ApplicationStartupSpringBootContextLoader.class)\n@AutoConfigureWebTestClient\nclass SampleWebFluxApplicationActuatorIsolatedJsonMapperTrueTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid bodyIsPresentAsOnlyMainObjectMapperRequiresSettersForGetters() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/startup\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.consumeWith(this::assertExpectedJson);\n\t}\n\n\tprivate void assertExpectedJson(EntityExchangeResult<byte[]> result) {\n\t\tString body = new String(result.getResponseBody(), StandardCharsets.UTF_8);\n\t\tassertThat(body).contains(\"\\\"timeline\\\":\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/test/java/smoketest/webflux/SampleWebFluxApplicationIntegrationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic integration tests for WebFlux application.\n *\n * @author Brian Clozel\n */\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = \"spring.web.error.include-message=always\")\n@AutoConfigureWebTestClient\nclass SampleWebFluxApplicationIntegrationTests {\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid testWelcome() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/\")\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.exchange()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello World\");\n\t}\n\n\t@Test\n\tvoid testEcho() {\n\t\tthis.webClient.post()\n\t\t\t.uri(\"/echo\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.body(Mono.just(\"Hello WebFlux!\"), String.class)\n\t\t\t.exchange()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello WebFlux!\");\n\t}\n\n\t@Test\n\tvoid testActuatorStatus() {\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/actuator/health\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isOk()\n\t\t\t.expectBody()\n\t\t\t.json(\"{\\\"status\\\":\\\"UP\\\"}\");\n\t}\n\n\t@Test\n\tvoid templated404ErrorPage() {\n\t\tConsumer<@Nullable String> test = (body) -> assertThat(body).isEqualToNormalizingNewlines(\"404 page\\n\");\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/404\")\n\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isNotFound()\n\t\t\t.expectBody(String.class)\n\t\t\t.value(test);\n\t}\n\n\t@Test\n\tvoid templated4xxErrorPage() {\n\t\tConsumer<@Nullable String> test = (body) -> assertThat(body).isEqualToNormalizingNewlines(\"4xx page\\n\");\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/bad-request\")\n\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isBadRequest()\n\t\t\t.expectBody(String.class)\n\t\t\t.value(test);\n\t}\n\n\t@Test\n\tvoid htmlErrorPage() {\n\t\tConsumer<@Nullable String> test = (body) -> assertThat(body).contains(\"status: 500\")\n\t\t\t.contains(\"message: Expected!\");\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/five-hundred\")\n\t\t\t.accept(MediaType.TEXT_HTML)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t.expectBody(String.class)\n\t\t\t.value(test);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux/src/test/java/smoketest/webflux/SampleWebFluxApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webflux;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport reactor.core.publisher.Mono;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient;\nimport org.springframework.core.ParameterizedTypeReference;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.web.reactive.server.WebTestClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Basic tests for a WebFlux application, configuring the {@link WebTestClient} to test\n * without a running server.\n *\n * @author Stephane Nicoll\n */\n@SpringBootTest\n@AutoConfigureWebTestClient\nclass SampleWebFluxApplicationTests {\n\n\tprivate static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE = new ParameterizedTypeReference<Map<String, Object>>() {\n\t};\n\n\t@Autowired\n\tprivate WebTestClient webClient;\n\n\t@Test\n\tvoid testEcho() {\n\t\tthis.webClient.post()\n\t\t\t.uri(\"/echo\")\n\t\t\t.contentType(MediaType.TEXT_PLAIN)\n\t\t\t.accept(MediaType.TEXT_PLAIN)\n\t\t\t.body(Mono.just(\"Hello WebFlux!\"), String.class)\n\t\t\t.exchange()\n\t\t\t.expectBody(String.class)\n\t\t\t.isEqualTo(\"Hello WebFlux!\");\n\t}\n\n\t@Test\n\tvoid testBadRequest() {\n\t\tConsumer<@Nullable Map<String, Object>> test = (content) -> assertThat(content).containsEntry(\"path\",\n\t\t\t\t\"/bad-request\");\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/bad-request\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isBadRequest()\n\t\t\t.expectBody(MAP_TYPE)\n\t\t\t.value(test);\n\t}\n\n\t@Test\n\tvoid testServerError() {\n\t\tConsumer<@Nullable Map<String, Object>> test = (content) -> assertThat(content).containsEntry(\"path\",\n\t\t\t\t\"/five-hundred\");\n\t\tthis.webClient.get()\n\t\t\t.uri(\"/five-hundred\")\n\t\t\t.accept(MediaType.APPLICATION_JSON)\n\t\t\t.exchange()\n\t\t\t.expectStatus()\n\t\t\t.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR)\n\t\t\t.expectBody(MAP_TYPE)\n\t\t\t.value(test);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux-coroutines/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.jetbrains.kotlin.jvm\"\n\tid \"org.jetbrains.kotlin.plugin.spring\"\n}\n\ndescription = \"Spring Boot WebFlux coroutines smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webflux\"))\n\timplementation(\"com.fasterxml.jackson.module:jackson-module-kotlin\")\n\timplementation(\"org.jetbrains.kotlin:kotlin-reflect\")\n\timplementation(\"org.jetbrains.kotlin:kotlin-stdlib-jdk8\")\n\timplementation(\"org.jetbrains.kotlinx:kotlinx-coroutines-reactor\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webflux-test\"))\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux-coroutines/src/main/kotlin/smoketest/coroutines/CoroutinesController.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.coroutines\n\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.flow.flow\nimport org.springframework.web.bind.annotation.GetMapping\nimport org.springframework.web.bind.annotation.RestController\n\n@RestController\nclass CoroutinesController {\n\n\t@GetMapping(\"/suspending\")\n\tsuspend fun suspendingFunction(): String {\n\t\tdelay(10)\n\t\treturn \"Hello World\"\n\t}\n\n\t@GetMapping(\"/flow\")\n\tfun flow() = flow {\n\t\tdelay(10)\n\t\temit(\"Hello \")\n\t\tdelay(10)\n\t\temit(\"World\")\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux-coroutines/src/main/kotlin/smoketest/coroutines/SampleCoroutinesApplication.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.coroutines\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication\nimport org.springframework.boot.runApplication\n\n@SpringBootApplication\nclass SampleCoroutinesApplication\nfun main(args: Array<String>) {\n\trunApplication<SampleCoroutinesApplication>(*args)\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webflux-coroutines/src/test/kotlin/smoketest/coroutines/CoroutinesControllerTests.kt",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.coroutines\n\nimport org.junit.jupiter.api.Test\nimport org.springframework.beans.factory.annotation.Autowired\nimport org.springframework.boot.test.context.SpringBootTest\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment\nimport org.springframework.http.MediaType\nimport org.springframework.test.web.reactive.server.WebTestClient\nimport org.springframework.test.web.reactive.server.expectBody\nimport org.springframework.boot.webtestclient.autoconfigure.AutoConfigureWebTestClient\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@AutoConfigureWebTestClient\nclass CoroutinesControllerTests(@Autowired private val webClient: WebTestClient) {\n\n\t@Test\n\tfun testSuspendingFunction() {\n\t\twebClient.get().uri(\"/suspending\").accept(MediaType.TEXT_PLAIN).exchange()\n\t\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n\t@Test\n\tfun testFlow() {\n\t\twebClient.get().uri(\"/flow\").accept(MediaType.TEXT_PLAIN).exchange()\n\t\t\t\t.expectBody<String>().isEqualTo(\"Hello World\")\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot Web Services smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-webservices\"))\n\timplementation(\"org.jdom:jdom2\")\n\n\truntimeOnly(\"jaxen:jaxen\")\n\truntimeOnly(\"wsdl4j:wsdl4j\")\n\n\ttestImplementation(project(\":starter:spring-boot-starter-webservices-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/SampleWebServicesApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleWebServicesApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleWebServicesApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/WebServiceConfig.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;\nimport org.springframework.xml.xsd.XsdSchema;\n\n@Configuration(proxyBeanMethods = false)\nclass WebServiceConfig {\n\n\t@Bean(name = \"holiday\")\n\tDefaultWsdl11Definition defaultWsdl11Definition(@Qualifier(\"hr\") XsdSchema hrSchema) {\n\t\tDefaultWsdl11Definition wsdl = new DefaultWsdl11Definition();\n\t\twsdl.setPortTypeName(\"HumanResource\");\n\t\twsdl.setLocationUri(\"/holidayService/\");\n\t\twsdl.setTargetNamespace(\"https://company.example.com/hr/definitions\");\n\t\twsdl.setSchema(hrSchema);\n\t\treturn wsdl;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/endpoint/HolidayEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices.endpoint;\n\nimport java.time.LocalDate;\n\nimport org.jdom2.Element;\nimport org.jdom2.Namespace;\nimport org.jdom2.filter.Filters;\nimport org.jdom2.xpath.XPathExpression;\nimport org.jdom2.xpath.XPathFactory;\nimport smoketest.webservices.service.HumanResourceService;\n\nimport org.springframework.ws.server.endpoint.annotation.Endpoint;\nimport org.springframework.ws.server.endpoint.annotation.PayloadRoot;\nimport org.springframework.ws.server.endpoint.annotation.RequestPayload;\n\n@Endpoint\npublic class HolidayEndpoint {\n\n\tprivate static final String NAMESPACE_URI = \"https://company.example.com/hr/schemas\";\n\n\tprivate final XPathExpression<Element> startDateExpression;\n\n\tprivate final XPathExpression<Element> endDateExpression;\n\n\tprivate final XPathExpression<String> nameExpression;\n\n\tprivate final HumanResourceService humanResourceService;\n\n\tpublic HolidayEndpoint(HumanResourceService humanResourceService) {\n\t\tthis.humanResourceService = humanResourceService;\n\t\tNamespace namespace = Namespace.getNamespace(\"hr\", NAMESPACE_URI);\n\t\tXPathFactory xPathFactory = XPathFactory.instance();\n\t\tthis.startDateExpression = xPathFactory.compile(\"//hr:StartDate\", Filters.element(), null, namespace);\n\t\tthis.endDateExpression = xPathFactory.compile(\"//hr:EndDate\", Filters.element(), null, namespace);\n\t\tthis.nameExpression = xPathFactory.compile(\"concat(//hr:FirstName,' ',//hr:LastName)\", Filters.fstring(), null,\n\t\t\t\tnamespace);\n\t}\n\n\t@PayloadRoot(namespace = NAMESPACE_URI, localPart = \"HolidayRequest\")\n\tpublic void handleHolidayRequest(@RequestPayload Element holidayRequest) {\n\t\tLocalDate startDate = LocalDate.parse(this.startDateExpression.evaluateFirst(holidayRequest).getText());\n\t\tLocalDate endDate = LocalDate.parse(this.endDateExpression.evaluateFirst(holidayRequest).getText());\n\t\tString name = this.nameExpression.evaluateFirst(holidayRequest);\n\t\tthis.humanResourceService.bookHoliday(startDate, endDate, name);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/endpoint/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.webservices.endpoint;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.webservices;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/service/HumanResourceService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices.service;\n\nimport java.time.LocalDate;\n\npublic interface HumanResourceService {\n\n\tvoid bookHoliday(LocalDate startDate, LocalDate endDate, String name);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/service/StubHumanResourceService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices.service;\n\nimport java.time.LocalDate;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.stereotype.Service;\n\n@Service\nclass StubHumanResourceService implements HumanResourceService {\n\n\tprivate static final Log logger = LogFactory.getLog(StubHumanResourceService.class);\n\n\t@Override\n\tpublic void bookHoliday(LocalDate startDate, LocalDate endDate, String name) {\n\t\tlogger.info(\"Booking holiday for [\" + startDate + \" - \" + endDate + \"] for [\" + name + \"]\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/java/smoketest/webservices/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.webservices.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/resources/META-INF/schemas/hr.xsd",
    "content": "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"\n\t\txmlns:hr=\"https://company.example.com/hr/schemas\"\n\t\telementFormDefault=\"qualified\"\n\t\ttargetNamespace=\"https://company.example.com/hr/schemas\">\n\t<xs:element name=\"HolidayRequest\">\n\t\t<xs:complexType>\n\t\t\t<xs:all>\n\t\t\t\t<xs:element name=\"Holiday\" type=\"hr:HolidayType\"/>\n\t\t\t\t<xs:element name=\"Employee\" type=\"hr:EmployeeType\"/>\n\t\t\t</xs:all>\n\t\t</xs:complexType>\n\t</xs:element>\n\t<xs:complexType name=\"HolidayType\">\n\t\t<xs:sequence>\n\t\t\t<xs:element name=\"StartDate\" type=\"xs:date\"/>\n\t\t\t<xs:element name=\"EndDate\" type=\"xs:date\"/>\n\t\t</xs:sequence>\n\t</xs:complexType>\n\t<xs:complexType name=\"EmployeeType\">\n\t\t<xs:sequence>\n\t\t\t<xs:element name=\"Number\" type=\"xs:integer\"/>\n\t\t\t<xs:element name=\"FirstName\" type=\"xs:string\"/>\n\t\t\t<xs:element name=\"LastName\" type=\"xs:string\"/>\n\t\t</xs:sequence>\n\t</xs:complexType>\n</xs:schema>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/main/resources/application.properties",
    "content": "spring.webservices.wsdl-locations=classpath:META-INF/schemas/\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/test/java/smoketest/webservices/SampleWsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices;\n\nimport java.io.StringReader;\n\nimport javax.xml.transform.stream.StreamResult;\nimport javax.xml.transform.stream.StreamSource;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.ws.client.core.WebServiceTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleWsApplicationTests {\n\n\tprivate final WebServiceTemplate webServiceTemplate = new WebServiceTemplate();\n\n\t@LocalServerPort\n\tprivate int serverPort;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.webServiceTemplate.setDefaultUri(\"http://localhost:\" + this.serverPort + \"/services/\");\n\t}\n\n\t@Test\n\tvoid testSendingHolidayRequest(CapturedOutput output) {\n\t\tString request = \"\"\"\n\t\t\t\t<hr:HolidayRequest xmlns:hr=\"https://company.example.com/hr/schemas\">\n\t\t\t\t\t<hr:Holiday>\n\t\t\t\t\t\t<hr:StartDate>2013-10-20</hr:StartDate>\n\t\t\t\t\t\t<hr:EndDate>2013-11-22</hr:EndDate>\n\t\t\t\t\t</hr:Holiday>\n\t\t\t\t\t<hr:Employee>\n\t\t\t\t\t\t<hr:Number>1</hr:Number>\n\t\t\t\t\t\t<hr:FirstName>John</hr:FirstName>\n\t\t\t\t\t\t<hr:LastName>Doe</hr:LastName>\n\t\t\t\t\t</hr:Employee>\n\t\t\t\t</hr:HolidayRequest>\"\"\";\n\t\tStreamSource source = new StreamSource(new StringReader(request));\n\t\tStreamResult result = new StreamResult(System.out);\n\t\tthis.webServiceTemplate.sendSourceAndReceiveToResult(source, result);\n\t\tassertThat(output).contains(\"Booking holiday for\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-webservices/src/test/java/smoketest/webservices/WebServiceServerTestSampleWsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.webservices;\n\nimport java.io.StringReader;\nimport java.time.LocalDate;\n\nimport javax.xml.transform.stream.StreamSource;\n\nimport org.junit.jupiter.api.Test;\nimport smoketest.webservices.service.HumanResourceService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.webservices.test.autoconfigure.server.WebServiceServerTest;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.ws.test.server.MockWebServiceClient;\nimport org.springframework.ws.test.server.RequestCreators;\nimport org.springframework.ws.test.server.ResponseMatchers;\n\nimport static org.mockito.BDDMockito.then;\n\n/**\n * Tests for {@link SampleWsApplicationTests} that use {@link WebServiceServerTest} and\n * {@link MockWebServiceClient}.\n *\n * @author Andy Wilkinson\n * @author Stephane Nicoll\n */\n@WebServiceServerTest\nclass WebServiceServerTestSampleWsApplicationTests {\n\n\t@MockitoBean\n\tHumanResourceService service;\n\n\t@Autowired\n\tprivate MockWebServiceClient client;\n\n\t@Test\n\tvoid testSendingHolidayRequest() {\n\t\tString request = \"\"\"\n\t\t\t\t<hr:HolidayRequest xmlns:hr=\"https://company.example.com/hr/schemas\">\n\t\t\t\t\t<hr:Holiday>\n\t\t\t\t\t\t<hr:StartDate>2013-10-20</hr:StartDate>\n\t\t\t\t\t\t<hr:EndDate>2013-11-22</hr:EndDate>\n\t\t\t\t\t</hr:Holiday>\n\t\t\t\t\t<hr:Employee>\n\t\t\t\t\t\t<hr:Number>1</hr:Number>\n\t\t\t\t\t\t<hr:FirstName>John</hr:FirstName>\n\t\t\t\t\t\t<hr:LastName>Doe</hr:LastName>\n\t\t\t\t\t</hr:Employee>\n\t\t\t\t</hr:HolidayRequest>\"\"\";\n\t\tStreamSource source = new StreamSource(new StringReader(request));\n\t\tthis.client.sendRequest(RequestCreators.withPayload(source)).andExpect(ResponseMatchers.noFault());\n\t\tthen(this.service).should().bookHoliday(LocalDate.of(2013, 10, 20), LocalDate.of(2013, 11, 22), \"John Doe\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot WebSocket Jetty smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-jetty\"))\n\timplementation(project(\":starter:spring-boot-starter-websocket\")) {\n\t\texclude module: \"spring-boot-starter-tomcat\"\n\t}\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/SampleJettyWebSocketsApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty;\n\nimport smoketest.websocket.jetty.client.GreetingService;\nimport smoketest.websocket.jetty.client.SimpleGreetingService;\nimport smoketest.websocket.jetty.echo.DefaultEchoService;\nimport smoketest.websocket.jetty.echo.EchoService;\nimport smoketest.websocket.jetty.echo.EchoWebSocketHandler;\nimport smoketest.websocket.jetty.reverse.ReverseWebSocketEndpoint;\nimport smoketest.websocket.jetty.snake.SnakeWebSocketHandler;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.config.annotation.EnableWebSocket;\nimport org.springframework.web.socket.config.annotation.WebSocketConfigurer;\nimport org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;\nimport org.springframework.web.socket.handler.PerConnectionWebSocketHandler;\nimport org.springframework.web.socket.server.standard.ServerEndpointExporter;\n\n@Configuration(proxyBeanMethods = false)\n@EnableAutoConfiguration\n@EnableWebSocket\npublic class SampleJettyWebSocketsApplication extends SpringBootServletInitializer implements WebSocketConfigurer {\n\n\t@Override\n\tpublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {\n\t\tregistry.addHandler(echoWebSocketHandler(), \"/echo\").withSockJS();\n\t\tregistry.addHandler(snakeWebSocketHandler(), \"/snake\").withSockJS();\n\t}\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleJettyWebSocketsApplication.class);\n\t}\n\n\t@Bean\n\tpublic EchoService echoService() {\n\t\treturn new DefaultEchoService(\"Did you say \\\"%s\\\"?\");\n\t}\n\n\t@Bean\n\tpublic GreetingService greetingService() {\n\t\treturn new SimpleGreetingService();\n\t}\n\n\t@Bean\n\tpublic WebSocketHandler echoWebSocketHandler() {\n\t\treturn new EchoWebSocketHandler(echoService());\n\t}\n\n\t@Bean\n\tpublic WebSocketHandler snakeWebSocketHandler() {\n\t\treturn new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class);\n\t}\n\n\t@Bean\n\tpublic ReverseWebSocketEndpoint reverseWebSocketEndpoint() {\n\t\treturn new ReverseWebSocketEndpoint();\n\t}\n\n\t@Bean\n\tpublic ServerEndpointExporter serverEndpointExporter() {\n\t\treturn new ServerEndpointExporter();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleJettyWebSocketsApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/client/GreetingService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.client;\n\npublic interface GreetingService {\n\n\tString getGreeting();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/client/SimpleClientWebSocketHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.client;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\npublic class SimpleClientWebSocketHandler extends TextWebSocketHandler {\n\n\tprotected Log logger = LogFactory.getLog(SimpleClientWebSocketHandler.class);\n\n\tprivate final GreetingService greetingService;\n\n\tprivate final CountDownLatch latch;\n\n\tprivate final AtomicReference<String> messagePayload;\n\n\tpublic SimpleClientWebSocketHandler(GreetingService greetingService, CountDownLatch latch,\n\t\t\tAtomicReference<String> message) {\n\t\tthis.greetingService = greetingService;\n\t\tthis.latch = latch;\n\t\tthis.messagePayload = message;\n\t}\n\n\t@Override\n\tpublic void afterConnectionEstablished(WebSocketSession session) throws Exception {\n\t\tTextMessage message = new TextMessage(this.greetingService.getGreeting());\n\t\tsession.sendMessage(message);\n\t}\n\n\t@Override\n\tpublic void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n\t\tthis.logger.info(\"Received: \" + message + \" (\" + this.latch.getCount() + \")\");\n\t\tsession.close();\n\t\tthis.messagePayload.set(message.getPayload());\n\t\tthis.latch.countDown();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/client/SimpleGreetingService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.client;\n\npublic class SimpleGreetingService implements GreetingService {\n\n\t@Override\n\tpublic String getGreeting() {\n\t\treturn \"Hello world!\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.jetty.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/echo/DefaultEchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.echo;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class DefaultEchoService implements EchoService {\n\n\tprivate final String echoFormat;\n\n\tpublic DefaultEchoService(@Nullable String echoFormat) {\n\t\tthis.echoFormat = (echoFormat != null) ? echoFormat : \"%s\";\n\t}\n\n\t@Override\n\tpublic String getMessage(String message) {\n\t\treturn String.format(this.echoFormat, message);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/echo/EchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.echo;\n\npublic interface EchoService {\n\n\tString getMessage(String message);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/echo/EchoWebSocketHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.echo;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\n/**\n * Echo messages by implementing a Spring {@link WebSocketHandler} abstraction.\n */\npublic class EchoWebSocketHandler extends TextWebSocketHandler {\n\n\tprivate static final Log logger = LogFactory.getLog(EchoWebSocketHandler.class);\n\n\tprivate final EchoService echoService;\n\n\tpublic EchoWebSocketHandler(EchoService echoService) {\n\t\tthis.echoService = echoService;\n\t}\n\n\t@Override\n\tpublic void afterConnectionEstablished(WebSocketSession session) {\n\t\tlogger.debug(\"Opened new session in instance \" + this);\n\t}\n\n\t@Override\n\tpublic void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n\t\tString echoMessage = this.echoService.getMessage(message.getPayload());\n\t\tlogger.debug(echoMessage);\n\t\tsession.sendMessage(new TextMessage(echoMessage));\n\t}\n\n\t@Override\n\tpublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {\n\t\tsession.close(CloseStatus.SERVER_ERROR);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/echo/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.jetty.echo;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.jetty;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/reverse/ReverseWebSocketEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.reverse;\n\nimport java.io.IOException;\n\nimport jakarta.websocket.OnMessage;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.ServerEndpoint;\n\n@ServerEndpoint(\"/reverse\")\npublic class ReverseWebSocketEndpoint {\n\n\t@OnMessage\n\tpublic void handleMessage(Session session, String message) throws IOException {\n\t\tsession.getBasicRemote().sendText(\"Reversed: \" + new StringBuilder(message).reverse());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/reverse/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.jetty.reverse;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/Direction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\npublic enum Direction {\n\n\tNONE, NORTH, SOUTH, EAST, WEST\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/Location.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class Location {\n\n\t/**\n\t * The X location.\n\t */\n\tpublic int x;\n\n\t/**\n\t * The Y location.\n\t */\n\tpublic int y;\n\n\tpublic Location(int x, int y) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t}\n\n\tpublic Location getAdjacentLocation(Direction direction) {\n\t\treturn switch (direction) {\n\t\t\tcase NORTH -> new Location(this.x, this.y - SnakeUtils.GRID_SIZE);\n\t\t\tcase SOUTH -> new Location(this.x, this.y + SnakeUtils.GRID_SIZE);\n\t\t\tcase EAST -> new Location(this.x + SnakeUtils.GRID_SIZE, this.y);\n\t\t\tcase WEST -> new Location(this.x - SnakeUtils.GRID_SIZE, this.y);\n\t\t\tcase NONE -> this;\n\t\t};\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object o) {\n\t\tif (this == o) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tLocation location = (Location) o;\n\t\tif (this.x != location.x) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.y == location.y;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = this.x;\n\t\tresult = 31 * result + this.y;\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/Snake.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\nimport java.util.ArrayDeque;\nimport java.util.Collection;\nimport java.util.Deque;\n\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\n\npublic class Snake {\n\n\tprivate static final int DEFAULT_LENGTH = 5;\n\n\tprivate final Deque<Location> tail = new ArrayDeque<>();\n\n\tprivate final Object monitor = new Object();\n\n\tprivate final int id;\n\n\tprivate final WebSocketSession session;\n\n\tprivate final String hexColor;\n\n\tprivate Direction direction;\n\n\tprivate int length = DEFAULT_LENGTH;\n\n\tprivate Location head;\n\n\tpublic Snake(int id, WebSocketSession session) {\n\t\tthis.id = id;\n\t\tthis.session = session;\n\t\tthis.hexColor = SnakeUtils.getRandomHexColor();\n\t\tresetState();\n\t}\n\n\tprivate void resetState() {\n\t\tthis.direction = Direction.NONE;\n\t\tthis.head = SnakeUtils.getRandomLocation();\n\t\tthis.tail.clear();\n\t\tthis.length = DEFAULT_LENGTH;\n\t}\n\n\tprivate void kill() throws Exception {\n\t\tsynchronized (this.monitor) {\n\t\t\tresetState();\n\t\t\tsendMessage(\"{'type': 'dead'}\");\n\t\t}\n\t}\n\n\tprivate void reward() throws Exception {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.length++;\n\t\t\tsendMessage(\"{'type': 'kill'}\");\n\t\t}\n\t}\n\n\tprotected void sendMessage(String msg) throws Exception {\n\t\tthis.session.sendMessage(new TextMessage(msg));\n\t}\n\n\tpublic void update(Collection<Snake> snakes) throws Exception {\n\t\tsynchronized (this.monitor) {\n\t\t\tLocation nextLocation = this.head.getAdjacentLocation(this.direction);\n\t\t\tif (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) {\n\t\t\t\tnextLocation.x = 0;\n\t\t\t}\n\t\t\tif (nextLocation.y >= SnakeUtils.PLAYFIELD_HEIGHT) {\n\t\t\t\tnextLocation.y = 0;\n\t\t\t}\n\t\t\tif (nextLocation.x < 0) {\n\t\t\t\tnextLocation.x = SnakeUtils.PLAYFIELD_WIDTH;\n\t\t\t}\n\t\t\tif (nextLocation.y < 0) {\n\t\t\t\tnextLocation.y = SnakeUtils.PLAYFIELD_HEIGHT;\n\t\t\t}\n\t\t\tif (this.direction != Direction.NONE) {\n\t\t\t\tthis.tail.addFirst(this.head);\n\t\t\t\tif (this.tail.size() > this.length) {\n\t\t\t\t\tthis.tail.removeLast();\n\t\t\t\t}\n\t\t\t\tthis.head = nextLocation;\n\t\t\t}\n\n\t\t\thandleCollisions(snakes);\n\t\t}\n\t}\n\n\tprivate void handleCollisions(Collection<Snake> snakes) throws Exception {\n\t\tfor (Snake snake : snakes) {\n\t\t\tboolean headCollision = this.id != snake.id && snake.getHead().equals(this.head);\n\t\t\tboolean tailCollision = snake.getTail().contains(this.head);\n\t\t\tif (headCollision || tailCollision) {\n\t\t\t\tkill();\n\t\t\t\tif (this.id != snake.id) {\n\t\t\t\t\tsnake.reward();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic Location getHead() {\n\t\tsynchronized (this.monitor) {\n\t\t\treturn this.head;\n\t\t}\n\t}\n\n\tpublic Collection<Location> getTail() {\n\t\tsynchronized (this.monitor) {\n\t\t\treturn this.tail;\n\t\t}\n\t}\n\n\tpublic void setDirection(Direction direction) {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.direction = direction;\n\t\t}\n\t}\n\n\tpublic String getLocationsJson() {\n\t\tsynchronized (this.monitor) {\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tsb.append(String.format(\"{x: %d, y: %d}\", this.head.x, this.head.y));\n\t\t\tfor (Location location : this.tail) {\n\t\t\t\tsb.append(',');\n\t\t\t\tsb.append(String.format(\"{x: %d, y: %d}\", location.x, location.y));\n\t\t\t}\n\t\t\treturn String.format(\"{'id':%d,'body':[%s]}\", this.id, sb);\n\t\t}\n\t}\n\n\tpublic int getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getHexColor() {\n\t\treturn this.hexColor;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/SnakeTimer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Sets up the timer for the multiplayer snake game WebSocket example.\n */\npublic final class SnakeTimer {\n\n\tprivate static final long TICK_DELAY = 100;\n\n\tprivate static final Object MONITOR = new Object();\n\n\tprivate static final Log logger = LogFactory.getLog(SnakeTimer.class);\n\n\tprivate static final ConcurrentHashMap<Integer, Snake> snakes = new ConcurrentHashMap<>();\n\n\tprivate static @Nullable Timer gameTimer;\n\n\tprivate SnakeTimer() {\n\t}\n\n\tpublic static void addSnake(Snake snake) {\n\t\tsynchronized (MONITOR) {\n\t\t\tif (snakes.isEmpty()) {\n\t\t\t\tstartTimer();\n\t\t\t}\n\t\t\tsnakes.put(snake.getId(), snake);\n\t\t}\n\t}\n\n\tpublic static Collection<Snake> getSnakes() {\n\t\treturn Collections.unmodifiableCollection(snakes.values());\n\t}\n\n\tpublic static void removeSnake(Snake snake) {\n\t\tsynchronized (MONITOR) {\n\t\t\tsnakes.remove(snake.getId());\n\t\t\tif (snakes.isEmpty()) {\n\t\t\t\tstopTimer();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void tick() throws Exception {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) {\n\t\t\tSnake snake = iterator.next();\n\t\t\tsnake.update(SnakeTimer.getSnakes());\n\t\t\tsb.append(snake.getLocationsJson());\n\t\t\tif (iterator.hasNext()) {\n\t\t\t\tsb.append(',');\n\t\t\t}\n\t\t}\n\t\tbroadcast(String.format(\"{'type': 'update', 'data' : [%s]}\", sb));\n\t}\n\n\tpublic static void broadcast(String message) {\n\t\tCollection<Snake> snakes = new CopyOnWriteArrayList<>(SnakeTimer.getSnakes());\n\t\tfor (Snake snake : snakes) {\n\t\t\ttry {\n\t\t\t\tsnake.sendMessage(message);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\t// if Snake#sendMessage fails the client is removed\n\t\t\t\tremoveSnake(snake);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void startTimer() {\n\t\tgameTimer = new Timer(SnakeTimer.class.getSimpleName() + \" Timer\");\n\t\tgameTimer.scheduleAtFixedRate(new TimerTask() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\ttick();\n\t\t\t\t}\n\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t\tlogger.error(\"Caught to prevent timer from shutting down\", ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}, TICK_DELAY, TICK_DELAY);\n\t}\n\n\tpublic static void stopTimer() {\n\t\tif (gameTimer != null) {\n\t\t\tgameTimer.cancel();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/SnakeUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\nimport java.awt.Color;\nimport java.util.Random;\n\npublic final class SnakeUtils {\n\n\t/**\n\t * The width of the playfield.\n\t */\n\tpublic static final int PLAYFIELD_WIDTH = 640;\n\n\t/**\n\t * The height of the playfield.\n\t */\n\tpublic static final int PLAYFIELD_HEIGHT = 480;\n\n\t/**\n\t * The grid size.\n\t */\n\tpublic static final int GRID_SIZE = 10;\n\n\tprivate static final Random random = new Random();\n\n\tprivate SnakeUtils() {\n\t}\n\n\tpublic static String getRandomHexColor() {\n\t\tfloat hue = random.nextFloat();\n\t\t// sat between 0.1 and 0.3\n\t\tfloat saturation = (random.nextInt(2000) + 1000) / 10000f;\n\t\tfloat luminance = 0.9f;\n\t\tColor color = Color.getHSBColor(hue, saturation, luminance);\n\t\treturn '#' + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1);\n\t}\n\n\tpublic static Location getRandomLocation() {\n\t\tint x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH));\n\t\tint y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT));\n\t\treturn new Location(x, y);\n\t}\n\n\tprivate static int roundByGridSize(int value) {\n\t\tvalue = value + (GRID_SIZE / 2);\n\t\tvalue = value / GRID_SIZE;\n\t\tvalue = value * GRID_SIZE;\n\t\treturn value;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/SnakeWebSocketHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\nimport java.awt.Color;\nimport java.util.Iterator;\nimport java.util.Random;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\npublic class SnakeWebSocketHandler extends TextWebSocketHandler {\n\n\tprivate static final AtomicInteger snakeIds = new AtomicInteger();\n\n\tprivate static final Random random = new Random();\n\n\tprivate final int id;\n\n\tprivate @Nullable Snake snake;\n\n\tpublic static String getRandomHexColor() {\n\t\tfloat hue = random.nextFloat();\n\t\t// sat between 0.1 and 0.3\n\t\tfloat saturation = (random.nextInt(2000) + 1000) / 10000f;\n\t\tfloat luminance = 0.9f;\n\t\tColor color = Color.getHSBColor(hue, saturation, luminance);\n\t\treturn '#' + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1);\n\t}\n\n\tpublic static Location getRandomLocation() {\n\t\tint x = roundByGridSize(random.nextInt(SnakeUtils.PLAYFIELD_WIDTH));\n\t\tint y = roundByGridSize(random.nextInt(SnakeUtils.PLAYFIELD_HEIGHT));\n\t\treturn new Location(x, y);\n\t}\n\n\tprivate static int roundByGridSize(int value) {\n\t\tvalue = value + (SnakeUtils.GRID_SIZE / 2);\n\t\tvalue = value / SnakeUtils.GRID_SIZE;\n\t\tvalue = value * SnakeUtils.GRID_SIZE;\n\t\treturn value;\n\t}\n\n\tpublic SnakeWebSocketHandler() {\n\t\tthis.id = snakeIds.getAndIncrement();\n\t}\n\n\t@Override\n\tpublic void afterConnectionEstablished(WebSocketSession session) throws Exception {\n\t\tthis.snake = new Snake(this.id, session);\n\t\tSnakeTimer.addSnake(this.snake);\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) {\n\t\t\tSnake snake = iterator.next();\n\t\t\tsb.append(String.format(\"{id: %d, color: '%s'}\", snake.getId(), snake.getHexColor()));\n\t\t\tif (iterator.hasNext()) {\n\t\t\t\tsb.append(',');\n\t\t\t}\n\t\t}\n\t\tSnakeTimer.broadcast(String.format(\"{'type': 'join','data':[%s]}\", sb));\n\t}\n\n\t@Override\n\tprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n\t\tAssert.state(this.snake != null, \"'snake' must not be null\");\n\t\tString payload = message.getPayload();\n\t\tswitch (payload) {\n\t\t\tcase \"west\" -> this.snake.setDirection(Direction.WEST);\n\t\t\tcase \"north\" -> this.snake.setDirection(Direction.NORTH);\n\t\t\tcase \"east\" -> this.snake.setDirection(Direction.EAST);\n\t\t\tcase \"south\" -> this.snake.setDirection(Direction.SOUTH);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {\n\t\tAssert.state(this.snake != null, \"'snake' must not be null\");\n\t\tSnakeTimer.removeSnake(this.snake);\n\t\tSnakeTimer.broadcast(String.format(\"{'type': 'leave', 'id': %d}\", this.id));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/java/smoketest/websocket/jetty/snake/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.jetty.snake;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/resources/static/echo.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html>\n<html>\n<head>\n\t<title>Apache Tomcat WebSocket Examples: Echo</title>\n\t<style type=\"text/css\">\n\t\t#connect-container {\n\t\t\tfloat: left;\n\t\t\twidth: 400px\n\t\t}\n\n\t\t#connect-container div {\n\t\t\tpadding: 5px;\n\t\t}\n\n\t\t#console-container {\n\t\t\tfloat: left;\n\t\t\tmargin-left: 15px;\n\t\t\twidth: 400px;\n\t\t}\n\n\t\t#console {\n\t\t\tborder: 1px solid #CCCCCC;\n\t\t\tborder-right-color: #999999;\n\t\t\tborder-bottom-color: #999999;\n\t\t\theight: 170px;\n\t\t\toverflow-y: scroll;\n\t\t\tpadding: 5px;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t#console p {\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t}\n\t</style>\n\t<script src=\"https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js\"></script>\n\t<script type=\"text/javascript\">\n\t\tvar ws = null;\n\n\t\tfunction setConnected(connected) {\n\t\t\tdocument.getElementById('connect').disabled = connected;\n\t\t\tdocument.getElementById('disconnect').disabled = !connected;\n\t\t\tdocument.getElementById('echo').disabled = !connected;\n\t\t}\n\n\t\tfunction connect() {\n\t\t\tvar target = document.getElementById('target').value;\n\t\t\tws = new SockJS(target);\n\t\t\tws.onopen = function () {\n\t\t\t\tsetConnected(true);\n\t\t\t\tlog('Info: WebSocket connection opened.');\n\t\t\t};\n\t\t\tws.onmessage = function (event) {\n\t\t\t\tlog('Received: ' + event.data);\n\t\t\t};\n\t\t\tws.onclose = function () {\n\t\t\t\tsetConnected(false);\n\t\t\t\tlog('Info: WebSocket connection closed.');\n\t\t\t};\n\t\t}\n\n\t\tfunction disconnect() {\n\t\t\tif (ws != null) {\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t}\n\t\t\tsetConnected(false);\n\t\t}\n\n\t\tfunction echo() {\n\t\t\tif (ws != null) {\n\t\t\t\tvar message = document.getElementById('message').value;\n\t\t\t\tlog('Sent: ' + message);\n\t\t\t\tws.send(message);\n\t\t\t} else {\n\t\t\t\talert('WebSocket connection not established, please connect.');\n\t\t\t}\n\t\t}\n\n\t\tfunction log(message) {\n\t\t\tvar console = document.getElementById('console');\n\t\t\tvar p = document.createElement('p');\n\t\t\tp.style.wordWrap = 'break-word';\n\t\t\tp.appendChild(document.createTextNode(message));\n\t\t\tconsole.appendChild(p);\n\t\t\twhile (console.childNodes.length > 25) {\n\t\t\t\tconsole.removeChild(console.firstChild);\n\t\t\t}\n\t\t\tconsole.scrollTop = console.scrollHeight;\n\t\t}\n\t</script>\n</head>\n<body>\n<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n<div>\n\t<div id=\"connect-container\">\n\t\t<div>\n\t\t\t<input id=\"target\" type=\"text\" size=\"40\" style=\"width: 350px\" value=\"/echo\"/>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"connect\" onclick=\"connect();\">Connect</button>\n\t\t\t<button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">Disconnect</button>\n\t\t</div>\n\t\t<div>\n\t\t\t<textarea id=\"message\" style=\"width: 350px\">Here is a message!</textarea>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"echo\" onclick=\"echo();\" disabled=\"disabled\">Echo message</button>\n\t\t</div>\n\t</div>\n\t<div id=\"console-container\">\n\t\t<div id=\"console\"></div>\n\t</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/resources/static/index.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html>\n<html>\n<head>\n\t<title>Apache Tomcat WebSocket Examples: Index</title>\n</head>\n<body>\n<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n<p>Please select the sample you would like to try.</p>\n<ul>\n\t<li><a href=\"./echo.html\">Echo</a></li>\n\t<li><a href=\"./reverse.html\">Reverse</a></li>\n\t<li><a href=\"./snake.html\">Snake</a></li>\n</ul>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/resources/static/reverse.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html>\n<html>\n<head>\n\t<title>WebSocket Examples: Reverse</title>\n\t<style type=\"text/css\">\n\t\t#connect-container {\n\t\t\tfloat: left;\n\t\t\twidth: 400px\n\t\t}\n\n\t\t#connect-container div {\n\t\t\tpadding: 5px;\n\t\t}\n\n\t\t#console-container {\n\t\t\tfloat: left;\n\t\t\tmargin-left: 15px;\n\t\t\twidth: 400px;\n\t\t}\n\n\t\t#console {\n\t\t\tborder: 1px solid #CCCCCC;\n\t\t\tborder-right-color: #999999;\n\t\t\tborder-bottom-color: #999999;\n\t\t\theight: 170px;\n\t\t\toverflow-y: scroll;\n\t\t\tpadding: 5px;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t#console p {\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t}\n\t</style>\n\t<script type=\"text/javascript\">\n\t\tvar ws = null;\n\n\t\tfunction setConnected(connected) {\n\t\t\tdocument.getElementById('connect').disabled = connected;\n\t\t\tdocument.getElementById('disconnect').disabled = !connected;\n\t\t\tdocument.getElementById('reverse').disabled = !connected;\n\t\t}\n\n\t\tfunction connect() {\n\t\t\tvar target = document.getElementById('target').value;\n\t\t\tws = new WebSocket(target);\n\t\t\tws.onopen = function () {\n\t\t\t\tsetConnected(true);\n\t\t\t\tlog('Info: WebSocket connection opened.');\n\t\t\t};\n\t\t\tws.onmessage = function (event) {\n\t\t\t\tlog('Received: ' + event.data);\n\t\t\t};\n\t\t\tws.onclose = function () {\n\t\t\t\tsetConnected(false);\n\t\t\t\tlog('Info: WebSocket connection closed.');\n\t\t\t};\n\t\t}\n\n\t\tfunction updateTarget() {\n\t\t\tif (window.location.protocol == 'http:') {\n\t\t\t\tdocument.getElementById('target').value = 'ws://' + window.location.host + document.getElementById('target').value;\n\t\t\t} else {\n\t\t\t\tdocument.getElementById('target').value = 'wss://' + window.location.host + document.getElementById('target').value;\n\t\t\t}\n\t\t}\n\n\t\tfunction disconnect() {\n\t\t\tif (ws != null) {\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t}\n\t\t\tsetConnected(false);\n\t\t}\n\n\t\tfunction reverse() {\n\t\t\tif (ws != null) {\n\t\t\t\tvar message = document.getElementById('message').value;\n\t\t\t\tlog('Sent: ' + message);\n\t\t\t\tws.send(message);\n\t\t\t} else {\n\t\t\t\talert('WebSocket connection not established, please connect.');\n\t\t\t}\n\t\t}\n\n\t\tfunction log(message) {\n\t\t\tvar console = document.getElementById('console');\n\t\t\tvar p = document.createElement('p');\n\t\t\tp.style.wordWrap = 'break-word';\n\t\t\tp.appendChild(document.createTextNode(message));\n\t\t\tconsole.appendChild(p);\n\t\t\twhile (console.childNodes.length > 25) {\n\t\t\t\tconsole.removeChild(console.firstChild);\n\t\t\t}\n\t\t\tconsole.scrollTop = console.scrollHeight;\n\t\t}\n\t</script>\n</head>\n<body onload=\"updateTarget()\">\n<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n<div>\n\t<div id=\"connect-container\">\n\t\t<div>\n\t\t\t<input id=\"target\" type=\"text\" size=\"40\" style=\"width: 350px\" value=\"/reverse\"/>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"connect\" onclick=\"connect();\">Connect</button>\n\t\t\t<button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">Disconnect</button>\n\t\t</div>\n\t\t<div>\n\t\t\t<textarea id=\"message\" style=\"width: 350px\">Here is a message!</textarea>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"reverse\" onclick=\"reverse();\" disabled=\"disabled\">Reverse message</button>\n\t\t</div>\n\t</div>\n\t<div id=\"console-container\">\n\t\t<div id=\"console\"></div>\n\t</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/main/resources/static/snake.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\t\t\"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n\t<title>Apache Tomcat WebSocket Examples: Multiplayer Snake</title>\n\t<style type=\"text/css\">\n\t\t#playground {\n\t\t\twidth: 640px;\n\t\t\theight: 480px;\n\t\t\tbackground-color: #000;\n\t\t}\n\n\t\t#console-container {\n\t\t\tfloat: left;\n\t\t\tmargin-left: 15px;\n\t\t\twidth: 300px;\n\t\t}\n\n\t\t#console {\n\t\t\tborder: 1px solid #CCCCCC;\n\t\t\tborder-right-color: #999999;\n\t\t\tborder-bottom-color: #999999;\n\t\t\theight: 480px;\n\t\t\toverflow-y: scroll;\n\t\t\tpadding-left: 5px;\n\t\t\tpadding-right: 5px;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t#console p {\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t}\n\t</style>\n\t<script src=\"https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js\"></script>\n</head>\n<body>\n\t<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n\n\t<div style=\"float: left\">\n\t\t<canvas id=\"playground\" width=\"640\" height=\"480\"></canvas>\n\t</div>\n\t<div id=\"console-container\">\n\t\t<div id=\"console\"></div>\n\t</div>\n\t<script type=\"text/javascript\">\n\n\t\tvar Game = {};\n\n\t\tGame.fps = 30;\n\t\tGame.socket = null;\n\t\tGame.nextFrame = null;\n\t\tGame.interval = null;\n\t\tGame.direction = 'none';\n\t\tGame.gridSize = 10;\n\n\t\tfunction Snake() {\n\t\t\tthis.snakeBody = [];\n\t\t\tthis.color = null;\n\t\t}\n\n\t\tSnake.prototype.draw = function(context) {\n\t\t\tfor (var id in this.snakeBody) {\n\t\t\t\tcontext.fillStyle = this.color;\n\t\t\t\tcontext.fillRect(this.snakeBody[id].x, this.snakeBody[id].y, Game.gridSize, Game.gridSize);\n\t\t\t}\n\t\t};\n\n\t\tGame.initialize = function() {\n\t\t\tthis.entities = [];\n\t\t\tcanvas = document.getElementById('playground');\n\t\t\tif (!canvas.getContext) {\n\t\t\t\tConsole.log('Error: 2d canvas not supported by this browser.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.context = canvas.getContext('2d');\n\t\t\twindow.addEventListener('keydown', function (e) {\n\t\t\t\tvar code = e.keyCode;\n\t\t\t\tif (code > 36 && code < 41) {\n\t\t\t\t\tswitch (code) {\n\t\t\t\t\t\tcase 37:\n\t\t\t\t\t\t\tif (Game.direction != 'east') Game.setDirection('west');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 38:\n\t\t\t\t\t\t\tif (Game.direction != 'south') Game.setDirection('north');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 39:\n\t\t\t\t\t\t\tif (Game.direction != 'west') Game.setDirection('east');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 40:\n\t\t\t\t\t\t\tif (Game.direction != 'north') Game.setDirection('south');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, false);\n\t\t\tGame.connect();\n\t\t};\n\n\t\tGame.setDirection  = function(direction) {\n\t\t\tGame.direction = direction;\n\t\t\tGame.socket.send(direction);\n\t\t\tConsole.log('Sent: Direction ' + direction);\n\t\t};\n\n\t\tGame.startGameLoop = function() {\n\t\t\tif (window.webkitRequestAnimationFrame) {\n\t\t\t\tGame.nextFrame = function () {\n\t\t\t\t\twebkitRequestAnimationFrame(Game.run);\n\t\t\t\t};\n\t\t\t} else if (window.mozRequestAnimationFrame) {\n\t\t\t\tGame.nextFrame = function () {\n\t\t\t\t\tmozRequestAnimationFrame(Game.run);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tGame.interval = setInterval(Game.run, 1000 / Game.fps);\n\t\t\t}\n\t\t\tif (Game.nextFrame != null) {\n\t\t\t\tGame.nextFrame();\n\t\t\t}\n\t\t};\n\n\t\tGame.stopGameLoop = function () {\n\t\t\tGame.nextFrame = null;\n\t\t\tif (Game.interval != null) {\n\t\t\t\tclearInterval(Game.interval);\n\t\t\t}\n\t\t};\n\n\t\tGame.draw = function() {\n\t\t\tthis.context.clearRect(0, 0, 640, 480);\n\t\t\tfor (var id in this.entities) {\n\t\t\t\tthis.entities[id].draw(this.context);\n\t\t\t}\n\t\t};\n\n\t\tGame.addSnake = function(id, color) {\n\t\t\tGame.entities[id] = new Snake();\n\t\t\tGame.entities[id].color = color;\n\t\t};\n\n\t\tGame.updateSnake = function(id, snakeBody) {\n\t\t\tif (typeof Game.entities[id] != \"undefined\") {\n\t\t\t\tGame.entities[id].snakeBody = snakeBody;\n\t\t\t}\n\t\t};\n\n\t\tGame.removeSnake = function(id) {\n\t\t\tGame.entities[id] = null;\n\t\t\t// Force GC.\n\t\t\tdelete Game.entities[id];\n\t\t};\n\n\t\tGame.run = (function() {\n\t\t\tvar skipTicks = 1000 / Game.fps, nextGameTick = (new Date).getTime();\n\n\t\t\treturn function() {\n\t\t\t\twhile ((new Date).getTime() > nextGameTick) {\n\t\t\t\t\tnextGameTick += skipTicks;\n\t\t\t\t}\n\t\t\t\tGame.draw();\n\t\t\t\tif (Game.nextFrame != null) {\n\t\t\t\t\tGame.nextFrame();\n\t\t\t\t}\n\t\t\t};\n\t\t})();\n\n\t\tGame.connect = (function() {\n\t\t\tGame.socket = new SockJS(\"/snake\");\n\n\t\t\tGame.socket.onopen = function () {\n\t\t\t\t// Socket open.. start the game loop.\n\t\t\t\tConsole.log('Info: WebSocket connection opened.');\n\t\t\t\tConsole.log('Info: Press an arrow key to begin.');\n\t\t\t\tGame.startGameLoop();\n\t\t\t\tsetInterval(function() {\n\t\t\t\t\t// Prevent server read timeout.\n\t\t\t\t\tGame.socket.send('ping');\n\t\t\t\t}, 5000);\n\t\t\t};\n\n\t\t\tGame.socket.onclose = function () {\n\t\t\t\tConsole.log('Info: WebSocket closed.');\n\t\t\t\tGame.stopGameLoop();\n\t\t\t};\n\n\t\t\tGame.socket.onmessage = function (message) {\n\t\t\t\t// _Potential_ security hole, consider using json lib to parse data in production.\n\t\t\t\tvar packet = eval('(' + message.data + ')');\n\t\t\t\tswitch (packet.type) {\n\t\t\t\t\tcase 'update':\n\t\t\t\t\t\tfor (var i = 0; i < packet.data.length; i++) {\n\t\t\t\t\t\t\tGame.updateSnake(packet.data[i].id, packet.data[i].body);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'join':\n\t\t\t\t\t\tfor (var j = 0; j < packet.data.length; j++) {\n\t\t\t\t\t\t\tGame.addSnake(packet.data[j].id, packet.data[j].color);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'leave':\n\t\t\t\t\t\tGame.removeSnake(packet.id);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'dead':\n\t\t\t\t\t\tConsole.log('Info: Your snake is dead, bad luck!');\n\t\t\t\t\t\tGame.direction = 'none';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'kill':\n\t\t\t\t\t\tConsole.log('Info: Head shot!');\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\n\t\tvar Console = {};\n\n\t\tConsole.log = (function(message) {\n\t\t\tvar console = document.getElementById('console');\n\t\t\tvar p = document.createElement('p');\n\t\t\tp.style.wordWrap = 'break-word';\n\t\t\tp.innerHTML = message;\n\t\t\tconsole.appendChild(p);\n\t\t\twhile (console.childNodes.length > 25) {\n\t\t\t\tconsole.removeChild(console.firstChild);\n\t\t\t}\n\t\t\tconsole.scrollTop = console.scrollHeight;\n\t\t});\n\n\t\tGame.initialize();\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/test/java/smoketest/websocket/jetty/SampleWebSocketsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.junit.jupiter.api.Test;\nimport smoketest.websocket.jetty.client.GreetingService;\nimport smoketest.websocket.jetty.client.SimpleClientWebSocketHandler;\nimport smoketest.websocket.jetty.client.SimpleGreetingService;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.client.WebSocketConnectionManager;\nimport org.springframework.web.socket.client.standard.StandardWebSocketClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(classes = SampleJettyWebSocketsApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)\nclass SampleWebSocketsApplicationTests {\n\n\tprivate static final Log logger = LogFactory.getLog(SampleWebSocketsApplicationTests.class);\n\n\t@LocalServerPort\n\tprivate int port = 1234;\n\n\t@Test\n\tvoid echoEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/echo/websocket\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Did you say \\\"Hello world!\\\"?\");\n\t}\n\n\t@Test\n\tvoid reverseEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/reverse\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Reversed: !dlrow olleH\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientConfiguration implements CommandLineRunner {\n\n\t\t@Value(\"${websocket.uri}\")\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String webSocketUri;\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate final AtomicReference<String> messagePayload = new AtomicReference<>();\n\n\t\t@Override\n\t\tpublic void run(String... args) throws Exception {\n\t\t\tlogger.info(\"Waiting for response: latch=\" + this.latch.getCount());\n\t\t\tif (this.latch.await(10, TimeUnit.SECONDS)) {\n\t\t\t\tlogger.info(\"Got response: \" + this.messagePayload.get());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Response not received: latch=\" + this.latch.getCount());\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tWebSocketConnectionManager wsConnectionManager() {\n\t\t\tWebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri);\n\t\t\tmanager.setAutoStartup(true);\n\t\t\treturn manager;\n\t\t}\n\n\t\t@Bean\n\t\tStandardWebSocketClient client() {\n\t\t\treturn new StandardWebSocketClient();\n\t\t}\n\n\t\t@Bean\n\t\tSimpleClientWebSocketHandler handler() {\n\t\t\treturn new SimpleClientWebSocketHandler(greetingService(), this.latch, this.messagePayload);\n\t\t}\n\n\t\t@Bean\n\t\tGreetingService greetingService() {\n\t\t\treturn new SimpleGreetingService();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/test/java/smoketest/websocket/jetty/echo/CustomContainerWebSocketsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.echo;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.junit.jupiter.api.Test;\nimport smoketest.websocket.jetty.SampleJettyWebSocketsApplication;\nimport smoketest.websocket.jetty.client.GreetingService;\nimport smoketest.websocket.jetty.client.SimpleClientWebSocketHandler;\nimport smoketest.websocket.jetty.client.SimpleGreetingService;\nimport smoketest.websocket.jetty.echo.CustomContainerWebSocketsApplicationTests.CustomContainerConfiguration;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.client.WebSocketConnectionManager;\nimport org.springframework.web.socket.client.standard.StandardWebSocketClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(classes = { SampleJettyWebSocketsApplication.class, CustomContainerConfiguration.class },\n\t\twebEnvironment = WebEnvironment.RANDOM_PORT)\nclass CustomContainerWebSocketsApplicationTests {\n\n\tprivate static final Log logger = LogFactory.getLog(CustomContainerWebSocketsApplicationTests.class);\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid echoEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/ws/echo/websocket\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Did you say \\\"Hello world!\\\"?\");\n\t}\n\n\t@Test\n\tvoid reverseEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/ws/reverse\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Reversed: !dlrow olleH\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class CustomContainerConfiguration {\n\n\t\t@Bean\n\t\tpublic ServletWebServerFactory webServerFactory() {\n\t\t\treturn new JettyServletWebServerFactory(\"/ws\", 0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientConfiguration implements CommandLineRunner {\n\n\t\t@Value(\"${websocket.uri}\")\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String webSocketUri;\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate final AtomicReference<String> messagePayload = new AtomicReference<>();\n\n\t\t@Override\n\t\tpublic void run(String... args) throws Exception {\n\t\t\tlogger.info(\"Waiting for response: latch=\" + this.latch.getCount());\n\t\t\tif (this.latch.await(10, TimeUnit.SECONDS)) {\n\t\t\t\tlogger.info(\"Got response: \" + this.messagePayload.get());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Response not received: latch=\" + this.latch.getCount());\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tWebSocketConnectionManager wsConnectionManager() {\n\t\t\tWebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri);\n\t\t\tmanager.setAutoStartup(true);\n\t\t\treturn manager;\n\t\t}\n\n\t\t@Bean\n\t\tStandardWebSocketClient client() {\n\t\t\treturn new StandardWebSocketClient();\n\t\t}\n\n\t\t@Bean\n\t\tSimpleClientWebSocketHandler handler() {\n\t\t\treturn new SimpleClientWebSocketHandler(greetingService(), this.latch, this.messagePayload);\n\t\t}\n\n\t\t@Bean\n\t\tGreetingService greetingService() {\n\t\t\treturn new SimpleGreetingService();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-jetty/src/test/java/smoketest/websocket/jetty/snake/SnakeTimerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.jetty.snake;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\nclass SnakeTimerTests {\n\n\t@Test\n\tvoid removeDysfunctionalSnakes() throws Exception {\n\t\tSnake snake = mock(Snake.class);\n\t\twillThrow(new IOException()).given(snake).sendMessage(anyString());\n\t\tSnakeTimer.addSnake(snake);\n\n\t\tSnakeTimer.broadcast(\"\");\n\t\tassertThat(SnakeTimer.getSnakes()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot WebSocket Tomcat smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter-websocket\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/SampleTomcatWebSocketApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat;\n\nimport smoketest.websocket.tomcat.client.GreetingService;\nimport smoketest.websocket.tomcat.client.SimpleGreetingService;\nimport smoketest.websocket.tomcat.echo.DefaultEchoService;\nimport smoketest.websocket.tomcat.echo.EchoService;\nimport smoketest.websocket.tomcat.echo.EchoWebSocketHandler;\nimport smoketest.websocket.tomcat.reverse.ReverseWebSocketEndpoint;\nimport smoketest.websocket.tomcat.snake.SnakeWebSocketHandler;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.config.annotation.EnableWebSocket;\nimport org.springframework.web.socket.config.annotation.WebSocketConfigurer;\nimport org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;\nimport org.springframework.web.socket.handler.PerConnectionWebSocketHandler;\nimport org.springframework.web.socket.server.standard.ServerEndpointExporter;\n\n@Configuration(proxyBeanMethods = false)\n@EnableAutoConfiguration\n@EnableWebSocket\npublic class SampleTomcatWebSocketApplication extends SpringBootServletInitializer implements WebSocketConfigurer {\n\n\t@Override\n\tpublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {\n\t\tregistry.addHandler(echoWebSocketHandler(), \"/echo\").withSockJS();\n\t\tregistry.addHandler(snakeWebSocketHandler(), \"/snake\").withSockJS();\n\t}\n\n\t@Override\n\tprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\n\t\treturn application.sources(SampleTomcatWebSocketApplication.class);\n\t}\n\n\t@Bean\n\tpublic EchoService echoService() {\n\t\treturn new DefaultEchoService(\"Did you say \\\"%s\\\"?\");\n\t}\n\n\t@Bean\n\tpublic GreetingService greetingService() {\n\t\treturn new SimpleGreetingService();\n\t}\n\n\t@Bean\n\tpublic WebSocketHandler echoWebSocketHandler() {\n\t\treturn new EchoWebSocketHandler(echoService());\n\t}\n\n\t@Bean\n\tpublic WebSocketHandler snakeWebSocketHandler() {\n\t\treturn new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class);\n\t}\n\n\t@Bean\n\tpublic ReverseWebSocketEndpoint reverseWebSocketEndpoint() {\n\t\treturn new ReverseWebSocketEndpoint();\n\t}\n\n\t@Bean\n\tpublic ServerEndpointExporter serverEndpointExporter() {\n\t\treturn new ServerEndpointExporter();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SampleTomcatWebSocketApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/client/GreetingService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.client;\n\npublic interface GreetingService {\n\n\tString getGreeting();\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/client/SimpleClientWebSocketHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.client;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\npublic class SimpleClientWebSocketHandler extends TextWebSocketHandler {\n\n\tprotected Log logger = LogFactory.getLog(SimpleClientWebSocketHandler.class);\n\n\tprivate final GreetingService greetingService;\n\n\tprivate final CountDownLatch latch;\n\n\tprivate final AtomicReference<String> messagePayload;\n\n\tpublic SimpleClientWebSocketHandler(GreetingService greetingService, CountDownLatch latch,\n\t\t\tAtomicReference<String> message) {\n\t\tthis.greetingService = greetingService;\n\t\tthis.latch = latch;\n\t\tthis.messagePayload = message;\n\t}\n\n\t@Override\n\tpublic void afterConnectionEstablished(WebSocketSession session) throws Exception {\n\t\tTextMessage message = new TextMessage(this.greetingService.getGreeting());\n\t\tsession.sendMessage(message);\n\t}\n\n\t@Override\n\tpublic void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n\t\tthis.logger.info(\"Received: \" + message + \" (\" + this.latch.getCount() + \")\");\n\t\tsession.close();\n\t\tthis.messagePayload.set(message.getPayload());\n\t\tthis.latch.countDown();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/client/SimpleGreetingService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.client;\n\npublic class SimpleGreetingService implements GreetingService {\n\n\t@Override\n\tpublic String getGreeting() {\n\t\treturn \"Hello world!\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/client/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.tomcat.client;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/echo/DefaultEchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.echo;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class DefaultEchoService implements EchoService {\n\n\tprivate final String echoFormat;\n\n\tpublic DefaultEchoService(@Nullable String echoFormat) {\n\t\tthis.echoFormat = (echoFormat != null) ? echoFormat : \"%s\";\n\t}\n\n\t@Override\n\tpublic String getMessage(String message) {\n\t\treturn String.format(this.echoFormat, message);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/echo/EchoService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.echo;\n\npublic interface EchoService {\n\n\tString getMessage(String message);\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/echo/EchoWebSocketHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.echo;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketHandler;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\n/**\n * Echo messages by implementing a Spring {@link WebSocketHandler} abstraction.\n */\npublic class EchoWebSocketHandler extends TextWebSocketHandler {\n\n\tprivate static final Log logger = LogFactory.getLog(EchoWebSocketHandler.class);\n\n\tprivate final EchoService echoService;\n\n\tpublic EchoWebSocketHandler(EchoService echoService) {\n\t\tthis.echoService = echoService;\n\t}\n\n\t@Override\n\tpublic void afterConnectionEstablished(WebSocketSession session) {\n\t\tlogger.debug(\"Opened new session in instance \" + this);\n\t}\n\n\t@Override\n\tpublic void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n\t\tString echoMessage = this.echoService.getMessage(message.getPayload());\n\t\tlogger.debug(echoMessage);\n\t\tsession.sendMessage(new TextMessage(echoMessage));\n\t}\n\n\t@Override\n\tpublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {\n\t\tsession.close(CloseStatus.SERVER_ERROR);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/echo/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.tomcat.echo;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.tomcat;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/reverse/ReverseWebSocketEndpoint.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.reverse;\n\nimport java.io.IOException;\n\nimport jakarta.websocket.OnMessage;\nimport jakarta.websocket.Session;\nimport jakarta.websocket.server.ServerEndpoint;\n\n@ServerEndpoint(\"/reverse\")\npublic class ReverseWebSocketEndpoint {\n\n\t@OnMessage\n\tpublic void handleMessage(Session session, String message) throws IOException {\n\t\tsession.getBasicRemote().sendText(\"Reversed: \" + new StringBuilder(message).reverse());\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/reverse/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.tomcat.reverse;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/Direction.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\npublic enum Direction {\n\n\tNONE, NORTH, SOUTH, EAST, WEST\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/Location.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\nimport org.jspecify.annotations.Nullable;\n\npublic class Location {\n\n\t/**\n\t * The X location.\n\t */\n\tpublic int x;\n\n\t/**\n\t * The Y location.\n\t */\n\tpublic int y;\n\n\tpublic Location(int x, int y) {\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t}\n\n\tpublic Location getAdjacentLocation(Direction direction) {\n\t\treturn switch (direction) {\n\t\t\tcase NORTH -> new Location(this.x, this.y - SnakeUtils.GRID_SIZE);\n\t\t\tcase SOUTH -> new Location(this.x, this.y + SnakeUtils.GRID_SIZE);\n\t\t\tcase EAST -> new Location(this.x + SnakeUtils.GRID_SIZE, this.y);\n\t\t\tcase WEST -> new Location(this.x - SnakeUtils.GRID_SIZE, this.y);\n\t\t\tcase NONE -> this;\n\t\t};\n\t}\n\n\t@Override\n\tpublic boolean equals(@Nullable Object o) {\n\t\tif (this == o) {\n\t\t\treturn true;\n\t\t}\n\t\tif (o == null || getClass() != o.getClass()) {\n\t\t\treturn false;\n\t\t}\n\t\tLocation location = (Location) o;\n\t\tif (this.x != location.x) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.y == location.y;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tint result = this.x;\n\t\tresult = 31 * result + this.y;\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/Snake.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\nimport java.util.ArrayDeque;\nimport java.util.Collection;\nimport java.util.Deque;\n\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\n\npublic class Snake {\n\n\tprivate static final int DEFAULT_LENGTH = 5;\n\n\tprivate final Deque<Location> tail = new ArrayDeque<>();\n\n\tprivate final Object monitor = new Object();\n\n\tprivate final int id;\n\n\tprivate final WebSocketSession session;\n\n\tprivate final String hexColor;\n\n\tprivate Direction direction;\n\n\tprivate int length = DEFAULT_LENGTH;\n\n\tprivate Location head;\n\n\tpublic Snake(int id, WebSocketSession session) {\n\t\tthis.id = id;\n\t\tthis.session = session;\n\t\tthis.hexColor = SnakeUtils.getRandomHexColor();\n\t\tresetState();\n\t}\n\n\tprivate void resetState() {\n\t\tthis.direction = Direction.NONE;\n\t\tthis.head = SnakeUtils.getRandomLocation();\n\t\tthis.tail.clear();\n\t\tthis.length = DEFAULT_LENGTH;\n\t}\n\n\tprivate void kill() throws Exception {\n\t\tsynchronized (this.monitor) {\n\t\t\tresetState();\n\t\t\tsendMessage(\"{'type': 'dead'}\");\n\t\t}\n\t}\n\n\tprivate void reward() throws Exception {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.length++;\n\t\t\tsendMessage(\"{'type': 'kill'}\");\n\t\t}\n\t}\n\n\tprotected void sendMessage(String msg) throws Exception {\n\t\tthis.session.sendMessage(new TextMessage(msg));\n\t}\n\n\tpublic void update(Collection<Snake> snakes) throws Exception {\n\t\tsynchronized (this.monitor) {\n\t\t\tLocation nextLocation = this.head.getAdjacentLocation(this.direction);\n\t\t\tif (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) {\n\t\t\t\tnextLocation.x = 0;\n\t\t\t}\n\t\t\tif (nextLocation.y >= SnakeUtils.PLAYFIELD_HEIGHT) {\n\t\t\t\tnextLocation.y = 0;\n\t\t\t}\n\t\t\tif (nextLocation.x < 0) {\n\t\t\t\tnextLocation.x = SnakeUtils.PLAYFIELD_WIDTH;\n\t\t\t}\n\t\t\tif (nextLocation.y < 0) {\n\t\t\t\tnextLocation.y = SnakeUtils.PLAYFIELD_HEIGHT;\n\t\t\t}\n\t\t\tif (this.direction != Direction.NONE) {\n\t\t\t\tthis.tail.addFirst(this.head);\n\t\t\t\tif (this.tail.size() > this.length) {\n\t\t\t\t\tthis.tail.removeLast();\n\t\t\t\t}\n\t\t\t\tthis.head = nextLocation;\n\t\t\t}\n\n\t\t\thandleCollisions(snakes);\n\t\t}\n\t}\n\n\tprivate void handleCollisions(Collection<Snake> snakes) throws Exception {\n\t\tfor (Snake snake : snakes) {\n\t\t\tboolean headCollision = this.id != snake.id && snake.getHead().equals(this.head);\n\t\t\tboolean tailCollision = snake.getTail().contains(this.head);\n\t\t\tif (headCollision || tailCollision) {\n\t\t\t\tkill();\n\t\t\t\tif (this.id != snake.id) {\n\t\t\t\t\tsnake.reward();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic Location getHead() {\n\t\tsynchronized (this.monitor) {\n\t\t\treturn this.head;\n\t\t}\n\t}\n\n\tpublic Collection<Location> getTail() {\n\t\tsynchronized (this.monitor) {\n\t\t\treturn this.tail;\n\t\t}\n\t}\n\n\tpublic void setDirection(Direction direction) {\n\t\tsynchronized (this.monitor) {\n\t\t\tthis.direction = direction;\n\t\t}\n\t}\n\n\tpublic String getLocationsJson() {\n\t\tsynchronized (this.monitor) {\n\t\t\tStringBuilder sb = new StringBuilder();\n\t\t\tsb.append(String.format(\"{x: %d, y: %d}\", this.head.x, this.head.y));\n\t\t\tfor (Location location : this.tail) {\n\t\t\t\tsb.append(',');\n\t\t\t\tsb.append(String.format(\"{x: %d, y: %d}\", location.x, location.y));\n\t\t\t}\n\t\t\treturn String.format(\"{'id':%d,'body':[%s]}\", this.id, sb);\n\t\t}\n\t}\n\n\tpublic int getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic String getHexColor() {\n\t\treturn this.hexColor;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/SnakeTimer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.jspecify.annotations.Nullable;\n\n/**\n * Sets up the timer for the multiplayer snake game WebSocket example.\n */\npublic final class SnakeTimer {\n\n\tprivate static final long TICK_DELAY = 100;\n\n\tprivate static final Object MONITOR = new Object();\n\n\tprivate static final Log logger = LogFactory.getLog(SnakeTimer.class);\n\n\tprivate static final ConcurrentHashMap<Integer, Snake> snakes = new ConcurrentHashMap<>();\n\n\tprivate static @Nullable Timer gameTimer;\n\n\tprivate SnakeTimer() {\n\t}\n\n\tpublic static void addSnake(Snake snake) {\n\t\tsynchronized (MONITOR) {\n\t\t\tif (snakes.isEmpty()) {\n\t\t\t\tstartTimer();\n\t\t\t}\n\t\t\tsnakes.put(snake.getId(), snake);\n\t\t}\n\t}\n\n\tpublic static Collection<Snake> getSnakes() {\n\t\treturn Collections.unmodifiableCollection(snakes.values());\n\t}\n\n\tpublic static void removeSnake(Snake snake) {\n\t\tsynchronized (MONITOR) {\n\t\t\tsnakes.remove(snake.getId());\n\t\t\tif (snakes.isEmpty()) {\n\t\t\t\tstopTimer();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void tick() throws Exception {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) {\n\t\t\tSnake snake = iterator.next();\n\t\t\tsnake.update(SnakeTimer.getSnakes());\n\t\t\tsb.append(snake.getLocationsJson());\n\t\t\tif (iterator.hasNext()) {\n\t\t\t\tsb.append(',');\n\t\t\t}\n\t\t}\n\t\tbroadcast(String.format(\"{'type': 'update', 'data' : [%s]}\", sb));\n\t}\n\n\tpublic static void broadcast(String message) {\n\t\tCollection<Snake> snakes = new CopyOnWriteArrayList<>(SnakeTimer.getSnakes());\n\t\tfor (Snake snake : snakes) {\n\t\t\ttry {\n\t\t\t\tsnake.sendMessage(message);\n\t\t\t}\n\t\t\tcatch (Throwable ex) {\n\t\t\t\t// if Snake#sendMessage fails the client is removed\n\t\t\t\tremoveSnake(snake);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void startTimer() {\n\t\tgameTimer = new Timer(SnakeTimer.class.getSimpleName() + \" Timer\");\n\t\tgameTimer.scheduleAtFixedRate(new TimerTask() {\n\t\t\t@Override\n\t\t\tpublic void run() {\n\t\t\t\ttry {\n\t\t\t\t\ttick();\n\t\t\t\t}\n\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t\tlogger.error(\"Caught to prevent timer from shutting down\", ex);\n\t\t\t\t}\n\t\t\t}\n\t\t}, TICK_DELAY, TICK_DELAY);\n\t}\n\n\tpublic static void stopTimer() {\n\t\tif (gameTimer != null) {\n\t\t\tgameTimer.cancel();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/SnakeUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\nimport java.awt.Color;\nimport java.util.Random;\n\npublic final class SnakeUtils {\n\n\t/**\n\t * The width of the playfield.\n\t */\n\tpublic static final int PLAYFIELD_WIDTH = 640;\n\n\t/**\n\t * The height of the playfield.\n\t */\n\tpublic static final int PLAYFIELD_HEIGHT = 480;\n\n\t/**\n\t * The grid size.\n\t */\n\tpublic static final int GRID_SIZE = 10;\n\n\tprivate static final Random random = new Random();\n\n\tprivate SnakeUtils() {\n\t}\n\n\tpublic static String getRandomHexColor() {\n\t\tfloat hue = random.nextFloat();\n\t\t// sat between 0.1 and 0.3\n\t\tfloat saturation = (random.nextInt(2000) + 1000) / 10000f;\n\t\tfloat luminance = 0.9f;\n\t\tColor color = Color.getHSBColor(hue, saturation, luminance);\n\t\treturn '#' + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1);\n\t}\n\n\tpublic static Location getRandomLocation() {\n\t\tint x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH));\n\t\tint y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT));\n\t\treturn new Location(x, y);\n\t}\n\n\tprivate static int roundByGridSize(int value) {\n\t\tvalue = value + (GRID_SIZE / 2);\n\t\tvalue = value / GRID_SIZE;\n\t\tvalue = value * GRID_SIZE;\n\t\treturn value;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/SnakeWebSocketHandler.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\nimport java.awt.Color;\nimport java.util.Iterator;\nimport java.util.Random;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.util.Assert;\nimport org.springframework.web.socket.CloseStatus;\nimport org.springframework.web.socket.TextMessage;\nimport org.springframework.web.socket.WebSocketSession;\nimport org.springframework.web.socket.handler.TextWebSocketHandler;\n\npublic class SnakeWebSocketHandler extends TextWebSocketHandler {\n\n\tprivate static final AtomicInteger snakeIds = new AtomicInteger();\n\n\tprivate static final Random random = new Random();\n\n\tprivate final int id;\n\n\tprivate @Nullable Snake snake;\n\n\tpublic static String getRandomHexColor() {\n\t\tfloat hue = random.nextFloat();\n\t\t// sat between 0.1 and 0.3\n\t\tfloat saturation = (random.nextInt(2000) + 1000) / 10000f;\n\t\tfloat luminance = 0.9f;\n\t\tColor color = Color.getHSBColor(hue, saturation, luminance);\n\t\treturn '#' + Integer.toHexString((color.getRGB() & 0xffffff) | 0x1000000).substring(1);\n\t}\n\n\tpublic static Location getRandomLocation() {\n\t\tint x = roundByGridSize(random.nextInt(SnakeUtils.PLAYFIELD_WIDTH));\n\t\tint y = roundByGridSize(random.nextInt(SnakeUtils.PLAYFIELD_HEIGHT));\n\t\treturn new Location(x, y);\n\t}\n\n\tprivate static int roundByGridSize(int value) {\n\t\tvalue = value + (SnakeUtils.GRID_SIZE / 2);\n\t\tvalue = value / SnakeUtils.GRID_SIZE;\n\t\tvalue = value * SnakeUtils.GRID_SIZE;\n\t\treturn value;\n\t}\n\n\tpublic SnakeWebSocketHandler() {\n\t\tthis.id = snakeIds.getAndIncrement();\n\t}\n\n\t@Override\n\tpublic void afterConnectionEstablished(WebSocketSession session) throws Exception {\n\t\tthis.snake = new Snake(this.id, session);\n\t\tSnakeTimer.addSnake(this.snake);\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (Iterator<Snake> iterator = SnakeTimer.getSnakes().iterator(); iterator.hasNext();) {\n\t\t\tSnake snake = iterator.next();\n\t\t\tsb.append(String.format(\"{id: %d, color: '%s'}\", snake.getId(), snake.getHexColor()));\n\t\t\tif (iterator.hasNext()) {\n\t\t\t\tsb.append(',');\n\t\t\t}\n\t\t}\n\t\tSnakeTimer.broadcast(String.format(\"{'type': 'join','data':[%s]}\", sb));\n\t}\n\n\t@Override\n\tprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {\n\t\tAssert.state(this.snake != null, \"'snake' must not be null\");\n\t\tString payload = message.getPayload();\n\t\tswitch (payload) {\n\t\t\tcase \"west\" -> this.snake.setDirection(Direction.WEST);\n\t\t\tcase \"north\" -> this.snake.setDirection(Direction.NORTH);\n\t\t\tcase \"east\" -> this.snake.setDirection(Direction.EAST);\n\t\t\tcase \"south\" -> this.snake.setDirection(Direction.SOUTH);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {\n\t\tAssert.state(this.snake != null, \"'snake' must not be null\");\n\t\tSnakeTimer.removeSnake(this.snake);\n\t\tSnakeTimer.broadcast(String.format(\"{'type': 'leave', 'id': %d}\", this.id));\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/java/smoketest/websocket/tomcat/snake/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.websocket.tomcat.snake;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/resources/static/echo.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html>\n<html>\n<head>\n\t<title>Apache Tomcat WebSocket Examples: Echo</title>\n\t<style type=\"text/css\">\n\t\t#connect-container {\n\t\t\tfloat: left;\n\t\t\twidth: 400px\n\t\t}\n\n\t\t#connect-container div {\n\t\t\tpadding: 5px;\n\t\t}\n\n\t\t#console-container {\n\t\t\tfloat: left;\n\t\t\tmargin-left: 15px;\n\t\t\twidth: 400px;\n\t\t}\n\n\t\t#console {\n\t\t\tborder: 1px solid #CCCCCC;\n\t\t\tborder-right-color: #999999;\n\t\t\tborder-bottom-color: #999999;\n\t\t\theight: 170px;\n\t\t\toverflow-y: scroll;\n\t\t\tpadding: 5px;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t#console p {\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t}\n\t</style>\n\t<script src=\"https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js\"></script>\n\t<script type=\"text/javascript\">\n\t\tvar ws = null;\n\n\t\tfunction setConnected(connected) {\n\t\t\tdocument.getElementById('connect').disabled = connected;\n\t\t\tdocument.getElementById('disconnect').disabled = !connected;\n\t\t\tdocument.getElementById('echo').disabled = !connected;\n\t\t}\n\n\t\tfunction connect() {\n\t\t\tvar target = document.getElementById('target').value;\n\t\t\tws = new SockJS(target);\n\t\t\tws.onopen = function () {\n\t\t\t\tsetConnected(true);\n\t\t\t\tlog('Info: WebSocket connection opened.');\n\t\t\t};\n\t\t\tws.onmessage = function (event) {\n\t\t\t\tlog('Received: ' + event.data);\n\t\t\t};\n\t\t\tws.onclose = function () {\n\t\t\t\tsetConnected(false);\n\t\t\t\tlog('Info: WebSocket connection closed.');\n\t\t\t};\n\t\t}\n\n\t\tfunction disconnect() {\n\t\t\tif (ws != null) {\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t}\n\t\t\tsetConnected(false);\n\t\t}\n\n\t\tfunction echo() {\n\t\t\tif (ws != null) {\n\t\t\t\tvar message = document.getElementById('message').value;\n\t\t\t\tlog('Sent: ' + message);\n\t\t\t\tws.send(message);\n\t\t\t} else {\n\t\t\t\talert('WebSocket connection not established, please connect.');\n\t\t\t}\n\t\t}\n\n\t\tfunction log(message) {\n\t\t\tvar console = document.getElementById('console');\n\t\t\tvar p = document.createElement('p');\n\t\t\tp.style.wordWrap = 'break-word';\n\t\t\tp.appendChild(document.createTextNode(message));\n\t\t\tconsole.appendChild(p);\n\t\t\twhile (console.childNodes.length > 25) {\n\t\t\t\tconsole.removeChild(console.firstChild);\n\t\t\t}\n\t\t\tconsole.scrollTop = console.scrollHeight;\n\t\t}\n\t</script>\n</head>\n<body>\n<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n<div>\n\t<div id=\"connect-container\">\n\t\t<div>\n\t\t\t<input id=\"target\" type=\"text\" size=\"40\" style=\"width: 350px\" value=\"/echo\"/>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"connect\" onclick=\"connect();\">Connect</button>\n\t\t\t<button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">Disconnect</button>\n\t\t</div>\n\t\t<div>\n\t\t\t<textarea id=\"message\" style=\"width: 350px\">Here is a message!</textarea>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"echo\" onclick=\"echo();\" disabled=\"disabled\">Echo message</button>\n\t\t</div>\n\t</div>\n\t<div id=\"console-container\">\n\t\t<div id=\"console\"></div>\n\t</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/resources/static/index.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html>\n<html>\n<head>\n\t<title>Apache Tomcat WebSocket Examples: Index</title>\n</head>\n<body>\n<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n<p>Please select the sample you would like to try.</p>\n<ul>\n\t<li><a href=\"./echo.html\">Echo</a></li>\n\t<li><a href=\"./reverse.html\">Reverse</a></li>\n\t<li><a href=\"./snake.html\">Snake</a></li>\n</ul>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/resources/static/reverse.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html>\n<html>\n<head>\n\t<title>WebSocket Examples: Reverse</title>\n\t<style type=\"text/css\">\n\t\t#connect-container {\n\t\t\tfloat: left;\n\t\t\twidth: 400px\n\t\t}\n\n\t\t#connect-container div {\n\t\t\tpadding: 5px;\n\t\t}\n\n\t\t#console-container {\n\t\t\tfloat: left;\n\t\t\tmargin-left: 15px;\n\t\t\twidth: 400px;\n\t\t}\n\n\t\t#console {\n\t\t\tborder: 1px solid #CCCCCC;\n\t\t\tborder-right-color: #999999;\n\t\t\tborder-bottom-color: #999999;\n\t\t\theight: 170px;\n\t\t\toverflow-y: scroll;\n\t\t\tpadding: 5px;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t#console p {\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t}\n\t</style>\n\t<script type=\"text/javascript\">\n\t\tvar ws = null;\n\n\t\tfunction setConnected(connected) {\n\t\t\tdocument.getElementById('connect').disabled = connected;\n\t\t\tdocument.getElementById('disconnect').disabled = !connected;\n\t\t\tdocument.getElementById('reverse').disabled = !connected;\n\t\t}\n\n\t\tfunction connect() {\n\t\t\tvar target = document.getElementById('target').value;\n\t\t\tws = new WebSocket(target);\n\t\t\tws.onopen = function () {\n\t\t\t\tsetConnected(true);\n\t\t\t\tlog('Info: WebSocket connection opened.');\n\t\t\t};\n\t\t\tws.onmessage = function (event) {\n\t\t\t\tlog('Received: ' + event.data);\n\t\t\t};\n\t\t\tws.onclose = function () {\n\t\t\t\tsetConnected(false);\n\t\t\t\tlog('Info: WebSocket connection closed.');\n\t\t\t};\n\t\t}\n\n\t\tfunction updateTarget() {\n\t\t\tif (window.location.protocol == 'http:') {\n\t\t\t\tdocument.getElementById('target').value = 'ws://' + window.location.host + document.getElementById('target').value;\n\t\t\t} else {\n\t\t\t\tdocument.getElementById('target').value = 'wss://' + window.location.host + document.getElementById('target').value;\n\t\t\t}\n\t\t}\n\n\t\tfunction disconnect() {\n\t\t\tif (ws != null) {\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t}\n\t\t\tsetConnected(false);\n\t\t}\n\n\t\tfunction reverse() {\n\t\t\tif (ws != null) {\n\t\t\t\tvar message = document.getElementById('message').value;\n\t\t\t\tlog('Sent: ' + message);\n\t\t\t\tws.send(message);\n\t\t\t} else {\n\t\t\t\talert('WebSocket connection not established, please connect.');\n\t\t\t}\n\t\t}\n\n\t\tfunction log(message) {\n\t\t\tvar console = document.getElementById('console');\n\t\t\tvar p = document.createElement('p');\n\t\t\tp.style.wordWrap = 'break-word';\n\t\t\tp.appendChild(document.createTextNode(message));\n\t\t\tconsole.appendChild(p);\n\t\t\twhile (console.childNodes.length > 25) {\n\t\t\t\tconsole.removeChild(console.firstChild);\n\t\t\t}\n\t\t\tconsole.scrollTop = console.scrollHeight;\n\t\t}\n\t</script>\n</head>\n<body onload=\"updateTarget()\">\n<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n<div>\n\t<div id=\"connect-container\">\n\t\t<div>\n\t\t\t<input id=\"target\" type=\"text\" size=\"40\" style=\"width: 350px\" value=\"/reverse\"/>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"connect\" onclick=\"connect();\">Connect</button>\n\t\t\t<button id=\"disconnect\" disabled=\"disabled\" onclick=\"disconnect();\">Disconnect</button>\n\t\t</div>\n\t\t<div>\n\t\t\t<textarea id=\"message\" style=\"width: 350px\">Here is a message!</textarea>\n\t\t</div>\n\t\t<div>\n\t\t\t<button id=\"reverse\" onclick=\"reverse();\" disabled=\"disabled\">Reverse message</button>\n\t\t</div>\n\t</div>\n\t<div id=\"console-container\">\n\t\t<div id=\"console\"></div>\n\t</div>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/main/resources/static/snake.html",
    "content": "<!--\nLicensed to the Apache Software Foundation (ASF) under one or more\ncontributor license agreements.  See the NOTICE file distributed with\nthis work for additional information regarding copyright ownership.\nThe ASF licenses this file to You under the Apache License, Version 2.0\n(the \"License\"); you may not use this file except in compliance with\nthe License.  You may obtain a copy of the License at\n\n\t  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n\t\t\"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n<head>\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n\t<title>Apache Tomcat WebSocket Examples: Multiplayer Snake</title>\n\t<style type=\"text/css\">\n\t\t#playground {\n\t\t\twidth: 640px;\n\t\t\theight: 480px;\n\t\t\tbackground-color: #000;\n\t\t}\n\n\t\t#console-container {\n\t\t\tfloat: left;\n\t\t\tmargin-left: 15px;\n\t\t\twidth: 300px;\n\t\t}\n\n\t\t#console {\n\t\t\tborder: 1px solid #CCCCCC;\n\t\t\tborder-right-color: #999999;\n\t\t\tborder-bottom-color: #999999;\n\t\t\theight: 480px;\n\t\t\toverflow-y: scroll;\n\t\t\tpadding-left: 5px;\n\t\t\tpadding-right: 5px;\n\t\t\twidth: 100%;\n\t\t}\n\n\t\t#console p {\n\t\t\tpadding: 0;\n\t\t\tmargin: 0;\n\t\t}\n\t</style>\n\t<script src=\"https://cdn.jsdelivr.net/sockjs/0.3.4/sockjs.min.js\"></script>\n</head>\n<body>\n\t<noscript><h2 style=\"color: #ff0000\">Seems your browser doesn't support Javascript! Websockets rely on Javascript being enabled. Please enable\n\tJavascript and reload this page!</h2></noscript>\n\n\t<div style=\"float: left\">\n\t\t<canvas id=\"playground\" width=\"640\" height=\"480\"></canvas>\n\t</div>\n\t<div id=\"console-container\">\n\t\t<div id=\"console\"></div>\n\t</div>\n\t<script type=\"text/javascript\">\n\n\t\tvar Game = {};\n\n\t\tGame.fps = 30;\n\t\tGame.socket = null;\n\t\tGame.nextFrame = null;\n\t\tGame.interval = null;\n\t\tGame.direction = 'none';\n\t\tGame.gridSize = 10;\n\n\t\tfunction Snake() {\n\t\t\tthis.snakeBody = [];\n\t\t\tthis.color = null;\n\t\t}\n\n\t\tSnake.prototype.draw = function(context) {\n\t\t\tfor (var id in this.snakeBody) {\n\t\t\t\tcontext.fillStyle = this.color;\n\t\t\t\tcontext.fillRect(this.snakeBody[id].x, this.snakeBody[id].y, Game.gridSize, Game.gridSize);\n\t\t\t}\n\t\t};\n\n\t\tGame.initialize = function() {\n\t\t\tthis.entities = [];\n\t\t\tcanvas = document.getElementById('playground');\n\t\t\tif (!canvas.getContext) {\n\t\t\t\tConsole.log('Error: 2d canvas not supported by this browser.');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.context = canvas.getContext('2d');\n\t\t\twindow.addEventListener('keydown', function (e) {\n\t\t\t\tvar code = e.keyCode;\n\t\t\t\tif (code > 36 && code < 41) {\n\t\t\t\t\tswitch (code) {\n\t\t\t\t\t\tcase 37:\n\t\t\t\t\t\t\tif (Game.direction != 'east') Game.setDirection('west');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 38:\n\t\t\t\t\t\t\tif (Game.direction != 'south') Game.setDirection('north');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 39:\n\t\t\t\t\t\t\tif (Game.direction != 'west') Game.setDirection('east');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 40:\n\t\t\t\t\t\t\tif (Game.direction != 'north') Game.setDirection('south');\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, false);\n\t\t\tGame.connect();\n\t\t};\n\n\t\tGame.setDirection  = function(direction) {\n\t\t\tGame.direction = direction;\n\t\t\tGame.socket.send(direction);\n\t\t\tConsole.log('Sent: Direction ' + direction);\n\t\t};\n\n\t\tGame.startGameLoop = function() {\n\t\t\tif (window.webkitRequestAnimationFrame) {\n\t\t\t\tGame.nextFrame = function () {\n\t\t\t\t\twebkitRequestAnimationFrame(Game.run);\n\t\t\t\t};\n\t\t\t} else if (window.mozRequestAnimationFrame) {\n\t\t\t\tGame.nextFrame = function () {\n\t\t\t\t\tmozRequestAnimationFrame(Game.run);\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tGame.interval = setInterval(Game.run, 1000 / Game.fps);\n\t\t\t}\n\t\t\tif (Game.nextFrame != null) {\n\t\t\t\tGame.nextFrame();\n\t\t\t}\n\t\t};\n\n\t\tGame.stopGameLoop = function () {\n\t\t\tGame.nextFrame = null;\n\t\t\tif (Game.interval != null) {\n\t\t\t\tclearInterval(Game.interval);\n\t\t\t}\n\t\t};\n\n\t\tGame.draw = function() {\n\t\t\tthis.context.clearRect(0, 0, 640, 480);\n\t\t\tfor (var id in this.entities) {\n\t\t\t\tthis.entities[id].draw(this.context);\n\t\t\t}\n\t\t};\n\n\t\tGame.addSnake = function(id, color) {\n\t\t\tGame.entities[id] = new Snake();\n\t\t\tGame.entities[id].color = color;\n\t\t};\n\n\t\tGame.updateSnake = function(id, snakeBody) {\n\t\t\tif (typeof Game.entities[id] != \"undefined\") {\n\t\t\t\tGame.entities[id].snakeBody = snakeBody;\n\t\t\t}\n\t\t};\n\n\t\tGame.removeSnake = function(id) {\n\t\t\tGame.entities[id] = null;\n\t\t\t// Force GC.\n\t\t\tdelete Game.entities[id];\n\t\t};\n\n\t\tGame.run = (function() {\n\t\t\tvar skipTicks = 1000 / Game.fps, nextGameTick = (new Date).getTime();\n\n\t\t\treturn function() {\n\t\t\t\twhile ((new Date).getTime() > nextGameTick) {\n\t\t\t\t\tnextGameTick += skipTicks;\n\t\t\t\t}\n\t\t\t\tGame.draw();\n\t\t\t\tif (Game.nextFrame != null) {\n\t\t\t\t\tGame.nextFrame();\n\t\t\t\t}\n\t\t\t};\n\t\t})();\n\n\t\tGame.connect = (function() {\n\t\t\tGame.socket = new SockJS(\"/snake\");\n\n\t\t\tGame.socket.onopen = function () {\n\t\t\t\t// Socket open.. start the game loop.\n\t\t\t\tConsole.log('Info: WebSocket connection opened.');\n\t\t\t\tConsole.log('Info: Press an arrow key to begin.');\n\t\t\t\tGame.startGameLoop();\n\t\t\t\tsetInterval(function() {\n\t\t\t\t\t// Prevent server read timeout.\n\t\t\t\t\tGame.socket.send('ping');\n\t\t\t\t}, 5000);\n\t\t\t};\n\n\t\t\tGame.socket.onclose = function () {\n\t\t\t\tConsole.log('Info: WebSocket closed.');\n\t\t\t\tGame.stopGameLoop();\n\t\t\t};\n\n\t\t\tGame.socket.onmessage = function (message) {\n\t\t\t\t// _Potential_ security hole, consider using json lib to parse data in production.\n\t\t\t\tvar packet = eval('(' + message.data + ')');\n\t\t\t\tswitch (packet.type) {\n\t\t\t\t\tcase 'update':\n\t\t\t\t\t\tfor (var i = 0; i < packet.data.length; i++) {\n\t\t\t\t\t\t\tGame.updateSnake(packet.data[i].id, packet.data[i].body);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'join':\n\t\t\t\t\t\tfor (var j = 0; j < packet.data.length; j++) {\n\t\t\t\t\t\t\tGame.addSnake(packet.data[j].id, packet.data[j].color);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'leave':\n\t\t\t\t\t\tGame.removeSnake(packet.id);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'dead':\n\t\t\t\t\t\tConsole.log('Info: Your snake is dead, bad luck!');\n\t\t\t\t\t\tGame.direction = 'none';\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'kill':\n\t\t\t\t\t\tConsole.log('Info: Head shot!');\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\n\t\tvar Console = {};\n\n\t\tConsole.log = (function(message) {\n\t\t\tvar console = document.getElementById('console');\n\t\t\tvar p = document.createElement('p');\n\t\t\tp.style.wordWrap = 'break-word';\n\t\t\tp.innerHTML = message;\n\t\t\tconsole.appendChild(p);\n\t\t\twhile (console.childNodes.length > 25) {\n\t\t\t\tconsole.removeChild(console.firstChild);\n\t\t\t}\n\t\t\tconsole.scrollTop = console.scrollHeight;\n\t\t});\n\n\t\tGame.initialize();\n\t</script>\n</body>\n</html>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/test/java/smoketest/websocket/tomcat/SampleWebSocketsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.junit.jupiter.api.Test;\nimport smoketest.websocket.tomcat.client.GreetingService;\nimport smoketest.websocket.tomcat.client.SimpleClientWebSocketHandler;\nimport smoketest.websocket.tomcat.client.SimpleGreetingService;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.client.WebSocketConnectionManager;\nimport org.springframework.web.socket.client.standard.StandardWebSocketClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(classes = SampleTomcatWebSocketApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)\nclass SampleWebSocketsApplicationTests {\n\n\tprivate static final Log logger = LogFactory.getLog(SampleWebSocketsApplicationTests.class);\n\n\t@LocalServerPort\n\tprivate int port = 1234;\n\n\t@Test\n\tvoid echoEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/echo/websocket\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Did you say \\\"Hello world!\\\"?\");\n\t}\n\n\t@Test\n\tvoid reverseEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/reverse\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Reversed: !dlrow olleH\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientConfiguration implements CommandLineRunner {\n\n\t\t@Value(\"${websocket.uri}\")\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String webSocketUri;\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate final AtomicReference<String> messagePayload = new AtomicReference<>();\n\n\t\t@Override\n\t\tpublic void run(String... args) throws Exception {\n\t\t\tlogger.info(\"Waiting for response: latch=\" + this.latch.getCount());\n\t\t\tif (this.latch.await(10, TimeUnit.SECONDS)) {\n\t\t\t\tlogger.info(\"Got response: \" + this.messagePayload.get());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Response not received: latch=\" + this.latch.getCount());\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tWebSocketConnectionManager wsConnectionManager() {\n\t\t\tWebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri);\n\t\t\tmanager.setAutoStartup(true);\n\t\t\treturn manager;\n\t\t}\n\n\t\t@Bean\n\t\tStandardWebSocketClient client() {\n\t\t\treturn new StandardWebSocketClient();\n\t\t}\n\n\t\t@Bean\n\t\tSimpleClientWebSocketHandler handler() {\n\t\t\treturn new SimpleClientWebSocketHandler(greetingService(), this.latch, this.messagePayload);\n\t\t}\n\n\t\t@Bean\n\t\tGreetingService greetingService() {\n\t\t\treturn new SimpleGreetingService();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/test/java/smoketest/websocket/tomcat/echo/CustomContainerWebSocketsApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.echo;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.junit.jupiter.api.Test;\nimport smoketest.websocket.tomcat.SampleTomcatWebSocketApplication;\nimport smoketest.websocket.tomcat.client.GreetingService;\nimport smoketest.websocket.tomcat.client.SimpleClientWebSocketHandler;\nimport smoketest.websocket.tomcat.client.SimpleGreetingService;\nimport smoketest.websocket.tomcat.echo.CustomContainerWebSocketsApplicationTests.CustomContainerConfiguration;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.context.SpringBootTest.WebEnvironment;\nimport org.springframework.boot.test.web.server.LocalServerPort;\nimport org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;\nimport org.springframework.boot.web.server.servlet.ServletWebServerFactory;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.socket.client.WebSocketConnectionManager;\nimport org.springframework.web.socket.client.standard.StandardWebSocketClient;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@SpringBootTest(classes = { SampleTomcatWebSocketApplication.class, CustomContainerConfiguration.class },\n\t\twebEnvironment = WebEnvironment.RANDOM_PORT)\nclass CustomContainerWebSocketsApplicationTests {\n\n\tprivate static final Log logger = LogFactory.getLog(CustomContainerWebSocketsApplicationTests.class);\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Test\n\tvoid echoEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/ws/echo/websocket\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Did you say \\\"Hello world!\\\"?\");\n\t}\n\n\t@Test\n\tvoid reverseEndpoint() {\n\t\tConfigurableApplicationContext context = new SpringApplicationBuilder(ClientConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class)\n\t\t\t.properties(\"websocket.uri:ws://localhost:\" + this.port + \"/ws/reverse\")\n\t\t\t.run(\"--spring.main.web-application-type=none\");\n\t\tlong count = context.getBean(ClientConfiguration.class).latch.getCount();\n\t\tAtomicReference<String> messagePayloadReference = context.getBean(ClientConfiguration.class).messagePayload;\n\t\tcontext.close();\n\t\tassertThat(count).isZero();\n\t\tassertThat(messagePayloadReference.get()).isEqualTo(\"Reversed: !dlrow olleH\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tprotected static class CustomContainerConfiguration {\n\n\t\t@Bean\n\t\tpublic ServletWebServerFactory webServerFactory() {\n\t\t\treturn new TomcatServletWebServerFactory(\"/ws\", 0);\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class ClientConfiguration implements CommandLineRunner {\n\n\t\t@Value(\"${websocket.uri}\")\n\t\t@SuppressWarnings(\"NullAway.Init\")\n\t\tprivate String webSocketUri;\n\n\t\tprivate final CountDownLatch latch = new CountDownLatch(1);\n\n\t\tprivate final AtomicReference<String> messagePayload = new AtomicReference<>();\n\n\t\t@Override\n\t\tpublic void run(String... args) throws Exception {\n\t\t\tlogger.info(\"Waiting for response: latch=\" + this.latch.getCount());\n\t\t\tif (this.latch.await(10, TimeUnit.SECONDS)) {\n\t\t\t\tlogger.info(\"Got response: \" + this.messagePayload.get());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.info(\"Response not received: latch=\" + this.latch.getCount());\n\t\t\t}\n\t\t}\n\n\t\t@Bean\n\t\tWebSocketConnectionManager wsConnectionManager() {\n\n\t\t\tWebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), this.webSocketUri);\n\t\t\tmanager.setAutoStartup(true);\n\n\t\t\treturn manager;\n\t\t}\n\n\t\t@Bean\n\t\tStandardWebSocketClient client() {\n\t\t\treturn new StandardWebSocketClient();\n\t\t}\n\n\t\t@Bean\n\t\tSimpleClientWebSocketHandler handler() {\n\t\t\treturn new SimpleClientWebSocketHandler(greetingService(), this.latch, this.messagePayload);\n\t\t}\n\n\t\t@Bean\n\t\tGreetingService greetingService() {\n\t\t\treturn new SimpleGreetingService();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-websocket-tomcat/src/test/java/smoketest/websocket/tomcat/snake/SnakeTimerTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.websocket.tomcat.snake;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.BDDMockito.willThrow;\nimport static org.mockito.Mockito.mock;\n\nclass SnakeTimerTests {\n\n\t@Test\n\tvoid removeDysfunctionalSnakes() throws Exception {\n\t\tSnake snake = mock(Snake.class);\n\t\twillThrow(new IOException()).given(snake).sendMessage(anyString());\n\t\tSnakeTimer.addSnake(snake);\n\t\tSnakeTimer.broadcast(\"\");\n\t\tassertThat(SnakeTimer.getSnakes()).isEmpty();\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java\"\n}\n\ndescription = \"Spring Boot XML smoke test\"\n\ndependencies {\n\timplementation(project(\":starter:spring-boot-starter\"))\n\n\ttestImplementation(project(\":starter:spring-boot-starter-test\"))\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/main/java/smoketest/xml/SampleSpringXmlApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.xml;\n\nimport java.util.Collections;\n\nimport smoketest.xml.service.HelloWorldService;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SampleSpringXmlApplication implements CommandLineRunner {\n\n\tprivate static final String CONTEXT_XML = \"classpath:/META-INF/application-context.xml\";\n\n\t@Autowired\n\tprivate HelloWorldService helloWorldService;\n\n\t@Override\n\tpublic void run(String... args) {\n\t\tSystem.out.println(this.helloWorldService.getHelloMessage());\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication application = new SpringApplication();\n\t\tapplication.setSources(Collections.singleton(CONTEXT_XML));\n\t\tapplication.run(args);\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/main/java/smoketest/xml/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.xml;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/main/java/smoketest/xml/service/HelloWorldService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.xml.service;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class HelloWorldService {\n\n\t@Value(\"${test.name:World}\")\n\t@SuppressWarnings(\"NullAway.Init\")\n\tprivate String name;\n\n\tpublic String getHelloMessage() {\n\t\treturn \"Hello \" + this.name;\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/main/java/smoketest/xml/service/OtherService.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.xml.service;\n\npublic class OtherService {\n\n\tpublic String getMessage() {\n\t\treturn \"Hello Other World\";\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/main/java/smoketest/xml/service/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage smoketest.xml.service;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/main/resources/META-INF/application-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\n\t\t\t\thttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\n\t<context:annotation-config/>\n\t<context:property-placeholder/>\n\n\t<bean id=\"helloService\" class=\"smoketest.xml.service.HelloWorldService\"/>\n\t<bean id=\"application\" class=\"smoketest.xml.SampleSpringXmlApplication\"/>\n\n</beans>\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/test/java/smoketest/xml/SampleSpringXmlApplicationTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.xml;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleSpringXmlApplicationTests {\n\n\t@Test\n\tvoid testDefaultSettings(CapturedOutput output) {\n\t\tSampleSpringXmlApplication.main(new String[0]);\n\t\tassertThat(output).contains(\"Hello World\");\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/test/java/smoketest/xml/SampleSpringXmlPlaceholderBeanDefinitionTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage smoketest.xml;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport smoketest.xml.service.OtherService;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.ImportResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for XML config with placeholders in bean definitions.\n *\n * @author Madhura Bhave\n */\n@SpringBootTest(\n\t\tclasses = { SampleSpringXmlApplication.class, SampleSpringXmlPlaceholderBeanDefinitionTests.TestConfig.class })\n@ExtendWith(OutputCaptureExtension.class)\nclass SampleSpringXmlPlaceholderBeanDefinitionTests {\n\n\t@Test\n\tvoid beanWithPlaceholderShouldNotFail(CapturedOutput output) {\n\t\tassertThat(output).contains(\"Hello Other World\");\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@ImportResource({ \"classpath:/META-INF/context.xml\" })\n\tstatic class TestConfig {\n\n\t\t@Bean\n\t\tCommandLineRunner testCommandLineRunner(OtherService service) {\n\t\t\treturn (args) -> System.out.println(service.getMessage());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/test/resources/META-INF/context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd\n\t\t\t\thttp://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd\">\n\n\t<context:annotation-config/>\n\t<context:property-placeholder/>\n\n\t<bean id=\"otherService\" class=\"${bean.name}\"/>\n\n</beans>"
  },
  {
    "path": "smoke-test/spring-boot-smoke-test-xml/src/test/resources/application.properties",
    "content": "bean.name=smoketest.xml.service.OtherService\n"
  },
  {
    "path": "starter/README.adoc",
    "content": "= Starters\n\nSpring Boot Starters are a set of convenient dependency descriptors that you can include\nin your application. You get a one-stop-shop for all the Spring and related technology\nthat you need without having to hunt through sample code and copy paste loads of\ndependency descriptors. For example, if you want to get started using Spring and\nJPA for database access include the `spring-boot-starter-data-jpa` dependency in\nyour project, and you are good to go.\n\nFor complete details see the\nhttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter[reference documentation]\n\n== Community Contributions\n\nIf you create a starter for a technology that is not already in the standard list we can\nlist it here. To ask us to do so, please open a pull request that updates this page.\n\nWARNING: While the\nhttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#using-boot-starter[reference documentation]\nmentions that 3rd party starters should not start with `spring-boot`, some starters\ndo as they were designed before this was clarified.\n\n|===\n| Name | Location\n\n| AOProfiling (Aspect-oriented profiling)\n| https://github.com/rechnerherz/aoprofiling-spring-boot-starter\n\n| https://camel.apache.org/camel-spring-boot/latest/spring-boot.html[Apache Camel]\n| https://github.com/apache/camel-spring-boot\n\n| https://cxf.apache.org/docs/springboot.html[Apache CXF]\n| https://github.com/apache/cxf\n\n| https://qpid.apache.org/components/jms/[Apache Qpid]\n| https://github.com/amqphub/amqp-10-jms-spring-boot\n\n| https://wicket.apache.org/[Apache Wicket]\n| https://github.com/MarcGiffing/wicket-spring-boot\n\n| https://arangodb.com/[ArangoDB]\n| https://github.com/arangodb/spring-boot-starter\n\n| https://line.github.io/armeria/[Armeria]\n| https://github.com/line/armeria/\n\n| https://axoniq.io[Axon Framework]\n| https://github.com/AxonFramework/AxonFramework\n\n| https://azure.microsoft.com/[Azure]\n| https://github.com/Microsoft/azure-spring-boot-starters\n\n| https://github.com/bitcoin/bitcoin[Bitcoin]\n| https://github.com/theborakompanioni/bitcoin-spring-boot-starter\n\n| https://github.com/vladimir-bukhtoyarov/bucket4j/[Bucket4j]\n| https://github.com/MarcGiffing/bucket4j-spring-boot-starter\n\n| https://camunda.org/[Camunda BPM]\n| https://github.com/camunda/camunda-bpm-spring-boot-starter\n\n| https://casdoor.org/[Casdoor]\n| https://github.com/casdoor/casdoor-spring-boot-starter\n\n| Charon reverse proxy\n| https://github.com/mkopylec/charon-spring-boot-starter\n\n| https://cloudant.com/[Cloudant]\n| https://github.com/icha024/cloudant-spring-boot-starter\n\n| https://www.couchbase.com/[Couchbase] HTTP session\n| https://github.com/mkopylec/session-couchbase-spring-boot-starter\n\n| https://dapr.io[Dapr]\n| https://github.com/dapr/java-sdk/\n\n| DataSource decorating (https://github.com/p6spy/p6spy[P6Spy], https://github.com/ttddyy/datasource-proxy[datasource-proxy], https://github.com/vladmihalcea/flexy-pool[FlexyPool])\n| https://github.com/gavlyukovskiy/spring-boot-data-source-decorator\n\n| https://github.com/Allurx/desensitization[desensitization]\n| https://github.com/Allurx/desensitization-spring-boot\n\n| https://github.com/docker-java/docker-java/[Docker Java] and https://github.com/spotify/docker-client/[Docker Client]\n| https://github.com/jliu666/docker-api-spring-boot\n\n| https://dozermapper.github.io/[Dozer]\n| https://github.com/DozerMapper/dozer\n\n| Elegant Error Handling for Spring Boot\n| https://github.com/alimate/errors-spring-boot-starter\n\n| https://elide.io/[Elide]\n| https://github.com/yahoo/elide/tree/master/elide-spring/elide-spring-boot-starter\n\n| https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo[Embedded MongoDB]\n| https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo.spring\n\n| ErroREST exception handler\n| https://github.com/mkopylec/errorest-spring-boot-starter\n\n| Error Handling Spring Boot Starter\n| https://github.com/wimdeblauwe/error-handling-spring-boot-starter\n\n| https://societe-generale.github.io/failover/[Failover]\n| https://github.com/societe-generale/failover\n\n| https://www.flowable.org/[Flowable]\n| https://github.com/flowable/flowable-engine/tree/master/modules/flowable-spring-boot/flowable-spring-boot-starters\n\n| https://www.google.com/recaptcha[Google's reCAPTCHA]\n| https://github.com/mkopylec/recaptcha-spring-boot-starter\n\n| https://graphql.org/[GraphQL] and https://github.com/graphql/graphiql[GraphiQL] with https://github.com/graphql-java/[GraphQL Java]\n| https://github.com/graphql-java-kickstart/graphql-spring-boot\n\n| https://javaee.github.io/grizzly/[Grizzly]\n| https://github.com/dabla/grizzly-spring-boot-starter\n\n| https://www.grpc.io/[gRPC]\n| https://github.com/LogNet/grpc-spring-boot-starter & https://github.com/yidongnan/grpc-spring-boot-starter & https://github.com/DanielLiu1123/grpc-starter\n\n| https://ha-jdbc.github.io/[HA JDBC]\n| https://github.com/lievendoclo/hajdbc-spring-boot\n\n| https://github.com/jknack/handlebars.java[Handlebars]\n| https://github.com/allegro/handlebars-spring-boot-starter\n\n| https://hdiv.org/[HDIV]\n| https://github.com/hdiv/spring-boot-starter-hdiv\n\n| Hiatus for Spring Boot\n| https://github.com/jihor/hiatus-spring-boot\n\n| https://www.hyperledger.org/use/fabric[Hyperledger Fabric]\n| https://github.com/bxforce/hyperledger-fabric-spring-boot\n\n| https://www.ibm.com/products/mq[IBM MQ]\n| https://github.com/ibm-messaging/mq-jms-spring\n\n| https://github.com/neuland/jade4j[Jade Templates] (Jade4J)\n| https://github.com/domix/jade4j-spring-boot-starter\n\n| https://github.com/javamelody/javamelody/wiki[JavaMelody] monitoring\n| https://github.com/javamelody/javamelody/wiki/SpringBootStarter\n\n| https://javers.org[JaVers]\n| https://github.com/javers/javers\n\n| https://www.jobrunr.io[JobRunr]\n| https://github.com/jobrunr/jobrunr\n\n| https://github.com/sbraconnier/jodconverter[JODConverter]\n| https://github.com/sbraconnier/jodconverter\n\n| JSF integration for various libraries\n| https://github.com/joinfaces/joinfaces\n\n| https://kogito.kie.org/[Kogito]\n| https://github.com/kiegroup/kogito-runtimes/tree/main/springboot/starters\n\n| https://github.com/langchain4j/langchain4j[LangChain for Java]\n| https://github.com/langchain4j/langchain4j/tree/main/langchain4j-spring-boot-starter\n\n| https://www.liquigraph.org/[Liquigraph]\n| https://github.com/liquigraph/liquigraph\n\n| https://logback.qos.ch/access.html[Logback-access]\n| https://github.com/akkinoc/logback-access-spring-boot-starter\n\n| https://github.com/dmitrysulman/logback-access-reactor-netty[Logback-access Reactor Netty]\n| https://github.com/dmitrysulman/logback-access-reactor-netty\n\n| https://github.com/mulesoft/mule[Mule 4]\n| https://github.com/hawkore/mule4-spring-boot-starter\n\n| https://github.com/mybatis/mybatis-3[MyBatis]\n| https://github.com/mybatis/mybatis-spring-boot\n\n| https://github.com/jbosstm/narayana[Narayana]\n| https://github.com/snowdrop/narayana-spring-boot\n\n| https://developer.nexmo.com/[Nexmo]\n| https://github.com/nexmo/nexmo-spring-boot-starter\n\n| https://github.com/nostr-protocol/nostr[Nostr]\n| https://github.com/theborakompanioni/nostr-spring-boot-starter\n\n| https://github.com/nutzam/nutz[Nutz]\n| https://github.com/nutzam/nutzmore\n\n| https://groupe-sii.github.io/ogham/[Ogham]\n| https://github.com/groupe-sii/ogham/tree/master/ogham-spring-boot-starter-all, https://github.com/groupe-sii/ogham/tree/master/ogham-spring-boot-starter-email, and https://github.com/groupe-sii/ogham/tree/master/ogham-spring-boot-starter-sms\n\n| https://square.github.io/okhttp/[OkHttp]\n| https://github.com/freefair/okhttp-spring-boot\n\n| https://developer.okta.com/[Okta]\n| https://github.com/okta/okta-spring-boot\n\n| https://opentelemetry.io/docs/languages/java/automatic/spring-boot/#opentelemetry-spring-boot-starter[OpenTelemetry]\n| https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/spring/starters/spring-boot-starter\n\n| https://www.optaplanner.org/[OptaPlanner]\n| https://github.com/kiegroup/optaplanner/tree/master/optaplanner-spring-integration/optaplanner-spring-boot-starter\n\n| https://spring.coherence.community/3.0.0/refdocs/reference/html/spring-boot.html[Oracle Coherence]\n| https://github.com/coherence-community/coherence-spring/tree/main/coherence-spring-boot-starter\n\n| https://www.oracle.com/database/[Oracle Database]\n| https://github.com/oracle/microservices-datadriven/tree/main/spring/oracle-spring-boot-starters\n\n| https://orika-mapper.github.io/orika-docs/[Orika]\n| https://github.com/akihyro/orika-spring-boot-starter\n\n| https://pebbletemplates.io/[Pebble Templates]\n| https://github.com/PebbleTemplates/pebble\n\n| https://picocli.info/[picocli]\n| https://github.com/remkop/picocli/tree/master/picocli-spring-boot-starter\n\n| https://www.quickfixj.org/[quickfixj]\n| https://github.com/gevoulga/spring-boot-quickfixj\n\n| https://www.rabbitmq.com/[RabbitMQ] (Advanced usage)\n| https://github.com/societe-generale/rabbitmq-advanced-spring-boot-starter\n\n| https://www.rabbitmq.com/[RabbitMQ] (Declarative configuration)\n| https://github.com/EugeneMsv/amqp-rabbit-spring-boot-autoconfigure\n\n| https://resteasy.jboss.org/[RESTEasy]\n| https://github.com/resteasy/resteasy-spring-boot\n\n| https://github.com/rollbar/rollbar-java/[Rollbar]\n| https://github.com/olmero/rollbar-spring-boot-starter\n\n| https://sentry.io[Sentry]\n| https://github.com/getsentry/sentry-java/tree/master/sentry-spring-boot-starter\n\n| SOAP Web Services support with Apache CXF\n| https://github.com/codecentric/cxf-spring-boot-starter\n\n| https://projects.spring.io/spring-batch/[Spring Batch] (Advanced usage)\n| https://github.com/codecentric/spring-boot-starter-batch-web\n\n| https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-http-service-client[Spring Http Service Client]\n| https://github.com/DanielLiu1123/httpexchange-spring-boot-starter\n\n| https://projects.spring.io/spring-shell/[Spring Shell]\n| https://github.com/fonimus/ssh-shell-spring-boot\n\n| https://github.com/savantly-net/sprout-platform[Sprout Platform]\n| https://github.com/savantly-net/sprout-platform/tree/master/backend/starters/sprout-spring-boot-starter\n\n| SSH Daemon\n| https://github.com/anand1st/sshd-shell-spring-boot\n\n| https://github.com/stripe/stripe-java[Stripe API]\n| https://github.com/pankajtandon/stripe-starter\n\n| https://github.com/StripesFramework/stripes[Stripes]\n| https://github.com/juanpablo-santos/stripes-spring-boot\n\n| https://github.com/structurizr/java[Structurizr]\n| https://github.com/Catalysts/structurizr-extensions\n\n| https://docs.styra.com/das/systems/springboot/[Styra DAS] (https://www.openpolicyagent.org/[OPA])\n| https://github.com/styrainc/opa-springboot\n\n| https://www.torproject.org/[Tor]\n| https://github.com/theborakompanioni/tor-spring-boot-starter\n\n| https://vaadin.com/[Vaadin]\n| https://github.com/vaadin/platform/tree/master/vaadin-spring-boot-starter\n\n| https://github.com/valiktor/valiktor[Valiktor]\n| https://github.com/valiktor/valiktor/tree/master/valiktor-spring/valiktor-spring-boot-starter\n\n| https://github.com/Yubico/java-webauthn-server[WebAuthn]\n| https://github.com/mihaita-tinta/webauthn-spring-boot-starter\n\n| https://github.com/tomakehurst/wiremock[WireMock] and Spring REST Docs\n| https://github.com/ePages-de/restdocs-wiremock\n\n| https://alexo.github.io/wro4j/[Wro4j]\n| https://github.com/michael-simons/wro4j-spring-boot-starter\n\n| https://github.com/knowm/XChange[XChange]\n| https://github.com/cassandre-tech/cassandre-trading-bot\n\n|===\n"
  },
  {
    "path": "starter/spring-boot-starter/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Core starter, including auto-configuration support, logging and YAML\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-logging\"))\n\n\tapi(project(\":core:spring-boot-autoconfigure\"))\n\n\tapi(\"jakarta.annotation:jakarta.annotation-api\")\n\tapi(\"org.yaml:snakeyaml\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-activemq/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Apache ActiveMQ and JMS\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-activemq\"))\n\tapi(project(\":module:spring-boot-jms\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-activemq-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing using Apache ActiveMQ and JMS\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-activemq\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-actuator/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Boot's Actuator which provides production ready features to help you monitor and manage your application\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-micrometer-metrics\"))\n\n\tapi(project(\":module:spring-boot-actuator-autoconfigure\"))\n\tapi(project(\":module:spring-boot-health\"))\n\n\tapi(\"io.micrometer:micrometer-observation\")\n\tapi(\"io.micrometer:micrometer-jakarta9\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-actuator-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Boot's Actuator which provides production ready features to help you monitor and manage your application\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-actuator\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-micrometer-metrics-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-amqp/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring AMQP and Rabbit MQ\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-amqp\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-amqp-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring AMQP and Rabbit MQ\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-amqp\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(\"org.springframework.amqp:spring-rabbit-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-artemis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Apache Artemis and JMS\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-artemis\"))\n\tapi(project(\":module:spring-boot-jms\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-artemis-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Apache Artemis and JMS\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-artemis\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-aspectj/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using aspect-oriented programming with AspectJ\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(\"org.springframework:spring-aop\")\n\tapi(\"org.aspectj:aspectjweaver\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-aspectj-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing aspect-oriented programming with AspectJ\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-aspectj\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-batch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Batch\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-batch\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-batch-data-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Batch with Data MongoDB\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-batch\"))\n\tapi(project(\":starter:spring-boot-starter-data-mongodb\"))\n\n\tapi(project(\":module:spring-boot-batch-data-mongodb\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-batch-data-mongodb-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing using Spring Batch with Data MongoDB\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-batch-test\"))\n\tapi(project(\":starter:spring-boot-starter-data-mongodb-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-batch-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Batch with JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-batch\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-batch-jdbc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-batch-jdbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing using Spring Batch with JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-batch-test\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-batch-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing using Spring Batch\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-batch\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(\"org.springframework.batch:spring-batch-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-cache/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring's caching support\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-cache\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-cache-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring's caching support\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-cache\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-cache-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-cassandra/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Cassandra distributed database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-cassandra\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-cassandra-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Cassandra distributed database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-cassandra\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-classic/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Core classic starter, including full auto-configuration support, logging and YAML\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-autoconfigure-classic\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-cloudfoundry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Cloud Foundry\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-cloudfoundry\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-cloudfoundry-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Cloud Foundry\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-cloudfoundry\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-couchbase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Couchbase document-oriented database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-couchbase\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-couchbase-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Couchbase document-oriented database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-couchbase\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-cassandra/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Cassandra distributed database and Spring Data Cassandra\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-cassandra\"))\n\tapi(project(\":module:spring-boot-data-cassandra\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-cassandra-reactive/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Cassandra distributed database and Spring Data Cassandra Reactive\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-cassandra\"))\n\tapi(project(\":module:spring-boot-data-cassandra\"))\n\tapi(project(\":module:spring-boot-reactor\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-cassandra-reactive-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Cassandra distributed database and Spring Data Cassandra Reactive\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-cassandra-reactive\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-cassandra-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-cassandra-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Cassandra distributed database and Spring Data Cassandra\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-cassandra\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-cassandra-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-couchbase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Couchbase document-oriented database and Spring Data Couchbase\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-couchbase\"))\n\tapi(project(\":module:spring-boot-data-couchbase\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-couchbase-reactive/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-couchbase\"))\n\tapi(project(\":module:spring-boot-data-couchbase\"))\n\tapi(project(\":module:spring-boot-reactor\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-couchbase-reactive-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Couchbase document-oriented database and Spring Data Couchbase Reactive\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-couchbase-reactive\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-couchbase-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-couchbase-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Couchbase document-oriented database and Spring Data Couchbase\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-couchbase\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-couchbase-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-elasticsearch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-data-elasticsearch\"))\n\tapi(project(\":module:spring-boot-elasticsearch\"))\n\n\truntimeOnly(project(\":starter:spring-boot-starter-jackson\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-elasticsearch-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Elasticsearch search and analytics engine and Spring Data Elasticsearch\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-elasticsearch\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-elasticsearch-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Data JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-data-jdbc\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-jdbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Data JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-jdbc\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n\n\tapi(project(\":module:spring-boot-data-jdbc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-jpa/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Data JPA with Hibernate\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-data-jpa\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-jpa-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Data JPA with Hibernate\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-jpa\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n\n\tapi(project(\":module:spring-boot-data-jpa-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-ldap/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Data LDAP\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-data-ldap\"))\n\tapi(project(\":module:spring-boot-ldap\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-ldap-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Data LDAP\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-ldap\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-ldap-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using MongoDB document-oriented database and Spring Data MongoDB\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-mongodb\"))\n\n\tapi(project(\":module:spring-boot-data-mongodb\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-mongodb-reactive/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-mongodb\"))\n\n\tapi(project(\":module:spring-boot-data-mongodb\"))\n\tapi(project(\":module:spring-boot-reactor\"))\n\n\tapi(\"org.mongodb:mongodb-driver-reactivestreams\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-mongodb-reactive-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-mongodb-reactive\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-mongodb-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-mongodb-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing MongoDB document-oriented database and Spring Data MongoDB\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-mongodb\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-mongodb-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-neo4j/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Neo4j graph database and Spring Data Neo4j\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-data-neo4j\"))\n\tapi(project(\":module:spring-boot-neo4j\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-neo4j-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Neo4j graph database and Spring Data Neo4j\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-neo4j\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-neo4j-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-r2dbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Data R2DBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-data-r2dbc\"))\n\tapi(project(\":module:spring-boot-r2dbc\"))\n\tapi(project(\":module:spring-boot-reactor\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-r2dbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Data R2DBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-r2dbc\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-r2dbc-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-redis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-data-redis\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-redis-reactive/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-data-redis\"))\n\tapi(project(\":module:spring-boot-reactor\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-redis-reactive-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Redis key-value data store with Spring Data Redis reactive and the Lettuce client\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-redis-reactive\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-redis-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-redis-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Redis key-value data store with Spring Data Redis and the Lettuce client\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-redis\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-data-redis-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-rest/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Data repositories exposed over REST using Spring Data REST and Spring MVC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\n\tapi(project(\":module:spring-boot-data-rest\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-data-rest-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Data repositories exposed over REST using Spring Data REST and Spring MVC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-data-rest\"))\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-elasticsearch/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Elasticsearch search and analytics engine\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-elasticsearch\"))\n\tapi(\"co.elastic.clients:elasticsearch-java\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-elasticsearch-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Elasticsearch search and analytics engine\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-elasticsearch\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-flyway/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Flyway database migrations\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-flyway\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-flyway-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Flyway database migrations\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-flyway\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-freemarker/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using FreeMarker\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-freemarker\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-freemarker-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing FreeMarker\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-freemarker\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-graphql/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter using Spring GraphQL\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\n\tapi(project(\":module:spring-boot-reactor\"))\n\tapi(project(\":module:spring-boot-graphql\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-graphql-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring GraphQL\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-graphql\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\n\tapi(project(\":module:spring-boot-graphql-test\"))\n\tapi(project(\":module:spring-boot-webtestclient\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-groovy-templates/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Groovy Templates\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-groovy-templates\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-groovy-templates-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Groovy Templates\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-groovy-templates\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-grpc-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring gRPC client\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":module:spring-boot-grpc-client\"))\n\tapi(\"io.grpc:grpc-netty\")\n\tapi(\"io.grpc:grpc-stub\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-grpc-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring gRPC server\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":module:spring-boot-grpc-server\"))\n\tapi(\"io.grpc:grpc-netty\")\n\tapi(\"io.grpc:grpc-services\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-grpc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing gRPC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-grpc-test\"))\n\tapi(\"io.grpc:grpc-inprocess\")\n\tapi(\"io.grpc:grpc-stub\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-gson/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using GSON\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-gson\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-gson-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing GSON\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-gson\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-hateoas/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring HATEOS to build hypermedia-based RESTful Spring MVC web applications\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-hateoas\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-hateoas-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring HATEOS to build hypermedia-based RESTful Spring MVC web applications\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-hateoas\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-hazelcast/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Hazelcast\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-hazelcast\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-hazelcast-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Hazelcast\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-hazelcast\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-integration/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Integration\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-integration\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-integration-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Integration\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-integration\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(\"org.springframework.integration:spring-integration-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jackson/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Jackson\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-jackson\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jackson-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Jackson\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using JDBC with the HikariCP connection pool\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-jdbc\"))\n\n\tapi(\"com.zaxxer:HikariCP\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jdbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing JDBC with the HikariCP connection pool\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-jdbc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jersey/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using JAX-RS and Jersey\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-tomcat\"))\n\tapi(project(\":starter:spring-boot-starter-validation\"))\n\n\tapi(project(\":module:spring-boot-jackson2\"))\n\tapi(project(\":module:spring-boot-jersey\"))\n\n\tapi(\"org.glassfish.jersey.ext:jersey-bean-validation\") {\n\t\texclude group: \"jakarta.el\", module: \"jakarta.el-api\"\n\t}\n\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name.startsWith(\"org/aopalliance/intercept/\") }\n\tignore { name -> name.startsWith(\"org/aopalliance/aop/\") }\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jersey-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing JAX-RS and Jersey\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jersey\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":module:spring-boot-resttestclient\"))\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name.startsWith(\"org/aopalliance/intercept/\") }\n\tignore { name -> name.startsWith(\"org/aopalliance/aop/\") }\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jetty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Jetty as the embedded servlet container\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jetty-runtime\"))\n\n\tapi(project(\":module:spring-boot-jetty\"))\n\n\tapi(\"org.slf4j:slf4j-api\")\n\tapi(\"jakarta.annotation:jakarta.annotation-api\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jetty-runtime/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for the Jetty runtime\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-jetty\")) {\n \t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-web-server\")) {\n \t\ttransitive = false\n\t}\n\tapi(\"jakarta.servlet:jakarta.servlet-api\")\n\tapi(\"jakarta.websocket:jakarta.websocket-api\")\n\tapi(\"jakarta.websocket:jakarta.websocket-client-api\")\n\tapi(\"org.apache.tomcat.embed:tomcat-embed-el\")\n\tapi(\"org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jakarta-server\") {\n\t\texclude group: \"jakarta.el\",  module: \"jakarta.el-api\"\n\t\texclude group: \"org.eclipse.jetty\", module: \"jetty-jndi\"\n\t\texclude group: \"org.slf4j\", module: \"slf4j-api\"\n\t\texclude group: \"jakarta.annotation\", module: \"jakarta.annotation-api\"\n\t}\n\tapi(\"org.eclipse.jetty.ee11.websocket:jetty-ee11-websocket-jetty-server\") {\n\t\texclude group: \"jakarta.el\",  module: \"jakarta.el-api\"\n\t\texclude group: \"org.eclipse.jetty\", module: \"jetty-jndi\"\n\t\texclude group: \"org.slf4j\", module: \"slf4j-api\"\n\t}\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jms/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using JMS\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-jms\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jms-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing JMS\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jms\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jooq/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using jOOQ to access SQL databases with JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-jooq\"))\n\tapi(project(\":module:spring-boot-jdbc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jooq-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing jOOQ to access SQL databases with JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jooq\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n\n\tapi(project(\":module:spring-boot-jooq-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-json/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for reading and writing JSON\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-jackson\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jsonb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using JSON-B\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-jsonb\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-jsonb-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing JSON-B\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jsonb\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-kafka/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Apache Kafka\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-kafka\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-kafka-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Apache Kafka\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-kafka\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(\"org.springframework.kafka:spring-kafka-test\")\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name == \"NOTICE\" ||\n\t\t\t\tname.equals(\"kafka/kafka-version.properties\") ||\n\t\t\t\tname.equals(\"log4j2.yaml\")\n\t}\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-kotlinx-serialization-json/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Kotlinx Serialization JSON\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-kotlinx-serialization-json\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-kotlinx-serialization-json-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Kotlinx Serialization JSON\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-kotlinx-serialization-json\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-ldap/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using LDAP\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-ldap\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-ldap-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing LDAP\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-ldap\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-liquibase/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Liquibase database migrations\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(project(\":module:spring-boot-liquibase\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-liquibase-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Liquibase database migrations\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-liquibase\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-log4j2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Log4j2\"\n\ndependencies {\n\tapi(\"org.apache.logging.log4j:log4j-slf4j2-impl\")\n\tapi(\"org.apache.logging.log4j:log4j-core\")\n\tapi(\"org.apache.logging.log4j:log4j-jul\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-logback/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for logging using Logback\"\n\ndependencies {\n\tapi(\"ch.qos.logback:logback-classic\")\n\tapi(\"org.apache.logging.log4j:log4j-to-slf4j\")\n\tapi(\"org.slf4j:jul-to-slf4j\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-logging/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for logging default logging\"\n\ndependencies {\n\tapi(\"ch.qos.logback:logback-classic\")\n\tapi(\"org.apache.logging.log4j:log4j-to-slf4j\")\n\tapi(\"org.slf4j:jul-to-slf4j\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-mail/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Java Mail and Spring Framework's email sending support\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-mail\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-mail-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Java Mail and Spring Framework's email sending support\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-mail\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-micrometer-metrics/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Micrometer Metrics\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-micrometer-metrics\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-micrometer-metrics-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Micrometer Metrics\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-micrometer-metrics\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-micrometer-metrics-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-mongodb/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using MongoDB document-oriented database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-mongodb\"))\n\n\tapi(\"org.mongodb:mongodb-driver-sync\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-mongodb-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing MongoDB document-oriented database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-mongodb\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-mustache/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Mustache\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-mustache\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-mustache-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Mustache\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-mustache\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-neo4j/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Neo4j graph database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-neo4j\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-neo4j-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Neo4j graph database\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-neo4j\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-oauth2-authorization-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Authorization Server features (deprecated in favor of spring-boot-starter-security-oauth2-authorization-server)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-security-oauth2-authorization-server\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-oauth2-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Security's OAuth2/OpenID Connect client features (deprecated in favor of spring-boot-starter-security-oauth2-client)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\n\tapi(project(\":module:spring-boot-security-oauth2-client\"))\n\n\tapi(\"org.springframework.security:spring-security-oauth2-jose\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-oauth2-resource-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Security's OAuth2 resource server features (deprecated in favor of spring-boot-starter-security-oauth2-resource-server)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\n\tapi(project(\":module:spring-boot-security-oauth2-resource-server\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-opentelemetry/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using OpenTelemetry\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-micrometer-metrics\"))\n\tapi(project(\":module:spring-boot-micrometer-tracing-opentelemetry\"))\n\tapi(project(\":module:spring-boot-opentelemetry\"))\n\n\truntimeOnly 'io.micrometer:micrometer-registry-otlp'\n\truntimeOnly('io.micrometer:micrometer-tracing-bridge-otel') {\n\t\texclude(group: \"aopalliance\", module: \"aopalliance\")\n\t}\n\truntimeOnly 'io.opentelemetry:opentelemetry-exporter-otlp'\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-opentelemetry-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing OpenTelemetry\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-opentelemetry\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-micrometer-metrics-test\"))\n\n\tapi(project(\":module:spring-boot-micrometer-tracing-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-parent/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.deployed\"\n\tid \"org.springframework.boot.maven-repository\"\n}\n\ndescription = \"Parent pom providing dependency and plugin management for applications built with Maven\"\n\npublishing.publications.withType(MavenPublication) {\n\tpom.withXml { xml ->\n\t\tdef root = xml.asNode()\n\t\troot.groupId.replaceNode {\n\t\t\tparent {\n\t\t\t\tdelegate.groupId(\"${project.group}\")\n\t\t\t\tdelegate.artifactId(\"spring-boot-dependencies\")\n\t\t\t\tdelegate.version(\"${project.version}\")\n\t\t\t}\n\t\t}\n\t\troot.remove(root.version)\n\t\troot.description.plus {\n\t\t\tproperties {\n\t\t\t\tdelegate.\"java.version\"('17')\n\t\t\t\tdelegate.\"resource.delimiter\"('@')\n\t\t\t\tdelegate.\"maven.compiler.release\"('${java.version}')\n\t\t\t\tdelegate.\"project.build.sourceEncoding\"('UTF-8')\n\t\t\t\tdelegate.\"project.reporting.outputEncoding\"('UTF-8')\n\t\t\t\tdelegate.\"spring-boot.run.main-class\"('${start-class}')\n\t\t\t}\n\t\t}\n\t\troot.scm.plus {\n\t\t\tbuild {\n\t\t\t\tresources {\n\t\t\t\t\tresource {\n\t\t\t\t\t\tdelegate.directory('${basedir}/src/main/resources')\n\t\t\t\t\t\tdelegate.filtering('true')\n\t\t\t\t\t\tincludes {\n\t\t\t\t\t\t\tdelegate.include('**/application*.yml')\n\t\t\t\t\t\t\tdelegate.include('**/application*.yaml')\n\t\t\t\t\t\t\tdelegate.include('**/application*.properties')\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tresource {\n\t\t\t\t\t\tdelegate.directory('${basedir}/src/main/resources')\n\t\t\t\t\t\texcludes {\n\t\t\t\t\t\t\tdelegate.exclude('**/application*.yml')\n\t\t\t\t\t\t\tdelegate.exclude('**/application*.yaml')\n\t\t\t\t\t\t\tdelegate.exclude('**/application*.properties')\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tpluginManagement {\n\t\t\t\t\tplugins {\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('io.github.ascopes')\n\t\t\t\t\t\t\tdelegate.artifactId('protobuf-maven-plugin')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.protoc('${protobuf-java.version}')\n\t\t\t\t\t\t\t\tplugins {\n\t\t\t\t\t\t\t\t\tplugin(kind: 'binary-maven') {\n\t\t\t\t\t\t\t\t\t\tdelegate.groupId('io.grpc')\n\t\t\t\t\t\t\t\t\t\tdelegate.artifactId('protoc-gen-grpc-java')\n\t\t\t\t\t\t\t\t\t\tdelegate.version('${grpc-java.version}')\n\t\t\t\t\t\t\t\t\t\tdelegate.options('@generated=omit')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tdelegate.id('generate')\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('generate')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.jetbrains.kotlin')\n\t\t\t\t\t\t\tdelegate.artifactId('kotlin-maven-plugin')\n\t\t\t\t\t\t\tdelegate.version('${kotlin.version}')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.jvmTarget('${java.version}')\n\t\t\t\t\t\t\t\tdelegate.javaParameters('true')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tdelegate.id('compile')\n\t\t\t\t\t\t\t\t\tdelegate.phase('compile')\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('compile')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tdelegate.id('test-compile')\n\t\t\t\t\t\t\t\t\tdelegate.phase('test-compile')\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('test-compile')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\tdelegate.artifactId('maven-compiler-plugin')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.parameters('true')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\tdelegate.artifactId('maven-failsafe-plugin')\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('integration-test')\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('verify')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.classesDirectory('${project.build.outputDirectory}')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\tdelegate.artifactId('maven-jar-plugin')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tarchive {\n\t\t\t\t\t\t\t\t\tmanifest {\n\t\t\t\t\t\t\t\t\t\tdelegate.mainClass('${start-class}')\n\t\t\t\t\t\t\t\t\t\tdelegate.addDefaultImplementationEntries('true')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\tdelegate.artifactId('maven-war-plugin')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tarchive {\n\t\t\t\t\t\t\t\t\tmanifest {\n\t\t\t\t\t\t\t\t\t\tdelegate.mainClass('${start-class}')\n\t\t\t\t\t\t\t\t\t\tdelegate.addDefaultImplementationEntries('true')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\tdelegate.artifactId('maven-resources-plugin')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.propertiesEncoding('${project.build.sourceEncoding}')\n\t\t\t\t\t\t\t\tdelimiters {\n\t\t\t\t\t\t\t\t\tdelegate.delimiter('${resource.delimiter}')\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tdelegate.useDefaultDelimiters('false')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.graalvm.buildtools')\n\t\t\t\t\t\t\tdelegate.artifactId('native-maven-plugin')\n\t\t\t\t\t\t\tdelegate.extensions('true')\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('io.github.git-commit-id')\n\t\t\t\t\t\t\tdelegate.artifactId('git-commit-id-maven-plugin')\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('revision')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.verbose('true')\n\t\t\t\t\t\t\t\tdelegate.generateGitPropertiesFile('true')\n\t\t\t\t\t\t\t\tdelegate.generateGitPropertiesFilename('${project.build.outputDirectory}/git.properties')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.cyclonedx')\n\t\t\t\t\t\t\tdelegate.artifactId('cyclonedx-maven-plugin')\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tdelegate.phase('generate-resources')\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('makeAggregateBom')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\t\t\tdelegate.projectType('application')\n\t\t\t\t\t\t\t\t\t\tdelegate.outputDirectory('${project.build.outputDirectory}/META-INF/sbom')\n\t\t\t\t\t\t\t\t\t\tdelegate.outputFormat('json')\n\t\t\t\t\t\t\t\t\t\tdelegate.outputName('application.cdx')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.springframework.boot')\n\t\t\t\t\t\t\tdelegate.artifactId('spring-boot-maven-plugin')\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tdelegate.id('repackage')\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('repackage')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.mainClass('${spring-boot.run.main-class}')\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\tdelegate.artifactId('maven-shade-plugin')\n\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\tdelegate.keepDependenciesWithProvidedScope('true')\n\t\t\t\t\t\t\t\tdelegate.createDependencyReducedPom('true')\n\t\t\t\t\t\t\t\tfilters {\n\t\t\t\t\t\t\t\t\tfilter {\n\t\t\t\t\t\t\t\t\t\tdelegate.artifact('*:*')\n\t\t\t\t\t\t\t\t\t\texcludes {\n\t\t\t\t\t\t\t\t\t\t\tdelegate.exclude('META-INF/*.SF')\n\t\t\t\t\t\t\t\t\t\t\tdelegate.exclude('META-INF/*.DSA')\n\t\t\t\t\t\t\t\t\t\t\tdelegate.exclude('META-INF/*.RSA')\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdelegate.dependencies {\n\t\t\t\t\t\t\t\tdependency {\n\t\t\t\t\t\t\t\t\tdelegate.groupId('org.springframework.boot')\n\t\t\t\t\t\t\t\t\tdelegate.artifactId('spring-boot-maven-plugin')\n\t\t\t\t\t\t\t\t\tdelegate.version(\"${project.version}\")\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\tdelegate.phase('package')\n\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\tdelegate.goal('shade')\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\t\t\ttransformers {\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.apache.maven.plugins.shade.resource.AppendingTransformer') {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.resource('META-INF/spring.handlers')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.apache.maven.plugins.shade.resource.AppendingTransformer') {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.resource('META-INF/spring.schemas')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.apache.maven.plugins.shade.resource.AppendingTransformer') {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.resource('META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.apache.maven.plugins.shade.resource.AppendingTransformer') {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.resource('META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.springframework.boot.maven.PropertiesMergingResourceTransformer') {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.resource('META-INF/spring.factories')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.apache.maven.plugins.shade.resource.ServicesResourceTransformer')\n\t\t\t\t\t\t\t\t\t\t\ttransformer(implementation: 'org.apache.maven.plugins.shade.resource.ManifestResourceTransformer') {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.mainClass('${start-class}')\n\t\t\t\t\t\t\t\t\t\t\t\tmanifestEntries {\n\t\t\t\t\t\t\t\t\t\t\t\t\tdelegate.'Multi-Release'('true')\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tprofiles {\n\t\t\t\tprofile {\n\t\t\t\t\tdelegate.id(\"native\")\n\t\t\t\t\tbuild {\n\t\t\t\t\t\tpluginManagement {\n\t\t\t\t\t\t\tplugins {\n\t\t\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\t\t\tdelegate.groupId('org.apache.maven.plugins')\n\t\t\t\t\t\t\t\t\tdelegate.artifactId('maven-jar-plugin')\n\t\t\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\t\t\tarchive {\n\t\t\t\t\t\t\t\t\t\t\tmanifestEntries {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.'Spring-Boot-Native-Processed'(\"true\")\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\t\t\tdelegate.groupId('org.springframework.boot')\n\t\t\t\t\t\t\t\t\tdelegate.artifactId('spring-boot-maven-plugin')\n\t\t\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\t\t\tdelegate.id('process-aot')\n\t\t\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.goal('process-aot')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\t\t\tdelegate.groupId('org.graalvm.buildtools')\n\t\t\t\t\t\t\t\t\tdelegate.artifactId('native-maven-plugin')\n\t\t\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\t\t\tdelegate.classesDirectory('${project.build.outputDirectory}')\n\t\t\t\t\t\t\t\t\t\texclusions {\n\t\t\t\t\t\t\t\t\t\t\texclusion {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.groupId('org.springframework.boot')\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.artifactId('spring-boot-devtools')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\t\t\tdelegate.id('add-reachability-metadata')\n\t\t\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.goal('add-reachability-metadata')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tprofile {\n\t\t\t\t\tdelegate.id(\"nativeTest\")\n\t\t\t\t\tdelegate.dependencies {\n\t\t\t\t\t\tdependency {\n\t\t\t\t\t\t\tdelegate.groupId('org.junit.platform')\n\t\t\t\t\t\t\tdelegate.artifactId('junit-platform-launcher')\n\t\t\t\t\t\t\tdelegate.scope('test')\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbuild {\n\t\t\t\t\t\tpluginManagement {\n\t\t\t\t\t\t\tplugins {\n\t\t\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\t\t\tdelegate.groupId('org.springframework.boot')\n\t\t\t\t\t\t\t\t\tdelegate.artifactId('spring-boot-maven-plugin')\n\t\t\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\t\t\tdelegate.id('process-test-aot')\n\t\t\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.goal('process-test-aot')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tplugin {\n\t\t\t\t\t\t\t\t\tdelegate.groupId('org.graalvm.buildtools')\n\t\t\t\t\t\t\t\t\tdelegate.artifactId('native-maven-plugin')\n\t\t\t\t\t\t\t\t\tconfiguration {\n\t\t\t\t\t\t\t\t\t\tdelegate.classesDirectory('${project.build.outputDirectory}')\n\t\t\t\t\t\t\t\t\t\texclusions {\n\t\t\t\t\t\t\t\t\t\t\texclusion {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.groupId('org.springframework.boot')\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.artifactId('spring-boot-devtools')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\texecutions {\n\t\t\t\t\t\t\t\t\t\texecution {\n\t\t\t\t\t\t\t\t\t\t\tdelegate.id('native-test')\n\t\t\t\t\t\t\t\t\t\t\tgoals {\n\t\t\t\t\t\t\t\t\t\t\t\tdelegate.goal('test')\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-pulsar/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring for Apache Pulsar\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-pulsar\"))\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name.startsWith(\"org/bouncycastle/\") ||\n\t\t\t\tname.matches(\"^org/apache/pulsar/.*/package-info.class\\$\") ||\n\t\t\t\tname.equals(\"findbugsExclude.xml\") }\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-pulsar-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring for Apache Pulsar\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-pulsar\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name.startsWith(\"org/bouncycastle/\") ||\n\t\t\t\tname.matches(\"^org/apache/pulsar/.*/package-info.class\\$\") ||\n\t\t\t\tname.equals(\"findbugsExclude.xml\") }\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-quartz/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using the Quartz scheduler\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-quartz\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-quartz-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing the Quartz scheduler\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-quartz\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-r2dbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using R2DBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-r2dbc\"))\n\tapi(project(\":module:spring-boot-reactor\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-r2dbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing R2DBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-r2dbc\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-reactor-netty/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for Reactor Netty\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-reactor\"))\n\tapi(project(\":module:spring-boot-reactor-netty\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-restclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter using Spring's blocking HTTP clients (RestClient, RestTemplate and HTTP Service Clients)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\n\tapi(project(\":module:spring-boot-restclient\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-restclient-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring's blocking HTTP clients (RestClient, RestTemplate and HTTP Service Clients)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-restclient\"))\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-restclient-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-restdocs/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring REST Docs\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-restdocs\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-rsocket/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using RSocket\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\tapi(project(\":starter:spring-boot-starter-reactor-netty\"))\n\n\tapi(project(\":module:spring-boot-reactor\"))\n\tapi(project(\":module:spring-boot-rsocket\"))\n\n\tapi(\"io.rsocket:rsocket-transport-netty\")\n\tapi(\"org.springframework:spring-web\")\n\tapi(\"tools.jackson.dataformat:jackson-dataformat-cbor\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-rsocket-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing RSocket\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-rsocket\"))\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-rsocket-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Security\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-security\"))\n\n\tapi(\"org.springframework:spring-aop\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-oauth2-authorization-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Authorization Server features\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-security-oauth2-authorization-server\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-oauth2-authorization-server-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Authorization Server features\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-security-oauth2-authorization-server\"))\n\tapi(project(\":starter:spring-boot-starter-security-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-oauth2-client/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Security's OAuth2/OpenID Connect client features\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\n\tapi(project(\":module:spring-boot-security-oauth2-client\"))\n\n\tapi(\"org.springframework.security:spring-security-oauth2-jose\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-oauth2-client-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Security's OAuth2/OpenID Connect client features\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-security-oauth2-client\"))\n\tapi(project(\":starter:spring-boot-starter-security-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-oauth2-resource-server/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Security's OAuth2 resource server features\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\n\tapi(project(\":module:spring-boot-security-oauth2-resource-server\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-oauth2-resource-server-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Security's OAuth2 resource server features\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-security-oauth2-resource-server\"))\n\tapi(project(\":starter:spring-boot-starter-security-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-saml2/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Security with SAML2\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\n\tapi(project(\":module:spring-boot-security-saml2\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-saml2-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Security with SAML2\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-security-saml2\"))\n\tapi(project(\":starter:spring-boot-starter-security-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-security-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Security\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-security\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-security-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-sendgrid/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Session with Sendgrid\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-sendgrid\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-sendgrid-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Session with Sendgrid\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-sendgrid\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-session-data-redis/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Session with Spring Data Redis\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-data-redis\"))\n\n\tapi(project(\":module:spring-boot-data-redis\"))\n\tapi(project(\":module:spring-boot-session-data-redis\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-session-data-redis-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Session with Spring Data Redis\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-session-data-redis\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-session-jdbc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Session with JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc\"))\n\n\tapi(project(\":module:spring-boot-jdbc\"))\n\tapi(project(\":module:spring-boot-session-jdbc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-session-jdbc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Session with JDBC\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-session-jdbc\"))\n\tapi(project(\":starter:spring-boot-starter-jdbc-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":core:spring-boot-test\"))\n\n\tapi(project(\":core:spring-boot-test-autoconfigure\"))\n\n\tapi(\"com.jayway.jsonpath:json-path\")\n\tapi(\"jakarta.xml.bind:jakarta.xml.bind-api\")\n\tapi(\"net.minidev:json-smart\")\n\tapi(\"org.assertj:assertj-core\")\n\tapi(\"org.awaitility:awaitility\")\n\tapi(\"org.hamcrest:hamcrest\")\n\tapi(\"org.junit.jupiter:junit-jupiter\")\n\tapi(\"org.mockito:mockito-core\")\n\tapi(\"org.mockito:mockito-junit-jupiter\")\n\tapi(\"org.skyscreamer:jsonassert\")\n\tapi(\"org.springframework:spring-core\")\n\tapi(\"org.springframework:spring-test\")\n\tapi(\"org.xmlunit:xmlunit-core\")\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name.startsWith(\"mockito-extensions/\") }\n}\n\n"
  },
  {
    "path": "starter/spring-boot-starter-test-classic/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Classic starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-test-classic-modules\"))\n}\n\ncheckRuntimeClasspathForConflicts {\n\tignore { name -> name.startsWith(\"mockito-extensions/\") }\n}\n\n"
  },
  {
    "path": "starter/spring-boot-starter-thymeleaf/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Thymeleaf\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-thymeleaf\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-thymeleaf-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Thymeleaf\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-thymeleaf\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-tomcat/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Tomcat as the embedded servlet container\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-tomcat-runtime\"))\n\n\tapi(project(\":module:spring-boot-tomcat\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-tomcat-runtime/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for the Tomcat runtime\"\n\ndependencies {\n\tapi(project(\":module:spring-boot-tomcat\")) {\n \t\ttransitive = false\n\t}\n\tapi(project(\":module:spring-boot-web-server\")) {\n \t\ttransitive = false\n\t}\n\tapi(\"jakarta.annotation:jakarta.annotation-api\")\n\tapi(\"org.apache.tomcat.embed:tomcat-embed-core\") {\n\t\texclude group: \"org.apache.tomcat\", module: \"tomcat-annotations-api\"\n\t}\n\tapi(\"org.apache.tomcat.embed:tomcat-embed-el\")\n\tapi(\"org.apache.tomcat.embed:tomcat-embed-websocket\") {\n\t\texclude group: \"org.apache.tomcat\", module: \"tomcat-annotations-api\"\n\t}\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-validation/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Java Bean Validation with Hibernate Validator\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-validation\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-validation-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Java Bean Validation with Hibernate Validator\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-validation\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-web/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container (deprecated in favor of spring-boot-starter-webmvc)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\tapi(project(\":starter:spring-boot-starter-tomcat\"))\n\n\tapi(project(\":module:spring-boot-http-converter\"))\n\tapi(project(\":module:spring-boot-webmvc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-web-server-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Web Server\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":module:spring-boot-web-server-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-web-services/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Web Services (deprecated in favor of spring-boot-starter-webservices)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-webservices\"))\n\n\tapi(\"com.sun.xml.messaging.saaj:saaj-impl\")\n\tapi(\"jakarta.xml.ws:jakarta.xml.ws-api\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webclient/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter using Spring's reactive HTTP clients (WebClient and HTTP Service Clients)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\n\tapi(project(\":module:spring-boot-reactor\"))\n\tapi(project(\":module:spring-boot-webclient\"))\n\n\tapi(\"io.projectreactor.netty:reactor-netty-http\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webclient-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring's reactive HTTP clients (WebClient and HTTP Service Clients)\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webclient\"))\n\n\tapi(project(\":module:spring-boot-webclient-test\"))\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webflux/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using WebFlux and Reactor Netty\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\tapi(project(\":starter:spring-boot-starter-reactor-netty\"))\n\n\tapi(project(\":module:spring-boot-reactor\"))\n\tapi(project(\":module:spring-boot-webflux\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webflux-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing WebFlux and Reactor Netty\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webflux\"))\n\n\tapi(project(\":module:spring-boot-webflux-test\"))\n\tapi(project(\":module:spring-boot-webtestclient\"))\n\n\tapi(\"io.projectreactor:reactor-test\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webmvc/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring MVC and Tomcat\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-jackson\"))\n\tapi(project(\":starter:spring-boot-starter-tomcat\"))\n\n\tapi(project(\":module:spring-boot-http-converter\"))\n\tapi(project(\":module:spring-boot-webmvc\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webmvc-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring MVC and Tomcat\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-jackson-test\"))\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-webmvc-test\"))\n\tapi(project(\":module:spring-boot-resttestclient\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webservices/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring Web Services\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-webservices\"))\n\n\tapi(\"com.sun.xml.messaging.saaj:saaj-impl\")\n\tapi(\"jakarta.xml.ws:jakarta.xml.ws-api\")\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-webservices-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring Web Services\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc-test\"))\n\tapi(project(\":starter:spring-boot-starter-webservices\"))\n\n\tapi(project(\":module:spring-boot-webservices-test\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-websocket/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Spring MVC WebSocket support\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc\"))\n\n\tapi(project(\":module:spring-boot-websocket\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-websocket-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Spring MVC WebSocket support\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\tapi(project(\":starter:spring-boot-starter-webmvc-test\"))\n\tapi(project(\":starter:spring-boot-starter-websocket\"))\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-zipkin/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for using Zipkin\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter\"))\n\n\tapi(project(\":module:spring-boot-micrometer-tracing-brave\"))\n\tapi(project(\":module:spring-boot-zipkin\"))\n\n\truntimeOnly(\"io.micrometer:micrometer-tracing-bridge-brave\") {\n\t\texclude(group: \"aopalliance\", module: \"aopalliance\")\n\t}\n}\n"
  },
  {
    "path": "starter/spring-boot-starter-zipkin-test/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"org.springframework.boot.starter\"\n}\n\ndescription = \"Starter for testing Zipkin\"\n\ndependencies {\n\tapi(project(\":starter:spring-boot-starter-test\"))\n\n\tapi(project(\":starter:spring-boot-starter-zipkin\"))\n\n\tapi(project(\":module:spring-boot-micrometer-tracing-test\"))\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"war\"\n\tid \"org.springframework.boot.system-test\"\n}\n\ndescription = \"Spring Boot Deployment Tests\"\n\nconfigurations {\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\nconfigurations.all {\n\texclude module: \"spring-boot-starter-logging\"\n}\n\ndependencies {\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude group: \"org.hibernate.validator\"\n\t\texclude group: \"org.springframework.boot\", module: \"spring-boot-starter-tomcat\"\n\t}\n\timplementation(project(\":starter:spring-boot-starter-actuator\"))\n\n\tsystemTestImplementation(enforcedPlatform(project(path: \":platform:spring-boot-internal-dependencies\")))\n\tsystemTestImplementation(project(\":module:spring-boot-restclient\"))\n\tsystemTestImplementation(project(\":module:spring-boot-resttestclient\"))\n\tsystemTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tsystemTestImplementation(project(\":test-support:spring-boot-test-support\"))\n\tsystemTestImplementation(\"org.apache.httpcomponents.client5:httpclient5\")\n\tsystemTestImplementation(\"org.slf4j:slf4j-simple\")\n\tsystemTestImplementation(\"org.springframework:spring-web\")\n\tsystemTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\nsystemTest {\n\tinputs.files(war).withNormalizer(ClasspathNormalizer).withPropertyName(\"war\")\n}\n\nwar {\n\tarchiveVersion = ''\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileSystemTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/java/sample/app/DeploymentTestApplication.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample.app;\n\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n@SpringBootApplication\npublic class DeploymentTestApplication extends SpringBootServletInitializer {\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/java/sample/app/SampleController.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample.app;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class SampleController {\n\n\t@GetMapping(\"/\")\n\tpublic String hello() {\n\t\treturn \"Hello World\";\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/java/sample/app/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage sample.app;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/java/sample/autoconfig/ExampleAutoConfiguration.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage sample.autoconfig;\n\nimport org.springframework.boot.actuate.endpoint.annotation.Endpoint;\nimport org.springframework.boot.actuate.endpoint.annotation.ReadOperation;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWarDeployment;\nimport org.springframework.context.annotation.Bean;\n\n@ConditionalOnWarDeployment\n@AutoConfiguration\npublic final class ExampleAutoConfiguration {\n\n\t@Bean\n\tTestEndpoint testEndpoint() {\n\t\treturn new TestEndpoint();\n\t}\n\n\t@Endpoint(id = \"war\")\n\tstatic class TestEndpoint {\n\n\t\t@ReadOperation\n\t\tString hello() {\n\t\t\treturn \"{\\\"hello\\\":\\\"world\\\"}\";\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/java/sample/autoconfig/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage sample.autoconfig;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "sample.autoconfig.ExampleAutoConfiguration\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/main/resources/application.yml",
    "content": "management.endpoints.web.exposure.include: '*'\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/systemTest/java/org/springframework/boot/deployment/AbstractDeploymentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.deployment;\n\nimport java.io.File;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;\nimport org.apache.hc.client5.http.impl.classic.HttpClients;\nimport org.apache.hc.core5.util.TimeValue;\nimport org.awaitility.Awaitility;\nimport org.awaitility.core.ConditionTimeoutException;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.images.builder.ImageFromDockerfile;\nimport org.testcontainers.images.builder.dockerfile.DockerfileBuilder;\n\nimport org.springframework.boot.restclient.RestTemplateBuilder;\nimport org.springframework.boot.resttestclient.TestRestTemplate;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Abstract class for deployment tests.\n */\nabstract class AbstractDeploymentTests {\n\n\tprotected static final int DEFAULT_PORT = 8080;\n\n\t@Test\n\tvoid home() {\n\t\tgetDeployedApplication().test((rest) -> {\n\t\t\tResponseEntity<String> response = rest.getForEntity(\"/\", String.class);\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t\tassertThat(response.getBody()).isEqualTo(\"Hello World\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid errorPage() {\n\t\tgetDeployedApplication().test((rest) -> {\n\t\t\tResponseEntity<String> response = rest.getForEntity(\"/does-not-exist\", String.class);\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);\n\t\t});\n\t}\n\n\t@Test\n\tvoid health() {\n\t\tgetDeployedApplication().test((rest) -> {\n\t\t\tResponseEntity<String> response = rest.getForEntity(\"/actuator/health\", String.class);\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t\tassertThat(response.getBody()).isEqualTo(\"{\\\"groups\\\":[\\\"liveness\\\",\\\"readiness\\\"],\\\"status\\\":\\\"UP\\\"}\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid conditionalOnWarShouldBeTrue() {\n\t\tgetDeployedApplication().test((rest) -> {\n\t\t\tResponseEntity<String> response = rest.getForEntity(\"/actuator/war\", String.class);\n\t\t\tassertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);\n\t\t\tassertThat(response.getBody()).isEqualTo(\"{\\\"hello\\\":\\\"world\\\"}\");\n\t\t});\n\t}\n\n\tprivate DeployedApplication getDeployedApplication() {\n\t\treturn new DeployedApplication(getContainer(), getPort());\n\t}\n\n\tprotected int getPort() {\n\t\treturn DEFAULT_PORT;\n\t}\n\n\tabstract WarDeploymentContainer getContainer();\n\n\tstatic final class DeployedApplication {\n\n\t\tprivate final WarDeploymentContainer container;\n\n\t\tprivate final int port;\n\n\t\tDeployedApplication(WarDeploymentContainer container, int port) {\n\t\t\tthis.container = container;\n\t\t\tthis.port = port;\n\t\t}\n\n\t\tprivate void test(Consumer<TestRestTemplate> consumer) {\n\t\t\tTestRestTemplate rest = new TestRestTemplate(new RestTemplateBuilder()\n\t\t\t\t.baseUri(\"http://\" + this.container.getHost() + \":\" + this.container.getMappedPort(this.port)\n\t\t\t\t\t\t+ \"/spring-boot\")\n\t\t\t\t.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(HttpClients.custom()\n\t\t\t\t\t.setRetryStrategy(new DefaultHttpRequestRetryStrategy(10, TimeValue.of(1, TimeUnit.SECONDS)))\n\t\t\t\t\t.build())));\n\t\t\ttry {\n\t\t\t\tAwaitility.await().atMost(Duration.ofMinutes(10)).until(() -> {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tSystem.out.println(this.container.getLogs());\n\t\t\t\t\t\tconsumer.accept(rest);\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tcatch (Throwable ex) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\tcatch (ConditionTimeoutException ex) {\n\t\t\t\tSystem.out.println(this.container.getLogs());\n\t\t\t\tthrow ex;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstatic final class WarDeploymentContainer extends GenericContainer<WarDeploymentContainer> {\n\n\t\tWarDeploymentContainer(String baseImage, String deploymentLocation, int port) {\n\t\t\tthis(baseImage, deploymentLocation, port, null);\n\t\t}\n\n\t\tWarDeploymentContainer(String baseImage, String deploymentLocation, int port,\n\t\t\t\t@Nullable Consumer<DockerfileBuilder> dockerfileCustomizer) {\n\t\t\tsuper(new ImageFromDockerfile().withFileFromFile(\"spring-boot.war\", findWarToDeploy())\n\t\t\t\t.withDockerfileFromBuilder((builder) -> {\n\t\t\t\t\tbuilder.from(baseImage).add(\"spring-boot.war\", deploymentLocation + \"/spring-boot.war\");\n\t\t\t\t\tif (dockerfileCustomizer != null) {\n\t\t\t\t\t\tdockerfileCustomizer.accept(builder);\n\t\t\t\t\t}\n\t\t\t\t}));\n\t\t\twithExposedPorts(port).withStartupTimeout(Duration.ofMinutes(5)).withStartupAttempts(3);\n\t\t}\n\n\t\tprivate static File findWarToDeploy() {\n\t\t\tFile[] candidates = new File(\"build/libs\").listFiles();\n\t\t\tassertThat(candidates).hasSize(1);\n\t\t\treturn candidates[0];\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/systemTest/java/org/springframework/boot/deployment/TomcatDeploymentTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.deployment;\n\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\n\n/**\n * Deployment tests for Tomcat.\n *\n * @author Christoph Dreis\n * @author Scott Frederick\n */\n@Testcontainers(disabledWithoutDocker = true)\nclass TomcatDeploymentTests extends AbstractDeploymentTests {\n\n\t@Container\n\tstatic WarDeploymentContainer container = new WarDeploymentContainer(\"tomcat:11.0.10-jdk17\",\n\t\t\t\"/usr/local/tomcat/webapps\", DEFAULT_PORT);\n\n\t@Override\n\tWarDeploymentContainer getContainer() {\n\t\treturn container;\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-deployment-system-tests/src/systemTest/java/org/springframework/boot/deployment/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.deployment;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'java-gradle-plugin'\n\tid \"org.springframework.boot.system-test\"\n}\n\ndescription = \"Spring Boot Image Building Tests\"\n\nconfigurations {\n\tapp\n\tprovidedRuntime {\n\t\textendsFrom dependencyManagement\n\t}\n}\n\ntasks.register(\"syncMavenRepository\", Sync) {\n\tfrom configurations.app\n\tinto layout.buildDirectory.dir(\"system-test-maven-repository\")\n}\n\nsystemTest {\n\tdependsOn syncMavenRepository\n\tif (project.hasProperty(\"springBootVersion\")) {\n\t\tsystemProperty \"springBootVersion\", project.properties[\"springBootVersion\"]\n\t} else {\n\t\tsystemProperty \"springBootVersion\", project.getVersion()\n\t}\n}\n\ndependencies {\n\tapp project(path: \":build-plugin:spring-boot-gradle-plugin\", configuration: \"mavenRepository\")\n\tapp project(path: \":starter:spring-boot-starter-webmvc\", configuration: \"mavenRepository\")\n\n\timplementation(project(\":starter:spring-boot-starter-webmvc\")) {\n\t\texclude group: \"org.hibernate.validator\"\n\t}\n\n\tsystemTestImplementation(project(\":buildpack:spring-boot-buildpack-platform\"))\n\tsystemTestImplementation(project(\":starter:spring-boot-starter-test\"))\n\tsystemTestImplementation(project(\":test-support:spring-boot-gradle-test-support\"))\n\tsystemTestImplementation(gradleTestKit())\n\tsystemTestImplementation(\"org.assertj:assertj-core\")\n\tsystemTestImplementation(\"org.testcontainers:testcontainers-junit-jupiter\")\n}\n\ntoolchain {\n\tmaximumCompatibleJavaVersion = JavaLanguageVersion.of(23)\n}\n\ntasks.named(\"compileTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n\ntasks.named(\"compileSystemTestJava\") {\n\toptions.nullability.checking = \"tests\"\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ContainerConfigAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.image.assertions;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.function.Consumer;\n\nimport com.github.dockerjava.api.model.ContainerConfig;\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.AbstractListAssert;\nimport org.assertj.core.api.AbstractMapAssert;\nimport org.assertj.core.api.AbstractObjectAssert;\nimport org.assertj.core.api.ListAssert;\nimport org.assertj.core.api.ObjectAssert;\nimport org.jspecify.annotations.Nullable;\n\nimport org.springframework.boot.test.json.JsonContentAssert;\nimport org.springframework.lang.CheckReturnValue;\n\n/**\n * AssertJ {@link org.assertj.core.api.Assert} for Docker image container configuration.\n *\n * @author Scott Frederick\n */\npublic class ContainerConfigAssert extends AbstractAssert<ContainerConfigAssert, ContainerConfig> {\n\n\tprivate static final String BUILD_METADATA_LABEL = \"io.buildpacks.build.metadata\";\n\n\tprivate static final String LIFECYCLE_METADATA_LABEL = \"io.buildpacks.lifecycle.metadata\";\n\n\tContainerConfigAssert(ContainerConfig containerConfig) {\n\t\tsuper(containerConfig, ContainerConfigAssert.class);\n\t}\n\n\tpublic void buildMetadata(Consumer<BuildMetadataAssert> assertConsumer) {\n\t\tassertConsumer.accept(new BuildMetadataAssert(jsonLabel(BUILD_METADATA_LABEL)));\n\t}\n\n\tpublic void lifecycleMetadata(Consumer<LifecycleMetadataAssert> assertConsumer) {\n\t\tassertConsumer.accept(new LifecycleMetadataAssert(jsonLabel(LIFECYCLE_METADATA_LABEL)));\n\t}\n\n\tpublic void labels(Consumer<LabelsAssert> assertConsumer) {\n\t\tassertConsumer.accept(new LabelsAssert(this.actual.getLabels()));\n\t}\n\n\tprivate JsonContentAssert jsonLabel(String label) {\n\t\treturn new JsonContentAssert(ContainerConfigAssert.class, getLabel(label));\n\t}\n\n\tprivate String getLabel(String label) {\n\t\tMap<String, String> labels = this.actual.getLabels();\n\t\tif (labels == null) {\n\t\t\tfailWithMessage(\"Container config contains no labels\");\n\t\t}\n\t\tif (!labels.containsKey(label)) {\n\t\t\tfailWithActualExpectedAndMessage(labels, label, \"Expected label not found in container config\");\n\t\t}\n\t\treturn labels.get(label);\n\t}\n\n\t/**\n\t * Asserts for labels on an image.\n\t */\n\tpublic static class LabelsAssert extends AbstractMapAssert<LabelsAssert, Map<String, String>, String, String> {\n\n\t\tprotected LabelsAssert(@Nullable Map<String, String> labels) {\n\t\t\tsuper(labels, LabelsAssert.class);\n\t\t}\n\n\t}\n\n\t/**\n\t * Asserts for the JSON content in the {@code io.buildpacks.build.metadata} label.\n\t *\n\t * See <a href=\n\t * \"https://github.com/buildpacks/spec/blob/main/platform.md#iobuildpacksbuildmetadata-json\">the\n\t * spec</a>\n\t */\n\tpublic static class BuildMetadataAssert extends AbstractAssert<BuildMetadataAssert, JsonContentAssert> {\n\n\t\tBuildMetadataAssert(JsonContentAssert jsonContentAssert) {\n\t\t\tsuper(jsonContentAssert, BuildMetadataAssert.class);\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tpublic ListAssert<Object> buildpacks() {\n\t\t\treturn this.actual.extractingJsonPathArrayValue(\"$.buildpacks[*].id\");\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tpublic AbstractListAssert<?, List<? extends String>, String, ObjectAssert<String>> processOfType(String type) {\n\t\t\treturn this.actual.extractingJsonPathArrayValue(\"$.processes[?(@.type=='%s')]\", type)\n\t\t\t\t.singleElement()\n\t\t\t\t.extracting(\"command\", \"args\")\n\t\t\t\t.flatMap(this::getArgs);\n\t\t}\n\n\t\tprivate Collection<String> getArgs(Object obj) {\n\t\t\tif (obj instanceof List<?> list) {\n\t\t\t\treturn list.stream().map(Objects::toString).toList();\n\t\t\t}\n\t\t\treturn Collections.emptyList();\n\t\t}\n\n\t}\n\n\t/**\n\t * Asserts for the JSON content in the {@code io.buildpacks.lifecycle.metadata} label.\n\t *\n\t * See <a href=\n\t * \"https://github.com/buildpacks/spec/blob/main/platform.md#iobuildpackslifecyclemetadata-json\">the\n\t * spec</a>\n\t */\n\tpublic static class LifecycleMetadataAssert extends AbstractAssert<LifecycleMetadataAssert, JsonContentAssert> {\n\n\t\tLifecycleMetadataAssert(JsonContentAssert jsonContentAssert) {\n\t\t\tsuper(jsonContentAssert, LifecycleMetadataAssert.class);\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tpublic ListAssert<Object> buildpackLayers(String buildpackId) {\n\t\t\treturn this.actual.extractingJsonPathArrayValue(\"$.buildpacks[?(@.key=='%s')].layers\", buildpackId);\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tpublic AbstractListAssert<?, List<?>, Object, ObjectAssert<Object>> appLayerShas() {\n\t\t\treturn this.actual.extractingJsonPathArrayValue(\"$.app\").extracting(\"sha\");\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tpublic AbstractObjectAssert<?, Object> sbomLayerSha() {\n\t\t\treturn this.actual.extractingJsonPathValue(\"$.sbom.sha\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ImageAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.image.assertions;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.ListAssert;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.buildpack.platform.docker.type.Layer;\nimport org.springframework.boot.test.json.JsonContentAssert;\nimport org.springframework.lang.CheckReturnValue;\nimport org.springframework.util.StreamUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * AssertJ {@link org.assertj.core.api.Assert} for Docker image contents.\n *\n * @author Scott Frederick\n */\npublic class ImageAssert extends AbstractAssert<ImageAssert, ImageReference> {\n\n\tprivate final HashMap<String, Layer> layers = new HashMap<>();\n\n\tImageAssert(ImageReference imageReference) throws IOException {\n\t\tsuper(imageReference, ImageAssert.class);\n\t\tgetLayers();\n\t}\n\n\tpublic void layer(String layerDigest, Consumer<LayerContentAssert> assertConsumer) {\n\t\tif (!this.layers.containsKey(layerDigest)) {\n\t\t\tfailWithMessage(\"Layer with digest '%s' not found in image\", layerDigest);\n\t\t}\n\t\tassertConsumer.accept(new LayerContentAssert(this.layers.get(layerDigest)));\n\t}\n\n\tprivate void getLayers() throws IOException {\n\t\tnew DockerApi().image().exportLayers(this.actual, (id, tarArchive) -> {\n\t\t\tLayer layer = Layer.fromTarArchive(tarArchive);\n\t\t\tthis.layers.put(layer.getId().toString(), layer);\n\t\t});\n\t}\n\n\t/**\n\t * Asserts for image layers.\n\t */\n\tpublic static class LayerContentAssert extends AbstractAssert<LayerContentAssert, Layer> {\n\n\t\tpublic LayerContentAssert(Layer layer) {\n\t\t\tsuper(layer, LayerContentAssert.class);\n\t\t}\n\n\t\t@CheckReturnValue\n\t\tpublic ListAssert<String> entries() {\n\t\t\tList<String> entryNames = new ArrayList<>();\n\t\t\ttry {\n\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\tthis.actual.writeTo(out);\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(\n\t\t\t\t\t\tnew ByteArrayInputStream(out.toByteArray()))) {\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\t\t\tentryNames.add(entry.getName().replaceFirst(\"^/workspace/\", \"\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tfailWithMessage(\"IOException while reading image layer archive: '%s'\", ex.getMessage());\n\t\t\t}\n\t\t\treturn assertThat(entryNames);\n\t\t}\n\n\t\tpublic void jsonEntry(String name, Consumer<JsonContentAssert> assertConsumer) {\n\t\t\ttry {\n\t\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\t\tthis.actual.writeTo(out);\n\t\t\t\ttry (TarArchiveInputStream in = new TarArchiveInputStream(\n\t\t\t\t\t\tnew ByteArrayInputStream(out.toByteArray()))) {\n\t\t\t\t\tTarArchiveEntry entry = in.getNextEntry();\n\t\t\t\t\twhile (entry != null) {\n\t\t\t\t\t\tif (entry.getName().equals(name)) {\n\t\t\t\t\t\t\tByteArrayOutputStream entryOut = new ByteArrayOutputStream();\n\t\t\t\t\t\t\tStreamUtils.copy(in, entryOut);\n\t\t\t\t\t\t\tassertConsumer.accept(new JsonContentAssert(LayerContentAssert.class, entryOut.toString()));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tentry = in.getNextEntry();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfailWithMessage(\"Expected JSON entry '%s' in layer with digest '%s'\", name, this.actual.getId());\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tfailWithMessage(\"IOException while reading image layer archive: '%s'\", ex.getMessage());\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/ImageAssertions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.image.assertions;\n\nimport java.io.IOException;\n\nimport com.github.dockerjava.api.model.ContainerConfig;\n\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\n\n/**\n * Factory class for custom AssertJ {@link org.assertj.core.api.Assert}s related to images\n * and containers.\n *\n * @author Scott Frederick\n */\npublic final class ImageAssertions {\n\n\tprivate ImageAssertions() {\n\t}\n\n\tpublic static ContainerConfigAssert assertThat(ContainerConfig containerConfig) {\n\t\treturn new ContainerConfigAssert(containerConfig);\n\t}\n\n\tpublic static ImageAssert assertThat(ImageReference imageReference) throws IOException {\n\t\treturn new ImageAssert(imageReference);\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/assertions/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.image.assertions;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/junit/GradleBuildInjectionExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.image.junit;\n\nimport java.lang.reflect.Field;\n\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleVersions;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * A {@link BeforeEachCallback} to configure and set a test class's {@code gradleBuild}\n * field prior to test execution.\n *\n * @author Scott Frederick\n */\npublic class GradleBuildInjectionExtension implements BeforeEachCallback {\n\n\tprivate final String bootVersion;\n\n\tGradleBuildInjectionExtension() {\n\t\tString bootVersion = System.getProperty(\"springBootVersion\");\n\t\tAssert.state(bootVersion != null, \"Property 'springBootVersion' must be set in build environment\");\n\t\tthis.bootVersion = bootVersion;\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tGradleBuild gradleBuild = new GradleBuild(new BuildOutput(context.getRequiredTestClass()))\n\t\t\t.gradleVersion(GradleVersions.minimumCompatible())\n\t\t\t.bootVersion(this.bootVersion);\n\t\tField field = ReflectionUtils.findField(context.getRequiredTestClass(), \"gradleBuild\");\n\t\tAssert.notNull(field, \"No gradleBuild field found in \" + context.getRequiredTestClass().getName());\n\t\tfield.setAccessible(true);\n\t\tfield.set(context.getRequiredTestInstance(), gradleBuild);\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/junit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.image.junit;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/paketo/LayersIndex.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.image.paketo;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.jar.JarFile;\nimport java.util.zip.ZipEntry;\n\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.constructor.Constructor;\n\n/**\n * Index file describing the layers in the jar or war file and the files or directories in\n * each layer.\n *\n * @author Scott Frederick\n */\nclass LayersIndex extends ArrayList<Map<String, List<String>>> {\n\n\tList<String> getLayer(String layerName) {\n\t\treturn stream().filter((entry) -> entry.containsKey(layerName))\n\t\t\t.findFirst()\n\t\t\t.map((entry) -> entry.get(layerName))\n\t\t\t.orElse(Collections.emptyList());\n\t}\n\n\tstatic LayersIndex fromArchiveFile(File archiveFile) throws IOException {\n\t\tString indexPath = (archiveFile.getName().endsWith(\".war\") ? \"WEB-INF/layers.idx\" : \"BOOT-INF/layers.idx\");\n\t\ttry (JarFile jarFile = new JarFile(archiveFile)) {\n\t\t\tZipEntry indexEntry = jarFile.getEntry(indexPath);\n\t\t\tYaml yaml = new Yaml(new Constructor(LayersIndex.class, getLoaderOptions()));\n\t\t\treturn yaml.load(jarFile.getInputStream(indexEntry));\n\t\t}\n\t}\n\n\tprivate static LoaderOptions getLoaderOptions() {\n\t\tLoaderOptions loaderOptions = new LoaderOptions();\n\t\tloaderOptions.setAllowDuplicateKeys(false);\n\t\tloaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE);\n\t\tloaderOptions.setAllowRecursiveKeys(true);\n\t\treturn loaderOptions;\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/paketo/PaketoBuilderTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.image.paketo;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\n\nimport com.github.dockerjava.api.model.ContainerConfig;\nimport org.assertj.core.api.Condition;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.BuildTask;\nimport org.gradle.testkit.runner.TaskOutcome;\nimport org.jspecify.annotations.Nullable;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.containers.wait.strategy.Wait;\n\nimport org.springframework.boot.buildpack.platform.docker.DockerApi;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageName;\nimport org.springframework.boot.buildpack.platform.docker.type.ImageReference;\nimport org.springframework.boot.image.assertions.ImageAssertions;\nimport org.springframework.boot.image.junit.GradleBuildInjectionExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuild;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleBuildExtension;\nimport org.springframework.boot.testsupport.gradle.testkit.GradleVersions;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.entry;\n\n/**\n * Integration tests for the Paketo builder and buildpacks.\n *\n * See\n * https://paketo.io/docs/buildpacks/language-family-buildpacks/java/#additional-metadata\n *\n * @author Scott Frederick\n */\n@ExtendWith({ GradleBuildInjectionExtension.class, GradleBuildExtension.class })\nclass PaketoBuilderTests {\n\n\t@SuppressWarnings(\"NullAway.Init\")\n\tGradleBuild gradleBuild;\n\n\t@BeforeEach\n\tvoid configureGradleBuild() {\n\t\tthis.gradleBuild.scriptProperty(\"systemTestMavenRepository\",\n\t\t\t\tnew File(\"build/system-test-maven-repository\").getAbsoluteFile().toURI().toASCIIString());\n\t\tthis.gradleBuild.scriptPropertyFrom(new File(\"../../gradle.properties\"), \"nativeBuildToolsVersion\");\n\t\tthis.gradleBuild.expectDeprecationMessages(\"BPL_SPRING_CLOUD_BINDINGS_ENABLED.*true.*Deprecated\");\n\t\tthis.gradleBuild.expectDeprecationMessages(\"Command \\\"packages\\\" is deprecated, use `syft scan` instead\");\n\t\tthis.gradleBuild.expectDeprecationMessages(\"BP_ENABLE_RUNTIME_CERT_BINDING.*true.*Deprecated\");\n\t\tthis.gradleBuild.gradleVersion(GradleVersions.maximumCompatible());\n\t}\n\n\t@Test\n\tvoid executableJarApp() throws Exception {\n\t\twriteMainClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tassertLabelsMatchManifestAttributes(config);\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/executable-jar\", \"paketo-buildpacks/dist-zip\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/spring-boot\");\n\t\t\t\tmetadata.processOfType(\"web\")\n\t\t\t\t\t.containsExactly(\"java\", \"org.springframework.boot.loader.launch.JarLauncher\");\n\t\t\t\tmetadata.processOfType(\"executable-jar\")\n\t\t\t\t\t.containsExactly(\"java\", \"org.springframework.boot.loader.launch.JarLauncher\");\n\t\t\t});\n\t\t\tassertImageHasJvmSbomLayer(imageReference, config);\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"executable-jar\");\n\t\t\tassertImageLayersMatchLayersIndex(imageReference, config);\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid executableJarAppWithAdditionalArgs() throws Exception {\n\t\twriteMainClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withCommand(\"--server.port=9090\");\n\t\t\tcontainer.withExposedPorts(9090);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid executableJarAppBuiltTwiceWithCaching() throws Exception {\n\t\twriteMainClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tcontainer.stop();\n\t\t}\n\t\tthis.gradleBuild.expectDeprecationMessages(\"BOM table is deprecated\");\n\t\tresult = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\t@Disabled(\"0.4.292 of the builder launches an unpacked jar rather than the script in bin\")\n\tvoid bootDistZipJarApp() throws Exception {\n\t\twriteMainClass();\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tString imageName = \"paketo-integration/\" + projectName;\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName, \"assemble\", \"bootDistZip\");\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/dist-zip\", \"paketo-buildpacks/spring-boot\");\n\t\t\t\tString launcher = \"/workspace/\" + projectName + \"-boot/bin/\" + projectName;\n\t\t\t\tmetadata.processOfType(\"web\").containsExactly(launcher);\n\t\t\t\tmetadata.processOfType(\"dist-zip\").containsExactly(launcher);\n\t\t\t});\n\t\t\tassertImageHasJvmSbomLayer(imageReference, config);\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"dist-zip\");\n\t\t\tDigestCapturingCondition digest = new DigestCapturingCondition();\n\t\t\tImageAssertions.assertThat(config)\n\t\t\t\t.lifecycleMetadata((metadata) -> metadata.appLayerShas().haveExactly(1, digest));\n\t\t\tImageAssertions.assertThat(imageReference)\n\t\t\t\t.layer(digest.getDigest(),\n\t\t\t\t\t\t(layer) -> layer.entries()\n\t\t\t\t\t\t\t.contains(projectName + \"-boot/bin/\" + projectName,\n\t\t\t\t\t\t\t\t\tprojectName + \"-boot/lib/\" + projectName + \".jar\"));\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid plainDistZipJarApp() throws Exception {\n\t\twriteMainClass();\n\t\tString projectName = this.gradleBuild.getProjectDir().getName();\n\t\tString imageName = \"paketo-integration/\" + projectName;\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName, \"assemble\", \"bootDistZip\");\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/dist-zip\", \"paketo-buildpacks/spring-boot\");\n\t\t\t\tString launcher = \"/workspace/\" + projectName + \"/bin/\" + projectName;\n\t\t\t\tmetadata.processOfType(\"web\").containsExactly(launcher);\n\t\t\t\tmetadata.processOfType(\"dist-zip\").containsExactly(launcher);\n\t\t\t});\n\t\t\tassertImageHasJvmSbomLayer(imageReference, config);\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"dist-zip\");\n\t\t\tDigestCapturingCondition digest = new DigestCapturingCondition();\n\t\t\tImageAssertions.assertThat(config)\n\t\t\t\t.lifecycleMetadata((metadata) -> metadata.appLayerShas().haveExactly(1, digest));\n\t\t\tImageAssertions.assertThat(imageReference)\n\t\t\t\t.layer(digest.getDigest(), (layer) -> layer.entries()\n\t\t\t\t\t.contains(projectName + \"/bin/\" + projectName, projectName + \"/lib/\" + projectName + \"-plain.jar\")\n\t\t\t\t\t.anyMatch((s) -> s.startsWith(projectName + \"/lib/spring-boot-\"))\n\t\t\t\t\t.anyMatch((s) -> s.startsWith(projectName + \"/lib/spring-core-\"))\n\t\t\t\t\t.anyMatch((s) -> s.startsWith(projectName + \"/lib/spring-web-\")));\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid executableWarApp() throws Exception {\n\t\twriteMainClass();\n\t\twriteServletInitializerClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tassertLabelsMatchManifestAttributes(config);\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/executable-jar\", \"paketo-buildpacks/dist-zip\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/spring-boot\");\n\t\t\t\tmetadata.processOfType(\"web\")\n\t\t\t\t\t.containsExactly(\"java\", \"org.springframework.boot.loader.launch.WarLauncher\");\n\t\t\t\tmetadata.processOfType(\"executable-jar\")\n\t\t\t\t\t.containsExactly(\"java\", \"org.springframework.boot.loader.launch.WarLauncher\");\n\t\t\t});\n\t\t\tassertImageHasJvmSbomLayer(imageReference, config);\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"executable-jar\");\n\t\t\tassertImageLayersMatchLayersIndex(imageReference, config);\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid plainWarApp() throws Exception {\n\t\twriteMainClass();\n\t\twriteServletInitializerClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImageWithRetry(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/apache-tomcat\", \"paketo-buildpacks/dist-zip\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/spring-boot\");\n\t\t\t\tmetadata.processOfType(\"web\")\n\t\t\t\t\t.containsSubsequence(\"sh\", \"/layers/paketo-buildpacks_apache-tomcat/tomcat/bin/catalina.sh\", \"run\");\n\t\t\t\tmetadata.processOfType(\"tomcat\")\n\t\t\t\t\t.containsSubsequence(\"sh\", \"/layers/paketo-buildpacks_apache-tomcat/tomcat/bin/catalina.sh\", \"run\");\n\t\t\t});\n\t\t\tassertImageHasJvmSbomLayer(imageReference, config);\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"apache-tomcat\");\n\t\t\tDigestCapturingCondition digest = new DigestCapturingCondition();\n\t\t\tImageAssertions.assertThat(config)\n\t\t\t\t.lifecycleMetadata((metadata) -> metadata.appLayerShas().haveExactly(1, digest));\n\t\t\tImageAssertions.assertThat(imageReference)\n\t\t\t\t.layer(digest.getDigest(),\n\t\t\t\t\t\t(layer) -> layer.entries()\n\t\t\t\t\t\t\t.contains(\"WEB-INF/classes/example/ExampleApplication.class\",\n\t\t\t\t\t\t\t\t\t\"WEB-INF/classes/example/HelloController.class\", \"META-INF/MANIFEST.MF\")\n\t\t\t\t\t\t\t.anyMatch((s) -> s.startsWith(\"WEB-INF/lib/spring-boot-\"))\n\t\t\t\t\t\t\t.anyMatch((s) -> s.startsWith(\"WEB-INF/lib/spring-core-\"))\n\t\t\t\t\t\t\t.anyMatch((s) -> s.startsWith(\"WEB-INF/lib/spring-web-\")));\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid nativeApp() throws Exception {\n\t\tthis.gradleBuild.expectDeprecationMessages(\"uses or overrides a deprecated API\");\n\t\tthis.gradleBuild.expectDeprecationMessages(\"has been deprecated and marked for removal\");\n\t\t// these deprecations are transitive from the Native Build Tools Gradle plugin\n\t\tthis.gradleBuild\n\t\t\t.expectDeprecationMessages(\"has been deprecated. This is scheduled to be removed in Gradle 9.0\");\n\t\tthis.gradleBuild.expectDeprecationMessages(\"upgrading_version_8.html#deprecated_access_to_convention\");\n\t\t// these deprecations are from native image buildpacks\n\t\tthis.gradleBuild.expectDeprecationMessages(\"Using a deprecated option --report-unsupported-elements-at-runtime\",\n\t\t\t\t\"The option is deprecated and will be removed in the future.\");\n\t\twriteMainClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tassertLabelsMatchManifestAttributes(config);\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/executable-jar\", \"paketo-buildpacks/spring-boot\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/native-image\");\n\t\t\t\tmetadata.processOfType(\"web\")\n\t\t\t\t\t.satisfiesExactly((command) -> assertThat(command).endsWith(\"/example.ExampleApplication\"));\n\t\t\t\tmetadata.processOfType(\"native-image\")\n\t\t\t\t\t.satisfiesExactly((command) -> assertThat(command).endsWith(\"/example.ExampleApplication\"));\n\t\t\t});\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"native-image\");\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\t@Test\n\tvoid classDataSharingApp() throws Exception {\n\t\twriteMainClass();\n\t\tString imageName = \"paketo-integration/\" + this.gradleBuild.getProjectDir().getName();\n\t\tImageReference imageReference = ImageReference.of(ImageName.of(imageName));\n\t\tBuildResult result = buildImage(imageName);\n\t\tassertThat(result.task(\":bootBuildImage\")).extracting(BuildTask::getOutcome).isEqualTo(TaskOutcome.SUCCESS);\n\t\tassertThat(result.getOutput()).contains(\"Running creator\");\n\t\ttry (GenericContainer<?> container = new GenericContainer<>(imageName)) {\n\t\t\tcontainer.withExposedPorts(8080);\n\t\t\tcontainer.waitingFor(Wait.forHttp(\"/test\")).start();\n\t\t\tContainerConfig config = container.getContainerInfo().getConfig();\n\t\t\tassertLabelsMatchManifestAttributes(config);\n\t\t\tImageAssertions.assertThat(config).buildMetadata((metadata) -> {\n\t\t\t\tmetadata.buildpacks()\n\t\t\t\t\t.contains(\"paketo-buildpacks/ca-certificates\", \"paketo-buildpacks/bellsoft-liberica\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/executable-jar\", \"paketo-buildpacks/dist-zip\",\n\t\t\t\t\t\t\t\"paketo-buildpacks/spring-boot\");\n\t\t\t\tmetadata.processOfType(\"web\")\n\t\t\t\t\t.satisfiesExactly((command) -> assertThat(command).isEqualTo(\"java\"),\n\t\t\t\t\t\t\t(arg) -> assertThat(arg).isEqualTo(\"-cp\"),\n\t\t\t\t\t\t\t(arg) -> assertThat(arg).startsWith(\"runner.jar\"),\n\t\t\t\t\t\t\t(arg) -> assertThat(arg).isEqualTo(\"example.ExampleApplication\"));\n\t\t\t\tmetadata.processOfType(\"spring-boot-app\")\n\t\t\t\t\t.satisfiesExactly((command) -> assertThat(command).isEqualTo(\"java\"),\n\t\t\t\t\t\t\t(arg) -> assertThat(arg).isEqualTo(\"-cp\"),\n\t\t\t\t\t\t\t(arg) -> assertThat(arg).startsWith(\"runner.jar\"),\n\t\t\t\t\t\t\t(arg) -> assertThat(arg).isEqualTo(\"example.ExampleApplication\"));\n\t\t\t\tmetadata.processOfType(\"executable-jar\")\n\t\t\t\t\t.containsExactly(\"java\", \"org.springframework.boot.loader.launch.JarLauncher\");\n\t\t\t});\n\t\t\tassertImageHasJvmSbomLayer(imageReference, config);\n\t\t\tassertImageHasDependenciesSbomLayer(imageReference, config, \"executable-jar\");\n\t\t}\n\t\tfinally {\n\t\t\tremoveImage(imageReference);\n\t\t}\n\t}\n\n\tprivate BuildResult buildImageWithRetry(String imageName, String... arguments) {\n\t\tlong start = System.nanoTime();\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\treturn buildImage(imageName, arguments);\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tex.printStackTrace();\n\t\t\t\tif (Duration.ofNanos(System.nanoTime() - start).toMinutes() > 6) {\n\t\t\t\t\tthrow ex;\n\t\t\t\t}\n\t\t\t\tsleep(500);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void sleep(long time) {\n\t\ttry {\n\t\t\tThread.sleep(time);\n\t\t}\n\t\tcatch (InterruptedException ex) {\n\t\t\tThread.currentThread().interrupt();\n\t\t}\n\t}\n\n\tprivate BuildResult buildImage(String imageName, String... arguments) {\n\t\tList<String> args = new ArrayList<>(List.of(arguments));\n\t\targs.add(\"bootBuildImage\");\n\t\targs.add(\"--imageName=\" + imageName);\n\t\targs.add(\"--pullPolicy=IF_NOT_PRESENT\");\n\t\treturn this.gradleBuild.build(args.toArray(new String[0]));\n\t}\n\n\tprivate void writeMainClass() throws IOException {\n\t\twriteProjectFile(\"ExampleApplication.java\", (writer) -> {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import org.springframework.boot.SpringApplication;\");\n\t\t\twriter.println(\"import org.springframework.boot.autoconfigure.SpringBootApplication;\");\n\t\t\twriter.println(\"import org.springframework.stereotype.Controller;\");\n\t\t\twriter.println(\"import org.springframework.web.bind.annotation.RequestMapping;\");\n\t\t\twriter.println(\"import org.springframework.web.bind.annotation.ResponseBody;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"@SpringBootApplication\");\n\t\t\twriter.println(\"public class ExampleApplication {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    public static void main(String[] args) {\");\n\t\t\twriter.println(\"        SpringApplication.run(ExampleApplication.class, args);\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"@Controller\");\n\t\t\twriter.println(\"class HelloController {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    @RequestMapping(\\\"/test\\\")\");\n\t\t\twriter.println(\"    @ResponseBody\");\n\t\t\twriter.println(\"    String home() {\");\n\t\t\twriter.println(\"        return \\\"Hello, world!\\\";\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t});\n\t}\n\n\tprivate void writeServletInitializerClass() throws IOException {\n\t\twriteProjectFile(\"ServletInitializer.java\", (writer) -> {\n\t\t\twriter.println(\"package example;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"import org.springframework.boot.builder.SpringApplicationBuilder;\");\n\t\t\twriter.println(\"import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"public class ServletInitializer extends SpringBootServletInitializer {\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"    @Override\");\n\t\t\twriter.println(\"    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {\");\n\t\t\twriter.println(\"        return application.sources(ExampleApplication.class);\");\n\t\t\twriter.println(\"    }\");\n\t\t\twriter.println();\n\t\t\twriter.println(\"}\");\n\t\t});\n\t}\n\n\tprivate void writeProjectFile(String fileName, Consumer<PrintWriter> consumer) throws IOException {\n\t\tFile examplePackage = new File(this.gradleBuild.getProjectDir(), \"src/main/java/example\");\n\t\texamplePackage.mkdirs();\n\t\tFile main = new File(examplePackage, fileName);\n\t\ttry (PrintWriter writer = new PrintWriter(new FileWriter(main))) {\n\t\t\tconsumer.accept(writer);\n\t\t}\n\t}\n\n\tprivate void assertLabelsMatchManifestAttributes(ContainerConfig config) throws IOException {\n\t\ttry (JarFile jarFile = new JarFile(projectArchiveFile())) {\n\t\t\tAttributes attributes = jarFile.getManifest().getMainAttributes();\n\t\t\tImageAssertions.assertThat(config).labels((labels) -> {\n\t\t\t\tlabels.contains(entry(\"org.springframework.boot.version\", attributes.getValue(\"Spring-Boot-Version\")));\n\t\t\t\tlabels.contains(entry(\"org.opencontainers.image.title\",\n\t\t\t\t\t\tattributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE)));\n\t\t\t\tlabels.contains(entry(\"org.opencontainers.image.version\",\n\t\t\t\t\t\tattributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION)));\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate void assertImageHasJvmSbomLayer(ImageReference imageReference, ContainerConfig config) throws IOException {\n\t\tDigestCapturingCondition digest = new DigestCapturingCondition();\n\t\tImageAssertions.assertThat(config).lifecycleMetadata((metadata) -> metadata.sbomLayerSha().has(digest));\n\t\tImageAssertions.assertThat(imageReference).layer(digest.getDigest(), (layer) -> {\n\t\t\tlayer.entries().contains(\"/layers/sbom/launch/paketo-buildpacks_bellsoft-liberica/jre/sbom.syft.json\");\n\t\t\tlayer.jsonEntry(\"/layers/sbom/launch/paketo-buildpacks_bellsoft-liberica/jre/sbom.syft.json\", (json) -> {\n\t\t\t\tjson.extractingJsonPathStringValue(\"$.Artifacts[0].Name\").isEqualTo(\"BellSoft Liberica JRE\");\n\t\t\t\tjson.extractingJsonPathStringValue(\"$.Artifacts[0].Version\").startsWith(javaMajorVersion());\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate void assertImageHasDependenciesSbomLayer(ImageReference imageReference, ContainerConfig config,\n\t\t\tString buildpack) throws IOException {\n\t\tDigestCapturingCondition digest = new DigestCapturingCondition();\n\t\tImageAssertions.assertThat(config).lifecycleMetadata((metadata) -> metadata.sbomLayerSha().has(digest));\n\t\tImageAssertions.assertThat(imageReference).layer(digest.getDigest(), (layer) -> {\n\t\t\tlayer.entries()\n\t\t\t\t.contains(\"/layers/sbom/launch/paketo-buildpacks_\" + buildpack + \"/sbom.syft.json\",\n\t\t\t\t\t\t\"/layers/sbom/launch/paketo-buildpacks_\" + buildpack + \"/sbom.cdx.json\");\n\t\t\tlayer.jsonEntry(\"/layers/sbom/launch/paketo-buildpacks_\" + buildpack + \"/sbom.syft.json\",\n\t\t\t\t\t(json) -> json.extractingJsonPathArrayValue(\"$.artifacts.[*].name\")\n\t\t\t\t\t\t.contains(\"commons-logging\", \"spring-beans\", \"spring-boot\", \"spring-boot-autoconfigure\",\n\t\t\t\t\t\t\t\t\"spring-context\", \"spring-core\", \"spring-expression\", \"spring-web\", \"spring-webmvc\"));\n\t\t\tlayer.jsonEntry(\"/layers/sbom/launch/paketo-buildpacks_\" + buildpack + \"/sbom.cdx.json\",\n\t\t\t\t\t(json) -> json.extractingJsonPathArrayValue(\"$.components.[*].name\")\n\t\t\t\t\t\t.contains(\"commons-logging\", \"spring-beans\", \"spring-boot\", \"spring-boot-autoconfigure\",\n\t\t\t\t\t\t\t\t\"spring-context\", \"spring-core\", \"spring-expression\", \"spring-web\", \"spring-webmvc\"));\n\t\t});\n\t}\n\n\tprivate void assertImageLayersMatchLayersIndex(ImageReference imageReference, ContainerConfig config)\n\t\t\tthrows IOException {\n\t\tDigestsCapturingCondition digests = new DigestsCapturingCondition();\n\t\tImageAssertions.assertThat(config)\n\t\t\t.lifecycleMetadata((metadata) -> metadata.appLayerShas().haveExactly(5, digests));\n\t\tLayersIndex layersIndex = LayersIndex.fromArchiveFile(projectArchiveFile());\n\t\tImageAssertions.assertThat(imageReference)\n\t\t\t.layer(digests.getDigest(0), (layer) -> layer.entries()\n\t\t\t\t.allMatch((entry) -> startsWithOneOf(entry, layersIndex.getLayer(\"dependencies\"))));\n\t\tImageAssertions.assertThat(imageReference)\n\t\t\t.layer(digests.getDigest(1), (layer) -> layer.entries()\n\t\t\t\t.allMatch((entry) -> startsWithOneOf(entry, layersIndex.getLayer(\"spring-boot-loader\"))));\n\t\tImageAssertions.assertThat(imageReference)\n\t\t\t.layer(digests.getDigest(2), (layer) -> layer.entries()\n\t\t\t\t.allMatch((entry) -> startsWithOneOf(entry, layersIndex.getLayer(\"snapshot-dependencies\"))));\n\t\tImageAssertions.assertThat(imageReference)\n\t\t\t.layer(digests.getDigest(3), (layer) -> layer.entries()\n\t\t\t\t.allMatch((entry) -> startsWithOneOf(entry, layersIndex.getLayer(\"application\"))));\n\t\tImageAssertions.assertThat(imageReference)\n\t\t\t.layer(digests.getDigest(4),\n\t\t\t\t\t(layer) -> layer.entries().allMatch((entry) -> entry.contains(\"lib/spring-cloud-bindings-\")));\n\t}\n\n\tprivate File projectArchiveFile() {\n\t\treturn new File(this.gradleBuild.getProjectDir(), \"build/libs\").listFiles()[0];\n\t}\n\n\tprivate String javaMajorVersion() {\n\t\tString javaVersion = System.getProperty(\"java.version\");\n\t\tif (javaVersion.startsWith(\"1.\")) {\n\t\t\treturn javaVersion.substring(2, 3);\n\t\t}\n\t\tint firstDotIndex = javaVersion.indexOf(\".\");\n\t\tif (firstDotIndex != -1) {\n\t\t\treturn javaVersion.substring(0, firstDotIndex);\n\t\t}\n\t\treturn javaVersion;\n\t}\n\n\tprivate boolean startsWithOneOf(String actual, List<String> expectedPrefixes) {\n\t\tfor (String prefix : expectedPrefixes) {\n\t\t\tif (actual.startsWith(prefix)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate void removeImage(ImageReference image) throws IOException {\n\t\tnew DockerApi().image().remove(image, false);\n\t}\n\n\tprivate static class DigestCapturingCondition extends Condition<Object> {\n\n\t\tprivate static @Nullable String digest;\n\n\t\tDigestCapturingCondition() {\n\t\t\tsuper(predicate(), \"a value starting with 'sha256:'\");\n\t\t}\n\n\t\tprivate static Predicate<Object> predicate() {\n\t\t\treturn (sha) -> {\n\t\t\t\tdigest = sha.toString();\n\t\t\t\treturn sha.toString().startsWith(\"sha256:\");\n\t\t\t};\n\t\t}\n\n\t\tString getDigest() {\n\t\t\tassertThat(digest).isNotNull();\n\t\t\treturn digest;\n\t\t}\n\n\t}\n\n\tprivate static class DigestsCapturingCondition extends Condition<Object> {\n\n\t\tprivate static @Nullable List<String> digests;\n\n\t\tDigestsCapturingCondition() {\n\t\t\tsuper(predicate(), \"a value starting with 'sha256:'\");\n\t\t}\n\n\t\tprivate static Predicate<Object> predicate() {\n\t\t\tList<String> digests = new ArrayList<>();\n\t\t\tDigestsCapturingCondition.digests = digests;\n\t\t\treturn (sha) -> {\n\t\t\t\tdigests.add(sha.toString());\n\t\t\t\treturn sha.toString().startsWith(\"sha256:\");\n\t\t\t};\n\t\t}\n\n\t\tString getDigest(int index) {\n\t\t\tassertThat(digests).isNotNull();\n\t\t\treturn digests.get(index);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/java/org/springframework/boot/image/paketo/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n@NullMarked\npackage org.springframework.boot.image.paketo;\n\nimport org.jspecify.annotations.NullMarked;\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-bootDistZipJarApp.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'java'\n\tid 'application'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n}\n\nbootJar {\n\tmanifest {\n\t\tattributes(\n\t\t\t\t'Implementation-Version': '1.0.0',\n\t\t\t\t'Implementation-Title': \"Paketo Test\"\n\t\t)\n\t}\n}\n\napplication {\n\tmainClass = 'example.ExampleApplication'\n}\n\nbootBuildImage {\n\tarchiveFile = bootDistZip.archiveFile\n\tenvironment = ['BP_JVM_VERSION': java.targetCompatibility.getMajorVersion()]\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-classDataSharingApp.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'java'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tmaven {\n\t\turl = 'https://repo.spring.io/milestone'\n\t}\n\tmaven {\n\t\turl = 'https://repo.spring.io/snapshot'\n\t}\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n}\n\nbootJar {\n\tmanifest {\n\t\tattributes(\n\t\t\t\t'Implementation-Version': '1.0.0',\n\t\t\t\t'Implementation-Title': \"Paketo Test\"\n\t\t)\n\t}\n}\n\nbootBuildImage {\n\tenvironment = ['BP_JVM_CDS_ENABLED': 'true']\n}"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-executableWarApp.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'java'\n\tid 'war'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n\tprovidedRuntime(\"org.springframework.boot:spring-boot-starter-tomcat-runtime:{bootVersion}\")\n}\n\nbootWar {\n\tmanifest {\n\t\tattributes(\n\t\t\t\t'Implementation-Version': '1.0.0',\n\t\t\t\t'Implementation-Title': \"Paketo Test\"\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-nativeApp.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'org.springframework.boot.aot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'org.graalvm.buildtools.native' version '{nativeBuildToolsVersion}'\n\tid 'java'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ntasks.named(\"bootBuildImage\") {\n\tenvironment[\"BP_JVM_VERSION\"] = \"25\"\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n}\n\nbootJar {\n\tmanifest {\n\t\tattributes(\n\t\t\t\t'Implementation-Version': '1.0.0',\n\t\t\t\t'Implementation-Title': 'Paketo Test'\n\t\t)\n\t}\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-plainDistZipJarApp.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'java'\n\tid 'application'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n}\n\nbootJar {\n\tmanifest {\n\t\tattributes(\n\t\t\t\t'Implementation-Version': '1.0.0',\n\t\t\t\t'Implementation-Title': \"Paketo Test\"\n\t\t)\n\t}\n}\n\napplication {\n\tmainClass = 'example.ExampleApplication'\n}\n\nbootBuildImage {\n\tarchiveFile = distZip.archiveFile\n\trunImage = \"paketobuildpacks/ubuntu-noble-run:latest\"\n\tenvironment = ['BP_JVM_VERSION': java.targetCompatibility.getMajorVersion()]\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests-plainWarApp.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'java'\n\tid 'war'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n}\n\nwar {\n\tenabled = true\n\tarchiveClassifier.set('plain')\n}\n\nbootBuildImage {\n\tarchiveFile = war.archiveFile\n\trunImage = \"paketobuildpacks/ubuntu-noble-run:latest\"\n\tenvironment = [\n\t\t'BP_JVM_VERSION': java.targetCompatibility.getMajorVersion(),\n\t\t'BP_TOMCAT_VERSION': '11.*',\n\t\t'BP_DEPENDENCY_MIRROR_DOWNLOADS_APACHE_ORG': 'https://archive.apache.org/dist'\n\t]\n}\n"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/PaketoBuilderTests.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid 'org.springframework.boot' version '{bootVersion}'\n\tid 'io.spring.dependency-management' version '{dependencyManagementPluginVersion}'\n\tid 'java'\n}\n\nrepositories {\n\texclusiveContent {\n\t\tforRepository {\n\t\t\tmaven {\n\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t}\n\t\t}\n\t\tfilter {\n\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t}\n\t}\n\tmavenCentral()\n\tspring.mavenRepositories()\n}\n\ndependencies {\n\timplementation(\"org.springframework.boot:spring-boot-starter-webmvc:{bootVersion}\")\n}\n\nbootJar {\n\tmanifest {\n\t\tattributes(\n\t\t\t\t'Implementation-Version': '1.0.0',\n\t\t\t\t'Implementation-Title': \"Paketo Test\"\n\t\t)\n\t}\n}"
  },
  {
    "path": "system-test/spring-boot-image-system-tests/src/systemTest/resources/org/springframework/boot/image/paketo/settings.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npluginManagement {\n\tevaluate(new File(\"{parentRootDir}/buildSrc/SpringRepositorySupport.groovy\")).apply(this)\n\trepositories {\n\t\texclusiveContent {\n\t\t\tforRepository {\n\t\t\t\tmaven {\n\t\t\t\t\turl = '{systemTestMavenRepository}'\n\t\t\t\t}\n\t\t\t}\n\t\t\tfilter {\n\t\t\t\tincludeGroup \"org.springframework.boot\"\n\t\t\t}\n\t\t}\n\t\tspring.mavenRepositories()\n\t\tgradlePluginPortal()\n\t}\n\tresolutionStrategy {\n\t\teachPlugin {\n\t\t\tif (requested.id.id.startsWith(\"org.springframework.boot\")) {\n\t\t\t\tuseModule \"org.springframework.boot:spring-boot-gradle-plugin:${requested.version}\"\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Docker Testing Support\"\n\ndependencies {\n\tapi(platform(project(path: \":platform:spring-boot-internal-dependencies\")))\n\tapi(project(path: \":test-support:spring-boot-test-support\"))\n\n\tcompileOnly(\"org.testcontainers:testcontainers\")\n\n\tcompileOnly(\"org.junit.jupiter:junit-jupiter\")\n\tcompileOnly(\"org.springframework:spring-core\")\n\n\toptional(\"org.testcontainers:testcontainers-activemq\")\n\toptional(\"org.testcontainers:testcontainers-cassandra\")\n\toptional(\"org.testcontainers:testcontainers-couchbase\")\n\toptional(\"org.testcontainers:testcontainers-elasticsearch\")\n\toptional(\"org.testcontainers:testcontainers-grafana\")\n\toptional(\"org.testcontainers:testcontainers-junit-jupiter\")\n\toptional(\"org.testcontainers:testcontainers-kafka\")\n\toptional(\"org.testcontainers:testcontainers-ldap\")\n\toptional(\"org.testcontainers:testcontainers-mariadb\")\n\toptional(\"org.testcontainers:testcontainers-mongodb\")\n\toptional(\"org.testcontainers:testcontainers-mysql\")\n\toptional(\"org.testcontainers:testcontainers-neo4j\")\n\toptional(\"org.testcontainers:testcontainers-oracle-xe\")\n\toptional(\"org.testcontainers:testcontainers-oracle-free\")\n\toptional(\"org.testcontainers:testcontainers-postgresql\")\n\toptional(\"org.testcontainers:testcontainers-pulsar\")\n\toptional(\"org.testcontainers:testcontainers-rabbitmq\")\n\toptional(\"org.testcontainers:testcontainers-redpanda\")\n\toptional(\"com.redis:testcontainers-redis\")\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/DisabledIfDockerUnavailable.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Disables test execution if Docker is unavailable.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ExtendWith(DisabledIfDockerUnavailableCondition.class)\npublic @interface DisabledIfDockerUnavailable {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/DisabledIfDockerUnavailableCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.junit.jupiter.api.extension.ConditionEvaluationResult;\nimport org.junit.jupiter.api.extension.ExecutionCondition;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.testcontainers.DockerClientFactory;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ClassUtils;\n\n/**\n * An {@link ExecutionCondition} that disables execution if Docker is unavailable.\n *\n * @author Andy Wilkinson\n * @author Phillip Webb\n * @author Moritz Halbritter\n */\nclass DisabledIfDockerUnavailableCondition implements ExecutionCondition {\n\n\tprivate static final boolean TESTCONTAINERS_PRESENT = ClassUtils.isPresent(\"org.testcontainers.DockerClientFactory\",\n\t\t\tDisabledIfDockerUnavailableCondition.class.getClassLoader());\n\n\tprivate static final String SILENCE_PROPERTY = \"visibleassertions.silence\";\n\n\tprivate static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled(\"Docker available\");\n\n\t@Override\n\tpublic ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {\n\t\tAssert.isTrue(TESTCONTAINERS_PRESENT, \"Testcontainers is required when using @DisabledIfDockerUnavailable.\"\n\t\t\t\t+ \" Add a dependency on org.testcontainers:testcontainers\");\n\t\tString originalSilenceValue = System.getProperty(SILENCE_PROPERTY);\n\t\ttry {\n\t\t\tDockerClientFactory.instance().client();\n\t\t\treturn ENABLED;\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn ConditionEvaluationResult.disabled(\"Docker unavailable\", ex.getMessage());\n\t\t}\n\t\tfinally {\n\t\t\tif (originalSilenceValue != null) {\n\t\t\t\tSystem.setProperty(SILENCE_PROPERTY, originalSilenceValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tSystem.clearProperty(SILENCE_PROPERTY);\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/ElasticsearchContainer9.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\n\n/**\n * A container suitable for testing Elasticsearch 9.\n *\n * @author Dmytro Nosan\n */\npublic class ElasticsearchContainer9 extends ElasticsearchContainer {\n\n\tpublic ElasticsearchContainer9() {\n\t\tsuper(TestImage.ELASTICSEARCH_9.toString());\n\t\taddEnv(\"ES_JAVA_OPTS\", \"-Xms32m -Xmx512m\");\n\t\taddEnv(\"xpack.security.enabled\", \"false\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/HazelcastContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n/**\n * A {@link GenericContainer} for Hazelcast.\n *\n * @author Dmytro Nosan\n */\npublic final class HazelcastContainer extends GenericContainer<HazelcastContainer> {\n\n\tprivate static final int DEFAULT_PORT = 5701;\n\n\tpublic HazelcastContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\taddExposedPorts(DEFAULT_PORT);\n\t}\n\n\t/**\n\t * Sets the cluster name.\n\t * @param clusterName the cluster name\n\t * @return this instance\n\t */\n\tpublic HazelcastContainer withClusterName(String clusterName) {\n\t\treturn withEnv(\"HZ_CLUSTERNAME\", clusterName);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/MailpitContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\nimport org.testcontainers.utility.MountableFile;\n\n/**\n * A {@link GenericContainer} for MailDev.\n *\n * @author Rui Figueira\n */\npublic class MailpitContainer extends GenericContainer<MailpitContainer> {\n\n\tprivate static final int DEFAULT_SMTP_PORT = 1025;\n\n\tprivate static final int DEFAULT_POP3_PORT = 1110;\n\n\tpublic MailpitContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\taddExposedPorts(DEFAULT_SMTP_PORT, DEFAULT_POP3_PORT);\n\t}\n\n\tpublic int getSmtpPort() {\n\t\treturn getMappedPort(DEFAULT_SMTP_PORT);\n\t}\n\n\tpublic int getPop3Port() {\n\t\treturn getMappedPort(DEFAULT_POP3_PORT);\n\t}\n\n\tpublic MailpitContainer withSmtpTlsCert(MountableFile cert) {\n\t\tthis.withCopyFileToContainer(cert, \"/tmp/ssl/public.crt\");\n\t\tthis.withEnv(\"MP_SMTP_TLS_CERT\", \"/tmp/ssl/public.crt\");\n\t\treturn this.self();\n\t}\n\n\tpublic MailpitContainer withSmtpTlsKey(MountableFile key) {\n\t\tthis.withCopyFileToContainer(key, \"/tmp/ssl/private.key\");\n\t\tthis.withEnv(\"MP_SMTP_TLS_KEY\", \"/tmp/ssl/private.key\");\n\t\treturn this.self();\n\t}\n\n\tpublic MailpitContainer withSmtpRequireTls(boolean requireTls) {\n\t\tif (requireTls) {\n\t\t\tthis.withEnv(\"MP_SMTP_REQUIRE_TLS\", \"true\");\n\t\t}\n\t\treturn this.self();\n\t}\n\n\tpublic MailpitContainer withSmtpRequireStarttls(boolean requireStarttls) {\n\t\tif (requireStarttls) {\n\t\t\tthis.withEnv(\"MP_SMTP_REQUIRE_STARTTLS\", \"true\");\n\t\t}\n\t\treturn this.self();\n\t}\n\n\tpublic MailpitContainer withPop3Auth(String... auths) {\n\t\tthis.withEnv(\"MP_POP3_AUTH\", String.join(\" \", auths));\n\t\treturn this.self();\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/OpenLdapContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n/**\n * A {@link GenericContainer} for OpenLDAP.\n *\n * @author Philipp Kessler\n */\npublic class OpenLdapContainer extends GenericContainer<OpenLdapContainer> {\n\n\tprivate static final int DEFAULT_LDAP_PORT = 389;\n\n\tpublic OpenLdapContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\taddExposedPorts(DEFAULT_LDAP_PORT);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/RedisStackServerContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n/**\n * A {@link GenericContainer} for Redis Stack Server.\n *\n * @author Andy Wilkinson\n * @author Madhura Bhave\n */\npublic class RedisStackServerContainer extends GenericContainer<RedisStackServerContainer> {\n\n\tpublic RedisStackServerContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\taddExposedPorts(6379);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/RegistryContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n/**\n * A {@link GenericContainer} for Docker Registry.\n *\n * @author Phillip Webb\n */\npublic class RegistryContainer extends GenericContainer<RegistryContainer> {\n\n\tpublic RegistryContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\taddExposedPorts(5000);\n\t\taddEnv(\"SERVER_NAME\", \"localhost\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/SymptomaActiveMQContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n/**\n * A {@link GenericContainer} for Symptoma/ActiveMQ.\n *\n * @author Stephane Nicoll\n */\npublic final class SymptomaActiveMQContainer extends GenericContainer<SymptomaActiveMQContainer> {\n\n\tprivate static final int DEFAULT_PORT = 61616;\n\n\tpublic SymptomaActiveMQContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\taddExposedPorts(DEFAULT_PORT);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/TestImage.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport java.lang.reflect.Constructor;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\n\nimport com.redis.testcontainers.RedisContainer;\nimport com.redis.testcontainers.RedisStackContainer;\nimport org.testcontainers.activemq.ActiveMQContainer;\nimport org.testcontainers.activemq.ArtemisContainer;\nimport org.testcontainers.cassandra.CassandraContainer;\nimport org.testcontainers.containers.Container;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.couchbase.CouchbaseContainer;\nimport org.testcontainers.elasticsearch.ElasticsearchContainer;\nimport org.testcontainers.grafana.LgtmStackContainer;\nimport org.testcontainers.kafka.ConfluentKafkaContainer;\nimport org.testcontainers.ldap.LLdapContainer;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.mongodb.MongoDBAtlasLocalContainer;\nimport org.testcontainers.mongodb.MongoDBContainer;\nimport org.testcontainers.mysql.MySQLContainer;\nimport org.testcontainers.neo4j.Neo4jContainer;\nimport org.testcontainers.postgresql.PostgreSQLContainer;\nimport org.testcontainers.pulsar.PulsarContainer;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\nimport org.testcontainers.redpanda.RedpandaContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.util.Assert;\n\n/**\n * References to container images used for integration tests. This class also acts a\n * central location for tests to {@link #container(Class) create} a correctly configured\n * {@link Container testcontainer}.\n *\n * @author Stephane Nicoll\n * @author Eddú Meléndez\n * @author Moritz Halbritter\n * @author Chris Bono\n * @author Phillip Webb\n */\npublic enum TestImage {\n\n\t/**\n\t * A container image suitable for testing ActiveMQ.\n\t */\n\tACTIVE_MQ(\"symptoma/activemq\", \"5.18.3\", () -> SymptomaActiveMQContainer.class),\n\n\t/**\n\t * A container image suitable for testing ActiveMQ classic.\n\t */\n\tACTIVE_MQ_CLASSIC(\"apache/activemq-classic\", \"5.18.3\", () -> ActiveMQContainer.class),\n\n\t/**\n\t * A container image suitable for testing Apache Kafka.\n\t */\n\tAPACHE_KAFKA(\"apache/kafka\", \"3.7.0\", () -> org.testcontainers.kafka.KafkaContainer.class),\n\n\t/**\n\t * A container image suitable for testing Artemis.\n\t */\n\tARTEMIS(\"apache/activemq-artemis\", \"2.34.0\", () -> ArtemisContainer.class),\n\n\t/**\n\t * A container image suitable for testing Cassandra.\n\t */\n\tCASSANDRA(\"cassandra\", \"3.11.10\", () -> CassandraContainer.class,\n\t\t\t(container) -> ((CassandraContainer) container).withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing ClickHouse.\n\t */\n\tCLICKHOUSE(\"clickhouse/clickhouse-server\", \"24.3\"),\n\n\t/**\n\t * A container image suitable for testing Couchbase.\n\t */\n\tCOUCHBASE(\"couchbase/server\", \"7.1.4\", () -> CouchbaseContainer.class,\n\t\t\t(container) -> ((CouchbaseContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Elasticsearch 7.\n\t */\n\tELASTICSEARCH(\"docker.elastic.co/elasticsearch/elasticsearch\", \"7.17.28\", () -> ElasticsearchContainer.class,\n\t\t\t(container) -> ((ElasticsearchContainer) container).withEnv(\"ES_JAVA_OPTS\", \"-Xms32m -Xmx512m\")\n\t\t\t\t.withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Elasticsearch 8.\n\t */\n\tELASTICSEARCH_8(\"elasticsearch\", \"8.17.1\"),\n\n\t/**\n\t * A container image suitable for testing Elasticsearch 9.\n\t */\n\tELASTICSEARCH_9(\"elasticsearch\", \"9.0.2\"),\n\n\t/**\n\t * A container image suitable for testing Grafana OTel LGTM.\n\t */\n\tGRAFANA_OTEL_LGTM(\"grafana/otel-lgtm\", \"0.6.0\", () -> LgtmStackContainer.class,\n\t\t\t(container) -> ((LgtmStackContainer) container).withStartupTimeout(Duration.ofMinutes(2))),\n\n\t/**\n\t * A container image suitable for testing Hazelcast.\n\t */\n\tHAZELCAST(\"hazelcast/hazelcast\", \"5.5.0-slim-jdk17\", () -> HazelcastContainer.class),\n\n\t/**\n\t * A container image suitable for testing Confluent's distribution of Kafka.\n\t */\n\tCONFLUENT_KAFKA(\"confluentinc/cp-kafka\", \"7.4.0\", () -> ConfluentKafkaContainer.class),\n\n\t/**\n\t * A container image suitable for testing LLDAP.\n\t */\n\tLLDAP(\"lldap/lldap\", \"v0.6.1-alpine\", () -> LLdapContainer.class),\n\n\t/**\n\t * A container image suitable for testing OpenLDAP.\n\t */\n\tOPEN_LDAP(\"osixia/openldap\", \"1.5.0\", () -> OpenLdapContainer.class),\n\n\t/**\n\t * A container image suitable for testing SMTP.\n\t */\n\tMAILPIT(\"axllent/mailpit\", \"v1.19.0\", () -> MailpitContainer.class),\n\n\t/**\n\t * A container image suitable for testing MariaDB.\n\t */\n\tMARIADB(\"mariadb\", \"10.10\", () -> MariaDBContainer.class),\n\n\t/**\n\t * A container image suitable for testing MongoDB.\n\t */\n\tMONGODB(\"mongo\", \"5.0.17\", () -> MongoDBContainer.class,\n\t\t\t(container) -> ((MongoDBContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(5))),\n\n\t/**\n\t * A container image suitable for testing MongoDB using the deprecated\n\t * {@link org.testcontainers.containers.MongoDBContainer}.\n\t * @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #MONGODB}\n\t */\n\t@SuppressWarnings(\"deprecation\")\n\t@Deprecated(since = \"3.4.0\", forRemoval = true)\n\tMONGODB_DEPRECATED(\"mongo\", \"5.0.17\", () -> org.testcontainers.containers.MongoDBContainer.class,\n\t\t\t(container) -> ((org.testcontainers.containers.MongoDBContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(5))),\n\n\t/**\n\t * A container image suitable for testing MongoDB Atlas.\n\t */\n\tMONGODB_ATLAS(\"mongodb/mongodb-atlas-local\", \"8.0.4\", () -> MongoDBAtlasLocalContainer.class,\n\t\t\t(container) -> ((MongoDBAtlasLocalContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(5))),\n\n\t/**\n\t * A container image suitable for testing MySQL.\n\t */\n\tMYSQL(\"mysql\", \"8.0\", () -> MySQLContainer.class),\n\n\t/**\n\t * A container image suitable for testing Neo4j.\n\t */\n\tNEO4J(\"neo4j\", \"5.26.11\", () -> Neo4jContainer.class,\n\t\t\t(container) -> ((Neo4jContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Neo4j using the deprecated\n\t * {@link org.testcontainers.containers.Neo4jContainer}.\n\t * @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #NEO4J}\n\t */\n\t@SuppressWarnings({ \"deprecation\", \"rawtypes\" })\n\t@Deprecated(since = \"3.4.0\", forRemoval = true)\n\tNEO4J_DEPRECATED(\"neo4j\", \"5.26.11\", () -> org.testcontainers.containers.Neo4jContainer.class,\n\t\t\t(container) -> ((org.testcontainers.containers.Neo4jContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Oracle Free.\n\t */\n\tORACLE_FREE(\"gvenzl/oracle-free\", \"23.6-slim\", () -> org.testcontainers.oracle.OracleContainer.class,\n\t\t\t(container) -> ((org.testcontainers.oracle.OracleContainer) container)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(2))),\n\n\t/**\n\t * A container image suitable for testing Oracle XA.\n\t */\n\tORACLE_XE(\"gvenzl/oracle-xe\", \"18.4.0-slim\", () -> org.testcontainers.containers.OracleContainer.class,\n\t\t\t(container) -> ((org.testcontainers.containers.OracleContainer) container)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(2))),\n\n\t/**\n\t * A container image suitable for testing OpenTelemetry using the OpenTelemetry\n\t * collector.\n\t */\n\tOTEL_COLLECTOR(\"otel/opentelemetry-collector-contrib\", \"0.75.0\"),\n\n\t/**\n\t * A container image suitable for testing Postgres.\n\t */\n\tPOSTGRESQL(\"postgres\", \"14.0\", () -> PostgreSQLContainer.class),\n\n\t/**\n\t * A container image suitable for testing Pulsar.\n\t */\n\tPULSAR(\"apachepulsar/pulsar\", \"3.3.3\", () -> PulsarContainer.class,\n\t\t\t(container) -> ((PulsarContainer) container).withStartupAttempts(2)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(3))),\n\n\t/**\n\t * A container image suitable for testing Pulsar using the deprecated\n\t * {@link org.testcontainers.containers.PulsarContainer}.\n\t * @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #PULSAR}\n\t */\n\t@SuppressWarnings(\"deprecation\")\n\t@Deprecated(since = \"3.4.0\", forRemoval = true)\n\tPULSAR_DEPRECATED(\"apachepulsar/pulsar\", \"3.3.3\", () -> org.testcontainers.containers.PulsarContainer.class,\n\t\t\t(container) -> ((org.testcontainers.containers.PulsarContainer) container).withStartupAttempts(2)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(3))),\n\n\t/**\n\t * A container image suitable for testing RabbitMQ.\n\t */\n\tRABBITMQ(\"rabbitmq\", \"3.11-alpine\", () -> RabbitMQContainer.class,\n\t\t\t(container) -> ((RabbitMQContainer) container).withStartupTimeout(Duration.ofMinutes(4))),\n\n\t/**\n\t * A container image suitable for testing RabbitMQ using the deprecated\n\t * {@link org.testcontainers.containers.RabbitMQContainer}.\n\t * @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #RABBITMQ}\n\t */\n\t@SuppressWarnings(\"deprecation\")\n\t@Deprecated(since = \"3.4.0\", forRemoval = true)\n\tRABBITMQ_DEPRECATED(\"rabbitmq\", \"3.11-alpine\", () -> org.testcontainers.containers.RabbitMQContainer.class,\n\t\t\t(container) -> ((org.testcontainers.containers.RabbitMQContainer) container)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(4))),\n\n\t/**\n\t * A container image suitable for testing Redis.\n\t */\n\tREDIS(\"redis\", \"7.0.11\", () -> RedisContainer.class,\n\t\t\t(container) -> ((RedisContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Redis Stack.\n\t */\n\tREDIS_STACK(\"redis/redis-stack\", \"7.2.0-v11\", () -> RedisStackContainer.class,\n\t\t\t(container) -> ((RedisStackContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Redis Stack Server.\n\t */\n\tREDIS_STACK_SERVER(\"redis/redis-stack-server\", \"7.2.0-v11\", () -> RedisStackServerContainer.class,\n\t\t\t(container) -> ((RedisStackServerContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(10))),\n\n\t/**\n\t * A container image suitable for testing Redpanda.\n\t */\n\tREDPANDA(\"redpandadata/redpanda\", \"v23.1.2\", () -> RedpandaContainer.class,\n\t\t\t(container) -> ((RedpandaContainer) container).withStartupTimeout(Duration.ofMinutes(5))),\n\n\t/**\n\t * A container image suitable for testing Docker Registry.\n\t */\n\tREGISTRY(\"registry\", \"2.7.1\", () -> RegistryContainer.class,\n\t\t\t(container) -> ((RegistryContainer) container).withStartupAttempts(5)\n\t\t\t\t.withStartupTimeout(Duration.ofMinutes(3))),\n\n\t/**\n\t * A container image suitable for testing MS SQL Server.\n\t */\n\tSQL_SERVER(\"mcr.microsoft.com/mssql/server\"),\n\n\t/**\n\t * A container image suitable for testing Zipkin.\n\t */\n\tZIPKIN(\"openzipkin/zipkin\", \"3.0.6\", () -> ZipkinContainer.class);\n\n\tprivate final String name;\n\n\tprivate final String tag;\n\n\tprivate final Class<?> containerClass;\n\n\tprivate final Consumer<?> containerSetup;\n\n\tTestImage(String name) {\n\t\tthis(name, null);\n\t}\n\n\tTestImage(String name, String tag) {\n\t\tthis(name, tag, null, null);\n\t}\n\n\tTestImage(String name, String tag, Supplier<Class<?>> containerClass) {\n\t\tthis(name, tag, containerClass, null);\n\t}\n\n\tTestImage(String name, String tag, Consumer<?> containerSetup) {\n\t\tthis(name, tag, null, containerSetup);\n\t}\n\n\tTestImage(String name, String tag, Supplier<Class<?>> containerClass, Consumer<?> containerSetup) {\n\t\tthis.name = name;\n\t\tthis.tag = tag;\n\t\tthis.containerClass = getIfPossible(containerClass);\n\t\tthis.containerSetup = containerSetup;\n\t}\n\n\tstatic Class<?> getIfPossible(Supplier<Class<?>> supplier) {\n\t\ttry {\n\t\t\treturn (supplier != null) ? supplier.get() : null;\n\t\t}\n\t\tcatch (NoClassDefFoundError ex) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate boolean matchesContainerClass(Class<?> containerClass) {\n\t\treturn this.containerClass != null && this.containerClass.isAssignableFrom(containerClass);\n\t}\n\n\t/**\n\t * Create a {@link GenericContainer} for the given {@link TestImage}.\n\t * @return a generic container for the test image\n\t */\n\tpublic GenericContainer<?> genericContainer() {\n\t\treturn createContainer(GenericContainer.class);\n\t}\n\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tprivate <C extends Container<?>> C createContainer(Class<C> containerClass) {\n\t\tDockerImageName dockerImageName = DockerImageName.parse(toString());\n\t\ttry {\n\t\t\tConstructor<C> constructor = containerClass.getDeclaredConstructor(DockerImageName.class);\n\t\t\tconstructor.setAccessible(true);\n\t\t\tC container = constructor.newInstance(dockerImageName);\n\t\t\tif (this.containerSetup != null) {\n\t\t\t\t((Consumer) this.containerSetup).accept(container);\n\t\t\t}\n\t\t\treturn container;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to create container \" + containerClass, ex);\n\t\t}\n\t}\n\n\tpublic String getTag() {\n\t\treturn this.tag;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn (this.tag != null) ? this.name + \":\" + this.tag : this.name;\n\t}\n\n\t/**\n\t * Factory method to create and configure a {@link Container} using a deduced\n\t * {@link TestImage}.\n\t * @param <C> the container type\n\t * @param containerClass the container type\n\t * @return a container instance\n\t */\n\tpublic static <C extends Container<?>> C container(Class<C> containerClass) {\n\t\treturn forContainerClass(containerClass).createContainer(containerClass);\n\t}\n\n\tprivate static TestImage forContainerClass(Class<?> containerClass) {\n\t\tList<TestImage> images = Arrays.stream(values())\n\t\t\t.filter((image) -> image.matchesContainerClass(containerClass))\n\t\t\t.toList();\n\t\tAssert.state(!images.isEmpty(), () -> \"Unknown container class \" + containerClass);\n\t\tAssert.state(images.size() == 1, () -> \"Multiple test images match container class \" + containerClass);\n\t\treturn images.get(0);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/ZipkinContainer.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.container;\n\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.utility.DockerImageName;\n\n/**\n * A {@link GenericContainer} for Zipkin.\n *\n * @author Phillip Webb\n */\npublic class ZipkinContainer extends GenericContainer<ZipkinContainer> {\n\n\tpublic ZipkinContainer(DockerImageName dockerImageName) {\n\t\tsuper(dockerImageName);\n\t\twithExposedPorts(9411);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support for testing with Testcontainers.\n */\npackage org.springframework.boot.testsupport.container;\n"
  },
  {
    "path": "test-support/spring-boot-gradle-test-support/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n}\n\ndescription = \"Spring Boot Gradle Testing Support\"\n\ndependencies {\n\tapi(project(\":test-support:spring-boot-test-support\"))\n\n\tcompileOnly(\"org.junit.jupiter:junit-jupiter\")\n\n\timplementation(gradleTestKit())\n\timplementation(\"io.spring.gradle:dependency-management-plugin\")\n\timplementation(\"org.assertj:assertj-core\")\n\timplementation(\"org.springframework:spring-core\")\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "test-support/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/Dsl.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.gradle.testkit;\n\n/**\n * The DSLs supported by Gradle and demonstrated in the documentation samples.\n *\n * @author Andy Wilkinson\n */\npublic enum Dsl {\n\n\t/**\n\t * Supported DSL variants.\n\t */\n\tGROOVY(\"Groovy\", \".gradle\"), KOTLIN(\"Kotlin\", \".gradle.kts\");\n\n\tprivate final String name;\n\n\tprivate final String extension;\n\n\tDsl(String name, String extension) {\n\t\tthis.name = name;\n\t\tthis.extension = extension;\n\t}\n\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\tString getExtension() {\n\t\treturn this.extension;\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuild.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.gradle.testkit;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Properties;\nimport java.util.jar.JarFile;\n\nimport io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension;\nimport org.gradle.testkit.runner.BuildResult;\nimport org.gradle.testkit.runner.GradleRunner;\nimport org.gradle.util.GradleVersion;\n\nimport org.springframework.boot.testsupport.BuildOutput;\nimport org.springframework.util.FileCopyUtils;\nimport org.springframework.util.FileSystemUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * A {@code GradleBuild} is used to run a Gradle build using {@link GradleRunner}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic class GradleBuild {\n\n\tprivate final BuildOutput buildOutput;\n\n\tprivate final Dsl dsl;\n\n\tprivate File projectDir;\n\n\tprivate String script;\n\n\tprivate String settings;\n\n\tprivate String gradleVersion;\n\n\tprivate String springBootVersion = \"TEST-SNAPSHOT\";\n\n\tprivate GradleVersion expectDeprecationWarnings;\n\n\tprivate final List<String> expectedDeprecationMessages = new ArrayList<>();\n\n\tprivate boolean configurationCache;\n\n\tprivate final Map<String, String> scriptProperties = new HashMap<>();\n\n\tpublic GradleBuild(BuildOutput buildOutput) {\n\t\tthis(buildOutput, Dsl.GROOVY);\n\t}\n\n\tprotected GradleBuild(BuildOutput buildOutput, Dsl dsl) {\n\t\tthis.buildOutput = buildOutput;\n\t\tthis.dsl = dsl;\n\t}\n\n\tpublic Dsl getDsl() {\n\t\treturn this.dsl;\n\t}\n\n\tvoid before() throws IOException {\n\t\tthis.projectDir = Files.createTempDirectory(\"gradle-\").toFile();\n\t}\n\n\tvoid after() {\n\t\tthis.script = null;\n\t\tFileSystemUtils.deleteRecursively(this.projectDir);\n\t}\n\n\tpublic GradleBuild script(String script) {\n\t\tthis.script = script.endsWith(this.dsl.getExtension()) ? script : script + this.dsl.getExtension();\n\t\treturn this;\n\t}\n\n\tpublic void settings(String settings) {\n\t\tthis.settings = settings;\n\t}\n\n\tpublic GradleBuild expectDeprecationWarningsWithAtLeastVersion(String gradleVersion) {\n\t\tthis.expectDeprecationWarnings = GradleVersion.version(gradleVersion);\n\t\treturn this;\n\t}\n\n\tpublic GradleBuild expectDeprecationMessages(String... messages) {\n\t\tthis.expectedDeprecationMessages.addAll(Arrays.asList(messages));\n\t\treturn this;\n\t}\n\n\tpublic GradleBuild configurationCache() {\n\t\tthis.configurationCache = true;\n\t\treturn this;\n\t}\n\n\tpublic boolean isConfigurationCache() {\n\t\treturn this.configurationCache;\n\t}\n\n\tpublic GradleBuild scriptProperty(String key, String value) {\n\t\tthis.scriptProperties.put(key, value);\n\t\treturn this;\n\t}\n\n\tpublic GradleBuild scriptPropertyFrom(File propertiesFile, String key) {\n\t\tthis.scriptProperties.put(key, getProperty(propertiesFile, key));\n\t\treturn this;\n\t}\n\n\tpublic boolean gradleVersionIsAtLeast(String version) {\n\t\treturn GradleVersion.version(this.gradleVersion).compareTo(GradleVersion.version(version)) >= 0;\n\t}\n\n\tpublic boolean gradleVersionIsLessThan(String version) {\n\t\treturn GradleVersion.version(this.gradleVersion).compareTo(GradleVersion.version(version)) < 0;\n\t}\n\n\tpublic BuildResult build(String... arguments) {\n\t\ttry {\n\t\t\tBuildResult result = prepareRunner(arguments).build();\n\t\t\tif (this.expectDeprecationWarnings == null || (this.gradleVersion != null\n\t\t\t\t\t&& this.expectDeprecationWarnings.compareTo(GradleVersion.version(this.gradleVersion)) > 0)) {\n\t\t\t\tString buildOutput = result.getOutput();\n\t\t\t\tfor (String message : this.expectedDeprecationMessages) {\n\t\t\t\t\tbuildOutput = buildOutput.replaceAll(message, \"\");\n\t\t\t\t}\n\t\t\t\tassertThat(buildOutput).doesNotContainIgnoringCase(\"deprecated\");\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tpublic BuildResult buildAndFail(String... arguments) {\n\t\ttry {\n\t\t\treturn prepareRunner(arguments).buildAndFail();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tpublic GradleRunner prepareRunner(String... arguments) throws IOException {\n\t\tthis.scriptProperties.put(\"bootVersion\", getBootVersion());\n\t\tthis.scriptProperties.put(\"dependencyManagementPluginVersion\", getDependencyManagementPluginVersion());\n\t\tcopyTransformedScript(this.script, new File(this.projectDir, \"build\" + this.dsl.getExtension()));\n\t\tif (this.settings != null) {\n\t\t\tcopyTransformedScript(this.settings, new File(this.projectDir, \"settings.gradle\"));\n\t\t}\n\t\tFile repository = new File(\"src/test/resources/repository\");\n\t\tif (repository.exists()) {\n\t\t\tFileSystemUtils.copyRecursively(repository, new File(this.projectDir, \"repository\"));\n\t\t}\n\t\tGradleRunner gradleRunner = GradleRunner.create().withProjectDir(this.projectDir);\n\t\tif (!this.configurationCache) {\n\t\t\t// See https://github.com/gradle/gradle/issues/14125\n\t\t\tgradleRunner.withDebug(true);\n\t\t}\n\t\tif (this.gradleVersion != null) {\n\t\t\tgradleRunner.withGradleVersion(this.gradleVersion);\n\t\t}\n\t\tgradleRunner.withTestKitDir(getTestKitDir());\n\t\tList<String> allArguments = new ArrayList<>();\n\t\tallArguments.add(\"-PbootVersion=\" + getBootVersion());\n\t\tallArguments.add(\"--stacktrace\");\n\t\tallArguments.addAll(Arrays.asList(arguments));\n\t\tallArguments.add(\"--warning-mode\");\n\t\tallArguments.add(\"all\");\n\t\tif (this.configurationCache) {\n\t\t\tallArguments.add(\"--configuration-cache\");\n\t\t}\n\t\treturn gradleRunner.withArguments(allArguments);\n\t}\n\n\tprivate void copyTransformedScript(String script, File destination) throws IOException {\n\t\tString scriptContent = FileCopyUtils.copyToString(new FileReader(script));\n\t\tfor (Entry<String, String> property : this.scriptProperties.entrySet()) {\n\t\t\tscriptContent = scriptContent.replace(\"{\" + property.getKey() + \"}\", property.getValue());\n\t\t}\n\t\tFileCopyUtils.copy(scriptContent, new FileWriter(destination));\n\t}\n\n\tprivate File getTestKitDir() {\n\t\tFile build = this.buildOutput.getRootLocation();\n\t\tFile testKitRoot = new File(build, \"gradle-test-kit\");\n\t\tString gradleVersion = (this.gradleVersion != null) ? this.gradleVersion : \"default\";\n\t\treturn new File(testKitRoot, gradleVersion).getAbsoluteFile();\n\t}\n\n\tpublic File getProjectDir() {\n\t\treturn this.projectDir;\n\t}\n\n\tpublic void setProjectDir(File projectDir) {\n\t\tthis.projectDir = projectDir;\n\t}\n\n\tpublic GradleBuild gradleVersion(String version) {\n\t\tthis.gradleVersion = version;\n\t\treturn this;\n\t}\n\n\tpublic String getGradleVersion() {\n\t\treturn this.gradleVersion;\n\t}\n\n\tpublic GradleBuild bootVersion(String version) {\n\t\tthis.springBootVersion = version;\n\t\treturn this;\n\t}\n\n\tprivate String getBootVersion() {\n\t\treturn this.springBootVersion;\n\t}\n\n\tprivate static String getDependencyManagementPluginVersion() {\n\t\ttry {\n\t\t\tURL location = DependencyManagementExtension.class.getProtectionDomain().getCodeSource().getLocation();\n\t\t\ttry (JarFile jar = new JarFile(new File(location.toURI()))) {\n\t\t\t\treturn jar.getManifest().getMainAttributes().getValue(\"Implementation-Version\");\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalStateException(\"Failed to find dependency management plugin version\", ex);\n\t\t}\n\t}\n\n\tprivate String getProperty(File propertiesFile, String key) {\n\t\ttry {\n\t\t\tassertThat(propertiesFile)\n\t\t\t\t.withFailMessage(\"Expecting properties file to exist at path '%s'\", propertiesFile.getCanonicalFile())\n\t\t\t\t.exists();\n\t\t\tProperties properties = new Properties();\n\t\t\ttry (FileInputStream input = new FileInputStream(propertiesFile)) {\n\t\t\t\tproperties.load(input);\n\t\t\t\tString value = properties.getProperty(key);\n\t\t\t\tassertThat(value)\n\t\t\t\t\t.withFailMessage(\"Expecting properties file '%s' to contain the key '%s'\",\n\t\t\t\t\t\t\tpropertiesFile.getCanonicalFile(), key)\n\t\t\t\t\t.isNotEmpty();\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tfail(\"Error reading properties file '\" + propertiesFile + \"'\");\n\t\t\treturn null;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleBuildExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.gradle.testkit;\n\nimport java.io.File;\nimport java.lang.reflect.Field;\nimport java.net.URL;\nimport java.util.regex.Pattern;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * An {@link Extension} for managing the lifecycle of a {@link GradleBuild} stored in a\n * field named {@code gradleBuild}.\n *\n * @author Andy Wilkinson\n * @author Scott Frederick\n */\npublic class GradleBuildExtension implements BeforeEachCallback, AfterEachCallback {\n\n\tprivate static final Pattern GRADLE_VERSION_PATTERN = Pattern.compile(\"\\\\[Gradle .+]\");\n\n\tprivate final Dsl dsl = Dsl.GROOVY;\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tGradleBuild gradleBuild = extractGradleBuild(context);\n\t\tgradleBuild.scriptProperty(\"parentRootDir\", findParentRootDir().getAbsolutePath());\n\t\tURL scriptUrl = findDefaultScript(context);\n\t\tif (scriptUrl != null) {\n\t\t\tgradleBuild.script(scriptUrl.getFile());\n\t\t}\n\t\tURL settingsUrl = getSettings(context);\n\t\tif (settingsUrl != null) {\n\t\t\tgradleBuild.settings(settingsUrl.getFile());\n\t\t}\n\t\tgradleBuild.before();\n\t}\n\n\tprivate File findParentRootDir() {\n\t\tFile dir = new File(\"\").getAbsoluteFile();\n\t\tint depth = 0;\n\t\twhile (dir != null && !hasGradleBuildFiles(dir)) {\n\t\t\tAssert.state(depth++ < 5, \"Unable to find parent root\");\n\t\t\tdir = dir.getParentFile();\n\t\t}\n\t\tAssert.state(dir != null, \"Unable to find parent root\");\n\t\treturn dir;\n\t}\n\n\tprivate boolean hasGradleBuildFiles(File dir) {\n\t\treturn new File(dir, \"settings.gradle\").exists() && new File(dir, \"build.gradle\").exists()\n\t\t\t\t&& new File(dir, \"gradle.properties\").exists();\n\t}\n\n\tprivate GradleBuild extractGradleBuild(ExtensionContext context) throws Exception {\n\t\tObject testInstance = context.getRequiredTestInstance();\n\t\tField gradleBuildField = ReflectionUtils.findField(testInstance.getClass(), \"gradleBuild\");\n\t\tgradleBuildField.setAccessible(true);\n\t\tGradleBuild gradleBuild = (GradleBuild) gradleBuildField.get(testInstance);\n\t\treturn gradleBuild;\n\t}\n\n\tprivate URL findDefaultScript(ExtensionContext context) {\n\t\tURL scriptUrl = getScriptForTestMethod(context);\n\t\tif (scriptUrl != null) {\n\t\t\treturn scriptUrl;\n\t\t}\n\t\treturn getScriptForTestClass(context.getRequiredTestClass());\n\t}\n\n\tprivate URL getScriptForTestMethod(ExtensionContext context) {\n\t\tClass<?> testClass = context.getRequiredTestClass();\n\t\tString name = testClass.getSimpleName() + \"-\" + removeGradleVersion(context.getRequiredTestMethod().getName())\n\t\t\t\t+ this.dsl.getExtension();\n\t\treturn testClass.getResource(name);\n\t}\n\n\tprivate String removeGradleVersion(String methodName) {\n\t\treturn GRADLE_VERSION_PATTERN.matcher(methodName).replaceAll(\"\").trim();\n\t}\n\n\tprivate URL getScriptForTestClass(Class<?> testClass) {\n\t\treturn testClass.getResource(testClass.getSimpleName() + this.dsl.getExtension());\n\t}\n\n\tprivate URL getSettings(ExtensionContext context) {\n\t\tClass<?> testClass = context.getRequiredTestClass();\n\t\treturn testClass.getResource(\"settings.gradle\");\n\t}\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\textractGradleBuild(context).after();\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/GradleVersions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.gradle.testkit;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.gradle.api.JavaVersion;\nimport org.gradle.util.GradleVersion;\n\n/**\n * Versions of Gradle used for testing.\n *\n * @author Scott Frederick\n */\npublic final class GradleVersions {\n\n\tprivate GradleVersions() {\n\t}\n\n\tpublic static List<String> allCompatible() {\n\t\tif (isJavaVersion(JavaVersion.VERSION_26)) {\n\t\t\treturn Arrays.asList(\"9.4.0-rc-1\");\n\t\t}\n\t\tif (isJavaVersion(JavaVersion.VERSION_25)) {\n\t\t\treturn Arrays.asList(\"9.0.0\", GradleVersion.current().getVersion());\n\t\t}\n\t\treturn Arrays.asList(\"8.14.3\", \"9.0.0\", GradleVersion.current().getVersion());\n\t}\n\n\tpublic static String minimumCompatible() {\n\t\treturn allCompatible().get(0);\n\t}\n\n\tpublic static String maximumCompatible() {\n\t\tList<String> versions = allCompatible();\n\t\treturn versions.get(versions.size() - 1);\n\t}\n\n\tprivate static boolean isJavaVersion(JavaVersion version) {\n\t\treturn JavaVersion.current().isCompatibleWith(version);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-gradle-test-support/src/main/java/org/springframework/boot/testsupport/gradle/testkit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for testing with Gradle.\n */\npackage org.springframework.boot.testsupport.gradle.testkit;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/build.gradle",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the License);\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nplugins {\n\tid \"java-library\"\n\tid \"org.springframework.boot.optional-dependencies\"\n}\n\ndescription = \"Spring Boot Testing Support\"\n\ndependencies {\n\tapi(platform(project(path: \":platform:spring-boot-internal-dependencies\")))\n\tapi(\"com.jayway.jsonpath:json-path\")\n\tapi(\"org.assertj:assertj-core\")\n\tapi(\"org.awaitility:awaitility\")\n\tapi(\"org.hamcrest:hamcrest-core\")\n\tapi(\"org.hamcrest:hamcrest-library\")\n\tapi(\"org.junit.jupiter:junit-jupiter\")\n\tapi(\"org.mockito:mockito-core\")\n\tapi(\"org.mockito:mockito-junit-jupiter\")\n\tapi(\"org.skyscreamer:jsonassert\")\n\tapi(\"org.springframework:spring-core\")\n\tapi(\"org.springframework:spring-test\")\n\tapi(\"org.springframework:spring-core-test\")\n\n\tcompileOnly(\"org.apache.cassandra:java-driver-core\") {\n\t\texclude(group: \"org.slf4j\", module: \"jcl-over-slf4j\")\n\t}\n\tcompileOnly(\"jakarta.servlet:jakarta.servlet-api\")\n\tcompileOnly(\"junit:junit\")\n\tcompileOnly(\"org.junit.platform:junit-platform-engine\")\n\tcompileOnly(\"org.junit.platform:junit-platform-launcher\")\n\tcompileOnly(\"org.springframework:spring-context\")\n\tcompileOnly(\"org.springframework.data:spring-data-redis\")\n\n\timplementation(\"jakarta.inject:jakarta.inject-api\")\n\timplementation(\"org.apache.maven.resolver:maven-resolver-connector-basic\")\n\timplementation(\"org.apache.maven.resolver:maven-resolver-impl\")\n\timplementation(\"org.apache.maven:maven-resolver-provider\") {\n\t\texclude(group: \"javax.inject\", module: \"javax.inject\")\n\t}\n\timplementation(\"org.apache.maven.resolver:maven-resolver-transport-http\") {\n\t\texclude group: \"org.slf4j\", module: \"jcl-over-slf4j\"\n\t}\n\n\ttestImplementation(\"jakarta.servlet:jakarta.servlet-api\")\n\ttestImplementation(\"org.springframework:spring-context\")\n\n\ttestRuntimeOnly(\"org.hibernate.validator:hibernate-validator\")\n}\n\nnullability {\n\trequireExplicitNullMarking = false\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/BuildOutput.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport;\n\nimport java.io.File;\nimport java.net.URISyntaxException;\n\n/**\n * Provides access to build output locations in a build system and IDE agnostic manner.\n *\n * @author Andy Wilkinson\n */\npublic class BuildOutput {\n\n\tprivate final Class<?> testClass;\n\n\tpublic BuildOutput(Class<?> testClass) {\n\t\tthis.testClass = testClass;\n\t}\n\n\t/**\n\t * Returns the location into which test classes have been built.\n\t * @return test classes location\n\t */\n\tpublic File getTestClassesLocation() {\n\t\ttry {\n\t\t\tFile location = new File(this.testClass.getProtectionDomain().getCodeSource().getLocation().toURI());\n\t\t\tif (location.getPath().endsWith(path(\"bin\", \"test\")) || location.getPath().endsWith(path(\"bin\", \"intTest\"))\n\t\t\t\t\t|| location.getPath().endsWith(path(\"build\", \"classes\", \"java\", \"test\"))\n\t\t\t\t\t|| location.getPath().endsWith(path(\"build\", \"classes\", \"java\", \"intTest\"))) {\n\t\t\t\treturn location;\n\t\t\t}\n\t\t\tthrow new IllegalStateException(\"Unexpected test classes location '\" + location + \"'\");\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new IllegalStateException(\"Invalid test class code source location\", ex);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the location into which test resources have been built.\n\t * @return test resources location\n\t */\n\tpublic File getTestResourcesLocation() {\n\t\tFile testClassesLocation = getTestClassesLocation();\n\t\tif (testClassesLocation.getPath().endsWith(path(\"bin\", \"test\"))\n\t\t\t\t|| testClassesLocation.getPath().endsWith(path(\"bin\", \"intTest\"))) {\n\t\t\treturn testClassesLocation;\n\t\t}\n\t\tif (testClassesLocation.getPath().endsWith(path(\"build\", \"classes\", \"java\", \"test\"))) {\n\t\t\treturn new File(testClassesLocation.getParentFile().getParentFile().getParentFile(), \"resources/test\");\n\t\t}\n\t\tif (testClassesLocation.getPath().endsWith(path(\"build\", \"classes\", \"java\", \"intTest\"))) {\n\t\t\treturn new File(testClassesLocation.getParentFile().getParentFile().getParentFile(), \"resources/intTest\");\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"Cannot determine test resources location from classes location '\" + testClassesLocation + \"'\");\n\t}\n\n\t/**\n\t * Returns the root location into which build output is written.\n\t * @return root location\n\t */\n\tpublic File getRootLocation() {\n\t\treturn new File(\"build\");\n\t}\n\n\tprivate String path(String... components) {\n\t\treturn File.separator + String.join(File.separator, components);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/FileUtils.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HexFormat;\n\n/**\n * Utilities when working with {@link File files}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic abstract class FileUtils {\n\n\tprivate static final int BUFFER_SIZE = 32 * 1024;\n\n\t/**\n\t * Generate a SHA-1 Hash for a given file.\n\t * @param file the file to hash\n\t * @return the hash value as a String\n\t * @throws IOException if the file cannot be read\n\t */\n\tpublic static String sha1Hash(File file) throws IOException {\n\t\ttry {\n\t\t\tMessageDigest messageDigest = MessageDigest.getInstance(\"SHA-1\");\n\t\t\ttry (InputStream inputStream = new FileInputStream(file)) {\n\t\t\t\tbyte[] buffer = new byte[BUFFER_SIZE];\n\t\t\t\tint bytesRead;\n\t\t\t\twhile ((bytesRead = inputStream.read(buffer)) != -1) {\n\t\t\t\t\tmessageDigest.update(buffer, 0, bytesRead);\n\t\t\t\t}\n\t\t\t\treturn HexFormat.of().formatHex(messageDigest.digest());\n\t\t\t}\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/ScheduledExecutorServiceAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.assertj;\n\nimport java.lang.reflect.Method;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.Assert;\n\nimport org.springframework.lang.CheckReturnValue;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * AssertJ {@link Assert} for {@link ScheduledExecutorService}.\n *\n * @author Mike Turbe\n * @author Moritz Halbritter\n */\npublic final class ScheduledExecutorServiceAssert\n\t\textends AbstractAssert<ScheduledExecutorServiceAssert, ScheduledExecutorService> {\n\n\tprivate ScheduledExecutorServiceAssert(ScheduledExecutorService actual) {\n\t\tsuper(actual, ScheduledExecutorServiceAssert.class);\n\t}\n\n\t/**\n\t * Verifies that the actual executor uses platform threads.\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual executor doesn't use platform threads\n\t */\n\tpublic ScheduledExecutorServiceAssert usesPlatformThreads() {\n\t\tisNotNull();\n\t\tif (producesVirtualThreads()) {\n\t\t\tfailWithMessage(\"Expected executor to use platform threads, but it uses virtual threads\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the actual executor uses virtual threads.\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual executor doesn't use virtual threads\n\t */\n\tpublic ScheduledExecutorServiceAssert usesVirtualThreads() {\n\t\tisNotNull();\n\t\tif (!producesVirtualThreads()) {\n\t\t\tfailWithMessage(\"Expected executor to use virtual threads, but it uses platform threads\");\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate boolean producesVirtualThreads() {\n\t\ttry {\n\t\t\treturn this.actual.schedule(() -> {\n\t\t\t\tMethod isVirtual = ReflectionUtils.findMethod(Thread.class, \"isVirtual\");\n\t\t\t\tif (isVirtual == null) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn (boolean) ReflectionUtils.invokeMethod(isVirtual, Thread.currentThread());\n\t\t\t}, 0, TimeUnit.SECONDS).get();\n\t\t}\n\t\tcatch (InterruptedException | ExecutionException ex) {\n\t\t\tthrow new AssertionError(ex);\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new assertion instance with the given {@link ScheduledExecutorService}.\n\t * @param actual the {@link ScheduledExecutorService}\n\t * @return the assertion instance\n\t */\n\t@CheckReturnValue\n\tpublic static ScheduledExecutorServiceAssert assertThat(ScheduledExecutorService actual) {\n\t\treturn new ScheduledExecutorServiceAssert(actual);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssert.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.assertj;\n\nimport java.lang.reflect.Field;\n\nimport org.assertj.core.api.AbstractAssert;\nimport org.assertj.core.api.Assert;\n\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\nimport org.springframework.lang.CheckReturnValue;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * AssertJ {@link Assert} for {@link SimpleAsyncTaskExecutor}.\n *\n * @author Moritz Halbritter\n */\npublic final class SimpleAsyncTaskExecutorAssert\n\t\textends AbstractAssert<SimpleAsyncTaskExecutorAssert, SimpleAsyncTaskExecutor> {\n\n\tprivate SimpleAsyncTaskExecutorAssert(SimpleAsyncTaskExecutor actual) {\n\t\tsuper(actual, SimpleAsyncTaskExecutorAssert.class);\n\t}\n\n\t/**\n\t * Verifies that the actual executor uses platform threads.\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual executor doesn't use platform threads\n\t */\n\tpublic SimpleAsyncTaskExecutorAssert usesPlatformThreads() {\n\t\tisNotNull();\n\t\tif (producesVirtualThreads()) {\n\t\t\tfailWithMessage(\"Expected executor to use platform threads, but it uses virtual threads\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Verifies that the actual executor uses virtual threads.\n\t * @return {@code this} assertion object\n\t * @throws AssertionError if the actual executor doesn't use virtual threads\n\t */\n\tpublic SimpleAsyncTaskExecutorAssert usesVirtualThreads() {\n\t\tisNotNull();\n\t\tif (!producesVirtualThreads()) {\n\t\t\tfailWithMessage(\"Expected executor to use virtual threads, but it uses platform threads\");\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate boolean producesVirtualThreads() {\n\t\tField field = ReflectionUtils.findField(SimpleAsyncTaskExecutor.class, \"virtualThreadDelegate\");\n\t\tif (field == null) {\n\t\t\tthrow new IllegalStateException(\"Field SimpleAsyncTaskExecutor.virtualThreadDelegate not found\");\n\t\t}\n\t\tReflectionUtils.makeAccessible(field);\n\t\tObject virtualThreadDelegate = ReflectionUtils.getField(field, this.actual);\n\t\treturn virtualThreadDelegate != null;\n\t}\n\n\t/**\n\t * Creates a new assertion instance with the given {@link SimpleAsyncTaskExecutor}.\n\t * @param actual the {@link SimpleAsyncTaskExecutor}\n\t * @return the assertion instance\n\t */\n\t@CheckReturnValue\n\tpublic static SimpleAsyncTaskExecutorAssert assertThat(SimpleAsyncTaskExecutor actual) {\n\t\treturn new SimpleAsyncTaskExecutorAssert(actual);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/assertj/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom AssertJ assertions.\n */\npackage org.springframework.boot.testsupport.assertj;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ClassPathExclusions.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.io.File;\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.core.annotation.AliasFor;\n\n/**\n * Annotation used to exclude entries from the classpath.\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ExtendWith(ModifiedClassPathExtension.class)\npublic @interface ClassPathExclusions {\n\n\t/**\n\t * Alias for {@code files}.\n\t * <p>\n\t * One or more Ant-style patterns that identify entries to be excluded from the class\n\t * path. Matching is performed against an entry's {@link File#getName() file name}.\n\t * For example, to exclude Hibernate Validator from the classpath,\n\t * {@code \"hibernate-validator-*.jar\"} can be used.\n\t * @return the exclusion patterns\n\t */\n\t@AliasFor(\"files\")\n\tString[] value() default {};\n\n\t/**\n\t * One or more Ant-style patterns that identify entries to be excluded from the class\n\t * path. Matching is performed against an entry's {@link File#getName() file name}.\n\t * For example, to exclude Hibernate Validator from the classpath,\n\t * {@code \"hibernate-validator-*.jar\"} can be used.\n\t * @return the exclusion patterns\n\t */\n\t@AliasFor(\"value\")\n\tString[] files() default {};\n\n\t/**\n\t * One or more packages that should be excluded from the classpath.\n\t * @return the excluded packages\n\t */\n\tString[] packages() default {};\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ClassPathOverrides.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Annotation used to override entries on the classpath.\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ExtendWith(ModifiedClassPathExtension.class)\npublic @interface ClassPathOverrides {\n\n\t/**\n\t * One or more sets of Maven coordinates ({@code groupId:artifactId:version}) to be\n\t * added to the classpath. The additions will take precedence over any existing\n\t * classes on the classpath.\n\t * @return the coordinates\n\t */\n\tString[] value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ForkedClassPath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Annotation used to fork the classpath. This can be helpful when using annotations on\n * parameterized tests, or where neither {@link ClassPathExclusions} or\n * {@link ClassPathOverrides} are needed, but just a copy of the classpath.\n *\n * @author Christoph Dreis\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ExtendWith(ModifiedClassPathExtension.class)\npublic @interface ForkedClassPath {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.io.File;\nimport java.lang.management.ManagementFactory;\nimport java.lang.reflect.AnnotatedElement;\nimport java.lang.reflect.Method;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.regex.Pattern;\nimport java.util.stream.Stream;\n\nimport org.apache.maven.repository.internal.MavenRepositorySystemUtils;\nimport org.eclipse.aether.DefaultRepositorySystemSession;\nimport org.eclipse.aether.RepositorySystem;\nimport org.eclipse.aether.artifact.DefaultArtifact;\nimport org.eclipse.aether.collection.CollectRequest;\nimport org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;\nimport org.eclipse.aether.graph.Dependency;\nimport org.eclipse.aether.repository.LocalRepository;\nimport org.eclipse.aether.repository.RemoteRepository;\nimport org.eclipse.aether.resolution.ArtifactResult;\nimport org.eclipse.aether.resolution.DependencyRequest;\nimport org.eclipse.aether.resolution.DependencyResult;\nimport org.eclipse.aether.spi.connector.RepositoryConnectorFactory;\nimport org.eclipse.aether.spi.connector.transport.TransporterFactory;\nimport org.eclipse.aether.transport.http.HttpTransporterFactory;\n\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.util.AntPathMatcher;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.util.ConcurrentReferenceHashMap;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Custom {@link URLClassLoader} that modifies the class path.\n *\n * @author Andy Wilkinson\n * @author Christoph Dreis\n */\nfinal class ModifiedClassPathClassLoader extends URLClassLoader {\n\n\tprivate static final Map<List<AnnotatedElement>, ModifiedClassPathClassLoader> cache = new ConcurrentReferenceHashMap<>();\n\n\tprivate static final Pattern INTELLIJ_CLASSPATH_JAR_PATTERN = Pattern.compile(\".*classpath(\\\\d+)?\\\\.jar\");\n\n\tprivate static final int MAX_RESOLUTION_ATTEMPTS = 5;\n\n\tprivate final Set<String> excludedPackages;\n\n\tprivate final ClassLoader junitLoader;\n\n\tModifiedClassPathClassLoader(URL[] urls, Set<String> excludedPackages, ClassLoader parent,\n\t\t\tClassLoader junitLoader) {\n\t\tsuper(urls, parent);\n\t\tthis.excludedPackages = excludedPackages;\n\t\tthis.junitLoader = junitLoader;\n\t}\n\n\t@Override\n\tpublic Class<?> loadClass(String name) throws ClassNotFoundException {\n\t\tif (name.startsWith(\"org.junit.\") || name.startsWith(\"org.hamcrest.\")\n\t\t\t\t|| name.startsWith(\"io.netty.internal.tcnative.\")) {\n\t\t\treturn Class.forName(name, false, this.junitLoader);\n\t\t}\n\t\tString packageName = ClassUtils.getPackageName(name);\n\t\tif (this.excludedPackages.contains(packageName)) {\n\t\t\tthrow new ClassNotFoundException();\n\t\t}\n\t\treturn super.loadClass(name);\n\t}\n\n\t@SuppressWarnings(\"resource\")\n\tstatic ModifiedClassPathClassLoader get(Class<?> testClass, Method testMethod, List<Object> arguments) {\n\t\tSet<AnnotatedElement> candidates = new LinkedHashSet<>();\n\t\tcandidates.add(testClass);\n\t\tcandidates.add(testMethod);\n\t\tcandidates.addAll(getAnnotatedElements(arguments.toArray()));\n\t\tList<AnnotatedElement> annotatedElements = candidates.stream()\n\t\t\t.filter(ModifiedClassPathClassLoader::hasAnnotation)\n\t\t\t.toList();\n\t\tif (annotatedElements.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\treturn cache.computeIfAbsent(annotatedElements, (key) -> compute(testClass.getClassLoader(), key));\n\t}\n\n\tprivate static Collection<AnnotatedElement> getAnnotatedElements(Object[] array) {\n\t\tSet<AnnotatedElement> result = new LinkedHashSet<>();\n\t\tfor (Object item : array) {\n\t\t\tif (item instanceof AnnotatedElement annotatedElement) {\n\t\t\t\tresult.add(annotatedElement);\n\t\t\t}\n\t\t\telse if (ObjectUtils.isArray(item)) {\n\t\t\t\tresult.addAll(getAnnotatedElements(ObjectUtils.toObjectArray(item)));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static boolean hasAnnotation(AnnotatedElement element) {\n\t\tMergedAnnotations annotations = MergedAnnotations.from(element,\n\t\t\t\tMergedAnnotations.SearchStrategy.TYPE_HIERARCHY);\n\t\treturn annotations.isPresent(ForkedClassPath.class) || annotations.isPresent(ClassPathOverrides.class)\n\t\t\t\t|| annotations.isPresent(ClassPathExclusions.class);\n\t}\n\n\tprivate static ModifiedClassPathClassLoader compute(ClassLoader classLoader,\n\t\t\tList<AnnotatedElement> annotatedClasses) {\n\t\tList<MergedAnnotations> annotations = annotatedClasses.stream()\n\t\t\t.map((source) -> MergedAnnotations.from(source, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY))\n\t\t\t.toList();\n\t\treturn new ModifiedClassPathClassLoader(processUrls(extractUrls(classLoader), annotations),\n\t\t\t\texcludedPackages(annotations), classLoader.getParent(), classLoader);\n\t}\n\n\tprivate static URL[] extractUrls(ClassLoader classLoader) {\n\t\tList<URL> extractedUrls = new ArrayList<>();\n\t\tdoExtractUrls(classLoader).forEach((URL url) -> {\n\t\t\tif (isManifestOnlyJar(url)) {\n\t\t\t\textractedUrls.addAll(extractUrlsFromManifestClassPath(url));\n\t\t\t}\n\t\t\telse {\n\t\t\t\textractedUrls.add(url);\n\t\t\t}\n\t\t});\n\t\treturn extractedUrls.toArray(new URL[0]);\n\t}\n\n\tprivate static Stream<URL> doExtractUrls(ClassLoader classLoader) {\n\t\tif (classLoader instanceof URLClassLoader urlClassLoader) {\n\t\t\treturn Stream.of(urlClassLoader.getURLs());\n\t\t}\n\t\treturn Stream.of(ManagementFactory.getRuntimeMXBean().getClassPath().split(File.pathSeparator))\n\t\t\t.map(ModifiedClassPathClassLoader::toURL);\n\t}\n\n\tprivate static URL toURL(String entry) {\n\t\ttry {\n\t\t\treturn new File(entry).toURI().toURL();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new IllegalArgumentException(ex);\n\t\t}\n\t}\n\n\tprivate static boolean isManifestOnlyJar(URL url) {\n\t\treturn isShortenedIntelliJJar(url);\n\t}\n\n\tprivate static boolean isShortenedIntelliJJar(URL url) {\n\t\tString urlPath = url.getPath();\n\t\tboolean isCandidate = INTELLIJ_CLASSPATH_JAR_PATTERN.matcher(urlPath).matches();\n\t\tif (isCandidate) {\n\t\t\ttry {\n\t\t\t\tAttributes attributes = getManifestMainAttributesFromUrl(url);\n\t\t\t\tString createdBy = attributes.getValue(\"Created-By\");\n\t\t\t\treturn createdBy != null && createdBy.contains(\"IntelliJ\");\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\t// Ignore\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static List<URL> extractUrlsFromManifestClassPath(URL booterJar) {\n\t\tList<URL> urls = new ArrayList<>();\n\t\ttry {\n\t\t\tfor (String entry : getClassPath(booterJar)) {\n\t\t\t\turls.add(new URL(entry));\n\t\t\t}\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t\treturn urls;\n\t}\n\n\tprivate static String[] getClassPath(URL booterJar) throws Exception {\n\t\tAttributes attributes = getManifestMainAttributesFromUrl(booterJar);\n\t\treturn StringUtils.delimitedListToStringArray(attributes.getValue(Attributes.Name.CLASS_PATH), \" \");\n\t}\n\n\tprivate static Attributes getManifestMainAttributesFromUrl(URL url) throws Exception {\n\t\ttry (JarFile jarFile = new JarFile(new File(url.toURI()))) {\n\t\t\treturn jarFile.getManifest().getMainAttributes();\n\t\t}\n\t}\n\n\tprivate static URL[] processUrls(URL[] urls, List<MergedAnnotations> annotations) {\n\t\tClassPathEntryFilter filter = new ClassPathEntryFilter(annotations);\n\t\tList<URL> additionalUrls = getAdditionalUrls(annotations);\n\t\tList<URL> processedUrls = new ArrayList<>(additionalUrls);\n\t\tfor (URL url : urls) {\n\t\t\tif (!filter.isExcluded(url)) {\n\t\t\t\tprocessedUrls.add(url);\n\t\t\t}\n\t\t}\n\t\treturn processedUrls.toArray(new URL[0]);\n\t}\n\n\tprivate static List<URL> getAdditionalUrls(List<MergedAnnotations> annotations) {\n\t\tSet<URL> urls = new LinkedHashSet<>();\n\t\tfor (MergedAnnotations candidate : annotations) {\n\t\t\tMergedAnnotation<ClassPathOverrides> annotation = candidate.get(ClassPathOverrides.class);\n\t\t\tif (annotation.isPresent()) {\n\t\t\t\turls.addAll(resolveCoordinates(annotation.getStringArray(MergedAnnotation.VALUE)));\n\t\t\t}\n\t\t}\n\t\treturn urls.stream().toList();\n\t}\n\n\tprivate static List<URL> resolveCoordinates(String[] coordinates) {\n\t\tException latestFailure = null;\n\t\tRepositorySystem repositorySystem = createRepositorySystem();\n\t\tDefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();\n\t\tsession.setSystemProperties(System.getProperties());\n\t\tLocalRepository localRepository = new LocalRepository(System.getProperty(\"user.home\") + \"/.m2/repository\");\n\t\tRemoteRepository remoteRepository = new RemoteRepository.Builder(\"central\", \"default\",\n\t\t\t\t\"https://repo.maven.apache.org/maven2\")\n\t\t\t.build();\n\t\tsession.setLocalRepositoryManager(repositorySystem.newLocalRepositoryManager(session, localRepository));\n\t\tfor (int i = 0; i < MAX_RESOLUTION_ATTEMPTS; i++) {\n\t\t\tCollectRequest collectRequest = new CollectRequest(null, Arrays.asList(remoteRepository));\n\t\t\tcollectRequest.setDependencies(createDependencies(coordinates));\n\t\t\tDependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null);\n\t\t\ttry {\n\t\t\t\tDependencyResult result = repositorySystem.resolveDependencies(session, dependencyRequest);\n\t\t\t\tList<URL> resolvedArtifacts = new ArrayList<>();\n\t\t\t\tfor (ArtifactResult artifact : result.getArtifactResults()) {\n\t\t\t\t\tresolvedArtifacts.add(artifact.getArtifact().getFile().toURI().toURL());\n\t\t\t\t}\n\t\t\t\treturn resolvedArtifacts;\n\t\t\t}\n\t\t\tcatch (Exception ex) {\n\t\t\t\tlatestFailure = ex;\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\"Resolution failed after \" + MAX_RESOLUTION_ATTEMPTS + \" attempts\",\n\t\t\t\tlatestFailure);\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static RepositorySystem createRepositorySystem() {\n\t\torg.eclipse.aether.impl.DefaultServiceLocator serviceLocator = MavenRepositorySystemUtils.newServiceLocator();\n\t\tserviceLocator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);\n\t\tserviceLocator.addService(TransporterFactory.class, HttpTransporterFactory.class);\n\t\tRepositorySystem repositorySystem = serviceLocator.getService(RepositorySystem.class);\n\t\treturn repositorySystem;\n\t}\n\n\tprivate static List<Dependency> createDependencies(String[] allCoordinates) {\n\t\tList<Dependency> dependencies = new ArrayList<>();\n\t\tfor (String coordinate : allCoordinates) {\n\t\t\tdependencies.add(new Dependency(new DefaultArtifact(coordinate), null));\n\t\t}\n\t\treturn dependencies;\n\t}\n\n\tprivate static Set<String> excludedPackages(List<MergedAnnotations> annotations) {\n\t\tSet<String> excludedPackages = new HashSet<>();\n\t\tfor (MergedAnnotations candidate : annotations) {\n\t\t\tMergedAnnotation<ClassPathExclusions> annotation = candidate.get(ClassPathExclusions.class);\n\t\t\tif (annotation.isPresent()) {\n\t\t\t\texcludedPackages.addAll(Arrays.asList(annotation.getStringArray(\"packages\")));\n\t\t\t}\n\t\t}\n\t\treturn excludedPackages;\n\t}\n\n\t/**\n\t * Filter for class path entries.\n\t */\n\tprivate static final class ClassPathEntryFilter {\n\n\t\tprivate final List<String> exclusions;\n\n\t\tprivate final AntPathMatcher matcher = new AntPathMatcher();\n\n\t\tprivate ClassPathEntryFilter(List<MergedAnnotations> annotations) {\n\t\t\tSet<String> exclusions = new LinkedHashSet<>();\n\t\t\tfor (MergedAnnotations candidate : annotations) {\n\t\t\t\tMergedAnnotation<ClassPathExclusions> annotation = candidate.get(ClassPathExclusions.class);\n\t\t\t\tif (annotation.isPresent()) {\n\t\t\t\t\texclusions.addAll(Arrays.asList(annotation.getStringArray(MergedAnnotation.VALUE)));\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.exclusions = exclusions.stream().toList();\n\t\t}\n\n\t\tprivate boolean isExcluded(URL url) {\n\t\t\tif (\"file\".equals(url.getProtocol())) {\n\t\t\t\ttry {\n\t\t\t\t\tURI uri = url.toURI();\n\t\t\t\t\tFile file = new File(uri);\n\t\t\t\t\tString name = (!uri.toString().endsWith(\"/\")) ? file.getName()\n\t\t\t\t\t\t\t: file.getParentFile().getParentFile().getName();\n\t\t\t\t\tfor (String exclusion : this.exclusions) {\n\t\t\t\t\t\tif (this.matcher.match(exclusion, name)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (URISyntaxException ex) {\n\t\t\t\t\t// Ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.lang.reflect.Method;\nimport java.net.URLClassLoader;\n\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.InvocationInterceptor;\nimport org.junit.jupiter.api.extension.ReflectiveInvocationContext;\nimport org.junit.platform.engine.discovery.DiscoverySelectors;\nimport org.junit.platform.launcher.Launcher;\nimport org.junit.platform.launcher.LauncherDiscoveryRequest;\nimport org.junit.platform.launcher.TestPlan;\nimport org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;\nimport org.junit.platform.launcher.core.LauncherFactory;\nimport org.junit.platform.launcher.listeners.SummaryGeneratingListener;\nimport org.junit.platform.launcher.listeners.TestExecutionSummary;\n\nimport org.springframework.util.CollectionUtils;\n\n/**\n * A custom {@link Extension} that runs tests using a modified class path. Entries are\n * excluded from the class path using {@link ClassPathExclusions @ClassPathExclusions} and\n * overridden using {@link ClassPathOverrides @ClassPathOverrides} on the test class. For\n * an unchanged copy of the class path {@link ForkedClassPath @ForkedClassPath} can be\n * used. A class loader is created with the customized class path and is used both to load\n * the test class and as the thread context class loader while the test is being run.\n *\n * @author Christoph Dreis\n */\nclass ModifiedClassPathExtension implements InvocationInterceptor {\n\n\t@Override\n\tpublic void interceptBeforeAllMethod(Invocation<Void> invocation,\n\t\t\tReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {\n\t\tintercept(invocation, extensionContext);\n\t}\n\n\t@Override\n\tpublic void interceptBeforeEachMethod(Invocation<Void> invocation,\n\t\t\tReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {\n\t\tintercept(invocation, extensionContext);\n\t}\n\n\t@Override\n\tpublic void interceptAfterEachMethod(Invocation<Void> invocation,\n\t\t\tReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {\n\t\tintercept(invocation, extensionContext);\n\t}\n\n\t@Override\n\tpublic void interceptAfterAllMethod(Invocation<Void> invocation,\n\t\t\tReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {\n\t\tintercept(invocation, extensionContext);\n\t}\n\n\t@Override\n\tpublic void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,\n\t\t\tExtensionContext extensionContext) throws Throwable {\n\t\tinterceptMethod(invocation, invocationContext, extensionContext);\n\t}\n\n\t@Override\n\tpublic void interceptTestTemplateMethod(Invocation<Void> invocation,\n\t\t\tReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {\n\t\tinterceptMethod(invocation, invocationContext, extensionContext);\n\t}\n\n\tprivate void interceptMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext,\n\t\t\tExtensionContext extensionContext) throws Throwable {\n\t\tif (isModifiedClassPathClassLoader(extensionContext)) {\n\t\t\tinvocation.proceed();\n\t\t\treturn;\n\t\t}\n\t\tClass<?> testClass = extensionContext.getRequiredTestClass();\n\t\tMethod testMethod = invocationContext.getExecutable();\n\t\tURLClassLoader modifiedClassLoader = ModifiedClassPathClassLoader.get(testClass, testMethod,\n\t\t\t\tinvocationContext.getArguments());\n\t\tif (modifiedClassLoader == null) {\n\t\t\tinvocation.proceed();\n\t\t\treturn;\n\t\t}\n\t\tinvocation.skip();\n\t\tClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();\n\t\tThread.currentThread().setContextClassLoader(modifiedClassLoader);\n\t\ttry {\n\t\t\trunTest(extensionContext.getUniqueId());\n\t\t}\n\t\tfinally {\n\t\t\tThread.currentThread().setContextClassLoader(originalClassLoader);\n\t\t}\n\t}\n\n\tprivate void runTest(String testId) throws Throwable {\n\t\tLauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()\n\t\t\t.selectors(DiscoverySelectors.selectUniqueId(testId))\n\t\t\t.build();\n\t\tLauncher launcher = LauncherFactory.create();\n\t\tTestPlan testPlan = launcher.discover(request);\n\t\tSummaryGeneratingListener listener = new SummaryGeneratingListener();\n\t\tlauncher.registerTestExecutionListeners(listener);\n\t\tlauncher.execute(testPlan);\n\t\tTestExecutionSummary summary = listener.getSummary();\n\t\tif (!CollectionUtils.isEmpty(summary.getFailures())) {\n\t\t\tthrow summary.getFailures().get(0).getException();\n\t\t}\n\t}\n\n\tprivate void intercept(Invocation<Void> invocation, ExtensionContext extensionContext) throws Throwable {\n\t\tif (isModifiedClassPathClassLoader(extensionContext)) {\n\t\t\tinvocation.proceed();\n\t\t\treturn;\n\t\t}\n\t\tinvocation.skip();\n\t}\n\n\tprivate boolean isModifiedClassPathClassLoader(ExtensionContext extensionContext) {\n\t\tClass<?> testClass = extensionContext.getRequiredTestClass();\n\t\tClassLoader classLoader = testClass.getClassLoader();\n\t\treturn classLoader.getClass().getName().equals(ModifiedClassPathClassLoader.class.getName());\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom JUnit extension to change the classpath.\n */\npackage org.springframework.boot.testsupport.classpath;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/Resource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.nio.file.Path;\n\n/**\n * A resource that is to be made available in tests.\n *\n * @param path the path of the resource\n * @param additional whether the resource should be made available in addition to those\n * that already exist elsewhere\n * @author Andy Wilkinson\n */\nrecord Resource(Path path, boolean additional) {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/ResourceContent.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotation that indicates that the content of a resource should be injected. Supported\n * on parameters of type:\n *\n * <ul>\n * <li>{@link String}</li>\n * </ul>\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface ResourceContent {\n\n\t/**\n\t * The name of the resource whose content should be injected.\n\t * @return the resource name\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/ResourcePath.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.File;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.nio.file.Path;\n\n/**\n * Annotation that indicates that the path of a resource should be injected. Supported on\n * parameters of type:\n *\n * <ul>\n * <li>{@link File}</li>\n * <li>{@link Path}</li>\n * <li>{@link String}</li>\n * </ul>\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface ResourcePath {\n\n\t/**\n\t * The name of the resource whose path should be injected.\n\t * @return the resource name\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/Resources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.file.FileSystem;\nimport java.nio.file.FileSystemNotFoundException;\nimport java.nio.file.FileSystems;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.FileSystemUtils;\nimport org.springframework.util.function.ThrowingConsumer;\n\n/**\n * A collection of resources.\n *\n * @author Andy Wilkinson\n */\nclass Resources {\n\n\tprivate final Path root;\n\n\tprivate final Map<String, Resource> resources = new HashMap<>();\n\n\tResources(Path root) {\n\t\tthis.root = root;\n\t}\n\n\tResources addPackage(String packageName, String[] resourceNames) {\n\t\tSet<String> unmatchedNames = new HashSet<>(Arrays.asList(resourceNames));\n\t\twithPathsForPackage(packageName, (packagePath) -> {\n\t\t\tfor (String resourceName : resourceNames) {\n\t\t\t\tPath resource = packagePath.resolve(resourceName);\n\t\t\t\tif (Files.exists(resource) && !Files.isDirectory(resource)) {\n\t\t\t\t\tPath target = this.root.resolve(resourceName);\n\t\t\t\t\tPath targetDirectory = target.getParent();\n\t\t\t\t\tif (!Files.isDirectory(targetDirectory)) {\n\t\t\t\t\t\tFiles.createDirectories(targetDirectory);\n\t\t\t\t\t}\n\t\t\t\t\tFiles.copy(resource, target);\n\t\t\t\t\tregister(resourceName, target, true);\n\t\t\t\t\tunmatchedNames.remove(resourceName);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tAssert.isTrue(unmatchedNames.isEmpty(),\n\t\t\t\t\"Package '\" + packageName + \"' did not contain resources: \" + unmatchedNames);\n\t\treturn this;\n\t}\n\n\tprivate void withPathsForPackage(String packageName, ThrowingConsumer<Path> consumer) {\n\t\ttry {\n\t\t\tList<URL> sources = Collections\n\t\t\t\t.list(getClass().getClassLoader().getResources(packageName.replace(\".\", \"/\")));\n\t\t\tfor (URL source : sources) {\n\t\t\t\tURI sourceUri = source.toURI();\n\t\t\t\ttry {\n\t\t\t\t\tconsumer.accept(Paths.get(sourceUri));\n\t\t\t\t}\n\t\t\t\tcatch (FileSystemNotFoundException ex) {\n\t\t\t\t\ttry (FileSystem fileSystem = FileSystems.newFileSystem(sourceUri, Collections.emptyMap())) {\n\t\t\t\t\t\tconsumer.accept(Paths.get(sourceUri));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t\tcatch (URISyntaxException ex) {\n\t\t\tthrow new RuntimeException(ex);\n\t\t}\n\t}\n\n\tResources addResource(String name, String content, boolean additional) {\n\t\tPath resourcePath = this.root.resolve(name);\n\t\tif (Files.isDirectory(resourcePath)) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Cannot create resource '\" + name + \"' as a directory already exists at that location\");\n\t\t}\n\t\tPath parent = resourcePath.getParent();\n\t\ttry {\n\t\t\tif (!Files.isDirectory(resourcePath)) {\n\t\t\t\tFiles.createDirectories(parent);\n\t\t\t}\n\t\t\tFiles.writeString(resourcePath, processContent(content));\n\t\t\tregister(name, resourcePath, additional);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t\treturn this;\n\t}\n\n\tprivate void register(String name, Path resourcePath, boolean additional) {\n\t\tResource resource = new Resource(resourcePath, additional);\n\t\tregister(name, resource);\n\t\tPath ancestor = resourcePath.getParent();\n\t\twhile (!this.root.equals(ancestor)) {\n\t\t\tResource ancestorResource = new Resource(ancestor, additional);\n\t\t\tregister(this.root.relativize(ancestor).toString(), ancestorResource);\n\t\t\tancestor = ancestor.getParent();\n\t\t}\n\t}\n\n\tprivate void register(String name, Resource resource) {\n\t\tString normalized = name.replace(\"\\\\\", \"/\");\n\t\tthis.resources.put(normalized, resource);\n\t\tif (Files.isDirectory(resource.path())) {\n\t\t\tif (normalized.endsWith(\"/\")) {\n\t\t\t\tthis.resources.put(normalized.substring(0, normalized.length() - 1), resource);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.resources.put(normalized + \"/\", resource);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate String processContent(String content) {\n\t\treturn content.replace(\"${resourceRoot}\", this.root.toString());\n\t}\n\n\tResources addDirectory(String name) {\n\t\tPath directoryPath = this.root.resolve(name);\n\t\tif (Files.isRegularFile(directoryPath)) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Cannot create directory '\" + name + \" as a file already exists at that location\");\n\t\t}\n\t\ttry {\n\t\t\tFiles.createDirectories(directoryPath);\n\t\t\tregister(name, directoryPath, true);\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t\treturn this;\n\t}\n\n\tvoid delete() {\n\t\ttry {\n\t\t\tFileSystemUtils.deleteRecursively(this.root);\n\t\t\tthis.resources.clear();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\tPath getRoot() {\n\t\treturn this.root;\n\t}\n\n\tResource find(String name) {\n\t\treturn this.resources.get(name);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/ResourcesClassLoader.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.net.URL;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\n\nimport org.springframework.core.SmartClassLoader;\n\n/**\n * A {@link ClassLoader} that provides access to {@link Resources resources}.\n *\n * @author Andy Wilkinson\n */\nclass ResourcesClassLoader extends ClassLoader implements SmartClassLoader {\n\n\tprivate final Resources resources;\n\n\tResourcesClassLoader(ClassLoader parent, Resources resources) {\n\t\tsuper(parent);\n\t\tthis.resources = resources;\n\t}\n\n\t@Override\n\tpublic URL getResource(String name) {\n\t\tResource resource = this.resources.find(name);\n\t\treturn (resource != null) ? urlOf(resource) : getParent().getResource(name);\n\t}\n\n\tprivate URL urlOf(Resource resource) {\n\t\ttry {\n\t\t\treturn resource.path().toUri().toURL();\n\t\t}\n\t\tcatch (IOException ex) {\n\t\t\tthrow new UncheckedIOException(ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Enumeration<URL> getResources(String name) throws IOException {\n\t\tResource resource = this.resources.find(name);\n\t\tArrayList<URL> urls = new ArrayList<>();\n\t\tif (resource != null) {\n\t\t\tURL resourceUrl = urlOf(resource);\n\t\t\turls.add(resourceUrl);\n\t\t}\n\t\tif (resource == null || resource.additional()) {\n\t\t\turls.addAll(Collections.list(getParent().getResources(name)));\n\t\t}\n\t\treturn Collections.enumeration(urls);\n\t}\n\n\t@Override\n\tpublic ClassLoader getOriginalClassLoader() {\n\t\treturn getParent();\n\t}\n\n\t@Override\n\tpublic Class<?> publicDefineClass(String name, byte[] b, ProtectionDomain protectionDomain) {\n\t\treturn defineClass(name, b, 0, b.length, protectionDomain);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/ResourcesExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UncheckedIOException;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ExtensionContext.Namespace;\nimport org.junit.jupiter.api.extension.ExtensionContext.Store;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolutionException;\nimport org.junit.jupiter.api.extension.ParameterResolver;\nimport org.junit.platform.commons.support.AnnotationSupport;\n\nimport org.springframework.util.StreamUtils;\n\n/**\n * {@link Extension} for managing resources in tests. Resources are made available through\n * {@link Thread#getContextClassLoader() thread context class loader}.\n *\n * @author Andy Wilkinson\n * @see WithPackageResources\n * @see WithResource\n * @see WithResourceDirectory\n */\nclass ResourcesExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {\n\n\tprivate static final String RESOURCES_KEY = ResourcesExtension.class.getName() + \".resources\";\n\n\tprivate static final String TCCL_KEY = ResourcesExtension.class.getName() + \".tccl\";\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tStore store = context.getStore(Namespace.create(ResourcesExtension.class));\n\t\tResources resources = new Resources(Files.createTempDirectory(\"resources\"));\n\t\tstore.put(RESOURCES_KEY, resources);\n\t\tMethod testMethod = context.getRequiredTestMethod();\n\t\tresourcesOf(testMethod)\n\t\t\t.forEach((resource) -> resources.addResource(resource.name(), resource.content(), resource.additional()));\n\t\tresourceDirectoriesOf(testMethod).forEach((directory) -> resources.addDirectory(directory.value()));\n\t\tpackageResourcesOf(testMethod, context).forEach((withPackageResources) -> resources\n\t\t\t.addPackage(testMethod.getDeclaringClass().getPackage().getName(), withPackageResources.value()));\n\t\tResourcesClassLoader classLoader = new ResourcesClassLoader(context.getRequiredTestClass().getClassLoader(),\n\t\t\t\tresources);\n\t\tstore.put(TCCL_KEY, new Tccl());\n\t\tThread.currentThread().setContextClassLoader(classLoader);\n\t}\n\n\tprivate List<WithResource> resourcesOf(Method method) {\n\t\treturn withAnnotationsOf(method, WithResource.class);\n\t}\n\n\tprivate List<WithResourceDirectory> resourceDirectoriesOf(Method method) {\n\t\treturn withAnnotationsOf(method, WithResourceDirectory.class);\n\t}\n\n\tprivate <A extends Annotation> List<A> withAnnotationsOf(Method method, Class<A> annotationType) {\n\t\tList<A> annotations = new ArrayList<>();\n\t\tAnnotationSupport.findRepeatableAnnotations(method, annotationType).forEach(annotations::add);\n\t\tClass<?> type = method.getDeclaringClass();\n\t\twhile (type != null) {\n\t\t\tAnnotationSupport.findRepeatableAnnotations(type, annotationType).forEach(annotations::add);\n\t\t\ttype = type.getEnclosingClass();\n\t\t}\n\t\treturn annotations;\n\t}\n\n\tprivate List<WithPackageResources> packageResourcesOf(Method method, ExtensionContext context) {\n\t\tList<WithPackageResources> annotations = new ArrayList<>();\n\t\tAnnotationSupport.findAnnotation(method, WithPackageResources.class).ifPresent(annotations::add);\n\t\tAnnotationSupport\n\t\t\t.findAnnotation(method.getDeclaringClass(), WithPackageResources.class, context.getEnclosingTestClasses())\n\t\t\t.ifPresent(annotations::add);\n\t\treturn annotations;\n\t}\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\tStore store = context.getStore(Namespace.create(ResourcesExtension.class));\n\t\tstore.get(RESOURCES_KEY, Resources.class).delete();\n\t\tThread.currentThread().setContextClassLoader(store.get(TCCL_KEY, Tccl.class).get());\n\t}\n\n\t@Override\n\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\tthrows ParameterResolutionException {\n\t\treturn parameterContext.isAnnotated(ResourcesRoot.class) || parameterContext.isAnnotated(ResourcePath.class)\n\t\t\t\t|| parameterContext.isAnnotated(ResourceContent.class);\n\t}\n\n\t@Override\n\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\tthrows ParameterResolutionException {\n\t\tif (parameterContext.isAnnotated(ResourcesRoot.class)) {\n\t\t\treturn resolveResourcesRoot(parameterContext, extensionContext);\n\t\t}\n\t\tif (parameterContext.isAnnotated(ResourcePath.class)) {\n\t\t\treturn resolveResourcePath(parameterContext, extensionContext);\n\t\t}\n\t\tif (parameterContext.isAnnotated(ResourceContent.class)) {\n\t\t\treturn resolveResourceContent(parameterContext, extensionContext);\n\t\t}\n\t\tthrow new ParameterResolutionException(\n\t\t\t\t\"Parameter is not annotated with @ResourcesRoot, @ResourceContent, or @ResourcePath\");\n\t}\n\n\tprivate Object resolveResourcesRoot(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\tResources resources = getResources(extensionContext);\n\t\tClass<?> parameterType = parameterContext.getParameter().getType();\n\t\tif (parameterType.isAssignableFrom(Path.class)) {\n\t\t\treturn resources.getRoot();\n\t\t}\n\t\telse if (parameterType.isAssignableFrom(File.class)) {\n\t\t\treturn resources.getRoot().toFile();\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"@ResourcesRoot is not supported with parameter type '\" + parameterType.getName() + \"'\");\n\t}\n\n\tprivate Object resolveResourcePath(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\tResources resources = getResources(extensionContext);\n\t\tClass<?> parameterType = parameterContext.getParameter().getType();\n\t\tPath resourcePath = resources.find(parameterContext.findAnnotation(ResourcePath.class).get().value()).path();\n\t\tif (parameterType.isAssignableFrom(Path.class)) {\n\t\t\treturn resourcePath;\n\t\t}\n\t\telse if (parameterType.isAssignableFrom(File.class)) {\n\t\t\treturn resourcePath.toFile();\n\t\t}\n\t\telse if (parameterType.isAssignableFrom(String.class)) {\n\t\t\treturn resourcePath.toString();\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"@ResourcePath is not supported with parameter type '\" + parameterType.getName() + \"'\");\n\t}\n\n\tprivate Object resolveResourceContent(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\tResources resources = getResources(extensionContext);\n\t\tClass<?> parameterType = parameterContext.getParameter().getType();\n\t\tPath resourcePath = resources.find(parameterContext.findAnnotation(ResourceContent.class).get().value()).path();\n\t\tif (parameterType.isAssignableFrom(String.class)) {\n\t\t\ttry (InputStream in = Files.newInputStream(resourcePath)) {\n\t\t\t\treturn StreamUtils.copyToString(in, StandardCharsets.UTF_8);\n\t\t\t}\n\t\t\tcatch (IOException ex) {\n\t\t\t\tthrow new UncheckedIOException(ex);\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalStateException(\n\t\t\t\t\"@ResourceContent is not supported with parameter type '\" + parameterType.getName() + \"'\");\n\t}\n\n\tprivate Resources getResources(ExtensionContext extensionContext) {\n\t\tStore store = extensionContext.getStore(Namespace.create(ResourcesExtension.class));\n\t\tResources resources = store.get(RESOURCES_KEY, Resources.class);\n\t\treturn resources;\n\t}\n\n\t/**\n\t * Holder for the thread context class loader that can be safely\n\t * {@link Store#put(Object, Object) stored} without it causing unwanted\n\t * {@link ClassLoader#close closure} of the class loader.\n\t */\n\tprivate static class Tccl {\n\n\t\tprivate final ClassLoader classLoader;\n\n\t\tTccl() {\n\t\t\tthis.classLoader = Thread.currentThread().getContextClassLoader();\n\t\t}\n\n\t\tClassLoader get() {\n\t\t\treturn this.classLoader;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/ResourcesRoot.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.File;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\nimport java.nio.file.Path;\n\n/**\n * Annotation that indicates that the resources root should be injected. Supported on\n * parameters of type:\n *\n * <ul>\n * <li>{@link File}</li>\n * <li>{@link Path}</li>\n * </ul>\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface ResourcesRoot {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/WithPackageResources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Makes resources in the package of the annotated class available from the root of the\n * classpath.\n *\n * @author Andy Wilkinson\n */\n@Inherited\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@ExtendWith(ResourcesExtension.class)\npublic @interface WithPackageResources {\n\n\t/**\n\t * The resources to make available from the root.\n\t * @return the resources\n\t */\n\tString[] value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/WithResource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Repeatable;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Makes a resource directory available from the thread context class loader.\n * <p>\n * For cases where one resource needs to refer to another, the resource's content may\n * contain the placeholder <code>${resourceRoot}</code>. It will be replaced with the path\n * to the root of the resources. For example, a resource with the {@link #name}\n * {@code example.txt} can be referenced using <code>${resourceRoot}/example.txt</code>.\n *\n * @author Andy Wilkinson\n */\n@Inherited\n@Repeatable(WithResources.class)\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@ExtendWith(ResourcesExtension.class)\npublic @interface WithResource {\n\n\t/**\n\t * The name of the resource.\n\t * @return the name\n\t */\n\tString name();\n\n\t/**\n\t * The content of the resource. When omitted an empty resource will be created.\n\t * @return the content\n\t */\n\tString content() default \"\";\n\n\t/**\n\t * Whether the resource should be available in addition to those that are already on\n\t * the classpath are instead of any existing resources with the same name.\n\t * @return whether this is an additional resource\n\t */\n\tboolean additional() default true;\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/WithResourceDirectories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Container annotation for {@link WithResourceDirectory}.\n *\n * @author Andy Wilkinson\n */\n@Inherited\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.TYPE })\npublic @interface WithResourceDirectories {\n\n\tWithResourceDirectory[] value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/WithResourceDirectory.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Repeatable;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Makes a resource available from the thread context class loader. Typically used when a\n * test requires an empty directory to exist.\n *\n * @author Andy Wilkinson\n */\n@Inherited\n@Repeatable(WithResourceDirectories.class)\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.TYPE })\n@ExtendWith(ResourcesExtension.class)\npublic @interface WithResourceDirectory {\n\n\t/**\n\t * The name of the directory.\n\t * @return the name\n\t */\n\tString value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/WithResources.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Container annotation for {@link WithResource}.\n *\n * @author Andy Wilkinson\n */\n@Inherited\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.METHOD, ElementType.TYPE })\npublic @interface WithResources {\n\n\tWithResource[] value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Custom JUnit extension for testing with resources.\n */\npackage org.springframework.boot.testsupport.classpath.resources;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanArgumentsProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.junit;\n\nimport java.lang.reflect.Method;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.ArgumentsProvider;\nimport org.junit.jupiter.params.support.ParameterDeclarations;\nimport org.junit.platform.commons.util.Preconditions;\n\n/**\n * An {@link ArgumentsProvider} that provides {@code true} and {@code false} values.\n *\n * @author Scott Frederick\n */\nclass BooleanArgumentsProvider implements ArgumentsProvider {\n\n\t@Override\n\tpublic Stream<? extends Arguments> provideArguments(ParameterDeclarations parameterDeclarations,\n\t\t\tExtensionContext context) {\n\t\tMethod testMethod = context.getRequiredTestMethod();\n\t\tPreconditions.condition(testMethod.getParameterCount() > 0, () -> String.format(\n\t\t\t\t\"@BooleanValueSource cannot provide arguments to method [%s]: the method does not declare any formal parameters.\",\n\t\t\t\ttestMethod.toGenericString()));\n\n\t\treturn Stream.of(Arguments.arguments(false), Arguments.arguments(true));\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/BooleanValueSource.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.junit;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.params.provider.ArgumentsSource;\n\n/**\n * {@code @BooleanValueSource} is an {@link ArgumentsSource} which provides {@code true}\n * and {@code false} values to the annotated {@code @ParameterizedTest} method.\n *\n * @author Scott Frederick\n */\n@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ArgumentsSource(BooleanArgumentsProvider.class)\npublic @interface BooleanValueSource {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/DisabledOnOs.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.junit;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Improves JUnit5's {@link org.junit.jupiter.api.condition.DisabledOnOs} by adding an\n * architecture check.\n *\n * @author Moritz Halbritter\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@ExtendWith(DisabledOnOsCondition.class)\npublic @interface DisabledOnOs {\n\n\t/**\n\t * The operating systems on which the annotated class or method should be disabled.\n\t * @return the operating systems where the test is disabled\n\t */\n\tOS[] value() default {};\n\n\t/**\n\t * The operating systems on which the annotated class or method should be disabled.\n\t * @return the operating systems where the test is disabled\n\t */\n\tOS[] os() default {};\n\n\t/**\n\t * The architectures on which the annotated class or method should be disabled.\n\t * @return the architectures where the test is disabled\n\t */\n\tString[] architecture() default {};\n\n\t/**\n\t * See {@link org.junit.jupiter.api.condition.DisabledOnOs#disabledReason()}.\n\t * @return disabled reason\n\t */\n\tString disabledReason() default \"\";\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/DisabledOnOsCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.junit;\n\nimport java.util.Arrays;\n\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.extension.ConditionEvaluationResult;\nimport org.junit.jupiter.api.extension.ExecutionCondition;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\n\n/**\n * Evaluates {@link DisabledOnOs}.\n *\n * @author Moritz Halbritter\n * @author Phillip Webb\n */\nclass DisabledOnOsCondition implements ExecutionCondition {\n\n\t@Override\n\tpublic ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {\n\t\tif (context.getElement().isEmpty()) {\n\t\t\treturn ConditionEvaluationResult.enabled(\"No element for @DisabledOnOs found\");\n\t\t}\n\t\tMergedAnnotation<DisabledOnOs> annotation = MergedAnnotations\n\t\t\t.from(context.getElement().get(), SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.get(DisabledOnOs.class);\n\t\tif (!annotation.isPresent()) {\n\t\t\treturn ConditionEvaluationResult.enabled(\"No @DisabledOnOs found\");\n\t\t}\n\t\treturn evaluate(annotation.synthesize());\n\t}\n\n\tprivate ConditionEvaluationResult evaluate(DisabledOnOs annotation) {\n\t\tString architecture = System.getProperty(\"os.arch\");\n\t\tString os = System.getProperty(\"os.name\");\n\t\tboolean onDisabledOs = Arrays.stream(annotation.os()).anyMatch(OS::isCurrentOs);\n\t\tboolean onDisabledArchitecture = Arrays.asList(annotation.architecture()).contains(architecture);\n\t\tif (onDisabledOs && onDisabledArchitecture) {\n\t\t\tString reason = annotation.disabledReason().isEmpty()\n\t\t\t\t\t? String.format(\"Disabled on OS = %s, architecture = %s\", os, architecture)\n\t\t\t\t\t: annotation.disabledReason();\n\t\t\treturn ConditionEvaluationResult.disabled(reason);\n\t\t}\n\t\treturn ConditionEvaluationResult\n\t\t\t.enabled(String.format(\"Enabled on OS = %s, architecture = %s\", os, architecture));\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/EnabledOnLocale.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.junit;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * {@code @EnabledOnLocale} annotation is used to conditionally enable a test method based\n * on the specified locale attributes.\n *\n * @author Dmytro Nosan\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@ExtendWith(EnabledOnLocaleCondition.class)\npublic @interface EnabledOnLocale {\n\n\t/**\n\t * Specifies the language code for which the test method should be enabled.\n\t * @return the language code\n\t */\n\tString language();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/EnabledOnLocaleCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.junit;\n\nimport java.util.Locale;\n\nimport org.junit.jupiter.api.extension.ConditionEvaluationResult;\nimport org.junit.jupiter.api.extension.ExecutionCondition;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.platform.commons.support.AnnotationSupport;\n\n/**\n * An implementation of {@link ExecutionCondition} that conditionally enables or disables\n * the execution of a test method or class based on the specified locale attributes.\n *\n * @author Dmytro Nosan\n */\nclass EnabledOnLocaleCondition implements ExecutionCondition {\n\n\t@Override\n\tpublic ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {\n\t\treturn AnnotationSupport.findAnnotation(context.getElement(), EnabledOnLocale.class)\n\t\t\t.map(this::evaluate)\n\t\t\t.orElseGet(() -> ConditionEvaluationResult.enabled(\"No @EnabledOnLocale annotation found\"));\n\t}\n\n\tprivate ConditionEvaluationResult evaluate(EnabledOnLocale annotation) {\n\t\tLocale locale = Locale.getDefault();\n\t\tString language = locale.getLanguage();\n\t\tif (!annotation.language().equals(language)) {\n\t\t\treturn ConditionEvaluationResult.disabled(\"Disabled on language: \" + language);\n\t\t}\n\t\treturn ConditionEvaluationResult.enabled(\"Enabled on language: \" + language);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/junit/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * General support classes for testing with JUnit.\n */\npackage org.springframework.boot.testsupport.junit;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/logging/ConfigureClasspathToPreferLog4j2.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.logging;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.testsupport.classpath.ClassPathExclusions;\nimport org.springframework.boot.testsupport.classpath.ClassPathOverrides;\n\n/**\n * Configures the classpath to prefer Log4j2. Other logging systems may still be on the\n * classpath, but Log4j2 will be positioned before them.\n *\n * @author Andy Wilkinson\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\n@Documented\n@ClassPathExclusions(\"log4j-to-slf4j-*.jar\")\n@ClassPathOverrides({ \"org.apache.logging.log4j:log4j-core:2.24.3\",\n\t\t\"org.apache.logging.log4j:log4j-slf4j-impl:2.24.3\" })\npublic @interface ConfigureClasspathToPreferLog4j2 {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/logging/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Internal support classes used in Spring Boot tests related to logging.\n */\npackage org.springframework.boot.testsupport.logging;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Internal support classes used in Spring Boot tests.\n */\npackage org.springframework.boot.testsupport;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailable.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.process;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Repeatable;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Disables test execution if a process is unavailable.\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ExtendWith(DisabledIfProcessUnavailableCondition.class)\n@Repeatable(DisabledIfProcessUnavailables.class)\npublic @interface DisabledIfProcessUnavailable {\n\n\tString[] value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailableCondition.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.process;\n\nimport java.lang.reflect.AnnotatedElement;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.api.extension.ConditionEvaluationResult;\nimport org.junit.jupiter.api.extension.ExecutionCondition;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.core.annotation.MergedAnnotation;\nimport org.springframework.core.annotation.MergedAnnotations;\nimport org.springframework.core.annotation.MergedAnnotations.SearchStrategy;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * An {@link ExecutionCondition} that disables execution if specified processes cannot\n * start.\n *\n * @author Phillip Webb\n */\nclass DisabledIfProcessUnavailableCondition implements ExecutionCondition {\n\n\tprivate static final String USR_LOCAL_BIN = \"/usr/local/bin\";\n\n\tprivate static final boolean MAC_OS = System.getProperty(\"os.name\").toLowerCase(Locale.ROOT).contains(\"mac\");\n\n\t@Override\n\tpublic ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {\n\t\tList<String[]> commands = new ArrayList<>();\n\t\tcontext.getTestClass().map(this::getAnnotationValue).orElse(Stream.empty()).forEach(commands::add);\n\t\tcontext.getTestMethod().map(this::getAnnotationValue).orElse(Stream.empty()).forEach(commands::add);\n\t\ttry {\n\t\t\tcommands.forEach(this::check);\n\t\t\treturn ConditionEvaluationResult.enabled(\"All processes available\");\n\t\t}\n\t\tcatch (Throwable ex) {\n\t\t\treturn ConditionEvaluationResult.disabled(\"Process unavailable\", ex.getMessage());\n\t\t}\n\t}\n\n\tprivate Stream<String[]> getAnnotationValue(AnnotatedElement testElement) {\n\t\treturn MergedAnnotations.from(testElement, SearchStrategy.TYPE_HIERARCHY)\n\t\t\t.stream(DisabledIfProcessUnavailable.class)\n\t\t\t.map((annotation) -> annotation.getStringArray(MergedAnnotation.VALUE));\n\t}\n\n\tprivate void check(String[] command) {\n\t\tProcessBuilder processBuilder = new ProcessBuilder(command);\n\t\ttry {\n\t\t\tProcess process = processBuilder.start();\n\t\t\tAssert.state(process.waitFor(30, TimeUnit.SECONDS), \"Process did not exit within 30 seconds\");\n\t\t\tAssert.state(process.exitValue() == 0, () -> \"Process exited with %d\".formatted(process.exitValue()));\n\t\t\tprocess.destroy();\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tString path = processBuilder.environment().get(\"PATH\");\n\t\t\tif (MAC_OS && path != null && !path.contains(USR_LOCAL_BIN)\n\t\t\t\t\t&& !command[0].startsWith(USR_LOCAL_BIN + \"/\")) {\n\t\t\t\tString[] localCommand = command.clone();\n\t\t\t\tlocalCommand[0] = USR_LOCAL_BIN + \"/\" + localCommand[0];\n\t\t\t\tcheck(localCommand);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new RuntimeException(\n\t\t\t\t\t\"Unable to start process '%s'\".formatted(StringUtils.arrayToDelimitedString(command, \" \")));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailables.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.process;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Repeatable container for {@link DisabledIfProcessUnavailable}.\n *\n * @author Phillip Webb\n */\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ExtendWith(DisabledIfProcessUnavailableCondition.class)\npublic @interface DisabledIfProcessUnavailables {\n\n\tDisabledIfProcessUnavailable[] value();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/process/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes to help when shelling out to processes in tests.\n */\npackage org.springframework.boot.testsupport.process;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/ssl/MockKeyStoreSpi.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.ssl;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.security.Key;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStoreSpi;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.Certificate;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Mock Security Provider for testing purposes.\n *\n * @author Cyril Dangerville\n */\npublic class MockKeyStoreSpi extends KeyStoreSpi {\n\n\tprivate static final KeyPairGenerator KEYGEN;\n\n\tstatic {\n\t\ttry {\n\t\t\tKEYGEN = KeyPairGenerator.getInstance(\"RSA\");\n\t\t\tKEYGEN.initialize(2048);\n\t\t}\n\t\tcatch (NoSuchAlgorithmException ex) {\n\t\t\tthrow new IllegalStateException(ex);\n\t\t}\n\t}\n\n\tprivate final Map<String, KeyPair> aliases = new HashMap<>();\n\n\t@Override\n\tpublic Key engineGetKey(String alias, char[] password) {\n\t\tfinal KeyPair keyPair = this.aliases.get(alias);\n\t\treturn (keyPair != null) ? keyPair.getPrivate() : null;\n\t}\n\n\t@Override\n\tpublic Certificate[] engineGetCertificateChain(String alias) {\n\t\treturn new Certificate[0];\n\t}\n\n\t@Override\n\tpublic Certificate engineGetCertificate(String alias) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic Date engineGetCreationDate(String alias) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic void engineSetCertificateEntry(String alias, Certificate cert) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic void engineDeleteEntry(String alias) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic Enumeration<String> engineAliases() {\n\t\treturn Collections.enumeration(this.aliases.keySet());\n\t}\n\n\t@Override\n\tpublic boolean engineContainsAlias(String alias) {\n\t\tthis.aliases.put(alias, KEYGEN.generateKeyPair());\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic int engineSize() {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic boolean engineIsKeyEntry(String alias) {\n\t\treturn this.aliases.containsKey(alias);\n\t}\n\n\t@Override\n\tpublic boolean engineIsCertificateEntry(String alias) {\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic String engineGetCertificateAlias(Certificate cert) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic void engineStore(OutputStream stream, char[] password) {\n\t\tthrow new UnsupportedOperationException();\n\t}\n\n\t@Override\n\tpublic void engineLoad(InputStream stream, char[] password) {\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/ssl/MockPkcs11Security.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.ssl;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * JUnit {@link ExtendWith @ExtendWith} annotation to support\n * {@link MockPkcs11SecurityProvider}.\n *\n * @author Phillip Webb\n */\n@ExtendWith(MockPkcs11SecurityProviderExtension.class)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MockPkcs11Security {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/ssl/MockPkcs11SecurityProvider.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.ssl;\n\nimport java.security.Provider;\n\n/**\n * Mock PKCS#11 Security Provider for testing purposes.\n *\n * @author Cyril Dangerville\n */\npublic class MockPkcs11SecurityProvider extends Provider {\n\n\t/**\n\t * The name of the mock provider.\n\t */\n\tpublic static final String NAME = \"Mock-PKCS11\";\n\n\tstatic final MockPkcs11SecurityProvider INSTANCE = new MockPkcs11SecurityProvider();\n\n\tMockPkcs11SecurityProvider() {\n\t\tsuper(NAME, \"0.1\", \"Mock PKCS11 Provider\");\n\t\tputService(new Service(this, \"KeyStore\", \"PKCS11\", MockKeyStoreSpi.class.getName(), null, null));\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/ssl/MockPkcs11SecurityProviderExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.ssl;\n\nimport java.security.Security;\n\nimport org.junit.jupiter.api.extension.AfterAllCallback;\nimport org.junit.jupiter.api.extension.BeforeAllCallback;\nimport org.junit.jupiter.api.extension.Extension;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\n/**\n * {@link Extension} to support {@link MockPkcs11SecurityProvider}.\n *\n * @author Phillip Webb\n * @see MockPkcs11Security\n */\nclass MockPkcs11SecurityProviderExtension implements BeforeAllCallback, AfterAllCallback {\n\n\t@Override\n\tpublic void beforeAll(ExtensionContext context) throws Exception {\n\t\tSecurity.addProvider(MockPkcs11SecurityProvider.INSTANCE);\n\t}\n\n\t@Override\n\tpublic void afterAll(ExtensionContext context) throws Exception {\n\t\tSecurity.removeProvider(MockPkcs11SecurityProvider.NAME);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/ssl/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes to help when testing SSL-related functionality.\n */\npackage org.springframework.boot.testsupport.ssl;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/CapturedOutput.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.system;\n\n/**\n * Internal test class providing access to {@link System#out System.out} and\n * {@link System#err System.err} output that has been captured.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\npublic interface CapturedOutput extends CharSequence {\n\n\t@Override\n\tdefault int length() {\n\t\treturn toString().length();\n\t}\n\n\t@Override\n\tdefault char charAt(int index) {\n\t\treturn toString().charAt(index);\n\t}\n\n\t@Override\n\tdefault CharSequence subSequence(int start, int end) {\n\t\treturn toString().subSequence(start, end);\n\t}\n\n\t/**\n\t * Return all content (both {@link System#out System.out} and {@link System#err\n\t * System.err}) in the order that it was captured.\n\t * @return all captured output\n\t */\n\tString getAll();\n\n\t/**\n\t * Return {@link System#out System.out} content in the order that it was captured.\n\t * @return {@link System#out System.out} captured output\n\t */\n\tString getOut();\n\n\t/**\n\t * Return {@link System#err System.err} content in the order that it was captured.\n\t * @return {@link System#err System.err} captured output\n\t */\n\tString getErr();\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCapture.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.system;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\nimport org.springframework.util.Assert;\n\n/**\n * Provides support for capturing {@link System#out System.out} and {@link System#err\n * System.err}.\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass OutputCapture implements CapturedOutput {\n\n\tprivate final Deque<SystemCapture> systemCaptures = new ArrayDeque<>();\n\n\t/**\n\t * Push a new system capture session onto the stack.\n\t */\n\tfinal void push() {\n\t\tthis.systemCaptures.addLast(new SystemCapture());\n\t}\n\n\t/**\n\t * Pop the last system capture session from the stack.\n\t */\n\tfinal void pop() {\n\t\tthis.systemCaptures.removeLast().release();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\t\tif (obj instanceof CharSequence) {\n\t\t\treturn getAll().equals(obj.toString());\n\t\t}\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\treturn toString().hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn getAll();\n\t}\n\n\t/**\n\t * Return all content (both {@link System#out System.out} and {@link System#err\n\t * System.err}) in the order that it was captured.\n\t * @return all captured output\n\t */\n\t@Override\n\tpublic String getAll() {\n\t\treturn get((type) -> true);\n\t}\n\n\t/**\n\t * Return {@link System#out System.out} content in the order that it was captured.\n\t * @return {@link System#out System.out} captured output\n\t */\n\t@Override\n\tpublic String getOut() {\n\t\treturn get(Type.OUT::equals);\n\t}\n\n\t/**\n\t * Return {@link System#err System.err} content in the order that it was captured.\n\t * @return {@link System#err System.err} captured output\n\t */\n\t@Override\n\tpublic String getErr() {\n\t\treturn get(Type.ERR::equals);\n\t}\n\n\t/**\n\t * Resets the current capture session, clearing its captured output.\n\t */\n\tvoid reset() {\n\t\tthis.systemCaptures.peek().reset();\n\t}\n\n\tprivate String get(Predicate<Type> filter) {\n\t\tAssert.state(!this.systemCaptures.isEmpty(),\n\t\t\t\t\"No system captures found. Please check your output capture registration.\");\n\t\tStringBuilder builder = new StringBuilder();\n\t\tfor (SystemCapture systemCapture : this.systemCaptures) {\n\t\t\tsystemCapture.append(builder, filter);\n\t\t}\n\t\treturn builder.toString();\n\t}\n\n\t/**\n\t * A capture session that captures {@link System#out System.out} and {@link System#err\n\t * System.err}.\n\t */\n\tprivate static class SystemCapture {\n\n\t\tprivate final PrintStreamCapture out;\n\n\t\tprivate final PrintStreamCapture err;\n\n\t\tprivate final Object monitor = new Object();\n\n\t\tprivate final List<CapturedString> capturedStrings = new ArrayList<>();\n\n\t\tSystemCapture() {\n\t\t\tthis.out = new PrintStreamCapture(System.out, this::captureOut);\n\t\t\tthis.err = new PrintStreamCapture(System.err, this::captureErr);\n\t\t\tSystem.setOut(this.out);\n\t\t\tSystem.setErr(this.err);\n\t\t}\n\n\t\tvoid release() {\n\t\t\tSystem.setOut(this.out.getParent());\n\t\t\tSystem.setErr(this.err.getParent());\n\t\t}\n\n\t\tprivate void captureOut(String string) {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.capturedStrings.add(new CapturedString(Type.OUT, string));\n\t\t\t}\n\t\t}\n\n\t\tprivate void captureErr(String string) {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.capturedStrings.add(new CapturedString(Type.ERR, string));\n\t\t\t}\n\t\t}\n\n\t\tvoid append(StringBuilder builder, Predicate<Type> filter) {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tfor (CapturedString stringCapture : this.capturedStrings) {\n\t\t\t\t\tif (filter.test(stringCapture.getType())) {\n\t\t\t\t\t\tbuilder.append(stringCapture);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid reset() {\n\t\t\tsynchronized (this.monitor) {\n\t\t\t\tthis.capturedStrings.clear();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/**\n\t * A {@link PrintStream} implementation that captures written strings.\n\t */\n\tprivate static class PrintStreamCapture extends PrintStream {\n\n\t\tprivate final PrintStream parent;\n\n\t\tPrintStreamCapture(PrintStream parent, Consumer<String> copy) {\n\t\t\tsuper(new OutputStreamCapture(getSystemStream(parent), copy));\n\t\t\tthis.parent = parent;\n\t\t}\n\n\t\tPrintStream getParent() {\n\t\t\treturn this.parent;\n\t\t}\n\n\t\tprivate static PrintStream getSystemStream(PrintStream printStream) {\n\t\t\twhile (printStream instanceof PrintStreamCapture printStreamCapture) {\n\t\t\t\tprintStream = printStreamCapture.getParent();\n\t\t\t}\n\t\t\treturn printStream;\n\t\t}\n\n\t}\n\n\t/**\n\t * An {@link OutputStream} implementation that captures written strings.\n\t */\n\tprivate static class OutputStreamCapture extends OutputStream {\n\n\t\tprivate final PrintStream systemStream;\n\n\t\tprivate final Consumer<String> copy;\n\n\t\tOutputStreamCapture(PrintStream systemStream, Consumer<String> copy) {\n\t\t\tthis.systemStream = systemStream;\n\t\t\tthis.copy = copy;\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(int b) throws IOException {\n\t\t\twrite(new byte[] { (byte) (b & 0xFF) });\n\t\t}\n\n\t\t@Override\n\t\tpublic void write(byte[] b, int off, int len) throws IOException {\n\t\t\tthis.copy.accept(new String(b, off, len));\n\t\t\tthis.systemStream.write(b, off, len);\n\t\t}\n\n\t\t@Override\n\t\tpublic void flush() throws IOException {\n\t\t\tthis.systemStream.flush();\n\t\t}\n\n\t}\n\n\t/**\n\t * A captured string that forms part of the full output.\n\t */\n\tprivate static class CapturedString {\n\n\t\tprivate final Type type;\n\n\t\tprivate final String string;\n\n\t\tCapturedString(Type type, String string) {\n\t\t\tthis.type = type;\n\t\t\tthis.string = string;\n\t\t}\n\n\t\tType getType() {\n\t\t\treturn this.type;\n\t\t}\n\n\t\t@Override\n\t\tpublic String toString() {\n\t\t\treturn this.string;\n\t\t}\n\n\t}\n\n\t/**\n\t * Types of content that can be captured.\n\t */\n\tprivate enum Type {\n\n\t\tOUT, ERR\n\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/OutputCaptureExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.system;\n\nimport org.junit.jupiter.api.extension.AfterAllCallback;\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeAllCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.api.extension.ExtensionContext;\nimport org.junit.jupiter.api.extension.ExtensionContext.Namespace;\nimport org.junit.jupiter.api.extension.ExtensionContext.Store;\nimport org.junit.jupiter.api.extension.ParameterContext;\nimport org.junit.jupiter.api.extension.ParameterResolutionException;\nimport org.junit.jupiter.api.extension.ParameterResolver;\n\n/**\n * JUnit Jupiter {@code @Extension} to capture {@link System#out System.out} and\n * {@link System#err System.err}. Can be registered for an entire test class or for an\n * individual test method through {@link ExtendWith @ExtendWith}. This extension provides\n * {@linkplain ParameterResolver parameter resolution} for a {@link CapturedOutput}\n * instance which can be used to assert that the correct output was written.\n * <p>\n * To use with {@link ExtendWith @ExtendWith}, inject the {@link CapturedOutput} as an\n * argument to your test class constructor, test method, or lifecycle methods:\n *\n * <pre class=\"code\">\n * &#064;ExtendWith(OutputCaptureExtension.class)\n * class MyTest {\n *\n *     &#064;Test\n *     void test(CapturedOutput output) {\n *         System.out.println(\"ok\");\n *         assertThat(output).contains(\"ok\");\n *         System.err.println(\"error\");\n *     }\n *\n *     &#064;AfterEach\n *     void after(CapturedOutput output) {\n *         assertThat(output.getOut()).contains(\"ok\");\n *         assertThat(output.getErr()).contains(\"error\");\n *     }\n *\n * }\n * </pre>\n *\n * @author Madhura Bhave\n * @author Phillip Webb\n * @author Andy Wilkinson\n * @author Sam Brannen\n * @see CapturedOutput\n */\npublic class OutputCaptureExtension\n\t\timplements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback, ParameterResolver {\n\n\tOutputCaptureExtension() {\n\t\t// Package private to prevent users from directly creating an instance.\n\t}\n\n\t@Override\n\tpublic void beforeAll(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).push();\n\t}\n\n\t@Override\n\tpublic void afterAll(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).pop();\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).push();\n\t}\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\tgetOutputCapture(context).pop();\n\t}\n\n\t@Override\n\tpublic boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)\n\t\t\tthrows ParameterResolutionException {\n\t\treturn CapturedOutput.class.equals(parameterContext.getParameter().getType());\n\t}\n\n\t@Override\n\tpublic Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {\n\t\treturn getOutputCapture(extensionContext);\n\t}\n\n\tprivate OutputCapture getOutputCapture(ExtensionContext context) {\n\t\treturn getStore(context).computeIfAbsent(OutputCapture.class);\n\t}\n\n\tprivate Store getStore(ExtensionContext context) {\n\t\treturn context.getStore(Namespace.create(getClass()));\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/system/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes for {@link java.lang.System System}-related testing.\n */\npackage org.springframework.boot.testsupport.system;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactories.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.web.servlet;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n/**\n * Indicates that a test pollutes URL factories.\n *\n * @author Phillip Webb\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ ElementType.TYPE, ElementType.METHOD })\n@Documented\n@ExtendWith(DirtiesUrlFactoriesExtension.class)\npublic @interface DirtiesUrlFactories {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/DirtiesUrlFactoriesExtension.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.web.servlet;\n\nimport java.lang.reflect.InaccessibleObjectException;\nimport java.net.URL;\n\nimport org.junit.jupiter.api.extension.AfterEachCallback;\nimport org.junit.jupiter.api.extension.BeforeEachCallback;\nimport org.junit.jupiter.api.extension.ExtensionContext;\n\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.util.ClassUtils;\n\n/**\n * JUnit extension used by {@link DirtiesUrlFactories @DirtiesUrlFactories}.\n *\n * @author Phillip Webb\n */\nclass DirtiesUrlFactoriesExtension implements BeforeEachCallback, AfterEachCallback {\n\n\tprivate static final String TOMCAT_URL_STREAM_HANDLER_FACTORY = \"org.apache.catalina.webresources.TomcatURLStreamHandlerFactory\";\n\n\t@Override\n\tpublic void afterEach(ExtensionContext context) throws Exception {\n\t\treset();\n\t}\n\n\t@Override\n\tpublic void beforeEach(ExtensionContext context) throws Exception {\n\t\treset();\n\t}\n\n\tprivate void reset() {\n\t\ttry {\n\t\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\t\tif (ClassUtils.isPresent(TOMCAT_URL_STREAM_HANDLER_FACTORY, classLoader)) {\n\t\t\t\tClass<?> factoryClass = ClassUtils.resolveClassName(TOMCAT_URL_STREAM_HANDLER_FACTORY, classLoader);\n\t\t\t\tReflectionTestUtils.setField(factoryClass, \"instance\", null);\n\t\t\t}\n\t\t\tReflectionTestUtils.setField(URL.class, \"factory\", null);\n\t\t}\n\t\tcatch (InaccessibleObjectException ex) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Unable to reset field. Please run with '--add-opens=java.base/java.net=ALL-UNNAMED'\", ex);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/ExampleFilter.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.web.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.FilterConfig;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\n\n/**\n * Simple example Filter used for testing.\n *\n * @author Phillip Webb\n */\npublic class ExampleFilter implements Filter {\n\n\t@Override\n\tpublic void init(FilterConfig filterConfig) throws ServletException {\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n\t@Override\n\tpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)\n\t\t\tthrows IOException, ServletException {\n\t\tresponse.getWriter().write(\"[\");\n\t\tchain.doFilter(request, response);\n\t\tresponse.getWriter().write(\"]\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/ExampleServlet.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.web.servlet;\n\nimport java.io.IOException;\n\nimport jakarta.servlet.GenericServlet;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletOutputStream;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\n\nimport org.springframework.util.StreamUtils;\n\n/**\n * Simple example Servlet used for testing.\n *\n * @author Phillip Webb\n */\n@SuppressWarnings(\"serial\")\npublic class ExampleServlet extends GenericServlet {\n\n\tprivate final boolean echoRequestInfo;\n\n\tprivate final boolean writeWithoutContentLength;\n\n\tpublic ExampleServlet() {\n\t\tthis(false, false);\n\t}\n\n\tpublic ExampleServlet(boolean echoRequestInfo, boolean writeWithoutContentLength) {\n\t\tthis.echoRequestInfo = echoRequestInfo;\n\t\tthis.writeWithoutContentLength = writeWithoutContentLength;\n\t}\n\n\t@Override\n\tpublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {\n\t\tString content = \"Hello World\";\n\t\tif (this.echoRequestInfo) {\n\t\t\tcontent += \" scheme=\" + request.getScheme();\n\t\t\tcontent += \" remoteaddr=\" + request.getRemoteAddr();\n\t\t}\n\t\tif (this.writeWithoutContentLength) {\n\t\t\tresponse.setContentType(\"text/plain\");\n\t\t\tServletOutputStream outputStream = response.getOutputStream();\n\t\t\tStreamUtils.copy(content.getBytes(), outputStream);\n\t\t\toutputStream.flush();\n\t\t}\n\t\telse {\n\t\t\tresponse.getWriter().write(content);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/package-info.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Servlet test support.\n */\npackage org.springframework.boot.testsupport.web.servlet;\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/FileUtilsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link FileUtils}.\n *\n * @author Dave Syer\n * @author Phillip Webb\n * @author Andy Wilkinson\n */\nclass FileUtilsTests {\n\n\t@TempDir\n\tFile tempDir;\n\n\t@Test\n\tvoid hash() throws Exception {\n\t\tFile file = new File(this.tempDir, \"file\");\n\t\ttry (OutputStream outputStream = new FileOutputStream(file)) {\n\t\t\toutputStream.write(new byte[] { 1, 2, 3 });\n\t\t}\n\t\tassertThat(FileUtils.sha1Hash(file)).isEqualTo(\"7037807198c22a7d2b0807371d763779a84fdfcf\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/assertj/SimpleAsyncTaskExecutorAssertTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.assertj;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledForJreRange;\nimport org.junit.jupiter.api.condition.JRE;\n\nimport org.springframework.core.task.SimpleAsyncTaskExecutor;\n\n/**\n * Tests for {@link SimpleAsyncTaskExecutorAssert}.\n *\n * @author Moritz Halbritter\n */\nclass SimpleAsyncTaskExecutorAssertTests {\n\n\t@Test\n\tvoid usesPlatformThreads() {\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();\n\t\texecutor.setVirtualThreads(false);\n\t\tSimpleAsyncTaskExecutorAssert.assertThat(executor).usesPlatformThreads();\n\t}\n\n\t@Test\n\t@EnabledForJreRange(min = JRE.JAVA_21)\n\tvoid usesVirtualThreads() {\n\t\tSimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();\n\t\texecutor.setVirtualThreads(true);\n\t\tSimpleAsyncTaskExecutorAssert.assertThat(executor).usesVirtualThreads();\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtensionExclusionsTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport org.hamcrest.Matcher;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.util.ClassUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.hamcrest.Matchers.isA;\n\n/**\n * Tests for {@link ModifiedClassPathExtension} excluding entries from the class path.\n *\n * @author Christoph Dreis\n * @author Andy Wilkinson\n */\n@ClassPathExclusions(files = \"hibernate-validator-*.jar\", packages = \"java.net.http\")\nclass ModifiedClassPathExtensionExclusionsTests {\n\n\tprivate static final String EXCLUDED_RESOURCE = \"META-INF/services/jakarta.validation.spi.ValidationProvider\";\n\n\t@Test\n\tvoid fileExclusionsAreFilteredFromTestClassClassLoader() {\n\t\tassertThat(getClass().getClassLoader().getResource(EXCLUDED_RESOURCE)).isNull();\n\t}\n\n\t@Test\n\tvoid fileExclusionsAreFilteredFromThreadContextClassLoader() {\n\t\tassertThat(Thread.currentThread().getContextClassLoader().getResource(EXCLUDED_RESOURCE)).isNull();\n\t}\n\n\t@Test\n\tvoid packageExclusionsAreFilteredFromTestClassClassLoader() {\n\t\tassertThat(ClassUtils.isPresent(\"java.net.http.HttpClient\", getClass().getClassLoader())).isFalse();\n\t}\n\n\t@Test\n\tvoid packageExclusionsAreFilteredFromThreadContextClassLoader() {\n\t\tassertThat(ClassUtils.isPresent(\"java.net.http.HttpClient\", Thread.currentThread().getContextClassLoader()))\n\t\t\t.isFalse();\n\t}\n\n\t@Test\n\tvoid testsThatUseHamcrestWorkCorrectly() {\n\t\tMatcher<IllegalStateException> matcher = isA(IllegalStateException.class);\n\t\tassertThat(matcher.matches(new IllegalStateException())).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtensionForkParameterizedTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ForkedClassPath @ForkedClassPath}.\n *\n * @author Andy Wilkinson\n */\n@ForkedClassPath\nclass ModifiedClassPathExtensionForkParameterizedTests {\n\n\tprivate static final List<String> arguments = new ArrayList<>();\n\n\t@ParameterizedTest\n\t@ValueSource(strings = { \"one\", \"two\", \"three\" })\n\tvoid testIsInvokedOnceForEachArgument(String argument) {\n\t\tif (argument.equals(\"one\")) {\n\t\t\tassertThat(arguments).isEmpty();\n\t\t}\n\t\telse if (argument.equals(\"two\")) {\n\t\t\tassertThat(arguments).doesNotContain(\"two\", \"three\");\n\t\t}\n\t\telse if (argument.equals(\"three\")) {\n\t\t\tassertThat(arguments).doesNotContain(\"three\");\n\t\t}\n\t\targuments.add(argument);\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtensionForkTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ForkedClassPath @ForkedClassPath}.\n *\n * @author Christoph Dreis\n */\n@ForkedClassPath\nclass ModifiedClassPathExtensionForkTests {\n\n\t@Test\n\tvoid modifiedClassLoaderIsUsed() {\n\t\tClassLoader classLoader = getClass().getClassLoader();\n\t\tassertThat(classLoader.getClass().getName()).isEqualTo(ModifiedClassPathClassLoader.class.getName());\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtensionOverridesParameterizedTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport java.util.stream.Stream;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.Arguments;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.context.ApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ModifiedClassPathExtension} overriding entries on the class path via\n * parameters.\n *\n * @author Phillip Webb\n */\nclass ModifiedClassPathExtensionOverridesParameterizedTests {\n\n\t@ParameterizedTest\n\t@ForkedClassPath\n\t@MethodSource(\"parameter\")\n\tvoid classesAreLoadedFromParameter(Class<?> type) {\n\t\tassertThat(ApplicationContext.class.getProtectionDomain().getCodeSource().getLocation().toString())\n\t\t\t.endsWith(\"spring-context-4.1.0.RELEASE.jar\");\n\t}\n\n\tstatic Class<?>[] parameter() {\n\t\treturn new Class<?>[] { ClassWithOverride.class };\n\t}\n\n\t@ParameterizedTest\n\t@ForkedClassPath\n\t@MethodSource(\"arrayParameter\")\n\tvoid classesAreLoadedFromParameterInArray(Object[] types) {\n\t\tassertThat(ApplicationContext.class.getProtectionDomain().getCodeSource().getLocation().toString())\n\t\t\t.endsWith(\"spring-context-4.1.0.RELEASE.jar\");\n\t}\n\n\tstatic Stream<Arguments> arrayParameter() {\n\t\tObject[] types = new Object[] { ClassWithOverride.class };\n\t\treturn Stream.of(Arguments.of(new Object[] { types }));\n\t}\n\n\t@ClassPathOverrides(\"org.springframework:spring-context:4.1.0.RELEASE\")\n\tstatic class ClassWithOverride {\n\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/ModifiedClassPathExtensionOverridesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link ModifiedClassPathExtension} overriding entries on the class path.\n *\n * @author Christoph Dreis\n */\n@ClassPathOverrides(\"org.springframework:spring-context:4.1.0.RELEASE\")\nclass ModifiedClassPathExtensionOverridesTests {\n\n\t@Test\n\tvoid classesAreLoadedFromOverride() {\n\t\tassertThat(ApplicationContext.class.getProtectionDomain().getCodeSource().getLocation().toString())\n\t\t\t.endsWith(\"spring-context-4.1.0.RELEASE.jar\");\n\t}\n\n\t@Test\n\tvoid classesAreLoadedFromTransitiveDependencyOfOverride() {\n\t\tassertThat(StringUtils.class.getProtectionDomain().getCodeSource().getLocation().toString())\n\t\t\t.endsWith(\"spring-core-4.1.0.RELEASE.jar\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/OnClassWithPackageResourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithPackageResources} on a class.\n *\n * @author Andy Wilkinson\n */\n@WithPackageResources({ \"resource-1.txt\", \"resource-2.txt\", \"sub/resource-3.txt\" })\nclass OnClassWithPackageResourcesTests {\n\n\t@Test\n\tvoid whenWithPackageResourcesIsUsedOnAClassThenResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"resource-1.txt\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"one\");\n\t\tassertThat(new ClassPathResource(\"resource-2.txt\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"two\");\n\t\tassertThat(new ClassPathResource(\"sub/resource-3.txt\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"three\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/OnClassWithResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Nested;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithResource} when used on a class.\n *\n * @author Andy Wilkinson\n */\n@WithResource(name = \"on-class\", content = \"class content\")\nclass OnClassWithResourceTests {\n\n\t@Test\n\tvoid whenWithResourceIsUsedOnAClassThenResourceIsAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"on-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"class content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"method-resource\", content = \"method\")\n\tvoid whenWithResourceIsUsedOnClassAndMethodThenBothResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"on-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"class content\");\n\t\tassertThat(new ClassPathResource(\"method-resource\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"method\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"method-resource-1\", content = \"method-1\")\n\t@WithResource(name = \"method-resource-2\", content = \"method-2\")\n\tvoid whenWithResourceIsUsedOnClassAndRepeatedOnMethodThenAllResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"on-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"class content\");\n\t\tassertThat(new ClassPathResource(\"method-resource-1\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"method-1\");\n\t\tassertThat(new ClassPathResource(\"method-resource-2\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"method-2\");\n\t}\n\n\t@Nested\n\tclass NestedTests {\n\n\t\t@Test\n\t\tvoid whenWithResourceIsUsedOnEnclosingClassThenResourceIsAvailable() throws IOException {\n\t\t\tassertThat(new ClassPathResource(\"on-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t\t.isEqualTo(\"class content\");\n\t\t}\n\n\t}\n\n\t@Nested\n\t@WithResource(name = \"on-nested-class\", content = \"nested class content\")\n\tclass WithResourceNestedTests {\n\n\t\t@Test\n\t\tvoid whenWithResourceIsUsedOnEnclosingClassAndClassThenBothResourcesAreAvailable() throws IOException {\n\t\t\tassertThat(new ClassPathResource(\"on-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t\t.isEqualTo(\"class content\");\n\t\t\tassertThat(new ClassPathResource(\"on-nested-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t\t.isEqualTo(\"nested class content\");\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/OnSuperClassWithPackageResourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithPackageResources} when used on a super-class.\n *\n * @author Andy Wilkinson\n */\nclass OnSuperClassWithPackageResourcesTests extends WithPackageResourcesClass {\n\n\t@Test\n\tvoid whenWithPackageResourcesIsUsedOnASuperClassThenResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"resource-1.txt\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"one\");\n\t\tassertThat(new ClassPathResource(\"resource-2.txt\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"two\");\n\t\tassertThat(new ClassPathResource(\"sub/resource-3.txt\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"three\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/OnSuperClassWithResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithResource} when used on a super-class.\n *\n * @author Andy Wilkinson\n */\nclass OnSuperClassWithResourceTests extends WithResourceClass {\n\n\t@Test\n\tvoid whenWithResourceIsUsedOnASuperClassThenResourceIsAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"on-super-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"super-class content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"method-resource\", content = \"method\")\n\tvoid whenWithResourceIsUsedOnASuperClassAndMethodThenBothResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"on-super-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"super-class content\");\n\t\tassertThat(new ClassPathResource(\"method-resource\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"method\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"method-resource-1\", content = \"method-1\")\n\t@WithResource(name = \"method-resource-2\", content = \"method-2\")\n\tvoid whenWithResourceIsUsedOnASuperClassAndRepeatedOnMethodThenAllResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"on-super-class\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"super-class content\");\n\t\tassertThat(new ClassPathResource(\"method-resource-1\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"method-1\");\n\t\tassertThat(new ClassPathResource(\"method-resource-2\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"method-2\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/ResourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatIllegalStateException;\n\n/**\n * Tests for {@link Resources}.\n *\n * @author Andy Wilkinson\n */\nclass ResourcesTests {\n\n\t@TempDir\n\tprivate Path root;\n\n\tprivate Resources resources;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.resources = new Resources(this.root);\n\t}\n\n\t@Test\n\tvoid whenAddResourceThenResourceIsCreatedAndCanBeFound() {\n\t\tthis.resources.addResource(\"test\", \"test-content\", true);\n\t\tassertThat(this.root.resolve(\"test\")).hasContent(\"test-content\");\n\t\tassertThat(this.resources.find(\"test\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenAddResourceHasContentReferencingResourceRootThenResourceIsCreatedWithReferenceToRoot() {\n\t\tthis.resources.addResource(\"test\", \"*** ${resourceRoot} ***\", true);\n\t\tassertThat(this.root.resolve(\"test\")).hasContent(\"*** \" + this.root + \" ***\");\n\t}\n\n\t@Test\n\tvoid whenAddResourceWithPathThenResourceIsCreatedAndItAndItsAncestorsCanBeFound() {\n\t\tthis.resources.addResource(\"a/b/c/test\", \"test-content\", true);\n\t\tassertThat(this.root.resolve(\"a/b/c/test\")).hasContent(\"test-content\");\n\t\tassertThat(this.resources.find(\"a/b/c/test\")).isNotNull();\n\t\tassertThat(this.resources.find(\"a/b/c/\")).isNotNull();\n\t\tassertThat(this.resources.find(\"a/b/\")).isNotNull();\n\t\tassertThat(this.resources.find(\"a/\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenAddResourceAndResourceAlreadyExistsThenResourcesIsOverwritten() {\n\t\tthis.resources.addResource(\"a/b/c/test\", \"original-content\", true);\n\t\tthis.resources.addResource(\"a/b/c/test\", \"new-content\", true);\n\t\tassertThat(this.root.resolve(\"a/b/c/test\")).hasContent(\"new-content\");\n\t}\n\n\t@Test\n\tvoid whenAddPackageThenNamedResourcesFromPackageAreCreatedAndCanBeFound() {\n\t\tthis.resources.addPackage(getClass().getPackage().getName(),\n\t\t\t\tnew String[] { \"resource-1.txt\", \"sub/resource-3.txt\" });\n\t\tassertThat(this.root.resolve(\"resource-1.txt\")).hasContent(\"one\");\n\t\tassertThat(this.root.resolve(\"resource-2.txt\")).doesNotExist();\n\t\tassertThat(this.root.resolve(\"sub/resource-3.txt\")).hasContent(\"three\");\n\t\tassertThat(this.resources.find(\"resource-1.txt\")).isNotNull();\n\t\tassertThat(this.resources.find(\"resource-2.txt\")).isNull();\n\t\tassertThat(this.resources.find(\"sub/resource-3.txt\")).isNotNull();\n\t\tassertThat(this.resources.find(\"sub/\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenAddResourceAndDeleteThenResourceDoesNotExistAndCannotBeFound() {\n\t\tthis.resources.addResource(\"test\", \"test-content\", true);\n\t\tassertThat(this.root.resolve(\"test\")).hasContent(\"test-content\");\n\t\tassertThat(this.resources.find(\"test\")).isNotNull();\n\t\tthis.resources.delete();\n\t\tassertThat(this.root.resolve(\"test\")).doesNotExist();\n\t\tassertThat(this.resources.find(\"test\")).isNull();\n\t}\n\n\t@Test\n\tvoid whenAddPackageAndDeleteThenResourcesDoNotExistAndCannotBeFound() {\n\t\tthis.resources.addPackage(getClass().getPackage().getName(),\n\t\t\t\tnew String[] { \"resource-1.txt\", \"resource-2.txt\", \"sub/resource-3.txt\" });\n\t\tassertThat(this.root.resolve(\"resource-1.txt\")).hasContent(\"one\");\n\t\tassertThat(this.root.resolve(\"resource-2.txt\")).hasContent(\"two\");\n\t\tassertThat(this.root.resolve(\"sub/resource-3.txt\")).hasContent(\"three\");\n\t\tassertThat(this.resources.find(\"resource-1.txt\")).isNotNull();\n\t\tassertThat(this.resources.find(\"resource-2.txt\")).isNotNull();\n\t\tassertThat(this.resources.find(\"sub/resource-3.txt\")).isNotNull();\n\t\tassertThat(this.resources.find(\"sub/\")).isNotNull();\n\t\tthis.resources.delete();\n\t\tassertThat(this.root.resolve(\"resource-1.txt\")).doesNotExist();\n\t\tassertThat(this.root.resolve(\"resource-2.txt\")).doesNotExist();\n\t\tassertThat(this.root.resolve(\"sub/resource-3.txt\")).doesNotExist();\n\t\tassertThat(this.root.resolve(\"sub\")).doesNotExist();\n\t\tassertThat(this.resources.find(\"resource-1.txt\")).isNull();\n\t\tassertThat(this.resources.find(\"resource-2.txt\")).isNull();\n\t\tassertThat(this.resources.find(\"sub/resource-3.txt\")).isNull();\n\t\tassertThat(this.resources.find(\"sub/\")).isNull();\n\t}\n\n\t@Test\n\tvoid whenAddDirectoryThenDirectoryIsCreatedAndCanBeFound() {\n\t\tthis.resources.addDirectory(\"dir\");\n\t\tassertThat(this.root.resolve(\"dir\")).isDirectory();\n\t\tassertThat(this.resources.find(\"dir/\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenAddDirectoryWithPathThenDirectoryIsCreatedAndItAndItsAncestorsCanBeFound() {\n\t\tthis.resources.addDirectory(\"one/two/three/dir\");\n\t\tassertThat(this.root.resolve(\"one/two/three/dir\")).isDirectory();\n\t\tassertThat(this.resources.find(\"one/two/three/dir/\")).isNotNull();\n\t\tassertThat(this.resources.find(\"one/two/three/\")).isNotNull();\n\t\tassertThat(this.resources.find(\"one/two/\")).isNotNull();\n\t\tassertThat(this.resources.find(\"one/\")).isNotNull();\n\t}\n\n\t@Test\n\tvoid whenAddDirectoryAndDirectoryAlreadyExistsThenDoesNotThrow() {\n\t\tthis.resources.addDirectory(\"one/two/three/dir\");\n\t\tthis.resources.addDirectory(\"one/two/three/dir\");\n\t\tassertThat(this.root.resolve(\"one/two/three/dir\")).isDirectory();\n\t}\n\n\t@Test\n\tvoid whenAddDirectoryAndResourceAlreadyExistsThenIllegalStateExceptionIsThrown() {\n\t\tthis.resources.addResource(\"one/two/three/\", \"content\", true);\n\t\tassertThatIllegalStateException().isThrownBy(() -> this.resources.addDirectory(\"one/two/three\"));\n\t}\n\n\t@Test\n\tvoid whenAddResourceAndDirectoryAlreadyExistsThenIllegalStateExceptionIsThrown() {\n\t\tthis.resources.addDirectory(\"one/two/three\");\n\t\tassertThatIllegalStateException()\n\t\t\t.isThrownBy(() -> this.resources.addResource(\"one/two/three\", \"content\", true));\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/WithPackageResourcesClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\n/**\n * Class to test the use of {@link WithPackageResources} on a super-class.\n *\n * @author Andy Wilkinson\n */\n@WithPackageResources({ \"resource-1.txt\", \"resource-2.txt\", \"sub/resource-3.txt\" })\nclass WithPackageResourcesClass {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/WithPackageResourcesTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithPackageResources}.\n *\n * @author Andy Wilkinson\n */\nclass WithPackageResourcesTests {\n\n\t@Test\n\t@WithPackageResources({ \"resource-1.txt\", \"resource-2.txt\", \"sub/resource-3.txt\" })\n\tvoid whenWithPackageResourcesIsUsedOnAMethodThenResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"resource-1.txt\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"one\");\n\t\tassertThat(new ClassPathResource(\"resource-2.txt\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"two\");\n\t\tassertThat(new ClassPathResource(\"sub/resource-3.txt\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"three\");\n\t}\n\n\t@Test\n\t@WithPackageResources(\"sub/resource-3.txt\")\n\tvoid whenWithPackageResourcesOnlyIncludesSomeResourcesThenOnlyIncludedResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"resource-1.txt\").exists()).isFalse();\n\t\tassertThat(new ClassPathResource(\"resource-2.txt\").exists()).isFalse();\n\t\tassertThat(new ClassPathResource(\"sub/resource-3.txt\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"three\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/WithResourceClass.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\n/**\n * Class to test the use of {@link WithResource} on a super-class\n *\n * @author Andy Wilkinson\n */\n@WithResource(name = \"on-super-class\", content = \"super-class content\")\nclass WithResourceClass {\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/WithResourceDirectoryTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.IOException;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithResourceDirectory}.\n *\n * @author Andy Wilkinson\n */\nclass WithResourceDirectoryTests {\n\n\t@Test\n\t@WithResourceDirectory(\"test\")\n\tvoid whenWithResourceDirectoryIsUsedOnAMethodThenDirectoryIsCreated() throws IOException {\n\t\tassertThat(new ClassPathResource(\"test\").getFile()).isDirectory();\n\t}\n\n\t@Test\n\t@WithResourceDirectory(\"com/example/nested\")\n\tvoid whenWithResourceDirectoryNamesANestedDirectoryThenDirectoryIsCreated() throws IOException {\n\t\tassertThat(new ClassPathResource(\"com/example/nested\").getFile()).isDirectory();\n\t}\n\n\t@Test\n\t@WithResourceDirectory(\"1\")\n\t@WithResourceDirectory(\"2\")\n\t@WithResourceDirectory(\"3\")\n\tvoid whenWithResourceDirectoryIsRepeatedOnAMethodThenAllResourceDirectoriesAreCreated() throws IOException {\n\t\tassertThat(new ClassPathResource(\"1\").getFile()).isDirectory();\n\t\tassertThat(new ClassPathResource(\"2\").getFile()).isDirectory();\n\t\tassertThat(new ClassPathResource(\"3\").getFile()).isDirectory();\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/classpath/resources/WithResourceTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.classpath.resources;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Tests for {@link WithResource}.\n *\n * @author Andy Wilkinson\n */\nclass WithResourceTests {\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceIsAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"test\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromFileResourcesRoot(@ResourcesRoot File root) {\n\t\tassertThat(new File(root, \"test\")).hasContent(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromPathResourcesRoot(@ResourcesRoot Path root) {\n\t\tassertThat(root.resolve(\"test\")).hasContent(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromPathResourcePath(\n\t\t\t@ResourcePath(\"test\") Path resource) {\n\t\tassertThat(resource).hasContent(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromFileResourcePath(\n\t\t\t@ResourcePath(\"test\") File resource) {\n\t\tassertThat(resource).hasContent(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceIsAvailableFromStringResourcePath(\n\t\t\t@ResourcePath(\"test\") String resource) {\n\t\tassertThat(new File(resource)).hasContent(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"test\", content = \"content\")\n\tvoid whenWithResourceIsUsedOnAMethodThenResourceContentIsAvailableAsAString(\n\t\t\t@ResourceContent(\"test\") String content) {\n\t\tassertThat(content).isEqualTo(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"com/example/test-resource\", content = \"content\")\n\tvoid whenWithResourceNameIncludesADirectoryThenResourceIsAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"com/example/test-resource\").getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.isEqualTo(\"content\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"1\", content = \"one\")\n\t@WithResource(name = \"2\", content = \"two\")\n\t@WithResource(name = \"3\", content = \"three\")\n\tvoid whenWithResourceIsRepeatedOnAMethodThenAllResourcesAreAvailable() throws IOException {\n\t\tassertThat(new ClassPathResource(\"1\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"one\");\n\t\tassertThat(new ClassPathResource(\"2\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"two\");\n\t\tassertThat(new ClassPathResource(\"3\").getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"three\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"org/springframework/boot/testsupport/classpath/resources/resource-1.txt\",\n\t\t\tcontent = \"from-with-resource\")\n\tvoid whenWithResourceCreatesResourceThatIsAvailableElsewhereBothResourcesCanBeLoaded() throws IOException {\n\t\tResource[] resources = new PathMatchingResourcePatternResolver()\n\t\t\t.getResources(\"classpath*:org/springframework/boot/testsupport/classpath/resources/resource-1.txt\");\n\t\tassertThat(resources).hasSize(2);\n\t\tassertThat(resources).extracting((resource) -> resource.getContentAsString(StandardCharsets.UTF_8))\n\t\t\t.containsExactly(\"from-with-resource\", \"one\");\n\t}\n\n\t@Test\n\t@WithResource(name = \"org/springframework/boot/testsupport/classpath/resources/resource-1.txt\",\n\t\t\tcontent = \"from-with-resource\", additional = false)\n\tvoid whenWithResourceCreatesResourceThatIsNotAdditionalThenResourceThatIsAvailableElsewhereCannotBeLoaded()\n\t\t\tthrows IOException {\n\t\tResource[] resources = new PathMatchingResourcePatternResolver()\n\t\t\t.getResources(\"classpath*:org/springframework/boot/testsupport/classpath/resources/resource-1.txt\");\n\t\tassertThat(resources).hasSize(1);\n\t\tassertThat(resources[0].getContentAsString(StandardCharsets.UTF_8)).isEqualTo(\"from-with-resource\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/process/DisabledIfProcessUnavailableTests.java",
    "content": "/*\n * Copyright 2012-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.boot.testsupport.process;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Tests for {@link DisabledIfProcessUnavailable}.\n *\n * @author Phillip Webb\n */\n@DisabledIfProcessUnavailable(\"iverymuchdontexist\")\nclass DisabledIfProcessUnavailableTests {\n\n\t@Test\n\tvoid test() {\n\t\tfail(\"I should have been disabled\");\n\t}\n\n}\n"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/resources/org/springframework/boot/testsupport/classpath/resources/resource-1.txt",
    "content": "one"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/resources/org/springframework/boot/testsupport/classpath/resources/resource-2.txt",
    "content": "two"
  },
  {
    "path": "test-support/spring-boot-test-support/src/test/resources/org/springframework/boot/testsupport/classpath/resources/sub/resource-3.txt",
    "content": "three"
  }
]